diff options
Diffstat (limited to 'source4/lib/appweb/ejs-2.0/ejs/ejs.c')
-rw-r--r-- | source4/lib/appweb/ejs-2.0/ejs/ejs.c | 1378 |
1 files changed, 1378 insertions, 0 deletions
diff --git a/source4/lib/appweb/ejs-2.0/ejs/ejs.c b/source4/lib/appweb/ejs-2.0/ejs/ejs.c new file mode 100644 index 0000000000..0fcc6f0545 --- /dev/null +++ b/source4/lib/appweb/ejs-2.0/ejs/ejs.c @@ -0,0 +1,1378 @@ +/* + * @file ejs.c + * @brief Embedded JavaScript (EJS) + * @overview Main module interface logic. + * @remarks The initialization code must be run single-threaded. Includes: + * ejsOpen, ejsClose. + */ +/********************************* Copyright **********************************/ +/* + * @copy default + * + * Copyright (c) Mbedthis Software LLC, 2003-2006. 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 "ejs.h" + +#if BLD_FEATURE_EJS + +/************************************* Code ***********************************/ +/* + * Initialize the EJS subsystem + */ + +EjsService *ejsOpenService(MprCtx ctx) +{ + EjsService *service; + Ejs *interp; + + service = mprAllocTypeZeroed(ctx, EjsService); + if (service == 0) { + mprError(ctx, MPR_LOC, "Can't allocate service memory"); + return 0; + } + + interp = ejsCreateInterp(service, 0, 0, 0, 1); + if (interp == 0) { + mprError(ctx, MPR_LOC, "Can't create master interpreter"); + mprFree(service); + return 0; + } + service->master = interp; + + /* + * Restore the default GC settings for the master interpreter. + * ejsCreateInterp will have initialized them. + */ + ejsGCInit(interp, EJS_DEFAULT_OBJ_INC, EJS_DEFAULT_PROP_INC, + EJS_DEFAULT_VAR_INC, EJS_DEFAULT_STR_INC); + + /* + * Save the default interpreter and global class for all to access + * MOB -- don't store these. Store the service + */ + mprSetKeyValue(interp, "ejsMaster", interp); + mprSetKeyValue(interp, "ejsGlobalClass", interp->global); + + /* + * Once the Object class is created, this routine will also make the + * Global class a subclass of Object. + */ + if (ejsDefineObjectClass(interp) < 0) { + mprError(ctx, MPR_LOC, "Can't define EJS object class"); + mprFree(service); + return 0; + } + + /* + * Create all the standard classes + */ + if (ejsDefineStandardClasses(interp) < 0) { + mprError(ctx, MPR_LOC, "Can't define EJS standard classes"); + mprFree(service); + return 0; + } + + if (ejsDefineSystemClasses(interp) < 0) { + mprError(ctx, MPR_LOC, "Can't define EJS system classes"); + mprFree(service); + return 0; + } + + if (ejsCreateObjectModel(interp) < 0) { + mprError(ctx, MPR_LOC, "Can't create EJS object model"); + mprFree(service); + return 0; + } + +#if UNUSED && BLD_FEATURE_ALLOC_STATS +{ + EjsVar v; + mprLog(ctx, 0, "Obj %d, Var %d, Prop %d\n", sizeof(EjsObj), sizeof(EjsVar), + sizeof(EjsProperty)); + mprLog(ctx, 0, "GCLink %d\n", sizeof(EjsGCLink)); + mprLog(ctx, 0, "objectState %d\n", (uint) &v.objectState - (uint) &v); +} +#endif + + return service; +} + +/******************************************************************************/ +/* + * Close down the EJS Service + */ + +void ejsCloseService(EjsService *sp, bool doStats) +{ + Ejs *ep; + + mprAssert(sp); + + ep = sp->master; + mprAssert(ep); + + ejsTermSystemClasses(ep); + + if (ep) { + ejsFreeVar(ep, sp->globalClass); + +#if BLD_FEATURE_ALLOC_STATS + if (doStats) { + mprLog(sp, 0, "GC Statistics for the Global Interpreter"); + } +#endif + ejsDestroyInterp(ep, doStats); + } + + mprRemoveKeyValue(sp, "ejsMaster"); + mprRemoveKeyValue(sp, "ejsGlobalClass"); + + mprFree(sp); +} + +/******************************************************************************/ + +Ejs *ejsGetMasterInterp(EjsService *sp) +{ + return sp->master; +} + +/******************************************************************************/ +#if BLD_FEATURE_MULTITHREAD + +int ejsSetServiceLocks(EjsService *sp, EjsLockFn lock, EjsUnlockFn unlock, + void *data) +{ + mprAssert(sp); + + sp->lock = lock; + sp->unlock = unlock; + sp->lockData = data; + return 0; +} + +#endif +/******************************************************************************/ +/* + * Create and initialize an EJS interpreter. Interpreters have a global object + * that has the service global class set as a base class. This way, it + * inherits all the desired global properties, methods and classes. + * + * The primary and alternate handles are provided to C methods depending on + * the flags provided when the C methods are defined. The global variable + * (optionally) defines a predefined global variable space. + */ + +Ejs *ejsCreateInterp(EjsService *sp, void *primaryHandle, void *altHandle, + EjsVar *global, bool useOwnSlab) +{ + EjsProperty *pp; + EjsVar *baseClass; + Ejs *ep; + + ep = mprAllocTypeZeroed(sp, Ejs); + if (ep == 0) { + mprAssert(0); + return ep; + } + + ep->stkPtr = &ep->stack[EJS_MAX_STACK]; + + ep->service = sp; + ep->primaryHandle = primaryHandle; + ep->altHandle = altHandle; + + if (sp->master) { + ep->objectClass = sp->master->objectClass; + } + + if (useOwnSlab) { + ep->slabs = (EjsSlab*) mprAllocZeroed(ep, sizeof(EjsSlab) * + EJS_SLAB_MAX); + ep->slabAllocContext = ep; + + } else { + ep->slabs = sp->master->slabs; + ep->slabAllocContext = sp->master; + ep->flags |= EJS_FLAGS_SHARED_SLAB; + } + + ep->frames = mprCreateItemArray(ep, EJS_INC_FRAMES, EJS_MAX_FRAMES); + if (ep->frames == 0) { + mprFree(ep); + return 0; + } + + ejsGCInit(ep, EJS_OBJ_INC, EJS_PROP_INC, EJS_VAR_INC, EJS_STR_INC); + + if (sp->globalClass == 0) { + /* + * Only do this for the Global interpreter. Create a global class + * (prototype) object. This is base class from which all global + * spaces will inherit. + */ + sp->globalClass = ejsCreateObjVar(ep); + if (sp->globalClass == 0) { + mprFree(ep); + return 0; + } + ejsSetClassName(ep, sp->globalClass, "Global"); + global = sp->globalClass; + } + + if (global) { + /* + * The default interpreter uses the Global class as its global + * space. + */ + ep->global = ejsDupVar(ep, global, EJS_SHALLOW_COPY); + if (ep->global == 0) { + mprFree(ep); + return 0; + } + if (ep->global->objectState != sp->globalClass->objectState) { + ejsSetBaseClass(ep->global, sp->globalClass); + } + + } else { + /* + * Use the global class as our global so we can find the object class + */ + baseClass = ejsGetClass(ep, sp->globalClass, "Object"); + if (baseClass) { + ep->global = ejsCreateSimpleObjUsingClass(ep, baseClass); + if (ep->global == 0) { + mprFree(ep); + return 0; + } + + /* + * Override the base class and set to the master Global class + */ + ejsSetBaseClass(ep->global, sp->globalClass); + + } else { + ep->global = ejsCreateObjVar(ep); + } + } + + /* + * The "global" variable points to the global space + */ + pp = ejsSetProperty(ep, ep->global, "global", ep->global); + if (pp == 0) { + mprFree(ep); + return 0; + } + ejsMakePropertyEnumerable(pp, 0); + + /* + * The "Global" variable points to the Global class + */ + pp = ejsSetProperty(ep, ep->global, "Global", sp->globalClass); + if (pp == 0) { + mprFree(ep); + return 0; + } + ejsMakePropertyEnumerable(pp, 0); + + ep->local = ejsDupVar(ep, ep->global, EJS_SHALLOW_COPY); + if (ep->frames == 0 || ep->global == 0 || ep->local == 0) { + mprFree(ep); + return 0; + } + ejsSetVarName(ep, ep->local, "topLevelLocal"); + + if (mprAddItem(ep->frames, ep->global) < 0 || + mprAddItem(ep->frames, ep->local) < 0) { + mprFree(ep); + return 0; + } + + ep->result = ejsCreateUndefinedVar(ep); + if (ep->result == 0) { + mprFree(ep); + return 0; + } + + return ep; +} + +/******************************************************************************/ +/* + * Close an EJS interpreter + */ + +void ejsDestroyInterp(Ejs *ep, bool doStats) +{ + ejsCleanInterp(ep, doStats); + + mprFree(ep); +} + +/******************************************************************************/ +/* + * Clean an EJS interpreter of all allocated variables, but DONT destroy. + * We use this rather than DestroyInterp so we delay freeing the Ejs struct + * until after the service is closed. + */ + +void ejsCleanInterp(Ejs *ep, bool doStats) +{ + int i; + + if (ep->global) { + ejsDeleteProperty(ep, ep->local, "global"); + ejsDeleteProperty(ep, ep->global, "global"); + ep->global = 0; + } + if (ep->local) { + ejsFreeVar(ep, ep->local); + ep->local = 0; + } + if (ep->global) { + ejsFreeVar(ep, ep->global); + ep->global = 0; + } + if (ep->result) { + ejsFreeVar(ep, ep->result); + ep->result = 0; + } + if (ep->castAlloc && ep->castTemp) { + mprFree(ep->castTemp); + ep->castTemp = 0; + } + if (ep->frames) { + for (i = ep->frames->length - 1; i >= 0; i--) { + mprRemoveItemByIndex(ep->frames, i); + } + mprFree(ep->frames); + ep->frames = 0; + } + + if (doStats) { + +#if BLD_FEATURE_ALLOC_STATS + mprLog(ep, 0, " "); + mprLog(ep, 0, "GC Statistics for Interpreter (0x%X)", (uint) ep); +#endif + + /* + * Cleanup before printing the alloc report + */ + ejsSetGCDebugLevel(ep, 3); + ejsCollectGarbage(ep, -1); + +#if BLD_DEBUG + /* + * If we are the master, dump objects + */ + if (ep->service->master == ep) { + ejsDumpObjects(ep); + } +#endif + +#if BLD_FEATURE_ALLOC_STATS + /* + * Print an alloc report. 1 == do leak report + */ + ejsPrintAllocReport(ep, 1); +#endif + + } else { + /* + * Must collect garbage here incase sharing interpreters with the + * master. If we don't, the mprFree later in DestroyInterp will free + * all memory and when the master does GC --> crash. + */ + ejsCollectGarbage(ep, -1); + } +} + +/******************************************************************************/ +/* + * Evaluate an EJS script file. This will evaluate the script at the current + * context. Ie. if inside a function, declarations will be local. + */ + +int ejsEvalFile(Ejs *ep, const char *path, EjsVar *result) +{ + MprFile *file; + MprFileInfo info; + char *script; + char *saveFileName; + int rc; + + mprAssert(path && *path); + + if ((file = mprOpen(ep, path, O_RDONLY | O_BINARY, 0666)) == 0) { + ejsError(ep, EJS_IO_ERROR, "Can't open %s", path); + return -1; + } + + if (mprGetFileInfo(ep, path, &info) < 0) { + ejsError(ep, EJS_IO_ERROR, "Can't get file info for %s", path); + goto error; + } + + if ((script = (char*) mprAlloc(ep, info.size + 1)) == NULL) { + ejsError(ep, "MemoryError", "Cant malloc %d", (int) info.size); + goto error; + } + + if (mprRead(file, script, info.size) != (int) info.size) { + mprFree(script); + ejsError(ep, EJS_IO_ERROR, "Error reading %s", path); + goto error; + } + mprClose(file); + script[info.size] = '\0'; + + saveFileName = ep->fileName; + ep->fileName = mprStrdup(ep, path); + + rc = ejsEvalScript(ep, script, result); + mprFree(script); + + mprFree(ep->fileName); + ep->fileName = saveFileName; + + return rc; + +/* + * Error return + */ +error: + mprClose(file); + 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(Ejs *ep) +{ + EjsProperty *pp; + int fid; + + ep->local = ejsCreateSimpleObj(ep, "Object"); + ejsSetVarName(ep, ep->local, "local"); + + if (ep->local == 0) { + ejsMemoryError(ep); + return -1; + } + + if (ep->frames->length > EJS_MAX_FRAMES && !ep->gotException) { + ejsError(ep, EJS_RANGE_ERROR, "Recursion too deep: Max depth %d", + EJS_MAX_FRAMES); + return -1; + } + + /* + * Must add to frames before ejsSetProperty which will make the object live + */ + fid = mprAddItem(ep->frames, ep->local); + if (fid < 0) { + ejsMemoryError(ep); + return -1; + } + + /* Self reference */ + pp = ejsSetProperty(ep, ep->local, "local", ep->local); + ejsMakePropertyEnumerable(pp, 0); + + return fid; +} + +/******************************************************************************/ +/* + * Set a new variable scope block. This pushes the old local frame down + * the stack and creates a new local variables frame. + */ + +int ejsSetBlock(Ejs *ep, EjsVar *local) +{ + ep->local = ejsDupVar(ep, local, EJS_SHALLOW_COPY); + ejsMakeObjPermanent(ep->local, 1); + return mprAddItem(ep->frames, ep->local); +} + +/******************************************************************************/ +/* + * Close a variable scope block opened via ejsOpenBlock. Pop back the old + * local variables frame. + */ + +int ejsCloseBlock(Ejs *ep, int fid) +{ + mprAssert(ep->local >= 0); + mprAssert(fid >= 0); + + mprAssert(ep->local == (EjsVar*) mprGetItem(ep->frames, fid)); + + if (ep->local) { + /* Allow GC */ + ejsMakeObjPermanent(ep->local, 0); + ejsFreeVar(ep, ep->local); + } + + mprRemoveItemByIndex(ep->frames, fid); + + ep->local = (EjsVar*) mprGetItem(ep->frames, + mprGetItemCount(ep->frames) - 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 is optional. i.e. created local variables will be discarded + * when this routine returns. + */ + +int ejsEvalBlock(Ejs *ep, char *script, EjsVar *vp) +{ + int rc, fid; + + mprAssert(script); + + fid = ejsOpenBlock(ep); + if (fid < 0) { + return fid; + } + + rc = ejsEvalScript(ep, script, vp); + + ejsCloseBlock(ep, fid); + + return rc; +} + +/******************************************************************************/ +/* + * Parse and evaluate a EJS. The script is evaluated at the current context. + * 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. + */ + +int ejsEvalScript(Ejs *ep, const char *script, EjsVar *vp) +{ + int state; + + ejsClearVar(ep, ep->result); + ep->gotException = 0; + + if (script == 0) { + return 0; + } + + /* + * Allocate a new evaluation block, and save the old one + */ + if (ejsLexOpenScript(ep, script) < 0) { + return MPR_ERR_MEMORY; + } + + /* + * Do the actual parsing and evaluation + */ + ep->scriptStatus = 0; + + do { + state = ejsParse(ep, EJS_STATE_BEGIN, EJS_FLAGS_EXE); + + if (state == EJS_STATE_RET) { + state = EJS_STATE_EOF; + } + } while (state != EJS_STATE_EOF && state != EJS_STATE_ERR); + + ejsLexCloseScript(ep); + + if (state == EJS_STATE_ERR) { + return -1; + } + + if (vp) { + /* Caller must not free. */ + *vp = *ep->result; + } + + return ep->scriptStatus; +} + +/******************************************************************************/ + +void ejsSetFileName(Ejs *ep, const char *fileName) +{ + mprFree(ep->fileName); + ep->fileName = mprStrdup(ep, fileName); +} + +/******************************************************************************/ +/* + * Format the stack backtrace + */ + +char *ejsFormatStack(Ejs* ep) +{ + EjsInput *ip; + char *errbuf; + int frame, len; + + mprAssert(ep); + + ip = ep->input; + + errbuf = 0; + + len = 0; + frame = 0; + while (ip && frame < EJS_MAX_BACKTRACE) { + char *traceLine, *newErrbuf, *line; + for (line = ip->line; *line && isspace(*line); line++) { + ; + } + mprAllocSprintf(MPR_LOC_ARGS(ep), &traceLine, MPR_MAX_STRING, + " [%02d] %s, %s, line %d -> %s\n", + frame++, + ip->fileName ? ip->fileName : "script", + ip->procName ? ip->procName: "global", + ip->lineNumber, line); + if (traceLine == 0) { + break; + } + newErrbuf = mprRealloc(ep, errbuf, len + strlen(traceLine) + 1); + if (newErrbuf == NULL) { + break; + } + errbuf = newErrbuf; + memcpy(&errbuf[len], traceLine, strlen(traceLine) + 1); + len += strlen(traceLine); + mprFree(traceLine); + ip = ip->next; + } + return errbuf; +} + +/******************************************************************************/ +/* + * Internal use method to set the error message + * + * Error, ArgError, AssertError, IOError, MemoryError, RangeError, + * ReferenceError, SyntaxError, TypeError, MemoryError + */ + +void ejsError(Ejs* ep, const char *errorType, const char* fmt, ...) +{ + va_list fmtArgs; + EjsVar *error; + char *msg, *stack; + + va_start(fmtArgs, fmt); + mprAllocVsprintf(MPR_LOC_ARGS(ep), &msg, MPR_MAX_STRING, fmt, fmtArgs); + va_end(fmtArgs); + + /* + * Create a new Error exception object. If bad error type, default to + * "Error" + */ + if (ejsGetClass(ep, 0, errorType) == 0) { + errorType = "Error"; + } + ep->gotException = 1; + + error = ejsCreateObj(ep, 0, errorType, msg); + if (error == 0) { + return; + } + mprFree(msg); + + stack = ejsFormatStack(ep); + ejsSetPropertyToString(ep, error, "stack", stack); + mprFree(stack); + + ejsWriteVar(ep, ep->result, error, EJS_SHALLOW_COPY); + ejsFreeVar(ep, error); +} + +/******************************************************************************/ + +void ejsSyntaxError(Ejs *ep, const char *msg) +{ + if (msg == 0) { + msg = " "; + } + ejsError(ep, EJS_SYNTAX_ERROR, msg); +} + +/******************************************************************************/ + +void ejsMemoryError(Ejs *ep) +{ + ejsError(ep, EJS_MEMORY_ERROR, "Memory allocation error"); +} + +/******************************************************************************/ + +void ejsArgError(Ejs *ep, const char *msg) +{ + mprAssert(msg && *msg); + + ejsError(ep, EJS_ARG_ERROR, msg); +} + +/******************************************************************************/ + +void ejsInternalError(Ejs *ep, const char *msg) +{ + mprAssert(msg && *msg); + + ejsError(ep, EJS_INTERNAL_ERROR, msg); +} + +/******************************************************************************/ +/* + * Public routine to set the error message. Caller MUST NOT free. + */ + +char *ejsGetErrorMsg(Ejs *ep) +{ + EjsVar *error; + const char *message, *stack, *name; + char *buf; + + error = ep->result; + + if (! ejsVarIsObject(error)) { + name = message = stack = 0; + } else { + name = ejsGetPropertyAsString(ep, error, "name"); + message = ejsGetPropertyAsString(ep, error, "message"); + stack = ejsGetPropertyAsString(ep, error, "stack"); + } + if (name == 0 || message == 0) { + buf = mprStrdup(ep, "Unspecified execution error\n"); + } else { + mprAllocSprintf(MPR_LOC_ARGS(ep), &buf, 0, + "%s Exception: %s\nStack:\n%s\n", + name, message, stack ? stack : " " ); + } + mprFree(ep->errorMsg); + ep->errorMsg = buf; + return buf; +} + +/******************************************************************************/ +/* + * Get the current line number + */ + +int ejsGetLineNumber(Ejs *ep) +{ + if (ep->input == 0) { + return -1; + } + return ep->input->lineNumber; +} + +/******************************************************************************/ +/* + * Return the local object + */ + +EjsVar *ejsGetLocalObj(Ejs *ep) +{ + return ep->local; +} + +/******************************************************************************/ +/* + * Return the global object + */ + +EjsVar *ejsGetGlobalObj(Ejs *ep) +{ + return ep->global; +} + +/******************************************************************************/ +/* + * Set the expression return value + */ + +void ejsSetReturnValue(Ejs *ep, EjsVar *vp) +{ + mprAssert(ep); + mprAssert(vp); + + if (vp == 0) { + return; + } + ejsWriteVar(ep, ep->result, vp, EJS_SHALLOW_COPY); +} + +/******************************************************************************/ +/* + * Set the expression return value and free the arg. + */ + +void ejsSetReturnValueAndFree(Ejs *ep, EjsVar *vp) +{ + mprAssert(ep); + mprAssert(vp); + + ejsWriteVar(ep, ep->result, vp, EJS_SHALLOW_COPY); + ejsFreeVar(ep, vp); +} + +/******************************************************************************/ +/* + * Set the expression return value to a string value. + */ + +void ejsSetReturnValueToString(Ejs *ep, const char *value) +{ + mprAssert(ep); + mprAssert(value); + + ejsWriteVarAsString(ep, ep->result, value); +} + +/******************************************************************************/ +/* + * Set the expression return value to a binary string value. + */ + +void ejsSetReturnValueToBinaryString(Ejs *ep, const uchar *value, int len) +{ + mprAssert(ep); + mprAssert(value); + + ejsWriteVarAsBinaryString(ep, ep->result, value, len); +} + +/******************************************************************************/ +/* + * Set the expression return value to a integer value. + */ + +void ejsSetReturnValueToInteger(Ejs *ep, int value) +{ + mprAssert(ep); + + ejsWriteVarAsInteger(ep, ep->result, value); +} + +/******************************************************************************/ +/* + * Set the expression return value to an EjsNum value. + */ + +void ejsSetReturnValueToNumber(Ejs *ep, EjsNum value) +{ + mprAssert(ep); + + ejsWriteVarAsNumber(ep, ep->result, value); +} + +/******************************************************************************/ +/* + * Set the expression return value to a boolean value. + */ + +void ejsSetReturnValueToBoolean(Ejs *ep, int value) +{ + mprAssert(ep); + + ejsWriteVarAsBoolean(ep, ep->result, value); +} + +/******************************************************************************/ +/* + * Set the expression return value to a boolean value. + */ + +void ejsSetReturnValueToUndefined(Ejs *ep) +{ + mprAssert(ep); + + ejsWriteVarAsUndefined(ep, ep->result); +} + +/******************************************************************************/ +/* + * Get the expression return value + */ + +EjsVar *ejsGetReturnValue(Ejs *ep) +{ + mprAssert(ep); + + return ep->result; +} + +/******************************************************************************/ + +void *ejsGetUserData(Ejs *ep) +{ + mprAssert(ep); + + return ep->userData; +} + +/******************************************************************************/ +/* + * Get a variable given a full variable spec possibly containing "." or "[]". + */ + +EjsVar *ejsGetVar(Ejs *ep, const char *fullName) +{ + mprAssert(ep); + mprAssert(fullName && *fullName); + + return ejsFindProperty(ep, 0, 0, ep->global, ep->local, fullName, 0); +} + +/******************************************************************************/ +/* + * Get a string var given a full variable spec possibly containing "." or "[]". + */ + +const char *ejsGetStr(Ejs *ep, const char *fullName, const char *defaultValue) +{ + EjsVar *vp; + + mprAssert(fullName && *fullName); + + vp = ejsFindProperty(ep, 0, 0, ep->global, ep->local, fullName, 0); + if (vp == 0 || !ejsVarIsString(vp)) { + return defaultValue; + } + /* MOB -- what about VarToStr */ + return vp->string; +} + +/******************************************************************************/ +/* + * Get an int var given a full variable spec possibly containing "." or "[]". + */ + +int ejsGetInt(Ejs *ep, const char *fullName, int defaultValue) +{ + EjsVar *vp; + + mprAssert(ep); + mprAssert(fullName && *fullName); + + vp = ejsFindProperty(ep, 0, 0, ep->global, ep->local, fullName, 0); + if (vp == 0 || !ejsVarIsInteger(vp)) { + return defaultValue; + } + /* MOB -- should use VarToInt */ + return vp->integer; +} + +/******************************************************************************/ +/* + * Get an bool var given a full variable spec possibly containing "." or "[]". + */ + +int ejsGetBool(Ejs *ep, const char *fullName, int defaultValue) +{ + EjsVar *vp; + + mprAssert(ep); + mprAssert(fullName && *fullName); + + vp = ejsFindProperty(ep, 0, 0, ep->global, ep->local, fullName, 0); + if (vp == 0 || !ejsVarIsBoolean(vp)) { + return defaultValue; + } + /* MOB -- should use VarToBool */ + return vp->boolean; +} + +/******************************************************************************/ +/* + * Set a variable that may be an arbitrarily complex object or array reference. + * Will always define in the top most variable frame. + */ + +int ejsSetVar(Ejs *ep, const char *fullName, const EjsVar *value) +{ + EjsVar *vp; + + mprAssert(fullName && *fullName); + + vp = ejsFindProperty(ep, 0, 0, ep->global, ep->local, fullName, 1); + if (vp == 0) { + return MPR_ERR_CANT_CREATE; + } + + if (ejsWriteVar(ep, vp, value, EJS_SHALLOW_COPY) == 0) { + return MPR_ERR_CANT_WRITE; + } + + 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 ejsSetStr(Ejs *ep, const char *fullName, const char *value) +{ + EjsVar *vp; + + mprAssert(fullName && *fullName); + + vp = ejsFindProperty(ep, 0, 0, ep->global, ep->local, fullName, 1); + if (vp == 0) { + return MPR_ERR_CANT_CREATE; + } + + if (ejsWriteVarAsString(ep, vp, value) == 0) { + return MPR_ERR_CANT_WRITE; + } + + 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 ejsSetInt(Ejs *ep, const char *fullName, int value) +{ + EjsVar *vp; + + mprAssert(fullName && *fullName); + + vp = ejsFindProperty(ep, 0, 0, ep->global, ep->local, fullName, 1); + if (vp == 0) { + return MPR_ERR_CANT_CREATE; + } + + /* Can't fail */ + ejsWriteVarAsInteger(ep, 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 ejsSetBool(Ejs *ep, const char *fullName, bool value) +{ + EjsVar *vp; + + mprAssert(fullName && *fullName); + + vp = ejsFindProperty(ep, 0, 0, ep->global, ep->local, fullName, 1); + if (vp == 0) { + return MPR_ERR_CANT_CREATE; + } + + /* Can't fail */ + ejsWriteVarAsBoolean(ep, 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. Free the value passed in. + */ + +int ejsSetVarAndFree(Ejs *ep, const char *fullName, EjsVar *value) +{ + EjsVar *vp; + + mprAssert(fullName && *fullName); + + vp = ejsFindProperty(ep, 0, 0, ep->global, ep->local, fullName, 1); + if (vp == 0) { + return MPR_ERR_CANT_CREATE; + } + + if (ejsWriteVar(ep, vp, value, EJS_SHALLOW_COPY) == 0) { + ejsFreeVar(ep, value); + return MPR_ERR_CANT_WRITE; + } + + ejsFreeVar(ep, value); + return 0; +} + +/******************************************************************************/ +/* + * Delete a variable + */ + +int ejsDeleteVar(Ejs *ep, const char *fullName) +{ + EjsVar *vp; + EjsVar *obj; + char *propertyName; + + vp = ejsFindProperty(ep, &obj, &propertyName, ep->global, ep->local, + fullName, 0); + if (vp == 0) { + return -1; + } + + mprAssert(propertyName); + mprAssert(propertyName); + + return ejsDeleteProperty(ep, obj, propertyName); +} + +/******************************************************************************/ +/* + * 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) { + * // Insufficient args + * return -1; + * } + */ + +int ejsParseArgs(int argc, char **argv, const char *fmt, ...) +{ + va_list vargs; + const char *cp; + char **sp, *s; + int *bp, *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, int*); + 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; +} + +/******************************************************************************/ +/* + * Define the standard classes + */ + +int ejsDefineStandardClasses(Ejs *master) +{ + if (ejsDefineArrayClass(master) != 0 || + ejsDefineBooleanClass(master) != 0 || + ejsDefineErrorClasses(master) != 0 || + ejsDefineFunctionClass(master) != 0 || + ejsDefineNumberClass(master) != 0 || +#if FUTURE + ejsDefineDateClass(master) != 0 || +#endif +#if BLD_FEATURE_EJS_E4X + ejsDefineXmlClasses(master) != 0 || +#endif +#if BLD_FEATURE_EJS_DB && NOT_HERE + ejsDefineDbClasses(master) != 0 || +#endif + ejsDefineStringClass(master) != 0) { + return MPR_ERR_MEMORY; + } + return 0; +} + +/******************************************************************************/ +/* + * Define the EJS System Object Model + */ + +int ejsDefineSystemClasses(Ejs *master) +{ + if (ejsDefineSystemClass(master) != 0 || + ejsDefineAppClass(master) != 0 || + ejsDefineMemoryClass(master) != 0 || + ejsDefineLogClass(master) != 0 || + ejsDefineDebugClass(master) != 0 || + ejsDefineGCClass(master) != 0 || + ejsDefineFileSystemClass(master) != 0 || +#if BREW + ejsDefineFileClass(master) != 0 || + ejsDefineHTTPClass(master) != 0 || +#endif + ejsDefineGlobalProperties(master) != 0) { + return MPR_ERR_MEMORY; + } + return 0; +} + +/******************************************************************************/ +/* + * Terminate the system object model and classes + */ + +int ejsTermSystemClasses(Ejs *master) +{ +#if BREW + ejsTermHTTPClass(master); +#endif + return 0; +} + +/******************************************************************************/ +/* + * Define the EJS object model + */ + +int ejsCreateObjectModel(Ejs *ejs) +{ + EjsProperty *pp; + + pp = ejsSetPropertyToNewObj(ejs, ejs->global, "system", "System", 0); + if (pp == 0) { + return MPR_ERR_MEMORY; + } + + if (ejsSetPropertyToNewObj(ejs, ejsGetVarPtr(pp), "app", "System.App", + 0) == 0) { + return MPR_ERR_MEMORY; + } + return 0; +} + +/******************************************************************************/ + +void ejsTrace(Ejs *ep, const char *fmt, ...) +{ + va_list args; + char buf[MPR_MAX_LOG_STRING]; + int len; + + va_start(args, fmt); + len = mprVsprintf(buf, sizeof(buf) - 1, fmt, args); + va_end(args); + + mprLog(ep, 0, buf, len); + + va_end(args); +} + +/******************************************************************************/ + +bool ejsGotException(Ejs *ep) +{ + return (bool) ep->gotException; +} + +/******************************************************************************/ + +void ejsSetPrimaryHandle(Ejs *ep, void *primaryHandle) +{ + mprAssert(ep); + + ep->primaryHandle = primaryHandle; +} + +/******************************************************************************/ + +void ejsSetAlternateHandle(Ejs *ep, void *alternateHandle) +{ + mprAssert(ep); + + ep->altHandle = alternateHandle; +} + +/******************************************************************************/ + +#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 + */ |