r7023: reduced the number of warnings in building ejs and esp
[sfrench/samba-autobuild/.git] / source4 / web_server / ejs / var.c
1 /*
2  *      @file   var.c
3  *      @brief  MPR Universal Variable Type
4  *      @overview
5  *
6  *      @copy   default.m
7  *      
8  *      Copyright (c) Mbedthis Software LLC, 2003-2005. All Rights Reserved.
9  *      Copyright (c) Michael O'Brien, 1994-1995. All Rights Reserved.
10  *      
11  *      This software is distributed under commercial and open source licenses.
12  *      You may use the GPL open source license described below or you may acquire 
13  *      a commercial license from Mbedthis Software. You agree to be fully bound 
14  *      by the terms of either license. Consult the LICENSE.TXT distributed with 
15  *      this software for full details.
16  *      
17  *      This software is open source; you can redistribute it and/or modify it 
18  *      under the terms of the GNU General Public License as published by the 
19  *      Free Software Foundation; either version 2 of the License, or (at your 
20  *      option) any later version. See the GNU General Public License for more 
21  *      details at: http://www.mbedthis.com/downloads/gplLicense.html
22  *      
23  *      This program is distributed WITHOUT ANY WARRANTY; without even the 
24  *      implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 
25  *      
26  *      This GPL license does NOT permit incorporating this software into 
27  *      proprietary programs. If you are unable to comply with the GPL, you must
28  *      acquire a commercial license to use this software. Commercial licenses 
29  *      for this software and support services are available from Mbedthis 
30  *      Software at http://www.mbedthis.com 
31  *      
32  *      @end
33  */
34
35 /******************************* Documentation ********************************/
36
37 /*
38  *      This module is NOT multithreaded. 
39  *
40  *      Properties are variables that are stored in an object type variable.
41  *      Properties can be primitive data types, other objects or functions.
42  *      Properties are indexed by a character name.
43  */
44
45 /********************************** Includes **********************************/
46
47 #include        "web_server/ejs/var.h"
48
49 /*********************************** Locals ***********************************/
50 #if VAR_DEBUG
51
52 static MprProperties    objectList;                     /* Dummy head of objects list */
53 static int                              objectCount = -1;       /* Count of objects */
54
55 #endif
56 /***************************** Forward Declarations ***************************/
57
58 static int              adjustRefCount(MprProperties *pp, int adj);
59 static int              adjustVarRefCount(MprVar *vp, int adj);
60 static MprVar   *allocProperty(const char *propertyName);
61 static void     copyVarCore(MprVar *dest, MprVar *src, int copyDepth);
62 static MprProperties 
63                                 *createProperties(const char *name, int hashSize);
64 static bool     freeVar(MprVar *vp, int force);
65 static bool     freeVarStorage(MprVar *vp, int force);
66 static MprVar   *getObjChain(MprProperties *pp, const char *property);
67 static int              hash(MprProperties *pp, const char *property);
68 static bool             releaseProperties(MprProperties *pp, int force);
69
70 /*********************************** Code *************************************/
71 /*
72  *      Destroy a variable and all referenced variables. Release any referenced 
73  *      object regardless of whether other users still have references. Be VERY
74  *      careful using this routine. 
75  *
76  *      Return TRUE if the underlying data is freed. Objects may not be freed if 
77  *      there are other users of the object.
78  */
79
80 bool mprDestroyAllVars(MprVar *vp)
81 {
82         mprAssert(vp);
83
84         if (vp->trigger) {
85                 if ((vp->trigger)(MPR_VAR_DELETE, vp->parentProperties, vp, 0, 0) 
86                                 == MPR_TRIGGER_ABORT) {
87                         return 0;
88                 }
89         }
90
91         /*
92          *      Free the actual value. If this var refers to an object, we will 
93          *      recurse through all the properties freeing all vars.
94          */
95         return freeVar(vp, 1);
96 }
97
98 /******************************************************************************/
99 /*
100  *      Destroy a variable. Release any referenced object (destroy if no other
101  *      users are referencing).
102  *
103  *      Return TRUE if the underlying data is freed. Objects may not be freed if 
104  *      there are other users of the object.
105  */
106
107 bool mprDestroyVar(MprVar *vp)
108 {
109         mprAssert(vp);
110
111         if (vp->trigger) {
112                 if ((vp->trigger)(MPR_VAR_DELETE, vp->parentProperties, vp, 0, 0) 
113                                 == MPR_TRIGGER_ABORT) {
114                         return 0;
115                 }
116         }
117
118         /*
119          *      Free the actual value. If this var refers to an object, we will 
120          *      recurse through all the properties freeing all that have no other
121          *      references.
122          */
123         return freeVar(vp, 0);
124 }
125
126 /******************************************************************************/
127 /*
128  *      Free the value in a variable for primitive types. Release objects.
129  *
130  *      Return TRUE if the underlying data is freed. Objects may not be freed if 
131  *      there are other users of the object.
132  */
133
134 static bool freeVar(MprVar *vp, int force)
135 {
136         bool    freed;
137
138         mprAssert(vp);
139
140         freed = freeVarStorage(vp, force);
141
142         mprFree(vp->name);
143         mprFree(vp->fullName);
144
145         if (vp->allocatedVar) {
146                 mprFree(vp);
147         } else {
148                 vp->name = 0;
149                 vp->fullName = 0;
150                 vp->type = MPR_TYPE_UNDEFINED;
151         }
152         return freed;
153 }
154
155 /******************************************************************************/
156 /*
157  *      Free the value in a variable for primitive types. Release objects.
158  *
159  *      Return TRUE if the underlying data is freed. Objects may not be freed if 
160  *      there are other users of the object.
161  */
162
163 static bool freeVarStorage(MprVar *vp, int force)
164 {
165         MprArray        *argList;
166         bool            freed;
167         int                     i;
168
169         freed = 1;
170         mprAssert(vp);
171
172         switch (vp->type) {
173         default:
174                 break;
175
176         case MPR_TYPE_STRING:
177                 if (vp->allocatedData && vp->string != 0) {
178                         mprFree(vp->string);
179                         vp->string = 0;
180                         vp->allocatedData = 0;
181                 }
182                 break;
183
184         case MPR_TYPE_OBJECT:
185 #if VAR_DEBUG
186                 /*
187                  *      Recurse through all properties and release / delete. Release the 
188                  *      properties hash table.
189                  */
190                 if (vp->properties->refCount > 1) {
191                         mprLog(7, "freeVar: ACT \"%s\", 0x%x, ref %d, force %d\n", 
192                                 vp->name, vp->properties, vp->properties->refCount, force);
193                 } else {
194                         mprLog(7, "freeVar: DEL \"%s\", 0x%x, ref %d, force %d\n", 
195                                 vp->name, vp->properties, vp->properties->refCount, force);
196                 }
197 #endif
198                 if (vp->allocatedData) {
199                         freed = releaseProperties(vp->properties, force);
200                 }
201                 vp->properties = 0;
202                 break;
203
204         case MPR_TYPE_FUNCTION:
205                 if (vp->allocatedData) {
206                         argList = vp->function.args;
207                         for (i = 0; i < argList->max; i++) {
208                                 if (argList->handles[i] != 0) {
209                                         mprFree(argList->handles[i]);
210                                 }
211                         }
212                         mprDestroyArray(argList);
213                         vp->function.args = 0;
214                         mprFree(vp->function.body);
215                         vp->function.body = 0;
216                 }
217                 break;
218         }
219
220         vp->type = MPR_TYPE_UNDEFINED;
221         return freed;
222 }
223
224 /******************************************************************************/
225 /*
226  *      Adjust the object reference count and return the currrent count of 
227  *      users.
228  */
229
230 static int adjustVarRefCount(MprVar *vp, int adj)
231 {
232         mprAssert(vp);
233
234         if (vp->type != MPR_TYPE_OBJECT) {
235                 mprAssert(vp->type == MPR_TYPE_OBJECT);
236                 return 0;
237         }
238         return adjustRefCount(vp->properties, adj);
239 }
240
241 /******************************************************************************/
242 /*
243  *      Get the object reference count 
244  */
245
246 int mprGetVarRefCount(MprVar *vp)
247 {
248         mprAssert(vp);
249
250         if (vp->type != MPR_TYPE_OBJECT) {
251                 mprAssert(vp->type == MPR_TYPE_OBJECT);
252                 return 0;
253         }
254         return adjustRefCount(vp->properties, 0);
255 }
256
257 /******************************************************************************/
258 /*
259  *      Update the variable's name
260  */
261
262 void mprSetVarName(MprVar *vp, char *name)
263 {
264         mprAssert(vp);
265
266         mprFree(vp->name);
267         vp->name = mprStrdup(name);
268 }
269
270 /******************************************************************************/
271 /*
272  *      Append to the variable's full name
273  */
274
275 void mprSetVarFullName(MprVar *vp, char *name)
276 {
277 #if VAR_DEBUG
278         mprAssert(vp);
279
280         mprFree(vp->fullName);
281         vp->fullName = mprStrdup(name);
282         if (vp->type == MPR_TYPE_OBJECT) {
283                 if (strcmp(vp->properties->name, "this") == 0) {
284                         mprStrcpy(vp->properties->name, sizeof(vp->properties->name), name);
285                 }
286         }
287 #endif
288 }
289
290 /******************************************************************************/
291 /*
292  *      Make a var impervious to recursive forced deletes. 
293  */
294
295 void mprSetVarDeleteProtect(MprVar *vp, int deleteProtect)
296 {
297         mprAssert(vp);
298
299         if (vp->type == MPR_TYPE_OBJECT && vp->properties) {
300                 vp->properties->deleteProtect = deleteProtect;
301         }
302 }
303
304 /******************************************************************************/
305 /*
306  *      Make a variable readonly. Can still be deleted.
307  */
308
309 void mprSetVarReadonly(MprVar *vp, int readonly)
310 {
311         mprAssert(vp);
312
313         vp->readonly = readonly;
314 }
315
316 /******************************************************************************/
317
318 MprVarTrigger mprAddVarTrigger(MprVar *vp, MprVarTrigger fn)
319 {
320         MprVarTrigger oldTrigger;
321
322         mprAssert(vp);
323         mprAssert(fn);
324
325         oldTrigger = vp->trigger;
326         vp->trigger = fn;
327         return oldTrigger;
328 }
329
330 /******************************************************************************/
331
332 MprType mprGetVarType(MprVar *vp)
333 {
334         mprAssert(vp);
335
336         return vp->type;
337 }
338
339 /******************************************************************************/
340 /********************************** Properties ********************************/
341 /******************************************************************************/
342 /*
343  *      Create a property in an object with a defined value. If the property 
344  *      already exists in the object, then just write its value.
345  */
346
347 MprVar *mprCreateProperty(MprVar *obj, const char *propertyName, MprVar *newValue)
348 {
349         MprVar  *prop, *last;
350         int             bucketIndex;
351
352         mprAssert(obj);
353         mprAssert(propertyName && *propertyName);
354
355         if (obj->type != MPR_TYPE_OBJECT) {
356                 mprAssert(obj->type == MPR_TYPE_OBJECT);
357                 return 0;
358         }
359
360         /*
361          *      See if property already exists and locate the bucket to hold the
362          *      property reference.
363          */
364         last = 0;
365         bucketIndex = hash(obj->properties, propertyName);
366         prop = obj->properties->buckets[bucketIndex];
367
368         /*
369          *      Find the property in the hash chain if it exists
370          */
371         for (last = 0; prop; last = prop, prop = prop->forw) {
372                 if (prop->name[0] == propertyName[0] && 
373                                 strcmp(prop->name, propertyName) == 0) {
374                         break;
375                 }
376         }
377
378         if (prop) {
379                 //      FUTURE -- remove. Just for debug.
380                 mprAssert(prop == 0);
381                 mprLog(0, "Attempting to create property %s in object %s\n",
382                         propertyName, obj->name);
383                 return 0;
384         }
385
386         if (obj->trigger) {
387                 if ((obj->trigger)(MPR_VAR_CREATE_PROPERTY, obj->properties, prop, 
388                                 newValue, 0) == MPR_TRIGGER_ABORT) {
389                         return 0;
390                 }
391         }
392
393         /*
394          *      Create a new property
395          */
396         prop = allocProperty(propertyName);
397         if (prop == 0) {
398                 mprAssert(prop);
399                 return 0;
400         }
401
402         copyVarCore(prop, newValue, MPR_SHALLOW_COPY);
403
404         prop->bucketIndex = bucketIndex;
405         if (last) {
406                 last->forw = prop;
407         } else {
408                 obj->properties->buckets[bucketIndex] = prop;
409         }
410         prop->parentProperties = obj->properties;
411
412         /*
413          *      Update the item counts 
414          */
415         obj->properties->numItems++;
416         if (! mprVarIsFunction(prop->type)) {
417                 obj->properties->numDataItems++;
418         }
419
420         return prop;
421 }
422
423 /******************************************************************************/
424 /*
425  *      Create a property in an object with a defined value. If the property 
426  *      already exists in the object, then just write its value. Same as 
427  *      mprCreateProperty except that the new value is passed by value rather than
428  *      by pointer.
429  */
430
431 MprVar *mprCreatePropertyValue(MprVar *obj, const char *propertyName, MprVar newValue)
432 {
433         return mprCreateProperty(obj, propertyName, &newValue);
434 }
435
436 /******************************************************************************/
437 /*
438  *      Create a new property
439  */
440
441 static MprVar *allocProperty(const char *propertyName)
442 {
443         MprVar          *prop;
444
445         prop = (MprVar*) mprMalloc(sizeof(MprVar));
446         if (prop == 0) {
447                 mprAssert(prop);
448                 return 0;
449         }
450         memset(prop, 0, sizeof(MprVar));
451         prop->allocatedVar = 1;
452         prop->name = mprStrdup(propertyName);
453         prop->forw = (MprVar*) 0;
454
455         return prop;
456 }
457
458 /******************************************************************************/
459 /*
460  *      Update a property in an object with a defined value. Create the property
461  *      if it doesn not already exist.
462  */
463
464 MprVar *mprSetProperty(MprVar *obj, const char *propertyName, MprVar *newValue)
465 {
466         MprVar  *prop, triggerValue;
467         int             rc;
468
469         mprAssert(obj);
470         mprAssert(propertyName && *propertyName);
471         mprAssert(obj->type == MPR_TYPE_OBJECT);
472
473         if (obj->type != MPR_TYPE_OBJECT) {
474                 mprAssert(0);
475                 return 0;
476         }
477
478         prop = mprGetProperty(obj, propertyName, 0);
479         if (prop == 0) {
480                 return mprCreateProperty(obj, propertyName, newValue);
481         }
482
483         if (obj->trigger) {
484                 /* 
485                  *      Call the trigger before the update and pass it the new value.
486                  */
487                 triggerValue = *newValue;
488                 triggerValue.allocatedVar = 0;
489                 triggerValue.allocatedData = 0;
490                 rc = (obj->trigger)(MPR_VAR_WRITE, obj->properties, obj, 
491                                 &triggerValue, 0);
492                 if (rc == MPR_TRIGGER_ABORT) {
493                         return 0;
494
495                 } else if (rc == MPR_TRIGGER_USE_NEW_VALUE) {
496                         /*
497                          *      Trigger must copy to triggerValue a variable that is not
498                          *      a structure copy of the existing data.
499                          */
500                         copyVarCore(prop, &triggerValue, MPR_SHALLOW_COPY);
501                         mprDestroyVar(&triggerValue);
502                         return prop;
503                 }
504         }
505         copyVarCore(prop, newValue, MPR_SHALLOW_COPY);
506         return prop;
507 }
508
509 /******************************************************************************/
510 /*
511  *      Update a property in an object with a defined value. Create the property
512  *      if it does not already exist. Same as mprSetProperty except that the 
513  *      new value is passed by value rather than by pointer.
514  */
515
516 MprVar *mprSetPropertyValue(MprVar *obj, const char *propertyName, MprVar newValue)
517 {
518         return mprSetProperty(obj, propertyName, &newValue);
519 }
520
521 /******************************************************************************/
522 /*
523  *      Delete a property from this object
524  */
525
526 int mprDeleteProperty(MprVar *obj, const char *property)
527 {
528         MprVar          *prop, *last;
529         char            *cp;
530         int                     bucketIndex;
531
532         mprAssert(obj);
533         mprAssert(property && *property);
534         mprAssert(obj->type == MPR_TYPE_OBJECT);
535
536         if (obj->type != MPR_TYPE_OBJECT) {
537                 mprAssert(obj->type == MPR_TYPE_OBJECT);
538                 return 0;
539         }
540
541         last = 0;
542         bucketIndex = hash(obj->properties, property);
543         if ((prop = obj->properties->buckets[bucketIndex]) != 0) {
544                 for ( ; prop; prop = prop->forw) {
545                         cp = prop->name;
546                         if (cp[0] == property[0] && strcmp(cp, property) == 0) {
547                                 break;
548                         }
549                         last = prop;
550                 }
551         }
552         if (prop == (MprVar*) 0) {
553                 mprAssert(prop);
554                 return MPR_ERR_NOT_FOUND;
555         }
556         if (prop->readonly) {
557                 mprAssert(! prop->readonly);
558                 return MPR_ERR_READ_ONLY;
559         }
560
561         if (obj->trigger) {
562                 if ((obj->trigger)(MPR_VAR_DELETE_PROPERTY, obj->properties, prop, 0, 0)
563                                 == MPR_TRIGGER_ABORT) {
564                         return MPR_ERR_ABORTED;
565                 }
566         }
567
568         if (last) {
569                 last->forw = prop->forw;
570         } else {
571                 obj->properties->buckets[bucketIndex] = prop->forw;
572         }
573
574         obj->properties->numItems--;
575         if (! mprVarIsFunction(prop->type)) {
576                 obj->properties->numDataItems--;
577         }
578
579         mprDestroyVar(prop);
580
581         return 0;
582 }
583
584 /******************************************************************************/
585 /*
586  *      Find a property in an object and return a pointer to it. If a value arg
587  *      is supplied, then copy the data into the var. 
588  */
589
590 MprVar *mprGetProperty(MprVar *obj, const char *property, MprVar *value)
591 {
592         MprVar  *prop, triggerValue;
593         int             rc;
594
595         if (obj == 0 || obj->type != MPR_TYPE_OBJECT || property == 0 || 
596                         *property == '\0') {
597                 if (value) {
598                         value->type = MPR_TYPE_UNDEFINED;
599                 }
600                 return 0;
601         }
602
603         for (prop = getObjChain(obj->properties, property); prop; 
604                         prop = prop->forw) {
605                 if (prop->name[0] == property[0] && strcmp(prop->name, property) == 0) {
606                         break;
607                 }
608         }
609         if (prop == 0) {
610                 if (value) {
611                         value->type = MPR_TYPE_UNDEFINED;
612                 }
613                 return 0;
614         }
615         if (value) {
616                 if (prop->trigger) {
617                         triggerValue = *prop;
618                         triggerValue.allocatedVar = 0;
619                         triggerValue.allocatedData = 0;
620                         /*
621                          *      Pass the trigger the current read value and may receive
622                          *      a new value.
623                          */ 
624                         rc = (prop->trigger)(MPR_VAR_READ, prop->parentProperties, prop, 
625                                 &triggerValue, 0);
626                         if (rc == MPR_TRIGGER_ABORT) {
627                                 if (value) {
628                                         value->type = MPR_TYPE_UNDEFINED;
629                                 }
630                                 return 0;
631
632                         } else if (rc == MPR_TRIGGER_USE_NEW_VALUE) {
633                                 copyVarCore(prop, &triggerValue, MPR_SHALLOW_COPY);
634                                 mprDestroyVar(&triggerValue);
635                         }
636                 }
637                 /*
638                  *      Clone. No copy.
639                  */
640                 *value = *prop;
641         }
642         return prop;
643 }
644
645 /******************************************************************************/
646 /*
647  *      Read a properties value. This returns the property's value. It does not
648  *      copy object/string data but returns a pointer directly into the variable.
649  *      The caller does not and should not call mprDestroy on the returned value.
650  *      If value is null, just read the property and run triggers.
651  */
652
653 int mprReadProperty(MprVar *prop, MprVar *value)
654 {
655         MprVar  triggerValue;
656         int             rc;
657
658         mprAssert(prop);
659
660         if (prop->trigger) {
661                 triggerValue = *prop;
662                 triggerValue.allocatedVar = 0;
663                 triggerValue.allocatedData = 0;
664                 rc = (prop->trigger)(MPR_VAR_READ, prop->parentProperties, prop, 
665                         &triggerValue, 0);
666
667                 if (rc == MPR_TRIGGER_ABORT) {
668                         return MPR_ERR_ABORTED;
669
670                 } else if (rc == MPR_TRIGGER_USE_NEW_VALUE) {
671                         copyVarCore(prop, &triggerValue, MPR_SHALLOW_COPY);
672                         mprDestroyVar(&triggerValue);
673                         return 0;
674                 }
675         }
676         if (value) {
677                 *value = *prop;
678
679                 /*
680                  *      Just so that if the user calls mprDestroyVar on value, it will do no
681                  *      harm.
682                  */
683                 value->allocatedVar = 0;
684                 value->allocatedData = 0;
685         }
686         return 0;
687 }
688
689 /******************************************************************************/
690 /*
691  *      Read a properties value. This returns a copy of the property variable. 
692  *      However, if the property is an object or string, it returns a copy of the
693  *      reference to the underlying data. If copyDepth is set to MPR_DEEP_COPY,
694  *      then the underlying objects and strings data will be copied as well. If 
695  *      copyDepth is set to MPR_SHALLOW_COPY, then only strings will be copied. If
696  *      it is set to MPR_NO_COPY, then no data will be copied. In all cases, the 
697  *      user must call mprDestroyVar to free resources. This routine will run any 
698  *      registered triggers which may modify the value the user receives (without 
699  *      updating the properties real value).
700  *
701  *      WARNING: the args are reversed to most other APIs. This conforms to the
702  *      strcpy(dest, src) standard instead.
703  */
704
705 int mprCopyProperty(MprVar *dest, MprVar *prop, int copyDepth)
706 {
707         MprVar  triggerValue;
708         int             rc;
709
710         mprAssert(prop);
711         mprAssert(dest);
712
713         if (prop->trigger) {
714                 triggerValue = *prop;
715                 triggerValue.allocatedVar = 0;
716                 triggerValue.allocatedData = 0;
717                 rc = (prop->trigger)(MPR_VAR_READ, prop->parentProperties, prop, 
718                         &triggerValue, copyDepth);
719
720                 if (rc == MPR_TRIGGER_ABORT) {
721                         return MPR_ERR_ABORTED;
722
723                 } else if (rc == MPR_TRIGGER_USE_NEW_VALUE) {
724                         copyVarCore(dest, &triggerValue, MPR_SHALLOW_COPY);
725                         mprDestroyVar(&triggerValue);
726                         return 0;
727                 }
728         }
729         mprCopyVar(dest, prop, copyDepth);
730         return 0;
731 }
732
733 /******************************************************************************/
734 /*
735  *      Write a new value into an existing property in an object.
736  */
737
738 int mprWriteProperty(MprVar *vp, MprVar *value)
739 {
740         MprVar  triggerValue;
741         int             rc;
742
743         mprAssert(vp);
744         mprAssert(value);
745
746         if (vp->readonly) {
747                 return MPR_ERR_READ_ONLY;
748         }
749
750         if (vp->trigger) {
751                 triggerValue = *value;
752
753                 rc = (vp->trigger)(MPR_VAR_WRITE, vp->parentProperties, vp, 
754                         &triggerValue, 0);
755
756                 if (rc == MPR_TRIGGER_ABORT) {
757                         return MPR_ERR_ABORTED;
758
759                 } else if (rc == MPR_TRIGGER_USE_NEW_VALUE) {
760                         copyVarCore(vp, &triggerValue, MPR_SHALLOW_COPY);
761                         mprDestroyVar(&triggerValue);
762                         return 0;
763                 }
764                 /* Fall through */
765         }
766
767         copyVarCore(vp, value, MPR_SHALLOW_COPY);
768         return 0;
769 }
770
771 /******************************************************************************/
772 /*
773  *      Write a new value into an existing property in an object.
774  */
775
776 int mprWritePropertyValue(MprVar *vp, MprVar value)
777 {
778         mprAssert(vp);
779
780         return mprWriteProperty(vp, &value);
781 }
782
783 /******************************************************************************/
784 /*
785  *      Get the count of properties.
786  */
787
788 int mprGetPropertyCount(MprVar *vp, int includeFlags)
789 {
790         mprAssert(vp);
791
792         if (vp->type != MPR_TYPE_OBJECT) {
793                 return 0;
794         }
795         if (includeFlags == MPR_ENUM_DATA) {
796                 return vp->properties->numDataItems;
797         } else {
798                 return vp->properties->numItems;
799         }
800 }
801
802 /******************************************************************************/
803 /*
804  *      Get the first property in an object. Used for walking all properties in an
805  *      object.
806  */
807
808 MprVar *mprGetFirstProperty(MprVar *obj, int includeFlags)
809 {
810         MprVar          *prop;
811         int                     i;
812
813         mprAssert(obj);
814         mprAssert(obj->type == MPR_TYPE_OBJECT);
815
816         if (obj->type != MPR_TYPE_OBJECT) {
817                 mprAssert(obj->type == MPR_TYPE_OBJECT);
818                 return 0;
819         }
820
821         for (i = 0; i < (int) obj->properties->hashSize; i++) {
822                 for (prop = obj->properties->buckets[i]; prop; prop = prop->forw) {
823                         if (prop) {
824                                 if (mprVarIsFunction(prop->type)) {
825                                         if (!(includeFlags & MPR_ENUM_FUNCTIONS)) {
826                                                 continue;
827                                         }
828                                 } else {
829                                         if (!(includeFlags & MPR_ENUM_DATA)) {
830                                                 continue;
831                                         }
832                                 }
833                                 return prop;
834                         }
835                         break;
836                 }
837         }
838         return 0;
839 }
840
841 /******************************************************************************/
842 /*
843  *      Get the next property in sequence.
844  */
845
846 MprVar *mprGetNextProperty(MprVar *obj, MprVar *last, int includeFlags)
847 {
848         MprProperties   *properties;
849         int                             i;
850
851         mprAssert(obj);
852         mprAssert(obj->type == MPR_TYPE_OBJECT);
853
854         if (obj->type != MPR_TYPE_OBJECT) {
855                 mprAssert(obj->type == MPR_TYPE_OBJECT);
856                 return 0;
857         }
858         properties = obj->properties;
859
860         if (last->forw) {
861                 return last->forw;
862         }
863
864         for (i = last->bucketIndex + 1; i < (int) properties->hashSize; i++) {
865                 for (last = properties->buckets[i]; last; last = last->forw) {
866                         if (mprVarIsFunction(last->type)) {
867                                 if (!(includeFlags & MPR_ENUM_FUNCTIONS)) {
868                                         continue;
869                                 }
870                         } else {
871                                 if (!(includeFlags & MPR_ENUM_DATA)) {
872                                         continue;
873                                 }
874                         }
875                         return last;
876                 }
877         }
878         return 0;
879 }
880
881 /******************************************************************************/
882 /************************** Internal Support Routines *************************/
883 /******************************************************************************/
884 /*
885  *      Create an hash table to hold and index properties. Properties are just 
886  *      variables which may contain primitive data types, functions or other
887  *      objects. The hash table is the essence of an object. HashSize specifies 
888  *      the size of the hash table to use and should be a prime number.
889  */
890
891 static MprProperties *createProperties(const char *name, int hashSize)
892 {
893         MprProperties   *pp;
894
895         if (hashSize < 7) {
896                 hashSize = 7;
897         }
898         if ((pp = (MprProperties*) mprMalloc(sizeof(MprProperties))) == NULL) {
899                 mprAssert(0);
900                 return 0;
901         }
902         mprAssert(pp);
903         memset(pp, 0, sizeof(MprProperties));
904
905         pp->numItems = 0;
906         pp->numDataItems = 0;
907         pp->hashSize = hashSize;
908         pp->buckets = (MprVar**) mprMalloc(pp->hashSize * sizeof(MprVar*));
909         mprAssert(pp->buckets);
910         memset(pp->buckets, 0, pp->hashSize * sizeof(MprVar*));
911         pp->refCount = 1;
912
913 #if VAR_DEBUG
914         if (objectCount == -1) {
915                 objectCount = 0;
916                 objectList.next = objectList.prev = &objectList;
917         }
918
919         mprStrcpy(pp->name, sizeof(pp->name), name);
920         pp->next = &objectList;
921         pp->prev = objectList.prev;
922         objectList.prev->next = pp;
923         objectList.prev = pp;
924         objectCount++;
925 #endif
926         return pp;
927 }
928
929 /******************************************************************************/
930 /*
931  *      Release an object's properties hash table. If this is the last person 
932  *      using it, free it. Return TRUE if the object is released.
933  */
934
935 static bool releaseProperties(MprProperties *obj, int force)
936 {
937         MprProperties   *pp;
938         MprVar                  *prop, *forw;
939         int                             i;
940
941         mprAssert(obj);
942         mprAssert(obj->refCount > 0);
943
944 #if VAR_DEBUG
945         /*
946          *      Debug sanity check
947          */
948         mprAssert(obj->refCount < 20);
949 #endif
950
951         if (--obj->refCount > 0 && !force) {
952                 return 0;
953         }
954
955 #if VAR_DEBUG
956         mprAssert(obj->prev);
957         mprAssert(obj->next);
958         mprAssert(obj->next->prev);
959         mprAssert(obj->prev->next);
960         obj->next->prev = obj->prev;
961         obj->prev->next = obj->next;
962         objectCount--;
963 #endif
964
965         for (i = 0; i < (int) obj->hashSize; i++) {
966                 for (prop = obj->buckets[i]; prop; prop = forw) {
967                         forw = prop->forw;
968                         if (prop->type == MPR_TYPE_OBJECT) {
969
970                                 if (prop->properties == obj) {
971                                         /* Self reference */
972                                         continue;
973                                 }
974                                 pp = prop->properties;
975                                 if (pp->visited) {
976                                         continue;
977                                 }
978
979                                 pp->visited = 1;
980                                 if (! freeVar(prop, pp->deleteProtect ? 0 : force)) {
981                                         pp->visited = 0;
982                                 }
983
984                         } else {
985                                 freeVar(prop, force);
986                         }
987                 }
988         }
989
990         mprFree((void*) obj->buckets);
991         mprFree((void*) obj);
992
993         return 1;
994 }
995
996 /******************************************************************************/
997 /*
998  *      Adjust the reference count
999  */
1000
1001 static int adjustRefCount(MprProperties *pp, int adj)
1002 {
1003         mprAssert(pp);
1004
1005         /*
1006          *      Debug sanity check
1007          */
1008         mprAssert(pp->refCount < 20);
1009
1010         return pp->refCount += adj;
1011 }
1012
1013 /******************************************************************************/
1014 #if VAR_DEBUG
1015 /*
1016  *      Print objects held
1017  */
1018
1019 void mprPrintObjects(char *msg)
1020 {
1021         MprProperties   *pp, *np;
1022         MprVar                  *prop, *forw;
1023         char                    *buf;
1024         int                             i;
1025
1026         mprLog(7, "%s: Object Store. %d objects.\n", msg, objectCount);
1027         pp = objectList.next;
1028         while (pp != &objectList) {
1029                 mprLog(7, "%s: 0x%x, refCount %d, properties %d\n", 
1030                         pp->name, pp, pp->refCount, pp->numItems);
1031                 for (i = 0; i < (int) pp->hashSize; i++) {
1032                         for (prop = pp->buckets[i]; prop; prop = forw) {
1033                                 forw = prop->forw;
1034                                 if (prop->properties == pp) {
1035                                         /* Self reference */
1036                                         continue;
1037                                 }
1038                                 mprVarToString(&buf, MPR_MAX_STRING, 0, prop);
1039                                 if (prop->type == MPR_TYPE_OBJECT) {
1040                                         np = objectList.next;
1041                                         while (np != &objectList) {
1042                                                 if (prop->properties == np) {
1043                                                         break;
1044                                                 }
1045                                                 np = np->next;
1046                                         }
1047                                         if (prop->properties == np) {
1048                                                 mprLog(7, "    %s: OBJECT 0x%x, <%s>\n", 
1049                                                         prop->name, prop->properties, prop->fullName);
1050                                         } else {
1051                                                 mprLog(7, "    %s: OBJECT NOT FOUND, %s <%s>\n", 
1052                                                         prop->name, buf, prop->fullName);
1053                                         }
1054                                 } else {
1055                                         mprLog(7, "    %s: <%s> = %s\n", prop->name, 
1056                                                 prop->fullName, buf);
1057                                 }
1058                                 mprFree(buf);
1059                         }
1060                 }
1061                 pp = pp->next;
1062         }
1063 }
1064
1065 /******************************************************************************/
1066
1067 void mprPrintObjRefCount(MprVar *vp)
1068 {
1069         mprLog(7, "OBJECT 0x%x, refCount %d\n", vp->properties,
1070                 vp->properties->refCount);
1071 }
1072
1073 #endif
1074 /******************************************************************************/
1075 /*
1076  *      Get the bucket chain containing a property.
1077  */
1078
1079 static MprVar *getObjChain(MprProperties *obj, const char *property)
1080 {
1081         mprAssert(obj);
1082
1083         return obj->buckets[hash(obj, property)];
1084 }
1085
1086 /******************************************************************************/
1087 /*
1088  *      Fast hash. The history of this algorithm is part of lost computer science 
1089  *      folk lore.
1090  */
1091
1092 static int hash(MprProperties *pp, const char *property)
1093 {
1094         uint    sum;
1095
1096         mprAssert(pp);
1097         mprAssert(property);
1098
1099         sum = 0;
1100         while (*property) {
1101                 sum += (sum * 33) + *property++;
1102         }
1103
1104         return sum % pp->hashSize;
1105 }
1106
1107 /******************************************************************************/
1108 /*********************************** Constructors *****************************/
1109 /******************************************************************************/
1110 /*
1111  *      Initialize an undefined value.
1112  */
1113
1114 MprVar mprCreateUndefinedVar()
1115 {
1116         MprVar  v;
1117
1118         memset(&v, 0x0, sizeof(v));
1119         v.type = MPR_TYPE_UNDEFINED;
1120         return v;
1121 }
1122
1123 /******************************************************************************/
1124 /*
1125  *      Initialize an null value.
1126  */
1127
1128 MprVar mprCreateNullVar()
1129 {
1130         MprVar  v;
1131
1132         memset(&v, 0x0, sizeof(v));
1133         v.type = MPR_TYPE_NULL;
1134         return v;
1135 }
1136
1137 /******************************************************************************/
1138
1139 MprVar mprCreateBoolVar(bool value)
1140 {
1141         MprVar  v;
1142
1143         memset(&v, 0x0, sizeof(v));
1144         v.type = MPR_TYPE_BOOL;
1145         v.boolean = value;
1146         return v;
1147 }
1148
1149 /******************************************************************************/
1150 /*
1151  *      Initialize a C function.
1152  */
1153
1154 MprVar mprCreateCFunctionVar(MprCFunction fn, void *thisPtr, int flags)
1155 {
1156         MprVar  v;
1157
1158         memset(&v, 0x0, sizeof(v));
1159         v.type = MPR_TYPE_CFUNCTION;
1160         v.cFunction.fn = fn;
1161         v.cFunction.thisPtr = thisPtr;
1162         v.flags = flags;
1163
1164         return v;
1165 }
1166
1167 /******************************************************************************/
1168 /*
1169  *      Initialize a C function.
1170  */
1171
1172 MprVar mprCreateStringCFunctionVar(MprStringCFunction fn, void *thisPtr, int flags)
1173 {
1174         MprVar  v;
1175
1176         memset(&v, 0x0, sizeof(v));
1177         v.type = MPR_TYPE_STRING_CFUNCTION;
1178         v.cFunctionWithStrings.fn = fn;
1179         v.cFunctionWithStrings.thisPtr = thisPtr;
1180         v.flags = flags;
1181
1182         return v;
1183 }
1184
1185 /******************************************************************************/
1186 #if BLD_FEATURE_FLOATING_POINT
1187 /*
1188  *      Initialize a floating value.
1189  */
1190
1191 MprVar mprCreateFloatVar(double value)
1192 {
1193         MprVar  v;
1194
1195         memset(&v, 0x0, sizeof(v));
1196         v.type = MPR_TYPE_FLOAT;
1197         v.floating = value;
1198         return v;
1199 }
1200
1201 #endif
1202 /******************************************************************************/
1203 /*
1204  *      Initialize an integer value.
1205  */
1206
1207 MprVar mprCreateIntegerVar(int value)
1208 {
1209         MprVar  v;
1210
1211         memset(&v, 0x0, sizeof(v));
1212         v.type = MPR_TYPE_INT;
1213         v.integer = value;
1214         return v;
1215 }
1216
1217 /******************************************************************************/
1218 #if BLD_FEATURE_INT64
1219 /*
1220  *      Initialize a 64-bit integer value.
1221  */
1222
1223 MprVar mprCreateInteger64Var(int64 value)
1224 {
1225         MprVar  v;
1226
1227         memset(&v, 0x0, sizeof(v));
1228         v.type = MPR_TYPE_INT64;
1229         v.integer64 = value;
1230         return v;
1231 }
1232
1233 #endif /* BLD_FEATURE_INT64 */
1234 /******************************************************************************/
1235 /*
1236  *      Initialize an number variable. Type is defined by configure.
1237  */
1238
1239 MprVar mprCreateNumberVar(MprNum value)
1240 {
1241         MprVar  v;
1242
1243         memset(&v, 0x0, sizeof(v));
1244         v.type = BLD_FEATURE_NUM_TYPE_ID;
1245 #if   BLD_FEATURE_NUM_TYPE_ID == MPR_TYPE_INT64
1246         v.integer64 = value;
1247 #elif BLD_FEATURE_NUM_TYPE_ID == MPR_TYPE_FLOAT
1248         v.float = value;
1249 #else
1250         v.integer = value;
1251 #endif
1252         return v;
1253 }
1254
1255 /******************************************************************************/
1256 /*
1257  *      Initialize a (bare) JavaScript function. args and body can be null.
1258  */
1259
1260 MprVar mprCreateFunctionVar(char *args, char *body, int flags)
1261 {
1262         MprVar          v;
1263         char            *cp, *arg, *last;
1264         int                     aid;
1265
1266         memset(&v, 0x0, sizeof(v));
1267         v.type = MPR_TYPE_FUNCTION;
1268         v.flags = flags;
1269
1270         v.function.args = mprCreateArray();
1271
1272         if (args) {
1273                 args = mprStrdup(args);
1274                 arg = mprStrTok(args, ",", &last);
1275                 while (arg) {
1276                         while (isspace((int) *arg))
1277                                 arg++;
1278                         for (cp = &arg[strlen(arg) - 1]; cp > arg; cp--) {
1279                                 if (!isspace((int) *cp)) {
1280                                         break;
1281                                 }
1282                         }
1283                         cp[1] = '\0';
1284                                         
1285                         aid = mprAddToArray(v.function.args, mprStrdup(arg));
1286                         arg = mprStrTok(0, ",", &last);
1287                 }
1288                 mprFree(args);
1289         }
1290
1291         if (body) {
1292                 v.function.body = mprStrdup(body);
1293         }
1294         v.allocatedData = 1;
1295         return v;
1296 }
1297
1298 /******************************************************************************/
1299 /*
1300  *      Initialize an object variable. Return type == MPR_TYPE_UNDEFINED if the
1301  *      memory allocation for the properties table failed.
1302  */
1303
1304 MprVar mprCreateObjVar(const char *name, int hashSize)
1305 {
1306         MprVar  v;
1307
1308         mprAssert(name && *name);
1309
1310         memset(&v, 0x0, sizeof(MprVar));
1311         v.type = MPR_TYPE_OBJECT;
1312         if (hashSize <= 0) {
1313                 hashSize = MPR_DEFAULT_HASH_SIZE;
1314         }
1315         v.properties = createProperties(name, hashSize);
1316         if (v.properties == 0) {
1317                 /* Indicate failed memory allocation */
1318                 v.type = MPR_TYPE_UNDEFINED;
1319         }
1320         v.allocatedData = 1;
1321         v.name = mprStrdup(name);
1322         mprLog(7, "mprCreateObjVar %s, 0x%p\n", name, v.properties);
1323         return v;
1324 }
1325
1326 /******************************************************************************/
1327 /*
1328  *      Initialize a string value.
1329  */
1330
1331 MprVar mprCreateStringVar(const char *value, bool allocate)
1332 {
1333         MprVar  v;
1334
1335         memset(&v, 0x0, sizeof(v));
1336         v.type = MPR_TYPE_STRING;
1337         if (value == 0) {
1338                 v.string = "";
1339         } else if (allocate) {
1340                 v.string = mprStrdup(value);
1341                 v.allocatedData = 1;
1342         } else {
1343                 v.string = value;
1344         }
1345         return v;
1346 }
1347
1348 /******************************************************************************/
1349 /*
1350  *      Copy an objects core value (only). This preserves the destination object's 
1351  *      name. This implements copy by reference for objects and copy by value for 
1352  *      strings and other types. Caller must free dest prior to calling.
1353  */
1354
1355 static void copyVarCore(MprVar *dest, MprVar *src, int copyDepth)
1356 {
1357         MprVarTrigger   saveTrigger;
1358         MprVar                  *srcProp, *destProp, *last;
1359         char                    **srcArgs;
1360         int                             i;
1361
1362         mprAssert(dest);
1363         mprAssert(src);
1364
1365         if (dest == src) {
1366                 return;
1367         }
1368
1369         /*
1370          *      FUTURE: we should allow read-only triggers where the value is never
1371          *      stored in the object. Currently, triggers override the readonly
1372          *      status.
1373          */
1374
1375         if (dest->type != MPR_TYPE_UNDEFINED && dest->readonly && !dest->trigger) {
1376                 mprAssert(0);
1377                 return;
1378         }
1379
1380         if (dest->type != MPR_TYPE_UNDEFINED) {
1381                 saveTrigger = dest->trigger;
1382                 freeVarStorage(dest, 0);
1383         } else {
1384                 saveTrigger = 0;
1385         }
1386
1387         switch (src->type) {
1388         default:
1389         case MPR_TYPE_UNDEFINED:
1390         case MPR_TYPE_NULL:
1391                 break;
1392
1393         case MPR_TYPE_BOOL:
1394                 dest->boolean = src->boolean;
1395                 break;
1396
1397         case MPR_TYPE_STRING_CFUNCTION:
1398                 dest->cFunctionWithStrings = src->cFunctionWithStrings;
1399                 break;
1400
1401         case MPR_TYPE_CFUNCTION:
1402                 dest->cFunction = src->cFunction;
1403                 break;
1404
1405 #if BLD_FEATURE_FLOATING_POINT
1406         case MPR_TYPE_FLOAT:
1407                 dest->floating = src->floating;
1408                 break;
1409 #endif
1410
1411         case MPR_TYPE_INT:
1412                 dest->integer = src->integer;
1413                 break;
1414
1415 #if BLD_FEATURE_INT64
1416         case MPR_TYPE_INT64:
1417                 dest->integer64 = src->integer64;
1418                 break;
1419 #endif
1420
1421         case MPR_TYPE_OBJECT:
1422                 if (copyDepth == MPR_DEEP_COPY) {
1423
1424                         dest->properties = createProperties(src->name, 
1425                                 src->properties->hashSize);
1426                         dest->allocatedData = 1;
1427
1428                         for (i = 0; i < (int) src->properties->hashSize; i++) {
1429                                 last = 0;
1430                                 for (srcProp = src->properties->buckets[i]; srcProp; 
1431                                                 srcProp = srcProp->forw) {
1432                                         if (srcProp->visited) {
1433                                                 continue;
1434                                         }
1435                                         destProp = allocProperty(srcProp->name);
1436                                         if (destProp == 0) {
1437                                                 mprAssert(destProp);
1438                                                 return;
1439                                         }
1440
1441                                         destProp->bucketIndex = i;
1442                                         if (last) {
1443                                                 last->forw = destProp;
1444                                         } else {
1445                                                 dest->properties->buckets[i] = destProp;
1446                                         }
1447                                         destProp->parentProperties = dest->properties;
1448
1449                                         /*
1450                                          *      Recursively copy the object
1451                                          */
1452                                         srcProp->visited = 1;
1453                                         copyVarCore(destProp, srcProp, copyDepth);
1454                                         srcProp->visited = 0;
1455                                         last = srcProp;
1456                                 }
1457                         }
1458                         dest->properties->numItems = src->properties->numItems;
1459                         dest->properties->numDataItems = src->properties->numDataItems;
1460                         dest->allocatedData = 1;
1461
1462                 } else if (copyDepth == MPR_SHALLOW_COPY) {
1463                         dest->properties = src->properties;
1464                         adjustVarRefCount(src, 1);
1465                         dest->allocatedData = 1;
1466
1467                 } else {
1468                         dest->properties = src->properties;
1469                         dest->allocatedData = 0;
1470                 }
1471                 break;
1472
1473         case MPR_TYPE_FUNCTION:
1474                 if (copyDepth != MPR_NO_COPY) {
1475                         dest->function.args = mprCreateArray();
1476                         srcArgs = (char**) src->function.args->handles;
1477                         for (i = 0; i < src->function.args->max; i++) {
1478                                 if (srcArgs[i]) {
1479                                         mprAddToArray(dest->function.args, mprStrdup(srcArgs[i]));
1480                                 }
1481                         }
1482                         dest->function.body = mprStrdup(src->function.body);
1483                         dest->allocatedData = 1;
1484                 } else {
1485                         dest->function.args = src->function.args;
1486                         dest->function.body = src->function.body;
1487                         dest->allocatedData = 0;
1488                 }
1489                 break;
1490
1491         case MPR_TYPE_STRING:
1492                 if (src->string && copyDepth != MPR_NO_COPY) {
1493                         dest->string = mprStrdup(src->string);
1494                         dest->allocatedData = 1;
1495                 } else {
1496                         dest->string = src->string;
1497                         dest->allocatedData = 0;
1498                 }
1499                 break;
1500         }
1501
1502         dest->type = src->type;
1503         dest->flags = src->flags;
1504         dest->trigger = saveTrigger;
1505
1506         /*
1507          *      Just for safety
1508          */
1509         dest->spare = 0;
1510 }
1511
1512 /******************************************************************************/
1513 /*
1514  *      Copy an entire object including name.
1515  */
1516
1517 void mprCopyVar(MprVar *dest, MprVar *src, int copyDepth)
1518 {
1519         mprAssert(dest);
1520         mprAssert(src);
1521
1522         copyVarCore(dest, src, copyDepth);
1523
1524         mprFree(dest->name);
1525         dest->name = mprStrdup(src->name);
1526
1527 #if VAR_DEBUG
1528         if (src->type == MPR_TYPE_OBJECT) {
1529
1530                 mprFree(dest->fullName);
1531                 dest->fullName = mprStrdup(src->fullName);
1532
1533                 mprLog(7, "mprCopyVar: object \"%s\", FDQ \"%s\" 0x%x, refCount %d\n", 
1534                         dest->name, dest->fullName, dest->properties, 
1535                         dest->properties->refCount);
1536         }
1537 #endif
1538 }
1539
1540 /******************************************************************************/
1541 /*
1542  *      Copy an entire object including name.
1543  */
1544
1545 void mprCopyVarValue(MprVar *dest, MprVar src, int copyDepth)
1546 {
1547         mprAssert(dest);
1548
1549         mprCopyVar(dest, &src, copyDepth); 
1550 }
1551
1552 /******************************************************************************/
1553 /*
1554  *      Copy an object. This implements copy by reference for objects and copy by
1555  *      value for strings and other types. Caller must free dest prior to calling.
1556  */
1557
1558 MprVar *mprDupVar(MprVar *src, int copyDepth)
1559 {
1560         MprVar  *dest;
1561
1562         mprAssert(src);
1563
1564         dest = (MprVar*) mprMalloc(sizeof(MprVar));
1565         memset(dest, 0, sizeof(MprVar));
1566
1567         mprCopyVar(dest, src, copyDepth);
1568         return dest;
1569 }
1570
1571 /******************************************************************************/
1572 /*
1573  *      Convert a value to a text based representation of its value
1574  *      FUTURE -- conver this to use the format string in all cases. Allow
1575  *      arbitrary format strings.
1576  */
1577
1578 void mprVarToString(char** out, int size, char *fmt, MprVar *obj)
1579 {
1580         char    *src;
1581
1582         mprAssert(out);
1583
1584         *out = NULL;
1585
1586         if (obj->trigger) {
1587                 mprReadProperty(obj, 0);
1588         }
1589
1590         switch (obj->type) {
1591         case MPR_TYPE_UNDEFINED:
1592                 //      FUTURE -- spec says convert to "undefined"
1593                 *out = mprStrdup("");
1594                 break;
1595
1596         case MPR_TYPE_NULL:
1597                 *out = mprStrdup("null");
1598                 break;
1599
1600         case MPR_TYPE_BOOL:
1601                 if (obj->boolean) {
1602                         *out = mprStrdup("true");
1603                 } else {
1604                         *out = mprStrdup("false");
1605                 }
1606                 break;
1607
1608 #if BLD_FEATURE_FLOATING_POINT
1609         case MPR_TYPE_FLOAT:
1610                 if (fmt == NULL || *fmt == '\0') {
1611                         mprAllocSprintf(out, size, "%f", obj->floating);
1612                 } else {
1613                         mprAllocSprintf(out, size, fmt, obj->floating);
1614                 }
1615                 break;
1616 #endif
1617
1618         case MPR_TYPE_INT:
1619                 if (fmt == NULL || *fmt == '\0') {
1620                         mprAllocSprintf(out, size, "%d", obj->integer);
1621                 } else {
1622                         mprAllocSprintf(out, size, fmt, obj->integer);
1623                 }
1624                 break;
1625
1626 #if BLD_FEATURE_INT64
1627         case MPR_TYPE_INT64:
1628                 if (fmt == NULL || *fmt == '\0') {
1629 #if BLD_GOAHEAD_WEBSERVER
1630                         mprAllocSprintf(out, size, "%d", (int) obj->integer64);
1631 #else
1632                         mprAllocSprintf(out, size, "%Ld", obj->integer64);
1633 #endif
1634                 } else {
1635                         mprAllocSprintf(out, size, fmt, obj->integer64);
1636                 }
1637                 break;
1638 #endif
1639
1640         case MPR_TYPE_CFUNCTION:
1641                 mprAllocSprintf(out, size, "[C Function]");
1642                 break;
1643
1644         case MPR_TYPE_STRING_CFUNCTION:
1645                 mprAllocSprintf(out, size, "[C StringFunction]");
1646                 break;
1647
1648         case MPR_TYPE_FUNCTION:
1649                 mprAllocSprintf(out, size, "[JavaScript Function]");
1650                 break;
1651
1652         case MPR_TYPE_OBJECT:
1653                 //      FUTURE -- really want: [object class: name] 
1654                 mprAllocSprintf(out, size, "[object %s]", obj->name);
1655                 break;
1656
1657         case MPR_TYPE_STRING:
1658                 src = obj->string;
1659
1660                 mprAssert(src);
1661                 if (fmt && *fmt) {
1662                         mprAllocSprintf(out, size, fmt, src);
1663
1664                 } else if (src == NULL) {
1665                         *out = mprStrdup("null");
1666
1667                 } else {
1668                         *out = mprStrdup(src);
1669                 }
1670                 break;
1671
1672         default:
1673                 mprAssert(0);
1674         }
1675 }
1676
1677 /******************************************************************************/
1678 /*
1679  *      Parse a string based on formatting instructions and intelligently 
1680  *      create a variable.
1681  */
1682
1683 MprVar mprParseVar(char *buf, MprType preferredType)
1684 {
1685         MprType         type;
1686         char            *cp;
1687
1688         mprAssert(buf);
1689
1690         if (preferredType == MPR_TYPE_UNDEFINED) {
1691                 if (*buf == '-') {
1692                         type = MPR_NUM_VAR;
1693
1694                 } else if (!isdigit((int) *buf)) {
1695                         if (strcmp(buf, "true") == 0 || strcmp(buf, "false") == 0) {
1696                                 type = MPR_TYPE_BOOL;
1697                         } else {
1698                                 type = MPR_TYPE_STRING;
1699                         }
1700
1701                 } else if (isdigit((int) *buf)) {
1702                         type = MPR_NUM_VAR;
1703                         cp = buf;
1704                         if (*cp && tolower(cp[1]) == 'x') {
1705                                 cp = &cp[2];
1706                         }
1707                         for (cp = buf; *cp; cp++) {
1708                                 if (! isdigit((int) *cp)) {
1709                                         break;
1710                                 }
1711                         }
1712
1713                         if (*cp != '\0') {
1714 #if BLD_FEATURE_FLOATING_POINT
1715                                 if (*cp == '.' || tolower(*cp) == 'e') {
1716                                         type = MPR_TYPE_FLOAT;
1717                                 } else
1718 #endif
1719                                 {
1720                                         type = MPR_NUM_VAR;
1721                                 }
1722                         }
1723                 }
1724         } else {
1725                 type = preferredType;
1726         }
1727
1728         switch (type) {
1729         case MPR_TYPE_OBJECT:
1730         case MPR_TYPE_UNDEFINED:
1731         case MPR_TYPE_NULL:
1732         default:
1733                 break;
1734
1735         case MPR_TYPE_BOOL:
1736                 return mprCreateBoolVar(buf[0] == 't' ? 1 : 0);
1737
1738         case MPR_TYPE_INT:
1739                 return mprCreateIntegerVar(mprParseInteger(buf));
1740
1741 #if BLD_FEATURE_INT64
1742         case MPR_TYPE_INT64:
1743                 return mprCreateInteger64Var(mprParseInteger64(buf));
1744 #endif
1745
1746         case MPR_TYPE_STRING:
1747                 if (strcmp(buf, "null") == 0) {
1748                         return mprCreateNullVar();
1749                 } else if (strcmp(buf, "undefined") == 0) {
1750                         return mprCreateUndefinedVar();
1751                 } 
1752                         
1753                 return mprCreateStringVar(buf, 1);
1754
1755 #if BLD_FEATURE_FLOATING_POINT
1756         case MPR_TYPE_FLOAT:
1757                 return mprCreateFloatVar(atof(buf));
1758 #endif
1759
1760         }
1761         return mprCreateUndefinedVar();
1762 }
1763
1764 /******************************************************************************/
1765 /*
1766  *      Convert the variable to a boolean. Only for primitive types.
1767  */
1768
1769 bool mprVarToBool(MprVar *vp)
1770 {
1771         mprAssert(vp);
1772
1773         switch (vp->type) {
1774         case MPR_TYPE_UNDEFINED:
1775         case MPR_TYPE_NULL:
1776         case MPR_TYPE_STRING_CFUNCTION:
1777         case MPR_TYPE_CFUNCTION:
1778         case MPR_TYPE_FUNCTION:
1779         case MPR_TYPE_OBJECT:
1780                 return 0;
1781
1782         case MPR_TYPE_BOOL:
1783                 return vp->boolean;
1784
1785 #if BLD_FEATURE_FLOATING_POINT
1786         case MPR_TYPE_FLOAT:
1787                 return (vp->floating != 0 && !mprIsNan(vp->floating));
1788 #endif
1789
1790         case MPR_TYPE_INT:
1791                 return (vp->integer != 0);
1792
1793 #if BLD_FEATURE_INT64
1794         case MPR_TYPE_INT64:
1795                 return (vp->integer64 != 0);
1796 #endif
1797
1798         case MPR_TYPE_STRING:
1799                 mprAssert(vp->string);
1800                 return (vp->string[0] != '\0');
1801         }
1802
1803         /* Not reached */
1804         return 0;
1805 }
1806
1807 /******************************************************************************/
1808 #if BLD_FEATURE_FLOATING_POINT
1809 /*
1810  *      Convert the variable to a floating point number. Only for primitive types.
1811  */
1812
1813 double mprVarToFloat(MprVar *vp)
1814 {
1815         mprAssert(vp);
1816
1817         switch (vp->type) {
1818         case MPR_TYPE_UNDEFINED:
1819         case MPR_TYPE_NULL:
1820         case MPR_TYPE_STRING_CFUNCTION:
1821         case MPR_TYPE_CFUNCTION:
1822         case MPR_TYPE_FUNCTION:
1823         case MPR_TYPE_OBJECT:
1824                 return 0;
1825
1826         case MPR_TYPE_BOOL:
1827                 return (vp->boolean) ? 1.0 : 0.0;
1828
1829         case MPR_TYPE_FLOAT:
1830                 return vp->floating;
1831
1832         case MPR_TYPE_INT:
1833                 return (double) vp->integer;
1834
1835 #if BLD_FEATURE_INT64
1836         case MPR_TYPE_INT64:
1837                 return (double) vp->integer64;
1838 #endif
1839
1840         case MPR_TYPE_STRING:
1841                 mprAssert(vp->string);
1842                 return atof(vp->string);
1843         }
1844
1845         /* Not reached */
1846         return 0;
1847 }
1848
1849 #endif
1850 /******************************************************************************/
1851 /*
1852  *      Convert the variable to a number type. Only works for primitive types.
1853  */
1854
1855 MprNum mprVarToNumber(MprVar *vp)
1856 {
1857 #if BLD_FEATURE_NUM_TYPE_ID == MPR_TYPE_INT64
1858         return mprVarToInteger64(vp);
1859 #elif BLD_FEATURE_NUM_TYPE_ID == MPR_TYPE_FLOAT
1860         return mprVarToFloat(vp);
1861 #else 
1862         return mprVarToInteger(vp);
1863 #endif
1864 }
1865
1866 /******************************************************************************/
1867 /*
1868  *      Convert the variable to a number type. Only works for primitive types.
1869  */
1870
1871 MprNum mprParseNumber(char *s)
1872 {
1873 #if BLD_FEATURE_NUM_TYPE_ID == MPR_TYPE_INT64
1874         return mprParseInteger64(s);
1875 #elif BLD_FEATURE_NUM_TYPE_ID == MPR_TYPE_FLOAT
1876         return mprParseFloat(s);
1877 #else 
1878         return mprParseInteger(s);
1879 #endif
1880 }
1881
1882 /******************************************************************************/
1883 #if BLD_FEATURE_INT64
1884 /*
1885  *      Convert the variable to an Integer64 type. Only works for primitive types.
1886  */
1887
1888 int64 mprVarToInteger64(MprVar *vp)
1889 {
1890         mprAssert(vp);
1891
1892         switch (vp->type) {
1893         case MPR_TYPE_UNDEFINED:
1894         case MPR_TYPE_NULL:
1895         case MPR_TYPE_STRING_CFUNCTION:
1896         case MPR_TYPE_CFUNCTION:
1897         case MPR_TYPE_FUNCTION:
1898         case MPR_TYPE_OBJECT:
1899                 return 0;
1900
1901         case MPR_TYPE_BOOL:
1902                 return (vp->boolean) ? 1 : 0;
1903
1904 #if BLD_FEATURE_FLOATING_POINT
1905         case MPR_TYPE_FLOAT:
1906                 if (mprIsNan(vp->floating)) {
1907                         return 0;
1908                 }
1909                 return (int64) vp->floating;
1910 #endif
1911
1912         case MPR_TYPE_INT:
1913                 return vp->integer;
1914
1915         case MPR_TYPE_INT64:
1916                 return vp->integer64;
1917
1918         case MPR_TYPE_STRING:
1919                 return mprParseInteger64(vp->string);
1920         }
1921
1922         /* Not reached */
1923         return 0;
1924 }
1925
1926 /******************************************************************************/
1927 /*
1928  *      Convert the string buffer to an Integer64.
1929  */
1930
1931 int64 mprParseInteger64(char *str)
1932 {
1933         char    *cp;
1934         int64   num64;
1935         int             radix, c, negative;
1936
1937         mprAssert(str);
1938
1939         cp = str;
1940         num64 = 0;
1941         negative = 0;
1942
1943         if (*cp == '-') {
1944                 cp++;
1945                 negative = 1;
1946         }
1947
1948         /*
1949          *      Parse a number. Observe hex and octal prefixes (0x, 0)
1950          */
1951         if (*cp != '0') {
1952                 /* 
1953                  *      Normal numbers (Radix 10)
1954                  */
1955                 while (isdigit((int) *cp)) {
1956                         num64 = (*cp - '0') + (num64 * 10);
1957                         cp++;
1958                 }
1959         } else {
1960                 cp++;
1961                 if (tolower(*cp) == 'x') {
1962                         cp++;
1963                         radix = 16;
1964                         while (*cp) {
1965                                 c = tolower(*cp);
1966                                 if (isdigit(c)) {
1967                                         num64 = (c - '0') + (num64 * radix);
1968                                 } else if (c >= 'a' && c <= 'f') {
1969                                         num64 = (c - 'a') + (num64 * radix);
1970                                 } else {
1971                                         break;
1972                                 }
1973                                 cp++;
1974                         }
1975
1976                 } else{
1977                         radix = 8;
1978                         while (*cp) {
1979                                 c = tolower(*cp);
1980                                 if (isdigit(c) && c < '8') {
1981                                         num64 = (c - '0') + (num64 * radix);
1982                                 } else {
1983                                         break;
1984                                 }
1985                                 cp++;
1986                         }
1987                 }
1988         }
1989
1990         if (negative) {
1991                 return 0 - num64;
1992         }
1993         return num64;
1994 }
1995
1996 #endif /* BLD_FEATURE_INT64 */
1997 /******************************************************************************/
1998 /*
1999  *      Convert the variable to an Integer type. Only works for primitive types.
2000  */
2001
2002 int mprVarToInteger(MprVar *vp)
2003 {
2004         mprAssert(vp);
2005
2006         switch (vp->type) {
2007         case MPR_TYPE_UNDEFINED:
2008         case MPR_TYPE_NULL:
2009         case MPR_TYPE_STRING_CFUNCTION:
2010         case MPR_TYPE_CFUNCTION:
2011         case MPR_TYPE_FUNCTION:
2012         case MPR_TYPE_OBJECT:
2013                 return 0;
2014
2015         case MPR_TYPE_BOOL:
2016                 return (vp->boolean) ? 1 : 0;
2017
2018 #if BLD_FEATURE_FLOATING_POINT
2019         case MPR_TYPE_FLOAT:
2020                 if (mprIsNan(vp->floating)) {
2021                         return 0;
2022                 }
2023                 return (int) vp->floating;
2024 #endif
2025
2026         case MPR_TYPE_INT:
2027                 return vp->integer;
2028
2029 #if BLD_FEATURE_INT64
2030         case MPR_TYPE_INT64:
2031                 return (int) vp->integer64;
2032 #endif
2033
2034         case MPR_TYPE_STRING:
2035                 return mprParseInteger(vp->string);
2036         }
2037
2038         /* Not reached */
2039         return 0;
2040 }
2041
2042 /******************************************************************************/
2043 /*
2044  *      Convert the string buffer to an Integer.
2045  */
2046
2047 int mprParseInteger(char *str)
2048 {
2049         char    *cp;
2050         int             num;
2051         int             radix, c, negative;
2052
2053         mprAssert(str);
2054
2055         cp = str;
2056         num = 0;
2057         negative = 0;
2058
2059         if (*cp == '-') {
2060                 cp++;
2061                 negative = 1;
2062         }
2063
2064         /*
2065          *      Parse a number. Observe hex and octal prefixes (0x, 0)
2066          */
2067         if (*cp != '0') {
2068                 /* 
2069                  *      Normal numbers (Radix 10)
2070                  */
2071                 while (isdigit((int) *cp)) {
2072                         num = (*cp - '0') + (num * 10);
2073                         cp++;
2074                 }
2075         } else {
2076                 cp++;
2077                 if (tolower(*cp) == 'x') {
2078                         cp++;
2079                         radix = 16;
2080                         while (*cp) {
2081                                 c = tolower(*cp);
2082                                 if (isdigit(c)) {
2083                                         num = (c - '0') + (num * radix);
2084                                 } else if (c >= 'a' && c <= 'f') {
2085                                         num = (c - 'a') + (num * radix);
2086                                 } else {
2087                                         break;
2088                                 }
2089                                 cp++;
2090                         }
2091
2092                 } else{
2093                         radix = 8;
2094                         while (*cp) {
2095                                 c = tolower(*cp);
2096                                 if (isdigit(c) && c < '8') {
2097                                         num = (c - '0') + (num * radix);
2098                                 } else {
2099                                         break;
2100                                 }
2101                                 cp++;
2102                         }
2103                 }
2104         }
2105
2106         if (negative) {
2107                 return 0 - num;
2108         }
2109         return num;
2110 }
2111
2112 /******************************************************************************/
2113 #if BLD_FEATURE_FLOATING_POINT
2114 /*
2115  *      Convert the string buffer to an Floating.
2116  */
2117
2118 double mprParseFloat(char *str)
2119 {
2120         return atof(str);
2121 }
2122
2123 /******************************************************************************/
2124
2125 bool mprIsNan(double f)
2126 {
2127 #if WIN
2128         return _isnan(f);
2129 #elif VXWORKS
2130         //      FUTURE
2131         return (0);
2132 #else
2133         return (f == FP_NAN);
2134 #endif
2135 }
2136 /******************************************************************************/
2137
2138 bool mprIsInfinite(double f)
2139 {
2140 #if WIN
2141         return !_finite(f);
2142 #elif VXWORKS
2143         //      FUTURE
2144         return (0);
2145 #else
2146         return (f == FP_INFINITE);
2147 #endif
2148 }
2149
2150 #endif // BLD_FEATURE_FLOATING_POINT
2151 /******************************************************************************/
2152
2153 /*
2154  * Local variables:
2155  * tab-width: 4
2156  * c-basic-offset: 4
2157  * End:
2158  * vim:tw=78
2159  * vim600: sw=4 ts=4 fdm=marker
2160  * vim<600: sw=4 ts=4
2161  */