r9173: catch ep->local being NULL
[Samba/aatanasov.git] / source4 / lib / appweb / ejs / ejsLib.c
blobb24b2b013ce378249614ec0b01b11cd2f041cf57
1 /*
2 * @file ejs.c
3 * @brief Embedded JavaScript (EJS)
4 * @overview Main module interface logic.
5 */
6 /********************************* Copyright **********************************/
7 /*
8 * @copy default.g
9 *
10 * Copyright (c) Mbedthis Software LLC, 2003-2005. All Rights Reserved.
11 * Portions Copyright (c) GoAhead Software, 1995-2000. All Rights Reserved.
13 * This software is distributed under commercial and open source licenses.
14 * You may use the GPL open source license described below or you may acquire
15 * a commercial license from Mbedthis Software. You agree to be fully bound
16 * by the terms of either license. Consult the LICENSE.TXT distributed with
17 * this software for full details.
19 * This software is open source; you can redistribute it and/or modify it
20 * under the terms of the GNU General Public License as published by the
21 * Free Software Foundation; either version 2 of the License, or (at your
22 * option) any later version. See the GNU General Public License for more
23 * details at: http://www.mbedthis.com/downloads/gplLicense.html
25 * This program is distributed WITHOUT ANY WARRANTY; without even the
26 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
28 * This GPL license does NOT permit incorporating this software into
29 * proprietary programs. If you are unable to comply with the GPL, you must
30 * acquire a commercial license to use this software. Commercial licenses
31 * for this software and support services are available from Mbedthis
32 * Software at http://www.mbedthis.com
34 * @end
36 /********************************** Includes **********************************/
38 #include "ejsInternal.h"
40 #if BLD_FEATURE_EJS
42 /********************************** Local Data ********************************/
45 * These fields must be locked before any access when multithreaded
47 static MprVar master; /* Master object */
48 static MprArray *ejsList; /* List of ej handles */
50 #if BLD_FEATURE_MULTITHREAD
51 static EjsLock lock;
52 static EjsUnlock unlock;
53 static void *lockData;
54 #define ejsLock() if (lock) { (lock)(lockData); } else
55 #define ejsUnlock() if (unlock) { (unlock)(lockData); } else
56 #else
57 #define ejsLock()
58 #define ejsUnlock()
59 #endif
61 /****************************** Forward Declarations **************************/
63 static char *getNextVarToken(char **next, char *tokBuf, int tokBufLen);
65 /************************************* Code ***********************************/
67 * Initialize the EJ subsystem
70 int ejsOpen(EjsLock lockFn, EjsUnlock unlockFn, void *data)
72 MprVar *np;
74 #if BLD_FEATURE_MULTITHREAD
75 if (lockFn) {
76 lock = lockFn;
77 unlock = unlockFn;
78 lockData = data;
80 #endif
81 ejsLock();
84 * Master is the top level object (above global). It is used to clone its
85 * contents into the global scope for each. This is never visible to the
86 * user, so don't use ejsCreateObj().
88 master = mprCreateObjVar("master", EJS_SMALL_OBJ_HASH_SIZE);
89 if (master.type == MPR_TYPE_UNDEFINED) {
90 ejsUnlock();
91 return MPR_ERR_CANT_ALLOCATE;
94 ejsList = mprCreateArray();
95 ejsDefineStandardProperties(&master);
98 * Make these objects immutable
100 np = mprGetFirstProperty(&master, MPR_ENUM_FUNCTIONS | MPR_ENUM_DATA);
101 while (np) {
102 mprSetVarReadonly(np, 1);
103 np = mprGetNextProperty(&master, np, MPR_ENUM_FUNCTIONS |
104 MPR_ENUM_DATA);
106 ejsUnlock();
107 return 0;
110 /******************************************************************************/
112 void ejsClose()
114 ejsLock();
115 mprDestroyArray(ejsList);
116 mprDestroyVar(&master);
117 ejsUnlock();
120 /******************************************************************************/
122 * Create and initialize an EJS engine
125 EjsId ejsOpenEngine(EjsHandle primaryHandle, EjsHandle altHandle)
127 MprVar *np;
128 Ejs *ep;
130 ep = mprMalloc(sizeof(Ejs));
131 if (ep == 0) {
132 return (EjsId) -1;
134 memset(ep, 0, sizeof(Ejs));
136 ejsLock();
137 ep->eid = (EjsId) mprAddToArray(ejsList, ep);
138 ejsUnlock();
141 * Create array of local variable frames
143 ep->frames = mprCreateArray();
144 if (ep->frames == 0) {
145 ejsCloseEngine(ep->eid);
146 return (EjsId) -1;
148 ep->primaryHandle = primaryHandle;
149 ep->altHandle = altHandle;
152 * Create first frame: global variables
154 ep->global = (MprVar*) mprMalloc(sizeof(MprVar));
155 *ep->global = ejsCreateObj("global", EJS_OBJ_HASH_SIZE);
156 if (ep->global->type == MPR_TYPE_UNDEFINED) {
157 ejsCloseEngine(ep->eid);
158 return (EjsId) -1;
160 mprAddToArray(ep->frames, ep->global);
163 * Create first local variable frame
165 ep->local = (MprVar*) mprMalloc(sizeof(MprVar));
166 *ep->local = ejsCreateObj("local", EJS_OBJ_HASH_SIZE);
167 if (ep->local->type == MPR_TYPE_UNDEFINED) {
168 ejsCloseEngine(ep->eid);
169 return (EjsId) -1;
171 mprAddToArray(ep->frames, ep->local);
174 * Clone all master variables into the global frame. This does a
175 * reference copy.
177 * ejsDefineStandardProperties(ep->global);
179 np = mprGetFirstProperty(&master, MPR_ENUM_FUNCTIONS | MPR_ENUM_DATA);
180 while (np) {
181 mprCreateProperty(ep->global, np->name, np);
182 np = mprGetNextProperty(&master, np, MPR_ENUM_FUNCTIONS |
183 MPR_ENUM_DATA);
186 mprCreateProperty(ep->global, "global", ep->global);
187 mprCreateProperty(ep->global, "this", ep->global);
188 mprCreateProperty(ep->local, "local", ep->local);
190 return ep->eid;
193 /******************************************************************************/
195 * Close an EJS instance
198 void ejsCloseEngine(EjsId eid)
200 Ejs *ep;
201 MprVar *vp;
202 void **handles;
203 int i;
205 if ((ep = ejsPtr(eid)) == NULL) {
206 mprAssert(ep);
207 return;
210 mprFree(ep->error);
211 mprDestroyVar(&ep->result);
212 mprDestroyVar(&ep->tokenNumber);
214 if (ep->local) {
215 mprDeleteProperty(ep->local, "local");
217 mprDeleteProperty(ep->global, "this");
218 mprDeleteProperty(ep->global, "global");
220 handles = ep->frames->handles;
221 for (i = 0; i < ep->frames->max; i++) {
222 vp = handles[i];
223 if (vp) {
224 #if BLD_DEBUG
225 if (vp->type == MPR_TYPE_OBJECT && vp->properties->refCount > 1) {
226 mprLog(7, "ejsCloseEngine: %s has ref count %d\n",
227 vp->name, vp->properties->refCount);
229 #endif
230 mprDestroyVar(vp);
231 mprFree(vp);
232 mprRemoveFromArray(ep->frames, i);
235 mprDestroyArray(ep->frames);
237 ejsLock();
238 mprRemoveFromArray(ejsList, (int) ep->eid);
239 ejsUnlock();
241 mprFree(ep);
244 /******************************************************************************/
246 * Evaluate an EJS script file
249 int ejsEvalFile(EjsId eid, char *path, MprVar *result, char **emsg)
251 struct stat sbuf;
252 Ejs *ep;
253 char *script;
254 int rc, fd;
256 mprAssert(path && *path);
258 if (emsg) {
259 *emsg = NULL;
262 if ((ep = ejsPtr(eid)) == NULL) {
263 mprAssert(ep);
264 goto error;
267 if ((fd = open(path, O_RDONLY | O_BINARY, 0666)) < 0) {
268 ejsError(ep, "Can't open %s\n", path);
269 goto error;
272 if (stat(path, &sbuf) < 0) {
273 close(fd);
274 ejsError(ep, "Cant stat %s", path);
275 goto error;
278 if ((script = (char*) mprMalloc(sbuf.st_size + 1)) == NULL) {
279 close(fd);
280 ejsError(ep, "Cant malloc %d", (int) sbuf.st_size);
281 goto error;
284 if (read(fd, script, sbuf.st_size) != (int) sbuf.st_size) {
285 close(fd);
286 mprFree(script);
287 ejsError(ep, "Error reading %s", path);
288 goto error;
291 script[sbuf.st_size] = '\0';
292 close(fd);
294 rc = ejsEvalBlock(eid, script, result, emsg);
295 mprFree(script);
297 return rc;
300 * Error return
302 error:
303 *emsg = mprStrdup(ep->error);
304 return -1;
307 /******************************************************************************/
309 * Create a new variable scope block. This pushes the old local frame down
310 * the stack and creates a new local variables frame.
313 int ejsOpenBlock(EjsId eid)
315 Ejs *ep;
317 if((ep = ejsPtr(eid)) == NULL) {
318 return -1;
321 ep->local = (MprVar*) mprMalloc(sizeof(MprVar));
322 *ep->local = ejsCreateObj("localBlock", EJS_OBJ_HASH_SIZE);
324 mprCreateProperty(ep->local, "local", ep->local);
326 return mprAddToArray(ep->frames, ep->local);
329 /******************************************************************************/
331 * Close a variable scope block opened via ejsOpenBlock. Pop back the old
332 * local variables frame.
335 int ejsCloseBlock(EjsId eid, int fid)
337 Ejs *ep;
339 if((ep = ejsPtr(eid)) == NULL) {
340 mprAssert(ep);
341 return -1;
345 * Must remove self-references before destroying "local"
347 mprDeleteProperty(ep->local, "local");
349 mprDestroyVar(ep->local);
350 mprFree(ep->local);
352 mprRemoveFromArray(ep->frames, fid);
353 ep->local = (MprVar*) ep->frames->handles[ep->frames->used - 1];
355 return 0;
358 /******************************************************************************/
360 * Create a new variable scope block and evaluate a script. All frames
361 * created during this context will be automatically deleted when complete.
362 * vp and emsg are optional. i.e. created local variables will be discarded
363 * when this routine returns.
366 int ejsEvalBlock(EjsId eid, char *script, MprVar *vp, char **emsg)
368 int rc, fid;
370 mprAssert(script);
372 fid = ejsOpenBlock(eid);
373 rc = ejsEvalScript(eid, script, vp, emsg);
374 ejsCloseBlock(eid, fid);
376 return rc;
379 /******************************************************************************/
381 * Parse and evaluate a EJS. Return the result in *vp. The result is "owned"
382 * by EJ and the caller must not free it. Returns -1 on errors and zero
383 * for success. On errors, emsg will be set to the reason. The caller must
384 * free emsg.
387 int ejsEvalScript(EjsId eid, char *script, MprVar *vp, char **emsg)
389 Ejs *ep;
390 int state;
391 void *endlessLoopTest;
392 int loopCounter;
394 if (emsg) {
395 *emsg = NULL;
398 if ((ep = ejsPtr(eid)) == NULL) {
399 mprAssert(ep);
400 return -1;
403 mprDestroyVar(&ep->result);
405 if (script == 0) {
406 return 0;
410 * Allocate a new evaluation block, and save the old one
412 ejsLexOpenScript(ep, script);
415 * Do the actual parsing and evaluation
417 loopCounter = 0;
418 endlessLoopTest = NULL;
419 ep->exitStatus = 0;
421 do {
422 state = ejsParse(ep, EJS_STATE_BEGIN, EJS_FLAGS_EXE);
424 if (state == EJS_STATE_RET) {
425 state = EJS_STATE_EOF;
428 * Stuck parser and endless recursion protection.
430 if (endlessLoopTest == ep->input->scriptServp) {
431 if (loopCounter++ > 10) {
432 state = EJS_STATE_ERR;
433 ejsError(ep, "Syntax error");
435 } else {
436 endlessLoopTest = ep->input->scriptServp;
437 loopCounter = 0;
439 } while (state != EJS_STATE_EOF && state != EJS_STATE_ERR);
441 ejsLexCloseScript(ep);
444 * Return any error string to the user
446 if (state == EJS_STATE_ERR && emsg) {
447 *emsg = mprStrdup(ep->error);
450 if (state == EJS_STATE_ERR) {
451 return -1;
454 if (vp) {
455 *vp = ep->result;
458 return ep->exitStatus;
461 /******************************************************************************/
463 * Core error handling
466 static void ejsErrorCore(Ejs* ep, const char *fmt, va_list args)
467 PRINTF_ATTRIBUTE(2, 0);
469 static void ejsErrorCore(Ejs* ep, const char *fmt, va_list args)
471 EjsInput *ip;
472 char *errbuf, *msgbuf;
473 int frame = 0;
475 mprAssert(ep);
477 msgbuf = NULL;
478 mprAllocVsprintf(&msgbuf, MPR_MAX_STRING, fmt, args);
480 ip = ep->input;
481 mprAllocSprintf(&errbuf, MPR_MAX_STRING, "%s\nBacktrace:\n", msgbuf);
483 /* form a backtrace */
484 while (ip) {
485 char *msg2, *ebuf2;
486 mprAllocSprintf(&msg2, MPR_MAX_STRING,
487 "\t[%2d] %20s:%-4d -> %s\n",
488 frame++, ip->procName?ip->procName:"", ip->lineNumber, ip->line);
489 ebuf2 = mprRealloc(errbuf, strlen(errbuf) + strlen(msg2) + 1);
490 if (ebuf2 == NULL) break;
491 errbuf = ebuf2;
492 memcpy(errbuf+strlen(errbuf), msg2, strlen(msg2)+1);
493 mprFree(msg2);
494 ip = ip->next;
496 mprFree(ep->error);
497 ep->error = errbuf;
498 mprFree(msgbuf);
501 /******************************************************************************/
503 * Internal use function to set the error message
506 void ejsError(Ejs* ep, const char* fmt, ...)
508 va_list args;
510 va_start(args, fmt);
511 ejsErrorCore(ep, fmt, args);
512 va_end(args);
515 /******************************************************************************/
517 * Public routine to set the error message
520 void ejsSetErrorMsg(EjsId eid, const char* fmt, ...)
522 va_list args;
523 Ejs *ep;
525 if ((ep = ejsPtr(eid)) == NULL) {
526 mprAssert(ep);
527 return;
529 va_start(args, fmt);
530 ejsErrorCore(ep, fmt, args);
531 va_end(args);
534 /******************************************************************************/
536 * Get the current line number
539 int ejsGetLineNumber(EjsId eid)
541 Ejs *ep;
543 if ((ep = ejsPtr(eid)) == NULL) {
544 mprAssert(ep);
545 return -1;
547 return ep->input->lineNumber;
550 /******************************************************************************/
552 * Return the local object
555 MprVar *ejsGetLocalObject(EjsId eid)
557 Ejs *ep;
559 if ((ep = ejsPtr(eid)) == NULL) {
560 mprAssert(ep);
561 return 0;
563 return ep->local;
566 /******************************************************************************/
568 * Return the global object
571 MprVar *ejsGetGlobalObject(EjsId eid)
573 Ejs *ep;
575 if ((ep = ejsPtr(eid)) == NULL) {
576 mprAssert(ep);
577 return 0;
579 return ep->global;
582 /******************************************************************************/
584 * Copy the value of an object property. Return value is in "value".
585 * If deepCopy is true, copy all object/strings. Otherwise, object reference
586 * counts are incremented. Callers must always call mprDestroyVar on the
587 * return value to prevent leaks.
589 * Returns: -1 on errors or if the variable is not found.
592 int ejsCopyVar(EjsId eid, const char *var, MprVar *value, bool deepCopy)
594 Ejs *ep;
595 MprVar *vp;
597 mprAssert(var && *var);
598 mprAssert(value);
600 if ((ep = ejsPtr(eid)) == NULL) {
601 mprAssert(ep);
602 return -1;
605 if (ejsGetVarCore(ep, var, 0, &vp, 0) < 0) {
606 return -1;
609 return mprCopyProperty(value, vp, deepCopy);
612 /******************************************************************************/
614 * Return the value of an object property. Return value is in "value".
615 * Objects and strings are not copied and reference counts are not modified.
616 * Callers should NOT call mprDestroyVar. Returns: -1 on errors or if the
617 * variable is not found.
620 int ejsReadVar(EjsId eid, const char *var, MprVar *value)
622 Ejs *ep;
623 MprVar *vp;
625 mprAssert(var && *var);
626 mprAssert(value);
628 if ((ep = ejsPtr(eid)) == NULL) {
629 mprAssert(ep);
630 return -1;
633 if (ejsGetVarCore(ep, var, 0, &vp, 0) < 0) {
634 return -1;
637 return mprReadProperty(vp, value);
640 /******************************************************************************/
642 * Set a variable that may be an arbitrarily complex object or array reference.
643 * Will always define in the top most variable frame.
646 int ejsWriteVar(EjsId eid, const char *var, MprVar *value)
648 Ejs *ep;
649 MprVar *vp;
651 mprAssert(var && *var);
653 if ((ep = ejsPtr(eid)) == NULL) {
654 mprAssert(ep);
655 return -1;
658 if (ejsGetVarCore(ep, var, 0, &vp, EJS_FLAGS_CREATE) < 0) {
659 return -1;
661 mprAssert(vp);
664 * Only copy the value. Don't overwrite the object's name
666 mprWriteProperty(vp, value);
668 return 0;
671 /******************************************************************************/
673 * Set a variable that may be an arbitrarily complex object or array reference.
674 * Will always define in the top most variable frame.
677 int ejsWriteVarValue(EjsId eid, const char *var, MprVar value)
679 return ejsWriteVar(eid, var, &value);
682 /******************************************************************************/
684 * Delete a variable
687 int ejsDeleteVar(EjsId eid, const char *var)
689 Ejs *ep;
690 MprVar *vp;
691 MprVar *obj;
693 if ((ep = ejsPtr(eid)) == NULL) {
694 mprAssert(ep);
695 return -1;
697 if (ejsGetVarCore(ep, var, &obj, &vp, 0) < 0) {
698 return -1;
700 mprDeleteProperty(obj, vp->name);
701 return 0;
704 /******************************************************************************/
706 * Set the expression return value
709 void ejsSetReturnValue(EjsId eid, MprVar value)
711 Ejs *ep;
713 if ((ep = ejsPtr(eid)) == NULL) {
714 mprAssert(ep);
715 return;
717 mprCopyVar(&ep->result, &value, MPR_SHALLOW_COPY);
720 /******************************************************************************/
722 * Set the expression return value to a string value
725 void ejsSetReturnString(EjsId eid, const char *str)
727 Ejs *ep;
729 if ((ep = ejsPtr(eid)) == NULL) {
730 mprAssert(ep);
731 return;
733 mprCopyVarValue(&ep->result, mprCreateStringVar(str, 0), MPR_SHALLOW_COPY);
736 /******************************************************************************/
738 * Get the expression return value
741 MprVar *ejsGetReturnValue(EjsId eid)
743 Ejs *ep;
745 if ((ep = ejsPtr(eid)) == NULL) {
746 mprAssert(ep);
747 return 0;
749 return &ep->result;
752 /******************************************************************************/
754 * Define a C function. If eid < 0, then update the master object with this
755 * function. NOTE: in this case, functionName must be simple without any "." or
756 * "[]" elements. If eid >= 0, add to the specified script engine. In this
757 * case, functionName can be an arbitrary object reference and can contain "."
758 * or "[]".
761 void ejsDefineCFunction(EjsId eid, const char *functionName, MprCFunction fn,
762 void *thisPtr, int flags)
764 if (eid < 0) {
765 ejsLock();
766 mprCreatePropertyValue(&master, functionName,
767 mprCreateCFunctionVar(fn, thisPtr, flags));
768 ejsUnlock();
769 } else {
770 ejsWriteVarValue(eid, functionName,
771 mprCreateCFunctionVar(fn, thisPtr, flags));
775 /******************************************************************************/
777 * Define a C function with String arguments
780 void ejsDefineStringCFunction(EjsId eid, const char *functionName,
781 MprStringCFunction fn, void *thisPtr, int flags)
783 if (eid < 0) {
784 ejsLock();
785 mprCreatePropertyValue(&master, functionName,
786 mprCreateStringCFunctionVar(fn, thisPtr, flags));
787 ejsUnlock();
788 } else {
789 ejsWriteVarValue(eid, functionName,
790 mprCreateStringCFunctionVar(fn, thisPtr, flags));
794 /******************************************************************************/
796 * Define a JavaScript function. Args should be comma separated.
797 * Body should not contain braces.
800 void ejsDefineFunction(EjsId eid, const char *functionName, char *args,
801 char *body)
803 MprVar v;
805 v = mprCreateFunctionVar(args, body, 0);
806 if (eid < 0) {
807 ejsLock();
808 mprCreateProperty(&master, functionName, &v);
809 ejsUnlock();
810 } else {
811 ejsWriteVar(eid, functionName, &v);
813 mprDestroyVar(&v);
816 /******************************************************************************/
818 void *ejsGetThisPtr(EjsId eid)
820 Ejs *ep;
822 if ((ep = ejsPtr(eid)) == NULL) {
823 mprAssert(ep);
824 return 0;
826 return ep->thisPtr;
829 /******************************************************************************/
831 * Find a variable given a variable name and return the parent object and
832 * the variable itself, the variable . This routine supports variable names
833 * that may be objects or arrays but may NOT have expressions in the array
834 * indicies. Returns -1 on errors or if the variable is not found.
837 int ejsGetVarCore(Ejs *ep, const char *vname, MprVar **obj,
838 MprVar **varValue, int flags)
840 MprVar *currentObj;
841 MprVar *currentVar;
842 char tokBuf[EJS_MAX_ID];
843 char *propertyName, *token, *next, *cp, *varName;
845 if (obj) {
846 *obj = 0;
848 if (varValue) {
849 *varValue = 0;
851 currentObj = ejsFindObj(ep, 0, vname, flags);
852 currentVar = 0;
853 propertyName = 0;
855 next = varName = mprStrdup(vname);
857 token = getNextVarToken(&next, tokBuf, sizeof(tokBuf));
859 while (currentObj != 0 && token != 0 && *token) {
861 if (*token == '[') {
862 token = getNextVarToken(&next, tokBuf, sizeof(tokBuf));
864 propertyName = token;
865 if (*propertyName == '\"') {
866 propertyName++;
867 if ((cp = strchr(propertyName, '\"')) != 0) {
868 *cp = '\0';
870 } else if (*propertyName == '\'') {
871 propertyName++;
872 if ((cp = strchr(propertyName, '\'')) != 0) {
873 *cp = '\0';
877 currentObj = currentVar;
878 currentVar = ejsFindProperty(ep, 0, currentObj, propertyName, 0);
880 token = getNextVarToken(&next, tokBuf, sizeof(tokBuf));
881 if (*token != ']') {
882 mprFree(varName);
883 return -1;
886 } else if (*token == '.') {
887 token = getNextVarToken(&next, tokBuf, sizeof(tokBuf));
888 if (!isalpha((int) token[0]) &&
889 token[0] != '_' && token[0] != '$') {
890 mprFree(varName);
891 return -1;
894 propertyName = token;
895 currentObj = currentVar;
896 currentVar = ejsFindProperty(ep, 0, currentObj, token, 0);
898 } else {
899 currentVar = ejsFindProperty(ep, 0, currentObj, token, 0);
901 token = getNextVarToken(&next, tokBuf, sizeof(tokBuf));
903 mprFree(varName);
905 if (currentVar == 0 && currentObj >= 0 && flags & EJS_FLAGS_CREATE) {
906 currentVar = mprCreatePropertyValue(currentObj, propertyName,
907 mprCreateUndefinedVar());
909 if (obj) {
910 *obj = currentObj;
914 * Don't use mprCopyVar as it will copy the data
916 if (varValue) {
917 *varValue = currentVar;
919 return currentVar ? 0 : -1;
922 /******************************************************************************/
924 * Get the next token as part of a variable specification. This will return
925 * a pointer to the next token and will return a pointer to the next token
926 * (after this one) in "next". The tokBuf holds the parsed token.
928 static char *getNextVarToken(char **next, char *tokBuf, int tokBufLen)
930 char *start, *cp;
931 int len;
933 start = *next;
934 while (isspace((int) *start) || *start == '\n' || *start == '\r') {
935 start++;
937 cp = start;
939 if (*cp == '.' || *cp == '[' || *cp == ']') {
940 cp++;
941 } else {
942 while (*cp && *cp != '.' && *cp != '[' && *cp != ']' &&
943 !isspace((int) *cp) && *cp != '\n' && *cp != '\r') {
944 cp++;
947 len = mprMemcpy(tokBuf, tokBufLen - 1, start, cp - start);
948 tokBuf[len] = '\0';
950 *next = cp;
951 return tokBuf;
954 /******************************************************************************/
956 * Get the EJS structure pointer
959 Ejs *ejsPtr(EjsId eid)
961 Ejs *handle;
962 int intId;
964 intId = (int) eid;
966 ejsLock();
967 mprAssert(0 <= intId && intId < ejsList->max);
969 if (intId < 0 || intId >= ejsList->max || ejsList->handles[intId] == NULL) {
970 mprAssert(0);
971 ejsUnlock();
972 return NULL;
974 handle = ejsList->handles[intId];
975 ejsUnlock();
976 return handle;
979 /******************************************************************************/
981 * Utility routine to crack JavaScript arguments. Return the number of args
982 * seen. This routine only supports %s and %d type args.
984 * Typical usage:
986 * if (ejsParseArgs(argc, argv, "%s %d", &name, &age) < 2) {
987 * mprError("Insufficient args\n");
988 * return -1;
992 int ejsParseArgs(int argc, char **argv, char *fmt, ...)
994 va_list vargs;
995 bool *bp;
996 char *cp, **sp, *s;
997 int *ip, argn;
999 va_start(vargs, fmt);
1001 if (argv == 0) {
1002 return 0;
1005 for (argn = 0, cp = fmt; cp && *cp && argn < argc && argv[argn]; ) {
1006 if (*cp++ != '%') {
1007 continue;
1010 s = argv[argn];
1011 switch (*cp) {
1012 case 'b':
1013 bp = va_arg(vargs, bool*);
1014 if (bp) {
1015 if (strcmp(s, "true") == 0 || s[0] == '1') {
1016 *bp = 1;
1017 } else {
1018 *bp = 0;
1020 } else {
1021 *bp = 0;
1023 break;
1025 case 'd':
1026 ip = va_arg(vargs, int*);
1027 *ip = atoi(s);
1028 break;
1030 case 's':
1031 sp = va_arg(vargs, char**);
1032 *sp = s;
1033 break;
1035 default:
1036 mprAssert(0);
1038 argn++;
1041 va_end(vargs);
1042 return argn;
1045 /******************************************************************************/
1047 #else
1048 void ejsDummy() {}
1050 /******************************************************************************/
1051 #endif /* BLD_FEATURE_EJS */
1053 /******************************************************************************/
1055 * Local variables:
1056 * tab-width: 4
1057 * c-basic-offset: 4
1058 * End:
1059 * vim:tw=78
1060 * vim600: sw=4 ts=4 fdm=marker
1061 * vim<600: sw=4 ts=4