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