1
0
mirror of https://github.com/samba-team/samba.git synced 2025-02-08 05:57:51 +03:00
Jelmer Vernooij 98b57d5eb6 r25035: Fix some more warnings, use service pointer rather than service number in more places.
(This used to be commit df9cebcb97e20564359097148665bd519f31bc6f)
2007-10-10 15:05:43 -05:00

1091 lines
24 KiB
C

/*
* @file ejs.c
* @brief Embedded JavaScript (EJS)
* @overview Main module interface logic.
*/
/********************************* Copyright **********************************/
/*
* @copy default.g
*
* Copyright (c) Mbedthis Software LLC, 2003-2005. All Rights Reserved.
* Portions Copyright (c) GoAhead Software, 1995-2000. All Rights Reserved.
*
* This software is distributed under commercial and open source licenses.
* You may use the GPL open source license described below or you may acquire
* a commercial license from Mbedthis Software. You agree to be fully bound
* by the terms of either license. Consult the LICENSE.TXT distributed with
* this software for full details.
*
* This software is open source; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See the GNU General Public License for more
* details at: http://www.mbedthis.com/downloads/gplLicense.html
*
* This program is distributed WITHOUT ANY WARRANTY; without even the
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
*
* This GPL license does NOT permit incorporating this software into
* proprietary programs. If you are unable to comply with the GPL, you must
* acquire a commercial license to use this software. Commercial licenses
* for this software and support services are available from Mbedthis
* Software at http://www.mbedthis.com
*
* @end
*/
/********************************** Includes **********************************/
#include "ejsInternal.h"
#if BLD_FEATURE_EJS
/********************************** Local Data ********************************/
/*
* These fields must be locked before any access when multithreaded
*/
static MprVar master; /* Master object */
static MprArray *ejsList; /* List of ej handles */
#if BLD_FEATURE_MULTITHREAD
static EjsLock lock;
static EjsUnlock unlock;
static void *lockData;
#define ejsLock() if (lock) { (lock)(lockData); } else
#define ejsUnlock() if (unlock) { (unlock)(lockData); } else
#else
#define ejsLock()
#define ejsUnlock()
#endif
/*
save/restore global ejs state - used to cope with simultaneous ejs requests
this is a workaround for the use of global variables in ejs
*/
struct ejs_state_ctx {
MprVar master;
MprArray *ejsList;
};
void *ejs_save_state(void)
{
struct ejs_state_ctx *ctx = talloc(talloc_autofree_context(), struct ejs_state_ctx);
ctx->master = master;
ctx->ejsList = ejsList;
return ctx;
}
void ejs_restore_state(void *ptr)
{
struct ejs_state_ctx *ctx = talloc_get_type(ptr, struct ejs_state_ctx);
master = ctx->master;
ejsList = ctx->ejsList;
talloc_free(ctx);
}
/****************************** Forward Declarations **************************/
static char *getNextVarToken(char **next, char *tokBuf, int tokBufLen);
/************************************* Code ***********************************/
/*
* Initialize the EJ subsystem
*/
int ejsOpen(EjsLock lockFn, EjsUnlock unlockFn, void *data)
{
MprVar *np;
#if BLD_FEATURE_MULTITHREAD
if (lockFn) {
lock = lockFn;
unlock = unlockFn;
lockData = data;
}
#endif
ejsLock();
/*
* Master is the top level object (above global). It is used to clone its
* contents into the global scope for each. This is never visible to the
* user, so don't use ejsCreateObj().
*/
master = mprCreateObjVar("master", EJS_SMALL_OBJ_HASH_SIZE);
if (master.type == MPR_TYPE_UNDEFINED) {
ejsUnlock();
return MPR_ERR_CANT_ALLOCATE;
}
ejsList = mprCreateArray();
ejsDefineStandardProperties(&master);
/*
* Make these objects immutable
*/
np = mprGetFirstProperty(&master, MPR_ENUM_FUNCTIONS | MPR_ENUM_DATA);
while (np) {
mprSetVarReadonly(np, 1);
np = mprGetNextProperty(&master, np, MPR_ENUM_FUNCTIONS |
MPR_ENUM_DATA);
}
ejsUnlock();
return 0;
}
/******************************************************************************/
void ejsClose()
{
ejsLock();
mprDestroyArray(ejsList);
mprDestroyVar(&master);
ejsUnlock();
}
/******************************************************************************/
/*
* Create and initialize an EJS engine
*/
EjsId ejsOpenEngine(EjsHandle primaryHandle, EjsHandle altHandle)
{
MprVar *np;
Ejs *ep;
ep = (Ejs *)mprMalloc(sizeof(Ejs));
if (ep == 0) {
return (EjsId) -1;
}
memset(ep, 0, sizeof(Ejs));
ejsLock();
ep->eid = (EjsId) mprAddToArray(ejsList, ep);
ejsUnlock();
/*
* Create array of local variable frames
*/
ep->frames = mprCreateArray();
if (ep->frames == 0) {
ejsCloseEngine(ep->eid);
return (EjsId) -1;
}
ep->primaryHandle = primaryHandle;
ep->altHandle = altHandle;
/*
* Create first frame: global variables
*/
ep->global = (MprVar*) mprMalloc(sizeof(MprVar));
*ep->global = ejsCreateObj("global", EJS_OBJ_HASH_SIZE);
if (ep->global->type == MPR_TYPE_UNDEFINED) {
ejsCloseEngine(ep->eid);
return (EjsId) -1;
}
mprAddToArray(ep->frames, ep->global);
/*
* Create first local variable frame
*/
ep->local = (MprVar*) mprMalloc(sizeof(MprVar));
*ep->local = ejsCreateObj("local", EJS_OBJ_HASH_SIZE);
if (ep->local->type == MPR_TYPE_UNDEFINED) {
ejsCloseEngine(ep->eid);
return (EjsId) -1;
}
mprAddToArray(ep->frames, ep->local);
/*
* Clone all master variables into the global frame. This does a
* reference copy.
*
* ejsDefineStandardProperties(ep->global);
*/
np = mprGetFirstProperty(&master, MPR_ENUM_FUNCTIONS | MPR_ENUM_DATA);
while (np) {
mprCreateProperty(ep->global, np->name, np);
np = mprGetNextProperty(&master, np, MPR_ENUM_FUNCTIONS |
MPR_ENUM_DATA);
}
mprCreateProperty(ep->global, "global", ep->global);
mprCreateProperty(ep->global, "this", ep->global);
mprCreateProperty(ep->local, "local", ep->local);
return ep->eid;
}
/******************************************************************************/
/*
* Close an EJS instance
*/
void ejsCloseEngine(EjsId eid)
{
Ejs *ep;
MprVar *vp;
void **handles;
int i;
if ((ep = ejsPtr(eid)) == NULL) {
mprAssert(ep);
return;
}
mprFree(ep->error);
mprDestroyVar(&ep->result);
mprDestroyVar(&ep->tokenNumber);
if (ep->local) {
mprDeleteProperty(ep->local, "local");
}
mprDeleteProperty(ep->global, "this");
mprDeleteProperty(ep->global, "global");
handles = ep->frames->handles;
for (i = 0; i < ep->frames->max; i++) {
vp = handles[i];
if (vp) {
#if BLD_DEBUG
if (vp->type == MPR_TYPE_OBJECT && vp->properties->refCount > 1) {
mprLog(7, "ejsCloseEngine: %s has ref count %d\n",
vp->name, vp->properties->refCount);
}
#endif
mprDestroyVar(vp);
mprFree(vp);
mprRemoveFromArray(ep->frames, i);
}
}
mprDestroyArray(ep->frames);
ejsLock();
mprRemoveFromArray(ejsList, (int) ep->eid);
ejsUnlock();
mprFree(ep);
}
/******************************************************************************/
/*
* Evaluate an EJS script file
*/
int ejsEvalFile(EjsId eid, char *path, MprVar *result, char **emsg)
{
struct stat sbuf;
Ejs *ep;
char *script;
int rc, fd;
mprAssert(path && *path);
if (emsg) {
*emsg = NULL;
}
if ((ep = ejsPtr(eid)) == NULL) {
mprAssert(ep);
goto error;
}
if ((fd = open(path, O_RDONLY | O_BINARY, 0666)) < 0) {
ejsError(ep, "Can't open %s\n", path);
goto error;
}
if (stat(path, &sbuf) < 0) {
close(fd);
ejsError(ep, "Cant stat %s", path);
goto error;
}
if ((script = (char*) mprMalloc(sbuf.st_size + 1)) == NULL) {
close(fd);
ejsError(ep, "Cant malloc %d", (int) sbuf.st_size);
goto error;
}
if (read(fd, script, sbuf.st_size) != (int) sbuf.st_size) {
close(fd);
mprFree(script);
ejsError(ep, "Error reading %s", path);
goto error;
}
script[sbuf.st_size] = '\0';
close(fd);
rc = ejsEvalBlock(eid, script, result, emsg);
mprFree(script);
return rc;
/*
* Error return
*/
error:
if(emsg)
*emsg = mprStrdup(ep->error);
return -1;
}
/******************************************************************************/
/*
* Create a new variable scope block. This pushes the old local frame down
* the stack and creates a new local variables frame.
*/
int ejsOpenBlock(EjsId eid)
{
Ejs *ep;
if((ep = ejsPtr(eid)) == NULL) {
return -1;
}
ep->local = (MprVar*) mprMalloc(sizeof(MprVar));
*ep->local = ejsCreateObj("localBlock", EJS_OBJ_HASH_SIZE);
mprCreateProperty(ep->local, "local", ep->local);
return mprAddToArray(ep->frames, ep->local);
}
/******************************************************************************/
/*
* Close a variable scope block opened via ejsOpenBlock. Pop back the old
* local variables frame.
*/
int ejsCloseBlock(EjsId eid, int fid)
{
Ejs *ep;
if((ep = ejsPtr(eid)) == NULL) {
mprAssert(ep);
return -1;
}
/*
* Must remove self-references before destroying "local"
*/
mprDeleteProperty(ep->local, "local");
mprDestroyVar(ep->local);
mprFree(ep->local);
mprRemoveFromArray(ep->frames, fid);
ep->local = (MprVar*) ep->frames->handles[ep->frames->used - 1];
return 0;
}
/******************************************************************************/
/*
* Create a new variable scope block and evaluate a script. All frames
* created during this context will be automatically deleted when complete.
* vp and emsg are optional. i.e. created local variables will be discarded
* when this routine returns.
*/
int ejsEvalBlock(EjsId eid, char *script, MprVar *vp, char **emsg)
{
int rc, fid;
mprAssert(script);
fid = ejsOpenBlock(eid);
rc = ejsEvalScript(eid, script, vp, emsg);
ejsCloseBlock(eid, fid);
return rc;
}
/******************************************************************************/
/*
* Parse and evaluate a EJS. Return the result in *vp. The result is "owned"
* by EJ and the caller must not free it. Returns -1 on errors and zero
* for success. On errors, emsg will be set to the reason. The caller must
* free emsg.
*/
int ejsEvalScript(EjsId eid, char *script, MprVar *vp, char **emsg)
{
Ejs *ep;
int state;
void *endlessLoopTest;
int loopCounter;
if (emsg) {
*emsg = NULL;
}
if ((ep = ejsPtr(eid)) == NULL) {
mprAssert(ep);
return -1;
}
mprDestroyVar(&ep->result);
if (script == 0) {
return 0;
}
/*
* Allocate a new evaluation block, and save the old one
*/
ejsLexOpenScript(ep, script);
/*
* Do the actual parsing and evaluation
*/
loopCounter = 0;
endlessLoopTest = NULL;
ep->exitStatus = 0;
do {
state = ejsParse(ep, EJS_STATE_BEGIN, EJS_FLAGS_EXE);
if (state == EJS_STATE_RET) {
state = EJS_STATE_EOF;
}
/*
* Stuck parser and endless recursion protection.
*/
if (endlessLoopTest == ep->input->scriptServp) {
if (loopCounter++ > 10) {
state = EJS_STATE_ERR;
ejsError(ep, "Syntax error");
}
} else {
endlessLoopTest = ep->input->scriptServp;
loopCounter = 0;
}
} while (state != EJS_STATE_EOF && state != EJS_STATE_ERR);
ejsLexCloseScript(ep);
/*
* Return any error string to the user
*/
if (state == EJS_STATE_ERR && emsg) {
*emsg = mprStrdup(ep->error);
}
if (state == EJS_STATE_ERR) {
return -1;
}
if (vp) {
*vp = ep->result;
}
return ep->exitStatus;
}
/******************************************************************************/
/*
* Core error handling
*/
static void ejsErrorCore(Ejs* ep, const char *fmt, va_list args)
PRINTF_ATTRIBUTE(2, 0);
static void ejsErrorCore(Ejs* ep, const char *fmt, va_list args)
{
EjsInput *ip;
char *errbuf, *msgbuf;
int frame = 0;
mprAssert(ep);
msgbuf = NULL;
mprAllocVsprintf(&msgbuf, MPR_MAX_STRING, fmt, args);
ip = ep->input;
mprAllocSprintf(&errbuf, MPR_MAX_STRING, "%s\nBacktrace:\n", msgbuf);
/* form a backtrace */
while (ip) {
char *msg2, *ebuf2;
mprAllocSprintf(&msg2, MPR_MAX_STRING,
"\t[%2d] %20s:%-4d -> %s\n",
frame++, ip->procName?ip->procName:"", ip->lineNumber, ip->line);
ebuf2 = mprRealloc(errbuf, strlen(errbuf) + strlen(msg2) + 1);
if (ebuf2 == NULL) break;
errbuf = ebuf2;
memcpy(errbuf+strlen(errbuf), msg2, strlen(msg2)+1);
mprFree(msg2);
ip = ip->next;
}
mprFree(ep->error);
ep->error = errbuf;
mprFree(msgbuf);
}
/******************************************************************************/
/*
* Internal use function to set the error message
*/
void ejsError(Ejs* ep, const char* fmt, ...)
{
va_list args;
va_start(args, fmt);
ejsErrorCore(ep, fmt, args);
va_end(args);
}
/******************************************************************************/
/*
* Public routine to set the error message
*/
void ejsSetErrorMsg(EjsId eid, const char* fmt, ...)
{
va_list args;
Ejs *ep;
if ((ep = ejsPtr(eid)) == NULL) {
mprAssert(ep);
return;
}
va_start(args, fmt);
ejsErrorCore(ep, fmt, args);
va_end(args);
}
/******************************************************************************/
/*
* Get the current line number
*/
int ejsGetLineNumber(EjsId eid)
{
Ejs *ep;
if ((ep = ejsPtr(eid)) == NULL) {
mprAssert(ep);
return -1;
}
return ep->input->lineNumber;
}
/******************************************************************************/
/*
* Return the local object
*/
MprVar *ejsGetLocalObject(EjsId eid)
{
Ejs *ep;
if ((ep = ejsPtr(eid)) == NULL) {
mprAssert(ep);
return 0;
}
return ep->local;
}
/******************************************************************************/
/*
* Return the global object
*/
MprVar *ejsGetGlobalObject(EjsId eid)
{
Ejs *ep;
if ((ep = ejsPtr(eid)) == NULL) {
mprAssert(ep);
return 0;
}
return ep->global;
}
/******************************************************************************/
/*
* Copy the value of an object property. Return value is in "value".
* If deepCopy is true, copy all object/strings. Otherwise, object reference
* counts are incremented. Callers must always call mprDestroyVar on the
* return value to prevent leaks.
*
* Returns: -1 on errors or if the variable is not found.
*/
int ejsCopyVar(EjsId eid, const char *var, MprVar *value, bool deepCopy)
{
Ejs *ep;
MprVar *vp;
mprAssert(var && *var);
mprAssert(value);
if ((ep = ejsPtr(eid)) == NULL) {
mprAssert(ep);
return -1;
}
if (ejsGetVarCore(ep, var, 0, &vp, 0) < 0) {
return -1;
}
return mprCopyProperty(value, vp, deepCopy);
}
/******************************************************************************/
/*
* Return the value of an object property. Return value is in "value".
* Objects and strings are not copied and reference counts are not modified.
* Callers should NOT call mprDestroyVar. Returns: -1 on errors or if the
* variable is not found.
*/
int ejsReadVar(EjsId eid, const char *var, MprVar *value)
{
Ejs *ep;
MprVar *vp;
mprAssert(var && *var);
mprAssert(value);
if ((ep = ejsPtr(eid)) == NULL) {
mprAssert(ep);
return -1;
}
if (ejsGetVarCore(ep, var, 0, &vp, 0) < 0) {
return -1;
}
return mprReadProperty(vp, value);
}
/******************************************************************************/
/*
* Set a variable that may be an arbitrarily complex object or array reference.
* Will always define in the top most variable frame.
*/
int ejsWriteVar(EjsId eid, const char *var, MprVar *value)
{
Ejs *ep;
MprVar *vp;
mprAssert(var && *var);
if ((ep = ejsPtr(eid)) == NULL) {
mprAssert(ep);
return -1;
}
if (ejsGetVarCore(ep, var, 0, &vp, EJS_FLAGS_CREATE) < 0) {
return -1;
}
mprAssert(vp);
/*
* Only copy the value. Don't overwrite the object's name
*/
mprWriteProperty(vp, value);
return 0;
}
/******************************************************************************/
/*
* Set a variable that may be an arbitrarily complex object or array reference.
* Will always define in the top most variable frame.
*/
int ejsWriteVarValue(EjsId eid, const char *var, MprVar value)
{
return ejsWriteVar(eid, var, &value);
}
/******************************************************************************/
/*
* Delete a variable
*/
int ejsDeleteVar(EjsId eid, const char *var)
{
Ejs *ep;
MprVar *vp;
MprVar *obj;
if ((ep = ejsPtr(eid)) == NULL) {
mprAssert(ep);
return -1;
}
if (ejsGetVarCore(ep, var, &obj, &vp, 0) < 0) {
return -1;
}
mprDeleteProperty(obj, vp->name);
return 0;
}
/******************************************************************************/
/*
* Set the expression return value
*/
void ejsSetReturnValue(EjsId eid, MprVar value)
{
Ejs *ep;
if ((ep = ejsPtr(eid)) == NULL) {
mprAssert(ep);
return;
}
mprCopyVar(&ep->result, &value, MPR_SHALLOW_COPY);
}
/******************************************************************************/
/*
* Set the expression return value to a string value
*/
void ejsSetReturnString(EjsId eid, const char *str)
{
Ejs *ep;
if ((ep = ejsPtr(eid)) == NULL) {
mprAssert(ep);
return;
}
mprCopyVarValue(&ep->result, mprCreateStringVar(str, 0), MPR_SHALLOW_COPY);
}
/******************************************************************************/
/*
* Get the expression return value
*/
MprVar *ejsGetReturnValue(EjsId eid)
{
Ejs *ep;
if ((ep = ejsPtr(eid)) == NULL) {
mprAssert(ep);
return 0;
}
return &ep->result;
}
/******************************************************************************/
/*
* Define a C function. If eid < 0, then update the master object with this
* function. NOTE: in this case, functionName must be simple without any "." or
* "[]" elements. If eid >= 0, add to the specified script engine. In this
* case, functionName can be an arbitrary object reference and can contain "."
* or "[]".
*/
void ejsDefineCFunction(EjsId eid, const char *functionName, MprCFunction fn,
void *thisPtr, int flags)
{
if (eid < 0) {
ejsLock();
mprCreatePropertyValue(&master, functionName,
mprCreateCFunctionVar(fn, thisPtr, flags));
ejsUnlock();
} else {
ejsWriteVarValue(eid, functionName,
mprCreateCFunctionVar(fn, thisPtr, flags));
}
}
/******************************************************************************/
/*
* Define a C function with String arguments
*/
void ejsDefineStringCFunction(EjsId eid, const char *functionName,
MprStringCFunction fn, void *thisPtr, int flags)
{
if (eid < 0) {
ejsLock();
mprCreatePropertyValue(&master, functionName,
mprCreateStringCFunctionVar(fn, thisPtr, flags));
ejsUnlock();
} else {
ejsWriteVarValue(eid, functionName,
mprCreateStringCFunctionVar(fn, thisPtr, flags));
}
}
/******************************************************************************/
/*
* Define a JavaScript function. Args should be comma separated.
* Body should not contain braces.
*/
void ejsDefineFunction(EjsId eid, const char *functionName, char *args,
char *body)
{
MprVar v;
v = mprCreateFunctionVar(args, body, 0);
if (eid < 0) {
ejsLock();
mprCreateProperty(&master, functionName, &v);
ejsUnlock();
} else {
ejsWriteVar(eid, functionName, &v);
}
mprDestroyVar(&v);
}
/******************************************************************************/
void *ejsGetThisPtr(EjsId eid)
{
Ejs *ep;
if ((ep = ejsPtr(eid)) == NULL) {
mprAssert(ep);
return 0;
}
return ep->thisPtr;
}
/******************************************************************************/
/*
* Find a variable given a variable name and return the parent object and
* the variable itself, the variable . This routine supports variable names
* that may be objects or arrays but may NOT have expressions in the array
* indicies. Returns -1 on errors or if the variable is not found.
*/
int ejsGetVarCore(Ejs *ep, const char *vname, MprVar **obj,
MprVar **varValue, int flags)
{
MprVar *currentObj;
MprVar *currentVar;
char tokBuf[EJS_MAX_ID];
char *propertyName, *token, *next, *cp, *varName;
if (obj) {
*obj = 0;
}
if (varValue) {
*varValue = 0;
}
currentObj = ejsFindObj(ep, 0, vname, flags);
currentVar = 0;
propertyName = 0;
next = varName = mprStrdup(vname);
token = getNextVarToken(&next, tokBuf, sizeof(tokBuf));
while (currentObj != 0 && token != 0 && *token) {
if (*token == '[') {
token = getNextVarToken(&next, tokBuf, sizeof(tokBuf));
propertyName = token;
if (*propertyName == '\"') {
propertyName++;
if ((cp = strchr(propertyName, '\"')) != 0) {
*cp = '\0';
}
} else if (*propertyName == '\'') {
propertyName++;
if ((cp = strchr(propertyName, '\'')) != 0) {
*cp = '\0';
}
}
currentObj = currentVar;
currentVar = ejsFindProperty(ep, 0, currentObj, propertyName, 0);
token = getNextVarToken(&next, tokBuf, sizeof(tokBuf));
if (*token != ']') {
mprFree(varName);
return -1;
}
} else if (*token == '.') {
token = getNextVarToken(&next, tokBuf, sizeof(tokBuf));
if (!isalpha((int) token[0]) &&
token[0] != '_' && token[0] != '$') {
mprFree(varName);
return -1;
}
propertyName = token;
currentObj = currentVar;
currentVar = ejsFindProperty(ep, 0, currentObj, token, 0);
} else {
currentVar = ejsFindProperty(ep, 0, currentObj, token, 0);
}
token = getNextVarToken(&next, tokBuf, sizeof(tokBuf));
}
mprFree(varName);
if (currentVar == 0 && currentObj >= 0 && flags & EJS_FLAGS_CREATE) {
currentVar = mprCreatePropertyValue(currentObj, propertyName,
mprCreateUndefinedVar());
}
if (obj) {
*obj = currentObj;
}
/*
* Don't use mprCopyVar as it will copy the data
*/
if (varValue) {
*varValue = currentVar;
}
return currentVar ? 0 : -1;
}
/******************************************************************************/
/*
* Get the next token as part of a variable specification. This will return
* a pointer to the next token and will return a pointer to the next token
* (after this one) in "next". The tokBuf holds the parsed token.
*/
static char *getNextVarToken(char **next, char *tokBuf, int tokBufLen)
{
char *start, *cp;
int len;
start = *next;
while (isspace((int) *start) || *start == '\n' || *start == '\r') {
start++;
}
cp = start;
if (*cp == '.' || *cp == '[' || *cp == ']') {
cp++;
} else {
while (*cp && *cp != '.' && *cp != '[' && *cp != ']' &&
!isspace((int) *cp) && *cp != '\n' && *cp != '\r') {
cp++;
}
}
len = mprMemcpy(tokBuf, tokBufLen - 1, start, cp - start);
tokBuf[len] = '\0';
*next = cp;
return tokBuf;
}
/******************************************************************************/
/*
* Get the EJS structure pointer
*/
Ejs *ejsPtr(EjsId eid)
{
Ejs *handle;
int intId;
intId = (int) eid;
ejsLock();
mprAssert(0 <= intId && intId < ejsList->max);
if (intId < 0 || intId >= ejsList->max || ejsList->handles[intId] == NULL) {
mprAssert(0);
ejsUnlock();
return NULL;
}
handle = ejsList->handles[intId];
ejsUnlock();
return handle;
}
/******************************************************************************/
/*
* Utility routine to crack JavaScript arguments. Return the number of args
* seen. This routine only supports %s and %d type args.
*
* Typical usage:
*
* if (ejsParseArgs(argc, argv, "%s %d", &name, &age) < 2) {
* mprError("Insufficient args\n");
* return -1;
* }
*/
int ejsParseArgs(int argc, char **argv, char *fmt, ...)
{
va_list vargs;
bool *bp;
char *cp, **sp, *s;
int *ip, argn;
va_start(vargs, fmt);
if (argv == 0) {
return 0;
}
for (argn = 0, cp = fmt; cp && *cp && argn < argc && argv[argn]; ) {
if (*cp++ != '%') {
continue;
}
s = argv[argn];
switch (*cp) {
case 'b':
bp = va_arg(vargs, bool*);
if (bp) {
if (strcmp(s, "true") == 0 || s[0] == '1') {
*bp = 1;
} else {
*bp = 0;
}
} else {
*bp = 0;
}
break;
case 'd':
ip = va_arg(vargs, int*);
*ip = atoi(s);
break;
case 's':
sp = va_arg(vargs, char**);
*sp = s;
break;
default:
mprAssert(0);
}
argn++;
}
va_end(vargs);
return argn;
}
/******************************************************************************/
#else
void ejsDummy() {}
/******************************************************************************/
#endif /* BLD_FEATURE_EJS */
/******************************************************************************/
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim:tw=78
* vim600: sw=4 ts=4 fdm=marker
* vim<600: sw=4 ts=4
*/