summaryrefslogtreecommitdiff
path: root/source4/lib/appweb/ejs-2.0/ejs/ejs.c
diff options
context:
space:
mode:
Diffstat (limited to 'source4/lib/appweb/ejs-2.0/ejs/ejs.c')
-rw-r--r--source4/lib/appweb/ejs-2.0/ejs/ejs.c1378
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
+ */