3 * @brief MPR Universal Variable Type
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
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 **********************************/
49 /*********************************** Locals ***********************************/
52 static MprProperties objectList; /* Dummy head of objects list */
53 static int objectCount = -1; /* Count of objects */
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);
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)
85 if ((vp->trigger)(MPR_VAR_DELETE, vp->parentProperties, vp, 0, 0)
86 == MPR_TRIGGER_ABORT) {
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)
112 if ((vp->trigger)(MPR_VAR_DELETE, vp->parentProperties, vp, 0, 0)
113 == MPR_TRIGGER_ABORT) {
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
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)
140 freed = freeVarStorage(vp, force);
143 mprFree(vp->fullName);
145 if (vp->allocatedVar) {
150 vp->type = MPR_TYPE_UNDEFINED;
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)
176 case MPR_TYPE_STRING:
177 if (vp->allocatedData && vp->string != 0) {
180 vp->allocatedData = 0;
184 case MPR_TYPE_OBJECT:
187 * Recurse through all properties and release / delete. Release the
188 * properties hash table.
190 if (vp->properties->refCount > 1) {
191 mprLog(7, "freeVar: ACT \"%s\", 0x%x, ref %d, force %d\n",
192 vp->name, vp->properties, vp->properties->refCount, force);
194 mprLog(7, "freeVar: DEL \"%s\", 0x%x, ref %d, force %d\n",
195 vp->name, vp->properties, vp->properties->refCount, force);
198 if (vp->allocatedData) {
199 freed = releaseProperties(vp->properties, force);
204 case MPR_TYPE_FUNCTION:
205 if (vp->allocatedData) {
206 argList = vp->function.args;
207 for (i = 0; i < argList->max; i++) {
208 if (argList->handles[i] != 0) {
209 mprFree(argList->handles[i]);
212 mprDestroyArray(argList);
213 vp->function.args = 0;
214 mprFree(vp->function.body);
215 vp->function.body = 0;
220 vp->type = MPR_TYPE_UNDEFINED;
224 /******************************************************************************/
226 * Adjust the object reference count and return the currrent count of
230 static int adjustVarRefCount(MprVar *vp, int adj)
234 if (vp->type != MPR_TYPE_OBJECT) {
235 mprAssert(vp->type == MPR_TYPE_OBJECT);
238 return adjustRefCount(vp->properties, adj);
241 /******************************************************************************/
243 * Get the object reference count
246 int mprGetVarRefCount(MprVar *vp)
250 if (vp->type != MPR_TYPE_OBJECT) {
251 mprAssert(vp->type == MPR_TYPE_OBJECT);
254 return adjustRefCount(vp->properties, 0);
257 /******************************************************************************/
259 * Update the variable's name
262 void mprSetVarName(MprVar *vp, char *name)
267 vp->name = mprStrdup(name);
270 /******************************************************************************/
272 * Append to the variable's full name
275 void mprSetVarFullName(MprVar *vp, char *name)
280 mprFree(vp->fullName);
281 vp->fullName = mprStrdup(name);
282 if (vp->type == MPR_TYPE_OBJECT) {
283 if (strcmp(vp->properties->name, "this") == 0) {
284 mprStrcpy(vp->properties->name, sizeof(vp->properties->name), name);
290 /******************************************************************************/
292 * Make a var impervious to recursive forced deletes.
295 void mprSetVarDeleteProtect(MprVar *vp, int deleteProtect)
299 if (vp->type == MPR_TYPE_OBJECT && vp->properties) {
300 vp->properties->deleteProtect = deleteProtect;
304 /******************************************************************************/
306 * Make a variable readonly. Can still be deleted.
309 void mprSetVarReadonly(MprVar *vp, int readonly)
313 vp->readonly = readonly;
316 /******************************************************************************/
318 MprVarTrigger mprAddVarTrigger(MprVar *vp, MprVarTrigger fn)
320 MprVarTrigger oldTrigger;
325 oldTrigger = vp->trigger;
330 /******************************************************************************/
332 MprType mprGetVarType(MprVar *vp)
339 /******************************************************************************/
340 /********************************** Properties ********************************/
341 /******************************************************************************/
343 * Create a property in an object with a defined value. If the property
344 * already exists in the object, then just write its value.
347 MprVar *mprCreateProperty(MprVar *obj, const char *propertyName,
354 mprAssert(propertyName && *propertyName);
356 if (obj->type != MPR_TYPE_OBJECT) {
357 mprAssert(obj->type == MPR_TYPE_OBJECT);
362 * See if property already exists and locate the bucket to hold the
363 * property reference.
366 bucketIndex = hash(obj->properties, propertyName);
367 prop = obj->properties->buckets[bucketIndex];
370 * Find the property in the hash chain if it exists
372 for (last = 0; prop; last = prop, prop = prop->forw) {
373 if (prop->name[0] == propertyName[0] &&
374 strcmp(prop->name, propertyName) == 0) {
380 /* FUTURE -- remove. Just for debug. */
381 mprAssert(prop == 0);
382 mprLog(0, "Attempting to create property %s in object %s\n",
383 propertyName, obj->name);
388 if ((obj->trigger)(MPR_VAR_CREATE_PROPERTY, obj->properties, prop,
389 newValue, 0) == MPR_TRIGGER_ABORT) {
395 * Create a new property
397 prop = allocProperty(propertyName);
403 copyVarCore(prop, newValue, MPR_SHALLOW_COPY);
405 prop->bucketIndex = bucketIndex;
409 obj->properties->buckets[bucketIndex] = prop;
411 prop->parentProperties = obj->properties;
414 * Update the item counts
416 obj->properties->numItems++;
417 if (! mprVarIsFunction(prop->type)) {
418 obj->properties->numDataItems++;
424 /******************************************************************************/
426 * Create a property in an object with a defined value. If the property
427 * already exists in the object, then just write its value. Same as
428 * mprCreateProperty except that the new value is passed by value rather than
432 MprVar *mprCreatePropertyValue(MprVar *obj, const char *propertyName,
435 return mprCreateProperty(obj, propertyName, &newValue);
438 /******************************************************************************/
440 * Create a new property
443 static MprVar *allocProperty(const char *propertyName)
447 prop = (MprVar*) mprMalloc(sizeof(MprVar));
452 memset(prop, 0, sizeof(MprVar));
453 prop->allocatedVar = 1;
454 prop->name = mprStrdup(propertyName);
455 prop->forw = (MprVar*) 0;
460 /******************************************************************************/
462 * Update a property in an object with a defined value. Create the property
463 * if it doesn not already exist.
466 MprVar *mprSetProperty(MprVar *obj, const char *propertyName, MprVar *newValue)
468 MprVar *prop, triggerValue;
472 mprAssert(propertyName && *propertyName);
473 mprAssert(obj->type == MPR_TYPE_OBJECT);
475 if (obj->type != MPR_TYPE_OBJECT) {
480 prop = mprGetProperty(obj, propertyName, 0);
482 return mprCreateProperty(obj, propertyName, newValue);
487 * Call the trigger before the update and pass it the new value.
489 triggerValue = *newValue;
490 triggerValue.allocatedVar = 0;
491 triggerValue.allocatedData = 0;
492 rc = (obj->trigger)(MPR_VAR_WRITE, obj->properties, obj,
494 if (rc == MPR_TRIGGER_ABORT) {
497 } else if (rc == MPR_TRIGGER_USE_NEW_VALUE) {
499 * Trigger must copy to triggerValue a variable that is not
500 * a structure copy of the existing data.
502 copyVarCore(prop, &triggerValue, MPR_SHALLOW_COPY);
503 mprDestroyVar(&triggerValue);
507 copyVarCore(prop, newValue, MPR_SHALLOW_COPY);
511 /******************************************************************************/
513 * Update a property in an object with a defined value. Create the property
514 * if it does not already exist. Same as mprSetProperty except that the
515 * new value is passed by value rather than by pointer.
518 MprVar *mprSetPropertyValue(MprVar *obj, const char *propertyName,
521 return mprSetProperty(obj, propertyName, &newValue);
524 /******************************************************************************/
526 * Delete a property from this object
529 int mprDeleteProperty(MprVar *obj, const char *property)
536 mprAssert(property && *property);
537 mprAssert(obj->type == MPR_TYPE_OBJECT);
539 if (obj->type != MPR_TYPE_OBJECT) {
540 mprAssert(obj->type == MPR_TYPE_OBJECT);
545 bucketIndex = hash(obj->properties, property);
546 if ((prop = obj->properties->buckets[bucketIndex]) != 0) {
547 for ( ; prop; prop = prop->forw) {
549 if (cp[0] == property[0] && strcmp(cp, property) == 0) {
555 if (prop == (MprVar*) 0) {
557 return MPR_ERR_NOT_FOUND;
559 if (prop->readonly) {
560 mprAssert(! prop->readonly);
561 return MPR_ERR_READ_ONLY;
565 if ((obj->trigger)(MPR_VAR_DELETE_PROPERTY, obj->properties, prop, 0, 0)
566 == MPR_TRIGGER_ABORT) {
567 return MPR_ERR_ABORTED;
572 last->forw = prop->forw;
574 obj->properties->buckets[bucketIndex] = prop->forw;
577 obj->properties->numItems--;
578 if (! mprVarIsFunction(prop->type)) {
579 obj->properties->numDataItems--;
587 /******************************************************************************/
589 * Find a property in an object and return a pointer to it. If a value arg
590 * is supplied, then copy the data into the var.
593 MprVar *mprGetProperty(MprVar *obj, const char *property, MprVar *value)
595 MprVar *prop, triggerValue;
598 if (obj == 0 || obj->type != MPR_TYPE_OBJECT || property == 0 ||
601 value->type = MPR_TYPE_UNDEFINED;
606 for (prop = getObjChain(obj->properties, property); prop;
609 prop->name[0] == property[0] && strcmp(prop->name, property) == 0) {
615 value->type = MPR_TYPE_UNDEFINED;
621 triggerValue = *prop;
622 triggerValue.allocatedVar = 0;
623 triggerValue.allocatedData = 0;
625 * Pass the trigger the current read value and may receive
628 rc = (prop->trigger)(MPR_VAR_READ, prop->parentProperties, prop,
630 if (rc == MPR_TRIGGER_ABORT) {
632 value->type = MPR_TYPE_UNDEFINED;
636 } else if (rc == MPR_TRIGGER_USE_NEW_VALUE) {
637 copyVarCore(prop, &triggerValue, MPR_SHALLOW_COPY);
638 mprDestroyVar(&triggerValue);
649 /******************************************************************************/
651 * Read a properties value. This returns the property's value. It does not
652 * copy object/string data but returns a pointer directly into the variable.
653 * The caller does not and should not call mprDestroy on the returned value.
654 * If value is null, just read the property and run triggers.
657 int mprReadProperty(MprVar *prop, MprVar *value)
665 triggerValue = *prop;
666 triggerValue.allocatedVar = 0;
667 triggerValue.allocatedData = 0;
668 rc = (prop->trigger)(MPR_VAR_READ, prop->parentProperties, prop,
671 if (rc == MPR_TRIGGER_ABORT) {
672 return MPR_ERR_ABORTED;
674 } else if (rc == MPR_TRIGGER_USE_NEW_VALUE) {
675 copyVarCore(prop, &triggerValue, MPR_SHALLOW_COPY);
676 mprDestroyVar(&triggerValue);
684 * Just so that if the user calls mprDestroyVar on value, it will do no
687 value->allocatedVar = 0;
688 value->allocatedData = 0;
693 /******************************************************************************/
695 * Read a properties value. This returns a copy of the property variable.
696 * However, if the property is an object or string, it returns a copy of the
697 * reference to the underlying data. If copyDepth is set to MPR_DEEP_COPY,
698 * then the underlying objects and strings data will be copied as well. If
699 * copyDepth is set to MPR_SHALLOW_COPY, then only strings will be copied. If
700 * it is set to MPR_NO_COPY, then no data will be copied. In all cases, the
701 * user must call mprDestroyVar to free resources. This routine will run any
702 * registered triggers which may modify the value the user receives (without
703 * updating the properties real value).
705 * WARNING: the args are reversed to most other APIs. This conforms to the
706 * strcpy(dest, src) standard instead.
709 int mprCopyProperty(MprVar *dest, MprVar *prop, int copyDepth)
718 triggerValue = *prop;
719 triggerValue.allocatedVar = 0;
720 triggerValue.allocatedData = 0;
721 rc = (prop->trigger)(MPR_VAR_READ, prop->parentProperties, prop,
722 &triggerValue, copyDepth);
724 if (rc == MPR_TRIGGER_ABORT) {
725 return MPR_ERR_ABORTED;
727 } else if (rc == MPR_TRIGGER_USE_NEW_VALUE) {
728 copyVarCore(dest, &triggerValue, MPR_SHALLOW_COPY);
729 mprDestroyVar(&triggerValue);
733 mprCopyVar(dest, prop, copyDepth);
737 /******************************************************************************/
739 * Write a new value into an existing property in an object.
742 int mprWriteProperty(MprVar *vp, MprVar *value)
751 return MPR_ERR_READ_ONLY;
755 triggerValue = *value;
757 rc = (vp->trigger)(MPR_VAR_WRITE, vp->parentProperties, vp,
760 if (rc == MPR_TRIGGER_ABORT) {
761 return MPR_ERR_ABORTED;
763 } else if (rc == MPR_TRIGGER_USE_NEW_VALUE) {
764 copyVarCore(vp, &triggerValue, MPR_SHALLOW_COPY);
765 mprDestroyVar(&triggerValue);
771 copyVarCore(vp, value, MPR_SHALLOW_COPY);
775 /******************************************************************************/
777 * Write a new value into an existing property in an object.
780 int mprWritePropertyValue(MprVar *vp, MprVar value)
784 return mprWriteProperty(vp, &value);
787 /******************************************************************************/
789 * Get the count of properties.
792 int mprGetPropertyCount(MprVar *vp, int includeFlags)
796 if (vp->type != MPR_TYPE_OBJECT) {
799 if (includeFlags == MPR_ENUM_DATA) {
800 return vp->properties->numDataItems;
802 return vp->properties->numItems;
806 /******************************************************************************/
808 * Get the first property in an object. Used for walking all properties in an
812 MprVar *mprGetFirstProperty(MprVar *obj, int includeFlags)
818 mprAssert(obj->type == MPR_TYPE_OBJECT);
820 if (obj->type != MPR_TYPE_OBJECT) {
821 mprAssert(obj->type == MPR_TYPE_OBJECT);
825 for (i = 0; i < (int) obj->properties->hashSize; i++) {
826 for (prop = obj->properties->buckets[i]; prop; prop = prop->forw) {
828 if (mprVarIsFunction(prop->type)) {
829 if (!(includeFlags & MPR_ENUM_FUNCTIONS)) {
833 if (!(includeFlags & MPR_ENUM_DATA)) {
845 /******************************************************************************/
847 * Get the next property in sequence.
850 MprVar *mprGetNextProperty(MprVar *obj, MprVar *last, int includeFlags)
852 MprProperties *properties;
856 mprAssert(obj->type == MPR_TYPE_OBJECT);
858 if (obj->type != MPR_TYPE_OBJECT) {
859 mprAssert(obj->type == MPR_TYPE_OBJECT);
862 properties = obj->properties;
868 for (i = last->bucketIndex + 1; i < (int) properties->hashSize; i++) {
869 for (last = properties->buckets[i]; last; last = last->forw) {
870 if (mprVarIsFunction(last->type)) {
871 if (!(includeFlags & MPR_ENUM_FUNCTIONS)) {
875 if (!(includeFlags & MPR_ENUM_DATA)) {
885 /******************************************************************************/
886 /************************** Internal Support Routines *************************/
887 /******************************************************************************/
889 * Create an hash table to hold and index properties. Properties are just
890 * variables which may contain primitive data types, functions or other
891 * objects. The hash table is the essence of an object. HashSize specifies
892 * the size of the hash table to use and should be a prime number.
895 static MprProperties *createProperties(const char *name, int hashSize)
902 if ((pp = (MprProperties*) mprMalloc(sizeof(MprProperties))) == NULL) {
907 memset(pp, 0, sizeof(MprProperties));
910 pp->numDataItems = 0;
911 pp->hashSize = hashSize;
912 pp->buckets = (MprVar**) mprMalloc(pp->hashSize * sizeof(MprVar*));
913 mprAssert(pp->buckets);
914 memset(pp->buckets, 0, pp->hashSize * sizeof(MprVar*));
918 if (objectCount == -1) {
920 objectList.next = objectList.prev = &objectList;
923 mprStrcpy(pp->name, sizeof(pp->name), name);
924 pp->next = &objectList;
925 pp->prev = objectList.prev;
926 objectList.prev->next = pp;
927 objectList.prev = pp;
933 /******************************************************************************/
935 * Release an object's properties hash table. If this is the last person
936 * using it, free it. Return TRUE if the object is released.
939 static bool releaseProperties(MprProperties *obj, int force)
946 mprAssert(obj->refCount > 0);
952 mprAssert(obj->refCount < 20);
955 if (--obj->refCount > 0 && !force) {
960 mprAssert(obj->prev);
961 mprAssert(obj->next);
962 mprAssert(obj->next->prev);
963 mprAssert(obj->prev->next);
964 obj->next->prev = obj->prev;
965 obj->prev->next = obj->next;
969 for (i = 0; i < (int) obj->hashSize; i++) {
970 for (prop = obj->buckets[i]; prop; prop = forw) {
972 if (prop->type == MPR_TYPE_OBJECT) {
974 if (prop->properties == obj) {
978 pp = prop->properties;
984 if (! freeVar(prop, pp->deleteProtect ? 0 : force)) {
989 freeVar(prop, force);
994 mprFree((void*) obj->buckets);
995 mprFree((void*) obj);
1000 /******************************************************************************/
1002 * Adjust the reference count
1005 static int adjustRefCount(MprProperties *pp, int adj)
1010 * Debug sanity check
1012 mprAssert(pp->refCount < 20);
1014 return pp->refCount += adj;
1017 /******************************************************************************/
1020 * Print objects held
1023 void mprPrintObjects(char *msg)
1025 MprProperties *pp, *np;
1026 MprVar *prop, *forw;
1030 mprLog(7, "%s: Object Store. %d objects.\n", msg, objectCount);
1031 pp = objectList.next;
1032 while (pp != &objectList) {
1033 mprLog(7, "%s: 0x%x, refCount %d, properties %d\n",
1034 pp->name, pp, pp->refCount, pp->numItems);
1035 for (i = 0; i < (int) pp->hashSize; i++) {
1036 for (prop = pp->buckets[i]; prop; prop = forw) {
1038 if (prop->properties == pp) {
1039 /* Self reference */
1042 mprVarToString(&buf, MPR_MAX_STRING, 0, prop);
1043 if (prop->type == MPR_TYPE_OBJECT) {
1044 np = objectList.next;
1045 while (np != &objectList) {
1046 if (prop->properties == np) {
1051 if (prop->properties == np) {
1052 mprLog(7, " %s: OBJECT 0x%x, <%s>\n",
1053 prop->name, prop->properties, prop->fullName);
1055 mprLog(7, " %s: OBJECT NOT FOUND, %s <%s>\n",
1056 prop->name, buf, prop->fullName);
1059 mprLog(7, " %s: <%s> = %s\n", prop->name,
1060 prop->fullName, buf);
1069 /******************************************************************************/
1071 void mprPrintObjRefCount(MprVar *vp)
1073 mprLog(7, "OBJECT 0x%x, refCount %d\n", vp->properties,
1074 vp->properties->refCount);
1078 /******************************************************************************/
1080 * Get the bucket chain containing a property.
1083 static MprVar *getObjChain(MprProperties *obj, const char *property)
1087 return obj->buckets[hash(obj, property)];
1090 /******************************************************************************/
1092 * Fast hash. The history of this algorithm is part of lost computer science
1096 static int hash(MprProperties *pp, const char *property)
1101 mprAssert(property);
1105 sum += (sum * 33) + *property++;
1108 return sum % pp->hashSize;
1111 /******************************************************************************/
1112 /*********************************** Constructors *****************************/
1113 /******************************************************************************/
1115 * Initialize an undefined value.
1118 MprVar mprCreateUndefinedVar()
1122 memset(&v, 0x0, sizeof(v));
1123 v.type = MPR_TYPE_UNDEFINED;
1127 /******************************************************************************/
1129 * Initialize an null value.
1132 MprVar mprCreateNullVar()
1136 memset(&v, 0x0, sizeof(v));
1137 v.type = MPR_TYPE_NULL;
1141 /******************************************************************************/
1143 MprVar mprCreateBoolVar(bool value)
1147 memset(&v, 0x0, sizeof(v));
1148 v.type = MPR_TYPE_BOOL;
1153 /******************************************************************************/
1155 * Initialize a C function.
1158 MprVar mprCreateCFunctionVar(MprCFunction fn, void *thisPtr, int flags)
1162 memset(&v, 0x0, sizeof(v));
1163 v.type = MPR_TYPE_CFUNCTION;
1164 v.cFunction.fn = fn;
1165 v.cFunction.thisPtr = thisPtr;
1171 /******************************************************************************/
1173 * Initialize a C function.
1176 MprVar mprCreateStringCFunctionVar(MprStringCFunction fn, void *thisPtr,
1181 memset(&v, 0x0, sizeof(v));
1182 v.type = MPR_TYPE_STRING_CFUNCTION;
1183 v.cFunctionWithStrings.fn = fn;
1184 v.cFunctionWithStrings.thisPtr = thisPtr;
1190 /******************************************************************************/
1192 * Initialize an opaque pointer.
1195 MprVar mprCreatePtrVar(void *ptr)
1199 memset(&v, 0x0, sizeof(v));
1200 v.type = MPR_TYPE_PTR;
1206 /******************************************************************************/
1207 #if BLD_FEATURE_FLOATING_POINT
1209 * Initialize a floating value.
1212 MprVar mprCreateFloatVar(double value)
1216 memset(&v, 0x0, sizeof(v));
1217 v.type = MPR_TYPE_FLOAT;
1223 /******************************************************************************/
1225 * Initialize an integer value.
1228 MprVar mprCreateIntegerVar(int value)
1232 memset(&v, 0x0, sizeof(v));
1233 v.type = MPR_TYPE_INT;
1238 /******************************************************************************/
1239 #if BLD_FEATURE_INT64
1241 * Initialize a 64-bit integer value.
1244 MprVar mprCreateInteger64Var(int64 value)
1248 memset(&v, 0x0, sizeof(v));
1249 v.type = MPR_TYPE_INT64;
1250 v.integer64 = value;
1254 #endif /* BLD_FEATURE_INT64 */
1255 /******************************************************************************/
1257 * Initialize an number variable. Type is defined by configure.
1260 MprVar mprCreateNumberVar(MprNum value)
1264 memset(&v, 0x0, sizeof(v));
1265 v.type = BLD_FEATURE_NUM_TYPE_ID;
1266 #if BLD_FEATURE_NUM_TYPE_ID == MPR_TYPE_INT64
1267 v.integer64 = value;
1268 #elif BLD_FEATURE_NUM_TYPE_ID == MPR_TYPE_FLOAT
1276 /******************************************************************************/
1278 * Initialize a (bare) JavaScript function. args and body can be null.
1281 MprVar mprCreateFunctionVar(char *args, char *body, int flags)
1284 char *cp, *arg, *last;
1287 memset(&v, 0x0, sizeof(v));
1288 v.type = MPR_TYPE_FUNCTION;
1291 v.function.args = mprCreateArray();
1294 args = mprStrdup(args);
1295 arg = mprStrTok(args, ",", &last);
1297 while (isspace((int) *arg))
1299 for (cp = &arg[strlen(arg) - 1]; cp > arg; cp--) {
1300 if (!isspace((int) *cp)) {
1306 aid = mprAddToArray(v.function.args, mprStrdup(arg));
1307 arg = mprStrTok(0, ",", &last);
1313 v.function.body = mprStrdup(body);
1315 v.allocatedData = 1;
1319 /******************************************************************************/
1321 * Initialize an object variable. Return type == MPR_TYPE_UNDEFINED if the
1322 * memory allocation for the properties table failed.
1325 MprVar mprCreateObjVar(const char *name, int hashSize)
1329 mprAssert(name && *name);
1331 memset(&v, 0x0, sizeof(MprVar));
1332 v.type = MPR_TYPE_OBJECT;
1333 if (hashSize <= 0) {
1334 hashSize = MPR_DEFAULT_HASH_SIZE;
1336 v.properties = createProperties(name, hashSize);
1337 if (v.properties == 0) {
1338 /* Indicate failed memory allocation */
1339 v.type = MPR_TYPE_UNDEFINED;
1341 v.allocatedData = 1;
1342 v.name = mprStrdup(name);
1343 mprLog(7, "mprCreateObjVar %s, 0x%p\n", name, v.properties);
1347 /******************************************************************************/
1349 * Initialize a string value.
1352 MprVar mprCreateStringVar(const char *value, bool allocate)
1356 memset(&v, 0x0, sizeof(v));
1357 v.type = MPR_TYPE_STRING;
1360 } else if (allocate) {
1361 v.string = mprStrdup(value);
1362 v.allocatedData = 1;
1364 v.string = (char*) value;
1369 /******************************************************************************/
1371 * Copy an objects core value (only). This preserves the destination object's
1372 * name. This implements copy by reference for objects and copy by value for
1373 * strings and other types. Caller must free dest prior to calling.
1376 static void copyVarCore(MprVar *dest, MprVar *src, int copyDepth)
1378 MprVarTrigger saveTrigger;
1379 MprVar *srcProp, *destProp, *last;
1391 * FUTURE: we should allow read-only triggers where the value is never
1392 * stored in the object. Currently, triggers override the readonly
1396 if (dest->type != MPR_TYPE_UNDEFINED && dest->readonly && !dest->trigger) {
1401 if (dest->type != MPR_TYPE_UNDEFINED) {
1402 saveTrigger = dest->trigger;
1403 freeVarStorage(dest, 0);
1408 switch (src->type) {
1410 case MPR_TYPE_UNDEFINED:
1415 dest->boolean = src->boolean;
1419 dest->ptr = src->ptr;
1422 case MPR_TYPE_STRING_CFUNCTION:
1423 dest->cFunctionWithStrings = src->cFunctionWithStrings;
1426 case MPR_TYPE_CFUNCTION:
1427 dest->cFunction = src->cFunction;
1430 #if BLD_FEATURE_FLOATING_POINT
1431 case MPR_TYPE_FLOAT:
1432 dest->floating = src->floating;
1437 dest->integer = src->integer;
1440 #if BLD_FEATURE_INT64
1441 case MPR_TYPE_INT64:
1442 dest->integer64 = src->integer64;
1446 case MPR_TYPE_OBJECT:
1447 if (copyDepth == MPR_DEEP_COPY) {
1449 dest->properties = createProperties(src->name,
1450 src->properties->hashSize);
1451 dest->allocatedData = 1;
1453 for (i = 0; i < (int) src->properties->hashSize; i++) {
1455 for (srcProp = src->properties->buckets[i]; srcProp;
1456 srcProp = srcProp->forw) {
1457 if (srcProp->visited) {
1460 destProp = allocProperty(srcProp->name);
1461 if (destProp == 0) {
1462 mprAssert(destProp);
1466 destProp->bucketIndex = i;
1468 last->forw = destProp;
1470 dest->properties->buckets[i] = destProp;
1472 destProp->parentProperties = dest->properties;
1475 * Recursively copy the object
1477 srcProp->visited = 1;
1478 copyVarCore(destProp, srcProp, copyDepth);
1479 srcProp->visited = 0;
1483 dest->properties->numItems = src->properties->numItems;
1484 dest->properties->numDataItems = src->properties->numDataItems;
1485 dest->allocatedData = 1;
1487 } else if (copyDepth == MPR_SHALLOW_COPY) {
1488 dest->properties = src->properties;
1489 adjustVarRefCount(src, 1);
1490 dest->allocatedData = 1;
1493 dest->properties = src->properties;
1494 dest->allocatedData = 0;
1498 case MPR_TYPE_FUNCTION:
1499 if (copyDepth != MPR_NO_COPY) {
1500 dest->function.args = mprCreateArray();
1501 srcArgs = (char**) src->function.args->handles;
1502 for (i = 0; i < src->function.args->max; i++) {
1504 mprAddToArray(dest->function.args, mprStrdup(srcArgs[i]));
1507 dest->function.body = mprStrdup(src->function.body);
1508 dest->allocatedData = 1;
1510 dest->function.args = src->function.args;
1511 dest->function.body = src->function.body;
1512 dest->allocatedData = 0;
1516 case MPR_TYPE_STRING:
1517 if (src->string && copyDepth != MPR_NO_COPY) {
1518 dest->string = mprStrdup(src->string);
1519 dest->allocatedData = 1;
1521 dest->string = src->string;
1522 dest->allocatedData = 0;
1527 dest->type = src->type;
1528 dest->flags = src->flags;
1529 dest->trigger = saveTrigger;
1537 /******************************************************************************/
1539 * Copy an entire object including name.
1542 void mprCopyVar(MprVar *dest, MprVar *src, int copyDepth)
1547 copyVarCore(dest, src, copyDepth);
1549 mprFree(dest->name);
1550 dest->name = mprStrdup(src->name);
1553 if (src->type == MPR_TYPE_OBJECT) {
1555 mprFree(dest->fullName);
1556 dest->fullName = mprStrdup(src->fullName);
1558 mprLog(7, "mprCopyVar: object \"%s\", FDQ \"%s\" 0x%x, refCount %d\n",
1559 dest->name, dest->fullName, dest->properties,
1560 dest->properties->refCount);
1565 /******************************************************************************/
1567 * Copy an entire object including name.
1570 void mprCopyVarValue(MprVar *dest, MprVar src, int copyDepth)
1574 mprCopyVar(dest, &src, copyDepth);
1577 /******************************************************************************/
1579 * Copy an object. This implements copy by reference for objects and copy by
1580 * value for strings and other types. Caller must free dest prior to calling.
1583 MprVar *mprDupVar(MprVar *src, int copyDepth)
1589 dest = (MprVar*) mprMalloc(sizeof(MprVar));
1590 memset(dest, 0, sizeof(MprVar));
1592 mprCopyVar(dest, src, copyDepth);
1596 /******************************************************************************/
1598 * Convert a value to a text based representation of its value
1599 * FUTURE -- conver this to use the format string in all cases. Allow
1600 * arbitrary format strings.
1603 void mprVarToString(char** out, int size, char *fmt, MprVar *obj)
1612 mprReadProperty(obj, 0);
1615 switch (obj->type) {
1616 case MPR_TYPE_UNDEFINED:
1617 /* FUTURE -- spec says convert to "undefined" */
1618 *out = mprStrdup("");
1622 *out = mprStrdup("null");
1626 mprAllocSprintf(out, size, "[Opaque Pointer %p]", obj->ptr);
1631 *out = mprStrdup("true");
1633 *out = mprStrdup("false");
1637 #if BLD_FEATURE_FLOATING_POINT
1638 case MPR_TYPE_FLOAT:
1639 if (fmt == NULL || *fmt == '\0') {
1640 mprAllocSprintf(out, size, "%f", obj->floating);
1642 mprAllocSprintf(out, size, fmt, obj->floating);
1648 if (fmt == NULL || *fmt == '\0') {
1649 mprAllocSprintf(out, size, "%d", obj->integer);
1651 mprAllocSprintf(out, size, fmt, obj->integer);
1655 #if BLD_FEATURE_INT64
1656 case MPR_TYPE_INT64:
1657 if (fmt == NULL || *fmt == '\0') {
1658 #if BLD_GOAHEAD_WEBSERVER
1659 mprAllocSprintf(out, size, "%d", (int) obj->integer64);
1661 mprAllocSprintf(out, size, "%Ld", obj->integer64);
1664 mprAllocSprintf(out, size, fmt, obj->integer64);
1669 case MPR_TYPE_CFUNCTION:
1670 mprAllocSprintf(out, size, "[C Function]");
1673 case MPR_TYPE_STRING_CFUNCTION:
1674 mprAllocSprintf(out, size, "[C StringFunction]");
1677 case MPR_TYPE_FUNCTION:
1678 mprAllocSprintf(out, size, "[JavaScript Function]");
1681 case MPR_TYPE_OBJECT:
1682 /* FUTURE -- really want: [object class: name] */
1683 mprAllocSprintf(out, size, "[object %s]", obj->name);
1686 case MPR_TYPE_STRING:
1691 mprAllocSprintf(out, size, fmt, src);
1693 } else if (src == NULL) {
1694 *out = mprStrdup("null");
1697 *out = mprStrdup(src);
1706 /******************************************************************************/
1708 * Parse a string based on formatting instructions and intelligently
1709 * create a variable.
1712 MprVar mprParseVar(char *buf, MprType preferredType)
1714 MprType type = MPR_TYPE_UNDEFINED;
1719 if (preferredType == MPR_TYPE_UNDEFINED) {
1723 } else if (!isdigit((int) *buf)) {
1724 if (strcmp(buf, "true") == 0 || strcmp(buf, "false") == 0) {
1725 type = MPR_TYPE_BOOL;
1727 type = MPR_TYPE_STRING;
1730 } else if (isdigit((int) *buf)) {
1733 if (*cp && tolower((unsigned char)cp[1]) == 'x') {
1736 for (cp = buf; *cp; cp++) {
1737 if (! isdigit((unsigned char) *cp)) {
1743 #if BLD_FEATURE_FLOATING_POINT
1744 if (*cp == '.' || tolower((unsigned char)*cp) == 'e') {
1745 type = MPR_TYPE_FLOAT;
1754 type = preferredType;
1758 case MPR_TYPE_OBJECT:
1759 case MPR_TYPE_UNDEFINED:
1766 return mprCreateBoolVar(buf[0] == 't' ? 1 : 0);
1769 return mprCreateIntegerVar(mprParseInteger(buf));
1771 #if BLD_FEATURE_INT64
1772 case MPR_TYPE_INT64:
1773 return mprCreateInteger64Var(mprParseInteger64(buf));
1776 case MPR_TYPE_STRING:
1777 if (strcmp(buf, "null") == 0) {
1778 return mprCreateNullVar();
1779 } else if (strcmp(buf, "undefined") == 0) {
1780 return mprCreateUndefinedVar();
1783 return mprCreateStringVar(buf, 1);
1785 #if BLD_FEATURE_FLOATING_POINT
1786 case MPR_TYPE_FLOAT:
1787 return mprCreateFloatVar(atof(buf));
1791 return mprCreateUndefinedVar();
1794 /******************************************************************************/
1796 * Convert the variable to a boolean. Only for primitive types.
1799 bool mprVarToBool(const MprVar *vp)
1804 case MPR_TYPE_UNDEFINED:
1806 case MPR_TYPE_STRING_CFUNCTION:
1807 case MPR_TYPE_CFUNCTION:
1808 case MPR_TYPE_FUNCTION:
1809 case MPR_TYPE_OBJECT:
1813 return (vp->ptr != NULL);
1818 #if BLD_FEATURE_FLOATING_POINT
1819 case MPR_TYPE_FLOAT:
1820 return (vp->floating != 0 && !mprIsNan(vp->floating));
1824 return (vp->integer != 0);
1826 #if BLD_FEATURE_INT64
1827 case MPR_TYPE_INT64:
1828 return (vp->integer64 != 0);
1831 case MPR_TYPE_STRING:
1832 mprAssert(vp->string);
1833 return (vp->string[0] != '\0');
1840 /******************************************************************************/
1841 #if BLD_FEATURE_FLOATING_POINT
1843 * Convert the variable to a floating point number. Only for primitive types.
1846 double mprVarToFloat(const MprVar *vp)
1851 case MPR_TYPE_UNDEFINED:
1853 case MPR_TYPE_STRING_CFUNCTION:
1854 case MPR_TYPE_CFUNCTION:
1855 case MPR_TYPE_FUNCTION:
1856 case MPR_TYPE_OBJECT:
1861 return (vp->boolean) ? 1.0 : 0.0;
1863 case MPR_TYPE_FLOAT:
1864 return vp->floating;
1867 return (double) vp->integer;
1869 #if BLD_FEATURE_INT64
1870 case MPR_TYPE_INT64:
1871 return (double) vp->integer64;
1874 case MPR_TYPE_STRING:
1875 mprAssert(vp->string);
1876 return atof(vp->string);
1884 /******************************************************************************/
1886 * Convert the variable to a number type. Only works for primitive types.
1889 MprNum mprVarToNumber(const MprVar *vp)
1891 #if BLD_FEATURE_NUM_TYPE_ID == MPR_TYPE_INT64
1892 return mprVarToInteger64(vp);
1893 #elif BLD_FEATURE_NUM_TYPE_ID == MPR_TYPE_FLOAT
1894 return mprVarToFloat(vp);
1896 return mprVarToInteger(vp);
1900 /******************************************************************************/
1902 * Convert the variable to a number type. Only works for primitive types.
1905 MprNum mprParseNumber(char *s)
1907 #if BLD_FEATURE_NUM_TYPE_ID == MPR_TYPE_INT64
1908 return mprParseInteger64(s);
1909 #elif BLD_FEATURE_NUM_TYPE_ID == MPR_TYPE_FLOAT
1910 return mprParseFloat(s);
1912 return mprParseInteger(s);
1916 /******************************************************************************/
1917 #if BLD_FEATURE_INT64
1919 * Convert the variable to an Integer64 type. Only works for primitive types.
1922 int64 mprVarToInteger64(const MprVar *vp)
1927 case MPR_TYPE_UNDEFINED:
1929 case MPR_TYPE_STRING_CFUNCTION:
1930 case MPR_TYPE_CFUNCTION:
1931 case MPR_TYPE_FUNCTION:
1932 case MPR_TYPE_OBJECT:
1937 return (vp->boolean) ? 1 : 0;
1939 #if BLD_FEATURE_FLOATING_POINT
1940 case MPR_TYPE_FLOAT:
1941 if (mprIsNan(vp->floating)) {
1944 return (int64) vp->floating;
1950 case MPR_TYPE_INT64:
1951 return vp->integer64;
1953 case MPR_TYPE_STRING:
1954 return mprParseInteger64(vp->string);
1961 /******************************************************************************/
1963 * Convert the string buffer to an Integer64.
1966 int64 mprParseInteger64(char *str)
1970 int radix, c, negative;
1984 * Parse a number. Observe hex and octal prefixes (0x, 0)
1988 * Normal numbers (Radix 10)
1990 while (isdigit((int) *cp)) {
1991 num64 = (*cp - '0') + (num64 * 10);
1996 if (tolower((unsigned char)*cp) == 'x') {
2000 c = tolower((unsigned char)*cp);
2002 num64 = (c - '0') + (num64 * radix);
2003 } else if (c >= 'a' && c <= 'f') {
2004 num64 = (c - 'a') + (num64 * radix);
2014 c = tolower((unsigned char)*cp);
2015 if (isdigit(c) && c < '8') {
2016 num64 = (c - '0') + (num64 * radix);
2031 #endif /* BLD_FEATURE_INT64 */
2032 /******************************************************************************/
2034 * Convert the variable to an Integer type. Only works for primitive types.
2037 int mprVarToInteger(const MprVar *vp)
2042 case MPR_TYPE_UNDEFINED:
2044 case MPR_TYPE_STRING_CFUNCTION:
2045 case MPR_TYPE_CFUNCTION:
2046 case MPR_TYPE_FUNCTION:
2047 case MPR_TYPE_OBJECT:
2052 return (vp->boolean) ? 1 : 0;
2054 #if BLD_FEATURE_FLOATING_POINT
2055 case MPR_TYPE_FLOAT:
2056 if (mprIsNan(vp->floating)) {
2059 return (int) vp->floating;
2065 #if BLD_FEATURE_INT64
2066 case MPR_TYPE_INT64:
2067 return (int) vp->integer64;
2070 case MPR_TYPE_STRING:
2071 return mprParseInteger(vp->string);
2078 /******************************************************************************/
2080 * Convert the string buffer to an Integer.
2083 int mprParseInteger(char *str)
2087 int radix, c, negative;
2101 * Parse a number. Observe hex and octal prefixes (0x, 0)
2105 * Normal numbers (Radix 10)
2107 while (isdigit((int) *cp)) {
2108 num = (*cp - '0') + (num * 10);
2113 if (tolower((unsigned char)*cp) == 'x') {
2117 c = tolower((unsigned char)*cp);
2119 num = (c - '0') + (num * radix);
2120 } else if (c >= 'a' && c <= 'f') {
2121 num = (c - 'a') + (num * radix);
2131 c = tolower((unsigned char)*cp);
2132 if (isdigit(c) && c < '8') {
2133 num = (c - '0') + (num * radix);
2148 /******************************************************************************/
2149 #if BLD_FEATURE_FLOATING_POINT
2151 * Convert the string buffer to an Floating.
2154 double mprParseFloat(char *str)
2159 /******************************************************************************/
2161 bool mprIsNan(double f)
2169 return (f == FP_NAN);
2172 /******************************************************************************/
2174 bool mprIsInfinite(double f)
2182 return (f == FP_INFINITE);
2186 #endif /* BLD_FEATURE_FLOATING_POINT */
2187 /******************************************************************************/
2195 * vim600: sw=4 ts=4 fdm=marker
2196 * vim<600: sw=4 ts=4