1
0
mirror of https://github.com/samba-team/samba.git synced 2025-12-17 04:23:50 +03:00
Files
samba-mirror/source/lib/appweb/ejs-2.0/ejs/ejs.c

1379 lines
30 KiB
C

/*
* @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
*/