diff options
author | Derrell Lipman <derrell@samba.org> | 2006-09-26 16:58:27 +0000 |
---|---|---|
committer | Gerald (Jerry) Carter <jerry@samba.org> | 2007-10-10 14:20:21 -0500 |
commit | 77e8402dd68079c0e245fc8826daf2c6ad334766 (patch) | |
tree | 64f65c7d3fb7f3aa970311f70e3f8bae4c0fc40c /source4/lib/appweb/ejs-2.0/ejs/classes | |
parent | 06de0f0b743056ba845de000339d4c3beb7cb845 (diff) | |
download | samba-77e8402dd68079c0e245fc8826daf2c6ad334766.tar.gz samba-77e8402dd68079c0e245fc8826daf2c6ad334766.tar.bz2 samba-77e8402dd68079c0e245fc8826daf2c6ad334766.zip |
r18925: Add current snapshot of the ejs-2.0 code. Tridge, will you be incorporating this?
(This used to be commit 917af234a8d517f82bd42256a940608a16b988f4)
Diffstat (limited to 'source4/lib/appweb/ejs-2.0/ejs/classes')
-rw-r--r-- | source4/lib/appweb/ejs-2.0/ejs/classes/.ignore | 1 | ||||
-rw-r--r-- | source4/lib/appweb/ejs-2.0/ejs/classes/Makefile | 21 | ||||
-rw-r--r-- | source4/lib/appweb/ejs-2.0/ejs/classes/ejsArray.c | 167 | ||||
-rwxr-xr-x | source4/lib/appweb/ejs-2.0/ejs/classes/ejsDate.c | 197 | ||||
-rwxr-xr-x | source4/lib/appweb/ejs-2.0/ejs/classes/ejsError.c | 140 | ||||
-rw-r--r-- | source4/lib/appweb/ejs-2.0/ejs/classes/ejsObject.c | 588 | ||||
-rw-r--r-- | source4/lib/appweb/ejs-2.0/ejs/classes/ejsStndClasses.c | 144 | ||||
-rw-r--r-- | source4/lib/appweb/ejs-2.0/ejs/classes/ejsString.c | 381 | ||||
-rw-r--r-- | source4/lib/appweb/ejs-2.0/ejs/classes/ejsXml.c | 1327 |
9 files changed, 2966 insertions, 0 deletions
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 + */ |