Add header.
[vlendec/samba-autobuild/.git] / source4 / lib / appweb / ejs-2.0 / ejs / ejs.c
1 /*
2  *      @file   ejs.c
3  *      @brief  Embedded JavaScript (EJS) 
4  *      @overview Main module interface logic.
5  *      @remarks The initialization code must be run single-threaded. Includes:
6  *              ejsOpen, ejsClose.
7  */
8 /********************************* Copyright **********************************/
9 /*
10  *      @copy   default
11  *      
12  *      Copyright (c) Mbedthis Software LLC, 2003-2006. All Rights Reserved.
13  *      
14  *      This software is distributed under commercial and open source licenses.
15  *      You may use the GPL open source license described below or you may acquire 
16  *      a commercial license from Mbedthis Software. You agree to be fully bound 
17  *      by the terms of either license. Consult the LICENSE.TXT distributed with 
18  *      this software for full details.
19  *      
20  *      This software is open source; you can redistribute it and/or modify it 
21  *      under the terms of the GNU General Public License as published by the 
22  *      Free Software Foundation; either version 2 of the License, or (at your 
23  *      option) any later version. See the GNU General Public License for more 
24  *      details at: http://www.mbedthis.com/downloads/gplLicense.html
25  *      
26  *      This program is distributed WITHOUT ANY WARRANTY; without even the 
27  *      implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
28  *      
29  *      This GPL license does NOT permit incorporating this software into 
30  *      proprietary programs. If you are unable to comply with the GPL, you must
31  *      acquire a commercial license to use this software. Commercial licenses 
32  *      for this software and support services are available from Mbedthis 
33  *      Software at http://www.mbedthis.com 
34  *      
35  *      @end
36  */
37 /********************************** Includes **********************************/
38
39 #include        "ejs.h"
40
41 #if BLD_FEATURE_EJS
42
43 /************************************* Code ***********************************/
44 /*
45  *      Initialize the EJS subsystem
46  */
47
48 EjsService *ejsOpenService(MprCtx ctx)
49 {
50         EjsService      *service;
51         Ejs                     *interp;
52
53         service = mprAllocTypeZeroed(ctx, EjsService);
54         if (service == 0) {
55                 mprError(ctx, MPR_LOC, "Can't allocate service memory");
56                 return 0;
57         }
58
59         interp = ejsCreateInterp(service, 0, 0, 0, 1);
60         if (interp == 0) {
61                 mprError(ctx, MPR_LOC, "Can't create master interpreter");
62                 mprFree(service);
63                 return 0;
64         }
65         service->master = interp;
66
67         /*
68          *      Restore the default GC settings for the master interpreter.
69          *      ejsCreateInterp will have initialized them.
70          */
71         ejsGCInit(interp, EJS_DEFAULT_OBJ_INC, EJS_DEFAULT_PROP_INC,
72                 EJS_DEFAULT_VAR_INC, EJS_DEFAULT_STR_INC);
73
74         /*
75          *      Save the default interpreter and global class for all to access
76          *      MOB -- don't store these. Store the service
77          */
78         mprSetKeyValue(interp, "ejsMaster", interp);
79         mprSetKeyValue(interp, "ejsGlobalClass", interp->global);
80
81         /*
82          *      Once the Object class is created, this routine will also make the
83          *      Global class a subclass of Object.
84          */
85         if (ejsDefineObjectClass(interp) < 0) {
86                 mprError(ctx, MPR_LOC, "Can't define EJS object class");
87                 mprFree(service);
88                 return 0;
89         }
90
91         /*
92          *      Create all the standard classes
93          */
94         if (ejsDefineStandardClasses(interp) < 0) {
95                 mprError(ctx, MPR_LOC, "Can't define EJS standard classes");
96                 mprFree(service);
97                 return 0;
98         }
99
100         if (ejsDefineSystemClasses(interp) < 0) {
101                 mprError(ctx, MPR_LOC, "Can't define EJS system classes");
102                 mprFree(service);
103                 return 0;
104         }
105
106         if (ejsCreateObjectModel(interp) < 0) {
107                 mprError(ctx, MPR_LOC, "Can't create EJS object model");
108                 mprFree(service);
109                 return 0;
110         }
111
112 #if UNUSED && BLD_FEATURE_ALLOC_STATS
113 {
114         EjsVar  v;
115         mprLog(ctx, 0, "Obj %d, Var %d, Prop %d\n", sizeof(EjsObj), sizeof(EjsVar),
116                 sizeof(EjsProperty));
117         mprLog(ctx, 0, "GCLink %d\n", sizeof(EjsGCLink));
118         mprLog(ctx, 0, "objectState %d\n", (uint) &v.objectState - (uint) &v);
119 }
120 #endif
121
122         return service;
123 }
124
125 /******************************************************************************/
126 /*
127  *      Close down the EJS Service
128  */
129
130 void ejsCloseService(EjsService *sp, bool doStats)
131 {
132         Ejs             *ep;
133
134         mprAssert(sp);
135
136         ep = sp->master;
137         mprAssert(ep);
138
139         ejsTermSystemClasses(ep);
140
141         if (ep) {
142                 ejsFreeVar(ep, sp->globalClass);
143
144 #if BLD_FEATURE_ALLOC_STATS
145                 if (doStats) {
146                         mprLog(sp, 0, "GC Statistics for the Global Interpreter");
147                 }
148 #endif
149                 ejsDestroyInterp(ep, doStats);
150         }
151
152         mprRemoveKeyValue(sp, "ejsMaster");
153         mprRemoveKeyValue(sp, "ejsGlobalClass");
154
155         mprFree(sp);
156 }
157
158 /******************************************************************************/
159
160 Ejs *ejsGetMasterInterp(EjsService *sp)
161 {
162         return sp->master;
163 }
164
165 /******************************************************************************/
166 #if BLD_FEATURE_MULTITHREAD
167
168 int ejsSetServiceLocks(EjsService *sp, EjsLockFn lock, EjsUnlockFn unlock, 
169                 void *data)
170 {
171         mprAssert(sp);
172
173         sp->lock = lock;
174         sp->unlock = unlock;
175         sp->lockData = data;
176         return 0;
177 }
178
179 #endif
180 /******************************************************************************/
181 /*
182  *      Create and initialize an EJS interpreter. Interpreters have a global object
183  *      that has the service global class set as a base class. This way, it 
184  *      inherits all the desired global properties, methods and classes.
185  *
186  *      The primary and alternate handles are provided to C methods depending on 
187  *      the flags provided when the C methods are defined. The global variable 
188  *      (optionally) defines a predefined global variable space.
189  */
190
191 Ejs *ejsCreateInterp(EjsService *sp, void *primaryHandle, void *altHandle,
192         EjsVar *global, bool useOwnSlab)
193 {
194         EjsProperty     *pp;
195         EjsVar          *baseClass;
196         Ejs                     *ep;
197
198         ep = mprAllocTypeZeroed(sp, Ejs);
199         if (ep == 0) {
200                 mprAssert(0);
201                 return ep;
202         }
203
204         ep->stkPtr = &ep->stack[EJS_MAX_STACK];
205
206         ep->service = sp;
207         ep->primaryHandle = primaryHandle;
208         ep->altHandle = altHandle;
209
210         if (sp->master) {
211                 ep->objectClass = sp->master->objectClass;
212         }
213
214         if (useOwnSlab) {
215                 ep->slabs = (EjsSlab*) mprAllocZeroed(ep, sizeof(EjsSlab) * 
216                         EJS_SLAB_MAX);
217                  ep->slabAllocContext = ep;
218
219         } else {
220                 ep->slabs = sp->master->slabs;
221                 ep->slabAllocContext = sp->master;
222                 ep->flags |= EJS_FLAGS_SHARED_SLAB;
223         }
224
225         ep->frames = mprCreateItemArray(ep, EJS_INC_FRAMES, EJS_MAX_FRAMES);
226         if (ep->frames == 0) {
227                 mprFree(ep);
228                 return 0;
229         }
230
231         ejsGCInit(ep, EJS_OBJ_INC, EJS_PROP_INC, EJS_VAR_INC, EJS_STR_INC);
232
233         if (sp->globalClass == 0) {
234                 /*
235                  *      Only do this for the Global interpreter. Create a global class 
236                  *      (prototype) object. This is base class from which all global 
237                  *      spaces will inherit. 
238                  */
239                 sp->globalClass = ejsCreateObjVar(ep);
240                 if (sp->globalClass == 0) {
241                         mprFree(ep);
242                         return 0;
243                 }
244                 ejsSetClassName(ep, sp->globalClass, "Global");
245                 global = sp->globalClass;
246         }
247         
248         if (global) {
249                 /*
250                  *      The default interpreter uses the Global class as its global
251                  *      space.
252                  */
253                 ep->global = ejsDupVar(ep, global, EJS_SHALLOW_COPY);
254                 if (ep->global == 0) {
255                         mprFree(ep);
256                         return 0;
257                 }
258                 if (ep->global->objectState != sp->globalClass->objectState) {
259                         ejsSetBaseClass(ep->global, sp->globalClass);
260                 }
261
262         } else {
263                 /*
264                  *      Use the global class as our global so we can find the object class
265                  */
266                 baseClass = ejsGetClass(ep, sp->globalClass, "Object");
267                 if (baseClass) {
268                         ep->global = ejsCreateSimpleObjUsingClass(ep, baseClass);
269                         if (ep->global == 0) {
270                                 mprFree(ep);
271                                 return 0;
272                         }
273
274                         /*
275                          *      Override the base class and set to the master Global class
276                          */
277                         ejsSetBaseClass(ep->global, sp->globalClass);
278
279                 } else {
280                         ep->global = ejsCreateObjVar(ep);
281                 }
282         }
283
284         /*
285          *      The "global" variable points to the global space
286          */
287         pp = ejsSetProperty(ep, ep->global, "global", ep->global);
288         if (pp == 0) {
289                 mprFree(ep);
290                 return 0;
291         }
292         ejsMakePropertyEnumerable(pp, 0);
293
294         /*
295          *      The "Global" variable points to the Global class
296          */
297         pp = ejsSetProperty(ep, ep->global, "Global", sp->globalClass);
298         if (pp == 0) {
299                 mprFree(ep);
300                 return 0;
301         }
302         ejsMakePropertyEnumerable(pp, 0);
303
304         ep->local = ejsDupVar(ep, ep->global, EJS_SHALLOW_COPY);
305         if (ep->frames == 0 || ep->global == 0 || ep->local == 0) {
306                 mprFree(ep);
307                 return 0;
308         }
309         ejsSetVarName(ep, ep->local, "topLevelLocal");
310
311         if (mprAddItem(ep->frames, ep->global) < 0 ||
312                         mprAddItem(ep->frames, ep->local) < 0) {
313                 mprFree(ep);
314                 return 0;
315         }
316
317         ep->result = ejsCreateUndefinedVar(ep);
318         if (ep->result == 0) {
319                 mprFree(ep);
320                 return 0;
321         }
322
323         return ep;
324 }
325
326 /******************************************************************************/
327 /*
328  *      Close an EJS interpreter
329  */
330
331 void ejsDestroyInterp(Ejs *ep, bool doStats)
332 {
333         ejsCleanInterp(ep, doStats);
334
335         mprFree(ep);
336 }
337
338 /******************************************************************************/
339 /*
340  *      Clean an EJS interpreter of all allocated variables, but DONT destroy.
341  *      We use this rather than DestroyInterp so we delay freeing the Ejs struct
342  *      until after the service is closed.
343  */
344
345 void ejsCleanInterp(Ejs *ep, bool doStats)
346 {
347         int             i;
348
349         if (ep->global) {
350                 ejsDeleteProperty(ep, ep->local, "global");
351                 ejsDeleteProperty(ep, ep->global, "global");
352                 ep->global = 0;
353         }
354         if (ep->local) {
355                 ejsFreeVar(ep, ep->local);
356                 ep->local = 0;
357         }
358         if (ep->global) {
359                 ejsFreeVar(ep, ep->global);
360                 ep->global = 0;
361         }
362         if (ep->result) {
363                 ejsFreeVar(ep, ep->result);
364                 ep->result = 0;
365         }
366         if (ep->castAlloc && ep->castTemp) {
367                 mprFree(ep->castTemp);
368                 ep->castTemp = 0;
369         }
370         if (ep->frames) {
371                 for (i = ep->frames->length - 1; i >= 0; i--) {
372                         mprRemoveItemByIndex(ep->frames, i);
373                 }
374                 mprFree(ep->frames);
375                 ep->frames = 0;
376         }
377
378         if (doStats) {
379
380 #if BLD_FEATURE_ALLOC_STATS
381                 mprLog(ep, 0, " ");
382                 mprLog(ep, 0, "GC Statistics for Interpreter (0x%X)", (uint) ep);
383 #endif
384
385                 /*
386                  *      Cleanup before printing the alloc report
387                  */
388                 ejsSetGCDebugLevel(ep, 3);
389                 ejsCollectGarbage(ep, -1);
390
391 #if BLD_DEBUG
392                 /*
393                  *      If we are the master, dump objects
394                  */
395                 if (ep->service->master == ep) {
396                         ejsDumpObjects(ep);
397                 }
398 #endif
399
400 #if BLD_FEATURE_ALLOC_STATS
401                 /*
402                  *      Print an alloc report. 1 == do leak report
403                  */
404                 ejsPrintAllocReport(ep, 1);
405 #endif
406
407         } else {
408                 /*
409                  *      Must collect garbage here incase sharing interpreters with the
410                  *      master. If we don't, the mprFree later in DestroyInterp will free
411                  *      all memory and when the master does GC --> crash.
412                  */
413                 ejsCollectGarbage(ep, -1);
414         }
415 }
416
417 /******************************************************************************/
418 /*
419  *      Evaluate an EJS script file. This will evaluate the script at the current
420  *      context. Ie. if inside a function, declarations will be local.
421  */
422
423 int ejsEvalFile(Ejs *ep, const char *path, EjsVar *result)
424 {
425         MprFile                 *file;
426         MprFileInfo             info;
427         char                    *script;
428         char                    *saveFileName;
429         int                             rc;
430
431         mprAssert(path && *path);
432
433         if ((file = mprOpen(ep, path, O_RDONLY | O_BINARY, 0666)) == 0) {
434                 ejsError(ep, EJS_IO_ERROR, "Can't open %s", path);
435                 return -1;
436         }
437         
438         if (mprGetFileInfo(ep, path, &info) < 0) {
439                 ejsError(ep, EJS_IO_ERROR, "Can't get file info for %s", path);
440                 goto error;
441         }
442         
443         if ((script = (char*) mprAlloc(ep, info.size + 1)) == NULL) {
444                 ejsError(ep, "MemoryError", "Cant malloc %d", (int) info.size);
445                 goto error;
446         }
447         
448         if (mprRead(file, script, info.size) != (int) info.size) {
449                 mprFree(script);
450                 ejsError(ep, EJS_IO_ERROR, "Error reading %s", path);
451                 goto error;
452         }
453         mprClose(file);
454         script[info.size] = '\0';
455
456         saveFileName = ep->fileName;
457         ep->fileName = mprStrdup(ep, path);
458
459         rc = ejsEvalScript(ep, script, result);
460         mprFree(script);
461
462         mprFree(ep->fileName);
463         ep->fileName = saveFileName;
464
465         return rc;
466
467 /*
468  *      Error return
469  */
470 error:
471         mprClose(file);
472         return -1;
473 }
474
475 /******************************************************************************/
476 /*
477  *      Create a new variable scope block. This pushes the old local frame down
478  *      the stack and creates a new local variables frame.
479  */
480
481 int ejsOpenBlock(Ejs *ep)
482 {
483         EjsProperty             *pp;
484         int                             fid;
485
486         ep->local = ejsCreateSimpleObj(ep, "Object");
487         ejsSetVarName(ep, ep->local, "local");
488
489         if (ep->local == 0) {
490                 ejsMemoryError(ep);
491                 return -1;
492         }
493
494         if (ep->frames->length > EJS_MAX_FRAMES && !ep->gotException) {
495                 ejsError(ep, EJS_RANGE_ERROR, "Recursion too deep: Max depth %d", 
496                         EJS_MAX_FRAMES);
497                 return -1;
498         }
499
500         /*
501          *      Must add to frames before ejsSetProperty which will make the object live
502          */
503         fid = mprAddItem(ep->frames, ep->local);
504         if (fid < 0) {
505                 ejsMemoryError(ep);
506                 return -1;
507         }
508
509         /* Self reference */
510         pp = ejsSetProperty(ep, ep->local, "local", ep->local);
511         ejsMakePropertyEnumerable(pp, 0);
512
513         return fid;
514 }
515
516 /******************************************************************************/
517 /*
518  *      Set a new variable scope block. This pushes the old local frame down
519  *      the stack and creates a new local variables frame.
520  */
521
522 int ejsSetBlock(Ejs *ep, EjsVar *local)
523 {
524         ep->local = ejsDupVar(ep, local, EJS_SHALLOW_COPY);
525         ejsMakeObjPermanent(ep->local, 1);
526         return mprAddItem(ep->frames, ep->local);
527 }
528
529 /******************************************************************************/
530 /*
531  *      Close a variable scope block opened via ejsOpenBlock. Pop back the old
532  *      local variables frame.
533  */
534
535 int ejsCloseBlock(Ejs *ep, int fid)
536 {
537         mprAssert(ep->local >= 0);
538         mprAssert(fid >= 0);
539
540         mprAssert(ep->local == (EjsVar*) mprGetItem(ep->frames, fid));
541
542         if (ep->local) {
543                 /* Allow GC */
544                 ejsMakeObjPermanent(ep->local, 0);
545                 ejsFreeVar(ep, ep->local);
546         }
547
548         mprRemoveItemByIndex(ep->frames, fid);
549
550         ep->local = (EjsVar*) mprGetItem(ep->frames, 
551                 mprGetItemCount(ep->frames) - 1);
552
553         return 0;
554 }
555
556 /******************************************************************************/
557 /*
558  *      Create a new variable scope block and evaluate a script. All frames
559  *      created during this context will be automatically deleted when complete.
560  *      vp is optional. i.e. created local variables will be discarded
561  *      when this routine returns.
562  */
563
564 int ejsEvalBlock(Ejs *ep, char *script, EjsVar *vp)
565 {
566         int                     rc, fid;
567
568         mprAssert(script);
569
570         fid = ejsOpenBlock(ep);
571         if (fid < 0) {
572                 return fid;
573         }
574
575         rc = ejsEvalScript(ep, script, vp);
576
577         ejsCloseBlock(ep, fid);
578
579         return rc;
580 }
581
582 /******************************************************************************/
583 /*
584  *      Parse and evaluate a EJS. The script is evaluated at the current context.
585  *      Return the result in *vp. The result is "owned" by EJ and the caller 
586  *      must not free it. Returns -1 on errors and zero for success. 
587  */
588
589 int ejsEvalScript(Ejs *ep, const char *script, EjsVar *vp)
590 {
591         int                     state;
592         
593         ejsClearVar(ep, ep->result);
594         ep->gotException = 0;
595
596         if (script == 0) {
597                 return 0;
598         }
599
600         /*
601          *      Allocate a new evaluation block, and save the old one
602          */
603         if (ejsLexOpenScript(ep, script) < 0) {
604                 return MPR_ERR_MEMORY;
605         }
606
607         /*
608          *      Do the actual parsing and evaluation
609          */
610         ep->scriptStatus = 0;
611
612         do {
613                 state = ejsParse(ep, EJS_STATE_BEGIN, EJS_FLAGS_EXE);
614
615                 if (state == EJS_STATE_RET) {
616                         state = EJS_STATE_EOF;
617                 }
618         } while (state != EJS_STATE_EOF && state != EJS_STATE_ERR);
619
620         ejsLexCloseScript(ep);
621
622         if (state == EJS_STATE_ERR) {
623                 return -1;
624         }
625
626         if (vp) {
627                 /* Caller must not free. */
628                 *vp = *ep->result;
629         }
630
631         return ep->scriptStatus;
632 }
633
634 /******************************************************************************/
635
636 void ejsSetFileName(Ejs *ep, const char *fileName)
637 {
638         mprFree(ep->fileName);
639         ep->fileName = mprStrdup(ep, fileName);
640 }
641
642 /******************************************************************************/
643 /*
644  *      Format the stack backtrace
645  */
646
647 char *ejsFormatStack(Ejs* ep)
648 {
649         EjsInput        *ip;
650         char            *errbuf;
651         int                     frame, len;
652
653         mprAssert(ep);
654
655         ip = ep->input;
656
657         errbuf = 0;
658
659         len = 0;
660         frame = 0;
661         while (ip && frame < EJS_MAX_BACKTRACE) {
662                 char *traceLine, *newErrbuf, *line;
663                 for (line = ip->line; *line && isspace(*line); line++) {
664                         ;
665                 }
666                 mprAllocSprintf(MPR_LOC_ARGS(ep), &traceLine, MPR_MAX_STRING,
667                         " [%02d] %s, %s, line %d -> %s\n",
668                         frame++, 
669                         ip->fileName ? ip->fileName : "script",
670                         ip->procName ? ip->procName: "global", 
671                         ip->lineNumber, line);
672                 if (traceLine == 0) {
673                         break;
674                 }
675                 newErrbuf = mprRealloc(ep, errbuf, len + strlen(traceLine) + 1);
676                 if (newErrbuf == NULL) {
677                         break;
678                 }
679                 errbuf = newErrbuf;
680                 memcpy(&errbuf[len], traceLine, strlen(traceLine) + 1);
681                 len += strlen(traceLine);
682                 mprFree(traceLine);
683                 ip = ip->next;
684         }
685         return errbuf;
686 }
687
688 /******************************************************************************/
689 /*
690  *      Internal use method to set the error message
691  *
692  *      Error, ArgError, AssertError, IOError, MemoryError, RangeError, 
693  *              ReferenceError, SyntaxError, TypeError, MemoryError
694  */
695
696 void ejsError(Ejs* ep, const char *errorType, const char* fmt, ...)
697 {
698         va_list         fmtArgs;
699         EjsVar          *error;
700         char            *msg, *stack;
701
702         va_start(fmtArgs, fmt);
703         mprAllocVsprintf(MPR_LOC_ARGS(ep), &msg, MPR_MAX_STRING, fmt, fmtArgs);
704         va_end(fmtArgs);
705
706         /*
707          *      Create a new Error exception object. If bad error type, default to 
708          *      "Error"
709          */
710         if (ejsGetClass(ep, 0, errorType) == 0) {
711                 errorType = "Error";
712         }
713         ep->gotException = 1;
714         
715         error = ejsCreateObj(ep, 0, errorType, msg);
716         if (error == 0) {
717                 return;
718         }
719         mprFree(msg);
720
721         stack = ejsFormatStack(ep);
722         ejsSetPropertyToString(ep, error, "stack", stack);
723         mprFree(stack);
724
725         ejsWriteVar(ep, ep->result, error, EJS_SHALLOW_COPY);
726         ejsFreeVar(ep, error);
727 }
728
729 /******************************************************************************/
730
731 void ejsSyntaxError(Ejs *ep, const char *msg)
732 {
733         if (msg == 0) {
734                 msg = " ";
735         }
736         ejsError(ep, EJS_SYNTAX_ERROR, msg);
737 }
738
739 /******************************************************************************/
740
741 void ejsMemoryError(Ejs *ep)
742 {
743         ejsError(ep, EJS_MEMORY_ERROR, "Memory allocation error");
744 }
745
746 /******************************************************************************/
747
748 void ejsArgError(Ejs *ep, const char *msg)
749 {
750         mprAssert(msg && *msg);
751
752         ejsError(ep, EJS_ARG_ERROR, msg);
753 }
754
755 /******************************************************************************/
756
757 void ejsInternalError(Ejs *ep, const char *msg)
758 {
759         mprAssert(msg && *msg);
760
761         ejsError(ep, EJS_INTERNAL_ERROR, msg);
762 }
763
764 /******************************************************************************/
765 /*
766  *      Public routine to set the error message. Caller MUST NOT free.
767  */
768
769 char *ejsGetErrorMsg(Ejs *ep)
770 {
771         EjsVar          *error;
772         const char      *message, *stack, *name;
773         char            *buf;
774
775         error = ep->result;
776
777         if (! ejsVarIsObject(error)) {
778                 name = message = stack = 0;
779         } else {
780                 name = ejsGetPropertyAsString(ep, error, "name");
781                 message = ejsGetPropertyAsString(ep, error, "message");
782                 stack = ejsGetPropertyAsString(ep, error, "stack");
783         }
784         if (name == 0 || message == 0) {
785                 buf = mprStrdup(ep, "Unspecified execution error\n");
786         } else {
787                 mprAllocSprintf(MPR_LOC_ARGS(ep), &buf, 0, 
788                         "%s Exception: %s\nStack:\n%s\n",
789                         name, message, stack ? stack : " " );
790         }
791         mprFree(ep->errorMsg);
792         ep->errorMsg = buf;
793         return buf;
794 }
795
796 /******************************************************************************/
797 /*
798  *      Get the current line number
799  */
800
801 int ejsGetLineNumber(Ejs *ep)
802 {
803         if (ep->input == 0) {
804                 return -1;
805         }
806         return ep->input->lineNumber;
807 }
808
809 /******************************************************************************/
810 /*
811  *      Return the local object
812  */
813
814 EjsVar *ejsGetLocalObj(Ejs *ep)
815 {
816         return ep->local;
817 }
818
819 /******************************************************************************/
820 /*
821  *      Return the global object
822  */
823
824 EjsVar *ejsGetGlobalObj(Ejs *ep)
825 {
826         return ep->global;
827 }
828
829 /******************************************************************************/
830 /*
831  *      Set the expression return value
832  */
833
834 void ejsSetReturnValue(Ejs *ep, EjsVar *vp)
835 {
836         mprAssert(ep);
837         mprAssert(vp);
838
839         if (vp == 0) {
840                 return;
841         }
842         ejsWriteVar(ep, ep->result, vp, EJS_SHALLOW_COPY);
843 }
844
845 /******************************************************************************/
846 /*
847  *      Set the expression return value and free the arg.
848  */
849
850 void ejsSetReturnValueAndFree(Ejs *ep, EjsVar *vp)
851 {
852         mprAssert(ep);
853         mprAssert(vp);
854
855         ejsWriteVar(ep, ep->result, vp, EJS_SHALLOW_COPY);
856         ejsFreeVar(ep, vp);
857 }
858
859 /******************************************************************************/
860 /*
861  *      Set the expression return value to a string value.
862  */
863
864 void ejsSetReturnValueToString(Ejs *ep, const char *value)
865 {
866         mprAssert(ep);
867         mprAssert(value);
868
869         ejsWriteVarAsString(ep, ep->result, value);
870 }
871
872 /******************************************************************************/
873 /*
874  *      Set the expression return value to a binary string value.
875  */
876
877 void ejsSetReturnValueToBinaryString(Ejs *ep, const uchar *value, int len)
878 {
879         mprAssert(ep);
880         mprAssert(value);
881
882         ejsWriteVarAsBinaryString(ep, ep->result, value, len);
883 }
884
885 /******************************************************************************/
886 /*
887  *      Set the expression return value to a integer value.
888  */
889
890 void ejsSetReturnValueToInteger(Ejs *ep, int value)
891 {
892         mprAssert(ep);
893
894         ejsWriteVarAsInteger(ep, ep->result, value);
895 }
896
897 /******************************************************************************/
898 /*
899  *      Set the expression return value to an EjsNum value.
900  */
901
902 void ejsSetReturnValueToNumber(Ejs *ep, EjsNum value)
903 {
904         mprAssert(ep);
905
906         ejsWriteVarAsNumber(ep, ep->result, value);
907 }
908
909 /******************************************************************************/
910 /*
911  *      Set the expression return value to a boolean value.
912  */
913
914 void ejsSetReturnValueToBoolean(Ejs *ep, int value)
915 {
916         mprAssert(ep);
917
918         ejsWriteVarAsBoolean(ep, ep->result, value);
919 }
920
921 /******************************************************************************/
922 /*
923  *      Set the expression return value to a boolean value.
924  */
925
926 void ejsSetReturnValueToUndefined(Ejs *ep)
927 {
928         mprAssert(ep);
929
930         ejsWriteVarAsUndefined(ep, ep->result);
931 }
932
933 /******************************************************************************/
934 /*
935  *      Get the expression return value
936  */
937
938 EjsVar *ejsGetReturnValue(Ejs *ep)
939 {
940         mprAssert(ep);
941
942         return ep->result;
943 }
944
945 /******************************************************************************/
946
947 void *ejsGetUserData(Ejs *ep)
948 {
949         mprAssert(ep);
950
951         return ep->userData;
952 }
953
954 /******************************************************************************/
955 /*
956  *      Get a variable given a full variable spec possibly containing "." or "[]".
957  */
958
959 EjsVar *ejsGetVar(Ejs *ep, const char *fullName)
960 {
961         mprAssert(ep);
962         mprAssert(fullName && *fullName);
963
964         return ejsFindProperty(ep, 0, 0, ep->global, ep->local, fullName, 0);
965 }
966
967 /******************************************************************************/
968 /*
969  *      Get a string var given a full variable spec possibly containing "." or "[]".
970  */
971
972 const char *ejsGetStr(Ejs *ep, const char *fullName, const char *defaultValue)
973 {
974         EjsVar  *vp;
975
976         mprAssert(fullName && *fullName);
977
978         vp = ejsFindProperty(ep, 0, 0, ep->global, ep->local, fullName, 0);
979         if (vp == 0 || !ejsVarIsString(vp)) {
980                 return defaultValue;
981         }
982         /* MOB -- what about VarToStr */
983         return vp->string;
984 }
985
986 /******************************************************************************/
987 /*
988  *      Get an int var given a full variable spec possibly containing "." or "[]".
989  */
990
991 int ejsGetInt(Ejs *ep, const char *fullName, int defaultValue)
992 {
993         EjsVar  *vp;
994
995         mprAssert(ep);
996         mprAssert(fullName && *fullName);
997
998         vp = ejsFindProperty(ep, 0, 0, ep->global, ep->local, fullName, 0);
999         if (vp == 0 || !ejsVarIsInteger(vp)) {
1000                 return defaultValue;
1001         }
1002         /* MOB -- should use VarToInt */
1003         return vp->integer;
1004 }
1005
1006 /******************************************************************************/
1007 /*
1008  *      Get an bool var given a full variable spec possibly containing "." or "[]".
1009  */
1010
1011 int ejsGetBool(Ejs *ep, const char *fullName, int defaultValue)
1012 {
1013         EjsVar  *vp;
1014
1015         mprAssert(ep);
1016         mprAssert(fullName && *fullName);
1017
1018         vp = ejsFindProperty(ep, 0, 0, ep->global, ep->local, fullName, 0);
1019         if (vp == 0 || !ejsVarIsBoolean(vp)) {
1020                 return defaultValue;
1021         }
1022         /* MOB -- should use VarToBool */
1023         return vp->boolean;
1024 }
1025
1026 /******************************************************************************/
1027 /*
1028  *      Set a variable that may be an arbitrarily complex object or array reference.
1029  *      Will always define in the top most variable frame.
1030  */
1031
1032 int ejsSetVar(Ejs *ep, const char *fullName, const EjsVar *value)
1033 {
1034         EjsVar          *vp;
1035
1036         mprAssert(fullName && *fullName);
1037
1038         vp = ejsFindProperty(ep, 0, 0, ep->global, ep->local, fullName, 1);
1039         if (vp == 0) {
1040                 return MPR_ERR_CANT_CREATE;
1041         }
1042
1043         if (ejsWriteVar(ep, vp, value, EJS_SHALLOW_COPY) == 0) {
1044                 return MPR_ERR_CANT_WRITE;
1045         }
1046
1047         return 0;
1048 }
1049
1050 /******************************************************************************/
1051 /*
1052  *      Set a variable that may be an arbitrarily complex object or array reference.
1053  *      Will always define in the top most variable frame.
1054  */
1055
1056 int ejsSetStr(Ejs *ep, const char *fullName, const char *value)
1057 {
1058         EjsVar          *vp;
1059
1060         mprAssert(fullName && *fullName);
1061
1062         vp = ejsFindProperty(ep, 0, 0, ep->global, ep->local, fullName, 1);
1063         if (vp == 0) {
1064                 return MPR_ERR_CANT_CREATE;
1065         }
1066
1067         if (ejsWriteVarAsString(ep, vp, value) == 0) {
1068                 return MPR_ERR_CANT_WRITE;
1069         }
1070
1071         return 0;
1072 }
1073
1074 /******************************************************************************/
1075 /*
1076  *      Set a variable that may be an arbitrarily complex object or array reference.
1077  *      Will always define in the top most variable frame.
1078  */
1079
1080 int ejsSetInt(Ejs *ep, const char *fullName, int value)
1081 {
1082         EjsVar          *vp;
1083
1084         mprAssert(fullName && *fullName);
1085
1086         vp = ejsFindProperty(ep, 0, 0, ep->global, ep->local, fullName, 1);
1087         if (vp == 0) {
1088                 return MPR_ERR_CANT_CREATE;
1089         }
1090
1091         /*      Can't fail */
1092         ejsWriteVarAsInteger(ep, vp, value);
1093
1094         return 0;
1095 }
1096
1097 /******************************************************************************/
1098 /*
1099  *      Set a variable that may be an arbitrarily complex object or array reference.
1100  *      Will always define in the top most variable frame.
1101  */
1102
1103 int ejsSetBool(Ejs *ep, const char *fullName, bool value)
1104 {
1105         EjsVar          *vp;
1106
1107         mprAssert(fullName && *fullName);
1108
1109         vp = ejsFindProperty(ep, 0, 0, ep->global, ep->local, fullName, 1);
1110         if (vp == 0) {
1111                 return MPR_ERR_CANT_CREATE;
1112         }
1113
1114         /* Can't fail */
1115         ejsWriteVarAsBoolean(ep, vp, value);
1116
1117         return 0;
1118 }
1119
1120 /******************************************************************************/
1121 /*
1122  *      Set a variable that may be an arbitrarily complex object or array reference.
1123  *      Will always define in the top most variable frame. Free the value passed in.
1124  */
1125
1126 int ejsSetVarAndFree(Ejs *ep, const char *fullName, EjsVar *value)
1127 {
1128         EjsVar          *vp;
1129
1130         mprAssert(fullName && *fullName);
1131
1132         vp = ejsFindProperty(ep, 0, 0, ep->global, ep->local, fullName, 1);
1133         if (vp == 0) {
1134                 return MPR_ERR_CANT_CREATE;
1135         }
1136
1137         if (ejsWriteVar(ep, vp, value, EJS_SHALLOW_COPY) == 0) {
1138                 ejsFreeVar(ep, value);
1139                 return MPR_ERR_CANT_WRITE;
1140         }
1141
1142         ejsFreeVar(ep, value);
1143         return 0;
1144 }
1145
1146 /******************************************************************************/
1147 /*
1148  *      Delete a variable
1149  */
1150
1151 int ejsDeleteVar(Ejs *ep, const char *fullName)
1152 {
1153         EjsVar          *vp;
1154         EjsVar          *obj;
1155         char            *propertyName;
1156
1157         vp = ejsFindProperty(ep, &obj, &propertyName, ep->global, ep->local, 
1158                 fullName, 0);
1159         if (vp == 0) {
1160                 return -1;
1161         }
1162
1163         mprAssert(propertyName);
1164         mprAssert(propertyName);
1165
1166         return ejsDeleteProperty(ep, obj, propertyName);
1167 }
1168
1169 /******************************************************************************/
1170 /*
1171  *      Utility routine to crack JavaScript arguments. Return the number of args
1172  *      seen. This routine only supports %s and %d type args.
1173  *
1174  *      Typical usage:
1175  *
1176  *              if (ejsParseArgs(argc, argv, "%s %d", &name, &age) < 2) {
1177  *                      // Insufficient args
1178  *                      return -1;
1179  *              }
1180  */ 
1181
1182 int ejsParseArgs(int argc, char **argv, const char *fmt, ...)
1183 {
1184         va_list         vargs;
1185         const char      *cp;
1186         char            **sp, *s;
1187         int                     *bp, *ip, argn;
1188
1189         va_start(vargs, fmt);
1190
1191         if (argv == 0) {
1192                 return 0;
1193         }
1194
1195         for (argn = 0, cp = fmt; cp && *cp && argn < argc && argv[argn]; ) {
1196                 if (*cp++ != '%') {
1197                         continue;
1198                 }
1199
1200                 s = argv[argn];
1201                 switch (*cp) {
1202                 case 'b':
1203                         bp = va_arg(vargs, int*);
1204                         if (bp) {
1205                                 if (strcmp(s, "true") == 0 || s[0] == '1') {
1206                                         *bp = 1;
1207                                 } else {
1208                                         *bp = 0;
1209                                 }
1210                         } else {
1211                                 *bp = 0;
1212                         }
1213                         break;
1214
1215                 case 'd':
1216                         ip = va_arg(vargs, int*);
1217                         *ip = atoi(s);
1218                         break;
1219
1220                 case 's':
1221                         sp = va_arg(vargs, char**);
1222                         *sp = s;
1223                         break;
1224
1225                 default:
1226                         mprAssert(0);
1227                 }
1228                 argn++;
1229         }
1230
1231         va_end(vargs);
1232         return argn;
1233 }
1234
1235 /******************************************************************************/
1236 /*
1237  *      Define the standard classes
1238  */
1239
1240 int ejsDefineStandardClasses(Ejs *master)
1241 {
1242         if (ejsDefineArrayClass(master) != 0 ||
1243                         ejsDefineBooleanClass(master) != 0 || 
1244                         ejsDefineErrorClasses(master) != 0 || 
1245                         ejsDefineFunctionClass(master) != 0 || 
1246                         ejsDefineNumberClass(master) != 0 ||
1247 #if FUTURE
1248                         ejsDefineDateClass(master) != 0 ||
1249 #endif
1250 #if BLD_FEATURE_EJS_E4X
1251                         ejsDefineXmlClasses(master) != 0 ||
1252 #endif
1253 #if BLD_FEATURE_EJS_DB && NOT_HERE
1254                         ejsDefineDbClasses(master) != 0 ||
1255 #endif
1256                         ejsDefineStringClass(master) != 0) {
1257                 return MPR_ERR_MEMORY;
1258         }
1259         return 0;
1260 }
1261
1262 /******************************************************************************/
1263 /*
1264  *      Define the EJS System Object Model
1265  */
1266
1267 int ejsDefineSystemClasses(Ejs *master)
1268 {
1269         if (ejsDefineSystemClass(master) != 0 ||
1270                         ejsDefineAppClass(master) != 0 ||
1271                         ejsDefineMemoryClass(master) != 0 ||
1272                         ejsDefineLogClass(master) != 0 ||
1273                         ejsDefineDebugClass(master) != 0 ||
1274                         ejsDefineGCClass(master) != 0 ||
1275                         ejsDefineFileSystemClass(master) != 0 ||
1276 #if BREW
1277                         ejsDefineFileClass(master) != 0 ||
1278                         ejsDefineHTTPClass(master) != 0 ||
1279 #endif
1280                         ejsDefineGlobalProperties(master) != 0) {
1281                 return MPR_ERR_MEMORY;
1282         }
1283         return 0;
1284 }
1285
1286 /******************************************************************************/
1287 /*
1288  *      Terminate the system object model and classes
1289  */
1290
1291 int ejsTermSystemClasses(Ejs *master)
1292 {
1293 #if BREW
1294         ejsTermHTTPClass(master);
1295 #endif
1296         return 0;
1297 }
1298
1299 /******************************************************************************/
1300 /*
1301  *      Define the EJS object model
1302  */
1303
1304 int ejsCreateObjectModel(Ejs *ejs)
1305 {
1306         EjsProperty             *pp;
1307
1308         pp = ejsSetPropertyToNewObj(ejs, ejs->global, "system", "System", 0);
1309         if (pp == 0) {
1310                 return MPR_ERR_MEMORY;
1311         }
1312
1313         if (ejsSetPropertyToNewObj(ejs, ejsGetVarPtr(pp), "app", "System.App", 
1314                         0) == 0) {
1315                 return MPR_ERR_MEMORY;
1316         }
1317         return 0;
1318 }
1319
1320 /******************************************************************************/
1321
1322 void ejsTrace(Ejs *ep, const char *fmt, ...)
1323 {
1324         va_list         args;
1325         char            buf[MPR_MAX_LOG_STRING];
1326         int                     len;
1327
1328         va_start(args, fmt);
1329         len = mprVsprintf(buf, sizeof(buf) - 1, fmt, args);
1330         va_end(args);
1331
1332         mprLog(ep, 0, buf, len);
1333
1334         va_end(args);
1335 }
1336
1337 /******************************************************************************/
1338
1339 bool ejsGotException(Ejs *ep)
1340 {
1341         return (bool) ep->gotException;
1342 }
1343
1344 /******************************************************************************/
1345
1346 void ejsSetPrimaryHandle(Ejs *ep, void *primaryHandle)
1347 {
1348         mprAssert(ep);
1349
1350         ep->primaryHandle = primaryHandle;
1351 }
1352
1353 /******************************************************************************/
1354
1355 void ejsSetAlternateHandle(Ejs *ep, void *alternateHandle)
1356 {
1357         mprAssert(ep);
1358
1359         ep->altHandle = alternateHandle;
1360 }
1361
1362 /******************************************************************************/
1363
1364 #else
1365 void ejsDummy() {}
1366
1367 #endif /* BLD_FEATURE_EJS */
1368
1369 /******************************************************************************/
1370 /*
1371  * Local variables:
1372  * tab-width: 4
1373  * c-basic-offset: 4
1374  * End:
1375  * vim:tw=78
1376  * vim600: sw=4 ts=4 fdm=marker
1377  * vim<600: sw=4 ts=4
1378  */