summaryrefslogtreecommitdiff
path: root/source4/lib/appweb/mpr
diff options
context:
space:
mode:
authorAndrew Tridgell <tridge@samba.org>2005-07-13 00:12:22 +0000
committerGerald (Jerry) Carter <jerry@samba.org>2007-10-10 13:22:57 -0500
commita102f52db89f8a31327a3a9fafa1e5a1699ca3cd (patch)
treea2fe9e3dc32ea021264bfd38a3be2403c7ea2879 /source4/lib/appweb/mpr
parentadbb1612c12d03fa94e4ee23fbc2fa96c09d9dcd (diff)
downloadsamba-a102f52db89f8a31327a3a9fafa1e5a1699ca3cd.tar.gz
samba-a102f52db89f8a31327a3a9fafa1e5a1699ca3cd.tar.bz2
samba-a102f52db89f8a31327a3a9fafa1e5a1699ca3cd.zip
r8400: separate out the mpr code, as it is in the upstream appweb sources
(This used to be commit 0e30b6e4cc9e70975d3179cfeddc4bfcc8c8fbb7)
Diffstat (limited to 'source4/lib/appweb/mpr')
-rw-r--r--source4/lib/appweb/mpr/miniMpr.c512
-rw-r--r--source4/lib/appweb/mpr/miniMpr.h292
-rw-r--r--source4/lib/appweb/mpr/var.c2197
-rw-r--r--source4/lib/appweb/mpr/var.h496
4 files changed, 3497 insertions, 0 deletions
diff --git a/source4/lib/appweb/mpr/miniMpr.c b/source4/lib/appweb/mpr/miniMpr.c
new file mode 100644
index 0000000000..abeefe1ec8
--- /dev/null
+++ b/source4/lib/appweb/mpr/miniMpr.c
@@ -0,0 +1,512 @@
+/*
+ * @file miniMpr.cpp
+ * @brief Mini Mbedthis Portable Runtime (MPR)
+ * @copy default
+ *
+ * Copyright (c) Mbedthis Software LLC, 2003-2005. All Rights Reserved.
+ *
+ * This software is distributed under commercial and open source licenses.
+ * You may use the GPL open source license described below or you may acquire
+ * a commercial license from Mbedthis Software. You agree to be fully bound
+ * by the terms of either license. Consult the LICENSE.TXT distributed with
+ * this software for full details.
+ *
+ * This software is open source; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See the GNU General Public License for more
+ * details at: http://www.mbedthis.com/downloads/gplLicense.html
+ *
+ * This program is distributed WITHOUT ANY WARRANTY; without even the
+ * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * This GPL license does NOT permit incorporating this software into
+ * proprietary programs. If you are unable to comply with the GPL, you must
+ * acquire a commercial license to use this software. Commercial licenses
+ * for this software and support services are available from Mbedthis
+ * Software at http://www.mbedthis.com
+ *
+ * @end
+ */
+
+#include "miniMpr.h"
+
+/************************************ Code ************************************/
+#if !BLD_APPWEB
+#if !BLD_GOAHEAD_WEBSERVER
+
+static void *mpr_ctx;
+
+/* set the memory context to be used for all ejs variables */
+void mprSetCtx(TALLOC_CTX *ctx)
+{
+ mpr_ctx = ctx;
+}
+
+/* return the memory context being used for all ejs variables */
+void *mprMemCtx(void)
+{
+ return mpr_ctx;
+}
+
+void mprFree(void *ptr)
+{
+ talloc_free(ptr);
+}
+
+void *mprMalloc(uint size)
+{
+ return talloc_size(mpr_ctx, size);
+}
+
+/******************************************************************************/
+
+void *mprRealloc(void *ptr, uint size)
+{
+ return talloc_realloc_size(mpr_ctx, ptr, size);
+}
+
+/******************************************************************************/
+
+char *mprStrdup(const char *str)
+{
+ if (str == 0) {
+ str = "";
+ }
+ return talloc_strdup(mpr_ctx, str);
+}
+
+/*****************************************************************************/
+
+int mprAllocSprintf(char **msgbuf, int maxSize, const char *fmt, ...)
+{
+ va_list args;
+ char *buf;
+ int count;
+
+ va_start(args, fmt);
+ buf = mprMalloc(maxSize + 1);
+ count = mtVsprintf(buf, maxSize, fmt, args);
+ *msgbuf = buf;
+ va_end(args);
+ return count;
+}
+
+/*****************************************************************************/
+
+int mprAllocVsprintf(char **msgbuf, int maxSize, const char *fmt, va_list args)
+{
+ char *buf;
+ int count;
+
+ buf = mprMalloc(maxSize + 1);
+ count = mtVsprintf(buf, maxSize, fmt, args);
+ *msgbuf = buf;
+ return count;
+}
+
+
+/*****************************************************************************/
+/*
+ * Format a number as a string. FUTURE -- reverse args to be standard.
+ * ie. mprItoa(char *userBuf, int bufsize, int value);
+ */
+
+char *mprItoa(int value, char *buf, int width)
+{
+ char numBuf[16];
+ char *cp, *dp, *endp;
+ int negative;
+
+ cp = &numBuf[sizeof(numBuf)];
+ *--cp = '\0';
+
+ if (value < 0) {
+ negative = 1;
+ value = -value;
+ width--;
+ } else {
+ negative = 0;
+ }
+
+ do {
+ *--cp = '0' + (value % 10);
+ value /= 10;
+ } while (value > 0);
+
+ if (negative) {
+ *--cp = '-';
+ }
+
+ dp = buf;
+ endp = &buf[width];
+ while (dp < endp && *cp) {
+ *dp++ = *cp++;
+ }
+ *dp++ = '\0';
+ return buf;
+}
+
+/*****************************************************************************/
+
+void mprLog(int level, const char *fmt, ...)
+{
+ va_list args;
+ char *buf;
+
+ if (DEBUGLVL(level)) {
+ va_start(args, fmt);
+ mprAllocVsprintf(&buf, MPR_MAX_STRING, fmt, args);
+ va_end(args);
+ DEBUG(level, ("mprLog: %s", buf));
+ mprFree(buf);
+ }
+}
+
+/*****************************************************************************/
+
+void mprBreakpoint(const char *file, int line, const char *cond)
+{
+ char *buf;
+ mprAllocSprintf(&buf, MPR_MAX_STRING, "esp exception - ASSERT at %s:%d, %s\n",
+ file, line, cond);
+ ejs_exception(buf);
+}
+
+#endif /* !BLD_GOAHEAD_WEBSERVER */
+/*****************************************************************************/
+/*
+ * Create a general growable array structure
+ */
+
+MprArray *mprCreateArray()
+{
+ MprArray *array;
+ int size;
+
+ array = (MprArray*) mprMalloc(sizeof(MprArray));
+ if (array == 0) {
+ return 0;
+ }
+ memset(array, 0, sizeof(MprArray));
+
+ size = MPR_ARRAY_INCR * sizeof(void*);
+ array->handles = (void**) mprMalloc(size);
+ if (array->handles == 0) {
+ mprFree(array);
+ return 0;
+ }
+ memset(array->handles, 0, size);
+ array->max = MPR_ARRAY_INCR;
+ array->used = 0;
+ return array;
+}
+
+/*****************************************************************************/
+/*
+ * Dispose of the array. Callers responsibility to dispose of handle entries.
+ */
+
+void mprDestroyArray(MprArray *array)
+{
+ mprAssert(array);
+ mprAssert(array->max >= 0);
+ mprAssert(array->used >= 0);
+
+ mprFree(array->handles);
+ mprFree(array);
+}
+
+/*****************************************************************************/
+/*
+ * Add an item to the array
+ */
+
+int mprAddToArray(MprArray *array, void *item)
+{
+ int memsize, idx, len;
+
+ mprAssert(array);
+ mprAssert(array->max >= 0);
+ mprAssert(array->used >= 0);
+
+ if (array->used < array->max) {
+ idx = array->used++;
+ mprAssert(idx >= 0 && idx < array->max);
+ mprAssert(array->handles[idx] == 0);
+ array->handles[idx] = item;
+ return idx;
+ }
+
+ for (idx = array->used; idx < array->max; idx++) {
+ if (array->handles[idx] == 0) {
+ array->used++;
+ mprAssert(array->handles[idx] == 0);
+ array->handles[idx] = item;
+ return idx;
+ }
+ }
+
+ len = array->max + MPR_ARRAY_INCR;
+ memsize = len * sizeof(void*);
+ array->handles = (void**) mprRealloc((void*) array->handles, memsize);
+ if (array->handles == NULL) {
+ return -1;
+ }
+ memset(&array->handles[array->max], 0, sizeof(void*) * MPR_ARRAY_INCR);
+ array->max = len;
+ array->used++;
+
+ mprAssert(idx >= 0 && idx < array->max);
+ mprAssert(array->handles[idx] == 0);
+
+ array->handles[idx] = item;
+ return idx;
+}
+
+/*****************************************************************************/
+/*
+ * Remove from the array
+ */
+
+int mprRemoveFromArray(MprArray *array, int idx)
+{
+ mprAssert(array);
+ mprAssert(array->max > 0);
+ mprAssert(idx >= 0 && idx < array->max);
+ mprAssert(array->handles[idx] != 0);
+ mprAssert(array->used > 0);
+
+ array->handles[idx] = 0;
+ return --array->used;
+}
+
+/*****************************************************************************/
+/*
+ * Thread-safe wrapping of strtok. Note "str" is modifed as per strtok()
+ */
+
+char *mprStrTok(char *str, const char *delim, char **tok)
+{
+ char *start, *end;
+ int i;
+
+ start = str ? str : *tok;
+
+ if (start == 0) {
+ return 0;
+ }
+
+ i = strspn(start, delim);
+ start += i;
+ if (*start == '\0') {
+ *tok = 0;
+ return 0;
+ }
+ end = strpbrk(start, delim);
+ if (end) {
+ *end++ = '\0';
+ i = strspn(end, delim);
+ end += i;
+ }
+ *tok = end;
+ return start;
+}
+
+/*****************************************************************************/
+
+static int mprCoreStrcat(int alloc, char **destp, int destMax, int existingLen,
+ const char *delim, const char *src, va_list args)
+{
+ va_list ap;
+ char *dest, *dp;
+ const char *str;
+ int sepLen, addBytes, required;
+
+ mprAssert(destp);
+ mprAssert(destMax > 0);
+ mprAssert(src);
+
+ dest = *destp;
+ sepLen = (delim) ? strlen(delim) : 0;
+
+#ifdef __va_copy
+ __va_copy(ap, args);
+#else
+ ap = args;
+#endif
+ addBytes = 0;
+ str = src;
+ while (str) {
+ addBytes += strlen(str) + sepLen;
+ str = va_arg(ap, const char*);
+ }
+
+ if (existingLen > 0) {
+ addBytes += sepLen;
+ }
+ required = existingLen + addBytes + 1;
+ if (required >= destMax) {
+ mprAssert(0);
+ return MPR_ERR_WONT_FIT;
+ }
+
+ if (alloc) {
+ if (dest == 0) {
+ dest = (char*) mprMalloc(required);
+ } else {
+ dest = (char*) mprRealloc(dest, required);
+ }
+ } else {
+ dest = (char*) *destp;
+ }
+
+ dp = &dest[existingLen];
+ if (delim) {
+ strcpy(dp, delim);
+ dp += sepLen;
+ }
+
+ if (addBytes > 0) {
+#ifdef __va_copy
+ __va_copy(ap, args);
+#else
+ ap = args;
+#endif
+ str = src;
+ while (str) {
+ strcpy(dp, str);
+ dp += strlen(str);
+ str = va_arg(ap, char*);
+ if (delim && str) {
+ strcpy(dp, delim);
+ dp += sepLen;
+ }
+ }
+ } else if (dest == 0) {
+ dest = (char*) mprMalloc(1);
+ }
+ *dp = '\0';
+
+ *destp = dest;
+ mprAssert(dp < &dest[required]);
+ return required - 1;
+}
+
+/*****************************************************************************/
+
+int mprReallocStrcat(char **destp, int destMax, int existingLen,
+ const char *delim, const char *src,...)
+{
+ va_list ap;
+ int rc;
+
+ va_start(ap, src);
+ rc = mprCoreStrcat(1, destp, destMax, existingLen, delim, src, ap);
+ va_end(ap);
+ return rc;
+}
+
+/*****************************************************************************/
+/*
+ * Return the directory portion of a pathname into the users buffer.
+ */
+
+int mprGetDirName(char *buf, int bufsize, char *path)
+{
+ char *cp;
+ int dlen;
+
+ mprAssert(path);
+ mprAssert(buf);
+ mprAssert(bufsize > 0);
+
+ cp = strrchr(path, '/');
+ if (cp == 0) {
+#if WIN
+ cp = strrchr(path, '\\');
+ if (cp == 0)
+#endif
+ {
+ buf[0] = '\0';
+ return 0;
+ }
+ }
+
+ if (cp == path && cp[1] == '\0') {
+ strcpy(buf, ".");
+ return 0;
+ }
+
+ dlen = cp - path;
+ if (dlen < bufsize) {
+ if (dlen == 0) {
+ dlen++;
+ }
+ mprMemcpy(buf, bufsize, path, dlen);
+ buf[dlen] = '\0';
+ return 0;
+ }
+ return MPR_ERR_WONT_FIT;
+}
+
+/*****************************************************************************/
+
+int mprStrcpy(char *dest, int destMax, const char *src)
+{
+ int len;
+
+ mprAssert(dest);
+ mprAssert(destMax > 0);
+ mprAssert(src);
+
+ len = strlen(src);
+ if (len >= destMax && len > 0) {
+ mprAssert(0);
+ return MPR_ERR_WONT_FIT;
+ }
+ if (len > 0) {
+ memcpy(dest, src, len);
+ dest[len] = '\0';
+ } else {
+ *dest = '\0';
+ len = 0;
+ }
+ return len;
+}
+
+/*****************************************************************************/
+
+int mprMemcpy(char *dest, int destMax, const char *src, int nbytes)
+{
+ mprAssert(dest);
+ mprAssert(destMax > nbytes);
+ mprAssert(src);
+ mprAssert(nbytes > 0);
+
+ if (nbytes > destMax) {
+ mprAssert(0);
+ return MPR_ERR_WONT_FIT;
+ }
+ if (nbytes > 0) {
+ memcpy(dest, src, nbytes);
+ return nbytes;
+ } else {
+ return 0;
+ }
+}
+
+/*****************************************************************************/
+#else
+void miniMprDummy() {}
+#endif // !BLD_APPWEB && !BLD_GOAHEAD_WEBSERVER
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim:tw=78
+ * vim600: sw=4 ts=4 fdm=marker
+ * vim<600: sw=4 ts=4
+ */
diff --git a/source4/lib/appweb/mpr/miniMpr.h b/source4/lib/appweb/mpr/miniMpr.h
new file mode 100644
index 0000000000..a0030b25b5
--- /dev/null
+++ b/source4/lib/appweb/mpr/miniMpr.h
@@ -0,0 +1,292 @@
+/*
+ * @file miniMpr.h
+ * @brief Mini Mbedthis Portable Runtime (MPR) Environment.
+ * @copy default
+ *
+ * Copyright (c) Mbedthis Software LLC, 2003-2005. All Rights Reserved.
+ *
+ * This software is distributed under commercial and open source licenses.
+ * You may use the GPL open source license described below or you may acquire
+ * a commercial license from Mbedthis Software. You agree to be fully bound
+ * by the terms of either license. Consult the LICENSE.TXT distributed with
+ * this software for full details.
+ *
+ * This software is open source; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See the GNU General Public License for more
+ * details at: http://www.mbedthis.com/downloads/gplLicense.html
+ *
+ * This program is distributed WITHOUT ANY WARRANTY; without even the
+ * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * This GPL license does NOT permit incorporating this software into
+ * proprietary programs. If you are unable to comply with the GPL, you must
+ * acquire a commercial license to use this software. Commercial licenses
+ * for this software and support services are available from Mbedthis
+ * Software at http://www.mbedthis.com
+ *
+ * @end
+ */
+#ifndef _h_MINI_MPR
+#define _h_MINI_MPR 1
+
+/********************************** Includes **********************************/
+/*
+ * Find out about our configuration
+ */
+#ifndef _INCLUDES_H
+ #include "includes.h"
+#endif
+
+/* allow this library to use strcpy() */
+#undef strcpy
+ #include "lib/appweb/ejs/config.h"
+
+#if BLD_APPWEB
+ /*
+ * If building within AppWeb, use the full MPR
+ */
+ #include "mpr.h"
+#else
+
+ #include <ctype.h>
+ #include <fcntl.h>
+ #include <stdarg.h>
+ #include <stdlib.h>
+ #include <stdio.h>
+ #include <string.h>
+ #include <sys/stat.h>
+
+#if !WIN
+ #include <unistd.h>
+#endif
+
+#if CE
+ #include <io.h>
+ #include "CE/wincompat.h"
+#endif
+
+#if LYNX
+ #include <unistd.h>
+#endif
+
+#if QNX4
+ #include <dirent.h>
+#endif
+ #include <math.h>
+
+/********************************** Defines ***********************************/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if BLD_FEATURE_SQUEEZE
+/*
+ * Reasonable length of a file path name to use in most cases where you know
+ * the expected file name and it is certain to be less than this limit.
+ */
+#define MPR_MAX_FNAME 128
+#define MPR_MAX_STRING 512
+#define MPR_DEFAULT_HASH_SIZE 23 /* Default size of hash table index */
+#define MPR_MAX_HEAP_SIZE (32 * 1024)
+#else
+#define MPR_MAX_FNAME 256
+#define MPR_MAX_STRING 4096
+#define MPR_DEFAULT_HASH_SIZE 43 /* Default size of hash table index */
+#define MPR_MAX_HEAP_SIZE (64 * 1024)
+#endif
+
+/*
+ * Useful for debugging
+ */
+#define MPR_L __FILE__, __LINE__
+
+#if BLD_FEATURE_ASSERT
+#define mprAssert(C) \
+ if (C) ; else mprBreakpoint(__FILE__, __LINE__, #C)
+#else
+ #define mprAssert(C) if (1) ; else
+#endif
+
+/*
+ * Standard MPR return and error codes
+ */
+#define MPR_ERR_BASE (-200) /* Error code */
+#define MPR_ERR_GENERAL (MPR_ERR_BASE - 1) /* Error code */
+#define MPR_ERR_ABORTED (MPR_ERR_BASE - 2) /* Error code */
+#define MPR_ERR_ALREADY_EXISTS (MPR_ERR_BASE - 3) /* Error code */
+#define MPR_ERR_BAD_ARGS (MPR_ERR_BASE - 4) /* Error code */
+#define MPR_ERR_BAD_FORMAT (MPR_ERR_BASE - 5) /* Error code */
+#define MPR_ERR_BAD_HANDLE (MPR_ERR_BASE - 6) /* Error code */
+#define MPR_ERR_BAD_STATE (MPR_ERR_BASE - 7) /* Error code */
+#define MPR_ERR_BAD_SYNTAX (MPR_ERR_BASE - 8) /* Error code */
+#define MPR_ERR_BAD_TYPE (MPR_ERR_BASE - 9) /* Error code */
+#define MPR_ERR_BAD_VALUE (MPR_ERR_BASE - 10) /* Error code */
+#define MPR_ERR_BUSY (MPR_ERR_BASE - 11) /* Error code */
+#define MPR_ERR_CANT_ACCESS (MPR_ERR_BASE - 12) /* Error code */
+#define MPR_ERR_CANT_COMPLETE (MPR_ERR_BASE - 13) /* Error code */
+#define MPR_ERR_CANT_CREATE (MPR_ERR_BASE - 14) /* Error code */
+#define MPR_ERR_CANT_INITIALIZE (MPR_ERR_BASE - 15) /* Error code */
+#define MPR_ERR_CANT_OPEN (MPR_ERR_BASE - 16) /* Error code */
+#define MPR_ERR_CANT_READ (MPR_ERR_BASE - 17) /* Error code */
+#define MPR_ERR_CANT_WRITE (MPR_ERR_BASE - 18) /* Error code */
+#define MPR_ERR_DELETED (MPR_ERR_BASE - 19) /* Error code */
+#define MPR_ERR_NETWORK (MPR_ERR_BASE - 20) /* Error code */
+#define MPR_ERR_NOT_FOUND (MPR_ERR_BASE - 21) /* Error code */
+#define MPR_ERR_NOT_INITIALIZED (MPR_ERR_BASE - 22) /* Error code */
+#define MPR_ERR_NOT_READY (MPR_ERR_BASE - 23) /* Error code */
+#define MPR_ERR_READ_ONLY (MPR_ERR_BASE - 24) /* Error code */
+#define MPR_ERR_TIMEOUT (MPR_ERR_BASE - 25) /* Error code */
+#define MPR_ERR_TOO_MANY (MPR_ERR_BASE - 26) /* Error code */
+#define MPR_ERR_WONT_FIT (MPR_ERR_BASE - 27) /* Error code */
+#define MPR_ERR_WOULD_BLOCK (MPR_ERR_BASE - 28) /* Error code */
+#define MPR_ERR_CANT_ALLOCATE (MPR_ERR_BASE - 29) /* Error code */
+#define MPR_ERR_MAX (MPR_ERR_BASE - 30) /* Error code */
+
+/*
+ * Standard error severity and trace levels. These are ored with the error
+ * severities below. The MPR_LOG_MASK is used to extract the trace level
+ * from a flags word. We expect most apps to run with level 2 trace.
+ */
+#define MPR_FATAL 0 /* Fatal error. Cant continue. */
+#define MPR_ERROR 1 /* Hard error */
+#define MPR_WARN 2 /* Soft warning */
+#define MPR_CONFIG 2 /* Essential configuration settings */
+#define MPR_INFO 3 /* Informational only */
+#define MPR_DEBUG 4 /* Debug information */
+#define MPR_VERBOSE 9 /* Highest level of trace */
+#define MPR_LOG_MASK 0xf /* Level mask */
+
+/*
+ * Error flags. Specify where the error should be sent to. Note that the
+ * product.xml setting "headless" will modify how errors are reported.
+ * Assert errors are trapped when in DEV mode. Otherwise ignored.
+ */
+#define MPR_TRAP 0x10 /* Assert error -- trap in debugger */
+#define MPR_LOG 0x20 /* Log the error in the O/S event log */
+#define MPR_USER 0x40 /* Display to the user */
+#define MPR_ALERT 0x80 /* Send a management alert */
+#define MPR_TRACE 0x100 /* Trace */
+
+/*
+ * Error format flags
+ */
+#define MPR_RAW 0x200 /* Raw trace output */
+
+/*
+ * Error line number information
+ */
+#define MPR_L __FILE__, __LINE__
+
+typedef char* MprStr;
+
+#ifndef __cplusplus
+typedef unsigned char uchar;
+typedef int bool;
+#endif
+
+/*
+ * Porters: put other operating system type defines here
+ */
+#if WIN
+ typedef unsigned int uint;
+ typedef __int64 int64;
+ typedef unsigned __int64 uint64;
+#else
+#define O_BINARY 0
+#ifndef uint
+ #define uint unsigned
+#endif
+ __extension__ typedef long long int int64;
+ __extension__ typedef unsigned long long int uint64;
+#endif
+
+/*
+ * Flexible array data type
+ */
+typedef struct {
+ int max; /* Size of the handles array */
+ int used; /* Count of used entries in handles */
+ void **handles;
+} MprArray;
+
+#if BLD_FEATURE_SQUEEZE
+#define MPR_ARRAY_INCR 8
+#else
+#define MPR_ARRAY_INCR 16
+#endif
+
+#ifndef max
+#define max(a,b) (((a) > (b)) ? (a) : (b))
+#endif
+
+/********************************* Prototypes *********************************/
+/*
+ * If running in the GoAhead WebServer, map some MPR routines to WebServer
+ * equivalents.
+ */
+
+#if BLD_GOAHEAD_WEBSERVER
+#include "uemf.h"
+#define mprMalloc(size) balloc(B_L, size)
+#define mprFree(ptr) bfreeSafe(B_L, ptr)
+#define mprRealloc(ptr, size) brealloc(B_L, ptr, size)
+#define mprStrdup(ptr) bstrdup(B_L, ptr)
+#define mprAllocSprintf fmtAlloc
+#define mprAllocVsprintf fmtValloc
+#define mprSprintf fmtStatic
+#define mprItoa stritoa
+#define mprLog trace
+#define mprBreakpoint(file, line, cond) \
+ error(file, line, E_BLD_FEATURE_ASSERT, T("%s"), cond)
+
+#else /* !BLD_GOAHEAD_WEBSERVER */
+/* #define mprMalloc malloc */
+#define mprSprintf snprintf
+#define mtVsprintf vsnprintf
+extern void *mprMalloc(uint size);
+extern void *mprRealloc(void *ptr, uint size);
+extern void mprFree(void *ptr);
+extern char *mprStrdup(const char *str);
+extern int mprAllocVsprintf(char **msgbuf, int maxSize, const char *fmt,
+ va_list args) PRINTF_ATTRIBUTE(3,0);
+extern int mprAllocSprintf(char **msgbuf, int maxSize, const char *fmt, ...) PRINTF_ATTRIBUTE(3,4);
+extern char *mprItoa(int num, char *buf, int width);
+extern void mprLog(int level, const char *fmt, ...) PRINTF_ATTRIBUTE(2,3);
+extern void mprBreakpoint(const char *file, int line, const char *msg);
+#endif /* BLD_GOAHEAD_WEBSERVER */
+
+extern MprArray *mprCreateArray(void);
+extern void mprDestroyArray(MprArray *array);
+extern int mprAddToArray(MprArray *array, void *item);
+extern int mprRemoveFromArray(MprArray *array, int idx);
+extern char *mprStrTok(char *str, const char *delim, char **tok);
+
+extern int mprGetDirName(char *buf, int bufsize, char *path);
+extern int mprReallocStrcat(char **dest, int max, int existingLen,
+ const char *delim, const char *src, ...);
+extern int mprStrcpy(char *dest, int destMax, const char *src);
+extern int mprMemcpy(char *dest, int destMax, const char *src, int nbytes);
+
+extern void mprSetCtx(void *ctx);
+extern void *mprMemCtx(void);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* !BLD_APPWEB */
+#endif /* _h_MINI_MPR */
+
+/*****************************************************************************/
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim:tw=78
+ * vim600: sw=4 ts=4 fdm=marker
+ * vim<600: sw=4 ts=4
+ */
diff --git a/source4/lib/appweb/mpr/var.c b/source4/lib/appweb/mpr/var.c
new file mode 100644
index 0000000000..9d2afe5306
--- /dev/null
+++ b/source4/lib/appweb/mpr/var.c
@@ -0,0 +1,2197 @@
+/*
+ * @file var.c
+ * @brief MPR Universal Variable Type
+ * @overview
+ *
+ * @copy default.m
+ *
+ * Copyright (c) Mbedthis Software LLC, 2003-2005. All Rights Reserved.
+ * Copyright (c) Michael O'Brien, 1994-1995. All Rights Reserved.
+ *
+ * This software is distributed under commercial and open source licenses.
+ * You may use the GPL open source license described below or you may acquire
+ * a commercial license from Mbedthis Software. You agree to be fully bound
+ * by the terms of either license. Consult the LICENSE.TXT distributed with
+ * this software for full details.
+ *
+ * This software is open source; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See the GNU General Public License for more
+ * details at: http://www.mbedthis.com/downloads/gplLicense.html
+ *
+ * This program is distributed WITHOUT ANY WARRANTY; without even the
+ * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * This GPL license does NOT permit incorporating this software into
+ * proprietary programs. If you are unable to comply with the GPL, you must
+ * acquire a commercial license to use this software. Commercial licenses
+ * for this software and support services are available from Mbedthis
+ * Software at http://www.mbedthis.com
+ *
+ * @end
+ */
+
+/******************************* Documentation ********************************/
+
+/*
+ * This module is NOT multithreaded.
+ *
+ * Properties are variables that are stored in an object type variable.
+ * Properties can be primitive data types, other objects or functions.
+ * Properties are indexed by a character name.
+ */
+
+/********************************** Includes **********************************/
+
+#include "var.h"
+
+/*********************************** Locals ***********************************/
+#if VAR_DEBUG
+
+static MprProperties objectList; /* Dummy head of objects list */
+static int objectCount = -1; /* Count of objects */
+
+#endif
+/***************************** Forward Declarations ***************************/
+
+static int adjustRefCount(MprProperties *pp, int adj);
+static int adjustVarRefCount(MprVar *vp, int adj);
+static MprVar *allocProperty(const char *propertyName);
+static void copyVarCore(MprVar *dest, MprVar *src, int copyDepth);
+static MprProperties
+ *createProperties(const char *name, int hashSize);
+static bool freeVar(MprVar *vp, int force);
+static bool freeVarStorage(MprVar *vp, int force);
+static MprVar *getObjChain(MprProperties *pp, const char *property);
+static int hash(MprProperties *pp, const char *property);
+static bool releaseProperties(MprProperties *pp, int force);
+
+/*********************************** Code *************************************/
+/*
+ * Destroy a variable and all referenced variables. Release any referenced
+ * object regardless of whether other users still have references. Be VERY
+ * careful using this routine.
+ *
+ * Return TRUE if the underlying data is freed. Objects may not be freed if
+ * there are other users of the object.
+ */
+
+bool mprDestroyAllVars(MprVar *vp)
+{
+ mprAssert(vp);
+
+ if (vp->trigger) {
+ if ((vp->trigger)(MPR_VAR_DELETE, vp->parentProperties, vp, 0, 0)
+ == MPR_TRIGGER_ABORT) {
+ return 0;
+ }
+ }
+
+ /*
+ * Free the actual value. If this var refers to an object, we will
+ * recurse through all the properties freeing all vars.
+ */
+ return freeVar(vp, 1);
+}
+
+/******************************************************************************/
+/*
+ * Destroy a variable. Release any referenced object (destroy if no other
+ * users are referencing).
+ *
+ * Return TRUE if the underlying data is freed. Objects may not be freed if
+ * there are other users of the object.
+ */
+
+bool mprDestroyVar(MprVar *vp)
+{
+ mprAssert(vp);
+
+ if (vp->trigger) {
+ if ((vp->trigger)(MPR_VAR_DELETE, vp->parentProperties, vp, 0, 0)
+ == MPR_TRIGGER_ABORT) {
+ return 0;
+ }
+ }
+
+ /*
+ * Free the actual value. If this var refers to an object, we will
+ * recurse through all the properties freeing all that have no other
+ * references.
+ */
+ return freeVar(vp, 0);
+}
+
+/******************************************************************************/
+/*
+ * Free the value in a variable for primitive types. Release objects.
+ *
+ * Return TRUE if the underlying data is freed. Objects may not be freed if
+ * there are other users of the object.
+ */
+
+static bool freeVar(MprVar *vp, int force)
+{
+ bool freed;
+
+ mprAssert(vp);
+
+ freed = freeVarStorage(vp, force);
+
+ mprFree(vp->name);
+ mprFree(vp->fullName);
+
+ if (vp->allocatedVar) {
+ mprFree(vp);
+ } else {
+ vp->name = 0;
+ vp->fullName = 0;
+ vp->type = MPR_TYPE_UNDEFINED;
+ }
+ return freed;
+}
+
+/******************************************************************************/
+/*
+ * Free the value in a variable for primitive types. Release objects.
+ *
+ * Return TRUE if the underlying data is freed. Objects may not be freed if
+ * there are other users of the object.
+ */
+
+static bool freeVarStorage(MprVar *vp, int force)
+{
+ MprArray *argList;
+ bool freed;
+ int i;
+
+ freed = 1;
+ mprAssert(vp);
+
+ switch (vp->type) {
+ default:
+ break;
+
+ case MPR_TYPE_STRING:
+ if (vp->allocatedData && vp->string != 0) {
+ mprFree(vp->string);
+ vp->string = 0;
+ vp->allocatedData = 0;
+ }
+ break;
+
+ case MPR_TYPE_OBJECT:
+#if VAR_DEBUG
+ /*
+ * Recurse through all properties and release / delete. Release the
+ * properties hash table.
+ */
+ if (vp->properties->refCount > 1) {
+ mprLog(7, "freeVar: ACT \"%s\", 0x%x, ref %d, force %d\n",
+ vp->name, vp->properties, vp->properties->refCount, force);
+ } else {
+ mprLog(7, "freeVar: DEL \"%s\", 0x%x, ref %d, force %d\n",
+ vp->name, vp->properties, vp->properties->refCount, force);
+ }
+#endif
+ if (vp->allocatedData) {
+ freed = releaseProperties(vp->properties, force);
+ }
+ vp->properties = 0;
+ break;
+
+ case MPR_TYPE_FUNCTION:
+ if (vp->allocatedData) {
+ argList = vp->function.args;
+ for (i = 0; i < argList->max; i++) {
+ if (argList->handles[i] != 0) {
+ mprFree(argList->handles[i]);
+ }
+ }
+ mprDestroyArray(argList);
+ vp->function.args = 0;
+ mprFree(vp->function.body);
+ vp->function.body = 0;
+ }
+ break;
+ }
+
+ vp->type = MPR_TYPE_UNDEFINED;
+ return freed;
+}
+
+/******************************************************************************/
+/*
+ * Adjust the object reference count and return the currrent count of
+ * users.
+ */
+
+static int adjustVarRefCount(MprVar *vp, int adj)
+{
+ mprAssert(vp);
+
+ if (vp->type != MPR_TYPE_OBJECT) {
+ mprAssert(vp->type == MPR_TYPE_OBJECT);
+ return 0;
+ }
+ return adjustRefCount(vp->properties, adj);
+}
+
+/******************************************************************************/
+/*
+ * Get the object reference count
+ */
+
+int mprGetVarRefCount(MprVar *vp)
+{
+ mprAssert(vp);
+
+ if (vp->type != MPR_TYPE_OBJECT) {
+ mprAssert(vp->type == MPR_TYPE_OBJECT);
+ return 0;
+ }
+ return adjustRefCount(vp->properties, 0);
+}
+
+/******************************************************************************/
+/*
+ * Update the variable's name
+ */
+
+void mprSetVarName(MprVar *vp, char *name)
+{
+ mprAssert(vp);
+
+ mprFree(vp->name);
+ vp->name = mprStrdup(name);
+}
+
+/******************************************************************************/
+/*
+ * Append to the variable's full name
+ */
+
+void mprSetVarFullName(MprVar *vp, char *name)
+{
+#if VAR_DEBUG
+ mprAssert(vp);
+
+ mprFree(vp->fullName);
+ vp->fullName = mprStrdup(name);
+ if (vp->type == MPR_TYPE_OBJECT) {
+ if (strcmp(vp->properties->name, "this") == 0) {
+ mprStrcpy(vp->properties->name, sizeof(vp->properties->name), name);
+ }
+ }
+#endif
+}
+
+/******************************************************************************/
+/*
+ * Make a var impervious to recursive forced deletes.
+ */
+
+void mprSetVarDeleteProtect(MprVar *vp, int deleteProtect)
+{
+ mprAssert(vp);
+
+ if (vp->type == MPR_TYPE_OBJECT && vp->properties) {
+ vp->properties->deleteProtect = deleteProtect;
+ }
+}
+
+/******************************************************************************/
+/*
+ * Make a variable readonly. Can still be deleted.
+ */
+
+void mprSetVarReadonly(MprVar *vp, int readonly)
+{
+ mprAssert(vp);
+
+ vp->readonly = readonly;
+}
+
+/******************************************************************************/
+
+MprVarTrigger mprAddVarTrigger(MprVar *vp, MprVarTrigger fn)
+{
+ MprVarTrigger oldTrigger;
+
+ mprAssert(vp);
+ mprAssert(fn);
+
+ oldTrigger = vp->trigger;
+ vp->trigger = fn;
+ return oldTrigger;
+}
+
+/******************************************************************************/
+
+MprType mprGetVarType(MprVar *vp)
+{
+ mprAssert(vp);
+
+ return vp->type;
+}
+
+/******************************************************************************/
+/********************************** Properties ********************************/
+/******************************************************************************/
+/*
+ * Create a property in an object with a defined value. If the property
+ * already exists in the object, then just write its value.
+ */
+
+MprVar *mprCreateProperty(MprVar *obj, const char *propertyName,
+ MprVar *newValue)
+{
+ MprVar *prop, *last;
+ int bucketIndex;
+
+ mprAssert(obj);
+ mprAssert(propertyName && *propertyName);
+
+ if (obj->type != MPR_TYPE_OBJECT) {
+ mprAssert(obj->type == MPR_TYPE_OBJECT);
+ return 0;
+ }
+
+ /*
+ * See if property already exists and locate the bucket to hold the
+ * property reference.
+ */
+ last = 0;
+ bucketIndex = hash(obj->properties, propertyName);
+ prop = obj->properties->buckets[bucketIndex];
+
+ /*
+ * Find the property in the hash chain if it exists
+ */
+ for (last = 0; prop; last = prop, prop = prop->forw) {
+ if (prop->name[0] == propertyName[0] &&
+ strcmp(prop->name, propertyName) == 0) {
+ break;
+ }
+ }
+
+ if (prop) {
+ /* FUTURE -- remove. Just for debug. */
+ mprAssert(prop == 0);
+ mprLog(0, "Attempting to create property %s in object %s\n",
+ propertyName, obj->name);
+ return 0;
+ }
+
+ if (obj->trigger) {
+ if ((obj->trigger)(MPR_VAR_CREATE_PROPERTY, obj->properties, prop,
+ newValue, 0) == MPR_TRIGGER_ABORT) {
+ return 0;
+ }
+ }
+
+ /*
+ * Create a new property
+ */
+ prop = allocProperty(propertyName);
+ if (prop == 0) {
+ mprAssert(prop);
+ return 0;
+ }
+
+ copyVarCore(prop, newValue, MPR_SHALLOW_COPY);
+
+ prop->bucketIndex = bucketIndex;
+ if (last) {
+ last->forw = prop;
+ } else {
+ obj->properties->buckets[bucketIndex] = prop;
+ }
+ prop->parentProperties = obj->properties;
+
+ /*
+ * Update the item counts
+ */
+ obj->properties->numItems++;
+ if (! mprVarIsFunction(prop->type)) {
+ obj->properties->numDataItems++;
+ }
+
+ return prop;
+}
+
+/******************************************************************************/
+/*
+ * Create a property in an object with a defined value. If the property
+ * already exists in the object, then just write its value. Same as
+ * mprCreateProperty except that the new value is passed by value rather than
+ * by pointer.
+ */
+
+MprVar *mprCreatePropertyValue(MprVar *obj, const char *propertyName,
+ MprVar newValue)
+{
+ return mprCreateProperty(obj, propertyName, &newValue);
+}
+
+/******************************************************************************/
+/*
+ * Create a new property
+ */
+
+static MprVar *allocProperty(const char *propertyName)
+{
+ MprVar *prop;
+
+ prop = (MprVar*) mprMalloc(sizeof(MprVar));
+ if (prop == 0) {
+ mprAssert(prop);
+ return 0;
+ }
+ memset(prop, 0, sizeof(MprVar));
+ prop->allocatedVar = 1;
+ prop->name = mprStrdup(propertyName);
+ prop->forw = (MprVar*) 0;
+
+ return prop;
+}
+
+/******************************************************************************/
+/*
+ * Update a property in an object with a defined value. Create the property
+ * if it doesn not already exist.
+ */
+
+MprVar *mprSetProperty(MprVar *obj, const char *propertyName, MprVar *newValue)
+{
+ MprVar *prop, triggerValue;
+ int rc;
+
+ mprAssert(obj);
+ mprAssert(propertyName && *propertyName);
+ mprAssert(obj->type == MPR_TYPE_OBJECT);
+
+ if (obj->type != MPR_TYPE_OBJECT) {
+ mprAssert(0);
+ return 0;
+ }
+
+ prop = mprGetProperty(obj, propertyName, 0);
+ if (prop == 0) {
+ return mprCreateProperty(obj, propertyName, newValue);
+ }
+
+ if (obj->trigger) {
+ /*
+ * Call the trigger before the update and pass it the new value.
+ */
+ triggerValue = *newValue;
+ triggerValue.allocatedVar = 0;
+ triggerValue.allocatedData = 0;
+ rc = (obj->trigger)(MPR_VAR_WRITE, obj->properties, obj,
+ &triggerValue, 0);
+ if (rc == MPR_TRIGGER_ABORT) {
+ return 0;
+
+ } else if (rc == MPR_TRIGGER_USE_NEW_VALUE) {
+ /*
+ * Trigger must copy to triggerValue a variable that is not
+ * a structure copy of the existing data.
+ */
+ copyVarCore(prop, &triggerValue, MPR_SHALLOW_COPY);
+ mprDestroyVar(&triggerValue);
+ return prop;
+ }
+ }
+ copyVarCore(prop, newValue, MPR_SHALLOW_COPY);
+ return prop;
+}
+
+/******************************************************************************/
+/*
+ * Update a property in an object with a defined value. Create the property
+ * if it does not already exist. Same as mprSetProperty except that the
+ * new value is passed by value rather than by pointer.
+ */
+
+MprVar *mprSetPropertyValue(MprVar *obj, const char *propertyName,
+ MprVar newValue)
+{
+ return mprSetProperty(obj, propertyName, &newValue);
+}
+
+/******************************************************************************/
+/*
+ * Delete a property from this object
+ */
+
+int mprDeleteProperty(MprVar *obj, const char *property)
+{
+ MprVar *prop, *last;
+ char *cp;
+ int bucketIndex;
+
+ mprAssert(obj);
+ mprAssert(property && *property);
+ mprAssert(obj->type == MPR_TYPE_OBJECT);
+
+ if (obj->type != MPR_TYPE_OBJECT) {
+ mprAssert(obj->type == MPR_TYPE_OBJECT);
+ return 0;
+ }
+
+ last = 0;
+ bucketIndex = hash(obj->properties, property);
+ if ((prop = obj->properties->buckets[bucketIndex]) != 0) {
+ for ( ; prop; prop = prop->forw) {
+ cp = prop->name;
+ if (cp[0] == property[0] && strcmp(cp, property) == 0) {
+ break;
+ }
+ last = prop;
+ }
+ }
+ if (prop == (MprVar*) 0) {
+ mprAssert(prop);
+ return MPR_ERR_NOT_FOUND;
+ }
+ if (prop->readonly) {
+ mprAssert(! prop->readonly);
+ return MPR_ERR_READ_ONLY;
+ }
+
+ if (obj->trigger) {
+ if ((obj->trigger)(MPR_VAR_DELETE_PROPERTY, obj->properties, prop, 0, 0)
+ == MPR_TRIGGER_ABORT) {
+ return MPR_ERR_ABORTED;
+ }
+ }
+
+ if (last) {
+ last->forw = prop->forw;
+ } else {
+ obj->properties->buckets[bucketIndex] = prop->forw;
+ }
+
+ obj->properties->numItems--;
+ if (! mprVarIsFunction(prop->type)) {
+ obj->properties->numDataItems--;
+ }
+
+ mprDestroyVar(prop);
+
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * Find a property in an object and return a pointer to it. If a value arg
+ * is supplied, then copy the data into the var.
+ */
+
+MprVar *mprGetProperty(MprVar *obj, const char *property, MprVar *value)
+{
+ MprVar *prop, triggerValue;
+ int rc;
+
+ if (obj == 0 || obj->type != MPR_TYPE_OBJECT || property == 0 ||
+ *property == '\0') {
+ if (value) {
+ value->type = MPR_TYPE_UNDEFINED;
+ }
+ return 0;
+ }
+
+ for (prop = getObjChain(obj->properties, property); prop;
+ prop = prop->forw) {
+ if (prop->name &&
+ prop->name[0] == property[0] && strcmp(prop->name, property) == 0) {
+ break;
+ }
+ }
+ if (prop == 0) {
+ if (value) {
+ value->type = MPR_TYPE_UNDEFINED;
+ }
+ return 0;
+ }
+ if (value) {
+ if (prop->trigger) {
+ triggerValue = *prop;
+ triggerValue.allocatedVar = 0;
+ triggerValue.allocatedData = 0;
+ /*
+ * Pass the trigger the current read value and may receive
+ * a new value.
+ */
+ rc = (prop->trigger)(MPR_VAR_READ, prop->parentProperties, prop,
+ &triggerValue, 0);
+ if (rc == MPR_TRIGGER_ABORT) {
+ if (value) {
+ value->type = MPR_TYPE_UNDEFINED;
+ }
+ return 0;
+
+ } else if (rc == MPR_TRIGGER_USE_NEW_VALUE) {
+ copyVarCore(prop, &triggerValue, MPR_SHALLOW_COPY);
+ mprDestroyVar(&triggerValue);
+ }
+ }
+ /*
+ * Clone. No copy.
+ */
+ *value = *prop;
+ }
+ return prop;
+}
+
+/******************************************************************************/
+/*
+ * Read a properties value. This returns the property's value. It does not
+ * copy object/string data but returns a pointer directly into the variable.
+ * The caller does not and should not call mprDestroy on the returned value.
+ * If value is null, just read the property and run triggers.
+ */
+
+int mprReadProperty(MprVar *prop, MprVar *value)
+{
+ MprVar triggerValue;
+ int rc;
+
+ mprAssert(prop);
+
+ if (prop->trigger) {
+ triggerValue = *prop;
+ triggerValue.allocatedVar = 0;
+ triggerValue.allocatedData = 0;
+ rc = (prop->trigger)(MPR_VAR_READ, prop->parentProperties, prop,
+ &triggerValue, 0);
+
+ if (rc == MPR_TRIGGER_ABORT) {
+ return MPR_ERR_ABORTED;
+
+ } else if (rc == MPR_TRIGGER_USE_NEW_VALUE) {
+ copyVarCore(prop, &triggerValue, MPR_SHALLOW_COPY);
+ mprDestroyVar(&triggerValue);
+ return 0;
+ }
+ }
+ if (value) {
+ *value = *prop;
+
+ /*
+ * Just so that if the user calls mprDestroyVar on value, it will do no
+ * harm.
+ */
+ value->allocatedVar = 0;
+ value->allocatedData = 0;
+ }
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * Read a properties value. This returns a copy of the property variable.
+ * However, if the property is an object or string, it returns a copy of the
+ * reference to the underlying data. If copyDepth is set to MPR_DEEP_COPY,
+ * then the underlying objects and strings data will be copied as well. If
+ * copyDepth is set to MPR_SHALLOW_COPY, then only strings will be copied. If
+ * it is set to MPR_NO_COPY, then no data will be copied. In all cases, the
+ * user must call mprDestroyVar to free resources. This routine will run any
+ * registered triggers which may modify the value the user receives (without
+ * updating the properties real value).
+ *
+ * WARNING: the args are reversed to most other APIs. This conforms to the
+ * strcpy(dest, src) standard instead.
+ */
+
+int mprCopyProperty(MprVar *dest, MprVar *prop, int copyDepth)
+{
+ MprVar triggerValue;
+ int rc;
+
+ mprAssert(prop);
+ mprAssert(dest);
+
+ if (prop->trigger) {
+ triggerValue = *prop;
+ triggerValue.allocatedVar = 0;
+ triggerValue.allocatedData = 0;
+ rc = (prop->trigger)(MPR_VAR_READ, prop->parentProperties, prop,
+ &triggerValue, copyDepth);
+
+ if (rc == MPR_TRIGGER_ABORT) {
+ return MPR_ERR_ABORTED;
+
+ } else if (rc == MPR_TRIGGER_USE_NEW_VALUE) {
+ copyVarCore(dest, &triggerValue, MPR_SHALLOW_COPY);
+ mprDestroyVar(&triggerValue);
+ return 0;
+ }
+ }
+ mprCopyVar(dest, prop, copyDepth);
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * Write a new value into an existing property in an object.
+ */
+
+int mprWriteProperty(MprVar *vp, MprVar *value)
+{
+ MprVar triggerValue;
+ int rc;
+
+ mprAssert(vp);
+ mprAssert(value);
+
+ if (vp->readonly) {
+ return MPR_ERR_READ_ONLY;
+ }
+
+ if (vp->trigger) {
+ triggerValue = *value;
+
+ rc = (vp->trigger)(MPR_VAR_WRITE, vp->parentProperties, vp,
+ &triggerValue, 0);
+
+ if (rc == MPR_TRIGGER_ABORT) {
+ return MPR_ERR_ABORTED;
+
+ } else if (rc == MPR_TRIGGER_USE_NEW_VALUE) {
+ copyVarCore(vp, &triggerValue, MPR_SHALLOW_COPY);
+ mprDestroyVar(&triggerValue);
+ return 0;
+ }
+ /* Fall through */
+ }
+
+ copyVarCore(vp, value, MPR_SHALLOW_COPY);
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * Write a new value into an existing property in an object.
+ */
+
+int mprWritePropertyValue(MprVar *vp, MprVar value)
+{
+ mprAssert(vp);
+
+ return mprWriteProperty(vp, &value);
+}
+
+/******************************************************************************/
+/*
+ * Get the count of properties.
+ */
+
+int mprGetPropertyCount(MprVar *vp, int includeFlags)
+{
+ mprAssert(vp);
+
+ if (vp->type != MPR_TYPE_OBJECT) {
+ return 0;
+ }
+ if (includeFlags == MPR_ENUM_DATA) {
+ return vp->properties->numDataItems;
+ } else {
+ return vp->properties->numItems;
+ }
+}
+
+/******************************************************************************/
+/*
+ * Get the first property in an object. Used for walking all properties in an
+ * object.
+ */
+
+MprVar *mprGetFirstProperty(MprVar *obj, int includeFlags)
+{
+ MprVar *prop;
+ int i;
+
+ mprAssert(obj);
+ mprAssert(obj->type == MPR_TYPE_OBJECT);
+
+ if (obj->type != MPR_TYPE_OBJECT) {
+ mprAssert(obj->type == MPR_TYPE_OBJECT);
+ return 0;
+ }
+
+ for (i = 0; i < (int) obj->properties->hashSize; i++) {
+ for (prop = obj->properties->buckets[i]; prop; prop = prop->forw) {
+ if (prop) {
+ if (mprVarIsFunction(prop->type)) {
+ if (!(includeFlags & MPR_ENUM_FUNCTIONS)) {
+ continue;
+ }
+ } else {
+ if (!(includeFlags & MPR_ENUM_DATA)) {
+ continue;
+ }
+ }
+ return prop;
+ }
+ break;
+ }
+ }
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * Get the next property in sequence.
+ */
+
+MprVar *mprGetNextProperty(MprVar *obj, MprVar *last, int includeFlags)
+{
+ MprProperties *properties;
+ int i;
+
+ mprAssert(obj);
+ mprAssert(obj->type == MPR_TYPE_OBJECT);
+
+ if (obj->type != MPR_TYPE_OBJECT) {
+ mprAssert(obj->type == MPR_TYPE_OBJECT);
+ return 0;
+ }
+ properties = obj->properties;
+
+ if (last->forw) {
+ return last->forw;
+ }
+
+ for (i = last->bucketIndex + 1; i < (int) properties->hashSize; i++) {
+ for (last = properties->buckets[i]; last; last = last->forw) {
+ if (mprVarIsFunction(last->type)) {
+ if (!(includeFlags & MPR_ENUM_FUNCTIONS)) {
+ continue;
+ }
+ } else {
+ if (!(includeFlags & MPR_ENUM_DATA)) {
+ continue;
+ }
+ }
+ return last;
+ }
+ }
+ return 0;
+}
+
+/******************************************************************************/
+/************************** Internal Support Routines *************************/
+/******************************************************************************/
+/*
+ * Create an hash table to hold and index properties. Properties are just
+ * variables which may contain primitive data types, functions or other
+ * objects. The hash table is the essence of an object. HashSize specifies
+ * the size of the hash table to use and should be a prime number.
+ */
+
+static MprProperties *createProperties(const char *name, int hashSize)
+{
+ MprProperties *pp;
+
+ if (hashSize < 7) {
+ hashSize = 7;
+ }
+ if ((pp = (MprProperties*) mprMalloc(sizeof(MprProperties))) == NULL) {
+ mprAssert(0);
+ return 0;
+ }
+ mprAssert(pp);
+ memset(pp, 0, sizeof(MprProperties));
+
+ pp->numItems = 0;
+ pp->numDataItems = 0;
+ pp->hashSize = hashSize;
+ pp->buckets = (MprVar**) mprMalloc(pp->hashSize * sizeof(MprVar*));
+ mprAssert(pp->buckets);
+ memset(pp->buckets, 0, pp->hashSize * sizeof(MprVar*));
+ pp->refCount = 1;
+
+#if VAR_DEBUG
+ if (objectCount == -1) {
+ objectCount = 0;
+ objectList.next = objectList.prev = &objectList;
+ }
+
+ mprStrcpy(pp->name, sizeof(pp->name), name);
+ pp->next = &objectList;
+ pp->prev = objectList.prev;
+ objectList.prev->next = pp;
+ objectList.prev = pp;
+ objectCount++;
+#endif
+ return pp;
+}
+
+/******************************************************************************/
+/*
+ * Release an object's properties hash table. If this is the last person
+ * using it, free it. Return TRUE if the object is released.
+ */
+
+static bool releaseProperties(MprProperties *obj, int force)
+{
+ MprProperties *pp;
+ MprVar *prop, *forw;
+ int i;
+
+ mprAssert(obj);
+ mprAssert(obj->refCount > 0);
+
+#if VAR_DEBUG
+ /*
+ * Debug sanity check
+ */
+ mprAssert(obj->refCount < 20);
+#endif
+
+ if (--obj->refCount > 0 && !force) {
+ return 0;
+ }
+
+#if VAR_DEBUG
+ mprAssert(obj->prev);
+ mprAssert(obj->next);
+ mprAssert(obj->next->prev);
+ mprAssert(obj->prev->next);
+ obj->next->prev = obj->prev;
+ obj->prev->next = obj->next;
+ objectCount--;
+#endif
+
+ for (i = 0; i < (int) obj->hashSize; i++) {
+ for (prop = obj->buckets[i]; prop; prop = forw) {
+ forw = prop->forw;
+ if (prop->type == MPR_TYPE_OBJECT) {
+
+ if (prop->properties == obj) {
+ /* Self reference */
+ continue;
+ }
+ pp = prop->properties;
+ if (pp->visited) {
+ continue;
+ }
+
+ pp->visited = 1;
+ if (! freeVar(prop, pp->deleteProtect ? 0 : force)) {
+ pp->visited = 0;
+ }
+
+ } else {
+ freeVar(prop, force);
+ }
+ }
+ }
+
+ mprFree((void*) obj->buckets);
+ mprFree((void*) obj);
+
+ return 1;
+}
+
+/******************************************************************************/
+/*
+ * Adjust the reference count
+ */
+
+static int adjustRefCount(MprProperties *pp, int adj)
+{
+ mprAssert(pp);
+
+ /*
+ * Debug sanity check
+ */
+ mprAssert(pp->refCount < 20);
+
+ return pp->refCount += adj;
+}
+
+/******************************************************************************/
+#if VAR_DEBUG
+/*
+ * Print objects held
+ */
+
+void mprPrintObjects(char *msg)
+{
+ MprProperties *pp, *np;
+ MprVar *prop, *forw;
+ char *buf;
+ int i;
+
+ mprLog(7, "%s: Object Store. %d objects.\n", msg, objectCount);
+ pp = objectList.next;
+ while (pp != &objectList) {
+ mprLog(7, "%s: 0x%x, refCount %d, properties %d\n",
+ pp->name, pp, pp->refCount, pp->numItems);
+ for (i = 0; i < (int) pp->hashSize; i++) {
+ for (prop = pp->buckets[i]; prop; prop = forw) {
+ forw = prop->forw;
+ if (prop->properties == pp) {
+ /* Self reference */
+ continue;
+ }
+ mprVarToString(&buf, MPR_MAX_STRING, 0, prop);
+ if (prop->type == MPR_TYPE_OBJECT) {
+ np = objectList.next;
+ while (np != &objectList) {
+ if (prop->properties == np) {
+ break;
+ }
+ np = np->next;
+ }
+ if (prop->properties == np) {
+ mprLog(7, " %s: OBJECT 0x%x, <%s>\n",
+ prop->name, prop->properties, prop->fullName);
+ } else {
+ mprLog(7, " %s: OBJECT NOT FOUND, %s <%s>\n",
+ prop->name, buf, prop->fullName);
+ }
+ } else {
+ mprLog(7, " %s: <%s> = %s\n", prop->name,
+ prop->fullName, buf);
+ }
+ mprFree(buf);
+ }
+ }
+ pp = pp->next;
+ }
+}
+
+/******************************************************************************/
+
+void mprPrintObjRefCount(MprVar *vp)
+{
+ mprLog(7, "OBJECT 0x%x, refCount %d\n", vp->properties,
+ vp->properties->refCount);
+}
+
+#endif
+/******************************************************************************/
+/*
+ * Get the bucket chain containing a property.
+ */
+
+static MprVar *getObjChain(MprProperties *obj, const char *property)
+{
+ mprAssert(obj);
+
+ return obj->buckets[hash(obj, property)];
+}
+
+/******************************************************************************/
+/*
+ * Fast hash. The history of this algorithm is part of lost computer science
+ * folk lore.
+ */
+
+static int hash(MprProperties *pp, const char *property)
+{
+ uint sum;
+
+ mprAssert(pp);
+ mprAssert(property);
+
+ sum = 0;
+ while (*property) {
+ sum += (sum * 33) + *property++;
+ }
+
+ return sum % pp->hashSize;
+}
+
+/******************************************************************************/
+/*********************************** Constructors *****************************/
+/******************************************************************************/
+/*
+ * Initialize an undefined value.
+ */
+
+MprVar mprCreateUndefinedVar()
+{
+ MprVar v;
+
+ memset(&v, 0x0, sizeof(v));
+ v.type = MPR_TYPE_UNDEFINED;
+ return v;
+}
+
+/******************************************************************************/
+/*
+ * Initialize an null value.
+ */
+
+MprVar mprCreateNullVar()
+{
+ MprVar v;
+
+ memset(&v, 0x0, sizeof(v));
+ v.type = MPR_TYPE_NULL;
+ return v;
+}
+
+/******************************************************************************/
+
+MprVar mprCreateBoolVar(bool value)
+{
+ MprVar v;
+
+ memset(&v, 0x0, sizeof(v));
+ v.type = MPR_TYPE_BOOL;
+ v.boolean = value;
+ return v;
+}
+
+/******************************************************************************/
+/*
+ * Initialize a C function.
+ */
+
+MprVar mprCreateCFunctionVar(MprCFunction fn, void *thisPtr, int flags)
+{
+ MprVar v;
+
+ memset(&v, 0x0, sizeof(v));
+ v.type = MPR_TYPE_CFUNCTION;
+ v.cFunction.fn = fn;
+ v.cFunction.thisPtr = thisPtr;
+ v.flags = flags;
+
+ return v;
+}
+
+/******************************************************************************/
+/*
+ * Initialize a C function.
+ */
+
+MprVar mprCreateStringCFunctionVar(MprStringCFunction fn, void *thisPtr,
+ int flags)
+{
+ MprVar v;
+
+ memset(&v, 0x0, sizeof(v));
+ v.type = MPR_TYPE_STRING_CFUNCTION;
+ v.cFunctionWithStrings.fn = fn;
+ v.cFunctionWithStrings.thisPtr = thisPtr;
+ v.flags = flags;
+
+ return v;
+}
+
+/******************************************************************************/
+/*
+ * Initialize an opaque pointer.
+ */
+
+MprVar mprCreatePtrVar(void *ptr)
+{
+ MprVar v;
+
+ memset(&v, 0x0, sizeof(v));
+ v.type = MPR_TYPE_PTR;
+ v.ptr = ptr;
+
+ return v;
+}
+
+/******************************************************************************/
+#if BLD_FEATURE_FLOATING_POINT
+/*
+ * Initialize a floating value.
+ */
+
+MprVar mprCreateFloatVar(double value)
+{
+ MprVar v;
+
+ memset(&v, 0x0, sizeof(v));
+ v.type = MPR_TYPE_FLOAT;
+ v.floating = value;
+ return v;
+}
+
+#endif
+/******************************************************************************/
+/*
+ * Initialize an integer value.
+ */
+
+MprVar mprCreateIntegerVar(int value)
+{
+ MprVar v;
+
+ memset(&v, 0x0, sizeof(v));
+ v.type = MPR_TYPE_INT;
+ v.integer = value;
+ return v;
+}
+
+/******************************************************************************/
+#if BLD_FEATURE_INT64
+/*
+ * Initialize a 64-bit integer value.
+ */
+
+MprVar mprCreateInteger64Var(int64 value)
+{
+ MprVar v;
+
+ memset(&v, 0x0, sizeof(v));
+ v.type = MPR_TYPE_INT64;
+ v.integer64 = value;
+ return v;
+}
+
+#endif /* BLD_FEATURE_INT64 */
+/******************************************************************************/
+/*
+ * Initialize an number variable. Type is defined by configure.
+ */
+
+MprVar mprCreateNumberVar(MprNum value)
+{
+ MprVar v;
+
+ memset(&v, 0x0, sizeof(v));
+ v.type = BLD_FEATURE_NUM_TYPE_ID;
+#if BLD_FEATURE_NUM_TYPE_ID == MPR_TYPE_INT64
+ v.integer64 = value;
+#elif BLD_FEATURE_NUM_TYPE_ID == MPR_TYPE_FLOAT
+ v.float = value;
+#else
+ v.integer = value;
+#endif
+ return v;
+}
+
+/******************************************************************************/
+/*
+ * Initialize a (bare) JavaScript function. args and body can be null.
+ */
+
+MprVar mprCreateFunctionVar(char *args, char *body, int flags)
+{
+ MprVar v;
+ char *cp, *arg, *last;
+ int aid;
+
+ memset(&v, 0x0, sizeof(v));
+ v.type = MPR_TYPE_FUNCTION;
+ v.flags = flags;
+
+ v.function.args = mprCreateArray();
+
+ if (args) {
+ args = mprStrdup(args);
+ arg = mprStrTok(args, ",", &last);
+ while (arg) {
+ while (isspace((int) *arg))
+ arg++;
+ for (cp = &arg[strlen(arg) - 1]; cp > arg; cp--) {
+ if (!isspace((int) *cp)) {
+ break;
+ }
+ }
+ cp[1] = '\0';
+
+ aid = mprAddToArray(v.function.args, mprStrdup(arg));
+ arg = mprStrTok(0, ",", &last);
+ }
+ mprFree(args);
+ }
+
+ if (body) {
+ v.function.body = mprStrdup(body);
+ }
+ v.allocatedData = 1;
+ return v;
+}
+
+/******************************************************************************/
+/*
+ * Initialize an object variable. Return type == MPR_TYPE_UNDEFINED if the
+ * memory allocation for the properties table failed.
+ */
+
+MprVar mprCreateObjVar(const char *name, int hashSize)
+{
+ MprVar v;
+
+ mprAssert(name && *name);
+
+ memset(&v, 0x0, sizeof(MprVar));
+ v.type = MPR_TYPE_OBJECT;
+ if (hashSize <= 0) {
+ hashSize = MPR_DEFAULT_HASH_SIZE;
+ }
+ v.properties = createProperties(name, hashSize);
+ if (v.properties == 0) {
+ /* Indicate failed memory allocation */
+ v.type = MPR_TYPE_UNDEFINED;
+ }
+ v.allocatedData = 1;
+ v.name = mprStrdup(name);
+ mprLog(7, "mprCreateObjVar %s, 0x%p\n", name, v.properties);
+ return v;
+}
+
+/******************************************************************************/
+/*
+ * Initialize a string value.
+ */
+
+MprVar mprCreateStringVar(const char *value, bool allocate)
+{
+ MprVar v;
+
+ memset(&v, 0x0, sizeof(v));
+ v.type = MPR_TYPE_STRING;
+ if (value == 0) {
+ v.string = "";
+ } else if (allocate) {
+ v.string = mprStrdup(value);
+ v.allocatedData = 1;
+ } else {
+ v.string = (char*) value;
+ }
+ return v;
+}
+
+/******************************************************************************/
+/*
+ * Copy an objects core value (only). This preserves the destination object's
+ * name. This implements copy by reference for objects and copy by value for
+ * strings and other types. Caller must free dest prior to calling.
+ */
+
+static void copyVarCore(MprVar *dest, MprVar *src, int copyDepth)
+{
+ MprVarTrigger saveTrigger;
+ MprVar *srcProp, *destProp, *last;
+ char **srcArgs;
+ int i;
+
+ mprAssert(dest);
+ mprAssert(src);
+
+ if (dest == src) {
+ return;
+ }
+
+ /*
+ * FUTURE: we should allow read-only triggers where the value is never
+ * stored in the object. Currently, triggers override the readonly
+ * status.
+ */
+
+ if (dest->type != MPR_TYPE_UNDEFINED && dest->readonly && !dest->trigger) {
+ mprAssert(0);
+ return;
+ }
+
+ if (dest->type != MPR_TYPE_UNDEFINED) {
+ saveTrigger = dest->trigger;
+ freeVarStorage(dest, 0);
+ } else {
+ saveTrigger = 0;
+ }
+
+ switch (src->type) {
+ default:
+ case MPR_TYPE_UNDEFINED:
+ case MPR_TYPE_NULL:
+ break;
+
+ case MPR_TYPE_BOOL:
+ dest->boolean = src->boolean;
+ break;
+
+ case MPR_TYPE_PTR:
+ dest->ptr = src->ptr;
+ break;
+
+ case MPR_TYPE_STRING_CFUNCTION:
+ dest->cFunctionWithStrings = src->cFunctionWithStrings;
+ break;
+
+ case MPR_TYPE_CFUNCTION:
+ dest->cFunction = src->cFunction;
+ break;
+
+#if BLD_FEATURE_FLOATING_POINT
+ case MPR_TYPE_FLOAT:
+ dest->floating = src->floating;
+ break;
+#endif
+
+ case MPR_TYPE_INT:
+ dest->integer = src->integer;
+ break;
+
+#if BLD_FEATURE_INT64
+ case MPR_TYPE_INT64:
+ dest->integer64 = src->integer64;
+ break;
+#endif
+
+ case MPR_TYPE_OBJECT:
+ if (copyDepth == MPR_DEEP_COPY) {
+
+ dest->properties = createProperties(src->name,
+ src->properties->hashSize);
+ dest->allocatedData = 1;
+
+ for (i = 0; i < (int) src->properties->hashSize; i++) {
+ last = 0;
+ for (srcProp = src->properties->buckets[i]; srcProp;
+ srcProp = srcProp->forw) {
+ if (srcProp->visited) {
+ continue;
+ }
+ destProp = allocProperty(srcProp->name);
+ if (destProp == 0) {
+ mprAssert(destProp);
+ return;
+ }
+
+ destProp->bucketIndex = i;
+ if (last) {
+ last->forw = destProp;
+ } else {
+ dest->properties->buckets[i] = destProp;
+ }
+ destProp->parentProperties = dest->properties;
+
+ /*
+ * Recursively copy the object
+ */
+ srcProp->visited = 1;
+ copyVarCore(destProp, srcProp, copyDepth);
+ srcProp->visited = 0;
+ last = srcProp;
+ }
+ }
+ dest->properties->numItems = src->properties->numItems;
+ dest->properties->numDataItems = src->properties->numDataItems;
+ dest->allocatedData = 1;
+
+ } else if (copyDepth == MPR_SHALLOW_COPY) {
+ dest->properties = src->properties;
+ adjustVarRefCount(src, 1);
+ dest->allocatedData = 1;
+
+ } else {
+ dest->properties = src->properties;
+ dest->allocatedData = 0;
+ }
+ break;
+
+ case MPR_TYPE_FUNCTION:
+ if (copyDepth != MPR_NO_COPY) {
+ dest->function.args = mprCreateArray();
+ srcArgs = (char**) src->function.args->handles;
+ for (i = 0; i < src->function.args->max; i++) {
+ if (srcArgs[i]) {
+ mprAddToArray(dest->function.args, mprStrdup(srcArgs[i]));
+ }
+ }
+ dest->function.body = mprStrdup(src->function.body);
+ dest->allocatedData = 1;
+ } else {
+ dest->function.args = src->function.args;
+ dest->function.body = src->function.body;
+ dest->allocatedData = 0;
+ }
+ break;
+
+ case MPR_TYPE_STRING:
+ if (src->string && copyDepth != MPR_NO_COPY) {
+ dest->string = mprStrdup(src->string);
+ dest->allocatedData = 1;
+ } else {
+ dest->string = src->string;
+ dest->allocatedData = 0;
+ }
+ break;
+ }
+
+ dest->type = src->type;
+ dest->flags = src->flags;
+ dest->trigger = saveTrigger;
+
+ /*
+ * Just for safety
+ */
+ dest->spare = 0;
+}
+
+/******************************************************************************/
+/*
+ * Copy an entire object including name.
+ */
+
+void mprCopyVar(MprVar *dest, MprVar *src, int copyDepth)
+{
+ mprAssert(dest);
+ mprAssert(src);
+
+ copyVarCore(dest, src, copyDepth);
+
+ mprFree(dest->name);
+ dest->name = mprStrdup(src->name);
+
+#if VAR_DEBUG
+ if (src->type == MPR_TYPE_OBJECT) {
+
+ mprFree(dest->fullName);
+ dest->fullName = mprStrdup(src->fullName);
+
+ mprLog(7, "mprCopyVar: object \"%s\", FDQ \"%s\" 0x%x, refCount %d\n",
+ dest->name, dest->fullName, dest->properties,
+ dest->properties->refCount);
+ }
+#endif
+}
+
+/******************************************************************************/
+/*
+ * Copy an entire object including name.
+ */
+
+void mprCopyVarValue(MprVar *dest, MprVar src, int copyDepth)
+{
+ mprAssert(dest);
+
+ mprCopyVar(dest, &src, copyDepth);
+}
+
+/******************************************************************************/
+/*
+ * Copy an object. This implements copy by reference for objects and copy by
+ * value for strings and other types. Caller must free dest prior to calling.
+ */
+
+MprVar *mprDupVar(MprVar *src, int copyDepth)
+{
+ MprVar *dest;
+
+ mprAssert(src);
+
+ dest = (MprVar*) mprMalloc(sizeof(MprVar));
+ memset(dest, 0, sizeof(MprVar));
+
+ mprCopyVar(dest, src, copyDepth);
+ return dest;
+}
+
+/******************************************************************************/
+/*
+ * Convert a value to a text based representation of its value
+ * FUTURE -- conver this to use the format string in all cases. Allow
+ * arbitrary format strings.
+ */
+
+void mprVarToString(char** out, int size, char *fmt, MprVar *obj)
+{
+ char *src;
+
+ mprAssert(out);
+
+ *out = NULL;
+
+ if (obj->trigger) {
+ mprReadProperty(obj, 0);
+ }
+
+ switch (obj->type) {
+ case MPR_TYPE_UNDEFINED:
+ /* FUTURE -- spec says convert to "undefined" */
+ *out = mprStrdup("");
+ break;
+
+ case MPR_TYPE_NULL:
+ *out = mprStrdup("null");
+ break;
+
+ case MPR_TYPE_PTR:
+ mprAllocSprintf(out, size, "[Opaque Pointer %p]", obj->ptr);
+ break;
+
+ case MPR_TYPE_BOOL:
+ if (obj->boolean) {
+ *out = mprStrdup("true");
+ } else {
+ *out = mprStrdup("false");
+ }
+ break;
+
+#if BLD_FEATURE_FLOATING_POINT
+ case MPR_TYPE_FLOAT:
+ if (fmt == NULL || *fmt == '\0') {
+ mprAllocSprintf(out, size, "%f", obj->floating);
+ } else {
+ mprAllocSprintf(out, size, fmt, obj->floating);
+ }
+ break;
+#endif
+
+ case MPR_TYPE_INT:
+ if (fmt == NULL || *fmt == '\0') {
+ mprAllocSprintf(out, size, "%d", obj->integer);
+ } else {
+ mprAllocSprintf(out, size, fmt, obj->integer);
+ }
+ break;
+
+#if BLD_FEATURE_INT64
+ case MPR_TYPE_INT64:
+ if (fmt == NULL || *fmt == '\0') {
+#if BLD_GOAHEAD_WEBSERVER
+ mprAllocSprintf(out, size, "%d", (int) obj->integer64);
+#else
+ mprAllocSprintf(out, size, "%Ld", obj->integer64);
+#endif
+ } else {
+ mprAllocSprintf(out, size, fmt, obj->integer64);
+ }
+ break;
+#endif
+
+ case MPR_TYPE_CFUNCTION:
+ mprAllocSprintf(out, size, "[C Function]");
+ break;
+
+ case MPR_TYPE_STRING_CFUNCTION:
+ mprAllocSprintf(out, size, "[C StringFunction]");
+ break;
+
+ case MPR_TYPE_FUNCTION:
+ mprAllocSprintf(out, size, "[JavaScript Function]");
+ break;
+
+ case MPR_TYPE_OBJECT:
+ /* FUTURE -- really want: [object class: name] */
+ mprAllocSprintf(out, size, "[object %s]", obj->name);
+ break;
+
+ case MPR_TYPE_STRING:
+ src = obj->string;
+
+ mprAssert(src);
+ if (fmt && *fmt) {
+ mprAllocSprintf(out, size, fmt, src);
+
+ } else if (src == NULL) {
+ *out = mprStrdup("null");
+
+ } else {
+ *out = mprStrdup(src);
+ }
+ break;
+
+ default:
+ mprAssert(0);
+ }
+}
+
+/******************************************************************************/
+/*
+ * Parse a string based on formatting instructions and intelligently
+ * create a variable.
+ */
+
+MprVar mprParseVar(char *buf, MprType preferredType)
+{
+ MprType type = MPR_TYPE_UNDEFINED;
+ char *cp;
+
+ mprAssert(buf);
+
+ if (preferredType == MPR_TYPE_UNDEFINED) {
+ if (*buf == '-') {
+ type = MPR_NUM_VAR;
+
+ } else if (!isdigit((int) *buf)) {
+ if (strcmp(buf, "true") == 0 || strcmp(buf, "false") == 0) {
+ type = MPR_TYPE_BOOL;
+ } else {
+ type = MPR_TYPE_STRING;
+ }
+
+ } else if (isdigit((int) *buf)) {
+ type = MPR_NUM_VAR;
+ cp = buf;
+ if (*cp && tolower((unsigned char)cp[1]) == 'x') {
+ cp = &cp[2];
+ }
+ for (cp = buf; *cp; cp++) {
+ if (! isdigit((unsigned char) *cp)) {
+ break;
+ }
+ }
+
+ if (*cp != '\0') {
+#if BLD_FEATURE_FLOATING_POINT
+ if (*cp == '.' || tolower((unsigned char)*cp) == 'e') {
+ type = MPR_TYPE_FLOAT;
+ } else
+#endif
+ {
+ type = MPR_NUM_VAR;
+ }
+ }
+ }
+ } else {
+ type = preferredType;
+ }
+
+ switch (type) {
+ case MPR_TYPE_OBJECT:
+ case MPR_TYPE_UNDEFINED:
+ case MPR_TYPE_NULL:
+ case MPR_TYPE_PTR:
+ default:
+ break;
+
+ case MPR_TYPE_BOOL:
+ return mprCreateBoolVar(buf[0] == 't' ? 1 : 0);
+
+ case MPR_TYPE_INT:
+ return mprCreateIntegerVar(mprParseInteger(buf));
+
+#if BLD_FEATURE_INT64
+ case MPR_TYPE_INT64:
+ return mprCreateInteger64Var(mprParseInteger64(buf));
+#endif
+
+ case MPR_TYPE_STRING:
+ if (strcmp(buf, "null") == 0) {
+ return mprCreateNullVar();
+ } else if (strcmp(buf, "undefined") == 0) {
+ return mprCreateUndefinedVar();
+ }
+
+ return mprCreateStringVar(buf, 1);
+
+#if BLD_FEATURE_FLOATING_POINT
+ case MPR_TYPE_FLOAT:
+ return mprCreateFloatVar(atof(buf));
+#endif
+
+ }
+ return mprCreateUndefinedVar();
+}
+
+/******************************************************************************/
+/*
+ * Convert the variable to a boolean. Only for primitive types.
+ */
+
+bool mprVarToBool(const MprVar *vp)
+{
+ mprAssert(vp);
+
+ switch (vp->type) {
+ case MPR_TYPE_UNDEFINED:
+ case MPR_TYPE_NULL:
+ case MPR_TYPE_STRING_CFUNCTION:
+ case MPR_TYPE_CFUNCTION:
+ case MPR_TYPE_FUNCTION:
+ case MPR_TYPE_OBJECT:
+ return 0;
+
+ case MPR_TYPE_PTR:
+ return (vp->ptr != NULL);
+
+ case MPR_TYPE_BOOL:
+ return vp->boolean;
+
+#if BLD_FEATURE_FLOATING_POINT
+ case MPR_TYPE_FLOAT:
+ return (vp->floating != 0 && !mprIsNan(vp->floating));
+#endif
+
+ case MPR_TYPE_INT:
+ return (vp->integer != 0);
+
+#if BLD_FEATURE_INT64
+ case MPR_TYPE_INT64:
+ return (vp->integer64 != 0);
+#endif
+
+ case MPR_TYPE_STRING:
+ mprAssert(vp->string);
+ return (vp->string[0] != '\0');
+ }
+
+ /* Not reached */
+ return 0;
+}
+
+/******************************************************************************/
+#if BLD_FEATURE_FLOATING_POINT
+/*
+ * Convert the variable to a floating point number. Only for primitive types.
+ */
+
+double mprVarToFloat(const MprVar *vp)
+{
+ mprAssert(vp);
+
+ switch (vp->type) {
+ case MPR_TYPE_UNDEFINED:
+ case MPR_TYPE_NULL:
+ case MPR_TYPE_STRING_CFUNCTION:
+ case MPR_TYPE_CFUNCTION:
+ case MPR_TYPE_FUNCTION:
+ case MPR_TYPE_OBJECT:
+ case MPR_TYPE_PTR:
+ return 0;
+
+ case MPR_TYPE_BOOL:
+ return (vp->boolean) ? 1.0 : 0.0;
+
+ case MPR_TYPE_FLOAT:
+ return vp->floating;
+
+ case MPR_TYPE_INT:
+ return (double) vp->integer;
+
+#if BLD_FEATURE_INT64
+ case MPR_TYPE_INT64:
+ return (double) vp->integer64;
+#endif
+
+ case MPR_TYPE_STRING:
+ mprAssert(vp->string);
+ return atof(vp->string);
+ }
+
+ /* Not reached */
+ return 0;
+}
+
+#endif
+/******************************************************************************/
+/*
+ * Convert the variable to a number type. Only works for primitive types.
+ */
+
+MprNum mprVarToNumber(const MprVar *vp)
+{
+#if BLD_FEATURE_NUM_TYPE_ID == MPR_TYPE_INT64
+ return mprVarToInteger64(vp);
+#elif BLD_FEATURE_NUM_TYPE_ID == MPR_TYPE_FLOAT
+ return mprVarToFloat(vp);
+#else
+ return mprVarToInteger(vp);
+#endif
+}
+
+/******************************************************************************/
+/*
+ * Convert the variable to a number type. Only works for primitive types.
+ */
+
+MprNum mprParseNumber(char *s)
+{
+#if BLD_FEATURE_NUM_TYPE_ID == MPR_TYPE_INT64
+ return mprParseInteger64(s);
+#elif BLD_FEATURE_NUM_TYPE_ID == MPR_TYPE_FLOAT
+ return mprParseFloat(s);
+#else
+ return mprParseInteger(s);
+#endif
+}
+
+/******************************************************************************/
+#if BLD_FEATURE_INT64
+/*
+ * Convert the variable to an Integer64 type. Only works for primitive types.
+ */
+
+int64 mprVarToInteger64(const MprVar *vp)
+{
+ mprAssert(vp);
+
+ switch (vp->type) {
+ case MPR_TYPE_UNDEFINED:
+ case MPR_TYPE_NULL:
+ case MPR_TYPE_STRING_CFUNCTION:
+ case MPR_TYPE_CFUNCTION:
+ case MPR_TYPE_FUNCTION:
+ case MPR_TYPE_OBJECT:
+ case MPR_TYPE_PTR:
+ return 0;
+
+ case MPR_TYPE_BOOL:
+ return (vp->boolean) ? 1 : 0;
+
+#if BLD_FEATURE_FLOATING_POINT
+ case MPR_TYPE_FLOAT:
+ if (mprIsNan(vp->floating)) {
+ return 0;
+ }
+ return (int64) vp->floating;
+#endif
+
+ case MPR_TYPE_INT:
+ return vp->integer;
+
+ case MPR_TYPE_INT64:
+ return vp->integer64;
+
+ case MPR_TYPE_STRING:
+ return mprParseInteger64(vp->string);
+ }
+
+ /* Not reached */
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * Convert the string buffer to an Integer64.
+ */
+
+int64 mprParseInteger64(char *str)
+{
+ char *cp;
+ int64 num64;
+ int radix, c, negative;
+
+ mprAssert(str);
+
+ cp = str;
+ num64 = 0;
+ negative = 0;
+
+ if (*cp == '-') {
+ cp++;
+ negative = 1;
+ }
+
+ /*
+ * Parse a number. Observe hex and octal prefixes (0x, 0)
+ */
+ if (*cp != '0') {
+ /*
+ * Normal numbers (Radix 10)
+ */
+ while (isdigit((int) *cp)) {
+ num64 = (*cp - '0') + (num64 * 10);
+ cp++;
+ }
+ } else {
+ cp++;
+ if (tolower((unsigned char)*cp) == 'x') {
+ cp++;
+ radix = 16;
+ while (*cp) {
+ c = tolower((unsigned char)*cp);
+ if (isdigit(c)) {
+ num64 = (c - '0') + (num64 * radix);
+ } else if (c >= 'a' && c <= 'f') {
+ num64 = (c - 'a') + (num64 * radix);
+ } else {
+ break;
+ }
+ cp++;
+ }
+
+ } else{
+ radix = 8;
+ while (*cp) {
+ c = tolower((unsigned char)*cp);
+ if (isdigit(c) && c < '8') {
+ num64 = (c - '0') + (num64 * radix);
+ } else {
+ break;
+ }
+ cp++;
+ }
+ }
+ }
+
+ if (negative) {
+ return 0 - num64;
+ }
+ return num64;
+}
+
+#endif /* BLD_FEATURE_INT64 */
+/******************************************************************************/
+/*
+ * Convert the variable to an Integer type. Only works for primitive types.
+ */
+
+int mprVarToInteger(const MprVar *vp)
+{
+ mprAssert(vp);
+
+ switch (vp->type) {
+ case MPR_TYPE_UNDEFINED:
+ case MPR_TYPE_NULL:
+ case MPR_TYPE_STRING_CFUNCTION:
+ case MPR_TYPE_CFUNCTION:
+ case MPR_TYPE_FUNCTION:
+ case MPR_TYPE_OBJECT:
+ case MPR_TYPE_PTR:
+ return 0;
+
+ case MPR_TYPE_BOOL:
+ return (vp->boolean) ? 1 : 0;
+
+#if BLD_FEATURE_FLOATING_POINT
+ case MPR_TYPE_FLOAT:
+ if (mprIsNan(vp->floating)) {
+ return 0;
+ }
+ return (int) vp->floating;
+#endif
+
+ case MPR_TYPE_INT:
+ return vp->integer;
+
+#if BLD_FEATURE_INT64
+ case MPR_TYPE_INT64:
+ return (int) vp->integer64;
+#endif
+
+ case MPR_TYPE_STRING:
+ return mprParseInteger(vp->string);
+ }
+
+ /* Not reached */
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * Convert the string buffer to an Integer.
+ */
+
+int mprParseInteger(char *str)
+{
+ char *cp;
+ int num;
+ int radix, c, negative;
+
+ mprAssert(str);
+
+ cp = str;
+ num = 0;
+ negative = 0;
+
+ if (*cp == '-') {
+ cp++;
+ negative = 1;
+ }
+
+ /*
+ * Parse a number. Observe hex and octal prefixes (0x, 0)
+ */
+ if (*cp != '0') {
+ /*
+ * Normal numbers (Radix 10)
+ */
+ while (isdigit((int) *cp)) {
+ num = (*cp - '0') + (num * 10);
+ cp++;
+ }
+ } else {
+ cp++;
+ if (tolower((unsigned char)*cp) == 'x') {
+ cp++;
+ radix = 16;
+ while (*cp) {
+ c = tolower((unsigned char)*cp);
+ if (isdigit(c)) {
+ num = (c - '0') + (num * radix);
+ } else if (c >= 'a' && c <= 'f') {
+ num = (c - 'a') + (num * radix);
+ } else {
+ break;
+ }
+ cp++;
+ }
+
+ } else{
+ radix = 8;
+ while (*cp) {
+ c = tolower((unsigned char)*cp);
+ if (isdigit(c) && c < '8') {
+ num = (c - '0') + (num * radix);
+ } else {
+ break;
+ }
+ cp++;
+ }
+ }
+ }
+
+ if (negative) {
+ return 0 - num;
+ }
+ return num;
+}
+
+/******************************************************************************/
+#if BLD_FEATURE_FLOATING_POINT
+/*
+ * Convert the string buffer to an Floating.
+ */
+
+double mprParseFloat(char *str)
+{
+ return atof(str);
+}
+
+/******************************************************************************/
+
+bool mprIsNan(double f)
+{
+#if WIN
+ return _isnan(f);
+#elif VXWORKS
+ /* FUTURE */
+ return (0);
+#else
+ return (f == FP_NAN);
+#endif
+}
+/******************************************************************************/
+
+bool mprIsInfinite(double f)
+{
+#if WIN
+ return !_finite(f);
+#elif VXWORKS
+ /* FUTURE */
+ return (0);
+#else
+ return (f == FP_INFINITE);
+#endif
+}
+
+#endif /* BLD_FEATURE_FLOATING_POINT */
+/******************************************************************************/
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim:tw=78
+ * vim600: sw=4 ts=4 fdm=marker
+ * vim<600: sw=4 ts=4
+ */
diff --git a/source4/lib/appweb/mpr/var.h b/source4/lib/appweb/mpr/var.h
new file mode 100644
index 0000000000..8ed13a4995
--- /dev/null
+++ b/source4/lib/appweb/mpr/var.h
@@ -0,0 +1,496 @@
+/*
+ * @file var.h
+ * @brief MPR Universal Variable Type
+ * @copy default.m
+ *
+ * Copyright (c) Mbedthis Software LLC, 2003-2005. All Rights Reserved.
+ * Copyright (c) Michael O'Brien, 1994-1995. All Rights Reserved.
+ *
+ * This software is distributed under commercial and open source licenses.
+ * You may use the GPL open source license described below or you may acquire
+ * a commercial license from Mbedthis Software. You agree to be fully bound
+ * by the terms of either license. Consult the LICENSE.TXT distributed with
+ * this software for full details.
+ *
+ * This software is open source; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version. See the GNU General Public License for more
+ * details at: http://www.mbedthis.com/downloads/gplLicense.html
+ *
+ * This program is distributed WITHOUT ANY WARRANTY; without even the
+ * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * This GPL license does NOT permit incorporating this software into
+ * proprietary programs. If you are unable to comply with the GPL, you must
+ * acquire a commercial license to use this software. Commercial licenses
+ * for this software and support services are available from Mbedthis
+ * Software at http://www.mbedthis.com
+ *
+ * @end
+ */
+
+/******************************* Documentation ********************************/
+/*
+ * Variables can efficiently store primitive types and can hold references to
+ * objects. Objects can store properties which are themselves variables.
+ * Properties can be primitive data types, other objects or functions.
+ * Properties are indexed by a character name. A variable may store one of
+ * the following types:
+ *
+ * string, integer, integer-64bit, C function, C function with string args,
+ * Javascript function, Floating point number, boolean value, Undefined
+ * value and the Null value.
+ *
+ * Variables have names while objects may be referenced by multiple variables.
+ * Objects use reference counting for garbage collection.
+ *
+ * This module is not thread safe for performance and compactness. It relies
+ * on upper modules to provide thread synchronization as required. The API
+ * provides primitives to get variable/object references or to get copies of
+ * variables which will help minimize required lock times.
+ */
+
+#ifndef _h_MPR_VAR
+#define _h_MPR_VAR 1
+
+/********************************* Includes ***********************************/
+
+#include "miniMpr.h"
+
+/********************************** Defines ***********************************/
+
+/*
+ * Define VAR_DEBUG if you want to track objects. However, this code is not
+ * thread safe and you need to run the server single threaded.
+ *
+ * #define VAR_DEBUG 1
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+/*
+ * Forward declare types
+ */
+struct MprProperties;
+struct MprVar;
+
+/*
+ * Possible variable types. Don't use enum because we need to be able to
+ * do compile time conditional compilation on BLD_FEATURE_NUM_TYPE_ID.
+ */
+typedef int MprType;
+#define MPR_TYPE_UNDEFINED 0 /* Undefined. No value has been set. */
+#define MPR_TYPE_NULL 1 /* Value defined to be null. */
+#define MPR_TYPE_BOOL 2 /* Boolean type. */
+#define MPR_TYPE_CFUNCTION 3 /* C function or C++ method */
+#define MPR_TYPE_FLOAT 4 /* Floating point number */
+#define MPR_TYPE_INT 5 /* Integer number */
+#define MPR_TYPE_INT64 6 /* 64-bit Integer number */
+#define MPR_TYPE_OBJECT 7 /* Object reference */
+#define MPR_TYPE_FUNCTION 8 /* JavaScript function */
+#define MPR_TYPE_STRING 9 /* String (immutable) */
+#define MPR_TYPE_STRING_CFUNCTION 10 /* C/C++ function with string args */
+#define MPR_TYPE_PTR 11 /* Opaque pointer */
+
+/*
+ * Create a type for the default number type
+ * Config.h will define the default number type. For example:
+ *
+ * BLD_FEATURE_NUM_TYPE=int
+ * BLD_FEATURE_NUM_TYPE_ID=MPR_TYPE_INT
+ */
+
+/**
+ * Set to the type used for MPR numeric variables. Will equate to int, int64
+ * or double.
+ */
+typedef BLD_FEATURE_NUM_TYPE MprNum;
+
+/**
+ * Set to the MPR_TYPE used for MPR numeric variables. Will equate to
+ * MPR_TYPE_INT, MPR_TYPE_INT64 or MPR_TYPE_FLOAT.
+ */
+#define MPR_NUM_VAR BLD_FEATURE_NUM_TYPE_ID
+#define MPR_TYPE_NUM BLD_FEATURE_NUM_TYPE_ID
+
+/*
+ * Return TRUE if a variable is a function type
+ */
+#define mprVarIsFunction(type) \
+ (type == MPR_TYPE_FUNCTION || type == MPR_TYPE_STRING_CFUNCTION || \
+ type == MPR_TYPE_CFUNCTION)
+
+/*
+ * Return TRUE if a variable is a numeric type
+ */
+#define mprVarIsNumber(type) \
+ (type == MPR_TYPE_INT || type == MPR_TYPE_INT64 || type == MPR_TYPE_FLOAT)
+
+/*
+ * Return TRUE if a variable is a boolean
+ */
+#define mprVarIsBoolean(type) \
+ (type == MPR_TYPE_BOOL)
+#define mprVarIsString(type) \
+ (type == MPR_TYPE_STRING)
+#define mprVarIsObject(type) \
+ (type == MPR_TYPE_OBJECT)
+#define mprVarIsFloating(type) \
+ (type == MPR_TYPE_FLOAT)
+#define mprVarIsPtr(type) \
+ (type == MPR_TYPE_PTR)
+#define mprVarIsUndefined(var) \
+ ((var)->type == MPR_TYPE_UNDEFINED)
+#define mprVarIsNull(var) \
+ ((var)->type == MPR_TYPE_NULL)
+#define mprVarIsValid(var) \
+ (((var)->type != MPR_TYPE_NULL) && ((var)->type != MPR_TYPE_UNDEFINED))
+
+#define MPR_VAR_MAX_RECURSE 5 /* Max object loops */
+
+#if BLD_FEATURE_SQUEEZE
+#define MPR_MAX_VAR 64 /* Max var full name */
+#else
+#define MPR_MAX_VAR 512
+#endif
+
+#ifndef __NO_PACK
+#pragma pack(2)
+#endif /* _NO_PACK */
+
+/*
+ * Function signatures
+ */
+typedef int MprVarHandle;
+typedef int (*MprCFunction)(MprVarHandle userHandle, int argc,
+ struct MprVar **argv);
+typedef int (*MprStringCFunction)(MprVarHandle userHandle, int argc,
+ char **argv);
+
+/*
+ * Triggers
+ */
+typedef enum {
+ MPR_VAR_WRITE, /* This property is being updated */
+ MPR_VAR_READ, /* This property is being read */
+ MPR_VAR_CREATE_PROPERTY, /* A property is being created */
+ MPR_VAR_DELETE_PROPERTY, /* A property is being deleted */
+ MPR_VAR_DELETE /* This object is being deleted */
+} MprVarTriggerOp;
+
+/*
+ * Trigger function return codes.
+ */
+typedef enum {
+ MPR_TRIGGER_ABORT, /* Abort the current operation */
+ MPR_TRIGGER_USE_NEW_VALUE, /* Proceed and use the newValue */
+ MPR_TRIGGER_PROCEED /* Proceed with the operation */
+} MprVarTriggerStatus;
+
+/*
+ * The MprVarTrigger arguments have the following meaning:
+ *
+ * op The operation being performed. See MprVarTriggerOp.
+ * parentProperties Pointer to the MprProperties structure.
+ * vp Pointer to the property that registered the trigger.
+ * newValue New value (see below for more details).
+ * copyDepth Specify what data items to copy.
+ *
+ * For VAR_READ, newVar is set to a temporary variable that the trigger
+ * function may assign a value to be returned instead of the actual
+ * property value.
+ * For VAR_WRITE, newValue holds the new value. The old existing value may be
+ * accessed via vp.
+ * For DELETE_PROPERTY, vp is the property being deleted. newValue is null.
+ * For ADD_PROPERTY, vp is set to the property being added and newValue holds
+ * the new value.
+ */
+typedef MprVarTriggerStatus (*MprVarTrigger)(MprVarTriggerOp op,
+ struct MprProperties *parentProperties, struct MprVar *vp,
+ struct MprVar *newValue, int copyDepth);
+
+/*
+ * mprCreateFunctionVar flags
+ */
+/** Use the alternate handle on function callbacks */
+#define MPR_VAR_ALT_HANDLE 0x1
+
+/** Use the script handle on function callbacks */
+#define MPR_VAR_SCRIPT_HANDLE 0x2
+
+/*
+ * Useful define for the copyDepth argument
+ */
+/** Don't copy any data. Copy only the variable name */
+#define MPR_NO_COPY 0
+
+/** Copy strings. Increment object reference counts. */
+#define MPR_SHALLOW_COPY 1
+
+/** Copy strings and do complete object copies. */
+#define MPR_DEEP_COPY 2
+
+/*
+ * GetFirst / GetNext flags
+ */
+/** Step into data properties. */
+#define MPR_ENUM_DATA 0x1
+
+/** Step into functions properties. */
+#define MPR_ENUM_FUNCTIONS 0x2
+
+/*
+ * Collection type to hold properties in an object
+ */
+typedef struct MprProperties { /* Collection of properties */
+#if VAR_DEBUG
+ struct MprProperties *next; /* Linked list */
+ struct MprProperties *prev; /* Linked list */
+ char name[32]; /* Debug name */
+#endif
+ struct MprVar **buckets; /* Hash chains */
+ int numItems; /* Total count of items */
+ /* FUTURE - Better way of doing this */
+ int numDataItems; /* Enumerable data items */
+ uint hashSize : 8; /* Size of the hash table */
+ /* FUTURE -- increase size of refCount */
+ uint refCount : 8; /* References to this property*/
+ /* FUTURE - make these flags */
+ uint deleteProtect : 8; /* Don't recursively delete */
+ uint visited : 8; /* Node has been processed */
+} MprProperties;
+
+/*
+ * Universal Variable Type
+ */
+typedef struct MprVar {
+ /* FUTURE - remove name to outside reference */
+ MprStr name; /* Property name */
+ /* FUTURE - remove */
+ MprStr fullName; /* Full object name */
+ /* FUTURE - make part of the union */
+ MprProperties *properties; /* Pointer to properties */
+
+ /*
+ * Packed bit field
+ */
+ MprType type : 8; /* Selector into union */
+ uint bucketIndex : 8; /* Copy of bucket index */
+
+ uint flags : 5; /* Type specific flags */
+ uint allocatedData : 1; /* Data needs freeing */
+ uint readonly : 1; /* Unmodifiable */
+ uint deleteProtect : 1; /* Don't recursively delete */
+
+ uint visited : 1; /* Node has been processed */
+ uint allocatedVar : 1; /* Var needs freeing */
+ uint spare : 6; /* Unused */
+
+ struct MprVar *forw; /* Hash table linkage */
+ MprVarTrigger trigger; /* Trigger function */
+
+#if UNUSED && KEEP
+ struct MprVar *baseClass; /* Pointer to class object */
+#endif
+ MprProperties *parentProperties; /* Pointer to parent object */
+
+ /*
+ * Union of primitive types. When debugging on Linux, don't use unions
+ * as the gdb debugger can't display them.
+ */
+#if !BLD_DEBUG && !LINUX && !VXWORKS
+ union {
+#endif
+ int boolean; /* Use int for speed */
+#if BLD_FEATURE_FLOATING_POINT
+ double floating;
+#endif
+ int integer;
+#if BLD_FEATURE_INT64
+ int64 integer64;
+#endif
+ struct { /* Javascript functions */
+ MprArray *args; /* Null terminated */
+ char *body;
+ } function;
+ struct { /* Function with MprVar args */
+ MprCFunction fn;
+ void *thisPtr;
+ } cFunction;
+ struct { /* Function with string args */
+ MprStringCFunction fn;
+ void *thisPtr;
+ } cFunctionWithStrings;
+ MprStr string; /* Allocated string */
+ void *ptr; /* Opaque pointer */
+#if !BLD_DEBUG && !LINUX && !VXWORKS
+ };
+#endif
+} MprVar;
+
+/*
+ * Define a field macro so code an use numbers in a "generic" fashion.
+ */
+#if MPR_NUM_VAR == MPR_TYPE_INT || DOXYGEN
+/* Default numeric type */
+#define mprNumber integer
+#endif
+#if MPR_NUM_VAR == MPR_TYPE_INT64
+/* Default numeric type */
+#define mprNumber integer64
+#endif
+#if MPR_NUM_VAR == MPR_TYPE_FLOAT
+/* Default numeric type */
+#define mprNumber floating
+#endif
+
+typedef BLD_FEATURE_NUM_TYPE MprNumber;
+
+
+#ifndef __NO_PACK
+#pragma pack()
+#endif /* __NO_PACK */
+
+/********************************* Prototypes *********************************/
+/*
+ * Variable constructors and destructors
+ */
+extern MprVar mprCreateObjVar(const char *name, int hashSize);
+extern MprVar mprCreateBoolVar(bool value);
+extern MprVar mprCreateCFunctionVar(MprCFunction fn, void *thisPtr,
+ int flags);
+#if BLD_FEATURE_FLOATING_POINT
+extern MprVar mprCreateFloatVar(double value);
+#endif
+extern MprVar mprCreateIntegerVar(int value);
+#if BLD_FEATURE_INT64
+extern MprVar mprCreateInteger64Var(int64 value);
+#endif
+extern MprVar mprCreateFunctionVar(char *args, char *body, int flags);
+extern MprVar mprCreateNullVar(void);
+extern MprVar mprCreateNumberVar(MprNumber value);
+extern MprVar mprCreateStringCFunctionVar(MprStringCFunction fn,
+ void *thisPtr, int flags);
+extern MprVar mprCreateStringVar(const char *value, bool allocate);
+extern MprVar mprCreateUndefinedVar(void);
+extern MprVar mprCreatePtrVar(void *ptr);
+extern bool mprDestroyVar(MprVar *vp);
+extern bool mprDestroyAllVars(MprVar* vp);
+extern MprType mprGetVarType(MprVar *vp);
+
+/*
+ * Copy
+ */
+extern void mprCopyVar(MprVar *dest, MprVar *src, int copyDepth);
+extern void mprCopyVarValue(MprVar *dest, MprVar src, int copyDepth);
+extern MprVar *mprDupVar(MprVar *src, int copyDepth);
+
+/*
+ * Manage vars
+ */
+extern MprVarTrigger
+ mprAddVarTrigger(MprVar *vp, MprVarTrigger fn);
+extern int mprGetVarRefCount(MprVar *vp);
+extern void mprSetVarDeleteProtect(MprVar *vp, int deleteProtect);
+extern void mprSetVarFullName(MprVar *vp, char *name);
+extern void mprSetVarReadonly(MprVar *vp, int readonly);
+extern void mprSetVarName(MprVar *vp, char *name);
+
+/*
+ * Create properties and return a reference to the property.
+ */
+extern MprVar *mprCreateProperty(MprVar *obj, const char *property,
+ MprVar *newValue);
+extern MprVar *mprCreatePropertyValue(MprVar *obj, const char *property,
+ MprVar newValue);
+extern int mprDeleteProperty(MprVar *obj, const char *property);
+
+/*
+ * Get/Set properties. Set will update/create.
+ */
+extern MprVar *mprGetProperty(MprVar *obj, const char *property,
+ MprVar *value);
+extern MprVar *mprSetProperty(MprVar *obj, const char *property,
+ MprVar *value);
+extern MprVar *mprSetPropertyValue(MprVar *obj, const char *property,
+ MprVar value);
+
+/*
+ * Directly read/write property values (the property must already exist)
+ * For mprCopyProperty, mprDestroyVar must always called on the var.
+ */
+extern int mprReadProperty(MprVar *prop, MprVar *value);
+extern int mprWriteProperty(MprVar *prop, MprVar *newValue);
+extern int mprWritePropertyValue(MprVar *prop, MprVar newValue);
+
+/*
+ * Copy a property. NOTE: reverse of most other args: (dest, src)
+ */
+extern int mprCopyProperty(MprVar *dest, MprVar *prop, int copyDepth);
+
+/*
+ * Enumerate properties
+ */
+extern MprVar *mprGetFirstProperty(MprVar *obj, int includeFlags);
+extern MprVar *mprGetNextProperty(MprVar *obj, MprVar *currentProperty,
+ int includeFlags);
+
+/*
+ * Query properties characteristics
+ */
+extern int mprGetPropertyCount(MprVar *obj, int includeFlags);
+
+/*
+ * Conversion routines
+ */
+extern MprVar mprParseVar(char *str, MprType prefType);
+extern MprNum mprVarToNumber(const MprVar *vp);
+extern int mprVarToInteger(const MprVar *vp);
+#if BLD_FEATURE_INT64
+extern int64 mprVarToInteger64(const MprVar *vp);
+#endif
+extern bool mprVarToBool(const MprVar *vp);
+#if BLD_FEATURE_FLOATING_POINT
+extern double mprVarToFloat(const MprVar *vp);
+#endif
+extern void mprVarToString(char** buf, int size, char *fmt, MprVar *vp);
+
+/*
+ * Parsing and utility routines
+ */
+extern MprNum mprParseNumber(char *str);
+extern int mprParseInteger(char *str);
+
+#if BLD_FEATURE_INT64
+extern int64 mprParseInteger64(char *str);
+#endif
+
+#if BLD_FEATURE_FLOATING_POINT
+extern double mprParseFloat(char *str);
+extern bool mprIsInfinite(double f);
+extern bool mprIsNan(double f);
+#endif
+
+#if VAR_DEBUG
+extern void mprPrintObjects(char *msg);
+extern void mprPrintObjRefCount(MprVar *vp);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+/*****************************************************************************/
+#endif /* _h_MPR_VAR */
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim:tw=78
+ * vim600: sw=4 ts=4 fdm=marker
+ * vim<600: sw=4 ts=4
+ */