summaryrefslogtreecommitdiff
path: root/source4
diff options
context:
space:
mode:
Diffstat (limited to 'source4')
-rw-r--r--source4/lib/appweb/ejs-2.0/.bashrc153
-rw-r--r--source4/lib/appweb/ejs-2.0/.exrc1
-rw-r--r--source4/lib/appweb/ejs-2.0/.ignore57
-rw-r--r--source4/lib/appweb/ejs-2.0/.loginrc218
-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
-rw-r--r--source4/lib/appweb/ejs-2.0/exml/Makefile42
-rw-r--r--source4/lib/appweb/ejs-2.0/exml/exml.h94
-rw-r--r--source4/lib/appweb/ejs-2.0/exml/exmlParser.c752
-rw-r--r--source4/lib/appweb/ejs-2.0/exml/files1
-rw-r--r--source4/lib/appweb/ejs-2.0/mpr/Makefile41
-rw-r--r--source4/lib/appweb/ejs-2.0/mpr/UNIX/Makefile16
-rw-r--r--source4/lib/appweb/ejs-2.0/mpr/UNIX/mprFile.c86
-rw-r--r--source4/lib/appweb/ejs-2.0/mpr/UNIX/mprPlatform.c218
-rw-r--r--source4/lib/appweb/ejs-2.0/mpr/UNIX/mprTime.c163
-rw-r--r--source4/lib/appweb/ejs-2.0/mpr/VXWORKS/Makefile16
-rw-r--r--source4/lib/appweb/ejs-2.0/mpr/VXWORKS/mprFile.c85
-rw-r--r--source4/lib/appweb/ejs-2.0/mpr/VXWORKS/mprPlatform.c191
-rwxr-xr-xsource4/lib/appweb/ejs-2.0/mpr/VXWORKS/mprTime.c163
-rw-r--r--source4/lib/appweb/ejs-2.0/mpr/WIN/Makefile16
-rw-r--r--source4/lib/appweb/ejs-2.0/mpr/WIN/mprFile.c123
-rw-r--r--source4/lib/appweb/ejs-2.0/mpr/WIN/mprPlatform.c378
-rw-r--r--source4/lib/appweb/ejs-2.0/mpr/WIN/mprTime.c192
-rw-r--r--source4/lib/appweb/ejs-2.0/mpr/files14
-rw-r--r--source4/lib/appweb/ejs-2.0/mpr/mpr.c340
-rw-r--r--source4/lib/appweb/ejs-2.0/mpr/mpr.h1027
-rw-r--r--source4/lib/appweb/ejs-2.0/mpr/mprAlloc.c1775
-rw-r--r--source4/lib/appweb/ejs-2.0/mpr/mprArray.c385
-rw-r--r--source4/lib/appweb/ejs-2.0/mpr/mprBuf.c535
-rw-r--r--source4/lib/appweb/ejs-2.0/mpr/mprGenFile.c336
-rw-r--r--source4/lib/appweb/ejs-2.0/mpr/mprGenTime.c195
-rw-r--r--source4/lib/appweb/ejs-2.0/mpr/mprLock.c266
-rw-r--r--source4/lib/appweb/ejs-2.0/mpr/mprLog.c602
-rw-r--r--source4/lib/appweb/ejs-2.0/mpr/mprOs.h707
-rw-r--r--source4/lib/appweb/ejs-2.0/mpr/mprPrintf.c924
-rw-r--r--source4/lib/appweb/ejs-2.0/mpr/mprString.c727
-rw-r--r--source4/lib/appweb/ejs-2.0/mpr/mprSymbol.c279
-rw-r--r--source4/lib/appweb/ejs-2.0/mpr/mprUnix.h105
80 files changed, 33339 insertions, 0 deletions
diff --git a/source4/lib/appweb/ejs-2.0/.bashrc b/source4/lib/appweb/ejs-2.0/.bashrc
new file mode 100644
index 0000000000..c05ee0e6e8
--- /dev/null
+++ b/source4/lib/appweb/ejs-2.0/.bashrc
@@ -0,0 +1,153 @@
+#
+# .bashrc -- Login shell startup script for windows using Mbedthis winTools
+#
+# Copyright (c) Mbedthis Software, 2003-2005. All Rights Reserved.
+#
+
+TERM=ansi
+#
+# Set the desired .NET Framework
+#
+# FRAMEWORK=v1.0.3705
+FRAMEWORK=v1.1.4322
+# FRAMEWORK=v2.0.40607
+
+#
+# Set the desired Microsoft C Compiler version
+#
+# PREFERRED_CC=VS2005
+# PREFERRED_CC=VS2003
+# PREFERRED_CC=VS.NET
+PREFERRED_CC=VS6
+
+#
+# Set to 1 if VXWORKS support is required
+#
+# VXWORKS=1
+
+HOME=`pwd`
+if [ ! -x winTools -o ! -x winTools/cygpath.exe ]
+then
+ echo "Can't find build tools. Install build tools in $HOME/winTools"
+fi
+
+ROOT=`winTools/cygpath -u $HOMEDRIVE`
+: ${ROOT:=C:/}
+APPWEB_PATH="${HOME}/bin/DEBUG:${HOME}/bin/RELEASE:${HOME}/bin:${HOME}/winTools"
+CDPATH=".:${HOME}:${HOME}/http:${HOME}/http/modules:${HOME}/packages"
+PS1="$ "
+
+export CDPATH INCLUDE LIB LIBPATH PATH PS1 TERM
+
+echo -e "\n\n###################################################"
+echo "Mbedthis AppWeb, Cygwin build tools."
+echo "Using compiler: $PREFERRED_CC, .NET framework: $FRAMEWORK"
+echo -e "###################################################"
+
+################################################################################
+
+#
+# Setup for Visual Studio and SDK
+#
+if [ $PREFERRED_CC == "VS2005" ]
+then
+ #
+ # Visual Studio .NET 2005 defines.
+ #
+ CYNET="${ROOT}/Program Files/Microsoft Visual Studio 8"
+ DOSNET="C:/Program Files/Microsoft Visual Studio 8"
+ PATH="$APPWEB_PATH:$CYNET/Common7/IDE:$CYNET/VC/BIN:$CYNET/VC/VCPackages:$CYNET/Common7/Tools:$CYNET/Common7/Tools/bin:$CYNET/SDK/v2.0/bin:`cygpath -W`/Microsoft.NET/Framework/v2.0.40607:$CYNET/SDK/v2.0/bin:$PATH"
+ INCLUDE="$DOSNET/VC/ATLMFC/INCLUDE;$DOSNET/VC/INCLUDE;$DOSNET/VC/PlatformSDK/include;$DOSNET/SDK/v2.0/include;$INCLUDE"
+ LIB="$DOSNET/VC/ATLMFC/LIB;$DOSNET/VC/LIB;$DOSNET/VC/PlatformSDK/lib;$DOSNET/SDK/v2.0/lib;$LIB"
+ LIBPATH=c:/WINDOWS/Microsoft.NET/Framework/$FRAMEWORK
+fi
+
+if [ $PREFERRED_CC == "VS2003" ]
+then
+ #
+ # Visual Studio .NET 2003 defines.
+ #
+ CYNET="${ROOT}/Program Files/Microsoft Visual Studio .NET 2003"
+ DOSNET="C:/Program Files/Microsoft Visual Studio .NET 2003"
+ PATH="$APPWEB_PATH:$CYNET/Common7/IDE:$CYNET/VC7/BIN:$CYNET/Common7/Tools:$CYNET/Common7/Tools/bin/prerelease:$CYNET/Common7/Tools/bin:$CYNET/FrameworkSDK/bin:${ROOT}/WINDOWS/Microsoft.NET/Framework/$FRAMEWORK:$CYNET/SDK/v1.1/bin:$PATH"
+ INCLUDE="$DOSNET/VC7/ATLMFC/INCLUDE;$DOSNET/VC7/INCLUDE;$DOSNET/VC7/PlatformSDK/include/prerelease;$DOSNET/VC7/PlatformSDK/include;$DOSNET/FrameworkSDK/include;$INCLUDE"
+ LIB="$DOSNET/VC7/ATLMFC/LIB;$DOSNET/VC7/LIB;$DOSNET/VC7/PlatformSDK/lib/prerelease;$DOSNET/VC7/PlatformSDK/lib;$DOSNET/FrameworkSDK/lib;$LIB"
+fi
+
+
+if [ $PREFERRED_CC == "VS.NET" ]
+then
+ #
+ # Visual Studio .NET defines.
+ #
+ CYNET="${ROOT}/Program Files/Microsoft Visual Studio .NET"
+ DOSNET="C:/Program Files/Microsoft Visual Studio .NET"
+ PATH="$APPWEB_PATH:$CYNET/Common7/IDE:$CYNET/VC7/BIN:$CYNET/Common7/Tools:$CYNET/Common7/Tools/bin/prerelease:$CYNET/Common7/Tools/bin:$CYNET/FrameworkSDK/bin:${ROOT}/WINDOWS/Microsoft.NET/Framework/$FRAMEWORK:$CYNET/SDK/v1.0/bin:$PATH"
+ INCLUDE="$DOSNET/VC7/ATLMFC/INCLUDE;$DOSNET/VC7/INCLUDE;$DOSNET/VC7/PlatformSDK/include/prerelease;$DOSNET/VC7/PlatformSDK/include;$DOSNET/FrameworkSDK/include;$INCLUDE"
+ LIB="$DOSNET/VC7/ATLMFC/LIB;$DOSNET/VC7/LIB;$DOSNET/VC7/PlatformSDK/lib/prerelease;$DOSNET/VC7/PlatformSDK/lib;$DOSNET/FrameworkSDK/lib;$LIB"
+fi
+
+
+if [ $PREFERRED_CC == "VS6" ]
+then
+ # Visual Studio 6 defines.
+ #
+ CYNET="${ROOT}/Program Files/Microsoft Visual Studio"
+ DOSNET="C:/Program Files/Microsoft Visual Studio"
+ PATH="$APPWEB_PATH:$CYNET/Common/MSDev98/bin:$CYNET/VC98/BIN:$CYNET/Common/IDE:$CYNET/Common/Tools/WinNT:$CYNET/Common/Tools:$PATH"
+ INCLUDE="$DOSNET/VC98/ATLMFC/INCLUDE;$DOSNET/VC98/INCLUDE;$DOSNET/VC98/MFC/INCLUDE;$INCLUDE"
+ LIB="$DOSNET/VC98/LIB;$DOSNET/VC98/MFC/LIB;$LIB"
+fi
+
+if [ $VXWORKS ]
+then
+ #
+ # Required by VxWorks
+ #
+ WIND_BASE=C:/tornado
+ WIND_HOST_TYPE=x86-win32
+ WIND_REGISTRY=coalsack
+ WIND_LMHOST=coalsack
+ BLD_VX_HOST=i386-wrs-vxworks
+ VX_TOOLS=`cygpath $WIND_BASE`/host/$WIND_HOST_TYPE
+ export WIND_BASE WIND_HOST_TYPE WIND_REGISTRY WIND_LMHOST BLD_VX_HOST
+
+ #
+ # Use cygwin make and tools by preference
+ #
+ PATH="$APPWEB_PATH:$VX_TOOLS/bin:$PATH"
+fi
+
+#
+# Make required directories for CYGWIN
+#
+if [ ! -x /bin/bash.exe ]
+then
+ DIR=`cygpath -w "$HOME/winTools"`
+ echo -e "\nCreating /bin"
+ echo Mounting \"${DIR}\" as /bin
+ mount -f -b "$DIR" /bin
+fi
+
+if [ ! -x /tmp ]
+then
+ mkdir -p tmp
+ DIR=`cygpath -w "$HOME/tmp"`
+ echo -e "\nCreating /tmp"
+ echo Mounting \"${DIR}\" as /tmp
+ mount -f -b "$DIR" /tmp
+fi
+echo
+
+################################################################################
+#
+# Do a bit of validation
+#
+type cl 2>/dev/null >/dev/null
+if [ $? -ne 0 ]
+then
+ echo "Can't find compiler: cl. Check WIN/bashrc settings for PATH"
+fi
+set -o vi
+
+################################################################################
diff --git a/source4/lib/appweb/ejs-2.0/.exrc b/source4/lib/appweb/ejs-2.0/.exrc
new file mode 100644
index 0000000000..dd37846529
--- /dev/null
+++ b/source4/lib/appweb/ejs-2.0/.exrc
@@ -0,0 +1 @@
+set ts=4 sw=4
diff --git a/source4/lib/appweb/ejs-2.0/.ignore b/source4/lib/appweb/ejs-2.0/.ignore
new file mode 100644
index 0000000000..866f06c6c1
--- /dev/null
+++ b/source4/lib/appweb/ejs-2.0/.ignore
@@ -0,0 +1,57 @@
+*.class
+*.dll
+*.exe
+*.exp
+*.jar
+*.lib
+*.lnk
+*.map
+*.new
+*.old
+*.pdb
+*.res
+*.sln
+*.suo
+*.sym
+*.tmp
+*.sav
+.ICEauthority
+.bash_history
+.changes
+.cvsignore
+.esd_auth
+.fonts.cache-1
+.viminfo
+make.dep
+thumbs.db
+vc70.pdb
+*.ncb
+*.opt
+*.idb
+*.pch
+*.dep
+*.aps
+all
+tmp
+make.vars
+sh.vars
+config.make
+config.h
+config.sh
+configure
+make.os
+.firstBuild
+.viminfo
+.ssh
+_viminfo
+buildConfig.h
+buildConfig.make
+buildConfig.sh
+.ccache
+appWeb.kdev*
+subversion
+.vimrc
+.subversion
+.ignore
+njs
+msvc
diff --git a/source4/lib/appweb/ejs-2.0/.loginrc b/source4/lib/appweb/ejs-2.0/.loginrc
new file mode 100644
index 0000000000..90b76a2ad0
--- /dev/null
+++ b/source4/lib/appweb/ejs-2.0/.loginrc
@@ -0,0 +1,218 @@
+#
+# .loginrc -- Michael's login shell startup script (used only for Windows)
+#
+# NOTE: this should not be distributed with releases.
+#
+# Copyright (c) Mbedthis Software, 2003-2005. All Rights Reserved.
+#
+HOME=`pwd`
+
+TERM=ansi
+CYROOT=/cygdrive/c
+JDK="/cygdrive/c/program files/java/jdk1.5.0_07/bin"
+H=$CYROOT
+R=usr/svn/appWeb/main
+CDPATH=".:${H}/usr/svn/appWeb:${H}/${R}/http:${H}/${R}/http/modules:${H}/${R}:${H}/usr/svn/appWeb/releases:${H}/usr/svn/packages:${H}/usr/svn/bling/player/trunk:${H}/usr/svn/bling/player/trunk/src:${H}/usr/svn/bling/player/trunk/appdir:${H}/usr/svn:${H}:${H}/usr/svn:${H}/usr"
+APPWEB_PATH="${H}/${R}/bin/DEBUG:${H}/${R}/bin/RELEASE:${H}/${R}/bin:${H}/usr/bin"
+PATH="${H}/usr/bin:/usr/local/bin:/usr/bin:/bin:/usr/X11R6/bin:$PATH:${H}/tcl/bin:${JDK}"
+
+CLASSPATH="c:/usr/svn/j/ggperf"
+PS1='`cygpath -m $PWD`> '
+SVN_EDITOR=C:/cygwin/bin/vim.exe
+
+umask 022
+
+export TERM CDPATH INCLUDE LIB LIBPATH PATH PS1 SVN_EDITOR MSCL CLASSPATH
+
+################################################################################
+#
+# Set the dev environment PATH and other critical environment variables
+#
+
+# export BLD_ALTERNATE_CONFIG=WIN/buildConfig
+
+#
+# Desired .NET Framework
+#
+# FRAMEWORK=v1.0.3705
+# FRAMEWORK=v1.1.4322
+FRAMEWORK=v2.0.50727
+
+#
+# Desired C Compiler
+#
+# MSCL=VS2005
+# MSCL=VS2003
+# MSCL=VS.NET
+MSCL=VS6
+VXWORKS=1
+
+echo "Using compiler: $MSCL, .NET framework: $FRAMEWORK"
+
+#
+# Setup for Visual Studio and SDK
+#
+if [ $MSCL == "VS2005" ]
+then
+ #
+ # Visual Studio .NET 2005 defines.
+ #
+ CYNET="$H/Program Files/Microsoft Visual Studio 8"
+ DOSNET="C:/Program Files/Microsoft Visual Studio 8"
+ PATH="$APPWEB_PATH:$CYNET/Common7/IDE:$CYNET/VC/BIN:$CYNET/VC/VCPackages:$CYNET/Common7/Tools:$CYNET/Common7/Tools/bin:$CYNET/SDK/v2.0/bin:$CYROOT/WINDOWS/Microsoft.NET/Framework/v2.0.40607:$CYNET/SDK/v2.0/bin:$PATH"
+ INCLUDE="$DOSNET/VC/ATLMFC/INCLUDE;$DOSNET/VC/INCLUDE;$DOSNET/VC/PlatformSDK/include;$DOSNET/SDK/v2.0/include;$INCLUDE"
+ LIB="$DOSNET/VC/ATLMFC/LIB;$DOSNET/VC/LIB;$DOSNET/VC/PlatformSDK/lib;$DOSNET/SDK/v2.0/lib;$LIB"
+ LIBPATH=c:/WINDOWS/Microsoft.NET/Framework/$FRAMEWORK
+
+ # MOB -- old
+ # PATH="$APPWEB_PATH:$CYNET/Common7/IDE:$CYNET/VC/BIN:$CYNET/Common7/Tools:$CYNET/Common7/Tools/bin/prerelease:$CYNET/Common7/Tools/bin:$CYNET/FrameworkSDK/bin:$H/WINDOWS/Microsoft.NET/Framework/$FRAMEWORK:$PATH"
+ # INCLUDE="$DOSNET/VC/ATLMFC/INCLUDE;$DOSNET/VC/INCLUDE;$DOSNET/VC/PlatformSDK/include/prerelease;$DOSNET/VC/PlatformSDK/include;$DOSNET/FrameworkSDK/include;$INCLUDE"
+ # LIB="$DOSNET/VC/ATLMFC/LIB;$DOSNET/VC/LIB;$DOSNET/VC/PlatformSDK/lib/prerelease;$DOSNET/VC/PlatformSDK/lib;$DOSNET/FrameworkSDK/lib;$LIB"
+fi
+
+if [ $MSCL == "VS2003" ]
+then
+ #
+ # Visual Studio .NET 2003 defines.
+ #
+ CYNET="$H/Program Files/Microsoft Visual Studio .NET 2003"
+ DOSNET="C:/Program Files/Microsoft Visual Studio .NET 2003"
+ PATH="$APPWEB_PATH:$CYNET/Common7/IDE:$CYNET/VC7/BIN:$CYNET/Common7/Tools:$CYNET/Common7/Tools/bin/prerelease:$CYNET/Common7/Tools/bin:$CYNET/FrameworkSDK/bin:$H/WINDOWS/Microsoft.NET/Framework/$FRAMEWORK:$CYNET/SDK/v1.1/bin:$PATH"
+ INCLUDE="$DOSNET/VC7/ATLMFC/INCLUDE;$DOSNET/VC7/INCLUDE;$DOSNET/VC7/PlatformSDK/include/prerelease;$DOSNET/VC7/PlatformSDK/include;$DOSNET/FrameworkSDK/include;$INCLUDE"
+ LIB="$DOSNET/VC7/ATLMFC/LIB;$DOSNET/VC7/LIB;$DOSNET/VC7/PlatformSDK/lib/prerelease;$DOSNET/VC7/PlatformSDK/lib;$DOSNET/FrameworkSDK/lib;$LIB"
+fi
+
+
+if [ $MSCL == "VS.NET" ]
+then
+ #
+ # Visual Studio .NET defines.
+ #
+ CYNET="$H/Program Files/Microsoft Visual Studio .NET"
+ DOSNET="C:/Program Files/Microsoft Visual Studio .NET"
+ PATH="$APPWEB_PATH:$CYNET/Common7/IDE:$CYNET/VC7/BIN:$CYNET/Common7/Tools:$CYNET/Common7/Tools/bin/prerelease:$CYNET/Common7/Tools/bin:$CYNET/FrameworkSDK/bin:$H/WINDOWS/Microsoft.NET/Framework/$FRAMEWORK:$CYNET/SDK/v1.0/bin:$PATH"
+ INCLUDE="$DOSNET/VC7/ATLMFC/INCLUDE;$DOSNET/VC7/INCLUDE;$DOSNET/VC7/PlatformSDK/include/prerelease;$DOSNET/VC7/PlatformSDK/include;$DOSNET/FrameworkSDK/include;$INCLUDE"
+ LIB="$DOSNET/VC7/ATLMFC/LIB;$DOSNET/VC7/LIB;$DOSNET/VC7/PlatformSDK/lib/prerelease;$DOSNET/VC7/PlatformSDK/lib;$DOSNET/FrameworkSDK/lib;$LIB"
+fi
+
+
+if [ $MSCL == "VS6" ]
+then
+ # Visual Studio 6 defines.
+ #
+ CYNET="$H/Program Files/Microsoft Visual Studio"
+ DOSNET="C:/Program Files/Microsoft Visual Studio"
+ PATH="$APPWEB_PATH:$CYNET/Common/MSDev98/bin:$CYNET/VC98/BIN:$CYNET/Common/IDE:$CYNET/Common/Tools/WinNT:$CYNET/Common/Tools:$PATH"
+ # OLD PATH="$APPWEB_PATH:$CYNET/Common/IDE:$CYNET/VC98/BIN:$CYNET/Common/MSDev98/bin:$CYNET/Common/Tools:$CYNET/Common/Tools/bin/prerelease:$CYNET/Common/Tools/bin:$CYNET/FrameworkSDK/bin:$H/WINDOWS/Microsoft.NET/Framework/$FRAMEWORK:$PATH"
+ INCLUDE="$DOSNET/VC98/ATLMFC/INCLUDE;$DOSNET/VC98/INCLUDE;$DOSNET/VC98/MFC/INCLUDE;$INCLUDE"
+ LIB="$DOSNET/VC98/LIB;$DOSNET/VC98/MFC/LIB;$LIB"
+fi
+
+if [ $VXWORKS ]
+then
+ #
+ # Required by VxWorks
+ #
+ WIND_BASE=C:/tornado
+ WIND_HOST_TYPE=x86-win32
+ WIND_REGISTRY=coalsack
+ WIND_LMHOST=coalsack
+ BLD_VX_HOST=i386-wrs-vxworks
+ export WIND_BASE WIND_HOST_TYPE WIND_REGISTRY WIND_LMHOST BLD_VX_HOST
+
+ VX_TOOLS=`cygpath $WIND_BASE`/host/$WIND_HOST_TYPE
+ #
+ # Use cygwin make and tools by preference
+ #
+ PATH="$APPWEB_PATH:$PATH:$VX_TOOLS/bin"
+fi
+
+#
+# Make required directories for CYGWIN
+#
+if [ ! -x /bin/bash.exe ]
+then
+ DIR=`cygpath -w "$HOME/winTools"`
+ echo -e "\nCreating /bin"
+ echo Mounting \"${DIR}\" as /bin
+ mount -f -b "$DIR" /bin
+fi
+
+if [ ! -x /tmp ]
+then
+ mkdir -p tmp
+ DIR=`cygpath -w "$HOME/tmp"`
+ echo -e "\nCreating /tmp"
+ echo Mounting \"${DIR}\" as /tmp
+ mount -f -b "$DIR" /tmp
+fi
+echo
+
+
+################################################################################
+#
+# Do a bit of validation (MOB -- extend)
+#
+type cl 2>/dev/null >/dev/null
+if [ $? -ne 0 ]
+then
+ echo "Can't find compiler: cl. Check WIN/bashrc settings for PATH"
+fi
+
+################################################################################
+#
+# Some convenient functions
+#
+pvi () {
+
+ pattern=$1
+ shift
+ files=$*
+ if [ -z "${files}" ]
+ then
+ files='*.c *.cpp *.h Makefile *.html *.aspx *.cs'
+ fi
+ vi -c "/${pattern}" $(grep -l "${pattern}" ${files})
+}
+
+################################################################################
+
+g() {
+ pattern=$1
+ shift
+ files=$*
+ if [ -z "${files}" ]
+ then
+ files=`echo *.c *.cpp *.h Makefile *.html *.aspx *.cs`
+ fi
+ eval grep "${pattern}" ${files}
+}
+
+################################################################################
+
+usedvi() {
+ pvi $1 $HOME/mr/*.c $HOME/mr/*.h $HOME/mr/WIN/*.c $HOME/lib/*/*.c
+}
+
+################################################################################
+
+alias ls='ls -CF $*'
+alias lc='ls -CF $*'
+alias lr='ls -R $*'
+alias xwin='startxwin.sh'
+alias htmlview='"C:/Program Files/Internet Explorer/iexplore.exe" $*'
+set -o vi
+
+if [ `uname -o` = "Cygwin" ]
+then
+ alias vim='"C:/Program Files/vim/vim64/vim.exe" $*'
+ alias gvim='"C:/Program Files/vim/vim64/gvim.exe" $*'
+fi
+
+brew() {
+ "C:/Program Files/BREW SDK v2.1.3/Bin/BREW_Emulator.exe"
+}
+
+js() {
+ cscript /nologo $*
+}
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
+ */
diff --git a/source4/lib/appweb/ejs-2.0/exml/Makefile b/source4/lib/appweb/ejs-2.0/exml/Makefile
new file mode 100644
index 0000000000..663e65ed53
--- /dev/null
+++ b/source4/lib/appweb/ejs-2.0/exml/Makefile
@@ -0,0 +1,42 @@
+#
+# Makefile for Embedded XML (EXML)
+#
+# Copyright (c) Mbedthis Software LLC, 2003-2006. All Rights Reserved.
+#
+
+#
+# EXML may be linked into shared handlers so we must build the objects both
+# shared and static.
+#
+COMPILE := *.c
+EXPORT_OBJECTS := yes
+MAKE_IFLAGS := -I../mpr
+
+include make.dep
+
+ifeq ($(BLD_FEATURE_TEST),1)
+POST_DIRS := test
+endif
+
+TARGETS += $(BLD_BIN_DIR)/libexml$(BLD_LIB)
+
+ifeq ($(BLD_FEATURE_XML),1)
+compileExtra: $(TARGETS)
+endif
+
+# MOB -- remove when FEATURE_XML is defined
+compileExtra: $(TARGETS)
+
+$(BLD_BIN_DIR)/libexml$(BLD_LIB): $(FILES)
+ @bld --library $(BLD_BIN_DIR)/libexml \
+ --objectsDir $(BLD_OBJ_DIR) --objectList files --libs mpr
+
+cleanExtra:
+ @echo "rm -f $(TARGETS)" | $(BLDOUT)
+ @rm -f $(TARGETS)
+ @rm -f $(BLD_BIN_DIR)/libexml.*
+
+## Local variables:
+## tab-width: 4
+## End:
+## vim: tw=78 sw=4 ts=4
diff --git a/source4/lib/appweb/ejs-2.0/exml/exml.h b/source4/lib/appweb/ejs-2.0/exml/exml.h
new file mode 100644
index 0000000000..44c50a56b9
--- /dev/null
+++ b/source4/lib/appweb/ejs-2.0/exml/exml.h
@@ -0,0 +1,94 @@
+/*
+ * exml.h -- Embedded Xml Parser header
+ *
+ * Copyright (c) Mbedthis Software, LLC, 2003-2003. All Rights Reserved. -- MOB
+ */
+
+#ifndef _h_EXML
+#define _h_EXML 1
+
+/******************************** Description *********************************/
+
+#include "mpr.h"
+
+/********************************** Defines ***********************************/
+
+#if BLD_FEATURE_SQUEEZE
+ #define EXML_BUFSIZE 512 /* Read buffer size */
+#else
+ #define EXML_BUFSIZE 1024 /* Read buffer size */
+#endif
+
+/*
+ * XML parser states. The states that are passed to the user handler have
+ * "U" appended to the comment. The error states (ERR and EOF) must be
+ * negative.
+ */
+#define EXML_ERR -1 /* Error */
+#define EXML_EOF -2 /* End of input */
+#define EXML_BEGIN 1 /* Before next tag */
+#define EXML_AFTER_LS 2 /* Seen "<" */
+#define EXML_COMMENT 3 /* Seen "<!--" (usr) U */
+#define EXML_NEW_ELT 4 /* Seen "<tag" (usr) U */
+#define EXML_ATT_NAME 5 /* Seen "<tag att" */
+#define EXML_ATT_EQ 6 /* Seen "<tag att" = */
+#define EXML_NEW_ATT 7 /* Seen "<tag att = "val" U */
+#define EXML_SOLO_ELT_DEFINED 8 /* Seen "<tag../>" U */
+#define EXML_ELT_DEFINED 9 /* Seen "<tag...>" U */
+#define EXML_ELT_DATA 10 /* Seen "<tag>....<" U */
+#define EXML_END_ELT 11 /* Seen "<tag>....</tag>" U */
+#define EXML_PI 12 /* Seen "<?processingInst" U */
+#define EXML_CDATA 13 /* Seen "<![CDATA[" U */
+
+/*
+ * Lex tokens
+ */
+typedef enum ExmlToken {
+ TOKEN_ERR,
+ TOKEN_TOO_BIG, /* Token is too big */
+ TOKEN_CDATA,
+ TOKEN_COMMENT,
+ TOKEN_INSTRUCTIONS,
+ TOKEN_LS, /* "<" -- Opening a tag */
+ TOKEN_LS_SLASH, /* "</" -- Closing a tag */
+ TOKEN_GR, /* ">" -- End of an open tag */
+ TOKEN_SLASH_GR, /* "/>" -- End of a solo tag */
+ TOKEN_TEXT,
+ TOKEN_EQ,
+ TOKEN_EOF,
+ TOKEN_SPACE,
+} ExmlToken;
+
+struct Exml;
+typedef int (*ExmlHandler)(struct Exml *xp, int state,
+ const char *tagName, const char* attName, const char* value);
+typedef int (*ExmlInputStream)(struct Exml *xp, void *arg, char *buf, int size);
+
+/*
+ * Per XML session structure
+ */
+typedef struct Exml {
+ ExmlHandler handler; /* Callback function */
+ ExmlInputStream readFn; /* Read data function */
+ MprBuf *inBuf; /* Input data queue */
+ MprBuf *tokBuf; /* Parsed token buffer */
+ int quoteChar; /* XdbAtt quote char */
+ int lineNumber; /* Current line no for debug */
+ void *parseArg; /* Arg passed to exmlParse() */
+ void *inputArg; /* Arg passed to exmlSetInputStream() */
+ char *errMsg; /* Error message text */
+} Exml;
+
+extern Exml *exmlOpen(MprCtx ctx, int initialSize, int maxSize);
+extern void exmlClose(Exml *xp);
+extern void exmlSetParserHandler(Exml *xp, ExmlHandler h);
+extern void exmlSetInputStream(Exml *xp, ExmlInputStream s, void *arg);
+extern int exmlParse(Exml *xp);
+extern void exmlSetParseArg(Exml *xp, void *parseArg);
+extern void *exmlGetParseArg(Exml *xp);
+extern const char *exmlGetErrorMsg(Exml *xp);
+extern int exmlGetLineNumber(Exml *xp);
+
+/******************************************************************************/
+
+#endif /* _h_EXML */
diff --git a/source4/lib/appweb/ejs-2.0/exml/exmlParser.c b/source4/lib/appweb/ejs-2.0/exml/exmlParser.c
new file mode 100644
index 0000000000..14871411a6
--- /dev/null
+++ b/source4/lib/appweb/ejs-2.0/exml/exmlParser.c
@@ -0,0 +1,752 @@
+/*
+ * exml.c -- A simple SAX style XML parser
+ */
+
+/********************************* Description ********************************/
+/*
+ * This is a recursive descent parser for XML text files. It is a one-pass
+ * simple parser that invokes a user supplied callback for key tokens in the
+ * XML file. The user supplies a read function so that XML files can be parsed
+ * from disk or in-memory.
+ */
+/********************************** Includes **********************************/
+
+#include "exml.h"
+
+/****************************** Forward Declarations **************************/
+/* MOB -- FIX */
+#if BLD_FEATURE_EXML || 1
+
+static int parseNext(Exml *xp, int state);
+static ExmlToken getToken(Exml *xp, int state);
+static int getNextChar(Exml *xp);
+static int scanFor(Exml *xp, char *str);
+static int putLastChar(Exml *xp, int c);
+static void error(Exml *xp, char *fmt, ...);
+static void trimToken(Exml *xp);
+
+/************************************ Code ************************************/
+
+Exml *exmlOpen(MprCtx ctx, int initialSize, int maxSize)
+{
+ Exml *xp;
+
+ xp = mprAllocTypeZeroed(ctx, Exml);
+
+ xp->inBuf = mprCreateBuf(xp, EXML_BUFSIZE, EXML_BUFSIZE);
+ xp->tokBuf = mprCreateBuf(xp, initialSize, maxSize);
+
+ return xp;
+}
+
+/******************************************************************************/
+
+void exmlClose(Exml *xp)
+{
+ mprAssert(xp);
+
+ mprFree(xp);
+}
+
+/******************************************************************************/
+
+void exmlSetParserHandler(Exml *xp, ExmlHandler h)
+{
+ mprAssert(xp);
+
+ xp->handler = h;
+}
+
+/******************************************************************************/
+
+void exmlSetInputStream(Exml *xp, ExmlInputStream s, void *arg)
+{
+ mprAssert(xp);
+
+ xp->readFn = s;
+ xp->inputArg = arg;
+}
+
+/******************************************************************************/
+/*
+ * Set the parse arg
+ */
+
+void exmlSetParseArg(Exml *xp, void *parseArg)
+{
+ mprAssert(xp);
+
+ xp->parseArg = parseArg;
+}
+
+/******************************************************************************/
+/*
+ * Set the parse arg
+ */
+
+void *exmlGetParseArg(Exml *xp)
+{
+ mprAssert(xp);
+
+ return xp->parseArg;
+}
+
+/******************************************************************************/
+/*
+ * Parse an XML file. Return 0 for success, -1 for error.
+ */
+
+int exmlParse(Exml *xp)
+{
+ mprAssert(xp);
+
+ return parseNext(xp, EXML_BEGIN);
+}
+
+/******************************************************************************/
+/*
+ * XML parser. This is a recursive descent parser. Return -1 for errors, 0 for
+ * EOF and 1 if there is still more data to parse.
+ */
+
+static int parseNext(Exml *xp, int state)
+{
+ ExmlHandler handler;
+ ExmlToken token;
+ MprBuf *tokBuf;
+ char *tname, *aname;
+ int rc;
+
+ mprAssert(state >= 0);
+
+ tokBuf = xp->tokBuf;
+ handler = xp->handler;
+ tname = aname = 0;
+ rc = 0;
+
+ /*
+ * In this parse loop, the state is never assigned EOF or ERR. In
+ * such cases we always return EOF or ERR.
+ */
+ while (1) {
+
+ token = getToken(xp, state);
+
+ if (token == TOKEN_TOO_BIG) {
+ error(xp, "XML token is too big");
+ goto err;
+ }
+
+ switch (state) {
+ case EXML_BEGIN: /* ------------------------------------------ */
+ /*
+ * Expect to get an element, comment or processing instruction
+ */
+ switch (token) {
+ case TOKEN_EOF:
+ goto exit;
+
+ case TOKEN_LS:
+ /*
+ * Recurse to handle the new element, comment etc.
+ */
+ rc = parseNext(xp, EXML_AFTER_LS);
+ if (rc < 0) {
+ goto exit;
+ }
+ break;
+
+ default:
+ error(xp, "Syntax error");
+ goto err;
+ }
+ break;
+
+ case EXML_AFTER_LS: /* ------------------------------------------ */
+ switch (token) {
+ case TOKEN_COMMENT:
+ state = EXML_COMMENT;
+ rc = (*handler)(xp, state, "!--", 0, mprGetBufStart(tokBuf));
+ if (rc < 0) {
+ goto err;
+ }
+ rc = 1;
+ goto exit;
+
+ case TOKEN_CDATA:
+ state = EXML_CDATA;
+ rc = (*handler)(xp, state, "!--", 0, mprGetBufStart(tokBuf));
+ if (rc < 0) {
+ goto err;
+ }
+ rc = 1;
+ goto exit;
+
+ case TOKEN_INSTRUCTIONS:
+ /* Just ignore processing instructions */
+ rc = 1;
+ goto exit;
+
+ case TOKEN_TEXT:
+ state = EXML_NEW_ELT;
+ tname = mprStrdup(xp, mprGetBufStart(tokBuf));
+ if (tname == 0) {
+ rc = MPR_ERR_MEMORY;
+ goto exit;
+ }
+ rc = (*handler)(xp, state, tname, 0, 0);
+ if (rc < 0) {
+ goto err;
+ }
+ break;
+
+ default:
+ error(xp, "Syntax error");
+ goto err;
+ }
+ break;
+
+ case EXML_NEW_ELT: /* ------------------------------------------ */
+ /*
+ * We have seen the opening "<element" for a new element and have
+ * not yet seen the terminating ">" of the opening element.
+ */
+ switch (token) {
+ case TOKEN_TEXT:
+ /*
+ * Must be an attribute name
+ */
+ aname = mprStrdup(xp, mprGetBufStart(tokBuf));
+ token = getToken(xp, state);
+ if (token != TOKEN_EQ) {
+ error(xp, "Missing assignment for attribute \"%s\"", aname);
+ goto err;
+ }
+
+ token = getToken(xp, state);
+ if (token != TOKEN_TEXT) {
+ error(xp, "Missing value for attribute \"%s\"", aname);
+ goto err;
+ }
+ state = EXML_NEW_ATT;
+ rc = (*handler)(xp, state, tname, aname,
+ mprGetBufStart(tokBuf));
+ if (rc < 0) {
+ goto err;
+ }
+ state = EXML_NEW_ELT;
+ break;
+
+ case TOKEN_GR:
+ /*
+ * This is ">" the termination of the opening element
+ */
+ if (*tname == '\0') {
+ error(xp, "Missing element name");
+ goto err;
+ }
+
+ /*
+ * Tell the user that the opening element is now complete
+ */
+ state = EXML_ELT_DEFINED;
+ rc = (*handler)(xp, state, tname, 0, 0);
+ if (rc < 0) {
+ goto err;
+ }
+ state = EXML_ELT_DATA;
+ break;
+
+ case TOKEN_SLASH_GR:
+ /*
+ * If we see a "/>" then this is a solo element
+ */
+ if (*tname == '\0') {
+ error(xp, "Missing element name");
+ goto err;
+ }
+ state = EXML_SOLO_ELT_DEFINED;
+ rc = (*handler)(xp, state, tname, 0, 0);
+ if (rc < 0) {
+ goto err;
+ }
+ rc = 1;
+ goto exit;
+
+ default:
+ error(xp, "Syntax error");
+ goto err;
+ }
+ break;
+
+ case EXML_ELT_DATA: /* -------------------------------------- */
+ /*
+ * We have seen the full opening element "<name ...>" and now
+ * await data or another element.
+ */
+ if (token == TOKEN_LS) {
+ /*
+ * Recurse to handle the new element, comment etc.
+ */
+ rc = parseNext(xp, EXML_AFTER_LS);
+ if (rc < 0) {
+ goto exit;
+ }
+ break;
+
+ } else if (token == TOKEN_LS_SLASH) {
+ state = EXML_END_ELT;
+ break;
+
+ } else if (token != TOKEN_TEXT) {
+ goto err;
+ }
+ if (mprGetBufLength(tokBuf) > 0) {
+ /*
+ * Pass the data between the element to the user
+ */
+ rc = (*handler)(xp, state, tname, 0, mprGetBufStart(tokBuf));
+ if (rc < 0) {
+ goto err;
+ }
+ }
+ break;
+
+ case EXML_END_ELT: /* -------------------------------------- */
+ if (token != TOKEN_TEXT) {
+ error(xp, "Missing closing element name for \"%s\"", tname);
+ goto err;
+ }
+ /*
+ * The closing element name must match the opening element name
+ */
+ if (strcmp(tname, mprGetBufStart(tokBuf)) != 0) {
+ error(xp,
+ "Closing element name \"%s\" does not match on line %d"
+ "opening name \"%s\"",
+ mprGetBufStart(tokBuf), xp->lineNumber, tname);
+ goto err;
+ }
+ rc = (*handler)(xp, state, tname, 0, 0);
+ if (rc < 0) {
+ goto err;
+ }
+ if (getToken(xp, state) != TOKEN_GR) {
+ error(xp, "Syntax error");
+ goto err;
+ }
+ return 1;
+
+ case EXML_EOF: /* ---------------------------------------------- */
+ goto exit;
+
+ case EXML_ERR: /* ---------------------------------------------- */
+ default:
+ goto err;
+ }
+ }
+ mprAssert(0);
+
+err:
+ rc = -1;
+
+exit:
+ mprFree(tname);
+ mprFree(aname);
+
+ return rc;
+}
+
+/******************************************************************************/
+/*
+ * Lexical analyser for XML. Return the next token reading input as required.
+ * It uses a one token look ahead and push back mechanism (LAR1 parser).
+ * Text token identifiers are left in the tokBuf parser buffer on exit.
+ * This Lex has special cases for the states EXML_ELT_DATA where we
+ * have an optimized read of element data, and EXML_AFTER_LS where we
+ * distinguish between element names, processing instructions and comments.
+ */
+
+static ExmlToken getToken(Exml *xp, int state)
+{
+ MprBuf *tokBuf, *inBuf;
+ uchar *cp;
+ int c, rc;
+
+ tokBuf = xp->tokBuf;
+ inBuf = xp->inBuf;
+
+ mprAssert(state >= 0);
+
+ if ((c = getNextChar(xp)) < 0) {
+ return TOKEN_EOF;
+ }
+ mprFlushBuf(tokBuf);
+
+ /*
+ * Special case parsing for names and for element data. We do this for
+ * performance so we can return to the caller the largest token possible
+ */
+ if (state == EXML_ELT_DATA) {
+ /*
+ * Read all the data up to the start of the closing element "<" or the
+ * start of a sub-element.
+ */
+#if UNUSED
+ while (isspace(c)) {
+ if ((c = getNextChar(xp)) < 0) {
+ return TOKEN_EOF;
+ }
+ }
+#endif
+ if (c == '<') {
+ if ((c = getNextChar(xp)) < 0) {
+ return TOKEN_EOF;
+ }
+ if (c == '/') {
+ return TOKEN_LS_SLASH;
+ }
+ putLastChar(xp, c);
+ return TOKEN_LS;
+ }
+ do {
+ if (mprPutCharToBuf(tokBuf, c) < 0) {
+ return TOKEN_TOO_BIG;
+ }
+ if ((c = getNextChar(xp)) < 0) {
+ return TOKEN_EOF;
+ }
+ } while (c != '<');
+
+ /*
+ * Put back the last look-ahead character
+ */
+ putLastChar(xp, c);
+
+ /*
+ * If all white space, then zero the token buffer
+ */
+ for (cp = tokBuf->start; *cp; cp++) {
+ if (!isspace(*cp)) {
+ return TOKEN_TEXT;
+ }
+ }
+ mprFlushBuf(tokBuf);
+ return TOKEN_TEXT;
+ }
+
+ while (1) {
+ switch (c) {
+ case ' ':
+ case '\n':
+ case '\t':
+ case '\r':
+ break;
+
+ case '<':
+ if ((c = getNextChar(xp)) < 0) {
+ return TOKEN_EOF;
+ }
+ if (c == '/') {
+ return TOKEN_LS_SLASH;
+ }
+ putLastChar(xp, c);
+ return TOKEN_LS;
+
+ case '=':
+ return TOKEN_EQ;
+
+ case '>':
+ return TOKEN_GR;
+
+ case '/':
+ if ((c = getNextChar(xp)) < 0) {
+ return TOKEN_EOF;
+ }
+ if (c == '>') {
+ return TOKEN_SLASH_GR;
+ }
+ return TOKEN_ERR;
+
+ case '\"':
+ case '\'':
+ xp->quoteChar = c;
+ /* Fall through */
+
+ default:
+ /*
+ * We handle element names, attribute names and attribute values
+ * here. We do NOT handle data between elements here. Read the
+ * token. Stop on white space or a closing element ">"
+ */
+ if (xp->quoteChar) {
+ if ((c = getNextChar(xp)) < 0) {
+ return TOKEN_EOF;
+ }
+ while (c != xp->quoteChar) {
+ if (mprPutCharToBuf(tokBuf, c) < 0) {
+ return TOKEN_TOO_BIG;
+ }
+ if ((c = getNextChar(xp)) < 0) {
+ return TOKEN_EOF;
+ }
+ }
+ xp->quoteChar = 0;
+
+ } else {
+ while (!isspace(c) && c != '>' && c != '/' && c != '=') {
+ if (mprPutCharToBuf(tokBuf, c) < 0) {
+ return TOKEN_TOO_BIG;
+ }
+ if ((c = getNextChar(xp)) < 0) {
+ return TOKEN_EOF;
+ }
+ }
+ putLastChar(xp, c);
+ }
+ if (mprGetBufLength(tokBuf) <= 0) {
+ return TOKEN_ERR;
+ }
+ mprAddNullToBuf(tokBuf);
+
+ if (state == EXML_AFTER_LS) {
+ /*
+ * If we are just inside an element "<", then analyze what we
+ * have to see if we have an element name, instruction or
+ * comment. Tokbuf will hold "?" for instructions or "!--"
+ * for comments.
+ */
+ if (mprLookAtNextCharInBuf(tokBuf) == '?') {
+ /* Just ignore processing instructions */
+ rc = scanFor(xp, "?>");
+ if (rc < 0) {
+ return TOKEN_TOO_BIG;
+ } else if (rc == 0) {
+ return TOKEN_ERR;
+ }
+ return TOKEN_INSTRUCTIONS;
+
+ } else if (mprLookAtNextCharInBuf(tokBuf) == '!') {
+ /*
+ * First discard the comment leadin "!--" and eat leading
+ * white space.
+ */
+ if (strcmp((char*) tokBuf->start, "![CDATA[") == 0) {
+ mprFlushBuf(tokBuf);
+#if UNUSED
+ c = mprLookAtNextCharInBuf(inBuf);
+ while (isspace(c)) {
+ if ((c = getNextChar(xp)) < 0) {
+ return TOKEN_EOF;
+ }
+ c = mprLookAtNextCharInBuf(inBuf);
+ }
+#endif
+ rc = scanFor(xp, "]]>");
+ if (rc < 0) {
+ return TOKEN_TOO_BIG;
+ } else if (rc == 0) {
+ return TOKEN_ERR;
+ }
+ return TOKEN_CDATA;
+
+ } else {
+ mprFlushBuf(tokBuf);
+#if UNUSED
+ c = mprLookAtNextCharInBuf(inBuf);
+ while (isspace(c)) {
+ if ((c = getNextChar(xp)) < 0) {
+ return TOKEN_EOF;
+ }
+ c = mprLookAtNextCharInBuf(inBuf);
+ }
+#endif
+ rc = scanFor(xp, "-->");
+ if (rc < 0) {
+ return TOKEN_TOO_BIG;
+ } else if (rc == 0) {
+ return TOKEN_ERR;
+ }
+ return TOKEN_COMMENT;
+ }
+ }
+ }
+ trimToken(xp);
+ return TOKEN_TEXT;
+ }
+ if ((c = getNextChar(xp)) < 0) {
+ return TOKEN_EOF;
+ }
+ }
+
+ /* Should never get here */
+ mprAssert(0);
+ return TOKEN_ERR;
+}
+
+/******************************************************************************/
+/*
+ * Scan for a pattern. Eat and discard input up to the pattern. Return 1 if
+ * the pattern was found, return 0 if not found. Return < 0 on errors.
+ */
+
+static int scanFor(Exml *xp, char *str)
+{
+ MprBuf *tokBuf;
+ char *cp;
+ int c;
+
+ mprAssert(str);
+
+ tokBuf = xp->tokBuf;
+
+ while (1) {
+ for (cp = str; *cp; cp++) {
+ if ((c = getNextChar(xp)) < 0) {
+ return 0;
+ }
+ if (tokBuf) {
+ if (mprPutCharToBuf(tokBuf, c) < 0) {
+ return -1;
+ }
+ }
+ if (c != *cp) {
+ break;
+ }
+ }
+ if (*cp == '\0') {
+ /*
+ * Remove the pattern from the tokBuf
+ */
+ if (tokBuf) {
+ mprAdjustBufEnd(tokBuf, -(int) strlen(str));
+ trimToken(xp);
+ }
+ return 1;
+ }
+ }
+}
+
+/******************************************************************************/
+/*
+ * Get another character. We read and buffer blocks of data if we need more
+ * data to parse.
+ */
+
+static int getNextChar(Exml *xp)
+{
+ MprBuf *inBuf;
+ char c;
+ int l;
+
+ inBuf = xp->inBuf;
+ if (mprGetBufLength(inBuf) <= 0) {
+ /*
+ * Flush to reset the servp/endp pointers to the start of the buffer
+ * so we can do a maximal read
+ */
+ mprFlushBuf(inBuf);
+ l = (xp->readFn)(xp, xp->inputArg, mprGetBufStart(inBuf),
+ mprGetBufLinearSpace(inBuf));
+ if (l <= 0) {
+ return -1;
+ }
+ mprAdjustBufEnd(inBuf, l);
+ }
+ c = mprGetCharFromBuf(inBuf);
+
+ if (c == '\n') {
+ xp->lineNumber++;
+ }
+ return c;
+}
+
+/******************************************************************************/
+/*
+ * Put back a character in the input buffer
+ */
+
+static int putLastChar(Exml *xp, int c)
+{
+ if (mprInsertCharToBuf(xp->inBuf, (char) c) < 0) {
+ mprAssert(0);
+ return -1;
+ }
+ if (c == '\n') {
+ xp->lineNumber--;
+ }
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * Output a parse message
+ */
+
+static void error(Exml *xp, char *fmt, ...)
+{
+ va_list args;
+ char *buf;
+
+ mprAssert(fmt);
+
+ va_start(args, fmt);
+ mprAllocVsprintf(MPR_LOC_ARGS(xp), &buf, MPR_MAX_STRING, fmt, args);
+ va_end(args);
+
+ /*
+ * MOB need to add the failing line text and a pointer to which column
+ */
+ mprFree(xp->errMsg);
+ mprAllocSprintf(MPR_LOC_ARGS(xp), &xp->errMsg, MPR_MAX_STRING,
+ "XML error: %s\nAt line %d\n", buf, xp->lineNumber);
+
+ mprFree(buf);
+}
+
+/******************************************************************************/
+/*
+ * Remove trailing whitespace in a token and ensure it is terminated with
+ * a NULL for easy parsing
+ */
+
+static void trimToken(Exml *xp)
+{
+ while (isspace(mprLookAtLastCharInBuf(xp->tokBuf))) {
+ mprAdjustBufEnd(xp->tokBuf, -1);
+ }
+ mprAddNullToBuf(xp->tokBuf);
+}
+
+/******************************************************************************/
+
+const char *exmlGetErrorMsg(Exml *xp)
+{
+ if (xp->errMsg == 0) {
+ return "";
+ }
+ return xp->errMsg;
+}
+
+/******************************************************************************/
+
+int exmlGetLineNumber(Exml *xp)
+{
+ return xp->lineNumber;
+}
+
+/******************************************************************************/
+#else
+
+void exmlParserDummy() {}
+#endif /* BLD_FEATURE_EXML */
+
+/*
+ * 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/exml/files b/source4/lib/appweb/ejs-2.0/exml/files
new file mode 100644
index 0000000000..0f10ea44dd
--- /dev/null
+++ b/source4/lib/appweb/ejs-2.0/exml/files
@@ -0,0 +1 @@
+${BLD_OBJ_DIR}/exmlParser${BLD_OBJ}
diff --git a/source4/lib/appweb/ejs-2.0/mpr/Makefile b/source4/lib/appweb/ejs-2.0/mpr/Makefile
new file mode 100644
index 0000000000..6dd0e45d9e
--- /dev/null
+++ b/source4/lib/appweb/ejs-2.0/mpr/Makefile
@@ -0,0 +1,41 @@
+#
+# Makefile for the Mbedthis Portable Runtime (MPR) library
+#
+# Copyright (c) Mbedthis Software LLC, 2003-2006. All Rights Reserved.
+#
+
+COMPILE := *.c
+EXPORT_OBJECTS := yes
+
+include make.dep
+
+ifeq ($(BLD_HOST_UNIX),1)
+PRE_DIRS = UNIX
+else
+PRE_DIRS = $(BLD_HOST_OS)
+endif
+
+POST_DIRS = package
+
+TARGETS += $(BLD_BIN_DIR)/libmpr$(BLD_LIB)
+
+compileExtra: $(TARGETS)
+
+#
+# Build the mpr libraries
+#
+$(BLD_BIN_DIR)/libmpr$(BLD_LIB): files \
+ $(shell BLD_OBJ=$(BLD_OBJ) \; BLD_OBJ_DIR=$(BLD_OBJ_DIR) \; \
+ eval echo `cat files`)
+ @bld --library $(BLD_BIN_DIR)/libmpr \
+ --objectsDir $(BLD_OBJ_DIR) --objectList files
+
+cleanExtra:
+ @echo "rm -f $(TARGETS)" | $(BLDOUT)
+ @rm -f $(TARGETS)
+ @rm -f $(BLD_BIN_DIR)/libmpr.*
+
+## Local variables:
+## tab-width: 4
+## End:
+## vim: tw=78 sw=4 ts=4
diff --git a/source4/lib/appweb/ejs-2.0/mpr/UNIX/Makefile b/source4/lib/appweb/ejs-2.0/mpr/UNIX/Makefile
new file mode 100644
index 0000000000..5259b1e3a0
--- /dev/null
+++ b/source4/lib/appweb/ejs-2.0/mpr/UNIX/Makefile
@@ -0,0 +1,16 @@
+#
+# Makefile for the Mbedthis Portable Runtime (MPR) library for UNIX
+#
+# Copyright (c) Mbedthis Software LLC, 2003-2006. All Rights Reserved.
+#
+
+COMPILE := *.c
+EXPORT_OBJECTS := yes
+MAKE_IFLAGS := -I..
+
+include make.dep
+
+## Local variables:
+## tab-width: 4
+## End:
+## vim: tw=78 sw=4 ts=4
diff --git a/source4/lib/appweb/ejs-2.0/mpr/UNIX/mprFile.c b/source4/lib/appweb/ejs-2.0/mpr/UNIX/mprFile.c
new file mode 100644
index 0000000000..f647f1ed56
--- /dev/null
+++ b/source4/lib/appweb/ejs-2.0/mpr/UNIX/mprFile.c
@@ -0,0 +1,86 @@
+/**
+ * @file mprFile.c
+ * @brief File services for Unix
+ * @overview
+ * @remarks
+ * See mprGenFile.c for other file services.
+ */
+
+/******************************************************************************/
+/*
+ * @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 "mpr.h"
+
+/************************************ Code ************************************/
+
+int mprGetFileInfo(MprCtx ctx, const char *path, MprFileInfo *info)
+{
+ struct stat s;
+
+ mprAssert(path);
+ mprAssert(info);
+
+ if (stat(path, &s) < 0) {
+ return -1;
+ }
+
+ info->size = s.st_size;
+ info->ctime = s.st_ctime;
+ info->mtime = s.st_mtime;
+ info->inode = s.st_ino;
+ info->isDir = (s.st_mode & S_IFDIR) != 0;
+ info->isReg = (s.st_mode & S_IFREG) != 0;
+
+ if (strcmp(path, "/dev/null") == 0) {
+ info->isReg = 0;
+ }
+
+ return 0;
+}
+
+/******************************************************************************/
+
+int mprMakeDir(MprCtx ctx, const char *path, int perms)
+{
+ return mkdir(path, perms);
+}
+
+/******************************************************************************/
+/*
+ * 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/mpr/UNIX/mprPlatform.c b/source4/lib/appweb/ejs-2.0/mpr/UNIX/mprPlatform.c
new file mode 100644
index 0000000000..2c7fbf8a00
--- /dev/null
+++ b/source4/lib/appweb/ejs-2.0/mpr/UNIX/mprPlatform.c
@@ -0,0 +1,218 @@
+/**
+ * @file mprPlatform.c
+ * @brief Cross platform routines
+ * @overview This module provides low level cross platform routines.
+ * @remarks Most routines in this file are not thread-safe. It is the callers
+ * responsibility to perform all thread synchronization.
+ */
+
+/*
+ * @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 **********************************/
+/*
+ * We need to use the underlying str(cpy) routines to implement our safe
+ * alternatives
+ */
+#if !DOXYGEN
+#define UNSAFE_FUNCTIONS_OK 1
+#endif
+
+#include "mpr.h"
+
+/************************************ Code ************************************/
+
+char *mprInetToStr(char *buffer, int bufsize, const struct in_addr in)
+{
+#if HAVE_NTOA_R
+ inet_ntoa_r(in, buffer, bufsize);
+#else
+ uchar *cp;
+ /* FUTURE -- this is not portable */
+ cp = (uchar*) &in;
+ mprSprintf(buffer, bufsize, "%d.%d.%d.%d", cp[0], cp[1], cp[2], cp[3]);
+#endif
+ return buffer;
+}
+
+/******************************************************************************/
+
+void mprSetShell(MprCtx ctx, void *shell)
+{
+}
+
+/******************************************************************************/
+
+void *mprGetShell(MprCtx ctx)
+{
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * Sleep. Period given in milliseconds.
+ */
+
+void mprSleep(MprCtx ctx, int milliseconds)
+{
+ struct timespec timeout;
+ int rc;
+
+ mprAssert(milliseconds >= 0);
+ timeout.tv_sec = milliseconds / 1000;
+ timeout.tv_nsec = (milliseconds % 1000) * 1000000;
+ do {
+ rc = nanosleep(&timeout, 0);
+ } while (rc < 0 && errno == EINTR);
+}
+
+/******************************************************************************/
+/*
+ * Make intervening directories
+ */
+
+int mprMakeDirPath(MprCtx ctx, const char *path)
+{
+ char dir[MPR_MAX_PATH], buf[MPR_MAX_PATH];
+ char *dirSep;
+ char *next, *tok;
+
+ dir[0] = '\0';
+ dirSep = "/\\";
+
+ if (path == 0 || *path == '\0') {
+ return MPR_ERR_BAD_ARGS;
+ }
+
+ mprStrcpy(buf, sizeof(buf), path);
+ next = mprStrTok(buf, dirSep, &tok);
+ if (*buf == '/') {
+ dir[0] = '/';
+ }
+ while (next != NULL) {
+ if (strcmp(next, ".") == 0 ) {
+ next = mprStrTok(NULL, dirSep, &tok);
+ continue;
+ }
+ strcat(dir, next);
+ if (access(dir, R_OK) != 0) {
+ if (mkdir(dir, 0666) < 0) {
+ return MPR_ERR_CANT_CREATE;
+ }
+ }
+ strcat(dir, "/");
+ next = mprStrTok(NULL, dirSep, &tok);
+ }
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * Get a fully qualified file name for the given path. Return with forward
+ * slashes always
+ */
+
+char *mprGetFullPathName(char *buf, int buflen, const char *path)
+{
+ if (mprStrcpy(buf, buflen, path) < 0) {
+ mprAssert(0);
+ return 0;
+ }
+ return buf;
+}
+
+/******************************************************************************/
+/*
+ * Replacement for gethostbyname that is multi-thread safe
+ */
+
+struct hostent *mprGetHostByName(MprCtx ctx, const char *name)
+{
+ MprApp *app;
+ struct hostent *hp;
+ struct hostent *ip;
+ int count, i;
+
+ hp = (struct hostent*) mprAlloc(ctx, sizeof(struct hostent));
+ memset(hp, 0, sizeof(struct hostent));
+
+ app = mprGetApp(ctx);
+
+ #undef gethostbyname
+
+ mprGlobalLock(app);
+ ip = gethostbyname(name);
+ mprGlobalUnlock(app);
+
+ if (ip == 0) {
+ return 0;
+ }
+ hp->h_addrtype = ip->h_addrtype;
+ hp->h_length = ip->h_length;
+ hp->h_name = mprStrdup(hp, ip->h_name);
+ hp->h_addr_list = 0;
+ hp->h_aliases = 0;
+
+ for (count = 0; ip->h_addr_list[count] != 0; ) {
+ count++;
+ }
+ if (count > 0) {
+ count++;
+ hp->h_addr_list = mprAlloc(hp, count * sizeof(char*));
+ for (i = 0; ip->h_addr_list[i] != 0; i++) {
+ memcpy(&hp->h_addr_list[i], &ip->h_addr_list[i], ip->h_length);
+ }
+ hp->h_addr_list[i] = 0;
+ }
+
+ for (count = 0; ip->h_aliases[count] != 0; ) {
+ count++;
+ }
+ if (count > 0) {
+ count++;
+ hp->h_aliases = mprAlloc(hp, count * sizeof(char*));
+ for (i = 0; ip->h_aliases[i] != 0; i++) {
+ hp->h_aliases[i] = mprStrdup(hp, ip->h_aliases[i]);
+ }
+ hp->h_aliases[i] = 0;
+ }
+ return hp;
+}
+
+/******************************************************************************/
+
+/*
+ * 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/mpr/UNIX/mprTime.c b/source4/lib/appweb/ejs-2.0/mpr/UNIX/mprTime.c
new file mode 100644
index 0000000000..0153c0622d
--- /dev/null
+++ b/source4/lib/appweb/ejs-2.0/mpr/UNIX/mprTime.c
@@ -0,0 +1,163 @@
+/**
+ * @file mprTime.c
+ * @brief Time handling for Unix
+ * @overview
+ */
+
+/*
+ * @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 "mpr.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#undef localtime
+#undef localtime_r
+#undef gmtime
+#undef gmtime_r
+#undef ctime
+#undef ctime_r
+#undef asctime
+#undef asctime_r
+
+/******************************************************************************/
+/*
+ * Returns time in seconds and milliseconds. This is NOT time-of-day.
+ */
+
+MprTime *mprGetTime(MprCtx ctx, MprTime *tp)
+{
+ struct timeval tv;
+
+ if (gettimeofday(&tv, 0) < 0) {
+ mprAssert(0);
+ tp->sec = 0;
+ tp->msec = 0;
+ return tp;
+ }
+ tp->sec = tv.tv_sec;
+ tp->msec = tv.tv_usec / 1000;
+ return tp;
+}
+
+/******************************************************************************/
+/*
+ * Thread-safe wrapping of localtime
+ */
+
+struct tm *mprLocaltime(MprCtx ctx, struct tm *timep, time_t *now)
+{
+ localtime_r(now, timep);
+
+ return timep;
+}
+
+/******************************************************************************/
+/*
+ * Thread-safe wrapping of gmtime
+ */
+
+struct tm *mprGmtime(MprCtx ctx, time_t *now, struct tm *timep)
+{
+ gmtime_r(now, timep);
+
+ return timep;
+}
+
+/******************************************************************************/
+/*
+ * Thread-safe wrapping of ctime
+ */
+
+int mprCtime(MprCtx ctx, char *buf, int bufsize, const time_t *timer)
+{
+ char localBuf[80];
+ char *cp;
+ int len;
+
+ mprAssert(buf);
+
+ mprGlobalLock(ctx);
+
+ cp = ctime_r(timer, localBuf);
+ if ((int) strlen(cp) >= bufsize) {
+ mprStrcpy(buf, bufsize, "WONT FIT");
+ mprAssert(0);
+ return MPR_ERR_WONT_FIT;
+ }
+ len = mprStrcpy(buf, bufsize, cp);
+
+ if (buf[len - 1] == '\n') {
+ buf[len - 1] = '\0';
+ }
+
+ mprGlobalUnlock(ctx);
+
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * Thread-safe wrapping of asctime
+ */
+
+int mprAsctime(MprCtx ctx, char *buf, int bufsize, const struct tm *timeptr)
+{
+ char *cp;
+ char localBuf[80];
+
+ cp = asctime_r(timeptr, localBuf);
+ if ((int) strlen(cp) >= bufsize) {
+ mprAssert(0);
+ return MPR_ERR_WONT_FIT;
+ }
+ mprStrcpy(buf, bufsize, cp);
+
+ return strlen(buf);
+}
+
+/******************************************************************************/
+
+#ifdef __cplusplus
+}
+#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/mpr/VXWORKS/Makefile b/source4/lib/appweb/ejs-2.0/mpr/VXWORKS/Makefile
new file mode 100644
index 0000000000..f3a2394b6e
--- /dev/null
+++ b/source4/lib/appweb/ejs-2.0/mpr/VXWORKS/Makefile
@@ -0,0 +1,16 @@
+#
+# Makefile for the Mbedthis Portable Runtime (MPR) library for VXWORKS
+#
+# Copyright (c) Mbedthis Software LLC, 2003-2006. All Rights Reserved.
+#
+
+COMPILE := *.c
+EXPORT_OBJECTS := yes
+MAKE_IFLAGS := -I..
+
+include make.dep
+
+## Local variables:
+## tab-width: 4
+## End:
+## vim: tw=78 sw=4 ts=4
diff --git a/source4/lib/appweb/ejs-2.0/mpr/VXWORKS/mprFile.c b/source4/lib/appweb/ejs-2.0/mpr/VXWORKS/mprFile.c
new file mode 100644
index 0000000000..ae0b523faa
--- /dev/null
+++ b/source4/lib/appweb/ejs-2.0/mpr/VXWORKS/mprFile.c
@@ -0,0 +1,85 @@
+/**
+ * @file mprUnixFile.c
+ * @brief File services for Unix
+ * @overview
+ * @remarks
+ */
+
+/******************************************************************************/
+/*
+ * @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 "mpr.h"
+
+/************************************ Code ************************************/
+
+int mprGetFileInfo(MprCtx ctx, const char *path, MprFileInfo *info)
+{
+ struct stat s;
+
+ mprAssert(path);
+ mprAssert(info);
+
+ if (stat(path, &s) < 0) {
+ return -1;
+ }
+
+ info->size = s.st_size;
+ info->ctime = s.st_ctime;
+ info->mtime = s.st_mtime;
+ info->inode = s.st_ino;
+ info->isDir = (s.st_mode & S_IFDIR) != 0;
+ info->isReg = (s.st_mode & S_IFREG) != 0;
+
+ if (strcmp(path, "/dev/null") == 0) {
+ info->isReg = 0;
+ }
+
+ return 0;
+}
+
+/******************************************************************************/
+
+int mprMakeDir(MprCtx ctx, const char *path, int perms)
+{
+ return mkdir(path, perms);
+}
+
+/******************************************************************************/
+/*
+ * 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/mpr/VXWORKS/mprPlatform.c b/source4/lib/appweb/ejs-2.0/mpr/VXWORKS/mprPlatform.c
new file mode 100644
index 0000000000..29258dfe1c
--- /dev/null
+++ b/source4/lib/appweb/ejs-2.0/mpr/VXWORKS/mprPlatform.c
@@ -0,0 +1,191 @@
+/**
+ * @file mprPlatform.c
+ * @brief Cross platform routines
+ * @overview This module provides low level cross platform routines.
+ * @remarks Most routines in this file are not thread-safe. It is the callers
+ * responsibility to perform all thread synchronization.
+ */
+
+/*
+ * @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 **********************************/
+/*
+ * We need to use the underlying str(cpy) routines to implement our safe
+ * alternatives
+ */
+#if !DOXYGEN
+#define UNSAFE_FUNCTIONS_OK 1
+#endif
+
+#include "mpr.h"
+
+/************************************ Code ************************************/
+
+char *mprInetToStr(char *buffer, int bufsize, const struct in_addr in)
+{
+#if HAVE_NTOA_R
+ inet_ntoa_r(in, buffer, bufsize);
+#else
+ uchar *cp;
+ /* FUTURE -- this is not portable */
+ cp = (uchar*) &in;
+ mprSprintf(buffer, bufsize, "%d.%d.%d.%d", cp[0], cp[1], cp[2], cp[3]);
+#endif
+ return buffer;
+}
+
+/******************************************************************************/
+
+void mprSetShell(MprCtx ctx, void *shell)
+{
+}
+
+/******************************************************************************/
+
+void *mprGetShell(MprCtx ctx)
+{
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * Sleep. Period given in milliseconds.
+ */
+
+void mprSleep(MprCtx ctx, int milliseconds)
+{
+ struct timeval timeout;
+ int rc;
+
+ timeout.tv_sec = milliseconds / 1000;
+ timeout.tv_usec = (milliseconds % 1000) * 1000;
+ do {
+ rc = select(1, 0, 0, 0, &timeout);
+ } while (rc < 0 && errno == EINTR);
+}
+
+/******************************************************************************/
+/*
+ * Make intervening directories
+ */
+
+int mprMakeDirPath(MprCtx ctx, const char *path)
+{
+ char dir[MPR_MAX_PATH], buf[MPR_MAX_PATH];
+ char *dirSep;
+ char *next, *tok;
+
+ dir[0] = '\0';
+ dirSep = "/\\";
+
+ if (path == 0 || *path == '\0') {
+ return MPR_ERR_BAD_ARGS;
+ }
+
+ mprStrcpy(buf, sizeof(buf), path);
+ next = mprStrTok(buf, dirSep, &tok);
+ if (*buf == '/') {
+ dir[0] = '/';
+ }
+ while (next != NULL) {
+ if (strcmp(next, ".") == 0 ) {
+ next = mprStrTok(NULL, dirSep, &tok);
+ continue;
+ }
+ strcat(dir, next);
+ if (access(dir, R_OK) != 0) {
+ if (mkdir(dir) < 0) {
+ return MPR_ERR_CANT_CREATE;
+ }
+ }
+ strcat(dir, "/");
+ next = mprStrTok(NULL, dirSep, &tok);
+ }
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * Get a fully qualified file name for the given path. Return with forward
+ * slashes always
+ */
+
+char *mprGetFullPathName(char *buf, int buflen, const char *path)
+{
+ if (mprStrcpy(buf, buflen, path) < 0) {
+ mprAssert(0);
+ return 0;
+ }
+ return buf;
+}
+
+/******************************************************************************/
+/*
+ * Replacement for gethostbyname that is multi-thread safe
+ */
+
+struct hostent *mprGetHostByName(MprCtx ctx, const char *name)
+{
+ struct hostent *hp;
+
+ hp = (struct hostent*) mprAlloc(ctx, sizeof(struct hostent));
+ memset(hp, 0, sizeof(struct hostent));
+
+ struct in_addr inaddr;
+ inaddr.s_addr = (ulong) hostGetByName(name);
+ if (inaddr.s_addr < 0) {
+ mprAssert(0);
+ return 0;
+ }
+ hp->h_addrtype = AF_INET;
+ hp->h_length = sizeof(int);
+ hp->h_name = mprStrdup(name);
+ hp->h_addr_list = 0;
+ hp->h_aliases = 0;
+
+ hp->h_addr_list = new char*[2];
+ hp->h_addr_list[0] = (char *) mprAlloc(hp, sizeof(struct in_addr));
+ memcpy(&hp->h_addr_list[0], &inaddr, hp->h_length);
+ hp->h_addr_list[1] = 0;
+
+ return hp;
+}
+
+/******************************************************************************/
+
+/*
+ * 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/mpr/VXWORKS/mprTime.c b/source4/lib/appweb/ejs-2.0/mpr/VXWORKS/mprTime.c
new file mode 100755
index 0000000000..c9b7560f46
--- /dev/null
+++ b/source4/lib/appweb/ejs-2.0/mpr/VXWORKS/mprTime.c
@@ -0,0 +1,163 @@
+/**
+ * @file mprTime.c
+ * @brief Time handling for VxWorks
+ * @overview
+ */
+
+/*
+ * @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 "mpr.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#undef localtime
+#undef localtime_r
+#undef gmtime
+#undef gmtime_r
+#undef ctime
+#undef ctime_r
+#undef asctime
+#undef asctime_r
+
+/******************************************************************************/
+/*
+ * Returns time in seconds and milliseconds. This is NOT time-of-day.
+ */
+
+MprTime *mprGetTime(MprCtx ctx, MprTime *tp)
+{
+ struct timeval tv;
+
+ if (gettimeofday(&tv, 0) < 0) {
+ mprAssert(0);
+ tp->sec = 0;
+ tp->msec = 0;
+ return tp;
+ }
+ tp->sec = tv.tv_sec;
+ tp->msec = tv.tv_usec / 1000;
+ return tp;
+}
+
+/******************************************************************************/
+/*
+ * Thread-safe wrapping of localtime
+ */
+
+struct tm *mprLocaltime(MprCtx ctx, struct tm *timep, time_t *now)
+{
+ localtime_r(now, timep);
+
+ return timep;
+}
+
+/******************************************************************************/
+/*
+ * Thread-safe wrapping of gmtime
+ */
+
+struct tm *mprGmtime(MprCtx ctx, time_t *now, struct tm *timep)
+{
+ gmtime_r(now, timep);
+
+ return timep;
+}
+
+/******************************************************************************/
+/*
+ * Thread-safe wrapping of ctime
+ */
+
+int mprCtime(MprCtx ctx, char *buf, int bufsize, const time_t *timer)
+{
+ char localBuf[80];
+ char *cp;
+ int len;
+
+ mprAssert(buf);
+
+ mprGlobalLock(ctx);
+
+ cp = ctime_r(timer, localBuf);
+ if ((int) strlen(cp) >= bufsize) {
+ mprStrcpy(buf, bufsize, "WONT FIT");
+ mprAssert(0);
+ return MPR_ERR_WONT_FIT;
+ }
+ len = mprStrcpy(buf, bufsize, cp);
+
+ if (buf[len - 1] == '\n') {
+ buf[len - 1] = '\0';
+ }
+
+ mprGlobalUnlock(ctx);
+
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * Thread-safe wrapping of asctime
+ */
+
+int mprAsctime(MprCtx ctx, char *buf, int bufsize, const struct tm *timeptr)
+{
+ char *cp;
+ char localBuf[80];
+
+ cp = asctime_r(timeptr, localBuf);
+ if ((int) strlen(cp) >= bufsize) {
+ mprAssert(0);
+ return MPR_ERR_WONT_FIT;
+ }
+ mprStrcpy(buf, bufsize, cp);
+
+ return strlen(buf);
+}
+
+/******************************************************************************/
+
+#ifdef __cplusplus
+}
+#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/mpr/WIN/Makefile b/source4/lib/appweb/ejs-2.0/mpr/WIN/Makefile
new file mode 100644
index 0000000000..84e30ff8f1
--- /dev/null
+++ b/source4/lib/appweb/ejs-2.0/mpr/WIN/Makefile
@@ -0,0 +1,16 @@
+#
+# Makefile for the Mbedthis Portable Runtime (MPR) library for Windows
+#
+# Copyright (c) Mbedthis Software LLC, 2003-2006. All Rights Reserved.
+#
+
+COMPILE := *.c
+EXPORT_OBJECTS := yes
+MAKE_IFLAGS := -I..
+
+include make.dep
+
+## Local variables:
+## tab-width: 4
+## End:
+## vim: tw=78 sw=4 ts=4
diff --git a/source4/lib/appweb/ejs-2.0/mpr/WIN/mprFile.c b/source4/lib/appweb/ejs-2.0/mpr/WIN/mprFile.c
new file mode 100644
index 0000000000..9ac1669f3d
--- /dev/null
+++ b/source4/lib/appweb/ejs-2.0/mpr/WIN/mprFile.c
@@ -0,0 +1,123 @@
+/**
+ * @file mprWinFile.c
+ * @brief File services for Windows
+ * @overview
+ * @remarks
+ */
+
+/******************************************************************************/
+/*
+ * @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 "mpr.h"
+
+/************************************ Code ************************************/
+
+int mprGetFileInfo(MprCtx ctx, const char *path, MprFileInfo *info)
+{
+ struct stat s;
+
+ mprAssert(path);
+ mprAssert(info);
+
+ if (stat(path, &s) < 0) {
+ return -1;
+ }
+
+ info->size = s.st_size;
+ /*
+ * MOB -- these are time64_t. Loss of precision
+ */
+ info->ctime = (uint) s.st_ctime;
+ info->mtime = (uint) s.st_mtime;
+ info->inode = s.st_ino;
+ info->isDir = (s.st_mode & S_IFDIR) != 0;
+ info->isReg = (s.st_mode & S_IFREG) != 0;
+
+ /*
+ * Work hard on windows to determine if the file is a regular file.
+ * FUTURE -- OPT. Eliminate this CreateFile.
+ */
+ if (info->isReg) {
+ long fileType, att;
+
+ if ((att = GetFileAttributes(path)) == -1) {
+ return -1;
+ }
+ if (att & (FILE_ATTRIBUTE_REPARSE_POINT |
+ FILE_ATTRIBUTE_DIRECTORY |
+ FILE_ATTRIBUTE_ENCRYPTED |
+ FILE_ATTRIBUTE_SYSTEM |
+ FILE_ATTRIBUTE_OFFLINE)) {
+ /*
+ * Catch accesses to devices like CON, AUX, NUL, LPT etc
+ * att will be set to ENCRYPTED on Win9X and NT.
+ */
+ info->isReg = 0;
+ }
+ if (info->isReg) {
+ HANDLE handle;
+ handle = CreateFile(path, 0, FILE_SHARE_READ | FILE_SHARE_WRITE,
+ 0, OPEN_EXISTING, 0, 0);
+ if (handle == INVALID_HANDLE_VALUE) {
+ info->isReg = 0;
+ } else {
+ fileType = GetFileType(handle);
+ if (fileType == FILE_TYPE_CHAR || fileType == FILE_TYPE_PIPE) {
+ info->isReg = 0;
+ }
+ CloseHandle(handle);
+ }
+ }
+ }
+ if (strcmp(path, "nul") == 0) {
+ info->isReg = 0;
+ }
+ return 0;
+}
+
+/******************************************************************************/
+
+int mprMakeDir(MprCtx ctx, const char *path, int perms)
+{
+ return mkdir(path, perms);
+}
+
+/******************************************************************************/
+/*
+ * 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/mpr/WIN/mprPlatform.c b/source4/lib/appweb/ejs-2.0/mpr/WIN/mprPlatform.c
new file mode 100644
index 0000000000..65718694b1
--- /dev/null
+++ b/source4/lib/appweb/ejs-2.0/mpr/WIN/mprPlatform.c
@@ -0,0 +1,378 @@
+/**
+ * @file mprPlatform.c
+ * @brief Cross platform routines
+ * @overview This module provides low level cross platform routines.
+ * @remarks Most routines in this file are not thread-safe. It is the callers
+ * responsibility to perform all thread synchronization.
+ */
+
+/*
+ * @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 **********************************/
+/*
+ * We need to use the underlying str(cpy) routines to implement our safe
+ * alternatives
+ */
+#if !DOXYGEN
+#define UNSAFE_FUNCTIONS_OK 1
+#endif
+
+#include "mpr.h"
+
+/**************************** Forward Declarations ****************************/
+
+static const char *getHive(const char *keyPath, HKEY *hive);
+
+/************************************ Code ************************************/
+
+char *mprInetToStr(char *buffer, int bufsize, const struct in_addr in)
+{
+#if HAVE_NTOA_R
+ inet_ntoa_r(in, buffer, bufsize);
+#else
+ uchar *cp;
+ cp = (uchar*) &in;
+ mprSprintf(buffer, bufsize, "%d.%d.%d.%d", cp[0], cp[1], cp[2], cp[3]);
+#endif
+ return buffer;
+}
+
+/******************************************************************************/
+
+void mprSetShell(MprCtx ctx, void *shell)
+{
+}
+
+/******************************************************************************/
+
+void *mprGetShell(MprCtx ctx)
+{
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * Sleep. Period given in milliseconds.
+ */
+
+void mprSleep(MprCtx ctx, int milliseconds)
+{
+ Sleep(milliseconds);
+}
+
+/******************************************************************************/
+/*
+ * Make intervening directories
+ */
+
+int mprMakeDirPath(MprCtx ctx, const char *path)
+{
+ char dir[MPR_MAX_PATH], buf[MPR_MAX_PATH];
+ char *dirSep;
+ char *next, *tok;
+
+ dir[0] = '\0';
+ dirSep = "/\\";
+
+ if (path == 0 || *path == '\0') {
+ return MPR_ERR_BAD_ARGS;
+ }
+
+ mprStrcpy(buf, sizeof(buf), path);
+ next = mprStrTok(buf, dirSep, &tok);
+ if (*buf == '/') {
+ dir[0] = '/';
+ }
+ while (next != NULL) {
+ if (strcmp(next, ".") == 0 ) {
+ next = mprStrTok(NULL, dirSep, &tok);
+ continue;
+ }
+ strcat(dir, next);
+ if (access(dir, R_OK) != 0) {
+ if (_mkdir(dir) < 0) {
+ return MPR_ERR_CANT_CREATE;
+ }
+ }
+ strcat(dir, "/");
+ next = mprStrTok(NULL, dirSep, &tok);
+ }
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * Get a fully qualified file name for the given path. Return with forward
+ * slashes always
+ */
+
+char *mprGetFullPathName(char *buf, int buflen, const char *path)
+{
+#if (WIN || NW || OS2) && !BLD_FEATURE_ROMFS
+ char *junk, *cp;
+ int rc;
+
+ --buflen;
+ rc = GetFullPathName(path, buflen, buf, &junk);
+ for (cp = buf; *cp; cp++) {
+ if (*cp == '\\') {
+ *cp = '/';
+ }
+ }
+ buf[buflen] = '\0';
+#else
+ if (mprStrcpy(buf, buflen, path) < 0) {
+ mprAssert(0);
+ return 0;
+ }
+#endif
+ return buf;
+}
+
+/******************************************************************************/
+/*
+ * Replacement for gethostbyname that is multi-thread safe
+ */
+
+struct hostent *mprGetHostByName(MprCtx ctx, const char *name)
+{
+ MprApp *app;
+ struct hostent *hp;
+ struct hostent *ip;
+ int count, i;
+
+ hp = (struct hostent*) mprAlloc(ctx, sizeof(struct hostent));
+ memset(hp, 0, sizeof(struct hostent));
+
+ app = mprGetApp(ctx);
+
+ #undef gethostbyname
+
+ mprGlobalLock(app);
+ ip = gethostbyname(name);
+ mprGlobalUnlock(app);
+
+ if (ip == 0) {
+ return 0;
+ }
+ hp->h_addrtype = ip->h_addrtype;
+ hp->h_length = ip->h_length;
+ hp->h_name = mprStrdup(hp, ip->h_name);
+ hp->h_addr_list = 0;
+ hp->h_aliases = 0;
+
+ for (count = 0; ip->h_addr_list[count] != 0; ) {
+ count++;
+ }
+ if (count > 0) {
+ count++;
+ hp->h_addr_list = mprAlloc(hp, count * sizeof(char*));
+ for (i = 0; ip->h_addr_list[i] != 0; i++) {
+ memcpy(&hp->h_addr_list[i], &ip->h_addr_list[i], ip->h_length);
+ }
+ hp->h_addr_list[i] = 0;
+ }
+
+ for (count = 0; ip->h_aliases[count] != 0; ) {
+ count++;
+ }
+ if (count > 0) {
+ count++;
+ hp->h_aliases = mprAlloc(hp, count * sizeof(char*));
+ for (i = 0; ip->h_aliases[i] != 0; i++) {
+ hp->h_aliases[i] = mprStrdup(hp, ip->h_aliases[i]);
+ }
+ hp->h_aliases[i] = 0;
+ }
+ return hp;
+}
+
+/******************************************************************************/
+/*
+ * Read a registry value. Returns allocated memory in buf.
+ */
+
+int mprReadRegistry(MprCtx ctx, char **buf, int max, const char *key,
+ const char *name)
+{
+ HKEY top, h;
+ char *value;
+ ulong type, size;
+
+ mprAssert(key && *key);
+ mprAssert(buf);
+
+ /*
+ * Get the registry hive
+ */
+ if ((key = getHive(key, &top)) == 0) {
+ return MPR_ERR_CANT_ACCESS;
+ }
+
+ if (RegOpenKeyEx(top, key, 0, KEY_READ, &h) != ERROR_SUCCESS) {
+ return MPR_ERR_CANT_ACCESS;
+ }
+
+ /*
+ * Get the type
+ */
+ if (RegQueryValueEx(h, name, 0, &type, 0, &size) != ERROR_SUCCESS) {
+ RegCloseKey(h);
+ return MPR_ERR_CANT_READ;
+ }
+ if (type != REG_SZ && type != REG_EXPAND_SZ) {
+ RegCloseKey(h);
+ return MPR_ERR_BAD_TYPE;
+ }
+
+ value = (char*) mprAlloc(ctx, size);
+ if ((int) size > max) {
+ RegCloseKey(h);
+ return MPR_ERR_WONT_FIT;
+ }
+ if (RegQueryValueEx(h, name, 0, &type, (uchar*) value, &size) !=
+ ERROR_SUCCESS) {
+ mprFree(value);
+ RegCloseKey(h);
+ return MPR_ERR_CANT_READ;
+ }
+
+ RegCloseKey(h);
+ *buf = value;
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * Write a string registry value. Returns allocated memory in buf.
+ */
+
+int mprWriteRegistry(MprCtx ctx, const char *key, const char *name,
+ const char *value)
+{
+ HKEY top, h, subHandle;
+ ulong disposition;
+
+ mprAssert(key && *key);
+ mprAssert(name && *name);
+ mprAssert(value && *value);
+
+ /*
+ * Get the registry hive
+ */
+ if ((key = getHive(key, &top)) == 0) {
+ return MPR_ERR_CANT_ACCESS;
+ }
+
+ if (name) {
+ /*
+ * Write a registry string value
+ */
+ if (RegOpenKeyEx(top, key, 0, KEY_ALL_ACCESS, &h) != ERROR_SUCCESS) {
+ return MPR_ERR_CANT_ACCESS;
+ }
+ if (RegSetValueEx(h, name, 0, REG_SZ, value, strlen(value) + 1)
+ != ERROR_SUCCESS) {
+ RegCloseKey(h);
+ return MPR_ERR_CANT_READ;
+ }
+
+ } else {
+ /*
+ * Create a new sub key
+ */
+ if (RegOpenKeyEx(top, key, 0, KEY_CREATE_SUB_KEY, &h) != ERROR_SUCCESS){
+ return MPR_ERR_CANT_ACCESS;
+ }
+ if (RegCreateKeyEx(h, name, 0, NULL, REG_OPTION_NON_VOLATILE,
+ KEY_ALL_ACCESS, NULL, &subHandle, &disposition) != ERROR_SUCCESS) {
+ return MPR_ERR_CANT_ACCESS;
+ }
+ RegCloseKey(subHandle);
+ }
+ RegCloseKey(h);
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * Determine the registry hive by the first portion of the path. Return
+ * a pointer to the rest of key path after the hive portion.
+ */
+
+static const char *getHive(const char *keyPath, HKEY *hive)
+{
+ char key[MPR_MAX_STRING], *cp;
+ int len;
+
+ mprAssert(keyPath && *keyPath);
+
+ *hive = 0;
+
+ mprStrcpy(key, sizeof(key), keyPath);
+ key[sizeof(key) - 1] = '\0';
+
+ if (cp = strchr(key, '\\')) {
+ *cp++ = '\0';
+ }
+ if (cp == 0 || *cp == '\0') {
+ return 0;
+ }
+
+ if (!mprStrcmpAnyCase(key, "HKEY_LOCAL_MACHINE")) {
+ *hive = HKEY_LOCAL_MACHINE;
+ } else if (!mprStrcmpAnyCase(key, "HKEY_CURRENT_USER")) {
+ *hive = HKEY_CURRENT_USER;
+ } else if (!mprStrcmpAnyCase(key, "HKEY_USERS")) {
+ *hive = HKEY_USERS;
+ } else if (!mprStrcmpAnyCase(key, "HKEY_CLASSES_ROOT")) {
+ *hive = HKEY_CLASSES_ROOT;
+ } else {
+ return 0;
+ }
+
+ if (*hive == 0) {
+ return 0;
+ }
+ len = strlen(key) + 1;
+ return keyPath + len;
+}
+
+/******************************************************************************/
+
+/*
+ * 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/mpr/WIN/mprTime.c b/source4/lib/appweb/ejs-2.0/mpr/WIN/mprTime.c
new file mode 100644
index 0000000000..74e59c9c73
--- /dev/null
+++ b/source4/lib/appweb/ejs-2.0/mpr/WIN/mprTime.c
@@ -0,0 +1,192 @@
+/**
+ * @file mprTime.c
+ * @brief Time handling for Windows
+ * @overview
+ */
+
+/*
+ * @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 "mpr.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/************************************ Code ************************************/
+/*
+ * Returns time in seconds and milliseconds. This is NOT time-of-day.
+ */
+
+MprTime *mprGetTime(MprCtx ctx, MprTime *tp)
+{
+ FILETIME fileTime;
+ int64 now, base;
+
+ GetSystemTimeAsFileTime(&fileTime);
+
+ now = ((((int64) fileTime.dwHighDateTime) << BITS(uint)) +
+ ((int64) fileTime.dwLowDateTime));
+
+ /*
+ * Convert from 100-nanosec units to milliseconds
+ */
+ now = (now / 10000);
+
+ /*
+ * Adjust to be seconds since Jan 1 1970. Do this to be consistent with
+ * UNIX but not really required by the API definition.
+ */
+ base = ((UINT64(365) * 86400 * (1970 - 1601)) * 1000);
+ now -= base;
+ tp->sec = (uint) (now / 1000);
+ tp->msec = (uint) (now % 1000);
+
+#if UNUSED
+{
+ static int64 start;
+
+ if (start == 0) {
+ start = now;
+ }
+ if (now < start) {
+ mprLog(ctx, 0, "TIME WENT BACKWARDS");
+ mprLog(ctx, 0, "start %Ld", start);
+ mprLog(ctx, 0, "now %Ld", now);
+ }
+ mprLog(ctx, 0, "getTime %Ld", now);
+ start = now;
+}
+#endif
+
+ return tp;
+}
+
+/******************************************************************************/
+/*
+ * Thread-safe wrapping of localtime
+ */
+
+struct tm *mprLocaltime(MprCtx ctx, struct tm *timep, time_t *now)
+{
+ struct tm *tbuf;
+ mprGlobalLock(ctx);
+ tbuf = localtime(now);
+ *timep = *tbuf;
+ mprGlobalUnlock(ctx);
+
+ return timep;
+}
+
+/******************************************************************************/
+/*
+ * Thread-safe wrapping of gmtime
+ */
+
+struct tm *mprGmtime(MprCtx ctx, time_t *now, struct tm *timep)
+{
+ struct tm *tbuf;
+ tbuf = gmtime(now);
+ *timep = *tbuf;
+
+ return timep;
+}
+
+/******************************************************************************/
+/*
+ * Thread-safe wrapping of ctime
+ */
+
+int mprCtime(MprCtx ctx, char *buf, int bufsize, const time_t *timer)
+{
+ char *cp;
+ int len;
+
+ mprAssert(buf);
+
+ mprGlobalLock(ctx);
+
+ cp = ctime(timer);
+ if ((int) strlen(cp) >= bufsize) {
+ mprStrcpy(buf, bufsize, "WONT FIT");
+ mprAssert(0);
+ mprGlobalUnlock(ctx);
+ return MPR_ERR_WONT_FIT;
+ }
+
+ len = mprStrcpy(buf, bufsize, cp);
+ if (buf[len - 1] == '\n') {
+ buf[len - 1] = '\0';
+ }
+
+ mprGlobalUnlock(ctx);
+
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * Thread-safe wrapping of asctime
+ */
+
+int mprAsctime(MprCtx ctx, char *buf, int bufsize, const struct tm *timeptr)
+{
+ char *cp;
+
+ mprAssert(buf);
+ mprGlobalLock(ctx);
+ cp = asctime(timeptr);
+ if ((int) strlen(cp) >= bufsize) {
+ mprAssert(0);
+ mprGlobalUnlock(ctx);
+ return MPR_ERR_WONT_FIT;
+ }
+ mprStrcpy(buf, bufsize, cp);
+ mprGlobalUnlock(ctx);
+
+ return strlen(buf);
+}
+
+/******************************************************************************/
+
+#ifdef __cplusplus
+}
+#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/mpr/files b/source4/lib/appweb/ejs-2.0/mpr/files
new file mode 100644
index 0000000000..290c9ce790
--- /dev/null
+++ b/source4/lib/appweb/ejs-2.0/mpr/files
@@ -0,0 +1,14 @@
+${BLD_OBJ_DIR}/mpr${BLD_OBJ}
+${BLD_OBJ_DIR}/mprAlloc${BLD_OBJ}
+${BLD_OBJ_DIR}/mprArray${BLD_OBJ}
+${BLD_OBJ_DIR}/mprBuf${BLD_OBJ}
+${BLD_OBJ_DIR}/mprFile${BLD_OBJ}
+${BLD_OBJ_DIR}/mprGenFile${BLD_OBJ}
+${BLD_OBJ_DIR}/mprGenTime${BLD_OBJ}
+${BLD_OBJ_DIR}/mprLock${BLD_OBJ}
+${BLD_OBJ_DIR}/mprLog${BLD_OBJ}
+${BLD_OBJ_DIR}/mprPlatform${BLD_OBJ}
+${BLD_OBJ_DIR}/mprPrintf${BLD_OBJ}
+${BLD_OBJ_DIR}/mprString${BLD_OBJ}
+${BLD_OBJ_DIR}/mprSymbol${BLD_OBJ}
+${BLD_OBJ_DIR}/mprTime${BLD_OBJ}
diff --git a/source4/lib/appweb/ejs-2.0/mpr/mpr.c b/source4/lib/appweb/ejs-2.0/mpr/mpr.c
new file mode 100644
index 0000000000..163b51eccf
--- /dev/null
+++ b/source4/lib/appweb/ejs-2.0/mpr/mpr.c
@@ -0,0 +1,340 @@
+/**
+ * @file mpr.c
+ * @brief Mpr initialization
+ * @overview
+ * @remarks Most routines in this file are not thread-safe. It is the callers
+ * responsibility to perform all thread synchronization.
+ */
+
+/*
+ * @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 **********************************/
+/*
+ * We need to use the underlying str(cpy) routines to implement our safe
+ * alternatives
+ */
+#if !DOXYGEN
+#define UNSAFE_FUNCTIONS_OK 1
+#endif
+
+#include "mpr.h"
+
+/******************************************************************************/
+/*
+ * Initialize the MPR. Create the top level memory context. This routine is
+ * the first call an MPR application must do. If using MprServices, the
+ * creation of an Mpr object will call this routine.
+ */
+
+MprApp *mprInit(MprAllocCback cback)
+{
+ return mprInitEx(cback, 0);
+}
+
+/******************************************************************************/
+/*
+ * Add a shell parameter then do the regular init
+ */
+
+MprApp *mprInitEx(MprAllocCback cback, void *shell)
+{
+ MprApp *app;
+
+ app = (MprApp*) mprAllocInit(cback);
+
+ mprAssert(app);
+ if (app == 0) {
+ return 0;
+ }
+
+ app->name = mprStrdup(app, BLD_PRODUCT);
+ app->title = mprStrdup(app, BLD_NAME);
+ app->version = mprStrdup(app, BLD_VERSION);
+
+ mprSetShell(app, shell);
+
+ app->table = mprCreateSymbolTable(app, 0);
+
+ if (mprStartFileServices(app) < 0) {
+ mprAllocTerm(app);
+ return 0;
+ }
+
+#if BLD_FEATURE_MULTITHREAD
+ mprInitThreads(app);
+#endif
+
+ /*
+ * See if any of the preceeding allocations failed
+ */
+ if (mprGetAllocErrors(app) > 0) {
+ mprAllocTerm(app);
+ return 0;
+ }
+
+ /*
+ * Mark all blocks allocated so far as required. They will then be
+ * omitted from leak reports.
+ */
+ mprSetRequiredAlloc(app, 1);
+
+ return app;
+}
+
+/******************************************************************************/
+/*
+ * Terminate the MPR. If doStats is true, then output a memory allocation
+ * report.
+ */
+
+void mprTerm(MprApp *app, bool doStats)
+{
+#if BLD_FEATURE_ALLOC_STATS
+ if (doStats) {
+ mprPrintAllocReport(app, 1, "MPR Memory Allocation Report");
+ }
+#endif
+
+#if BLD_FEATURE_MULTITHREAD
+ mprTermThreads(app);
+#endif
+
+ mprStopFileServices(app);
+
+#if BLD_DEBUG
+ mprValidateAllocTree(app);
+#endif
+ mprAllocTerm(app);
+}
+
+/******************************************************************************/
+
+bool mprIsExiting(MprCtx ctx)
+{
+ MprApp *app;
+
+ app = mprGetApp(ctx);
+ if (app == 0) {
+ return 1;
+ }
+ return app->flags & MPR_APP_EXITING;
+}
+
+/******************************************************************************/
+
+int mprHasAllocError(MprCtx ctx)
+{
+ MprApp *app;
+
+ app = mprGetApp(ctx);
+ if (app == 0) {
+ return 1;
+ }
+
+ return app->flags & MPR_APP_ALLOC_ERROR;
+}
+
+/******************************************************************************/
+
+void mprSignalExit(MprCtx ctx)
+{
+ MprApp *app;
+
+ app = mprGetApp(ctx);
+ app->flags |= MPR_APP_EXITING;
+}
+
+/******************************************************************************/
+
+void mprSignalAllocError(MprCtx ctx)
+{
+ MprApp *app;
+
+ app = mprGetApp(ctx);
+ app->flags |= MPR_APP_ALLOC_ERROR;
+}
+
+/******************************************************************************/
+
+int mprSetAppName(MprCtx ctx, const char *name, const char *title,
+ const char *version)
+{
+ MprApp *app;
+
+ app = mprGetApp(ctx);
+
+ if (name) {
+ mprFree(app->name);
+ if ((app->name = mprStrdup(ctx, name)) == 0) {
+ return MPR_ERR_CANT_ALLOCATE;
+ }
+ }
+
+ if (title) {
+ mprFree(app->title);
+ if ((app->title = mprStrdup(ctx, title)) == 0) {
+ return MPR_ERR_CANT_ALLOCATE;
+ }
+ }
+
+ if (version) {
+ mprFree(app->version);
+ if ((app->version = mprStrdup(ctx, version)) == 0) {
+ return MPR_ERR_CANT_ALLOCATE;
+ }
+ }
+ return 0;
+}
+
+/******************************************************************************/
+
+const char *mprGetAppName(MprCtx ctx)
+{
+ MprApp *app;
+
+ app = mprGetApp(ctx);
+ return app->name;
+}
+
+/******************************************************************************/
+
+const char *mprGetAppTitle(MprCtx ctx)
+{
+ MprApp *app;
+
+ app = mprGetApp(ctx);
+ return app->title;
+}
+
+/******************************************************************************/
+
+const char *mprGetAppVersion(MprCtx ctx)
+{
+ MprApp *app;
+
+ app = mprGetApp(ctx);
+ return app->version;
+}
+
+/******************************************************************************/
+
+int mprSetKeyValue(MprCtx ctx, const char *key, void *ptr)
+{
+ MprApp *app;
+
+ app = mprGetApp(ctx);
+ if (mprInsertSymbol(app->table, key, ptr) == 0) {
+ return MPR_ERR_CANT_WRITE;
+ }
+ return 0;
+}
+
+/******************************************************************************/
+
+int mprRemoveKeyValue(MprCtx ctx, const char *key)
+{
+ MprApp *app;
+
+ app = mprGetApp(ctx);
+ return mprRemoveSymbol(app->table, key);
+}
+
+/******************************************************************************/
+
+void *mprGetKeyValue(MprCtx ctx, const char *key)
+{
+ MprApp *app;
+
+ app = mprGetApp(ctx);
+ return mprLookupSymbol(app->table, key);
+}
+
+/******************************************************************************/
+
+bool mprGetDebugMode(MprCtx ctx)
+{
+ return mprGetApp(ctx)->debugMode;
+}
+
+/******************************************************************************/
+
+void mprSetDebugMode(MprCtx ctx, bool on)
+{
+ mprGetApp(ctx)->debugMode = on;
+}
+
+/******************************************************************************/
+
+void mprSetLogHandler(MprCtx ctx, MprLogHandler handler)
+{
+ mprGetApp(ctx)->logHandler = handler;
+}
+
+/******************************************************************************/
+
+MprLogHandler mprGetLogHandler(MprCtx ctx)
+{
+ return mprGetApp(ctx)->logHandler;
+}
+
+#if UNUSED
+/******************************************************************************/
+
+void mprSetMprInstance(MprCtx ctx, void *mprInstance)
+{
+ mprGetApp(ctx)->mprInstance = mprInstance;
+}
+
+/******************************************************************************/
+
+void *mprGetMprInstance(MprCtx ctx)
+{
+ return mprGetApp(ctx)->mprInstance;
+}
+
+#endif
+/******************************************************************************/
+
+const char *mprCopyright()
+{
+ return "Copyright (c) Mbedthis Software LLC, 2003-2006. All Rights Reserved.";
+}
+
+/******************************************************************************/
+
+/*
+ * 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/mpr/mpr.h b/source4/lib/appweb/ejs-2.0/mpr/mpr.h
new file mode 100644
index 0000000000..67505a6e01
--- /dev/null
+++ b/source4/lib/appweb/ejs-2.0/mpr/mpr.h
@@ -0,0 +1,1027 @@
+/*
+ * @file mpr.h
+ * @brief Header for the Mbedthis Portable Runtime (MPR) Base.
+ * @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
+ */
+/******************************* Documentation ********************************/
+/*
+ * See mpr.dox for additional documentation.
+ */
+
+/******************************************************************************/
+
+#ifndef _h_MPR
+#define _h_MPR 1
+
+/***********************************Includes **********************************/
+
+#include "mprOs.h"
+
+/******************************************************************************/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/********************************** Constants *********************************/
+
+#if BLD_FEATURE_SQUEEZE
+#if BREW || DOXYGEN
+/*
+ * Maximum length of a file path name. Reduced from the system maximum to
+ * save memory space.
+ */
+#define MPR_MAX_FNAME 64 /**< Reasonable filename size */
+#define MPR_MAX_PATH 64 /**< Reasonable path name size */
+#define MPR_DEFAULT_STACK (16 * 1024) /**< Default stack size */
+#else
+#define MPR_MAX_FNAME 128 /**< Reasonable filename size */
+#define MPR_MAX_PATH 256 /**< Reasonable path name size */
+#define MPR_DEFAULT_STACK (32 * 1024) /**< Default stack size */
+#endif
+/*
+ * Reasonable length of a file name used by the product. Use where you know
+ * the expected file name and it is certain to be less than this limit.
+ */
+#define MPR_DEFAULT_ALLOC 64 /**< Default small alloc size */
+#define MPR_DEFAULT_HASH_SIZE 23 /**< Default size of hash table */
+#define MPR_MAX_ARGC 32 /**< Reasonable max of args */
+#define MPR_MAX_STRING 512 /**< Maximum (stack) string size */
+#define MPR_MAX_LOG_STRING 512 /**< Maximum log message */
+#define MPR_MAX_URL 256 /**< Reasonable size of a URL */
+#define MPR_BUFSIZE 512 /**< Reasonable size for buffers */
+#define MPR_SLAB_STR_MAX 32 /**< Size of string slab blocks */
+#define MPR_SLAB_STR_INC 32 /**< Pre-allocate increment */
+#define MPR_SLAB_DEFAULT_INC 8 /**< Default pre-allocate inc */
+#define MPR_ARRAY_INCR 8 /**< Default array growth inc */
+#define MPR_BUF_INCR 1024 /**< Default array growth inc */
+#define MPR_MAX_BUF (1024*4096) /**< Default array growth inc */
+
+#define MPR_BLK_HDR_SIZE ((sizeof(struct MprBlk) + 3) & ~3)
+
+#else
+#define MPR_MAX_FNAME 256
+#define MPR_MAX_PATH 1024
+#define MPR_DEFAULT_ALLOC 256
+#define MPR_DEFAULT_HASH_SIZE 43
+#define MPR_DEFAULT_STACK (64 * 1024)
+#define MPR_MAX_ARGC 128
+#define MPR_MAX_STRING 4096
+#define MPR_MAX_LOG_STRING 8192
+#define MPR_MAX_URL 1024
+#define MPR_BUFSIZE 1024
+#define MPR_SLAB_STR_MAX 32
+#define MPR_SLAB_STR_INC 64
+#define MPR_SLAB_DEFAULT_INC 16
+#define MPR_ARRAY_INCR 16
+#define MPR_BUF_INCR 1024
+#define MPR_MAX_BUF (1024*4096)
+
+#define MPR_BLK_HDR_SIZE ((sizeof(struct MprBlk) + 15) & ~15)
+#endif
+
+/**
+ * Maximum size of a host name string
+ */
+#define MPR_MAX_IP_NAME 64
+
+/**
+ * Maximum size of an IP address
+ */
+#define MPR_MAX_IP_ADDR 16
+
+/**
+ * Maximum size of an IP address including port number
+ */
+#define MPR_MAX_IP_ADDR_PORT 32
+
+#define MPR_MAX_SLAB 16 /* Slabs from 32-512 bytes */
+
+#define MPR_MAX_TIME_SYNC (10 * 1000) /* Time sync adjustments */
+
+/**
+ * @overview Memory context type
+ * @description Blocks of memory are allocated using a memory context
+ * as the parent with the \ref MprApp structure being the root of the
+ * tree. Any allocated memory block may serve as the memory context for
+ * subsequent memory allocations. Freeing a block via \ref mprFree will
+ * release the allocated block and all child blocks.
+ * @stability Prototype.
+ * @library libmpr.
+ * @see mprInit, mprAlloc, mprFree
+ */
+typedef const void *MprCtx;
+
+/*
+ * Allocated memory destructor type
+ */
+typedef int (*MprDestructor)(void *);
+
+/******************************** Error Codes *********************************/
+
+/*
+ * Standard MPR return and error codes
+ */
+
+#define MPR_ERR_OK (0)
+/**< Success */
+
+#define MPR_ERR_BASE (-200)
+/**< Base error code */
+
+#define MPR_ERR_GENERAL (MPR_ERR_BASE - 1)
+/**< General error */
+#define MPR_ERR_ABORTED (MPR_ERR_BASE - 2)
+/**< Action aborted */
+#define MPR_ERR_ALREADY_EXISTS (MPR_ERR_BASE - 3)
+/**< Item already exists */
+#define MPR_ERR_BAD_ARGS (MPR_ERR_BASE - 4)
+/**< Bad arguments or paramaeters */
+#define MPR_ERR_BAD_FORMAT (MPR_ERR_BASE - 5)
+/**< Bad input format */
+#define MPR_ERR_BAD_HANDLE (MPR_ERR_BASE - 6)
+#define MPR_ERR_BAD_STATE (MPR_ERR_BASE - 7)
+/**< Module is in a bad state */
+#define MPR_ERR_BAD_SYNTAX (MPR_ERR_BASE - 8)
+/**< Input has bad syntax */
+#define MPR_ERR_BAD_TYPE (MPR_ERR_BASE - 9)
+#define MPR_ERR_BAD_VALUE (MPR_ERR_BASE - 10)
+#define MPR_ERR_BUSY (MPR_ERR_BASE - 11)
+#define MPR_ERR_CANT_ACCESS (MPR_ERR_BASE - 12)
+/**< Can't access the file or resource */
+#define MPR_ERR_CANT_COMPLETE (MPR_ERR_BASE - 13)
+#define MPR_ERR_CANT_CREATE (MPR_ERR_BASE - 14)
+/**< Can't create the file or resource */
+#define MPR_ERR_CANT_INITIALIZE (MPR_ERR_BASE - 15)
+#define MPR_ERR_CANT_OPEN (MPR_ERR_BASE - 16)
+/**< Can't open the file or resource */
+#define MPR_ERR_CANT_READ (MPR_ERR_BASE - 17)
+/**< Can't read from the file or resource */
+#define MPR_ERR_CANT_WRITE (MPR_ERR_BASE - 18)
+/**< Can't write to the file or resource */
+#define MPR_ERR_DELETED (MPR_ERR_BASE - 19)
+#define MPR_ERR_NETWORK (MPR_ERR_BASE - 20)
+#define MPR_ERR_NOT_FOUND (MPR_ERR_BASE - 21)
+#define MPR_ERR_NOT_INITIALIZED (MPR_ERR_BASE - 22)
+/**< Module or resource is not initialized */
+#define MPR_ERR_NOT_READY (MPR_ERR_BASE - 23)
+#define MPR_ERR_READ_ONLY (MPR_ERR_BASE - 24)
+/**< The operation timed out */
+#define MPR_ERR_TIMEOUT (MPR_ERR_BASE - 25)
+#define MPR_ERR_TOO_MANY (MPR_ERR_BASE - 26)
+#define MPR_ERR_WONT_FIT (MPR_ERR_BASE - 27)
+#define MPR_ERR_WOULD_BLOCK (MPR_ERR_BASE - 28)
+#define MPR_ERR_CANT_ALLOCATE (MPR_ERR_BASE - 29)
+// MOB -- rename NO_MEMORY
+#define MPR_ERR_MEMORY (MPR_ERR_BASE - 30)
+#define MPR_ERR_CANT_DELETE (MPR_ERR_BASE - 31)
+#define MPR_ERR_MAX (MPR_ERR_BASE - 32)
+
+/*
+ * Standard logging trace levels are 0 to 9 with 0 being the most verbose.
+ * the These are ored with the error source and type flags. The MPR_LOG_MASK
+ * is used to extract the trace level from a flags word. We expect most apps
+ * to run with level 2 trace enabled.
+ */
+#define MPR_ERROR 1 /**< Hard error trace level */
+#define MPR_WARN 2 /**< Soft warning trace level */
+#define MPR_CONFIG 2 /**< Configuration settings trace level. */
+#define MPR_INFO 3 /**< Informational trace only */
+#define MPR_DEBUG 4 /**< Debug information trace level */
+#define MPR_VERBOSE 9 /**< Highest level of trace */
+#define MPR_LEVEL_MASK 0xf /**< Level mask */
+
+/*
+ * Error source flags
+ */
+#define MPR_ERROR_SRC 0x10 /**< Originated from mprError */
+#define MPR_LOG_SRC 0x20 /**< Originated from mprLog */
+#define MPR_ASSERT_SRC 0x40 /**< Originated from mprAssert */
+#define MPR_FATAL_SRC 0x80 /**< Fatal error. Log and exit */
+
+/*
+ * Log message type flags. Specify what kind of log / error message it is.
+ * Listener handlers examine this flag to determine if they should process
+ * the message.Assert messages are trapped when in DEV mode. Otherwise ignored.
+ */
+#define MPR_LOG_MSG 0x100 /**< Log trace message - not an error */
+#define MPR_ERROR_MSG 0x200 /**< General error */
+#define MPR_ASSERT_MSG 0x400 /**< Assert flags -- trap in debugger */
+#define MPR_USER_MSG 0x800 /**< User message */
+
+/*
+ * Log output modifiers
+ */
+#define MPR_RAW 0x1000 /**< Raw trace output */
+
+/*
+ * Error line number information.
+ */
+#define MPR_LINE(s) #s
+#define MPR_LINE2(s) MPR_LINE(s)
+#define MPR_LINE3 MPR_LINE2(__LINE__)
+#define MPR_LOC __FILE__ ":" MPR_LINE3
+
+/*
+ * Macros to pass file and line number information
+ * Use MPR_LOC_ARGS in normal user code.
+ * Use MPR_LOC_DEC in declarations.
+ * Use MPR_LOC_PASS in layered APIs to pass original line info down.
+ */
+#if BLD_FEATURE_ALLOC_LEAK_TRACK
+#define MPR_LOC_ARGS(ctx) ctx, MPR_LOC
+#define MPR_LOC_DEC(ctx, loc) MprCtx ctx, const char *loc
+#define MPR_LOC_PASS(ctx, loc) ctx, loc
+#else
+#define MPR_LOC_ARGS(ctx) ctx
+#define MPR_LOC_DEC(ctx, loc) MprCtx ctx
+#define MPR_LOC_PASS(ctx, loc) ctx
+#endif
+
+/******************************* Debug and Assert *****************************/
+
+extern void mprBreakpoint(const char *loc, const char *msg);
+
+#if BLD_FEATURE_ASSERT
+ #define mprAssert(C) if (C) ; else mprStaticAssert(MPR_LOC, #C)
+#else
+ #define mprAssert(C) if (1) ; else
+#endif
+
+/********************************* Safe Strings *******************************/
+/*
+ * Unsafe functions that should not be used. Define UNSAFE_STRINGS_OK before
+ * including mpr.h if you really want to use these functions. A better approach
+ * is to undefine them just prior to using them in your C/C++ source file.
+ */
+#if BLD_FEATURE_SAFE_STRINGS
+
+#if BLD_FEATURE_PHP4_MODULE || BLD_FEATURE_PHP5_MODULE
+ #ifndef UNSAFE_FUNCTIONS_OK
+ #define UNSAFE_FUNCTIONS_OK 1
+ #endif
+#endif
+
+#ifndef UNSAFE_FUNCTIONS_OK
+ #define sprintf UseMprSprintfInstead
+ #define fprintf UseMprFprintfInstead
+ #define vsprintf UseMprVsprintfInstead
+ #define strtok UseMprStrTokInstead
+ #define gethostbyname UseMprGetHostByNameInstead
+ #define ctime UseMprCtimeInstead
+ #define asctime UseMprAsctimeInstead
+ #define localtime UseMprLocaltimeInstead
+ #define gmtime UseMprGmtimeInstead
+ #define malloc UseMprMallocInstead
+ #define free UseMprFreeInstead
+ #define realloc UseMprReallocInstead
+ #define strncpy UseMprStrcpyInstead
+ #define inet_ntoa UseMprInetToStrInstead
+
+#if !BREW
+ #define printf UseMprPrintfInstead
+#endif
+
+ #if FUTURE
+ #define strlen UseMprStrlenInstead
+ #define strcpy UseMprStrcpyInstead
+ #endif
+
+#endif /* UNSAFE_FUNCTIONS_OK */
+#endif /* BLD_FEATURE_SAFE_STRINGS */
+
+/******************************************************************************/
+
+struct MprBuf;
+typedef int (*MprBufProc)(struct MprBuf* bp, void *arg);
+
+/**
+ * @overview Dynamic buffer structure
+ * @description MprBuf is a flexible, dynamic growable buffer structure. It
+ * utilizes a ring buffer mechanism and is suitable for high performance
+ * buffering in a variety of situations.
+ * @stability Prototype.
+ * @library libmpr.
+ * @see mprCreateBuf, mprFree, MprArray
+ */
+typedef struct MprBuf {
+ uchar *buf; /* Actual buffer for data */
+ uchar *endbuf; /* Pointer one past the end of buffer */
+ uchar *start; /* Pointer to next data char */
+ uchar *end; /* Pointer one past the last data chr */
+ int buflen; /* Current size of buffer */
+ int maxsize; /* Max size the buffer can ever grow */
+ int growBy; /* Next growth increment to use */
+ MprBufProc refillProc; /* Auto-refill procedure */
+ void *refillArg; /* Refill arg */
+} MprBuf;
+
+/**
+ * @overview File structure
+ * @description MprFile is the cross platform File I/O abstraction control
+ * structure.
+ * @stability Prototype.
+ * @library libmpr.
+ * @see mprOpen, mprClose, mprRead, mprWrite
+ */
+typedef struct MprFile
+{
+ MprBuf *buf; /* Buffer for I/O */
+#if BREW
+ IFile *fd; /* File handle */
+#else
+ int fd;
+#endif
+} MprFile;
+
+/**
+ * File information structure
+ * @overview File information structure
+ * @description MprFileInfo is the cross platform File information structure.
+ * @stability Prototype.
+ * @see mprGetFileInfo, mprOpen, mprClose, mprRead, mprWrite
+ */
+typedef struct MprFileInfo
+{
+ uint size; /* File length */
+ uint ctime; /* Create time */
+ uint mtime; /* Modified time */
+ uint inode; /* Inode number */
+ int isDir; /* Set if directory */
+ int isReg; /* Set if a regular file */
+} MprFileInfo;
+
+/**
+ * @overview Mpr time structure.
+ * @description MprTime is the cross platform time abstraction structure.
+ * @stability Prototype.
+ * @library libmpr.
+ * @see mprGetTime
+ */
+typedef struct MprTime
+{
+ uint sec; /* Seconds */
+ uint msec; /* Milliseconds */
+} MprTime;
+
+
+/**
+ * @overview Generic array type
+ * @description The MprArray is a dynamic growable array suitable for storing
+ * pointers to arbitrary objects.
+ * @stability Prototype.
+ * @library libmpr.
+ * @see mprCreateItemArray, mprFree, MprBuf
+ */
+typedef struct MprArray
+{
+ int capacity; /* Current capacity of the array */
+ int length; /* Count of used items */
+ int incr; /* Growth increment */
+ int maxSize; /* Maximum capacity */
+ void **items;
+} MprArray;
+
+
+#if BLD_FEATURE_MULTITHREAD
+/**
+ * @overview Multithreading lock control structure
+ * @description MprLock is used for multithread locking in multithreaded
+ * applications.
+ * @library libmpr.
+ * @see mprCreateLock, mprDestroyLock, mprLock, mprUnlock
+ */
+typedef struct
+{
+ #if WIN
+ CRITICAL_SECTION cs; /* O/S critical section */
+ #endif
+ #if LINUX || MACOSX || SOLARIS
+ pthread_mutex_t cs; /* O/S critical section */
+ #endif
+ #if VXWORKS
+ SEM_ID cs; /* Semaphore */
+ #endif
+} MprLock;
+#endif
+
+/*
+ * Error and Logging callback
+ */
+typedef void (*MprLogHandler)(MPR_LOC_DEC(ctx, loc), int flags,
+ int level, const char *msg);
+
+/*
+ * Symbol table
+ * MOB -- rename hash
+ */
+typedef struct MprSymbol
+{
+ struct MprSymbol *next; /* Next symbol in hash chain */
+ char *key; /* Symbol key */
+ void *data; /* Pointer to symbol data */
+ int bucket; /* Hash bucket index */
+} MprSymbol;
+
+typedef struct MprSymbolTable
+{
+ MprSymbol **buckets;
+ int hashSize; /* Size of the buckets array */
+ int count; /* Number of symbols in the table */
+} MprSymbolTable;
+
+
+/*
+ * Memory allocation error callback
+ */
+struct MprApp;
+typedef int (*MprAllocCback)(struct MprApp *app, uint size, uint total,
+ bool granted);
+
+
+/*
+ * Slab block pointer links
+ */
+typedef struct MprSlabBlock {
+ struct MprSlabBlock *next;
+} MprSlabBlock;
+
+
+#if BLD_FEATURE_ALLOC_STATS
+/*
+ * Memory Slab Statistics
+ */
+typedef struct MprSlabStats {
+ uint allocCount; /* Number of allocated blocks */
+ uint freeCount; /* Number of blocks on the slab freelist */
+ uint peakAllocCount; /* Peak allocated */
+ uint totalAllocCount; /* Total count of allocation calls */
+ uint peakFreeCount; /* Peak on the free list */
+ MprSlabBlock *next;
+} MprSlabStats;
+#endif
+
+
+/*
+ * Slab control structure
+ */
+typedef struct MprSlab {
+ MprSlabBlock *next;
+ uint preAllocateIncr; /* Pre-allocation increment */
+#if BLD_FEATURE_ALLOC_STATS
+ MprSlabStats stats;
+#endif
+} MprSlab;
+
+/*
+ * Allocation stats (kept even in production code so we can detect memory
+ * allocation failures)
+ */
+typedef struct MprAllocStats
+{
+ uint bytesAllocated; /* Bytes currently allocated */
+ uint peakAllocated; /* Peak bytes allocated */
+ uint allocCount; /* Number of allocated blocks */
+ uint redLine; /* Warn above this level */
+ uint maxMemory; /* Max memory to allocate */
+ uint errors; /* Allocation errors */
+} MprAllocStats;
+
+/*
+ * Memory allocation control
+ */
+
+typedef struct MprAlloc {
+ MprSlab *slabs; /* Array[MPR_MAX_SLAB] of MprSlab */
+ MprAllocCback cback; /* Memory allocation callback */
+ MprAllocStats stats; /* Keep stats even in release */
+ int inAllocException; /* Recursive protect */
+} MprAlloc;
+
+
+/*
+ * MprApp State Flags
+ */
+#define MPR_APP_EXITING 0x1 /* App is exiting */
+#define MPR_APP_ALLOC_ERROR 0x2 /* App has allocation error */
+
+/* MOB -- temporary */
+#define MPR_APP_NEED_GC 0x4 /* App needs GC */
+
+/**
+ * @overview Primary MPR application control structure
+ * @description The MprApp structure stores critical application state
+ * information and is the root memory allocation context block. It is
+ * used as the MprCtx context for other memory allocations and is thus
+ * the ultimate parent of all allocated memory.
+ * \n\n
+ * The MprApp structure is allocated by the mprInit API.
+ */
+typedef struct MprApp
+{
+ uint magic; /* Corruption protection */
+ MprFile *console; /* Stdout file */
+ bool debugMode; /* Run in debug mode (no timers) */
+ MprFile *error; /* Stderr file */
+ int logLevel; /* Log trace level */
+ MprFile *logFile; /* Log file */
+ MprLogHandler logHandler; /* Current log handler callback */
+ MprSymbolTable *table;
+ char *name; /* Product name */
+ char *title; /* Product title */
+ char *version; /* Product version */
+
+#if BREW
+ uint classId; /* Brew class ID */
+ IShell *shell; /* Brew shell object */
+ IDisplay *display; /* Brew display object */
+ IFileMgr *fileMgr; /* File manager */
+ ITAPI *tapi; /* TAPI object */
+ int displayHeight; /* Display height */
+ int displayWidth; /* Display width */
+ char *args; /* Command line args */
+#endif
+
+ void *stackStart; /* Start of app stack */
+ uint maxStack; /* Max stack size recorded */
+
+ MprAlloc alloc; /* Memory allocation data */
+ int flags; /* App state flags */
+
+#if BLD_FEATURE_MULTITHREAD
+ MprLock *globalLock;
+ MprLock *allocLock;
+#endif
+} MprApp;
+
+
+/*
+ * String type. Minimum size is 8 words (32 bytes).
+ */
+#define MPR_MAX_INLINE_STR 24
+
+
+/*
+ * The block header structure for all allocated memory blocks (32 bytes)
+ * WARNING: Don't increase the size of this structure. It just fits into
+ * 32 bytes currently. Alignment requirements will double this size if you
+ * add one byte!
+ */
+typedef struct MprBlk
+{
+ MprApp *app; /* app is the top level alloc context */
+ struct MprBlk *parent; /* Parent block */
+ struct MprBlk *children; /* First child block */
+ struct MprBlk *next; /* Next sibling */
+ struct MprBlk *prev; /* Previous sibling */
+ MprDestructor destructor; /* Destructor function (optional) */
+ uint size; /* Size of block sans HDR_SIZE */
+ uint flags; /* Allocation flags and magic number */
+#if BLD_FEATURE_ALLOC_LEAK_TRACK
+ const char *location; /* Allocating code (file + line) */
+#endif
+} MprBlk;
+
+/******************************************************************************/
+/****************************** Internal Prototypes ***************************/
+/******************************************************************************/
+
+extern void mprSignalAllocError(MprCtx ctx);
+
+/******************************************************************************/
+/********************************** Prototypes ********************************/
+/******************************************************************************/
+
+extern MprApp *mprInit(MprAllocCback cback);
+extern MprApp *mprInitEx(MprAllocCback cback, void *shell);
+extern void mprTerm(MprApp *app, bool doStats);
+extern void mprSignalExit(MprCtx ctx);
+extern bool mprIsExiting(MprCtx ctx);
+extern bool mprHasAllocError(MprCtx ctx);
+
+#if BLD_DEBUG && UNUSED
+extern MprApp *mprGetApp(MprCtx ctx);
+#else
+#define mprGetApp(ctx) \
+ (((MprBlk*) ((char*) ctx - MPR_BLK_HDR_SIZE))->app)
+#endif
+
+/******************************************************************************/
+
+extern int mprSetKeyValue(MprCtx ctx, const char *key, void *ptr);
+/* MOB -- should this be delete or remove or unset */
+extern int mprRemoveKeyValue(MprCtx ctx, const char *key);
+extern void *mprGetKeyValue(MprCtx ctx, const char *key);
+/* MOB -- should be setAppName, getAppName */
+extern int mprSetAppName(MprCtx ctx, const char *name, const char *title,
+ const char *version);
+extern const char *mprGetAppName(MprCtx ctx);
+extern const char *mprGetAppTitle(MprCtx ctx);
+extern const char *mprGetAppVersion(MprCtx ctx);
+
+/*
+ * File services
+ */
+extern void mprStopFileServices(MprCtx ctx);
+extern int mprStartFileServices(MprCtx ctx);
+
+/*
+ * Item Array
+ */
+#define mprCreateItemArray(ctx, initialSize, maxSize) \
+ mprCreateItemArrayInternal(MPR_LOC_ARGS(ctx), initialSize, \
+ maxSize)
+
+extern MprArray *mprCreateItemArrayInternal(MPR_LOC_DEC(ctx, loc),
+ int initialSize, int maxSize);
+/* MOB -- should be insert not add/delete or insert / remove */
+extern int mprAddItem(MprArray *array, void *item);
+extern void mprClearItems(MprArray *array);
+extern void mprClearAndFreeItems(MprArray *array);
+extern int mprFindItem(MprArray *array, void *item);
+extern void *mprGetFirstItem(MprArray *array, int *lastIndex);
+extern void *mprGetItem(MprArray *array, int index);
+extern int mprGetItemCapacity(MprArray *array);
+extern int mprGetItemCount(MprArray *array);
+extern void *mprGetNextItem(MprArray *array, int *lastIndex);
+extern void *mprGetPrevItem(MprArray *array, int *lastIndex);
+extern int mprRemoveItem(MprArray *array, void *item);
+extern int mprRemoveItemByIndex(MprArray *array, int index);
+extern int mprRemoveRangeOfItems(MprArray *array, int start, int end);
+
+
+/*
+ * Printf replacements
+ */
+extern int mprSprintf(char *buf, int maxSize, const char *fmt, ...)
+ PRINTF_ATTRIBUTE(3,4);
+extern int mprVsprintf(char *buf, int maxSize, const char *fmt,
+ va_list arg) PRINTF_ATTRIBUTE(3,0);
+extern char *mprItoa(char *buf, int size, int value);
+extern int mprAtoi(const char *str, int radix);
+
+extern int mprPrintf(MprCtx ctx, const char *fmt, ...)
+ PRINTF_ATTRIBUTE(2,3);
+/* MOB -- NEED DOC */
+extern int mprErrorPrintf(MprCtx ctx, const char *fmt, ...)
+ PRINTF_ATTRIBUTE(2,3);
+extern int mprStaticPrintf(MprCtx ctx, const char *fmt, ...)
+ PRINTF_ATTRIBUTE(2,3);
+extern int mprPrintfError(MprCtx ctx, const char *fmt, ...)
+ PRINTF_ATTRIBUTE(2,3);
+extern int mprFprintf(MprFile *file, const char *fmt, ...)
+ PRINTF_ATTRIBUTE(2,3);
+
+/*
+ * Safe string routines
+ */
+extern char *mprGetWordTok(char *buf, int bufsize, const char *str,
+ const char *delim, const char **tok);
+extern int mprMemcpy(char *dest, int destMax, const char *src,
+ int nbytes);
+extern int mprStrcat(char *dest, int max, const char *delim,
+ const char *src, ...);
+extern int mprStrcpy(char *dest, int destMax, const char *src);
+
+extern int mprStrcmpAnyCase(const char *str1, const char *str2);
+extern int mprStrcmpAnyCaseCount(const char *str1, const char *str2,
+ int len);
+extern int mprStrlen(const char *src, int max);
+
+extern char *mprStrLower(char *str);
+extern char *mprStrUpper(char *str);
+extern char *mprStrTrim(char *str, const char *set);
+extern char *mprStrTok(char *str, const char *delim, char **last);
+
+/*
+ * Symbol table
+ */
+extern MprSymbolTable *mprCreateSymbolTable(MprCtx ctx, int hashSize);
+extern MprSymbol *mprGetFirstSymbol(MprSymbolTable *table);
+extern MprSymbol *mprGetNextSymbol(MprSymbolTable *table, MprSymbol *last);
+extern int mprGetSymbolCount(MprSymbolTable *table);
+extern MprSymbol *mprInsertSymbol(MprSymbolTable *table, const char *key,
+ void *ptr);
+extern void *mprLookupSymbol(MprSymbolTable *table, const char *key);
+extern int mprRemoveSymbol(MprSymbolTable *table, const char *key);
+
+/*
+ * File I/O support
+ */
+extern void mprClose(MprFile *file);
+extern int mprDelete(MprCtx ctx, const char *path);
+extern int mprDeleteDir(MprCtx ctx, const char *path);
+extern int mprGetFileInfo(MprCtx ctx, const char *path, MprFileInfo *info);
+extern char *mprGets(MprFile *file, char *buf, uint size);
+extern int mprMakeDir(MprCtx ctx, const char *path, int perms);
+extern MprFile *mprOpen(MprCtx ctx, const char *path, int omode, int perms);
+extern int mprPuts(MprFile *file, const char *buf, uint size);
+extern int mprRead(MprFile *file, void *buf, uint size);
+extern int mprSeek(MprFile *file, int seekType, long distance);
+extern int mprWrite(MprFile *file, const void *buf, uint count);
+
+extern int mprMakeTempFileName(MprCtx ctx, char *buf, int bufsize,
+ const char *tmpDir);
+
+
+/*
+ * Error handling and logging
+ */
+extern void mprSetLogHandler(MprCtx ctx, MprLogHandler handler);
+extern MprLogHandler mprGetLogHandler(MprCtx ctx);
+
+extern void mprAssertError(MPR_LOC_DEC(ctx, loc), const char *msg);
+extern void mprError(MPR_LOC_DEC(ctx, loc),
+ const char *fmt, ...) PRINTF_ATTRIBUTE(3,4);
+extern void mprFatalError(MPR_LOC_DEC(ctx, loc),
+ const char *fmt, ...) PRINTF_ATTRIBUTE(3,4);
+extern void mprLog(MprCtx ctx, int level,
+ const char *fmt, ...) PRINTF_ATTRIBUTE(3,4);
+extern void mprRawLog(MprCtx ctx, const char *fmt, ...);
+extern void mprStaticAssert(const char *loc, const char *msg);
+extern void mprStaticError(MPR_LOC_DEC(ctx, loc),
+ const char *fmt, ...) PRINTF_ATTRIBUTE(3,4);
+extern void mprUserError(MPR_LOC_DEC(ctx, loc),
+ const char *fmt, ...) PRINTF_ATTRIBUTE(3,4);
+
+/*
+ * Dynamic Buffering routines
+ */
+extern MprBuf *mprCreateBuf(MprCtx ctx, int initialSize, int maxSize);
+extern char *mprStealBuf(MprCtx ctx, MprBuf *bp);
+extern void mprAddNullToBuf(MprBuf *bp);
+extern void mprAdjustBufStart(MprBuf *bp, int size);
+extern void mprAdjustBufEnd(MprBuf *bp, int size);
+extern void mprCopyBufDown(MprBuf *bp);
+extern void mprFlushBuf(MprBuf *bp);
+extern int mprGetCharFromBuf(MprBuf *bp);
+extern int mprGetBlockFromBuf(MprBuf *bp, uchar *buf, int len);
+extern int mprGetBufLength(MprBuf *bp);
+extern int mprGetBufLinearSpace(MprBuf *bp);
+extern int mprGetBufLinearData(MprBuf *bp);
+extern char *mprGetBufOrigin(MprBuf *bp);
+extern int mprGetBufSize(MprBuf *bp);
+extern int mprGetBufSpace(MprBuf *bp);
+extern char *mprGetBufStart(MprBuf *bp);
+extern char *mprGetBufEnd(MprBuf *bp);
+extern int mprInsertCharToBuf(MprBuf *bp, int c);
+extern int mprLookAtNextCharInBuf(MprBuf *bp);
+extern int mprLookAtLastCharInBuf(MprBuf *bp);
+extern int mprPutCharToBuf(MprBuf *bp, int c);
+extern int mprPutBlockToBuf(MprBuf *bp, const char *str, int size);
+extern int mprPutIntToBuf(MprBuf *bp, int i);
+extern int mprPutStringToBuf(MprBuf *bp, const char *str);
+extern int mprPutFmtStringToBuf(MprBuf *bp, const char *fmt, ...);
+extern int mprRefillBuf(MprBuf *bp);
+extern void mprResetBufIfEmpty(MprBuf *bp);
+extern void mprSetBufSize(MprBuf *bp, int initialSize, int maxSize);
+extern MprBufProc mprGetBufRefillProc(MprBuf *bp);
+extern void mprSetBufRefillProc(MprBuf *bp, MprBufProc fn, void *arg);
+
+/*
+ * General other xPlatform routines
+ */
+extern const char *mprGetBaseName(const char *name);
+extern bool mprGetDebugMode(MprCtx ctx);
+extern char *mprGetDirName(char *buf, int bufsize, const char *path);
+extern char *mprGetFullPathName(char *buf, int buflen, const char *path);
+extern int mprGetLogLevel(MprCtx ctx);
+extern int mprGetOsError();
+
+
+extern int mprMakeArgv(MprCtx ctx, const char *prog, const char *cmd,
+ char ***argv, int *argc);
+extern int mprMakeDirPath(MprCtx ctx, const char *path);
+extern void mprSetDebugMode(MprCtx ctx, bool on);
+extern void mprSetLogLevel(MprCtx ctx, int level);
+extern void mprSleep(MprCtx ctx, int msec);
+extern void mprSetShell(MprCtx ctx, void *shell);
+extern void *mprGetShell(MprCtx ctx);
+extern void mprSetClassId(MprCtx ctx, uint classId);
+extern uint mprGetClassId(MprCtx ctx);
+
+#if BREW
+extern void mprSetDisplay(MprCtx ctx, void *display);
+extern void *mprGetDisplay(MprCtx ctx);
+extern void mprSetFileMgr(MprCtx ctx, void *fileMgr);
+extern void *mprGetFileMgr(MprCtx ctx);
+#else
+extern char *mprInetToStr(char *buf, int size, const struct in_addr in);
+#endif
+
+/*
+ * Memory allocation
+ */
+extern MprApp *mprAllocInit(MprAllocCback cback);
+extern void mprAllocTerm(MprApp *app);
+extern void mprAllocAbort();
+
+extern void *mprAllocBlock(MPR_LOC_DEC(ctx, loc), uint size);
+extern void *mprAllocZeroedBlock(MPR_LOC_DEC(ctx, loc), uint size);
+extern void *mprReallocBlock(MPR_LOC_DEC(ctx, loc), void *ptr, uint size);
+extern int mprFree(void *ptr);
+extern int mprStealAllocBlock(MPR_LOC_DEC(ctx, loc), const void *ptr);
+extern void *mprMemdupInternal(MPR_LOC_DEC(ctx, loc), const void *ptr,
+ uint size);
+extern char *mprStrndupInternal(MPR_LOC_DEC(ctx, loc), const char *str,
+ uint size);
+extern char *mprStrdupInternal(MPR_LOC_DEC(ctx, loc), const char *str);
+
+extern void *mprSlabAllocBlock(MPR_LOC_DEC(ctx, loc), uint size, uint inc);
+extern void *mprSlabAllocZeroedBlock(MPR_LOC_DEC(ctx, loc), uint size,
+ uint inc);
+
+extern uint mprGetAllocBlockSize(MprCtx ctx);
+extern uint mprGetAllocBlockCount(MprCtx ctx);
+extern uint mprGetAllocBlockMemory(MprCtx ctx);
+extern void *mprGetAllocParent(MprCtx ctx);
+extern uint mprGetAllocatedMemory(MprCtx ctx);
+extern uint mprGetPeakAllocatedMemory(MprCtx ctx);
+extern uint mprGetAllocatedSlabMemory(MprCtx ctx);
+extern int mprIsAllocBlockValid(MprCtx ctx);
+extern int mprStackCheck(MprCtx ctx);
+extern int mprStackSize(MprCtx ctx);
+extern int mprGetAllocErrors(MprCtx ctx);
+extern void mprClearAllocErrors(MprCtx ctx);
+
+extern MprDestructor mprSetDestructor(MprCtx ctx, MprDestructor destructor);
+extern MprAllocCback mprSetAllocCallback(MprApp *app, MprAllocCback cback);
+extern void mprSetAllocLimits(MprApp *app, uint redLine, uint maxMemory);
+
+#if BLD_FEATURE_ALLOC_STATS
+extern MprSlabStats *mprGetSlabAllocStats(MprApp *app, int slabIndex);
+extern MprAllocStats *mprGetAllocStats(MprApp *app);
+extern void mprPrintAllocReport(MprApp *app, bool doBlocks,
+ const char *msg);
+#endif
+
+#if BLD_DEBUG
+extern int mprPrintAllocBlocks(MprCtx ctx, int indent);
+extern const char *mprGetAllocLocation(MprCtx ptr);
+#endif
+
+extern int mprValidateBlock(MprCtx ctx);
+extern int mprValidateAllocTree(MprCtx ptr);
+extern void mprSetRequiredAlloc(MprCtx ptr, bool recurse);
+
+/*
+ * Sprintf style allocators
+ */
+extern int mprAllocSprintf(MPR_LOC_DEC(ctx, loc), char **buf, int maxSize,
+ const char *fmt, ...) PRINTF_ATTRIBUTE(5,6);
+extern int mprAllocVsprintf(MPR_LOC_DEC(ctx, loc), char **buf, int maxSize,
+ const char *fmt, va_list arg) PRINTF_ATTRIBUTE(5,0);
+extern int mprAllocMemcpy(MPR_LOC_DEC(ctx, loc), char **dest, int destMax,
+ const void *src, int nbytes);
+extern int mprAllocStrcat(MPR_LOC_DEC(ctx, loc), char **dest, int max,
+ const char *delim, const char *src, ...);
+extern int mprAllocStrcpy(MPR_LOC_DEC(ctx, loc), char **dest, int max,
+ const char *src);
+extern int mprReallocStrcat(MPR_LOC_DEC(ctx, loc), char **dest, int max,
+ int existingLen, const char *delim, const char *src, ...);
+
+/*
+ * MACROS: These are the convenience macros to automatically supply file
+ * names and line numbers when debugging.
+ */
+#define mprNew(ctx) new(MPR_LOC_ARGS(ctx))
+
+#define mprAlloc(ctx, size) mprAllocBlock(MPR_LOC_ARGS(ctx), size)
+
+#define mprAllocZeroed(ctx, size) mprAllocZeroedBlock(MPR_LOC_ARGS(ctx), size)
+
+#define mprSlabAlloc(ctx, size, inc) \
+ ((type*) mprSlabAllocBlock(MPR_LOC_ARGS(ctx), size, inc))
+
+#define mprSlabAllocZeroed(ctx, size, inc) \
+ ((type*) mprSlabAllocBlock(MPR_LOC_ARGS(ctx), size, inc))
+
+#define mprRealloc(ctx, ptr, size) mprReallocBlock(MPR_LOC_ARGS(ctx), ptr, size)
+
+#define mprMemdup(ctx, ptr, size) \
+ mprMemdupInternal(MPR_LOC_ARGS(ctx), ptr, size)
+
+#define mprStrdup(ctx, str) mprStrdupInternal(MPR_LOC_ARGS(ctx), str)
+
+#define mprStrndup(ctx, str, size) mprStrndupDebug(MPR_LOC_ARGS(ctx), str, size)
+
+/*
+ * Allocate type macros
+ */
+#define mprAllocType(ctx, type) \
+ ((type*) mprAllocBlock(MPR_LOC_ARGS(ctx), sizeof(type)))
+
+#define mprAllocTypeZeroed(ctx, type) \
+ ((type*) mprAllocZeroedBlock(MPR_LOC_ARGS(ctx), sizeof(type)))
+
+#define mprSlabAllocType(ctx, type, inc) \
+ ((type*) mprSlabAllocBlock(MPR_LOC_ARGS(ctx), sizeof(type), inc))
+
+#define mprSlabAllocTypeZeroed(ctx, type, inc) \
+ ((type*) mprSlabAllocZeroedBlock(MPR_LOC_ARGS(ctx), sizeof(type), \
+ inc))
+
+/*
+ * Multithread locking
+ */
+#if BLD_FEATURE_MULTITHREAD
+extern void mprInitThreads(MprApp *app);
+extern void mprTermThreads(MprApp *app);
+extern MprLock *mprCreateLock(MprCtx ctx);
+extern void mprDestroyLock(MprLock *lock);
+extern void mprLock(MprLock *lock);
+extern int mprTryLock(MprLock *lock);
+extern void mprUnlock(MprLock *lock);
+extern void mprGlobalLock(MprCtx ctx);
+extern void mprGlobalUnlock(MprCtx ctx);
+extern int mprGetCurrentThreadID();
+#else
+/*
+ * Disable multithreading
+ */
+#define mprInitThreads(ctx, app)
+#define mprTermThreads(app)
+#define mprCreateLock(ctx)
+#define mprDestroyLock(lock)
+#define mprLock(lock)
+#define mprTryLock(lock)
+#define mprUnlock(lock)
+#define mprGlobalLock(app)
+#define mprGlobalUnlock(app)
+#define mprGetCurrentThreadID()
+#endif
+
+/*
+ * Time
+ */
+extern MprTime *mprGetTime(MprCtx ctx, MprTime *tp);
+extern int mprGetTimeRemaining(MprCtx ctx, MprTime mark, uint timeout);
+extern int mprGetElapsedTime(MprCtx ctx, MprTime mark);
+extern int mprCompareTime(MprTime *t1, MprTime *t2);
+extern uint mprSubtractTime(MprTime *t1, MprTime *t2);
+extern void mprAddElapsedToTime(MprTime *time, uint elapsed);
+
+#if !BREW
+extern int mprAsctime(MprCtx ctx, char *buf, int bufsize,
+ const struct tm *timeptr);
+extern int mprCtime(MprCtx ctx, char *buf, int bufsize,
+ const time_t *timer);
+extern struct tm *mprLocaltime(MprCtx ctx, struct tm *timep, time_t *now);
+extern struct tm *mprGmtime(MprCtx ctx, time_t* now, struct tm *timep);
+extern int mprRfcTime(MprCtx ctx, char *buf, int bufsize,
+ const struct tm *timep);
+#endif /* !BREW */
+
+/*
+ * Host name
+ */
+extern struct hostent* mprGetHostByName(MprCtx ctx, const char *name);
+
+#if WIN
+extern int mprReadRegistry(MprCtx ctx, char **buf, int max,
+ const char *key, const char *val);
+extern int mprWriteRegistry(MprCtx ctx, const char *key, const char *name,
+ const char *value);
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _h_MPR */
+
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim:tw=78
+ * vim600: sw=4 ts=4 fdm=marker
+ * vim<600: sw=4 ts=4
+ */
diff --git a/source4/lib/appweb/ejs-2.0/mpr/mprAlloc.c b/source4/lib/appweb/ejs-2.0/mpr/mprAlloc.c
new file mode 100644
index 0000000000..6fcaa63a6c
--- /dev/null
+++ b/source4/lib/appweb/ejs-2.0/mpr/mprAlloc.c
@@ -0,0 +1,1775 @@
+/**
+ * @file mprAlloc.c
+ * @brief Memory Allocation
+ * @overview
+ */
+
+/*
+ * @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 ***********************************/
+
+#define UNSAFE_FUNCTIONS_OK 1
+
+#include "mpr.h"
+
+/******************************* Local Defines ********************************/
+/*
+ * Set to 1 to disable slab based allocations
+ */
+#define NO_SLAB 0
+
+/*
+ * Validation mode is quite slow
+ */
+#define VALIDATE_ALLOC 0
+#if VALIDATE_ALLOC
+#define VALIDATE_BLOCK(ptr) mprValidateBlock(ptr)
+#else
+#define VALIDATE_BLOCK(ptr)
+#endif
+
+/*
+ * Align on 4 bytes if squeeze, Otherwize on 16 bytes.
+ */
+#define HDR_SIZE MPR_BLK_HDR_SIZE
+
+#define APP_MAGIC 0xa571cb80
+#define ALLOC_MAGIC 0xe814ecc0
+
+/*
+ * This must be at least one word to ensure that the smallest allocation is
+ * 4 bytes. Slab allocations need at least one word to store their next ptr.
+ */
+#define ALLOC_ALIGN(x) (((x)+3)&~3)
+#define GET_HDR(ptr) ((MprBlk*) (((char*) (ptr)) - HDR_SIZE))
+#define GET_PTR(bp) ((void*) (((char*) (bp)) + HDR_SIZE))
+#define VALID_HDR(bp) (((bp)->flags & ~0x3F) == ALLOC_MAGIC)
+#define VALID_BLK(ptr) (VALID_HDR(GET_HDR(ptr)))
+
+/*
+ * In production releases, mprAssert will compile out (not be included)
+ * but CHECK_HDR will remain even in production builds.
+ */
+#define CHECK_HDR(bp) \
+ if (1) { if (! VALID_HDR(bp)) { mprAllocAbort(); } } else
+
+/*
+ * Chunk the slabs into 32 byte increments.
+ * This allows for allocations up to 512 bytes via slabs and maximizes
+ * sharing of slab allocations.
+ *
+ * Index map:
+ * 0 == 32 bytes
+ * 1 == 64 bytes
+ * 2 == 96 bytes
+ * 3 == 128 bytes
+ * 4 == 160 bytes
+ * 5 == 192 bytes
+ * 6 == 224 bytes
+ * 7 == 256 bytes
+ * 8 == 288 bytes
+ * 9 == 320 bytes
+ * 10 == 352 bytes
+ * 11 == 384 bytes
+ * 12 == 416 bytes
+ * 13 == 448 bytes
+ * 14 == 480 bytes
+ * 15 == 512 bytes
+ */
+#define SLAB_ALIGN(size) ((size + 31) & ~31)
+#define GET_SLAB(size) (size >> 6)
+
+/*
+ * Block flags
+ */
+#define ALLOC_FLAGS_FREE 0x1 /* Block is free */
+#define ALLOC_FLAGS_FREEING 0x2 /* Block is being freed */
+#define ALLOC_FLAGS_SLAB_BLOCK 0x4 /* Block was allocated from slab */
+#define ALLOC_FLAGS_REQUIRED 0x8 /* Block is required by alloc */
+#define ALLOC_FLAGS_KEEP 0x10 /* Keep block - don't mprFree */
+#define ALLOC_FLAGS_DONT_OS_FREE 0x20 /* Don't return mem to O/S */
+#define ALLOC_FLAGS_IS_SLAB 0x40 /* Block is a slab */
+
+#if BLD_DEBUG && !BREW
+/*
+ * Set this address to break when this address is allocated or freed. This is
+ * a block address (not a user ptr).
+ */
+static MprBlk *stopAlloc;
+#endif
+
+#if !BREW
+static MprCtx rootCtx; /* Root context if none supplied */
+#endif
+
+/***************************** Forward Declarations ***************************/
+
+static int mprAllocException(MPR_LOC_DEC(ptr, loc), uint size, bool granted);
+static void slabFree(MprBlk *bp);
+static int growSlab(MPR_LOC_DEC(ctx, loc), MprSlab *slab, uint size, uint inc);
+
+/******************************************************************************/
+/*
+ * Put first in file so it is easy to locate in a debugger
+ */
+
+void mprBreakpoint(const char *loc, const char *msg)
+{
+}
+
+/******************************************************************************/
+#if (WIN || BREW_SIMULATOR) && BLD_DEBUG
+
+int crtReportHook(int type, char *msg, int *retval)
+{
+ printf("%s\n", msg);
+ *retval = 0;
+ return TRUE;
+}
+
+#endif
+/******************************************************************************/
+/*
+ * Initialize the memory subsystem
+ */
+
+MprApp *mprAllocInit(MprAllocCback cback)
+{
+ MprAllocStats *stats;
+ MprApp *app;
+ MprSlab *slab;
+ MprBlk *bp, *sp;
+ int i;
+
+ bp = malloc(sizeof(MprApp) + HDR_SIZE);
+ mprAssert(bp);
+ if (bp == 0) {
+ if (cback) {
+ (*cback)(0, sizeof(MprApp), 0, 0);
+ }
+ return 0;
+ }
+ memset(bp, 0, sizeof(MprApp) + HDR_SIZE);
+
+ bp->parent = bp;
+ bp->size = sizeof(MprApp);
+ bp->flags = ALLOC_MAGIC;
+ bp->next = bp->prev = bp;
+
+#if BLD_FEATURE_ALLOC_LEAK_TRACK
+ bp->location = MPR_LOC;
+#endif
+
+ app = (MprApp*) GET_PTR(bp);
+ app->magic = APP_MAGIC;
+
+ app->alloc.cback = cback;
+ app->stackStart = (void*) &app;
+
+ bp->app = app;
+
+ app->alloc.slabs = mprAllocZeroedBlock(MPR_LOC_PASS(app, MPR_LOC),
+ sizeof(MprSlab) * MPR_MAX_SLAB);
+ if (app->alloc.slabs == 0) {
+ mprFree(app);
+ return 0;
+ }
+
+ /*
+ * The slab control structures must not be freed. Set keep to safeguard
+ * against accidents.
+ */
+ sp = GET_HDR(app->alloc.slabs);
+ sp->flags |= ALLOC_FLAGS_KEEP;
+
+ for (i = 0; i < MPR_MAX_SLAB; i++) {
+ /*
+ * This is overriden by requestors calling slabAlloc
+ */
+ slab = &app->alloc.slabs[i];
+ slab->preAllocateIncr = MPR_SLAB_DEFAULT_INC;
+ }
+
+ /*
+ * Keep aggregated stats even in production code
+ */
+ stats = &app->alloc.stats;
+ stats->bytesAllocated += sizeof(MprApp);
+ if (stats->bytesAllocated > stats->peakAllocated) {
+ stats->peakAllocated = stats->bytesAllocated;
+ }
+ stats->allocCount++;
+
+#if !BREW
+ rootCtx = app;
+#endif
+#if (WIN || BREW_SIMULATOR) && BLD_DEBUG
+ _CrtSetReportHook(crtReportHook);
+#endif
+ return app;
+}
+
+/******************************************************************************/
+/*
+ * Terminate the alloc module
+ */
+
+void mprAllocTerm(MprApp *app)
+{
+ MprSlab *slabs;
+ MprBlk *appBlk, *slabBlk;
+
+ /*
+ * Must do a carefully ordered cleanup. Need to free all children blocks
+ * before freeing the slab memory. Save a local pointer to the slabs.
+ */
+ slabs = app->alloc.slabs;
+
+ /*
+ * Free the app and all children. Set DONT_OS_FREE to prevent free() being
+ * called on app itself. We need that so we can free the slabs below.
+ */
+ appBlk = GET_HDR(app);
+ appBlk->flags |= ALLOC_FLAGS_DONT_OS_FREE;
+ mprFree(app);
+
+ /*
+ * Slabs are initially marked don't free. We must preserve them while all
+ * other blocks are freed. Then we clear the don't free flag and free.
+ * Now we don't have an app structure which is used by mprFree. We must
+ * fake it.
+ */
+ slabBlk = GET_HDR(slabs);
+ slabBlk->flags &= ~ALLOC_FLAGS_KEEP;
+ mprFree(slabs);
+
+ /*
+ * Now we can finally free the memory for the app structure
+ */
+ free(appBlk);
+}
+
+/******************************************************************************/
+/*
+ * Allocate a block
+ */
+
+void *mprAllocBlock(MPR_LOC_DEC(ctx, loc), uint size)
+{
+ MprAllocStats *stats;
+ MprBlk *bp, *parent;
+ MprApp *app;
+ int diff;
+
+ mprAssert(size > 0);
+
+ if (ctx == 0) {
+#if BREW
+ mprAssert(ctx);
+ return 0;
+#else
+ ctx = rootCtx;
+#endif
+ }
+ if (size == 0) {
+ size = 1;
+ }
+
+ mprAssert(VALID_BLK(ctx));
+ parent = GET_HDR(ctx);
+ mprAssert(VALID_HDR(parent));
+
+ CHECK_HDR(parent);
+
+ size = ALLOC_ALIGN(size);
+
+ app = parent->app;
+
+ stats = &app->alloc.stats;
+
+ mprLock(app->allocLock);
+
+ stats->bytesAllocated += size + HDR_SIZE;
+ if (stats->bytesAllocated > stats->peakAllocated) {
+ stats->peakAllocated = stats->bytesAllocated;
+ }
+
+ /*
+ * Prevent allocation if over the maximum
+ */
+ if (stats->maxMemory && stats->bytesAllocated > stats->maxMemory) {
+ stats->bytesAllocated -= (size + HDR_SIZE);
+ mprUnlock(app->allocLock);
+ if (mprAllocException(MPR_LOC_PASS(ctx, loc), size, 0) < 0) {
+ return 0;
+ }
+ mprLock(app->allocLock);
+ }
+
+ if ((bp = malloc(size + HDR_SIZE)) == 0) {
+ mprAssert(bp);
+ stats->errors++;
+ mprUnlock(app->allocLock);
+ mprAllocException(MPR_LOC_PASS(ctx, loc), size, 0);
+ return 0;
+ }
+
+#if BLD_DEBUG
+ memset(bp, 0xf7, size + HDR_SIZE);
+#endif
+
+#if BLD_DEBUG && !BREW
+ if (bp == stopAlloc) {
+ mprBreakpoint(MPR_LOC, "breakOnAddr");
+ }
+#endif
+
+ /*
+ * Warn if allocation puts us over the red line
+ */
+ if (stats->redLine && stats->bytesAllocated > stats->redLine) {
+ mprUnlock(app->allocLock);
+ if (mprAllocException(MPR_LOC_PASS(ctx, loc), size, 1) < 0) {
+ return 0;
+ }
+ mprLock(app->allocLock);
+ }
+
+ bp->size = size;
+ bp->flags = ALLOC_MAGIC;
+ bp->destructor = 0;
+
+ bp->parent = parent;
+
+ if (parent->children == 0) {
+ parent->children = bp;
+ bp->next = bp->prev = bp;
+
+ } else {
+ /*
+ * Append to the end of the list. Preserve alloc order
+ */
+ bp->next = parent->children;
+ bp->prev = parent->children->prev;
+ parent->children->prev->next = bp;
+ parent->children->prev = bp;
+ }
+
+ bp->children = 0;
+
+#if BLD_FEATURE_ALLOC_LEAK_TRACK
+ bp->location = loc;
+#endif
+
+ bp->app = parent->app;
+
+ VALIDATE_BLOCK(GET_PTR(bp));
+
+ stats->allocCount++;
+
+ /*
+ * Monitor stack usage
+ */
+ diff = (int) bp->app->stackStart - (int) &stats;
+ if (diff < 0) {
+ app->maxStack -= diff;
+ app->stackStart = (void*) &stats;
+ diff = 0;
+ }
+
+ if ((uint) diff > app->maxStack) {
+ app->maxStack = diff;
+ }
+ mprUnlock(app->allocLock);
+
+ return GET_PTR(bp);
+}
+
+/******************************************************************************/
+/*
+ * Allocate and zero a block
+ */
+
+void *mprAllocZeroedBlock(MPR_LOC_DEC(ctx, loc), uint size)
+{
+ void *newBlock;
+
+ MprBlk *bp;
+
+ bp = GET_HDR(ctx);
+ mprAssert(VALID_BLK(ctx));
+
+ newBlock = mprAllocBlock(MPR_LOC_PASS(ctx, loc), size);
+ if (newBlock) {
+ memset(newBlock, 0, size);
+ }
+ return newBlock;
+}
+
+/******************************************************************************/
+/*
+ * Free a block of memory. Free all children recursively.
+ */
+
+int mprFree(void *ptr)
+{
+ MprAllocStats *stats;
+ MprBlk *bp, *parent, *cp, *firstChild, *prev;
+ MprApp *app;
+
+ if (ptr == 0) {
+ return 0;
+ }
+
+ mprAssert(VALID_BLK(ptr));
+ VALIDATE_BLOCK(ptr);
+
+ bp = GET_HDR(ptr);
+
+#if BLD_DEBUG && !BREW
+ if (bp == stopAlloc) {
+ mprBreakpoint(MPR_LOC, "breakOnAddr");
+ }
+#endif
+
+ mprAssert(bp);
+ mprAssert(VALID_HDR(bp));
+
+ CHECK_HDR(bp);
+
+ /*
+ * Test if already freed
+ */
+ mprAssert(! (bp->flags & ALLOC_FLAGS_FREE));
+ if (bp->flags & ALLOC_FLAGS_FREE) {
+ return 0;
+ }
+
+ /*
+ * Return if recursive freeing or this is a permanent block
+ */
+ app = bp->app;
+ mprLock(app->allocLock);
+ if (bp->flags & (ALLOC_FLAGS_FREEING | ALLOC_FLAGS_KEEP)) {
+ mprUnlock(app->allocLock);
+ return 0;
+ }
+ bp->flags |= ALLOC_FLAGS_FREEING;
+
+
+ /*
+ * Call any destructors
+ */
+ if (bp->destructor) {
+ mprUnlock(app->allocLock);
+ if ((bp->destructor)(ptr) < 0) {
+ return -1;
+ }
+ mprLock(app->allocLock);
+ bp->destructor = 0;
+ }
+
+ /*
+ * Free the children. Free in reverse order so firstChild is preserved
+ * during the list scan as an end of list marker.
+ */
+ if ((firstChild = bp->children) != 0) {
+ cp = firstChild->prev;
+ while (cp != firstChild) {
+
+ mprAssert(VALID_HDR(cp));
+ VALIDATE_BLOCK(GET_PTR(cp));
+
+ prev = cp->prev;
+
+ /*
+ * FUTURE - OPT. Make this inline
+ */
+ mprFree(GET_PTR(cp));
+
+ cp = prev;
+ }
+
+ mprFree(GET_PTR(firstChild));
+
+ /*
+ * Just for clarity
+ */
+ bp->children = 0;
+ }
+
+ parent = bp->parent;
+
+ mprAssert(VALID_HDR(parent));
+
+ /*
+ * Unlink from the parent
+ */
+ if (parent->children == bp) {
+ if (bp->next == bp) {
+ parent->children = 0;
+ } else {
+ parent->children = bp->next;
+ }
+ }
+
+ /*
+ * Remove from the sibling chain
+ */
+ bp->prev->next = bp->next;
+ bp->next->prev = bp->prev;
+
+ bp->flags |= ALLOC_FLAGS_FREE;
+
+ /*
+ * Release the memory. If from a slab, return to the slab. Otherwise,
+ * return to the O/S.
+ */
+ if (bp->flags & ALLOC_FLAGS_SLAB_BLOCK) {
+ slabFree(bp);
+
+ } else {
+ mprAssert(bp);
+
+ /*
+ * Update the stats
+ */
+ stats = &bp->app->alloc.stats;
+ stats->bytesAllocated -= (bp->size + HDR_SIZE);
+ mprAssert(stats->bytesAllocated >= 0);
+
+ stats->allocCount--;
+ mprAssert(stats->allocCount >= 0);
+
+#if BLD_DEBUG && !BREW
+ if (bp == stopAlloc) {
+ mprBreakpoint(MPR_LOC, "breakOnAddr");
+ }
+#endif
+
+ /*
+ * Return to the O/S
+ */
+ if (! (bp->flags & ALLOC_FLAGS_DONT_OS_FREE)) {
+ free(bp);
+ }
+ }
+ /* OPT */
+ if (app != ptr) {
+ mprUnlock(app->allocLock);
+ }
+
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * Rallocate a block
+ */
+
+void *mprReallocBlock(MPR_LOC_DEC(ctx, loc), void *ptr, uint size)
+{
+ MprBlk *bp, *newbp, *firstChild, *cp;
+ MprApp *app;
+ void *newPtr;
+
+ mprAssert(VALID_BLK(ctx));
+ mprAssert(size > 0);
+
+ if (ptr == 0) {
+ return mprAllocBlock(MPR_LOC_PASS(ctx, loc), size);
+ }
+
+ mprAssert(VALID_BLK(ptr));
+ bp = GET_HDR(ptr);
+ mprAssert(bp);
+ mprAssert(VALID_HDR(bp));
+
+ CHECK_HDR(bp);
+
+ if (size < bp->size) {
+ return ptr;
+ }
+
+ newPtr = mprAllocBlock(MPR_LOC_PASS(ctx, loc), size);
+ if (newPtr == 0) {
+ bp->flags &= ~ALLOC_FLAGS_FREE;
+ free(bp);
+ return 0;
+ }
+
+ newbp = GET_HDR(newPtr);
+ mprAssert(newbp->size >= size);
+ memcpy((char*) newbp + HDR_SIZE, (char*) bp + HDR_SIZE, bp->size);
+ mprAssert(newbp->size >= size);
+
+ /*
+ * Fix the next / prev pointers
+ */
+ app = bp->app;
+ mprLock(app->allocLock);
+ newbp->next->prev = newbp;
+ newbp->prev->next = newbp;
+
+ /*
+ * Need to fix the parent pointer of all children
+ */
+ if ((firstChild = newbp->children) != 0) {
+ cp = firstChild;
+ do {
+ cp->parent = newbp;
+ cp = cp->next;
+ } while (cp != firstChild);
+ }
+
+ /*
+ * May need to set the children pointer of our parent
+ */
+ if (newbp->parent->children == bp) {
+ newbp->parent->children = newbp;
+ }
+
+ /*
+ * Free the original block
+ */
+ mprFree(ptr);
+
+ mprUnlock(app->allocLock);
+
+ return GET_PTR(newbp);
+}
+
+/******************************************************************************/
+/*
+ * Allocate a block from a slab
+ */
+
+void *mprSlabAllocBlock(MPR_LOC_DEC(ctx, loc), uint size, uint inc)
+{
+
+#if NO_SLAB
+ return mprAllocBlock(MPR_LOC_PASS(ctx, loc), size);
+#else
+
+ MprBlk *parent, *bp;
+ MprSlabBlock *sb;
+ MprApp *app;
+ MprSlab *slab;
+ int slabIndex;
+
+ if (ctx == 0) {
+ mprAssert(ctx);
+ return 0;
+ }
+
+ mprAssert(size > 0);
+ mprAssert(VALID_BLK(ctx));
+
+ parent = GET_HDR(ctx);
+ mprAssert(VALID_HDR(parent));
+
+ CHECK_HDR(parent);
+
+ size = SLAB_ALIGN(size);
+
+ app = parent->app;
+ mprAssert(app);
+
+ slabIndex = GET_SLAB(size);
+
+ if (slabIndex < 0 || slabIndex >= MPR_MAX_SLAB) {
+ return mprAllocBlock(MPR_LOC_PASS(ctx, loc), size);
+ }
+
+ /*
+ * Dequeue a block from the slab. "sb" will point to the user data
+ * portion of the block (i.e. after the MprBlk header). Slabs must be
+ * allocated off the "slabs" context to ensure they don't get freed
+ * until after all other blocks are freed.
+ */
+ mprLock(app->allocLock);
+ slab = &app->alloc.slabs[slabIndex];
+ if ((sb = slab->next) == 0) {
+ if (growSlab(MPR_LOC_ARGS(parent->app->alloc.slabs),
+ slab, size, inc) < 0) {
+ mprUnlock(app->allocLock);
+ return 0;
+ }
+ sb = slab->next;
+ }
+ mprAssert(sb);
+
+ /*
+ * Dequeue the block
+ */
+ slab->next = sb->next;
+
+#if BLD_FEATURE_ALLOC_STATS
+{
+ MprSlabStats *slabStats;
+ /*
+ * Update the slab stats
+ */
+ slabStats = &slab->stats;
+ slabStats->totalAllocCount++;
+ slabStats->freeCount--;
+ slabStats->allocCount++;
+ if (slabStats->allocCount > slabStats->peakAllocCount) {
+ slabStats->peakAllocCount = slabStats->allocCount;
+ }
+}
+#endif /* BLD_FEATURE_ALLOC_STATS */
+
+ bp = GET_HDR(sb);
+
+#if BLD_DEBUG && !BREW
+ if (bp == stopAlloc) {
+ mprBreakpoint(MPR_LOC, "breakOnAddr");
+ }
+#endif
+
+ bp->size = size;
+ bp->flags = ALLOC_MAGIC | ALLOC_FLAGS_SLAB_BLOCK;
+ bp->destructor = 0;
+
+ bp->parent = parent;
+
+ if (parent->children == 0) {
+ parent->children = bp;
+ bp->next = bp->prev = bp;
+
+ } else {
+ /*
+ * Append to the end of the list. Preserve alloc order
+ */
+ bp->next = parent->children;
+ bp->prev = parent->children->prev;
+ parent->children->prev->next = bp;
+ parent->children->prev = bp;
+ }
+
+ bp->children = 0;
+
+ bp->app = app;
+
+#if BLD_FEATURE_ALLOC_LEAK_TRACK
+ bp->location = loc;
+#endif
+ mprUnlock(app->allocLock);
+
+ return GET_PTR(bp);
+#endif
+}
+
+/******************************************************************************/
+/*
+ * Return a block back to its slab
+ */
+
+static void slabFree(MprBlk *bp)
+{
+ MprSlab *slab;
+ MprApp *app;
+ void *ptr;
+ int slabIndex;
+
+ mprAssert(VALID_HDR(bp));
+
+ slabIndex = GET_SLAB(bp->size);
+ mprAssert(0 <= slabIndex && slabIndex < MPR_MAX_SLAB);
+
+ if (0 <= slabIndex && slabIndex < MPR_MAX_SLAB) {
+ mprLock(bp->app->allocLock);
+ slab = &bp->app->alloc.slabs[slabIndex];
+ app = bp->app;
+
+#if BLD_DEBUG
+ memset(bp, 0xfc, bp->size + HDR_SIZE);
+#endif
+
+ ptr = GET_PTR(bp);
+ ((MprSlabBlock*) ptr)->next = slab->next;
+ slab->next = ((MprSlabBlock*) ptr);
+
+#if BLD_FEATURE_ALLOC_STATS
+{
+ MprSlabStats *slabStats;
+ slabStats = &slab->stats;
+
+ slabStats->freeCount++;
+ slabStats->allocCount--;
+
+ if (slabStats->freeCount >= slabStats->peakFreeCount) {
+ slabStats->peakFreeCount = slabStats->freeCount;
+ }
+}
+#endif
+ mprUnlock(app->allocLock);
+ }
+}
+
+/******************************************************************************/
+/*
+ * Grow the slab and return the next free block
+ * Must be called locked.
+ */
+
+static int growSlab(MPR_LOC_DEC(ctx, loc), MprSlab *slab, uint size, uint inc)
+{
+ MprBlk *bp;
+ MprSlabBlock *sb;
+ int i, chunkSize, len;
+
+ mprAssert(VALID_BLK(ctx));
+ mprAssert(slab);
+ mprAssert(size > 0);
+
+ /*
+ * Take the maximum requested by anyone
+ */
+ slab->preAllocateIncr = max(slab->preAllocateIncr, inc);
+
+ /*
+ * We allocate an array of blocks each of user "size" bytes.
+ */
+ chunkSize = HDR_SIZE + size;
+ len = chunkSize * slab->preAllocateIncr;
+ bp = mprAllocBlock(MPR_LOC_PASS(ctx, loc), len);
+
+#if BLD_DEBUG
+ memset(bp, 0xf1, len);
+#endif
+
+ if (bp == 0) {
+ mprAssert(0);
+ return MPR_ERR_MEMORY;
+ }
+ bp->flags |= ALLOC_FLAGS_IS_SLAB;
+
+ /*
+ * We store the slab information in the user data portion
+ */
+ sb = (MprSlabBlock*) GET_PTR(bp);
+
+
+ sb = (MprSlabBlock*) ((char*) sb + len - chunkSize);
+ for (i = slab->preAllocateIncr - 1; i >= 0; i--) {
+ sb->next = slab->next;
+ slab->next = sb;
+ sb = (MprSlabBlock*) ((char*) sb - chunkSize);
+ }
+
+#if BLD_FEATURE_ALLOC_STATS
+{
+ MprSlabStats *stats;
+ stats = &slab->stats;
+ stats->freeCount += slab->preAllocateIncr;
+ if (stats->freeCount > stats->peakFreeCount) {
+ stats->peakFreeCount = stats->freeCount;
+ }
+}
+#endif
+
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * Set the pre-allocate amount
+ */
+
+int mprSetSlabPreAllocate(MprCtx ctx, int slabIndex, int preAllocateIncr)
+{
+ MprApp *app;
+ MprSlab *slab;
+
+ mprAssert(VALID_BLK(ctx));
+ mprAssert(0 <= slabIndex && slabIndex < MPR_MAX_SLAB);
+ mprAssert(preAllocateIncr > 0);
+
+ if (0 <= slabIndex && slabIndex < MPR_MAX_SLAB) {
+ app = mprGetApp(ctx);
+ slab = &app->alloc.slabs[slabIndex];
+ slab->preAllocateIncr = preAllocateIncr;
+ } else {
+ return MPR_ERR_BAD_ARGS;
+ }
+ return 0;
+}
+
+/******************************************************************************/
+
+void *mprSlabAllocZeroedBlock(MPR_LOC_DEC(ctx, loc), uint size, uint inc)
+{
+ void *newBlock;
+
+ mprAssert(VALID_BLK(ctx));
+ mprAssert(size > 0);
+
+ newBlock = mprSlabAllocBlock(MPR_LOC_PASS(ctx, loc), size, inc);
+ if (newBlock) {
+ memset(newBlock, 0, size);
+ }
+ return newBlock;
+}
+
+/******************************************************************************/
+/*
+ * Internal strdup function. Will use the slab allocator for small strings
+ */
+
+char *mprStrdupInternal(MPR_LOC_DEC(ctx, loc), const char *str)
+{
+ char *newp;
+ int len;
+
+ mprAssert(VALID_BLK(ctx));
+
+ if (str == 0) {
+ str = "";
+ }
+
+ len = strlen(str) + 1;
+
+ if (len < MPR_SLAB_STR_MAX) {
+ newp = mprSlabAllocBlock(MPR_LOC_PASS(ctx, loc), MPR_SLAB_STR_MAX,
+ MPR_SLAB_STR_INC);
+ } else {
+ newp = mprAllocBlock(MPR_LOC_PASS(ctx, loc), len);
+ }
+
+ if (newp) {
+ memcpy(newp, str, len);
+ }
+
+ return newp;
+}
+
+/******************************************************************************/
+/*
+ * Internal strndup function. Will use the slab allocator for small strings
+ */
+
+char *mprStrndupInternal(MPR_LOC_DEC(ctx, loc), const char *str, uint size)
+{
+ char *newp;
+ uint len;
+
+ mprAssert(VALID_BLK(ctx));
+
+ if (str == 0) {
+ str = "";
+ }
+ len = strlen(str) + 1;
+ len = min(len, size);
+
+ if (len < MPR_SLAB_STR_MAX) {
+ newp = mprSlabAllocBlock(MPR_LOC_PASS(ctx, loc), MPR_SLAB_STR_MAX,
+ MPR_SLAB_STR_INC);
+ } else {
+ newp = mprAllocBlock(MPR_LOC_PASS(ctx, loc), len);
+ }
+
+ if (newp) {
+ memcpy(newp, str, len);
+ }
+
+ return newp;
+}
+
+/******************************************************************************/
+/*
+ * Internal memcpy function. Will use the slab allocator for small strings
+ */
+
+void *mprMemdupInternal(MPR_LOC_DEC(ctx, loc), const void *ptr, uint size)
+{
+ char *newp;
+
+ mprAssert(VALID_BLK(ctx));
+
+ if (size < MPR_SLAB_STR_MAX) {
+ newp = mprSlabAllocBlock(MPR_LOC_PASS(ctx, loc), MPR_SLAB_STR_MAX,
+ MPR_SLAB_STR_INC);
+ } else {
+ newp = mprAllocBlock(MPR_LOC_PASS(ctx, loc), size);
+ }
+
+ if (newp) {
+ memcpy(newp, ptr, size);
+ }
+
+ return newp;
+}
+
+/******************************************************************************/
+/*
+ * Steal a block from one context and insert in another
+ */
+
+int mprStealAllocBlock(MPR_LOC_DEC(ctx, loc), const void *ptr)
+{
+ MprBlk *bp, *parent;
+
+ if (ptr == 0) {
+ return 0;
+ }
+
+ mprAssert(VALID_BLK(ctx));
+ mprAssert(VALID_BLK(ptr));
+
+ bp = GET_HDR(ptr);
+
+#if BLD_DEBUG && !BREW
+ if (bp == stopAlloc) {
+ mprBreakpoint(MPR_LOC, "breakOnAddr");
+ }
+#endif
+
+ mprAssert(bp);
+ mprAssert(VALID_HDR(bp));
+ mprAssert(ptr != mprGetAllocParent(ptr));
+
+ CHECK_HDR(bp);
+
+ mprAssert(bp->prev);
+ mprAssert(bp->prev->next);
+ mprAssert(bp->next);
+ mprAssert(bp->next->prev);
+
+ parent = bp->parent;
+ mprAssert(VALID_HDR(parent));
+
+ mprLock(bp->app->allocLock);
+ if (parent->children == bp) {
+ if (bp->next == bp) {
+ parent->children = 0;
+ } else {
+ parent->children = bp->next;
+ }
+ }
+
+ bp->prev->next = bp->next;
+ bp->next->prev = bp->prev;
+
+ parent = GET_HDR(ctx);
+ mprAssert(VALID_HDR(parent));
+ bp->parent = parent;
+
+ if (parent->children == 0) {
+ parent->children = bp;
+ bp->next = bp->prev = bp;
+
+ } else {
+ bp->next = parent->children;
+ bp->prev = parent->children->prev;
+ parent->children->prev->next = bp;
+ parent->children->prev = bp;
+ }
+
+#if BLD_FEATURE_ALLOC_LEAK_TRACK
+ bp->location = loc;
+#endif
+
+ VALIDATE_BLOCK(GET_PTR(bp));
+
+ mprUnlock(bp->app->allocLock);
+
+ return 0;
+}
+
+/******************************************************************************/
+
+void mprSetRequiredAlloc(MprCtx ptr, bool recurse)
+{
+ MprBlk *bp, *firstChild, *cp;
+
+ bp = GET_HDR(ptr);
+
+ bp->flags |= ALLOC_FLAGS_REQUIRED;
+
+ if (recurse && (firstChild = bp->children) != 0) {
+ cp = firstChild;
+ do {
+ mprSetRequiredAlloc(GET_PTR(cp), recurse);
+ cp = cp->next;
+ } while (cp != firstChild);
+ }
+}
+
+/******************************************************************************/
+/*
+ * Monitor stack usage. Return true if the stack has grown
+ */
+
+int mprStackCheck(MprCtx ptr)
+{
+ MprApp *app;
+ int size;
+
+ mprAssert(VALID_BLK(ptr));
+
+ app = mprGetApp(ptr);
+
+ size = (int) app->stackStart - (int) &app;
+ if (size < 0) {
+ app->maxStack -= size;
+ app->stackStart = (void*) &app;
+ size = 0;
+ }
+ if ((uint) size > app->maxStack) {
+ app->maxStack = size;
+ return 1;
+ }
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * Return the stack size
+ */
+
+int mprStackSize(MprCtx ptr)
+{
+ MprApp *app;
+
+ mprAssert(VALID_BLK(ptr));
+
+ app = mprGetApp(ptr);
+ return app->maxStack;
+}
+
+/******************************************************************************/
+
+static int mprAllocException(MPR_LOC_DEC(ctx, loc), uint size, bool granted)
+{
+ MprApp *app;
+ MprAlloc *alloc;
+ int rc;
+
+ mprAssert(VALID_BLK(ctx));
+
+ app = mprGetApp(ctx);
+ alloc = &app->alloc;
+
+ if (alloc->cback == 0) {
+ return 0;
+ }
+
+ mprLock(app->allocLock);
+ if (alloc->inAllocException == 0) {
+ alloc->inAllocException = 1;
+ mprUnlock(app->allocLock);
+
+ rc = (alloc->cback)(app, size, alloc->stats.bytesAllocated, granted);
+
+ mprLock(app->allocLock);
+ app->alloc.inAllocException = 0;
+ mprUnlock(app->allocLock);
+
+ return rc;
+ }
+ return 0;
+}
+
+/******************************************************************************/
+
+void mprSetAllocLimits(MprApp *app, uint redLine, uint maxMemory)
+{
+ app->alloc.stats.redLine = redLine;
+ app->alloc.stats.maxMemory = maxMemory;
+}
+
+/******************************************************************************/
+
+MprAllocCback mprSetAllocCallback(MprApp *app, MprAllocCback cback)
+{
+ MprAllocCback old;
+
+ mprAssert(app);
+ mprAssert(VALID_BLK(app));
+
+ old = app->alloc.cback;
+ app->alloc.cback = cback;
+ return old;
+}
+
+/******************************************************************************/
+
+uint mprGetAllocBlockSize(MprCtx ptr)
+{
+ MprBlk *bp;
+
+ mprAssert(VALID_BLK(ptr));
+
+ if (ptr == 0) {
+ return 0;
+ }
+
+ bp = GET_HDR(ptr);
+ mprAssert(VALID_HDR(bp));
+
+ CHECK_HDR(bp);
+
+ return bp->size;
+}
+
+/******************************************************************************/
+/*
+ * Return the total block count used by a block including all children
+ */
+
+uint mprGetAllocBlockCount(MprCtx ptr)
+{
+ MprBlk *bp, *firstChild, *cp;
+ uint count;
+
+ mprAssert(VALID_BLK(ptr));
+
+ if (ptr == 0) {
+ return 0;
+ }
+
+ bp = GET_HDR(ptr);
+ mprAssert(VALID_HDR(bp));
+
+ /*
+ * Add one for itself
+ */
+ count = 1;
+ if ((firstChild = bp->children) != 0) {
+ cp = firstChild;
+ do {
+ count += mprGetAllocBlockCount(GET_PTR(cp));
+ cp = cp->next;
+ } while (cp != firstChild);
+ }
+ return count;
+}
+
+/******************************************************************************/
+/*
+ * Return the total of all memory allocated including slabs
+ */
+
+uint mprGetAllocBlockMemory(MprCtx ptr)
+{
+ MprBlk *bp, *firstChild, *cp;
+ uint count;
+
+ mprAssert(VALID_BLK(ptr));
+
+ if (ptr == 0) {
+ return 0;
+ }
+
+ bp = GET_HDR(ptr);
+ mprAssert(VALID_HDR(bp));
+
+ count = bp->size + HDR_SIZE;
+ if ((firstChild = bp->children) != 0) {
+ cp = firstChild;
+ do {
+ count += mprGetAllocBlockMemory(GET_PTR(cp));
+ cp = cp->next;
+ } while (cp != firstChild);
+ }
+ return count;
+}
+
+/******************************************************************************/
+#if BLD_FEATURE_ALLOC_LEAK_TRACK
+
+const char *mprGetAllocLocation(MprCtx ptr)
+{
+ MprBlk *bp;
+
+ if (ptr == 0) {
+ return 0;
+ }
+ mprAssert(VALID_BLK(ptr));
+
+ bp = GET_HDR(ptr);
+ mprAssert(VALID_HDR(bp));
+ return bp->location;
+}
+
+#endif
+/******************************************************************************/
+
+void *mprGetAllocParent(MprCtx ptr)
+{
+ MprBlk *bp;
+
+ mprAssert(VALID_BLK(ptr));
+
+ if (ptr == 0) {
+ return 0;
+ }
+
+ bp = GET_HDR(ptr);
+ mprAssert(VALID_HDR(bp));
+
+ CHECK_HDR(bp);
+
+ return GET_PTR(bp->parent);
+}
+
+/******************************************************************************/
+
+MprAllocStats *mprGetAllocStats(MprApp *app)
+{
+ mprAssert(VALID_BLK(app));
+
+ return &app->alloc.stats;
+}
+
+/******************************************************************************/
+#if BLD_FEATURE_ALLOC_STATS
+
+MprSlabStats *mprGetSlabAllocStats(MprApp *app, int slabIndex)
+{
+ MprSlab *slab;
+
+ mprAssert(VALID_BLK(app));
+
+ if (0 <= slabIndex && slabIndex < MPR_MAX_SLAB) {
+ slab = &app->alloc.slabs[slabIndex];
+ return &slab->stats;
+ }
+
+ mprAssert(0 <= slabIndex && slabIndex < MPR_MAX_SLAB);
+ return 0;
+}
+
+#endif /* BLD_FEATURE_ALLOC_STATS */
+/******************************************************************************/
+#if BLD_DEBUG
+
+int mprPrintAllocBlocks(MprCtx ptr, int indent)
+{
+ MprBlk *bp, *firstChild, *cp;
+ const char *location;
+ int subTotal, size, indentSpaces, code;
+
+ subTotal = 0;
+
+ bp = GET_HDR(ptr);
+
+ if (! (bp->flags & ALLOC_FLAGS_REQUIRED)) {
+ size = bp->size + HDR_SIZE;
+
+ /*
+ * Take one level off because we don't trace app
+ */
+ indentSpaces = indent;
+
+ if (bp->flags & ALLOC_FLAGS_REQUIRED) {
+ code = 'R';
+ } else if (bp->flags & ALLOC_FLAGS_IS_SLAB) {
+ code = 'S';
+ } else {
+ code = ' ';
+ }
+
+#if BLD_FEATURE_ALLOC_LEAK_TRACK
+ location = bp->location;
+#else
+ location = "";
+#endif
+ mprLog(bp->app, 0,
+ "%c %.*s %-16s %.*s size %5d has %3d deps, total %6d", code,
+ indentSpaces, " ",
+ mprGetBaseName(location),
+ 8 - indent, " ",
+ size,
+ mprGetAllocBlockCount(GET_PTR(bp)),
+ mprGetAllocBlockMemory(GET_PTR(bp))
+ /* (uint) bp */
+ );
+
+ subTotal += size;
+ }
+
+ if ((firstChild = bp->children) != 0) {
+ cp = firstChild;
+ do {
+ subTotal += mprPrintAllocBlocks(GET_PTR(cp), indent + 2);
+ cp = cp->next;
+ } while (cp != firstChild);
+ }
+
+ return subTotal;
+}
+
+#endif
+/******************************************************************************/
+#if BLD_FEATURE_ALLOC_STATS
+/*
+ * Print a memory allocation report that includes a list of allocated blocks
+ * and a statistics summary
+ */
+
+void mprPrintAllocReport(MprApp *app, bool printBlocks, const char *msg)
+{
+ MprSlabStats *stats;
+ uint total;
+ int i, size;
+
+ mprAssert(VALID_BLK(app));
+
+ if (msg) {
+ mprLog(app, 0, " ");
+ mprLog(app, 0, "%s", msg);
+ }
+
+#if BLD_DEBUG
+ /*
+ * Do block stats
+ */
+ if (printBlocks) {
+ int sum;
+ mprLog(app, 0, " ");
+ sum = mprPrintAllocBlocks(app, 0);
+ if (sum) {
+ mprLog(app, 0, " Sum of blocks %d", sum);
+ } else {
+ mprLog(app, 0, " None");
+ }
+ }
+#endif
+
+ /*
+ * Do Slab stats
+ */
+ mprLog(app, 0, " ");
+ mprLog(app, 0, "MPR Slab Memory Stats");
+ mprLog(app, 0, " ");
+
+ mprLog(app, 0,
+ " Index Size Total Allocated Free PeakAlloc PeakFree TotalAlloc");
+
+ total = 0;
+ for (i = 0; i < MPR_MAX_SLAB; i++) {
+ stats = &app->alloc.slabs[i].stats;
+ size = 1 << (i + 5);
+ if (stats->totalAllocCount > 0) {
+ mprLog(app, 0, " %2d %6d %8d %9d %6d %9d %8d %10d",
+ i, size, size * (stats->allocCount + stats->freeCount),
+ stats->allocCount, stats->freeCount,
+ stats->peakAllocCount, stats->peakFreeCount,
+ stats->totalAllocCount);
+ total += size * (stats->allocCount + stats->freeCount);
+ }
+ }
+ mprLog(app, 0, " ");
+ mprLog(app, 0, "MPR Total Allocated Slab RAM: %10d", total);
+ mprLog(app, 0, "MPR Total Allocated RAM: %10d",
+ mprGetAllocatedMemory(app));
+ mprLog(app, 0, "MPR Peak Allocated RAM: %10d",
+ mprGetPeakAllocatedMemory(app));
+ mprLog(app, 0, " ");
+}
+
+/******************************************************************************/
+/*
+ * Return the total memory allocated.
+ */
+
+uint mprGetAllocatedMemory(MprCtx ctx)
+{
+ MprApp *app;
+
+ app = mprGetApp(ctx);
+
+ return app->alloc.stats.bytesAllocated;
+}
+
+/******************************************************************************/
+/*
+ * Return the peak memory allocated.
+ */
+
+uint mprGetPeakAllocatedMemory(MprCtx ctx)
+{
+ MprApp *app;
+
+ app = mprGetApp(ctx);
+
+ return app->alloc.stats.peakAllocated;
+}
+
+/******************************************************************************/
+/*
+ * Return memory in the MPR slab. This excludes the EJS slabs
+ */
+
+uint mprGetAllocatedSlabMemory(MprCtx ctx)
+{
+ MprApp *app;
+ MprSlabStats *stats;
+ uint total;
+ int i, size;
+
+ app = mprGetApp(ctx);
+
+ total = 0;
+ for (i = 0; i < MPR_MAX_SLAB; i++) {
+ stats = &app->alloc.slabs[i].stats;
+ size = 1 << (i + 5);
+ if (stats->totalAllocCount > 0) {
+ total += size * (stats->allocCount + stats->freeCount);
+ }
+ }
+ return total;
+}
+
+#endif /* BLD_FEATURE_ALLOC_STATS */
+/******************************************************************************/
+
+MprDestructor mprSetDestructor(MprCtx ptr, MprDestructor destructor)
+{
+ MprDestructor old;
+ MprBlk *bp;
+
+ mprAssert(VALID_BLK(ptr));
+
+ if (ptr == 0) {
+ return 0;
+ }
+
+ bp = GET_HDR(ptr);
+
+ mprAssert(bp);
+ mprAssert(VALID_HDR(bp));
+ mprAssert(ptr != mprGetAllocParent(ptr));
+
+ CHECK_HDR(bp);
+
+ old = bp->destructor;
+ bp->destructor = destructor;
+
+ return old;
+}
+
+/******************************************************************************/
+
+int mprIsAllocBlockValid(MprCtx ptr)
+{
+ MprBlk *bp;
+
+ bp = GET_HDR(ptr);
+ return (bp && VALID_HDR(bp));
+}
+
+/******************************************************************************/
+#if VALIDATE_ALLOC
+/*
+ * Exhaustive validation of the block and its children. Does not go recursive
+ * as it would be too slow.
+ */
+
+int mprValidateBlock(MprCtx ptr)
+{
+ MprBlk *bp, *parent, *cp, *firstChild;
+ int count;
+
+ mprAssert(ptr);
+ mprAssert(VALID_BLK(ptr));
+
+ bp = GET_HDR(ptr);
+
+ mprAssert(bp);
+ mprAssert(VALID_HDR(bp));
+ mprAssert(VALID_HDR(bp->parent));
+
+ if (ptr != bp->app) {
+ mprAssert(bp != bp->parent);
+ }
+ mprAssert(! (bp->flags & ALLOC_FLAGS_FREE));
+ mprAssert(! (bp->flags & ALLOC_FLAGS_FREEING));
+
+ /*
+ *
+ */
+ count = 0;
+ parent = bp->parent;
+
+ if ((firstChild = bp->children) != 0) {
+ cp = firstChild;
+ mprAssert((int) cp != 0xfeefee);
+ do {
+ mprAssert(bp->next->prev == bp);
+ mprAssert(bp->prev->next == bp);
+ mprAssert(bp->prev->parent == parent);
+ mprAssert(bp->next->parent == parent);
+
+ count++;
+ cp = cp->next;
+
+ if (bp->next == bp) {
+ mprAssert(bp->prev == bp);
+ if (ptr != bp->app) {
+ mprAssert(parent->children == bp);
+ }
+ }
+ if (bp->prev == bp) {
+ mprAssert(bp->next == bp);
+ if (ptr != bp->app) {
+ mprAssert(parent->children == bp);
+ }
+ }
+ } while (cp != firstChild);
+ }
+
+ return 0;
+}
+
+#endif
+/******************************************************************************/
+/*
+ * Validate a block and all children
+ */
+
+int mprValidateAllocTree(MprCtx ptr)
+{
+#if VALIDATE_ALLOC
+ MprBlk *bp, *cp, *firstChild;
+
+ mprAssert(ptr);
+ mprAssert(VALID_BLK(ptr));
+
+ bp = GET_HDR(ptr);
+
+ mprValidateBlock(GET_PTR(bp));
+
+ if ((firstChild = bp->children) != 0) {
+ cp = firstChild;
+ do {
+ mprValidateAllocTree(GET_PTR(cp));
+ cp = cp->next;
+ } while (cp != firstChild);
+ }
+
+#endif
+ return 0;
+}
+
+/******************************************************************************/
+#if UNUSED && FUTURE
+/*
+ * Exhaustive validation of the block and its children. Does not go recursive
+ * as it would be too slow.
+ */
+
+int mprValidateSlabs(MprApp *app)
+{
+ MprSlab *slab;
+ MprSlabStats *slabStats;
+ MprSlabBlock *sp;
+ int count, i;
+
+ for (i = 0; i < MPR_MAX_SLAB; i++) {
+ slab = &app->alloc.slabs[i];
+ slabStats = &slab->stats;
+
+ count = 0;
+ for (sp = slab->next; sp; sp = sp->next) {
+ count++;
+ }
+ mprAssert(count == (int) slabStats->freeCount);
+ }
+ return 0;
+}
+
+#endif
+/******************************************************************************/
+
+void mprAllocAbort()
+{
+#if BREW
+ printf("Bad block header");
+#else
+ exit(255);
+#endif
+}
+
+/******************************************************************************/
+#undef mprGetApp
+/*
+ * Get the root parent from any block (which is the MprApp structure)
+ */
+
+MprApp *mprGetApp(MprCtx ptr)
+{
+ MprBlk *bp;
+
+ mprAssert(ptr);
+
+ bp = GET_HDR(ptr);
+ mprAssert(VALID_HDR(bp));
+
+ CHECK_HDR(bp);
+
+ mprAssert(bp->app->magic == APP_MAGIC);
+
+ return bp->app;
+}
+
+/******************************************************************************/
+
+int mprGetAllocErrors(MprCtx ctx)
+{
+ MprApp *app;
+
+ app = mprGetApp(ctx);
+ return app->alloc.stats.errors;
+}
+
+/******************************************************************************/
+
+void mprClearAllocErrors(MprCtx ctx)
+{
+ MprApp *app;
+
+ app = mprGetApp(ctx);
+ app->alloc.stats.errors = 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/mpr/mprArray.c b/source4/lib/appweb/ejs-2.0/mpr/mprArray.c
new file mode 100644
index 0000000000..95b0a14450
--- /dev/null
+++ b/source4/lib/appweb/ejs-2.0/mpr/mprArray.c
@@ -0,0 +1,385 @@
+/**
+ * @file mprArray.c
+ * @brief Growable array structure
+ * @overview Simple growable array structure.
+ * @remarks Most routines in this file are not thread-safe. It is the callers
+ * responsibility to perform all thread synchronization.
+ */
+
+/*
+ * @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 "mpr.h"
+
+/******************************************************************************/
+/*
+ * Create a general growable array structure. Use mprFree to destroy.
+ */
+
+MprArray *mprCreateItemArrayInternal(MPR_LOC_DEC(ctx, loc), int initialSize,
+ int maxSize)
+{
+ MprArray *array;
+ int size;
+
+ mprAssert(initialSize <= maxSize);
+
+ array = (MprArray*) mprSlabAllocZeroedBlock(MPR_LOC_PASS(ctx, loc),
+ sizeof(MprArray), 0);
+ if (array == 0) {
+ return 0;
+ }
+
+ if (initialSize == 0) {
+ initialSize = MPR_ARRAY_INCR;
+ }
+ if (maxSize == 0) {
+ maxSize = MAXINT;
+ }
+ size = initialSize * sizeof(void*);
+
+ array->items = (void**) mprSlabAllocBlock(MPR_LOC_PASS(array, loc),
+ size, 0);
+
+ if (array->items == 0) {
+ mprFree(array);
+ return 0;
+ }
+
+ array->capacity = initialSize;
+ array->maxSize = maxSize;
+ array->incr = min(initialSize * 2, (array->maxSize - array->length));
+ array->length = 0;
+
+ return array;
+}
+
+/******************************************************************************/
+/*
+ * Add an item to the array
+ */
+
+int mprAddItem(MprArray *array, void *item)
+{
+ int memsize, index, len;
+
+ mprAssert(array);
+ mprAssert(array->capacity >= 0);
+ mprAssert(array->length >= 0);
+
+ if (array->length < array->capacity) {
+ /*
+ * Room to fit in the current capacity
+ */
+ index = array->length++;
+ array->items[index] = item;
+ return index;
+ }
+ mprAssert(array->length == array->capacity);
+
+ /*
+ * Need to grow the array
+ */
+ if (array->capacity >= array->maxSize) {
+ mprAssert(array->capacity < array->maxSize);
+ return MPR_ERR_TOO_MANY;
+ }
+
+ len = array->capacity + array->incr;
+ memsize = len * sizeof(void*);
+
+ /*
+ * Grow the array of items
+ */
+
+ array->items = (void**) mprRealloc(array, array->items, memsize);
+
+ /*
+ * Zero the new portion
+ */
+ memset(&array->items[array->capacity], 0, sizeof(void*) * array->incr);
+ array->capacity = len;
+
+ array->incr = min(array->incr * 2, (array->maxSize - array->length));
+
+ index = array->length++;
+ array->items[index] = item;
+
+ return index;
+}
+
+/******************************************************************************/
+/*
+ * Remove an item from the array
+ */
+
+int mprRemoveItem(MprArray *array, void *item)
+{
+ int index;
+
+ mprAssert(array);
+ mprAssert(array->capacity > 0);
+ mprAssert(array->length > 0);
+
+ index = mprFindItem(array, item);
+ if (index < 0) {
+ return index;
+ }
+
+ return mprRemoveItemByIndex(array, index);
+}
+
+/******************************************************************************/
+/*
+ * Remove an index from the array
+ */
+
+int mprRemoveItemByIndex(MprArray *array, int index)
+{
+ void **items;
+ int i;
+
+ mprAssert(array);
+ mprAssert(array->capacity > 0);
+ mprAssert(index >= 0 && index < array->capacity);
+ mprAssert(array->items[index] != 0);
+ mprAssert(array->length > 0);
+
+ if (index < 0 || index >= array->length) {
+ return MPR_ERR_NOT_FOUND;
+ }
+
+ /*
+ * Copy down to compress
+ */
+ items = array->items;
+ for (i = index; i < (array->length - 1); i++) {
+ items[i] = items[i + 1];
+ }
+ array->length--;
+
+#if BLD_DEBUG
+ if (array->length < array->capacity) {
+ items[array->length] = 0;
+ }
+#endif
+ return 0;
+}
+
+/******************************************************************************/
+
+int mprRemoveRangeOfItems(MprArray *array, int start, int end)
+{
+ void **items;
+ int i, count;
+
+ mprAssert(array);
+ mprAssert(array->capacity > 0);
+ mprAssert(array->length > 0);
+ mprAssert(start > end);
+
+ if (start < 0 || start >= array->length) {
+ return MPR_ERR_NOT_FOUND;
+ }
+ if (end < 0 || end >= array->length) {
+ return MPR_ERR_NOT_FOUND;
+ }
+ if (start > end) {
+ return MPR_ERR_BAD_ARGS;
+ }
+
+ /*
+ * Copy down to compress
+ */
+ items = array->items;
+ count = end - start;
+ for (i = start; i < (array->length - count); i++) {
+ items[i] = items[i + count];
+ }
+ array->length -= count;
+
+#if BLD_DEBUG
+ if (array->length < array->capacity) {
+ for (i = array->length; i < array->capacity; i++) {
+ items[i] = 0;
+ }
+ }
+#endif
+ return 0;
+}
+
+/******************************************************************************/
+
+void *mprGetItem(MprArray *array, int index)
+{
+ mprAssert(array);
+
+ if (index < 0 || index >= array->length) {
+ return 0;
+ }
+ return array->items[index];
+}
+
+/******************************************************************************/
+
+void *mprGetFirstItem(MprArray *array, int *last)
+{
+ mprAssert(array);
+ mprAssert(last);
+
+ if (array == 0) {
+ return 0;
+ }
+
+ *last = 0;
+
+ if (array->length == 0) {
+ return 0;
+ }
+ return array->items[0];
+}
+
+/******************************************************************************/
+
+void *mprGetNextItem(MprArray *array, int *last)
+{
+ int index;
+
+ mprAssert(array);
+ mprAssert(last);
+ mprAssert(*last >= 0);
+
+ index = *last;
+
+ if (++index < array->length) {
+ *last = index;
+ return array->items[index];
+ }
+ return 0;
+}
+
+/******************************************************************************/
+
+void *mprGetPrevItem(MprArray *array, int *last)
+{
+ int index;
+
+ mprAssert(array);
+ mprAssert(last);
+ mprAssert(*last >= 0);
+
+ if (array == 0) {
+ return 0;
+ }
+
+ index = *last;
+
+ if (--index < array->length && index >= 0) {
+ *last = index;
+ return array->items[index];
+ }
+ return 0;
+}
+
+/******************************************************************************/
+
+int mprGetItemCount(MprArray *array)
+{
+ mprAssert(array);
+
+ if (array == 0) {
+ return 0;
+ }
+
+ return array->length;
+}
+
+/******************************************************************************/
+
+int mprGetItemCapacity(MprArray *array)
+{
+ mprAssert(array);
+
+ if (array == 0) {
+ return 0;
+ }
+
+ return array->capacity;
+}
+
+/******************************************************************************/
+
+void mprClearAndFreeItems(MprArray *array)
+{
+ int i;
+
+ mprAssert(array);
+
+ for (i = 0; i < array->length; i++) {
+ mprFree(array->items[i]);
+ }
+}
+
+/******************************************************************************/
+
+void mprClearItems(MprArray *array)
+{
+ mprAssert(array);
+
+ array->length = 0;
+}
+
+/******************************************************************************/
+
+int mprFindItem(MprArray *array, void *item)
+{
+ int i;
+
+ mprAssert(array);
+
+ for (i = 0; i < array->length; i++) {
+ if (array->items[i] == item) {
+ return i;
+ }
+ }
+ return MPR_ERR_NOT_FOUND;
+}
+
+/******************************************************************************/
+/*
+ * 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/mpr/mprBuf.c b/source4/lib/appweb/ejs-2.0/mpr/mprBuf.c
new file mode 100644
index 0000000000..ba9888a9fc
--- /dev/null
+++ b/source4/lib/appweb/ejs-2.0/mpr/mprBuf.c
@@ -0,0 +1,535 @@
+/**
+ * @file mprBuf.c
+ * @brief Dynamic buffer module
+ * @overview
+ * @remarks
+ */
+
+/******************************************************************************/
+/*
+ * @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 "mpr.h"
+
+/**************************** Forward Declarations ****************************/
+
+static int grow(MprBuf *bp);
+
+/*********************************** Code *************************************/
+/*
+ * Create a new buffer. "maxsize" is the limit to which the buffer can
+ * ever grow. -1 means no limit. The buffer can ever only fix maxsize-1 bytes.
+ * "initialSize" is used to define the amount to increase the size of the
+ * buffer each time if it becomes full. (Note: grow() will exponentially
+ * increase this number for performance.)
+ */
+
+MprBuf *mprCreateBuf(MprCtx ctx, int initialSize, int maxSize)
+{
+ MprBuf *bp;
+
+ if (initialSize <= 0) {
+ initialSize = MPR_DEFAULT_ALLOC;
+ }
+ bp = mprAllocTypeZeroed(ctx, MprBuf);
+ bp->growBy = MPR_BUFSIZE;
+ bp->maxsize = 0;
+ mprSetBufSize(bp, initialSize, maxSize);
+ return bp;
+}
+
+/******************************************************************************/
+/*
+ * Set the initial buffer parameters and create the first buffer
+ */
+
+void mprSetBufSize(MprBuf *bp, int initialSize, int max)
+{
+ mprAssert(initialSize > 0);
+
+ if (max > 0 && initialSize > max) {
+ initialSize = max;
+ }
+
+ if (bp->buf && bp->growBy > 0) {
+ mprFree(bp->buf);
+ }
+
+ bp->buf = (uchar*) mprAlloc(bp, initialSize);
+ bp->growBy = initialSize;
+ bp->maxsize = max;
+ bp->buflen = initialSize;
+ bp->endbuf = &bp->buf[bp->buflen];
+ bp->start = bp->buf;
+ bp->end = bp->buf;
+ *bp->start = '\0';
+}
+
+/******************************************************************************/
+
+char *mprStealBuf(MprCtx ctx, MprBuf *bp)
+{
+ char *str;
+
+ str = (char*) bp->start;
+
+ mprStealAllocBlock(MPR_LOC_ARGS(ctx), bp->start);
+
+ bp->start = bp->end = bp->buf = bp->endbuf = 0;
+ bp->buflen = 0;
+
+ return str;
+}
+
+/******************************************************************************/
+
+void mprAddNullToBuf(MprBuf *bp)
+{
+ *((char*) bp->end) = (char) '\0';
+}
+
+/******************************************************************************/
+
+void mprAdjustBufEnd(MprBuf *bp, int size)
+{
+ mprAssert(bp->buflen == (bp->endbuf - bp->buf));
+ mprAssert(size < bp->buflen);
+
+ bp->end += size;
+ if (bp->end >= bp->endbuf) {
+ bp->end -= bp->buflen;
+ }
+ if (bp->end < bp->buf) {
+ bp->end += bp->buflen;
+ }
+
+ if (bp->end >= bp->endbuf) {
+ mprAssert(bp->end < bp->endbuf);
+ mprFlushBuf(bp);
+ }
+}
+
+/******************************************************************************/
+/*
+ * Adjust the start pointer after a user copy
+ */
+
+void mprAdjustBufStart(MprBuf *bp, int size)
+{
+ mprAssert(bp->buflen == (bp->endbuf - bp->buf));
+ mprAssert(size < bp->buflen);
+
+ bp->start += size;
+ while (bp->start >= bp->endbuf) {
+ bp->start -= bp->buflen;
+ }
+ while (bp->start < bp->buf) {
+ bp->start += bp->buflen;
+ }
+
+ /*
+ * Flush the buffer if the start pointer is corrupted via a bad size
+ */
+ if (bp->start >= bp->endbuf) {
+ mprAssert(bp->start < bp->endbuf);
+ mprFlushBuf(bp);
+ }
+}
+
+
+/******************************************************************************/
+
+void mprFlushBuf(MprBuf *bp)
+{
+ bp->start = bp->buf;
+ bp->end = bp->buf;
+}
+
+/******************************************************************************/
+
+int mprGetCharFromBuf(MprBuf *bp)
+{
+ int c;
+
+ if (bp->start == bp->end) {
+ return -1;
+ }
+ c = (uchar) *bp->start++;
+ if (bp->start >= bp->endbuf) {
+ bp->start = bp->buf;
+ }
+ return c;
+}
+
+/******************************************************************************/
+
+int mprGetBlockFromBuf(MprBuf *bp, uchar *buf, int size)
+{
+ int thisLen, bytesRead;
+
+ mprAssert(buf);
+ mprAssert(size > 0);
+ mprAssert(bp->buflen == (bp->endbuf - bp->buf));
+
+ /*
+ * Get the max bytes in a straight copy
+ */
+ bytesRead = 0;
+ while (size > 0) {
+ thisLen = mprGetBufLinearData(bp);
+ thisLen = min(thisLen, size);
+ if (thisLen <= 0) {
+ break;
+ }
+
+ memcpy(buf, bp->start, thisLen);
+ buf += thisLen;
+ bp->start += thisLen;
+ size -= thisLen;
+ bytesRead += thisLen;
+
+ if (bp->start >= bp->endbuf) {
+ bp->start = bp->buf;
+ }
+ }
+ return bytesRead;
+}
+
+/******************************************************************************/
+
+int mprGetBufLength(MprBuf *bp)
+{
+ if (bp->start > bp->end) {
+ return (bp->buflen + (bp->end - bp->start));
+ } else {
+ return (bp->end - bp->start);
+ }
+}
+
+/******************************************************************************/
+
+int mprGetBufLinearData(MprBuf *bp)
+{
+ return min(mprGetBufLength(bp), (bp->endbuf - bp->start));
+}
+
+/******************************************************************************/
+
+int mprGetBufLinearSpace(MprBuf *bp)
+{
+ int len = mprGetBufLength(bp);
+ int space = bp->buflen - len - 1;
+ return min((bp->endbuf - bp->end), space);
+}
+
+/******************************************************************************/
+
+int mprGetBufSize(MprBuf *bp)
+{
+ return bp->buflen;
+}
+
+/******************************************************************************/
+
+int mprGetBufSpace(MprBuf *bp)
+{
+ return bp->buflen - mprGetBufLength(bp) - 1;
+}
+
+/******************************************************************************/
+
+char *mprGetBufOrigin(MprBuf *bp)
+{
+ return (char*) bp->buf;
+}
+
+/******************************************************************************/
+
+char *mprGetBufStart(MprBuf *bp)
+{
+ return (char*) bp->start;
+}
+
+/******************************************************************************/
+
+char *mprGetBufEnd(MprBuf *bp)
+{
+ return (char*) bp->end;
+}
+
+/******************************************************************************/
+
+int mprInsertCharToBuf(MprBuf *bp, int c)
+{
+ char *cp;
+ int space;
+
+ mprAssert(bp->buflen == (bp->endbuf - bp->buf));
+
+ space = bp->buflen - mprGetBufLength(bp) - 1;
+ if (space < (int) sizeof(char)) {
+ if (!grow(bp)) {
+ return -1;
+ }
+ }
+ if (bp->start <= bp->buf) {
+ bp->start = bp->endbuf;
+ }
+ cp = (char*) bp->start;
+ *--cp = (char) c;
+ bp->start = (uchar *) cp;
+ return 0;
+}
+
+/******************************************************************************/
+
+int mprLookAtNextCharInBuf(MprBuf *bp)
+{
+ if (bp->start == bp->end) {
+ return -1;
+ }
+ return *bp->start;
+}
+
+/******************************************************************************/
+
+int mprLookAtLastCharInBuf(MprBuf *bp)
+{
+ if (bp->start == bp->end) {
+ return -1;
+ }
+ return (bp->end == bp->buf) ? bp->endbuf[-1] : bp->end[-1];
+}
+
+/******************************************************************************/
+
+int mprPutCharToBuf(MprBuf *bp, int c)
+{
+ char *cp;
+ int space;
+
+ mprAssert(bp->buflen == (bp->endbuf - bp->buf));
+
+ space = bp->buflen - mprGetBufLength(bp) - 1;
+ if (space < (int) sizeof(char)) {
+ if (! grow(bp)) {
+ return -1;
+ }
+ }
+
+ cp = (char*) bp->end;
+ *cp++ = (char) c;
+ bp->end = (uchar *) cp;
+ if (bp->end >= bp->endbuf) {
+ bp->end = bp->buf;
+ }
+ *((char*) bp->end) = (char) '\0';
+ return 0;
+}
+
+/******************************************************************************/
+
+int mprPutBlockToBuf(MprBuf *bp, const char *str, int size)
+{
+ int thisLen, bytes, space;
+
+ mprAssert(str);
+ mprAssert(size >= 0);
+ mprAssert(bp->buflen == (bp->endbuf - bp->buf));
+
+ /*
+ * Add the max we can in one copy
+ */
+ bytes = 0;
+ while (size > 0) {
+ space = mprGetBufLinearSpace(bp);
+ thisLen = min(space, size);
+ if (thisLen <= 0) {
+ if (! grow(bp)) {
+ break;
+ }
+ space = mprGetBufLinearSpace(bp);
+ thisLen = min(space, size);
+ }
+
+ memcpy(bp->end, str, thisLen);
+ str += thisLen;
+ bp->end += thisLen;
+ size -= thisLen;
+ bytes += thisLen;
+
+ if (bp->end >= bp->endbuf) {
+ bp->end = bp->buf;
+ }
+ }
+ *((char*) bp->end) = (char) '\0';
+ return bytes;
+}
+
+/******************************************************************************/
+
+int mprPutStringToBuf(MprBuf *bp, const char *str)
+{
+ return mprPutBlockToBuf(bp, str, strlen(str));
+}
+
+/******************************************************************************/
+
+int mprPutFmtStringToBuf(MprBuf *bp, const char *fmt, ...)
+{
+ va_list ap;
+ char *buf;
+ int rc, len, space;
+
+ va_start(ap, fmt);
+ space = mprGetBufLinearSpace(bp);
+
+ /*
+ * Add max that the buffer can grow
+ */
+ space += (bp->maxsize - bp->buflen - 1);
+
+ len = mprAllocVsprintf(MPR_LOC_ARGS(bp), &buf, space, fmt, ap);
+ rc = mprPutBlockToBuf(bp, buf, len);
+
+ mprFree(buf);
+ va_end(ap);
+ return rc;
+}
+
+/******************************************************************************/
+/*
+ * Grow the buffer to fit new data. Return 1 if the buffer can grow.
+ * Grow using the growBy size specified when creating the buffer.
+ */
+
+static int grow(MprBuf *bp)
+{
+ uchar *newbuf;
+
+ if (bp->maxsize > 0 && bp->buflen >= bp->maxsize) {
+ return 0;
+ }
+
+ newbuf = (uchar*) mprAlloc(bp, bp->buflen + bp->growBy);
+ if (bp->buf) {
+ memcpy(newbuf, bp->buf, bp->buflen);
+ mprFree(bp->buf);
+ }
+
+ bp->buflen += bp->growBy;
+ bp->end = newbuf + (bp->end - bp->buf);
+ bp->start = newbuf + (bp->start - bp->buf);
+ bp->buf = newbuf;
+ bp->endbuf = &bp->buf[bp->buflen];
+
+ /*
+ * Increase growBy to reduce overhead
+ */
+ bp->growBy *= 2;
+ if (bp->maxsize > 0 && (bp->buflen + bp->growBy) > bp->maxsize) {
+ bp->growBy = bp->maxsize - bp->buflen;
+ }
+ return 1;
+}
+
+/******************************************************************************/
+/*
+ * Add a number to the buffer (always null terminated).
+ */
+
+int mprPutIntToBuf(MprBuf *bp, int i)
+{
+ char numBuf[16];
+ int rc;
+
+ mprItoa(numBuf, sizeof(numBuf), i);
+ rc = mprPutStringToBuf(bp, numBuf);
+ *((char*) bp->end) = (char) '\0';
+
+ return rc;
+}
+
+/******************************************************************************/
+
+void mprCopyBufDown(MprBuf *bp)
+{
+ if (mprGetBufLength(bp) == 0) {
+ mprFlushBuf(bp);
+ return;
+ }
+ memmove(bp->buf, bp->start, (bp->end - bp->start));
+ bp->end -= (bp->start - bp->buf);
+ bp->start = bp->buf;
+}
+
+/******************************************************************************/
+
+MprBufProc mprGetBufRefillProc(MprBuf *bp)
+{
+ return bp->refillProc;
+}
+
+/******************************************************************************/
+
+void mprSetBufRefillProc(MprBuf *bp, MprBufProc fn, void *arg)
+{
+ bp->refillProc = fn;
+ bp->refillArg = arg;
+}
+
+/******************************************************************************/
+
+int mprRefillBuf(MprBuf *bp)
+{
+ return (bp->refillProc) ? (bp->refillProc)(bp, bp->refillArg) : 0;
+}
+
+/******************************************************************************/
+
+void mprResetBufIfEmpty(MprBuf *bp)
+{
+ if (mprGetBufLength(bp) == 0) {
+ mprFlushBuf(bp);
+ }
+}
+
+/******************************************************************************/
+/*
+ * 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/mpr/mprGenFile.c b/source4/lib/appweb/ejs-2.0/mpr/mprGenFile.c
new file mode 100644
index 0000000000..517e43853f
--- /dev/null
+++ b/source4/lib/appweb/ejs-2.0/mpr/mprGenFile.c
@@ -0,0 +1,336 @@
+/**
+ * @file mprGenFile.c
+ * @brief Generic File services
+ * @overview
+ * @remarks
+ * See OS/mprFile.c for the per O/S portions
+ */
+
+/******************************************************************************/
+/*
+ * @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 "mpr.h"
+
+/****************************** Forward Declarations **************************/
+#if !BREW
+
+static int closeDestructor(void *data);
+
+/************************************ Code ************************************/
+
+int mprStartFileServices(MprCtx ctx)
+{
+ MprApp *app;
+
+ app = mprGetApp(ctx);
+ app->console = mprAllocTypeZeroed(ctx, MprFile);
+ app->error = mprAllocTypeZeroed(ctx, MprFile);
+
+ /*
+ * We assume that STDOUT is 1 and STDERR is 2
+ */
+ app->console->fd = 1;
+ app->error->fd = 2;
+
+ return 0;
+}
+
+/******************************************************************************/
+
+void mprStopFileServices(MprCtx ctx)
+{
+ MprApp *app;
+
+ app = mprGetApp(ctx);
+
+ mprFree(app->console);
+ app->console = 0;
+ mprFree(app->error);
+ app->error = 0;
+}
+
+/******************************************************************************/
+
+MprFile *mprOpen(MprCtx ctx, const char *path, int omode, int perms)
+{
+ MprFile *file;
+
+ mprAssert(path && *path);
+
+ file = mprAllocTypeZeroed(ctx, MprFile);
+
+ file->fd = open(path, omode, perms);
+ if (file->fd < 0) {
+ mprFree(file);
+ return 0;
+ }
+
+ mprSetDestructor(file, closeDestructor);
+ return file;
+}
+
+/******************************************************************************/
+
+static int closeDestructor(void *data)
+{
+ MprFile *file = (MprFile*) data;
+
+ mprAssert(file);
+
+ mprClose(file);
+ return 0;
+}
+
+/******************************************************************************/
+
+void mprClose(MprFile *file)
+{
+ mprAssert(file);
+
+ if (file < 0) {
+ return;
+ }
+
+ mprAssert(file->fd >= 0);
+ close(file->fd);
+
+ mprSetDestructor(file, 0);
+ mprFree(file);
+}
+
+/******************************************************************************/
+
+int mprRead(MprFile *file, void *buf, uint size)
+{
+ mprAssert(file);
+
+ if (file == 0) {
+ return MPR_ERR_BAD_HANDLE;
+ }
+
+ return read(file->fd, buf, size);
+}
+
+/******************************************************************************/
+
+int mprWrite(MprFile *file, const void *buf, uint count)
+{
+ mprAssert(file);
+
+ if (file == 0) {
+ return MPR_ERR_BAD_HANDLE;
+ }
+
+ return write(file->fd, buf, count);
+}
+
+/******************************************************************************/
+
+int mprSeek(MprFile *file, int seekType, long distance)
+{
+ mprAssert(file);
+
+ if (file == 0) {
+ return MPR_ERR_BAD_HANDLE;
+ }
+
+ return lseek(file->fd, seekType, distance);
+}
+
+/******************************************************************************/
+
+int mprDelete(MprCtx ctx, const char *path)
+{
+ return unlink(path);
+}
+
+/******************************************************************************/
+
+int mprDeleteDir(MprCtx ctx, const char *path)
+{
+ return rmdir(path);
+}
+
+#endif /* !BREW */
+/******************************************************************************/
+
+char *mprGets(MprFile *file, char *buf, uint size)
+{
+ MprBuf *bp;
+ int count, len, c;
+
+ mprAssert(file);
+
+ if (file == 0) {
+ return 0;
+ }
+
+ if (file->buf == 0) {
+ file->buf = mprCreateBuf(file, MPR_DEFAULT_ALLOC, MPR_MAX_STRING);
+ }
+ bp = file->buf;
+
+ /*
+ * Must leave room for null
+ */
+ count = 0;
+ while (--size > 0) {
+ if (mprGetBufLength(bp) == 0) {
+ mprFlushBuf(bp);
+ len = mprRead(file, mprGetBufEnd(bp),
+ mprGetBufLinearSpace(bp));
+ if (len <= 0) {
+ return 0;
+ }
+ mprAdjustBufEnd(bp, len);
+ mprAddNullToBuf(bp);
+ }
+ if ((c = mprGetCharFromBuf(bp)) == '\n') {
+ buf[count] = '\0';
+ return buf;
+ }
+ buf[count++] = c;
+ }
+ buf[count] = '\0';
+ return buf;
+}
+
+/******************************************************************************/
+
+int mprPuts(MprFile *file, const char *writeBuf, uint count)
+{
+ MprBuf *bp;
+ char *buf;
+ int total, bytes, len;
+
+ mprAssert(file);
+
+ /*
+ * Buffer output and flush when full.
+ */
+ if (file->buf == 0) {
+ file->buf = mprCreateBuf(file, MPR_BUFSIZE, 0);
+ if (file->buf == 0) {
+ return MPR_ERR_CANT_ALLOCATE;
+ }
+ }
+ bp = file->buf;
+
+ if (mprGetBufLength(bp) > 0 && mprGetBufSpace(bp) < (int) count) {
+ len = mprGetBufLength(bp);
+ if (mprWrite(file, mprGetBufStart(bp), len) != len) {
+ return MPR_ERR_CANT_WRITE;
+ }
+ mprFlushBuf(bp);
+ }
+
+ total = 0;
+ buf = (char*) writeBuf;
+
+ while (count > 0) {
+ bytes = mprPutBlockToBuf(bp, buf, count);
+ if (bytes <= 0) {
+ return MPR_ERR_CANT_ALLOCATE;
+ }
+ count -= bytes;
+ buf += bytes;
+ total += bytes;
+ mprAddNullToBuf(bp);
+
+ if (count > 0) {
+ len = mprGetBufLength(bp);
+ if (mprWrite(file, mprGetBufStart(bp), len) != len) {
+ return MPR_ERR_CANT_WRITE;
+ }
+ mprFlushBuf(bp);
+ }
+ }
+ return total;
+}
+
+/******************************************************************************/
+
+int mprMakeTempFileName(MprCtx ctx, char *buf, int bufsize, const char *tempDir)
+{
+ MprFile *file;
+ MprTime now;
+ char *dir;
+ int seed, i;
+
+ if (tempDir == 0) {
+#if WIN
+ char *cp;
+ dir = mprStrdup(ctx, getenv("TEMP"));
+ for (cp = dir; *cp; cp++) {
+ if (*cp == '\\') {
+ *cp = '/';
+ }
+ }
+#else
+ dir = mprStrdup(ctx, "/tmp");
+#endif
+ } else {
+ dir = mprStrdup(ctx, tempDir);
+ }
+
+ mprGetTime(ctx, &now);
+ seed = now.msec % 64000;
+ file = 0;
+
+ for (i = 0; i < 128; i++) {
+ mprSprintf(buf, bufsize, "%s/MPR_%d_%d.tmp", dir, getpid(), seed++);
+ file = mprOpen(ctx, buf, O_CREAT | O_EXCL | O_BINARY, 0664);
+ if (file) {
+ break;
+ }
+ }
+
+ if (file == 0) {
+ return MPR_ERR_CANT_CREATE;
+ }
+
+ mprClose(file);
+ mprFree(dir);
+
+ 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/mpr/mprGenTime.c b/source4/lib/appweb/ejs-2.0/mpr/mprGenTime.c
new file mode 100644
index 0000000000..6b0ed97bbc
--- /dev/null
+++ b/source4/lib/appweb/ejs-2.0/mpr/mprGenTime.c
@@ -0,0 +1,195 @@
+/**
+ * @file mprGenTime.c
+ * @brief Generic Time handling
+ * @overview
+ */
+
+/*
+ * @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 "mpr.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/******************************************************************************/
+/*
+ * Return the number of milliseconds until the given timeout has expired.
+ */
+
+int mprGetTimeRemaining(MprCtx ctx, MprTime mark, uint timeout)
+{
+ MprTime now;
+ uint diff;
+
+ mprGetTime(ctx, &now);
+ diff = ((now.sec - mark.sec) * 1000) + (now.msec - mark.msec);
+
+ if (diff < 0) {
+ /*
+ * Detect time going backwards
+ */
+ mprAssert(diff >= 0);
+ diff = 0;
+ }
+ return (int) (timeout - diff);
+}
+
+/******************************************************************************/
+/*
+ * Return the number of milliseconds until the given timeout has expired.
+ */
+
+int mprGetElapsedTime(MprCtx ctx, MprTime mark)
+{
+ MprTime now;
+
+ mprGetTime(ctx, &now);
+ return ((now.sec - mark.sec) * 1000) + (now.msec - mark.msec);
+}
+
+/******************************************************************************/
+
+void mprAddElapsedToTime(MprTime *time, uint elapsed)
+{
+ time->sec += elapsed / 1000;
+ time->msec += elapsed % 1000;
+ if (time->msec > 1000) {
+ time->msec -= 1000;
+ time->sec++;
+ }
+}
+
+/******************************************************************************/
+
+int mprCompareTime(MprTime *t1, MprTime *t2)
+{
+ if (t1->sec < t2->sec) {
+ return -1;
+ } else if (t1->sec == t2->sec) {
+ if (t1->msec < t2->msec) {
+ return -1;
+ } else if (t1->msec == t2->msec) {
+ return 0;
+ }
+ }
+ return 1;
+}
+
+/******************************************************************************/
+
+uint mprSubtractTime(MprTime *t1, MprTime *t2)
+{
+ return ((t1->sec - t2->sec) * 1000) + (t1->msec - t2->msec);
+}
+
+/******************************************************************************/
+#if !BREW
+/*
+ * Thread-safe RFC822 dates (Eg: "Fri, 07 Jan 2003 12:12:21 GMT")
+ */
+
+int mprRfcTime(MprCtx ctx, char *buf, int bufsize, const struct tm *timep)
+{
+ char months[12][4] = {
+ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep",
+ "Oct", "Nov", "Dec"
+ };
+
+ char days[7][4] = {
+ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
+ };
+
+ char *dayp, *monthp;
+ int year;
+
+ if (bufsize < 30) {
+ return MPR_ERR_WONT_FIT;
+ }
+ dayp = &days[timep->tm_wday][0];
+ *buf++ = *dayp++;
+ *buf++ = *dayp++;
+ *buf++ = *dayp++;
+ *buf++ = ',';
+ *buf++ = ' ';
+
+ *buf++ = timep->tm_mday / 10 + '0';
+ *buf++ = timep->tm_mday % 10 + '0';
+ *buf++ = ' ';
+
+ monthp = &months[timep->tm_mon][0];
+ *buf++ = *monthp++;
+ *buf++ = *monthp++;
+ *buf++ = *monthp++;
+ *buf++ = ' ';
+
+ year = 1900 + timep->tm_year;
+ /* This routine isn't y10k ready. */
+ *buf++ = year / 1000 + '0';
+ *buf++ = year % 1000 / 100 + '0';
+ *buf++ = year % 100 / 10 + '0';
+ *buf++ = year % 10 + '0';
+ *buf++ = ' ';
+
+ *buf++ = timep->tm_hour / 10 + '0';
+ *buf++ = timep->tm_hour % 10 + '0';
+ *buf++ = ':';
+ *buf++ = timep->tm_min / 10 + '0';
+ *buf++ = timep->tm_min % 10 + '0';
+ *buf++ = ':';
+ *buf++ = timep->tm_sec / 10 + '0';
+ *buf++ = timep->tm_sec % 10 + '0';
+ *buf++ = ' ';
+
+ *buf++ = 'G';
+ *buf++ = 'M';
+ *buf++ = 'T';
+ *buf++ = 0;
+ return 0;
+}
+
+#endif
+/******************************************************************************/
+
+#ifdef __cplusplus
+}
+#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/mpr/mprLock.c b/source4/lib/appweb/ejs-2.0/mpr/mprLock.c
new file mode 100644
index 0000000000..df9ce276d4
--- /dev/null
+++ b/source4/lib/appweb/ejs-2.0/mpr/mprLock.c
@@ -0,0 +1,266 @@
+/**
+ * @file mprThread.c
+ * @brief Mbedthis Portable Runtime Base Thread Locking Support
+ */
+
+/*
+ * @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
+ */
+
+#include "mpr.h"
+
+#if BLD_FEATURE_MULTITHREAD
+/************************************ Code ************************************/
+
+void mprInitThreads(MprApp *app)
+{
+ mprAssert(app);
+
+ if (app->globalLock == 0) {
+ app->globalLock = mprCreateLock(app);
+ app->allocLock = mprCreateLock(app);
+ }
+}
+
+/******************************************************************************/
+
+void mprTermThreads(MprApp *app)
+{
+ mprAssert(app);
+
+ if (app->globalLock) {
+ mprDestroyLock(app->globalLock);
+ app->globalLock = 0;
+ }
+ if (app->allocLock) {
+ MprLock *lock = app->allocLock;
+ app->allocLock = 0;
+ mprDestroyLock(lock);
+ }
+}
+
+/******************************************************************************/
+
+MprLock *mprCreateLock(MprCtx ctx)
+{
+ MprLock *lock;
+
+ mprAssert(ctx);
+
+ lock = mprAllocType(ctx, MprLock);
+
+#if BLD_HOST_UNIX
+ pthread_mutexattr_t attr;
+
+ pthread_mutexattr_init(&attr);
+ pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE_NP);
+ pthread_mutex_init(&lock->cs, &attr);
+ pthread_mutexattr_destroy(&attr);
+#elif WIN
+ InitializeCriticalSectionAndSpinCount(&lock->cs, 5000);
+#elif VXWORKS
+ lock->cs = semMCreate(SEM_Q_PRIORITY | SEM_DELETE_SAFE |
+ SEM_INVERSION_SAFE);
+ if (lock->cs == 0) {
+ mprAssert(0);
+ mprFree(lock);
+ return 0;
+ }
+#endif
+ return lock;
+}
+
+/******************************************************************************/
+/*
+ * Destroy a lock. Must be locked on entrance.
+ */
+
+void mprDestroyLock(MprLock *lock)
+{
+ mprAssert(lock);
+ if (lock == 0) {
+ return;
+ }
+
+#if BLD_HOST_UNIX
+ pthread_mutex_unlock(&lock->cs);
+ pthread_mutex_destroy(&lock->cs);
+#elif WIN
+ DeleteCriticalSection(&lock->cs);
+#elif VXWORKS
+ semDelete(lock->cs);
+#endif
+ mprFree(lock);
+}
+
+/******************************************************************************/
+/*
+ * Lock a mutex
+ */
+
+void mprLock(MprLock *lock)
+{
+ /*
+ * OPT -- Do this just so we can allocate MprApp before we have created its
+ * lock. Should remove this test here and in mprUnlock.
+ */
+ if (lock == 0) {
+ return;
+ }
+
+#if BLD_HOST_UNIX
+ pthread_mutex_lock(&lock->cs);
+#elif WIN
+ EnterCriticalSection(&lock->cs);
+#elif VXWORKS
+ semTake(lock->cs, WAIT_FOREVER);
+#endif
+}
+
+/******************************************************************************/
+/*
+ * Try to attain a lock. Do not block!
+ */
+
+int mprTryLock(MprLock *lock)
+{
+ mprAssert(lock);
+
+#if BLD_HOST_UNIX
+ {
+ int err;
+
+ if ((err = pthread_mutex_trylock(&lock->cs)) != 0) {
+ if (err == EBUSY) {
+ return MPR_ERR_BUSY;
+ } else {
+ return MPR_ERR_CANT_ACCESS;
+ }
+ }
+ return 0;
+ }
+#elif WIN
+ if (TryEnterCriticalSection(&lock->cs) == 0) {
+ return MPR_ERR_BUSY;
+ }
+#elif VXWORKS
+ {
+ int rc;
+
+ rc = semTake(cs, NO_WAIT);
+ if (rc == -1) {
+ mprAssert(0);
+ }
+ if (rc == S_objLib_OBJ_UNAVAILABLE) {
+ return MPR_ERR_BUSY;
+ } else {
+ return MPR_ERR_CANT_ACCESS;
+ }
+ /* Success */
+ return 0;
+ }
+#endif
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * Unlock.
+ */
+
+void mprUnlock(MprLock *lock)
+{
+ if (lock == 0) {
+ return;
+ }
+
+#if BLD_HOST_UNIX
+ pthread_mutex_unlock(&lock->cs);
+#elif WIN
+ LeaveCriticalSection(&lock->cs);
+#elif VXWORKS
+ semGive(lock->cs);
+#endif
+}
+
+/******************************************************************************/
+/*
+ * Big global lock. Avoid using this.
+ */
+
+void mprGlobalLock(MprCtx ctx)
+{
+ MprApp *app;
+
+ app = mprGetApp(ctx);
+ mprAssert(app);
+
+ if (app && app->globalLock) {
+ mprLock(app->globalLock);
+ }
+}
+
+/******************************************************************************/
+
+void mprGlobalUnlock(MprCtx ctx)
+{
+ MprApp *app;
+
+ app = mprGetApp(ctx);
+ mprAssert(app);
+
+ if (app && app->globalLock) {
+ mprUnlock(app->globalLock);
+ }
+}
+
+/******************************************************************************/
+
+int mprGetCurrentThreadID()
+{
+#if BLD_HOST_UNIX
+ return (int) pthread_self();
+#elif WIN
+ return GetCurrentThreadId();
+#elif VXWORKS
+ return (int) pthread_self();
+#endif
+}
+
+/******************************************************************************/
+#endif /* BLD_FEATURE_MULTITHREAD */
+
+/*
+ * 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/mpr/mprLog.c b/source4/lib/appweb/ejs-2.0/mpr/mprLog.c
new file mode 100644
index 0000000000..1eb175ed95
--- /dev/null
+++ b/source4/lib/appweb/ejs-2.0/mpr/mprLog.c
@@ -0,0 +1,602 @@
+/**
+ * @file mprLog.c
+ * @brief Mbedthis Portable Runtime (MPR) Logging and error reporting.
+ * @remarks We always provide these routines.
+ */
+
+/*********************************** License **********************************/
+/*
+ * @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
+ */
+
+#include "mpr.h"
+
+/****************************** Forward Declarations **************************/
+
+static void defaultLogHandler(MPR_LOC_DEC(ctx, loc), int flags,
+ int level, const char *msg);
+static void logOutput(MPR_LOC_DEC(ctx, loc), int flags, int level,
+ const char *msg);
+
+/************************************ Code ************************************/
+
+void mprLog(MprCtx ctx, int level, const char *fmt, ...)
+{
+ va_list args;
+ char *buf;
+
+ if (level > mprGetLogLevel(ctx)) {
+ return;
+ }
+
+ va_start(args, fmt);
+ mprAllocVsprintf(MPR_LOC_ARGS(ctx), &buf, 0, fmt, args);
+ va_end(args);
+
+ logOutput(MPR_LOC_ARGS(ctx), MPR_LOG_SRC, level, buf);
+
+ va_end(args);
+ mprFree(buf);
+}
+
+/*****************************************************************************/
+/*
+ * Do raw output
+ */
+
+void mprRawLog(MprCtx ctx, const char *fmt, ...)
+{
+ va_list args;
+ char *buf;
+ int len;
+
+ va_start(args, fmt);
+ len = mprAllocVsprintf(MPR_LOC_ARGS(ctx), &buf, 0, fmt, args);
+ va_end(args);
+
+ logOutput(MPR_LOC_ARGS(ctx), MPR_RAW, 0, buf);
+ mprFree(buf);
+}
+
+/*****************************************************************************/
+/*
+ * Handle an error
+ */
+
+void mprError(MPR_LOC_DEC(ctx, loc), const char *fmt, ...)
+{
+ va_list args;
+ char *buf;
+ int len;
+
+ va_start(args, fmt);
+ len = mprAllocVsprintf(MPR_LOC_ARGS(ctx), &buf, 0, fmt, args);
+ va_end(args);
+
+ logOutput(MPR_LOC_PASS(ctx, loc), MPR_ERROR_MSG | MPR_ERROR_SRC, 0, buf);
+
+ mprFree(buf);
+}
+
+/*****************************************************************************/
+/*
+ * Handle an error that should be displayed to the user
+ */
+
+void mprUserError(MPR_LOC_DEC(ctx, loc), const char *fmt, ...)
+{
+ va_list args;
+ char *buf;
+ int len;
+
+ va_start(args, fmt);
+ len = mprAllocVsprintf(MPR_LOC_ARGS(ctx), &buf, 0, fmt, args);
+ va_end(args);
+
+ logOutput(MPR_LOC_PASS(ctx, loc), MPR_USER_MSG | MPR_ERROR_SRC, 0, buf);
+
+ mprFree(buf);
+}
+
+/*****************************************************************************/
+/*
+ * Handle a fatal error. Forcibly shutdown the application.
+ */
+
+void mprFatalError(MPR_LOC_DEC(ctx, loc), const char *fmt, ...)
+{
+ va_list args;
+ char *buf;
+ int len;
+
+ va_start(args, fmt);
+ len = mprAllocVsprintf(MPR_LOC_ARGS(ctx), &buf, 0, fmt, args);
+ va_end(args);
+
+ logOutput(MPR_LOC_PASS(ctx, loc), MPR_USER_MSG | MPR_FATAL_SRC, 0, buf);
+
+ mprFree(buf);
+
+#if BREW
+ mprSignalExit(ctx);
+#else
+ exit(2);
+#endif
+}
+
+/*****************************************************************************/
+/*
+ * Handle a program assertion
+ */
+
+void mprAssertError(MPR_LOC_DEC(ctx, loc), const char *msg)
+{
+ logOutput(MPR_LOC_PASS(ctx, loc), MPR_ASSERT_MSG | MPR_ASSERT_SRC, 0, msg);
+}
+
+/*****************************************************************************/
+/*
+ * Handle an error
+ */
+
+void mprStaticError(MPR_LOC_DEC(ctx, loc), const char *fmt, ...)
+{
+ va_list args;
+ int len;
+ char buf[MPR_MAX_STRING];
+
+ va_start(args, fmt);
+ len = mprVsprintf(buf, sizeof(buf), fmt, args);
+ va_end(args);
+
+ logOutput(MPR_LOC_PASS(ctx, loc), MPR_ERROR_MSG | MPR_ERROR_SRC, 0, buf);
+}
+
+/*****************************************************************************/
+/*
+ * Direct output to the standard output. Does not hook into the logging
+ * system and does not allocate memory.
+ */
+
+void mprStaticAssert(const char *loc, const char *msg)
+{
+#if BLD_DEBUG
+ char buf[MPR_MAX_STRING];
+ int len;
+
+ len = mprSprintf(buf, sizeof(buf), "Assertion %s, failed at %s\n",
+ msg, loc);
+ mprBreakpoint(loc, buf);
+
+#if BLD_HOST_UNIX
+ /*
+ * MOB -- but is stdout always okay to use
+ */
+ write(1, buf, len);
+#elif BREW || WIN
+ /*
+ * Only time we use printf. We can't get an alloc context so we have
+ * to use real print
+ */
+#if BREW && !BREW_SIMULATOR
+ printf(" MP: %s\n", buf);
+#else
+ printf("%s\n", buf);
+#endif
+
+#endif
+#endif
+}
+
+/*****************************************************************************/
+
+int mprGetLogLevel(MprCtx ctx)
+{
+ return mprGetApp(ctx)->logLevel;
+}
+
+/******************************************************************************/
+
+void mprSetLogLevel(MprCtx ctx, int level)
+{
+ mprGetApp(ctx)->logLevel = level;
+}
+
+/*****************************************************************************/
+/*
+ * Output a log message to the log handler
+ */
+
+static void logOutput(MPR_LOC_DEC(ctx, loc), int flags, int level,
+ const char *msg)
+{
+ MprLogHandler handler;
+
+ if (flags & (MPR_ERROR_SRC | MPR_FATAL_SRC | MPR_ASSERT_SRC)) {
+ mprBreakpoint(MPR_LOC, 0);
+ }
+
+ mprAssert(ctx != 0);
+ handler = mprGetApp(ctx)->logHandler;
+ if (handler != 0) {
+ (handler)(MPR_LOC_PASS(ctx, loc), flags, level, msg);
+ return;
+ }
+ defaultLogHandler(MPR_LOC_PASS(ctx, loc), flags, level, msg);
+}
+
+/*****************************************************************************/
+/*
+ * Default log output is just to the console
+ */
+
+static void defaultLogHandler(MPR_LOC_DEC(ctx, loc), int flags,
+ int level, const char *msg)
+{
+ MprApp *app;
+ char *prefix;
+
+ app = mprGetApp(ctx);
+ prefix = app->name;
+
+ while (*msg == '\n') {
+ mprPrintf(ctx, "\n");
+ msg++;
+ }
+
+ if (flags & MPR_LOG_SRC) {
+#if BREW && !BREW_SIMULATOR
+ mprPrintf(ctx, "%s\n", msg);
+#else
+ mprPrintf(ctx, "%s: %d: %s\n", prefix, level, msg);
+#endif
+
+ } else if (flags & MPR_ERROR_SRC) {
+ /*
+ * Use static printing to avoid malloc when the messages are small.
+ * This is important for memory allocation errors.
+ */
+ if (strlen(msg) < (MPR_MAX_STRING - 32)) {
+ mprStaticPrintf(ctx, "%s: Error: %s\n", prefix, msg);
+ } else {
+ mprPrintf(ctx, "%s: Error: %s\n", prefix, msg);
+ }
+
+ } else if (flags & MPR_FATAL_SRC) {
+ mprPrintf(ctx, "%s: Fatal: %s\n", prefix, msg);
+
+ } else if (flags & MPR_ASSERT_SRC) {
+#if BLD_FEATURE_ALLOC_LEAK_TRACK
+ mprPrintf(ctx, "%s: Assertion %s, failed at %s\n", prefix, msg, loc);
+#else
+ mprPrintf(ctx, "%s: Assertion %s, failed\n", prefix, msg);
+#endif
+
+ } else if (flags & MPR_RAW) {
+ mprPrintf(ctx, "%s", msg);
+
+ } else {
+ return;
+ }
+}
+
+/*****************************************************************************/
+/*
+ * Map the O/S error code to portable error codes.
+ */
+
+int mprGetOsError()
+{
+#if WIN
+ int rc;
+ rc = GetLastError();
+
+ /*
+ * Client has closed the pipe
+ */
+ if (rc == ERROR_NO_DATA) {
+ return EPIPE;
+ }
+ return rc;
+#endif
+#if LINUX || VXWORKS || SOLARIS
+ return errno;
+#endif
+#if BREW
+ /*
+ * No such thing on Brew. Errors are per class
+ */
+ return 0;
+#endif
+}
+
+/******************************************************************************/
+#if UNUSED
+
+const char *mprGetErrorMsg(int err)
+{
+ /*
+ * MPR error messages. Declare here so we don't have any globals.
+ */
+ char *mprErrMessages[] = {
+ /* 0 MPR_ERR_OK */ "Success",
+ /* -201 MPR_ERR_GENERAL */ "General error",
+ /* -202 MPR_ERR_ABORTED */ "Aborted",
+ /* -203 MPR_ERR_ALREADY_EXISTS */ "Already exists",
+ /* -204 MPR_ERR_BAD_ARGS */ "Bad args",
+ /* -205 MPR_ERR_BAD_FORMAT */ "Bad format",
+ /* -206 MPR_ERR_BAD_HANDLE */ "Bad handle",
+ /* -207 MPR_ERR_BAD_STATE */ "Bad state",
+ /* -208 MPR_ERR_BAD_SYNTAX */ "Bad syntax",
+ /* -209 MPR_ERR_BAD_TYPE */ "Bad type",
+ /* -210 MPR_ERR_BAD_VALUE */ "Bad value",
+ /* -211 MPR_ERR_BUSY */ "Busy",
+ /* -212 MPR_ERR_CANT_ACCESS */ "Can't access",
+ /* -213 MPR_ERR_CANT_COMPLETE */ "Can't complete",
+ /* -214 MPR_ERR_CANT_CREATE */ "Can't create",
+ /* -215 MPR_ERR_CANT_INITIALIZE */ "Can't initialize",
+ /* -216 MPR_ERR_CANT_OPEN */ "Can't open",
+ /* -217 MPR_ERR_CANT_READ */ "Can't read",
+ /* -218 MPR_ERR_CANT_WRITE */ "Can't write",
+ /* -219 MPR_ERR_DELETED */ "Already deleted",
+ /* -220 MPR_ERR_NETWORK */ "Network error",
+ /* -221 MPR_ERR_NOT_FOUND */ "Not found",
+ /* -222 MPR_ERR_NOT_INITIALIZED */ "Not initialized",
+ /* -223 MPR_ERR_NOT_READY */ "Not ready",
+ /* -224 MPR_ERR_READ_ONLY */ "Read only",
+ /* -225 MPR_ERR_TIMEOUT */ "Timeout",
+ /* -226 MPR_ERR_TOO_MANY */ "Too many",
+ /* -227 MPR_ERR_WONT_FIT */ "Won't fit",
+ /* -228 MPR_ERR_WOULD_BLOCK */ "Would block",
+ /* -229 MPR_ERR_CANT_ALLOCATE */ "Can't allocate",
+ };
+ int mprNumErr = sizeof(mprErrMessages) / sizeof(char*);
+
+/*
+ * Operating system error messages
+ */
+#if WIN
+char *osErrMessages[] =
+{
+ /* 0 */ "No error",
+ /* 1 EPERM */ "Operation not permitted",
+ /* 2 ENOENT */ "No such file or directory",
+ /* 3 ESRCH */ "No such process",
+ /* 4 EINTR */ "Interrupted function call",
+ /* 5 EIO */ "I/O error",
+ /* 6 ENXIO */ "No such device or address",
+ /* 7 E2BIG */ "Arg list too long",
+ /* 8 ENOEXEC */ "Exec format error",
+ /* 9 EBADF */ "Bad file number",
+ /* 10 ECHILD */ "No child processes",
+ /* 11 EAGAIN */ "Try again",
+ /* 12 ENOMEM */ "Out of memory",
+ /* 13 EACCES */ "Permission denied",
+ /* 14 EFAULT */ "Bad address",
+ /* 15 ENOTBLK */ "Unknown error",
+ /* 16 EBUSY */ "Resource busy",
+ /* 17 EEXIST */ "File exists",
+ /* 18 EXDEV */ "Improper link",
+ /* 19 ENODEV */ "No such device",
+ /* 20 ENOTDIR */ "Not a directory",
+ /* 21 EISDIR */ "Is a directory",
+ /* 22 EINVAL */ "Invalid argument",
+ /* 23 ENFILE */ "Too many open files in system",
+ /* 24 EMFILE */ "Too many open files",
+ /* 25 ENOTTY */ "Inappropriate I/O control operation",
+ /* 26 ETXTBSY */ "Unknown error",
+ /* 27 EFBIG */ "File too large",
+ /* 28 ENOSPC */ "No space left on device",
+ /* 29 ESPIPE */ "Invalid seek",
+ /* 30 EROFS */ "Read-only file system",
+ /* 31 EMLINK */ "Too many links",
+ /* 32 EPIPE */ "Broken pipe",
+ /* 33 EDOM */ "Domain error",
+ /* 34 ERANGE */ "Result too large",
+ /* 35 EUCLEAN */ "Unknown error",
+ /* 36 EDEADLK */ "Resource deadlock would occur",
+ /* 37 UNKNOWN */ "Unknown error",
+ /* 38 ENAMETOOLONG */ "Filename too long",
+ /* 39 ENOLCK */ "No locks available",
+ /* 40 ENOSYS */ "Function not implemented",
+ /* 41 ENOTEMPTY */ "Directory not empty",
+ /* 42 EILSEQ */ "Illegal byte sequence",
+ /* 43 ENETDOWN */ "Network is down",
+ /* 44 ECONNRESET */ "Connection reset",
+ /* 45 ECONNREFUSED */ "Connection refused",
+ /* 46 EADDRINUSE */ "Address already in use"
+
+};
+
+#else /* WIN */
+
+char *osErrMessages[] =
+{
+ /* 0 */ "Success"
+ /* 1 EPERM */ "Operation not permitted"
+ /* 2 ENOENT */ "No such file or directory"
+ /* 3 ESRCH */ "No such process"
+ /* 4 EINTR */ "Interrupted system call"
+ /* 5 EIO */ "I/O error"
+ /* 6 ENXIO */ "No such device or address"
+ /* 7 E2BIG */ "Arg list too long"
+ /* 8 ENOEXEC */ "Exec format error"
+ /* 9 EBADF */ "Bad file number"
+ /* 10 ECHILD */ "No child processes"
+ /* 11 EAGAIN */ "Try again"
+ /* 12 ENOMEM */ "Out of memory"
+ /* 13 EACCES */ "Permission denied"
+ /* 14 EFAULT */ "Bad address"
+ /* 15 ENOTBLK */ "Block device required"
+ /* 16 EBUSY */ "Device or resource busy"
+ /* 17 EEXIST */ "File exists"
+ /* 18 EXDEV */ "Cross-device link"
+ /* 19 ENODEV */ "No such device"
+ /* 20 ENOTDIR */ "Not a directory"
+ /* 21 EISDIR */ "Is a directory"
+ /* 22 EINVAL */ "Invalid argument"
+ /* 23 ENFILE */ "File table overflow"
+ /* 24 EMFILE */ "Too many open files"
+ /* 25 ENOTTY */ "Not a typewriter"
+ /* 26 ETXTBSY */ "Text file busy"
+ /* 27 EFBIG */ "File too large"
+ /* 28 ENOSPC */ "No space left on device"
+ /* 29 ESPIPE */ "Illegal seek"
+ /* 30 EROFS */ "Read-only file system"
+ /* 31 EMLINK */ "Too many links"
+ /* 32 EPIPE */ "Broken pipe"
+ /* 33 EDOM */ "Math argument out of domain of func"
+ /* 34 ERANGE */ "Math result not representable"
+ /* 35 EDEADLK */ "Resource deadlock would occur"
+ /* 36 ENAMETOOLONG */ "File name too long"
+ /* 37 ENOLCK */ "No record locks available"
+ /* 38 ENOSYS */ "Function not implemented"
+ /* 39 ENOTEMPTY */ "Directory not empty"
+ /* 40 ELOOP */ "Too many symbolic links encountered"
+ /* 41 EWOULDBLOCK EAGAIN */"Operation would block"
+ /* 42 ENOMSG */ "No message of desired type"
+ /* 43 EIDRM */ "Identifier removed"
+
+#if !BLD_FEATURE_SQUEEZE
+ /* 44 ECHRNG */ "Channel number out of range"
+ /* 45 EL2NSYNC */ "Level 2 not synchronized"
+ /* 46 EL3HLT */ "Level 3 halted"
+ /* 47 EL3RST */ "Level 3 reset"
+ /* 48 ELNRNG */ "Link number out of range"
+ /* 49 EUNATCH */ "Protocol driver not attached"
+ /* 50 ENOCSI */ "No CSI structure available"
+ /* 51 EL2HLT */ "Level 2 halted"
+ /* 52 EBADE */ "Invalid exchange"
+ /* 53 EBADR */ "Invalid request descriptor"
+ /* 54 EXFULL */ "Exchange full"
+ /* 55 ENOANO */ "No anode"
+ /* 56 EBADRQC */ "Invalid request code"
+ /* 57 EBADSLT */ "Invalid slot"
+ /* 59 EBFONT */ "Bad font file format"
+ /* 60 ENOSTR */ "Device not a stream"
+ /* 61 ENODATA */ "No data available"
+ /* 62 ETIME */ "Timer expired"
+ /* 63 ENOSR */ "Out of streams resources"
+ /* 64 ENONET */ "Machine is not on the network"
+ /* 65 ENOPKG */ "Package not installed"
+ /* 66 EREMOTE */ "Object is remote"
+ /* 67 ENOLINK */ "Link has been severed"
+ /* 68 EADV */ "Advertise error"
+ /* 69 ESRMNT */ "Srmount error"
+ /* 70 ECOMM */ "Communication error on send"
+ /* 71 EPROTO */ "Protocol error"
+ /* 72 EMULTIHOP */ "Multihop attempted"
+ /* 73 EDOTDOT */ "RFS specific error"
+ /* 74 EBADMSG */ "Not a data message"
+ /* 75 EOVERFLOW */ "Value too large for defined data type"
+ /* 76 ENOTUNIQ */ "Name not unique on network"
+ /* 77 EBADFD */ "File descriptor in bad state"
+ /* 78 EREMCHG */ "Remote address changed"
+ /* 79 ELIBACC */ "Can not access a needed shared library"
+ /* 80 ELIBBAD */ "Accessing a corrupted shared library"
+ /* 81 ELIBSCN */ ".lib section in a.out corrupted"
+ /* 82 ELIBMAX */ "Linking in too many shared libraries"
+ /* 83 ELIBEXEC */ "Cannot exec a shared library directly"
+ /* 84 EILSEQ */ "Illegal byte sequence"
+ /* 85 ERESTART */ "Interrupted system call should be restarted"
+ /* 86 ESTRPIPE */ "Streams pipe error"
+ /* 87 EUSERS */ "Too many users"
+ /* 88 ENOTSOCK */ "Socket operation on non-socket"
+ /* 89 EDESTADDRREQ */ "Destination address required"
+ /* 90 EMSGSIZE */ "Message too long"
+ /* 91 EPROTOTYPE */ "Protocol wrong type for socket"
+ /* 92 ENOPROTOOPT */ "Protocol not available"
+ /* 93 EPROTONOSUPPORT */ "Protocol not supported"
+ /* 94 ESOCKTNOSUPPORT */ "Socket type not supported"
+ /* 95 EOPNOTSUPP */ "Operation not supported on transport endpoint"
+ /* 96 EPFNOSUPPORT */ "Protocol family not supported"
+ /* 97 EAFNOSUPPORT */ "Address family not supported by protocol"
+ /* 98 EADDRINUSE */ "Address already in use"
+ /* 99 EADDRNOTAVAIL */ "Cannot assign requested address"
+ /* 100 ENETDOWN */ "Network is down"
+ /* 101 ENETUNREACH */ "Network is unreachable"
+ /* 102 ENETRESET */ "Network dropped connection because of reset"
+ /* 103 ECONNABORTED */ "Software caused connection abort"
+ /* 104 ECONNRESET */ "Connection reset by peer"
+ /* 105 ENOBUFS */ "No buffer space available"
+ /* 106 EISCONN */ "Transport endpoint is already connected"
+ /* 107 ENOTCONN */ "Transport endpoint is not connected"
+ /* 108 ESHUTDOWN */ "Cannot send after transport endpoint shutdown"
+ /* 109 ETOOMANYREFS */ "Too many references: cannot splice"
+ /* 110 ETIMEDOUT */ "Connection timed out"
+ /* 111 ECONNREFUSED */ "Connection refused"
+ /* 112 EHOSTDOWN */ "Host is down"
+ /* 113 EHOSTUNREACH */ "No route to host"
+ /* 114 EALREADY */ "Operation already in progress"
+ /* 115 EINPROGRESS */ "Operation now in progress"
+ /* 116 ESTALE */ "Stale NFS file handle"
+ /* 117 EUCLEAN */ "Structure needs cleaning"
+ /* 118 ENOTNAM */ "Not a XENIX named type file"
+ /* 119 ENAVAIL */ "No XENIX semaphores available"
+ /* 120 EISNAM */ "Is a named type file"
+ /* 121 EREMOTEIO */ "Remote I/O error"
+ /* 122 EDQUOT */ "Quota exceeded"
+ /* 123 ENOMEDIUM */ "No medium found"
+ /* 124 EMEDIUMTYPE */ "Wrong medium type"
+};
+#endif /* BLD_FEATURE_SQUEEZE */
+#endif /* WIN */
+
+ int osNumErr = sizeof(osErrMessages) / sizeof(char*);
+
+ if (err < MPR_ERR_BASE) {
+ err = MPR_ERR_BASE - err;
+ if (err < 0 || err >= mprNumErr) {
+ return "Bad error code";
+ }
+ return mprErrMessages[err];
+
+ } else {
+ /*
+ * Negative O/S error code. Map to a positive standard Posix error.
+ */
+ err = -err;
+ if (err < 0 || err >= osNumErr) {
+ return "Bad O/S error code";
+ }
+ return osErrMessages[err];
+ }
+}
+
+#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/mpr/mprOs.h b/source4/lib/appweb/ejs-2.0/mpr/mprOs.h
new file mode 100644
index 0000000000..bed4ca5979
--- /dev/null
+++ b/source4/lib/appweb/ejs-2.0/mpr/mprOs.h
@@ -0,0 +1,707 @@
+/*
+ * @file mprOs.h
+ * @brief Include O/S headers and smooth out per-O/S differences
+ * @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
+ */
+
+/******************************* Documentation ********************************/
+
+/*
+ * This header is part of the Mbedthis Portable Runtime and aims to include
+ * all necessary O/S headers and to unify the constants and declarations
+ * required by Mbedthis products. It can be included by C or C++ programs.
+ */
+
+/******************************************************************************/
+
+#ifndef _h_MPR_OS_HDRS
+#define _h_MPR_OS_HDRS 1
+
+#include "buildConfig.h"
+
+/********************************* CPU Families *******************************/
+/*
+ * Porters, add your CPU families here and update configure code.
+ */
+#define MPR_CPU_UNKNOWN 0
+#define MPR_CPU_IX86 1
+#define MPR_CPU_PPC 2
+#define MPR_CPU_SPARC 3
+#define MPR_CPU_XSCALE 4
+#define MPR_CPU_ARM 5
+#define MPR_CPU_MIPS 6
+#define MPR_CPU_68K 7
+#define MPR_CPU_SIMNT 8 /* VxWorks NT simulator */
+#define MPR_CPU_SIMSPARC 9 /* VxWorks sparc simulator */
+
+/********************************* O/S Includes *******************************/
+
+#if LINUX || SOLARIS
+ #include <sys/types.h>
+ #include <time.h>
+ #include <arpa/inet.h>
+ #include <ctype.h>
+ #include <dirent.h>
+ #include <dlfcn.h>
+ #include <fcntl.h>
+ #include <grp.h>
+ #include <errno.h>
+ #include <libgen.h>
+ #include <limits.h>
+ #include <netdb.h>
+ #include <net/if.h>
+ #include <netinet/in.h>
+ #include <netinet/tcp.h>
+ #include <netinet/ip.h>
+ #include <pthread.h>
+ #include <pwd.h>
+ #include <resolv.h>
+ #include <signal.h>
+ #include <stdarg.h>
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <string.h>
+ #include <syslog.h>
+ #include <sys/ioctl.h>
+ #include <sys/stat.h>
+ #include <sys/param.h>
+ #include <sys/resource.h>
+ #include <sys/sem.h>
+ #include <sys/shm.h>
+ #include <sys/socket.h>
+ #include <sys/select.h>
+ #include <sys/time.h>
+ #include <sys/times.h>
+ #include <sys/utsname.h>
+ #include <sys/wait.h>
+ #include <unistd.h>
+
+#if LINUX
+ #include <stdint.h>
+#endif
+
+#if SOLARIS
+ #include <netinet/in_systm.h>
+#endif
+
+#if BLD_FEATURE_FLOATING_POINT
+ #define __USE_ISOC99 1
+ #include <math.h>
+ #include <values.h>
+#endif
+
+#endif /* LINUX || SOLARIS */
+
+#if VXWORKS
+ #include <vxWorks.h>
+ #include <envLib.h>
+ #include <sys/types.h>
+ #include <time.h>
+ #include <arpa/inet.h>
+ #include <ctype.h>
+ #include <dirent.h>
+ #include <fcntl.h>
+ #include <errno.h>
+ #include <limits.h>
+ #include <loadLib.h>
+ #include <netdb.h>
+ #include <net/if.h>
+ #include <netinet/tcp.h>
+ #include <netinet/in.h>
+ #include <netinet/ip.h>
+ #include <signal.h>
+ #include <stdarg.h>
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <string.h>
+ #include <sysSymTbl.h>
+ #include <sys/fcntlcom.h>
+ #include <sys/ioctl.h>
+ #include <sys/stat.h>
+ #include <sys/socket.h>
+ #include <sys/times.h>
+ #include <sys/wait.h>
+ #include <unistd.h>
+ #include <unldLib.h>
+
+ #if BLD_FEATURE_FLOATING_POINT
+ #include <float.h>
+ #define __USE_ISOC99 1
+ #include <math.h>
+ #endif
+
+ #include <sockLib.h>
+ #include <inetLib.h>
+ #include <ioLib.h>
+ #include <pipeDrv.h>
+ #include <hostLib.h>
+ #include <netdb.h>
+ #include <tickLib.h>
+ #include <taskHookLib.h>
+
+#endif /* VXWORKS */
+
+#if MACOSX
+ #include <time.h>
+ #include <arpa/inet.h>
+ #include <ctype.h>
+ #include <fcntl.h>
+ #include <grp.h>
+ #include <errno.h>
+ #include <libgen.h>
+ #include <limits.h>
+ #include <mach-o/dyld.h>
+ #include <netdb.h>
+ #include <net/if.h>
+ #include <netinet/in_systm.h>
+ #include <netinet/in.h>
+ #include <netinet/tcp.h>
+ #include <netinet/ip.h>
+ #include <pthread.h>
+ #include <pwd.h>
+ #include <resolv.h>
+ #include <signal.h>
+ #include <stdarg.h>
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <stdint.h>
+ #include <string.h>
+ #include <syslog.h>
+ #include <sys/ioctl.h>
+ #include <sys/types.h>
+ #include <sys/stat.h>
+ #include <sys/param.h>
+ #include <sys/resource.h>
+ #include <sys/sem.h>
+ #include <sys/shm.h>
+ #include <sys/socket.h>
+ #include <sys/select.h>
+ #include <sys/time.h>
+ #include <sys/times.h>
+ #include <sys/types.h>
+ #include <sys/utsname.h>
+ #include <sys/wait.h>
+ #include <unistd.h>
+#endif /* MACOSX */
+
+#if WIN
+ /*
+ * We replace insecure functions with Mbedthis replacements
+ */
+ #define _CRT_SECURE_NO_DEPRECATE 1
+
+ #include <ctype.h>
+ #include <conio.h>
+ #include <direct.h>
+ #include <errno.h>
+ #include <fcntl.h>
+ #include <io.h>
+ #include <limits.h>
+ #include <malloc.h>
+ #include <process.h>
+ #include <sys/stat.h>
+ #include <sys/types.h>
+ #include <stddef.h>
+ #include <stdio.h>
+ #include <stdlib.h>
+ #include <string.h>
+ #include <stdarg.h>
+ #include <time.h>
+ #define WIN32_LEAN_AND_MEAN
+ #include <winsock2.h>
+ #include <windows.h>
+ #include <winbase.h>
+ #if BLD_FEATURE_FLOATING_POINT
+ #include <float.h>
+ #endif
+ #include <shlobj.h>
+ #include <shellapi.h>
+ #include <wincrypt.h>
+
+#if BLD_DEBUG
+ #include <crtdbg.h>
+#endif
+ #include "mprUnix.h"
+#endif /* WIN */
+
+#if BREW
+ #if BLD_FEATURE_FLOATING_POINT
+ #warning "Floating point is not supported on Brew"
+ #endif
+ #if BLD_FEATURE_MULTITHREAD
+ #warning "Multithreading is not supported on Brew"
+ #endif
+
+ #include "AEEModGen.h"
+ #include "AEEAppGen.h"
+ #include "BREWVersion.h"
+
+ #if BREW_MAJ_VER == 2
+ /*
+ * Fix for BREW 2.X
+ */
+ #ifdef __GNUC__
+ #define __inline extern __inline__
+ #endif
+ #include "AEENet.h"
+ #undef __inline
+ #endif
+
+ #include "AEE.h"
+ #include "AEEBitmap.h"
+ #include "AEEDisp.h"
+ #include "AEEFile.h"
+ #include "AEEHeap.h"
+ #include "AEEImageCtl.h"
+ #include "AEEMedia.h"
+ #include "AEEMediaUtil.h"
+ #include "AEEMimeTypes.h"
+ #include "AEEStdLib.h"
+ #include "AEEShell.h"
+ #include "AEESoundPlayer.h"
+ #include "AEEText.h"
+ #include "AEETransform.h"
+ #include "AEEWeb.h"
+ #if BREW_MAJ_VER >= 3
+ #include "AEESMS.h"
+ #endif
+ #include "AEETAPI.h"
+
+#if 0
+ #include "AEESound.h"
+ #include "AEEDb.h"
+ #include "AEEMenu.h"
+#endif
+
+#endif /* BREW */
+
+/******************************************************************************/
+/******************************* General Defines ******************************/
+/******************************************************************************/
+
+#ifndef MAXINT
+#if INT_MAX
+ #define MAXINT INT_MAX
+#else
+ #define MAXINT 0x7fffffff
+#endif
+#endif
+
+#ifndef BITSPERBYTE
+#define BITSPERBYTE (8 * sizeof(char))
+#endif
+
+#define BITS(type) (BITSPERBYTE * (int) sizeof(type))
+
+#ifndef max
+#define max(a,b) (((a) > (b)) ? (a) : (b))
+#endif
+
+#ifndef min
+#define min(a,b) (((a) < (b)) ? (a) : (b))
+#endif
+
+#define MPR_ARRAY_SIZE(type) (sizeof(type) / sizeof(type[0]))
+
+#ifndef PRINTF_ATTRIBUTE
+#if (__GNUC__ >= 3) && !DOXYGEN && BLD_FEATURE_ALLOC_LEAK_TRACK
+/** Use gcc attribute to check printf fns. a1 is the 1-based index of
+ * the parameter containing the format, and a2 the index of the first
+ * argument. Note that some gcc 2.x versions don't handle this
+ * properly **/
+#define PRINTF_ATTRIBUTE(a1, a2) __attribute__ ((format (__printf__, a1, a2)))
+#else
+#define PRINTF_ATTRIBUTE(a1, a2)
+#endif
+#endif
+
+typedef char *MprStr; /* Used for dynamic strings */
+
+#ifdef __cplusplus
+extern "C" {
+#else
+typedef int bool;
+#endif
+
+/******************************************************************************/
+/******************************** Linux Defines *******************************/
+/******************************************************************************/
+
+#if LINUX
+ typedef unsigned char uchar;
+
+#if BLD_FEATURE_INT64
+ __extension__ typedef long long int int64;
+ __extension__ typedef unsigned long long int uint64;
+ #define INT64(x) (x##LL)
+ #define UINT64(x) (x##ULL)
+#endif
+
+ #define closesocket(x) close(x)
+ #define MPR_BINARY ""
+ #define MPR_TEXT ""
+ #define O_BINARY 0
+ #define O_TEXT 0
+ #define SOCKET_ERROR -1
+ #define MPR_DLL_EXT ".so"
+
+#if BLD_FEATURE_FLOATING_POINT
+ #define MAX_FLOAT MAXFLOAT
+#endif
+
+/*
+ * For some reason it is removed from fedora pthreads.h and only
+ * comes in for UNIX96
+ */
+extern int pthread_mutexattr_gettype (__const pthread_mutexattr_t *__restrict
+ __attr, int *__restrict __kind) __THROW;
+/* Set the mutex kind attribute in *ATTR to KIND (either PTHREAD_MUTEX_NORMAL,
+ PTHREAD_MUTEX_RECURSIVE, PTHREAD_MUTEX_ERRORCHECK, or
+ PTHREAD_MUTEX_DEFAULT). */
+extern int pthread_mutexattr_settype (pthread_mutexattr_t *__attr, int __kind)
+ __THROW;
+
+#endif /* LINUX */
+
+/******************************************************************************/
+/******************************* VxWorks Defines ******************************/
+/******************************************************************************/
+
+#if VXWORKS
+
+ typedef unsigned char uchar;
+ typedef unsigned int uint;
+ typedef unsigned long ulong;
+
+ #define HAVE_SOCKLEN_T
+ typedef int socklen_t;
+
+#if BLD_FEATURE_INT64
+ typedef long long int int64;
+ typedef unsigned long long int uint64;
+ #define INT64(x) (x##LL)
+ #define UINT64(x) (x##ULL)
+#endif
+
+ #define closesocket(x) close(x)
+ #define getpid() taskIdSelf()
+ #define MPR_BINARY ""
+ #define MPR_TEXT ""
+ #define O_BINARY 0
+ #define O_TEXT 0
+ #define SOCKET_ERROR -1
+ #define MPR_DLL_EXT ".so"
+
+#if BLD_FEATURE_FLOATING_POINT
+ #define MAX_FLOAT FLT_MAX
+#endif
+
+ #undef R_OK
+ #define R_OK 4
+ #undef W_OK
+ #define W_OK 2
+ #undef X_OK
+ #define X_OK 1
+ #undef F_OK
+ #define F_OK 0
+
+ #define MSG_NOSIGNAL 0
+
+ extern int access(char *path, int mode);
+ extern int sysClkRateGet();
+
+#endif /* VXWORKS */
+
+/******************************************************************************/
+/******************************** MacOsx Defines ******************************/
+/******************************************************************************/
+#if MACOSX
+ typedef unsigned long ulong;
+ typedef unsigned char uchar;
+
+#if BLD_FEATURE_INT64
+ __extension__ typedef long long int int64;
+ __extension__ typedef unsigned long long int uint64;
+ #define INT64(x) (x##LL)
+ #define UINT64(x) (x##ULL)
+#endif
+
+ #define closesocket(x) close(x)
+ #define MPR_BINARY ""
+ #define MPR_TEXT ""
+ #define O_BINARY 0
+ #define O_TEXT 0
+ #define SOCKET_ERROR -1
+ #define MPR_DLL_EXT ".dylib"
+ #define MSG_NOSIGNAL 0
+ #define __WALL 0x40000000
+ #define PTHREAD_MUTEX_RECURSIVE_NP PTHREAD_MUTEX_RECURSIVE
+
+#if BLD_FEATURE_FLOATING_POINT
+ #define MAX_FLOAT MAXFLOAT
+#endif
+
+#endif /* MACOSX */
+
+/******************************************************************************/
+/******************************* Windows Defines ******************************/
+/******************************************************************************/
+
+#if WIN
+ typedef unsigned char uchar;
+ typedef unsigned int uint;
+ typedef unsigned long ulong;
+ typedef unsigned short ushort;
+
+/*
+ * We always define INT64 types on windows
+ */
+#if BLD_FEATURE_INT64 || 1
+ typedef __int64 int64;
+ typedef unsigned __int64 uint64;
+ #define INT64(x) (x##i64)
+ #define UINT64(x) (x##Ui64)
+#endif
+
+ typedef int uid_t;
+ typedef void *handle;
+ typedef char *caddr_t;
+ typedef long pid_t;
+ typedef int gid_t;
+ typedef ushort mode_t;
+ typedef void *siginfo_t;
+
+ #define HAVE_SOCKLEN_T
+ typedef int socklen_t;
+
+ #undef R_OK
+ #define R_OK 4
+ #undef W_OK
+ #define W_OK 2
+
+ /*
+ * On windows map X_OK to R_OK
+ */
+ #undef X_OK
+ #define X_OK 4
+ #undef F_OK
+ #define F_OK 0
+
+ #ifndef EADDRINUSE
+ #define EADDRINUSE 46
+ #endif
+ #ifndef EWOULDBLOCK
+ #define EWOULDBLOCK EAGAIN
+ #endif
+ #ifndef ENETDOWN
+ #define ENETDOWN 43
+ #endif
+ #ifndef ECONNRESET
+ #define ECONNRESET 44
+ #endif
+ #ifndef ECONNREFUSED
+ #define ECONNREFUSED 45
+ #endif
+
+ #define MSG_NOSIGNAL 0
+ #define MPR_BINARY "b"
+ #define MPR_TEXT "t"
+
+#if BLD_FEATURE_FLOATING_POINT
+ #define MAX_FLOAT DBL_MAX
+#endif
+
+#ifndef FILE_FLAG_FIRST_PIPE_INSTANCE
+#define FILE_FLAG_FIRST_PIPE_INSTANCE 0x00080000
+#endif
+
+ #define MPR_DLL_EXT ".dll"
+#endif /* WIN */
+
+/******************************************************************************/
+/****************************** Solaris Defines *******************************/
+/******************************************************************************/
+
+#if SOLARIS
+ typedef unsigned char uchar;
+
+#if BLD_FEATURE_INT64
+ typedef long long int int64;
+ typedef unsigned long long int uint64;
+ #define INT64(x) (x##LL)
+ #define UINT64(x) (x##ULL)
+#endif
+
+ #define closesocket(x) close(x)
+ #define MPR_BINARY ""
+ #define MPR_TEXT ""
+ #define O_BINARY 0
+ #define O_TEXT 0
+ #define SOCKET_ERROR -1
+ #define MPR_DLL_EXT ".so"
+ #define MSG_NOSIGNAL 0
+ #define INADDR_NONE ((in_addr_t) 0xffffffff)
+ #define __WALL 0
+ #define PTHREAD_MUTEX_RECURSIVE_NP PTHREAD_MUTEX_RECURSIVE
+
+#if BLD_FEATURE_FLOATING_POINT
+ #define MAX_FLOAT MAXFLOAT
+#endif
+
+#endif /* SOLARIS */
+
+/******************************************************************************/
+/********************************* BREW Defines *******************************/
+/******************************************************************************/
+
+#if BREW
+ typedef unsigned char uchar;
+ typedef unsigned int uint;
+ typedef unsigned long ulong;
+ typedef unsigned short ushort;
+
+ typedef uint off_t;
+ typedef long pid_t;
+
+#if UNUSED
+ typedef int uid_t;
+ typedef void *handle;
+ typedef char *caddr_t;
+ typedef int gid_t;
+ typedef ushort mode_t;
+ typedef void *siginfo_t;
+
+ #define HAVE_SOCKLEN_T
+ typedef int socklen_t;
+
+ #ifndef EADDRINUSE
+ #define EADDRINUSE 46
+ #endif
+ #ifndef EWOULDBLOCK
+ #define EWOULDBLOCK EAGAIN
+ #endif
+ #ifndef ENETDOWN
+ #define ENETDOWN 43
+ #endif
+ #ifndef ECONNRESET
+ #define ECONNRESET 44
+ #endif
+ #ifndef ECONNREFUSED
+ #define ECONNREFUSED 45
+ #endif
+
+ #define MSG_NOSIGNAL 0
+ #define MPR_BINARY "b"
+ #define MPR_TEXT "t"
+
+ #define MPR_DLL_EXT ".dll"
+#endif
+
+ #define O_RDONLY 0
+ #define O_WRONLY 1
+ #define O_RDWR 2
+ #define O_CREAT 0x200
+ #define O_TRUNC 0x400
+ #define O_BINARY 0
+ #define O_TEXT 0x20000
+ #define O_EXCL 0x40000
+ #define O_APPEND 0x80000
+
+ #define R_OK 4
+ #define W_OK 2
+ #define X_OK 1
+ #define F_OK 0
+
+ #define SEEK_SET 0
+ #define SEEK_CUR 1
+ #define SEEK_END 2
+
+#if UNUSED
+struct stat {
+ uint st_size;
+};
+#endif
+
+extern int getpid();
+extern int isalnum(int c);
+extern int isalpha(int c);
+extern int isdigit(int c);
+extern int islower(int c);
+extern int isupper(int c);
+extern int isspace(int c);
+extern int isxdigit(int c);
+
+extern uint strlen(const char *str);
+extern char *strstr(const char *string, const char *strSet);
+extern void *memset(const void *dest, int c, uint count);
+extern void exit(int status);
+extern char *strpbrk(const char *str, const char *set);
+extern uint strspn(const char *str, const char *set);
+extern int tolower(int c);
+extern int toupper(int c);
+extern void *memcpy(void *dest, const void *src, uint count);
+extern void *memmove(void *dest, const void *src, uint count);
+
+extern int atoi(const char *str);
+extern void free(void *ptr);
+extern void *malloc(uint size);
+extern void *realloc(void *ptr, uint size);
+extern char *strcat(char *dest, const char *src);
+extern char *strchr(const char *str, int c);
+extern int strcmp(const char *s1, const char *s2);
+extern int strncmp(const char *s1, const char *s2, uint count);
+extern char *strcpy(char *dest, const char *src);
+extern char *strncpy(char *dest, const char *src, uint count);
+extern char *strrchr(const char *str, int c);
+
+#undef printf
+#define printf DBGPRINTF
+
+#if BREW_SIMULATOR && BLD_DEBUG
+extern _CRTIMP int __cdecl _CrtCheckMemory(void);
+extern _CRTIMP int __cdecl _CrtSetReportHook();
+#endif
+
+#endif /* BREW */
+
+/******************************************************************************/
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _h_MPR_OS_HDRS */
+
+/*
+ * 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/mpr/mprPrintf.c b/source4/lib/appweb/ejs-2.0/mpr/mprPrintf.c
new file mode 100644
index 0000000000..2d0951acfa
--- /dev/null
+++ b/source4/lib/appweb/ejs-2.0/mpr/mprPrintf.c
@@ -0,0 +1,924 @@
+/**
+ * @file mprPrintf.c
+ * @brief Printf routines safe for embedded programming
+ * @overview This module provides safe replacements for the standard
+ * printf formatting routines.
+ * @remarks Most routines in this file are not thread-safe. It is the callers
+ * responsibility to perform all thread synchronization.
+ */
+
+/*
+ * @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 **********************************/
+/*
+ * We need to use the underlying str(cpy) routines to implement our safe
+ * alternatives
+ */
+#if !DOXYGEN
+#define UNSAFE_FUNCTIONS_OK 1
+#endif
+
+#include "mpr.h"
+
+/*********************************** Defines **********************************/
+/*
+ * Class definitions
+ */
+#define CLASS_NORMAL 0 /* [All other] Normal characters */
+#define CLASS_PERCENT 1 /* [%] Begin format */
+#define CLASS_MODIFIER 2 /* [-+ #,] Modifiers */
+#define CLASS_ZERO 3 /* [0] Special modifier */
+#define CLASS_STAR 4 /* [*] Width supplied by arg */
+#define CLASS_DIGIT 5 /* [1-9] Field widths */
+#define CLASS_DOT 6 /* [.] Introduce precision */
+#define CLASS_BITS 7 /* [hlL] Length bits */
+#define CLASS_TYPE 8 /* [cdfinopsSuxX] Type specifiers */
+
+#define STATE_NORMAL 0 /* Normal chars in format string */
+#define STATE_PERCENT 1 /* "%" */
+#define STATE_MODIFIER 2 /* Read flag */
+#define STATE_WIDTH 3 /* Width spec */
+#define STATE_DOT 4 /* "." */
+#define STATE_PRECISION 5 /* Precision spec */
+#define STATE_BITS 6 /* Size spec */
+#define STATE_TYPE 7 /* Data type */
+#define STATE_COUNT 8
+
+/*
+ * Format: %[modifier][width][precision][bits][type]
+ *
+ * #define CLASS_MODIFIER 2 [-+ #,] Modifiers
+ * #define CLASS_BITS 7 [hlL] Length bits
+ */
+
+
+/*
+ * Flags
+ */
+#define SPRINTF_LEFT 0x1 /* Left align */
+#define SPRINTF_SIGN 0x2 /* Always sign the result */
+#define SPRINTF_LEAD_SPACE 0x4 /* put leading space for +ve numbers */
+#define SPRINTF_ALTERNATE 0x8 /* Alternate format */
+#define SPRINTF_LEAD_ZERO 0x10 /* Zero pad */
+#define SPRINTF_SHORT 0x20 /* 16-bit */
+#define SPRINTF_LONG 0x40 /* 32-bit */
+#if BLD_FEATURE_INT64
+#define SPRINTF_LONGLONG 0x80 /* 64-bit */
+#endif
+#define SPRINTF_COMMA 0x100 /* Thousand comma separators */
+#define SPRINTF_UPPER_CASE 0x200 /* As the name says for numbers */
+
+typedef struct Format {
+ uchar *buf;
+ uchar *endbuf;
+ uchar *start;
+ uchar *end;
+ int growBy;
+ int maxsize;
+
+ int precision;
+ int radix;
+ int width;
+ int flags;
+ int len;
+} Format;
+
+static int growBuf(MPR_LOC_DEC(ctx, loc), Format *fmt);
+
+#define BPUT(ctx, loc, fmt, c) \
+ if (1) { \
+ /* Less one to allow room for the null */ \
+ if ((fmt)->end >= ((fmt)->endbuf - sizeof(char))) { \
+ if (growBuf(MPR_LOC_PASS(ctx, loc), fmt)) { \
+ *(fmt)->end++ = (c); \
+ } \
+ } else { \
+ *(fmt)->end++ = (c); \
+ } \
+ } else
+
+#define BPUTNULL(ctx, loc, fmt) \
+ if (1) { \
+ if ((fmt)->end > (fmt)->endbuf) { \
+ if (growBuf(MPR_LOC_PASS(ctx, loc), fmt)) { \
+ *(fmt)->end = '\0'; \
+ } \
+ } else { \
+ *(fmt)->end = '\0'; \
+ } \
+ } else
+
+/******************************************************************************/
+
+#if BLD_FEATURE_INT64
+#define unum uint64
+#define num int64
+#else
+#define unum uint
+#define num int
+#endif
+
+/***************************** Forward Declarations ***************************/
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+static int getState(char c, int state);
+static int mprSprintfCore(MPR_LOC_DEC(ctx, loc), char **s,
+ int maxsize, const char *fmt, va_list arg);
+static void outNum(MPR_LOC_DEC(ctx, loc), Format *fmt, const char *prefix,
+ unum val);
+
+#if BLD_FEATURE_FLOATING_POINT
+static void outFloat(MPR_LOC_DEC(ctx, loc), Format *fmt, char specChar,
+ double value);
+#endif
+
+/******************************************************************************/
+
+int mprPrintf(MprCtx ctx, const char *fmt, ...)
+{
+ va_list ap;
+ char *buf;
+ int len;
+ MprApp *app;
+
+ /* No asserts here as this is used as part of assert reporting */
+
+ app = mprGetApp(ctx);
+
+ va_start(ap, fmt);
+ len = mprAllocVsprintf(MPR_LOC_ARGS(ctx), &buf, 0, fmt, ap);
+ va_end(ap);
+ if (len >= 0 && app->console) {
+ len = mprWrite(app->console, buf, len);
+ }
+ mprFree(buf);
+
+ return len;
+}
+
+/******************************************************************************/
+
+int mprErrorPrintf(MprCtx ctx, const char *fmt, ...)
+{
+ va_list ap;
+ char *buf;
+ int len;
+ MprApp *app;
+
+ /* No asserts here as this is used as part of assert reporting */
+
+ app = mprGetApp(ctx);
+
+ va_start(ap, fmt);
+ len = mprAllocVsprintf(MPR_LOC_ARGS(ctx), &buf, 0, fmt, ap);
+ va_end(ap);
+ if (len >= 0 && app->error) {
+ len = mprWrite(app->error, buf, len);
+ }
+ mprFree(buf);
+
+ return len;
+}
+
+/******************************************************************************/
+
+int mprFprintf(MprFile *file, const char *fmt, ...)
+{
+ va_list ap;
+ char *buf;
+ int len;
+
+ if (file == 0) {
+ return MPR_ERR_BAD_HANDLE;
+ }
+
+ va_start(ap, fmt);
+ len = mprAllocVsprintf(MPR_LOC_ARGS(file), &buf, 0, fmt, ap);
+ va_end(ap);
+
+ if (len >= 0) {
+ len = mprWrite(file, buf, len);
+ }
+ mprFree(buf);
+ return len;
+}
+
+/******************************************************************************/
+/*
+ * Printf with a static buffer. Used internally only. WILL NOT MALLOC.
+ */
+
+int mprStaticPrintf(MprCtx ctx, const char *fmt, ...)
+{
+ va_list ap;
+ char buf[MPR_MAX_STRING];
+ char *bufp;
+ int len;
+ MprApp *app;
+
+ app = mprGetApp(ctx);
+
+ va_start(ap, fmt);
+ bufp = buf;
+ len = mprSprintfCore(MPR_LOC_ARGS(0), &bufp, MPR_MAX_STRING, fmt, ap);
+ va_end(ap);
+ if (len >= 0) {
+ len = mprWrite(app->console, buf, len);
+ }
+ return len;
+}
+
+/******************************************************************************/
+
+int mprSprintf(char *buf, int n, const char *fmt, ...)
+{
+ va_list ap;
+ int result;
+
+ mprAssert(buf);
+ mprAssert(fmt);
+ mprAssert(n > 0);
+
+ va_start(ap, fmt);
+ result = mprSprintfCore(MPR_LOC_ARGS(0), &buf, n, fmt, ap);
+ va_end(ap);
+ return result;
+}
+
+/******************************************************************************/
+
+int mprVsprintf(char *buf, int n, const char *fmt, va_list arg)
+{
+ mprAssert(buf);
+ mprAssert(fmt);
+ mprAssert(n > 0);
+
+ return mprSprintfCore(MPR_LOC_ARGS(0), &buf, n, fmt, arg);
+}
+
+/******************************************************************************/
+
+int mprAllocSprintf(MPR_LOC_DEC(ctx, loc), char **buf, int maxSize,
+ const char *fmt, ...)
+{
+ va_list ap;
+ int result;
+
+ mprAssert(buf);
+ mprAssert(fmt);
+
+ *buf = 0;
+ va_start(ap, fmt);
+ result = mprSprintfCore(MPR_LOC_PASS(ctx, loc), buf, maxSize, fmt, ap);
+ va_end(ap);
+ return result;
+}
+
+/******************************************************************************/
+
+int mprAllocVsprintf(MPR_LOC_DEC(ctx, loc), char **buf, int maxSize,
+ const char *fmt, va_list arg)
+{
+ mprAssert(buf);
+ mprAssert(fmt);
+
+ *buf = 0;
+ return mprSprintfCore(MPR_LOC_PASS(ctx, loc), buf, maxSize, fmt, arg);
+}
+
+/******************************************************************************/
+
+static int getState(char c, int state)
+{
+ /*
+ * Declared here to remove all static / globals
+ * FUTURE OPT -- need to measure this. Could be slow on BREW.
+ */
+
+ char stateMap[] = {
+ /* STATES: Normal Percent Modifier Width Dot Prec Bits Type */
+ /* CLASS 0 1 2 3 4 5 6 7 */
+ /* Normal 0 */ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* Percent 1 */ 1, 0, 1, 1, 1, 1, 1, 1,
+ /* Modifier 2 */ 0, 2, 2, 0, 0, 0, 0, 0,
+ /* Zero 3 */ 0, 2, 2, 3, 0, 5, 0, 0,
+ /* Star 4 */ 0, 3, 3, 0, 5, 0, 0, 0,
+ /* Digit 5 */ 0, 3, 3, 3, 5, 5, 0, 0,
+ /* Dot 6 */ 0, 4, 4, 4, 0, 0, 0, 0,
+ /* Bits 7 */ 0, 6, 6, 6, 6, 6, 6, 0,
+ /* Types 8 */ 0, 7, 7, 7, 7, 7, 7, 0,
+ };
+
+ /*
+ * Format: %[modifier][width][precision][bits][type]
+ */
+ char classMap[] = {
+ /* 0 ' ' ! " # $ % & ' */
+ 2, 0, 0, 2, 0, 1, 0, 0,
+ /* 07 ( ) * + , - . / */
+ 0, 0, 4, 2, 2, 2, 6, 0,
+ /* 10 0 1 2 3 4 5 6 7 */
+ 3, 5, 5, 5, 5, 5, 5, 5,
+ /* 17 8 9 : ; < = > ? */
+ 5, 5, 0, 0, 0, 0, 0, 0,
+ /* 20 @ A B C D E F G */
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 27 H I J K L M N O */
+ 0, 0, 0, 0, 7, 0, 0, 0,
+ /* 30 P Q R S T U V W */
+ 0, 0, 0, 8, 0, 0, 0, 0,
+ /* 37 X Y Z [ \ ] ^ _ */
+ 8, 0, 0, 0, 0, 0, 0, 0,
+ /* 40 ' a b c d e f g */
+ 0, 0, 0, 8, 8, 0, 8, 0,
+ /* 47 h i j k l m n o */
+ 7, 8, 0, 0, 7, 0, 8, 8,
+ /* 50 p q r s t u v w */
+ 8, 0, 0, 8, 0, 8, 0, 0,
+ /* 57 x y z */
+ 8, 0, 0,
+ };
+
+ int chrClass;
+
+ if (c < ' ' || c > 'z') {
+ chrClass = CLASS_NORMAL;
+ } else {
+ mprAssert((c - ' ') < (int) sizeof(classMap));
+ chrClass = classMap[(c - ' ')];
+ }
+ mprAssert((chrClass * STATE_COUNT + state) < (int) sizeof(stateMap));
+ state = stateMap[chrClass * STATE_COUNT + state];
+ return state;
+}
+
+/******************************************************************************/
+
+static int mprSprintfCore(MPR_LOC_DEC(ctx, loc), char **bufPtr,
+ int maxsize, const char *spec, va_list arg)
+{
+ Format fmt;
+ char *cp;
+ char c;
+ char *sValue;
+ num iValue;
+ unum uValue;
+ int count, i, len, state;
+
+ mprAssert(bufPtr);
+ mprAssert(spec);
+
+ if (*bufPtr != 0) {
+ mprAssert(maxsize > 0);
+ fmt.buf = (uchar*) *bufPtr;
+ fmt.endbuf = &fmt.buf[maxsize];
+ fmt.growBy = 0;
+ } else {
+ if (maxsize <= 0) {
+ maxsize = MAXINT;
+ }
+
+ len = min(MPR_DEFAULT_ALLOC, maxsize);
+ fmt.buf = (uchar*) mprAllocBlock(MPR_LOC_PASS(ctx, loc), len);
+ fmt.endbuf = &fmt.buf[len];
+ fmt.growBy = MPR_DEFAULT_ALLOC * 2;
+ }
+
+ fmt.maxsize = maxsize;
+ fmt.start = fmt.buf;
+ fmt.end = fmt.buf;
+ fmt.len = 0;
+ *fmt.start = '\0';
+
+ state = STATE_NORMAL;
+
+ while ((c = *spec++) != '\0') {
+ state = getState(c, state);
+
+ switch (state) {
+ case STATE_NORMAL:
+ BPUT(ctx, loc, &fmt, c);
+ break;
+
+ case STATE_PERCENT:
+ fmt.precision = -1;
+ fmt.width = 0;
+ fmt.flags = 0;
+ break;
+
+ case STATE_MODIFIER:
+ switch (c) {
+ case '+':
+ fmt.flags |= SPRINTF_SIGN;
+ break;
+ case '-':
+ fmt.flags |= SPRINTF_LEFT;
+ break;
+ case '#':
+ fmt.flags |= SPRINTF_ALTERNATE;
+ break;
+ case '0':
+ fmt.flags |= SPRINTF_LEAD_ZERO;
+ break;
+ case ' ':
+ fmt.flags |= SPRINTF_LEAD_SPACE;
+ break;
+ case ',':
+ fmt.flags |= SPRINTF_COMMA;
+ break;
+ }
+ break;
+
+ case STATE_WIDTH:
+ if (c == '*') {
+ fmt.width = va_arg(arg, int);
+ if (fmt.width < 0) {
+ fmt.width = -fmt.width;
+ fmt.flags |= SPRINTF_LEFT;
+ }
+ } else {
+ while (isdigit((int)c)) {
+ fmt.width = fmt.width * 10 + (c - '0');
+ c = *spec++;
+ }
+ spec--;
+ }
+ break;
+
+ case STATE_DOT:
+ fmt.precision = 0;
+ fmt.flags &= ~SPRINTF_LEAD_ZERO;
+ break;
+
+ case STATE_PRECISION:
+ if (c == '*') {
+ fmt.precision = va_arg(arg, int);
+ } else {
+ while (isdigit((int) c)) {
+ fmt.precision = fmt.precision * 10 + (c - '0');
+ c = *spec++;
+ }
+ spec--;
+ }
+ break;
+
+ case STATE_BITS:
+ switch (c) {
+#if BLD_FEATURE_INT64
+ case 'L':
+ fmt.flags |= SPRINTF_LONGLONG; /* 64 bit */
+ break;
+#endif
+
+ case 'l':
+ fmt.flags |= SPRINTF_LONG;
+ break;
+
+ case 'h':
+ fmt.flags |= SPRINTF_SHORT;
+ break;
+ }
+ break;
+
+ case STATE_TYPE:
+ switch (c) {
+#if BLD_FEATURE_FLOATING_POINT
+ case 'e':
+ case 'g':
+ case 'f':
+ fmt.radix = 10;
+ outFloat(MPR_LOC_PASS(ctx, loc), &fmt, c,
+ (double) va_arg(arg, double));
+ break;
+#endif
+ case 'c':
+ BPUT(ctx, loc, &fmt, (char) va_arg(arg, int));
+ break;
+
+ case 's':
+ case 'S':
+ sValue = va_arg(arg, char*);
+ if (sValue == 0) {
+ sValue = "null";
+ len = strlen(sValue);
+ } else if (fmt.flags & SPRINTF_ALTERNATE) {
+ sValue++;
+ len = (int) *sValue;
+ } else if (fmt.precision >= 0) {
+ /*
+ * Can't use strlen(), the string may not have a null
+ */
+ cp = sValue;
+ for (len = 0; len < fmt.precision; len++) {
+ if (*cp++ == '\0') {
+ break;
+ }
+ }
+ } else {
+ len = strlen(sValue);
+ }
+ if (!(fmt.flags & SPRINTF_LEFT)) {
+ for (i = len; i < fmt.width; i++) {
+ BPUT(ctx, loc, &fmt, (char) ' ');
+ }
+ }
+ for (i = 0; i < len && *sValue; i++) {
+ BPUT(ctx, loc, &fmt, *sValue++);
+ }
+ if (fmt.flags & SPRINTF_LEFT) {
+ for (i = len; i < fmt.width; i++) {
+ BPUT(ctx, loc, &fmt, (char) ' ');
+ }
+ }
+ break;
+
+ case 'i':
+ ;
+ case 'd':
+ fmt.radix = 10;
+ if (fmt.flags & SPRINTF_SHORT) {
+ iValue = (short) va_arg(arg, int);
+ } else if (fmt.flags & SPRINTF_LONG) {
+ iValue = va_arg(arg, long);
+#if BLD_FEATURE_INT64
+ } else if (fmt.flags & SPRINTF_LONGLONG) {
+ iValue = va_arg(arg, num);
+#endif
+ } else {
+ iValue = va_arg(arg, int);
+ }
+ if (iValue >= 0) {
+ if (fmt.flags & SPRINTF_LEAD_SPACE) {
+ outNum(MPR_LOC_PASS(ctx, loc), &fmt, " ", iValue);
+ } else if (fmt.flags & SPRINTF_SIGN) {
+ outNum(MPR_LOC_PASS(ctx, loc), &fmt, "+", iValue);
+ } else {
+ outNum(MPR_LOC_PASS(ctx, loc), &fmt, 0, iValue);
+ }
+ } else {
+ outNum(MPR_LOC_PASS(ctx, loc), &fmt, "-", -iValue);
+ }
+ break;
+
+ case 'X':
+ fmt.flags |= SPRINTF_UPPER_CASE;
+ /* Fall through */
+ case 'o':
+ case 'x':
+ case 'u':
+ if (fmt.flags & SPRINTF_SHORT) {
+ uValue = (ushort) va_arg(arg, uint);
+ } else if (fmt.flags & SPRINTF_LONG) {
+ uValue = va_arg(arg, ulong);
+#if BLD_FEATURE_INT64
+ } else if (fmt.flags & SPRINTF_LONGLONG) {
+ uValue = va_arg(arg, unum);
+#endif
+ } else {
+ uValue = va_arg(arg, uint);
+ }
+ if (c == 'u') {
+ fmt.radix = 10;
+ outNum(MPR_LOC_PASS(ctx, loc), &fmt, 0, uValue);
+ } else if (c == 'o') {
+ fmt.radix = 8;
+ if (fmt.flags & SPRINTF_ALTERNATE && uValue != 0) {
+ outNum(MPR_LOC_PASS(ctx, loc), &fmt, "0", uValue);
+ } else {
+ outNum(MPR_LOC_PASS(ctx, loc), &fmt, 0, uValue);
+ }
+ } else {
+ fmt.radix = 16;
+ if (fmt.flags & SPRINTF_ALTERNATE && uValue != 0) {
+ if (c == 'X') {
+ outNum(MPR_LOC_PASS(ctx, loc), &fmt, "0X", uValue);
+ } else {
+ outNum(MPR_LOC_PASS(ctx, loc), &fmt, "0x", uValue);
+ }
+ } else {
+ outNum(MPR_LOC_PASS(ctx, loc), &fmt, 0, uValue);
+ }
+ }
+ break;
+
+ case 'n': /* Count of chars seen thus far */
+ if (fmt.flags & SPRINTF_SHORT) {
+ short *count = va_arg(arg, short*);
+ *count = fmt.end - fmt.start;
+ } else if (fmt.flags & SPRINTF_LONG) {
+ long *count = va_arg(arg, long*);
+ *count = fmt.end - fmt.start;
+ } else {
+ int *count = va_arg(arg, int *);
+ *count = fmt.end - fmt.start;
+ }
+ break;
+
+ case 'p': /* Pointer */
+#if __WORDSIZE == 64 && BLD_FEATURE_INT64
+ uValue = (unum) va_arg(arg, void*);
+#else
+ uValue = (uint) (int) va_arg(arg, void*);
+#endif
+ fmt.radix = 16;
+ outNum(MPR_LOC_PASS(ctx, loc), &fmt, "0x", uValue);
+ break;
+
+ default:
+ BPUT(ctx, loc, &fmt, c);
+ }
+ }
+ }
+ BPUTNULL(ctx, loc, &fmt);
+
+ count = fmt.end - fmt.start;
+ if (*bufPtr == 0) {
+ *bufPtr = (char*) fmt.buf;
+ }
+ return count;
+}
+
+/******************************************************************************/
+/*
+ * Output a number according to the given format. If BLD_FEATURE_INT64 is
+ * defined, then uses 64 bits universally. Slower but smaller code.
+ */
+
+static void outNum(MPR_LOC_DEC(ctx, loc), Format *fmt, const char *prefix,
+ unum value)
+{
+ char numBuf[64];
+ char *cp;
+ char *endp;
+ char c;
+ int letter, len, leadingZeros, i, fill;
+
+ endp = &numBuf[sizeof(numBuf) - 1];
+ *endp = '\0';
+ cp = endp;
+
+ /*
+ * Convert to ascii
+ */
+ if (fmt->radix == 16) {
+ do {
+ letter = (int) (value % fmt->radix);
+ if (letter > 9) {
+ if (fmt->flags & SPRINTF_UPPER_CASE) {
+ letter = 'A' + letter - 10;
+ } else {
+ letter = 'a' + letter - 10;
+ }
+ } else {
+ letter += '0';
+ }
+ *--cp = letter;
+ value /= fmt->radix;
+ } while (value > 0);
+
+ } else if (fmt->flags & SPRINTF_COMMA) {
+ i = 1;
+ do {
+ *--cp = '0' + (int) (value % fmt->radix);
+ value /= fmt->radix;
+ if ((i++ % 3) == 0 && value > 0) {
+ *--cp = ',';
+ }
+ } while (value > 0);
+ } else {
+ do {
+ *--cp = '0' + (int) (value % fmt->radix);
+ value /= fmt->radix;
+ } while (value > 0);
+ }
+
+ len = endp - cp;
+ fill = fmt->width - len;
+
+ if (prefix != 0) {
+ fill -= strlen(prefix);
+ }
+ leadingZeros = (fmt->precision > len) ? fmt->precision - len : 0;
+ fill -= leadingZeros;
+
+ if (!(fmt->flags & SPRINTF_LEFT)) {
+ c = (fmt->flags & SPRINTF_LEAD_ZERO) ? '0': ' ';
+ for (i = 0; i < fill; i++) {
+ BPUT(ctx, loc, fmt, c);
+ }
+ }
+ if (prefix != 0) {
+ while (*prefix) {
+ BPUT(ctx, loc, fmt, *prefix++);
+ }
+ }
+ for (i = 0; i < leadingZeros; i++) {
+ BPUT(ctx, loc, fmt, '0');
+ }
+ while (*cp) {
+ BPUT(ctx, loc, fmt, *cp);
+ cp++;
+ }
+ if (fmt->flags & SPRINTF_LEFT) {
+ for (i = 0; i < fill; i++) {
+ BPUT(ctx, loc, fmt, ' ');
+ }
+ }
+}
+
+/******************************************************************************/
+#if BLD_FEATURE_FLOATING_POINT
+/*
+ * Output a floating point number
+ */
+
+static void outFloat(MPR_LOC_DEC(ctx, loc), Format *fmt, char specChar,
+ double value)
+{
+ char *cp;
+#if FUTURE
+ char numBuf[64];
+ char *endp;
+ char c;
+ int letter, len, leadingZeros, i, fill, width, precision;
+
+ endp = &numBuf[sizeof(numBuf) - 1];
+ *endp = '\0';
+
+ precision = fmt->precision;
+ if (precision < 0) {
+ precision = 6;
+ } else if (precision > (sizeof(numBuf) - 1)) {
+ precision = (sizeof(numBuf) - 1);
+ }
+ width = min(fmt->width, sizeof(numBuf) - 1);
+
+ if (__isnanl(value)) {
+ "nan"
+ } else if (__isinfl(value)) {
+ "infinity"
+ } else if (value < 0) {
+ prefix = "-";
+ } else if (fmt.flags & SPRINTF_LEAD_SPACE) {
+ prefix = " ";
+ } else if (fmt.flags & SPRINTF_SIGN) {
+ prefix = "+";
+ }
+
+
+ /*
+ * Do the exponent part
+ */
+ cp = &numBuf[sizeof(numBuf) - precision];
+ for (i = 0; i < precision; i++) {
+ *cp++ = '0' + (int) (value % fmt->radix);
+ value /= fmt->radix;
+ }
+
+ /*
+ * Do the decimal part
+ */
+ if (fmt->flags & SPRINTF_COMMA) {
+ i = 1;
+ do {
+ *--cp = '0' + (int) (value % fmt->radix);
+ value /= fmt->radix;
+ if ((i++ % 3) == 0 && value > 0) {
+ *--cp = ',';
+ }
+ } while (value >= 1.0);
+
+ } else {
+ do {
+ *--cp = '0' + (int) (value % fmt->radix);
+ value /= fmt->radix;
+ } while (value > 1.0);
+ }
+
+ len = endp - cp;
+ fill = fmt->width - len;
+
+ if (prefix != 0) {
+ fill -= strlen(prefix);
+ }
+
+ leadingZeros = (fmt->precision > len) ? fmt->precision - len : 0;
+ fill -= leadingZeros;
+
+ if (!(fmt->flags & SPRINTF_LEFT)) {
+ c = (fmt->flags & SPRINTF_LEAD_ZERO) ? '0': ' ';
+ for (i = 0; i < fill; i++) {
+ BPUT(ctx, loc, fmt, c);
+ }
+ }
+ if (prefix != 0) {
+ BPUT(ctx, loc, fmt, prefix);
+ }
+ for (i = 0; i < leadingZeros; i++) {
+ BPUT(ctx, loc, fmt, '0');
+ }
+ BPUT(ctx, loc, fmt, cp);
+ if (fmt->flags & SPRINTF_LEFT) {
+ for (i = 0; i < fill; i++) {
+ BPUT(ctx, loc, fmt, ' ');
+ }
+ }
+#else
+ char numBuf[64];
+ if (specChar == 'f') {
+ sprintf(numBuf, "%*.*f", fmt->width, fmt->precision, value);
+ } else if (specChar == 'g') {
+ sprintf(numBuf, "%*.*g", fmt->width, fmt->precision, value);
+ } else if (specChar == 'e') {
+ sprintf(numBuf, "%*.*e", fmt->width, fmt->precision, value);
+ }
+ for (cp = numBuf; *cp; cp++) {
+ BPUT(ctx, loc, fmt, *cp);
+ }
+#endif
+}
+
+#endif /* BLD_FEATURE_FLOATING_POINT */
+/******************************************************************************/
+/*
+ * Grow the buffer to fit new data. Return 1 if the buffer can grow.
+ * Grow using the growBy size specified when creating the buffer.
+ */
+
+static int growBuf(MPR_LOC_DEC(ctx, loc), Format *fmt)
+{
+ uchar *newbuf;
+ int buflen;
+
+ buflen = fmt->endbuf - fmt->buf;
+ if (fmt->maxsize >= 0 && buflen >= fmt->maxsize) {
+ return 0;
+ }
+ if (fmt->growBy < 0) {
+ /*
+ * User supplied buffer
+ */
+ return 0;
+ }
+
+ newbuf = (uchar*) mprAlloc(ctx, buflen + fmt->growBy);
+ if (fmt->buf) {
+ memcpy(newbuf, fmt->buf, buflen);
+ mprFree(fmt->buf);
+ }
+
+ buflen += fmt->growBy;
+ fmt->end = newbuf + (fmt->end - fmt->buf);
+ fmt->start = newbuf + (fmt->start - fmt->buf);
+ fmt->buf = newbuf;
+ fmt->endbuf = &fmt->buf[buflen];
+
+ /*
+ * Increase growBy to reduce overhead
+ */
+ if ((buflen + (fmt->growBy * 2)) < fmt->maxsize) {
+ fmt->growBy *= 2;
+ }
+ return 1;
+}
+
+/******************************************************************************/
+
+/*
+ * 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/mpr/mprString.c b/source4/lib/appweb/ejs-2.0/mpr/mprString.c
new file mode 100644
index 0000000000..b688667bcc
--- /dev/null
+++ b/source4/lib/appweb/ejs-2.0/mpr/mprString.c
@@ -0,0 +1,727 @@
+/**
+ * @file mprString.c
+ * @brief String routines safe for embedded programming
+ * @overview This module provides safe replacements for the standard
+ * string library.
+ * @remarks Most routines in this file are not thread-safe. It is the callers
+ * responsibility to perform all thread synchronization.
+ */
+
+/*
+ * @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
+ */
+
+#include "mpr.h"
+
+/********************************** Includes **********************************/
+/*
+ * We need to use the underlying str(cpy) routines to implement our safe
+ * alternatives
+ */
+#if !DOXYGEN
+#define UNSAFE_FUNCTIONS_OK 1
+#endif
+
+/******************************************************************************/
+/**************************** Safe String Handling ****************************/
+/******************************************************************************/
+
+int mprStrcpy(char *dest, int destMax, const char *src)
+{
+ int len;
+
+ mprAssert(dest);
+ mprAssert(destMax >= 0);
+ mprAssert(src);
+
+ len = strlen(src);
+ if (destMax > 0 && len >= destMax && len > 0) {
+ return MPR_ERR_WONT_FIT;
+ }
+ if (len > 0) {
+ memcpy(dest, src, len);
+ dest[len] = '\0';
+ } else {
+ *dest = '\0';
+ len = 0;
+ }
+ return len;
+}
+
+/******************************************************************************/
+
+int mprAllocStrcpy(MPR_LOC_DEC(ctx, loc), char **dest, int destMax,
+ const char *src)
+{
+ int len;
+
+ mprAssert(dest);
+ mprAssert(destMax >= 0);
+ mprAssert(src);
+
+ len = strlen(src);
+ if (destMax > 0 && len >= destMax) {
+ mprAssert(0);
+ return MPR_ERR_WONT_FIT;
+ }
+ if (len > 0) {
+ *dest = (char*) mprAllocBlock(MPR_LOC_PASS(ctx, loc), len);
+ memcpy(*dest, src, len);
+ (*dest)[len] = '\0';
+ } else {
+ *dest = (char*) mprAlloc(ctx, 1);
+ *dest = '\0';
+ len = 0;
+ }
+ return len;
+}
+
+/******************************************************************************/
+
+int mprMemcpy(char *dest, int destMax, const char *src, int nbytes)
+{
+ mprAssert(dest);
+ mprAssert(destMax <= 0 || destMax >= nbytes);
+ mprAssert(src);
+ mprAssert(nbytes >= 0);
+
+ if (destMax > 0 && nbytes > destMax) {
+ mprAssert(0);
+ return MPR_ERR_WONT_FIT;
+ }
+ if (nbytes > 0) {
+ memcpy(dest, src, nbytes);
+ return nbytes;
+ } else {
+ return 0;
+ }
+}
+
+/******************************************************************************/
+
+int mprAllocMemcpy(MPR_LOC_DEC(ctx, loc), char **dest, int destMax,
+ const void *src, int nbytes)
+{
+ mprAssert(dest);
+ mprAssert(src);
+ mprAssert(nbytes > 0);
+ mprAssert(destMax <= 0 || destMax >= nbytes);
+
+ if (destMax > 0 && nbytes > destMax) {
+ mprAssert(0);
+ return MPR_ERR_WONT_FIT;
+ }
+ if (nbytes > 0) {
+ *dest = (char*) mprAllocBlock(MPR_LOC_PASS(ctx,loc), nbytes);
+ if (*dest == 0) {
+ return MPR_ERR_MEMORY;
+ }
+ memcpy(*dest, src, nbytes);
+ } else {
+ *dest = (char*) mprAlloc(ctx, 1);
+ }
+ return nbytes;
+}
+
+/******************************************************************************/
+
+static int mprCoreStrcat(MPR_LOC_DEC(ctx, loc), char **destp, int destMax,
+ int existingLen, const char *delim, const char *src, va_list args)
+{
+ va_list ap;
+ char *dest, *str, *dp;
+ int sepLen, addBytes, required;
+
+ mprAssert(destp);
+ mprAssert(destMax >= 0);
+ mprAssert(src);
+
+ dest = *destp;
+ sepLen = (delim) ? strlen(delim) : 0;
+
+#ifdef __va_copy
+ __va_copy(ap, args);
+#else
+ ap = args;
+#endif
+ addBytes = 0;
+ if (existingLen > 0) {
+ addBytes += sepLen;
+ }
+ str = (char*) src;
+
+ while (str) {
+ addBytes += strlen(str);
+ str = va_arg(ap, char*);
+ if (str) {
+ addBytes += sepLen;
+ }
+ }
+
+ required = existingLen + addBytes + 1;
+ if (destMax > 0 && required >= destMax) {
+ mprAssert(0);
+ return MPR_ERR_WONT_FIT;
+ }
+
+ if (ctx != 0) {
+ if (dest == 0) {
+ dest = (char*) mprAllocBlock(MPR_LOC_PASS(ctx, loc), required);
+ } else {
+ dest = (char*) mprReallocBlock(MPR_LOC_PASS(ctx, loc), dest,
+ required);
+ }
+ } else {
+ dest = (char*) *destp;
+ }
+
+ dp = &dest[existingLen];
+ if (delim && existingLen > 0) {
+ strcpy(dp, delim);
+ dp += sepLen;
+ }
+
+ if (addBytes > 0) {
+#ifdef __va_copy
+ __va_copy(ap, args);
+#else
+ ap = args;
+#endif
+ str = (char*) src;
+ while (str) {
+ strcpy(dp, str);
+ dp += strlen(str);
+ str = va_arg(ap, char*);
+ if (delim && str) {
+ strcpy(dp, delim);
+ dp += sepLen;
+ }
+ }
+ } else if (dest == 0) {
+ dest = (char*) mprAlloc(ctx, 1);
+ }
+ *dp = '\0';
+
+ *destp = dest;
+ mprAssert(dp < &dest[required]);
+ return required - 1;
+}
+
+/******************************************************************************/
+
+int mprStrcat(char *dest, int destMax, const char *delim, const char *src, ...)
+{
+ va_list ap;
+ int rc;
+
+ mprAssert(dest);
+ mprAssert(src);
+
+ va_start(ap, src);
+ rc = mprCoreStrcat(MPR_LOC_ARGS(0), &dest, destMax, strlen(dest),
+ delim, src, ap);
+ va_end(ap);
+ return rc;
+}
+
+/******************************************************************************/
+
+int mprAllocStrcat(MPR_LOC_DEC(ctx, loc), char **destp, int destMax,
+ const char *delim, const char *src, ...)
+{
+ va_list ap;
+ int rc;
+
+ mprAssert(destp);
+ mprAssert(src);
+
+ *destp = 0;
+ va_start(ap, src);
+ rc = mprCoreStrcat(MPR_LOC_PASS(ctx, loc), destp, destMax, 0, delim,
+ src, ap);
+ va_end(ap);
+ return rc;
+}
+
+/******************************************************************************/
+
+int mprReallocStrcat(MPR_LOC_DEC(ctx, loc), char **destp, int destMax,
+ int existingLen, const char *delim, const char *src,...)
+{
+ va_list ap;
+ int rc;
+
+ va_start(ap, src);
+ rc = mprCoreStrcat(MPR_LOC_PASS(ctx, loc), destp, destMax, existingLen,
+ delim, src, ap);
+ va_end(ap);
+ return rc;
+}
+
+/******************************************************************************/
+
+int mprStrlen(const char *src, int max)
+{
+ int len;
+
+ len = strlen(src);
+ if (len >= max) {
+ mprAssert(0);
+ return MPR_ERR_WONT_FIT;
+ }
+ return len;
+}
+
+/******************************************************************************/
+
+char *mprStrTrim(char *str, const char *set)
+{
+ int len, i;
+
+ if (str == 0 || set == 0) {
+ return str;
+ }
+
+ i = strspn(str, set);
+ str += i;
+
+ len = strlen(str);
+ while (strspn(&str[len - 1], set) > 0) {
+ str[len - 1] = '\0';
+ len--;
+ }
+ return str;
+}
+
+/******************************************************************************/
+/*
+ * Map a string to lower case (overwrites original string)
+ */
+
+char *mprStrLower(char *str)
+{
+ char *cp;
+
+ mprAssert(str);
+
+ if (str == 0) {
+ return 0;
+ }
+
+ for (cp = str; *cp; cp++) {
+ if (isupper(*cp)) {
+ *cp = (char) tolower(*cp);
+ }
+ }
+ return str;
+}
+
+/******************************************************************************/
+/*
+ * Map a string to upper case (overwrites buffer)
+ */
+
+char *mprStrUpper(char *str)
+{
+ char *cp;
+
+ mprAssert(str);
+ if (str == 0) {
+ return 0;
+ }
+
+ for (cp = str; *cp; cp++) {
+ if (islower(*cp)) {
+ *cp = (char) toupper(*cp);
+ }
+ }
+ return str;
+}
+
+/******************************************************************************/
+/*
+ * Case insensitive string comparison. Stop at the end of str1.
+ */
+
+int mprStrcmpAnyCase(const char *str1, const char *str2)
+{
+ int rc;
+
+ if (str1 == 0 || str2 == 0) {
+ return -1;
+ }
+ if (str1 == str2) {
+ return 0;
+ }
+
+ for (rc = 0; *str1 && rc == 0; str1++, str2++) {
+ rc = tolower(*str1) - tolower(*str2);
+ }
+ if (*str2) {
+ return -1;
+ }
+ return rc;
+}
+
+/******************************************************************************/
+/*
+ * Case insensitive string comparison. Limited by length
+ */
+
+int mprStrcmpAnyCaseCount(const char *str1, const char *str2, int len)
+{
+ int rc;
+
+ if (str1 == 0 || str2 == 0) {
+ return -1;
+ }
+ if (str1 == str2) {
+ return 0;
+ }
+
+ for (rc = 0; len-- > 0 && *str1 && rc == 0; str1++, str2++) {
+ rc = tolower(*str1) - tolower(*str2);
+ }
+ return rc;
+}
+
+/******************************************************************************/
+/*
+ * Return the last portion of a pathname
+ */
+
+const char *mprGetBaseName(const char *name)
+{
+ char *cp;
+
+ cp = strrchr(name, '/');
+
+ if (cp == 0) {
+ cp = strrchr(name, '\\');
+ if (cp == 0) {
+ return name;
+ }
+ }
+ if (cp == name) {
+ if (cp[1] == '\0') {
+ return name;
+ }
+ } else {
+ if (cp[1] == '\0') {
+ return "";
+ }
+ }
+ return &cp[1];
+}
+
+/******************************************************************************/
+/*
+ * Return the directory portion of a pathname into the users buffer.
+ */
+
+char *mprGetDirName(char *buf, int bufsize, const char *path)
+{
+ char *cp;
+ int dlen;
+
+ mprAssert(path);
+ mprAssert(buf);
+ mprAssert(bufsize > 0);
+
+ cp = strrchr(path, '/');
+ if (cp == 0) {
+#if WIN
+ cp = strrchr(path, '\\');
+ if (cp == 0)
+#endif
+ {
+ buf[0] = '\0';
+ return buf;
+ }
+ }
+
+ if (cp == path && cp[1] == '\0') {
+ strcpy(buf, ".");
+ return buf;
+ }
+
+ dlen = cp - path;
+ if (dlen < bufsize) {
+ if (dlen == 0) {
+ dlen++;
+ }
+ mprMemcpy(buf, bufsize, path, dlen);
+ buf[dlen] = '\0';
+ return buf;
+ }
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * Thread-safe wrapping of strtok. Note "str" is modifed as per strtok()
+ */
+
+char *mprStrTok(char *str, const char *delim, char **last)
+{
+ char *start, *end;
+ int i;
+
+ start = str ? str : *last;
+
+ if (start == 0) {
+ return 0;
+ }
+
+ i = strspn(start, delim);
+ start += i;
+ if (*start == '\0') {
+ *last = 0;
+ return 0;
+ }
+ end = strpbrk(start, delim);
+ if (end) {
+ *end++ = '\0';
+ i = strspn(end, delim);
+ end += i;
+ }
+ *last = end;
+ return start;
+}
+
+/******************************************************************************/
+/*
+ * Split the buffer into word tokens
+ */
+
+char *mprGetWordTok(char *buf, int bufsize, const char *str, const char *delim,
+ const char **tok)
+{
+ const char *start, *end;
+ int i, len;
+
+ start = str ? str : *tok;
+
+ if (start == 0) {
+ return 0;
+ }
+
+ i = strspn(start, delim);
+ start += i;
+ if (*start =='\0') {
+ *tok = 0;
+ return 0;
+ }
+ end = strpbrk(start, delim);
+ if (end) {
+ len = min(end - start, bufsize - 1);
+ mprMemcpy(buf, bufsize, start, len);
+ buf[len] = '\0';
+ } else {
+ if (mprStrcpy(buf, bufsize, start) < 0) {
+ buf[bufsize - 1] = '\0';
+ return 0;
+ }
+ buf[bufsize - 1] = '\0';
+ }
+ *tok = end;
+ return buf;
+}
+
+/******************************************************************************/
+/*
+ * Format a number as a string.
+ */
+
+char *mprItoa(char *buf, int size, int value)
+{
+ char numBuf[16];
+ char *cp, *dp, *endp;
+ int negative;
+
+ cp = &numBuf[sizeof(numBuf)];
+ *--cp = '\0';
+
+ if (value < 0) {
+ negative = 1;
+ value = -value;
+ size--;
+ } else {
+ negative = 0;
+ }
+
+ do {
+ *--cp = '0' + (value % 10);
+ value /= 10;
+ } while (value > 0);
+
+ if (negative) {
+ *--cp = '-';
+ }
+
+ dp = buf;
+ endp = &buf[size];
+ while (dp < endp && *cp) {
+ *dp++ = *cp++;
+ }
+ *dp++ = '\0';
+ return buf;
+}
+
+/******************************************************************************/
+/*
+ * Parse an ascii number. Supports radix 10 or 16.
+ */
+
+int mprAtoi(const char *str, int radix)
+{
+ int c, val, negative;
+
+ mprAssert(radix == 10 || radix == 16);
+
+ if (str == 0) {
+ return 0;
+ }
+
+ val = 0;
+ if (radix == 10 && *str == '-') {
+ negative = 1;
+ str++;
+ } else {
+ negative = 0;
+ }
+
+ if (radix == 10) {
+ while (*str && isdigit(*str)) {
+ val = (val * radix) + *str - '0';
+ str++;
+ }
+ } else if (radix == 16) {
+ if (*str == '0' && tolower(str[1]) == 'x') {
+ str += 2;
+ }
+ while (*str) {
+ c = tolower(*str);
+ if (isdigit(c)) {
+ val = (val * radix) + c - '0';
+ } else if (c >= 'a' && c <= 'f') {
+ val = (val * radix) + c - 'a' + 10;
+ } else {
+ break;
+ }
+ str++;
+ }
+ }
+
+ return (negative) ? -val: val;
+}
+
+/******************************************************************************/
+/*
+ * Make an argv array. Caller must free by calling mprFree(argv) to free
+ * everything.
+ */
+
+int mprMakeArgv(MprCtx ctx, const char *program, const char *cmd,
+ char ***argvp, int *argcp)
+{
+ char *cp, **argv, *buf, *args;
+ int size, argc;
+
+ /*
+ * Allocate one buffer for argv and the actual args themselves
+ */
+ size = strlen(cmd) + 1;
+
+ buf = (char*) mprAlloc(ctx, (MPR_MAX_ARGC * sizeof(char*)) + size);
+ if (buf == 0) {
+ return MPR_ERR_MEMORY;
+ }
+
+ args = &buf[MPR_MAX_ARGC * sizeof(char*)];
+ strcpy(args, cmd);
+ argv = (char**) buf;
+
+ argc = 0;
+ if (program) {
+ argv[argc++] = (char*) mprStrdup(ctx, program);
+ }
+
+ for (cp = args; cp && *cp != '\0'; argc++) {
+ if (argc >= MPR_MAX_ARGC) {
+ mprAssert(argc < MPR_MAX_ARGC);
+ mprFree(buf);
+ *argvp = 0;
+ if (argcp) {
+ *argcp = 0;
+ }
+ return MPR_ERR_TOO_MANY;
+ }
+ while (isspace(*cp)) {
+ cp++;
+ }
+ if (*cp == '\0') {
+ break;
+ }
+ if (*cp == '"') {
+ cp++;
+ argv[argc] = cp;
+ while ((*cp != '\0') && (*cp != '"')) {
+ cp++;
+ }
+ } else {
+ argv[argc] = cp;
+ while (*cp != '\0' && !isspace(*cp)) {
+ cp++;
+ }
+ }
+ if (*cp != '\0') {
+ *cp++ = '\0';
+ }
+ }
+ argv[argc] = 0;
+
+ if (argcp) {
+ *argcp = argc;
+ }
+ *argvp = argv;
+
+ return argc;
+}
+
+/******************************************************************************/
+
+/*
+ * 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/mpr/mprSymbol.c b/source4/lib/appweb/ejs-2.0/mpr/mprSymbol.c
new file mode 100644
index 0000000000..11ac278db4
--- /dev/null
+++ b/source4/lib/appweb/ejs-2.0/mpr/mprSymbol.c
@@ -0,0 +1,279 @@
+/*
+ * @file mprSym.cpp
+ * @brief Fast hashing symbol table lookup module
+ * @overview This symbol table uses a fast key lookup mechanism. Keys are
+ * strings and the value entries are arbitrary pointers. The keys are
+ * hashed into a series of buckets which then have a chain of hash
+ * entries using the standard doubly linked list classes (List/Link).
+ * The chain in in collating sequence so search time through the chain
+ * is on average (N/hashSize)/2.
+ * @remarks This module is not thread-safe. It is the callers responsibility
+ * to perform all thread synchronization.
+ */
+/********************************* 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 "mpr.h"
+
+/**************************** Forward Declarations ****************************/
+
+static int hashIndex(const char *key, int size);
+static MprSymbol *lookupInner(int *bucketIndex, MprSymbol **prevSp,
+ MprSymbolTable *table, const char *key);
+
+/*********************************** Code *************************************/
+/*
+ * Create a new symbol table of a given size. Caller should provide a size
+ * that is a prime number for the greatest efficiency. Caller should use
+ * mprFree to free the symbol table.
+ */
+
+MprSymbolTable *mprCreateSymbolTable(MprCtx ctx, int hashSize)
+{
+ MprSymbolTable *table;
+
+ table = mprAllocTypeZeroed(ctx, MprSymbolTable);
+ if (table == 0) {
+ return 0;
+ }
+
+ if (hashSize < MPR_DEFAULT_HASH_SIZE) {
+ hashSize = MPR_DEFAULT_HASH_SIZE;
+ }
+ table->hashSize = hashSize;
+
+ table->count = 0;
+ table->hashSize = hashSize;
+ table->buckets = mprAllocZeroedBlock(MPR_LOC_ARGS(table),
+ sizeof(MprSymbol*) * hashSize);
+
+ if (table->buckets == 0) {
+ mprFree(table);
+ return 0;
+ }
+
+ return table;
+}
+
+/******************************************************************************/
+/*
+ * Insert an entry into the symbol table. If the entry already exists, update
+ * its value. Order of insertion is not preserved.
+ */
+
+MprSymbol *mprInsertSymbol(MprSymbolTable *table, const char *key, void *ptr)
+{
+ MprSymbol *sp, *prevSp;
+ int index;
+
+ sp = lookupInner(&index, &prevSp, table, key);
+
+ if (sp != 0) {
+ /*
+ * Already exists. Just update the data.
+ */
+ sp->data = ptr;
+ return sp;
+ }
+
+ /*
+ * New entry
+ */
+ sp = mprAllocTypeZeroed(table, MprSymbol);
+ if (sp == 0) {
+ return 0;
+ }
+
+ sp->data = ptr;
+ sp->key = mprStrdup(sp, key);
+ sp->bucket = index;
+
+ sp->next = table->buckets[index];
+ table->buckets[index] = sp;
+
+ table->count++;
+ return sp;
+}
+
+/******************************************************************************/
+/*
+ * Remove an entry from the table
+ */
+
+int mprRemoveSymbol(MprSymbolTable *table, const char *key)
+{
+ MprSymbol *sp, *prevSp;
+ int index;
+
+ if ((sp = lookupInner(&index, &prevSp, table, key)) == 0) {
+ return MPR_ERR_NOT_FOUND;
+ }
+
+ if (prevSp) {
+ prevSp->next = sp->next;
+ } else {
+ table->buckets[index] = sp->next;
+ }
+ table->count--;
+
+ mprFree(sp);
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * Lookup a key and return the hash entry
+ */
+
+void *mprLookupSymbol(MprSymbolTable *table, const char *key)
+{
+ MprSymbol *sp;
+
+ mprAssert(key);
+
+ sp = lookupInner(0, 0, table, key);
+ if (sp == 0) {
+ return 0;
+ }
+ return sp->data;
+}
+
+/******************************************************************************/
+
+static MprSymbol *lookupInner(int *bucketIndex, MprSymbol **prevSp,
+ MprSymbolTable *table, const char *key)
+{
+ MprSymbol *sp, *prev;
+ int index, rc;
+
+ mprAssert(key);
+
+ index = hashIndex(key, table->hashSize);
+ if (bucketIndex) {
+ *bucketIndex = index;
+ }
+
+ sp = table->buckets[index];
+ prev = 0;
+
+ while (sp) {
+ rc = strcmp(sp->key, key);
+ if (rc == 0) {
+ if (prevSp) {
+ *prevSp = prev;
+ }
+ return sp;
+ }
+ prev = sp;
+ mprAssert(sp != sp->next);
+ sp = sp->next;
+ }
+ return 0;
+}
+
+/******************************************************************************/
+
+int mprGetSymbolCount(MprSymbolTable *table)
+{
+ return table->count;
+}
+
+/******************************************************************************/
+/*
+ * Return the first entry in the table.
+ */
+
+MprSymbol *mprGetFirstSymTab(MprSymbolTable *table)
+{
+ MprSymbol *sp;
+ int i;
+
+ mprAssert(table);
+
+ for (i = 0; i < table->hashSize; i++) {
+ if ((sp = (MprSymbol*) table->buckets[i]) != 0) {
+ return sp;
+ }
+ }
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * Return the next entry in the table
+ */
+
+MprSymbol *mprGetNextSymTab(MprSymbolTable *table, MprSymbol *last)
+{
+ MprSymbol *sp;
+ int i;
+
+ mprAssert(table);
+
+ if (last->next) {
+ return last->next;
+ }
+
+ for (i = last->bucket + 1; i < table->hashSize; i++) {
+ if ((sp = (MprSymbol*) table->buckets[i]) != 0) {
+ return sp;
+ }
+ }
+ return 0;
+}
+
+/******************************************************************************/
+/*
+ * Hash the key to produce a hash index.
+ */
+
+static int hashIndex(const char *key, int size)
+{
+ uint sum;
+
+ sum = 0;
+ while (*key) {
+ sum += (sum * 33) + *key++;
+ }
+
+ return sum % size;
+}
+
+/******************************************************************************/
+/*
+ * 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/mpr/mprUnix.h b/source4/lib/appweb/ejs-2.0/mpr/mprUnix.h
new file mode 100644
index 0000000000..fbbe29ae9c
--- /dev/null
+++ b/source4/lib/appweb/ejs-2.0/mpr/mprUnix.h
@@ -0,0 +1,105 @@
+/*
+ * @file mprUnix.h
+ * @brief Make windows a bit more unix like
+ * @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
+ */
+
+/******************************* Documentation ********************************/
+
+/*
+ * This header is part of the Mbedthis Portable Runtime and aims to include
+ * all necessary O/S headers and to unify the constants and declarations
+ * required by Mbedthis products. It can be included by C or C++ programs.
+ */
+
+/******************************************************************************/
+
+#ifndef _h_MPR_UNIX
+#define _h_MPR_UNIX 1
+
+/******************************************************************************/
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Define BLD_NO_POSIX_REMAP if these defines mess with your app
+ */
+#if WIN && !BLD_NO_POSIX_REMAP
+/*
+ * MOB -- clashes with ATL
+ */
+#define access _access
+#define close _close
+#define fileno _fileno
+#define fstat _fstat
+#define getpid _getpid
+#define open _open
+#define putenv _putenv
+#define read _read
+#define stat _stat
+#define umask _umask
+#define unlink _unlink
+#define write _write
+#define strdup _strdup
+#define lseek _lseek
+#define getcwd _getcwd
+#define chdir _chdir
+
+#define mkdir(a,b) _mkdir(a)
+#define rmdir(a) _rmdir(a)
+
+#define R_OK 4
+#define W_OK 2
+#define MPR_TEXT "t"
+
+extern void srand48(long);
+extern long lrand48(void);
+extern long ulimit(int, ...);
+extern long nap(long);
+extern int getuid(void);
+extern int geteuid(void);
+#endif
+
+
+/******************************************************************************/
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _h_MPR_UNIX */
+
+/*
+ * 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
+ */