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;
185 if (vp
->allocatedData
) {
186 vp
->allocatedData
= 0;
191 case MPR_TYPE_OBJECT
:
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
);
201 mprLog(7, "freeVar: DEL \"%s\", 0x%x, ref %d, force %d\n",
202 vp
->name
, vp
->properties
, vp
->properties
->refCount
, force
);
205 if (vp
->allocatedData
) {
206 freed
= releaseProperties(vp
->properties
, force
);
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;
227 vp
->type
= MPR_TYPE_UNDEFINED
;
231 /******************************************************************************/
233 * Adjust the object reference count and return the currrent count of
237 static int adjustVarRefCount(MprVar
*vp
, int adj
)
241 if (vp
->type
!= MPR_TYPE_OBJECT
) {
242 mprAssert(vp
->type
== MPR_TYPE_OBJECT
);
245 return adjustRefCount(vp
->properties
, adj
);
248 /******************************************************************************/
250 * Get the object reference count
253 int mprGetVarRefCount(MprVar
*vp
)
257 if (vp
->type
!= MPR_TYPE_OBJECT
) {
258 mprAssert(vp
->type
== MPR_TYPE_OBJECT
);
261 return adjustRefCount(vp
->properties
, 0);
264 /******************************************************************************/
266 * Update the variable's name
269 void mprSetVarName(MprVar
*vp
, char *name
)
274 vp
->name
= mprStrdup(name
);
277 /******************************************************************************/
279 * Append to the variable's full name
282 void mprSetVarFullName(MprVar
*vp
, char *name
)
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
);
297 /******************************************************************************/
299 * Make a var impervious to recursive forced deletes.
302 void mprSetVarDeleteProtect(MprVar
*vp
, int deleteProtect
)
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
)
320 vp
->readonly
= readonly
;
323 /******************************************************************************/
325 MprVarTrigger
mprAddVarTrigger(MprVar
*vp
, MprVarTrigger fn
)
327 MprVarTrigger oldTrigger
;
332 oldTrigger
= vp
->trigger
;
337 /******************************************************************************/
339 MprType
mprGetVarType(MprVar
*vp
)
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
,
361 mprAssert(propertyName
&& *propertyName
);
363 if (obj
->type
!= MPR_TYPE_OBJECT
) {
364 mprAssert(obj
->type
== MPR_TYPE_OBJECT
);
369 * See if property already exists and locate the bucket to hold the
370 * property reference.
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) {
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
);
395 if ((obj
->trigger
)(MPR_VAR_CREATE_PROPERTY
, obj
->properties
, prop
,
396 newValue
, 0) == MPR_TRIGGER_ABORT
) {
402 * Create a new property
404 prop
= allocProperty(propertyName
);
410 copyVarCore(prop
, newValue
, MPR_SHALLOW_COPY
);
412 prop
->bucketIndex
= bucketIndex
;
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
++;
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
439 MprVar
*mprCreatePropertyValue(MprVar
*obj
, const char *propertyName
,
442 return mprCreateProperty(obj
, propertyName
, &newValue
);
445 /******************************************************************************/
447 * Create a new property
450 static MprVar
*allocProperty(const char *propertyName
)
454 prop
= (MprVar
*) mprMalloc(sizeof(MprVar
));
459 memset(prop
, 0, sizeof(MprVar
));
460 prop
->allocatedVar
= 1;
461 prop
->name
= mprStrdup(propertyName
);
462 prop
->forw
= (MprVar
*) 0;
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
;
479 mprAssert(propertyName
&& *propertyName
);
480 mprAssert(obj
->type
== MPR_TYPE_OBJECT
);
482 if (obj
->type
!= MPR_TYPE_OBJECT
) {
487 prop
= mprGetProperty(obj
, propertyName
, 0);
489 return mprCreateProperty(obj
, propertyName
, newValue
);
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
,
501 if (rc
== MPR_TRIGGER_ABORT
) {
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
);
514 copyVarCore(prop
, newValue
, MPR_SHALLOW_COPY
);
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
,
528 return mprSetProperty(obj
, propertyName
, &newValue
);
531 /******************************************************************************/
533 * Delete a property from this object
536 int mprDeleteProperty(MprVar
*obj
, const char *property
)
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
);
552 bucketIndex
= hash(obj
->properties
, property
);
553 if ((prop
= obj
->properties
->buckets
[bucketIndex
]) != 0) {
554 for ( ; prop
; prop
= prop
->forw
) {
556 if (cp
[0] == property
[0] && strcmp(cp
, property
) == 0) {
562 if (prop
== (MprVar
*) 0) {
564 return MPR_ERR_NOT_FOUND
;
566 if (prop
->readonly
) {
567 mprAssert(! prop
->readonly
);
568 return MPR_ERR_READ_ONLY
;
572 if ((obj
->trigger
)(MPR_VAR_DELETE_PROPERTY
, obj
->properties
, prop
, 0, 0)
573 == MPR_TRIGGER_ABORT
) {
574 return MPR_ERR_ABORTED
;
579 last
->forw
= prop
->forw
;
581 obj
->properties
->buckets
[bucketIndex
] = prop
->forw
;
584 obj
->properties
->numItems
--;
585 if (! mprVarIsFunction(prop
->type
)) {
586 obj
->properties
->numDataItems
--;
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
;
605 if (obj
== 0 || obj
->type
!= MPR_TYPE_OBJECT
|| property
== 0 ||
608 value
->type
= MPR_TYPE_UNDEFINED
;
613 for (prop
= getObjChain(obj
->properties
, property
); prop
;
616 prop
->name
[0] == property
[0] && strcmp(prop
->name
, property
) == 0) {
622 value
->type
= MPR_TYPE_UNDEFINED
;
628 triggerValue
= *prop
;
629 triggerValue
.allocatedVar
= 0;
630 triggerValue
.allocatedData
= 0;
632 * Pass the trigger the current read value and may receive
635 rc
= (prop
->trigger
)(MPR_VAR_READ
, prop
->parentProperties
, prop
,
637 if (rc
== MPR_TRIGGER_ABORT
) {
639 value
->type
= MPR_TYPE_UNDEFINED
;
643 } else if (rc
== MPR_TRIGGER_USE_NEW_VALUE
) {
644 copyVarCore(prop
, &triggerValue
, MPR_SHALLOW_COPY
);
645 mprDestroyVar(&triggerValue
);
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
)
672 triggerValue
= *prop
;
673 triggerValue
.allocatedVar
= 0;
674 triggerValue
.allocatedData
= 0;
675 rc
= (prop
->trigger
)(MPR_VAR_READ
, prop
->parentProperties
, prop
,
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
);
691 * Just so that if the user calls mprDestroyVar on value, it will do no
694 value
->allocatedVar
= 0;
695 value
->allocatedData
= 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
)
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
);
740 mprCopyVar(dest
, prop
, copyDepth
);
744 /******************************************************************************/
746 * Write a new value into an existing property in an object.
749 int mprWriteProperty(MprVar
*vp
, MprVar
*value
)
758 return MPR_ERR_READ_ONLY
;
762 triggerValue
= *value
;
764 rc
= (vp
->trigger
)(MPR_VAR_WRITE
, vp
->parentProperties
, vp
,
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
);
778 copyVarCore(vp
, value
, MPR_SHALLOW_COPY
);
782 /******************************************************************************/
784 * Write a new value into an existing property in an object.
787 int mprWritePropertyValue(MprVar
*vp
, MprVar value
)
791 return mprWriteProperty(vp
, &value
);
794 /******************************************************************************/
796 * Get the count of properties.
799 int mprGetPropertyCount(MprVar
*vp
, int includeFlags
)
803 if (vp
->type
!= MPR_TYPE_OBJECT
) {
806 if (includeFlags
== MPR_ENUM_DATA
) {
807 return vp
->properties
->numDataItems
;
809 return vp
->properties
->numItems
;
813 /******************************************************************************/
815 * Get the first property in an object. Used for walking all properties in an
819 MprVar
*mprGetFirstProperty(MprVar
*obj
, int includeFlags
)
825 mprAssert(obj
->type
== MPR_TYPE_OBJECT
);
827 if (obj
->type
!= MPR_TYPE_OBJECT
) {
828 mprAssert(obj
->type
== MPR_TYPE_OBJECT
);
832 for (i
= 0; i
< (int) obj
->properties
->hashSize
; i
++) {
833 for (prop
= obj
->properties
->buckets
[i
]; prop
; prop
= prop
->forw
) {
835 if (mprVarIsFunction(prop
->type
)) {
836 if (!(includeFlags
& MPR_ENUM_FUNCTIONS
)) {
840 if (!(includeFlags
& MPR_ENUM_DATA
)) {
852 /******************************************************************************/
854 * Get the next property in sequence.
857 MprVar
*mprGetNextProperty(MprVar
*obj
, MprVar
*last
, int includeFlags
)
859 MprProperties
*properties
;
863 mprAssert(obj
->type
== MPR_TYPE_OBJECT
);
865 if (obj
->type
!= MPR_TYPE_OBJECT
) {
866 mprAssert(obj
->type
== MPR_TYPE_OBJECT
);
869 properties
= obj
->properties
;
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
)) {
882 if (!(includeFlags
& MPR_ENUM_DATA
)) {
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
)
909 if ((pp
= (MprProperties
*) mprMalloc(sizeof(MprProperties
))) == NULL
) {
914 memset(pp
, 0, sizeof(MprProperties
));
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
*));
925 if (objectCount
== -1) {
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
;
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
)
953 mprAssert(obj
->refCount
> 0);
959 mprAssert(obj
->refCount
< 20);
962 if (--obj
->refCount
> 0 && !force
) {
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
;
976 for (i
= 0; i
< (int) obj
->hashSize
; i
++) {
977 for (prop
= obj
->buckets
[i
]; prop
; prop
= forw
) {
979 if (prop
->type
== MPR_TYPE_OBJECT
) {
981 if (prop
->properties
== obj
) {
985 pp
= prop
->properties
;
991 if (! freeVar(prop
, pp
->deleteProtect
? 0 : force
)) {
996 freeVar(prop
, force
);
1001 mprFree((void*) obj
->buckets
);
1002 mprFree((void*) obj
);
1007 /******************************************************************************/
1009 * Adjust the reference count
1012 static int adjustRefCount(MprProperties
*pp
, int adj
)
1017 * Debug sanity check
1019 mprAssert(pp
->refCount
< 20);
1021 return pp
->refCount
+= adj
;
1024 /******************************************************************************/
1027 * Print objects held
1030 void mprPrintObjects(char *msg
)
1032 MprProperties
*pp
, *np
;
1033 MprVar
*prop
, *forw
;
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
) {
1045 if (prop
->properties
== pp
) {
1046 /* Self reference */
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
) {
1058 if (prop
->properties
== np
) {
1059 mprLog(7, " %s: OBJECT 0x%x, <%s>\n",
1060 prop
->name
, prop
->properties
, prop
->fullName
);
1062 mprLog(7, " %s: OBJECT NOT FOUND, %s <%s>\n",
1063 prop
->name
, buf
, prop
->fullName
);
1066 mprLog(7, " %s: <%s> = %s\n", prop
->name
,
1067 prop
->fullName
, buf
);
1076 /******************************************************************************/
1078 void mprPrintObjRefCount(MprVar
*vp
)
1080 mprLog(7, "OBJECT 0x%x, refCount %d\n", vp
->properties
,
1081 vp
->properties
->refCount
);
1085 /******************************************************************************/
1087 * Get the bucket chain containing a property.
1090 static MprVar
*getObjChain(MprProperties
*obj
, const char *property
)
1094 return obj
->buckets
[hash(obj
, property
)];
1097 /******************************************************************************/
1099 * Fast hash. The history of this algorithm is part of lost computer science
1103 static int hash(MprProperties
*pp
, const char *property
)
1108 mprAssert(property
);
1112 sum
+= (sum
* 33) + *property
++;
1115 return sum
% pp
->hashSize
;
1118 /******************************************************************************/
1119 /*********************************** Constructors *****************************/
1120 /******************************************************************************/
1122 * Initialize an undefined value.
1125 MprVar
mprCreateUndefinedVar()
1129 memset(&v
, 0x0, sizeof(v
));
1130 v
.type
= MPR_TYPE_UNDEFINED
;
1134 /******************************************************************************/
1136 * Initialize an null value.
1139 MprVar
mprCreateNullVar()
1143 memset(&v
, 0x0, sizeof(v
));
1144 v
.type
= MPR_TYPE_NULL
;
1148 /******************************************************************************/
1150 MprVar
mprCreateBoolVar(bool value
)
1154 memset(&v
, 0x0, sizeof(v
));
1155 v
.type
= MPR_TYPE_BOOL
;
1160 /******************************************************************************/
1162 * Initialize a C function.
1165 MprVar
mprCreateCFunctionVar(MprCFunction fn
, void *thisPtr
, int flags
)
1169 memset(&v
, 0x0, sizeof(v
));
1170 v
.type
= MPR_TYPE_CFUNCTION
;
1171 v
.cFunction
.fn
= fn
;
1172 v
.cFunction
.thisPtr
= thisPtr
;
1178 /******************************************************************************/
1180 * Initialize a C function.
1183 MprVar
mprCreateStringCFunctionVar(MprStringCFunction fn
, void *thisPtr
,
1188 memset(&v
, 0x0, sizeof(v
));
1189 v
.type
= MPR_TYPE_STRING_CFUNCTION
;
1190 v
.cFunctionWithStrings
.fn
= fn
;
1191 v
.cFunctionWithStrings
.thisPtr
= thisPtr
;
1197 /******************************************************************************/
1199 * Initialize an opaque pointer.
1202 MprVar
mprCreatePtrVar(void *ptr
)
1206 memset(&v
, 0x0, sizeof(v
));
1207 v
.type
= MPR_TYPE_PTR
;
1213 /******************************************************************************/
1214 #if BLD_FEATURE_FLOATING_POINT
1216 * Initialize a floating value.
1219 MprVar
mprCreateFloatVar(double value
)
1223 memset(&v
, 0x0, sizeof(v
));
1224 v
.type
= MPR_TYPE_FLOAT
;
1230 /******************************************************************************/
1232 * Initialize an integer value.
1235 MprVar
mprCreateIntegerVar(int value
)
1239 memset(&v
, 0x0, sizeof(v
));
1240 v
.type
= MPR_TYPE_INT
;
1245 /******************************************************************************/
1246 #if BLD_FEATURE_INT64
1248 * Initialize a 64-bit integer value.
1251 MprVar
mprCreateInteger64Var(int64 value
)
1255 memset(&v
, 0x0, sizeof(v
));
1256 v
.type
= MPR_TYPE_INT64
;
1257 v
.integer64
= value
;
1261 #endif /* BLD_FEATURE_INT64 */
1262 /******************************************************************************/
1264 * Initialize an number variable. Type is defined by configure.
1267 MprVar
mprCreateNumberVar(MprNum value
)
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
1283 /******************************************************************************/
1285 * Initialize a (bare) JavaScript function. args and body can be null.
1288 MprVar
mprCreateFunctionVar(char *args
, char *body
, int flags
)
1291 char *cp
, *arg
, *last
;
1294 memset(&v
, 0x0, sizeof(v
));
1295 v
.type
= MPR_TYPE_FUNCTION
;
1298 v
.function
.args
= mprCreateArray();
1301 args
= mprStrdup(args
);
1302 arg
= mprStrTok(args
, ",", &last
);
1304 while (isspace((int) *arg
))
1306 for (cp
= &arg
[strlen(arg
) - 1]; cp
> arg
; cp
--) {
1307 if (!isspace((int) *cp
)) {
1313 aid
= mprAddToArray(v
.function
.args
, mprStrdup(arg
));
1314 arg
= mprStrTok(0, ",", &last
);
1320 v
.function
.body
= mprStrdup(body
);
1322 v
.allocatedData
= 1;
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
)
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
);
1354 /******************************************************************************/
1356 * Initialize a string value.
1359 MprVar
mprCreateStringVar(const char *value
, bool allocate
)
1363 memset(&v
, 0x0, sizeof(v
));
1364 v
.type
= MPR_TYPE_STRING
;
1367 } else if (allocate
) {
1368 v
.string
= mprStrdup(value
);
1369 v
.allocatedData
= 1;
1371 v
.string
= (char*) value
;
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
;
1398 * FUTURE: we should allow read-only triggers where the value is never
1399 * stored in the object. Currently, triggers override the readonly
1403 if (dest
->type
!= MPR_TYPE_UNDEFINED
&& dest
->readonly
&& !dest
->trigger
) {
1408 if (dest
->type
!= MPR_TYPE_UNDEFINED
) {
1409 saveTrigger
= dest
->trigger
;
1410 freeVarStorage(dest
, 0);
1415 switch (src
->type
) {
1417 case MPR_TYPE_UNDEFINED
:
1422 dest
->boolean
= src
->boolean
;
1426 /* we have to reference here so talloc structures survive a
1428 if (src
->allocatedData
) {
1429 dest
->ptr
= talloc_reference(mprMemCtx(), src
->ptr
);
1430 dest
->allocatedData
= 1;
1432 dest
->ptr
= src
->ptr
;
1436 case MPR_TYPE_STRING_CFUNCTION
:
1437 dest
->cFunctionWithStrings
= src
->cFunctionWithStrings
;
1440 case MPR_TYPE_CFUNCTION
:
1441 dest
->cFunction
= src
->cFunction
;
1444 #if BLD_FEATURE_FLOATING_POINT
1445 case MPR_TYPE_FLOAT
:
1446 dest
->floating
= src
->floating
;
1451 dest
->integer
= src
->integer
;
1454 #if BLD_FEATURE_INT64
1455 case MPR_TYPE_INT64
:
1456 dest
->integer64
= src
->integer64
;
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
++) {
1469 for (srcProp
= src
->properties
->buckets
[i
]; srcProp
;
1470 srcProp
= srcProp
->forw
) {
1471 if (srcProp
->visited
) {
1474 destProp
= allocProperty(srcProp
->name
);
1475 if (destProp
== 0) {
1476 mprAssert(destProp
);
1480 destProp
->bucketIndex
= i
;
1482 last
->forw
= destProp
;
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;
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;
1507 dest
->properties
= src
->properties
;
1508 dest
->allocatedData
= 0;
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
++) {
1518 mprAddToArray(dest
->function
.args
, mprStrdup(srcArgs
[i
]));
1521 dest
->function
.body
= mprStrdup(src
->function
.body
);
1522 dest
->allocatedData
= 1;
1524 dest
->function
.args
= src
->function
.args
;
1525 dest
->function
.body
= src
->function
.body
;
1526 dest
->allocatedData
= 0;
1530 case MPR_TYPE_STRING
:
1531 if (src
->string
&& copyDepth
!= MPR_NO_COPY
) {
1532 dest
->string
= mprStrdup(src
->string
);
1533 dest
->allocatedData
= 1;
1535 dest
->string
= src
->string
;
1536 dest
->allocatedData
= 0;
1541 dest
->type
= src
->type
;
1542 dest
->flags
= src
->flags
;
1543 dest
->trigger
= saveTrigger
;
1551 /******************************************************************************/
1553 * Copy an entire object including name.
1556 void mprCopyVar(MprVar
*dest
, MprVar
*src
, int copyDepth
)
1561 copyVarCore(dest
, src
, copyDepth
);
1563 mprFree(dest
->name
);
1564 dest
->name
= mprStrdup(src
->name
);
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
);
1579 /******************************************************************************/
1581 * Copy an entire object including name.
1584 void mprCopyVarValue(MprVar
*dest
, MprVar src
, int copyDepth
)
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
)
1603 dest
= (MprVar
*) mprMalloc(sizeof(MprVar
));
1604 memset(dest
, 0, sizeof(MprVar
));
1606 mprCopyVar(dest
, src
, copyDepth
);
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
)
1626 mprReadProperty(obj
, 0);
1629 switch (obj
->type
) {
1630 case MPR_TYPE_UNDEFINED
:
1631 /* FUTURE -- spec says convert to "undefined" */
1632 *out
= mprStrdup("");
1636 *out
= mprStrdup("null");
1640 mprAllocSprintf(out
, size
, "[Opaque Pointer %p]", obj
->ptr
);
1645 *out
= mprStrdup("true");
1647 *out
= mprStrdup("false");
1651 #if BLD_FEATURE_FLOATING_POINT
1652 case MPR_TYPE_FLOAT
:
1653 if (fmt
== NULL
|| *fmt
== '\0') {
1654 mprAllocSprintf(out
, size
, "%f", obj
->floating
);
1656 mprAllocSprintf(out
, size
, fmt
, obj
->floating
);
1662 if (fmt
== NULL
|| *fmt
== '\0') {
1663 mprAllocSprintf(out
, size
, "%d", obj
->integer
);
1665 mprAllocSprintf(out
, size
, fmt
, obj
->integer
);
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
);
1675 mprAllocSprintf(out
, size
, "%lld", (long long)obj
->integer64
);
1678 mprAllocSprintf(out
, size
, fmt
, obj
->integer64
);
1683 case MPR_TYPE_CFUNCTION
:
1684 mprAllocSprintf(out
, size
, "[C Function]");
1687 case MPR_TYPE_STRING_CFUNCTION
:
1688 mprAllocSprintf(out
, size
, "[C StringFunction]");
1691 case MPR_TYPE_FUNCTION
:
1692 mprAllocSprintf(out
, size
, "[JavaScript Function]");
1695 case MPR_TYPE_OBJECT
:
1696 /* FUTURE -- really want: [object class: name] */
1697 mprAllocSprintf(out
, size
, "[object %s]", obj
->name
);
1700 case MPR_TYPE_STRING
:
1705 mprAllocSprintf(out
, size
, fmt
, src
);
1707 } else if (src
== NULL
) {
1708 *out
= mprStrdup("null");
1711 *out
= mprStrdup(src
);
1720 /******************************************************************************/
1722 * Parse a string based on formatting instructions and intelligently
1723 * create a variable.
1726 MprVar
mprParseVar(char *buf
, MprType preferredType
)
1733 type
= preferredType
;
1735 if (preferredType
== MPR_TYPE_UNDEFINED
) {
1739 } else if (!isdigit((int) *buf
)) {
1740 if (strcmp(buf
, "true") == 0 || strcmp(buf
, "false") == 0) {
1741 type
= MPR_TYPE_BOOL
;
1743 type
= MPR_TYPE_STRING
;
1746 } else if (isdigit((int) *buf
)) {
1749 if (*cp
&& tolower(cp
[1]) == 'x') {
1752 for (cp
= buf
; *cp
; cp
++) {
1753 if (! isdigit((int) *cp
)) {
1759 #if BLD_FEATURE_FLOATING_POINT
1760 if (*cp
== '.' || tolower(*cp
) == 'e') {
1761 type
= MPR_TYPE_FLOAT
;
1772 case MPR_TYPE_OBJECT
:
1773 case MPR_TYPE_UNDEFINED
:
1780 return mprCreateBoolVar(buf
[0] == 't' ? 1 : 0);
1783 return mprCreateIntegerVar(mprParseInteger(buf
));
1785 #if BLD_FEATURE_INT64
1786 case MPR_TYPE_INT64
:
1787 return mprCreateInteger64Var(mprParseInteger64(buf
));
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
));
1805 return mprCreateUndefinedVar();
1808 /******************************************************************************/
1810 * Convert the variable to a boolean. Only for primitive types.
1813 bool mprVarToBool(const MprVar
*vp
)
1818 case MPR_TYPE_UNDEFINED
:
1820 case MPR_TYPE_STRING_CFUNCTION
:
1821 case MPR_TYPE_CFUNCTION
:
1822 case MPR_TYPE_FUNCTION
:
1823 case MPR_TYPE_OBJECT
:
1827 return (vp
->ptr
!= NULL
);
1832 #if BLD_FEATURE_FLOATING_POINT
1833 case MPR_TYPE_FLOAT
:
1834 return (vp
->floating
!= 0 && !mprIsNan(vp
->floating
));
1838 return (vp
->integer
!= 0);
1840 #if BLD_FEATURE_INT64
1841 case MPR_TYPE_INT64
:
1842 return (vp
->integer64
!= 0);
1845 case MPR_TYPE_STRING
:
1846 mprAssert(vp
->string
);
1847 return (vp
->string
[0] != '\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
)
1865 case MPR_TYPE_UNDEFINED
:
1867 case MPR_TYPE_STRING_CFUNCTION
:
1868 case MPR_TYPE_CFUNCTION
:
1869 case MPR_TYPE_FUNCTION
:
1870 case MPR_TYPE_OBJECT
:
1875 return (vp
->boolean
) ? 1.0 : 0.0;
1877 case MPR_TYPE_FLOAT
:
1878 return vp
->floating
;
1881 return (double) vp
->integer
;
1883 #if BLD_FEATURE_INT64
1884 case MPR_TYPE_INT64
:
1885 return (double) vp
->integer64
;
1888 case MPR_TYPE_STRING
:
1889 mprAssert(vp
->string
);
1890 return atof(vp
->string
);
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
);
1910 return mprVarToInteger(vp
);
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
);
1926 return mprParseInteger(s
);
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
)
1941 case MPR_TYPE_UNDEFINED
:
1943 case MPR_TYPE_STRING_CFUNCTION
:
1944 case MPR_TYPE_CFUNCTION
:
1945 case MPR_TYPE_FUNCTION
:
1946 case MPR_TYPE_OBJECT
:
1951 return (vp
->boolean
) ? 1 : 0;
1953 #if BLD_FEATURE_FLOATING_POINT
1954 case MPR_TYPE_FLOAT
:
1955 if (mprIsNan(vp
->floating
)) {
1958 return (int64
) vp
->floating
;
1964 case MPR_TYPE_INT64
:
1965 return vp
->integer64
;
1967 case MPR_TYPE_STRING
:
1968 return mprParseInteger64(vp
->string
);
1975 /******************************************************************************/
1977 * Convert the string buffer to an Integer64.
1980 int64
mprParseInteger64(char *str
)
1984 int radix
, c
, negative
;
1998 * Parse a number. Observe hex and octal prefixes (0x, 0)
2002 * Normal numbers (Radix 10)
2004 while (isdigit((int) *cp
)) {
2005 num64
= (*cp
- '0') + (num64
* 10);
2010 if (tolower(*cp
) == 'x') {
2016 num64
= (c
- '0') + (num64
* radix
);
2017 } else if (c
>= 'a' && c
<= 'f') {
2018 num64
= (c
- ('a' - 10)) + (num64
* radix
);
2029 if (isdigit(c
) && c
< '8') {
2030 num64
= (c
- '0') + (num64
* radix
);
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
)
2056 case MPR_TYPE_UNDEFINED
:
2058 case MPR_TYPE_STRING_CFUNCTION
:
2059 case MPR_TYPE_CFUNCTION
:
2060 case MPR_TYPE_FUNCTION
:
2061 case MPR_TYPE_OBJECT
:
2066 return (vp
->boolean
) ? 1 : 0;
2068 #if BLD_FEATURE_FLOATING_POINT
2069 case MPR_TYPE_FLOAT
:
2070 if (mprIsNan(vp
->floating
)) {
2073 return (int) vp
->floating
;
2079 #if BLD_FEATURE_INT64
2080 case MPR_TYPE_INT64
:
2081 return (int) vp
->integer64
;
2084 case MPR_TYPE_STRING
:
2085 return mprParseInteger(vp
->string
);
2092 /******************************************************************************/
2094 * Convert the string buffer to an Integer.
2097 int mprParseInteger(char *str
)
2101 int radix
, c
, negative
;
2115 * Parse a number. Observe hex and octal prefixes (0x, 0)
2119 * Normal numbers (Radix 10)
2121 while (isdigit((int) *cp
)) {
2122 num
= (*cp
- '0') + (num
* 10);
2127 if (tolower(*cp
) == 'x') {
2133 num
= (c
- '0') + (num
* radix
);
2134 } else if (c
>= 'a' && c
<= 'f') {
2135 num
= (c
- ('a' - 10)) + (num
* radix
);
2146 if (isdigit(c
) && c
< '8') {
2147 num
= (c
- '0') + (num
* radix
);
2162 /******************************************************************************/
2163 #if BLD_FEATURE_FLOATING_POINT
2165 * Convert the string buffer to an Floating.
2168 double mprParseFloat(char *str
)
2173 /******************************************************************************/
2175 bool mprIsNan(double f
)
2182 #elif defined(FP_NAN)
2183 return (f
== FP_NAN
);
2188 /******************************************************************************/
2190 bool mprIsInfinite(double f
)
2197 #elif defined(FP_INFINITE)
2198 return (f
== FP_INFINITE
);
2204 #endif /* BLD_FEATURE_FLOATING_POINT */
2205 /******************************************************************************/
2213 * vim600: sw=4 ts=4 fdm=marker
2214 * vim<600: sw=4 ts=4