📄 ejs.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_MULTITHREADint 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);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -