c01f4111612099c4dff1e5b13d7e864adbeca2d9
[ira/wip.git] / source4 / 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        "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 && mprVarIsNumber(argv[0]->type)) {
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 {
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
195         lp = mprCreatePropertyValue(obj, "length", mprCreateIntegerVar(max));
196         mprAssert(lp);
197
198         mprSetVarReadonly(lp, 1);
199         mprAddVarTrigger(lp, lengthTrigger);
200
201         return 0;
202 }
203
204 /******************************************************************************/
205 /*
206  *      Boolean constructor
207  */
208
209 static int booleanConsProc(EjsHandle eid, int argc, MprVar **argv)
210 {
211         objectConsProc(eid, argc, argv);
212         return 0;
213 }
214
215 /******************************************************************************/
216 #if FUTURE
217 /*
218  *      Date constructor
219  */
220
221 static int dateConsProc(EjsHandle eid, int argc, MprVar **argv)
222 {
223         objectConsProc(eid, argc, argv);
224         return 0;
225 }
226
227 #endif
228 /******************************************************************************/
229 /*
230  *      Number constructor
231  */
232
233 static int numberConsProc(EjsHandle eid, int argc, MprVar **argv)
234 {
235         objectConsProc(eid, argc, argv);
236         return 0;
237 }
238
239 /******************************************************************************/
240 /*
241  *      String constructor
242  */
243
244 static int stringConsProc(EjsHandle eid, int argc, MprVar **argv)
245 {
246         objectConsProc(eid, argc, argv);
247         return 0;
248 }
249
250 /******************************************************************************/
251 /********************************** Functions *********************************/
252 /******************************************************************************/
253
254 static int toStringProc(EjsHandle eid, int argc, MprVar **argv)
255 {
256         MprVar  *obj;
257         Ejs             *ep;
258         char    *buf;
259         int             radix;
260
261         if (argc == 0) {
262                 radix = 10;
263
264         } else if (argc == 1) {
265                 radix = (int) mprVarToInteger(argv[0]);
266
267         } else {
268                 mprAssert(0);
269                 return -1;
270         }
271
272         if((ep = ejsPtr(eid)) == NULL) {
273                 return -1;
274         }
275
276         obj = mprGetProperty(ep->local, "this", 0);
277         mprAssert(obj);
278
279         mprVarToString(&buf, MPR_MAX_STRING, 0, obj);
280         mprCopyVarValue(&ep->result, mprCreateStringVar(buf, 0), MPR_SHALLOW_COPY);
281         mprFree(buf);
282
283         return 0;
284 }
285
286 /******************************************************************************/
287
288 static int valueOfProc(EjsHandle eid, int argc, MprVar **argv)
289 {
290         MprVar  *obj;
291         Ejs             *ep;
292
293         if (argc != 0) {
294                 mprAssert(0);
295                 return -1;
296         }
297
298         if((ep = ejsPtr(eid)) == NULL) {
299                 return -1;
300         }
301
302         obj = mprGetProperty(ep->local, "this", 0);
303         mprAssert(obj);
304
305         switch (obj->type) {
306         default:
307         case MPR_TYPE_UNDEFINED:
308         case MPR_TYPE_NULL:
309         case MPR_TYPE_CFUNCTION:
310         case MPR_TYPE_OBJECT:
311         case MPR_TYPE_FUNCTION:
312         case MPR_TYPE_STRING_CFUNCTION:
313         case MPR_TYPE_PTR:
314                 mprCopyVar(&ep->result, obj, MPR_SHALLOW_COPY);
315                 break;
316
317         case MPR_TYPE_STRING:
318                 mprCopyVarValue(&ep->result, mprCreateIntegerVar(atoi(obj->string)), 0);
319                 break;
320
321         case MPR_TYPE_BOOL:
322         case MPR_TYPE_INT:
323 #if BLD_FEATURE_INT64
324         case MPR_TYPE_INT64:
325 #endif
326 #if BLD_FEATURE_FLOATING_POINT
327         case MPR_TYPE_FLOAT:
328 #endif
329                 mprCopyVar(&ep->result, obj, 0);
330                 break;
331         } 
332         return 0;
333 }
334
335 /******************************************************************************/
336 /*
337  *      Var access trigger on the Array.length property. Return the count of
338  *      enumerable properties (don't count functions).
339  */
340
341 static MprVarTriggerStatus lengthTrigger(MprVarTriggerOp op, 
342         MprProperties *parentProperties, MprVar *prop, MprVar *newValue, 
343         bool copyRef)
344 {
345         switch (op) {
346         case MPR_VAR_READ:
347                 /*
348                  *      Subtract one for the length property
349                  *      FUTURE -- need an API to access parentProperties
350                  *      FUTURE -- contradiction to be read-only yet allow USE_NEW_VALUE.
351                  *              API needs finer control.
352                  */
353                 *newValue = mprCreateIntegerVar(parentProperties->numDataItems - 1);
354                 return MPR_TRIGGER_USE_NEW_VALUE;
355
356         case MPR_VAR_WRITE:
357                 return MPR_TRIGGER_ABORT;
358
359         case MPR_VAR_CREATE_PROPERTY:
360         case MPR_VAR_DELETE_PROPERTY:
361         case MPR_VAR_DELETE:
362         default:
363                 break;
364         }
365         return MPR_TRIGGER_PROCEED;
366 }
367
368 /******************************************************************************/
369 /**************************** Extension Functions *****************************/
370 /******************************************************************************/
371 /*
372  *      Assert 
373  */
374
375 static int assertProc(EjsHandle eid, int argc, MprVar **argv)
376 {
377         bool    b;
378
379         if (argc < 1) {
380                 ejsSetErrorMsg(eid, "usage: assert(condition)\n");
381                 return -1;
382         }
383         b = mprVarToBool(argv[0]);
384         if (b == 0) {
385                 ejsSetErrorMsg(eid, "Assertion failure\n");
386                 return -1;
387         }
388         ejsSetReturnValue(eid, mprCreateBoolVar(b));
389         return 0;
390 }
391
392 /******************************************************************************/
393 /*
394  *      Exit 
395  */
396
397 static int exitProc(EjsHandle eid, int argc, MprVar **argv)
398 {
399         int                     status;
400
401         if (argc < 1) {
402                 ejsSetErrorMsg(eid, "usage: exit(status)\n");
403                 return -1;
404         }
405         status = (int) mprVarToInteger(argv[0]);
406         ejsSetExitStatus(eid, status);
407
408         ejsSetReturnValue(eid, mprCreateStringVar("", 0));
409         return 0;
410 }
411
412 /******************************************************************************/
413
414 static void printVar(MprVar *vp, int recurseCount, int indent)
415 {
416         MprVar  *np;
417         char    *buf;
418         int             i;
419
420         if (recurseCount > 5) {
421                 write(1, "Skipping - recursion too deep\n", 29);
422                 return;
423         }
424
425         for (i = 0; i < indent; i++) {
426                 write(1, "  ", 2);
427         }
428
429         if (vp->type == MPR_TYPE_OBJECT) {
430                 if (vp->name) {
431                         write(1, vp->name, strlen(vp->name));
432                 } else {
433                         write(1, "unknown", 7);
434                 }
435                 write(1, ": {\n", 4);
436                 np = mprGetFirstProperty(vp, MPR_ENUM_DATA);
437                 while (np) {
438                         if (strcmp(np->name, "local") == 0 ||
439                                         strcmp(np->name, "global") == 0 ||
440                                         strcmp(np->name, "this") == 0) {
441                                 np = mprGetNextProperty(vp, np, MPR_ENUM_DATA);
442                                 continue;
443                         }
444                         printVar(np, recurseCount + 1, indent + 1);
445                         np = mprGetNextProperty(vp, np, MPR_ENUM_DATA);
446                         if (np) {
447                                 write(1, ",\n", 2);
448                         }
449                 }
450                 write(1, "\n", 1);
451                 for (i = 0; i < indent; i++) {
452                         write(1, "  ", 2);
453                 }
454                 write(1, "}", 1);
455
456         } else {
457                 if (vp->name) {
458                         write(1, vp->name, strlen(vp->name));
459                 } else {
460                         write(1, "unknown", 7);
461                 }
462                 write(1, ": ", 2);
463
464                 /*      FUTURE -- other types ? */
465                 mprVarToString(&buf, MPR_MAX_STRING, 0, vp);
466                 if (vp->type == MPR_TYPE_STRING) {
467                         write(1, "\"", 1);
468                 }
469                 write(1, buf, strlen(buf));
470                 if (vp->type == MPR_TYPE_STRING) {
471                         write(1, "\"", 1);
472                 }
473                 mprFree(buf);
474         }
475 }
476
477 /******************************************************************************/
478 /*
479  *      Print the args to stdout
480  */
481
482 static int printVarsProc(EjsHandle eid, int argc, MprVar **argv)
483 {
484         MprVar  *vp;
485         char    *buf;
486         int             i;
487
488         for (i = 0; i < argc; i++) {
489                 vp = argv[i];
490                 switch (vp->type) {
491                 case MPR_TYPE_OBJECT:
492                         printVar(vp, 0, 0);
493                         break;
494                 default:
495                         mprVarToString(&buf, MPR_MAX_STRING, 0, vp);
496                         write(1, buf, strlen(buf));
497                         mprFree(buf);
498                         break;
499                 }
500         }
501         write(1, "\n", 1);
502
503         ejsSetReturnValue(eid, mprCreateStringVar("", 0));
504         return 0;
505 }
506
507 /******************************************************************************/
508 /*
509  *      Print the args to stdout
510  */
511
512 static int printProc(EjsHandle eid, int argc, MprVar **argv)
513 {
514         char    *buf;
515         int             i;
516
517         for (i = 0; i < argc; i++) {
518                 mprVarToString(&buf, MPR_MAX_STRING, 0, argv[i]);
519                 write(1, buf, strlen(buf));
520                 mprFree(buf);
521         }
522         return 0;
523 }
524
525 /******************************************************************************/
526 /*
527  *      println
528  */
529
530 static int printlnProc(EjsHandle eid, int argc, MprVar **argv)
531 {
532         printProc(eid, argc, argv);
533         write(1, "\n", 1);
534         return 0;
535 }
536
537 /******************************************************************************/
538 /*
539  *      Trace 
540  */
541
542 static int traceProc(EjsHandle eid, int argc, char **argv)
543 {
544         if (argc == 1) {
545                 mprLog(0, "%s", argv[0]);
546
547         } else if (argc == 2) {
548                 mprLog(atoi(argv[0]), "%s", argv[1]);
549
550         } else {
551                 ejsSetErrorMsg(eid, "Usage: trace([level], message)");
552                 return -1;
553         }
554         ejsSetReturnString(eid, "");
555         return 0;
556 }
557
558 /******************************************************************************/
559 /*
560  *      Return the object reference count
561  */
562
563 static int refCountProc(EjsHandle eid, int argc, MprVar **argv)
564 {
565         MprVar          *vp;
566         int                     count;
567
568         vp = argv[0];
569         if (vp->type == MPR_TYPE_OBJECT) {
570                 count = mprGetVarRefCount(vp);
571                 ejsSetReturnValue(eid, mprCreateIntegerVar(count));
572         } else {
573                 ejsSetReturnValue(eid, mprCreateIntegerVar(0));
574         }
575
576         return 0;
577 }
578
579 /******************************************************************************/
580 /*
581  *      Evaluate a sub-script. It is evaluated in the same variable scope as
582  *      the calling script / function.
583  */
584
585 static int evalScriptProc(EjsHandle eid, int argc, MprVar **argv)
586 {
587         MprVar          *arg;
588         char            *emsg;
589         int                     i;
590
591         ejsSetReturnValue(eid, mprCreateUndefinedVar());
592
593         for (i = 0; i < argc; i++) {
594                 arg = argv[i];
595                 if (arg->type != MPR_TYPE_STRING) {
596                         continue;
597                 }
598                 if (ejsEvalScript(eid, arg->string, 0, &emsg) < 0) {
599                         ejsSetErrorMsg(eid, "%s", emsg);
600                         mprFree(emsg);
601                         return -1;
602                 }
603         }
604         /*
605          *      Return with the value of the last expression
606          */
607         return 0;
608 }
609
610 /******************************************************************************/
611 /******************************************************************************/
612 /******************************************************************************/
613 /*
614  *      Define the standard properties and functions inherited by all script engines.
615  */
616
617 int ejsDefineStandardProperties(MprVar *obj)
618 {
619 #if BLD_FEATURE_FLOATING_POINT
620         double  d = 0.0;
621
622         /*      FUTURE - this generates warnings on some systems. This is okay. */
623
624         mprCreatePropertyValue(obj, "NaN", mprCreateFloatVar(0.0 / d));
625         d = MAX_FLOAT;
626         mprCreatePropertyValue(obj, "Infinity", mprCreateFloatVar(d * d));
627 #endif
628         mprCreatePropertyValue(obj, "null", mprCreateNullVar());
629         mprCreatePropertyValue(obj, "undefined", mprCreateUndefinedVar());
630         mprCreatePropertyValue(obj, "true", mprCreateBoolVar(1));
631         mprCreatePropertyValue(obj, "false", mprCreateBoolVar(0));
632
633 #if BLD_FEATURE_LEGACY_API
634         /*
635          *      DEPRECATED: 2.0.
636          *      So that ESP/ASP can ignore "language=javascript" statements
637          */
638         mprCreatePropertyValue(obj, "javascript", mprCreateIntegerVar(0));
639 #endif
640
641         /*
642          *      Extension functions
643          */
644         mprCreatePropertyValue(obj, "assert", 
645                 mprCreateCFunctionVar(assertProc, 0, MPR_VAR_SCRIPT_HANDLE));
646         mprCreatePropertyValue(obj, "eval", 
647                 mprCreateCFunctionVar(evalScriptProc, 0, MPR_VAR_SCRIPT_HANDLE));
648         mprCreatePropertyValue(obj, "exit", 
649                 mprCreateCFunctionVar(exitProc, 0, MPR_VAR_SCRIPT_HANDLE));
650         mprCreatePropertyValue(obj, "refCount", 
651                 mprCreateCFunctionVar(refCountProc, 0, MPR_VAR_SCRIPT_HANDLE));
652         mprCreatePropertyValue(obj, "print", 
653                 mprCreateCFunctionVar(printProc, 0, MPR_VAR_SCRIPT_HANDLE));
654         mprCreatePropertyValue(obj, "println", 
655                 mprCreateCFunctionVar(printlnProc, 0, MPR_VAR_SCRIPT_HANDLE));
656         mprCreatePropertyValue(obj, "printVars", 
657                 mprCreateCFunctionVar(printVarsProc,0, MPR_VAR_SCRIPT_HANDLE));
658         mprCreatePropertyValue(obj, "trace", 
659                 mprCreateStringCFunctionVar(traceProc, 0, MPR_VAR_SCRIPT_HANDLE));
660
661         /*
662          *      Constructors
663          */
664         mprCreatePropertyValue(obj, "Array", 
665                 mprCreateCFunctionVar(arrayConsProc, 0, MPR_VAR_SCRIPT_HANDLE));
666         mprCreatePropertyValue(obj, "Boolean",
667                 mprCreateCFunctionVar(booleanConsProc, 0, MPR_VAR_SCRIPT_HANDLE));
668         mprCreatePropertyValue(obj, "Object", 
669                 mprCreateCFunctionVar(objectConsProc, 0, MPR_VAR_SCRIPT_HANDLE));
670         mprCreatePropertyValue(obj, "Number", 
671                 mprCreateCFunctionVar(numberConsProc, 0, MPR_VAR_SCRIPT_HANDLE));
672         mprCreatePropertyValue(obj, "String", 
673                 mprCreateCFunctionVar(stringConsProc, 0, MPR_VAR_SCRIPT_HANDLE));
674
675         /*      mprCreatePropertyValue(obj, "Date", 
676          *              mprCreateCFunctionVar(dateConsProc, 0, MPR_VAR_SCRIPT_HANDLE));
677          *      mprCreatePropertyValue(obj, "Regexp", 
678          *              mprCreateCFunctionVar(regexpConsProc, 0, MPR_VAR_SCRIPT_HANDLE));
679          */
680
681         /*
682          *      Can we use on var x = "string text";
683          */
684         return 0;
685 }
686
687 /******************************************************************************/
688
689 #else
690 void ejsProcsDummy() {}
691
692 /******************************************************************************/
693 #endif /* BLD_FEATURE_EJS */
694
695 /*
696  * Local variables:
697  * tab-width: 4
698  * c-basic-offset: 4
699  * End:
700  * vim:tw=78
701  * vim600: sw=4 ts=4 fdm=marker
702  * vim<600: sw=4 ts=4
703  */