r7065: Move ejs from web_server to lib so it can be shared with smbscript.
[samba.git] / source / lib / ejs / ejsProcs.c
1 /*
2  *      @file   ejsProc.c
3  *      @brief  EJS support functions
4  */
5 /********************************* Copyright **********************************/
6 /*
7  *      @copy   default.g
8  *      
9  *      Copyright (c) Mbedthis Software LLC, 2003-2005. All Rights Reserved.
10  *      Portions Copyright (c) GoAhead Software, 1995-2000. All Rights Reserved.
11  *      
12  *      This software is distributed under commercial and open source licenses.
13  *      You may use the GPL open source license described below or you may acquire 
14  *      a commercial license from Mbedthis Software. You agree to be fully bound 
15  *      by the terms of either license. Consult the LICENSE.TXT distributed with 
16  *      this software for full details.
17  *      
18  *      This software is open source; you can redistribute it and/or modify it 
19  *      under the terms of the GNU General Public License as published by the 
20  *      Free Software Foundation; either version 2 of the License, or (at your 
21  *      option) any later version. See the GNU General Public License for more 
22  *      details at: http://www.mbedthis.com/downloads/gplLicense.html
23  *      
24  *      This program is distributed WITHOUT ANY WARRANTY; without even the 
25  *      implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
26  *      
27  *      This GPL license does NOT permit incorporating this software into 
28  *      proprietary programs. If you are unable to comply with the GPL, you must
29  *      acquire a commercial license to use this software. Commercial licenses 
30  *      for this software and support services are available from Mbedthis 
31  *      Software at http://www.mbedthis.com 
32  *      
33  *      @end
34  */
35 /********************************** Includes **********************************/
36
37 #include        "lib/ejs/ejsInternal.h"
38
39 #if BLD_FEATURE_EJS
40
41 /****************************** Forward Declarations **************************/
42 /*
43  *      Object constructors
44  */
45 static int              objectConsProc(EjsHandle eid, int argc, MprVar **argv);
46 static int              arrayConsProc(EjsHandle eid, int argc, MprVar **argv);
47 static int              booleanConsProc(EjsHandle eid, int argc, MprVar **agv);
48 static int              numberConsProc(EjsHandle eid, int argc, MprVar **argv);
49 static int              stringConsProc(EjsHandle eid, int argc, MprVar **argv);
50
51 /*
52  *      Core functions
53  */
54 static int              toStringProc(EjsHandle eid, int argc, MprVar **argv);
55 static int              valueOfProc(EjsHandle eid, int argc, MprVar **argv);
56
57 /*
58  *      Triggers
59  */
60 static MprVarTriggerStatus lengthTrigger(MprVarTriggerOp op, 
61         MprProperties *parentProperties, MprVar *prop, MprVar *newValue,
62         bool copyRef);
63
64 /******************************************************************************/
65 /*
66  *      Routine to create the base common to all object types
67  */
68
69 MprVar ejsCreateObj(const char *name, int hashSize)
70 {
71         MprVar  o;
72
73         o = mprCreateObjVar(name, hashSize);
74         if (o.type == MPR_TYPE_UNDEFINED) {
75                 mprAssert(0);
76                 return o;
77         }
78
79         mprCreatePropertyValue(&o, "toString", 
80                 mprCreateCFunctionVar(toStringProc, 0, MPR_VAR_SCRIPT_HANDLE));
81         mprCreatePropertyValue(&o, "valueOf", 
82                 mprCreateCFunctionVar(valueOfProc, 0, MPR_VAR_SCRIPT_HANDLE));
83         return o;
84 }
85
86 /******************************************************************************/
87 /*
88  *      Routine to destroy a variable
89  */
90
91 bool ejsDestroyVar(MprVar *obj)
92 {
93         return mprDestroyVar(obj);
94 }
95
96 /******************************************************************************/
97 /*
98  *      Routine to create the base array type
99  */
100
101 MprVar ejsCreateArray(const char *name, int size)
102 {
103         MprVar  obj, *lp, undef;
104         char    idx[16];
105         int             i;
106
107         /*      Sanity limit for size of hash table */
108
109         obj = ejsCreateObj(name, max(size, 503));
110         if (obj.type == MPR_TYPE_UNDEFINED) {
111                 mprAssert(0);
112                 return obj;
113         }
114
115         undef = mprCreateUndefinedVar();
116         for (i = 0; i < size; i++) {
117                 mprItoa(i, idx, sizeof(idx));
118                 mprCreateProperty(&obj, idx, &undef);
119         }
120
121         lp = mprCreatePropertyValue(&obj, "length", mprCreateIntegerVar(size));
122         mprAssert(lp);
123
124         mprSetVarReadonly(lp, 1);
125         mprAddVarTrigger(lp, lengthTrigger);
126
127         return obj;
128 }
129
130 /******************************************************************************/
131 /******************************** Constructors ********************************/
132 /******************************************************************************/
133 /*
134  *      Object constructor. Nothing really done here. For future expansion.
135  */
136
137 static int objectConsProc(EjsHandle eid, int argc, MprVar **argv)
138 {
139 #if XX_UNUSED_XX
140         MprVar  *obj;
141         Ejs             *ep;
142
143         if((ep = ejsPtr(eid)) == NULL) {
144                 return -1;
145         }
146
147         obj = mprGetProperty(ep->local, "this", 0);
148         mprAssert(obj);
149 #endif
150         return 0;
151 }
152
153 /******************************************************************************/
154 /*
155  *      Array constructor
156  */
157
158 static int arrayConsProc(EjsHandle eid, int argc, MprVar **argv)
159 {
160         MprVar  *obj, *lp, undef;
161         Ejs             *ep;
162         char    idx[16];
163         int             i, max;
164
165         objectConsProc(eid, argc, argv);
166
167         if((ep = ejsPtr(eid)) == NULL) {
168                 return -1;
169         }
170         obj = mprGetProperty(ep->local, "this", 0);
171         mprAssert(obj);
172
173
174         if (argc == 1) {
175                 /*
176                  *      x = new Array(size);
177                  */
178                 undef = mprCreateUndefinedVar();
179                 max = (int) mprVarToInteger(argv[0]);
180                 for (i = 0; i < max; i++) {
181                         mprItoa(i, idx, sizeof(idx));
182                         mprCreateProperty(obj, idx, &undef);
183                 }
184         } else if (argc > 1) {
185                 /*
186                  *      x = new Array(element0, element1, ..., elementN):
187                  */
188                 max = argc;
189                 for (i = 0; i < max; i++) {
190                         mprItoa(i, idx, sizeof(idx));
191                         mprCreateProperty(obj, idx, argv[i]);
192                 }
193
194         } else {
195                 max = 0;
196         }
197
198         lp = mprCreatePropertyValue(obj, "length", mprCreateIntegerVar(max));
199         mprAssert(lp);
200
201         mprSetVarReadonly(lp, 1);
202         mprAddVarTrigger(lp, lengthTrigger);
203
204         return 0;
205 }
206
207 /******************************************************************************/
208 /*
209  *      Boolean constructor
210  */
211
212 static int booleanConsProc(EjsHandle eid, int argc, MprVar **argv)
213 {
214         objectConsProc(eid, argc, argv);
215         return 0;
216 }
217
218 /******************************************************************************/
219 #if FUTURE
220 /*
221  *      Date constructor
222  */
223
224 static int dateConsProc(EjsHandle eid, int argc, MprVar **argv)
225 {
226         objectConsProc(eid, argc, argv);
227         return 0;
228 }
229
230 #endif
231 /******************************************************************************/
232 /*
233  *      Number constructor
234  */
235
236 static int numberConsProc(EjsHandle eid, int argc, MprVar **argv)
237 {
238         objectConsProc(eid, argc, argv);
239         return 0;
240 }
241
242 /******************************************************************************/
243 /*
244  *      String constructor
245  */
246
247 static int stringConsProc(EjsHandle eid, int argc, MprVar **argv)
248 {
249         objectConsProc(eid, argc, argv);
250         return 0;
251 }
252
253 /******************************************************************************/
254 /********************************** Functions *********************************/
255 /******************************************************************************/
256
257 static int toStringProc(EjsHandle eid, int argc, MprVar **argv)
258 {
259         MprVar  *obj;
260         Ejs             *ep;
261         char    *buf;
262         int             radix;
263
264         if (argc == 0) {
265                 radix = 10;
266
267         } else if (argc == 1) {
268                 radix = (int) mprVarToInteger(argv[0]);
269
270         } else {
271                 mprAssert(0);
272                 return -1;
273         }
274
275         if((ep = ejsPtr(eid)) == NULL) {
276                 return -1;
277         }
278
279         obj = mprGetProperty(ep->local, "this", 0);
280         mprAssert(obj);
281
282         mprVarToString(&buf, MPR_MAX_STRING, 0, obj);
283         mprCopyVarValue(&ep->result, mprCreateStringVar(buf, 0), MPR_SHALLOW_COPY);
284         mprFree(buf);
285
286         return 0;
287 }
288
289 /******************************************************************************/
290
291 static int valueOfProc(EjsHandle eid, int argc, MprVar **argv)
292 {
293         MprVar  *obj;
294         Ejs             *ep;
295
296         if (argc != 0) {
297                 mprAssert(0);
298                 return -1;
299         }
300
301         if((ep = ejsPtr(eid)) == NULL) {
302                 return -1;
303         }
304
305         obj = mprGetProperty(ep->local, "this", 0);
306         mprAssert(obj);
307
308         switch (obj->type) {
309         default:
310         case MPR_TYPE_UNDEFINED:
311         case MPR_TYPE_NULL:
312         case MPR_TYPE_CFUNCTION:
313         case MPR_TYPE_OBJECT:
314         case MPR_TYPE_FUNCTION:
315         case MPR_TYPE_STRING_CFUNCTION:
316                 mprCopyVar(&ep->result, obj, MPR_SHALLOW_COPY);
317                 break;
318
319         case MPR_TYPE_STRING:
320                 mprCopyVarValue(&ep->result, mprCreateIntegerVar(atoi(obj->string)), 0);
321                 break;
322
323         case MPR_TYPE_BOOL:
324         case MPR_TYPE_INT:
325 #if BLD_FEATURE_INT64
326         case MPR_TYPE_INT64:
327 #endif
328 #if BLD_FEATURE_FLOATING_POINT
329         case MPR_TYPE_FLOAT:
330 #endif
331                 mprCopyVar(&ep->result, obj, 0);
332                 break;
333         } 
334         return 0;
335 }
336
337 /******************************************************************************/
338 /*
339  *      Var access trigger on the Array.length property. Return the count of
340  *      enumerable properties (don't count functions).
341  */
342
343 static MprVarTriggerStatus lengthTrigger(MprVarTriggerOp op, 
344         MprProperties *parentProperties, MprVar *prop, MprVar *newValue, 
345         bool copyRef)
346 {
347         switch (op) {
348         case MPR_VAR_READ:
349                 /*
350                  *      Subtract one for the length property
351                  *      FUTURE -- need an API to access parentProperties
352                  *      FUTURE -- contradiction to be read-only yet allow USE_NEW_VALUE.
353                  *              API needs finer control.
354                  */
355                 *newValue = mprCreateIntegerVar(parentProperties->numDataItems - 1);
356                 return MPR_TRIGGER_USE_NEW_VALUE;
357
358         case MPR_VAR_WRITE:
359                 return MPR_TRIGGER_ABORT;
360
361         case MPR_VAR_CREATE_PROPERTY:
362         case MPR_VAR_DELETE_PROPERTY:
363         case MPR_VAR_DELETE:
364         default:
365                 break;
366         }
367         return MPR_TRIGGER_PROCEED;
368 }
369
370 /******************************************************************************/
371 /**************************** Extension Functions *****************************/
372 /******************************************************************************/
373 /*
374  *      Assert 
375  */
376
377 static int assertProc(EjsHandle eid, int argc, MprVar **argv)
378 {
379         bool    b;
380
381         if (argc < 1) {
382                 ejsSetErrorMsg(eid, "usage: assert(condition)\n");
383                 return -1;
384         }
385         b = mprVarToBool(argv[0]);
386         if (b == 0) {
387                 ejsSetErrorMsg(eid, "Assertion failure\n");
388                 return -1;
389         }
390         ejsSetReturnValue(eid, mprCreateBoolVar(b));
391         return 0;
392 }
393
394 /******************************************************************************/
395 /*
396  *      Exit 
397  */
398
399 static int exitProc(EjsHandle eid, int argc, MprVar **argv)
400 {
401         int                     status;
402
403         if (argc < 1) {
404                 ejsSetErrorMsg(eid, "usage: exit(status)\n");
405                 return -1;
406         }
407         status = (int) mprVarToInteger(argv[0]);
408         ejsSetExitStatus(eid, status);
409
410         ejsSetReturnValue(eid, mprCreateStringVar("", 0));
411         return 0;
412 }
413
414 /******************************************************************************/
415
416 static void printVar(MprVar *vp, int recurseCount, int indent)
417 {
418         MprVar  *np;
419         char    *buf;
420         int             i;
421
422         if (recurseCount > 5) {
423                 write(1, "Skipping - recursion too deep\n", 29);
424                 return;
425         }
426
427         for (i = 0; i < indent; i++) {
428                 write(1, "  ", 2);
429         }
430
431         if (vp->type == MPR_TYPE_OBJECT) {
432                 if (vp->name) {
433                         write(1, vp->name, strlen(vp->name));
434                 } else {
435                         write(1, "unknown", 7);
436                 }
437                 write(1, ": {\n", 4);
438                 np = mprGetFirstProperty(vp, MPR_ENUM_DATA);
439                 while (np) {
440                         if (strcmp(np->name, "local") == 0 ||
441                                         strcmp(np->name, "global") == 0 ||
442                                         strcmp(np->name, "this") == 0) {
443                                 np = mprGetNextProperty(vp, np, MPR_ENUM_DATA);
444                                 continue;
445                         }
446                         printVar(np, recurseCount + 1, indent + 1);
447                         np = mprGetNextProperty(vp, np, MPR_ENUM_DATA);
448                         if (np) {
449                                 write(1, ",\n", 2);
450                         }
451                 }
452                 write(1, "\n", 1);
453                 for (i = 0; i < indent; i++) {
454                         write(1, "  ", 2);
455                 }
456                 write(1, "}", 1);
457
458         } else {
459                 if (vp->name) {
460                         write(1, vp->name, strlen(vp->name));
461                 } else {
462                         write(1, "unknown", 7);
463                 }
464                 write(1, ": ", 2);
465
466                 /*      FUTURE -- other types ? */
467                 mprVarToString(&buf, MPR_MAX_STRING, 0, vp);
468                 if (vp->type == MPR_TYPE_STRING) {
469                         write(1, "\"", 1);
470                 }
471                 write(1, buf, strlen(buf));
472                 if (vp->type == MPR_TYPE_STRING) {
473                         write(1, "\"", 1);
474                 }
475                 mprFree(buf);
476         }
477 }
478
479 /******************************************************************************/
480 /*
481  *      Print the args to stdout
482  */
483
484 static int printVarsProc(EjsHandle eid, int argc, MprVar **argv)
485 {
486         MprVar  *vp;
487         char    *buf;
488         int             i;
489
490         for (i = 0; i < argc; i++) {
491                 vp = argv[i];
492                 switch (vp->type) {
493                 case MPR_TYPE_OBJECT:
494                         printVar(vp, 0, 0);
495                         break;
496                 default:
497                         mprVarToString(&buf, MPR_MAX_STRING, 0, vp);
498                         write(1, buf, strlen(buf));
499                         mprFree(buf);
500                         break;
501                 }
502         }
503         write(1, "\n", 1);
504
505         ejsSetReturnValue(eid, mprCreateStringVar("", 0));
506         return 0;
507 }
508
509 /******************************************************************************/
510 /*
511  *      Print the args to stdout
512  */
513
514 static int printProc(EjsHandle eid, int argc, MprVar **argv)
515 {
516         char    *buf;
517         int             i;
518
519         for (i = 0; i < argc; i++) {
520                 mprVarToString(&buf, MPR_MAX_STRING, 0, argv[i]);
521                 write(1, buf, strlen(buf));
522                 mprFree(buf);
523         }
524         return 0;
525 }
526
527 /******************************************************************************/
528 /*
529  *      println
530  */
531
532 static int printlnProc(EjsHandle eid, int argc, MprVar **argv)
533 {
534         printProc(eid, argc, argv);
535         write(1, "\n", 1);
536         return 0;
537 }
538
539 /******************************************************************************/
540 /*
541  *      Trace 
542  */
543
544 static int traceProc(EjsHandle eid, int argc, char **argv)
545 {
546         if (argc == 1) {
547                 mprLog(0, "%s", argv[0]);
548
549         } else if (argc == 2) {
550                 mprLog(atoi(argv[0]), "%s", argv[1]);
551
552         } else {
553                 ejsSetErrorMsg(eid, "Usage: trace([level], message)");
554                 return -1;
555         }
556         ejsSetReturnString(eid, "");
557         return 0;
558 }
559
560 /******************************************************************************/
561 /*
562  *      Return the object reference count
563  */
564
565 static int refCountProc(EjsHandle eid, int argc, MprVar **argv)
566 {
567         MprVar          *vp;
568         int                     count;
569
570         vp = argv[0];
571         if (vp->type == MPR_TYPE_OBJECT) {
572                 count = mprGetVarRefCount(vp);
573                 ejsSetReturnValue(eid, mprCreateIntegerVar(count));
574         } else {
575                 ejsSetReturnValue(eid, mprCreateIntegerVar(0));
576         }
577
578         return 0;
579 }
580
581 /******************************************************************************/
582 /*
583  *      Evaluate a sub-script. It is evaluated in the same variable scope as
584  *      the calling script / function.
585  */
586
587 static int evalScriptProc(EjsHandle eid, int argc, MprVar **argv)
588 {
589         MprVar          *arg;
590         char            *emsg;
591         int                     i;
592
593         ejsSetReturnValue(eid, mprCreateUndefinedVar());
594
595         for (i = 0; i < argc; i++) {
596                 arg = argv[i];
597                 if (arg->type != MPR_TYPE_STRING) {
598                         continue;
599                 }
600                 if (ejsEvalScript(eid, arg->string, 0, &emsg) < 0) {
601                         ejsSetErrorMsg(eid, "%s", emsg);
602                         mprFree(emsg);
603                         return -1;
604                 }
605         }
606         /*
607          *      Return with the value of the last expression
608          */
609         return 0;
610 }
611
612 /******************************************************************************/
613 /******************************************************************************/
614 /******************************************************************************/
615 /*
616  *      Define the standard properties and functions inherited by all script engines.
617  */
618
619 int ejsDefineStandardProperties(MprVar *obj)
620 {
621 #if BLD_FEATURE_FLOATING_POINT
622         double  d = 0.0;
623
624         /*      FUTURE - this generates warnings on some systems. This is okay. */
625
626         mprCreatePropertyValue(obj, "NaN", mprCreateFloatVar(0.0 / d));
627         d = MAX_FLOAT;
628         mprCreatePropertyValue(obj, "Infinity", mprCreateFloatVar(d * d));
629 #endif
630         mprCreatePropertyValue(obj, "null", mprCreateNullVar());
631         mprCreatePropertyValue(obj, "undefined", mprCreateUndefinedVar());
632         mprCreatePropertyValue(obj, "true", mprCreateBoolVar(1));
633         mprCreatePropertyValue(obj, "false", mprCreateBoolVar(0));
634
635 #if BLD_FEATURE_LEGACY_API
636         /*
637          *      DEPRECATED: 2.0.
638          *      So that ESP/ASP can ignore "language=javascript" statements
639          */
640         mprCreatePropertyValue(obj, "javascript", mprCreateIntegerVar(0));
641 #endif
642
643         /*
644          *      Extension functions
645          */
646         mprCreatePropertyValue(obj, "assert", 
647                 mprCreateCFunctionVar(assertProc, 0, MPR_VAR_SCRIPT_HANDLE));
648         mprCreatePropertyValue(obj, "eval", 
649                 mprCreateCFunctionVar(evalScriptProc, 0, MPR_VAR_SCRIPT_HANDLE));
650         mprCreatePropertyValue(obj, "exit", 
651                 mprCreateCFunctionVar(exitProc, 0, MPR_VAR_SCRIPT_HANDLE));
652         mprCreatePropertyValue(obj, "refCount", 
653                 mprCreateCFunctionVar(refCountProc, 0, MPR_VAR_SCRIPT_HANDLE));
654         mprCreatePropertyValue(obj, "print", 
655                 mprCreateCFunctionVar(printProc, 0, MPR_VAR_SCRIPT_HANDLE));
656         mprCreatePropertyValue(obj, "println", 
657                 mprCreateCFunctionVar(printlnProc, 0, MPR_VAR_SCRIPT_HANDLE));
658         mprCreatePropertyValue(obj, "printVars", 
659                 mprCreateCFunctionVar(printVarsProc,0, MPR_VAR_SCRIPT_HANDLE));
660         mprCreatePropertyValue(obj, "trace", 
661                 mprCreateStringCFunctionVar(traceProc, 0, MPR_VAR_SCRIPT_HANDLE));
662
663         /*
664          *      Constructors
665          */
666         mprCreatePropertyValue(obj, "Array", 
667                 mprCreateCFunctionVar(arrayConsProc, 0, MPR_VAR_SCRIPT_HANDLE));
668         mprCreatePropertyValue(obj, "Boolean",
669                 mprCreateCFunctionVar(booleanConsProc, 0, MPR_VAR_SCRIPT_HANDLE));
670         mprCreatePropertyValue(obj, "Object", 
671                 mprCreateCFunctionVar(objectConsProc, 0, MPR_VAR_SCRIPT_HANDLE));
672         mprCreatePropertyValue(obj, "Number", 
673                 mprCreateCFunctionVar(numberConsProc, 0, MPR_VAR_SCRIPT_HANDLE));
674         mprCreatePropertyValue(obj, "String", 
675                 mprCreateCFunctionVar(stringConsProc, 0, MPR_VAR_SCRIPT_HANDLE));
676
677         /*      mprCreatePropertyValue(obj, "Date", 
678          *              mprCreateCFunctionVar(dateConsProc, 0, MPR_VAR_SCRIPT_HANDLE));
679          *      mprCreatePropertyValue(obj, "Regexp", 
680          *              mprCreateCFunctionVar(regexpConsProc, 0, MPR_VAR_SCRIPT_HANDLE));
681          */
682
683         /*
684          *      Can we use on var x = "string text";
685          */
686         return 0;
687 }
688
689 /******************************************************************************/
690
691 #else
692 void ejsProcsDummy() {}
693
694 /******************************************************************************/
695 #endif /* BLD_FEATURE_EJS */
696
697 /*
698  * Local variables:
699  * tab-width: 4
700  * c-basic-offset: 4
701  * End:
702  * vim:tw=78
703  * vim600: sw=4 ts=4 fdm=marker
704  * vim<600: sw=4 ts=4
705  */