From a102f52db89f8a31327a3a9fafa1e5a1699ca3cd Mon Sep 17 00:00:00 2001 From: Andrew Tridgell Date: Wed, 13 Jul 2005 00:12:22 +0000 Subject: r8400: separate out the mpr code, as it is in the upstream appweb sources (This used to be commit 0e30b6e4cc9e70975d3179cfeddc4bfcc8c8fbb7) --- source4/lib/appweb/config.mk | 16 +- source4/lib/appweb/ejs/ejs.h | 4 +- source4/lib/appweb/ejs/miniMpr.c | 512 --------- source4/lib/appweb/ejs/miniMpr.h | 292 ----- source4/lib/appweb/ejs/var.c | 2197 -------------------------------------- source4/lib/appweb/ejs/var.h | 496 --------- source4/lib/appweb/esp/esp.h | 4 +- source4/lib/appweb/mpr/miniMpr.c | 512 +++++++++ source4/lib/appweb/mpr/miniMpr.h | 292 +++++ source4/lib/appweb/mpr/var.c | 2197 ++++++++++++++++++++++++++++++++++++++ source4/lib/appweb/mpr/var.h | 496 +++++++++ 11 files changed, 3514 insertions(+), 3504 deletions(-) delete mode 100644 source4/lib/appweb/ejs/miniMpr.c delete mode 100644 source4/lib/appweb/ejs/miniMpr.h delete mode 100644 source4/lib/appweb/ejs/var.c delete mode 100644 source4/lib/appweb/ejs/var.h create mode 100644 source4/lib/appweb/mpr/miniMpr.c create mode 100644 source4/lib/appweb/mpr/miniMpr.h create mode 100644 source4/lib/appweb/mpr/var.c create mode 100644 source4/lib/appweb/mpr/var.h (limited to 'source4/lib/appweb') diff --git a/source4/lib/appweb/config.mk b/source4/lib/appweb/config.mk index 7d1eca3437..1a73d6834a 100644 --- a/source4/lib/appweb/config.mk +++ b/source4/lib/appweb/config.mk @@ -1,3 +1,14 @@ +####################### +# Start SUBSYSTEM MPR +[SUBSYSTEM::MPR] +ADD_OBJ_FILES = \ + lib/appweb/mpr/miniMpr.o \ + lib/appweb/mpr/var.o +NOPROTO=YES +# End SUBSYSTEM MPR +####################### + + ####################### # Start SUBSYSTEM EJS [SUBSYSTEM::EJS] @@ -5,9 +16,8 @@ ADD_OBJ_FILES = \ lib/appweb/ejs/ejsLib.o \ lib/appweb/ejs/ejsLex.o \ lib/appweb/ejs/ejsParser.o \ - lib/appweb/ejs/ejsProcs.o \ - lib/appweb/ejs/miniMpr.o \ - lib/appweb/ejs/var.o + lib/appweb/ejs/ejsProcs.o +REQUIRED_SUBSYSTEMS = MPR NOPROTO=YES # End SUBSYSTEM EJS ####################### diff --git a/source4/lib/appweb/ejs/ejs.h b/source4/lib/appweb/ejs/ejs.h index f1d2bb4c6e..5efdb47192 100644 --- a/source4/lib/appweb/ejs/ejs.h +++ b/source4/lib/appweb/ejs/ejs.h @@ -44,8 +44,8 @@ #ifndef _h_EJS #define _h_EJS 1 -#include "miniMpr.h" -#include "var.h" +#include "lib/appweb/mpr/miniMpr.h" +#include "lib/appweb/mpr/var.h" #ifdef __cplusplus extern "C" { diff --git a/source4/lib/appweb/ejs/miniMpr.c b/source4/lib/appweb/ejs/miniMpr.c deleted file mode 100644 index 7dda4e7bd7..0000000000 --- a/source4/lib/appweb/ejs/miniMpr.c +++ /dev/null @@ -1,512 +0,0 @@ -/* - * @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 "lib/appweb/ejs/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/ejs/miniMpr.h b/source4/lib/appweb/ejs/miniMpr.h deleted file mode 100644 index d431ebdc1b..0000000000 --- a/source4/lib/appweb/ejs/miniMpr.h +++ /dev/null @@ -1,292 +0,0 @@ -/* - * @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 "config.h" - -#if BLD_APPWEB - /* - * If building within AppWeb, use the full MPR - */ - #include "mpr.h" -#else - - #include - #include - #include - #include - #include - #include - #include - -#if !WIN - #include -#endif - -#if CE - #include - #include "CE/wincompat.h" -#endif - -#if LYNX - #include -#endif - -#if QNX4 - #include -#endif - #include - -/********************************** 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/ejs/var.c b/source4/lib/appweb/ejs/var.c deleted file mode 100644 index 9d2afe5306..0000000000 --- a/source4/lib/appweb/ejs/var.c +++ /dev/null @@ -1,2197 +0,0 @@ -/* - * @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/ejs/var.h b/source4/lib/appweb/ejs/var.h deleted file mode 100644 index 8ed13a4995..0000000000 --- a/source4/lib/appweb/ejs/var.h +++ /dev/null @@ -1,496 +0,0 @@ -/* - * @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 - */ diff --git a/source4/lib/appweb/esp/esp.h b/source4/lib/appweb/esp/esp.h index ee86e8d345..e15daf0b4e 100644 --- a/source4/lib/appweb/esp/esp.h +++ b/source4/lib/appweb/esp/esp.h @@ -38,8 +38,8 @@ #include "lib/appweb/ejs/ejs.h" #include "lib/appweb/esp/espEnv.h" -#include "lib/appweb/ejs/var.h" -#include "lib/appweb/ejs/miniMpr.h" +#include "lib/appweb/mpr/var.h" +#include "lib/appweb/mpr/miniMpr.h" /*********************************** Defines **********************************/ 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 + #include + #include + #include + #include + #include + #include + +#if !WIN + #include +#endif + +#if CE + #include + #include "CE/wincompat.h" +#endif + +#if LYNX + #include +#endif + +#if QNX4 + #include +#endif + #include + +/********************************** 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 + */ -- cgit