ejslib.c
来自「samba最新软件」· C语言 代码 · 共 1,091 行 · 第 1/2 页
C
1,091 行
/* * @file ejs.c * @brief Embedded JavaScript (EJS) * @overview Main module interface logic. *//********************************* Copyright **********************************//* * @copy default.g * * Copyright (c) Mbedthis Software LLC, 2003-2005. All Rights Reserved. * Portions Copyright (c) GoAhead Software, 1995-2000. All Rights Reserved. * * This software is distributed under commercial and open source licenses. * You may use the GPL open source license described below or you may acquire * a commercial license from Mbedthis Software. You agree to be fully bound * by the terms of either license. Consult the LICENSE.TXT distributed with * this software for full details. * * This software is open source; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the * Free Software Foundation; either version 2 of the License, or (at your * option) any later version. See the GNU General Public License for more * details at: http://www.mbedthis.com/downloads/gplLicense.html * * This program is distributed WITHOUT ANY WARRANTY; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * * This GPL license does NOT permit incorporating this software into * proprietary programs. If you are unable to comply with the GPL, you must * acquire a commercial license to use this software. Commercial licenses * for this software and support services are available from Mbedthis * Software at http://www.mbedthis.com * * @end *//********************************** Includes **********************************/#include "ejsInternal.h"#if BLD_FEATURE_EJS/********************************** Local Data ********************************//* * These fields must be locked before any access when multithreaded */static MprVar master; /* Master object */static MprArray *ejsList; /* List of ej handles */#if BLD_FEATURE_MULTITHREADstatic EjsLock lock;static EjsUnlock unlock;static void *lockData;#define ejsLock() if (lock) { (lock)(lockData); } else#define ejsUnlock() if (unlock) { (unlock)(lockData); } else#else#define ejsLock() #define ejsUnlock() #endif/* save/restore global ejs state - used to cope with simultaneous ejs requests this is a workaround for the use of global variables in ejs*/struct ejs_state_ctx { MprVar master; MprArray *ejsList;};void *ejs_save_state(void){ struct ejs_state_ctx *ctx = talloc(talloc_autofree_context(), struct ejs_state_ctx); ctx->master = master; ctx->ejsList = ejsList; return ctx;}void ejs_restore_state(void *ptr){ struct ejs_state_ctx *ctx = talloc_get_type(ptr, struct ejs_state_ctx); master = ctx->master; ejsList = ctx->ejsList; talloc_free(ctx);}/****************************** Forward Declarations **************************/static char *getNextVarToken(char **next, char *tokBuf, int tokBufLen);/************************************* Code ***********************************//* * Initialize the EJ subsystem */int ejsOpen(EjsLock lockFn, EjsUnlock unlockFn, void *data){ MprVar *np;#if BLD_FEATURE_MULTITHREAD if (lockFn) { lock = lockFn; unlock = unlockFn; lockData = data; }#endif ejsLock(); /* * Master is the top level object (above global). It is used to clone its * contents into the global scope for each. This is never visible to the * user, so don't use ejsCreateObj(). */ master = mprCreateObjVar("master", EJS_SMALL_OBJ_HASH_SIZE); if (master.type == MPR_TYPE_UNDEFINED) { ejsUnlock(); return MPR_ERR_CANT_ALLOCATE; } ejsList = mprCreateArray(); ejsDefineStandardProperties(&master); /* * Make these objects immutable */ np = mprGetFirstProperty(&master, MPR_ENUM_FUNCTIONS | MPR_ENUM_DATA); while (np) { mprSetVarReadonly(np, 1); np = mprGetNextProperty(&master, np, MPR_ENUM_FUNCTIONS | MPR_ENUM_DATA); } ejsUnlock(); return 0;}/******************************************************************************/void ejsClose(){ ejsLock(); mprDestroyArray(ejsList); mprDestroyVar(&master); ejsUnlock();}/******************************************************************************//* * Create and initialize an EJS engine */EjsId ejsOpenEngine(EjsHandle primaryHandle, EjsHandle altHandle){ MprVar *np; Ejs *ep; ep = (Ejs *)mprMalloc(sizeof(Ejs)); if (ep == 0) { return (EjsId) -1; } memset(ep, 0, sizeof(Ejs)); ejsLock(); ep->eid = (EjsId) mprAddToArray(ejsList, ep); ejsUnlock(); /* * Create array of local variable frames */ ep->frames = mprCreateArray(); if (ep->frames == 0) { ejsCloseEngine(ep->eid); return (EjsId) -1; } ep->primaryHandle = primaryHandle; ep->altHandle = altHandle; /* * Create first frame: global variables */ ep->global = (MprVar*) mprMalloc(sizeof(MprVar)); *ep->global = ejsCreateObj("global", EJS_OBJ_HASH_SIZE); if (ep->global->type == MPR_TYPE_UNDEFINED) { ejsCloseEngine(ep->eid); return (EjsId) -1; } mprAddToArray(ep->frames, ep->global); /* * Create first local variable frame */ ep->local = (MprVar*) mprMalloc(sizeof(MprVar)); *ep->local = ejsCreateObj("local", EJS_OBJ_HASH_SIZE); if (ep->local->type == MPR_TYPE_UNDEFINED) { ejsCloseEngine(ep->eid); return (EjsId) -1; } mprAddToArray(ep->frames, ep->local); /* * Clone all master variables into the global frame. This does a * reference copy. * * ejsDefineStandardProperties(ep->global); */ np = mprGetFirstProperty(&master, MPR_ENUM_FUNCTIONS | MPR_ENUM_DATA); while (np) { mprCreateProperty(ep->global, np->name, np); np = mprGetNextProperty(&master, np, MPR_ENUM_FUNCTIONS | MPR_ENUM_DATA); } mprCreateProperty(ep->global, "global", ep->global); mprCreateProperty(ep->global, "this", ep->global); mprCreateProperty(ep->local, "local", ep->local); return ep->eid;}/******************************************************************************//* * Close an EJS instance */void ejsCloseEngine(EjsId eid){ Ejs *ep; MprVar *vp; void **handles; int i; if ((ep = ejsPtr(eid)) == NULL) { mprAssert(ep); return; } mprFree(ep->error); mprDestroyVar(&ep->result); mprDestroyVar(&ep->tokenNumber); if (ep->local) { mprDeleteProperty(ep->local, "local"); } mprDeleteProperty(ep->global, "this"); mprDeleteProperty(ep->global, "global"); handles = ep->frames->handles; for (i = 0; i < ep->frames->max; i++) { vp = handles[i]; if (vp) {#if BLD_DEBUG if (vp->type == MPR_TYPE_OBJECT && vp->properties->refCount > 1) { mprLog(7, "ejsCloseEngine: %s has ref count %d\n", vp->name, vp->properties->refCount); }#endif mprDestroyVar(vp); mprFree(vp); mprRemoveFromArray(ep->frames, i); } } mprDestroyArray(ep->frames); ejsLock(); mprRemoveFromArray(ejsList, (int) ep->eid); ejsUnlock(); mprFree(ep);}/******************************************************************************//* * Evaluate an EJS script file */int ejsEvalFile(EjsId eid, char *path, MprVar *result, char **emsg){ struct stat sbuf; Ejs *ep; char *script; int rc, fd; mprAssert(path && *path); if (emsg) { *emsg = NULL; } if ((ep = ejsPtr(eid)) == NULL) { mprAssert(ep); goto error; } if ((fd = open(path, O_RDONLY | O_BINARY, 0666)) < 0) { ejsError(ep, "Can't open %s\n", path); goto error; } if (stat(path, &sbuf) < 0) { close(fd); ejsError(ep, "Cant stat %s", path); goto error; } if ((script = (char*) mprMalloc(sbuf.st_size + 1)) == NULL) { close(fd); ejsError(ep, "Cant malloc %d", (int) sbuf.st_size); goto error; } if (read(fd, script, sbuf.st_size) != (int) sbuf.st_size) { close(fd); mprFree(script); ejsError(ep, "Error reading %s", path); goto error; } script[sbuf.st_size] = '\0'; close(fd); rc = ejsEvalBlock(eid, script, result, emsg); mprFree(script); return rc;/* * Error return */error: if(emsg) *emsg = mprStrdup(ep->error); return -1;}/******************************************************************************//* * Create a new variable scope block. This pushes the old local frame down * the stack and creates a new local variables frame. */int ejsOpenBlock(EjsId eid){ Ejs *ep; if((ep = ejsPtr(eid)) == NULL) { return -1; } ep->local = (MprVar*) mprMalloc(sizeof(MprVar)); *ep->local = ejsCreateObj("localBlock", EJS_OBJ_HASH_SIZE); mprCreateProperty(ep->local, "local", ep->local); return mprAddToArray(ep->frames, ep->local);}/******************************************************************************//* * Close a variable scope block opened via ejsOpenBlock. Pop back the old * local variables frame. */int ejsCloseBlock(EjsId eid, int fid){ Ejs *ep; if((ep = ejsPtr(eid)) == NULL) { mprAssert(ep); return -1; } /* * Must remove self-references before destroying "local" */ mprDeleteProperty(ep->local, "local"); mprDestroyVar(ep->local); mprFree(ep->local); mprRemoveFromArray(ep->frames, fid); ep->local = (MprVar*) ep->frames->handles[ep->frames->used - 1]; return 0;}/******************************************************************************//* * Create a new variable scope block and evaluate a script. All frames * created during this context will be automatically deleted when complete. * vp and emsg are optional. i.e. created local variables will be discarded * when this routine returns. */int ejsEvalBlock(EjsId eid, char *script, MprVar *vp, char **emsg){ int rc, fid; mprAssert(script); fid = ejsOpenBlock(eid); rc = ejsEvalScript(eid, script, vp, emsg); ejsCloseBlock(eid, fid); return rc;}/******************************************************************************//* * Parse and evaluate a EJS. Return the result in *vp. The result is "owned" * by EJ and the caller must not free it. Returns -1 on errors and zero * for success. On errors, emsg will be set to the reason. The caller must * free emsg. */int ejsEvalScript(EjsId eid, char *script, MprVar *vp, char **emsg){ Ejs *ep; int state; void *endlessLoopTest; int loopCounter; if (emsg) { *emsg = NULL; } if ((ep = ejsPtr(eid)) == NULL) { mprAssert(ep); return -1; } mprDestroyVar(&ep->result); if (script == 0) { return 0; } /* * Allocate a new evaluation block, and save the old one */ ejsLexOpenScript(ep, script); /* * Do the actual parsing and evaluation */ loopCounter = 0; endlessLoopTest = NULL; ep->exitStatus = 0; do { state = ejsParse(ep, EJS_STATE_BEGIN, EJS_FLAGS_EXE); if (state == EJS_STATE_RET) { state = EJS_STATE_EOF; } /* * Stuck parser and endless recursion protection. */ if (endlessLoopTest == ep->input->scriptServp) { if (loopCounter++ > 10) { state = EJS_STATE_ERR; ejsError(ep, "Syntax error"); } } else { endlessLoopTest = ep->input->scriptServp; loopCounter = 0; } } while (state != EJS_STATE_EOF && state != EJS_STATE_ERR); ejsLexCloseScript(ep); /* * Return any error string to the user */ if (state == EJS_STATE_ERR && emsg) { *emsg = mprStrdup(ep->error); } if (state == EJS_STATE_ERR) { return -1; } if (vp) { *vp = ep->result; } return ep->exitStatus;}/******************************************************************************//* * Core error handling */static void ejsErrorCore(Ejs* ep, const char *fmt, va_list args) PRINTF_ATTRIBUTE(2, 0);static void ejsErrorCore(Ejs* ep, const char *fmt, va_list args){ EjsInput *ip; char *errbuf, *msgbuf; int frame = 0; mprAssert(ep); msgbuf = NULL; mprAllocVsprintf(&msgbuf, MPR_MAX_STRING, fmt, args); ip = ep->input; mprAllocSprintf(&errbuf, MPR_MAX_STRING, "%s\nBacktrace:\n", msgbuf); /* form a backtrace */ while (ip) { char *msg2, *ebuf2; mprAllocSprintf(&msg2, MPR_MAX_STRING, "\t[%2d] %20s:%-4d -> %s\n", frame++, ip->procName?ip->procName:"", ip->lineNumber, ip->line); ebuf2 = mprRealloc(errbuf, strlen(errbuf) + strlen(msg2) + 1); if (ebuf2 == NULL) break; errbuf = ebuf2; memcpy(errbuf+strlen(errbuf), msg2, strlen(msg2)+1); mprFree(msg2); ip = ip->next; } mprFree(ep->error); ep->error = errbuf; mprFree(msgbuf);}/******************************************************************************//* * Internal use function to set the error message */void ejsError(Ejs* ep, const char* fmt, ...){ va_list args; va_start(args, fmt); ejsErrorCore(ep, fmt, args); va_end(args);}/******************************************************************************//* * Public routine to set the error message */
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?