/* Update an existing element */ static int updateElement(Ejs *ejs, EjsXML *list, EjsXML *elt, int index, EjsObj *value) { EjsXML *node; int i, j; if (!ejsIsXML(ejs, value)) { /* Not XML or XMLList -- convert to string */ value = ejsCast(ejs, value, String); // TODO - seem to be doing this in too many places } mprSetItem(list->elements, index, value); if (elt->kind == EJS_XML_ATTRIBUTE) { assure(ejsIs(ejs, value, String)); i = mprLookupItem(elt->parent->elements, elt); assure(i >= 0); ejsSetXMLElement(ejs, elt->parent, i, elt); // TODO - why do this. Doesn't above do this? ejsSetPropertyByName(ejs, elt->parent, elt->qname, value); elt->value = (EjsString*) value; } if (ejsIsXML(ejs, value) && ((EjsXML*) value)->kind == EJS_XML_LIST) { value = (EjsObj*) shallowCopy(ejs, (EjsXML*) value); if (elt->parent) { index = mprLookupItem(elt->parent->elements, elt); assure(index >= 0); for (j = 0; j < mprGetListLength(((EjsXML*) value)->elements); j++) { mprInsertItemAtPos(elt->parent->elements, index, value); } } } else if (ejsIsXML(ejs, value) || elt->kind != EJS_XML_ELEMENT) { if (elt->parent) { index = mprLookupItem(elt->parent->elements, elt); assure(index >= 0); mprSetItem(elt->parent->elements, index, value); ((EjsXML*) value)->parent = elt->parent; if (ejsIs(ejs, value, String)) { node = ejsCreateXML(ejs, EJS_XML_TEXT, N(NULL, NULL), list, (EjsString*) value); mprSetItem(list->elements, index, node); } else { mprSetItem(list->elements, index, value); } } } else { ejsSetPropertyByName(ejs, elt, N(NULL, "*"), value); } return index; }
static int blendEnv(MprCmd *cmd, cchar **env, int flags) { cchar **ep, *prior; int next; cmd->env = 0; if ((cmd->env = mprCreateList(128, MPR_LIST_STATIC_VALUES | MPR_LIST_STABLE)) == 0) { return MPR_ERR_MEMORY; } #if !VXWORKS /* Add prior environment to the list */ if (!(flags & MPR_CMD_EXACT_ENV)) { for (ep = (cchar**) environ; ep && *ep; ep++) { #if MACOSX if (sstarts(*ep, "DYLD_LIBRARY_PATH=")) { continue; } #endif mprAddItem(cmd->env, *ep); } } #endif /* Add new env keys. Detect and overwrite duplicates */ for (ep = env; ep && *ep; ep++) { prior = 0; for (ITERATE_ITEMS(cmd->env, prior, next)) { if (matchEnvKey(*ep, prior)) { mprSetItem(cmd->env, next - 1, *ep); break; } } if (prior == 0) { mprAddItem(cmd->env, *ep); } } #if ME_WIN_LIKE /* Windows requires a caseless sort with two trailing nulls */ mprSortList(cmd->env, (MprSortProc) sortEnv, 0); #endif mprAddItem(cmd->env, NULL); return 0; }
PUBLIC int mprNotifyOn(MprWaitHandler *wp, int mask) { MprWaitService *ws; struct epoll_event ev; int fd, rc; assert(wp); fd = wp->fd; ws = wp->service; lock(ws); if (wp->desiredMask != mask) { memset(&ev, 0, sizeof(ev)); ev.data.fd = fd; if (wp->desiredMask & MPR_READABLE) { ev.events |= EPOLLIN | EPOLLHUP; } if (wp->desiredMask & MPR_WRITABLE) { ev.events |= EPOLLOUT; } if (wp->desiredMask == (MPR_READABLE | MPR_WRITABLE)) { ev.events |= EPOLLHUP; } if (ev.events) { if ((rc = epoll_ctl(ws->epoll, EPOLL_CTL_DEL, fd, &ev)) != 0) { mprLog("error mpr event", 0, "Epoll delete error %d on fd %d", errno, fd); } } ev.events = 0; if (mask & MPR_READABLE) { ev.events |= (EPOLLIN | EPOLLHUP); } if (mask & MPR_WRITABLE) { ev.events |= EPOLLOUT | EPOLLHUP; } if (ev.events) { if ((rc = epoll_ctl(ws->epoll, EPOLL_CTL_ADD, fd, &ev)) != 0) { mprLog("error mpr event", 0, "Epoll add error %d on fd %d", errno, fd); } } wp->desiredMask = mask; mprSetItem(ws->handlerMap, fd, mask ? wp : 0); } unlock(ws); return 0; }
/* Set an indexed element to an XML value */ PUBLIC EjsXML *ejsSetXMLElement(Ejs *ejs, EjsXML *xml, int index, EjsXML *node) { EjsXML *old; if (xml == 0 || node == 0) { return 0; } if (xml->elements == 0) { xml->elements = mprCreateList(-1, 0); } else { old = (EjsXML*) mprGetItem(xml->elements, index); if (old && old != node) { old->parent = 0; } } if (xml->kind != EJS_XML_LIST) { node->parent = xml; } mprSetItem(xml->elements, index, node); return xml; }
MAIN(ejsMain, int argc, char **argv, char **envp) { Mpr *mpr; EcCompiler *cp; Ejs *ejs; cchar *cmd, *className, *method, *homeDir; char *argp, *searchPath, *modules, *name, *tok, *extraFiles; int nextArg, err, ecFlags, stats, merge, bind, noout, debug, optimizeLevel, warnLevel, strict, i, next; /* Initialize Multithreaded Portable Runtime (MPR) */ mpr = mprCreate(argc, argv, 0); app = mprAllocObj(App, manageApp); mprAddRoot(app); mprAddStandardSignals(); if (mprStart(mpr) < 0) { mprError("Cannot start mpr services"); return EJS_ERR; } err = 0; className = 0; cmd = 0; method = 0; searchPath = 0; stats = 0; merge = 0; bind = 1; noout = 1; debug = 1; warnLevel = 1; optimizeLevel = 9; strict = 0; app->files = mprCreateList(-1, 0); app->iterations = 1; argc = mpr->argc; argv = (char**) mpr->argv; for (nextArg = 1; nextArg < argc; nextArg++) { argp = argv[nextArg]; if (*argp != '-') { break; } if (smatch(argp, "--bind")) { bind = 1; } else if (smatch(argp, "--class")) { if (nextArg >= argc) { err++; } else { className = argv[++nextArg]; } } else if (smatch(argp, "--chdir") || smatch(argp, "--home") || smatch(argp, "-C")) { if (nextArg >= argc) { err++; } else { homeDir = argv[++nextArg]; if (chdir((char*) homeDir) < 0) { mprError("Cannot change directory to %s", homeDir); } } #if BIT_UNIX_LIKE } else if (smatch(argp, "--chroot")) { /* Not documented or supported */ if (nextArg >= argc) { err++; } else { homeDir = mprGetAbsPath(argv[++nextArg]); if (chroot(homeDir) < 0) { if (errno == EPERM) { mprPrintfError("%s: Must be super user to use the --chroot option", mprGetAppName(mpr)); } else { mprPrintfError("%s: Cannot change change root directory to %s, errno %d", mprGetAppName(), homeDir, errno); } return 4; } } #endif } else if (smatch(argp, "--cmd") || smatch(argp, "-c")) { if (nextArg >= argc) { err++; } else { cmd = argv[++nextArg]; } #if BIT_WIN_LIKE } else if (smatch(argp, "--cygroot")) { if (nextArg >= argc) { err++; } else { app->cygroot = sclone(argv[++nextArg]); } #endif } else if (smatch(argp, "--debug")) { debug = 1; } else if (smatch(argp, "--debugger") || smatch(argp, "-D")) { mprSetDebugMode(1); } else if (smatch(argp, "--files") || smatch(argp, "-f")) { /* Compatibility with mozilla shell */ if (nextArg >= argc) { err++; } else { extraFiles = sclone(argv[++nextArg]); name = stok(extraFiles, " \t", &tok); while (name != NULL) { mprAddItem(app->files, sclone(name)); name = stok(NULL, " \t", &tok); } } } else if (smatch(argp, "--iterations") || smatch(argp, "-i")) { if (nextArg >= argc) { err++; } else { app->iterations = atoi(argv[++nextArg]); } } else if (smatch(argp, "--log")) { if (nextArg >= argc) { err++; } else { mprStartLogging(argv[++nextArg], 0); mprSetCmdlineLogging(1); } } else if (smatch(argp, "--method")) { if (nextArg >= argc) { err++; } else { method = argv[++nextArg]; } } else if (smatch(argp, "--name")) { /* Just ignore. Used to tag commands with a unique command line */ nextArg++; } else if (smatch(argp, "--nobind")) { bind = 0; } else if (smatch(argp, "--nodebug")) { debug = 0; } else if (smatch(argp, "--optimize")) { if (nextArg >= argc) { err++; } else { optimizeLevel = atoi(argv[++nextArg]); } } else if (smatch(argp, "-s")) { /* Compatibility with mozilla shell. Just ignore */ } else if (smatch(argp, "--search") || smatch(argp, "--searchpath")) { if (nextArg >= argc) { err++; } else { searchPath = argv[++nextArg]; } } else if (smatch(argp, "--standard")) { strict = 0; } else if (smatch(argp, "--stats")) { stats = 1; } else if (smatch(argp, "--strict")) { strict = 1; } else if (smatch(argp, "--require")) { if (nextArg >= argc) { err++; } else { if (app->modules == 0) { app->modules = mprCreateList(-1, 0); } modules = sclone(argv[++nextArg]); name = stok(modules, " \t", &tok); while (name != NULL) { require(name); name = stok(NULL, " \t", &tok); } } } else if (smatch(argp, "--verbose") || smatch(argp, "-v")) { mprStartLogging("stderr:2", 0); mprSetCmdlineLogging(1); } else if (smatch(argp, "--version") || smatch(argp, "-V")) { mprPrintf("%s-%s\n", BIT_VERSION, BIT_BUILD_NUMBER); return 0; } else if (smatch(argp, "--warn")) { if (nextArg >= argc) { err++; } else { warnLevel = atoi(argv[++nextArg]); } } else { err++; break; } } if (err) { /* If --method or --class is specified, then the named class.method will be run (method defaults to "main", class defaults to first class with a "main"). Examples: ejs ejs script.es arg1 arg2 arg3 ejs --class "Customer" --method "start" --files "script1.es script2.es" main.es */ mprPrintfError("Usage: %s [options] script.es [arguments] ...\n" " Ejscript shell program options:\n" " --class className # Name of class containing method to run\n" " --cmd ejscriptCode # Literal ejscript statements to execute\n" " --cygroot path # Set cygwin root for resolving script paths\n" " --debug # Use symbolic debugging information (default)\n" " --debugger # Disable timeouts to make using a debugger easier\n" " --files \"files..\" # Extra source to compile\n" " --log logSpec # Internal compiler diagnostics logging\n" " --method methodName # Name of method to run. Defaults to main\n" " --nodebug # Omit symbolic debugging information\n" " --optimize level # Set the optimization level (0-9 default is 9)\n" " --require 'module,...' # Required list of modules to pre-load\n" " --search ejsPath # Module search path\n" " --standard # Default compilation mode to standard (default)\n" " --stats # Print memory stats on exit\n" " --strict # Default compilation mode to strict\n" " --verbose | -v # Same as --log stderr:2 \n" " --version # Emit the compiler version information\n" " --warn level # Set the warning message level (0-9 default is 0)\n\n", mpr->name); return -1; } if ((ejs = ejsCreateVM(argc - nextArg, (cchar **) &argv[nextArg], 0)) == 0) { return MPR_ERR_MEMORY; } app->ejs = ejs; if (ejsLoadModules(ejs, searchPath, app->modules) < 0) { return MPR_ERR_CANT_READ; } ecFlags = 0; ecFlags |= (merge) ? EC_FLAGS_MERGE: 0; ecFlags |= (bind) ? EC_FLAGS_BIND: 0; ecFlags |= (noout) ? EC_FLAGS_NO_OUT: 0; ecFlags |= (debug) ? EC_FLAGS_DEBUG: 0; cp = app->compiler = ecCreateCompiler(ejs, ecFlags); if (cp == 0) { return MPR_ERR_MEMORY; } ecSetRequire(cp, app->modules); ecSetOptimizeLevel(cp, optimizeLevel); ecSetWarnLevel(cp, warnLevel); ecSetStrictMode(cp, strict); if (nextArg < argc) { mprAddItem(app->files, sclone(argv[nextArg])); } if (app->cygroot) { /* When cygwin invokes a script with shebang, it passes a cygwin path to the script The ejs --cygroot option permits ejscript to conver this to a native path */ for (next = 0; (name = mprGetNextItem(app->files, &next)) != 0; ) { if (*name == '/' || *name == '\\') { mprSetItem(app->files, next - 1, sjoin(app->cygroot, name, NULL)); } } } for (i = 0; !err && i < app->iterations; i++) { if (cmd) { if (interpretCommands(cp, cmd) < 0) { err++; } } else if (mprGetListLength(app->files) > 0) { if (interpretFiles(cp, app->files, argc - nextArg, &argv[nextArg], className, method) < 0) { err++; } } else { /* No args - run as an interactive shell */ if (interpretCommands(cp, NULL) < 0) { err++; } } } if (stats) { #if BIT_DEBUG mprSetLogLevel(1); mprPrintMem("Memory Usage", 1); #endif } if (!err) { err = mpr->exitStatus; } app->ejs = 0; mprTerminate(MPR_EXIT_DEFAULT, err); ejsDestroyVM(ejs); mprDestroy(MPR_EXIT_DEFAULT); return err; }
/* Set a property attribute by name. */ static int setXmlPropertyAttributeByName(Ejs *ejs, EjsXML *xml, EjsName qname, EjsObj *value) { EjsXML *elt, *attribute, *xvalue, *lastElt; EjsString *sv; EjsName qn; wchar *str; int index, last, next; /* Attribute. If the value is an XML list, convert to a space separated string */ xvalue = (EjsXML*) value; if (ejsIsXML(ejs, xvalue) && xvalue->kind == EJS_XML_LIST) { str = 0; for (next = 0; (elt = mprGetNextItem(xvalue->elements, &next)) != 0; ) { sv = (EjsString*) ejsCast(ejs, (EjsObj*) elt, String); str = mrejoin(str, NULL, " ", sv->value, NULL); } value = (EjsObj*) ejsCreateString(ejs, str, -1); } else { value = ejsCast(ejs, value, String); } assert(ejsIs(ejs, value, String)); /* Find the first attribute that matches. Delete all other attributes of the same name. */ index = 0; if (xml->attributes) { lastElt = 0; for (last = -1, index = -1; (elt = mprGetPrevItem(xml->attributes, &index)) != 0; ) { assert(qname.name->value[0] == '@'); if (wcmp(elt->qname.name->value, &qname.name->value[1]) == 0) { if (last >= 0) { mprRemoveItemAtPos(xml->attributes, last); } last = index; lastElt = elt; } } if (lastElt) { /* Found a match. So replace its value */ lastElt->value = (EjsString*) value; return last; } else { index = mprGetListLength(xml->attributes); } } // TODO - namespace work to do here /* Not found. Create a new attribute node */ assert(ejsIs(ejs, value, String)); qn.space = NULL; qn.name = ejsSubstring(ejs, qname.name, 1, -1); attribute = ejsCreateXML(ejs, EJS_XML_ATTRIBUTE, qn, xml, (EjsString*) value); if (xml->attributes == 0) { xml->attributes = mprCreateList(-1, 0); } mprSetItem(xml->attributes, index, attribute); return index; }
static EjsXML *createElement(Ejs *ejs, EjsXML *list, EjsXML *targetObject, EjsName qname, EjsObj *value) { EjsXML *elt, *last, *attList; int index; int j; if (targetObject && ejsIsXML(ejs, targetObject) && targetObject->kind == EJS_XML_LIST) { /* If the target is a list it must have 1 element. So switch to it. TODO - could we get resolve to do this? */ if (mprGetListLength(targetObject->elements) != 1) { /* Spec says so - TODO why no error? */ return 0; } targetObject = mprGetFirstItem(targetObject->elements); } /* Return if the target object is not an XML element */ if (!ejsIsXML(ejs, targetObject) || targetObject->kind != EJS_XML_ELEMENT) { /* Spec says so - TODO why no error? */ return 0; } elt = ejsCreateXML(ejs, EJS_XML_ELEMENT, list->targetProperty, targetObject, NULL); if (list->targetProperty.name && list->targetProperty.name->value[0] == '@') { elt->kind = EJS_XML_ATTRIBUTE; attList = ejsGetPropertyByName(ejs, (EjsObj*) targetObject, list->targetProperty); if (attList && mprGetListLength(attList->elements) > 0) { /* Spec says so. But this surely means you can't update an attribute? */ return 0; } } else if (list->targetProperty.name == NULL || qname.name->value[0] == '*') { elt->kind = EJS_XML_TEXT; elt->qname.name = 0; } index = mprGetListLength(list->elements); if (elt->kind != EJS_XML_ATTRIBUTE) { if (targetObject) { if (index > 0) { /* Find the place of the last list item in the resolved target object. */ last = mprGetItem(list->elements, index - 1); j = mprLookupItem(targetObject->elements, last); } else { j = -1; } if (j < 0) { j = mprGetListLength(targetObject->elements) - 1; } // TODO - really need to wrap this ejsInsertXML(EjsXML *xml, int index, EjsXML *node) if (targetObject->elements == 0) { targetObject->elements = mprCreateList(-1, 0); } /* Insert into the target object */ mprInsertItemAtPos(targetObject->elements, j + 1, elt); } if (ejsIsXML(ejs, value)) { if (((EjsXML*) value)->kind == EJS_XML_LIST) { elt->qname = ((EjsXML*) value)->targetProperty; } else { elt->qname = ((EjsXML*) value)->qname; } } /* Insert into the XML list */ mprSetItem(list->elements, index, elt); } return (EjsXML*) mprGetItem(list->elements, index); }