r18301: I discovered how to load the warnings from a build farm build into
[Samba/aatanasov.git] / source4 / lib / appweb / mpr / var.c
blob11ac7120651cd649081feb3724f99f1eb649e4c2
1 /*
2 * @file var.c
3 * @brief MPR Universal Variable Type
4 * @overview
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.
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.
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
23 * This program is distributed WITHOUT ANY WARRANTY; without even the
24 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
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
32 * @end
35 /******************************* Documentation ********************************/
38 * This module is NOT multithreaded.
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.
45 /********************************** Includes **********************************/
47 #include "var.h"
49 /*********************************** Locals ***********************************/
50 #if VAR_DEBUG
52 static MprProperties objectList; /* Dummy head of objects list */
53 static int objectCount = -1; /* Count of objects */
55 #endif
56 /***************************** Forward Declarations ***************************/
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);
70 /*********************************** Code *************************************/
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.
76 * Return TRUE if the underlying data is freed. Objects may not be freed if
77 * there are other users of the object.
80 bool mprDestroyAllVars(MprVar *vp)
82 mprAssert(vp);
84 if (vp->trigger) {
85 if ((vp->trigger)(MPR_VAR_DELETE, vp->parentProperties, vp, 0, 0)
86 == MPR_TRIGGER_ABORT) {
87 return 0;
92 * Free the actual value. If this var refers to an object, we will
93 * recurse through all the properties freeing all vars.
95 return freeVar(vp, 1);
98 /******************************************************************************/
100 * Destroy a variable. Release any referenced object (destroy if no other
101 * users are referencing).
103 * Return TRUE if the underlying data is freed. Objects may not be freed if
104 * there are other users of the object.
107 bool mprDestroyVar(MprVar *vp)
109 mprAssert(vp);
111 if (vp->trigger) {
112 if ((vp->trigger)(MPR_VAR_DELETE, vp->parentProperties, vp, 0, 0)
113 == MPR_TRIGGER_ABORT) {
114 return 0;
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.
123 return freeVar(vp, 0);
126 /******************************************************************************/
128 * Free the value in a variable for primitive types. Release objects.
130 * Return TRUE if the underlying data is freed. Objects may not be freed if
131 * there are other users of the object.
134 static bool freeVar(MprVar *vp, int force)
136 bool freed;
138 mprAssert(vp);
140 freed = freeVarStorage(vp, force);
142 mprFree(vp->name);
143 mprFree(vp->fullName);
145 if (vp->allocatedVar) {
146 mprFree(vp);
147 } else {
148 vp->name = 0;
149 vp->fullName = 0;
150 vp->type = MPR_TYPE_UNDEFINED;
152 return freed;
155 /******************************************************************************/
157 * Free the value in a variable for primitive types. Release objects.
159 * Return TRUE if the underlying data is freed. Objects may not be freed if
160 * there are other users of the object.
163 static bool freeVarStorage(MprVar *vp, int force)
165 MprArray *argList;
166 bool freed;
167 int i;
169 freed = 1;
170 mprAssert(vp);
172 switch (vp->type) {
173 default:
174 break;
176 case MPR_TYPE_STRING:
177 if (vp->allocatedData && vp->string != 0) {
178 mprFree(vp->string);
179 vp->string = 0;
180 vp->allocatedData = 0;
182 break;
184 case MPR_TYPE_PTR:
185 if (vp->allocatedData) {
186 vp->allocatedData = 0;
187 mprFree(vp->ptr);
189 break;
191 case MPR_TYPE_OBJECT:
192 #if VAR_DEBUG
194 * Recurse through all properties and release / delete. Release the
195 * properties hash table.
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);
204 #endif
205 if (vp->allocatedData) {
206 freed = releaseProperties(vp->properties, force);
208 vp->properties = 0;
209 break;
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]);
219 mprDestroyArray(argList);
220 vp->function.args = 0;
221 mprFree(vp->function.body);
222 vp->function.body = 0;
224 break;
227 vp->type = MPR_TYPE_UNDEFINED;
228 return freed;
231 /******************************************************************************/
233 * Adjust the object reference count and return the currrent count of
234 * users.
237 static int adjustVarRefCount(MprVar *vp, int adj)
239 mprAssert(vp);
241 if (vp->type != MPR_TYPE_OBJECT) {
242 mprAssert(vp->type == MPR_TYPE_OBJECT);
243 return 0;
245 return adjustRefCount(vp->properties, adj);
248 /******************************************************************************/
250 * Get the object reference count
253 int mprGetVarRefCount(MprVar *vp)
255 mprAssert(vp);
257 if (vp->type != MPR_TYPE_OBJECT) {
258 mprAssert(vp->type == MPR_TYPE_OBJECT);
259 return 0;
261 return adjustRefCount(vp->properties, 0);
264 /******************************************************************************/
266 * Update the variable's name
269 void mprSetVarName(MprVar *vp, char *name)
271 mprAssert(vp);
273 mprFree(vp->name);
274 vp->name = mprStrdup(name);
277 /******************************************************************************/
279 * Append to the variable's full name
282 void mprSetVarFullName(MprVar *vp, char *name)
284 #if VAR_DEBUG
285 mprAssert(vp);
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);
294 #endif
297 /******************************************************************************/
299 * Make a var impervious to recursive forced deletes.
302 void mprSetVarDeleteProtect(MprVar *vp, int deleteProtect)
304 mprAssert(vp);
306 if (vp->type == MPR_TYPE_OBJECT && vp->properties) {
307 vp->properties->deleteProtect = deleteProtect;
311 /******************************************************************************/
313 * Make a variable readonly. Can still be deleted.
316 void mprSetVarReadonly(MprVar *vp, int readonly)
318 mprAssert(vp);
320 vp->readonly = readonly;
323 /******************************************************************************/
325 MprVarTrigger mprAddVarTrigger(MprVar *vp, MprVarTrigger fn)
327 MprVarTrigger oldTrigger;
329 mprAssert(vp);
330 mprAssert(fn);
332 oldTrigger = vp->trigger;
333 vp->trigger = fn;
334 return oldTrigger;
337 /******************************************************************************/
339 MprType mprGetVarType(MprVar *vp)
341 mprAssert(vp);
343 return vp->type;
346 /******************************************************************************/
347 /********************************** Properties ********************************/
348 /******************************************************************************/
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.
354 MprVar *mprCreateProperty(MprVar *obj, const char *propertyName,
355 MprVar *newValue)
357 MprVar *prop, *last;
358 int bucketIndex;
360 mprAssert(obj);
361 mprAssert(propertyName && *propertyName);
363 if (obj->type != MPR_TYPE_OBJECT) {
364 mprAssert(obj->type == MPR_TYPE_OBJECT);
365 return 0;
369 * See if property already exists and locate the bucket to hold the
370 * property reference.
372 last = 0;
373 bucketIndex = hash(obj->properties, propertyName);
374 prop = obj->properties->buckets[bucketIndex];
377 * Find the property in the hash chain if it exists
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;
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;
394 if (obj->trigger) {
395 if ((obj->trigger)(MPR_VAR_CREATE_PROPERTY, obj->properties, prop,
396 newValue, 0) == MPR_TRIGGER_ABORT) {
397 return 0;
402 * Create a new property
404 prop = allocProperty(propertyName);
405 if (prop == 0) {
406 mprAssert(prop);
407 return 0;
410 copyVarCore(prop, newValue, MPR_SHALLOW_COPY);
412 prop->bucketIndex = bucketIndex;
413 if (last) {
414 last->forw = prop;
415 } else {
416 obj->properties->buckets[bucketIndex] = prop;
418 prop->parentProperties = obj->properties;
421 * Update the item counts
423 obj->properties->numItems++;
424 if (! mprVarIsFunction(prop->type)) {
425 obj->properties->numDataItems++;
428 return prop;
431 /******************************************************************************/
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.
439 MprVar *mprCreatePropertyValue(MprVar *obj, const char *propertyName,
440 MprVar newValue)
442 return mprCreateProperty(obj, propertyName, &newValue);
445 /******************************************************************************/
447 * Create a new property
450 static MprVar *allocProperty(const char *propertyName)
452 MprVar *prop;
454 prop = (MprVar*) mprMalloc(sizeof(MprVar));
455 if (prop == 0) {
456 mprAssert(prop);
457 return 0;
459 memset(prop, 0, sizeof(MprVar));
460 prop->allocatedVar = 1;
461 prop->name = mprStrdup(propertyName);
462 prop->forw = (MprVar*) 0;
464 return prop;
467 /******************************************************************************/
469 * Update a property in an object with a defined value. Create the property
470 * if it doesn not already exist.
473 MprVar *mprSetProperty(MprVar *obj, const char *propertyName, MprVar *newValue)
475 MprVar *prop, triggerValue;
476 int rc;
478 mprAssert(obj);
479 mprAssert(propertyName && *propertyName);
480 mprAssert(obj->type == MPR_TYPE_OBJECT);
482 if (obj->type != MPR_TYPE_OBJECT) {
483 mprAssert(0);
484 return 0;
487 prop = mprGetProperty(obj, propertyName, 0);
488 if (prop == 0) {
489 return mprCreateProperty(obj, propertyName, newValue);
492 if (obj->trigger) {
494 * Call the trigger before the update and pass it the new value.
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;
504 } else if (rc == MPR_TRIGGER_USE_NEW_VALUE) {
506 * Trigger must copy to triggerValue a variable that is not
507 * a structure copy of the existing data.
509 copyVarCore(prop, &triggerValue, MPR_SHALLOW_COPY);
510 mprDestroyVar(&triggerValue);
511 return prop;
514 copyVarCore(prop, newValue, MPR_SHALLOW_COPY);
515 return prop;
518 /******************************************************************************/
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.
525 MprVar *mprSetPropertyValue(MprVar *obj, const char *propertyName,
526 MprVar newValue)
528 return mprSetProperty(obj, propertyName, &newValue);
531 /******************************************************************************/
533 * Delete a property from this object
536 int mprDeleteProperty(MprVar *obj, const char *property)
538 MprVar *prop, *last;
539 char *cp;
540 int bucketIndex;
542 mprAssert(obj);
543 mprAssert(property && *property);
544 mprAssert(obj->type == MPR_TYPE_OBJECT);
546 if (obj->type != MPR_TYPE_OBJECT) {
547 mprAssert(obj->type == MPR_TYPE_OBJECT);
548 return 0;
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;
559 last = prop;
562 if (prop == (MprVar*) 0) {
563 mprAssert(prop);
564 return MPR_ERR_NOT_FOUND;
566 if (prop->readonly) {
567 mprAssert(! prop->readonly);
568 return MPR_ERR_READ_ONLY;
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;
578 if (last) {
579 last->forw = prop->forw;
580 } else {
581 obj->properties->buckets[bucketIndex] = prop->forw;
584 obj->properties->numItems--;
585 if (! mprVarIsFunction(prop->type)) {
586 obj->properties->numDataItems--;
589 mprDestroyVar(prop);
591 return 0;
594 /******************************************************************************/
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.
600 MprVar *mprGetProperty(MprVar *obj, const char *property, MprVar *value)
602 MprVar *prop, triggerValue;
603 int rc;
605 if (obj == 0 || obj->type != MPR_TYPE_OBJECT || property == 0 ||
606 *property == '\0') {
607 if (value) {
608 value->type = MPR_TYPE_UNDEFINED;
610 return 0;
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;
620 if (prop == 0) {
621 if (value) {
622 value->type = MPR_TYPE_UNDEFINED;
624 return 0;
626 if (value) {
627 if (prop->trigger) {
628 triggerValue = *prop;
629 triggerValue.allocatedVar = 0;
630 triggerValue.allocatedData = 0;
632 * Pass the trigger the current read value and may receive
633 * a new value.
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;
641 return 0;
643 } else if (rc == MPR_TRIGGER_USE_NEW_VALUE) {
644 copyVarCore(prop, &triggerValue, MPR_SHALLOW_COPY);
645 mprDestroyVar(&triggerValue);
649 * Clone. No copy.
651 *value = *prop;
653 return prop;
656 /******************************************************************************/
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.
664 int mprReadProperty(MprVar *prop, MprVar *value)
666 MprVar triggerValue;
667 int rc;
669 mprAssert(prop);
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);
678 if (rc == MPR_TRIGGER_ABORT) {
679 return MPR_ERR_ABORTED;
681 } else if (rc == MPR_TRIGGER_USE_NEW_VALUE) {
682 copyVarCore(prop, &triggerValue, MPR_SHALLOW_COPY);
683 mprDestroyVar(&triggerValue);
684 return 0;
687 if (value) {
688 *value = *prop;
691 * Just so that if the user calls mprDestroyVar on value, it will do no
692 * harm.
694 value->allocatedVar = 0;
695 value->allocatedData = 0;
697 return 0;
700 /******************************************************************************/
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).
712 * WARNING: the args are reversed to most other APIs. This conforms to the
713 * strcpy(dest, src) standard instead.
716 int mprCopyProperty(MprVar *dest, MprVar *prop, int copyDepth)
718 MprVar triggerValue;
719 int rc;
721 mprAssert(prop);
722 mprAssert(dest);
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);
731 if (rc == MPR_TRIGGER_ABORT) {
732 return MPR_ERR_ABORTED;
734 } else if (rc == MPR_TRIGGER_USE_NEW_VALUE) {
735 copyVarCore(dest, &triggerValue, MPR_SHALLOW_COPY);
736 mprDestroyVar(&triggerValue);
737 return 0;
740 mprCopyVar(dest, prop, copyDepth);
741 return 0;
744 /******************************************************************************/
746 * Write a new value into an existing property in an object.
749 int mprWriteProperty(MprVar *vp, MprVar *value)
751 MprVar triggerValue;
752 int rc;
754 mprAssert(vp);
755 mprAssert(value);
757 if (vp->readonly) {
758 return MPR_ERR_READ_ONLY;
761 if (vp->trigger) {
762 triggerValue = *value;
764 rc = (vp->trigger)(MPR_VAR_WRITE, vp->parentProperties, vp,
765 &triggerValue, 0);
767 if (rc == MPR_TRIGGER_ABORT) {
768 return MPR_ERR_ABORTED;
770 } else if (rc == MPR_TRIGGER_USE_NEW_VALUE) {
771 copyVarCore(vp, &triggerValue, MPR_SHALLOW_COPY);
772 mprDestroyVar(&triggerValue);
773 return 0;
775 /* Fall through */
778 copyVarCore(vp, value, MPR_SHALLOW_COPY);
779 return 0;
782 /******************************************************************************/
784 * Write a new value into an existing property in an object.
787 int mprWritePropertyValue(MprVar *vp, MprVar value)
789 mprAssert(vp);
791 return mprWriteProperty(vp, &value);
794 /******************************************************************************/
796 * Get the count of properties.
799 int mprGetPropertyCount(MprVar *vp, int includeFlags)
801 mprAssert(vp);
803 if (vp->type != MPR_TYPE_OBJECT) {
804 return 0;
806 if (includeFlags == MPR_ENUM_DATA) {
807 return vp->properties->numDataItems;
808 } else {
809 return vp->properties->numItems;
813 /******************************************************************************/
815 * Get the first property in an object. Used for walking all properties in an
816 * object.
819 MprVar *mprGetFirstProperty(MprVar *obj, int includeFlags)
821 MprVar *prop;
822 int i;
824 mprAssert(obj);
825 mprAssert(obj->type == MPR_TYPE_OBJECT);
827 if (obj->type != MPR_TYPE_OBJECT) {
828 mprAssert(obj->type == MPR_TYPE_OBJECT);
829 return 0;
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;
839 } else {
840 if (!(includeFlags & MPR_ENUM_DATA)) {
841 continue;
844 return prop;
846 break;
849 return 0;
852 /******************************************************************************/
854 * Get the next property in sequence.
857 MprVar *mprGetNextProperty(MprVar *obj, MprVar *last, int includeFlags)
859 MprProperties *properties;
860 int i;
862 mprAssert(obj);
863 mprAssert(obj->type == MPR_TYPE_OBJECT);
865 if (obj->type != MPR_TYPE_OBJECT) {
866 mprAssert(obj->type == MPR_TYPE_OBJECT);
867 return 0;
869 properties = obj->properties;
871 if (last->forw) {
872 return last->forw;
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;
881 } else {
882 if (!(includeFlags & MPR_ENUM_DATA)) {
883 continue;
886 return last;
889 return 0;
892 /******************************************************************************/
893 /************************** Internal Support Routines *************************/
894 /******************************************************************************/
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.
902 static MprProperties *createProperties(const char *name, int hashSize)
904 MprProperties *pp;
906 if (hashSize < 7) {
907 hashSize = 7;
909 if ((pp = (MprProperties*) mprMalloc(sizeof(MprProperties))) == NULL) {
910 mprAssert(0);
911 return 0;
913 mprAssert(pp);
914 memset(pp, 0, sizeof(MprProperties));
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;
924 #if VAR_DEBUG
925 if (objectCount == -1) {
926 objectCount = 0;
927 objectList.next = objectList.prev = &objectList;
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;
940 /******************************************************************************/
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.
946 static bool releaseProperties(MprProperties *obj, int force)
948 MprProperties *pp;
949 MprVar *prop, *forw;
950 int i;
952 mprAssert(obj);
953 mprAssert(obj->refCount > 0);
955 #if VAR_DEBUG
957 * Debug sanity check
959 mprAssert(obj->refCount < 20);
960 #endif
962 if (--obj->refCount > 0 && !force) {
963 return 0;
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
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) {
981 if (prop->properties == obj) {
982 /* Self reference */
983 continue;
985 pp = prop->properties;
986 if (pp->visited) {
987 continue;
990 pp->visited = 1;
991 if (! freeVar(prop, pp->deleteProtect ? 0 : force)) {
992 pp->visited = 0;
995 } else {
996 freeVar(prop, force);
1001 mprFree((void*) obj->buckets);
1002 mprFree((void*) obj);
1004 return 1;
1007 /******************************************************************************/
1009 * Adjust the reference count
1012 static int adjustRefCount(MprProperties *pp, int adj)
1014 mprAssert(pp);
1017 * Debug sanity check
1019 mprAssert(pp->refCount < 20);
1021 return pp->refCount += adj;
1024 /******************************************************************************/
1025 #if VAR_DEBUG
1027 * Print objects held
1030 void mprPrintObjects(char *msg)
1032 MprProperties *pp, *np;
1033 MprVar *prop, *forw;
1034 char *buf;
1035 int i;
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;
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;
1056 np = np->next;
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);
1065 } else {
1066 mprLog(7, " %s: <%s> = %s\n", prop->name,
1067 prop->fullName, buf);
1069 mprFree(buf);
1072 pp = pp->next;
1076 /******************************************************************************/
1078 void mprPrintObjRefCount(MprVar *vp)
1080 mprLog(7, "OBJECT 0x%x, refCount %d\n", vp->properties,
1081 vp->properties->refCount);
1084 #endif
1085 /******************************************************************************/
1087 * Get the bucket chain containing a property.
1090 static MprVar *getObjChain(MprProperties *obj, const char *property)
1092 mprAssert(obj);
1094 return obj->buckets[hash(obj, property)];
1097 /******************************************************************************/
1099 * Fast hash. The history of this algorithm is part of lost computer science
1100 * folk lore.
1103 static int hash(MprProperties *pp, const char *property)
1105 uint sum;
1107 mprAssert(pp);
1108 mprAssert(property);
1110 sum = 0;
1111 while (*property) {
1112 sum += (sum * 33) + *property++;
1115 return sum % pp->hashSize;
1118 /******************************************************************************/
1119 /*********************************** Constructors *****************************/
1120 /******************************************************************************/
1122 * Initialize an undefined value.
1125 MprVar mprCreateUndefinedVar()
1127 MprVar v;
1129 memset(&v, 0x0, sizeof(v));
1130 v.type = MPR_TYPE_UNDEFINED;
1131 return v;
1134 /******************************************************************************/
1136 * Initialize an null value.
1139 MprVar mprCreateNullVar()
1141 MprVar v;
1143 memset(&v, 0x0, sizeof(v));
1144 v.type = MPR_TYPE_NULL;
1145 return v;
1148 /******************************************************************************/
1150 MprVar mprCreateBoolVar(bool value)
1152 MprVar v;
1154 memset(&v, 0x0, sizeof(v));
1155 v.type = MPR_TYPE_BOOL;
1156 v.boolean = value;
1157 return v;
1160 /******************************************************************************/
1162 * Initialize a C function.
1165 MprVar mprCreateCFunctionVar(MprCFunction fn, void *thisPtr, int flags)
1167 MprVar v;
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;
1175 return v;
1178 /******************************************************************************/
1180 * Initialize a C function.
1183 MprVar mprCreateStringCFunctionVar(MprStringCFunction fn, void *thisPtr,
1184 int flags)
1186 MprVar v;
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;
1194 return v;
1197 /******************************************************************************/
1199 * Initialize an opaque pointer.
1202 MprVar mprCreatePtrVar(void *ptr)
1204 MprVar v;
1206 memset(&v, 0x0, sizeof(v));
1207 v.type = MPR_TYPE_PTR;
1208 v.ptr = ptr;
1210 return v;
1213 /******************************************************************************/
1214 #if BLD_FEATURE_FLOATING_POINT
1216 * Initialize a floating value.
1219 MprVar mprCreateFloatVar(double value)
1221 MprVar v;
1223 memset(&v, 0x0, sizeof(v));
1224 v.type = MPR_TYPE_FLOAT;
1225 v.floating = value;
1226 return v;
1229 #endif
1230 /******************************************************************************/
1232 * Initialize an integer value.
1235 MprVar mprCreateIntegerVar(int value)
1237 MprVar v;
1239 memset(&v, 0x0, sizeof(v));
1240 v.type = MPR_TYPE_INT;
1241 v.integer = value;
1242 return v;
1245 /******************************************************************************/
1246 #if BLD_FEATURE_INT64
1248 * Initialize a 64-bit integer value.
1251 MprVar mprCreateInteger64Var(int64 value)
1253 MprVar v;
1255 memset(&v, 0x0, sizeof(v));
1256 v.type = MPR_TYPE_INT64;
1257 v.integer64 = value;
1258 return v;
1261 #endif /* BLD_FEATURE_INT64 */
1262 /******************************************************************************/
1264 * Initialize an number variable. Type is defined by configure.
1267 MprVar mprCreateNumberVar(MprNum value)
1269 MprVar v;
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;
1283 /******************************************************************************/
1285 * Initialize a (bare) JavaScript function. args and body can be null.
1288 MprVar mprCreateFunctionVar(char *args, char *body, int flags)
1290 MprVar v;
1291 char *cp, *arg, *last;
1292 int aid;
1294 memset(&v, 0x0, sizeof(v));
1295 v.type = MPR_TYPE_FUNCTION;
1296 v.flags = flags;
1298 v.function.args = mprCreateArray();
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;
1311 cp[1] = '\0';
1313 aid = mprAddToArray(v.function.args, mprStrdup(arg));
1314 arg = mprStrTok(0, ",", &last);
1316 mprFree(args);
1319 if (body) {
1320 v.function.body = mprStrdup(body);
1322 v.allocatedData = 1;
1323 return v;
1326 /******************************************************************************/
1328 * Initialize an object variable. Return type == MPR_TYPE_UNDEFINED if the
1329 * memory allocation for the properties table failed.
1332 MprVar mprCreateObjVar(const char *name, int hashSize)
1334 MprVar v;
1336 mprAssert(name && *name);
1338 memset(&v, 0x0, sizeof(MprVar));
1339 v.type = MPR_TYPE_OBJECT;
1340 if (hashSize <= 0) {
1341 hashSize = MPR_DEFAULT_HASH_SIZE;
1343 v.properties = createProperties(name, hashSize);
1344 if (v.properties == 0) {
1345 /* Indicate failed memory allocation */
1346 v.type = MPR_TYPE_UNDEFINED;
1348 v.allocatedData = 1;
1349 v.name = mprStrdup(name);
1350 mprLog(7, "mprCreateObjVar %s, 0x%p\n", name, v.properties);
1351 return v;
1354 /******************************************************************************/
1356 * Initialize a string value.
1359 MprVar mprCreateStringVar(const char *value, bool allocate)
1361 MprVar v;
1363 memset(&v, 0x0, sizeof(v));
1364 v.type = MPR_TYPE_STRING;
1365 if (value == 0) {
1366 v.string = "";
1367 } else if (allocate) {
1368 v.string = mprStrdup(value);
1369 v.allocatedData = 1;
1370 } else {
1371 v.string = (char*) value;
1373 return v;
1376 /******************************************************************************/
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.
1383 static void copyVarCore(MprVar *dest, MprVar *src, int copyDepth)
1385 MprVarTrigger saveTrigger;
1386 MprVar *srcProp, *destProp, *last;
1387 char **srcArgs;
1388 int i;
1390 mprAssert(dest);
1391 mprAssert(src);
1393 if (dest == src) {
1394 return;
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.
1403 if (dest->type != MPR_TYPE_UNDEFINED && dest->readonly && !dest->trigger) {
1404 mprAssert(0);
1405 return;
1408 if (dest->type != MPR_TYPE_UNDEFINED) {
1409 saveTrigger = dest->trigger;
1410 freeVarStorage(dest, 0);
1411 } else {
1412 saveTrigger = 0;
1415 switch (src->type) {
1416 default:
1417 case MPR_TYPE_UNDEFINED:
1418 case MPR_TYPE_NULL:
1419 break;
1421 case MPR_TYPE_BOOL:
1422 dest->boolean = src->boolean;
1423 break;
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;
1434 break;
1436 case MPR_TYPE_STRING_CFUNCTION:
1437 dest->cFunctionWithStrings = src->cFunctionWithStrings;
1438 break;
1440 case MPR_TYPE_CFUNCTION:
1441 dest->cFunction = src->cFunction;
1442 break;
1444 #if BLD_FEATURE_FLOATING_POINT
1445 case MPR_TYPE_FLOAT:
1446 dest->floating = src->floating;
1447 break;
1448 #endif
1450 case MPR_TYPE_INT:
1451 dest->integer = src->integer;
1452 break;
1454 #if BLD_FEATURE_INT64
1455 case MPR_TYPE_INT64:
1456 dest->integer64 = src->integer64;
1457 break;
1458 #endif
1460 case MPR_TYPE_OBJECT:
1461 if (copyDepth == MPR_DEEP_COPY) {
1463 dest->properties = createProperties(src->name,
1464 src->properties->hashSize);
1465 dest->allocatedData = 1;
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;
1474 destProp = allocProperty(srcProp->name);
1475 if (destProp == 0) {
1476 mprAssert(destProp);
1477 return;
1480 destProp->bucketIndex = i;
1481 if (last) {
1482 last->forw = destProp;
1483 } else {
1484 dest->properties->buckets[i] = destProp;
1486 destProp->parentProperties = dest->properties;
1489 * Recursively copy the object
1491 srcProp->visited = 1;
1492 copyVarCore(destProp, srcProp, copyDepth);
1493 srcProp->visited = 0;
1494 last = destProp;
1497 dest->properties->numItems = src->properties->numItems;
1498 dest->properties->numDataItems = src->properties->numDataItems;
1499 dest->allocatedData = 1;
1501 } else if (copyDepth == MPR_SHALLOW_COPY) {
1502 dest->properties = src->properties;
1503 adjustVarRefCount(src, 1);
1504 dest->allocatedData = 1;
1506 } else {
1507 dest->properties = src->properties;
1508 dest->allocatedData = 0;
1510 break;
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]));
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;
1528 break;
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;
1538 break;
1541 dest->type = src->type;
1542 dest->flags = src->flags;
1543 dest->trigger = saveTrigger;
1546 * Just for safety
1548 dest->spare = 0;
1551 /******************************************************************************/
1553 * Copy an entire object including name.
1556 void mprCopyVar(MprVar *dest, MprVar *src, int copyDepth)
1558 mprAssert(dest);
1559 mprAssert(src);
1561 copyVarCore(dest, src, copyDepth);
1563 mprFree(dest->name);
1564 dest->name = mprStrdup(src->name);
1566 #if VAR_DEBUG
1567 if (src->type == MPR_TYPE_OBJECT) {
1569 mprFree(dest->fullName);
1570 dest->fullName = mprStrdup(src->fullName);
1572 mprLog(7, "mprCopyVar: object \"%s\", FDQ \"%s\" 0x%x, refCount %d\n",
1573 dest->name, dest->fullName, dest->properties,
1574 dest->properties->refCount);
1576 #endif
1579 /******************************************************************************/
1581 * Copy an entire object including name.
1584 void mprCopyVarValue(MprVar *dest, MprVar src, int copyDepth)
1586 mprAssert(dest);
1588 mprCopyVar(dest, &src, copyDepth);
1591 /******************************************************************************/
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.
1597 MprVar *mprDupVar(MprVar *src, int copyDepth)
1599 MprVar *dest;
1601 mprAssert(src);
1603 dest = (MprVar*) mprMalloc(sizeof(MprVar));
1604 memset(dest, 0, sizeof(MprVar));
1606 mprCopyVar(dest, src, copyDepth);
1607 return dest;
1610 /******************************************************************************/
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.
1617 void mprVarToString(char** out, int size, char *fmt, MprVar *obj)
1619 char *src;
1621 mprAssert(out);
1623 *out = NULL;
1625 if (obj->trigger) {
1626 mprReadProperty(obj, 0);
1629 switch (obj->type) {
1630 case MPR_TYPE_UNDEFINED:
1631 /* FUTURE -- spec says convert to "undefined" */
1632 *out = mprStrdup("");
1633 break;
1635 case MPR_TYPE_NULL:
1636 *out = mprStrdup("null");
1637 break;
1639 case MPR_TYPE_PTR:
1640 mprAllocSprintf(out, size, "[Opaque Pointer %p]", obj->ptr);
1641 break;
1643 case MPR_TYPE_BOOL:
1644 if (obj->boolean) {
1645 *out = mprStrdup("true");
1646 } else {
1647 *out = mprStrdup("false");
1649 break;
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);
1658 break;
1659 #endif
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);
1667 break;
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);
1680 break;
1681 #endif
1683 case MPR_TYPE_CFUNCTION:
1684 mprAllocSprintf(out, size, "[C Function]");
1685 break;
1687 case MPR_TYPE_STRING_CFUNCTION:
1688 mprAllocSprintf(out, size, "[C StringFunction]");
1689 break;
1691 case MPR_TYPE_FUNCTION:
1692 mprAllocSprintf(out, size, "[JavaScript Function]");
1693 break;
1695 case MPR_TYPE_OBJECT:
1696 /* FUTURE -- really want: [object class: name] */
1697 mprAllocSprintf(out, size, "[object %s]", obj->name);
1698 break;
1700 case MPR_TYPE_STRING:
1701 src = obj->string;
1703 mprAssert(src);
1704 if (fmt && *fmt) {
1705 mprAllocSprintf(out, size, fmt, src);
1707 } else if (src == NULL) {
1708 *out = mprStrdup("null");
1710 } else {
1711 *out = mprStrdup(src);
1713 break;
1715 default:
1716 mprAssert(0);
1720 /******************************************************************************/
1722 * Parse a string based on formatting instructions and intelligently
1723 * create a variable.
1726 MprVar mprParseVar(char *buf, MprType preferredType)
1728 MprType type;
1729 char *cp;
1731 mprAssert(buf);
1733 type = preferredType;
1735 if (preferredType == MPR_TYPE_UNDEFINED) {
1736 if (*buf == '-') {
1737 type = MPR_NUM_VAR;
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;
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];
1752 for (cp = buf; *cp; cp++) {
1753 if (! isdigit((int) *cp)) {
1754 break;
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
1765 type = MPR_NUM_VAR;
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;
1779 case MPR_TYPE_BOOL:
1780 return mprCreateBoolVar(buf[0] == 't' ? 1 : 0);
1782 case MPR_TYPE_INT:
1783 return mprCreateIntegerVar(mprParseInteger(buf));
1785 #if BLD_FEATURE_INT64
1786 case MPR_TYPE_INT64:
1787 return mprCreateInteger64Var(mprParseInteger64(buf));
1788 #endif
1790 case MPR_TYPE_STRING:
1791 if (strcmp(buf, "null") == 0) {
1792 return mprCreateNullVar();
1793 } else if (strcmp(buf, "undefined") == 0) {
1794 return mprCreateUndefinedVar();
1797 return mprCreateStringVar(buf, 1);
1799 #if BLD_FEATURE_FLOATING_POINT
1800 case MPR_TYPE_FLOAT:
1801 return mprCreateFloatVar(atof(buf));
1802 #endif
1805 return mprCreateUndefinedVar();
1808 /******************************************************************************/
1810 * Convert the variable to a boolean. Only for primitive types.
1813 bool mprVarToBool(const MprVar *vp)
1815 mprAssert(vp);
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;
1826 case MPR_TYPE_PTR:
1827 return (vp->ptr != NULL);
1829 case MPR_TYPE_BOOL:
1830 return vp->boolean;
1832 #if BLD_FEATURE_FLOATING_POINT
1833 case MPR_TYPE_FLOAT:
1834 return (vp->floating != 0 && !mprIsNan(vp->floating));
1835 #endif
1837 case MPR_TYPE_INT:
1838 return (vp->integer != 0);
1840 #if BLD_FEATURE_INT64
1841 case MPR_TYPE_INT64:
1842 return (vp->integer64 != 0);
1843 #endif
1845 case MPR_TYPE_STRING:
1846 mprAssert(vp->string);
1847 return (vp->string[0] != '\0');
1850 /* Not reached */
1851 return 0;
1854 /******************************************************************************/
1855 #if BLD_FEATURE_FLOATING_POINT
1857 * Convert the variable to a floating point number. Only for primitive types.
1860 double mprVarToFloat(const MprVar *vp)
1862 mprAssert(vp);
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;
1874 case MPR_TYPE_BOOL:
1875 return (vp->boolean) ? 1.0 : 0.0;
1877 case MPR_TYPE_FLOAT:
1878 return vp->floating;
1880 case MPR_TYPE_INT:
1881 return (double) vp->integer;
1883 #if BLD_FEATURE_INT64
1884 case MPR_TYPE_INT64:
1885 return (double) vp->integer64;
1886 #endif
1888 case MPR_TYPE_STRING:
1889 mprAssert(vp->string);
1890 return atof(vp->string);
1893 /* Not reached */
1894 return 0;
1897 #endif
1898 /******************************************************************************/
1900 * Convert the variable to a number type. Only works for primitive types.
1903 MprNum mprVarToNumber(const MprVar *vp)
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
1914 /******************************************************************************/
1916 * Convert the variable to a number type. Only works for primitive types.
1919 MprNum mprParseNumber(char *s)
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
1930 /******************************************************************************/
1931 #if BLD_FEATURE_INT64
1933 * Convert the variable to an Integer64 type. Only works for primitive types.
1936 int64 mprVarToInteger64(const MprVar *vp)
1938 mprAssert(vp);
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;
1950 case MPR_TYPE_BOOL:
1951 return (vp->boolean) ? 1 : 0;
1953 #if BLD_FEATURE_FLOATING_POINT
1954 case MPR_TYPE_FLOAT:
1955 if (mprIsNan(vp->floating)) {
1956 return 0;
1958 return (int64) vp->floating;
1959 #endif
1961 case MPR_TYPE_INT:
1962 return vp->integer;
1964 case MPR_TYPE_INT64:
1965 return vp->integer64;
1967 case MPR_TYPE_STRING:
1968 return mprParseInteger64(vp->string);
1971 /* Not reached */
1972 return 0;
1975 /******************************************************************************/
1977 * Convert the string buffer to an Integer64.
1980 int64 mprParseInteger64(char *str)
1982 char *cp;
1983 int64 num64;
1984 int radix, c, negative;
1986 mprAssert(str);
1988 cp = str;
1989 num64 = 0;
1990 negative = 0;
1992 if (*cp == '-') {
1993 cp++;
1994 negative = 1;
1998 * Parse a number. Observe hex and octal prefixes (0x, 0)
2000 if (*cp != '0') {
2002 * Normal numbers (Radix 10)
2004 while (isdigit((int) *cp)) {
2005 num64 = (*cp - '0') + (num64 * 10);
2006 cp++;
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;
2022 cp++;
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;
2034 cp++;
2039 if (negative) {
2040 return 0 - num64;
2042 return num64;
2045 #endif /* BLD_FEATURE_INT64 */
2046 /******************************************************************************/
2048 * Convert the variable to an Integer type. Only works for primitive types.
2051 int mprVarToInteger(const MprVar *vp)
2053 mprAssert(vp);
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;
2065 case MPR_TYPE_BOOL:
2066 return (vp->boolean) ? 1 : 0;
2068 #if BLD_FEATURE_FLOATING_POINT
2069 case MPR_TYPE_FLOAT:
2070 if (mprIsNan(vp->floating)) {
2071 return 0;
2073 return (int) vp->floating;
2074 #endif
2076 case MPR_TYPE_INT:
2077 return vp->integer;
2079 #if BLD_FEATURE_INT64
2080 case MPR_TYPE_INT64:
2081 return (int) vp->integer64;
2082 #endif
2084 case MPR_TYPE_STRING:
2085 return mprParseInteger(vp->string);
2088 /* Not reached */
2089 return 0;
2092 /******************************************************************************/
2094 * Convert the string buffer to an Integer.
2097 int mprParseInteger(char *str)
2099 char *cp;
2100 int num;
2101 int radix, c, negative;
2103 mprAssert(str);
2105 cp = str;
2106 num = 0;
2107 negative = 0;
2109 if (*cp == '-') {
2110 cp++;
2111 negative = 1;
2115 * Parse a number. Observe hex and octal prefixes (0x, 0)
2117 if (*cp != '0') {
2119 * Normal numbers (Radix 10)
2121 while (isdigit((int) *cp)) {
2122 num = (*cp - '0') + (num * 10);
2123 cp++;
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;
2139 cp++;
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;
2151 cp++;
2156 if (negative) {
2157 return 0 - num;
2159 return num;
2162 /******************************************************************************/
2163 #if BLD_FEATURE_FLOATING_POINT
2165 * Convert the string buffer to an Floating.
2168 double mprParseFloat(char *str)
2170 return atof(str);
2173 /******************************************************************************/
2175 bool mprIsNan(double f)
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
2188 /******************************************************************************/
2190 bool mprIsInfinite(double f)
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
2204 #endif /* BLD_FEATURE_FLOATING_POINT */
2205 /******************************************************************************/
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