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