r18925: Add current snapshot of the ejs-2.0 code. Tridge, will you be incorporating...
authorDerrell Lipman <derrell@samba.org>
Tue, 26 Sep 2006 16:58:27 +0000 (16:58 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 19:20:21 +0000 (14:20 -0500)
(This used to be commit 917af234a8d517f82bd42256a940608a16b988f4)

80 files changed:
source4/lib/appweb/ejs-2.0/.bashrc [new file with mode: 0644]
source4/lib/appweb/ejs-2.0/.exrc [new file with mode: 0644]
source4/lib/appweb/ejs-2.0/.ignore [new file with mode: 0644]
source4/lib/appweb/ejs-2.0/.loginrc [new file with mode: 0644]
source4/lib/appweb/ejs-2.0/ejs/.ignore [new file with mode: 0644]
source4/lib/appweb/ejs-2.0/ejs/Makefile [new file with mode: 0644]
source4/lib/appweb/ejs-2.0/ejs/classes/.ignore [new file with mode: 0644]
source4/lib/appweb/ejs-2.0/ejs/classes/Makefile [new file with mode: 0644]
source4/lib/appweb/ejs-2.0/ejs/classes/ejsArray.c [new file with mode: 0644]
source4/lib/appweb/ejs-2.0/ejs/classes/ejsDate.c [new file with mode: 0755]
source4/lib/appweb/ejs-2.0/ejs/classes/ejsError.c [new file with mode: 0755]
source4/lib/appweb/ejs-2.0/ejs/classes/ejsObject.c [new file with mode: 0644]
source4/lib/appweb/ejs-2.0/ejs/classes/ejsStndClasses.c [new file with mode: 0644]
source4/lib/appweb/ejs-2.0/ejs/classes/ejsString.c [new file with mode: 0644]
source4/lib/appweb/ejs-2.0/ejs/classes/ejsXml.c [new file with mode: 0644]
source4/lib/appweb/ejs-2.0/ejs/ejs.c [new file with mode: 0644]
source4/lib/appweb/ejs-2.0/ejs/ejs.h [new file with mode: 0644]
source4/lib/appweb/ejs-2.0/ejs/ejsClass.c [new file with mode: 0644]
source4/lib/appweb/ejs-2.0/ejs/ejsCmd.c [new file with mode: 0644]
source4/lib/appweb/ejs-2.0/ejs/ejsGarbage.c [new file with mode: 0755]
source4/lib/appweb/ejs-2.0/ejs/ejsLex.c [new file with mode: 0644]
source4/lib/appweb/ejs-2.0/ejs/ejsParser.c [new file with mode: 0644]
source4/lib/appweb/ejs-2.0/ejs/ejsVar.c [new file with mode: 0644]
source4/lib/appweb/ejs-2.0/ejs/ejsVar.h [new file with mode: 0644]
source4/lib/appweb/ejs-2.0/ejs/lib/event.js [new file with mode: 0644]
source4/lib/appweb/ejs-2.0/ejs/lib/global.js [new file with mode: 0644]
source4/lib/appweb/ejs-2.0/ejs/lib/startup.js [new file with mode: 0644]
source4/lib/appweb/ejs-2.0/ejs/lib/timer.js [new file with mode: 0644]
source4/lib/appweb/ejs-2.0/ejs/system/.ignore [new file with mode: 0755]
source4/lib/appweb/ejs-2.0/ejs/system/Makefile [new file with mode: 0755]
source4/lib/appweb/ejs-2.0/ejs/system/README.TXT [new file with mode: 0644]
source4/lib/appweb/ejs-2.0/ejs/system/UNIX/.ignore [new file with mode: 0644]
source4/lib/appweb/ejs-2.0/ejs/system/UNIX/Makefile [new file with mode: 0755]
source4/lib/appweb/ejs-2.0/ejs/system/UNIX/ejsFile.c [new file with mode: 0644]
source4/lib/appweb/ejs-2.0/ejs/system/UNIX/ejsFileSystem.c [new file with mode: 0755]
source4/lib/appweb/ejs-2.0/ejs/system/UNIX/ejsHTTP.c [new file with mode: 0755]
source4/lib/appweb/ejs-2.0/ejs/system/WIN/.ignore [new file with mode: 0644]
source4/lib/appweb/ejs-2.0/ejs/system/WIN/Makefile [new file with mode: 0755]
source4/lib/appweb/ejs-2.0/ejs/system/WIN/ejsFile.c [new file with mode: 0644]
source4/lib/appweb/ejs-2.0/ejs/system/WIN/ejsFileSystem.c [new file with mode: 0755]
source4/lib/appweb/ejs-2.0/ejs/system/WIN/ejsHTTP.c [new file with mode: 0755]
source4/lib/appweb/ejs-2.0/ejs/system/ejsGC.c [new file with mode: 0644]
source4/lib/appweb/ejs-2.0/ejs/system/ejsGlobal.c [new file with mode: 0755]
source4/lib/appweb/ejs-2.0/ejs/system/ejsSystem.c [new file with mode: 0644]
source4/lib/appweb/ejs-2.0/ejs/system/ejsSystemApp.c [new file with mode: 0644]
source4/lib/appweb/ejs-2.0/ejs/system/ejsSystemDebug.c [new file with mode: 0644]
source4/lib/appweb/ejs-2.0/ejs/system/ejsSystemLog.c [new file with mode: 0644]
source4/lib/appweb/ejs-2.0/ejs/system/ejsSystemMemory.c [new file with mode: 0755]
source4/lib/appweb/ejs-2.0/exml/Makefile [new file with mode: 0644]
source4/lib/appweb/ejs-2.0/exml/exml.h [new file with mode: 0644]
source4/lib/appweb/ejs-2.0/exml/exmlParser.c [new file with mode: 0644]
source4/lib/appweb/ejs-2.0/exml/files [new file with mode: 0644]
source4/lib/appweb/ejs-2.0/mpr/Makefile [new file with mode: 0644]
source4/lib/appweb/ejs-2.0/mpr/UNIX/Makefile [new file with mode: 0644]
source4/lib/appweb/ejs-2.0/mpr/UNIX/mprFile.c [new file with mode: 0644]
source4/lib/appweb/ejs-2.0/mpr/UNIX/mprPlatform.c [new file with mode: 0644]
source4/lib/appweb/ejs-2.0/mpr/UNIX/mprTime.c [new file with mode: 0644]
source4/lib/appweb/ejs-2.0/mpr/VXWORKS/Makefile [new file with mode: 0644]
source4/lib/appweb/ejs-2.0/mpr/VXWORKS/mprFile.c [new file with mode: 0644]
source4/lib/appweb/ejs-2.0/mpr/VXWORKS/mprPlatform.c [new file with mode: 0644]
source4/lib/appweb/ejs-2.0/mpr/VXWORKS/mprTime.c [new file with mode: 0755]
source4/lib/appweb/ejs-2.0/mpr/WIN/Makefile [new file with mode: 0644]
source4/lib/appweb/ejs-2.0/mpr/WIN/mprFile.c [new file with mode: 0644]
source4/lib/appweb/ejs-2.0/mpr/WIN/mprPlatform.c [new file with mode: 0644]
source4/lib/appweb/ejs-2.0/mpr/WIN/mprTime.c [new file with mode: 0644]
source4/lib/appweb/ejs-2.0/mpr/files [new file with mode: 0644]
source4/lib/appweb/ejs-2.0/mpr/mpr.c [new file with mode: 0644]
source4/lib/appweb/ejs-2.0/mpr/mpr.h [new file with mode: 0644]
source4/lib/appweb/ejs-2.0/mpr/mprAlloc.c [new file with mode: 0644]
source4/lib/appweb/ejs-2.0/mpr/mprArray.c [new file with mode: 0644]
source4/lib/appweb/ejs-2.0/mpr/mprBuf.c [new file with mode: 0644]
source4/lib/appweb/ejs-2.0/mpr/mprGenFile.c [new file with mode: 0644]
source4/lib/appweb/ejs-2.0/mpr/mprGenTime.c [new file with mode: 0644]
source4/lib/appweb/ejs-2.0/mpr/mprLock.c [new file with mode: 0644]
source4/lib/appweb/ejs-2.0/mpr/mprLog.c [new file with mode: 0644]
source4/lib/appweb/ejs-2.0/mpr/mprOs.h [new file with mode: 0644]
source4/lib/appweb/ejs-2.0/mpr/mprPrintf.c [new file with mode: 0644]
source4/lib/appweb/ejs-2.0/mpr/mprString.c [new file with mode: 0644]
source4/lib/appweb/ejs-2.0/mpr/mprSymbol.c [new file with mode: 0644]
source4/lib/appweb/ejs-2.0/mpr/mprUnix.h [new file with mode: 0644]

diff --git a/source4/lib/appweb/ejs-2.0/.bashrc b/source4/lib/appweb/ejs-2.0/.bashrc
new file mode 100644 (file)
index 0000000..c05ee0e
--- /dev/null
@@ -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\a
+       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\a
+       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 (file)
index 0000000..dd37846
--- /dev/null
@@ -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 (file)
index 0000000..866f06c
--- /dev/null
@@ -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 (file)
index 0000000..90b76a2
--- /dev/null
@@ -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\a
+       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\a
+       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 (file)
index 0000000..47f4ac6
--- /dev/null
@@ -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 (file)
index 0000000..ea6be8c
--- /dev/null
@@ -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 (file)
index 0000000..fb5a290
--- /dev/null
@@ -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 (file)
index 0000000..ce12bb3
--- /dev/null
@@ -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 (file)
index 0000000..feb64b1
--- /dev/null
@@ -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 (executable)
index 0000000..096316a
--- /dev/null
@@ -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 (executable)
index 0000000..99445af
--- /dev/null
@@ -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 (file)
index 0000000..4f2e23b
--- /dev/null
@@ -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 (file)
index 0000000..fd6cda7
--- /dev/null
@@ -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 (file)
index 0000000..2339650
--- /dev/null
@@ -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 (file)
index 0000000..a2ef8d1
--- /dev/null
@@ -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 (file)
index 0000000..0fcc6f0
--- /dev/null
@@ -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 (file)
index 0000000..a926446
--- /dev/null
@@ -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 (file)
index 0000000..58609ad
--- /dev/null
@@ -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 (file)
index 0000000..b5279c9
--- /dev/null
@@ -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 (executable)
index 0000000..264da05
--- /dev/null
@@ -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 (file)
index 0000000..fbfee6e
--- /dev/null
@@ -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 (file)
index 0000000..9fce6d2
--- /dev/null
@@ -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 (file)
index 0000000..5067215
--- /dev/null
@@ -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 (file)
index 0000000..071665e
--- /dev/null
@@ -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 (file)
index 0000000..283a3ec
--- /dev/null
@@ -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 (file)
index 0000000..f2daaa5
--- /dev/null
@@ -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 (file)
index 0000000..e627a96
--- /dev/null
@@ -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 (file)
index 0000000..f4cb8b1
--- /dev/null
@@ -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 (executable)
index 0000000..fb5a290
--- /dev/null
@@ -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 (executable)
index 0000000..2d83662
--- /dev/null
@@ -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 (file)
index 0000000..a24e0e2
--- /dev/null
@@ -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 (file)
index 0000000..fb5a290
--- /dev/null
@@ -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 (executable)
index 0000000..4247470
--- /dev/null
@@ -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 (file)
index 0000000..7723031
--- /dev/null
@@ -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 (executable)
index 0000000..7b39c16
--- /dev/null
@@ -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 (executable)
index 0000000..25821f6
--- /dev/null
@@ -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 (file)
index 0000000..fb5a290
--- /dev/null
@@ -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 (executable)
index 0000000..4247470
--- /dev/null
@@ -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 (file)
index 0000000..24c5218
--- /dev/null
@@ -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 (executable)
index 0000000..66c3b84
--- /dev/null
@@ -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 (executable)
index 0000000..25821f6
--- /dev/null
@@ -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 (file)
index 0000000..411975f
--- /dev/null
@@ -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 (executable)
index 0000000..6ab8f86
--- /dev/null
@@ -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 (file)
index 0000000..e035e1c
--- /dev/null
@@ -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 (file)
index 0000000..e2f1ceb
--- /dev/null
@@ -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 (file)
index 0000000..5a011e2
--- /dev/null
@@ -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 (file)
index 0000000..66467f8
--- /dev/null
@@ -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 (executable)
index 0000000..d10787b
--- /dev/null
@@ -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 (file)
index 0000000..663e65e
--- /dev/null
@@ -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 (file)
index 0000000..44c50a5
--- /dev/null
@@ -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 (file)
index 0000000..1487141
--- /dev/null
@@ -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 (file)
index 0000000..0f10ea4
--- /dev/null
@@ -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 (file)
index 0000000..6dd0e45
--- /dev/null
@@ -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 (file)
index 0000000..5259b1e
--- /dev/null
@@ -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 (file)
index 0000000..f647f1e
--- /dev/null
@@ -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 (file)
index 0000000..2c7fbf8
--- /dev/null
@@ -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 (file)
index 0000000..0153c06
--- /dev/null
@@ -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 (file)
index 0000000..f3a2394
--- /dev/null
@@ -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 (file)
index 0000000..ae0b523
--- /dev/null
@@ -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 (file)
index 0000000..29258df
--- /dev/null
@@ -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 (executable)
index 0000000..c9b7560
--- /dev/null
@@ -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 (file)
index 0000000..84e30ff
--- /dev/null
@@ -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 (file)
index 0000000..9ac1669
--- /dev/null
@@ -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 (file)
index 0000000..6571869
--- /dev/null
@@ -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 (file)
index 0000000..74e59c9
--- /dev/null
@@ -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 (file)
index 0000000..290c9ce
--- /dev/null
@@ -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 (file)
index 0000000..163b51e
--- /dev/null
@@ -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 (file)
index 0000000..67505a6
--- /dev/null
@@ -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 (file)
index 0000000..6fcaa63
--- /dev/null
@@ -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 (file)
index 0000000..95b0a14
--- /dev/null
@@ -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 (file)
index 0000000..ba9888a
--- /dev/null
@@ -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 (file)
index 0000000..517e438
--- /dev/null
@@ -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 (file)
index 0000000..6b0ed97
--- /dev/null
@@ -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 (file)
index 0000000..df9ce27
--- /dev/null
@@ -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 (file)
index 0000000..1eb175e
--- /dev/null
@@ -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 (file)
index 0000000..bed4ca5
--- /dev/null
@@ -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 (file)
index 0000000..2d0951a
--- /dev/null
@@ -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 (file)
index 0000000..b688667
--- /dev/null
@@ -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 (file)
index 0000000..11ac278
--- /dev/null
@@ -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 (file)
index 0000000..fbbe29a
--- /dev/null
@@ -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
+ */