summaryrefslogtreecommitdiff
path: root/source4/lib/appweb/ejs-2.0/ejs
diff options
context:
space:
mode:
Diffstat (limited to 'source4/lib/appweb/ejs-2.0/ejs')
-rw-r--r--source4/lib/appweb/ejs-2.0/ejs/.ignore2
-rw-r--r--source4/lib/appweb/ejs-2.0/ejs/Makefile61
-rw-r--r--source4/lib/appweb/ejs-2.0/ejs/classes/.ignore1
-rw-r--r--source4/lib/appweb/ejs-2.0/ejs/classes/Makefile21
-rw-r--r--source4/lib/appweb/ejs-2.0/ejs/classes/ejsArray.c167
-rwxr-xr-xsource4/lib/appweb/ejs-2.0/ejs/classes/ejsDate.c197
-rwxr-xr-xsource4/lib/appweb/ejs-2.0/ejs/classes/ejsError.c140
-rw-r--r--source4/lib/appweb/ejs-2.0/ejs/classes/ejsObject.c588
-rw-r--r--source4/lib/appweb/ejs-2.0/ejs/classes/ejsStndClasses.c144
-rw-r--r--source4/lib/appweb/ejs-2.0/ejs/classes/ejsString.c381
-rw-r--r--source4/lib/appweb/ejs-2.0/ejs/classes/ejsXml.c1327
-rw-r--r--source4/lib/appweb/ejs-2.0/ejs/ejs.c1378
-rw-r--r--source4/lib/appweb/ejs-2.0/ejs/ejs.h849
-rw-r--r--source4/lib/appweb/ejs-2.0/ejs/ejsClass.c273
-rw-r--r--source4/lib/appweb/ejs-2.0/ejs/ejsCmd.c468
-rwxr-xr-xsource4/lib/appweb/ejs-2.0/ejs/ejsGarbage.c1214
-rw-r--r--source4/lib/appweb/ejs-2.0/ejs/ejsLex.c1033
-rw-r--r--source4/lib/appweb/ejs-2.0/ejs/ejsParser.c4514
-rw-r--r--source4/lib/appweb/ejs-2.0/ejs/ejsVar.c4033
-rw-r--r--source4/lib/appweb/ejs-2.0/ejs/ejsVar.h1091
-rw-r--r--source4/lib/appweb/ejs-2.0/ejs/lib/event.js141
-rw-r--r--source4/lib/appweb/ejs-2.0/ejs/lib/global.js34
-rw-r--r--source4/lib/appweb/ejs-2.0/ejs/lib/startup.js15
-rw-r--r--source4/lib/appweb/ejs-2.0/ejs/lib/timer.js158
-rwxr-xr-xsource4/lib/appweb/ejs-2.0/ejs/system/.ignore1
-rwxr-xr-xsource4/lib/appweb/ejs-2.0/ejs/system/Makefile27
-rw-r--r--source4/lib/appweb/ejs-2.0/ejs/system/README.TXT63
-rw-r--r--source4/lib/appweb/ejs-2.0/ejs/system/UNIX/.ignore1
-rwxr-xr-xsource4/lib/appweb/ejs-2.0/ejs/system/UNIX/Makefile21
-rw-r--r--source4/lib/appweb/ejs-2.0/ejs/system/UNIX/ejsFile.c98
-rwxr-xr-xsource4/lib/appweb/ejs-2.0/ejs/system/UNIX/ejsFileSystem.c454
-rwxr-xr-xsource4/lib/appweb/ejs-2.0/ejs/system/UNIX/ejsHTTP.c488
-rw-r--r--source4/lib/appweb/ejs-2.0/ejs/system/WIN/.ignore1
-rwxr-xr-xsource4/lib/appweb/ejs-2.0/ejs/system/WIN/Makefile21
-rw-r--r--source4/lib/appweb/ejs-2.0/ejs/system/WIN/ejsFile.c98
-rwxr-xr-xsource4/lib/appweb/ejs-2.0/ejs/system/WIN/ejsFileSystem.c456
-rwxr-xr-xsource4/lib/appweb/ejs-2.0/ejs/system/WIN/ejsHTTP.c488
-rw-r--r--source4/lib/appweb/ejs-2.0/ejs/system/ejsGC.c326
-rwxr-xr-xsource4/lib/appweb/ejs-2.0/ejs/system/ejsGlobal.c785
-rw-r--r--source4/lib/appweb/ejs-2.0/ejs/system/ejsSystem.c112
-rw-r--r--source4/lib/appweb/ejs-2.0/ejs/system/ejsSystemApp.c49
-rw-r--r--source4/lib/appweb/ejs-2.0/ejs/system/ejsSystemDebug.c60
-rw-r--r--source4/lib/appweb/ejs-2.0/ejs/system/ejsSystemLog.c163
-rwxr-xr-xsource4/lib/appweb/ejs-2.0/ejs/system/ejsSystemMemory.c174
44 files changed, 22116 insertions, 0 deletions
diff --git a/source4/lib/appweb/ejs-2.0/ejs/.ignore b/source4/lib/appweb/ejs-2.0/ejs/.ignore
new file mode 100644
index 0000000000..47f4ac63b2
--- /dev/null
+++ b/source4/lib/appweb/ejs-2.0/ejs/.ignore
@@ -0,0 +1,2 @@
+ejs
+future
diff --git a/source4/lib/appweb/ejs-2.0/ejs/Makefile b/source4/lib/appweb/ejs-2.0/ejs/Makefile
new file mode 100644
index 0000000000..ea6be8c401
--- /dev/null
+++ b/source4/lib/appweb/ejs-2.0/ejs/Makefile
@@ -0,0 +1,61 @@
+#
+# Makefile for Embedded Javascript (EJS)
+#
+# Copyright (c) Mbedthis Software LLC, 2003-2006. All Rights Reserved.
+#
+
+#
+# Ejs may be linked into shared handlers so we must build the objects both
+# shared and static if --shared was specified to configure.
+#
+COMPILE := *.c
+EXPORT_OBJECTS := yes
+PRE_DIRS := classes system db
+MAKE_IFLAGS := -I../mpr -I../exml
+
+include make.dep
+
+ifeq ($(BLD_PRODUCT),ejs)
+POST_DIRS := package
+endif
+
+ifeq ($(BLD_FEATURE_TEST),1)
+POST_DIRS += test
+endif
+
+ifeq ($(BLD_FEATURE_EJS_DB),1)
+LIBS += sqlite
+endif
+
+TARGETS += $(BLD_BIN_DIR)/libejs$(BLD_LIB)
+TARGETS += $(BLD_BIN_DIR)/ejs$(BLD_EXE)
+
+ifeq ($(BLD_FEATURE_EJS),1)
+compileExtra: $(TARGETS)
+endif
+
+$(BLD_BIN_DIR)/libejs$(BLD_LIB): files \
+ $(shell BLD_OBJ=$(BLD_OBJ) \; BLD_OBJ_DIR=$(BLD_OBJ_DIR) \; \
+ eval echo `cat files`)
+ @bld --library $(BLD_BIN_DIR)/libejs \
+ --objectsDir $(BLD_OBJ_DIR) --objectList files \
+ --libs "exml mpr $(LIBS)"
+
+$(BLD_BIN_DIR)/ejs$(BLD_EXE): $(BLD_BIN_DIR)/libejs$(BLD_LIB) \
+ $(BLD_BIN_DIR)/libmpr$(BLD_LIB) \
+ $(BLD_BIN_DIR)/libejs$(BLD_LIB) $(FILES)
+ @bld --executable $(BLD_BIN_DIR)/ejs$(BLD_EXE) \
+ --rpath "$(BLD_PREFIX)/bin" \
+ --preferStatic --smartLibs "ejs exml mpr $(LIBS)" \
+ --objectsDir $(BLD_OBJ_DIR) \
+ --objects "$(BLD_OBJ_DIR)/ejsCmd$(BLD_OBJ)"
+
+cleanExtra:
+ @echo "rm -f $(TARGETS)" | $(BLDOUT)
+ @rm -f $(TARGETS)
+ @rm -f $(BLD_BIN_DIR)/libejs.*
+
+## Local variables:
+## tab-width: 4
+## End:
+## vim: tw=78 sw=4 ts=4
diff --git a/source4/lib/appweb/ejs-2.0/ejs/classes/.ignore b/source4/lib/appweb/ejs-2.0/ejs/classes/.ignore
new file mode 100644
index 0000000000..fb5a29031e
--- /dev/null
+++ b/source4/lib/appweb/ejs-2.0/ejs/classes/.ignore
@@ -0,0 +1 @@
+.updated
diff --git a/source4/lib/appweb/ejs-2.0/ejs/classes/Makefile b/source4/lib/appweb/ejs-2.0/ejs/classes/Makefile
new file mode 100644
index 0000000000..ce12bb3829
--- /dev/null
+++ b/source4/lib/appweb/ejs-2.0/ejs/classes/Makefile
@@ -0,0 +1,21 @@
+#
+# Makefile to build the EJS Classes
+#
+# Copyright (c) Mbedthis Software LLC, 2003-2006. All Rights Reserved.
+#
+
+COMPILE := *.c
+EXPORT_OBJECTS := yes
+MAKE_IFLAGS := -I.. -I../../mpr -I../../exml
+
+include make.dep
+
+compileExtra: .updated
+
+.updated: $(FILES)
+ @touch .updated
+
+## Local variables:
+## tab-width: 4
+## End:
+## vim: tw=78 sw=4 ts=4
diff --git a/source4/lib/appweb/ejs-2.0/ejs/classes/ejsArray.c b/source4/lib/appweb/ejs-2.0/ejs/classes/ejsArray.c
new file mode 100644
index 0000000000..feb64b1aa8
--- /dev/null
+++ b/source4/lib/appweb/ejs-2.0/ejs/classes/ejsArray.c
@@ -0,0 +1,167 @@
+/*
+ * @file ejsArray.c
+ * @brief Array class
+ */
+/********************************* Copyright **********************************/
+/*
+ * @copy default
+ *
+ * Copyright (c) Mbedthis Software LLC, 2003-2006. 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
+ */
+/********************************** Includes **********************************/
+
+#include "ejs.h"
+
+#if BLD_FEATURE_EJS
+
+/************************************ Code ************************************/
+
+int ejsDefineArrayClass(Ejs *ep)
+{
+ if (ejsDefineClass(ep, "Array", "Object", ejsArrayConstructor) == 0) {
+ return MPR_ERR_CANT_INITIALIZE;
+ }
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * Routine to create the base array type
+ */
+
+EjsVar *ejsCreateArrayInternal(EJS_LOC_DEC(ep, loc), int size)
+{
+ EjsProperty *pp;
+ EjsVar *obj, *vp;
+
+ /* MOB -- need to supply hash size -- max(size, 503)); */
+
+ obj = ejsCreateSimpleObjInternal(EJS_LOC_PASS(ep, loc), "Array");
+ if (obj == 0) {
+ mprAssert(0);
+ return obj;
+ }
+ obj->isArray = 1;
+
+ /* MOB -- call constructor here and replace this code */
+
+ pp = ejsSetPropertyToInteger(ep, obj, "length", size);
+ ejsMakePropertyEnumerable(pp, 0);
+
+ vp = ejsGetVarPtr(pp);
+ vp->isArrayLength = 1;
+
+ return obj;
+}
+
+/******************************************************************************/
+
+EjsVar *ejsAddArrayElt(Ejs *ep, EjsVar *op, EjsVar *element,
+ EjsCopyDepth copyDepth)
+{
+ EjsProperty *pp;
+ EjsVar *vp;
+ char idx[16];
+ int length;
+
+ mprAssert(op->isArray);
+
+ length = ejsGetPropertyAsInteger(ep, op, "length");
+
+ mprItoa(idx, sizeof(idx), length);
+ pp = ejsCreateProperty(ep, op, idx);
+ vp = ejsGetVarPtr(pp);
+
+ ejsWriteVar(ep, vp, element, copyDepth);
+
+ ejsSetPropertyToInteger(ep, op, "length", length + 1);
+
+ return vp;
+}
+
+/******************************************************************************/
+/*
+ * Constructor
+ */
+
+int ejsArrayConstructor(Ejs *ep, EjsVar *thisObj, int argc, EjsVar **argv)
+{
+ EjsProperty *pp;
+ EjsVar *vp;
+ char idx[16];
+ int i, max;
+
+ thisObj->isArray = 1;
+ max = 0;
+
+ if (argc > 0) {
+ if (argc == 1 && ejsVarIsNumber(argv[0])) {
+ /*
+ * x = new Array(size);
+ */
+ max = (int) ejsVarToInteger(argv[0]);
+
+ } else {
+ /*
+ * x = new Array(element0, element1, ..., elementN):
+ */
+ max = argc;
+ for (i = 0; i < max; i++) {
+ mprItoa(idx, sizeof(idx), i);
+ pp = ejsCreateSimpleProperty(ep, thisObj, idx);
+ vp = ejsGetVarPtr(pp);
+ ejsWriteVar(ep, vp, argv[i], EJS_SHALLOW_COPY);
+ }
+ }
+ }
+
+ pp = ejsCreateSimpleProperty(ep, thisObj, "length");
+ ejsMakePropertyEnumerable(pp, 0);
+ vp = ejsGetVarPtr(pp);
+ ejsWriteVarAsInteger(ep, vp, max);
+ vp->isArrayLength = 1;
+
+ return 0;
+}
+
+/******************************************************************************/
+
+#else
+void ejsArrayDummy() {}
+
+/******************************************************************************/
+#endif /* BLD_FEATURE_EJS */
+
+/*
+ * 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-2.0/ejs/classes/ejsDate.c b/source4/lib/appweb/ejs-2.0/ejs/classes/ejsDate.c
new file mode 100755
index 0000000000..096316a822
--- /dev/null
+++ b/source4/lib/appweb/ejs-2.0/ejs/classes/ejsDate.c
@@ -0,0 +1,197 @@
+/*
+ * @file ejsStndClasses.c
+ * @brief EJS support methods
+ */
+/********************************* Copyright **********************************/
+/*
+ * @copy default
+ *
+ * Copyright (c) Mbedthis Software LLC, 2003-2006. 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
+ */
+/********************************** Includes **********************************/
+
+#include "ejs.h"
+
+#if BLD_FEATURE_EJS && 0
+
+/******************************************************************************/
+/*
+ * Date constructor
+
+ *
+ * Date();
+ * Date(milliseconds);
+ * Date(dateString);
+ * Date(year, month, date);
+ * Date(year, month, date, hour, minute, second);
+ */
+
+int ejsDateConstructor(Ejs *ep, EjsVar *thisObj, int argc, EjsVar **argv)
+{
+ return 0;
+}
+
+/******************************************************************************/
+
+static int load(Ejs *ep, EjsVar *thisObj, int argc, EjsVar **argv)
+{
+ const char *fileName;
+ XmlState *parser;
+ Exml *xp;
+ MprFile *file;
+
+ if (argc != 1 || !ejsVarIsString(argv[0])) {
+ ejsError(ep, EJS_ARG_ERROR, "Bad args. Usage: load(fileName);");
+ return -1;
+ }
+ fileName = argv[0]->string;
+
+ /* FUTURE -- not romable
+ Need rom code in MPR not MprServices
+ */
+ file = mprOpen(ep, fileName, O_RDONLY, 0664);
+ if (file == 0) {
+ ejsError(ep, EJS_IO_ERROR, "Can't open: %s", fileName);
+ return -1;
+ }
+
+ xp = initParser(ep, thisObj, fileName);
+ parser = exmlGetParseArg(xp);
+
+ exmlSetInputStream(xp, readFileData, (void*) file);
+
+ if (exmlParse(xp) < 0) {
+ if (! ejsGotException(ep)) {
+ ejsError(ep, EJS_IO_ERROR, "Can't parse XML file: %s\nDetails %s",
+ fileName, exmlGetErrorMsg(xp));
+ }
+ termParser(xp);
+ mprClose(file);
+ return -1;
+ }
+
+ ejsSetReturnValue(ep, parser->nodeStack[0].obj);
+
+ termParser(xp);
+ mprClose(file);
+
+ return 0;
+}
+
+/******************************************************************************/
+
+int ejsDefineDateClass(Ejs *ep)
+{
+ EjsVar *dateClass;
+
+ dateClass = ejsDefineClass(ep, "Date", "Object", ejsDateConstructor);
+ if (dateClass == 0) {
+ return MPR_ERR_CANT_INITIALIZE;
+ }
+
+ ejsDefineCMethod(ep, dateClass, "getDate", xxxProc, EJS_NO_LOCAL);
+
+ /* Returns "Friday" or 4 ? */
+ ejsDefineCMethod(ep, dateClass, "getDay", xxxProc, EJS_NO_LOCAL);
+
+ ejsDefineCMethod(ep, dateClass, "getMonth", xxxProc, EJS_NO_LOCAL);
+ ejsDefineCMethod(ep, dateClass, "getFullYear", xxxProc, EJS_NO_LOCAL);
+ ejsDefineCMethod(ep, dateClass, "getYear", xxxProc, EJS_NO_LOCAL);
+ ejsDefineCMethod(ep, dateClass, "getHours", xxxProc, EJS_NO_LOCAL);
+ ejsDefineCMethod(ep, dateClass, "getMinutes", xxxProc, EJS_NO_LOCAL);
+ ejsDefineCMethod(ep, dateClass, "getSeconds", xxxProc, EJS_NO_LOCAL);
+ ejsDefineCMethod(ep, dateClass, "getMilliseconds", xxxProc, EJS_NO_LOCAL);
+ ejsDefineCMethod(ep, dateClass, "getTime", xxxProc, EJS_NO_LOCAL);
+ ejsDefineCMethod(ep, dateClass, "getTimeZoneOffset", xxxProc, EJS_NO_LOCAL);
+
+ ejsDefineCMethod(ep, dateClass, "parse", xxxProc, EJS_NO_LOCAL);
+ ejsDefineCMethod(ep, dateClass, "setDate", xxxProc, EJS_NO_LOCAL);
+ ejsDefineCMethod(ep, dateClass, "setMonth", xxxProc, EJS_NO_LOCAL);
+ ejsDefineCMethod(ep, dateClass, "setFullYear", xxxProc, EJS_NO_LOCAL);
+ ejsDefineCMethod(ep, dateClass, "setYear", xxxProc, EJS_NO_LOCAL);
+ ejsDefineCMethod(ep, dateClass, "setMinutes", xxxProc, EJS_NO_LOCAL);
+ ejsDefineCMethod(ep, dateClass, "setSeconds", xxxProc, EJS_NO_LOCAL);
+ ejsDefineCMethod(ep, dateClass, "setMilliseconds", xxxProc, EJS_NO_LOCAL);
+ ejsDefineCMethod(ep, dateClass, "setTime", xxxProc, EJS_NO_LOCAL);
+
+ ejsDefineCMethod(ep, dateClass, "toString", xxxProc, EJS_NO_LOCAL);
+ ejsDefineCMethod(ep, dateClass, "toGMTString", xxxProc, EJS_NO_LOCAL);
+ ejsDefineCMethod(ep, dateClass, "toUTCString", xxxProc, EJS_NO_LOCAL);
+ ejsDefineCMethod(ep, dateClass, "toLocaleString", xxxProc, EJS_NO_LOCAL);
+ ejsDefineCMethod(ep, dateClass, "UTC", xxxProc, EJS_NO_LOCAL);
+ ejsDefineCMethod(ep, dateClass, "valueOf", xxxProc, EJS_NO_LOCAL);
+ /*
+ UTC: getUTCDate, getUTCDay, getUTCMonth, getUTCFullYear, getUTCHours,
+ getUTCMinutes, getUTCSeconds, getUTCMilliseconds
+ setUTCDate, setUTCDay, setUTCMonth, setUTCFullYear, setUTCHours,
+ setUTCMinutes, setUTCSeconds, setUTCMilliseconds
+ */
+
+ return ejsObjHasErrors(dateClass) ? MPR_ERR_CANT_INITIALIZE : 0;
+}
+
+/******************************************************************************/
+/*
+ Time is since 1970/01/01 GMT
+
+ Normal: Fri Feb 10 2006 05:06:44 GMT-0800 (Pacific Standard Time)
+ UTC: Sat, 11 Feb 2006 05:06:44 GMT
+
+ // Using without New
+
+ println(Date());
+
+ var myDate = new Date();
+ myDate.setFullYear(2010, 0, 14);
+
+ var today = new Date();
+
+ if (myDate > today) {
+ } else {
+ }
+
+
+ X=Date() should be equivalent to X=(new Date()).toString()
+
+ */
+/******************************************************************************/
+
+#else
+void ejsStndClassesDummy() {}
+
+/******************************************************************************/
+#endif /* BLD_FEATURE_EJS */
+
+/*
+ * 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-2.0/ejs/classes/ejsError.c b/source4/lib/appweb/ejs-2.0/ejs/classes/ejsError.c
new file mode 100755
index 0000000000..99445afc7c
--- /dev/null
+++ b/source4/lib/appweb/ejs-2.0/ejs/classes/ejsError.c
@@ -0,0 +1,140 @@
+/*
+ * @file ejsError.c
+ * @brief Error class
+ */
+/********************************* Copyright **********************************/
+/*
+ * @copy default
+ *
+ * Copyright (c) Mbedthis Software LLC, 2003-2006. 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
+ */
+/********************************** Includes **********************************/
+
+#include "ejs.h"
+
+#if BLD_FEATURE_EJS
+
+/************************************ Code ************************************/
+/*
+ * Parse the args and return the message. Convert non-string args using
+ * .toString.
+ */
+
+static char *getMessage(Ejs *ep, int argc, EjsVar **argv)
+{
+ if (argc == 0) {
+ return "";
+
+ } else if (argc == 1) {
+ if (! ejsVarIsString(argv[0])) {
+ if (ejsRunMethod(ep, argv[0], "toString", 0) < 0) {
+ return 0;
+ }
+ return ep->result->string;
+
+ } else {
+ return argv[0]->string;
+ }
+
+ } else {
+ /* Don't call ejsError here or it will go recursive. */
+ return 0;
+ }
+}
+
+
+/******************************************************************************/
+/*
+ * Error Constructor and also used for constructor for sub classes.
+ *
+ * Usage: new Error([message])
+ */
+
+int ejsErrorCons(Ejs *ep, EjsVar *thisObj, int argc, EjsVar **argv)
+{
+ char *msg, *stack;
+
+ msg = getMessage(ep, argc, argv);
+ if (msg == 0) {
+ return -1;
+ }
+
+ ejsSetPropertyToString(ep, thisObj, "name", ejsGetBaseClassName(thisObj));
+ ejsSetPropertyToString(ep, thisObj, "message", msg);
+
+ ejsSetPropertyToUndefined(ep, thisObj, "stack");
+
+ stack = ejsFormatStack(ep);
+ if (stack) {
+ ejsSetPropertyToString(ep, thisObj, "stack", stack);
+ mprFree(stack);
+ }
+
+ if (ejsObjHasErrors(thisObj)) {
+ return -1;
+ }
+
+ return 0;
+}
+
+/******************************************************************************/
+
+int ejsDefineErrorClasses(Ejs *ep)
+{
+ if (ejsDefineClass(ep, "Error", "Object", ejsErrorCons) == 0 ||
+ ejsDefineClass(ep, "AssertError", "Error", ejsErrorCons) == 0 ||
+ ejsDefineClass(ep, "EvalError", "Error", ejsErrorCons) == 0 ||
+ ejsDefineClass(ep, "InternalError", "Error", ejsErrorCons) == 0 ||
+ ejsDefineClass(ep, "IOError", "Error", ejsErrorCons) == 0 ||
+ ejsDefineClass(ep, "MemoryError", "Error", ejsErrorCons) == 0 ||
+ ejsDefineClass(ep, "RangeError", "Error", ejsErrorCons) == 0 ||
+ ejsDefineClass(ep, "ReferenceError", "Error", ejsErrorCons) == 0 ||
+ ejsDefineClass(ep, "SyntaxError", "Error", ejsErrorCons) == 0 ||
+ ejsDefineClass(ep, "TypeError", "Error", ejsErrorCons) == 0) {
+
+ return MPR_ERR_CANT_INITIALIZE;
+ }
+ return 0;
+}
+
+/******************************************************************************/
+
+#else
+void ejsErrorDummy() {}
+
+/******************************************************************************/
+#endif /* BLD_FEATURE_EJS */
+
+/*
+ * 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-2.0/ejs/classes/ejsObject.c b/source4/lib/appweb/ejs-2.0/ejs/classes/ejsObject.c
new file mode 100644
index 0000000000..4f2e23beb2
--- /dev/null
+++ b/source4/lib/appweb/ejs-2.0/ejs/classes/ejsObject.c
@@ -0,0 +1,588 @@
+/*
+ * @file ejsObject.c
+ * @brief Object class
+ */
+/********************************* Copyright **********************************/
+/*
+ * @copy default
+ *
+ * Copyright (c) Mbedthis Software LLC, 2003-2006. 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
+ */
+/********************************** Includes **********************************/
+
+#include "ejs.h"
+
+#if BLD_FEATURE_EJS
+
+/****************************** Forward Declarations **************************/
+/*
+ * Support routines
+ */
+
+static void formatVar(Ejs *ep, MprBuf *bp, EjsVar *vp);
+
+/******************************************************************************/
+/*
+ * Routine to create an object of the desired class. Class name may
+ * contain "."
+ *
+ * The created object will be a stand-alone class NOT entered into the
+ * properties of any other object. Callers must do this if required. ClassName
+ * may contain "." and is interpreted relative to "obj" if supplied.
+ *
+ * Note: this does not call the constructors for the various objects and base
+ * classes.
+ */
+
+EjsVar *ejsCreateSimpleObjInternal(EJS_LOC_DEC(ep, loc), const char *className)
+{
+ EjsVar *baseClass;
+
+ if (className && *className) {
+ baseClass = ejsGetClass(ep, 0, className);
+ if (baseClass == 0) {
+ mprError(ep, MPR_LOC, "Can't find base class %s", className);
+ return 0;
+ }
+ } else {
+ baseClass = 0;
+ }
+
+ return ejsCreateSimpleObjUsingClassInt(EJS_LOC_PASS(ep, loc),
+ baseClass);
+}
+
+/******************************************************************************/
+/*
+ * Create an object based upon the specified base class object. It will be a
+ * stand-alone class not entered into the properties of any other object.
+ * Callers must do this if required.
+ *
+ * Note: this does not call the constructors for the various objects and base
+ * classes.
+ */
+
+EjsVar *ejsCreateSimpleObjUsingClassInt(EJS_LOC_DEC(ep, loc),
+ EjsVar *baseClass)
+{
+ EjsVar *vp;
+
+ mprAssert(baseClass);
+
+ if (baseClass == 0) {
+ mprError(ep, MPR_LOC, "Missing base class\n");
+ return 0;
+ }
+
+ vp = ejsCreateObjVarInternal(EJS_LOC_PASS(ep, loc));
+ if (vp == 0) {
+ return vp;
+ }
+
+ ejsSetBaseClass(vp, baseClass);
+
+ /*
+ * This makes all internal method accesses faster
+ * NOTE: this code is duplicated in ejsCreateSimpleClass
+ */
+ mprAssert(vp->objectState);
+ vp->objectState->methods = baseClass->objectState->methods;
+
+ return vp;
+}
+
+/******************************************************************************/
+
+void ejsSetMethods(Ejs *ep, EjsVar *op)
+{
+ op->objectState->methods = ep->global->objectState->methods;
+}
+
+/******************************************************************************/
+/******************************** Internal Methods ****************************/
+/******************************************************************************/
+
+static EjsVar *createObjProperty(Ejs *ep, EjsVar *obj, const char *property)
+{
+ return ejsGetVarPtr(ejsCreateSimpleProperty(ep, obj, property));
+}
+
+/******************************************************************************/
+
+static int deleteObjProperty(Ejs *ep, EjsVar *obj, const char *property)
+{
+ return ejsDeleteProperty(ep, obj, property);
+}
+
+/******************************************************************************/
+
+static EjsVar *getObjProperty(Ejs *ep, EjsVar *obj, const char *property)
+{
+ return ejsGetVarPtr(ejsGetSimpleProperty(ep, obj, property));
+}
+
+/******************************************************************************/
+/*
+ * Set the value of a property. Create if it does not exist
+ */
+
+static EjsVar *setObjProperty(Ejs *ep, EjsVar *obj, const char *property,
+ const EjsVar *value)
+{
+ EjsProperty *pp;
+ EjsVar *vp;
+
+ pp = ejsCreateSimpleProperty(ep, obj, property);
+ if (pp == 0) {
+ mprAssert(pp);
+ return 0;
+ }
+ vp = ejsGetVarPtr(pp);
+ if (ejsWriteVar(ep, vp, value, EJS_SHALLOW_COPY) < 0) {
+ mprAssert(0);
+ return 0;
+ }
+ return ejsGetVarPtr(pp);
+}
+
+/******************************************************************************/
+/*********************************** Constructors *****************************/
+/******************************************************************************/
+#if UNUSED
+/*
+ * Object constructor. We don't use this for speed. Think very carefully if
+ * you add an object constructor.
+ */
+
+int ejsObjectConstructor(Ejs *ep, EjsVar *thisObj, int argc, EjsVar **argv)
+{
+ return 0;
+}
+
+#endif
+/******************************************************************************/
+/******************************** Visible Methods *****************************/
+/******************************************************************************/
+
+static int cloneMethod(Ejs *ep, EjsVar *thisObj, int argc, EjsVar **argv)
+{
+ int copyDepth;
+
+ copyDepth = EJS_DEEP_COPY;
+
+ if (argc == 1 && ejsVarToBoolean(argv[0])) {
+ copyDepth = EJS_RECURSIVE_DEEP_COPY;
+ }
+
+ ejsWriteVar(ep, ep->result, thisObj, copyDepth);
+
+ return 0;
+}
+
+/******************************************************************************/
+
+static int toStringMethod(Ejs *ep, EjsVar *thisObj, int argc, EjsVar **argv)
+{
+ MprBuf *bp;
+ int saveMaxDepth, saveDepth, saveFlags;
+
+ saveMaxDepth = ep->maxDepth;
+
+ if (argc >= 1) {
+ ep->maxDepth = ejsVarToInteger(argv[0]);
+ } else if (ep->maxDepth == 0) {
+ ep->maxDepth = MAXINT;
+ }
+
+ saveFlags = ep->flags;
+ if (argc >= 2) {
+ if (ejsVarToBoolean(argv[1])) {
+ ep->flags |= EJS_FLAGS_ENUM_HIDDEN;
+ }
+ }
+ if (argc == 3) {
+ if (ejsVarToBoolean(argv[2])) {
+ ep->flags |= EJS_FLAGS_ENUM_BASE;
+ }
+ }
+
+ bp = mprCreateBuf(ep, 0, 0);
+
+ saveDepth = ep->depth;
+
+ formatVar(ep, bp, thisObj);
+
+ ep->depth = saveDepth;
+ ep->maxDepth = saveMaxDepth;
+
+ mprAddNullToBuf(bp);
+
+ ejsWriteVarAsString(ep, ep->result, mprGetBufStart(bp));
+ mprFree(bp);
+
+ ep->flags = saveFlags;
+
+ return 0;
+}
+
+/******************************************************************************/
+
+static int valueOfMethod(Ejs *ep, EjsVar *thisObj, int argc, EjsVar **argv)
+{
+ if (argc != 0) {
+ mprAssert(0);
+ return -1;
+ }
+
+ switch (thisObj->type) {
+ default:
+ case EJS_TYPE_UNDEFINED:
+ case EJS_TYPE_NULL:
+ case EJS_TYPE_CMETHOD:
+ case EJS_TYPE_OBJECT:
+ case EJS_TYPE_METHOD:
+ case EJS_TYPE_STRING_CMETHOD:
+ ejsWriteVar(ep, ep->result, thisObj, EJS_SHALLOW_COPY);
+ break;
+
+ case EJS_TYPE_STRING:
+ ejsWriteVarAsInteger(ep, ep->result, atoi(thisObj->string));
+ break;
+
+ case EJS_TYPE_BOOL:
+ case EJS_TYPE_INT:
+#if BLD_FEATURE_INT64
+ case EJS_TYPE_INT64:
+#endif
+#if BLD_FEATURE_FLOATING_POINT
+ case EJS_TYPE_FLOAT:
+#endif
+ ejsWriteVar(ep, ep->result, thisObj, EJS_SHALLOW_COPY);
+ break;
+ }
+ return 0;
+}
+
+/******************************************************************************/
+
+static int hashGetAccessor(Ejs *ejs, EjsVar *thisObj, int argc, EjsVar **argv)
+{
+ ejsSetReturnValueToInteger(ejs, (int) thisObj->objectState);
+ return 0;
+}
+
+/******************************************************************************/
+
+static int classGetAccessor(Ejs *ejs, EjsVar *thisObj, int argc, EjsVar **argv)
+{
+ if (thisObj->objectState == 0 || thisObj->objectState->baseClass == 0) {
+ ejsSetReturnValueToString(ejs, "object");
+ } else {
+ ejsSetReturnValueToString(ejs,
+ thisObj->objectState->baseClass->objectState->className);
+ }
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * Format an object. Called recursively to format properties and contained
+ * objects.
+ */
+
+static void formatVar(Ejs *ep, MprBuf *bp, EjsVar *vp)
+{
+ EjsProperty *pp, *first;
+ EjsVar *propVar, *baseClass;
+ char *buf, *value;
+ int i;
+
+ if (vp->type == EJS_TYPE_OBJECT) {
+ if (!vp->objectState->visited) {
+
+ mprPutStringToBuf(bp, vp->isArray ? "[\n" : "{\n");
+
+ ep->depth++;
+ vp->objectState->visited = 1;
+
+ if (ep->depth <= ep->maxDepth) {
+ first = ejsGetFirstProperty(vp, EJS_ENUM_ALL);
+
+ if (ep->flags & EJS_FLAGS_ENUM_BASE) {
+ baseClass = vp->objectState->baseClass;
+ if (baseClass) {
+ for (i = 0; i < ep->depth; i++) {
+ mprPutStringToBuf(bp, " ");
+ }
+ mprPutStringToBuf(bp, baseClass->objectState->objName);
+ mprPutStringToBuf(bp, ": /* Base Class */ ");
+ if (baseClass->objectState == vp->objectState) {
+ value = "this";
+ } else if (ejsRunMethodCmd(ep, baseClass, "toString",
+ "%d", ep->maxDepth) < 0) {
+ value = "[object Object]";
+ } else {
+ mprAssert(ejsVarIsString(ep->result));
+ value = ep->result->string;
+ }
+ mprPutStringToBuf(bp, value);
+ if (first) {
+ mprPutStringToBuf(bp, ",\n");
+ }
+ }
+ }
+
+ pp = first;
+ while (pp) {
+ if (! pp->dontEnumerate ||
+ ep->flags & EJS_FLAGS_ENUM_HIDDEN) {
+ for (i = 0; i < ep->depth; i++) {
+ mprPutStringToBuf(bp, " ");
+ }
+
+ if (! vp->isArray) {
+ mprPutStringToBuf(bp, pp->name);
+ mprPutStringToBuf(bp, ": ");
+ }
+
+ propVar = ejsGetVarPtr(pp);
+ if (propVar->type == EJS_TYPE_OBJECT) {
+ if (pp->var.objectState == vp->objectState) {
+ value = "this";
+ } else if (ejsRunMethodCmd(ep, propVar,
+ "toString", "%d", ep->maxDepth) < 0) {
+ value = "[object Object]";
+ } else {
+ mprAssert(ejsVarIsString(ep->result));
+ value = ep->result->string;
+ }
+ mprPutStringToBuf(bp, value);
+
+ } else {
+ formatVar(ep, bp, &pp->var);
+ }
+
+ pp = ejsGetNextProperty(pp, EJS_ENUM_ALL);
+ if (pp) {
+ mprPutStringToBuf(bp, ",\n");
+ }
+ } else {
+ pp = ejsGetNextProperty(pp, EJS_ENUM_ALL);
+ }
+ }
+ }
+ vp->objectState->visited = 0;
+
+ mprPutCharToBuf(bp, '\n');
+
+ ep->depth--;
+ for (i = 0; i < ep->depth; i++) {
+ mprPutStringToBuf(bp, " ");
+ }
+ mprPutCharToBuf(bp, vp->isArray ? ']' : '}');
+ }
+
+ } else if (vp->type == EJS_TYPE_METHOD) {
+
+ mprPutStringToBuf(bp, "function (");
+ for (i = 0; i < vp->method.args->length; i++) {
+ mprPutStringToBuf(bp, vp->method.args->items[i]);
+ if ((i + 1) < vp->method.args->length) {
+ mprPutStringToBuf(bp, ", ");
+ }
+ }
+ mprPutStringToBuf(bp, ") {");
+ mprPutStringToBuf(bp, vp->method.body);
+ for (i = 0; i < ep->depth; i++) {
+ mprPutStringToBuf(bp, " ");
+ }
+ mprPutStringToBuf(bp, "}");
+
+ } else {
+
+ if (vp->type == EJS_TYPE_STRING) {
+ mprPutCharToBuf(bp, '\"');
+ }
+
+ /*
+ * We don't use ejsVarToString for arrays, objects and strings.
+ * This is because ejsVarToString does not call "obj.toString"
+ * and it is not required for strings.
+ * MOB - rc
+ */
+ buf = ejsVarToString(ep, vp);
+ mprPutStringToBuf(bp, buf);
+
+ if (vp->type == EJS_TYPE_STRING) {
+ mprPutCharToBuf(bp, '\"');
+ }
+ }
+}
+
+/******************************************************************************/
+/*
+ * mixin code. Blends code at the "thisObj" level.
+ */
+
+static int mixinMethod(Ejs *ep, EjsVar *thisObj, int argc, EjsVar **argv)
+{
+ EjsProperty *pp;
+ char *buf;
+ int fid, i, rc;
+
+ mprAssert(argv);
+
+ /*
+ * Create a variable scope block set to the current object
+ */
+ rc = 0;
+ fid = ejsSetBlock(ep, thisObj);
+
+ for (i = 0; i < argc; i++) {
+
+ if (ejsVarIsString(argv[i])) {
+ rc = ejsEvalScript(ep, argv[i]->string, 0);
+
+ } else if (ejsVarIsObject(argv[i])) {
+
+ /* MOB -- OPT. When we have proper scope chains, we should just
+ refer to the module and not copy */
+ pp = ejsGetFirstProperty(argv[i], EJS_ENUM_ALL);
+ while (pp) {
+ ejsSetProperty(ep, thisObj, pp->name, ejsGetVarPtr(pp));
+ pp = ejsGetNextProperty(pp, EJS_ENUM_ALL);
+ }
+
+ } else {
+ /* MOB - rc */
+ buf = ejsVarToString(ep, argv[i]);
+ rc = ejsEvalScript(ep, buf, 0);
+
+ }
+ if (rc < 0) {
+ ejsCloseBlock(ep, fid);
+ return -1;
+ }
+ }
+ ejsCloseBlock(ep, fid);
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * Create the object class
+ */
+
+int ejsDefineObjectClass(Ejs *ep)
+{
+ EjsMethods *methods;
+ EjsProperty *objectProp, *protoProp;
+ EjsVar *op, *globalClass;
+
+ /*
+ * Must specially hand-craft the object class as it is the base class
+ * of all objects.
+ */
+ op = ejsCreateObjVar(ep);
+ if (op == 0) {
+ return MPR_ERR_CANT_CREATE;
+ }
+ ejsSetClassName(ep, op, "Object");
+
+ /*
+ * Don't use a constructor for objects for speed
+ */
+ ejsMakeClassNoConstructor(op);
+
+ /*
+ * MOB -- should mark properties as public / private and class or instance.
+ */
+ ejsDefineCMethod(ep, op, "clone", cloneMethod, EJS_NO_LOCAL);
+ ejsDefineCMethod(ep, op, "toString", toStringMethod, EJS_NO_LOCAL);
+ ejsDefineCMethod(ep, op, "valueOf", valueOfMethod, EJS_NO_LOCAL);
+ ejsDefineCMethod(ep, op, "mixin", mixinMethod, EJS_NO_LOCAL);
+
+ ejsDefineCAccessors(ep, op, "hash", hashGetAccessor, 0, EJS_NO_LOCAL);
+ ejsDefineCAccessors(ep, op, "baseClass", classGetAccessor, 0, EJS_NO_LOCAL);
+
+ /*
+ * MOB -- make this an accessor
+ */
+ protoProp = ejsSetProperty(ep, op, "prototype", op);
+ if (protoProp == 0) {
+ ejsFreeVar(ep, op);
+ return MPR_ERR_CANT_CREATE;
+ }
+
+ /*
+ * Setup the internal methods. Most classes will never override these.
+ * The XML class will. We rely on talloc to free internal. Use "ep" as
+ * the parent as we need "methods" to live while the interpreter lives.
+ */
+ methods = mprAllocTypeZeroed(ep, EjsMethods);
+ op->objectState->methods = methods;
+
+ methods->createProperty = createObjProperty;
+ methods->deleteProperty = deleteObjProperty;
+ methods->getProperty = getObjProperty;
+ methods->setProperty = setObjProperty;
+
+ objectProp = ejsSetPropertyAndFree(ep, ep->global, "Object", op);
+
+ /*
+ * Change the global class to use Object's methods
+ */
+ globalClass = ep->service->globalClass;
+ globalClass->objectState->methods = methods;
+ globalClass->objectState->baseClass = ejsGetVarPtr(protoProp);
+
+ ep->objectClass = ejsGetVarPtr(objectProp);
+
+ if (ejsObjHasErrors(ejsGetVarPtr(objectProp))) {
+ ejsFreeVar(ep, op);
+ return MPR_ERR_CANT_CREATE;
+ }
+ return 0;
+}
+
+/******************************************************************************/
+
+#else
+void ejsObjectDummy() {}
+
+/******************************************************************************/
+#endif /* BLD_FEATURE_EJS */
+
+/*
+ * 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-2.0/ejs/classes/ejsStndClasses.c b/source4/lib/appweb/ejs-2.0/ejs/classes/ejsStndClasses.c
new file mode 100644
index 0000000000..fd6cda7813
--- /dev/null
+++ b/source4/lib/appweb/ejs-2.0/ejs/classes/ejsStndClasses.c
@@ -0,0 +1,144 @@
+/*
+ * @file ejsStndClasses.c
+ * @brief EJS support methods
+ */
+/********************************* Copyright **********************************/
+/*
+ * @copy default
+ *
+ * Copyright (c) Mbedthis Software LLC, 2003-2006. 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
+ */
+/********************************** Includes **********************************/
+
+#include "ejs.h"
+
+#if BLD_FEATURE_EJS
+
+/******************************************************************************/
+/******************************* Function Class *******************************/
+/******************************************************************************/
+
+int ejsDefineFunctionClass(Ejs *ep)
+{
+ if (ejsDefineClass(ep, "Function", "Object", ejsFunctionConstructor) == 0) {
+ return MPR_ERR_CANT_INITIALIZE;
+ }
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * Function constructor
+ */
+
+int ejsFunctionConstructor(Ejs *ep, EjsVar *thisObj, int argc, EjsVar **argv)
+{
+ int rc;
+
+ if (argc != 1 || !ejsVarIsString(argv[0])) {
+ ejsArgError(ep, "Usage: Function(\"function (arg) { script };\");");
+ }
+
+ rc = ejsEvalScript(ep, argv[0]->string, 0);
+
+ /*
+ * Note: this will convert the object into a method. It will cease to be
+ * an object.
+ */
+ if (rc == 0 && ejsVarIsMethod(ep->result)) {
+ /*
+ * Must make thisObj collectable.
+ */
+ ejsMakeObjPermanent(thisObj, 0);
+ ejsMakeObjLive(thisObj, 1);
+ mprAssert(ejsObjIsCollectable(thisObj));
+ ejsWriteVar(ep, thisObj, ep->result, EJS_SHALLOW_COPY);
+ }
+ return rc;
+}
+
+/******************************************************************************/
+/******************************* Boolean Class ********************************/
+/******************************************************************************/
+
+int ejsDefineBooleanClass(Ejs *ep)
+{
+ if (ejsDefineClass(ep, "Boolean", "Object", ejsBooleanConstructor) == 0){
+ return MPR_ERR_CANT_INITIALIZE;
+ }
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * Boolean constructor
+ */
+
+int ejsBooleanConstructor(Ejs *ep, EjsVar *thisObj, int argc, EjsVar **argv)
+{
+ return 0;
+}
+
+/******************************************************************************/
+/******************************** Number Class ********************************/
+/******************************************************************************/
+
+int ejsDefineNumberClass(Ejs *ep)
+{
+ if (ejsDefineClass(ep, "Number", "Object", ejsNumberConstructor) == 0) {
+ return MPR_ERR_CANT_INITIALIZE;
+ }
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * Number constructor
+ */
+
+int ejsNumberConstructor(Ejs *ep, EjsVar *thisObj, int argc, EjsVar **argv)
+{
+ return 0;
+}
+
+/******************************************************************************/
+
+#else
+void ejsStndClassesDummy() {}
+
+/******************************************************************************/
+#endif /* BLD_FEATURE_EJS */
+
+/*
+ * 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-2.0/ejs/classes/ejsString.c b/source4/lib/appweb/ejs-2.0/ejs/classes/ejsString.c
new file mode 100644
index 0000000000..2339650361
--- /dev/null
+++ b/source4/lib/appweb/ejs-2.0/ejs/classes/ejsString.c
@@ -0,0 +1,381 @@
+/*
+ * @file ejsString.c
+ * @brief EJScript string class
+ */
+/********************************* Copyright **********************************/
+/*
+ * @copy default
+ *
+ * Copyright (c) Mbedthis Software LLC, 2003-2006. 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
+ */
+/********************************** Includes **********************************/
+
+#include "ejs.h"
+
+#if BLD_FEATURE_EJS
+/******************************************************************************/
+/*********************************** Constructors *****************************/
+/******************************************************************************/
+/*
+ * String constructor.
+ */
+
+int ejsStringConstructor(Ejs *ejs, EjsVar *thisObj, int argc, EjsVar **argv)
+{
+ char *str;
+
+ if (argc == 0) {
+ ejsSetReturnValueToString(ejs, "");
+
+ } else if (argc == 1) {
+ /* MOB -- rc */
+ str = ejsVarToString(ejs, argv[0]);
+ ejsSetReturnValueToString(ejs, str);
+
+ } else {
+ ejsArgError(ejs, "usage: String([var])");
+ return -1;
+ }
+
+ return 0;
+}
+
+/******************************************************************************/
+/******************************** Visible Methods *****************************/
+/******************************************************************************/
+/*
+ * Return a string containing the character at a given index
+ *
+ * String string.charAt(Number)
+ */
+
+static int charAt(Ejs *ejs, EjsVar *thisObj, int argc, EjsVar **argv)
+{
+ EjsNum num;
+ char buf[2];
+
+ if (argc != 1) {
+ ejsArgError(ejs, "usage: charAt(integer)");
+ return -1;
+ }
+
+ num = ejsVarToNumber(argv[0]);
+ if (num < 0 || num >= thisObj->length) {
+ ejsError(ejs, EJS_RANGE_ERROR, "Bad index");
+ return -1;
+ }
+
+ mprAssert(ejsVarIsString(thisObj));
+
+ buf[0] = argv[0]->string[num];
+ buf[1] = '\0';
+ ejsSetReturnValueToString(ejs, buf);
+
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * Return an integer containing the character at a given index
+ *
+ * Number string.charCodeAt(Number)
+ */
+
+static EjsNum charCodeAt(Ejs *ejs, EjsVar *thisObj, int argc, EjsVar **argv)
+{
+ EjsNum num;
+
+ if (argc != 1) {
+ ejsArgError(ejs, "usage: charCodeAt(integer)");
+ return -1;
+ }
+
+ num = ejsVarToNumber(argv[0]);
+ if (num < 0 || num >= thisObj->length) {
+ ejsError(ejs, EJS_RANGE_ERROR, "Bad index");
+ return -1;
+ }
+ ejsSetReturnValueToNumber(ejs, (EjsNum) argv[0]->string[num]);
+
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * Catenate
+ *
+ * String string.catenate(var, ...)
+ */
+
+static int concat(Ejs *ejs, EjsVar *thisObj, int argc, EjsVar **argv)
+{
+ int i;
+
+ if (argc == 0) {
+ ejsArgError(ejs, "usage: concat(String, ...)");
+ return -1;
+ }
+
+ mprAssert(ejsVarIsString(thisObj));
+
+ for (i = 0; i < argc; i++) {
+ if (ejsStrcat(ejs, thisObj, argv[i]) < 0) {
+ ejsMemoryError(ejs);
+ return -1;
+ }
+ }
+ ejsSetReturnValue(ejs, thisObj);
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * Return the position of the first occurance of a substring
+ *
+ * Number string.indexOf(String subString [, Number start])
+ */
+
+static int indexOf(Ejs *ejs, EjsVar *thisObj, int argc, EjsVar **argv)
+{
+ char *pat, *s1, *s2, *origin;
+ int start, i;
+
+ if (argc == 0 || argc > 2) {
+ ejsArgError(ejs, "usage: indexOf(String [, Number])");
+ return -1;
+ }
+
+ pat = ejsVarToString(ejs, argv[0]);
+
+ if (argc == 2) {
+ start = ejsVarToNumber(argv[1]);
+ if (start > thisObj->length) {
+ start = thisObj->length;
+ }
+ } else {
+ start = 0;
+ }
+
+ i = start;
+ for (origin = &thisObj->string[i]; i < thisObj->length; i++, origin++) {
+ s1 = origin;
+ for (s2 = pat; *s1 && *s2; s1++, s2++) {
+ if (*s1 != *s2) {
+ break;
+ }
+ }
+ if (*s2 == '\0') {
+ ejsSetReturnValueToNumber(ejs, (EjsNum) (origin - thisObj->string));
+ }
+ }
+
+ ejsSetReturnValueToNumber(ejs, (EjsNum) -1);
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * Return the position of the last occurance of a substring
+ *
+ * Number string.lastIndexOf(String subString [, Number start])
+ */
+
+static int lastIndexOf(Ejs *ejs, EjsVar *thisObj, int argc, EjsVar **argv)
+{
+ char *pat, *s1, *s2, *origin;
+ int start;
+
+ if (argc == 0 || argc > 2) {
+ ejsArgError(ejs, "usage: indexOf(String [, Number])");
+ return -1;
+ }
+
+ pat = ejsVarToString(ejs, argv[0]);
+
+ if (argc == 2) {
+ start = ejsVarToNumber(argv[1]);
+ if (start > thisObj->length) {
+ start = thisObj->length;
+ }
+ } else {
+ start = 0;
+ }
+
+ origin = &thisObj->string[thisObj->length - 1];
+ for (; origin >= &thisObj->string[start]; origin--) {
+
+ s1 = origin;
+ for (s2 = pat; *s1 && *s2; s1++, s2++) {
+ if (*s1 != *s2) {
+ break;
+ }
+ }
+ if (*s2 == '\0') {
+ ejsSetReturnValueToNumber(ejs, (EjsNum) (origin - thisObj->string));
+ }
+ }
+
+ ejsSetReturnValueToNumber(ejs, (EjsNum) -1);
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * Return a substring
+ *
+ * Number string.slice(Number start, Number end)
+ */
+
+static int slice(Ejs *ejs, EjsVar *thisObj, int argc, EjsVar **argv)
+{
+ EjsNum start, end;
+
+ if (argc != 2) {
+ ejsArgError(ejs, "usage: slice(Number, Number)");
+ return -1;
+ }
+
+ start = ejsVarToNumber(argv[0]);
+ end = ejsVarToNumber(argv[1]);
+ if (start < 0 || start >= thisObj->length) {
+ ejsError(ejs, EJS_RANGE_ERROR, "Bad start index");
+ return-1;
+ }
+ if (end < 0 || end >= thisObj->length) {
+ ejsError(ejs, EJS_RANGE_ERROR, "Bad end index");
+ return -1;
+ }
+
+ mprAssert(ejsVarIsString(thisObj));
+
+ ejsSetReturnValueToBinaryString(ejs, (uchar*) &thisObj->string[start],
+ end - start);
+
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * Split a string
+ *
+ * Number string.split(String delimiter [, Number limit])
+ */
+
+static int split(Ejs *ejs, EjsVar *thisObj, int argc, EjsVar **argv)
+{
+ EjsVar *array, *vp;
+ char *delim, *last, *cp;
+ int len, limit, alloc;
+
+ if (argc == 0 || argc > 2) {
+ ejsArgError(ejs, "usage: split(String [, Number])");
+ return -1;
+ }
+
+ delim = ejsVarToStringEx(ejs, argv[0], &alloc);
+
+ limit = ejsVarToNumber(argv[1]);
+
+ array = ejsCreateArray(ejs, 0);
+
+ len = strlen(delim);
+
+ last = thisObj->string;
+ for (cp = last; *cp; cp++) {
+ if (*cp == *delim && strncmp(cp, delim, len) == 0) {
+ if (cp > last) {
+ vp = ejsCreateBinaryStringVar(ejs, (uchar*) last, (cp - last));
+ ejsAddArrayElt(ejs, array, vp, EJS_SHALLOW_COPY);
+ ejsFreeVar(ejs, vp);
+ }
+ }
+ }
+
+ ejsSetReturnValue(ejs, array);
+ ejsFreeVar(ejs, array);
+
+ if (alloc) {
+ mprFree(delim);
+ }
+
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * Create the object class
+ */
+
+int ejsDefineStringClass(Ejs *ejs)
+{
+ EjsVar *sc;
+
+ sc = ejsDefineClass(ejs, "String", "Object", ejsStringConstructor);
+ if (sc == 0) {
+ return MPR_ERR_CANT_INITIALIZE;
+ }
+
+ ejsDefineCMethod(ejs, sc, "charAt", charAt, EJS_NO_LOCAL);
+ ejsDefineCMethod(ejs, sc, "charCodeAt", charCodeAt, EJS_NO_LOCAL);
+ ejsDefineCMethod(ejs, sc, "concat", concat, EJS_NO_LOCAL);
+ ejsDefineCMethod(ejs, sc, "indexOf", indexOf, EJS_NO_LOCAL);
+ ejsDefineCMethod(ejs, sc, "lastIndexOf", lastIndexOf, EJS_NO_LOCAL);
+ ejsDefineCMethod(ejs, sc, "slice", slice, EJS_NO_LOCAL);
+ ejsDefineCMethod(ejs, sc, "split", split, EJS_NO_LOCAL);
+#if UNUSED
+ ejsDefineCMethod(ejs, sc, "match", match, EJS_NO_LOCAL);
+ ejsDefineCMethod(ejs, sc, "replace", replace, EJS_NO_LOCAL);
+ ejsDefineCMethod(ejs, sc, "search", search, EJS_NO_LOCAL);
+ ejsDefineCMethod(ejs, sc, "substring", substring, EJS_NO_LOCAL);
+ // MOB bad name
+ ejsDefineCMethod(ejs, sc, "substr", substr, EJS_NO_LOCAL);
+ ejsDefineCMethod(ejs, sc, "toLowerCase", toLowerCase, EJS_NO_LOCAL);
+ ejsDefineCMethod(ejs, sc, "toUpperCase", toUpperCase, EJS_NO_LOCAL);
+
+ // Static method
+ ejsDefineCMethod(ejs, sc, "fromCharCode", fromCharCode, 0, EJS_NO_LOCAL);
+#endif
+
+ if (ejsObjHasErrors(sc)) {
+ ejsFreeVar(ejs, sc);
+ return MPR_ERR_CANT_CREATE;
+ }
+ return 0;
+}
+
+/******************************************************************************/
+#endif /* BLD_FEATURE_EJS */
+
+/*
+ * 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-2.0/ejs/classes/ejsXml.c b/source4/lib/appweb/ejs-2.0/ejs/classes/ejsXml.c
new file mode 100644
index 0000000000..a2ef8d1390
--- /dev/null
+++ b/source4/lib/appweb/ejs-2.0/ejs/classes/ejsXml.c
@@ -0,0 +1,1327 @@
+/*
+ * @file ejsXml.c
+ * @brief E4X XML support
+ */
+/********************************* Copyright **********************************/
+/*
+ * @copy default
+ *
+ * Copyright (c) Mbedthis Software LLC, 2003-2006. 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
+ */
+/************************************ Doc *************************************/
+/*
+ * Javascript class definition
+ *
+ * class XML {
+ * public XML();
+ * public XML(string xmlString); // "<tag... "
+ * public XML(string file); // "file"
+ *
+ * public void load(string file);
+ * public void save(string file);
+ * public Array children();
+ * public Array attributes();
+ * }
+ *
+ [[Internal Properties / Methods]]
+ - prototype - Ptr to class prototype (base class)
+ - class - Type of class
+ Object.prototype.toString
+ - Value -
+ - Get(name) - Returns the value
+ - Put(name, value) - Sets the value
+ - HasProperty(name) - Bool if property exists
+ - Delete(name) - Delete property
+ - DefaultValue(hint) - Return default primitive (not obj) value
+ toString, if result is obj, then call valueOf
+ if hint is number, then call valueOf, then toString
+ - Construct(arg list) - Constructor
+ - Call(arg list) - Function call
+ - HasInstance(value) - ??
+ - Scope - Frame scope chain
+ - Match(string, index) - Regexp match
+
+ - Example:
+ XML attribute @name
+ @*
+ *
+ var node = new XML("<order/>");
+ Operators:
+ var prices = order..price;
+ var urgentItems = order.item(@level == "rush");
+ var itemAttrs = order.item[0].@*; # @ for attributes
+ XML Literals
+ order.customer.address =
+ <address>.....
+ <zip>{zipCode}</zip> Where {var} is a JS var
+ <tag attribute={prefix}> ... Also for attributes
+ </address>
+ Omit namespaces
+ Example:
+ var html = <html/>;
+ html.head.title = "My title";
+ head.body@bgcolor = "#e4e4e4";
+*/
+
+/********************************** Includes **********************************/
+
+#include "ejs.h"
+#include "exml.h"
+
+/************************************ Data ************************************/
+#if BLD_FEATURE_EJS_E4X
+
+/*
+ * Per tag state
+ */
+typedef struct XmlTagState {
+ EjsVar *obj;
+ EjsVar *attributes;
+ EjsVar *comments;
+} XmlTagState;
+
+/*
+ * Parser state
+ */
+typedef struct XmlState {
+ Ejs *ep;
+ EjsVar *xmlClass;
+ EjsVar *xmlListClass;
+ XmlTagState nodeStack[E4X_MAX_NODE_DEPTH];
+ int topOfStack;
+ long inputSize;
+ long inputPos;
+ const char *inputBuf;
+ const char *fileName;
+} XmlState;
+
+/****************************** Forward Declarations **************************/
+/*
+ * XML methods
+ */
+static int text(Ejs *ep, EjsVar *thisObj, int argc, EjsVar **argv);
+static int name(Ejs *ep, EjsVar *thisObj, int argc, EjsVar **argv);
+static int load(Ejs *ep, EjsVar *thisObj, int argc, EjsVar **argv);
+static int save(Ejs *ep, EjsVar *thisObj, int argc, EjsVar **argv);
+static int toString(Ejs *ep, EjsVar *thisObj, int argc, EjsVar **argv);
+static int valueOf(Ejs *ep, EjsVar *thisObj, int argc, EjsVar **argv);
+
+/* MOB -- temp */
+static int getList(Ejs *ep, EjsVar *thisObj, int argc, EjsVar **argv);
+static int setText(Ejs *ep, EjsVar *thisObj, int argc, EjsVar **argv);
+
+#if FUTURE
+static int length(Ejs *ep, EjsVar *thisObj, int argc, EjsVar **argv);
+static int toXmlString(Ejs *ep, EjsVar *thisObj, int argc, EjsVar **argv);
+
+static int appendChild(Ejs *ep, EjsVar *thisObj, int argc, EjsVar **argv);
+static int attributes(Ejs *ep, EjsVar *thisObj, int argc, EjsVar **argv);
+static int child(Ejs *ep, EjsVar *thisObj, int argc, EjsVar **argv);
+static int children(Ejs *ep, EjsVar *thisObj, int argc, EjsVar **argv);
+static int comments(Ejs *ep, EjsVar *thisObj, int argc, EjsVar **argv);
+static int decendants(Ejs *ep, EjsVar *thisObj, int argc, EjsVar **argv);
+static int elements(Ejs *ep, EjsVar *thisObj, int argc, EjsVar **argv);
+static int insertChildAfter(Ejs *ep, EjsVar *thisObj, int argc, EjsVar **argv);
+static int insertChildBefore(Ejs *ep, EjsVar *thisObj, int argc,
+ EjsVar **argv);
+static int replace(Ejs *ep, EjsVar *thisObj, int argc, EjsVar **argv);
+static int setName(Ejs *ep, EjsVar *thisObj, int argc, EjsVar **argv);
+static int text(Ejs *ep, EjsVar *thisObj, int argc, EjsVar **argv);
+#endif
+
+/*
+ * Internal methods
+ */
+static EjsVar *createXmlProperty(Ejs *ep, EjsVar *obj, const char *property);
+static int deleteXmlProperty(Ejs *ep, EjsVar *obj, const char *property);
+static EjsVar *getXmlProperty(Ejs *ep, EjsVar *obj, const char *property);
+static EjsVar *setXmlProperty(Ejs *ep, EjsVar *obj, const char *property,
+ const EjsVar *value);
+static int loadXmlString(Ejs *ep, EjsVar *thisObj, const char *xmlString);
+
+/*
+ * XMLList methods
+ */
+static EjsVar *createXmlListProperty(Ejs *ep, EjsVar *obj,
+ const char *property);
+static int deleteXmlListProperty(Ejs *ep, EjsVar *obj,
+ const char *property);
+static EjsVar *getXmlListProperty(Ejs *ep, EjsVar *obj, const char *property);
+static EjsVar *setXmlListProperty(Ejs *ep, EjsVar *obj, const char *property,
+ const EjsVar *value);
+
+/*
+ * Misc
+ */
+static int readFileData(Exml *xp, void *data, char *buf, int size);
+static int readStringData(Exml *xp, void *data, char *buf, int size);
+static int parserHandler(Exml *xp, int state, const char *tagName,
+ const char *attName, const char *value);
+static void termParser(Exml *xp);
+static Exml *initParser(Ejs *ep, EjsVar *thisObj, const char *fileName);
+static int getNumElements(EjsVar *obj);
+static int getText(MprBuf *buf, EjsVar *obj);
+static int xmlToString(Ejs *ep, MprBuf *buf, EjsVar *obj, int indentLevel);
+static void indent(MprBuf *bp, int level);
+static char *cleanTagName(char *name);
+
+/******************************************************************************/
+/*
+ * Define the E4X classes (XML, XMLList)
+ */
+
+int ejsDefineXmlClasses(Ejs *ep)
+{
+ EjsMethods *methods;
+ EjsVar *xmlClass, *xmlListClass;
+
+ /*
+ * Create the XML class
+ */
+ xmlClass = ejsDefineClass(ep, "XML", "Object", ejsXmlConstructor);
+ if (xmlClass == 0) {
+ return MPR_ERR_CANT_INITIALIZE;
+ }
+
+ /*
+ * Define the XML class methods
+ */
+ ejsDefineCMethod(ep, xmlClass, "text", text, EJS_NO_LOCAL);
+ ejsDefineCMethod(ep, xmlClass, "name", name, EJS_NO_LOCAL);
+ ejsDefineCMethod(ep, xmlClass, "load", load, EJS_NO_LOCAL);
+ ejsDefineCMethod(ep, xmlClass, "save", save, EJS_NO_LOCAL);
+ ejsDefineCMethod(ep, xmlClass, "toString", toString, EJS_NO_LOCAL);
+ ejsDefineCMethod(ep, xmlClass, "valueOf", valueOf, EJS_NO_LOCAL);
+
+/* MOB -- temporary only */
+ ejsDefineCMethod(ep, xmlClass, "getList", getList, EJS_NO_LOCAL);
+ ejsDefineCMethod(ep, xmlClass, "setText", setText, EJS_NO_LOCAL);
+
+ /*
+ * Setup the XML internal methods.
+ */
+ methods = mprAllocTypeZeroed(ep, EjsMethods);
+ xmlClass->objectState->methods = methods;
+
+ methods->createProperty = createXmlProperty;
+ methods->deleteProperty = deleteXmlProperty;
+ methods->getProperty = getXmlProperty;
+ methods->setProperty = setXmlProperty;
+
+ /*
+ * Create the XMLList class
+ */
+ xmlListClass = ejsDefineClass(ep, "XMLList", "Array",
+ ejsXmlListConstructor);
+
+ /*
+ * Define the XMLList class methods
+ */
+
+ /*
+ * Setup the XML internal methods.
+ */
+ methods = mprAllocTypeZeroed(ep, EjsMethods);
+ xmlListClass->objectState->methods = methods;
+
+ methods->createProperty = createXmlListProperty;
+ methods->deleteProperty = deleteXmlListProperty;
+ methods->getProperty = getXmlListProperty;
+ methods->setProperty = setXmlListProperty;
+
+ /* MOB -- need to complete xmlListClass */
+
+ return (ejsObjHasErrors(xmlClass) || ejsObjHasErrors(xmlListClass))
+ ? MPR_ERR_CANT_INITIALIZE : 0;
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * Routine to create an XML object using a default constructor
+ */
+
+EjsVar *ejsCreateXml(Ejs *ep)
+{
+ EjsVar *op;
+
+ op = ejsCreateSimpleObj(ep, "XML");
+ if (op == 0) {
+ mprAssert(op);
+ return op;
+ }
+ ejsSetVarName(ep, op, "xmlNode");
+
+ /*
+ * Invoke class constructors manually (for speed and space)
+ */
+ if (ejsXmlConstructor(ep, op, 0, 0) < 0) {
+ mprFree(op);
+ mprAssert(0);
+ return 0;
+ }
+ return op;
+}
+
+/******************************************************************************/
+/*
+ * XML constructor
+ */
+
+int ejsXmlConstructor(Ejs *ep, EjsVar *thisObj, int argc, EjsVar **argv)
+{
+ EjsVar *vp;
+ const char *str;
+
+ ejsSetVarFlags(thisObj, EJS_XML_FLAGS_ELEMENT);
+
+ if (argc == 1) {
+ vp = argv[0];
+
+ if (ejsVarIsObject(vp)) {
+ /* Convert DOM to XML. Not implemented */;
+
+ } else if (ejsVarIsString(vp)) {
+ str = vp->string;
+ if (str == 0) {
+ return 0;
+ }
+ if (*str == '<') {
+ /* XML Literal */
+ return loadXmlString(ep, thisObj, str);
+
+ } else {
+ /* Load from file */
+ return load(ep, thisObj, argc, argv);
+ }
+ } else {
+ ejsError(ep, EJS_TYPE_ERROR, "Bad type passed to XML constructor");
+ return -1;
+ }
+ }
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * Routine to create an XMLList object
+ */
+
+EjsVar *ejsCreateXmlList(Ejs *ep)
+{
+ EjsVar *op;
+
+ /* Sanity limit for size of hash table */
+
+ op = ejsCreateSimpleObj(ep, "XMLList");
+ if (op == 0) {
+ mprAssert(0);
+ return op;
+ }
+ if (ejsArrayConstructor(ep, op, 0, 0) < 0 ||
+ ejsXmlConstructor(ep, op, 0, 0) < 0) {
+ mprFree(op);
+ mprAssert(0);
+ return 0;
+ }
+ return op;
+}
+
+/******************************************************************************/
+/*
+ * XMLList constructor
+ */
+
+int ejsXmlListConstructor(Ejs *ep, EjsVar *thisObj, int argc, EjsVar **argv)
+{
+ // ejsSetVarFlags(vp, EJS_XML_FLAGS_ELEMENT);
+ return 0;
+}
+
+/******************************************************************************/
+/******************************** Internal Methods ****************************/
+/******************************************************************************/
+
+static EjsVar *createXmlProperty(Ejs *ep, EjsVar *obj, const char *property)
+{
+ return ejsGetVarPtr(ejsCreateSimpleProperty(ep, obj, property));
+}
+
+/******************************************************************************/
+
+static int deleteXmlProperty(Ejs *ep, EjsVar *obj, const char *property)
+{
+ return ejsDeleteProperty(ep, obj, property);
+}
+
+/******************************************************************************/
+/* MOB -- need ep as an arg */
+static EjsVar *getXmlProperty(Ejs *ep, EjsVar *obj, const char *property)
+{
+#if NEW
+ EjsVar *lp;
+
+ lp = ejsCreateXmlList(ep);
+ if (isdigit(*property)) {
+ /* MOB -- where do we store these. Do we need them ? */
+ lp->targetObject = obj
+ lp->targetProperty = property
+ return getXmlListProperty(lp, property);
+ }
+
+ /* What about a simple elment. Should it not return the text */
+
+ if (*property == '@') {
+ ap = ejsGetFirstProperty(obj, EJS_ENUM_ALL);
+ while (ap) {
+ vp = ejsGetVarPtr(ap);
+ /* MOB -- are attributes unique ? */
+ if (vp->flags & EJS_XML_FLAGS_ATTRIBUTE &&
+ strcmp(property, ap->name) == 0) {
+ ejsAppendXml(lp, vp);
+ }
+ ap = ejsGetNexttProperty(ap, EJS_ENUM_ALL);
+ }
+ } else {
+ while (ap) {
+ vp = ejsGetVarPtr(ap);
+ /* MOB -- are attributes unique ? */
+ if (vp->flags & EJS_XML_FLAGS_ELEMENT &&
+ strcmp(property, ap->name) == 0) {
+ ejsAppendXml(lp, vp);
+ }
+ ap = ejsGetNexttProperty(ap, EJS_ENUM_ALL);
+ }
+ }
+ return l;
+
+ // Must always return XML or XMLList event for comments and attributes
+#endif
+ return ejsGetVarPtr(ejsGetSimpleProperty(ep, obj, property));
+}
+
+/******************************************************************************/
+
+static EjsVar *setXmlProperty(Ejs *ep, EjsVar *obj, const char *property,
+ const EjsVar *value)
+{
+ EjsProperty *pp;
+ EjsVar *vp;
+
+ pp = ejsCreateSimpleProperty(ep, obj, property);
+ if (pp == 0) {
+ /* Should never happen */
+ mprAssert(pp);
+ return 0;
+ }
+ vp = ejsGetVarPtr(pp);
+ if (ejsWriteVar(ep, vp, value, EJS_SHALLOW_COPY) < 0) {
+ return 0;
+ }
+ return ejsGetVarPtr(pp);
+}
+
+/******************************************************************************/
+/*
+ NEW
+
+static EjsVar *setXmlProperty(Ejs *ep, EjsVar *op, const char *property,
+ EjsVar *value)
+{
+
+ if ((value->objectState->baseClass != XML &&
+ value->objectState->baseClass != XMLList) ||
+ value->string[0] != '<') {
+ ejsVarToString(luevalue.toString();
+ ejsRunMethod(ep, value, "toString", 0);
+ value = ejsDupVar(ep->result);
+
+ } else {
+ value = ejsDupVar(value);
+ }
+
+ if (isdigit(*property)) {
+ // ERROR -- reserved for future versions
+ return 0;
+ }
+
+ if (*property == '@') {
+ if (op->objectState->baseClass == XMLList) {
+ if (op->obj.LENGTH_PROPERTY == 0) {
+ c = "";
+ } else {
+ // Catenate all result of toString on all elts in list
+ }
+ } else {
+ c = c.toString();
+ }
+ // Replace existing attribute of same name or insert
+ return;
+ }
+ for (i = op->obj.LENGTH - 1; i >= 0; i--) {
+ // Delete item of same name
+ }
+ if (not Found) {
+ Append new Xml object
+ - set [[name]], [[class]] == "element"
+ }
+
+ mprFree(value);
+}
+
+ */
+/******************************************************************************/
+/************************************ Methods *********************************/
+/******************************************************************************/
+
+static int load(Ejs *ep, EjsVar *thisObj, int argc, EjsVar **argv)
+{
+ const char *fileName;
+ XmlState *parser;
+ Exml *xp;
+ MprFile *file;
+
+ if (argc != 1 || !ejsVarIsString(argv[0])) {
+ ejsError(ep, EJS_ARG_ERROR, "Bad args. Usage: load(fileName);");
+ return -1;
+ }
+ fileName = argv[0]->string;
+
+ /* MOB -- not romable
+ Need rom code in MPR not MprServices
+ */
+ file = mprOpen(ep, fileName, O_RDONLY, 0664);
+ if (file == 0) {
+ ejsError(ep, EJS_IO_ERROR, "Can't open: %s", fileName);
+ return -1;
+ }
+
+ /* MOB -- should we empty thisObj of all existing properties ? */
+
+ xp = initParser(ep, thisObj, fileName);
+ parser = exmlGetParseArg(xp);
+
+ exmlSetInputStream(xp, readFileData, (void*) file);
+
+ if (exmlParse(xp) < 0) {
+ if (! ejsGotException(ep)) {
+ ejsError(ep, EJS_IO_ERROR, "Can't parse XML file: %s\nDetails %s",
+ fileName, exmlGetErrorMsg(xp));
+ }
+ termParser(xp);
+ mprClose(file);
+ return -1;
+ }
+
+ ejsSetReturnValue(ep, parser->nodeStack[0].obj);
+
+ termParser(xp);
+ mprClose(file);
+
+ return 0;
+}
+
+/******************************************************************************/
+
+static int loadXmlString(Ejs *ep, EjsVar *thisObj, const char *xmlString)
+{
+ XmlState *parser;
+ Exml *xp;
+
+ xp = initParser(ep, thisObj, "string");
+ parser = exmlGetParseArg(xp);
+
+ parser->inputBuf = xmlString;
+ parser->inputSize = strlen(xmlString);
+
+ exmlSetInputStream(xp, readStringData, (void*) 0);
+
+ if (exmlParse(xp) < 0) {
+ if (! ejsGotException(ep)) {
+ ejsError(ep, EJS_IO_ERROR, "Can't parse XML string\nError %s",
+ exmlGetErrorMsg(xp));
+ }
+ termParser(xp);
+ return -1;
+ }
+
+ ejsSetReturnValue(ep, parser->nodeStack[0].obj);
+
+ termParser(xp);
+
+ return 0;
+}
+
+/******************************************************************************/
+
+static int text(Ejs *ep, EjsVar *thisObj, int argc, EjsVar **argv)
+{
+ EjsVar *vp;
+
+ vp = ejsGetVarPtr(ejsGetSimpleProperty(ep, thisObj, E4X_TEXT_PROPERTY));
+ if (vp == 0) {
+ ejsSetReturnValueToString(ep, "");
+ return 0;
+ }
+ ejsSetReturnValue(ep, vp);
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * Return the tag name
+ */
+
+static int name(Ejs *ep, EjsVar *thisObj, int argc, EjsVar **argv)
+{
+ EjsVar *vp;
+
+ vp = ejsGetVarPtr(ejsGetSimpleProperty(ep, thisObj, E4X_TAG_NAME_PROPERTY));
+ if (vp == 0) {
+ ejsSetReturnValueToString(ep, "");
+ return 0;
+ }
+ ejsSetReturnValue(ep, vp);
+#if UNDEFINED
+ char *name;
+ /* MOB -- not ideal as we can't guarantee thisObj is a property */
+ name = ejsGetPropertyPtr(thisObj)->name;
+ if (name == 0) {
+ name = "";
+ }
+ ejsSetReturnValueToString(ep, name);
+#endif
+ return 0;
+}
+
+/******************************************************************************/
+/* MOB -- temporary only */
+
+static int setText(Ejs *ep, EjsVar *thisObj, int argc, EjsVar **argv)
+{
+ if (argc != 1) {
+ ejsArgError(ep, "usage: setText(string)");
+ }
+
+ ejsSetProperty(ep, thisObj, E4X_TEXT_PROPERTY, argv[0]);
+ ejsSetReturnValue(ep, argv[0]);
+ return 0;
+}
+
+/******************************************************************************/
+
+static Exml *initParser(Ejs *ep, EjsVar *thisObj, const char *fileName)
+{
+ XmlState *parser;
+ Exml *xp;
+
+ xp = exmlOpen(ep, 512, E4X_BUF_MAX);
+ mprAssert(xp);
+
+ /*
+ * Create the parser stack
+ */
+ parser = mprAllocTypeZeroed(ep, XmlState);
+ parser->ep = ep;
+ parser->nodeStack[0].obj = thisObj;
+ parser->xmlClass = ejsGetClass(ep, 0, "XML");
+ parser->xmlListClass = ejsGetClass(ep, 0, "XMLList");
+ parser->fileName = fileName;
+
+ exmlSetParseArg(xp, parser);
+ exmlSetParserHandler(xp, parserHandler);
+
+ return xp;
+}
+
+/******************************************************************************/
+
+static void termParser(Exml *xp)
+{
+ mprFree(exmlGetParseArg(xp));
+ exmlClose(xp);
+}
+
+/******************************************************************************/
+/*
+ * XML parsing callback. Called for each elt and attribute/value pair.
+ * For speed, we handcraft the object model here rather than calling
+ * putXmlProperty.
+ *
+ * "<!-- txt -->" parseHandler(efd, , EXML_COMMENT);
+ * "<elt" parseHandler(efd, , EXML_NEW_ELT);
+ * "...att=value" parseHandler(efd, , EXML_NEW_ATT);
+ * "<elt ...>" parseHandler(efd, , EXML_ELT_DEFINED);
+ * "<elt/>" parseHandler(efd, , EXML_SOLO_ELT_DEFINED);
+ * "<elt> ...<" parseHandler(efd, , EXML_ELT_DATA);
+ * "...</elt>" parseHandler(efd, , EXML_END_ELT);
+ *
+ * Note: we recurse on every new nested elt.
+ */
+
+static int parserHandler(Exml *xp, int state, const char *tagName,
+ const char *attName, const char *value)
+{
+ XmlState *parser;
+ XmlTagState *tos;
+ EjsVar *currentNode, *vp, *tagNode, *parent, *vpx;
+ EjsProperty *pp;
+ Ejs *ep;
+ char *name;
+
+ parser = (XmlState*) xp->parseArg;
+ ep = parser->ep;
+ tos = &parser->nodeStack[parser->topOfStack];
+ currentNode = tos->obj;
+
+ mprAssert(state >= 0);
+ mprAssert(tagName && *tagName);
+
+ switch (state) {
+ case EXML_PI:
+ /*
+ * By using a property name with a leading space, we can store
+ * non-user-visible processing instructions as regular properties.
+ */
+ pp = ejsCreateSimpleNonUniqueProperty(ep, currentNode, E4X_PI_PROPERTY);
+ ejsMakePropertyEnumerable(pp, 1);
+ vp = ejsGetVarPtr(pp);
+ ejsWriteVarAsString(ep, vp, value);
+ ejsSetVarFlags(vp, EJS_XML_FLAGS_PI);
+ break;
+
+ case EXML_COMMENT:
+ /*
+ * By using a property name with a leading space, we can store
+ * non- user-visible comments as regular properties.
+ */
+ pp = ejsCreateSimpleNonUniqueProperty(ep, currentNode,
+ E4X_COMMENT_PROPERTY);
+ ejsMakePropertyEnumerable(pp, 1);
+ vp = ejsGetVarPtr(pp);
+ ejsWriteVarAsString(ep, vp, value);
+ ejsSetVarFlags(vp, EJS_XML_FLAGS_COMMENT);
+ break;
+
+ case EXML_NEW_ELT:
+ if (parser->topOfStack > E4X_MAX_NODE_DEPTH) {
+ ejsError(ep, EJS_IO_ERROR,
+ "XML nodes nested too deeply in %s at line %d",
+ parser->fileName, exmlGetLineNumber(xp));
+ return MPR_ERR_BAD_SYNTAX;
+ }
+
+ name = mprStrdup(xp, tagName);
+ if (name == 0) {
+ return MPR_ERR_MEMORY;
+ }
+
+ if (cleanTagName(name) < 0) {
+ ejsError(ep, EJS_TYPE_ERROR, "Bad XML tag name in %s at %d",
+ parser->fileName, exmlGetLineNumber(xp));
+ mprFree(name);
+ return MPR_ERR_BAD_SYNTAX;
+ }
+
+ pp = ejsCreateSimpleNonUniqueProperty(ep, currentNode, name);
+ ejsMakePropertyEnumerable(pp, 1);
+
+ tagNode = ejsGetVarPtr(pp);
+
+ /* MOB -- OPT */
+ vpx = ejsCreateXml(ep);
+ vp = ejsWriteVar(ep, tagNode, vpx, EJS_SHALLOW_COPY);
+ ejsMakeObjLive(vp, 1);
+ ejsFreeVar(ep, vpx);
+
+ /* MOB -- return code */
+ pp = ejsSetPropertyToString(ep, vp, E4X_TAG_NAME_PROPERTY, name);
+ ejsMakePropertyEnumerable(pp, 0);
+
+ ejsSetVarFlags(vp, EJS_XML_FLAGS_ELEMENT);
+ ejsMakePropertyEnumerable(ejsGetPropertyPtr(vp), 1);
+
+ tos = &parser->nodeStack[++(parser->topOfStack)];
+ currentNode = tos->obj = vp;
+ tos->attributes = 0;
+ tos->comments = 0;
+ mprFree(name);
+ break;
+
+ case EXML_NEW_ATT:
+ if (mprAllocSprintf(MPR_LOC_ARGS(xp), &name, 0, "@%s", attName) < 0) {
+ return MPR_ERR_MEMORY;
+ }
+ pp = ejsCreateProperty(ep, currentNode, name);
+ ejsMakePropertyEnumerable(pp, 1);
+
+ vp = ejsGetVarPtr(pp);
+ ejsWriteVarAsString(ep, vp, value);
+ ejsSetVarFlags(vp, EJS_XML_FLAGS_ATTRIBUTE);
+ mprFree(name);
+ break;
+
+ case EXML_SOLO_ELT_DEFINED:
+ parser->topOfStack--;
+ mprAssert(parser->topOfStack >= 0);
+ tos = &parser->nodeStack[parser->topOfStack];
+ break;
+
+ case EXML_ELT_DEFINED:
+ if (parser->topOfStack > 0) {
+ parent = parser->nodeStack[parser->topOfStack - 1].obj;
+ ejsSetProperty(ep, currentNode, E4X_PARENT_PROPERTY, parent);
+ }
+ break;
+
+ case EXML_ELT_DATA:
+ case EXML_CDATA:
+ pp = ejsCreateSimpleNonUniqueProperty(ep, currentNode,
+ E4X_TEXT_PROPERTY);
+ ejsMakePropertyEnumerable(pp, 1);
+ vp = ejsGetVarPtr(pp);
+ ejsWriteVarAsString(ep, vp, value);
+ ejsSetVarFlags(vp, EJS_XML_FLAGS_TEXT);
+ break;
+
+ case EXML_END_ELT:
+ /*
+ * This is the closing element in a pair "<x>...</x>".
+ * Pop the stack frame off the elt stack
+ */
+ parser->topOfStack--;
+ mprAssert(parser->topOfStack >= 0);
+ tos = &parser->nodeStack[parser->topOfStack];
+ break;
+
+ default:
+ ejsError(ep, EJS_IO_ERROR, "XML error in %s at %d\nDetails %s",
+ parser->fileName, exmlGetLineNumber(xp), exmlGetErrorMsg(xp));
+ mprAssert(0);
+ return MPR_ERR_BAD_SYNTAX;
+ }
+ return 0;
+}
+
+/******************************************************************************/
+
+static char *cleanTagName(char *name)
+{
+ char *cp;
+
+ for (cp = name; *cp; cp++) {
+ if (*cp == ':') {
+ *cp = '_';
+ } else if (!isalnum(*cp) && *cp != '_' && *cp != '$' && *cp != '@') {
+ return 0;
+ }
+ }
+ return name;
+}
+
+/******************************************************************************/
+
+static int readFileData(Exml *xp, void *data, char *buf, int size)
+{
+ mprAssert(xp);
+ mprAssert(data);
+ mprAssert(buf);
+ mprAssert(size > 0);
+
+ return mprRead((MprFile*) data, buf, size);
+}
+
+/******************************************************************************/
+
+static int readStringData(Exml *xp, void *data, char *buf, int size)
+{
+ XmlState *parser;
+ int rc, len;
+
+ mprAssert(xp);
+ mprAssert(buf);
+ mprAssert(size > 0);
+
+ parser = (XmlState*) xp->parseArg;
+
+ if (parser->inputPos < parser->inputSize) {
+ len = min(size, (parser->inputSize - parser->inputPos));
+ rc = mprMemcpy(buf, size, &parser->inputBuf[parser->inputPos], len);
+ parser->inputPos += len;
+ return rc;
+ }
+ return 0;
+}
+
+/******************************************************************************/
+
+static int save(Ejs *ep, EjsVar *thisObj, int argc, EjsVar **argv)
+{
+ const char *fileName;
+ MprBuf *buf;
+ MprFile *file;
+ int bytes, len;
+
+ if (argc != 1 || !ejsVarIsString(argv[0])) {
+ ejsError(ep, EJS_ARG_ERROR, "Bad args. Usage: save(fileName);");
+ return -1;
+ }
+ fileName = argv[0]->string;
+
+ /* MOB -- not romable
+ Need rom code in MPR not MprServices
+ */
+
+ /*
+ * Convert to a string
+ */
+ buf = mprCreateBuf(ep, E4X_BUF_SIZE, E4X_BUF_MAX);
+ if (xmlToString(ep, buf, thisObj, -1) < 0) {
+ mprFree(buf);
+ return -1;
+ }
+
+ file = mprOpen(ep, fileName,
+ O_CREAT | O_TRUNC | O_WRONLY | O_TEXT, 0664);
+ if (file == 0) {
+ ejsError(ep, EJS_IO_ERROR, "Can't open: %s, %d", fileName,
+ mprGetOsError());
+ return -1;
+ }
+
+ len = mprGetBufLength(buf);
+ bytes = mprWrite(file, buf->start, len);
+ if (bytes != len) {
+ ejsError(ep, EJS_IO_ERROR, "Can't write to: %s", fileName);
+ mprClose(file);
+ return -1;
+ }
+ mprWrite(file, "\n", 1);
+ mprFree(buf);
+
+ mprClose(file);
+
+ return 0;
+}
+
+/******************************************************************************/
+
+static int toString(Ejs *ep, EjsVar *thisObj, int argc, EjsVar **argv)
+{
+ MprBuf *buf;
+
+ buf = mprCreateBuf(ep, E4X_BUF_SIZE, E4X_BUF_MAX);
+
+ if (xmlToString(ep, buf, thisObj, -1) < 0) {
+ mprFree(buf);
+ return -1;
+ }
+ ejsWriteVarAsString(ep, ep->result, (char*) buf->start);
+
+ mprFree(buf);
+
+ return 0;
+}
+
+/******************************************************************************/
+/* MOB -- need to support XMLList */
+
+static int xmlToString(Ejs *ep, MprBuf *buf, EjsVar *obj, int indentLevel)
+{
+ EjsProperty *pp;
+ EjsVar *vp;
+ char *varBuf;
+ int endTag, sawElements;
+
+ if (indentLevel < 0) {
+ mprPutStringToBuf(buf, "<?xml version=\"1.0\"?>");
+ }
+
+ switch (obj->type) {
+ case EJS_TYPE_STRING:
+ if (obj->flags & EJS_XML_FLAGS_ATTRIBUTE) {
+ mprPutFmtStringToBuf(buf, " %s=\"%s\"",
+ &ejsGetPropertyPtr(obj)->name[1], obj->string);
+ /* No new line */
+
+ } else if (obj->flags & EJS_XML_FLAGS_COMMENT) {
+ mprPutCharToBuf(buf, '\n');
+ indent(buf, indentLevel);
+ mprPutFmtStringToBuf(buf, "<!-- %s -->", obj->string);
+
+ } else if (obj->flags & EJS_XML_FLAGS_TEXT) {
+ mprPutStringToBuf(buf, obj->string);
+
+ } else {
+// indent(buf, indentLevel);
+ mprPutStringToBuf(buf, obj->string);
+// mprPutCharToBuf(buf, '\n');
+ }
+ break;
+
+ default:
+ /* Primitive types come here */
+ indent(buf, indentLevel);
+ /* MOB -- rc */
+ varBuf = ejsVarToString(ep, obj);
+ mprPutStringToBuf(buf, varBuf);
+ break;
+
+ case EJS_TYPE_OBJECT:
+ if (obj->objectState->baseClass == ejsGetClass(ep, 0, "XML")) {
+ if (!obj->objectState->visited) {
+ obj->objectState->visited = 1;
+
+ /* MOB -- opt. Flags would be quicker */
+ if (strcmp(ejsGetPropertyPtr(obj)->name,
+ E4X_PARENT_PROPERTY) == 0) {
+ return 0;
+ }
+ /*
+ * MOB -- short term fix for tags with no body but with
+ * attributes
+ */
+ if (getNumElements(obj) == 0 && 0) {
+ /*
+ * XML element is simple with no elements, so return just
+ * the text.
+ */
+ if (getText(buf, obj) < 0) {
+ ejsError(ep, EJS_IO_ERROR,
+ "XML is to big to convert to a string");
+ obj->objectState->visited = 0;
+ return -1;
+ }
+
+ } else if (obj->flags & (EJS_XML_FLAGS_ELEMENT)) {
+ /*
+ * XML object is complex (has elements) so return full XML
+ * content.
+ */
+ mprPutCharToBuf(buf, '\n');
+ indent(buf, indentLevel);
+
+ /*
+ * When called from toString, obj is not a property
+ */
+ if (indentLevel >= 0) {
+ mprPutFmtStringToBuf(buf, "<%s",
+ ejsGetPropertyPtr(obj)->name);
+ endTag = 0;
+
+ } else {
+ endTag = 1;
+ }
+
+ sawElements = 0;
+ pp = ejsGetFirstProperty(obj, 0);
+ while (pp) {
+ vp = ejsGetVarPtr(pp);
+
+ if (! (vp->flags & EJS_XML_FLAGS_ATTRIBUTE)) {
+ if (endTag == 0) {
+ endTag++;
+ mprPutStringToBuf(buf, ">");
+ }
+ }
+ if (vp->flags & EJS_XML_FLAGS_ELEMENT) {
+ if (strcmp(ejsGetPropertyPtr(vp)->name,
+ E4X_PARENT_PROPERTY) != 0) {
+ sawElements++;
+ }
+ }
+
+ if (xmlToString(ep, buf, ejsGetVarPtr(pp),
+ indentLevel + 1) < 0){
+ return -1;
+ }
+
+ pp = ejsGetNextProperty(pp, 0);
+ }
+ if (indentLevel >= 0) {
+ if (sawElements) {
+ mprPutCharToBuf(buf, '\n');
+ indent(buf, indentLevel);
+ }
+ mprPutFmtStringToBuf(buf, "</%s>",
+ ejsGetPropertyPtr(obj)->name);
+ }
+ }
+ obj->objectState->visited = 0;
+ }
+ return 0;
+ }
+
+ if (obj->objectState->baseClass == ejsGetClass(ep, 0, "XMLList")) {
+ indent(buf, indentLevel);
+ /* MOB -- TBD */
+ return 0;
+ }
+
+ /*
+ * All other objects. Allow other objects to override toString
+ */
+ if (ejsRunMethod(ep, obj->objectState->baseClass, "toString",
+ 0) < 0) {
+ return -1;
+ }
+ if (ejsVarIsString(ep->result)) {
+ indent(buf, indentLevel);
+ mprPutStringToBuf(buf, obj->string);
+ }
+ break;
+ }
+ return 0;
+}
+
+/******************************************************************************/
+
+static void indent(MprBuf *bp, int level)
+{
+ int i;
+
+ for (i = 0; i < level; i++) {
+ mprPutCharToBuf(bp, '\t');
+ }
+}
+
+/******************************************************************************/
+
+static int valueOf(Ejs *ep, EjsVar *thisObj, int argc, EjsVar **argv)
+{
+ if (argc != 0) {
+ mprAssert(0);
+ return -1;
+ }
+
+ switch (thisObj->type) {
+ default:
+ case EJS_TYPE_UNDEFINED:
+ case EJS_TYPE_NULL:
+ case EJS_TYPE_CMETHOD:
+ case EJS_TYPE_OBJECT:
+ case EJS_TYPE_METHOD:
+ case EJS_TYPE_STRING_CMETHOD:
+ ejsWriteVar(ep, ep->result, thisObj, EJS_SHALLOW_COPY);
+ break;
+
+ case EJS_TYPE_STRING:
+ ejsWriteVarAsInteger(ep, ep->result, atoi(thisObj->string));
+ break;
+
+ case EJS_TYPE_BOOL:
+ case EJS_TYPE_INT:
+#if BLD_FEATURE_INT64
+ case EJS_TYPE_INT64:
+#endif
+#if BLD_FEATURE_FLOATING_POINT
+ case EJS_TYPE_FLOAT:
+#endif
+ ejsWriteVar(ep, ep->result, thisObj, EJS_SHALLOW_COPY);
+ break;
+ }
+ return 0;
+}
+
+/******************************************************************************/
+
+static int getList(Ejs *ep, EjsVar *thisObj, int argc, EjsVar **argv)
+{
+ const char *nodeName;
+ EjsProperty *pp;
+ EjsVar *list, *vp;
+
+ if (argc != 1) {
+ nodeName = 0;
+ } else {
+ nodeName = argv[0]->string;
+ }
+
+ list = ejsCreateArray(ep, 0);
+
+ pp = ejsGetFirstProperty(thisObj, EJS_ENUM_ALL);
+ while (pp) {
+ vp = ejsGetVarPtr(pp);
+ if (vp->type == EJS_TYPE_OBJECT) {
+ if (strcmp(ejsGetPropertyPtr(vp)->name, E4X_PARENT_PROPERTY) != 0) {
+ if (vp->flags & EJS_XML_FLAGS_ELEMENT &&
+ (nodeName == 0 || strcmp(nodeName, pp->name) == 0)) {
+ ejsAddArrayElt(ep, list, vp, EJS_SHALLOW_COPY);
+ }
+ }
+ }
+ pp = ejsGetNextProperty(pp, EJS_ENUM_ALL);
+ }
+
+ ejsSetReturnValueAndFree(ep, list);
+ return 0;
+}
+
+/******************************************************************************/
+
+static int getNumElements(EjsVar *obj)
+{
+ EjsProperty *pp;
+ int count;
+
+ count = 0;
+ pp = ejsGetFirstProperty(obj, EJS_ENUM_ALL);
+ while (pp) {
+ if (ejsGetVarPtr(pp)->flags & EJS_XML_FLAGS_ELEMENT) {
+ count++;
+ }
+ pp = ejsGetNextProperty(pp, EJS_ENUM_ALL);
+ }
+ return count;
+}
+
+/******************************************************************************/
+/* MOB - This needs to be a public method */
+
+static int getText(MprBuf *buf, EjsVar *obj)
+{
+ EjsProperty *pp;
+ EjsVar *vp;
+
+ pp = ejsGetFirstProperty(obj, EJS_ENUM_ALL);
+ while (pp) {
+ vp = ejsGetVarPtr(pp);
+ if (vp->flags & EJS_XML_FLAGS_TEXT) {
+ /* MOB -- should test for overflow */
+ mprPutStringToBuf(buf, vp->string);
+ }
+ pp = ejsGetNextProperty(pp, EJS_ENUM_ALL);
+ }
+ return 0;
+}
+
+/******************************************************************************/
+/******************************************************************************/
+/******************************** Internal Methods ****************************/
+/******************************************************************************/
+
+static EjsVar *createXmlListProperty(Ejs *ep, EjsVar *obj, const char *property)
+{
+ return ejsGetVarPtr(ejsCreateProperty(ep, obj, property));
+}
+
+/******************************************************************************/
+
+static int deleteXmlListProperty(Ejs *ep, EjsVar *obj, const char *property)
+{
+ return ejsDeleteProperty(ep, obj, property);
+}
+
+/******************************************************************************/
+
+static EjsVar *getXmlListProperty(Ejs *ep, EjsVar *obj, const char *property)
+{
+ // Must always return XML or XMLList event for comments and attributes
+ return ejsGetVarPtr(ejsGetSimpleProperty(ep, obj, property));
+}
+
+/******************************************************************************/
+
+static EjsVar *setXmlListProperty(Ejs *ep, EjsVar *obj, const char *property,
+ const EjsVar *value)
+{
+ EjsProperty *pp;
+ EjsVar *vp;
+
+ pp = ejsGetSimpleProperty(ep, obj, property);
+ if (pp == 0) {
+ mprAssert(pp);
+ return 0;
+ }
+ vp = ejsGetVarPtr(pp);
+ if (ejsWriteVar(ep, vp, value, EJS_SHALLOW_COPY) < 0){
+ mprAssert(0);
+ return 0;
+ }
+ return ejsGetVarPtr(pp);
+}
+
+/******************************************************************************/
+/*
+ NEW
+
+static EjsVar *putXmlListProperty(EjsVar *op, const char *property,
+ EjsVar *value)
+{
+
+ if ((value->objectState->baseClass != XML &&
+ value->objectState->baseClass != XMLList) ||
+ value->string[0] != '<') {
+ c = value.toString();
+ } else {
+ value = ejsDupVar(value);
+ ??
+ }
+ if (isdigit(*property)) {
+ // ERROR
+ return 0;
+ }
+ if (*property == '@') {
+ if (op->objectState->baseClass == XMLList) {
+ if (op->obj.LENGTH_PROPERTY == 0) {
+ c = "";
+ } else {
+ // Catenate all result of toString on all elts in list
+ }
+ } else {
+ c = c.toString();
+ }
+ // Replace existing attribute of same name or insert
+ return;
+ }
+ for (i = op->obj.LENGTH - 1; i >= 0; i--) {
+ // Delete item of same name
+ }
+ if (not Found) {
+ Append new Xml object
+ - set [[name]], [[class]] == "element"
+ }
+}
+
+ */
+
+/******************************************************************************/
+#else
+void ejs4xDummy() {}
+
+/******************************************************************************/
+#endif /* BLD_FEATURE_EJS_E4X */
+
+/*
+ * 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-2.0/ejs/ejs.c b/source4/lib/appweb/ejs-2.0/ejs/ejs.c
new file mode 100644
index 0000000000..0fcc6f0545
--- /dev/null
+++ b/source4/lib/appweb/ejs-2.0/ejs/ejs.c
@@ -0,0 +1,1378 @@
+/*
+ * @file ejs.c
+ * @brief Embedded JavaScript (EJS)
+ * @overview Main module interface logic.
+ * @remarks The initialization code must be run single-threaded. Includes:
+ * ejsOpen, ejsClose.
+ */
+/********************************* Copyright **********************************/
+/*
+ * @copy default
+ *
+ * Copyright (c) Mbedthis Software LLC, 2003-2006. 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
+ */
+/********************************** Includes **********************************/
+
+#include "ejs.h"
+
+#if BLD_FEATURE_EJS
+
+/************************************* Code ***********************************/
+/*
+ * Initialize the EJS subsystem
+ */
+
+EjsService *ejsOpenService(MprCtx ctx)
+{
+ EjsService *service;
+ Ejs *interp;
+
+ service = mprAllocTypeZeroed(ctx, EjsService);
+ if (service == 0) {
+ mprError(ctx, MPR_LOC, "Can't allocate service memory");
+ return 0;
+ }
+
+ interp = ejsCreateInterp(service, 0, 0, 0, 1);
+ if (interp == 0) {
+ mprError(ctx, MPR_LOC, "Can't create master interpreter");
+ mprFree(service);
+ return 0;
+ }
+ service->master = interp;
+
+ /*
+ * Restore the default GC settings for the master interpreter.
+ * ejsCreateInterp will have initialized them.
+ */
+ ejsGCInit(interp, EJS_DEFAULT_OBJ_INC, EJS_DEFAULT_PROP_INC,
+ EJS_DEFAULT_VAR_INC, EJS_DEFAULT_STR_INC);
+
+ /*
+ * Save the default interpreter and global class for all to access
+ * MOB -- don't store these. Store the service
+ */
+ mprSetKeyValue(interp, "ejsMaster", interp);
+ mprSetKeyValue(interp, "ejsGlobalClass", interp->global);
+
+ /*
+ * Once the Object class is created, this routine will also make the
+ * Global class a subclass of Object.
+ */
+ if (ejsDefineObjectClass(interp) < 0) {
+ mprError(ctx, MPR_LOC, "Can't define EJS object class");
+ mprFree(service);
+ return 0;
+ }
+
+ /*
+ * Create all the standard classes
+ */
+ if (ejsDefineStandardClasses(interp) < 0) {
+ mprError(ctx, MPR_LOC, "Can't define EJS standard classes");
+ mprFree(service);
+ return 0;
+ }
+
+ if (ejsDefineSystemClasses(interp) < 0) {
+ mprError(ctx, MPR_LOC, "Can't define EJS system classes");
+ mprFree(service);
+ return 0;
+ }
+
+ if (ejsCreateObjectModel(interp) < 0) {
+ mprError(ctx, MPR_LOC, "Can't create EJS object model");
+ mprFree(service);
+ return 0;
+ }
+
+#if UNUSED && BLD_FEATURE_ALLOC_STATS
+{
+ EjsVar v;
+ mprLog(ctx, 0, "Obj %d, Var %d, Prop %d\n", sizeof(EjsObj), sizeof(EjsVar),
+ sizeof(EjsProperty));
+ mprLog(ctx, 0, "GCLink %d\n", sizeof(EjsGCLink));
+ mprLog(ctx, 0, "objectState %d\n", (uint) &v.objectState - (uint) &v);
+}
+#endif
+
+ return service;
+}
+
+/******************************************************************************/
+/*
+ * Close down the EJS Service
+ */
+
+void ejsCloseService(EjsService *sp, bool doStats)
+{
+ Ejs *ep;
+
+ mprAssert(sp);
+
+ ep = sp->master;
+ mprAssert(ep);
+
+ ejsTermSystemClasses(ep);
+
+ if (ep) {
+ ejsFreeVar(ep, sp->globalClass);
+
+#if BLD_FEATURE_ALLOC_STATS
+ if (doStats) {
+ mprLog(sp, 0, "GC Statistics for the Global Interpreter");
+ }
+#endif
+ ejsDestroyInterp(ep, doStats);
+ }
+
+ mprRemoveKeyValue(sp, "ejsMaster");
+ mprRemoveKeyValue(sp, "ejsGlobalClass");
+
+ mprFree(sp);
+}
+
+/******************************************************************************/
+
+Ejs *ejsGetMasterInterp(EjsService *sp)
+{
+ return sp->master;
+}
+
+/******************************************************************************/
+#if BLD_FEATURE_MULTITHREAD
+
+int ejsSetServiceLocks(EjsService *sp, EjsLockFn lock, EjsUnlockFn unlock,
+ void *data)
+{
+ mprAssert(sp);
+
+ sp->lock = lock;
+ sp->unlock = unlock;
+ sp->lockData = data;
+ return 0;
+}
+
+#endif
+/******************************************************************************/
+/*
+ * Create and initialize an EJS interpreter. Interpreters have a global object
+ * that has the service global class set as a base class. This way, it
+ * inherits all the desired global properties, methods and classes.
+ *
+ * The primary and alternate handles are provided to C methods depending on
+ * the flags provided when the C methods are defined. The global variable
+ * (optionally) defines a predefined global variable space.
+ */
+
+Ejs *ejsCreateInterp(EjsService *sp, void *primaryHandle, void *altHandle,
+ EjsVar *global, bool useOwnSlab)
+{
+ EjsProperty *pp;
+ EjsVar *baseClass;
+ Ejs *ep;
+
+ ep = mprAllocTypeZeroed(sp, Ejs);
+ if (ep == 0) {
+ mprAssert(0);
+ return ep;
+ }
+
+ ep->stkPtr = &ep->stack[EJS_MAX_STACK];
+
+ ep->service = sp;
+ ep->primaryHandle = primaryHandle;
+ ep->altHandle = altHandle;
+
+ if (sp->master) {
+ ep->objectClass = sp->master->objectClass;
+ }
+
+ if (useOwnSlab) {
+ ep->slabs = (EjsSlab*) mprAllocZeroed(ep, sizeof(EjsSlab) *
+ EJS_SLAB_MAX);
+ ep->slabAllocContext = ep;
+
+ } else {
+ ep->slabs = sp->master->slabs;
+ ep->slabAllocContext = sp->master;
+ ep->flags |= EJS_FLAGS_SHARED_SLAB;
+ }
+
+ ep->frames = mprCreateItemArray(ep, EJS_INC_FRAMES, EJS_MAX_FRAMES);
+ if (ep->frames == 0) {
+ mprFree(ep);
+ return 0;
+ }
+
+ ejsGCInit(ep, EJS_OBJ_INC, EJS_PROP_INC, EJS_VAR_INC, EJS_STR_INC);
+
+ if (sp->globalClass == 0) {
+ /*
+ * Only do this for the Global interpreter. Create a global class
+ * (prototype) object. This is base class from which all global
+ * spaces will inherit.
+ */
+ sp->globalClass = ejsCreateObjVar(ep);
+ if (sp->globalClass == 0) {
+ mprFree(ep);
+ return 0;
+ }
+ ejsSetClassName(ep, sp->globalClass, "Global");
+ global = sp->globalClass;
+ }
+
+ if (global) {
+ /*
+ * The default interpreter uses the Global class as its global
+ * space.
+ */
+ ep->global = ejsDupVar(ep, global, EJS_SHALLOW_COPY);
+ if (ep->global == 0) {
+ mprFree(ep);
+ return 0;
+ }
+ if (ep->global->objectState != sp->globalClass->objectState) {
+ ejsSetBaseClass(ep->global, sp->globalClass);
+ }
+
+ } else {
+ /*
+ * Use the global class as our global so we can find the object class
+ */
+ baseClass = ejsGetClass(ep, sp->globalClass, "Object");
+ if (baseClass) {
+ ep->global = ejsCreateSimpleObjUsingClass(ep, baseClass);
+ if (ep->global == 0) {
+ mprFree(ep);
+ return 0;
+ }
+
+ /*
+ * Override the base class and set to the master Global class
+ */
+ ejsSetBaseClass(ep->global, sp->globalClass);
+
+ } else {
+ ep->global = ejsCreateObjVar(ep);
+ }
+ }
+
+ /*
+ * The "global" variable points to the global space
+ */
+ pp = ejsSetProperty(ep, ep->global, "global", ep->global);
+ if (pp == 0) {
+ mprFree(ep);
+ return 0;
+ }
+ ejsMakePropertyEnumerable(pp, 0);
+
+ /*
+ * The "Global" variable points to the Global class
+ */
+ pp = ejsSetProperty(ep, ep->global, "Global", sp->globalClass);
+ if (pp == 0) {
+ mprFree(ep);
+ return 0;
+ }
+ ejsMakePropertyEnumerable(pp, 0);
+
+ ep->local = ejsDupVar(ep, ep->global, EJS_SHALLOW_COPY);
+ if (ep->frames == 0 || ep->global == 0 || ep->local == 0) {
+ mprFree(ep);
+ return 0;
+ }
+ ejsSetVarName(ep, ep->local, "topLevelLocal");
+
+ if (mprAddItem(ep->frames, ep->global) < 0 ||
+ mprAddItem(ep->frames, ep->local) < 0) {
+ mprFree(ep);
+ return 0;
+ }
+
+ ep->result = ejsCreateUndefinedVar(ep);
+ if (ep->result == 0) {
+ mprFree(ep);
+ return 0;
+ }
+
+ return ep;
+}
+
+/******************************************************************************/
+/*
+ * Close an EJS interpreter
+ */
+
+void ejsDestroyInterp(Ejs *ep, bool doStats)
+{
+ ejsCleanInterp(ep, doStats);
+
+ mprFree(ep);
+}
+
+/******************************************************************************/
+/*
+ * Clean an EJS interpreter of all allocated variables, but DONT destroy.
+ * We use this rather than DestroyInterp so we delay freeing the Ejs struct
+ * until after the service is closed.
+ */
+
+void ejsCleanInterp(Ejs *ep, bool doStats)
+{
+ int i;
+
+ if (ep->global) {
+ ejsDeleteProperty(ep, ep->local, "global");
+ ejsDeleteProperty(ep, ep->global, "global");
+ ep->global = 0;
+ }
+ if (ep->local) {
+ ejsFreeVar(ep, ep->local);
+ ep->local = 0;
+ }
+ if (ep->global) {
+ ejsFreeVar(ep, ep->global);
+ ep->global = 0;
+ }
+ if (ep->result) {
+ ejsFreeVar(ep, ep->result);
+ ep->result = 0;
+ }
+ if (ep->castAlloc && ep->castTemp) {
+ mprFree(ep->castTemp);
+ ep->castTemp = 0;
+ }
+ if (ep->frames) {
+ for (i = ep->frames->length - 1; i >= 0; i--) {
+ mprRemoveItemByIndex(ep->frames, i);
+ }
+ mprFree(ep->frames);
+ ep->frames = 0;
+ }
+
+ if (doStats) {
+
+#if BLD_FEATURE_ALLOC_STATS
+ mprLog(ep, 0, " ");
+ mprLog(ep, 0, "GC Statistics for Interpreter (0x%X)", (uint) ep);
+#endif
+
+ /*
+ * Cleanup before printing the alloc report
+ */
+ ejsSetGCDebugLevel(ep, 3);
+ ejsCollectGarbage(ep, -1);
+
+#if BLD_DEBUG
+ /*
+ * If we are the master, dump objects
+ */
+ if (ep->service->master == ep) {
+ ejsDumpObjects(ep);
+ }
+#endif
+
+#if BLD_FEATURE_ALLOC_STATS
+ /*
+ * Print an alloc report. 1 == do leak report
+ */
+ ejsPrintAllocReport(ep, 1);
+#endif
+
+ } else {
+ /*
+ * Must collect garbage here incase sharing interpreters with the
+ * master. If we don't, the mprFree later in DestroyInterp will free
+ * all memory and when the master does GC --> crash.
+ */
+ ejsCollectGarbage(ep, -1);
+ }
+}
+
+/******************************************************************************/
+/*
+ * Evaluate an EJS script file. This will evaluate the script at the current
+ * context. Ie. if inside a function, declarations will be local.
+ */
+
+int ejsEvalFile(Ejs *ep, const char *path, EjsVar *result)
+{
+ MprFile *file;
+ MprFileInfo info;
+ char *script;
+ char *saveFileName;
+ int rc;
+
+ mprAssert(path && *path);
+
+ if ((file = mprOpen(ep, path, O_RDONLY | O_BINARY, 0666)) == 0) {
+ ejsError(ep, EJS_IO_ERROR, "Can't open %s", path);
+ return -1;
+ }
+
+ if (mprGetFileInfo(ep, path, &info) < 0) {
+ ejsError(ep, EJS_IO_ERROR, "Can't get file info for %s", path);
+ goto error;
+ }
+
+ if ((script = (char*) mprAlloc(ep, info.size + 1)) == NULL) {
+ ejsError(ep, "MemoryError", "Cant malloc %d", (int) info.size);
+ goto error;
+ }
+
+ if (mprRead(file, script, info.size) != (int) info.size) {
+ mprFree(script);
+ ejsError(ep, EJS_IO_ERROR, "Error reading %s", path);
+ goto error;
+ }
+ mprClose(file);
+ script[info.size] = '\0';
+
+ saveFileName = ep->fileName;
+ ep->fileName = mprStrdup(ep, path);
+
+ rc = ejsEvalScript(ep, script, result);
+ mprFree(script);
+
+ mprFree(ep->fileName);
+ ep->fileName = saveFileName;
+
+ return rc;
+
+/*
+ * Error return
+ */
+error:
+ mprClose(file);
+ return -1;
+}
+
+/******************************************************************************/
+/*
+ * Create a new variable scope block. This pushes the old local frame down
+ * the stack and creates a new local variables frame.
+ */
+
+int ejsOpenBlock(Ejs *ep)
+{
+ EjsProperty *pp;
+ int fid;
+
+ ep->local = ejsCreateSimpleObj(ep, "Object");
+ ejsSetVarName(ep, ep->local, "local");
+
+ if (ep->local == 0) {
+ ejsMemoryError(ep);
+ return -1;
+ }
+
+ if (ep->frames->length > EJS_MAX_FRAMES && !ep->gotException) {
+ ejsError(ep, EJS_RANGE_ERROR, "Recursion too deep: Max depth %d",
+ EJS_MAX_FRAMES);
+ return -1;
+ }
+
+ /*
+ * Must add to frames before ejsSetProperty which will make the object live
+ */
+ fid = mprAddItem(ep->frames, ep->local);
+ if (fid < 0) {
+ ejsMemoryError(ep);
+ return -1;
+ }
+
+ /* Self reference */
+ pp = ejsSetProperty(ep, ep->local, "local", ep->local);
+ ejsMakePropertyEnumerable(pp, 0);
+
+ return fid;
+}
+
+/******************************************************************************/
+/*
+ * Set a new variable scope block. This pushes the old local frame down
+ * the stack and creates a new local variables frame.
+ */
+
+int ejsSetBlock(Ejs *ep, EjsVar *local)
+{
+ ep->local = ejsDupVar(ep, local, EJS_SHALLOW_COPY);
+ ejsMakeObjPermanent(ep->local, 1);
+ return mprAddItem(ep->frames, ep->local);
+}
+
+/******************************************************************************/
+/*
+ * Close a variable scope block opened via ejsOpenBlock. Pop back the old
+ * local variables frame.
+ */
+
+int ejsCloseBlock(Ejs *ep, int fid)
+{
+ mprAssert(ep->local >= 0);
+ mprAssert(fid >= 0);
+
+ mprAssert(ep->local == (EjsVar*) mprGetItem(ep->frames, fid));
+
+ if (ep->local) {
+ /* Allow GC */
+ ejsMakeObjPermanent(ep->local, 0);
+ ejsFreeVar(ep, ep->local);
+ }
+
+ mprRemoveItemByIndex(ep->frames, fid);
+
+ ep->local = (EjsVar*) mprGetItem(ep->frames,
+ mprGetItemCount(ep->frames) - 1);
+
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * Create a new variable scope block and evaluate a script. All frames
+ * created during this context will be automatically deleted when complete.
+ * vp is optional. i.e. created local variables will be discarded
+ * when this routine returns.
+ */
+
+int ejsEvalBlock(Ejs *ep, char *script, EjsVar *vp)
+{
+ int rc, fid;
+
+ mprAssert(script);
+
+ fid = ejsOpenBlock(ep);
+ if (fid < 0) {
+ return fid;
+ }
+
+ rc = ejsEvalScript(ep, script, vp);
+
+ ejsCloseBlock(ep, fid);
+
+ return rc;
+}
+
+/******************************************************************************/
+/*
+ * Parse and evaluate a EJS. The script is evaluated at the current context.
+ * Return the result in *vp. The result is "owned" by EJ and the caller
+ * must not free it. Returns -1 on errors and zero for success.
+ */
+
+int ejsEvalScript(Ejs *ep, const char *script, EjsVar *vp)
+{
+ int state;
+
+ ejsClearVar(ep, ep->result);
+ ep->gotException = 0;
+
+ if (script == 0) {
+ return 0;
+ }
+
+ /*
+ * Allocate a new evaluation block, and save the old one
+ */
+ if (ejsLexOpenScript(ep, script) < 0) {
+ return MPR_ERR_MEMORY;
+ }
+
+ /*
+ * Do the actual parsing and evaluation
+ */
+ ep->scriptStatus = 0;
+
+ do {
+ state = ejsParse(ep, EJS_STATE_BEGIN, EJS_FLAGS_EXE);
+
+ if (state == EJS_STATE_RET) {
+ state = EJS_STATE_EOF;
+ }
+ } while (state != EJS_STATE_EOF && state != EJS_STATE_ERR);
+
+ ejsLexCloseScript(ep);
+
+ if (state == EJS_STATE_ERR) {
+ return -1;
+ }
+
+ if (vp) {
+ /* Caller must not free. */
+ *vp = *ep->result;
+ }
+
+ return ep->scriptStatus;
+}
+
+/******************************************************************************/
+
+void ejsSetFileName(Ejs *ep, const char *fileName)
+{
+ mprFree(ep->fileName);
+ ep->fileName = mprStrdup(ep, fileName);
+}
+
+/******************************************************************************/
+/*
+ * Format the stack backtrace
+ */
+
+char *ejsFormatStack(Ejs* ep)
+{
+ EjsInput *ip;
+ char *errbuf;
+ int frame, len;
+
+ mprAssert(ep);
+
+ ip = ep->input;
+
+ errbuf = 0;
+
+ len = 0;
+ frame = 0;
+ while (ip && frame < EJS_MAX_BACKTRACE) {
+ char *traceLine, *newErrbuf, *line;
+ for (line = ip->line; *line && isspace(*line); line++) {
+ ;
+ }
+ mprAllocSprintf(MPR_LOC_ARGS(ep), &traceLine, MPR_MAX_STRING,
+ " [%02d] %s, %s, line %d -> %s\n",
+ frame++,
+ ip->fileName ? ip->fileName : "script",
+ ip->procName ? ip->procName: "global",
+ ip->lineNumber, line);
+ if (traceLine == 0) {
+ break;
+ }
+ newErrbuf = mprRealloc(ep, errbuf, len + strlen(traceLine) + 1);
+ if (newErrbuf == NULL) {
+ break;
+ }
+ errbuf = newErrbuf;
+ memcpy(&errbuf[len], traceLine, strlen(traceLine) + 1);
+ len += strlen(traceLine);
+ mprFree(traceLine);
+ ip = ip->next;
+ }
+ return errbuf;
+}
+
+/******************************************************************************/
+/*
+ * Internal use method to set the error message
+ *
+ * Error, ArgError, AssertError, IOError, MemoryError, RangeError,
+ * ReferenceError, SyntaxError, TypeError, MemoryError
+ */
+
+void ejsError(Ejs* ep, const char *errorType, const char* fmt, ...)
+{
+ va_list fmtArgs;
+ EjsVar *error;
+ char *msg, *stack;
+
+ va_start(fmtArgs, fmt);
+ mprAllocVsprintf(MPR_LOC_ARGS(ep), &msg, MPR_MAX_STRING, fmt, fmtArgs);
+ va_end(fmtArgs);
+
+ /*
+ * Create a new Error exception object. If bad error type, default to
+ * "Error"
+ */
+ if (ejsGetClass(ep, 0, errorType) == 0) {
+ errorType = "Error";
+ }
+ ep->gotException = 1;
+
+ error = ejsCreateObj(ep, 0, errorType, msg);
+ if (error == 0) {
+ return;
+ }
+ mprFree(msg);
+
+ stack = ejsFormatStack(ep);
+ ejsSetPropertyToString(ep, error, "stack", stack);
+ mprFree(stack);
+
+ ejsWriteVar(ep, ep->result, error, EJS_SHALLOW_COPY);
+ ejsFreeVar(ep, error);
+}
+
+/******************************************************************************/
+
+void ejsSyntaxError(Ejs *ep, const char *msg)
+{
+ if (msg == 0) {
+ msg = " ";
+ }
+ ejsError(ep, EJS_SYNTAX_ERROR, msg);
+}
+
+/******************************************************************************/
+
+void ejsMemoryError(Ejs *ep)
+{
+ ejsError(ep, EJS_MEMORY_ERROR, "Memory allocation error");
+}
+
+/******************************************************************************/
+
+void ejsArgError(Ejs *ep, const char *msg)
+{
+ mprAssert(msg && *msg);
+
+ ejsError(ep, EJS_ARG_ERROR, msg);
+}
+
+/******************************************************************************/
+
+void ejsInternalError(Ejs *ep, const char *msg)
+{
+ mprAssert(msg && *msg);
+
+ ejsError(ep, EJS_INTERNAL_ERROR, msg);
+}
+
+/******************************************************************************/
+/*
+ * Public routine to set the error message. Caller MUST NOT free.
+ */
+
+char *ejsGetErrorMsg(Ejs *ep)
+{
+ EjsVar *error;
+ const char *message, *stack, *name;
+ char *buf;
+
+ error = ep->result;
+
+ if (! ejsVarIsObject(error)) {
+ name = message = stack = 0;
+ } else {
+ name = ejsGetPropertyAsString(ep, error, "name");
+ message = ejsGetPropertyAsString(ep, error, "message");
+ stack = ejsGetPropertyAsString(ep, error, "stack");
+ }
+ if (name == 0 || message == 0) {
+ buf = mprStrdup(ep, "Unspecified execution error\n");
+ } else {
+ mprAllocSprintf(MPR_LOC_ARGS(ep), &buf, 0,
+ "%s Exception: %s\nStack:\n%s\n",
+ name, message, stack ? stack : " " );
+ }
+ mprFree(ep->errorMsg);
+ ep->errorMsg = buf;
+ return buf;
+}
+
+/******************************************************************************/
+/*
+ * Get the current line number
+ */
+
+int ejsGetLineNumber(Ejs *ep)
+{
+ if (ep->input == 0) {
+ return -1;
+ }
+ return ep->input->lineNumber;
+}
+
+/******************************************************************************/
+/*
+ * Return the local object
+ */
+
+EjsVar *ejsGetLocalObj(Ejs *ep)
+{
+ return ep->local;
+}
+
+/******************************************************************************/
+/*
+ * Return the global object
+ */
+
+EjsVar *ejsGetGlobalObj(Ejs *ep)
+{
+ return ep->global;
+}
+
+/******************************************************************************/
+/*
+ * Set the expression return value
+ */
+
+void ejsSetReturnValue(Ejs *ep, EjsVar *vp)
+{
+ mprAssert(ep);
+ mprAssert(vp);
+
+ if (vp == 0) {
+ return;
+ }
+ ejsWriteVar(ep, ep->result, vp, EJS_SHALLOW_COPY);
+}
+
+/******************************************************************************/
+/*
+ * Set the expression return value and free the arg.
+ */
+
+void ejsSetReturnValueAndFree(Ejs *ep, EjsVar *vp)
+{
+ mprAssert(ep);
+ mprAssert(vp);
+
+ ejsWriteVar(ep, ep->result, vp, EJS_SHALLOW_COPY);
+ ejsFreeVar(ep, vp);
+}
+
+/******************************************************************************/
+/*
+ * Set the expression return value to a string value.
+ */
+
+void ejsSetReturnValueToString(Ejs *ep, const char *value)
+{
+ mprAssert(ep);
+ mprAssert(value);
+
+ ejsWriteVarAsString(ep, ep->result, value);
+}
+
+/******************************************************************************/
+/*
+ * Set the expression return value to a binary string value.
+ */
+
+void ejsSetReturnValueToBinaryString(Ejs *ep, const uchar *value, int len)
+{
+ mprAssert(ep);
+ mprAssert(value);
+
+ ejsWriteVarAsBinaryString(ep, ep->result, value, len);
+}
+
+/******************************************************************************/
+/*
+ * Set the expression return value to a integer value.
+ */
+
+void ejsSetReturnValueToInteger(Ejs *ep, int value)
+{
+ mprAssert(ep);
+
+ ejsWriteVarAsInteger(ep, ep->result, value);
+}
+
+/******************************************************************************/
+/*
+ * Set the expression return value to an EjsNum value.
+ */
+
+void ejsSetReturnValueToNumber(Ejs *ep, EjsNum value)
+{
+ mprAssert(ep);
+
+ ejsWriteVarAsNumber(ep, ep->result, value);
+}
+
+/******************************************************************************/
+/*
+ * Set the expression return value to a boolean value.
+ */
+
+void ejsSetReturnValueToBoolean(Ejs *ep, int value)
+{
+ mprAssert(ep);
+
+ ejsWriteVarAsBoolean(ep, ep->result, value);
+}
+
+/******************************************************************************/
+/*
+ * Set the expression return value to a boolean value.
+ */
+
+void ejsSetReturnValueToUndefined(Ejs *ep)
+{
+ mprAssert(ep);
+
+ ejsWriteVarAsUndefined(ep, ep->result);
+}
+
+/******************************************************************************/
+/*
+ * Get the expression return value
+ */
+
+EjsVar *ejsGetReturnValue(Ejs *ep)
+{
+ mprAssert(ep);
+
+ return ep->result;
+}
+
+/******************************************************************************/
+
+void *ejsGetUserData(Ejs *ep)
+{
+ mprAssert(ep);
+
+ return ep->userData;
+}
+
+/******************************************************************************/
+/*
+ * Get a variable given a full variable spec possibly containing "." or "[]".
+ */
+
+EjsVar *ejsGetVar(Ejs *ep, const char *fullName)
+{
+ mprAssert(ep);
+ mprAssert(fullName && *fullName);
+
+ return ejsFindProperty(ep, 0, 0, ep->global, ep->local, fullName, 0);
+}
+
+/******************************************************************************/
+/*
+ * Get a string var given a full variable spec possibly containing "." or "[]".
+ */
+
+const char *ejsGetStr(Ejs *ep, const char *fullName, const char *defaultValue)
+{
+ EjsVar *vp;
+
+ mprAssert(fullName && *fullName);
+
+ vp = ejsFindProperty(ep, 0, 0, ep->global, ep->local, fullName, 0);
+ if (vp == 0 || !ejsVarIsString(vp)) {
+ return defaultValue;
+ }
+ /* MOB -- what about VarToStr */
+ return vp->string;
+}
+
+/******************************************************************************/
+/*
+ * Get an int var given a full variable spec possibly containing "." or "[]".
+ */
+
+int ejsGetInt(Ejs *ep, const char *fullName, int defaultValue)
+{
+ EjsVar *vp;
+
+ mprAssert(ep);
+ mprAssert(fullName && *fullName);
+
+ vp = ejsFindProperty(ep, 0, 0, ep->global, ep->local, fullName, 0);
+ if (vp == 0 || !ejsVarIsInteger(vp)) {
+ return defaultValue;
+ }
+ /* MOB -- should use VarToInt */
+ return vp->integer;
+}
+
+/******************************************************************************/
+/*
+ * Get an bool var given a full variable spec possibly containing "." or "[]".
+ */
+
+int ejsGetBool(Ejs *ep, const char *fullName, int defaultValue)
+{
+ EjsVar *vp;
+
+ mprAssert(ep);
+ mprAssert(fullName && *fullName);
+
+ vp = ejsFindProperty(ep, 0, 0, ep->global, ep->local, fullName, 0);
+ if (vp == 0 || !ejsVarIsBoolean(vp)) {
+ return defaultValue;
+ }
+ /* MOB -- should use VarToBool */
+ return vp->boolean;
+}
+
+/******************************************************************************/
+/*
+ * Set a variable that may be an arbitrarily complex object or array reference.
+ * Will always define in the top most variable frame.
+ */
+
+int ejsSetVar(Ejs *ep, const char *fullName, const EjsVar *value)
+{
+ EjsVar *vp;
+
+ mprAssert(fullName && *fullName);
+
+ vp = ejsFindProperty(ep, 0, 0, ep->global, ep->local, fullName, 1);
+ if (vp == 0) {
+ return MPR_ERR_CANT_CREATE;
+ }
+
+ if (ejsWriteVar(ep, vp, value, EJS_SHALLOW_COPY) == 0) {
+ return MPR_ERR_CANT_WRITE;
+ }
+
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * Set a variable that may be an arbitrarily complex object or array reference.
+ * Will always define in the top most variable frame.
+ */
+
+int ejsSetStr(Ejs *ep, const char *fullName, const char *value)
+{
+ EjsVar *vp;
+
+ mprAssert(fullName && *fullName);
+
+ vp = ejsFindProperty(ep, 0, 0, ep->global, ep->local, fullName, 1);
+ if (vp == 0) {
+ return MPR_ERR_CANT_CREATE;
+ }
+
+ if (ejsWriteVarAsString(ep, vp, value) == 0) {
+ return MPR_ERR_CANT_WRITE;
+ }
+
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * Set a variable that may be an arbitrarily complex object or array reference.
+ * Will always define in the top most variable frame.
+ */
+
+int ejsSetInt(Ejs *ep, const char *fullName, int value)
+{
+ EjsVar *vp;
+
+ mprAssert(fullName && *fullName);
+
+ vp = ejsFindProperty(ep, 0, 0, ep->global, ep->local, fullName, 1);
+ if (vp == 0) {
+ return MPR_ERR_CANT_CREATE;
+ }
+
+ /* Can't fail */
+ ejsWriteVarAsInteger(ep, vp, value);
+
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * Set a variable that may be an arbitrarily complex object or array reference.
+ * Will always define in the top most variable frame.
+ */
+
+int ejsSetBool(Ejs *ep, const char *fullName, bool value)
+{
+ EjsVar *vp;
+
+ mprAssert(fullName && *fullName);
+
+ vp = ejsFindProperty(ep, 0, 0, ep->global, ep->local, fullName, 1);
+ if (vp == 0) {
+ return MPR_ERR_CANT_CREATE;
+ }
+
+ /* Can't fail */
+ ejsWriteVarAsBoolean(ep, vp, value);
+
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * Set a variable that may be an arbitrarily complex object or array reference.
+ * Will always define in the top most variable frame. Free the value passed in.
+ */
+
+int ejsSetVarAndFree(Ejs *ep, const char *fullName, EjsVar *value)
+{
+ EjsVar *vp;
+
+ mprAssert(fullName && *fullName);
+
+ vp = ejsFindProperty(ep, 0, 0, ep->global, ep->local, fullName, 1);
+ if (vp == 0) {
+ return MPR_ERR_CANT_CREATE;
+ }
+
+ if (ejsWriteVar(ep, vp, value, EJS_SHALLOW_COPY) == 0) {
+ ejsFreeVar(ep, value);
+ return MPR_ERR_CANT_WRITE;
+ }
+
+ ejsFreeVar(ep, value);
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * Delete a variable
+ */
+
+int ejsDeleteVar(Ejs *ep, const char *fullName)
+{
+ EjsVar *vp;
+ EjsVar *obj;
+ char *propertyName;
+
+ vp = ejsFindProperty(ep, &obj, &propertyName, ep->global, ep->local,
+ fullName, 0);
+ if (vp == 0) {
+ return -1;
+ }
+
+ mprAssert(propertyName);
+ mprAssert(propertyName);
+
+ return ejsDeleteProperty(ep, obj, propertyName);
+}
+
+/******************************************************************************/
+/*
+ * Utility routine to crack JavaScript arguments. Return the number of args
+ * seen. This routine only supports %s and %d type args.
+ *
+ * Typical usage:
+ *
+ * if (ejsParseArgs(argc, argv, "%s %d", &name, &age) < 2) {
+ * // Insufficient args
+ * return -1;
+ * }
+ */
+
+int ejsParseArgs(int argc, char **argv, const char *fmt, ...)
+{
+ va_list vargs;
+ const char *cp;
+ char **sp, *s;
+ int *bp, *ip, argn;
+
+ va_start(vargs, fmt);
+
+ if (argv == 0) {
+ return 0;
+ }
+
+ for (argn = 0, cp = fmt; cp && *cp && argn < argc && argv[argn]; ) {
+ if (*cp++ != '%') {
+ continue;
+ }
+
+ s = argv[argn];
+ switch (*cp) {
+ case 'b':
+ bp = va_arg(vargs, int*);
+ if (bp) {
+ if (strcmp(s, "true") == 0 || s[0] == '1') {
+ *bp = 1;
+ } else {
+ *bp = 0;
+ }
+ } else {
+ *bp = 0;
+ }
+ break;
+
+ case 'd':
+ ip = va_arg(vargs, int*);
+ *ip = atoi(s);
+ break;
+
+ case 's':
+ sp = va_arg(vargs, char**);
+ *sp = s;
+ break;
+
+ default:
+ mprAssert(0);
+ }
+ argn++;
+ }
+
+ va_end(vargs);
+ return argn;
+}
+
+/******************************************************************************/
+/*
+ * Define the standard classes
+ */
+
+int ejsDefineStandardClasses(Ejs *master)
+{
+ if (ejsDefineArrayClass(master) != 0 ||
+ ejsDefineBooleanClass(master) != 0 ||
+ ejsDefineErrorClasses(master) != 0 ||
+ ejsDefineFunctionClass(master) != 0 ||
+ ejsDefineNumberClass(master) != 0 ||
+#if FUTURE
+ ejsDefineDateClass(master) != 0 ||
+#endif
+#if BLD_FEATURE_EJS_E4X
+ ejsDefineXmlClasses(master) != 0 ||
+#endif
+#if BLD_FEATURE_EJS_DB && NOT_HERE
+ ejsDefineDbClasses(master) != 0 ||
+#endif
+ ejsDefineStringClass(master) != 0) {
+ return MPR_ERR_MEMORY;
+ }
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * Define the EJS System Object Model
+ */
+
+int ejsDefineSystemClasses(Ejs *master)
+{
+ if (ejsDefineSystemClass(master) != 0 ||
+ ejsDefineAppClass(master) != 0 ||
+ ejsDefineMemoryClass(master) != 0 ||
+ ejsDefineLogClass(master) != 0 ||
+ ejsDefineDebugClass(master) != 0 ||
+ ejsDefineGCClass(master) != 0 ||
+ ejsDefineFileSystemClass(master) != 0 ||
+#if BREW
+ ejsDefineFileClass(master) != 0 ||
+ ejsDefineHTTPClass(master) != 0 ||
+#endif
+ ejsDefineGlobalProperties(master) != 0) {
+ return MPR_ERR_MEMORY;
+ }
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * Terminate the system object model and classes
+ */
+
+int ejsTermSystemClasses(Ejs *master)
+{
+#if BREW
+ ejsTermHTTPClass(master);
+#endif
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * Define the EJS object model
+ */
+
+int ejsCreateObjectModel(Ejs *ejs)
+{
+ EjsProperty *pp;
+
+ pp = ejsSetPropertyToNewObj(ejs, ejs->global, "system", "System", 0);
+ if (pp == 0) {
+ return MPR_ERR_MEMORY;
+ }
+
+ if (ejsSetPropertyToNewObj(ejs, ejsGetVarPtr(pp), "app", "System.App",
+ 0) == 0) {
+ return MPR_ERR_MEMORY;
+ }
+ return 0;
+}
+
+/******************************************************************************/
+
+void ejsTrace(Ejs *ep, const char *fmt, ...)
+{
+ va_list args;
+ char buf[MPR_MAX_LOG_STRING];
+ int len;
+
+ va_start(args, fmt);
+ len = mprVsprintf(buf, sizeof(buf) - 1, fmt, args);
+ va_end(args);
+
+ mprLog(ep, 0, buf, len);
+
+ va_end(args);
+}
+
+/******************************************************************************/
+
+bool ejsGotException(Ejs *ep)
+{
+ return (bool) ep->gotException;
+}
+
+/******************************************************************************/
+
+void ejsSetPrimaryHandle(Ejs *ep, void *primaryHandle)
+{
+ mprAssert(ep);
+
+ ep->primaryHandle = primaryHandle;
+}
+
+/******************************************************************************/
+
+void ejsSetAlternateHandle(Ejs *ep, void *alternateHandle)
+{
+ mprAssert(ep);
+
+ ep->altHandle = alternateHandle;
+}
+
+/******************************************************************************/
+
+#else
+void ejsDummy() {}
+
+#endif /* BLD_FEATURE_EJS */
+
+/******************************************************************************/
+/*
+ * 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-2.0/ejs/ejs.h b/source4/lib/appweb/ejs-2.0/ejs/ejs.h
new file mode 100644
index 0000000000..a926446524
--- /dev/null
+++ b/source4/lib/appweb/ejs-2.0/ejs/ejs.h
@@ -0,0 +1,849 @@
+/*
+ * ejs.h - EJScript Language (ECMAScript) header.
+ */
+
+/********************************* Copyright **********************************/
+/*
+ * @copy default.g
+ *
+ * Copyright (c) Mbedthis Software LLC, 2003-2006. All Rights Reserved.
+ * Copyright (c) Michael O'Brien, 1994-1995. All Rights Reserved.
+ * Portions Copyright (c) GoAhead Software, 1995-2000. 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
+ */
+/********************************** Includes **********************************/
+
+#ifndef _h_EJS
+#define _h_EJS 1
+
+#include "mpr.h"
+#include "ejsVar.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/********************************* Prototypes *********************************/
+/*
+ * Constants
+ */
+#if BLD_FEATURE_SQUEEZE
+ #define EJS_GC_WORK_QUOTA 160 /* Allocations required before
+ garbage colllection */
+
+ #define EJS_PARSE_INCR 256 /* Growth factor */
+ #define EJS_MAX_RECURSE 25 /* Sanity for maximum recursion */
+ #define EJS_SMALL_OBJ_HASH_SIZE 11 /* Small object hash size */
+ #define EJS_LIST_INCR 8 /* Growth increment for lists */
+ #define EJS_MAX_BACKTRACE 10 /* Recursion limit for assert */
+
+#else
+ #define EJS_GC_WORK_QUOTA 500
+
+ #define EJS_PARSE_INCR 1024
+ #define EJS_MAX_RECURSE 100
+ #define EJS_SMALL_OBJ_HASH_SIZE 11
+ #define EJS_LIST_INCR 16
+ #define EJS_MAX_BACKTRACE 25
+
+#endif
+
+/*
+ * Allocation increments for the default interpreter
+ */
+#define EJS_DEFAULT_VAR_INC 8 /* Var allocation increment */
+#define EJS_DEFAULT_PROP_INC 96 /* Property allocation increment */
+#define EJS_DEFAULT_OBJ_INC 24 /* Object allocation increment */
+#define EJS_DEFAULT_STR_INC 64 /* Object allocation increment */
+
+#define EJS_MIN_TIME_FOR_GC 300 /**< Need 1/3 sec for GC */
+#define EJS_GC_MIN_WORK_QUOTA 50 /**< Min to stop thrashing */
+
+/*
+ * Allocation increments for all non-default interpreters
+ */
+#define EJS_VAR_INC 32
+#define EJS_PROP_INC 64
+#define EJS_OBJ_INC 64
+#define EJS_STR_INC 64
+
+#define EJS_INC_FRAMES 8 /* Frame stack increment */
+#define EJS_MAX_FRAMES 64 /* Max frame stack */
+
+/*
+ * Lexical analyser tokens
+ */
+#define EJS_TOK_ERR -1 /* Any error */
+#define EJS_TOK_LPAREN 1 /* ( */
+#define EJS_TOK_RPAREN 2 /* ) */
+#define EJS_TOK_IF 3 /* if */
+#define EJS_TOK_ELSE 4 /* else */
+#define EJS_TOK_LBRACE 5 /* { */
+#define EJS_TOK_RBRACE 6 /* } */
+#define EJS_TOK_LOGICAL 7 /* ||, &&, ! */
+#define EJS_TOK_EXPR 8 /* +, -, /, % */
+#define EJS_TOK_SEMI 9 /* ; */
+#define EJS_TOK_LITERAL 10 /* literal string */
+#define EJS_TOK_METHOD_NAME 11 /* methodName( */
+#define EJS_TOK_NEWLINE 12 /* newline white space */
+#define EJS_TOK_ID 13 /* Identifier */
+#define EJS_TOK_EOF 14 /* End of script */
+#define EJS_TOK_COMMA 15 /* Comma */
+#define EJS_TOK_VAR 16 /* var */
+#define EJS_TOK_ASSIGNMENT 17 /* = */
+#define EJS_TOK_FOR 18 /* for */
+#define EJS_TOK_INC_DEC 19 /* ++, -- */
+#define EJS_TOK_RETURN 20 /* return */
+#define EJS_TOK_PERIOD 21 /* . */
+#define EJS_TOK_LBRACKET 22 /* [ */
+#define EJS_TOK_RBRACKET 23 /* ] */
+#define EJS_TOK_NEW 24 /* new */
+#define EJS_TOK_DELETE 25 /* delete */
+#define EJS_TOK_IN 26 /* in */
+#define EJS_TOK_FUNCTION 27 /* function */
+#define EJS_TOK_NUMBER 28 /* Number */
+#define EJS_TOK_CLASS 29 /* class */
+#define EJS_TOK_EXTENDS 30 /* extends */
+#define EJS_TOK_PUBLIC 31 /* public */
+#define EJS_TOK_PRIVATE 32 /* private */
+#define EJS_TOK_PROTECTED 33 /* private */
+#define EJS_TOK_TRY 34 /* try */
+#define EJS_TOK_CATCH 35 /* catch */
+#define EJS_TOK_FINALLY 36 /* finally */
+#define EJS_TOK_THROW 37 /* throw */
+#define EJS_TOK_COLON 38 /* : */
+#define EJS_TOK_GET 39 /* get */
+#define EJS_TOK_SET 40 /* set */
+#define EJS_TOK_MODULE 41 /* module */
+#define EJS_TOK_EACH 42 /* each */
+
+/*
+ * Expression operators
+ */
+#define EJS_EXPR_LESS 1 /* < */
+#define EJS_EXPR_LESSEQ 2 /* <= */
+#define EJS_EXPR_GREATER 3 /* > */
+#define EJS_EXPR_GREATEREQ 4 /* >= */
+#define EJS_EXPR_EQ 5 /* == */
+#define EJS_EXPR_NOTEQ 6 /* != */
+#define EJS_EXPR_PLUS 7 /* + */
+#define EJS_EXPR_MINUS 8 /* - */
+#define EJS_EXPR_DIV 9 /* / */
+#define EJS_EXPR_MOD 10 /* % */
+#define EJS_EXPR_LSHIFT 11 /* << */
+#define EJS_EXPR_RSHIFT 12 /* >> */
+#define EJS_EXPR_MUL 13 /* * */
+#define EJS_EXPR_ASSIGNMENT 14 /* = */
+#define EJS_EXPR_INC 15 /* ++ */
+#define EJS_EXPR_DEC 16 /* -- */
+#define EJS_EXPR_BOOL_COMP 17 /* ! */
+
+/*
+ * Conditional operators
+ */
+#define EJS_COND_AND 1 /* && */
+#define EJS_COND_OR 2 /* || */
+#define EJS_COND_NOT 3 /* ! */
+
+/**
+ * EJ Parsing States. Error and Return are be negative.
+ */
+#define EJS_STATE_ERR -1 /**< Error state */
+#define EJS_STATE_RET -2 /**< Return statement */
+#define EJS_STATE_EOF -3 /**< End of file */
+#define EJS_STATE_COND 2 /* Parsing a conditional stmt */
+#define EJS_STATE_COND_DONE 3
+#define EJS_STATE_RELEXP 4 /* Parsing a relational expr */
+#define EJS_STATE_RELEXP_DONE 5
+#define EJS_STATE_EXPR 6 /* Parsing an expression */
+#define EJS_STATE_EXPR_DONE 7
+#define EJS_STATE_STMT 8 /* Parsing General statement */
+#define EJS_STATE_STMT_DONE 9
+#define EJS_STATE_STMT_BLOCK_DONE 10 /* End of block "}" */
+#define EJS_STATE_ARG_LIST 11 /* Method arg list */
+#define EJS_STATE_ARG_LIST_DONE 12
+#define EJS_STATE_DEC_LIST 16 /* Declaration list */
+#define EJS_STATE_DEC_LIST_DONE 17
+#define EJS_STATE_DEC 18 /* Declaration statement */
+#define EJS_STATE_DEC_DONE 19
+
+#define EJS_STATE_BEGIN EJS_STATE_STMT
+
+/*
+ * General parsing flags.
+ */
+#define EJS_FLAGS_EXE 0x1 /* Execute statements */
+#define EJS_FLAGS_LOCAL 0x2 /* Get local vars only */
+#define EJS_FLAGS_GLOBAL 0x4 /* Get global vars only */
+#define EJS_FLAGS_CREATE 0x8 /* Create var */
+#define EJS_FLAGS_ASSIGNMENT 0x10 /* In assignment stmt */
+#define EJS_FLAGS_DELETE 0x20 /* Deleting a variable */
+#define EJS_FLAGS_NEW 0x80 /* In a new stmt() */
+#define EJS_FLAGS_EXIT 0x100 /* Must exit */
+#define EJS_FLAGS_LHS 0x200 /* Left-hand-side of assignment */
+#define EJS_FLAGS_FORIN 0x400 /* In "for (v in ..." */
+#define EJS_FLAGS_CLASS_DEC 0x800 /* "class name [extends] name " */
+#define EJS_FLAGS_TRY 0x2000 /* In a try {} block */
+#define EJS_FLAGS_CATCH 0x4000 /* "catch (variable)" */
+#define EJS_FLAGS_DONT_GC 0x8000 /* Don't garbage collect */
+#define EJS_FLAGS_NO_ARGS 0x10000 /* Accessors don't use args */
+#define EJS_FLAGS_ENUM_HIDDEN 0x20000 /* Enumerate hidden fields */
+#define EJS_FLAGS_ENUM_BASE 0x40000 /* Enumerate base classes */
+#define EJS_FLAGS_TRACE_ARGS 0x80000 /* Support for printv */
+#define EJS_FLAGS_SHARED_SLAB 0x100000/* Using a shared slab */
+
+/*
+ * Exceptions
+ */
+#define EJS_ARG_ERROR "ArgError" /**< Method argument error */
+#define EJS_ASSERT_ERROR "AssertError" /**< Assertion error */
+#define EJS_EVAL_ERROR "EvalError" /**< General evalation error */
+#define EJS_INTERNAL_ERROR "InternalError" /**< Internal error */
+#define EJS_IO_ERROR "IOError" /**< IO or data error */
+#define EJS_MEMORY_ERROR "MemoryError" /**< Memory allocation error */
+#define EJS_RANGE_ERROR "RangeError" /**< Data out of range (div by 0) */
+#define EJS_REFERENCE_ERROR "ReferenceError"/**< Object or property reference */
+#define EJS_SYNTAX_ERROR "SyntaxError" /**< Javascript syntax error */
+#define EJS_TYPE_ERROR "TypeError" /**< Wrong type supplied */
+
+/*
+ * E4X
+ */
+#if BLD_FEATURE_EJS_E4X
+#if BLD_FEATURE_SQUEEZE
+#define E4X_BUF_SIZE 512 /* Initial buffer size for tokens */
+#define E4X_BUF_MAX (32 * 1024) /* Max size for tokens */
+#define E4X_MAX_NODE_DEPTH 24 /* Max nesting of tags */
+#else
+#define E4X_BUF_SIZE 4096
+#define E4X_BUF_MAX (128 * 1024)
+#define E4X_MAX_NODE_DEPTH 128
+#endif
+
+#define E4X_MAX_ELT_SIZE (E4X_BUF_MAX-1)
+#define E4X_TEXT_PROPERTY "-txt"
+#define E4X_TAG_NAME_PROPERTY "-tag"
+#define E4X_COMMENT_PROPERTY "-com"
+#define E4X_ATTRIBUTES_PROPERTY "-att"
+#define E4X_PI_PROPERTY "-pi"
+#define E4X_PARENT_PROPERTY "-parent"
+#endif
+
+#if BLD_FEATURE_MULTITHREAD
+/**
+ * Multithreaded lock function
+ */
+typedef void (*EjsLockFn)(void *lockData);
+/**
+ * Multithreaded unlock function
+ */
+typedef void (*EjsUnlockFn)(void *lockData);
+#endif
+
+/*
+ * Token limits
+ */
+#define EJS_MAX_LINE 128 /* Maximum input line buffer */
+#define EJS_MAX_TOKEN 640 /* Max input parse token */
+#define EJS_TOKEN_STACK 3 /* Put back token stack */
+
+/*
+ * Putback token
+ */
+
+typedef struct EjsToken {
+ char tokbuf[EJS_MAX_TOKEN];
+ int tid; /* Token ID */
+} EjsToken;
+
+/*
+ * EJ evaluation block structure
+ */
+typedef struct EjsInput {
+ EjsToken putBack[EJS_TOKEN_STACK]; /* Put back token stack */
+ int putBackIndex; /* Top of stack index */
+ char line[EJS_MAX_LINE]; /* Current line */
+ char *fileName; /* File or script name */
+ int lineLength; /* Current line length */
+ int lineNumber; /* Parse line number */
+ int lineColumn; /* Column in line */
+ struct EjsInput *next; /* Used for backtraces */
+ const char *procName; /* Gives name in backtrace */
+ const char *script; /* Input script for parsing */
+ char *scriptServp; /* Next token in the script */
+ int scriptSize; /* Length of script */
+ char tokbuf[EJS_MAX_TOKEN]; /* Current token */
+ int tid; /* Token ID */
+ char *tokEndp; /* Pointer past end of token */
+ char *tokServp; /* Pointer to next token char */
+ struct EjsInput *nextInput; /* Free list of input structs */
+} EjsInput;
+
+/*
+ * Method call structure
+ */
+typedef struct EjsProc {
+ MprArray *args; /* Args for method */
+ EjsVar *fn; /* Method definition */
+ char *procName; /* Method name */
+} EjsProc;
+
+
+/**
+ * @overview EJScript Service structure
+ * @description The EJScript service manages the overall language runtime. It
+ * is the factory that creates interpreter instances via ejsCreateInterp.
+ * The EJScript service creates a master interpreter that holds the
+ * standard language classes and properties. When user interpreters are
+ * created, they reference (without copying) the master interpreter to
+ * gain access to the standard classes and types.
+ * @stability Prototype.
+ * @library libejs.
+ * @see ejsOpenService, ejsCloseService, ejsCreateInterp, ejsDestoryInterp
+ */
+typedef struct EjsService {
+ EjsVar *globalClass; /* Global class */
+ struct Ejs *master; /* Master Interp inherited by all */
+#if BLD_FEATURE_MULTITHREAD
+ EjsLockFn lock;
+ EjsUnlockFn unlock;
+ void *lockData;
+#endif
+} EjsService;
+
+
+/*
+ * Memory statistics
+ */
+typedef struct EjsMemStats {
+ uint maxMem;
+ uint usedMem;
+} EjsMemStats;
+
+
+/*
+ * Garbage collection block alignment
+ */
+#define EJS_ALLOC_ALIGN(ptr) \
+ (((ptr) + sizeof(void*) - 1) & ~(sizeof(void*) - 1))
+
+/*
+ * Default GC tune factors
+ */
+#define EJS_GC_START_THRESHOLD (32 * 1024)
+
+/*
+ * The Garbage collector is a generational collector. It ages blocks and
+ * optimizes the mark / sweep algorithm to focus on new and recent blocks
+ */
+typedef enum EjsGeneration {
+ EJS_GEN_NEW = 0,
+ EJS_GEN_RECENT_1 = 1,
+ EJS_GEN_RECENT_2 = 2,
+ EJS_GEN_OLD = 3,
+ EJS_GEN_PERMANENT = 4,
+ EJS_GEN_MAX = 5,
+} EjsGeneration;
+
+/*
+ * Garbage collector control
+ */
+typedef struct EjsGC {
+ bool enable;
+ bool enableDemandCollect;
+ bool enableIdleCollect;
+ /*
+ * maxMemory should be set to be 95% of the real max memory limit
+ */
+ uint maxMemory; /* Above this, Throw Memory exception. */
+ int workQuota; /* Quota of work before GC */
+ int workDone; /* Count of allocations */
+ int degraded; /* Have exceeded maxMemory */
+
+ /*
+ * Debug Levels 0-N (increases verbosity)
+ * 1 -- Sweep and collection count
+ * 2 -- Trace objects deleted
+ * 3 -- Trace objects marked
+ * 4 -- Print alloc report when needing a demand allocation
+ *
+ */
+ int debugLevel; /* In debug mode */
+ int collecting; /* Running garbage collection */
+ uint collectionCount; /* Number of times GC ran */
+#if BLD_DEBUG
+ int gcIndent; /* Indent formatting */
+ int objectsInUse; /* Objects currently reachable */
+ int propertiesInUse; /* Properties currently reachable */
+#endif
+} EjsGC;
+
+/*
+ * Slab memory allocation
+ */
+typedef struct EjsSlab {
+ uint allocIncrement; /* Growth increment in slab */
+ uint size; /* Size of allocations */
+ EjsGCLink freeList; /* Free list (only next ptr is used) */
+ EjsObj *lastRecentBlock; /* Saved for GC age generations phase */
+ EjsGCLink allocList[EJS_GEN_MAX]; /* Allocated block list */
+
+#if BLD_FEATURE_ALLOC_STATS
+ uint totalAlloc; /* Total count of allocation calls */
+ uint freeCount; /* Number of blocks on the slab freelist */
+ uint allocCount; /* Number of allocated blocks */
+ uint peakAllocated; /* Peak allocated */
+ uint peakFree; /* Peak on the free list */
+ uint totalReclaimed; /* Total blocks reclaimed on sweeps */
+ uint totalSweeps; /* Total sweeps */
+#endif
+} EjsSlab;
+
+
+/**
+ * @overview EJ interpreter control structure.
+ * @description EJ allocates one control structure per active interpreter.
+ * The \ref ejsCreateInterp routine creates the Ejs structure and returns
+ * a reference to be used in subsequent EJ API calls.
+ * @stability Prototype.
+ * @library libejs.
+ * @see ejsCreateInterp, ejsDestroyInterp, ejsOpenService
+ */
+struct Ejs {
+ void *altHandle; /* Alternate callback handle */
+ bool castAlloc; /* True if castTemp is allocated */
+ char *castTemp; /* Temporary string for casting */
+ char *currentClass; /* Current class name */
+ EjsVar *currentObj; /* Ptr to current object */
+ EjsVar *thisObject; /* Ptr to current "this" */
+ EjsProperty *currentProperty; /* Ptr to current property */
+ EjsGC gc; /* Garbage collector control */
+ char *errorMsg; /* Error message */
+ char *fileName; /* File or script name */
+ int lineNumber; /* File line number */
+ int scriptStatus; /* Status to exit() */
+ int flags; /* Flags */
+ MprArray *frames; /* List of variable frames */
+ EjsVar *global; /* Global object */
+ EjsVar *objectClass; /* Object class */
+ int gotException; /* Exception thrown */
+ EjsInput *input; /* Input evaluation block */
+ int depth; /* Recursion depth */
+ EjsVar *local; /* Local object */
+ int maxDepth; /* Maximum depth for formatting */
+ void *primaryHandle; /* primary callback handle */
+ EjsProc *proc; /* Current method */
+ int recurseCount; /* Recursion counter */
+ EjsVar *result; /* Variable result */
+ int tid; /* Current token id */
+ char *token; /* Pointer to token string */
+ EjsVar tokenNumber; /* Parsed number */
+ EjsService *service; /* Service object */
+ void *userData; /* Method user data */
+
+ EjsSlab *slabs; /* Memory allocation slabs */
+ MprCtx slabAllocContext; /* Allocation context */
+ EjsInput *inputList; /* Free list of input structs */
+
+#if BLD_FEATURE_MULTITHREAD
+ EjsLockFn lock; /* Lock method */
+ EjsUnlockFn unlock; /* Unlock method */
+ void *lockData; /* Lock data argument */
+#endif
+#define EJS_MAX_STACK (10 * 1024)
+ char stack[EJS_MAX_STACK]; /* Local variable stack */
+ char *stkPtr; /* Local variable stack ptr */
+ void *inputMarker; /* Recurse protection */
+};
+
+
+typedef struct EjsModule
+{
+ int dummy;
+} EjsModule;
+
+
+/*
+ * Method callback when using Alternate handles. GaCompat uses these and
+ * passes the web server request structure via the altHandle.
+ */
+typedef void *EjsHandle;
+typedef int (*EjsAltCMethod)(Ejs *ejs, EjsHandle altHandle,
+ EjsVar *thisObj, int argc, EjsVar **argv);
+typedef int (*EjsAltStringCMethod)(Ejs *ejs, EjsHandle altHandle,
+ EjsVar *thisObj, int argc, char **argv);
+
+
+/*
+ * API Constants
+ */
+#define EJS_USE_OWN_SLAB 1
+
+/******************************** Internal API ********************************/
+/*
+ * Ejs Lex
+ */
+extern int ejsLexOpenScript(Ejs *ejs, const char *script);
+extern void ejsLexCloseScript(Ejs *ejs);
+extern int ejsInitInputState(EjsInput *ip);
+extern void ejsLexSaveInputState(Ejs *ejs, EjsInput* state);
+extern void ejsLexFreeInputState(Ejs *ejs, EjsInput* state);
+extern void ejsLexRestoreInputState(Ejs *ejs, EjsInput* state);
+extern int ejsLexGetToken(Ejs *ejs, int state);
+extern void ejsLexPutbackToken(Ejs *ejs, int tid, char *string);
+
+/*
+ * Parsing
+ */
+extern int ejsParse(Ejs *ejs, int state, int flags);
+extern int ejsGetFlags(Ejs *ejs);
+
+/*
+ * Create variable scope blocks
+ */
+extern int ejsOpenBlock(Ejs *ejs);
+extern int ejsSetBlock(Ejs *ejs, EjsVar *local);
+extern int ejsCloseBlock(Ejs *ejs, int vid);
+extern int ejsEvalBlock(Ejs *ejs, char *script, EjsVar *vp);
+extern void ejsSetFileName(Ejs *ejs, const char *fileName);
+
+/*
+ * Class definitions
+ */
+extern EjsVar *ejsCreateSimpleClass(Ejs *ejs, EjsVar *baseClass,
+ const char *className);
+extern int ejsDefineObjectClass(Ejs *ejs);
+extern int ejsDefineArrayClass(Ejs *ejs);
+extern int ejsDefineBooleanClass(Ejs *ejs);
+extern int ejsDefineErrorClasses(Ejs *ejs);
+extern int ejsDefineFileClass(Ejs *ejs);
+extern int ejsDefineFileSystemClass(Ejs *ejs);
+extern int ejsDefineHTTPClass(Ejs *ejs);
+extern int ejsDefineFunctionClass(Ejs *ejs);
+extern int ejsDefineNumberClass(Ejs *ejs);
+extern int ejsDefineStringClass(Ejs *ejs);
+extern int ejsDefineDateClass(Ejs *ejs);
+extern int ejsDefineStandardClasses(Ejs *ejs);
+
+#if BLD_FEATURE_EJS_E4X
+extern int ejsDefineXmlClasses(Ejs *ejs);
+extern EjsVar *ejsCreateXml(Ejs *ejs);
+#endif
+
+#if BLD_FEATURE_EJS_DB
+extern int ejsDefineDbClasses(Ejs *ejs);
+#endif
+
+/*
+ * System class definitions
+ */
+extern int ejsDefineSystemClasses(Ejs *ejs);
+extern int ejsDefineSystemClass(Ejs *ejs);
+extern int ejsDefineAppClass(Ejs *ejs);
+extern int ejsDefineDebugClass(Ejs *ejs);
+extern int ejsDefineLogClass(Ejs *ejs);
+extern int ejsDefineMemoryClass(Ejs *ejs);
+extern int ejsDefineGCClass(Ejs *ejs);
+extern int ejsDefineGlobalProperties(Ejs *ejs);
+
+extern int ejsTermSystemClasses(Ejs *ejs);
+extern void ejsTermHTTPClass(Ejs *ejs);
+
+extern int ejsCreateObjectModel(Ejs *ejs);
+
+/*
+ * Class constructors
+ */
+extern int ejsArrayConstructor(Ejs *ejs, EjsVar *thisObj, int argc,
+ EjsVar **argv);
+extern int ejsXmlConstructor(Ejs *ejs, EjsVar *thisObj, int argc,
+ EjsVar **argv);
+extern int ejsXmlListConstructor(Ejs *ejs, EjsVar *thisObj, int argc,
+ EjsVar **argv);
+extern int ejsBooleanConstructor(Ejs *ejs, EjsVar *thisObj, int argc,
+ EjsVar **agv);
+extern int ejsFunctionConstructor(Ejs *ejs, EjsVar *thisObj, int argc,
+ EjsVar **agv);
+extern int ejsNumberConstructor(Ejs *ejs, EjsVar *thisObj, int argc,
+ EjsVar **argv);
+extern int ejsStringConstructor(Ejs *ejs, EjsVar *thisObj, int argc,
+ EjsVar **argv);
+extern int ejsDateConstructor(Ejs *ejs, EjsVar *thisObj,
+ int argc, EjsVar **argv);
+
+/*
+ * Garbage collection
+ */
+extern void ejsGCInit(Ejs *ejs, int objInc, int propInc, int varInc,
+ int strInc);
+extern int ejsIsTimeForGC(Ejs *ep, int timeTillNextEvent);
+
+extern bool ejsSetGCDebugLevel(Ejs *ep, int debugLevel);
+extern void ejsSweepAll(Ejs *ep);
+
+extern EjsObj *ejsAllocObj(EJS_LOC_DEC(ejs, loc));
+extern EjsProperty *ejsAllocProperty(EJS_LOC_DEC(ejs, loc));
+extern EjsVar *ejsAllocVar(EJS_LOC_DEC(ejs, loc));
+extern void ejsFree(Ejs *ejs, void *ptr, int slabIndex);
+
+extern int ejsCollectGarbage(Ejs *ejs, int slabIndex);
+extern int ejsIncrementalCollectGarbage(Ejs *ejs);
+
+#if BLD_DEBUG
+extern void ejsDumpObjects(Ejs *ejs);
+#endif
+
+#if BLD_FEATURE_ALLOC_STATS
+extern void ejsPrintAllocReport(Ejs *ejs, bool printLeakReport);
+#endif
+
+extern void ejsCleanInterp(Ejs *ejs, bool doStats);
+extern void ejsSetInternalMethods(Ejs *ejs, EjsVar *op);
+extern void ejsSetPrimaryHandle(Ejs *ep, void *primaryHandle);
+extern void ejsSetAlternateHandle(Ejs *ep, void *alternateHandle);
+extern void *ejsGetUserData(Ejs *ejs);
+
+/*
+ * Could possibly make these routines public
+ */
+
+extern int ejsSetGCMaxMemory(Ejs *ep, uint maxMemory);
+extern uint ejsGetUsedMemory(Ejs *ejs);
+extern uint ejsGetAllocatedMemory(Ejs *ejs);
+extern uint ejsGetAvailableMemory(Ejs *ejs);
+extern char *ejsFormatStack(Ejs* ep);;
+
+/********************************* Prototypes *********************************/
+#if BLD_FEATURE_MULTITHREAD
+extern int ejsSetServiceLocks(EjsService *sp, EjsLockFn lock,
+ EjsUnlockFn unlock, void *data);
+#endif
+
+/*
+ * Ejs service and interpreter management
+ */
+extern EjsService *ejsOpenService(MprCtx ctx);
+extern void ejsCloseService(EjsService *sp, bool doStats);
+
+extern Ejs *ejsCreateInterp(EjsService *sp, void *primaryHandle,
+ void *altHandle, EjsVar *global, bool useOwnSlab);
+extern void ejsDestroyInterp(Ejs *ejs, bool doStats);
+
+extern Ejs *ejsGetMasterInterp(EjsService *sp);
+extern EjsVar *ejsGetGlobalClass(Ejs *ejs);
+
+/*
+ * Module support
+ */
+extern EjsModule *ejsCreateModule(const char *name, const char *version,
+ int (*start)(EjsModule*), int (*stop)(EjsModule*));
+
+/*
+ * Native Objects
+ */
+
+void ejsSetNativeData(EjsVar *obj, void *data);
+void ejsSetNativeHelpers(Ejs *ejs, EjsVar *nativeClass,
+ int (*createInstance)(Ejs *ejs, EjsVar *thisObj, int argc,
+ EjsVar **argv),
+ void (*disposeInstance)(Ejs *ejs, EjsVar *thisObj),
+ bool (*hasProperty)(Ejs *ejs, EjsVar *thisObj, const char *prop),
+ int (*deleteProperty)(Ejs *ejs, EjsVar *thisObj, const char *prop),
+ int (*getProperty)(Ejs *ejs, EjsVar *thisObj, const char *prop,
+ EjsVar *dest),
+ int (*setProperty)(Ejs *ejs, EjsVar *thisObj, const char *prop,
+ EjsVar *value),
+ int (*doOperator)(Ejs *ejs, EjsVar *thisObj, EjsOp *op, EjsVar
+ *result, EjsVar *lhs, EjsVar *rhs, int *code)
+ );
+
+/*
+ * Evaluation methods
+ */
+extern int ejsEvalFile(Ejs *ejs, const char *path, EjsVar *result);
+extern int ejsEvalScript(Ejs *ejs, const char *script, EjsVar *result);
+extern int ejsRunMethod(Ejs *ejs, EjsVar *obj,
+ const char *methodName, MprArray *args);
+extern int ejsRunMethodCmd(Ejs *ejs, EjsVar *obj,
+ const char *methodName, const char *cmdFmt, ...);
+extern EjsVar *ejsGetReturnValue(Ejs *ejs);
+
+extern EjsVar *ejsGetLocalObj(Ejs *ejs);
+extern EjsVar *ejsGetGlobalObj(Ejs *ejs);
+
+/*
+ * Define a class in the specified interpreter. If used with the default
+ * interpeter, then the class is defined for all interpreters.
+ */
+extern EjsVar *ejsDefineClass(Ejs *ejs, const char *className,
+ const char *extends, EjsCMethod constructor);
+extern EjsVar *ejsGetClass(Ejs *ejs, EjsVar *parentClass,
+ const char *className);
+
+extern const char *ejsGetClassName(EjsVar *obj);
+extern const char *ejsGetBaseClassName(EjsVar *obj);
+
+extern bool ejsIsSubClass(EjsVar *target, EjsVar *baseClass);
+extern EjsVar *ejsGetBaseClass(EjsVar *obj);
+extern void ejsSetBaseClass(EjsVar *obj, EjsVar *baseClass);
+
+
+#define ejsCreateSimpleObj(ejs, className) \
+ ejsCreateSimpleObjInternal(EJS_LOC_ARGS(ejs), className)
+extern EjsVar *ejsCreateSimpleObjInternal(EJS_LOC_DEC(ejs, loc),
+ const char *className);
+
+#define ejsCreateSimpleObjUsingClass(ejs, baseClass) \
+ ejsCreateSimpleObjUsingClassInt(EJS_LOC_ARGS(ejs), \
+ baseClass)
+extern EjsVar *ejsCreateSimpleObjUsingClassInt(EJS_LOC_DEC(ejs, loc),
+ EjsVar *baseClass);
+
+/*
+ * This will create an object and call all required constructors
+ */
+extern EjsVar *ejsCreateObj(Ejs *ejs, EjsVar *obj,
+ const char *className, const char *constructorArgs);
+
+#define ejsCreateObjUsingArgv(ejs, obj, className, args) \
+ ejsCreateObjUsingArgvInternal(EJS_LOC_ARGS(ejs), obj, \
+ className, args)
+extern EjsVar *ejsCreateObjUsingArgvInternal(EJS_LOC_DEC(ejs, loc),
+ EjsVar *obj, const char *className, MprArray *args);
+
+#define ejsCreateArray(ejs, size) \
+ ejsCreateArrayInternal(EJS_LOC_ARGS(ejs), size)
+extern EjsVar *ejsCreateArrayInternal(EJS_LOC_DEC(ejs, loc),
+ int size);
+
+/*
+ * Array methods. MOB -- need other array methods
+ */
+/* MOB -- spell out element */
+extern EjsVar *ejsAddArrayElt(Ejs *ejs, EjsVar *op, EjsVar *element,
+ EjsCopyDepth copyDepth);
+/*
+ * Required: Array methods
+ *
+ array = obj.getMethods();
+ array = obj.getProperties();
+
+ array.property.isPublic();
+ array.property.isPrivate();
+ array.property.isMethod();
+ array.property.isEnumerable();
+ array.property.isReadOnly();
+ array.property.allowsNonUnique();
+ array.property.getParent();
+*/
+
+/* MOB -- should we have an API that takes a EjsCopyDepth */
+extern void ejsSetReturnValue(Ejs *ejs, EjsVar *vp);
+extern void ejsSetReturnValueAndFree(Ejs *ejs, EjsVar *vp);
+extern void ejsSetReturnValueToBoolean(Ejs *ejs, bool value);
+extern void ejsSetReturnValueToBinaryString(Ejs *ejs,
+ const uchar *value, int len);
+extern void ejsSetReturnValueToInteger(Ejs *ejs, int value);
+extern void ejsSetReturnValueToNumber(Ejs *ejs, EjsNum value);
+extern void ejsSetReturnValueToString(Ejs *ejs, const char *value);
+extern void ejsSetReturnValueToUndefined(Ejs *ejs);
+
+/*
+ * Variable access and control. The fullName arg can contain "[]" and "."
+ */
+extern bool ejsGetBool(Ejs *ejs, const char *fullName, bool defaultValue);
+extern int ejsGetInt(Ejs *ejs, const char *fullName, int defaultValue);
+extern const char *ejsGetStr(Ejs *ejs, const char *fullName,
+ const char *defaultValue);
+extern EjsVar *ejsGetVar(Ejs *ejs, const char *fullName);
+
+extern int ejsSetBool(Ejs *ejs, const char *fullName, bool value);
+extern int ejsSetInt(Ejs *ejs, const char *fullName, int value);
+extern int ejsSetStr(Ejs *ejs, const char *fullName, const char *value);
+extern int ejsSetVar(Ejs *ejs, const char *fullName, const EjsVar *value);
+extern int ejsSetVarAndFree(Ejs *ejs, const char *fullName, EjsVar *value);
+
+extern int ejsDeleteVar(Ejs *ejs, const char *fullName);
+
+/*
+ * Error handling
+ */
+extern void ejsError(Ejs *ejs, const char *errorType, const char *fmt,
+ ...) PRINTF_ATTRIBUTE(3,4);
+/* MOB -- this should take no arguments */
+extern void ejsArgError(Ejs *ejs, const char *msg);
+extern void ejsInternalError(Ejs *ejs, const char *msg);
+extern void ejsMemoryError(Ejs *ejs);
+extern void ejsSyntaxError(Ejs *ejs, const char *msg);
+
+/*
+ * Utility methods
+ */
+extern int ejsParseArgs(int argc, char **argv, const char *fmt, ...);
+
+extern void ejsExit(Ejs *ejs, int status);
+extern bool ejsIsExiting(Ejs *ejs);
+extern void ejsClearExiting(Ejs *ejs);
+
+extern bool ejsGotException(Ejs *ejs);
+
+/* MOB -- rename Method to Function */
+extern void ejsFreeMethodArgs(Ejs *ep, MprArray *args);
+extern int ejsStrcat(Ejs *ep, EjsVar *dest, EjsVar *src);
+
+/*
+ * Debugging routines
+ */
+extern char *ejsGetErrorMsg(Ejs *ejs);
+extern int ejsGetLineNumber(Ejs *ejs);
+extern void ejsTrace(Ejs *ejs, const char *fmt, ...);
+
+/*
+ * Multithreaded lock routines
+ */
+#if BLD_FEATURE_MULTITHREAD
+#define ejsLock(sp) if (sp->lock) { (sp->lock)(sp->lockData); } else
+#define ejsUnlock(sp) if (sp->unlock) { (sp->unlock)(sp->lockData); } else
+#else
+#define ejsLock(sp)
+#define ejsUnlock(sp)
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* _h_EJS */
+
+/*****************************************************************************/
+
+/*
+ * 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-2.0/ejs/ejsClass.c b/source4/lib/appweb/ejs-2.0/ejs/ejsClass.c
new file mode 100644
index 0000000000..58609adf3f
--- /dev/null
+++ b/source4/lib/appweb/ejs-2.0/ejs/ejsClass.c
@@ -0,0 +1,273 @@
+/*
+ * @file ejsClass.c
+ * @brief EJS class support
+ */
+/********************************* Copyright **********************************/
+/*
+ * @copy default
+ *
+ * Copyright (c) Mbedthis Software LLC, 2003-2006. 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
+ */
+/********************************* Includes ***********************************/
+
+#include "ejs.h"
+
+#if BLD_FEATURE_EJS
+
+/************************************ Code ************************************/
+/*
+ * Internal API
+ *
+ * Routine to create a simple class object. This routine will create a
+ * stand-alone class object. Callers must insert this into the relevant
+ * "global" object for name resolution. From these class objects, instance
+ * objects may be created via the javascript "new" command.
+ *
+ * Users should use ejsDefineClass
+ */
+
+EjsVar *ejsCreateSimpleClass(Ejs *ep, EjsVar *baseClass, const char *className)
+{
+ EjsProperty *pp;
+ EjsVar *classObj;
+
+ /*
+ * Create an instance of an Object to act as the static class object
+ */
+ classObj = ejsCreateSimpleObjUsingClass(ep, baseClass);
+ if (classObj == 0) {
+ mprAssert(classObj);
+ return 0;
+ }
+ ejsSetClassName(ep, classObj, className);
+
+ /*
+ * Set the propotype property to point to this class.
+ * Note: this is a self reference so the alive bit will not be turned on.
+ */
+ pp = ejsSetProperty(ep, classObj, "prototype", classObj);
+ ejsMakePropertyEnumerable(pp, 0);
+
+ return classObj;
+}
+
+/******************************************************************************/
+/*
+ * Define a class in the given interpreter. If parentClass is specified, the
+ * class is defined in the parent. Otherwise, the class will be defined
+ * locally/globally. ClassName and extends are full variable specs
+ * (may contain ".")
+ */
+
+EjsVar *ejsDefineClass(Ejs *ep, const char *className, const char *extends,
+ EjsCMethod constructor)
+{
+ EjsVar *parentClass, *classObj, *baseClass, *vp;
+ char *name;
+ char *cp;
+
+ /*
+ * If the className is a qualified name (with "."), then get the
+ * parent class name.
+ */
+ name = mprStrdup(ep, className);
+ cp = strrchr(name, '.');
+ if (cp != 0) {
+ *cp++ = '\0';
+ className = cp;
+ parentClass = ejsFindProperty(ep, 0, 0, ep->global, ep->local, name, 0);
+ if (parentClass == 0 || parentClass->type != EJS_TYPE_OBJECT) {
+ mprError(ep, MPR_LOC, "Can't find class's parent class %s", name);
+ mprFree(name);
+ return 0;
+ }
+
+ } else {
+ /*
+ * Simple class name without a "." so create the class locally
+ * if a local scope exists, otherwise globally.
+ */
+ parentClass = (ep->local) ? ep->local : ep->global;
+ }
+
+ if (parentClass == 0) {
+ mprError(ep, MPR_LOC, "Can't find parent class");
+ mprFree(name);
+ return 0;
+ }
+
+ /* OPT should use function that doesn't parse [] . */
+ baseClass = ejsGetClass(ep, 0, extends);
+ if (baseClass == 0) {
+ mprAssert(baseClass);
+ mprFree(name);
+ return 0;
+ }
+
+ classObj = ejsCreateSimpleClass(ep, baseClass, className);
+ if (classObj == 0) {
+ mprAssert(classObj);
+ mprFree(name);
+ return 0;
+ }
+
+ if (constructor) {
+ ejsDefineCMethod(ep, classObj, className, constructor, 0);
+ }
+
+ ejsSetPropertyAndFree(ep, parentClass, className, classObj);
+
+ vp = ejsGetPropertyAsVar(ep, parentClass, className);
+ mprFree(name);
+
+ return vp;
+}
+
+/******************************************************************************/
+/*
+ * Find a class and return the property defining the class. ClassName may
+ * contain "." and is interpreted relative to obj. Obj is typically some
+ * parent object, ep->local or ep->global. If obj is null, then the global
+ * space is used.
+ */
+
+EjsVar *ejsGetClass(Ejs *ep, EjsVar *obj, const char *className)
+{
+ EjsVar *vp;
+
+ mprAssert(ep);
+
+ /*
+ * Search first for a constructor of the name of class
+ * global may not be defined yet.
+ */
+ if (obj) {
+ vp = ejsFindProperty(ep, 0, 0, obj, 0, className, 0);
+
+ } else {
+ mprAssert(ep->global);
+ vp = ejsFindProperty(ep, 0, 0, ep->global, ep->local, className, 0);
+ }
+ if (vp == 0 || vp->type != EJS_TYPE_OBJECT) {
+ return 0;
+ }
+
+ /*
+ * Return a reference to the prototype (self) reference. This
+ * ensures that even if "obj" is deleted, this reference will remain
+ * usable.
+ */
+ return ejsGetPropertyAsVar(ep, vp, "prototype");
+}
+
+/******************************************************************************/
+/*
+ * Return the class name of a class or object
+ */
+
+const char *ejsGetClassName(EjsVar *vp)
+{
+ EjsObj *obj;
+
+ mprAssert(vp);
+ mprAssert(vp->type == EJS_TYPE_OBJECT);
+ mprAssert(vp->objectState->baseClass);
+
+ if (vp == 0 || !ejsVarIsObject(vp)) {
+ return 0;
+ }
+ obj = vp->objectState;
+
+ return obj->className;
+}
+
+/******************************************************************************/
+/*
+ * Return the class name of an objects underlying class
+ * If called on an object, it returns the base class.
+ * If called on a class, it returns the base class for the class.
+ */
+
+const char *ejsGetBaseClassName(EjsVar *vp)
+{
+ EjsObj *obj;
+
+ mprAssert(vp);
+ mprAssert(vp->type == EJS_TYPE_OBJECT);
+ mprAssert(vp->objectState->baseClass);
+
+ if (vp == 0 || !ejsVarIsObject(vp)) {
+ return 0;
+ }
+ obj = vp->objectState;
+ if (obj->baseClass == 0) {
+ return 0;
+ }
+ mprAssert(obj->baseClass->objectState);
+
+ return obj->baseClass->objectState->className;
+}
+
+/******************************************************************************/
+
+EjsVar *ejsGetBaseClass(EjsVar *vp)
+{
+ if (vp == 0 || !ejsVarIsObject(vp) || vp->objectState == 0) {
+ mprAssert(0);
+ return 0;
+ }
+ return vp->objectState->baseClass;
+}
+
+/******************************************************************************/
+
+void ejsSetBaseClass(EjsVar *vp, EjsVar *baseClass)
+{
+ if (vp == 0 || !ejsVarIsObject(vp) || vp->objectState == 0) {
+ mprAssert(0);
+ return;
+ }
+ vp->objectState->baseClass = baseClass;
+}
+
+/******************************************************************************/
+
+#else
+void ejsProcsDummy() {}
+
+/******************************************************************************/
+#endif /* BLD_FEATURE_EJS */
+
+/*
+ * 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-2.0/ejs/ejsCmd.c b/source4/lib/appweb/ejs-2.0/ejs/ejsCmd.c
new file mode 100644
index 0000000000..b5279c949a
--- /dev/null
+++ b/source4/lib/appweb/ejs-2.0/ejs/ejsCmd.c
@@ -0,0 +1,468 @@
+/*
+ * @file ejsCmd.c
+ * @brief Embedded JavaScript (EJS) command line program.
+ * @overview
+ */
+/********************************* Copyright **********************************/
+/*
+ * @copy default
+ *
+ * Copyright (c) Mbedthis Software LLC, 2003-2006. 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
+ */
+/********************************** Includes **********************************/
+
+#include "ejs.h"
+
+#if BLD_FEATURE_EJS && !BREW
+
+/************************************ Defines *********************************/
+
+#define EJS_MAX_CMD_LINE (16 * 1024)
+#define EJS_MAX_SCRIPT (4 * 1024 * 1024)
+#define EJS_MAX_RESULT_SIZE (4 * 1024 * 1024)
+#define EJS_PROMPT "ejs> "
+
+/****************************** Forward Declarations **************************/
+
+static int parseFile(EjsService *ejsService, Ejs *ejs, const char *fileName,
+ const char *testName, MprFile *testLogFile);
+static int ifConsole();
+
+static int interactiveUse(MprApp *app, Ejs *ejs, FILE *input,
+ char *fileName);
+static char *readCmd(MprApp *app, FILE *input);
+
+static int memoryFailure(MprApp *app, uint size, uint total, bool granted);
+
+static int isConsole = 0;
+static int traceCmds = 0;
+static int stats = 0;
+static int verbose = 0;
+
+/************************************ Main ************************************/
+
+int main(int argc, char *argv[])
+{
+ MprApp *app;
+ const char *programName;
+ MprFile *testLogFile;
+ EjsService *ejsService;
+ Ejs *ejs;
+ char *commandLine;
+ const char *testName;
+ char *argp, *cmd, *testLog;
+ int i, rc, nextArg, err, len, firstArg, iterations, debugLevel;
+
+ app = mprInit(memoryFailure);
+
+ isConsole = ifConsole();
+ programName = mprGetBaseName(argv[0]);
+ debugLevel = 0;
+
+ ejsService = ejsOpenService(app);
+ if (ejsService == 0) {
+ mprError(app, MPR_LOC, "Can't initialize the EJS service.");
+ return -1;
+ }
+
+ err = 0;
+ iterations = 1;
+ stats = 0;
+ testLog = getenv("TEST_LOG");
+ testLogFile = 0;
+ testName = 0;
+
+ for (nextArg = 1; nextArg < argc; nextArg++) {
+ argp = argv[nextArg];
+ if (*argp != '-') {
+ break;
+ }
+ if (strcmp(argp, "--debug") == 0) {
+ if (nextArg >= argc) {
+ err++;
+ } else {
+ debugLevel = atoi(argv[++nextArg]);
+ }
+
+ } else if (strcmp(argp, "--stats") == 0) {
+ stats++;
+
+ } else if (strcmp(argp, "--trace") == 0) {
+ traceCmds++;
+
+ } else if (strcmp(argp, "--iterations") == 0) {
+ if (nextArg >= argc) {
+ err++;
+ } else {
+ iterations = atoi(argv[++nextArg]);
+ }
+
+ } else if (strcmp(argp, "--log") == 0) {
+ /* Get file to log test results to when using ejs as a test shell */
+ if (nextArg >= argc) {
+ err++;
+ } else {
+ testLog = argv[++nextArg];
+ }
+
+ } else if (strcmp(argp, "--testName") == 0) {
+ if (nextArg >= argc) {
+ err++;
+ } else {
+ testName = argv[++nextArg];
+ }
+
+ } else if (strcmp(argp, "-v") == 0) {
+ verbose++;
+
+ } else if (strcmp(argp, "-vv") == 0) {
+ verbose += 2;
+
+ } else if (strcmp(argp, "--verbose") == 0) {
+ verbose += 2;
+
+ } else {
+ err++;
+ break;
+ }
+ if (err) {
+ mprErrorPrintf(app,
+ "Usage: %s [options] files... or\n"
+ " %s < file or\n"
+ " %s or\n"
+ " Switches:\n"
+ " --iterations num # Number of iterations to eval file\n"
+ " --stats # Output stats on exit\n"
+ " --testName name # Set the test name",
+ programName, programName, programName);
+ return -1;
+ }
+ }
+
+ if (testName) {
+ i = 0;
+ commandLine = 0;
+ len = mprAllocStrcat(MPR_LOC_ARGS(app), &commandLine, 0, " ",
+ mprGetBaseName(argv[i++]), 0);
+ for (; i < argc; i++) {
+ len = mprReallocStrcat(MPR_LOC_ARGS(app), &commandLine, 0, len,
+ " ", argv[i], 0);
+ }
+ mprPrintf(app, " %s\n", commandLine);
+ }
+ if (testLog) {
+ testLogFile = mprOpen(app, testLog,
+ O_CREAT | O_APPEND | O_WRONLY | O_TEXT, 0664);
+ if (testLogFile == 0) {
+ mprError(app, MPR_LOC, "Can't open %s", testLog);
+ return MPR_ERR_CANT_OPEN;
+ }
+ mprFprintf(testLogFile, "\n %s\n", commandLine);
+ }
+
+ ejs = ejsCreateInterp(ejsService, 0, 0, 0, 0);
+ if (ejs == 0) {
+ mprError(app, MPR_LOC, "Can't create EJS interpreter");
+ ejsCloseService(ejsService, stats);
+ if (testLogFile) {
+ mprClose(testLogFile);
+ }
+ mprTerm(app, stats);
+ exit(-1);
+ }
+
+ if (debugLevel > 0) {
+ ejsSetGCDebugLevel(ejs, debugLevel);
+ }
+
+ rc = 0;
+
+ if (nextArg < argc) {
+ /*
+ * Process files supplied on the command line
+ */
+ firstArg = nextArg;
+ for (i = 0; i < iterations; i++) {
+ for (nextArg = firstArg; nextArg < argc; nextArg++) {
+ rc = parseFile(ejsService, ejs, argv[nextArg], testName,
+ testLogFile);
+ if (rc < 0) {
+ return rc;
+ }
+ }
+ }
+ if (testName) {
+ if (verbose == 1) {
+ mprPrintf(app, "\n");
+ }
+ if (verbose <= 1) {
+ mprPrintf(app, " # PASSED all tests for \"%s\"\n", testName);
+ }
+ }
+
+ } else if (! isConsole) {
+ /*
+ * Read a script from stdin
+ */
+ cmd = readCmd(app, stdin);
+
+ ejsSetFileName(ejs, "stdin");
+
+ rc = ejsEvalScript(ejs, cmd, 0);
+ if (rc < 0) {
+ mprPrintf(app, "ejs: Error: %s\n", ejsGetErrorMsg(ejs));
+ }
+ mprFree(cmd);
+
+ } else {
+ /*
+ * Interactive use. Read commands from the command line.
+ */
+ rc = interactiveUse(app, ejs, stdin, "stdin");
+ }
+
+ /*
+ * Cleanup. Do stats if required.
+ */
+ if (ejs) {
+ ejsCleanInterp(ejs, 0);
+ ejsCleanInterp(ejs->service->master, 0);
+ ejsDestroyInterp(ejs, 0);
+ }
+
+ ejsCloseService(ejsService, stats);
+
+ if (testLogFile) {
+ mprClose(testLogFile);
+ }
+
+ mprTerm(app, stats);
+ return rc;
+}
+
+/******************************************************************************/
+
+static int parseFile(EjsService *ejsService, Ejs *ejs, const char *fileName,
+ const char *testName, MprFile *testLogFile)
+{
+ int rc;
+
+ if (testName && verbose == 1) {
+ mprPrintf(ejs, ".");
+ }
+ if (verbose > 1) {
+ mprPrintf(ejs, "File: %s\n", fileName);
+ }
+
+ rc = ejsEvalFile(ejs, fileName, 0);
+
+ if (testName) {
+ char fileBuf[MPR_MAX_FNAME], *cp;
+ mprStrcpy(fileBuf, sizeof(fileBuf), fileName);
+ if ((cp = strstr(fileBuf, ".ejs")) != 0) {
+ *cp = '\0';
+ }
+ if (rc == 0) {
+ if (verbose > 1) {
+ mprPrintf(ejs, " # PASSED test \"%s.%s\"\n", testName,
+ fileBuf);
+ }
+ if (testLogFile) {
+ mprFprintf(testLogFile, " # PASSED test \"%s.%s\"\n",
+ testName, fileBuf);
+ }
+
+ } else {
+
+ mprPrintf(ejs, "FAILED test \"%s.%s\"\nDetails: %s\n",
+ testName, fileBuf, ejsGetErrorMsg(ejs));
+
+ if (testLogFile) {
+ mprFprintf(testLogFile,
+ "FAILED test \"%s.%s\"\nDetails: %s\n",
+ testName, fileBuf, ejsGetErrorMsg(ejs));
+ }
+ }
+ } else if (rc < 0) {
+ mprPrintf(ejs, "ejs: %sIn file \"%s\"\n",
+ ejsGetErrorMsg(ejs), fileName);
+ }
+ return rc;
+}
+
+/******************************************************************************/
+
+static char *readCmd(MprApp *app, FILE *input)
+{
+ char line[EJS_MAX_CMD_LINE];
+ char *cmd;
+ int len, cmdLen;
+
+ cmd = 0;
+ cmdLen = 0;
+
+ line[sizeof(line) - 1] = '\0';
+
+ while (1) {
+
+ if (fgets(line, sizeof(line) - 1, input) == NULL) {
+ break;
+ }
+
+ len = strlen(line);
+
+ if (line[len - 1] == '\\') {
+ line[len - 1] = '\0';
+ }
+ cmdLen = mprReallocStrcat(MPR_LOC_ARGS(app), &cmd, EJS_MAX_SCRIPT,
+ cmdLen, 0, line, 0);
+ }
+ return cmd;
+}
+
+/******************************************************************************/
+
+static int interactiveUse(MprApp *app, Ejs *ejs, FILE *input, char *fileName)
+{
+ EjsVar result;
+ char line[EJS_MAX_CMD_LINE];
+ char *cmd, *buf;
+ int len, cmdLen, rc;
+
+ cmd = 0;
+ cmdLen = 0;
+
+ line[sizeof(line) - 1] = '\0';
+
+ ejsSetFileName(ejs, "console");
+
+ while (! ejsIsExiting(ejs)) {
+
+ if (isConsole) {
+ write(1, EJS_PROMPT, strlen(EJS_PROMPT));
+ }
+
+ if (fgets(line, sizeof(line) - 1, input) == NULL) {
+ break;
+ }
+
+ len = strlen(line);
+ while (len > 0 &&
+ (line[len - 1] == '\n' || line[len - 1] == '\r')) {
+ len--;
+ line[len] = '\0';
+ }
+
+ if (line[len - 1] == '\\') {
+ line[len - 1] = '\0';
+ cmdLen = mprReallocStrcat(MPR_LOC_ARGS(app), &cmd, EJS_MAX_SCRIPT,
+ cmdLen, 0, line, 0);
+
+ } else {
+
+ cmdLen = mprReallocStrcat(MPR_LOC_ARGS(app), &cmd, EJS_MAX_SCRIPT,
+ cmdLen, 0, line, 0);
+
+
+ if (traceCmds) {
+ mprPrintf(ejs, "# %s\n", cmd);
+ }
+
+ if (cmd[0] == 0x4 || cmd[0] == 0x26 || strcmp(cmd, "quit") == 0) {
+ ejsExit(ejs, 0);
+
+ } else if ((rc = ejsEvalScript(ejs, cmd, &result)) < 0) {
+
+ mprPrintf(app, "ejs: Error: %s\n", ejsGetErrorMsg(ejs));
+
+ if (! isConsole) {
+ return rc;
+ }
+
+ } else {
+ if (isConsole || traceCmds) {
+ buf = ejsVarToString(ejs, &result);
+ mprPrintf(ejs, "%s\n", buf);
+ }
+ }
+ mprFree(cmd);
+ cmd = 0;
+ cmdLen = 0;
+ }
+ }
+ return 0;
+}
+
+/******************************************************************************/
+
+static int ifConsole()
+{
+#if WIN
+ INPUT_RECORD irec[1];
+ int records = 0;
+
+ if (PeekConsoleInput(GetStdHandle(STD_INPUT_HANDLE), irec, 1,
+ &records) != 0) {
+ return 1;
+ }
+#else
+ return isatty(0);
+#endif
+ return 0;
+}
+
+/******************************************************************************/
+
+static int memoryFailure(MprApp *app, uint size, uint total, bool granted)
+{
+ if (!granted) {
+ mprPrintf(app, "Can't allocate memory block of size %d\n", size);
+ mprPrintf(app, "Total memory used %d\n", total);
+ exit(255);
+ }
+ mprPrintf(app, "Memory request for %d bytes exceeds memory red-line\n",
+ size);
+ mprPrintf(app, "Total memory used %d\n", total);
+ return 0;
+}
+
+/******************************************************************************/
+
+#else
+void ejsCmdLineDummy() {}
+
+/******************************************************************************/
+#endif /* BLD_FEATURE_EJS */
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: sw=4 ts=4 fdm=marker
+ * vim<600: sw=4 ts=4
+ */
diff --git a/source4/lib/appweb/ejs-2.0/ejs/ejsGarbage.c b/source4/lib/appweb/ejs-2.0/ejs/ejsGarbage.c
new file mode 100755
index 0000000000..264da05721
--- /dev/null
+++ b/source4/lib/appweb/ejs-2.0/ejs/ejsGarbage.c
@@ -0,0 +1,1214 @@
+/*
+ * @file ejsGarbage.c
+ * @brief EJS Garbage collector.
+ * @overview This implements a generational mark and sweep collection scheme.
+ */
+/********************************* Copyright **********************************/
+/*
+ * @copy default
+ *
+ * Copyright (c) Mbedthis Software LLC, 2003-2006. 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
+ */
+/********************************** Includes **********************************/
+
+#include "ejs.h"
+
+#if BLD_FEATURE_EJS
+
+/****************************** Forward Declarations **************************/
+
+static void mark(Ejs *ep);
+static void markObjByVar(Ejs *ep, EjsVar *op);
+static void markObj(EjsObj *obj);
+static void markPerm(Ejs *ep, uint gen);
+static int sweep(Ejs *ep, uint gen);
+static EjsGCLink *ejsAlloc(EJS_LOC_DEC(ep, loc), int slabIndex);
+static void ejsGracefulDegrade(Ejs *ep);
+static void resetMarks(Ejs *ep, EjsSlab *slab);
+
+#if FUTURE
+static void ageGenerations(Ejs *ep);
+#endif
+
+#if BLD_DEBUG && (!BREW || BREW_SIMULATOR)
+uint breakAddr;
+#endif
+
+/************************************* Code ***********************************/
+
+void ejsGCInit(Ejs *ep, int objInc, int propInc, int varInc, int strInc)
+{
+ EjsSlab *slab;
+
+ if (ep->service && ep->service->globalClass) {
+ ep->service->globalClass->objectState->gcMarked = 1;
+ }
+
+ slab = &ep->slabs[EJS_SLAB_OBJ];
+ slab->allocIncrement = objInc;
+ slab->size = EJS_ALLOC_ALIGN(sizeof(EjsObj));
+
+ slab = &ep->slabs[EJS_SLAB_PROPERTY];
+ slab->allocIncrement = propInc;
+ slab->size = EJS_ALLOC_ALIGN(sizeof(EjsProperty));
+
+ slab = &ep->slabs[EJS_SLAB_VAR];
+ slab->allocIncrement = varInc;
+ slab->size = EJS_ALLOC_ALIGN(sizeof(EjsVar));
+
+ /*
+ * Initialize GC.
+ * Enable GC both idle and demand collections.
+ * Set no limits and garbage collect if the slabs are
+ * empty and we have used more than the THRESHOLD of ram.
+ */
+ ep->gc.debugLevel = 0;
+ ep->gc.enable = 1;
+ ep->gc.enableIdleCollect = 1;
+ ep->gc.enableDemandCollect = 1;
+ ep->gc.workQuota = EJS_GC_WORK_QUOTA;
+ ep->gc.maxMemory = 0;
+}
+
+
+/******************************************************************************/
+#if BLD_FEATURE_ALLOC_STATS
+
+void ejsPrintAllocReport(Ejs *ep, bool printLeakReport)
+{
+ EjsSlab *slab;
+ char *name;
+ int slabIndex, isObj;
+
+ for (slabIndex = 0; slabIndex < EJS_SLAB_MAX; slabIndex++) {
+ slab = &ep->slabs[slabIndex];
+ if (slabIndex == EJS_SLAB_VAR) {
+ name = "var";
+ } else if (slabIndex == EJS_SLAB_PROPERTY) {
+ name = "prop";
+ } else {
+ name = "obj";
+ }
+ mprLog(ep, 0, " ");
+ mprLog(ep, 0, " GC \"%s\" local slab", name);
+ mprLog(ep, 0, " Total blocks %14d",
+ slab->allocCount + slab->freeCount);
+ mprLog(ep, 0, " Block size %14d", slab->size);
+ mprLog(ep, 0, " Slab RAM allocated %14d",
+ (slab->allocCount + slab->freeCount) * slab->size);
+ mprLog(ep, 0, " Slab RAM in use %14d",
+ slab->allocCount * slab->size);
+ mprLog(ep, 0, " Blocks in use %14d", slab->allocCount);
+ mprLog(ep, 0, " Free blocks %14d", slab->freeCount);
+ mprLog(ep, 0, " Peak allocated %14d", slab->peakAllocated);
+ mprLog(ep, 0, " Peak free %14d", slab->peakFree);
+ mprLog(ep, 0, " Total allocations %14d", slab->totalAlloc);
+ mprLog(ep, 0, " Total blocks reclaimed %14d", slab->totalReclaimed);
+ mprLog(ep, 0, " Total sweeps %14d", slab->totalSweeps);
+ mprLog(ep, 0, " Allocation inc %14d", slab->allocIncrement);
+ }
+
+ mprLog(ep, 0, " ");
+ mprLog(ep, 0, " Total EJS memory in use %10d", ejsGetUsedMemory(ep));
+ mprLog(ep, 0, " Total EJS memory allocated %10d",
+ ejsGetAllocatedMemory(ep));
+
+ if (printLeakReport) {
+ mprLog(ep, 0, " ");
+ for (slabIndex = 0; slabIndex < EJS_SLAB_MAX; slabIndex++) {
+ int size;
+
+ slab = &ep->slabs[slabIndex];
+
+ isObj = 0;
+ mprLog(ep, 0, " ");
+ if (slabIndex == EJS_SLAB_VAR) {
+ name = "var";
+ size = sizeof(EjsVar);
+ } else if (slabIndex == EJS_SLAB_PROPERTY) {
+ name = "prop";
+ size = sizeof(EjsProperty);
+ } else {
+ name = "obj";
+ size = sizeof(EjsObj);
+ isObj++;
+ }
+#if BLD_FEATURE_ALLOC_LEAK_TRACK
+{
+ EjsGCLink *lp;
+ EjsObj *obj;
+ int count;
+
+ mprLog(ep, 0, "EJS Leak Report for \"%s\"", name);
+ count = 0;
+
+ for (lp = slab->allocList[0].next; lp; lp = lp->next) {
+ mprLog(ep, 0, " %-20s %10d", lp->allocatedBy, size);
+ if (isObj) {
+ obj = (EjsObj*) lp;
+ mprLog(ep, 0, " %-20s %10d %s %s",
+ lp->allocatedBy, size,
+ obj->permanent ? "permanent" : "",
+ obj->alive ? "alive" : ""
+ );
+ } else {
+ mprLog(ep, 0, " %-20s %10d", lp->allocatedBy,
+ size);
+ }
+ count++;
+ }
+ mprLog(ep, 0, " Total blocks %14d", count);
+}
+#endif
+ }
+ mprLog(ep, 0, " ");
+ }
+}
+
+#endif
+/******************************************************************************/
+/*
+ * Slab allocator
+ */
+
+static EjsGCLink *ejsAlloc(EJS_LOC_DEC(ep, loc), int slabIndex)
+{
+ EjsSlab *slab;
+ EjsGCLink *block;
+ EjsGC *gc;
+ uint allocatedMemory;
+ int i;
+
+ mprStackCheck(ep);
+
+ if (slabIndex < 0 || slabIndex >= EJS_SLAB_MAX) {
+ mprAssert(0);
+ return 0;
+ }
+
+ /*
+ * See if the slab has some free blocks
+ */
+ slab = &ep->slabs[slabIndex];
+ if ((block = slab->freeList.next) == 0) {
+
+ allocatedMemory = ejsGetAllocatedMemory(ep);
+ gc = &ep->gc;
+
+ /*
+ * No blocks available. If demand collection is enabled, try
+ * to garbage collect first. We collect if we have done a good
+ * work quota or we are over the max memory limit.
+ */
+ if (slabIndex != EJS_SLAB_VAR &&
+ ep->gc.enable && ep->gc.enableDemandCollect) {
+ if ((ep->gc.workDone > ep->gc.workQuota) ||
+ (gc->maxMemory > 0 && allocatedMemory > gc->maxMemory)) {
+
+#if DEBUG_USE_ONLY
+ if (ep->gc.debugLevel > 0) {
+ mprLog(ep, 0, "Need GC, EJS RAM %d, MPR RAM %d\n",
+ allocatedMemory, mprGetAllocatedMemory(ep));
+ if (ep->gc.debugLevel > 4) {
+ ejsPrintAllocReport(ep, 0);
+ }
+ }
+#endif
+ if (ejsCollectGarbage(ep, slabIndex) == 0) {
+ block = slab->freeList.next;
+ }
+ }
+ }
+
+ if (block == 0) {
+ if (gc->maxMemory > 0 && allocatedMemory > gc->maxMemory) {
+ /*
+ * We are above the max memory limit. We will fail this
+ * memory allocation, but allow subsequent allocations to
+ * permit error recovery. We gracefully degrade by setting
+ * slab chunk sizes to 1. This minimizes real memory
+ * consumption. This allows us to create
+ * an exception block to be created by upper layers.
+ */
+ if (! gc->degraded) {
+ ejsGracefulDegrade(ep);
+ return 0;
+ }
+ }
+
+ /*
+ * Still non available, so allocate more memory for a set of blocks
+ * OPT -- should bypass mprAlloc. Need mprMalloc.
+ */
+ block = mprAlloc(ep->slabAllocContext,
+ slab->size * slab->allocIncrement);
+ if (block == 0) {
+ /*
+ * Now we're in trouble. We should really never get here
+ * as the graceful degrade will have signaled a memory
+ * allocation failure.
+ */
+ mprAssert(block != 0);
+ return 0;
+ }
+
+ /*
+ * Chain all the blocks together onto the slab free list
+ */
+ for (i = slab->allocIncrement - 1; i >= 0; i--) {
+ block->next = slab->freeList.next;
+#if BLD_DEBUG
+ block->magic = EJS_MAGIC_FREE;
+#endif
+ slab->freeList.next = block;
+ block = (EjsGCLink*) ((char*) block + slab->size);
+ }
+
+ block = slab->freeList.next;
+
+#if BLD_FEATURE_ALLOC_STATS
+ slab->freeCount += slab->allocIncrement;
+ if (slab->freeCount > slab->peakFree) {
+ slab->peakFree = slab->freeCount;
+ }
+#endif
+ }
+ }
+
+ /*
+ * We use block to point to the user data in the block. We only
+ * store the magic number (if debug). No other data is stored in the
+ * user block.
+ */
+#if BLD_DEBUG
+ mprAssert(block->magic == EJS_MAGIC_FREE);
+#endif
+
+ /*
+ * Remove from the free list
+ */
+ slab->freeList.next = block->next;
+
+ /*
+ * Zero block
+ */
+ memset(block, 0, slab->size);
+
+#if BLD_DEBUG
+ block->magic = EJS_MAGIC;
+#endif
+
+#if BLD_FEATURE_ALLOC_STATS
+ slab->totalAlloc++;
+ if (++slab->allocCount > slab->peakAllocated) {
+ slab->peakAllocated = slab->allocCount;
+ }
+ slab->freeCount--;
+#endif
+
+#if BLD_DEBUG && (!BREW || BREW_SIMULATOR)
+ if ((uint) block == breakAddr) {
+ mprBreakpoint(MPR_LOC, "Watched Block");
+ }
+#endif
+ return block;
+}
+
+
+/******************************************************************************/
+
+EjsObj *ejsAllocObj(EJS_LOC_DEC(ep, loc))
+{
+ EjsObj *obj;
+ EjsSlab *slab;
+
+ obj = (EjsObj*) ejsAlloc(EJS_LOC_PASS(ep, loc), EJS_SLAB_OBJ);
+
+ /*
+ * Add to the allocated block list for the New generation.
+ */
+ if (obj) {
+ slab = &ep->slabs[EJS_SLAB_OBJ];
+ obj->gc.next = slab->allocList[EJS_GEN_NEW].next;
+
+#if BLD_FEATURE_ALLOC_LEAK_TRACK
+ obj->gc.allocatedBy = loc;
+#endif
+
+ obj->ejs = ep;
+ slab->allocList[EJS_GEN_NEW].next = (EjsGCLink*) obj;
+
+ ep->gc.workDone++;
+ }
+
+ return obj;
+}
+
+
+/******************************************************************************/
+
+EjsProperty *ejsAllocProperty(EJS_LOC_DEC(ep, loc))
+{
+ EjsProperty *prop;
+
+ prop = (EjsProperty*) ejsAlloc(EJS_LOC_PASS(ep, loc), EJS_SLAB_PROPERTY);
+ mprAssert(prop);
+
+ if (prop) {
+ prop->var.type = EJS_TYPE_NULL;
+ prop->var.isProperty = 1;
+#if BLD_FEATURE_ALLOC_LEAK_TRACK
+ prop->var.gc.allocatedBy = loc;
+#endif
+ }
+ return prop;
+}
+
+
+/******************************************************************************/
+
+EjsVar *ejsAllocVar(EJS_LOC_DEC(ep, loc))
+{
+ EjsVar *vp;
+
+ vp = (EjsVar*) ejsAlloc(EJS_LOC_PASS(ep, loc), EJS_SLAB_VAR);
+ mprAssert(vp);
+
+ if (vp) {
+#if BLD_FEATURE_ALLOC_LEAK_TRACK
+ EjsSlab *slab;
+ vp->gc.allocatedBy = loc;
+ slab = &ep->slabs[EJS_SLAB_VAR];
+ vp->gc.next = slab->allocList[EJS_GEN_NEW].next;
+ slab->allocList[EJS_GEN_NEW].next = (EjsGCLink*) vp;
+#endif
+#if BLD_DEBUG
+ vp->propertyName = 0;
+#endif
+ }
+ return vp;
+}
+
+
+/******************************************************************************/
+/*
+ * Return the block back to the relevant slab
+ */
+
+void ejsFree(Ejs *ep, void *ptr, int slabIndex)
+{
+ EjsSlab *slab;
+ EjsGCLink *block;
+
+ mprAssert(ep);
+ mprAssert(ptr);
+
+ if (slabIndex < 0 || slabIndex >= EJS_SLAB_MAX) {
+ mprAssert(slabIndex >= 0 && slabIndex < EJS_SLAB_MAX);
+ return;
+ }
+ slab = &ep->slabs[slabIndex];
+
+#if BLD_FEATURE_ALLOC_LEAK_TRACK
+ if (slabIndex == EJS_SLAB_VAR) {
+ EjsVar *vp, *np, *prev;
+
+ /*
+ * Remove the block rom the alloc list. WARNING: this is slow
+ * and should not be used in production code.
+ */
+ vp = (EjsVar*) ptr;
+ prev = 0;
+ for (np = (EjsVar*) slab->allocList[0].next; np;
+ np = (EjsVar*) np->gc.next) {
+ if (vp == np) {
+ if (prev) {
+ prev->gc.next = (EjsGCLink*) np->gc.next;
+ } else {
+ slab->allocList[0].next = (EjsGCLink*) np->gc.next;
+ }
+ break;
+ }
+ prev = np;
+ }
+ if (np == 0) {
+ mprAssert(0);
+ }
+ }
+#endif
+
+ /*
+ * Insert into the free list. Only use the next ptr
+ */
+ block = (EjsGCLink*) ptr;
+
+#if BLD_DEBUG
+#if !BREW || BREW_SIMULATOR
+ if ((uint) block == breakAddr) {
+ mprBreakpoint(MPR_LOC, "Watched Block");
+ }
+#endif
+ mprAssert(block->magic == EJS_MAGIC);
+ block->magic = EJS_MAGIC_FREE;
+#endif
+
+ block->next = slab->freeList.next;
+ slab->freeList.next = block;
+
+#if BLD_FEATURE_ALLOC_STATS
+ slab->allocCount--;
+ if (++slab->freeCount >= slab->peakFree) {
+ slab->peakFree = slab->freeCount;
+ }
+ slab->totalReclaimed++;
+ if (slabIndex != 2) {
+ slabIndex = slabIndex;
+ }
+#endif
+}
+
+/******************************************************************************/
+/*
+ * Mark an object as being in-use. Traverse all properties for referenced
+ * objects and base classes.
+ */
+
+static void markObjByVar(Ejs *ep, EjsVar *obj)
+{
+ EjsProperty *pp;
+ EjsVar *vp, *baseClass;
+
+ mprAssert(ep);
+ mprAssert(obj);
+
+ obj->objectState->gcMarked = 1;
+
+#if BLD_DEBUG
+ if (ep->gc.debugLevel >= 3) {
+ int indent = min(ep->gc.gcIndent * 2, 32);
+ mprLog(ep, 0, "%.*s %-24s %.*s 0x%08X",
+ indent, " ",
+ obj->propertyName,
+ 32 - indent, "................................ ",
+ (uint) obj->objectState);
+ ep->gc.gcIndent++;
+ }
+ ep->gc.objectsInUse++;
+#endif
+
+ /*
+ * Traverse all referenced objects
+ * OPT -- optimize by directly accessing the object links and not using
+ * ejsGetFirst/NextProperty. Then just examine objects
+ * OPT -- first property in global is global. Should optimize this.
+ */
+ pp = ejsGetFirstProperty(obj, EJS_ENUM_ALL);
+ while (pp) {
+ vp = ejsGetVarPtr(pp);
+ if (vp->type == EJS_TYPE_OBJECT) {
+ if (!vp->objectState->gcMarked) {
+#if FUTURE
+ /*
+ * OPT -- we can use the dirty bit on objects to avoid
+ * visiting permanent objects that are clean. If so, don't
+ * forget the else case below.
+ */
+ obj = vp->objectState;
+ if ((!obj->alive && !obj->permanent) || obj->dirty)
+#endif
+ markObjByVar(ep, vp);
+ }
+
+ } else {
+#if BLD_DEBUG
+ if (ep->gc.debugLevel >= 3) {
+ int indent = min(ep->gc.gcIndent * 2, 32);
+ mprLog(ep, 0, "%.*s %-24s %.*s %s",
+ indent, " ",
+ vp->propertyName,
+ 32 - indent, "................................ ",
+ ejsGetVarTypeAsString(vp));
+ }
+ ep->gc.propertiesInUse++;
+#endif
+ }
+ pp = ejsGetNextProperty(pp, EJS_ENUM_ALL);
+ }
+
+ /*
+ * Traverse the base class
+ */
+ baseClass = obj->objectState->baseClass;
+ if (baseClass) {
+ mprAssert(baseClass->type == EJS_TYPE_OBJECT);
+ mprAssert(baseClass->objectState);
+ if (baseClass->objectState) {
+ if (! baseClass->objectState->gcMarked) {
+ markObjByVar(ep, baseClass);
+ }
+ }
+ }
+#if BLD_DEBUG
+ if (ep->gc.debugLevel >= 3) {
+ ep->gc.gcIndent--;
+ }
+#endif
+}
+
+
+/******************************************************************************/
+/*
+ * Mark phase. Examine all variable frames and the return result.
+ */
+
+static void mark(Ejs *ep)
+{
+ EjsVar *vp;
+ int i;
+
+#if BLD_DEBUG
+ if (ep->gc.debugLevel >= 3) {
+ mprLog(ep, 0, " ");
+ mprLog(ep, 0, "GC: Marked Blocks:");
+ }
+#endif
+
+ if (ep->frames) {
+ for (i = 0; i < mprGetItemCount(ep->frames); i++) {
+
+ vp = (EjsVar*) mprGetItem(ep->frames, i);
+ mprAssert(vp->type == EJS_TYPE_OBJECT);
+
+ if (! vp->objectState->gcMarked) {
+ markObjByVar(ep, vp);
+ }
+ }
+ }
+
+ vp = ep->result;
+ if (vp && vp->type == EJS_TYPE_OBJECT && ! vp->objectState->gcMarked) {
+ markObjByVar(ep, vp);
+ }
+
+ vp = ep->currentObj;
+ if (vp && vp->type == EJS_TYPE_OBJECT && ! vp->objectState->gcMarked) {
+ markObjByVar(ep, vp);
+ }
+
+ vp = ejsGetVarPtr(ep->currentProperty);
+ if (vp && vp->type == EJS_TYPE_OBJECT && ! vp->objectState->gcMarked) {
+ markObjByVar(ep, vp);
+ }
+
+ /*
+ * OPT -- we could mark master as "mark permanent" somehow and
+ * then we would not need to walk the master objects.
+ */
+ if (ep->slabAllocContext == ep->service->master) {
+ if (ep->service->master->global) {
+ markObjByVar(ep, ep->service->master->global);
+ }
+ }
+
+#if BLD_DEBUG
+ if (ep->gc.debugLevel >= 3) {
+ mprLog(ep, 0, " ");
+ }
+#endif
+}
+
+
+/******************************************************************************/
+#if UNUSED
+
+static void resetMark(EjsVar *obj)
+{
+ EjsProperty *pp;
+ EjsVar *vp, *baseClass;
+
+ obj->objectState->gcMarked = 0;
+ obj->objectState->visited = 1;
+
+ pp = ejsGetFirstProperty(obj, EJS_ENUM_ALL);
+ while (pp) {
+ vp = ejsGetVarPtr(pp);
+ if (vp->type == EJS_TYPE_OBJECT && !vp->objectState->visited) {
+ resetMark(vp);
+ }
+ pp = ejsGetNextProperty(pp, EJS_ENUM_ALL);
+ }
+
+ baseClass = obj->objectState->baseClass;
+ if (baseClass) {
+ mprAssert(baseClass->type == EJS_TYPE_OBJECT);
+ mprAssert(baseClass->objectState);
+ if (baseClass->objectState) {
+ if (! baseClass->objectState->visited) {
+ resetMark(baseClass);
+ }
+ }
+ }
+ obj->objectState->visited = 0;
+}
+
+/******************************************************************************/
+/*
+ * Mark phase. Examine all variable frames and the return result.
+ */
+
+static void resetAllMarks(Ejs *ep)
+{
+ EjsVar *vp;
+ int i;
+
+ for (i = 0; i < mprGetItemCount(ep->frames); i++) {
+ vp = (EjsVar*) mprGetItem(ep->frames, i);
+ resetMark(vp);
+ }
+
+ if (ep->result && ep->result->type == EJS_TYPE_OBJECT &&
+ ! ep->result->objectState->gcMarked) {
+ resetMark(ep->result);
+ }
+}
+
+#endif
+/******************************************************************************/
+/*
+ * Sweep up the garbage
+ */
+
+static void resetMarks(Ejs *ep, EjsSlab *slab)
+{
+ EjsVar *vp;
+ EjsObj *obj;
+ int gen, i;
+
+ for (gen = EJS_GEN_NEW; gen < EJS_GEN_MAX; gen++) {
+ obj = (EjsObj*) slab->allocList[gen].next;
+ for (; obj; obj = (EjsObj*) obj->gc.next) {
+ obj->gcMarked = 0;
+ obj->visited = 0;
+ }
+ }
+
+ if (ep->frames) {
+ for (i = 0; i < mprGetItemCount(ep->frames); i++) {
+
+ vp = (EjsVar*) mprGetItem(ep->frames, i);
+ mprAssert(vp->type == EJS_TYPE_OBJECT);
+
+ vp->objectState->gcMarked = 0;
+ vp->objectState->visited = 0;
+ }
+ }
+
+ if (ep->result && ep->result->type == EJS_TYPE_OBJECT) {
+ ep->result->objectState->gcMarked = 0;
+ }
+}
+
+/******************************************************************************/
+/*
+ * Mark all permanent and non-alive objects
+ */
+
+static void markPerm(Ejs *ep, uint gen)
+{
+ EjsSlab *slab;
+ EjsObj *obj;
+
+ slab = &ep->slabs[EJS_SLAB_OBJ];
+
+ for (obj = (EjsObj*) slab->allocList[gen].next; obj; ) {
+
+ if (! obj->gcMarked) {
+ if (!obj->alive || obj->permanent) {
+ markObj(obj);
+ }
+ }
+ obj = (EjsObj*) obj->gc.next;
+
+ }
+}
+
+/******************************************************************************/
+
+static void markObj(EjsObj *obj)
+{
+ EjsProperty *pp;
+ EjsPropLink *lp, *head;
+ EjsObj *op;
+
+ mprAssert(obj);
+
+ obj->gcMarked = 1;
+
+ head = &obj->link;
+ for (lp = head->next; lp != head; lp = lp->next) {
+
+ pp = ejsGetPropertyFromLink(lp);
+
+ if (pp->var.type == EJS_TYPE_OBJECT) {
+ op = pp->var.objectState;
+ if (op != 0 && !op->gcMarked) {
+ markObj(op);
+ }
+ }
+ }
+}
+
+/******************************************************************************/
+/*
+ * Sweep up the garbage. Return the number of objects freed.
+ */
+
+static int sweep(Ejs *ep, uint gen)
+{
+ EjsSlab *slab;
+ EjsObj *obj, *next, *prev;
+ int count;
+
+ slab = &ep->slabs[EJS_SLAB_OBJ];
+
+ /*
+ * Examine allocated objects in the specified generation (only).
+ * NOTE: we only sweep object allocated to this interpreter and so
+ * we do not sweep any permanent objects in the default interpreter.
+ */
+ prev = 0;
+ count = 0;
+ for (obj = (EjsObj*) slab->allocList[gen].next; obj; obj = next) {
+
+ next = (EjsObj*) obj->gc.next;
+
+#if BLD_DEBUG && (!BREW || BREW_SIMULATOR)
+ if ((uint) obj == breakAddr) {
+ mprBreakpoint(MPR_LOC, "Watched Block");
+ }
+#endif
+
+ /*
+ * If object has not been marked inuse and is not a permanent
+ * object, then free it.
+ */
+ if (! obj->gcMarked && obj->alive && !obj->permanent) {
+
+#if BLD_DEBUG
+ if (ep->gc.debugLevel >= 2) {
+ if (obj->objName) {
+ mprLog(ep, 0, "GC: destroy %-18s %10d, %8X",
+ obj->objName, (uint) obj, (uint) obj);
+ } else {
+ mprLog(ep, 0, "GC: destroy UNKNOWN %x", (uint) obj);
+ }
+ }
+#endif
+ if (ejsDestroyObj(ep, obj) < 0) {
+ prev = obj;
+ obj->gcMarked = 0;
+ continue;
+ }
+
+ if (prev) {
+ prev->gc.next = (EjsGCLink*) next;
+ } else {
+ slab->allocList[gen].next = (EjsGCLink*) next;
+ }
+ count++;
+
+ } else {
+ prev = obj;
+ /* Reset for next time */
+ obj->gcMarked = 0;
+ }
+ }
+
+ if (gen == (EJS_GEN_OLD - 1)) {
+ slab->lastRecentBlock = prev;
+ }
+#if BLD_FEATURE_ALLOC_STATS
+ slab->totalSweeps++;
+#endif
+#if BLD_DEBUG
+ if (ep->gc.debugLevel > 0) {
+ mprLog(ep, 0, "GC: Sweep freed %d objects", count);
+ }
+#endif
+ return count;
+}
+
+/******************************************************************************/
+/*
+ * Sweep all variables
+ */
+
+void ejsSweepAll(Ejs *ep)
+{
+ EjsSlab *slab;
+ EjsObj *obj, *next, *prev;
+ int gen;
+
+ slab = &ep->slabs[EJS_SLAB_OBJ];
+
+ for (gen = EJS_GEN_NEW; gen < EJS_GEN_MAX; gen++) {
+ prev = 0;
+ for (obj = (EjsObj*) slab->allocList[gen].next; obj; obj = next) {
+ next = (EjsObj*) obj->gc.next;
+ ejsDestroyObj(ep, obj);
+ }
+ break;
+ }
+}
+
+/******************************************************************************/
+
+bool ejsObjIsCollectable(EjsVar *vp)
+{
+ if (vp == 0 || !ejsVarIsObject(vp)) {
+ return 0;
+ }
+ return (vp->objectState->alive && !vp->objectState->permanent);
+}
+
+/******************************************************************************/
+#if FUTURE
+
+static void ageGenerations(Ejs *ep)
+{
+ EjsSlab *slab;
+ EjsGCLink *oldList;
+ int gen;
+
+ slab = &ep->slabs[EJS_SLAB_OBJ];
+
+ /*
+ * Age all blocks. First append all (old - 1) blocks onto the old
+ * alloc list
+ */
+ oldList = &slab->allocList[EJS_GEN_OLD];
+
+ if (slab->lastRecentBlock) {
+ slab->lastRecentBlock->gc.next = oldList->next;
+ oldList->next = (EjsGCLink*) slab->lastRecentBlock;
+ }
+
+ /*
+ * Now simply copy all allocation lists up one generation
+ */
+ for (gen = EJS_GEN_OLD - 1; gen > 0; gen--) {
+ slab->allocList[gen] = slab->allocList[gen - 1];
+ }
+ slab->allocList[0].next = 0;
+}
+
+#endif
+/******************************************************************************/
+/*
+ * Collect the garbage. This is a mark and sweep over all possible objects.
+ * If an object is not referenced, it and all contained properties will be
+ * freed. If a slabIndex is provided, the collection halts when a block is
+ * available for allocation on that slab.
+ *
+ * Return 0 if memory is now available after collecting garbage. Otherwise,
+ * return MPR_ERR_MEMORY.
+ */
+
+int ejsCollectGarbage(Ejs *ep, int slabIndex)
+{
+ EjsGeneration gen;
+
+ if (ep->flags & EJS_FLAGS_DONT_GC) {
+ return -1;
+ }
+
+ /*
+ * Prevent destructors invoking the garbage collector
+ */
+ if (ep->gc.collecting) {
+ return 0;
+ }
+ ep->gc.collecting = 1;
+
+ resetMarks(ep, &ep->slabs[EJS_SLAB_OBJ]);
+
+ /*
+ * Examine each generation of objects starting with the most recent
+ * generation. Stop scanning when we have a free block to use.
+ */
+ for (gen = EJS_GEN_NEW; gen < EJS_GEN_MAX; gen++) {
+
+ if (slabIndex >= 0 && ep->slabs[slabIndex].freeList.next) {
+ break;
+ }
+
+ /*
+ * FUTURE OPT. Should mark objects in new generation and those
+ * with a dirty bit set in older generations. Don't need to mark
+ * entire heap. But how to keep list of dirty objects.
+ */
+ mark(ep);
+ markPerm(ep, gen);
+ sweep(ep, gen);
+
+ /* FUTURE - not using generations yet */
+ break;
+ }
+
+ /*
+ * FUTURE -- not using generations yet.
+ *
+ * ageGenerations(ep);
+ */
+
+ ep->gc.workDone = 0;
+ ep->gc.collecting = 0;
+
+ return (gen < EJS_GEN_MAX) ? 0 : MPR_ERR_MEMORY;
+}
+
+
+/******************************************************************************/
+/*
+ * Should be called when the app has been idle for a little while and when it
+ * is likely to be idle a bit longer. Call ejsIsTimeForGC to see if this is
+ * true. Return the count of objects collected .
+ */
+
+int ejsIncrementalCollectGarbage(Ejs *ep)
+{
+ int count;
+
+ if (ep->gc.collecting) {
+ return 0;
+ }
+
+ ep->gc.collecting = 1;
+
+ resetMarks(ep, &ep->slabs[EJS_SLAB_OBJ]);
+ mark(ep);
+
+ /* Not generational yet */
+ count = sweep(ep, EJS_GEN_NEW);
+
+ ep->gc.collecting = 0;
+ ep->gc.workDone = 0;
+
+ return count;
+}
+
+/******************************************************************************/
+#if BLD_DEBUG
+
+void ejsDumpObjects(Ejs *ep)
+{
+ int oldDebugLevel;
+
+ mprLog(ep, 0, "Dump of objects in use\n");
+
+ oldDebugLevel = ep->gc.debugLevel;
+
+ ep->gc.debugLevel = 3;
+ ep->gc.objectsInUse = 0;
+ ep->gc.propertiesInUse = 0;
+ ep->gc.collecting = 1;
+
+ resetMarks(ep, &ep->slabs[EJS_SLAB_OBJ]);
+ mark(ep);
+
+ ep->gc.collecting = 0;
+ ep->gc.debugLevel = oldDebugLevel;
+
+ mprLog(ep, 0, "%d objects and %d properties in use",
+ ep->gc.objectsInUse, ep->gc.propertiesInUse);
+ mprLog(ep, 0, "%d object bytes, %d property bytes and %d total",
+ (int) (ep->gc.objectsInUse * sizeof(EjsObj)),
+ (int) (ep->gc.propertiesInUse * sizeof(EjsProperty)),
+ (int) ((ep->gc.objectsInUse * sizeof(EjsObj) +
+ ep->gc.propertiesInUse * sizeof(EjsProperty))));
+}
+
+#endif
+/******************************************************************************/
+/*
+ * Return true if there is time to do a garbage collection and if we will
+ * benefit from it.
+ */
+
+int ejsIsTimeForGC(Ejs *ep, int timeTillNextEvent)
+{
+ EjsGC *gc;
+
+ if (timeTillNextEvent < EJS_MIN_TIME_FOR_GC) {
+ /*
+ * Not enough time to complete a collection
+ */
+ return 0;
+ }
+
+ gc = &ep->gc;
+
+ /*
+ * Return if we haven't done enough work to warrant a collection
+ * Trigger a little short of the work quota to try to run GC before
+ * a demand allocation requires it.
+ */
+ if (!gc->enable || !gc->enableIdleCollect ||
+ (gc->workDone < (gc->workQuota - EJS_GC_MIN_WORK_QUOTA))) {
+ return 0;
+ }
+
+#if UNUSED
+ mprLog(ep, 0, "Time for GC. Work done %d, time till next event %d",
+ gc->workDone, timeTillNextEvent);
+#endif
+ return 1;
+}
+
+/******************************************************************************/
+/*
+ * Return the amount of memory in use by EJS
+ */
+
+uint ejsGetUsedMemory(Ejs *ep)
+{
+#if BLD_FEATURE_ALLOC_STATS
+ EjsSlab *slab;
+ int i, totalMemory, slabMemory;
+
+ totalMemory = 0;
+ for (i = 0; i < EJS_SLAB_MAX; i++) {
+ slab = &ep->slabs[i];
+ slabMemory = slab->allocCount * slab->size;
+ totalMemory += slabMemory;
+ }
+ return totalMemory;
+#else
+ return 0;
+#endif
+}
+
+/******************************************************************************/
+/*
+ * Return the amount of memory allocated by EJS
+ */
+
+uint ejsGetAllocatedMemory(Ejs *ep)
+{
+#if BLD_FEATURE_ALLOC_STATS
+ EjsSlab *slab;
+ int i, totalMemory, slabMemory;
+
+ totalMemory = 0;
+ for (i = 0; i < EJS_SLAB_MAX; i++) {
+ slab = &ep->slabs[i];
+ slabMemory = (slab->allocCount + slab->freeCount) * slab->size;
+ totalMemory += slabMemory;
+ }
+ return totalMemory;
+#else
+ return 0;
+#endif
+}
+
+/******************************************************************************/
+/*
+ * On a memory allocation failure, go into graceful degrade mode. Set all
+ * slab allocation chunk increments to 1 so we can create an exception block
+ * to throw.
+ */
+
+static void ejsGracefulDegrade(Ejs *ep)
+{
+ EjsSlab *slab;
+ int i;
+
+ mprLog(ep, 1, "WARNING: Memory almost depleted. In graceful degrade mode");
+ for (i = 0; i < EJS_SLAB_MAX; i++) {
+ slab = &ep->slabs[i];
+ slab->allocIncrement = 8;
+ }
+ ep->gc.degraded = 1;
+}
+
+/******************************************************************************/
+
+int ejsSetGCDebugLevel(Ejs *ep, int debugLevel)
+{
+ int old;
+
+ old = ep->gc.debugLevel;
+ ep->gc.debugLevel = debugLevel;
+ return old;
+}
+
+/******************************************************************************/
+
+int ejsSetGCMaxMemory(Ejs *ep, uint maxMemory)
+{
+ int old;
+
+ old = ep->gc.maxMemory;
+ ep->gc.maxMemory = maxMemory;
+
+ return old;
+}
+
+/******************************************************************************/
+
+bool ejsBlockInUseInt(EjsVar *vp)
+{
+ if (vp) {
+#if BLD_DEBUG
+ if (vp->gc.magic != EJS_MAGIC) {
+ return 0;
+ }
+ if (vp->type == EJS_TYPE_OBJECT && vp->objectState &&
+ vp->objectState->gc.magic != EJS_MAGIC) {
+ return 0;
+ }
+#endif
+ return 1;
+ }
+ return 1;
+}
+
+/******************************************************************************/
+#else
+void ejsGarbageDummy() {}
+
+#endif /* BLD_FEATURE_EJS */
+
+/******************************************************************************/
+/*
+ * 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-2.0/ejs/ejsLex.c b/source4/lib/appweb/ejs-2.0/ejs/ejsLex.c
new file mode 100644
index 0000000000..fbfee6e4d5
--- /dev/null
+++ b/source4/lib/appweb/ejs-2.0/ejs/ejsLex.c
@@ -0,0 +1,1033 @@
+/*
+ * @file ejsLex.c
+ * @brief EJS Lexical Analyser
+ * @overview EJS lexical analyser. This implementes a lexical analyser
+ * for a subset of the JavaScript language.
+ */
+/********************************* Copyright **********************************/
+/*
+ * @copy default.g
+ *
+ * Copyright (c) Mbedthis Software LLC, 2003-2006. All Rights Reserved.
+ * Portions Copyright (c) GoAhead Software, 1995-2000. 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
+ */
+/********************************** Includes **********************************/
+
+#include "ejs.h"
+
+#if BLD_FEATURE_EJS
+
+/****************************** Forward Declarations **************************/
+
+static int getLexicalToken(Ejs *ep, int state);
+static int tokenAddChar(Ejs *ep, int c);
+static int inputGetc(Ejs *ep);
+static void inputPutback(Ejs *ep, int c);
+static int charConvert(Ejs *ep, int base, int maxDig);
+static void parseNumber(Ejs *ep, EjsType type);
+
+/************************************* Code ***********************************/
+/*
+ * Open a new input script
+ */
+
+int ejsLexOpenScript(Ejs *ep, const char *script)
+{
+ EjsInput *ip;
+
+ mprAssert(ep);
+ mprAssert(script);
+
+ if ((ip = mprAllocTypeZeroed(ep, EjsInput)) == NULL) {
+ return MPR_ERR_MEMORY;
+ }
+ ip->next = ep->input;
+ ep->input = ip;
+ ip->procName = ep->proc ? ep->proc->procName : NULL;
+ ip->fileName = ep->fileName ? ep->fileName : NULL;
+
+/*
+ * Create the parse token buffer and script buffer
+ */
+ ip->tokServp = ip->tokbuf;
+ ip->tokEndp = ip->tokbuf;
+
+ ip->script = script;
+ ip->scriptSize = strlen(script);
+ ip->scriptServp = (char*) ip->script;
+
+ ip->lineNumber = 1;
+ ip->lineColumn = 0;
+
+ ip->putBackIndex = -1;
+
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * Close the input script
+ */
+
+void ejsLexCloseScript(Ejs *ep)
+{
+ EjsInput *ip;
+
+ mprAssert(ep);
+
+ ip = ep->input;
+ mprAssert(ip);
+ ep->input = ip->next;
+
+ mprFree(ip);
+}
+
+/******************************************************************************/
+/*
+ * Initialize an input state structure
+ */
+
+int ejsInitInputState(EjsInput *ip)
+{
+ mprAssert(ip);
+
+ memset(ip, 0, sizeof(*ip));
+ ip->putBackIndex = -1;
+
+ return 0;
+}
+/******************************************************************************/
+/*
+ * Save the input state
+ */
+
+void ejsLexSaveInputState(Ejs *ep, EjsInput *state)
+{
+ EjsInput *ip;
+ int i;
+
+ mprAssert(ep);
+
+ ip = ep->input;
+ mprAssert(ip);
+
+ *state = *ip;
+
+ for (i = 0; i <= ip->putBackIndex; i++) {
+ mprStrcpy(state->putBack[i].tokbuf, EJS_MAX_TOKEN,
+ ip->putBack[i].tokbuf);
+ state->putBack[i].tid = ip->putBack[i].tid;
+ }
+
+ mprStrcpy(state->line, sizeof(state->line), ip->line);
+
+ state->lineColumn = ip->lineColumn;
+ state->lineNumber = ip->lineNumber;
+}
+
+/******************************************************************************/
+/*
+ * Restore the input state
+ */
+
+void ejsLexRestoreInputState(Ejs *ep, EjsInput *state)
+{
+ EjsInput *ip;
+ EjsToken *tp;
+ int i;
+
+ mprAssert(ep);
+ mprAssert(state);
+
+ ip = ep->input;
+ mprAssert(ip);
+
+ mprStrcpy(ip->tokbuf, sizeof(ip->tokbuf), state->tokbuf);
+ ip->tokServp = state->tokServp;
+ ip->tokEndp = state->tokEndp;
+
+ ip->script = state->script;
+ ip->scriptServp = state->scriptServp;
+ ip->scriptSize = state->scriptSize;
+
+ ip->putBackIndex = state->putBackIndex;
+ for (i = 0; i <= ip->putBackIndex; i++) {
+ tp = &ip->putBack[i];
+ tp->tid = state->putBack[i].tid;
+ mprStrcpy(tp->tokbuf, sizeof(tp->tokbuf), state->putBack[i].tokbuf);
+ }
+
+ mprStrcpy(ip->line, sizeof(ip->line), state->line);
+
+ ip->lineColumn = state->lineColumn;
+ ip->lineNumber = state->lineNumber;
+}
+
+/******************************************************************************/
+/*
+ * Free a saved input state
+ */
+
+void ejsLexFreeInputState(Ejs *ep, EjsInput *state)
+{
+ mprAssert(ep);
+ mprAssert(state);
+
+ state->putBackIndex = -1;
+ state->lineColumn = 0;
+}
+
+/******************************************************************************/
+/*
+ * Get the next EJS token
+ */
+
+int ejsLexGetToken(Ejs *ep, int state)
+{
+ mprAssert(ep);
+
+ ep->tid = getLexicalToken(ep, state);
+ return ep->tid;
+}
+
+/******************************************************************************/
+
+/*
+ * Check for reserved words "if", "else", "var", "for", "delete", "function",
+ * "class", "extends", "public", "private", "protected", "try", "catch",
+ * "finally", "throw", "return", "get", "set", "this", "module", "each"
+ *
+ * The "new" and "in" reserved words are handled below. The "true", "false",
+ * "null" "typeof" and "undefined" reserved words are handled as global
+ * objects.
+ *
+ * Other reserved words not supported:
+ * "break", "case", "continue", "default", "do",
+ * "instanceof", "switch", "while", "with"
+ *
+ * ECMA extensions reserved words (not supported):
+ * "abstract", "boolean", "byte", "char", "const",
+ * "debugger", "double", "enum", "export",
+ * "final", "float", "goto", "implements", "import", "int",
+ * "interface", "long", "native", "package",
+ * "short", "static", "super", "synchronized", "transient", "volatile"
+ *
+ * FUTURE -- use a hash lookup
+ */
+
+static int checkReservedWord(Ejs *ep, int state, int c, int tid)
+{
+ /* FUTURE -- probably should return for all tokens != EJS_TOK_ID */
+ /* FUTURE -- Should have a hash for this. MUCH faster. */
+
+ if (!isalpha(ep->token[0]) || tid == EJS_TOK_LITERAL) {
+ return tid;
+ }
+ if (state == EJS_STATE_STMT) {
+ /* FUTURE OPT -- convert to hash lookup */
+ if (strcmp(ep->token, "if") == 0) {
+ inputPutback(ep, c);
+ return EJS_TOK_IF;
+ } else if (strcmp(ep->token, "else") == 0) {
+ inputPutback(ep, c);
+ return EJS_TOK_ELSE;
+ } else if (strcmp(ep->token, "var") == 0) {
+ inputPutback(ep, c);
+ return EJS_TOK_VAR;
+ } else if (strcmp(ep->token, "new") == 0) {
+ inputPutback(ep, c);
+ return EJS_TOK_NEW;
+ } else if (strcmp(ep->token, "for") == 0) {
+ inputPutback(ep, c);
+ return EJS_TOK_FOR;
+ } else if (strcmp(ep->token, "delete") == 0) {
+ inputPutback(ep, c);
+ return EJS_TOK_DELETE;
+ } else if (strcmp(ep->token, "function") == 0) {
+ inputPutback(ep, c);
+ return EJS_TOK_FUNCTION;
+ } else if (strcmp(ep->token, "class") == 0) {
+ inputPutback(ep, c);
+ return EJS_TOK_CLASS;
+ } else if (strcmp(ep->token, "module") == 0) {
+ inputPutback(ep, c);
+ return EJS_TOK_MODULE;
+ } else if (strcmp(ep->token, "extends") == 0) {
+ inputPutback(ep, c);
+ return EJS_TOK_EXTENDS;
+ } else if (strcmp(ep->token, "try") == 0) {
+ inputPutback(ep, c);
+ return EJS_TOK_TRY;
+ } else if (strcmp(ep->token, "catch") == 0) {
+ inputPutback(ep, c);
+ return EJS_TOK_CATCH;
+ } else if (strcmp(ep->token, "finally") == 0) {
+ inputPutback(ep, c);
+ return EJS_TOK_FINALLY;
+ } else if (strcmp(ep->token, "throw") == 0) {
+ inputPutback(ep, c);
+ return EJS_TOK_THROW;
+ } else if (strcmp(ep->token, "public") == 0) {
+ inputPutback(ep, c);
+ return EJS_TOK_PUBLIC;
+ } else if (strcmp(ep->token, "protected") == 0) {
+ inputPutback(ep, c);
+ return EJS_TOK_PROTECTED;
+ } else if (strcmp(ep->token, "private") == 0) {
+ inputPutback(ep, c);
+ return EJS_TOK_PRIVATE;
+ } else if (strcmp(ep->token, "get") == 0) {
+ inputPutback(ep, c);
+ return EJS_TOK_GET;
+ } else if (strcmp(ep->token, "set") == 0) {
+ inputPutback(ep, c);
+ return EJS_TOK_SET;
+ } else if (strcmp(ep->token, "extends") == 0) {
+ inputPutback(ep, c);
+ return EJS_TOK_EXTENDS;
+ } else if (strcmp(ep->token, "try") == 0) {
+ inputPutback(ep, c);
+ return EJS_TOK_TRY;
+ } else if (strcmp(ep->token, "catch") == 0) {
+ inputPutback(ep, c);
+ return EJS_TOK_CATCH;
+ } else if (strcmp(ep->token, "finally") == 0) {
+ inputPutback(ep, c);
+ return EJS_TOK_FINALLY;
+ } else if (strcmp(ep->token, "throw") == 0) {
+ inputPutback(ep, c);
+ return EJS_TOK_THROW;
+ } else if (strcmp(ep->token, "public") == 0) {
+ inputPutback(ep, c);
+ return EJS_TOK_PUBLIC;
+ } else if (strcmp(ep->token, "protected") == 0) {
+ inputPutback(ep, c);
+ return EJS_TOK_PROTECTED;
+ } else if (strcmp(ep->token, "private") == 0) {
+ inputPutback(ep, c);
+ return EJS_TOK_PRIVATE;
+ } else if (strcmp(ep->token, "get") == 0) {
+ inputPutback(ep, c);
+ return EJS_TOK_GET;
+ } else if (strcmp(ep->token, "set") == 0) {
+ inputPutback(ep, c);
+ return EJS_TOK_SET;
+ } else if (strcmp(ep->token, "each") == 0) {
+ inputPutback(ep, c);
+ return EJS_TOK_EACH;
+ } else if (strcmp(ep->token, "return") == 0) {
+ if ((c == ';') || (c == '(')) {
+ inputPutback(ep, c);
+ }
+ return EJS_TOK_RETURN;
+ }
+
+ } else if (state == EJS_STATE_EXPR) {
+ if (strcmp(ep->token, "new") == 0) {
+ inputPutback(ep, c);
+ return EJS_TOK_NEW;
+ } else if (strcmp(ep->token, "in") == 0) {
+ inputPutback(ep, c);
+ return EJS_TOK_IN;
+ } else if (strcmp(ep->token, "function") == 0) {
+ inputPutback(ep, c);
+ return EJS_TOK_FUNCTION;
+ }
+
+ } else if (state == EJS_STATE_DEC) {
+ if (strcmp(ep->token, "extends") == 0) {
+ inputPutback(ep, c);
+ return EJS_TOK_EXTENDS;
+ }
+ }
+ return tid;
+}
+
+/******************************************************************************/
+/*
+ * Get the next EJS token
+ */
+
+static int getLexicalToken(Ejs *ep, int state)
+{
+ EjsType type;
+ EjsInput *ip;
+ int done, tid, c, quote, style, idx, isHex;
+
+ mprAssert(ep);
+ ip = ep->input;
+ mprAssert(ip);
+
+ ep->tid = -1;
+ tid = -1;
+ type = BLD_FEATURE_NUM_TYPE_ID;
+ isHex = 0;
+
+ /*
+ * Use a putback tokens first. Don't free strings as caller needs access.
+ */
+ if (ip->putBackIndex >= 0) {
+ idx = ip->putBackIndex;
+ tid = ip->putBack[idx].tid;
+ ep->token = (char*) ip->putBack[idx].tokbuf;
+ tid = checkReservedWord(ep, state, 0, tid);
+ ip->putBackIndex--;
+ return tid;
+ }
+ ep->token = ip->tokServp = ip->tokEndp = ip->tokbuf;
+ *ip->tokServp = '\0';
+
+ if ((c = inputGetc(ep)) < 0) {
+ return EJS_TOK_EOF;
+ }
+
+ /*
+ * Main lexical analyser
+ */
+ for (done = 0; !done; ) {
+ switch (c) {
+ case -1:
+ return EJS_TOK_EOF;
+
+ case ' ':
+ case '\t':
+ case '\r':
+ do {
+ if ((c = inputGetc(ep)) < 0)
+ break;
+ } while (c == ' ' || c == '\t' || c == '\r');
+ break;
+
+ case '\n':
+ return EJS_TOK_NEWLINE;
+
+ case '(':
+ tokenAddChar(ep, c);
+ return EJS_TOK_LPAREN;
+
+ case ')':
+ tokenAddChar(ep, c);
+ return EJS_TOK_RPAREN;
+
+ case '[':
+ tokenAddChar(ep, c);
+ return EJS_TOK_LBRACKET;
+
+ case ']':
+ tokenAddChar(ep, c);
+ return EJS_TOK_RBRACKET;
+
+ case '.':
+ tokenAddChar(ep, c);
+ return EJS_TOK_PERIOD;
+
+ case '{':
+ tokenAddChar(ep, c);
+ return EJS_TOK_LBRACE;
+
+ case '}':
+ tokenAddChar(ep, c);
+ return EJS_TOK_RBRACE;
+
+ case '+':
+ if ((c = inputGetc(ep)) < 0) {
+ ejsSyntaxError(ep, 0);
+ return EJS_TOK_ERR;
+ }
+ if (c != '+' ) {
+ inputPutback(ep, c);
+ tokenAddChar(ep, EJS_EXPR_PLUS);
+ return EJS_TOK_EXPR;
+ }
+ tokenAddChar(ep, EJS_EXPR_INC);
+ return EJS_TOK_INC_DEC;
+
+ case '-':
+ if ((c = inputGetc(ep)) < 0) {
+ ejsSyntaxError(ep, 0);
+ return EJS_TOK_ERR;
+ }
+ if (c != '-' ) {
+ inputPutback(ep, c);
+ tokenAddChar(ep, EJS_EXPR_MINUS);
+ return EJS_TOK_EXPR;
+ }
+ tokenAddChar(ep, EJS_EXPR_DEC);
+ return EJS_TOK_INC_DEC;
+
+ case '*':
+ tokenAddChar(ep, EJS_EXPR_MUL);
+ return EJS_TOK_EXPR;
+
+ case '%':
+ tokenAddChar(ep, EJS_EXPR_MOD);
+ return EJS_TOK_EXPR;
+
+ case '/':
+ /*
+ * Handle the division operator and comments
+ */
+ if ((c = inputGetc(ep)) < 0) {
+ ejsSyntaxError(ep, 0);
+ return EJS_TOK_ERR;
+ }
+ if (c != '*' && c != '/') {
+ inputPutback(ep, c);
+ tokenAddChar(ep, EJS_EXPR_DIV);
+ return EJS_TOK_EXPR;
+ }
+ style = c;
+ /*
+ * Eat comments. Both C and C++ comment styles are supported.
+ */
+ while (1) {
+ if ((c = inputGetc(ep)) < 0) {
+ if (style == '/') {
+ return EJS_TOK_EOF;
+ }
+ ejsSyntaxError(ep, 0);
+ return EJS_TOK_ERR;
+ }
+ if (c == '\n' && style == '/') {
+ break;
+ } else if (c == '*') {
+ c = inputGetc(ep);
+ if (style == '/') {
+ if (c == '\n') {
+ break;
+ }
+ } else {
+ if (c == '/') {
+ break;
+ }
+ }
+ }
+ }
+ /*
+ * Continue looking for a token, so get the next character
+ */
+ if ((c = inputGetc(ep)) < 0) {
+ return EJS_TOK_EOF;
+ }
+ break;
+
+ case '<': /* < and <= */
+ if ((c = inputGetc(ep)) < 0) {
+ ejsSyntaxError(ep, 0);
+ return EJS_TOK_ERR;
+ }
+ if (c == '<') {
+ tokenAddChar(ep, EJS_EXPR_LSHIFT);
+ return EJS_TOK_EXPR;
+ } else if (c == '=') {
+ tokenAddChar(ep, EJS_EXPR_LESSEQ);
+ return EJS_TOK_EXPR;
+ }
+ tokenAddChar(ep, EJS_EXPR_LESS);
+ inputPutback(ep, c);
+ return EJS_TOK_EXPR;
+
+ case '>': /* > and >= */
+ if ((c = inputGetc(ep)) < 0) {
+ ejsSyntaxError(ep, 0);
+ return EJS_TOK_ERR;
+ }
+ if (c == '>') {
+ tokenAddChar(ep, EJS_EXPR_RSHIFT);
+ return EJS_TOK_EXPR;
+ } else if (c == '=') {
+ tokenAddChar(ep, EJS_EXPR_GREATEREQ);
+ return EJS_TOK_EXPR;
+ }
+ tokenAddChar(ep, EJS_EXPR_GREATER);
+ inputPutback(ep, c);
+ return EJS_TOK_EXPR;
+
+ case '=': /* "==" */
+ if ((c = inputGetc(ep)) < 0) {
+ ejsSyntaxError(ep, 0);
+ return EJS_TOK_ERR;
+ }
+ if (c == '=') {
+ tokenAddChar(ep, EJS_EXPR_EQ);
+ return EJS_TOK_EXPR;
+ }
+ inputPutback(ep, c);
+ return EJS_TOK_ASSIGNMENT;
+
+ case '!': /* "!=" or "!"*/
+ if ((c = inputGetc(ep)) < 0) {
+ ejsSyntaxError(ep, 0);
+ return EJS_TOK_ERR;
+ }
+ if (c == '=') {
+ tokenAddChar(ep, EJS_EXPR_NOTEQ);
+ return EJS_TOK_EXPR;
+ }
+ inputPutback(ep, c);
+ tokenAddChar(ep, EJS_EXPR_BOOL_COMP);
+ return EJS_TOK_EXPR;
+
+ case ';':
+ tokenAddChar(ep, c);
+ return EJS_TOK_SEMI;
+
+ case ',':
+ tokenAddChar(ep, c);
+ return EJS_TOK_COMMA;
+
+ case ':':
+ tokenAddChar(ep, c);
+ return EJS_TOK_COLON;
+
+ case '|': /* "||" */
+ if ((c = inputGetc(ep)) < 0 || c != '|') {
+ ejsSyntaxError(ep, 0);
+ return EJS_TOK_ERR;
+ }
+ tokenAddChar(ep, EJS_COND_OR);
+ return EJS_TOK_LOGICAL;
+
+ case '&': /* "&&" */
+ if ((c = inputGetc(ep)) < 0 || c != '&') {
+ ejsSyntaxError(ep, 0);
+ return EJS_TOK_ERR;
+ }
+ tokenAddChar(ep, EJS_COND_AND);
+ return EJS_TOK_LOGICAL;
+
+ case '\"': /* String quote */
+ case '\'':
+ quote = c;
+ if ((c = inputGetc(ep)) < 0) {
+ ejsSyntaxError(ep, 0);
+ return EJS_TOK_ERR;
+ }
+
+ while (c != quote) {
+ /*
+ * Check for escape sequence characters
+ */
+ if (c == '\\') {
+ c = inputGetc(ep);
+
+ if (isdigit(c)) {
+ /*
+ * Octal support, \101 maps to 65 = 'A'. Put first
+ * char back so converter will work properly.
+ */
+ inputPutback(ep, c);
+ c = charConvert(ep, 8, 3);
+
+ } else {
+ switch (c) {
+ case 'n':
+ c = '\n'; break;
+ case 'b':
+ c = '\b'; break;
+ case 'f':
+ c = '\f'; break;
+ case 'r':
+ c = '\r'; break;
+ case 't':
+ c = '\t'; break;
+ case 'x':
+ /*
+ * Hex support, \x41 maps to 65 = 'A'
+ */
+ c = charConvert(ep, 16, 2);
+ break;
+ case 'u':
+ /*
+ * Unicode support, \x0401 maps to 65 = 'A'
+ */
+ c = charConvert(ep, 16, 2);
+ c = c*16 + charConvert(ep, 16, 2);
+
+ break;
+ case '\'':
+ case '\"':
+ case '\\':
+ break;
+ default:
+ if (tokenAddChar(ep, '\\') < 0) {
+ return EJS_TOK_ERR;
+ }
+ }
+ }
+ if (tokenAddChar(ep, c) < 0) {
+ return EJS_TOK_ERR;
+ }
+ } else {
+ if (tokenAddChar(ep, c) < 0) {
+ return EJS_TOK_ERR;
+ }
+ }
+ if ((c = inputGetc(ep)) < 0) {
+ ejsSyntaxError(ep, "Unmatched Quote");
+ return EJS_TOK_ERR;
+ }
+ }
+ return EJS_TOK_LITERAL;
+
+ case '0':
+ if (tokenAddChar(ep, c) < 0) {
+ return EJS_TOK_ERR;
+ }
+ if ((c = inputGetc(ep)) < 0) {
+ break;
+ }
+ if (tolower(c) == 'x') {
+ if (tokenAddChar(ep, c) < 0) {
+ return EJS_TOK_ERR;
+ }
+ if ((c = inputGetc(ep)) < 0) {
+ break;
+ }
+ isHex = 1;
+ if (! isxdigit(c)) {
+ parseNumber(ep, type);
+ inputPutback(ep, c);
+ return EJS_TOK_NUMBER;
+ }
+ } else if (! isdigit(c)) {
+#if BLD_FEATURE_FLOATING_POINT
+ if (c == '.' || tolower(c) == 'e' || c == '+' || c == '-') {
+ /* Fall through */
+ type = EJS_TYPE_FLOAT;
+ } else
+#endif
+ {
+ parseNumber(ep, type);
+ inputPutback(ep, c);
+ return EJS_TOK_NUMBER;
+ }
+ }
+ /* Fall through to get more digits */
+
+ case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ if (isHex) {
+ do {
+ if (tokenAddChar(ep, c) < 0) {
+ return EJS_TOK_ERR;
+ }
+ if ((c = inputGetc(ep)) < 0) {
+ break;
+ }
+ } while (isxdigit(c));
+
+ } else {
+#if BLD_FEATURE_FLOATING_POINT
+ do {
+ if (tokenAddChar(ep, c) < 0) {
+ return EJS_TOK_ERR;
+ }
+ if ((c = inputGetc(ep)) < 0) {
+ break;
+ }
+ c = tolower(c);
+ if (c == '.' || c == 'e' || c == 'f') {
+ type = EJS_TYPE_FLOAT;
+ }
+ } while (isdigit(c) || c == '.' || c == 'e' ||
+ c == 'f' ||
+ ((type == EJS_TYPE_FLOAT) && (c == '+' || c == '-')));
+#else
+ do {
+ if (tokenAddChar(ep, c) < 0) {
+ return EJS_TOK_ERR;
+ }
+ if ((c = inputGetc(ep)) < 0) {
+ break;
+ }
+ } while (isdigit(c));
+#endif
+ }
+
+ parseNumber(ep, type);
+ inputPutback(ep, c);
+ return EJS_TOK_NUMBER;
+
+ default:
+ /*
+ * Identifiers or a function names
+ */
+ while (1) {
+ if (c == '\\') {
+ if ((c = inputGetc(ep)) < 0) {
+ break;
+ }
+ if (c == '\n' || c == '\r') {
+ break;
+ }
+ } else if (tokenAddChar(ep, c) < 0) {
+ break;
+ }
+ if ((c = inputGetc(ep)) < 0) {
+ break;
+ }
+ if (!isalnum(c) && c != '$' && c != '_' &&
+ c != '\\' && c != '@') {
+ break;
+ }
+ }
+ if (*ep->token == '\0') {
+ c = inputGetc(ep);
+ break;
+ }
+
+ if (! isalpha((int) *ep->token) && *ep->token != '$' &&
+ *ep->token != '_' && *ep->token != '@') {
+ ejsError(ep, EJS_SYNTAX_ERROR, "Invalid identifier %s",
+ ep->token);
+ return EJS_TOK_ERR;
+ }
+
+ tid = checkReservedWord(ep, state, c, EJS_TOK_ID);
+ if (tid != EJS_TOK_ID) {
+ return tid;
+ }
+
+ /*
+ * Skip white space after token to find out whether this is
+ * a function or not.
+ */
+ while (c == ' ' || c == '\t' || c == '\r' || c == '\n') {
+ if ((c = inputGetc(ep)) < 0)
+ break;
+ }
+
+ tid = EJS_TOK_ID;
+ if ((strlen(ep->token) + 1) >= EJS_MAX_ID) {
+ ejsError(ep, EJS_SYNTAX_ERROR,
+ "Identifier too big. Max is %d letters.", EJS_MAX_ID);
+ return EJS_TOK_ERR;
+ }
+ done++;
+ }
+ }
+
+ /*
+ * Putback the last extra character for next time
+ */
+ inputPutback(ep, c);
+ return tid;
+}
+
+/******************************************************************************/
+
+static void parseNumber(Ejs *ep, EjsType type)
+{
+ switch (type) {
+ case EJS_TYPE_INT:
+ ep->tokenNumber.integer = ejsParseInteger(ep->token);
+ ep->tokenNumber.type = type;
+ break;
+
+#if BLD_FEATURE_FLOATING_POINT
+ case EJS_TYPE_FLOAT:
+ ep->tokenNumber.floating = atof(ep->token);
+ ep->tokenNumber.type = type;
+ break;
+#endif
+
+#if BLD_FEATURE_INT64
+ case EJS_TYPE_INT64:
+ ep->tokenNumber.integer64 = ejsParseInteger64(ep->token);
+ ep->tokenNumber.type = type;
+ break;
+#endif
+ }
+}
+
+/******************************************************************************/
+/*
+ * Convert a hex or octal character back to binary, return original char if
+ * not a hex digit
+ */
+
+static int charConvert(Ejs *ep, int base, int maxDig)
+{
+ int i, c, lval, convChar;
+
+ lval = 0;
+ for (i = 0; i < maxDig; i++) {
+ if ((c = inputGetc(ep)) < 0) {
+ break;
+ }
+ /*
+ * Initialize to out of range value
+ */
+ convChar = base;
+ if (isdigit(c)) {
+ convChar = c - '0';
+ } else if (c >= 'a' && c <= 'f') {
+ convChar = c - 'a' + 10;
+ } else if (c >= 'A' && c <= 'F') {
+ convChar = c - 'A' + 10;
+ }
+ /*
+ * If unexpected character then return it to buffer.
+ */
+ if (convChar >= base) {
+ inputPutback(ep, c);
+ break;
+ }
+ lval = (lval * base) + convChar;
+ }
+ return lval;
+}
+
+/******************************************************************************/
+/*
+ * Putback the last token read. Accept at most one push back token.
+ */
+
+void ejsLexPutbackToken(Ejs *ep, int tid, char *string)
+{
+ EjsInput *ip;
+ EjsToken *tp;
+ int idx;
+
+ mprAssert(ep);
+ ip = ep->input;
+ mprAssert(ip);
+
+ ip->putBackIndex += 1;
+
+ mprAssert(ip->putBackIndex < EJS_TOKEN_STACK);
+ idx = ip->putBackIndex;
+
+ tp = &ip->putBack[idx];
+ tp->tid = tid;
+
+ mprStrcpy(tp->tokbuf, sizeof(tp->tokbuf), string);
+}
+
+/******************************************************************************/
+/*
+ * Add a character to the token buffer
+ */
+
+static int tokenAddChar(Ejs *ep, int c)
+{
+ EjsInput *ip;
+
+ mprAssert(ep);
+ ip = ep->input;
+ mprAssert(ip);
+
+ if (ip->tokEndp >= &ip->tokbuf[sizeof(ip->tokbuf) - 1]) {
+ ejsSyntaxError(ep, "Token too big");
+ return -1;
+ }
+ *ip->tokEndp++ = c;
+ *ip->tokEndp = '\0';
+
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * Get another input character
+ */
+
+static int inputGetc(Ejs *ep)
+{
+ EjsInput *ip;
+ int c;
+
+ mprAssert(ep);
+ ip = ep->input;
+
+ if (ip->scriptSize <= 0) {
+ return -1;
+ }
+
+ c = (uchar) (*ip->scriptServp++);
+ ip->scriptSize--;
+
+ /*
+ * For debugging, accumulate the line number and the currenly parsed line
+ */
+ if (c == '\n') {
+#if 0 && BLD_DEBUG
+ if (ip->lineColumn > 0) {
+ printf("PARSED: %s\n", ip->line);
+ }
+#endif
+ ip->lineNumber++;
+ ip->lineColumn = 0;
+ } else if ((ip->lineColumn + 2) < sizeof(ip->line)) {
+ ip->line[ip->lineColumn++] = c;
+ ip->line[ip->lineColumn] = '\0';
+ }
+ return c;
+}
+
+/******************************************************************************/
+/*
+ * Putback a character onto the input queue
+ */
+
+static void inputPutback(Ejs *ep, int c)
+{
+ EjsInput *ip;
+
+ mprAssert(ep);
+
+ if (c > 0) {
+ ip = ep->input;
+ *--ip->scriptServp = c;
+ ip->scriptSize++;
+ if (--(ip->lineColumn) < 0) {
+ ip->lineColumn = 0;
+ }
+ mprAssert(ip->line);
+ mprAssert(ip->lineColumn >= 0);
+ mprAssert(ip->lineColumn < sizeof(ip->line));
+ ip->line[ip->lineColumn] = '\0';
+ }
+}
+
+/******************************************************************************/
+
+#else
+void ejsLexDummy() {}
+
+/******************************************************************************/
+#endif /* BLD_FEATURE_EJS */
+
+/*
+ * 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-2.0/ejs/ejsParser.c b/source4/lib/appweb/ejs-2.0/ejs/ejsParser.c
new file mode 100644
index 0000000000..9fce6d27ee
--- /dev/null
+++ b/source4/lib/appweb/ejs-2.0/ejs/ejsParser.c
@@ -0,0 +1,4514 @@
+/*
+ * @file ejsParser.c
+ * @brief EJS Parser and Execution
+ */
+/********************************* Copyright **********************************/
+/*
+ * @copy default.g
+ *
+ * Copyright (c) Mbedthis Software LLC, 2003-2006. All Rights Reserved.
+ * Portions Copyright (c) GoAhead Software, 1995-2000. 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
+ */
+
+/********************************** Includes **********************************/
+
+#include "ejs.h"
+
+#if BLD_FEATURE_EJS
+
+/****************************** Forward Declarations **************************/
+
+static int createClass(Ejs *ep, EjsVar *parentClass,
+ const char *className, EjsVar *baseClass);
+static int createProperty(Ejs *ep, EjsVar **obj, const char *id,
+ int state);
+static int evalCond(Ejs *ep, EjsVar *lhs, int rel, EjsVar *rhs);
+static int evalExpr(Ejs *ep, EjsVar *lhs, int rel, EjsVar *rhs);
+#if BLD_FEATURE_FLOATING_POINT
+static int evalFloatExpr(Ejs *ep, double l, int rel, double r);
+#endif
+static int evalBoolExpr(Ejs *ep, int l, int rel, int r);
+static int evalNumericExpr(Ejs *ep, EjsNum l, int rel, EjsNum r);
+static int evalObjExpr(Ejs *ep, EjsVar *lhs, int rel, EjsVar *rhs) ;
+static int evalStringExpr(Ejs *ep, EjsVar *lhs, int rel, EjsVar *rhs);
+static int evalMethod(Ejs *ep, EjsVar *obj, EjsProc *proc, int flags);
+static EjsProperty *findProperty(Ejs *ep, EjsVar *op, const char *property,
+ int flags);
+static EjsVar *pickSpace(Ejs *ep, int state, const char *property, int flags);
+static void freeProc(Ejs *ep, EjsProc *proc);
+static int parseArgs(Ejs *ep, int state, int flags);
+static int parseArrayLiteral(Ejs *ep, int state, int flags, char *id);
+static int parseAssignment(Ejs *ep, int state, int flags, char *id);
+static int parseClass(Ejs *ep, int state, int flags);
+static int parseForInner(Ejs *ep, int state, int flags,
+ EjsInput *condScript, EjsInput *incrScript,
+ EjsInput *bodyScript, EjsInput *endScript);
+static int parseCond(Ejs *ep, int state, int flags);
+static int parseDeclaration(Ejs *ep, int state, int flags);
+static int parseExpr(Ejs *ep, int state, int flags);
+static int parseFor(Ejs *ep, int state, int flags);
+static int parseRegFor(Ejs *ep, int state, int flags);
+static int parseForIn(Ejs *ep, int state, int flags, int each);
+static int parseId(Ejs *ep, int state, int flags, char **id, int *done);
+static int parseInc(Ejs *ep, int state, int flags);
+static int parseIf(Ejs *ep, int state, int flags, int *done);
+static int parseFunction(Ejs *ep, int state, int flags);
+static int parseMethod(Ejs *ep, int state, int flags, char *id);
+static int parseObjectLiteral(Ejs *ep, int state, int flags, char *id);
+static int parseStmt(Ejs *ep, int state, int flags);
+static int parseThrow(Ejs *ep, int state, int flags);
+static int parseTry(Ejs *ep, int state, int flags);
+static void removeNewlines(Ejs *ep, int state);
+static EjsProperty *searchSpacesForProperty(Ejs *ep, int state, EjsVar *obj,
+ char *property, int flags);
+static int assignPropertyValue(Ejs *ep, char *id, int state, EjsVar *value,
+ int flags);
+static int updateProperty(Ejs *ep, EjsVar *obj, const char *id, int state,
+ EjsVar *value);
+static void updateResult(Ejs *ep, int state, int flags, EjsVar *vp);
+static int getNextNonSpaceToken(Ejs *ep, int state);
+
+static int callConstructor(Ejs *ep, EjsVar *thisObj, EjsVar *baseClass,
+ MprArray *args);
+static int callCMethod(Ejs *ep, EjsVar *obj, EjsProc *proc,
+ EjsVar *prototype);
+static int callStringCMethod(Ejs *ep, EjsVar *obj, EjsProc *proc,
+ EjsVar *prototype);
+static int callMethod(Ejs *ep, EjsVar *obj, EjsProc *proc,
+ EjsVar *prototype);
+static int runMethod(Ejs *ep, EjsVar *thisObj, EjsVar *method,
+ const char *methodName, MprArray *args);
+
+static EjsInput *getInputStruct(Ejs *ep);
+static void freeInputStruct(Ejs *ep, EjsInput *input);
+
+static void *pushFrame(Ejs *ep, int size);
+static void *popFrame(Ejs *ep, int size);
+
+/************************************* Code ***********************************/
+/*
+ * Recursive descent parser for EJS
+ */
+
+int ejsParse(Ejs *ep, int state, int flags)
+{
+ mprAssert(ep);
+
+#if MOB
+ if (mprStackCheck(ep)) {
+ char *stack;
+ stack = ejsFormatStack(ep);
+ mprLog(ep, 0, "\nStack grew : MAX %d\n", mprStackSize(ep));
+ mprLog(ep, 0, "Stack\n %s\n", stack);
+ mprFree(stack);
+ }
+#endif
+
+ if (ep->flags & EJS_FLAGS_EXIT) {
+ return EJS_STATE_RET;
+ }
+
+ ep->inputMarker = ep->input->scriptServp;
+
+ switch (state) {
+ /*
+ * Any statement, method arguments or conditional expressions
+ */
+ case EJS_STATE_STMT:
+ state = parseStmt(ep, state, flags);
+ if (state != EJS_STATE_STMT_BLOCK_DONE && state != EJS_STATE_STMT_DONE){
+ goto err;
+ }
+ break;
+
+ case EJS_STATE_DEC:
+ state = parseStmt(ep, state, flags);
+ if (state != EJS_STATE_DEC_DONE) {
+ goto err;
+ }
+ break;
+
+ case EJS_STATE_EXPR:
+ state = parseStmt(ep, state, flags);
+ if (state != EJS_STATE_EXPR_DONE) {
+ goto err;
+ }
+ break;
+
+ /*
+ * Variable declaration list
+ */
+ case EJS_STATE_DEC_LIST:
+ state = parseDeclaration(ep, state, flags);
+ if (state != EJS_STATE_DEC_LIST_DONE) {
+ goto err;
+ }
+ break;
+
+ /*
+ * Method argument string
+ */
+ case EJS_STATE_ARG_LIST:
+ state = parseArgs(ep, state, flags);
+ if (state != EJS_STATE_ARG_LIST_DONE) {
+ goto err;
+ }
+ break;
+
+ /*
+ * Logical condition list (relational operations separated by &&, ||)
+ */
+ case EJS_STATE_COND:
+ state = parseCond(ep, state, flags);
+ if (state != EJS_STATE_COND_DONE) {
+ goto err;
+ }
+ break;
+
+ /*
+ * Expression list
+ */
+ case EJS_STATE_RELEXP:
+ state = parseExpr(ep, state, flags);
+ if (state != EJS_STATE_RELEXP_DONE) {
+ goto err;
+ }
+ break;
+ }
+
+ /*
+ * Recursion protection
+ */
+ if (ep->input->scriptServp == ep->inputMarker) {
+ if (ep->recurseCount++ > 20) {
+ ejsSyntaxError(ep, "Input syntax error");
+ state = EJS_STATE_ERR;
+ }
+ } else {
+ ep->recurseCount = 0;
+ }
+
+ if (state == EJS_STATE_RET || state == EJS_STATE_EOF) {
+ return state;
+ }
+
+done:
+ return state;
+
+err:
+ if (state == EJS_STATE_RET || state == EJS_STATE_EOF) {
+ goto done;
+ }
+ if (state != EJS_STATE_ERR) {
+ ejsSyntaxError(ep, 0);
+ }
+ state = EJS_STATE_ERR;
+ goto done;
+}
+
+/******************************************************************************/
+/*
+ * Local vars
+ */
+
+typedef struct ParseStmt {
+ EjsProc *saveProc;
+ EjsProperty *pp;
+ EjsVar *saveObj, *exception;
+ char *str, *id;
+ int done, tid, rs, saveObjPerm, expectEndOfStmt;
+} ParseStmt;
+
+/*
+ * Parse expression (leftHandSide operator rightHandSide)
+ */
+
+
+static int parseStmt(Ejs *ep, int state, int flags)
+{
+ ParseStmt *sp;
+
+ mprAssert(ep);
+
+ if ((sp = pushFrame(ep, sizeof(ParseStmt))) == 0) {
+ return EJS_STATE_ERR;
+ }
+
+ sp->id = 0;
+ sp->expectEndOfStmt = 0;
+ sp->saveProc = NULL;
+
+ ep->currentObj = 0;
+ ep->currentProperty = 0;
+
+ for (sp->done = 0; !sp->done && state != EJS_STATE_ERR; ) {
+ sp->tid = ejsLexGetToken(ep, state);
+
+#if (WIN || BREW_SIMULATOR) && BLD_DEBUG && DISABLED
+ /* MOB -- make cross platform */
+ _CrtCheckMemory();
+#endif
+
+ switch (sp->tid) {
+ default:
+ ejsLexPutbackToken(ep, sp->tid, ep->token);
+ goto done;
+
+ case EJS_TOK_EXPR:
+ if (state == EJS_STATE_EXPR) {
+ ejsLexPutbackToken(ep, EJS_TOK_EXPR, ep->token);
+ }
+ goto done;
+
+ case EJS_TOK_LOGICAL:
+ ejsLexPutbackToken(ep, sp->tid, ep->token);
+ goto done;
+
+ case EJS_TOK_ERR:
+ if (state != EJS_STATE_ERR && !ep->gotException) {
+ ejsSyntaxError(ep, 0);
+ }
+ state = EJS_STATE_ERR;
+ goto done;
+
+ case EJS_TOK_EOF:
+ state = EJS_STATE_EOF;
+ goto done;
+
+ case EJS_TOK_NEWLINE:
+ break;
+
+ case EJS_TOK_SEMI:
+ /*
+ * This case is when we discover no statement and just a lone ';'
+ */
+ if (state != EJS_STATE_STMT) {
+ ejsLexPutbackToken(ep, sp->tid, ep->token);
+ }
+ goto done;
+
+ case EJS_TOK_LBRACKET:
+ if (flags & EJS_FLAGS_EXE) {
+ ep->currentObj = &ep->currentProperty->var;
+ if (ep->currentObj != 0 && ep->currentObj->type !=
+ EJS_TYPE_OBJECT) {
+ ejsError(ep, EJS_REFERENCE_ERROR,
+ "Property reference to a non-object type \"%s\"\n",
+ sp->id);
+ goto err;
+ }
+ }
+
+ sp->saveObj = ep->currentObj;
+ sp->saveObjPerm = ejsMakeObjPermanent(sp->saveObj, 1);
+
+ sp->rs = ejsParse(ep, EJS_STATE_RELEXP, flags);
+
+ ejsMakeObjPermanent(sp->saveObj, sp->saveObjPerm);
+ ep->currentObj = sp->saveObj;
+
+ if (sp->rs < 0) {
+ state = sp->rs;
+ goto done;
+ }
+
+ mprFree(sp->id);
+ /* MOB rc */
+ sp->str = ejsVarToString(ep, ep->result);
+ sp->id = mprStrdup(ep, sp->str);
+
+ if (sp->id[0] == '\0') {
+ if (flags & EJS_FLAGS_EXE) {
+ ejsError(ep, EJS_RANGE_ERROR,
+ "[] expression evaluates to the empty string\n");
+ goto err;
+ }
+ } else {
+ sp->pp = searchSpacesForProperty(ep, state, ep->currentObj,
+ sp->id, flags);
+ ep->currentProperty = sp->pp;
+ updateResult(ep, state, flags, ejsGetVarPtr(sp->pp));
+ }
+
+ if ((sp->tid = ejsLexGetToken(ep, state)) != EJS_TOK_RBRACKET) {
+ ejsSyntaxError(ep, "Missing ']'");
+ goto err;
+ }
+ break;
+
+ case EJS_TOK_PERIOD:
+ if (flags & EJS_FLAGS_EXE) {
+ if (ep->currentProperty == 0) {
+ ejsError(ep, EJS_REFERENCE_ERROR,
+ "Undefined object \"%s\"", sp->id);
+ goto err;
+ }
+ }
+ ep->currentObj = &ep->currentProperty->var;
+ if (flags & EJS_FLAGS_EXE) {
+ if (ep->currentObj != 0 && ep->currentObj->type !=
+ EJS_TYPE_OBJECT) {
+ ejsError(ep, EJS_REFERENCE_ERROR,
+ "Property reference to a non-object type \"%s\"\n",
+ sp->id);
+ goto err;
+ }
+ }
+ if ((sp->tid = ejsLexGetToken(ep, state)) != EJS_TOK_ID) {
+ ejsError(ep, EJS_REFERENCE_ERROR, "Bad property after '.': %s",
+ ep->token);
+ goto err;
+ }
+ /* Fall through */
+
+ case EJS_TOK_ID:
+ state = parseId(ep, state, flags, &sp->id, &sp->done);
+ if (sp->done && state == EJS_STATE_STMT) {
+ sp->expectEndOfStmt = 1;
+ }
+ break;
+
+ case EJS_TOK_ASSIGNMENT:
+ sp->tid = ejsLexGetToken(ep, state);
+ if (sp->tid == EJS_TOK_LBRACE) {
+ /*
+ * var = { name: value, name: value, ... }
+ */
+ if (parseObjectLiteral(ep, state, flags, sp->id) < 0) {
+ ejsSyntaxError(ep, "Bad object literal");
+ goto err;
+ }
+
+ } else if (sp->tid == EJS_TOK_LBRACKET) {
+ /*
+ * var = [ array elements ]
+ */
+ if (parseArrayLiteral(ep, state, flags, sp->id) < 0) {
+ ejsSyntaxError(ep, "Bad array literal");
+ goto err;
+ }
+
+ } else if (sp->tid == EJS_TOK_EXPR &&
+ (int) *ep->token == EJS_EXPR_LESS) {
+ /*
+ * var = <xmlTag> .../</xmlTag>
+ */
+ ejsSyntaxError(ep, "XML literals are not yet supported");
+ goto err;
+
+ } else {
+ /*
+ * var = expression
+ */
+ ejsLexPutbackToken(ep, sp->tid, ep->token);
+ state = parseAssignment(ep, state, flags, sp->id);
+ if (state == EJS_STATE_ERR) {
+ if (ep->flags & EJS_FLAGS_EXIT) {
+ state = EJS_STATE_RET;
+ goto done;
+ }
+ if (!ep->gotException) {
+ ejsSyntaxError(ep, 0);
+ }
+ goto err;
+ }
+ }
+
+ if (flags & EJS_FLAGS_EXE) {
+ if (assignPropertyValue(ep, sp->id, state, ep->result,
+ flags) < 0) {
+ if (ep->gotException == 0) {
+ ejsError(ep, EJS_EVAL_ERROR, "Can't set property %s",
+ sp->id);
+ }
+ goto err;
+ }
+ }
+
+ if (state == EJS_STATE_STMT) {
+ sp->expectEndOfStmt = 1;
+ goto done;
+ }
+ break;
+
+ case EJS_TOK_INC_DEC:
+ state = parseInc(ep, state, flags);
+ if (state == EJS_STATE_STMT) {
+ sp->expectEndOfStmt = 1;
+ }
+ break;
+
+ case EJS_TOK_NEW:
+ /* MOB -- could we remove rs and just use state */
+ sp->rs = ejsParse(ep, EJS_STATE_EXPR, flags | EJS_FLAGS_NEW);
+ if (sp->rs < 0) {
+ state = sp->rs;
+ goto done;
+ }
+ break;
+
+ case EJS_TOK_DELETE:
+ sp->rs = ejsParse(ep, EJS_STATE_EXPR, flags | EJS_FLAGS_DELETE);
+ if (sp->rs < 0) {
+ state = sp->rs;
+ goto done;
+ }
+ if (flags & EJS_FLAGS_EXE) {
+ /* Single place where properties are deleted */
+ if (ep->currentObj == 0 || ep->currentProperty == 0) {
+ ejsError(ep, EJS_EVAL_ERROR,
+ "Can't find property to delete");
+ goto err;
+ }
+ if (ep->currentObj->isArray) {
+ ejsSetArrayLength(ep, ep->currentObj, 0,
+ ep->currentProperty->name, 0);
+ }
+ ejsDeleteProperty(ep, ep->currentObj,
+ ep->currentProperty->name);
+ ep->currentProperty = 0;
+ }
+ goto done;
+
+ case EJS_TOK_FUNCTION:
+ /*
+ * Parse a function declaration
+ */
+ state = parseFunction(ep, state, flags);
+ goto done;
+
+ case EJS_TOK_THROW:
+ state = parseThrow(ep, state, flags);
+ goto done;
+
+ case EJS_TOK_TRY:
+ state = parseTry(ep, state, flags);
+ goto done;
+
+ case EJS_TOK_CLASS:
+ case EJS_TOK_MODULE:
+ state = parseClass(ep, state, flags);
+ goto done;
+
+ case EJS_TOK_LITERAL:
+ /*
+ * Set the result to the string literal
+ */
+ if (flags & EJS_FLAGS_EXE) {
+ ejsWriteVarAsString(ep, ep->result, ep->token);
+ ejsSetVarName(ep, ep->result, "");
+ }
+ if (state == EJS_STATE_STMT) {
+ sp->expectEndOfStmt = 1;
+ }
+ goto done;
+
+ case EJS_TOK_NUMBER:
+ /*
+ * Set the result to the parsed number
+ */
+ if (flags & EJS_FLAGS_EXE) {
+ ejsWriteVar(ep, ep->result, &ep->tokenNumber, 0);
+ }
+ if (state == EJS_STATE_STMT) {
+ sp->expectEndOfStmt = 1;
+ }
+ goto done;
+
+ case EJS_TOK_METHOD_NAME:
+ /*
+ * parse a method() invocation
+ */
+ mprAssert(ep->currentObj);
+ state = parseMethod(ep, state, flags, sp->id);
+ if (state == EJS_STATE_STMT) {
+ sp->expectEndOfStmt = 1;
+ }
+ if (ep->flags & EJS_FLAGS_EXIT) {
+ state = EJS_STATE_RET;
+ }
+ goto done;
+
+ case EJS_TOK_IF:
+ state = parseIf(ep, state, flags, &sp->done);
+ if (state < 0) {
+ goto done;
+ }
+ break;
+
+ case EJS_TOK_FOR:
+ state = parseFor(ep, state, flags);
+ goto done;
+
+ case EJS_TOK_VAR:
+ if ((sp->rs = ejsParse(ep, EJS_STATE_DEC_LIST, flags)) < 0) {
+ state = sp->rs;
+ goto done;
+ }
+ goto done;
+
+ case EJS_TOK_COMMA:
+ ejsLexPutbackToken(ep, sp->tid, ep->token);
+ goto done;
+
+ case EJS_TOK_LPAREN:
+ if (state == EJS_STATE_EXPR) {
+ if ((sp->rs = ejsParse(ep, EJS_STATE_RELEXP, flags)) < 0) {
+ state = sp->rs;
+ goto done;
+ }
+ if (ejsLexGetToken(ep, state) != EJS_TOK_RPAREN) {
+ ejsSyntaxError(ep, 0);
+ goto err;
+ }
+ goto done;
+
+ } else if (state == EJS_STATE_STMT) {
+ ejsLexPutbackToken(ep, EJS_TOK_METHOD_NAME, ep->token);
+ }
+ break;
+
+ case EJS_TOK_RPAREN:
+ ejsLexPutbackToken(ep, sp->tid, ep->token);
+ goto done;
+
+ case EJS_TOK_EXTENDS:
+ if (! (flags & EJS_FLAGS_CLASS_DEC)) {
+ ejsSyntaxError(ep, 0);
+ goto err;
+ }
+ sp->saveObj = ep->currentObj;
+ sp->saveObjPerm = ejsMakeObjPermanent(sp->saveObj, 1);
+
+ sp->rs = ejsParse(ep, EJS_STATE_STMT, flags);
+ ejsMakeObjPermanent(sp->saveObj, sp->saveObjPerm);
+
+ if (sp->rs < 0) {
+ state = sp->rs;
+ goto done;
+ }
+
+ if (flags & EJS_FLAGS_EXE) {
+ if (createClass(ep, sp->saveObj, sp->id,
+ ejsGetVarPtr(ep->currentProperty)) < 0) {
+ goto err;
+ }
+ }
+ if (ejsLexGetToken(ep, state) != EJS_TOK_LBRACE) {
+ ejsSyntaxError(ep, 0);
+ goto err;
+ }
+ ejsLexPutbackToken(ep, ep->tid, ep->token);
+ goto done;
+
+ case EJS_TOK_LBRACE:
+ if (flags & EJS_FLAGS_CLASS_DEC) {
+ if (state == EJS_STATE_DEC) {
+ if (flags & EJS_FLAGS_EXE) {
+ if (createClass(ep, ep->currentObj, sp->id, 0) < 0) {
+ goto err;
+ }
+ }
+ ejsLexPutbackToken(ep, sp->tid, ep->token);
+
+ } else if (state == EJS_STATE_STMT) {
+ ejsLexPutbackToken(ep, sp->tid, ep->token);
+ }
+ goto done;
+ }
+
+ /*
+ * This handles any code in braces except "if () {} else {}"
+ */
+ if (state != EJS_STATE_STMT) {
+ ejsSyntaxError(ep, 0);
+ goto err;
+ }
+
+ /*
+ * Parse will return EJS_STATE_STMT_BLOCK_DONE when the RBRACE
+ * is seen.
+ */
+ sp->exception = 0;
+ do {
+ state = ejsParse(ep, EJS_STATE_STMT, flags);
+ if (state == EJS_STATE_ERR) {
+ /*
+ * We need to keep parsing to get to the end of the block
+ */
+ if (sp->exception == 0) {
+ sp->exception = ejsDupVar(ep, ep->result,
+ EJS_SHALLOW_COPY);
+ if (sp->exception == 0) {
+ ejsMemoryError(ep);
+ goto err;
+ }
+ if (sp->exception->type == EJS_TYPE_OBJECT) {
+ ejsMakeObjLive(sp->exception, 0);
+ mprAssert(sp->exception->objectState->alive == 0);
+ }
+
+ /*
+ * If we're in a try block, we need to keep parsing
+ * so we can find the end of the block and the start
+ * of the catch block. Otherwise, we are done.
+ */
+ if (!(flags & EJS_FLAGS_TRY)) {
+ break;
+ }
+ }
+ flags &= ~EJS_FLAGS_EXE;
+ if (ep->recurseCount > 20) {
+ break;
+ }
+ state = EJS_STATE_STMT_DONE;
+ ep->gotException = 0;
+ }
+
+ } while (state == EJS_STATE_STMT_DONE);
+
+ if (sp->exception) {
+ ep->gotException = 1;
+ ejsWriteVar(ep, ep->result, sp->exception, EJS_SHALLOW_COPY);
+
+ /* Eat the closing brace */
+ ejsLexGetToken(ep, state);
+ ejsFreeVar(ep, sp->exception);
+
+ goto err;
+ }
+ ejsFreeVar(ep, sp->exception);
+
+ if (state < 0) {
+ goto done;
+ }
+
+ if (ejsLexGetToken(ep, state) != EJS_TOK_RBRACE) {
+ ejsSyntaxError(ep, 0);
+ goto err;
+ }
+ state = EJS_STATE_STMT_DONE;
+ goto done;
+
+ case EJS_TOK_RBRACE:
+ if (state == EJS_STATE_STMT) {
+ ejsLexPutbackToken(ep, sp->tid, ep->token);
+ state = EJS_STATE_STMT_BLOCK_DONE;
+
+ } else if (state == EJS_STATE_EXPR) {
+ ejsLexPutbackToken(ep, sp->tid, ep->token);
+ state = EJS_STATE_EXPR;
+
+ } else {
+ ejsSyntaxError(ep, 0);
+ state = EJS_STATE_ERR;
+ }
+ goto done;
+
+ case EJS_TOK_RETURN:
+ if ((sp->rs = ejsParse(ep, EJS_STATE_RELEXP, flags)) < 0) {
+ state = sp->rs;
+ goto done;
+ }
+ if (flags & EJS_FLAGS_EXE) {
+ state = EJS_STATE_RET;
+ goto done;
+ }
+ break;
+ }
+ }
+done:
+ mprFree(sp->id);
+
+ if (sp->expectEndOfStmt && state >= 0) {
+ sp->tid = ejsLexGetToken(ep, state);
+ if (sp->tid == EJS_TOK_RBRACE) {
+ ejsLexPutbackToken(ep, EJS_TOK_RBRACE, ep->token);
+
+ } else if (sp->tid != EJS_TOK_SEMI && sp->tid != EJS_TOK_NEWLINE &&
+ sp->tid != EJS_TOK_EOF) {
+ ejsSyntaxError(ep, 0);
+ state = EJS_STATE_ERR;
+
+ } else {
+ /*
+ * Skip newlines after semi-colon
+ */
+ removeNewlines(ep, state);
+ }
+ }
+
+ /*
+ * Advance the state
+ */
+ switch (state) {
+ case EJS_STATE_STMT:
+ case EJS_STATE_STMT_DONE:
+ state = EJS_STATE_STMT_DONE;
+ break;
+
+ case EJS_STATE_DEC:
+ case EJS_STATE_DEC_DONE:
+ state = EJS_STATE_DEC_DONE;
+ break;
+
+ case EJS_STATE_EXPR:
+ case EJS_STATE_EXPR_DONE:
+ state = EJS_STATE_EXPR_DONE;
+ break;
+
+ case EJS_STATE_STMT_BLOCK_DONE:
+ case EJS_STATE_EOF:
+ case EJS_STATE_RET:
+ break;
+
+ default:
+ if (state != EJS_STATE_ERR) {
+ ejsSyntaxError(ep, 0);
+ }
+ state = EJS_STATE_ERR;
+ }
+ popFrame(ep, sizeof(ParseStmt));
+ return state;
+
+err:
+ state = EJS_STATE_ERR;
+ goto done;
+}
+
+/******************************************************************************/
+/*
+ * Local vars
+ */
+
+typedef struct ParseFor {
+ char *initToken;
+ int tid, foundVar, initId, each;
+} ParseFor;
+
+/*
+ * Parse method arguments
+ */
+
+static int parseFor(Ejs *ep, int state, int flags)
+{
+ ParseFor *sp;
+
+ if ((sp = pushFrame(ep, sizeof(ParseFor))) == 0) {
+ return EJS_STATE_ERR;
+ }
+
+ mprAssert(ep);
+
+ if (state != EJS_STATE_STMT) {
+ ejsSyntaxError(ep, 0);
+ goto err;
+ }
+
+ if ((sp->tid = ejsLexGetToken(ep, state)) == EJS_TOK_EACH) {
+ sp->each = 1;
+ sp->tid = ejsLexGetToken(ep, state);
+
+ } else {
+ sp->each = 0;
+ }
+
+ if (sp->tid != EJS_TOK_LPAREN) {
+ ejsSyntaxError(ep, 0);
+ goto err;
+ }
+
+ /*
+ * Need to peek 2-3 tokens ahead and see if this is a
+ * for [each] ([var] x in set)
+ * or
+ * for (init ; whileCond; incr)
+ */
+ sp->initId = ejsLexGetToken(ep, EJS_STATE_EXPR);
+ sp->foundVar = 0;
+ if (sp->initId == EJS_TOK_ID && strcmp(ep->token, "var") == 0) {
+ sp->foundVar = 1;
+ sp->initId = ejsLexGetToken(ep, EJS_STATE_EXPR);
+ }
+ sp->initToken = mprStrdup(ep, ep->token);
+
+ sp->tid = ejsLexGetToken(ep, EJS_STATE_EXPR);
+
+ ejsLexPutbackToken(ep, sp->tid, ep->token);
+ ejsLexPutbackToken(ep, sp->initId, sp->initToken);
+ mprFree(sp->initToken);
+
+ if (sp->foundVar) {
+ ejsLexPutbackToken(ep, EJS_TOK_ID, "var");
+ }
+
+ if (sp->tid == EJS_TOK_IN) {
+ state = parseForIn(ep, state, flags, sp->each);
+
+ } else {
+ state = parseRegFor(ep, state, flags);
+ }
+
+done:
+ popFrame(ep, sizeof(ParseFor));
+ return state;
+
+err:
+ state = EJS_STATE_ERR;
+ goto done;
+}
+
+/******************************************************************************/
+/*
+ * Parse method arguments
+ */
+
+static int parseArgs(Ejs *ep, int state, int flags)
+{
+ EjsVar *vp;
+ int tid;
+
+ mprAssert(ep);
+
+ do {
+ /*
+ * Peek and see if there are no args
+ */
+ tid = ejsLexGetToken(ep, state);
+ ejsLexPutbackToken(ep, tid, ep->token);
+ if (tid == EJS_TOK_RPAREN) {
+ break;
+ }
+
+ /*
+ * If this is part of a constructor, must run methods in args normally
+ */
+ flags &= ~EJS_FLAGS_NEW;
+
+ state = ejsParse(ep, EJS_STATE_RELEXP, flags);
+ if (state < 0) {
+ return state;
+ }
+ if (flags & EJS_FLAGS_EXE) {
+ mprAssert(ep->proc->args);
+ vp = ejsDupVar(ep, ep->result, EJS_SHALLOW_COPY);
+ if (vp == 0) {
+ ejsMemoryError(ep);
+ return EJS_STATE_ERR;
+ }
+ /* MOB */
+ if (vp->type == EJS_TYPE_OBJECT) {
+ ejsMakeObjLive(vp, 0);
+ mprAssert(vp->objectState->alive == 0);
+ }
+
+ /*
+ * Propagate the name
+ */
+ ejsSetVarName(ep, vp, ep->result->propertyName);
+
+ mprAddItem(ep->proc->args, vp);
+
+ }
+ /*
+ * Peek at the next token, continue if more args (ie. comma seen)
+ */
+ tid = ejsLexGetToken(ep, state);
+ if (tid != EJS_TOK_COMMA) {
+ ejsLexPutbackToken(ep, tid, ep->token);
+ }
+ } while (tid == EJS_TOK_COMMA);
+
+ if (tid != EJS_TOK_RPAREN && state != EJS_STATE_RELEXP_DONE) {
+ ejsSyntaxError(ep, 0);
+ return EJS_STATE_ERR;
+ }
+ return EJS_STATE_ARG_LIST_DONE;
+}
+
+/******************************************************************************/
+/*
+ * Local vars
+ */
+
+typedef struct ParseAssign {
+ EjsProperty *saveProperty;
+ EjsVar *saveObj;
+ int saveObjPerm, savePropPerm, rc;
+} ParseAssign;
+
+/*
+ * Parse an assignment statement
+ */
+
+static int parseAssignment(Ejs *ep, int state, int flags, char *id)
+{
+ ParseAssign *sp;
+
+
+ if (id == 0) {
+ if (!ep->gotException) {
+ ejsSyntaxError(ep, 0);
+ }
+ return EJS_STATE_ERR;
+ }
+
+ if ((sp = pushFrame(ep, sizeof(ParseAssign))) == 0) {
+ return EJS_STATE_ERR;
+ }
+
+ mprAssert(ep->currentObj);
+
+ /*
+ * Parse the right hand side of the "="
+ */
+ sp->saveObj = ep->currentObj;
+ sp->saveProperty = ep->currentProperty;
+
+ sp->saveObjPerm = ejsMakeObjPermanent(sp->saveObj, 1);
+ sp->savePropPerm = ejsMakeObjPermanent(ejsGetVarPtr(sp->saveProperty), 1);
+
+ sp->rc = ejsParse(ep, EJS_STATE_RELEXP, flags | EJS_FLAGS_ASSIGNMENT);
+
+ ejsMakeObjPermanent(sp->saveObj, sp->saveObjPerm);
+ ejsMakeObjPermanent(ejsGetVarPtr(sp->saveProperty), sp->savePropPerm);
+
+ if (sp->rc < 0) {
+ state = EJS_STATE_ERR;
+ }
+
+ ep->currentObj = sp->saveObj;
+ ep->currentProperty = sp->saveProperty;
+
+ popFrame(ep, sizeof(ParseAssign));
+
+ if (! (flags & EJS_FLAGS_EXE)) {
+ return state;
+ }
+
+ return state;
+}
+
+/******************************************************************************/
+
+static int assignPropertyValue(Ejs *ep, char *id, int state, EjsVar *value,
+ int flags)
+{
+ EjsProperty *saveProperty;
+ EjsVar *saveObj, *obj, *vp;
+ char *procName;
+ int saveObjPerm, savePropPerm, rc;
+
+ mprAssert(flags & EJS_FLAGS_EXE);
+
+ if (ep->currentProperty &&
+ !ep->currentProperty->var.flags & EJS_GET_ACCESSOR) {
+ obj = ep->currentObj;
+
+ } else {
+ /*
+ * Handle any set accessors.
+ * FUTURE OPT -- could be faster
+ * FUTURE OPT -- coming here even when doing just a set "x = value";
+ */
+ procName = 0;
+ if (mprAllocStrcat(MPR_LOC_ARGS(ep), &procName, EJS_MAX_ID + 5, 0,
+ "-set-", id, 0) > 0) {
+
+ MprArray *args;
+
+ ep->currentProperty = searchSpacesForProperty(ep, state,
+ ep->currentObj, procName, flags);
+
+ if (ep->currentProperty) {
+ args = mprCreateItemArray(ep, EJS_INC_ARGS, EJS_MAX_ARGS);
+
+ vp = ejsDupVar(ep, value, EJS_SHALLOW_COPY);
+ mprAddItem(args, vp);
+ mprAssert(! ejsObjIsCollectable(vp));
+
+ saveObj = ep->currentObj;
+ saveProperty = ep->currentProperty;
+
+ saveObjPerm = ejsMakeObjPermanent(saveObj, 1);
+ savePropPerm = ejsMakeObjPermanent(ejsGetVarPtr(saveProperty),
+ 1);
+
+ /*
+ * Invoke the set accessor
+ */
+ rc = ejsRunMethod(ep, ep->currentObj, procName, args);
+ mprFree(procName);
+ ejsFreeMethodArgs(ep, args);
+
+ ejsMakeObjPermanent(saveObj, saveObjPerm);
+ ejsMakeObjPermanent(ejsGetVarPtr(saveProperty), savePropPerm);
+
+ ep->currentObj = saveObj;
+ ep->currentProperty = saveProperty;
+
+ if (rc < 0) {
+ return EJS_STATE_ERR;
+ }
+ return state;
+ }
+ mprFree(procName);
+ }
+
+ if (ep->currentProperty == 0) {
+ /*
+ * MOB -- can we omit this as updateProperty below will create
+ */
+ if (createProperty(ep, &obj, id, state) < 0) {
+ return EJS_STATE_ERR;
+ }
+ }
+ }
+
+ if (updateProperty(ep, obj, id, state, value) < 0) {
+ return EJS_STATE_ERR;
+ }
+
+ vp = ejsGetVarPtr(ep->currentProperty);
+ if (vp->type == EJS_TYPE_OBJECT) {
+ ejsMakeObjLive(vp, 1);
+ }
+
+ return state;
+}
+
+/******************************************************************************/
+
+static int parseObjectLiteral(Ejs *ep, int state, int flags, char *id)
+{
+ EjsProperty *saveProperty;
+ EjsVar *saveObj;
+ EjsVar *obj;
+ char *name;
+ int saveObjPerm, savePropPerm, tid;
+
+ name = 0;
+
+ saveObj = ep->currentObj;
+ saveProperty = ep->currentProperty;
+
+ saveObjPerm = ejsMakeObjPermanent(saveObj, 1);
+ savePropPerm = ejsMakeObjPermanent(ejsGetVarPtr(saveProperty), 1);
+
+ if (flags & EJS_FLAGS_EXE) {
+ obj = ejsCreateSimpleObj(ep, "Object");
+ if (obj == 0) {
+ ejsMemoryError(ep);
+ goto err;
+ }
+ mprAssert(! ejsObjIsCollectable(obj));
+
+ } else {
+ obj = 0;
+ }
+
+ do {
+ tid = getNextNonSpaceToken(ep, state);
+ if (tid != EJS_TOK_ID) {
+ ejsSyntaxError(ep, 0);
+ goto err;
+ }
+ name = mprStrdup(ep, ep->token);
+
+ tid = getNextNonSpaceToken(ep, state);
+ if (tid != EJS_TOK_COLON) {
+ ejsSyntaxError(ep, 0);
+ goto err;
+ }
+
+ if (flags & EJS_FLAGS_EXE) {
+ /* FUTURE OPT -- can we optimize this. We are double accessing id
+ with the Put below. Should we be using this or ejsSetProperty
+ */
+ if (ejsCreatePropertyMethod(ep, obj, name) == 0) {
+ ejsMemoryError(ep);
+ goto err;
+ }
+ }
+
+ if (ejsParse(ep, EJS_STATE_RELEXP, flags) < 0) {
+ goto err;
+ }
+ if (flags & EJS_FLAGS_EXE) {
+ if (ejsSetPropertyMethod(ep, obj, name, ep->result) == 0) {
+ ejsMemoryError(ep);
+ goto err;
+ }
+ }
+ mprFree(name);
+ name = 0;
+
+ tid = getNextNonSpaceToken(ep, state);
+
+ } while (tid == EJS_TOK_COMMA);
+
+ if (tid != EJS_TOK_RBRACE) {
+ ejsSyntaxError(ep, 0);
+ goto err;
+ }
+
+ if (flags & EJS_FLAGS_EXE) {
+ ejsMakeObjLive(obj, 1);
+ ejsWriteVar(ep, ep->result, obj, EJS_SHALLOW_COPY);
+ }
+
+done:
+ ejsMakeObjPermanent(saveObj, saveObjPerm);
+ ejsMakeObjPermanent(ejsGetVarPtr(saveProperty), savePropPerm);
+
+ ep->currentObj = saveObj;
+ ep->currentProperty = saveProperty;
+
+ if (obj) {
+ ejsFreeVar(ep, obj);
+ }
+ return state;
+
+err:
+ mprFree(name);
+ state = EJS_STATE_ERR;
+ goto done;
+}
+
+/******************************************************************************/
+
+static int parseArrayLiteral(Ejs *ep, int state, int flags, char *id)
+{
+ EjsProperty *saveProperty;
+ EjsVar *saveObj;
+ EjsVar *obj;
+ int saveObjPerm, savePropPerm, tid;
+
+ saveObj = ep->currentObj;
+ saveProperty = ep->currentProperty;
+
+ saveObjPerm = ejsMakeObjPermanent(saveObj, 1);
+ savePropPerm = ejsMakeObjPermanent(ejsGetVarPtr(saveProperty), 1);
+
+ if (flags & EJS_FLAGS_EXE) {
+ obj = ejsCreateArray(ep, 0);
+ if (obj == 0) {
+ ejsMemoryError(ep);
+ goto err;
+ }
+ mprAssert(! ejsObjIsCollectable(obj));
+
+ } else {
+ obj = 0;
+ }
+
+ do {
+ if (ejsParse(ep, EJS_STATE_RELEXP, flags) < 0) {
+ goto err;
+ }
+ if (flags & EJS_FLAGS_EXE) {
+ /* MOB _- should this be put[array.length] */
+ if (ejsAddArrayElt(ep, obj, ep->result, EJS_SHALLOW_COPY) == 0) {
+ goto err;
+ }
+ }
+
+ tid = getNextNonSpaceToken(ep, state);
+
+ } while (tid == EJS_TOK_COMMA);
+
+ if (tid != EJS_TOK_RBRACKET) {
+ ejsSyntaxError(ep, "Missing right bracket");
+ goto err;
+ }
+
+ if (flags & EJS_FLAGS_EXE) {
+ ejsMakeObjLive(obj, 1);
+ ejsWriteVar(ep, ep->result, obj, EJS_SHALLOW_COPY);
+ }
+
+done:
+ ejsMakeObjPermanent(saveObj, saveObjPerm);
+ ejsMakeObjPermanent(ejsGetVarPtr(saveProperty), savePropPerm);
+
+ ep->currentObj = saveObj;
+ ep->currentProperty = saveProperty;
+
+ ejsFreeVar(ep, obj);
+ return state;
+
+err:
+ state = EJS_STATE_ERR;
+ goto done;
+}
+
+/******************************************************************************/
+/*
+ * Create a property.
+ */
+
+/*
+MOB -- simplify this. Enforce ep->currentObj to be always set.
+Then we can delete this and just call
+
+ ejsCreatePropertyMethod(ep->currentObj, id);
+*/
+//XX
+static int createProperty(Ejs *ep, EjsVar **objp, const char *id, int state)
+{
+ EjsVar *obj, *vp;
+
+ mprAssert(id && *id);
+ mprAssert(objp);
+
+ /*
+ * Determine the variable scope to use for the property.
+ * Standard says: "var x" means declare locally.
+ * "x = 2" means declare globally if x is undefined.
+ */
+ if (ep->currentObj) {
+ if (ep->currentObj->type != EJS_TYPE_OBJECT) {
+ ejsSyntaxError(ep, "Reference is not an object");
+ return EJS_STATE_ERR;
+ }
+ obj = ep->currentObj;
+
+ } else {
+ /* MOB -- we should never be doing this here. ep->currentObj should
+ always be set already */
+ obj = (state == EJS_STATE_DEC) ? ep->local : ep->global;
+ }
+ mprAssert(obj);
+
+ vp = ejsCreatePropertyMethod(ep, obj, id);
+ if (vp == 0) {
+ if (!ep->gotException) {
+ ejsMemoryError(ep);
+ }
+ return EJS_STATE_ERR;
+ }
+
+ *objp = obj;
+ return state;
+}
+
+/******************************************************************************/
+/*
+ * Update a property.
+ *
+ * Return with ep->currentProperty updated to point to the property.
+ */
+
+static int updateProperty(Ejs *ep, EjsVar *obj, const char *id, int state,
+ EjsVar *value)
+{
+ EjsVar *vp;
+
+ /*
+ * MOB -- do ready-only check here
+ */
+ vp = ejsSetPropertyMethod(ep, obj, id, value);
+ if (vp == 0) {
+ ejsMemoryError(ep);
+ return EJS_STATE_ERR;
+ }
+ ep->currentProperty = ejsGetPropertyPtr(vp);
+
+ obj->objectState->dirty = 1;
+
+ return state;
+}
+
+/******************************************************************************/
+/*
+ * Local vars
+ */
+
+typedef struct ParseCond {
+ EjsVar lhs, rhs;
+ int tid, operator;
+} ParseCond;
+
+/*
+ * Parse conditional expression (relational ops separated by ||, &&)
+ */
+
+static int parseCond(Ejs *ep, int state, int flags)
+{
+ ParseCond *sp;
+
+ if ((sp = pushFrame(ep, sizeof(ParseCond))) == 0) {
+ return EJS_STATE_ERR;
+ }
+
+ mprAssert(ep);
+
+ if (flags & EJS_FLAGS_EXE) {
+ ejsClearVar(ep, ep->result);
+ }
+
+ sp->lhs.type = sp->rhs.type = EJS_TYPE_UNDEFINED;
+ sp->lhs.objectState = sp->rhs.objectState = 0;
+ sp->lhs.allocatedData = sp->rhs.allocatedData = 0;
+
+ ejsSetVarName(ep, &sp->lhs, "lhs");
+ ejsSetVarName(ep, &sp->rhs, "rhs");
+
+ sp->operator = 0;
+
+ do {
+ /*
+ * Recurse to handle one side of a conditional. Accumulate the
+ * left hand side and the final result in ep->result.
+ */
+ state = ejsParse(ep, EJS_STATE_RELEXP, flags);
+ if (state < 0) {
+ break;
+ }
+
+ if (flags & EJS_FLAGS_EXE) {
+ if (sp->operator > 0) {
+ /*
+ * FUTURE -- does not do precedence
+ */
+ ejsWriteVar(ep, &sp->rhs, ep->result, EJS_SHALLOW_COPY);
+ if (evalCond(ep, &sp->lhs, sp->operator, &sp->rhs) < 0) {
+ state = EJS_STATE_ERR;
+ break;
+ }
+ /* Result left in ep->result */
+ /* MOB */
+ if (sp->lhs.type == EJS_TYPE_OBJECT) {
+ mprAssert(sp->lhs.objectState->alive == 0);
+ }
+ if (sp->rhs.type == EJS_TYPE_OBJECT) {
+ mprAssert(sp->rhs.objectState->alive == 0);
+ }
+ }
+ }
+
+ sp->tid = ejsLexGetToken(ep, state);
+ if (sp->tid == EJS_TOK_LOGICAL) {
+ sp->operator = (int) *ep->token;
+
+ } else if (sp->tid == EJS_TOK_RPAREN || sp->tid == EJS_TOK_SEMI) {
+ ejsLexPutbackToken(ep, sp->tid, ep->token);
+ state = EJS_STATE_COND_DONE;
+ break;
+
+ } else {
+ ejsLexPutbackToken(ep, sp->tid, ep->token);
+ }
+
+ if (flags & EJS_FLAGS_EXE) {
+ ejsWriteVar(ep, &sp->lhs, ep->result, EJS_SHALLOW_COPY);
+ }
+
+ } while (state == EJS_STATE_RELEXP_DONE);
+
+ ejsClearVar(ep, &sp->lhs);
+ ejsClearVar(ep, &sp->rhs);
+
+ popFrame(ep, sizeof(ParseCond));
+
+ return state;
+}
+
+/******************************************************************************/
+/*
+ * Parse variable declaration list. Declarations can be of the following forms:
+ * var x;
+ * var x, y, z;
+ * var x = 1 + 2 / 3, y = 2 + 4;
+ * var x = { property: value, property: value ... };
+ * var x = [ property: value, property: value ... ];
+ *
+ * We set the variable to NULL if there is no associated assignment.
+ */
+
+static int parseDeclaration(Ejs *ep, int state, int flags)
+{
+ int tid;
+
+ mprAssert(ep);
+
+ do {
+ if ((tid = ejsLexGetToken(ep, state)) != EJS_TOK_ID) {
+ ejsSyntaxError(ep, 0);
+ return EJS_STATE_ERR;
+ }
+ ejsLexPutbackToken(ep, tid, ep->token);
+
+ /*
+ * Parse the entire assignment or simple identifier declaration
+ */
+ if (ejsParse(ep, EJS_STATE_DEC, flags) != EJS_STATE_DEC_DONE) {
+ return EJS_STATE_ERR;
+ }
+
+ /*
+ * Peek at the next token, continue if comma seen
+ * Stop on ";" or "in" which is used in a "for (var x in ..."
+ */
+ tid = ejsLexGetToken(ep, state);
+
+ if (tid == EJS_TOK_SEMI) {
+ return EJS_STATE_DEC_LIST_DONE;
+
+ } else if (tid == EJS_TOK_IN) {
+ ejsLexPutbackToken(ep, tid, ep->token);
+ return EJS_STATE_DEC_LIST_DONE;
+
+ } else if (flags & EJS_FLAGS_CLASS_DEC &&
+ (tid == EJS_TOK_LBRACE || tid == EJS_TOK_EXTENDS)) {
+ ejsLexPutbackToken(ep, tid, ep->token);
+ return EJS_STATE_DEC_LIST_DONE;
+
+ } else if (tid == EJS_TOK_RPAREN && flags & EJS_FLAGS_CATCH) {
+ ejsLexPutbackToken(ep, tid, ep->token);
+ return EJS_STATE_DEC_LIST_DONE;
+
+ } else if (tid != EJS_TOK_COMMA) {
+ ejsSyntaxError(ep, 0);
+ return EJS_STATE_ERR;
+ }
+
+ } while (tid == EJS_TOK_COMMA);
+
+ if (tid != EJS_TOK_SEMI) {
+ ejsSyntaxError(ep, 0);
+ return EJS_STATE_ERR;
+ }
+ return EJS_STATE_DEC_LIST_DONE;
+}
+
+/******************************************************************************/
+/*
+ * Local vars
+ */
+
+typedef struct ParseExpr {
+ EjsVar lhs, rhs;
+ int rel, tid, unaryMinus;
+} ParseExpr;
+
+/*
+ * Parse expression (leftHandSide operator rightHandSide)
+ */
+
+static int parseExpr(Ejs *ep, int state, int flags)
+{
+ ParseExpr *sp;
+
+ mprAssert(ep);
+
+ if ((sp = pushFrame(ep, sizeof(ParseExpr))) == 0) {
+ return EJS_STATE_ERR;
+ }
+
+ if (flags & EJS_FLAGS_EXE) {
+ ejsClearVar(ep, ep->result);
+ }
+
+ sp->lhs.type = sp->rhs.type = EJS_TYPE_UNDEFINED;
+ sp->lhs.objectState = sp->rhs.objectState = 0;
+ sp->lhs.allocatedData = sp->rhs.allocatedData = 0;
+
+ ejsSetVarName(ep, &sp->lhs, "lhs");
+ ejsSetVarName(ep, &sp->rhs, "rhs");
+
+ sp->rel = 0;
+ sp->tid = 0;
+ sp->unaryMinus = 0;
+
+ do {
+ /*
+ * This loop will handle an entire expression list. We call parse
+ * to evalutate each term which returns the result in ep->result.
+ */
+ if (sp->tid == EJS_TOK_LOGICAL) {
+ state = ejsParse(ep, EJS_STATE_RELEXP, flags);
+ if (state < 0) {
+ break;
+ }
+ } else {
+ sp->tid = ejsLexGetToken(ep, state);
+ if (sp->tid == EJS_TOK_EXPR && (int) *ep->token == EJS_EXPR_MINUS) {
+ sp->unaryMinus = 1;
+
+ } else {
+ ejsLexPutbackToken(ep, sp->tid, ep->token);
+ }
+
+ state = ejsParse(ep, EJS_STATE_EXPR, flags);
+ if (state < 0) {
+ break;
+ }
+ }
+
+ if (flags & EJS_FLAGS_EXE) {
+ if (sp->unaryMinus) {
+ switch (ep->result->type) {
+ default:
+ case EJS_TYPE_UNDEFINED:
+ case EJS_TYPE_NULL:
+ case EJS_TYPE_STRING_CMETHOD:
+ case EJS_TYPE_CMETHOD:
+ case EJS_TYPE_METHOD:
+ case EJS_TYPE_PTR:
+ case EJS_TYPE_OBJECT:
+ case EJS_TYPE_STRING:
+ case EJS_TYPE_BOOL:
+ ejsError(ep, EJS_SYNTAX_ERROR, "Invalid unary minus");
+ state = EJS_STATE_ERR;
+ break;
+
+#if BLD_FEATURE_FLOATING_POINT
+ case EJS_TYPE_FLOAT:
+ ep->result->floating = - ep->result->floating;
+ break;
+#endif
+
+ case EJS_TYPE_INT:
+ ep->result->integer = - ep->result->integer;
+ break;
+
+#if BLD_FEATURE_INT64
+ case EJS_TYPE_INT64:
+ ep->result->integer64 = - ep->result->integer64;
+ break;
+#endif
+ }
+ }
+ sp->unaryMinus = 0;
+
+ if (sp->rel > 0) {
+ ejsWriteVar(ep, &sp->rhs, ep->result, EJS_SHALLOW_COPY);
+ if (sp->tid == EJS_TOK_LOGICAL) {
+ if (evalCond(ep, &sp->lhs, sp->rel, &sp->rhs) < 0) {
+ state = EJS_STATE_ERR;
+ break;
+ }
+ } else {
+ if (evalExpr(ep, &sp->lhs, sp->rel, &sp->rhs) < 0) {
+ state = EJS_STATE_ERR;
+ break;
+ }
+ }
+ }
+ /* MOB */
+ if (sp->lhs.type == EJS_TYPE_OBJECT) {
+ ejsMakeObjLive(&sp->lhs, 0);
+ mprAssert(sp->lhs.objectState->alive == 0);
+ }
+ if (sp->rhs.type == EJS_TYPE_OBJECT) {
+ ejsMakeObjLive(&sp->rhs, 0);
+ mprAssert(sp->rhs.objectState->alive == 0);
+ }
+ }
+
+ if ((sp->tid = ejsLexGetToken(ep, state)) == EJS_TOK_EXPR ||
+ sp->tid == EJS_TOK_INC_DEC || sp->tid == EJS_TOK_LOGICAL) {
+ sp->rel = (int) *ep->token;
+ ejsWriteVar(ep, &sp->lhs, ep->result, EJS_SHALLOW_COPY);
+
+ } else {
+ ejsLexPutbackToken(ep, sp->tid, ep->token);
+ state = EJS_STATE_RELEXP_DONE;
+ }
+
+ } while (state == EJS_STATE_EXPR_DONE);
+
+ ejsClearVar(ep, &sp->lhs);
+ ejsClearVar(ep, &sp->rhs);
+
+ popFrame(ep, sizeof(ParseExpr));
+
+ return state;
+}
+
+/******************************************************************************/
+/*
+ * Local vars
+ */
+
+typedef struct ParseForIn {
+ EjsInput *endScript, *bodyScript;
+ EjsProperty *pp, *nextp;
+ EjsVar *iteratorVar, *setVar, *vp;
+ int forFlags, tid;
+} ParseForIn;
+
+/*
+ * Parse the "for ... in" statement. Format for the statement is:
+ *
+ * for [each] (var varName in expression) {
+ * body;
+ * }
+ */
+
+static int parseForIn(Ejs *ep, int state, int flags, int each)
+{
+ ParseForIn *sp;
+
+ mprAssert(ep);
+
+ if ((sp = pushFrame(ep, sizeof(ParseForIn))) == 0) {
+ return EJS_STATE_ERR;
+ }
+
+ sp->setVar = 0;
+ sp->iteratorVar = 0;
+ sp->bodyScript = 0;
+ sp->endScript = 0;
+
+ sp->tid = ejsLexGetToken(ep, state);
+ if (sp->tid != EJS_TOK_ID && sp->tid != EJS_TOK_VAR) {
+ ejsSyntaxError(ep, 0);
+ goto err;
+ }
+ ejsLexPutbackToken(ep, sp->tid, ep->token);
+
+ state = ejsParse(ep, EJS_STATE_EXPR, EJS_FLAGS_FORIN | flags);
+ if (state < 0) {
+ goto done;
+ }
+ if (flags & EJS_FLAGS_EXE) {
+ if (ep->currentProperty == 0) {
+ ejsSyntaxError(ep, 0);
+ goto err;
+ }
+ sp->iteratorVar = &ep->currentProperty->var;
+ } else {
+ sp->iteratorVar = 0;
+ }
+
+ if (ejsLexGetToken(ep, state) != EJS_TOK_IN) {
+ ejsSyntaxError(ep, 0);
+ goto err;
+ }
+
+ /*
+ * Get the set
+ */
+ sp->tid = ejsLexGetToken(ep, state);
+ if (sp->tid != EJS_TOK_ID) {
+ ejsSyntaxError(ep, 0);
+ goto err;
+ }
+ ejsLexPutbackToken(ep, sp->tid, ep->token);
+
+ state = ejsParse(ep, EJS_STATE_EXPR, flags);
+ if (state < 0) {
+ goto done;
+ }
+
+ if ((flags & EJS_FLAGS_EXE) &&
+ (ep->result == 0 || ep->result->type == EJS_TYPE_UNDEFINED)) {
+ ejsError(ep, EJS_REFERENCE_ERROR, "Can't access array or object");
+ goto err;
+ }
+
+ if (ejsLexGetToken(ep, state) != EJS_TOK_RPAREN) {
+ ejsSyntaxError(ep, 0);
+ goto err;
+ }
+
+ sp->setVar = ejsDupVar(ep, ep->result, EJS_SHALLOW_COPY);
+
+ sp->bodyScript = getInputStruct(ep);
+
+ /*
+ * Parse the body and remember the end of the body script
+ */
+ sp->forFlags = flags & ~EJS_FLAGS_EXE;
+ ejsLexSaveInputState(ep, sp->bodyScript);
+
+ state = ejsParse(ep, EJS_STATE_STMT, sp->forFlags);
+ if (state < 0) {
+ goto done;
+ }
+
+ sp->endScript = getInputStruct(ep);
+ ejsInitInputState(sp->endScript);
+ ejsLexSaveInputState(ep, sp->endScript);
+
+ /*
+ * Enumerate the properties
+ */
+ if (flags & EJS_FLAGS_EXE) {
+ if (sp->setVar->type == EJS_TYPE_OBJECT) {
+
+ sp->setVar->objectState->preventDeleteProp = 1;
+
+ sp->pp = ejsGetFirstProperty(sp->setVar, 0);
+ while (sp->pp) {
+ sp->nextp = ejsGetNextProperty(sp->pp, 0);
+ if (! sp->pp->dontEnumerate && !sp->pp->delayedDelete) {
+ if (each) {
+ sp->vp = ejsWriteVar(ep, sp->iteratorVar,
+ ejsGetVarPtr(sp->pp), EJS_SHALLOW_COPY);
+ } else {
+ sp->vp = ejsWriteVarAsString(ep, sp->iteratorVar,
+ sp->pp->name);
+ }
+ if (sp->vp == 0) {
+ ejsError(ep, EJS_MEMORY_ERROR,
+ "Can't write to variable");
+ goto err;
+ }
+
+ ejsLexRestoreInputState(ep, sp->bodyScript);
+
+ state = ejsParse(ep, EJS_STATE_STMT, flags);
+
+ if (state < 0) {
+ if (sp->setVar->objectState) {
+ sp->setVar->objectState->preventDeleteProp = 0;
+ }
+ goto done;
+ }
+ }
+ sp->pp = sp->nextp;
+ }
+
+ /*
+ * Process delayed deletes
+ */
+ if (sp->setVar->objectState) {
+ sp->setVar->objectState->preventDeleteProp = 0;
+ if (sp->setVar->objectState->delayedDeleteProp) {
+ sp->pp = ejsGetFirstProperty(sp->setVar, 0);
+ while (sp->pp) {
+ sp->nextp = ejsGetNextProperty(sp->pp, 0);
+ if (sp->pp->delayedDelete) {
+ ejsDeleteProperty(ep, sp->setVar, sp->pp->name);
+ }
+ sp->pp = sp->nextp;
+ }
+ sp->setVar->objectState->delayedDeleteProp = 0;
+ }
+ }
+
+ } else {
+ ejsError(ep, EJS_REFERENCE_ERROR,
+ "Variable to iterate over is not an array or object");
+ goto err;
+ }
+ }
+
+ ejsLexRestoreInputState(ep, sp->endScript);
+
+done:
+ if (sp->endScript) {
+ ejsLexFreeInputState(ep, sp->endScript);
+ ejsLexFreeInputState(ep, sp->bodyScript);
+ }
+
+ if (sp->bodyScript) {
+ freeInputStruct(ep, sp->bodyScript);
+ }
+ if (sp->endScript) {
+ freeInputStruct(ep, sp->endScript);
+ }
+
+ if (sp->setVar) {
+ ejsFreeVar(ep, sp->setVar);
+ }
+
+ popFrame(ep, sizeof(ParseForIn));
+
+ return state;
+
+err:
+ state = EJS_STATE_ERR;
+ goto done;
+}
+
+/******************************************************************************/
+/*
+ * Parse the for statement. Format for the expression is:
+ *
+ * for (initial; condition; incr) {
+ * body;
+ * }
+ */
+
+static int parseRegFor(Ejs *ep, int state, int flags)
+{
+ EjsInput *condScript, *endScript, *bodyScript, *incrScript;
+
+ endScript = getInputStruct(ep);
+ bodyScript = getInputStruct(ep);
+ incrScript = getInputStruct(ep);
+ condScript = getInputStruct(ep);
+
+ ejsInitInputState(endScript);
+ ejsInitInputState(bodyScript);
+ ejsInitInputState(incrScript);
+ ejsInitInputState(condScript);
+
+ state = parseForInner(ep, state, flags,
+ condScript, incrScript, bodyScript, endScript);
+
+ ejsLexFreeInputState(ep, condScript);
+ ejsLexFreeInputState(ep, incrScript);
+ ejsLexFreeInputState(ep, endScript);
+ ejsLexFreeInputState(ep, bodyScript);
+
+ freeInputStruct(ep, condScript);
+ freeInputStruct(ep, incrScript);
+ freeInputStruct(ep, endScript);
+ freeInputStruct(ep, bodyScript);
+
+ return state;
+}
+
+/******************************************************************************/
+
+static int parseForInner(Ejs *ep, int state, int flags, EjsInput *condScript,
+ EjsInput *incrScript, EjsInput *bodyScript, EjsInput *endScript)
+{
+ int forFlags, cond, rs;
+
+ mprAssert(ep);
+
+ /*
+ * Evaluate the for loop initialization statement
+ */
+ if ((state = ejsParse(ep, EJS_STATE_STMT, flags)) < 0) {
+ return state;
+ }
+
+ /*
+ * The first time through, we save the current input context just prior
+ * to each step: prior to the conditional, the loop increment and
+ * the loop body.
+ */
+ ejsLexSaveInputState(ep, condScript);
+ if ((rs = ejsParse(ep, EJS_STATE_COND, flags)) < 0) {
+ return rs;
+ }
+
+ cond = (ep->result->boolean != 0);
+
+ if (ejsLexGetToken(ep, state) != EJS_TOK_SEMI) {
+ ejsSyntaxError(ep, 0);
+ return EJS_STATE_ERR;
+ }
+
+ /*
+ * Don't execute the loop increment statement or the body
+ * first time.
+ */
+ forFlags = flags & ~EJS_FLAGS_EXE;
+ ejsLexSaveInputState(ep, incrScript);
+ if ((rs = ejsParse(ep, EJS_STATE_EXPR, forFlags)) < 0) {
+ return rs;
+ }
+
+ if (ejsLexGetToken(ep, state) != EJS_TOK_RPAREN) {
+ ejsSyntaxError(ep, 0);
+ return EJS_STATE_ERR;
+ }
+
+ /*
+ * Parse the body and remember the end of the body script
+ */
+ ejsLexSaveInputState(ep, bodyScript);
+ if ((rs = ejsParse(ep, EJS_STATE_STMT, forFlags)) < 0) {
+ return rs;
+ }
+ ejsLexSaveInputState(ep, endScript);
+
+ /*
+ * Now actually do the for loop. Note loop has been rotated
+ */
+ while (cond && (flags & EJS_FLAGS_EXE)) {
+ /*
+ * Evaluate the body
+ */
+ ejsLexRestoreInputState(ep, bodyScript);
+
+ if ((rs = ejsParse(ep, EJS_STATE_STMT, flags)) < 0) {
+ return rs;
+ }
+
+ /*
+ * Evaluate the increment script
+ */
+ ejsLexRestoreInputState(ep, incrScript);
+ if ((rs = ejsParse(ep, EJS_STATE_EXPR, flags)) < 0) {
+ return rs;
+ }
+ /*
+ * Evaluate the condition
+ */
+ ejsLexRestoreInputState(ep, condScript);
+ if ((rs = ejsParse(ep, EJS_STATE_COND, flags)) < 0) {
+ return 0;
+ }
+ mprAssert(ep->result->type == EJS_TYPE_BOOL);
+ cond = (ep->result->boolean != 0);
+ }
+
+ ejsLexRestoreInputState(ep, endScript);
+
+ return state;
+}
+
+/******************************************************************************/
+/*
+ * Create the bare class object
+ */
+
+static int createClass(Ejs *ep, EjsVar *obj, const char *className,
+ EjsVar *baseClass)
+{
+ EjsVar *classObj, *existingClass;
+
+ existingClass = ejsGetClass(ep, obj, className);
+ if (existingClass) {
+ /*
+ * We allow partial clases and method redefinition
+ * FUTURE -- should prevent this if the class is sealed.
+ * DISABLED Error message and return OK.
+ */
+ /* ejsError(ep, EJS_EVAL_ERROR, "Can't create class %s", className); */
+ return 0;
+ }
+
+ if (baseClass == 0) {
+ baseClass = ejsGetClass(ep, ep->service->globalClass, "Object");
+ mprAssert(baseClass);
+ }
+
+ classObj = ejsCreateSimpleClass(ep, baseClass, className);
+ if (classObj == 0) {
+ ejsMemoryError(ep);
+ return -1;
+ }
+ mprAssert(! ejsObjIsCollectable(classObj));
+
+ ep->currentProperty = ejsSetPropertyAndFree(ep, obj, className, classObj);
+ mprAssert(ep->currentProperty);
+
+ if (ep->currentProperty == 0) {
+ return -1;
+ }
+
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * Local vars for parseTry
+ */
+
+typedef struct ParseTry {
+ EjsVar *exception;
+ int tid, caught, rs, catchFlags;
+} ParseTry;
+
+/*
+ * Parse try block
+ *
+ * try {}
+ */
+
+static int parseTry(Ejs *ep, int state, int flags)
+{
+ ParseTry *sp;
+
+ if ((sp = pushFrame(ep, sizeof(ParseTry))) == 0) {
+ return EJS_STATE_ERR;
+ }
+
+ mprAssert(ep);
+
+ sp->caught = 0;
+ sp->exception = 0;
+ sp->catchFlags = flags;
+
+ /*
+ * Execute the code in the try block
+ */
+ sp->rs = ejsParse(ep, EJS_STATE_STMT, flags | EJS_FLAGS_TRY);
+ if (sp->rs < 0) {
+ if (sp->rs == EJS_STATE_ERR) {
+ sp->exception = ejsDupVar(ep, ep->result, EJS_SHALLOW_COPY);
+ if (sp->exception == 0) {
+ ejsMemoryError(ep);
+ goto err;
+ }
+ } else {
+ state = sp->rs;
+ goto done;
+ }
+
+ } else {
+ sp->catchFlags = flags & ~EJS_FLAGS_EXE;
+ }
+
+ /*
+ * On success path or when an exception is caught, we must parse all
+ * catch and finally blocks.
+ */
+ sp->tid = getNextNonSpaceToken(ep, state);
+
+ if (sp->tid == EJS_TOK_CATCH) {
+
+ ep->gotException = 0;
+
+ sp->tid = getNextNonSpaceToken(ep, state);
+
+ if (sp->tid == EJS_TOK_LBRACE) {
+ /*
+ * Unqualified "catch "
+ */
+ ejsLexPutbackToken(ep, sp->tid, ep->token);
+ if (ejsParse(ep, EJS_STATE_STMT, sp->catchFlags) >= 0) {
+ sp->caught++;
+ }
+
+ } else if (sp->tid == EJS_TOK_LPAREN) {
+
+ /*
+ * Qualified "catch (variable) "
+ */
+ if ((sp->rs = ejsParse(ep, EJS_STATE_DEC_LIST,
+ sp->catchFlags | EJS_FLAGS_CATCH)) < 0) {
+ ejsSyntaxError(ep, "Bad catch statement");
+ state = sp->rs;
+ goto done;
+ }
+
+ sp->tid = getNextNonSpaceToken(ep, state);
+ if (sp->tid != EJS_TOK_RPAREN) {
+ ejsSyntaxError(ep, 0);
+ goto err;
+ }
+
+ if (sp->catchFlags & EJS_FLAGS_EXE) {
+ if (ep->currentProperty == 0) {
+ ejsError(ep, EJS_EVAL_ERROR, "Can't define catch variable");
+ goto err;
+ }
+
+ /*
+ * Set the catch variable
+ */
+ if (ejsWriteVar(ep,
+ ejsGetVarPtr(ep->currentProperty), sp->exception,
+ EJS_SHALLOW_COPY) == 0) {
+ ejsError(ep, EJS_EVAL_ERROR, "Can't update catch variable");
+ goto err;
+ }
+ }
+
+ /*
+ * Parse the catch block
+ */
+ if ((sp->rs = ejsParse(ep, EJS_STATE_STMT, sp->catchFlags)) < 0) {
+ state = sp->rs;
+ goto done;
+ }
+ sp->caught++;
+ ep->gotException = 0;
+ }
+ sp->tid = getNextNonSpaceToken(ep, state);
+ }
+
+ /*
+ * Parse the finally block
+ */
+ if (sp->tid == EJS_TOK_FINALLY) {
+ if (ejsParse(ep, EJS_STATE_STMT, flags) < 0) {
+ goto err;
+ }
+ } else {
+ ejsLexPutbackToken(ep, sp->tid, ep->token);
+ }
+
+ /*
+ * Set the exception value
+ */
+ if (sp->exception && !sp->caught) {
+ ejsWriteVar(ep, ep->result, sp->exception, EJS_SHALLOW_COPY);
+ goto err;
+ }
+
+ state = EJS_STATE_STMT_DONE;
+
+done:
+ if (sp->exception) {
+ ejsFreeVar(ep, sp->exception);
+ }
+
+ popFrame(ep, sizeof(ParseTry));
+ return state;
+
+
+err:
+ state = EJS_STATE_ERR;
+ goto done;
+}
+
+/******************************************************************************/
+/*
+ * Parse throw statement
+ *
+ * throw expression
+ */
+
+static int parseThrow(Ejs *ep, int state, int flags)
+{
+ int rc;
+
+ mprAssert(ep);
+
+ if ((rc = ejsParse(ep, EJS_STATE_EXPR, flags)) < 0) {
+ return rc;
+ }
+
+
+ if (flags & EJS_FLAGS_EXE) {
+ /*
+ * We have thrown the exception so set the state to ERR
+ */
+ ep->gotException = 1;
+ return EJS_STATE_ERR;
+ }
+ return state;
+}
+
+/******************************************************************************/
+/*
+ * Parse a class and module declaration
+ *
+ * class <name> [extends baseClass] {
+ * [public | private | ... ] var declarations ...
+ * [constructor] function declarations ...
+ * }
+ *
+ * Modules are identical except declared with a "module" instead of
+ * "class". Modules cannot be instantiated and are used for mixins.
+ *
+ */
+
+static int parseClass(Ejs *ep, int state, int flags)
+{
+ int originalToken, tid, fid;
+
+ mprAssert(ep);
+
+ originalToken = ep->tid;
+
+ /*
+ * Parse "class Name [extends BaseClass]"
+ */
+ if (ejsParse(ep, EJS_STATE_DEC_LIST, flags | EJS_FLAGS_CLASS_DEC) < 0) {
+ return EJS_STATE_ERR;
+ }
+
+ tid = getNextNonSpaceToken(ep, state);
+
+ if (tid != EJS_TOK_LBRACE) {
+ return EJS_STATE_ERR;
+ }
+
+ /*
+ * After parsing the class body, ep->local will contain the actual
+ * class/module object. So, we save ep->local by creating a new block.
+ */
+ if (flags & EJS_FLAGS_EXE) {
+ fid = ejsSetBlock(ep, ejsGetVarPtr(ep->currentProperty));
+ ejsSetVarName(ep, ep->local, ep->currentProperty->name);
+
+ } else {
+ fid = -1;
+ }
+
+ /* FUTURE -- should prevent modules from being instantiated */
+
+ /*
+ * Parse class body
+ */
+ do {
+ state = ejsParse(ep, EJS_STATE_STMT, flags);
+ if (state < 0) {
+ if (fid >= 0) {
+ ejsCloseBlock(ep, fid);
+ }
+ return state;
+ }
+ tid = getNextNonSpaceToken(ep, state);
+ if (tid == EJS_TOK_RBRACE) {
+ break;
+ }
+ ejsLexPutbackToken(ep, tid, ep->token);
+
+ } while (state >= 0);
+
+ if (fid >= 0) {
+ ejsCloseBlock(ep, fid);
+ }
+
+ if (tid != EJS_TOK_RBRACE) {
+ ejsSyntaxError(ep, 0);
+ state = EJS_STATE_ERR;
+ }
+
+ return state;
+}
+
+/******************************************************************************/
+/*
+ * Parse a function declaration
+ */
+
+static int parseFunction(Ejs *ep, int state, int flags)
+{
+ EjsInput *endScript, *bodyScript;
+ EjsProperty *pp;
+ EjsVar *func, *funcProp, *currentObj, *vp, *baseClass;
+ char *procName;
+ int varFlags, len, tid, bodyFlags, innerState;
+
+ mprAssert(ep);
+
+ func = 0;
+ varFlags = 0;
+
+ /*
+ * method <name>(arg, arg, arg) { body };
+ * method name(arg, arg, arg) { body };
+ */
+
+ tid = ejsLexGetToken(ep, state);
+
+ if (tid == EJS_TOK_GET) {
+ varFlags |= EJS_GET_ACCESSOR;
+ tid = ejsLexGetToken(ep, state);
+
+ } else if (tid == EJS_TOK_SET) {
+ varFlags |= EJS_SET_ACCESSOR;
+ tid = ejsLexGetToken(ep, state);
+ }
+
+ if (tid == EJS_TOK_ID) {
+ if (varFlags & EJS_SET_ACCESSOR) {
+
+ if (mprAllocStrcat(MPR_LOC_ARGS(ep), &procName, EJS_MAX_ID + 5,
+ 0, "-set-", ep->token, 0) < 0) {
+ ejsError(ep, EJS_SYNTAX_ERROR,
+ "Name %s is too long", ep->token);
+ return EJS_STATE_ERR;
+ }
+
+ } else {
+ procName = mprStrdup(ep, ep->token);
+ }
+
+ tid = ejsLexGetToken(ep, state);
+
+ } else {
+ procName = 0;
+ }
+
+ if (tid != EJS_TOK_LPAREN) {
+ mprFree(procName);
+ ejsSyntaxError(ep, 0);
+ return EJS_STATE_ERR;
+ }
+
+ /*
+ * Hand craft the method value structure.
+ */
+ if (flags & EJS_FLAGS_EXE) {
+ func = ejsCreateMethodVar(ep, 0, 0, 0);
+ if (func == 0) {
+ mprFree(procName);
+ ejsMemoryError(ep);
+ return EJS_STATE_ERR;
+ }
+ func->flags = varFlags;
+ }
+
+ tid = ejsLexGetToken(ep, state);
+ while (tid == EJS_TOK_ID) {
+ if (flags & EJS_FLAGS_EXE) {
+ mprAddItem(func->method.args,
+ mprStrdup(func->method.args, ep->token));
+ }
+ tid = ejsLexGetToken(ep, state);
+ if (tid == EJS_TOK_RPAREN || tid != EJS_TOK_COMMA) {
+ break;
+ }
+ tid = ejsLexGetToken(ep, state);
+ }
+ if (tid != EJS_TOK_RPAREN) {
+ mprFree(procName);
+ ejsFreeVar(ep, func);
+ ejsSyntaxError(ep, 0);
+ return EJS_STATE_ERR;
+ }
+
+ /* Allow new lines before opening brace */
+ do {
+ tid = ejsLexGetToken(ep, state);
+ } while (tid == EJS_TOK_NEWLINE);
+
+ if (tid != EJS_TOK_LBRACE) {
+ mprFree(procName);
+ ejsFreeVar(ep, func);
+ ejsSyntaxError(ep, 0);
+ return EJS_STATE_ERR;
+ }
+
+ /*
+ * Register the method name early to allow for recursive
+ * method calls (see note in ECMA standard, page 71)
+ */
+ funcProp = 0;
+ if (flags & EJS_FLAGS_EXE && procName) {
+ currentObj = pickSpace(ep, 0, procName, flags | EJS_FLAGS_LOCAL);
+ pp = ejsSetProperty(ep, currentObj, procName, func);
+ if (pp == 0) {
+ ejsFreeVar(ep, func);
+ ejsMemoryError(ep);
+ return EJS_STATE_ERR;
+ }
+ funcProp = ejsGetVarPtr(pp);
+ }
+
+
+ bodyScript = getInputStruct(ep);
+
+ /*
+ * Parse the method body. Turn execute off.
+ */
+ bodyFlags = flags & ~EJS_FLAGS_EXE;
+ ejsLexSaveInputState(ep, bodyScript);
+
+ do {
+ innerState = ejsParse(ep, EJS_STATE_STMT, bodyFlags);
+ } while (innerState == EJS_STATE_STMT_DONE);
+
+ tid = ejsLexGetToken(ep, state);
+
+ if (innerState != EJS_STATE_STMT_BLOCK_DONE || tid != EJS_TOK_RBRACE) {
+ mprFree(procName);
+ ejsFreeVar(ep, func);
+ ejsLexFreeInputState(ep, bodyScript);
+ if (innerState != EJS_STATE_ERR) {
+ ejsSyntaxError(ep, 0);
+ }
+ freeInputStruct(ep, bodyScript);
+ return EJS_STATE_ERR;
+ }
+
+ if (flags & EJS_FLAGS_EXE) {
+ endScript = getInputStruct(ep);
+ ejsLexSaveInputState(ep, endScript);
+
+ /*
+ * Save the method body between the starting and ending parse
+ * positions. Overwrite the trailing '}' with a null.
+ */
+ len = endScript->scriptServp - bodyScript->scriptServp;
+ func->method.body = mprAlloc(ep, len + 1);
+ memcpy(func->method.body, bodyScript->scriptServp, len);
+
+ if (len <= 0) {
+ func->method.body[0] = '\0';
+ } else {
+ func->method.body[len - 1] = '\0';
+ }
+ ejsLexFreeInputState(ep, bodyScript);
+ ejsLexFreeInputState(ep, endScript);
+ freeInputStruct(ep, endScript);
+
+ /*
+ * If we are in an assignment, don't register the method name, rather
+ * return the method structure in the parser result.
+ */
+ if (procName) {
+ currentObj = pickSpace(ep, 0, procName, flags | EJS_FLAGS_LOCAL);
+ pp = ejsSetProperty(ep, currentObj, procName, func);
+ if (pp == 0) {
+ ejsFreeVar(ep, func);
+ ejsMemoryError(ep);
+ return EJS_STATE_ERR;
+ }
+
+ if (currentObj->objectState->className &&
+ strcmp(currentObj->objectState->className, procName) == 0) {
+ baseClass = currentObj->objectState->baseClass;
+ if (baseClass) {
+ if (strstr(func->method.body, "super(") != 0) {
+ funcProp->callsSuper = 1;
+ /*
+ * Define super() to point to the baseClass constructor
+ */
+ vp = ejsGetPropertyAsVar(ep, baseClass,
+ baseClass->objectState->className);
+ if (vp) {
+ mprAssert(vp);
+ if (ejsSetProperty(ep, currentObj, "super",
+ vp) == 0) {
+ ejsFreeVar(ep, func);
+ ejsMemoryError(ep);
+ return EJS_STATE_ERR;
+ }
+ }
+ }
+ }
+ }
+ }
+ /*
+ * Always return the function. Try for all stmts to be expressions.
+ */
+ /* MOB - rc */
+ ejsWriteVar(ep, ep->result, func, EJS_SHALLOW_COPY);
+ }
+ freeInputStruct(ep, bodyScript);
+
+ mprFree(procName);
+ ejsFreeVar(ep, func);
+
+ return state;
+}
+
+/******************************************************************************/
+/*
+ * Local vars
+ */
+
+typedef struct ParseMethod {
+ EjsProc proc, *saveProc;
+ EjsVar *saveObj, *newObj;
+ int saveObjPerm, rc;
+
+} ParseMethod;
+
+/*
+ * Parse a method name and invoke the method. See parseFunction for
+ * function declarations.
+ */
+
+static int parseMethod(Ejs *ep, int state, int flags, char *id)
+{
+ ParseMethod *sp;
+
+ if ((sp = pushFrame(ep, sizeof(ParseMethod))) == 0) {
+ return EJS_STATE_ERR;
+ }
+
+ /*
+ * Must save any current ep->proc value for the current stack frame
+ * to allow for recursive method calls.
+ */
+ sp->saveProc = (ep->proc) ? ep->proc: 0;
+
+ memset(&sp->proc, 0, sizeof(EjsProc));
+ sp->proc.procName = mprStrdup(ep, id);
+ sp->proc.fn = &ep->currentProperty->var;
+ sp->proc.args = mprCreateItemArray(ep, EJS_INC_ARGS, EJS_MAX_ARGS);
+ ep->proc = &sp->proc;
+
+#if BLD_DEBUG
+ if (strcmp(sp->proc.procName, "printv") == 0) {
+ flags |= EJS_FLAGS_TRACE_ARGS;
+ }
+#endif
+
+ if (flags & EJS_FLAGS_EXE) {
+ ejsClearVar(ep, ep->result);
+ }
+
+ if (! (flags & EJS_FLAGS_NO_ARGS)) {
+ sp->saveObj = ep->currentObj;
+ sp->saveObjPerm = ejsMakeObjPermanent(sp->saveObj, 1);
+ sp->rc = ejsParse(ep, EJS_STATE_ARG_LIST, flags);
+ ejsMakeObjPermanent(sp->saveObj, sp->saveObjPerm);
+ if (sp->rc < 0) {
+ goto err;
+ }
+ ep->currentObj = sp->saveObj;
+ }
+
+#if BLD_DEBUG
+ flags &= ~EJS_FLAGS_TRACE_ARGS;
+#endif
+
+ /*
+ * Evaluate the method if required
+ */
+ if (flags & EJS_FLAGS_EXE) {
+ if (flags & EJS_FLAGS_NEW) {
+ sp->newObj = ejsCreateObjUsingArgv(ep, ep->currentObj,
+ sp->proc.procName, sp->proc.args);
+
+ if (sp->newObj == 0) {
+ state = EJS_STATE_ERR;
+
+ } else {
+ mprAssert(! ejsObjIsCollectable(sp->newObj));
+
+ /*
+ * Return the newly created object as the result of the
+ * command. NOTE: newObj may not be an object!
+ */
+ /* MOB - rc */
+ ejsWriteVar(ep, ep->result, sp->newObj, EJS_SHALLOW_COPY);
+ if (ejsVarIsObject(sp->newObj)) {
+ ejsMakeObjLive(sp->newObj, 1);
+ mprAssert(ejsObjIsCollectable(sp->newObj));
+ mprAssert(ejsBlockInUse(sp->newObj));
+ }
+ ejsFreeVar(ep, sp->newObj);
+ }
+
+ } else {
+
+ if (evalMethod(ep, ep->currentObj, &sp->proc, flags) < 0) {
+ /* Methods must call ejsError to set exceptions */
+ state = EJS_STATE_ERR;
+ }
+ }
+ }
+
+ if (! (flags & EJS_FLAGS_NO_ARGS)) {
+ if (ejsLexGetToken(ep, state) != EJS_TOK_RPAREN) {
+ if (state != EJS_STATE_ERR) {
+ ejsSyntaxError(ep, 0);
+ }
+ state = EJS_STATE_ERR;
+ }
+ }
+
+done:
+ freeProc(ep, &sp->proc);
+ ep->proc = sp->saveProc;
+
+ popFrame(ep, sizeof(ParseMethod));
+ return state;
+
+err:
+ state = EJS_STATE_ERR;
+ goto done;
+}
+
+/******************************************************************************/
+/*
+ * Parse an identifier. This is a segment of a fully qualified variable.
+ * May come here for an initial identifier or for property names
+ * after a "." or "[...]".
+ */
+
+static int parseId(Ejs *ep, int state, int flags, char **id, int *done)
+{
+ EjsVar *null;
+ int tid;
+
+ mprFree(*id);
+ *id = mprStrdup(ep, ep->token);
+
+ if (ep->currentObj == 0) {
+ /* First identifier segement */
+ ep->currentObj = pickSpace(ep, state, *id, flags);
+ }
+
+ tid = ejsLexGetToken(ep, state);
+ if (tid == EJS_TOK_ASSIGNMENT) {
+ flags |= EJS_FLAGS_LHS;
+ }
+
+ /*
+ * Find the referenced variable and store it in currentProperty.
+ */
+ if (flags & EJS_FLAGS_EXE) {
+ ep->currentProperty = searchSpacesForProperty(ep, state,
+ ep->currentObj, *id, flags);
+
+ /*
+ * Handle properties that have been deleted inside an enumeration
+ */
+ if (ep->currentProperty && ep->currentProperty->delayedDelete) {
+ ep->currentProperty = 0;
+ }
+
+ if (ep->currentProperty &&
+ ejsVarIsMethod(&ep->currentProperty->var) &&
+ tid != EJS_TOK_LPAREN) {
+ if (ep->currentProperty->var.flags & EJS_GET_ACCESSOR) {
+ ejsLexPutbackToken(ep, tid, ep->token);
+ state = parseMethod(ep, state, flags | EJS_FLAGS_NO_ARGS, *id);
+ if (ep->flags & EJS_FLAGS_EXIT) {
+ state = EJS_STATE_RET;
+ }
+ if (state >= 0) {
+ ejsSetVarName(ep, ep->result, ep->currentProperty->name);
+ }
+ return state;
+ }
+ }
+ /*
+ * OPT. We should not have to do this always
+ */
+ updateResult(ep, state, flags, ejsGetVarPtr(ep->currentProperty));
+ }
+
+ flags &= ~EJS_FLAGS_LHS;
+
+ if (tid == EJS_TOK_LPAREN) {
+ if (ep->currentProperty == 0 && (flags & EJS_FLAGS_EXE)) {
+ ejsError(ep, EJS_REFERENCE_ERROR,
+ "Method name not defined \"%s\"", *id);
+ return EJS_STATE_ERR;
+ }
+ ejsLexPutbackToken(ep, EJS_TOK_METHOD_NAME, ep->token);
+ return state;
+ }
+
+ if (tid == EJS_TOK_PERIOD || tid == EJS_TOK_LBRACKET ||
+ tid == EJS_TOK_ASSIGNMENT || tid == EJS_TOK_INC_DEC) {
+ ejsLexPutbackToken(ep, tid, ep->token);
+ return state;
+ }
+
+ if (flags & EJS_FLAGS_CLASS_DEC) {
+ if (tid == EJS_TOK_LBRACE || tid == EJS_TOK_EXTENDS) {
+ ejsLexPutbackToken(ep, tid, ep->token);
+ return state;
+ }
+ }
+
+ if (flags & EJS_FLAGS_DELETE) {
+ if (tid == EJS_TOK_RBRACE) {
+ ejsLexPutbackToken(ep, tid, ep->token);
+ }
+ }
+
+ /*
+ * Only come here for variable access and declarations.
+ * Assignment handled elsewhere.
+ */
+ if (flags & EJS_FLAGS_EXE) {
+ if (state == EJS_STATE_DEC) {
+ /*
+ * Declare a variable. Standard allows: var x ; var x ;
+ */
+#if DISABLED
+ if (ep->currentProperty != 0) {
+ ejsError(ep, EJS_REFERENCE_ERROR,
+ "Variable already defined \"%s\"", *id);
+ return EJS_STATE_ERR;
+ }
+#endif
+ /*
+ * Create or overwrite if it already exists
+ * Set newly declared variables to the null value.
+ */
+ null = ejsCreateNullVar(ep);
+ ep->currentProperty = ejsSetPropertyAndFree(ep, ep->currentObj,
+ *id, null);
+ ejsClearVar(ep, ep->result);
+
+ } else if (flags & EJS_FLAGS_FORIN) {
+ /*
+ * This allows "for (x" when x has not yet been defined
+ */
+ if (ep->currentProperty == 0) {
+ /* MOB -- return code */
+ ep->currentProperty = ejsCreateProperty(ep,
+ ep->currentObj, *id);
+ }
+
+ } else if (ep->currentProperty == 0) {
+
+ if (ep->currentObj && ((ep->currentObj == ep->global ||
+ (ep->currentObj == ep->local)))) {
+ /*
+ * Test against currentObj and not currentObj->objectState
+ * as we must allow "i = global.x" and not allow
+ * "i = x" where x does not exist.
+ */
+ ejsError(ep, EJS_REFERENCE_ERROR,
+ "Undefined variable \"%s\"", *id);
+ return EJS_STATE_ERR;
+ }
+
+ if (flags & EJS_FLAGS_DELETE) {
+ ejsError(ep, EJS_REFERENCE_ERROR,
+ "Undefined variable \"%s\"", *id);
+ return EJS_STATE_ERR;
+ }
+ }
+ }
+ ejsLexPutbackToken(ep, tid, ep->token);
+ if (tid == EJS_TOK_RBRACKET || tid == EJS_TOK_COMMA ||
+ tid == EJS_TOK_IN) {
+ *done = 1;
+ }
+ return state;
+}
+
+/******************************************************************************/
+/*
+ * Local vars
+ */
+
+typedef struct ParseIf {
+ int ifResult, thenFlags, elseFlags, tid, rs;
+} ParseIf;
+
+/*
+ * Parse an "if" statement
+ */
+
+static int parseIf(Ejs *ep, int state, int flags, int *done)
+{
+ ParseIf *sp;
+
+ if ((sp = pushFrame(ep, sizeof(ParseIf))) == 0) {
+ return EJS_STATE_ERR;
+ }
+
+ if (state != EJS_STATE_STMT) {
+ goto err;
+ }
+ if (ejsLexGetToken(ep, state) != EJS_TOK_LPAREN) {
+ goto err;
+ }
+
+ /*
+ * Evaluate the entire condition list "(condition)"
+ */
+ if (ejsParse(ep, EJS_STATE_COND, flags) < 0) {
+ goto err;
+ }
+ if (ejsLexGetToken(ep, state) != EJS_TOK_RPAREN) {
+ goto err;
+ }
+
+ /*
+ * This is the "then" case. We need to always parse both cases and
+ * execute only the relevant case.
+ */
+ sp->ifResult = ejsVarToBoolean(ep->result);
+ if (sp->ifResult) {
+ sp->thenFlags = flags;
+ sp->elseFlags = flags & ~EJS_FLAGS_EXE;
+ } else {
+ sp->thenFlags = flags & ~EJS_FLAGS_EXE;
+ sp->elseFlags = flags;
+ }
+
+ /*
+ * Process the "then" case.
+ */
+ if ((sp->rs = ejsParse(ep, EJS_STATE_STMT, sp->thenFlags)) < 0) {
+ if (! ep->gotException) {
+ state = sp->rs;
+ goto done;
+ }
+ }
+
+ /*
+ * Check to see if there is an "else" case
+ */
+ removeNewlines(ep, state);
+ sp->tid = ejsLexGetToken(ep, state);
+ if (sp->tid != EJS_TOK_ELSE) {
+ ejsLexPutbackToken(ep, sp->tid, ep->token);
+ *done = 1;
+ if (ep->gotException) {
+ goto err;
+ }
+ goto done;
+ }
+
+ /*
+ * Process the "else" case.
+ */
+ state = ejsParse(ep, EJS_STATE_STMT, sp->elseFlags);
+
+done:
+ *done = 1;
+ if (ep->gotException) {
+ state = EJS_STATE_ERR;
+ }
+ popFrame(ep, sizeof(ParseIf));
+ return state;
+
+
+err:
+ state = EJS_STATE_ERR;
+ goto done;
+}
+
+/******************************************************************************/
+/*
+ * Parse a postix "++" or "--" statement
+ */
+
+static int parseInc(Ejs *ep, int state, int flags)
+{
+ EjsVar *one;
+
+ if (! (flags & EJS_FLAGS_EXE)) {
+ return state;
+ }
+
+ if (ep->currentProperty == 0) {
+ ejsError(ep, EJS_REFERENCE_ERROR,
+ "Undefined variable \"%s\"", ep->token);
+ return EJS_STATE_ERR;
+ }
+ one = ejsCreateIntegerVar(ep, 1);
+ if (evalExpr(ep, &ep->currentProperty->var, (int) *ep->token, one) < 0) {
+ ejsFreeVar(ep, one);
+ return EJS_STATE_ERR;
+ }
+ if (ejsWriteVar(ep, &ep->currentProperty->var, ep->result,
+ EJS_SHALLOW_COPY) < 0) {
+ ejsError(ep, EJS_IO_ERROR, "Can't write to variable");
+ ejsFreeVar(ep, one);
+ return EJS_STATE_ERR;
+ }
+ ejsFreeVar(ep, one);
+ return state;
+}
+
+/******************************************************************************/
+/*
+ * Evaluate a condition. Implements &&, ||, !. Returns with a boolean result
+ * in ep->result. Returns EJS_STATE_ERR on errors, zero if successful.
+ */
+
+static int evalCond(Ejs *ep, EjsVar *lhs, int rel, EjsVar *rhs)
+{
+ int l, r, lval;
+
+ mprAssert(rel > 0);
+
+ l = ejsVarToBoolean(lhs);
+ r = ejsVarToBoolean(rhs);
+
+ switch (rel) {
+ case EJS_COND_AND:
+ lval = l && r;
+ break;
+ case EJS_COND_OR:
+ lval = l || r;
+ break;
+ default:
+ ejsError(ep, EJS_SYNTAX_ERROR, "Bad operator %d", rel);
+ return -1;
+ }
+
+ /* MOB - rc */
+ ejsWriteVarAsBoolean(ep, ep->result, lval);
+ return 0;
+}
+
+
+/******************************************************************************/
+/*
+ * return true if this string is a valid number
+ */
+
+static int stringIsNumber(const char *s)
+{
+ char *endptr = NULL;
+
+ if (s == NULL || *s == 0) {
+ return 0;
+ }
+ /* MOB -- not ideal */
+#if BREW
+ /* MOB this should check all digits and not just the first. */
+ /* Does not support floating point - easy */
+
+ if (isdigit(*s) || (*s == '-' && isdigit(s[1]))) {
+ return 1;
+ }
+#else
+ strtod(s, &endptr);
+#endif
+ if (endptr != NULL && *endptr == 0) {
+ return 1;
+ }
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * Evaluate an operation. Returns with the result in ep->result. Returns -1
+ * on errors, otherwise zero is returned.
+ */
+
+static int evalExpr(Ejs *ep, EjsVar *lhs, int rel, EjsVar *rhs)
+{
+ EjsNum lval;
+ char *str;
+ int rc;
+
+ mprAssert(rel > 0);
+ str = 0;
+ lval = 0;
+
+ /*
+ * Type conversion. This is tricky and must be according to the standard.
+ * Only numbers (including floats) and strings can be compared. All other
+ * types are first converted to numbers by preference and if that fails,
+ * to strings.
+ *
+ * MOB -- should we do "valueOf" here also.
+ */
+ if (lhs->type == EJS_TYPE_OBJECT &&
+ (rhs->type != EJS_TYPE_OBJECT &&
+ (rhs->type != EJS_TYPE_UNDEFINED && rhs->type != EJS_TYPE_NULL))) {
+ if (ejsVarIsNumber(rhs)) {
+ if (ejsRunMethod(ep, lhs, "toValue", 0) == 0) {
+ /* MOB - rc */
+ ejsWriteVar(ep, lhs, ep->result, EJS_SHALLOW_COPY);
+ } else {
+ if (ejsRunMethod(ep, lhs, "toString", 0) == 0) {
+ /* MOB - rc */
+ ejsWriteVar(ep, lhs, ep->result, EJS_SHALLOW_COPY);
+ }
+ }
+
+ } else {
+ if (ejsRunMethod(ep, lhs, "toString", 0) == 0) {
+ /* MOB - rc */
+ ejsWriteVar(ep, lhs, ep->result, EJS_SHALLOW_COPY);
+ } else {
+ if (ejsRunMethod(ep, lhs, "toValue", 0) == 0) {
+ /* MOB - rc */
+ ejsWriteVar(ep, lhs, ep->result, EJS_SHALLOW_COPY);
+ }
+ }
+ }
+ /* Nothing more can be done */
+ }
+
+ if (rhs->type == EJS_TYPE_OBJECT &&
+ (lhs->type != EJS_TYPE_OBJECT &&
+ (lhs->type != EJS_TYPE_UNDEFINED && lhs->type != EJS_TYPE_NULL))) {
+ if (ejsVarIsNumber(lhs)) {
+ /* If LHS is number, then convert to a value first */
+ if (ejsRunMethod(ep, rhs, "toValue", 0) == 0) {
+ /* MOB - rc */
+ ejsWriteVar(ep, rhs, ep->result, EJS_SHALLOW_COPY);
+ } else {
+ if (ejsRunMethod(ep, rhs, "toString", 0) == 0) {
+ /* MOB - rc */
+ ejsWriteVar(ep, rhs, ep->result, EJS_SHALLOW_COPY);
+ }
+ }
+
+ } else {
+ /* If LHS is not a number, then convert to a string first */
+ if (ejsRunMethod(ep, rhs, "toString", 0) == 0) {
+ /* MOB - rc */
+ ejsWriteVar(ep, rhs, ep->result, EJS_SHALLOW_COPY);
+
+ } else {
+ if (ejsRunMethod(ep, rhs, "toValue", 0) == 0) {
+ /* MOB - rc */
+ ejsWriteVar(ep, rhs, ep->result, EJS_SHALLOW_COPY);
+ }
+ }
+ }
+ /* Nothing more can be done */
+ }
+
+ /*
+ * undefined and null are special, in that they don't get promoted when
+ * comparing.
+ */
+ if (rel == EJS_EXPR_EQ || rel == EJS_EXPR_NOTEQ) {
+ if (lhs->type == EJS_TYPE_UNDEFINED ||
+ rhs->type == EJS_TYPE_UNDEFINED) {
+ return evalBoolExpr(ep,
+ lhs->type == EJS_TYPE_UNDEFINED,
+ rel,
+ rhs->type == EJS_TYPE_UNDEFINED);
+ }
+
+ if (lhs->type == EJS_TYPE_NULL || rhs->type == EJS_TYPE_NULL) {
+ return evalBoolExpr(ep,
+ lhs->type == EJS_TYPE_NULL,
+ rel,
+ rhs->type == EJS_TYPE_NULL);
+ }
+ }
+
+ /*
+ * From here on, lhs and rhs may contain allocated data (strings), so
+ * we must always destroy before overwriting.
+ */
+
+ /*
+ * Only allow a few bool operations. Otherwise convert to number.
+ */
+ if (lhs->type == EJS_TYPE_BOOL && rhs->type == EJS_TYPE_BOOL &&
+ (rel != EJS_EXPR_EQ && rel != EJS_EXPR_NOTEQ &&
+ rel != EJS_EXPR_BOOL_COMP)) {
+ ejsWriteVarAsNumber(ep, lhs, ejsVarToNumber(lhs));
+ }
+
+ /*
+ * Types do not match, so try to coerce the right operand to match the left
+ * But first, try to convert a left operand that is a numeric stored as a
+ * string, into a numeric.
+ */
+ if (lhs->type != rhs->type) {
+ if (lhs->type == EJS_TYPE_STRING) {
+ if (stringIsNumber(lhs->string)) {
+ ejsWriteVarAsNumber(ep, lhs, ejsVarToNumber(lhs));
+
+ /* Examine further below */
+
+ } else {
+ /*
+ * Convert the RHS to a string
+ * MOB rc
+ */
+ str = ejsVarToString(ep, rhs);
+ ejsWriteVarAsString(ep, rhs, str);
+ }
+
+#if BLD_FEATURE_FLOATING_POINT
+ } else if (lhs->type == EJS_TYPE_FLOAT) {
+ /*
+ * Convert rhs to floating
+ */
+ ejsWriteVarAsFloat(ep, rhs, ejsVarToFloat(rhs));
+
+#endif
+#if BLD_FEATURE_INT64
+ } else if (lhs->type == EJS_TYPE_INT64) {
+ /*
+ * Convert the rhs to 64 bit
+ */
+ ejsWriteVarAsInteger64(ep, rhs, ejsVarToInteger64(rhs));
+#endif
+ } else if (lhs->type == EJS_TYPE_BOOL || lhs->type == EJS_TYPE_INT) {
+
+ if (rhs->type == EJS_TYPE_STRING) {
+ if (stringIsNumber(rhs->string)) {
+ ejsWriteVarAsNumber(ep, rhs, ejsVarToNumber(rhs));
+ } else {
+ /*
+ * Convert to lhs to a string
+ */
+ str = ejsVarToString(ep, lhs);
+ /* MOB -- rc */
+ if (str) {
+ ejsWriteVarAsString(ep, lhs, str);
+ }
+ }
+
+#if BLD_FEATURE_FLOATING_POINT
+ } else if (rhs->type == EJS_TYPE_FLOAT) {
+ /*
+ * Convert lhs to floating
+ */
+ ejsWriteVarAsFloat(ep, lhs, ejsVarToFloat(lhs));
+#endif
+
+ } else {
+ /*
+ * Forcibly convert both operands to numbers
+ */
+ ejsWriteVarAsNumber(ep, lhs, ejsVarToNumber(lhs));
+ ejsWriteVarAsNumber(ep, rhs, ejsVarToNumber(rhs));
+ }
+ }
+ }
+
+ /*
+ * We have failed to coerce the types to be the same. Special case here
+ * for undefined and null. We need to allow comparisions against these
+ * special values.
+ */
+ if (lhs->type == EJS_TYPE_UNDEFINED || lhs->type == EJS_TYPE_NULL) {
+ switch (rel) {
+ case EJS_EXPR_EQ:
+ lval = lhs->type == rhs->type;
+ break;
+ case EJS_EXPR_NOTEQ:
+ lval = lhs->type != rhs->type;
+ break;
+ case EJS_EXPR_BOOL_COMP:
+ lval = ! ejsVarToBoolean(rhs);
+ break;
+ default:
+ ejsWriteVar(ep, ep->result, rhs, EJS_SHALLOW_COPY);
+ return 0;
+ }
+ ejsWriteVarAsBoolean(ep, ep->result, lval);
+ return 0;
+ }
+
+ /*
+ * Types are the same here
+ */
+ switch (lhs->type) {
+ default:
+ case EJS_TYPE_UNDEFINED:
+ case EJS_TYPE_NULL:
+ /* Should be handled above */
+ mprAssert(0);
+ return 0;
+
+ case EJS_TYPE_STRING_CMETHOD:
+ case EJS_TYPE_CMETHOD:
+ case EJS_TYPE_METHOD:
+ case EJS_TYPE_PTR:
+ ejsWriteVarAsBoolean(ep, ep->result, 0);
+ return 0;
+
+ case EJS_TYPE_OBJECT:
+ rc = evalObjExpr(ep, lhs, rel, rhs);
+ break;
+
+ case EJS_TYPE_BOOL:
+ rc = evalBoolExpr(ep, lhs->boolean, rel, rhs->boolean);
+ break;
+
+#if BLD_FEATURE_FLOATING_POINT
+ case EJS_TYPE_FLOAT:
+ rc = evalFloatExpr(ep, lhs->floating, rel, rhs->floating);
+ break;
+#endif
+
+ case EJS_TYPE_INT:
+ rc = evalNumericExpr(ep, (EjsNum) lhs->integer, rel,
+ (EjsNum) rhs->integer);
+ break;
+
+#if BLD_FEATURE_INT64
+ case EJS_TYPE_INT64:
+ rc = evalNumericExpr(ep, (EjsNum) lhs->integer64, rel,
+ (EjsNum) rhs->integer64);
+ break;
+#endif
+
+ case EJS_TYPE_STRING:
+ rc = evalStringExpr(ep, lhs, rel, rhs);
+ }
+
+ /* MOB */
+ if (lhs->type == EJS_TYPE_OBJECT) {
+ ejsMakeObjLive(lhs, 0);
+ mprAssert(lhs->objectState->alive == 0);
+ }
+ if (rhs->type == EJS_TYPE_OBJECT) {
+ ejsMakeObjLive(rhs, 0);
+ mprAssert(rhs->objectState->alive == 0);
+ }
+
+ return rc;
+}
+
+/******************************************************************************/
+#if BLD_FEATURE_FLOATING_POINT
+/*
+ * Expressions with floating operands
+ */
+
+static int evalFloatExpr(Ejs *ep, double l, int rel, double r)
+{
+ double lval;
+ int logical;
+
+ lval = 0;
+ logical = 0;
+
+ switch (rel) {
+ case EJS_EXPR_PLUS:
+ lval = l + r;
+ break;
+ case EJS_EXPR_INC:
+ lval = l + 1;
+ break;
+ case EJS_EXPR_MINUS:
+ lval = l - r;
+ break;
+ case EJS_EXPR_DEC:
+ lval = l - 1;
+ break;
+ case EJS_EXPR_MUL:
+ lval = l * r;
+ break;
+ case EJS_EXPR_DIV:
+ lval = l / r;
+ break;
+ default:
+ logical++;
+ break;
+ }
+
+ /*
+ * Logical operators
+ */
+ if (logical) {
+
+ switch (rel) {
+ case EJS_EXPR_EQ:
+ lval = l == r;
+ break;
+ case EJS_EXPR_NOTEQ:
+ lval = l != r;
+ break;
+ case EJS_EXPR_LESS:
+ lval = (l < r) ? 1 : 0;
+ break;
+ case EJS_EXPR_LESSEQ:
+ lval = (l <= r) ? 1 : 0;
+ break;
+ case EJS_EXPR_GREATER:
+ lval = (l > r) ? 1 : 0;
+ break;
+ case EJS_EXPR_GREATEREQ:
+ lval = (l >= r) ? 1 : 0;
+ break;
+ case EJS_EXPR_BOOL_COMP:
+ lval = (r == 0) ? 1 : 0;
+ break;
+ default:
+ ejsError(ep, EJS_SYNTAX_ERROR, "Bad operator %d", rel);
+ return -1;
+ }
+ ejsWriteVarAsBoolean(ep, ep->result, lval != 0);
+
+ } else {
+ ejsWriteVarAsFloat(ep, ep->result, lval);
+ }
+ return 0;
+}
+
+#endif /* BLD_FEATURE_FLOATING_POINT */
+/******************************************************************************/
+/*
+ * Expressions with object operands
+ */
+
+static int evalObjExpr(Ejs *ep, EjsVar *lhs, int rel, EjsVar *rhs)
+{
+ int lval;
+
+ switch (rel) {
+ case EJS_EXPR_EQ:
+ lval = lhs->objectState == rhs->objectState;
+ break;
+ case EJS_EXPR_NOTEQ:
+ lval = lhs->objectState != rhs->objectState;
+ break;
+ default:
+ ejsError(ep, EJS_SYNTAX_ERROR, "Bad operator %d", rel);
+ return -1;
+ }
+ ejsWriteVarAsBoolean(ep, ep->result, lval);
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * Expressions with boolean operands
+ */
+
+static int evalBoolExpr(Ejs *ep, int l, int rel, int r)
+{
+ int lval;
+
+ switch (rel) {
+ case EJS_EXPR_EQ:
+ lval = l == r;
+ break;
+ case EJS_EXPR_NOTEQ:
+ lval = l != r;
+ break;
+ case EJS_EXPR_BOOL_COMP:
+ lval = (r == 0) ? 1 : 0;
+ break;
+ default:
+ ejsError(ep, EJS_SYNTAX_ERROR, "Bad operator %d", rel);
+ return -1;
+ }
+ ejsWriteVarAsBoolean(ep, ep->result, lval);
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * Expressions with numeric operands
+ */
+
+static int evalNumericExpr(Ejs *ep, EjsNum l, int rel, EjsNum r)
+{
+ EjsNum lval;
+ int logical;
+
+ lval = 0;
+ logical = 0;
+
+ switch (rel) {
+ case EJS_EXPR_PLUS:
+ lval = l + r;
+ break;
+ case EJS_EXPR_INC:
+ lval = l + 1;
+ break;
+ case EJS_EXPR_MINUS:
+ lval = l - r;
+ break;
+ case EJS_EXPR_DEC:
+ lval = l - 1;
+ break;
+ case EJS_EXPR_MUL:
+ lval = l * r;
+ break;
+ case EJS_EXPR_DIV:
+ if (r != 0) {
+ lval = l / r;
+ } else {
+ ejsError(ep, EJS_RANGE_ERROR, "Divide by zero");
+ return -1;
+ }
+ break;
+ case EJS_EXPR_MOD:
+ if (r != 0) {
+ lval = l % r;
+ } else {
+ ejsError(ep, EJS_RANGE_ERROR, "Modulo zero");
+ return -1;
+ }
+ break;
+ case EJS_EXPR_LSHIFT:
+ lval = l << r;
+ break;
+ case EJS_EXPR_RSHIFT:
+ lval = l >> r;
+ break;
+
+ default:
+ logical++;
+ break;
+ }
+
+ /*
+ * Logical operators
+ */
+ if (logical) {
+
+ switch (rel) {
+ case EJS_EXPR_EQ:
+ lval = l == r;
+ break;
+ case EJS_EXPR_NOTEQ:
+ lval = l != r;
+ break;
+ case EJS_EXPR_LESS:
+ lval = (l < r) ? 1 : 0;
+ break;
+ case EJS_EXPR_LESSEQ:
+ lval = (l <= r) ? 1 : 0;
+ break;
+ case EJS_EXPR_GREATER:
+ lval = (l > r) ? 1 : 0;
+ break;
+ case EJS_EXPR_GREATEREQ:
+ lval = (l >= r) ? 1 : 0;
+ break;
+ case EJS_EXPR_BOOL_COMP:
+ lval = (r == 0) ? 1 : 0;
+ break;
+ default:
+ ejsError(ep, EJS_SYNTAX_ERROR, "Bad operator %d", rel);
+ return -1;
+ }
+ ejsWriteVarAsBoolean(ep, ep->result, lval != 0);
+
+ } else {
+ ejsWriteVarAsNumber(ep, ep->result, lval);
+ }
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * Expressions with string operands
+ */
+
+static int evalStringExpr(Ejs *ep, EjsVar *lhs, int rel, EjsVar *rhs)
+{
+ int lval;
+
+ mprAssert(ep);
+ mprAssert(lhs);
+ mprAssert(rhs);
+
+ switch (rel) {
+ case EJS_EXPR_LESS:
+ lval = strcmp(lhs->string, rhs->string) < 0;
+ break;
+ case EJS_EXPR_LESSEQ:
+ lval = strcmp(lhs->string, rhs->string) <= 0;
+ break;
+ case EJS_EXPR_GREATER:
+ lval = strcmp(lhs->string, rhs->string) > 0;
+ break;
+ case EJS_EXPR_GREATEREQ:
+ lval = strcmp(lhs->string, rhs->string) >= 0;
+ break;
+ case EJS_EXPR_EQ:
+ lval = strcmp(lhs->string, rhs->string) == 0;
+ break;
+ case EJS_EXPR_NOTEQ:
+ lval = strcmp(lhs->string, rhs->string) != 0;
+ break;
+ case EJS_EXPR_PLUS:
+ /*
+ * This differs from all the above operations. We append rhs to lhs.
+ */
+ ejsClearVar(ep, ep->result);
+ ejsStrcat(ep, ep->result, lhs);
+ ejsStrcat(ep, ep->result, rhs);
+ return 0;
+
+ case EJS_EXPR_INC:
+ case EJS_EXPR_DEC:
+ case EJS_EXPR_MINUS:
+ case EJS_EXPR_DIV:
+ case EJS_EXPR_MOD:
+ case EJS_EXPR_LSHIFT:
+ case EJS_EXPR_RSHIFT:
+ default:
+ ejsSyntaxError(ep, "Bad operator");
+ return -1;
+ }
+
+ ejsWriteVarAsBoolean(ep, ep->result, lval);
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * Evaluate a method. obj is set to the current object if a method is being
+ * run.
+ */
+
+static int evalMethod(Ejs *ep, EjsVar *obj, EjsProc *proc, int flags)
+{
+ EjsProperty *pp;
+ EjsVar *saveThis, *prototype;
+ int saveThisPerm, rc, fid;
+
+ mprAssert(ep);
+
+ rc = 0;
+ fid = -1;
+ saveThis = 0;
+ saveThisPerm = 0;
+ prototype = proc->fn;
+
+ if (prototype == 0) {
+ ejsError(ep, EJS_EVAL_ERROR, "Undefined method");
+ return EJS_STATE_ERR;
+ }
+
+ if (prototype->type == EJS_TYPE_OBJECT) {
+ prototype = ejsGetPropertyAsVar(ep, prototype, proc->procName);
+ }
+
+ if (prototype) {
+ /*
+ * Create a new variable stack frame. ie. new local variables.
+ * Some C methods (eg. include) don't create a new local context.
+ */
+ if (! (prototype->flags & EJS_NO_LOCAL)) {
+ fid = ejsOpenBlock(ep);
+ if (fid < 0) {
+ return EJS_STATE_ERR;
+ }
+ mprAssert(ejsBlockInUse(ep->local));
+
+ pp = ejsSetProperty(ep, ep->local, "this", obj);
+ ejsMakePropertyEnumerable(pp, 0);
+
+ /*
+ * Optimization. Save "this" during this block.
+ */
+ saveThis = ep->thisObject;
+ ep->thisObject = ejsGetVarPtr(pp);
+ saveThisPerm = ejsMakeObjPermanent(saveThis, 1);
+ }
+
+ switch (prototype->type) {
+ default:
+ mprAssert(0);
+ break;
+
+ case EJS_TYPE_STRING_CMETHOD:
+ rc = callStringCMethod(ep, obj, proc, prototype);
+ break;
+
+ case EJS_TYPE_CMETHOD:
+ rc = callCMethod(ep, obj, proc, prototype);
+ break;
+
+ case EJS_TYPE_METHOD:
+ rc = callMethod(ep, obj, proc, prototype);
+ break;
+ }
+
+ if (fid >= 0) {
+ ejsMakeObjPermanent(saveThis, saveThisPerm);
+ ep->thisObject = saveThis;
+ mprAssert(ejsBlockInUse(ep->local));
+ mprAssert(ejsBlockInUse(ep->thisObject));
+ ejsCloseBlock(ep, fid);
+ }
+ }
+
+ return rc;
+}
+
+/******************************************************************************/
+/*
+ * Create a new object and call all required constructors.
+ * obj may be null in which case we look globally for className.
+ */
+
+EjsVar *ejsCreateObjUsingArgvInternal(EJS_LOC_DEC(ep, loc), EjsVar *obj,
+ const char *className, MprArray *args)
+{
+ EjsVar *baseClass, *objectClass, *thisObj;
+ int rc;
+
+ mprAssert(className && *className);
+
+ /*
+ * Create a new object of the required class and pass it into the
+ * constructor as the "this" local variable.
+ */
+ baseClass = ejsGetClass(ep, obj, className);
+ if (baseClass == 0) {
+
+ if (obj && obj->objectState->className &&
+ strcmp(obj->objectState->className, className) == 0) {
+ /*
+ * Handle case where we are calling the constructor inside
+ * the class. In this case, obj == baseClass.
+ */
+ thisObj = ejsCreateSimpleObjUsingClassInt(EJS_LOC_PASS(ep, loc),
+ obj);
+
+ } else {
+
+ /*
+ * If the baseClass does not exist, try to create an Object
+ * We do this for compatibility with JS 1.5 style new Function.
+ * MOB -- but this masks an error if we really need className.
+ */
+ objectClass = ejsGetClass(ep, 0, "Object");
+ thisObj = ejsCreateSimpleObjUsingClassInt(EJS_LOC_PASS(ep, loc),
+ objectClass);
+ }
+
+ } else {
+ thisObj = ejsCreateSimpleObjUsingClassInt(EJS_LOC_PASS(ep, loc),
+ baseClass);
+ }
+
+ if (thisObj == 0) {
+ ejsMemoryError(ep);
+ return 0;
+ }
+
+ /*
+ * Make the object permanent. While currently not alive, the constructor
+ * below may make the object alive.
+ */
+ ejsMakeObjPermanent(thisObj, 1);
+ mprAssert(! ejsObjIsCollectable(thisObj));
+
+ rc = 0;
+ if (baseClass) {
+ if (! baseClass->objectState->noConstructor) {
+ rc = callConstructor(ep, thisObj, baseClass, args);
+ }
+ } else {
+ /*
+ * className is the function name when calling new on functions
+ */
+ rc = ejsRunMethod(ep, thisObj, className, args);
+ }
+
+ /*
+ * Constructor may change the type to a non-object.
+ * Function() does this. Ensure object is not collectable yet.
+ */
+ if (ejsVarIsObject(thisObj)) {
+ ejsMakeObjPermanent(thisObj, 0);
+ ejsMakeObjLive(thisObj, 0);
+ }
+
+ if (rc < 0) {
+ if (rc == MPR_ERR_NOT_FOUND) {
+ /* No constructor (default) */
+ return thisObj;
+ }
+ if (! (ep->flags & EJS_FLAGS_EXIT)) {
+ if (! ep->gotException) {
+ ejsMemoryError(ep);
+ }
+ }
+ ejsFreeVar(ep, thisObj);
+ return 0;
+ }
+
+ mprAssert(ejsBlockInUse(thisObj));
+
+ return thisObj;
+}
+
+/******************************************************************************/
+/*
+ * Local vars
+ */
+
+typedef struct CallCons {
+ EjsVar *subClassConstructor, *subClass, *method;
+} CallCons;
+
+/*
+ * Create a new object and call all required constructors.
+ */
+
+static int callConstructor(Ejs *ep, EjsVar *thisObj, EjsVar *baseClass,
+ MprArray *args)
+{
+ CallCons *sp;
+ int state;
+
+ if ((sp = pushFrame(ep, sizeof(CallCons))) == 0) {
+ return EJS_STATE_ERR;
+ }
+
+ mprAssert(baseClass);
+ mprAssert(baseClass->objectState);
+
+ state = 0;
+
+ /*
+ * method will be null if there is no constructor for this class
+ */
+ sp->method = ejsGetPropertyAsVar(ep, baseClass,
+ baseClass->objectState->className);
+
+ if (sp->method == 0 || !ejsVarIsMethod(sp->method) ||
+ !sp->method->callsSuper) {
+ /*
+ * Invoke base class constructors in reverse order (RECURSIVE)
+ */
+ sp->subClass = baseClass->objectState->baseClass;
+ if (sp->subClass) {
+
+ /*
+ * Note that the Object class does not have a constructor for
+ * speed. Construction for the base Object is done via
+ * ejsCreateObj above. The code below will invoke constructors
+ * in the right order (bottom up) via recursion. MOB -- need to
+ * scan for super() MOB -- Bug. Fails poorly if no constructor.
+ * Should allows this and invoke a default constructor.
+ */
+ sp->subClassConstructor = ejsGetPropertyAsVar(ep, sp->subClass,
+ sp->subClass->objectState->className);
+
+ if (sp->subClassConstructor) {
+
+ if (callConstructor(ep, thisObj, sp->subClass, 0) < 0) {
+ if (! ep->gotException) {
+ ejsMemoryError(ep);
+ }
+ goto err;
+ }
+ }
+ }
+ }
+
+ if (sp->method) {
+ /*
+ * Finally, invoke the constructor for this class itself.
+ */
+ state = runMethod(ep, thisObj, sp->method,
+ baseClass->objectState->className, args);
+ }
+
+done:
+ popFrame(ep, sizeof(CallCons));
+ return state;
+
+err:
+ state = EJS_STATE_ERR;
+ goto done;
+}
+
+/******************************************************************************/
+/*
+ * Create a new object and call all required constructors using string args.
+ * MOB -- would be good to parse constructorArgs for "," and break into
+ * separate args.
+ * Returned object is not yet collectable. Will have alive bit cleared.
+ */
+
+EjsVar *ejsCreateObj(Ejs *ep, EjsVar *obj, const char *className,
+ const char *constructorArgs)
+{
+ MprArray *args;
+ EjsVar *newp, *vp;
+
+ args = mprCreateItemArray(ep, 0, 0);
+ if (args == 0) {
+ return 0;
+ }
+
+ if (constructorArgs && *constructorArgs) {
+ vp = ejsCreateStringVarInternal(EJS_LOC_ARGS(ep), constructorArgs);
+
+ if (mprAddItem(args, vp) < 0) {
+ mprFree(args);
+ return 0;
+ }
+ }
+
+ newp = ejsCreateObjUsingArgv(ep, obj, className, args);
+
+ ejsFreeMethodArgs(ep, args);
+
+ mprAssert(! ejsObjIsCollectable(newp));
+ mprAssert(ejsBlockInUse(newp));
+
+ return newp;
+}
+
+/******************************************************************************/
+
+static int callStringCMethod(Ejs *ep, EjsVar *obj, EjsProc *proc,
+ EjsVar *prototype)
+{
+ EjsVar **argValues;
+ MprArray *actualArgs;
+ char **argBuf, *str;
+ int i, rc;
+
+ actualArgs = proc->args;
+ argValues = (EjsVar**) actualArgs->items;
+
+ if (actualArgs->length > 0) {
+ argBuf = mprAlloc(ep, actualArgs->length * sizeof(char*));
+ for (i = 0; i < actualArgs->length; i++) {
+ str = ejsVarToString(ep, argValues[i]);
+ /* MOB rc */
+ argBuf[i] = mprStrdup(ep, str);
+ }
+ } else {
+ argBuf = 0;
+ }
+
+ /*
+ * Call the method depending on the various handle flags
+ */
+ ep->userData = prototype->cMethodWithStrings.userData;
+ if (prototype->flags & EJS_ALT_HANDLE) {
+ /*
+ * Used by the AppWeb GaCompat module. The alt handle is set to the
+ * web server request struct
+ */
+ rc = ((EjsAltStringCMethod)
+ prototype->cMethodWithStrings.fn)
+ (ep, ep->altHandle, obj, actualArgs->length, argBuf);
+
+ } else if (prototype->flags & EJS_PRIMARY_HANDLE) {
+ /*
+ * Used by ESP. The primary handle is set to the esp struct
+ */
+ rc = (prototype->cMethodWithStrings.fn)(ep->primaryHandle,
+ obj, actualArgs->length, argBuf);
+
+ } else {
+ /*
+ * Used EJS for the standard procs
+ */
+ rc = (prototype->cMethodWithStrings.fn)(ep, obj, actualArgs->length,
+ argBuf);
+ }
+
+ if (actualArgs->length > 0) {
+ for (i = 0; i < actualArgs->length; i++) {
+ mprFree(argBuf[i]);
+ }
+ mprFree(argBuf);
+ }
+ ep->userData = 0;
+
+ return rc;
+}
+
+/******************************************************************************/
+
+static int callCMethod(Ejs *ep, EjsVar *obj, EjsProc *proc, EjsVar *prototype)
+{
+ EjsVar **argValues;
+ MprArray *actualArgs;
+ int rc;
+
+ actualArgs = proc->args;
+ argValues = (EjsVar**) actualArgs->items;
+
+ ep->userData = prototype->cMethod.userData;
+
+ /*
+ * Call the method depending on the various handle flags
+ * Sometimes cMethod.fn is NULL if there is no constructor for
+ * an object.
+ */
+ if (prototype->flags & EJS_ALT_HANDLE) {
+ /*
+ * Use by the GaCompat module. The alt handle is set to the
+ * web server request struct
+ */
+ rc = ((EjsAltCMethod) prototype->cMethod.fn)
+ (ep, ep->altHandle, obj, actualArgs->length, argValues);
+
+ } else if (prototype->flags & EJS_PRIMARY_HANDLE) {
+ /*
+ * Used by ESP. The primary handle is set to the esp struct
+ */
+ rc = (prototype->cMethod.fn)
+ (ep->primaryHandle, obj, actualArgs->length, argValues);
+
+ } else {
+ /*
+ * Used EJS for the standard procs
+ */
+ rc = (prototype->cMethod.fn)(ep, obj, actualArgs->length, argValues);
+ }
+
+ ep->userData = 0;
+
+ return rc;
+}
+
+/******************************************************************************/
+/*
+ * Local vars
+ */
+
+typedef struct CallMethod {
+ MprArray *formalArgs, *actualArgs;
+ EjsVar *arguments, *callee, **argValues;
+ char **argNames, buf[16];
+ int i, argumentsObj;
+} CallMethod;
+
+
+static int callMethod(Ejs *ep, EjsVar *obj, EjsProc *proc, EjsVar *prototype)
+{
+ CallMethod *sp;
+ int i;
+
+ if ((sp = pushFrame(ep, sizeof(CallMethod))) == 0) {
+ return EJS_STATE_ERR;
+ }
+
+ sp->arguments = 0;
+ sp->callee = 0;
+
+ sp->actualArgs = proc->args;
+ sp->argValues = (EjsVar**) sp->actualArgs->items;
+ sp->formalArgs = prototype->method.args;
+ sp->argNames = (char**) sp->formalArgs->items;
+
+ /*
+ * Only create arguments and callee if the function actually uses them
+ */
+ sp->argumentsObj = 0;
+ if (strstr(prototype->method.body, "arguments") != 0) {
+ sp->argumentsObj++;
+
+ /*
+ * Create the arguments and callee variables
+ * MOB -- should we make real arrays here ? YES
+ */
+ sp->arguments = ejsCreateSimpleObj(ep, "Object");
+ ejsSetVarName(ep, sp->arguments, "arguments");
+ mprAssert(! ejsObjIsCollectable(sp->arguments));
+
+ sp->callee = ejsCreateSimpleObj(ep, "Object");
+ ejsSetVarName(ep, sp->callee, "callee");
+ mprAssert(! ejsObjIsCollectable(sp->callee));
+
+ /*
+ * Overwrite the length property
+ */
+ ejsSetPropertyToInteger(ep, sp->arguments, "length",
+ sp->actualArgs->length);
+ ejsSetPropertyToInteger(ep, sp->callee, "length",
+ sp->formalArgs->length);
+ }
+
+ /*
+ * Define all the agruments to be set to the actual parameters
+ */
+ for (i = 0; i < sp->formalArgs->length; i++) {
+ if (i >= sp->actualArgs->length) {
+ /* MOB -- return code */
+ ejsCreateProperty(ep, ep->local, sp->argNames[i]);
+
+ } else {
+ /* MOB -- return code */
+ ejsSetProperty(ep, ep->local, sp->argNames[i], sp->argValues[i]);
+ }
+ }
+
+ if (sp->argumentsObj) {
+ for (i = 0; i < sp->actualArgs->length; i++) {
+ mprItoa(sp->buf, sizeof(sp->buf), i);
+ ejsSetProperty(ep, sp->arguments, sp->buf, sp->argValues[i]);
+ }
+
+ ejsSetPropertyAndFree(ep, sp->arguments, "callee", sp->callee);
+ ejsSetPropertyAndFree(ep, ep->local, "arguments", sp->arguments);
+ }
+
+ /*
+ * Actually run the method
+ */
+
+ i = ejsEvalScript(ep, prototype->method.body, 0);
+
+ popFrame(ep, sizeof(CallMethod));
+ return i;
+}
+
+/******************************************************************************/
+/*
+ * Run a method. Obj is set to "this" object. MethodName must exist in it
+ * or in a sub class.
+ */
+
+int ejsRunMethod(Ejs *ep, EjsVar *obj, const char *methodName, MprArray *args)
+{
+ EjsProperty *pp;
+ EjsProc proc, *saveProc;
+ int rc;
+
+ mprAssert(obj);
+ mprAssert(methodName && *methodName);
+
+ pp = ejsGetProperty(ep, obj, methodName);
+ if (pp == 0) {
+ /* MOB -- this should be all in some common accessor routine */
+ pp = ejsGetProperty(ep, ep->local, methodName);
+ if (pp == 0) {
+ pp = ejsGetProperty(ep, ep->global, methodName);
+ if (pp == 0) {
+ ejsError(ep, EJS_REFERENCE_ERROR,
+ "Undefined method \"%s\"", methodName);
+ return MPR_ERR_NOT_FOUND;
+ }
+ }
+ }
+
+ saveProc = ep->proc;
+ ep->proc = &proc;
+
+ memset(&proc, 0, sizeof(EjsProc));
+
+ ejsClearVar(ep, ep->result);
+
+ /* MOB -- if closures are going to work, we need to have proc be an
+ Object and let the GC look after it */
+
+ proc.fn = &pp->var;
+ if (proc.fn == 0 || proc.fn->type == EJS_TYPE_UNDEFINED) {
+ ep->proc = saveProc;
+ return MPR_ERR_NOT_FOUND;
+ }
+
+ proc.procName = mprStrdup(ep, methodName);
+ if (args == 0) {
+ proc.args = mprCreateItemArray(ep, EJS_INC_ARGS, EJS_MAX_ARGS);
+ } else {
+ proc.args = args;
+ }
+
+ rc = evalMethod(ep, obj, &proc, 0);
+
+ if (args) {
+ proc.args = 0;
+ }
+ freeProc(ep, &proc);
+
+ ep->proc = saveProc;
+
+ return rc;
+}
+
+/******************************************************************************/
+/*
+ * Run a method. Obj is set to "this" object. MethodName must exist in it
+ * or in a sub class.
+ */
+
+int ejsRunMethodCmd(Ejs *ep, EjsVar *obj, const char *methodName,
+ const char *cmdFmt, ...)
+{
+ MprArray *args;
+ va_list cmdArgs;
+ char *buf, *arg, *cp;
+ int rc;
+
+ mprAssert(methodName && *methodName);
+ mprAssert(cmdFmt && *cmdFmt);
+
+ va_start(cmdArgs, cmdFmt);
+ mprAllocVsprintf(MPR_LOC_ARGS(ep), &buf, 0, cmdFmt, cmdArgs);
+ va_end(cmdArgs);
+
+ args = mprCreateItemArray(ep, EJS_INC_ARGS, EJS_MAX_ARGS);
+
+ for (arg = cp = buf; cp && *cp; cp++) {
+ if (*cp == ',') {
+ *cp = 0;
+ mprAddItem(args, ejsParseVar(ep, arg, 0));
+ arg = cp + 1;
+ }
+ }
+ if (cp > arg) {
+ mprAddItem(args, ejsParseVar(ep, arg, 0));
+ }
+
+ rc = ejsRunMethod(ep, obj, methodName, args);
+
+ ejsFreeMethodArgs(ep, args);
+ mprFree(buf);
+
+ return rc;
+}
+
+/******************************************************************************/
+/*
+ * Run a method. Obj is set to "this" object.
+ */
+
+static int runMethod(Ejs *ep, EjsVar *thisObj, EjsVar *method,
+ const char *methodName, MprArray *args)
+{
+ EjsProc proc, *saveProc;
+ int rc;
+
+ mprAssert(thisObj);
+ mprAssert(method);
+
+ saveProc = ep->proc;
+ ep->proc = &proc;
+
+ memset(&proc, 0, sizeof(EjsProc));
+
+ ejsClearVar(ep, ep->result);
+
+ /* MOB -- if closures are going to work, we need to have proc be an
+ Object and let the GC look after it */
+
+ proc.fn = method;
+ if (proc.fn == 0 || proc.fn->type == EJS_TYPE_UNDEFINED) {
+ ep->proc = saveProc;
+ return MPR_ERR_NOT_FOUND;
+ }
+
+ proc.procName = mprStrdup(ep, methodName);
+ if (args == 0) {
+ proc.args = mprCreateItemArray(ep, EJS_INC_ARGS, EJS_MAX_ARGS);
+ } else {
+ proc.args = args;
+ }
+
+ rc = evalMethod(ep, thisObj, &proc, 0);
+
+ if (args) {
+ proc.args = 0;
+ }
+ freeProc(ep, &proc);
+
+ ep->proc = saveProc;
+
+ return rc;
+}
+
+/******************************************************************************/
+/*
+ * Find which object contains the property given the current context.
+ * We call this when there is no explicit object and the object must be
+ * determined by the context.
+ */
+
+static EjsVar *pickSpace(Ejs *ep, int state, const char *property, int flags)
+{
+ EjsVar *obj;
+
+ mprAssert(ep);
+ mprAssert(property && *property);
+
+ /* MOB - this is ugly and the logic is confused */
+
+ if (flags & EJS_FLAGS_GLOBAL) {
+ obj = ep->global;
+
+ } else if (state == EJS_STATE_DEC || flags & EJS_FLAGS_LOCAL) {
+ obj = ep->local;
+
+ } else {
+ /* First look local, then this and finally global */
+
+ if (ejsGetSimpleProperty(ep, ep->local, property)) {
+ obj = ep->local;
+
+ } else if (ep->thisObject &&
+ findProperty(ep, ep->thisObject, property, flags)) {
+ obj = ep->thisObject;
+
+ } else {
+#if EJS_ECMA_STND
+ obj = ep->global;
+#else
+ if (flags & EJS_FLAGS_EXE &&
+ !findProperty(ep, ep->global, property, flags)) {
+ obj = ep->local;
+ } else {
+ obj = ep->global;
+ }
+#endif
+ }
+ }
+ return obj;
+}
+
+/******************************************************************************/
+/*
+ * Find an object property given a object and a property name. We
+ * intelligently look in the local and global namespaces depending on
+ * our state. If not found in local or global, try base classes for method
+ * names only. Returns the property or NULL.
+ * MOB -- need to rework this API.
+ */
+
+static EjsProperty *searchSpacesForProperty(Ejs *ep, int state, EjsVar *obj,
+ char *property, int flags)
+{
+ EjsProperty *pp;
+
+ if (obj) {
+ return findProperty(ep, obj, property, flags);
+ }
+
+ /* MOB -- really should have a search stack */
+
+ pp = findProperty(ep, ep->local, property, flags);
+ if (pp == 0 && state != EJS_STATE_DEC) {
+
+ if (ep->thisObject) {
+ pp = findProperty(ep, ep->thisObject, property, flags);
+ }
+ if (pp == 0) {
+ pp = findProperty(ep, ep->global, property, flags);
+ }
+ }
+ return pp;
+}
+
+/******************************************************************************/
+/*
+ * Search an object and its base classes to find an object given an object
+ * an a property name. If not an assignment (LHS), then follow base classes.
+ * Otherwise, just look in the specified object.
+ */
+
+static EjsProperty *findProperty(Ejs *ep, EjsVar *op, const char *property,
+ int flags)
+{
+ /* MOB -- NEW. Remove when EXE fixes are in. */
+ if (! (flags & EJS_FLAGS_EXE) && op->type == EJS_TYPE_UNDEFINED) {
+ return 0;
+ }
+
+ if (flags & EJS_FLAGS_LHS) {
+ return ejsGetPropertyPtr(ejsGetSimpleProperty(ep, op, property));
+
+ } else {
+ /*
+ * Follow base classes
+ */
+ return ejsGetPropertyPtr(ejsGetProperty(ep, op, property));
+ }
+}
+
+/******************************************************************************/
+/*
+ * Update result
+ */
+
+static void updateResult(Ejs *ep, int state, int flags, EjsVar *vp)
+{
+ if (flags & EJS_FLAGS_EXE && state != EJS_STATE_DEC) {
+ ejsClearVar(ep, ep->result);
+ if (vp) {
+ ejsWriteVar(ep, ep->result, vp, EJS_SHALLOW_COPY);
+ ejsSetVarName(ep, ep->result, vp->propertyName);
+ }
+ }
+}
+
+/******************************************************************************/
+/*
+ * Append to the pointer value
+ */
+
+int ejsStrcat(Ejs *ep, EjsVar *dest, EjsVar *src)
+{
+ char *oldBuf, *buf, *str;
+ int oldLen, newLen, len;
+
+ mprAssert(dest);
+ mprAssert(ejsVarIsString(src));
+
+ if (ejsVarIsValid(dest)) {
+
+ if (! ejsVarIsString(dest)) {
+ /* Bad type for dest */
+ return -1;
+ }
+
+ if (! ejsVarIsString(src)) {
+ str = ejsVarToString(ep, src);
+ if (str == 0) {
+ return -1;
+ }
+ len = strlen(str);
+
+ } else {
+ str = src->string;
+ len = src->length;
+ }
+
+ oldBuf = dest->string;
+ oldLen = dest->length;
+ newLen = oldLen + len + 1;
+
+ if (newLen < MPR_SLAB_STR_MAX) {
+ buf = oldBuf;
+ } else {
+ buf = mprRealloc(ep, oldBuf, newLen);
+ if (buf == 0) {
+ return -1;
+ }
+ dest->string = buf;
+ }
+ memcpy(&buf[oldLen], str, len);
+ dest->length += len;
+
+ } else {
+ ejsWriteVarAsString(ep, dest, src->string);
+ }
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * Exit the script
+ */
+
+void ejsExit(Ejs *ep, int status)
+{
+ ep->scriptStatus = status;
+ ep->flags |= EJS_FLAGS_EXIT;
+}
+
+/******************************************************************************/
+/*
+ * Free an argument list
+ */
+
+static void freeProc(Ejs *ep, EjsProc *proc)
+{
+ if (proc->args) {
+ ejsFreeMethodArgs(ep, proc->args);
+ }
+
+ if (proc->procName) {
+ mprFree(proc->procName);
+ proc->procName = NULL;
+ }
+}
+
+/******************************************************************************/
+
+void ejsFreeMethodArgs(Ejs *ep, MprArray *args)
+{
+ int i;
+
+ for (i = args->length - 1; i >= 0; i--) {
+ ejsFreeVar(ep, args->items[i]);
+ mprRemoveItemByIndex(args, i);
+ }
+ mprFree(args);
+}
+
+/******************************************************************************/
+/*
+ * This method removes any new lines. Used for else cases, etc.
+ */
+
+static void removeNewlines(Ejs *ep, int state)
+{
+ int tid;
+
+ do {
+ tid = ejsLexGetToken(ep, state);
+ } while (tid == EJS_TOK_NEWLINE);
+
+ ejsLexPutbackToken(ep, tid, ep->token);
+}
+
+/******************************************************************************/
+
+static int getNextNonSpaceToken(Ejs *ep, int state)
+{
+ int tid;
+
+ do {
+ tid = ejsLexGetToken(ep, state);
+ } while (tid == EJS_TOK_NEWLINE);
+ return tid;
+}
+
+/******************************************************************************/
+
+int ejsGetFlags(Ejs *ep)
+{
+ return ep->flags;
+}
+
+/******************************************************************************/
+
+bool ejsIsExiting(Ejs *ep)
+{
+ return (ep->flags & EJS_FLAGS_EXIT) ? 1: 0;
+}
+
+/******************************************************************************/
+
+void ejsClearExiting(Ejs *ep)
+{
+ ep->flags &= ~EJS_FLAGS_EXIT;
+}
+
+/******************************************************************************/
+
+static EjsInput *getInputStruct(Ejs *ep)
+{
+ EjsInput *input;
+
+ if (ep->inputList) {
+ input = ep->inputList;
+ ep->inputList = input->nextInput;
+
+ } else {
+ input = mprAlloc(ep, sizeof(EjsInput));
+ }
+ return input;
+}
+
+/******************************************************************************/
+
+static void freeInputStruct(Ejs *ep, EjsInput *input)
+{
+ input->nextInput = ep->inputList;
+ ep->inputList = input;
+}
+
+/******************************************************************************/
+
+static void *pushFrame(Ejs *ep, int size)
+{
+ /*
+ * Grow down stack
+ */
+ ep->stkPtr -= size;
+ if (ep->stkPtr < ep->stack) {
+ mprError(ep, MPR_LOC, "Exceeded parse stack");
+ return 0;
+ }
+ return ep->stkPtr;
+}
+
+/******************************************************************************/
+
+static void *popFrame(Ejs *ep, int size)
+{
+ ep->stkPtr += size;
+ if (ep->stkPtr > &ep->stack[EJS_MAX_STACK]) {
+ mprError(ep, MPR_LOC, "Over poped parse stack");
+ return 0;
+ }
+ return ep->stkPtr;
+}
+
+/******************************************************************************/
+#else
+void ejsParserDummy() {}
+
+/******************************************************************************/
+#endif /* BLD_FEATURE_EJS */
+
+/*
+ * 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-2.0/ejs/ejsVar.c b/source4/lib/appweb/ejs-2.0/ejs/ejsVar.c
new file mode 100644
index 0000000000..5067215f03
--- /dev/null
+++ b/source4/lib/appweb/ejs-2.0/ejs/ejsVar.c
@@ -0,0 +1,4033 @@
+/**
+ * @file ejsVar.c
+ * @brief Mbedthis Portable Runtime Universal Variable Type
+ */
+
+/*
+ * @copy default
+ *
+ * Copyright (c) Mbedthis Software LLC, 2003-2006. 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 methods.
+ * Properties are indexed by a character name.
+ */
+
+/********************************** Includes **********************************/
+
+#include "ejs.h"
+
+/***************************** Forward Declarations ***************************/
+
+static EjsProperty *allocProperty(Ejs *ep, EjsVar *op, const char *property,
+ int propertyIndex, EjsProperty *last);
+static EjsVar *copyVar(EJS_LOC_DEC(ep, loc), EjsVar *dest,
+ const EjsVar *src, EjsCopyDepth copyDepth);
+static EjsObj *createObj(EJS_LOC_DEC(ep, loc));
+static char *getNextVarToken(char **next, char *tokBuf, int tokBufLen);
+static int hash(const char *property);
+static void unlinkProperty(EjsObj *obj, EjsPropLink *propLink);
+static void linkPropertyBefore(EjsObj *obj, EjsPropLink *at,
+ EjsPropLink *propLink);
+static int sortAllProperties(Ejs *ep, EjsProperty *p1,
+ EjsProperty *p2, const char *propertyName, int order);
+static int sortByProperty(Ejs *ep, EjsProperty *p1, EjsProperty *p2,
+ const char *propertyName, int order);
+static int dupString(MPR_LOC_DEC(ctx, loc), uchar **dest,
+ const void *src, int nbytes);
+#if UNUSED && KEEP
+static void linkPropertyAfter(EjsObj *obj, EjsPropLink *at,
+ EjsPropLink *propLink);
+#endif
+
+static EjsProperty *hashLookup(EjsObj *obj, const char *property,
+ int *propertyIndex, EjsProperty **hashTail);
+
+/******************************************************************************/
+/********************************** Var Routines ******************************/
+/******************************************************************************/
+
+EjsType ejsGetVarType(EjsVar *vp)
+{
+ mprAssert(vp);
+
+ return vp->type;
+}
+
+/******************************************************************************/
+
+void ejsFreeVar(Ejs *ep, EjsVar *vp)
+{
+ if (vp) {
+ ejsClearVar(ep, vp);
+ ejsFree(ep, vp, EJS_SLAB_VAR);
+ }
+}
+
+/******************************************************************************/
+#if UNUSED
+/*
+ * Clear the value by freeing any allocated data. This will release objects
+ * so that later garbage collection can reclaim storage if there are no other
+ * object references.
+ */
+
+void ejsZeroVar(Ejs *ep, EjsVar *vp)
+{
+ vp->type = EJS_TYPE_UNDEFINED;
+ vp->objectState = 0;
+ vp->method.body = 0;
+ vp->method.args = 0;
+ vp->callsSuper = 0;
+ vp->ptr.destructor = 0;
+ vp->allocatedData = 0;
+}
+
+#endif
+/******************************************************************************/
+/*
+ * Clear the value by freeing any allocated data. This will release objects
+ * so that later garbage collection can reclaim storage if there are no other
+ * object references.
+ */
+
+void ejsClearVar(Ejs *ep, EjsVar *vp)
+{
+ MprArray *argList;
+ int i;
+
+ mprAssert(vp);
+ mprAssert(ep);
+
+ if (! vp->allocatedData) {
+ vp->type = EJS_TYPE_UNDEFINED;
+ return;
+ }
+ if (vp->type == EJS_TYPE_UNDEFINED) {
+ return;
+ }
+
+ switch (vp->type) {
+ default:
+ break;
+
+ case EJS_TYPE_STRING:
+ mprFree(vp->string);
+ vp->string = 0;
+ break;
+
+ case EJS_TYPE_OBJECT:
+ /*
+ * Set the "alive" bit so that the GC will cleanup if no
+ * other references.
+ */
+ if (vp->objectState) {
+ vp->objectState->alive = 1;
+ }
+ vp->objectState = 0;
+ break;
+
+ case EJS_TYPE_METHOD:
+ argList = vp->method.args;
+ /*
+ * MOB OPT -- should be able to do just one mprFree(vp->method.args)
+ */
+ mprFree(vp->method.body);
+ if (argList) {
+ for (i = 0; i < argList->length; i++) {
+ mprFree(argList->items[i]);
+ }
+ mprFree(vp->method.args);
+ }
+ vp->method.args = 0;
+ vp->method.body = 0;
+ vp->callsSuper = 0;
+ break;
+
+ case EJS_TYPE_PTR:
+ if (vp->ptr.destructor) {
+ (vp->ptr.destructor)(ep, vp);
+ }
+ break;
+ }
+
+ vp->type = EJS_TYPE_UNDEFINED;
+ vp->allocatedData = 0;
+}
+
+/******************************************************************************/
+/*
+ * Initialize an undefined value.
+ */
+
+EjsVar *ejsCreateUndefinedVar(Ejs *ep)
+{
+ EjsVar *vp;
+
+ mprAssert(ep);
+
+ vp = ejsAllocVar(EJS_LOC_ARGS(ep));
+ if (vp) {
+ vp->type = EJS_TYPE_UNDEFINED;
+ }
+ return vp;
+}
+
+/******************************************************************************/
+/*
+ * Initialize an null value.
+ */
+
+EjsVar *ejsCreateNullVar(Ejs *ep)
+{
+ EjsVar *vp;
+
+ mprAssert(ep);
+
+ vp = ejsAllocVar(EJS_LOC_ARGS(ep));
+ if (vp) {
+ vp->type = EJS_TYPE_NULL;
+ }
+ return vp;
+}
+
+/******************************************************************************/
+
+EjsVar *ejsCreateBoolVar(Ejs *ep, int value)
+{
+ EjsVar *vp;
+
+ mprAssert(ep);
+
+ vp = ejsAllocVar(EJS_LOC_ARGS(ep));
+ if (vp) {
+ vp->type = EJS_TYPE_BOOL;
+ vp->boolean = value;
+ }
+ return vp;
+}
+
+/******************************************************************************/
+/*
+ * Initialize a C method.
+ */
+
+EjsVar *ejsCreateCMethodVar(Ejs *ep, EjsCMethod fn, void *userData, int flags)
+{
+ EjsVar *vp;
+
+ mprAssert(ep);
+
+ vp = ejsAllocVar(EJS_LOC_ARGS(ep));
+ if (vp) {
+ vp->type = EJS_TYPE_CMETHOD;
+ vp->cMethod.fn = fn;
+ vp->cMethod.userData = userData;
+ vp->flags = flags;
+ }
+ return vp;
+}
+
+/******************************************************************************/
+/*
+ * Initialize a C method.
+ */
+
+EjsVar *ejsCreateStringCMethodVar(Ejs *ep, EjsStringCMethod fn,
+ void *userData, int flags)
+{
+ EjsVar *vp;
+
+ mprAssert(ep);
+ mprAssert(fn);
+
+ vp = ejsAllocVar(EJS_LOC_ARGS(ep));
+ if (vp) {
+ vp->type = EJS_TYPE_STRING_CMETHOD;
+ vp->cMethodWithStrings.fn = fn;
+ vp->cMethodWithStrings.userData = userData;
+ vp->flags = flags;
+ }
+ return vp;
+}
+
+/******************************************************************************/
+/*
+ * Initialize an opaque pointer.
+ */
+
+EjsVar *ejsCreatePtrVar(Ejs *ep, void *ptr, EjsDestructor destructor)
+{
+ EjsVar *vp;
+
+ mprAssert(ep);
+ mprAssert(ptr);
+
+ vp = ejsAllocVar(EJS_LOC_ARGS(ep));
+ if (vp) {
+ vp->type = EJS_TYPE_PTR;
+ vp->ptr.userPtr = ptr;
+ vp->ptr.destructor = destructor;
+ vp->allocatedData = 1;
+ }
+ return vp;
+}
+
+/******************************************************************************/
+#if BLD_FEATURE_FLOATING_POINT
+/*
+ * Initialize a floating value.
+ */
+
+EjsVar *ejsCreateFloatVar(Ejs *ep, double value)
+{
+ EjsVar *vp;
+
+ mprAssert(ep);
+
+ vp = ejsAllocVar(EJS_LOC_ARGS(ep));
+ if (vp) {
+ vp->type = EJS_TYPE_FLOAT;
+ vp->floating = value;
+ }
+ return vp;
+}
+
+#endif
+/******************************************************************************/
+/*
+ * Initialize an integer value.
+ */
+
+EjsVar *ejsCreateIntegerVar(Ejs *ep, int value)
+{
+ EjsVar *vp;
+
+ mprAssert(ep);
+
+ vp = ejsAllocVar(EJS_LOC_ARGS(ep));
+ if (vp) {
+ vp->type = EJS_TYPE_INT;
+ vp->integer = value;
+ }
+ return vp;
+}
+
+/******************************************************************************/
+#if BLD_FEATURE_INT64
+/*
+ * Initialize a 64-bit integer value.
+ */
+
+EjsVar *ejsCreateInteger64Var(Ejs *ep, int64 value)
+{
+ EjsVar *vp;
+
+ mprAssert(ep);
+
+ vp = ejsAllocVar(EJS_LOC_ARGS(ep));
+ if (vp) {
+ vp->type = EJS_TYPE_INT64;
+ vp->integer64 = value;
+ }
+ return vp;
+}
+
+#endif /* BLD_FEATURE_INT64 */
+/******************************************************************************/
+/*
+ * Initialize an number variable. Type is defined by configure.
+ */
+
+EjsVar *ejsCreateNumberVar(Ejs *ep, EjsNum value)
+{
+ EjsVar *vp;
+
+ mprAssert(ep);
+
+ vp = ejsAllocVar(EJS_LOC_ARGS(ep));
+ mprAssert(vp);
+
+ if (vp) {
+ vp->type = BLD_FEATURE_NUM_TYPE_ID;
+#if BLD_FEATURE_NUM_TYPE_ID == EJS_TYPE_INT64
+ vp->integer64 = value;
+#elif BLD_FEATURE_NUM_TYPE_ID == EJS_TYPE_FLOAT
+ vp->float = value;
+#else
+ vp->integer = value;
+#endif
+ }
+ return vp;
+}
+
+/******************************************************************************/
+/*
+ * Initialize a (bare) JavaScript method. args and body can be null.
+ */
+
+EjsVar *ejsCreateMethodVar(Ejs *ep, const char *body, MprArray *args, int flags)
+{
+ EjsVar *vp;
+ int i;
+
+ mprAssert(ep);
+
+ vp = ejsAllocVar(EJS_LOC_ARGS(ep));
+ mprAssert(vp);
+
+ if (vp == 0) {
+ return 0;
+ }
+
+ vp->type = EJS_TYPE_METHOD;
+
+ vp->allocatedData = 1;
+
+ vp->method.args = mprCreateItemArray(ep, EJS_INC_ARGS, EJS_MAX_ARGS);
+ if (vp->method.args == 0) {
+ mprAssert(vp->method.args);
+ ejsFreeVar(ep, vp);
+ return 0;
+ }
+
+ if (args) {
+ for (i = 0; i < args->length; i++) {
+ mprAddItem(vp->method.args,
+ mprStrdup(vp->method.args, mprGetItem(args, i)));
+ }
+ }
+ vp->method.body = mprStrdup(vp->method.args, body);
+
+ if (vp->method.body == 0) {
+ ejsFreeVar(ep, vp);
+ return 0;
+ }
+ vp->flags = flags;
+
+ return vp;
+}
+
+/******************************************************************************/
+/*
+ * Initialize an object variable.
+ */
+
+EjsVar *ejsCreateObjVarInternal(EJS_LOC_DEC(ep, loc))
+{
+ EjsVar *vp;
+
+ mprAssert(ep);
+
+ vp = ejsAllocVar(EJS_LOC_PASS(ep, loc));
+ mprAssert(vp);
+
+ if (vp) {
+ vp->type = EJS_TYPE_OBJECT;
+ vp->objectState = createObj(EJS_LOC_PASS(ep, loc));
+ if (vp->objectState == 0) {
+ ejsFreeVar(ep, vp);
+ return 0;
+ }
+ vp->allocatedData = 1;
+ }
+ return vp;
+}
+
+/******************************************************************************/
+/*
+ * Initialize a string value.
+ */
+
+EjsVar *ejsCreateStringVarInternal(EJS_LOC_DEC(ep, loc), const char *value)
+{
+ EjsVar *vp;
+
+ mprAssert(ep);
+
+ vp = ejsAllocVar(EJS_LOC_PASS(ep, loc));
+ mprAssert(vp);
+
+ if (vp) {
+ vp->type = EJS_TYPE_STRING;
+ vp->string = mprStrdupInternal(EJS_LOC_PASS(ep, loc), value);
+ if (vp->string == 0) {
+ ejsFreeVar(ep, vp);
+ return 0;
+ }
+ vp->length = strlen(vp->string);
+ vp->allocatedData = 1;
+ }
+ return vp;
+}
+
+/******************************************************************************/
+/*
+ * Initialize a binary string value.
+ */
+
+EjsVar *ejsCreateBinaryStringVar(Ejs *ep, const uchar *value, int len)
+{
+ EjsVar *vp;
+
+ mprAssert(ep);
+
+ vp = ejsAllocVar(EJS_LOC_ARGS(ep));
+ if (vp) {
+ vp->type = EJS_TYPE_STRING;
+ vp->length = dupString(MPR_LOC_ARGS(ep), &vp->ustring, value, len);
+ if (vp->length < 0) {
+ ejsFreeVar(ep, vp);
+ return 0;
+ }
+ vp->allocatedData = 1;
+ }
+ return vp;
+}
+
+/******************************************************************************/
+
+void ejsSetClassName(Ejs *ep, EjsVar *vp, const char *name)
+{
+ EjsObj *obj;
+
+ if (vp == 0 || !ejsVarIsObject(vp) || vp->objectState == 0) {
+ mprAssert(0);
+ return;
+ }
+ obj = vp->objectState;
+
+ if (obj->className) {
+ mprFree(obj->className);
+ }
+ obj->className = mprStrdup(ep, name);
+}
+
+/******************************************************************************/
+
+EjsVar *ejsDupVarInternal(EJS_LOC_DEC(ep, loc), EjsVar *src,
+ EjsCopyDepth copyDepth)
+{
+ EjsVar *vp;
+
+ vp = ejsAllocVar(EJS_LOC_PASS(ep, loc));
+ if (vp == 0) {
+ return 0;
+ }
+
+ vp->type = EJS_TYPE_UNDEFINED;
+
+ return copyVar(EJS_LOC_PASS(ep, loc), vp, src, copyDepth);
+}
+
+/******************************************************************************/
+/*
+ * Set a var to a new value
+ */
+
+EjsVar *ejsWriteVarInternal(EJS_LOC_DEC(ep, loc), EjsVar *dest,
+ const EjsVar *src, EjsCopyDepth copyDepth)
+{
+ mprAssert(dest);
+ mprAssert(src);
+
+ return copyVar(EJS_LOC_PASS(ep, loc), dest, src, copyDepth);
+}
+
+/******************************************************************************/
+/*
+ * Set a var using a new bool value
+ */
+
+EjsVar *ejsWriteVarAsBoolean(Ejs *ep, EjsVar *dest, int value)
+{
+ mprAssert(dest);
+
+ if (dest->type != EJS_TYPE_UNDEFINED) {
+ ejsClearVar(ep, dest);
+ }
+
+ dest->type = EJS_TYPE_BOOL;
+ dest->boolean = value;
+ dest->allocatedData = 0;
+ dest->flags = 0;
+
+ return dest;
+}
+
+/******************************************************************************/
+/*
+ * Set a var using a new C Method
+ */
+
+EjsVar *ejsWriteVarAsCMethod(Ejs *ep, EjsVar *dest, EjsCMethod fn,
+ void *userData, int flags)
+{
+ mprAssert(dest);
+
+ if (dest->type != EJS_TYPE_UNDEFINED) {
+ ejsClearVar(ep, dest);
+ }
+
+ dest->type = EJS_TYPE_CMETHOD;
+ dest->cMethod.fn = fn;
+ dest->cMethod.userData = userData;
+ dest->flags = flags;
+ dest->allocatedData = 0;
+
+ return dest;
+}
+
+/******************************************************************************/
+#if BLD_FEATURE_FLOATING_POINT
+/*
+ * Set a var using a new float value
+ */
+
+EjsVar *ejsWriteVarAsFloat(Ejs *ep, EjsVar *dest, double value)
+{
+ mprAssert(dest);
+
+ if (dest->type != EJS_TYPE_UNDEFINED) {
+ ejsClearVar(ep, dest);
+ }
+
+ dest->type = EJS_TYPE_FLOAT;
+ dest->floating = value;
+ dest->allocatedData = 0;
+ dest->flags = 0;
+
+ return dest;
+}
+
+#endif
+/******************************************************************************/
+/*
+ * Set a var using a new integer value
+ */
+
+EjsVar *ejsWriteVarAsInteger(Ejs *ep, EjsVar *dest, int value)
+{
+ mprAssert(dest);
+
+ if (dest->type != EJS_TYPE_UNDEFINED) {
+ ejsClearVar(ep, dest);
+ }
+
+ dest->type = EJS_TYPE_INT;
+ dest->integer = value;
+ dest->allocatedData = 0;
+ dest->flags = 0;
+
+ return dest;
+}
+
+/******************************************************************************/
+#if BLD_FEATURE_INT64
+/*
+ * Set a var using a new integer value
+ */
+
+EjsVar *ejsWriteVarAsInteger64(Ejs *ep, EjsVar *dest, int64 value)
+{
+ mprAssert(dest);
+
+ if (dest->type != EJS_TYPE_UNDEFINED) {
+ ejsClearVar(ep, dest);
+ }
+
+ dest->type = EJS_TYPE_INT64;
+ dest->integer64 = value;
+ dest->allocatedData = 0;
+ dest->flags = 0;
+
+ return dest;
+}
+
+#endif
+/******************************************************************************/
+/*
+ * Set a var using a new Method
+ */
+
+EjsVar *ejsWriteVarAsMethod(Ejs *ep, EjsVar *dest, const char *body,
+ MprArray *args)
+{
+ EjsVar **srcArgs, *arg;
+ int i;
+
+ mprAssert(ep);
+ mprAssert(dest);
+ mprAssert(body);
+
+ if (dest->type != EJS_TYPE_UNDEFINED) {
+ ejsClearVar(ep, dest);
+ }
+
+ dest->method.args = mprCreateItemArray(ep, EJS_INC_ARGS, EJS_MAX_ARGS);
+ if (dest->method.args == 0) {
+ return 0;
+ }
+
+ dest->type = EJS_TYPE_METHOD;
+
+ if (args) {
+ srcArgs = (EjsVar**) args->items;
+ for (i = 0; i < args->length; i++) {
+ arg = ejsDupVar(ep, srcArgs[i], EJS_SHALLOW_COPY);
+ if (arg == 0) {
+ return 0;
+ }
+ if (mprAddItem(dest->method.args, arg) < 0) {
+ return 0;
+ }
+ }
+ }
+
+ dest->method.body = mprStrdup(dest->method.args, body);
+ if (dest->method.body == 0) {
+ return 0;
+ }
+
+ dest->allocatedData = 1;
+ dest->flags = 0;
+
+ return dest;
+}
+
+/******************************************************************************/
+/*
+ * Set a var to null
+ */
+
+EjsVar *ejsWriteVarAsNull(Ejs *ep, EjsVar *dest)
+{
+ mprAssert(dest);
+
+ if (dest->type != EJS_TYPE_UNDEFINED) {
+ ejsClearVar(ep, dest);
+ }
+
+ dest->type = EJS_TYPE_NULL;
+ dest->allocatedData = 0;
+ dest->flags = 0;
+
+ return dest;
+}
+
+/******************************************************************************/
+/*
+ * Set a var using a new number value
+ */
+
+EjsVar *ejsWriteVarAsNumber(Ejs *ep, EjsVar *dest, EjsNum value)
+{
+ mprAssert(dest);
+
+ if (dest->type != EJS_TYPE_UNDEFINED) {
+ ejsClearVar(ep, dest);
+ }
+
+ dest->type = EJS_NUM_VAR;
+ dest->ejsNumber = value;
+ dest->allocatedData = 0;
+ dest->flags = 0;
+
+ return dest;
+}
+
+/******************************************************************************/
+/*
+ * Set a var using a new C Method
+ */
+
+EjsVar *ejsWriteVarAsStringCMethod(Ejs *ep, EjsVar *dest, EjsStringCMethod fn,
+ void *userData, int flags)
+{
+ mprAssert(dest);
+
+ if (dest->type != EJS_TYPE_UNDEFINED) {
+ ejsClearVar(ep, dest);
+ }
+
+ dest->type = EJS_TYPE_CMETHOD;
+ dest->cMethodWithStrings.fn = fn;
+ dest->cMethodWithStrings.userData = userData;
+ dest->flags = flags;
+ dest->allocatedData = 0;
+
+ return dest;
+}
+
+/******************************************************************************/
+/*
+ * Set a var using a new string value
+ */
+
+EjsVar *ejsWriteVarAsStringInternal(EJS_LOC_DEC(ep, loc), EjsVar *dest,
+ const char *value)
+{
+ mprAssert(dest);
+ mprAssert(value);
+
+ if (dest->type != EJS_TYPE_UNDEFINED) {
+ ejsClearVar(ep, dest);
+ }
+
+ dest->string = mprStrdupInternal(EJS_LOC_PASS(ep, loc), value);
+ if (dest->string == 0) {
+ return 0;
+ }
+
+ dest->length = strlen(dest->string);
+
+ dest->type = EJS_TYPE_STRING;
+ dest->allocatedData = 1;
+ dest->flags = 0;
+
+ return dest;
+}
+
+/******************************************************************************/
+/*
+ * Set a var using a new string value
+ */
+
+EjsVar *ejsWriteVarAsBinaryString(Ejs *ep, EjsVar *dest, const uchar *value,
+ int len)
+{
+ mprAssert(dest);
+ mprAssert(value);
+
+ ejsClearVar(ep, dest);
+
+ if (dest->type != EJS_TYPE_UNDEFINED) {
+ ejsClearVar(ep, dest);
+ }
+
+ dest->length = dupString(MPR_LOC_ARGS(ep), &dest->ustring, value, len);
+ if (dest->length < 0) {
+ return 0;
+ }
+
+ dest->type = EJS_TYPE_STRING;
+ dest->allocatedData = 1;
+ dest->flags = 0;
+
+ return dest;
+}
+
+/******************************************************************************/
+/*
+ * Set a var to undefined
+ */
+
+EjsVar *ejsWriteVarAsUndefined(Ejs *ep, EjsVar *dest)
+{
+ mprAssert(dest);
+
+ if (dest->type != EJS_TYPE_UNDEFINED) {
+ ejsClearVar(ep, dest);
+ }
+
+ dest->type = EJS_TYPE_UNDEFINED;
+ dest->allocatedData = 0;
+ dest->flags = 0;
+
+ return dest;
+}
+
+/******************************************************************************/
+/*
+ * Convert a value to a text based representation of its value
+ * If you provide a format, you MUST ensure you know the type.
+ * Caller must free the result.
+ */
+
+char *ejsFormatVar(Ejs *ep, const char *fmt, EjsVar *vp)
+{
+ char *buf, *src, *value, *allocValue;
+ uchar *ubuf;
+ int len;
+
+ buf = 0;
+ allocValue = 0;
+ value = 0;
+
+ switch (vp->type) {
+ case EJS_TYPE_UNDEFINED:
+ value = "undefined";
+ break;
+
+ case EJS_TYPE_NULL:
+ value = "null";
+ break;
+
+ case EJS_TYPE_PTR:
+ if (fmt == NULL || *fmt == '\0') {
+ len = mprAllocSprintf(MPR_LOC_ARGS(ep), &buf, 0,
+ "[Opaque Pointer %p]", vp->ptr.userPtr);
+ } else {
+ len = mprAllocSprintf(MPR_LOC_ARGS(ep), &buf, 0, fmt, vp->ptr);
+ }
+ goto done;
+
+ case EJS_TYPE_BOOL:
+ value = (vp->boolean) ? "true" : "false";
+ break;
+
+#if BLD_FEATURE_FLOATING_POINT
+ case EJS_TYPE_FLOAT:
+ if (fmt == NULL || *fmt == '\0') {
+ fmt = "%f";
+ }
+ len = mprAllocSprintf(MPR_LOC_ARGS(ep), &buf, 0, fmt, vp->floating);
+ goto done;
+#endif
+
+ case EJS_TYPE_INT:
+ if (fmt == NULL || *fmt == '\0') {
+ fmt = "%d";
+ }
+ mprAllocSprintf(MPR_LOC_ARGS(ep), &buf, 0, fmt, vp->integer);
+ goto done;
+
+#if BLD_FEATURE_INT64
+ case EJS_TYPE_INT64:
+ if (fmt == NULL || *fmt == '\0') {
+ fmt = "%Ld";
+ }
+ mprAllocSprintf(MPR_LOC_ARGS(ep), &buf, 0, fmt, vp->integer64);
+ goto done;
+#endif
+
+ case EJS_TYPE_CMETHOD:
+ value = "[C Method]";
+ break;
+
+ case EJS_TYPE_STRING_CMETHOD:
+ value = "[C StringMethod]";
+ break;
+
+ case EJS_TYPE_METHOD:
+ value = ejsVarToString(ep, vp);
+ break;
+
+ case EJS_TYPE_OBJECT:
+ value = ejsVarToString(ep, vp);
+ break;
+
+ case EJS_TYPE_STRING:
+ src = vp->string;
+ mprAssert(src);
+
+ if (fmt && *fmt && src) {
+ mprAllocSprintf(MPR_LOC_ARGS(ep), &buf, 0, fmt, src);
+
+ } else if (src == NULL) {
+ buf = mprStrdup(ep, "null");
+
+ } else {
+ ubuf = (uchar*) buf;
+ if (dupString(MPR_LOC_ARGS(ep), &ubuf, src, vp->length) < 0) {
+ return mprStrdup(ep, "");
+ }
+ buf = (char*) ubuf;
+ }
+ break;
+
+ default:
+ mprAssert(0);
+ }
+
+ if (fmt == NULL || *fmt == '\0') {
+ len = mprAllocSprintf(MPR_LOC_ARGS(ep), &buf, 0, "%s", value);
+ } else {
+ len = mprAllocSprintf(MPR_LOC_ARGS(ep), &buf, 0, fmt, value);
+ }
+
+done:
+ if (allocValue) {
+ mprFree(allocValue);
+ }
+ return buf;
+}
+
+/******************************************************************************/
+/*
+ * Convert the variable to a boolean. Only for primitive types.
+ */
+
+int ejsVarToBoolean(EjsVar *vp)
+{
+ mprAssert(vp);
+
+ switch (vp->type) {
+ case EJS_TYPE_UNDEFINED:
+ case EJS_TYPE_NULL:
+ case EJS_TYPE_STRING_CMETHOD:
+ case EJS_TYPE_CMETHOD:
+ case EJS_TYPE_METHOD:
+ return 0;
+
+ case EJS_TYPE_OBJECT:
+ return (vp->objectState != NULL);
+
+ case EJS_TYPE_PTR:
+ return (vp->ptr.userPtr != NULL);
+
+ case EJS_TYPE_BOOL:
+ return vp->boolean;
+
+#if BLD_FEATURE_FLOATING_POINT
+ case EJS_TYPE_FLOAT:
+ return (vp->floating != 0 && !ejsIsNan(vp->floating));
+#endif
+
+ case EJS_TYPE_INT:
+ return (vp->integer != 0);
+
+#if BLD_FEATURE_INT64
+ case EJS_TYPE_INT64:
+ return (vp->integer64 != 0);
+#endif
+
+ case EJS_TYPE_STRING:
+ return (vp->length > 0);
+#if UNUSED
+ if (strcmp(vp->string, "true") == 0 ||
+ strcmp(vp->string, "TRUE") == 0) {
+ return 1;
+
+ } else if (strcmp(vp->string, "false") == 0 ||
+ strcmp(vp->string, "FALSE") == 0) {
+ return 0;
+
+ } else {
+ return atoi(vp->string);
+ }
+#endif
+ }
+
+ /* Not reached */
+ return 0;
+}
+
+/******************************************************************************/
+#if BLD_FEATURE_FLOATING_POINT
+/*
+ * Convert the variable to a floating point number. Only for primitive types.
+ */
+
+double ejsVarToFloat(EjsVar *vp)
+{
+ mprAssert(vp);
+
+ switch (vp->type) {
+ case EJS_TYPE_UNDEFINED:
+ case EJS_TYPE_NULL:
+ case EJS_TYPE_STRING_CMETHOD:
+ case EJS_TYPE_CMETHOD:
+ case EJS_TYPE_METHOD:
+ case EJS_TYPE_OBJECT:
+ case EJS_TYPE_PTR:
+ return 0;
+
+ case EJS_TYPE_BOOL:
+ return (vp->boolean) ? 1.0 : 0.0;
+
+ case EJS_TYPE_FLOAT:
+ return vp->floating;
+
+ case EJS_TYPE_INT:
+ return (double) vp->integer;
+
+#if BLD_FEATURE_INT64
+ case EJS_TYPE_INT64:
+ return (double) vp->integer64;
+#endif
+
+ case EJS_TYPE_STRING:
+ if (vp->length == 0) {
+ return 0.0;
+ } else {
+ return atof(vp->string);
+ }
+ }
+
+ /* Not reached */
+ return 0;
+}
+
+#endif
+/******************************************************************************/
+/*
+ * Convert the variable to an Integer type. Only works for primitive types.
+ */
+
+int ejsVarToInteger(EjsVar *vp)
+{
+ mprAssert(vp);
+
+ switch (vp->type) {
+ case EJS_TYPE_UNDEFINED:
+ case EJS_TYPE_NULL:
+ case EJS_TYPE_STRING_CMETHOD:
+ case EJS_TYPE_CMETHOD:
+ case EJS_TYPE_METHOD:
+ case EJS_TYPE_OBJECT:
+ return 0;
+
+ case EJS_TYPE_BOOL:
+ return (vp->boolean) ? 1 : 0;
+
+#if BLD_FEATURE_FLOATING_POINT
+ case EJS_TYPE_FLOAT:
+ if (ejsIsNan(vp->floating)) {
+ return 0;
+ }
+ return (int) vp->floating;
+#endif
+
+ case EJS_TYPE_INT:
+ return vp->integer;
+
+#if BLD_FEATURE_INT64
+ case EJS_TYPE_INT64:
+ return (int) vp->integer64;
+#endif
+
+ case EJS_TYPE_STRING:
+ if (vp->length == 0) {
+ return 0;
+ } else {
+ return ejsParseInteger(vp->string);
+ }
+ }
+
+ /* Not reached */
+ return 0;
+}
+
+/******************************************************************************/
+#if BLD_FEATURE_INT64
+/*
+ * Convert the variable to an Integer64 type. Only works for primitive types.
+ */
+
+int64 ejsVarToInteger64(EjsVar *vp)
+{
+ mprAssert(vp);
+
+ switch (vp->type) {
+ case EJS_TYPE_UNDEFINED:
+ case EJS_TYPE_NULL:
+ case EJS_TYPE_STRING_CMETHOD:
+ case EJS_TYPE_CMETHOD:
+ case EJS_TYPE_METHOD:
+ case EJS_TYPE_OBJECT:
+ case EJS_TYPE_PTR:
+ return 0;
+
+ case EJS_TYPE_BOOL:
+ return (vp->boolean) ? 1 : 0;
+
+#if BLD_FEATURE_FLOATING_POINT
+ case EJS_TYPE_FLOAT:
+ if (ejsIsNan(vp->floating)) {
+ return 0;
+ }
+ return (int64) vp->floating;
+#endif
+
+ case EJS_TYPE_INT:
+ return vp->integer;
+
+ case EJS_TYPE_INT64:
+ return vp->integer64;
+
+ case EJS_TYPE_STRING:
+ if (vp->length == 0) {
+ return 0;
+ } else {
+ return ejsParseInteger64(vp->string);
+ }
+ }
+
+ /* Not reached */
+ return 0;
+}
+
+#endif /* BLD_FEATURE_INT64 */
+/******************************************************************************/
+/*
+ * Convert the variable to a number type. Only works for primitive types.
+ */
+
+EjsNum ejsVarToNumber(EjsVar *vp)
+{
+#if BLD_FEATURE_NUM_TYPE_ID == EJS_TYPE_INT64
+ return ejsVarToInteger64(vp);
+#elif BLD_FEATURE_NUM_TYPE_ID == EJS_TYPE_FLOAT
+ return ejsVarToFloat(vp);
+#else
+ return ejsVarToInteger(vp);
+#endif
+}
+
+/******************************************************************************/
+/*
+ * Convert a var to a string. Store the result in ep->castTemp. If allocated
+ * set ep->castAlloc to TRUE. Caller must NOT free the result.
+ */
+
+char *ejsVarToString(Ejs *ep, EjsVar *vp)
+{
+ MprBuf *bp;
+ char numBuf[16];
+ int len, i;
+
+ if (ep->castAlloc) {
+ mprFree(ep->castTemp);
+ }
+ ep->castTemp = 0;
+ ep->castAlloc = 0;
+
+ switch (vp->type) {
+ case EJS_TYPE_UNDEFINED:
+ ep->castTemp = "undefined";
+ break;
+
+ case EJS_TYPE_NULL:
+ ep->castTemp = "null";
+ break;
+
+ case EJS_TYPE_PTR:
+ len = mprAllocSprintf(MPR_LOC_ARGS(ep), &ep->castTemp, 0,
+ "[Opaque Pointer %p]", vp->ptr.userPtr);
+ ep->castAlloc = 1;
+ break;
+
+ case EJS_TYPE_BOOL:
+ if (vp->boolean) {
+ ep->castTemp = "true";
+ } else {
+ ep->castTemp = "false";
+ }
+ break;
+
+#if BLD_FEATURE_FLOATING_POINT
+ case EJS_TYPE_FLOAT:
+ len = mprAllocSprintf(MPR_LOC_ARGS(ep), &ep->castTemp, 0,
+ "%f", vp->floating);
+ ep->castAlloc = 1;
+ break;
+#endif
+
+ case EJS_TYPE_INT:
+ mprItoa(numBuf, sizeof(numBuf), vp->integer);
+ ep->castTemp = mprStrdup(ep, numBuf);
+ ep->castAlloc = 1;
+ break;
+
+#if BLD_FEATURE_INT64
+ case EJS_TYPE_INT64:
+ mprAllocSprintf(MPR_LOC_ARGS(ep), &ep->castTemp, 0,
+ "%Ld", vp->integer64);
+ ep->castAlloc = 1;
+ break;
+#endif
+
+ case EJS_TYPE_CMETHOD:
+ ep->castTemp = "[C Method]";
+ break;
+
+ case EJS_TYPE_STRING_CMETHOD:
+ ep->castTemp = "[C StringMethod]";
+ break;
+
+ case EJS_TYPE_METHOD:
+ bp = mprCreateBuf(ep, 0, 0);
+ mprPutStringToBuf(bp, "function (");
+ for (i = 0; i < vp->method.args->length; i++) {
+ mprPutStringToBuf(bp, vp->method.args->items[i]);
+ if ((i + 1) < vp->method.args->length) {
+ mprPutStringToBuf(bp, ", ");
+ }
+ }
+ mprPutStringToBuf(bp, ") {");
+ mprPutStringToBuf(bp, vp->method.body);
+ mprPutStringToBuf(bp, "}");
+ mprAddNullToBuf(bp);
+ ep->castTemp = mprStealBuf(ep, bp);
+ ep->castAlloc = 1;
+ mprFree(bp);
+ break;
+
+ case EJS_TYPE_OBJECT:
+ if (ejsRunMethod(ep, vp, "toString", 0) < 0) {
+ return mprStrdup(ep, "[object Object]");
+ }
+ ep->castTemp = mprStrdup(ep, ep->result->string);
+ ep->castAlloc = 1;
+ break;
+
+ case EJS_TYPE_STRING:
+ if (vp->string == 0) {
+ ep->castTemp = "null";
+ } else {
+ ep->castTemp = vp->string;
+ }
+ break;
+
+ default:
+ mprAssert(0);
+ }
+
+ mprAssert(ep->castTemp);
+ return ep->castTemp;
+}
+
+/******************************************************************************/
+
+char *ejsVarToStringEx(Ejs *ep, EjsVar *vp, bool *alloc)
+{
+ char *str;
+
+ mprAssert(alloc);
+
+ str = ejsVarToString(ep, vp);
+ *alloc = ep->castAlloc;
+ ep->castAlloc = 0;
+ ep->castTemp = 0;
+ return str;
+}
+
+/******************************************************************************/
+/*
+ * Parse a string based on formatting instructions and intelligently
+ * create a variable.
+ *
+ * Float format: [+|-]DIGITS][DIGITS][(e|E)[+|-]DIGITS]
+ */
+
+EjsVar *ejsParseVar(Ejs *ep, const char *buf, EjsType preferredType)
+{
+ EjsType type;
+ const char *cp;
+ int isHex;
+
+ mprAssert(buf);
+
+ type = preferredType;
+
+ if (preferredType == EJS_TYPE_UNDEFINED) {
+ isHex = 0;
+ if (*buf == '-' || *buf == '+') {
+ type = EJS_NUM_VAR;
+
+ } else if (!isdigit((int) *buf)) {
+ if (strcmp(buf, "true") == 0 || strcmp(buf, "false") == 0) {
+ type = EJS_TYPE_BOOL;
+ } else {
+ type = EJS_TYPE_STRING;
+ }
+
+ } else if (isdigit((int) *buf)) {
+ type = EJS_NUM_VAR;
+ cp = buf;
+ if (*cp && tolower(cp[1]) == 'x') {
+ cp = &cp[2];
+ isHex = 1;
+ for (cp = buf; *cp; cp++) {
+ if (! isxdigit((int) *cp)) {
+ break;
+ }
+ }
+ } else {
+#if BLD_FEATURE_FLOATING_POINT
+ /* Could be integer or float */
+ for (cp = buf; *cp; cp++) {
+ if (! isdigit((int) *cp)) {
+ int c = tolower(*cp);
+ if (c == '.' || c == 'e' || c == 'f') {
+ type = EJS_TYPE_FLOAT;
+ break;
+ }
+ }
+ }
+#endif
+ }
+ }
+ }
+
+ switch (type) {
+ case EJS_TYPE_OBJECT:
+ case EJS_TYPE_UNDEFINED:
+ case EJS_TYPE_NULL:
+ case EJS_TYPE_PTR:
+ default:
+ break;
+
+ case EJS_TYPE_BOOL:
+ return ejsCreateBoolVar(ep, ejsParseBoolean(buf));
+
+ case EJS_TYPE_INT:
+ return ejsCreateIntegerVar(ep, ejsParseInteger(buf));
+
+#if BLD_FEATURE_INT64
+ case EJS_TYPE_INT64:
+ return ejsCreateInteger64Var(ep, ejsParseInteger64(buf));
+#endif
+
+ case EJS_TYPE_STRING:
+ if (strcmp(buf, "null") == 0) {
+ return ejsCreateNullVar(ep);
+
+ } else if (strcmp(buf, "undefined") == 0) {
+ return ejsCreateUndefinedVar(ep);
+ }
+
+ return ejsCreateStringVar(ep, buf);
+
+#if BLD_FEATURE_FLOATING_POINT
+ case EJS_TYPE_FLOAT:
+ return ejsCreateFloatVar(ep, atof(buf));
+#endif
+
+ }
+ return ejsCreateUndefinedVar(ep);
+}
+
+/******************************************************************************/
+/*
+ * Convert the variable to a number type. Only works for primitive types.
+ */
+
+bool ejsParseBoolean(const char *s)
+{
+ if (s == 0 || *s == '\0') {
+ return 0;
+ }
+ if (strcmp(s, "false") == 0 || strcmp(s, "FALSE") == 0) {
+ return 0;
+ }
+ return 1;
+}
+
+/******************************************************************************/
+/*
+ * Convert the variable to a number type. Only works for primitive types.
+ */
+
+EjsNum ejsParseNumber(const char *s)
+{
+#if BLD_FEATURE_NUM_TYPE_ID == EJS_TYPE_INT64
+ return ejsParseInteger64(s);
+#elif BLD_FEATURE_NUM_TYPE_ID == EJS_TYPE_FLOAT
+ return ejsParseFloat(s);
+#else
+ return ejsParseInteger(s);
+#endif
+}
+
+/******************************************************************************/
+#if BLD_FEATURE_INT64
+/*
+ * Convert the string buffer to an Integer64.
+ */
+
+int64 ejsParseInteger64(const char *str)
+{
+ const char *cp;
+ int64 num64;
+ int radix, c, negative;
+
+ mprAssert(str);
+
+ cp = str;
+ num64 = 0;
+ negative = 0;
+
+ if (*cp == '-') {
+ cp++;
+ negative = 1;
+ } else if (*cp == '+') {
+ cp++;
+ }
+
+ /*
+ * 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(*cp) == 'x') {
+ cp++;
+ radix = 16;
+ while (*cp) {
+ c = tolower(*cp);
+ if (isdigit(c)) {
+ num64 = (c - '0') + (num64 * radix);
+ } else if (c >= 'a' && c <= 'f') {
+ num64 = (c - 'a' + 10) + (num64 * radix);
+ } else {
+ break;
+ }
+ cp++;
+ }
+
+ } else{
+ radix = 8;
+ while (*cp) {
+ c = tolower(*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 string buffer to an Integer.
+ */
+
+int ejsParseInteger(const char *str)
+{
+ const char *cp;
+ int num;
+ int radix, c, negative;
+
+ mprAssert(str);
+
+ cp = str;
+ num = 0;
+ negative = 0;
+
+ if (*cp == '-') {
+ cp++;
+ negative = 1;
+ } else if (*cp == '+') {
+ cp++;
+ }
+
+ /*
+ * 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(*cp) == 'x') {
+ cp++;
+ radix = 16;
+ while (*cp) {
+ c = tolower(*cp);
+ if (isdigit(c)) {
+ num = (c - '0') + (num * radix);
+ } else if (c >= 'a' && c <= 'f') {
+ num = (c - 'a' + 10) + (num * radix);
+ } else {
+ break;
+ }
+ cp++;
+ }
+
+ } else{
+ radix = 8;
+ while (*cp) {
+ c = tolower(*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 ejsParseFloat(const char *str)
+{
+ return atof(str);
+}
+
+/******************************************************************************/
+
+int ejsIsNan(double f)
+{
+#if WIN
+ return _isnan(f);
+#elif VXWORKS
+ /* FUTURE */
+ return (0);
+#else
+ return (f == FP_NAN);
+#endif
+}
+/******************************************************************************/
+
+int ejsIsInfinite(double f)
+{
+#if WIN
+ return !_finite(f);
+#elif VXWORKS
+ /* FUTURE */
+ return (0);
+#else
+ return (f == FP_INFINITE);
+#endif
+}
+
+#endif /* BLD_FEATURE_FLOATING_POINT */
+
+/******************************************************************************/
+/*
+ * Single point of control for all assignment to properties.
+ *
+ * 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 EjsVar *copyVar(EJS_LOC_DEC(ep, loc), EjsVar *dest, const EjsVar *src,
+ EjsCopyDepth copyDepth)
+{
+ Ejs *ejsContext;
+ EjsObj *srcObj;
+ EjsProperty *destp;
+ const char **srcArgs;
+ char *str;
+ int i;
+
+ mprAssert(dest);
+ mprAssert(src);
+
+ if (dest == src) {
+ return dest;
+ }
+
+ if (dest->type != EJS_TYPE_UNDEFINED) {
+ ejsClearVar(ep, dest);
+ }
+
+ dest->allocatedData = 0;
+
+ switch (src->type) {
+ default:
+ case EJS_TYPE_UNDEFINED:
+ case EJS_TYPE_NULL:
+ break;
+
+ case EJS_TYPE_BOOL:
+ dest->boolean = src->boolean;
+ break;
+
+ case EJS_TYPE_PTR:
+ dest->ptr = src->ptr;
+ if (dest->ptr.destructor) {
+ dest->allocatedData = 1;
+ }
+ break;
+
+ case EJS_TYPE_STRING_CMETHOD:
+ dest->cMethodWithStrings = src->cMethodWithStrings;
+ break;
+
+ case EJS_TYPE_CMETHOD:
+ dest->cMethod = src->cMethod;
+ break;
+
+#if BLD_FEATURE_FLOATING_POINT
+ case EJS_TYPE_FLOAT:
+ dest->floating = src->floating;
+ break;
+#endif
+
+ case EJS_TYPE_INT:
+ dest->integer = src->integer;
+ break;
+
+#if BLD_FEATURE_INT64
+ case EJS_TYPE_INT64:
+ dest->integer64 = src->integer64;
+ break;
+#endif
+
+ case EJS_TYPE_OBJECT:
+ if (copyDepth == EJS_SHALLOW_COPY) {
+
+ /*
+ * If doing a shallow copy and the src object is from the same
+ * interpreter, or we are copying from the master interpreter, or
+ * we are using a shared slab, then we can do a shallow copy.
+ * Otherwise, we must do a deep copy.
+ */
+ srcObj = src->objectState;
+ if (srcObj->ejs == ep || srcObj->ejs == ep->service->master ||
+ (ep->flags & EJS_FLAGS_SHARED_SLAB)) {
+ dest->objectState = src->objectState;
+ dest->allocatedData = 1;
+ break;
+ }
+ }
+
+ /*
+ * Doing a deep or recursive deep. Can get here if doing a shallow
+ * copy and the object is from another non-master interpeter and not
+ * using a shared slab.
+ *
+ * We must make sure the data is allocated using the right memory
+ * context. It must be the same as the destination parent object.
+ * Otherwise, when we free the property memory, the parent may
+ * have a dangling pointer.
+ */
+ if (dest->isProperty) {
+ destp = ejsGetPropertyPtr(dest);
+ if (destp->parentObj == 0) {
+ ejsContext = ep;
+
+ } else {
+ mprAssert(destp->parentObj);
+ ejsContext = destp->parentObj->ejs;
+ mprAssert(ejsContext);
+ }
+
+ } else {
+ ejsContext = ep;
+ }
+
+ dest->objectState = createObj(EJS_LOC_PASS(ejsContext, loc));
+ if (dest->objectState == 0) {
+ /* Memory Error */
+ return 0;
+ }
+
+ dest->objectState->baseClass = src->objectState->baseClass;
+ dest->objectState->methods = src->objectState->methods;
+ dest->objectState->noConstructor = src->objectState->noConstructor;
+ dest->objectState->objName =
+ mprStrdup(ejsContext, src->objectState->objName);
+
+ if (dest->objectState->objName == 0) {
+ return 0;
+ }
+
+ if (ejsCopyProperties(ep, dest, src, copyDepth) == 0) {
+ return 0;
+ }
+ dest->allocatedData = 1;
+ break;
+
+ case EJS_TYPE_METHOD:
+ dest->method.args = mprCreateItemArray(ep, EJS_INC_ARGS,
+ EJS_MAX_ARGS);
+ if (dest->method.args == 0) {
+ return 0;
+ }
+ dest->allocatedData = 1;
+ if (src->method.args) {
+ srcArgs = (const char**) src->method.args->items;
+ for (i = 0; i < src->method.args->length; i++) {
+ str = mprStrdupInternal(EJS_LOC_PASS(dest->method.args,
+ loc), srcArgs[i]);
+ if (str == 0) {
+ mprFree(dest->method.args);
+ dest->method.args = 0;
+ return 0;
+ }
+ if (mprAddItem(dest->method.args, str) < 0) {
+ mprFree(dest->method.args);
+ dest->method.args = 0;
+ return 0;
+ }
+ }
+ }
+ dest->method.body = mprStrdup(dest->method.args, src->method.body);
+ if (dest->method.body == 0) {
+ mprFree(dest->method.args);
+ dest->method.args = 0;
+ return 0;
+ }
+ dest->callsSuper = src->callsSuper;
+ break;
+
+ case EJS_TYPE_STRING:
+ dest->length = src->length;
+ if (src->string) {
+ /* Shallow, deep or recursive deep */
+ dest->length = dupString(MPR_LOC_PASS(ep, loc), &dest->ustring,
+ src->ustring, src->length);
+ if (dest->length < 0) {
+ return 0;
+ }
+ dest->allocatedData = 1;
+
+ } else {
+ dest->string = src->string;
+ dest->allocatedData = 0;
+ }
+ break;
+ }
+
+ dest->type = src->type;
+ dest->flags = src->flags;
+ dest->isArray = src->isArray;
+
+ return dest;
+}
+
+/******************************************************************************/
+/*
+ * Copy all properies in an object. Must preserve property order
+ */
+
+EjsVar *ejsCopyProperties(Ejs *ep, EjsVar *dest, const EjsVar *src,
+ EjsCopyDepth copyDepth)
+{
+ EjsProperty *srcProp, *destProp, *last, *next;
+ int propertyIndex;
+
+ srcProp = ejsGetFirstProperty(src, EJS_ENUM_ALL);
+ while (srcProp) {
+ next = ejsGetNextProperty(srcProp, EJS_ENUM_ALL);
+ if (srcProp->visited) {
+ srcProp = next;
+ continue;
+ }
+
+ /*
+ * This finds the last variable in the hash chain
+ * FUTURE OPT. This is slow. If used double link, we could locate the
+ * tail more easily.
+ */
+ destProp = hashLookup(dest->objectState, srcProp->name,
+ &propertyIndex, &last);
+ mprAssert(destProp == 0);
+
+ destProp = allocProperty(ep, dest, srcProp->name, propertyIndex, last);
+ if (destProp == 0) {
+ mprAssert(destProp);
+ return 0;
+ }
+
+ /*
+ * Recursively copy the object. If DEEP_COPY, then we
+ * will do a shallow copy of the object contents. If
+ * RECURSIVE_DEEP, then we do a deep copy at all levels.
+ */
+ srcProp->visited = 1;
+
+ if (copyVar(EJS_LOC_ARGS(ep), ejsGetVarPtr(destProp),
+ ejsGetVarPtr(srcProp),
+ (copyDepth == EJS_DEEP_COPY) ? EJS_SHALLOW_COPY : copyDepth)
+ == 0) {
+ return 0;
+ }
+ srcProp->visited = 0;
+
+ srcProp = next;
+ }
+ return dest;
+}
+
+/******************************************************************************/
+/********************************** Properties ********************************/
+/******************************************************************************/
+/*
+ * Create a property in an object and return a pointer to it. If the property
+ * already exists then just return a pointer to it (no error).
+ * To test for existance of a property, use GetProperty
+ */
+
+static EjsProperty *hashLookup(EjsObj *obj, const char *property,
+ int *propertyIndex, EjsProperty **hashTail)
+{
+ EjsProperty *prop, *last;
+ int index;
+
+ mprAssert(obj);
+ mprAssert(property);
+
+ if (obj == 0 || property == 0 || *property == '\0') {
+ mprAssert(0);
+ return 0;
+ }
+
+ /*
+ * Find the property in the hash chain if it exists
+ */
+ index = hash(property);
+ prop = obj->propertyHash[index];
+ for (last = 0; prop != 0; last = prop, prop = prop->hashNext) {
+ if (prop->name[0] == property[0] &&
+ strcmp(prop->name, property) == 0) {
+ break;
+ }
+ }
+ if (propertyIndex) {
+ *propertyIndex = index;
+ }
+ if (hashTail) {
+ *hashTail = last;
+ }
+
+ return prop;
+}
+
+/******************************************************************************/
+/*
+ * Create a property in an object and return a pointer to it. If the property
+ * already exists then just return a pointer to it (no error). If the property
+ * does not exist, create an undefined variable. To test for existance of a
+ * property, use GetProperty.
+ */
+
+EjsProperty *ejsCreateSimpleProperty(Ejs *ep, EjsVar *op, const char *property)
+{
+ EjsProperty *prop, *last;
+ int propertyIndex;
+
+ if (op == 0 || op->type != EJS_TYPE_OBJECT || property == 0 ||
+ *property == '\0') {
+ mprAssert(0);
+ return 0;
+ }
+
+ /*
+ * Find the property in the hash chain if it exists
+ */
+ prop = hashLookup(op->objectState, property, &propertyIndex, &last);
+
+ if (prop == 0) {
+ /*
+ * Create a new property
+ */
+ prop = allocProperty(ep, op, property, propertyIndex, last);
+ if (prop == 0) {
+ mprAssert(prop == 0);
+ return 0;
+ }
+ }
+ return prop;
+}
+
+/******************************************************************************/
+/*
+ * Create a property in an object and return a pointer to it. If the property
+ * already exists then just return a pointer to it (no error).
+ * To test for existance of a property, use GetProperty
+ */
+
+EjsProperty *ejsCreateSimpleNonUniqueProperty(Ejs *ep, EjsVar *op,
+ const char *property)
+{
+ EjsProperty *prop, *last;
+ int propertyIndex;
+
+ if (op == 0 || op->type != EJS_TYPE_OBJECT || property == 0 ||
+ *property == '\0') {
+ mprAssert(0);
+ return 0;
+ }
+
+ /*
+ * Find end of chain
+ */
+ propertyIndex = hash(property);
+ prop = op->objectState->propertyHash[propertyIndex];
+ for (last = 0; prop != 0; last = prop, prop = prop->hashNext) {
+ ;
+ }
+
+ return allocProperty(ep, op, property, propertyIndex, last);
+}
+
+/******************************************************************************/
+/*
+ * Find a property in an object and return a pointer to it.
+ * This does NOT traverse base classes.
+ */
+
+EjsProperty *ejsGetSimpleProperty(Ejs *ep, EjsVar *op, const char *property)
+{
+ mprAssert(op);
+ mprAssert(op->type == EJS_TYPE_OBJECT);
+ mprAssert(property && *property);
+
+ /*
+ * This is an internal API. It has very little checking.
+ */
+ return hashLookup(op->objectState, property, 0, 0);
+}
+
+/******************************************************************************/
+
+/*
+ * NOTE: There is no ejsSetSimpleProperty as all the ejsSetProperty routines
+ * operate only on the instance and don't follow base classes. ie. there is
+ * no simple version required. However, there is a ejsSetBaseProperty routine
+ * that will follow base classes and is used to set static properties in base
+ * classes
+ */
+
+/******************************************************************************/
+/******************************* Property Access ******************************/
+/******************************************************************************/
+/*
+ * The property get routines follow base classes and utilize the propery
+ * method access routines. The property set routines do not follow base
+ * classes. The property ejsSetBase... routines do follow base classes.
+ */
+
+/*
+ * Find a property in an object and return a pointer to it.
+ * This follows base classes.
+ */
+
+EjsProperty *ejsGetProperty(Ejs *ep, EjsVar *op, const char *property)
+{
+ EjsVar *vp, *newOp;
+ int maxBaseClasses = 50;
+
+ do {
+ if (op->type != EJS_TYPE_OBJECT) {
+ mprAssert(op->type == EJS_TYPE_OBJECT);
+ return 0;
+ }
+ mprAssert(op->objectState);
+
+ vp = ejsGetPropertyMethod(ep, op, property);
+ if (vp != 0) {
+ /*
+ * Found
+ */
+ break;
+ }
+
+ newOp = op->objectState->baseClass;
+ if (newOp == 0) {
+ if (op->objectState != ep->objectClass->objectState) {
+ newOp = ep->objectClass;
+ }
+ }
+ op = newOp;
+
+ /*
+ * A little bit of sanity checking
+ */
+ if (--maxBaseClasses <= 0) {
+ mprAssert(maxBaseClasses > 0);
+ break;
+ }
+
+ } while (op);
+
+ return ejsGetPropertyPtr(vp);
+}
+
+/******************************************************************************/
+/*
+ * Get the property's variable. Optionally create if it does not exist.
+ */
+
+EjsVar *ejsGetPropertyAsVar(Ejs *ep, EjsVar *vp, const char *property)
+{
+ return ejsGetVarPtr(ejsGetProperty(ep, vp, property));
+}
+
+/******************************************************************************/
+/*
+ * Get the property's value as a binary string.
+ */
+
+const uchar *ejsGetPropertyAsBinaryString(Ejs *ep, EjsVar *obj,
+ const char *property, int *length)
+{
+ EjsVar *vp;
+
+ vp = ejsGetVarPtr(ejsGetProperty(ep, obj, property));
+ if (vp == 0 || ejsVarIsUndefined(vp)) {
+ return 0;
+ }
+
+ if (vp->type == EJS_TYPE_STRING) {
+ if (length) {
+ *length = vp->length;
+ }
+ return vp->ustring;
+ }
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * Get the property's value as a string.
+ */
+
+const char *ejsGetPropertyAsString(Ejs *ep, EjsVar *obj, const char *property)
+{
+ EjsVar *vp;
+
+ vp = ejsGetVarPtr(ejsGetProperty(ep, obj, property));
+ if (vp == 0 || ejsVarIsUndefined(vp)) {
+ return 0;
+ }
+
+ if (vp->type == EJS_TYPE_STRING) {
+ return vp->string;
+ }
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * Get the property's value as a number.
+ */
+
+BLD_FEATURE_NUM_TYPE ejsGetPropertyAsNumber(Ejs *ep, EjsVar *obj,
+ const char *property)
+{
+ EjsVar *vp;
+
+ vp = ejsGetVarPtr(ejsGetProperty(ep, obj, property));
+ if (vp == 0 || ejsVarIsUndefined(vp)) {
+ return 0;
+ }
+
+ return ejsVarToNumber(vp);
+}
+
+/******************************************************************************/
+/*
+ * Get the property's value as a integer.
+ */
+
+int ejsGetPropertyAsInteger(Ejs *ep, EjsVar *obj, const char *property)
+{
+ EjsVar *vp;
+
+ vp = ejsGetVarPtr(ejsGetProperty(ep, obj, property));
+ if (vp == 0 || ejsVarIsUndefined(vp)) {
+ return 0;
+ }
+
+ return ejsVarToInteger(vp);
+}
+
+/******************************************************************************/
+/*
+ * Get the property's value as a boolean.
+ */
+
+bool ejsGetPropertyAsBoolean(Ejs *ep, EjsVar *obj, const char *property)
+{
+ EjsVar *vp;
+
+ vp = ejsGetVarPtr(ejsGetProperty(ep, obj, property));
+ if (vp == 0 || ejsVarIsUndefined(vp)) {
+ return 0;
+ }
+
+ return ejsVarToBoolean(vp);
+}
+
+/******************************************************************************/
+/*
+ * Get the property's value as a pointer.
+ */
+
+void *ejsGetPropertyAsPtr(Ejs *ep, EjsVar *obj, const char *property)
+{
+ EjsVar *vp;
+
+ vp = ejsGetVarPtr(ejsGetProperty(ep, obj, property));
+ if (vp == 0 || ejsVarIsUndefined(vp)) {
+ return 0;
+ }
+ if (vp->type == EJS_TYPE_PTR) {
+ return vp->ptr.userPtr;
+ }
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * Create a property in the object. This will override any base class
+ * properties.
+ *
+ * MOB -- need to spell out the difference between ejsSetProperty and
+ * ejsCreateProperty.
+ */
+
+EjsProperty *ejsCreateProperty(Ejs *ep, EjsVar *obj, const char *property)
+{
+ EjsVar *vp;
+
+ vp = ejsCreatePropertyMethod(ep, obj, property);
+ return ejsGetPropertyPtr(vp);
+}
+
+/******************************************************************************/
+/*
+ * Set a property's variable value. Create the property if it does not exist.
+ * This routine DOES follow base classes.
+ */
+
+EjsProperty *ejsSetBaseProperty(Ejs *ep, EjsVar *op, const char *property,
+ const EjsVar *value)
+{
+ EjsVar *vp, *newOp;
+ int maxBaseClasses = 50;
+
+ do {
+ if (op->type != EJS_TYPE_OBJECT) {
+ mprAssert(op->type == EJS_TYPE_OBJECT);
+ return 0;
+ }
+ mprAssert(op->objectState);
+
+ vp = ejsGetPropertyMethod(ep, op, property);
+ if (vp != 0) {
+ /*
+ * Found
+ */
+ vp = ejsSetPropertyMethod(ep, op, property, value);
+ break;
+ }
+
+ newOp = op->objectState->baseClass;
+ if (newOp == 0) {
+ if (op->objectState != ep->objectClass->objectState) {
+ newOp = ep->objectClass;
+ }
+ }
+ op = newOp;
+
+ /*
+ * A little bit of sanity checking
+ */
+ if (--maxBaseClasses <= 0) {
+ mprAssert(maxBaseClasses > 0);
+ break;
+ }
+
+ } while (op);
+
+ return ejsGetPropertyPtr(vp);
+}
+
+/******************************************************************************/
+/*
+ * Set a property's variable value. Create the property if it does not exist.
+ * This does NOT follow base classes. Okay when updating instance properties,
+ * but not for class (static) properties. This does a shallow copy which
+ * will copy references.
+ */
+
+EjsProperty *ejsSetProperty(Ejs *ep, EjsVar *obj, const char *property,
+ const EjsVar *value)
+{
+ EjsVar *vp;
+
+ vp = ejsSetPropertyMethod(ep, obj, property, value);
+
+ return ejsGetPropertyPtr(vp);
+}
+
+/******************************************************************************/
+/*
+ * Set a property's variable value by assigning the given value. The caller
+ * must NOT free value as it is assigned directly into the property's value.
+ */
+
+EjsProperty *ejsSetPropertyAndFree(Ejs *ep, EjsVar *obj,
+ const char *property, EjsVar *value)
+{
+ EjsVar *vp;
+
+ vp = ejsSetPropertyMethod(ep, obj, property, value);
+
+ ejsFree(ep, value, EJS_SLAB_VAR);
+
+ return ejsGetPropertyPtr(vp);
+}
+
+/******************************************************************************/
+
+EjsProperty *ejsSetPropertyToCMethod(Ejs *ep, EjsVar *vp, const char *prop,
+ EjsCMethod fn, void *userData, int flags)
+{
+ EjsVar v;
+
+ ejsInitVar(&v, EJS_TYPE_CMETHOD);
+ v.cMethod.fn = fn;
+ v.cMethod.userData = userData;
+ v.flags = flags;
+
+ return ejsSetProperty(ep, vp, prop, &v);
+}
+
+/******************************************************************************/
+
+EjsProperty *ejsSetPropertyToBoolean(Ejs *ep, EjsVar *vp, const char *prop,
+ int value)
+{
+ EjsVar v;
+
+ ejsInitVar(&v, EJS_TYPE_BOOL);
+ v.boolean = value;
+
+ return ejsSetProperty(ep, vp, prop, &v);
+}
+
+/******************************************************************************/
+#if BLD_FEATURE_FLOATING_POINT
+
+EjsProperty *ejsSetPropertyToFloat(Ejs *ep, EjsVar *vp, const char *prop,
+ double value)
+{
+ EjsVar v;
+
+ ejsInitVar(&v, EJS_TYPE_FLOAT);
+ v.floating = value;
+
+ return ejsSetProperty(ep, vp, prop, &v);
+}
+
+#endif
+/******************************************************************************/
+
+EjsProperty *ejsSetPropertyToInteger(Ejs *ep, EjsVar *vp, const char *prop,
+ int value)
+{
+ EjsVar v;
+
+ ejsInitVar(&v, EJS_TYPE_INT);
+ v.integer = value;
+
+ return ejsSetProperty(ep, vp, prop, &v);
+}
+
+/******************************************************************************/
+#if BLD_FEATURE_INT64
+
+EjsProperty *ejsSetPropertyToInteger64(Ejs *ep, EjsVar *vp, const char *prop,
+ int64 value)
+{
+ EjsVar v;
+
+ ejsInitVar(&v, EJS_TYPE_INT64);
+ v.integer64 = value;
+
+ return ejsSetProperty(ep, vp, prop, &v);
+}
+
+#endif
+/******************************************************************************/
+
+EjsProperty *ejsSetPropertyToNull(Ejs *ep, EjsVar *vp, const char *prop)
+{
+ EjsVar v;
+
+ ejsInitVar(&v, EJS_TYPE_NULL);
+
+ return ejsSetProperty(ep, vp, prop, &v);
+}
+
+/******************************************************************************/
+
+EjsProperty *ejsSetPropertyToMethod(Ejs *ep, EjsVar *vp, const char *prop,
+ const char *body, MprArray *args, int flags)
+{
+ return ejsSetPropertyAndFree(ep, vp, prop,
+ ejsCreateMethodVar(ep, body, args, flags));
+}
+
+/******************************************************************************/
+
+EjsProperty *ejsSetPropertyToNumber(Ejs *ep, EjsVar *vp, const char *prop,
+ EjsNum value)
+{
+ return ejsSetPropertyAndFree(ep, vp, prop, ejsCreateNumberVar(ep, value));
+}
+
+/******************************************************************************/
+
+EjsProperty *ejsSetPropertyToStringCMethod(Ejs *ep, EjsVar *vp,
+ const char *prop, EjsStringCMethod fn, void *userData, int flags)
+{
+ EjsVar v;
+
+ ejsInitVar(&v, EJS_TYPE_STRING_CMETHOD);
+ v.cMethodWithStrings.fn = fn;
+ v.cMethodWithStrings.userData = userData;
+ v.flags = flags;
+
+ return ejsSetProperty(ep, vp, prop, &v);
+}
+
+/******************************************************************************/
+
+EjsProperty *ejsSetPropertyToString(Ejs *ep, EjsVar *vp, const char *prop,
+ const char *value)
+{
+ EjsProperty *pp;
+ EjsVar v;
+
+ ejsInitVar(&v, EJS_TYPE_STRING);
+
+ /* FUTURE OPT */
+ v.string = mprStrdupInternal(EJS_LOC_ARGS(ep), value);
+ if (v.string == 0) {
+ return 0;
+ }
+ v.length = strlen(v.string);
+ v.allocatedData = 1;
+
+ pp = ejsSetProperty(ep, vp, prop, &v);
+
+ mprFree(v.string);
+
+ return pp;
+}
+
+/******************************************************************************/
+
+EjsProperty *ejsSetPropertyToBinaryString(Ejs *ep, EjsVar *vp,
+ const char *prop, const uchar *value, int len)
+{
+ EjsProperty *pp;
+ EjsVar v;
+
+ ejsInitVar(&v, EJS_TYPE_STRING);
+
+ /* FUTURE OPT */
+ v.length = dupString(MPR_LOC_ARGS(ep), &v.ustring, value, len);
+ if (v.length < 0) {
+ return 0;
+ }
+ v.allocatedData = 1;
+
+ pp = ejsSetProperty(ep, vp, prop, &v);
+
+ mprFree(v.ustring);
+
+ return pp;
+}
+
+/******************************************************************************/
+
+EjsProperty *ejsSetPropertyToUndefined(Ejs *ep, EjsVar *vp, const char *prop)
+{
+ EjsVar v;
+
+ ejsInitVar(&v, EJS_TYPE_UNDEFINED);
+
+ return ejsSetProperty(ep, vp, prop, &v);
+}
+
+/******************************************************************************/
+
+EjsProperty *ejsSetPropertyToPtr(Ejs *ep, EjsVar *vp, const char *prop,
+ void *ptr, EjsDestructor destructor)
+{
+ EjsVar v;
+
+ ejsInitVar(&v, EJS_TYPE_PTR);
+ v.ptr.userPtr = ptr;
+ v.ptr.destructor = destructor;
+ v.allocatedData = 1;
+
+ return ejsSetProperty(ep, vp, prop, &v);
+}
+
+/******************************************************************************/
+
+EjsProperty *ejsSetPropertyToNewObj(Ejs *ep, EjsVar *vp, const char *prop,
+ const char *className, MprArray *args)
+{
+ return ejsSetPropertyAndFree(ep, vp, prop,
+ ejsCreateObjUsingArgv(ep, 0, className, args));
+}
+
+/******************************************************************************/
+
+EjsProperty *ejsSetPropertyToObj(Ejs *ep, EjsVar *op, const char *prop)
+{
+ return ejsSetPropertyAndFree(ep, op, prop, ejsCreateObjVar(ep));
+}
+
+/******************************************************************************/
+/*
+ * Convenience routines
+ */
+
+EjsVar *ejsSetPropertyToObjAsVar(Ejs *ep, EjsVar *op, const char *prop)
+{
+ return ejsGetVarPtr(ejsSetPropertyToObj(ep, op, prop));
+}
+
+/******************************************************************************/
+/******************************************************************************/
+/******************************************************************************/
+/******************************************************************************/
+/*
+ * Create a script method
+ */
+
+EjsProperty *ejsDefineMethod(Ejs *ep, EjsVar *vp, const char *prop,
+ const char *body, MprArray *args)
+{
+ if (vp == 0) {
+ vp = ejsGetGlobalObj(ep);
+ }
+ return ejsSetPropertyToMethod(ep, vp, prop, body, args, 0);
+}
+
+/******************************************************************************/
+/*
+ * Create a C language method
+ */
+
+EjsProperty *ejsDefineCMethod(Ejs *ep, EjsVar *vp, const char *prop,
+ EjsCMethod fn, int flags)
+{
+ if (vp == 0) {
+ vp = ejsGetGlobalObj(ep);
+ }
+ return ejsSetPropertyToCMethod(ep, vp, prop, fn, 0, flags);
+}
+
+/******************************************************************************/
+/*
+ * Define accessors
+ */
+
+EjsProperty *ejsDefineAccessors(Ejs *ep, EjsVar *vp, const char *prop,
+ const char *getBody, const char *setBody)
+{
+ EjsProperty *pp;
+ MprArray *args;
+ char *propName;
+
+ if (vp == 0) {
+ vp = ejsGetGlobalObj(ep);
+ }
+
+ if (ejsSetPropertyToMethod(ep, vp, prop, getBody, 0, EJS_GET_ACCESSOR) < 0){
+ ejsMemoryError(ep);
+ return 0;
+ }
+
+ /* MOB -- OPT to use SLAB */
+ /* MOB -- need to encapsulate this logic */
+
+ if (mprAllocStrcat(MPR_LOC_ARGS(ep), &propName, EJS_MAX_ID+5, 0,
+ "-set-", prop, 0) < 0) {
+ ejsMemoryError(ep);
+ return 0;
+ }
+
+ args = mprCreateItemArray(ep, EJS_INC_ARGS, EJS_MAX_ARGS);
+ mprAddItem(args, mprStrdup(args, "value"));
+
+ pp = ejsSetPropertyToMethod(ep, vp, propName, setBody, args,
+ EJS_SET_ACCESSOR);
+ mprFree(propName);
+
+ if (pp == 0) {
+ ejsMemoryError(ep);
+ return 0;
+ }
+
+ return pp;
+}
+
+/******************************************************************************/
+/*
+ * Define C accessors
+ */
+
+EjsProperty *ejsDefineCAccessors(Ejs *ep, EjsVar *vp, const char *prop,
+ EjsCMethod getFn, EjsCMethod setFn, int flags)
+{
+ EjsProperty *pp;
+ char *propName;
+
+ if (vp == 0) {
+ vp = ejsGetGlobalObj(ep);
+ }
+ pp = ejsSetPropertyToCMethod(ep, vp, prop, getFn, 0,
+ flags | EJS_GET_ACCESSOR);
+ if (pp == 0) {
+ ejsMemoryError(ep);
+ return 0;
+ }
+
+ /* MOB -- OPT to use SLAB */
+ if (mprAllocStrcat(MPR_LOC_ARGS(ep), &propName, EJS_MAX_ID + 5, 0,
+ "-set-", prop, 0) < 0) {
+ ejsMemoryError(ep);
+ return 0;
+ }
+ pp = ejsSetPropertyToCMethod(ep, vp, propName, setFn, 0,
+ flags | EJS_SET_ACCESSOR);
+ mprFree(propName);
+
+ if (pp == 0) {
+ ejsMemoryError(ep);
+ return 0;
+ }
+ return pp;
+}
+
+/******************************************************************************/
+/*
+ * Create a C language method with string arguments
+ */
+
+EjsProperty *ejsDefineStringCMethod(Ejs *ep, EjsVar *vp, const char *prop,
+ EjsStringCMethod fn, int flags)
+{
+ if (vp == 0) {
+ vp = ejsGetGlobalObj(ep);
+ }
+ return ejsSetPropertyToStringCMethod(ep, vp, prop, fn, 0, flags);
+}
+
+/******************************************************************************/
+
+void ejsSetCMethodUserData(EjsVar *obj, void *userData)
+{
+ /*
+ * This is a little dirty. We rely on the userData being in the same
+ * place in the var structure.
+ */
+ obj->cMethod.userData = userData;
+}
+
+/******************************************************************************/
+
+void ejsSetVarFlags(EjsVar *obj, int flags)
+{
+ obj->flags = flags;
+}
+
+/******************************************************************************/
+
+void *ejsGetCMethodUserData(EjsVar *obj)
+{
+ return obj->cMethod.userData;
+}
+
+/******************************************************************************/
+
+int ejsGetVarFlags(EjsVar *obj)
+{
+ return obj->flags;
+}
+
+/******************************************************************************/
+
+void ejsSetObjDestructor(Ejs *ep, EjsVar *obj, EjsDestructor destructor)
+{
+ obj->objectState->destructor = destructor;
+}
+
+/******************************************************************************/
+
+void ejsClearObjDestructor(Ejs *ep, EjsVar *obj)
+{
+ obj->objectState->destructor = 0;
+}
+
+/******************************************************************************/
+/*
+ * Create a new property
+ */
+
+static EjsProperty *allocProperty(Ejs *ep, EjsVar *op, const char *property,
+ int propertyIndex, EjsProperty *last)
+{
+ EjsProperty *prop;
+ EjsObj *obj;
+
+ obj = op->objectState;
+
+ /*
+ * Allocate the property using the memory context of the owning object
+ */
+ prop = ejsAllocProperty(EJS_LOC_ARGS(obj->ejs));
+ if (prop == 0) {
+ return 0;
+ }
+ if (mprStrcpy(prop->name, sizeof(prop->name), property) < 0) {
+ ejsError(ep, EJS_REFERENCE_ERROR,
+ "Property name %s is too long. Max is %d letters.",
+ prop->name, EJS_MAX_ID);
+ return 0;
+ }
+
+ ejsSetVarName(ep, ejsGetVarPtr(prop), &prop->name[0]);
+
+ /*
+ * Do hash linkage
+ */
+ if (last) {
+ last->hashNext = prop;
+ } else {
+ obj->propertyHash[propertyIndex] = prop;
+ }
+
+#if BLD_DEBUG
+ prop->link.propertyName = prop->name;
+ prop->link.property = prop;
+ prop->link.head = &obj->link;
+#endif
+
+ /*
+ * Inserting before the dummy head will append to the end
+ */
+ linkPropertyBefore(obj, &obj->link, &prop->link);
+
+ obj->numProperties++;
+ prop->parentObj = obj;
+ mprAssert(obj->ejs);
+
+ return prop;
+}
+
+/******************************************************************************/
+/*
+ * Delete a property from this object
+ */
+
+int ejsDeleteProperty(Ejs *ep, EjsVar *vp, const char *property)
+{
+ EjsProperty *prop, *last;
+ EjsObj *obj;
+ int propertyIndex;
+
+ mprAssert(vp);
+ mprAssert(property && *property);
+ mprAssert(vp->type == EJS_TYPE_OBJECT);
+
+ if (vp->type != EJS_TYPE_OBJECT) {
+ mprAssert(vp->type == EJS_TYPE_OBJECT);
+ return MPR_ERR_BAD_ARGS;
+ }
+
+ prop = hashLookup(vp->objectState, property, &propertyIndex, &last);
+ if (prop == (EjsProperty*) 0) {
+ return MPR_ERR_NOT_FOUND;
+ }
+ obj = vp->objectState;
+
+#if FUTURE
+ if (prop->readonly) {
+ mprAssert(! prop->readonly);
+ return MPR_ERR_READ_ONLY;
+ }
+#endif
+
+ /*
+ * If doing enumerations, then the object will mark preventDelete to
+ * prevent any properties being deleted and thus disturbing the
+ * traversal.
+ */
+ if (obj->preventDeleteProp) {
+ obj->delayedDeleteProp = 1;
+ prop->delayedDelete = 1;
+ return 0;
+ }
+
+ /*
+ * Remove from hash
+ */
+ if (last) {
+ last->hashNext = prop->hashNext;
+ } else {
+ obj->propertyHash[propertyIndex] = prop->hashNext;
+ }
+
+ unlinkProperty(obj, &prop->link);
+ obj->numProperties--;
+
+ /*
+ * Free any property data and return to the slab
+ */
+ if (prop->var.type != EJS_TYPE_OBJECT) {
+ ejsClearVar(ep, ejsGetVarPtr(prop));
+ }
+ ejsFree(ep, prop, EJS_SLAB_PROPERTY);
+
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * Remove a property's value from this object. The property is set to
+ * undefined.
+ */
+
+EjsVar *ejsClearProperty(Ejs *ep, EjsVar *vp, const char *property)
+{
+ EjsProperty *prop;
+
+ mprAssert(vp);
+ mprAssert(property && *property);
+ mprAssert(vp->type == EJS_TYPE_OBJECT);
+
+ if (vp->type != EJS_TYPE_OBJECT) {
+ mprAssert(vp->type == EJS_TYPE_OBJECT);
+ return 0;
+ }
+
+ prop = hashLookup(vp->objectState, property, 0, 0);
+ if (prop == (EjsProperty*) 0) {
+ return 0;
+ }
+#if FUTURE
+ if (prop->readonly) {
+ mprAssert(! prop->readonly);
+ return 0;
+ }
+#endif
+
+ ejsClearVar(ep, &prop->var);
+ return &prop->var;
+}
+
+/******************************************************************************/
+/*
+ * Unlink a property from the ordered list of properties
+ */
+
+static void unlinkProperty(EjsObj *obj, EjsPropLink *propLink)
+{
+ propLink->prev->next = propLink->next;
+ propLink->next->prev = propLink->prev;
+}
+
+/******************************************************************************/
+#if UNUSED && KEEP
+/*
+ * Insert a link after a specified link.
+ */
+
+static void linkPropertyAfter(EjsObj *obj, EjsPropLink *at,
+ EjsPropLink *propLink)
+{
+ propLink->next = at->next;
+ propLink->prev = at;
+
+ at->next->prev = propLink;
+ at->next = propLink;
+}
+
+#endif
+/******************************************************************************/
+/*
+ * Insert a link before a specified link.
+ */
+
+static void linkPropertyBefore(EjsObj *obj, EjsPropLink *at,
+ EjsPropLink *propLink)
+{
+ propLink->prev = at->prev;
+ propLink->next = at;
+
+ at->prev->next = propLink;
+ at->prev = propLink;
+}
+
+/******************************************************************************/
+/*
+ * This routine will sort properties in an object. If propertyName is not
+ * null, then the properties in op must be objects with a property of the
+ * name propertyName. If propertyName is null, then the properties of op
+ * are directly sorted. If order is 1, they are sorted in ascending order.
+ * If -1, they are sorted in descending order.
+ *
+ * NOTE: arrays keep their original index values.
+ */
+
+void ejsSortProperties(Ejs *ep, EjsVar *op, EjsSortFn fn,
+ const char *propertyName, int order)
+{
+ EjsProperty *p1, *p2, *tmp;
+ EjsPropLink *l1, *l2, *oldL1Spot;
+ EjsObj *obj;
+
+ obj = op->objectState;
+
+ p1 = ejsGetFirstProperty(op, 0);
+ while (p1) {
+ if (p1->dontEnumerate) {
+ p1 = ejsGetNextProperty(p1, 0);
+ continue;
+ }
+
+ p2 = ejsGetFirstProperty(op, 0);
+ while (p2 && p2 != p1) {
+
+ if (p2->dontEnumerate) {
+ p2 = ejsGetNextProperty(p2, 0);
+ continue;
+ }
+
+ if (fn == 0) {
+ if (propertyName) {
+ fn = sortByProperty;
+ } else {
+ fn = sortAllProperties;
+ }
+ }
+
+ if (fn(ep, p1, p2, propertyName, order) < 0) {
+
+ l1 = &p1->link;
+ l2 = &p2->link;
+
+ /*
+ * Swap the properties without disturbing the hash chains.
+ * l1 is always after l2 in the list. Unlink l1 and remember
+ * the one after l1.
+ */
+ oldL1Spot = l1->next;
+ unlinkProperty(obj, l1);
+
+ /*
+ * Manually reinsert l1 by replacing l2 with l1. l2 is out of
+ * the chain.
+ */
+ l2->prev->next = l1;
+ l2->next->prev = l1;
+ l1->prev = l2->prev;
+ l1->next = l2->next;
+
+ /*
+ * Reinsert l2 before the spot where l1 was.
+ */
+ linkPropertyBefore(obj, oldL1Spot, l2);
+
+ /*
+ * Swap the pointers so we continue to traverse correctly
+ */
+ tmp = p1;
+ p1 = p2;
+ p2 = tmp;
+ }
+ p2 = ejsGetNextProperty(p2, 0);
+ }
+ p1 = ejsGetNextProperty(p1, 0);
+ }
+}
+
+/******************************************************************************/
+/*
+ * Sort properties. Strings are sorted in ascending ASCII collating sequence
+ * Numbers are sorted in increasing numerical order.
+ */
+static int sortAllProperties(Ejs *ep, EjsProperty *p1, EjsProperty *p2,
+ const char *propertyName, int order)
+{
+ EjsVar *v1, *v2;
+ char *buf1, *buf2;
+ int rc, buf1Alloc;
+
+ v1 = ejsGetVarPtr(p1);
+ v2 = ejsGetVarPtr(p2);
+
+ if (v1->type == v2->type) {
+ /* MOB -- should support Numbers */
+ if (v1->type == EJS_TYPE_INT) {
+ if (v1->integer < v2->integer) {
+ return - order;
+
+ } else if (v1->integer == v2->integer) {
+ return 0;
+ }
+ return order;
+
+#if BLD_FEATURE_FLOATING_POINT
+ } else if (v1->type == EJS_TYPE_FLOAT) {
+ if (v1->floating < v2->floating) {
+ return - order;
+
+ } else if (v1->floating == v2->floating) {
+ return 0;
+ }
+ return order;
+
+#endif
+ } else if (v1->type == EJS_TYPE_STRING) {
+ /* MOB -- need binary support ? */
+ return strcmp(v1->string, v2->string) * order;
+
+ } else {
+
+ buf1 = ejsVarToStringEx(ep, v1, &buf1Alloc);
+ buf2 = ejsVarToString(ep, v2);
+
+ rc = strcmp(buf1, buf2);
+
+ if (buf1Alloc) {
+ mprFree(buf1);
+ }
+
+ return rc * order;
+ }
+
+ } else {
+ /* Type mismatch in array */
+ return 0;
+ }
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * Sort an object by a given property.
+ */
+static int sortByProperty(Ejs *ep, EjsProperty *p1, EjsProperty *p2,
+ const char *propertyName, int order)
+{
+ EjsVar *o1, *o2, *v1, *v2;
+ char *buf1, *buf2;
+ int rc, buf1Alloc;
+
+ o1 = ejsGetVarPtr(p1);
+ o2 = ejsGetVarPtr(p2);
+
+ if (!ejsVarIsObject(o1) || !ejsVarIsObject(o2)) {
+ mprAssert(ejsVarIsObject(o1));
+ mprAssert(ejsVarIsObject(o2));
+ return 0;
+ }
+
+ v1 = ejsGetPropertyAsVar(ep, o1, propertyName);
+ v2 = ejsGetPropertyAsVar(ep, o2, propertyName);
+
+ if (v1 == 0 || v2 == 0) {
+ /* Property name not found */
+ return 0;
+ }
+
+ if (v1->type != v2->type) {
+ mprAssert(v1->type == v2->type);
+ return 0;
+ }
+
+ if (v1->type == v2->type) {
+ /* MOB -- should support Numbers */
+ if (v1->type == EJS_TYPE_INT) {
+ if (v1->integer < v2->integer) {
+ return -order;
+
+ } else if (v1->integer == v2->integer) {
+ return 0;
+ }
+ return order;
+
+#if BLD_FEATURE_FLOATING_POINT
+ } else if (v1->type == EJS_TYPE_FLOAT) {
+ if (v1->floating < v2->floating) {
+ return -order;
+
+ } else if (v1->floating == v2->floating) {
+ return 0;
+ }
+ return order;
+
+#endif
+ } else if (v1->type == EJS_TYPE_STRING) {
+ /* MOB -- need binary support ? */
+ return strcmp(v1->string, v2->string) * order;
+
+ } else {
+ buf1 = ejsVarToStringEx(ep, v1, &buf1Alloc);
+
+ buf2 = ejsVarToString(ep, v2);
+
+ rc = strcmp(buf1, buf2);
+
+ if (buf1Alloc) {
+ mprFree(buf1);
+ }
+
+ return rc * order;
+ }
+
+ } else {
+ /* Type mismatch in array */
+ return 0;
+ }
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * Set a property's name
+ */
+
+void ejsSetPropertyName(EjsProperty *pp, const char *property)
+{
+ mprStrcpy(pp->name, sizeof(pp->name), property);
+}
+
+/******************************************************************************/
+
+int ejsMakePropertyEnumerable(EjsProperty *prop, int enumerate)
+{
+ int oldValue;
+
+ oldValue = prop->dontEnumerate;
+ prop->dontEnumerate = !enumerate;
+ return oldValue;
+}
+
+/******************************************************************************/
+
+void ejsMakePropertyPrivate(EjsProperty *prop, int isPrivate)
+{
+ prop->isPrivate = isPrivate;
+}
+
+/******************************************************************************/
+/*
+ * Make a variable read only. Can still be deleted.
+ */
+
+void ejsMakePropertyReadOnly(EjsProperty *prop, int readonly)
+{
+ prop->readonly = readonly;
+}
+
+/******************************************************************************/
+
+int ejsMakeObjPermanent(EjsVar *vp, int permanent)
+{
+ int oldValue;
+
+ if (vp && vp->type == EJS_TYPE_OBJECT) {
+ oldValue = vp->objectState->permanent;
+ vp->objectState->permanent = permanent;
+ } else {
+ oldValue = 0;
+ }
+ return oldValue;
+}
+
+/******************************************************************************/
+
+int ejsMakeObjLive(EjsVar *vp, bool alive)
+{
+ int oldValue;
+
+ oldValue = 0;
+ if (vp && vp->type == EJS_TYPE_OBJECT) {
+ oldValue = vp->objectState->alive;
+ vp->objectState->alive = alive;
+ } else {
+ oldValue = 0;
+ }
+ return oldValue;
+}
+
+/******************************************************************************/
+
+void ejsMakeClassNoConstructor(EjsVar *vp)
+{
+ mprAssert(vp->type == EJS_TYPE_OBJECT);
+
+ if (vp->type == EJS_TYPE_OBJECT) {
+ vp->objectState->noConstructor = 1;
+ }
+}
+
+/******************************************************************************/
+/*
+ * Get the count of properties.
+ */
+
+int ejsGetPropertyCount(EjsVar *vp)
+{
+ EjsProperty *pp;
+ EjsPropLink *lp, *head;
+ int count;
+
+ mprAssert(vp);
+
+ if (vp->type != EJS_TYPE_OBJECT) {
+ return 0;
+ }
+
+ count = 0;
+
+ head = &vp->objectState->link;
+ for (lp = head->next; lp != head; lp = lp->next) {
+ pp = ejsGetPropertyFromLink(lp);
+ if (! pp->dontEnumerate) {
+ count++;
+ }
+ }
+ return count;
+}
+
+/******************************************************************************/
+/*
+ * Get the first property in an object. Used for walking all properties in an
+ * object. This will only enumerate properties in this class and not in base
+ * classes.
+ */
+
+EjsProperty *ejsGetFirstProperty(const EjsVar *op, int flags)
+{
+ EjsProperty *pp;
+ EjsObj *obj;
+ EjsPropLink *head, *lp;
+
+ mprAssert(op);
+ mprAssert(op->type == EJS_TYPE_OBJECT);
+
+ if (op->type != EJS_TYPE_OBJECT) {
+ mprAssert(op->type == EJS_TYPE_OBJECT);
+ return 0;
+ }
+ pp = 0;
+
+ do {
+ obj = op->objectState;
+
+ head = &obj->link;
+ lp = head->next;
+
+ while (lp != head) {
+ pp = ejsGetPropertyFromLink(lp);
+ if (! pp->dontEnumerate || (flags & EJS_ENUM_HIDDEN)) {
+ break;
+ }
+ lp = lp->next;
+ }
+ if (lp != head || op->type != EJS_TYPE_OBJECT ||
+ !(flags & EJS_ENUM_CLASSES)) {
+ break;
+ }
+
+ op = obj->baseClass;
+
+ } while (lp == 0 && op);
+
+ return pp;
+}
+
+/******************************************************************************/
+/*
+ * Get the next property in sequence. This will only enumerate properties in
+ * this class and not in base classes.
+ */
+
+EjsProperty *ejsGetNextProperty(EjsProperty *last, int flags)
+{
+ EjsProperty *pp;
+ EjsObj *obj;
+ EjsPropLink *lp, *head;
+
+ obj = last->parentObj;
+
+ lp = last->link.next;
+ head = &obj->link;
+ pp = 0;
+
+ while (obj) {
+ while (lp != head) {
+ pp = ejsGetPropertyFromLink(lp);
+ if (! pp->dontEnumerate || (flags & EJS_ENUM_HIDDEN)) {
+ break;
+ }
+ lp = lp->next;
+ }
+ if (lp != head || !(flags & EJS_ENUM_CLASSES)) {
+ break;
+ }
+
+ /*
+ * Now iterate over properties in base classes (down the chain)
+ */
+ if (obj->baseClass == 0) {
+ break;
+ }
+
+ obj = obj->baseClass->objectState;
+ if (obj == 0) {
+ break;
+ }
+ }
+ return pp;
+}
+
+/******************************************************************************/
+/*
+ * Find a variable given a variable name and return the parent object and
+ * the variable itself. This routine supports literal variable and property
+ * names that may be objects or arrays but may NOT have expressions.
+ * Returns -1 on errors or if the variable is not found.
+ * FUTURE -- Needs OPT
+ */
+
+EjsVar *ejsFindProperty(Ejs *ep, EjsVar **obj, char **property, EjsVar *global,
+ EjsVar *local, const char *fullName, int create)
+{
+ EjsProperty *currentProp;
+ EjsVar *currentObj;
+ /* MOB -- WARNING BIG */
+ char tokBuf[EJS_MAX_ID], propertyName[EJS_MAX_ID];
+ char *token, *next, *cp, *endp;
+
+ mprAssert(fullName && *fullName);
+
+ currentProp = 0;
+ currentObj = 0;
+
+ if (global == 0) {
+ global = ep->global;
+ }
+
+ if (obj) {
+ *obj = 0;
+ }
+ if (property) {
+ *property = 0;
+ }
+
+ if (fullName == 0) {
+ return 0;
+ }
+
+ next = (char*) fullName;
+ token = getNextVarToken(&next, tokBuf, sizeof(tokBuf));
+ mprStrcpy(propertyName, sizeof(propertyName), token);
+
+ if (local) {
+ currentProp = ejsGetProperty(ep, local, token);
+ currentObj = local;
+ }
+ if (currentProp == 0) {
+ currentProp = ejsGetProperty(ep, global, token);
+ currentObj = global;
+ }
+
+ token = getNextVarToken(&next, tokBuf, sizeof(tokBuf));
+
+ while (currentObj != 0 && token != 0 && *token) {
+
+ if (currentProp == 0) {
+ return 0;
+ }
+ currentObj = &currentProp->var;
+ currentProp = 0;
+
+ if (*token == '[') {
+ token = getNextVarToken(&next, tokBuf, sizeof(tokBuf));
+
+ mprStrcpy(propertyName, sizeof(propertyName), token);
+ cp = propertyName;
+ if (*cp == '\"') {
+ cp++;
+ if ((endp = strchr(cp, '\"')) != 0) {
+ *endp = '\0';
+ }
+ } else if (*cp == '\'') {
+ cp++;
+ if ((endp = strchr(cp, '\'')) != 0) {
+ *endp = '\0';
+ }
+ }
+
+ currentProp = ejsGetProperty(ep, currentObj, propertyName);
+
+ token = getNextVarToken(&next, tokBuf, sizeof(tokBuf));
+ if (*token != ']') {
+ return 0;
+ }
+
+ } else if (*token == '.') {
+ token = getNextVarToken(&next, tokBuf, sizeof(tokBuf));
+ if (!isalpha((int) token[0]) &&
+ token[0] != '_' && token[0] != '$') {
+ return 0;
+ }
+
+ mprStrcpy(propertyName, sizeof(propertyName), token);
+ currentProp = ejsGetProperty(ep, currentObj, token);
+
+ } else {
+ currentProp = ejsGetProperty(ep, currentObj, token);
+ }
+
+ if (next == 0 || *next == '\0') {
+ break;
+ }
+ token = getNextVarToken(&next, tokBuf, sizeof(tokBuf));
+ }
+
+ if (obj) {
+ *obj = currentObj;
+ }
+
+
+ if (currentProp == 0 && currentObj >= 0 && create) {
+ currentProp = ejsCreateSimpleProperty(ep, currentObj, propertyName);
+ }
+
+ if (property) {
+ *property = currentProp->name;
+ }
+ return ejsGetVarPtr(currentProp);
+}
+
+/******************************************************************************/
+/*
+ * Get the next token as part of a variable specification. This will return
+ * a pointer to the next token and will return a pointer to the next token
+ * (after this one) in "next". The tokBuf holds the parsed token.
+ */
+
+static char *getNextVarToken(char **next, char *tokBuf, int tokBufLen)
+{
+ char *start, *cp;
+ int len;
+
+ start = *next;
+ while (isspace((int) *start) || *start == '\n' || *start == '\r') {
+ start++;
+ }
+ cp = start;
+
+ if (*cp == '.' || *cp == '[' || *cp == ']') {
+ cp++;
+ } else {
+ while (*cp && *cp != '.' && *cp != '[' && *cp != ']' &&
+ !isspace((int) *cp) && *cp != '\n' && *cp != '\r') {
+ cp++;
+ }
+ }
+ len = mprMemcpy(tokBuf, tokBufLen - 1, start, cp - start);
+ tokBuf[len] = '\0';
+
+ *next = cp;
+ return tokBuf;
+}
+
+/******************************************************************************/
+
+EjsVar *ejsGetGlobalClass(Ejs *ep)
+{
+ return ep->global;
+}
+
+/******************************************************************************/
+/*************************** Property Access Methods **************************/
+/******************************************************************************/
+/*
+ * Create an undefined property. This routine calls the object method hooks.
+ */
+
+/* MOB -- better suffix than "Method" */
+EjsVar *ejsCreatePropertyMethod(Ejs *ep, EjsVar *op, const char *property)
+{
+ EjsVar *vp;
+
+ mprAssert(ep);
+ mprAssert(op);
+ mprAssert(property && *property);
+
+ if (op == 0) {
+ return 0;
+ }
+
+ mprAssert(op->type == EJS_TYPE_OBJECT);
+ mprAssert(op->objectState);
+
+ if (op->objectState == 0) {
+ return 0;
+ }
+
+ if (op->objectState->methods == 0) {
+ vp = ejsGetVarPtr(ejsCreateSimpleProperty(ep, op, property));
+ } else {
+ vp = (op->objectState->methods->createProperty)(ep, op, property);
+ }
+
+ if (vp == 0) {
+ mprAssert(vp);
+ op->objectState->hasErrors = 1;
+ return 0;
+ }
+
+ /*
+ * FUTURE - find a better way.
+ */
+ if (op->isArray) {
+ ejsSetArrayLength(ep, op, property, 0, 0);
+ }
+ return vp;
+}
+
+/******************************************************************************/
+
+int ejsDeletePropertyMethod(Ejs *ep, EjsVar *op, const char *property)
+{
+ int rc;
+
+ mprAssert(ep);
+ mprAssert(op);
+ mprAssert(property && *property);
+
+ if (op == 0) {
+ return -1;
+ }
+
+ mprAssert(op->type == EJS_TYPE_OBJECT);
+ mprAssert(op->objectState);
+
+ if (op->objectState == 0) {
+ return -1;
+ }
+
+ if (op->objectState->methods == 0) {
+ rc = ejsDeleteProperty(ep, op, property);
+ } else {
+ rc = (op->objectState->methods->deleteProperty)(ep, op, property);
+ }
+
+ if (rc < 0) {
+ op->objectState->hasErrors = 1;
+ }
+
+ op->objectState->dirty = 1;
+
+ return rc;
+}
+
+/******************************************************************************/
+/*
+ * Set the value of a property. Create if it does not exist
+ * If the object has property accessor methods defined, use those.
+ */
+
+EjsVar *ejsSetPropertyMethod(Ejs *ep, EjsVar *op, const char *property,
+ const EjsVar *value)
+{
+ EjsVar *vp;
+
+ mprAssert(ep);
+ mprAssert(op);
+ mprAssert(property && *property);
+ mprAssert(value);
+
+ if (op == 0) {
+ return 0;
+ }
+
+ mprAssert(op->type == EJS_TYPE_OBJECT);
+ mprAssert(op->objectState);
+
+ if (op->objectState == 0) {
+ return 0;
+ }
+
+ if (op->objectState->methods == 0) {
+ vp = ejsGetVarPtr(ejsCreateSimpleProperty(ep, op, property));
+ if (vp && ejsWriteVar(ep, vp, (EjsVar*) value, EJS_SHALLOW_COPY) < 0) {
+ mprAssert(0);
+ op->objectState->hasErrors = 1;
+ return 0;
+ }
+
+ } else {
+ vp = (op->objectState->methods->setProperty)(ep, op, property, value);
+ }
+
+ if (vp == 0) {
+ mprAssert(vp);
+ op->objectState->hasErrors = 1;
+ return 0;
+ }
+
+ if (vp->type == EJS_TYPE_OBJECT) {
+ /*
+ * We make an object alive (and subject to garbage collection) when
+ * it is referenced in some other object. If this is undesirable, the
+ * caller should make the object permanent while calling this routine
+ * and then afterward clear the alive bit by calling ejsMakeObjLive().
+ */
+ if (op->objectState != vp->objectState) {
+ vp->objectState->alive = 1;
+ }
+#if BLD_DEBUG
+ {
+ EjsProperty *pp = ejsGetPropertyPtr(vp);
+ ejsSetVarName(ep, vp, &pp->name[0]);
+ if (value->propertyName == 0) {
+ ejsSetVarName(ep, (EjsVar*) value, &pp->name[0]);
+ }
+ }
+#endif
+ }
+
+ /*
+ * Trap assignments to array.length. MOB - find a better way.
+ */
+ if (vp->isArrayLength) {
+ ejsSetArrayLength(ep, op, 0, 0, value);
+ }
+
+ op->objectState->dirty = 1;
+
+ return vp;
+}
+
+/******************************************************************************/
+
+EjsVar *ejsGetPropertyMethod(Ejs *ep, EjsVar *op, const char *property)
+{
+ mprAssert(ep);
+ mprAssert(op);
+ mprAssert(property && *property);
+
+ if (op == 0) {
+ return 0;
+ }
+
+ mprAssert(op->type == EJS_TYPE_OBJECT);
+ mprAssert(op->objectState);
+
+ if (op->objectState == 0) {
+ return 0;
+ }
+
+ if (op->objectState->methods == 0) {
+ return ejsGetVarPtr(ejsGetSimpleProperty(ep, op, property));
+ } else {
+ return (op->objectState->methods->getProperty)(ep, op, property);
+ }
+}
+
+/******************************************************************************/
+/*************************** Advisory Locking Support *************************/
+/******************************************************************************/
+#if BLD_FEATURE_MULTITHREAD
+
+void ejsLockObj(EjsVar *vp)
+{
+ mprAssert(vp);
+ mprAssert(vp->type == EJS_TYPE_OBJECT);
+ mprAssert(vp->objectState);
+
+ if (vp->objectState->mutex == 0) {
+ vp->objectState->mutex = mprCreateLock(vp->objectState->ejs);
+ }
+ mprLock(vp->objectState->mutex);
+}
+
+/******************************************************************************/
+
+void ejsUnlockObj(EjsVar *vp)
+{
+ mprAssert(vp);
+ mprAssert(vp->type == EJS_TYPE_OBJECT);
+ mprAssert(vp->objectState);
+
+ if (vp->objectState->mutex) {
+ mprUnlock(vp->objectState->mutex);
+ }
+}
+
+#endif
+/******************************************************************************/
+/************************** Internal Support Routines *************************/
+/******************************************************************************/
+/*
+ * Create an object.
+ */
+
+static EjsObj *createObj(EJS_LOC_DEC(ep, loc))
+{
+ EjsObj *op;
+ EjsPropLink *lp;
+
+ op = (EjsObj*) ejsAllocObj(EJS_LOC_PASS(ep, loc));
+ if (op == NULL) {
+ return 0;
+ }
+
+ /*
+ * The objectState holds the dummy head for the ordered list of properties
+ */
+ lp = &op->link;
+ lp->next = lp->prev = lp;
+
+#if BLD_DEBUG
+ /*
+ * This makes it much easier to debug the list
+ */
+ lp->head = lp;
+ lp->propertyName = "dummyHead";
+#endif
+
+ return op;
+}
+
+/******************************************************************************/
+/*
+ * Destroy an object. Called by the garbage collector if there are no more
+ * references to an object.
+ */
+
+int ejsDestroyObj(Ejs *ep, EjsObj *obj)
+{
+ EjsProperty *pp;
+ EjsPropLink *lp, *head, *nextLink;
+
+ mprAssert(obj);
+
+ if (obj->destructor) {
+ EjsVar v;
+ memset(&v, 0, sizeof(v));
+ v.type = EJS_TYPE_OBJECT;
+ v.objectState = obj;
+ ejsSetVarName(ep, &v, "destructor");
+
+#if BLD_FEATURE_ALLOC_LEAK_TRACK
+ v.gc.allocatedBy = "static";
+#endif
+
+ if ((obj->destructor)(ep, &v) < 0) {
+ return -1;
+ }
+ }
+ mprFree(obj->objName);
+ obj->objName = 0;
+
+ /*
+ * Just for safety. An object may be marked by a GC on the default
+ * interpreter. After destroying, it won't be on the free list and so
+ * won't be reset.
+ */
+ obj->gcMarked = 0;
+ obj->visited = 0;
+
+ head = &obj->link;
+ for (lp = head->next; lp != head; lp = nextLink) {
+
+ pp = ejsGetPropertyFromLink(lp);
+ nextLink = lp->next;
+
+ /*
+ * We don't unlink as we are destroying all properties.
+ * If an object, we don't need to clear either.
+ */
+ if (pp->var.type != EJS_TYPE_OBJECT) {
+ ejsClearVar(ep, ejsGetVarPtr(pp));
+ }
+ ejsFree(ep, pp, EJS_SLAB_PROPERTY);
+ }
+
+#if BLD_FEATURE_MULTITHREAD
+ if (obj->mutex) {
+ mprDestroyLock(obj->mutex);
+ }
+#endif
+
+ ejsFree(ep, obj, EJS_SLAB_OBJ);
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * Fast hash. The history of this algorithm is part of lost computer science
+ * folk lore.
+ */
+
+static int hash(const char *property)
+{
+ uint sum;
+
+ mprAssert(property);
+
+ sum = 0;
+ while (*property) {
+ sum += (sum * 33) + *property++;
+ }
+
+ return sum % EJS_OBJ_HASH_SIZE;
+}
+
+/******************************************************************************/
+/*
+ * Set a new length for an array. If create is non-null, then it is the name
+ * of a new array index. If delete is set, it is the name of an index being
+ * deleted. If setLength is set to a variable, it counts the new length for the
+ * array. Note that create and delete are ignored if they are non-integer
+ * array indexes (eg. normal properties).
+ */
+
+void ejsSetArrayLength(Ejs *ep, EjsVar *obj, const char *create,
+ const char *delete, const EjsVar *setLength)
+{
+ EjsVar *vp;
+ char idx[16];
+ int oldSize, newSize, i;
+
+ vp = ejsGetPropertyAsVar(ep, obj, "length");
+ oldSize = vp->integer;
+ newSize = oldSize;
+
+ if (create) {
+ if (isdigit(*create)) {
+ i = atoi(create);
+ newSize = max(i + 1, oldSize);
+ }
+ } else if (delete) {
+ if (isdigit(*delete)) {
+ i = atoi(delete);
+ newSize = (i == (oldSize - 1) ? oldSize - 1 : oldSize);
+ }
+ } else {
+ newSize = setLength->integer;
+ }
+
+ for (i = newSize; i < oldSize; i++) {
+ mprItoa(idx, sizeof(idx), i);
+ ejsDeleteProperty(ep, obj, idx);
+ }
+
+ if (ejsWriteVarAsInteger(ep, vp, newSize) == 0) {
+ mprAssert(0);
+ }
+}
+
+/******************************************************************************/
+
+void ejsClearObjErrors(EjsVar *vp)
+{
+ if (vp == 0 || vp->type != EJS_TYPE_OBJECT || vp->objectState == 0) {
+ mprAssert(0);
+ return;
+ }
+ vp->objectState->hasErrors = 0;
+}
+
+/******************************************************************************/
+
+int ejsObjHasErrors(EjsVar *vp)
+{
+ if (vp == 0 || vp->type != EJS_TYPE_OBJECT || vp->objectState == 0) {
+ mprAssert(0);
+ return -1;
+ }
+ return vp->objectState->hasErrors;
+}
+
+/******************************************************************************/
+
+bool ejsIsObjDirty(EjsVar *vp)
+{
+ mprAssert(vp->type == EJS_TYPE_OBJECT && vp->objectState);
+
+ if (vp->type == EJS_TYPE_OBJECT && vp->objectState) {
+ return vp->objectState->dirty;
+ }
+ return 0;
+}
+
+/******************************************************************************/
+
+void ejsResetObjDirtyBit(EjsVar *vp)
+{
+ mprAssert(vp->type == EJS_TYPE_OBJECT && vp->objectState);
+
+ if (vp->type == EJS_TYPE_OBJECT && vp->objectState) {
+ vp->objectState->dirty = 0;
+ }
+}
+
+/******************************************************************************/
+/*
+ * Copy a string. Always null terminate.
+ */
+
+static int dupString(MPR_LOC_DEC(ctx, loc), uchar **dest, const void *src,
+ int nbytes)
+{
+ mprAssert(dest);
+ mprAssert(src);
+
+ if (nbytes > 0) {
+ *dest = mprMemdupInternal(MPR_LOC_PASS(ctx, loc), src, nbytes + 1);
+ if (*dest == 0) {
+ return MPR_ERR_MEMORY;
+ }
+
+ } else {
+ *dest = (uchar*) mprAlloc(ctx, 1);
+ nbytes = 0;
+ }
+
+ (*dest)[nbytes] = '\0';
+
+ return nbytes;
+}
+
+/******************************************************************************/
+
+const char *ejsGetVarTypeAsString(EjsVar *vp)
+{
+ switch (vp->type) {
+ default:
+ case EJS_TYPE_UNDEFINED:
+ return "undefined";
+ case EJS_TYPE_NULL:
+ return "null";
+ case EJS_TYPE_BOOL:
+ return "bool";
+ case EJS_TYPE_CMETHOD:
+ return "cmethod";
+ case EJS_TYPE_FLOAT:
+ return "float";
+ case EJS_TYPE_INT:
+ return "int";
+ case EJS_TYPE_INT64:
+ return "int64";
+ case EJS_TYPE_OBJECT:
+ return "object";
+ case EJS_TYPE_METHOD:
+ return "method";
+ case EJS_TYPE_STRING:
+ return "string";
+ case EJS_TYPE_STRING_CMETHOD:
+ return "string method";
+ case EJS_TYPE_PTR:
+ return "ptr";
+ }
+}
+
+/******************************************************************************/
+
+void *ejsGetVarUserPtr(EjsVar *vp)
+{
+ mprAssert(vp);
+ mprAssert(vp->type == EJS_TYPE_PTR);
+
+ if (!ejsVarIsPtr(vp)) {
+ return 0;
+ }
+ return vp->ptr.userPtr;
+}
+
+/******************************************************************************/
+
+void ejsSetVarUserPtr(EjsVar *vp, void *data)
+{
+ mprAssert(vp);
+ mprAssert(vp->type == EJS_TYPE_PTR);
+
+ vp->ptr.userPtr = data;
+}
+
+/******************************************************************************/
+/*
+ * Return TRUE if target is a subclass (or the same class) as baseClass.
+ */
+
+bool ejsIsSubClass(EjsVar *target, EjsVar *baseClass)
+{
+ do {
+ if (target->objectState == baseClass->objectState) {
+ return 1;
+ }
+ target = target->objectState->baseClass;
+ } while (target);
+
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * 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-2.0/ejs/ejsVar.h b/source4/lib/appweb/ejs-2.0/ejs/ejsVar.h
new file mode 100644
index 0000000000..071665e00b
--- /dev/null
+++ b/source4/lib/appweb/ejs-2.0/ejs/ejsVar.h
@@ -0,0 +1,1091 @@
+/*
+ * ejsVar.h -- EJS Universal Variable Type
+ */
+
+/*
+ * @copy default
+ *
+ * Copyright (c) Mbedthis Software LLC, 2003-2006. 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
+ */
+
+/*
+ * 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 methods.
+ * Properties are indexed by a character name. A variable may store one of
+ * the following types:
+ *
+ * string, integer, integer-64bit, C method, C method with string args,
+ * Javascript method, 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_EJS_VAR
+#define _h_EJS_VAR 1
+
+/********************************* Includes ***********************************/
+
+#include "mpr.h"
+
+/********************************** Defines ***********************************/
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Defined in ejs.h
+ */
+typedef struct Ejs Ejs;
+
+/*
+ * Constants
+ */
+#if BLD_FEATURE_SQUEEZE
+ /**
+ * Maximum property or variable name size
+ */
+ #define EJS_MAX_ID 64
+
+ /*
+ * EJS_VAR_HASH_SIZE must be less than the size of the bit field
+ * propertyIndex in EjsProperty.
+ */
+ #define EJS_OBJ_HASH_SIZE 13
+
+ /**
+ * Maximum number of arguments per function call
+ */
+ #define EJS_MAX_ARGS 32
+ #define EJS_INC_ARGS 8 /* Frame stack increment */
+
+#else
+ #define EJS_MAX_ID 256
+ #define EJS_OBJ_HASH_SIZE 29
+ #define EJS_MAX_ARGS 64
+ #define EJS_INC_ARGS 8
+#endif
+
+#define EJS_VAR_MAX_RECURSE 5 /* Max object loops */
+
+#if !DOXYGEN
+/*
+ * Forward declare types
+ */
+struct Ejs;
+struct EjsObj;
+struct EjsProperty;
+struct EjsVar;
+#endif
+
+/**
+ * @overview EJ primitive variable type
+ * @description EJ primitive variable values are stored in EjsVar structures.
+ * The type of the primitive data is described by an EjsType field.
+ * EjsVar variable types.
+ * @stability Prototype.
+ * @library libejs.
+ * @see EJS_TYPE_UNDEFINED, EJS_TYPE_NULL, EJS_TYPE_BOOL, EJS_TYPE_CMETHOD,
+ * EJS_TYPE_FLOAT, EJS_TYPE_INT, EJS_TYPE_INT64, EJS_TYPE_OBJECT,
+ * EJS_TYPE_METHOD, EJS_TYPE_STRING, EJS_TYPE_STRING_CMETHOD, EJS_TYPE_PTR,
+ */
+typedef uint EjsType;
+#define EJS_TYPE_UNDEFINED 0 /**< Undefined. No value has been set */
+#define EJS_TYPE_NULL 1 /**< Value defined to be null. */
+#define EJS_TYPE_BOOL 2 /**< Boolean type. */
+#define EJS_TYPE_CMETHOD 3 /**< C method */
+#define EJS_TYPE_FLOAT 4 /**< Floating point number */
+#define EJS_TYPE_INT 5 /**< Integer number */
+#define EJS_TYPE_INT64 6 /**< 64-bit Integer number */
+#define EJS_TYPE_OBJECT 7 /**< Object reference */
+#define EJS_TYPE_METHOD 8 /**< JavaScript method */
+#define EJS_TYPE_STRING 9 /**< String (immutable) */
+#define EJS_TYPE_STRING_CMETHOD 10 /**< C method with string args */
+#define EJS_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=EJS_TYPE_INT
+ */
+
+/**
+ * Set to the type used for EJS numeric variables. Will equate to int, int64
+ * or double.
+ */
+typedef BLD_FEATURE_NUM_TYPE EjsNum;
+
+/**
+ * Set to the EJS_TYPE used for EJS numeric variables. Will equate to
+ * EJS_TYPE_INT, EJS_TYPE_INT64 or EJS_TYPE_FLOAT.
+ */
+#define EJS_NUM_VAR BLD_FEATURE_NUM_TYPE_ID
+#define EJS_TYPE_NUM BLD_FEATURE_NUM_TYPE_ID
+
+/*
+ * Return TRUE if a variable is a method type
+ */
+#define ejsVarIsMethod(vp) \
+ ((vp)->type == EJS_TYPE_METHOD || (vp)->type == EJS_TYPE_STRING_CMETHOD || \
+ (vp)->type == EJS_TYPE_CMETHOD)
+
+/*
+ * Return TRUE if a variable is a numeric type
+ */
+#define ejsVarIsNumber(vp) \
+ ((vp)->type == EJS_TYPE_INT || (vp)->type == EJS_TYPE_INT64 || \
+ (vp)->type == EJS_TYPE_FLOAT)
+
+/*
+ * Return TRUE if a variable is a boolean
+ */
+#define ejsVarIsBoolean(vp) \
+ ((vp)->type == EJS_TYPE_BOOL)
+
+/*
+ * Return TRUE if a variable is an integer type
+ */
+#define ejsVarIsInteger(vp) ((vp)->type == EJS_TYPE_INT)
+
+/*
+ * Return TRUE if a variable is a string
+ */
+#define ejsVarIsString(vp) \
+ ((vp)->type == EJS_TYPE_STRING)
+
+/*
+ * Return TRUE if a variable is an object
+ */
+#define ejsVarIsObject(vp) \
+ ((vp)->type == EJS_TYPE_OBJECT)
+
+/*
+ * Return TRUE if a variable is a floating number
+ */
+#define ejsVarIsFloating(vp) \
+ ((vp)->type == EJS_TYPE_FLOAT)
+
+/*
+ * Return TRUE if a variable is undefined
+ */
+#define ejsVarIsUndefined(var) \
+ ((var)->type == EJS_TYPE_UNDEFINED)
+
+/*
+ * Return TRUE if a variable is null
+ */
+#define ejsVarIsNull(var) \
+ ((var)->type == EJS_TYPE_NULL)
+
+/*
+ * Return TRUE if a variable is a valid type (not null or undefined)
+ */
+#define ejsVarIsValid(var) \
+ (((var)->type != EJS_TYPE_NULL) && ((var)->type != EJS_TYPE_UNDEFINED))
+
+/*
+ * Return TRUE if a variable is a ptr type
+ */
+#define ejsVarIsPtr(vp) \
+ ((vp)->type == EJS_TYPE_PTR)
+
+/* MOB -- convert all ep to ejs */
+/**
+ * @overview C Method signature
+ * @description This is the calling signature for C Methods.
+ * @param ejs Ejs reference returned from ejsCreateInterp
+ * @param thisObj Reference to the "this" object. (The object containing the
+ * method).
+ * @param argc Number of arguments.
+ * @param argv Array of arguments. Each argument is held in an EjsVar type.
+ * @stability Prototype.
+ * @library libejs.
+ * @see ejsCreateCMethodVar
+ */
+typedef int (*EjsCMethod)(struct Ejs *ejs, struct EjsVar *thisObj,
+ int argc, struct EjsVar **argv);
+
+/**
+ * C Method with string arguments signature
+ * @overview C Method with string arguments signature
+ * @description This is the calling signature for C Methods.
+ * @param ejs Ejs reference returned from ejsCreateInterp
+ * @param thisObj Reference to the "this" object (object containing the
+ * method.
+ * @param argc Number of arguments.
+ * @param argv Array of arguments. Each argument is held in an C string
+ * pointer.
+ * @stability Prototype.
+ * @library libejs.
+ * @see ejsCreateStringCMethodVar
+ */
+typedef int (*EjsStringCMethod)(struct Ejs *ep, struct EjsVar *thisObj,
+ int argc, char **argv);
+
+/**
+ * Flags for types: EJS_TYPE_CMETHOD, EJS_TYPE_STRING_CMETHOD
+ * NOTE: flags == 0 means to use the EJS handle on method callbacks
+ */
+/* Use the primary handle on method callbacks */
+#define EJS_PRIMARY_HANDLE 0x1
+
+/* Use the alternate handle on method callbacks */
+#define EJS_ALT_HANDLE 0x2
+
+/** Method should not create a new local variable block */
+#define EJS_NO_LOCAL 0x4
+
+/* Method is a get accessor */
+#define EJS_GET_ACCESSOR 0x8
+
+/* Method is a set accessor */
+#define EJS_SET_ACCESSOR 0x10
+
+/*
+ * Flags for E4X (Xml type)
+ */
+/* Node is a text node */
+#define EJS_XML_FLAGS_TEXT 0x1
+
+/* Node is a processing instruction */
+#define EJS_XML_FLAGS_PI 0x2
+
+/* Node is a comment */
+#define EJS_XML_FLAGS_COMMENT 0x4
+
+/* Node is an attribute */
+#define EJS_XML_FLAGS_ATTRIBUTE 0x8
+
+/* Node is an element */
+#define EJS_XML_FLAGS_ELEMENT 0x10
+
+/**
+ * Copy depth
+ * @overview Specifies how an object should be copied
+ * @description The EjsCopyDepth type specifies how an object's properties
+ * should be copied. Several routines take EjsCopyDepth parameters to
+ * control how the properties of an object should be copied. It provides
+ * three copy options:
+ * @see ejsWriteVar
+ */
+typedef enum EjsCopyDepth {
+ /**
+ * During an object copy, object property references will be copied so
+ * that the original object and the copy will share the same reference to
+ * a property object. Properties containing primitive types including
+ * strings will have their values copied and will not share references.
+ */
+ EJS_SHALLOW_COPY, /** Copy strings. Copy object references. */
+ /*
+ * During an object copy, object properties will be replicated so that
+ * the original object and the copy will not share references to the same
+ * object properties. If the original object's properties are themselves
+ * objects, their properties will not be copied. Only their references
+ * will be copied. i.e. the deep copy is one level deep.
+ */
+ EJS_DEEP_COPY, /** Copy strings and copy object contents. */
+ /*
+ * During an object copy, all object properties will be replicated so that
+ * the original object and the copy will not share references to the same
+ * object properties. If the original object's properties are themselves
+ * objects, their properties will be copied. i.e. the copy is of infinite
+ * depth.
+ */
+ EJS_RECURSIVE_DEEP_COPY /** Copy strings and copy object contents
+ recursively (complete copy). */
+} EjsCopyDepth;
+
+
+/*
+ * Enumeration flags
+ */
+/** Enumerate data properties */
+#define EJS_ENUM_DATA 0x0
+
+/** Enumerate sub classes */
+#define EJS_ENUM_CLASSES 0x1
+
+/** Enumerate non-enumerable properties */
+#define EJS_ENUM_HIDDEN 0x2
+
+/** Enumerate all properties */
+#define EJS_ENUM_ALL (0x3)
+
+/** Magic number when allocated */
+#define EJS_MAGIC 0xe801e2ec
+#define EJS_MAGIC_FREE 0xe701e3ea
+
+
+/*
+ * Garbage Collection Linkage. Free list only uses the next pointers.
+ */
+typedef struct EjsGCLink {
+#if BLD_DEBUG
+ uint magic; /* Magic number */
+#endif
+#if BLD_FEATURE_ALLOC_LEAK_TRACK
+ const char *allocatedBy; /* Who allocated this */
+#endif
+ struct EjsGCLink *next; /* Next property */
+} EjsGCLink;
+
+
+/**
+ * @overview EJS Variable Type
+ * @description The EJ language supports an extensive set of primitive types.
+ * These variable types can efficiently store primitive data types such as
+ * integers, strings, binary string, booleans, floating point numbers,
+ * pointer references, and objects. EjsVars are the universal type used by
+ * EJ to hold objects, classes and properties.
+ * \n\n
+ * An EjsVar may store one of the following types:
+ * @li Boolean
+ * @li Floating point (if supported in this build)
+ * @li Integer
+ * @li 64 bit integer (if supported in this build)
+ * @li String
+ * @li Binary string
+ * @li C function or C++ method
+ * @li C function with string args
+ * @li Javascript method
+ * @li Object
+ * @li Null value.
+ * @li Undefined value
+ * \n\n
+ * Objects can hold object properties which are themselves EJS variables.
+ * Properties are hash indexed by the property name and are stored in
+ * an ordered sequence. i.e. Order of properties is maintained. Objects may
+ * be referenced by multiple variables and they use garbage collection to
+ * reclaim memory no longer in use by objects and properties.
+ *
+ * @warning This module is @e 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 should
+ * help minimize required lock times.
+ * @stability Prototype.
+ * @library libejs
+ * @see Ejs, EjsProperty, ejsCreateStringVar, ejsFreeVar
+ */
+
+typedef struct EjsVar { /* Size 12 bytes */
+ /*
+ * GC must be first
+ */
+#if BLD_DEBUG || BLD_FEATURE_ALLOC_LEAK_TRACK
+ EjsGCLink gc; /* Garbage collection links */
+#endif
+
+#if BLD_DEBUG
+ const char *propertyName; /* Ptr to property name */
+#endif
+
+ /*
+ * Union of primitive types. When debugging on Linux, don't use unions
+ * as the gdb debugger can't display them.
+ */
+#if (!BLD_DEBUG && !VXWORKS) || WIN || BREW_SIMULATOR
+ union {
+#endif
+ /*
+ * For debugging, we order the common types first
+ */
+ struct EjsObj *objectState; /* Object state information */
+ int integer;
+ bool boolean;
+
+#if BLD_FEATURE_FLOATING_POINT
+ double floating;
+#endif
+#if BLD_FEATURE_INT64
+ int64 integer64;
+#endif
+
+ struct {
+ int length; /* String length (sans null) */
+ /*
+ * All strings always have a trailing null allocated
+ */
+ union {
+ char *string; /* String */
+ uchar *ustring; /* Binary string */
+ };
+ };
+
+ struct { /* Javascript methods */
+ MprArray *args; /* Null terminated */
+ char *body;
+ } method;
+
+ struct { /* Method with EjsVar args */
+ EjsCMethod fn; /* Method pointer */
+ void *userData; /* User data for method */
+ } cMethod;
+
+ struct { /* Method with string args */
+ EjsStringCMethod fn; /* Method pointer */
+ void *userData; /* User data for method */
+ } cMethodWithStrings;
+
+ struct {
+ void *userPtr; /* Opaque pointer */
+ int (*destructor)(Ejs *ejs, struct EjsVar *vp);
+ } ptr;
+
+#if (!BLD_DEBUG && !VXWORKS) || WIN || BREW_SIMULATOR
+ };
+#endif
+
+ /*
+ * Packed bit field (32 bits)
+ */
+ uint flags : 8; /* Type specific flags */
+ EjsType type : 4; /* Selector into union */
+ uint stringLen : 4; /* Length of string if inline */
+ uint allocatedData : 1; /* Node needs freeing */
+ uint isArray : 1; /* Var is an array */
+ uint isArrayLength : 1; /* Var is array.length */
+ uint callsSuper : 1; /* Method calls super() */
+ uint isProperty : 1; /* Part of a property */
+ uint reserved : 11; /* Unused */
+
+} EjsVar;
+
+
+/*
+ * Linkage for the ordered list of properties
+ */
+typedef struct EjsPropLink {
+ struct EjsPropLink *next; /* Next property */
+ struct EjsPropLink *prev; /* Previous property */
+
+ /*
+ * To make debugging easier
+ */
+#if BLD_DEBUG
+ const char *propertyName; /* Pointer to name */
+ struct EjsProperty *property; /* Pointer to property */
+ struct EjsPropLink *head; /* Dummy head of list */
+#endif
+} EjsPropLink;
+
+
+/**
+ * @overview Object Property Type
+ * @description The EjsProperty type is used to store all object properties.
+ * It contains the property name, property linkage, propery attributes
+ * such as public/private, enumerable and readonly settings. It also
+ * contains an EjsVar to store the property data value.
+ * @stability Prototype.
+ * @library libejs
+ * @see Ejs, EjsVar
+ */
+typedef struct EjsProperty { /* Size 96 bytes in squeeze */
+ /*
+ * EjsVar must be first. We often take the address of "var" and take
+ * advantage of if an EjsProperty is null, then &prop->var will be null
+ * also. Be WARNED. External users should use ejsGetVarPtr and
+ * ejsGetPropertyPtr to convert between the two.
+ */
+ EjsVar var; /* Property value */
+
+ /* OPT change this to a pointer to the base class property */
+ char name[EJS_MAX_ID]; /* Name */
+
+ uint visited : 1; /* Has been traversed */
+ uint isPrivate : 1; /* Property is private */
+ uint isProtected : 1; /* Property is protected */
+ uint dontEnumerate : 1; /* Not enumerable */
+ uint dontDelete : 1; /* Prevent delete */
+ uint readonly : 1; /* Unmodifiable */
+ uint allowNonUnique : 1; /* Multiple of same name ok */
+ uint delayedDelete : 1;
+ uint reserved : 24;
+
+ EjsPropLink link; /* Ordered linked list */
+ struct EjsProperty *hashNext; /* Hash table linkage */
+
+ /* MOB -- is this really required */
+ struct EjsObj *parentObj; /* Pointer to parent object */
+
+} EjsProperty;
+
+
+#define EJS_OP_DOT 0x1
+#define EJS_OP_INDEX 0x2
+#define EJS_OP_PLUS 0x3
+#define EJS_OP_MINUS 0x4
+#define EJS_OP_MULTIPLY 0x5
+#define EJS_OP_DIVIDE 0x6
+#define EJS_OP_CALL 0x7
+
+typedef struct EjsOp {
+ int opType;
+
+} EjsOp;
+
+/*
+ * Propety Access Methods. Used per class.
+ * MOB -- rename EjsHelpers
+ */
+typedef struct EjsMethods {
+#if FUTURE
+ int (*create)(Ejs *ep, EjsVar *thisObj);
+ int (*deleteProperty)(Ejs *ep, EjsVar *thisObj, const char *prop);
+ EjsVar *(*getProperty)(Ejs *ep, EjsVar *thisObj, const char *prop);
+ EjsVar *(*setProperty)(Ejs *ep, EjsVar *thisObj, const char *prop);
+ int (*hasProperty)(Ejs *ep, EjsVar *thisObj, const char *prop);
+ int (*hasInstance)(Ejs *ep, EjsVar *thisObj, const char *prop);
+ int (*operate)(Ejs *ep, EjsVar *thisObj, EjsOp op, EjsVar *result,
+ EjsVar *lhs, EjsVar *rhs, int *code);
+#else
+
+ EjsVar *(*createProperty)(Ejs *ep, EjsVar *obj, const char *property);
+ int (*deleteProperty)(Ejs *ep, EjsVar *obj, const char *property);
+ EjsVar *(*getProperty)(Ejs *ep, EjsVar *obj, const char *property);
+ EjsVar *(*setProperty)(Ejs *ep, EjsVar *obj, const char *property,
+ const EjsVar *value);
+ /*
+ * Other implemented internal properties in ECMA-262 are:
+ *
+ * [[Construct]] implemented via EjsVar methods
+ * [[Prototype]] implemented via EjsObj->baseClass
+ * [[Class]] implemented via EjsObj->baseClass->name
+ * [[Value]] Implemented via EjsProperty + EjsVar + EjsObj
+ */
+
+ /*
+ * FUTURE -- not implemented
+ */
+ int (*canPut)(Ejs *ep, EjsVar *obj, const char *property);
+ int (*defaultValue)(Ejs *ep, EjsVar *obj, const char *property,
+ const char *hint);
+ int (*hasProperty)(Ejs *ep, EjsVar *obj, const char *property);
+ EjsVar *(*call)(Ejs *ep, EjsVar *obj, const char *property,
+ EjsVar *args);
+ int (*hasInstance)(Ejs *ep, EjsVar *obj, const char *property);
+ int (*scope)(Ejs *ep, EjsVar *obj, const char *property);
+ int (*match)(Ejs *ep, EjsVar *obj, const char *property,
+ const char *string, int index);
+#endif
+} EjsMethods;
+
+
+/*
+ * Ejs Object Type
+ */
+typedef struct EjsObj {
+ /*
+ * GC must be first
+ */
+ EjsGCLink gc; /* Garbage collection links */
+
+ union {
+ char *objName; /* Object name */
+ char *className; /* Class name */
+ };
+
+ struct EjsVar *baseClass; /* Pointer to base class object */
+
+ EjsPropLink link; /* Ordered list of properties */
+
+ /* OPT -- dynamically allocate this only if required */
+ EjsProperty *propertyHash[EJS_OBJ_HASH_SIZE]; /* Hash chains */
+
+ /* OPT -- could save this and store off baseClass only */
+ EjsMethods *methods; /* Property access methods */
+ void *nativeData; /* Native object data */
+
+ int (*destructor)(Ejs *ejs, struct EjsVar *vp);
+
+ uint numProperties : 16; /* Total count of items */
+ uint visited : 1; /* Has been traversed */
+ uint gcMarked : 1; /* Node marked in-use by GC */
+ uint permanent : 1; /* Permanent object, dont GC */
+ uint alive : 1; /* Only GC if alive */
+ uint noConstructor : 1; /* Object has no constructor */
+ uint dirty : 1; /* Object has been modified */
+ uint hasErrors : 1; /* Update error */
+ uint preventDeleteProp : 1; /* Don't allow prop deletion */
+ uint delayedDeleteProp : 1; /* Delayed delete of props */
+ uint reserved : 7; /* Unused */
+
+ Ejs *ejs; /* Owning interp */
+
+#if BLD_FEATURE_MULTITHREAD
+ MprLock *mutex; /* Advisory mutex lock */
+#endif
+} EjsObj;
+
+
+/*
+ * Define a field macro so code an use numbers in a "generic" fashion.
+ */
+#if EJS_NUM_VAR == EJS_TYPE_INT || DOXYGEN
+/*
+ * Default numeric type
+ */
+#define ejsNumber integer
+#endif
+#if EJS_NUM_VAR == EJS_TYPE_INT64
+/* Default numeric type */
+#define ejsNumber integer64
+#endif
+#if EJS_NUM_VAR == EJS_TYPE_FLOAT
+/* Default numeric type */
+#define ejsNumber floating
+#endif
+
+typedef BLD_FEATURE_NUM_TYPE EjsNumber;
+
+/*
+ * Memory allocation slabs
+ */
+#define EJS_SLAB_OBJ 0
+#define EJS_SLAB_PROPERTY 1
+#define EJS_SLAB_VAR 2
+#define EJS_SLAB_MAX 3
+
+/**
+ * Object and pointer property destructory type
+ */
+typedef int (*EjsDestructor)(Ejs *ejs, EjsVar *vp);
+
+#if BLD_FEATURE_ALLOC_LEAK_TRACK || DOXYGEN
+/*
+ * Line number information args and declarations for ejsAlloc.
+ * Use EJS_LOC_ARGS in normal user code.
+ * Use EJS_LOC_DEC in declarations.
+ * Use EJS_LOC_PASS in layered APIs to pass original line info down.
+ */
+#define EJS_LOC_ARGS(ejs) ejs, MPR_LOC
+#define EJS_LOC_DEC(ejs, loc) Ejs *ejs, const char *loc
+#define EJS_LOC_PASS(ejs, loc) ejs, loc
+#else
+#define EJS_LOC_ARGS(ejs) ejs
+#define EJS_LOC_DEC(ejs, loc) Ejs *ejs
+#define EJS_LOC_PASS(ejs, loc) ejs
+#endif
+
+/******************************* Internal Prototypes **************************/
+
+#define ejsInitVar(vp, varType) \
+ if (1) { \
+ (vp)->type = varType; \
+ (vp)->isArray = 0; \
+ (vp)->flags = 0; \
+ } else
+extern void ejsClearVar(Ejs *ep, EjsVar *vp);
+
+extern int ejsDestroyObj(Ejs *ep, EjsObj *obj);
+extern EjsVar *ejsCreatePropertyMethod(Ejs *ep, EjsVar *obj,
+ const char *name);
+extern EjsVar *ejsSetPropertyMethod(Ejs *ep, EjsVar *obj, const char *name,
+ const EjsVar *value);
+extern EjsVar *ejsGetPropertyMethod(Ejs *ep, EjsVar *obj, const char *name);
+extern int ejsDeletePropertyMethod(Ejs *ep, EjsVar *obj,
+ const char *name);
+extern void ejsSetArrayLength(Ejs *ep, EjsVar *obj, const char *creating,
+ const char *deleting, const EjsVar *setLength);
+
+/*
+ * At the moment, these are the same routine
+ */
+extern void ejsSetClassName(Ejs *ep, EjsVar *obj, const char *name);
+#define ejsSetObjName ejsSetObjName
+
+extern bool ejsIsObjDirty(EjsVar *vp);
+extern void ejsResetObjDirtyBit(EjsVar *vp);
+
+extern int ejsObjHasErrors(EjsVar *vp);
+extern void ejsClearObjErrors(EjsVar *vp);
+
+extern EjsVar *ejsClearProperty(Ejs *ep, EjsVar *obj, const char *prop);
+
+typedef int (*EjsSortFn)(Ejs *ep, EjsProperty *p1, EjsProperty *p2,
+ const char *propertyName, int order);
+extern void ejsSortProperties(Ejs *ep, EjsVar *obj, EjsSortFn fn,
+ const char *propertyName, int order);
+
+#if BLD_DEBUG
+#define ejsSetVarName(ep, vp, varName) \
+ if (1) { \
+ (vp)->propertyName = varName; \
+ if ((vp)->type == EJS_TYPE_OBJECT && \
+ (vp)->objectState && \
+ ((vp)->objectState->objName == 0)) { \
+ (vp)->objectState->objName = \
+ mprStrdup(ep, varName); \
+ } \
+ } else
+#else
+#define ejsSetVarName(ep, vp, varName)
+#endif
+
+EjsVar *ejsFindProperty(Ejs *ep, EjsVar **obj, char **property,
+ EjsVar *global, EjsVar *local, const char *fullName,
+ int create);
+
+extern EjsVar *ejsCopyProperties(Ejs *ep, EjsVar *dest,
+ const EjsVar *src, EjsCopyDepth copyDepth);
+
+#define EJS_LINK_OFFSET ((uint) (&((EjsProperty*) 0)->link))
+#define ejsGetPropertyFromLink(lp) \
+ ((EjsProperty*) ((char*) lp - EJS_LINK_OFFSET))
+
+#define ejsGetObjPtr(vp) ((EjsObj*) vp->objectState)
+
+extern void ejsMakePropertyPrivate(EjsProperty *pp, int isPrivate);
+extern void ejsMakePropertyReadOnly(EjsProperty *pp, int readonly);
+extern void ejsMakePropertyUndeleteable(EjsProperty *pp, int deletable);
+extern int ejsMakeObjLive(EjsVar *vp, bool alive);
+extern void ejsMakeClassNoConstructor(EjsVar *vp);
+
+extern bool ejsBlockInUseInt(EjsVar *vp);
+#if BLD_DEBUG
+ #define ejsBlockInUse(vp) ejsBlockInUseInt(vp)
+#else
+ #define ejsBlockInUse(vp)
+#endif
+
+/********************************* Prototypes *********************************/
+
+/*
+ * Variable constructors and destructors
+ */
+extern EjsVar *ejsCreateBinaryStringVar(Ejs *ep, const uchar *value,
+ int len);
+extern EjsVar *ejsCreateBoolVar(Ejs *ep, int value);
+extern EjsVar *ejsCreateCMethodVar(Ejs *ep, EjsCMethod fn,
+ void *userData, int flags);
+#if BLD_FEATURE_FLOATING_POINT
+extern EjsVar *ejsCreateFloatVar(Ejs *ep, double value);
+#endif
+extern EjsVar *ejsCreateIntegerVar(Ejs *ep, int value);
+#if BLD_FEATURE_INT64
+extern EjsVar *ejsCreateInteger64Var(Ejs *ep, int64 value);
+#endif
+
+extern EjsVar *ejsCreateMethodVar(Ejs *ep, const char *body,
+ MprArray *args, int flags);
+extern EjsVar *ejsCreateNullVar(Ejs *ep);
+extern EjsVar *ejsCreateNumberVar(Ejs *ep, EjsNumber value);
+
+#define ejsCreateObjVar(ep) \
+ ejsCreateObjVarInternal(EJS_LOC_ARGS(ep))
+extern EjsVar *ejsCreateObjVarInternal(EJS_LOC_DEC(ep, loc));
+
+extern EjsVar *ejsCreatePtrVar(Ejs *ep, void *ptr, EjsDestructor dest);
+
+extern EjsVar *ejsCreateStringCMethodVar(Ejs *ep, EjsStringCMethod fn,
+ void *userData, int flags);
+
+#define ejsCreateStringVar(ep, value) \
+ ejsCreateStringVarInternal(EJS_LOC_ARGS(ep), value)
+extern EjsVar *ejsCreateStringVarInternal(EJS_LOC_DEC(ep, loc),
+ const char *value);
+
+extern EjsVar *ejsCreateUndefinedVar(Ejs *ep);
+
+/* MOB -- naming. Should be Create/Destroy */
+extern void ejsFreeVar(Ejs *ep, EjsVar *vp);
+
+/*
+ * Var support routines
+ */
+extern int ejsGetVarFlags(EjsVar *vp);
+extern void ejsSetVarFlags(EjsVar *obj, int flags);
+
+extern EjsType ejsGetVarType(EjsVar *vp);
+extern const char *ejsGetVarTypeAsString(EjsVar *vp);
+
+extern void *ejsGetCMethodUserData(EjsVar *obj);
+extern void ejsSetCMethodUserData(EjsVar *obj, void *userData);
+
+extern void *ejsGetVarUserPtr(EjsVar *vp);
+extern void ejsSetVarUserPtr(EjsVar *vp, void *data);
+
+
+/*
+ * Variable access and manipulation. These work on standalone objects.
+ */
+#define ejsDupVar(ep, src, copyDepth) \
+ ejsDupVarInternal(EJS_LOC_ARGS(ep), src, copyDepth)
+extern EjsVar *ejsDupVarInternal(EJS_LOC_DEC(ep, loc), EjsVar *src,
+ EjsCopyDepth copyDepth);
+#define ejsWriteVar(ep, dest, src, copyDepth) \
+ ejsWriteVarInternal(EJS_LOC_ARGS(ep), dest, src, copyDepth)
+extern EjsVar *ejsWriteVarInternal(EJS_LOC_DEC(ep, loc), EjsVar *dest,
+ const EjsVar *src, EjsCopyDepth copyDepth);
+extern EjsVar *ejsWriteVarAsBinaryString(Ejs *ep, EjsVar *dest,
+ const uchar *value, int len);
+extern EjsVar *ejsWriteVarAsBoolean(Ejs *ep, EjsVar *dest, bool value);
+extern EjsVar *ejsWriteVarAsCMethod(Ejs *ep, EjsVar *dest, EjsCMethod fn,
+ void *userData, int flags);
+#if BLD_FEATURE_FLOATING_POINT
+extern EjsVar *ejsWriteVarAsFloat(Ejs *ep, EjsVar *dest, double value);
+#endif
+extern EjsVar *ejsWriteVarAsInteger(Ejs *ep, EjsVar *dest, int value);
+#if BLD_FEATURE_INT64
+extern EjsVar *ejsWriteVarAsInteger64(Ejs *ep, EjsVar *dest, int64 value);
+#endif
+extern EjsVar *ejsWriteVarAsMethod(Ejs *ep, EjsVar *dest,
+ const char *body, MprArray *args);
+extern EjsVar *ejsWriteVarAsNull(Ejs *ep, EjsVar *dest);
+extern EjsVar *ejsWriteVarAsNumber(Ejs *ep, EjsVar *dest, EjsNum value);
+#define ejsWriteVarAsString(ep, dest, value) \
+ ejsWriteVarAsStringInternal(EJS_LOC_ARGS(ep), dest, value)
+extern EjsVar *ejsWriteVarAsStringInternal(EJS_LOC_DEC(ep, loc),
+ EjsVar *dest, const char *value);
+extern EjsVar *ejsWriteVarAsStringCMethod(Ejs *ep, EjsVar *dest,
+ EjsStringCMethod fn, void *userData, int flags);
+extern EjsVar *ejsWriteVarAsUndefined(Ejs *ep, EjsVar *dest);
+
+/*
+ * These routines do not convert types
+ */
+/* MOB -- make this a fn and pass back the length as an arg */
+#define ejsReadVarAsBinaryString(vp) ((const uchar*) (vp->ustring));
+#define ejsReadVarAsBoolean(vp) (vp->boolean);
+#define ejsReadVarAsCMethod(vp) (vp->cMethod);
+#if BLD_FEATURE_FLOATING_POINT
+#define ejsReadVarAsFloat(vp) (vp->floating);
+#endif
+#define ejsReadVarAsInteger(vp) (vp->integer);
+#if BLD_FEATURE_INT64
+#define ejsReadVarAsInteger64(vp) (vp->int64);
+#endif
+#define ejsReadVarAsString(vp) ((const char*) (vp->string));
+#define ejsReadVarAsStringCMethod(vp) (vp->cMethodWithStrings);
+/* MOB -- remove this fn */
+#define ejsReadVarStringLength(vp) (vp->length);
+
+/*
+ * Object property creation routines
+ */
+extern EjsProperty *ejsCreateProperty(Ejs *ep, EjsVar *obj, const char *prop);
+extern EjsProperty *ejsCreateSimpleProperty(Ejs *ep, EjsVar *obj,
+ const char *prop);
+extern EjsProperty *ejsCreateSimpleNonUniqueProperty(Ejs *ep, EjsVar *obj,
+ const char *prop);
+/* MOB -- should be destroy */
+extern int ejsDeleteProperty(Ejs *ep, EjsVar *obj, const char *prop);
+
+
+/*
+ * Get property routines
+ */
+extern EjsProperty *ejsGetProperty(Ejs *ep, EjsVar *obj, const char *prop);
+extern EjsProperty *ejsGetSimpleProperty(Ejs *ep, EjsVar *obj,
+ const char *prop);
+
+extern EjsVar *ejsGetPropertyAsVar(Ejs *ep, EjsVar *obj,
+ const char *prop);
+extern int ejsGetPropertyCount(EjsVar *obj);
+
+extern const uchar *ejsGetPropertyAsBinaryString(Ejs *ep, EjsVar *obj,
+ const char *prop, int *length);
+extern bool ejsGetPropertyAsBoolean(Ejs *ep, EjsVar *obj,
+ const char *prop);
+extern int ejsGetPropertyAsInteger(Ejs *ep, EjsVar *obj,
+ const char *prop);
+extern int64 ejsGetPropertyAsInteger64(Ejs *ep, EjsVar *obj,
+ const char *prop);
+extern EjsNum ejsGetPropertyAsNumber(Ejs *ep, EjsVar *obj,
+ const char *prop);
+extern void *ejsGetPropertyAsPtr(Ejs *ep, EjsVar *obj,
+ const char *prop);
+extern const char *ejsGetPropertyAsString(Ejs *ep, EjsVar *obj,
+ const char *prop);
+
+/*
+ * Object property update routines
+ */
+extern EjsProperty *ejsSetBaseProperty(Ejs *ep, EjsVar *obj, const char *prop,
+ const EjsVar *value);
+extern EjsProperty *ejsSetProperty(Ejs *ep, EjsVar *obj, const char *prop,
+ const EjsVar *value);
+extern EjsProperty *ejsSetPropertyAndFree(Ejs *ep, EjsVar *obj,
+ const char *prop, EjsVar *value);
+extern EjsProperty *ejsSetPropertyToBinaryString(Ejs *ep, EjsVar *obj,
+ const char *prop, const uchar *value, int len);
+extern EjsProperty *ejsSetPropertyToBoolean(Ejs *ep, EjsVar *obj,
+ const char *prop, bool value);
+extern EjsProperty *ejsSetPropertyToCMethod(Ejs *ep, EjsVar *obj,
+ const char *prop, EjsCMethod fn, void *userData,
+ int flags);
+#if BLD_FEATURE_FLOATING_POINT
+extern EjsProperty *ejsSetPropertyToFloat(Ejs *ep, EjsVar *obj,
+ const char *prop, double value);
+#endif
+extern EjsProperty *ejsSetPropertyToInteger(Ejs *ep, EjsVar *obj,
+ const char *prop, int value);
+#if BLD_FEATURE_INT64
+extern EjsProperty *ejsSetPropertyToInteger64(Ejs *ep, EjsVar *obj,
+ const char *prop, int64 value);
+#endif
+extern EjsProperty *ejsSetPropertyToMethod(Ejs *ep, EjsVar *obj,
+ const char *prop, const char *body, MprArray *args,
+ int flags);
+extern EjsProperty *ejsSetPropertyToNewObj(Ejs *ep, EjsVar *obj,
+ const char *prop, const char *className,
+ MprArray *args);
+extern EjsProperty *ejsSetPropertyToNull(Ejs *ep, EjsVar *obj,
+ const char *prop);
+extern EjsProperty *ejsSetPropertyToNumber(Ejs *ep, EjsVar *obj,
+ const char *prop, EjsNum value);
+extern EjsProperty *ejsSetPropertyToObj(Ejs *ep, EjsVar *obj,
+ const char *prop);
+extern EjsProperty *ejsSetPropertyToPtr(Ejs *ep, EjsVar *obj,
+ const char *prop, void *ptr, EjsDestructor destructor);
+
+extern EjsProperty *ejsSetPropertyToStringCMethod(Ejs *ep, EjsVar *obj,
+ const char *prop, EjsStringCMethod fn,
+ void *userData, int flags);
+extern EjsProperty *ejsSetPropertyToString(Ejs *ep, EjsVar *obj,
+ const char *prop, const char *value);
+extern EjsProperty *ejsSetPropertyToUndefined(Ejs *ep, EjsVar *obj,
+ const char *prop);
+
+
+/* Convenience function */
+extern EjsVar *ejsSetPropertyToObjAsVar(Ejs *ep, EjsVar *obj,
+ const char *prop);
+extern void ejsSetObjDestructor(Ejs *ep, EjsVar *obj,
+ EjsDestructor destructor);
+extern void ejsClearObjDestructor(Ejs *ep, EjsVar *obj);
+
+/*
+ * Enumeration of properties
+ * MOB -- should these take an ejs parameter to be consistent
+ */
+extern EjsProperty *ejsGetFirstProperty(const EjsVar *obj, int flags);
+extern EjsProperty *ejsGetNextProperty(EjsProperty *last, int flags);
+
+/*
+ * Method definition and control.
+ */
+extern EjsProperty *ejsDefineMethod(Ejs *ep, EjsVar *obj, const char *prop,
+ const char *body, MprArray *args);
+extern EjsProperty *ejsDefineCMethod(Ejs *ep, EjsVar *obj, const char *prop,
+ EjsCMethod fn, int flags);
+
+extern EjsProperty *ejsDefineStringCMethod(Ejs *ep, EjsVar *obj,
+ const char *prop, EjsStringCMethod fn, int flags);
+
+extern EjsProperty *ejsDefineAccessors(Ejs *ep, EjsVar *obj,
+ const char *prop, const char *getBody,
+ const char *setBody);
+extern EjsProperty *ejsDefineCAccessors(Ejs *ep, EjsVar *obj,
+ const char *prop, EjsCMethod getFn, EjsCMethod setFn,
+ int flags);
+
+/*
+ * Macro to get the variable value portion of a property
+ */
+#define ejsGetVarPtr(pp) (&((pp)->var))
+#define ejsGetPropertyPtr(vp) ((EjsProperty*) vp)
+
+/* MOB -- take ejs to be consistent */
+extern int ejsMakePropertyEnumerable(EjsProperty *pp, bool enumerable);
+extern int ejsMakeObjPermanent(EjsVar *vp, bool permanent);
+
+
+/*
+ * Var conversion routines
+ * MOB -- should these take an Ejs as first arg for consistency
+ */
+extern bool ejsVarToBoolean(EjsVar *vp);
+#if BLD_FEATURE_FLOATING_POINT
+extern double ejsVarToFloat(EjsVar *vp);
+#endif
+extern int ejsVarToInteger(EjsVar *vp);
+#if BLD_FEATURE_INT64
+extern int64 ejsVarToInteger64(EjsVar *vp);
+#endif
+extern EjsNum ejsVarToNumber(EjsVar *vp);
+extern char *ejsVarToString(Ejs *ep, EjsVar *vp);
+extern char *ejsVarToStringEx(Ejs *ep, EjsVar *vp, bool *alloc);
+extern char *ejsFormatVar(Ejs *ep, const char *fmt, EjsVar *vp);
+
+#if BLD_FEATURE_FLOATING_POINT
+extern double ejsParseFloat(const char *str);
+#endif
+/*
+ * Parsing and type range checking routines
+ */
+extern bool ejsParseBoolean(const char *str);
+extern int ejsParseInteger(const char *str);
+#if BLD_FEATURE_INT64
+extern int64 ejsParseInteger64(const char *str);
+#endif
+extern EjsNum ejsParseNumber(const char *str);
+extern EjsVar *ejsParseVar(Ejs *ep, const char *str, EjsType prefType);
+
+#if BLD_FEATURE_FLOATING_POINT
+extern bool ejsIsInfinite(double f);
+extern bool ejsIsNan(double f);
+#endif
+
+/*
+ * Advisory locking support
+ */
+#if BLD_FEATURE_MULTITHREAD
+extern void ejsLockObj(EjsVar *vp);
+extern void ejsUnlockObj(EjsVar *vp);
+#endif
+
+/*
+ * Just for debugging
+ */
+extern bool ejsObjIsCollectable(EjsVar *vp);
+
+#ifdef __cplusplus
+}
+#endif
+
+/*****************************************************************************/
+#endif /* _h_EJS_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/ejs-2.0/ejs/lib/event.js b/source4/lib/appweb/ejs-2.0/ejs/lib/event.js
new file mode 100644
index 0000000000..283a3ec72f
--- /dev/null
+++ b/source4/lib/appweb/ejs-2.0/ejs/lib/event.js
@@ -0,0 +1,141 @@
+/*
+ * @file event.js
+ * @brief Event class
+ * @copy Copyright (c) Mbedthis Software LLC, 2005-2006. All Rights Reserved.
+ *
+ * Usage:
+ * listener = new System.Listener();
+ * listener.onClick = function() {
+ * // Any code here
+ * }
+ * eventTarget.addListener(eventName, listener);
+ * or
+ * listener = new System.Listener(obj, method);
+ * eventTarget.addListener(eventName, listener);
+ *
+ * To fire events:
+ * eventTarget.fire(eventName, new System.Event("My Event"));
+ */
+
+/******************************************************************************/
+/*
+ * Base event class
+ */
+class System.Event
+{
+ var type; // keyboard
+ var timeStamp;
+ var arg;
+
+ /* MOB -- constructor should take a type */
+ function Event(arg)
+ {
+ timeStamp = time();
+ type = "default";
+ this.arg = arg;
+ }
+}
+
+/* MOB -- should not be needed */
+Event = System.Event;
+
+class System.Listener
+{
+ var obj;
+ var method;
+
+ function Listener(obj, method)
+ {
+ if (arguments.length >= 1) {
+ this.obj = obj;
+ } else {
+ this.obj = this;
+ }
+ if (arguments.length == 2) {
+ this.method = method;
+ } else {
+ this.method = "onEvent";
+ }
+ }
+}
+/* MOB -- should not be needed */
+Listener = System.Listener;
+
+
+/*
+ * The Event target class
+ */
+class System.EventTarget
+{
+ // Private
+ var events; /* Hash of a event names */
+
+ function EventTarget()
+ {
+ events = new Object();
+ }
+
+ // Public
+ function addListener(eventName, listener)
+ {
+ var listeners = events[eventName];
+ if (listeners == undefined) {
+ listeners = events[eventName] = new Array();
+ }
+ if (arguments.length == 2) {
+ var method = eventName;
+ }
+ /* MOB OPT */
+ for (var i = 0; i < listeners.length; i++) {
+ var l = listeners[i];
+ if (l == listener) {
+ return;
+ }
+ }
+ listeners[listeners.length] = listener;
+ }
+
+ function removeListener(eventName, listener)
+ {
+ var listeners = events[eventName];
+
+ if (listeners == undefined) {
+ return;
+ }
+
+ for (var i = 0; i < listeners.length; i++) {
+ var l = listeners[i];
+ if (l == listener) {
+ // MOB -- want listeners.splice here
+ // listeners.splice(i, 1);
+ for (var j = i; j < (listeners.length - 1); j++) {
+ listeners[j] = listeners[j + 1];
+ }
+ delete listeners[listeners.length - 1];
+ i = listeners.length;
+ }
+ }
+ }
+
+ function fire(eventName, event)
+ {
+ var listeners = events[eventName];
+
+ if (listeners == undefined) {
+ // println("Event.fire(): unknown eventName " + eventName);
+ return;
+ }
+
+ for (var i = listeners.length - 1; i >= 0; i--) {
+ var listener = listeners[i];
+ var method = listener.obj[listener.method];
+ if (method == undefined) {
+ throw new EvalError("Undefined method: " + listener.method);
+ }
+ listener.obj[listener.method](listener, event);
+ }
+ }
+}
+
+/* MOB -- should not be needed */
+EventTarget = System.EventTarget;
diff --git a/source4/lib/appweb/ejs-2.0/ejs/lib/global.js b/source4/lib/appweb/ejs-2.0/ejs/lib/global.js
new file mode 100644
index 0000000000..f2daaa57c0
--- /dev/null
+++ b/source4/lib/appweb/ejs-2.0/ejs/lib/global.js
@@ -0,0 +1,34 @@
+/*
+ * @file global.js
+ * @brief Misc global functions
+ * @copy Copyright (c) Mbedthis Software LLC, 2005-2006. All Rights Reserved.
+ */
+
+/******************************************************************************/
+
+function min(a, b)
+{
+ if (a < b) {
+ return a;
+ } else {
+ return b;
+ }
+}
+
+
+function max(a, b)
+{
+ if (a > b) {
+ return a;
+ } else {
+ return b;
+ }
+}
+
+function abs(a)
+{
+ if (a < 0) {
+ return -a;
+ }
+ return a;
+}
diff --git a/source4/lib/appweb/ejs-2.0/ejs/lib/startup.js b/source4/lib/appweb/ejs-2.0/ejs/lib/startup.js
new file mode 100644
index 0000000000..e627a96e04
--- /dev/null
+++ b/source4/lib/appweb/ejs-2.0/ejs/lib/startup.js
@@ -0,0 +1,15 @@
+/*
+ * @file startup.js
+ * @brief Embedded JavaScript Startup Code
+ * @copy Copyright (c) Mbedthis Software LLC, 2005-2006. All Rights Reserved.
+ *
+ * Invoked automatically on startup.
+ */
+
+/******************************************************************************/
+
+// println("Loading startup.js ...");
+
+include("lib/event.js");
+include("lib/global.js");
+include("lib/timer.js");
diff --git a/source4/lib/appweb/ejs-2.0/ejs/lib/timer.js b/source4/lib/appweb/ejs-2.0/ejs/lib/timer.js
new file mode 100644
index 0000000000..f4cb8b12ce
--- /dev/null
+++ b/source4/lib/appweb/ejs-2.0/ejs/lib/timer.js
@@ -0,0 +1,158 @@
+/*
+ * @file timer.js
+ * @brief Timer class
+ * @copy Copyright (c) Mbedthis Software LLC, 2005-2006. All Rights Reserved.
+ *
+ * Usage:
+ * timer = new System.Timer("name", period);
+ * timer.onTick = function(arg) {
+ * // Anything here
+ * }
+ * timer.start();
+ * or
+ *
+ * timer = new System.Timer("name", period, obj, method);
+ * timer.start();
+ */
+
+/******************************************************************************/
+
+class System.Timer
+{
+ var id;
+
+ /* MOB -- really need accessor on period. If user updates period,
+ then due must be updated. */
+ var period;
+ var due;
+ var runOnce; // Run timer just once
+ var method; // Callback method
+ var obj; // Callback object
+
+ function Timer(id, period, obj, method)
+ {
+ this.id = id;
+ this.period = period;
+ due = time() + period;
+
+ if (arguments.length >= 3) {
+ this.obj = obj;
+ } else {
+ this.obj = this;
+ }
+ if (arguments.length >= 4) {
+ this.method = method;
+ } else {
+ this.method = "onTick";
+ }
+ }
+
+ /* MOB this should be deprecated */
+ function reschedule(period)
+ {
+ /* MOB -- should update the timer service somehow */
+ this.period = period;
+ }
+
+ function run(now)
+ {
+ if (obj[method] == undefined) {
+ trace("Timer cant find timer method " + method);
+ due = now + this.period;
+ return;
+ }
+
+ /*
+ * Run the timer
+ */
+ try {
+ obj[method](this);
+ }
+ catch (error) {
+ trace("Timer exception: " + error);
+ }
+
+ if (runOnce) {
+ timerService.removeTimer(this);
+
+ } else {
+ due = now + this.period;
+ }
+ }
+
+ function start()
+ {
+ if (obj[method] == undefined) {
+ throw new Error("Callback method is undefined");
+ } else {
+ timerService.addTimer(this);
+ }
+ }
+
+ function stop()
+ {
+ timerService.removeTimer(this);
+ }
+
+}
+
+/* MOB -- should not need this */
+Timer = System.Timer;
+
+
+/*
+ * Timer service
+ */
+class System.TimerService
+{
+ var timers;
+ var nextDue;
+
+ function TimerService()
+ {
+ timers = new Object();
+ nextDue = 0;
+ global.timerService = this;
+ }
+
+ function addTimer(timer)
+ {
+ timers[timer.id] = timer;
+ }
+
+ function removeTimer(timer)
+ {
+ try {
+ delete timers[timer.id];
+ }
+ catch {}
+ }
+
+ function getIdleTime()
+ {
+ return nextDue - time();
+ }
+
+ function runTimers()
+ {
+ var now = time();
+
+ nextDue = 2147483647; /* MOB -- MATH.MAX_INT; */
+
+ for each (var timer in timers)
+ {
+ if (timer.due < now) {
+ timer.run(now);
+ }
+ }
+ for each (var timer in timers)
+ {
+ if (timer.due < nextDue) {
+ nextDue = timer.due;
+ }
+ }
+ // println("runTimers leaving with " + (nextDue - now));
+ return nextDue - time();
+ }
+}
+TimerService = System.TimerService;
diff --git a/source4/lib/appweb/ejs-2.0/ejs/system/.ignore b/source4/lib/appweb/ejs-2.0/ejs/system/.ignore
new file mode 100755
index 0000000000..fb5a29031e
--- /dev/null
+++ b/source4/lib/appweb/ejs-2.0/ejs/system/.ignore
@@ -0,0 +1 @@
+.updated
diff --git a/source4/lib/appweb/ejs-2.0/ejs/system/Makefile b/source4/lib/appweb/ejs-2.0/ejs/system/Makefile
new file mode 100755
index 0000000000..2d83662655
--- /dev/null
+++ b/source4/lib/appweb/ejs-2.0/ejs/system/Makefile
@@ -0,0 +1,27 @@
+#
+# Makefile to build the EJS Object Model
+#
+# Copyright (c) Mbedthis Software LLC, 2003-2006. All Rights Reserved.
+#
+
+COMPILE := *.c
+EXPORT_OBJECTS := yes
+MAKE_IFLAGS := -I.. -I../../mpr -I../../exml
+
+include make.dep
+
+ifeq ($(BLD_HOST_UNIX),1)
+PRE_DIRS = UNIX
+else
+PRE_DIRS = $(BLD_HOST_OS)
+endif
+
+compileExtra: .updated
+
+.updated: $(FILES)
+ @touch .updated
+
+## Local variables:
+## tab-width: 4
+## End:
+## vim: tw=78 sw=4 ts=4
diff --git a/source4/lib/appweb/ejs-2.0/ejs/system/README.TXT b/source4/lib/appweb/ejs-2.0/ejs/system/README.TXT
new file mode 100644
index 0000000000..a24e0e299c
--- /dev/null
+++ b/source4/lib/appweb/ejs-2.0/ejs/system/README.TXT
@@ -0,0 +1,63 @@
+Embedded JavaScript System Model
+
+
+- Need args, arg types and exceptions thrown
+- Error classes
+
+class Global
+ class System
+ class environment
+ var
+ class GC
+ void function run()
+ function tune()
+ function getUsedMemory() // Should be properties
+ function getAllocatedMemory() // Should be properties
+
+ var javascript
+ var null
+ var undefined
+ var true
+ var false
+ var Nan
+ var Infinity
+
+ function random // Not implemented
+ function sleep // Not implemented
+ function exit
+ function yield // Not implemented
+
+ Debug
+ isDebugMode
+
+ Limits
+ isLimitsMode // Not implemented
+ stack // Not implemented
+ heap // Not implemented
+ flash // Not implemented
+
+ Memory
+ getUsedMemory() // Should be properties
+ getAvailableMemory() // Should be properties
+ used
+ flash // Not implemented
+
+ assert()
+ breakpoint()
+ dirname()
+ basename()
+ eval()
+ exit()
+ print()
+ println()
+ printVars()
+ sleep()
+ sort()
+ time()
+ typeof()
+ include()
+ trace()
+ printf() // Not implemented
+ sprintf()
+
+
diff --git a/source4/lib/appweb/ejs-2.0/ejs/system/UNIX/.ignore b/source4/lib/appweb/ejs-2.0/ejs/system/UNIX/.ignore
new file mode 100644
index 0000000000..fb5a29031e
--- /dev/null
+++ b/source4/lib/appweb/ejs-2.0/ejs/system/UNIX/.ignore
@@ -0,0 +1 @@
+.updated
diff --git a/source4/lib/appweb/ejs-2.0/ejs/system/UNIX/Makefile b/source4/lib/appweb/ejs-2.0/ejs/system/UNIX/Makefile
new file mode 100755
index 0000000000..424747052a
--- /dev/null
+++ b/source4/lib/appweb/ejs-2.0/ejs/system/UNIX/Makefile
@@ -0,0 +1,21 @@
+#
+# Makefile to build the EJS Object Model for WIN
+#
+# Copyright (c) Mbedthis Software LLC, 2003-2006. All Rights Reserved.
+#
+
+COMPILE := *.c
+EXPORT_OBJECTS := yes
+MAKE_IFLAGS := -I../.. -I../../../mpr
+
+include make.dep
+
+compileExtra: .updated
+
+.updated: $(FILES)
+ @touch .updated
+
+## Local variables:
+## tab-width: 4
+## End:
+## vim: tw=78 sw=4 ts=4
diff --git a/source4/lib/appweb/ejs-2.0/ejs/system/UNIX/ejsFile.c b/source4/lib/appweb/ejs-2.0/ejs/system/UNIX/ejsFile.c
new file mode 100644
index 0000000000..772303152e
--- /dev/null
+++ b/source4/lib/appweb/ejs-2.0/ejs/system/UNIX/ejsFile.c
@@ -0,0 +1,98 @@
+/*
+ * @file ejsFile.c
+ * @brief File class for the EJ System Object Model
+ */
+/********************************** Copyright *********************************/
+/*
+ * Copyright (c) Mbedthis Software LLC, 2003-2006. All Rights Reserved.
+ */
+/********************************** Includes **********************************/
+
+#include "ejs.h"
+
+/******************************************************************************/
+/*
+ * Default Constructor
+ */
+
+/******************************************************************************/
+/************************************ Methods *********************************/
+/******************************************************************************/
+/*
+ * function open();
+ */
+
+static int openProc(Ejs *ep, EjsVar *thisObj, int argc, EjsVar **argv)
+{
+ ejsTrace(ep, "File.open()\n");
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * function close();
+ */
+
+static int closeProc(Ejs *ep, EjsVar *thisObj, int argc, EjsVar **argv)
+{
+ ejsTrace(ep, "File.close()\n");
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * function read();
+ */
+
+static int readProc(Ejs *ep, EjsVar *thisObj, int argc, EjsVar **argv)
+{
+ ejsTrace(ep, "File.read()\n");
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * function write();
+ */
+
+static int writeProc(Ejs *ep, EjsVar *thisObj, int argc, EjsVar **argv)
+{
+ ejsTrace(ep, "File.write()\n");
+ return 0;
+}
+
+/******************************************************************************/
+/******************************** Initialization ******************************/
+/******************************************************************************/
+
+int ejsDefineFileClass(Ejs *ep)
+{
+ EjsVar *fileClass;
+
+ fileClass = ejsDefineClass(ep, "File", "Object", 0);
+ if (fileClass == 0) {
+ return MPR_ERR_CANT_INITIALIZE;
+ }
+
+ /*
+ * Define the methods
+ */
+ ejsDefineCMethod(ep, fileClass, "open", openProc, 0);
+ ejsDefineCMethod(ep, fileClass, "close", closeProc, 0);
+ ejsDefineCMethod(ep, fileClass, "read", readProc, 0);
+ ejsDefineCMethod(ep, fileClass, "write", writeProc, 0);
+
+ return ejsObjHasErrors(fileClass) ? MPR_ERR_CANT_INITIALIZE: 0;
+}
+
+/******************************************************************************/
+
+/*
+ * 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-2.0/ejs/system/UNIX/ejsFileSystem.c b/source4/lib/appweb/ejs-2.0/ejs/system/UNIX/ejsFileSystem.c
new file mode 100755
index 0000000000..7b39c16e4d
--- /dev/null
+++ b/source4/lib/appweb/ejs-2.0/ejs/system/UNIX/ejsFileSystem.c
@@ -0,0 +1,454 @@
+/*
+ * @file ejsFileSystem.c
+ * @brief FileSystem class for the EJ System Object Model
+ * MOB -- this is almost the same as for Windows. Should common up.
+ */
+/********************************** Copyright *********************************/
+/*
+ * Copyright (c) Mbedthis Software LLC, 2003-2006. All Rights Reserved.
+ */
+/********************************** Includes **********************************/
+
+#include "ejs.h"
+#include <dirent.h>
+
+/******************************************************************************/
+/************************************ Methods *********************************/
+/******************************************************************************/
+/*
+ * function void access(string path);
+ * MOB - API insufficient. Access for read or write?
+ */
+
+static int accessProc(Ejs *ejs, EjsVar *thisObj, int argc, EjsVar **argv)
+{
+ int rc;
+
+ if (argc != 1 || !ejsVarIsString(argv[0])) {
+ ejsError(ejs, EJS_ARG_ERROR, "Bad usage: access(path)");
+ return -1;
+ }
+
+ rc = access(argv[0]->string, 04);
+
+ ejsSetReturnValueToBoolean(ejs, (rc == 0) ? 1 : 0);
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * function void mkdir(string path);
+ */
+
+static int mkdirProc(Ejs *ejs, EjsVar *thisObj, int argc, EjsVar **argv)
+{
+ if (argc != 1 || !ejsVarIsString(argv[0])) {
+ ejsError(ejs, EJS_ARG_ERROR, "Bad usage: mkdir(path)");
+ return -1;
+ }
+
+ if (mprMakeDirPath(ejs, argv[0]->string) < 0) {
+ ejsError(ejs, EJS_IO_ERROR, "Cant create directory");
+ return -1;
+ }
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * function void rmdir(string path);
+ */
+
+static int rmdirProc(Ejs *ejs, EjsVar *thisObj, int argc, EjsVar **argv)
+{
+ int rc;
+
+ if (argc != 1 || !ejsVarIsString(argv[0])) {
+ ejsError(ejs, EJS_ARG_ERROR, "Bad usage: mkdir(path)");
+ return -1;
+ }
+
+ rc = mprDeleteDir(ejs, argv[0]->string);
+
+ if (rc < 0) {
+ ejsError(ejs, EJS_IO_ERROR, "Cant remove directory");
+ return -1;
+ }
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * function void dirList(string path, [bool enumDirs]);
+ * MOB -- need pattern to match (what about "." and ".." and ".*"
+ */
+
+static int dirListProc(Ejs *ejs, EjsVar *thisObj, int argc, EjsVar **argv)
+{
+ DIR *dir;
+ struct dirent *dirent;
+ char path[MPR_MAX_FNAME];
+ EjsVar *array, *vp;
+ uchar enumDirs;
+
+ if (argc < 1 || !ejsVarIsString(argv[0])) {
+ ejsError(ejs, EJS_ARG_ERROR, "Bad usage: dirList(path)");
+ return -1;
+ }
+ if (argc == 2) {
+ enumDirs = ejsVarToBoolean(argv[1]);
+ } else {
+ enumDirs = 0;
+ }
+ array = ejsCreateArray(ejs, 0);
+ ejsMakeObjPermanent(array, 1);
+
+ /*
+ * First collect the files
+ */
+ mprSprintf(path, sizeof(path), "%s/*.*", argv[0]->string);
+
+ dir = opendir(path);
+ if (dir == 0) {
+ ejsError(ejs, EJS_ARG_ERROR, "Can't enumerate dirList(path)");
+ return -1;
+ }
+
+ while ((dirent = readdir(dir)) != 0) {
+ if (dirent->d_name[0] == '.') {
+ continue;
+ }
+ if (!enumDirs || (dirent->d_type & DT_DIR)) {
+ mprSprintf(path, sizeof(path), "%s/%s", argv[0]->string,
+ dirent->d_name);
+ vp = ejsCreateStringVar(ejs, path);
+ ejsAddArrayElt(ejs, array, vp, EJS_SHALLOW_COPY);
+ ejsFreeVar(ejs, vp);
+ }
+ }
+
+ closedir(dir);
+
+ ejsSetReturnValue(ejs, array);
+ ejsMakeObjPermanent(array, 0);
+
+ /*
+ * Can free now as the return value holds the reference
+ */
+ ejsFreeVar(ejs, array);
+
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * function void getFreeSpace();
+ */
+
+static int getFreeSpaceProc(Ejs *ejs, EjsVar *thisObj, int argc, EjsVar **argv)
+{
+#if UNUSED
+ MprApp *app;
+ uint space;
+
+ app = mprGetApp(ejs);
+ space = IFILEMGR_GetFreeSpace(app->fileMgr, 0);
+ ejsSetReturnValueToInteger(ejs, space);
+#endif
+
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * function void writeFile(string path, var data);
+ */
+
+static int writeFileProc(Ejs *ejs, EjsVar *thisObj, int argc, EjsVar **argv)
+{
+ MprFile *file;
+ char *data, *buf;
+ int bytes, length, rc;
+
+ if (argc != 2 || !ejsVarIsString(argv[0])) {
+ ejsError(ejs, EJS_ARG_ERROR, "Bad usage: writeFile(path, var)");
+ return -1;
+ }
+
+ if (ejsVarIsString(argv[1])) {
+ data = argv[1]->string;
+ length = argv[1]->length;
+ buf = 0;
+ } else {
+ buf = data = ejsVarToString(ejs, argv[1]);
+ length = strlen(data);
+ }
+
+ /*
+ * Create fails if already present
+ */
+ rc = mprDelete(ejs, argv[0]->string);
+ file = mprOpen(ejs, argv[0]->string, O_CREAT | O_WRONLY | O_BINARY, 0664);
+ if (file == 0) {
+ ejsError(ejs, EJS_IO_ERROR, "Cant create %s", argv[0]->string);
+ mprFree(buf);
+ return -1;
+ }
+
+ rc = 0;
+ bytes = mprWrite(file, data, length);
+ if (bytes != length) {
+ ejsError(ejs, EJS_IO_ERROR, "Write error to %s", argv[1]->string);
+ rc = -1;
+ }
+
+ mprClose(file);
+
+ mprFree(buf);
+ return rc;
+}
+
+/******************************************************************************/
+/*
+ * function string readFile(string path);
+ */
+
+static int readFileProc(Ejs *ejs, EjsVar *thisObj, int argc, EjsVar **argv)
+{
+ MprApp *app;
+ MprFile *file;
+ MprBuf *buf;
+ char *data;
+ int bytes, rc;
+
+ if (argc != 1 || !ejsVarIsString(argv[0])) {
+ ejsError(ejs, EJS_ARG_ERROR, "Bad usage: readFile(path)");
+ return -1;
+ }
+ buf = mprCreateBuf(ejs, MPR_BUF_INCR, MPR_MAX_BUF);
+ if (buf == 0) {
+ ejsMemoryError(ejs);
+ return -1;
+ }
+
+ data = mprAlloc(ejs, MPR_BUFSIZE);
+ if (buf == 0) {
+ mprFree(buf);
+ ejsMemoryError(ejs);
+ return -1;
+ }
+
+ app = mprGetApp(ejs);
+ file = mprOpen(ejs, argv[0]->string, O_RDONLY, 0664);
+ if (file == 0) {
+ ejsError(ejs, EJS_IO_ERROR, "Cant open %s", argv[0]->string);
+ mprFree(buf);
+ return -1;
+ }
+
+ rc = 0;
+ while ((bytes = mprRead(file, data, MPR_BUFSIZE)) > 0) {
+ if (mprPutBlockToBuf(buf, data, bytes) != bytes) {
+ ejsError(ejs, EJS_IO_ERROR, "Write error to %s", argv[1]->string);
+ rc = -1;
+ break;
+ }
+ }
+
+ ejsSetReturnValueToBinaryString(ejs, (uchar*) mprGetBufStart(buf),
+ mprGetBufLength(buf));
+
+ mprClose(file);
+ mprFree(data);
+ mprFree(buf);
+
+ return rc;
+}
+
+/******************************************************************************/
+/*
+ * function void remove(string path);
+ */
+
+static int removeProc(Ejs *ejs, EjsVar *thisObj, int argc, EjsVar **argv)
+{
+ int rc;
+
+ if (argc != 1 || !ejsVarIsString(argv[0])) {
+ ejsError(ejs, EJS_ARG_ERROR, "Bad usage: remove(path)");
+ return -1;
+ }
+
+ rc = unlink(argv[0]->string);
+ if (rc < 0) {
+ ejsError(ejs, EJS_IO_ERROR, "Cant remove file");
+ return -1;
+ }
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * function void rename(string from, string to);
+ */
+
+static int renameProc(Ejs *ejs, EjsVar *thisObj, int argc, EjsVar **argv)
+{
+ int rc;
+
+ if (argc != 2 || !ejsVarIsString(argv[0]) || !ejsVarIsString(argv[1])) {
+ ejsError(ejs, EJS_ARG_ERROR, "Bad usage: rename(old, new)");
+ return -1;
+ }
+
+ unlink(argv[1]->string);
+ rc = rename(argv[0]->string, argv[1]->string);
+ if (rc < 0) {
+ ejsError(ejs, EJS_IO_ERROR, "Cant rename file");
+ return -1;
+ }
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * function void copy(string old, string new);
+ */
+
+static int copyProc(Ejs *ejs, EjsVar *thisObj, int argc, EjsVar **argv)
+{
+ MprFile *from, *to;
+ char *buf;
+ uint bytes;
+ int rc;
+
+ if (argc != 2 || !ejsVarIsString(argv[0]) || !ejsVarIsString(argv[1])) {
+ ejsError(ejs, EJS_ARG_ERROR, "Bad usage: copy(old, new)");
+ return -1;
+ }
+
+ buf = mprAlloc(ejs, MPR_BUFSIZE);
+ if (buf == 0) {
+ ejsMemoryError(ejs);
+ return -1;
+ }
+
+ from = mprOpen(ejs, argv[0]->string, O_RDONLY | O_BINARY, 0664);
+ if (from == 0) {
+ ejsError(ejs, EJS_IO_ERROR, "Cant open %s", argv[0]->string);
+ mprFree(buf);
+ return -1;
+ }
+
+ to = mprOpen(ejs, argv[1]->string, O_CREAT | O_BINARY, 0664);
+ if (to == 0) {
+ ejsError(ejs, EJS_IO_ERROR, "Cant create %s", argv[1]->string);
+ mprClose(from);
+ mprFree(buf);
+ return -1;
+ }
+
+ rc = 0;
+ while ((bytes = mprRead(from, buf, MPR_BUFSIZE)) > 0) {
+ if (mprWrite(to, buf, bytes) != bytes) {
+ ejsError(ejs, EJS_IO_ERROR, "Write error to %s", argv[1]->string);
+ rc = -1;
+ break;
+ }
+ }
+
+ mprClose(from);
+ mprClose(to);
+ mprFree(buf);
+
+ return rc;
+}
+
+/******************************************************************************/
+/*
+ * function FileInfo getFileInfo(string path);
+ *
+ * MOB -- should create a real class FileInfo
+ */
+
+static int getFileInfoProc(Ejs *ejs, EjsVar *thisObj, int argc, EjsVar **argv)
+{
+ MprFileInfo info;
+ EjsVar *fileInfo;
+ int rc;
+
+ if (argc != 1 || !ejsVarIsString(argv[0])) {
+ ejsError(ejs, EJS_ARG_ERROR, "Bad usage: getFileInfo(path)");
+ return -1;
+ }
+
+ fileInfo = ejsCreateObjVar(ejs);
+ if (fileInfo == 0) {
+ ejsMemoryError(ejs);
+ return -1;
+ }
+ ejsMakeObjPermanent(fileInfo, 1);
+
+ rc = mprGetFileInfo(ejs, argv[0]->string, &info);
+ if (rc < 0) {
+ ejsMakeObjPermanent(fileInfo, 0);
+ ejsFreeVar(ejs, fileInfo);
+ ejsError(ejs, EJS_IO_ERROR, "Cant get file info for %s",
+ argv[0]->string);
+ return -1;
+ }
+
+ ejsSetPropertyToInteger(ejs, fileInfo, "created", info.ctime);
+ ejsSetPropertyToInteger(ejs, fileInfo, "length", info.size);
+ ejsSetPropertyToBoolean(ejs, fileInfo, "isDir", info.isDir);
+
+ ejsSetReturnValue(ejs, fileInfo);
+ ejsMakeObjPermanent(fileInfo, 0);
+
+ return 0;
+}
+
+/******************************************************************************/
+/******************************** Initialization ******************************/
+/******************************************************************************/
+
+int ejsDefineFileSystemClass(Ejs *ejs)
+{
+ EjsVar *fileSystemClass;
+
+ fileSystemClass = ejsDefineClass(ejs, "FileSystem", "Object", 0);
+ if (fileSystemClass == 0) {
+ return MPR_ERR_CANT_INITIALIZE;
+ }
+
+ /*
+ * Define the methods
+ */
+ ejsDefineCMethod(ejs, fileSystemClass, "access", accessProc, 0);
+ ejsDefineCMethod(ejs, fileSystemClass, "mkdir", mkdirProc, 0);
+ ejsDefineCMethod(ejs, fileSystemClass, "rmdir", rmdirProc, 0);
+ ejsDefineCMethod(ejs, fileSystemClass, "dirList", dirListProc, 0);
+ ejsDefineCMethod(ejs, fileSystemClass, "writeFile", writeFileProc, 0);
+ ejsDefineCMethod(ejs, fileSystemClass, "readFile", readFileProc, 0);
+ ejsDefineCMethod(ejs, fileSystemClass, "remove", removeProc, 0);
+ ejsDefineCMethod(ejs, fileSystemClass, "rename", renameProc, 0);
+ ejsDefineCMethod(ejs, fileSystemClass, "copy", copyProc, 0);
+ ejsDefineCMethod(ejs, fileSystemClass, "getFileInfo", getFileInfoProc, 0);
+
+ // MOB -- should be a property with accessor
+ ejsDefineCMethod(ejs, fileSystemClass, "getFreeSpace", getFreeSpaceProc, 0);
+
+ return ejsObjHasErrors(fileSystemClass) ? MPR_ERR_CANT_INITIALIZE: 0;
+}
+
+/******************************************************************************/
+
+/*
+ * 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-2.0/ejs/system/UNIX/ejsHTTP.c b/source4/lib/appweb/ejs-2.0/ejs/system/UNIX/ejsHTTP.c
new file mode 100755
index 0000000000..25821f6960
--- /dev/null
+++ b/source4/lib/appweb/ejs-2.0/ejs/system/UNIX/ejsHTTP.c
@@ -0,0 +1,488 @@
+/*
+ * @file ejsHTTP.c
+ * @brief HTTP class for the EJ System Object Model
+ */
+/********************************** Copyright *********************************/
+/*
+ * Copyright (c) Mbedthis Software LLC, 2005-2006. All Rights Reserved.
+ */
+/********************************** Includes **********************************/
+
+#include "ejs.h"
+
+#if UNUSED
+/*********************************** Defines **********************************/
+
+#define EJS_WEB_PROPERTY "-web"
+#define EJS_HTTP_PROPERTY "-http"
+
+#define EJS_HTTP_DISPOSED 550
+
+/*
+ * Control structure for one HTTP request structure
+ */
+typedef struct HTTPControl {
+ Ejs *ejs;
+ IWebResp *webResp;
+ AEECallback *callback;
+ MprBuf *buf;
+ EjsVar *thisObj;
+ char *url;
+ MprTime requestStarted;
+ uint timeout;
+} HTTPControl;
+
+/****************************** Forward Declarations **************************/
+
+static void cleanup(HTTPControl *hp);
+static int createWeb(Ejs *ejs, EjsVar *thisObj);
+static void brewCallback(HTTPControl *hp);
+static int httpDestructor(Ejs *ejs, EjsVar *vp);
+static void httpCallback(HTTPControl *hp, int responseCode);
+static int setCallback(Ejs *ejs, EjsVar *thisObj, int argc, EjsVar **argv);
+
+/******************************************************************************/
+/*
+ * Constructor
+ */
+
+int ejsHTTPConstructor(Ejs *ejs, EjsVar *thisObj, int argc, EjsVar **argv)
+{
+ if (argc != 0 && argc != 2) {
+ ejsError(ejs, EJS_ARG_ERROR,
+ "Bad usage: HTTP([obj = this, method = onComplete]);");
+ return -1;
+ }
+
+ if (createWeb(ejs, thisObj) < 0) {
+ return -1;
+ }
+
+ setCallback(ejs, thisObj, argc, argv);
+ return 0;
+}
+
+/******************************************************************************/
+
+static int createWeb(Ejs *ejs, EjsVar *thisObj)
+{
+ MprApp *app;
+ void *web;
+
+ app = mprGetApp(ejs);
+
+ /*
+ * Create one instance of IWeb for the entire application. Do it here
+ * so only widgets that require HTTP incurr the overhead.
+ */
+ web = mprGetKeyValue(ejs, "bpWeb");
+ if (web == 0) {
+ if (ISHELL_CreateInstance(app->shell, AEECLSID_WEB, &web) != SUCCESS) {
+ ejsError(ejs, EJS_IO_ERROR, "Can't create IWEB");
+ return -1;
+ }
+ }
+ mprSetKeyValue(ejs, "bpWeb", web);
+ return 0;
+}
+
+/******************************************************************************/
+/************************************ Methods *********************************/
+/******************************************************************************/
+/*
+ * function setCallback(obj, methodString);
+ */
+
+static int setCallback(Ejs *ejs, EjsVar *thisObj, int argc, EjsVar **argv)
+{
+ if (argc >= 1) {
+ ejsSetProperty(ejs, thisObj, "obj", argv[0]);
+ } else {
+ ejsSetProperty(ejs, thisObj, "obj", thisObj);
+ }
+
+ if (argc >= 2) {
+ ejsSetProperty(ejs, thisObj, "method", argv[1]);
+ } else {
+ ejsSetPropertyToString(ejs, thisObj, "method", "onComplete");
+ }
+
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * function fetch();
+ */
+
+static int fetchProc(Ejs *ejs, EjsVar *thisObj, int argc, EjsVar **argv)
+{
+ HTTPControl *hp;
+ EjsProperty *pp;
+ MprApp *app;
+ IWeb *web;
+
+ if (argc != 1 || !ejsVarIsString(argv[0])) {
+ ejsError(ejs, EJS_ARG_ERROR, "Bad usage: fetch(url)");
+ return -1;
+ }
+
+ app = mprGetApp(ejs);
+ web = (IWeb*) mprGetKeyValue(ejs, "bpWeb");
+
+ /*
+ * Web options
+ *
+ * WEBOPT_USERAGENT (char*) sets user agent
+ * WEBOPT_HANDLERDATA (void*)
+ * WEBOPT_CONNECTTIMEOUT (uint) msec
+ * WEBOPT_CONTENTLENGTH (long)
+ * WEBOPT_IDLECONNTIMEOUT (int)
+ * WEBOPT_ACTIVEXACTIONST (uint) Number of active requests
+ *
+ * WEBREQUEST_REDIRECT redirect transparently
+ *
+ */
+
+ hp = mprAllocType(ejs, HTTPControl);
+ if (hp == 0) {
+ ejsMemoryError(ejs);
+ return -1;
+ }
+
+ hp->ejs = ejs;
+ hp->buf = mprCreateBuf(hp, MPR_BUF_INCR, MPR_MAX_BUF);
+ if (hp->buf == 0) {
+ mprFree(hp);
+ ejsMemoryError(ejs);
+ return -1;
+ }
+
+ /*
+ * We copy thisObj because we need to preserve both the var and the object.
+ * We pass the var to brewCallback and so it must persist. The call to
+ * ejsMakeObjPermanent will stop the GC from collecting the object.
+ */
+ hp->thisObj = ejsDupVar(ejs, thisObj, EJS_SHALLOW_COPY);
+ ejsSetVarName(ejs, hp->thisObj, "internalHttp");
+
+ /*
+ * Must keep a reference to the http object
+ */
+ ejsMakeObjPermanent(hp->thisObj, 1);
+
+ /*
+ * Make a property so we can access the HTTPControl structure from other
+ * methods.
+ */
+ pp = ejsSetPropertyToPtr(ejs, thisObj, EJS_HTTP_PROPERTY, hp, 0);
+ ejsMakePropertyEnumerable(pp, 0);
+ ejsSetObjDestructor(ejs, hp->thisObj, httpDestructor);
+
+ hp->url = mprStrdup(hp, argv[0]->string);
+
+ hp->timeout = ejsGetPropertyAsInteger(ejs, thisObj, "timeout");
+ mprGetTime(hp, &hp->requestStarted);
+
+ hp->callback = mprAllocTypeZeroed(hp, AEECallback);
+ CALLBACK_Init(hp->callback, brewCallback, hp);
+
+ hp->webResp = 0;
+ IWEB_GetResponse(web,
+ (web, &hp->webResp, hp->callback, hp->url,
+ WEBOPT_HANDLERDATA, hp,
+ WEBOPT_USERAGENT, "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0)",
+ WEBOPT_CONNECTTIMEOUT, hp->timeout,
+ WEBOPT_COPYOPTS, TRUE,
+ WEBOPT_CONTENTLENGTH, 0,
+ WEBOPT_END));
+
+ ejsSetPropertyToString(ejs, thisObj, "status", "active");
+
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * Called whenver the http object is deleted.
+ */
+
+static int httpDestructor(Ejs *ejs, EjsVar *thisObj)
+{
+ HTTPControl *hp;
+
+ /*
+ * If the httpCallback has run, then this property will not exist
+ */
+ hp = ejsGetPropertyAsPtr(ejs, thisObj, EJS_HTTP_PROPERTY);
+
+ if (hp) {
+ cleanup(hp);
+ }
+
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * Stop the request immediately without calling the callback
+ */
+
+static int stopProc(Ejs *ejs, EjsVar *thisObj, int argc, EjsVar **argv)
+{
+ HTTPControl *hp;
+
+ hp = ejsGetPropertyAsPtr(ejs, thisObj, EJS_HTTP_PROPERTY);
+
+ if (hp) {
+ cleanup(hp);
+ }
+
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * Brew HTTP callback. Invoked for any return data.
+ */
+
+static void brewCallback(HTTPControl *hp)
+{
+ Ejs *ejs;
+ EjsVar *thisObj;
+ ISource *source;
+ WebRespInfo *info;
+ char data[MPR_BUF_INCR];
+ int bytes;
+
+ mprAssert(hp);
+ mprAssert(hp->webResp);
+
+ info = IWEBRESP_GetInfo(hp->webResp);
+
+ if (info == 0) {
+ mprAssert(info);
+ /* should not happen */
+ return;
+ }
+
+ ejs = hp->ejs;
+ thisObj = hp->thisObj;
+
+ if (! WEB_ERROR_SUCCEEDED(info->nCode)) {
+ ejsSetPropertyToString(ejs, thisObj, "status", "error");
+ httpCallback(hp, info->nCode);
+ return;
+ }
+
+ if (hp->timeout) {
+ if (mprGetTimeRemaining(hp, hp->requestStarted, hp->timeout) <= 0) {
+ ejsSetPropertyToString(ejs, thisObj, "status", "timeout");
+ httpCallback(hp, 504);
+ return;
+ }
+ }
+
+ /*
+ * Normal success
+ */
+ source = info->pisMessage;
+ mprAssert(source);
+
+ bytes = ISOURCE_Read(source, data, sizeof(data));
+
+ switch (bytes) {
+ case ISOURCE_WAIT: // No data yet
+ ISOURCE_Readable(source, hp->callback);
+ break;
+
+ case ISOURCE_ERROR:
+ ejsSetPropertyToString(ejs, thisObj, "status", "error");
+ httpCallback(hp, info->nCode);
+ break;
+
+ case ISOURCE_END:
+ mprAddNullToBuf(hp->buf);
+ ejsSetPropertyToString(ejs, thisObj, "status", "complete");
+ httpCallback(hp, info->nCode);
+ break;
+
+ default:
+ if (bytes > 0) {
+ if (mprPutBlockToBuf(hp->buf, data, bytes) != bytes) {
+ ejsSetPropertyToString(ejs, thisObj, "status", "partialData");
+ httpCallback(hp, 500);
+ }
+ }
+ ISOURCE_Readable(source, hp->callback);
+ break;
+ }
+}
+
+/******************************************************************************/
+/*
+ * Invoke the HTTP completion method
+ */
+
+static void httpCallback(HTTPControl *hp, int responseCode)
+{
+ Ejs *ejs;
+ EjsVar *thisObj, *callbackObj;
+ MprArray *args;
+ char *msg;
+ const char *callbackMethod;
+
+ mprAssert(hp);
+ mprAssert(hp->webResp);
+
+ thisObj = hp->thisObj;
+ ejs = hp->ejs;
+
+ ejsSetPropertyToInteger(ejs, thisObj, "responseCode", responseCode);
+ if (mprGetBufLength(hp->buf) > 0) {
+ ejsSetPropertyToBinaryString(ejs, thisObj, "responseData",
+ mprGetBufStart(hp->buf), mprGetBufLength(hp->buf));
+ }
+
+ callbackObj = ejsGetPropertyAsVar(ejs, thisObj, "obj");
+ callbackMethod = ejsGetPropertyAsString(ejs, thisObj, "method");
+
+ if (callbackObj != 0 && callbackMethod != 0) {
+
+ args = mprCreateItemArray(ejs, EJS_INC_ARGS, EJS_MAX_ARGS);
+ mprAddItem(args, ejsDupVar(ejs, hp->thisObj, EJS_SHALLOW_COPY));
+
+ if (ejsRunMethod(ejs, callbackObj, callbackMethod, args) < 0) {
+ msg = ejsGetErrorMsg(ejs);
+ mprError(ejs, MPR_LOC, "HTTP callback failed. Details: %s", msg);
+ }
+ ejsFreeMethodArgs(ejs, args);
+
+ } else if (ejsRunMethod(ejs, thisObj, "onComplete", 0) < 0) {
+ msg = ejsGetErrorMsg(ejs);
+ mprError(ejs, MPR_LOC, "HTTP onComplete failed. Details: %s", msg);
+ }
+
+ cleanup(hp);
+}
+
+/******************************************************************************/
+/*
+ * Cleanup
+ */
+
+static void cleanup(HTTPControl *hp)
+{
+ Ejs *ejs;
+ MprApp *app;
+ int rc;
+
+ mprAssert(hp);
+ mprAssert(hp->webResp);
+
+ ejs = hp->ejs;
+
+ if (hp->webResp) {
+ rc = IWEBRESP_Release(hp->webResp);
+ // mprAssert(rc == 0);
+ hp->webResp = 0;
+ }
+
+ if (hp->callback) {
+ CALLBACK_Cancel(hp->callback);
+ mprFree(hp->callback);
+ hp->callback = 0;
+ }
+
+ /*
+ * Once the property is deleted, then if the destructor runs, it will
+ * notice that the EJS_HTTP_PROPERTY is undefined.
+ */
+ ejsDeleteProperty(ejs, hp->thisObj, EJS_HTTP_PROPERTY);
+
+ /*
+ * Allow garbage collection to work on thisObj
+ */
+ ejsMakeObjPermanent(hp->thisObj, 0);
+ ejsFreeVar(ejs, hp->thisObj);
+
+ mprFree(hp->buf);
+ mprFree(hp->url);
+
+ mprFree(hp);
+
+ app = mprGetApp(ejs);
+
+
+ ISHELL_SendEvent(app->shell, (AEECLSID) app->classId, EVT_USER, 0, 0);
+}
+
+/******************************************************************************/
+/******************************** Initialization ******************************/
+/******************************************************************************/
+
+int ejsDefineHTTPClass(Ejs *ejs)
+{
+ EjsVar *httpClass;
+
+ httpClass =
+ ejsDefineClass(ejs, "HTTP", "Object", ejsHTTPConstructor);
+ if (httpClass == 0) {
+ return MPR_ERR_CANT_INITIALIZE;
+ }
+
+ /*
+ * Define the methods
+ */
+ ejsDefineCMethod(ejs, httpClass, "fetch", fetchProc, 0);
+ ejsDefineCMethod(ejs, httpClass, "stop", stopProc, 0);
+ ejsDefineCMethod(ejs, httpClass, "setCallback", setCallback, 0);
+
+#if FUTURE
+ ejsDefineCMethod(ejs, httpClass, "put", put, 0);
+ ejsDefineCMethod(ejs, httpClass, "upload", upload, 0);
+ ejsDefineCMethod(ejs, httpClass, "addUploadFile", addUploadFile, 0);
+ ejsDefineCMethod(ejs, httpClass, "addPostData", addPostData, 0);
+ ejsDefineCMethod(ejs, httpClass, "setUserPassword", setUserPassword, 0);
+ ejsDefineCMethod(ejs, httpClass, "addCookie", addCookie, 0);
+#endif
+
+ /*
+ * Define properties
+ */
+ ejsSetPropertyToString(ejs, httpClass, "status", "inactive");
+
+ /* This default should come from player.xml */
+
+ ejsSetPropertyToInteger(ejs, httpClass, "timeout", 30 * 1000);
+ ejsSetPropertyToInteger(ejs, httpClass, "responseCode", 0);
+
+ return ejsObjHasErrors(httpClass) ? MPR_ERR_CANT_INITIALIZE: 0;
+}
+
+/******************************************************************************/
+
+void ejsTermHTTPClass(Ejs *ejs)
+{
+ IWeb *web;
+ int rc;
+
+ web = (IWeb*) mprGetKeyValue(ejs, "bpWeb");
+ if (web) {
+ rc = IWEB_Release(web);
+ mprAssert(rc == 0);
+ }
+}
+
+#endif
+/******************************************************************************/
+
+/*
+ * 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-2.0/ejs/system/WIN/.ignore b/source4/lib/appweb/ejs-2.0/ejs/system/WIN/.ignore
new file mode 100644
index 0000000000..fb5a29031e
--- /dev/null
+++ b/source4/lib/appweb/ejs-2.0/ejs/system/WIN/.ignore
@@ -0,0 +1 @@
+.updated
diff --git a/source4/lib/appweb/ejs-2.0/ejs/system/WIN/Makefile b/source4/lib/appweb/ejs-2.0/ejs/system/WIN/Makefile
new file mode 100755
index 0000000000..424747052a
--- /dev/null
+++ b/source4/lib/appweb/ejs-2.0/ejs/system/WIN/Makefile
@@ -0,0 +1,21 @@
+#
+# Makefile to build the EJS Object Model for WIN
+#
+# Copyright (c) Mbedthis Software LLC, 2003-2006. All Rights Reserved.
+#
+
+COMPILE := *.c
+EXPORT_OBJECTS := yes
+MAKE_IFLAGS := -I../.. -I../../../mpr
+
+include make.dep
+
+compileExtra: .updated
+
+.updated: $(FILES)
+ @touch .updated
+
+## Local variables:
+## tab-width: 4
+## End:
+## vim: tw=78 sw=4 ts=4
diff --git a/source4/lib/appweb/ejs-2.0/ejs/system/WIN/ejsFile.c b/source4/lib/appweb/ejs-2.0/ejs/system/WIN/ejsFile.c
new file mode 100644
index 0000000000..24c521891e
--- /dev/null
+++ b/source4/lib/appweb/ejs-2.0/ejs/system/WIN/ejsFile.c
@@ -0,0 +1,98 @@
+/*
+ * @file ejsFile.c
+ * @brief File class for the EJScript System Object Model
+ */
+/********************************** Copyright *********************************/
+/*
+ * Copyright (c) Mbedthis Software LLC, 2003-2006. All Rights Reserved.
+ */
+/********************************** Includes **********************************/
+
+#include "ejs.h"
+
+/******************************************************************************/
+/*
+ * Default Constructor
+ */
+
+/******************************************************************************/
+/************************************ Methods *********************************/
+/******************************************************************************/
+/*
+ * function open();
+ */
+
+static int openProc(Ejs *ep, EjsVar *thisObj, int argc, EjsVar **argv)
+{
+ ejsTrace(ep, "File.open()\n");
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * function close();
+ */
+
+static int closeProc(Ejs *ep, EjsVar *thisObj, int argc, EjsVar **argv)
+{
+ ejsTrace(ep, "File.close()\n");
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * function read();
+ */
+
+static int readProc(Ejs *ep, EjsVar *thisObj, int argc, EjsVar **argv)
+{
+ ejsTrace(ep, "File.read()\n");
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * function write();
+ */
+
+static int writeProc(Ejs *ep, EjsVar *thisObj, int argc, EjsVar **argv)
+{
+ ejsTrace(ep, "File.write()\n");
+ return 0;
+}
+
+/******************************************************************************/
+/******************************** Initialization ******************************/
+/******************************************************************************/
+
+int ejsDefineFileClass(Ejs *ep)
+{
+ EjsVar *fileClass;
+
+ fileClass = ejsDefineClass(ep, "File", "Object", 0);
+ if (fileClass == 0) {
+ return MPR_ERR_CANT_INITIALIZE;
+ }
+
+ /*
+ * Define the methods
+ */
+ ejsDefineCMethod(ep, fileClass, "open", openProc, 0);
+ ejsDefineCMethod(ep, fileClass, "close", closeProc, 0);
+ ejsDefineCMethod(ep, fileClass, "read", readProc, 0);
+ ejsDefineCMethod(ep, fileClass, "write", writeProc, 0);
+
+ return ejsObjHasErrors(fileClass) ? MPR_ERR_CANT_INITIALIZE: 0;
+}
+
+/******************************************************************************/
+
+/*
+ * 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-2.0/ejs/system/WIN/ejsFileSystem.c b/source4/lib/appweb/ejs-2.0/ejs/system/WIN/ejsFileSystem.c
new file mode 100755
index 0000000000..66c3b84870
--- /dev/null
+++ b/source4/lib/appweb/ejs-2.0/ejs/system/WIN/ejsFileSystem.c
@@ -0,0 +1,456 @@
+/*
+ * @file ejsFileSystem.c
+ * @brief FileSystem class for the EJ System Object Model
+ */
+/********************************** Copyright *********************************/
+/*
+ * Copyright (c) Mbedthis Software LLC, 2003-2006. All Rights Reserved.
+ */
+/********************************** Includes **********************************/
+
+#include "ejs.h"
+
+/******************************************************************************/
+/*
+ * Default Constructor
+ */
+
+/******************************************************************************/
+/************************************ Methods *********************************/
+/******************************************************************************/
+/*
+ * function void access(string path);
+ * MOB - API insufficient. Access for read or write?
+ */
+
+static int accessProc(Ejs *ejs, EjsVar *thisObj, int argc, EjsVar **argv)
+{
+ int rc;
+
+ if (argc != 1 || !ejsVarIsString(argv[0])) {
+ ejsError(ejs, EJS_ARG_ERROR, "Bad usage: access(path)");
+ return -1;
+ }
+
+ rc = access(argv[0]->string, 04);
+
+ ejsSetReturnValueToBoolean(ejs, (rc == 0) ? 1 : 0);
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * function void mkdir(string path);
+ */
+
+static int mkdirProc(Ejs *ejs, EjsVar *thisObj, int argc, EjsVar **argv)
+{
+ if (argc != 1 || !ejsVarIsString(argv[0])) {
+ ejsError(ejs, EJS_ARG_ERROR, "Bad usage: mkdir(path)");
+ return -1;
+ }
+
+ if (mprMakeDirPath(ejs, argv[0]->string) < 0) {
+ ejsError(ejs, EJS_IO_ERROR, "Cant create directory");
+ return -1;
+ }
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * function void rmdir(string path);
+ */
+
+static int rmdirProc(Ejs *ejs, EjsVar *thisObj, int argc, EjsVar **argv)
+{
+ int rc;
+
+ if (argc != 1 || !ejsVarIsString(argv[0])) {
+ ejsError(ejs, EJS_ARG_ERROR, "Bad usage: mkdir(path)");
+ return -1;
+ }
+
+ rc = mprDeleteDir(ejs, argv[0]->string);
+
+ if (rc < 0) {
+ ejsError(ejs, EJS_IO_ERROR, "Cant remove directory");
+ return -1;
+ }
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * function void dirList(string path, [bool enumDirs]);
+ * MOB -- need pattern to match (what about "." and ".." and ".*"
+ */
+
+static int dirListProc(Ejs *ejs, EjsVar *thisObj, int argc, EjsVar **argv)
+{
+ WIN32_FIND_DATA findData;
+ HANDLE h;
+ char path[MPR_MAX_FNAME];
+ EjsVar *array, *vp;
+ uchar enumDirs;
+
+ if (argc < 1 || !ejsVarIsString(argv[0])) {
+ ejsError(ejs, EJS_ARG_ERROR, "Bad usage: dirList(path)");
+ return -1;
+ }
+ if (argc == 2) {
+ enumDirs = ejsVarToBoolean(argv[1]);
+ } else {
+ enumDirs = 0;
+ }
+ array = ejsCreateArray(ejs, 0);
+ ejsMakeObjPermanent(array, 1);
+
+ /*
+ * First collect the files
+ */
+ mprSprintf(path, sizeof(path), "%s/*.*", argv[0]->string);
+ h = FindFirstFile(path, &findData);
+ if (h == INVALID_HANDLE_VALUE) {
+ ejsError(ejs, EJS_ARG_ERROR, "Can't enumerate dirList(path)");
+ return -1;
+ }
+
+ do {
+ if (findData.cFileName[0] == '.') {
+ continue;
+ }
+ if (!enumDirs ||
+ (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) {
+ mprSprintf(path, sizeof(path), "%s/%s", argv[0]->string,
+ findData.cFileName);
+ vp = ejsCreateStringVar(ejs, path);
+ ejsAddArrayElt(ejs, array, vp, EJS_SHALLOW_COPY);
+ ejsFreeVar(ejs, vp);
+ }
+ } while (FindNextFile(h, &findData) != 0);
+
+ FindClose(h);
+
+ ejsSetReturnValue(ejs, array);
+ ejsMakeObjPermanent(array, 0);
+
+ /*
+ * Can free now as the return value holds the reference
+ */
+ ejsFreeVar(ejs, array);
+
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * function void getFreeSpace();
+ */
+
+static int getFreeSpaceProc(Ejs *ejs, EjsVar *thisObj, int argc, EjsVar **argv)
+{
+#if UNUSED
+ MprApp *app;
+ uint space;
+
+ app = mprGetApp(ejs);
+ space = IFILEMGR_GetFreeSpace(app->fileMgr, 0);
+ ejsSetReturnValueToInteger(ejs, space);
+#endif
+
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * function void writeFile(string path, var data);
+ */
+
+static int writeFileProc(Ejs *ejs, EjsVar *thisObj, int argc, EjsVar **argv)
+{
+ MprFile *file;
+ char *data, *buf;
+ int bytes, length, rc;
+
+ if (argc != 2 || !ejsVarIsString(argv[0])) {
+ ejsError(ejs, EJS_ARG_ERROR, "Bad usage: writeFile(path, var)");
+ return -1;
+ }
+
+ if (ejsVarIsString(argv[1])) {
+ data = argv[1]->string;
+ length = argv[1]->length;
+ buf = 0;
+ } else {
+ buf = data = ejsVarToString(ejs, argv[1]);
+ length = strlen(data);
+ }
+
+ /*
+ * Create fails if already present
+ */
+ rc = mprDelete(ejs, argv[0]->string);
+ file = mprOpen(ejs, argv[0]->string, O_CREAT | O_WRONLY | O_BINARY, 0664);
+ if (file == 0) {
+ ejsError(ejs, EJS_IO_ERROR, "Cant create %s", argv[0]->string);
+ mprFree(buf);
+ return -1;
+ }
+
+ rc = 0;
+ bytes = mprWrite(file, data, length);
+ if (bytes != length) {
+ ejsError(ejs, EJS_IO_ERROR, "Write error to %s", argv[1]->string);
+ rc = -1;
+ }
+
+ mprClose(file);
+
+ mprFree(buf);
+ return rc;
+}
+
+/******************************************************************************/
+/*
+ * function string readFile(string path);
+ */
+
+static int readFileProc(Ejs *ejs, EjsVar *thisObj, int argc, EjsVar **argv)
+{
+ MprApp *app;
+ MprFile *file;
+ MprBuf *buf;
+ char *data;
+ int bytes, rc;
+
+ if (argc != 1 || !ejsVarIsString(argv[0])) {
+ ejsError(ejs, EJS_ARG_ERROR, "Bad usage: readFile(path)");
+ return -1;
+ }
+ buf = mprCreateBuf(ejs, MPR_BUF_INCR, MPR_MAX_BUF);
+ if (buf == 0) {
+ ejsMemoryError(ejs);
+ return -1;
+ }
+
+ data = mprAlloc(ejs, MPR_BUFSIZE);
+ if (buf == 0) {
+ mprFree(buf);
+ ejsMemoryError(ejs);
+ return -1;
+ }
+
+ app = mprGetApp(ejs);
+ file = mprOpen(ejs, argv[0]->string, O_RDONLY, 0664);
+ if (file == 0) {
+ ejsError(ejs, EJS_IO_ERROR, "Cant open %s", argv[0]->string);
+ mprFree(buf);
+ return -1;
+ }
+
+ rc = 0;
+ while ((bytes = mprRead(file, data, MPR_BUFSIZE)) > 0) {
+ if (mprPutBlockToBuf(buf, data, bytes) != bytes) {
+ ejsError(ejs, EJS_IO_ERROR, "Write error to %s", argv[1]->string);
+ rc = -1;
+ break;
+ }
+ }
+
+ ejsSetReturnValueToBinaryString(ejs, mprGetBufStart(buf),
+ mprGetBufLength(buf));
+
+ mprClose(file);
+ mprFree(data);
+ mprFree(buf);
+
+ return rc;
+}
+
+/******************************************************************************/
+/*
+ * function void remove(string path);
+ */
+
+static int removeProc(Ejs *ejs, EjsVar *thisObj, int argc, EjsVar **argv)
+{
+ int rc;
+
+ if (argc != 1 || !ejsVarIsString(argv[0])) {
+ ejsError(ejs, EJS_ARG_ERROR, "Bad usage: remove(path)");
+ return -1;
+ }
+
+ rc = unlink(argv[0]->string);
+ if (rc < 0) {
+ ejsError(ejs, EJS_IO_ERROR, "Cant remove file");
+ return -1;
+ }
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * function void rename(string from, string to);
+ */
+
+static int renameProc(Ejs *ejs, EjsVar *thisObj, int argc, EjsVar **argv)
+{
+ int rc;
+
+ if (argc != 2 || !ejsVarIsString(argv[0]) || !ejsVarIsString(argv[1])) {
+ ejsError(ejs, EJS_ARG_ERROR, "Bad usage: rename(old, new)");
+ return -1;
+ }
+
+ unlink(argv[1]->string);
+ rc = rename(argv[0]->string, argv[1]->string);
+ if (rc < 0) {
+ ejsError(ejs, EJS_IO_ERROR, "Cant rename file");
+ return -1;
+ }
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * function void copy(string old, string new);
+ */
+
+static int copyProc(Ejs *ejs, EjsVar *thisObj, int argc, EjsVar **argv)
+{
+ MprFile *from, *to;
+ char *buf;
+ int bytes, rc;
+
+ if (argc != 2 || !ejsVarIsString(argv[0]) || !ejsVarIsString(argv[1])) {
+ ejsError(ejs, EJS_ARG_ERROR, "Bad usage: copy(old, new)");
+ return -1;
+ }
+
+ buf = mprAlloc(ejs, MPR_BUFSIZE);
+ if (buf == 0) {
+ ejsMemoryError(ejs);
+ return -1;
+ }
+
+ from = mprOpen(ejs, argv[0]->string, O_RDONLY | O_BINARY, 0664);
+ if (from == 0) {
+ ejsError(ejs, EJS_IO_ERROR, "Cant open %s", argv[0]->string);
+ mprFree(buf);
+ return -1;
+ }
+
+ to = mprOpen(ejs, argv[1]->string, O_CREAT | O_BINARY, 0664);
+ if (to == 0) {
+ ejsError(ejs, EJS_IO_ERROR, "Cant create %s", argv[1]->string);
+ mprClose(from);
+ mprFree(buf);
+ return -1;
+ }
+
+ rc = 0;
+ while ((bytes = mprRead(from, buf, MPR_BUFSIZE)) > 0) {
+ if (mprWrite(to, buf, bytes) != bytes) {
+ ejsError(ejs, EJS_IO_ERROR, "Write error to %s", argv[1]->string);
+ rc = -1;
+ break;
+ }
+ }
+
+ mprClose(from);
+ mprClose(to);
+ mprFree(buf);
+
+ return rc;
+}
+
+/******************************************************************************/
+/*
+ * function FileInfo getFileInfo(string path);
+ *
+ * MOB -- should create a real class FileInfo
+ */
+
+static int getFileInfoProc(Ejs *ejs, EjsVar *thisObj, int argc, EjsVar **argv)
+{
+ MprFileInfo info;
+ EjsVar *fileInfo;
+ int rc;
+
+ if (argc != 1 || !ejsVarIsString(argv[0])) {
+ ejsError(ejs, EJS_ARG_ERROR, "Bad usage: getFileInfo(path)");
+ return -1;
+ }
+
+ fileInfo = ejsCreateObjVar(ejs);
+ if (fileInfo == 0) {
+ ejsMemoryError(ejs);
+ return -1;
+ }
+ ejsMakeObjPermanent(fileInfo, 1);
+
+ rc = mprGetFileInfo(ejs, argv[0]->string, &info);
+ if (rc < 0) {
+ ejsMakeObjPermanent(fileInfo, 0);
+ ejsFreeVar(ejs, fileInfo);
+ ejsError(ejs, EJS_IO_ERROR, "Cant get file info for %s",
+ argv[0]->string);
+ return -1;
+ }
+
+ ejsSetPropertyToInteger(ejs, fileInfo, "created", info.ctime);
+ ejsSetPropertyToInteger(ejs, fileInfo, "length", info.size);
+ ejsSetPropertyToBoolean(ejs, fileInfo, "isDir", info.isDir);
+
+ ejsSetReturnValue(ejs, fileInfo);
+ ejsMakeObjPermanent(fileInfo, 0);
+
+ return 0;
+}
+
+/******************************************************************************/
+/******************************** Initialization ******************************/
+/******************************************************************************/
+
+int ejsDefineFileSystemClass(Ejs *ejs)
+{
+ EjsVar *fileSystemClass;
+
+ fileSystemClass = ejsDefineClass(ejs, "FileSystem", "Object", 0);
+ if (fileSystemClass == 0) {
+ return MPR_ERR_CANT_INITIALIZE;
+ }
+
+ /*
+ * Define the methods
+ */
+ ejsDefineCMethod(ejs, fileSystemClass, "access", accessProc, 0);
+ ejsDefineCMethod(ejs, fileSystemClass, "mkdir", mkdirProc, 0);
+ ejsDefineCMethod(ejs, fileSystemClass, "rmdir", rmdirProc, 0);
+ ejsDefineCMethod(ejs, fileSystemClass, "dirList", dirListProc, 0);
+ ejsDefineCMethod(ejs, fileSystemClass, "writeFile", writeFileProc, 0);
+ ejsDefineCMethod(ejs, fileSystemClass, "readFile", readFileProc, 0);
+ ejsDefineCMethod(ejs, fileSystemClass, "remove", removeProc, 0);
+ ejsDefineCMethod(ejs, fileSystemClass, "rename", renameProc, 0);
+ ejsDefineCMethod(ejs, fileSystemClass, "copy", copyProc, 0);
+ ejsDefineCMethod(ejs, fileSystemClass, "getFileInfo", getFileInfoProc, 0);
+
+ // MOB -- should be a property with accessor
+ ejsDefineCMethod(ejs, fileSystemClass, "getFreeSpace", getFreeSpaceProc, 0);
+
+ return ejsObjHasErrors(fileSystemClass) ? MPR_ERR_CANT_INITIALIZE: 0;
+}
+
+/******************************************************************************/
+
+/*
+ * 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-2.0/ejs/system/WIN/ejsHTTP.c b/source4/lib/appweb/ejs-2.0/ejs/system/WIN/ejsHTTP.c
new file mode 100755
index 0000000000..25821f6960
--- /dev/null
+++ b/source4/lib/appweb/ejs-2.0/ejs/system/WIN/ejsHTTP.c
@@ -0,0 +1,488 @@
+/*
+ * @file ejsHTTP.c
+ * @brief HTTP class for the EJ System Object Model
+ */
+/********************************** Copyright *********************************/
+/*
+ * Copyright (c) Mbedthis Software LLC, 2005-2006. All Rights Reserved.
+ */
+/********************************** Includes **********************************/
+
+#include "ejs.h"
+
+#if UNUSED
+/*********************************** Defines **********************************/
+
+#define EJS_WEB_PROPERTY "-web"
+#define EJS_HTTP_PROPERTY "-http"
+
+#define EJS_HTTP_DISPOSED 550
+
+/*
+ * Control structure for one HTTP request structure
+ */
+typedef struct HTTPControl {
+ Ejs *ejs;
+ IWebResp *webResp;
+ AEECallback *callback;
+ MprBuf *buf;
+ EjsVar *thisObj;
+ char *url;
+ MprTime requestStarted;
+ uint timeout;
+} HTTPControl;
+
+/****************************** Forward Declarations **************************/
+
+static void cleanup(HTTPControl *hp);
+static int createWeb(Ejs *ejs, EjsVar *thisObj);
+static void brewCallback(HTTPControl *hp);
+static int httpDestructor(Ejs *ejs, EjsVar *vp);
+static void httpCallback(HTTPControl *hp, int responseCode);
+static int setCallback(Ejs *ejs, EjsVar *thisObj, int argc, EjsVar **argv);
+
+/******************************************************************************/
+/*
+ * Constructor
+ */
+
+int ejsHTTPConstructor(Ejs *ejs, EjsVar *thisObj, int argc, EjsVar **argv)
+{
+ if (argc != 0 && argc != 2) {
+ ejsError(ejs, EJS_ARG_ERROR,
+ "Bad usage: HTTP([obj = this, method = onComplete]);");
+ return -1;
+ }
+
+ if (createWeb(ejs, thisObj) < 0) {
+ return -1;
+ }
+
+ setCallback(ejs, thisObj, argc, argv);
+ return 0;
+}
+
+/******************************************************************************/
+
+static int createWeb(Ejs *ejs, EjsVar *thisObj)
+{
+ MprApp *app;
+ void *web;
+
+ app = mprGetApp(ejs);
+
+ /*
+ * Create one instance of IWeb for the entire application. Do it here
+ * so only widgets that require HTTP incurr the overhead.
+ */
+ web = mprGetKeyValue(ejs, "bpWeb");
+ if (web == 0) {
+ if (ISHELL_CreateInstance(app->shell, AEECLSID_WEB, &web) != SUCCESS) {
+ ejsError(ejs, EJS_IO_ERROR, "Can't create IWEB");
+ return -1;
+ }
+ }
+ mprSetKeyValue(ejs, "bpWeb", web);
+ return 0;
+}
+
+/******************************************************************************/
+/************************************ Methods *********************************/
+/******************************************************************************/
+/*
+ * function setCallback(obj, methodString);
+ */
+
+static int setCallback(Ejs *ejs, EjsVar *thisObj, int argc, EjsVar **argv)
+{
+ if (argc >= 1) {
+ ejsSetProperty(ejs, thisObj, "obj", argv[0]);
+ } else {
+ ejsSetProperty(ejs, thisObj, "obj", thisObj);
+ }
+
+ if (argc >= 2) {
+ ejsSetProperty(ejs, thisObj, "method", argv[1]);
+ } else {
+ ejsSetPropertyToString(ejs, thisObj, "method", "onComplete");
+ }
+
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * function fetch();
+ */
+
+static int fetchProc(Ejs *ejs, EjsVar *thisObj, int argc, EjsVar **argv)
+{
+ HTTPControl *hp;
+ EjsProperty *pp;
+ MprApp *app;
+ IWeb *web;
+
+ if (argc != 1 || !ejsVarIsString(argv[0])) {
+ ejsError(ejs, EJS_ARG_ERROR, "Bad usage: fetch(url)");
+ return -1;
+ }
+
+ app = mprGetApp(ejs);
+ web = (IWeb*) mprGetKeyValue(ejs, "bpWeb");
+
+ /*
+ * Web options
+ *
+ * WEBOPT_USERAGENT (char*) sets user agent
+ * WEBOPT_HANDLERDATA (void*)
+ * WEBOPT_CONNECTTIMEOUT (uint) msec
+ * WEBOPT_CONTENTLENGTH (long)
+ * WEBOPT_IDLECONNTIMEOUT (int)
+ * WEBOPT_ACTIVEXACTIONST (uint) Number of active requests
+ *
+ * WEBREQUEST_REDIRECT redirect transparently
+ *
+ */
+
+ hp = mprAllocType(ejs, HTTPControl);
+ if (hp == 0) {
+ ejsMemoryError(ejs);
+ return -1;
+ }
+
+ hp->ejs = ejs;
+ hp->buf = mprCreateBuf(hp, MPR_BUF_INCR, MPR_MAX_BUF);
+ if (hp->buf == 0) {
+ mprFree(hp);
+ ejsMemoryError(ejs);
+ return -1;
+ }
+
+ /*
+ * We copy thisObj because we need to preserve both the var and the object.
+ * We pass the var to brewCallback and so it must persist. The call to
+ * ejsMakeObjPermanent will stop the GC from collecting the object.
+ */
+ hp->thisObj = ejsDupVar(ejs, thisObj, EJS_SHALLOW_COPY);
+ ejsSetVarName(ejs, hp->thisObj, "internalHttp");
+
+ /*
+ * Must keep a reference to the http object
+ */
+ ejsMakeObjPermanent(hp->thisObj, 1);
+
+ /*
+ * Make a property so we can access the HTTPControl structure from other
+ * methods.
+ */
+ pp = ejsSetPropertyToPtr(ejs, thisObj, EJS_HTTP_PROPERTY, hp, 0);
+ ejsMakePropertyEnumerable(pp, 0);
+ ejsSetObjDestructor(ejs, hp->thisObj, httpDestructor);
+
+ hp->url = mprStrdup(hp, argv[0]->string);
+
+ hp->timeout = ejsGetPropertyAsInteger(ejs, thisObj, "timeout");
+ mprGetTime(hp, &hp->requestStarted);
+
+ hp->callback = mprAllocTypeZeroed(hp, AEECallback);
+ CALLBACK_Init(hp->callback, brewCallback, hp);
+
+ hp->webResp = 0;
+ IWEB_GetResponse(web,
+ (web, &hp->webResp, hp->callback, hp->url,
+ WEBOPT_HANDLERDATA, hp,
+ WEBOPT_USERAGENT, "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0)",
+ WEBOPT_CONNECTTIMEOUT, hp->timeout,
+ WEBOPT_COPYOPTS, TRUE,
+ WEBOPT_CONTENTLENGTH, 0,
+ WEBOPT_END));
+
+ ejsSetPropertyToString(ejs, thisObj, "status", "active");
+
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * Called whenver the http object is deleted.
+ */
+
+static int httpDestructor(Ejs *ejs, EjsVar *thisObj)
+{
+ HTTPControl *hp;
+
+ /*
+ * If the httpCallback has run, then this property will not exist
+ */
+ hp = ejsGetPropertyAsPtr(ejs, thisObj, EJS_HTTP_PROPERTY);
+
+ if (hp) {
+ cleanup(hp);
+ }
+
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * Stop the request immediately without calling the callback
+ */
+
+static int stopProc(Ejs *ejs, EjsVar *thisObj, int argc, EjsVar **argv)
+{
+ HTTPControl *hp;
+
+ hp = ejsGetPropertyAsPtr(ejs, thisObj, EJS_HTTP_PROPERTY);
+
+ if (hp) {
+ cleanup(hp);
+ }
+
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * Brew HTTP callback. Invoked for any return data.
+ */
+
+static void brewCallback(HTTPControl *hp)
+{
+ Ejs *ejs;
+ EjsVar *thisObj;
+ ISource *source;
+ WebRespInfo *info;
+ char data[MPR_BUF_INCR];
+ int bytes;
+
+ mprAssert(hp);
+ mprAssert(hp->webResp);
+
+ info = IWEBRESP_GetInfo(hp->webResp);
+
+ if (info == 0) {
+ mprAssert(info);
+ /* should not happen */
+ return;
+ }
+
+ ejs = hp->ejs;
+ thisObj = hp->thisObj;
+
+ if (! WEB_ERROR_SUCCEEDED(info->nCode)) {
+ ejsSetPropertyToString(ejs, thisObj, "status", "error");
+ httpCallback(hp, info->nCode);
+ return;
+ }
+
+ if (hp->timeout) {
+ if (mprGetTimeRemaining(hp, hp->requestStarted, hp->timeout) <= 0) {
+ ejsSetPropertyToString(ejs, thisObj, "status", "timeout");
+ httpCallback(hp, 504);
+ return;
+ }
+ }
+
+ /*
+ * Normal success
+ */
+ source = info->pisMessage;
+ mprAssert(source);
+
+ bytes = ISOURCE_Read(source, data, sizeof(data));
+
+ switch (bytes) {
+ case ISOURCE_WAIT: // No data yet
+ ISOURCE_Readable(source, hp->callback);
+ break;
+
+ case ISOURCE_ERROR:
+ ejsSetPropertyToString(ejs, thisObj, "status", "error");
+ httpCallback(hp, info->nCode);
+ break;
+
+ case ISOURCE_END:
+ mprAddNullToBuf(hp->buf);
+ ejsSetPropertyToString(ejs, thisObj, "status", "complete");
+ httpCallback(hp, info->nCode);
+ break;
+
+ default:
+ if (bytes > 0) {
+ if (mprPutBlockToBuf(hp->buf, data, bytes) != bytes) {
+ ejsSetPropertyToString(ejs, thisObj, "status", "partialData");
+ httpCallback(hp, 500);
+ }
+ }
+ ISOURCE_Readable(source, hp->callback);
+ break;
+ }
+}
+
+/******************************************************************************/
+/*
+ * Invoke the HTTP completion method
+ */
+
+static void httpCallback(HTTPControl *hp, int responseCode)
+{
+ Ejs *ejs;
+ EjsVar *thisObj, *callbackObj;
+ MprArray *args;
+ char *msg;
+ const char *callbackMethod;
+
+ mprAssert(hp);
+ mprAssert(hp->webResp);
+
+ thisObj = hp->thisObj;
+ ejs = hp->ejs;
+
+ ejsSetPropertyToInteger(ejs, thisObj, "responseCode", responseCode);
+ if (mprGetBufLength(hp->buf) > 0) {
+ ejsSetPropertyToBinaryString(ejs, thisObj, "responseData",
+ mprGetBufStart(hp->buf), mprGetBufLength(hp->buf));
+ }
+
+ callbackObj = ejsGetPropertyAsVar(ejs, thisObj, "obj");
+ callbackMethod = ejsGetPropertyAsString(ejs, thisObj, "method");
+
+ if (callbackObj != 0 && callbackMethod != 0) {
+
+ args = mprCreateItemArray(ejs, EJS_INC_ARGS, EJS_MAX_ARGS);
+ mprAddItem(args, ejsDupVar(ejs, hp->thisObj, EJS_SHALLOW_COPY));
+
+ if (ejsRunMethod(ejs, callbackObj, callbackMethod, args) < 0) {
+ msg = ejsGetErrorMsg(ejs);
+ mprError(ejs, MPR_LOC, "HTTP callback failed. Details: %s", msg);
+ }
+ ejsFreeMethodArgs(ejs, args);
+
+ } else if (ejsRunMethod(ejs, thisObj, "onComplete", 0) < 0) {
+ msg = ejsGetErrorMsg(ejs);
+ mprError(ejs, MPR_LOC, "HTTP onComplete failed. Details: %s", msg);
+ }
+
+ cleanup(hp);
+}
+
+/******************************************************************************/
+/*
+ * Cleanup
+ */
+
+static void cleanup(HTTPControl *hp)
+{
+ Ejs *ejs;
+ MprApp *app;
+ int rc;
+
+ mprAssert(hp);
+ mprAssert(hp->webResp);
+
+ ejs = hp->ejs;
+
+ if (hp->webResp) {
+ rc = IWEBRESP_Release(hp->webResp);
+ // mprAssert(rc == 0);
+ hp->webResp = 0;
+ }
+
+ if (hp->callback) {
+ CALLBACK_Cancel(hp->callback);
+ mprFree(hp->callback);
+ hp->callback = 0;
+ }
+
+ /*
+ * Once the property is deleted, then if the destructor runs, it will
+ * notice that the EJS_HTTP_PROPERTY is undefined.
+ */
+ ejsDeleteProperty(ejs, hp->thisObj, EJS_HTTP_PROPERTY);
+
+ /*
+ * Allow garbage collection to work on thisObj
+ */
+ ejsMakeObjPermanent(hp->thisObj, 0);
+ ejsFreeVar(ejs, hp->thisObj);
+
+ mprFree(hp->buf);
+ mprFree(hp->url);
+
+ mprFree(hp);
+
+ app = mprGetApp(ejs);
+
+
+ ISHELL_SendEvent(app->shell, (AEECLSID) app->classId, EVT_USER, 0, 0);
+}
+
+/******************************************************************************/
+/******************************** Initialization ******************************/
+/******************************************************************************/
+
+int ejsDefineHTTPClass(Ejs *ejs)
+{
+ EjsVar *httpClass;
+
+ httpClass =
+ ejsDefineClass(ejs, "HTTP", "Object", ejsHTTPConstructor);
+ if (httpClass == 0) {
+ return MPR_ERR_CANT_INITIALIZE;
+ }
+
+ /*
+ * Define the methods
+ */
+ ejsDefineCMethod(ejs, httpClass, "fetch", fetchProc, 0);
+ ejsDefineCMethod(ejs, httpClass, "stop", stopProc, 0);
+ ejsDefineCMethod(ejs, httpClass, "setCallback", setCallback, 0);
+
+#if FUTURE
+ ejsDefineCMethod(ejs, httpClass, "put", put, 0);
+ ejsDefineCMethod(ejs, httpClass, "upload", upload, 0);
+ ejsDefineCMethod(ejs, httpClass, "addUploadFile", addUploadFile, 0);
+ ejsDefineCMethod(ejs, httpClass, "addPostData", addPostData, 0);
+ ejsDefineCMethod(ejs, httpClass, "setUserPassword", setUserPassword, 0);
+ ejsDefineCMethod(ejs, httpClass, "addCookie", addCookie, 0);
+#endif
+
+ /*
+ * Define properties
+ */
+ ejsSetPropertyToString(ejs, httpClass, "status", "inactive");
+
+ /* This default should come from player.xml */
+
+ ejsSetPropertyToInteger(ejs, httpClass, "timeout", 30 * 1000);
+ ejsSetPropertyToInteger(ejs, httpClass, "responseCode", 0);
+
+ return ejsObjHasErrors(httpClass) ? MPR_ERR_CANT_INITIALIZE: 0;
+}
+
+/******************************************************************************/
+
+void ejsTermHTTPClass(Ejs *ejs)
+{
+ IWeb *web;
+ int rc;
+
+ web = (IWeb*) mprGetKeyValue(ejs, "bpWeb");
+ if (web) {
+ rc = IWEB_Release(web);
+ mprAssert(rc == 0);
+ }
+}
+
+#endif
+/******************************************************************************/
+
+/*
+ * 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-2.0/ejs/system/ejsGC.c b/source4/lib/appweb/ejs-2.0/ejs/system/ejsGC.c
new file mode 100644
index 0000000000..411975f80e
--- /dev/null
+++ b/source4/lib/appweb/ejs-2.0/ejs/system/ejsGC.c
@@ -0,0 +1,326 @@
+/*
+ * @file ejsGC.c
+ * @brief Garbage collector class for the EJS Object Model
+ */
+/********************************** Copyright *********************************/
+/*
+ * Copyright (c) Mbedthis Software LLC, 2005-2006. All Rights Reserved.
+ */
+/********************************** Includes **********************************/
+
+#include "ejs.h"
+
+/******************************************************************************/
+/************************************ Methods *********************************/
+/******************************************************************************/
+#if (WIN || BREW_SIMULATOR) && BLD_DEBUG
+
+static int checkProc(Ejs *ep, EjsVar *thisObj, int argc, EjsVar **argv)
+{
+ _CrtCheckMemory();
+ return 0;
+}
+
+#endif
+/******************************************************************************/
+
+static int debugProc(Ejs *ep, EjsVar *thisObj, int argc, EjsVar **argv)
+{
+ if (argc != 1) {
+ ejsError(ep, EJS_ARG_ERROR, "Bad args: debug(debugLevel)");
+ return -1;
+ }
+
+ ejsSetGCDebugLevel(ep, ejsVarToInteger(argv[0]));
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * Print stats and dump objects
+ */
+
+static int printStatsProc(Ejs *ep, EjsVar *thisObj, int argc, EjsVar **argv)
+{
+ bool leakStats;
+
+ if (argc > 1) {
+ leakStats = ejsVarToInteger(argv[0]);
+ } else {
+ leakStats = 0;
+ }
+
+#if BLD_FEATURE_ALLOC_STATS
+ ejsPrintAllocReport(ep, 0);
+
+ mprPrintAllocReport(mprGetApp(ep), leakStats, 0);
+#endif
+
+#if BLD_DEBUG
+ ejsDumpObjects(ep);
+#endif
+
+ return 0;
+}
+
+/******************************************************************************/
+
+static int runProc(Ejs *ep, EjsVar *thisObj, int argc, EjsVar **argv)
+{
+ if (argc > 1) {
+ ejsError(ep, EJS_ARG_ERROR, "Bad args: run([quick])");
+ return -1;
+ }
+
+ if (argc == 1) {
+ ejsIncrementalCollectGarbage(ep);
+ } else {
+ ejsCollectGarbage(ep, -1);
+ }
+ return 0;
+}
+
+/******************************************************************************/
+
+static int usedMemoryProc(Ejs *ep, EjsVar *thisObj, int argc, EjsVar **argv)
+{
+ ejsSetReturnValueToInteger(ep, ejsGetUsedMemory(ep));
+ return 0;
+}
+
+/******************************************************************************/
+
+static int allocatedMemoryProc(Ejs *ep, EjsVar *thisObj, int argc,
+ EjsVar **argv)
+{
+#if BLD_FEATURE_ALLOC_STATS
+ ejsSetReturnValueToInteger(ep, ejsGetAllocatedMemory(ep));
+#endif
+ return 0;
+}
+
+/******************************************************************************/
+
+static int mprMemoryProc(Ejs *ep, EjsVar *thisObj, int argc, EjsVar **argv)
+{
+#if BLD_FEATURE_ALLOC_STATS
+ ejsSetReturnValueToInteger(ep, mprGetAllocatedMemory(ep));
+#endif
+ return 0;
+}
+
+/******************************************************************************/
+
+static int peakMprMemoryProc(Ejs *ep, EjsVar *thisObj, int argc, EjsVar **argv)
+{
+#if BLD_FEATURE_ALLOC_STATS
+ ejsSetReturnValueToInteger(ep, mprGetPeakAllocatedMemory(ep));
+#endif
+ return 0;
+}
+
+/******************************************************************************/
+
+static int getDebugLevel(Ejs *ep, EjsVar *thisObj, int argc, EjsVar **argv)
+{
+ ejsSetReturnValueToInteger(ep, ep->gc.debugLevel);
+ return 0;
+}
+
+/******************************************************************************/
+
+static int setDebugLevel(Ejs *ep, EjsVar *thisObj, int argc, EjsVar **argv)
+{
+ if (argc != 1) {
+ ejsArgError(ep, "Bad arguments");
+ return -1;
+ }
+ ep->gc.debugLevel= ejsVarToInteger(argv[0]);
+ return 0;
+}
+
+/******************************************************************************/
+
+static int getEnable(Ejs *ep, EjsVar *thisObj, int argc, EjsVar **argv)
+{
+ ejsSetReturnValueToBoolean(ep, ep->gc.enable);
+ return 0;
+}
+
+/******************************************************************************/
+
+static int setEnable(Ejs *ep, EjsVar *thisObj, int argc, EjsVar **argv)
+{
+ if (argc != 1) {
+ ejsArgError(ep, "Bad arguments");
+ return -1;
+ }
+ ep->gc.enable= ejsVarToBoolean(argv[0]);
+ return 0;
+}
+
+/******************************************************************************/
+
+static int getDemandCollect(Ejs *ep, EjsVar *thisObj, int argc, EjsVar **argv)
+{
+ ejsSetReturnValueToBoolean(ep, ep->gc.enableDemandCollect);
+ return 0;
+}
+
+/******************************************************************************/
+
+static int setDemandCollect(Ejs *ep, EjsVar *thisObj, int argc, EjsVar **argv)
+{
+ if (argc != 1) {
+ ejsArgError(ep, "Bad arguments");
+ return -1;
+ }
+ ep->gc.enableDemandCollect = ejsVarToBoolean(argv[0]);
+ return 0;
+}
+
+/******************************************************************************/
+
+static int getIdleCollect(Ejs *ep, EjsVar *thisObj, int argc, EjsVar **argv)
+{
+ ejsSetReturnValueToBoolean(ep, ep->gc.enableIdleCollect);
+ return 0;
+}
+
+/******************************************************************************/
+
+static int setIdleCollect(Ejs *ep, EjsVar *thisObj, int argc, EjsVar **argv)
+{
+ if (argc != 1) {
+ ejsArgError(ep, "Bad arguments");
+ return -1;
+ }
+ ep->gc.enableIdleCollect = ejsVarToBoolean(argv[0]);
+ return 0;
+}
+
+/******************************************************************************/
+
+static int getWorkQuota(Ejs *ep, EjsVar *thisObj, int argc, EjsVar **argv)
+{
+ ejsSetReturnValueToInteger(ep, ep->gc.workQuota);
+ return 0;
+}
+
+/******************************************************************************/
+
+static int setWorkQuota(Ejs *ep, EjsVar *thisObj, int argc, EjsVar **argv)
+{
+ int quota;
+
+ if (argc != 1) {
+ ejsArgError(ep, "Bad arguments");
+ return -1;
+ }
+ quota = ejsVarToInteger(argv[0]);
+ if (quota < EJS_GC_MIN_WORK_QUOTA && quota != 0) {
+ ejsArgError(ep, "Bad work quota");
+ return -1;
+ }
+
+ ep->gc.workQuota = quota;
+ return 0;
+}
+
+/******************************************************************************/
+
+static int getMaxMemory(Ejs *ep, EjsVar *thisObj, int argc, EjsVar **argv)
+{
+ ejsSetReturnValueToInteger(ep, ep->gc.maxMemory);
+ return 0;
+}
+
+/******************************************************************************/
+
+static int setMaxMemory(Ejs *ep, EjsVar *thisObj, int argc, EjsVar **argv)
+{
+ int maxMemory;
+
+ if (argc != 1) {
+ ejsArgError(ep, "Bad arguments");
+ return -1;
+ }
+ maxMemory = ejsVarToInteger(argv[0]);
+ if (maxMemory < 0) {
+ ejsArgError(ep, "Bad maxMemory");
+ return -1;
+ }
+
+ ep->gc.maxMemory = maxMemory;
+ return 0;
+}
+
+/******************************************************************************/
+/******************************** Initialization ******************************/
+/******************************************************************************/
+
+int ejsDefineGCClass(Ejs *ep)
+{
+ EjsVar *gcClass;
+ int flags;
+
+ flags = EJS_NO_LOCAL;
+
+ /*
+ * NOTE: We create the GC class and define static methods on it. There
+ * is no object instance
+ */
+ gcClass = ejsDefineClass(ep, "System.GC", "Object", 0);
+ if (gcClass == 0) {
+ return MPR_ERR_CANT_INITIALIZE;
+ }
+
+ /*
+ * MOB -- convert these to properties with accessors when available
+ */
+ ejsDefineCMethod(ep, gcClass, "printStats", printStatsProc, flags);
+ ejsDefineCMethod(ep, gcClass, "run", runProc, flags);
+
+ ejsDefineCMethod(ep, gcClass, "getUsedMemory", usedMemoryProc, flags);
+ ejsDefineCMethod(ep, gcClass, "getAllocatedMemory", allocatedMemoryProc,
+ flags);
+ ejsDefineCMethod(ep, gcClass, "getMprMemory", mprMemoryProc, flags);
+ ejsDefineCMethod(ep, gcClass, "getPeakMprMemory", peakMprMemoryProc, flags);
+ ejsDefineCMethod(ep, gcClass, "debug", debugProc, flags);
+
+#if (WIN || BREW_SIMULATOR) && BLD_DEBUG
+ ejsDefineCMethod(ep, gcClass, "check", checkProc, flags);
+#endif
+
+ ejsDefineCAccessors(ep, gcClass, "debugLevel",
+ getDebugLevel, setDebugLevel, flags);
+
+ ejsDefineCAccessors(ep, gcClass, "enable",
+ getEnable, setEnable, flags);
+
+ ejsDefineCAccessors(ep, gcClass, "demandCollect",
+ getDemandCollect, setDemandCollect, flags);
+
+ ejsDefineCAccessors(ep, gcClass, "idleCollect",
+ getIdleCollect, setIdleCollect, flags);
+
+ ejsDefineCAccessors(ep, gcClass, "workQuota",
+ getWorkQuota, setWorkQuota, flags);
+
+ ejsDefineCAccessors(ep, gcClass, "maxMemory",
+ getMaxMemory, setMaxMemory, flags);
+
+ return ejsObjHasErrors(gcClass) ? MPR_ERR_CANT_INITIALIZE : 0;
+}
+
+/******************************************************************************/
+
+/*
+ * 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-2.0/ejs/system/ejsGlobal.c b/source4/lib/appweb/ejs-2.0/ejs/system/ejsGlobal.c
new file mode 100755
index 0000000000..6ab8f867e1
--- /dev/null
+++ b/source4/lib/appweb/ejs-2.0/ejs/system/ejsGlobal.c
@@ -0,0 +1,785 @@
+/*
+ * @file ejsGlobal.c
+ * @brief EJS support methods
+ */
+/********************************* Copyright **********************************/
+/*
+ * @copy default
+ *
+ * Copyright (c) Mbedthis Software LLC, 2003-2006. 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
+ */
+/********************************** Includes **********************************/
+
+#include "ejs.h"
+
+#if BLD_FEATURE_EJS
+
+/******************************************************************************/
+/************************************* Code ***********************************/
+/******************************************************************************/
+/*
+ * assert(condition)
+ */
+
+static int assertProc(Ejs *ep, EjsVar *thisObj, int argc, EjsVar **argv)
+{
+ int b;
+
+ if (argc < 1) {
+ ejsError(ep, EJS_ARG_ERROR, "usage: assert(condition)");
+ return -1;
+ }
+ b = ejsVarToBoolean(argv[0]);
+ if (b == 0) {
+ ejsError(ep, EJS_ASSERT_ERROR, "Assertion failure at line %d",
+ ejsGetLineNumber(ep));
+ return -1;
+ }
+ ejsWriteVarAsBoolean(ep, ep->result, b);
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * breakpoint(msg)
+ */
+
+static int breakpointProc(Ejs *ep, EjsVar *thisObj, int argc, EjsVar **argv)
+{
+ char *buf;
+
+ if (argc < 1) {
+ return 0;
+ }
+ buf = ejsVarToString(ep, argv[0]);
+ if (buf) {
+ mprBreakpoint(0, buf);
+ }
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * basename(path)
+ */
+
+static int basenameProc(Ejs *ep, EjsVar *thisObj, int argc, EjsVar **argv)
+{
+ char *path;
+
+ if (argc != 1) {
+ ejsError(ep, EJS_ARG_ERROR, "usage: basename(path)");
+ return -1;
+ }
+
+ path = ejsVarToString(ep, argv[0]);
+ if (path == 0) {
+ return MPR_ERR_MEMORY;
+ }
+ ejsSetReturnValueToString(ep, mprGetBaseName(path));
+
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * stripext(path)
+ */
+
+static int stripextProc(Ejs *ep, EjsVar *thisObj, int argc, EjsVar **argv)
+{
+ char *cp, *path, *stripPath;
+
+ if (argc != 1) {
+ ejsError(ep, EJS_ARG_ERROR, "usage: stripext(path)");
+ return -1;
+ }
+
+ path = ejsVarToString(ep, argv[0]);
+ if (path == 0) {
+ return MPR_ERR_MEMORY;
+ }
+ stripPath = mprStrdup(ep, path);
+
+ if ((cp = strrchr(stripPath, '.')) != 0) {
+ *cp = '\0';
+ }
+
+ ejsSetReturnValueToString(ep, stripPath);
+
+ mprFree(stripPath);
+
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * dirname(path)
+ */
+
+static int dirnameProc(Ejs *ep, EjsVar *thisObj, int argc, EjsVar **argv)
+{
+ char *path;
+ char dirname[MPR_MAX_FNAME];
+
+ if (argc != 1) {
+ ejsError(ep, EJS_ARG_ERROR, "usage: dirname(path)");
+ return -1;
+ }
+
+ path = ejsVarToString(ep, argv[0]);
+ if (path == 0) {
+ return MPR_ERR_MEMORY;
+ }
+
+ ejsSetReturnValueToString(ep,
+ mprGetDirName(dirname, sizeof(dirname), path));
+
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * trim(string) -- trim white space
+ */
+
+static int trimProc(Ejs *ep, EjsVar *thisObj, int argc, EjsVar **argv)
+{
+ char *str, *buf, *cp;
+
+ if (argc != 1) {
+ ejsError(ep, EJS_ARG_ERROR, "usage: trim(string)");
+ return -1;
+ }
+
+ str = ejsVarToString(ep, argv[0]);
+ if (str == 0) {
+ return MPR_ERR_MEMORY;
+ }
+ str = buf = mprStrdup(ep, str);
+
+ while (isspace(*str)) {
+ str++;
+ }
+ cp = &str[strlen(str) - 1];
+ while (cp >= str) {
+ if (isspace(*cp)) {
+ *cp = '\0';
+ } else {
+ break;
+ }
+ cp--;
+ }
+
+ ejsSetReturnValueToString(ep, str);
+
+ mprFree(buf);
+
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * Terminate the script
+ */
+
+static int exitScript(Ejs *ep, EjsVar *thisObj, int argc, EjsVar **argv)
+{
+ int status;
+
+ if (argc != 1) {
+ ejsError(ep, EJS_ARG_ERROR, "usage: exit(status)");
+ return -1;
+ }
+ status = (int) ejsVarToInteger(argv[0]);
+ ejsExit(ep, status);
+
+ ejsWriteVarAsString(ep, ep->result, "");
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * include javascript libraries.
+ */
+
+static int includeProc(Ejs *ep, EjsVar *thisObj, int argc, char **argv)
+{
+ int i;
+
+ mprAssert(argv);
+
+ for (i = 0; i < argc; i++) {
+ if (ejsEvalFile(ep, argv[i], 0) < 0) {
+ return -1;
+ }
+ }
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * include javascript libraries at the global level
+ */
+
+static int includeGlobalProc(Ejs *ep, EjsVar *thisObj, int argc, char **argv)
+{
+ int fid, i;
+
+ mprAssert(argv);
+
+ /*
+ * Create a new block and set the context to be the global scope
+ */
+ fid = ejsSetBlock(ep, ep->global);
+
+ for (i = 0; i < argc; i++) {
+ if (ejsEvalFile(ep, argv[i], 0) < 0) {
+ ejsCloseBlock(ep, fid);
+ return -1;
+ }
+ }
+ ejsCloseBlock(ep, fid);
+ return 0;
+}
+
+/******************************************************************************/
+#if BLD_DEBUG
+/*
+ * Print variables to stdout
+ */
+
+static int printvProc(Ejs *ep, EjsVar *thisObj, int argc, EjsVar **argv)
+{
+ EjsVar *vp;
+ char *buf;
+ int i;
+
+ for (i = 0; i < argc; ) {
+ vp = argv[i++];
+
+ /* mprPrintf(ep, "arg[%d] = ", i); */
+
+ buf = ejsVarToString(ep, vp);
+
+ if (vp->propertyName == 0 || *vp->propertyName == '\0') {
+ mprPrintf(ep, "%s: ", buf);
+
+ } else if (i < argc) {
+ mprPrintf(ep, "%s = %s, ", vp->propertyName, buf);
+ } else {
+ mprPrintf(ep, "%s = %s\n", vp->propertyName, buf);
+ }
+ }
+ return 0;
+}
+
+#endif
+/******************************************************************************/
+/*
+ * Print the args to stdout
+ */
+
+static int printProc(Ejs *ep, EjsVar *thisObj, int argc, EjsVar **argv)
+{
+ char *buf;
+ int i;
+
+ for (i = 0; i < argc; i++) {
+ buf = ejsVarToString(ep, argv[i]);
+ mprPrintf(ep, "%s", buf);
+ }
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * println
+ */
+
+static int printlnProc(Ejs *ep, EjsVar *thisObj, int argc, EjsVar **argv)
+{
+ printProc(ep, thisObj, argc, argv);
+ mprPrintf(ep, "\n");
+ return 0;
+}
+
+/******************************************************************************/
+#if FUTURE
+/*
+ * sprintf
+ */
+
+static int sprintfProc(Ejs *ep, EjsVar *thisObj, int argc, EjsVar **argv)
+{
+ va_list ap;
+ char *buf;
+ void **args;
+ int result;
+
+ if (argc <= 1) {
+ ejsError(ep, EJS_ARG_ERROR, "Usage: sprintf(fmt, [args ...])");
+ return -1;
+ }
+
+ args = mprAlloc(ep, sizeof(void*) * (argc - 1));
+ if (args == 0) {
+ mprAssert(args);
+ return -1;
+ }
+
+ for (i = 1; i < argc; i++) {
+ args[i - 1] = argv[i]);
+ }
+
+ va_start(ap, fmt);
+ *buf = 0;
+ result = inner(0, &buf, MPR_MAX_STRING, fmt, args);
+ va_end(ap);
+
+ ejsSetReturnValueToString(ep, buf);
+
+ mprFree(buf);
+ return 0;
+}
+
+/******************************************************************************/
+
+inner(const char *fmt, void **args)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ *buf = 0;
+ mprSprintfCore(ctx, &buf, maxSize, fmt, ap, MPR_PRINTF_ARGV);
+ va_end(ap);
+}
+
+#endif
+/******************************************************************************/
+/*
+ * sleep
+ */
+
+static int sleepProc(Ejs *ep, EjsVar *thisObj, int argc, EjsVar **argv)
+{
+ if (argc != 1) {
+ ejsError(ep, EJS_ARG_ERROR, "Usage: sleep(milliseconds)");
+ return -1;
+ }
+ mprSleep(ep, ejsVarToInteger(argv[0]));
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * sort properties
+ * FUTURE -- should have option to sort object based on a given property value
+ * ascending or descending
+ * Usage: sort(object, order = ascending, property = 0);
+ */
+
+static int sortProc(Ejs *ep, EjsVar *thisObj, int argc, EjsVar **argv)
+{
+ const char *property;
+ int error, order;
+
+ error = 0;
+ property = 0;
+
+ /*
+ * Default order is increasing
+ */
+ order = 1;
+
+ if (argc < 1 || argc > 3 || !ejsVarIsObject(argv[0])) {
+ error++;
+ }
+
+ if (argc >= 2) {
+ order = ejsVarToInteger(argv[1]);
+ }
+
+ /*
+ * If property is not defined, it sorts the properties in the object
+ */
+ if (argc == 3) {
+ if (! ejsVarIsString(argv[2])) {
+ error++;
+ } else {
+ property = argv[2]->string;
+ }
+ }
+
+ if (error) {
+ ejsError(ep, EJS_ARG_ERROR, "Usage: sort(object, [order], [property])");
+ return -1;
+ }
+ ejsSortProperties(ep, argv[0], 0, property, order);
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * Get a time mark
+ * MOB -- WARNING: this can overflow. OK on BREW, but other O/Ss it may have
+ * overflowed on the first call. It should be renamed.
+ * MOB -- replace with proper Date.
+ */
+
+static int timeProc(Ejs *ep, EjsVar *thisObj, int argc, EjsVar **argv)
+{
+ MprTime now;
+
+ mprGetTime(ep, &now);
+#if WIN || LINUX || SOLARIS
+{
+ /* MOB -- poor hack */
+ static MprTime initial;
+ if (initial.sec == 0) {
+ initial = now;
+ }
+ now.sec -= initial.sec;
+
+ if (initial.msec > now.msec) {
+ now.msec = now.msec + 1000 - initial.msec;
+ now.sec--;
+ } else {
+ now.msec -= initial.msec;
+ }
+}
+#endif
+ /* MOB -- this can overflow */
+ ejsSetReturnValueToInteger(ep, now.sec * 1000 + now.msec);
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * MOB -- Temporary Get the date (time since Jan 6, 1980 GMT
+ */
+
+static int dateProc(Ejs *ep, EjsVar *thisObj, int argc, EjsVar **argv)
+{
+#if BREW
+ uint now;
+
+ now = GETTIMESECONDS();
+ ejsSetReturnValueToInteger(ep, now);
+#endif
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * strlen(string)
+ */
+
+static int strlenProc(Ejs *ep, EjsVar *thisObj, int argc, EjsVar **argv)
+{
+ char *buf;
+ int len;
+
+ if (argc != 1) {
+ ejsError(ep, EJS_ARG_ERROR, "Usage: strlen(var)");
+ return -1;
+ }
+
+ len = 0;
+ if (! ejsVarIsString(argv[0])) {
+ buf = ejsVarToString(ep, argv[0]);
+ if (buf) {
+ len = strlen(buf);
+ }
+
+ } else {
+ len = argv[0]->length;
+ }
+
+ ejsSetReturnValueToInteger(ep, len);
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * toint(num)
+ */
+
+static int tointProc(Ejs *ep, EjsVar *thisObj, int argc, EjsVar **argv)
+{
+ int i;
+
+ if (argc != 1) {
+ ejsError(ep, EJS_ARG_ERROR, "Usage: toint(number)");
+ return -1;
+ }
+
+ i = ejsVarToInteger(argv[0]);
+
+ ejsSetReturnValueToInteger(ep, i);
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * string strstr(string, pat)
+ */
+
+static int strstrProc(Ejs *ep, EjsVar *thisObj, int argc, EjsVar **argv)
+{
+ char *str, *pat;
+ char *s;
+ int strAlloc;
+
+ if (argc != 2) {
+ ejsError(ep, EJS_ARG_ERROR, "Usage: strstr(string, pat)");
+ return -1;
+ }
+
+ str = ejsVarToString(ep, argv[0]);
+
+ strAlloc = ep->castAlloc;
+ ep->castTemp = 0;
+
+ pat = ejsVarToString(ep, argv[1]);
+
+ s = strstr(str, pat);
+
+ if (s == 0) {
+ ejsSetReturnValueToUndefined(ep);
+ } else {
+ ejsSetReturnValueToString(ep, s);
+ }
+
+ if (strAlloc) {
+ mprFree(str);
+ }
+
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * Trace
+ */
+
+static int traceProc(Ejs *ep, EjsVar *thisObj, int argc, char **argv)
+{
+ if (argc == 1) {
+ mprLog(ep, 0, "%s", argv[0]);
+
+ } else if (argc == 2) {
+ mprLog(ep, atoi(argv[0]), "%s", argv[1]);
+
+ } else {
+ ejsError(ep, EJS_ARG_ERROR, "Usage: trace([level], message)");
+ return -1;
+ }
+ ejsWriteVarAsString(ep, ep->result, "");
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * Evaluate a sub-script. It is evaluated in the same variable scope as
+ * the calling script / method.
+ */
+
+static int evalScriptProc(Ejs *ep, EjsVar *thisObj, int argc, EjsVar **argv)
+{
+ EjsVar *arg;
+ int i;
+
+ ejsWriteVarAsUndefined(ep, ep->result);
+
+ for (i = 0; i < argc; i++) {
+ arg = argv[i];
+ if (arg->type != EJS_TYPE_STRING) {
+ continue;
+ }
+ if (ejsEvalScript(ep, arg->string, 0) < 0) {
+ return -1;
+ }
+ }
+ /*
+ * Return with the value of the last expression
+ */
+ return 0;
+}
+
+/******************************************************************************/
+
+/* MOB -- need a real datatype returning int, int64, etc */
+
+static int typeofProc(Ejs *ep, EjsVar *thisObj, int argc, EjsVar **argv)
+{
+ const struct {
+ EjsType type;
+ const char *name;
+ } types[] = {
+ { EJS_TYPE_UNDEFINED, "undefined" },
+#if EJS_ECMA_STND
+ { EJS_TYPE_NULL, "object" },
+#else
+ { EJS_TYPE_NULL, "null" },
+#endif
+ { EJS_TYPE_BOOL, "boolean" },
+ { EJS_TYPE_CMETHOD, "function" },
+ { EJS_TYPE_FLOAT, "number" },
+ { EJS_TYPE_INT, "number" },
+ { EJS_TYPE_INT64, "number" },
+ { EJS_TYPE_OBJECT, "object" },
+ { EJS_TYPE_METHOD, "function" },
+ { EJS_TYPE_STRING, "string" },
+ { EJS_TYPE_STRING_CMETHOD, "function" },
+ { EJS_TYPE_PTR, "pointer" }
+ };
+ const char *type;
+ int i;
+
+ type = NULL;
+ if (argc != 1) {
+ ejsError(ep, EJS_ARG_ERROR, "Bad args: typeof(var)");
+ return -1;
+ }
+
+ for (i = 0; i < MPR_ARRAY_SIZE(types); i++) {
+ if (argv[0]->type == types[i].type) {
+ type = types[i].name;
+ break;
+ }
+ }
+ if (type == NULL) {
+ mprAssert(type);
+ return -1;
+ }
+
+ ejsSetReturnValueToString(ep, type);
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * Define the standard properties and methods inherited by all interpreters
+ * Obj is set to the global class in the default interpreter. When an
+ * interpreter attempts to write to any property, a copy will be written
+ * into the interpeters own global space. This is like a "copy-on-write".
+ */
+
+int ejsDefineGlobalProperties(Ejs *ep)
+{
+ EjsVar *obj;
+
+ obj = ep->service->globalClass;
+ mprAssert(obj);
+
+ ejsSetPropertyToNull(ep, obj, "null");
+ ejsSetPropertyToUndefined(ep, obj, "undefined");
+ ejsSetPropertyToBoolean(ep, obj, "true", 1);
+ ejsSetPropertyToBoolean(ep, obj, "false", 0);
+
+#if BLD_FEATURE_FLOATING_POINT
+ {
+ /* MOB. Fix. This generates warnings on some systems.
+ This is intended. */
+ double d = 0.0;
+ double e = 0.0;
+ ejsSetPropertyToFloat(ep, obj, "NaN", e / d);
+
+ d = MAX_FLOAT;
+ ejsSetPropertyToFloat(ep, obj, "Infinity", d * d);
+ }
+#endif
+
+#if BLD_FEATURE_LEGACY_API
+ /*
+ * DEPRECATED: 2.0.
+ * So that ESP/ASP can ignore "language=javascript" statements
+ */
+ ejsSetPropertyToInteger(ep, obj, "javascript", 0);
+#endif
+
+ /*
+ * Extension methods. We go directly to the mpr property APIs for speed.
+ * Flags will cause the callbacks to be supplied the Ejs handle.
+ */
+ ejsDefineCMethod(ep, obj, "assert", assertProc, EJS_NO_LOCAL);
+ ejsDefineCMethod(ep, obj, "breakpoint", breakpointProc, EJS_NO_LOCAL);
+ ejsDefineCMethod(ep, obj, "basename", basenameProc, EJS_NO_LOCAL);
+ ejsDefineCMethod(ep, obj, "dirname", dirnameProc, EJS_NO_LOCAL);
+ ejsDefineCMethod(ep, obj, "stripext", stripextProc, EJS_NO_LOCAL);
+ ejsDefineCMethod(ep, obj, "trim", trimProc, EJS_NO_LOCAL);
+ ejsDefineCMethod(ep, obj, "eval", evalScriptProc, EJS_NO_LOCAL);
+ ejsDefineCMethod(ep, obj, "exit", exitScript, EJS_NO_LOCAL);
+ ejsDefineCMethod(ep, obj, "print", printProc, EJS_NO_LOCAL);
+ ejsDefineCMethod(ep, obj, "println", printlnProc, EJS_NO_LOCAL);
+ ejsDefineCMethod(ep, obj, "sleep", sleepProc, EJS_NO_LOCAL);
+ ejsDefineCMethod(ep, obj, "sort", sortProc, EJS_NO_LOCAL);
+ ejsDefineCMethod(ep, obj, "time", timeProc, EJS_NO_LOCAL);
+ ejsDefineCMethod(ep, obj, "date", dateProc, EJS_NO_LOCAL);
+ ejsDefineCMethod(ep, obj, "strlen", strlenProc, EJS_NO_LOCAL);
+ ejsDefineCMethod(ep, obj, "strstr", strstrProc, EJS_NO_LOCAL);
+ ejsDefineCMethod(ep, obj, "typeof", typeofProc, EJS_NO_LOCAL);
+ ejsDefineCMethod(ep, obj, "toint", tointProc, EJS_NO_LOCAL);
+
+ ejsDefineStringCMethod(ep, obj, "include", includeProc, EJS_NO_LOCAL);
+ ejsDefineStringCMethod(ep, obj, "includeGlobal", includeGlobalProc,
+ EJS_NO_LOCAL);
+ ejsDefineStringCMethod(ep, obj, "trace", traceProc, EJS_NO_LOCAL);
+
+#if BLD_DEBUG
+ ejsDefineCMethod(ep, obj, "printv", printvProc, EJS_NO_LOCAL);
+#endif
+
+#if FUTURE
+ ejsDefineCMethod(ep, obj, "printf", printfProc, EJS_NO_LOCAL);
+ ejsDefineCMethod(ep, obj, "sprintf", sprintfProc, EJS_NO_LOCAL);
+#endif
+
+ if (ejsObjHasErrors(obj)) {
+ return MPR_ERR_CANT_INITIALIZE;
+ }
+ return 0;
+}
+
+/******************************************************************************/
+
+#else
+void ejsProcsDummy() {}
+
+/******************************************************************************/
+#endif /* BLD_FEATURE_EJS */
+
+/*
+ * 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-2.0/ejs/system/ejsSystem.c b/source4/lib/appweb/ejs-2.0/ejs/system/ejsSystem.c
new file mode 100644
index 0000000000..e035e1c740
--- /dev/null
+++ b/source4/lib/appweb/ejs-2.0/ejs/system/ejsSystem.c
@@ -0,0 +1,112 @@
+/*
+ * @file ejsSystem.c
+ * @brief System class for the EJS Object Model
+ */
+/********************************** Copyright *********************************/
+/*
+ * Copyright (c) Mbedthis Software LLC, 2005-2006. All Rights Reserved.
+ */
+/********************************** Includes **********************************/
+
+#include "ejs.h"
+
+/******************************************************************************/
+/************************************ Methods *********************************/
+/******************************************************************************/
+#if UNUSED
+/*
+ * function int random()
+ */
+
+static int randomProc(Ejs *ep, EjsVar *thisObj, int argc, EjsVar **argv)
+{
+ ejsTrace(ep, "random()\n");
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * function void yield()
+ */
+
+static int yieldProc(Ejs *ep, EjsVar *thisObj, int argc, EjsVar **argv)
+{
+ ejsTrace(ep, "yield()\n");
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * function void sleep(int milliSeconds)
+ */
+
+static int sleepProc(Ejs *ep, EjsVar *thisObj, int argc, EjsVar **argv)
+{
+ ejsTrace(ep, "sleep()\n");
+ return 0;
+}
+
+#endif
+/******************************************************************************/
+/*
+ * function void exit(int status)
+ *
+ * Exit the widget with the given status. All JavaScript processing ceases.
+ */
+
+static int exitProc(Ejs *ep, EjsVar *thisObj, int argc, EjsVar **argv)
+{
+ int status;
+
+ status = 0;
+ if ((argc == 1) && ejsVarIsInteger(argv[0])) {
+ status = argv[0]->integer;
+ }
+ ejsExit(ep, status);
+ return 0;
+}
+
+/******************************************************************************/
+/******************************** Initialization ******************************/
+/******************************************************************************/
+
+int ejsDefineSystemClass(Ejs *ep)
+{
+ EjsVar *systemClass;
+
+ /*
+ * We create the system class and define static methods on it.
+ * NOTE: There is no object instance
+ */
+ systemClass = ejsDefineClass(ep, "System", "Object", 0);
+ if (systemClass == 0) {
+ return MPR_ERR_CANT_INITIALIZE;
+ }
+
+ ejsDefineCMethod(ep, systemClass, "exit", exitProc, EJS_NO_LOCAL);
+
+#if UNUSED
+ ejsDefineCMethod(ep, systemClass, "random", randomProc, EJS_NO_LOCAL);
+ ejsDefineCMethod(ep, systemClass, "yield", yieldProc, EJS_NO_LOCAL);
+ ejsDefineCMethod(ep, systemClass, "sleep", sleepProc, EJS_NO_LOCAL);
+
+ /*
+ * Define properties
+ */
+ ejsSetPropertyToString(systemClass, "name", "");
+#endif
+
+ return ejsObjHasErrors(systemClass) ? MPR_ERR_CANT_INITIALIZE : 0;
+}
+
+/******************************************************************************/
+
+/*
+ * 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-2.0/ejs/system/ejsSystemApp.c b/source4/lib/appweb/ejs-2.0/ejs/system/ejsSystemApp.c
new file mode 100644
index 0000000000..e2f1ceb363
--- /dev/null
+++ b/source4/lib/appweb/ejs-2.0/ejs/system/ejsSystemApp.c
@@ -0,0 +1,49 @@
+/*
+ * @file ejsSystemApp.c
+ * @brief App class
+ */
+/********************************** Copyright *********************************/
+/*
+ * Copyright (c) Mbedthis Software Inc, 2005-2006. All Rights Reserved.
+ */
+/********************************** Includes **********************************/
+
+#include "ejs.h"
+
+/************************************ Code ************************************/
+
+int ejsDefineAppClass(Ejs *ep)
+{
+ EjsVar *appClass;
+
+ appClass = ejsDefineClass(ep, "System.App", "Object", 0);
+ if (appClass == 0) {
+ return MPR_ERR_CANT_INITIALIZE;
+ }
+
+ /*
+ * Define properties
+ */
+ ejsSetPropertyToString(ep, appClass, "name", BLD_PRODUCT);
+ ejsSetPropertyToString(ep, appClass, "title", BLD_NAME);
+ ejsSetPropertyToString(ep, appClass, "version", BLD_VERSION);
+
+ /*
+ * Command line arguments
+ */
+ ejsSetPropertyToNull(ep, appClass, "args");
+
+ return ejsObjHasErrors(appClass) ? MPR_ERR_CANT_INITIALIZE : 0;
+}
+
+/******************************************************************************/
+
+/*
+ * 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-2.0/ejs/system/ejsSystemDebug.c b/source4/lib/appweb/ejs-2.0/ejs/system/ejsSystemDebug.c
new file mode 100644
index 0000000000..5a011e2a2d
--- /dev/null
+++ b/source4/lib/appweb/ejs-2.0/ejs/system/ejsSystemDebug.c
@@ -0,0 +1,60 @@
+/*
+ * @file ejsSystemDebug.c
+ * @brief System.Debug class
+ */
+/********************************** Copyright *********************************/
+/*
+ * Copyright (c) Mbedthis Software LLC, 2005-2006. All Rights Reserved.
+ */
+/********************************** Includes **********************************/
+
+#include "ejs.h"
+
+/******************************************************************************/
+/************************************ Methods *********************************/
+/******************************************************************************/
+/*
+ * function bool isDebugMode()
+ * MOB -- convert to accessor
+ */
+
+static int isDebugMode(Ejs *ejs, EjsVar *thisObj, int argc, EjsVar **argv)
+{
+ ejsTrace(ejs, "isDebugMode()\n");
+ ejsSetReturnValueToInteger(ejs, mprGetDebugMode(ejs));
+ return 0;
+}
+
+/******************************************************************************/
+/******************************** Initialization ******************************/
+/******************************************************************************/
+
+int ejsDefineDebugClass(Ejs *ejs)
+{
+ EjsVar *systemDebugClass;
+
+ systemDebugClass = ejsDefineClass(ejs, "System.Debug", "Object", 0);
+ if (systemDebugClass == 0) {
+ return MPR_ERR_CANT_INITIALIZE;
+ }
+
+ /*
+ * Define the class methods
+ */
+ ejsDefineCMethod(ejs, systemDebugClass, "isDebugMode", isDebugMode,
+ EJS_NO_LOCAL);
+
+ return ejsObjHasErrors(systemDebugClass) ? MPR_ERR_CANT_INITIALIZE : 0;
+}
+
+/******************************************************************************/
+
+/*
+ * 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-2.0/ejs/system/ejsSystemLog.c b/source4/lib/appweb/ejs-2.0/ejs/system/ejsSystemLog.c
new file mode 100644
index 0000000000..66467f8fcf
--- /dev/null
+++ b/source4/lib/appweb/ejs-2.0/ejs/system/ejsSystemLog.c
@@ -0,0 +1,163 @@
+/*
+ * @file ejsSystemLog.c
+ * @brief System.Log class for the EJS Object Model
+ */
+/********************************** Copyright *********************************/
+/*
+ * Copyright (c) Mbedthis Software LLC, 2005-2006. All Rights Reserved.
+ */
+/********************************** Includes **********************************/
+
+#include "ejs.h"
+
+/*********************************** Usage ************************************/
+/*
+ * System.Log.setLog(path);
+ * System.Log.enable;
+ */
+/******************************************************************************/
+
+static void logHandler(MPR_LOC_DEC(ctx, loc), int flags, int level,
+ const char *msg)
+{
+ MprApp *app;
+ char *buf;
+ int len;
+
+ app = mprGetApp(ctx);
+ if (app->logFile == 0) {
+ return;
+ }
+
+ if (flags & MPR_LOG_SRC) {
+ len = mprAllocSprintf(MPR_LOC_PASS(ctx, loc), &buf, 0,
+ "Log %d: %s\n", level, msg);
+
+ } else if (flags & MPR_ERROR_SRC) {
+ len = mprAllocSprintf(MPR_LOC_PASS(ctx, loc), &buf, 0,
+ "Error: %s\n", msg);
+
+ } else if (flags & MPR_FATAL_SRC) {
+ len = mprAllocSprintf(MPR_LOC_PASS(ctx, loc), &buf, 0,
+ "Fatal: %s\n", msg);
+
+ } else if (flags & MPR_ASSERT_SRC) {
+#if BLD_FEATURE_ALLOC_LEAK_TRACK
+ len = mprAllocSprintf(MPR_LOC_PASS(ctx, loc), &buf, 0,
+ "Assertion %s, failed at %s\n",
+ msg, loc);
+#else
+ len = mprAllocSprintf(MPR_LOC_PASS(ctx, loc), &buf, 0,
+ "Assertion %s, failed\n", msg);
+#endif
+
+ } else if (flags & MPR_RAW) {
+ /* OPT */
+ len = mprAllocSprintf(MPR_LOC_PASS(ctx, loc), &buf, 0,
+ "%s", msg);
+
+ } else {
+ return;
+ }
+
+ mprPuts(app->logFile, buf, len);
+
+ mprFree(buf);
+}
+
+/******************************************************************************/
+/************************************ Methods *********************************/
+/******************************************************************************/
+/*
+ * function int setLog(string path)
+ */
+
+static int setLog(Ejs *ejs, EjsVar *thisObj, int argc, EjsVar **argv)
+{
+ const char *path;
+ MprFile *file;
+ MprApp *app;
+
+ if (argc != 1 || !ejsVarIsString(argv[0])) {
+ ejsArgError(ejs, "Usage: setLog(path)");
+ return -1;
+ }
+
+ app = mprGetApp(ejs);
+
+ /*
+ * Ignore errors if we can't create the log file.
+ * Use the app context so this will live longer than the interpreter
+ * MOB -- this leaks files.
+ */
+ path = argv[0]->string;
+ file = mprOpen(app, path, O_CREAT | O_TRUNC | O_WRONLY, 0664);
+ if (file) {
+ app->logFile = file;
+ mprSetLogHandler(ejs, logHandler);
+ }
+ mprLog(ejs, 0, "Test log");
+
+ return 0;
+}
+
+/******************************************************************************/
+#if UNUSED
+
+static int enableSetAccessor(Ejs *ejs, EjsVar *thisObj, int argc, EjsVar **argv)
+{
+ if (argc != 1) {
+ ejsArgError(ejs, "Usage: set(value)");
+ return -1;
+ }
+ ejsSetProperty(ejs, thisObj, "_enabled", argv[0]);
+ return 0;
+}
+
+/******************************************************************************/
+
+static int enableGetAccessor(Ejs *ejs, EjsVar *thisObj, int argc, EjsVar **argv)
+{
+ ejsSetReturnValue(ejs, ejsGetPropertyAsVar(ejs, thisObj, "_enabled"));
+ return 0;
+}
+
+#endif
+/******************************************************************************/
+/******************************** Initialization ******************************/
+/******************************************************************************/
+
+int ejsDefineLogClass(Ejs *ejs)
+{
+ EjsVar *logClass;
+
+ logClass = ejsDefineClass(ejs, "System.Log", "Object", 0);
+ if (logClass == 0) {
+ return MPR_ERR_CANT_INITIALIZE;
+ }
+
+ ejsDefineCMethod(ejs, logClass, "setLog", setLog, EJS_NO_LOCAL);
+
+#if UNUSED
+ EjsProperty *pp;
+ ejsDefineCAccessors(ejs, logClass, "enable", enableSetAccessor,
+ enableGetAccessor, EJS_NO_LOCAL);
+
+ pp = ejsSetPropertyToBoolean(ejs, logClass, "_enabled", 0);
+ ejsMakePropertyEnumerable(pp, 0);
+#endif
+
+ return ejsObjHasErrors(logClass) ? MPR_ERR_CANT_INITIALIZE : 0;
+}
+
+/******************************************************************************/
+
+/*
+ * 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-2.0/ejs/system/ejsSystemMemory.c b/source4/lib/appweb/ejs-2.0/ejs/system/ejsSystemMemory.c
new file mode 100755
index 0000000000..d10787b1b4
--- /dev/null
+++ b/source4/lib/appweb/ejs-2.0/ejs/system/ejsSystemMemory.c
@@ -0,0 +1,174 @@
+/*
+ * @file ejsSystemMemory.c
+ * @brief System.Memory class
+ */
+/********************************** Copyright *********************************/
+/*
+ * Copyright (c) Mbedthis Software LLC, 2005-2006. All Rights Reserved.
+ */
+/********************************** Includes **********************************/
+
+#include "ejs.h"
+
+/****************************** Forward Declarations***************************/
+
+static uint getUsedMemory(Ejs *ejs);
+
+/******************************************************************************/
+/*********************************** Methods *********************************/
+/******************************************************************************/
+
+static int getUsedMemoryProc(Ejs *ejs, EjsVar *thisObj, int argc, EjsVar **argv)
+{
+ ejsSetReturnValueToInteger(ejs, getUsedMemory(ejs));
+ return 0;
+}
+
+/******************************************************************************/
+
+static int getUsedStackProc(Ejs *ejs, EjsVar *thisObj, int argc, EjsVar **argv)
+{
+ ejsSetReturnValueToInteger(ejs, mprStackSize(ejs));
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * Public function
+ */
+
+uint ejsGetAvailableMemory(Ejs *ejs)
+{
+ EjsVar *memoryClass;
+ uint ram;
+
+ memoryClass = ejsGetClass(ejs, 0, "System.Memory");
+
+ ram = ejsGetPropertyAsInteger(ejs, memoryClass, "ram");
+ return ram - getUsedMemory(ejs);
+}
+
+/******************************************************************************/
+
+static int getAvailableMemoryProc(Ejs *ejs, EjsVar *thisObj, int argc,
+ EjsVar **argv)
+{
+ EjsVar *memoryClass;
+ uint ram;
+
+ memoryClass = ejsGetClass(ejs, 0, "System.Memory");
+
+ ram = ejsGetPropertyAsInteger(ejs, memoryClass, "ram");
+#if BREW
+ ejsSetReturnValueToInteger(ejs, ram - getUsedMemory(ejs));
+#else
+ ejsSetReturnValueToInteger(ejs, 0);
+#endif
+ return 0;
+}
+
+/******************************************************************************/
+
+static uint getUsedMemory(Ejs *ejs)
+{
+#if BREW
+ MprApp *app;
+ IHeap *heap;
+ uint memInUse;
+ void *ptr;
+
+ app = mprGetApp(ejs);
+ ptr = (void*) &heap;
+ if (ISHELL_CreateInstance(app->shell, AEECLSID_HEAP, (void**) ptr)
+ == SUCCESS) {
+ memInUse = IHEAP_GetMemStats(heap);
+ IHEAP_Release(heap);
+ } else {
+ memInUse = 0;
+ }
+
+ return memInUse;
+#else
+ return 0;
+#endif
+}
+
+/******************************************************************************/
+/******************************** Initialization ******************************/
+/******************************************************************************/
+
+int ejsDefineMemoryClass(Ejs *ejs)
+{
+ EjsVar *memoryClass;
+ uint used;
+
+#if BREW
+ MprApp *app;
+ AEEDeviceInfo *info;
+
+ /*
+ * Get needed information for class properties.
+ */
+ info = mprAllocType(ejs, AEEDeviceInfo);
+ if (info == 0) {
+ return MPR_ERR_CANT_ALLOCATE;
+ }
+ info->wStructSize = sizeof(AEEDeviceInfo);
+ app = mprGetApp(ejs);
+ ISHELL_GetDeviceInfo(app->shell, info);
+ used = getUsedMemory(ejs);
+#else
+ used = 0;
+#endif
+
+ /*
+ * Create the class
+ */
+ memoryClass = ejsDefineClass(ejs, "System.Memory", "Object", 0);
+ if (memoryClass == 0) {
+ return MPR_ERR_CANT_INITIALIZE;
+ }
+
+ /*
+ * Define the class methods
+ * MOB -- change to accessors
+ */
+ ejsDefineCMethod(ejs, memoryClass, "getUsedStack", getUsedStackProc,
+ EJS_NO_LOCAL);
+ ejsDefineCMethod(ejs, memoryClass, "getUsedMemory", getUsedMemoryProc,
+ EJS_NO_LOCAL);
+ ejsDefineCMethod(ejs, memoryClass, "getAvailableMemory",
+ getAvailableMemoryProc, EJS_NO_LOCAL);
+
+ /*
+ * Define properties
+ */
+#if BREW
+ ejsSetPropertyToInteger(ejs, memoryClass, "ram", info->dwRAM);
+
+#if UNUSED
+ /* MOB -- delete this */
+ ejsSetPropertyToInteger(ejs, memoryClass, "available",
+ info->dwRAM - used);
+#endif
+#endif
+
+#if UNUSED
+ ejsSetPropertyToInteger(ejs, memoryClass, "used", used);
+ ejsSetPropertyToInteger(ejs, memoryClass, "flash", 0);
+#endif
+
+ return ejsObjHasErrors(memoryClass) ? MPR_ERR_CANT_INITIALIZE : 0;
+}
+
+/******************************************************************************/
+
+/*
+ * 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
+ */