ADDED .fossil-settings/clean-glob
Index: .fossil-settings/clean-glob
==================================================================
--- .fossil-settings/clean-glob
+++ .fossil-settings/clean-glob
@@ -0,0 +1,17 @@
+*.a
+*.lib
+*.manifest
+*.o
+*.obj
+*.pdb
+*.res
+Makefile
+bld/*
+wbld/*
+win/*.c
+win/*.h
+win/*.exe
+win/headers
+win/linkopts
+autoconfig.h
+config.log
ADDED .fossil-settings/ignore-glob
Index: .fossil-settings/ignore-glob
==================================================================
--- .fossil-settings/ignore-glob
+++ .fossil-settings/ignore-glob
@@ -0,0 +1,2 @@
+fossil
+fossil.exe
ADDED .fossil-settings/keep-glob
Index: .fossil-settings/keep-glob
==================================================================
--- .fossil-settings/keep-glob
+++ .fossil-settings/keep-glob
@@ -0,0 +1,2 @@
+fossil
+fossil.exe
ADDED .project
Index: .project
==================================================================
--- .project
+++ .project
@@ -0,0 +1,11 @@
+
+
+ fossil
+
+
+
+
+
+
+
+
ADDED .settings/org.eclipse.core.resources.prefs
Index: .settings/org.eclipse.core.resources.prefs
==================================================================
--- .settings/org.eclipse.core.resources.prefs
+++ .settings/org.eclipse.core.resources.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+encoding/=UTF-8
ADDED .settings/org.eclipse.core.runtime.prefs
Index: .settings/org.eclipse.core.runtime.prefs
==================================================================
--- .settings/org.eclipse.core.runtime.prefs
+++ .settings/org.eclipse.core.runtime.prefs
@@ -0,0 +1,2 @@
+eclipse.preferences.version=1
+line.separator=\n
Index: BUILD.txt
==================================================================
--- BUILD.txt
+++ BUILD.txt
@@ -1,42 +1,61 @@
-All of the source code for fossil is contained in the src/ subdirectory.
-But there is a lot of generated code, so you will probably want to
-use the Makefile. To do a complete build, just type:
-
- make
-
-That should work out-of-the-box on Macs and Linux systems. If you are
-building on a Windows box, install MinGW as well as MinGW's make (or
-MSYS). You can then type:
-
- make -f Makefile.w32
+To do a complete build, just type:
+
+ ./configure; make
+
+The ./configure script builds Makefile from Makefile.in based on
+your system and any options you select (run "./configure --help"
+for a listing of the available options.)
+
+If you wish to use the original Makefile with no configuration, you can
+instead use:
+
+ make -f Makefile.classic
+
+On a windows box, use one of the Makefiles in the win/ subdirectory,
+according to your compiler and environment. If you have MinGW or
+MinGW-w64 installed on your system (Msys or Cygwin, or as
+cross-compile environment on Linux or Darwin), then consider:
+
+ make -f win/Makefile.mingw
+
+If you have VC++ installed on your system, then consider:
+
+ cd win; nmake /f Makefile.msc
If you have trouble, or you want to do something fancy, just look at
-top level makefile. There are 6 configuration options that are all well
-commented. Instead of editing the Makefile, consider copying the Makefile
-to an alternative name such as "GNUMakefile", "BSDMakefile", or "makefile"
-and editing the copy.
+Makefile.classic. There are 6 configuration options that are all well
+commented. Instead of editing the Makefile.classic, consider copying
+Makefile.classic to an alternative name such as "GNUMakefile",
+"BSDMakefile", or "makefile" and editing the copy.
+
-Out of source builds?
---------------------------------------------------------------------------
+BUILDING OUTSIDE THE SOURCE TREE
An out of source build is pretty easy:
- 1. Make a new directory to do the builds in.
- 2. Copy "Makefile" from the source into the build directory and
- modify the SRCDIR macro along the lines of:
-
- SRCDIR=../src
-
- 3. type: "make"
-
-This will now keep all generates files seperate from the maintained
+ 1. Make and change to a new directory to do the builds in.
+ 2. Run the "configure" script from this directory.
+ 3. Type: "make"
+
+For example:
+
+ mkdir build
+ cd build
+ ../configure
+ make
+
+This will now keep all generates files separate from the maintained
source code.
--------------------------------------------------------------------------
Here are some notes on what is happening behind the scenes:
+
+* The configure script (if used) examines the options given
+ and runs various tests with the C compiler to create Makefile
+ from the Makefile.in template as well as autoconfig.h
* The Makefile just sets up a few macros and then invokes the
real makefile in src/main.mk. The src/main.mk makefile is
automatically generated by a TCL script found at src/makemake.tcl.
Do not edit src/main.mk directly. Update src/makemake.tcl and
@@ -52,5 +71,8 @@
A header comment in src/translate.c explains in detail what it does.
* The src/mkindex.c program generates some C code that implements
static lookup tables. See the header comment in the source code
for details on what it does.
+
+Additional information on the build process is available from
+http://www.fossil-scm.org/fossil/doc/trunk/www/makefile.wiki
DELETED Makefile
Index: Makefile
==================================================================
--- Makefile
+++ Makefile
@@ -1,56 +0,0 @@
-#!/usr/bin/make
-#
-#### The toplevel directory of the source tree. Fossil can be built
-# in a directory that is separate from the source tree. Just change
-# the following to point from the build directory to the src/ folder.
-#
-SRCDIR = ./src
-
-#### The directory into which object code files should be written.
-#
-#
-OBJDIR = ./obj
-
-#### C Compiler and options for use in building executables that
-# will run on the platform that is doing the build. This is used
-# to compile code-generator programs as part of the build process.
-# See TCC below for the C compiler for building the finished binary.
-#
-BCC = gcc -g -O2
-
-#### The suffix to add to executable files. ".exe" for windows.
-# Nothing for unix.
-#
-E =
-
-#### C Compile and options for use in building executables that
-# will run on the target platform. This is usually the same
-# as BCC, unless you are cross-compiling. This C compiler builds
-# the finished binary for fossil. The BCC compiler above is used
-# for building intermediate code-generator tools.
-#
-#TCC = gcc -O6
-#TCC = gcc -g -O0 -Wall -fprofile-arcs -ftest-coverage
-TCC = gcc -g -Os -Wall
-
-#### Extra arguments for linking the finished binary. Fossil needs
-# to link against the Z-Lib compression library. There are no
-# other dependencies. We sometimes add the -static option here
-# so that we can build a static executable that will run in a
-# chroot jail.
-#
-LIB = -lz $(LDFLAGS)
-# If you're on OpenSolaris:
-# LIB += lsocket
-# Solaris 10 needs:
-# LIB += -lsocket -lnsl
-# My assumption is that the Sol10 flags will work for Sol8/9 and possibly 11.
-#
-
-#### Tcl shell for use in running the fossil testsuite.
-#
-TCLSH = tclsh
-
-# You should not need to change anything below this line
-###############################################################################
-include $(SRCDIR)/main.mk
ADDED Makefile.classic
Index: Makefile.classic
==================================================================
--- Makefile.classic
+++ Makefile.classic
@@ -0,0 +1,75 @@
+#!/usr/bin/make
+#
+# This is the top-level makefile for Fossil when the build is occurring
+# on a unix platform. This works out-of-the-box on most unix platforms.
+# But you are free to vary some of the definitions if desired.
+#
+#### The toplevel directory of the source tree. Fossil can be built
+# in a directory that is separate from the source tree. Just change
+# the following to point from the build directory to the src/ folder.
+#
+SRCDIR = ./src
+
+#### The directory into which object code files should be written.
+#
+#
+OBJDIR = ./bld
+
+#### C Compiler and options for use in building executables that
+# will run on the platform that is doing the build. This is used
+# to compile code-generator programs as part of the build process.
+# See TCC below for the C compiler for building the finished binary.
+#
+BCC = gcc
+
+#### The suffix to add to final executable file. When cross-compiling
+# to windows, make this ".exe". Otherwise leave it blank.
+#
+E =
+
+#### C Compile and options for use in building executables that
+# will run on the target platform. This is usually the same
+# as BCC, unless you are cross-compiling. This C compiler builds
+# the finished binary for fossil. The BCC compiler above is used
+# for building intermediate code-generator tools.
+#
+#TCC = gcc -O6
+#TCC = gcc -g -O0 -Wall -fprofile-arcs -ftest-coverage
+TCC = gcc -g -Os -Wall
+
+# To add support for HTTPS
+TCC += -DFOSSIL_ENABLE_SSL
+
+#### Extra arguments for linking the finished binary. Fossil needs
+# to link against the Z-Lib compression library. There are no
+# other dependencies. We sometimes add the -static option here
+# so that we can build a static executable that will run in a
+# chroot jail.
+#
+LIB = -lz $(LDFLAGS)
+
+# If using HTTPS:
+LIB += -lcrypto -lssl
+
+#### Tcl shell for use in running the fossil testsuite. If you do not
+# care about testing the end result, this can be blank.
+#
+TCLSH = tclsh
+
+# You should not need to change anything below this line
+###############################################################################
+#
+# Automatic platform-specific options.
+HOST_OS_CMD = uname -s
+HOST_OS = $(HOST_OS_CMD:sh)
+
+LIB.SunOS= -lsocket -lnsl
+LIB += $(LIB.$(HOST_OS))
+
+TCC.DragonFly += -DUSE_PREAD
+TCC.FreeBSD += -DUSE_PREAD
+TCC.NetBSD += -DUSE_PREAD
+TCC.OpenBSD += -DUSE_PREAD
+TCC += $(TCC.$(HOST_OS))
+
+include $(SRCDIR)/main.mk
ADDED Makefile.in
Index: Makefile.in
==================================================================
--- Makefile.in
+++ Makefile.in
@@ -0,0 +1,51 @@
+#!/usr/bin/make
+#
+# This is the top-level makefile for Fossil when the build is occurring
+# on a unix platform. This works out-of-the-box on most unix platforms.
+# But you are free to vary some of the definitions if desired.
+#
+#### The toplevel directory of the source tree. Fossil can be built
+# in a directory that is separate from the source tree. Just change
+# the following to point from the build directory to the src/ folder.
+#
+SRCDIR = @srcdir@/src
+
+#### The directory into which object code files should be written.
+# Having a "./" prefix in the value of this variable breaks our use of the
+# "makeheaders" tool when running make on the MinGW platform, apparently
+# due to some command line argument manipulation performed automatically
+# by the shell.
+#
+#
+OBJDIR = bld
+
+#### C Compiler and options for use in building executables that
+# will run on the platform that is doing the build. This is used
+# to compile code-generator programs as part of the build process.
+# See TCC below for the C compiler for building the finished binary.
+#
+BCC = @CC_FOR_BUILD@
+
+#### The suffix to add to final executable file. When cross-compiling
+# to windows, make this ".exe". Otherwise leave it blank.
+#
+E = @EXEEXT@
+
+TCC = @CC@
+
+#### Tcl shell for use in running the fossil testsuite. If you do not
+# care about testing the end result, this can be blank.
+#
+TCLSH = tclsh
+
+LIB = @LDFLAGS@ @EXTRA_LDFLAGS@ @LIBS@
+TCC += @EXTRA_CFLAGS@ @CPPFLAGS@ @CFLAGS@ -DHAVE_AUTOCONFIG_H
+INSTALLDIR = $(DESTDIR)@prefix@/bin
+USE_SYSTEM_SQLITE = @USE_SYSTEM_SQLITE@
+FOSSIL_ENABLE_TCL = @FOSSIL_ENABLE_TCL@
+FOSSIL_ENABLE_TCL_STUBS = @FOSSIL_ENABLE_TCL_STUBS@
+
+include $(SRCDIR)/main.mk
+
+distclean: clean
+ rm -f autoconfig.h config.log Makefile
DELETED Makefile.w32
Index: Makefile.w32
==================================================================
--- Makefile.w32
+++ Makefile.w32
@@ -1,67 +0,0 @@
-#!/usr/bin/make
-#
-#### The toplevel directory of the source tree. Fossil can be built
-# in a directory that is separate from the source tree. Just change
-# the following to point from the build directory to the src/ folder.
-#
-SRCDIR = ./src
-OBJDIR = ./wobj
-
-#### C Compiler and options for use in building executables that
-# will run on the platform that is doing the build. This is used
-# to compile code-generator programs as part of the build process.
-# See TCC below for the C compiler for building the finished binary.
-#
-BCC = gcc -g -O2
-
-#### The suffix to add to executable files. ".exe" for windows.
-# Nothing for unix.
-#
-E = .exe
-
-#### Enable HTTPS support via OpenSSL (links to libssl and libcrypto)
-#
-# FOSSIL_ENABLE_SSL=1
-
-#### C Compile and options for use in building executables that
-# will run on the target platform. This is usually the same
-# as BCC, unless you are cross-compiling. This C compiler builds
-# the finished binary for fossil. The BCC compiler above is used
-# for building intermediate code-generator tools.
-#
-#TCC = gcc -O6
-#TCC = gcc -g -O0 -Wall -fprofile-arcs -ftest-coverage
-#TCC = gcc -g -Os -Wall
-#TCC = gcc -g -Os -Wall -DFOSSIL_I18N=0 -L/usr/local/lib -I/usr/local/include
-TCC = gcc -Os -Wall -DFOSSIL_I18N=0 -L/mingw/lib -I/mingw/include
-
-# With HTTPS support
-ifdef FOSSIL_ENABLE_SSL
-TCC += -DFOSSIL_ENABLE_SSL=1
-endif
-
-#### Extra arguments for linking the finished binary. Fossil needs
-# to link against the Z-Lib compression library. There are no
-# other dependencies. We sometimes add the -static option here
-# so that we can build a static executable that will run in a
-# chroot jail.
-#
-#LIB = -lz
-#LIB = -lz -lws2_32
-LIB = -lmingwex -lz -lws2_32
-# OpenSSL:
-ifdef FOSSIL_ENABLE_SSL
-LIB += -lcrypto -lssl
-endif
-
-#### Tcl shell for use in running the fossil testsuite.
-#
-TCLSH = tclsh
-
-#### Include a configuration file that can override any one of these settings.
-#
--include config.w32
-
-# You should not need to change anything below this line
-###############################################################################
-include $(SRCDIR)/main.mk
ADDED VERSION
Index: VERSION
==================================================================
--- VERSION
+++ VERSION
@@ -0,0 +1,1 @@
+1.26
ADDED ajax/README
Index: ajax/README
==================================================================
--- ajax/README
+++ ajax/README
@@ -0,0 +1,38 @@
+This is the README for how to set up the Fossil/JSON test web page
+under Apache on Unix systems. This is only intended only for
+Fossil/JSON developers/tinkerers:
+
+First, copy cgi-bin/fossil-json.cgi.example to
+cgi-bin/fossil-json.cgi. Edit it and correct the paths to the fossil
+binary and the repo you want to serve. Make it executable.
+
+MAKE SURE that the fossil repo you use is world-writable OR that your
+Web/CGI server is set up to run as the user ID of the owner of the
+fossil file. ALSO: the DIRECTORY CONTAINING the repo file must be
+writable by the CGI process.
+
+Next, set up an apache vhost entry. Mine looks like:
+
+
+ ServerAlias fjson
+ ScriptAlias /cgi-bin/ /home/stephan/cvs/fossil/fossil-json/ajax/cgi-bin/
+ DocumentRoot /home/stephan/cvs/fossil/fossil-json/ajax
+
+
+Now add your preferred vhost name (fjson in the above example) to /etc/hosts:
+
+ 127.0.0.1 ...other aliases... fjson
+
+Restart your Apache.
+
+Now visit: http://fjson/
+
+that will show the test/demo page. If it doesn't, edit index.html and
+make sure that:
+
+ WhAjaj.Connector.options.ajax.url = ...;
+
+points to your CGI script. In theory you can also do this over fossil
+standalone server mode, but i haven't yet tested that particular test
+page in that mode.
+
ADDED ajax/cgi-bin/fossil-json.cgi.example
Index: ajax/cgi-bin/fossil-json.cgi.example
==================================================================
--- ajax/cgi-bin/fossil-json.cgi.example
+++ ajax/cgi-bin/fossil-json.cgi.example
@@ -0,0 +1,2 @@
+#!/path/to/fossil/binary
+repository: /path/to/repo.fsl
ADDED ajax/i-test/rhino-shell.js
Index: ajax/i-test/rhino-shell.js
==================================================================
--- ajax/i-test/rhino-shell.js
+++ ajax/i-test/rhino-shell.js
@@ -0,0 +1,208 @@
+var FShell = {
+ serverUrl:
+ 'http://localhost:8080'
+ //'http://fjson/cgi-bin/fossil-json.cgi'
+ //'http://192.168.1.62:8080'
+ //'http://fossil.wanderinghorse.net/repos/fossil-json-java/index.cgi'
+ ,
+ verbose:false,
+ prompt:"fossil shell > ",
+ wiki:{},
+ consol:java.lang.System.console(),
+ v:function(msg){
+ if(this.verbose){
+ print("VERBOSE: "+msg);
+ }
+ }
+};
+(function bootstrap() {
+ var srcdir = '../js/';
+ var includes = [srcdir+'json2.js',
+ srcdir+'whajaj.js',
+ srcdir+'fossil-ajaj.js'
+ ];
+ for( var i in includes ) {
+ load(includes[i]);
+ }
+ WhAjaj.Connector.prototype.sendImpl = WhAjaj.Connector.sendImpls.rhino;
+ FShell.fossil = new FossilAjaj({
+ asynchronous:false, /* rhino-based impl doesn't support async. */
+ timeout:10000,
+ url:FShell.serverUrl
+ });
+ print("Server: "+FShell.serverUrl);
+ var cb = FShell.fossil.ajaj.callbacks;
+ cb.beforeSend = function(req,opt){
+ if(!FShell.verbose) return;
+ print("SENDING REQUEST: AJAJ options="+JSON.stringify(opt));
+ if(req) print("Request envelope="+WhAjaj.stringify(req));
+ };
+ cb.afterSend = function(req,opt){
+ //if(!FShell.verbose) return;
+ //print("REQUEST RETURNED: opt="+JSON.stringify(opt));
+ //if(req) print("Request="+WhAjaj.stringify(req));
+ };
+ cb.onError = function(req,opt){
+ //if(!FShell.verbose) return;
+ print("ERROR: "+WhAjaj.stringify(opt));
+ };
+ cb.onResponse = function(resp,req){
+ if(!FShell.verbose) return;
+ if(resp && resp.resultCode){
+ print("Response contains error info: "+resp.resultCode+": "+resp.resultText);
+ }
+ print("GOT RESPONSE: "+(('string'===typeof resp) ? resp : WhAjaj.stringify(resp)));
+ };
+ FShell.fossil.HAI({
+ onResponse:function(resp,opt){
+ assertResponseOK(resp);
+ }
+ });
+})();
+
+/**
+ Throws an exception of cond is a falsy value.
+*/
+function assert(cond, descr){
+ descr = descr || "Undescribed condition.";
+ if(!cond){
+ throw new Error("Assertion failed: "+descr);
+ }else{
+ //print("Assertion OK: "+descr);
+ }
+}
+
+/**
+ Convenience form of FShell.fossil.sendCommand(command,payload,ajajOpt).
+*/
+function send(command,payload, ajajOpt){
+ FShell.fossil.sendCommand(command,payload,ajajOpt);
+}
+
+/**
+ Asserts that resp is-a Object, resp.fossil is-a string, and
+ !resp.resultCode.
+*/
+function assertResponseOK(resp){
+ assert('object' === typeof resp,'Response is-a object.');
+ assert( 'string' === typeof resp.fossil, 'Response contains fossil property.');
+ assert( !resp.resultCode, 'resp.resultCode='+resp.resultCode);
+}
+/**
+ Asserts that resp is-a Object, resp.fossil is-a string, and
+ resp.resultCode is a truthy value. If expectCode is set then
+ it also asserts that (resp.resultCode=='FOSSIL-'+expectCode).
+*/
+function assertResponseError(resp,expectCode){
+ assert('object' === typeof resp,'Response is-a object.');
+ assert( 'string' === typeof resp.fossil, 'Response contains fossil property.');
+ assert( resp.resultCode, 'resp.resultCode='+resp.resultCode);
+ if(expectCode){
+ assert( 'FOSSIL-'+expectCode == resp.resultCode, 'Expecting result code '+expectCode );
+ }
+}
+
+FShell.readline = (typeof readline === 'function') ? (readline) : (function() {
+ importPackage(java.io);
+ importPackage(java.lang);
+ var stdin = new BufferedReader(new InputStreamReader(System['in']));
+ var self = this;
+ return function(prompt) {
+ if(prompt) print(prompt);
+ var x = stdin.readLine();
+ return null===x ? x : String(x) /*convert to JS string!*/;
+ };
+}());
+
+FShell.dispatchLine = function(line){
+ var av = line.split(' '); // FIXME: to shell-like tokenization. Too tired!
+ var cmd = av[0];
+ var key, h;
+ if('/' == cmd[0]) key = '/';
+ else key = this.commandAliases[cmd];
+ if(!key) key = cmd;
+ h = this.commandHandlers[key];
+ if(!h){
+ print("Command not known: "+cmd +" ("+key+")");
+ }else if(!WhAjaj.isFunction(h)){
+ print("Not a function: "+key);
+ }
+ else{
+ print("Sending ["+key+"] command... ");
+ try{h(av);}
+ catch(e){ print("EXCEPTION: "+e); }
+ }
+};
+
+FShell.onResponseDefault = function(callback){
+ return function(resp,req){
+ assertResponseOK(resp);
+ print("Payload: "+(resp.payload ? WhAjaj.stringify(resp.payload) : "none"));
+ if(WhAjaj.isFunction(callback)){
+ callback(resp,req);
+ }
+ };
+};
+FShell.commandHandlers = {
+ "?":function(args){
+ var k;
+ print("Available commands...\n");
+ var o = FShell.commandHandlers;
+ for(k in o){
+ if(! o.hasOwnProperty(k)) continue;
+ print("\t"+k);
+ }
+ },
+ "/":function(args){
+ FShell.fossil.sendCommand('/json'+args[0],undefined,{
+ beforeSend:function(req,opt){
+ print("Sending to: "+opt.url);
+ },
+ onResponse:FShell.onResponseDefault()
+ });
+ },
+ "eval":function(args){
+ eval(args.join(' '));
+ },
+ "login":function(args){
+ FShell.fossil.login(args[1], args[2], {
+ onResponse:FShell.onResponseDefault()
+ });
+ },
+ "whoami":function(args){
+ FShell.fossil.whoami({
+ onResponse:FShell.onResponseDefault()
+ });
+ },
+ "HAI":function(args){
+ FShell.fossil.HAI({
+ onResponse:FShell.onResponseDefault()
+ });
+ }
+
+};
+FShell.commandAliases = {
+ "li":"login",
+ "lo":"logout",
+ "who":"whoami",
+ "hi":"HAI",
+ "tci":"/timeline/ci?limit=3"
+};
+FShell.mainLoop = function(){
+ var line;
+ var check = /\S/;
+ //var isJavaNull = /java\.lang\.null/;
+ //print(typeof java.lang['null']);
+ while( null != (line=this.readline(this.prompt)) ){
+ if(null===line) break /*EOF*/;
+ else if( "" === line ) continue;
+ //print("Got line: "+line);
+ else if(!check.test(line)) continue;
+ print('typeof line = '+typeof line);
+ this.dispatchLine(line);
+ print("");
+ }
+ print("Bye!");
+};
+
+FShell.mainLoop();
ADDED ajax/i-test/rhino-test.js
Index: ajax/i-test/rhino-test.js
==================================================================
--- ajax/i-test/rhino-test.js
+++ ajax/i-test/rhino-test.js
@@ -0,0 +1,279 @@
+var TestApp = {
+ serverUrl:
+ 'http://localhost:8080'
+ //'http://fjson/cgi-bin/fossil-json.cgi'
+ //'http://192.168.1.62:8080'
+ //'http://fossil.wanderinghorse.net/repos/fossil-json-java/index.cgi'
+ ,
+ verbose:true,
+ fossilBinary:'fossil',
+ wiki:{}
+};
+(function bootstrap() {
+ var srcdir = '../js/';
+ var includes = [srcdir+'json2.js',
+ srcdir+'whajaj.js',
+ srcdir+'fossil-ajaj.js'
+ ];
+ for( var i in includes ) {
+ load(includes[i]);
+ }
+ WhAjaj.Connector.prototype.sendImpl = WhAjaj.Connector.sendImpls.rhino;
+ TestApp.fossil = new FossilAjaj({
+ asynchronous:false, /* rhino-based impl doesn't support async or timeout. */
+ timeout:0,
+ url:TestApp.serverUrl,
+ fossilBinary:TestApp.fossilBinary
+ });
+ var cb = TestApp.fossil.ajaj.callbacks;
+ cb.beforeSend = function(req,opt){
+ if(!TestApp.verbose) return;
+ print("SENDING REQUEST: AJAJ options="+JSON.stringify(opt));
+ if(req) print("Request envelope="+WhAjaj.stringify(req));
+ };
+ cb.afterSend = function(req,opt){
+ //if(!TestApp.verbose) return;
+ //print("REQUEST RETURNED: opt="+JSON.stringify(opt));
+ //if(req) print("Request="+WhAjaj.stringify(req));
+ };
+ cb.onError = function(req,opt){
+ if(!TestApp.verbose) return;
+ print("ERROR: "+WhAjaj.stringify(opt));
+ };
+ cb.onResponse = function(resp,req){
+ if(!TestApp.verbose) return;
+ print("GOT RESPONSE: "+(('string'===typeof resp) ? resp : WhAjaj.stringify(resp)));
+ };
+
+})();
+
+/**
+ Throws an exception of cond is a falsy value.
+*/
+function assert(cond, descr){
+ descr = descr || "Undescribed condition.";
+ if(!cond){
+ print("Assertion FAILED: "+descr);
+ throw new Error("Assertion failed: "+descr);
+ // aarrgghh. Exceptions are of course swallowed by
+ // the AJAX layer, to keep from killing a browser's
+ // script environment.
+ }else{
+ if(TestApp.verbose) print("Assertion OK: "+descr);
+ }
+}
+
+/**
+ Calls func() in a try/catch block and throws an exception if
+ func() does NOT throw.
+*/
+function assertThrows(func, descr){
+ descr = descr || "Undescribed condition failed.";
+ var ex;
+ try{
+ func();
+ }catch(e){
+ ex = e;
+ }
+ if(!ex){
+ throw new Error("Function did not throw (as expected): "+descr);
+ }else{
+ if(TestApp.verbose) print("Function threw (as expected): "+descr+": "+ex);
+ }
+}
+
+/**
+ Convenience form of TestApp.fossil.sendCommand(command,payload,ajajOpt).
+*/
+function send(command,payload, ajajOpt){
+ TestApp.fossil.sendCommand(command,payload,ajajOpt);
+}
+
+/**
+ Asserts that resp is-a Object, resp.fossil is-a string, and
+ !resp.resultCode.
+*/
+function assertResponseOK(resp){
+ assert('object' === typeof resp,'Response is-a object.');
+ assert( 'string' === typeof resp.fossil, 'Response contains fossil property.');
+ assert( undefined === resp.resultCode, 'resp.resultCode is not set');
+}
+/**
+ Asserts that resp is-a Object, resp.fossil is-a string, and
+ resp.resultCode is a truthy value. If expectCode is set then
+ it also asserts that (resp.resultCode=='FOSSIL-'+expectCode).
+*/
+function assertResponseError(resp,expectCode){
+ assert('object' === typeof resp,'Response is-a object.');
+ assert( 'string' === typeof resp.fossil, 'Response contains fossil property.');
+ assert( !!resp.resultCode, 'resp.resultCode='+resp.resultCode);
+ if(expectCode){
+ assert( 'FOSSIL-'+expectCode == resp.resultCode, 'Expecting result code '+expectCode );
+ }
+}
+
+function testHAI(){
+ var rs;
+ TestApp.fossil.HAI({
+ onResponse:function(resp,req){
+ rs = resp;
+ }
+ });
+ assertResponseOK(rs);
+ TestApp.serverVersion = rs.fossil;
+ assert( 'string' === typeof TestApp.serverVersion, 'server version = '+TestApp.serverVersion);
+}
+testHAI.description = 'Get server version info.';
+
+function testIAmNobody(){
+ TestApp.fossil.whoami('/json/whoami');
+ assert('nobody' === TestApp.fossil.auth.name, 'User == nobody.' );
+ assert(!TestApp.fossil.auth.authToken, 'authToken is not set.' );
+
+}
+testIAmNobody.description = 'Ensure that current user is "nobody".';
+
+
+function testAnonymousLogin(){
+ TestApp.fossil.login();
+ assert('string' === typeof TestApp.fossil.auth.authToken, 'authToken = '+TestApp.fossil.auth.authToken);
+ assert( 'string' === typeof TestApp.fossil.auth.name, 'User name = '+TestApp.fossil.auth.name);
+ TestApp.fossil.userName = null;
+ TestApp.fossil.whoami('/json/whoami');
+ assert( 'string' === typeof TestApp.fossil.auth.name, 'User name = '+TestApp.fossil.auth.name);
+}
+testAnonymousLogin.description = 'Perform anonymous login.';
+
+function testAnonWiki(){
+ var rs;
+ TestApp.fossil.sendCommand('/json/wiki/list',undefined,{
+ beforeSend:function(req,opt){
+ assert( req && (req.authToken==TestApp.fossil.auth.authToken), 'Request envelope contains expected authToken.' );
+ },
+ onResponse:function(resp,req){
+ rs = resp;
+ }
+ });
+ assertResponseOK(rs);
+ assert( (typeof [] === typeof rs.payload) && rs.payload.length,
+ "Wiki list seems to be okay.");
+ TestApp.wiki.list = rs.payload;
+
+ TestApp.fossil.sendCommand('/json/wiki/get',{
+ name:TestApp.wiki.list[0]
+ },{
+ onResponse:function(resp,req){
+ rs = resp;
+ }
+ });
+ assertResponseOK(rs);
+ assert(rs.payload.name == TestApp.wiki.list[0], "Fetched page name matches expectations.");
+ print("Got first wiki page: "+WhAjaj.stringify(rs.payload));
+
+}
+testAnonWiki.description = 'Fetch wiki list as anonymous user.';
+
+function testFetchCheckinArtifact(){
+ var art = '18dd383e5e7684ece';
+ var rs;
+ TestApp.fossil.sendCommand('/json/artifact',{
+ 'name': art
+ },
+ {
+ onResponse:function(resp,req){
+ rs = resp;
+ }
+ });
+ assertResponseOK(rs);
+ assert(3 == rs.payload.parents.length, 'Got 3 parent artifacts.');
+}
+testFetchCheckinArtifact.description = '/json/artifact/CHECKIN';
+
+function testAnonLogout(){
+ var rs;
+ TestApp.fossil.logout({
+ onResponse:function(resp,req){
+ rs = resp;
+ }
+ });
+ assertResponseOK(rs);
+ print("Ensure that second logout attempt fails...");
+ TestApp.fossil.logout({
+ onResponse:function(resp,req){
+ rs = resp;
+ }
+ });
+ assertResponseError(rs);
+}
+testAnonLogout.description = 'Log out anonymous user.';
+
+function testExternalProcess(){
+
+ var req = { command:"HAI", requestId:'testExternalProcess()' };
+ var args = [TestApp.fossilBinary, 'json', '--json-input', '-'];
+ var p = java.lang.Runtime.getRuntime().exec(args);
+ var outs = p.getOutputStream();
+ var osr = new java.io.OutputStreamWriter(outs);
+ var osb = new java.io.BufferedWriter(osr);
+ var json = JSON.stringify(req);
+ osb.write(json,0, json.length);
+ osb.close();
+ req = json = outs = osr = osb = undefined;
+ var ins = p.getInputStream();
+ var isr = new java.io.InputStreamReader(ins);
+ var br = new java.io.BufferedReader(isr);
+ var line;
+
+ while( null !== (line=br.readLine())){
+ print(line);
+ }
+ br.close();
+ isr.close();
+ ins.close();
+ p.waitFor();
+}
+testExternalProcess.description = 'Run fossil as external process.';
+
+function testExternalProcessHandler(){
+ var aj = TestApp.fossil.ajaj;
+ var oldImpl = aj.sendImpl;
+ aj.sendImpl = FossilAjaj.rhinoLocalBinarySendImpl;
+ var rs;
+ TestApp.fossil.sendCommand('/json/HAI',undefined,{
+ onResponse:function(resp,opt){
+ rs = resp;
+ }
+ });
+ aj.sendImpl = oldImpl;
+ assertResponseOK(rs);
+ print("Using local fossil binary via AJAX interface, we fetched: "+
+ WhAjaj.stringify(rs));
+}
+testExternalProcessHandler.description = 'Try local fossil binary via AJAX interface.';
+
+(function runAllTests(){
+ var testList = [
+ testHAI,
+ testIAmNobody,
+ testAnonymousLogin,
+ testAnonWiki,
+ testFetchCheckinArtifact,
+ testAnonLogout,
+ testExternalProcess,
+ testExternalProcessHandler
+ ];
+ var i, f;
+ for( i = 0; i < testList.length; ++i ){
+ f = testList[i];
+ try{
+ print("Running test #"+(i+1)+": "+(f.description || "no description."));
+ f();
+ }catch(e){
+ print("Test #"+(i+1)+" failed: "+e);
+ throw e;
+ }
+ }
+
+})();
+
+print("Done! If you don't see an exception message in the last few lines, you win!");
ADDED ajax/index.html
Index: ajax/index.html
==================================================================
--- ajax/index.html
+++ ajax/index.html
@@ -0,0 +1,333 @@
+
+
+
+
+ Fossil/JSON raw request sending
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+See also: prototype wiki editor .
+
+Request...
+
+Path:
+
+If the POST textarea is not empty then it will be posted with the request.
+
+Quick-posts:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Login:
+
+
+
+
+name:
+pw:
+
+
+
+
+
+
+
+
+
+
+
+ POST data
+ Request AJAJ options
+
+
+
+
+
+
+
+
+
+
+ Response
+
+
+
+
+
+
+
+
+
+
+
+
ADDED ajax/js/fossil-ajaj.js
Index: ajax/js/fossil-ajaj.js
==================================================================
--- ajax/js/fossil-ajaj.js
+++ ajax/js/fossil-ajaj.js
@@ -0,0 +1,274 @@
+/**
+ This file contains a WhAjaj extension for use with Fossil/JSON.
+
+ Author: Stephan Beal (sgbeal@googlemail.com)
+
+ License: Public Domain
+*/
+
+/**
+ Constructor for a new Fossil AJAJ client. ajajOpt may be an optional
+ object suitable for passing to the WhAjaj.Connector() constructor.
+
+ On returning, this.ajaj is-a WhAjaj.Connector instance which can
+ be used to send requests to the back-end (though the convenience
+ functions of this class are the preferred way to do it). Clients
+ are encouraged to use FossilAjaj.sendCommand() (and friends) instead
+ of the underlying WhAjaj.Connector API, since this class' API
+ contains Fossil-specific request-calling handling (e.g. of authentication
+ info) whereas WhAjaj is more generic.
+*/
+function FossilAjaj(ajajOpt)
+{
+ this.ajaj = new WhAjaj.Connector(ajajOpt);
+ return this;
+}
+
+FossilAjaj.prototype.generateRequestId = function() {
+ return this.ajaj.generateRequestId();
+};
+
+/**
+ Proxy for this.ajaj.sendRequest().
+*/
+FossilAjaj.prototype.sendRequest = function(req,opt) {
+ return this.ajaj.sendRequest(req,opt);
+};
+
+/**
+ Sends a command to the fossil back-end. Command should be the
+ path part of the URL, e.g. /json/stat, payload is a request-specific
+ value type (may often be null/undefined). ajajOpt is an optional object
+ holding WhAjaj.sendRequest()-compatible options.
+
+ This function constructs a Fossil/JSON request envelope based
+ on the given arguments and adds this.auth.authToken and a requestId
+ to it.
+*/
+FossilAjaj.prototype.sendCommand = function(command, payload, ajajOpt) {
+ var req;
+ ajajOpt = ajajOpt || {};
+ if(payload || (this.auth && this.auth.authToken) || ajajOpt.jsonp) {
+ req = {
+ payload:payload,
+ requestId:('function' === typeof this.generateRequestId) ? this.generateRequestId() : undefined,
+ authToken:(this.auth ? this.auth.authToken : undefined),
+ jsonp:('string' === typeof ajajOpt.jsonp) ? ajajOpt.jsonp : undefined
+ };
+ }
+ ajajOpt.method = req ? 'POST' : 'GET';
+ // just for debuggering: ajajOpt.method = 'POST'; if(!req) req={};
+ if(command) ajajOpt.url = this.ajaj.derivedOption('url',ajajOpt) + command;
+ this.ajaj.sendRequest(req,ajajOpt);
+};
+
+/**
+ Sends a login request to the back-end.
+
+ ajajOpt is an optional configuration object suitable for passing
+ to sendCommand().
+
+ After the response returns, this.auth will be
+ set to the response payload.
+
+ If name === 'anonymous' (the default if none is passed in) then this
+ function ignores the pw argument and must make two requests - the first
+ one gets the captcha code and the second one submits it.
+ ajajOpt.onResponse() (if set) is only called for the actual login
+ response (the 2nd one), as opposed to being called for both requests.
+ However, this.ajaj.callbacks.onResponse() _is_ called for both (because
+ it happens at a lower level).
+
+ If this object has an onLogin() function it is called (with
+ no arguments) before the onResponse() handler of the login is called
+ (that is the 2nd request for anonymous logins) and any exceptions
+ it throws are ignored.
+
+*/
+FossilAjaj.prototype.login = function(name,pw,ajajOpt) {
+ name = name || 'anonymous';
+ var self = this;
+ var loginReq = {
+ name:name,
+ password:pw
+ };
+ ajajOpt = this.ajaj.normalizeAjaxParameters( ajajOpt || {} );
+ var oldOnResponse = ajajOpt.onResponse;
+ ajajOpt.onResponse = function(resp,req) {
+ var thisOpt = this;
+ //alert('login response:\n'+WhAjaj.stringify(resp));
+ if( resp && resp.payload ) {
+ //self.userName = resp.payload.name;
+ //self.capabilities = resp.payload.capabilities;
+ self.auth = resp.payload;
+ }
+ if( WhAjaj.isFunction( self.onLogin ) ){
+ try{ self.onLogin(); }
+ catch(e){}
+ }
+ if( WhAjaj.isFunction(oldOnResponse) ) {
+ oldOnResponse.apply(thisOpt,[resp,req]);
+ }
+ };
+ function doLogin(){
+ //alert("Sending login request..."+WhAjaj.stringify(loginReq));
+ self.sendCommand('/json/login', loginReq, ajajOpt);
+ }
+ if( 'anonymous' === name ){
+ this.sendCommand('/json/anonymousPassword',undefined,{
+ onResponse:function(resp,req){
+/*
+ if( WhAjaj.isFunction(oldOnResponse) ){
+ oldOnResponse.apply(this, [resp,req]);
+ };
+*/
+ if(resp && !resp.resultCode){
+ //alert("Got PW. Trying to log in..."+WhAjaj.stringify(resp));
+ loginReq.anonymousSeed = resp.payload.seed;
+ loginReq.password = resp.payload.password;
+ doLogin();
+ }
+ }
+ });
+ }
+ else doLogin();
+};
+
+/**
+ Logs out of fossil, invaliding this login token.
+
+ ajajOpt is an optional configuration object suitable for passing
+ to sendCommand().
+
+ If this object has an onLogout() function it is called (with
+ no arguments) before the onResponse() handler is called.
+ IFF the response succeeds then this.auth is unset.
+*/
+FossilAjaj.prototype.logout = function(ajajOpt) {
+ var self = this;
+ ajajOpt = this.ajaj.normalizeAjaxParameters( ajajOpt || {} );
+ var oldOnResponse = ajajOpt.onResponse;
+ ajajOpt.onResponse = function(resp,req) {
+ var thisOpt = this;
+ self.auth = undefined;
+ if( WhAjaj.isFunction( self.onLogout ) ){
+ try{ self.onLogout(); }
+ catch(e){}
+ }
+ if( WhAjaj.isFunction(oldOnResponse) ) {
+ oldOnResponse.apply(thisOpt,[resp,req]);
+ }
+ };
+ this.sendCommand('/json/logout', undefined, ajajOpt );
+};
+
+/**
+ Sends a HAI request to the server. /json/HAI is an alias /json/version.
+
+ ajajOpt is an optional configuration object suitable for passing
+ to sendCommand().
+*/
+FossilAjaj.prototype.HAI = function(ajajOpt) {
+ this.sendCommand('/json/HAI', undefined, ajajOpt);
+};
+
+
+/**
+ Sends a /json/whoami request. Updates this.auth to contain
+ the login info, removing them if the response does not contain
+ that data.
+*/
+FossilAjaj.prototype.whoami = function(ajajOpt) {
+ var self = this;
+ ajajOpt = this.ajaj.normalizeAjaxParameters( ajajOpt || {} );
+ var oldOnResponse = ajajOpt.onResponse;
+ ajajOpt.onResponse = function(resp,req) {
+ var thisOpt = this;
+ if( resp && resp.payload ){
+ if(!self.auth || (self.auth.authToken!==resp.payload.authToken)){
+ self.auth = resp.payload;
+ if( WhAjaj.isFunction(self.onLogin) ){
+ self.onLogin();
+ }
+ }
+ }
+ else { delete self.auth; }
+ if( WhAjaj.isFunction(oldOnResponse) ) {
+ oldOnResponse.apply(thisOpt,[resp,req]);
+ }
+ };
+ self.sendCommand('/json/whoami', undefined, ajajOpt);
+};
+
+/**
+ EXPERIMENTAL concrete WhAjaj.Connector.sendImpl() implementation which
+ uses Rhino to connect to a local fossil binary for input and output. Its
+ signature and semantics are as described for
+ WhAjaj.Connector.prototype.sendImpl(), with a few exceptions and
+ additions:
+
+ - It does not support timeouts or asynchronous mode.
+
+ - The args.fossilBinary property must point to the local fossil binary
+ (it need not be a complete path if fossil is in the $PATH). This
+ function throws (without calling any request callbacks) if
+ args.fossilBinary is not set. fossilBinary may be set on
+ WhAjaj.Connector.options.ajax, in the FossilAjaj constructor call, as
+ the ajax options parameter to any of the FossilAjaj.sendCommand() family
+ of functions, or by setting
+ aFossilAjajInstance.ajaj.options.fossilBinary on a specific
+ FossilAjaj instance.
+
+ - It uses the args.url field to create the "command" property of the
+ request, constructs a request envelope, spawns a fossil process in JSON
+ mode, feeds it the request envelope, and returns the response envelope
+ via the same mechanisms defined for the HTTP-based implementations.
+
+ The interface is otherwise compatible with the "normal"
+ FossilAjaj.sendCommand() front-end (it is, however, fossil-specific, and
+ not back-end agnostic like the WhAjaj.sendImpl() interface intends).
+
+
+*/
+FossilAjaj.rhinoLocalBinarySendImpl = function(request,args){
+ var self = this;
+ request = request || {};
+ if(!args.fossilBinary){
+ throw new Error("fossilBinary is not set on AJAX options!");
+ }
+ var url = args.url.split('?')[0].split(/\/+/);
+ if(url.length>1){
+ // 3x shift(): protocol, host, 'json' part of path
+ request.command = (url.shift(),url.shift(),url.shift(), url.join('/'));
+ }
+ delete args.url;
+ //print("rhinoLocalBinarySendImpl SENDING: "+WhAjaj.stringify(request));
+ var json;
+ try{
+ var pargs = [args.fossilBinary, 'json', '--json-input', '-'];
+ var p = java.lang.Runtime.getRuntime().exec(pargs);
+ var outs = p.getOutputStream();
+ var osr = new java.io.OutputStreamWriter(outs);
+ var osb = new java.io.BufferedWriter(osr);
+
+ json = JSON.stringify(request);
+ osb.write(json,0, json.length);
+ osb.close();
+ var ins = p.getInputStream();
+ var isr = new java.io.InputStreamReader(ins);
+ var br = new java.io.BufferedReader(isr);
+ var line;
+ json = [];
+ while( null !== (line=br.readLine())){
+ json.push(line);
+ }
+ ins.close();
+ }catch(e){
+ args.errorMessage = e.toString();
+ WhAjaj.Connector.sendHelper.onSendError.apply( self, [request, args] );
+ return undefined;
+ }
+ json = json.join('');
+ //print("READ IN JSON: "+json);
+ WhAjaj.Connector.sendHelper.onSendSuccess.apply( self, [request, json, args] );
+}/*rhinoLocalBinary*/
ADDED ajax/js/json2.js
Index: ajax/js/json2.js
==================================================================
--- ajax/js/json2.js
+++ ajax/js/json2.js
@@ -0,0 +1,476 @@
+/*
+ http://www.JSON.org/json2.js
+ 2009-06-29
+
+ Public Domain.
+
+ NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.
+
+ See http://www.JSON.org/js.html
+
+ This file creates a global JSON object containing two methods: stringify
+ and parse.
+
+ JSON.stringify(value, replacer, space)
+ value any JavaScript value, usually an object or array.
+
+ replacer an optional parameter that determines how object
+ values are stringified for objects. It can be a
+ function or an array of strings.
+
+ space an optional parameter that specifies the indentation
+ of nested structures. If it is omitted, the text will
+ be packed without extra whitespace. If it is a number,
+ it will specify the number of spaces to indent at each
+ level. If it is a string (such as '\t' or ' '),
+ it contains the characters used to indent at each level.
+
+ This method produces a JSON text from a JavaScript value.
+
+ When an object value is found, if the object contains a toJSON
+ method, its toJSON method will be called and the result will be
+ stringified. A toJSON method does not serialize: it returns the
+ value represented by the name/value pair that should be serialized,
+ or undefined if nothing should be serialized. The toJSON method
+ will be passed the key associated with the value, and this will be
+ bound to the object holding the key.
+
+ For example, this would serialize Dates as ISO strings.
+
+ Date.prototype.toJSON = function (key) {
+ function f(n) {
+ // Format integers to have at least two digits.
+ return n < 10 ? '0' + n : n;
+ }
+
+ return this.getUTCFullYear() + '-' +
+ f(this.getUTCMonth() + 1) + '-' +
+ f(this.getUTCDate()) + 'T' +
+ f(this.getUTCHours()) + ':' +
+ f(this.getUTCMinutes()) + ':' +
+ f(this.getUTCSeconds()) + 'Z';
+ };
+
+ You can provide an optional replacer method. It will be passed the
+ key and value of each member, with this bound to the containing
+ object. The value that is returned from your method will be
+ serialized. If your method returns undefined, then the member will
+ be excluded from the serialization.
+
+ If the replacer parameter is an array of strings, then it will be
+ used to select the members to be serialized. It filters the results
+ such that only members with keys listed in the replacer array are
+ stringified.
+
+ Values that do not have JSON representations, such as undefined or
+ functions, will not be serialized. Such values in objects will be
+ dropped; in arrays they will be replaced with null. You can use
+ a replacer function to replace those with JSON values.
+ JSON.stringify(undefined) returns undefined.
+
+ The optional space parameter produces a stringification of the
+ value that is filled with line breaks and indentation to make it
+ easier to read.
+
+ If the space parameter is a non-empty string, then that string will
+ be used for indentation. If the space parameter is a number, then
+ the indentation will be that many spaces.
+
+ Example:
+
+ text = JSON.stringify(['e', {pluribus: 'unum'}]);
+ // text is '["e",{"pluribus":"unum"}]'
+
+
+ text = JSON.stringify(['e', {pluribus: 'unum'}], null, '\t');
+ // text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]'
+
+ text = JSON.stringify([new Date()], function (key, value) {
+ return this[key] instanceof Date ?
+ 'Date(' + this[key] + ')' : value;
+ });
+ // text is '["Date(---current time---)"]'
+
+
+ JSON.parse(text, reviver)
+ This method parses a JSON text to produce an object or array.
+ It can throw a SyntaxError exception.
+
+ The optional reviver parameter is a function that can filter and
+ transform the results. It receives each of the keys and values,
+ and its return value is used instead of the original value.
+ If it returns what it received, then the structure is not modified.
+ If it returns undefined then the member is deleted.
+
+ Example:
+
+ // Parse the text. Values that look like ISO date strings will
+ // be converted to Date objects.
+
+ myData = JSON.parse(text, function (key, value) {
+ var a;
+ if (typeof value === 'string') {
+ a =
+/^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
+ if (a) {
+ return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4],
+ +a[5], +a[6]));
+ }
+ }
+ return value;
+ });
+
+ myData = JSON.parse('["Date(09/09/2001)"]', function (key, value) {
+ var d;
+ if (typeof value === 'string' &&
+ value.slice(0, 5) === 'Date(' &&
+ value.slice(-1) === ')') {
+ d = new Date(value.slice(5, -1));
+ if (d) {
+ return d;
+ }
+ }
+ return value;
+ });
+
+
+ This is a reference implementation. You are free to copy, modify, or
+ redistribute.
+
+ This code should be minified before deployment.
+ See http://javascript.crockford.com/jsmin.html
+
+ USE YOUR OWN COPY. IT IS EXTREMELY UNWISE TO LOAD CODE FROM SERVERS YOU DO
+ NOT CONTROL.
+*/
+
+/*jslint evil: true */
+
+/*members "", "\b", "\t", "\n", "\f", "\r", "\"", JSON, "\\", apply,
+ call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours,
+ getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join,
+ lastIndex, length, parse, prototype, push, replace, slice, stringify,
+ test, toJSON, toString, valueOf
+*/
+
+// Create a JSON object only if one does not already exist. We create the
+// methods in a closure to avoid creating global variables.
+
+var JSON = JSON || {};
+
+(function () {
+
+ function f(n) {
+ // Format integers to have at least two digits.
+ return n < 10 ? '0' + n : n;
+ }
+
+ if (typeof Date.prototype.toJSON !== 'function') {
+
+ Date.prototype.toJSON = function (key) {
+
+ return isFinite(this.valueOf()) ?
+ this.getUTCFullYear() + '-' +
+ f(this.getUTCMonth() + 1) + '-' +
+ f(this.getUTCDate()) + 'T' +
+ f(this.getUTCHours()) + ':' +
+ f(this.getUTCMinutes()) + ':' +
+ f(this.getUTCSeconds()) + 'Z' : null;
+ };
+
+ String.prototype.toJSON =
+ Number.prototype.toJSON =
+ Boolean.prototype.toJSON = function (key) {
+ return this.valueOf();
+ };
+ }
+
+ var cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
+ escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
+ gap,
+ indent,
+ meta = { // table of character substitutions
+ '\b': '\\b',
+ '\t': '\\t',
+ '\n': '\\n',
+ '\f': '\\f',
+ '\r': '\\r',
+ '"' : '\\"',
+ '\\': '\\\\'
+ },
+ rep;
+
+
+ function quote(string) {
+
+// If the string contains no control characters, no quote characters, and no
+// backslash characters, then we can safely slap some quotes around it.
+// Otherwise we must also replace the offending characters with safe escape
+// sequences.
+
+ escapable.lastIndex = 0;
+ return escapable.test(string) ?
+ '"' + string.replace(escapable, function (a) {
+ var c = meta[a];
+ return typeof c === 'string' ? c :
+ '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
+ }) + '"' :
+ '"' + string + '"';
+ }
+
+
+ function str(key, holder) {
+
+// Produce a string from holder[key].
+
+ var i, // The loop counter.
+ k, // The member key.
+ v, // The member value.
+ length,
+ mind = gap,
+ partial,
+ value = holder[key];
+
+// If the value has a toJSON method, call it to obtain a replacement value.
+
+ if (value && typeof value === 'object' &&
+ typeof value.toJSON === 'function') {
+ value = value.toJSON(key);
+ }
+
+// If we were called with a replacer function, then call the replacer to
+// obtain a replacement value.
+
+ if (typeof rep === 'function') {
+ value = rep.call(holder, key, value);
+ }
+
+// What happens next depends on the value's type.
+
+ switch (typeof value) {
+ case 'string':
+ return quote(value);
+
+ case 'number':
+
+// JSON numbers must be finite. Encode non-finite numbers as null.
+
+ return isFinite(value) ? String(value) : 'null';
+
+ case 'boolean':
+ case 'null':
+
+// If the value is a boolean or null, convert it to a string. Note:
+// typeof null does not produce 'null'. The case is included here in
+// the remote chance that this gets fixed someday.
+
+ return String(value);
+
+// If the type is 'object', we might be dealing with an object or an array or
+// null.
+
+ case 'object':
+
+// Due to a specification blunder in ECMAScript, typeof null is 'object',
+// so watch out for that case.
+
+ if (!value) {
+ return 'null';
+ }
+
+// Make an array to hold the partial results of stringifying this object value.
+
+ gap += indent;
+ partial = [];
+
+// Is the value an array?
+
+ if (Object.prototype.toString.apply(value) === '[object Array]') {
+
+// The value is an array. Stringify every element. Use null as a placeholder
+// for non-JSON values.
+
+ length = value.length;
+ for (i = 0; i < length; i += 1) {
+ partial[i] = str(i, value) || 'null';
+ }
+
+// Join all of the elements together, separated with commas, and wrap them in
+// brackets.
+
+ v = partial.length === 0 ? '[]' :
+ gap ? '[\n' + gap +
+ partial.join(',\n' + gap) + '\n' +
+ mind + ']' :
+ '[' + partial.join(',') + ']';
+ gap = mind;
+ return v;
+ }
+
+// If the replacer is an array, use it to select the members to be stringified.
+
+ if (rep && typeof rep === 'object') {
+ length = rep.length;
+ for (i = 0; i < length; i += 1) {
+ k = rep[i];
+ if (typeof k === 'string') {
+ v = str(k, value);
+ if (v) {
+ partial.push(quote(k) + (gap ? ': ' : ':') + v);
+ }
+ }
+ }
+ } else {
+
+// Otherwise, iterate through all of the keys in the object.
+
+ for (k in value) {
+ if (Object.hasOwnProperty.call(value, k)) {
+ v = str(k, value);
+ if (v) {
+ partial.push(quote(k) + (gap ? ': ' : ':') + v);
+ }
+ }
+ }
+ }
+
+// Join all of the member texts together, separated with commas,
+// and wrap them in braces.
+
+ v = partial.length === 0 ? '{}' :
+ gap ? '{\n' + gap + partial.join(',\n' + gap) + '\n' +
+ mind + '}' : '{' + partial.join(',') + '}';
+ gap = mind;
+ return v;
+ }
+ }
+
+// If the JSON object does not yet have a stringify method, give it one.
+
+ if (typeof JSON.stringify !== 'function') {
+ JSON.stringify = function (value, replacer, space) {
+
+// The stringify method takes a value and an optional replacer, and an optional
+// space parameter, and returns a JSON text. The replacer can be a function
+// that can replace values, or an array of strings that will select the keys.
+// A default replacer method can be provided. Use of the space parameter can
+// produce text that is more easily readable.
+
+ var i;
+ gap = '';
+ indent = '';
+
+// If the space parameter is a number, make an indent string containing that
+// many spaces.
+
+ if (typeof space === 'number') {
+ for (i = 0; i < space; i += 1) {
+ indent += ' ';
+ }
+
+// If the space parameter is a string, it will be used as the indent string.
+
+ } else if (typeof space === 'string') {
+ indent = space;
+ }
+
+// If there is a replacer, it must be a function or an array.
+// Otherwise, throw an error.
+
+ rep = replacer;
+ if (replacer && typeof replacer !== 'function' &&
+ (typeof replacer !== 'object' ||
+ typeof replacer.length !== 'number')) {
+ throw new Error('JSON.stringify');
+ }
+
+// Make a fake root object containing our value under the key of ''.
+// Return the result of stringifying the value.
+
+ return str('', {'': value});
+ };
+ }
+
+
+// If the JSON object does not yet have a parse method, give it one.
+
+ if (typeof JSON.parse !== 'function') {
+ JSON.parse = function (text, reviver) {
+
+// The parse method takes a text and an optional reviver function, and returns
+// a JavaScript value if the text is a valid JSON text.
+
+ var j;
+
+ function walk(holder, key) {
+
+// The walk method is used to recursively walk the resulting structure so
+// that modifications can be made.
+
+ var k, v, value = holder[key];
+ if (value && typeof value === 'object') {
+ for (k in value) {
+ if (Object.hasOwnProperty.call(value, k)) {
+ v = walk(value, k);
+ if (v !== undefined) {
+ value[k] = v;
+ } else {
+ delete value[k];
+ }
+ }
+ }
+ }
+ return reviver.call(holder, key, value);
+ }
+
+
+// Parsing happens in four stages. In the first stage, we replace certain
+// Unicode characters with escape sequences. JavaScript handles many characters
+// incorrectly, either silently deleting them, or treating them as line endings.
+
+ cx.lastIndex = 0;
+ if (cx.test(text)) {
+ text = text.replace(cx, function (a) {
+ return '\\u' +
+ ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
+ });
+ }
+
+// In the second stage, we run the text against regular expressions that look
+// for non-JSON patterns. We are especially concerned with '()' and 'new'
+// because they can cause invocation, and '=' because it can cause mutation.
+// But just to be safe, we want to reject all unexpected forms.
+
+// We split the second stage into 4 regexp operations in order to work around
+// crippling inefficiencies in IE's and Safari's regexp engines. First we
+// replace the JSON backslash pairs with '@' (a non-JSON character). Second, we
+// replace all simple value tokens with ']' characters. Third, we delete all
+// open brackets that follow a colon or comma or that begin the text. Finally,
+// we look to see that the remaining characters are only whitespace or ']' or
+// ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval.
+
+ if (/^[\],:{}\s]*$/.
+test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@').
+replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']').
+replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
+
+// In the third stage we use the eval function to compile the text into a
+// JavaScript structure. The '{' operator is subject to a syntactic ambiguity
+// in JavaScript: it can begin a block or an object literal. We wrap the text
+// in parens to eliminate the ambiguity.
+
+ j = eval('(' + text + ')');
+
+// In the optional fourth stage, we recursively walk the new structure, passing
+// each name/value pair to a reviver function for possible transformation.
+
+ return typeof reviver === 'function' ?
+ walk({'': j}, '') : j;
+ }
+
+// If the text is not JSON parseable, then a SyntaxError is thrown.
+
+ throw new SyntaxError('JSON.parse');
+ };
+ }
+}());
ADDED ajax/js/whajaj.js
Index: ajax/js/whajaj.js
==================================================================
--- ajax/js/whajaj.js
+++ ajax/js/whajaj.js
@@ -0,0 +1,1221 @@
+/**
+ This file provides a JS interface into the core functionality of
+ JSON-centric back-ends. It sends GET or JSON POST requests to
+ a back-end and expects JSON responses. The exact semantics of
+ the underlying back-end and overlying front-end are not its concern,
+ and it leaves the interpretation of the data up to the client/server
+ insofar as possible.
+
+ All functionality is part of a class named WhAjaj, and that class
+ acts as namespace for this framework.
+
+ Author: Stephan Beal (http://wanderinghorse.net/home/stephan/)
+
+ License: Public Domain
+
+ This framework is directly derived from code originally found in
+ http://code.google.com/p/jsonmessage, and later in
+ http://whiki.wanderinghorse.net, where it contained quite a bit
+ of application-specific logic. It was eventually (the 3rd time i
+ needed it) split off into its own library to simplify inclusion
+ into my many mini-projects.
+*/
+
+
+/**
+ The WhAjaj function is primarily a namespace, and not intended
+ to called or instantiated via the 'new' operator.
+*/
+function WhAjaj()
+{
+}
+
+/** Returns a millisecond Unix Epoch timestamp. */
+WhAjaj.msTimestamp = function()
+{
+ return (new Date()).getTime();
+};
+
+/** Returns a Unix Epoch timestamp (in seconds) in integer format.
+
+ Reminder to self: (1.1 %1.2) evaluates to a floating-point value
+ in JS, and thus this implementation is less than optimal.
+*/
+WhAjaj.unixTimestamp = function()
+{
+ var ts = (new Date()).getTime();
+ return parseInt( ""+((ts / 1000) % ts) );
+};
+
+/**
+ Returns true if v is-a Array instance.
+*/
+WhAjaj.isArray = function( v )
+{
+ return (v &&
+ (v instanceof Array) ||
+ (Object.prototype.toString.call(v) === "[object Array]")
+ );
+ /* Reminders to self:
+ typeof [] == "object"
+ toString.call([]) == "[object Array]"
+ ([]).toString() == empty
+ */
+};
+
+/**
+ Returns true if v is-a Object instance.
+*/
+WhAjaj.isObject = function( v )
+{
+ return v &&
+ (v instanceof Object) &&
+ ('[object Object]' === Object.prototype.toString.apply(v) );
+};
+
+/**
+ Returns true if v is-a Function instance.
+*/
+WhAjaj.isFunction = function(obj)
+{
+ return obj
+ && (
+ (obj instanceof Function)
+ || ('function' === typeof obj)
+ || ("[object Function]" === Object.prototype.toString.call(obj))
+ )
+ ;
+};
+
+/**
+ Parses window.location.search-style string into an object
+ containing key/value pairs of URL arguments (already urldecoded).
+
+ If the str argument is not passed (arguments.length==0) then
+ window.location.search.substring(1) is used by default. If
+ neither str is passed in nor window exists then false is returned.
+
+ On success it returns an Object containing the key/value pairs
+ parsed from the string. Keys which have no value are treated
+ has having the boolean true value.
+
+ FIXME: for keys in the form "name[]", build an array of results,
+ like PHP does.
+
+*/
+WhAjaj.processUrlArgs = function(str) {
+ if( 0 === arguments.length ) {
+ if( ('undefined' === typeof window) ||
+ !window.location ||
+ !window.location.search ) return false;
+ else str = (''+window.location.search).substring(1);
+ }
+ if( ! str ) return false;
+ str = (''+str).split(/#/,2)[0]; // remove #... to avoid it being added as part of the last value.
+ var args = {};
+ var sp = str.split(/&+/);
+ var rx = /^([^=]+)(=(.+))?/;
+ var i, m;
+ for( i in sp ) {
+ m = rx.exec( sp[i] );
+ if( ! m ) continue;
+ args[decodeURIComponent(m[1])] = (m[3] ? decodeURIComponent(m[3]) : true);
+ }
+ return args;
+};
+
+/**
+ A simple wrapper around JSON.stringify(), using my own personal
+ preferred values for the 2nd and 3rd parameters. To globally
+ set its indentation level, assign WhAjaj.stringify.indent to
+ an integer value (0 for no intendation).
+
+ This function is intended only for human-readable output, not
+ generic over-the-wire JSON output (where JSON.stringify(val) will
+ produce smaller results).
+*/
+WhAjaj.stringify = function(val) {
+ if( ! arguments.callee.indent ) arguments.callee.indent = 4;
+ return JSON.stringify(val,0,arguments.callee.indent);
+};
+
+/**
+ Each instance of this class holds state information for making
+ AJAJ requests to a back-end system. While clients may use one
+ "requester" object per connection attempt, for connections to the
+ same back-end, using an instance configured for that back-end
+ can simplify usage. This class is designed so that the actual
+ connection-related details (i.e. _how_ it connects to the
+ back-end) may be re-implemented to use a client's preferred
+ connection mechanism (e.g. jQuery).
+
+ The optional opt paramater may be an object with any (or all) of
+ the properties documented for WhAjaj.Connector.options.ajax.
+ Properties set here (or later via modification of the "options"
+ property of this object) will be used in calls to
+ WhAjaj.Connector.sendRequest(), and these override (normally) any
+ options set in WhAjaj.Connector.options.ajax. Note that
+ WhAjaj.Connector.sendRequest() _also_ takes an options object,
+ and ones passed there will override, for purposes of that one
+ request, any options passed in here or defined in
+ WhAjaj.Connector.options.ajax. See WhAjaj.Connector.options.ajax
+ and WhAjaj.Connector.prototype.sendRequest() for more details
+ about the precedence of options.
+
+ Sample usage:
+
+ @code
+ // Set up common connection-level options:
+ var cgi = new WhAjaj.Connector({
+ url: '/cgi-bin/my.cgi',
+ timeout:10000,
+ onResponse(resp,req) { alert(JSON.stringify(resp,0.4)); },
+ onError(req,opt) {
+ alert(opt.errorMessage);
+ }
+ });
+ // Any of those options may optionally be set globally in
+ // WhAjaj.Connector.options.ajax (onError(), beforeSend(), and afterSend()
+ // are often easiest/most useful to set globally).
+
+ // Get list of pages...
+ cgi.sendRequest( null, {
+ onResponse(resp,req){ alert(WhAjaj.stringify(resp)); }
+ });
+ @endcode
+
+ For common request types, clients can add functions to this
+ object which act as wrappers for backend-specific functionality. As
+ a simple example:
+
+ @code
+ cgi.login = function(name,pw,ajajOpt) {
+ this.sendRequest(
+ {command:"json/login",
+ name:name,
+ password:pw
+ }, ajajOpt );
+ };
+ @endcode
+
+ TODOs:
+
+ - Caching of page-load requests, with a configurable lifetime.
+
+ - Use-cases like the above login() function are a tiny bit
+ problematic to implement when each request has a different URL
+ path (i know this from the whiki and fossil implementations).
+ This is partly a side-effect of design descisions made back in
+ the very first days of this code's life. i need to go through
+ and see where i can bend those conventions a bit (where it won't
+ break my other apps unduly).
+*/
+WhAjaj.Connector = function(opt)
+{
+ if(WhAjaj.isObject(opt)) this.options = opt;
+ //TODO?: this.$cache = {};
+};
+
+/**
+ The core options used by WhAjaj.Connector instances for performing
+ network operations. These options can (and some _should_)
+ be changed by a client application. They can also be changed
+ on specific instances of WhAjaj.Connector, but for most applications
+ it is simpler to set them here and not have to bother with configuring
+ each WhAjaj.Connector instance. Apps which use multiple back-ends at one time,
+ however, will need to customize each instance for a given back-end.
+*/
+WhAjaj.Connector.options = {
+ /**
+ A (meaningless) prefix to apply to WhAjaj.Connector-generated
+ request IDs.
+ */
+ requestIdPrefix:'WhAjaj.Connector-',
+ /**
+ Default options for WhAjaj.Connector.sendRequest() connection
+ parameters. This object holds only connection-related
+ options and callbacks (all optional), and not options
+ related to the required JSON structure of any given request.
+ i.e. the page name used in a get-page request are not set
+ here but are specified as part of the request object.
+
+ These connection options are a "normalized form" of options
+ often found in various AJAX libraries like jQuery,
+ Prototype, dojo, etc. This approach allows us to swap out
+ the real connection-related parts by writing a simple proxy
+ which transforms our "normalized" form to the
+ backend-specific form. For examples, see the various
+ implementations stored in WhAjaj.Connector.sendImpls.
+
+ The following callback options are, in practice, almost
+ always set globally to some app-wide defaults:
+
+ - onError() to report errors using a common mechanism.
+ - beforeSend() to start a visual activity notification
+ - afterSend() to disable the visual activity notification
+
+ However, be aware that if any given WhAjaj.Connector instance is
+ given its own before/afterSend callback then those will
+ override these. Mixing shared/global and per-instance
+ callbacks can potentially lead to confusing results if, e.g.,
+ the beforeSend() and afterSend() functions have side-effects
+ but are not used with their proper before/after partner.
+
+ TODO: rename this to 'ajaj' (the name is historical). The
+ problem with renaming it is is that the word 'ajax' is
+ pretty prevelant in the source tree, so i can't globally
+ swap it out.
+ */
+ ajax: {
+ /**
+ URL of the back-end server/CGI.
+ */
+ url: '/some/path',
+
+ /**
+ Connection method. Some connection-related functions might
+ override any client-defined setting.
+
+ Must be one of 'GET' or 'POST'. For custom connection
+ implementation, it may optionally be some
+ implementation-specified value.
+
+ Normally the API can derive this value automatically - if the
+ request uses JSON data it is POSTed, else it is GETted.
+ */
+ method:'GET',
+
+ /**
+ A hint whether to run the operation asynchronously or
+ not. Not all concrete WhAjaj.Connector.sendImpl()
+ implementations can support this. Interestingly, at
+ least one popular AJAX toolkit does not document
+ supporting _synchronous_ AJAX operations. All common
+ browser-side implementations support async operation, but
+ non-browser implementations might not.
+ */
+ asynchronous:true,
+
+ /**
+ A HTTP authentication login name for the AJAX
+ connection. Not all concrete WhAjaj.Connector.sendImpl()
+ implementations can support this.
+ */
+ loginName:undefined,
+
+ /**
+ An HTTP authentication login password for the AJAJ
+ connection. Not all concrete WhAjaj.Connector.sendImpl()
+ implementations can support this.
+ */
+ loginPassword:undefined,
+
+ /**
+ A connection timeout, in milliseconds, for establishing
+ an AJAJ connection. Not all concrete
+ WhAjaj.Connector.sendImpl() implementations can support this.
+ */
+ timeout:10000,
+
+ /**
+ If an AJAJ request receives JSON data from the back-end,
+ that data is passed as a plain Object as the response
+ parameter (exception: in jsonp mode it is passed a
+ string (why???)). The initiating request object is
+ passed as the second parameter, but clients can normally
+ ignore it (only those which need a way to map specific
+ requests to responses will need it). The 3rd parameter
+ is the same as the 'this' object for the context of the
+ callback, but is provided because the instance-level
+ callbacks (set in (WhAjaj.Connector instance).callbacks,
+ require it in some cases (because their 'this' is
+ different!).
+
+ Note that the response might contain error information
+ which comes from the back-end. The difference between
+ this error info and the info passed to the onError()
+ callback is that this data indicates an
+ application-level error, whereas onError() is used to
+ report connection-level problems or when the backend
+ produces non-JSON data (which, when not in jsonp mode,
+ is unexpected and is as fatal to the request as a
+ connection error).
+ */
+ onResponse: function(response, request, opt){},
+
+ /**
+ If an AJAX request fails to establish a connection or it
+ receives non-JSON data from the back-end, this function
+ is called (e.g. timeout error or host name not
+ resolvable). It is passed the originating request and the
+ "normalized" connection parameters used for that
+ request. The connectOpt object "should" (or "might")
+ have an "errorMessage" property which describes the
+ nature of the problem.
+
+ Clients will almost always want to replace the default
+ implementation with something which integrates into
+ their application.
+ */
+ onError: function(request, connectOpt)
+ {
+ alert('AJAJ request failed:\n'
+ +'Connection information:\n'
+ +JSON.stringify(connectOpt,0,4)
+ );
+ },
+
+ /**
+ Called before each connection attempt is made. Clients
+ can use this to, e.g., enable a visual "network activity
+ notification" for the user. It is passed the original
+ request object and the normalized connection parameters
+ for the request. If this function changes opt, those
+ changes _are_ applied to the subsequent request. If this
+ function throws, neither the onError() nor afterSend()
+ callbacks are triggered and WhAjaj.Connector.sendImpl()
+ propagates the exception back to the caller.
+ */
+ beforeSend: function(request,opt){},
+
+ /**
+ Called after an AJAJ connection attempt completes,
+ regardless of success or failure. Passed the same
+ parameters as beforeSend() (see that function for
+ details).
+
+ Here's an example of setting up a visual notification on
+ ajax operations using jQuery (but it's also easy to do
+ without jQuery as well):
+
+ @code
+ function startAjaxNotif(req,opt) {
+ var me = arguments.callee;
+ var c = ++me.ajaxCount;
+ me.element.text( c + " pending AJAX operation(s)..." );
+ if( 1 == c ) me.element.stop().fadeIn();
+ }
+ startAjaxNotif.ajaxCount = 0.
+ startAjaxNotif.element = jQuery('#whikiAjaxNotification');
+
+ function endAjaxNotif() {
+ var c = --startAjaxNotif.ajaxCount;
+ startAjaxNotif.element.text( c+" pending AJAX operation(s)..." );
+ if( 0 == c ) startAjaxNotif.element.stop().fadeOut();
+ }
+ @endcode
+
+ Set the beforeSend/afterSend properties to those
+ functions to enable the notifications by default.
+ */
+ afterSend: function(request,opt){},
+
+ /**
+ If jsonp is a string then the WhAjaj-internal response
+ handling code ASSUMES that the response contains a JSONP-style
+ construct and eval()s it after afterSend() but before onResponse().
+ In this case, onResponse() will get a string value for the response
+ instead of a response object parsed from JSON.
+ */
+ jsonp:undefined,
+ /**
+ Don't use yet. Planned future option.
+ */
+ propagateExceptions:false
+ }
+};
+
+
+/**
+ WhAjaj.Connector.prototype.callbacks defines callbacks analog
+ to the onXXX callbacks defined in WhAjaj.Connector.options.ajax,
+ with two notable differences:
+
+ 1) these callbacks, if set, are called in addition to any
+ request-specific callback. The intention is to allow a framework to set
+ "framework-level" callbacks which should be called independently of the
+ request-specific callbacks (without interfering with them, e.g.
+ requiring special re-forwarding features).
+
+ 2) The 'this' object in these callbacks is the Connector instance
+ associated with the callback, whereas the "other" onXXX form has its
+ "ajax options" object as its this.
+
+ When this API says that an onXXX callback will be called for a request,
+ both the request's onXXX (if set) and this one (if set) will be called.
+*/
+WhAjaj.Connector.prototype.callbacks = {};
+/**
+ Instance-specific values for AJAJ-level properties (as opposed to
+ application-level request properties). Options set here "override" those
+ specified in WhAjaj.Connector.options.ajax and are "overridden" by
+ options passed to sendRequest().
+*/
+WhAjaj.Connector.prototype.options = {};
+
+
+/**
+ Tries to find the given key in any of the following, returning
+ the first match found: opt, this.options, WhAjaj.Connector.options.ajax.
+
+ Returns undefined if key is not found.
+*/
+WhAjaj.Connector.prototype.derivedOption = function(key,opt) {
+ var v = opt ? opt[key] : undefined;
+ if( undefined !== v ) return v;
+ else v = this.options[key];
+ if( undefined !== v ) return v;
+ else v = WhAjaj.Connector.options.ajax[key];
+ return v;
+};
+
+/**
+ Returns a unique string on each call containing a generic
+ reandom request identifier string. This is not used by the core
+ API but can be used by client code to generate unique IDs for
+ each request (if needed).
+
+ The exact format is unspecified and may change in the future.
+
+ Request IDs can be used by clients to "match up" responses to
+ specific requests if needed. In practice, however, they are
+ seldom, if ever, needed. When passing several concurrent
+ requests through the same response callback, it might be useful
+ for some clients to be able to distinguish, possibly re-routing
+ them through other handlers based on the originating request type.
+
+ If this.options.requestIdPrefix or
+ WhAjaj.Connector.options.requestIdPrefix is set then that text
+ is prefixed to the returned string.
+*/
+WhAjaj.Connector.prototype.generateRequestId = function()
+{
+ if( undefined === arguments.callee.sequence )
+ {
+ arguments.callee.sequence = 0;
+ }
+ var pref = this.options.requestIdPrefix || WhAjaj.Connector.options.requestIdPrefix || '';
+ return pref +
+ WhAjaj.msTimestamp() +
+ '/'+(Math.round( Math.random() * 100000000) )+
+ ':'+(++arguments.callee.sequence);
+};
+
+/**
+ Copies (SHALLOWLY) all properties in opt to this.options.
+*/
+WhAjaj.Connector.prototype.addOptions = function(opt) {
+ var k, v;
+ for( k in opt ) {
+ if( ! opt.hasOwnProperty(k) ) continue /* proactive Prototype kludge! */;
+ this.options[k] = opt[k];
+ }
+ return this.options;
+};
+
+/**
+ An internal helper object which holds several functions intended
+ to simplify the creation of concrete communication channel
+ implementations for WhAjaj.Connector.sendImpl(). These operations
+ take care of some of the more error-prone parts of ensuring that
+ onResponse(), onError(), etc. callbacks are called consistently
+ using the same rules.
+*/
+WhAjaj.Connector.sendHelper = {
+ /**
+ opt is assumed to be a normalized set of
+ WhAjaj.Connector.sendRequest() options. This function
+ creates a url by concatenating opt.url and some form of
+ opt.urlParam.
+
+ If opt.urlParam is an object or string then it is appended
+ to the url. An object is assumed to be a one-dimensional set
+ of simple (urlencodable) key/value pairs, and not larger
+ data structures. A string value is assumed to be a
+ well-formed, urlencoded set of key/value pairs separated by
+ '&' characters.
+
+ The new/normalized URL is returned (opt is not modified). If
+ opt.urlParam is not set then opt.url is returned (or an
+ empty string if opt.url is itself a false value).
+
+ TODO: if opt is-a Object and any key points to an array,
+ build up a list of keys in the form "keyname[]". We could
+ arguably encode sub-objects like "keyname[subkey]=...", but
+ i don't know if that's conventions-compatible with other
+ frameworks.
+ */
+ normalizeURL: function(opt) {
+ var u = opt.url || '';
+ if( opt.urlParam ) {
+ var addQ = (u.indexOf('?') >= 0) ? false : true;
+ var addA = addQ ? false : ((u.indexOf('&')>=0) ? true : false);
+ var tail = '';
+ if( WhAjaj.isObject(opt.urlParam) ) {
+ var li = [], k;
+ for( k in opt.urlParam) {
+ li.push( k+'='+encodeURIComponent( opt.urlParam[k] ) );
+ }
+ tail = li.join('&');
+ }
+ else if( 'string' === typeof opt.urlParam ) {
+ tail = opt.urlParam;
+ }
+ u = u + (addQ ? '?' : '') + (addA ? '&' : '') + tail;
+ }
+ return u;
+ },
+ /**
+ Should be called by WhAjaj.Connector.sendImpl()
+ implementations after a response has come back. This
+ function takes care of most of ensuring that framework-level
+ conventions involving WhAjaj.Connector.options.ajax
+ properties are followed.
+
+ The request argument must be the original request passed to
+ the sendImpl() function. It may legally be null for GET requests.
+
+ The opt object should be the normalized AJAX options used
+ for the connection.
+
+ The resp argument may be either a plain Object or a string
+ (in which case it is assumed to be JSON).
+
+ The 'this' object for this call MUST be a WhAjaj.Connector
+ instance in order for callback processing to work properly.
+
+ This function takes care of the following:
+
+ - Calling opt.afterSend()
+
+ - If resp is a string, de-JSON-izing it to an object.
+
+ - Calling opt.onResponse()
+
+ - Calling opt.onError() in several common (potential) error
+ cases.
+
+ - If resp is-a String and opt.jsonp then resp is assumed to be
+ a JSONP-form construct and is eval()d BEFORE opt.onResponse()
+ is called. It is arguable to eval() it first, but the logic
+ integrates better with the non-jsonp handler.
+
+ The sendImpl() should return immediately after calling this.
+
+ The sendImpl() must call only one of onSendSuccess() or
+ onSendError(). It must call one of them or it must implement
+ its own response/error handling, which is not recommended
+ because getting the documented semantics of the
+ onError/onResponse/afterSend handling correct can be tedious.
+ */
+ onSendSuccess:function(request,resp,opt) {
+ var cb = this.callbacks || {};
+ if( WhAjaj.isFunction(cb.afterSend) ) {
+ try {cb.afterSend( request, opt );}
+ catch(e){}
+ }
+ if( WhAjaj.isFunction(opt.afterSend) ) {
+ try {opt.afterSend( request, opt );}
+ catch(e){}
+ }
+ function doErr(){
+ if( WhAjaj.isFunction(cb.onError) ) {
+ try {cb.onError( request, opt );}
+ catch(e){}
+ }
+ if( WhAjaj.isFunction(opt.onError) ) {
+ try {opt.onError( request, opt );}
+ catch(e){}
+ }
+ }
+ if( ! resp ) {
+ opt.errorMessage = "Sending of request succeeded but returned no data!";
+ doErr();
+ return false;
+ }
+
+ if( 'string' === typeof resp ) {
+ try {
+ resp = opt.jsonp ? eval(resp) : JSON.parse(resp);
+ } catch(e) {
+ opt.errorMessage = e.toString();
+ doErr();
+ return;
+ }
+ }
+ try {
+ if( WhAjaj.isFunction( cb.onResponse ) ) {
+ cb.onResponse( resp, request, opt );
+ }
+ if( WhAjaj.isFunction( opt.onResponse ) ) {
+ opt.onResponse( resp, request, opt );
+ }
+ return true;
+ }
+ catch(e) {
+ opt.errorMessage = "Exception while handling inbound JSON response:\n"
+ + e
+ +"\nOriginal response data:\n"+JSON.stringify(resp,0,2)
+ ;
+ ;
+ doErr();
+ return false;
+ }
+ },
+ /**
+ Should be called by sendImpl() implementations after a response
+ has failed to connect (e.g. could not resolve host or timeout
+ reached). This function takes care of most of ensuring that
+ framework-level conventions involving WhAjaj.Connector.options.ajax
+ properties are followed.
+
+ The request argument must be the original request passed to
+ the sendImpl() function. It may legally be null for GET
+ requests.
+
+ The 'this' object for this call MUST be a WhAjaj.Connector
+ instance in order for callback processing to work properly.
+
+ The opt object should be the normalized AJAX options used
+ for the connection. By convention, the caller of this
+ function "should" set opt.errorMessage to contain a
+ human-readable description of the error.
+
+ The sendImpl() should return immediately after calling this. The
+ return value from this function is unspecified.
+ */
+ onSendError: function(request,opt) {
+ var cb = this.callbacks || {};
+ if( WhAjaj.isFunction(cb.afterSend) ) {
+ try {cb.afterSend( request, opt );}
+ catch(e){}
+ }
+ if( WhAjaj.isFunction(opt.afterSend) ) {
+ try {opt.afterSend( request, opt );}
+ catch(e){}
+ }
+ if( WhAjaj.isFunction( cb.onError ) ) {
+ try {cb.onError( request, opt );}
+ catch(e) {/*ignore*/}
+ }
+ if( WhAjaj.isFunction( opt.onError ) ) {
+ try {opt.onError( request, opt );}
+ catch(e) {/*ignore*/}
+ }
+ }
+};
+
+/**
+ WhAjaj.Connector.sendImpls holds several concrete
+ implementations of WhAjaj.Connector.prototype.sendImpl(). To use
+ a specific implementation by default assign
+ WhAjaj.Connector.prototype.sendImpl to one of these functions.
+
+ The functions defined here require that the 'this' object be-a
+ WhAjaj.Connector instance.
+
+ Historical notes:
+
+ a) We once had an implementation based on Prototype, but that
+ library just pisses me off (they change base-most types'
+ prototypes, introducing side-effects in client code which
+ doesn't even use Prototype). The Prototype version at the time
+ had a serious toJSON() bug which caused empty arrays to
+ serialize as the string "[]", which broke a bunch of my code.
+ (That has been fixed in the mean time, but i don't use
+ Prototype.)
+
+ b) We once had an implementation for the dojo library,
+
+ If/when the time comes to add Prototype/dojo support, we simply
+ need to port:
+
+ http://code.google.com/p/jsonmessage/source/browse/trunk/lib/JSONMessage/JSONMessage.inc.js
+
+ (search that file for "dojo" and "Prototype") to this tree. That
+ code is this code's generic grandfather and they are still very
+ similar, so a port is trivial.
+
+*/
+WhAjaj.Connector.sendImpls = {
+ /**
+ This is a concrete implementation of
+ WhAjaj.Connector.prototype.sendImpl() which uses the
+ environment's native XMLHttpRequest class to send whiki
+ requests and fetch the responses.
+
+ The only argument must be a connection properties object, as
+ constructed by WhAjaj.Connector.normalizeAjaxParameters().
+
+ If window.firebug is set then window.firebug.watchXHR() is
+ called to enable monitoring of the XMLHttpRequest object.
+
+ This implementation honors the loginName and loginPassword
+ connection parameters.
+
+ Returns the XMLHttpRequest object.
+
+ This implementation requires that the 'this' object be-a
+ WhAjaj.Connector.
+
+ This implementation uses setTimeout() to implement the
+ timeout support, and thus the JS engine must provide that
+ functionality.
+ */
+ XMLHttpRequest: function(request, args)
+ {
+ var json = WhAjaj.isObject(request) ? JSON.stringify(request) : request;
+ var xhr = new XMLHttpRequest();
+ var startTime = (new Date()).getTime();
+ var timeout = args.timeout || 10000/*arbitrary!*/;
+ var hitTimeout = false;
+ var done = false;
+ var tmid /* setTimeout() ID */;
+ var whself = this;
+ function handleTimeout()
+ {
+ hitTimeout = true;
+ if( ! done )
+ {
+ var now = (new Date()).getTime();
+ try { xhr.abort(); } catch(e) {/*ignore*/}
+ // see: http://www.w3.org/TR/XMLHttpRequest/#the-abort-method
+ args.errorMessage = "Timeout of "+timeout+"ms reached after "+(now-startTime)+"ms during AJAX request.";
+ WhAjaj.Connector.sendHelper.onSendError.apply( whself, [request, args] );
+ }
+ return;
+ }
+ function onStateChange()
+ { // reminder to self: apparently 'this' is-not-a XHR :/
+ if( hitTimeout )
+ { /* we're too late - the error was already triggered. */
+ return;
+ }
+
+ if( 4 == xhr.readyState )
+ {
+ done = true;
+ if( tmid )
+ {
+ clearTimeout( tmid );
+ tmid = null;
+ }
+ if( (xhr.status >= 200) && (xhr.status < 300) )
+ {
+ WhAjaj.Connector.sendHelper.onSendSuccess.apply( whself, [request, xhr.responseText, args] );
+ return;
+ }
+ else
+ {
+ if( undefined === args.errorMessage )
+ {
+ args.errorMessage = "Error sending a '"+args.method+"' AJAX request to "
+ +"["+args.url+"]: "
+ +"Status text=["+xhr.statusText+"]"
+ ;
+ WhAjaj.Connector.sendHelper.onSendError.apply( whself, [request, args] );
+ }
+ else { /*maybe it was was set by the timeout handler. */ }
+ return;
+ }
+ }
+ };
+
+ xhr.onreadystatechange = onStateChange;
+ if( ('undefined'!==(typeof window)) && ('firebug' in window) && ('watchXHR' in window.firebug) )
+ { /* plug in to firebug lite's XHR monitor... */
+ window.firebug.watchXHR( xhr );
+ }
+ try
+ {
+ //alert( JSON.stringify( args ));
+ function xhrOpen()
+ {
+ if( ('loginName' in args) && args.loginName )
+ {
+ xhr.open( args.method, args.url, args.asynchronous, args.loginName, args.loginPassword );
+ }
+ else
+ {
+ xhr.open( args.method, args.url, args.asynchronous );
+ }
+ }
+ if( json && ('POST' === args.method.toUpperCase()) )
+ {
+ xhrOpen();
+ xhr.setRequestHeader("Content-Type", "application/json; charset=utf-8");
+ // Google Chrome warns that it refuses to set these
+ // "unsafe" headers (his words, not mine):
+ // xhr.setRequestHeader("Content-length", json.length);
+ // xhr.setRequestHeader("Connection", "close");
+ xhr.send( json );
+ }
+ else /* assume GET */
+ {
+ xhrOpen();
+ xhr.send(null);
+ }
+ tmid = setTimeout( handleTimeout, timeout );
+ return xhr;
+ }
+ catch(e)
+ {
+ args.errorMessage = e.toString();
+ WhAjaj.Connector.sendHelper.onSendError.apply( whself, [request, args] );
+ return undefined;
+ }
+ }/*XMLHttpRequest()*/,
+ /**
+ This is a concrete implementation of
+ WhAjaj.Connector.prototype.sendImpl() which uses the jQuery
+ AJAX API to send requests and fetch the responses.
+
+ The first argument may be either null/false, an Object
+ containing toJSON-able data to post to the back-end, or such an
+ object in JSON string form.
+
+ The second argument must be a connection properties object, as
+ constructed by WhAjaj.Connector.normalizeAjaxParameters().
+
+ If window.firebug is set then window.firebug.watchXHR() is
+ called to enable monitoring of the XMLHttpRequest object.
+
+ This implementation honors the loginName and loginPassword
+ connection parameters.
+
+ Returns the XMLHttpRequest object.
+
+ This implementation requires that the 'this' object be-a
+ WhAjaj.Connector.
+ */
+ jQuery:function(request,args)
+ {
+ var data = request || undefined;
+ var whself = this;
+ if( data ) {
+ if('string'!==typeof data) {
+ try {
+ data = JSON.stringify(data);
+ }
+ catch(e) {
+ WhAjaj.Connector.sendHelper.onSendError.apply( whself, [request, args] );
+ return;
+ }
+ }
+ }
+ var ajopt = {
+ url: args.url,
+ data: data,
+ type: args.method,
+ async: args.asynchronous,
+ password: (undefined !== args.loginPassword) ? args.loginPassword : undefined,
+ username: (undefined !== args.loginName) ? args.loginName : undefined,
+ contentType: 'application/json; charset=utf-8',
+ error: function(xhr, textStatus, errorThrown)
+ {
+ //this === the options for this ajax request
+ args.errorMessage = "Error sending a '"+ajopt.type+"' request to ["+ajopt.url+"]: "
+ +"Status text=["+textStatus+"]"
+ +(errorThrown ? ("Error=["+errorThrown+"]") : "")
+ ;
+ WhAjaj.Connector.sendHelper.onSendError.apply( whself, [request, args] );
+ },
+ success: function(data)
+ {
+ WhAjaj.Connector.sendHelper.onSendSuccess.apply( whself, [request, data, args] );
+ },
+ /* Set dataType=text instead of json to keep jQuery from doing our carefully
+ written response handling for us.
+ */
+ dataType: 'text'
+ };
+ if( undefined !== args.timeout )
+ {
+ ajopt.timeout = args.timeout;
+ }
+ try
+ {
+ return jQuery.ajax(ajopt);
+ }
+ catch(e)
+ {
+ args.errorMessage = e.toString();
+ WhAjaj.Connector.sendHelper.onSendError.apply( whself, [request, args] );
+ return undefined;
+ }
+ }/*jQuery()*/,
+ /**
+ This is a concrete implementation of
+ WhAjaj.Connector.prototype.sendImpl() which uses the rhino
+ Java API to send requests and fetch the responses.
+
+ Limitations vis-a-vis the interface:
+
+ - timeouts are not supported.
+
+ - asynchronous mode is not supported because implementing it
+ requires the ability to kill a running thread (which is deprecated
+ in the Java API).
+
+ TODOs:
+
+ - add socket timeouts.
+
+ - support HTTP proxy.
+
+ The Java APIs support this, it just hasn't been added here yet.
+ */
+ rhino:function(request,args)
+ {
+ var self = this;
+ var data = request || undefined;
+ if( data ) {
+ if('string'!==typeof data) {
+ try {
+ data = JSON.stringify(data);
+ }
+ catch(e) {
+ WhAjaj.Connector.sendHelper.onSendError.apply( self, [request, args] );
+ return;
+ }
+ }
+ }
+ var url;
+ var con;
+ var IO = new JavaImporter(java.io);
+ var wr;
+ var rd, ln, json = [];
+ function setIncomingCookies(list){
+ if(!list || !list.length) return;
+ if( !self.cookies ) self.cookies = {};
+ var k, v, i;
+ for( i = 0; i < list.length; ++i ){
+ v = list[i].split('=',2);
+ k = decodeURIComponent(v[0])
+ v = v[0] ? decodeURIComponent(v[0].split(';',2)[0]) : null;
+ //print("RECEIVED COOKIE: "+k+"="+v);
+ if(!v) {
+ delete self.cookies[k];
+ continue;
+ }else{
+ self.cookies[k] = v;
+ }
+ }
+ };
+ function setOutboundCookies(conn){
+ if(!self.cookies) return;
+ var k, v;
+ for( k in self.cookies ){
+ if(!self.cookies.hasOwnProperty(k)) continue /*kludge for broken JS libs*/;
+ v = self.cookies[k];
+ conn.addRequestProperty("Cookie", encodeURIComponent(k)+'='+encodeURIComponent(v));
+ //print("SENDING COOKIE: "+k+"="+v);
+ }
+ };
+ try{
+ url = new java.net.URL( args.url )
+ con = url.openConnection(/*FIXME: add proxy support!*/);
+ con.setRequestProperty("Accept-Charset","utf-8");
+ setOutboundCookies(con);
+ if(data){
+ con.setRequestProperty("Content-Type","application/json; charset=utf-8");
+ con.setDoOutput( true );
+ wr = new IO.OutputStreamWriter(con.getOutputStream())
+ wr.write(data);
+ wr.flush();
+ wr.close();
+ wr = null;
+ //print("POSTED: "+data);
+ }
+ rd = new IO.BufferedReader(new IO.InputStreamReader(con.getInputStream()));
+ //var skippedHeaders = false;
+ while ((line = rd.readLine()) !== null) {
+ //print("LINE: "+line);
+ //if(!line.length && !skippedHeaders){
+ // skippedHeaders = true;
+ // json = [];
+ // continue;
+ //}
+ json.push(line);
+ }
+ setIncomingCookies(con.getHeaderFields().get("Set-Cookie"));
+ }catch(e){
+ args.errorMessage = e.toString();
+ WhAjaj.Connector.sendHelper.onSendError.apply( self, [request, args] );
+ return undefined;
+ }
+ try { if(wr) wr.close(); } catch(e) { /*ignore*/}
+ try { if(rd) rd.close(); } catch(e) { /*ignore*/}
+ json = json.join('');
+ //print("READ IN JSON: "+json);
+ WhAjaj.Connector.sendHelper.onSendSuccess.apply( self, [request, json, args] );
+ }/*rhino*/
+};
+
+/**
+ An internal function which takes an object containing properties
+ for a WhAjaj.Connector network request. This function creates a new
+ object containing a superset of the properties from:
+
+ a) opt
+ b) this.options
+ c) WhAjaj.Connector.options.ajax
+
+ in that order, using the first one it finds.
+
+ All non-function properties are _deeply_ copied via JSON cloning
+ in order to prevent accidental "cross-request pollenation" (been
+ there, done that). Functions cannot be cloned and are simply
+ copied by reference.
+
+ This function throws if JSON-copying one of the options fails
+ (e.g. due to cyclic data structures).
+
+ Reminder to self: this function does not "normalize" opt.urlParam
+ by encoding it into opt.url, mainly for historical reasons, but
+ also because that behaviour was specifically undesirable in this
+ code's genetic father.
+*/
+WhAjaj.Connector.prototype.normalizeAjaxParameters = function (opt)
+{
+ var rc = {};
+ function merge(k,v)
+ {
+ if( rc.hasOwnProperty(k) ) return;
+ else if( WhAjaj.isFunction(v) ) {}
+ else if( WhAjaj.isObject(v) ) v = JSON.parse( JSON.stringify(v) );
+ rc[k]=v;
+ }
+ function cp(obj) {
+ if( ! WhAjaj.isObject(obj) ) return;
+ var k;
+ for( k in obj ) {
+ if( ! obj.hasOwnProperty(k) ) continue /* i will always hate the Prototype designers for this. */;
+ merge(k, obj[k]);
+ }
+ }
+ cp( opt );
+ cp( this.options );
+ cp( WhAjaj.Connector.options.ajax );
+ // no, not here: rc.url = WhAjaj.Connector.sendHelper.normalizeURL(rc);
+ return rc;
+};
+
+/**
+ This is the generic interface for making calls to a back-end
+ JSON-producing request handler. It is a simple wrapper around
+ WhAjaj.Connector.prototype.sendImpl(), which just normalizes the
+ connection options for sendImpl() and makes sure that
+ opt.beforeSend() is (possibly) called.
+
+ The request parameter must either be false/null/empty or a
+ fully-populated JSON-able request object (which will be sent as
+ unencoded application/json text), depending on the type of
+ request being made. It is never semantically legal (in this API)
+ for request to be a string/number/true/array value. As a rule,
+ only POST requests use the request data. GET requests should
+ encode their data in opt.url or opt.urlParam (see below).
+
+ opt must contain the network-related parameters for the request.
+ Paramters _not_ set in opt are pulled from this.options or
+ WhAjaj.Connector.options.ajax (in that order, using the first
+ value it finds). Thus the set of connection-level options used
+ for the request are a superset of those various sources.
+
+ The "normalized" (or "superimposed") opt object's URL may be
+ modified before the request is sent, as follows:
+
+ if opt.urlParam is a string then it is assumed to be properly
+ URL-encoded parameters and is appended to the opt.url. If it is
+ an Object then it is assumed to be a one-dimensional set of
+ key/value pairs with simple values (numbers, strings, booleans,
+ null, and NOT objects/arrays). The keys/values are URL-encoded
+ and appended to the URL.
+
+ The beforeSend() callback (see below) can modify the options
+ object before the request attempt is made.
+
+ The callbacks in the normalized opt object will be triggered as
+ follows (if they are set to Function values):
+
+ - beforeSend(request,opt) will be called before any network
+ processing starts. If beforeSend() throws then no other
+ callbacks are triggered and this function propagates the
+ exception. This function is passed normalized connection options
+ as its second parameter, and changes this function makes to that
+ object _will_ be used for the pending connection attempt.
+
+ - onError(request,opt) will be called if a connection to the
+ back-end cannot be established. It will be passed the original
+ request object (which might be null, depending on the request
+ type) and the normalized options object. In the error case, the
+ opt object passed to onError() "should" have a property called
+ "errorMessage" which contains a description of the problem.
+
+ - onError(request,opt) will also be called if connection
+ succeeds but the response is not JSON data.
+
+ - onResponse(response,request) will be called if the response
+ returns JSON data. That data might hold an error response code -
+ clients need to check for that. It is passed the response object
+ (a plain object) and the original request object.
+
+ - afterSend(request,opt) will be called directly after the
+ AJAX request is finished, before onError() or onResonse() are
+ called. Possible TODO: we explicitly do NOT pass the response to
+ this function in order to keep the line between the responsibilities
+ of the various callback clear (otherwise this could be used the same
+ as onResponse()). In practice it would sometimes be useful have the
+ response passed to this function, mainly for logging/debugging
+ purposes.
+
+ The return value from this function is meaningless because
+ AJAX operations tend to take place asynchronously.
+
+*/
+WhAjaj.Connector.prototype.sendRequest = function(request,opt)
+{
+ if( !WhAjaj.isFunction(this.sendImpl) )
+ {
+ throw new Error("This object has no sendImpl() member function! I don't know how to send the request!");
+ }
+ var ex = false;
+ var av = Array.prototype.slice.apply( arguments, [0] );
+
+ /**
+ FIXME: how to handle the error, vis-a-vis- the callbacks, if
+ normalizeAjaxParameters() throws? It can throw if
+ (de)JSON-izing fails.
+ */
+ var norm = this.normalizeAjaxParameters( WhAjaj.isObject(opt) ? opt : {} );
+ norm.url = WhAjaj.Connector.sendHelper.normalizeURL(norm);
+ if( ! request ) norm.method = 'GET';
+ var cb = this.callbacks || {};
+ if( this.callbacks && WhAjaj.isFunction(this.callbacks.beforeSend) ) {
+ this.callbacks.beforeSend( request, norm );
+ }
+ if( WhAjaj.isFunction(norm.beforeSend) ){
+ norm.beforeSend( request, norm );
+ }
+ //alert( WhAjaj.stringify(request)+'\n'+WhAjaj.stringify(norm));
+ try { this.sendImpl( request, norm ); }
+ catch(e) { ex = e; }
+ if(ex) throw ex;
+};
+
+/**
+ sendImpl() holds a concrete back-end connection implementation. It
+ can be replaced with a custom implementation if one follows the rules
+ described throughout this API. See WhAjaj.Connector.sendImpls for
+ the concrete implementations included with this API.
+*/
+//WhAjaj.Connector.prototype.sendImpl = WhAjaj.Connector.sendImpls.XMLHttpRequest;
+//WhAjaj.Connector.prototype.sendImpl = WhAjaj.Connector.sendImpls.rhino;
+//WhAjaj.Connector.prototype.sendImpl = WhAjaj.Connector.sendImpls.jQuery;
+
+if( 'undefined' !== typeof jQuery ){
+ WhAjaj.Connector.prototype.sendImpl = WhAjaj.Connector.sendImpls.jQuery;
+}
+else {
+ WhAjaj.Connector.prototype.sendImpl = WhAjaj.Connector.sendImpls.XMLHttpRequest;
+}
ADDED ajax/wiki-editor.html
Index: ajax/wiki-editor.html
==================================================================
--- ajax/wiki-editor.html
+++ ajax/wiki-editor.html
@@ -0,0 +1,382 @@
+
+
+
+
+ Fossil/JSON Wiki Editor Prototype
+
+
+
+
+
+
+
+
+
+
+
+
+
+PROTOTYPE JSON-based Fossil Wiki Editor
+
+See also: main test page .
+
+
+Login:
+
+
+or:
+name:
+pw:
+
+
+
+
+
+
+
+Quick-posts:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
ADDED auto.def
Index: auto.def
==================================================================
--- auto.def
+++ auto.def
@@ -0,0 +1,239 @@
+# System autoconfiguration. Try: ./configure --help
+
+use cc cc-lib
+
+options {
+ with-openssl:path|auto|none
+ => {Look for openssl in the given path, or auto or none}
+ with-zlib:path => {Look for zlib in the given path}
+ with-tcl:path => {Enable Tcl integration, with Tcl in the specified path}
+ with-tcl-stubs=0 => {Enable Tcl integration via stubs mechanism}
+ internal-sqlite=1 => {Don't use the internal sqlite, use the system one}
+ static=0 => {Link a static executable}
+ lineedit=1 => {Disable line editing}
+ fossil-debug=0 => {Build with fossil debugging enabled}
+ json=0 => {Build with fossil JSON API enabled}
+}
+
+# sqlite wants these types if possible
+cc-with {-includes {stdint.h inttypes.h}} {
+ cc-check-types uint32_t uint16_t int16_t uint8_t
+}
+
+# Use pread/pwrite system calls in place of seek + read/write if possible
+define USE_PREAD [cc-check-functions pread]
+
+# Find tclsh for the test suite. Can't yet use jimsh for this.
+cc-check-progs tclsh
+
+define EXTRA_CFLAGS ""
+define EXTRA_LDFLAGS ""
+define USE_SYSTEM_SQLITE ""
+
+if {![opt-bool internal-sqlite]} {
+ proc find_internal_sqlite {} {
+
+ # On some systems (slackware), libsqlite3 requires -ldl to link. So
+ # search for the system SQLite once with -ldl, and once without. If
+ # the library can only be found with $extralibs set to -ldl, then
+ # the code below will append -ldl to LIBS.
+ #
+ foreach extralibs {{} {-ldl}} {
+
+ # Locate the system SQLite by searching for sqlite3_open(). Then check
+ # if sqlite3_wal_checkpoint() can be found as well. If we can find
+ # open() but not wal_checkpoint(), then the system SQLite is too old
+ # to link against fossil.
+ #
+ if {[cc-check-function-in-lib sqlite3_open sqlite3 $extralibs]} {
+ if {![cc-check-function-in-lib sqlite3_wal_checkpoint sqlite3 $extralibs]} {
+ user-error "system sqlite3 too old (require >= 3.7.0)"
+ }
+
+ # Success. Update symbols and return.
+ #
+ define USE_SYSTEM_SQLITE 1
+ define-append LIBS $extralibs
+ return
+ }
+ }
+ user-error "system sqlite3 not found"
+ }
+
+ find_internal_sqlite
+}
+
+if {[opt-bool fossil-debug]} {
+ define-append EXTRA_CFLAGS -DFOSSIL_DEBUG
+}
+
+if {[opt-bool json]} {
+ # Reminder/FIXME (stephan): FOSSIL_ENABLE_JSON
+ # is required in the CFLAGS because json*.c
+ # have #ifdef guards around the whole file without
+ # reading config.h first.
+ define-append EXTRA_CFLAGS -DFOSSIL_ENABLE_JSON
+ define FOSSIL_ENABLE_JSON
+}
+
+#if {[opt-bool markdown]} {
+# # no-op. Markdown is now enabled by default.
+#}
+
+if {[opt-bool static]} {
+ # XXX: This will not work on all systems.
+ define-append EXTRA_LDFLAGS -static
+}
+
+# Check for zlib, using the given location if specified
+set zlibpath [opt-val with-zlib]
+if {$zlibpath ne ""} {
+ cc-with [list -cflags "-I$zlibpath -L$zlibpath"]
+ define-append EXTRA_CFLAGS -I$zlibpath
+ define-append EXTRA_LDFLAGS -L$zlibpath
+}
+if {![cc-check-includes zlib.h] || ![cc-check-function-in-lib inflateEnd z]} {
+ user-error "zlib not found please install it or specify the location with --with-zlib"
+}
+
+set tclpath [opt-val with-tcl]
+if {$tclpath ne ""} {
+ # Note parse-tclconfig-sh is in autosetup/local.tcl
+ if {$tclpath eq "1"} {
+ # Use the system Tcl. Look in some likely places.
+ array set tclconfig [parse-tclconfig-sh \
+ /usr /usr/local /usr/share /opt/local]
+ set msg "on your system"
+ } else {
+ array set tclconfig [parse-tclconfig-sh $tclpath]
+ set msg "at $tclpath"
+ }
+ if {![info exists tclconfig(TCL_INCLUDE_SPEC)]} {
+ user-error "Cannot find Tcl $msg"
+ }
+ set tclstubs [opt-bool with-tcl-stubs]
+ if {$tclstubs && $tclconfig(TCL_SUPPORTS_STUBS)} {
+ set libs "$tclconfig(TCL_STUB_LIB_SPEC)"
+ define FOSSIL_ENABLE_TCL_STUBS
+ define USE_TCL_STUBS
+ } else {
+ set libs "$tclconfig(TCL_LIB_SPEC) $tclconfig(TCL_LIBS)"
+ }
+ set cflags $tclconfig(TCL_INCLUDE_SPEC)
+ cc-with [list -cflags $cflags -libs $libs] {
+ if {$tclstubs} {
+ if {![cc-check-functions Tcl_InitStubs]} {
+ user-error "Cannot find a usable Tcl stubs library $msg"
+ }
+ } else {
+ if {![cc-check-functions Tcl_CreateInterp]} {
+ user-error "Cannot find a usable Tcl library $msg"
+ }
+ }
+ }
+ set version $tclconfig(TCL_VERSION)$tclconfig(TCL_PATCH_LEVEL)
+ msg-result "Found Tcl $version at $tclconfig(TCL_PREFIX)"
+ define-append LIBS $libs
+ define-append EXTRA_CFLAGS $cflags
+ define-append EXTRA_LDFLAGS $tclconfig(TCL_LD_FLAGS)
+ define FOSSIL_ENABLE_TCL
+}
+
+# Helper for openssl checking
+proc check-for-openssl {msg {cflags {}}} {
+ msg-checking "Checking for $msg..."
+ set rc 0
+ msg-quiet cc-with [list -cflags $cflags -libs {-lssl -lcrypto}] {
+ if {[cc-check-includes openssl/ssl.h] && [cc-check-functions SSL_new]} {
+ incr rc
+ }
+ }
+ if {$rc} {
+ msg-result "ok"
+ return 1
+ } else {
+ msg-result "no"
+ return 0
+ }
+}
+
+set ssldirs [opt-val with-openssl]
+if {$ssldirs ne "none"} {
+ set found 0
+ if {$ssldirs in {auto ""}} {
+ catch {
+ set cflags [exec pkg-config openssl --cflags-only-I]
+ set ldflags [exec pkg-config openssl --libs-only-L]
+
+ set found [check-for-openssl "ssl via pkg-config" "$cflags $ldflags"]
+ } msg
+ if {!$found} {
+ set ssldirs "{} /usr/sfw /usr/local/ssl /usr/lib/ssl /usr/ssl /usr/pkg /usr/local /usr"
+ }
+ }
+ if {!$found} {
+ foreach dir $ssldirs {
+ if {$dir eq ""} {
+ set msg "system ssl"
+ set cflags ""
+ set ldflags ""
+ } else {
+ set msg "ssl in $dir"
+ set cflags "-I$dir/include"
+ set ldflags "-L$dir/lib"
+ }
+ if {[check-for-openssl $msg "$cflags $ldflags"]} {
+ incr found
+ break
+ }
+ }
+ }
+ if {$found} {
+ define FOSSIL_ENABLE_SSL
+ define-append EXTRA_CFLAGS $cflags
+ define-append EXTRA_LDFLAGS $ldflags
+ define-append LIBS -lssl -lcrypto
+ msg-result "HTTPS support enabled"
+
+ # Silence OpenSSL deprecation warnings on Mac OS X 10.7.
+ if {[string match *-darwin* [get-define host]]} {
+ if {[cctest -cflags {-Wdeprecated-declarations}]} {
+ define-append EXTRA_CFLAGS -Wdeprecated-declarations
+ }
+ }
+ } else {
+ user-error "OpenSSL not found. Consider --with-openssl=none to disable HTTPS support"
+ }
+}
+
+if {[opt-bool lineedit]} {
+ # Need readline-compatible line editing
+ cc-with {-includes stdio.h} {
+ if {[cc-check-includes readline/readline.h] && [cc-check-function-in-lib readline readline]} {
+ msg-result "Using readline for line editing"
+ } elseif {[cc-check-includes editline/readline.h] && [cc-check-function-in-lib readline edit]} {
+ define-feature editline
+ msg-result "Using editline for line editing"
+ }
+ }
+}
+
+# Network functions require libraries on some systems
+cc-check-function-in-lib gethostbyname nsl
+if {![cc-check-function-in-lib socket {socket network}]} {
+ # Last resort, may be Windows
+ if {[string match *mingw* [get-define host]]} {
+ define-append LIBS -lwsock32
+ }
+}
+cc-check-function-in-lib iconv iconv
+
+# Check for getpassphrase() for Solaris 10 where getpass() truncates to 10 chars
+if {![cc-check-functions getpassphrase]} {
+ # Haiku needs this
+ cc-check-function-in-lib getpass bsd
+}
+cc-check-function-in-lib dlopen dl
+
+make-template Makefile.in
+make-config-header autoconfig.h -auto {USE_* FOSSIL_*}
ADDED autosetup/LICENSE
Index: autosetup/LICENSE
==================================================================
--- autosetup/LICENSE
+++ autosetup/LICENSE
@@ -0,0 +1,35 @@
+Unless explicitly stated, all files which form part of autosetup
+are released under the following license:
+
+---------------------------------------------------------------------
+autosetup - A build environment "autoconfigurator"
+
+Copyright (c) 2010-2011, WorkWare Systems
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials
+ provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE WORKWARE SYSTEMS ``AS IS'' AND ANY
+EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WORKWARE
+SYSTEMS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+The views and conclusions contained in the software and documentation
+are those of the authors and should not be interpreted as representing
+official policies, either expressed or implied, of WorkWare Systems.
ADDED autosetup/README.autosetup
Index: autosetup/README.autosetup
==================================================================
--- autosetup/README.autosetup
+++ autosetup/README.autosetup
@@ -0,0 +1,1 @@
+This is autosetup v0.6.5. See http://msteveb.github.com/autosetup/
ADDED autosetup/autosetup
Index: autosetup/autosetup
==================================================================
--- autosetup/autosetup
+++ autosetup/autosetup
@@ -0,0 +1,1898 @@
+#!/bin/sh
+# Copyright (c) 2006-2011 WorkWare Systems http://www.workware.net.au/
+# All rights reserved
+# vim:se syntax=tcl:
+# \
+dir=`dirname "$0"`; exec "`$dir/find-tclsh`" "$0" "$@"
+
+set autosetup(version) 0.6.5
+
+# Can be set to 1 to debug early-init problems
+set autosetup(debug) 0
+
+##################################################################
+#
+# Main flow of control, option handling
+#
+proc main {argv} {
+ global autosetup define
+
+ # There are 3 potential directories involved:
+ # 1. The directory containing autosetup (this script)
+ # 2. The directory containing auto.def
+ # 3. The current directory
+
+ # From this we need to determine:
+ # a. The path to this script (and related support files)
+ # b. The path to auto.def
+ # c. The build directory, where output files are created
+
+ # This is also complicated by the fact that autosetup may
+ # have been run via the configure wrapper ([getenv WRAPPER] is set)
+
+ # Here are the rules.
+ # a. This script is $::argv0
+ # => dir, prog, exe, libdir
+ # b. auto.def is in the directory containing the configure wrapper,
+ # otherwise it is in the current directory.
+ # => srcdir, autodef
+ # c. The build directory is the current directory
+ # => builddir, [pwd]
+
+ # 'misc' is needed before we can do anything, so set a temporary libdir
+ # in case this is the development version
+ set autosetup(libdir) [file dirname $::argv0]/lib
+ use misc
+
+ # (a)
+ set autosetup(dir) [realdir [file dirname [realpath $::argv0]]]
+ set autosetup(prog) [file join $autosetup(dir) [file tail $::argv0]]
+ set autosetup(exe) [getenv WRAPPER $autosetup(prog)]
+ if {$autosetup(installed)} {
+ set autosetup(libdir) $autosetup(dir)
+ } else {
+ set autosetup(libdir) [file join $autosetup(dir) lib]
+ }
+ autosetup_add_dep $autosetup(prog)
+
+ # (b)
+ if {[getenv WRAPPER ""] eq ""} {
+ # Invoked directly
+ set autosetup(srcdir) [pwd]
+ } else {
+ # Invoked via the configure wrapper
+ set autosetup(srcdir) [file dirname $autosetup(exe)]
+ }
+ set autosetup(autodef) [relative-path $autosetup(srcdir)/auto.def]
+
+ # (c)
+ set autosetup(builddir) [pwd]
+
+ set autosetup(argv) $argv
+ set autosetup(cmdline) {}
+ set autosetup(options) {}
+ set autosetup(optionhelp) {}
+ set autosetup(showhelp) 0
+
+ # Parse options
+ use getopt
+
+ array set ::useropts [getopt argv]
+
+ #"=Core Options:"
+ options-add {
+ help:=local => "display help and options. Optionally specify a module name, such as --help=system"
+ version => "display the version of autosetup"
+ ref:=text manual:=text
+ reference:=text => "display the autosetup command reference. 'text', 'wiki', 'asciidoc' or 'markdown'"
+ debug => "display debugging output as autosetup runs"
+ install:=. => "install autosetup to the current or given directory (in the 'autosetup/' subdirectory)"
+ force init:=help => "create initial auto.def, etc. Use --init=help for known types"
+ # Undocumented options
+ option-checking=1
+ nopager
+ quiet
+ timing
+ conf:
+ }
+
+ #parray ::useropts
+ if {[opt-bool version]} {
+ puts $autosetup(version)
+ exit 0
+ }
+
+ # autosetup --conf=alternate-auto.def
+ if {[opt-val conf] ne ""} {
+ set autosetup(autodef) [opt-val conf]
+ }
+
+ # Debugging output (set this early)
+ incr autosetup(debug) [opt-bool debug]
+ incr autosetup(force) [opt-bool force]
+ incr autosetup(msg-quiet) [opt-bool quiet]
+ incr autosetup(msg-timing) [opt-bool timing]
+
+ # If the local module exists, source it now to allow for
+ # project-local customisations
+ if {[file exists $autosetup(libdir)/local.tcl]} {
+ use local
+ }
+
+ # Now any auto-load modules
+ foreach file [glob -nocomplain $autosetup(libdir)/*.auto $autosetup(libdir)/*/*.auto] {
+ automf_load source $file
+ }
+
+ if {[opt-val help] ne ""} {
+ incr autosetup(showhelp)
+ use help
+ autosetup_help [opt-val help]
+ }
+
+ if {[opt-val {manual ref reference}] ne ""} {
+ use help
+ autosetup_reference [opt-val {manual ref reference}]
+ }
+
+ if {[opt-val init] ne ""} {
+ use init
+ autosetup_init [opt-val init]
+ }
+
+ if {[opt-val install] ne ""} {
+ use install
+ autosetup_install [opt-val install]
+ }
+
+ if {![file exists $autosetup(autodef)]} {
+ # Check for invalid option first
+ options {}
+ user-error "No auto.def found in \"$autosetup(srcdir)\" (use [file tail $::autosetup(exe)] --init to create one)"
+ }
+
+ # Parse extra arguments into autosetup(cmdline)
+ foreach arg $argv {
+ if {[regexp {([^=]*)=(.*)} $arg -> n v]} {
+ dict set autosetup(cmdline) $n $v
+ define $n $v
+ } else {
+ user-error "Unexpected parameter: $arg"
+ }
+ }
+
+ autosetup_add_dep $autosetup(autodef)
+
+ set cmd [file-normalize $autosetup(exe)]
+ foreach arg $autosetup(argv) {
+ append cmd " [quote-if-needed $arg]"
+ }
+ define AUTOREMAKE $cmd
+
+ # Log how we were invoked
+ configlog "Invoked as: [getenv WRAPPER $::argv0] [quote-argv $autosetup(argv)]"
+
+ # Note that auto.def is *not* loaded in the global scope
+ source $autosetup(autodef)
+
+ # Could warn here if options {} was not specified
+
+ show-notices
+
+ if {$autosetup(debug)} {
+ msg-result "Writing all defines to config.log"
+ configlog "================ defines ======================"
+ foreach n [lsort [array names define]] {
+ configlog "define $n $define($n)"
+ }
+ }
+
+ exit 0
+}
+
+# @opt-bool option ...
+#
+# Check each of the named, boolean options and return 1 if any of them have
+# been set by the user.
+#
+proc opt-bool {args} {
+ option-check-names {*}$args
+ opt_bool ::useropts {*}$args
+}
+
+# @opt-val option-list ?default=""?
+#
+# Returns a list containing all the values given for the non-boolean options in 'option-list'.
+# There will be one entry in the list for each option given by the user, including if the
+# same option was used multiple times.
+# If only a single value is required, use something like:
+#
+## lindex [opt-val $names] end
+#
+# If no options were set, $default is returned (exactly, not as a list).
+#
+proc opt-val {names {default ""}} {
+ option-check-names {*}$names
+ join [opt_val ::useropts $names $default]
+}
+
+proc option-check-names {args} {
+ foreach o $args {
+ if {$o ni $::autosetup(options)} {
+ autosetup-error "Request for undeclared option --$o"
+ }
+ }
+}
+
+# Parse the option definition in $opts and update
+# ::useropts() and ::autosetup(optionhelp) appropriately
+#
+proc options-add {opts {header ""}} {
+ global useropts autosetup
+
+ # First weed out comment lines
+ set realopts {}
+ foreach line [split $opts \n] {
+ if {![string match "#*" [string trimleft $line]]} {
+ append realopts $line \n
+ }
+ }
+ set opts $realopts
+
+ for {set i 0} {$i < [llength $opts]} {incr i} {
+ set opt [lindex $opts $i]
+ if {[string match =* $opt]} {
+ # This is a special heading
+ lappend autosetup(optionhelp) $opt ""
+ set header {}
+ continue
+ }
+
+ #puts "i=$i, opt=$opt"
+ regexp {^([^:=]*)(:)?(=)?(.*)$} $opt -> name colon equal value
+ if {$name in $autosetup(options)} {
+ autosetup-error "Option $name already specified"
+ }
+
+ #puts "$opt => $name $colon $equal $value"
+
+ # Find the corresponding value in the user options
+ # and set the default if necessary
+ if {[string match "-*" $opt]} {
+ # This is a documentation-only option, like "-C "
+ set opthelp $opt
+ } elseif {$colon eq ""} {
+ # Boolean option
+ lappend autosetup(options) $name
+
+ if {![info exists useropts($name)]} {
+ set useropts($name) $value
+ }
+ if {$value eq "1"} {
+ set opthelp "--disable-$name"
+ } else {
+ set opthelp "--$name"
+ }
+ } else {
+ # String option.
+ lappend autosetup(options) $name
+
+ if {$equal eq "="} {
+ if {[info exists useropts($name)]} {
+ # If the user specified the option with no value, the value will be "1"
+ # Replace with the default
+ if {$useropts($name) eq "1"} {
+ set useropts($name) $value
+ }
+ }
+ set opthelp "--$name?=$value?"
+ } else {
+ set opthelp "--$name=$value"
+ }
+ }
+
+ # Now create the help for this option if appropriate
+ if {[lindex $opts $i+1] eq "=>"} {
+ set desc [lindex $opts $i+2]
+ #string match \n* $desc
+ if {$header ne ""} {
+ lappend autosetup(optionhelp) $header ""
+ set header ""
+ }
+ # A multi-line description
+ lappend autosetup(optionhelp) $opthelp $desc
+ incr i 2
+ }
+ }
+}
+
+# @module-options optionlist
+#
+# Like 'options', but used within a module.
+proc module-options {opts} {
+ set header ""
+ if {$::autosetup(showhelp) > 1 && [llength $opts]} {
+ set header "Module Options:"
+ }
+ options-add $opts $header
+
+ if {$::autosetup(showhelp)} {
+ # Ensure that the module isn't executed on --help
+ # We are running under eval or source, so use break
+ # to prevent further execution
+ #return -code break -level 2
+ return -code break
+ }
+}
+
+proc max {a b} {
+ expr {$a > $b ? $a : $b}
+}
+
+proc options-wrap-desc {text length firstprefix nextprefix initial} {
+ set len $initial
+ set space $firstprefix
+ foreach word [split $text] {
+ set word [string trim $word]
+ if {$word == ""} {
+ continue
+ }
+ if {$len && [string length $space$word] + $len >= $length} {
+ puts ""
+ set len 0
+ set space $nextprefix
+ }
+ incr len [string length $space$word]
+ puts -nonewline $space$word
+ set space " "
+ }
+ if {$len} {
+ puts ""
+ }
+}
+
+proc options-show {} {
+ # Determine the max option width
+ set max 0
+ foreach {opt desc} $::autosetup(optionhelp) {
+ if {[string match =* $opt] || [string match \n* $desc]} {
+ continue
+ }
+ set max [max $max [string length $opt]]
+ }
+ set indent [string repeat " " [expr $max+4]]
+ set cols [getenv COLUMNS 80]
+ catch {
+ lassign [exec stty size] rows cols
+ }
+ incr cols -1
+ # Now output
+ foreach {opt desc} $::autosetup(optionhelp) {
+ if {[string match =* $opt]} {
+ puts [string range $opt 1 end]
+ continue
+ }
+ puts -nonewline " [format %-${max}s $opt]"
+ if {[string match \n* $desc]} {
+ puts $desc
+ } else {
+ options-wrap-desc [string trim $desc] $cols " " $indent [expr $max + 2]
+ }
+ }
+}
+
+# @options options-spec
+#
+# Specifies configuration-time options which may be selected by the user
+# and checked with opt-val and opt-bool. The format of options-spec follows.
+#
+# A boolean option is of the form:
+#
+## name[=0|1] => "Description of this boolean option"
+#
+# The default is name=0, meaning that the option is disabled by default.
+# If name=1 is used to make the option enabled by default, the description should reflect
+# that with text like "Disable support for ...".
+#
+# An argument option (one which takes a parameter) is of the form:
+#
+## name:[=]value => "Description of this option"
+#
+# If the name:value form is used, the value must be provided with the option (as --name=myvalue).
+# If the name:=value form is used, the value is optional and the given value is used as the default
+# if is not provided.
+#
+# Undocumented options are also supported by omitting the "=> description.
+# These options are not displayed with --help and can be useful for internal options or as aliases.
+#
+# For example, --disable-lfs is an alias for --disable=largefile:
+#
+## lfs=1 largefile=1 => "Disable large file support"
+#
+proc options {optlist} {
+ # Allow options as a list or args
+ options-add $optlist "Local Options:"
+
+ if {$::autosetup(showhelp)} {
+ options-show
+ exit 0
+ }
+
+ # Check for invalid options
+ if {[opt-bool option-checking]} {
+ foreach o [array names ::useropts] {
+ if {$o ni $::autosetup(options)} {
+ user-error "Unknown option --$o"
+ }
+ }
+ }
+}
+
+proc config_guess {} {
+ if {[file-isexec $::autosetup(dir)/config.guess]} {
+ exec-with-stderr sh $::autosetup(dir)/config.guess
+ if {[catch {exec-with-stderr sh $::autosetup(dir)/config.guess} alias]} {
+ user-error $alias
+ }
+ return $alias
+ } else {
+ configlog "No config.guess, so using uname"
+ string tolower [exec uname -p]-unknown-[exec uname -s][exec uname -r]
+ }
+}
+
+proc config_sub {alias} {
+ if {[file-isexec $::autosetup(dir)/config.sub]} {
+ if {[catch {exec-with-stderr sh $::autosetup(dir)/config.sub $alias} alias]} {
+ user-error $alias
+ }
+ }
+ return $alias
+}
+
+# @define name ?value=1?
+#
+# Defines the named variable to the given value.
+# These (name, value) pairs represent the results of the configuration check
+# and are available to be checked, modified and substituted.
+#
+proc define {name {value 1}} {
+ set ::define($name) $value
+ #dputs "$name <= $value"
+}
+
+# @define-append name value ...
+#
+# Appends the given value(s) to the given 'defined' variable.
+# If the variable is not defined or empty, it is set to $value.
+# Otherwise the value is appended, separated by a space.
+# Any extra values are similarly appended.
+# If any value is already contained in the variable (as a substring) it is omitted.
+#
+proc define-append {name args} {
+ if {[get-define $name ""] ne ""} {
+ # Make a token attempt to avoid duplicates
+ foreach arg $args {
+ if {[string first $arg $::define($name)] == -1} {
+ append ::define($name) " " $arg
+ }
+ }
+ } else {
+ set ::define($name) [join $args]
+ }
+ #dputs "$name += [join $args] => $::define($name)"
+}
+
+# @get-define name ?default=0?
+#
+# Returns the current value of the 'defined' variable, or $default
+# if not set.
+#
+proc get-define {name {default 0}} {
+ if {[info exists ::define($name)]} {
+ #dputs "$name => $::define($name)"
+ return $::define($name)
+ }
+ #dputs "$name => $default"
+ return $default
+}
+
+# @is-defined name
+#
+# Returns 1 if the given variable is defined.
+#
+proc is-defined {name} {
+ info exists ::define($name)
+}
+
+# @all-defines
+#
+# Returns a dictionary (name value list) of all defined variables.
+#
+# This is suitable for use with 'dict', 'array set' or 'foreach'
+# and allows for arbitrary processing of the defined variables.
+#
+proc all-defines {} {
+ array get ::define
+}
+
+
+# @get-env name default
+#
+# If $name was specified on the command line, return it.
+# If $name was set in the environment, return it.
+# Otherwise return $default.
+#
+proc get-env {name default} {
+ if {[dict exists $::autosetup(cmdline) $name]} {
+ return [dict get $::autosetup(cmdline) $name]
+ }
+ getenv $name $default
+}
+
+# @env-is-set name
+#
+# Returns 1 if the $name was specified on the command line or in the environment.
+# Note that an empty environment variable is not considered to be set.
+#
+proc env-is-set {name} {
+ if {[dict exists $::autosetup(cmdline) $name]} {
+ return 1
+ }
+ if {[getenv $name ""] ne ""} {
+ return 1
+ }
+ return 0
+}
+
+# @readfile filename ?default=""?
+#
+# Return the contents of the file, without the trailing newline.
+# If the doesn't exist or can't be read, returns $default.
+#
+proc readfile {filename {default_value ""}} {
+ set result $default_value
+ catch {
+ set f [open $filename]
+ set result [read -nonewline $f]
+ close $f
+ }
+ return $result
+}
+
+# @writefile filename value
+#
+# Creates the given file containing $value.
+# Does not add an extra newline.
+#
+proc writefile {filename value} {
+ set f [open $filename w]
+ puts -nonewline $f $value
+ close $f
+}
+
+proc quote-if-needed {str} {
+ if {[string match {*[\" ]*} $str]} {
+ return \"[string map [list \" \\" \\ \\\\] $str]\"
+ }
+ return $str
+}
+
+proc quote-argv {argv} {
+ set args {}
+ foreach arg $argv {
+ lappend args [quote-if-needed $arg]
+ }
+ join $args
+}
+
+# @suffix suf list
+#
+# Takes a list and returns a new list with $suf appended
+# to each element
+#
+## suffix .c {a b c} => {a.c b.c c.c}
+#
+proc suffix {suf list} {
+ set result {}
+ foreach p $list {
+ lappend result $p$suf
+ }
+ return $result
+}
+
+# @prefix pre list
+#
+# Takes a list and returns a new list with $pre prepended
+# to each element
+#
+## prefix jim- {a.c b.c} => {jim-a.c jim-b.c}
+#
+proc prefix {pre list} {
+ set result {}
+ foreach p $list {
+ lappend result $pre$p
+ }
+ return $result
+}
+
+# @find-executable name
+#
+# Searches the path for an executable with the given name.
+# Note that the name may include some parameters, e.g. "cc -mbig-endian",
+# in which case the parameters are ignored.
+# Returns 1 if found, or 0 if not.
+#
+proc find-executable {name} {
+ # Ignore any parameters
+ set name [lindex $name 0]
+ if {$name eq ""} {
+ # The empty string is never a valid executable
+ return 0
+ }
+ foreach p [split-path] {
+ dputs "Looking for $name in $p"
+ set exec [file join $p $name]
+ if {[file-isexec $exec]} {
+ dputs "Found $name -> $exec"
+ return 1
+ }
+ }
+ return 0
+}
+
+# @find-an-executable ?-required? name ...
+#
+# Given a list of possible executable names,
+# searches for one of these on the path.
+#
+# Returns the name found, or "" if none found.
+# If the first parameter is '-required', an error is generated
+# if no executable is found.
+#
+proc find-an-executable {args} {
+ set required 0
+ if {[lindex $args 0] eq "-required"} {
+ set args [lrange $args 1 end]
+ incr required
+ }
+ foreach name $args {
+ if {[find-executable $name]} {
+ return $name
+ }
+ }
+ if {$required} {
+ if {[llength $args] == 1} {
+ user-error "failed to find: [join $args]"
+ } else {
+ user-error "failed to find one of: [join $args]"
+ }
+ }
+ return ""
+}
+
+# @configlog msg
+#
+# Writes the given message to the configuration log, config.log
+#
+proc configlog {msg} {
+ if {![info exists ::autosetup(logfh)]} {
+ set ::autosetup(logfh) [open config.log w]
+ }
+ puts $::autosetup(logfh) $msg
+}
+
+# @msg-checking msg
+#
+# Writes the message with no newline to stdout.
+#
+proc msg-checking {msg} {
+ if {$::autosetup(msg-quiet) == 0} {
+ maybe-show-timestamp
+ puts -nonewline $msg
+ set ::autosetup(msg-checking) 1
+ }
+}
+
+# @msg-result msg
+#
+# Writes the message to stdout.
+#
+proc msg-result {msg} {
+ if {$::autosetup(msg-quiet) == 0} {
+ maybe-show-timestamp
+ puts $msg
+ set ::autosetup(msg-checking) 0
+ show-notices
+ }
+}
+
+# @msg-quiet command ...
+#
+# msg-quiet evaluates it's arguments as a command with output
+# from msg-checking and msg-result suppressed.
+#
+# This is useful if a check needs to run a subcheck which isn't
+# of interest to the user.
+proc msg-quiet {args} {
+ incr ::autosetup(msg-quiet)
+ set rc [uplevel 1 $args]
+ incr ::autosetup(msg-quiet) -1
+ return $rc
+}
+
+# Will be overridden by 'use misc'
+proc error-stacktrace {msg} {
+ return $msg
+}
+
+proc error-location {msg} {
+ return $msg
+}
+
+##################################################################
+#
+# Debugging output
+#
+proc dputs {msg} {
+ if {$::autosetup(debug)} {
+ puts $msg
+ }
+}
+
+##################################################################
+#
+# User and system warnings and errors
+#
+# Usage errors such as wrong command line options
+
+# @user-error msg
+#
+# Indicate incorrect usage to the user, including if required components
+# or features are not found.
+# autosetup exits with a non-zero return code.
+#
+proc user-error {msg} {
+ show-notices
+ puts stderr "Error: $msg"
+ puts stderr "Try: '[file tail $::autosetup(exe)] --help' for options"
+ exit 1
+}
+
+# @user-notice msg
+#
+# Output the given message to stderr.
+#
+proc user-notice {msg} {
+ lappend ::autosetup(notices) $msg
+}
+
+# Incorrect usage in the auto.def file. Identify the location.
+proc autosetup-error {msg} {
+ autosetup-full-error [error-location $msg]
+}
+
+# Like autosetup-error, except $msg is the full error message.
+proc autosetup-full-error {msg} {
+ show-notices
+ puts stderr $msg
+ exit 1
+}
+
+proc show-notices {} {
+ if {$::autosetup(msg-checking)} {
+ puts ""
+ set ::autosetup(msg-checking) 0
+ }
+ flush stdout
+ if {[info exists ::autosetup(notices)]} {
+ puts stderr [join $::autosetup(notices) \n]
+ unset ::autosetup(notices)
+ }
+}
+
+proc maybe-show-timestamp {} {
+ if {$::autosetup(msg-timing) && $::autosetup(msg-checking) == 0} {
+ puts -nonewline [format {[%6.2f] } [expr {([clock millis] - $::autosetup(start)) % 10000 / 1000.0}]]
+ }
+}
+
+proc autosetup_version {} {
+ return "autosetup v$::autosetup(version)"
+}
+
+##################################################################
+#
+# Directory/path handling
+#
+
+proc realdir {dir} {
+ set oldpwd [pwd]
+ cd $dir
+ set pwd [pwd]
+ cd $oldpwd
+ return $pwd
+}
+
+# Follow symlinks until we get to something which is not a symlink
+proc realpath {path} {
+ while {1} {
+ if {[catch {
+ set path [file link $path]
+ }]} {
+ # Not a link
+ break
+ }
+ }
+ return $path
+}
+
+# Convert absolute path, $path into a path relative
+# to the given directory (or the current dir, if not given).
+#
+proc relative-path {path {pwd {}}} {
+ set diff 0
+ set same 0
+ set newf {}
+ set prefix {}
+ set path [file-normalize $path]
+ if {$pwd eq ""} {
+ set pwd [pwd]
+ } else {
+ set pwd [file-normalize $pwd]
+ }
+
+ if {$path eq $pwd} {
+ return .
+ }
+
+ # Try to make the filename relative to the current dir
+ foreach p [split $pwd /] f [split $path /] {
+ if {$p ne $f} {
+ incr diff
+ } elseif {!$diff} {
+ incr same
+ }
+ if {$diff} {
+ if {$p ne ""} {
+ # Add .. for sibling or parent dir
+ lappend prefix ..
+ }
+ if {$f ne ""} {
+ lappend newf $f
+ }
+ }
+ }
+ if {$same == 1 || [llength $prefix] > 3} {
+ return $path
+ }
+
+ file join [join $prefix /] [join $newf /]
+}
+
+# Add filename as a dependency to rerun autosetup
+# The name will be normalised (converted to a full path)
+#
+proc autosetup_add_dep {filename} {
+ lappend ::autosetup(deps) [file-normalize $filename]
+}
+
+##################################################################
+#
+# Library module support
+#
+
+# @use module ...
+#
+# Load the given library modules.
+# e.g. 'use cc cc-shared'
+#
+# Note that module 'X' is implemented in either 'autosetup/X.tcl'
+# or 'autosetup/X/init.tcl'
+#
+# The latter form is useful for a complex module which requires additional
+# support file. In this form, '$::usedir' is set to the module directory
+# when it is loaded.
+#
+proc use {args} {
+ foreach m $args {
+ if {[info exists ::libmodule($m)]} {
+ continue
+ }
+ set ::libmodule($m) 1
+ if {[info exists ::modsource($m)]} {
+ automf_load eval $::modsource($m)
+ } else {
+ set sources [list $::autosetup(libdir)/${m}.tcl $::autosetup(libdir)/${m}/init.tcl]
+ set found 0
+ foreach source $sources {
+ if {[file exists $source]} {
+ incr found
+ break
+ }
+ }
+ if {$found} {
+ # For the convenience of the "use" source, point to the directory
+ # it is being loaded from
+ set ::usedir [file dirname $source]
+ automf_load source $source
+ autosetup_add_dep $source
+ } else {
+ autosetup-error "use: No such module: $m"
+ }
+ }
+ }
+}
+
+# Load module source in the global scope by executing the given command
+proc automf_load {args} {
+ if {[catch [list uplevel #0 $args] msg opts] ni {0 2 3}} {
+ autosetup-full-error [error-dump $msg $opts]
+ }
+}
+
+# Initial settings
+set autosetup(exe) $::argv0
+set autosetup(istcl) 1
+set autosetup(start) [clock millis]
+set autosetup(installed) 0
+set autosetup(msg-checking) 0
+set autosetup(msg-quiet) 0
+
+# Embedded modules are inserted below here
+set autosetup(installed) 1
+# ----- module asciidoc-formatting -----
+
+set modsource(asciidoc-formatting) {
+# Copyright (c) 2010 WorkWare Systems http://www.workware.net.au/
+# All rights reserved
+
+# Module which provides text formatting
+# asciidoc format
+
+use formatting
+
+proc para {text} {
+ regsub -all "\[ \t\n\]+" [string trim $text] " "
+}
+proc title {text} {
+ underline [para $text] =
+ nl
+}
+proc p {text} {
+ puts [para $text]
+ nl
+}
+proc code {text} {
+ foreach line [parse_code_block $text] {
+ puts " $line"
+ }
+ nl
+}
+proc codelines {lines} {
+ foreach line $lines {
+ puts " $line"
+ }
+ nl
+}
+proc nl {} {
+ puts ""
+}
+proc underline {text char} {
+ regexp "^(\[ \t\]*)(.*)" $text -> indent words
+ puts $text
+ puts $indent[string repeat $char [string length $words]]
+}
+proc section {text} {
+ underline "[para $text]" -
+ nl
+}
+proc subsection {text} {
+ underline "$text" ~
+ nl
+}
+proc bullet {text} {
+ puts "* [para $text]"
+}
+proc indent {text} {
+ puts " :: "
+ puts [para $text]
+}
+proc defn {first args} {
+ set sep ""
+ if {$first ne ""} {
+ puts "${first}::"
+ } else {
+ puts " :: "
+ }
+ set defn [string trim [join $args \n]]
+ regsub -all "\n\n" $defn "\n ::\n" defn
+ puts $defn
+}
+}
+
+# ----- module formatting -----
+
+set modsource(formatting) {
+# Copyright (c) 2010 WorkWare Systems http://www.workware.net.au/
+# All rights reserved
+
+# Module which provides common text formatting
+
+# This is designed for documenation which looks like:
+# code {...}
+# or
+# code {
+# ...
+# ...
+# }
+# In the second case, we need to work out the indenting
+# and strip it from all lines but preserve the remaining indenting.
+# Note that all lines need to be indented with the same initial
+# spaces/tabs.
+#
+# Returns a list of lines with the indenting removed.
+#
+proc parse_code_block {text} {
+ # If the text begins with newline, take the following text,
+ # otherwise just return the original
+ if {![regexp "^\n(.*)" $text -> text]} {
+ return [list [string trim $text]]
+ }
+
+ # And trip spaces off the end
+ set text [string trimright $text]
+
+ set min 100
+ # Examine each line to determine the minimum indent
+ foreach line [split $text \n] {
+ if {$line eq ""} {
+ # Ignore empty lines for the indent calculation
+ continue
+ }
+ regexp "^(\[ \t\]*)" $line -> indent
+ set len [string length $indent]
+ if {$len < $min} {
+ set min $len
+ }
+ }
+
+ # Now make a list of lines with this indent removed
+ set lines {}
+ foreach line [split $text \n] {
+ lappend lines [string range $line $min end]
+ }
+
+ # Return the result
+ return $lines
+}
+}
+
+# ----- module getopt -----
+
+set modsource(getopt) {
+# Copyright (c) 2006 WorkWare Systems http://www.workware.net.au/
+# All rights reserved
+
+# Simple getopt module
+
+# Parse everything out of the argv list which looks like an option
+# Knows about --enable-thing and --disable-thing as alternatives for --thing=0 or --thing=1
+# Everything which doesn't look like an option, or is after --, is left unchanged
+proc getopt {argvname} {
+ upvar $argvname argv
+ set nargv {}
+
+ for {set i 0} {$i < [llength $argv]} {incr i} {
+ set arg [lindex $argv $i]
+
+ #dputs arg=$arg
+
+ if {$arg eq "--"} {
+ # End of options
+ incr i
+ lappend nargv {*}[lrange $argv $i end]
+ break
+ }
+
+ if {[regexp {^--([^=][^=]+)=(.*)$} $arg -> name value]} {
+ lappend opts($name) $value
+ } elseif {[regexp {^--(enable-|disable-)?([^=]*)$} $arg -> prefix name]} {
+ if {$prefix eq "disable-"} {
+ set value 0
+ } else {
+ set value 1
+ }
+ lappend opts($name) $value
+ } else {
+ lappend nargv $arg
+ }
+ }
+
+ #puts "getopt: argv=[join $argv] => [join $nargv]"
+ #parray opts
+
+ set argv $nargv
+
+ return [array get opts]
+}
+
+proc opt_val {optarrayname options {default {}}} {
+ upvar $optarrayname opts
+
+ set result {}
+
+ foreach o $options {
+ if {[info exists opts($o)]} {
+ lappend result {*}$opts($o)
+ }
+ }
+ if {[llength $result] == 0} {
+ return $default
+ }
+ return $result
+}
+
+proc opt_bool {optarrayname args} {
+ upvar $optarrayname opts
+
+ # Support the args being passed as a list
+ if {[llength $args] == 1} {
+ set args [lindex $args 0]
+ }
+
+ foreach o $args {
+ if {[info exists opts($o)]} {
+ if {"1" in $opts($o) || "yes" in $opts($o)} {
+ return 1
+ }
+ }
+ }
+ return 0
+}
+}
+
+# ----- module help -----
+
+set modsource(help) {
+# Copyright (c) 2010 WorkWare Systems http://workware.net.au/
+# All rights reserved
+
+# Module which provides usage, help and the command reference
+
+proc autosetup_help {what} {
+ use_pager
+
+ puts "Usage: [file tail $::autosetup(exe)] \[options\] \[settings\]\n"
+ puts "This is [autosetup_version], a build environment \"autoconfigurator\""
+ puts "See the documentation online at http://msteveb.github.com/autosetup/\n"
+
+ if {$what eq "local"} {
+ if {[file exists $::autosetup(autodef)]} {
+ # This relies on auto.def having a call to 'options'
+ # which will display options and quit
+ source $::autosetup(autodef)
+ } else {
+ options-show
+ }
+ } else {
+ incr ::autosetup(showhelp)
+ if {[catch {use $what}]} {
+ user-error "Unknown module: $what"
+ } else {
+ options-show
+ }
+ }
+ exit 0
+}
+
+# If not already paged and stdout is a tty, pipe the output through the pager
+# This is done by reinvoking autosetup with --nopager added
+proc use_pager {} {
+ if {![opt-bool nopager] && [getenv PAGER ""] ne "" && [isatty? stdin] && [isatty? stdout]} {
+ catch {
+ exec [info nameofexecutable] $::argv0 --nopager {*}$::argv |& [getenv PAGER] >@stdout <@stdin
+ }
+ exit 0
+ }
+}
+
+# Outputs the autosetup references in one of several formats
+proc autosetup_reference {{type text}} {
+
+ use_pager
+
+ switch -glob -- $type {
+ wiki {use wiki-formatting}
+ ascii* {use asciidoc-formatting}
+ md - markdown {use markdown-formatting}
+ default {use text-formatting}
+ }
+
+ title "[autosetup_version] -- Command Reference"
+
+ section {Introduction}
+
+ p {
+ See http://msteveb.github.com/autosetup/ for the online documentation for 'autosetup'
+ }
+
+ p {
+ 'autosetup' provides a number of built-in commands which
+ are documented below. These may be used from 'auto.def' to test
+ for features, define variables, create files from templates and
+ other similar actions.
+ }
+
+ automf_command_reference
+
+ exit 0
+}
+
+proc autosetup_output_block {type lines} {
+ if {[llength $lines]} {
+ switch $type {
+ code {
+ codelines $lines
+ }
+ p {
+ p [join $lines]
+ }
+ list {
+ foreach line $lines {
+ bullet $line
+ }
+ nl
+ }
+ }
+ }
+}
+
+# Generate a command reference from inline documentation
+proc automf_command_reference {} {
+ lappend files $::autosetup(prog)
+ lappend files {*}[lsort [glob -nocomplain $::autosetup(libdir)/*.tcl]]
+
+ section "Core Commands"
+ set type p
+ set lines {}
+ set cmd {}
+
+ foreach file $files {
+ set f [open $file]
+ while {![eof $f]} {
+ set line [gets $f]
+
+ # Find lines starting with "# @*" and continuing through the remaining comment lines
+ if {![regexp {^# @(.*)} $line -> cmd]} {
+ continue
+ }
+
+ # Synopsis or command?
+ if {$cmd eq "synopsis:"} {
+ section "Module: [file rootname [file tail $file]]"
+ } else {
+ subsection $cmd
+ }
+
+ set lines {}
+ set type p
+
+ # Now the description
+ while {![eof $f]} {
+ set line [gets $f]
+
+ if {![regexp {^#(#)? ?(.*)} $line -> hash cmd]} {
+ break
+ }
+ if {$hash eq "#"} {
+ set t code
+ } elseif {[regexp {^- (.*)} $cmd -> cmd]} {
+ set t list
+ } else {
+ set t p
+ }
+
+ #puts "hash=$hash, oldhash=$oldhash, lines=[llength $lines], cmd=$cmd"
+
+ if {$t ne $type || $cmd eq ""} {
+ # Finish the current block
+ autosetup_output_block $type $lines
+ set lines {}
+ set type $t
+ }
+ if {$cmd ne ""} {
+ lappend lines $cmd
+ }
+ }
+
+ autosetup_output_block $type $lines
+ }
+ close $f
+ }
+}
+}
+
+# ----- module init -----
+
+set modsource(init) {
+# Copyright (c) 2010 WorkWare Systems http://www.workware.net.au/
+# All rights reserved
+
+# Module to help create auto.def and configure
+
+proc autosetup_init {type} {
+ set help 0
+ if {$type in {? help}} {
+ incr help
+ } elseif {![dict exists $::autosetup(inittypes) $type]} {
+ puts "Unknown type, --init=$type"
+ incr help
+ }
+ if {$help} {
+ puts "Use one of the following types (e.g. --init=make)\n"
+ foreach type [lsort [dict keys $::autosetup(inittypes)]] {
+ lassign [dict get $::autosetup(inittypes) $type] desc
+ # XXX: Use the options-show code to wrap the description
+ puts [format "%-10s %s" $type $desc]
+ }
+ exit 0
+ }
+ lassign [dict get $::autosetup(inittypes) $type] desc script
+
+ puts "Initialising $type: $desc\n"
+
+ # All initialisations happens in the top level srcdir
+ cd $::autosetup(srcdir)
+
+ uplevel #0 $script
+
+ exit 0
+}
+
+proc autosetup_add_init_type {type desc script} {
+ dict set ::autosetup(inittypes) $type [list $desc $script]
+}
+
+# This is for in creating build-system init scripts
+#
+# If the file doesn't exist, create it containing $contents
+# If the file does exist, only overwrite if --force is specified.
+#
+proc autosetup_check_create {filename contents} {
+ if {[file exists $filename]} {
+ if {!$::autosetup(force)} {
+ puts "I see $filename already exists."
+ return
+ } else {
+ puts "I will overwrite the existing $filename because you used --force."
+ }
+ } else {
+ puts "I don't see $filename, so I will create it."
+ }
+ writefile $filename $contents
+}
+}
+
+# ----- module install -----
+
+set modsource(install) {
+# Copyright (c) 2006-2010 WorkWare Systems http://www.workware.net.au/
+# All rights reserved
+
+# Module which can install autosetup
+
+proc autosetup_install {dir} {
+ if {[catch {
+ cd $dir
+ file mkdir autosetup
+
+ set f [open autosetup/autosetup w]
+
+ set publicmodules $::autosetup(libdir)/default.auto
+
+ # First the main script, but only up until "CUT HERE"
+ set in [open $::autosetup(dir)/autosetup]
+ while {[gets $in buf] >= 0} {
+ if {$buf ne "##-- CUT HERE --##"} {
+ puts $f $buf
+ continue
+ }
+
+ # Insert the static modules here
+ # i.e. those which don't contain @synopsis:
+ puts $f "set autosetup(installed) 1"
+ foreach file [lsort [glob $::autosetup(libdir)/*.tcl]] {
+ set buf [readfile $file]
+ if {[string match "*\n# @synopsis:*" $buf]} {
+ lappend publicmodules $file
+ continue
+ }
+ set modname [file rootname [file tail $file]]
+ puts $f "# ----- module $modname -----"
+ puts $f "\nset modsource($modname) \{"
+ puts $f $buf
+ puts $f "\}\n"
+ }
+ }
+ close $in
+ close $f
+ exec chmod 755 autosetup/autosetup
+
+ # Install public modules
+ foreach file $publicmodules {
+ autosetup_install_file $file autosetup
+ }
+
+ # Install support files
+ foreach file {config.guess config.sub jimsh0.c find-tclsh test-tclsh LICENSE} {
+ autosetup_install_file $::autosetup(dir)/$file autosetup
+ }
+ exec chmod 755 autosetup/config.sub autosetup/config.guess autosetup/find-tclsh
+
+ writefile autosetup/README.autosetup \
+ "This is [autosetup_version]. See http://msteveb.github.com/autosetup/\n"
+
+ } error]} {
+ user-error "Failed to install autosetup: $error"
+ }
+ puts "Installed [autosetup_version] to autosetup/"
+
+ # Now create 'configure' if necessary
+ autosetup_create_configure
+
+ exit 0
+}
+
+proc autosetup_create_configure {} {
+ if {[file exists configure]} {
+ if {!$::autosetup(force)} {
+ # Could this be an autosetup configure?
+ if {![string match "*\nWRAPPER=*" [readfile configure]]} {
+ puts "I see configure, but not created by autosetup, so I won't overwrite it."
+ puts "Remove it or use --force to overwrite."
+ return
+ }
+ } else {
+ puts "I will overwrite the existing configure because you used --force."
+ }
+ } else {
+ puts "I don't see configure, so I will create it."
+ }
+ writefile configure \
+{#!/bin/sh
+dir="`dirname "$0"`/autosetup"
+WRAPPER="$0"; export WRAPPER; exec "`$dir/find-tclsh`" "$dir/autosetup" "$@"
+}
+ catch {exec chmod 755 configure}
+}
+
+# Append the contents of $file to filehandle $f
+proc autosetup_install_append {f file} {
+ set in [open $file]
+ puts $f [read $in]
+ close $in
+}
+
+proc autosetup_install_file {file dir} {
+ if {![file exists $file]} {
+ error "Missing installation file '$file'"
+ }
+ writefile [file join $dir [file tail $file]] [readfile $file]\n
+}
+
+if {$::autosetup(installed)} {
+ user-error "autosetup can only be installed from development source, not from installed copy"
+}
+}
+
+# ----- module markdown-formatting -----
+
+set modsource(markdown-formatting) {
+# Copyright (c) 2010 WorkWare Systems http://www.workware.net.au/
+# All rights reserved
+
+# Module which provides text formatting
+# markdown format (kramdown syntax)
+
+use formatting
+
+proc para {text} {
+ regsub -all "\[ \t\n\]+" [string trim $text] " " text
+ regsub -all {([^a-zA-Z])'([^']*)'} $text {\1**`\2`**} text
+ regsub -all {^'([^']*)'} $text {**`\1`**} text
+ regsub -all {(http[^ \t\n]*)} $text {[\1](\1)} text
+ return $text
+}
+proc title {text} {
+ underline [para $text] =
+ nl
+}
+proc p {text} {
+ puts [para $text]
+ nl
+}
+proc codelines {lines} {
+ puts "~~~~~~~~~~~~"
+ foreach line $lines {
+ puts $line
+ }
+ puts "~~~~~~~~~~~~"
+ nl
+}
+proc code {text} {
+ puts "~~~~~~~~~~~~"
+ foreach line [parse_code_block $text] {
+ puts $line
+ }
+ puts "~~~~~~~~~~~~"
+ nl
+}
+proc nl {} {
+ puts ""
+}
+proc underline {text char} {
+ regexp "^(\[ \t\]*)(.*)" $text -> indent words
+ puts $text
+ puts $indent[string repeat $char [string length $words]]
+}
+proc section {text} {
+ underline "[para $text]" -
+ nl
+}
+proc subsection {text} {
+ puts "### `$text`"
+ nl
+}
+proc bullet {text} {
+ puts "* [para $text]"
+}
+proc defn {first args} {
+ puts "^"
+ set defn [string trim [join $args \n]]
+ if {$first ne ""} {
+ puts "**${first}**"
+ puts -nonewline ": "
+ regsub -all "\n\n" $defn "\n: " defn
+ }
+ puts "$defn"
+}
+}
+
+# ----- module misc -----
+
+set modsource(misc) {
+# Copyright (c) 2007-2010 WorkWare Systems http://www.workware.net.au/
+# All rights reserved
+
+# Module containing misc procs useful to modules
+# Largely for platform compatibility
+
+set autosetup(istcl) [info exists ::tcl_library]
+set autosetup(iswin) [string equal windows $tcl_platform(platform)]
+
+if {$autosetup(iswin)} {
+ # mingw/windows separates $PATH with semicolons
+ # and doesn't have an executable bit
+ proc split-path {} {
+ split [getenv PATH .] {;}
+ }
+ proc file-isexec {exec} {
+ # Basic test for windows. We ignore .bat
+ if {[file isfile $exec] || [file isfile $exec.exe]} {
+ return 1
+ }
+ return 0
+ }
+} else {
+ # unix separates $PATH with colons and has and executable bit
+ proc split-path {} {
+ split [getenv PATH .] :
+ }
+ proc file-isexec {exec} {
+ file executable $exec
+ }
+}
+
+# Assume that exec can return stdout and stderr
+proc exec-with-stderr {args} {
+ exec {*}$args 2>@1
+}
+
+if {$autosetup(istcl)} {
+ # Tcl doesn't have the env command
+ proc getenv {name args} {
+ if {[info exists ::env($name)]} {
+ return $::env($name)
+ }
+ if {[llength $args]} {
+ return [lindex $args 0]
+ }
+ return -code error "environment variable \"$name\" does not exist"
+ }
+ proc isatty? {channel} {
+ dict exists [fconfigure $channel] -xchar
+ }
+} else {
+ if {$autosetup(iswin)} {
+ # On Windows, backslash convert all environment variables
+ # (Assume that Tcl does this for us)
+ proc getenv {name args} {
+ string map {\\ /} [env $name {*}$args]
+ }
+ } else {
+ # Jim on unix is simple
+ alias getenv env
+ }
+ proc isatty? {channel} {
+ set tty 0
+ catch {
+ # isatty is a recent addition to Jim Tcl
+ set tty [$channel isatty]
+ }
+ return $tty
+ }
+}
+
+# In case 'file normalize' doesn't exist
+#
+proc file-normalize {path} {
+ if {[catch {file normalize $path} result]} {
+ if {$path eq ""} {
+ return ""
+ }
+ set oldpwd [pwd]
+ if {[file isdir $path]} {
+ cd $path
+ set result [pwd]
+ } else {
+ cd [file dirname $path]
+ set result [file join [pwd] [file tail $path]]
+ }
+ cd $oldpwd
+ }
+ return $result
+}
+
+# If everything is working properly, the only errors which occur
+# should be generated in user code (e.g. auto.def).
+# By default, we only want to show the error location in user code.
+# We use [info frame] to achieve this, but it works differently on Tcl and Jim.
+#
+# This is designed to be called for incorrect usage in auto.def, via autosetup-error
+#
+proc error-location {msg} {
+ if {$::autosetup(debug)} {
+ return -code error $msg
+ }
+ # Search back through the stack trace for the first error in a .def file
+ for {set i 1} {$i < [info level]} {incr i} {
+ if {$::autosetup(istcl)} {
+ array set info [info frame -$i]
+ } else {
+ lassign [info frame -$i] info(caller) info(file) info(line)
+ }
+ if {[string match *.def $info(file)]} {
+ return "[relative-path $info(file)]:$info(line): Error: $msg"
+ }
+ #puts "Skipping $info(file):$info(line)"
+ }
+ return $msg
+}
+
+# If everything is working properly, the only errors which occur
+# should be generated in user code (e.g. auto.def).
+# By default, we only want to show the error location in user code.
+# We use [info frame] to achieve this, but it works differently on Tcl and Jim.
+#
+# This is designed to be called for incorrect usage in auto.def, via autosetup-error
+#
+proc error-stacktrace {msg} {
+ if {$::autosetup(debug)} {
+ return -code error $msg
+ }
+ # Search back through the stack trace for the first error in a .def file
+ for {set i 1} {$i < [info level]} {incr i} {
+ if {$::autosetup(istcl)} {
+ array set info [info frame -$i]
+ } else {
+ lassign [info frame -$i] info(caller) info(file) info(line)
+ }
+ if {[string match *.def $info(file)]} {
+ return "[relative-path $info(file)]:$info(line): Error: $msg"
+ }
+ #puts "Skipping $info(file):$info(line)"
+ }
+ return $msg
+}
+
+# Given the return from [catch {...} msg opts], returns an appropriate
+# error message. A nice one for Jim and a less-nice one for Tcl.
+#
+# This is designed for developer errors, e.g. in module code
+#
+proc error-dump {msg opts} {
+ if {$::autosetup(istcl)} {
+ return "Error: [dict get $opts -errorinfo]"
+ } else {
+ return "Error: $msg\n[stackdump $opts(-errorinfo)]"
+ }
+}
+}
+
+# ----- module text-formatting -----
+
+set modsource(text-formatting) {
+# Copyright (c) 2010 WorkWare Systems http://www.workware.net.au/
+# All rights reserved
+
+# Module which provides text formatting
+
+use formatting
+
+proc wordwrap {text length {firstprefix ""} {nextprefix ""}} {
+ set len 0
+ set space $firstprefix
+ foreach word [split $text] {
+ set word [string trim $word]
+ if {$word == ""} {
+ continue
+ }
+ if {$len && [string length $space$word] + $len >= $length} {
+ puts ""
+ set len 0
+ set space $nextprefix
+ }
+ incr len [string length $space$word]
+
+ # Use man-page conventions for highlighting 'quoted' and *quoted*
+ # single words.
+ # Use x^Hx for *bold* and _^Hx for 'underline'.
+ #
+ # less and more will both understand this.
+ # Pipe through 'col -b' to remove them.
+ if {[regexp {^'(.*)'([^a-zA-Z0-9_]*)$} $word -> bareword dot]} {
+ regsub -all . $bareword "_\b&" word
+ append word $dot
+ } elseif {[regexp {^[*](.*)[*]([^a-zA-Z0-9_]*)$} $word -> bareword dot]} {
+ regsub -all . $bareword "&\b&" word
+ append word $dot
+ }
+ puts -nonewline $space$word
+ set space " "
+ }
+ if {$len} {
+ puts ""
+ }
+}
+proc title {text} {
+ underline [string trim $text] =
+ nl
+}
+proc p {text} {
+ wordwrap $text 80
+ nl
+}
+proc codelines {lines} {
+ foreach line $lines {
+ puts " $line"
+ }
+ nl
+}
+proc nl {} {
+ puts ""
+}
+proc underline {text char} {
+ regexp "^(\[ \t\]*)(.*)" $text -> indent words
+ puts $text
+ puts $indent[string repeat $char [string length $words]]
+}
+proc section {text} {
+ underline "[string trim $text]" -
+ nl
+}
+proc subsection {text} {
+ underline "$text" ~
+ nl
+}
+proc bullet {text} {
+ wordwrap $text 76 " * " " "
+}
+proc indent {text} {
+ wordwrap $text 76 " " " "
+}
+proc defn {first args} {
+ if {$first ne ""} {
+ underline " $first" ~
+ }
+ foreach p $args {
+ if {$p ne ""} {
+ indent $p
+ }
+ }
+}
+}
+
+# ----- module wiki-formatting -----
+
+set modsource(wiki-formatting) {
+# Copyright (c) 2010 WorkWare Systems http://www.workware.net.au/
+# All rights reserved
+
+# Module which provides text formatting
+# wiki.tcl.tk format output
+
+use formatting
+
+proc joinlines {text} {
+ set lines {}
+ foreach l [split [string trim $text] \n] {
+ lappend lines [string trim $l]
+ }
+ join $lines
+}
+proc p {text} {
+ puts [joinlines $text]
+ puts ""
+}
+proc title {text} {
+ puts "*** [joinlines $text] ***"
+ puts ""
+}
+proc codelines {lines} {
+ puts "======"
+ foreach line $lines {
+ puts " $line"
+ }
+ puts "======"
+}
+proc code {text} {
+ puts "======"
+ foreach line [parse_code_block $text] {
+ puts " $line"
+ }
+ puts "======"
+}
+proc nl {} {
+}
+proc section {text} {
+ puts "'''$text'''"
+ puts ""
+}
+proc subsection {text} {
+ puts "''$text''"
+ puts ""
+}
+proc bullet {text} {
+ puts " * [joinlines $text]"
+}
+proc indent {text} {
+ puts " : [joinlines $text]"
+}
+proc defn {first args} {
+ if {$first ne ""} {
+ indent '''$first'''
+ }
+
+ foreach p $args {
+ p $p
+ }
+}
+}
+
+
+##################################################################
+#
+# Entry/Exit
+#
+if {$autosetup(debug)} {
+ main $argv
+}
+if {[catch {main $argv} msg] == 1} {
+ show-notices
+ puts stderr [error-stacktrace $msg]
+ if {!$autosetup(debug) && !$autosetup(istcl)} {
+ puts stderr "Try: '[file tail $autosetup(exe)] --debug' for a full stack trace"
+ }
+ exit 1
+}
ADDED autosetup/cc-db.tcl
Index: autosetup/cc-db.tcl
==================================================================
--- autosetup/cc-db.tcl
+++ autosetup/cc-db.tcl
@@ -0,0 +1,15 @@
+# Copyright (c) 2011 WorkWare Systems http://www.workware.net.au/
+# All rights reserved
+
+# @synopsis:
+#
+# The 'cc-db' module provides a knowledge based of system idiosyncracies
+# In general, this module can always be included
+
+use cc
+
+module-options {}
+
+# openbsd needs sys/types.h to detect some system headers
+cc-include-needs sys/socket.h sys/types.h
+cc-include-needs netinet/in.h sys/types.h
ADDED autosetup/cc-lib.tcl
Index: autosetup/cc-lib.tcl
==================================================================
--- autosetup/cc-lib.tcl
+++ autosetup/cc-lib.tcl
@@ -0,0 +1,161 @@
+# Copyright (c) 2011 WorkWare Systems http://www.workware.net.au/
+# All rights reserved
+
+# @synopsis:
+#
+# Provides a library of common tests on top of the 'cc' module.
+
+use cc
+
+module-options {}
+
+# @cc-check-lfs
+#
+# The equivalent of the AC_SYS_LARGEFILE macro
+#
+# defines 'HAVE_LFS' if LFS is available,
+# and defines '_FILE_OFFSET_BITS=64' if necessary
+#
+# Returns 1 if 'LFS' is available or 0 otherwise
+#
+proc cc-check-lfs {} {
+ cc-check-includes sys/types.h
+ msg-checking "Checking if -D_FILE_OFFSET_BITS=64 is needed..."
+ set lfs 1
+ if {[msg-quiet cc-with {-includes sys/types.h} {cc-check-sizeof off_t}] == 8} {
+ msg-result no
+ } elseif {[msg-quiet cc-with {-includes sys/types.h -cflags -D_FILE_OFFSET_BITS=64} {cc-check-sizeof off_t}] == 8} {
+ define _FILE_OFFSET_BITS 64
+ msg-result yes
+ } else {
+ set lfs 0
+ msg-result none
+ }
+ define-feature lfs $lfs
+ return $lfs
+}
+
+# @cc-check-endian
+#
+# The equivalent of the AC_C_BIGENDIAN macro
+#
+# defines 'HAVE_BIG_ENDIAN' if endian is known to be big,
+# or 'HAVE_LITTLE_ENDIAN' if endian is known to be little.
+#
+# Returns 1 if determined, or 0 if not.
+#
+proc cc-check-endian {} {
+ cc-check-includes sys/types.h sys/param.h
+ set rc 0
+ msg-checking "Checking endian..."
+ cc-with {-includes {sys/types.h sys/param.h}} {
+ if {[cctest -code {
+ #if !defined(BIG_ENDIAN) || !defined(BYTE_ORDER)
+ #error unknown
+ #elif BYTE_ORDER != BIG_ENDIAN
+ #error little
+ #endif
+ }]} {
+ define-feature big-endian
+ msg-result "big"
+ set rc 1
+ } elseif {[cctest -code {
+ #if !defined(LITTLE_ENDIAN) || !defined(BYTE_ORDER)
+ #error unknown
+ #elif BYTE_ORDER != LITTLE_ENDIAN
+ #error big
+ #endif
+ }]} {
+ define-feature little-endian
+ msg-result "little"
+ set rc 1
+ } else {
+ msg-result "unknown"
+ }
+ }
+ return $rc
+}
+
+# @cc-check-flags flag ?...?
+#
+# Checks whether the given C/C++ compiler flags can be used. Defines feature
+# names prefixed with 'HAVE_CFLAG' and 'HAVE_CXXFLAG' respectively, and
+# appends working flags to '-cflags' and 'CFLAGS' or 'CXXFLAGS'.
+proc cc-check-flags {args} {
+ set result 1
+ array set opts [cc-get-settings]
+ switch -exact -- $opts(-lang) {
+ c++ {
+ set lang C++
+ set prefix CXXFLAG
+ }
+ c {
+ set lang C
+ set prefix CFLAG
+ }
+ default {
+ autosetup-error "cc-check-flags failed with unknown language: $opts(-lang)"
+ }
+ }
+ foreach flag $args {
+ msg-checking "Checking whether the $lang compiler accepts $flag..."
+ if {[cctest -cflags $flag]} {
+ msg-result yes
+ define-feature $prefix$flag
+ cc-with [list -cflags [list $flag]]
+ define-append ${prefix}S $flag
+ } else {
+ msg-result no
+ set result 0
+ }
+ }
+ return $result
+}
+
+# @cc-check-standards ver ?...?
+#
+# Checks whether the C/C++ compiler accepts one of the specified '-std=$ver'
+# options, and appends the first working one to '-cflags' and 'CFLAGS' or
+# 'CXXFLAGS'.
+proc cc-check-standards {args} {
+ array set opts [cc-get-settings]
+ foreach std $args {
+ if {[cc-check-flags -std=$std]} {
+ return $std
+ }
+ }
+ return ""
+}
+
+# Checks whether $keyword is usable as alignof
+proc cctest_alignof {keyword} {
+ msg-checking "Checking for $keyword..."
+ if {[cctest -code [subst -nobackslashes {
+ printf("minimum alignment is %d == %d\n", ${keyword}(char), ${keyword}('x'));
+ }]]} then {
+ msg-result ok
+ define-feature $keyword
+ } else {
+ msg-result "not found"
+ }
+}
+
+# @cc-check-c11
+#
+# Checks for several C11/C++11 extensions and their alternatives. Currently
+# checks for '_Static_assert', '_Alignof', '__alignof__', '__alignof'.
+proc cc-check-c11 {} {
+ msg-checking "Checking for _Static_assert..."
+ if {[cctest -code {
+ _Static_assert(1, "static assertions are available");
+ }]} then {
+ msg-result ok
+ define-feature _Static_assert
+ } else {
+ msg-result "not found"
+ }
+
+ cctest_alignof _Alignof
+ cctest_alignof __alignof__
+ cctest_alignof __alignof
+}
ADDED autosetup/cc-shared.tcl
Index: autosetup/cc-shared.tcl
==================================================================
--- autosetup/cc-shared.tcl
+++ autosetup/cc-shared.tcl
@@ -0,0 +1,103 @@
+# Copyright (c) 2010 WorkWare Systems http://www.workware.net.au/
+# All rights reserved
+
+# @synopsis:
+#
+# The 'cc-shared' module provides support for shared libraries and shared objects.
+# It defines the following variables:
+#
+## SH_CFLAGS Flags to use compiling sources destined for a shared library
+## SH_LDFLAGS Flags to use linking (creating) a shared library
+## SH_SOPREFIX Prefix to use to set the soname when creating a shared library
+## SH_SOEXT Extension for shared libs
+## SH_SOEXTVER Format for versioned shared libs - %s = version
+## SHOBJ_CFLAGS Flags to use compiling sources destined for a shared object
+## SHOBJ_LDFLAGS Flags to use linking a shared object, undefined symbols allowed
+## SHOBJ_LDFLAGS_R - as above, but all symbols must be resolved
+## SH_LINKFLAGS Flags to use linking an executable which will load shared objects
+## LD_LIBRARY_PATH Environment variable which specifies path to shared libraries
+## STRIPLIBFLAGS Arguments to strip to strip a dynamic library
+
+module-options {}
+
+# Defaults: gcc on unix
+define SHOBJ_CFLAGS -fpic
+define SHOBJ_LDFLAGS -shared
+define SH_CFLAGS -fpic
+define SH_LDFLAGS -shared
+define SH_LINKFLAGS -rdynamic
+define SH_SOEXT .so
+define SH_SOEXTVER .so.%s
+define SH_SOPREFIX -Wl,-soname,
+define LD_LIBRARY_PATH LD_LIBRARY_PATH
+define STRIPLIBFLAGS --strip-unneeded
+
+# Note: This is a helpful reference for identifying the toolchain
+# http://sourceforge.net/apps/mediawiki/predef/index.php?title=Compilers
+
+switch -glob -- [get-define host] {
+ *-*-darwin* {
+ define SHOBJ_CFLAGS "-dynamic -fno-common"
+ define SHOBJ_LDFLAGS "-bundle -undefined dynamic_lookup"
+ define SHOBJ_LDFLAGS_R -bundle
+ define SH_CFLAGS -dynamic
+ define SH_LDFLAGS -dynamiclib
+ define SH_LINKFLAGS ""
+ define SH_SOEXT .dylib
+ define SH_SOEXTVER .%s.dylib
+ define SH_SOPREFIX -Wl,-install_name,
+ define LD_LIBRARY_PATH DYLD_LIBRARY_PATH
+ define STRIPLIBFLAGS -x
+ }
+ *-*-ming* - *-*-cygwin - *-*-msys {
+ define SHOBJ_CFLAGS ""
+ define SHOBJ_LDFLAGS -shared
+ define SH_CFLAGS ""
+ define SH_LDFLAGS -shared
+ define SH_LINKFLAGS ""
+ define SH_SOEXT .dll
+ define SH_SOEXTVER .dll
+ define SH_SOPREFIX ""
+ define LD_LIBRARY_PATH PATH
+ }
+ sparc* {
+ if {[msg-quiet cc-check-decls __SUNPRO_C]} {
+ msg-result "Found sun stdio compiler"
+ # sun stdio compiler
+ # XXX: These haven't been fully tested.
+ define SHOBJ_CFLAGS -KPIC
+ define SHOBJ_LDFLAGS "-G"
+ define SH_CFLAGS -KPIC
+ define SH_LINKFLAGS -Wl,-export-dynamic
+ define SH_SOPREFIX -Wl,-h,
+ } else {
+ # sparc has a very small GOT table limit, so use -fPIC
+ define SH_CFLAGS -fPIC
+ define SHOBJ_CFLAGS -fPIC
+ }
+ }
+ *-*-solaris* {
+ if {[msg-quiet cc-check-decls __SUNPRO_C]} {
+ msg-result "Found sun stdio compiler"
+ # sun stdio compiler
+ # XXX: These haven't been fully tested.
+ define SHOBJ_CFLAGS -KPIC
+ define SHOBJ_LDFLAGS "-G"
+ define SH_CFLAGS -KPIC
+ define SH_LINKFLAGS -Wl,-export-dynamic
+ define SH_SOPREFIX -Wl,-h,
+ }
+ }
+ *-*-hpux {
+ # XXX: These haven't been tested
+ define SHOBJ_CFLAGS "+O3 +z"
+ define SHOBJ_LDFLAGS -b
+ define SH_CFLAGS +z
+ define SH_LINKFLAGS -Wl,+s
+ define LD_LIBRARY_PATH SHLIB_PATH
+ }
+}
+
+if {![is-defined SHOBJ_LDFLAGS_R]} {
+ define SHOBJ_LDFLAGS_R [get-define SHOBJ_LDFLAGS]
+}
ADDED autosetup/cc.tcl
Index: autosetup/cc.tcl
==================================================================
--- autosetup/cc.tcl
+++ autosetup/cc.tcl
@@ -0,0 +1,697 @@
+# Copyright (c) 2010 WorkWare Systems http://www.workware.net.au/
+# All rights reserved
+
+# @synopsis:
+#
+# The 'cc' module supports checking various 'features' of the C or C++
+# compiler/linker environment. Common commands are cc-check-includes,
+# cc-check-types, cc-check-functions, cc-with, make-autoconf-h and make-template.
+#
+# The following environment variables are used if set:
+#
+## CC - C compiler
+## CXX - C++ compiler
+## CCACHE - Set to "none" to disable automatic use of ccache
+## CFLAGS - Additional C compiler flags
+## CXXFLAGS - Additional C++ compiler flags
+## LDFLAGS - Additional compiler flags during linking
+## LIBS - Additional libraries to use (for all tests)
+## CROSS - Tool prefix for cross compilation
+#
+# The following variables are defined from the corresponding
+# environment variables if set.
+#
+## CPPFLAGS
+## LINKFLAGS
+## CC_FOR_BUILD
+## LD
+
+use system
+
+module-options {}
+
+# Note that the return code is not meaningful
+proc cc-check-something {name code} {
+ uplevel 1 $code
+}
+
+# Checks for the existence of the given function by linking
+#
+proc cctest_function {function} {
+ cctest -link 1 -declare "extern void $function\(void);" -code "$function\();"
+}
+
+# Checks for the existence of the given type by compiling
+proc cctest_type {type} {
+ cctest -code "$type _x;"
+}
+
+# Checks for the existence of the given type/structure member.
+# e.g. "struct stat.st_mtime"
+proc cctest_member {struct_member} {
+ lassign [split $struct_member .] struct member
+ cctest -code "static $struct _s; return sizeof(_s.$member);"
+}
+
+# Checks for the existence of the given define by compiling
+#
+proc cctest_define {name} {
+ cctest -code "#ifndef $name\n#error not defined\n#endif"
+}
+
+# Checks for the existence of the given name either as
+# a macro (#define) or an rvalue (such as an enum)
+#
+proc cctest_decl {name} {
+ cctest -code "#ifndef $name\n(void)$name;\n#endif"
+}
+
+# @cc-check-sizeof type ...
+#
+# Checks the size of the given types (between 1 and 32, inclusive).
+# Defines a variable with the size determined, or "unknown" otherwise.
+# e.g. for type 'long long', defines SIZEOF_LONG_LONG.
+# Returns the size of the last type.
+#
+proc cc-check-sizeof {args} {
+ foreach type $args {
+ msg-checking "Checking for sizeof $type..."
+ set size unknown
+ # Try the most common sizes first
+ foreach i {4 8 1 2 16 32} {
+ if {[cctest -code "static int _x\[sizeof($type) == $i ? 1 : -1\] = { 1 };"]} {
+ set size $i
+ break
+ }
+ }
+ msg-result $size
+ set define [feature-define-name $type SIZEOF_]
+ define $define $size
+ }
+ # Return the last result
+ get-define $define
+}
+
+# Checks for each feature in $list by using the given script.
+#
+# When the script is evaluated, $each is set to the feature
+# being checked, and $extra is set to any additional cctest args.
+#
+# Returns 1 if all features were found, or 0 otherwise.
+proc cc-check-some-feature {list script} {
+ set ret 1
+ foreach each $list {
+ if {![check-feature $each $script]} {
+ set ret 0
+ }
+ }
+ return $ret
+}
+
+# @cc-check-includes includes ...
+#
+# Checks that the given include files can be used
+proc cc-check-includes {args} {
+ cc-check-some-feature $args {
+ set with {}
+ if {[dict exists $::autosetup(cc-include-deps) $each]} {
+ set deps [dict keys [dict get $::autosetup(cc-include-deps) $each]]
+ msg-quiet cc-check-includes {*}$deps
+ foreach i $deps {
+ if {[have-feature $i]} {
+ lappend with $i
+ }
+ }
+ }
+ if {[llength $with]} {
+ cc-with [list -includes $with] {
+ cctest -includes $each
+ }
+ } else {
+ cctest -includes $each
+ }
+ }
+}
+
+# @cc-include-needs include required ...
+#
+# Ensures that when checking for 'include', a check is first
+# made for each 'required' file, and if found, it is #included
+proc cc-include-needs {file args} {
+ foreach depfile $args {
+ dict set ::autosetup(cc-include-deps) $file $depfile 1
+ }
+}
+
+# @cc-check-types type ...
+#
+# Checks that the types exist.
+proc cc-check-types {args} {
+ cc-check-some-feature $args {
+ cctest_type $each
+ }
+}
+
+# @cc-check-defines define ...
+#
+# Checks that the given preprocessor symbol is defined
+proc cc-check-defines {args} {
+ cc-check-some-feature $args {
+ cctest_define $each
+ }
+}
+
+# @cc-check-decls name ...
+#
+# Checks that each given name is either a preprocessor symbol or rvalue
+# such as an enum. Note that the define used for a decl is HAVE_DECL_xxx
+# rather than HAVE_xxx
+proc cc-check-decls {args} {
+ set ret 1
+ foreach name $args {
+ msg-checking "Checking for $name..."
+ set r [cctest_decl $name]
+ define-feature "decl $name" $r
+ if {$r} {
+ msg-result "ok"
+ } else {
+ msg-result "not found"
+ set ret 0
+ }
+ }
+ return $ret
+}
+
+# @cc-check-functions function ...
+#
+# Checks that the given functions exist (can be linked)
+proc cc-check-functions {args} {
+ cc-check-some-feature $args {
+ cctest_function $each
+ }
+}
+
+# @cc-check-members type.member ...
+#
+# Checks that the given type/structure members exist.
+# A structure member is of the form "struct stat.st_mtime"
+proc cc-check-members {args} {
+ cc-check-some-feature $args {
+ cctest_member $each
+ }
+}
+
+# @cc-check-function-in-lib function libs ?otherlibs?
+#
+# Checks that the given given function can be found in one of the libs.
+#
+# First checks for no library required, then checks each of the libraries
+# in turn.
+#
+# If the function is found, the feature is defined and lib_$function is defined
+# to -l$lib where the function was found, or "" if no library required.
+# In addition, -l$lib is added to the LIBS define.
+#
+# If additional libraries may be needed for linking, they should be specified
+# as $extralibs as "-lotherlib1 -lotherlib2".
+# These libraries are not automatically added to LIBS.
+#
+# Returns 1 if found or 0 if not.
+#
+proc cc-check-function-in-lib {function libs {otherlibs {}}} {
+ msg-checking "Checking libs for $function..."
+ set found 0
+ cc-with [list -libs $otherlibs] {
+ if {[cctest_function $function]} {
+ msg-result "none needed"
+ define lib_$function ""
+ incr found
+ } else {
+ foreach lib $libs {
+ cc-with [list -libs -l$lib] {
+ if {[cctest_function $function]} {
+ msg-result -l$lib
+ define lib_$function -l$lib
+ define-append LIBS -l$lib
+ incr found
+ break
+ }
+ }
+ }
+ }
+ }
+ if {$found} {
+ define [feature-define-name $function]
+ } else {
+ msg-result "no"
+ }
+ return $found
+}
+
+# @cc-check-tools tool ...
+#
+# Checks for existence of the given compiler tools, taking
+# into account any cross compilation prefix.
+#
+# For example, when checking for "ar", first AR is checked on the command
+# line and then in the environment. If not found, "${host}-ar" or
+# simply "ar" is assumed depending upon whether cross compiling.
+# The path is searched for this executable, and if found AR is defined
+# to the executable name.
+# Note that even when cross compiling, the simple "ar" is used as a fallback,
+# but a warning is generated. This is necessary for some toolchains.
+#
+# It is an error if the executable is not found.
+#
+proc cc-check-tools {args} {
+ foreach tool $args {
+ set TOOL [string toupper $tool]
+ set exe [get-env $TOOL [get-define cross]$tool]
+ if {[find-executable {*}$exe]} {
+ define $TOOL $exe
+ continue
+ }
+ if {[find-executable {*}$tool]} {
+ msg-result "Warning: Failed to find $exe, falling back to $tool which may be incorrect"
+ define $TOOL $tool
+ continue
+ }
+ user-error "Failed to find $exe"
+ }
+}
+
+# @cc-check-progs prog ...
+#
+# Checks for existence of the given executables on the path.
+#
+# For example, when checking for "grep", the path is searched for
+# the executable, 'grep', and if found GREP is defined as "grep".
+#
+# It the executable is not found, the variable is defined as false.
+# Returns 1 if all programs were found, or 0 otherwise.
+#
+proc cc-check-progs {args} {
+ set failed 0
+ foreach prog $args {
+ set PROG [string toupper $prog]
+ msg-checking "Checking for $prog..."
+ if {![find-executable $prog]} {
+ msg-result no
+ define $PROG false
+ incr failed
+ } else {
+ msg-result ok
+ define $PROG $prog
+ }
+ }
+ expr {!$failed}
+}
+
+# Adds the given settings to $::autosetup(ccsettings) and
+# returns the old settings.
+#
+proc cc-add-settings {settings} {
+ if {[llength $settings] % 2} {
+ autosetup-error "settings list is missing a value: $settings"
+ }
+
+ set prev [cc-get-settings]
+ # workaround a bug in some versions of jimsh by forcing
+ # conversion of $prev to a list
+ llength $prev
+
+ array set new $prev
+
+ foreach {name value} $settings {
+ switch -exact -- $name {
+ -cflags - -includes {
+ # These are given as lists
+ lappend new($name) {*}$value
+ }
+ -declare {
+ lappend new($name) $value
+ }
+ -libs {
+ # Note that new libraries are added before previous libraries
+ set new($name) [list {*}$value {*}$new($name)]
+ }
+ -link - -lang {
+ set new($name) $value
+ }
+ -source - -sourcefile - -code {
+ # XXX: These probably are only valid directly from cctest
+ set new($name) $value
+ }
+ default {
+ autosetup-error "unknown cctest setting: $name"
+ }
+ }
+ }
+
+ cc-store-settings [array get new]
+
+ return $prev
+}
+
+proc cc-store-settings {new} {
+ set ::autosetup(ccsettings) $new
+}
+
+proc cc-get-settings {} {
+ return $::autosetup(ccsettings)
+}
+
+# Similar to cc-add-settings, but each given setting
+# simply replaces the existing value.
+#
+# Returns the previous settings
+proc cc-update-settings {args} {
+ set prev [cc-get-settings]
+ cc-store-settings [dict merge $prev $args]
+ return $prev
+}
+
+# @cc-with settings ?{ script }?
+#
+# Sets the given 'cctest' settings and then runs the tests in 'script'.
+# Note that settings such as -lang replace the current setting, while
+# those such as -includes are appended to the existing setting.
+#
+# If no script is given, the settings become the default for the remainder
+# of the auto.def file.
+#
+## cc-with {-lang c++} {
+## # This will check with the C++ compiler
+## cc-check-types bool
+## cc-with {-includes signal.h} {
+## # This will check with the C++ compiler, signal.h and any existing includes.
+## ...
+## }
+## # back to just the C++ compiler
+## }
+#
+# The -libs setting is special in that newer values are added *before* earlier ones.
+#
+## cc-with {-libs {-lc -lm}} {
+## cc-with {-libs -ldl} {
+## cctest -libs -lsocket ...
+## # libs will be in this order: -lsocket -ldl -lc -lm
+## }
+## }
+proc cc-with {settings args} {
+ if {[llength $args] == 0} {
+ cc-add-settings $settings
+ } elseif {[llength $args] > 1} {
+ autosetup-error "usage: cc-with settings ?script?"
+ } else {
+ set save [cc-add-settings $settings]
+ set rc [catch {uplevel 1 [lindex $args 0]} result info]
+ cc-store-settings $save
+ if {$rc != 0} {
+ return -code [dict get $info -code] $result
+ }
+ return $result
+ }
+}
+
+# @cctest ?settings?
+#
+# Low level C compiler checker. Compiles and or links a small C program
+# according to the arguments and returns 1 if OK, or 0 if not.
+#
+# Supported settings are:
+#
+## -cflags cflags A list of flags to pass to the compiler
+## -includes list A list of includes, e.g. {stdlib.h stdio.h}
+## -declare code Code to declare before main()
+## -link 1 Don't just compile, link too
+## -lang c|c++ Use the C (default) or C++ compiler
+## -libs liblist List of libraries to link, e.g. {-ldl -lm}
+## -code code Code to compile in the body of main()
+## -source code Compile a complete program. Ignore -includes, -declare and -code
+## -sourcefile file Shorthand for -source [readfile [get-define srcdir]/$file]
+#
+# Unless -source or -sourcefile is specified, the C program looks like:
+#
+## #include /* same for remaining includes in the list */
+##
+## declare-code /* any code in -declare, verbatim */
+##
+## int main(void) {
+## code /* any code in -code, verbatim */
+## return 0;
+## }
+#
+# Any failures are recorded in 'config.log'
+#
+proc cctest {args} {
+ set src conftest__.c
+ set tmp conftest__
+
+ # Easiest way to merge in the settings
+ cc-with $args {
+ array set opts [cc-get-settings]
+ }
+
+ if {[info exists opts(-sourcefile)]} {
+ set opts(-source) [readfile [get-define srcdir]/$opts(-sourcefile) "#error can't find $opts(-sourcefile)"]
+ }
+ if {[info exists opts(-source)]} {
+ set lines $opts(-source)
+ } else {
+ foreach i $opts(-includes) {
+ if {$opts(-code) ne "" && ![feature-checked $i]} {
+ # Compiling real code with an unchecked header file
+ # Quickly (and silently) check for it now
+
+ # Remove all -includes from settings before checking
+ set saveopts [cc-update-settings -includes {}]
+ msg-quiet cc-check-includes $i
+ cc-store-settings $saveopts
+ }
+ if {$opts(-code) eq "" || [have-feature $i]} {
+ lappend source "#include <$i>"
+ }
+ }
+ lappend source {*}$opts(-declare)
+ lappend source "int main(void) {"
+ lappend source $opts(-code)
+ lappend source "return 0;"
+ lappend source "}"
+
+ set lines [join $source \n]
+ }
+
+ # Build the command line
+ set cmdline {}
+ lappend cmdline {*}[get-define CCACHE]
+ switch -exact -- $opts(-lang) {
+ c++ {
+ lappend cmdline {*}[get-define CXX] {*}[get-define CXXFLAGS]
+ }
+ c {
+ lappend cmdline {*}[get-define CC] {*}[get-define CFLAGS]
+ }
+ default {
+ autosetup-error "cctest called with unknown language: $opts(-lang)"
+ }
+ }
+
+ if {!$opts(-link)} {
+ set tmp conftest__.o
+ lappend cmdline -c
+ }
+ lappend cmdline {*}$opts(-cflags) {*}[get-define cc-default-debug ""]
+
+ lappend cmdline $src -o $tmp {*}$opts(-libs)
+
+ # At this point we have the complete command line and the
+ # complete source to be compiled. Get the result from cache if
+ # we can
+ if {[info exists ::cc_cache($cmdline,$lines)]} {
+ msg-checking "(cached) "
+ set ok $::cc_cache($cmdline,$lines)
+ if {$::autosetup(debug)} {
+ configlog "From cache (ok=$ok): [join $cmdline]"
+ configlog "============"
+ configlog $lines
+ configlog "============"
+ }
+ return $ok
+ }
+
+ writefile $src $lines\n
+
+ set ok 1
+ if {[catch {exec-with-stderr {*}$cmdline} result errinfo]} {
+ configlog "Failed: [join $cmdline]"
+ configlog $result
+ configlog "============"
+ configlog "The failed code was:"
+ configlog $lines
+ configlog "============"
+ set ok 0
+ } elseif {$::autosetup(debug)} {
+ configlog "Compiled OK: [join $cmdline]"
+ configlog "============"
+ configlog $lines
+ configlog "============"
+ }
+ file delete $src
+ file delete $tmp
+
+ # cache it
+ set ::cc_cache($cmdline,$lines) $ok
+
+ return $ok
+}
+
+# @make-autoconf-h outfile ?auto-patterns=HAVE_*? ?bare-patterns=SIZEOF_*?
+#
+# Deprecated - see make-config-header
+proc make-autoconf-h {file {autopatterns {HAVE_*}} {barepatterns {SIZEOF_* HAVE_DECL_*}}} {
+ user-notice "*** make-autoconf-h is deprecated -- use make-config-header instead"
+ make-config-header $file -auto $autopatterns -bare $barepatterns
+}
+
+# @make-config-header outfile ?-auto patternlist? ?-bare patternlist? ?-none patternlist? ?-str patternlist? ...
+#
+# Examines all defined variables which match the given patterns
+# and writes an include file, $file, which defines each of these.
+# Variables which match '-auto' are output as follows:
+# - defines which have the value "0" are ignored.
+# - defines which have integer values are defined as the integer value.
+# - any other value is defined as a string, e.g. "value"
+# Variables which match '-bare' are defined as-is.
+# Variables which match '-str' are defined as a string, e.g. "value"
+# Variables which match '-none' are omitted.
+#
+# Note that order is important. The first pattern which matches is selected
+# Default behaviour is:
+#
+# -bare {SIZEOF_* HAVE_DECL_*} -auto HAVE_* -none *
+#
+# If the file would be unchanged, it is not written.
+proc make-config-header {file args} {
+ set guard _[string toupper [regsub -all {[^a-zA-Z0-9]} [file tail $file] _]]
+ file mkdir [file dirname $file]
+ set lines {}
+ lappend lines "#ifndef $guard"
+ lappend lines "#define $guard"
+
+ # Add some defaults
+ lappend args -bare {SIZEOF_* HAVE_DECL_*} -auto HAVE_*
+
+ foreach n [lsort [dict keys [all-defines]]] {
+ set value [get-define $n]
+ set type [calc-define-output-type $n $args]
+ switch -exact -- $type {
+ -bare {
+ # Just output the value unchanged
+ }
+ -none {
+ continue
+ }
+ -str {
+ set value \"[string map [list \\ \\\\ \" \\\"] $value]\"
+ }
+ -auto {
+ # Automatically determine the type
+ if {$value eq "0"} {
+ lappend lines "/* #undef $n */"
+ continue
+ }
+ if {![string is integer -strict $value]} {
+ set value \"[string map [list \\ \\\\ \" \\\"] $value]\"
+ }
+ }
+ "" {
+ continue
+ }
+ default {
+ autosetup-error "Unknown type in make-config-header: $type"
+ }
+ }
+ lappend lines "#define $n $value"
+ }
+ lappend lines "#endif"
+ set buf [join $lines \n]
+ write-if-changed $file $buf {
+ msg-result "Created $file"
+ }
+}
+
+proc calc-define-output-type {name spec} {
+ foreach {type patterns} $spec {
+ foreach pattern $patterns {
+ if {[string match $pattern $name]} {
+ return $type
+ }
+ }
+ }
+ return ""
+}
+
+# Initialise some values from the environment or commandline or default settings
+foreach i {LDFLAGS LIBS CPPFLAGS LINKFLAGS {CFLAGS "-g -O2"}} {
+ lassign $i var default
+ define $var [get-env $var $default]
+}
+
+if {[env-is-set CC]} {
+ # Set by the user, so don't try anything else
+ set try [list [get-env CC ""]]
+} else {
+ # Try some reasonable options
+ set try [list [get-define cross]cc [get-define cross]gcc]
+}
+define CC [find-an-executable {*}$try]
+if {[get-define CC] eq ""} {
+ user-error "Could not find a C compiler. Tried: [join $try ", "]"
+}
+
+define CPP [get-env CPP "[get-define CC] -E"]
+
+# XXX: Could avoid looking for a C++ compiler until requested
+# Note that if CXX isn't found, we just set it to "false". It might not be needed.
+if {[env-is-set CXX]} {
+ define CXX [find-an-executable -required [get-env CXX ""]]
+} else {
+ define CXX [find-an-executable [get-define cross]c++ [get-define cross]g++ false]
+}
+
+# CXXFLAGS default to CFLAGS if not specified
+define CXXFLAGS [get-env CXXFLAGS [get-define CFLAGS]]
+
+# May need a CC_FOR_BUILD, so look for one
+define CC_FOR_BUILD [find-an-executable [get-env CC_FOR_BUILD ""] cc gcc false]
+
+if {[get-define CC] eq ""} {
+ user-error "Could not find a C compiler. Tried: [join $try ", "]"
+}
+
+define CCACHE [find-an-executable [get-env CCACHE ccache]]
+
+# Initial cctest settings
+cc-store-settings {-cflags {} -includes {} -declare {} -link 0 -lang c -libs {} -code {}}
+set autosetup(cc-include-deps) {}
+
+msg-result "C compiler...[get-define CCACHE] [get-define CC] [get-define CFLAGS]"
+if {[get-define CXX] ne "false"} {
+ msg-result "C++ compiler...[get-define CCACHE] [get-define CXX] [get-define CXXFLAGS]"
+}
+msg-result "Build C compiler...[get-define CC_FOR_BUILD]"
+
+# On Darwin, we prefer to use -gstabs to avoid creating .dSYM directories
+# but some compilers don't support -gstabs, so test for it here.
+switch -glob -- [get-define host] {
+ *-*-darwin* {
+ if {[cctest -cflags {-gstabs}]} {
+ define cc-default-debug -gstabs
+ }
+ }
+}
+
+if {![cc-check-includes stdlib.h]} {
+ user-error "Compiler does not work. See config.log"
+}
ADDED autosetup/config.guess
Index: autosetup/config.guess
==================================================================
--- autosetup/config.guess
+++ autosetup/config.guess
@@ -0,0 +1,1511 @@
+#! /bin/sh
+# Attempt to guess a canonical system name.
+# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+# 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
+# Free Software Foundation, Inc.
+
+timestamp='2010-09-24'
+
+# This file is free software; 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.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
+# 02110-1301, USA.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+
+# Originally written by Per Bothner. Please send patches (context
+# diff format) to and include a ChangeLog
+# entry.
+#
+# This script attempts to guess a canonical system name similar to
+# config.sub. If it succeeds, it prints the system name on stdout, and
+# exits with 0. Otherwise, it exits with 1.
+#
+# You can get the latest version of this script from:
+# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION]
+
+Output the configuration name of the system \`$me' is run on.
+
+Operation modes:
+ -h, --help print this help, then exit
+ -t, --time-stamp print date of last modification, then exit
+ -v, --version print version number, then exit
+
+Report bugs and patches to ."
+
+version="\
+GNU config.guess ($timestamp)
+
+Originally written by Per Bothner.
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
+2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free
+Software Foundation, Inc.
+
+This is free software; see the source for copying conditions. There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+ case $1 in
+ --time-stamp | --time* | -t )
+ echo "$timestamp" ; exit ;;
+ --version | -v )
+ echo "$version" ; exit ;;
+ --help | --h* | -h )
+ echo "$usage"; exit ;;
+ -- ) # Stop option processing
+ shift; break ;;
+ - ) # Use stdin as input.
+ break ;;
+ -* )
+ echo "$me: invalid option $1$help" >&2
+ exit 1 ;;
+ * )
+ break ;;
+ esac
+done
+
+if test $# != 0; then
+ echo "$me: too many arguments$help" >&2
+ exit 1
+fi
+
+trap 'exit 1' HUP INT TERM
+
+# CC_FOR_BUILD -- compiler used by this script. Note that the use of a
+# compiler to aid in system detection is discouraged as it requires
+# temporary files to be created and, as you can see below, it is a
+# headache to deal with in a portable fashion.
+
+# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still
+# use `HOST_CC' if defined, but it is deprecated.
+
+# Portable tmp directory creation inspired by the Autoconf team.
+
+set_cc_for_build='
+trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ;
+trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" HUP INT PIPE TERM ;
+: ${TMPDIR=/tmp} ;
+ { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } ||
+ { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } ||
+ { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } ||
+ { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ;
+dummy=$tmp/dummy ;
+tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ;
+case $CC_FOR_BUILD,$HOST_CC,$CC in
+ ,,) echo "int x;" > $dummy.c ;
+ for c in cc gcc c89 c99 ; do
+ if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then
+ CC_FOR_BUILD="$c"; break ;
+ fi ;
+ done ;
+ if test x"$CC_FOR_BUILD" = x ; then
+ CC_FOR_BUILD=no_compiler_found ;
+ fi
+ ;;
+ ,,*) CC_FOR_BUILD=$CC ;;
+ ,*,*) CC_FOR_BUILD=$HOST_CC ;;
+esac ; set_cc_for_build= ;'
+
+# This is needed to find uname on a Pyramid OSx when run in the BSD universe.
+# (ghazi@noc.rutgers.edu 1994-08-24)
+if (test -f /.attbin/uname) >/dev/null 2>&1 ; then
+ PATH=$PATH:/.attbin ; export PATH
+fi
+
+UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown
+UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
+UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown
+UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
+
+# Note: order is significant - the case branches are not exclusive.
+
+case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
+ *:NetBSD:*:*)
+ # NetBSD (nbsd) targets should (where applicable) match one or
+ # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*,
+ # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently
+ # switched to ELF, *-*-netbsd* would select the old
+ # object file format. This provides both forward
+ # compatibility and a consistent mechanism for selecting the
+ # object file format.
+ #
+ # Note: NetBSD doesn't particularly care about the vendor
+ # portion of the name. We always set it to "unknown".
+ sysctl="sysctl -n hw.machine_arch"
+ UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \
+ /usr/sbin/$sysctl 2>/dev/null || echo unknown)`
+ case "${UNAME_MACHINE_ARCH}" in
+ armeb) machine=armeb-unknown ;;
+ arm*) machine=arm-unknown ;;
+ sh3el) machine=shl-unknown ;;
+ sh3eb) machine=sh-unknown ;;
+ sh5el) machine=sh5le-unknown ;;
+ *) machine=${UNAME_MACHINE_ARCH}-unknown ;;
+ esac
+ # The Operating System including object format, if it has switched
+ # to ELF recently, or will in the future.
+ case "${UNAME_MACHINE_ARCH}" in
+ arm*|i386|m68k|ns32k|sh3*|sparc|vax)
+ eval $set_cc_for_build
+ if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \
+ | grep -q __ELF__
+ then
+ # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout).
+ # Return netbsd for either. FIX?
+ os=netbsd
+ else
+ os=netbsdelf
+ fi
+ ;;
+ *)
+ os=netbsd
+ ;;
+ esac
+ # The OS release
+ # Debian GNU/NetBSD machines have a different userland, and
+ # thus, need a distinct triplet. However, they do not need
+ # kernel version information, so it can be replaced with a
+ # suitable tag, in the style of linux-gnu.
+ case "${UNAME_VERSION}" in
+ Debian*)
+ release='-gnu'
+ ;;
+ *)
+ release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
+ ;;
+ esac
+ # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM:
+ # contains redundant information, the shorter form:
+ # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used.
+ echo "${machine}-${os}${release}"
+ exit ;;
+ *:OpenBSD:*:*)
+ UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'`
+ echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE}
+ exit ;;
+ *:ekkoBSD:*:*)
+ echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE}
+ exit ;;
+ *:SolidBSD:*:*)
+ echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE}
+ exit ;;
+ macppc:MirBSD:*:*)
+ echo powerpc-unknown-mirbsd${UNAME_RELEASE}
+ exit ;;
+ *:MirBSD:*:*)
+ echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE}
+ exit ;;
+ alpha:OSF1:*:*)
+ case $UNAME_RELEASE in
+ *4.0)
+ UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`
+ ;;
+ *5.*)
+ UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'`
+ ;;
+ esac
+ # According to Compaq, /usr/sbin/psrinfo has been available on
+ # OSF/1 and Tru64 systems produced since 1995. I hope that
+ # covers most systems running today. This code pipes the CPU
+ # types through head -n 1, so we only detect the type of CPU 0.
+ ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1`
+ case "$ALPHA_CPU_TYPE" in
+ "EV4 (21064)")
+ UNAME_MACHINE="alpha" ;;
+ "EV4.5 (21064)")
+ UNAME_MACHINE="alpha" ;;
+ "LCA4 (21066/21068)")
+ UNAME_MACHINE="alpha" ;;
+ "EV5 (21164)")
+ UNAME_MACHINE="alphaev5" ;;
+ "EV5.6 (21164A)")
+ UNAME_MACHINE="alphaev56" ;;
+ "EV5.6 (21164PC)")
+ UNAME_MACHINE="alphapca56" ;;
+ "EV5.7 (21164PC)")
+ UNAME_MACHINE="alphapca57" ;;
+ "EV6 (21264)")
+ UNAME_MACHINE="alphaev6" ;;
+ "EV6.7 (21264A)")
+ UNAME_MACHINE="alphaev67" ;;
+ "EV6.8CB (21264C)")
+ UNAME_MACHINE="alphaev68" ;;
+ "EV6.8AL (21264B)")
+ UNAME_MACHINE="alphaev68" ;;
+ "EV6.8CX (21264D)")
+ UNAME_MACHINE="alphaev68" ;;
+ "EV6.9A (21264/EV69A)")
+ UNAME_MACHINE="alphaev69" ;;
+ "EV7 (21364)")
+ UNAME_MACHINE="alphaev7" ;;
+ "EV7.9 (21364A)")
+ UNAME_MACHINE="alphaev79" ;;
+ esac
+ # A Pn.n version is a patched version.
+ # A Vn.n version is a released version.
+ # A Tn.n version is a released field test version.
+ # A Xn.n version is an unreleased experimental baselevel.
+ # 1.2 uses "1.2" for uname -r.
+ echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+ exit ;;
+ Alpha\ *:Windows_NT*:*)
+ # How do we know it's Interix rather than the generic POSIX subsystem?
+ # Should we change UNAME_MACHINE based on the output of uname instead
+ # of the specific Alpha model?
+ echo alpha-pc-interix
+ exit ;;
+ 21064:Windows_NT:50:3)
+ echo alpha-dec-winnt3.5
+ exit ;;
+ Amiga*:UNIX_System_V:4.0:*)
+ echo m68k-unknown-sysv4
+ exit ;;
+ *:[Aa]miga[Oo][Ss]:*:*)
+ echo ${UNAME_MACHINE}-unknown-amigaos
+ exit ;;
+ *:[Mm]orph[Oo][Ss]:*:*)
+ echo ${UNAME_MACHINE}-unknown-morphos
+ exit ;;
+ *:OS/390:*:*)
+ echo i370-ibm-openedition
+ exit ;;
+ *:z/VM:*:*)
+ echo s390-ibm-zvmoe
+ exit ;;
+ *:OS400:*:*)
+ echo powerpc-ibm-os400
+ exit ;;
+ arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
+ echo arm-acorn-riscix${UNAME_RELEASE}
+ exit ;;
+ arm:riscos:*:*|arm:RISCOS:*:*)
+ echo arm-unknown-riscos
+ exit ;;
+ SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*)
+ echo hppa1.1-hitachi-hiuxmpp
+ exit ;;
+ Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*)
+ # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE.
+ if test "`(/bin/universe) 2>/dev/null`" = att ; then
+ echo pyramid-pyramid-sysv3
+ else
+ echo pyramid-pyramid-bsd
+ fi
+ exit ;;
+ NILE*:*:*:dcosx)
+ echo pyramid-pyramid-svr4
+ exit ;;
+ DRS?6000:unix:4.0:6*)
+ echo sparc-icl-nx6
+ exit ;;
+ DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*)
+ case `/usr/bin/uname -p` in
+ sparc) echo sparc-icl-nx7; exit ;;
+ esac ;;
+ s390x:SunOS:*:*)
+ echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
+ sun4H:SunOS:5.*:*)
+ echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
+ sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
+ echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
+ i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*)
+ echo i386-pc-auroraux${UNAME_RELEASE}
+ exit ;;
+ i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*)
+ eval $set_cc_for_build
+ SUN_ARCH="i386"
+ # If there is a compiler, see if it is configured for 64-bit objects.
+ # Note that the Sun cc does not turn __LP64__ into 1 like gcc does.
+ # This test works for both compilers.
+ if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
+ if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \
+ (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
+ grep IS_64BIT_ARCH >/dev/null
+ then
+ SUN_ARCH="x86_64"
+ fi
+ fi
+ echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
+ sun4*:SunOS:6*:*)
+ # According to config.sub, this is the proper way to canonicalize
+ # SunOS6. Hard to guess exactly what SunOS6 will be like, but
+ # it's likely to be more like Solaris than SunOS4.
+ echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
+ sun4*:SunOS:*:*)
+ case "`/usr/bin/arch -k`" in
+ Series*|S4*)
+ UNAME_RELEASE=`uname -v`
+ ;;
+ esac
+ # Japanese Language versions have a version number like `4.1.3-JL'.
+ echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'`
+ exit ;;
+ sun3*:SunOS:*:*)
+ echo m68k-sun-sunos${UNAME_RELEASE}
+ exit ;;
+ sun*:*:4.2BSD:*)
+ UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
+ test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3
+ case "`/bin/arch`" in
+ sun3)
+ echo m68k-sun-sunos${UNAME_RELEASE}
+ ;;
+ sun4)
+ echo sparc-sun-sunos${UNAME_RELEASE}
+ ;;
+ esac
+ exit ;;
+ aushp:SunOS:*:*)
+ echo sparc-auspex-sunos${UNAME_RELEASE}
+ exit ;;
+ # The situation for MiNT is a little confusing. The machine name
+ # can be virtually everything (everything which is not
+ # "atarist" or "atariste" at least should have a processor
+ # > m68000). The system name ranges from "MiNT" over "FreeMiNT"
+ # to the lowercase version "mint" (or "freemint"). Finally
+ # the system name "TOS" denotes a system which is actually not
+ # MiNT. But MiNT is downward compatible to TOS, so this should
+ # be no problem.
+ atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*)
+ echo m68k-atari-mint${UNAME_RELEASE}
+ exit ;;
+ atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*)
+ echo m68k-atari-mint${UNAME_RELEASE}
+ exit ;;
+ *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*)
+ echo m68k-atari-mint${UNAME_RELEASE}
+ exit ;;
+ milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*)
+ echo m68k-milan-mint${UNAME_RELEASE}
+ exit ;;
+ hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*)
+ echo m68k-hades-mint${UNAME_RELEASE}
+ exit ;;
+ *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*)
+ echo m68k-unknown-mint${UNAME_RELEASE}
+ exit ;;
+ m68k:machten:*:*)
+ echo m68k-apple-machten${UNAME_RELEASE}
+ exit ;;
+ powerpc:machten:*:*)
+ echo powerpc-apple-machten${UNAME_RELEASE}
+ exit ;;
+ RISC*:Mach:*:*)
+ echo mips-dec-mach_bsd4.3
+ exit ;;
+ RISC*:ULTRIX:*:*)
+ echo mips-dec-ultrix${UNAME_RELEASE}
+ exit ;;
+ VAX*:ULTRIX*:*:*)
+ echo vax-dec-ultrix${UNAME_RELEASE}
+ exit ;;
+ 2020:CLIX:*:* | 2430:CLIX:*:*)
+ echo clipper-intergraph-clix${UNAME_RELEASE}
+ exit ;;
+ mips:*:*:UMIPS | mips:*:*:RISCos)
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+#ifdef __cplusplus
+#include /* for printf() prototype */
+ int main (int argc, char *argv[]) {
+#else
+ int main (argc, argv) int argc; char *argv[]; {
+#endif
+ #if defined (host_mips) && defined (MIPSEB)
+ #if defined (SYSTYPE_SYSV)
+ printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0);
+ #endif
+ #if defined (SYSTYPE_SVR4)
+ printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0);
+ #endif
+ #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD)
+ printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0);
+ #endif
+ #endif
+ exit (-1);
+ }
+EOF
+ $CC_FOR_BUILD -o $dummy $dummy.c &&
+ dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` &&
+ SYSTEM_NAME=`$dummy $dummyarg` &&
+ { echo "$SYSTEM_NAME"; exit; }
+ echo mips-mips-riscos${UNAME_RELEASE}
+ exit ;;
+ Motorola:PowerMAX_OS:*:*)
+ echo powerpc-motorola-powermax
+ exit ;;
+ Motorola:*:4.3:PL8-*)
+ echo powerpc-harris-powermax
+ exit ;;
+ Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*)
+ echo powerpc-harris-powermax
+ exit ;;
+ Night_Hawk:Power_UNIX:*:*)
+ echo powerpc-harris-powerunix
+ exit ;;
+ m88k:CX/UX:7*:*)
+ echo m88k-harris-cxux7
+ exit ;;
+ m88k:*:4*:R4*)
+ echo m88k-motorola-sysv4
+ exit ;;
+ m88k:*:3*:R3*)
+ echo m88k-motorola-sysv3
+ exit ;;
+ AViiON:dgux:*:*)
+ # DG/UX returns AViiON for all architectures
+ UNAME_PROCESSOR=`/usr/bin/uname -p`
+ if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ]
+ then
+ if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \
+ [ ${TARGET_BINARY_INTERFACE}x = x ]
+ then
+ echo m88k-dg-dgux${UNAME_RELEASE}
+ else
+ echo m88k-dg-dguxbcs${UNAME_RELEASE}
+ fi
+ else
+ echo i586-dg-dgux${UNAME_RELEASE}
+ fi
+ exit ;;
+ M88*:DolphinOS:*:*) # DolphinOS (SVR3)
+ echo m88k-dolphin-sysv3
+ exit ;;
+ M88*:*:R3*:*)
+ # Delta 88k system running SVR3
+ echo m88k-motorola-sysv3
+ exit ;;
+ XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3)
+ echo m88k-tektronix-sysv3
+ exit ;;
+ Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD)
+ echo m68k-tektronix-bsd
+ exit ;;
+ *:IRIX*:*:*)
+ echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'`
+ exit ;;
+ ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX.
+ echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id
+ exit ;; # Note that: echo "'`uname -s`'" gives 'AIX '
+ i*86:AIX:*:*)
+ echo i386-ibm-aix
+ exit ;;
+ ia64:AIX:*:*)
+ if [ -x /usr/bin/oslevel ] ; then
+ IBM_REV=`/usr/bin/oslevel`
+ else
+ IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+ fi
+ echo ${UNAME_MACHINE}-ibm-aix${IBM_REV}
+ exit ;;
+ *:AIX:2:3)
+ if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #include
+
+ main()
+ {
+ if (!__power_pc())
+ exit(1);
+ puts("powerpc-ibm-aix3.2.5");
+ exit(0);
+ }
+EOF
+ if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy`
+ then
+ echo "$SYSTEM_NAME"
+ else
+ echo rs6000-ibm-aix3.2.5
+ fi
+ elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then
+ echo rs6000-ibm-aix3.2.4
+ else
+ echo rs6000-ibm-aix3.2
+ fi
+ exit ;;
+ *:AIX:*:[4567])
+ IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'`
+ if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then
+ IBM_ARCH=rs6000
+ else
+ IBM_ARCH=powerpc
+ fi
+ if [ -x /usr/bin/oslevel ] ; then
+ IBM_REV=`/usr/bin/oslevel`
+ else
+ IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+ fi
+ echo ${IBM_ARCH}-ibm-aix${IBM_REV}
+ exit ;;
+ *:AIX:*:*)
+ echo rs6000-ibm-aix
+ exit ;;
+ ibmrt:4.4BSD:*|romp-ibm:BSD:*)
+ echo romp-ibm-bsd4.4
+ exit ;;
+ ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and
+ echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to
+ exit ;; # report: romp-ibm BSD 4.3
+ *:BOSX:*:*)
+ echo rs6000-bull-bosx
+ exit ;;
+ DPX/2?00:B.O.S.:*:*)
+ echo m68k-bull-sysv3
+ exit ;;
+ 9000/[34]??:4.3bsd:1.*:*)
+ echo m68k-hp-bsd
+ exit ;;
+ hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*)
+ echo m68k-hp-bsd4.4
+ exit ;;
+ 9000/[34678]??:HP-UX:*:*)
+ HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+ case "${UNAME_MACHINE}" in
+ 9000/31? ) HP_ARCH=m68000 ;;
+ 9000/[34]?? ) HP_ARCH=m68k ;;
+ 9000/[678][0-9][0-9])
+ if [ -x /usr/bin/getconf ]; then
+ sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null`
+ sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null`
+ case "${sc_cpu_version}" in
+ 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0
+ 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1
+ 532) # CPU_PA_RISC2_0
+ case "${sc_kernel_bits}" in
+ 32) HP_ARCH="hppa2.0n" ;;
+ 64) HP_ARCH="hppa2.0w" ;;
+ '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20
+ esac ;;
+ esac
+ fi
+ if [ "${HP_ARCH}" = "" ]; then
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+
+ #define _HPUX_SOURCE
+ #include
+ #include
+
+ int main ()
+ {
+ #if defined(_SC_KERNEL_BITS)
+ long bits = sysconf(_SC_KERNEL_BITS);
+ #endif
+ long cpu = sysconf (_SC_CPU_VERSION);
+
+ switch (cpu)
+ {
+ case CPU_PA_RISC1_0: puts ("hppa1.0"); break;
+ case CPU_PA_RISC1_1: puts ("hppa1.1"); break;
+ case CPU_PA_RISC2_0:
+ #if defined(_SC_KERNEL_BITS)
+ switch (bits)
+ {
+ case 64: puts ("hppa2.0w"); break;
+ case 32: puts ("hppa2.0n"); break;
+ default: puts ("hppa2.0"); break;
+ } break;
+ #else /* !defined(_SC_KERNEL_BITS) */
+ puts ("hppa2.0"); break;
+ #endif
+ default: puts ("hppa1.0"); break;
+ }
+ exit (0);
+ }
+EOF
+ (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy`
+ test -z "$HP_ARCH" && HP_ARCH=hppa
+ fi ;;
+ esac
+ if [ ${HP_ARCH} = "hppa2.0w" ]
+ then
+ eval $set_cc_for_build
+
+ # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating
+ # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler
+ # generating 64-bit code. GNU and HP use different nomenclature:
+ #
+ # $ CC_FOR_BUILD=cc ./config.guess
+ # => hppa2.0w-hp-hpux11.23
+ # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess
+ # => hppa64-hp-hpux11.23
+
+ if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) |
+ grep -q __LP64__
+ then
+ HP_ARCH="hppa2.0w"
+ else
+ HP_ARCH="hppa64"
+ fi
+ fi
+ echo ${HP_ARCH}-hp-hpux${HPUX_REV}
+ exit ;;
+ ia64:HP-UX:*:*)
+ HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+ echo ia64-hp-hpux${HPUX_REV}
+ exit ;;
+ 3050*:HI-UX:*:*)
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #include
+ int
+ main ()
+ {
+ long cpu = sysconf (_SC_CPU_VERSION);
+ /* The order matters, because CPU_IS_HP_MC68K erroneously returns
+ true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct
+ results, however. */
+ if (CPU_IS_PA_RISC (cpu))
+ {
+ switch (cpu)
+ {
+ case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break;
+ case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break;
+ case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break;
+ default: puts ("hppa-hitachi-hiuxwe2"); break;
+ }
+ }
+ else if (CPU_IS_HP_MC68K (cpu))
+ puts ("m68k-hitachi-hiuxwe2");
+ else puts ("unknown-hitachi-hiuxwe2");
+ exit (0);
+ }
+EOF
+ $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` &&
+ { echo "$SYSTEM_NAME"; exit; }
+ echo unknown-hitachi-hiuxwe2
+ exit ;;
+ 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* )
+ echo hppa1.1-hp-bsd
+ exit ;;
+ 9000/8??:4.3bsd:*:*)
+ echo hppa1.0-hp-bsd
+ exit ;;
+ *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*)
+ echo hppa1.0-hp-mpeix
+ exit ;;
+ hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* )
+ echo hppa1.1-hp-osf
+ exit ;;
+ hp8??:OSF1:*:*)
+ echo hppa1.0-hp-osf
+ exit ;;
+ i*86:OSF1:*:*)
+ if [ -x /usr/sbin/sysversion ] ; then
+ echo ${UNAME_MACHINE}-unknown-osf1mk
+ else
+ echo ${UNAME_MACHINE}-unknown-osf1
+ fi
+ exit ;;
+ parisc*:Lites*:*:*)
+ echo hppa1.1-hp-lites
+ exit ;;
+ C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
+ echo c1-convex-bsd
+ exit ;;
+ C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
+ if getsysinfo -f scalar_acc
+ then echo c32-convex-bsd
+ else echo c2-convex-bsd
+ fi
+ exit ;;
+ C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
+ echo c34-convex-bsd
+ exit ;;
+ C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
+ echo c38-convex-bsd
+ exit ;;
+ C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
+ echo c4-convex-bsd
+ exit ;;
+ CRAY*Y-MP:*:*:*)
+ echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ CRAY*[A-Z]90:*:*:*)
+ echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \
+ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \
+ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \
+ -e 's/\.[^.]*$/.X/'
+ exit ;;
+ CRAY*TS:*:*:*)
+ echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ CRAY*T3E:*:*:*)
+ echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ CRAY*SV1:*:*:*)
+ echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ *:UNICOS/mp:*:*)
+ echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*)
+ FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+ FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+ FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
+ echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+ exit ;;
+ 5000:UNIX_System_V:4.*:*)
+ FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+ FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'`
+ echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+ exit ;;
+ i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
+ echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE}
+ exit ;;
+ sparc*:BSD/OS:*:*)
+ echo sparc-unknown-bsdi${UNAME_RELEASE}
+ exit ;;
+ *:BSD/OS:*:*)
+ echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
+ exit ;;
+ *:FreeBSD:*:*)
+ case ${UNAME_MACHINE} in
+ pc98)
+ echo i386-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+ amd64)
+ echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+ *)
+ echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+ esac
+ exit ;;
+ i*:CYGWIN*:*)
+ echo ${UNAME_MACHINE}-pc-cygwin
+ exit ;;
+ *:MINGW*:*)
+ echo ${UNAME_MACHINE}-pc-mingw32
+ exit ;;
+ i*:MSYS*:*)
+ echo ${UNAME_MACHINE}-pc-msys
+ exit ;;
+ i*:windows32*:*)
+ # uname -m includes "-pc" on this system.
+ echo ${UNAME_MACHINE}-mingw32
+ exit ;;
+ i*:PW*:*)
+ echo ${UNAME_MACHINE}-pc-pw32
+ exit ;;
+ *:Interix*:*)
+ case ${UNAME_MACHINE} in
+ x86)
+ echo i586-pc-interix${UNAME_RELEASE}
+ exit ;;
+ authenticamd | genuineintel | EM64T)
+ echo x86_64-unknown-interix${UNAME_RELEASE}
+ exit ;;
+ IA64)
+ echo ia64-unknown-interix${UNAME_RELEASE}
+ exit ;;
+ esac ;;
+ [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*)
+ echo i${UNAME_MACHINE}-pc-mks
+ exit ;;
+ 8664:Windows_NT:*)
+ echo x86_64-pc-mks
+ exit ;;
+ i*:Windows_NT*:* | Pentium*:Windows_NT*:*)
+ # How do we know it's Interix rather than the generic POSIX subsystem?
+ # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we
+ # UNAME_MACHINE based on the output of uname instead of i386?
+ echo i586-pc-interix
+ exit ;;
+ i*:UWIN*:*)
+ echo ${UNAME_MACHINE}-pc-uwin
+ exit ;;
+ amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*)
+ echo x86_64-unknown-cygwin
+ exit ;;
+ p*:CYGWIN*:*)
+ echo powerpcle-unknown-cygwin
+ exit ;;
+ prep*:SunOS:5.*:*)
+ echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
+ *:GNU:*:*)
+ # the GNU system
+ echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
+ exit ;;
+ *:GNU/*:*:*)
+ # other systems with GNU libc and userland
+ echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu
+ exit ;;
+ i*86:Minix:*:*)
+ echo ${UNAME_MACHINE}-pc-minix
+ exit ;;
+ alpha:Linux:*:*)
+ case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in
+ EV5) UNAME_MACHINE=alphaev5 ;;
+ EV56) UNAME_MACHINE=alphaev56 ;;
+ PCA56) UNAME_MACHINE=alphapca56 ;;
+ PCA57) UNAME_MACHINE=alphapca56 ;;
+ EV6) UNAME_MACHINE=alphaev6 ;;
+ EV67) UNAME_MACHINE=alphaev67 ;;
+ EV68*) UNAME_MACHINE=alphaev68 ;;
+ esac
+ objdump --private-headers /bin/sh | grep -q ld.so.1
+ if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi
+ echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC}
+ exit ;;
+ arm*:Linux:*:*)
+ eval $set_cc_for_build
+ if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \
+ | grep -q __ARM_EABI__
+ then
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ else
+ echo ${UNAME_MACHINE}-unknown-linux-gnueabi
+ fi
+ exit ;;
+ avr32*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ cris:Linux:*:*)
+ echo cris-axis-linux-gnu
+ exit ;;
+ crisv32:Linux:*:*)
+ echo crisv32-axis-linux-gnu
+ exit ;;
+ frv:Linux:*:*)
+ echo frv-unknown-linux-gnu
+ exit ;;
+ i*86:Linux:*:*)
+ LIBC=gnu
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #ifdef __dietlibc__
+ LIBC=dietlibc
+ #endif
+EOF
+ eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC'`
+ echo "${UNAME_MACHINE}-pc-linux-${LIBC}"
+ exit ;;
+ ia64:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ m32r*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ m68*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ mips:Linux:*:* | mips64:Linux:*:*)
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #undef CPU
+ #undef ${UNAME_MACHINE}
+ #undef ${UNAME_MACHINE}el
+ #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
+ CPU=${UNAME_MACHINE}el
+ #else
+ #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
+ CPU=${UNAME_MACHINE}
+ #else
+ CPU=
+ #endif
+ #endif
+EOF
+ eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'`
+ test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; }
+ ;;
+ or32:Linux:*:*)
+ echo or32-unknown-linux-gnu
+ exit ;;
+ padre:Linux:*:*)
+ echo sparc-unknown-linux-gnu
+ exit ;;
+ parisc64:Linux:*:* | hppa64:Linux:*:*)
+ echo hppa64-unknown-linux-gnu
+ exit ;;
+ parisc:Linux:*:* | hppa:Linux:*:*)
+ # Look for CPU level
+ case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in
+ PA7*) echo hppa1.1-unknown-linux-gnu ;;
+ PA8*) echo hppa2.0-unknown-linux-gnu ;;
+ *) echo hppa-unknown-linux-gnu ;;
+ esac
+ exit ;;
+ ppc64:Linux:*:*)
+ echo powerpc64-unknown-linux-gnu
+ exit ;;
+ ppc:Linux:*:*)
+ echo powerpc-unknown-linux-gnu
+ exit ;;
+ s390:Linux:*:* | s390x:Linux:*:*)
+ echo ${UNAME_MACHINE}-ibm-linux
+ exit ;;
+ sh64*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ sh*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ sparc:Linux:*:* | sparc64:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ tile*:Linux:*:*)
+ echo ${UNAME_MACHINE}-tilera-linux-gnu
+ exit ;;
+ vax:Linux:*:*)
+ echo ${UNAME_MACHINE}-dec-linux-gnu
+ exit ;;
+ x86_64:Linux:*:*)
+ echo x86_64-unknown-linux-gnu
+ exit ;;
+ xtensa*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-gnu
+ exit ;;
+ i*86:DYNIX/ptx:4*:*)
+ # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.
+ # earlier versions are messed up and put the nodename in both
+ # sysname and nodename.
+ echo i386-sequent-sysv4
+ exit ;;
+ i*86:UNIX_SV:4.2MP:2.*)
+ # Unixware is an offshoot of SVR4, but it has its own version
+ # number series starting with 2...
+ # I am not positive that other SVR4 systems won't match this,
+ # I just have to hope. -- rms.
+ # Use sysv4.2uw... so that sysv4* matches it.
+ echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION}
+ exit ;;
+ i*86:OS/2:*:*)
+ # If we were able to find `uname', then EMX Unix compatibility
+ # is probably installed.
+ echo ${UNAME_MACHINE}-pc-os2-emx
+ exit ;;
+ i*86:XTS-300:*:STOP)
+ echo ${UNAME_MACHINE}-unknown-stop
+ exit ;;
+ i*86:atheos:*:*)
+ echo ${UNAME_MACHINE}-unknown-atheos
+ exit ;;
+ i*86:syllable:*:*)
+ echo ${UNAME_MACHINE}-pc-syllable
+ exit ;;
+ i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*)
+ echo i386-unknown-lynxos${UNAME_RELEASE}
+ exit ;;
+ i*86:*DOS:*:*)
+ echo ${UNAME_MACHINE}-pc-msdosdjgpp
+ exit ;;
+ i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*)
+ UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'`
+ if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
+ echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL}
+ else
+ echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL}
+ fi
+ exit ;;
+ i*86:*:5:[678]*)
+ # UnixWare 7.x, OpenUNIX and OpenServer 6.
+ case `/bin/uname -X | grep "^Machine"` in
+ *486*) UNAME_MACHINE=i486 ;;
+ *Pentium) UNAME_MACHINE=i586 ;;
+ *Pent*|*Celeron) UNAME_MACHINE=i686 ;;
+ esac
+ echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION}
+ exit ;;
+ i*86:*:3.2:*)
+ if test -f /usr/options/cb.name; then
+ UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then
+ UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')`
+ (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486
+ (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \
+ && UNAME_MACHINE=i586
+ (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \
+ && UNAME_MACHINE=i686
+ (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \
+ && UNAME_MACHINE=i686
+ echo ${UNAME_MACHINE}-pc-sco$UNAME_REL
+ else
+ echo ${UNAME_MACHINE}-pc-sysv32
+ fi
+ exit ;;
+ pc:*:*:*)
+ # Left here for compatibility:
+ # uname -m prints for DJGPP always 'pc', but it prints nothing about
+ # the processor, so we play safe by assuming i586.
+ # Note: whatever this is, it MUST be the same as what config.sub
+ # prints for the "djgpp" host, or else GDB configury will decide that
+ # this is a cross-build.
+ echo i586-pc-msdosdjgpp
+ exit ;;
+ Intel:Mach:3*:*)
+ echo i386-pc-mach3
+ exit ;;
+ paragon:*:*:*)
+ echo i860-intel-osf1
+ exit ;;
+ i860:*:4.*:*) # i860-SVR4
+ if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then
+ echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4
+ else # Add other i860-SVR4 vendors below as they are discovered.
+ echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4
+ fi
+ exit ;;
+ mini*:CTIX:SYS*5:*)
+ # "miniframe"
+ echo m68010-convergent-sysv
+ exit ;;
+ mc68k:UNIX:SYSTEM5:3.51m)
+ echo m68k-convergent-sysv
+ exit ;;
+ M680?0:D-NIX:5.3:*)
+ echo m68k-diab-dnix
+ exit ;;
+ M68*:*:R3V[5678]*:*)
+ test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;;
+ 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0)
+ OS_REL=''
+ test -r /etc/.relid \
+ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+ /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+ && { echo i486-ncr-sysv4.3${OS_REL}; exit; }
+ /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;
+ 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
+ /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+ && { echo i486-ncr-sysv4; exit; } ;;
+ NCR*:*:4.2:* | MPRAS*:*:4.2:*)
+ OS_REL='.3'
+ test -r /etc/.relid \
+ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+ /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+ && { echo i486-ncr-sysv4.3${OS_REL}; exit; }
+ /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+ && { echo i586-ncr-sysv4.3${OS_REL}; exit; }
+ /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \
+ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;
+ m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*)
+ echo m68k-unknown-lynxos${UNAME_RELEASE}
+ exit ;;
+ mc68030:UNIX_System_V:4.*:*)
+ echo m68k-atari-sysv4
+ exit ;;
+ TSUNAMI:LynxOS:2.*:*)
+ echo sparc-unknown-lynxos${UNAME_RELEASE}
+ exit ;;
+ rs6000:LynxOS:2.*:*)
+ echo rs6000-unknown-lynxos${UNAME_RELEASE}
+ exit ;;
+ PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*)
+ echo powerpc-unknown-lynxos${UNAME_RELEASE}
+ exit ;;
+ SM[BE]S:UNIX_SV:*:*)
+ echo mips-dde-sysv${UNAME_RELEASE}
+ exit ;;
+ RM*:ReliantUNIX-*:*:*)
+ echo mips-sni-sysv4
+ exit ;;
+ RM*:SINIX-*:*:*)
+ echo mips-sni-sysv4
+ exit ;;
+ *:SINIX-*:*:*)
+ if uname -p 2>/dev/null >/dev/null ; then
+ UNAME_MACHINE=`(uname -p) 2>/dev/null`
+ echo ${UNAME_MACHINE}-sni-sysv4
+ else
+ echo ns32k-sni-sysv
+ fi
+ exit ;;
+ PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
+ # says
+ echo i586-unisys-sysv4
+ exit ;;
+ *:UNIX_System_V:4*:FTX*)
+ # From Gerald Hewes .
+ # How about differentiating between stratus architectures? -djm
+ echo hppa1.1-stratus-sysv4
+ exit ;;
+ *:*:*:FTX*)
+ # From seanf@swdc.stratus.com.
+ echo i860-stratus-sysv4
+ exit ;;
+ i*86:VOS:*:*)
+ # From Paul.Green@stratus.com.
+ echo ${UNAME_MACHINE}-stratus-vos
+ exit ;;
+ *:VOS:*:*)
+ # From Paul.Green@stratus.com.
+ echo hppa1.1-stratus-vos
+ exit ;;
+ mc68*:A/UX:*:*)
+ echo m68k-apple-aux${UNAME_RELEASE}
+ exit ;;
+ news*:NEWS-OS:6*:*)
+ echo mips-sony-newsos6
+ exit ;;
+ R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*)
+ if [ -d /usr/nec ]; then
+ echo mips-nec-sysv${UNAME_RELEASE}
+ else
+ echo mips-unknown-sysv${UNAME_RELEASE}
+ fi
+ exit ;;
+ BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only.
+ echo powerpc-be-beos
+ exit ;;
+ BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only.
+ echo powerpc-apple-beos
+ exit ;;
+ BePC:BeOS:*:*) # BeOS running on Intel PC compatible.
+ echo i586-pc-beos
+ exit ;;
+ BePC:Haiku:*:*) # Haiku running on Intel PC compatible.
+ echo i586-pc-haiku
+ exit ;;
+ SX-4:SUPER-UX:*:*)
+ echo sx4-nec-superux${UNAME_RELEASE}
+ exit ;;
+ SX-5:SUPER-UX:*:*)
+ echo sx5-nec-superux${UNAME_RELEASE}
+ exit ;;
+ SX-6:SUPER-UX:*:*)
+ echo sx6-nec-superux${UNAME_RELEASE}
+ exit ;;
+ SX-7:SUPER-UX:*:*)
+ echo sx7-nec-superux${UNAME_RELEASE}
+ exit ;;
+ SX-8:SUPER-UX:*:*)
+ echo sx8-nec-superux${UNAME_RELEASE}
+ exit ;;
+ SX-8R:SUPER-UX:*:*)
+ echo sx8r-nec-superux${UNAME_RELEASE}
+ exit ;;
+ Power*:Rhapsody:*:*)
+ echo powerpc-apple-rhapsody${UNAME_RELEASE}
+ exit ;;
+ *:Rhapsody:*:*)
+ echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE}
+ exit ;;
+ *:Darwin:*:*)
+ UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown
+ case $UNAME_PROCESSOR in
+ i386)
+ eval $set_cc_for_build
+ if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
+ if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \
+ (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
+ grep IS_64BIT_ARCH >/dev/null
+ then
+ UNAME_PROCESSOR="x86_64"
+ fi
+ fi ;;
+ unknown) UNAME_PROCESSOR=powerpc ;;
+ esac
+ echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE}
+ exit ;;
+ *:procnto*:*:* | *:QNX:[0123456789]*:*)
+ UNAME_PROCESSOR=`uname -p`
+ if test "$UNAME_PROCESSOR" = "x86"; then
+ UNAME_PROCESSOR=i386
+ UNAME_MACHINE=pc
+ fi
+ echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE}
+ exit ;;
+ *:QNX:*:4*)
+ echo i386-pc-qnx
+ exit ;;
+ NEO-?:NONSTOP_KERNEL:*:*)
+ echo neo-tandem-nsk${UNAME_RELEASE}
+ exit ;;
+ NSE-?:NONSTOP_KERNEL:*:*)
+ echo nse-tandem-nsk${UNAME_RELEASE}
+ exit ;;
+ NSR-?:NONSTOP_KERNEL:*:*)
+ echo nsr-tandem-nsk${UNAME_RELEASE}
+ exit ;;
+ *:NonStop-UX:*:*)
+ echo mips-compaq-nonstopux
+ exit ;;
+ BS2000:POSIX*:*:*)
+ echo bs2000-siemens-sysv
+ exit ;;
+ DS/*:UNIX_System_V:*:*)
+ echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE}
+ exit ;;
+ *:Plan9:*:*)
+ # "uname -m" is not consistent, so use $cputype instead. 386
+ # is converted to i386 for consistency with other x86
+ # operating systems.
+ if test "$cputype" = "386"; then
+ UNAME_MACHINE=i386
+ else
+ UNAME_MACHINE="$cputype"
+ fi
+ echo ${UNAME_MACHINE}-unknown-plan9
+ exit ;;
+ *:TOPS-10:*:*)
+ echo pdp10-unknown-tops10
+ exit ;;
+ *:TENEX:*:*)
+ echo pdp10-unknown-tenex
+ exit ;;
+ KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*)
+ echo pdp10-dec-tops20
+ exit ;;
+ XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*)
+ echo pdp10-xkl-tops20
+ exit ;;
+ *:TOPS-20:*:*)
+ echo pdp10-unknown-tops20
+ exit ;;
+ *:ITS:*:*)
+ echo pdp10-unknown-its
+ exit ;;
+ SEI:*:*:SEIUX)
+ echo mips-sei-seiux${UNAME_RELEASE}
+ exit ;;
+ *:DragonFly:*:*)
+ echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
+ exit ;;
+ *:*VMS:*:*)
+ UNAME_MACHINE=`(uname -p) 2>/dev/null`
+ case "${UNAME_MACHINE}" in
+ A*) echo alpha-dec-vms ; exit ;;
+ I*) echo ia64-dec-vms ; exit ;;
+ V*) echo vax-dec-vms ; exit ;;
+ esac ;;
+ *:XENIX:*:SysV)
+ echo i386-pc-xenix
+ exit ;;
+ i*86:skyos:*:*)
+ echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//'
+ exit ;;
+ i*86:rdos:*:*)
+ echo ${UNAME_MACHINE}-pc-rdos
+ exit ;;
+ i*86:AROS:*:*)
+ echo ${UNAME_MACHINE}-pc-aros
+ exit ;;
+esac
+
+#echo '(No uname command or uname output not recognized.)' 1>&2
+#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2
+
+eval $set_cc_for_build
+cat >$dummy.c <
+# include
+#endif
+main ()
+{
+#if defined (sony)
+#if defined (MIPSEB)
+ /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed,
+ I don't know.... */
+ printf ("mips-sony-bsd\n"); exit (0);
+#else
+#include
+ printf ("m68k-sony-newsos%s\n",
+#ifdef NEWSOS4
+ "4"
+#else
+ ""
+#endif
+ ); exit (0);
+#endif
+#endif
+
+#if defined (__arm) && defined (__acorn) && defined (__unix)
+ printf ("arm-acorn-riscix\n"); exit (0);
+#endif
+
+#if defined (hp300) && !defined (hpux)
+ printf ("m68k-hp-bsd\n"); exit (0);
+#endif
+
+#if defined (NeXT)
+#if !defined (__ARCHITECTURE__)
+#define __ARCHITECTURE__ "m68k"
+#endif
+ int version;
+ version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`;
+ if (version < 4)
+ printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version);
+ else
+ printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version);
+ exit (0);
+#endif
+
+#if defined (MULTIMAX) || defined (n16)
+#if defined (UMAXV)
+ printf ("ns32k-encore-sysv\n"); exit (0);
+#else
+#if defined (CMU)
+ printf ("ns32k-encore-mach\n"); exit (0);
+#else
+ printf ("ns32k-encore-bsd\n"); exit (0);
+#endif
+#endif
+#endif
+
+#if defined (__386BSD__)
+ printf ("i386-pc-bsd\n"); exit (0);
+#endif
+
+#if defined (sequent)
+#if defined (i386)
+ printf ("i386-sequent-dynix\n"); exit (0);
+#endif
+#if defined (ns32000)
+ printf ("ns32k-sequent-dynix\n"); exit (0);
+#endif
+#endif
+
+#if defined (_SEQUENT_)
+ struct utsname un;
+
+ uname(&un);
+
+ if (strncmp(un.version, "V2", 2) == 0) {
+ printf ("i386-sequent-ptx2\n"); exit (0);
+ }
+ if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */
+ printf ("i386-sequent-ptx1\n"); exit (0);
+ }
+ printf ("i386-sequent-ptx\n"); exit (0);
+
+#endif
+
+#if defined (vax)
+# if !defined (ultrix)
+# include
+# if defined (BSD)
+# if BSD == 43
+ printf ("vax-dec-bsd4.3\n"); exit (0);
+# else
+# if BSD == 199006
+ printf ("vax-dec-bsd4.3reno\n"); exit (0);
+# else
+ printf ("vax-dec-bsd\n"); exit (0);
+# endif
+# endif
+# else
+ printf ("vax-dec-bsd\n"); exit (0);
+# endif
+# else
+ printf ("vax-dec-ultrix\n"); exit (0);
+# endif
+#endif
+
+#if defined (alliant) && defined (i860)
+ printf ("i860-alliant-bsd\n"); exit (0);
+#endif
+
+ exit (1);
+}
+EOF
+
+$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` &&
+ { echo "$SYSTEM_NAME"; exit; }
+
+# Apollos put the system type in the environment.
+
+test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; }
+
+# Convex versions that predate uname can use getsysinfo(1)
+
+if [ -x /usr/convex/getsysinfo ]
+then
+ case `getsysinfo -f cpu_type` in
+ c1*)
+ echo c1-convex-bsd
+ exit ;;
+ c2*)
+ if getsysinfo -f scalar_acc
+ then echo c32-convex-bsd
+ else echo c2-convex-bsd
+ fi
+ exit ;;
+ c34*)
+ echo c34-convex-bsd
+ exit ;;
+ c38*)
+ echo c38-convex-bsd
+ exit ;;
+ c4*)
+ echo c4-convex-bsd
+ exit ;;
+ esac
+fi
+
+cat >&2 < in order to provide the needed
+information to handle your system.
+
+config.guess timestamp = $timestamp
+
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null`
+/bin/uname -X = `(/bin/uname -X) 2>/dev/null`
+
+hostinfo = `(hostinfo) 2>/dev/null`
+/bin/universe = `(/bin/universe) 2>/dev/null`
+/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null`
+/bin/arch = `(/bin/arch) 2>/dev/null`
+/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null`
+
+UNAME_MACHINE = ${UNAME_MACHINE}
+UNAME_RELEASE = ${UNAME_RELEASE}
+UNAME_SYSTEM = ${UNAME_SYSTEM}
+UNAME_VERSION = ${UNAME_VERSION}
+EOF
+
+exit 1
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
ADDED autosetup/config.sub
Index: autosetup/config.sub
==================================================================
--- autosetup/config.sub
+++ autosetup/config.sub
@@ -0,0 +1,1743 @@
+#! /bin/sh
+# Configuration validation subroutine script.
+# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+# 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
+# Free Software Foundation, Inc.
+
+timestamp='2010-09-11'
+
+# This file is (in principle) common to ALL GNU software.
+# The presence of a machine in this file suggests that SOME GNU software
+# can handle that machine. It does not imply ALL GNU software can.
+#
+# This file is free software; 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.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
+# 02110-1301, USA.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+
+# Please send patches to . Submit a context
+# diff and a properly formatted GNU ChangeLog entry.
+#
+# Configuration subroutine to validate and canonicalize a configuration type.
+# Supply the specified configuration type as an argument.
+# If it is invalid, we print an error message on stderr and exit with code 1.
+# Otherwise, we print the canonical config type on stdout and succeed.
+
+# You can get the latest version of this script from:
+# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD
+
+# This file is supposed to be the same for all GNU packages
+# and recognize all the CPU types, system types and aliases
+# that are meaningful with *any* GNU software.
+# Each package is responsible for reporting which valid configurations
+# it does not support. The user should be able to distinguish
+# a failure to support a valid configuration from a meaningless
+# configuration.
+
+# The goal of this file is to map all the various variations of a given
+# machine specification into a single specification in the form:
+# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM
+# or in some cases, the newer four-part form:
+# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
+# It is wrong to echo any other type of specification.
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION] CPU-MFR-OPSYS
+ $0 [OPTION] ALIAS
+
+Canonicalize a configuration name.
+
+Operation modes:
+ -h, --help print this help, then exit
+ -t, --time-stamp print date of last modification, then exit
+ -v, --version print version number, then exit
+
+Report bugs and patches to ."
+
+version="\
+GNU config.sub ($timestamp)
+
+Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
+2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free
+Software Foundation, Inc.
+
+This is free software; see the source for copying conditions. There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+ case $1 in
+ --time-stamp | --time* | -t )
+ echo "$timestamp" ; exit ;;
+ --version | -v )
+ echo "$version" ; exit ;;
+ --help | --h* | -h )
+ echo "$usage"; exit ;;
+ -- ) # Stop option processing
+ shift; break ;;
+ - ) # Use stdin as input.
+ break ;;
+ -* )
+ echo "$me: invalid option $1$help"
+ exit 1 ;;
+
+ *local*)
+ # First pass through any local machine types.
+ echo $1
+ exit ;;
+
+ * )
+ break ;;
+ esac
+done
+
+case $# in
+ 0) echo "$me: missing argument$help" >&2
+ exit 1;;
+ 1) ;;
+ *) echo "$me: too many arguments$help" >&2
+ exit 1;;
+esac
+
+# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any).
+# Here we must recognize all the valid KERNEL-OS combinations.
+maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
+case $maybe_os in
+ nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \
+ linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \
+ knetbsd*-gnu* | netbsd*-gnu* | \
+ kopensolaris*-gnu* | \
+ storm-chaos* | os2-emx* | rtmk-nova*)
+ os=-$maybe_os
+ basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
+ ;;
+ *)
+ basic_machine=`echo $1 | sed 's/-[^-]*$//'`
+ if [ $basic_machine != $1 ]
+ then os=`echo $1 | sed 's/.*-/-/'`
+ else os=; fi
+ ;;
+esac
+
+### Let's recognize common machines as not being operating systems so
+### that things like config.sub decstation-3100 work. We also
+### recognize some manufacturers as not being operating systems, so we
+### can provide default operating systems below.
+case $os in
+ -sun*os*)
+ # Prevent following clause from handling this invalid input.
+ ;;
+ -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \
+ -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \
+ -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \
+ -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
+ -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
+ -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \
+ -apple | -axis | -knuth | -cray | -microblaze)
+ os=
+ basic_machine=$1
+ ;;
+ -bluegene*)
+ os=-cnk
+ ;;
+ -sim | -cisco | -oki | -wec | -winbond)
+ os=
+ basic_machine=$1
+ ;;
+ -scout)
+ ;;
+ -wrs)
+ os=-vxworks
+ basic_machine=$1
+ ;;
+ -chorusos*)
+ os=-chorusos
+ basic_machine=$1
+ ;;
+ -chorusrdb)
+ os=-chorusrdb
+ basic_machine=$1
+ ;;
+ -hiux*)
+ os=-hiuxwe2
+ ;;
+ -sco6)
+ os=-sco5v6
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco5)
+ os=-sco3.2v5
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco4)
+ os=-sco3.2v4
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco3.2.[4-9]*)
+ os=`echo $os | sed -e 's/sco3.2./sco3.2v/'`
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco3.2v[4-9]*)
+ # Don't forget version if it is 3.2v4 or newer.
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco5v6*)
+ # Don't forget version if it is 3.2v4 or newer.
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco*)
+ os=-sco3.2v2
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -udk*)
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -isc)
+ os=-isc2.2
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -clix*)
+ basic_machine=clipper-intergraph
+ ;;
+ -isc*)
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -lynx*)
+ os=-lynxos
+ ;;
+ -ptx*)
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'`
+ ;;
+ -windowsnt*)
+ os=`echo $os | sed -e 's/windowsnt/winnt/'`
+ ;;
+ -psos*)
+ os=-psos
+ ;;
+ -mint | -mint[0-9]*)
+ basic_machine=m68k-atari
+ os=-mint
+ ;;
+esac
+
+# Decode aliases for certain CPU-COMPANY combinations.
+case $basic_machine in
+ # Recognize the basic CPU types without company name.
+ # Some are omitted here because they have special meanings below.
+ 1750a | 580 \
+ | a29k \
+ | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \
+ | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \
+ | am33_2.0 \
+ | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr | avr32 \
+ | bfin \
+ | c4x | clipper \
+ | d10v | d30v | dlx | dsp16xx \
+ | fido | fr30 | frv \
+ | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
+ | i370 | i860 | i960 | ia64 \
+ | ip2k | iq2000 \
+ | lm32 \
+ | m32c | m32r | m32rle | m68000 | m68k | m88k \
+ | maxq | mb | microblaze | mcore | mep | metag \
+ | mips | mipsbe | mipseb | mipsel | mipsle \
+ | mips16 \
+ | mips64 | mips64el \
+ | mips64octeon | mips64octeonel \
+ | mips64orion | mips64orionel \
+ | mips64r5900 | mips64r5900el \
+ | mips64vr | mips64vrel \
+ | mips64vr4100 | mips64vr4100el \
+ | mips64vr4300 | mips64vr4300el \
+ | mips64vr5000 | mips64vr5000el \
+ | mips64vr5900 | mips64vr5900el \
+ | mipsisa32 | mipsisa32el \
+ | mipsisa32r2 | mipsisa32r2el \
+ | mipsisa64 | mipsisa64el \
+ | mipsisa64r2 | mipsisa64r2el \
+ | mipsisa64sb1 | mipsisa64sb1el \
+ | mipsisa64sr71k | mipsisa64sr71kel \
+ | mipstx39 | mipstx39el \
+ | mn10200 | mn10300 \
+ | moxie \
+ | mt \
+ | msp430 \
+ | nds32 | nds32le | nds32be \
+ | nios | nios2 \
+ | ns16k | ns32k \
+ | or32 \
+ | pdp10 | pdp11 | pj | pjl \
+ | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \
+ | pyramid \
+ | rx \
+ | score \
+ | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \
+ | sh64 | sh64le \
+ | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \
+ | sparcv8 | sparcv9 | sparcv9b | sparcv9v \
+ | spu | strongarm \
+ | tahoe | thumb | tic4x | tic54x | tic55x | tic6x | tic80 | tron \
+ | ubicom32 \
+ | v850 | v850e \
+ | we32k \
+ | x86 | xc16x | xscale | xscalee[bl] | xstormy16 | xtensa \
+ | z8k | z80)
+ basic_machine=$basic_machine-unknown
+ ;;
+ c54x)
+ basic_machine=tic54x-unknown
+ ;;
+ c55x)
+ basic_machine=tic55x-unknown
+ ;;
+ c6x)
+ basic_machine=tic6x-unknown
+ ;;
+ m6811 | m68hc11 | m6812 | m68hc12 | picochip)
+ # Motorola 68HC11/12.
+ basic_machine=$basic_machine-unknown
+ os=-none
+ ;;
+ m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k)
+ ;;
+ ms1)
+ basic_machine=mt-unknown
+ ;;
+
+ # We use `pc' rather than `unknown'
+ # because (1) that's what they normally are, and
+ # (2) the word "unknown" tends to confuse beginning users.
+ i*86 | x86_64)
+ basic_machine=$basic_machine-pc
+ ;;
+ # Object if more than one company name word.
+ *-*-*)
+ echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+ exit 1
+ ;;
+ # Recognize the basic CPU types with company name.
+ 580-* \
+ | a29k-* \
+ | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \
+ | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \
+ | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \
+ | arm-* | armbe-* | armle-* | armeb-* | armv*-* \
+ | avr-* | avr32-* \
+ | bfin-* | bs2000-* \
+ | c[123]* | c30-* | [cjt]90-* | c4x-* \
+ | clipper-* | craynv-* | cydra-* \
+ | d10v-* | d30v-* | dlx-* \
+ | elxsi-* \
+ | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \
+ | h8300-* | h8500-* \
+ | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \
+ | i*86-* | i860-* | i960-* | ia64-* \
+ | ip2k-* | iq2000-* \
+ | lm32-* \
+ | m32c-* | m32r-* | m32rle-* \
+ | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \
+ | m88110-* | m88k-* | maxq-* | mcore-* | metag-* | microblaze-* \
+ | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \
+ | mips16-* \
+ | mips64-* | mips64el-* \
+ | mips64octeon-* | mips64octeonel-* \
+ | mips64orion-* | mips64orionel-* \
+ | mips64r5900-* | mips64r5900el-* \
+ | mips64vr-* | mips64vrel-* \
+ | mips64vr4100-* | mips64vr4100el-* \
+ | mips64vr4300-* | mips64vr4300el-* \
+ | mips64vr5000-* | mips64vr5000el-* \
+ | mips64vr5900-* | mips64vr5900el-* \
+ | mipsisa32-* | mipsisa32el-* \
+ | mipsisa32r2-* | mipsisa32r2el-* \
+ | mipsisa64-* | mipsisa64el-* \
+ | mipsisa64r2-* | mipsisa64r2el-* \
+ | mipsisa64sb1-* | mipsisa64sb1el-* \
+ | mipsisa64sr71k-* | mipsisa64sr71kel-* \
+ | mipstx39-* | mipstx39el-* \
+ | mmix-* \
+ | mt-* \
+ | msp430-* \
+ | nds32-* | nds32le-* | nds32be-* \
+ | nios-* | nios2-* \
+ | none-* | np1-* | ns16k-* | ns32k-* \
+ | orion-* \
+ | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
+ | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \
+ | pyramid-* \
+ | romp-* | rs6000-* | rx-* \
+ | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \
+ | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \
+ | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \
+ | sparclite-* \
+ | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | strongarm-* | sv1-* | sx?-* \
+ | tahoe-* | thumb-* \
+ | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \
+ | tile-* | tilegx-* \
+ | tron-* \
+ | ubicom32-* \
+ | v850-* | v850e-* | vax-* \
+ | we32k-* \
+ | x86-* | x86_64-* | xc16x-* | xps100-* | xscale-* | xscalee[bl]-* \
+ | xstormy16-* | xtensa*-* \
+ | ymp-* \
+ | z8k-* | z80-*)
+ ;;
+ # Recognize the basic CPU types without company name, with glob match.
+ xtensa*)
+ basic_machine=$basic_machine-unknown
+ ;;
+ # Recognize the various machine names and aliases which stand
+ # for a CPU type and a company and sometimes even an OS.
+ 386bsd)
+ basic_machine=i386-unknown
+ os=-bsd
+ ;;
+ 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc)
+ basic_machine=m68000-att
+ ;;
+ 3b*)
+ basic_machine=we32k-att
+ ;;
+ a29khif)
+ basic_machine=a29k-amd
+ os=-udi
+ ;;
+ abacus)
+ basic_machine=abacus-unknown
+ ;;
+ adobe68k)
+ basic_machine=m68010-adobe
+ os=-scout
+ ;;
+ alliant | fx80)
+ basic_machine=fx80-alliant
+ ;;
+ altos | altos3068)
+ basic_machine=m68k-altos
+ ;;
+ am29k)
+ basic_machine=a29k-none
+ os=-bsd
+ ;;
+ amd64)
+ basic_machine=x86_64-pc
+ ;;
+ amd64-*)
+ basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ amdahl)
+ basic_machine=580-amdahl
+ os=-sysv
+ ;;
+ amiga | amiga-*)
+ basic_machine=m68k-unknown
+ ;;
+ amigaos | amigados)
+ basic_machine=m68k-unknown
+ os=-amigaos
+ ;;
+ amigaunix | amix)
+ basic_machine=m68k-unknown
+ os=-sysv4
+ ;;
+ apollo68)
+ basic_machine=m68k-apollo
+ os=-sysv
+ ;;
+ apollo68bsd)
+ basic_machine=m68k-apollo
+ os=-bsd
+ ;;
+ aros)
+ basic_machine=i386-pc
+ os=-aros
+ ;;
+ aux)
+ basic_machine=m68k-apple
+ os=-aux
+ ;;
+ balance)
+ basic_machine=ns32k-sequent
+ os=-dynix
+ ;;
+ blackfin)
+ basic_machine=bfin-unknown
+ os=-linux
+ ;;
+ blackfin-*)
+ basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'`
+ os=-linux
+ ;;
+ bluegene*)
+ basic_machine=powerpc-ibm
+ os=-cnk
+ ;;
+ c54x-*)
+ basic_machine=tic54x-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ c55x-*)
+ basic_machine=tic55x-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ c6x-*)
+ basic_machine=tic6x-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ c90)
+ basic_machine=c90-cray
+ os=-unicos
+ ;;
+ cegcc)
+ basic_machine=arm-unknown
+ os=-cegcc
+ ;;
+ convex-c1)
+ basic_machine=c1-convex
+ os=-bsd
+ ;;
+ convex-c2)
+ basic_machine=c2-convex
+ os=-bsd
+ ;;
+ convex-c32)
+ basic_machine=c32-convex
+ os=-bsd
+ ;;
+ convex-c34)
+ basic_machine=c34-convex
+ os=-bsd
+ ;;
+ convex-c38)
+ basic_machine=c38-convex
+ os=-bsd
+ ;;
+ cray | j90)
+ basic_machine=j90-cray
+ os=-unicos
+ ;;
+ craynv)
+ basic_machine=craynv-cray
+ os=-unicosmp
+ ;;
+ cr16)
+ basic_machine=cr16-unknown
+ os=-elf
+ ;;
+ crds | unos)
+ basic_machine=m68k-crds
+ ;;
+ crisv32 | crisv32-* | etraxfs*)
+ basic_machine=crisv32-axis
+ ;;
+ cris | cris-* | etrax*)
+ basic_machine=cris-axis
+ ;;
+ crx)
+ basic_machine=crx-unknown
+ os=-elf
+ ;;
+ da30 | da30-*)
+ basic_machine=m68k-da30
+ ;;
+ decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn)
+ basic_machine=mips-dec
+ ;;
+ decsystem10* | dec10*)
+ basic_machine=pdp10-dec
+ os=-tops10
+ ;;
+ decsystem20* | dec20*)
+ basic_machine=pdp10-dec
+ os=-tops20
+ ;;
+ delta | 3300 | motorola-3300 | motorola-delta \
+ | 3300-motorola | delta-motorola)
+ basic_machine=m68k-motorola
+ ;;
+ delta88)
+ basic_machine=m88k-motorola
+ os=-sysv3
+ ;;
+ dicos)
+ basic_machine=i686-pc
+ os=-dicos
+ ;;
+ djgpp)
+ basic_machine=i586-pc
+ os=-msdosdjgpp
+ ;;
+ dpx20 | dpx20-*)
+ basic_machine=rs6000-bull
+ os=-bosx
+ ;;
+ dpx2* | dpx2*-bull)
+ basic_machine=m68k-bull
+ os=-sysv3
+ ;;
+ ebmon29k)
+ basic_machine=a29k-amd
+ os=-ebmon
+ ;;
+ elxsi)
+ basic_machine=elxsi-elxsi
+ os=-bsd
+ ;;
+ encore | umax | mmax)
+ basic_machine=ns32k-encore
+ ;;
+ es1800 | OSE68k | ose68k | ose | OSE)
+ basic_machine=m68k-ericsson
+ os=-ose
+ ;;
+ fx2800)
+ basic_machine=i860-alliant
+ ;;
+ genix)
+ basic_machine=ns32k-ns
+ ;;
+ gmicro)
+ basic_machine=tron-gmicro
+ os=-sysv
+ ;;
+ go32)
+ basic_machine=i386-pc
+ os=-go32
+ ;;
+ h3050r* | hiux*)
+ basic_machine=hppa1.1-hitachi
+ os=-hiuxwe2
+ ;;
+ h8300hms)
+ basic_machine=h8300-hitachi
+ os=-hms
+ ;;
+ h8300xray)
+ basic_machine=h8300-hitachi
+ os=-xray
+ ;;
+ h8500hms)
+ basic_machine=h8500-hitachi
+ os=-hms
+ ;;
+ harris)
+ basic_machine=m88k-harris
+ os=-sysv3
+ ;;
+ hp300-*)
+ basic_machine=m68k-hp
+ ;;
+ hp300bsd)
+ basic_machine=m68k-hp
+ os=-bsd
+ ;;
+ hp300hpux)
+ basic_machine=m68k-hp
+ os=-hpux
+ ;;
+ hp3k9[0-9][0-9] | hp9[0-9][0-9])
+ basic_machine=hppa1.0-hp
+ ;;
+ hp9k2[0-9][0-9] | hp9k31[0-9])
+ basic_machine=m68000-hp
+ ;;
+ hp9k3[2-9][0-9])
+ basic_machine=m68k-hp
+ ;;
+ hp9k6[0-9][0-9] | hp6[0-9][0-9])
+ basic_machine=hppa1.0-hp
+ ;;
+ hp9k7[0-79][0-9] | hp7[0-79][0-9])
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k78[0-9] | hp78[0-9])
+ # FIXME: really hppa2.0-hp
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893)
+ # FIXME: really hppa2.0-hp
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k8[0-9][13679] | hp8[0-9][13679])
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k8[0-9][0-9] | hp8[0-9][0-9])
+ basic_machine=hppa1.0-hp
+ ;;
+ hppa-next)
+ os=-nextstep3
+ ;;
+ hppaosf)
+ basic_machine=hppa1.1-hp
+ os=-osf
+ ;;
+ hppro)
+ basic_machine=hppa1.1-hp
+ os=-proelf
+ ;;
+ i370-ibm* | ibm*)
+ basic_machine=i370-ibm
+ ;;
+# I'm not sure what "Sysv32" means. Should this be sysv3.2?
+ i*86v32)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-sysv32
+ ;;
+ i*86v4*)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-sysv4
+ ;;
+ i*86v)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-sysv
+ ;;
+ i*86sol2)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-solaris2
+ ;;
+ i386mach)
+ basic_machine=i386-mach
+ os=-mach
+ ;;
+ i386-vsta | vsta)
+ basic_machine=i386-unknown
+ os=-vsta
+ ;;
+ iris | iris4d)
+ basic_machine=mips-sgi
+ case $os in
+ -irix*)
+ ;;
+ *)
+ os=-irix4
+ ;;
+ esac
+ ;;
+ isi68 | isi)
+ basic_machine=m68k-isi
+ os=-sysv
+ ;;
+ m68knommu)
+ basic_machine=m68k-unknown
+ os=-linux
+ ;;
+ m68knommu-*)
+ basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'`
+ os=-linux
+ ;;
+ m88k-omron*)
+ basic_machine=m88k-omron
+ ;;
+ magnum | m3230)
+ basic_machine=mips-mips
+ os=-sysv
+ ;;
+ merlin)
+ basic_machine=ns32k-utek
+ os=-sysv
+ ;;
+ microblaze)
+ basic_machine=microblaze-xilinx
+ ;;
+ mingw32)
+ basic_machine=i386-pc
+ os=-mingw32
+ ;;
+ mingw32ce)
+ basic_machine=arm-unknown
+ os=-mingw32ce
+ ;;
+ miniframe)
+ basic_machine=m68000-convergent
+ ;;
+ *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*)
+ basic_machine=m68k-atari
+ os=-mint
+ ;;
+ mips3*-*)
+ basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`
+ ;;
+ mips3*)
+ basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown
+ ;;
+ monitor)
+ basic_machine=m68k-rom68k
+ os=-coff
+ ;;
+ morphos)
+ basic_machine=powerpc-unknown
+ os=-morphos
+ ;;
+ msdos)
+ basic_machine=i386-pc
+ os=-msdos
+ ;;
+ ms1-*)
+ basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'`
+ ;;
+ mvs)
+ basic_machine=i370-ibm
+ os=-mvs
+ ;;
+ msys)
+ basic_machine=i386-pc
+ os=-msys
+ ;;
+ ncr3000)
+ basic_machine=i486-ncr
+ os=-sysv4
+ ;;
+ netbsd386)
+ basic_machine=i386-unknown
+ os=-netbsd
+ ;;
+ netwinder)
+ basic_machine=armv4l-rebel
+ os=-linux
+ ;;
+ news | news700 | news800 | news900)
+ basic_machine=m68k-sony
+ os=-newsos
+ ;;
+ news1000)
+ basic_machine=m68030-sony
+ os=-newsos
+ ;;
+ news-3600 | risc-news)
+ basic_machine=mips-sony
+ os=-newsos
+ ;;
+ necv70)
+ basic_machine=v70-nec
+ os=-sysv
+ ;;
+ next | m*-next )
+ basic_machine=m68k-next
+ case $os in
+ -nextstep* )
+ ;;
+ -ns2*)
+ os=-nextstep2
+ ;;
+ *)
+ os=-nextstep3
+ ;;
+ esac
+ ;;
+ nh3000)
+ basic_machine=m68k-harris
+ os=-cxux
+ ;;
+ nh[45]000)
+ basic_machine=m88k-harris
+ os=-cxux
+ ;;
+ nindy960)
+ basic_machine=i960-intel
+ os=-nindy
+ ;;
+ mon960)
+ basic_machine=i960-intel
+ os=-mon960
+ ;;
+ nonstopux)
+ basic_machine=mips-compaq
+ os=-nonstopux
+ ;;
+ np1)
+ basic_machine=np1-gould
+ ;;
+ neo-tandem)
+ basic_machine=neo-tandem
+ ;;
+ nse-tandem)
+ basic_machine=nse-tandem
+ ;;
+ nsr-tandem)
+ basic_machine=nsr-tandem
+ ;;
+ op50n-* | op60c-*)
+ basic_machine=hppa1.1-oki
+ os=-proelf
+ ;;
+ openrisc | openrisc-*)
+ basic_machine=or32-unknown
+ ;;
+ os400)
+ basic_machine=powerpc-ibm
+ os=-os400
+ ;;
+ OSE68000 | ose68000)
+ basic_machine=m68000-ericsson
+ os=-ose
+ ;;
+ os68k)
+ basic_machine=m68k-none
+ os=-os68k
+ ;;
+ pa-hitachi)
+ basic_machine=hppa1.1-hitachi
+ os=-hiuxwe2
+ ;;
+ paragon)
+ basic_machine=i860-intel
+ os=-osf
+ ;;
+ parisc)
+ basic_machine=hppa-unknown
+ os=-linux
+ ;;
+ parisc-*)
+ basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'`
+ os=-linux
+ ;;
+ pbd)
+ basic_machine=sparc-tti
+ ;;
+ pbb)
+ basic_machine=m68k-tti
+ ;;
+ pc532 | pc532-*)
+ basic_machine=ns32k-pc532
+ ;;
+ pc98)
+ basic_machine=i386-pc
+ ;;
+ pc98-*)
+ basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pentium | p5 | k5 | k6 | nexgen | viac3)
+ basic_machine=i586-pc
+ ;;
+ pentiumpro | p6 | 6x86 | athlon | athlon_*)
+ basic_machine=i686-pc
+ ;;
+ pentiumii | pentium2 | pentiumiii | pentium3)
+ basic_machine=i686-pc
+ ;;
+ pentium4)
+ basic_machine=i786-pc
+ ;;
+ pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*)
+ basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pentiumpro-* | p6-* | 6x86-* | athlon-*)
+ basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*)
+ basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pentium4-*)
+ basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pn)
+ basic_machine=pn-gould
+ ;;
+ power) basic_machine=power-ibm
+ ;;
+ ppc) basic_machine=powerpc-unknown
+ ;;
+ ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ppcle | powerpclittle | ppc-le | powerpc-little)
+ basic_machine=powerpcle-unknown
+ ;;
+ ppcle-* | powerpclittle-*)
+ basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ppc64) basic_machine=powerpc64-unknown
+ ;;
+ ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ppc64le | powerpc64little | ppc64-le | powerpc64-little)
+ basic_machine=powerpc64le-unknown
+ ;;
+ ppc64le-* | powerpc64little-*)
+ basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ps2)
+ basic_machine=i386-ibm
+ ;;
+ pw32)
+ basic_machine=i586-unknown
+ os=-pw32
+ ;;
+ rdos)
+ basic_machine=i386-pc
+ os=-rdos
+ ;;
+ rom68k)
+ basic_machine=m68k-rom68k
+ os=-coff
+ ;;
+ rm[46]00)
+ basic_machine=mips-siemens
+ ;;
+ rtpc | rtpc-*)
+ basic_machine=romp-ibm
+ ;;
+ s390 | s390-*)
+ basic_machine=s390-ibm
+ ;;
+ s390x | s390x-*)
+ basic_machine=s390x-ibm
+ ;;
+ sa29200)
+ basic_machine=a29k-amd
+ os=-udi
+ ;;
+ sb1)
+ basic_machine=mipsisa64sb1-unknown
+ ;;
+ sb1el)
+ basic_machine=mipsisa64sb1el-unknown
+ ;;
+ sde)
+ basic_machine=mipsisa32-sde
+ os=-elf
+ ;;
+ sei)
+ basic_machine=mips-sei
+ os=-seiux
+ ;;
+ sequent)
+ basic_machine=i386-sequent
+ ;;
+ sh)
+ basic_machine=sh-hitachi
+ os=-hms
+ ;;
+ sh5el)
+ basic_machine=sh5le-unknown
+ ;;
+ sh64)
+ basic_machine=sh64-unknown
+ ;;
+ sparclite-wrs | simso-wrs)
+ basic_machine=sparclite-wrs
+ os=-vxworks
+ ;;
+ sps7)
+ basic_machine=m68k-bull
+ os=-sysv2
+ ;;
+ spur)
+ basic_machine=spur-unknown
+ ;;
+ st2000)
+ basic_machine=m68k-tandem
+ ;;
+ stratus)
+ basic_machine=i860-stratus
+ os=-sysv4
+ ;;
+ sun2)
+ basic_machine=m68000-sun
+ ;;
+ sun2os3)
+ basic_machine=m68000-sun
+ os=-sunos3
+ ;;
+ sun2os4)
+ basic_machine=m68000-sun
+ os=-sunos4
+ ;;
+ sun3os3)
+ basic_machine=m68k-sun
+ os=-sunos3
+ ;;
+ sun3os4)
+ basic_machine=m68k-sun
+ os=-sunos4
+ ;;
+ sun4os3)
+ basic_machine=sparc-sun
+ os=-sunos3
+ ;;
+ sun4os4)
+ basic_machine=sparc-sun
+ os=-sunos4
+ ;;
+ sun4sol2)
+ basic_machine=sparc-sun
+ os=-solaris2
+ ;;
+ sun3 | sun3-*)
+ basic_machine=m68k-sun
+ ;;
+ sun4)
+ basic_machine=sparc-sun
+ ;;
+ sun386 | sun386i | roadrunner)
+ basic_machine=i386-sun
+ ;;
+ sv1)
+ basic_machine=sv1-cray
+ os=-unicos
+ ;;
+ symmetry)
+ basic_machine=i386-sequent
+ os=-dynix
+ ;;
+ t3e)
+ basic_machine=alphaev5-cray
+ os=-unicos
+ ;;
+ t90)
+ basic_machine=t90-cray
+ os=-unicos
+ ;;
+ # This must be matched before tile*.
+ tilegx*)
+ basic_machine=tilegx-unknown
+ os=-linux-gnu
+ ;;
+ tile*)
+ basic_machine=tile-unknown
+ os=-linux-gnu
+ ;;
+ tx39)
+ basic_machine=mipstx39-unknown
+ ;;
+ tx39el)
+ basic_machine=mipstx39el-unknown
+ ;;
+ toad1)
+ basic_machine=pdp10-xkl
+ os=-tops20
+ ;;
+ tower | tower-32)
+ basic_machine=m68k-ncr
+ ;;
+ tpf)
+ basic_machine=s390x-ibm
+ os=-tpf
+ ;;
+ udi29k)
+ basic_machine=a29k-amd
+ os=-udi
+ ;;
+ ultra3)
+ basic_machine=a29k-nyu
+ os=-sym1
+ ;;
+ v810 | necv810)
+ basic_machine=v810-nec
+ os=-none
+ ;;
+ vaxv)
+ basic_machine=vax-dec
+ os=-sysv
+ ;;
+ vms)
+ basic_machine=vax-dec
+ os=-vms
+ ;;
+ vpp*|vx|vx-*)
+ basic_machine=f301-fujitsu
+ ;;
+ vxworks960)
+ basic_machine=i960-wrs
+ os=-vxworks
+ ;;
+ vxworks68)
+ basic_machine=m68k-wrs
+ os=-vxworks
+ ;;
+ vxworks29k)
+ basic_machine=a29k-wrs
+ os=-vxworks
+ ;;
+ w65*)
+ basic_machine=w65-wdc
+ os=-none
+ ;;
+ w89k-*)
+ basic_machine=hppa1.1-winbond
+ os=-proelf
+ ;;
+ xbox)
+ basic_machine=i686-pc
+ os=-mingw32
+ ;;
+ xps | xps100)
+ basic_machine=xps100-honeywell
+ ;;
+ ymp)
+ basic_machine=ymp-cray
+ os=-unicos
+ ;;
+ z8k-*-coff)
+ basic_machine=z8k-unknown
+ os=-sim
+ ;;
+ z80-*-coff)
+ basic_machine=z80-unknown
+ os=-sim
+ ;;
+ none)
+ basic_machine=none-none
+ os=-none
+ ;;
+
+# Here we handle the default manufacturer of certain CPU types. It is in
+# some cases the only manufacturer, in others, it is the most popular.
+ w89k)
+ basic_machine=hppa1.1-winbond
+ ;;
+ op50n)
+ basic_machine=hppa1.1-oki
+ ;;
+ op60c)
+ basic_machine=hppa1.1-oki
+ ;;
+ romp)
+ basic_machine=romp-ibm
+ ;;
+ mmix)
+ basic_machine=mmix-knuth
+ ;;
+ rs6000)
+ basic_machine=rs6000-ibm
+ ;;
+ vax)
+ basic_machine=vax-dec
+ ;;
+ pdp10)
+ # there are many clones, so DEC is not a safe bet
+ basic_machine=pdp10-unknown
+ ;;
+ pdp11)
+ basic_machine=pdp11-dec
+ ;;
+ we32k)
+ basic_machine=we32k-att
+ ;;
+ sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele)
+ basic_machine=sh-unknown
+ ;;
+ sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v)
+ basic_machine=sparc-sun
+ ;;
+ cydra)
+ basic_machine=cydra-cydrome
+ ;;
+ orion)
+ basic_machine=orion-highlevel
+ ;;
+ orion105)
+ basic_machine=clipper-highlevel
+ ;;
+ mac | mpw | mac-mpw)
+ basic_machine=m68k-apple
+ ;;
+ pmac | pmac-mpw)
+ basic_machine=powerpc-apple
+ ;;
+ *-unknown)
+ # Make sure to match an already-canonicalized machine name.
+ ;;
+ *)
+ echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+ exit 1
+ ;;
+esac
+
+# Here we canonicalize certain aliases for manufacturers.
+case $basic_machine in
+ *-digital*)
+ basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'`
+ ;;
+ *-commodore*)
+ basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'`
+ ;;
+ *)
+ ;;
+esac
+
+# Decode manufacturer-specific aliases for certain operating systems.
+
+if [ x"$os" != x"" ]
+then
+case $os in
+ # First match some system type aliases
+ # that might get confused with valid system types.
+ # -solaris* is a basic system type, with this one exception.
+ -auroraux)
+ os=-auroraux
+ ;;
+ -solaris1 | -solaris1.*)
+ os=`echo $os | sed -e 's|solaris1|sunos4|'`
+ ;;
+ -solaris)
+ os=-solaris2
+ ;;
+ -svr4*)
+ os=-sysv4
+ ;;
+ -unixware*)
+ os=-sysv4.2uw
+ ;;
+ -gnu/linux*)
+ os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'`
+ ;;
+ # First accept the basic system types.
+ # The portable systems comes first.
+ # Each alternative MUST END IN A *, to match a version number.
+ # -sysv* is not here because it comes later, after sysvr4.
+ -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \
+ | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\
+ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \
+ | -sym* | -kopensolaris* \
+ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
+ | -aos* | -aros* \
+ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
+ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
+ | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \
+ | -openbsd* | -solidbsd* \
+ | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \
+ | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
+ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
+ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
+ | -chorusos* | -chorusrdb* | -cegcc* \
+ | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
+ | -mingw32* | -linux-gnu* | -linux-android* \
+ | -linux-newlib* | -linux-uclibc* \
+ | -uxpv* | -beos* | -mpeix* | -udk* \
+ | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \
+ | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \
+ | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \
+ | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \
+ | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \
+ | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \
+ | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es*)
+ # Remember, each alternative MUST END IN *, to match a version number.
+ ;;
+ -qnx*)
+ case $basic_machine in
+ x86-* | i*86-*)
+ ;;
+ *)
+ os=-nto$os
+ ;;
+ esac
+ ;;
+ -nto-qnx*)
+ ;;
+ -nto*)
+ os=`echo $os | sed -e 's|nto|nto-qnx|'`
+ ;;
+ -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \
+ | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \
+ | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*)
+ ;;
+ -mac*)
+ os=`echo $os | sed -e 's|mac|macos|'`
+ ;;
+ -linux-dietlibc)
+ os=-linux-dietlibc
+ ;;
+ -linux*)
+ os=`echo $os | sed -e 's|linux|linux-gnu|'`
+ ;;
+ -sunos5*)
+ os=`echo $os | sed -e 's|sunos5|solaris2|'`
+ ;;
+ -sunos6*)
+ os=`echo $os | sed -e 's|sunos6|solaris3|'`
+ ;;
+ -opened*)
+ os=-openedition
+ ;;
+ -os400*)
+ os=-os400
+ ;;
+ -wince*)
+ os=-wince
+ ;;
+ -osfrose*)
+ os=-osfrose
+ ;;
+ -osf*)
+ os=-osf
+ ;;
+ -utek*)
+ os=-bsd
+ ;;
+ -dynix*)
+ os=-bsd
+ ;;
+ -acis*)
+ os=-aos
+ ;;
+ -atheos*)
+ os=-atheos
+ ;;
+ -syllable*)
+ os=-syllable
+ ;;
+ -386bsd)
+ os=-bsd
+ ;;
+ -ctix* | -uts*)
+ os=-sysv
+ ;;
+ -nova*)
+ os=-rtmk-nova
+ ;;
+ -ns2 )
+ os=-nextstep2
+ ;;
+ -nsk*)
+ os=-nsk
+ ;;
+ # Preserve the version number of sinix5.
+ -sinix5.*)
+ os=`echo $os | sed -e 's|sinix|sysv|'`
+ ;;
+ -sinix*)
+ os=-sysv4
+ ;;
+ -tpf*)
+ os=-tpf
+ ;;
+ -triton*)
+ os=-sysv3
+ ;;
+ -oss*)
+ os=-sysv3
+ ;;
+ -svr4)
+ os=-sysv4
+ ;;
+ -svr3)
+ os=-sysv3
+ ;;
+ -sysvr4)
+ os=-sysv4
+ ;;
+ # This must come after -sysvr4.
+ -sysv*)
+ ;;
+ -ose*)
+ os=-ose
+ ;;
+ -es1800*)
+ os=-ose
+ ;;
+ -xenix)
+ os=-xenix
+ ;;
+ -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+ os=-mint
+ ;;
+ -aros*)
+ os=-aros
+ ;;
+ -kaos*)
+ os=-kaos
+ ;;
+ -zvmoe)
+ os=-zvmoe
+ ;;
+ -dicos*)
+ os=-dicos
+ ;;
+ -nacl*)
+ ;;
+ -none)
+ ;;
+ *)
+ # Get rid of the `-' at the beginning of $os.
+ os=`echo $os | sed 's/[^-]*-//'`
+ echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2
+ exit 1
+ ;;
+esac
+else
+
+# Here we handle the default operating systems that come with various machines.
+# The value should be what the vendor currently ships out the door with their
+# machine or put another way, the most popular os provided with the machine.
+
+# Note that if you're going to try to match "-MANUFACTURER" here (say,
+# "-sun"), then you have to tell the case statement up towards the top
+# that MANUFACTURER isn't an operating system. Otherwise, code above
+# will signal an error saying that MANUFACTURER isn't an operating
+# system, and we'll never get to this point.
+
+case $basic_machine in
+ score-*)
+ os=-elf
+ ;;
+ spu-*)
+ os=-elf
+ ;;
+ *-acorn)
+ os=-riscix1.2
+ ;;
+ arm*-rebel)
+ os=-linux
+ ;;
+ arm*-semi)
+ os=-aout
+ ;;
+ c4x-* | tic4x-*)
+ os=-coff
+ ;;
+ tic54x-*)
+ os=-coff
+ ;;
+ tic55x-*)
+ os=-coff
+ ;;
+ tic6x-*)
+ os=-coff
+ ;;
+ # This must come before the *-dec entry.
+ pdp10-*)
+ os=-tops20
+ ;;
+ pdp11-*)
+ os=-none
+ ;;
+ *-dec | vax-*)
+ os=-ultrix4.2
+ ;;
+ m68*-apollo)
+ os=-domain
+ ;;
+ i386-sun)
+ os=-sunos4.0.2
+ ;;
+ m68000-sun)
+ os=-sunos3
+ # This also exists in the configure program, but was not the
+ # default.
+ # os=-sunos4
+ ;;
+ m68*-cisco)
+ os=-aout
+ ;;
+ mep-*)
+ os=-elf
+ ;;
+ mips*-cisco)
+ os=-elf
+ ;;
+ mips*-*)
+ os=-elf
+ ;;
+ or32-*)
+ os=-coff
+ ;;
+ *-tti) # must be before sparc entry or we get the wrong os.
+ os=-sysv3
+ ;;
+ sparc-* | *-sun)
+ os=-sunos4.1.1
+ ;;
+ *-be)
+ os=-beos
+ ;;
+ *-haiku)
+ os=-haiku
+ ;;
+ *-ibm)
+ os=-aix
+ ;;
+ *-knuth)
+ os=-mmixware
+ ;;
+ *-wec)
+ os=-proelf
+ ;;
+ *-winbond)
+ os=-proelf
+ ;;
+ *-oki)
+ os=-proelf
+ ;;
+ *-hp)
+ os=-hpux
+ ;;
+ *-hitachi)
+ os=-hiux
+ ;;
+ i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent)
+ os=-sysv
+ ;;
+ *-cbm)
+ os=-amigaos
+ ;;
+ *-dg)
+ os=-dgux
+ ;;
+ *-dolphin)
+ os=-sysv3
+ ;;
+ m68k-ccur)
+ os=-rtu
+ ;;
+ m88k-omron*)
+ os=-luna
+ ;;
+ *-next )
+ os=-nextstep
+ ;;
+ *-sequent)
+ os=-ptx
+ ;;
+ *-crds)
+ os=-unos
+ ;;
+ *-ns)
+ os=-genix
+ ;;
+ i370-*)
+ os=-mvs
+ ;;
+ *-next)
+ os=-nextstep3
+ ;;
+ *-gould)
+ os=-sysv
+ ;;
+ *-highlevel)
+ os=-bsd
+ ;;
+ *-encore)
+ os=-bsd
+ ;;
+ *-sgi)
+ os=-irix
+ ;;
+ *-siemens)
+ os=-sysv4
+ ;;
+ *-masscomp)
+ os=-rtu
+ ;;
+ f30[01]-fujitsu | f700-fujitsu)
+ os=-uxpv
+ ;;
+ *-rom68k)
+ os=-coff
+ ;;
+ *-*bug)
+ os=-coff
+ ;;
+ *-apple)
+ os=-macos
+ ;;
+ *-atari*)
+ os=-mint
+ ;;
+ *)
+ os=-none
+ ;;
+esac
+fi
+
+# Here we handle the case where we know the os, and the CPU type, but not the
+# manufacturer. We pick the logical manufacturer.
+vendor=unknown
+case $basic_machine in
+ *-unknown)
+ case $os in
+ -riscix*)
+ vendor=acorn
+ ;;
+ -sunos*)
+ vendor=sun
+ ;;
+ -cnk*|-aix*)
+ vendor=ibm
+ ;;
+ -beos*)
+ vendor=be
+ ;;
+ -hpux*)
+ vendor=hp
+ ;;
+ -mpeix*)
+ vendor=hp
+ ;;
+ -hiux*)
+ vendor=hitachi
+ ;;
+ -unos*)
+ vendor=crds
+ ;;
+ -dgux*)
+ vendor=dg
+ ;;
+ -luna*)
+ vendor=omron
+ ;;
+ -genix*)
+ vendor=ns
+ ;;
+ -mvs* | -opened*)
+ vendor=ibm
+ ;;
+ -os400*)
+ vendor=ibm
+ ;;
+ -ptx*)
+ vendor=sequent
+ ;;
+ -tpf*)
+ vendor=ibm
+ ;;
+ -vxsim* | -vxworks* | -windiss*)
+ vendor=wrs
+ ;;
+ -aux*)
+ vendor=apple
+ ;;
+ -hms*)
+ vendor=hitachi
+ ;;
+ -mpw* | -macos*)
+ vendor=apple
+ ;;
+ -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+ vendor=atari
+ ;;
+ -vos*)
+ vendor=stratus
+ ;;
+ esac
+ basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"`
+ ;;
+esac
+
+echo $basic_machine$os
+exit
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
ADDED autosetup/default.auto
Index: autosetup/default.auto
==================================================================
--- autosetup/default.auto
+++ autosetup/default.auto
@@ -0,0 +1,25 @@
+# Copyright (c) 2012 WorkWare Systems http://www.workware.net.au/
+# All rights reserved
+
+# Auto-load module for 'make' build system integration
+
+use init
+
+autosetup_add_init_type make {Simple "make" build system} {
+ autosetup_check_create auto.def \
+{# Initial auto.def created by 'autosetup --init=make'
+
+use cc
+
+# Add any user options here
+options {
+}
+
+make-config-header config.h
+make-template Makefile.in
+}
+
+ if {![file exists Makefile.in]} {
+ puts "Note: I don't see Makefile.in. You will probably need to create one."
+ }
+}
ADDED autosetup/find-tclsh
Index: autosetup/find-tclsh
==================================================================
--- autosetup/find-tclsh
+++ autosetup/find-tclsh
@@ -0,0 +1,16 @@
+#!/bin/sh
+# Looks for a suitable tclsh or jimsh in the PATH
+# If not found, builds a bootstrap jimsh from source
+d=`dirname "$0"`
+{ "$d/jimsh0" "$d/test-tclsh"; } 2>/dev/null && exit 0
+PATH="$PATH:$d"; export PATH
+for tclsh in jimsh tclsh tclsh8.5 tclsh8.6; do
+ { $tclsh "$d/test-tclsh"; } 2>/dev/null && exit 0
+done
+echo 1>&2 "No installed jimsh or tclsh, building local bootstrap jimsh0"
+for cc in ${CC_FOR_BUILD:-cc} gcc; do
+ { $cc -o "$d/jimsh0" "$d/jimsh0.c"; } 2>/dev/null || continue
+ "$d/jimsh0" "$d/test-tclsh" && exit 0
+done
+echo 1>&2 "No working C compiler found. Tried ${CC_FOR_BUILD:-cc} and gcc."
+echo false
ADDED autosetup/jimsh0.c
Index: autosetup/jimsh0.c
==================================================================
--- autosetup/jimsh0.c
+++ autosetup/jimsh0.c
@@ -0,0 +1,21555 @@
+/* This is single source file, bootstrap version of Jim Tcl. See http://jim.berlios.de/ */
+#define _GNU_SOURCE
+#define JIM_TCL_COMPAT
+#define JIM_REFERENCES
+#define JIM_ANSIC
+#define JIM_REGEXP
+#define HAVE_NO_AUTOCONF
+#define _JIMAUTOCONF_H
+#define TCL_LIBRARY "."
+#define jim_ext_bootstrap
+#define jim_ext_aio
+#define jim_ext_readdir
+#define jim_ext_glob
+#define jim_ext_regexp
+#define jim_ext_file
+#define jim_ext_exec
+#define jim_ext_clock
+#define jim_ext_array
+#define jim_ext_stdlib
+#define jim_ext_tclcompat
+#if defined(_MSC_VER)
+#define TCL_PLATFORM_OS "windows"
+#define TCL_PLATFORM_PLATFORM "windows"
+#define TCL_PLATFORM_PATH_SEPARATOR ";"
+#define HAVE_MKDIR_ONE_ARG
+#define HAVE_SYSTEM
+#elif defined(__MINGW32__)
+#define TCL_PLATFORM_OS "mingw"
+#define TCL_PLATFORM_PLATFORM "windows"
+#define TCL_PLATFORM_PATH_SEPARATOR ";"
+#define HAVE_MKDIR_ONE_ARG
+#define HAVE_SYSTEM
+#define HAVE_SYS_TIME_H
+#define HAVE_DIRENT_H
+#define HAVE_UNISTD_H
+#else
+#define TCL_PLATFORM_OS "unknown"
+#define TCL_PLATFORM_PLATFORM "unix"
+#define TCL_PLATFORM_PATH_SEPARATOR ":"
+#define HAVE_VFORK
+#define HAVE_WAITPID
+#define HAVE_ISATTY
+#define HAVE_SYS_TIME_H
+#define HAVE_DIRENT_H
+#define HAVE_UNISTD_H
+#endif
+#ifndef JIM_WIN32COMPAT_H
+#define JIM_WIN32COMPAT_H
+
+
+
+
+#if defined(_WIN32) || defined(WIN32)
+
+#define HAVE_DLOPEN
+void *dlopen(const char *path, int mode);
+int dlclose(void *handle);
+void *dlsym(void *handle, const char *symbol);
+char *dlerror(void);
+
+
+#define JIM_SPRINTF_DOUBLE_NEEDS_FIX
+
+#ifdef _MSC_VER
+
+
+#if _MSC_VER >= 1000
+ #pragma warning(disable:4146)
+#endif
+
+#include
+#define jim_wide _int64
+#ifndef LLONG_MAX
+ #define LLONG_MAX 9223372036854775807I64
+#endif
+#ifndef LLONG_MIN
+ #define LLONG_MIN (-LLONG_MAX - 1I64)
+#endif
+#define JIM_WIDE_MIN LLONG_MIN
+#define JIM_WIDE_MAX LLONG_MAX
+#define JIM_WIDE_MODIFIER "I64d"
+#define strcasecmp _stricmp
+#define strtoull _strtoui64
+#define snprintf _snprintf
+
+#include
+
+struct timeval {
+ long tv_sec;
+ long tv_usec;
+};
+
+int gettimeofday(struct timeval *tv, void *unused);
+
+#define HAVE_OPENDIR
+struct dirent {
+ char *d_name;
+};
+
+typedef struct DIR {
+ long handle;
+ struct _finddata_t info;
+ struct dirent result;
+ char *name;
+} DIR;
+
+DIR *opendir(const char *name);
+int closedir(DIR *dir);
+struct dirent *readdir(DIR *dir);
+#endif
+
+#endif
+
+#endif
+#ifndef UTF8_UTIL_H
+#define UTF8_UTIL_H
+
+
+#define MAX_UTF8_LEN 4
+
+int utf8_fromunicode(char *p, unsigned uc);
+
+#ifndef JIM_UTF8
+#include
+
+
+#define utf8_strlen(S, B) ((B) < 0 ? strlen(S) : (B))
+#define utf8_tounicode(S, CP) (*(CP) = (unsigned char)*(S), 1)
+#define utf8_upper(C) toupper(C)
+#define utf8_title(C) toupper(C)
+#define utf8_lower(C) tolower(C)
+#define utf8_index(C, I) (I)
+#define utf8_charlen(C) 1
+#define utf8_prev_len(S, L) 1
+
+#else
+
+#endif
+
+#endif
+
+#ifndef __JIM__H
+#define __JIM__H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include
+#include
+#include
+#include
+#include
+
+
+#ifndef HAVE_NO_AUTOCONF
+#endif
+
+
+
+#ifndef jim_wide
+# ifdef HAVE_LONG_LONG
+# define jim_wide long long
+# ifndef LLONG_MAX
+# define LLONG_MAX 9223372036854775807LL
+# endif
+# ifndef LLONG_MIN
+# define LLONG_MIN (-LLONG_MAX - 1LL)
+# endif
+# define JIM_WIDE_MIN LLONG_MIN
+# define JIM_WIDE_MAX LLONG_MAX
+# else
+# define jim_wide long
+# define JIM_WIDE_MIN LONG_MIN
+# define JIM_WIDE_MAX LONG_MAX
+# endif
+
+
+# ifdef HAVE_LONG_LONG
+# define JIM_WIDE_MODIFIER "lld"
+# else
+# define JIM_WIDE_MODIFIER "ld"
+# define strtoull strtoul
+# endif
+#endif
+
+#define UCHAR(c) ((unsigned char)(c))
+
+
+#define JIM_VERSION 73
+
+#define JIM_OK 0
+#define JIM_ERR 1
+#define JIM_RETURN 2
+#define JIM_BREAK 3
+#define JIM_CONTINUE 4
+#define JIM_SIGNAL 5
+#define JIM_EXIT 6
+
+#define JIM_EVAL 7
+
+#define JIM_MAX_CALLFRAME_DEPTH 1000
+#define JIM_MAX_EVAL_DEPTH 2000
+
+#define JIM_NONE 0
+#define JIM_ERRMSG 1
+
+#define JIM_UNSHARED 4
+#define JIM_MUSTEXIST 8
+
+
+#define JIM_GLOBAL_ONLY 0x100
+
+
+#define JIM_SUBST_NOVAR 1
+#define JIM_SUBST_NOCMD 2
+#define JIM_SUBST_NOESC 4
+#define JIM_SUBST_FLAG 128
+
+
+#define JIM_NOTUSED(V) ((void) V)
+
+
+#define JIM_ENUM_ABBREV 2
+
+
+#define JIM_CASESENS 0
+#define JIM_NOCASE 1
+
+
+#define JIM_PATH_LEN 1024
+
+
+#ifdef JIM_CRLF
+#define JIM_NL "\r\n"
+#else
+#define JIM_NL "\n"
+#endif
+
+#define JIM_LIBPATH "auto_path"
+#define JIM_INTERACTIVE "tcl_interactive"
+
+
+typedef struct Jim_Stack {
+ int len;
+ int maxlen;
+ void **vector;
+} Jim_Stack;
+
+
+typedef struct Jim_HashEntry {
+ void *key;
+ union {
+ void *val;
+ int intval;
+ } u;
+ struct Jim_HashEntry *next;
+} Jim_HashEntry;
+
+typedef struct Jim_HashTableType {
+ unsigned int (*hashFunction)(const void *key);
+ void *(*keyDup)(void *privdata, const void *key);
+ void *(*valDup)(void *privdata, const void *obj);
+ int (*keyCompare)(void *privdata, const void *key1, const void *key2);
+ void (*keyDestructor)(void *privdata, void *key);
+ void (*valDestructor)(void *privdata, void *obj);
+} Jim_HashTableType;
+
+typedef struct Jim_HashTable {
+ Jim_HashEntry **table;
+ const Jim_HashTableType *type;
+ unsigned int size;
+ unsigned int sizemask;
+ unsigned int used;
+ unsigned int collisions;
+ void *privdata;
+} Jim_HashTable;
+
+typedef struct Jim_HashTableIterator {
+ Jim_HashTable *ht;
+ int index;
+ Jim_HashEntry *entry, *nextEntry;
+} Jim_HashTableIterator;
+
+
+#define JIM_HT_INITIAL_SIZE 16
+
+
+#define Jim_FreeEntryVal(ht, entry) \
+ if ((ht)->type->valDestructor) \
+ (ht)->type->valDestructor((ht)->privdata, (entry)->u.val)
+
+#define Jim_SetHashVal(ht, entry, _val_) do { \
+ if ((ht)->type->valDup) \
+ entry->u.val = (ht)->type->valDup((ht)->privdata, _val_); \
+ else \
+ entry->u.val = (_val_); \
+} while(0)
+
+#define Jim_FreeEntryKey(ht, entry) \
+ if ((ht)->type->keyDestructor) \
+ (ht)->type->keyDestructor((ht)->privdata, (entry)->key)
+
+#define Jim_SetHashKey(ht, entry, _key_) do { \
+ if ((ht)->type->keyDup) \
+ entry->key = (ht)->type->keyDup((ht)->privdata, _key_); \
+ else \
+ entry->key = (void *)(_key_); \
+} while(0)
+
+#define Jim_CompareHashKeys(ht, key1, key2) \
+ (((ht)->type->keyCompare) ? \
+ (ht)->type->keyCompare((ht)->privdata, key1, key2) : \
+ (key1) == (key2))
+
+#define Jim_HashKey(ht, key) (ht)->type->hashFunction(key)
+
+#define Jim_GetHashEntryKey(he) ((he)->key)
+#define Jim_GetHashEntryVal(he) ((he)->val)
+#define Jim_GetHashTableCollisions(ht) ((ht)->collisions)
+#define Jim_GetHashTableSize(ht) ((ht)->size)
+#define Jim_GetHashTableUsed(ht) ((ht)->used)
+
+
+typedef struct Jim_Obj {
+ int refCount;
+ char *bytes;
+ int length;
+ const struct Jim_ObjType *typePtr;
+
+ union {
+
+ jim_wide wideValue;
+
+ int intValue;
+
+ double doubleValue;
+
+ void *ptr;
+
+ struct {
+ void *ptr1;
+ void *ptr2;
+ } twoPtrValue;
+
+ struct {
+ unsigned long callFrameId;
+ struct Jim_Var *varPtr;
+ int global;
+ } varValue;
+
+ struct {
+ unsigned long procEpoch;
+ struct Jim_Obj *nsObj;
+ struct Jim_Cmd *cmdPtr;
+ } cmdValue;
+
+ struct {
+ struct Jim_Obj **ele;
+ int len;
+ int maxLen;
+ } listValue;
+
+ struct {
+ int maxLength;
+ int charLength;
+ } strValue;
+
+ struct {
+ unsigned long id;
+ struct Jim_Reference *refPtr;
+ } refValue;
+
+ struct {
+ struct Jim_Obj *fileNameObj;
+ int lineNumber;
+ } sourceValue;
+
+ struct {
+ struct Jim_Obj *varNameObjPtr;
+ struct Jim_Obj *indexObjPtr;
+ } dictSubstValue;
+
+ struct {
+ unsigned flags;
+ void *compre;
+ } regexpValue;
+ struct {
+ int line;
+ int argc;
+ } scriptLineValue;
+ } internalRep;
+ struct Jim_Obj *prevObjPtr;
+ struct Jim_Obj *nextObjPtr;
+} Jim_Obj;
+
+
+#define Jim_IncrRefCount(objPtr) \
+ ++(objPtr)->refCount
+#define Jim_DecrRefCount(interp, objPtr) \
+ if (--(objPtr)->refCount <= 0) Jim_FreeObj(interp, objPtr)
+#define Jim_IsShared(objPtr) \
+ ((objPtr)->refCount > 1)
+
+#define Jim_FreeNewObj Jim_FreeObj
+
+
+#define Jim_FreeIntRep(i,o) \
+ if ((o)->typePtr && (o)->typePtr->freeIntRepProc) \
+ (o)->typePtr->freeIntRepProc(i, o)
+
+
+#define Jim_GetIntRepPtr(o) (o)->internalRep.ptr
+
+
+#define Jim_SetIntRepPtr(o, p) \
+ (o)->internalRep.ptr = (p)
+
+
+struct Jim_Interp;
+
+typedef void (Jim_FreeInternalRepProc)(struct Jim_Interp *interp,
+ struct Jim_Obj *objPtr);
+typedef void (Jim_DupInternalRepProc)(struct Jim_Interp *interp,
+ struct Jim_Obj *srcPtr, Jim_Obj *dupPtr);
+typedef void (Jim_UpdateStringProc)(struct Jim_Obj *objPtr);
+
+typedef struct Jim_ObjType {
+ const char *name;
+ Jim_FreeInternalRepProc *freeIntRepProc;
+ Jim_DupInternalRepProc *dupIntRepProc;
+ Jim_UpdateStringProc *updateStringProc;
+ int flags;
+} Jim_ObjType;
+
+
+#define JIM_TYPE_NONE 0
+#define JIM_TYPE_REFERENCES 1
+
+#define JIM_PRIV_FLAG_SHIFT 20
+
+
+
+typedef struct Jim_CallFrame {
+ unsigned long id;
+ int level;
+ struct Jim_HashTable vars;
+ struct Jim_HashTable *staticVars;
+ struct Jim_CallFrame *parent;
+ Jim_Obj *const *argv;
+ int argc;
+ Jim_Obj *procArgsObjPtr;
+ Jim_Obj *procBodyObjPtr;
+ struct Jim_CallFrame *next;
+ Jim_Obj *nsObj;
+ Jim_Obj *fileNameObj;
+ int line;
+ Jim_Stack *localCommands;
+} Jim_CallFrame;
+
+typedef struct Jim_Var {
+ Jim_Obj *objPtr;
+ struct Jim_CallFrame *linkFramePtr;
+} Jim_Var;
+
+
+typedef int (*Jim_CmdProc)(struct Jim_Interp *interp, int argc,
+ Jim_Obj *const *argv);
+typedef void (*Jim_DelCmdProc)(struct Jim_Interp *interp, void *privData);
+
+
+
+typedef struct Jim_Cmd {
+ int inUse;
+ int isproc;
+ struct Jim_Cmd *prevCmd;
+ union {
+ struct {
+
+ Jim_CmdProc cmdProc;
+ Jim_DelCmdProc delProc;
+ void *privData;
+ } native;
+ struct {
+
+ Jim_Obj *argListObjPtr;
+ Jim_Obj *bodyObjPtr;
+ Jim_HashTable *staticVars;
+ int argListLen;
+ int reqArity;
+ int optArity;
+ int argsPos;
+ int upcall;
+ struct Jim_ProcArg {
+ Jim_Obj *nameObjPtr;
+ Jim_Obj *defaultObjPtr;
+ } *arglist;
+ Jim_Obj *nsObj;
+ } proc;
+ } u;
+} Jim_Cmd;
+
+
+typedef struct Jim_PrngState {
+ unsigned char sbox[256];
+ unsigned int i, j;
+} Jim_PrngState;
+
+typedef struct Jim_Interp {
+ Jim_Obj *result;
+ int errorLine;
+ Jim_Obj *errorFileNameObj;
+ int addStackTrace;
+ int maxCallFrameDepth;
+ int maxEvalDepth;
+ int evalDepth;
+ int returnCode;
+ int returnLevel;
+ int exitCode;
+ long id;
+ int signal_level;
+ jim_wide sigmask;
+ int (*signal_set_result)(struct Jim_Interp *interp, jim_wide sigmask);
+ Jim_CallFrame *framePtr;
+ Jim_CallFrame *topFramePtr;
+ struct Jim_HashTable commands;
+ unsigned long procEpoch; /* Incremented every time the result
+ of procedures names lookup caching
+ may no longer be valid. */
+ unsigned long callFrameEpoch; /* Incremented every time a new
+ callframe is created. This id is used for the
+ 'ID' field contained in the Jim_CallFrame
+ structure. */
+ int local;
+ Jim_Obj *liveList;
+ Jim_Obj *freeList;
+ Jim_Obj *currentScriptObj;
+ Jim_Obj *nullScriptObj;
+ Jim_Obj *emptyObj;
+ Jim_Obj *trueObj;
+ Jim_Obj *falseObj;
+ unsigned long referenceNextId;
+ struct Jim_HashTable references;
+ unsigned long lastCollectId; /* reference max Id of the last GC
+ execution. It's set to -1 while the collection
+ is running as sentinel to avoid to recursive
+ calls via the [collect] command inside
+ finalizers. */
+ time_t lastCollectTime;
+ Jim_Obj *stackTrace;
+ Jim_Obj *errorProc;
+ Jim_Obj *unknown;
+ int unknown_called;
+ int errorFlag;
+ void *cmdPrivData; /* Used to pass the private data pointer to
+ a command. It is set to what the user specified
+ via Jim_CreateCommand(). */
+
+ struct Jim_CallFrame *freeFramesList;
+ struct Jim_HashTable assocData;
+ Jim_PrngState *prngState;
+ struct Jim_HashTable packages;
+ Jim_Stack *loadHandles;
+} Jim_Interp;
+
+#define Jim_InterpIncrProcEpoch(i) (i)->procEpoch++
+#define Jim_SetResultString(i,s,l) Jim_SetResult(i, Jim_NewStringObj(i,s,l))
+#define Jim_SetResultInt(i,intval) Jim_SetResult(i, Jim_NewIntObj(i,intval))
+
+#define Jim_SetResultBool(i,b) Jim_SetResultInt(i, b)
+#define Jim_SetEmptyResult(i) Jim_SetResult(i, (i)->emptyObj)
+#define Jim_GetResult(i) ((i)->result)
+#define Jim_CmdPrivData(i) ((i)->cmdPrivData)
+
+#define Jim_SetResult(i,o) do { \
+ Jim_Obj *_resultObjPtr_ = (o); \
+ Jim_IncrRefCount(_resultObjPtr_); \
+ Jim_DecrRefCount(i,(i)->result); \
+ (i)->result = _resultObjPtr_; \
+} while(0)
+
+
+#define Jim_GetId(i) (++(i)->id)
+
+
+#define JIM_REFERENCE_TAGLEN 7 /* The tag is fixed-length, because the reference
+ string representation must be fixed length. */
+typedef struct Jim_Reference {
+ Jim_Obj *objPtr;
+ Jim_Obj *finalizerCmdNamePtr;
+ char tag[JIM_REFERENCE_TAGLEN+1];
+} Jim_Reference;
+
+
+
+#define Jim_NewEmptyStringObj(i) Jim_NewStringObj(i, "", 0)
+
+
+
+#define Jim_FreeHashTableIterator(iter) Jim_Free(iter)
+
+#define JIM_EXPORT
+
+
+JIM_EXPORT void *Jim_Alloc (int size);
+JIM_EXPORT void *Jim_Realloc(void *ptr, int size);
+JIM_EXPORT void Jim_Free (void *ptr);
+JIM_EXPORT char * Jim_StrDup (const char *s);
+JIM_EXPORT char *Jim_StrDupLen(const char *s, int l);
+
+
+JIM_EXPORT char **Jim_GetEnviron(void);
+JIM_EXPORT void Jim_SetEnviron(char **env);
+
+
+JIM_EXPORT int Jim_Eval(Jim_Interp *interp, const char *script);
+
+
+JIM_EXPORT int Jim_EvalSource(Jim_Interp *interp, const char *filename, int lineno, const char *script);
+
+#define Jim_Eval_Named(I, S, F, L) Jim_EvalSource((I), (F), (L), (S))
+
+JIM_EXPORT int Jim_EvalGlobal(Jim_Interp *interp, const char *script);
+JIM_EXPORT int Jim_EvalFile(Jim_Interp *interp, const char *filename);
+JIM_EXPORT int Jim_EvalFileGlobal(Jim_Interp *interp, const char *filename);
+JIM_EXPORT int Jim_EvalObj (Jim_Interp *interp, Jim_Obj *scriptObjPtr);
+JIM_EXPORT int Jim_EvalObjVector (Jim_Interp *interp, int objc,
+ Jim_Obj *const *objv);
+JIM_EXPORT int Jim_EvalObjList(Jim_Interp *interp, Jim_Obj *listObj);
+JIM_EXPORT int Jim_EvalObjPrefix(Jim_Interp *interp, Jim_Obj *prefix,
+ int objc, Jim_Obj *const *objv);
+#define Jim_EvalPrefix(i, p, oc, ov) Jim_EvalObjPrefix((i), Jim_NewStringObj((i), (p), -1), (oc), (ov))
+JIM_EXPORT int Jim_EvalNamespace(Jim_Interp *interp, Jim_Obj *scriptObj, Jim_Obj *nsObj);
+JIM_EXPORT int Jim_SubstObj (Jim_Interp *interp, Jim_Obj *substObjPtr,
+ Jim_Obj **resObjPtrPtr, int flags);
+
+
+JIM_EXPORT void Jim_InitStack(Jim_Stack *stack);
+JIM_EXPORT void Jim_FreeStack(Jim_Stack *stack);
+JIM_EXPORT int Jim_StackLen(Jim_Stack *stack);
+JIM_EXPORT void Jim_StackPush(Jim_Stack *stack, void *element);
+JIM_EXPORT void * Jim_StackPop(Jim_Stack *stack);
+JIM_EXPORT void * Jim_StackPeek(Jim_Stack *stack);
+JIM_EXPORT void Jim_FreeStackElements(Jim_Stack *stack, void (*freeFunc)(void *ptr));
+
+
+JIM_EXPORT int Jim_InitHashTable (Jim_HashTable *ht,
+ const Jim_HashTableType *type, void *privdata);
+JIM_EXPORT void Jim_ExpandHashTable (Jim_HashTable *ht,
+ unsigned int size);
+JIM_EXPORT int Jim_AddHashEntry (Jim_HashTable *ht, const void *key,
+ void *val);
+JIM_EXPORT int Jim_ReplaceHashEntry (Jim_HashTable *ht,
+ const void *key, void *val);
+JIM_EXPORT int Jim_DeleteHashEntry (Jim_HashTable *ht,
+ const void *key);
+JIM_EXPORT int Jim_FreeHashTable (Jim_HashTable *ht);
+JIM_EXPORT Jim_HashEntry * Jim_FindHashEntry (Jim_HashTable *ht,
+ const void *key);
+JIM_EXPORT void Jim_ResizeHashTable (Jim_HashTable *ht);
+JIM_EXPORT Jim_HashTableIterator *Jim_GetHashTableIterator
+ (Jim_HashTable *ht);
+JIM_EXPORT Jim_HashEntry * Jim_NextHashEntry
+ (Jim_HashTableIterator *iter);
+
+
+JIM_EXPORT Jim_Obj * Jim_NewObj (Jim_Interp *interp);
+JIM_EXPORT void Jim_FreeObj (Jim_Interp *interp, Jim_Obj *objPtr);
+JIM_EXPORT void Jim_InvalidateStringRep (Jim_Obj *objPtr);
+JIM_EXPORT void Jim_InitStringRep (Jim_Obj *objPtr, const char *bytes,
+ int length);
+JIM_EXPORT Jim_Obj * Jim_DuplicateObj (Jim_Interp *interp,
+ Jim_Obj *objPtr);
+JIM_EXPORT const char * Jim_GetString(Jim_Obj *objPtr,
+ int *lenPtr);
+JIM_EXPORT const char *Jim_String(Jim_Obj *objPtr);
+JIM_EXPORT int Jim_Length(Jim_Obj *objPtr);
+
+
+JIM_EXPORT Jim_Obj * Jim_NewStringObj (Jim_Interp *interp,
+ const char *s, int len);
+JIM_EXPORT Jim_Obj *Jim_NewStringObjUtf8(Jim_Interp *interp,
+ const char *s, int charlen);
+JIM_EXPORT Jim_Obj * Jim_NewStringObjNoAlloc (Jim_Interp *interp,
+ char *s, int len);
+JIM_EXPORT void Jim_AppendString (Jim_Interp *interp, Jim_Obj *objPtr,
+ const char *str, int len);
+JIM_EXPORT void Jim_AppendObj (Jim_Interp *interp, Jim_Obj *objPtr,
+ Jim_Obj *appendObjPtr);
+JIM_EXPORT void Jim_AppendStrings (Jim_Interp *interp,
+ Jim_Obj *objPtr, ...);
+JIM_EXPORT int Jim_StringEqObj(Jim_Obj *aObjPtr, Jim_Obj *bObjPtr);
+JIM_EXPORT int Jim_StringMatchObj (Jim_Interp *interp, Jim_Obj *patternObjPtr,
+ Jim_Obj *objPtr, int nocase);
+JIM_EXPORT Jim_Obj * Jim_StringRangeObj (Jim_Interp *interp,
+ Jim_Obj *strObjPtr, Jim_Obj *firstObjPtr,
+ Jim_Obj *lastObjPtr);
+JIM_EXPORT Jim_Obj * Jim_FormatString (Jim_Interp *interp,
+ Jim_Obj *fmtObjPtr, int objc, Jim_Obj *const *objv);
+JIM_EXPORT Jim_Obj * Jim_ScanString (Jim_Interp *interp, Jim_Obj *strObjPtr,
+ Jim_Obj *fmtObjPtr, int flags);
+JIM_EXPORT int Jim_CompareStringImmediate (Jim_Interp *interp,
+ Jim_Obj *objPtr, const char *str);
+JIM_EXPORT int Jim_StringCompareObj(Jim_Interp *interp, Jim_Obj *firstObjPtr,
+ Jim_Obj *secondObjPtr, int nocase);
+JIM_EXPORT int Jim_StringCompareLenObj(Jim_Interp *interp, Jim_Obj *firstObjPtr,
+ Jim_Obj *secondObjPtr, int nocase);
+JIM_EXPORT int Jim_Utf8Length(Jim_Interp *interp, Jim_Obj *objPtr);
+
+
+JIM_EXPORT Jim_Obj * Jim_NewReference (Jim_Interp *interp,
+ Jim_Obj *objPtr, Jim_Obj *tagPtr, Jim_Obj *cmdNamePtr);
+JIM_EXPORT Jim_Reference * Jim_GetReference (Jim_Interp *interp,
+ Jim_Obj *objPtr);
+JIM_EXPORT int Jim_SetFinalizer (Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj *cmdNamePtr);
+JIM_EXPORT int Jim_GetFinalizer (Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj **cmdNamePtrPtr);
+
+
+JIM_EXPORT Jim_Interp * Jim_CreateInterp (void);
+JIM_EXPORT void Jim_FreeInterp (Jim_Interp *i);
+JIM_EXPORT int Jim_GetExitCode (Jim_Interp *interp);
+JIM_EXPORT const char *Jim_ReturnCode(int code);
+JIM_EXPORT void Jim_SetResultFormatted(Jim_Interp *interp, const char *format, ...);
+
+
+JIM_EXPORT void Jim_RegisterCoreCommands (Jim_Interp *interp);
+JIM_EXPORT int Jim_CreateCommand (Jim_Interp *interp,
+ const char *cmdName, Jim_CmdProc cmdProc, void *privData,
+ Jim_DelCmdProc delProc);
+JIM_EXPORT int Jim_DeleteCommand (Jim_Interp *interp,
+ const char *cmdName);
+JIM_EXPORT int Jim_RenameCommand (Jim_Interp *interp,
+ const char *oldName, const char *newName);
+JIM_EXPORT Jim_Cmd * Jim_GetCommand (Jim_Interp *interp,
+ Jim_Obj *objPtr, int flags);
+JIM_EXPORT int Jim_SetVariable (Jim_Interp *interp,
+ Jim_Obj *nameObjPtr, Jim_Obj *valObjPtr);
+JIM_EXPORT int Jim_SetVariableStr (Jim_Interp *interp,
+ const char *name, Jim_Obj *objPtr);
+JIM_EXPORT int Jim_SetGlobalVariableStr (Jim_Interp *interp,
+ const char *name, Jim_Obj *objPtr);
+JIM_EXPORT int Jim_SetVariableStrWithStr (Jim_Interp *interp,
+ const char *name, const char *val);
+JIM_EXPORT int Jim_SetVariableLink (Jim_Interp *interp,
+ Jim_Obj *nameObjPtr, Jim_Obj *targetNameObjPtr,
+ Jim_CallFrame *targetCallFrame);
+JIM_EXPORT int Jim_CreateNamespaceVariable(Jim_Interp *interp,
+ Jim_Obj *varNameObj, Jim_Obj *targetNameObj);
+JIM_EXPORT int Jim_DiscardNamespaceVars(Jim_Interp *interp);
+JIM_EXPORT Jim_Obj * Jim_GetVariable (Jim_Interp *interp,
+ Jim_Obj *nameObjPtr, int flags);
+JIM_EXPORT Jim_Obj * Jim_GetGlobalVariable (Jim_Interp *interp,
+ Jim_Obj *nameObjPtr, int flags);
+JIM_EXPORT Jim_Obj * Jim_GetVariableStr (Jim_Interp *interp,
+ const char *name, int flags);
+JIM_EXPORT Jim_Obj * Jim_GetGlobalVariableStr (Jim_Interp *interp,
+ const char *name, int flags);
+JIM_EXPORT int Jim_UnsetVariable (Jim_Interp *interp,
+ Jim_Obj *nameObjPtr, int flags);
+
+
+JIM_EXPORT Jim_CallFrame *Jim_GetCallFrameByLevel(Jim_Interp *interp,
+ Jim_Obj *levelObjPtr);
+
+
+JIM_EXPORT int Jim_Collect (Jim_Interp *interp);
+JIM_EXPORT void Jim_CollectIfNeeded (Jim_Interp *interp);
+
+
+JIM_EXPORT int Jim_GetIndex (Jim_Interp *interp, Jim_Obj *objPtr,
+ int *indexPtr);
+
+
+JIM_EXPORT Jim_Obj * Jim_NewListObj (Jim_Interp *interp,
+ Jim_Obj *const *elements, int len);
+JIM_EXPORT void Jim_ListInsertElements (Jim_Interp *interp,
+ Jim_Obj *listPtr, int listindex, int objc, Jim_Obj *const *objVec);
+JIM_EXPORT void Jim_ListAppendElement (Jim_Interp *interp,
+ Jim_Obj *listPtr, Jim_Obj *objPtr);
+JIM_EXPORT void Jim_ListAppendList (Jim_Interp *interp,
+ Jim_Obj *listPtr, Jim_Obj *appendListPtr);
+JIM_EXPORT int Jim_ListLength (Jim_Interp *interp, Jim_Obj *objPtr);
+JIM_EXPORT int Jim_ListIndex (Jim_Interp *interp, Jim_Obj *listPrt,
+ int listindex, Jim_Obj **objPtrPtr, int seterr);
+JIM_EXPORT Jim_Obj *Jim_ListGetIndex(Jim_Interp *interp, Jim_Obj *listPtr, int idx);
+JIM_EXPORT int Jim_SetListIndex (Jim_Interp *interp,
+ Jim_Obj *varNamePtr, Jim_Obj *const *indexv, int indexc,
+ Jim_Obj *newObjPtr);
+JIM_EXPORT Jim_Obj * Jim_ConcatObj (Jim_Interp *interp, int objc,
+ Jim_Obj *const *objv);
+JIM_EXPORT Jim_Obj *Jim_ListJoin(Jim_Interp *interp,
+ Jim_Obj *listObjPtr, const char *joinStr, int joinStrLen);
+
+
+JIM_EXPORT Jim_Obj * Jim_NewDictObj (Jim_Interp *interp,
+ Jim_Obj *const *elements, int len);
+JIM_EXPORT int Jim_DictKey (Jim_Interp *interp, Jim_Obj *dictPtr,
+ Jim_Obj *keyPtr, Jim_Obj **objPtrPtr, int flags);
+JIM_EXPORT int Jim_DictKeysVector (Jim_Interp *interp,
+ Jim_Obj *dictPtr, Jim_Obj *const *keyv, int keyc,
+ Jim_Obj **objPtrPtr, int flags);
+JIM_EXPORT int Jim_SetDictKeysVector (Jim_Interp *interp,
+ Jim_Obj *varNamePtr, Jim_Obj *const *keyv, int keyc,
+ Jim_Obj *newObjPtr, int flags);
+JIM_EXPORT int Jim_DictPairs(Jim_Interp *interp,
+ Jim_Obj *dictPtr, Jim_Obj ***objPtrPtr, int *len);
+JIM_EXPORT int Jim_DictAddElement(Jim_Interp *interp, Jim_Obj *objPtr,
+ Jim_Obj *keyObjPtr, Jim_Obj *valueObjPtr);
+JIM_EXPORT int Jim_DictKeys(Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj *patternObj);
+JIM_EXPORT int Jim_DictValues(Jim_Interp *interp, Jim_Obj *dictObjPtr, Jim_Obj *patternObjPtr);
+JIM_EXPORT int Jim_DictSize(Jim_Interp *interp, Jim_Obj *objPtr);
+
+
+JIM_EXPORT int Jim_GetReturnCode (Jim_Interp *interp, Jim_Obj *objPtr,
+ int *intPtr);
+
+
+JIM_EXPORT int Jim_EvalExpression (Jim_Interp *interp,
+ Jim_Obj *exprObjPtr, Jim_Obj **exprResultPtrPtr);
+JIM_EXPORT int Jim_GetBoolFromExpr (Jim_Interp *interp,
+ Jim_Obj *exprObjPtr, int *boolPtr);
+
+
+JIM_EXPORT int Jim_GetWide (Jim_Interp *interp, Jim_Obj *objPtr,
+ jim_wide *widePtr);
+JIM_EXPORT int Jim_GetLong (Jim_Interp *interp, Jim_Obj *objPtr,
+ long *longPtr);
+#define Jim_NewWideObj Jim_NewIntObj
+JIM_EXPORT Jim_Obj * Jim_NewIntObj (Jim_Interp *interp,
+ jim_wide wideValue);
+
+
+JIM_EXPORT int Jim_GetDouble(Jim_Interp *interp, Jim_Obj *objPtr,
+ double *doublePtr);
+JIM_EXPORT void Jim_SetDouble(Jim_Interp *interp, Jim_Obj *objPtr,
+ double doubleValue);
+JIM_EXPORT Jim_Obj * Jim_NewDoubleObj(Jim_Interp *interp, double doubleValue);
+
+
+JIM_EXPORT const char * Jim_GetSharedString (Jim_Interp *interp,
+ const char *str);
+JIM_EXPORT void Jim_ReleaseSharedString (Jim_Interp *interp,
+ const char *str);
+
+
+JIM_EXPORT void Jim_WrongNumArgs (Jim_Interp *interp, int argc,
+ Jim_Obj *const *argv, const char *msg);
+JIM_EXPORT int Jim_GetEnum (Jim_Interp *interp, Jim_Obj *objPtr,
+ const char * const *tablePtr, int *indexPtr, const char *name, int flags);
+JIM_EXPORT int Jim_ScriptIsComplete (const char *s, int len,
+ char *stateCharPtr);
+JIM_EXPORT int Jim_FindByName(const char *name, const char * const array[], size_t len);
+
+
+typedef void (Jim_InterpDeleteProc)(Jim_Interp *interp, void *data);
+JIM_EXPORT void * Jim_GetAssocData(Jim_Interp *interp, const char *key);
+JIM_EXPORT int Jim_SetAssocData(Jim_Interp *interp, const char *key,
+ Jim_InterpDeleteProc *delProc, void *data);
+JIM_EXPORT int Jim_DeleteAssocData(Jim_Interp *interp, const char *key);
+
+
+
+JIM_EXPORT int Jim_PackageProvide (Jim_Interp *interp,
+ const char *name, const char *ver, int flags);
+JIM_EXPORT int Jim_PackageRequire (Jim_Interp *interp,
+ const char *name, int flags);
+
+
+JIM_EXPORT void Jim_MakeErrorMessage (Jim_Interp *interp);
+
+
+JIM_EXPORT int Jim_InteractivePrompt (Jim_Interp *interp);
+JIM_EXPORT void Jim_HistoryLoad(const char *filename);
+JIM_EXPORT void Jim_HistorySave(const char *filename);
+JIM_EXPORT char *Jim_HistoryGetline(const char *prompt);
+JIM_EXPORT void Jim_HistoryAdd(const char *line);
+JIM_EXPORT void Jim_HistoryShow(void);
+
+
+JIM_EXPORT int Jim_InitStaticExtensions(Jim_Interp *interp);
+JIM_EXPORT int Jim_StringToWide(const char *str, jim_wide *widePtr, int base);
+
+
+JIM_EXPORT int Jim_LoadLibrary(Jim_Interp *interp, const char *pathName);
+JIM_EXPORT void Jim_FreeLoadHandles(Jim_Interp *interp);
+
+
+JIM_EXPORT FILE *Jim_AioFilehandle(Jim_Interp *interp, Jim_Obj *command);
+
+
+
+JIM_EXPORT int Jim_IsDict(Jim_Obj *objPtr);
+JIM_EXPORT int Jim_IsList(Jim_Obj *objPtr);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+#ifndef JIM_SUBCMD_H
+#define JIM_SUBCMD_H
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+#define JIM_MODFLAG_HIDDEN 0x0001
+#define JIM_MODFLAG_FULLARGV 0x0002
+
+
+
+typedef int tclmod_cmd_function(Jim_Interp *interp, int argc, Jim_Obj *const *argv);
+
+typedef struct {
+ const char *cmd;
+ const char *args;
+ tclmod_cmd_function *function;
+ short minargs;
+ short maxargs;
+ unsigned short flags;
+} jim_subcmd_type;
+
+const jim_subcmd_type *
+Jim_ParseSubCmd(Jim_Interp *interp, const jim_subcmd_type *command_table, int argc, Jim_Obj *const *argv);
+
+int Jim_SubCmdProc(Jim_Interp *interp, int argc, Jim_Obj *const *argv);
+
+int Jim_CallSubCmd(Jim_Interp *interp, const jim_subcmd_type *ct, int argc, Jim_Obj *const *argv);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+#ifndef JIMREGEXP_H
+#define JIMREGEXP_H
+
+#ifndef _JIMAUTOCONF_H
+#error Need jimautoconf.h
+#endif
+
+#if defined(HAVE_REGCOMP) && !defined(JIM_REGEXP)
+
+#include
+
+#else
+
+#include
+
+
+typedef struct {
+ int rm_so;
+ int rm_eo;
+} regmatch_t;
+
+
+typedef struct regexp {
+
+ int re_nsub;
+
+
+ int cflags;
+ int err;
+ int regstart;
+ int reganch;
+ int regmust;
+ int regmlen;
+ int *program;
+
+
+ const char *regparse;
+ int p;
+ int proglen;
+
+
+ int eflags;
+ const char *start;
+ const char *reginput;
+ const char *regbol;
+
+
+ regmatch_t *pmatch;
+ int nmatch;
+} regexp;
+
+typedef regexp regex_t;
+
+#define REG_EXTENDED 0
+#define REG_NEWLINE 1
+#define REG_ICASE 2
+
+#define REG_NOTBOL 16
+
+enum {
+ REG_NOERROR,
+ REG_NOMATCH,
+ REG_BADPAT,
+ REG_ERR_NULL_ARGUMENT,
+ REG_ERR_UNKNOWN,
+ REG_ERR_TOO_BIG,
+ REG_ERR_NOMEM,
+ REG_ERR_TOO_MANY_PAREN,
+ REG_ERR_UNMATCHED_PAREN,
+ REG_ERR_UNMATCHED_BRACES,
+ REG_ERR_BAD_COUNT,
+ REG_ERR_JUNK_ON_END,
+ REG_ERR_OPERAND_COULD_BE_EMPTY,
+ REG_ERR_NESTED_COUNT,
+ REG_ERR_INTERNAL,
+ REG_ERR_COUNT_FOLLOWS_NOTHING,
+ REG_ERR_TRAILING_BACKSLASH,
+ REG_ERR_CORRUPTED,
+ REG_ERR_NULL_CHAR,
+ REG_ERR_NUM
+};
+
+int regcomp(regex_t *preg, const char *regex, int cflags);
+int regexec(regex_t *preg, const char *string, size_t nmatch, regmatch_t pmatch[], int eflags);
+size_t regerror(int errcode, const regex_t *preg, char *errbuf, size_t errbuf_size);
+void regfree(regex_t *preg);
+
+#endif
+
+#endif
+int Jim_bootstrapInit(Jim_Interp *interp)
+{
+ if (Jim_PackageProvide(interp, "bootstrap", "1.0", JIM_ERRMSG))
+ return JIM_ERR;
+
+ return Jim_EvalSource(interp, "bootstrap.tcl", 1,
+"\n"
+"\n"
+"proc package {args} {}\n"
+);
+}
+int Jim_initjimshInit(Jim_Interp *interp)
+{
+ if (Jim_PackageProvide(interp, "initjimsh", "1.0", JIM_ERRMSG))
+ return JIM_ERR;
+
+ return Jim_EvalSource(interp, "initjimsh.tcl", 1,
+"\n"
+"\n"
+"\n"
+"proc _jimsh_init {} {\n"
+" rename _jimsh_init {}\n"
+"\n"
+"\n"
+" lappend p {*}[split [env JIMLIB {}] $::tcl_platform(pathSeparator)]\n"
+" lappend p {*}$::auto_path\n"
+" lappend p [file dirname [info nameofexecutable]]\n"
+" set ::auto_path $p\n"
+"\n"
+" if {$::tcl_interactive && [env HOME {}] ne \"\"} {\n"
+" foreach src {.jimrc jimrc.tcl} {\n"
+" if {[file exists [env HOME]/$src]} {\n"
+" uplevel #0 source [env HOME]/$src\n"
+" break\n"
+" }\n"
+" }\n"
+" }\n"
+"}\n"
+"\n"
+"if {$tcl_platform(platform) eq \"windows\"} {\n"
+" set jim_argv0 [string map {\\\\ /} $jim_argv0]\n"
+"}\n"
+"\n"
+"_jimsh_init\n"
+);
+}
+int Jim_globInit(Jim_Interp *interp)
+{
+ if (Jim_PackageProvide(interp, "glob", "1.0", JIM_ERRMSG))
+ return JIM_ERR;
+
+ return Jim_EvalSource(interp, "glob.tcl", 1,
+"\n"
+"\n"
+"\n"
+"\n"
+"\n"
+"\n"
+"\n"
+"package require readdir\n"
+"\n"
+"\n"
+"proc glob.globdir {dir pattern} {\n"
+" set result {}\n"
+" set files [readdir $dir]\n"
+" lappend files . ..\n"
+"\n"
+" foreach name $files {\n"
+" if {[string match $pattern $name]} {\n"
+"\n"
+" if {[string index $name 0] eq \".\" && [string index $pattern 0] ne \".\"} {\n"
+" continue\n"
+" }\n"
+" lappend result $name\n"
+" }\n"
+" }\n"
+"\n"
+" return $result\n"
+"}\n"
+"\n"
+"\n"
+"\n"
+"\n"
+"proc glob.explode {pattern} {\n"
+" set oldexp {}\n"
+" set newexp {\"\"}\n"
+"\n"
+" while 1 {\n"
+" set oldexp $newexp\n"
+" set newexp {}\n"
+" set ob [string first \\{ $pattern]\n"
+" set cb [string first \\} $pattern]\n"
+"\n"
+" if {$ob < $cb && $ob != -1} {\n"
+" set mid [string range $pattern 0 $ob-1]\n"
+" set subexp [lassign [glob.explode [string range $pattern $ob+1 end]] pattern]\n"
+" if {$pattern eq \"\"} {\n"
+" error \"unmatched open brace in glob pattern\"\n"
+" }\n"
+" set pattern [string range $pattern 1 end]\n"
+"\n"
+" foreach subs $subexp {\n"
+" foreach sub [split $subs ,] {\n"
+" foreach old $oldexp {\n"
+" lappend newexp $old$mid$sub\n"
+" }\n"
+" }\n"
+" }\n"
+" } elseif {$cb != -1} {\n"
+" set suf [string range $pattern 0 $cb-1]\n"
+" set rest [string range $pattern $cb end]\n"
+" break\n"
+" } else {\n"
+" set suf $pattern\n"
+" set rest \"\"\n"
+" break\n"
+" }\n"
+" }\n"
+"\n"
+" foreach old $oldexp {\n"
+" lappend newexp $old$suf\n"
+" }\n"
+" linsert $newexp 0 $rest\n"
+"}\n"
+"\n"
+"\n"
+"\n"
+"proc glob.glob {base pattern} {\n"
+" set dir [file dirname $pattern]\n"
+" if {$pattern eq $dir || $pattern eq \"\"} {\n"
+" return [list [file join $base $dir] $pattern]\n"
+" } elseif {$pattern eq [file tail $pattern]} {\n"
+" set dir \"\"\n"
+" }\n"
+"\n"
+"\n"
+" set dirlist [glob.glob $base $dir]\n"
+" set pattern [file tail $pattern]\n"
+"\n"
+"\n"
+" set result {}\n"
+" foreach {realdir dir} $dirlist {\n"
+" if {![file isdir $realdir]} {\n"
+" continue\n"
+" }\n"
+" if {[string index $dir end] ne \"/\" && $dir ne \"\"} {\n"
+" append dir /\n"
+" }\n"
+" foreach name [glob.globdir $realdir $pattern] {\n"
+" lappend result [file join $realdir $name] $dir$name\n"
+" }\n"
+" }\n"
+" return $result\n"
+"}\n"
+"\n"
+"\n"
+"\n"
+"\n"
+"\n"
+"\n"
+"\n"
+"\n"
+"\n"
+"\n"
+"\n"
+"\n"
+"proc glob {args} {\n"
+" set nocomplain 0\n"
+" set base \"\"\n"
+"\n"
+" set n 0\n"
+" foreach arg $args {\n"
+" if {[info exists param]} {\n"
+" set $param $arg\n"
+" unset param\n"
+" incr n\n"
+" continue\n"
+" }\n"
+" switch -glob -- $arg {\n"
+" -d* {\n"
+" set switch $arg\n"
+" set param base\n"
+" }\n"
+" -n* {\n"
+" set nocomplain 1\n"
+" }\n"
+" -t* {\n"
+"\n"
+" }\n"
+"\n"
+" -* {\n"
+" return -code error \"bad option \\\"$switch\\\": must be -directory, -nocomplain, -tails, or --\"\n"
+" }\n"
+" -- {\n"
+" incr n\n"
+" break\n"
+" }\n"
+" * {\n"
+" break\n"
+" }\n"
+" }\n"
+" incr n\n"
+" }\n"
+" if {[info exists param]} {\n"
+" return -code error \"missing argument to \\\"$switch\\\"\"\n"
+" }\n"
+" if {[llength $args] <= $n} {\n"
+" return -code error \"wrong # args: should be \\\"glob ?options? pattern ?pattern ...?\\\"\"\n"
+" }\n"
+"\n"
+" set args [lrange $args $n end]\n"
+"\n"
+" set result {}\n"
+" foreach pattern $args {\n"
+" set pattern [string map {\n"
+" \\\\\\\\ \\x01 \\\\\\{ \\x02 \\\\\\} \\x03 \\\\, \\x04\n"
+" } $pattern]\n"
+" set patexps [lassign [glob.explode $pattern] rest]\n"
+" if {$rest ne \"\"} {\n"
+" return -code error \"unmatched close brace in glob pattern\"\n"
+" }\n"
+" foreach patexp $patexps {\n"
+" set patexp [string map {\n"
+" \\x01 \\\\\\\\ \\x02 \\{ \\x03 \\} \\x04 ,\n"
+" } $patexp]\n"
+" foreach {realname name} [glob.glob $base $patexp] {\n"
+" lappend result $name\n"
+" }\n"
+" }\n"
+" }\n"
+"\n"
+" if {!$nocomplain && [llength $result] == 0} {\n"
+" return -code error \"no files matched glob patterns\"\n"
+" }\n"
+"\n"
+" return $result\n"
+"}\n"
+);
+}
+int Jim_stdlibInit(Jim_Interp *interp)
+{
+ if (Jim_PackageProvide(interp, "stdlib", "1.0", JIM_ERRMSG))
+ return JIM_ERR;
+
+ return Jim_EvalSource(interp, "stdlib.tcl", 1,
+"\n"
+"proc lambda {arglist args} {\n"
+" tailcall proc [ref {} function lambda.finalizer] $arglist {*}$args\n"
+"}\n"
+"\n"
+"proc lambda.finalizer {name val} {\n"
+" rename $name {}\n"
+"}\n"
+"\n"
+"\n"
+"proc curry {args} {\n"
+" alias [ref {} function lambda.finalizer] {*}$args\n"
+"}\n"
+"\n"
+"\n"
+"\n"
+"\n"
+"\n"
+"\n"
+"\n"
+"\n"
+"\n"
+"proc function {value} {\n"
+" return $value\n"
+"}\n"
+"\n"
+"\n"
+"\n"
+"\n"
+"proc stacktrace {} {\n"
+" set trace {}\n"
+" foreach level [range 1 [info level]] {\n"
+" lassign [info frame -$level] p f l\n"
+" lappend trace $p $f $l\n"
+" }\n"
+" return $trace\n"
+"}\n"
+"\n"
+"\n"
+"proc stackdump {stacktrace} {\n"
+" set result {}\n"
+" set count 0\n"
+" foreach {l f p} [lreverse $stacktrace] {\n"
+" if {$count} {\n"
+" append result \\n\n"
+" }\n"
+" incr count\n"
+" if {$p ne \"\"} {\n"
+" append result \"in procedure '$p' \"\n"
+" if {$f ne \"\"} {\n"
+" append result \"called \"\n"
+" }\n"
+" }\n"
+" if {$f ne \"\"} {\n"
+" append result \"at file \\\"$f\\\", line $l\"\n"
+" }\n"
+" }\n"
+" return $result\n"
+"}\n"
+"\n"
+"\n"
+"\n"
+"proc errorInfo {msg {stacktrace \"\"}} {\n"
+" if {$stacktrace eq \"\"} {\n"
+" set stacktrace [info stacktrace]\n"
+" }\n"
+" lassign $stacktrace p f l\n"
+" if {$f ne \"\"} {\n"
+" set result \"Runtime Error: $f:$l: \"\n"
+" }\n"
+" append result \"$msg\\n\"\n"
+" append result [stackdump $stacktrace]\n"
+"\n"
+"\n"
+" string trim $result\n"
+"}\n"
+"\n"
+"\n"
+"\n"
+"proc {info nameofexecutable} {} {\n"
+" if {[info exists ::jim_argv0]} {\n"
+" if {[string match \"*/*\" $::jim_argv0]} {\n"
+" return [file join [pwd] $::jim_argv0]\n"
+" }\n"
+" foreach path [split [env PATH \"\"] $::tcl_platform(pathSeparator)] {\n"
+" set exec [file join [pwd] [string map {\\\\ /} $path] $::jim_argv0]\n"
+" if {[file executable $exec]} {\n"
+" return $exec\n"
+" }\n"
+" }\n"
+" }\n"
+" return \"\"\n"
+"}\n"
+"\n"
+"\n"
+"proc {dict with} {dictVar args script} {\n"
+" upvar $dictVar dict\n"
+" set keys {}\n"
+" foreach {n v} [dict get $dict {*}$args] {\n"
+" upvar $n var_$n\n"
+" set var_$n $v\n"
+" lappend keys $n\n"
+" }\n"
+" catch {uplevel 1 $script} msg opts\n"
+" if {[info exists dict] && [dict exists $dict {*}$args]} {\n"
+" foreach n $keys {\n"
+" if {[info exists var_$n]} {\n"
+" dict set dict {*}$args $n [set var_$n]\n"
+" } else {\n"
+" dict unset dict {*}$args $n\n"
+" }\n"
+" }\n"
+" }\n"
+" return {*}$opts $msg\n"
+"}\n"
+"\n"
+"\n"
+"\n"
+"proc {dict merge} {dict args} {\n"
+" foreach d $args {\n"
+"\n"
+" dict size $d\n"
+" foreach {k v} $d {\n"
+" dict set dict $k $v\n"
+" }\n"
+" }\n"
+" return $dict\n"
+"}\n"
+);
+}
+int Jim_tclcompatInit(Jim_Interp *interp)
+{
+ if (Jim_PackageProvide(interp, "tclcompat", "1.0", JIM_ERRMSG))
+ return JIM_ERR;
+
+ return Jim_EvalSource(interp, "tclcompat.tcl", 1,
+"\n"
+"\n"
+"\n"
+"\n"
+"\n"
+"\n"
+"\n"
+"set env [env]\n"
+"\n"
+"if {[info commands stdout] ne \"\"} {\n"
+"\n"
+" foreach p {gets flush close eof seek tell} {\n"
+" proc $p {chan args} {p} {\n"
+" tailcall $chan $p {*}$args\n"
+" }\n"
+" }\n"
+" unset p\n"
+"\n"
+"\n"
+"\n"
+" proc puts {{-nonewline {}} {chan stdout} msg} {\n"
+" if {${-nonewline} ni {-nonewline {}}} {\n"
+" tailcall ${-nonewline} puts $msg\n"
+" }\n"
+" tailcall $chan puts {*}${-nonewline} $msg\n"
+" }\n"
+"\n"
+"\n"
+"\n"
+"\n"
+"\n"
+" proc read {{-nonewline {}} chan} {\n"
+" if {${-nonewline} ni {-nonewline {}}} {\n"
+" tailcall ${-nonewline} read {*}${chan}\n"
+" }\n"
+" tailcall $chan read {*}${-nonewline}\n"
+" }\n"
+"\n"
+" proc fconfigure {f args} {\n"
+" foreach {n v} $args {\n"
+" switch -glob -- $n {\n"
+" -bl* {\n"
+" $f ndelay $(!$v)\n"
+" }\n"
+" -bu* {\n"
+" $f buffering $v\n"
+" }\n"
+" -tr* {\n"
+"\n"
+" }\n"
+" default {\n"
+" return -code error \"fconfigure: unknown option $n\"\n"
+" }\n"
+" }\n"
+" }\n"
+" }\n"
+"}\n"
+"\n"
+"\n"
+"proc case {var args} {\n"
+"\n"
+" if {[lindex $args 0] eq \"in\"} {\n"
+" set args [lrange $args 1 end]\n"
+" }\n"
+"\n"
+"\n"
+" if {[llength $args] == 1} {\n"
+" set args [lindex $args 0]\n"
+" }\n"
+"\n"
+"\n"
+" if {[llength $args] % 2 != 0} {\n"
+" return -code error \"extra case pattern with no body\"\n"
+" }\n"
+"\n"
+"\n"
+" local proc case.checker {value pattern} {\n"
+" string match $pattern $value\n"
+" }\n"
+"\n"
+" foreach {value action} $args {\n"
+" if {$value eq \"default\"} {\n"
+" set do_action $action\n"
+" continue\n"
+" } elseif {[lsearch -bool -command case.checker $value $var]} {\n"
+" set do_action $action\n"
+" break\n"
+" }\n"
+" }\n"
+"\n"
+" if {[info exists do_action]} {\n"
+" set rc [catch [list uplevel 1 $do_action] result opts]\n"
+" if {$rc} {\n"
+" incr opts(-level)\n"
+" }\n"
+" return {*}$opts $result\n"
+" }\n"
+"}\n"
+"\n"
+"\n"
+"proc fileevent {args} {\n"
+" tailcall {*}$args\n"
+"}\n"
+"\n"
+"\n"
+"\n"
+"\n"
+"proc parray {arrayname {pattern *} {puts puts}} {\n"
+" upvar $arrayname a\n"
+"\n"
+" set max 0\n"
+" foreach name [array names a $pattern]] {\n"
+" if {[string length $name] > $max} {\n"
+" set max [string length $name]\n"
+" }\n"
+" }\n"
+" incr max [string length $arrayname]\n"
+" incr max 2\n"
+" foreach name [lsort [array names a $pattern]] {\n"
+" $puts [format \"%-${max}s = %s\" $arrayname\\($name\\) $a($name)]\n"
+" }\n"
+"}\n"
+"\n"
+"\n"
+"proc {file copy} {{force {}} source target} {\n"
+" try {\n"
+" if {$force ni {{} -force}} {\n"
+" error \"bad option \\\"$force\\\": should be -force\"\n"
+" }\n"
+"\n"
+" set in [open $source]\n"
+"\n"
+" if {$force eq \"\" && [file exists $target]} {\n"
+" $in close\n"
+" error \"error copying \\\"$source\\\" to \\\"$target\\\": file already exists\"\n"
+" }\n"
+" set out [open $target w]\n"
+" $in copyto $out\n"
+" $out close\n"
+" } on error {msg opts} {\n"
+" incr opts(-level)\n"
+" return {*}$opts $msg\n"
+" } finally {\n"
+" catch {$in close}\n"
+" }\n"
+"}\n"
+"\n"
+"\n"
+"\n"
+"proc popen {cmd {mode r}} {\n"
+" lassign [socket pipe] r w\n"
+" try {\n"
+" if {[string match \"w*\" $mode]} {\n"
+" lappend cmd <@$r &\n"
+" set pids [exec {*}$cmd]\n"
+" $r close\n"
+" set f $w\n"
+" } else {\n"
+" lappend cmd >@$w &\n"
+" set pids [exec {*}$cmd]\n"
+" $w close\n"
+" set f $r\n"
+" }\n"
+" lambda {cmd args} {f pids} {\n"
+" if {$cmd eq \"pid\"} {\n"
+" return $pids\n"
+" }\n"
+" if {$cmd eq \"close\"} {\n"
+" $f close\n"
+"\n"
+" foreach p $pids { os.wait $p }\n"
+" return\n"
+" }\n"
+" tailcall $f $cmd {*}$args\n"
+" }\n"
+" } on error {error opts} {\n"
+" $r close\n"
+" $w close\n"
+" error $error\n"
+" }\n"
+"}\n"
+"\n"
+"\n"
+"local proc pid {{chan {}}} {\n"
+" if {$chan eq \"\"} {\n"
+" tailcall upcall pid\n"
+" }\n"
+" if {[catch {$chan tell}]} {\n"
+" return -code error \"can not find channel named \\\"$chan\\\"\"\n"
+" }\n"
+" if {[catch {$chan pid} pids]} {\n"
+" return \"\"\n"
+" }\n"
+" return $pids\n"
+"}\n"
+"\n"
+"\n"
+"\n"
+"\n"
+"\n"
+"\n"
+"\n"
+"\n"
+"\n"
+"\n"
+"\n"
+"\n"
+"\n"
+"\n"
+"proc try {args} {\n"
+" set catchopts {}\n"
+" while {[string match -* [lindex $args 0]]} {\n"
+" set args [lassign $args opt]\n"
+" if {$opt eq \"--\"} {\n"
+" break\n"
+" }\n"
+" lappend catchopts $opt\n"
+" }\n"
+" if {[llength $args] == 0} {\n"
+" return -code error {wrong # args: should be \"try ?options? script ?argument ...?\"}\n"
+" }\n"
+" set args [lassign $args script]\n"
+" set code [catch -eval {*}$catchopts [list uplevel 1 $script] msg opts]\n"
+"\n"
+" set handled 0\n"
+"\n"
+" foreach {on codes vars script} $args {\n"
+" switch -- $on \\\n"
+" on {\n"
+" if {!$handled && ($codes eq \"*\" || [info returncode $code] in $codes)} {\n"
+" lassign $vars msgvar optsvar\n"
+" if {$msgvar ne \"\"} {\n"
+" upvar $msgvar hmsg\n"
+" set hmsg $msg\n"
+" }\n"
+" if {$optsvar ne \"\"} {\n"
+" upvar $optsvar hopts\n"
+" set hopts $opts\n"
+" }\n"
+"\n"
+" set code [catch [list uplevel 1 $script] msg opts]\n"
+" incr handled\n"
+" }\n"
+" } \\\n"
+" finally {\n"
+" set finalcode [catch [list uplevel 1 $codes] finalmsg finalopts]\n"
+" if {$finalcode} {\n"
+"\n"
+" set code $finalcode\n"
+" set msg $finalmsg\n"
+" set opts $finalopts\n"
+" }\n"
+" break\n"
+" } \\\n"
+" default {\n"
+" return -code error \"try: expected 'on' or 'finally', got '$on'\"\n"
+" }\n"
+" }\n"
+"\n"
+" if {$code} {\n"
+" incr opts(-level)\n"
+" return {*}$opts $msg\n"
+" }\n"
+" return $msg\n"
+"}\n"
+"\n"
+"\n"
+"\n"
+"proc throw {code {msg \"\"}} {\n"
+" return -code $code $msg\n"
+"}\n"
+"\n"
+"\n"
+"proc {file delete force} {path} {\n"
+" foreach e [readdir $path] {\n"
+" file delete -force $path/$e\n"
+" }\n"
+" file delete $path\n"
+"}\n"
+);
+}
+
+
+
+#include
+#include
+#include
+#include
+
+
+#if defined(HAVE_SYS_SOCKET_H) && defined(HAVE_SELECT) && defined(HAVE_NETINET_IN_H) && defined(HAVE_NETDB_H) && defined(HAVE_ARPA_INET_H)
+#include
+#include
+#include
+#include
+#include
+#ifdef HAVE_SYS_UN_H
+#include
+#endif
+#else
+#define JIM_ANSIC
+#endif
+
+
+#define AIO_CMD_LEN 32
+#define AIO_BUF_LEN 256
+
+#ifndef HAVE_FTELLO
+ #define ftello ftell
+#endif
+#ifndef HAVE_FSEEKO
+ #define fseeko fseek
+#endif
+
+#define AIO_KEEPOPEN 1
+
+#if defined(JIM_IPV6)
+#define IPV6 1
+#else
+#define IPV6 0
+#ifndef PF_INET6
+#define PF_INET6 0
+#endif
+#endif
+
+
+typedef struct AioFile
+{
+ FILE *fp;
+ Jim_Obj *filename;
+ int type;
+ int OpenFlags;
+ int fd;
+#ifdef O_NDELAY
+ int flags;
+#endif
+ Jim_Obj *rEvent;
+ Jim_Obj *wEvent;
+ Jim_Obj *eEvent;
+ int addr_family;
+} AioFile;
+
+static int JimAioSubCmdProc(Jim_Interp *interp, int argc, Jim_Obj *const *argv);
+static int JimMakeChannel(Jim_Interp *interp, FILE *fh, int fd, Jim_Obj *filename,
+ const char *hdlfmt, int family, const char *mode);
+
+
+static void JimAioSetError(Jim_Interp *interp, Jim_Obj *name)
+{
+ if (name) {
+ Jim_SetResultFormatted(interp, "%#s: %s", name, strerror(errno));
+ }
+ else {
+ Jim_SetResultString(interp, strerror(errno), -1);
+ }
+}
+
+static void JimAioDelProc(Jim_Interp *interp, void *privData)
+{
+ AioFile *af = privData;
+
+ JIM_NOTUSED(interp);
+
+ if (!(af->OpenFlags & AIO_KEEPOPEN)) {
+ fclose(af->fp);
+ }
+
+ Jim_DecrRefCount(interp, af->filename);
+
+#ifdef jim_ext_eventloop
+
+ if (af->rEvent) {
+ Jim_DeleteFileHandler(interp, af->fp);
+ }
+ if (af->wEvent) {
+ Jim_DeleteFileHandler(interp, af->fp);
+ }
+ if (af->eEvent) {
+ Jim_DeleteFileHandler(interp, af->fp);
+ }
+#endif
+ Jim_Free(af);
+}
+
+static int JimCheckStreamError(Jim_Interp *interp, AioFile *af)
+{
+ if (!ferror(af->fp)) {
+ return JIM_OK;
+ }
+ clearerr(af->fp);
+
+ if (feof(af->fp) || errno == EAGAIN || errno == EINTR) {
+ return JIM_OK;
+ }
+#ifdef ECONNRESET
+ if (errno == ECONNRESET) {
+ return JIM_OK;
+ }
+#endif
+#ifdef ECONNABORTED
+ if (errno != ECONNABORTED) {
+ return JIM_OK;
+ }
+#endif
+ JimAioSetError(interp, af->filename);
+ return JIM_ERR;
+}
+
+static int aio_cmd_read(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ AioFile *af = Jim_CmdPrivData(interp);
+ char buf[AIO_BUF_LEN];
+ Jim_Obj *objPtr;
+ int nonewline = 0;
+ jim_wide neededLen = -1;
+
+ if (argc && Jim_CompareStringImmediate(interp, argv[0], "-nonewline")) {
+ nonewline = 1;
+ argv++;
+ argc--;
+ }
+ if (argc == 1) {
+ if (Jim_GetWide(interp, argv[0], &neededLen) != JIM_OK)
+ return JIM_ERR;
+ if (neededLen < 0) {
+ Jim_SetResultString(interp, "invalid parameter: negative len", -1);
+ return JIM_ERR;
+ }
+ }
+ else if (argc) {
+ return -1;
+ }
+ objPtr = Jim_NewStringObj(interp, NULL, 0);
+ while (neededLen != 0) {
+ int retval;
+ int readlen;
+
+ if (neededLen == -1) {
+ readlen = AIO_BUF_LEN;
+ }
+ else {
+ readlen = (neededLen > AIO_BUF_LEN ? AIO_BUF_LEN : neededLen);
+ }
+ retval = fread(buf, 1, readlen, af->fp);
+ if (retval > 0) {
+ Jim_AppendString(interp, objPtr, buf, retval);
+ if (neededLen != -1) {
+ neededLen -= retval;
+ }
+ }
+ if (retval != readlen)
+ break;
+ }
+
+ if (JimCheckStreamError(interp, af)) {
+ Jim_FreeNewObj(interp, objPtr);
+ return JIM_ERR;
+ }
+ if (nonewline) {
+ int len;
+ const char *s = Jim_GetString(objPtr, &len);
+
+ if (len > 0 && s[len - 1] == '\n') {
+ objPtr->length--;
+ objPtr->bytes[objPtr->length] = '\0';
+ }
+ }
+ Jim_SetResult(interp, objPtr);
+ return JIM_OK;
+}
+
+static int aio_cmd_copy(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ AioFile *af = Jim_CmdPrivData(interp);
+ jim_wide count = 0;
+ jim_wide maxlen = JIM_WIDE_MAX;
+ FILE *outfh = Jim_AioFilehandle(interp, argv[0]);
+
+ if (outfh == NULL) {
+ return JIM_ERR;
+ }
+
+ if (argc == 2) {
+ if (Jim_GetWide(interp, argv[1], &maxlen) != JIM_OK) {
+ return JIM_ERR;
+ }
+ }
+
+ while (count < maxlen) {
+ int ch = fgetc(af->fp);
+
+ if (ch == EOF || fputc(ch, outfh) == EOF) {
+ break;
+ }
+ count++;
+ }
+
+ if (ferror(af->fp)) {
+ Jim_SetResultFormatted(interp, "error while reading: %s", strerror(errno));
+ clearerr(af->fp);
+ return JIM_ERR;
+ }
+
+ if (ferror(outfh)) {
+ Jim_SetResultFormatted(interp, "error while writing: %s", strerror(errno));
+ clearerr(outfh);
+ return JIM_ERR;
+ }
+
+ Jim_SetResultInt(interp, count);
+
+ return JIM_OK;
+}
+
+static int aio_cmd_gets(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ AioFile *af = Jim_CmdPrivData(interp);
+ char buf[AIO_BUF_LEN];
+ Jim_Obj *objPtr;
+ int len;
+
+ errno = 0;
+
+ objPtr = Jim_NewStringObj(interp, NULL, 0);
+ while (1) {
+ buf[AIO_BUF_LEN - 1] = '_';
+ if (fgets(buf, AIO_BUF_LEN, af->fp) == NULL)
+ break;
+
+ if (buf[AIO_BUF_LEN - 1] == '\0' && buf[AIO_BUF_LEN - 2] != '\n') {
+ Jim_AppendString(interp, objPtr, buf, AIO_BUF_LEN - 1);
+ }
+ else {
+ len = strlen(buf);
+
+ if (len && (buf[len - 1] == '\n')) {
+
+ len--;
+ }
+
+ Jim_AppendString(interp, objPtr, buf, len);
+ break;
+ }
+ }
+ if (JimCheckStreamError(interp, af)) {
+
+ Jim_FreeNewObj(interp, objPtr);
+ return JIM_ERR;
+ }
+
+ if (argc) {
+ if (Jim_SetVariable(interp, argv[0], objPtr) != JIM_OK) {
+ Jim_FreeNewObj(interp, objPtr);
+ return JIM_ERR;
+ }
+
+ len = Jim_Length(objPtr);
+
+ if (len == 0 && feof(af->fp)) {
+
+ len = -1;
+ }
+ Jim_SetResultInt(interp, len);
+ }
+ else {
+ Jim_SetResult(interp, objPtr);
+ }
+ return JIM_OK;
+}
+
+static int aio_cmd_puts(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ AioFile *af = Jim_CmdPrivData(interp);
+ int wlen;
+ const char *wdata;
+ Jim_Obj *strObj;
+
+ if (argc == 2) {
+ if (!Jim_CompareStringImmediate(interp, argv[0], "-nonewline")) {
+ return -1;
+ }
+ strObj = argv[1];
+ }
+ else {
+ strObj = argv[0];
+ }
+
+ wdata = Jim_GetString(strObj, &wlen);
+ if (fwrite(wdata, 1, wlen, af->fp) == (unsigned)wlen) {
+ if (argc == 2 || putc('\n', af->fp) != EOF) {
+ return JIM_OK;
+ }
+ }
+ JimAioSetError(interp, af->filename);
+ return JIM_ERR;
+}
+
+static int aio_cmd_isatty(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+#ifdef HAVE_ISATTY
+ AioFile *af = Jim_CmdPrivData(interp);
+ Jim_SetResultInt(interp, isatty(fileno(af->fp)));
+#else
+ Jim_SetResultInt(interp, 0);
+#endif
+
+ return JIM_OK;
+}
+
+
+static int aio_cmd_flush(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ AioFile *af = Jim_CmdPrivData(interp);
+
+ if (fflush(af->fp) == EOF) {
+ JimAioSetError(interp, af->filename);
+ return JIM_ERR;
+ }
+ return JIM_OK;
+}
+
+static int aio_cmd_eof(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ AioFile *af = Jim_CmdPrivData(interp);
+
+ Jim_SetResultInt(interp, feof(af->fp));
+ return JIM_OK;
+}
+
+static int aio_cmd_close(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ Jim_DeleteCommand(interp, Jim_String(argv[0]));
+ return JIM_OK;
+}
+
+static int aio_cmd_seek(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ AioFile *af = Jim_CmdPrivData(interp);
+ int orig = SEEK_SET;
+ jim_wide offset;
+
+ if (argc == 2) {
+ if (Jim_CompareStringImmediate(interp, argv[1], "start"))
+ orig = SEEK_SET;
+ else if (Jim_CompareStringImmediate(interp, argv[1], "current"))
+ orig = SEEK_CUR;
+ else if (Jim_CompareStringImmediate(interp, argv[1], "end"))
+ orig = SEEK_END;
+ else {
+ return -1;
+ }
+ }
+ if (Jim_GetWide(interp, argv[0], &offset) != JIM_OK) {
+ return JIM_ERR;
+ }
+ if (fseeko(af->fp, offset, orig) == -1) {
+ JimAioSetError(interp, af->filename);
+ return JIM_ERR;
+ }
+ return JIM_OK;
+}
+
+static int aio_cmd_tell(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ AioFile *af = Jim_CmdPrivData(interp);
+
+ Jim_SetResultInt(interp, ftello(af->fp));
+ return JIM_OK;
+}
+
+static int aio_cmd_filename(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ AioFile *af = Jim_CmdPrivData(interp);
+
+ Jim_SetResult(interp, af->filename);
+ return JIM_OK;
+}
+
+#ifdef O_NDELAY
+static int aio_cmd_ndelay(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ AioFile *af = Jim_CmdPrivData(interp);
+
+ int fmode = af->flags;
+
+ if (argc) {
+ long nb;
+
+ if (Jim_GetLong(interp, argv[0], &nb) != JIM_OK) {
+ return JIM_ERR;
+ }
+ if (nb) {
+ fmode |= O_NDELAY;
+ }
+ else {
+ fmode &= ~O_NDELAY;
+ }
+ fcntl(af->fd, F_SETFL, fmode);
+ af->flags = fmode;
+ }
+ Jim_SetResultInt(interp, (fmode & O_NONBLOCK) ? 1 : 0);
+ return JIM_OK;
+}
+#endif
+
+static int aio_cmd_buffering(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ AioFile *af = Jim_CmdPrivData(interp);
+
+ static const char * const options[] = {
+ "none",
+ "line",
+ "full",
+ NULL
+ };
+ enum
+ {
+ OPT_NONE,
+ OPT_LINE,
+ OPT_FULL,
+ };
+ int option;
+
+ if (Jim_GetEnum(interp, argv[0], options, &option, NULL, JIM_ERRMSG) != JIM_OK) {
+ return JIM_ERR;
+ }
+ switch (option) {
+ case OPT_NONE:
+ setvbuf(af->fp, NULL, _IONBF, 0);
+ break;
+ case OPT_LINE:
+ setvbuf(af->fp, NULL, _IOLBF, BUFSIZ);
+ break;
+ case OPT_FULL:
+ setvbuf(af->fp, NULL, _IOFBF, BUFSIZ);
+ break;
+ }
+ return JIM_OK;
+}
+
+#ifdef jim_ext_eventloop
+static void JimAioFileEventFinalizer(Jim_Interp *interp, void *clientData)
+{
+ Jim_Obj *objPtr = clientData;
+
+ Jim_DecrRefCount(interp, objPtr);
+}
+
+static int JimAioFileEventHandler(Jim_Interp *interp, void *clientData, int mask)
+{
+ Jim_Obj *objPtr = clientData;
+
+ return Jim_EvalObjBackground(interp, objPtr);
+}
+
+static int aio_eventinfo(Jim_Interp *interp, AioFile * af, unsigned mask, Jim_Obj **scriptHandlerObj,
+ int argc, Jim_Obj * const *argv)
+{
+ int scriptlen = 0;
+
+ if (argc == 0) {
+
+ if (*scriptHandlerObj) {
+ Jim_SetResult(interp, *scriptHandlerObj);
+ }
+ return JIM_OK;
+ }
+
+ if (*scriptHandlerObj) {
+
+ Jim_DeleteFileHandler(interp, af->fp);
+ *scriptHandlerObj = NULL;
+ }
+
+
+ Jim_GetString(argv[0], &scriptlen);
+ if (scriptlen == 0) {
+
+ return JIM_OK;
+ }
+
+
+ Jim_IncrRefCount(argv[0]);
+ *scriptHandlerObj = argv[0];
+
+ Jim_CreateFileHandler(interp, af->fp, mask,
+ JimAioFileEventHandler, *scriptHandlerObj, JimAioFileEventFinalizer);
+
+ return JIM_OK;
+}
+
+static int aio_cmd_readable(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ AioFile *af = Jim_CmdPrivData(interp);
+
+ return aio_eventinfo(interp, af, JIM_EVENT_READABLE, &af->rEvent, argc, argv);
+}
+
+static int aio_cmd_writable(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ AioFile *af = Jim_CmdPrivData(interp);
+
+ return aio_eventinfo(interp, af, JIM_EVENT_WRITABLE, &af->wEvent, argc, argv);
+}
+
+static int aio_cmd_onexception(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ AioFile *af = Jim_CmdPrivData(interp);
+
+ return aio_eventinfo(interp, af, JIM_EVENT_EXCEPTION, &af->wEvent, argc, argv);
+}
+#endif
+
+static const jim_subcmd_type aio_command_table[] = {
+ { "read",
+ "?-nonewline? ?len?",
+ aio_cmd_read,
+ 0,
+ 2,
+
+ },
+ { "copyto",
+ "handle ?size?",
+ aio_cmd_copy,
+ 1,
+ 2,
+
+ },
+ { "gets",
+ "?var?",
+ aio_cmd_gets,
+ 0,
+ 1,
+
+ },
+ { "puts",
+ "?-nonewline? str",
+ aio_cmd_puts,
+ 1,
+ 2,
+
+ },
+ { "isatty",
+ NULL,
+ aio_cmd_isatty,
+ 0,
+ 0,
+
+ },
+ { "flush",
+ NULL,
+ aio_cmd_flush,
+ 0,
+ 0,
+
+ },
+ { "eof",
+ NULL,
+ aio_cmd_eof,
+ 0,
+ 0,
+
+ },
+ { "close",
+ NULL,
+ aio_cmd_close,
+ 0,
+ 0,
+ JIM_MODFLAG_FULLARGV,
+
+ },
+ { "seek",
+ "offset ?start|current|end",
+ aio_cmd_seek,
+ 1,
+ 2,
+
+ },
+ { "tell",
+ NULL,
+ aio_cmd_tell,
+ 0,
+ 0,
+
+ },
+ { "filename",
+ NULL,
+ aio_cmd_filename,
+ 0,
+ 0,
+
+ },
+#ifdef O_NDELAY
+ { "ndelay",
+ "?0|1?",
+ aio_cmd_ndelay,
+ 0,
+ 1,
+
+ },
+#endif
+ { "buffering",
+ "none|line|full",
+ aio_cmd_buffering,
+ 1,
+ 1,
+
+ },
+#ifdef jim_ext_eventloop
+ { "readable",
+ "?readable-script?",
+ aio_cmd_readable,
+ 0,
+ 1,
+
+ },
+ { "writable",
+ "?writable-script?",
+ aio_cmd_writable,
+ 0,
+ 1,
+
+ },
+ { "onexception",
+ "?exception-script?",
+ aio_cmd_onexception,
+ 0,
+ 1,
+
+ },
+#endif
+ { NULL }
+};
+
+static int JimAioSubCmdProc(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ return Jim_CallSubCmd(interp, Jim_ParseSubCmd(interp, aio_command_table, argc, argv), argc, argv);
+}
+
+static int JimAioOpenCommand(Jim_Interp *interp, int argc,
+ Jim_Obj *const *argv)
+{
+ const char *mode;
+ const char *filename;
+
+ if (argc != 2 && argc != 3) {
+ Jim_WrongNumArgs(interp, 1, argv, "filename ?mode?");
+ return JIM_ERR;
+ }
+
+ mode = (argc == 3) ? Jim_String(argv[2]) : "r";
+ filename = Jim_String(argv[1]);
+
+#ifdef jim_ext_tclcompat
+
+ if (*filename == '|') {
+ Jim_Obj *evalObj[3];
+
+ evalObj[0] = Jim_NewStringObj(interp, "popen", -1);
+ evalObj[1] = Jim_NewStringObj(interp, filename + 1, -1);
+ evalObj[2] = Jim_NewStringObj(interp, mode, -1);
+
+ return Jim_EvalObjVector(interp, 3, evalObj);
+ }
+#endif
+ return JimMakeChannel(interp, NULL, -1, argv[1], "aio.handle%ld", 0, mode);
+}
+
+static int JimMakeChannel(Jim_Interp *interp, FILE *fh, int fd, Jim_Obj *filename,
+ const char *hdlfmt, int family, const char *mode)
+{
+ AioFile *af;
+ char buf[AIO_CMD_LEN];
+ int OpenFlags = 0;
+
+ if (filename == NULL) {
+ filename = Jim_NewStringObj(interp, hdlfmt, -1);
+ }
+
+ Jim_IncrRefCount(filename);
+
+ if (fh == NULL) {
+ if (fd < 0) {
+ fh = fopen(Jim_String(filename), mode);
+ }
+ else {
+ fh = fdopen(fd, mode);
+ }
+ }
+ else {
+ OpenFlags = AIO_KEEPOPEN;
+ }
+
+ if (fh == NULL) {
+ JimAioSetError(interp, filename);
+#if !defined(JIM_ANSIC)
+ if (fd >= 0) {
+ close(fd);
+ }
+#endif
+ Jim_DecrRefCount(interp, filename);
+ return JIM_ERR;
+ }
+
+
+ af = Jim_Alloc(sizeof(*af));
+ memset(af, 0, sizeof(*af));
+ af->fp = fh;
+ af->fd = fileno(fh);
+ af->filename = filename;
+#ifdef FD_CLOEXEC
+ if ((OpenFlags & AIO_KEEPOPEN) == 0) {
+ fcntl(af->fd, F_SETFD, FD_CLOEXEC);
+ }
+#endif
+ af->OpenFlags = OpenFlags;
+#ifdef O_NDELAY
+ af->flags = fcntl(af->fd, F_GETFL);
+#endif
+ af->addr_family = family;
+ snprintf(buf, sizeof(buf), hdlfmt, Jim_GetId(interp));
+ Jim_CreateCommand(interp, buf, JimAioSubCmdProc, af, JimAioDelProc);
+
+ Jim_SetResultString(interp, buf, -1);
+
+ return JIM_OK;
+}
+
+
+FILE *Jim_AioFilehandle(Jim_Interp *interp, Jim_Obj *command)
+{
+ Jim_Cmd *cmdPtr = Jim_GetCommand(interp, command, JIM_ERRMSG);
+
+ if (cmdPtr && !cmdPtr->isproc && cmdPtr->u.native.cmdProc == JimAioSubCmdProc) {
+ return ((AioFile *) cmdPtr->u.native.privData)->fp;
+ }
+ Jim_SetResultFormatted(interp, "Not a filehandle: \"%#s\"", command);
+ return NULL;
+}
+
+int Jim_aioInit(Jim_Interp *interp)
+{
+ if (Jim_PackageProvide(interp, "aio", "1.0", JIM_ERRMSG))
+ return JIM_ERR;
+
+ Jim_CreateCommand(interp, "open", JimAioOpenCommand, NULL, NULL);
+#ifndef JIM_ANSIC
+ Jim_CreateCommand(interp, "socket", JimAioSockCommand, NULL, NULL);
+#endif
+
+
+ JimMakeChannel(interp, stdin, -1, NULL, "stdin", 0, "r");
+ JimMakeChannel(interp, stdout, -1, NULL, "stdout", 0, "w");
+ JimMakeChannel(interp, stderr, -1, NULL, "stderr", 0, "w");
+
+ return JIM_OK;
+}
+
+
+#include
+#include
+#include
+
+
+#ifdef HAVE_DIRENT_H
+#include
+#endif
+
+int Jim_ReaddirCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ const char *dirPath;
+ DIR *dirPtr;
+ struct dirent *entryPtr;
+ int nocomplain = 0;
+
+ if (argc == 3 && Jim_CompareStringImmediate(interp, argv[1], "-nocomplain")) {
+ nocomplain = 1;
+ }
+ if (argc != 2 && !nocomplain) {
+ Jim_WrongNumArgs(interp, 1, argv, "?-nocomplain? dirPath");
+ return JIM_ERR;
+ }
+
+ dirPath = Jim_String(argv[1 + nocomplain]);
+
+ dirPtr = opendir(dirPath);
+ if (dirPtr == NULL) {
+ if (nocomplain) {
+ return JIM_OK;
+ }
+ Jim_SetResultString(interp, strerror(errno), -1);
+ return JIM_ERR;
+ }
+ Jim_SetResultString(interp, strerror(errno), -1);
+
+ Jim_SetResult(interp, Jim_NewListObj(interp, NULL, 0));
+
+ while ((entryPtr = readdir(dirPtr)) != NULL) {
+ if (entryPtr->d_name[0] == '.') {
+ if (entryPtr->d_name[1] == '\0') {
+ continue;
+ }
+ if ((entryPtr->d_name[1] == '.') && (entryPtr->d_name[2] == '\0'))
+ continue;
+ }
+ Jim_ListAppendElement(interp, Jim_GetResult(interp), Jim_NewStringObj(interp,
+ entryPtr->d_name, -1));
+ }
+ closedir(dirPtr);
+
+ return JIM_OK;
+}
+
+int Jim_readdirInit(Jim_Interp *interp)
+{
+ if (Jim_PackageProvide(interp, "readdir", "1.0", JIM_ERRMSG))
+ return JIM_ERR;
+
+ Jim_CreateCommand(interp, "readdir", Jim_ReaddirCmd, NULL, NULL);
+ return JIM_OK;
+}
+
+#include
+#include
+
+
+static void FreeRegexpInternalRep(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+ regfree(objPtr->internalRep.regexpValue.compre);
+ Jim_Free(objPtr->internalRep.regexpValue.compre);
+}
+
+static const Jim_ObjType regexpObjType = {
+ "regexp",
+ FreeRegexpInternalRep,
+ NULL,
+ NULL,
+ JIM_TYPE_NONE
+};
+
+static regex_t *SetRegexpFromAny(Jim_Interp *interp, Jim_Obj *objPtr, unsigned flags)
+{
+ regex_t *compre;
+ const char *pattern;
+ int ret;
+
+
+ if (objPtr->typePtr == ®expObjType &&
+ objPtr->internalRep.regexpValue.compre && objPtr->internalRep.regexpValue.flags == flags) {
+
+ return objPtr->internalRep.regexpValue.compre;
+ }
+
+
+
+
+ pattern = Jim_String(objPtr);
+ compre = Jim_Alloc(sizeof(regex_t));
+
+ if ((ret = regcomp(compre, pattern, REG_EXTENDED | flags)) != 0) {
+ char buf[100];
+
+ regerror(ret, compre, buf, sizeof(buf));
+ Jim_SetResultFormatted(interp, "couldn't compile regular expression pattern: %s", buf);
+ regfree(compre);
+ Jim_Free(compre);
+ return NULL;
+ }
+
+ Jim_FreeIntRep(interp, objPtr);
+
+ objPtr->typePtr = ®expObjType;
+ objPtr->internalRep.regexpValue.flags = flags;
+ objPtr->internalRep.regexpValue.compre = compre;
+
+ return compre;
+}
+
+int Jim_RegexpCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ int opt_indices = 0;
+ int opt_all = 0;
+ int opt_inline = 0;
+ regex_t *regex;
+ int match, i, j;
+ int offset = 0;
+ regmatch_t *pmatch = NULL;
+ int source_len;
+ int result = JIM_OK;
+ const char *pattern;
+ const char *source_str;
+ int num_matches = 0;
+ int num_vars;
+ Jim_Obj *resultListObj = NULL;
+ int regcomp_flags = 0;
+ int eflags = 0;
+ int option;
+ enum {
+ OPT_INDICES, OPT_NOCASE, OPT_LINE, OPT_ALL, OPT_INLINE, OPT_START, OPT_END
+ };
+ static const char * const options[] = {
+ "-indices", "-nocase", "-line", "-all", "-inline", "-start", "--", NULL
+ };
+
+ if (argc < 3) {
+ wrongNumArgs:
+ Jim_WrongNumArgs(interp, 1, argv,
+ "?switches? exp string ?matchVar? ?subMatchVar subMatchVar ...?");
+ return JIM_ERR;
+ }
+
+ for (i = 1; i < argc; i++) {
+ const char *opt = Jim_String(argv[i]);
+
+ if (*opt != '-') {
+ break;
+ }
+ if (Jim_GetEnum(interp, argv[i], options, &option, "switch", JIM_ERRMSG | JIM_ENUM_ABBREV) != JIM_OK) {
+ return JIM_ERR;
+ }
+ if (option == OPT_END) {
+ i++;
+ break;
+ }
+ switch (option) {
+ case OPT_INDICES:
+ opt_indices = 1;
+ break;
+
+ case OPT_NOCASE:
+ regcomp_flags |= REG_ICASE;
+ break;
+
+ case OPT_LINE:
+ regcomp_flags |= REG_NEWLINE;
+ break;
+
+ case OPT_ALL:
+ opt_all = 1;
+ break;
+
+ case OPT_INLINE:
+ opt_inline = 1;
+ break;
+
+ case OPT_START:
+ if (++i == argc) {
+ goto wrongNumArgs;
+ }
+ if (Jim_GetIndex(interp, argv[i], &offset) != JIM_OK) {
+ return JIM_ERR;
+ }
+ break;
+ }
+ }
+ if (argc - i < 2) {
+ goto wrongNumArgs;
+ }
+
+ regex = SetRegexpFromAny(interp, argv[i], regcomp_flags);
+ if (!regex) {
+ return JIM_ERR;
+ }
+
+ pattern = Jim_String(argv[i]);
+ source_str = Jim_GetString(argv[i + 1], &source_len);
+
+ num_vars = argc - i - 2;
+
+ if (opt_inline) {
+ if (num_vars) {
+ Jim_SetResultString(interp, "regexp match variables not allowed when using -inline",
+ -1);
+ result = JIM_ERR;
+ goto done;
+ }
+ num_vars = regex->re_nsub + 1;
+ }
+
+ pmatch = Jim_Alloc((num_vars + 1) * sizeof(*pmatch));
+
+ if (offset) {
+ if (offset < 0) {
+ offset += source_len + 1;
+ }
+ if (offset > source_len) {
+ source_str += source_len;
+ }
+ else if (offset > 0) {
+ source_str += offset;
+ }
+ eflags |= REG_NOTBOL;
+ }
+
+ if (opt_inline) {
+ resultListObj = Jim_NewListObj(interp, NULL, 0);
+ }
+
+ next_match:
+ match = regexec(regex, source_str, num_vars + 1, pmatch, eflags);
+ if (match >= REG_BADPAT) {
+ char buf[100];
+
+ regerror(match, regex, buf, sizeof(buf));
+ Jim_SetResultFormatted(interp, "error while matching pattern: %s", buf);
+ result = JIM_ERR;
+ goto done;
+ }
+
+ if (match == REG_NOMATCH) {
+ goto done;
+ }
+
+ num_matches++;
+
+ if (opt_all && !opt_inline) {
+
+ goto try_next_match;
+ }
+
+
+ j = 0;
+ for (i += 2; opt_inline ? j < num_vars : i < argc; i++, j++) {
+ Jim_Obj *resultObj;
+
+ if (opt_indices) {
+ resultObj = Jim_NewListObj(interp, NULL, 0);
+ }
+ else {
+ resultObj = Jim_NewStringObj(interp, "", 0);
+ }
+
+ if (pmatch[j].rm_so == -1) {
+ if (opt_indices) {
+ Jim_ListAppendElement(interp, resultObj, Jim_NewIntObj(interp, -1));
+ Jim_ListAppendElement(interp, resultObj, Jim_NewIntObj(interp, -1));
+ }
+ }
+ else {
+ int len = pmatch[j].rm_eo - pmatch[j].rm_so;
+
+ if (opt_indices) {
+ Jim_ListAppendElement(interp, resultObj, Jim_NewIntObj(interp,
+ offset + pmatch[j].rm_so));
+ Jim_ListAppendElement(interp, resultObj, Jim_NewIntObj(interp,
+ offset + pmatch[j].rm_so + len - 1));
+ }
+ else {
+ Jim_AppendString(interp, resultObj, source_str + pmatch[j].rm_so, len);
+ }
+ }
+
+ if (opt_inline) {
+ Jim_ListAppendElement(interp, resultListObj, resultObj);
+ }
+ else {
+
+ result = Jim_SetVariable(interp, argv[i], resultObj);
+
+ if (result != JIM_OK) {
+ Jim_FreeObj(interp, resultObj);
+ break;
+ }
+ }
+ }
+
+ try_next_match:
+ if (opt_all && (pattern[0] != '^' || (regcomp_flags & REG_NEWLINE)) && *source_str) {
+ if (pmatch[0].rm_eo) {
+ offset += pmatch[0].rm_eo;
+ source_str += pmatch[0].rm_eo;
+ }
+ else {
+ source_str++;
+ offset++;
+ }
+ if (*source_str) {
+ eflags = REG_NOTBOL;
+ goto next_match;
+ }
+ }
+
+ done:
+ if (result == JIM_OK) {
+ if (opt_inline) {
+ Jim_SetResult(interp, resultListObj);
+ }
+ else {
+ Jim_SetResultInt(interp, num_matches);
+ }
+ }
+
+ Jim_Free(pmatch);
+ return result;
+}
+
+#define MAX_SUB_MATCHES 50
+
+int Jim_RegsubCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ int regcomp_flags = 0;
+ int regexec_flags = 0;
+ int opt_all = 0;
+ int offset = 0;
+ regex_t *regex;
+ const char *p;
+ int result;
+ regmatch_t pmatch[MAX_SUB_MATCHES + 1];
+ int num_matches = 0;
+
+ int i, j, n;
+ Jim_Obj *varname;
+ Jim_Obj *resultObj;
+ const char *source_str;
+ int source_len;
+ const char *replace_str;
+ int replace_len;
+ const char *pattern;
+ int option;
+ enum {
+ OPT_NOCASE, OPT_LINE, OPT_ALL, OPT_START, OPT_END
+ };
+ static const char * const options[] = {
+ "-nocase", "-line", "-all", "-start", "--", NULL
+ };
+
+ if (argc < 4) {
+ wrongNumArgs:
+ Jim_WrongNumArgs(interp, 1, argv,
+ "?switches? exp string subSpec ?varName?");
+ return JIM_ERR;
+ }
+
+ for (i = 1; i < argc; i++) {
+ const char *opt = Jim_String(argv[i]);
+
+ if (*opt != '-') {
+ break;
+ }
+ if (Jim_GetEnum(interp, argv[i], options, &option, "switch", JIM_ERRMSG | JIM_ENUM_ABBREV) != JIM_OK) {
+ return JIM_ERR;
+ }
+ if (option == OPT_END) {
+ i++;
+ break;
+ }
+ switch (option) {
+ case OPT_NOCASE:
+ regcomp_flags |= REG_ICASE;
+ break;
+
+ case OPT_LINE:
+ regcomp_flags |= REG_NEWLINE;
+ break;
+
+ case OPT_ALL:
+ opt_all = 1;
+ break;
+
+ case OPT_START:
+ if (++i == argc) {
+ goto wrongNumArgs;
+ }
+ if (Jim_GetIndex(interp, argv[i], &offset) != JIM_OK) {
+ return JIM_ERR;
+ }
+ break;
+ }
+ }
+ if (argc - i != 3 && argc - i != 4) {
+ goto wrongNumArgs;
+ }
+
+ regex = SetRegexpFromAny(interp, argv[i], regcomp_flags);
+ if (!regex) {
+ return JIM_ERR;
+ }
+ pattern = Jim_String(argv[i]);
+
+ source_str = Jim_GetString(argv[i + 1], &source_len);
+ replace_str = Jim_GetString(argv[i + 2], &replace_len);
+ varname = argv[i + 3];
+
+
+ resultObj = Jim_NewStringObj(interp, "", 0);
+
+ if (offset) {
+ if (offset < 0) {
+ offset += source_len + 1;
+ }
+ if (offset > source_len) {
+ offset = source_len;
+ }
+ else if (offset < 0) {
+ offset = 0;
+ }
+ }
+
+
+ Jim_AppendString(interp, resultObj, source_str, offset);
+
+
+ n = source_len - offset;
+ p = source_str + offset;
+ do {
+ int match = regexec(regex, p, MAX_SUB_MATCHES, pmatch, regexec_flags);
+
+ if (match >= REG_BADPAT) {
+ char buf[100];
+
+ regerror(match, regex, buf, sizeof(buf));
+ Jim_SetResultFormatted(interp, "error while matching pattern: %s", buf);
+ return JIM_ERR;
+ }
+ if (match == REG_NOMATCH) {
+ break;
+ }
+
+ num_matches++;
+
+ Jim_AppendString(interp, resultObj, p, pmatch[0].rm_so);
+
+
+ for (j = 0; j < replace_len; j++) {
+ int idx;
+ int c = replace_str[j];
+
+ if (c == '&') {
+ idx = 0;
+ }
+ else if (c == '\\' && j < replace_len) {
+ c = replace_str[++j];
+ if ((c >= '0') && (c <= '9')) {
+ idx = c - '0';
+ }
+ else if ((c == '\\') || (c == '&')) {
+ Jim_AppendString(interp, resultObj, replace_str + j, 1);
+ continue;
+ }
+ else {
+ Jim_AppendString(interp, resultObj, replace_str + j - 1, 2);
+ continue;
+ }
+ }
+ else {
+ Jim_AppendString(interp, resultObj, replace_str + j, 1);
+ continue;
+ }
+ if ((idx < MAX_SUB_MATCHES) && pmatch[idx].rm_so != -1 && pmatch[idx].rm_eo != -1) {
+ Jim_AppendString(interp, resultObj, p + pmatch[idx].rm_so,
+ pmatch[idx].rm_eo - pmatch[idx].rm_so);
+ }
+ }
+
+ p += pmatch[0].rm_eo;
+ n -= pmatch[0].rm_eo;
+
+
+ if (!opt_all || n == 0) {
+ break;
+ }
+
+
+ if ((regcomp_flags & REG_NEWLINE) == 0 && pattern[0] == '^') {
+ break;
+ }
+
+
+ if (pattern[0] == '\0' && n) {
+
+ Jim_AppendString(interp, resultObj, p, 1);
+ p++;
+ n--;
+ }
+
+ regexec_flags |= REG_NOTBOL;
+ } while (n);
+
+ Jim_AppendString(interp, resultObj, p, -1);
+
+
+ if (argc - i == 4) {
+ result = Jim_SetVariable(interp, varname, resultObj);
+
+ if (result == JIM_OK) {
+ Jim_SetResultInt(interp, num_matches);
+ }
+ else {
+ Jim_FreeObj(interp, resultObj);
+ }
+ }
+ else {
+ Jim_SetResult(interp, resultObj);
+ result = JIM_OK;
+ }
+
+ return result;
+}
+
+int Jim_regexpInit(Jim_Interp *interp)
+{
+ if (Jim_PackageProvide(interp, "regexp", "1.0", JIM_ERRMSG))
+ return JIM_ERR;
+
+ Jim_CreateCommand(interp, "regexp", Jim_RegexpCmd, NULL, NULL);
+ Jim_CreateCommand(interp, "regsub", Jim_RegsubCmd, NULL, NULL);
+ return JIM_OK;
+}
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+
+#ifdef HAVE_UTIMES
+#include
+#endif
+#ifdef HAVE_UNISTD_H
+#include
+#elif defined(_MSC_VER)
+#include
+#define F_OK 0
+#define W_OK 2
+#define R_OK 4
+#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
+#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
+#endif
+
+# ifndef MAXPATHLEN
+# define MAXPATHLEN JIM_PATH_LEN
+# endif
+
+
+static const char *JimGetFileType(int mode)
+{
+ if (S_ISREG(mode)) {
+ return "file";
+ }
+ else if (S_ISDIR(mode)) {
+ return "directory";
+ }
+#ifdef S_ISCHR
+ else if (S_ISCHR(mode)) {
+ return "characterSpecial";
+ }
+#endif
+#ifdef S_ISBLK
+ else if (S_ISBLK(mode)) {
+ return "blockSpecial";
+ }
+#endif
+#ifdef S_ISFIFO
+ else if (S_ISFIFO(mode)) {
+ return "fifo";
+ }
+#endif
+#ifdef S_ISLNK
+ else if (S_ISLNK(mode)) {
+ return "link";
+ }
+#endif
+#ifdef S_ISSOCK
+ else if (S_ISSOCK(mode)) {
+ return "socket";
+ }
+#endif
+ return "unknown";
+}
+
+
+static int set_array_int_value(Jim_Interp *interp, Jim_Obj *container, const char *key,
+ jim_wide value)
+{
+ Jim_Obj *nameobj = Jim_NewStringObj(interp, key, -1);
+ Jim_Obj *valobj = Jim_NewWideObj(interp, value);
+
+ if (Jim_SetDictKeysVector(interp, container, &nameobj, 1, valobj, JIM_ERRMSG) != JIM_OK) {
+ Jim_FreeObj(interp, nameobj);
+ Jim_FreeObj(interp, valobj);
+ return JIM_ERR;
+ }
+ return JIM_OK;
+}
+
+static int set_array_string_value(Jim_Interp *interp, Jim_Obj *container, const char *key,
+ const char *value)
+{
+ Jim_Obj *nameobj = Jim_NewStringObj(interp, key, -1);
+ Jim_Obj *valobj = Jim_NewStringObj(interp, value, -1);
+
+ if (Jim_SetDictKeysVector(interp, container, &nameobj, 1, valobj, JIM_ERRMSG) != JIM_OK) {
+ Jim_FreeObj(interp, nameobj);
+ Jim_FreeObj(interp, valobj);
+ return JIM_ERR;
+ }
+ return JIM_OK;
+}
+
+static int StoreStatData(Jim_Interp *interp, Jim_Obj *varName, const struct stat *sb)
+{
+ if (set_array_int_value(interp, varName, "dev", sb->st_dev) != JIM_OK) {
+ Jim_SetResultFormatted(interp, "can't set \"%#s(dev)\": variable isn't array", varName);
+ return JIM_ERR;
+ }
+ set_array_int_value(interp, varName, "ino", sb->st_ino);
+ set_array_int_value(interp, varName, "mode", sb->st_mode);
+ set_array_int_value(interp, varName, "nlink", sb->st_nlink);
+ set_array_int_value(interp, varName, "uid", sb->st_uid);
+ set_array_int_value(interp, varName, "gid", sb->st_gid);
+ set_array_int_value(interp, varName, "size", sb->st_size);
+ set_array_int_value(interp, varName, "atime", sb->st_atime);
+ set_array_int_value(interp, varName, "mtime", sb->st_mtime);
+ set_array_int_value(interp, varName, "ctime", sb->st_ctime);
+ set_array_string_value(interp, varName, "type", JimGetFileType((int)sb->st_mode));
+
+
+ Jim_SetResult(interp, Jim_GetVariable(interp, varName, 0));
+
+ return JIM_OK;
+}
+
+static int file_cmd_dirname(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ const char *path = Jim_String(argv[0]);
+ const char *p = strrchr(path, '/');
+
+ if (!p && path[0] == '.' && path[1] == '.' && path[2] == '\0') {
+ Jim_SetResultString(interp, "..", -1);
+ } else if (!p) {
+ Jim_SetResultString(interp, ".", -1);
+ }
+ else if (p == path) {
+ Jim_SetResultString(interp, "/", -1);
+ }
+#if defined(__MINGW32__) || defined(_MSC_VER)
+ else if (p[-1] == ':') {
+
+ Jim_SetResultString(interp, path, p - path + 1);
+ }
+#endif
+ else {
+ Jim_SetResultString(interp, path, p - path);
+ }
+ return JIM_OK;
+}
+
+static int file_cmd_rootname(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ const char *path = Jim_String(argv[0]);
+ const char *lastSlash = strrchr(path, '/');
+ const char *p = strrchr(path, '.');
+
+ if (p == NULL || (lastSlash != NULL && lastSlash > p)) {
+ Jim_SetResult(interp, argv[0]);
+ }
+ else {
+ Jim_SetResultString(interp, path, p - path);
+ }
+ return JIM_OK;
+}
+
+static int file_cmd_extension(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ const char *path = Jim_String(argv[0]);
+ const char *lastSlash = strrchr(path, '/');
+ const char *p = strrchr(path, '.');
+
+ if (p == NULL || (lastSlash != NULL && lastSlash >= p)) {
+ p = "";
+ }
+ Jim_SetResultString(interp, p, -1);
+ return JIM_OK;
+}
+
+static int file_cmd_tail(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ const char *path = Jim_String(argv[0]);
+ const char *lastSlash = strrchr(path, '/');
+
+ if (lastSlash) {
+ Jim_SetResultString(interp, lastSlash + 1, -1);
+ }
+ else {
+ Jim_SetResult(interp, argv[0]);
+ }
+ return JIM_OK;
+}
+
+static int file_cmd_normalize(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+#ifdef HAVE_REALPATH
+ const char *path = Jim_String(argv[0]);
+ char *newname = Jim_Alloc(MAXPATHLEN + 1);
+
+ if (realpath(path, newname)) {
+ Jim_SetResult(interp, Jim_NewStringObjNoAlloc(interp, newname, -1));
+ return JIM_OK;
+ }
+ else {
+ Jim_Free(newname);
+ Jim_SetResultFormatted(interp, "can't normalize \"%#s\": %s", argv[0], strerror(errno));
+ return JIM_ERR;
+ }
+#else
+ Jim_SetResultString(interp, "Not implemented", -1);
+ return JIM_ERR;
+#endif
+}
+
+static int file_cmd_join(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ int i;
+ char *newname = Jim_Alloc(MAXPATHLEN + 1);
+ char *last = newname;
+
+ *newname = 0;
+
+
+ for (i = 0; i < argc; i++) {
+ int len;
+ const char *part = Jim_GetString(argv[i], &len);
+
+ if (*part == '/') {
+
+ last = newname;
+ }
+#if defined(__MINGW32__) || defined(_MSC_VER)
+ else if (strchr(part, ':')) {
+
+ last = newname;
+ }
+#endif
+ else if (part[0] == '.') {
+ if (part[1] == '/') {
+ part += 2;
+ len -= 2;
+ }
+ else if (part[1] == 0 && last != newname) {
+
+ continue;
+ }
+ }
+
+
+ if (last != newname && last[-1] != '/') {
+ *last++ = '/';
+ }
+
+ if (len) {
+ if (last + len - newname >= MAXPATHLEN) {
+ Jim_Free(newname);
+ Jim_SetResultString(interp, "Path too long", -1);
+ return JIM_ERR;
+ }
+ memcpy(last, part, len);
+ last += len;
+ }
+
+
+ if (last > newname + 1 && last[-1] == '/') {
+ *--last = 0;
+ }
+ }
+
+ *last = 0;
+
+
+
+ Jim_SetResult(interp, Jim_NewStringObjNoAlloc(interp, newname, last - newname));
+
+ return JIM_OK;
+}
+
+static int file_access(Jim_Interp *interp, Jim_Obj *filename, int mode)
+{
+ const char *path = Jim_String(filename);
+ int rc = access(path, mode);
+
+ Jim_SetResultBool(interp, rc != -1);
+
+ return JIM_OK;
+}
+
+static int file_cmd_readable(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ return file_access(interp, argv[0], R_OK);
+}
+
+static int file_cmd_writable(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ return file_access(interp, argv[0], W_OK);
+}
+
+static int file_cmd_executable(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+#ifdef X_OK
+ return file_access(interp, argv[0], X_OK);
+#else
+ Jim_SetResultBool(interp, 1);
+ return JIM_OK;
+#endif
+}
+
+static int file_cmd_exists(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ return file_access(interp, argv[0], F_OK);
+}
+
+static int file_cmd_delete(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ int force = Jim_CompareStringImmediate(interp, argv[0], "-force");
+
+ if (force || Jim_CompareStringImmediate(interp, argv[0], "--")) {
+ argc++;
+ argv--;
+ }
+
+ while (argc--) {
+ const char *path = Jim_String(argv[0]);
+
+ if (unlink(path) == -1 && errno != ENOENT) {
+ if (rmdir(path) == -1) {
+
+ if (!force || Jim_EvalPrefix(interp, "file delete force", 1, argv) != JIM_OK) {
+ Jim_SetResultFormatted(interp, "couldn't delete file \"%s\": %s", path,
+ strerror(errno));
+ return JIM_ERR;
+ }
+ }
+ }
+ argv++;
+ }
+ return JIM_OK;
+}
+
+#ifdef HAVE_MKDIR_ONE_ARG
+#define MKDIR_DEFAULT(PATHNAME) mkdir(PATHNAME)
+#else
+#define MKDIR_DEFAULT(PATHNAME) mkdir(PATHNAME, 0755)
+#endif
+
+static int mkdir_all(char *path)
+{
+ int ok = 1;
+
+
+ goto first;
+
+ while (ok--) {
+
+ {
+ char *slash = strrchr(path, '/');
+
+ if (slash && slash != path) {
+ *slash = 0;
+ if (mkdir_all(path) != 0) {
+ return -1;
+ }
+ *slash = '/';
+ }
+ }
+ first:
+ if (MKDIR_DEFAULT(path) == 0) {
+ return 0;
+ }
+ if (errno == ENOENT) {
+
+ continue;
+ }
+
+ if (errno == EEXIST) {
+ struct stat sb;
+
+ if (stat(path, &sb) == 0 && S_ISDIR(sb.st_mode)) {
+ return 0;
+ }
+
+ errno = EEXIST;
+ }
+
+ break;
+ }
+ return -1;
+}
+
+static int file_cmd_mkdir(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ while (argc--) {
+ char *path = Jim_StrDup(Jim_String(argv[0]));
+ int rc = mkdir_all(path);
+
+ Jim_Free(path);
+ if (rc != 0) {
+ Jim_SetResultFormatted(interp, "can't create directory \"%#s\": %s", argv[0],
+ strerror(errno));
+ return JIM_ERR;
+ }
+ argv++;
+ }
+ return JIM_OK;
+}
+
+#ifdef HAVE_MKSTEMP
+static int file_cmd_tempfile(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ int fd;
+ char *filename;
+ const char *template = "/tmp/tcl.tmp.XXXXXX";
+
+ if (argc >= 1) {
+ template = Jim_String(argv[0]);
+ }
+ filename = Jim_StrDup(template);
+
+ fd = mkstemp(filename);
+ if (fd < 0) {
+ Jim_SetResultString(interp, "Failed to create tempfile", -1);
+ return JIM_ERR;
+ }
+ close(fd);
+
+ Jim_SetResult(interp, Jim_NewStringObjNoAlloc(interp, filename, -1));
+ return JIM_OK;
+}
+#endif
+
+static int file_cmd_rename(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ const char *source;
+ const char *dest;
+ int force = 0;
+
+ if (argc == 3) {
+ if (!Jim_CompareStringImmediate(interp, argv[0], "-force")) {
+ return -1;
+ }
+ force++;
+ argv++;
+ argc--;
+ }
+
+ source = Jim_String(argv[0]);
+ dest = Jim_String(argv[1]);
+
+ if (!force && access(dest, F_OK) == 0) {
+ Jim_SetResultFormatted(interp, "error renaming \"%#s\" to \"%#s\": target exists", argv[0],
+ argv[1]);
+ return JIM_ERR;
+ }
+
+ if (rename(source, dest) != 0) {
+ Jim_SetResultFormatted(interp, "error renaming \"%#s\" to \"%#s\": %s", argv[0], argv[1],
+ strerror(errno));
+ return JIM_ERR;
+ }
+
+ return JIM_OK;
+}
+
+static int file_stat(Jim_Interp *interp, Jim_Obj *filename, struct stat *sb)
+{
+ const char *path = Jim_String(filename);
+
+ if (stat(path, sb) == -1) {
+ Jim_SetResultFormatted(interp, "could not read \"%#s\": %s", filename, strerror(errno));
+ return JIM_ERR;
+ }
+ return JIM_OK;
+}
+
+#ifndef HAVE_LSTAT
+#define lstat stat
+#endif
+
+static int file_lstat(Jim_Interp *interp, Jim_Obj *filename, struct stat *sb)
+{
+ const char *path = Jim_String(filename);
+
+ if (lstat(path, sb) == -1) {
+ Jim_SetResultFormatted(interp, "could not read \"%#s\": %s", filename, strerror(errno));
+ return JIM_ERR;
+ }
+ return JIM_OK;
+}
+
+static int file_cmd_atime(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ struct stat sb;
+
+ if (file_stat(interp, argv[0], &sb) != JIM_OK) {
+ return JIM_ERR;
+ }
+ Jim_SetResultInt(interp, sb.st_atime);
+ return JIM_OK;
+}
+
+static int file_cmd_mtime(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ struct stat sb;
+
+ if (argc == 2) {
+#ifdef HAVE_UTIMES
+ jim_wide newtime;
+ struct timeval times[2];
+
+ if (Jim_GetWide(interp, argv[1], &newtime) != JIM_OK) {
+ return JIM_ERR;
+ }
+
+ times[1].tv_sec = times[0].tv_sec = newtime;
+ times[1].tv_usec = times[0].tv_usec = 0;
+
+ if (utimes(Jim_String(argv[0]), times) != 0) {
+ Jim_SetResultFormatted(interp, "can't set time on \"%#s\": %s", argv[0], strerror(errno));
+ return JIM_ERR;
+ }
+#else
+ Jim_SetResultString(interp, "Not implemented", -1);
+ return JIM_ERR;
+#endif
+ }
+ if (file_stat(interp, argv[0], &sb) != JIM_OK) {
+ return JIM_ERR;
+ }
+ Jim_SetResultInt(interp, sb.st_mtime);
+ return JIM_OK;
+}
+
+static int file_cmd_copy(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ return Jim_EvalPrefix(interp, "file copy", argc, argv);
+}
+
+static int file_cmd_size(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ struct stat sb;
+
+ if (file_stat(interp, argv[0], &sb) != JIM_OK) {
+ return JIM_ERR;
+ }
+ Jim_SetResultInt(interp, sb.st_size);
+ return JIM_OK;
+}
+
+static int file_cmd_isdirectory(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ struct stat sb;
+ int ret = 0;
+
+ if (file_stat(interp, argv[0], &sb) == JIM_OK) {
+ ret = S_ISDIR(sb.st_mode);
+ }
+ Jim_SetResultInt(interp, ret);
+ return JIM_OK;
+}
+
+static int file_cmd_isfile(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ struct stat sb;
+ int ret = 0;
+
+ if (file_stat(interp, argv[0], &sb) == JIM_OK) {
+ ret = S_ISREG(sb.st_mode);
+ }
+ Jim_SetResultInt(interp, ret);
+ return JIM_OK;
+}
+
+#ifdef HAVE_GETEUID
+static int file_cmd_owned(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ struct stat sb;
+ int ret = 0;
+
+ if (file_stat(interp, argv[0], &sb) == JIM_OK) {
+ ret = (geteuid() == sb.st_uid);
+ }
+ Jim_SetResultInt(interp, ret);
+ return JIM_OK;
+}
+#endif
+
+#if defined(HAVE_READLINK)
+static int file_cmd_readlink(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ const char *path = Jim_String(argv[0]);
+ char *linkValue = Jim_Alloc(MAXPATHLEN + 1);
+
+ int linkLength = readlink(path, linkValue, MAXPATHLEN);
+
+ if (linkLength == -1) {
+ Jim_Free(linkValue);
+ Jim_SetResultFormatted(interp, "couldn't readlink \"%#s\": %s", argv[0], strerror(errno));
+ return JIM_ERR;
+ }
+ linkValue[linkLength] = 0;
+ Jim_SetResult(interp, Jim_NewStringObjNoAlloc(interp, linkValue, linkLength));
+ return JIM_OK;
+}
+#endif
+
+static int file_cmd_type(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ struct stat sb;
+
+ if (file_lstat(interp, argv[0], &sb) != JIM_OK) {
+ return JIM_ERR;
+ }
+ Jim_SetResultString(interp, JimGetFileType((int)sb.st_mode), -1);
+ return JIM_OK;
+}
+
+static int file_cmd_lstat(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ struct stat sb;
+
+ if (file_lstat(interp, argv[0], &sb) != JIM_OK) {
+ return JIM_ERR;
+ }
+ return StoreStatData(interp, argv[1], &sb);
+}
+
+static int file_cmd_stat(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ struct stat sb;
+
+ if (file_stat(interp, argv[0], &sb) != JIM_OK) {
+ return JIM_ERR;
+ }
+ return StoreStatData(interp, argv[1], &sb);
+}
+
+static const jim_subcmd_type file_command_table[] = {
+ { "atime",
+ "name",
+ file_cmd_atime,
+ 1,
+ 1,
+
+ },
+ { "mtime",
+ "name ?time?",
+ file_cmd_mtime,
+ 1,
+ 2,
+
+ },
+ { "copy",
+ "?-force? source dest",
+ file_cmd_copy,
+ 2,
+ 3,
+
+ },
+ { "dirname",
+ "name",
+ file_cmd_dirname,
+ 1,
+ 1,
+
+ },
+ { "rootname",
+ "name",
+ file_cmd_rootname,
+ 1,
+ 1,
+
+ },
+ { "extension",
+ "name",
+ file_cmd_extension,
+ 1,
+ 1,
+
+ },
+ { "tail",
+ "name",
+ file_cmd_tail,
+ 1,
+ 1,
+
+ },
+ { "normalize",
+ "name",
+ file_cmd_normalize,
+ 1,
+ 1,
+
+ },
+ { "join",
+ "name ?name ...?",
+ file_cmd_join,
+ 1,
+ -1,
+
+ },
+ { "readable",
+ "name",
+ file_cmd_readable,
+ 1,
+ 1,
+
+ },
+ { "writable",
+ "name",
+ file_cmd_writable,
+ 1,
+ 1,
+
+ },
+ { "executable",
+ "name",
+ file_cmd_executable,
+ 1,
+ 1,
+
+ },
+ { "exists",
+ "name",
+ file_cmd_exists,
+ 1,
+ 1,
+
+ },
+ { "delete",
+ "?-force|--? name ...",
+ file_cmd_delete,
+ 1,
+ -1,
+
+ },
+ { "mkdir",
+ "dir ...",
+ file_cmd_mkdir,
+ 1,
+ -1,
+
+ },
+#ifdef HAVE_MKSTEMP
+ { "tempfile",
+ "?template?",
+ file_cmd_tempfile,
+ 0,
+ 1,
+
+ },
+#endif
+ { "rename",
+ "?-force? source dest",
+ file_cmd_rename,
+ 2,
+ 3,
+
+ },
+#if defined(HAVE_READLINK)
+ { "readlink",
+ "name",
+ file_cmd_readlink,
+ 1,
+ 1,
+
+ },
+#endif
+ { "size",
+ "name",
+ file_cmd_size,
+ 1,
+ 1,
+
+ },
+ { "stat",
+ "name var",
+ file_cmd_stat,
+ 2,
+ 2,
+
+ },
+ { "lstat",
+ "name var",
+ file_cmd_lstat,
+ 2,
+ 2,
+
+ },
+ { "type",
+ "name",
+ file_cmd_type,
+ 1,
+ 1,
+
+ },
+#ifdef HAVE_GETEUID
+ { "owned",
+ "name",
+ file_cmd_owned,
+ 1,
+ 1,
+
+ },
+#endif
+ { "isdirectory",
+ "name",
+ file_cmd_isdirectory,
+ 1,
+ 1,
+
+ },
+ { "isfile",
+ "name",
+ file_cmd_isfile,
+ 1,
+ 1,
+
+ },
+ {
+ NULL
+ }
+};
+
+static int Jim_CdCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ const char *path;
+
+ if (argc != 2) {
+ Jim_WrongNumArgs(interp, 1, argv, "dirname");
+ return JIM_ERR;
+ }
+
+ path = Jim_String(argv[1]);
+
+ if (chdir(path) != 0) {
+ Jim_SetResultFormatted(interp, "couldn't change working directory to \"%s\": %s", path,
+ strerror(errno));
+ return JIM_ERR;
+ }
+ return JIM_OK;
+}
+
+static int Jim_PwdCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ const int cwd_len = 2048;
+ char *cwd = malloc(cwd_len);
+
+ if (getcwd(cwd, cwd_len) == NULL) {
+ Jim_SetResultString(interp, "Failed to get pwd", -1);
+ return JIM_ERR;
+ }
+#if defined(__MINGW32__) || defined(_MSC_VER)
+ {
+
+ char *p = cwd;
+ while ((p = strchr(p, '\\')) != NULL) {
+ *p++ = '/';
+ }
+ }
+#endif
+
+ Jim_SetResultString(interp, cwd, -1);
+
+ free(cwd);
+ return JIM_OK;
+}
+
+int Jim_fileInit(Jim_Interp *interp)
+{
+ if (Jim_PackageProvide(interp, "file", "1.0", JIM_ERRMSG))
+ return JIM_ERR;
+
+ Jim_CreateCommand(interp, "file", Jim_SubCmdProc, (void *)file_command_table, NULL);
+ Jim_CreateCommand(interp, "pwd", Jim_PwdCmd, NULL, NULL);
+ Jim_CreateCommand(interp, "cd", Jim_CdCmd, NULL, NULL);
+ return JIM_OK;
+}
+
+#include
+#include
+
+
+#if (!defined(HAVE_VFORK) || !defined(HAVE_WAITPID)) && !defined(__MINGW32__)
+static int Jim_ExecCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ Jim_Obj *cmdlineObj = Jim_NewEmptyStringObj(interp);
+ int i, j;
+ int rc;
+
+
+ for (i = 1; i < argc; i++) {
+ int len;
+ const char *arg = Jim_GetString(argv[i], &len);
+
+ if (i > 1) {
+ Jim_AppendString(interp, cmdlineObj, " ", 1);
+ }
+ if (strpbrk(arg, "\\\" ") == NULL) {
+
+ Jim_AppendString(interp, cmdlineObj, arg, len);
+ continue;
+ }
+
+ Jim_AppendString(interp, cmdlineObj, "\"", 1);
+ for (j = 0; j < len; j++) {
+ if (arg[j] == '\\' || arg[j] == '"') {
+ Jim_AppendString(interp, cmdlineObj, "\\", 1);
+ }
+ Jim_AppendString(interp, cmdlineObj, &arg[j], 1);
+ }
+ Jim_AppendString(interp, cmdlineObj, "\"", 1);
+ }
+ rc = system(Jim_String(cmdlineObj));
+
+ Jim_FreeNewObj(interp, cmdlineObj);
+
+ if (rc) {
+ Jim_Obj *errorCode = Jim_NewListObj(interp, NULL, 0);
+ Jim_ListAppendElement(interp, errorCode, Jim_NewStringObj(interp, "CHILDSTATUS", -1));
+ Jim_ListAppendElement(interp, errorCode, Jim_NewIntObj(interp, 0));
+ Jim_ListAppendElement(interp, errorCode, Jim_NewIntObj(interp, rc));
+ Jim_SetGlobalVariableStr(interp, "errorCode", errorCode);
+ return JIM_ERR;
+ }
+
+ return JIM_OK;
+}
+
+int Jim_execInit(Jim_Interp *interp)
+{
+ if (Jim_PackageProvide(interp, "exec", "1.0", JIM_ERRMSG))
+ return JIM_ERR;
+ Jim_CreateCommand(interp, "exec", Jim_ExecCmd, NULL, NULL);
+ return JIM_OK;
+}
+#else
+
+
+#include
+#include
+
+#if defined(__MINGW32__)
+
+ #ifndef STRICT
+ #define STRICT
+ #endif
+ #define WIN32_LEAN_AND_MEAN
+ #include
+ #include
+
+ typedef HANDLE fdtype;
+ typedef HANDLE pidtype;
+ #define JIM_BAD_FD INVALID_HANDLE_VALUE
+ #define JIM_BAD_PID INVALID_HANDLE_VALUE
+ #define JimCloseFd CloseHandle
+
+ #define WIFEXITED(STATUS) 1
+ #define WEXITSTATUS(STATUS) (STATUS)
+ #define WIFSIGNALED(STATUS) 0
+ #define WTERMSIG(STATUS) 0
+ #define WNOHANG 1
+
+ static fdtype JimFileno(FILE *fh);
+ static pidtype JimWaitPid(pidtype pid, int *status, int nohang);
+ static fdtype JimDupFd(fdtype infd);
+ static fdtype JimOpenForRead(const char *filename);
+ static FILE *JimFdOpenForRead(fdtype fd);
+ static int JimPipe(fdtype pipefd[2]);
+ static pidtype JimStartWinProcess(Jim_Interp *interp, char **argv, char *env,
+ fdtype inputId, fdtype outputId, fdtype errorId);
+ static int JimErrno(void);
+#else
+ #include
+ #include
+ #include
+
+ typedef int fdtype;
+ typedef int pidtype;
+ #define JimPipe pipe
+ #define JimErrno() errno
+ #define JIM_BAD_FD -1
+ #define JIM_BAD_PID -1
+ #define JimFileno fileno
+ #define JimReadFd read
+ #define JimCloseFd close
+ #define JimWaitPid waitpid
+ #define JimDupFd dup
+ #define JimFdOpenForRead(FD) fdopen((FD), "r")
+ #define JimOpenForRead(NAME) open((NAME), O_RDONLY, 0)
+
+ #ifndef HAVE_EXECVPE
+ #define execvpe(ARG0, ARGV, ENV) execvp(ARG0, ARGV)
+ #endif
+#endif
+
+static const char *JimStrError(void);
+static char **JimSaveEnv(char **env);
+static void JimRestoreEnv(char **env);
+static int JimCreatePipeline(Jim_Interp *interp, int argc, Jim_Obj *const *argv,
+ pidtype **pidArrayPtr, fdtype *inPipePtr, fdtype *outPipePtr, fdtype *errFilePtr);
+static void JimDetachPids(Jim_Interp *interp, int numPids, const pidtype *pidPtr);
+static int JimCleanupChildren(Jim_Interp *interp, int numPids, pidtype *pidPtr, fdtype errorId);
+static fdtype JimCreateTemp(Jim_Interp *interp, const char *contents);
+static fdtype JimOpenForWrite(const char *filename, int append);
+static int JimRewindFd(fdtype fd);
+
+static void Jim_SetResultErrno(Jim_Interp *interp, const char *msg)
+{
+ Jim_SetResultFormatted(interp, "%s: %s", msg, JimStrError());
+}
+
+static const char *JimStrError(void)
+{
+ return strerror(JimErrno());
+}
+
+static void Jim_RemoveTrailingNewline(Jim_Obj *objPtr)
+{
+ int len;
+ const char *s = Jim_GetString(objPtr, &len);
+
+ if (len > 0 && s[len - 1] == '\n') {
+ objPtr->length--;
+ objPtr->bytes[objPtr->length] = '\0';
+ }
+}
+
+static int JimAppendStreamToString(Jim_Interp *interp, fdtype fd, Jim_Obj *strObj)
+{
+ char buf[256];
+ FILE *fh = JimFdOpenForRead(fd);
+ if (fh == NULL) {
+ return JIM_ERR;
+ }
+
+ while (1) {
+ int retval = fread(buf, 1, sizeof(buf), fh);
+ if (retval > 0) {
+ Jim_AppendString(interp, strObj, buf, retval);
+ }
+ if (retval != sizeof(buf)) {
+ break;
+ }
+ }
+ Jim_RemoveTrailingNewline(strObj);
+ fclose(fh);
+ return JIM_OK;
+}
+
+static void JimTrimTrailingNewline(Jim_Interp *interp)
+{
+ int len;
+ const char *p = Jim_GetString(Jim_GetResult(interp), &len);
+
+ if (len > 0 && p[len - 1] == '\n') {
+ Jim_SetResultString(interp, p, len - 1);
+ }
+}
+
+static char **JimBuildEnv(Jim_Interp *interp)
+{
+#if defined(jim_ext_tclcompat)
+ int i;
+ int size;
+ int num;
+ int n;
+ char **envptr;
+ char *envdata;
+
+ Jim_Obj *objPtr = Jim_GetGlobalVariableStr(interp, "env", JIM_NONE);
+
+ if (!objPtr) {
+ return Jim_GetEnviron();
+ }
+
+
+
+ num = Jim_ListLength(interp, objPtr);
+ if (num % 2) {
+ num--;
+ }
+ size = Jim_Length(objPtr) + 2;
+
+ envptr = Jim_Alloc(sizeof(*envptr) * (num / 2 + 1) + size);
+ envdata = (char *)&envptr[num / 2 + 1];
+
+ n = 0;
+ for (i = 0; i < num; i += 2) {
+ const char *s1, *s2;
+ Jim_Obj *elemObj;
+
+ Jim_ListIndex(interp, objPtr, i, &elemObj, JIM_NONE);
+ s1 = Jim_String(elemObj);
+ Jim_ListIndex(interp, objPtr, i + 1, &elemObj, JIM_NONE);
+ s2 = Jim_String(elemObj);
+
+ envptr[n] = envdata;
+ envdata += sprintf(envdata, "%s=%s", s1, s2);
+ envdata++;
+ n++;
+ }
+ envptr[n] = NULL;
+ *envdata = 0;
+
+ return envptr;
+#else
+ return Jim_GetEnviron();
+#endif
+}
+
+static void JimFreeEnv(char **env, char **original_environ)
+{
+#ifdef jim_ext_tclcompat
+ if (env != original_environ) {
+ Jim_Free(env);
+ }
+#endif
+}
+
+static int JimCheckWaitStatus(Jim_Interp *interp, pidtype pid, int waitStatus)
+{
+ Jim_Obj *errorCode = Jim_NewListObj(interp, NULL, 0);
+ int rc = JIM_ERR;
+
+ if (WIFEXITED(waitStatus)) {
+ if (WEXITSTATUS(waitStatus) == 0) {
+ Jim_ListAppendElement(interp, errorCode, Jim_NewStringObj(interp, "NONE", -1));
+ rc = JIM_OK;
+ }
+ else {
+ Jim_ListAppendElement(interp, errorCode, Jim_NewStringObj(interp, "CHILDSTATUS", -1));
+ Jim_ListAppendElement(interp, errorCode, Jim_NewIntObj(interp, (long)pid));
+ Jim_ListAppendElement(interp, errorCode, Jim_NewIntObj(interp, WEXITSTATUS(waitStatus)));
+ }
+ }
+ else {
+ const char *type;
+ const char *action;
+
+ if (WIFSIGNALED(waitStatus)) {
+ type = "CHILDKILLED";
+ action = "killed";
+ }
+ else {
+ type = "CHILDSUSP";
+ action = "suspended";
+ }
+
+ Jim_ListAppendElement(interp, errorCode, Jim_NewStringObj(interp, type, -1));
+
+#ifdef jim_ext_signal
+ Jim_SetResultFormatted(interp, "child %s by signal %s", action, Jim_SignalId(WTERMSIG(waitStatus)));
+ Jim_ListAppendElement(interp, errorCode, Jim_NewStringObj(interp, Jim_SignalId(WTERMSIG(waitStatus)), -1));
+ Jim_ListAppendElement(interp, errorCode, Jim_NewIntObj(interp, pid));
+ Jim_ListAppendElement(interp, errorCode, Jim_NewStringObj(interp, Jim_SignalName(WTERMSIG(waitStatus)), -1));
+#else
+ Jim_SetResultFormatted(interp, "child %s by signal %d", action, WTERMSIG(waitStatus));
+ Jim_ListAppendElement(interp, errorCode, Jim_NewIntObj(interp, WTERMSIG(waitStatus)));
+ Jim_ListAppendElement(interp, errorCode, Jim_NewIntObj(interp, (long)pid));
+ Jim_ListAppendElement(interp, errorCode, Jim_NewIntObj(interp, WTERMSIG(waitStatus)));
+#endif
+ }
+ Jim_SetGlobalVariableStr(interp, "errorCode", errorCode);
+ return rc;
+}
+
+
+struct WaitInfo
+{
+ pidtype pid;
+ int status;
+ int flags;
+};
+
+struct WaitInfoTable {
+ struct WaitInfo *info;
+ int size;
+ int used;
+};
+
+
+#define WI_DETACHED 2
+
+#define WAIT_TABLE_GROW_BY 4
+
+static void JimFreeWaitInfoTable(struct Jim_Interp *interp, void *privData)
+{
+ struct WaitInfoTable *table = privData;
+
+ Jim_Free(table->info);
+ Jim_Free(table);
+}
+
+static struct WaitInfoTable *JimAllocWaitInfoTable(void)
+{
+ struct WaitInfoTable *table = Jim_Alloc(sizeof(*table));
+ table->info = NULL;
+ table->size = table->used = 0;
+
+ return table;
+}
+
+static int Jim_ExecCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ fdtype outputId; /* File id for output pipe. -1
+ * means command overrode. */
+ fdtype errorId; /* File id for temporary file
+ * containing error output. */
+ pidtype *pidPtr;
+ int numPids, result;
+
+ if (argc > 1 && Jim_CompareStringImmediate(interp, argv[argc - 1], "&")) {
+ Jim_Obj *listObj;
+ int i;
+
+ argc--;
+ numPids = JimCreatePipeline(interp, argc - 1, argv + 1, &pidPtr, NULL, NULL, NULL);
+ if (numPids < 0) {
+ return JIM_ERR;
+ }
+
+ listObj = Jim_NewListObj(interp, NULL, 0);
+ for (i = 0; i < numPids; i++) {
+ Jim_ListAppendElement(interp, listObj, Jim_NewIntObj(interp, (long)pidPtr[i]));
+ }
+ Jim_SetResult(interp, listObj);
+ JimDetachPids(interp, numPids, pidPtr);
+ Jim_Free(pidPtr);
+ return JIM_OK;
+ }
+
+ numPids =
+ JimCreatePipeline(interp, argc - 1, argv + 1, &pidPtr, NULL, &outputId, &errorId);
+
+ if (numPids < 0) {
+ return JIM_ERR;
+ }
+
+ Jim_SetResultString(interp, "", 0);
+
+ result = JIM_OK;
+ if (outputId != JIM_BAD_FD) {
+ result = JimAppendStreamToString(interp, outputId, Jim_GetResult(interp));
+ if (result < 0) {
+ Jim_SetResultErrno(interp, "error reading from output pipe");
+ }
+ }
+
+ if (JimCleanupChildren(interp, numPids, pidPtr, errorId) != JIM_OK) {
+ result = JIM_ERR;
+ }
+ return result;
+}
+
+static void JimReapDetachedPids(struct WaitInfoTable *table)
+{
+ struct WaitInfo *waitPtr;
+ int count;
+
+ if (!table) {
+ return;
+ }
+
+ for (waitPtr = table->info, count = table->used; count > 0; waitPtr++, count--) {
+ if (waitPtr->flags & WI_DETACHED) {
+ int status;
+ pidtype pid = JimWaitPid(waitPtr->pid, &status, WNOHANG);
+ if (pid != JIM_BAD_PID) {
+ if (waitPtr != &table->info[table->used - 1]) {
+ *waitPtr = table->info[table->used - 1];
+ }
+ table->used--;
+ }
+ }
+ }
+}
+
+static pidtype JimWaitForProcess(struct WaitInfoTable *table, pidtype pid, int *statusPtr)
+{
+ int i;
+
+
+ for (i = 0; i < table->used; i++) {
+ if (pid == table->info[i].pid) {
+
+ JimWaitPid(pid, statusPtr, 0);
+
+
+ if (i != table->used - 1) {
+ table->info[i] = table->info[table->used - 1];
+ }
+ table->used--;
+ return pid;
+ }
+ }
+
+
+ return JIM_BAD_PID;
+}
+
+
+static void JimDetachPids(Jim_Interp *interp, int numPids, const pidtype *pidPtr)
+{
+ int j;
+ struct WaitInfoTable *table = Jim_CmdPrivData(interp);
+
+ for (j = 0; j < numPids; j++) {
+
+ int i;
+ for (i = 0; i < table->used; i++) {
+ if (pidPtr[j] == table->info[i].pid) {
+ table->info[i].flags |= WI_DETACHED;
+ break;
+ }
+ }
+ }
+}
+
+static FILE *JimGetAioFilehandle(Jim_Interp *interp, const char *name)
+{
+ FILE *fh;
+ Jim_Obj *fhObj;
+
+ fhObj = Jim_NewStringObj(interp, name, -1);
+ Jim_IncrRefCount(fhObj);
+ fh = Jim_AioFilehandle(interp, fhObj);
+ Jim_DecrRefCount(interp, fhObj);
+
+ return fh;
+}
+
+static int
+JimCreatePipeline(Jim_Interp *interp, int argc, Jim_Obj *const *argv, pidtype **pidArrayPtr,
+ fdtype *inPipePtr, fdtype *outPipePtr, fdtype *errFilePtr)
+{
+ pidtype *pidPtr = NULL; /* Points to malloc-ed array holding all
+ * the pids of child processes. */
+ int numPids = 0; /* Actual number of processes that exist
+ * at *pidPtr right now. */
+ int cmdCount; /* Count of number of distinct commands
+ * found in argc/argv. */
+ const char *input = NULL; /* Describes input for pipeline, depending
+ * on "inputFile". NULL means take input
+ * from stdin/pipe. */
+
+#define FILE_NAME 0
+#define FILE_APPEND 1
+#define FILE_HANDLE 2
+#define FILE_TEXT 3
+
+ int inputFile = FILE_NAME; /* 1 means input is name of input file.
+ * 2 means input is filehandle name.
+ * 0 means input holds actual
+ * text to be input to command. */
+
+ int outputFile = FILE_NAME; /* 0 means output is the name of output file.
+ * 1 means output is the name of output file, and append.
+ * 2 means output is filehandle name.
+ * All this is ignored if output is NULL
+ */
+ int errorFile = FILE_NAME; /* 0 means error is the name of error file.
+ * 1 means error is the name of error file, and append.
+ * 2 means error is filehandle name.
+ * All this is ignored if error is NULL
+ */
+ const char *output = NULL; /* Holds name of output file to pipe to,
+ * or NULL if output goes to stdout/pipe. */
+ const char *error = NULL; /* Holds name of stderr file to pipe to,
+ * or NULL if stderr goes to stderr/pipe. */
+ fdtype inputId = JIM_BAD_FD;
+ fdtype outputId = JIM_BAD_FD;
+ fdtype errorId = JIM_BAD_FD;
+ fdtype lastOutputId = JIM_BAD_FD;
+ fdtype pipeIds[2];
+ int firstArg, lastArg; /* Indexes of first and last arguments in
+ * current command. */
+ int lastBar;
+ int i;
+ pidtype pid;
+ char **save_environ;
+ struct WaitInfoTable *table = Jim_CmdPrivData(interp);
+
+
+ char **arg_array = Jim_Alloc(sizeof(*arg_array) * (argc + 1));
+ int arg_count = 0;
+
+ JimReapDetachedPids(table);
+
+ if (inPipePtr != NULL) {
+ *inPipePtr = JIM_BAD_FD;
+ }
+ if (outPipePtr != NULL) {
+ *outPipePtr = JIM_BAD_FD;
+ }
+ if (errFilePtr != NULL) {
+ *errFilePtr = JIM_BAD_FD;
+ }
+ pipeIds[0] = pipeIds[1] = JIM_BAD_FD;
+
+ cmdCount = 1;
+ lastBar = -1;
+ for (i = 0; i < argc; i++) {
+ const char *arg = Jim_String(argv[i]);
+
+ if (arg[0] == '<') {
+ inputFile = FILE_NAME;
+ input = arg + 1;
+ if (*input == '<') {
+ inputFile = FILE_TEXT;
+ input++;
+ }
+ else if (*input == '@') {
+ inputFile = FILE_HANDLE;
+ input++;
+ }
+
+ if (!*input && ++i < argc) {
+ input = Jim_String(argv[i]);
+ }
+ }
+ else if (arg[0] == '>') {
+ int dup_error = 0;
+
+ outputFile = FILE_NAME;
+
+ output = arg + 1;
+ if (*output == '>') {
+ outputFile = FILE_APPEND;
+ output++;
+ }
+ if (*output == '&') {
+
+ output++;
+ dup_error = 1;
+ }
+ if (*output == '@') {
+ outputFile = FILE_HANDLE;
+ output++;
+ }
+ if (!*output && ++i < argc) {
+ output = Jim_String(argv[i]);
+ }
+ if (dup_error) {
+ errorFile = outputFile;
+ error = output;
+ }
+ }
+ else if (arg[0] == '2' && arg[1] == '>') {
+ error = arg + 2;
+ errorFile = FILE_NAME;
+
+ if (*error == '@') {
+ errorFile = FILE_HANDLE;
+ error++;
+ }
+ else if (*error == '>') {
+ errorFile = FILE_APPEND;
+ error++;
+ }
+ if (!*error && ++i < argc) {
+ error = Jim_String(argv[i]);
+ }
+ }
+ else {
+ if (strcmp(arg, "|") == 0 || strcmp(arg, "|&") == 0) {
+ if (i == lastBar + 1 || i == argc - 1) {
+ Jim_SetResultString(interp, "illegal use of | or |& in command", -1);
+ goto badargs;
+ }
+ lastBar = i;
+ cmdCount++;
+ }
+
+ arg_array[arg_count++] = (char *)arg;
+ continue;
+ }
+
+ if (i >= argc) {
+ Jim_SetResultFormatted(interp, "can't specify \"%s\" as last word in command", arg);
+ goto badargs;
+ }
+ }
+
+ if (arg_count == 0) {
+ Jim_SetResultString(interp, "didn't specify command to execute", -1);
+badargs:
+ Jim_Free(arg_array);
+ return -1;
+ }
+
+
+ save_environ = JimSaveEnv(JimBuildEnv(interp));
+
+ if (input != NULL) {
+ if (inputFile == FILE_TEXT) {
+ inputId = JimCreateTemp(interp, input);
+ if (inputId == JIM_BAD_FD) {
+ goto error;
+ }
+ }
+ else if (inputFile == FILE_HANDLE) {
+
+ FILE *fh = JimGetAioFilehandle(interp, input);
+
+ if (fh == NULL) {
+ goto error;
+ }
+ inputId = JimDupFd(JimFileno(fh));
+ }
+ else {
+ inputId = JimOpenForRead(input);
+ if (inputId == JIM_BAD_FD) {
+ Jim_SetResultFormatted(interp, "couldn't read file \"%s\": %s", input, JimStrError());
+ goto error;
+ }
+ }
+ }
+ else if (inPipePtr != NULL) {
+ if (JimPipe(pipeIds) != 0) {
+ Jim_SetResultErrno(interp, "couldn't create input pipe for command");
+ goto error;
+ }
+ inputId = pipeIds[0];
+ *inPipePtr = pipeIds[1];
+ pipeIds[0] = pipeIds[1] = JIM_BAD_FD;
+ }
+
+ if (output != NULL) {
+ if (outputFile == FILE_HANDLE) {
+ FILE *fh = JimGetAioFilehandle(interp, output);
+ if (fh == NULL) {
+ goto error;
+ }
+ fflush(fh);
+ lastOutputId = JimDupFd(JimFileno(fh));
+ }
+ else {
+ lastOutputId = JimOpenForWrite(output, outputFile == FILE_APPEND);
+ if (lastOutputId == JIM_BAD_FD) {
+ Jim_SetResultFormatted(interp, "couldn't write file \"%s\": %s", output, JimStrError());
+ goto error;
+ }
+ }
+ }
+ else if (outPipePtr != NULL) {
+ if (JimPipe(pipeIds) != 0) {
+ Jim_SetResultErrno(interp, "couldn't create output pipe");
+ goto error;
+ }
+ lastOutputId = pipeIds[1];
+ *outPipePtr = pipeIds[0];
+ pipeIds[0] = pipeIds[1] = JIM_BAD_FD;
+ }
+
+ if (error != NULL) {
+ if (errorFile == FILE_HANDLE) {
+ if (strcmp(error, "1") == 0) {
+
+ if (lastOutputId != JIM_BAD_FD) {
+ errorId = JimDupFd(lastOutputId);
+ }
+ else {
+
+ error = "stdout";
+ }
+ }
+ if (errorId == JIM_BAD_FD) {
+ FILE *fh = JimGetAioFilehandle(interp, error);
+ if (fh == NULL) {
+ goto error;
+ }
+ fflush(fh);
+ errorId = JimDupFd(JimFileno(fh));
+ }
+ }
+ else {
+ errorId = JimOpenForWrite(error, errorFile == FILE_APPEND);
+ if (errorId == JIM_BAD_FD) {
+ Jim_SetResultFormatted(interp, "couldn't write file \"%s\": %s", error, JimStrError());
+ goto error;
+ }
+ }
+ }
+ else if (errFilePtr != NULL) {
+ errorId = JimCreateTemp(interp, NULL);
+ if (errorId == JIM_BAD_FD) {
+ goto error;
+ }
+ *errFilePtr = JimDupFd(errorId);
+ }
+
+
+ pidPtr = Jim_Alloc(cmdCount * sizeof(*pidPtr));
+ for (i = 0; i < numPids; i++) {
+ pidPtr[i] = JIM_BAD_PID;
+ }
+ for (firstArg = 0; firstArg < arg_count; numPids++, firstArg = lastArg + 1) {
+ int pipe_dup_err = 0;
+ fdtype origErrorId = errorId;
+
+ for (lastArg = firstArg; lastArg < arg_count; lastArg++) {
+ if (arg_array[lastArg][0] == '|') {
+ if (arg_array[lastArg][1] == '&') {
+ pipe_dup_err = 1;
+ }
+ break;
+ }
+ }
+
+ arg_array[lastArg] = NULL;
+ if (lastArg == arg_count) {
+ outputId = lastOutputId;
+ }
+ else {
+ if (JimPipe(pipeIds) != 0) {
+ Jim_SetResultErrno(interp, "couldn't create pipe");
+ goto error;
+ }
+ outputId = pipeIds[1];
+ }
+
+
+
+#ifdef __MINGW32__
+ pid = JimStartWinProcess(interp, &arg_array[firstArg], save_environ ? save_environ[0] : NULL, inputId, outputId, errorId);
+ if (pid == JIM_BAD_PID) {
+ Jim_SetResultFormatted(interp, "couldn't exec \"%s\"", arg_array[firstArg]);
+ goto error;
+ }
+#else
+ if (table->info == NULL) {
+ (void)signal(SIGPIPE, SIG_IGN);
+ }
+
+
+ if (pipe_dup_err) {
+ errorId = outputId;
+ }
+
+ pid = vfork();
+ if (pid < 0) {
+ Jim_SetResultErrno(interp, "couldn't fork child process");
+ goto error;
+ }
+ if (pid == 0) {
+
+
+ if (inputId != -1) dup2(inputId, 0);
+ if (outputId != -1) dup2(outputId, 1);
+ if (errorId != -1) dup2(errorId, 2);
+
+ for (i = 3; (i <= outputId) || (i <= inputId) || (i <= errorId); i++) {
+ close(i);
+ }
+
+ execvpe(arg_array[firstArg], &arg_array[firstArg], Jim_GetEnviron());
+
+
+ fprintf(stderr, "couldn't exec \"%s\"", arg_array[firstArg]);
+ _exit(127);
+ }
+#endif
+
+
+
+ if (table->used == table->size) {
+ table->size += WAIT_TABLE_GROW_BY;
+ table->info = Jim_Realloc(table->info, table->size * sizeof(*table->info));
+ }
+
+ table->info[table->used].pid = pid;
+ table->info[table->used].flags = 0;
+ table->used++;
+
+ pidPtr[numPids] = pid;
+
+
+ errorId = origErrorId;
+
+
+ if (inputId != JIM_BAD_FD) {
+ JimCloseFd(inputId);
+ }
+ if (outputId != JIM_BAD_FD) {
+ JimCloseFd(outputId);
+ }
+ inputId = pipeIds[0];
+ pipeIds[0] = pipeIds[1] = JIM_BAD_FD;
+ }
+ *pidArrayPtr = pidPtr;
+
+
+ cleanup:
+ if (inputId != JIM_BAD_FD) {
+ JimCloseFd(inputId);
+ }
+ if (lastOutputId != JIM_BAD_FD) {
+ JimCloseFd(lastOutputId);
+ }
+ if (errorId != JIM_BAD_FD) {
+ JimCloseFd(errorId);
+ }
+ Jim_Free(arg_array);
+
+ JimRestoreEnv(save_environ);
+
+ return numPids;
+
+
+ error:
+ if ((inPipePtr != NULL) && (*inPipePtr != JIM_BAD_FD)) {
+ JimCloseFd(*inPipePtr);
+ *inPipePtr = JIM_BAD_FD;
+ }
+ if ((outPipePtr != NULL) && (*outPipePtr != JIM_BAD_FD)) {
+ JimCloseFd(*outPipePtr);
+ *outPipePtr = JIM_BAD_FD;
+ }
+ if ((errFilePtr != NULL) && (*errFilePtr != JIM_BAD_FD)) {
+ JimCloseFd(*errFilePtr);
+ *errFilePtr = JIM_BAD_FD;
+ }
+ if (pipeIds[0] != JIM_BAD_FD) {
+ JimCloseFd(pipeIds[0]);
+ }
+ if (pipeIds[1] != JIM_BAD_FD) {
+ JimCloseFd(pipeIds[1]);
+ }
+ if (pidPtr != NULL) {
+ for (i = 0; i < numPids; i++) {
+ if (pidPtr[i] != JIM_BAD_PID) {
+ JimDetachPids(interp, 1, &pidPtr[i]);
+ }
+ }
+ Jim_Free(pidPtr);
+ }
+ numPids = -1;
+ goto cleanup;
+}
+
+
+static int JimCleanupChildren(Jim_Interp *interp, int numPids, pidtype *pidPtr, fdtype errorId)
+{
+ struct WaitInfoTable *table = Jim_CmdPrivData(interp);
+ int result = JIM_OK;
+ int i;
+
+ for (i = 0; i < numPids; i++) {
+ int waitStatus = 0;
+ if (JimWaitForProcess(table, pidPtr[i], &waitStatus) != JIM_BAD_PID) {
+ if (JimCheckWaitStatus(interp, pidPtr[i], waitStatus) != JIM_OK) {
+ result = JIM_ERR;
+ }
+ }
+ }
+ Jim_Free(pidPtr);
+
+ if (errorId != JIM_BAD_FD) {
+ JimRewindFd(errorId);
+ if (JimAppendStreamToString(interp, errorId, Jim_GetResult(interp)) != JIM_OK) {
+ result = JIM_ERR;
+ }
+ }
+
+ JimTrimTrailingNewline(interp);
+
+ return result;
+}
+
+int Jim_execInit(Jim_Interp *interp)
+{
+ if (Jim_PackageProvide(interp, "exec", "1.0", JIM_ERRMSG))
+ return JIM_ERR;
+ Jim_CreateCommand(interp, "exec", Jim_ExecCmd, JimAllocWaitInfoTable(), JimFreeWaitInfoTable);
+ return JIM_OK;
+}
+
+#if defined(__MINGW32__)
+
+
+static SECURITY_ATTRIBUTES *JimStdSecAttrs(void)
+{
+ static SECURITY_ATTRIBUTES secAtts;
+
+ secAtts.nLength = sizeof(SECURITY_ATTRIBUTES);
+ secAtts.lpSecurityDescriptor = NULL;
+ secAtts.bInheritHandle = TRUE;
+ return &secAtts;
+}
+
+static int JimErrno(void)
+{
+ switch (GetLastError()) {
+ case ERROR_FILE_NOT_FOUND: return ENOENT;
+ case ERROR_PATH_NOT_FOUND: return ENOENT;
+ case ERROR_TOO_MANY_OPEN_FILES: return EMFILE;
+ case ERROR_ACCESS_DENIED: return EACCES;
+ case ERROR_INVALID_HANDLE: return EBADF;
+ case ERROR_BAD_ENVIRONMENT: return E2BIG;
+ case ERROR_BAD_FORMAT: return ENOEXEC;
+ case ERROR_INVALID_ACCESS: return EACCES;
+ case ERROR_INVALID_DRIVE: return ENOENT;
+ case ERROR_CURRENT_DIRECTORY: return EACCES;
+ case ERROR_NOT_SAME_DEVICE: return EXDEV;
+ case ERROR_NO_MORE_FILES: return ENOENT;
+ case ERROR_WRITE_PROTECT: return EROFS;
+ case ERROR_BAD_UNIT: return ENXIO;
+ case ERROR_NOT_READY: return EBUSY;
+ case ERROR_BAD_COMMAND: return EIO;
+ case ERROR_CRC: return EIO;
+ case ERROR_BAD_LENGTH: return EIO;
+ case ERROR_SEEK: return EIO;
+ case ERROR_WRITE_FAULT: return EIO;
+ case ERROR_READ_FAULT: return EIO;
+ case ERROR_GEN_FAILURE: return EIO;
+ case ERROR_SHARING_VIOLATION: return EACCES;
+ case ERROR_LOCK_VIOLATION: return EACCES;
+ case ERROR_SHARING_BUFFER_EXCEEDED: return ENFILE;
+ case ERROR_HANDLE_DISK_FULL: return ENOSPC;
+ case ERROR_NOT_SUPPORTED: return ENODEV;
+ case ERROR_REM_NOT_LIST: return EBUSY;
+ case ERROR_DUP_NAME: return EEXIST;
+ case ERROR_BAD_NETPATH: return ENOENT;
+ case ERROR_NETWORK_BUSY: return EBUSY;
+ case ERROR_DEV_NOT_EXIST: return ENODEV;
+ case ERROR_TOO_MANY_CMDS: return EAGAIN;
+ case ERROR_ADAP_HDW_ERR: return EIO;
+ case ERROR_BAD_NET_RESP: return EIO;
+ case ERROR_UNEXP_NET_ERR: return EIO;
+ case ERROR_NETNAME_DELETED: return ENOENT;
+ case ERROR_NETWORK_ACCESS_DENIED: return EACCES;
+ case ERROR_BAD_DEV_TYPE: return ENODEV;
+ case ERROR_BAD_NET_NAME: return ENOENT;
+ case ERROR_TOO_MANY_NAMES: return ENFILE;
+ case ERROR_TOO_MANY_SESS: return EIO;
+ case ERROR_SHARING_PAUSED: return EAGAIN;
+ case ERROR_REDIR_PAUSED: return EAGAIN;
+ case ERROR_FILE_EXISTS: return EEXIST;
+ case ERROR_CANNOT_MAKE: return ENOSPC;
+ case ERROR_OUT_OF_STRUCTURES: return ENFILE;
+ case ERROR_ALREADY_ASSIGNED: return EEXIST;
+ case ERROR_INVALID_PASSWORD: return EPERM;
+ case ERROR_NET_WRITE_FAULT: return EIO;
+ case ERROR_NO_PROC_SLOTS: return EAGAIN;
+ case ERROR_DISK_CHANGE: return EXDEV;
+ case ERROR_BROKEN_PIPE: return EPIPE;
+ case ERROR_OPEN_FAILED: return ENOENT;
+ case ERROR_DISK_FULL: return ENOSPC;
+ case ERROR_NO_MORE_SEARCH_HANDLES: return EMFILE;
+ case ERROR_INVALID_TARGET_HANDLE: return EBADF;
+ case ERROR_INVALID_NAME: return ENOENT;
+ case ERROR_PROC_NOT_FOUND: return ESRCH;
+ case ERROR_WAIT_NO_CHILDREN: return ECHILD;
+ case ERROR_CHILD_NOT_COMPLETE: return ECHILD;
+ case ERROR_DIRECT_ACCESS_HANDLE: return EBADF;
+ case ERROR_SEEK_ON_DEVICE: return ESPIPE;
+ case ERROR_BUSY_DRIVE: return EAGAIN;
+ case ERROR_DIR_NOT_EMPTY: return EEXIST;
+ case ERROR_NOT_LOCKED: return EACCES;
+ case ERROR_BAD_PATHNAME: return ENOENT;
+ case ERROR_LOCK_FAILED: return EACCES;
+ case ERROR_ALREADY_EXISTS: return EEXIST;
+ case ERROR_FILENAME_EXCED_RANGE: return ENAMETOOLONG;
+ case ERROR_BAD_PIPE: return EPIPE;
+ case ERROR_PIPE_BUSY: return EAGAIN;
+ case ERROR_PIPE_NOT_CONNECTED: return EPIPE;
+ case ERROR_DIRECTORY: return ENOTDIR;
+ }
+ return EINVAL;
+}
+
+static int JimPipe(fdtype pipefd[2])
+{
+ if (CreatePipe(&pipefd[0], &pipefd[1], NULL, 0)) {
+ return 0;
+ }
+ return -1;
+}
+
+static fdtype JimDupFd(fdtype infd)
+{
+ fdtype dupfd;
+ pidtype pid = GetCurrentProcess();
+
+ if (DuplicateHandle(pid, infd, pid, &dupfd, 0, TRUE, DUPLICATE_SAME_ACCESS)) {
+ return dupfd;
+ }
+ return JIM_BAD_FD;
+}
+
+static int JimRewindFd(fdtype fd)
+{
+ return SetFilePointer(fd, 0, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER ? -1 : 0;
+}
+
+#if 0
+static int JimReadFd(fdtype fd, char *buffer, size_t len)
+{
+ DWORD num;
+
+ if (ReadFile(fd, buffer, len, &num, NULL)) {
+ return num;
+ }
+ if (GetLastError() == ERROR_HANDLE_EOF || GetLastError() == ERROR_BROKEN_PIPE) {
+ return 0;
+ }
+ return -1;
+}
+#endif
+
+static FILE *JimFdOpenForRead(fdtype fd)
+{
+ return _fdopen(_open_osfhandle((int)fd, _O_RDONLY | _O_TEXT), "r");
+}
+
+static fdtype JimFileno(FILE *fh)
+{
+ return (fdtype)_get_osfhandle(_fileno(fh));
+}
+
+static fdtype JimOpenForRead(const char *filename)
+{
+ return CreateFile(filename, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
+ JimStdSecAttrs(), OPEN_EXISTING, 0, NULL);
+}
+
+static fdtype JimOpenForWrite(const char *filename, int append)
+{
+ return CreateFile(filename, append ? FILE_APPEND_DATA : GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
+ JimStdSecAttrs(), append ? OPEN_ALWAYS : CREATE_ALWAYS, 0, (HANDLE) NULL);
+}
+
+static FILE *JimFdOpenForWrite(fdtype fd)
+{
+ return _fdopen(_open_osfhandle((int)fd, _O_TEXT), "w");
+}
+
+static pidtype JimWaitPid(pidtype pid, int *status, int nohang)
+{
+ DWORD ret = WaitForSingleObject(pid, nohang ? 0 : INFINITE);
+ if (ret == WAIT_TIMEOUT || ret == WAIT_FAILED) {
+
+ return JIM_BAD_PID;
+ }
+ GetExitCodeProcess(pid, &ret);
+ *status = ret;
+ CloseHandle(pid);
+ return pid;
+}
+
+static HANDLE JimCreateTemp(Jim_Interp *interp, const char *contents)
+{
+ char name[MAX_PATH];
+ HANDLE handle;
+
+ if (!GetTempPath(MAX_PATH, name) || !GetTempFileName(name, "JIM", 0, name)) {
+ return JIM_BAD_FD;
+ }
+
+ handle = CreateFile(name, GENERIC_READ | GENERIC_WRITE, 0, JimStdSecAttrs(),
+ CREATE_ALWAYS, FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE,
+ NULL);
+
+ if (handle == INVALID_HANDLE_VALUE) {
+ goto error;
+ }
+
+ if (contents != NULL) {
+
+ FILE *fh = JimFdOpenForWrite(JimDupFd(handle));
+ if (fh == NULL) {
+ goto error;
+ }
+
+ if (fwrite(contents, strlen(contents), 1, fh) != 1) {
+ fclose(fh);
+ goto error;
+ }
+ fseek(fh, 0, SEEK_SET);
+ fclose(fh);
+ }
+ return handle;
+
+ error:
+ Jim_SetResultErrno(interp, "failed to create temp file");
+ CloseHandle(handle);
+ DeleteFile(name);
+ return JIM_BAD_FD;
+}
+
+static int
+JimWinFindExecutable(const char *originalName, char fullPath[MAX_PATH])
+{
+ int i;
+ static char extensions[][5] = {".exe", "", ".bat"};
+
+ for (i = 0; i < (int) (sizeof(extensions) / sizeof(extensions[0])); i++) {
+ lstrcpyn(fullPath, originalName, MAX_PATH - 5);
+ lstrcat(fullPath, extensions[i]);
+
+ if (SearchPath(NULL, fullPath, NULL, MAX_PATH, fullPath, NULL) == 0) {
+ continue;
+ }
+ if (GetFileAttributes(fullPath) & FILE_ATTRIBUTE_DIRECTORY) {
+ continue;
+ }
+ return 0;
+ }
+
+ return -1;
+}
+
+static char **JimSaveEnv(char **env)
+{
+ return env;
+}
+
+static void JimRestoreEnv(char **env)
+{
+ JimFreeEnv(env, Jim_GetEnviron());
+}
+
+static Jim_Obj *
+JimWinBuildCommandLine(Jim_Interp *interp, char **argv)
+{
+ char *start, *special;
+ int quote, i;
+
+ Jim_Obj *strObj = Jim_NewStringObj(interp, "", 0);
+
+ for (i = 0; argv[i]; i++) {
+ if (i > 0) {
+ Jim_AppendString(interp, strObj, " ", 1);
+ }
+
+ if (argv[i][0] == '\0') {
+ quote = 1;
+ }
+ else {
+ quote = 0;
+ for (start = argv[i]; *start != '\0'; start++) {
+ if (isspace(UCHAR(*start))) {
+ quote = 1;
+ break;
+ }
+ }
+ }
+ if (quote) {
+ Jim_AppendString(interp, strObj, "\"" , 1);
+ }
+
+ start = argv[i];
+ for (special = argv[i]; ; ) {
+ if ((*special == '\\') && (special[1] == '\\' ||
+ special[1] == '"' || (quote && special[1] == '\0'))) {
+ Jim_AppendString(interp, strObj, start, special - start);
+ start = special;
+ while (1) {
+ special++;
+ if (*special == '"' || (quote && *special == '\0')) {
+
+ Jim_AppendString(interp, strObj, start, special - start);
+ break;
+ }
+ if (*special != '\\') {
+ break;
+ }
+ }
+ Jim_AppendString(interp, strObj, start, special - start);
+ start = special;
+ }
+ if (*special == '"') {
+ if (special == start) {
+ Jim_AppendString(interp, strObj, "\"", 1);
+ }
+ else {
+ Jim_AppendString(interp, strObj, start, special - start);
+ }
+ Jim_AppendString(interp, strObj, "\\\"", 2);
+ start = special + 1;
+ }
+ if (*special == '\0') {
+ break;
+ }
+ special++;
+ }
+ Jim_AppendString(interp, strObj, start, special - start);
+ if (quote) {
+ Jim_AppendString(interp, strObj, "\"", 1);
+ }
+ }
+ return strObj;
+}
+
+static pidtype
+JimStartWinProcess(Jim_Interp *interp, char **argv, char *env, fdtype inputId, fdtype outputId, fdtype errorId)
+{
+ STARTUPINFO startInfo;
+ PROCESS_INFORMATION procInfo;
+ HANDLE hProcess, h;
+ char execPath[MAX_PATH];
+ char *originalName;
+ pidtype pid = JIM_BAD_PID;
+ Jim_Obj *cmdLineObj;
+
+ if (JimWinFindExecutable(argv[0], execPath) < 0) {
+ return JIM_BAD_PID;
+ }
+ originalName = argv[0];
+ argv[0] = execPath;
+
+ hProcess = GetCurrentProcess();
+ cmdLineObj = JimWinBuildCommandLine(interp, argv);
+
+
+ ZeroMemory(&startInfo, sizeof(startInfo));
+ startInfo.cb = sizeof(startInfo);
+ startInfo.dwFlags = STARTF_USESTDHANDLES;
+ startInfo.hStdInput = INVALID_HANDLE_VALUE;
+ startInfo.hStdOutput= INVALID_HANDLE_VALUE;
+ startInfo.hStdError = INVALID_HANDLE_VALUE;
+
+ if (inputId == JIM_BAD_FD) {
+ if (CreatePipe(&startInfo.hStdInput, &h, JimStdSecAttrs(), 0) != FALSE) {
+ CloseHandle(h);
+ }
+ } else {
+ DuplicateHandle(hProcess, inputId, hProcess, &startInfo.hStdInput,
+ 0, TRUE, DUPLICATE_SAME_ACCESS);
+ }
+ if (startInfo.hStdInput == JIM_BAD_FD) {
+ goto end;
+ }
+
+ if (outputId == JIM_BAD_FD) {
+ startInfo.hStdOutput = CreateFile("NUL:", GENERIC_WRITE, 0,
+ JimStdSecAttrs(), OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
+ } else {
+ DuplicateHandle(hProcess, outputId, hProcess, &startInfo.hStdOutput,
+ 0, TRUE, DUPLICATE_SAME_ACCESS);
+ }
+ if (startInfo.hStdOutput == JIM_BAD_FD) {
+ goto end;
+ }
+
+ if (errorId == JIM_BAD_FD) {
+
+ startInfo.hStdError = CreateFile("NUL:", GENERIC_WRITE, 0,
+ JimStdSecAttrs(), OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+ } else {
+ DuplicateHandle(hProcess, errorId, hProcess, &startInfo.hStdError,
+ 0, TRUE, DUPLICATE_SAME_ACCESS);
+ }
+ if (startInfo.hStdError == JIM_BAD_FD) {
+ goto end;
+ }
+
+ if (!CreateProcess(NULL, (char *)Jim_String(cmdLineObj), NULL, NULL, TRUE,
+ 0, env, NULL, &startInfo, &procInfo)) {
+ goto end;
+ }
+
+
+ WaitForInputIdle(procInfo.hProcess, 5000);
+ CloseHandle(procInfo.hThread);
+
+ pid = procInfo.hProcess;
+
+ end:
+ Jim_FreeNewObj(interp, cmdLineObj);
+ if (startInfo.hStdInput != JIM_BAD_FD) {
+ CloseHandle(startInfo.hStdInput);
+ }
+ if (startInfo.hStdOutput != JIM_BAD_FD) {
+ CloseHandle(startInfo.hStdOutput);
+ }
+ if (startInfo.hStdError != JIM_BAD_FD) {
+ CloseHandle(startInfo.hStdError);
+ }
+ return pid;
+}
+#else
+
+static int JimOpenForWrite(const char *filename, int append)
+{
+ return open(filename, O_WRONLY | O_CREAT | (append ? O_APPEND : O_TRUNC), 0666);
+}
+
+static int JimRewindFd(int fd)
+{
+ return lseek(fd, 0L, SEEK_SET);
+}
+
+static int JimCreateTemp(Jim_Interp *interp, const char *contents)
+{
+ char inName[] = "/tmp/tcl.tmp.XXXXXX";
+
+ int fd = mkstemp(inName);
+ if (fd == JIM_BAD_FD) {
+ Jim_SetResultErrno(interp, "couldn't create temp file");
+ return -1;
+ }
+ unlink(inName);
+ if (contents) {
+ int length = strlen(contents);
+ if (write(fd, contents, length) != length) {
+ Jim_SetResultErrno(interp, "couldn't write temp file");
+ close(fd);
+ return -1;
+ }
+ lseek(fd, 0L, SEEK_SET);
+ }
+ return fd;
+}
+
+static char **JimSaveEnv(char **env)
+{
+ char **saveenv = Jim_GetEnviron();
+ Jim_SetEnviron(env);
+ return saveenv;
+}
+
+static void JimRestoreEnv(char **env)
+{
+ JimFreeEnv(Jim_GetEnviron(), env);
+ Jim_SetEnviron(env);
+}
+#endif
+#endif
+
+
+
+#ifndef _XOPEN_SOURCE
+#define _XOPEN_SOURCE 500
+#endif
+
+#include
+#include
+#include
+#include
+
+
+#ifdef HAVE_SYS_TIME_H
+#include
+#endif
+
+static int clock_cmd_format(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+
+ char buf[100];
+ time_t t;
+ long seconds;
+
+ const char *format = "%a %b %d %H:%M:%S %Z %Y";
+
+ if (argc == 2 || (argc == 3 && !Jim_CompareStringImmediate(interp, argv[1], "-format"))) {
+ return -1;
+ }
+
+ if (argc == 3) {
+ format = Jim_String(argv[2]);
+ }
+
+ if (Jim_GetLong(interp, argv[0], &seconds) != JIM_OK) {
+ return JIM_ERR;
+ }
+ t = seconds;
+
+ strftime(buf, sizeof(buf), format, localtime(&t));
+
+ Jim_SetResultString(interp, buf, -1);
+
+ return JIM_OK;
+}
+
+#ifdef HAVE_STRPTIME
+static int clock_cmd_scan(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ char *pt;
+ struct tm tm;
+ time_t now = time(0);
+
+ if (!Jim_CompareStringImmediate(interp, argv[1], "-format")) {
+ return -1;
+ }
+
+
+ localtime_r(&now, &tm);
+
+ pt = strptime(Jim_String(argv[0]), Jim_String(argv[2]), &tm);
+ if (pt == 0 || *pt != 0) {
+ Jim_SetResultString(interp, "Failed to parse time according to format", -1);
+ return JIM_ERR;
+ }
+
+
+ Jim_SetResultInt(interp, mktime(&tm));
+
+ return JIM_OK;
+}
+#endif
+
+static int clock_cmd_seconds(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ Jim_SetResultInt(interp, time(NULL));
+
+ return JIM_OK;
+}
+
+static int clock_cmd_micros(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ struct timeval tv;
+
+ gettimeofday(&tv, NULL);
+
+ Jim_SetResultInt(interp, (jim_wide) tv.tv_sec * 1000000 + tv.tv_usec);
+
+ return JIM_OK;
+}
+
+static int clock_cmd_millis(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ struct timeval tv;
+
+ gettimeofday(&tv, NULL);
+
+ Jim_SetResultInt(interp, (jim_wide) tv.tv_sec * 1000 + tv.tv_usec / 1000);
+
+ return JIM_OK;
+}
+
+static const jim_subcmd_type clock_command_table[] = {
+ { "seconds",
+ NULL,
+ clock_cmd_seconds,
+ 0,
+ 0,
+
+ },
+ { "clicks",
+ NULL,
+ clock_cmd_micros,
+ 0,
+ 0,
+
+ },
+ { "microseconds",
+ NULL,
+ clock_cmd_micros,
+ 0,
+ 0,
+
+ },
+ { "milliseconds",
+ NULL,
+ clock_cmd_millis,
+ 0,
+ 0,
+
+ },
+ { "format",
+ "seconds ?-format format?",
+ clock_cmd_format,
+ 1,
+ 3,
+
+ },
+#ifdef HAVE_STRPTIME
+ { "scan",
+ "str -format format",
+ clock_cmd_scan,
+ 3,
+ 3,
+
+ },
+#endif
+ { NULL }
+};
+
+int Jim_clockInit(Jim_Interp *interp)
+{
+ if (Jim_PackageProvide(interp, "clock", "1.0", JIM_ERRMSG))
+ return JIM_ERR;
+
+ Jim_CreateCommand(interp, "clock", Jim_SubCmdProc, (void *)clock_command_table, NULL);
+ return JIM_OK;
+}
+
+
+#include
+#include
+#include
+#include
+#include
+
+
+static int array_cmd_exists(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+
+ Jim_SetResultInt(interp, Jim_GetVariable(interp, argv[0], 0) != 0);
+ return JIM_OK;
+}
+
+static int array_cmd_get(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ Jim_Obj *objPtr = Jim_GetVariable(interp, argv[0], JIM_NONE);
+
+ if (!objPtr) {
+ return JIM_OK;
+ }
+
+ if (argc == 1 || Jim_CompareStringImmediate(interp, argv[1], "*")) {
+
+ if (Jim_IsList(objPtr)) {
+ if (Jim_ListLength(interp, objPtr) % 2 != 0) {
+
+ return JIM_ERR;
+ }
+ }
+ else if (Jim_DictSize(interp, objPtr) < 0) {
+
+ return JIM_ERR;
+ }
+ Jim_SetResult(interp, objPtr);
+ return JIM_OK;
+ }
+
+
+ return Jim_DictValues(interp, objPtr, argv[1]);
+}
+
+static int array_cmd_names(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ Jim_Obj *objPtr = Jim_GetVariable(interp, argv[0], JIM_NONE);
+
+ if (!objPtr) {
+ return JIM_OK;
+ }
+
+ return Jim_DictKeys(interp, objPtr, argc == 1 ? NULL : argv[1]);
+}
+
+static int array_cmd_unset(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ int i;
+ int len;
+ Jim_Obj *resultObj;
+ Jim_Obj *objPtr;
+ Jim_Obj **dictValuesObj;
+
+ if (argc == 1 || Jim_CompareStringImmediate(interp, argv[1], "*")) {
+
+ Jim_UnsetVariable(interp, argv[0], JIM_NONE);
+ return JIM_OK;
+ }
+
+ objPtr = Jim_GetVariable(interp, argv[0], JIM_NONE);
+
+ if (Jim_DictPairs(interp, objPtr, &dictValuesObj, &len) != JIM_OK) {
+ return JIM_ERR;
+ }
+
+
+ resultObj = Jim_NewDictObj(interp, NULL, 0);
+
+ for (i = 0; i < len; i += 2) {
+ if (!Jim_StringMatchObj(interp, argv[1], dictValuesObj[i], 0)) {
+ Jim_DictAddElement(interp, resultObj, dictValuesObj[i], dictValuesObj[i + 1]);
+ }
+ }
+ Jim_Free(dictValuesObj);
+
+ Jim_SetVariable(interp, argv[0], resultObj);
+ return JIM_OK;
+}
+
+static int array_cmd_size(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ Jim_Obj *objPtr;
+ int len = 0;
+
+
+ objPtr = Jim_GetVariable(interp, argv[0], JIM_NONE);
+ if (objPtr) {
+ len = Jim_DictSize(interp, objPtr);
+ if (len < 0) {
+ return JIM_ERR;
+ }
+ }
+
+ Jim_SetResultInt(interp, len);
+
+ return JIM_OK;
+}
+
+static int array_cmd_set(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ int i;
+ int len;
+ Jim_Obj *listObj = argv[1];
+ Jim_Obj *dictObj;
+
+ len = Jim_ListLength(interp, listObj);
+ if (len % 2) {
+ Jim_SetResultString(interp, "list must have an even number of elements", -1);
+ return JIM_ERR;
+ }
+
+ dictObj = Jim_GetVariable(interp, argv[0], JIM_UNSHARED);
+ if (!dictObj) {
+
+ return Jim_SetVariable(interp, argv[0], listObj);
+ }
+
+ if (Jim_IsShared(dictObj)) {
+ dictObj = Jim_DuplicateObj(interp, dictObj);
+ }
+
+ for (i = 0; i < len; i += 2) {
+ Jim_Obj *nameObj;
+ Jim_Obj *valueObj;
+
+ Jim_ListIndex(interp, listObj, i, &nameObj, JIM_NONE);
+ Jim_ListIndex(interp, listObj, i + 1, &valueObj, JIM_NONE);
+
+ Jim_DictAddElement(interp, dictObj, nameObj, valueObj);
+ }
+ return Jim_SetVariable(interp, argv[0], dictObj);
+}
+
+static const jim_subcmd_type array_command_table[] = {
+ { "exists",
+ "arrayName",
+ array_cmd_exists,
+ 1,
+ 1,
+
+ },
+ { "get",
+ "arrayName ?pattern?",
+ array_cmd_get,
+ 1,
+ 2,
+
+ },
+ { "names",
+ "arrayName ?pattern?",
+ array_cmd_names,
+ 1,
+ 2,
+
+ },
+ { "set",
+ "arrayName list",
+ array_cmd_set,
+ 2,
+ 2,
+
+ },
+ { "size",
+ "arrayName",
+ array_cmd_size,
+ 1,
+ 1,
+
+ },
+ { "unset",
+ "arrayName ?pattern?",
+ array_cmd_unset,
+ 1,
+ 2,
+
+ },
+ { NULL
+ }
+};
+
+int Jim_arrayInit(Jim_Interp *interp)
+{
+ if (Jim_PackageProvide(interp, "array", "1.0", JIM_ERRMSG))
+ return JIM_ERR;
+
+ Jim_CreateCommand(interp, "array", Jim_SubCmdProc, (void *)array_command_table, NULL);
+ return JIM_OK;
+}
+int Jim_InitStaticExtensions(Jim_Interp *interp)
+{
+extern int Jim_bootstrapInit(Jim_Interp *);
+extern int Jim_aioInit(Jim_Interp *);
+extern int Jim_readdirInit(Jim_Interp *);
+extern int Jim_globInit(Jim_Interp *);
+extern int Jim_regexpInit(Jim_Interp *);
+extern int Jim_fileInit(Jim_Interp *);
+extern int Jim_execInit(Jim_Interp *);
+extern int Jim_clockInit(Jim_Interp *);
+extern int Jim_arrayInit(Jim_Interp *);
+extern int Jim_stdlibInit(Jim_Interp *);
+extern int Jim_tclcompatInit(Jim_Interp *);
+Jim_bootstrapInit(interp);
+Jim_aioInit(interp);
+Jim_readdirInit(interp);
+Jim_globInit(interp);
+Jim_regexpInit(interp);
+Jim_fileInit(interp);
+Jim_execInit(interp);
+Jim_clockInit(interp);
+Jim_arrayInit(interp);
+Jim_stdlibInit(interp);
+Jim_tclcompatInit(interp);
+return JIM_OK;
+}
+
+#define JIM_OPTIMIZATION
+
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+
+#ifdef HAVE_SYS_TIME_H
+#include
+#endif
+#ifdef HAVE_BACKTRACE
+#include
+#endif
+#ifdef HAVE_CRT_EXTERNS_H
+#include
+#endif
+
+
+#include
+
+
+
+
+
+#ifndef TCL_LIBRARY
+#define TCL_LIBRARY "."
+#endif
+#ifndef TCL_PLATFORM_OS
+#define TCL_PLATFORM_OS "unknown"
+#endif
+#ifndef TCL_PLATFORM_PLATFORM
+#define TCL_PLATFORM_PLATFORM "unknown"
+#endif
+#ifndef TCL_PLATFORM_PATH_SEPARATOR
+#define TCL_PLATFORM_PATH_SEPARATOR ":"
+#endif
+
+
+
+
+
+
+
+#ifdef JIM_MAINTAINER
+#define JIM_DEBUG_COMMAND
+#define JIM_DEBUG_PANIC
+#endif
+
+const char *jim_tt_name(int type);
+
+#ifdef JIM_DEBUG_PANIC
+static void JimPanicDump(int panic_condition, const char *fmt, ...);
+#define JimPanic(X) JimPanicDump X
+#else
+#define JimPanic(X)
+#endif
+
+
+static char JimEmptyStringRep[] = "";
+
+static void JimChangeCallFrameId(Jim_Interp *interp, Jim_CallFrame *cf);
+static void JimFreeCallFrame(Jim_Interp *interp, Jim_CallFrame *cf, int flags);
+static int ListSetIndex(Jim_Interp *interp, Jim_Obj *listPtr, int listindex, Jim_Obj *newObjPtr,
+ int flags);
+static int JimDeleteLocalProcs(Jim_Interp *interp, Jim_Stack *localCommands);
+static Jim_Obj *JimExpandDictSugar(Jim_Interp *interp, Jim_Obj *objPtr);
+static void SetDictSubstFromAny(Jim_Interp *interp, Jim_Obj *objPtr);
+static void JimSetFailedEnumResult(Jim_Interp *interp, const char *arg, const char *badtype,
+ const char *prefix, const char *const *tablePtr, const char *name);
+static int JimCallProcedure(Jim_Interp *interp, Jim_Cmd *cmd, int argc, Jim_Obj *const *argv);
+static int JimGetWideNoErr(Jim_Interp *interp, Jim_Obj *objPtr, jim_wide * widePtr);
+static int JimSign(jim_wide w);
+static int JimValidName(Jim_Interp *interp, const char *type, Jim_Obj *nameObjPtr);
+static void JimPrngSeed(Jim_Interp *interp, unsigned char *seed, int seedLen);
+static void JimRandomBytes(Jim_Interp *interp, void *dest, unsigned int len);
+
+
+
+#define JimWideValue(objPtr) (objPtr)->internalRep.wideValue
+
+#define JimObjTypeName(O) ((O)->typePtr ? (O)->typePtr->name : "none")
+
+static int utf8_tounicode_case(const char *s, int *uc, int upper)
+{
+ int l = utf8_tounicode(s, uc);
+ if (upper) {
+ *uc = utf8_upper(*uc);
+ }
+ return l;
+}
+
+
+#define JIM_CHARSET_SCAN 2
+#define JIM_CHARSET_GLOB 0
+
+static const char *JimCharsetMatch(const char *pattern, int c, int flags)
+{
+ int not = 0;
+ int pchar;
+ int match = 0;
+ int nocase = 0;
+
+ if (flags & JIM_NOCASE) {
+ nocase++;
+ c = utf8_upper(c);
+ }
+
+ if (flags & JIM_CHARSET_SCAN) {
+ if (*pattern == '^') {
+ not++;
+ pattern++;
+ }
+
+
+ if (*pattern == ']') {
+ goto first;
+ }
+ }
+
+ while (*pattern && *pattern != ']') {
+
+ if (pattern[0] == '\\') {
+first:
+ pattern += utf8_tounicode_case(pattern, &pchar, nocase);
+ }
+ else {
+
+ int start;
+ int end;
+
+ pattern += utf8_tounicode_case(pattern, &start, nocase);
+ if (pattern[0] == '-' && pattern[1]) {
+
+ pattern += utf8_tounicode(pattern, &pchar);
+ pattern += utf8_tounicode_case(pattern, &end, nocase);
+
+
+ if ((c >= start && c <= end) || (c >= end && c <= start)) {
+ match = 1;
+ }
+ continue;
+ }
+ pchar = start;
+ }
+
+ if (pchar == c) {
+ match = 1;
+ }
+ }
+ if (not) {
+ match = !match;
+ }
+
+ return match ? pattern : NULL;
+}
+
+
+
+static int JimGlobMatch(const char *pattern, const char *string, int nocase)
+{
+ int c;
+ int pchar;
+ while (*pattern) {
+ switch (pattern[0]) {
+ case '*':
+ while (pattern[1] == '*') {
+ pattern++;
+ }
+ pattern++;
+ if (!pattern[0]) {
+ return 1;
+ }
+ while (*string) {
+
+ if (JimGlobMatch(pattern, string, nocase))
+ return 1;
+ string += utf8_tounicode(string, &c);
+ }
+ return 0;
+
+ case '?':
+ string += utf8_tounicode(string, &c);
+ break;
+
+ case '[': {
+ string += utf8_tounicode(string, &c);
+ pattern = JimCharsetMatch(pattern + 1, c, nocase ? JIM_NOCASE : 0);
+ if (!pattern) {
+ return 0;
+ }
+ if (!*pattern) {
+
+ continue;
+ }
+ break;
+ }
+ case '\\':
+ if (pattern[1]) {
+ pattern++;
+ }
+
+ default:
+ string += utf8_tounicode_case(string, &c, nocase);
+ utf8_tounicode_case(pattern, &pchar, nocase);
+ if (pchar != c) {
+ return 0;
+ }
+ break;
+ }
+ pattern += utf8_tounicode_case(pattern, &pchar, nocase);
+ if (!*string) {
+ while (*pattern == '*') {
+ pattern++;
+ }
+ break;
+ }
+ }
+ if (!*pattern && !*string) {
+ return 1;
+ }
+ return 0;
+}
+
+static int JimStringCompare(const char *s1, int l1, const char *s2, int l2)
+{
+ if (l1 < l2) {
+ return memcmp(s1, s2, l1) <= 0 ? -1 : 1;
+ }
+ else if (l2 < l1) {
+ return memcmp(s1, s2, l2) >= 0 ? 1 : -1;
+ }
+ else {
+ return JimSign(memcmp(s1, s2, l1));
+ }
+}
+
+static int JimStringCompareLen(const char *s1, const char *s2, int maxchars, int nocase)
+{
+ while (*s1 && *s2 && maxchars) {
+ int c1, c2;
+ s1 += utf8_tounicode_case(s1, &c1, nocase);
+ s2 += utf8_tounicode_case(s2, &c2, nocase);
+ if (c1 != c2) {
+ return JimSign(c1 - c2);
+ }
+ maxchars--;
+ }
+ if (!maxchars) {
+ return 0;
+ }
+
+ if (*s1) {
+ return 1;
+ }
+ if (*s2) {
+ return -1;
+ }
+ return 0;
+}
+
+static int JimStringFirst(const char *s1, int l1, const char *s2, int l2, int idx)
+{
+ int i;
+ int l1bytelen;
+
+ if (!l1 || !l2 || l1 > l2) {
+ return -1;
+ }
+ if (idx < 0)
+ idx = 0;
+ s2 += utf8_index(s2, idx);
+
+ l1bytelen = utf8_index(s1, l1);
+
+ for (i = idx; i <= l2 - l1; i++) {
+ int c;
+ if (memcmp(s2, s1, l1bytelen) == 0) {
+ return i;
+ }
+ s2 += utf8_tounicode(s2, &c);
+ }
+ return -1;
+}
+
+static int JimStringLast(const char *s1, int l1, const char *s2, int l2)
+{
+ const char *p;
+
+ if (!l1 || !l2 || l1 > l2)
+ return -1;
+
+
+ for (p = s2 + l2 - 1; p != s2 - 1; p--) {
+ if (*p == *s1 && memcmp(s1, p, l1) == 0) {
+ return p - s2;
+ }
+ }
+ return -1;
+}
+
+#ifdef JIM_UTF8
+static int JimStringLastUtf8(const char *s1, int l1, const char *s2, int l2)
+{
+ int n = JimStringLast(s1, utf8_index(s1, l1), s2, utf8_index(s2, l2));
+ if (n > 0) {
+ n = utf8_strlen(s2, n);
+ }
+ return n;
+}
+#endif
+
+int Jim_WideToString(char *buf, jim_wide wideValue)
+{
+ const char *fmt = "%" JIM_WIDE_MODIFIER;
+
+ return sprintf(buf, fmt, wideValue);
+}
+
+static int JimCheckConversion(const char *str, const char *endptr)
+{
+ if (str[0] == '\0' || str == endptr) {
+ return JIM_ERR;
+ }
+
+ if (endptr[0] != '\0') {
+ while (*endptr) {
+ if (!isspace(UCHAR(*endptr))) {
+ return JIM_ERR;
+ }
+ endptr++;
+ }
+ }
+ return JIM_OK;
+}
+
+static int JimNumberBase(const char *str, int *base, int *sign)
+{
+ int i = 0;
+
+ *base = 10;
+
+ while (isspace(UCHAR(str[i]))) {
+ i++;
+ }
+
+ if (str[i] == '-') {
+ *sign = -1;
+ i++;
+ }
+ else {
+ if (str[i] == '+') {
+ i++;
+ }
+ *sign = 1;
+ }
+
+ if (str[i] != '0') {
+
+ return 0;
+ }
+
+
+ switch (str[i + 1]) {
+ case 'x': case 'X': *base = 16; break;
+ case 'o': case 'O': *base = 8; break;
+ case 'b': case 'B': *base = 2; break;
+ default: return 0;
+ }
+ i += 2;
+
+ if (str[i] != '-' && str[i] != '+' && !isspace(UCHAR(str[i]))) {
+
+ return i;
+ }
+
+ return 10;
+}
+
+static long jim_strtol(const char *str, char **endptr)
+{
+ int sign;
+ int base;
+ int i = JimNumberBase(str, &base, &sign);
+
+ if (base != 10) {
+ long value = strtol(str + i, endptr, base);
+ if (endptr == NULL || *endptr != str + i) {
+ return value * sign;
+ }
+ }
+
+
+ return strtol(str, endptr, 10);
+}
+
+
+static jim_wide jim_strtoull(const char *str, char **endptr)
+{
+#ifdef HAVE_LONG_LONG
+ int sign;
+ int base;
+ int i = JimNumberBase(str, &base, &sign);
+
+ if (base != 10) {
+ jim_wide value = strtoull(str + i, endptr, base);
+ if (endptr == NULL || *endptr != str + i) {
+ return value * sign;
+ }
+ }
+
+
+ return strtoull(str, endptr, 10);
+#else
+ return (unsigned long)jim_strtol(str, endptr);
+#endif
+}
+
+int Jim_StringToWide(const char *str, jim_wide * widePtr, int base)
+{
+ char *endptr;
+
+ if (base) {
+ *widePtr = strtoull(str, &endptr, base);
+ }
+ else {
+ *widePtr = jim_strtoull(str, &endptr);
+ }
+
+ return JimCheckConversion(str, endptr);
+}
+
+int Jim_DoubleToString(char *buf, double doubleValue)
+{
+ int len;
+ int i;
+
+ len = sprintf(buf, "%.12g", doubleValue);
+
+
+ for (i = 0; i < len; i++) {
+ if (buf[i] == '.' || buf[i] == 'e') {
+#if defined(JIM_SPRINTF_DOUBLE_NEEDS_FIX)
+ char *e = strchr(buf, 'e');
+ if (e && (e[1] == '-' || e[1] == '+') && e[2] == '0') {
+
+ e += 2;
+ memmove(e, e + 1, len - (e - buf));
+ return len - 1;
+ }
+#endif
+ return len;
+ }
+
+ if (buf[i] == 'i' || buf[i] == 'I' || buf[i] == 'n' || buf[i] == 'N') {
+ buf[i] = toupper(UCHAR(buf[i]));
+ buf[i + 3] = 0;
+ return i + 3;
+ }
+ }
+
+ buf[i++] = '.';
+ buf[i++] = '0';
+ buf[i] = '\0';
+
+ return i;
+}
+
+int Jim_StringToDouble(const char *str, double *doublePtr)
+{
+ char *endptr;
+
+
+ errno = 0;
+
+ *doublePtr = strtod(str, &endptr);
+
+ return JimCheckConversion(str, endptr);
+}
+
+static jim_wide JimPowWide(jim_wide b, jim_wide e)
+{
+ jim_wide i, res = 1;
+
+ if ((b == 0 && e != 0) || (e < 0))
+ return 0;
+ for (i = 0; i < e; i++) {
+ res *= b;
+ }
+ return res;
+}
+
+#ifdef JIM_DEBUG_PANIC
+void JimPanicDump(int condition, const char *fmt, ...)
+{
+ va_list ap;
+
+ if (!condition) {
+ return;
+ }
+
+ va_start(ap, fmt);
+
+ fprintf(stderr, JIM_NL "JIM INTERPRETER PANIC: ");
+ vfprintf(stderr, fmt, ap);
+ fprintf(stderr, JIM_NL JIM_NL);
+ va_end(ap);
+
+#ifdef HAVE_BACKTRACE
+ {
+ void *array[40];
+ int size, i;
+ char **strings;
+
+ size = backtrace(array, 40);
+ strings = backtrace_symbols(array, size);
+ for (i = 0; i < size; i++)
+ fprintf(stderr, "[backtrace] %s" JIM_NL, strings[i]);
+ fprintf(stderr, "[backtrace] Include the above lines and the output" JIM_NL);
+ fprintf(stderr, "[backtrace] of 'nm ' in the bug report." JIM_NL);
+ }
+#endif
+
+ exit(1);
+}
+#endif
+
+
+void *Jim_Alloc(int size)
+{
+ return size ? malloc(size) : NULL;
+}
+
+void Jim_Free(void *ptr)
+{
+ free(ptr);
+}
+
+void *Jim_Realloc(void *ptr, int size)
+{
+ return realloc(ptr, size);
+}
+
+char *Jim_StrDup(const char *s)
+{
+ return strdup(s);
+}
+
+char *Jim_StrDupLen(const char *s, int l)
+{
+ char *copy = Jim_Alloc(l + 1);
+
+ memcpy(copy, s, l + 1);
+ copy[l] = 0;
+ return copy;
+}
+
+
+
+static jim_wide JimClock(void)
+{
+ struct timeval tv;
+
+ gettimeofday(&tv, NULL);
+ return (jim_wide) tv.tv_sec * 1000000 + tv.tv_usec;
+}
+
+
+
+static void JimExpandHashTableIfNeeded(Jim_HashTable *ht);
+static unsigned int JimHashTableNextPower(unsigned int size);
+static Jim_HashEntry *JimInsertHashEntry(Jim_HashTable *ht, const void *key, int replace);
+
+
+
+
+unsigned int Jim_IntHashFunction(unsigned int key)
+{
+ key += ~(key << 15);
+ key ^= (key >> 10);
+ key += (key << 3);
+ key ^= (key >> 6);
+ key += ~(key << 11);
+ key ^= (key >> 16);
+ return key;
+}
+
+unsigned int Jim_GenHashFunction(const unsigned char *buf, int len)
+{
+ unsigned int h = 0;
+
+ while (len--)
+ h += (h << 3) + *buf++;
+ return h;
+}
+
+
+
+static void JimResetHashTable(Jim_HashTable *ht)
+{
+ ht->table = NULL;
+ ht->size = 0;
+ ht->sizemask = 0;
+ ht->used = 0;
+ ht->collisions = 0;
+}
+
+
+int Jim_InitHashTable(Jim_HashTable *ht, const Jim_HashTableType *type, void *privDataPtr)
+{
+ JimResetHashTable(ht);
+ ht->type = type;
+ ht->privdata = privDataPtr;
+ return JIM_OK;
+}
+
+void Jim_ResizeHashTable(Jim_HashTable *ht)
+{
+ int minimal = ht->used;
+
+ if (minimal < JIM_HT_INITIAL_SIZE)
+ minimal = JIM_HT_INITIAL_SIZE;
+ Jim_ExpandHashTable(ht, minimal);
+}
+
+
+void Jim_ExpandHashTable(Jim_HashTable *ht, unsigned int size)
+{
+ Jim_HashTable n;
+ unsigned int realsize = JimHashTableNextPower(size), i;
+
+ if (size <= ht->used)
+ return;
+
+ Jim_InitHashTable(&n, ht->type, ht->privdata);
+ n.size = realsize;
+ n.sizemask = realsize - 1;
+ n.table = Jim_Alloc(realsize * sizeof(Jim_HashEntry *));
+
+
+ memset(n.table, 0, realsize * sizeof(Jim_HashEntry *));
+
+ n.used = ht->used;
+ for (i = 0; ht->used > 0; i++) {
+ Jim_HashEntry *he, *nextHe;
+
+ if (ht->table[i] == NULL)
+ continue;
+
+
+ he = ht->table[i];
+ while (he) {
+ unsigned int h;
+
+ nextHe = he->next;
+
+ h = Jim_HashKey(ht, he->key) & n.sizemask;
+ he->next = n.table[h];
+ n.table[h] = he;
+ ht->used--;
+
+ he = nextHe;
+ }
+ }
+ assert(ht->used == 0);
+ Jim_Free(ht->table);
+
+
+ *ht = n;
+}
+
+
+int Jim_AddHashEntry(Jim_HashTable *ht, const void *key, void *val)
+{
+ Jim_HashEntry *entry;
+
+ entry = JimInsertHashEntry(ht, key, 0);
+ if (entry == NULL)
+ return JIM_ERR;
+
+
+ Jim_SetHashKey(ht, entry, key);
+ Jim_SetHashVal(ht, entry, val);
+ return JIM_OK;
+}
+
+
+int Jim_ReplaceHashEntry(Jim_HashTable *ht, const void *key, void *val)
+{
+ int existed;
+ Jim_HashEntry *entry;
+
+ entry = JimInsertHashEntry(ht, key, 1);
+ if (entry->key) {
+
+ Jim_FreeEntryVal(ht, entry);
+ existed = 1;
+ }
+ else {
+
+ Jim_SetHashKey(ht, entry, key);
+ existed = 0;
+ }
+ Jim_SetHashVal(ht, entry, val);
+
+ return existed;
+}
+
+
+int Jim_DeleteHashEntry(Jim_HashTable *ht, const void *key)
+{
+ unsigned int h;
+ Jim_HashEntry *he, *prevHe;
+
+ if (ht->used == 0)
+ return JIM_ERR;
+ h = Jim_HashKey(ht, key) & ht->sizemask;
+ he = ht->table[h];
+
+ prevHe = NULL;
+ while (he) {
+ if (Jim_CompareHashKeys(ht, key, he->key)) {
+
+ if (prevHe)
+ prevHe->next = he->next;
+ else
+ ht->table[h] = he->next;
+ Jim_FreeEntryKey(ht, he);
+ Jim_FreeEntryVal(ht, he);
+ Jim_Free(he);
+ ht->used--;
+ return JIM_OK;
+ }
+ prevHe = he;
+ he = he->next;
+ }
+ return JIM_ERR;
+}
+
+
+int Jim_FreeHashTable(Jim_HashTable *ht)
+{
+ unsigned int i;
+
+
+ for (i = 0; ht->used > 0; i++) {
+ Jim_HashEntry *he, *nextHe;
+
+ if ((he = ht->table[i]) == NULL)
+ continue;
+ while (he) {
+ nextHe = he->next;
+ Jim_FreeEntryKey(ht, he);
+ Jim_FreeEntryVal(ht, he);
+ Jim_Free(he);
+ ht->used--;
+ he = nextHe;
+ }
+ }
+
+ Jim_Free(ht->table);
+
+ JimResetHashTable(ht);
+ return JIM_OK;
+}
+
+Jim_HashEntry *Jim_FindHashEntry(Jim_HashTable *ht, const void *key)
+{
+ Jim_HashEntry *he;
+ unsigned int h;
+
+ if (ht->used == 0)
+ return NULL;
+ h = Jim_HashKey(ht, key) & ht->sizemask;
+ he = ht->table[h];
+ while (he) {
+ if (Jim_CompareHashKeys(ht, key, he->key))
+ return he;
+ he = he->next;
+ }
+ return NULL;
+}
+
+Jim_HashTableIterator *Jim_GetHashTableIterator(Jim_HashTable *ht)
+{
+ Jim_HashTableIterator *iter = Jim_Alloc(sizeof(*iter));
+
+ iter->ht = ht;
+ iter->index = -1;
+ iter->entry = NULL;
+ iter->nextEntry = NULL;
+ return iter;
+}
+
+Jim_HashEntry *Jim_NextHashEntry(Jim_HashTableIterator *iter)
+{
+ while (1) {
+ if (iter->entry == NULL) {
+ iter->index++;
+ if (iter->index >= (signed)iter->ht->size)
+ break;
+ iter->entry = iter->ht->table[iter->index];
+ }
+ else {
+ iter->entry = iter->nextEntry;
+ }
+ if (iter->entry) {
+ iter->nextEntry = iter->entry->next;
+ return iter->entry;
+ }
+ }
+ return NULL;
+}
+
+
+
+
+static void JimExpandHashTableIfNeeded(Jim_HashTable *ht)
+{
+ if (ht->size == 0)
+ Jim_ExpandHashTable(ht, JIM_HT_INITIAL_SIZE);
+ if (ht->size == ht->used)
+ Jim_ExpandHashTable(ht, ht->size * 2);
+}
+
+
+static unsigned int JimHashTableNextPower(unsigned int size)
+{
+ unsigned int i = JIM_HT_INITIAL_SIZE;
+
+ if (size >= 2147483648U)
+ return 2147483648U;
+ while (1) {
+ if (i >= size)
+ return i;
+ i *= 2;
+ }
+}
+
+static Jim_HashEntry *JimInsertHashEntry(Jim_HashTable *ht, const void *key, int replace)
+{
+ unsigned int h;
+ Jim_HashEntry *he;
+
+
+ JimExpandHashTableIfNeeded(ht);
+
+
+ h = Jim_HashKey(ht, key) & ht->sizemask;
+
+ he = ht->table[h];
+ while (he) {
+ if (Jim_CompareHashKeys(ht, key, he->key))
+ return replace ? he : NULL;
+ he = he->next;
+ }
+
+
+ he = Jim_Alloc(sizeof(*he));
+ he->next = ht->table[h];
+ ht->table[h] = he;
+ ht->used++;
+ he->key = NULL;
+
+ return he;
+}
+
+
+
+static unsigned int JimStringCopyHTHashFunction(const void *key)
+{
+ return Jim_GenHashFunction(key, strlen(key));
+}
+
+static void *JimStringCopyHTDup(void *privdata, const void *key)
+{
+ return strdup(key);
+}
+
+static int JimStringCopyHTKeyCompare(void *privdata, const void *key1, const void *key2)
+{
+ return strcmp(key1, key2) == 0;
+}
+
+static void JimStringCopyHTKeyDestructor(void *privdata, void *key)
+{
+ Jim_Free(key);
+}
+
+static const Jim_HashTableType JimPackageHashTableType = {
+ JimStringCopyHTHashFunction,
+ JimStringCopyHTDup,
+ NULL,
+ JimStringCopyHTKeyCompare,
+ JimStringCopyHTKeyDestructor,
+ NULL
+};
+
+typedef struct AssocDataValue
+{
+ Jim_InterpDeleteProc *delProc;
+ void *data;
+} AssocDataValue;
+
+static void JimAssocDataHashTableValueDestructor(void *privdata, void *data)
+{
+ AssocDataValue *assocPtr = (AssocDataValue *) data;
+
+ if (assocPtr->delProc != NULL)
+ assocPtr->delProc((Jim_Interp *)privdata, assocPtr->data);
+ Jim_Free(data);
+}
+
+static const Jim_HashTableType JimAssocDataHashTableType = {
+ JimStringCopyHTHashFunction,
+ JimStringCopyHTDup,
+ NULL,
+ JimStringCopyHTKeyCompare,
+ JimStringCopyHTKeyDestructor,
+ JimAssocDataHashTableValueDestructor
+};
+
+void Jim_InitStack(Jim_Stack *stack)
+{
+ stack->len = 0;
+ stack->maxlen = 0;
+ stack->vector = NULL;
+}
+
+void Jim_FreeStack(Jim_Stack *stack)
+{
+ Jim_Free(stack->vector);
+}
+
+int Jim_StackLen(Jim_Stack *stack)
+{
+ return stack->len;
+}
+
+void Jim_StackPush(Jim_Stack *stack, void *element)
+{
+ int neededLen = stack->len + 1;
+
+ if (neededLen > stack->maxlen) {
+ stack->maxlen = neededLen < 20 ? 20 : neededLen * 2;
+ stack->vector = Jim_Realloc(stack->vector, sizeof(void *) * stack->maxlen);
+ }
+ stack->vector[stack->len] = element;
+ stack->len++;
+}
+
+void *Jim_StackPop(Jim_Stack *stack)
+{
+ if (stack->len == 0)
+ return NULL;
+ stack->len--;
+ return stack->vector[stack->len];
+}
+
+void *Jim_StackPeek(Jim_Stack *stack)
+{
+ if (stack->len == 0)
+ return NULL;
+ return stack->vector[stack->len - 1];
+}
+
+void Jim_FreeStackElements(Jim_Stack *stack, void (*freeFunc) (void *ptr))
+{
+ int i;
+
+ for (i = 0; i < stack->len; i++)
+ freeFunc(stack->vector[i]);
+}
+
+
+
+#define JIM_TT_NONE 0
+#define JIM_TT_STR 1
+#define JIM_TT_ESC 2
+#define JIM_TT_VAR 3
+#define JIM_TT_DICTSUGAR 4
+#define JIM_TT_CMD 5
+
+#define JIM_TT_SEP 6
+#define JIM_TT_EOL 7
+#define JIM_TT_EOF 8
+
+#define JIM_TT_LINE 9
+#define JIM_TT_WORD 10
+
+
+#define JIM_TT_SUBEXPR_START 11
+#define JIM_TT_SUBEXPR_END 12
+#define JIM_TT_SUBEXPR_COMMA 13
+#define JIM_TT_EXPR_INT 14
+#define JIM_TT_EXPR_DOUBLE 15
+
+#define JIM_TT_EXPRSUGAR 16
+
+
+#define JIM_TT_EXPR_OP 20
+
+#define TOKEN_IS_SEP(type) (type >= JIM_TT_SEP && type <= JIM_TT_EOF)
+
+
+#define JIM_PS_DEF 0
+#define JIM_PS_QUOTE 1
+#define JIM_PS_DICTSUGAR 2
+
+struct JimParserCtx
+{
+ const char *p;
+ int len;
+ int linenr;
+ const char *tstart;
+ const char *tend;
+ int tline;
+ int tt;
+ int eof;
+ int state;
+ int comment;
+ char missing;
+ int missingline;
+};
+
+struct JimParseResult {
+ char missing;
+ int line;
+};
+
+static int JimParseScript(struct JimParserCtx *pc);
+static int JimParseSep(struct JimParserCtx *pc);
+static int JimParseEol(struct JimParserCtx *pc);
+static int JimParseCmd(struct JimParserCtx *pc);
+static int JimParseQuote(struct JimParserCtx *pc);
+static int JimParseVar(struct JimParserCtx *pc);
+static int JimParseBrace(struct JimParserCtx *pc);
+static int JimParseStr(struct JimParserCtx *pc);
+static int JimParseComment(struct JimParserCtx *pc);
+static void JimParseSubCmd(struct JimParserCtx *pc);
+static int JimParseSubQuote(struct JimParserCtx *pc);
+static void JimParseSubCmd(struct JimParserCtx *pc);
+static Jim_Obj *JimParserGetTokenObj(Jim_Interp *interp, struct JimParserCtx *pc);
+
+static void JimParserInit(struct JimParserCtx *pc, const char *prg, int len, int linenr)
+{
+ pc->p = prg;
+ pc->len = len;
+ pc->tstart = NULL;
+ pc->tend = NULL;
+ pc->tline = 0;
+ pc->tt = JIM_TT_NONE;
+ pc->eof = 0;
+ pc->state = JIM_PS_DEF;
+ pc->linenr = linenr;
+ pc->comment = 1;
+ pc->missing = ' ';
+ pc->missingline = linenr;
+}
+
+static int JimParseScript(struct JimParserCtx *pc)
+{
+ while (1) {
+ if (!pc->len) {
+ pc->tstart = pc->p;
+ pc->tend = pc->p - 1;
+ pc->tline = pc->linenr;
+ pc->tt = JIM_TT_EOL;
+ pc->eof = 1;
+ return JIM_OK;
+ }
+ switch (*(pc->p)) {
+ case '\\':
+ if (*(pc->p + 1) == '\n' && pc->state == JIM_PS_DEF) {
+ return JimParseSep(pc);
+ }
+ pc->comment = 0;
+ return JimParseStr(pc);
+ case ' ':
+ case '\t':
+ case '\r':
+ case '\f':
+ if (pc->state == JIM_PS_DEF)
+ return JimParseSep(pc);
+ pc->comment = 0;
+ return JimParseStr(pc);
+ case '\n':
+ case ';':
+ pc->comment = 1;
+ if (pc->state == JIM_PS_DEF)
+ return JimParseEol(pc);
+ return JimParseStr(pc);
+ case '[':
+ pc->comment = 0;
+ return JimParseCmd(pc);
+ case '$':
+ pc->comment = 0;
+ if (JimParseVar(pc) == JIM_ERR) {
+
+ pc->tstart = pc->tend = pc->p++;
+ pc->len--;
+ pc->tt = JIM_TT_ESC;
+ }
+ return JIM_OK;
+ case '#':
+ if (pc->comment) {
+ JimParseComment(pc);
+ continue;
+ }
+ return JimParseStr(pc);
+ default:
+ pc->comment = 0;
+ return JimParseStr(pc);
+ }
+ return JIM_OK;
+ }
+}
+
+static int JimParseSep(struct JimParserCtx *pc)
+{
+ pc->tstart = pc->p;
+ pc->tline = pc->linenr;
+ while (isspace(UCHAR(*pc->p)) || (*pc->p == '\\' && *(pc->p + 1) == '\n')) {
+ if (*pc->p == '\n') {
+ break;
+ }
+ if (*pc->p == '\\') {
+ pc->p++;
+ pc->len--;
+ pc->linenr++;
+ }
+ pc->p++;
+ pc->len--;
+ }
+ pc->tend = pc->p - 1;
+ pc->tt = JIM_TT_SEP;
+ return JIM_OK;
+}
+
+static int JimParseEol(struct JimParserCtx *pc)
+{
+ pc->tstart = pc->p;
+ pc->tline = pc->linenr;
+ while (isspace(UCHAR(*pc->p)) || *pc->p == ';') {
+ if (*pc->p == '\n')
+ pc->linenr++;
+ pc->p++;
+ pc->len--;
+ }
+ pc->tend = pc->p - 1;
+ pc->tt = JIM_TT_EOL;
+ return JIM_OK;
+}
+
+
+static void JimParseSubBrace(struct JimParserCtx *pc)
+{
+ int level = 1;
+
+
+ pc->p++;
+ pc->len--;
+ while (pc->len) {
+ switch (*pc->p) {
+ case '\\':
+ if (pc->len > 1) {
+ if (*++pc->p == '\n') {
+ pc->linenr++;
+ }
+ pc->len--;
+ }
+ break;
+
+ case '{':
+ level++;
+ break;
+
+ case '}':
+ if (--level == 0) {
+ pc->tend = pc->p - 1;
+ pc->p++;
+ pc->len--;
+ return;
+ }
+ break;
+
+ case '\n':
+ pc->linenr++;
+ break;
+ }
+ pc->p++;
+ pc->len--;
+ }
+ pc->missing = '{';
+ pc->missingline = pc->tline;
+ pc->tend = pc->p - 1;
+}
+
+static int JimParseSubQuote(struct JimParserCtx *pc)
+{
+ int tt = JIM_TT_STR;
+ int line = pc->tline;
+
+
+ pc->p++;
+ pc->len--;
+ while (pc->len) {
+ switch (*pc->p) {
+ case '\\':
+ if (pc->len > 1) {
+ if (*++pc->p == '\n') {
+ pc->linenr++;
+ }
+ pc->len--;
+ tt = JIM_TT_ESC;
+ }
+ break;
+
+ case '"':
+ pc->tend = pc->p - 1;
+ pc->p++;
+ pc->len--;
+ return tt;
+
+ case '[':
+ JimParseSubCmd(pc);
+ tt = JIM_TT_ESC;
+ continue;
+
+ case '\n':
+ pc->linenr++;
+ break;
+
+ case '$':
+ tt = JIM_TT_ESC;
+ break;
+ }
+ pc->p++;
+ pc->len--;
+ }
+ pc->missing = '"';
+ pc->missingline = line;
+ pc->tend = pc->p - 1;
+ return tt;
+}
+
+static void JimParseSubCmd(struct JimParserCtx *pc)
+{
+ int level = 1;
+ int startofword = 1;
+ int line = pc->tline;
+
+
+ pc->p++;
+ pc->len--;
+ while (pc->len) {
+ switch (*pc->p) {
+ case '\\':
+ if (pc->len > 1) {
+ if (*++pc->p == '\n') {
+ pc->linenr++;
+ }
+ pc->len--;
+ }
+ break;
+
+ case '[':
+ level++;
+ break;
+
+ case ']':
+ if (--level == 0) {
+ pc->tend = pc->p - 1;
+ pc->p++;
+ pc->len--;
+ return;
+ }
+ break;
+
+ case '"':
+ if (startofword) {
+ JimParseSubQuote(pc);
+ continue;
+ }
+ break;
+
+ case '{':
+ JimParseSubBrace(pc);
+ startofword = 0;
+ continue;
+
+ case '\n':
+ pc->linenr++;
+ break;
+ }
+ startofword = isspace(UCHAR(*pc->p));
+ pc->p++;
+ pc->len--;
+ }
+ pc->missing = '[';
+ pc->missingline = line;
+ pc->tend = pc->p - 1;
+}
+
+static int JimParseBrace(struct JimParserCtx *pc)
+{
+ pc->tstart = pc->p + 1;
+ pc->tline = pc->linenr;
+ pc->tt = JIM_TT_STR;
+ JimParseSubBrace(pc);
+ return JIM_OK;
+}
+
+static int JimParseCmd(struct JimParserCtx *pc)
+{
+ pc->tstart = pc->p + 1;
+ pc->tline = pc->linenr;
+ pc->tt = JIM_TT_CMD;
+ JimParseSubCmd(pc);
+ return JIM_OK;
+}
+
+static int JimParseQuote(struct JimParserCtx *pc)
+{
+ pc->tstart = pc->p + 1;
+ pc->tline = pc->linenr;
+ pc->tt = JimParseSubQuote(pc);
+ return JIM_OK;
+}
+
+static int JimParseVar(struct JimParserCtx *pc)
+{
+
+ pc->p++;
+ pc->len--;
+
+#ifdef EXPRSUGAR_BRACKET
+ if (*pc->p == '[') {
+
+ JimParseCmd(pc);
+ pc->tt = JIM_TT_EXPRSUGAR;
+ return JIM_OK;
+ }
+#endif
+
+ pc->tstart = pc->p;
+ pc->tt = JIM_TT_VAR;
+ pc->tline = pc->linenr;
+
+ if (*pc->p == '{') {
+ pc->tstart = ++pc->p;
+ pc->len--;
+
+ while (pc->len && *pc->p != '}') {
+ if (*pc->p == '\n') {
+ pc->linenr++;
+ }
+ pc->p++;
+ pc->len--;
+ }
+ pc->tend = pc->p - 1;
+ if (pc->len) {
+ pc->p++;
+ pc->len--;
+ }
+ }
+ else {
+ while (1) {
+
+ if (pc->p[0] == ':' && pc->p[1] == ':') {
+ while (*pc->p == ':') {
+ pc->p++;
+ pc->len--;
+ }
+ continue;
+ }
+ if (isalnum(UCHAR(*pc->p)) || *pc->p == '_' || UCHAR(*pc->p) >= 0x80) {
+ pc->p++;
+ pc->len--;
+ continue;
+ }
+ break;
+ }
+
+ if (*pc->p == '(') {
+ int count = 1;
+ const char *paren = NULL;
+
+ pc->tt = JIM_TT_DICTSUGAR;
+
+ while (count && pc->len) {
+ pc->p++;
+ pc->len--;
+ if (*pc->p == '\\' && pc->len >= 1) {
+ pc->p++;
+ pc->len--;
+ }
+ else if (*pc->p == '(') {
+ count++;
+ }
+ else if (*pc->p == ')') {
+ paren = pc->p;
+ count--;
+ }
+ }
+ if (count == 0) {
+ pc->p++;
+ pc->len--;
+ }
+ else if (paren) {
+
+ paren++;
+ pc->len += (pc->p - paren);
+ pc->p = paren;
+ }
+#ifndef EXPRSUGAR_BRACKET
+ if (*pc->tstart == '(') {
+ pc->tt = JIM_TT_EXPRSUGAR;
+ }
+#endif
+ }
+ pc->tend = pc->p - 1;
+ }
+ if (pc->tstart == pc->p) {
+ pc->p--;
+ pc->len++;
+ return JIM_ERR;
+ }
+ return JIM_OK;
+}
+
+static int JimParseStr(struct JimParserCtx *pc)
+{
+ if (pc->tt == JIM_TT_SEP || pc->tt == JIM_TT_EOL ||
+ pc->tt == JIM_TT_NONE || pc->tt == JIM_TT_STR) {
+
+ if (*pc->p == '{') {
+ return JimParseBrace(pc);
+ }
+ if (*pc->p == '"') {
+ pc->state = JIM_PS_QUOTE;
+ pc->p++;
+ pc->len--;
+
+ pc->missingline = pc->tline;
+ }
+ }
+ pc->tstart = pc->p;
+ pc->tline = pc->linenr;
+ while (1) {
+ if (pc->len == 0) {
+ if (pc->state == JIM_PS_QUOTE) {
+ pc->missing = '"';
+ }
+ pc->tend = pc->p - 1;
+ pc->tt = JIM_TT_ESC;
+ return JIM_OK;
+ }
+ switch (*pc->p) {
+ case '\\':
+ if (pc->state == JIM_PS_DEF && *(pc->p + 1) == '\n') {
+ pc->tend = pc->p - 1;
+ pc->tt = JIM_TT_ESC;
+ return JIM_OK;
+ }
+ if (pc->len >= 2) {
+ if (*(pc->p + 1) == '\n') {
+ pc->linenr++;
+ }
+ pc->p++;
+ pc->len--;
+ }
+ break;
+ case '(':
+
+ if (pc->len > 1 && pc->p[1] != '$') {
+ break;
+ }
+ case ')':
+
+ if (*pc->p == '(' || pc->tt == JIM_TT_VAR) {
+ if (pc->p == pc->tstart) {
+
+ pc->p++;
+ pc->len--;
+ }
+ pc->tend = pc->p - 1;
+ pc->tt = JIM_TT_ESC;
+ return JIM_OK;
+ }
+ break;
+
+ case '$':
+ case '[':
+ pc->tend = pc->p - 1;
+ pc->tt = JIM_TT_ESC;
+ return JIM_OK;
+ case ' ':
+ case '\t':
+ case '\n':
+ case '\r':
+ case '\f':
+ case ';':
+ if (pc->state == JIM_PS_DEF) {
+ pc->tend = pc->p - 1;
+ pc->tt = JIM_TT_ESC;
+ return JIM_OK;
+ }
+ else if (*pc->p == '\n') {
+ pc->linenr++;
+ }
+ break;
+ case '"':
+ if (pc->state == JIM_PS_QUOTE) {
+ pc->tend = pc->p - 1;
+ pc->tt = JIM_TT_ESC;
+ pc->p++;
+ pc->len--;
+ pc->state = JIM_PS_DEF;
+ return JIM_OK;
+ }
+ break;
+ }
+ pc->p++;
+ pc->len--;
+ }
+ return JIM_OK;
+}
+
+static int JimParseComment(struct JimParserCtx *pc)
+{
+ while (*pc->p) {
+ if (*pc->p == '\n') {
+ pc->linenr++;
+ if (*(pc->p - 1) != '\\') {
+ pc->p++;
+ pc->len--;
+ return JIM_OK;
+ }
+ }
+ pc->p++;
+ pc->len--;
+ }
+ return JIM_OK;
+}
+
+
+static int xdigitval(int c)
+{
+ if (c >= '0' && c <= '9')
+ return c - '0';
+ if (c >= 'a' && c <= 'f')
+ return c - 'a' + 10;
+ if (c >= 'A' && c <= 'F')
+ return c - 'A' + 10;
+ return -1;
+}
+
+static int odigitval(int c)
+{
+ if (c >= '0' && c <= '7')
+ return c - '0';
+ return -1;
+}
+
+static int JimEscape(char *dest, const char *s, int slen)
+{
+ char *p = dest;
+ int i, len;
+
+ if (slen == -1)
+ slen = strlen(s);
+
+ for (i = 0; i < slen; i++) {
+ switch (s[i]) {
+ case '\\':
+ switch (s[i + 1]) {
+ case 'a':
+ *p++ = 0x7;
+ i++;
+ break;
+ case 'b':
+ *p++ = 0x8;
+ i++;
+ break;
+ case 'f':
+ *p++ = 0xc;
+ i++;
+ break;
+ case 'n':
+ *p++ = 0xa;
+ i++;
+ break;
+ case 'r':
+ *p++ = 0xd;
+ i++;
+ break;
+ case 't':
+ *p++ = 0x9;
+ i++;
+ break;
+ case 'u':
+ case 'U':
+ case 'x':
+ {
+ unsigned val = 0;
+ int k;
+ int maxchars = 2;
+
+ i++;
+
+ if (s[i] == 'U') {
+ maxchars = 8;
+ }
+ else if (s[i] == 'u') {
+ if (s[i + 1] == '{') {
+ maxchars = 6;
+ i++;
+ }
+ else {
+ maxchars = 4;
+ }
+ }
+
+ for (k = 0; k < maxchars; k++) {
+ int c = xdigitval(s[i + k + 1]);
+ if (c == -1) {
+ break;
+ }
+ val = (val << 4) | c;
+ }
+
+ if (s[i] == '{') {
+ if (k == 0 || val > 0x1fffff || s[i + k + 1] != '}') {
+
+ i--;
+ k = 0;
+ }
+ else {
+
+ k++;
+ }
+ }
+ if (k) {
+
+ if (s[i] == 'x') {
+ *p++ = val;
+ }
+ else {
+ p += utf8_fromunicode(p, val);
+ }
+ i += k;
+ break;
+ }
+
+ *p++ = s[i];
+ }
+ break;
+ case 'v':
+ *p++ = 0xb;
+ i++;
+ break;
+ case '\0':
+ *p++ = '\\';
+ i++;
+ break;
+ case '\n':
+
+ *p++ = ' ';
+ do {
+ i++;
+ } while (s[i + 1] == ' ' || s[i + 1] == '\t');
+ break;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+
+ {
+ int val = 0;
+ int c = odigitval(s[i + 1]);
+
+ val = c;
+ c = odigitval(s[i + 2]);
+ if (c == -1) {
+ *p++ = val;
+ i++;
+ break;
+ }
+ val = (val * 8) + c;
+ c = odigitval(s[i + 3]);
+ if (c == -1) {
+ *p++ = val;
+ i += 2;
+ break;
+ }
+ val = (val * 8) + c;
+ *p++ = val;
+ i += 3;
+ }
+ break;
+ default:
+ *p++ = s[i + 1];
+ i++;
+ break;
+ }
+ break;
+ default:
+ *p++ = s[i];
+ break;
+ }
+ }
+ len = p - dest;
+ *p = '\0';
+ return len;
+}
+
+static Jim_Obj *JimParserGetTokenObj(Jim_Interp *interp, struct JimParserCtx *pc)
+{
+ const char *start, *end;
+ char *token;
+ int len;
+
+ start = pc->tstart;
+ end = pc->tend;
+ if (start > end) {
+ len = 0;
+ token = Jim_Alloc(1);
+ token[0] = '\0';
+ }
+ else {
+ len = (end - start) + 1;
+ token = Jim_Alloc(len + 1);
+ if (pc->tt != JIM_TT_ESC) {
+
+ memcpy(token, start, len);
+ token[len] = '\0';
+ }
+ else {
+
+ len = JimEscape(token, start, len);
+ }
+ }
+
+ return Jim_NewStringObjNoAlloc(interp, token, len);
+}
+
+int Jim_ScriptIsComplete(const char *s, int len, char *stateCharPtr)
+{
+ struct JimParserCtx parser;
+
+ JimParserInit(&parser, s, len, 1);
+ while (!parser.eof) {
+ JimParseScript(&parser);
+ }
+ if (stateCharPtr) {
+ *stateCharPtr = parser.missing;
+ }
+ return parser.missing == ' ';
+}
+
+static int JimParseListSep(struct JimParserCtx *pc);
+static int JimParseListStr(struct JimParserCtx *pc);
+static int JimParseListQuote(struct JimParserCtx *pc);
+
+static int JimParseList(struct JimParserCtx *pc)
+{
+ if (isspace(UCHAR(*pc->p))) {
+ return JimParseListSep(pc);
+ }
+ switch (*pc->p) {
+ case '"':
+ return JimParseListQuote(pc);
+
+ case '{':
+ return JimParseBrace(pc);
+
+ default:
+ if (pc->len) {
+ return JimParseListStr(pc);
+ }
+ break;
+ }
+
+ pc->tstart = pc->tend = pc->p;
+ pc->tline = pc->linenr;
+ pc->tt = JIM_TT_EOL;
+ pc->eof = 1;
+ return JIM_OK;
+}
+
+static int JimParseListSep(struct JimParserCtx *pc)
+{
+ pc->tstart = pc->p;
+ pc->tline = pc->linenr;
+ while (isspace(UCHAR(*pc->p))) {
+ if (*pc->p == '\n') {
+ pc->linenr++;
+ }
+ pc->p++;
+ pc->len--;
+ }
+ pc->tend = pc->p - 1;
+ pc->tt = JIM_TT_SEP;
+ return JIM_OK;
+}
+
+static int JimParseListQuote(struct JimParserCtx *pc)
+{
+ pc->p++;
+ pc->len--;
+
+ pc->tstart = pc->p;
+ pc->tline = pc->linenr;
+ pc->tt = JIM_TT_STR;
+
+ while (pc->len) {
+ switch (*pc->p) {
+ case '\\':
+ pc->tt = JIM_TT_ESC;
+ if (--pc->len == 0) {
+
+ pc->tend = pc->p;
+ return JIM_OK;
+ }
+ pc->p++;
+ break;
+ case '\n':
+ pc->linenr++;
+ break;
+ case '"':
+ pc->tend = pc->p - 1;
+ pc->p++;
+ pc->len--;
+ return JIM_OK;
+ }
+ pc->p++;
+ pc->len--;
+ }
+
+ pc->tend = pc->p - 1;
+ return JIM_OK;
+}
+
+static int JimParseListStr(struct JimParserCtx *pc)
+{
+ pc->tstart = pc->p;
+ pc->tline = pc->linenr;
+ pc->tt = JIM_TT_STR;
+
+ while (pc->len) {
+ if (isspace(UCHAR(*pc->p))) {
+ pc->tend = pc->p - 1;
+ return JIM_OK;
+ }
+ if (*pc->p == '\\') {
+ if (--pc->len == 0) {
+
+ pc->tend = pc->p;
+ return JIM_OK;
+ }
+ pc->tt = JIM_TT_ESC;
+ pc->p++;
+ }
+ pc->p++;
+ pc->len--;
+ }
+ pc->tend = pc->p - 1;
+ return JIM_OK;
+}
+
+
+
+Jim_Obj *Jim_NewObj(Jim_Interp *interp)
+{
+ Jim_Obj *objPtr;
+
+
+ if (interp->freeList != NULL) {
+
+ objPtr = interp->freeList;
+ interp->freeList = objPtr->nextObjPtr;
+ }
+ else {
+
+ objPtr = Jim_Alloc(sizeof(*objPtr));
+ }
+
+ objPtr->refCount = 0;
+
+
+ objPtr->prevObjPtr = NULL;
+ objPtr->nextObjPtr = interp->liveList;
+ if (interp->liveList)
+ interp->liveList->prevObjPtr = objPtr;
+ interp->liveList = objPtr;
+
+ return objPtr;
+}
+
+void Jim_FreeObj(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+
+ JimPanic((objPtr->refCount != 0, "!!!Object %p freed with bad refcount %d, type=%s", objPtr,
+ objPtr->refCount, objPtr->typePtr ? objPtr->typePtr->name : ""));
+
+
+ Jim_FreeIntRep(interp, objPtr);
+
+ if (objPtr->bytes != NULL) {
+ if (objPtr->bytes != JimEmptyStringRep)
+ Jim_Free(objPtr->bytes);
+ }
+
+ if (objPtr->prevObjPtr)
+ objPtr->prevObjPtr->nextObjPtr = objPtr->nextObjPtr;
+ if (objPtr->nextObjPtr)
+ objPtr->nextObjPtr->prevObjPtr = objPtr->prevObjPtr;
+ if (interp->liveList == objPtr)
+ interp->liveList = objPtr->nextObjPtr;
+
+ objPtr->prevObjPtr = NULL;
+ objPtr->nextObjPtr = interp->freeList;
+ if (interp->freeList)
+ interp->freeList->prevObjPtr = objPtr;
+ interp->freeList = objPtr;
+ objPtr->refCount = -1;
+}
+
+
+void Jim_InvalidateStringRep(Jim_Obj *objPtr)
+{
+ if (objPtr->bytes != NULL) {
+ if (objPtr->bytes != JimEmptyStringRep)
+ Jim_Free(objPtr->bytes);
+ }
+ objPtr->bytes = NULL;
+}
+
+
+Jim_Obj *Jim_DuplicateObj(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+ Jim_Obj *dupPtr;
+
+ dupPtr = Jim_NewObj(interp);
+ if (objPtr->bytes == NULL) {
+
+ dupPtr->bytes = NULL;
+ }
+ else if (objPtr->length == 0) {
+
+ dupPtr->bytes = JimEmptyStringRep;
+ dupPtr->length = 0;
+ dupPtr->typePtr = NULL;
+ return dupPtr;
+ }
+ else {
+ dupPtr->bytes = Jim_Alloc(objPtr->length + 1);
+ dupPtr->length = objPtr->length;
+
+ memcpy(dupPtr->bytes, objPtr->bytes, objPtr->length + 1);
+ }
+
+
+ dupPtr->typePtr = objPtr->typePtr;
+ if (objPtr->typePtr != NULL) {
+ if (objPtr->typePtr->dupIntRepProc == NULL) {
+ dupPtr->internalRep = objPtr->internalRep;
+ }
+ else {
+
+ objPtr->typePtr->dupIntRepProc(interp, objPtr, dupPtr);
+ }
+ }
+ return dupPtr;
+}
+
+const char *Jim_GetString(Jim_Obj *objPtr, int *lenPtr)
+{
+ if (objPtr->bytes == NULL) {
+
+ JimPanic((objPtr->typePtr->updateStringProc == NULL, "UpdateStringProc called against '%s' type.", objPtr->typePtr->name));
+ objPtr->typePtr->updateStringProc(objPtr);
+ }
+ if (lenPtr)
+ *lenPtr = objPtr->length;
+ return objPtr->bytes;
+}
+
+
+int Jim_Length(Jim_Obj *objPtr)
+{
+ if (objPtr->bytes == NULL) {
+
+ JimPanic((objPtr->typePtr->updateStringProc == NULL, "UpdateStringProc called against '%s' type.", objPtr->typePtr->name));
+ objPtr->typePtr->updateStringProc(objPtr);
+ }
+ return objPtr->length;
+}
+
+
+const char *Jim_String(Jim_Obj *objPtr)
+{
+ if (objPtr->bytes == NULL) {
+
+ JimPanic((objPtr->typePtr->updateStringProc == NULL, "UpdateStringProc called against '%s' type.", objPtr->typePtr->name));
+ objPtr->typePtr->updateStringProc(objPtr);
+ }
+ return objPtr->bytes;
+}
+
+static void FreeDictSubstInternalRep(Jim_Interp *interp, Jim_Obj *objPtr);
+static void DupDictSubstInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr);
+
+static const Jim_ObjType dictSubstObjType = {
+ "dict-substitution",
+ FreeDictSubstInternalRep,
+ DupDictSubstInternalRep,
+ NULL,
+ JIM_TYPE_NONE,
+};
+
+static void FreeInterpolatedInternalRep(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+ Jim_DecrRefCount(interp, objPtr->internalRep.dictSubstValue.indexObjPtr);
+}
+
+static const Jim_ObjType interpolatedObjType = {
+ "interpolated",
+ FreeInterpolatedInternalRep,
+ NULL,
+ NULL,
+ JIM_TYPE_NONE,
+};
+
+static void DupStringInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr);
+static int SetStringFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr);
+
+static const Jim_ObjType stringObjType = {
+ "string",
+ NULL,
+ DupStringInternalRep,
+ NULL,
+ JIM_TYPE_REFERENCES,
+};
+
+static void DupStringInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr)
+{
+ JIM_NOTUSED(interp);
+
+ dupPtr->internalRep.strValue.maxLength = srcPtr->length;
+
+ dupPtr->internalRep.strValue.charLength = srcPtr->internalRep.strValue.charLength;
+}
+
+static int SetStringFromAny(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+ if (objPtr->typePtr != &stringObjType) {
+
+ if (objPtr->bytes == NULL) {
+
+ JimPanic((objPtr->typePtr->updateStringProc == NULL, "UpdateStringProc called against '%s' type.", objPtr->typePtr->name));
+ objPtr->typePtr->updateStringProc(objPtr);
+ }
+
+ Jim_FreeIntRep(interp, objPtr);
+
+ objPtr->typePtr = &stringObjType;
+ objPtr->internalRep.strValue.maxLength = objPtr->length;
+
+ objPtr->internalRep.strValue.charLength = -1;
+ }
+ return JIM_OK;
+}
+
+int Jim_Utf8Length(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+#ifdef JIM_UTF8
+ SetStringFromAny(interp, objPtr);
+
+ if (objPtr->internalRep.strValue.charLength < 0) {
+ objPtr->internalRep.strValue.charLength = utf8_strlen(objPtr->bytes, objPtr->length);
+ }
+ return objPtr->internalRep.strValue.charLength;
+#else
+ return Jim_Length(objPtr);
+#endif
+}
+
+
+Jim_Obj *Jim_NewStringObj(Jim_Interp *interp, const char *s, int len)
+{
+ Jim_Obj *objPtr = Jim_NewObj(interp);
+
+
+ if (len == -1)
+ len = strlen(s);
+
+ if (len == 0) {
+ objPtr->bytes = JimEmptyStringRep;
+ objPtr->length = 0;
+ }
+ else {
+ objPtr->bytes = Jim_Alloc(len + 1);
+ objPtr->length = len;
+ memcpy(objPtr->bytes, s, len);
+ objPtr->bytes[len] = '\0';
+ }
+
+
+ objPtr->typePtr = NULL;
+ return objPtr;
+}
+
+
+Jim_Obj *Jim_NewStringObjUtf8(Jim_Interp *interp, const char *s, int charlen)
+{
+#ifdef JIM_UTF8
+
+ int bytelen = utf8_index(s, charlen);
+
+ Jim_Obj *objPtr = Jim_NewStringObj(interp, s, bytelen);
+
+
+ objPtr->typePtr = &stringObjType;
+ objPtr->internalRep.strValue.maxLength = bytelen;
+ objPtr->internalRep.strValue.charLength = charlen;
+
+ return objPtr;
+#else
+ return Jim_NewStringObj(interp, s, charlen);
+#endif
+}
+
+Jim_Obj *Jim_NewStringObjNoAlloc(Jim_Interp *interp, char *s, int len)
+{
+ Jim_Obj *objPtr = Jim_NewObj(interp);
+
+ objPtr->bytes = s;
+ objPtr->length = len == -1 ? strlen(s) : len;
+ objPtr->typePtr = NULL;
+ return objPtr;
+}
+
+static void StringAppendString(Jim_Obj *objPtr, const char *str, int len)
+{
+ int needlen;
+
+ if (len == -1)
+ len = strlen(str);
+ needlen = objPtr->length + len;
+ if (objPtr->internalRep.strValue.maxLength < needlen ||
+ objPtr->internalRep.strValue.maxLength == 0) {
+ needlen *= 2;
+
+ if (needlen < 7) {
+ needlen = 7;
+ }
+ if (objPtr->bytes == JimEmptyStringRep) {
+ objPtr->bytes = Jim_Alloc(needlen + 1);
+ }
+ else {
+ objPtr->bytes = Jim_Realloc(objPtr->bytes, needlen + 1);
+ }
+ objPtr->internalRep.strValue.maxLength = needlen;
+ }
+ memcpy(objPtr->bytes + objPtr->length, str, len);
+ objPtr->bytes[objPtr->length + len] = '\0';
+ if (objPtr->internalRep.strValue.charLength >= 0) {
+
+ objPtr->internalRep.strValue.charLength += utf8_strlen(objPtr->bytes + objPtr->length, len);
+ }
+ objPtr->length += len;
+}
+
+
+void Jim_AppendString(Jim_Interp *interp, Jim_Obj *objPtr, const char *str, int len)
+{
+ JimPanic((Jim_IsShared(objPtr), "Jim_AppendString called with shared object"));
+ SetStringFromAny(interp, objPtr);
+ StringAppendString(objPtr, str, len);
+}
+
+void Jim_AppendObj(Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj *appendObjPtr)
+{
+ int len;
+ const char *str;
+
+ str = Jim_GetString(appendObjPtr, &len);
+ Jim_AppendString(interp, objPtr, str, len);
+}
+
+void Jim_AppendStrings(Jim_Interp *interp, Jim_Obj *objPtr, ...)
+{
+ va_list ap;
+
+ SetStringFromAny(interp, objPtr);
+ va_start(ap, objPtr);
+ while (1) {
+ char *s = va_arg(ap, char *);
+
+ if (s == NULL)
+ break;
+ Jim_AppendString(interp, objPtr, s, -1);
+ }
+ va_end(ap);
+}
+
+int Jim_StringEqObj(Jim_Obj *aObjPtr, Jim_Obj *bObjPtr)
+{
+ const char *aStr, *bStr;
+ int aLen, bLen;
+
+ if (aObjPtr == bObjPtr)
+ return 1;
+ aStr = Jim_GetString(aObjPtr, &aLen);
+ bStr = Jim_GetString(bObjPtr, &bLen);
+ if (aLen != bLen)
+ return 0;
+ return JimStringCompare(aStr, aLen, bStr, bLen) == 0;
+}
+
+int Jim_StringMatchObj(Jim_Interp *interp, Jim_Obj *patternObjPtr, Jim_Obj *objPtr, int nocase)
+{
+ return JimGlobMatch(Jim_String(patternObjPtr), Jim_String(objPtr), nocase);
+}
+
+int Jim_StringCompareObj(Jim_Interp *interp, Jim_Obj *firstObjPtr, Jim_Obj *secondObjPtr, int nocase)
+{
+ int l1, l2;
+ const char *s1 = Jim_GetString(firstObjPtr, &l1);
+ const char *s2 = Jim_GetString(secondObjPtr, &l2);
+
+ if (nocase) {
+
+ return JimStringCompareLen(s1, s2, -1, nocase);
+ }
+ return JimStringCompare(s1, l1, s2, l2);
+}
+
+int Jim_StringCompareLenObj(Jim_Interp *interp, Jim_Obj *firstObjPtr, Jim_Obj *secondObjPtr, int nocase)
+{
+ const char *s1 = Jim_String(firstObjPtr);
+ const char *s2 = Jim_String(secondObjPtr);
+
+ return JimStringCompareLen(s1, s2, Jim_Utf8Length(interp, firstObjPtr), nocase);
+}
+
+static int JimRelToAbsIndex(int len, int idx)
+{
+ if (idx < 0)
+ return len + idx;
+ return idx;
+}
+
+static void JimRelToAbsRange(int len, int *firstPtr, int *lastPtr, int *rangeLenPtr)
+{
+ int rangeLen;
+
+ if (*firstPtr > *lastPtr) {
+ rangeLen = 0;
+ }
+ else {
+ rangeLen = *lastPtr - *firstPtr + 1;
+ if (rangeLen) {
+ if (*firstPtr < 0) {
+ rangeLen += *firstPtr;
+ *firstPtr = 0;
+ }
+ if (*lastPtr >= len) {
+ rangeLen -= (*lastPtr - (len - 1));
+ *lastPtr = len - 1;
+ }
+ }
+ }
+ if (rangeLen < 0)
+ rangeLen = 0;
+
+ *rangeLenPtr = rangeLen;
+}
+
+static int JimStringGetRange(Jim_Interp *interp, Jim_Obj *firstObjPtr, Jim_Obj *lastObjPtr,
+ int len, int *first, int *last, int *range)
+{
+ if (Jim_GetIndex(interp, firstObjPtr, first) != JIM_OK) {
+ return JIM_ERR;
+ }
+ if (Jim_GetIndex(interp, lastObjPtr, last) != JIM_OK) {
+ return JIM_ERR;
+ }
+ *first = JimRelToAbsIndex(len, *first);
+ *last = JimRelToAbsIndex(len, *last);
+ JimRelToAbsRange(len, first, last, range);
+ return JIM_OK;
+}
+
+Jim_Obj *Jim_StringByteRangeObj(Jim_Interp *interp,
+ Jim_Obj *strObjPtr, Jim_Obj *firstObjPtr, Jim_Obj *lastObjPtr)
+{
+ int first, last;
+ const char *str;
+ int rangeLen;
+ int bytelen;
+
+ str = Jim_GetString(strObjPtr, &bytelen);
+
+ if (JimStringGetRange(interp, firstObjPtr, lastObjPtr, bytelen, &first, &last, &rangeLen) != JIM_OK) {
+ return NULL;
+ }
+
+ if (first == 0 && rangeLen == bytelen) {
+ return strObjPtr;
+ }
+ return Jim_NewStringObj(interp, str + first, rangeLen);
+}
+
+Jim_Obj *Jim_StringRangeObj(Jim_Interp *interp,
+ Jim_Obj *strObjPtr, Jim_Obj *firstObjPtr, Jim_Obj *lastObjPtr)
+{
+#ifdef JIM_UTF8
+ int first, last;
+ const char *str;
+ int len, rangeLen;
+ int bytelen;
+
+ str = Jim_GetString(strObjPtr, &bytelen);
+ len = Jim_Utf8Length(interp, strObjPtr);
+
+ if (JimStringGetRange(interp, firstObjPtr, lastObjPtr, len, &first, &last, &rangeLen) != JIM_OK) {
+ return NULL;
+ }
+
+ if (first == 0 && rangeLen == len) {
+ return strObjPtr;
+ }
+ if (len == bytelen) {
+
+ return Jim_NewStringObj(interp, str + first, rangeLen);
+ }
+ return Jim_NewStringObjUtf8(interp, str + utf8_index(str, first), rangeLen);
+#else
+ return Jim_StringByteRangeObj(interp, strObjPtr, firstObjPtr, lastObjPtr);
+#endif
+}
+
+Jim_Obj *JimStringReplaceObj(Jim_Interp *interp,
+ Jim_Obj *strObjPtr, Jim_Obj *firstObjPtr, Jim_Obj *lastObjPtr, Jim_Obj *newStrObj)
+{
+ int first, last;
+ const char *str;
+ int len, rangeLen;
+ Jim_Obj *objPtr;
+
+ len = Jim_Utf8Length(interp, strObjPtr);
+
+ if (JimStringGetRange(interp, firstObjPtr, lastObjPtr, len, &first, &last, &rangeLen) != JIM_OK) {
+ return NULL;
+ }
+
+ if (last < first) {
+ return strObjPtr;
+ }
+
+ str = Jim_String(strObjPtr);
+
+
+ objPtr = Jim_NewStringObjUtf8(interp, str, first);
+
+
+ if (newStrObj) {
+ Jim_AppendObj(interp, objPtr, newStrObj);
+ }
+
+
+ Jim_AppendString(interp, objPtr, str + utf8_index(str, last + 1), len - last - 1);
+
+ return objPtr;
+}
+
+static void JimStrCopyUpperLower(char *dest, const char *str, int uc)
+{
+ while (*str) {
+ int c;
+ str += utf8_tounicode(str, &c);
+ dest += utf8_fromunicode(dest, uc ? utf8_upper(c) : utf8_lower(c));
+ }
+ *dest = 0;
+}
+
+static Jim_Obj *JimStringToLower(Jim_Interp *interp, Jim_Obj *strObjPtr)
+{
+ char *buf;
+ int len;
+ const char *str;
+
+ SetStringFromAny(interp, strObjPtr);
+
+ str = Jim_GetString(strObjPtr, &len);
+
+#ifdef JIM_UTF8
+ len *= 2;
+#endif
+ buf = Jim_Alloc(len + 1);
+ JimStrCopyUpperLower(buf, str, 0);
+ return Jim_NewStringObjNoAlloc(interp, buf, -1);
+}
+
+static Jim_Obj *JimStringToUpper(Jim_Interp *interp, Jim_Obj *strObjPtr)
+{
+ char *buf;
+ const char *str;
+ int len;
+
+ if (strObjPtr->typePtr != &stringObjType) {
+ SetStringFromAny(interp, strObjPtr);
+ }
+
+ str = Jim_GetString(strObjPtr, &len);
+
+#ifdef JIM_UTF8
+ len *= 2;
+#endif
+ buf = Jim_Alloc(len + 1);
+ JimStrCopyUpperLower(buf, str, 1);
+ return Jim_NewStringObjNoAlloc(interp, buf, -1);
+}
+
+static Jim_Obj *JimStringToTitle(Jim_Interp *interp, Jim_Obj *strObjPtr)
+{
+ char *buf, *p;
+ int len;
+ int c;
+ const char *str;
+
+ str = Jim_GetString(strObjPtr, &len);
+ if (len == 0) {
+ return strObjPtr;
+ }
+#ifdef JIM_UTF8
+ len *= 2;
+#endif
+ buf = p = Jim_Alloc(len + 1);
+
+ str += utf8_tounicode(str, &c);
+ p += utf8_fromunicode(p, utf8_title(c));
+
+ JimStrCopyUpperLower(p, str, 0);
+
+ return Jim_NewStringObjNoAlloc(interp, buf, -1);
+}
+
+static const char *utf8_memchr(const char *str, int len, int c)
+{
+#ifdef JIM_UTF8
+ while (len) {
+ int sc;
+ int n = utf8_tounicode(str, &sc);
+ if (sc == c) {
+ return str;
+ }
+ str += n;
+ len -= n;
+ }
+ return NULL;
+#else
+ return memchr(str, c, len);
+#endif
+}
+
+static const char *JimFindTrimLeft(const char *str, int len, const char *trimchars, int trimlen)
+{
+ while (len) {
+ int c;
+ int n = utf8_tounicode(str, &c);
+
+ if (utf8_memchr(trimchars, trimlen, c) == NULL) {
+
+ break;
+ }
+ str += n;
+ len -= n;
+ }
+ return str;
+}
+
+static const char *JimFindTrimRight(const char *str, int len, const char *trimchars, int trimlen)
+{
+ str += len;
+
+ while (len) {
+ int c;
+ int n = utf8_prev_len(str, len);
+
+ len -= n;
+ str -= n;
+
+ n = utf8_tounicode(str, &c);
+
+ if (utf8_memchr(trimchars, trimlen, c) == NULL) {
+ return str + n;
+ }
+ }
+
+ return NULL;
+}
+
+static const char default_trim_chars[] = " \t\n\r";
+
+static int default_trim_chars_len = sizeof(default_trim_chars);
+
+static Jim_Obj *JimStringTrimLeft(Jim_Interp *interp, Jim_Obj *strObjPtr, Jim_Obj *trimcharsObjPtr)
+{
+ int len;
+ const char *str = Jim_GetString(strObjPtr, &len);
+ const char *trimchars = default_trim_chars;
+ int trimcharslen = default_trim_chars_len;
+ const char *newstr;
+
+ if (trimcharsObjPtr) {
+ trimchars = Jim_GetString(trimcharsObjPtr, &trimcharslen);
+ }
+
+ newstr = JimFindTrimLeft(str, len, trimchars, trimcharslen);
+ if (newstr == str) {
+ return strObjPtr;
+ }
+
+ return Jim_NewStringObj(interp, newstr, len - (newstr - str));
+}
+
+static Jim_Obj *JimStringTrimRight(Jim_Interp *interp, Jim_Obj *strObjPtr, Jim_Obj *trimcharsObjPtr)
+{
+ int len;
+ const char *trimchars = default_trim_chars;
+ int trimcharslen = default_trim_chars_len;
+ const char *nontrim;
+
+ if (trimcharsObjPtr) {
+ trimchars = Jim_GetString(trimcharsObjPtr, &trimcharslen);
+ }
+
+ SetStringFromAny(interp, strObjPtr);
+
+ len = Jim_Length(strObjPtr);
+ nontrim = JimFindTrimRight(strObjPtr->bytes, len, trimchars, trimcharslen);
+
+ if (nontrim == NULL) {
+
+ return Jim_NewEmptyStringObj(interp);
+ }
+ if (nontrim == strObjPtr->bytes + len) {
+ return strObjPtr;
+ }
+
+ if (Jim_IsShared(strObjPtr)) {
+ strObjPtr = Jim_NewStringObj(interp, strObjPtr->bytes, (nontrim - strObjPtr->bytes));
+ }
+ else {
+
+ strObjPtr->bytes[nontrim - strObjPtr->bytes] = 0;
+ strObjPtr->length = (nontrim - strObjPtr->bytes);
+ }
+
+ return strObjPtr;
+}
+
+static Jim_Obj *JimStringTrim(Jim_Interp *interp, Jim_Obj *strObjPtr, Jim_Obj *trimcharsObjPtr)
+{
+
+ Jim_Obj *objPtr = JimStringTrimLeft(interp, strObjPtr, trimcharsObjPtr);
+
+
+ strObjPtr = JimStringTrimRight(interp, objPtr, trimcharsObjPtr);
+
+ if (objPtr != strObjPtr) {
+
+ Jim_IncrRefCount(objPtr);
+ Jim_DecrRefCount(interp, objPtr);
+ }
+
+ return strObjPtr;
+}
+
+
+static int JimStringIs(Jim_Interp *interp, Jim_Obj *strObjPtr, Jim_Obj *strClass, int strict)
+{
+ static const char * const strclassnames[] = {
+ "integer", "alpha", "alnum", "ascii", "digit",
+ "double", "lower", "upper", "space", "xdigit",
+ "control", "print", "graph", "punct",
+ NULL
+ };
+ enum {
+ STR_IS_INTEGER, STR_IS_ALPHA, STR_IS_ALNUM, STR_IS_ASCII, STR_IS_DIGIT,
+ STR_IS_DOUBLE, STR_IS_LOWER, STR_IS_UPPER, STR_IS_SPACE, STR_IS_XDIGIT,
+ STR_IS_CONTROL, STR_IS_PRINT, STR_IS_GRAPH, STR_IS_PUNCT
+ };
+ int strclass;
+ int len;
+ int i;
+ const char *str;
+ int (*isclassfunc)(int c) = NULL;
+
+ if (Jim_GetEnum(interp, strClass, strclassnames, &strclass, "class", JIM_ERRMSG | JIM_ENUM_ABBREV) != JIM_OK) {
+ return JIM_ERR;
+ }
+
+ str = Jim_GetString(strObjPtr, &len);
+ if (len == 0) {
+ Jim_SetResultInt(interp, !strict);
+ return JIM_OK;
+ }
+
+ switch (strclass) {
+ case STR_IS_INTEGER:
+ {
+ jim_wide w;
+ Jim_SetResultInt(interp, JimGetWideNoErr(interp, strObjPtr, &w) == JIM_OK);
+ return JIM_OK;
+ }
+
+ case STR_IS_DOUBLE:
+ {
+ double d;
+ Jim_SetResultInt(interp, Jim_GetDouble(interp, strObjPtr, &d) == JIM_OK && errno != ERANGE);
+ return JIM_OK;
+ }
+
+ case STR_IS_ALPHA: isclassfunc = isalpha; break;
+ case STR_IS_ALNUM: isclassfunc = isalnum; break;
+ case STR_IS_ASCII: isclassfunc = isascii; break;
+ case STR_IS_DIGIT: isclassfunc = isdigit; break;
+ case STR_IS_LOWER: isclassfunc = islower; break;
+ case STR_IS_UPPER: isclassfunc = isupper; break;
+ case STR_IS_SPACE: isclassfunc = isspace; break;
+ case STR_IS_XDIGIT: isclassfunc = isxdigit; break;
+ case STR_IS_CONTROL: isclassfunc = iscntrl; break;
+ case STR_IS_PRINT: isclassfunc = isprint; break;
+ case STR_IS_GRAPH: isclassfunc = isgraph; break;
+ case STR_IS_PUNCT: isclassfunc = ispunct; break;
+ default:
+ return JIM_ERR;
+ }
+
+ for (i = 0; i < len; i++) {
+ if (!isclassfunc(str[i])) {
+ Jim_SetResultInt(interp, 0);
+ return JIM_OK;
+ }
+ }
+ Jim_SetResultInt(interp, 1);
+ return JIM_OK;
+}
+
+
+
+static const Jim_ObjType comparedStringObjType = {
+ "compared-string",
+ NULL,
+ NULL,
+ NULL,
+ JIM_TYPE_REFERENCES,
+};
+
+int Jim_CompareStringImmediate(Jim_Interp *interp, Jim_Obj *objPtr, const char *str)
+{
+ if (objPtr->typePtr == &comparedStringObjType && objPtr->internalRep.ptr == str)
+ return 1;
+ else {
+ const char *objStr = Jim_String(objPtr);
+
+ if (strcmp(str, objStr) != 0)
+ return 0;
+ if (objPtr->typePtr != &comparedStringObjType) {
+ Jim_FreeIntRep(interp, objPtr);
+ objPtr->typePtr = &comparedStringObjType;
+ }
+ objPtr->internalRep.ptr = (char *)str;
+ return 1;
+ }
+}
+
+static int qsortCompareStringPointers(const void *a, const void *b)
+{
+ char *const *sa = (char *const *)a;
+ char *const *sb = (char *const *)b;
+
+ return strcmp(*sa, *sb);
+}
+
+
+
+static void FreeSourceInternalRep(Jim_Interp *interp, Jim_Obj *objPtr);
+static void DupSourceInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr);
+
+static const Jim_ObjType sourceObjType = {
+ "source",
+ FreeSourceInternalRep,
+ DupSourceInternalRep,
+ NULL,
+ JIM_TYPE_REFERENCES,
+};
+
+void FreeSourceInternalRep(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+ Jim_DecrRefCount(interp, objPtr->internalRep.sourceValue.fileNameObj);
+}
+
+void DupSourceInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr)
+{
+ dupPtr->internalRep.sourceValue = srcPtr->internalRep.sourceValue;
+ Jim_IncrRefCount(dupPtr->internalRep.sourceValue.fileNameObj);
+}
+
+static void JimSetSourceInfo(Jim_Interp *interp, Jim_Obj *objPtr,
+ Jim_Obj *fileNameObj, int lineNumber)
+{
+ JimPanic((Jim_IsShared(objPtr), "JimSetSourceInfo called with shared object"));
+ JimPanic((objPtr->typePtr == &sourceObjType, "JimSetSourceInfo called with non-source object"));
+ Jim_IncrRefCount(fileNameObj);
+ objPtr->internalRep.sourceValue.fileNameObj = fileNameObj;
+ objPtr->internalRep.sourceValue.lineNumber = lineNumber;
+ objPtr->typePtr = &sourceObjType;
+}
+
+
+static const Jim_ObjType scriptLineObjType = {
+ "scriptline",
+ NULL,
+ NULL,
+ NULL,
+ 0,
+};
+
+static Jim_Obj *JimNewScriptLineObj(Jim_Interp *interp, int argc, int line)
+{
+ Jim_Obj *objPtr;
+
+#ifdef DEBUG_SHOW_SCRIPT
+ char buf[100];
+ snprintf(buf, sizeof(buf), "line=%d, argc=%d", line, argc);
+ objPtr = Jim_NewStringObj(interp, buf, -1);
+#else
+ objPtr = Jim_NewEmptyStringObj(interp);
+#endif
+ objPtr->typePtr = &scriptLineObjType;
+ objPtr->internalRep.scriptLineValue.argc = argc;
+ objPtr->internalRep.scriptLineValue.line = line;
+
+ return objPtr;
+}
+
+#define JIM_CMDSTRUCT_EXPAND -1
+
+static void FreeScriptInternalRep(Jim_Interp *interp, Jim_Obj *objPtr);
+static void DupScriptInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr);
+static int SetScriptFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr, struct JimParseResult *result);
+
+static const Jim_ObjType scriptObjType = {
+ "script",
+ FreeScriptInternalRep,
+ DupScriptInternalRep,
+ NULL,
+ JIM_TYPE_REFERENCES,
+};
+
+typedef struct ScriptToken
+{
+ int type;
+ Jim_Obj *objPtr;
+} ScriptToken;
+
+typedef struct ScriptObj
+{
+ int len;
+ ScriptToken *token;
+ int substFlags;
+ int inUse; /* Used to share a ScriptObj. Currently
+ only used by Jim_EvalObj() as protection against
+ shimmering of the currently evaluated object. */
+ Jim_Obj *fileNameObj;
+ int firstline;
+ int linenr;
+} ScriptObj;
+
+void FreeScriptInternalRep(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+ int i;
+ struct ScriptObj *script = (void *)objPtr->internalRep.ptr;
+
+ script->inUse--;
+ if (script->inUse != 0)
+ return;
+ for (i = 0; i < script->len; i++) {
+ Jim_DecrRefCount(interp, script->token[i].objPtr);
+ }
+ Jim_Free(script->token);
+ Jim_DecrRefCount(interp, script->fileNameObj);
+ Jim_Free(script);
+}
+
+void DupScriptInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr)
+{
+ JIM_NOTUSED(interp);
+ JIM_NOTUSED(srcPtr);
+
+
+ dupPtr->typePtr = NULL;
+}
+
+typedef struct
+{
+ const char *token;
+ int len;
+ int type;
+ int line;
+} ParseToken;
+
+typedef struct
+{
+
+ ParseToken *list;
+ int size;
+ int count;
+ ParseToken static_list[20];
+} ParseTokenList;
+
+static void ScriptTokenListInit(ParseTokenList *tokenlist)
+{
+ tokenlist->list = tokenlist->static_list;
+ tokenlist->size = sizeof(tokenlist->static_list) / sizeof(ParseToken);
+ tokenlist->count = 0;
+}
+
+static void ScriptTokenListFree(ParseTokenList *tokenlist)
+{
+ if (tokenlist->list != tokenlist->static_list) {
+ Jim_Free(tokenlist->list);
+ }
+}
+
+static void ScriptAddToken(ParseTokenList *tokenlist, const char *token, int len, int type,
+ int line)
+{
+ ParseToken *t;
+
+ if (tokenlist->count == tokenlist->size) {
+
+ tokenlist->size *= 2;
+ if (tokenlist->list != tokenlist->static_list) {
+ tokenlist->list =
+ Jim_Realloc(tokenlist->list, tokenlist->size * sizeof(*tokenlist->list));
+ }
+ else {
+
+ tokenlist->list = Jim_Alloc(tokenlist->size * sizeof(*tokenlist->list));
+ memcpy(tokenlist->list, tokenlist->static_list,
+ tokenlist->count * sizeof(*tokenlist->list));
+ }
+ }
+ t = &tokenlist->list[tokenlist->count++];
+ t->token = token;
+ t->len = len;
+ t->type = type;
+ t->line = line;
+}
+
+static int JimCountWordTokens(ParseToken *t)
+{
+ int expand = 1;
+ int count = 0;
+
+
+ if (t->type == JIM_TT_STR && !TOKEN_IS_SEP(t[1].type)) {
+ if ((t->len == 1 && *t->token == '*') || (t->len == 6 && strncmp(t->token, "expand", 6) == 0)) {
+
+ expand = -1;
+ t++;
+ }
+ }
+
+
+ while (!TOKEN_IS_SEP(t->type)) {
+ t++;
+ count++;
+ }
+
+ return count * expand;
+}
+
+static Jim_Obj *JimMakeScriptObj(Jim_Interp *interp, const ParseToken *t)
+{
+ Jim_Obj *objPtr;
+
+ if (t->type == JIM_TT_ESC && memchr(t->token, '\\', t->len) != NULL) {
+
+ int len = t->len;
+ char *str = Jim_Alloc(len + 1);
+ len = JimEscape(str, t->token, len);
+ objPtr = Jim_NewStringObjNoAlloc(interp, str, len);
+ }
+ else {
+ objPtr = Jim_NewStringObj(interp, t->token, t->len);
+ }
+ return objPtr;
+}
+
+static void ScriptObjAddTokens(Jim_Interp *interp, struct ScriptObj *script,
+ ParseTokenList *tokenlist)
+{
+ int i;
+ struct ScriptToken *token;
+
+ int lineargs = 0;
+
+ ScriptToken *linefirst;
+ int count;
+ int linenr;
+
+#ifdef DEBUG_SHOW_SCRIPT_TOKENS
+ printf("==== Tokens ====\n");
+ for (i = 0; i < tokenlist->count; i++) {
+ printf("[%2d]@%d %s '%.*s'\n", i, tokenlist->list[i].line, jim_tt_name(tokenlist->list[i].type),
+ tokenlist->list[i].len, tokenlist->list[i].token);
+ }
+#endif
+
+
+ count = tokenlist->count;
+ for (i = 0; i < tokenlist->count; i++) {
+ if (tokenlist->list[i].type == JIM_TT_EOL) {
+ count++;
+ }
+ }
+ linenr = script->firstline = tokenlist->list[0].line;
+
+ token = script->token = Jim_Alloc(sizeof(ScriptToken) * count);
+
+
+ linefirst = token++;
+
+ for (i = 0; i < tokenlist->count; ) {
+
+ int wordtokens;
+
+
+ while (tokenlist->list[i].type == JIM_TT_SEP) {
+ i++;
+ }
+
+ wordtokens = JimCountWordTokens(tokenlist->list + i);
+
+ if (wordtokens == 0) {
+
+ if (lineargs) {
+ linefirst->type = JIM_TT_LINE;
+ linefirst->objPtr = JimNewScriptLineObj(interp, lineargs, linenr);
+ Jim_IncrRefCount(linefirst->objPtr);
+
+
+ lineargs = 0;
+ linefirst = token++;
+ }
+ i++;
+ continue;
+ }
+ else if (wordtokens != 1) {
+
+ token->type = JIM_TT_WORD;
+ token->objPtr = Jim_NewIntObj(interp, wordtokens);
+ Jim_IncrRefCount(token->objPtr);
+ token++;
+ if (wordtokens < 0) {
+
+ i++;
+ wordtokens = -wordtokens - 1;
+ lineargs--;
+ }
+ }
+
+ if (lineargs == 0) {
+
+ linenr = tokenlist->list[i].line;
+ }
+ lineargs++;
+
+
+ while (wordtokens--) {
+ const ParseToken *t = &tokenlist->list[i++];
+
+ token->type = t->type;
+ token->objPtr = JimMakeScriptObj(interp, t);
+ Jim_IncrRefCount(token->objPtr);
+
+ JimSetSourceInfo(interp, token->objPtr, script->fileNameObj, t->line);
+ token++;
+ }
+ }
+
+ if (lineargs == 0) {
+ token--;
+ }
+
+ script->len = token - script->token;
+
+ assert(script->len < count);
+
+#ifdef DEBUG_SHOW_SCRIPT
+ printf("==== Script (%s) ====\n", Jim_String(script->fileNameObj));
+ for (i = 0; i < script->len; i++) {
+ const ScriptToken *t = &script->token[i];
+ printf("[%2d] %s %s\n", i, jim_tt_name(t->type), Jim_String(t->objPtr));
+ }
+#endif
+
+}
+
+static void SubstObjAddTokens(Jim_Interp *interp, struct ScriptObj *script,
+ ParseTokenList *tokenlist)
+{
+ int i;
+ struct ScriptToken *token;
+
+ token = script->token = Jim_Alloc(sizeof(ScriptToken) * tokenlist->count);
+
+ for (i = 0; i < tokenlist->count; i++) {
+ const ParseToken *t = &tokenlist->list[i];
+
+
+ token->type = t->type;
+ token->objPtr = JimMakeScriptObj(interp, t);
+ Jim_IncrRefCount(token->objPtr);
+ token++;
+ }
+
+ script->len = i;
+}
+
+static int SetScriptFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr, struct JimParseResult *result)
+{
+ int scriptTextLen;
+ const char *scriptText = Jim_GetString(objPtr, &scriptTextLen);
+ struct JimParserCtx parser;
+ struct ScriptObj *script;
+ ParseTokenList tokenlist;
+ int line = 1;
+
+
+ if (objPtr->typePtr == &sourceObjType) {
+ line = objPtr->internalRep.sourceValue.lineNumber;
+ }
+
+
+ ScriptTokenListInit(&tokenlist);
+
+ JimParserInit(&parser, scriptText, scriptTextLen, line);
+ while (!parser.eof) {
+ JimParseScript(&parser);
+ ScriptAddToken(&tokenlist, parser.tstart, parser.tend - parser.tstart + 1, parser.tt,
+ parser.tline);
+ }
+ if (result && parser.missing != ' ') {
+ ScriptTokenListFree(&tokenlist);
+ result->missing = parser.missing;
+ result->line = parser.missingline;
+ return JIM_ERR;
+ }
+
+
+ ScriptAddToken(&tokenlist, scriptText + scriptTextLen, 0, JIM_TT_EOF, 0);
+
+
+ script = Jim_Alloc(sizeof(*script));
+ memset(script, 0, sizeof(*script));
+ script->inUse = 1;
+ if (objPtr->typePtr == &sourceObjType) {
+ script->fileNameObj = objPtr->internalRep.sourceValue.fileNameObj;
+ }
+ else {
+ script->fileNameObj = interp->emptyObj;
+ }
+ Jim_IncrRefCount(script->fileNameObj);
+
+ ScriptObjAddTokens(interp, script, &tokenlist);
+
+
+ ScriptTokenListFree(&tokenlist);
+
+
+ Jim_FreeIntRep(interp, objPtr);
+ Jim_SetIntRepPtr(objPtr, script);
+ objPtr->typePtr = &scriptObjType;
+
+ return JIM_OK;
+}
+
+ScriptObj *Jim_GetScript(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+ if (objPtr == interp->emptyObj) {
+
+ objPtr = interp->nullScriptObj;
+ }
+
+ if (objPtr->typePtr != &scriptObjType || ((struct ScriptObj *)Jim_GetIntRepPtr(objPtr))->substFlags) {
+ SetScriptFromAny(interp, objPtr, NULL);
+ }
+ return (ScriptObj *) Jim_GetIntRepPtr(objPtr);
+}
+
+static void JimIncrCmdRefCount(Jim_Cmd *cmdPtr)
+{
+ cmdPtr->inUse++;
+}
+
+static void JimDecrCmdRefCount(Jim_Interp *interp, Jim_Cmd *cmdPtr)
+{
+ if (--cmdPtr->inUse == 0) {
+ if (cmdPtr->isproc) {
+ Jim_DecrRefCount(interp, cmdPtr->u.proc.argListObjPtr);
+ Jim_DecrRefCount(interp, cmdPtr->u.proc.bodyObjPtr);
+ Jim_DecrRefCount(interp, cmdPtr->u.proc.nsObj);
+ if (cmdPtr->u.proc.staticVars) {
+ Jim_FreeHashTable(cmdPtr->u.proc.staticVars);
+ Jim_Free(cmdPtr->u.proc.staticVars);
+ }
+ }
+ else {
+
+ if (cmdPtr->u.native.delProc) {
+ cmdPtr->u.native.delProc(interp, cmdPtr->u.native.privData);
+ }
+ }
+ if (cmdPtr->prevCmd) {
+
+ JimDecrCmdRefCount(interp, cmdPtr->prevCmd);
+ }
+ Jim_Free(cmdPtr);
+ }
+}
+
+
+static void JimVariablesHTValDestructor(void *interp, void *val)
+{
+ Jim_DecrRefCount(interp, ((Jim_Var *)val)->objPtr);
+ Jim_Free(val);
+}
+
+static const Jim_HashTableType JimVariablesHashTableType = {
+ JimStringCopyHTHashFunction,
+ JimStringCopyHTDup,
+ NULL,
+ JimStringCopyHTKeyCompare,
+ JimStringCopyHTKeyDestructor,
+ JimVariablesHTValDestructor
+};
+
+static void JimCommandsHT_ValDestructor(void *interp, void *val)
+{
+ JimDecrCmdRefCount(interp, val);
+}
+
+static const Jim_HashTableType JimCommandsHashTableType = {
+ JimStringCopyHTHashFunction,
+ JimStringCopyHTDup,
+ NULL,
+ JimStringCopyHTKeyCompare,
+ JimStringCopyHTKeyDestructor,
+ JimCommandsHT_ValDestructor
+};
+
+
+
+#ifdef jim_ext_namespace
+static Jim_Obj *JimQualifyNameObj(Jim_Interp *interp, Jim_Obj *nsObj)
+{
+ const char *name = Jim_String(nsObj);
+ if (name[0] == ':' && name[1] == ':') {
+
+ while (*++name == ':') {
+ }
+ nsObj = Jim_NewStringObj(interp, name, -1);
+ }
+ else if (Jim_Length(interp->framePtr->nsObj)) {
+
+ nsObj = Jim_DuplicateObj(interp, interp->framePtr->nsObj);
+ Jim_AppendStrings(interp, nsObj, "::", name, NULL);
+ }
+ return nsObj;
+}
+
+static const char *JimQualifyName(Jim_Interp *interp, const char *name, Jim_Obj **objPtrPtr)
+{
+ Jim_Obj *objPtr = interp->emptyObj;
+
+ if (name[0] == ':' && name[1] == ':') {
+
+ while (*++name == ':') {
+ }
+ }
+ else if (Jim_Length(interp->framePtr->nsObj)) {
+
+ objPtr = Jim_DuplicateObj(interp, interp->framePtr->nsObj);
+ Jim_AppendStrings(interp, objPtr, "::", name, NULL);
+ name = Jim_String(objPtr);
+ }
+ Jim_IncrRefCount(objPtr);
+ *objPtrPtr = objPtr;
+ return name;
+}
+
+ #define JimFreeQualifiedName(INTERP, OBJ) Jim_DecrRefCount((INTERP), (OBJ))
+
+#else
+
+ #define JimQualifyName(INTERP, NAME, DUMMY) (((NAME)[0] == ':' && (NAME)[1] == ':') ? (NAME) + 2 : (NAME))
+ #define JimFreeQualifiedName(INTERP, DUMMY) (void)(DUMMY)
+#endif
+
+static int JimCreateCommand(Jim_Interp *interp, const char *name, Jim_Cmd *cmd)
+{
+ Jim_HashEntry *he = Jim_FindHashEntry(&interp->commands, name);
+ if (he) {
+
+ Jim_InterpIncrProcEpoch(interp);
+ }
+
+ if (he && interp->local) {
+
+ cmd->prevCmd = he->u.val;
+ he->u.val = cmd;
+ }
+ else {
+ if (he) {
+
+ Jim_DeleteHashEntry(&interp->commands, name);
+ }
+
+ Jim_AddHashEntry(&interp->commands, name, cmd);
+ }
+ return JIM_OK;
+}
+
+
+int Jim_CreateCommand(Jim_Interp *interp, const char *cmdNameStr,
+ Jim_CmdProc cmdProc, void *privData, Jim_DelCmdProc delProc)
+{
+ Jim_Cmd *cmdPtr = Jim_Alloc(sizeof(*cmdPtr));
+
+
+ memset(cmdPtr, 0, sizeof(*cmdPtr));
+ cmdPtr->inUse = 1;
+ cmdPtr->u.native.delProc = delProc;
+ cmdPtr->u.native.cmdProc = cmdProc;
+ cmdPtr->u.native.privData = privData;
+
+ JimCreateCommand(interp, cmdNameStr, cmdPtr);
+
+ return JIM_OK;
+}
+
+static int JimCreateProcedureStatics(Jim_Interp *interp, Jim_Cmd *cmdPtr, Jim_Obj *staticsListObjPtr)
+{
+ int len, i;
+
+ len = Jim_ListLength(interp, staticsListObjPtr);
+ if (len == 0) {
+ return JIM_OK;
+ }
+
+ cmdPtr->u.proc.staticVars = Jim_Alloc(sizeof(Jim_HashTable));
+ Jim_InitHashTable(cmdPtr->u.proc.staticVars, &JimVariablesHashTableType, interp);
+ for (i = 0; i < len; i++) {
+ Jim_Obj *objPtr = NULL, *initObjPtr = NULL, *nameObjPtr = NULL;
+ Jim_Var *varPtr;
+ int subLen;
+
+ Jim_ListIndex(interp, staticsListObjPtr, i, &objPtr, JIM_NONE);
+
+ subLen = Jim_ListLength(interp, objPtr);
+ if (subLen == 1 || subLen == 2) {
+ Jim_ListIndex(interp, objPtr, 0, &nameObjPtr, JIM_NONE);
+ if (subLen == 1) {
+ initObjPtr = Jim_GetVariable(interp, nameObjPtr, JIM_NONE);
+ if (initObjPtr == NULL) {
+ Jim_SetResultFormatted(interp,
+ "variable for initialization of static \"%#s\" not found in the local context",
+ nameObjPtr);
+ return JIM_ERR;
+ }
+ }
+ else {
+ Jim_ListIndex(interp, objPtr, 1, &initObjPtr, JIM_NONE);
+ }
+ if (JimValidName(interp, "static variable", nameObjPtr) != JIM_OK) {
+ return JIM_ERR;
+ }
+
+ varPtr = Jim_Alloc(sizeof(*varPtr));
+ varPtr->objPtr = initObjPtr;
+ Jim_IncrRefCount(initObjPtr);
+ varPtr->linkFramePtr = NULL;
+ if (Jim_AddHashEntry(cmdPtr->u.proc.staticVars,
+ Jim_String(nameObjPtr), varPtr) != JIM_OK) {
+ Jim_SetResultFormatted(interp,
+ "static variable name \"%#s\" duplicated in statics list", nameObjPtr);
+ Jim_DecrRefCount(interp, initObjPtr);
+ Jim_Free(varPtr);
+ return JIM_ERR;
+ }
+ }
+ else {
+ Jim_SetResultFormatted(interp, "too many fields in static specifier \"%#s\"",
+ objPtr);
+ return JIM_ERR;
+ }
+ }
+ return JIM_OK;
+}
+
+static void JimUpdateProcNamespace(Jim_Interp *interp, Jim_Cmd *cmdPtr, const char *cmdname)
+{
+#ifdef jim_ext_namespace
+ if (cmdPtr->isproc) {
+
+ const char *pt = strrchr(cmdname, ':');
+ if (pt && pt != cmdname && pt[-1] == ':') {
+ Jim_DecrRefCount(interp, cmdPtr->u.proc.nsObj);
+ cmdPtr->u.proc.nsObj = Jim_NewStringObj(interp, cmdname, pt - cmdname - 1);
+ Jim_IncrRefCount(cmdPtr->u.proc.nsObj);
+
+ if (Jim_FindHashEntry(&interp->commands, pt + 1)) {
+
+ Jim_InterpIncrProcEpoch(interp);
+ }
+ }
+ }
+#endif
+}
+
+static Jim_Cmd *JimCreateProcedureCmd(Jim_Interp *interp, Jim_Obj *argListObjPtr,
+ Jim_Obj *staticsListObjPtr, Jim_Obj *bodyObjPtr, Jim_Obj *nsObj)
+{
+ Jim_Cmd *cmdPtr;
+ int argListLen;
+ int i;
+
+ argListLen = Jim_ListLength(interp, argListObjPtr);
+
+
+ cmdPtr = Jim_Alloc(sizeof(*cmdPtr) + sizeof(struct Jim_ProcArg) * argListLen);
+ memset(cmdPtr, 0, sizeof(*cmdPtr));
+ cmdPtr->inUse = 1;
+ cmdPtr->isproc = 1;
+ cmdPtr->u.proc.argListObjPtr = argListObjPtr;
+ cmdPtr->u.proc.argListLen = argListLen;
+ cmdPtr->u.proc.bodyObjPtr = bodyObjPtr;
+ cmdPtr->u.proc.argsPos = -1;
+ cmdPtr->u.proc.arglist = (struct Jim_ProcArg *)(cmdPtr + 1);
+ cmdPtr->u.proc.nsObj = nsObj ? nsObj : interp->emptyObj;
+ Jim_IncrRefCount(argListObjPtr);
+ Jim_IncrRefCount(bodyObjPtr);
+ Jim_IncrRefCount(cmdPtr->u.proc.nsObj);
+
+
+ if (staticsListObjPtr && JimCreateProcedureStatics(interp, cmdPtr, staticsListObjPtr) != JIM_OK) {
+ goto err;
+ }
+
+
+
+ for (i = 0; i < argListLen; i++) {
+ Jim_Obj *argPtr;
+ Jim_Obj *nameObjPtr;
+ Jim_Obj *defaultObjPtr;
+ int len;
+
+
+ Jim_ListIndex(interp, argListObjPtr, i, &argPtr, JIM_NONE);
+ len = Jim_ListLength(interp, argPtr);
+ if (len == 0) {
+ Jim_SetResultString(interp, "argument with no name", -1);
+err:
+ JimDecrCmdRefCount(interp, cmdPtr);
+ return NULL;
+ }
+ if (len > 2) {
+ Jim_SetResultFormatted(interp, "too many fields in argument specifier \"%#s\"", argPtr);
+ goto err;
+ }
+
+ if (len == 2) {
+
+ Jim_ListIndex(interp, argPtr, 0, &nameObjPtr, JIM_NONE);
+ Jim_ListIndex(interp, argPtr, 1, &defaultObjPtr, JIM_NONE);
+ }
+ else {
+
+ nameObjPtr = argPtr;
+ defaultObjPtr = NULL;
+ }
+
+
+ if (Jim_CompareStringImmediate(interp, nameObjPtr, "args")) {
+ if (cmdPtr->u.proc.argsPos >= 0) {
+ Jim_SetResultString(interp, "'args' specified more than once", -1);
+ goto err;
+ }
+ cmdPtr->u.proc.argsPos = i;
+ }
+ else {
+ if (len == 2) {
+ cmdPtr->u.proc.optArity++;
+ }
+ else {
+ cmdPtr->u.proc.reqArity++;
+ }
+ }
+
+ cmdPtr->u.proc.arglist[i].nameObjPtr = nameObjPtr;
+ cmdPtr->u.proc.arglist[i].defaultObjPtr = defaultObjPtr;
+ }
+
+ return cmdPtr;
+}
+
+int Jim_DeleteCommand(Jim_Interp *interp, const char *name)
+{
+ int ret = JIM_OK;
+ Jim_Obj *qualifiedNameObj;
+ const char *qualname = JimQualifyName(interp, name, &qualifiedNameObj);
+
+ if (Jim_DeleteHashEntry(&interp->commands, qualname) == JIM_ERR) {
+ Jim_SetResultFormatted(interp, "can't delete \"%s\": command doesn't exist", name);
+ ret = JIM_ERR;
+ }
+ else {
+ Jim_InterpIncrProcEpoch(interp);
+ }
+
+ JimFreeQualifiedName(interp, qualifiedNameObj);
+
+ return ret;
+}
+
+int Jim_RenameCommand(Jim_Interp *interp, const char *oldName, const char *newName)
+{
+ int ret = JIM_ERR;
+ Jim_HashEntry *he;
+ Jim_Cmd *cmdPtr;
+ Jim_Obj *qualifiedOldNameObj;
+ Jim_Obj *qualifiedNewNameObj;
+ const char *fqold;
+ const char *fqnew;
+
+ if (newName[0] == 0) {
+ return Jim_DeleteCommand(interp, oldName);
+ }
+
+ fqold = JimQualifyName(interp, oldName, &qualifiedOldNameObj);
+ fqnew = JimQualifyName(interp, newName, &qualifiedNewNameObj);
+
+
+ he = Jim_FindHashEntry(&interp->commands, fqold);
+ if (he == NULL) {
+ Jim_SetResultFormatted(interp, "can't rename \"%s\": command doesn't exist", oldName);
+ }
+ else if (Jim_FindHashEntry(&interp->commands, fqnew)) {
+ Jim_SetResultFormatted(interp, "can't rename to \"%s\": command already exists", newName);
+ }
+ else {
+
+ cmdPtr = he->u.val;
+ JimIncrCmdRefCount(cmdPtr);
+ JimUpdateProcNamespace(interp, cmdPtr, fqnew);
+ Jim_AddHashEntry(&interp->commands, fqnew, cmdPtr);
+
+
+ Jim_DeleteHashEntry(&interp->commands, fqold);
+
+
+ Jim_InterpIncrProcEpoch(interp);
+
+ ret = JIM_OK;
+ }
+
+ JimFreeQualifiedName(interp, qualifiedOldNameObj);
+ JimFreeQualifiedName(interp, qualifiedNewNameObj);
+
+ return ret;
+}
+
+
+static void FreeCommandInternalRep(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+ Jim_DecrRefCount(interp, objPtr->internalRep.cmdValue.nsObj);
+}
+
+static void DupCommandInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr)
+{
+ dupPtr->internalRep.cmdValue = srcPtr->internalRep.cmdValue;
+ dupPtr->typePtr = srcPtr->typePtr;
+ Jim_IncrRefCount(dupPtr->internalRep.cmdValue.nsObj);
+}
+
+static const Jim_ObjType commandObjType = {
+ "command",
+ FreeCommandInternalRep,
+ DupCommandInternalRep,
+ NULL,
+ JIM_TYPE_REFERENCES,
+};
+
+Jim_Cmd *Jim_GetCommand(Jim_Interp *interp, Jim_Obj *objPtr, int flags)
+{
+ Jim_Cmd *cmd;
+
+ if (objPtr->typePtr != &commandObjType ||
+ objPtr->internalRep.cmdValue.procEpoch != interp->procEpoch
+#ifdef jim_ext_namespace
+ || !Jim_StringEqObj(objPtr->internalRep.cmdValue.nsObj, interp->framePtr->nsObj)
+#endif
+ ) {
+
+
+
+ const char *name = Jim_String(objPtr);
+ Jim_HashEntry *he;
+
+ if (name[0] == ':' && name[1] == ':') {
+ while (*++name == ':') {
+ }
+ }
+#ifdef jim_ext_namespace
+ else if (Jim_Length(interp->framePtr->nsObj)) {
+
+ Jim_Obj *nameObj = Jim_DuplicateObj(interp, interp->framePtr->nsObj);
+ Jim_AppendStrings(interp, nameObj, "::", name, NULL);
+ he = Jim_FindHashEntry(&interp->commands, Jim_String(nameObj));
+ Jim_FreeNewObj(interp, nameObj);
+ if (he) {
+ goto found;
+ }
+ }
+#endif
+
+
+ he = Jim_FindHashEntry(&interp->commands, name);
+ if (he == NULL) {
+ if (flags & JIM_ERRMSG) {
+ Jim_SetResultFormatted(interp, "invalid command name \"%#s\"", objPtr);
+ }
+ return NULL;
+ }
+#ifdef jim_ext_namespace
+found:
+#endif
+ cmd = (Jim_Cmd *)he->u.val;
+
+
+ Jim_FreeIntRep(interp, objPtr);
+ objPtr->typePtr = &commandObjType;
+ objPtr->internalRep.cmdValue.procEpoch = interp->procEpoch;
+ objPtr->internalRep.cmdValue.cmdPtr = cmd;
+ objPtr->internalRep.cmdValue.nsObj = interp->framePtr->nsObj;
+ Jim_IncrRefCount(interp->framePtr->nsObj);
+ }
+ else {
+ cmd = objPtr->internalRep.cmdValue.cmdPtr;
+ }
+ while (cmd->u.proc.upcall) {
+ cmd = cmd->prevCmd;
+ }
+ return cmd;
+}
+
+
+
+#define JIM_DICT_SUGAR 100
+
+static int SetVariableFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr);
+
+static const Jim_ObjType variableObjType = {
+ "variable",
+ NULL,
+ NULL,
+ NULL,
+ JIM_TYPE_REFERENCES,
+};
+
+static int JimValidName(Jim_Interp *interp, const char *type, Jim_Obj *nameObjPtr)
+{
+
+ if (nameObjPtr->typePtr != &variableObjType) {
+ int len;
+ const char *str = Jim_GetString(nameObjPtr, &len);
+ if (memchr(str, '\0', len)) {
+ Jim_SetResultFormatted(interp, "%s name contains embedded null", type);
+ return JIM_ERR;
+ }
+ }
+ return JIM_OK;
+}
+
+static int SetVariableFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr)
+{
+ const char *varName;
+ Jim_CallFrame *framePtr;
+ Jim_HashEntry *he;
+ int global;
+ int len;
+
+
+ if (objPtr->typePtr == &variableObjType) {
+ framePtr = objPtr->internalRep.varValue.global ? interp->topFramePtr : interp->framePtr;
+ if (objPtr->internalRep.varValue.callFrameId == framePtr->id) {
+
+ return JIM_OK;
+ }
+
+ }
+ else if (objPtr->typePtr == &dictSubstObjType) {
+ return JIM_DICT_SUGAR;
+ }
+ else if (JimValidName(interp, "variable", objPtr) != JIM_OK) {
+ return JIM_ERR;
+ }
+
+
+ varName = Jim_GetString(objPtr, &len);
+
+
+ if (len && varName[len - 1] == ')' && strchr(varName, '(') != NULL) {
+ return JIM_DICT_SUGAR;
+ }
+
+ if (varName[0] == ':' && varName[1] == ':') {
+ while (*++varName == ':') {
+ }
+ global = 1;
+ framePtr = interp->topFramePtr;
+ }
+ else {
+ global = 0;
+ framePtr = interp->framePtr;
+ }
+
+
+ he = Jim_FindHashEntry(&framePtr->vars, varName);
+ if (he == NULL) {
+ if (!global && framePtr->staticVars) {
+
+ he = Jim_FindHashEntry(framePtr->staticVars, varName);
+ }
+ if (he == NULL) {
+ return JIM_ERR;
+ }
+ }
+
+
+ Jim_FreeIntRep(interp, objPtr);
+ objPtr->typePtr = &variableObjType;
+ objPtr->internalRep.varValue.callFrameId = framePtr->id;
+ objPtr->internalRep.varValue.varPtr = he->u.val;
+ objPtr->internalRep.varValue.global = global;
+ return JIM_OK;
+}
+
+
+static int JimDictSugarSet(Jim_Interp *interp, Jim_Obj *ObjPtr, Jim_Obj *valObjPtr);
+static Jim_Obj *JimDictSugarGet(Jim_Interp *interp, Jim_Obj *ObjPtr, int flags);
+
+static Jim_Var *JimCreateVariable(Jim_Interp *interp, Jim_Obj *nameObjPtr, Jim_Obj *valObjPtr)
+{
+ const char *name;
+ Jim_CallFrame *framePtr;
+ int global;
+
+
+ Jim_Var *var = Jim_Alloc(sizeof(*var));
+
+ var->objPtr = valObjPtr;
+ Jim_IncrRefCount(valObjPtr);
+ var->linkFramePtr = NULL;
+
+ name = Jim_String(nameObjPtr);
+ if (name[0] == ':' && name[1] == ':') {
+ while (*++name == ':') {
+ }
+ framePtr = interp->topFramePtr;
+ global = 1;
+ }
+ else {
+ framePtr = interp->framePtr;
+ global = 0;
+ }
+
+
+ Jim_AddHashEntry(&framePtr->vars, name, var);
+
+
+ Jim_FreeIntRep(interp, nameObjPtr);
+ nameObjPtr->typePtr = &variableObjType;
+ nameObjPtr->internalRep.varValue.callFrameId = framePtr->id;
+ nameObjPtr->internalRep.varValue.varPtr = var;
+ nameObjPtr->internalRep.varValue.global = global;
+
+ return var;
+}
+
+
+int Jim_SetVariable(Jim_Interp *interp, Jim_Obj *nameObjPtr, Jim_Obj *valObjPtr)
+{
+ int err;
+ Jim_Var *var;
+
+ switch (SetVariableFromAny(interp, nameObjPtr)) {
+ case JIM_DICT_SUGAR:
+ return JimDictSugarSet(interp, nameObjPtr, valObjPtr);
+
+ case JIM_ERR:
+ if (JimValidName(interp, "variable", nameObjPtr) != JIM_OK) {
+ return JIM_ERR;
+ }
+ JimCreateVariable(interp, nameObjPtr, valObjPtr);
+ break;
+
+ case JIM_OK:
+ var = nameObjPtr->internalRep.varValue.varPtr;
+ if (var->linkFramePtr == NULL) {
+ Jim_IncrRefCount(valObjPtr);
+ Jim_DecrRefCount(interp, var->objPtr);
+ var->objPtr = valObjPtr;
+ }
+ else {
+ Jim_CallFrame *savedCallFrame;
+
+ savedCallFrame = interp->framePtr;
+ interp->framePtr = var->linkFramePtr;
+ err = Jim_SetVariable(interp, var->objPtr, valObjPtr);
+ interp->framePtr = savedCallFrame;
+ if (err != JIM_OK)
+ return err;
+ }
+ }
+ return JIM_OK;
+}
+
+int Jim_SetVariableStr(Jim_Interp *interp, const char *name, Jim_Obj *objPtr)
+{
+ Jim_Obj *nameObjPtr;
+ int result;
+
+ nameObjPtr = Jim_NewStringObj(interp, name, -1);
+ Jim_IncrRefCount(nameObjPtr);
+ result = Jim_SetVariable(interp, nameObjPtr, objPtr);
+ Jim_DecrRefCount(interp, nameObjPtr);
+ return result;
+}
+
+int Jim_SetGlobalVariableStr(Jim_Interp *interp, const char *name, Jim_Obj *objPtr)
+{
+ Jim_CallFrame *savedFramePtr;
+ int result;
+
+ savedFramePtr = interp->framePtr;
+ interp->framePtr = interp->topFramePtr;
+ result = Jim_SetVariableStr(interp, name, objPtr);
+ interp->framePtr = savedFramePtr;
+ return result;
+}
+
+int Jim_SetVariableStrWithStr(Jim_Interp *interp, const char *name, const char *val)
+{
+ Jim_Obj *nameObjPtr, *valObjPtr;
+ int result;
+
+ nameObjPtr = Jim_NewStringObj(interp, name, -1);
+ valObjPtr = Jim_NewStringObj(interp, val, -1);
+ Jim_IncrRefCount(nameObjPtr);
+ Jim_IncrRefCount(valObjPtr);
+ result = Jim_SetVariable(interp, nameObjPtr, valObjPtr);
+ Jim_DecrRefCount(interp, nameObjPtr);
+ Jim_DecrRefCount(interp, valObjPtr);
+ return result;
+}
+
+int Jim_SetVariableLink(Jim_Interp *interp, Jim_Obj *nameObjPtr,
+ Jim_Obj *targetNameObjPtr, Jim_CallFrame *targetCallFrame)
+{
+ const char *varName;
+ const char *targetName;
+ Jim_CallFrame *framePtr;
+ Jim_Var *varPtr;
+
+
+ switch (SetVariableFromAny(interp, nameObjPtr)) {
+ case JIM_DICT_SUGAR:
+
+ Jim_SetResultFormatted(interp, "bad variable name \"%#s\": upvar won't create a scalar variable that looks like an array element", nameObjPtr);
+ return JIM_ERR;
+
+ case JIM_OK:
+ varPtr = nameObjPtr->internalRep.varValue.varPtr;
+
+ if (varPtr->linkFramePtr == NULL) {
+ Jim_SetResultFormatted(interp, "variable \"%#s\" already exists", nameObjPtr);
+ return JIM_ERR;
+ }
+
+
+ varPtr->linkFramePtr = NULL;
+ break;
+ }
+
+
+
+ varName = Jim_String(nameObjPtr);
+
+ if (varName[0] == ':' && varName[1] == ':') {
+ while (*++varName == ':') {
+ }
+
+ framePtr = interp->topFramePtr;
+ }
+ else {
+ framePtr = interp->framePtr;
+ }
+
+ targetName = Jim_String(targetNameObjPtr);
+ if (targetName[0] == ':' && targetName[1] == ':') {
+ while (*++targetName == ':') {
+ }
+ targetNameObjPtr = Jim_NewStringObj(interp, targetName, -1);
+ targetCallFrame = interp->topFramePtr;
+ }
+ Jim_IncrRefCount(targetNameObjPtr);
+
+ if (framePtr->level < targetCallFrame->level) {
+ Jim_SetResultFormatted(interp,
+ "bad variable name \"%#s\": upvar won't create namespace variable that refers to procedure variable",
+ nameObjPtr);
+ Jim_DecrRefCount(interp, targetNameObjPtr);
+ return JIM_ERR;
+ }
+
+
+ if (framePtr == targetCallFrame) {
+ Jim_Obj *objPtr = targetNameObjPtr;
+
+
+ while (1) {
+ if (strcmp(Jim_String(objPtr), varName) == 0) {
+ Jim_SetResultString(interp, "can't upvar from variable to itself", -1);
+ Jim_DecrRefCount(interp, targetNameObjPtr);
+ return JIM_ERR;
+ }
+ if (SetVariableFromAny(interp, objPtr) != JIM_OK)
+ break;
+ varPtr = objPtr->internalRep.varValue.varPtr;
+ if (varPtr->linkFramePtr != targetCallFrame)
+ break;
+ objPtr = varPtr->objPtr;
+ }
+ }
+
+
+ Jim_SetVariable(interp, nameObjPtr, targetNameObjPtr);
+
+ nameObjPtr->internalRep.varValue.varPtr->linkFramePtr = targetCallFrame;
+ Jim_DecrRefCount(interp, targetNameObjPtr);
+ return JIM_OK;
+}
+
+Jim_Obj *Jim_GetVariable(Jim_Interp *interp, Jim_Obj *nameObjPtr, int flags)
+{
+ switch (SetVariableFromAny(interp, nameObjPtr)) {
+ case JIM_OK:{
+ Jim_Var *varPtr = nameObjPtr->internalRep.varValue.varPtr;
+
+ if (varPtr->linkFramePtr == NULL) {
+ return varPtr->objPtr;
+ }
+ else {
+ Jim_Obj *objPtr;
+
+
+ Jim_CallFrame *savedCallFrame = interp->framePtr;
+
+ interp->framePtr = varPtr->linkFramePtr;
+ objPtr = Jim_GetVariable(interp, varPtr->objPtr, flags);
+ interp->framePtr = savedCallFrame;
+ if (objPtr) {
+ return objPtr;
+ }
+
+ }
+ }
+ break;
+
+ case JIM_DICT_SUGAR:
+
+ return JimDictSugarGet(interp, nameObjPtr, flags);
+ }
+ if (flags & JIM_ERRMSG) {
+ Jim_SetResultFormatted(interp, "can't read \"%#s\": no such variable", nameObjPtr);
+ }
+ return NULL;
+}
+
+Jim_Obj *Jim_GetGlobalVariable(Jim_Interp *interp, Jim_Obj *nameObjPtr, int flags)
+{
+ Jim_CallFrame *savedFramePtr;
+ Jim_Obj *objPtr;
+
+ savedFramePtr = interp->framePtr;
+ interp->framePtr = interp->topFramePtr;
+ objPtr = Jim_GetVariable(interp, nameObjPtr, flags);
+ interp->framePtr = savedFramePtr;
+
+ return objPtr;
+}
+
+Jim_Obj *Jim_GetVariableStr(Jim_Interp *interp, const char *name, int flags)
+{
+ Jim_Obj *nameObjPtr, *varObjPtr;
+
+ nameObjPtr = Jim_NewStringObj(interp, name, -1);
+ Jim_IncrRefCount(nameObjPtr);
+ varObjPtr = Jim_GetVariable(interp, nameObjPtr, flags);
+ Jim_DecrRefCount(interp, nameObjPtr);
+ return varObjPtr;
+}
+
+Jim_Obj *Jim_GetGlobalVariableStr(Jim_Interp *interp, const char *name, int flags)
+{
+ Jim_CallFrame *savedFramePtr;
+ Jim_Obj *objPtr;
+
+ savedFramePtr = interp->framePtr;
+ interp->framePtr = interp->topFramePtr;
+ objPtr = Jim_GetVariableStr(interp, name, flags);
+ interp->framePtr = savedFramePtr;
+
+ return objPtr;
+}
+
+int Jim_UnsetVariable(Jim_Interp *interp, Jim_Obj *nameObjPtr, int flags)
+{
+ Jim_Var *varPtr;
+ int retval;
+ Jim_CallFrame *framePtr;
+
+ retval = SetVariableFromAny(interp, nameObjPtr);
+ if (retval == JIM_DICT_SUGAR) {
+
+ return JimDictSugarSet(interp, nameObjPtr, NULL);
+ }
+ else if (retval == JIM_OK) {
+ varPtr = nameObjPtr->internalRep.varValue.varPtr;
+
+
+ if (varPtr->linkFramePtr) {
+ framePtr = interp->framePtr;
+ interp->framePtr = varPtr->linkFramePtr;
+ retval = Jim_UnsetVariable(interp, varPtr->objPtr, JIM_NONE);
+ interp->framePtr = framePtr;
+ }
+ else {
+ const char *name = Jim_String(nameObjPtr);
+ if (nameObjPtr->internalRep.varValue.global) {
+ name += 2;
+ framePtr = interp->topFramePtr;
+ }
+ else {
+ framePtr = interp->framePtr;
+ }
+
+ retval = Jim_DeleteHashEntry(&framePtr->vars, name);
+ if (retval == JIM_OK) {
+
+ JimChangeCallFrameId(interp, framePtr);
+ }
+ }
+ }
+ if (retval != JIM_OK && (flags & JIM_ERRMSG)) {
+ Jim_SetResultFormatted(interp, "can't unset \"%#s\": no such variable", nameObjPtr);
+ }
+ return retval;
+}
+
+
+
+static void JimDictSugarParseVarKey(Jim_Interp *interp, Jim_Obj *objPtr,
+ Jim_Obj **varPtrPtr, Jim_Obj **keyPtrPtr)
+{
+ const char *str, *p;
+ int len, keyLen;
+ Jim_Obj *varObjPtr, *keyObjPtr;
+
+ str = Jim_GetString(objPtr, &len);
+
+ p = strchr(str, '(');
+ JimPanic((p == NULL, "JimDictSugarParseVarKey() called for non-dict-sugar (%s)", str));
+
+ varObjPtr = Jim_NewStringObj(interp, str, p - str);
+
+ p++;
+ keyLen = (str + len) - p;
+ if (str[len - 1] == ')') {
+ keyLen--;
+ }
+
+
+ keyObjPtr = Jim_NewStringObj(interp, p, keyLen);
+
+ Jim_IncrRefCount(varObjPtr);
+ Jim_IncrRefCount(keyObjPtr);
+ *varPtrPtr = varObjPtr;
+ *keyPtrPtr = keyObjPtr;
+}
+
+static int JimDictSugarSet(Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj *valObjPtr)
+{
+ int err;
+
+ SetDictSubstFromAny(interp, objPtr);
+
+ err = Jim_SetDictKeysVector(interp, objPtr->internalRep.dictSubstValue.varNameObjPtr,
+ &objPtr->internalRep.dictSubstValue.indexObjPtr, 1, valObjPtr, JIM_MUSTEXIST);
+
+ if (err == JIM_OK) {
+
+ Jim_SetEmptyResult(interp);
+ }
+ else {
+ if (!valObjPtr) {
+
+ if (Jim_GetVariable(interp, objPtr->internalRep.dictSubstValue.varNameObjPtr, JIM_NONE)) {
+ Jim_SetResultFormatted(interp, "can't unset \"%#s\": no such element in array",
+ objPtr);
+ return err;
+ }
+ }
+
+ Jim_SetResultFormatted(interp, "can't %s \"%#s\": variable isn't array",
+ (valObjPtr ? "set" : "unset"), objPtr);
+ }
+ return err;
+}
+
+static Jim_Obj *JimDictExpandArrayVariable(Jim_Interp *interp, Jim_Obj *varObjPtr,
+ Jim_Obj *keyObjPtr, int flags)
+{
+ Jim_Obj *dictObjPtr;
+ Jim_Obj *resObjPtr = NULL;
+ int ret;
+
+ dictObjPtr = Jim_GetVariable(interp, varObjPtr, JIM_ERRMSG);
+ if (!dictObjPtr) {
+ return NULL;
+ }
+
+ ret = Jim_DictKey(interp, dictObjPtr, keyObjPtr, &resObjPtr, JIM_NONE);
+ if (ret != JIM_OK) {
+ resObjPtr = NULL;
+ if (ret < 0) {
+ Jim_SetResultFormatted(interp,
+ "can't read \"%#s(%#s)\": variable isn't array", varObjPtr, keyObjPtr);
+ }
+ else {
+ Jim_SetResultFormatted(interp,
+ "can't read \"%#s(%#s)\": no such element in array", varObjPtr, keyObjPtr);
+ }
+ }
+ else if ((flags & JIM_UNSHARED) && Jim_IsShared(dictObjPtr)) {
+ dictObjPtr = Jim_DuplicateObj(interp, dictObjPtr);
+ if (Jim_SetVariable(interp, varObjPtr, dictObjPtr) != JIM_OK) {
+
+ JimPanic((1, "SetVariable failed for JIM_UNSHARED"));
+ }
+
+ Jim_DictKey(interp, dictObjPtr, keyObjPtr, &resObjPtr, JIM_NONE);
+ }
+
+ return resObjPtr;
+}
+
+
+static Jim_Obj *JimDictSugarGet(Jim_Interp *interp, Jim_Obj *objPtr, int flags)
+{
+ SetDictSubstFromAny(interp, objPtr);
+
+ return JimDictExpandArrayVariable(interp,
+ objPtr->internalRep.dictSubstValue.varNameObjPtr,
+ objPtr->internalRep.dictSubstValue.indexObjPtr, flags);
+}
+
+
+
+void FreeDictSubstInternalRep(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+ Jim_DecrRefCount(interp, objPtr->internalRep.dictSubstValue.varNameObjPtr);
+ Jim_DecrRefCount(interp, objPtr->internalRep.dictSubstValue.indexObjPtr);
+}
+
+void DupDictSubstInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr)
+{
+ JIM_NOTUSED(interp);
+
+ dupPtr->internalRep.dictSubstValue.varNameObjPtr =
+ srcPtr->internalRep.dictSubstValue.varNameObjPtr;
+ dupPtr->internalRep.dictSubstValue.indexObjPtr = srcPtr->internalRep.dictSubstValue.indexObjPtr;
+ dupPtr->typePtr = &dictSubstObjType;
+}
+
+
+static void SetDictSubstFromAny(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+ if (objPtr->typePtr != &dictSubstObjType) {
+ Jim_Obj *varObjPtr, *keyObjPtr;
+
+ if (objPtr->typePtr == &interpolatedObjType) {
+
+
+ varObjPtr = objPtr->internalRep.dictSubstValue.varNameObjPtr;
+ keyObjPtr = objPtr->internalRep.dictSubstValue.indexObjPtr;
+
+ Jim_IncrRefCount(varObjPtr);
+ Jim_IncrRefCount(keyObjPtr);
+ }
+ else {
+ JimDictSugarParseVarKey(interp, objPtr, &varObjPtr, &keyObjPtr);
+ }
+
+ Jim_FreeIntRep(interp, objPtr);
+ objPtr->typePtr = &dictSubstObjType;
+ objPtr->internalRep.dictSubstValue.varNameObjPtr = varObjPtr;
+ objPtr->internalRep.dictSubstValue.indexObjPtr = keyObjPtr;
+ }
+}
+
+static Jim_Obj *JimExpandDictSugar(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+ Jim_Obj *resObjPtr = NULL;
+ Jim_Obj *substKeyObjPtr = NULL;
+
+ SetDictSubstFromAny(interp, objPtr);
+
+ if (Jim_SubstObj(interp, objPtr->internalRep.dictSubstValue.indexObjPtr,
+ &substKeyObjPtr, JIM_NONE)
+ != JIM_OK) {
+ return NULL;
+ }
+ Jim_IncrRefCount(substKeyObjPtr);
+ resObjPtr =
+ JimDictExpandArrayVariable(interp, objPtr->internalRep.dictSubstValue.varNameObjPtr,
+ substKeyObjPtr, 0);
+ Jim_DecrRefCount(interp, substKeyObjPtr);
+
+ return resObjPtr;
+}
+
+static Jim_Obj *JimExpandExprSugar(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+ Jim_Obj *resultObjPtr;
+
+ if (Jim_EvalExpression(interp, objPtr, &resultObjPtr) == JIM_OK) {
+
+ resultObjPtr->refCount--;
+ return resultObjPtr;
+ }
+ return NULL;
+}
+
+
+static Jim_CallFrame *JimCreateCallFrame(Jim_Interp *interp, Jim_CallFrame *parent, Jim_Obj *nsObj)
+{
+ Jim_CallFrame *cf;
+
+ if (interp->freeFramesList) {
+ cf = interp->freeFramesList;
+ interp->freeFramesList = cf->next;
+ }
+ else {
+ cf = Jim_Alloc(sizeof(*cf));
+ cf->vars.table = NULL;
+ }
+
+ cf->id = interp->callFrameEpoch++;
+ cf->parent = parent;
+ cf->level = parent ? parent->level + 1 : 0;
+ cf->argv = NULL;
+ cf->argc = 0;
+ cf->procArgsObjPtr = NULL;
+ cf->procBodyObjPtr = NULL;
+ cf->next = NULL;
+ cf->staticVars = NULL;
+ cf->localCommands = NULL;
+
+ cf->nsObj = nsObj;
+ Jim_IncrRefCount(nsObj);
+ if (cf->vars.table == NULL)
+ Jim_InitHashTable(&cf->vars, &JimVariablesHashTableType, interp);
+ return cf;
+}
+
+
+static void JimChangeCallFrameId(Jim_Interp *interp, Jim_CallFrame *cf)
+{
+ cf->id = interp->callFrameEpoch++;
+}
+
+static int JimDeleteLocalProcs(Jim_Interp *interp, Jim_Stack *localCommands)
+{
+
+ if (localCommands) {
+ Jim_Obj *cmdNameObj;
+
+ while ((cmdNameObj = Jim_StackPop(localCommands)) != NULL) {
+ Jim_HashEntry *he;
+ Jim_Obj *fqObjName;
+
+ const char *fqname = JimQualifyName(interp, Jim_String(cmdNameObj), &fqObjName);
+
+ he = Jim_FindHashEntry(&interp->commands, fqname);
+
+ if (he) {
+ Jim_Cmd *cmd = he->u.val;
+ if (cmd->prevCmd) {
+ Jim_Cmd *prevCmd = cmd->prevCmd;
+ cmd->prevCmd = NULL;
+
+
+ JimDecrCmdRefCount(interp, cmd);
+
+
+ he->u.val = prevCmd;
+ }
+ else {
+ Jim_DeleteHashEntry(&interp->commands, fqname);
+ Jim_InterpIncrProcEpoch(interp);
+ }
+ }
+ Jim_DecrRefCount(interp, cmdNameObj);
+ JimFreeQualifiedName(interp, fqObjName);
+ }
+ Jim_FreeStack(localCommands);
+ Jim_Free(localCommands);
+ }
+ return JIM_OK;
+}
+
+
+#define JIM_FCF_NONE 0
+#define JIM_FCF_NOHT 1
+static void JimFreeCallFrame(Jim_Interp *interp, Jim_CallFrame *cf, int flags)
+{
+ if (cf->procArgsObjPtr)
+ Jim_DecrRefCount(interp, cf->procArgsObjPtr);
+ if (cf->procBodyObjPtr)
+ Jim_DecrRefCount(interp, cf->procBodyObjPtr);
+ Jim_DecrRefCount(interp, cf->nsObj);
+ if (!(flags & JIM_FCF_NOHT))
+ Jim_FreeHashTable(&cf->vars);
+ else {
+ int i;
+ Jim_HashEntry **table = cf->vars.table, *he;
+
+ for (i = 0; i < JIM_HT_INITIAL_SIZE; i++) {
+ he = table[i];
+ while (he != NULL) {
+ Jim_HashEntry *nextEntry = he->next;
+ Jim_Var *varPtr = (void *)he->u.val;
+
+ Jim_DecrRefCount(interp, varPtr->objPtr);
+ Jim_Free(he->u.val);
+ Jim_Free((void *)he->key);
+ Jim_Free(he);
+ table[i] = NULL;
+ he = nextEntry;
+ }
+ }
+ cf->vars.used = 0;
+ }
+
+ JimDeleteLocalProcs(interp, cf->localCommands);
+
+ cf->next = interp->freeFramesList;
+ interp->freeFramesList = cf;
+
+}
+
+
+#ifdef JIM_REFERENCES
+
+static void JimReferencesHTValDestructor(void *interp, void *val)
+{
+ Jim_Reference *refPtr = (void *)val;
+
+ Jim_DecrRefCount(interp, refPtr->objPtr);
+ if (refPtr->finalizerCmdNamePtr != NULL) {
+ Jim_DecrRefCount(interp, refPtr->finalizerCmdNamePtr);
+ }
+ Jim_Free(val);
+}
+
+static unsigned int JimReferencesHTHashFunction(const void *key)
+{
+
+ const unsigned long *widePtr = key;
+ unsigned int intValue = (unsigned int)*widePtr;
+
+ return Jim_IntHashFunction(intValue);
+}
+
+static void *JimReferencesHTKeyDup(void *privdata, const void *key)
+{
+ void *copy = Jim_Alloc(sizeof(unsigned long));
+
+ JIM_NOTUSED(privdata);
+
+ memcpy(copy, key, sizeof(unsigned long));
+ return copy;
+}
+
+static int JimReferencesHTKeyCompare(void *privdata, const void *key1, const void *key2)
+{
+ JIM_NOTUSED(privdata);
+
+ return memcmp(key1, key2, sizeof(unsigned long)) == 0;
+}
+
+static void JimReferencesHTKeyDestructor(void *privdata, void *key)
+{
+ JIM_NOTUSED(privdata);
+
+ Jim_Free(key);
+}
+
+static const Jim_HashTableType JimReferencesHashTableType = {
+ JimReferencesHTHashFunction,
+ JimReferencesHTKeyDup,
+ NULL,
+ JimReferencesHTKeyCompare,
+ JimReferencesHTKeyDestructor,
+ JimReferencesHTValDestructor
+};
+
+
+
+#define JIM_REFERENCE_SPACE (35+JIM_REFERENCE_TAGLEN)
+
+static int JimFormatReference(char *buf, Jim_Reference *refPtr, unsigned long id)
+{
+ const char *fmt = ".%020lu>";
+
+ sprintf(buf, fmt, refPtr->tag, id);
+ return JIM_REFERENCE_SPACE;
+}
+
+static void UpdateStringOfReference(struct Jim_Obj *objPtr);
+
+static const Jim_ObjType referenceObjType = {
+ "reference",
+ NULL,
+ NULL,
+ UpdateStringOfReference,
+ JIM_TYPE_REFERENCES,
+};
+
+void UpdateStringOfReference(struct Jim_Obj *objPtr)
+{
+ int len;
+ char buf[JIM_REFERENCE_SPACE + 1];
+ Jim_Reference *refPtr;
+
+ refPtr = objPtr->internalRep.refValue.refPtr;
+ len = JimFormatReference(buf, refPtr, objPtr->internalRep.refValue.id);
+ objPtr->bytes = Jim_Alloc(len + 1);
+ memcpy(objPtr->bytes, buf, len + 1);
+ objPtr->length = len;
+}
+
+static int isrefchar(int c)
+{
+ return (c == '_' || isalnum(c));
+}
+
+static int SetReferenceFromAny(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+ unsigned long value;
+ int i, len;
+ const char *str, *start, *end;
+ char refId[21];
+ Jim_Reference *refPtr;
+ Jim_HashEntry *he;
+ char *endptr;
+
+
+ str = Jim_GetString(objPtr, &len);
+
+ if (len < JIM_REFERENCE_SPACE)
+ goto badformat;
+
+ start = str;
+ end = str + len - 1;
+ while (*start == ' ')
+ start++;
+ while (*end == ' ' && end > start)
+ end--;
+ if (end - start + 1 != JIM_REFERENCE_SPACE)
+ goto badformat;
+
+ if (memcmp(start, "' || end[0] != '>')
+ goto badformat;
+
+ for (i = 0; i < JIM_REFERENCE_TAGLEN; i++) {
+ if (!isrefchar(start[12 + i]))
+ goto badformat;
+ }
+
+ memcpy(refId, start + 14 + JIM_REFERENCE_TAGLEN, 20);
+ refId[20] = '\0';
+
+ value = strtoul(refId, &endptr, 10);
+ if (JimCheckConversion(refId, endptr) != JIM_OK)
+ goto badformat;
+
+ he = Jim_FindHashEntry(&interp->references, &value);
+ if (he == NULL) {
+ Jim_SetResultFormatted(interp, "invalid reference id \"%#s\"", objPtr);
+ return JIM_ERR;
+ }
+ refPtr = he->u.val;
+
+ Jim_FreeIntRep(interp, objPtr);
+ objPtr->typePtr = &referenceObjType;
+ objPtr->internalRep.refValue.id = value;
+ objPtr->internalRep.refValue.refPtr = refPtr;
+ return JIM_OK;
+
+ badformat:
+ Jim_SetResultFormatted(interp, "expected reference but got \"%#s\"", objPtr);
+ return JIM_ERR;
+}
+
+Jim_Obj *Jim_NewReference(Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj *tagPtr, Jim_Obj *cmdNamePtr)
+{
+ struct Jim_Reference *refPtr;
+ unsigned long id;
+ Jim_Obj *refObjPtr;
+ const char *tag;
+ int tagLen, i;
+
+
+ Jim_CollectIfNeeded(interp);
+
+ refPtr = Jim_Alloc(sizeof(*refPtr));
+ refPtr->objPtr = objPtr;
+ Jim_IncrRefCount(objPtr);
+ refPtr->finalizerCmdNamePtr = cmdNamePtr;
+ if (cmdNamePtr)
+ Jim_IncrRefCount(cmdNamePtr);
+ id = interp->referenceNextId++;
+ Jim_AddHashEntry(&interp->references, &id, refPtr);
+ refObjPtr = Jim_NewObj(interp);
+ refObjPtr->typePtr = &referenceObjType;
+ refObjPtr->bytes = NULL;
+ refObjPtr->internalRep.refValue.id = id;
+ refObjPtr->internalRep.refValue.refPtr = refPtr;
+ interp->referenceNextId++;
+ tag = Jim_GetString(tagPtr, &tagLen);
+ if (tagLen > JIM_REFERENCE_TAGLEN)
+ tagLen = JIM_REFERENCE_TAGLEN;
+ for (i = 0; i < JIM_REFERENCE_TAGLEN; i++) {
+ if (i < tagLen && isrefchar(tag[i]))
+ refPtr->tag[i] = tag[i];
+ else
+ refPtr->tag[i] = '_';
+ }
+ refPtr->tag[JIM_REFERENCE_TAGLEN] = '\0';
+ return refObjPtr;
+}
+
+Jim_Reference *Jim_GetReference(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+ if (objPtr->typePtr != &referenceObjType && SetReferenceFromAny(interp, objPtr) == JIM_ERR)
+ return NULL;
+ return objPtr->internalRep.refValue.refPtr;
+}
+
+int Jim_SetFinalizer(Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj *cmdNamePtr)
+{
+ Jim_Reference *refPtr;
+
+ if ((refPtr = Jim_GetReference(interp, objPtr)) == NULL)
+ return JIM_ERR;
+ Jim_IncrRefCount(cmdNamePtr);
+ if (refPtr->finalizerCmdNamePtr)
+ Jim_DecrRefCount(interp, refPtr->finalizerCmdNamePtr);
+ refPtr->finalizerCmdNamePtr = cmdNamePtr;
+ return JIM_OK;
+}
+
+int Jim_GetFinalizer(Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj **cmdNamePtrPtr)
+{
+ Jim_Reference *refPtr;
+
+ if ((refPtr = Jim_GetReference(interp, objPtr)) == NULL)
+ return JIM_ERR;
+ *cmdNamePtrPtr = refPtr->finalizerCmdNamePtr;
+ return JIM_OK;
+}
+
+
+
+static const Jim_HashTableType JimRefMarkHashTableType = {
+ JimReferencesHTHashFunction,
+ JimReferencesHTKeyDup,
+ NULL,
+ JimReferencesHTKeyCompare,
+ JimReferencesHTKeyDestructor,
+ NULL
+};
+
+
+int Jim_Collect(Jim_Interp *interp)
+{
+ int collected = 0;
+ return collected;
+}
+
+#define JIM_COLLECT_ID_PERIOD 5000
+#define JIM_COLLECT_TIME_PERIOD 300
+
+void Jim_CollectIfNeeded(Jim_Interp *interp)
+{
+ unsigned long elapsedId;
+ int elapsedTime;
+
+ elapsedId = interp->referenceNextId - interp->lastCollectId;
+ elapsedTime = time(NULL) - interp->lastCollectTime;
+
+
+ if (elapsedId > JIM_COLLECT_ID_PERIOD || elapsedTime > JIM_COLLECT_TIME_PERIOD) {
+ Jim_Collect(interp);
+ }
+}
+#endif
+
+static int JimIsBigEndian(void)
+{
+ union {
+ unsigned short s;
+ unsigned char c[2];
+ } uval = {0x0102};
+
+ return uval.c[0] == 1;
+}
+
+
+Jim_Interp *Jim_CreateInterp(void)
+{
+ Jim_Interp *i = Jim_Alloc(sizeof(*i));
+
+ memset(i, 0, sizeof(*i));
+
+ i->maxCallFrameDepth = JIM_MAX_CALLFRAME_DEPTH;
+ i->maxEvalDepth = JIM_MAX_EVAL_DEPTH;
+ i->lastCollectTime = time(NULL);
+
+ Jim_InitHashTable(&i->commands, &JimCommandsHashTableType, i);
+#ifdef JIM_REFERENCES
+ Jim_InitHashTable(&i->references, &JimReferencesHashTableType, i);
+#endif
+ Jim_InitHashTable(&i->assocData, &JimAssocDataHashTableType, i);
+ Jim_InitHashTable(&i->packages, &JimPackageHashTableType, NULL);
+ i->emptyObj = Jim_NewEmptyStringObj(i);
+ i->trueObj = Jim_NewIntObj(i, 1);
+ i->falseObj = Jim_NewIntObj(i, 0);
+ i->framePtr = i->topFramePtr = JimCreateCallFrame(i, NULL, i->emptyObj);
+ i->errorFileNameObj = i->emptyObj;
+ i->result = i->emptyObj;
+ i->stackTrace = Jim_NewListObj(i, NULL, 0);
+ i->unknown = Jim_NewStringObj(i, "unknown", -1);
+ i->errorProc = i->emptyObj;
+ i->currentScriptObj = Jim_NewEmptyStringObj(i);
+ i->nullScriptObj = Jim_NewEmptyStringObj(i);
+ Jim_IncrRefCount(i->emptyObj);
+ Jim_IncrRefCount(i->errorFileNameObj);
+ Jim_IncrRefCount(i->result);
+ Jim_IncrRefCount(i->stackTrace);
+ Jim_IncrRefCount(i->unknown);
+ Jim_IncrRefCount(i->currentScriptObj);
+ Jim_IncrRefCount(i->nullScriptObj);
+ Jim_IncrRefCount(i->errorProc);
+ Jim_IncrRefCount(i->trueObj);
+ Jim_IncrRefCount(i->falseObj);
+
+
+ Jim_SetVariableStrWithStr(i, JIM_LIBPATH, TCL_LIBRARY);
+ Jim_SetVariableStrWithStr(i, JIM_INTERACTIVE, "0");
+
+ Jim_SetVariableStrWithStr(i, "tcl_platform(os)", TCL_PLATFORM_OS);
+ Jim_SetVariableStrWithStr(i, "tcl_platform(platform)", TCL_PLATFORM_PLATFORM);
+ Jim_SetVariableStrWithStr(i, "tcl_platform(pathSeparator)", TCL_PLATFORM_PATH_SEPARATOR);
+ Jim_SetVariableStrWithStr(i, "tcl_platform(byteOrder)", JimIsBigEndian() ? "bigEndian" : "littleEndian");
+ Jim_SetVariableStrWithStr(i, "tcl_platform(threaded)", "0");
+ Jim_SetVariableStr(i, "tcl_platform(pointerSize)", Jim_NewIntObj(i, sizeof(void *)));
+ Jim_SetVariableStr(i, "tcl_platform(wordSize)", Jim_NewIntObj(i, sizeof(jim_wide)));
+
+ return i;
+}
+
+void Jim_FreeInterp(Jim_Interp *i)
+{
+ Jim_CallFrame *cf = i->framePtr, *prevcf, *nextcf;
+ Jim_Obj *objPtr, *nextObjPtr;
+
+ Jim_DecrRefCount(i, i->emptyObj);
+ Jim_DecrRefCount(i, i->trueObj);
+ Jim_DecrRefCount(i, i->falseObj);
+ Jim_DecrRefCount(i, i->result);
+ Jim_DecrRefCount(i, i->stackTrace);
+ Jim_DecrRefCount(i, i->errorProc);
+ Jim_DecrRefCount(i, i->unknown);
+ Jim_DecrRefCount(i, i->errorFileNameObj);
+ Jim_DecrRefCount(i, i->currentScriptObj);
+ Jim_DecrRefCount(i, i->nullScriptObj);
+ Jim_FreeHashTable(&i->commands);
+#ifdef JIM_REFERENCES
+ Jim_FreeHashTable(&i->references);
+#endif
+ Jim_FreeHashTable(&i->packages);
+ Jim_Free(i->prngState);
+ Jim_FreeHashTable(&i->assocData);
+
+
+ while (cf) {
+ prevcf = cf->parent;
+ JimFreeCallFrame(i, cf, JIM_FCF_NONE);
+ cf = prevcf;
+ }
+ if (i->liveList != NULL) {
+ objPtr = i->liveList;
+
+ printf(JIM_NL "-------------------------------------" JIM_NL);
+ printf("Objects still in the free list:" JIM_NL);
+ while (objPtr) {
+ const char *type = objPtr->typePtr ? objPtr->typePtr->name : "string";
+
+ if (objPtr->bytes && strlen(objPtr->bytes) > 20) {
+ printf("%p (%d) %-10s: '%.20s...'" JIM_NL,
+ (void *)objPtr, objPtr->refCount, type, objPtr->bytes);
+ }
+ else {
+ printf("%p (%d) %-10s: '%s'" JIM_NL,
+ (void *)objPtr, objPtr->refCount, type, objPtr->bytes ? objPtr->bytes : "(null)");
+ }
+ if (objPtr->typePtr == &sourceObjType) {
+ printf("FILE %s LINE %d" JIM_NL,
+ Jim_String(objPtr->internalRep.sourceValue.fileNameObj),
+ objPtr->internalRep.sourceValue.lineNumber);
+ }
+ objPtr = objPtr->nextObjPtr;
+ }
+ printf("-------------------------------------" JIM_NL JIM_NL);
+ JimPanic((1, "Live list non empty freeing the interpreter! Leak?"));
+ }
+
+ objPtr = i->freeList;
+ while (objPtr) {
+ nextObjPtr = objPtr->nextObjPtr;
+ Jim_Free(objPtr);
+ objPtr = nextObjPtr;
+ }
+
+ cf = i->freeFramesList;
+ while (cf) {
+ nextcf = cf->next;
+ if (cf->vars.table != NULL)
+ Jim_Free(cf->vars.table);
+ Jim_Free(cf);
+ cf = nextcf;
+ }
+#ifdef jim_ext_load
+ Jim_FreeLoadHandles(i);
+#endif
+
+
+ Jim_Free(i);
+}
+
+Jim_CallFrame *Jim_GetCallFrameByLevel(Jim_Interp *interp, Jim_Obj *levelObjPtr)
+{
+ long level;
+ const char *str;
+ Jim_CallFrame *framePtr;
+
+ if (levelObjPtr) {
+ str = Jim_String(levelObjPtr);
+ if (str[0] == '#') {
+ char *endptr;
+
+ level = jim_strtol(str + 1, &endptr);
+ if (str[1] == '\0' || endptr[0] != '\0') {
+ level = -1;
+ }
+ }
+ else {
+ if (Jim_GetLong(interp, levelObjPtr, &level) != JIM_OK || level < 0) {
+ level = -1;
+ }
+ else {
+
+ level = interp->framePtr->level - level;
+ }
+ }
+ }
+ else {
+ str = "1";
+ level = interp->framePtr->level - 1;
+ }
+
+ if (level == 0) {
+ return interp->topFramePtr;
+ }
+ if (level > 0) {
+
+ for (framePtr = interp->framePtr; framePtr; framePtr = framePtr->parent) {
+ if (framePtr->level == level) {
+ return framePtr;
+ }
+ }
+ }
+
+ Jim_SetResultFormatted(interp, "bad level \"%s\"", str);
+ return NULL;
+}
+
+static Jim_CallFrame *JimGetCallFrameByInteger(Jim_Interp *interp, Jim_Obj *levelObjPtr)
+{
+ long level;
+ Jim_CallFrame *framePtr;
+
+ if (Jim_GetLong(interp, levelObjPtr, &level) == JIM_OK) {
+ if (level <= 0) {
+
+ level = interp->framePtr->level + level;
+ }
+
+ if (level == 0) {
+ return interp->topFramePtr;
+ }
+
+
+ for (framePtr = interp->framePtr; framePtr; framePtr = framePtr->parent) {
+ if (framePtr->level == level) {
+ return framePtr;
+ }
+ }
+ }
+
+ Jim_SetResultFormatted(interp, "bad level \"%#s\"", levelObjPtr);
+ return NULL;
+}
+
+static void JimResetStackTrace(Jim_Interp *interp)
+{
+ Jim_DecrRefCount(interp, interp->stackTrace);
+ interp->stackTrace = Jim_NewListObj(interp, NULL, 0);
+ Jim_IncrRefCount(interp->stackTrace);
+}
+
+static void JimSetStackTrace(Jim_Interp *interp, Jim_Obj *stackTraceObj)
+{
+ int len;
+
+
+ Jim_IncrRefCount(stackTraceObj);
+ Jim_DecrRefCount(interp, interp->stackTrace);
+ interp->stackTrace = stackTraceObj;
+ interp->errorFlag = 1;
+
+ len = Jim_ListLength(interp, interp->stackTrace);
+ if (len >= 3) {
+ Jim_Obj *filenameObj;
+
+ Jim_ListIndex(interp, interp->stackTrace, len - 2, &filenameObj, JIM_NONE);
+
+ Jim_GetString(filenameObj, &len);
+
+ if (!Jim_Length(filenameObj)) {
+ interp->addStackTrace = 1;
+ }
+ }
+}
+
+
+static void JimAppendStackTrace(Jim_Interp *interp, const char *procname,
+ Jim_Obj *fileNameObj, int linenr)
+{
+ if (strcmp(procname, "unknown") == 0) {
+ procname = "";
+ }
+ if (!*procname && !Jim_Length(fileNameObj)) {
+
+ return;
+ }
+
+ if (Jim_IsShared(interp->stackTrace)) {
+ Jim_DecrRefCount(interp, interp->stackTrace);
+ interp->stackTrace = Jim_DuplicateObj(interp, interp->stackTrace);
+ Jim_IncrRefCount(interp->stackTrace);
+ }
+
+
+ if (!*procname && Jim_Length(fileNameObj)) {
+
+ int len = Jim_ListLength(interp, interp->stackTrace);
+
+ if (len >= 3) {
+ Jim_Obj *objPtr;
+ if (Jim_ListIndex(interp, interp->stackTrace, len - 3, &objPtr, JIM_NONE) == JIM_OK && Jim_Length(objPtr)) {
+
+ if (Jim_ListIndex(interp, interp->stackTrace, len - 2, &objPtr, JIM_NONE) == JIM_OK && !Jim_Length(objPtr)) {
+
+ ListSetIndex(interp, interp->stackTrace, len - 2, fileNameObj, 0);
+ ListSetIndex(interp, interp->stackTrace, len - 1, Jim_NewIntObj(interp, linenr), 0);
+ return;
+ }
+ }
+ }
+ }
+
+ Jim_ListAppendElement(interp, interp->stackTrace, Jim_NewStringObj(interp, procname, -1));
+ Jim_ListAppendElement(interp, interp->stackTrace, fileNameObj);
+ Jim_ListAppendElement(interp, interp->stackTrace, Jim_NewIntObj(interp, linenr));
+}
+
+int Jim_SetAssocData(Jim_Interp *interp, const char *key, Jim_InterpDeleteProc * delProc,
+ void *data)
+{
+ AssocDataValue *assocEntryPtr = (AssocDataValue *) Jim_Alloc(sizeof(AssocDataValue));
+
+ assocEntryPtr->delProc = delProc;
+ assocEntryPtr->data = data;
+ return Jim_AddHashEntry(&interp->assocData, key, assocEntryPtr);
+}
+
+void *Jim_GetAssocData(Jim_Interp *interp, const char *key)
+{
+ Jim_HashEntry *entryPtr = Jim_FindHashEntry(&interp->assocData, key);
+
+ if (entryPtr != NULL) {
+ AssocDataValue *assocEntryPtr = (AssocDataValue *) entryPtr->u.val;
+
+ return assocEntryPtr->data;
+ }
+ return NULL;
+}
+
+int Jim_DeleteAssocData(Jim_Interp *interp, const char *key)
+{
+ return Jim_DeleteHashEntry(&interp->assocData, key);
+}
+
+int Jim_GetExitCode(Jim_Interp *interp)
+{
+ return interp->exitCode;
+}
+
+#define JIM_INTEGER_SPACE 24
+
+static void UpdateStringOfInt(struct Jim_Obj *objPtr);
+static int SetIntFromAny(Jim_Interp *interp, Jim_Obj *objPtr, int flags);
+
+static const Jim_ObjType intObjType = {
+ "int",
+ NULL,
+ NULL,
+ UpdateStringOfInt,
+ JIM_TYPE_NONE,
+};
+
+static const Jim_ObjType coercedDoubleObjType = {
+ "coerced-double",
+ NULL,
+ NULL,
+ UpdateStringOfInt,
+ JIM_TYPE_NONE,
+};
+
+
+void UpdateStringOfInt(struct Jim_Obj *objPtr)
+{
+ int len;
+ char buf[JIM_INTEGER_SPACE + 1];
+
+ len = Jim_WideToString(buf, JimWideValue(objPtr));
+ objPtr->bytes = Jim_Alloc(len + 1);
+ memcpy(objPtr->bytes, buf, len + 1);
+ objPtr->length = len;
+}
+
+int SetIntFromAny(Jim_Interp *interp, Jim_Obj *objPtr, int flags)
+{
+ jim_wide wideValue;
+ const char *str;
+
+ if (objPtr->typePtr == &coercedDoubleObjType) {
+
+ objPtr->typePtr = &intObjType;
+ return JIM_OK;
+ }
+
+
+ str = Jim_String(objPtr);
+
+ if (Jim_StringToWide(str, &wideValue, 0) != JIM_OK) {
+ if (flags & JIM_ERRMSG) {
+ Jim_SetResultFormatted(interp, "expected integer but got \"%#s\"", objPtr);
+ }
+ return JIM_ERR;
+ }
+ if ((wideValue == JIM_WIDE_MIN || wideValue == JIM_WIDE_MAX) && errno == ERANGE) {
+ Jim_SetResultString(interp, "Integer value too big to be represented", -1);
+ return JIM_ERR;
+ }
+
+ Jim_FreeIntRep(interp, objPtr);
+ objPtr->typePtr = &intObjType;
+ objPtr->internalRep.wideValue = wideValue;
+ return JIM_OK;
+}
+
+#ifdef JIM_OPTIMIZATION
+static int JimIsWide(Jim_Obj *objPtr)
+{
+ return objPtr->typePtr == &intObjType;
+}
+#endif
+
+int Jim_GetWide(Jim_Interp *interp, Jim_Obj *objPtr, jim_wide * widePtr)
+{
+ if (objPtr->typePtr != &intObjType && SetIntFromAny(interp, objPtr, JIM_ERRMSG) == JIM_ERR)
+ return JIM_ERR;
+ *widePtr = JimWideValue(objPtr);
+ return JIM_OK;
+}
+
+
+static int JimGetWideNoErr(Jim_Interp *interp, Jim_Obj *objPtr, jim_wide * widePtr)
+{
+ if (objPtr->typePtr != &intObjType && SetIntFromAny(interp, objPtr, JIM_NONE) == JIM_ERR)
+ return JIM_ERR;
+ *widePtr = JimWideValue(objPtr);
+ return JIM_OK;
+}
+
+int Jim_GetLong(Jim_Interp *interp, Jim_Obj *objPtr, long *longPtr)
+{
+ jim_wide wideValue;
+ int retval;
+
+ retval = Jim_GetWide(interp, objPtr, &wideValue);
+ if (retval == JIM_OK) {
+ *longPtr = (long)wideValue;
+ return JIM_OK;
+ }
+ return JIM_ERR;
+}
+
+Jim_Obj *Jim_NewIntObj(Jim_Interp *interp, jim_wide wideValue)
+{
+ Jim_Obj *objPtr;
+
+ objPtr = Jim_NewObj(interp);
+ objPtr->typePtr = &intObjType;
+ objPtr->bytes = NULL;
+ objPtr->internalRep.wideValue = wideValue;
+ return objPtr;
+}
+
+#define JIM_DOUBLE_SPACE 30
+
+static void UpdateStringOfDouble(struct Jim_Obj *objPtr);
+static int SetDoubleFromAny(Jim_Interp *interp, Jim_Obj *objPtr);
+
+static const Jim_ObjType doubleObjType = {
+ "double",
+ NULL,
+ NULL,
+ UpdateStringOfDouble,
+ JIM_TYPE_NONE,
+};
+
+void UpdateStringOfDouble(struct Jim_Obj *objPtr)
+{
+ int len;
+ char buf[JIM_DOUBLE_SPACE + 1];
+
+ len = Jim_DoubleToString(buf, objPtr->internalRep.doubleValue);
+ objPtr->bytes = Jim_Alloc(len + 1);
+ memcpy(objPtr->bytes, buf, len + 1);
+ objPtr->length = len;
+}
+
+int SetDoubleFromAny(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+ double doubleValue;
+ jim_wide wideValue;
+ const char *str;
+
+ str = Jim_String(objPtr);
+
+#ifdef HAVE_LONG_LONG
+
+#define MIN_INT_IN_DOUBLE -(1LL << 53)
+#define MAX_INT_IN_DOUBLE -(MIN_INT_IN_DOUBLE + 1)
+
+ if (objPtr->typePtr == &intObjType
+ && JimWideValue(objPtr) >= MIN_INT_IN_DOUBLE
+ && JimWideValue(objPtr) <= MAX_INT_IN_DOUBLE) {
+
+
+ objPtr->typePtr = &coercedDoubleObjType;
+ return JIM_OK;
+ }
+ else
+#endif
+ if (Jim_StringToWide(str, &wideValue, 10) == JIM_OK) {
+
+ Jim_FreeIntRep(interp, objPtr);
+ objPtr->typePtr = &coercedDoubleObjType;
+ objPtr->internalRep.wideValue = wideValue;
+ return JIM_OK;
+ }
+ else {
+
+ if (Jim_StringToDouble(str, &doubleValue) != JIM_OK) {
+ Jim_SetResultFormatted(interp, "expected number but got \"%#s\"", objPtr);
+ return JIM_ERR;
+ }
+
+ Jim_FreeIntRep(interp, objPtr);
+ }
+ objPtr->typePtr = &doubleObjType;
+ objPtr->internalRep.doubleValue = doubleValue;
+ return JIM_OK;
+}
+
+int Jim_GetDouble(Jim_Interp *interp, Jim_Obj *objPtr, double *doublePtr)
+{
+ if (objPtr->typePtr == &coercedDoubleObjType) {
+ *doublePtr = JimWideValue(objPtr);
+ return JIM_OK;
+ }
+ if (objPtr->typePtr != &doubleObjType && SetDoubleFromAny(interp, objPtr) == JIM_ERR)
+ return JIM_ERR;
+
+ if (objPtr->typePtr == &coercedDoubleObjType) {
+ *doublePtr = JimWideValue(objPtr);
+ }
+ else {
+ *doublePtr = objPtr->internalRep.doubleValue;
+ }
+ return JIM_OK;
+}
+
+Jim_Obj *Jim_NewDoubleObj(Jim_Interp *interp, double doubleValue)
+{
+ Jim_Obj *objPtr;
+
+ objPtr = Jim_NewObj(interp);
+ objPtr->typePtr = &doubleObjType;
+ objPtr->bytes = NULL;
+ objPtr->internalRep.doubleValue = doubleValue;
+ return objPtr;
+}
+
+static void ListInsertElements(Jim_Obj *listPtr, int idx, int elemc, Jim_Obj *const *elemVec);
+static void ListAppendElement(Jim_Obj *listPtr, Jim_Obj *objPtr);
+static void FreeListInternalRep(Jim_Interp *interp, Jim_Obj *objPtr);
+static void DupListInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr);
+static void UpdateStringOfList(struct Jim_Obj *objPtr);
+static int SetListFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr);
+
+static const Jim_ObjType listObjType = {
+ "list",
+ FreeListInternalRep,
+ DupListInternalRep,
+ UpdateStringOfList,
+ JIM_TYPE_NONE,
+};
+
+void FreeListInternalRep(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+ int i;
+
+ for (i = 0; i < objPtr->internalRep.listValue.len; i++) {
+ Jim_DecrRefCount(interp, objPtr->internalRep.listValue.ele[i]);
+ }
+ Jim_Free(objPtr->internalRep.listValue.ele);
+}
+
+void DupListInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr)
+{
+ int i;
+
+ JIM_NOTUSED(interp);
+
+ dupPtr->internalRep.listValue.len = srcPtr->internalRep.listValue.len;
+ dupPtr->internalRep.listValue.maxLen = srcPtr->internalRep.listValue.maxLen;
+ dupPtr->internalRep.listValue.ele =
+ Jim_Alloc(sizeof(Jim_Obj *) * srcPtr->internalRep.listValue.maxLen);
+ memcpy(dupPtr->internalRep.listValue.ele, srcPtr->internalRep.listValue.ele,
+ sizeof(Jim_Obj *) * srcPtr->internalRep.listValue.len);
+ for (i = 0; i < dupPtr->internalRep.listValue.len; i++) {
+ Jim_IncrRefCount(dupPtr->internalRep.listValue.ele[i]);
+ }
+ dupPtr->typePtr = &listObjType;
+}
+
+#define JIM_ELESTR_SIMPLE 0
+#define JIM_ELESTR_BRACE 1
+#define JIM_ELESTR_QUOTE 2
+static int ListElementQuotingType(const char *s, int len)
+{
+ int i, level, blevel, trySimple = 1;
+
+
+ if (len == 0)
+ return JIM_ELESTR_BRACE;
+ if (s[0] == '"' || s[0] == '{') {
+ trySimple = 0;
+ goto testbrace;
+ }
+ for (i = 0; i < len; i++) {
+ switch (s[i]) {
+ case ' ':
+ case '$':
+ case '"':
+ case '[':
+ case ']':
+ case ';':
+ case '\\':
+ case '\r':
+ case '\n':
+ case '\t':
+ case '\f':
+ case '\v':
+ trySimple = 0;
+ case '{':
+ case '}':
+ goto testbrace;
+ }
+ }
+ return JIM_ELESTR_SIMPLE;
+
+ testbrace:
+
+ if (s[len - 1] == '\\')
+ return JIM_ELESTR_QUOTE;
+ level = 0;
+ blevel = 0;
+ for (i = 0; i < len; i++) {
+ switch (s[i]) {
+ case '{':
+ level++;
+ break;
+ case '}':
+ level--;
+ if (level < 0)
+ return JIM_ELESTR_QUOTE;
+ break;
+ case '[':
+ blevel++;
+ break;
+ case ']':
+ blevel--;
+ break;
+ case '\\':
+ if (s[i + 1] == '\n')
+ return JIM_ELESTR_QUOTE;
+ else if (s[i + 1] != '\0')
+ i++;
+ break;
+ }
+ }
+ if (blevel < 0) {
+ return JIM_ELESTR_QUOTE;
+ }
+
+ if (level == 0) {
+ if (!trySimple)
+ return JIM_ELESTR_BRACE;
+ for (i = 0; i < len; i++) {
+ switch (s[i]) {
+ case ' ':
+ case '$':
+ case '"':
+ case '[':
+ case ']':
+ case ';':
+ case '\\':
+ case '\r':
+ case '\n':
+ case '\t':
+ case '\f':
+ case '\v':
+ return JIM_ELESTR_BRACE;
+ break;
+ }
+ }
+ return JIM_ELESTR_SIMPLE;
+ }
+ return JIM_ELESTR_QUOTE;
+}
+
+static int BackslashQuoteString(const char *s, char *q)
+{
+ char *p = q;
+
+ while (*s) {
+ switch (*s) {
+ case ' ':
+ case '$':
+ case '"':
+ case '[':
+ case ']':
+ case '{':
+ case '}':
+ case ';':
+ case '\\':
+ *p++ = '\\';
+ *p++ = *s++;
+ break;
+ case '\n':
+ *p++ = '\\';
+ *p++ = 'n';
+ s++;
+ break;
+ case '\r':
+ *p++ = '\\';
+ *p++ = 'r';
+ s++;
+ break;
+ case '\t':
+ *p++ = '\\';
+ *p++ = 't';
+ s++;
+ break;
+ case '\f':
+ *p++ = '\\';
+ *p++ = 'f';
+ s++;
+ break;
+ case '\v':
+ *p++ = '\\';
+ *p++ = 'v';
+ s++;
+ break;
+ default:
+ *p++ = *s++;
+ break;
+ }
+ }
+ *p = '\0';
+
+ return p - q;
+}
+
+static void JimMakeListStringRep(Jim_Obj *objPtr, Jim_Obj **objv, int objc)
+{
+ int i, bufLen, realLength;
+ const char *strRep;
+ char *p;
+ int *quotingType;
+
+
+ quotingType = Jim_Alloc(sizeof(int) * objc + 1);
+ bufLen = 0;
+ for (i = 0; i < objc; i++) {
+ int len;
+
+ strRep = Jim_GetString(objv[i], &len);
+ quotingType[i] = ListElementQuotingType(strRep, len);
+ switch (quotingType[i]) {
+ case JIM_ELESTR_SIMPLE:
+ if (i != 0 || strRep[0] != '#') {
+ bufLen += len;
+ break;
+ }
+
+ quotingType[i] = JIM_ELESTR_BRACE;
+
+ case JIM_ELESTR_BRACE:
+ bufLen += len + 2;
+ break;
+ case JIM_ELESTR_QUOTE:
+ bufLen += len * 2;
+ break;
+ }
+ bufLen++;
+ }
+ bufLen++;
+
+
+ p = objPtr->bytes = Jim_Alloc(bufLen + 1);
+ realLength = 0;
+ for (i = 0; i < objc; i++) {
+ int len, qlen;
+
+ strRep = Jim_GetString(objv[i], &len);
+
+ switch (quotingType[i]) {
+ case JIM_ELESTR_SIMPLE:
+ memcpy(p, strRep, len);
+ p += len;
+ realLength += len;
+ break;
+ case JIM_ELESTR_BRACE:
+ *p++ = '{';
+ memcpy(p, strRep, len);
+ p += len;
+ *p++ = '}';
+ realLength += len + 2;
+ break;
+ case JIM_ELESTR_QUOTE:
+ if (i == 0 && strRep[0] == '#') {
+ *p++ = '\\';
+ realLength++;
+ }
+ qlen = BackslashQuoteString(strRep, p);
+ p += qlen;
+ realLength += qlen;
+ break;
+ }
+
+ if (i + 1 != objc) {
+ *p++ = ' ';
+ realLength++;
+ }
+ }
+ *p = '\0';
+ objPtr->length = realLength;
+ Jim_Free(quotingType);
+}
+
+static void UpdateStringOfList(struct Jim_Obj *objPtr)
+{
+ JimMakeListStringRep(objPtr, objPtr->internalRep.listValue.ele, objPtr->internalRep.listValue.len);
+}
+
+static int SetListFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr)
+{
+ struct JimParserCtx parser;
+ const char *str;
+ int strLen;
+ Jim_Obj *fileNameObj;
+ int linenr;
+
+ if (objPtr->typePtr == &listObjType) {
+ return JIM_OK;
+ }
+
+ if (Jim_IsDict(objPtr) && !Jim_IsShared(objPtr)) {
+ Jim_Obj **listObjPtrPtr;
+ int len;
+ int i;
+
+ Jim_DictPairs(interp, objPtr, &listObjPtrPtr, &len);
+ for (i = 0; i < len; i++) {
+ Jim_IncrRefCount(listObjPtrPtr[i]);
+ }
+
+
+ Jim_FreeIntRep(interp, objPtr);
+ objPtr->typePtr = &listObjType;
+ objPtr->internalRep.listValue.len = len;
+ objPtr->internalRep.listValue.maxLen = len;
+ objPtr->internalRep.listValue.ele = listObjPtrPtr;
+
+ return JIM_OK;
+ }
+
+
+ if (objPtr->typePtr == &sourceObjType) {
+ fileNameObj = objPtr->internalRep.sourceValue.fileNameObj;
+ linenr = objPtr->internalRep.sourceValue.lineNumber;
+ }
+ else {
+ fileNameObj = interp->emptyObj;
+ linenr = 1;
+ }
+ Jim_IncrRefCount(fileNameObj);
+
+
+ str = Jim_GetString(objPtr, &strLen);
+
+ Jim_FreeIntRep(interp, objPtr);
+ objPtr->typePtr = &listObjType;
+ objPtr->internalRep.listValue.len = 0;
+ objPtr->internalRep.listValue.maxLen = 0;
+ objPtr->internalRep.listValue.ele = NULL;
+
+
+ if (strLen) {
+ JimParserInit(&parser, str, strLen, linenr);
+ while (!parser.eof) {
+ Jim_Obj *elementPtr;
+
+ JimParseList(&parser);
+ if (parser.tt != JIM_TT_STR && parser.tt != JIM_TT_ESC)
+ continue;
+ elementPtr = JimParserGetTokenObj(interp, &parser);
+ JimSetSourceInfo(interp, elementPtr, fileNameObj, parser.tline);
+ ListAppendElement(objPtr, elementPtr);
+ }
+ }
+ Jim_DecrRefCount(interp, fileNameObj);
+ return JIM_OK;
+}
+
+Jim_Obj *Jim_NewListObj(Jim_Interp *interp, Jim_Obj *const *elements, int len)
+{
+ Jim_Obj *objPtr;
+
+ objPtr = Jim_NewObj(interp);
+ objPtr->typePtr = &listObjType;
+ objPtr->bytes = NULL;
+ objPtr->internalRep.listValue.ele = NULL;
+ objPtr->internalRep.listValue.len = 0;
+ objPtr->internalRep.listValue.maxLen = 0;
+
+ if (len) {
+ ListInsertElements(objPtr, 0, len, elements);
+ }
+
+ return objPtr;
+}
+
+static void JimListGetElements(Jim_Interp *interp, Jim_Obj *listObj, int *listLen,
+ Jim_Obj ***listVec)
+{
+ *listLen = Jim_ListLength(interp, listObj);
+ *listVec = listObj->internalRep.listValue.ele;
+}
+
+
+static int JimSign(jim_wide w)
+{
+ if (w == 0) {
+ return 0;
+ }
+ else if (w < 0) {
+ return -1;
+ }
+ return 1;
+}
+
+
+struct lsort_info {
+ jmp_buf jmpbuf;
+ Jim_Obj *command;
+ Jim_Interp *interp;
+ enum {
+ JIM_LSORT_ASCII,
+ JIM_LSORT_NOCASE,
+ JIM_LSORT_INTEGER,
+ JIM_LSORT_COMMAND
+ } type;
+ int order;
+ int index;
+ int indexed;
+ int (*subfn)(Jim_Obj **, Jim_Obj **);
+};
+
+static struct lsort_info *sort_info;
+
+static int ListSortIndexHelper(Jim_Obj **lhsObj, Jim_Obj **rhsObj)
+{
+ Jim_Obj *lObj, *rObj;
+
+ if (Jim_ListIndex(sort_info->interp, *lhsObj, sort_info->index, &lObj, JIM_ERRMSG) != JIM_OK ||
+ Jim_ListIndex(sort_info->interp, *rhsObj, sort_info->index, &rObj, JIM_ERRMSG) != JIM_OK) {
+ longjmp(sort_info->jmpbuf, JIM_ERR);
+ }
+ return sort_info->subfn(&lObj, &rObj);
+}
+
+
+static int ListSortString(Jim_Obj **lhsObj, Jim_Obj **rhsObj)
+{
+ return Jim_StringCompareObj(sort_info->interp, *lhsObj, *rhsObj, 0) * sort_info->order;
+}
+
+static int ListSortStringNoCase(Jim_Obj **lhsObj, Jim_Obj **rhsObj)
+{
+ return Jim_StringCompareObj(sort_info->interp, *lhsObj, *rhsObj, 1) * sort_info->order;
+}
+
+static int ListSortInteger(Jim_Obj **lhsObj, Jim_Obj **rhsObj)
+{
+ jim_wide lhs = 0, rhs = 0;
+
+ if (Jim_GetWide(sort_info->interp, *lhsObj, &lhs) != JIM_OK ||
+ Jim_GetWide(sort_info->interp, *rhsObj, &rhs) != JIM_OK) {
+ longjmp(sort_info->jmpbuf, JIM_ERR);
+ }
+
+ return JimSign(lhs - rhs) * sort_info->order;
+}
+
+static int ListSortCommand(Jim_Obj **lhsObj, Jim_Obj **rhsObj)
+{
+ Jim_Obj *compare_script;
+ int rc;
+
+ jim_wide ret = 0;
+
+
+ compare_script = Jim_DuplicateObj(sort_info->interp, sort_info->command);
+ Jim_ListAppendElement(sort_info->interp, compare_script, *lhsObj);
+ Jim_ListAppendElement(sort_info->interp, compare_script, *rhsObj);
+
+ rc = Jim_EvalObj(sort_info->interp, compare_script);
+
+ if (rc != JIM_OK || Jim_GetWide(sort_info->interp, Jim_GetResult(sort_info->interp), &ret) != JIM_OK) {
+ longjmp(sort_info->jmpbuf, rc);
+ }
+
+ return JimSign(ret) * sort_info->order;
+}
+
+
+static int ListSortElements(Jim_Interp *interp, Jim_Obj *listObjPtr, struct lsort_info *info)
+{
+ struct lsort_info *prev_info;
+
+ typedef int (qsort_comparator) (const void *, const void *);
+ int (*fn) (Jim_Obj **, Jim_Obj **);
+ Jim_Obj **vector;
+ int len;
+ int rc;
+
+ JimPanic((Jim_IsShared(listObjPtr), "Jim_ListSortElements called with shared object"));
+ SetListFromAny(interp, listObjPtr);
+
+
+ prev_info = sort_info;
+ sort_info = info;
+
+ vector = listObjPtr->internalRep.listValue.ele;
+ len = listObjPtr->internalRep.listValue.len;
+ switch (info->type) {
+ case JIM_LSORT_ASCII:
+ fn = ListSortString;
+ break;
+ case JIM_LSORT_NOCASE:
+ fn = ListSortStringNoCase;
+ break;
+ case JIM_LSORT_INTEGER:
+ fn = ListSortInteger;
+ break;
+ case JIM_LSORT_COMMAND:
+ fn = ListSortCommand;
+ break;
+ default:
+ fn = NULL;
+ JimPanic((1, "ListSort called with invalid sort type"));
+ }
+
+ if (info->indexed) {
+
+ info->subfn = fn;
+ fn = ListSortIndexHelper;
+ }
+
+ if ((rc = setjmp(info->jmpbuf)) == 0) {
+ qsort(vector, len, sizeof(Jim_Obj *), (qsort_comparator *) fn);
+ }
+ Jim_InvalidateStringRep(listObjPtr);
+ sort_info = prev_info;
+
+ return rc;
+}
+
+static void ListInsertElements(Jim_Obj *listPtr, int idx, int elemc, Jim_Obj *const *elemVec)
+{
+ int currentLen = listPtr->internalRep.listValue.len;
+ int requiredLen = currentLen + elemc;
+ int i;
+ Jim_Obj **point;
+
+ if (requiredLen > listPtr->internalRep.listValue.maxLen) {
+ listPtr->internalRep.listValue.maxLen = requiredLen * 2;
+
+ listPtr->internalRep.listValue.ele = Jim_Realloc(listPtr->internalRep.listValue.ele,
+ sizeof(Jim_Obj *) * listPtr->internalRep.listValue.maxLen);
+ }
+ if (idx < 0) {
+ idx = currentLen;
+ }
+ point = listPtr->internalRep.listValue.ele + idx;
+ memmove(point + elemc, point, (currentLen - idx) * sizeof(Jim_Obj *));
+ for (i = 0; i < elemc; ++i) {
+ point[i] = elemVec[i];
+ Jim_IncrRefCount(point[i]);
+ }
+ listPtr->internalRep.listValue.len += elemc;
+}
+
+static void ListAppendElement(Jim_Obj *listPtr, Jim_Obj *objPtr)
+{
+ ListInsertElements(listPtr, -1, 1, &objPtr);
+}
+
+static void ListAppendList(Jim_Obj *listPtr, Jim_Obj *appendListPtr)
+{
+ ListInsertElements(listPtr, -1,
+ appendListPtr->internalRep.listValue.len, appendListPtr->internalRep.listValue.ele);
+}
+
+void Jim_ListAppendElement(Jim_Interp *interp, Jim_Obj *listPtr, Jim_Obj *objPtr)
+{
+ JimPanic((Jim_IsShared(listPtr), "Jim_ListAppendElement called with shared object"));
+ SetListFromAny(interp, listPtr);
+ Jim_InvalidateStringRep(listPtr);
+ ListAppendElement(listPtr, objPtr);
+}
+
+void Jim_ListAppendList(Jim_Interp *interp, Jim_Obj *listPtr, Jim_Obj *appendListPtr)
+{
+ JimPanic((Jim_IsShared(listPtr), "Jim_ListAppendList called with shared object"));
+ SetListFromAny(interp, listPtr);
+ SetListFromAny(interp, appendListPtr);
+ Jim_InvalidateStringRep(listPtr);
+ ListAppendList(listPtr, appendListPtr);
+}
+
+int Jim_ListLength(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+ SetListFromAny(interp, objPtr);
+ return objPtr->internalRep.listValue.len;
+}
+
+void Jim_ListInsertElements(Jim_Interp *interp, Jim_Obj *listPtr, int idx,
+ int objc, Jim_Obj *const *objVec)
+{
+ JimPanic((Jim_IsShared(listPtr), "Jim_ListInsertElement called with shared object"));
+ SetListFromAny(interp, listPtr);
+ if (idx >= 0 && idx > listPtr->internalRep.listValue.len)
+ idx = listPtr->internalRep.listValue.len;
+ else if (idx < 0)
+ idx = 0;
+ Jim_InvalidateStringRep(listPtr);
+ ListInsertElements(listPtr, idx, objc, objVec);
+}
+
+Jim_Obj *Jim_ListGetIndex(Jim_Interp *interp, Jim_Obj *listPtr, int idx)
+{
+ SetListFromAny(interp, listPtr);
+ if ((idx >= 0 && idx >= listPtr->internalRep.listValue.len) ||
+ (idx < 0 && (-idx - 1) >= listPtr->internalRep.listValue.len)) {
+ return NULL;
+ }
+ if (idx < 0)
+ idx = listPtr->internalRep.listValue.len + idx;
+ return listPtr->internalRep.listValue.ele[idx];
+}
+
+int Jim_ListIndex(Jim_Interp *interp, Jim_Obj *listPtr, int idx, Jim_Obj **objPtrPtr, int flags)
+{
+ *objPtrPtr = Jim_ListGetIndex(interp, listPtr, idx);
+ if (*objPtrPtr == NULL) {
+ if (flags & JIM_ERRMSG) {
+ Jim_SetResultString(interp, "list index out of range", -1);
+ }
+ return JIM_ERR;
+ }
+ return JIM_OK;
+}
+
+static int ListSetIndex(Jim_Interp *interp, Jim_Obj *listPtr, int idx,
+ Jim_Obj *newObjPtr, int flags)
+{
+ SetListFromAny(interp, listPtr);
+ if ((idx >= 0 && idx >= listPtr->internalRep.listValue.len) ||
+ (idx < 0 && (-idx - 1) >= listPtr->internalRep.listValue.len)) {
+ if (flags & JIM_ERRMSG) {
+ Jim_SetResultString(interp, "list index out of range", -1);
+ }
+ return JIM_ERR;
+ }
+ if (idx < 0)
+ idx = listPtr->internalRep.listValue.len + idx;
+ Jim_DecrRefCount(interp, listPtr->internalRep.listValue.ele[idx]);
+ listPtr->internalRep.listValue.ele[idx] = newObjPtr;
+ Jim_IncrRefCount(newObjPtr);
+ return JIM_OK;
+}
+
+int Jim_SetListIndex(Jim_Interp *interp, Jim_Obj *varNamePtr,
+ Jim_Obj *const *indexv, int indexc, Jim_Obj *newObjPtr)
+{
+ Jim_Obj *varObjPtr, *objPtr, *listObjPtr;
+ int shared, i, idx;
+
+ varObjPtr = objPtr = Jim_GetVariable(interp, varNamePtr, JIM_ERRMSG | JIM_UNSHARED);
+ if (objPtr == NULL)
+ return JIM_ERR;
+ if ((shared = Jim_IsShared(objPtr)))
+ varObjPtr = objPtr = Jim_DuplicateObj(interp, objPtr);
+ for (i = 0; i < indexc - 1; i++) {
+ listObjPtr = objPtr;
+ if (Jim_GetIndex(interp, indexv[i], &idx) != JIM_OK)
+ goto err;
+ if (Jim_ListIndex(interp, listObjPtr, idx, &objPtr, JIM_ERRMSG) != JIM_OK) {
+ goto err;
+ }
+ if (Jim_IsShared(objPtr)) {
+ objPtr = Jim_DuplicateObj(interp, objPtr);
+ ListSetIndex(interp, listObjPtr, idx, objPtr, JIM_NONE);
+ }
+ Jim_InvalidateStringRep(listObjPtr);
+ }
+ if (Jim_GetIndex(interp, indexv[indexc - 1], &idx) != JIM_OK)
+ goto err;
+ if (ListSetIndex(interp, objPtr, idx, newObjPtr, JIM_ERRMSG) == JIM_ERR)
+ goto err;
+ Jim_InvalidateStringRep(objPtr);
+ Jim_InvalidateStringRep(varObjPtr);
+ if (Jim_SetVariable(interp, varNamePtr, varObjPtr) != JIM_OK)
+ goto err;
+ Jim_SetResult(interp, varObjPtr);
+ return JIM_OK;
+ err:
+ if (shared) {
+ Jim_FreeNewObj(interp, varObjPtr);
+ }
+ return JIM_ERR;
+}
+
+Jim_Obj *Jim_ListJoin(Jim_Interp *interp, Jim_Obj *listObjPtr, const char *joinStr, int joinStrLen)
+{
+ int i;
+ int listLen = Jim_ListLength(interp, listObjPtr);
+ Jim_Obj *resObjPtr = Jim_NewEmptyStringObj(interp);
+
+ for (i = 0; i < listLen; ) {
+ Jim_Obj *objPtr;
+
+ Jim_ListIndex(interp, listObjPtr, i, &objPtr, JIM_NONE);
+ Jim_AppendObj(interp, resObjPtr, objPtr);
+ if (++i != listLen) {
+ Jim_AppendString(interp, resObjPtr, joinStr, joinStrLen);
+ }
+ }
+ return resObjPtr;
+}
+
+Jim_Obj *Jim_ConcatObj(Jim_Interp *interp, int objc, Jim_Obj *const *objv)
+{
+ int i;
+
+ for (i = 0; i < objc; i++) {
+ if (!Jim_IsList(objv[i]))
+ break;
+ }
+ if (i == objc) {
+ Jim_Obj *objPtr = Jim_NewListObj(interp, NULL, 0);
+
+ for (i = 0; i < objc; i++)
+ ListAppendList(objPtr, objv[i]);
+ return objPtr;
+ }
+ else {
+
+ int len = 0, objLen;
+ char *bytes, *p;
+
+
+ for (i = 0; i < objc; i++) {
+ Jim_GetString(objv[i], &objLen);
+ len += objLen;
+ }
+ if (objc)
+ len += objc - 1;
+
+ p = bytes = Jim_Alloc(len + 1);
+ for (i = 0; i < objc; i++) {
+ const char *s = Jim_GetString(objv[i], &objLen);
+
+
+ while (objLen && (*s == ' ' || *s == '\t' || *s == '\n')) {
+ s++;
+ objLen--;
+ len--;
+ }
+
+ while (objLen && (s[objLen - 1] == ' ' ||
+ s[objLen - 1] == '\n' || s[objLen - 1] == '\t')) {
+
+ if (objLen > 1 && s[objLen - 2] == '\\') {
+ break;
+ }
+ objLen--;
+ len--;
+ }
+ memcpy(p, s, objLen);
+ p += objLen;
+ if (objLen && i + 1 != objc) {
+ *p++ = ' ';
+ }
+ else if (i + 1 != objc) {
+ len--;
+ }
+ }
+ *p = '\0';
+ return Jim_NewStringObjNoAlloc(interp, bytes, len);
+ }
+}
+
+Jim_Obj *Jim_ListRange(Jim_Interp *interp, Jim_Obj *listObjPtr, Jim_Obj *firstObjPtr,
+ Jim_Obj *lastObjPtr)
+{
+ int first, last;
+ int len, rangeLen;
+
+ if (Jim_GetIndex(interp, firstObjPtr, &first) != JIM_OK ||
+ Jim_GetIndex(interp, lastObjPtr, &last) != JIM_OK)
+ return NULL;
+ len = Jim_ListLength(interp, listObjPtr);
+ first = JimRelToAbsIndex(len, first);
+ last = JimRelToAbsIndex(len, last);
+ JimRelToAbsRange(len, &first, &last, &rangeLen);
+ if (first == 0 && last == len) {
+ return listObjPtr;
+ }
+ return Jim_NewListObj(interp, listObjPtr->internalRep.listValue.ele + first, rangeLen);
+}
+
+static void FreeDictInternalRep(Jim_Interp *interp, Jim_Obj *objPtr);
+static void DupDictInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr);
+static void UpdateStringOfDict(struct Jim_Obj *objPtr);
+static int SetDictFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr);
+
+
+static unsigned int JimObjectHTHashFunction(const void *key)
+{
+ int len;
+ const char *str = Jim_GetString((Jim_Obj *)key, &len);
+ return Jim_GenHashFunction((const unsigned char *)str, len);
+}
+
+static int JimObjectHTKeyCompare(void *privdata, const void *key1, const void *key2)
+{
+ return Jim_StringEqObj((Jim_Obj *)key1, (Jim_Obj *)key2);
+}
+
+static void JimObjectHTKeyValDestructor(void *interp, void *val)
+{
+ Jim_DecrRefCount(interp, (Jim_Obj *)val);
+}
+
+static const Jim_HashTableType JimDictHashTableType = {
+ JimObjectHTHashFunction,
+ NULL,
+ NULL,
+ JimObjectHTKeyCompare,
+ JimObjectHTKeyValDestructor,
+ JimObjectHTKeyValDestructor
+};
+
+static const Jim_ObjType dictObjType = {
+ "dict",
+ FreeDictInternalRep,
+ DupDictInternalRep,
+ UpdateStringOfDict,
+ JIM_TYPE_NONE,
+};
+
+void FreeDictInternalRep(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+ JIM_NOTUSED(interp);
+
+ Jim_FreeHashTable(objPtr->internalRep.ptr);
+ Jim_Free(objPtr->internalRep.ptr);
+}
+
+void DupDictInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr)
+{
+ Jim_HashTable *ht, *dupHt;
+ Jim_HashTableIterator *htiter;
+ Jim_HashEntry *he;
+
+
+ ht = srcPtr->internalRep.ptr;
+ dupHt = Jim_Alloc(sizeof(*dupHt));
+ Jim_InitHashTable(dupHt, &JimDictHashTableType, interp);
+ if (ht->size != 0)
+ Jim_ExpandHashTable(dupHt, ht->size);
+
+ htiter = Jim_GetHashTableIterator(ht);
+ while ((he = Jim_NextHashEntry(htiter)) != NULL) {
+ const Jim_Obj *keyObjPtr = he->key;
+ Jim_Obj *valObjPtr = he->u.val;
+
+ Jim_IncrRefCount((Jim_Obj *)keyObjPtr);
+ Jim_IncrRefCount(valObjPtr);
+ Jim_AddHashEntry(dupHt, keyObjPtr, valObjPtr);
+ }
+ Jim_FreeHashTableIterator(htiter);
+
+ dupPtr->internalRep.ptr = dupHt;
+ dupPtr->typePtr = &dictObjType;
+}
+
+static Jim_Obj **JimDictPairs(Jim_Obj *dictPtr, int *len)
+{
+ Jim_HashTable *ht;
+ Jim_HashTableIterator *htiter;
+ Jim_HashEntry *he;
+ Jim_Obj **objv;
+ int i;
+
+ ht = dictPtr->internalRep.ptr;
+
+
+ objv = Jim_Alloc((ht->used * 2) * sizeof(Jim_Obj *));
+ htiter = Jim_GetHashTableIterator(ht);
+ i = 0;
+ while ((he = Jim_NextHashEntry(htiter)) != NULL) {
+ objv[i++] = (Jim_Obj *)he->key;
+ objv[i++] = he->u.val;
+ }
+ *len = i;
+ Jim_FreeHashTableIterator(htiter);
+ return objv;
+}
+
+static void UpdateStringOfDict(struct Jim_Obj *objPtr)
+{
+
+ int len;
+ Jim_Obj **objv = JimDictPairs(objPtr, &len);
+
+ JimMakeListStringRep(objPtr, objv, len);
+
+ Jim_Free(objv);
+}
+
+static int SetDictFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr)
+{
+ int listlen;
+
+ if (objPtr->typePtr == &dictObjType) {
+ return JIM_OK;
+ }
+
+ Jim_String(objPtr);
+
+
+ listlen = Jim_ListLength(interp, objPtr);
+ if (listlen % 2) {
+ Jim_SetResultString(interp, "missing value to go with key", -1);
+ return JIM_ERR;
+ }
+ else {
+
+ Jim_HashTable *ht;
+ int i;
+
+ ht = Jim_Alloc(sizeof(*ht));
+ Jim_InitHashTable(ht, &JimDictHashTableType, interp);
+
+ for (i = 0; i < listlen; i += 2) {
+ Jim_Obj *keyObjPtr;
+ Jim_Obj *valObjPtr;
+
+ Jim_ListIndex(interp, objPtr, i, &keyObjPtr, JIM_NONE);
+ Jim_ListIndex(interp, objPtr, i + 1, &valObjPtr, JIM_NONE);
+
+ Jim_IncrRefCount(keyObjPtr);
+ Jim_IncrRefCount(valObjPtr);
+
+ if (Jim_AddHashEntry(ht, keyObjPtr, valObjPtr) != JIM_OK) {
+ Jim_HashEntry *he;
+
+ he = Jim_FindHashEntry(ht, keyObjPtr);
+ Jim_DecrRefCount(interp, keyObjPtr);
+
+ Jim_DecrRefCount(interp, (Jim_Obj *)he->u.val);
+ he->u.val = valObjPtr;
+ }
+ }
+
+ Jim_FreeIntRep(interp, objPtr);
+ objPtr->typePtr = &dictObjType;
+ objPtr->internalRep.ptr = ht;
+
+ return JIM_OK;
+ }
+}
+
+
+
+static int DictAddElement(Jim_Interp *interp, Jim_Obj *objPtr,
+ Jim_Obj *keyObjPtr, Jim_Obj *valueObjPtr)
+{
+ Jim_HashTable *ht = objPtr->internalRep.ptr;
+
+ if (valueObjPtr == NULL) {
+ return Jim_DeleteHashEntry(ht, keyObjPtr);
+ }
+ Jim_IncrRefCount(keyObjPtr);
+ Jim_IncrRefCount(valueObjPtr);
+ if (Jim_ReplaceHashEntry(ht, keyObjPtr, valueObjPtr)) {
+
+ Jim_DecrRefCount(interp, keyObjPtr);
+ }
+ return JIM_OK;
+}
+
+int Jim_DictAddElement(Jim_Interp *interp, Jim_Obj *objPtr,
+ Jim_Obj *keyObjPtr, Jim_Obj *valueObjPtr)
+{
+ int retcode;
+
+ JimPanic((Jim_IsShared(objPtr), "Jim_DictAddElement called with shared object"));
+ if (SetDictFromAny(interp, objPtr) != JIM_OK) {
+ return JIM_ERR;
+ }
+ retcode = DictAddElement(interp, objPtr, keyObjPtr, valueObjPtr);
+ Jim_InvalidateStringRep(objPtr);
+ return retcode;
+}
+
+Jim_Obj *Jim_NewDictObj(Jim_Interp *interp, Jim_Obj *const *elements, int len)
+{
+ Jim_Obj *objPtr;
+ int i;
+
+ JimPanic((len % 2, "Jim_NewDictObj() 'len' argument must be even"));
+
+ objPtr = Jim_NewObj(interp);
+ objPtr->typePtr = &dictObjType;
+ objPtr->bytes = NULL;
+ objPtr->internalRep.ptr = Jim_Alloc(sizeof(Jim_HashTable));
+ Jim_InitHashTable(objPtr->internalRep.ptr, &JimDictHashTableType, interp);
+ for (i = 0; i < len; i += 2)
+ DictAddElement(interp, objPtr, elements[i], elements[i + 1]);
+ return objPtr;
+}
+
+int Jim_DictKey(Jim_Interp *interp, Jim_Obj *dictPtr, Jim_Obj *keyPtr,
+ Jim_Obj **objPtrPtr, int flags)
+{
+ Jim_HashEntry *he;
+ Jim_HashTable *ht;
+
+ if (SetDictFromAny(interp, dictPtr) != JIM_OK) {
+ return -1;
+ }
+ ht = dictPtr->internalRep.ptr;
+ if ((he = Jim_FindHashEntry(ht, keyPtr)) == NULL) {
+ if (flags & JIM_ERRMSG) {
+ Jim_SetResultFormatted(interp, "key \"%#s\" not known in dictionary", keyPtr);
+ }
+ return JIM_ERR;
+ }
+ *objPtrPtr = he->u.val;
+ return JIM_OK;
+}
+
+
+int Jim_DictPairs(Jim_Interp *interp, Jim_Obj *dictPtr, Jim_Obj ***objPtrPtr, int *len)
+{
+ if (SetDictFromAny(interp, dictPtr) != JIM_OK) {
+ return JIM_ERR;
+ }
+ *objPtrPtr = JimDictPairs(dictPtr, len);
+
+ return JIM_OK;
+}
+
+
+
+int Jim_DictKeysVector(Jim_Interp *interp, Jim_Obj *dictPtr,
+ Jim_Obj *const *keyv, int keyc, Jim_Obj **objPtrPtr, int flags)
+{
+ int i;
+
+ if (keyc == 0) {
+ *objPtrPtr = dictPtr;
+ return JIM_OK;
+ }
+
+ for (i = 0; i < keyc; i++) {
+ Jim_Obj *objPtr;
+
+ int rc = Jim_DictKey(interp, dictPtr, keyv[i], &objPtr, flags);
+ if (rc != JIM_OK) {
+ return rc;
+ }
+ dictPtr = objPtr;
+ }
+ *objPtrPtr = dictPtr;
+ return JIM_OK;
+}
+
+int Jim_SetDictKeysVector(Jim_Interp *interp, Jim_Obj *varNamePtr,
+ Jim_Obj *const *keyv, int keyc, Jim_Obj *newObjPtr, int flags)
+{
+ Jim_Obj *varObjPtr, *objPtr, *dictObjPtr;
+ int shared, i;
+
+ varObjPtr = objPtr = Jim_GetVariable(interp, varNamePtr, flags);
+ if (objPtr == NULL) {
+ if (newObjPtr == NULL && (flags & JIM_MUSTEXIST)) {
+
+ return JIM_ERR;
+ }
+ varObjPtr = objPtr = Jim_NewDictObj(interp, NULL, 0);
+ if (Jim_SetVariable(interp, varNamePtr, objPtr) != JIM_OK) {
+ Jim_FreeNewObj(interp, varObjPtr);
+ return JIM_ERR;
+ }
+ }
+ if ((shared = Jim_IsShared(objPtr)))
+ varObjPtr = objPtr = Jim_DuplicateObj(interp, objPtr);
+ for (i = 0; i < keyc; i++) {
+ dictObjPtr = objPtr;
+
+
+ if (SetDictFromAny(interp, dictObjPtr) != JIM_OK) {
+ goto err;
+ }
+
+ if (i == keyc - 1) {
+
+ if (Jim_DictAddElement(interp, objPtr, keyv[keyc - 1], newObjPtr) != JIM_OK) {
+ if (newObjPtr || (flags & JIM_MUSTEXIST)) {
+ goto err;
+ }
+ }
+ break;
+ }
+
+
+ Jim_InvalidateStringRep(dictObjPtr);
+ if (Jim_DictKey(interp, dictObjPtr, keyv[i], &objPtr,
+ newObjPtr ? JIM_NONE : JIM_ERRMSG) == JIM_OK) {
+ if (Jim_IsShared(objPtr)) {
+ objPtr = Jim_DuplicateObj(interp, objPtr);
+ DictAddElement(interp, dictObjPtr, keyv[i], objPtr);
+ }
+ }
+ else {
+ if (newObjPtr == NULL) {
+ goto err;
+ }
+ objPtr = Jim_NewDictObj(interp, NULL, 0);
+ DictAddElement(interp, dictObjPtr, keyv[i], objPtr);
+ }
+ }
+ Jim_InvalidateStringRep(objPtr);
+ Jim_InvalidateStringRep(varObjPtr);
+ if (Jim_SetVariable(interp, varNamePtr, varObjPtr) != JIM_OK) {
+ goto err;
+ }
+ Jim_SetResult(interp, varObjPtr);
+ return JIM_OK;
+ err:
+ if (shared) {
+ Jim_FreeNewObj(interp, varObjPtr);
+ }
+ return JIM_ERR;
+}
+
+static void UpdateStringOfIndex(struct Jim_Obj *objPtr);
+static int SetIndexFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr);
+
+static const Jim_ObjType indexObjType = {
+ "index",
+ NULL,
+ NULL,
+ UpdateStringOfIndex,
+ JIM_TYPE_NONE,
+};
+
+void UpdateStringOfIndex(struct Jim_Obj *objPtr)
+{
+ int len;
+ char buf[JIM_INTEGER_SPACE + 1];
+
+ if (objPtr->internalRep.intValue >= 0)
+ len = sprintf(buf, "%d", objPtr->internalRep.intValue);
+ else if (objPtr->internalRep.intValue == -1)
+ len = sprintf(buf, "end");
+ else {
+ len = sprintf(buf, "end%d", objPtr->internalRep.intValue + 1);
+ }
+ objPtr->bytes = Jim_Alloc(len + 1);
+ memcpy(objPtr->bytes, buf, len + 1);
+ objPtr->length = len;
+}
+
+int SetIndexFromAny(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+ int idx, end = 0;
+ const char *str;
+ char *endptr;
+
+
+ str = Jim_String(objPtr);
+
+
+ if (strncmp(str, "end", 3) == 0) {
+ end = 1;
+ str += 3;
+ idx = 0;
+ }
+ else {
+ idx = jim_strtol(str, &endptr);
+
+ if (endptr == str) {
+ goto badindex;
+ }
+ str = endptr;
+ }
+
+
+ if (*str == '+' || *str == '-') {
+ int sign = (*str == '+' ? 1 : -1);
+
+ idx += sign * jim_strtol(++str, &endptr);
+ if (str == endptr || *endptr) {
+ goto badindex;
+ }
+ str = endptr;
+ }
+
+ while (isspace(UCHAR(*str))) {
+ str++;
+ }
+ if (*str) {
+ goto badindex;
+ }
+ if (end) {
+ if (idx > 0) {
+ idx = INT_MAX;
+ }
+ else {
+
+ idx--;
+ }
+ }
+ else if (idx < 0) {
+ idx = -INT_MAX;
+ }
+
+
+ Jim_FreeIntRep(interp, objPtr);
+ objPtr->typePtr = &indexObjType;
+ objPtr->internalRep.intValue = idx;
+ return JIM_OK;
+
+ badindex:
+ Jim_SetResultFormatted(interp,
+ "bad index \"%#s\": must be integer?[+-]integer? or end?[+-]integer?", objPtr);
+ return JIM_ERR;
+}
+
+int Jim_GetIndex(Jim_Interp *interp, Jim_Obj *objPtr, int *indexPtr)
+{
+
+ if (objPtr->typePtr == &intObjType) {
+ jim_wide val = JimWideValue(objPtr);
+
+ if (!(val < LONG_MIN) && !(val > LONG_MAX)) {
+ *indexPtr = (val < 0) ? -INT_MAX : (long)val;;
+ return JIM_OK;
+ }
+ }
+ if (objPtr->typePtr != &indexObjType && SetIndexFromAny(interp, objPtr) == JIM_ERR)
+ return JIM_ERR;
+ *indexPtr = objPtr->internalRep.intValue;
+ return JIM_OK;
+}
+
+
+
+static const char * const jimReturnCodes[] = {
+ "ok",
+ "error",
+ "return",
+ "break",
+ "continue",
+ "signal",
+ "exit",
+ "eval",
+ NULL
+};
+
+#define jimReturnCodesSize (sizeof(jimReturnCodes)/sizeof(*jimReturnCodes))
+
+static int SetReturnCodeFromAny(Jim_Interp *interp, Jim_Obj *objPtr);
+
+static const Jim_ObjType returnCodeObjType = {
+ "return-code",
+ NULL,
+ NULL,
+ NULL,
+ JIM_TYPE_NONE,
+};
+
+const char *Jim_ReturnCode(int code)
+{
+ if (code < 0 || code >= (int)jimReturnCodesSize) {
+ return "?";
+ }
+ else {
+ return jimReturnCodes[code];
+ }
+}
+
+int SetReturnCodeFromAny(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+ int returnCode;
+ jim_wide wideValue;
+
+
+ if (JimGetWideNoErr(interp, objPtr, &wideValue) != JIM_ERR)
+ returnCode = (int)wideValue;
+ else if (Jim_GetEnum(interp, objPtr, jimReturnCodes, &returnCode, NULL, JIM_NONE) != JIM_OK) {
+ Jim_SetResultFormatted(interp, "expected return code but got \"%#s\"", objPtr);
+ return JIM_ERR;
+ }
+
+ Jim_FreeIntRep(interp, objPtr);
+ objPtr->typePtr = &returnCodeObjType;
+ objPtr->internalRep.intValue = returnCode;
+ return JIM_OK;
+}
+
+int Jim_GetReturnCode(Jim_Interp *interp, Jim_Obj *objPtr, int *intPtr)
+{
+ if (objPtr->typePtr != &returnCodeObjType && SetReturnCodeFromAny(interp, objPtr) == JIM_ERR)
+ return JIM_ERR;
+ *intPtr = objPtr->internalRep.intValue;
+ return JIM_OK;
+}
+
+static int JimParseExprOperator(struct JimParserCtx *pc);
+static int JimParseExprNumber(struct JimParserCtx *pc);
+static int JimParseExprIrrational(struct JimParserCtx *pc);
+
+
+
+
+enum
+{
+
+
+ JIM_EXPROP_MUL = JIM_TT_EXPR_OP,
+ JIM_EXPROP_DIV,
+ JIM_EXPROP_MOD,
+ JIM_EXPROP_SUB,
+ JIM_EXPROP_ADD,
+ JIM_EXPROP_LSHIFT,
+ JIM_EXPROP_RSHIFT,
+ JIM_EXPROP_ROTL,
+ JIM_EXPROP_ROTR,
+ JIM_EXPROP_LT,
+ JIM_EXPROP_GT,
+ JIM_EXPROP_LTE,
+ JIM_EXPROP_GTE,
+ JIM_EXPROP_NUMEQ,
+ JIM_EXPROP_NUMNE,
+ JIM_EXPROP_BITAND,
+ JIM_EXPROP_BITXOR,
+ JIM_EXPROP_BITOR,
+
+
+ JIM_EXPROP_LOGICAND,
+ JIM_EXPROP_LOGICAND_LEFT,
+ JIM_EXPROP_LOGICAND_RIGHT,
+
+
+ JIM_EXPROP_LOGICOR,
+ JIM_EXPROP_LOGICOR_LEFT,
+ JIM_EXPROP_LOGICOR_RIGHT,
+
+
+
+ JIM_EXPROP_TERNARY,
+ JIM_EXPROP_TERNARY_LEFT,
+ JIM_EXPROP_TERNARY_RIGHT,
+
+
+ JIM_EXPROP_COLON,
+ JIM_EXPROP_COLON_LEFT,
+ JIM_EXPROP_COLON_RIGHT,
+
+ JIM_EXPROP_POW,
+
+
+ JIM_EXPROP_STREQ,
+ JIM_EXPROP_STRNE,
+ JIM_EXPROP_STRIN,
+ JIM_EXPROP_STRNI,
+
+
+ JIM_EXPROP_NOT,
+ JIM_EXPROP_BITNOT,
+ JIM_EXPROP_UNARYMINUS,
+ JIM_EXPROP_UNARYPLUS,
+
+
+ JIM_EXPROP_FUNC_FIRST,
+ JIM_EXPROP_FUNC_INT = JIM_EXPROP_FUNC_FIRST,
+ JIM_EXPROP_FUNC_ABS,
+ JIM_EXPROP_FUNC_DOUBLE,
+ JIM_EXPROP_FUNC_ROUND,
+ JIM_EXPROP_FUNC_RAND,
+ JIM_EXPROP_FUNC_SRAND,
+
+
+ JIM_EXPROP_FUNC_SIN,
+ JIM_EXPROP_FUNC_COS,
+ JIM_EXPROP_FUNC_TAN,
+ JIM_EXPROP_FUNC_ASIN,
+ JIM_EXPROP_FUNC_ACOS,
+ JIM_EXPROP_FUNC_ATAN,
+ JIM_EXPROP_FUNC_SINH,
+ JIM_EXPROP_FUNC_COSH,
+ JIM_EXPROP_FUNC_TANH,
+ JIM_EXPROP_FUNC_CEIL,
+ JIM_EXPROP_FUNC_FLOOR,
+ JIM_EXPROP_FUNC_EXP,
+ JIM_EXPROP_FUNC_LOG,
+ JIM_EXPROP_FUNC_LOG10,
+ JIM_EXPROP_FUNC_SQRT,
+ JIM_EXPROP_FUNC_POW,
+};
+
+struct JimExprState
+{
+ Jim_Obj **stack;
+ int stacklen;
+ int opcode;
+ int skip;
+};
+
+
+typedef struct Jim_ExprOperator
+{
+ const char *name;
+ int precedence;
+ int arity;
+ int (*funcop) (Jim_Interp *interp, struct JimExprState * e);
+ int lazy;
+} Jim_ExprOperator;
+
+static void ExprPush(struct JimExprState *e, Jim_Obj *obj)
+{
+ Jim_IncrRefCount(obj);
+ e->stack[e->stacklen++] = obj;
+}
+
+static Jim_Obj *ExprPop(struct JimExprState *e)
+{
+ return e->stack[--e->stacklen];
+}
+
+static int JimExprOpNumUnary(Jim_Interp *interp, struct JimExprState *e)
+{
+ int intresult = 0;
+ int rc = JIM_OK;
+ Jim_Obj *A = ExprPop(e);
+ double dA, dC = 0;
+ jim_wide wA, wC = 0;
+
+ if ((A->typePtr != &doubleObjType || A->bytes) && JimGetWideNoErr(interp, A, &wA) == JIM_OK) {
+ intresult = 1;
+
+ switch (e->opcode) {
+ case JIM_EXPROP_FUNC_INT:
+ wC = wA;
+ break;
+ case JIM_EXPROP_FUNC_ROUND:
+ wC = wA;
+ break;
+ case JIM_EXPROP_FUNC_DOUBLE:
+ dC = wA;
+ intresult = 0;
+ break;
+ case JIM_EXPROP_FUNC_ABS:
+ wC = wA >= 0 ? wA : -wA;
+ break;
+ case JIM_EXPROP_UNARYMINUS:
+ wC = -wA;
+ break;
+ case JIM_EXPROP_UNARYPLUS:
+ wC = wA;
+ break;
+ case JIM_EXPROP_NOT:
+ wC = !wA;
+ break;
+ default:
+ abort();
+ }
+ }
+ else if ((rc = Jim_GetDouble(interp, A, &dA)) == JIM_OK) {
+ switch (e->opcode) {
+ case JIM_EXPROP_FUNC_INT:
+ wC = dA;
+ intresult = 1;
+ break;
+ case JIM_EXPROP_FUNC_ROUND:
+ wC = dA < 0 ? (dA - 0.5) : (dA + 0.5);
+ intresult = 1;
+ break;
+ case JIM_EXPROP_FUNC_DOUBLE:
+ dC = dA;
+ break;
+ case JIM_EXPROP_FUNC_ABS:
+ dC = dA >= 0 ? dA : -dA;
+ break;
+ case JIM_EXPROP_UNARYMINUS:
+ dC = -dA;
+ break;
+ case JIM_EXPROP_UNARYPLUS:
+ dC = dA;
+ break;
+ case JIM_EXPROP_NOT:
+ wC = !dA;
+ intresult = 1;
+ break;
+ default:
+ abort();
+ }
+ }
+
+ if (rc == JIM_OK) {
+ if (intresult) {
+ ExprPush(e, Jim_NewIntObj(interp, wC));
+ }
+ else {
+ ExprPush(e, Jim_NewDoubleObj(interp, dC));
+ }
+ }
+
+ Jim_DecrRefCount(interp, A);
+
+ return rc;
+}
+
+static double JimRandDouble(Jim_Interp *interp)
+{
+ unsigned long x;
+ JimRandomBytes(interp, &x, sizeof(x));
+
+ return (double)x / (unsigned long)~0;
+}
+
+static int JimExprOpIntUnary(Jim_Interp *interp, struct JimExprState *e)
+{
+ Jim_Obj *A = ExprPop(e);
+ jim_wide wA;
+
+ int rc = Jim_GetWide(interp, A, &wA);
+ if (rc == JIM_OK) {
+ switch (e->opcode) {
+ case JIM_EXPROP_BITNOT:
+ ExprPush(e, Jim_NewIntObj(interp, ~wA));
+ break;
+ case JIM_EXPROP_FUNC_SRAND:
+ JimPrngSeed(interp, (unsigned char *)&wA, sizeof(wA));
+ ExprPush(e, Jim_NewDoubleObj(interp, JimRandDouble(interp)));
+ break;
+ default:
+ abort();
+ }
+ }
+
+ Jim_DecrRefCount(interp, A);
+
+ return rc;
+}
+
+static int JimExprOpNone(Jim_Interp *interp, struct JimExprState *e)
+{
+ JimPanic((e->opcode != JIM_EXPROP_FUNC_RAND, "JimExprOpNone only support rand()"));
+
+ ExprPush(e, Jim_NewDoubleObj(interp, JimRandDouble(interp)));
+
+ return JIM_OK;
+}
+
+#ifdef JIM_MATH_FUNCTIONS
+static int JimExprOpDoubleUnary(Jim_Interp *interp, struct JimExprState *e)
+{
+ int rc;
+ Jim_Obj *A = ExprPop(e);
+ double dA, dC;
+
+ rc = Jim_GetDouble(interp, A, &dA);
+ if (rc == JIM_OK) {
+ switch (e->opcode) {
+ case JIM_EXPROP_FUNC_SIN:
+ dC = sin(dA);
+ break;
+ case JIM_EXPROP_FUNC_COS:
+ dC = cos(dA);
+ break;
+ case JIM_EXPROP_FUNC_TAN:
+ dC = tan(dA);
+ break;
+ case JIM_EXPROP_FUNC_ASIN:
+ dC = asin(dA);
+ break;
+ case JIM_EXPROP_FUNC_ACOS:
+ dC = acos(dA);
+ break;
+ case JIM_EXPROP_FUNC_ATAN:
+ dC = atan(dA);
+ break;
+ case JIM_EXPROP_FUNC_SINH:
+ dC = sinh(dA);
+ break;
+ case JIM_EXPROP_FUNC_COSH:
+ dC = cosh(dA);
+ break;
+ case JIM_EXPROP_FUNC_TANH:
+ dC = tanh(dA);
+ break;
+ case JIM_EXPROP_FUNC_CEIL:
+ dC = ceil(dA);
+ break;
+ case JIM_EXPROP_FUNC_FLOOR:
+ dC = floor(dA);
+ break;
+ case JIM_EXPROP_FUNC_EXP:
+ dC = exp(dA);
+ break;
+ case JIM_EXPROP_FUNC_LOG:
+ dC = log(dA);
+ break;
+ case JIM_EXPROP_FUNC_LOG10:
+ dC = log10(dA);
+ break;
+ case JIM_EXPROP_FUNC_SQRT:
+ dC = sqrt(dA);
+ break;
+ default:
+ abort();
+ }
+ ExprPush(e, Jim_NewDoubleObj(interp, dC));
+ }
+
+ Jim_DecrRefCount(interp, A);
+
+ return rc;
+}
+#endif
+
+
+static int JimExprOpIntBin(Jim_Interp *interp, struct JimExprState *e)
+{
+ Jim_Obj *B = ExprPop(e);
+ Jim_Obj *A = ExprPop(e);
+ jim_wide wA, wB;
+ int rc = JIM_ERR;
+
+ if (Jim_GetWide(interp, A, &wA) == JIM_OK && Jim_GetWide(interp, B, &wB) == JIM_OK) {
+ jim_wide wC;
+
+ rc = JIM_OK;
+
+ switch (e->opcode) {
+ case JIM_EXPROP_LSHIFT:
+ wC = wA << wB;
+ break;
+ case JIM_EXPROP_RSHIFT:
+ wC = wA >> wB;
+ break;
+ case JIM_EXPROP_BITAND:
+ wC = wA & wB;
+ break;
+ case JIM_EXPROP_BITXOR:
+ wC = wA ^ wB;
+ break;
+ case JIM_EXPROP_BITOR:
+ wC = wA | wB;
+ break;
+ case JIM_EXPROP_MOD:
+ if (wB == 0) {
+ wC = 0;
+ Jim_SetResultString(interp, "Division by zero", -1);
+ rc = JIM_ERR;
+ }
+ else {
+ int negative = 0;
+
+ if (wB < 0) {
+ wB = -wB;
+ wA = -wA;
+ negative = 1;
+ }
+ wC = wA % wB;
+ if (wC < 0) {
+ wC += wB;
+ }
+ if (negative) {
+ wC = -wC;
+ }
+ }
+ break;
+ case JIM_EXPROP_ROTL:
+ case JIM_EXPROP_ROTR:{
+
+ unsigned long uA = (unsigned long)wA;
+ unsigned long uB = (unsigned long)wB;
+ const unsigned int S = sizeof(unsigned long) * 8;
+
+
+ uB %= S;
+
+ if (e->opcode == JIM_EXPROP_ROTR) {
+ uB = S - uB;
+ }
+ wC = (unsigned long)(uA << uB) | (uA >> (S - uB));
+ break;
+ }
+ default:
+ abort();
+ }
+ ExprPush(e, Jim_NewIntObj(interp, wC));
+
+ }
+
+ Jim_DecrRefCount(interp, A);
+ Jim_DecrRefCount(interp, B);
+
+ return rc;
+}
+
+
+
+static int JimExprOpBin(Jim_Interp *interp, struct JimExprState *e)
+{
+ int intresult = 0;
+ int rc = JIM_OK;
+ double dA, dB, dC = 0;
+ jim_wide wA, wB, wC = 0;
+
+ Jim_Obj *B = ExprPop(e);
+ Jim_Obj *A = ExprPop(e);
+
+ if ((A->typePtr != &doubleObjType || A->bytes) &&
+ (B->typePtr != &doubleObjType || B->bytes) &&
+ JimGetWideNoErr(interp, A, &wA) == JIM_OK && JimGetWideNoErr(interp, B, &wB) == JIM_OK) {
+
+
+
+ intresult = 1;
+
+ switch (e->opcode) {
+ case JIM_EXPROP_POW:
+ case JIM_EXPROP_FUNC_POW:
+ wC = JimPowWide(wA, wB);
+ break;
+ case JIM_EXPROP_ADD:
+ wC = wA + wB;
+ break;
+ case JIM_EXPROP_SUB:
+ wC = wA - wB;
+ break;
+ case JIM_EXPROP_MUL:
+ wC = wA * wB;
+ break;
+ case JIM_EXPROP_DIV:
+ if (wB == 0) {
+ Jim_SetResultString(interp, "Division by zero", -1);
+ rc = JIM_ERR;
+ }
+ else {
+ if (wB < 0) {
+ wB = -wB;
+ wA = -wA;
+ }
+ wC = wA / wB;
+ if (wA % wB < 0) {
+ wC--;
+ }
+ }
+ break;
+ case JIM_EXPROP_LT:
+ wC = wA < wB;
+ break;
+ case JIM_EXPROP_GT:
+ wC = wA > wB;
+ break;
+ case JIM_EXPROP_LTE:
+ wC = wA <= wB;
+ break;
+ case JIM_EXPROP_GTE:
+ wC = wA >= wB;
+ break;
+ case JIM_EXPROP_NUMEQ:
+ wC = wA == wB;
+ break;
+ case JIM_EXPROP_NUMNE:
+ wC = wA != wB;
+ break;
+ default:
+ abort();
+ }
+ }
+ else if (Jim_GetDouble(interp, A, &dA) == JIM_OK && Jim_GetDouble(interp, B, &dB) == JIM_OK) {
+ switch (e->opcode) {
+ case JIM_EXPROP_POW:
+ case JIM_EXPROP_FUNC_POW:
+#ifdef JIM_MATH_FUNCTIONS
+ dC = pow(dA, dB);
+#else
+ Jim_SetResultString(interp, "unsupported", -1);
+ rc = JIM_ERR;
+#endif
+ break;
+ case JIM_EXPROP_ADD:
+ dC = dA + dB;
+ break;
+ case JIM_EXPROP_SUB:
+ dC = dA - dB;
+ break;
+ case JIM_EXPROP_MUL:
+ dC = dA * dB;
+ break;
+ case JIM_EXPROP_DIV:
+ if (dB == 0) {
+#ifdef INFINITY
+ dC = dA < 0 ? -INFINITY : INFINITY;
+#else
+ dC = (dA < 0 ? -1.0 : 1.0) * strtod("Inf", NULL);
+#endif
+ }
+ else {
+ dC = dA / dB;
+ }
+ break;
+ case JIM_EXPROP_LT:
+ wC = dA < dB;
+ intresult = 1;
+ break;
+ case JIM_EXPROP_GT:
+ wC = dA > dB;
+ intresult = 1;
+ break;
+ case JIM_EXPROP_LTE:
+ wC = dA <= dB;
+ intresult = 1;
+ break;
+ case JIM_EXPROP_GTE:
+ wC = dA >= dB;
+ intresult = 1;
+ break;
+ case JIM_EXPROP_NUMEQ:
+ wC = dA == dB;
+ intresult = 1;
+ break;
+ case JIM_EXPROP_NUMNE:
+ wC = dA != dB;
+ intresult = 1;
+ break;
+ default:
+ abort();
+ }
+ }
+ else {
+
+
+
+ int i = Jim_StringCompareObj(interp, A, B, 0);
+
+ intresult = 1;
+
+ switch (e->opcode) {
+ case JIM_EXPROP_LT:
+ wC = i < 0;
+ break;
+ case JIM_EXPROP_GT:
+ wC = i > 0;
+ break;
+ case JIM_EXPROP_LTE:
+ wC = i <= 0;
+ break;
+ case JIM_EXPROP_GTE:
+ wC = i >= 0;
+ break;
+ case JIM_EXPROP_NUMEQ:
+ wC = i == 0;
+ break;
+ case JIM_EXPROP_NUMNE:
+ wC = i != 0;
+ break;
+ default:
+ rc = JIM_ERR;
+ break;
+ }
+ }
+
+ if (rc == JIM_OK) {
+ if (intresult) {
+ ExprPush(e, Jim_NewIntObj(interp, wC));
+ }
+ else {
+ ExprPush(e, Jim_NewDoubleObj(interp, dC));
+ }
+ }
+
+ Jim_DecrRefCount(interp, A);
+ Jim_DecrRefCount(interp, B);
+
+ return rc;
+}
+
+static int JimSearchList(Jim_Interp *interp, Jim_Obj *listObjPtr, Jim_Obj *valObj)
+{
+ int listlen;
+ int i;
+
+ listlen = Jim_ListLength(interp, listObjPtr);
+ for (i = 0; i < listlen; i++) {
+ Jim_Obj *objPtr;
+
+ Jim_ListIndex(interp, listObjPtr, i, &objPtr, JIM_NONE);
+
+ if (Jim_StringEqObj(objPtr, valObj)) {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static int JimExprOpStrBin(Jim_Interp *interp, struct JimExprState *e)
+{
+ Jim_Obj *B = ExprPop(e);
+ Jim_Obj *A = ExprPop(e);
+
+ jim_wide wC;
+
+ switch (e->opcode) {
+ case JIM_EXPROP_STREQ:
+ case JIM_EXPROP_STRNE: {
+ int Alen, Blen;
+ const char *sA = Jim_GetString(A, &Alen);
+ const char *sB = Jim_GetString(B, &Blen);
+
+ if (e->opcode == JIM_EXPROP_STREQ) {
+ wC = (Alen == Blen && memcmp(sA, sB, Alen) == 0);
+ }
+ else {
+ wC = (Alen != Blen || memcmp(sA, sB, Alen) != 0);
+ }
+ break;
+ }
+ case JIM_EXPROP_STRIN:
+ wC = JimSearchList(interp, B, A);
+ break;
+ case JIM_EXPROP_STRNI:
+ wC = !JimSearchList(interp, B, A);
+ break;
+ default:
+ abort();
+ }
+ ExprPush(e, Jim_NewIntObj(interp, wC));
+
+ Jim_DecrRefCount(interp, A);
+ Jim_DecrRefCount(interp, B);
+
+ return JIM_OK;
+}
+
+static int ExprBool(Jim_Interp *interp, Jim_Obj *obj)
+{
+ long l;
+ double d;
+
+ if (Jim_GetLong(interp, obj, &l) == JIM_OK) {
+ return l != 0;
+ }
+ if (Jim_GetDouble(interp, obj, &d) == JIM_OK) {
+ return d != 0;
+ }
+ return -1;
+}
+
+static int JimExprOpAndLeft(Jim_Interp *interp, struct JimExprState *e)
+{
+ Jim_Obj *skip = ExprPop(e);
+ Jim_Obj *A = ExprPop(e);
+ int rc = JIM_OK;
+
+ switch (ExprBool(interp, A)) {
+ case 0:
+
+ e->skip = JimWideValue(skip);
+ ExprPush(e, Jim_NewIntObj(interp, 0));
+ break;
+
+ case 1:
+
+ break;
+
+ case -1:
+
+ rc = JIM_ERR;
+ }
+ Jim_DecrRefCount(interp, A);
+ Jim_DecrRefCount(interp, skip);
+
+ return rc;
+}
+
+static int JimExprOpOrLeft(Jim_Interp *interp, struct JimExprState *e)
+{
+ Jim_Obj *skip = ExprPop(e);
+ Jim_Obj *A = ExprPop(e);
+ int rc = JIM_OK;
+
+ switch (ExprBool(interp, A)) {
+ case 0:
+
+ break;
+
+ case 1:
+
+ e->skip = JimWideValue(skip);
+ ExprPush(e, Jim_NewIntObj(interp, 1));
+ break;
+
+ case -1:
+
+ rc = JIM_ERR;
+ break;
+ }
+ Jim_DecrRefCount(interp, A);
+ Jim_DecrRefCount(interp, skip);
+
+ return rc;
+}
+
+static int JimExprOpAndOrRight(Jim_Interp *interp, struct JimExprState *e)
+{
+ Jim_Obj *A = ExprPop(e);
+ int rc = JIM_OK;
+
+ switch (ExprBool(interp, A)) {
+ case 0:
+ ExprPush(e, Jim_NewIntObj(interp, 0));
+ break;
+
+ case 1:
+ ExprPush(e, Jim_NewIntObj(interp, 1));
+ break;
+
+ case -1:
+
+ rc = JIM_ERR;
+ break;
+ }
+ Jim_DecrRefCount(interp, A);
+
+ return rc;
+}
+
+static int JimExprOpTernaryLeft(Jim_Interp *interp, struct JimExprState *e)
+{
+ Jim_Obj *skip = ExprPop(e);
+ Jim_Obj *A = ExprPop(e);
+ int rc = JIM_OK;
+
+
+ ExprPush(e, A);
+
+ switch (ExprBool(interp, A)) {
+ case 0:
+
+ e->skip = JimWideValue(skip);
+
+ ExprPush(e, Jim_NewIntObj(interp, 0));
+ break;
+
+ case 1:
+
+ break;
+
+ case -1:
+
+ rc = JIM_ERR;
+ break;
+ }
+ Jim_DecrRefCount(interp, A);
+ Jim_DecrRefCount(interp, skip);
+
+ return rc;
+}
+
+static int JimExprOpColonLeft(Jim_Interp *interp, struct JimExprState *e)
+{
+ Jim_Obj *skip = ExprPop(e);
+ Jim_Obj *B = ExprPop(e);
+ Jim_Obj *A = ExprPop(e);
+
+
+ if (ExprBool(interp, A)) {
+
+ e->skip = JimWideValue(skip);
+
+ ExprPush(e, B);
+ }
+
+ Jim_DecrRefCount(interp, skip);
+ Jim_DecrRefCount(interp, A);
+ Jim_DecrRefCount(interp, B);
+ return JIM_OK;
+}
+
+static int JimExprOpNull(Jim_Interp *interp, struct JimExprState *e)
+{
+ return JIM_OK;
+}
+
+enum
+{
+ LAZY_NONE,
+ LAZY_OP,
+ LAZY_LEFT,
+ LAZY_RIGHT
+};
+
+static const struct Jim_ExprOperator Jim_ExprOperators[] = {
+ {"*", 200, 2, JimExprOpBin, LAZY_NONE},
+ {"/", 200, 2, JimExprOpBin, LAZY_NONE},
+ {"%", 200, 2, JimExprOpIntBin, LAZY_NONE},
+
+ {"-", 100, 2, JimExprOpBin, LAZY_NONE},
+ {"+", 100, 2, JimExprOpBin, LAZY_NONE},
+
+ {"<<", 90, 2, JimExprOpIntBin, LAZY_NONE},
+ {">>", 90, 2, JimExprOpIntBin, LAZY_NONE},
+
+ {"<<<", 90, 2, JimExprOpIntBin, LAZY_NONE},
+ {">>>", 90, 2, JimExprOpIntBin, LAZY_NONE},
+
+ {"<", 80, 2, JimExprOpBin, LAZY_NONE},
+ {">", 80, 2, JimExprOpBin, LAZY_NONE},
+ {"<=", 80, 2, JimExprOpBin, LAZY_NONE},
+ {">=", 80, 2, JimExprOpBin, LAZY_NONE},
+
+ {"==", 70, 2, JimExprOpBin, LAZY_NONE},
+ {"!=", 70, 2, JimExprOpBin, LAZY_NONE},
+
+ {"&", 50, 2, JimExprOpIntBin, LAZY_NONE},
+ {"^", 49, 2, JimExprOpIntBin, LAZY_NONE},
+ {"|", 48, 2, JimExprOpIntBin, LAZY_NONE},
+
+ {"&&", 10, 2, NULL, LAZY_OP},
+ {NULL, 10, 2, JimExprOpAndLeft, LAZY_LEFT},
+ {NULL, 10, 2, JimExprOpAndOrRight, LAZY_RIGHT},
+
+ {"||", 9, 2, NULL, LAZY_OP},
+ {NULL, 9, 2, JimExprOpOrLeft, LAZY_LEFT},
+ {NULL, 9, 2, JimExprOpAndOrRight, LAZY_RIGHT},
+
+ {"?", 5, 2, JimExprOpNull, LAZY_OP},
+ {NULL, 5, 2, JimExprOpTernaryLeft, LAZY_LEFT},
+ {NULL, 5, 2, JimExprOpNull, LAZY_RIGHT},
+
+ {":", 5, 2, JimExprOpNull, LAZY_OP},
+ {NULL, 5, 2, JimExprOpColonLeft, LAZY_LEFT},
+ {NULL, 5, 2, JimExprOpNull, LAZY_RIGHT},
+
+ {"**", 250, 2, JimExprOpBin, LAZY_NONE},
+
+ {"eq", 60, 2, JimExprOpStrBin, LAZY_NONE},
+ {"ne", 60, 2, JimExprOpStrBin, LAZY_NONE},
+
+ {"in", 55, 2, JimExprOpStrBin, LAZY_NONE},
+ {"ni", 55, 2, JimExprOpStrBin, LAZY_NONE},
+
+ {"!", 300, 1, JimExprOpNumUnary, LAZY_NONE},
+ {"~", 300, 1, JimExprOpIntUnary, LAZY_NONE},
+ {NULL, 300, 1, JimExprOpNumUnary, LAZY_NONE},
+ {NULL, 300, 1, JimExprOpNumUnary, LAZY_NONE},
+
+
+
+ {"int", 400, 1, JimExprOpNumUnary, LAZY_NONE},
+ {"abs", 400, 1, JimExprOpNumUnary, LAZY_NONE},
+ {"double", 400, 1, JimExprOpNumUnary, LAZY_NONE},
+ {"round", 400, 1, JimExprOpNumUnary, LAZY_NONE},
+ {"rand", 400, 0, JimExprOpNone, LAZY_NONE},
+ {"srand", 400, 1, JimExprOpIntUnary, LAZY_NONE},
+
+#ifdef JIM_MATH_FUNCTIONS
+ {"sin", 400, 1, JimExprOpDoubleUnary, LAZY_NONE},
+ {"cos", 400, 1, JimExprOpDoubleUnary, LAZY_NONE},
+ {"tan", 400, 1, JimExprOpDoubleUnary, LAZY_NONE},
+ {"asin", 400, 1, JimExprOpDoubleUnary, LAZY_NONE},
+ {"acos", 400, 1, JimExprOpDoubleUnary, LAZY_NONE},
+ {"atan", 400, 1, JimExprOpDoubleUnary, LAZY_NONE},
+ {"sinh", 400, 1, JimExprOpDoubleUnary, LAZY_NONE},
+ {"cosh", 400, 1, JimExprOpDoubleUnary, LAZY_NONE},
+ {"tanh", 400, 1, JimExprOpDoubleUnary, LAZY_NONE},
+ {"ceil", 400, 1, JimExprOpDoubleUnary, LAZY_NONE},
+ {"floor", 400, 1, JimExprOpDoubleUnary, LAZY_NONE},
+ {"exp", 400, 1, JimExprOpDoubleUnary, LAZY_NONE},
+ {"log", 400, 1, JimExprOpDoubleUnary, LAZY_NONE},
+ {"log10", 400, 1, JimExprOpDoubleUnary, LAZY_NONE},
+ {"sqrt", 400, 1, JimExprOpDoubleUnary, LAZY_NONE},
+ {"pow", 400, 2, JimExprOpBin, LAZY_NONE},
+#endif
+};
+
+#define JIM_EXPR_OPERATORS_NUM \
+ (sizeof(Jim_ExprOperators)/sizeof(struct Jim_ExprOperator))
+
+static int JimParseExpression(struct JimParserCtx *pc)
+{
+
+ while (isspace(UCHAR(*pc->p)) || (*(pc->p) == '\\' && *(pc->p + 1) == '\n')) {
+ if (*pc->p == '\n') {
+ pc->linenr++;
+ }
+ pc->p++;
+ pc->len--;
+ }
+
+ if (pc->len == 0) {
+ pc->tstart = pc->tend = pc->p;
+ pc->tline = pc->linenr;
+ pc->tt = JIM_TT_EOL;
+ pc->eof = 1;
+ return JIM_OK;
+ }
+ switch (*(pc->p)) {
+ case '(':
+ pc->tt = JIM_TT_SUBEXPR_START;
+ goto singlechar;
+ case ')':
+ pc->tt = JIM_TT_SUBEXPR_END;
+ goto singlechar;
+ case ',':
+ pc->tt = JIM_TT_SUBEXPR_COMMA;
+singlechar:
+ pc->tstart = pc->tend = pc->p;
+ pc->tline = pc->linenr;
+ pc->p++;
+ pc->len--;
+ break;
+ case '[':
+ return JimParseCmd(pc);
+ case '$':
+ if (JimParseVar(pc) == JIM_ERR)
+ return JimParseExprOperator(pc);
+ else {
+
+ if (pc->tt == JIM_TT_EXPRSUGAR) {
+ return JIM_ERR;
+ }
+ return JIM_OK;
+ }
+ break;
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ case '.':
+ return JimParseExprNumber(pc);
+ case '"':
+ return JimParseQuote(pc);
+ case '{':
+ return JimParseBrace(pc);
+
+ case 'N':
+ case 'I':
+ case 'n':
+ case 'i':
+ if (JimParseExprIrrational(pc) == JIM_ERR)
+ return JimParseExprOperator(pc);
+ break;
+ default:
+ return JimParseExprOperator(pc);
+ break;
+ }
+ return JIM_OK;
+}
+
+static int JimParseExprNumber(struct JimParserCtx *pc)
+{
+ int allowdot = 1;
+ int base = 10;
+
+
+ pc->tt = JIM_TT_EXPR_INT;
+ pc->tstart = pc->p;
+ pc->tline = pc->linenr;
+
+
+ if (pc->p[0] == '0') {
+ switch (pc->p[1]) {
+ case 'x':
+ case 'X':
+ base = 16;
+ allowdot = 0;
+ pc->p += 2;
+ pc->len -= 2;
+ break;
+ case 'o':
+ case 'O':
+ base = 8;
+ allowdot = 0;
+ pc->p += 2;
+ pc->len -= 2;
+ break;
+ case 'b':
+ case 'B':
+ base = 2;
+ allowdot = 0;
+ pc->p += 2;
+ pc->len -= 2;
+ break;
+ }
+ }
+
+ while (isdigit(UCHAR(*pc->p))
+ || (base == 16 && isxdigit(UCHAR(*pc->p)))
+ || (base == 8 && *pc->p >= '0' && *pc->p <= '7')
+ || (base == 2 && (*pc->p == '0' || *pc->p == '1'))
+ || (allowdot && *pc->p == '.')
+ ) {
+ if (*pc->p == '.') {
+ allowdot = 0;
+ pc->tt = JIM_TT_EXPR_DOUBLE;
+ }
+ pc->p++;
+ pc->len--;
+ if (base == 10 && (*pc->p == 'e' || *pc->p == 'E') && (pc->p[1] == '-' || pc->p[1] == '+'
+ || isdigit(UCHAR(pc->p[1])))) {
+ pc->p += 2;
+ pc->len -= 2;
+ pc->tt = JIM_TT_EXPR_DOUBLE;
+ }
+ }
+ pc->tend = pc->p - 1;
+ return JIM_OK;
+}
+
+static int JimParseExprIrrational(struct JimParserCtx *pc)
+{
+ const char *Tokens[] = { "NaN", "nan", "NAN", "Inf", "inf", "INF", NULL };
+ const char **token;
+
+ for (token = Tokens; *token != NULL; token++) {
+ int len = strlen(*token);
+
+ if (strncmp(*token, pc->p, len) == 0) {
+ pc->tstart = pc->p;
+ pc->tend = pc->p + len - 1;
+ pc->p += len;
+ pc->len -= len;
+ pc->tline = pc->linenr;
+ pc->tt = JIM_TT_EXPR_DOUBLE;
+ return JIM_OK;
+ }
+ }
+ return JIM_ERR;
+}
+
+static int JimParseExprOperator(struct JimParserCtx *pc)
+{
+ int i;
+ int bestIdx = -1, bestLen = 0;
+
+
+ for (i = 0; i < (signed)JIM_EXPR_OPERATORS_NUM; i++) {
+ const char *opname;
+ int oplen;
+
+ opname = Jim_ExprOperators[i].name;
+ if (opname == NULL) {
+ continue;
+ }
+ oplen = strlen(opname);
+
+ if (strncmp(opname, pc->p, oplen) == 0 && oplen > bestLen) {
+ bestIdx = i + JIM_TT_EXPR_OP;
+ bestLen = oplen;
+ }
+ }
+ if (bestIdx == -1) {
+ return JIM_ERR;
+ }
+
+
+ if (bestIdx >= JIM_EXPROP_FUNC_FIRST) {
+ const char *p = pc->p + bestLen;
+ int len = pc->len - bestLen;
+
+ while (len && isspace(UCHAR(*p))) {
+ len--;
+ p++;
+ }
+ if (*p != '(') {
+ return JIM_ERR;
+ }
+ }
+ pc->tstart = pc->p;
+ pc->tend = pc->p + bestLen - 1;
+ pc->p += bestLen;
+ pc->len -= bestLen;
+ pc->tline = pc->linenr;
+
+ pc->tt = bestIdx;
+ return JIM_OK;
+}
+
+static const struct Jim_ExprOperator *JimExprOperatorInfoByOpcode(int opcode)
+{
+ static Jim_ExprOperator dummy_op;
+ if (opcode < JIM_TT_EXPR_OP) {
+ return &dummy_op;
+ }
+ return &Jim_ExprOperators[opcode - JIM_TT_EXPR_OP];
+}
+
+const char *jim_tt_name(int type)
+{
+ static const char * const tt_names[JIM_TT_EXPR_OP] =
+ { "NIL", "STR", "ESC", "VAR", "ARY", "CMD", "SEP", "EOL", "EOF", "LIN", "WRD", "(((", ")))", ",,,", "INT",
+ "DBL", "$()" };
+ if (type < JIM_TT_EXPR_OP) {
+ return tt_names[type];
+ }
+ else {
+ const struct Jim_ExprOperator *op = JimExprOperatorInfoByOpcode(type);
+ static char buf[20];
+
+ if (op->name) {
+ return op->name;
+ }
+ sprintf(buf, "(%d)", type);
+ return buf;
+ }
+}
+
+static void FreeExprInternalRep(Jim_Interp *interp, Jim_Obj *objPtr);
+static void DupExprInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr);
+static int SetExprFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr);
+
+static const Jim_ObjType exprObjType = {
+ "expression",
+ FreeExprInternalRep,
+ DupExprInternalRep,
+ NULL,
+ JIM_TYPE_REFERENCES,
+};
+
+
+typedef struct ExprByteCode
+{
+ int len;
+ ScriptToken *token;
+ int inUse;
+} ExprByteCode;
+
+static void ExprFreeByteCode(Jim_Interp *interp, ExprByteCode * expr)
+{
+ int i;
+
+ for (i = 0; i < expr->len; i++) {
+ Jim_DecrRefCount(interp, expr->token[i].objPtr);
+ }
+ Jim_Free(expr->token);
+ Jim_Free(expr);
+}
+
+static void FreeExprInternalRep(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+ ExprByteCode *expr = (void *)objPtr->internalRep.ptr;
+
+ if (expr) {
+ if (--expr->inUse != 0) {
+ return;
+ }
+
+ ExprFreeByteCode(interp, expr);
+ }
+}
+
+static void DupExprInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr)
+{
+ JIM_NOTUSED(interp);
+ JIM_NOTUSED(srcPtr);
+
+
+ dupPtr->typePtr = NULL;
+}
+
+
+static int ExprCheckCorrectness(ExprByteCode * expr)
+{
+ int i;
+ int stacklen = 0;
+ int ternary = 0;
+
+ for (i = 0; i < expr->len; i++) {
+ ScriptToken *t = &expr->token[i];
+ const struct Jim_ExprOperator *op = JimExprOperatorInfoByOpcode(t->type);
+
+ stacklen -= op->arity;
+ if (stacklen < 0) {
+ break;
+ }
+ if (t->type == JIM_EXPROP_TERNARY || t->type == JIM_EXPROP_TERNARY_LEFT) {
+ ternary++;
+ }
+ else if (t->type == JIM_EXPROP_COLON || t->type == JIM_EXPROP_COLON_LEFT) {
+ ternary--;
+ }
+
+
+ stacklen++;
+ }
+ if (stacklen != 1 || ternary != 0) {
+ return JIM_ERR;
+ }
+ return JIM_OK;
+}
+
+static int ExprAddLazyOperator(Jim_Interp *interp, ExprByteCode * expr, ParseToken *t)
+{
+ int i;
+
+ int leftindex, arity, offset;
+
+
+ leftindex = expr->len - 1;
+
+ arity = 1;
+ while (arity) {
+ ScriptToken *tt = &expr->token[leftindex];
+
+ if (tt->type >= JIM_TT_EXPR_OP) {
+ arity += JimExprOperatorInfoByOpcode(tt->type)->arity;
+ }
+ arity--;
+ if (--leftindex < 0) {
+ return JIM_ERR;
+ }
+ }
+ leftindex++;
+
+
+ memmove(&expr->token[leftindex + 2], &expr->token[leftindex],
+ sizeof(*expr->token) * (expr->len - leftindex));
+ expr->len += 2;
+ offset = (expr->len - leftindex) - 1;
+
+ expr->token[leftindex + 1].type = t->type + 1;
+ expr->token[leftindex + 1].objPtr = interp->emptyObj;
+
+ expr->token[leftindex].type = JIM_TT_EXPR_INT;
+ expr->token[leftindex].objPtr = Jim_NewIntObj(interp, offset);
+
+
+ expr->token[expr->len].objPtr = interp->emptyObj;
+ expr->token[expr->len].type = t->type + 2;
+ expr->len++;
+
+
+ for (i = leftindex - 1; i > 0; i--) {
+ const struct Jim_ExprOperator *op = JimExprOperatorInfoByOpcode(expr->token[i].type);
+ if (op->lazy == LAZY_LEFT) {
+ if (JimWideValue(expr->token[i - 1].objPtr) + i - 1 >= leftindex) {
+ JimWideValue(expr->token[i - 1].objPtr) += 2;
+ }
+ }
+ }
+ return JIM_OK;
+}
+
+static int ExprAddOperator(Jim_Interp *interp, ExprByteCode * expr, ParseToken *t)
+{
+ struct ScriptToken *token = &expr->token[expr->len];
+ const struct Jim_ExprOperator *op = JimExprOperatorInfoByOpcode(t->type);
+
+ if (op->lazy == LAZY_OP) {
+ if (ExprAddLazyOperator(interp, expr, t) != JIM_OK) {
+ Jim_SetResultFormatted(interp, "Expression has bad operands to %s", op->name);
+ return JIM_ERR;
+ }
+ }
+ else {
+ token->objPtr = interp->emptyObj;
+ token->type = t->type;
+ expr->len++;
+ }
+ return JIM_OK;
+}
+
+static int ExprTernaryGetColonLeftIndex(ExprByteCode *expr, int right_index)
+{
+ int ternary_count = 1;
+
+ right_index--;
+
+ while (right_index > 1) {
+ if (expr->token[right_index].type == JIM_EXPROP_TERNARY_LEFT) {
+ ternary_count--;
+ }
+ else if (expr->token[right_index].type == JIM_EXPROP_COLON_RIGHT) {
+ ternary_count++;
+ }
+ else if (expr->token[right_index].type == JIM_EXPROP_COLON_LEFT && ternary_count == 1) {
+ return right_index;
+ }
+ right_index--;
+ }
+
+
+ return -1;
+}
+
+static int ExprTernaryGetMoveIndices(ExprByteCode *expr, int right_index, int *prev_right_index, int *prev_left_index)
+{
+ int i = right_index - 1;
+ int ternary_count = 1;
+
+ while (i > 1) {
+ if (expr->token[i].type == JIM_EXPROP_TERNARY_LEFT) {
+ if (--ternary_count == 0 && expr->token[i - 2].type == JIM_EXPROP_COLON_RIGHT) {
+ *prev_right_index = i - 2;
+ *prev_left_index = ExprTernaryGetColonLeftIndex(expr, *prev_right_index);
+ return 1;
+ }
+ }
+ else if (expr->token[i].type == JIM_EXPROP_COLON_RIGHT) {
+ if (ternary_count == 0) {
+ return 0;
+ }
+ ternary_count++;
+ }
+ i--;
+ }
+ return 0;
+}
+
+static void ExprTernaryReorderExpression(Jim_Interp *interp, ExprByteCode *expr)
+{
+ int i;
+
+ for (i = expr->len - 1; i > 1; i--) {
+ int prev_right_index;
+ int prev_left_index;
+ int j;
+ ScriptToken tmp;
+
+ if (expr->token[i].type != JIM_EXPROP_COLON_RIGHT) {
+ continue;
+ }
+
+
+ if (ExprTernaryGetMoveIndices(expr, i, &prev_right_index, &prev_left_index) == 0) {
+ continue;
+ }
+
+ tmp = expr->token[prev_right_index];
+ for (j = prev_right_index; j < i; j++) {
+ expr->token[j] = expr->token[j + 1];
+ }
+ expr->token[i] = tmp;
+
+ JimWideValue(expr->token[prev_left_index-1].objPtr) += (i - prev_right_index);
+
+
+ i++;
+ }
+}
+
+static ExprByteCode *ExprCreateByteCode(Jim_Interp *interp, const ParseTokenList *tokenlist, Jim_Obj *fileNameObj)
+{
+ Jim_Stack stack;
+ ExprByteCode *expr;
+ int ok = 1;
+ int i;
+ int prevtt = JIM_TT_NONE;
+ int have_ternary = 0;
+
+
+ int count = tokenlist->count - 1;
+
+ expr = Jim_Alloc(sizeof(*expr));
+ expr->inUse = 1;
+ expr->len = 0;
+
+ Jim_InitStack(&stack);
+
+ for (i = 0; i < tokenlist->count; i++) {
+ ParseToken *t = &tokenlist->list[i];
+ const struct Jim_ExprOperator *op = JimExprOperatorInfoByOpcode(t->type);
+
+ if (op->lazy == LAZY_OP) {
+ count += 2;
+
+ if (t->type == JIM_EXPROP_TERNARY) {
+ have_ternary = 1;
+ }
+ }
+ }
+
+ expr->token = Jim_Alloc(sizeof(ScriptToken) * count);
+
+ for (i = 0; i < tokenlist->count && ok; i++) {
+ ParseToken *t = &tokenlist->list[i];
+
+
+ struct ScriptToken *token = &expr->token[expr->len];
+
+ if (t->type == JIM_TT_EOL) {
+ break;
+ }
+
+ switch (t->type) {
+ case JIM_TT_STR:
+ case JIM_TT_ESC:
+ case JIM_TT_VAR:
+ case JIM_TT_DICTSUGAR:
+ case JIM_TT_EXPRSUGAR:
+ case JIM_TT_CMD:
+ token->type = t->type;
+strexpr:
+ token->objPtr = Jim_NewStringObj(interp, t->token, t->len);
+ if (t->type == JIM_TT_CMD) {
+
+ JimSetSourceInfo(interp, token->objPtr, fileNameObj, t->line);
+ }
+ expr->len++;
+ break;
+
+ case JIM_TT_EXPR_INT:
+ case JIM_TT_EXPR_DOUBLE:
+ {
+ char *endptr;
+ if (t->type == JIM_TT_EXPR_INT) {
+ token->objPtr = Jim_NewIntObj(interp, jim_strtoull(t->token, &endptr));
+ }
+ else {
+ token->objPtr = Jim_NewDoubleObj(interp, strtod(t->token, &endptr));
+ }
+ if (endptr != t->token + t->len) {
+
+ Jim_FreeNewObj(interp, token->objPtr);
+ token->type = JIM_TT_STR;
+ goto strexpr;
+ }
+ token->type = t->type;
+ expr->len++;
+ }
+ break;
+
+ case JIM_TT_SUBEXPR_START:
+ Jim_StackPush(&stack, t);
+ prevtt = JIM_TT_NONE;
+ continue;
+
+ case JIM_TT_SUBEXPR_COMMA:
+
+ continue;
+
+ case JIM_TT_SUBEXPR_END:
+ ok = 0;
+ while (Jim_StackLen(&stack)) {
+ ParseToken *tt = Jim_StackPop(&stack);
+
+ if (tt->type == JIM_TT_SUBEXPR_START) {
+ ok = 1;
+ break;
+ }
+
+ if (ExprAddOperator(interp, expr, tt) != JIM_OK) {
+ goto err;
+ }
+ }
+ if (!ok) {
+ Jim_SetResultString(interp, "Unexpected close parenthesis", -1);
+ goto err;
+ }
+ break;
+
+
+ default:{
+
+ const struct Jim_ExprOperator *op;
+ ParseToken *tt;
+
+
+ if (prevtt == JIM_TT_NONE || prevtt >= JIM_TT_EXPR_OP) {
+ if (t->type == JIM_EXPROP_SUB) {
+ t->type = JIM_EXPROP_UNARYMINUS;
+ }
+ else if (t->type == JIM_EXPROP_ADD) {
+ t->type = JIM_EXPROP_UNARYPLUS;
+ }
+ }
+
+ op = JimExprOperatorInfoByOpcode(t->type);
+
+
+ while ((tt = Jim_StackPeek(&stack)) != NULL) {
+ const struct Jim_ExprOperator *tt_op =
+ JimExprOperatorInfoByOpcode(tt->type);
+
+
+
+ if (op->arity != 1 && tt_op->precedence >= op->precedence) {
+ if (ExprAddOperator(interp, expr, tt) != JIM_OK) {
+ ok = 0;
+ goto err;
+ }
+ Jim_StackPop(&stack);
+ }
+ else {
+ break;
+ }
+ }
+ Jim_StackPush(&stack, t);
+ break;
+ }
+ }
+ prevtt = t->type;
+ }
+
+
+ while (Jim_StackLen(&stack)) {
+ ParseToken *tt = Jim_StackPop(&stack);
+
+ if (tt->type == JIM_TT_SUBEXPR_START) {
+ ok = 0;
+ Jim_SetResultString(interp, "Missing close parenthesis", -1);
+ goto err;
+ }
+ if (ExprAddOperator(interp, expr, tt) != JIM_OK) {
+ ok = 0;
+ goto err;
+ }
+ }
+
+ if (have_ternary) {
+ ExprTernaryReorderExpression(interp, expr);
+ }
+
+ err:
+
+ Jim_FreeStack(&stack);
+
+ for (i = 0; i < expr->len; i++) {
+ Jim_IncrRefCount(expr->token[i].objPtr);
+ }
+
+ if (!ok) {
+ ExprFreeByteCode(interp, expr);
+ return NULL;
+ }
+
+ return expr;
+}
+
+
+static int SetExprFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr)
+{
+ int exprTextLen;
+ const char *exprText;
+ struct JimParserCtx parser;
+ struct ExprByteCode *expr;
+ ParseTokenList tokenlist;
+ int line;
+ Jim_Obj *fileNameObj;
+ int rc = JIM_ERR;
+
+
+ if (objPtr->typePtr == &sourceObjType) {
+ fileNameObj = objPtr->internalRep.sourceValue.fileNameObj;
+ line = objPtr->internalRep.sourceValue.lineNumber;
+ }
+ else {
+ fileNameObj = interp->emptyObj;
+ line = 1;
+ }
+ Jim_IncrRefCount(fileNameObj);
+
+ exprText = Jim_GetString(objPtr, &exprTextLen);
+
+
+ ScriptTokenListInit(&tokenlist);
+
+ JimParserInit(&parser, exprText, exprTextLen, line);
+ while (!parser.eof) {
+ if (JimParseExpression(&parser) != JIM_OK) {
+ ScriptTokenListFree(&tokenlist);
+ invalidexpr:
+ Jim_SetResultFormatted(interp, "syntax error in expression: \"%#s\"", objPtr);
+ expr = NULL;
+ goto err;
+ }
+
+ ScriptAddToken(&tokenlist, parser.tstart, parser.tend - parser.tstart + 1, parser.tt,
+ parser.tline);
+ }
+
+#ifdef DEBUG_SHOW_EXPR_TOKENS
+ {
+ int i;
+ printf("==== Expr Tokens ====\n");
+ for (i = 0; i < tokenlist.count; i++) {
+ printf("[%2d]@%d %s '%.*s'\n", i, tokenlist.list[i].line, jim_tt_name(tokenlist.list[i].type),
+ tokenlist.list[i].len, tokenlist.list[i].token);
+ }
+ }
+#endif
+
+
+ expr = ExprCreateByteCode(interp, &tokenlist, fileNameObj);
+
+
+ ScriptTokenListFree(&tokenlist);
+
+ if (!expr) {
+ goto err;
+ }
+
+#ifdef DEBUG_SHOW_EXPR
+ {
+ int i;
+
+ printf("==== Expr ====\n");
+ for (i = 0; i < expr->len; i++) {
+ ScriptToken *t = &expr->token[i];
+
+ printf("[%2d] %s '%s'\n", i, jim_tt_name(t->type), Jim_String(t->objPtr));
+ }
+ }
+#endif
+
+
+ if (ExprCheckCorrectness(expr) != JIM_OK) {
+ ExprFreeByteCode(interp, expr);
+ goto invalidexpr;
+ }
+
+ rc = JIM_OK;
+
+ err:
+
+ Jim_DecrRefCount(interp, fileNameObj);
+ Jim_FreeIntRep(interp, objPtr);
+ Jim_SetIntRepPtr(objPtr, expr);
+ objPtr->typePtr = &exprObjType;
+ return rc;
+}
+
+static ExprByteCode *JimGetExpression(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+ if (objPtr->typePtr != &exprObjType) {
+ if (SetExprFromAny(interp, objPtr) != JIM_OK) {
+ return NULL;
+ }
+ }
+ return (ExprByteCode *) Jim_GetIntRepPtr(objPtr);
+}
+
+#define JIM_EE_STATICSTACK_LEN 10
+
+int Jim_EvalExpression(Jim_Interp *interp, Jim_Obj *exprObjPtr, Jim_Obj **exprResultPtrPtr)
+{
+ ExprByteCode *expr;
+ Jim_Obj *staticStack[JIM_EE_STATICSTACK_LEN];
+ int i;
+ int retcode = JIM_OK;
+ struct JimExprState e;
+
+ expr = JimGetExpression(interp, exprObjPtr);
+ if (!expr) {
+ return JIM_ERR;
+ }
+
+#ifdef JIM_OPTIMIZATION
+ {
+ Jim_Obj *objPtr;
+
+
+ switch (expr->len) {
+ case 1:
+ if (expr->token[0].type == JIM_TT_EXPR_INT) {
+ *exprResultPtrPtr = expr->token[0].objPtr;
+ Jim_IncrRefCount(*exprResultPtrPtr);
+ return JIM_OK;
+ }
+ if (expr->token[0].type == JIM_TT_VAR) {
+ objPtr = Jim_GetVariable(interp, expr->token[0].objPtr, JIM_ERRMSG);
+ if (objPtr) {
+ *exprResultPtrPtr = objPtr;
+ Jim_IncrRefCount(*exprResultPtrPtr);
+ return JIM_OK;
+ }
+ }
+ break;
+
+ case 2:
+ if (expr->token[1].type == JIM_EXPROP_NOT && expr->token[0].type == JIM_TT_VAR) {
+ jim_wide wideValue;
+
+ objPtr = Jim_GetVariable(interp, expr->token[0].objPtr, JIM_NONE);
+ if (objPtr && JimIsWide(objPtr)
+ && Jim_GetWide(interp, objPtr, &wideValue) == JIM_OK) {
+ *exprResultPtrPtr = wideValue ? interp->falseObj : interp->trueObj;
+ Jim_IncrRefCount(*exprResultPtrPtr);
+ return JIM_OK;
+ }
+ }
+ break;
+
+ case 3:
+ if (expr->token[0].type == JIM_TT_VAR && (expr->token[1].type == JIM_TT_EXPR_INT
+ || expr->token[1].type == JIM_TT_VAR)) {
+ switch (expr->token[2].type) {
+ case JIM_EXPROP_LT:
+ case JIM_EXPROP_LTE:
+ case JIM_EXPROP_GT:
+ case JIM_EXPROP_GTE:
+ case JIM_EXPROP_NUMEQ:
+ case JIM_EXPROP_NUMNE:{
+
+ jim_wide wideValueA;
+ jim_wide wideValueB;
+
+ objPtr = Jim_GetVariable(interp, expr->token[0].objPtr, JIM_NONE);
+ if (objPtr && JimIsWide(objPtr)
+ && Jim_GetWide(interp, objPtr, &wideValueA) == JIM_OK) {
+ if (expr->token[1].type == JIM_TT_VAR) {
+ objPtr =
+ Jim_GetVariable(interp, expr->token[1].objPtr,
+ JIM_NONE);
+ }
+ else {
+ objPtr = expr->token[1].objPtr;
+ }
+ if (objPtr && JimIsWide(objPtr)
+ && Jim_GetWide(interp, objPtr, &wideValueB) == JIM_OK) {
+ int cmpRes;
+
+ switch (expr->token[2].type) {
+ case JIM_EXPROP_LT:
+ cmpRes = wideValueA < wideValueB;
+ break;
+ case JIM_EXPROP_LTE:
+ cmpRes = wideValueA <= wideValueB;
+ break;
+ case JIM_EXPROP_GT:
+ cmpRes = wideValueA > wideValueB;
+ break;
+ case JIM_EXPROP_GTE:
+ cmpRes = wideValueA >= wideValueB;
+ break;
+ case JIM_EXPROP_NUMEQ:
+ cmpRes = wideValueA == wideValueB;
+ break;
+ case JIM_EXPROP_NUMNE:
+ cmpRes = wideValueA != wideValueB;
+ break;
+ default:
+ cmpRes = 0;
+ }
+ *exprResultPtrPtr =
+ cmpRes ? interp->trueObj : interp->falseObj;
+ Jim_IncrRefCount(*exprResultPtrPtr);
+ return JIM_OK;
+ }
+ }
+ }
+ }
+ }
+ break;
+ }
+ }
+#endif
+
+ expr->inUse++;
+
+
+
+ if (expr->len > JIM_EE_STATICSTACK_LEN)
+ e.stack = Jim_Alloc(sizeof(Jim_Obj *) * expr->len);
+ else
+ e.stack = staticStack;
+
+ e.stacklen = 0;
+
+
+ for (i = 0; i < expr->len && retcode == JIM_OK; i++) {
+ Jim_Obj *objPtr;
+
+ switch (expr->token[i].type) {
+ case JIM_TT_EXPR_INT:
+ case JIM_TT_EXPR_DOUBLE:
+ case JIM_TT_STR:
+ ExprPush(&e, expr->token[i].objPtr);
+ break;
+
+ case JIM_TT_VAR:
+ objPtr = Jim_GetVariable(interp, expr->token[i].objPtr, JIM_ERRMSG);
+ if (objPtr) {
+ ExprPush(&e, objPtr);
+ }
+ else {
+ retcode = JIM_ERR;
+ }
+ break;
+
+ case JIM_TT_DICTSUGAR:
+ objPtr = JimExpandDictSugar(interp, expr->token[i].objPtr);
+ if (objPtr) {
+ ExprPush(&e, objPtr);
+ }
+ else {
+ retcode = JIM_ERR;
+ }
+ break;
+
+ case JIM_TT_ESC:
+ retcode = Jim_SubstObj(interp, expr->token[i].objPtr, &objPtr, JIM_NONE);
+ if (retcode == JIM_OK) {
+ ExprPush(&e, objPtr);
+ }
+ break;
+
+ case JIM_TT_CMD:
+ retcode = Jim_EvalObj(interp, expr->token[i].objPtr);
+ if (retcode == JIM_OK) {
+ ExprPush(&e, Jim_GetResult(interp));
+ }
+ break;
+
+ default:{
+
+ e.skip = 0;
+ e.opcode = expr->token[i].type;
+
+ retcode = JimExprOperatorInfoByOpcode(e.opcode)->funcop(interp, &e);
+
+ i += e.skip;
+ continue;
+ }
+ }
+ }
+
+ expr->inUse--;
+
+ if (retcode == JIM_OK) {
+ *exprResultPtrPtr = ExprPop(&e);
+ }
+ else {
+ for (i = 0; i < e.stacklen; i++) {
+ Jim_DecrRefCount(interp, e.stack[i]);
+ }
+ }
+ if (e.stack != staticStack) {
+ Jim_Free(e.stack);
+ }
+ return retcode;
+}
+
+int Jim_GetBoolFromExpr(Jim_Interp *interp, Jim_Obj *exprObjPtr, int *boolPtr)
+{
+ int retcode;
+ jim_wide wideValue;
+ double doubleValue;
+ Jim_Obj *exprResultPtr;
+
+ retcode = Jim_EvalExpression(interp, exprObjPtr, &exprResultPtr);
+ if (retcode != JIM_OK)
+ return retcode;
+
+ if (JimGetWideNoErr(interp, exprResultPtr, &wideValue) != JIM_OK) {
+ if (Jim_GetDouble(interp, exprResultPtr, &doubleValue) != JIM_OK) {
+ Jim_DecrRefCount(interp, exprResultPtr);
+ return JIM_ERR;
+ }
+ else {
+ Jim_DecrRefCount(interp, exprResultPtr);
+ *boolPtr = doubleValue != 0;
+ return JIM_OK;
+ }
+ }
+ *boolPtr = wideValue != 0;
+
+ Jim_DecrRefCount(interp, exprResultPtr);
+ return JIM_OK;
+}
+
+
+
+
+typedef struct ScanFmtPartDescr
+{
+ char type;
+ char modifier;
+ size_t width;
+ int pos;
+ char *arg;
+ char *prefix;
+} ScanFmtPartDescr;
+
+
+typedef struct ScanFmtStringObj
+{
+ jim_wide size;
+ char *stringRep;
+ size_t count;
+ size_t convCount;
+ size_t maxPos;
+ const char *error;
+ char *scratch;
+ ScanFmtPartDescr descr[1];
+} ScanFmtStringObj;
+
+
+static void FreeScanFmtInternalRep(Jim_Interp *interp, Jim_Obj *objPtr);
+static void DupScanFmtInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr);
+static void UpdateStringOfScanFmt(Jim_Obj *objPtr);
+
+static const Jim_ObjType scanFmtStringObjType = {
+ "scanformatstring",
+ FreeScanFmtInternalRep,
+ DupScanFmtInternalRep,
+ UpdateStringOfScanFmt,
+ JIM_TYPE_NONE,
+};
+
+void FreeScanFmtInternalRep(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+ JIM_NOTUSED(interp);
+ Jim_Free((char *)objPtr->internalRep.ptr);
+ objPtr->internalRep.ptr = 0;
+}
+
+void DupScanFmtInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr)
+{
+ size_t size = (size_t) ((ScanFmtStringObj *) srcPtr->internalRep.ptr)->size;
+ ScanFmtStringObj *newVec = (ScanFmtStringObj *) Jim_Alloc(size);
+
+ JIM_NOTUSED(interp);
+ memcpy(newVec, srcPtr->internalRep.ptr, size);
+ dupPtr->internalRep.ptr = newVec;
+ dupPtr->typePtr = &scanFmtStringObjType;
+}
+
+void UpdateStringOfScanFmt(Jim_Obj *objPtr)
+{
+ char *bytes = ((ScanFmtStringObj *) objPtr->internalRep.ptr)->stringRep;
+
+ objPtr->bytes = Jim_StrDup(bytes);
+ objPtr->length = strlen(bytes);
+}
+
+
+static int SetScanFmtFromAny(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+ ScanFmtStringObj *fmtObj;
+ char *buffer;
+ int maxCount, i, approxSize, lastPos = -1;
+ const char *fmt = objPtr->bytes;
+ int maxFmtLen = objPtr->length;
+ const char *fmtEnd = fmt + maxFmtLen;
+ int curr;
+
+ Jim_FreeIntRep(interp, objPtr);
+
+ for (i = 0, maxCount = 0; i < maxFmtLen; ++i)
+ if (fmt[i] == '%')
+ ++maxCount;
+
+ approxSize = sizeof(ScanFmtStringObj)
+ +(maxCount + 1) * sizeof(ScanFmtPartDescr)
+ +maxFmtLen * sizeof(char) + 3 + 1
+ + maxFmtLen * sizeof(char) + 1
+ + maxFmtLen * sizeof(char)
+ +(maxCount + 1) * sizeof(char)
+ +1;
+ fmtObj = (ScanFmtStringObj *) Jim_Alloc(approxSize);
+ memset(fmtObj, 0, approxSize);
+ fmtObj->size = approxSize;
+ fmtObj->maxPos = 0;
+ fmtObj->scratch = (char *)&fmtObj->descr[maxCount + 1];
+ fmtObj->stringRep = fmtObj->scratch + maxFmtLen + 3 + 1;
+ memcpy(fmtObj->stringRep, fmt, maxFmtLen);
+ buffer = fmtObj->stringRep + maxFmtLen + 1;
+ objPtr->internalRep.ptr = fmtObj;
+ objPtr->typePtr = &scanFmtStringObjType;
+ for (i = 0, curr = 0; fmt < fmtEnd; ++fmt) {
+ int width = 0, skip;
+ ScanFmtPartDescr *descr = &fmtObj->descr[curr];
+
+ fmtObj->count++;
+ descr->width = 0;
+
+ if (*fmt != '%' || fmt[1] == '%') {
+ descr->type = 0;
+ descr->prefix = &buffer[i];
+ for (; fmt < fmtEnd; ++fmt) {
+ if (*fmt == '%') {
+ if (fmt[1] != '%')
+ break;
+ ++fmt;
+ }
+ buffer[i++] = *fmt;
+ }
+ buffer[i++] = 0;
+ }
+
+ ++fmt;
+
+ if (fmt >= fmtEnd)
+ goto done;
+ descr->pos = 0;
+ if (*fmt == '*') {
+ descr->pos = -1;
+ ++fmt;
+ }
+ else
+ fmtObj->convCount++;
+
+ if (sscanf(fmt, "%d%n", &width, &skip) == 1) {
+ fmt += skip;
+
+ if (descr->pos != -1 && *fmt == '$') {
+ int prev;
+
+ ++fmt;
+ descr->pos = width;
+ width = 0;
+
+ if ((lastPos == 0 && descr->pos > 0)
+ || (lastPos > 0 && descr->pos == 0)) {
+ fmtObj->error = "cannot mix \"%\" and \"%n$\" conversion specifiers";
+ return JIM_ERR;
+ }
+
+ for (prev = 0; prev < curr; ++prev) {
+ if (fmtObj->descr[prev].pos == -1)
+ continue;
+ if (fmtObj->descr[prev].pos == descr->pos) {
+ fmtObj->error =
+ "variable is assigned by multiple \"%n$\" conversion specifiers";
+ return JIM_ERR;
+ }
+ }
+
+ if (sscanf(fmt, "%d%n", &width, &skip) == 1) {
+ descr->width = width;
+ fmt += skip;
+ }
+ if (descr->pos > 0 && (size_t) descr->pos > fmtObj->maxPos)
+ fmtObj->maxPos = descr->pos;
+ }
+ else {
+
+ descr->width = width;
+ }
+ }
+
+ if (lastPos == -1)
+ lastPos = descr->pos;
+
+ if (*fmt == '[') {
+ int swapped = 1, beg = i, end, j;
+
+ descr->type = '[';
+ descr->arg = &buffer[i];
+ ++fmt;
+ if (*fmt == '^')
+ buffer[i++] = *fmt++;
+ if (*fmt == ']')
+ buffer[i++] = *fmt++;
+ while (*fmt && *fmt != ']')
+ buffer[i++] = *fmt++;
+ if (*fmt != ']') {
+ fmtObj->error = "unmatched [ in format string";
+ return JIM_ERR;
+ }
+ end = i;
+ buffer[i++] = 0;
+
+ while (swapped) {
+ swapped = 0;
+ for (j = beg + 1; j < end - 1; ++j) {
+ if (buffer[j] == '-' && buffer[j - 1] > buffer[j + 1]) {
+ char tmp = buffer[j - 1];
+
+ buffer[j - 1] = buffer[j + 1];
+ buffer[j + 1] = tmp;
+ swapped = 1;
+ }
+ }
+ }
+ }
+ else {
+
+ if (strchr("hlL", *fmt) != 0)
+ descr->modifier = tolower((int)*fmt++);
+
+ descr->type = *fmt;
+ if (strchr("efgcsndoxui", *fmt) == 0) {
+ fmtObj->error = "bad scan conversion character";
+ return JIM_ERR;
+ }
+ else if (*fmt == 'c' && descr->width != 0) {
+ fmtObj->error = "field width may not be specified in %c " "conversion";
+ return JIM_ERR;
+ }
+ else if (*fmt == 'u' && descr->modifier == 'l') {
+ fmtObj->error = "unsigned wide not supported";
+ return JIM_ERR;
+ }
+ }
+ curr++;
+ }
+ done:
+ return JIM_OK;
+}
+
+
+
+#define FormatGetCnvCount(_fo_) \
+ ((ScanFmtStringObj*)((_fo_)->internalRep.ptr))->convCount
+#define FormatGetMaxPos(_fo_) \
+ ((ScanFmtStringObj*)((_fo_)->internalRep.ptr))->maxPos
+#define FormatGetError(_fo_) \
+ ((ScanFmtStringObj*)((_fo_)->internalRep.ptr))->error
+
+static Jim_Obj *JimScanAString(Jim_Interp *interp, const char *sdescr, const char *str)
+{
+ char *buffer = Jim_StrDup(str);
+ char *p = buffer;
+
+ while (*str) {
+ int c;
+ int n;
+
+ if (!sdescr && isspace(UCHAR(*str)))
+ break;
+
+ n = utf8_tounicode(str, &c);
+ if (sdescr && !JimCharsetMatch(sdescr, c, JIM_CHARSET_SCAN))
+ break;
+ while (n--)
+ *p++ = *str++;
+ }
+ *p = 0;
+ return Jim_NewStringObjNoAlloc(interp, buffer, p - buffer);
+}
+
+
+static int ScanOneEntry(Jim_Interp *interp, const char *str, int pos, int strLen,
+ ScanFmtStringObj * fmtObj, long idx, Jim_Obj **valObjPtr)
+{
+ const char *tok;
+ const ScanFmtPartDescr *descr = &fmtObj->descr[idx];
+ size_t scanned = 0;
+ size_t anchor = pos;
+ int i;
+ Jim_Obj *tmpObj = NULL;
+
+
+ *valObjPtr = 0;
+ if (descr->prefix) {
+
+ for (i = 0; pos < strLen && descr->prefix[i]; ++i) {
+
+ if (isspace(UCHAR(descr->prefix[i])))
+ while (pos < strLen && isspace(UCHAR(str[pos])))
+ ++pos;
+ else if (descr->prefix[i] != str[pos])
+ break;
+ else
+ ++pos;
+ }
+ if (pos >= strLen) {
+ return -1;
+ }
+ else if (descr->prefix[i] != 0)
+ return 0;
+ }
+
+ if (descr->type != 'c' && descr->type != '[' && descr->type != 'n')
+ while (isspace(UCHAR(str[pos])))
+ ++pos;
+
+ scanned = pos - anchor;
+
+
+ if (descr->type == 'n') {
+
+ *valObjPtr = Jim_NewIntObj(interp, anchor + scanned);
+ }
+ else if (pos >= strLen) {
+
+ return -1;
+ }
+ else if (descr->type == 'c') {
+ int c;
+ scanned += utf8_tounicode(&str[pos], &c);
+ *valObjPtr = Jim_NewIntObj(interp, c);
+ return scanned;
+ }
+ else {
+
+ if (descr->width > 0) {
+ size_t sLen = utf8_strlen(&str[pos], strLen - pos);
+ size_t tLen = descr->width > sLen ? sLen : descr->width;
+
+ tmpObj = Jim_NewStringObjUtf8(interp, str + pos, tLen);
+ tok = tmpObj->bytes;
+ }
+ else {
+
+ tok = &str[pos];
+ }
+ switch (descr->type) {
+ case 'd':
+ case 'o':
+ case 'x':
+ case 'u':
+ case 'i':{
+ char *endp;
+ jim_wide w;
+
+ int base = descr->type == 'o' ? 8
+ : descr->type == 'x' ? 16 : descr->type == 'i' ? 0 : 10;
+
+
+ if (base == 0) {
+ w = jim_strtoull(tok, &endp);
+ }
+ else {
+ w = strtoull(tok, &endp, base);
+ }
+
+ if (endp != tok) {
+
+ *valObjPtr = Jim_NewIntObj(interp, w);
+
+
+ scanned += endp - tok;
+ }
+ else {
+ scanned = *tok ? 0 : -1;
+ }
+ break;
+ }
+ case 's':
+ case '[':{
+ *valObjPtr = JimScanAString(interp, descr->arg, tok);
+ scanned += Jim_Length(*valObjPtr);
+ break;
+ }
+ case 'e':
+ case 'f':
+ case 'g':{
+ char *endp;
+ double value = strtod(tok, &endp);
+
+ if (endp != tok) {
+
+ *valObjPtr = Jim_NewDoubleObj(interp, value);
+
+ scanned += endp - tok;
+ }
+ else {
+ scanned = *tok ? 0 : -1;
+ }
+ break;
+ }
+ }
+ if (tmpObj) {
+ Jim_FreeNewObj(interp, tmpObj);
+ }
+ }
+ return scanned;
+}
+
+
+Jim_Obj *Jim_ScanString(Jim_Interp *interp, Jim_Obj *strObjPtr, Jim_Obj *fmtObjPtr, int flags)
+{
+ size_t i, pos;
+ int scanned = 1;
+ const char *str = Jim_String(strObjPtr);
+ int strLen = Jim_Utf8Length(interp, strObjPtr);
+ Jim_Obj *resultList = 0;
+ Jim_Obj **resultVec = 0;
+ int resultc;
+ Jim_Obj *emptyStr = 0;
+ ScanFmtStringObj *fmtObj;
+
+
+ JimPanic((fmtObjPtr->typePtr != &scanFmtStringObjType, "Jim_ScanString() for non-scan format"));
+
+ fmtObj = (ScanFmtStringObj *) fmtObjPtr->internalRep.ptr;
+
+ if (fmtObj->error != 0) {
+ if (flags & JIM_ERRMSG)
+ Jim_SetResultString(interp, fmtObj->error, -1);
+ return 0;
+ }
+
+ emptyStr = Jim_NewEmptyStringObj(interp);
+ Jim_IncrRefCount(emptyStr);
+
+ resultList = Jim_NewListObj(interp, NULL, 0);
+ if (fmtObj->maxPos > 0) {
+ for (i = 0; i < fmtObj->maxPos; ++i)
+ Jim_ListAppendElement(interp, resultList, emptyStr);
+ JimListGetElements(interp, resultList, &resultc, &resultVec);
+ }
+
+ for (i = 0, pos = 0; i < fmtObj->count; ++i) {
+ ScanFmtPartDescr *descr = &(fmtObj->descr[i]);
+ Jim_Obj *value = 0;
+
+
+ if (descr->type == 0)
+ continue;
+
+ if (scanned > 0)
+ scanned = ScanOneEntry(interp, str, pos, strLen, fmtObj, i, &value);
+
+ if (scanned == -1 && i == 0)
+ goto eof;
+
+ pos += scanned;
+
+
+ if (value == 0)
+ value = Jim_NewEmptyStringObj(interp);
+
+ if (descr->pos == -1) {
+ Jim_FreeNewObj(interp, value);
+ }
+ else if (descr->pos == 0)
+
+ Jim_ListAppendElement(interp, resultList, value);
+ else if (resultVec[descr->pos - 1] == emptyStr) {
+
+ Jim_DecrRefCount(interp, resultVec[descr->pos - 1]);
+ Jim_IncrRefCount(value);
+ resultVec[descr->pos - 1] = value;
+ }
+ else {
+
+ Jim_FreeNewObj(interp, value);
+ goto err;
+ }
+ }
+ Jim_DecrRefCount(interp, emptyStr);
+ return resultList;
+ eof:
+ Jim_DecrRefCount(interp, emptyStr);
+ Jim_FreeNewObj(interp, resultList);
+ return (Jim_Obj *)EOF;
+ err:
+ Jim_DecrRefCount(interp, emptyStr);
+ Jim_FreeNewObj(interp, resultList);
+ return 0;
+}
+
+
+static void JimPrngInit(Jim_Interp *interp)
+{
+#define PRNG_SEED_SIZE 256
+ int i;
+ unsigned int *seed;
+ time_t t = time(NULL);
+
+ interp->prngState = Jim_Alloc(sizeof(Jim_PrngState));
+
+ seed = Jim_Alloc(PRNG_SEED_SIZE * sizeof(*seed));
+ for (i = 0; i < PRNG_SEED_SIZE; i++) {
+ seed[i] = (rand() ^ t ^ clock());
+ }
+ JimPrngSeed(interp, (unsigned char *)seed, PRNG_SEED_SIZE * sizeof(*seed));
+ Jim_Free(seed);
+}
+
+
+static void JimRandomBytes(Jim_Interp *interp, void *dest, unsigned int len)
+{
+ Jim_PrngState *prng;
+ unsigned char *destByte = (unsigned char *)dest;
+ unsigned int si, sj, x;
+
+
+ if (interp->prngState == NULL)
+ JimPrngInit(interp);
+ prng = interp->prngState;
+
+ for (x = 0; x < len; x++) {
+ prng->i = (prng->i + 1) & 0xff;
+ si = prng->sbox[prng->i];
+ prng->j = (prng->j + si) & 0xff;
+ sj = prng->sbox[prng->j];
+ prng->sbox[prng->i] = sj;
+ prng->sbox[prng->j] = si;
+ *destByte++ = prng->sbox[(si + sj) & 0xff];
+ }
+}
+
+
+static void JimPrngSeed(Jim_Interp *interp, unsigned char *seed, int seedLen)
+{
+ int i;
+ Jim_PrngState *prng;
+
+
+ if (interp->prngState == NULL)
+ JimPrngInit(interp);
+ prng = interp->prngState;
+
+
+ for (i = 0; i < 256; i++)
+ prng->sbox[i] = i;
+
+ for (i = 0; i < seedLen; i++) {
+ unsigned char t;
+
+ t = prng->sbox[i & 0xFF];
+ prng->sbox[i & 0xFF] = prng->sbox[seed[i]];
+ prng->sbox[seed[i]] = t;
+ }
+ prng->i = prng->j = 0;
+
+ for (i = 0; i < 256; i += seedLen) {
+ JimRandomBytes(interp, seed, seedLen);
+ }
+}
+
+
+static int Jim_IncrCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ jim_wide wideValue, increment = 1;
+ Jim_Obj *intObjPtr;
+
+ if (argc != 2 && argc != 3) {
+ Jim_WrongNumArgs(interp, 1, argv, "varName ?increment?");
+ return JIM_ERR;
+ }
+ if (argc == 3) {
+ if (Jim_GetWide(interp, argv[2], &increment) != JIM_OK)
+ return JIM_ERR;
+ }
+ intObjPtr = Jim_GetVariable(interp, argv[1], JIM_UNSHARED);
+ if (!intObjPtr) {
+
+ wideValue = 0;
+ }
+ else if (Jim_GetWide(interp, intObjPtr, &wideValue) != JIM_OK) {
+ return JIM_ERR;
+ }
+ if (!intObjPtr || Jim_IsShared(intObjPtr)) {
+ intObjPtr = Jim_NewIntObj(interp, wideValue + increment);
+ if (Jim_SetVariable(interp, argv[1], intObjPtr) != JIM_OK) {
+ Jim_FreeNewObj(interp, intObjPtr);
+ return JIM_ERR;
+ }
+ }
+ else {
+
+ Jim_InvalidateStringRep(intObjPtr);
+ JimWideValue(intObjPtr) = wideValue + increment;
+
+ if (argv[1]->typePtr != &variableObjType) {
+
+ Jim_SetVariable(interp, argv[1], intObjPtr);
+ }
+ }
+ Jim_SetResult(interp, intObjPtr);
+ return JIM_OK;
+}
+
+
+#define JIM_EVAL_SARGV_LEN 8
+#define JIM_EVAL_SINTV_LEN 8
+
+
+static int JimUnknown(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ int retcode;
+
+ if (interp->unknown_called > 50) {
+ return JIM_ERR;
+ }
+
+
+
+ if (Jim_GetCommand(interp, interp->unknown, JIM_NONE) == NULL)
+ return JIM_ERR;
+
+ interp->unknown_called++;
+
+ retcode = Jim_EvalObjPrefix(interp, interp->unknown, argc, argv);
+ interp->unknown_called--;
+
+ return retcode;
+}
+
+static int JimInvokeCommand(Jim_Interp *interp, int objc, Jim_Obj *const *objv)
+{
+ int retcode;
+ Jim_Cmd *cmdPtr = Jim_GetCommand(interp, objv[0], JIM_ERRMSG);
+
+ if (cmdPtr == NULL) {
+ return JimUnknown(interp, objc, objv);
+ }
+ if (interp->evalDepth == interp->maxEvalDepth) {
+ Jim_SetResultString(interp, "Infinite eval recursion", -1);
+ return JIM_ERR;
+ }
+ interp->evalDepth++;
+
+
+ JimIncrCmdRefCount(cmdPtr);
+ Jim_SetEmptyResult(interp);
+ if (cmdPtr->isproc) {
+ retcode = JimCallProcedure(interp, cmdPtr, objc, objv);
+ }
+ else {
+ interp->cmdPrivData = cmdPtr->u.native.privData;
+ retcode = cmdPtr->u.native.cmdProc(interp, objc, objv);
+ }
+ JimDecrCmdRefCount(interp, cmdPtr);
+ interp->evalDepth--;
+
+ return retcode;
+}
+
+int Jim_EvalObjVector(Jim_Interp *interp, int objc, Jim_Obj *const *objv)
+{
+ int i, retcode;
+
+
+ for (i = 0; i < objc; i++)
+ Jim_IncrRefCount(objv[i]);
+
+ retcode = JimInvokeCommand(interp, objc, objv);
+
+
+ for (i = 0; i < objc; i++)
+ Jim_DecrRefCount(interp, objv[i]);
+
+ return retcode;
+}
+
+int Jim_EvalObjPrefix(Jim_Interp *interp, Jim_Obj *prefix, int objc, Jim_Obj *const *objv)
+{
+ int ret;
+ Jim_Obj **nargv = Jim_Alloc((objc + 1) * sizeof(*nargv));
+
+ nargv[0] = prefix;
+ memcpy(&nargv[1], &objv[0], sizeof(nargv[0]) * objc);
+ ret = Jim_EvalObjVector(interp, objc + 1, nargv);
+ Jim_Free(nargv);
+ return ret;
+}
+
+static void JimAddErrorToStack(Jim_Interp *interp, int retcode, ScriptObj *script)
+{
+ int rc = retcode;
+
+ if (rc == JIM_ERR && !interp->errorFlag) {
+
+ interp->errorFlag = 1;
+ Jim_IncrRefCount(script->fileNameObj);
+ Jim_DecrRefCount(interp, interp->errorFileNameObj);
+ interp->errorFileNameObj = script->fileNameObj;
+ interp->errorLine = script->linenr;
+
+ JimResetStackTrace(interp);
+
+ interp->addStackTrace++;
+ }
+
+
+ if (rc == JIM_ERR && interp->addStackTrace > 0) {
+
+
+ JimAppendStackTrace(interp, Jim_String(interp->errorProc), script->fileNameObj, script->linenr);
+
+ if (Jim_Length(script->fileNameObj)) {
+ interp->addStackTrace = 0;
+ }
+
+ Jim_DecrRefCount(interp, interp->errorProc);
+ interp->errorProc = interp->emptyObj;
+ Jim_IncrRefCount(interp->errorProc);
+ }
+ else if (rc == JIM_RETURN && interp->returnCode == JIM_ERR) {
+
+ }
+ else {
+ interp->addStackTrace = 0;
+ }
+}
+
+static int JimSubstOneToken(Jim_Interp *interp, const ScriptToken *token, Jim_Obj **objPtrPtr)
+{
+ Jim_Obj *objPtr;
+
+ switch (token->type) {
+ case JIM_TT_STR:
+ case JIM_TT_ESC:
+ objPtr = token->objPtr;
+ break;
+ case JIM_TT_VAR:
+ objPtr = Jim_GetVariable(interp, token->objPtr, JIM_ERRMSG);
+ break;
+ case JIM_TT_DICTSUGAR:
+ objPtr = JimExpandDictSugar(interp, token->objPtr);
+ break;
+ case JIM_TT_EXPRSUGAR:
+ objPtr = JimExpandExprSugar(interp, token->objPtr);
+ break;
+ case JIM_TT_CMD:
+ switch (Jim_EvalObj(interp, token->objPtr)) {
+ case JIM_OK:
+ case JIM_RETURN:
+ objPtr = interp->result;
+ break;
+ case JIM_BREAK:
+
+ return JIM_BREAK;
+ case JIM_CONTINUE:
+
+ return JIM_CONTINUE;
+ default:
+ return JIM_ERR;
+ }
+ break;
+ default:
+ JimPanic((1,
+ "default token type (%d) reached " "in Jim_SubstObj().", token->type));
+ objPtr = NULL;
+ break;
+ }
+ if (objPtr) {
+ *objPtrPtr = objPtr;
+ return JIM_OK;
+ }
+ return JIM_ERR;
+}
+
+static Jim_Obj *JimInterpolateTokens(Jim_Interp *interp, const ScriptToken * token, int tokens, int flags)
+{
+ int totlen = 0, i;
+ Jim_Obj **intv;
+ Jim_Obj *sintv[JIM_EVAL_SINTV_LEN];
+ Jim_Obj *objPtr;
+ char *s;
+
+ if (tokens <= JIM_EVAL_SINTV_LEN)
+ intv = sintv;
+ else
+ intv = Jim_Alloc(sizeof(Jim_Obj *) * tokens);
+
+ for (i = 0; i < tokens; i++) {
+ switch (JimSubstOneToken(interp, &token[i], &intv[i])) {
+ case JIM_OK:
+ case JIM_RETURN:
+ break;
+ case JIM_BREAK:
+ if (flags & JIM_SUBST_FLAG) {
+
+ tokens = i;
+ continue;
+ }
+
+
+ case JIM_CONTINUE:
+ if (flags & JIM_SUBST_FLAG) {
+ intv[i] = NULL;
+ continue;
+ }
+
+
+ default:
+ while (i--) {
+ Jim_DecrRefCount(interp, intv[i]);
+ }
+ if (intv != sintv) {
+ Jim_Free(intv);
+ }
+ return NULL;
+ }
+ Jim_IncrRefCount(intv[i]);
+ Jim_String(intv[i]);
+ totlen += intv[i]->length;
+ }
+
+
+ if (tokens == 1 && intv[0] && intv == sintv) {
+ Jim_DecrRefCount(interp, intv[0]);
+ return intv[0];
+ }
+
+ objPtr = Jim_NewStringObjNoAlloc(interp, NULL, 0);
+
+ if (tokens == 4 && token[0].type == JIM_TT_ESC && token[1].type == JIM_TT_ESC
+ && token[2].type == JIM_TT_VAR) {
+
+ objPtr->typePtr = &interpolatedObjType;
+ objPtr->internalRep.dictSubstValue.varNameObjPtr = token[0].objPtr;
+ objPtr->internalRep.dictSubstValue.indexObjPtr = intv[2];
+ Jim_IncrRefCount(intv[2]);
+ }
+
+ s = objPtr->bytes = Jim_Alloc(totlen + 1);
+ objPtr->length = totlen;
+ for (i = 0; i < tokens; i++) {
+ if (intv[i]) {
+ memcpy(s, intv[i]->bytes, intv[i]->length);
+ s += intv[i]->length;
+ Jim_DecrRefCount(interp, intv[i]);
+ }
+ }
+ objPtr->bytes[totlen] = '\0';
+
+ if (intv != sintv) {
+ Jim_Free(intv);
+ }
+
+ return objPtr;
+}
+
+
+static int JimEvalObjList(Jim_Interp *interp, Jim_Obj *listPtr)
+{
+ int retcode = JIM_OK;
+
+ if (listPtr->internalRep.listValue.len) {
+ Jim_IncrRefCount(listPtr);
+ retcode = JimInvokeCommand(interp,
+ listPtr->internalRep.listValue.len,
+ listPtr->internalRep.listValue.ele);
+ Jim_DecrRefCount(interp, listPtr);
+ }
+ return retcode;
+}
+
+int Jim_EvalObjList(Jim_Interp *interp, Jim_Obj *listPtr)
+{
+ SetListFromAny(interp, listPtr);
+ return JimEvalObjList(interp, listPtr);
+}
+
+int Jim_EvalObj(Jim_Interp *interp, Jim_Obj *scriptObjPtr)
+{
+ int i;
+ ScriptObj *script;
+ ScriptToken *token;
+ int retcode = JIM_OK;
+ Jim_Obj *sargv[JIM_EVAL_SARGV_LEN], **argv = NULL;
+ Jim_Obj *prevScriptObj;
+
+ if (Jim_IsList(scriptObjPtr) && scriptObjPtr->bytes == NULL) {
+ return JimEvalObjList(interp, scriptObjPtr);
+ }
+
+ Jim_IncrRefCount(scriptObjPtr);
+ script = Jim_GetScript(interp, scriptObjPtr);
+
+ Jim_SetEmptyResult(interp);
+
+ token = script->token;
+
+#ifdef JIM_OPTIMIZATION
+ if (script->len == 0) {
+ Jim_DecrRefCount(interp, scriptObjPtr);
+ return JIM_OK;
+ }
+ if (script->len == 3
+ && token[1].objPtr->typePtr == &commandObjType
+ && token[1].objPtr->internalRep.cmdValue.cmdPtr->isproc == 0
+ && token[1].objPtr->internalRep.cmdValue.cmdPtr->u.native.cmdProc == Jim_IncrCoreCommand
+ && token[2].objPtr->typePtr == &variableObjType) {
+
+ Jim_Obj *objPtr = Jim_GetVariable(interp, token[2].objPtr, JIM_NONE);
+
+ if (objPtr && !Jim_IsShared(objPtr) && objPtr->typePtr == &intObjType) {
+ JimWideValue(objPtr)++;
+ Jim_InvalidateStringRep(objPtr);
+ Jim_DecrRefCount(interp, scriptObjPtr);
+ Jim_SetResult(interp, objPtr);
+ return JIM_OK;
+ }
+ }
+#endif
+
+ script->inUse++;
+
+
+ prevScriptObj = interp->currentScriptObj;
+ interp->currentScriptObj = scriptObjPtr;
+
+ interp->errorFlag = 0;
+ argv = sargv;
+
+ for (i = 0; i < script->len && retcode == JIM_OK; ) {
+ int argc;
+ int j;
+
+
+ argc = token[i].objPtr->internalRep.scriptLineValue.argc;
+ script->linenr = token[i].objPtr->internalRep.scriptLineValue.line;
+
+
+ if (argc > JIM_EVAL_SARGV_LEN)
+ argv = Jim_Alloc(sizeof(Jim_Obj *) * argc);
+
+
+ i++;
+
+ for (j = 0; j < argc; j++) {
+ long wordtokens = 1;
+ int expand = 0;
+ Jim_Obj *wordObjPtr = NULL;
+
+ if (token[i].type == JIM_TT_WORD) {
+ wordtokens = JimWideValue(token[i++].objPtr);
+ if (wordtokens < 0) {
+ expand = 1;
+ wordtokens = -wordtokens;
+ }
+ }
+
+ if (wordtokens == 1) {
+
+ switch (token[i].type) {
+ case JIM_TT_ESC:
+ case JIM_TT_STR:
+ wordObjPtr = token[i].objPtr;
+ break;
+ case JIM_TT_VAR:
+ wordObjPtr = Jim_GetVariable(interp, token[i].objPtr, JIM_ERRMSG);
+ break;
+ case JIM_TT_EXPRSUGAR:
+ wordObjPtr = JimExpandExprSugar(interp, token[i].objPtr);
+ break;
+ case JIM_TT_DICTSUGAR:
+ wordObjPtr = JimExpandDictSugar(interp, token[i].objPtr);
+ break;
+ case JIM_TT_CMD:
+ retcode = Jim_EvalObj(interp, token[i].objPtr);
+ if (retcode == JIM_OK) {
+ wordObjPtr = Jim_GetResult(interp);
+ }
+ break;
+ default:
+ JimPanic((1, "default token type reached " "in Jim_EvalObj()."));
+ }
+ }
+ else {
+ wordObjPtr = JimInterpolateTokens(interp, token + i, wordtokens, JIM_NONE);
+ }
+
+ if (!wordObjPtr) {
+ if (retcode == JIM_OK) {
+ retcode = JIM_ERR;
+ }
+ break;
+ }
+
+ Jim_IncrRefCount(wordObjPtr);
+ i += wordtokens;
+
+ if (!expand) {
+ argv[j] = wordObjPtr;
+ }
+ else {
+
+ int len = Jim_ListLength(interp, wordObjPtr);
+ int newargc = argc + len - 1;
+ int k;
+
+ if (len > 1) {
+ if (argv == sargv) {
+ if (newargc > JIM_EVAL_SARGV_LEN) {
+ argv = Jim_Alloc(sizeof(*argv) * newargc);
+ memcpy(argv, sargv, sizeof(*argv) * j);
+ }
+ }
+ else {
+
+ argv = Jim_Realloc(argv, sizeof(*argv) * newargc);
+ }
+ }
+
+
+ for (k = 0; k < len; k++) {
+ argv[j++] = wordObjPtr->internalRep.listValue.ele[k];
+ Jim_IncrRefCount(wordObjPtr->internalRep.listValue.ele[k]);
+ }
+
+ Jim_DecrRefCount(interp, wordObjPtr);
+
+
+ j--;
+ argc += len - 1;
+ }
+ }
+
+ if (retcode == JIM_OK && argc) {
+
+ retcode = JimInvokeCommand(interp, argc, argv);
+ if (interp->signal_level && interp->sigmask) {
+
+ retcode = JIM_SIGNAL;
+ }
+ }
+
+
+ while (j-- > 0) {
+ Jim_DecrRefCount(interp, argv[j]);
+ }
+
+ if (argv != sargv) {
+ Jim_Free(argv);
+ argv = sargv;
+ }
+ }
+
+
+ JimAddErrorToStack(interp, retcode, script);
+
+
+ interp->currentScriptObj = prevScriptObj;
+
+ Jim_FreeIntRep(interp, scriptObjPtr);
+ scriptObjPtr->typePtr = &scriptObjType;
+ Jim_SetIntRepPtr(scriptObjPtr, script);
+ Jim_DecrRefCount(interp, scriptObjPtr);
+
+ return retcode;
+}
+
+static int JimSetProcArg(Jim_Interp *interp, Jim_Obj *argNameObj, Jim_Obj *argValObj)
+{
+ int retcode;
+
+ const char *varname = Jim_String(argNameObj);
+ if (*varname == '&') {
+
+ Jim_Obj *objPtr;
+ Jim_CallFrame *savedCallFrame = interp->framePtr;
+
+ interp->framePtr = interp->framePtr->parent;
+ objPtr = Jim_GetVariable(interp, argValObj, JIM_ERRMSG);
+ interp->framePtr = savedCallFrame;
+ if (!objPtr) {
+ return JIM_ERR;
+ }
+
+
+ objPtr = Jim_NewStringObj(interp, varname + 1, -1);
+ Jim_IncrRefCount(objPtr);
+ retcode = Jim_SetVariableLink(interp, objPtr, argValObj, interp->framePtr->parent);
+ Jim_DecrRefCount(interp, objPtr);
+ }
+ else {
+ retcode = Jim_SetVariable(interp, argNameObj, argValObj);
+ }
+ return retcode;
+}
+
+static void JimSetProcWrongArgs(Jim_Interp *interp, Jim_Obj *procNameObj, Jim_Cmd *cmd)
+{
+
+ Jim_Obj *argmsg = Jim_NewStringObj(interp, "", 0);
+ int i;
+
+ for (i = 0; i < cmd->u.proc.argListLen; i++) {
+ Jim_AppendString(interp, argmsg, " ", 1);
+
+ if (i == cmd->u.proc.argsPos) {
+ if (cmd->u.proc.arglist[i].defaultObjPtr) {
+
+ Jim_AppendString(interp, argmsg, "?", 1);
+ Jim_AppendObj(interp, argmsg, cmd->u.proc.arglist[i].defaultObjPtr);
+ Jim_AppendString(interp, argmsg, " ...?", -1);
+ }
+ else {
+
+ Jim_AppendString(interp, argmsg, "?arg...?", -1);
+ }
+ }
+ else {
+ if (cmd->u.proc.arglist[i].defaultObjPtr) {
+ Jim_AppendString(interp, argmsg, "?", 1);
+ Jim_AppendObj(interp, argmsg, cmd->u.proc.arglist[i].nameObjPtr);
+ Jim_AppendString(interp, argmsg, "?", 1);
+ }
+ else {
+ const char *arg = Jim_String(cmd->u.proc.arglist[i].nameObjPtr);
+ if (*arg == '&') {
+ arg++;
+ }
+ Jim_AppendString(interp, argmsg, arg, -1);
+ }
+ }
+ }
+ Jim_SetResultFormatted(interp, "wrong # args: should be \"%#s%#s\"", procNameObj, argmsg);
+ Jim_FreeNewObj(interp, argmsg);
+}
+
+#ifdef jim_ext_namespace
+int Jim_EvalNamespace(Jim_Interp *interp, Jim_Obj *scriptObj, Jim_Obj *nsObj)
+{
+ Jim_CallFrame *callFramePtr;
+ int retcode;
+
+
+ callFramePtr = JimCreateCallFrame(interp, interp->framePtr, nsObj);
+ callFramePtr->argv = &interp->emptyObj;
+ callFramePtr->argc = 0;
+ callFramePtr->procArgsObjPtr = NULL;
+ callFramePtr->procBodyObjPtr = scriptObj;
+ callFramePtr->staticVars = NULL;
+ callFramePtr->fileNameObj = interp->emptyObj;
+ callFramePtr->line = 0;
+ Jim_IncrRefCount(scriptObj);
+ interp->framePtr = callFramePtr;
+
+
+ if (interp->framePtr->level == interp->maxCallFrameDepth) {
+ Jim_SetResultString(interp, "Too many nested calls. Infinite recursion?", -1);
+ retcode = JIM_ERR;
+ }
+ else {
+
+ retcode = Jim_EvalObj(interp, scriptObj);
+ }
+
+
+ interp->framePtr = interp->framePtr->parent;
+ if (callFramePtr->vars.size != JIM_HT_INITIAL_SIZE) {
+ JimFreeCallFrame(interp, callFramePtr, JIM_FCF_NONE);
+ }
+ else {
+ JimFreeCallFrame(interp, callFramePtr, JIM_FCF_NOHT);
+ }
+
+ return retcode;
+}
+#endif
+
+static int JimCallProcedure(Jim_Interp *interp, Jim_Cmd *cmd, int argc, Jim_Obj *const *argv)
+{
+ Jim_CallFrame *callFramePtr;
+ int i, d, retcode, optargs;
+ Jim_Stack *localCommands;
+ ScriptObj *script;
+
+
+ if (argc - 1 < cmd->u.proc.reqArity ||
+ (cmd->u.proc.argsPos < 0 && argc - 1 > cmd->u.proc.reqArity + cmd->u.proc.optArity)) {
+ JimSetProcWrongArgs(interp, argv[0], cmd);
+ return JIM_ERR;
+ }
+
+ if (Jim_Length(cmd->u.proc.bodyObjPtr) == 0) {
+
+ return JIM_OK;
+ }
+
+
+ if (interp->framePtr->level == interp->maxCallFrameDepth) {
+ Jim_SetResultString(interp, "Too many nested calls. Infinite recursion?", -1);
+ return JIM_ERR;
+ }
+
+
+ callFramePtr = JimCreateCallFrame(interp, interp->framePtr, cmd->u.proc.nsObj);
+ callFramePtr->argv = argv;
+ callFramePtr->argc = argc;
+ callFramePtr->procArgsObjPtr = cmd->u.proc.argListObjPtr;
+ callFramePtr->procBodyObjPtr = cmd->u.proc.bodyObjPtr;
+ callFramePtr->staticVars = cmd->u.proc.staticVars;
+
+
+ script = Jim_GetScript(interp, interp->currentScriptObj);
+ callFramePtr->fileNameObj = script->fileNameObj;
+ callFramePtr->line = script->linenr;
+
+ Jim_IncrRefCount(cmd->u.proc.argListObjPtr);
+ Jim_IncrRefCount(cmd->u.proc.bodyObjPtr);
+ interp->framePtr = callFramePtr;
+
+
+ optargs = (argc - 1 - cmd->u.proc.reqArity);
+
+
+ i = 1;
+ for (d = 0; d < cmd->u.proc.argListLen; d++) {
+ Jim_Obj *nameObjPtr = cmd->u.proc.arglist[d].nameObjPtr;
+ if (d == cmd->u.proc.argsPos) {
+
+ Jim_Obj *listObjPtr;
+ int argsLen = 0;
+ if (cmd->u.proc.reqArity + cmd->u.proc.optArity < argc - 1) {
+ argsLen = argc - 1 - (cmd->u.proc.reqArity + cmd->u.proc.optArity);
+ }
+ listObjPtr = Jim_NewListObj(interp, &argv[i], argsLen);
+
+
+ if (cmd->u.proc.arglist[d].defaultObjPtr) {
+ nameObjPtr =cmd->u.proc.arglist[d].defaultObjPtr;
+ }
+ retcode = Jim_SetVariable(interp, nameObjPtr, listObjPtr);
+ if (retcode != JIM_OK) {
+ goto badargset;
+ }
+
+ i += argsLen;
+ continue;
+ }
+
+
+ if (cmd->u.proc.arglist[d].defaultObjPtr == NULL || optargs-- > 0) {
+ retcode = JimSetProcArg(interp, nameObjPtr, argv[i++]);
+ }
+ else {
+
+ retcode = Jim_SetVariable(interp, nameObjPtr, cmd->u.proc.arglist[d].defaultObjPtr);
+ }
+ if (retcode != JIM_OK) {
+ goto badargset;
+ }
+ }
+
+
+ retcode = Jim_EvalObj(interp, cmd->u.proc.bodyObjPtr);
+
+badargset:
+
+
+ localCommands = callFramePtr->localCommands;
+ callFramePtr->localCommands = NULL;
+
+ interp->framePtr = interp->framePtr->parent;
+ if (callFramePtr->vars.size != JIM_HT_INITIAL_SIZE) {
+ JimFreeCallFrame(interp, callFramePtr, JIM_FCF_NONE);
+ }
+ else {
+ JimFreeCallFrame(interp, callFramePtr, JIM_FCF_NOHT);
+ }
+
+
+ while (retcode == JIM_EVAL) {
+ Jim_Obj *resultScriptObjPtr = Jim_GetResult(interp);
+
+ Jim_IncrRefCount(resultScriptObjPtr);
+
+ JimPanic((!Jim_IsList(resultScriptObjPtr), "tailcall (JIM_EVAL) returned non-list"));
+
+ retcode = JimEvalObjList(interp, resultScriptObjPtr);
+ if (retcode == JIM_RETURN) {
+ interp->returnLevel++;
+ }
+ Jim_DecrRefCount(interp, resultScriptObjPtr);
+ }
+
+ if (retcode == JIM_RETURN) {
+ if (--interp->returnLevel <= 0) {
+ retcode = interp->returnCode;
+ interp->returnCode = JIM_OK;
+ interp->returnLevel = 0;
+ }
+ }
+ else if (retcode == JIM_ERR) {
+ interp->addStackTrace++;
+ Jim_DecrRefCount(interp, interp->errorProc);
+ interp->errorProc = argv[0];
+ Jim_IncrRefCount(interp->errorProc);
+ }
+
+
+ JimDeleteLocalProcs(interp, localCommands);
+
+ return retcode;
+}
+
+int Jim_EvalSource(Jim_Interp *interp, const char *filename, int lineno, const char *script)
+{
+ int retval;
+ Jim_Obj *scriptObjPtr;
+
+ scriptObjPtr = Jim_NewStringObj(interp, script, -1);
+ Jim_IncrRefCount(scriptObjPtr);
+
+ if (filename) {
+ Jim_Obj *prevScriptObj;
+
+ JimSetSourceInfo(interp, scriptObjPtr, Jim_NewStringObj(interp, filename, -1), lineno);
+
+ prevScriptObj = interp->currentScriptObj;
+ interp->currentScriptObj = scriptObjPtr;
+
+ retval = Jim_EvalObj(interp, scriptObjPtr);
+
+ interp->currentScriptObj = prevScriptObj;
+ }
+ else {
+ retval = Jim_EvalObj(interp, scriptObjPtr);
+ }
+ Jim_DecrRefCount(interp, scriptObjPtr);
+ return retval;
+}
+
+int Jim_Eval(Jim_Interp *interp, const char *script)
+{
+ return Jim_EvalObj(interp, Jim_NewStringObj(interp, script, -1));
+}
+
+
+int Jim_EvalGlobal(Jim_Interp *interp, const char *script)
+{
+ int retval;
+ Jim_CallFrame *savedFramePtr = interp->framePtr;
+
+ interp->framePtr = interp->topFramePtr;
+ retval = Jim_Eval(interp, script);
+ interp->framePtr = savedFramePtr;
+
+ return retval;
+}
+
+int Jim_EvalFileGlobal(Jim_Interp *interp, const char *filename)
+{
+ int retval;
+ Jim_CallFrame *savedFramePtr = interp->framePtr;
+
+ interp->framePtr = interp->topFramePtr;
+ retval = Jim_EvalFile(interp, filename);
+ interp->framePtr = savedFramePtr;
+
+ return retval;
+}
+
+#include
+
+int Jim_EvalFile(Jim_Interp *interp, const char *filename)
+{
+ FILE *fp;
+ char *buf;
+ Jim_Obj *scriptObjPtr;
+ Jim_Obj *prevScriptObj;
+ struct stat sb;
+ int retcode;
+ int readlen;
+ struct JimParseResult result;
+
+ if (stat(filename, &sb) != 0 || (fp = fopen(filename, "rt")) == NULL) {
+ Jim_SetResultFormatted(interp, "couldn't read file \"%s\": %s", filename, strerror(errno));
+ return JIM_ERR;
+ }
+ if (sb.st_size == 0) {
+ fclose(fp);
+ return JIM_OK;
+ }
+
+ buf = Jim_Alloc(sb.st_size + 1);
+ readlen = fread(buf, 1, sb.st_size, fp);
+ if (ferror(fp)) {
+ fclose(fp);
+ Jim_Free(buf);
+ Jim_SetResultFormatted(interp, "failed to load file \"%s\": %s", filename, strerror(errno));
+ return JIM_ERR;
+ }
+ fclose(fp);
+ buf[readlen] = 0;
+
+ scriptObjPtr = Jim_NewStringObjNoAlloc(interp, buf, readlen);
+ JimSetSourceInfo(interp, scriptObjPtr, Jim_NewStringObj(interp, filename, -1), 1);
+ Jim_IncrRefCount(scriptObjPtr);
+
+
+ if (SetScriptFromAny(interp, scriptObjPtr, &result) == JIM_ERR) {
+ const char *msg;
+ char linebuf[20];
+
+ switch (result.missing) {
+ case '[':
+ msg = "unmatched \"[\"";
+ break;
+ case '{':
+ msg = "missing close-brace";
+ break;
+ case '"':
+ default:
+ msg = "missing quote";
+ break;
+ }
+
+ snprintf(linebuf, sizeof(linebuf), "%d", result.line);
+
+ Jim_SetResultFormatted(interp, "%s in \"%s\" at line %s",
+ msg, filename, linebuf);
+ Jim_DecrRefCount(interp, scriptObjPtr);
+ return JIM_ERR;
+ }
+
+ prevScriptObj = interp->currentScriptObj;
+ interp->currentScriptObj = scriptObjPtr;
+
+ retcode = Jim_EvalObj(interp, scriptObjPtr);
+
+
+ if (retcode == JIM_RETURN) {
+ if (--interp->returnLevel <= 0) {
+ retcode = interp->returnCode;
+ interp->returnCode = JIM_OK;
+ interp->returnLevel = 0;
+ }
+ }
+ if (retcode == JIM_ERR) {
+
+ interp->addStackTrace++;
+ }
+
+ interp->currentScriptObj = prevScriptObj;
+
+ Jim_DecrRefCount(interp, scriptObjPtr);
+
+ return retcode;
+}
+
+static void JimParseSubst(struct JimParserCtx *pc, int flags)
+{
+ pc->tstart = pc->p;
+ pc->tline = pc->linenr;
+
+ if (pc->len == 0) {
+ pc->tend = pc->p;
+ pc->tt = JIM_TT_EOL;
+ pc->eof = 1;
+ return;
+ }
+ if (*pc->p == '[' && !(flags & JIM_SUBST_NOCMD)) {
+ JimParseCmd(pc);
+ return;
+ }
+ if (*pc->p == '$' && !(flags & JIM_SUBST_NOVAR)) {
+ if (JimParseVar(pc) == JIM_OK) {
+ return;
+ }
+
+ pc->tstart = pc->p;
+ flags |= JIM_SUBST_NOVAR;
+ }
+ while (pc->len) {
+ if (*pc->p == '$' && !(flags & JIM_SUBST_NOVAR)) {
+ break;
+ }
+ if (*pc->p == '[' && !(flags & JIM_SUBST_NOCMD)) {
+ break;
+ }
+ if (*pc->p == '\\' && pc->len > 1) {
+ pc->p++;
+ pc->len--;
+ }
+ pc->p++;
+ pc->len--;
+ }
+ pc->tend = pc->p - 1;
+ pc->tt = (flags & JIM_SUBST_NOESC) ? JIM_TT_STR : JIM_TT_ESC;
+}
+
+
+static int SetSubstFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr, int flags)
+{
+ int scriptTextLen;
+ const char *scriptText = Jim_GetString(objPtr, &scriptTextLen);
+ struct JimParserCtx parser;
+ struct ScriptObj *script = Jim_Alloc(sizeof(*script));
+ ParseTokenList tokenlist;
+
+
+ ScriptTokenListInit(&tokenlist);
+
+ JimParserInit(&parser, scriptText, scriptTextLen, 1);
+ while (1) {
+ JimParseSubst(&parser, flags);
+ if (parser.eof) {
+
+ break;
+ }
+ ScriptAddToken(&tokenlist, parser.tstart, parser.tend - parser.tstart + 1, parser.tt,
+ parser.tline);
+ }
+
+
+ script->inUse = 1;
+ script->substFlags = flags;
+ script->fileNameObj = interp->emptyObj;
+ Jim_IncrRefCount(script->fileNameObj);
+ SubstObjAddTokens(interp, script, &tokenlist);
+
+
+ ScriptTokenListFree(&tokenlist);
+
+#ifdef DEBUG_SHOW_SUBST
+ {
+ int i;
+
+ printf("==== Subst ====\n");
+ for (i = 0; i < script->len; i++) {
+ printf("[%2d] %s '%s'\n", i, jim_tt_name(script->token[i].type),
+ Jim_String(script->token[i].objPtr));
+ }
+ }
+#endif
+
+
+ Jim_FreeIntRep(interp, objPtr);
+ Jim_SetIntRepPtr(objPtr, script);
+ objPtr->typePtr = &scriptObjType;
+ return JIM_OK;
+}
+
+static ScriptObj *Jim_GetSubst(Jim_Interp *interp, Jim_Obj *objPtr, int flags)
+{
+ if (objPtr->typePtr != &scriptObjType || ((ScriptObj *)Jim_GetIntRepPtr(objPtr))->substFlags != flags)
+ SetSubstFromAny(interp, objPtr, flags);
+ return (ScriptObj *) Jim_GetIntRepPtr(objPtr);
+}
+
+int Jim_SubstObj(Jim_Interp *interp, Jim_Obj *substObjPtr, Jim_Obj **resObjPtrPtr, int flags)
+{
+ ScriptObj *script = Jim_GetSubst(interp, substObjPtr, flags);
+
+ Jim_IncrRefCount(substObjPtr);
+ script->inUse++;
+
+ *resObjPtrPtr = JimInterpolateTokens(interp, script->token, script->len, flags);
+
+ script->inUse--;
+ Jim_DecrRefCount(interp, substObjPtr);
+ if (*resObjPtrPtr == NULL) {
+ return JIM_ERR;
+ }
+ return JIM_OK;
+}
+
+void Jim_WrongNumArgs(Jim_Interp *interp, int argc, Jim_Obj *const *argv, const char *msg)
+{
+ Jim_Obj *objPtr;
+ Jim_Obj *listObjPtr = Jim_NewListObj(interp, argv, argc);
+
+ if (*msg) {
+ Jim_ListAppendElement(interp, listObjPtr, Jim_NewStringObj(interp, msg, -1));
+ }
+ Jim_IncrRefCount(listObjPtr);
+ objPtr = Jim_ListJoin(interp, listObjPtr, " ", 1);
+ Jim_DecrRefCount(interp, listObjPtr);
+
+ Jim_IncrRefCount(objPtr);
+ Jim_SetResultFormatted(interp, "wrong # args: should be \"%#s\"", objPtr);
+ Jim_DecrRefCount(interp, objPtr);
+}
+
+typedef void JimHashtableIteratorCallbackType(Jim_Interp *interp, Jim_Obj *listObjPtr,
+ Jim_HashEntry *he, int type);
+
+#define JimTrivialMatch(pattern) (strpbrk((pattern), "*[?\\") == NULL)
+
+static Jim_Obj *JimHashtablePatternMatch(Jim_Interp *interp, Jim_HashTable *ht, Jim_Obj *patternObjPtr,
+ JimHashtableIteratorCallbackType *callback, int type)
+{
+ Jim_HashEntry *he;
+ Jim_Obj *listObjPtr = Jim_NewListObj(interp, NULL, 0);
+
+
+ if (patternObjPtr && JimTrivialMatch(Jim_String(patternObjPtr))) {
+ he = Jim_FindHashEntry(ht, Jim_String(patternObjPtr));
+ if (he) {
+ callback(interp, listObjPtr, he, type);
+ }
+ }
+ else {
+ Jim_HashTableIterator *htiter = Jim_GetHashTableIterator(ht);
+ while ((he = Jim_NextHashEntry(htiter)) != NULL) {
+ if (patternObjPtr == NULL || JimGlobMatch(Jim_String(patternObjPtr), he->key, 0)) {
+ callback(interp, listObjPtr, he, type);
+ }
+ }
+ Jim_FreeHashTableIterator(htiter);
+ }
+ return listObjPtr;
+}
+
+
+#define JIM_CMDLIST_COMMANDS 0
+#define JIM_CMDLIST_PROCS 1
+#define JIM_CMDLIST_CHANNELS 2
+
+static void JimCommandMatch(Jim_Interp *interp, Jim_Obj *listObjPtr,
+ Jim_HashEntry *he, int type)
+{
+ Jim_Cmd *cmdPtr = (Jim_Cmd *)he->u.val;
+ Jim_Obj *objPtr;
+
+ if (type == JIM_CMDLIST_PROCS && !cmdPtr->isproc) {
+
+ return;
+ }
+
+ objPtr = Jim_NewStringObj(interp, he->key, -1);
+ Jim_IncrRefCount(objPtr);
+
+ if (type != JIM_CMDLIST_CHANNELS || Jim_AioFilehandle(interp, objPtr)) {
+ Jim_ListAppendElement(interp, listObjPtr, objPtr);
+ }
+ Jim_DecrRefCount(interp, objPtr);
+}
+
+
+static Jim_Obj *JimCommandsList(Jim_Interp *interp, Jim_Obj *patternObjPtr, int type)
+{
+ return JimHashtablePatternMatch(interp, &interp->commands, patternObjPtr, JimCommandMatch, type);
+}
+
+
+#define JIM_VARLIST_GLOBALS 0
+#define JIM_VARLIST_LOCALS 1
+#define JIM_VARLIST_VARS 2
+
+#define JIM_VARLIST_VALUES 0x1000
+
+static void JimVariablesMatch(Jim_Interp *interp, Jim_Obj *listObjPtr,
+ Jim_HashEntry *he, int type)
+{
+ Jim_Var *varPtr = (Jim_Var *)he->u.val;
+
+ if (type != JIM_VARLIST_LOCALS || varPtr->linkFramePtr == NULL) {
+ Jim_ListAppendElement(interp, listObjPtr, Jim_NewStringObj(interp, he->key, -1));
+ if (type & JIM_VARLIST_VALUES) {
+ Jim_ListAppendElement(interp, listObjPtr, varPtr->objPtr);
+ }
+ }
+}
+
+
+static Jim_Obj *JimVariablesList(Jim_Interp *interp, Jim_Obj *patternObjPtr, int mode)
+{
+ if (mode == JIM_VARLIST_LOCALS && interp->framePtr == interp->topFramePtr) {
+ return interp->emptyObj;
+ }
+ else {
+ Jim_CallFrame *framePtr = (mode == JIM_VARLIST_GLOBALS) ? interp->topFramePtr : interp->framePtr;
+ return JimHashtablePatternMatch(interp, &framePtr->vars, patternObjPtr, JimVariablesMatch, mode);
+ }
+}
+
+static int JimInfoLevel(Jim_Interp *interp, Jim_Obj *levelObjPtr,
+ Jim_Obj **objPtrPtr, int info_level_cmd)
+{
+ Jim_CallFrame *targetCallFrame;
+
+ targetCallFrame = JimGetCallFrameByInteger(interp, levelObjPtr);
+ if (targetCallFrame == NULL) {
+ return JIM_ERR;
+ }
+
+ if (targetCallFrame == interp->topFramePtr) {
+ Jim_SetResultFormatted(interp, "bad level \"%#s\"", levelObjPtr);
+ return JIM_ERR;
+ }
+ if (info_level_cmd) {
+ *objPtrPtr = Jim_NewListObj(interp, targetCallFrame->argv, targetCallFrame->argc);
+ }
+ else {
+ Jim_Obj *listObj = Jim_NewListObj(interp, NULL, 0);
+
+ Jim_ListAppendElement(interp, listObj, targetCallFrame->argv[0]);
+ Jim_ListAppendElement(interp, listObj, targetCallFrame->fileNameObj);
+ Jim_ListAppendElement(interp, listObj, Jim_NewIntObj(interp, targetCallFrame->line));
+ *objPtrPtr = listObj;
+ }
+ return JIM_OK;
+}
+
+
+
+static int Jim_PutsCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ if (argc != 2 && argc != 3) {
+ Jim_WrongNumArgs(interp, 1, argv, "?-nonewline? string");
+ return JIM_ERR;
+ }
+ if (argc == 3) {
+ if (!Jim_CompareStringImmediate(interp, argv[1], "-nonewline")) {
+ Jim_SetResultString(interp, "The second argument must " "be -nonewline", -1);
+ return JIM_ERR;
+ }
+ else {
+ fputs(Jim_String(argv[2]), stdout);
+ }
+ }
+ else {
+ puts(Jim_String(argv[1]));
+ }
+ return JIM_OK;
+}
+
+
+static int JimAddMulHelper(Jim_Interp *interp, int argc, Jim_Obj *const *argv, int op)
+{
+ jim_wide wideValue, res;
+ double doubleValue, doubleRes;
+ int i;
+
+ res = (op == JIM_EXPROP_ADD) ? 0 : 1;
+
+ for (i = 1; i < argc; i++) {
+ if (Jim_GetWide(interp, argv[i], &wideValue) != JIM_OK)
+ goto trydouble;
+ if (op == JIM_EXPROP_ADD)
+ res += wideValue;
+ else
+ res *= wideValue;
+ }
+ Jim_SetResultInt(interp, res);
+ return JIM_OK;
+ trydouble:
+ doubleRes = (double)res;
+ for (; i < argc; i++) {
+ if (Jim_GetDouble(interp, argv[i], &doubleValue) != JIM_OK)
+ return JIM_ERR;
+ if (op == JIM_EXPROP_ADD)
+ doubleRes += doubleValue;
+ else
+ doubleRes *= doubleValue;
+ }
+ Jim_SetResult(interp, Jim_NewDoubleObj(interp, doubleRes));
+ return JIM_OK;
+}
+
+
+static int JimSubDivHelper(Jim_Interp *interp, int argc, Jim_Obj *const *argv, int op)
+{
+ jim_wide wideValue, res = 0;
+ double doubleValue, doubleRes = 0;
+ int i = 2;
+
+ if (argc < 2) {
+ Jim_WrongNumArgs(interp, 1, argv, "number ?number ... number?");
+ return JIM_ERR;
+ }
+ else if (argc == 2) {
+ if (Jim_GetWide(interp, argv[1], &wideValue) != JIM_OK) {
+ if (Jim_GetDouble(interp, argv[1], &doubleValue) != JIM_OK) {
+ return JIM_ERR;
+ }
+ else {
+ if (op == JIM_EXPROP_SUB)
+ doubleRes = -doubleValue;
+ else
+ doubleRes = 1.0 / doubleValue;
+ Jim_SetResult(interp, Jim_NewDoubleObj(interp, doubleRes));
+ return JIM_OK;
+ }
+ }
+ if (op == JIM_EXPROP_SUB) {
+ res = -wideValue;
+ Jim_SetResultInt(interp, res);
+ }
+ else {
+ doubleRes = 1.0 / wideValue;
+ Jim_SetResult(interp, Jim_NewDoubleObj(interp, doubleRes));
+ }
+ return JIM_OK;
+ }
+ else {
+ if (Jim_GetWide(interp, argv[1], &res) != JIM_OK) {
+ if (Jim_GetDouble(interp, argv[1], &doubleRes)
+ != JIM_OK) {
+ return JIM_ERR;
+ }
+ else {
+ goto trydouble;
+ }
+ }
+ }
+ for (i = 2; i < argc; i++) {
+ if (Jim_GetWide(interp, argv[i], &wideValue) != JIM_OK) {
+ doubleRes = (double)res;
+ goto trydouble;
+ }
+ if (op == JIM_EXPROP_SUB)
+ res -= wideValue;
+ else
+ res /= wideValue;
+ }
+ Jim_SetResultInt(interp, res);
+ return JIM_OK;
+ trydouble:
+ for (; i < argc; i++) {
+ if (Jim_GetDouble(interp, argv[i], &doubleValue) != JIM_OK)
+ return JIM_ERR;
+ if (op == JIM_EXPROP_SUB)
+ doubleRes -= doubleValue;
+ else
+ doubleRes /= doubleValue;
+ }
+ Jim_SetResult(interp, Jim_NewDoubleObj(interp, doubleRes));
+ return JIM_OK;
+}
+
+
+
+static int Jim_AddCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ return JimAddMulHelper(interp, argc, argv, JIM_EXPROP_ADD);
+}
+
+
+static int Jim_MulCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ return JimAddMulHelper(interp, argc, argv, JIM_EXPROP_MUL);
+}
+
+
+static int Jim_SubCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ return JimSubDivHelper(interp, argc, argv, JIM_EXPROP_SUB);
+}
+
+
+static int Jim_DivCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ return JimSubDivHelper(interp, argc, argv, JIM_EXPROP_DIV);
+}
+
+
+static int Jim_SetCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ if (argc != 2 && argc != 3) {
+ Jim_WrongNumArgs(interp, 1, argv, "varName ?newValue?");
+ return JIM_ERR;
+ }
+ if (argc == 2) {
+ Jim_Obj *objPtr;
+
+ objPtr = Jim_GetVariable(interp, argv[1], JIM_ERRMSG);
+ if (!objPtr)
+ return JIM_ERR;
+ Jim_SetResult(interp, objPtr);
+ return JIM_OK;
+ }
+
+ if (Jim_SetVariable(interp, argv[1], argv[2]) != JIM_OK)
+ return JIM_ERR;
+ Jim_SetResult(interp, argv[2]);
+ return JIM_OK;
+}
+
+static int Jim_UnsetCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ int i = 1;
+ int complain = 1;
+
+ while (i < argc) {
+ if (Jim_CompareStringImmediate(interp, argv[i], "--")) {
+ i++;
+ break;
+ }
+ if (Jim_CompareStringImmediate(interp, argv[i], "-nocomplain")) {
+ complain = 0;
+ i++;
+ continue;
+ }
+ break;
+ }
+
+ while (i < argc) {
+ if (Jim_UnsetVariable(interp, argv[i], complain ? JIM_ERRMSG : JIM_NONE) != JIM_OK
+ && complain) {
+ return JIM_ERR;
+ }
+ i++;
+ }
+ return JIM_OK;
+}
+
+
+static int Jim_WhileCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ if (argc != 3) {
+ Jim_WrongNumArgs(interp, 1, argv, "condition body");
+ return JIM_ERR;
+ }
+
+
+ while (1) {
+ int boolean, retval;
+
+ if ((retval = Jim_GetBoolFromExpr(interp, argv[1], &boolean)) != JIM_OK)
+ return retval;
+ if (!boolean)
+ break;
+
+ if ((retval = Jim_EvalObj(interp, argv[2])) != JIM_OK) {
+ switch (retval) {
+ case JIM_BREAK:
+ goto out;
+ break;
+ case JIM_CONTINUE:
+ continue;
+ break;
+ default:
+ return retval;
+ }
+ }
+ }
+ out:
+ Jim_SetEmptyResult(interp);
+ return JIM_OK;
+}
+
+
+static int Jim_ForCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ int retval;
+ int boolean = 1;
+ Jim_Obj *varNamePtr = NULL;
+ Jim_Obj *stopVarNamePtr = NULL;
+
+ if (argc != 5) {
+ Jim_WrongNumArgs(interp, 1, argv, "start test next body");
+ return JIM_ERR;
+ }
+
+
+ if ((retval = Jim_EvalObj(interp, argv[1])) != JIM_OK) {
+ return retval;
+ }
+
+ retval = Jim_GetBoolFromExpr(interp, argv[2], &boolean);
+
+
+#ifdef JIM_OPTIMIZATION
+ if (retval == JIM_OK && boolean) {
+ ScriptObj *incrScript;
+ ExprByteCode *expr;
+ jim_wide stop, currentVal;
+ Jim_Obj *objPtr;
+ int cmpOffset;
+
+
+ expr = JimGetExpression(interp, argv[2]);
+ incrScript = Jim_GetScript(interp, argv[3]);
+
+
+ if (incrScript->len != 3 || !expr || expr->len != 3) {
+ goto evalstart;
+ }
+
+ if (incrScript->token[1].type != JIM_TT_ESC ||
+ expr->token[0].type != JIM_TT_VAR ||
+ (expr->token[1].type != JIM_TT_EXPR_INT && expr->token[1].type != JIM_TT_VAR)) {
+ goto evalstart;
+ }
+
+ if (expr->token[2].type == JIM_EXPROP_LT) {
+ cmpOffset = 0;
+ }
+ else if (expr->token[2].type == JIM_EXPROP_LTE) {
+ cmpOffset = 1;
+ }
+ else {
+ goto evalstart;
+ }
+
+
+ if (!Jim_CompareStringImmediate(interp, incrScript->token[1].objPtr, "incr")) {
+ goto evalstart;
+ }
+
+
+ if (!Jim_StringEqObj(incrScript->token[2].objPtr, expr->token[0].objPtr)) {
+ goto evalstart;
+ }
+
+
+ if (expr->token[1].type == JIM_TT_EXPR_INT) {
+ if (Jim_GetWide(interp, expr->token[1].objPtr, &stop) == JIM_ERR) {
+ goto evalstart;
+ }
+ }
+ else {
+ stopVarNamePtr = expr->token[1].objPtr;
+ Jim_IncrRefCount(stopVarNamePtr);
+
+ stop = 0;
+ }
+
+
+ varNamePtr = expr->token[0].objPtr;
+ Jim_IncrRefCount(varNamePtr);
+
+ objPtr = Jim_GetVariable(interp, varNamePtr, JIM_NONE);
+ if (objPtr == NULL || Jim_GetWide(interp, objPtr, ¤tVal) != JIM_OK) {
+ goto testcond;
+ }
+
+
+ while (retval == JIM_OK) {
+
+
+
+
+ if (stopVarNamePtr) {
+ objPtr = Jim_GetVariable(interp, stopVarNamePtr, JIM_NONE);
+ if (objPtr == NULL || Jim_GetWide(interp, objPtr, &stop) != JIM_OK) {
+ goto testcond;
+ }
+ }
+
+ if (currentVal >= stop + cmpOffset) {
+ break;
+ }
+
+
+ retval = Jim_EvalObj(interp, argv[4]);
+ if (retval == JIM_OK || retval == JIM_CONTINUE) {
+ retval = JIM_OK;
+
+ objPtr = Jim_GetVariable(interp, varNamePtr, JIM_ERRMSG);
+
+
+ if (objPtr == NULL) {
+ retval = JIM_ERR;
+ goto out;
+ }
+ if (!Jim_IsShared(objPtr) && objPtr->typePtr == &intObjType) {
+ currentVal = ++JimWideValue(objPtr);
+ Jim_InvalidateStringRep(objPtr);
+ }
+ else {
+ if (Jim_GetWide(interp, objPtr, ¤tVal) != JIM_OK ||
+ Jim_SetVariable(interp, varNamePtr, Jim_NewIntObj(interp,
+ ++currentVal)) != JIM_OK) {
+ goto evalnext;
+ }
+ }
+ }
+ }
+ goto out;
+ }
+ evalstart:
+#endif
+
+ while (boolean && (retval == JIM_OK || retval == JIM_CONTINUE)) {
+
+ retval = Jim_EvalObj(interp, argv[4]);
+
+ if (retval == JIM_OK || retval == JIM_CONTINUE) {
+
+ evalnext:
+ retval = Jim_EvalObj(interp, argv[3]);
+ if (retval == JIM_OK || retval == JIM_CONTINUE) {
+
+ testcond:
+ retval = Jim_GetBoolFromExpr(interp, argv[2], &boolean);
+ }
+ }
+ }
+ out:
+ if (stopVarNamePtr) {
+ Jim_DecrRefCount(interp, stopVarNamePtr);
+ }
+ if (varNamePtr) {
+ Jim_DecrRefCount(interp, varNamePtr);
+ }
+
+ if (retval == JIM_CONTINUE || retval == JIM_BREAK || retval == JIM_OK) {
+ Jim_SetEmptyResult(interp);
+ return JIM_OK;
+ }
+
+ return retval;
+}
+
+
+static int Jim_LoopCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ int retval;
+ jim_wide i;
+ jim_wide limit;
+ jim_wide incr = 1;
+ Jim_Obj *bodyObjPtr;
+
+ if (argc != 5 && argc != 6) {
+ Jim_WrongNumArgs(interp, 1, argv, "var first limit ?incr? body");
+ return JIM_ERR;
+ }
+
+ if (Jim_GetWide(interp, argv[2], &i) != JIM_OK ||
+ Jim_GetWide(interp, argv[3], &limit) != JIM_OK ||
+ (argc == 6 && Jim_GetWide(interp, argv[4], &incr) != JIM_OK)) {
+ return JIM_ERR;
+ }
+ bodyObjPtr = (argc == 5) ? argv[4] : argv[5];
+
+ retval = Jim_SetVariable(interp, argv[1], argv[2]);
+
+ while (((i < limit && incr > 0) || (i > limit && incr < 0)) && retval == JIM_OK) {
+ retval = Jim_EvalObj(interp, bodyObjPtr);
+ if (retval == JIM_OK || retval == JIM_CONTINUE) {
+ Jim_Obj *objPtr = Jim_GetVariable(interp, argv[1], JIM_ERRMSG);
+
+ retval = JIM_OK;
+
+
+ i += incr;
+
+ if (objPtr && !Jim_IsShared(objPtr) && objPtr->typePtr == &intObjType) {
+ if (argv[1]->typePtr != &variableObjType) {
+ if (Jim_SetVariable(interp, argv[1], objPtr) != JIM_OK) {
+ return JIM_ERR;
+ }
+ }
+ JimWideValue(objPtr) = i;
+ Jim_InvalidateStringRep(objPtr);
+
+ if (argv[1]->typePtr != &variableObjType) {
+ if (Jim_SetVariable(interp, argv[1], objPtr) != JIM_OK) {
+ retval = JIM_ERR;
+ break;
+ }
+ }
+ }
+ else {
+ objPtr = Jim_NewIntObj(interp, i);
+ retval = Jim_SetVariable(interp, argv[1], objPtr);
+ if (retval != JIM_OK) {
+ Jim_FreeNewObj(interp, objPtr);
+ }
+ }
+ }
+ }
+
+ if (retval == JIM_OK || retval == JIM_CONTINUE || retval == JIM_BREAK) {
+ Jim_SetEmptyResult(interp);
+ return JIM_OK;
+ }
+ return retval;
+}
+
+typedef struct {
+ Jim_Obj *objPtr;
+ int idx;
+} Jim_ListIter;
+
+static void JimListIterInit(Jim_ListIter *iter, Jim_Obj *objPtr)
+{
+ iter->objPtr = objPtr;
+ iter->idx = 0;
+}
+
+static Jim_Obj *JimListIterNext(Jim_Interp *interp, Jim_ListIter *iter)
+{
+ if (iter->idx >= Jim_ListLength(interp, iter->objPtr)) {
+ return NULL;
+ }
+ return iter->objPtr->internalRep.listValue.ele[iter->idx++];
+}
+
+static int JimListIterDone(Jim_Interp *interp, Jim_ListIter *iter)
+{
+ return iter->idx >= Jim_ListLength(interp, iter->objPtr);
+}
+
+
+static int JimForeachMapHelper(Jim_Interp *interp, int argc, Jim_Obj *const *argv, int doMap)
+{
+ int result = JIM_ERR;
+ int i, numargs;
+ Jim_ListIter twoiters[2];
+ Jim_ListIter *iters;
+ Jim_Obj *script;
+ Jim_Obj *resultObj;
+
+ if (argc < 4 || argc % 2 != 0) {
+ Jim_WrongNumArgs(interp, 1, argv, "varList list ?varList list ...? script");
+ return JIM_ERR;
+ }
+ script = argv[argc - 1];
+ numargs = (argc - 1 - 1);
+
+ if (numargs == 2) {
+ iters = twoiters;
+ }
+ else {
+ iters = Jim_Alloc(numargs * sizeof(*iters));
+ }
+ for (i = 0; i < numargs; i++) {
+ JimListIterInit(&iters[i], argv[i + 1]);
+ if (i % 2 == 0 && JimListIterDone(interp, &iters[i])) {
+ Jim_SetResultString(interp, "foreach varlist is empty", -1);
+ return JIM_ERR;
+ }
+ }
+
+ if (doMap) {
+ resultObj = Jim_NewListObj(interp, NULL, 0);
+ }
+ else {
+ resultObj = interp->emptyObj;
+ }
+ Jim_IncrRefCount(resultObj);
+
+ while (1) {
+
+ for (i = 0; i < numargs; i += 2) {
+ if (!JimListIterDone(interp, &iters[i + 1])) {
+ break;
+ }
+ }
+ if (i == numargs) {
+
+ break;
+ }
+
+
+ for (i = 0; i < numargs; i += 2) {
+ Jim_Obj *varName;
+
+
+ JimListIterInit(&iters[i], argv[i + 1]);
+ while ((varName = JimListIterNext(interp, &iters[i])) != NULL) {
+ Jim_Obj *valObj = JimListIterNext(interp, &iters[i + 1]);
+ if (!valObj) {
+
+ valObj = interp->emptyObj;
+ }
+
+ Jim_IncrRefCount(valObj);
+ result = Jim_SetVariable(interp, varName, valObj);
+ Jim_DecrRefCount(interp, valObj);
+ if (result != JIM_OK) {
+ goto err;
+ }
+ }
+ }
+ switch (result = Jim_EvalObj(interp, script)) {
+ case JIM_OK:
+ if (doMap) {
+ Jim_ListAppendElement(interp, resultObj, interp->result);
+ }
+ break;
+ case JIM_CONTINUE:
+ break;
+ case JIM_BREAK:
+ goto out;
+ default:
+ goto err;
+ }
+ }
+ out:
+ result = JIM_OK;
+ Jim_SetResult(interp, resultObj);
+ err:
+ Jim_DecrRefCount(interp, resultObj);
+ if (numargs > 2) {
+ Jim_Free(iters);
+ }
+ return result;
+}
+
+
+static int Jim_ForeachCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ return JimForeachMapHelper(interp, argc, argv, 0);
+}
+
+
+static int Jim_LmapCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ return JimForeachMapHelper(interp, argc, argv, 1);
+}
+
+
+static int Jim_LassignCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ int result = JIM_ERR;
+ int i;
+ Jim_ListIter iter;
+ Jim_Obj *resultObj;
+
+ if (argc < 2) {
+ Jim_WrongNumArgs(interp, 1, argv, "varList list ?varName ...?");
+ return JIM_ERR;
+ }
+
+ JimListIterInit(&iter, argv[1]);
+
+ for (i = 2; i < argc; i++) {
+ Jim_Obj *valObj = JimListIterNext(interp, &iter);
+ result = Jim_SetVariable(interp, argv[i], valObj ? valObj : interp->emptyObj);
+ if (result != JIM_OK) {
+ return result;
+ }
+ }
+
+ resultObj = Jim_NewListObj(interp, NULL, 0);
+ while (!JimListIterDone(interp, &iter)) {
+ Jim_ListAppendElement(interp, resultObj, JimListIterNext(interp, &iter));
+ }
+
+ Jim_SetResult(interp, resultObj);
+
+ return JIM_OK;
+}
+
+
+static int Jim_IfCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ int boolean, retval, current = 1, falsebody = 0;
+
+ if (argc >= 3) {
+ while (1) {
+
+ if (current >= argc)
+ goto err;
+ if ((retval = Jim_GetBoolFromExpr(interp, argv[current++], &boolean))
+ != JIM_OK)
+ return retval;
+
+ if (current >= argc)
+ goto err;
+ if (Jim_CompareStringImmediate(interp, argv[current], "then"))
+ current++;
+
+ if (current >= argc)
+ goto err;
+ if (boolean)
+ return Jim_EvalObj(interp, argv[current]);
+
+ if (++current >= argc) {
+ Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
+ return JIM_OK;
+ }
+ falsebody = current++;
+ if (Jim_CompareStringImmediate(interp, argv[falsebody], "else")) {
+
+ if (current != argc - 1)
+ goto err;
+ return Jim_EvalObj(interp, argv[current]);
+ }
+ else if (Jim_CompareStringImmediate(interp, argv[falsebody], "elseif"))
+ continue;
+
+ else if (falsebody != argc - 1)
+ goto err;
+ return Jim_EvalObj(interp, argv[falsebody]);
+ }
+ return JIM_OK;
+ }
+ err:
+ Jim_WrongNumArgs(interp, 1, argv, "condition ?then? trueBody ?elseif ...? ?else? falseBody");
+ return JIM_ERR;
+}
+
+
+
+int Jim_CommandMatchObj(Jim_Interp *interp, Jim_Obj *commandObj, Jim_Obj *patternObj,
+ Jim_Obj *stringObj, int nocase)
+{
+ Jim_Obj *parms[4];
+ int argc = 0;
+ long eq;
+ int rc;
+
+ parms[argc++] = commandObj;
+ if (nocase) {
+ parms[argc++] = Jim_NewStringObj(interp, "-nocase", -1);
+ }
+ parms[argc++] = patternObj;
+ parms[argc++] = stringObj;
+
+ rc = Jim_EvalObjVector(interp, argc, parms);
+
+ if (rc != JIM_OK || Jim_GetLong(interp, Jim_GetResult(interp), &eq) != JIM_OK) {
+ eq = -rc;
+ }
+
+ return eq;
+}
+
+enum
+{ SWITCH_EXACT, SWITCH_GLOB, SWITCH_RE, SWITCH_CMD };
+
+
+static int Jim_SwitchCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ int matchOpt = SWITCH_EXACT, opt = 1, patCount, i;
+ Jim_Obj *command = 0, *const *caseList = 0, *strObj;
+ Jim_Obj *script = 0;
+
+ if (argc < 3) {
+ wrongnumargs:
+ Jim_WrongNumArgs(interp, 1, argv, "?options? string "
+ "pattern body ... ?default body? or " "{pattern body ?pattern body ...?}");
+ return JIM_ERR;
+ }
+ for (opt = 1; opt < argc; ++opt) {
+ const char *option = Jim_String(argv[opt]);
+
+ if (*option != '-')
+ break;
+ else if (strncmp(option, "--", 2) == 0) {
+ ++opt;
+ break;
+ }
+ else if (strncmp(option, "-exact", 2) == 0)
+ matchOpt = SWITCH_EXACT;
+ else if (strncmp(option, "-glob", 2) == 0)
+ matchOpt = SWITCH_GLOB;
+ else if (strncmp(option, "-regexp", 2) == 0)
+ matchOpt = SWITCH_RE;
+ else if (strncmp(option, "-command", 2) == 0) {
+ matchOpt = SWITCH_CMD;
+ if ((argc - opt) < 2)
+ goto wrongnumargs;
+ command = argv[++opt];
+ }
+ else {
+ Jim_SetResultFormatted(interp,
+ "bad option \"%#s\": must be -exact, -glob, -regexp, -command procname or --",
+ argv[opt]);
+ return JIM_ERR;
+ }
+ if ((argc - opt) < 2)
+ goto wrongnumargs;
+ }
+ strObj = argv[opt++];
+ patCount = argc - opt;
+ if (patCount == 1) {
+ Jim_Obj **vector;
+
+ JimListGetElements(interp, argv[opt], &patCount, &vector);
+ caseList = vector;
+ }
+ else
+ caseList = &argv[opt];
+ if (patCount == 0 || patCount % 2 != 0)
+ goto wrongnumargs;
+ for (i = 0; script == 0 && i < patCount; i += 2) {
+ Jim_Obj *patObj = caseList[i];
+
+ if (!Jim_CompareStringImmediate(interp, patObj, "default")
+ || i < (patCount - 2)) {
+ switch (matchOpt) {
+ case SWITCH_EXACT:
+ if (Jim_StringEqObj(strObj, patObj))
+ script = caseList[i + 1];
+ break;
+ case SWITCH_GLOB:
+ if (Jim_StringMatchObj(interp, patObj, strObj, 0))
+ script = caseList[i + 1];
+ break;
+ case SWITCH_RE:
+ command = Jim_NewStringObj(interp, "regexp", -1);
+
+ case SWITCH_CMD:{
+ int rc = Jim_CommandMatchObj(interp, command, patObj, strObj, 0);
+
+ if (argc - opt == 1) {
+ Jim_Obj **vector;
+
+ JimListGetElements(interp, argv[opt], &patCount, &vector);
+ caseList = vector;
+ }
+
+ if (rc < 0) {
+ return -rc;
+ }
+ if (rc)
+ script = caseList[i + 1];
+ break;
+ }
+ }
+ }
+ else {
+ script = caseList[i + 1];
+ }
+ }
+ for (; i < patCount && Jim_CompareStringImmediate(interp, script, "-"); i += 2)
+ script = caseList[i + 1];
+ if (script && Jim_CompareStringImmediate(interp, script, "-")) {
+ Jim_SetResultFormatted(interp, "no body specified for pattern \"%#s\"", caseList[i - 2]);
+ return JIM_ERR;
+ }
+ Jim_SetEmptyResult(interp);
+ if (script) {
+ return Jim_EvalObj(interp, script);
+ }
+ return JIM_OK;
+}
+
+
+static int Jim_ListCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ Jim_Obj *listObjPtr;
+
+ listObjPtr = Jim_NewListObj(interp, argv + 1, argc - 1);
+ Jim_SetResult(interp, listObjPtr);
+ return JIM_OK;
+}
+
+
+static int Jim_LindexCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ Jim_Obj *objPtr, *listObjPtr;
+ int i;
+ int idx;
+
+ if (argc < 3) {
+ Jim_WrongNumArgs(interp, 1, argv, "list index ?...?");
+ return JIM_ERR;
+ }
+ objPtr = argv[1];
+ Jim_IncrRefCount(objPtr);
+ for (i = 2; i < argc; i++) {
+ listObjPtr = objPtr;
+ if (Jim_GetIndex(interp, argv[i], &idx) != JIM_OK) {
+ Jim_DecrRefCount(interp, listObjPtr);
+ return JIM_ERR;
+ }
+ if (Jim_ListIndex(interp, listObjPtr, idx, &objPtr, JIM_NONE) != JIM_OK) {
+ Jim_DecrRefCount(interp, listObjPtr);
+ Jim_SetEmptyResult(interp);
+ return JIM_OK;
+ }
+ Jim_IncrRefCount(objPtr);
+ Jim_DecrRefCount(interp, listObjPtr);
+ }
+ Jim_SetResult(interp, objPtr);
+ Jim_DecrRefCount(interp, objPtr);
+ return JIM_OK;
+}
+
+
+static int Jim_LlengthCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ if (argc != 2) {
+ Jim_WrongNumArgs(interp, 1, argv, "list");
+ return JIM_ERR;
+ }
+ Jim_SetResultInt(interp, Jim_ListLength(interp, argv[1]));
+ return JIM_OK;
+}
+
+
+static int Jim_LsearchCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ static const char * const options[] = {
+ "-bool", "-not", "-nocase", "-exact", "-glob", "-regexp", "-all", "-inline", "-command",
+ NULL
+ };
+ enum
+ { OPT_BOOL, OPT_NOT, OPT_NOCASE, OPT_EXACT, OPT_GLOB, OPT_REGEXP, OPT_ALL, OPT_INLINE,
+ OPT_COMMAND };
+ int i;
+ int opt_bool = 0;
+ int opt_not = 0;
+ int opt_nocase = 0;
+ int opt_all = 0;
+ int opt_inline = 0;
+ int opt_match = OPT_EXACT;
+ int listlen;
+ int rc = JIM_OK;
+ Jim_Obj *listObjPtr = NULL;
+ Jim_Obj *commandObj = NULL;
+
+ if (argc < 3) {
+ wrongargs:
+ Jim_WrongNumArgs(interp, 1, argv,
+ "?-exact|-glob|-regexp|-command 'command'? ?-bool|-inline? ?-not? ?-nocase? ?-all? list value");
+ return JIM_ERR;
+ }
+
+ for (i = 1; i < argc - 2; i++) {
+ int option;
+
+ if (Jim_GetEnum(interp, argv[i], options, &option, NULL, JIM_ERRMSG) != JIM_OK) {
+ return JIM_ERR;
+ }
+ switch (option) {
+ case OPT_BOOL:
+ opt_bool = 1;
+ opt_inline = 0;
+ break;
+ case OPT_NOT:
+ opt_not = 1;
+ break;
+ case OPT_NOCASE:
+ opt_nocase = 1;
+ break;
+ case OPT_INLINE:
+ opt_inline = 1;
+ opt_bool = 0;
+ break;
+ case OPT_ALL:
+ opt_all = 1;
+ break;
+ case OPT_COMMAND:
+ if (i >= argc - 2) {
+ goto wrongargs;
+ }
+ commandObj = argv[++i];
+
+ case OPT_EXACT:
+ case OPT_GLOB:
+ case OPT_REGEXP:
+ opt_match = option;
+ break;
+ }
+ }
+
+ argv += i;
+
+ if (opt_all) {
+ listObjPtr = Jim_NewListObj(interp, NULL, 0);
+ }
+ if (opt_match == OPT_REGEXP) {
+ commandObj = Jim_NewStringObj(interp, "regexp", -1);
+ }
+ if (commandObj) {
+ Jim_IncrRefCount(commandObj);
+ }
+
+ listlen = Jim_ListLength(interp, argv[0]);
+ for (i = 0; i < listlen; i++) {
+ Jim_Obj *objPtr;
+ int eq = 0;
+
+ Jim_ListIndex(interp, argv[0], i, &objPtr, JIM_NONE);
+ switch (opt_match) {
+ case OPT_EXACT:
+ eq = Jim_StringCompareObj(interp, argv[1], objPtr, opt_nocase) == 0;
+ break;
+
+ case OPT_GLOB:
+ eq = Jim_StringMatchObj(interp, argv[1], objPtr, opt_nocase);
+ break;
+
+ case OPT_REGEXP:
+ case OPT_COMMAND:
+ eq = Jim_CommandMatchObj(interp, commandObj, argv[1], objPtr, opt_nocase);
+ if (eq < 0) {
+ if (listObjPtr) {
+ Jim_FreeNewObj(interp, listObjPtr);
+ }
+ rc = JIM_ERR;
+ goto done;
+ }
+ break;
+ }
+
+
+ if (!eq && opt_bool && opt_not && !opt_all) {
+ continue;
+ }
+
+ if ((!opt_bool && eq == !opt_not) || (opt_bool && (eq || opt_all))) {
+
+ Jim_Obj *resultObj;
+
+ if (opt_bool) {
+ resultObj = Jim_NewIntObj(interp, eq ^ opt_not);
+ }
+ else if (!opt_inline) {
+ resultObj = Jim_NewIntObj(interp, i);
+ }
+ else {
+ resultObj = objPtr;
+ }
+
+ if (opt_all) {
+ Jim_ListAppendElement(interp, listObjPtr, resultObj);
+ }
+ else {
+ Jim_SetResult(interp, resultObj);
+ goto done;
+ }
+ }
+ }
+
+ if (opt_all) {
+ Jim_SetResult(interp, listObjPtr);
+ }
+ else {
+
+ if (opt_bool) {
+ Jim_SetResultBool(interp, opt_not);
+ }
+ else if (!opt_inline) {
+ Jim_SetResultInt(interp, -1);
+ }
+ }
+
+ done:
+ if (commandObj) {
+ Jim_DecrRefCount(interp, commandObj);
+ }
+ return rc;
+}
+
+
+static int Jim_LappendCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ Jim_Obj *listObjPtr;
+ int shared, i;
+
+ if (argc < 2) {
+ Jim_WrongNumArgs(interp, 1, argv, "varName ?value value ...?");
+ return JIM_ERR;
+ }
+ listObjPtr = Jim_GetVariable(interp, argv[1], JIM_UNSHARED);
+ if (!listObjPtr) {
+
+ listObjPtr = Jim_NewListObj(interp, NULL, 0);
+ if (Jim_SetVariable(interp, argv[1], listObjPtr) != JIM_OK) {
+ Jim_FreeNewObj(interp, listObjPtr);
+ return JIM_ERR;
+ }
+ }
+ shared = Jim_IsShared(listObjPtr);
+ if (shared)
+ listObjPtr = Jim_DuplicateObj(interp, listObjPtr);
+ for (i = 2; i < argc; i++)
+ Jim_ListAppendElement(interp, listObjPtr, argv[i]);
+ if (Jim_SetVariable(interp, argv[1], listObjPtr) != JIM_OK) {
+ if (shared)
+ Jim_FreeNewObj(interp, listObjPtr);
+ return JIM_ERR;
+ }
+ Jim_SetResult(interp, listObjPtr);
+ return JIM_OK;
+}
+
+
+static int Jim_LinsertCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ int idx, len;
+ Jim_Obj *listPtr;
+
+ if (argc < 3) {
+ Jim_WrongNumArgs(interp, 1, argv, "list index ?element ...?");
+ return JIM_ERR;
+ }
+ listPtr = argv[1];
+ if (Jim_IsShared(listPtr))
+ listPtr = Jim_DuplicateObj(interp, listPtr);
+ if (Jim_GetIndex(interp, argv[2], &idx) != JIM_OK)
+ goto err;
+ len = Jim_ListLength(interp, listPtr);
+ if (idx >= len)
+ idx = len;
+ else if (idx < 0)
+ idx = len + idx + 1;
+ Jim_ListInsertElements(interp, listPtr, idx, argc - 3, &argv[3]);
+ Jim_SetResult(interp, listPtr);
+ return JIM_OK;
+ err:
+ if (listPtr != argv[1]) {
+ Jim_FreeNewObj(interp, listPtr);
+ }
+ return JIM_ERR;
+}
+
+
+static int Jim_LreplaceCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ int first, last, len, rangeLen;
+ Jim_Obj *listObj;
+ Jim_Obj *newListObj;
+
+ if (argc < 4) {
+ Jim_WrongNumArgs(interp, 1, argv, "list first last ?element ...?");
+ return JIM_ERR;
+ }
+ if (Jim_GetIndex(interp, argv[2], &first) != JIM_OK ||
+ Jim_GetIndex(interp, argv[3], &last) != JIM_OK) {
+ return JIM_ERR;
+ }
+
+ listObj = argv[1];
+ len = Jim_ListLength(interp, listObj);
+
+ first = JimRelToAbsIndex(len, first);
+ last = JimRelToAbsIndex(len, last);
+ JimRelToAbsRange(len, &first, &last, &rangeLen);
+
+
+
+ if (first < len) {
+
+ }
+ else if (len == 0) {
+
+ first = 0;
+ }
+ else {
+ Jim_SetResultString(interp, "list doesn't contain element ", -1);
+ Jim_AppendObj(interp, Jim_GetResult(interp), argv[2]);
+ return JIM_ERR;
+ }
+
+
+ newListObj = Jim_NewListObj(interp, listObj->internalRep.listValue.ele, first);
+
+
+ ListInsertElements(newListObj, -1, argc - 4, argv + 4);
+
+
+ ListInsertElements(newListObj, -1, len - first - rangeLen, listObj->internalRep.listValue.ele + first + rangeLen);
+
+ Jim_SetResult(interp, newListObj);
+ return JIM_OK;
+}
+
+
+static int Jim_LsetCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ if (argc < 3) {
+ Jim_WrongNumArgs(interp, 1, argv, "listVar ?index...? newVal");
+ return JIM_ERR;
+ }
+ else if (argc == 3) {
+ if (Jim_SetVariable(interp, argv[1], argv[2]) != JIM_OK)
+ return JIM_ERR;
+ Jim_SetResult(interp, argv[2]);
+ return JIM_OK;
+ }
+ if (Jim_SetListIndex(interp, argv[1], argv + 2, argc - 3, argv[argc - 1])
+ == JIM_ERR)
+ return JIM_ERR;
+ return JIM_OK;
+}
+
+
+static int Jim_LsortCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const argv[])
+{
+ static const char * const options[] = {
+ "-ascii", "-nocase", "-increasing", "-decreasing", "-command", "-integer", "-index", NULL
+ };
+ enum
+ { OPT_ASCII, OPT_NOCASE, OPT_INCREASING, OPT_DECREASING, OPT_COMMAND, OPT_INTEGER, OPT_INDEX };
+ Jim_Obj *resObj;
+ int i;
+ int retCode;
+
+ struct lsort_info info;
+
+ if (argc < 2) {
+ Jim_WrongNumArgs(interp, 1, argv, "?options? list");
+ return JIM_ERR;
+ }
+
+ info.type = JIM_LSORT_ASCII;
+ info.order = 1;
+ info.indexed = 0;
+ info.command = NULL;
+ info.interp = interp;
+
+ for (i = 1; i < (argc - 1); i++) {
+ int option;
+
+ if (Jim_GetEnum(interp, argv[i], options, &option, NULL, JIM_ERRMSG)
+ != JIM_OK)
+ return JIM_ERR;
+ switch (option) {
+ case OPT_ASCII:
+ info.type = JIM_LSORT_ASCII;
+ break;
+ case OPT_NOCASE:
+ info.type = JIM_LSORT_NOCASE;
+ break;
+ case OPT_INTEGER:
+ info.type = JIM_LSORT_INTEGER;
+ break;
+ case OPT_INCREASING:
+ info.order = 1;
+ break;
+ case OPT_DECREASING:
+ info.order = -1;
+ break;
+ case OPT_COMMAND:
+ if (i >= (argc - 2)) {
+ Jim_SetResultString(interp, "\"-command\" option must be followed by comparison command", -1);
+ return JIM_ERR;
+ }
+ info.type = JIM_LSORT_COMMAND;
+ info.command = argv[i + 1];
+ i++;
+ break;
+ case OPT_INDEX:
+ if (i >= (argc - 2)) {
+ Jim_SetResultString(interp, "\"-index\" option must be followed by list index", -1);
+ return JIM_ERR;
+ }
+ if (Jim_GetIndex(interp, argv[i + 1], &info.index) != JIM_OK) {
+ return JIM_ERR;
+ }
+ info.indexed = 1;
+ i++;
+ break;
+ }
+ }
+ resObj = Jim_DuplicateObj(interp, argv[argc - 1]);
+ retCode = ListSortElements(interp, resObj, &info);
+ if (retCode == JIM_OK) {
+ Jim_SetResult(interp, resObj);
+ }
+ else {
+ Jim_FreeNewObj(interp, resObj);
+ }
+ return retCode;
+}
+
+
+static int Jim_AppendCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ Jim_Obj *stringObjPtr;
+ int i;
+
+ if (argc < 2) {
+ Jim_WrongNumArgs(interp, 1, argv, "varName ?value value ...?");
+ return JIM_ERR;
+ }
+ if (argc == 2) {
+ stringObjPtr = Jim_GetVariable(interp, argv[1], JIM_ERRMSG);
+ if (!stringObjPtr)
+ return JIM_ERR;
+ }
+ else {
+ int freeobj = 0;
+ stringObjPtr = Jim_GetVariable(interp, argv[1], JIM_UNSHARED);
+ if (!stringObjPtr) {
+
+ stringObjPtr = Jim_NewEmptyStringObj(interp);
+ freeobj = 1;
+ }
+ else if (Jim_IsShared(stringObjPtr)) {
+ freeobj = 1;
+ stringObjPtr = Jim_DuplicateObj(interp, stringObjPtr);
+ }
+ for (i = 2; i < argc; i++) {
+ Jim_AppendObj(interp, stringObjPtr, argv[i]);
+ }
+ if (Jim_SetVariable(interp, argv[1], stringObjPtr) != JIM_OK) {
+ if (freeobj) {
+ Jim_FreeNewObj(interp, stringObjPtr);
+ }
+ return JIM_ERR;
+ }
+ }
+ Jim_SetResult(interp, stringObjPtr);
+ return JIM_OK;
+}
+
+
+static int Jim_DebugCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+#if !defined(JIM_DEBUG_COMMAND)
+ Jim_SetResultString(interp, "unsupported", -1);
+ return JIM_ERR;
+#endif
+}
+
+
+static int Jim_EvalCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ int rc;
+
+ if (argc < 2) {
+ Jim_WrongNumArgs(interp, 1, argv, "script ?...?");
+ return JIM_ERR;
+ }
+
+ if (argc == 2) {
+ rc = Jim_EvalObj(interp, argv[1]);
+ }
+ else {
+ rc = Jim_EvalObj(interp, Jim_ConcatObj(interp, argc - 1, argv + 1));
+ }
+
+ if (rc == JIM_ERR) {
+
+ interp->addStackTrace++;
+ }
+ return rc;
+}
+
+
+static int Jim_UplevelCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ if (argc >= 2) {
+ int retcode;
+ Jim_CallFrame *savedCallFrame, *targetCallFrame;
+ Jim_Obj *objPtr;
+ const char *str;
+
+
+ savedCallFrame = interp->framePtr;
+
+
+ str = Jim_String(argv[1]);
+ if ((str[0] >= '0' && str[0] <= '9') || str[0] == '#') {
+ targetCallFrame =Jim_GetCallFrameByLevel(interp, argv[1]);
+ argc--;
+ argv++;
+ }
+ else {
+ targetCallFrame = Jim_GetCallFrameByLevel(interp, NULL);
+ }
+ if (targetCallFrame == NULL) {
+ return JIM_ERR;
+ }
+ if (argc < 2) {
+ argv--;
+ Jim_WrongNumArgs(interp, 1, argv, "?level? command ?arg ...?");
+ return JIM_ERR;
+ }
+
+ interp->framePtr = targetCallFrame;
+ if (argc == 2) {
+ retcode = Jim_EvalObj(interp, argv[1]);
+ }
+ else {
+ objPtr = Jim_ConcatObj(interp, argc - 1, argv + 1);
+ Jim_IncrRefCount(objPtr);
+ retcode = Jim_EvalObj(interp, objPtr);
+ Jim_DecrRefCount(interp, objPtr);
+ }
+ interp->framePtr = savedCallFrame;
+ return retcode;
+ }
+ else {
+ Jim_WrongNumArgs(interp, 1, argv, "?level? command ?arg ...?");
+ return JIM_ERR;
+ }
+}
+
+
+static int Jim_ExprCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ Jim_Obj *exprResultPtr;
+ int retcode;
+
+ if (argc == 2) {
+ retcode = Jim_EvalExpression(interp, argv[1], &exprResultPtr);
+ }
+ else if (argc > 2) {
+ Jim_Obj *objPtr;
+
+ objPtr = Jim_ConcatObj(interp, argc - 1, argv + 1);
+ Jim_IncrRefCount(objPtr);
+ retcode = Jim_EvalExpression(interp, objPtr, &exprResultPtr);
+ Jim_DecrRefCount(interp, objPtr);
+ }
+ else {
+ Jim_WrongNumArgs(interp, 1, argv, "expression ?...?");
+ return JIM_ERR;
+ }
+ if (retcode != JIM_OK)
+ return retcode;
+ Jim_SetResult(interp, exprResultPtr);
+ Jim_DecrRefCount(interp, exprResultPtr);
+ return JIM_OK;
+}
+
+
+static int Jim_BreakCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ if (argc != 1) {
+ Jim_WrongNumArgs(interp, 1, argv, "");
+ return JIM_ERR;
+ }
+ return JIM_BREAK;
+}
+
+
+static int Jim_ContinueCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ if (argc != 1) {
+ Jim_WrongNumArgs(interp, 1, argv, "");
+ return JIM_ERR;
+ }
+ return JIM_CONTINUE;
+}
+
+
+static int Jim_ReturnCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ int i;
+ Jim_Obj *stackTraceObj = NULL;
+ Jim_Obj *errorCodeObj = NULL;
+ int returnCode = JIM_OK;
+ long level = 1;
+
+ for (i = 1; i < argc - 1; i += 2) {
+ if (Jim_CompareStringImmediate(interp, argv[i], "-code")) {
+ if (Jim_GetReturnCode(interp, argv[i + 1], &returnCode) == JIM_ERR) {
+ return JIM_ERR;
+ }
+ }
+ else if (Jim_CompareStringImmediate(interp, argv[i], "-errorinfo")) {
+ stackTraceObj = argv[i + 1];
+ }
+ else if (Jim_CompareStringImmediate(interp, argv[i], "-errorcode")) {
+ errorCodeObj = argv[i + 1];
+ }
+ else if (Jim_CompareStringImmediate(interp, argv[i], "-level")) {
+ if (Jim_GetLong(interp, argv[i + 1], &level) != JIM_OK || level < 0) {
+ Jim_SetResultFormatted(interp, "bad level \"%#s\"", argv[i + 1]);
+ return JIM_ERR;
+ }
+ }
+ else {
+ break;
+ }
+ }
+
+ if (i != argc - 1 && i != argc) {
+ Jim_WrongNumArgs(interp, 1, argv,
+ "?-code code? ?-errorinfo stacktrace? ?-level level? ?result?");
+ }
+
+
+ if (stackTraceObj && returnCode == JIM_ERR) {
+ JimSetStackTrace(interp, stackTraceObj);
+ }
+
+ if (errorCodeObj && returnCode == JIM_ERR) {
+ Jim_SetGlobalVariableStr(interp, "errorCode", errorCodeObj);
+ }
+ interp->returnCode = returnCode;
+ interp->returnLevel = level;
+
+ if (i == argc - 1) {
+ Jim_SetResult(interp, argv[i]);
+ }
+ return JIM_RETURN;
+}
+
+
+static int Jim_TailcallCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ Jim_SetResult(interp, Jim_NewListObj(interp, argv + 1, argc - 1));
+ return JIM_EVAL;
+}
+
+static int JimAliasCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ Jim_Obj *cmdList;
+ Jim_Obj *prefixListObj = Jim_CmdPrivData(interp);
+
+
+ cmdList = Jim_DuplicateObj(interp, prefixListObj);
+ ListInsertElements(cmdList, -1, argc - 1, argv + 1);
+
+ return JimEvalObjList(interp, cmdList);
+}
+
+static void JimAliasCmdDelete(Jim_Interp *interp, void *privData)
+{
+ Jim_Obj *prefixListObj = privData;
+ Jim_DecrRefCount(interp, prefixListObj);
+}
+
+static int Jim_AliasCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ Jim_Obj *prefixListObj;
+ const char *newname;
+
+ if (argc < 3) {
+ Jim_WrongNumArgs(interp, 1, argv, "newname command ?args ...?");
+ return JIM_ERR;
+ }
+
+ prefixListObj = Jim_NewListObj(interp, argv + 2, argc - 2);
+ Jim_IncrRefCount(prefixListObj);
+ newname = Jim_String(argv[1]);
+ if (newname[0] == ':' && newname[1] == ':') {
+ while (*++newname == ':') {
+ }
+ }
+
+ Jim_SetResult(interp, argv[1]);
+
+ return Jim_CreateCommand(interp, newname, JimAliasCmd, prefixListObj, JimAliasCmdDelete);
+}
+
+
+static int Jim_ProcCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ Jim_Cmd *cmd;
+
+ if (argc != 4 && argc != 5) {
+ Jim_WrongNumArgs(interp, 1, argv, "name arglist ?statics? body");
+ return JIM_ERR;
+ }
+
+ if (JimValidName(interp, "procedure", argv[1]) != JIM_OK) {
+ return JIM_ERR;
+ }
+
+ if (argc == 4) {
+ cmd = JimCreateProcedureCmd(interp, argv[2], NULL, argv[3], NULL);
+ }
+ else {
+ cmd = JimCreateProcedureCmd(interp, argv[2], argv[3], argv[4], NULL);
+ }
+
+ if (cmd) {
+
+ Jim_Obj *qualifiedCmdNameObj;
+ const char *cmdname = JimQualifyName(interp, Jim_String(argv[1]), &qualifiedCmdNameObj);
+
+ JimCreateCommand(interp, cmdname, cmd);
+
+
+ JimUpdateProcNamespace(interp, cmd, cmdname);
+
+ JimFreeQualifiedName(interp, qualifiedCmdNameObj);
+
+
+ Jim_SetResult(interp, argv[1]);
+ return JIM_OK;
+ }
+ return JIM_ERR;
+}
+
+
+static int Jim_LocalCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ int retcode;
+
+
+ interp->local++;
+ retcode = Jim_EvalObjVector(interp, argc - 1, argv + 1);
+ interp->local--;
+
+
+
+ if (retcode == 0) {
+ Jim_Obj *cmdNameObj = Jim_GetResult(interp);
+
+ if (Jim_GetCommand(interp, cmdNameObj, JIM_ERRMSG) == NULL) {
+ return JIM_ERR;
+ }
+ if (interp->framePtr->localCommands == NULL) {
+ interp->framePtr->localCommands = Jim_Alloc(sizeof(*interp->framePtr->localCommands));
+ Jim_InitStack(interp->framePtr->localCommands);
+ }
+ Jim_IncrRefCount(cmdNameObj);
+ Jim_StackPush(interp->framePtr->localCommands, cmdNameObj);
+ }
+
+ return retcode;
+}
+
+
+static int Jim_UpcallCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ if (argc < 2) {
+ Jim_WrongNumArgs(interp, 1, argv, "cmd ?args ...?");
+ return JIM_ERR;
+ }
+ else {
+ int retcode;
+
+ Jim_Cmd *cmdPtr = Jim_GetCommand(interp, argv[1], JIM_ERRMSG);
+ if (cmdPtr == NULL || !cmdPtr->isproc || !cmdPtr->prevCmd) {
+ Jim_SetResultFormatted(interp, "no previous command: \"%#s\"", argv[1]);
+ return JIM_ERR;
+ }
+
+ cmdPtr->u.proc.upcall++;
+ JimIncrCmdRefCount(cmdPtr);
+
+
+ retcode = Jim_EvalObjVector(interp, argc - 1, argv + 1);
+
+
+ cmdPtr->u.proc.upcall--;
+ JimDecrCmdRefCount(interp, cmdPtr);
+
+ return retcode;
+ }
+}
+
+
+static int Jim_ApplyCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ if (argc < 2) {
+ Jim_WrongNumArgs(interp, 1, argv, "lambdaExpr ?arg ...?");
+ return JIM_ERR;
+ }
+ else {
+ int ret;
+ Jim_Cmd *cmd;
+ Jim_Obj *argListObjPtr;
+ Jim_Obj *bodyObjPtr;
+ Jim_Obj *nsObj = NULL;
+ Jim_Obj **nargv;
+
+ int len = Jim_ListLength(interp, argv[1]);
+ if (len != 2 && len != 3) {
+ Jim_SetResultFormatted(interp, "can't interpret \"%#s\" as a lambda expression", argv[1]);
+ return JIM_ERR;
+ }
+
+ if (len == 3) {
+#ifdef jim_ext_namespace
+
+ nsObj = JimQualifyNameObj(interp, Jim_ListGetIndex(interp, argv[1], 2));
+#else
+ Jim_SetResultString(interp, "namespaces not enabled", -1);
+ return JIM_ERR;
+#endif
+ }
+ argListObjPtr = Jim_ListGetIndex(interp, argv[1], 0);
+ bodyObjPtr = Jim_ListGetIndex(interp, argv[1], 1);
+
+ cmd = JimCreateProcedureCmd(interp, argListObjPtr, NULL, bodyObjPtr, nsObj);
+
+ if (cmd) {
+
+ nargv = Jim_Alloc((argc - 2 + 1) * sizeof(*nargv));
+ nargv[0] = Jim_NewStringObj(interp, "apply lambdaExpr", -1);
+ Jim_IncrRefCount(nargv[0]);
+ memcpy(&nargv[1], argv + 2, (argc - 2) * sizeof(*nargv));
+ ret = JimCallProcedure(interp, cmd, argc - 2 + 1, nargv);
+ Jim_DecrRefCount(interp, nargv[0]);
+ Jim_Free(nargv);
+
+ JimDecrCmdRefCount(interp, cmd);
+ return ret;
+ }
+ return JIM_ERR;
+ }
+}
+
+
+
+static int Jim_ConcatCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ Jim_SetResult(interp, Jim_ConcatObj(interp, argc - 1, argv + 1));
+ return JIM_OK;
+}
+
+
+static int Jim_UpvarCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ int i;
+ Jim_CallFrame *targetCallFrame;
+
+
+ if (argc > 3 && (argc % 2 == 0)) {
+ targetCallFrame = Jim_GetCallFrameByLevel(interp, argv[1]);
+ argc--;
+ argv++;
+ }
+ else {
+ targetCallFrame = Jim_GetCallFrameByLevel(interp, NULL);
+ }
+ if (targetCallFrame == NULL) {
+ return JIM_ERR;
+ }
+
+
+ if (argc < 3) {
+ Jim_WrongNumArgs(interp, 1, argv, "?level? otherVar localVar ?otherVar localVar ...?");
+ return JIM_ERR;
+ }
+
+
+ for (i = 1; i < argc; i += 2) {
+ if (Jim_SetVariableLink(interp, argv[i + 1], argv[i], targetCallFrame) != JIM_OK)
+ return JIM_ERR;
+ }
+ return JIM_OK;
+}
+
+
+static int Jim_GlobalCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ int i;
+
+ if (argc < 2) {
+ Jim_WrongNumArgs(interp, 1, argv, "varName ?varName ...?");
+ return JIM_ERR;
+ }
+
+ if (interp->framePtr->level == 0)
+ return JIM_OK;
+ for (i = 1; i < argc; i++) {
+
+ const char *name = Jim_String(argv[i]);
+ if (name[0] != ':' || name[1] != ':') {
+ if (Jim_SetVariableLink(interp, argv[i], argv[i], interp->topFramePtr) != JIM_OK)
+ return JIM_ERR;
+ }
+ }
+ return JIM_OK;
+}
+
+static Jim_Obj *JimStringMap(Jim_Interp *interp, Jim_Obj *mapListObjPtr,
+ Jim_Obj *objPtr, int nocase)
+{
+ int numMaps;
+ const char *str, *noMatchStart = NULL;
+ int strLen, i;
+ Jim_Obj *resultObjPtr;
+
+ numMaps = Jim_ListLength(interp, mapListObjPtr);
+ if (numMaps % 2) {
+ Jim_SetResultString(interp, "list must contain an even number of elements", -1);
+ return NULL;
+ }
+
+ str = Jim_String(objPtr);
+ strLen = Jim_Utf8Length(interp, objPtr);
+
+
+ resultObjPtr = Jim_NewStringObj(interp, "", 0);
+ while (strLen) {
+ for (i = 0; i < numMaps; i += 2) {
+ Jim_Obj *objPtr;
+ const char *k;
+ int kl;
+
+ Jim_ListIndex(interp, mapListObjPtr, i, &objPtr, JIM_NONE);
+ k = Jim_String(objPtr);
+ kl = Jim_Utf8Length(interp, objPtr);
+
+ if (strLen >= kl && kl) {
+ int rc;
+ rc = JimStringCompareLen(str, k, kl, nocase);
+ if (rc == 0) {
+ if (noMatchStart) {
+ Jim_AppendString(interp, resultObjPtr, noMatchStart, str - noMatchStart);
+ noMatchStart = NULL;
+ }
+ Jim_ListIndex(interp, mapListObjPtr, i + 1, &objPtr, JIM_NONE);
+ Jim_AppendObj(interp, resultObjPtr, objPtr);
+ str += utf8_index(str, kl);
+ strLen -= kl;
+ break;
+ }
+ }
+ }
+ if (i == numMaps) {
+ int c;
+ if (noMatchStart == NULL)
+ noMatchStart = str;
+ str += utf8_tounicode(str, &c);
+ strLen--;
+ }
+ }
+ if (noMatchStart) {
+ Jim_AppendString(interp, resultObjPtr, noMatchStart, str - noMatchStart);
+ }
+ return resultObjPtr;
+}
+
+
+static int Jim_StringCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ int len;
+ int opt_case = 1;
+ int option;
+ static const char * const options[] = {
+ "bytelength", "length", "compare", "match", "equal", "is", "byterange", "range", "replace",
+ "map", "repeat", "reverse", "index", "first", "last",
+ "trim", "trimleft", "trimright", "tolower", "toupper", "totitle", NULL
+ };
+ enum
+ {
+ OPT_BYTELENGTH, OPT_LENGTH, OPT_COMPARE, OPT_MATCH, OPT_EQUAL, OPT_IS, OPT_BYTERANGE, OPT_RANGE, OPT_REPLACE,
+ OPT_MAP, OPT_REPEAT, OPT_REVERSE, OPT_INDEX, OPT_FIRST, OPT_LAST,
+ OPT_TRIM, OPT_TRIMLEFT, OPT_TRIMRIGHT, OPT_TOLOWER, OPT_TOUPPER, OPT_TOTITLE
+ };
+ static const char * const nocase_options[] = {
+ "-nocase", NULL
+ };
+ static const char * const nocase_length_options[] = {
+ "-nocase", "-length", NULL
+ };
+
+ if (argc < 2) {
+ Jim_WrongNumArgs(interp, 1, argv, "option ?arguments ...?");
+ return JIM_ERR;
+ }
+ if (Jim_GetEnum(interp, argv[1], options, &option, NULL,
+ JIM_ERRMSG | JIM_ENUM_ABBREV) != JIM_OK)
+ return JIM_ERR;
+
+ switch (option) {
+ case OPT_LENGTH:
+ case OPT_BYTELENGTH:
+ if (argc != 3) {
+ Jim_WrongNumArgs(interp, 2, argv, "string");
+ return JIM_ERR;
+ }
+ if (option == OPT_LENGTH) {
+ len = Jim_Utf8Length(interp, argv[2]);
+ }
+ else {
+ len = Jim_Length(argv[2]);
+ }
+ Jim_SetResultInt(interp, len);
+ return JIM_OK;
+
+ case OPT_COMPARE:
+ case OPT_EQUAL:
+ {
+
+ long opt_length = -1;
+ int n = argc - 4;
+ int i = 2;
+ while (n > 0) {
+ int subopt;
+ if (Jim_GetEnum(interp, argv[i++], nocase_length_options, &subopt, NULL,
+ JIM_ENUM_ABBREV) != JIM_OK) {
+badcompareargs:
+ Jim_WrongNumArgs(interp, 2, argv, "?-nocase? ?-length int? string1 string2");
+ return JIM_ERR;
+ }
+ if (subopt == 0) {
+
+ opt_case = 0;
+ n--;
+ }
+ else {
+
+ if (n < 2) {
+ goto badcompareargs;
+ }
+ if (Jim_GetLong(interp, argv[i++], &opt_length) != JIM_OK) {
+ return JIM_ERR;
+ }
+ n -= 2;
+ }
+ }
+ if (n) {
+ goto badcompareargs;
+ }
+ argv += argc - 2;
+ if (opt_length < 0 && option != OPT_COMPARE && opt_case) {
+
+ Jim_SetResultBool(interp, Jim_StringEqObj(argv[0], argv[1]));
+ }
+ else {
+ if (opt_length >= 0) {
+ n = JimStringCompareLen(Jim_String(argv[0]), Jim_String(argv[1]), opt_length, !opt_case);
+ }
+ else {
+ n = Jim_StringCompareObj(interp, argv[0], argv[1], !opt_case);
+ }
+ Jim_SetResultInt(interp, option == OPT_COMPARE ? n : n == 0);
+ }
+ return JIM_OK;
+ }
+
+ case OPT_MATCH:
+ if (argc != 4 &&
+ (argc != 5 ||
+ Jim_GetEnum(interp, argv[2], nocase_options, &opt_case, NULL,
+ JIM_ENUM_ABBREV) != JIM_OK)) {
+ Jim_WrongNumArgs(interp, 2, argv, "?-nocase? pattern string");
+ return JIM_ERR;
+ }
+ if (opt_case == 0) {
+ argv++;
+ }
+ Jim_SetResultBool(interp, Jim_StringMatchObj(interp, argv[2], argv[3], !opt_case));
+ return JIM_OK;
+
+ case OPT_MAP:{
+ Jim_Obj *objPtr;
+
+ if (argc != 4 &&
+ (argc != 5 ||
+ Jim_GetEnum(interp, argv[2], nocase_options, &opt_case, NULL,
+ JIM_ENUM_ABBREV) != JIM_OK)) {
+ Jim_WrongNumArgs(interp, 2, argv, "?-nocase? mapList string");
+ return JIM_ERR;
+ }
+
+ if (opt_case == 0) {
+ argv++;
+ }
+ objPtr = JimStringMap(interp, argv[2], argv[3], !opt_case);
+ if (objPtr == NULL) {
+ return JIM_ERR;
+ }
+ Jim_SetResult(interp, objPtr);
+ return JIM_OK;
+ }
+
+ case OPT_RANGE:
+ case OPT_BYTERANGE:{
+ Jim_Obj *objPtr;
+
+ if (argc != 5) {
+ Jim_WrongNumArgs(interp, 2, argv, "string first last");
+ return JIM_ERR;
+ }
+ if (option == OPT_RANGE) {
+ objPtr = Jim_StringRangeObj(interp, argv[2], argv[3], argv[4]);
+ }
+ else
+ {
+ objPtr = Jim_StringByteRangeObj(interp, argv[2], argv[3], argv[4]);
+ }
+
+ if (objPtr == NULL) {
+ return JIM_ERR;
+ }
+ Jim_SetResult(interp, objPtr);
+ return JIM_OK;
+ }
+
+ case OPT_REPLACE:{
+ Jim_Obj *objPtr;
+
+ if (argc != 5 && argc != 6) {
+ Jim_WrongNumArgs(interp, 2, argv, "string first last ?string?");
+ return JIM_ERR;
+ }
+ objPtr = JimStringReplaceObj(interp, argv[2], argv[3], argv[4], argc == 6 ? argv[5] : NULL);
+ if (objPtr == NULL) {
+ return JIM_ERR;
+ }
+ Jim_SetResult(interp, objPtr);
+ return JIM_OK;
+ }
+
+
+ case OPT_REPEAT:{
+ Jim_Obj *objPtr;
+ jim_wide count;
+
+ if (argc != 4) {
+ Jim_WrongNumArgs(interp, 2, argv, "string count");
+ return JIM_ERR;
+ }
+ if (Jim_GetWide(interp, argv[3], &count) != JIM_OK) {
+ return JIM_ERR;
+ }
+ objPtr = Jim_NewStringObj(interp, "", 0);
+ if (count > 0) {
+ while (count--) {
+ Jim_AppendObj(interp, objPtr, argv[2]);
+ }
+ }
+ Jim_SetResult(interp, objPtr);
+ return JIM_OK;
+ }
+
+ case OPT_REVERSE:{
+ char *buf, *p;
+ const char *str;
+ int len;
+ int i;
+
+ if (argc != 3) {
+ Jim_WrongNumArgs(interp, 2, argv, "string");
+ return JIM_ERR;
+ }
+
+ str = Jim_GetString(argv[2], &len);
+ buf = Jim_Alloc(len + 1);
+ p = buf + len;
+ *p = 0;
+ for (i = 0; i < len; ) {
+ int c;
+ int l = utf8_tounicode(str, &c);
+ memcpy(p - l, str, l);
+ p -= l;
+ i += l;
+ str += l;
+ }
+ Jim_SetResult(interp, Jim_NewStringObjNoAlloc(interp, buf, len));
+ return JIM_OK;
+ }
+
+ case OPT_INDEX:{
+ int idx;
+ const char *str;
+
+ if (argc != 4) {
+ Jim_WrongNumArgs(interp, 2, argv, "string index");
+ return JIM_ERR;
+ }
+ if (Jim_GetIndex(interp, argv[3], &idx) != JIM_OK) {
+ return JIM_ERR;
+ }
+ str = Jim_String(argv[2]);
+ len = Jim_Utf8Length(interp, argv[2]);
+ if (idx != INT_MIN && idx != INT_MAX) {
+ idx = JimRelToAbsIndex(len, idx);
+ }
+ if (idx < 0 || idx >= len || str == NULL) {
+ Jim_SetResultString(interp, "", 0);
+ }
+ else if (len == Jim_Length(argv[2])) {
+
+ Jim_SetResultString(interp, str + idx, 1);
+ }
+ else {
+ int c;
+ int i = utf8_index(str, idx);
+ Jim_SetResultString(interp, str + i, utf8_tounicode(str + i, &c));
+ }
+ return JIM_OK;
+ }
+
+ case OPT_FIRST:
+ case OPT_LAST:{
+ int idx = 0, l1, l2;
+ const char *s1, *s2;
+
+ if (argc != 4 && argc != 5) {
+ Jim_WrongNumArgs(interp, 2, argv, "subString string ?index?");
+ return JIM_ERR;
+ }
+ s1 = Jim_String(argv[2]);
+ s2 = Jim_String(argv[3]);
+ l1 = Jim_Utf8Length(interp, argv[2]);
+ l2 = Jim_Utf8Length(interp, argv[3]);
+ if (argc == 5) {
+ if (Jim_GetIndex(interp, argv[4], &idx) != JIM_OK) {
+ return JIM_ERR;
+ }
+ idx = JimRelToAbsIndex(l2, idx);
+ }
+ else if (option == OPT_LAST) {
+ idx = l2;
+ }
+ if (option == OPT_FIRST) {
+ Jim_SetResultInt(interp, JimStringFirst(s1, l1, s2, l2, idx));
+ }
+ else {
+#ifdef JIM_UTF8
+ Jim_SetResultInt(interp, JimStringLastUtf8(s1, l1, s2, idx));
+#else
+ Jim_SetResultInt(interp, JimStringLast(s1, l1, s2, idx));
+#endif
+ }
+ return JIM_OK;
+ }
+
+ case OPT_TRIM:
+ case OPT_TRIMLEFT:
+ case OPT_TRIMRIGHT:{
+ Jim_Obj *trimchars;
+
+ if (argc != 3 && argc != 4) {
+ Jim_WrongNumArgs(interp, 2, argv, "string ?trimchars?");
+ return JIM_ERR;
+ }
+ trimchars = (argc == 4 ? argv[3] : NULL);
+ if (option == OPT_TRIM) {
+ Jim_SetResult(interp, JimStringTrim(interp, argv[2], trimchars));
+ }
+ else if (option == OPT_TRIMLEFT) {
+ Jim_SetResult(interp, JimStringTrimLeft(interp, argv[2], trimchars));
+ }
+ else if (option == OPT_TRIMRIGHT) {
+ Jim_SetResult(interp, JimStringTrimRight(interp, argv[2], trimchars));
+ }
+ return JIM_OK;
+ }
+
+ case OPT_TOLOWER:
+ case OPT_TOUPPER:
+ case OPT_TOTITLE:
+ if (argc != 3) {
+ Jim_WrongNumArgs(interp, 2, argv, "string");
+ return JIM_ERR;
+ }
+ if (option == OPT_TOLOWER) {
+ Jim_SetResult(interp, JimStringToLower(interp, argv[2]));
+ }
+ else if (option == OPT_TOUPPER) {
+ Jim_SetResult(interp, JimStringToUpper(interp, argv[2]));
+ }
+ else {
+ Jim_SetResult(interp, JimStringToTitle(interp, argv[2]));
+ }
+ return JIM_OK;
+
+ case OPT_IS:
+ if (argc == 4 || (argc == 5 && Jim_CompareStringImmediate(interp, argv[3], "-strict"))) {
+ return JimStringIs(interp, argv[argc - 1], argv[2], argc == 5);
+ }
+ Jim_WrongNumArgs(interp, 2, argv, "class ?-strict? str");
+ return JIM_ERR;
+ }
+ return JIM_OK;
+}
+
+
+static int Jim_TimeCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ long i, count = 1;
+ jim_wide start, elapsed;
+ char buf[60];
+ const char *fmt = "%" JIM_WIDE_MODIFIER " microseconds per iteration";
+
+ if (argc < 2) {
+ Jim_WrongNumArgs(interp, 1, argv, "script ?count?");
+ return JIM_ERR;
+ }
+ if (argc == 3) {
+ if (Jim_GetLong(interp, argv[2], &count) != JIM_OK)
+ return JIM_ERR;
+ }
+ if (count < 0)
+ return JIM_OK;
+ i = count;
+ start = JimClock();
+ while (i-- > 0) {
+ int retval;
+
+ retval = Jim_EvalObj(interp, argv[1]);
+ if (retval != JIM_OK) {
+ return retval;
+ }
+ }
+ elapsed = JimClock() - start;
+ sprintf(buf, fmt, count == 0 ? 0 : elapsed / count);
+ Jim_SetResultString(interp, buf, -1);
+ return JIM_OK;
+}
+
+
+static int Jim_ExitCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ long exitCode = 0;
+
+ if (argc > 2) {
+ Jim_WrongNumArgs(interp, 1, argv, "?exitCode?");
+ return JIM_ERR;
+ }
+ if (argc == 2) {
+ if (Jim_GetLong(interp, argv[1], &exitCode) != JIM_OK)
+ return JIM_ERR;
+ }
+ interp->exitCode = exitCode;
+ return JIM_EXIT;
+}
+
+
+static int Jim_CatchCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ int exitCode = 0;
+ int i;
+ int sig = 0;
+
+
+ jim_wide ignore_mask = (1 << JIM_EXIT) | (1 << JIM_EVAL) | (1 << JIM_SIGNAL);
+ static const int max_ignore_code = sizeof(ignore_mask) * 8;
+
+ Jim_SetGlobalVariableStr(interp, "errorCode", Jim_NewStringObj(interp, "NONE", -1));
+
+ for (i = 1; i < argc - 1; i++) {
+ const char *arg = Jim_String(argv[i]);
+ jim_wide option;
+ int ignore;
+
+
+ if (strcmp(arg, "--") == 0) {
+ i++;
+ break;
+ }
+ if (*arg != '-') {
+ break;
+ }
+
+ if (strncmp(arg, "-no", 3) == 0) {
+ arg += 3;
+ ignore = 1;
+ }
+ else {
+ arg++;
+ ignore = 0;
+ }
+
+ if (Jim_StringToWide(arg, &option, 10) != JIM_OK) {
+ option = -1;
+ }
+ if (option < 0) {
+ option = Jim_FindByName(arg, jimReturnCodes, jimReturnCodesSize);
+ }
+ if (option < 0) {
+ goto wrongargs;
+ }
+
+ if (ignore) {
+ ignore_mask |= (1 << option);
+ }
+ else {
+ ignore_mask &= ~(1 << option);
+ }
+ }
+
+ argc -= i;
+ if (argc < 1 || argc > 3) {
+ wrongargs:
+ Jim_WrongNumArgs(interp, 1, argv,
+ "?-?no?code ... --? script ?resultVarName? ?optionVarName?");
+ return JIM_ERR;
+ }
+ argv += i;
+
+ if ((ignore_mask & (1 << JIM_SIGNAL)) == 0) {
+ sig++;
+ }
+
+ interp->signal_level += sig;
+ if (interp->signal_level && interp->sigmask) {
+
+ exitCode = JIM_SIGNAL;
+ }
+ else {
+ exitCode = Jim_EvalObj(interp, argv[0]);
+ }
+ interp->signal_level -= sig;
+
+
+ if (exitCode >= 0 && exitCode < max_ignore_code && ((1 << exitCode) & ignore_mask)) {
+
+ return exitCode;
+ }
+
+ if (sig && exitCode == JIM_SIGNAL) {
+
+ if (interp->signal_set_result) {
+ interp->signal_set_result(interp, interp->sigmask);
+ }
+ else {
+ Jim_SetResultInt(interp, interp->sigmask);
+ }
+ interp->sigmask = 0;
+ }
+
+ if (argc >= 2) {
+ if (Jim_SetVariable(interp, argv[1], Jim_GetResult(interp)) != JIM_OK) {
+ return JIM_ERR;
+ }
+ if (argc == 3) {
+ Jim_Obj *optListObj = Jim_NewListObj(interp, NULL, 0);
+
+ Jim_ListAppendElement(interp, optListObj, Jim_NewStringObj(interp, "-code", -1));
+ Jim_ListAppendElement(interp, optListObj,
+ Jim_NewIntObj(interp, exitCode == JIM_RETURN ? interp->returnCode : exitCode));
+ Jim_ListAppendElement(interp, optListObj, Jim_NewStringObj(interp, "-level", -1));
+ Jim_ListAppendElement(interp, optListObj, Jim_NewIntObj(interp, interp->returnLevel));
+ if (exitCode == JIM_ERR) {
+ Jim_Obj *errorCode;
+ Jim_ListAppendElement(interp, optListObj, Jim_NewStringObj(interp, "-errorinfo",
+ -1));
+ Jim_ListAppendElement(interp, optListObj, interp->stackTrace);
+
+ errorCode = Jim_GetGlobalVariableStr(interp, "errorCode", JIM_NONE);
+ if (errorCode) {
+ Jim_ListAppendElement(interp, optListObj, Jim_NewStringObj(interp, "-errorcode", -1));
+ Jim_ListAppendElement(interp, optListObj, errorCode);
+ }
+ }
+ if (Jim_SetVariable(interp, argv[2], optListObj) != JIM_OK) {
+ return JIM_ERR;
+ }
+ }
+ }
+ Jim_SetResultInt(interp, exitCode);
+ return JIM_OK;
+}
+
+#ifdef JIM_REFERENCES
+
+
+static int Jim_RefCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ if (argc != 3 && argc != 4) {
+ Jim_WrongNumArgs(interp, 1, argv, "string tag ?finalizer?");
+ return JIM_ERR;
+ }
+ if (argc == 3) {
+ Jim_SetResult(interp, Jim_NewReference(interp, argv[1], argv[2], NULL));
+ }
+ else {
+ Jim_SetResult(interp, Jim_NewReference(interp, argv[1], argv[2], argv[3]));
+ }
+ return JIM_OK;
+}
+
+
+static int Jim_GetrefCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ Jim_Reference *refPtr;
+
+ if (argc != 2) {
+ Jim_WrongNumArgs(interp, 1, argv, "reference");
+ return JIM_ERR;
+ }
+ if ((refPtr = Jim_GetReference(interp, argv[1])) == NULL)
+ return JIM_ERR;
+ Jim_SetResult(interp, refPtr->objPtr);
+ return JIM_OK;
+}
+
+
+static int Jim_SetrefCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ Jim_Reference *refPtr;
+
+ if (argc != 3) {
+ Jim_WrongNumArgs(interp, 1, argv, "reference newValue");
+ return JIM_ERR;
+ }
+ if ((refPtr = Jim_GetReference(interp, argv[1])) == NULL)
+ return JIM_ERR;
+ Jim_IncrRefCount(argv[2]);
+ Jim_DecrRefCount(interp, refPtr->objPtr);
+ refPtr->objPtr = argv[2];
+ Jim_SetResult(interp, argv[2]);
+ return JIM_OK;
+}
+
+
+static int Jim_CollectCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ if (argc != 1) {
+ Jim_WrongNumArgs(interp, 1, argv, "");
+ return JIM_ERR;
+ }
+ Jim_SetResultInt(interp, Jim_Collect(interp));
+
+
+ while (interp->freeList) {
+ Jim_Obj *nextObjPtr = interp->freeList->nextObjPtr;
+ Jim_Free(interp->freeList);
+ interp->freeList = nextObjPtr;
+ }
+
+ return JIM_OK;
+}
+
+
+static int Jim_FinalizeCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ if (argc != 2 && argc != 3) {
+ Jim_WrongNumArgs(interp, 1, argv, "reference ?finalizerProc?");
+ return JIM_ERR;
+ }
+ if (argc == 2) {
+ Jim_Obj *cmdNamePtr;
+
+ if (Jim_GetFinalizer(interp, argv[1], &cmdNamePtr) != JIM_OK)
+ return JIM_ERR;
+ if (cmdNamePtr != NULL)
+ Jim_SetResult(interp, cmdNamePtr);
+ }
+ else {
+ if (Jim_SetFinalizer(interp, argv[1], argv[2]) != JIM_OK)
+ return JIM_ERR;
+ Jim_SetResult(interp, argv[2]);
+ }
+ return JIM_OK;
+}
+
+
+static int JimInfoReferences(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ Jim_Obj *listObjPtr;
+ Jim_HashTableIterator *htiter;
+ Jim_HashEntry *he;
+
+ listObjPtr = Jim_NewListObj(interp, NULL, 0);
+
+ htiter = Jim_GetHashTableIterator(&interp->references);
+ while ((he = Jim_NextHashEntry(htiter)) != NULL) {
+ char buf[JIM_REFERENCE_SPACE + 1];
+ Jim_Reference *refPtr = he->u.val;
+ const unsigned long *refId = he->key;
+
+ JimFormatReference(buf, refPtr, *refId);
+ Jim_ListAppendElement(interp, listObjPtr, Jim_NewStringObj(interp, buf, -1));
+ }
+ Jim_FreeHashTableIterator(htiter);
+ Jim_SetResult(interp, listObjPtr);
+ return JIM_OK;
+}
+#endif
+
+
+static int Jim_RenameCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ if (argc != 3) {
+ Jim_WrongNumArgs(interp, 1, argv, "oldName newName");
+ return JIM_ERR;
+ }
+
+ if (JimValidName(interp, "new procedure", argv[2])) {
+ return JIM_ERR;
+ }
+
+ return Jim_RenameCommand(interp, Jim_String(argv[1]), Jim_String(argv[2]));
+}
+
+#define JIM_DICTMATCH_VALUES 0x0001
+
+typedef void JimDictMatchCallbackType(Jim_Interp *interp, Jim_Obj *listObjPtr, Jim_HashEntry *he, int type);
+
+static void JimDictMatchKeys(Jim_Interp *interp, Jim_Obj *listObjPtr, Jim_HashEntry *he, int type)
+{
+ Jim_ListAppendElement(interp, listObjPtr, (Jim_Obj *)he->key);
+ if (type & JIM_DICTMATCH_VALUES) {
+ Jim_ListAppendElement(interp, listObjPtr, (Jim_Obj *)he->u.val);
+ }
+}
+
+static Jim_Obj *JimDictPatternMatch(Jim_Interp *interp, Jim_HashTable *ht, Jim_Obj *patternObjPtr,
+ JimDictMatchCallbackType *callback, int type)
+{
+ Jim_HashEntry *he;
+ Jim_Obj *listObjPtr = Jim_NewListObj(interp, NULL, 0);
+
+
+ Jim_HashTableIterator *htiter = Jim_GetHashTableIterator(ht);
+ while ((he = Jim_NextHashEntry(htiter)) != NULL) {
+ if (patternObjPtr == NULL || JimGlobMatch(Jim_String(patternObjPtr), Jim_String((Jim_Obj *)he->key), 0)) {
+ callback(interp, listObjPtr, he, type);
+ }
+ }
+ Jim_FreeHashTableIterator(htiter);
+
+ return listObjPtr;
+}
+
+
+int Jim_DictKeys(Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj *patternObjPtr)
+{
+ if (SetDictFromAny(interp, objPtr) != JIM_OK) {
+ return JIM_ERR;
+ }
+ Jim_SetResult(interp, JimDictPatternMatch(interp, objPtr->internalRep.ptr, patternObjPtr, JimDictMatchKeys, 0));
+ return JIM_OK;
+}
+
+int Jim_DictValues(Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj *patternObjPtr)
+{
+ if (SetDictFromAny(interp, objPtr) != JIM_OK) {
+ return JIM_ERR;
+ }
+ Jim_SetResult(interp, JimDictPatternMatch(interp, objPtr->internalRep.ptr, patternObjPtr, JimDictMatchKeys, JIM_DICTMATCH_VALUES));
+ return JIM_OK;
+}
+
+int Jim_DictSize(Jim_Interp *interp, Jim_Obj *objPtr)
+{
+ if (SetDictFromAny(interp, objPtr) != JIM_OK) {
+ return -1;
+ }
+ return ((Jim_HashTable *)objPtr->internalRep.ptr)->used;
+}
+
+
+static int Jim_DictCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ Jim_Obj *objPtr;
+ int option;
+ static const char * const options[] = {
+ "create", "get", "set", "unset", "exists", "keys", "merge", "size", "with", NULL
+ };
+ enum
+ {
+ OPT_CREATE, OPT_GET, OPT_SET, OPT_UNSET, OPT_EXIST, OPT_KEYS, OPT_MERGE, OPT_SIZE, OPT_WITH,
+ };
+
+ if (argc < 2) {
+ Jim_WrongNumArgs(interp, 1, argv, "subcommand ?arguments ...?");
+ return JIM_ERR;
+ }
+
+ if (Jim_GetEnum(interp, argv[1], options, &option, "subcommand", JIM_ERRMSG) != JIM_OK) {
+ return JIM_ERR;
+ }
+
+ switch (option) {
+ case OPT_GET:
+ if (argc < 3) {
+ Jim_WrongNumArgs(interp, 2, argv, "varName ?key ...?");
+ return JIM_ERR;
+ }
+ if (Jim_DictKeysVector(interp, argv[2], argv + 3, argc - 3, &objPtr,
+ JIM_ERRMSG) != JIM_OK) {
+ return JIM_ERR;
+ }
+ Jim_SetResult(interp, objPtr);
+ return JIM_OK;
+
+ case OPT_SET:
+ if (argc < 5) {
+ Jim_WrongNumArgs(interp, 2, argv, "varName key ?key ...? value");
+ return JIM_ERR;
+ }
+ return Jim_SetDictKeysVector(interp, argv[2], argv + 3, argc - 4, argv[argc - 1], JIM_ERRMSG);
+
+ case OPT_EXIST:
+ if (argc < 3) {
+ Jim_WrongNumArgs(interp, 2, argv, "varName ?key ...?");
+ return JIM_ERR;
+ }
+ Jim_SetResultBool(interp, Jim_DictKeysVector(interp, argv[2], argv + 3, argc - 3,
+ &objPtr, JIM_ERRMSG) == JIM_OK);
+ return JIM_OK;
+
+ case OPT_UNSET:
+ if (argc < 4) {
+ Jim_WrongNumArgs(interp, 2, argv, "varName key ?key ...?");
+ return JIM_ERR;
+ }
+ return Jim_SetDictKeysVector(interp, argv[2], argv + 3, argc - 3, NULL, JIM_NONE);
+
+ case OPT_KEYS:
+ if (argc != 3 && argc != 4) {
+ Jim_WrongNumArgs(interp, 2, argv, "dictVar ?pattern?");
+ return JIM_ERR;
+ }
+ return Jim_DictKeys(interp, argv[2], argc == 4 ? argv[3] : NULL);
+
+ case OPT_SIZE: {
+ int size;
+
+ if (argc != 3) {
+ Jim_WrongNumArgs(interp, 2, argv, "dictVar");
+ return JIM_ERR;
+ }
+
+ size = Jim_DictSize(interp, argv[2]);
+ if (size < 0) {
+ return JIM_ERR;
+ }
+ Jim_SetResultInt(interp, size);
+ return JIM_OK;
+ }
+
+ case OPT_MERGE:
+ if (argc == 2) {
+ return JIM_OK;
+ }
+ else if (SetDictFromAny(interp, argv[2]) != JIM_OK) {
+ return JIM_ERR;
+ }
+ else {
+ return Jim_EvalPrefix(interp, "dict merge", argc - 2, argv + 2);
+ }
+
+ case OPT_WITH:
+ if (argc < 4) {
+ Jim_WrongNumArgs(interp, 2, argv, "dictVar ?key ...? script");
+ return JIM_ERR;
+ }
+ else if (Jim_GetVariable(interp, argv[2], JIM_ERRMSG) == NULL) {
+ return JIM_ERR;
+ }
+ else {
+ return Jim_EvalPrefix(interp, "dict with", argc - 2, argv + 2);
+ }
+
+ case OPT_CREATE:
+ if (argc % 2) {
+ Jim_WrongNumArgs(interp, 2, argv, "?key value ...?");
+ return JIM_ERR;
+ }
+ objPtr = Jim_NewDictObj(interp, argv + 2, argc - 2);
+ Jim_SetResult(interp, objPtr);
+ return JIM_OK;
+ }
+ return JIM_ERR;
+}
+
+
+static int Jim_SubstCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ static const char * const options[] = {
+ "-nobackslashes", "-nocommands", "-novariables", NULL
+ };
+ enum
+ { OPT_NOBACKSLASHES, OPT_NOCOMMANDS, OPT_NOVARIABLES };
+ int i;
+ int flags = JIM_SUBST_FLAG;
+ Jim_Obj *objPtr;
+
+ if (argc < 2) {
+ Jim_WrongNumArgs(interp, 1, argv, "?options? string");
+ return JIM_ERR;
+ }
+ for (i = 1; i < (argc - 1); i++) {
+ int option;
+
+ if (Jim_GetEnum(interp, argv[i], options, &option, NULL,
+ JIM_ERRMSG | JIM_ENUM_ABBREV) != JIM_OK) {
+ return JIM_ERR;
+ }
+ switch (option) {
+ case OPT_NOBACKSLASHES:
+ flags |= JIM_SUBST_NOESC;
+ break;
+ case OPT_NOCOMMANDS:
+ flags |= JIM_SUBST_NOCMD;
+ break;
+ case OPT_NOVARIABLES:
+ flags |= JIM_SUBST_NOVAR;
+ break;
+ }
+ }
+ if (Jim_SubstObj(interp, argv[argc - 1], &objPtr, flags) != JIM_OK) {
+ return JIM_ERR;
+ }
+ Jim_SetResult(interp, objPtr);
+ return JIM_OK;
+}
+
+
+static int Jim_InfoCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ int cmd;
+ Jim_Obj *objPtr;
+ int mode = 0;
+
+ static const char * const commands[] = {
+ "body", "statics", "commands", "procs", "channels", "exists", "globals", "level", "frame", "locals",
+ "vars", "version", "patchlevel", "complete", "args", "hostname",
+ "script", "source", "stacktrace", "nameofexecutable", "returncodes",
+ "references", "alias", NULL
+ };
+ enum
+ { INFO_BODY, INFO_STATICS, INFO_COMMANDS, INFO_PROCS, INFO_CHANNELS, INFO_EXISTS, INFO_GLOBALS, INFO_LEVEL,
+ INFO_FRAME, INFO_LOCALS, INFO_VARS, INFO_VERSION, INFO_PATCHLEVEL, INFO_COMPLETE, INFO_ARGS,
+ INFO_HOSTNAME, INFO_SCRIPT, INFO_SOURCE, INFO_STACKTRACE, INFO_NAMEOFEXECUTABLE,
+ INFO_RETURNCODES, INFO_REFERENCES, INFO_ALIAS
+ };
+
+#ifdef jim_ext_namespace
+ int nons = 0;
+
+ if (argc > 2 && Jim_CompareStringImmediate(interp, argv[1], "-nons")) {
+
+ argc--;
+ argv++;
+ nons = 1;
+ }
+#endif
+
+ if (argc < 2) {
+ Jim_WrongNumArgs(interp, 1, argv, "subcommand ?args ...?");
+ return JIM_ERR;
+ }
+ if (Jim_GetEnum(interp, argv[1], commands, &cmd, "subcommand", JIM_ERRMSG | JIM_ENUM_ABBREV)
+ != JIM_OK) {
+ return JIM_ERR;
+ }
+
+
+ switch (cmd) {
+ case INFO_EXISTS:
+ if (argc != 3) {
+ Jim_WrongNumArgs(interp, 2, argv, "varName");
+ return JIM_ERR;
+ }
+ Jim_SetResultBool(interp, Jim_GetVariable(interp, argv[2], 0) != NULL);
+ break;
+
+ case INFO_ALIAS:{
+ Jim_Cmd *cmdPtr;
+
+ if (argc != 3) {
+ Jim_WrongNumArgs(interp, 2, argv, "command");
+ return JIM_ERR;
+ }
+ if ((cmdPtr = Jim_GetCommand(interp, argv[2], JIM_ERRMSG)) == NULL) {
+ return JIM_ERR;
+ }
+ if (cmdPtr->isproc || cmdPtr->u.native.cmdProc != JimAliasCmd) {
+ Jim_SetResultFormatted(interp, "command \"%#s\" is not an alias", argv[2]);
+ return JIM_ERR;
+ }
+ Jim_SetResult(interp, (Jim_Obj *)cmdPtr->u.native.privData);
+ return JIM_OK;
+ }
+
+ case INFO_CHANNELS:
+ mode++;
+#ifndef jim_ext_aio
+ Jim_SetResultString(interp, "aio not enabled", -1);
+ return JIM_ERR;
+#endif
+ case INFO_PROCS:
+ mode++;
+ case INFO_COMMANDS:
+
+ if (argc != 2 && argc != 3) {
+ Jim_WrongNumArgs(interp, 2, argv, "?pattern?");
+ return JIM_ERR;
+ }
+#ifdef jim_ext_namespace
+ if (!nons) {
+ if (Jim_Length(interp->framePtr->nsObj) || (argc == 3 && JimGlobMatch("::*", Jim_String(argv[2]), 0))) {
+ return Jim_EvalPrefix(interp, "namespace info", argc - 1, argv + 1);
+ }
+ }
+#endif
+ Jim_SetResult(interp, JimCommandsList(interp, (argc == 3) ? argv[2] : NULL, mode));
+ break;
+
+ case INFO_VARS:
+ mode++;
+ case INFO_LOCALS:
+ mode++;
+ case INFO_GLOBALS:
+
+ if (argc != 2 && argc != 3) {
+ Jim_WrongNumArgs(interp, 2, argv, "?pattern?");
+ return JIM_ERR;
+ }
+#ifdef jim_ext_namespace
+ if (!nons) {
+ if (Jim_Length(interp->framePtr->nsObj) || (argc == 3 && JimGlobMatch("::*", Jim_String(argv[2]), 0))) {
+ return Jim_EvalPrefix(interp, "namespace info", argc - 1, argv + 1);
+ }
+ }
+#endif
+ Jim_SetResult(interp, JimVariablesList(interp, argc == 3 ? argv[2] : NULL, mode));
+ break;
+
+ case INFO_SCRIPT:
+ if (argc != 2) {
+ Jim_WrongNumArgs(interp, 2, argv, "");
+ return JIM_ERR;
+ }
+ Jim_SetResult(interp, Jim_GetScript(interp, interp->currentScriptObj)->fileNameObj);
+ break;
+
+ case INFO_SOURCE:{
+ int line;
+ Jim_Obj *resObjPtr;
+ Jim_Obj *fileNameObj;
+
+ if (argc != 3) {
+ Jim_WrongNumArgs(interp, 2, argv, "source");
+ return JIM_ERR;
+ }
+ if (argv[2]->typePtr == &sourceObjType) {
+ fileNameObj = argv[2]->internalRep.sourceValue.fileNameObj;
+ line = argv[2]->internalRep.sourceValue.lineNumber;
+ }
+ else if (argv[2]->typePtr == &scriptObjType) {
+ ScriptObj *script = Jim_GetScript(interp, argv[2]);
+ fileNameObj = script->fileNameObj;
+ line = script->firstline;
+ }
+ else {
+ fileNameObj = interp->emptyObj;
+ line = 1;
+ }
+ resObjPtr = Jim_NewListObj(interp, NULL, 0);
+ Jim_ListAppendElement(interp, resObjPtr, fileNameObj);
+ Jim_ListAppendElement(interp, resObjPtr, Jim_NewIntObj(interp, line));
+ Jim_SetResult(interp, resObjPtr);
+ break;
+ }
+
+ case INFO_STACKTRACE:
+ Jim_SetResult(interp, interp->stackTrace);
+ break;
+
+ case INFO_LEVEL:
+ case INFO_FRAME:
+ switch (argc) {
+ case 2:
+ Jim_SetResultInt(interp, interp->framePtr->level);
+ break;
+
+ case 3:
+ if (JimInfoLevel(interp, argv[2], &objPtr, cmd == INFO_LEVEL) != JIM_OK) {
+ return JIM_ERR;
+ }
+ Jim_SetResult(interp, objPtr);
+ break;
+
+ default:
+ Jim_WrongNumArgs(interp, 2, argv, "?levelNum?");
+ return JIM_ERR;
+ }
+ break;
+
+ case INFO_BODY:
+ case INFO_STATICS:
+ case INFO_ARGS:{
+ Jim_Cmd *cmdPtr;
+
+ if (argc != 3) {
+ Jim_WrongNumArgs(interp, 2, argv, "procname");
+ return JIM_ERR;
+ }
+ if ((cmdPtr = Jim_GetCommand(interp, argv[2], JIM_ERRMSG)) == NULL) {
+ return JIM_ERR;
+ }
+ if (!cmdPtr->isproc) {
+ Jim_SetResultFormatted(interp, "command \"%#s\" is not a procedure", argv[2]);
+ return JIM_ERR;
+ }
+ switch (cmd) {
+ case INFO_BODY:
+ Jim_SetResult(interp, cmdPtr->u.proc.bodyObjPtr);
+ break;
+ case INFO_ARGS:
+ Jim_SetResult(interp, cmdPtr->u.proc.argListObjPtr);
+ break;
+ case INFO_STATICS:
+ if (cmdPtr->u.proc.staticVars) {
+ int mode = JIM_VARLIST_LOCALS | JIM_VARLIST_VALUES;
+ Jim_SetResult(interp, JimHashtablePatternMatch(interp, cmdPtr->u.proc.staticVars,
+ NULL, JimVariablesMatch, mode));
+ }
+ break;
+ }
+ break;
+ }
+
+ case INFO_VERSION:
+ case INFO_PATCHLEVEL:{
+ char buf[(JIM_INTEGER_SPACE * 2) + 1];
+
+ sprintf(buf, "%d.%d", JIM_VERSION / 100, JIM_VERSION % 100);
+ Jim_SetResultString(interp, buf, -1);
+ break;
+ }
+
+ case INFO_COMPLETE:
+ if (argc != 3 && argc != 4) {
+ Jim_WrongNumArgs(interp, 2, argv, "script ?missing?");
+ return JIM_ERR;
+ }
+ else {
+ int len;
+ const char *s = Jim_GetString(argv[2], &len);
+ char missing;
+
+ Jim_SetResultBool(interp, Jim_ScriptIsComplete(s, len, &missing));
+ if (missing != ' ' && argc == 4) {
+ Jim_SetVariable(interp, argv[3], Jim_NewStringObj(interp, &missing, 1));
+ }
+ }
+ break;
+
+ case INFO_HOSTNAME:
+
+ return Jim_Eval(interp, "os.gethostname");
+
+ case INFO_NAMEOFEXECUTABLE:
+
+ return Jim_Eval(interp, "{info nameofexecutable}");
+
+ case INFO_RETURNCODES:
+ if (argc == 2) {
+ int i;
+ Jim_Obj *listObjPtr = Jim_NewListObj(interp, NULL, 0);
+
+ for (i = 0; jimReturnCodes[i]; i++) {
+ Jim_ListAppendElement(interp, listObjPtr, Jim_NewIntObj(interp, i));
+ Jim_ListAppendElement(interp, listObjPtr, Jim_NewStringObj(interp,
+ jimReturnCodes[i], -1));
+ }
+
+ Jim_SetResult(interp, listObjPtr);
+ }
+ else if (argc == 3) {
+ long code;
+ const char *name;
+
+ if (Jim_GetLong(interp, argv[2], &code) != JIM_OK) {
+ return JIM_ERR;
+ }
+ name = Jim_ReturnCode(code);
+ if (*name == '?') {
+ Jim_SetResultInt(interp, code);
+ }
+ else {
+ Jim_SetResultString(interp, name, -1);
+ }
+ }
+ else {
+ Jim_WrongNumArgs(interp, 2, argv, "?code?");
+ return JIM_ERR;
+ }
+ break;
+ case INFO_REFERENCES:
+#ifdef JIM_REFERENCES
+ return JimInfoReferences(interp, argc, argv);
+#else
+ Jim_SetResultString(interp, "not supported", -1);
+ return JIM_ERR;
+#endif
+ }
+ return JIM_OK;
+}
+
+
+static int Jim_ExistsCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ Jim_Obj *objPtr;
+ int result = 0;
+
+ static const char * const options[] = {
+ "-command", "-proc", "-alias", "-var", NULL
+ };
+ enum
+ {
+ OPT_COMMAND, OPT_PROC, OPT_ALIAS, OPT_VAR
+ };
+ int option;
+
+ if (argc == 2) {
+ option = OPT_VAR;
+ objPtr = argv[1];
+ }
+ else if (argc == 3) {
+ if (Jim_GetEnum(interp, argv[1], options, &option, NULL, JIM_ERRMSG | JIM_ENUM_ABBREV) != JIM_OK) {
+ return JIM_ERR;
+ }
+ objPtr = argv[2];
+ }
+ else {
+ Jim_WrongNumArgs(interp, 1, argv, "?option? name");
+ return JIM_ERR;
+ }
+
+ if (option == OPT_VAR) {
+ result = Jim_GetVariable(interp, objPtr, 0) != NULL;
+ }
+ else {
+
+ Jim_Cmd *cmd = Jim_GetCommand(interp, objPtr, JIM_NONE);
+
+ if (cmd) {
+ switch (option) {
+ case OPT_COMMAND:
+ result = 1;
+ break;
+
+ case OPT_ALIAS:
+ result = cmd->isproc == 0 && cmd->u.native.cmdProc == JimAliasCmd;
+ break;
+
+ case OPT_PROC:
+ result = cmd->isproc;
+ break;
+ }
+ }
+ }
+ Jim_SetResultBool(interp, result);
+ return JIM_OK;
+}
+
+
+static int Jim_SplitCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ const char *str, *splitChars, *noMatchStart;
+ int splitLen, strLen;
+ Jim_Obj *resObjPtr;
+ int c;
+ int len;
+
+ if (argc != 2 && argc != 3) {
+ Jim_WrongNumArgs(interp, 1, argv, "string ?splitChars?");
+ return JIM_ERR;
+ }
+
+ str = Jim_GetString(argv[1], &len);
+ if (len == 0) {
+ return JIM_OK;
+ }
+ strLen = Jim_Utf8Length(interp, argv[1]);
+
+
+ if (argc == 2) {
+ splitChars = " \n\t\r";
+ splitLen = 4;
+ }
+ else {
+ splitChars = Jim_String(argv[2]);
+ splitLen = Jim_Utf8Length(interp, argv[2]);
+ }
+
+ noMatchStart = str;
+ resObjPtr = Jim_NewListObj(interp, NULL, 0);
+
+
+ if (splitLen) {
+ Jim_Obj *objPtr;
+ while (strLen--) {
+ const char *sc = splitChars;
+ int scLen = splitLen;
+ int sl = utf8_tounicode(str, &c);
+ while (scLen--) {
+ int pc;
+ sc += utf8_tounicode(sc, &pc);
+ if (c == pc) {
+ objPtr = Jim_NewStringObj(interp, noMatchStart, (str - noMatchStart));
+ Jim_ListAppendElement(interp, resObjPtr, objPtr);
+ noMatchStart = str + sl;
+ break;
+ }
+ }
+ str += sl;
+ }
+ objPtr = Jim_NewStringObj(interp, noMatchStart, (str - noMatchStart));
+ Jim_ListAppendElement(interp, resObjPtr, objPtr);
+ }
+ else {
+ Jim_Obj **commonObj = NULL;
+#define NUM_COMMON (128 - 9)
+ while (strLen--) {
+ int n = utf8_tounicode(str, &c);
+#ifdef JIM_OPTIMIZATION
+ if (c >= 9 && c < 128) {
+
+ c -= 9;
+ if (!commonObj) {
+ commonObj = Jim_Alloc(sizeof(*commonObj) * NUM_COMMON);
+ memset(commonObj, 0, sizeof(*commonObj) * NUM_COMMON);
+ }
+ if (!commonObj[c]) {
+ commonObj[c] = Jim_NewStringObj(interp, str, 1);
+ }
+ Jim_ListAppendElement(interp, resObjPtr, commonObj[c]);
+ str++;
+ continue;
+ }
+#endif
+ Jim_ListAppendElement(interp, resObjPtr, Jim_NewStringObjUtf8(interp, str, 1));
+ str += n;
+ }
+ Jim_Free(commonObj);
+ }
+
+ Jim_SetResult(interp, resObjPtr);
+ return JIM_OK;
+}
+
+
+static int Jim_JoinCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ const char *joinStr;
+ int joinStrLen;
+
+ if (argc != 2 && argc != 3) {
+ Jim_WrongNumArgs(interp, 1, argv, "list ?joinString?");
+ return JIM_ERR;
+ }
+
+ if (argc == 2) {
+ joinStr = " ";
+ joinStrLen = 1;
+ }
+ else {
+ joinStr = Jim_GetString(argv[2], &joinStrLen);
+ }
+ Jim_SetResult(interp, Jim_ListJoin(interp, argv[1], joinStr, joinStrLen));
+ return JIM_OK;
+}
+
+
+static int Jim_FormatCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ Jim_Obj *objPtr;
+
+ if (argc < 2) {
+ Jim_WrongNumArgs(interp, 1, argv, "formatString ?arg arg ...?");
+ return JIM_ERR;
+ }
+ objPtr = Jim_FormatString(interp, argv[1], argc - 2, argv + 2);
+ if (objPtr == NULL)
+ return JIM_ERR;
+ Jim_SetResult(interp, objPtr);
+ return JIM_OK;
+}
+
+
+static int Jim_ScanCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ Jim_Obj *listPtr, **outVec;
+ int outc, i;
+
+ if (argc < 3) {
+ Jim_WrongNumArgs(interp, 1, argv, "string format ?varName varName ...?");
+ return JIM_ERR;
+ }
+ if (argv[2]->typePtr != &scanFmtStringObjType)
+ SetScanFmtFromAny(interp, argv[2]);
+ if (FormatGetError(argv[2]) != 0) {
+ Jim_SetResultString(interp, FormatGetError(argv[2]), -1);
+ return JIM_ERR;
+ }
+ if (argc > 3) {
+ int maxPos = FormatGetMaxPos(argv[2]);
+ int count = FormatGetCnvCount(argv[2]);
+
+ if (maxPos > argc - 3) {
+ Jim_SetResultString(interp, "\"%n$\" argument index out of range", -1);
+ return JIM_ERR;
+ }
+ else if (count > argc - 3) {
+ Jim_SetResultString(interp, "different numbers of variable names and "
+ "field specifiers", -1);
+ return JIM_ERR;
+ }
+ else if (count < argc - 3) {
+ Jim_SetResultString(interp, "variable is not assigned by any "
+ "conversion specifiers", -1);
+ return JIM_ERR;
+ }
+ }
+ listPtr = Jim_ScanString(interp, argv[1], argv[2], JIM_ERRMSG);
+ if (listPtr == 0)
+ return JIM_ERR;
+ if (argc > 3) {
+ int rc = JIM_OK;
+ int count = 0;
+
+ if (listPtr != 0 && listPtr != (Jim_Obj *)EOF) {
+ int len = Jim_ListLength(interp, listPtr);
+
+ if (len != 0) {
+ JimListGetElements(interp, listPtr, &outc, &outVec);
+ for (i = 0; i < outc; ++i) {
+ if (Jim_Length(outVec[i]) > 0) {
+ ++count;
+ if (Jim_SetVariable(interp, argv[3 + i], outVec[i]) != JIM_OK) {
+ rc = JIM_ERR;
+ }
+ }
+ }
+ }
+ Jim_FreeNewObj(interp, listPtr);
+ }
+ else {
+ count = -1;
+ }
+ if (rc == JIM_OK) {
+ Jim_SetResultInt(interp, count);
+ }
+ return rc;
+ }
+ else {
+ if (listPtr == (Jim_Obj *)EOF) {
+ Jim_SetResult(interp, Jim_NewListObj(interp, 0, 0));
+ return JIM_OK;
+ }
+ Jim_SetResult(interp, listPtr);
+ }
+ return JIM_OK;
+}
+
+
+static int Jim_ErrorCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ if (argc != 2 && argc != 3) {
+ Jim_WrongNumArgs(interp, 1, argv, "message ?stacktrace?");
+ return JIM_ERR;
+ }
+ Jim_SetResult(interp, argv[1]);
+ if (argc == 3) {
+ JimSetStackTrace(interp, argv[2]);
+ return JIM_ERR;
+ }
+ interp->addStackTrace++;
+ return JIM_ERR;
+}
+
+
+static int Jim_LrangeCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ Jim_Obj *objPtr;
+
+ if (argc != 4) {
+ Jim_WrongNumArgs(interp, 1, argv, "list first last");
+ return JIM_ERR;
+ }
+ if ((objPtr = Jim_ListRange(interp, argv[1], argv[2], argv[3])) == NULL)
+ return JIM_ERR;
+ Jim_SetResult(interp, objPtr);
+ return JIM_OK;
+}
+
+
+static int Jim_LrepeatCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ Jim_Obj *objPtr;
+ long count;
+
+ if (argc < 2 || Jim_GetLong(interp, argv[1], &count) != JIM_OK || count < 0) {
+ Jim_WrongNumArgs(interp, 1, argv, "count ?value ...?");
+ return JIM_ERR;
+ }
+
+ if (count == 0 || argc == 2) {
+ return JIM_OK;
+ }
+
+ argc -= 2;
+ argv += 2;
+
+ objPtr = Jim_NewListObj(interp, argv, argc);
+ while (--count) {
+ ListInsertElements(objPtr, -1, argc, argv);
+ }
+
+ Jim_SetResult(interp, objPtr);
+ return JIM_OK;
+}
+
+char **Jim_GetEnviron(void)
+{
+#if defined(HAVE__NSGETENVIRON)
+ return *_NSGetEnviron();
+#else
+ #if !defined(NO_ENVIRON_EXTERN)
+ extern char **environ;
+ #endif
+
+ return environ;
+#endif
+}
+
+void Jim_SetEnviron(char **env)
+{
+#if defined(HAVE__NSGETENVIRON)
+ *_NSGetEnviron() = env;
+#else
+ #if !defined(NO_ENVIRON_EXTERN)
+ extern char **environ;
+ #endif
+
+ environ = env;
+#endif
+}
+
+
+static int Jim_EnvCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ const char *key;
+ const char *val;
+
+ if (argc == 1) {
+ char **e = Jim_GetEnviron();
+
+ int i;
+ Jim_Obj *listObjPtr = Jim_NewListObj(interp, NULL, 0);
+
+ for (i = 0; e[i]; i++) {
+ const char *equals = strchr(e[i], '=');
+
+ if (equals) {
+ Jim_ListAppendElement(interp, listObjPtr, Jim_NewStringObj(interp, e[i],
+ equals - e[i]));
+ Jim_ListAppendElement(interp, listObjPtr, Jim_NewStringObj(interp, equals + 1, -1));
+ }
+ }
+
+ Jim_SetResult(interp, listObjPtr);
+ return JIM_OK;
+ }
+
+ if (argc < 2) {
+ Jim_WrongNumArgs(interp, 1, argv, "varName ?default?");
+ return JIM_ERR;
+ }
+ key = Jim_String(argv[1]);
+ val = getenv(key);
+ if (val == NULL) {
+ if (argc < 3) {
+ Jim_SetResultFormatted(interp, "environment variable \"%#s\" does not exist", argv[1]);
+ return JIM_ERR;
+ }
+ val = Jim_String(argv[2]);
+ }
+ Jim_SetResult(interp, Jim_NewStringObj(interp, val, -1));
+ return JIM_OK;
+}
+
+
+static int Jim_SourceCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ int retval;
+
+ if (argc != 2) {
+ Jim_WrongNumArgs(interp, 1, argv, "fileName");
+ return JIM_ERR;
+ }
+ retval = Jim_EvalFile(interp, Jim_String(argv[1]));
+ if (retval == JIM_RETURN)
+ return JIM_OK;
+ return retval;
+}
+
+
+static int Jim_LreverseCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ Jim_Obj *revObjPtr, **ele;
+ int len;
+
+ if (argc != 2) {
+ Jim_WrongNumArgs(interp, 1, argv, "list");
+ return JIM_ERR;
+ }
+ JimListGetElements(interp, argv[1], &len, &ele);
+ len--;
+ revObjPtr = Jim_NewListObj(interp, NULL, 0);
+ while (len >= 0)
+ ListAppendElement(revObjPtr, ele[len--]);
+ Jim_SetResult(interp, revObjPtr);
+ return JIM_OK;
+}
+
+static int JimRangeLen(jim_wide start, jim_wide end, jim_wide step)
+{
+ jim_wide len;
+
+ if (step == 0)
+ return -1;
+ if (start == end)
+ return 0;
+ else if (step > 0 && start > end)
+ return -1;
+ else if (step < 0 && end > start)
+ return -1;
+ len = end - start;
+ if (len < 0)
+ len = -len;
+ if (step < 0)
+ step = -step;
+ len = 1 + ((len - 1) / step);
+ if (len > INT_MAX)
+ len = INT_MAX;
+ return (int)((len < 0) ? -1 : len);
+}
+
+
+static int Jim_RangeCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ jim_wide start = 0, end, step = 1;
+ int len, i;
+ Jim_Obj *objPtr;
+
+ if (argc < 2 || argc > 4) {
+ Jim_WrongNumArgs(interp, 1, argv, "?start? end ?step?");
+ return JIM_ERR;
+ }
+ if (argc == 2) {
+ if (Jim_GetWide(interp, argv[1], &end) != JIM_OK)
+ return JIM_ERR;
+ }
+ else {
+ if (Jim_GetWide(interp, argv[1], &start) != JIM_OK ||
+ Jim_GetWide(interp, argv[2], &end) != JIM_OK)
+ return JIM_ERR;
+ if (argc == 4 && Jim_GetWide(interp, argv[3], &step) != JIM_OK)
+ return JIM_ERR;
+ }
+ if ((len = JimRangeLen(start, end, step)) == -1) {
+ Jim_SetResultString(interp, "Invalid (infinite?) range specified", -1);
+ return JIM_ERR;
+ }
+ objPtr = Jim_NewListObj(interp, NULL, 0);
+ for (i = 0; i < len; i++)
+ ListAppendElement(objPtr, Jim_NewIntObj(interp, start + i * step));
+ Jim_SetResult(interp, objPtr);
+ return JIM_OK;
+}
+
+
+static int Jim_RandCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ jim_wide min = 0, max = 0, len, maxMul;
+
+ if (argc < 1 || argc > 3) {
+ Jim_WrongNumArgs(interp, 1, argv, "?min? max");
+ return JIM_ERR;
+ }
+ if (argc == 1) {
+ max = JIM_WIDE_MAX;
+ } else if (argc == 2) {
+ if (Jim_GetWide(interp, argv[1], &max) != JIM_OK)
+ return JIM_ERR;
+ } else if (argc == 3) {
+ if (Jim_GetWide(interp, argv[1], &min) != JIM_OK ||
+ Jim_GetWide(interp, argv[2], &max) != JIM_OK)
+ return JIM_ERR;
+ }
+ len = max-min;
+ if (len < 0) {
+ Jim_SetResultString(interp, "Invalid arguments (max < min)", -1);
+ return JIM_ERR;
+ }
+ maxMul = JIM_WIDE_MAX - (len ? (JIM_WIDE_MAX%len) : 0);
+ while (1) {
+ jim_wide r;
+
+ JimRandomBytes(interp, &r, sizeof(jim_wide));
+ if (r < 0 || r >= maxMul) continue;
+ r = (len == 0) ? 0 : r%len;
+ Jim_SetResultInt(interp, min+r);
+ return JIM_OK;
+ }
+}
+
+static const struct {
+ const char *name;
+ Jim_CmdProc cmdProc;
+} Jim_CoreCommandsTable[] = {
+ {"alias", Jim_AliasCoreCommand},
+ {"set", Jim_SetCoreCommand},
+ {"unset", Jim_UnsetCoreCommand},
+ {"puts", Jim_PutsCoreCommand},
+ {"+", Jim_AddCoreCommand},
+ {"*", Jim_MulCoreCommand},
+ {"-", Jim_SubCoreCommand},
+ {"/", Jim_DivCoreCommand},
+ {"incr", Jim_IncrCoreCommand},
+ {"while", Jim_WhileCoreCommand},
+ {"loop", Jim_LoopCoreCommand},
+ {"for", Jim_ForCoreCommand},
+ {"foreach", Jim_ForeachCoreCommand},
+ {"lmap", Jim_LmapCoreCommand},
+ {"lassign", Jim_LassignCoreCommand},
+ {"if", Jim_IfCoreCommand},
+ {"switch", Jim_SwitchCoreCommand},
+ {"list", Jim_ListCoreCommand},
+ {"lindex", Jim_LindexCoreCommand},
+ {"lset", Jim_LsetCoreCommand},
+ {"lsearch", Jim_LsearchCoreCommand},
+ {"llength", Jim_LlengthCoreCommand},
+ {"lappend", Jim_LappendCoreCommand},
+ {"linsert", Jim_LinsertCoreCommand},
+ {"lreplace", Jim_LreplaceCoreCommand},
+ {"lsort", Jim_LsortCoreCommand},
+ {"append", Jim_AppendCoreCommand},
+ {"debug", Jim_DebugCoreCommand},
+ {"eval", Jim_EvalCoreCommand},
+ {"uplevel", Jim_UplevelCoreCommand},
+ {"expr", Jim_ExprCoreCommand},
+ {"break", Jim_BreakCoreCommand},
+ {"continue", Jim_ContinueCoreCommand},
+ {"proc", Jim_ProcCoreCommand},
+ {"concat", Jim_ConcatCoreCommand},
+ {"return", Jim_ReturnCoreCommand},
+ {"upvar", Jim_UpvarCoreCommand},
+ {"global", Jim_GlobalCoreCommand},
+ {"string", Jim_StringCoreCommand},
+ {"time", Jim_TimeCoreCommand},
+ {"exit", Jim_ExitCoreCommand},
+ {"catch", Jim_CatchCoreCommand},
+#ifdef JIM_REFERENCES
+ {"ref", Jim_RefCoreCommand},
+ {"getref", Jim_GetrefCoreCommand},
+ {"setref", Jim_SetrefCoreCommand},
+ {"finalize", Jim_FinalizeCoreCommand},
+ {"collect", Jim_CollectCoreCommand},
+#endif
+ {"rename", Jim_RenameCoreCommand},
+ {"dict", Jim_DictCoreCommand},
+ {"subst", Jim_SubstCoreCommand},
+ {"info", Jim_InfoCoreCommand},
+ {"exists", Jim_ExistsCoreCommand},
+ {"split", Jim_SplitCoreCommand},
+ {"join", Jim_JoinCoreCommand},
+ {"format", Jim_FormatCoreCommand},
+ {"scan", Jim_ScanCoreCommand},
+ {"error", Jim_ErrorCoreCommand},
+ {"lrange", Jim_LrangeCoreCommand},
+ {"lrepeat", Jim_LrepeatCoreCommand},
+ {"env", Jim_EnvCoreCommand},
+ {"source", Jim_SourceCoreCommand},
+ {"lreverse", Jim_LreverseCoreCommand},
+ {"range", Jim_RangeCoreCommand},
+ {"rand", Jim_RandCoreCommand},
+ {"tailcall", Jim_TailcallCoreCommand},
+ {"local", Jim_LocalCoreCommand},
+ {"upcall", Jim_UpcallCoreCommand},
+ {"apply", Jim_ApplyCoreCommand},
+ {NULL, NULL},
+};
+
+void Jim_RegisterCoreCommands(Jim_Interp *interp)
+{
+ int i = 0;
+
+ while (Jim_CoreCommandsTable[i].name != NULL) {
+ Jim_CreateCommand(interp,
+ Jim_CoreCommandsTable[i].name, Jim_CoreCommandsTable[i].cmdProc, NULL, NULL);
+ i++;
+ }
+}
+
+void Jim_MakeErrorMessage(Jim_Interp *interp)
+{
+ Jim_Obj *argv[2];
+
+ argv[0] = Jim_NewStringObj(interp, "errorInfo", -1);
+ argv[1] = interp->result;
+
+ Jim_EvalObjVector(interp, 2, argv);
+}
+
+static void JimSetFailedEnumResult(Jim_Interp *interp, const char *arg, const char *badtype,
+ const char *prefix, const char *const *tablePtr, const char *name)
+{
+ int count;
+ char **tablePtrSorted;
+ int i;
+
+ for (count = 0; tablePtr[count]; count++) {
+ }
+
+ if (name == NULL) {
+ name = "option";
+ }
+
+ Jim_SetResultFormatted(interp, "%s%s \"%s\": must be ", badtype, name, arg);
+ tablePtrSorted = Jim_Alloc(sizeof(char *) * count);
+ memcpy(tablePtrSorted, tablePtr, sizeof(char *) * count);
+ qsort(tablePtrSorted, count, sizeof(char *), qsortCompareStringPointers);
+ for (i = 0; i < count; i++) {
+ if (i + 1 == count && count > 1) {
+ Jim_AppendString(interp, Jim_GetResult(interp), "or ", -1);
+ }
+ Jim_AppendStrings(interp, Jim_GetResult(interp), prefix, tablePtrSorted[i], NULL);
+ if (i + 1 != count) {
+ Jim_AppendString(interp, Jim_GetResult(interp), ", ", -1);
+ }
+ }
+ Jim_Free(tablePtrSorted);
+}
+
+int Jim_GetEnum(Jim_Interp *interp, Jim_Obj *objPtr,
+ const char *const *tablePtr, int *indexPtr, const char *name, int flags)
+{
+ const char *bad = "bad ";
+ const char *const *entryPtr = NULL;
+ int i;
+ int match = -1;
+ int arglen;
+ const char *arg = Jim_GetString(objPtr, &arglen);
+
+ *indexPtr = -1;
+
+ for (entryPtr = tablePtr, i = 0; *entryPtr != NULL; entryPtr++, i++) {
+ if (Jim_CompareStringImmediate(interp, objPtr, *entryPtr)) {
+
+ *indexPtr = i;
+ return JIM_OK;
+ }
+ if (flags & JIM_ENUM_ABBREV) {
+ if (strncmp(arg, *entryPtr, arglen) == 0) {
+ if (*arg == '-' && arglen == 1) {
+ break;
+ }
+ if (match >= 0) {
+ bad = "ambiguous ";
+ goto ambiguous;
+ }
+ match = i;
+ }
+ }
+ }
+
+
+ if (match >= 0) {
+ *indexPtr = match;
+ return JIM_OK;
+ }
+
+ ambiguous:
+ if (flags & JIM_ERRMSG) {
+ JimSetFailedEnumResult(interp, arg, bad, "", tablePtr, name);
+ }
+ return JIM_ERR;
+}
+
+int Jim_FindByName(const char *name, const char * const array[], size_t len)
+{
+ int i;
+
+ for (i = 0; i < (int)len; i++) {
+ if (array[i] && strcmp(array[i], name) == 0) {
+ return i;
+ }
+ }
+ return -1;
+}
+
+int Jim_IsDict(Jim_Obj *objPtr)
+{
+ return objPtr->typePtr == &dictObjType;
+}
+
+int Jim_IsList(Jim_Obj *objPtr)
+{
+ return objPtr->typePtr == &listObjType;
+}
+
+void Jim_SetResultFormatted(Jim_Interp *interp, const char *format, ...)
+{
+
+ int len = strlen(format);
+ int extra = 0;
+ int n = 0;
+ const char *params[5];
+ char *buf;
+ va_list args;
+ int i;
+
+ va_start(args, format);
+
+ for (i = 0; i < len && n < 5; i++) {
+ int l;
+
+ if (strncmp(format + i, "%s", 2) == 0) {
+ params[n] = va_arg(args, char *);
+
+ l = strlen(params[n]);
+ }
+ else if (strncmp(format + i, "%#s", 3) == 0) {
+ Jim_Obj *objPtr = va_arg(args, Jim_Obj *);
+
+ params[n] = Jim_GetString(objPtr, &l);
+ }
+ else {
+ if (format[i] == '%') {
+ i++;
+ }
+ continue;
+ }
+ n++;
+ extra += l;
+ }
+
+ len += extra;
+ buf = Jim_Alloc(len + 1);
+ len = snprintf(buf, len + 1, format, params[0], params[1], params[2], params[3], params[4]);
+
+ Jim_SetResult(interp, Jim_NewStringObjNoAlloc(interp, buf, len));
+}
+
+
+#ifndef jim_ext_package
+int Jim_PackageProvide(Jim_Interp *interp, const char *name, const char *ver, int flags)
+{
+ return JIM_OK;
+}
+#endif
+#ifndef jim_ext_aio
+FILE *Jim_AioFilehandle(Jim_Interp *interp, Jim_Obj *fhObj)
+{
+ Jim_SetResultString(interp, "aio not enabled", -1);
+ return NULL;
+}
+#endif
+
+
+#include
+#include
+
+
+static int subcmd_null(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+
+ return JIM_OK;
+}
+
+static const jim_subcmd_type dummy_subcmd = {
+ "dummy", NULL, subcmd_null, 0, 0, JIM_MODFLAG_HIDDEN
+};
+
+static void add_commands(Jim_Interp *interp, const jim_subcmd_type * ct, const char *sep)
+{
+ const char *s = "";
+
+ for (; ct->cmd; ct++) {
+ if (!(ct->flags & JIM_MODFLAG_HIDDEN)) {
+ Jim_AppendStrings(interp, Jim_GetResult(interp), s, ct->cmd, NULL);
+ s = sep;
+ }
+ }
+}
+
+static void bad_subcmd(Jim_Interp *interp, const jim_subcmd_type * command_table, const char *type,
+ Jim_Obj *cmd, Jim_Obj *subcmd)
+{
+ Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
+ Jim_AppendStrings(interp, Jim_GetResult(interp), Jim_String(cmd), ", ", type,
+ " command \"", Jim_String(subcmd), "\": should be ", NULL);
+ add_commands(interp, command_table, ", ");
+}
+
+static void show_cmd_usage(Jim_Interp *interp, const jim_subcmd_type * command_table, int argc,
+ Jim_Obj *const *argv)
+{
+ Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
+ Jim_AppendStrings(interp, Jim_GetResult(interp), "Usage: \"", Jim_String(argv[0]),
+ " command ... \", where command is one of: ", NULL);
+ add_commands(interp, command_table, ", ");
+}
+
+static void add_cmd_usage(Jim_Interp *interp, const jim_subcmd_type * ct, Jim_Obj *cmd)
+{
+ if (cmd) {
+ Jim_AppendStrings(interp, Jim_GetResult(interp), Jim_String(cmd), " ", NULL);
+ }
+ Jim_AppendStrings(interp, Jim_GetResult(interp), ct->cmd, NULL);
+ if (ct->args && *ct->args) {
+ Jim_AppendStrings(interp, Jim_GetResult(interp), " ", ct->args, NULL);
+ }
+}
+
+static void set_wrong_args(Jim_Interp *interp, const jim_subcmd_type * command_table, Jim_Obj *subcmd)
+{
+ Jim_SetResultString(interp, "wrong # args: should be \"", -1);
+ add_cmd_usage(interp, command_table, subcmd);
+ Jim_AppendStrings(interp, Jim_GetResult(interp), "\"", NULL);
+}
+
+const jim_subcmd_type *Jim_ParseSubCmd(Jim_Interp *interp, const jim_subcmd_type * command_table,
+ int argc, Jim_Obj *const *argv)
+{
+ const jim_subcmd_type *ct;
+ const jim_subcmd_type *partial = 0;
+ int cmdlen;
+ Jim_Obj *cmd;
+ const char *cmdstr;
+ const char *cmdname;
+ int help = 0;
+
+ cmdname = Jim_String(argv[0]);
+
+ if (argc < 2) {
+ Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
+ Jim_AppendStrings(interp, Jim_GetResult(interp), "wrong # args: should be \"", cmdname,
+ " command ...\"\n", NULL);
+ Jim_AppendStrings(interp, Jim_GetResult(interp), "Use \"", cmdname, " -help ?command?\" for help", NULL);
+ return 0;
+ }
+
+ cmd = argv[1];
+
+
+ if (Jim_CompareStringImmediate(interp, cmd, "-help")) {
+ if (argc == 2) {
+
+ show_cmd_usage(interp, command_table, argc, argv);
+ return &dummy_subcmd;
+ }
+ help = 1;
+
+
+ cmd = argv[2];
+ }
+
+
+ if (Jim_CompareStringImmediate(interp, cmd, "-commands")) {
+
+ Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
+ add_commands(interp, command_table, " ");
+ return &dummy_subcmd;
+ }
+
+ cmdstr = Jim_GetString(cmd, &cmdlen);
+
+ for (ct = command_table; ct->cmd; ct++) {
+ if (Jim_CompareStringImmediate(interp, cmd, ct->cmd)) {
+
+ break;
+ }
+ if (strncmp(cmdstr, ct->cmd, cmdlen) == 0) {
+ if (partial) {
+
+ if (help) {
+
+ show_cmd_usage(interp, command_table, argc, argv);
+ return &dummy_subcmd;
+ }
+ bad_subcmd(interp, command_table, "ambiguous", argv[0], argv[1 + help]);
+ return 0;
+ }
+ partial = ct;
+ }
+ continue;
+ }
+
+
+ if (partial && !ct->cmd) {
+ ct = partial;
+ }
+
+ if (!ct->cmd) {
+
+ if (help) {
+
+ show_cmd_usage(interp, command_table, argc, argv);
+ return &dummy_subcmd;
+ }
+ bad_subcmd(interp, command_table, "unknown", argv[0], argv[1 + help]);
+ return 0;
+ }
+
+ if (help) {
+ Jim_SetResultString(interp, "Usage: ", -1);
+
+ add_cmd_usage(interp, ct, argv[0]);
+ return &dummy_subcmd;
+ }
+
+
+ if (argc - 2 < ct->minargs || (ct->maxargs >= 0 && argc - 2 > ct->maxargs)) {
+ Jim_SetResultString(interp, "wrong # args: should be \"", -1);
+
+ add_cmd_usage(interp, ct, argv[0]);
+ Jim_AppendStrings(interp, Jim_GetResult(interp), "\"", NULL);
+
+ return 0;
+ }
+
+
+ return ct;
+}
+
+int Jim_CallSubCmd(Jim_Interp *interp, const jim_subcmd_type * ct, int argc, Jim_Obj *const *argv)
+{
+ int ret = JIM_ERR;
+
+ if (ct) {
+ if (ct->flags & JIM_MODFLAG_FULLARGV) {
+ ret = ct->function(interp, argc, argv);
+ }
+ else {
+ ret = ct->function(interp, argc - 2, argv + 2);
+ }
+ if (ret < 0) {
+ set_wrong_args(interp, ct, argv[0]);
+ ret = JIM_ERR;
+ }
+ }
+ return ret;
+}
+
+int Jim_SubCmdProc(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ const jim_subcmd_type *ct =
+ Jim_ParseSubCmd(interp, (const jim_subcmd_type *)Jim_CmdPrivData(interp), argc, argv);
+
+ return Jim_CallSubCmd(interp, ct, argc, argv);
+}
+
+#include
+#include
+#include
+#include
+#include
+
+
+int utf8_fromunicode(char *p, unsigned uc)
+{
+ if (uc <= 0x7f) {
+ *p = uc;
+ return 1;
+ }
+ else if (uc <= 0x7ff) {
+ *p++ = 0xc0 | ((uc & 0x7c0) >> 6);
+ *p = 0x80 | (uc & 0x3f);
+ return 2;
+ }
+ else if (uc <= 0xffff) {
+ *p++ = 0xe0 | ((uc & 0xf000) >> 12);
+ *p++ = 0x80 | ((uc & 0xfc0) >> 6);
+ *p = 0x80 | (uc & 0x3f);
+ return 3;
+ }
+
+ else {
+ *p++ = 0xf0 | ((uc & 0x1c0000) >> 18);
+ *p++ = 0x80 | ((uc & 0x3f000) >> 12);
+ *p++ = 0x80 | ((uc & 0xfc0) >> 6);
+ *p = 0x80 | (uc & 0x3f);
+ return 4;
+ }
+}
+
+#include
+#include
+
+
+#define JIM_UTF_MAX 3
+#define JIM_INTEGER_SPACE 24
+#define MAX_FLOAT_WIDTH 320
+
+Jim_Obj *Jim_FormatString(Jim_Interp *interp, Jim_Obj *fmtObjPtr, int objc, Jim_Obj *const *objv)
+{
+ const char *span, *format, *formatEnd, *msg;
+ int numBytes = 0, objIndex = 0, gotXpg = 0, gotSequential = 0;
+ static const char * const mixedXPG =
+ "cannot mix \"%\" and \"%n$\" conversion specifiers";
+ static const char * const badIndex[2] = {
+ "not enough arguments for all format specifiers",
+ "\"%n$\" argument index out of range"
+ };
+ int formatLen;
+ Jim_Obj *resultPtr;
+
+ char *num_buffer = NULL;
+ int num_buffer_size = 0;
+
+ span = format = Jim_GetString(fmtObjPtr, &formatLen);
+ formatEnd = format + formatLen;
+ resultPtr = Jim_NewStringObj(interp, "", 0);
+
+ while (format != formatEnd) {
+ char *end;
+ int gotMinus, sawFlag;
+ int gotPrecision, useShort;
+ long width, precision;
+ int newXpg;
+ int ch;
+ int step;
+ int doubleType;
+ char pad = ' ';
+ char spec[2*JIM_INTEGER_SPACE + 12];
+ char *p;
+
+ int formatted_chars;
+ int formatted_bytes;
+ const char *formatted_buf;
+
+ step = utf8_tounicode(format, &ch);
+ format += step;
+ if (ch != '%') {
+ numBytes += step;
+ continue;
+ }
+ if (numBytes) {
+ Jim_AppendString(interp, resultPtr, span, numBytes);
+ numBytes = 0;
+ }
+
+
+ step = utf8_tounicode(format, &ch);
+ if (ch == '%') {
+ span = format;
+ numBytes = step;
+ format += step;
+ continue;
+ }
+
+
+ newXpg = 0;
+ if (isdigit(ch)) {
+ int position = strtoul(format, &end, 10);
+ if (*end == '$') {
+ newXpg = 1;
+ objIndex = position - 1;
+ format = end + 1;
+ step = utf8_tounicode(format, &ch);
+ }
+ }
+ if (newXpg) {
+ if (gotSequential) {
+ msg = mixedXPG;
+ goto errorMsg;
+ }
+ gotXpg = 1;
+ } else {
+ if (gotXpg) {
+ msg = mixedXPG;
+ goto errorMsg;
+ }
+ gotSequential = 1;
+ }
+ if ((objIndex < 0) || (objIndex >= objc)) {
+ msg = badIndex[gotXpg];
+ goto errorMsg;
+ }
+
+ p = spec;
+ *p++ = '%';
+
+ gotMinus = 0;
+ sawFlag = 1;
+ do {
+ switch (ch) {
+ case '-':
+ gotMinus = 1;
+ break;
+ case '0':
+ pad = ch;
+ break;
+ case ' ':
+ case '+':
+ case '#':
+ break;
+ default:
+ sawFlag = 0;
+ continue;
+ }
+ *p++ = ch;
+ format += step;
+ step = utf8_tounicode(format, &ch);
+ } while (sawFlag);
+
+
+ width = 0;
+ if (isdigit(ch)) {
+ width = strtoul(format, &end, 10);
+ format = end;
+ step = utf8_tounicode(format, &ch);
+ } else if (ch == '*') {
+ if (objIndex >= objc - 1) {
+ msg = badIndex[gotXpg];
+ goto errorMsg;
+ }
+ if (Jim_GetLong(interp, objv[objIndex], &width) != JIM_OK) {
+ goto error;
+ }
+ if (width < 0) {
+ width = -width;
+ if (!gotMinus) {
+ *p++ = '-';
+ gotMinus = 1;
+ }
+ }
+ objIndex++;
+ format += step;
+ step = utf8_tounicode(format, &ch);
+ }
+
+
+ gotPrecision = precision = 0;
+ if (ch == '.') {
+ gotPrecision = 1;
+ format += step;
+ step = utf8_tounicode(format, &ch);
+ }
+ if (isdigit(ch)) {
+ precision = strtoul(format, &end, 10);
+ format = end;
+ step = utf8_tounicode(format, &ch);
+ } else if (ch == '*') {
+ if (objIndex >= objc - 1) {
+ msg = badIndex[gotXpg];
+ goto errorMsg;
+ }
+ if (Jim_GetLong(interp, objv[objIndex], &precision) != JIM_OK) {
+ goto error;
+ }
+
+
+ if (precision < 0) {
+ precision = 0;
+ }
+ objIndex++;
+ format += step;
+ step = utf8_tounicode(format, &ch);
+ }
+
+
+ useShort = 0;
+ if (ch == 'h') {
+ useShort = 1;
+ format += step;
+ step = utf8_tounicode(format, &ch);
+ } else if (ch == 'l') {
+
+ format += step;
+ step = utf8_tounicode(format, &ch);
+ if (ch == 'l') {
+ format += step;
+ step = utf8_tounicode(format, &ch);
+ }
+ }
+
+ format += step;
+ span = format;
+
+
+ if (ch == 'i') {
+ ch = 'd';
+ }
+
+ doubleType = 0;
+
+ switch (ch) {
+ case '\0':
+ msg = "format string ended in middle of field specifier";
+ goto errorMsg;
+ case 's': {
+ formatted_buf = Jim_GetString(objv[objIndex], &formatted_bytes);
+ formatted_chars = Jim_Utf8Length(interp, objv[objIndex]);
+ if (gotPrecision && (precision < formatted_chars)) {
+
+ formatted_chars = precision;
+ formatted_bytes = utf8_index(formatted_buf, precision);
+ }
+ break;
+ }
+ case 'c': {
+ jim_wide code;
+
+ if (Jim_GetWide(interp, objv[objIndex], &code) != JIM_OK) {
+ goto error;
+ }
+
+ formatted_bytes = utf8_fromunicode(spec, code);
+ formatted_buf = spec;
+ formatted_chars = 1;
+ break;
+ }
+
+ case 'e':
+ case 'E':
+ case 'f':
+ case 'g':
+ case 'G':
+ doubleType = 1;
+
+ case 'd':
+ case 'u':
+ case 'o':
+ case 'x':
+ case 'X': {
+ jim_wide w;
+ double d;
+ int length;
+
+
+ if (width) {
+ p += sprintf(p, "%ld", width);
+ }
+ if (gotPrecision) {
+ p += sprintf(p, ".%ld", precision);
+ }
+
+
+ if (doubleType) {
+ if (Jim_GetDouble(interp, objv[objIndex], &d) != JIM_OK) {
+ goto error;
+ }
+ length = MAX_FLOAT_WIDTH;
+ }
+ else {
+ if (Jim_GetWide(interp, objv[objIndex], &w) != JIM_OK) {
+ goto error;
+ }
+ length = JIM_INTEGER_SPACE;
+ if (useShort) {
+ *p++ = 'h';
+ if (ch == 'd') {
+ w = (short)w;
+ }
+ else {
+ w = (unsigned short)w;
+ }
+ }
+ else {
+ *p++ = 'l';
+#ifdef HAVE_LONG_LONG
+ if (sizeof(long long) == sizeof(jim_wide)) {
+ *p++ = 'l';
+ }
+#endif
+ }
+ }
+
+ *p++ = (char) ch;
+ *p = '\0';
+
+
+ if (width > length) {
+ length = width;
+ }
+ if (gotPrecision) {
+ length += precision;
+ }
+
+
+ if (num_buffer_size < length + 1) {
+ num_buffer_size = length + 1;
+ num_buffer = Jim_Realloc(num_buffer, num_buffer_size);
+ }
+
+ if (doubleType) {
+ snprintf(num_buffer, length + 1, spec, d);
+ }
+ else {
+ formatted_bytes = snprintf(num_buffer, length + 1, spec, w);
+ }
+ formatted_chars = formatted_bytes = strlen(num_buffer);
+ formatted_buf = num_buffer;
+ break;
+ }
+
+ default: {
+
+ spec[0] = ch;
+ spec[1] = '\0';
+ Jim_SetResultFormatted(interp, "bad field specifier \"%s\"", spec);
+ goto error;
+ }
+ }
+
+ if (!gotMinus) {
+ while (formatted_chars < width) {
+ Jim_AppendString(interp, resultPtr, &pad, 1);
+ formatted_chars++;
+ }
+ }
+
+ Jim_AppendString(interp, resultPtr, formatted_buf, formatted_bytes);
+
+ while (formatted_chars < width) {
+ Jim_AppendString(interp, resultPtr, &pad, 1);
+ formatted_chars++;
+ }
+
+ objIndex += gotSequential;
+ }
+ if (numBytes) {
+ Jim_AppendString(interp, resultPtr, span, numBytes);
+ }
+
+ Jim_Free(num_buffer);
+ return resultPtr;
+
+ errorMsg:
+ Jim_SetResultString(interp, msg, -1);
+ error:
+ Jim_FreeNewObj(interp, resultPtr);
+ Jim_Free(num_buffer);
+ return NULL;
+}
+#include
+#include
+#include
+#include
+
+
+#if !defined(HAVE_REGCOMP) || defined(JIM_REGEXP)
+
+
+
+#define REG_MAX_PAREN 100
+
+
+#define END 0
+#define BOL 1
+#define EOL 2
+#define ANY 3
+#define ANYOF 4
+#define ANYBUT 5
+#define BRANCH 6
+#define BACK 7
+#define EXACTLY 8
+#define NOTHING 9
+#define REP 10
+#define REPMIN 11
+#define REPX 12
+#define REPXMIN 13
+
+#define WORDA 15
+#define WORDZ 16
+#define OPENNC 19
+#define OPEN 20
+
+#define CLOSE (OPEN+REG_MAX_PAREN+1)
+#define CLOSE_END (CLOSE+REG_MAX_PAREN)
+#define CLOSENC (CLOSE-1)
+
+#define REG_MAGIC 0xFADED00D
+
+
+#define OP(preg, p) (preg->program[p])
+#define NEXT(preg, p) (preg->program[p + 1])
+#define OPERAND(p) ((p) + 2)
+
+
+
+
+#define FAIL(R,M) { (R)->err = (M); return (M); }
+#define ISMULT(c) ((c) == '*' || (c) == '+' || (c) == '?' || (c) == '{')
+#define META "^$.[()|?{+*"
+
+#define HASWIDTH 01
+#define SIMPLE 02
+#define SPSTART 04
+#define WORST 0
+
+#define MAX_REP_COUNT 1000000
+
+static int reg(regex_t *preg, int paren , int *flagp );
+static int regpiece(regex_t *preg, int *flagp );
+static int regbranch(regex_t *preg, int *flagp );
+static int regatom(regex_t *preg, int *flagp );
+static int regnode(regex_t *preg, int op );
+static int regnext(regex_t *preg, int p );
+static void regc(regex_t *preg, int b );
+static int reginsert(regex_t *preg, int op, int size, int opnd );
+static void regtail_(regex_t *preg, int p, int val, int line );
+static void regoptail(regex_t *preg, int p, int val );
+#define regtail(PREG, P, VAL) regtail_(PREG, P, VAL, __LINE__)
+
+static int reg_range_find(const int *string, int c);
+static const char *str_find(const char *string, int c, int nocase);
+static int prefix_cmp(const int *prog, int proglen, const char *string, int nocase);
+
+
+#ifdef DEBUG
+static int regnarrate = 0;
+static void regdump(regex_t *preg);
+static const char *regprop( int op );
+#endif
+
+
+static int str_int_len(const int *seq)
+{
+ int n = 0;
+ while (*seq++) {
+ n++;
+ }
+ return n;
+}
+
+int regcomp(regex_t *preg, const char *exp, int cflags)
+{
+ int scan;
+ int longest;
+ unsigned len;
+ int flags;
+
+#ifdef DEBUG
+ fprintf(stderr, "Compiling: '%s'\n", exp);
+#endif
+ memset(preg, 0, sizeof(*preg));
+
+ if (exp == NULL)
+ FAIL(preg, REG_ERR_NULL_ARGUMENT);
+
+
+ preg->cflags = cflags;
+ preg->regparse = exp;
+
+ preg->program = NULL;
+ preg->proglen = 0;
+
+
+ preg->proglen = (strlen(exp) + 1) * 5;
+ preg->program = malloc(preg->proglen * sizeof(int));
+ if (preg->program == NULL)
+ FAIL(preg, REG_ERR_NOMEM);
+
+ regc(preg, REG_MAGIC);
+ if (reg(preg, 0, &flags) == 0) {
+ return preg->err;
+ }
+
+
+ if (preg->re_nsub >= REG_MAX_PAREN)
+ FAIL(preg,REG_ERR_TOO_BIG);
+
+
+ preg->regstart = 0;
+ preg->reganch = 0;
+ preg->regmust = 0;
+ preg->regmlen = 0;
+ scan = 1;
+ if (OP(preg, regnext(preg, scan)) == END) {
+ scan = OPERAND(scan);
+
+
+ if (OP(preg, scan) == EXACTLY) {
+ preg->regstart = preg->program[OPERAND(scan)];
+ }
+ else if (OP(preg, scan) == BOL)
+ preg->reganch++;
+
+ if (flags&SPSTART) {
+ longest = 0;
+ len = 0;
+ for (; scan != 0; scan = regnext(preg, scan)) {
+ if (OP(preg, scan) == EXACTLY) {
+ int plen = str_int_len(preg->program + OPERAND(scan));
+ if (plen >= len) {
+ longest = OPERAND(scan);
+ len = plen;
+ }
+ }
+ }
+ preg->regmust = longest;
+ preg->regmlen = len;
+ }
+ }
+
+#ifdef DEBUG
+ regdump(preg);
+#endif
+
+ return 0;
+}
+
+static int reg(regex_t *preg, int paren , int *flagp )
+{
+ int ret;
+ int br;
+ int ender;
+ int parno = 0;
+ int flags;
+
+ *flagp = HASWIDTH;
+
+
+ if (paren) {
+ if (preg->regparse[0] == '?' && preg->regparse[1] == ':') {
+
+ preg->regparse += 2;
+ parno = -1;
+ }
+ else {
+ parno = ++preg->re_nsub;
+ }
+ ret = regnode(preg, OPEN+parno);
+ } else
+ ret = 0;
+
+
+ br = regbranch(preg, &flags);
+ if (br == 0)
+ return 0;
+ if (ret != 0)
+ regtail(preg, ret, br);
+ else
+ ret = br;
+ if (!(flags&HASWIDTH))
+ *flagp &= ~HASWIDTH;
+ *flagp |= flags&SPSTART;
+ while (*preg->regparse == '|') {
+ preg->regparse++;
+ br = regbranch(preg, &flags);
+ if (br == 0)
+ return 0;
+ regtail(preg, ret, br);
+ if (!(flags&HASWIDTH))
+ *flagp &= ~HASWIDTH;
+ *flagp |= flags&SPSTART;
+ }
+
+
+ ender = regnode(preg, (paren) ? CLOSE+parno : END);
+ regtail(preg, ret, ender);
+
+
+ for (br = ret; br != 0; br = regnext(preg, br))
+ regoptail(preg, br, ender);
+
+
+ if (paren && *preg->regparse++ != ')') {
+ preg->err = REG_ERR_UNMATCHED_PAREN;
+ return 0;
+ } else if (!paren && *preg->regparse != '\0') {
+ if (*preg->regparse == ')') {
+ preg->err = REG_ERR_UNMATCHED_PAREN;
+ return 0;
+ } else {
+ preg->err = REG_ERR_JUNK_ON_END;
+ return 0;
+ }
+ }
+
+ return(ret);
+}
+
+static int regbranch(regex_t *preg, int *flagp )
+{
+ int ret;
+ int chain;
+ int latest;
+ int flags;
+
+ *flagp = WORST;
+
+ ret = regnode(preg, BRANCH);
+ chain = 0;
+ while (*preg->regparse != '\0' && *preg->regparse != ')' &&
+ *preg->regparse != '|') {
+ latest = regpiece(preg, &flags);
+ if (latest == 0)
+ return 0;
+ *flagp |= flags&HASWIDTH;
+ if (chain == 0) {
+ *flagp |= flags&SPSTART;
+ }
+ else {
+ regtail(preg, chain, latest);
+ }
+ chain = latest;
+ }
+ if (chain == 0)
+ (void) regnode(preg, NOTHING);
+
+ return(ret);
+}
+
+static int regpiece(regex_t *preg, int *flagp)
+{
+ int ret;
+ char op;
+ int next;
+ int flags;
+ int chain = 0;
+ int min;
+ int max;
+
+ ret = regatom(preg, &flags);
+ if (ret == 0)
+ return 0;
+
+ op = *preg->regparse;
+ if (!ISMULT(op)) {
+ *flagp = flags;
+ return(ret);
+ }
+
+ if (!(flags&HASWIDTH) && op != '?') {
+ preg->err = REG_ERR_OPERAND_COULD_BE_EMPTY;
+ return 0;
+ }
+
+
+ if (op == '{') {
+ char *end;
+
+ min = strtoul(preg->regparse + 1, &end, 10);
+ if (end == preg->regparse + 1) {
+ preg->err = REG_ERR_BAD_COUNT;
+ return 0;
+ }
+ if (*end == '}') {
+ max = min;
+ }
+ else {
+ preg->regparse = end;
+ max = strtoul(preg->regparse + 1, &end, 10);
+ if (*end != '}') {
+ preg->err = REG_ERR_UNMATCHED_BRACES;
+ return 0;
+ }
+ }
+ if (end == preg->regparse + 1) {
+ max = MAX_REP_COUNT;
+ }
+ else if (max < min || max >= 100) {
+ preg->err = REG_ERR_BAD_COUNT;
+ return 0;
+ }
+ if (min >= 100) {
+ preg->err = REG_ERR_BAD_COUNT;
+ return 0;
+ }
+
+ preg->regparse = strchr(preg->regparse, '}');
+ }
+ else {
+ min = (op == '+');
+ max = (op == '?' ? 1 : MAX_REP_COUNT);
+ }
+
+ if (preg->regparse[1] == '?') {
+ preg->regparse++;
+ next = reginsert(preg, flags & SIMPLE ? REPMIN : REPXMIN, 5, ret);
+ }
+ else {
+ next = reginsert(preg, flags & SIMPLE ? REP: REPX, 5, ret);
+ }
+ preg->program[ret + 2] = max;
+ preg->program[ret + 3] = min;
+ preg->program[ret + 4] = 0;
+
+ *flagp = (min) ? (WORST|HASWIDTH) : (WORST|SPSTART);
+
+ if (!(flags & SIMPLE)) {
+ int back = regnode(preg, BACK);
+ regtail(preg, back, ret);
+ regtail(preg, next, back);
+ }
+
+ preg->regparse++;
+ if (ISMULT(*preg->regparse)) {
+ preg->err = REG_ERR_NESTED_COUNT;
+ return 0;
+ }
+
+ return chain ? chain : ret;
+}
+
+static void reg_addrange(regex_t *preg, int lower, int upper)
+{
+ if (lower > upper) {
+ reg_addrange(preg, upper, lower);
+ }
+
+ regc(preg, upper - lower + 1);
+ regc(preg, lower);
+}
+
+static void reg_addrange_str(regex_t *preg, const char *str)
+{
+ while (*str) {
+ reg_addrange(preg, *str, *str);
+ str++;
+ }
+}
+
+static int reg_utf8_tounicode_case(const char *s, int *uc, int upper)
+{
+ int l = utf8_tounicode(s, uc);
+ if (upper) {
+ *uc = utf8_upper(*uc);
+ }
+ return l;
+}
+
+static int hexdigitval(int c)
+{
+ if (c >= '0' && c <= '9')
+ return c - '0';
+ if (c >= 'a' && c <= 'f')
+ return c - 'a' + 10;
+ if (c >= 'A' && c <= 'F')
+ return c - 'A' + 10;
+ return -1;
+}
+
+static int parse_hex(const char *s, int n, int *uc)
+{
+ int val = 0;
+ int k;
+
+ for (k = 0; k < n; k++) {
+ int c = hexdigitval(*s++);
+ if (c == -1) {
+ break;
+ }
+ val = (val << 4) | c;
+ }
+ if (k) {
+ *uc = val;
+ }
+ return k;
+}
+
+static int reg_decode_escape(const char *s, int *ch)
+{
+ int n;
+ const char *s0 = s;
+
+ *ch = *s++;
+
+ switch (*ch) {
+ case 'b': *ch = '\b'; break;
+ case 'e': *ch = 27; break;
+ case 'f': *ch = '\f'; break;
+ case 'n': *ch = '\n'; break;
+ case 'r': *ch = '\r'; break;
+ case 't': *ch = '\t'; break;
+ case 'v': *ch = '\v'; break;
+ case 'u':
+ if (*s == '{') {
+
+ n = parse_hex(s + 1, 6, ch);
+ if (n > 0 && s[n + 1] == '}' && *ch >= 0 && *ch <= 0x1fffff) {
+ s += n + 2;
+ }
+ else {
+
+ *ch = 'u';
+ }
+ }
+ else if ((n = parse_hex(s, 4, ch)) > 0) {
+ s += n;
+ }
+ break;
+ case 'U':
+ if ((n = parse_hex(s, 8, ch)) > 0) {
+ s += n;
+ }
+ case 'x':
+ if ((n = parse_hex(s, 2, ch)) > 0) {
+ s += n;
+ }
+ break;
+ case '\0':
+ s--;
+ *ch = '\\';
+ break;
+ }
+ return s - s0;
+}
+
+static int regatom(regex_t *preg, int *flagp)
+{
+ int ret;
+ int flags;
+ int nocase = (preg->cflags & REG_ICASE);
+
+ int ch;
+ int n = reg_utf8_tounicode_case(preg->regparse, &ch, nocase);
+
+ *flagp = WORST;
+
+ preg->regparse += n;
+ switch (ch) {
+
+ case '^':
+ ret = regnode(preg, BOL);
+ break;
+ case '$':
+ ret = regnode(preg, EOL);
+ break;
+ case '.':
+ ret = regnode(preg, ANY);
+ *flagp |= HASWIDTH|SIMPLE;
+ break;
+ case '[': {
+ const char *pattern = preg->regparse;
+
+ if (*pattern == '^') {
+ ret = regnode(preg, ANYBUT);
+ pattern++;
+ } else
+ ret = regnode(preg, ANYOF);
+
+
+ if (*pattern == ']' || *pattern == '-') {
+ reg_addrange(preg, *pattern, *pattern);
+ pattern++;
+ }
+
+ while (*pattern && *pattern != ']') {
+
+ int start;
+ int end;
+
+ pattern += reg_utf8_tounicode_case(pattern, &start, nocase);
+ if (start == '\\') {
+ pattern += reg_decode_escape(pattern, &start);
+ if (start == 0) {
+ preg->err = REG_ERR_NULL_CHAR;
+ return 0;
+ }
+ }
+ if (pattern[0] == '-' && pattern[1] && pattern[1] != ']') {
+
+ pattern += utf8_tounicode(pattern, &end);
+ pattern += reg_utf8_tounicode_case(pattern, &end, nocase);
+ if (end == '\\') {
+ pattern += reg_decode_escape(pattern, &end);
+ if (end == 0) {
+ preg->err = REG_ERR_NULL_CHAR;
+ return 0;
+ }
+ }
+
+ reg_addrange(preg, start, end);
+ continue;
+ }
+ if (start == '[') {
+ if (strncmp(pattern, ":alpha:]", 8) == 0) {
+ if ((preg->cflags & REG_ICASE) == 0) {
+ reg_addrange(preg, 'a', 'z');
+ }
+ reg_addrange(preg, 'A', 'Z');
+ pattern += 8;
+ continue;
+ }
+ if (strncmp(pattern, ":alnum:]", 8) == 0) {
+ if ((preg->cflags & REG_ICASE) == 0) {
+ reg_addrange(preg, 'a', 'z');
+ }
+ reg_addrange(preg, 'A', 'Z');
+ reg_addrange(preg, '0', '9');
+ pattern += 8;
+ continue;
+ }
+ if (strncmp(pattern, ":space:]", 8) == 0) {
+ reg_addrange_str(preg, " \t\r\n\f\v");
+ pattern += 8;
+ continue;
+ }
+ }
+
+ reg_addrange(preg, start, start);
+ }
+ regc(preg, '\0');
+
+ if (*pattern) {
+ pattern++;
+ }
+ preg->regparse = pattern;
+
+ *flagp |= HASWIDTH|SIMPLE;
+ }
+ break;
+ case '(':
+ ret = reg(preg, 1, &flags);
+ if (ret == 0)
+ return 0;
+ *flagp |= flags&(HASWIDTH|SPSTART);
+ break;
+ case '\0':
+ case '|':
+ case ')':
+ preg->err = REG_ERR_INTERNAL;
+ return 0;
+ case '?':
+ case '+':
+ case '*':
+ case '{':
+ preg->err = REG_ERR_COUNT_FOLLOWS_NOTHING;
+ return 0;
+ case '\\':
+ switch (*preg->regparse++) {
+ case '\0':
+ preg->err = REG_ERR_TRAILING_BACKSLASH;
+ return 0;
+ case '<':
+ case 'm':
+ ret = regnode(preg, WORDA);
+ break;
+ case '>':
+ case 'M':
+ ret = regnode(preg, WORDZ);
+ break;
+ case 'd':
+ ret = regnode(preg, ANYOF);
+ reg_addrange(preg, '0', '9');
+ regc(preg, '\0');
+ *flagp |= HASWIDTH|SIMPLE;
+ break;
+ case 'w':
+ ret = regnode(preg, ANYOF);
+ if ((preg->cflags & REG_ICASE) == 0) {
+ reg_addrange(preg, 'a', 'z');
+ }
+ reg_addrange(preg, 'A', 'Z');
+ reg_addrange(preg, '0', '9');
+ reg_addrange(preg, '_', '_');
+ regc(preg, '\0');
+ *flagp |= HASWIDTH|SIMPLE;
+ break;
+ case 's':
+ ret = regnode(preg, ANYOF);
+ reg_addrange_str(preg," \t\r\n\f\v");
+ regc(preg, '\0');
+ *flagp |= HASWIDTH|SIMPLE;
+ break;
+
+ default:
+
+
+ preg->regparse--;
+ goto de_fault;
+ }
+ break;
+ de_fault:
+ default: {
+ int added = 0;
+
+
+ preg->regparse -= n;
+
+ ret = regnode(preg, EXACTLY);
+
+
+
+ while (*preg->regparse && strchr(META, *preg->regparse) == NULL) {
+ n = reg_utf8_tounicode_case(preg->regparse, &ch, (preg->cflags & REG_ICASE));
+ if (ch == '\\' && preg->regparse[n]) {
+ if (strchr("<>mMwds", preg->regparse[n])) {
+
+ break;
+ }
+ n += reg_decode_escape(preg->regparse + n, &ch);
+ if (ch == 0) {
+ preg->err = REG_ERR_NULL_CHAR;
+ return 0;
+ }
+ }
+
+
+ if (ISMULT(preg->regparse[n])) {
+
+ if (added) {
+
+ break;
+ }
+
+ regc(preg, ch);
+ added++;
+ preg->regparse += n;
+ break;
+ }
+
+
+ regc(preg, ch);
+ added++;
+ preg->regparse += n;
+ }
+ regc(preg, '\0');
+
+ *flagp |= HASWIDTH;
+ if (added == 1)
+ *flagp |= SIMPLE;
+ break;
+ }
+ break;
+ }
+
+ return(ret);
+}
+
+static void reg_grow(regex_t *preg, int n)
+{
+ if (preg->p + n >= preg->proglen) {
+ preg->proglen = (preg->p + n) * 2;
+ preg->program = realloc(preg->program, preg->proglen * sizeof(int));
+ }
+}
+
+
+static int regnode(regex_t *preg, int op)
+{
+ reg_grow(preg, 2);
+
+ preg->program[preg->p++] = op;
+ preg->program[preg->p++] = 0;
+
+
+ return preg->p - 2;
+}
+
+static void regc(regex_t *preg, int b )
+{
+ reg_grow(preg, 1);
+ preg->program[preg->p++] = b;
+}
+
+static int reginsert(regex_t *preg, int op, int size, int opnd )
+{
+ reg_grow(preg, size);
+
+
+ memmove(preg->program + opnd + size, preg->program + opnd, sizeof(int) * (preg->p - opnd));
+
+ memset(preg->program + opnd, 0, sizeof(int) * size);
+
+ preg->program[opnd] = op;
+
+ preg->p += size;
+
+ return opnd + size;
+}
+
+static void regtail_(regex_t *preg, int p, int val, int line )
+{
+ int scan;
+ int temp;
+ int offset;
+
+
+ scan = p;
+ for (;;) {
+ temp = regnext(preg, scan);
+ if (temp == 0)
+ break;
+ scan = temp;
+ }
+
+ if (OP(preg, scan) == BACK)
+ offset = scan - val;
+ else
+ offset = val - scan;
+
+ preg->program[scan + 1] = offset;
+}
+
+
+static void regoptail(regex_t *preg, int p, int val )
+{
+
+ if (p != 0 && OP(preg, p) == BRANCH) {
+ regtail(preg, OPERAND(p), val);
+ }
+}
+
+
+static int regtry(regex_t *preg, const char *string );
+static int regmatch(regex_t *preg, int prog);
+static int regrepeat(regex_t *preg, int p, int max);
+
+int regexec(regex_t *preg, const char *string, size_t nmatch, regmatch_t pmatch[], int eflags)
+{
+ const char *s;
+ int scan;
+
+
+ if (preg == NULL || preg->program == NULL || string == NULL) {
+ return REG_ERR_NULL_ARGUMENT;
+ }
+
+
+ if (*preg->program != REG_MAGIC) {
+ return REG_ERR_CORRUPTED;
+ }
+
+#ifdef DEBUG
+ fprintf(stderr, "regexec: %s\n", string);
+ regdump(preg);
+#endif
+
+ preg->eflags = eflags;
+ preg->pmatch = pmatch;
+ preg->nmatch = nmatch;
+ preg->start = string;
+
+
+ for (scan = OPERAND(1); scan != 0; ) {
+ switch (OP(preg, scan)) {
+ case REP:
+ case REPMIN:
+ case REPX:
+ case REPXMIN:
+ preg->program[scan + 4] = 0;
+ scan += 5;
+ break;
+
+ case ANYOF:
+ case ANYBUT:
+ case EXACTLY:
+ scan += 2;
+ while (preg->program[scan++]) {
+ }
+ break;
+
+ case END:
+ scan = 0;
+ break;
+
+ default:
+ scan += 2;
+ break;
+ }
+ }
+
+
+ if (preg->regmust != 0) {
+ s = string;
+ while ((s = str_find(s, preg->program[preg->regmust], preg->cflags & REG_ICASE)) != NULL) {
+ if (prefix_cmp(preg->program + preg->regmust, preg->regmlen, s, preg->cflags & REG_ICASE) >= 0) {
+ break;
+ }
+ s++;
+ }
+ if (s == NULL)
+ return REG_NOMATCH;
+ }
+
+
+ preg->regbol = string;
+
+
+ if (preg->reganch) {
+ if (eflags & REG_NOTBOL) {
+
+ goto nextline;
+ }
+ while (1) {
+ if (regtry(preg, string)) {
+ return REG_NOERROR;
+ }
+ if (*string) {
+nextline:
+ if (preg->cflags & REG_NEWLINE) {
+
+ string = strchr(string, '\n');
+ if (string) {
+ preg->regbol = ++string;
+ continue;
+ }
+ }
+ }
+ return REG_NOMATCH;
+ }
+ }
+
+
+ s = string;
+ if (preg->regstart != '\0') {
+
+ while ((s = str_find(s, preg->regstart, preg->cflags & REG_ICASE)) != NULL) {
+ if (regtry(preg, s))
+ return REG_NOERROR;
+ s++;
+ }
+ }
+ else
+
+ while (1) {
+ if (regtry(preg, s))
+ return REG_NOERROR;
+ if (*s == '\0') {
+ break;
+ }
+ else {
+ int c;
+ s += utf8_tounicode(s, &c);
+ }
+ }
+
+
+ return REG_NOMATCH;
+}
+
+
+static int regtry( regex_t *preg, const char *string )
+{
+ int i;
+
+ preg->reginput = string;
+
+ for (i = 0; i < preg->nmatch; i++) {
+ preg->pmatch[i].rm_so = -1;
+ preg->pmatch[i].rm_eo = -1;
+ }
+ if (regmatch(preg, 1)) {
+ preg->pmatch[0].rm_so = string - preg->start;
+ preg->pmatch[0].rm_eo = preg->reginput - preg->start;
+ return(1);
+ } else
+ return(0);
+}
+
+static int prefix_cmp(const int *prog, int proglen, const char *string, int nocase)
+{
+ const char *s = string;
+ while (proglen && *s) {
+ int ch;
+ int n = reg_utf8_tounicode_case(s, &ch, nocase);
+ if (ch != *prog) {
+ return -1;
+ }
+ prog++;
+ s += n;
+ proglen--;
+ }
+ if (proglen == 0) {
+ return s - string;
+ }
+ return -1;
+}
+
+static int reg_range_find(const int *range, int c)
+{
+ while (*range) {
+
+ if (c >= range[1] && c <= (range[0] + range[1] - 1)) {
+ return 1;
+ }
+ range += 2;
+ }
+ return 0;
+}
+
+static const char *str_find(const char *string, int c, int nocase)
+{
+ if (nocase) {
+
+ c = utf8_upper(c);
+ }
+ while (*string) {
+ int ch;
+ int n = reg_utf8_tounicode_case(string, &ch, nocase);
+ if (c == ch) {
+ return string;
+ }
+ string += n;
+ }
+ return NULL;
+}
+
+static int reg_iseol(regex_t *preg, int ch)
+{
+ if (preg->cflags & REG_NEWLINE) {
+ return ch == '\0' || ch == '\n';
+ }
+ else {
+ return ch == '\0';
+ }
+}
+
+static int regmatchsimplerepeat(regex_t *preg, int scan, int matchmin)
+{
+ int nextch = '\0';
+ const char *save;
+ int no;
+ int c;
+
+ int max = preg->program[scan + 2];
+ int min = preg->program[scan + 3];
+ int next = regnext(preg, scan);
+
+ if (OP(preg, next) == EXACTLY) {
+ nextch = preg->program[OPERAND(next)];
+ }
+ save = preg->reginput;
+ no = regrepeat(preg, scan + 5, max);
+ if (no < min) {
+ return 0;
+ }
+ if (matchmin) {
+
+ max = no;
+ no = min;
+ }
+
+ while (1) {
+ if (matchmin) {
+ if (no > max) {
+ break;
+ }
+ }
+ else {
+ if (no < min) {
+ break;
+ }
+ }
+ preg->reginput = save + utf8_index(save, no);
+ reg_utf8_tounicode_case(preg->reginput, &c, (preg->cflags & REG_ICASE));
+
+ if (reg_iseol(preg, nextch) || c == nextch) {
+ if (regmatch(preg, next)) {
+ return(1);
+ }
+ }
+ if (matchmin) {
+
+ no++;
+ }
+ else {
+
+ no--;
+ }
+ }
+ return(0);
+}
+
+static int regmatchrepeat(regex_t *preg, int scan, int matchmin)
+{
+ int *scanpt = preg->program + scan;
+
+ int max = scanpt[2];
+ int min = scanpt[3];
+
+
+ if (scanpt[4] < min) {
+
+ scanpt[4]++;
+ if (regmatch(preg, scan + 5)) {
+ return 1;
+ }
+ scanpt[4]--;
+ return 0;
+ }
+ if (scanpt[4] > max) {
+ return 0;
+ }
+
+ if (matchmin) {
+
+ if (regmatch(preg, regnext(preg, scan))) {
+ return 1;
+ }
+
+ scanpt[4]++;
+ if (regmatch(preg, scan + 5)) {
+ return 1;
+ }
+ scanpt[4]--;
+ return 0;
+ }
+
+ if (scanpt[4] < max) {
+ scanpt[4]++;
+ if (regmatch(preg, scan + 5)) {
+ return 1;
+ }
+ scanpt[4]--;
+ }
+
+ return regmatch(preg, regnext(preg, scan));
+}
+
+
+static int regmatch(regex_t *preg, int prog)
+{
+ int scan;
+ int next;
+
+ scan = prog;
+
+#ifdef DEBUG
+ if (scan != 0 && regnarrate)
+ fprintf(stderr, "%s(\n", regprop(scan));
+#endif
+ while (scan != 0) {
+ int n;
+ int c;
+#ifdef DEBUG
+ if (regnarrate) {
+ fprintf(stderr, "%3d: %s...\n", scan, regprop(OP(preg, scan)));
+ }
+#endif
+ next = regnext(preg, scan);
+ n = reg_utf8_tounicode_case(preg->reginput, &c, (preg->cflags & REG_ICASE));
+
+ switch (OP(preg, scan)) {
+ case BOL:
+ if (preg->reginput != preg->regbol)
+ return(0);
+ break;
+ case EOL:
+ if (!reg_iseol(preg, c)) {
+ return(0);
+ }
+ break;
+ case WORDA:
+
+ if ((!isalnum(UCHAR(c))) && c != '_')
+ return(0);
+
+ if (preg->reginput > preg->regbol &&
+ (isalnum(UCHAR(preg->reginput[-1])) || preg->reginput[-1] == '_'))
+ return(0);
+ break;
+ case WORDZ:
+
+ if (preg->reginput > preg->regbol) {
+
+ if (reg_iseol(preg, c) || !isalnum(UCHAR(c)) || c != '_') {
+ c = preg->reginput[-1];
+
+ if (isalnum(UCHAR(c)) || c == '_') {
+ break;
+ }
+ }
+ }
+
+ return(0);
+
+ case ANY:
+ if (reg_iseol(preg, c))
+ return 0;
+ preg->reginput += n;
+ break;
+ case EXACTLY: {
+ int opnd;
+ int len;
+ int slen;
+
+ opnd = OPERAND(scan);
+ len = str_int_len(preg->program + opnd);
+
+ slen = prefix_cmp(preg->program + opnd, len, preg->reginput, preg->cflags & REG_ICASE);
+ if (slen < 0) {
+ return(0);
+ }
+ preg->reginput += slen;
+ }
+ break;
+ case ANYOF:
+ if (reg_iseol(preg, c) || reg_range_find(preg->program + OPERAND(scan), c) == 0) {
+ return(0);
+ }
+ preg->reginput += n;
+ break;
+ case ANYBUT:
+ if (reg_iseol(preg, c) || reg_range_find(preg->program + OPERAND(scan), c) != 0) {
+ return(0);
+ }
+ preg->reginput += n;
+ break;
+ case NOTHING:
+ break;
+ case BACK:
+ break;
+ case BRANCH: {
+ const char *save;
+
+ if (OP(preg, next) != BRANCH)
+ next = OPERAND(scan);
+ else {
+ do {
+ save = preg->reginput;
+ if (regmatch(preg, OPERAND(scan))) {
+ return(1);
+ }
+ preg->reginput = save;
+ scan = regnext(preg, scan);
+ } while (scan != 0 && OP(preg, scan) == BRANCH);
+ return(0);
+
+ }
+ }
+ break;
+ case REP:
+ case REPMIN:
+ return regmatchsimplerepeat(preg, scan, OP(preg, scan) == REPMIN);
+
+ case REPX:
+ case REPXMIN:
+ return regmatchrepeat(preg, scan, OP(preg, scan) == REPXMIN);
+
+ case END:
+ return(1);
+ break;
+
+ case OPENNC:
+ case CLOSENC:
+ if (regmatch(preg, next)) {
+ return 1;
+ }
+ return 0;
+
+ default:
+ if (OP(preg, scan) >= OPEN+1 && OP(preg, scan) < CLOSE_END) {
+ const char *save;
+
+ save = preg->reginput;
+
+ if (regmatch(preg, next)) {
+ int no;
+ if (OP(preg, scan) < CLOSE) {
+ no = OP(preg, scan) - OPEN;
+ if (no < preg->nmatch && preg->pmatch[no].rm_so == -1) {
+ preg->pmatch[no].rm_so = save - preg->start;
+ }
+ }
+ else {
+ no = OP(preg, scan) - CLOSE;
+ if (no < preg->nmatch && preg->pmatch[no].rm_eo == -1) {
+ preg->pmatch[no].rm_eo = save - preg->start;
+ }
+ }
+ return(1);
+ } else
+ return(0);
+ }
+ return REG_ERR_INTERNAL;
+ }
+
+ scan = next;
+ }
+
+ return REG_ERR_INTERNAL;
+}
+
+static int regrepeat(regex_t *preg, int p, int max)
+{
+ int count = 0;
+ const char *scan;
+ int opnd;
+ int ch;
+ int n;
+
+ scan = preg->reginput;
+ opnd = OPERAND(p);
+ switch (OP(preg, p)) {
+ case ANY:
+
+ while (!reg_iseol(preg, *scan) && count < max) {
+ count++;
+ scan++;
+ }
+ break;
+ case EXACTLY:
+ while (count < max) {
+ n = reg_utf8_tounicode_case(scan, &ch, preg->cflags & REG_ICASE);
+ if (preg->program[opnd] != ch) {
+ break;
+ }
+ count++;
+ scan += n;
+ }
+ break;
+ case ANYOF:
+ while (count < max) {
+ n = reg_utf8_tounicode_case(scan, &ch, preg->cflags & REG_ICASE);
+ if (reg_iseol(preg, ch) || reg_range_find(preg->program + opnd, ch) == 0) {
+ break;
+ }
+ count++;
+ scan += n;
+ }
+ break;
+ case ANYBUT:
+ while (count < max) {
+ n = reg_utf8_tounicode_case(scan, &ch, preg->cflags & REG_ICASE);
+ if (reg_iseol(preg, ch) || reg_range_find(preg->program + opnd, ch) != 0) {
+ break;
+ }
+ count++;
+ scan += n;
+ }
+ break;
+ default:
+ preg->err = REG_ERR_INTERNAL;
+ count = 0;
+ break;
+ }
+ preg->reginput = scan;
+
+ return(count);
+}
+
+static int regnext(regex_t *preg, int p )
+{
+ int offset;
+
+ offset = NEXT(preg, p);
+
+ if (offset == 0)
+ return 0;
+
+ if (OP(preg, p) == BACK)
+ return(p-offset);
+ else
+ return(p+offset);
+}
+
+
+size_t regerror(int errcode, const regex_t *preg, char *errbuf, size_t errbuf_size)
+{
+ static const char *error_strings[] = {
+ "success",
+ "no match",
+ "bad pattern",
+ "null argument",
+ "unknown error",
+ "too big",
+ "out of memory",
+ "too many ()",
+ "parentheses () not balanced",
+ "braces {} not balanced",
+ "invalid repetition count(s)",
+ "extra characters",
+ "*+ of empty atom",
+ "nested count",
+ "internal error",
+ "count follows nothing",
+ "trailing backslash",
+ "corrupted program",
+ "contains null char",
+ };
+ const char *err;
+
+ if (errcode < 0 || errcode >= REG_ERR_NUM) {
+ err = "Bad error code";
+ }
+ else {
+ err = error_strings[errcode];
+ }
+
+ return snprintf(errbuf, errbuf_size, "%s", err);
+}
+
+void regfree(regex_t *preg)
+{
+ free(preg->program);
+}
+
+#endif
+
+#if defined(_WIN32) || defined(WIN32)
+#ifndef STRICT
+#define STRICT
+#endif
+#define WIN32_LEAN_AND_MEAN
+#include
+
+#if defined(HAVE_DLOPEN_COMPAT)
+void *dlopen(const char *path, int mode)
+{
+ JIM_NOTUSED(mode);
+
+ return (void *)LoadLibraryA(path);
+}
+
+int dlclose(void *handle)
+{
+ FreeLibrary((HANDLE)handle);
+ return 0;
+}
+
+void *dlsym(void *handle, const char *symbol)
+{
+ return GetProcAddress((HMODULE)handle, symbol);
+}
+
+char *dlerror(void)
+{
+ static char msg[121];
+ FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(),
+ LANG_NEUTRAL, msg, sizeof(msg) - 1, NULL);
+ return msg;
+}
+#endif
+
+#ifdef _MSC_VER
+
+#include
+
+
+int gettimeofday(struct timeval *tv, void *unused)
+{
+ struct _timeb tb;
+
+ _ftime(&tb);
+ tv->tv_sec = tb.time;
+ tv->tv_usec = tb.millitm * 1000;
+
+ return 0;
+}
+
+
+DIR *opendir(const char *name)
+{
+ DIR *dir = 0;
+
+ if (name && name[0]) {
+ size_t base_length = strlen(name);
+ const char *all =
+ strchr("/\\", name[base_length - 1]) ? "*" : "/*";
+
+ if ((dir = (DIR *) Jim_Alloc(sizeof *dir)) != 0 &&
+ (dir->name = (char *)Jim_Alloc(base_length + strlen(all) + 1)) != 0) {
+ strcat(strcpy(dir->name, name), all);
+
+ if ((dir->handle = (long)_findfirst(dir->name, &dir->info)) != -1)
+ dir->result.d_name = 0;
+ else {
+ Jim_Free(dir->name);
+ Jim_Free(dir);
+ dir = 0;
+ }
+ }
+ else {
+ Jim_Free(dir);
+ dir = 0;
+ errno = ENOMEM;
+ }
+ }
+ else {
+ errno = EINVAL;
+ }
+ return dir;
+}
+
+int closedir(DIR * dir)
+{
+ int result = -1;
+
+ if (dir) {
+ if (dir->handle != -1)
+ result = _findclose(dir->handle);
+ Jim_Free(dir->name);
+ Jim_Free(dir);
+ }
+ if (result == -1)
+ errno = EBADF;
+ return result;
+}
+
+struct dirent *readdir(DIR * dir)
+{
+ struct dirent *result = 0;
+
+ if (dir && dir->handle != -1) {
+ if (!dir->result.d_name || _findnext(dir->handle, &dir->info) != -1) {
+ result = &dir->result;
+ result->d_name = dir->info.name;
+ }
+ }
+ else {
+ errno = EBADF;
+ }
+ return result;
+}
+#endif
+#endif
+#ifndef JIM_BOOTSTRAP_LIB_ONLY
+#include
+#include
+
+
+#ifdef USE_LINENOISE
+#include
+#include "linenoise.h"
+#else
+#define MAX_LINE_LEN 512
+#endif
+
+char *Jim_HistoryGetline(const char *prompt)
+{
+#ifdef USE_LINENOISE
+ return linenoise(prompt);
+#else
+ char *line = malloc(MAX_LINE_LEN);
+
+ fputs(prompt, stdout);
+ fflush(stdout);
+
+ if (fgets(line, MAX_LINE_LEN, stdin) == NULL) {
+ free(line);
+ return NULL;
+ }
+ return line;
+#endif
+}
+
+void Jim_HistoryLoad(const char *filename)
+{
+#ifdef USE_LINENOISE
+ linenoiseHistoryLoad(filename);
+#endif
+}
+
+void Jim_HistoryAdd(const char *line)
+{
+#ifdef USE_LINENOISE
+ linenoiseHistoryAdd(line);
+#endif
+}
+
+void Jim_HistorySave(const char *filename)
+{
+#ifdef USE_LINENOISE
+ linenoiseHistorySave(filename);
+#endif
+}
+
+void Jim_HistoryShow(void)
+{
+#ifdef USE_LINENOISE
+
+ int i;
+ int len;
+ char **history = linenoiseHistory(&len);
+ for (i = 0; i < len; i++) {
+ printf("%4d %s\n", i + 1, history[i]);
+ }
+#endif
+}
+
+int Jim_InteractivePrompt(Jim_Interp *interp)
+{
+ int retcode = JIM_OK;
+ char *history_file = NULL;
+#ifdef USE_LINENOISE
+ const char *home;
+
+ home = getenv("HOME");
+ if (home && isatty(STDIN_FILENO)) {
+ int history_len = strlen(home) + sizeof("/.jim_history");
+ history_file = Jim_Alloc(history_len);
+ snprintf(history_file, history_len, "%s/.jim_history", home);
+ Jim_HistoryLoad(history_file);
+ }
+#endif
+
+ printf("Welcome to Jim version %d.%d" JIM_NL,
+ JIM_VERSION / 100, JIM_VERSION % 100);
+ Jim_SetVariableStrWithStr(interp, JIM_INTERACTIVE, "1");
+
+ while (1) {
+ Jim_Obj *scriptObjPtr;
+ const char *result;
+ int reslen;
+ char prompt[20];
+ const char *str;
+
+ if (retcode != 0) {
+ const char *retcodestr = Jim_ReturnCode(retcode);
+
+ if (*retcodestr == '?') {
+ snprintf(prompt, sizeof(prompt) - 3, "[%d] ", retcode);
+ }
+ else {
+ snprintf(prompt, sizeof(prompt) - 3, "[%s] ", retcodestr);
+ }
+ }
+ else {
+ prompt[0] = '\0';
+ }
+ strcat(prompt, ". ");
+
+ scriptObjPtr = Jim_NewStringObj(interp, "", 0);
+ Jim_IncrRefCount(scriptObjPtr);
+ while (1) {
+ char state;
+ int len;
+ char *line;
+
+ line = Jim_HistoryGetline(prompt);
+ if (line == NULL) {
+ if (errno == EINTR) {
+ continue;
+ }
+ Jim_DecrRefCount(interp, scriptObjPtr);
+ retcode = JIM_OK;
+ goto out;
+ }
+ if (Jim_Length(scriptObjPtr) != 0) {
+ Jim_AppendString(interp, scriptObjPtr, "\n", 1);
+ }
+ Jim_AppendString(interp, scriptObjPtr, line, -1);
+ free(line);
+ str = Jim_GetString(scriptObjPtr, &len);
+ if (len == 0) {
+ continue;
+ }
+ if (Jim_ScriptIsComplete(str, len, &state))
+ break;
+
+ snprintf(prompt, sizeof(prompt), "%c> ", state);
+ }
+#ifdef USE_LINENOISE
+ if (strcmp(str, "h") == 0) {
+
+ Jim_HistoryShow();
+ Jim_DecrRefCount(interp, scriptObjPtr);
+ continue;
+ }
+
+ Jim_HistoryAdd(Jim_String(scriptObjPtr));
+ if (history_file) {
+ Jim_HistorySave(history_file);
+ }
+#endif
+ retcode = Jim_EvalObj(interp, scriptObjPtr);
+ Jim_DecrRefCount(interp, scriptObjPtr);
+
+ if (retcode == JIM_EXIT) {
+ retcode = JIM_EXIT;
+ break;
+ }
+ if (retcode == JIM_ERR) {
+ Jim_MakeErrorMessage(interp);
+ }
+ result = Jim_GetString(Jim_GetResult(interp), &reslen);
+ if (reslen) {
+ printf("%s\n", result);
+ }
+ }
+ out:
+ Jim_Free(history_file);
+ return retcode;
+}
+
+#include
+#include
+#include
+
+
+
+extern int Jim_initjimshInit(Jim_Interp *interp);
+
+static void JimSetArgv(Jim_Interp *interp, int argc, char *const argv[])
+{
+ int n;
+ Jim_Obj *listObj = Jim_NewListObj(interp, NULL, 0);
+
+
+ for (n = 0; n < argc; n++) {
+ Jim_Obj *obj = Jim_NewStringObj(interp, argv[n], -1);
+
+ Jim_ListAppendElement(interp, listObj, obj);
+ }
+
+ Jim_SetVariableStr(interp, "argv", listObj);
+ Jim_SetVariableStr(interp, "argc", Jim_NewIntObj(interp, argc));
+}
+
+int main(int argc, char *const argv[])
+{
+ int retcode;
+ Jim_Interp *interp;
+
+ if (argc > 1 && strcmp(argv[1], "--version") == 0) {
+ printf("%d.%d\n", JIM_VERSION / 100, JIM_VERSION % 100);
+ return 0;
+ }
+
+
+ interp = Jim_CreateInterp();
+ Jim_RegisterCoreCommands(interp);
+
+
+ if (Jim_InitStaticExtensions(interp) != JIM_OK) {
+ Jim_MakeErrorMessage(interp);
+ fprintf(stderr, "%s\n", Jim_String(Jim_GetResult(interp)));
+ }
+
+ Jim_SetVariableStrWithStr(interp, "jim_argv0", argv[0]);
+ Jim_SetVariableStrWithStr(interp, JIM_INTERACTIVE, argc == 1 ? "1" : "0");
+ retcode = Jim_initjimshInit(interp);
+
+ if (argc == 1) {
+ if (retcode == JIM_ERR) {
+ Jim_MakeErrorMessage(interp);
+ fprintf(stderr, "%s\n", Jim_String(Jim_GetResult(interp)));
+ }
+ if (retcode != JIM_EXIT) {
+ JimSetArgv(interp, 0, NULL);
+ retcode = Jim_InteractivePrompt(interp);
+ }
+ }
+ else {
+ if (argc > 2 && strcmp(argv[1], "-e") == 0) {
+ JimSetArgv(interp, argc - 3, argv + 3);
+ retcode = Jim_Eval(interp, argv[2]);
+ if (retcode != JIM_ERR) {
+ printf("%s\n", Jim_String(Jim_GetResult(interp)));
+ }
+ }
+ else {
+ Jim_SetVariableStr(interp, "argv0", Jim_NewStringObj(interp, argv[1], -1));
+ JimSetArgv(interp, argc - 2, argv + 2);
+ retcode = Jim_EvalFile(interp, argv[1]);
+ }
+ if (retcode == JIM_ERR) {
+ Jim_MakeErrorMessage(interp);
+ fprintf(stderr, "%s\n", Jim_String(Jim_GetResult(interp)));
+ }
+ }
+ if (retcode == JIM_EXIT) {
+ retcode = Jim_GetExitCode(interp);
+ }
+ else if (retcode == JIM_ERR) {
+ retcode = 1;
+ }
+ else {
+ retcode = 0;
+ }
+ Jim_FreeInterp(interp);
+ return retcode;
+}
+#endif
ADDED autosetup/local.tcl
Index: autosetup/local.tcl
==================================================================
--- autosetup/local.tcl
+++ autosetup/local.tcl
@@ -0,0 +1,30 @@
+# For this project, disable the pager for --help
+set useropts(nopager) 1
+
+# Searches for a usable Tcl (prefer 8.6, 8.5, 8.4) in the given paths
+# Returns a dictionary of the contents of the tclConfig.sh file, or
+# empty if not found
+proc parse-tclconfig-sh {args} {
+ foreach p $args {
+ # Allow pointing directly to the path containing tclConfig.sh
+ if {[file exists $p/tclConfig.sh]} {
+ return [parse-tclconfig-sh-file $p/tclConfig.sh]
+ }
+ # Some systems allow for multiple versions
+ foreach libpath {lib/tcl8.6 lib/tcl8.5 lib/tcl8.4 lib/tcl tcl lib} {
+ if {[file exists $p/$libpath/tclConfig.sh]} {
+ return [parse-tclconfig-sh-file $p/$libpath/tclConfig.sh]
+ }
+ }
+ }
+}
+
+proc parse-tclconfig-sh-file {filename} {
+ foreach line [split [readfile $filename] \n] {
+ if {[regexp {^(TCL_[^=]*)=(.*)$} $line -> name value]} {
+ set value [regsub -all {\$\{.*\}} $value ""]
+ set tclconfig($name) [string trim $value ']
+ }
+ }
+ return [array get tclconfig]
+}
ADDED autosetup/system.tcl
Index: autosetup/system.tcl
==================================================================
--- autosetup/system.tcl
+++ autosetup/system.tcl
@@ -0,0 +1,269 @@
+# Copyright (c) 2010 WorkWare Systems http://www.workware.net.au/
+# All rights reserved
+
+# @synopsis:
+#
+# This module supports common system interrogation and options
+# such as --host, --build, --prefix, and setting srcdir, builddir, and EXEXT.
+#
+# It also support the 'feature' naming convention, where searching
+# for a feature such as sys/type.h defines HAVE_SYS_TYPES_H
+#
+module-options {
+ host:host-alias => {a complete or partial cpu-vendor-opsys for the system where
+ the application will run (defaults to the same value as --build)}
+ build:build-alias => {a complete or partial cpu-vendor-opsys for the system
+ where the application will be built (defaults to the
+ result of running config.guess)}
+ prefix:dir => {the target directory for the build (defaults to /usr/local)}
+
+ # These (hidden) options are supported for autoconf/automake compatibility
+ exec-prefix:
+ bindir:
+ sbindir:
+ includedir:
+ mandir:
+ infodir:
+ libexecdir:
+ datadir:
+ libdir:
+ sysconfdir:
+ sharedstatedir:
+ localstatedir:
+ maintainer-mode=0
+ dependency-tracking=0
+}
+
+# Returns 1 if exists, or 0 if not
+#
+proc check-feature {name code} {
+ msg-checking "Checking for $name..."
+ set r [uplevel 1 $code]
+ define-feature $name $r
+ if {$r} {
+ msg-result "ok"
+ } else {
+ msg-result "not found"
+ }
+ return $r
+}
+
+# @have-feature name ?default=0?
+#
+# Returns the value of the feature if defined, or $default if not.
+# See 'feature-define-name' for how the feature name
+# is translated into the define name.
+#
+proc have-feature {name {default 0}} {
+ get-define [feature-define-name $name] $default
+}
+
+# @define-feature name ?value=1?
+#
+# Sets the feature 'define' to the given value.
+# See 'feature-define-name' for how the feature name
+# is translated into the define name.
+#
+proc define-feature {name {value 1}} {
+ define [feature-define-name $name] $value
+}
+
+# @feature-checked name
+#
+# Returns 1 if the feature has been checked, whether true or not
+#
+proc feature-checked {name} {
+ is-defined [feature-define-name $name]
+}
+
+# @feature-define-name name ?prefix=HAVE_?
+#
+# Converts a name to the corresponding define,
+# e.g. sys/stat.h becomes HAVE_SYS_STAT_H.
+#
+# Converts * to P and all non-alphanumeric to underscore.
+#
+proc feature-define-name {name {prefix HAVE_}} {
+ string toupper $prefix[regsub -all {[^a-zA-Z0-9]} [regsub -all {[*]} $name p] _]
+}
+
+# If $file doesn't exist, or it's contents are different than $buf,
+# the file is written and $script is executed.
+# Otherwise a "file is unchanged" message is displayed.
+proc write-if-changed {file buf {script {}}} {
+ set old [readfile $file ""]
+ if {$old eq $buf && [file exists $file]} {
+ msg-result "$file is unchanged"
+ } else {
+ writefile $file $buf\n
+ uplevel 1 $script
+ }
+}
+
+# @make-template template ?outfile?
+#
+# Reads the input file /$template and writes the output file $outfile.
+# If $outfile is blank/omitted, $template should end with ".in" which
+# is removed to create the output file name.
+#
+# Each pattern of the form @define@ is replaced the the corresponding
+# define, if it exists, or left unchanged if not.
+#
+# The special value @srcdir@ is subsituted with the relative
+# path to the source directory from the directory where the output
+# file is created. Use @top_srcdir@ for the absolute path.
+#
+# Conditional sections may be specified as follows:
+## @if name == value
+## lines
+## @else
+## lines
+## @endif
+#
+# Where 'name' is a defined variable name and @else is optional.
+# If the expression does not match, all lines through '@endif' are ignored.
+#
+# The alternative forms may also be used:
+## @if name
+## @if name != value
+#
+# Where the first form is true if the variable is defined, but not empty or 0
+#
+# Currently these expressions can't be nested.
+#
+proc make-template {template {out {}}} {
+ set infile [file join $::autosetup(srcdir) $template]
+
+ if {![file exists $infile]} {
+ user-error "Template $template is missing"
+ }
+
+ # Define this as late as possible
+ define AUTODEPS $::autosetup(deps)
+
+ if {$out eq ""} {
+ if {[file ext $template] ne ".in"} {
+ autosetup-error "make_template $template has no target file and can't guess"
+ }
+ set out [file rootname $template]
+ }
+
+ set outdir [file dirname $out]
+
+ # Make sure the directory exists
+ file mkdir $outdir
+
+ # Set up srcdir to be relative to the target dir
+ define srcdir [relative-path [file join $::autosetup(srcdir) $outdir] $outdir]
+
+ set mapping {}
+ foreach {n v} [array get ::define] {
+ lappend mapping @$n@ $v
+ }
+ set result {}
+ foreach line [split [readfile $infile] \n] {
+ if {[info exists cond]} {
+ set l [string trimright $line]
+ if {$l eq "@endif"} {
+ unset cond
+ continue
+ }
+ if {$l eq "@else"} {
+ set cond [expr {!$cond}]
+ continue
+ }
+ if {$cond} {
+ lappend result $line
+ }
+ continue
+ }
+ if {[regexp {^@if\s+(\w+)(.*)} $line -> name expression]} {
+ lassign $expression equal value
+ set varval [get-define $name ""]
+ if {$equal eq ""} {
+ set cond [expr {$varval ni {"" 0}}]
+ } else {
+ set cond [expr {$varval eq $value}]
+ if {$equal ne "=="} {
+ set cond [expr {!$cond}]
+ }
+ }
+ continue
+ }
+ lappend result $line
+ }
+ writefile $out [string map $mapping [join $result \n]]\n
+
+ msg-result "Created [relative-path $out] from [relative-path $template]"
+}
+
+# build/host tuples and cross-compilation prefix
+set build [opt-val build]
+define build_alias $build
+if {$build eq ""} {
+ define build [config_guess]
+} else {
+ define build [config_sub $build]
+}
+
+set host [opt-val host]
+define host_alias $host
+if {$host eq ""} {
+ define host [get-define build]
+ set cross ""
+} else {
+ define host [config_sub $host]
+ set cross $host-
+}
+define cross [get-env CROSS $cross]
+
+# Do "define defaultprefix myvalue" to set the default prefix *before* the first "use"
+set prefix [opt-val prefix [get-define defaultprefix /usr/local]]
+
+# These are for compatibility with autoconf
+define target [get-define host]
+define prefix $prefix
+define builddir $autosetup(builddir)
+define srcdir $autosetup(srcdir)
+# Allow this to come from the environment
+define top_srcdir [get-env top_srcdir [get-define srcdir]]
+
+# autoconf supports all of these
+set exec_prefix [opt-val exec-prefix $prefix]
+define exec_prefix $exec_prefix
+foreach {name defpath} {
+ bindir /bin
+ sbindir /sbin
+ libexecdir /libexec
+ libdir /lib
+} {
+ define $name [opt-val $name $exec_prefix$defpath]
+}
+foreach {name defpath} {
+ datadir /share
+ sysconfdir /etc
+ sharedstatedir /com
+ localstatedir /var
+ infodir /share/info
+ mandir /share/man
+ includedir /include
+} {
+ define $name [opt-val $name $prefix$defpath]
+}
+
+define SHELL [get-env SHELL [find-an-executable sh bash ksh]]
+
+# Windows vs. non-Windows
+switch -glob -- [get-define host] {
+ *-*-ming* - *-*-cygwin - *-*-msys {
+ define-feature windows
+ define EXEEXT .exe
+ }
+ default {
+ define EXEEXT ""
+ }
+}
+
+# Display
+msg-result "Host System...[get-define host]"
+msg-result "Build System...[get-define build]"
ADDED autosetup/test-tclsh
Index: autosetup/test-tclsh
==================================================================
--- autosetup/test-tclsh
+++ autosetup/test-tclsh
@@ -0,0 +1,20 @@
+# A small Tcl script to verify that the chosen
+# interpreter works. Sometimes we might e.g. pick up
+# an interpreter for a different arch.
+# Outputs the full path to the interpreter
+
+if {[catch {info version} version] == 0} {
+ # This is Jim Tcl
+ if {$version >= 0.72} {
+ # Ensure that regexp works
+ regexp (a.*?) a
+ puts [info nameofexecutable]
+ exit 0
+ }
+} elseif {[catch {info tclversion} version] == 0} {
+ if {$version >= 8.5 && ![string match 8.5a* [info patchlevel]]} {
+ puts [info nameofexecutable]
+ exit 0
+ }
+}
+exit 1
DELETED ci_cvs.txt
Index: ci_cvs.txt
==================================================================
--- ci_cvs.txt
+++ ci_cvs.txt
@@ -1,192 +0,0 @@
-===============================================================================
-
-First experimental codes ...
-
-tools/import-cvs.tcl
-tools/lib/rcsparser.tcl
-
-No actual import, right now only working on getting csets right. The
-code uses CVSROOT/history as foundation, and augments that with data
-from the individual RCS files (commit messages).
-
-Statistics of a run ...
- 3516 csets.
-
- 1545 breaks on user change
- 558 breaks on file duplicate
- 13 breaks on branch/trunk change
- 1402 breaks on commit message change
-
-Time statistics ...
- 3297 were processed in <= 1 seconds (93.77%)
- 217 were processed in between 2 seconds and 14 minutes.
- 1 was processed in ~41 minutes
- 1 was processed in ~22 hours
-
-Time fuzz - Differences between csets range from 0 seconds to 66
-days. Needs stats analysis to see if there is an obvious break. Even
-so the times within csets and between csets overlap a great deal,
-making time a bad criterium for cset separation, IMHO.
-
-Leaving that topic, back to the current cset separator ...
-
-It has a problem:
- The history file is not starting at the root!
-
-Examples:
- The first three changesets are
-
- =============================/user
- M {Wed Nov 22 09:28:49 AM PST 2000} ericm 1.4 tcllib/modules/ftpd/ChangeLog
- M {Wed Nov 22 09:28:49 AM PST 2000} ericm 1.7 tcllib/modules/ftpd/ftpd.tcl
- files: 2
- delta: 0
- range: 0 seconds
- =============================/cmsg
- M {Wed Nov 29 02:14:33 PM PST 2000} ericm 1.3 tcllib/aclocal.m4
- files: 1
- delta:
- range: 0 seconds
- =============================/cmsg
- M {Sun Feb 04 12:28:35 AM PST 2001} ericm 1.9 tcllib/modules/mime/ChangeLog
- M {Sun Feb 04 12:28:35 AM PST 2001} ericm 1.12 tcllib/modules/mime/mime.tcl
- files: 2
- delta: 0
- range: 0 seconds
-
-All csets modify files which already have several revisions. We have
-no csets from before that in the history, but these csets are in the
-RCS files.
-
-I wonder, is SF maybe removing old entries from the history when it
-grows too large ?
-
-This also affects incremental import ... I cannot assume that the
-history always grows. It may shrink ... I cannot keep an offset, will
-have to record the time of the last entry, or even the full entry
-processed last, to allow me to skip ahead to anything not known yet.
-
-I might have to try to implement the algorithm outlined below,
-matching the revision trees of the individual RCS files to each other
-to form the global tree of revisions. Maybe we can use the history to
-help in the matchup, for the parts where we do have it.
-
-Wait. This might be easier ... Take the delta information from the RCS
-files and generate a fake history ... Actually, this might even allow
-us to create a total history ... No, not quite, the merge entries the
-actual history may contain will be missing. These we can mix in from
-the actual history, as much as we have.
-
-Still, lets try that, a fake history, and then run this script on it
-to see if/where are differences.
-
-===============================================================================
-
-
-Notes about CVS import, regarding CVS.
-
-- Problem: CVS does not really track changesets, but only individual
- revisions of files. To recover changesets it is necessary to look at
- author, branch, timestamp information, and the commit messages. Even
- so this is only heuristic, not foolproof.
-
- Existing tool: cvsps.
-
- Processes the output of 'cvs log' to recover changesets. Problem:
- Sees only a linear list of revisions, does not see branchpoints,
- etc. Cannot use the tree structure to help in making the decisions.
-
-- Problem: CVS does not track merge-points at all. Recovery through
- heuristics is brittle at best, looking for keywords in commit
- messages which might indicate that a branch was merged with some
- other.
-
-
-Ideas regarding an algorithm to recover changesets.
-
-Key feature: Uses the per-file revision trees to help in uncovering
-the underlying changesets and global revision tree G.
-
-The per-file revision tree for a file X is in essence the global
-revision tree with all nodes not pertaining to X removed from it. In
-the reverse this allows us to built up the global revision tree from
-the per-file trees by matching nodes to each other and extending.
-
-Start with the per file revision tree of a single file as initial
-approximation of the global tree. All nodes of this tree refer to the
-revision of the file belonging to it, and through that the file
-itself. At each step the global tree contains the nodes for a finite
-set of files, and all nodes in the tree refer to revisions of all
-files in the set, making the mapping total.
-
-To add a file X to the tree take the per-file revision tree R and
-performs the following actions:
-
-- For each node N in R use the tuple
- to identify a set of nodes in G which may match N. Use the timestamp
- to locate the node nearest in time.
-
-- This process will leave nodes in N unmapped. If there are unmapped
- nodes which have no neighbouring mapped nodes we have to
- abort.
-
- Otherwise take the nodes which have mapped neighbours. Trace the
- edges and see which of these nodes are connected in the local
- tree. Then look at the identified neighbours and trace their
- connections.
-
- If two global nodes have a direct connection, but a multi-edge
- connection in the local tree insert global nodes mapping to the
- local nodes and map them together. This expands the global tree to
- hold the revisions added by the new file.
-
- Otherwise, both sides have multi-edge connections then abort. This
- looks like a merge of two different branches, but there are no such
- in CVS ... Wait ... sort the nodes over time and fit the new nodes
- in between the other nodes, per the timestamps. We have overlapping
- / alternating changes to one file and others.
-
- A last possibility is that a node is only connected to a mapped
- parent. This may be a new branch, or again an alternating change on
- the given line. Symbols on the revisions will help to map this.
-
-- We now have an extended global tree which incorporates the revisions
- of the new file. However new nodes will refer only to the new file,
- and old nodes may not refer to the new file. This has to be fixed,
- as all nodes have to refer to all files.
-
- Run over the tree and look at each parent/child pair. If a file is
- not referenced in the child, but the parent, then copy a reference
- to the file revision on the parent forward to the child. This
- signals that the file did not change in the given revision.
-
-- After all files have been integrated in this manner we have global
- revision tree capturing all changesets, including the unchanged
- files per changeset.
-
-
-This algorithm has to be refined to also take Attic/ files into
-account.
-
--------------------------------------------------------------------------
-
-Two archive files mapping to the same user file. How are they
-interleaved ?
-
-(a) sqlite/src/os_unix.h,v
-(b) sqlite/src/Attic/os_unix.h,v
-
-Problem: Max version of (a) is 1.9
- Max version of (b) is 1.11
- cvs co 1.10 -> no longer in the repository.
-
-This seems to indicate that the non-Attic file is relevant.
-
---------------------------------------------------------------------------
-
-tcllib - more problems - tklib/pie.tcl,v -
-
-invalid change text in
-/home/aku/Projects/Tcl/Fossil/Devel/Examples/cvs-tcllib/tklib/modules/tkpiechart/pie.tcl,v
-
-Possibly braces ?
DELETED ci_fossil.txt
Index: ci_fossil.txt
==================================================================
--- ci_fossil.txt
+++ ci_fossil.txt
@@ -1,127 +0,0 @@
-
-To perform CVS imports for fossil we need at least the ability to
-parse CVS files, i.e. RCS files, with slight differences.
-
-For the general architecture of the import facility we have two major
-paths to choose between.
-
-One is to use an external tool which processes a cvs repository and
-drives fossil through its CLI to insert the found changesets.
-
-The other is to integrate the whole facility into the fossil binary
-itself.
-
-I dislike the second choice. It may be faster, as the implementation
-can use all internal functionality of fossil to perform the import,
-however it will also bloat the binary with functionality not needed
-most of the time. Which becomes especially obvious if more importers
-are to be written, like for monotone, bazaar, mercurial, bitkeeper,
-git, SVN, Arc, etc. Keeping all this out of the core fossil binary is
-IMHO more beneficial in the long term, also from a maintenance point
-of view. The tools can evolve separately. Especially important for CVS
-as it will have to deal with lots of broken repositories, all
-different.
-
-However, nothing speaks against looking for common parts in all
-possible import tools, and having these in the fossil core, as a
-general backend all importer may use. Something like that has already
-been proposed: The deconstruct|reconstruct methods. For us, actually
-only reconstruct is important. Taking an unordered collection of files
-(data, and manifests) it generates a proper fossil repository. With
-that method implemented all import tools only have to generate the
-necessary collection and then leave the main work of filling the
-database to fossil itself.
-
-The disadvantage of this method is however that it will gobble up a
-lot of temporary space in the filesystem to hold all unique revisions
-of all files in their expanded form.
-
-It might be worthwhile to consider an extension of 'reconstruct' which
-is able to incrementally add a set of files to an existing fossil
-repository already containing revisions. In that case the import tool
-can be changed to incrementally generate the collection for a
-particular revision, import it, and iterate over all revisions in the
-origin repository. This is of course also dependent on the origin
-repository itself, how well it supports such incremental export.
-
-This also leads to a possible method for performing the import using
-only existing functionality ('reconstruct' has not been implemented
-yet). Instead generating an unordered collection for each revision
-generate a properly setup workspace, simply commit it. This will
-require use of rm, add and update methods as well, to remove old and
-enter new files, and point the fossil repository to the correct parent
-revision from the new revision is derived.
-
-The relative efficiency (in time) of these incremental methods versus
-importing a complete collection of files encoding the entire origin
-repository however is not clear.
-
-----------------------------------
-
-reconstruct
-
-The core logic for handling content is in the file "content.c", in
-particular the functions 'content_put' and 'content_deltify'. One of
-the main users of these functions is in the file "checkin.c", see the
-function 'commit_cmd'.
-
-The logic is clear. The new modified files are simply stored without
-delta-compression, using 'content_put'. And should fosssil have an id
-for the _previous_ revision of the committed file it uses
-'content_deltify' to convert the already stored data for that revision
-into a delta with the just stored new revision as origin.
-
-In other words, fossil produces reverse deltas, with leaf revisions
-stored just zip-compressed (plain) and older revisions using both zip-
-and delta-compression.
-
-Of note is that the underlying logic in 'content_deltify' gives up on
-delta compression if the involved files are either not large enough,
-or if the achieved compression factor was not high enough. In that
-case the old revision of the file is left plain.
-
-The scheme can thus be called a 'truncated reverse delta'.
-
-The manifest is created and committed after the modified files. It
-uses the same logic as for the regular files. The new leaf is stored
-plain, and storage of the parent manifest is modified to be a delta
-with the current as origin.
-
-Further note that for a checkin of a merge result oonly the primary
-parent is modified in that way. The secondary parent, the one merged
-into the current revision is not touched. I.e. from the storage layer
-point of view this revision is still a leaf and the data is kept
-stored plain, not delta-compressed.
-
-
-
-Now the "reconstruct" can be done like so:
-
-- Scan the files in the indicated directory, and look for a manifest.
-
-- When the manifest has been found parse its contents and follow the
- chain of parent links to locate the root manifest (no parent).
-
-- Import the files referenced by the root manifest, then the manifest
- itself. This can be done using a modified form of the 'commit_cmd'
- which does not have to construct a manifest on its own from vfile,
- vmerge, etc.
-
-- After that recursively apply the import of the previous step to the
- children of the root, and so on.
-
-For an incremental "reconstruct" the collection of files would not be
-a single tree with a root, but a forest, and the roots to look for are
-not manifests without parent, but with a parent which is already
-present in the repository. After one such root has been found and
-processed the unprocessed files have to be searched further for more
-roots, and only if no such are found anymore will the remaining files
-be considered as superfluous.
-
-We can use the functions in "manifest.c" for the parsing and following
-the parental chain.
-
-Hm. But we have no direct child information. So the above algorithm
-has to be modified, we have to scan all manifests before we start
-importing, and we have to create a reverse index, from manifest to
-children so that we can perform the import from root to leaves.
ADDED compat/zlib/CMakeLists.txt
Index: compat/zlib/CMakeLists.txt
==================================================================
--- compat/zlib/CMakeLists.txt
+++ compat/zlib/CMakeLists.txt
@@ -0,0 +1,249 @@
+cmake_minimum_required(VERSION 2.4.4)
+set(CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS ON)
+
+project(zlib C)
+
+set(VERSION "1.2.8")
+
+option(ASM686 "Enable building i686 assembly implementation")
+option(AMD64 "Enable building amd64 assembly implementation")
+
+set(INSTALL_BIN_DIR "${CMAKE_INSTALL_PREFIX}/bin" CACHE PATH "Installation directory for executables")
+set(INSTALL_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib" CACHE PATH "Installation directory for libraries")
+set(INSTALL_INC_DIR "${CMAKE_INSTALL_PREFIX}/include" CACHE PATH "Installation directory for headers")
+set(INSTALL_MAN_DIR "${CMAKE_INSTALL_PREFIX}/share/man" CACHE PATH "Installation directory for manual pages")
+set(INSTALL_PKGCONFIG_DIR "${CMAKE_INSTALL_PREFIX}/share/pkgconfig" CACHE PATH "Installation directory for pkgconfig (.pc) files")
+
+include(CheckTypeSize)
+include(CheckFunctionExists)
+include(CheckIncludeFile)
+include(CheckCSourceCompiles)
+enable_testing()
+
+check_include_file(sys/types.h HAVE_SYS_TYPES_H)
+check_include_file(stdint.h HAVE_STDINT_H)
+check_include_file(stddef.h HAVE_STDDEF_H)
+
+#
+# Check to see if we have large file support
+#
+set(CMAKE_REQUIRED_DEFINITIONS -D_LARGEFILE64_SOURCE=1)
+# We add these other definitions here because CheckTypeSize.cmake
+# in CMake 2.4.x does not automatically do so and we want
+# compatibility with CMake 2.4.x.
+if(HAVE_SYS_TYPES_H)
+ list(APPEND CMAKE_REQUIRED_DEFINITIONS -DHAVE_SYS_TYPES_H)
+endif()
+if(HAVE_STDINT_H)
+ list(APPEND CMAKE_REQUIRED_DEFINITIONS -DHAVE_STDINT_H)
+endif()
+if(HAVE_STDDEF_H)
+ list(APPEND CMAKE_REQUIRED_DEFINITIONS -DHAVE_STDDEF_H)
+endif()
+check_type_size(off64_t OFF64_T)
+if(HAVE_OFF64_T)
+ add_definitions(-D_LARGEFILE64_SOURCE=1)
+endif()
+set(CMAKE_REQUIRED_DEFINITIONS) # clear variable
+
+#
+# Check for fseeko
+#
+check_function_exists(fseeko HAVE_FSEEKO)
+if(NOT HAVE_FSEEKO)
+ add_definitions(-DNO_FSEEKO)
+endif()
+
+#
+# Check for unistd.h
+#
+check_include_file(unistd.h Z_HAVE_UNISTD_H)
+
+if(MSVC)
+ set(CMAKE_DEBUG_POSTFIX "d")
+ add_definitions(-D_CRT_SECURE_NO_DEPRECATE)
+ add_definitions(-D_CRT_NONSTDC_NO_DEPRECATE)
+ include_directories(${CMAKE_CURRENT_SOURCE_DIR})
+endif()
+
+if(NOT CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_CURRENT_BINARY_DIR)
+ # If we're doing an out of source build and the user has a zconf.h
+ # in their source tree...
+ if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/zconf.h)
+ message(STATUS "Renaming")
+ message(STATUS " ${CMAKE_CURRENT_SOURCE_DIR}/zconf.h")
+ message(STATUS "to 'zconf.h.included' because this file is included with zlib")
+ message(STATUS "but CMake generates it automatically in the build directory.")
+ file(RENAME ${CMAKE_CURRENT_SOURCE_DIR}/zconf.h ${CMAKE_CURRENT_SOURCE_DIR}/zconf.h.included)
+ endif()
+endif()
+
+set(ZLIB_PC ${CMAKE_CURRENT_BINARY_DIR}/zlib.pc)
+configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/zlib.pc.cmakein
+ ${ZLIB_PC} @ONLY)
+configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/zconf.h.cmakein
+ ${CMAKE_CURRENT_BINARY_DIR}/zconf.h @ONLY)
+include_directories(${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_SOURCE_DIR})
+
+
+#============================================================================
+# zlib
+#============================================================================
+
+set(ZLIB_PUBLIC_HDRS
+ ${CMAKE_CURRENT_BINARY_DIR}/zconf.h
+ zlib.h
+)
+set(ZLIB_PRIVATE_HDRS
+ crc32.h
+ deflate.h
+ gzguts.h
+ inffast.h
+ inffixed.h
+ inflate.h
+ inftrees.h
+ trees.h
+ zutil.h
+)
+set(ZLIB_SRCS
+ adler32.c
+ compress.c
+ crc32.c
+ deflate.c
+ gzclose.c
+ gzlib.c
+ gzread.c
+ gzwrite.c
+ inflate.c
+ infback.c
+ inftrees.c
+ inffast.c
+ trees.c
+ uncompr.c
+ zutil.c
+)
+
+if(NOT MINGW)
+ set(ZLIB_DLL_SRCS
+ win32/zlib1.rc # If present will override custom build rule below.
+ )
+endif()
+
+if(CMAKE_COMPILER_IS_GNUCC)
+ if(ASM686)
+ set(ZLIB_ASMS contrib/asm686/match.S)
+ elseif (AMD64)
+ set(ZLIB_ASMS contrib/amd64/amd64-match.S)
+ endif ()
+
+ if(ZLIB_ASMS)
+ add_definitions(-DASMV)
+ set_source_files_properties(${ZLIB_ASMS} PROPERTIES LANGUAGE C COMPILE_FLAGS -DNO_UNDERLINE)
+ endif()
+endif()
+
+if(MSVC)
+ if(ASM686)
+ ENABLE_LANGUAGE(ASM_MASM)
+ set(ZLIB_ASMS
+ contrib/masmx86/inffas32.asm
+ contrib/masmx86/match686.asm
+ )
+ elseif (AMD64)
+ ENABLE_LANGUAGE(ASM_MASM)
+ set(ZLIB_ASMS
+ contrib/masmx64/gvmat64.asm
+ contrib/masmx64/inffasx64.asm
+ )
+ endif()
+
+ if(ZLIB_ASMS)
+ add_definitions(-DASMV -DASMINF)
+ endif()
+endif()
+
+# parse the full version number from zlib.h and include in ZLIB_FULL_VERSION
+file(READ ${CMAKE_CURRENT_SOURCE_DIR}/zlib.h _zlib_h_contents)
+string(REGEX REPLACE ".*#define[ \t]+ZLIB_VERSION[ \t]+\"([-0-9A-Za-z.]+)\".*"
+ "\\1" ZLIB_FULL_VERSION ${_zlib_h_contents})
+
+if(MINGW)
+ # This gets us DLL resource information when compiling on MinGW.
+ if(NOT CMAKE_RC_COMPILER)
+ set(CMAKE_RC_COMPILER windres.exe)
+ endif()
+
+ add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/zlib1rc.obj
+ COMMAND ${CMAKE_RC_COMPILER}
+ -D GCC_WINDRES
+ -I ${CMAKE_CURRENT_SOURCE_DIR}
+ -I ${CMAKE_CURRENT_BINARY_DIR}
+ -o ${CMAKE_CURRENT_BINARY_DIR}/zlib1rc.obj
+ -i ${CMAKE_CURRENT_SOURCE_DIR}/win32/zlib1.rc)
+ set(ZLIB_DLL_SRCS ${CMAKE_CURRENT_BINARY_DIR}/zlib1rc.obj)
+endif(MINGW)
+
+add_library(zlib SHARED ${ZLIB_SRCS} ${ZLIB_ASMS} ${ZLIB_DLL_SRCS} ${ZLIB_PUBLIC_HDRS} ${ZLIB_PRIVATE_HDRS})
+add_library(zlibstatic STATIC ${ZLIB_SRCS} ${ZLIB_ASMS} ${ZLIB_PUBLIC_HDRS} ${ZLIB_PRIVATE_HDRS})
+set_target_properties(zlib PROPERTIES DEFINE_SYMBOL ZLIB_DLL)
+set_target_properties(zlib PROPERTIES SOVERSION 1)
+
+if(NOT CYGWIN)
+ # This property causes shared libraries on Linux to have the full version
+ # encoded into their final filename. We disable this on Cygwin because
+ # it causes cygz-${ZLIB_FULL_VERSION}.dll to be created when cygz.dll
+ # seems to be the default.
+ #
+ # This has no effect with MSVC, on that platform the version info for
+ # the DLL comes from the resource file win32/zlib1.rc
+ set_target_properties(zlib PROPERTIES VERSION ${ZLIB_FULL_VERSION})
+endif()
+
+if(UNIX)
+ # On unix-like platforms the library is almost always called libz
+ set_target_properties(zlib zlibstatic PROPERTIES OUTPUT_NAME z)
+ if(NOT APPLE)
+ set_target_properties(zlib PROPERTIES LINK_FLAGS "-Wl,--version-script,\"${CMAKE_CURRENT_SOURCE_DIR}/zlib.map\"")
+ endif()
+elseif(BUILD_SHARED_LIBS AND WIN32)
+ # Creates zlib1.dll when building shared library version
+ set_target_properties(zlib PROPERTIES SUFFIX "1.dll")
+endif()
+
+if(NOT SKIP_INSTALL_LIBRARIES AND NOT SKIP_INSTALL_ALL )
+ install(TARGETS zlib zlibstatic
+ RUNTIME DESTINATION "${INSTALL_BIN_DIR}"
+ ARCHIVE DESTINATION "${INSTALL_LIB_DIR}"
+ LIBRARY DESTINATION "${INSTALL_LIB_DIR}" )
+endif()
+if(NOT SKIP_INSTALL_HEADERS AND NOT SKIP_INSTALL_ALL )
+ install(FILES ${ZLIB_PUBLIC_HDRS} DESTINATION "${INSTALL_INC_DIR}")
+endif()
+if(NOT SKIP_INSTALL_FILES AND NOT SKIP_INSTALL_ALL )
+ install(FILES zlib.3 DESTINATION "${INSTALL_MAN_DIR}/man3")
+endif()
+if(NOT SKIP_INSTALL_FILES AND NOT SKIP_INSTALL_ALL )
+ install(FILES ${ZLIB_PC} DESTINATION "${INSTALL_PKGCONFIG_DIR}")
+endif()
+
+#============================================================================
+# Example binaries
+#============================================================================
+
+add_executable(example test/example.c)
+target_link_libraries(example zlib)
+add_test(example example)
+
+add_executable(minigzip test/minigzip.c)
+target_link_libraries(minigzip zlib)
+
+if(HAVE_OFF64_T)
+ add_executable(example64 test/example.c)
+ target_link_libraries(example64 zlib)
+ set_target_properties(example64 PROPERTIES COMPILE_FLAGS "-D_FILE_OFFSET_BITS=64")
+ add_test(example64 example64)
+
+ add_executable(minigzip64 test/minigzip.c)
+ target_link_libraries(minigzip64 zlib)
+ set_target_properties(minigzip64 PROPERTIES COMPILE_FLAGS "-D_FILE_OFFSET_BITS=64")
+endif()
ADDED compat/zlib/ChangeLog
Index: compat/zlib/ChangeLog
==================================================================
--- compat/zlib/ChangeLog
+++ compat/zlib/ChangeLog
@@ -0,0 +1,1472 @@
+
+ ChangeLog file for zlib
+
+Changes in 1.2.8 (28 Apr 2013)
+- Update contrib/minizip/iowin32.c for Windows RT [Vollant]
+- Do not force Z_CONST for C++
+- Clean up contrib/vstudio [Ro§]
+- Correct spelling error in zlib.h
+- Fix mixed line endings in contrib/vstudio
+
+Changes in 1.2.7.3 (13 Apr 2013)
+- Fix version numbers and DLL names in contrib/vstudio/*/zlib.rc
+
+Changes in 1.2.7.2 (13 Apr 2013)
+- Change check for a four-byte type back to hexadecimal
+- Fix typo in win32/Makefile.msc
+- Add casts in gzwrite.c for pointer differences
+
+Changes in 1.2.7.1 (24 Mar 2013)
+- Replace use of unsafe string functions with snprintf if available
+- Avoid including stddef.h on Windows for Z_SOLO compile [Niessink]
+- Fix gzgetc undefine when Z_PREFIX set [Turk]
+- Eliminate use of mktemp in Makefile (not always available)
+- Fix bug in 'F' mode for gzopen()
+- Add inflateGetDictionary() function
+- Correct comment in deflate.h
+- Use _snprintf for snprintf in Microsoft C
+- On Darwin, only use /usr/bin/libtool if libtool is not Apple
+- Delete "--version" file if created by "ar --version" [Richard G.]
+- Fix configure check for veracity of compiler error return codes
+- Fix CMake compilation of static lib for MSVC2010 x64
+- Remove unused variable in infback9.c
+- Fix argument checks in gzlog_compress() and gzlog_write()
+- Clean up the usage of z_const and respect const usage within zlib
+- Clean up examples/gzlog.[ch] comparisons of different types
+- Avoid shift equal to bits in type (caused endless loop)
+- Fix unintialized value bug in gzputc() introduced by const patches
+- Fix memory allocation error in examples/zran.c [Nor]
+- Fix bug where gzopen(), gzclose() would write an empty file
+- Fix bug in gzclose() when gzwrite() runs out of memory
+- Check for input buffer malloc failure in examples/gzappend.c
+- Add note to contrib/blast to use binary mode in stdio
+- Fix comparisons of differently signed integers in contrib/blast
+- Check for invalid code length codes in contrib/puff
+- Fix serious but very rare decompression bug in inftrees.c
+- Update inflateBack() comments, since inflate() can be faster
+- Use underscored I/O function names for WINAPI_FAMILY
+- Add _tr_flush_bits to the external symbols prefixed by --zprefix
+- Add contrib/vstudio/vc10 pre-build step for static only
+- Quote --version-script argument in CMakeLists.txt
+- Don't specify --version-script on Apple platforms in CMakeLists.txt
+- Fix casting error in contrib/testzlib/testzlib.c
+- Fix types in contrib/minizip to match result of get_crc_table()
+- Simplify contrib/vstudio/vc10 with 'd' suffix
+- Add TOP support to win32/Makefile.msc
+- Suport i686 and amd64 assembler builds in CMakeLists.txt
+- Fix typos in the use of _LARGEFILE64_SOURCE in zconf.h
+- Add vc11 and vc12 build files to contrib/vstudio
+- Add gzvprintf() as an undocumented function in zlib
+- Fix configure for Sun shell
+- Remove runtime check in configure for four-byte integer type
+- Add casts and consts to ease user conversion to C++
+- Add man pages for minizip and miniunzip
+- In Makefile uninstall, don't rm if preceding cd fails
+- Do not return Z_BUF_ERROR if deflateParam() has nothing to write
+
+Changes in 1.2.7 (2 May 2012)
+- Replace use of memmove() with a simple copy for portability
+- Test for existence of strerror
+- Restore gzgetc_ for backward compatibility with 1.2.6
+- Fix build with non-GNU make on Solaris
+- Require gcc 4.0 or later on Mac OS X to use the hidden attribute
+- Include unistd.h for Watcom C
+- Use __WATCOMC__ instead of __WATCOM__
+- Do not use the visibility attribute if NO_VIZ defined
+- Improve the detection of no hidden visibility attribute
+- Avoid using __int64 for gcc or solo compilation
+- Cast to char * in gzprintf to avoid warnings [Zinser]
+- Fix make_vms.com for VAX [Zinser]
+- Don't use library or built-in byte swaps
+- Simplify test and use of gcc hidden attribute
+- Fix bug in gzclose_w() when gzwrite() fails to allocate memory
+- Add "x" (O_EXCL) and "e" (O_CLOEXEC) modes support to gzopen()
+- Fix bug in test/minigzip.c for configure --solo
+- Fix contrib/vstudio project link errors [Mohanathas]
+- Add ability to choose the builder in make_vms.com [Schweda]
+- Add DESTDIR support to mingw32 win32/Makefile.gcc
+- Fix comments in win32/Makefile.gcc for proper usage
+- Allow overriding the default install locations for cmake
+- Generate and install the pkg-config file with cmake
+- Build both a static and a shared version of zlib with cmake
+- Include version symbols for cmake builds
+- If using cmake with MSVC, add the source directory to the includes
+- Remove unneeded EXTRA_CFLAGS from win32/Makefile.gcc [Truta]
+- Move obsolete emx makefile to old [Truta]
+- Allow the use of -Wundef when compiling or using zlib
+- Avoid the use of the -u option with mktemp
+- Improve inflate() documentation on the use of Z_FINISH
+- Recognize clang as gcc
+- Add gzopen_w() in Windows for wide character path names
+- Rename zconf.h in CMakeLists.txt to move it out of the way
+- Add source directory in CMakeLists.txt for building examples
+- Look in build directory for zlib.pc in CMakeLists.txt
+- Remove gzflags from zlibvc.def in vc9 and vc10
+- Fix contrib/minizip compilation in the MinGW environment
+- Update ./configure for Solaris, support --64 [Mooney]
+- Remove -R. from Solaris shared build (possible security issue)
+- Avoid race condition for parallel make (-j) running example
+- Fix type mismatch between get_crc_table() and crc_table
+- Fix parsing of version with "-" in CMakeLists.txt [Snider, Ziegler]
+- Fix the path to zlib.map in CMakeLists.txt
+- Force the native libtool in Mac OS X to avoid GNU libtool [Beebe]
+- Add instructions to win32/Makefile.gcc for shared install [Torri]
+
+Changes in 1.2.6.1 (12 Feb 2012)
+- Avoid the use of the Objective-C reserved name "id"
+- Include io.h in gzguts.h for Microsoft compilers
+- Fix problem with ./configure --prefix and gzgetc macro
+- Include gz_header definition when compiling zlib solo
+- Put gzflags() functionality back in zutil.c
+- Avoid library header include in crc32.c for Z_SOLO
+- Use name in GCC_CLASSIC as C compiler for coverage testing, if set
+- Minor cleanup in contrib/minizip/zip.c [Vollant]
+- Update make_vms.com [Zinser]
+- Remove unnecessary gzgetc_ function
+- Use optimized byte swap operations for Microsoft and GNU [Snyder]
+- Fix minor typo in zlib.h comments [Rzesniowiecki]
+
+Changes in 1.2.6 (29 Jan 2012)
+- Update the Pascal interface in contrib/pascal
+- Fix function numbers for gzgetc_ in zlibvc.def files
+- Fix configure.ac for contrib/minizip [Schiffer]
+- Fix large-entry detection in minizip on 64-bit systems [Schiffer]
+- Have ./configure use the compiler return code for error indication
+- Fix CMakeLists.txt for cross compilation [McClure]
+- Fix contrib/minizip/zip.c for 64-bit architectures [Dalsnes]
+- Fix compilation of contrib/minizip on FreeBSD [Marquez]
+- Correct suggested usages in win32/Makefile.msc [Shachar, Horvath]
+- Include io.h for Turbo C / Borland C on all platforms [Truta]
+- Make version explicit in contrib/minizip/configure.ac [Bosmans]
+- Avoid warning for no encryption in contrib/minizip/zip.c [Vollant]
+- Minor cleanup up contrib/minizip/unzip.c [Vollant]
+- Fix bug when compiling minizip with C++ [Vollant]
+- Protect for long name and extra fields in contrib/minizip [Vollant]
+- Avoid some warnings in contrib/minizip [Vollant]
+- Add -I../.. -L../.. to CFLAGS for minizip and miniunzip
+- Add missing libs to minizip linker command
+- Add support for VPATH builds in contrib/minizip
+- Add an --enable-demos option to contrib/minizip/configure
+- Add the generation of configure.log by ./configure
+- Exit when required parameters not provided to win32/Makefile.gcc
+- Have gzputc return the character written instead of the argument
+- Use the -m option on ldconfig for BSD systems [Tobias]
+- Correct in zlib.map when deflateResetKeep was added
+
+Changes in 1.2.5.3 (15 Jan 2012)
+- Restore gzgetc function for binary compatibility
+- Do not use _lseeki64 under Borland C++ [Truta]
+- Update win32/Makefile.msc to build test/*.c [Truta]
+- Remove old/visualc6 given CMakefile and other alternatives
+- Update AS400 build files and documentation [Monnerat]
+- Update win32/Makefile.gcc to build test/*.c [Truta]
+- Permit stronger flushes after Z_BLOCK flushes
+- Avoid extraneous empty blocks when doing empty flushes
+- Permit Z_NULL arguments to deflatePending
+- Allow deflatePrime() to insert bits in the middle of a stream
+- Remove second empty static block for Z_PARTIAL_FLUSH
+- Write out all of the available bits when using Z_BLOCK
+- Insert the first two strings in the hash table after a flush
+
+Changes in 1.2.5.2 (17 Dec 2011)
+- fix ld error: unable to find version dependency 'ZLIB_1.2.5'
+- use relative symlinks for shared libs
+- Avoid searching past window for Z_RLE strategy
+- Assure that high-water mark initialization is always applied in deflate
+- Add assertions to fill_window() in deflate.c to match comments
+- Update python link in README
+- Correct spelling error in gzread.c
+- Fix bug in gzgets() for a concatenated empty gzip stream
+- Correct error in comment for gz_make()
+- Change gzread() and related to ignore junk after gzip streams
+- Allow gzread() and related to continue after gzclearerr()
+- Allow gzrewind() and gzseek() after a premature end-of-file
+- Simplify gzseek() now that raw after gzip is ignored
+- Change gzgetc() to a macro for speed (~40% speedup in testing)
+- Fix gzclose() to return the actual error last encountered
+- Always add large file support for windows
+- Include zconf.h for windows large file support
+- Include zconf.h.cmakein for windows large file support
+- Update zconf.h.cmakein on make distclean
+- Merge vestigial vsnprintf determination from zutil.h to gzguts.h
+- Clarify how gzopen() appends in zlib.h comments
+- Correct documentation of gzdirect() since junk at end now ignored
+- Add a transparent write mode to gzopen() when 'T' is in the mode
+- Update python link in zlib man page
+- Get inffixed.h and MAKEFIXED result to match
+- Add a ./config --solo option to make zlib subset with no libary use
+- Add undocumented inflateResetKeep() function for CAB file decoding
+- Add --cover option to ./configure for gcc coverage testing
+- Add #define ZLIB_CONST option to use const in the z_stream interface
+- Add comment to gzdopen() in zlib.h to use dup() when using fileno()
+- Note behavior of uncompress() to provide as much data as it can
+- Add files in contrib/minizip to aid in building libminizip
+- Split off AR options in Makefile.in and configure
+- Change ON macro to Z_ARG to avoid application conflicts
+- Facilitate compilation with Borland C++ for pragmas and vsnprintf
+- Include io.h for Turbo C / Borland C++
+- Move example.c and minigzip.c to test/
+- Simplify incomplete code table filling in inflate_table()
+- Remove code from inflate.c and infback.c that is impossible to execute
+- Test the inflate code with full coverage
+- Allow deflateSetDictionary, inflateSetDictionary at any time (in raw)
+- Add deflateResetKeep and fix inflateResetKeep to retain dictionary
+- Fix gzwrite.c to accommodate reduced memory zlib compilation
+- Have inflate() with Z_FINISH avoid the allocation of a window
+- Do not set strm->adler when doing raw inflate
+- Fix gzeof() to behave just like feof() when read is not past end of file
+- Fix bug in gzread.c when end-of-file is reached
+- Avoid use of Z_BUF_ERROR in gz* functions except for premature EOF
+- Document gzread() capability to read concurrently written files
+- Remove hard-coding of resource compiler in CMakeLists.txt [Blammo]
+
+Changes in 1.2.5.1 (10 Sep 2011)
+- Update FAQ entry on shared builds (#13)
+- Avoid symbolic argument to chmod in Makefile.in
+- Fix bug and add consts in contrib/puff [Oberhumer]
+- Update contrib/puff/zeros.raw test file to have all block types
+- Add full coverage test for puff in contrib/puff/Makefile
+- Fix static-only-build install in Makefile.in
+- Fix bug in unzGetCurrentFileInfo() in contrib/minizip [Kuno]
+- Add libz.a dependency to shared in Makefile.in for parallel builds
+- Spell out "number" (instead of "nb") in zlib.h for total_in, total_out
+- Replace $(...) with `...` in configure for non-bash sh [Bowler]
+- Add darwin* to Darwin* and solaris* to SunOS\ 5* in configure [Groffen]
+- Add solaris* to Linux* in configure to allow gcc use [Groffen]
+- Add *bsd* to Linux* case in configure [Bar-Lev]
+- Add inffast.obj to dependencies in win32/Makefile.msc
+- Correct spelling error in deflate.h [Kohler]
+- Change libzdll.a again to libz.dll.a (!) in win32/Makefile.gcc
+- Add test to configure for GNU C looking for gcc in output of $cc -v
+- Add zlib.pc generation to win32/Makefile.gcc [Weigelt]
+- Fix bug in zlib.h for _FILE_OFFSET_BITS set and _LARGEFILE64_SOURCE not
+- Add comment in zlib.h that adler32_combine with len2 < 0 makes no sense
+- Make NO_DIVIDE option in adler32.c much faster (thanks to John Reiser)
+- Make stronger test in zconf.h to include unistd.h for LFS
+- Apply Darwin patches for 64-bit file offsets to contrib/minizip [Slack]
+- Fix zlib.h LFS support when Z_PREFIX used
+- Add updated as400 support (removed from old) [Monnerat]
+- Avoid deflate sensitivity to volatile input data
+- Avoid division in adler32_combine for NO_DIVIDE
+- Clarify the use of Z_FINISH with deflateBound() amount of space
+- Set binary for output file in puff.c
+- Use u4 type for crc_table to avoid conversion warnings
+- Apply casts in zlib.h to avoid conversion warnings
+- Add OF to prototypes for adler32_combine_ and crc32_combine_ [Miller]
+- Improve inflateSync() documentation to note indeterminancy
+- Add deflatePending() function to return the amount of pending output
+- Correct the spelling of "specification" in FAQ [Randers-Pehrson]
+- Add a check in configure for stdarg.h, use for gzprintf()
+- Check that pointers fit in ints when gzprint() compiled old style
+- Add dummy name before $(SHAREDLIBV) in Makefile [Bar-Lev, Bowler]
+- Delete line in configure that adds -L. libz.a to LDFLAGS [Weigelt]
+- Add debug records in assmebler code [Londer]
+- Update RFC references to use http://tools.ietf.org/html/... [Li]
+- Add --archs option, use of libtool to configure for Mac OS X [Borstel]
+
+Changes in 1.2.5 (19 Apr 2010)
+- Disable visibility attribute in win32/Makefile.gcc [Bar-Lev]
+- Default to libdir as sharedlibdir in configure [Nieder]
+- Update copyright dates on modified source files
+- Update trees.c to be able to generate modified trees.h
+- Exit configure for MinGW, suggesting win32/Makefile.gcc
+- Check for NULL path in gz_open [Homurlu]
+
+Changes in 1.2.4.5 (18 Apr 2010)
+- Set sharedlibdir in configure [Torok]
+- Set LDFLAGS in Makefile.in [Bar-Lev]
+- Avoid mkdir objs race condition in Makefile.in [Bowler]
+- Add ZLIB_INTERNAL in front of internal inter-module functions and arrays
+- Define ZLIB_INTERNAL to hide internal functions and arrays for GNU C
+- Don't use hidden attribute when it is a warning generator (e.g. Solaris)
+
+Changes in 1.2.4.4 (18 Apr 2010)
+- Fix CROSS_PREFIX executable testing, CHOST extract, mingw* [Torok]
+- Undefine _LARGEFILE64_SOURCE in zconf.h if it is zero, but not if empty
+- Try to use bash or ksh regardless of functionality of /bin/sh
+- Fix configure incompatibility with NetBSD sh
+- Remove attempt to run under bash or ksh since have better NetBSD fix
+- Fix win32/Makefile.gcc for MinGW [Bar-Lev]
+- Add diagnostic messages when using CROSS_PREFIX in configure
+- Added --sharedlibdir option to configure [Weigelt]
+- Use hidden visibility attribute when available [Frysinger]
+
+Changes in 1.2.4.3 (10 Apr 2010)
+- Only use CROSS_PREFIX in configure for ar and ranlib if they exist
+- Use CROSS_PREFIX for nm [Bar-Lev]
+- Assume _LARGEFILE64_SOURCE defined is equivalent to true
+- Avoid use of undefined symbols in #if with && and ||
+- Make *64 prototypes in gzguts.h consistent with functions
+- Add -shared load option for MinGW in configure [Bowler]
+- Move z_off64_t to public interface, use instead of off64_t
+- Remove ! from shell test in configure (not portable to Solaris)
+- Change +0 macro tests to -0 for possibly increased portability
+
+Changes in 1.2.4.2 (9 Apr 2010)
+- Add consistent carriage returns to readme.txt's in masmx86 and masmx64
+- Really provide prototypes for *64 functions when building without LFS
+- Only define unlink() in minigzip.c if unistd.h not included
+- Update README to point to contrib/vstudio project files
+- Move projects/vc6 to old/ and remove projects/
+- Include stdlib.h in minigzip.c for setmode() definition under WinCE
+- Clean up assembler builds in win32/Makefile.msc [Rowe]
+- Include sys/types.h for Microsoft for off_t definition
+- Fix memory leak on error in gz_open()
+- Symbolize nm as $NM in configure [Weigelt]
+- Use TEST_LDSHARED instead of LDSHARED to link test programs [Weigelt]
+- Add +0 to _FILE_OFFSET_BITS and _LFS64_LARGEFILE in case not defined
+- Fix bug in gzeof() to take into account unused input data
+- Avoid initialization of structures with variables in puff.c
+- Updated win32/README-WIN32.txt [Rowe]
+
+Changes in 1.2.4.1 (28 Mar 2010)
+- Remove the use of [a-z] constructs for sed in configure [gentoo 310225]
+- Remove $(SHAREDLIB) from LIBS in Makefile.in [Creech]
+- Restore "for debugging" comment on sprintf() in gzlib.c
+- Remove fdopen for MVS from gzguts.h
+- Put new README-WIN32.txt in win32 [Rowe]
+- Add check for shell to configure and invoke another shell if needed
+- Fix big fat stinking bug in gzseek() on uncompressed files
+- Remove vestigial F_OPEN64 define in zutil.h
+- Set and check the value of _LARGEFILE_SOURCE and _LARGEFILE64_SOURCE
+- Avoid errors on non-LFS systems when applications define LFS macros
+- Set EXE to ".exe" in configure for MINGW [Kahle]
+- Match crc32() in crc32.c exactly to the prototype in zlib.h [Sherrill]
+- Add prefix for cross-compilation in win32/makefile.gcc [Bar-Lev]
+- Add DLL install in win32/makefile.gcc [Bar-Lev]
+- Allow Linux* or linux* from uname in configure [Bar-Lev]
+- Allow ldconfig to be redefined in configure and Makefile.in [Bar-Lev]
+- Add cross-compilation prefixes to configure [Bar-Lev]
+- Match type exactly in gz_load() invocation in gzread.c
+- Match type exactly of zcalloc() in zutil.c to zlib.h alloc_func
+- Provide prototypes for *64 functions when building zlib without LFS
+- Don't use -lc when linking shared library on MinGW
+- Remove errno.h check in configure and vestigial errno code in zutil.h
+
+Changes in 1.2.4 (14 Mar 2010)
+- Fix VER3 extraction in configure for no fourth subversion
+- Update zlib.3, add docs to Makefile.in to make .pdf out of it
+- Add zlib.3.pdf to distribution
+- Don't set error code in gzerror() if passed pointer is NULL
+- Apply destination directory fixes to CMakeLists.txt [Lowman]
+- Move #cmakedefine's to a new zconf.in.cmakein
+- Restore zconf.h for builds that don't use configure or cmake
+- Add distclean to dummy Makefile for convenience
+- Update and improve INDEX, README, and FAQ
+- Update CMakeLists.txt for the return of zconf.h [Lowman]
+- Update contrib/vstudio/vc9 and vc10 [Vollant]
+- Change libz.dll.a back to libzdll.a in win32/Makefile.gcc
+- Apply license and readme changes to contrib/asm686 [Raiter]
+- Check file name lengths and add -c option in minigzip.c [Li]
+- Update contrib/amd64 and contrib/masmx86/ [Vollant]
+- Avoid use of "eof" parameter in trees.c to not shadow library variable
+- Update make_vms.com for removal of zlibdefs.h [Zinser]
+- Update assembler code and vstudio projects in contrib [Vollant]
+- Remove outdated assembler code contrib/masm686 and contrib/asm586
+- Remove old vc7 and vc8 from contrib/vstudio
+- Update win32/Makefile.msc, add ZLIB_VER_SUBREVISION [Rowe]
+- Fix memory leaks in gzclose_r() and gzclose_w(), file leak in gz_open()
+- Add contrib/gcc_gvmat64 for longest_match and inflate_fast [Vollant]
+- Remove *64 functions from win32/zlib.def (they're not 64-bit yet)
+- Fix bug in void-returning vsprintf() case in gzwrite.c
+- Fix name change from inflate.h in contrib/inflate86/inffas86.c
+- Check if temporary file exists before removing in make_vms.com [Zinser]
+- Fix make install and uninstall for --static option
+- Fix usage of _MSC_VER in gzguts.h and zutil.h [Truta]
+- Update readme.txt in contrib/masmx64 and masmx86 to assemble
+
+Changes in 1.2.3.9 (21 Feb 2010)
+- Expunge gzio.c
+- Move as400 build information to old
+- Fix updates in contrib/minizip and contrib/vstudio
+- Add const to vsnprintf test in configure to avoid warnings [Weigelt]
+- Delete zconf.h (made by configure) [Weigelt]
+- Change zconf.in.h to zconf.h.in per convention [Weigelt]
+- Check for NULL buf in gzgets()
+- Return empty string for gzgets() with len == 1 (like fgets())
+- Fix description of gzgets() in zlib.h for end-of-file, NULL return
+- Update minizip to 1.1 [Vollant]
+- Avoid MSVC loss of data warnings in gzread.c, gzwrite.c
+- Note in zlib.h that gzerror() should be used to distinguish from EOF
+- Remove use of snprintf() from gzlib.c
+- Fix bug in gzseek()
+- Update contrib/vstudio, adding vc9 and vc10 [Kuno, Vollant]
+- Fix zconf.h generation in CMakeLists.txt [Lowman]
+- Improve comments in zconf.h where modified by configure
+
+Changes in 1.2.3.8 (13 Feb 2010)
+- Clean up text files (tabs, trailing whitespace, etc.) [Oberhumer]
+- Use z_off64_t in gz_zero() and gz_skip() to match state->skip
+- Avoid comparison problem when sizeof(int) == sizeof(z_off64_t)
+- Revert to Makefile.in from 1.2.3.6 (live with the clutter)
+- Fix missing error return in gzflush(), add zlib.h note
+- Add *64 functions to zlib.map [Levin]
+- Fix signed/unsigned comparison in gz_comp()
+- Use SFLAGS when testing shared linking in configure
+- Add --64 option to ./configure to use -m64 with gcc
+- Fix ./configure --help to correctly name options
+- Have make fail if a test fails [Levin]
+- Avoid buffer overrun in contrib/masmx64/gvmat64.asm [Simpson]
+- Remove assembler object files from contrib
+
+Changes in 1.2.3.7 (24 Jan 2010)
+- Always gzopen() with O_LARGEFILE if available
+- Fix gzdirect() to work immediately after gzopen() or gzdopen()
+- Make gzdirect() more precise when the state changes while reading
+- Improve zlib.h documentation in many places
+- Catch memory allocation failure in gz_open()
+- Complete close operation if seek forward in gzclose_w() fails
+- Return Z_ERRNO from gzclose_r() if close() fails
+- Return Z_STREAM_ERROR instead of EOF for gzclose() being passed NULL
+- Return zero for gzwrite() errors to match zlib.h description
+- Return -1 on gzputs() error to match zlib.h description
+- Add zconf.in.h to allow recovery from configure modification [Weigelt]
+- Fix static library permissions in Makefile.in [Weigelt]
+- Avoid warnings in configure tests that hide functionality [Weigelt]
+- Add *BSD and DragonFly to Linux case in configure [gentoo 123571]
+- Change libzdll.a to libz.dll.a in win32/Makefile.gcc [gentoo 288212]
+- Avoid access of uninitialized data for first inflateReset2 call [Gomes]
+- Keep object files in subdirectories to reduce the clutter somewhat
+- Remove default Makefile and zlibdefs.h, add dummy Makefile
+- Add new external functions to Z_PREFIX, remove duplicates, z_z_ -> z_
+- Remove zlibdefs.h completely -- modify zconf.h instead
+
+Changes in 1.2.3.6 (17 Jan 2010)
+- Avoid void * arithmetic in gzread.c and gzwrite.c
+- Make compilers happier with const char * for gz_error message
+- Avoid unused parameter warning in inflate.c
+- Avoid signed-unsigned comparison warning in inflate.c
+- Indent #pragma's for traditional C
+- Fix usage of strwinerror() in glib.c, change to gz_strwinerror()
+- Correct email address in configure for system options
+- Update make_vms.com and add make_vms.com to contrib/minizip [Zinser]
+- Update zlib.map [Brown]
+- Fix Makefile.in for Solaris 10 make of example64 and minizip64 [Torok]
+- Apply various fixes to CMakeLists.txt [Lowman]
+- Add checks on len in gzread() and gzwrite()
+- Add error message for no more room for gzungetc()
+- Remove zlib version check in gzwrite()
+- Defer compression of gzprintf() result until need to
+- Use snprintf() in gzdopen() if available
+- Remove USE_MMAP configuration determination (only used by minigzip)
+- Remove examples/pigz.c (available separately)
+- Update examples/gun.c to 1.6
+
+Changes in 1.2.3.5 (8 Jan 2010)
+- Add space after #if in zutil.h for some compilers
+- Fix relatively harmless bug in deflate_fast() [Exarevsky]
+- Fix same problem in deflate_slow()
+- Add $(SHAREDLIBV) to LIBS in Makefile.in [Brown]
+- Add deflate_rle() for faster Z_RLE strategy run-length encoding
+- Add deflate_huff() for faster Z_HUFFMAN_ONLY encoding
+- Change name of "write" variable in inffast.c to avoid library collisions
+- Fix premature EOF from gzread() in gzio.c [Brown]
+- Use zlib header window size if windowBits is 0 in inflateInit2()
+- Remove compressBound() call in deflate.c to avoid linking compress.o
+- Replace use of errno in gz* with functions, support WinCE [Alves]
+- Provide alternative to perror() in minigzip.c for WinCE [Alves]
+- Don't use _vsnprintf on later versions of MSVC [Lowman]
+- Add CMake build script and input file [Lowman]
+- Update contrib/minizip to 1.1 [Svensson, Vollant]
+- Moved nintendods directory from contrib to .
+- Replace gzio.c with a new set of routines with the same functionality
+- Add gzbuffer(), gzoffset(), gzclose_r(), gzclose_w() as part of above
+- Update contrib/minizip to 1.1b
+- Change gzeof() to return 0 on error instead of -1 to agree with zlib.h
+
+Changes in 1.2.3.4 (21 Dec 2009)
+- Use old school .SUFFIXES in Makefile.in for FreeBSD compatibility
+- Update comments in configure and Makefile.in for default --shared
+- Fix test -z's in configure [Marquess]
+- Build examplesh and minigzipsh when not testing
+- Change NULL's to Z_NULL's in deflate.c and in comments in zlib.h
+- Import LDFLAGS from the environment in configure
+- Fix configure to populate SFLAGS with discovered CFLAGS options
+- Adapt make_vms.com to the new Makefile.in [Zinser]
+- Add zlib2ansi script for C++ compilation [Marquess]
+- Add _FILE_OFFSET_BITS=64 test to make test (when applicable)
+- Add AMD64 assembler code for longest match to contrib [Teterin]
+- Include options from $SFLAGS when doing $LDSHARED
+- Simplify 64-bit file support by introducing z_off64_t type
+- Make shared object files in objs directory to work around old Sun cc
+- Use only three-part version number for Darwin shared compiles
+- Add rc option to ar in Makefile.in for when ./configure not run
+- Add -WI,-rpath,. to LDFLAGS for OSF 1 V4*
+- Set LD_LIBRARYN32_PATH for SGI IRIX shared compile
+- Protect against _FILE_OFFSET_BITS being defined when compiling zlib
+- Rename Makefile.in targets allstatic to static and allshared to shared
+- Fix static and shared Makefile.in targets to be independent
+- Correct error return bug in gz_open() by setting state [Brown]
+- Put spaces before ;;'s in configure for better sh compatibility
+- Add pigz.c (parallel implementation of gzip) to examples/
+- Correct constant in crc32.c to UL [Leventhal]
+- Reject negative lengths in crc32_combine()
+- Add inflateReset2() function to work like inflateEnd()/inflateInit2()
+- Include sys/types.h for _LARGEFILE64_SOURCE [Brown]
+- Correct typo in doc/algorithm.txt [Janik]
+- Fix bug in adler32_combine() [Zhu]
+- Catch missing-end-of-block-code error in all inflates and in puff
+ Assures that random input to inflate eventually results in an error
+- Added enough.c (calculation of ENOUGH for inftrees.h) to examples/
+- Update ENOUGH and its usage to reflect discovered bounds
+- Fix gzerror() error report on empty input file [Brown]
+- Add ush casts in trees.c to avoid pedantic runtime errors
+- Fix typo in zlib.h uncompress() description [Reiss]
+- Correct inflate() comments with regard to automatic header detection
+- Remove deprecation comment on Z_PARTIAL_FLUSH (it stays)
+- Put new version of gzlog (2.0) in examples with interruption recovery
+- Add puff compile option to permit invalid distance-too-far streams
+- Add puff TEST command options, ability to read piped input
+- Prototype the *64 functions in zlib.h when _FILE_OFFSET_BITS == 64, but
+ _LARGEFILE64_SOURCE not defined
+- Fix Z_FULL_FLUSH to truly erase the past by resetting s->strstart
+- Fix deflateSetDictionary() to use all 32K for output consistency
+- Remove extraneous #define MIN_LOOKAHEAD in deflate.c (in deflate.h)
+- Clear bytes after deflate lookahead to avoid use of uninitialized data
+- Change a limit in inftrees.c to be more transparent to Coverity Prevent
+- Update win32/zlib.def with exported symbols from zlib.h
+- Correct spelling errors in zlib.h [Willem, Sobrado]
+- Allow Z_BLOCK for deflate() to force a new block
+- Allow negative bits in inflatePrime() to delete existing bit buffer
+- Add Z_TREES flush option to inflate() to return at end of trees
+- Add inflateMark() to return current state information for random access
+- Add Makefile for NintendoDS to contrib [Costa]
+- Add -w in configure compile tests to avoid spurious warnings [Beucler]
+- Fix typos in zlib.h comments for deflateSetDictionary()
+- Fix EOF detection in transparent gzread() [Maier]
+
+Changes in 1.2.3.3 (2 October 2006)
+- Make --shared the default for configure, add a --static option
+- Add compile option to permit invalid distance-too-far streams
+- Add inflateUndermine() function which is required to enable above
+- Remove use of "this" variable name for C++ compatibility [Marquess]
+- Add testing of shared library in make test, if shared library built
+- Use ftello() and fseeko() if available instead of ftell() and fseek()
+- Provide two versions of all functions that use the z_off_t type for
+ binary compatibility -- a normal version and a 64-bit offset version,
+ per the Large File Support Extension when _LARGEFILE64_SOURCE is
+ defined; use the 64-bit versions by default when _FILE_OFFSET_BITS
+ is defined to be 64
+- Add a --uname= option to configure to perhaps help with cross-compiling
+
+Changes in 1.2.3.2 (3 September 2006)
+- Turn off silly Borland warnings [Hay]
+- Use off64_t and define _LARGEFILE64_SOURCE when present
+- Fix missing dependency on inffixed.h in Makefile.in
+- Rig configure --shared to build both shared and static [Teredesai, Truta]
+- Remove zconf.in.h and instead create a new zlibdefs.h file
+- Fix contrib/minizip/unzip.c non-encrypted after encrypted [Vollant]
+- Add treebuild.xml (see http://treebuild.metux.de/) [Weigelt]
+
+Changes in 1.2.3.1 (16 August 2006)
+- Add watcom directory with OpenWatcom make files [Daniel]
+- Remove #undef of FAR in zconf.in.h for MVS [Fedtke]
+- Update make_vms.com [Zinser]
+- Use -fPIC for shared build in configure [Teredesai, Nicholson]
+- Use only major version number for libz.so on IRIX and OSF1 [Reinholdtsen]
+- Use fdopen() (not _fdopen()) for Interix in zutil.h [BŠck]
+- Add some FAQ entries about the contrib directory
+- Update the MVS question in the FAQ
+- Avoid extraneous reads after EOF in gzio.c [Brown]
+- Correct spelling of "successfully" in gzio.c [Randers-Pehrson]
+- Add comments to zlib.h about gzerror() usage [Brown]
+- Set extra flags in gzip header in gzopen() like deflate() does
+- Make configure options more compatible with double-dash conventions
+ [Weigelt]
+- Clean up compilation under Solaris SunStudio cc [Rowe, Reinholdtsen]
+- Fix uninstall target in Makefile.in [Truta]
+- Add pkgconfig support [Weigelt]
+- Use $(DESTDIR) macro in Makefile.in [Reinholdtsen, Weigelt]
+- Replace set_data_type() with a more accurate detect_data_type() in
+ trees.c, according to the txtvsbin.txt document [Truta]
+- Swap the order of #include and #include "zlib.h" in
+ gzio.c, example.c and minigzip.c [Truta]
+- Shut up annoying VS2005 warnings about standard C deprecation [Rowe,
+ Truta] (where?)
+- Fix target "clean" from win32/Makefile.bor [Truta]
+- Create .pdb and .manifest files in win32/makefile.msc [Ziegler, Rowe]
+- Update zlib www home address in win32/DLL_FAQ.txt [Truta]
+- Update contrib/masmx86/inffas32.asm for VS2005 [Vollant, Van Wassenhove]
+- Enable browse info in the "Debug" and "ASM Debug" configurations in
+ the Visual C++ 6 project, and set (non-ASM) "Debug" as default [Truta]
+- Add pkgconfig support [Weigelt]
+- Add ZLIB_VER_MAJOR, ZLIB_VER_MINOR and ZLIB_VER_REVISION in zlib.h,
+ for use in win32/zlib1.rc [Polushin, Rowe, Truta]
+- Add a document that explains the new text detection scheme to
+ doc/txtvsbin.txt [Truta]
+- Add rfc1950.txt, rfc1951.txt and rfc1952.txt to doc/ [Truta]
+- Move algorithm.txt into doc/ [Truta]
+- Synchronize FAQ with website
+- Fix compressBound(), was low for some pathological cases [Fearnley]
+- Take into account wrapper variations in deflateBound()
+- Set examples/zpipe.c input and output to binary mode for Windows
+- Update examples/zlib_how.html with new zpipe.c (also web site)
+- Fix some warnings in examples/gzlog.c and examples/zran.c (it seems
+ that gcc became pickier in 4.0)
+- Add zlib.map for Linux: "All symbols from zlib-1.1.4 remain
+ un-versioned, the patch adds versioning only for symbols introduced in
+ zlib-1.2.0 or later. It also declares as local those symbols which are
+ not designed to be exported." [Levin]
+- Update Z_PREFIX list in zconf.in.h, add --zprefix option to configure
+- Do not initialize global static by default in trees.c, add a response
+ NO_INIT_GLOBAL_POINTERS to initialize them if needed [Marquess]
+- Don't use strerror() in gzio.c under WinCE [Yakimov]
+- Don't use errno.h in zutil.h under WinCE [Yakimov]
+- Move arguments for AR to its usage to allow replacing ar [Marot]
+- Add HAVE_VISIBILITY_PRAGMA in zconf.in.h for Mozilla [Randers-Pehrson]
+- Improve inflateInit() and inflateInit2() documentation
+- Fix structure size comment in inflate.h
+- Change configure help option from --h* to --help [Santos]
+
+Changes in 1.2.3 (18 July 2005)
+- Apply security vulnerability fixes to contrib/infback9 as well
+- Clean up some text files (carriage returns, trailing space)
+- Update testzlib, vstudio, masmx64, and masmx86 in contrib [Vollant]
+
+Changes in 1.2.2.4 (11 July 2005)
+- Add inflatePrime() function for starting inflation at bit boundary
+- Avoid some Visual C warnings in deflate.c
+- Avoid more silly Visual C warnings in inflate.c and inftrees.c for 64-bit
+ compile
+- Fix some spelling errors in comments [Betts]
+- Correct inflateInit2() error return documentation in zlib.h
+- Add zran.c example of compressed data random access to examples
+ directory, shows use of inflatePrime()
+- Fix cast for assignments to strm->state in inflate.c and infback.c
+- Fix zlibCompileFlags() in zutil.c to use 1L for long shifts [Oberhumer]
+- Move declarations of gf2 functions to right place in crc32.c [Oberhumer]
+- Add cast in trees.c t avoid a warning [Oberhumer]
+- Avoid some warnings in fitblk.c, gun.c, gzjoin.c in examples [Oberhumer]
+- Update make_vms.com [Zinser]
+- Initialize state->write in inflateReset() since copied in inflate_fast()
+- Be more strict on incomplete code sets in inflate_table() and increase
+ ENOUGH and MAXD -- this repairs a possible security vulnerability for
+ invalid inflate input. Thanks to Tavis Ormandy and Markus Oberhumer for
+ discovering the vulnerability and providing test cases.
+- Add ia64 support to configure for HP-UX [Smith]
+- Add error return to gzread() for format or i/o error [Levin]
+- Use malloc.h for OS/2 [Necasek]
+
+Changes in 1.2.2.3 (27 May 2005)
+- Replace 1U constants in inflate.c and inftrees.c for 64-bit compile
+- Typecast fread() return values in gzio.c [Vollant]
+- Remove trailing space in minigzip.c outmode (VC++ can't deal with it)
+- Fix crc check bug in gzread() after gzungetc() [Heiner]
+- Add the deflateTune() function to adjust internal compression parameters
+- Add a fast gzip decompressor, gun.c, to examples (use of inflateBack)
+- Remove an incorrect assertion in examples/zpipe.c
+- Add C++ wrapper in infback9.h [Donais]
+- Fix bug in inflateCopy() when decoding fixed codes
+- Note in zlib.h how much deflateSetDictionary() actually uses
+- Remove USE_DICT_HEAD in deflate.c (would mess up inflate if used)
+- Add _WIN32_WCE to define WIN32 in zconf.in.h [Spencer]
+- Don't include stderr.h or errno.h for _WIN32_WCE in zutil.h [Spencer]
+- Add gzdirect() function to indicate transparent reads
+- Update contrib/minizip [Vollant]
+- Fix compilation of deflate.c when both ASMV and FASTEST [Oberhumer]
+- Add casts in crc32.c to avoid warnings [Oberhumer]
+- Add contrib/masmx64 [Vollant]
+- Update contrib/asm586, asm686, masmx86, testzlib, vstudio [Vollant]
+
+Changes in 1.2.2.2 (30 December 2004)
+- Replace structure assignments in deflate.c and inflate.c with zmemcpy to
+ avoid implicit memcpy calls (portability for no-library compilation)
+- Increase sprintf() buffer size in gzdopen() to allow for large numbers
+- Add INFLATE_STRICT to check distances against zlib header
+- Improve WinCE errno handling and comments [Chang]
+- Remove comment about no gzip header processing in FAQ
+- Add Z_FIXED strategy option to deflateInit2() to force fixed trees
+- Add updated make_vms.com [Coghlan], update README
+- Create a new "examples" directory, move gzappend.c there, add zpipe.c,
+ fitblk.c, gzlog.[ch], gzjoin.c, and zlib_how.html.
+- Add FAQ entry and comments in deflate.c on uninitialized memory access
+- Add Solaris 9 make options in configure [Gilbert]
+- Allow strerror() usage in gzio.c for STDC
+- Fix DecompressBuf in contrib/delphi/ZLib.pas [ManChesTer]
+- Update contrib/masmx86/inffas32.asm and gvmat32.asm [Vollant]
+- Use z_off_t for adler32_combine() and crc32_combine() lengths
+- Make adler32() much faster for small len
+- Use OS_CODE in deflate() default gzip header
+
+Changes in 1.2.2.1 (31 October 2004)
+- Allow inflateSetDictionary() call for raw inflate
+- Fix inflate header crc check bug for file names and comments
+- Add deflateSetHeader() and gz_header structure for custom gzip headers
+- Add inflateGetheader() to retrieve gzip headers
+- Add crc32_combine() and adler32_combine() functions
+- Add alloc_func, free_func, in_func, out_func to Z_PREFIX list
+- Use zstreamp consistently in zlib.h (inflate_back functions)
+- Remove GUNZIP condition from definition of inflate_mode in inflate.h
+ and in contrib/inflate86/inffast.S [Truta, Anderson]
+- Add support for AMD64 in contrib/inflate86/inffas86.c [Anderson]
+- Update projects/README.projects and projects/visualc6 [Truta]
+- Update win32/DLL_FAQ.txt [Truta]
+- Avoid warning under NO_GZCOMPRESS in gzio.c; fix typo [Truta]
+- Deprecate Z_ASCII; use Z_TEXT instead [Truta]
+- Use a new algorithm for setting strm->data_type in trees.c [Truta]
+- Do not define an exit() prototype in zutil.c unless DEBUG defined
+- Remove prototype of exit() from zutil.c, example.c, minigzip.c [Truta]
+- Add comment in zlib.h for Z_NO_FLUSH parameter to deflate()
+- Fix Darwin build version identification [Peterson]
+
+Changes in 1.2.2 (3 October 2004)
+- Update zlib.h comments on gzip in-memory processing
+- Set adler to 1 in inflateReset() to support Java test suite [Walles]
+- Add contrib/dotzlib [Ravn]
+- Update win32/DLL_FAQ.txt [Truta]
+- Update contrib/minizip [Vollant]
+- Move contrib/visual-basic.txt to old/ [Truta]
+- Fix assembler builds in projects/visualc6/ [Truta]
+
+Changes in 1.2.1.2 (9 September 2004)
+- Update INDEX file
+- Fix trees.c to update strm->data_type (no one ever noticed!)
+- Fix bug in error case in inflate.c, infback.c, and infback9.c [Brown]
+- Add "volatile" to crc table flag declaration (for DYNAMIC_CRC_TABLE)
+- Add limited multitasking protection to DYNAMIC_CRC_TABLE
+- Add NO_vsnprintf for VMS in zutil.h [Mozilla]
+- Don't declare strerror() under VMS [Mozilla]
+- Add comment to DYNAMIC_CRC_TABLE to use get_crc_table() to initialize
+- Update contrib/ada [Anisimkov]
+- Update contrib/minizip [Vollant]
+- Fix configure to not hardcode directories for Darwin [Peterson]
+- Fix gzio.c to not return error on empty files [Brown]
+- Fix indentation; update version in contrib/delphi/ZLib.pas and
+ contrib/pascal/zlibpas.pas [Truta]
+- Update mkasm.bat in contrib/masmx86 [Truta]
+- Update contrib/untgz [Truta]
+- Add projects/README.projects [Truta]
+- Add project for MS Visual C++ 6.0 in projects/visualc6 [Cadieux, Truta]
+- Update win32/DLL_FAQ.txt [Truta]
+- Update list of Z_PREFIX symbols in zconf.h [Randers-Pehrson, Truta]
+- Remove an unnecessary assignment to curr in inftrees.c [Truta]
+- Add OS/2 to exe builds in configure [Poltorak]
+- Remove err dummy parameter in zlib.h [Kientzle]
+
+Changes in 1.2.1.1 (9 January 2004)
+- Update email address in README
+- Several FAQ updates
+- Fix a big fat bug in inftrees.c that prevented decoding valid
+ dynamic blocks with only literals and no distance codes --
+ Thanks to "Hot Emu" for the bug report and sample file
+- Add a note to puff.c on no distance codes case.
+
+Changes in 1.2.1 (17 November 2003)
+- Remove a tab in contrib/gzappend/gzappend.c
+- Update some interfaces in contrib for new zlib functions
+- Update zlib version number in some contrib entries
+- Add Windows CE definition for ptrdiff_t in zutil.h [Mai, Truta]
+- Support shared libraries on Hurd and KFreeBSD [Brown]
+- Fix error in NO_DIVIDE option of adler32.c
+
+Changes in 1.2.0.8 (4 November 2003)
+- Update version in contrib/delphi/ZLib.pas and contrib/pascal/zlibpas.pas
+- Add experimental NO_DIVIDE #define in adler32.c
+ - Possibly faster on some processors (let me know if it is)
+- Correct Z_BLOCK to not return on first inflate call if no wrap
+- Fix strm->data_type on inflate() return to correctly indicate EOB
+- Add deflatePrime() function for appending in the middle of a byte
+- Add contrib/gzappend for an example of appending to a stream
+- Update win32/DLL_FAQ.txt [Truta]
+- Delete Turbo C comment in README [Truta]
+- Improve some indentation in zconf.h [Truta]
+- Fix infinite loop on bad input in configure script [Church]
+- Fix gzeof() for concatenated gzip files [Johnson]
+- Add example to contrib/visual-basic.txt [Michael B.]
+- Add -p to mkdir's in Makefile.in [vda]
+- Fix configure to properly detect presence or lack of printf functions
+- Add AS400 support [Monnerat]
+- Add a little Cygwin support [Wilson]
+
+Changes in 1.2.0.7 (21 September 2003)
+- Correct some debug formats in contrib/infback9
+- Cast a type in a debug statement in trees.c
+- Change search and replace delimiter in configure from % to # [Beebe]
+- Update contrib/untgz to 0.2 with various fixes [Truta]
+- Add build support for Amiga [Nikl]
+- Remove some directories in old that have been updated to 1.2
+- Add dylib building for Mac OS X in configure and Makefile.in
+- Remove old distribution stuff from Makefile
+- Update README to point to DLL_FAQ.txt, and add comment on Mac OS X
+- Update links in README
+
+Changes in 1.2.0.6 (13 September 2003)
+- Minor FAQ updates
+- Update contrib/minizip to 1.00 [Vollant]
+- Remove test of gz functions in example.c when GZ_COMPRESS defined [Truta]
+- Update POSTINC comment for 68060 [Nikl]
+- Add contrib/infback9 with deflate64 decoding (unsupported)
+- For MVS define NO_vsnprintf and undefine FAR [van Burik]
+- Add pragma for fdopen on MVS [van Burik]
+
+Changes in 1.2.0.5 (8 September 2003)
+- Add OF to inflateBackEnd() declaration in zlib.h
+- Remember start when using gzdopen in the middle of a file
+- Use internal off_t counters in gz* functions to properly handle seeks
+- Perform more rigorous check for distance-too-far in inffast.c
+- Add Z_BLOCK flush option to return from inflate at block boundary
+- Set strm->data_type on return from inflate
+ - Indicate bits unused, if at block boundary, and if in last block
+- Replace size_t with ptrdiff_t in crc32.c, and check for correct size
+- Add condition so old NO_DEFLATE define still works for compatibility
+- FAQ update regarding the Windows DLL [Truta]
+- INDEX update: add qnx entry, remove aix entry [Truta]
+- Install zlib.3 into mandir [Wilson]
+- Move contrib/zlib_dll_FAQ.txt to win32/DLL_FAQ.txt; update [Truta]
+- Adapt the zlib interface to the new DLL convention guidelines [Truta]
+- Introduce ZLIB_WINAPI macro to allow the export of functions using
+ the WINAPI calling convention, for Visual Basic [Vollant, Truta]
+- Update msdos and win32 scripts and makefiles [Truta]
+- Export symbols by name, not by ordinal, in win32/zlib.def [Truta]
+- Add contrib/ada [Anisimkov]
+- Move asm files from contrib/vstudio/vc70_32 to contrib/asm386 [Truta]
+- Rename contrib/asm386 to contrib/masmx86 [Truta, Vollant]
+- Add contrib/masm686 [Truta]
+- Fix offsets in contrib/inflate86 and contrib/masmx86/inffas32.asm
+ [Truta, Vollant]
+- Update contrib/delphi; rename to contrib/pascal; add example [Truta]
+- Remove contrib/delphi2; add a new contrib/delphi [Truta]
+- Avoid inclusion of the nonstandard in contrib/iostream,
+ and fix some method prototypes [Truta]
+- Fix the ZCR_SEED2 constant to avoid warnings in contrib/minizip
+ [Truta]
+- Avoid the use of backslash (\) in contrib/minizip [Vollant]
+- Fix file time handling in contrib/untgz; update makefiles [Truta]
+- Update contrib/vstudio/vc70_32 to comply with the new DLL guidelines
+ [Vollant]
+- Remove contrib/vstudio/vc15_16 [Vollant]
+- Rename contrib/vstudio/vc70_32 to contrib/vstudio/vc7 [Truta]
+- Update README.contrib [Truta]
+- Invert the assignment order of match_head and s->prev[...] in
+ INSERT_STRING [Truta]
+- Compare TOO_FAR with 32767 instead of 32768, to avoid 16-bit warnings
+ [Truta]
+- Compare function pointers with 0, not with NULL or Z_NULL [Truta]
+- Fix prototype of syncsearch in inflate.c [Truta]
+- Introduce ASMINF macro to be enabled when using an ASM implementation
+ of inflate_fast [Truta]
+- Change NO_DEFLATE to NO_GZCOMPRESS [Truta]
+- Modify test_gzio in example.c to take a single file name as a
+ parameter [Truta]
+- Exit the example.c program if gzopen fails [Truta]
+- Add type casts around strlen in example.c [Truta]
+- Remove casting to sizeof in minigzip.c; give a proper type
+ to the variable compared with SUFFIX_LEN [Truta]
+- Update definitions of STDC and STDC99 in zconf.h [Truta]
+- Synchronize zconf.h with the new Windows DLL interface [Truta]
+- Use SYS16BIT instead of __32BIT__ to distinguish between
+ 16- and 32-bit platforms [Truta]
+- Use far memory allocators in small 16-bit memory models for
+ Turbo C [Truta]
+- Add info about the use of ASMV, ASMINF and ZLIB_WINAPI in
+ zlibCompileFlags [Truta]
+- Cygwin has vsnprintf [Wilson]
+- In Windows16, OS_CODE is 0, as in MSDOS [Truta]
+- In Cygwin, OS_CODE is 3 (Unix), not 11 (Windows32) [Wilson]
+
+Changes in 1.2.0.4 (10 August 2003)
+- Minor FAQ updates
+- Be more strict when checking inflateInit2's windowBits parameter
+- Change NO_GUNZIP compile option to NO_GZIP to cover deflate as well
+- Add gzip wrapper option to deflateInit2 using windowBits
+- Add updated QNX rule in configure and qnx directory [Bonnefoy]
+- Make inflate distance-too-far checks more rigorous
+- Clean up FAR usage in inflate
+- Add casting to sizeof() in gzio.c and minigzip.c
+
+Changes in 1.2.0.3 (19 July 2003)
+- Fix silly error in gzungetc() implementation [Vollant]
+- Update contrib/minizip and contrib/vstudio [Vollant]
+- Fix printf format in example.c
+- Correct cdecl support in zconf.in.h [Anisimkov]
+- Minor FAQ updates
+
+Changes in 1.2.0.2 (13 July 2003)
+- Add ZLIB_VERNUM in zlib.h for numerical preprocessor comparisons
+- Attempt to avoid warnings in crc32.c for pointer-int conversion
+- Add AIX to configure, remove aix directory [Bakker]
+- Add some casts to minigzip.c
+- Improve checking after insecure sprintf() or vsprintf() calls
+- Remove #elif's from crc32.c
+- Change leave label to inf_leave in inflate.c and infback.c to avoid
+ library conflicts
+- Remove inflate gzip decoding by default--only enable gzip decoding by
+ special request for stricter backward compatibility
+- Add zlibCompileFlags() function to return compilation information
+- More typecasting in deflate.c to avoid warnings
+- Remove leading underscore from _Capital #defines [Truta]
+- Fix configure to link shared library when testing
+- Add some Windows CE target adjustments [Mai]
+- Remove #define ZLIB_DLL in zconf.h [Vollant]
+- Add zlib.3 [Rodgers]
+- Update RFC URL in deflate.c and algorithm.txt [Mai]
+- Add zlib_dll_FAQ.txt to contrib [Truta]
+- Add UL to some constants [Truta]
+- Update minizip and vstudio [Vollant]
+- Remove vestigial NEED_DUMMY_RETURN from zconf.in.h
+- Expand use of NO_DUMMY_DECL to avoid all dummy structures
+- Added iostream3 to contrib [Schwardt]
+- Replace rewind() with fseek() for WinCE [Truta]
+- Improve setting of zlib format compression level flags
+ - Report 0 for huffman and rle strategies and for level == 0 or 1
+ - Report 2 only for level == 6
+- Only deal with 64K limit when necessary at compile time [Truta]
+- Allow TOO_FAR check to be turned off at compile time [Truta]
+- Add gzclearerr() function [Souza]
+- Add gzungetc() function
+
+Changes in 1.2.0.1 (17 March 2003)
+- Add Z_RLE strategy for run-length encoding [Truta]
+ - When Z_RLE requested, restrict matches to distance one
+ - Update zlib.h, minigzip.c, gzopen(), gzdopen() for Z_RLE
+- Correct FASTEST compilation to allow level == 0
+- Clean up what gets compiled for FASTEST
+- Incorporate changes to zconf.in.h [Vollant]
+ - Refine detection of Turbo C need for dummy returns
+ - Refine ZLIB_DLL compilation
+ - Include additional header file on VMS for off_t typedef
+- Try to use _vsnprintf where it supplants vsprintf [Vollant]
+- Add some casts in inffast.c
+- Enchance comments in zlib.h on what happens if gzprintf() tries to
+ write more than 4095 bytes before compression
+- Remove unused state from inflateBackEnd()
+- Remove exit(0) from minigzip.c, example.c
+- Get rid of all those darn tabs
+- Add "check" target to Makefile.in that does the same thing as "test"
+- Add "mostlyclean" and "maintainer-clean" targets to Makefile.in
+- Update contrib/inflate86 [Anderson]
+- Update contrib/testzlib, contrib/vstudio, contrib/minizip [Vollant]
+- Add msdos and win32 directories with makefiles [Truta]
+- More additions and improvements to the FAQ
+
+Changes in 1.2.0 (9 March 2003)
+- New and improved inflate code
+ - About 20% faster
+ - Does not allocate 32K window unless and until needed
+ - Automatically detects and decompresses gzip streams
+ - Raw inflate no longer needs an extra dummy byte at end
+ - Added inflateBack functions using a callback interface--even faster
+ than inflate, useful for file utilities (gzip, zip)
+ - Added inflateCopy() function to record state for random access on
+ externally generated deflate streams (e.g. in gzip files)
+ - More readable code (I hope)
+- New and improved crc32()
+ - About 50% faster, thanks to suggestions from Rodney Brown
+- Add deflateBound() and compressBound() functions
+- Fix memory leak in deflateInit2()
+- Permit setting dictionary for raw deflate (for parallel deflate)
+- Fix const declaration for gzwrite()
+- Check for some malloc() failures in gzio.c
+- Fix bug in gzopen() on single-byte file 0x1f
+- Fix bug in gzread() on concatenated file with 0x1f at end of buffer
+ and next buffer doesn't start with 0x8b
+- Fix uncompress() to return Z_DATA_ERROR on truncated input
+- Free memory at end of example.c
+- Remove MAX #define in trees.c (conflicted with some libraries)
+- Fix static const's in deflate.c, gzio.c, and zutil.[ch]
+- Declare malloc() and free() in gzio.c if STDC not defined
+- Use malloc() instead of calloc() in zutil.c if int big enough
+- Define STDC for AIX
+- Add aix/ with approach for compiling shared library on AIX
+- Add HP-UX support for shared libraries in configure
+- Add OpenUNIX support for shared libraries in configure
+- Use $cc instead of gcc to build shared library
+- Make prefix directory if needed when installing
+- Correct Macintosh avoidance of typedef Byte in zconf.h
+- Correct Turbo C memory allocation when under Linux
+- Use libz.a instead of -lz in Makefile (assure use of compiled library)
+- Update configure to check for snprintf or vsnprintf functions and their
+ return value, warn during make if using an insecure function
+- Fix configure problem with compile-time knowledge of HAVE_UNISTD_H that
+ is lost when library is used--resolution is to build new zconf.h
+- Documentation improvements (in zlib.h):
+ - Document raw deflate and inflate
+ - Update RFCs URL
+ - Point out that zlib and gzip formats are different
+ - Note that Z_BUF_ERROR is not fatal
+ - Document string limit for gzprintf() and possible buffer overflow
+ - Note requirement on avail_out when flushing
+ - Note permitted values of flush parameter of inflate()
+- Add some FAQs (and even answers) to the FAQ
+- Add contrib/inflate86/ for x86 faster inflate
+- Add contrib/blast/ for PKWare Data Compression Library decompression
+- Add contrib/puff/ simple inflate for deflate format description
+
+Changes in 1.1.4 (11 March 2002)
+- ZFREE was repeated on same allocation on some error conditions.
+ This creates a security problem described in
+ http://www.zlib.org/advisory-2002-03-11.txt
+- Returned incorrect error (Z_MEM_ERROR) on some invalid data
+- Avoid accesses before window for invalid distances with inflate window
+ less than 32K.
+- force windowBits > 8 to avoid a bug in the encoder for a window size
+ of 256 bytes. (A complete fix will be available in 1.1.5).
+
+Changes in 1.1.3 (9 July 1998)
+- fix "an inflate input buffer bug that shows up on rare but persistent
+ occasions" (Mark)
+- fix gzread and gztell for concatenated .gz files (Didier Le Botlan)
+- fix gzseek(..., SEEK_SET) in write mode
+- fix crc check after a gzeek (Frank Faubert)
+- fix miniunzip when the last entry in a zip file is itself a zip file
+ (J Lillge)
+- add contrib/asm586 and contrib/asm686 (Brian Raiter)
+ See http://www.muppetlabs.com/~breadbox/software/assembly.html
+- add support for Delphi 3 in contrib/delphi (Bob Dellaca)
+- add support for C++Builder 3 and Delphi 3 in contrib/delphi2 (Davide Moretti)
+- do not exit prematurely in untgz if 0 at start of block (Magnus Holmgren)
+- use macro EXTERN instead of extern to support DLL for BeOS (Sander Stoks)
+- added a FAQ file
+
+- Support gzdopen on Mac with Metrowerks (Jason Linhart)
+- Do not redefine Byte on Mac (Brad Pettit & Jason Linhart)
+- define SEEK_END too if SEEK_SET is not defined (Albert Chin-A-Young)
+- avoid some warnings with Borland C (Tom Tanner)
+- fix a problem in contrib/minizip/zip.c for 16-bit MSDOS (Gilles Vollant)
+- emulate utime() for WIN32 in contrib/untgz (Gilles Vollant)
+- allow several arguments to configure (Tim Mooney, Frodo Looijaard)
+- use libdir and includedir in Makefile.in (Tim Mooney)
+- support shared libraries on OSF1 V4 (Tim Mooney)
+- remove so_locations in "make clean" (Tim Mooney)
+- fix maketree.c compilation error (Glenn, Mark)
+- Python interface to zlib now in Python 1.5 (Jeremy Hylton)
+- new Makefile.riscos (Rich Walker)
+- initialize static descriptors in trees.c for embedded targets (Nick Smith)
+- use "foo-gz" in example.c for RISCOS and VMS (Nick Smith)
+- add the OS/2 files in Makefile.in too (Andrew Zabolotny)
+- fix fdopen and halloc macros for Microsoft C 6.0 (Tom Lane)
+- fix maketree.c to allow clean compilation of inffixed.h (Mark)
+- fix parameter check in deflateCopy (Gunther Nikl)
+- cleanup trees.c, use compressed_len only in debug mode (Christian Spieler)
+- Many portability patches by Christian Spieler:
+ . zutil.c, zutil.h: added "const" for zmem*
+ . Make_vms.com: fixed some typos
+ . Make_vms.com: msdos/Makefile.*: removed zutil.h from some dependency lists
+ . msdos/Makefile.msc: remove "default rtl link library" info from obj files
+ . msdos/Makefile.*: use model-dependent name for the built zlib library
+ . msdos/Makefile.emx, nt/Makefile.emx, nt/Makefile.gcc:
+ new makefiles, for emx (DOS/OS2), emx&rsxnt and mingw32 (Windows 9x / NT)
+- use define instead of typedef for Bytef also for MSC small/medium (Tom Lane)
+- replace __far with _far for better portability (Christian Spieler, Tom Lane)
+- fix test for errno.h in configure (Tim Newsham)
+
+Changes in 1.1.2 (19 March 98)
+- added contrib/minzip, mini zip and unzip based on zlib (Gilles Vollant)
+ See http://www.winimage.com/zLibDll/unzip.html
+- preinitialize the inflate tables for fixed codes, to make the code
+ completely thread safe (Mark)
+- some simplifications and slight speed-up to the inflate code (Mark)
+- fix gzeof on non-compressed files (Allan Schrum)
+- add -std1 option in configure for OSF1 to fix gzprintf (Martin Mokrejs)
+- use default value of 4K for Z_BUFSIZE for 16-bit MSDOS (Tim Wegner + Glenn)
+- added os2/Makefile.def and os2/zlib.def (Andrew Zabolotny)
+- add shared lib support for UNIX_SV4.2MP (MATSUURA Takanori)
+- do not wrap extern "C" around system includes (Tom Lane)
+- mention zlib binding for TCL in README (Andreas Kupries)
+- added amiga/Makefile.pup for Amiga powerUP SAS/C PPC (Andreas Kleinert)
+- allow "make install prefix=..." even after configure (Glenn Randers-Pehrson)
+- allow "configure --prefix $HOME" (Tim Mooney)
+- remove warnings in example.c and gzio.c (Glenn Randers-Pehrson)
+- move Makefile.sas to amiga/Makefile.sas
+
+Changes in 1.1.1 (27 Feb 98)
+- fix macros _tr_tally_* in deflate.h for debug mode (Glenn Randers-Pehrson)
+- remove block truncation heuristic which had very marginal effect for zlib
+ (smaller lit_bufsize than in gzip 1.2.4) and degraded a little the
+ compression ratio on some files. This also allows inlining _tr_tally for
+ matches in deflate_slow.
+- added msdos/Makefile.w32 for WIN32 Microsoft Visual C++ (Bob Frazier)
+
+Changes in 1.1.0 (24 Feb 98)
+- do not return STREAM_END prematurely in inflate (John Bowler)
+- revert to the zlib 1.0.8 inflate to avoid the gcc 2.8.0 bug (Jeremy Buhler)
+- compile with -DFASTEST to get compression code optimized for speed only
+- in minigzip, try mmap'ing the input file first (Miguel Albrecht)
+- increase size of I/O buffers in minigzip.c and gzio.c (not a big gain
+ on Sun but significant on HP)
+
+- add a pointer to experimental unzip library in README (Gilles Vollant)
+- initialize variable gcc in configure (Chris Herborth)
+
+Changes in 1.0.9 (17 Feb 1998)
+- added gzputs and gzgets functions
+- do not clear eof flag in gzseek (Mark Diekhans)
+- fix gzseek for files in transparent mode (Mark Diekhans)
+- do not assume that vsprintf returns the number of bytes written (Jens Krinke)
+- replace EXPORT with ZEXPORT to avoid conflict with other programs
+- added compress2 in zconf.h, zlib.def, zlib.dnt
+- new asm code from Gilles Vollant in contrib/asm386
+- simplify the inflate code (Mark):
+ . Replace ZALLOC's in huft_build() with single ZALLOC in inflate_blocks_new()
+ . ZALLOC the length list in inflate_trees_fixed() instead of using stack
+ . ZALLOC the value area for huft_build() instead of using stack
+ . Simplify Z_FINISH check in inflate()
+
+- Avoid gcc 2.8.0 comparison bug a little differently than zlib 1.0.8
+- in inftrees.c, avoid cc -O bug on HP (Farshid Elahi)
+- in zconf.h move the ZLIB_DLL stuff earlier to avoid problems with
+ the declaration of FAR (Gilles VOllant)
+- install libz.so* with mode 755 (executable) instead of 644 (Marc Lehmann)
+- read_buf buf parameter of type Bytef* instead of charf*
+- zmemcpy parameters are of type Bytef*, not charf* (Joseph Strout)
+- do not redeclare unlink in minigzip.c for WIN32 (John Bowler)
+- fix check for presence of directories in "make install" (Ian Willis)
+
+Changes in 1.0.8 (27 Jan 1998)
+- fixed offsets in contrib/asm386/gvmat32.asm (Gilles Vollant)
+- fix gzgetc and gzputc for big endian systems (Markus Oberhumer)
+- added compress2() to allow setting the compression level
+- include sys/types.h to get off_t on some systems (Marc Lehmann & QingLong)
+- use constant arrays for the static trees in trees.c instead of computing
+ them at run time (thanks to Ken Raeburn for this suggestion). To create
+ trees.h, compile with GEN_TREES_H and run "make test".
+- check return code of example in "make test" and display result
+- pass minigzip command line options to file_compress
+- simplifying code of inflateSync to avoid gcc 2.8 bug
+
+- support CC="gcc -Wall" in configure -s (QingLong)
+- avoid a flush caused by ftell in gzopen for write mode (Ken Raeburn)
+- fix test for shared library support to avoid compiler warnings
+- zlib.lib -> zlib.dll in msdos/zlib.rc (Gilles Vollant)
+- check for TARGET_OS_MAC in addition to MACOS (Brad Pettit)
+- do not use fdopen for Metrowerks on Mac (Brad Pettit))
+- add checks for gzputc and gzputc in example.c
+- avoid warnings in gzio.c and deflate.c (Andreas Kleinert)
+- use const for the CRC table (Ken Raeburn)
+- fixed "make uninstall" for shared libraries
+- use Tracev instead of Trace in infblock.c
+- in example.c use correct compressed length for test_sync
+- suppress +vnocompatwarnings in configure for HPUX (not always supported)
+
+Changes in 1.0.7 (20 Jan 1998)
+- fix gzseek which was broken in write mode
+- return error for gzseek to negative absolute position
+- fix configure for Linux (Chun-Chung Chen)
+- increase stack space for MSC (Tim Wegner)
+- get_crc_table and inflateSyncPoint are EXPORTed (Gilles Vollant)
+- define EXPORTVA for gzprintf (Gilles Vollant)
+- added man page zlib.3 (Rick Rodgers)
+- for contrib/untgz, fix makedir() and improve Makefile
+
+- check gzseek in write mode in example.c
+- allocate extra buffer for seeks only if gzseek is actually called
+- avoid signed/unsigned comparisons (Tim Wegner, Gilles Vollant)
+- add inflateSyncPoint in zconf.h
+- fix list of exported functions in nt/zlib.dnt and mdsos/zlib.def
+
+Changes in 1.0.6 (19 Jan 1998)
+- add functions gzprintf, gzputc, gzgetc, gztell, gzeof, gzseek, gzrewind and
+ gzsetparams (thanks to Roland Giersig and Kevin Ruland for some of this code)
+- Fix a deflate bug occurring only with compression level 0 (thanks to
+ Andy Buckler for finding this one).
+- In minigzip, pass transparently also the first byte for .Z files.
+- return Z_BUF_ERROR instead of Z_OK if output buffer full in uncompress()
+- check Z_FINISH in inflate (thanks to Marc Schluper)
+- Implement deflateCopy (thanks to Adam Costello)
+- make static libraries by default in configure, add --shared option.
+- move MSDOS or Windows specific files to directory msdos
+- suppress the notion of partial flush to simplify the interface
+ (but the symbol Z_PARTIAL_FLUSH is kept for compatibility with 1.0.4)
+- suppress history buffer provided by application to simplify the interface
+ (this feature was not implemented anyway in 1.0.4)
+- next_in and avail_in must be initialized before calling inflateInit or
+ inflateInit2
+- add EXPORT in all exported functions (for Windows DLL)
+- added Makefile.nt (thanks to Stephen Williams)
+- added the unsupported "contrib" directory:
+ contrib/asm386/ by Gilles Vollant
+ 386 asm code replacing longest_match().
+ contrib/iostream/ by Kevin Ruland
+ A C++ I/O streams interface to the zlib gz* functions
+ contrib/iostream2/ by Tyge Løvset
+ Another C++ I/O streams interface
+ contrib/untgz/ by "Pedro A. Aranda Guti\irrez"
+ A very simple tar.gz file extractor using zlib
+ contrib/visual-basic.txt by Carlos Rios
+ How to use compress(), uncompress() and the gz* functions from VB.
+- pass params -f (filtered data), -h (huffman only), -1 to -9 (compression
+ level) in minigzip (thanks to Tom Lane)
+
+- use const for rommable constants in deflate
+- added test for gzseek and gztell in example.c
+- add undocumented function inflateSyncPoint() (hack for Paul Mackerras)
+- add undocumented function zError to convert error code to string
+ (for Tim Smithers)
+- Allow compilation of gzio with -DNO_DEFLATE to avoid the compression code.
+- Use default memcpy for Symantec MSDOS compiler.
+- Add EXPORT keyword for check_func (needed for Windows DLL)
+- add current directory to LD_LIBRARY_PATH for "make test"
+- create also a link for libz.so.1
+- added support for FUJITSU UXP/DS (thanks to Toshiaki Nomura)
+- use $(SHAREDLIB) instead of libz.so in Makefile.in (for HPUX)
+- added -soname for Linux in configure (Chun-Chung Chen,
+- assign numbers to the exported functions in zlib.def (for Windows DLL)
+- add advice in zlib.h for best usage of deflateSetDictionary
+- work around compiler bug on Atari (cast Z_NULL in call of s->checkfn)
+- allow compilation with ANSI keywords only enabled for TurboC in large model
+- avoid "versionString"[0] (Borland bug)
+- add NEED_DUMMY_RETURN for Borland
+- use variable z_verbose for tracing in debug mode (L. Peter Deutsch).
+- allow compilation with CC
+- defined STDC for OS/2 (David Charlap)
+- limit external names to 8 chars for MVS (Thomas Lund)
+- in minigzip.c, use static buffers only for 16-bit systems
+- fix suffix check for "minigzip -d foo.gz"
+- do not return an error for the 2nd of two consecutive gzflush() (Felix Lee)
+- use _fdopen instead of fdopen for MSC >= 6.0 (Thomas Fanslau)
+- added makelcc.bat for lcc-win32 (Tom St Denis)
+- in Makefile.dj2, use copy and del instead of install and rm (Frank Donahoe)
+- Avoid expanded $Id$. Use "rcs -kb" or "cvs admin -kb" to avoid Id expansion.
+- check for unistd.h in configure (for off_t)
+- remove useless check parameter in inflate_blocks_free
+- avoid useless assignment of s->check to itself in inflate_blocks_new
+- do not flush twice in gzclose (thanks to Ken Raeburn)
+- rename FOPEN as F_OPEN to avoid clash with /usr/include/sys/file.h
+- use NO_ERRNO_H instead of enumeration of operating systems with errno.h
+- work around buggy fclose on pipes for HP/UX
+- support zlib DLL with BORLAND C++ 5.0 (thanks to Glenn Randers-Pehrson)
+- fix configure if CC is already equal to gcc
+
+Changes in 1.0.5 (3 Jan 98)
+- Fix inflate to terminate gracefully when fed corrupted or invalid data
+- Use const for rommable constants in inflate
+- Eliminate memory leaks on error conditions in inflate
+- Removed some vestigial code in inflate
+- Update web address in README
+
+Changes in 1.0.4 (24 Jul 96)
+- In very rare conditions, deflate(s, Z_FINISH) could fail to produce an EOF
+ bit, so the decompressor could decompress all the correct data but went
+ on to attempt decompressing extra garbage data. This affected minigzip too.
+- zlibVersion and gzerror return const char* (needed for DLL)
+- port to RISCOS (no fdopen, no multiple dots, no unlink, no fileno)
+- use z_error only for DEBUG (avoid problem with DLLs)
+
+Changes in 1.0.3 (2 Jul 96)
+- use z_streamp instead of z_stream *, which is now a far pointer in MSDOS
+ small and medium models; this makes the library incompatible with previous
+ versions for these models. (No effect in large model or on other systems.)
+- return OK instead of BUF_ERROR if previous deflate call returned with
+ avail_out as zero but there is nothing to do
+- added memcmp for non STDC compilers
+- define NO_DUMMY_DECL for more Mac compilers (.h files merged incorrectly)
+- define __32BIT__ if __386__ or i386 is defined (pb. with Watcom and SCO)
+- better check for 16-bit mode MSC (avoids problem with Symantec)
+
+Changes in 1.0.2 (23 May 96)
+- added Windows DLL support
+- added a function zlibVersion (for the DLL support)
+- fixed declarations using Bytef in infutil.c (pb with MSDOS medium model)
+- Bytef is define's instead of typedef'd only for Borland C
+- avoid reading uninitialized memory in example.c
+- mention in README that the zlib format is now RFC1950
+- updated Makefile.dj2
+- added algorithm.doc
+
+Changes in 1.0.1 (20 May 96) [1.0 skipped to avoid confusion]
+- fix array overlay in deflate.c which sometimes caused bad compressed data
+- fix inflate bug with empty stored block
+- fix MSDOS medium model which was broken in 0.99
+- fix deflateParams() which could generated bad compressed data.
+- Bytef is define'd instead of typedef'ed (work around Borland bug)
+- added an INDEX file
+- new makefiles for DJGPP (Makefile.dj2), 32-bit Borland (Makefile.b32),
+ Watcom (Makefile.wat), Amiga SAS/C (Makefile.sas)
+- speed up adler32 for modern machines without auto-increment
+- added -ansi for IRIX in configure
+- static_init_done in trees.c is an int
+- define unlink as delete for VMS
+- fix configure for QNX
+- add configure branch for SCO and HPUX
+- avoid many warnings (unused variables, dead assignments, etc...)
+- no fdopen for BeOS
+- fix the Watcom fix for 32 bit mode (define FAR as empty)
+- removed redefinition of Byte for MKWERKS
+- work around an MWKERKS bug (incorrect merge of all .h files)
+
+Changes in 0.99 (27 Jan 96)
+- allow preset dictionary shared between compressor and decompressor
+- allow compression level 0 (no compression)
+- add deflateParams in zlib.h: allow dynamic change of compression level
+ and compression strategy.
+- test large buffers and deflateParams in example.c
+- add optional "configure" to build zlib as a shared library
+- suppress Makefile.qnx, use configure instead
+- fixed deflate for 64-bit systems (detected on Cray)
+- fixed inflate_blocks for 64-bit systems (detected on Alpha)
+- declare Z_DEFLATED in zlib.h (possible parameter for deflateInit2)
+- always return Z_BUF_ERROR when deflate() has nothing to do
+- deflateInit and inflateInit are now macros to allow version checking
+- prefix all global functions and types with z_ with -DZ_PREFIX
+- make falloc completely reentrant (inftrees.c)
+- fixed very unlikely race condition in ct_static_init
+- free in reverse order of allocation to help memory manager
+- use zlib-1.0/* instead of zlib/* inside the tar.gz
+- make zlib warning-free with "gcc -O3 -Wall -Wwrite-strings -Wpointer-arith
+ -Wconversion -Wstrict-prototypes -Wmissing-prototypes"
+- allow gzread on concatenated .gz files
+- deflateEnd now returns Z_DATA_ERROR if it was premature
+- deflate is finally (?) fully deterministic (no matches beyond end of input)
+- Document Z_SYNC_FLUSH
+- add uninstall in Makefile
+- Check for __cpluplus in zlib.h
+- Better test in ct_align for partial flush
+- avoid harmless warnings for Borland C++
+- initialize hash_head in deflate.c
+- avoid warning on fdopen (gzio.c) for HP cc -Aa
+- include stdlib.h for STDC compilers
+- include errno.h for Cray
+- ignore error if ranlib doesn't exist
+- call ranlib twice for NeXTSTEP
+- use exec_prefix instead of prefix for libz.a
+- renamed ct_* as _tr_* to avoid conflict with applications
+- clear z->msg in inflateInit2 before any error return
+- initialize opaque in example.c, gzio.c, deflate.c and inflate.c
+- fixed typo in zconf.h (_GNUC__ => __GNUC__)
+- check for WIN32 in zconf.h and zutil.c (avoid farmalloc in 32-bit mode)
+- fix typo in Make_vms.com (f$trnlnm -> f$getsyi)
+- in fcalloc, normalize pointer if size > 65520 bytes
+- don't use special fcalloc for 32 bit Borland C++
+- use STDC instead of __GO32__ to avoid redeclaring exit, calloc, etc...
+- use Z_BINARY instead of BINARY
+- document that gzclose after gzdopen will close the file
+- allow "a" as mode in gzopen.
+- fix error checking in gzread
+- allow skipping .gz extra-field on pipes
+- added reference to Perl interface in README
+- put the crc table in FAR data (I dislike more and more the medium model :)
+- added get_crc_table
+- added a dimension to all arrays (Borland C can't count).
+- workaround Borland C bug in declaration of inflate_codes_new & inflate_fast
+- guard against multiple inclusion of *.h (for precompiled header on Mac)
+- Watcom C pretends to be Microsoft C small model even in 32 bit mode.
+- don't use unsized arrays to avoid silly warnings by Visual C++:
+ warning C4746: 'inflate_mask' : unsized array treated as '__far'
+ (what's wrong with far data in far model?).
+- define enum out of inflate_blocks_state to allow compilation with C++
+
+Changes in 0.95 (16 Aug 95)
+- fix MSDOS small and medium model (now easier to adapt to any compiler)
+- inlined send_bits
+- fix the final (:-) bug for deflate with flush (output was correct but
+ not completely flushed in rare occasions).
+- default window size is same for compression and decompression
+ (it's now sufficient to set MAX_WBITS in zconf.h).
+- voidp -> voidpf and voidnp -> voidp (for consistency with other
+ typedefs and because voidnp was not near in large model).
+
+Changes in 0.94 (13 Aug 95)
+- support MSDOS medium model
+- fix deflate with flush (could sometimes generate bad output)
+- fix deflateReset (zlib header was incorrectly suppressed)
+- added support for VMS
+- allow a compression level in gzopen()
+- gzflush now calls fflush
+- For deflate with flush, flush even if no more input is provided.
+- rename libgz.a as libz.a
+- avoid complex expression in infcodes.c triggering Turbo C bug
+- work around a problem with gcc on Alpha (in INSERT_STRING)
+- don't use inline functions (problem with some gcc versions)
+- allow renaming of Byte, uInt, etc... with #define.
+- avoid warning about (unused) pointer before start of array in deflate.c
+- avoid various warnings in gzio.c, example.c, infblock.c, adler32.c, zutil.c
+- avoid reserved word 'new' in trees.c
+
+Changes in 0.93 (25 June 95)
+- temporarily disable inline functions
+- make deflate deterministic
+- give enough lookahead for PARTIAL_FLUSH
+- Set binary mode for stdin/stdout in minigzip.c for OS/2
+- don't even use signed char in inflate (not portable enough)
+- fix inflate memory leak for segmented architectures
+
+Changes in 0.92 (3 May 95)
+- don't assume that char is signed (problem on SGI)
+- Clear bit buffer when starting a stored block
+- no memcpy on Pyramid
+- suppressed inftest.c
+- optimized fill_window, put longest_match inline for gcc
+- optimized inflate on stored blocks.
+- untabify all sources to simplify patches
+
+Changes in 0.91 (2 May 95)
+- Default MEM_LEVEL is 8 (not 9 for Unix) as documented in zlib.h
+- Document the memory requirements in zconf.h
+- added "make install"
+- fix sync search logic in inflateSync
+- deflate(Z_FULL_FLUSH) now works even if output buffer too short
+- after inflateSync, don't scare people with just "lo world"
+- added support for DJGPP
+
+Changes in 0.9 (1 May 95)
+- don't assume that zalloc clears the allocated memory (the TurboC bug
+ was Mark's bug after all :)
+- let again gzread copy uncompressed data unchanged (was working in 0.71)
+- deflate(Z_FULL_FLUSH), inflateReset and inflateSync are now fully implemented
+- added a test of inflateSync in example.c
+- moved MAX_WBITS to zconf.h because users might want to change that.
+- document explicitly that zalloc(64K) on MSDOS must return a normalized
+ pointer (zero offset)
+- added Makefiles for Microsoft C, Turbo C, Borland C++
+- faster crc32()
+
+Changes in 0.8 (29 April 95)
+- added fast inflate (inffast.c)
+- deflate(Z_FINISH) now returns Z_STREAM_END when done. Warning: this
+ is incompatible with previous versions of zlib which returned Z_OK.
+- work around a TurboC compiler bug (bad code for b << 0, see infutil.h)
+ (actually that was not a compiler bug, see 0.81 above)
+- gzread no longer reads one extra byte in certain cases
+- In gzio destroy(), don't reference a freed structure
+- avoid many warnings for MSDOS
+- avoid the ERROR symbol which is used by MS Windows
+
+Changes in 0.71 (14 April 95)
+- Fixed more MSDOS compilation problems :( There is still a bug with
+ TurboC large model.
+
+Changes in 0.7 (14 April 95)
+- Added full inflate support.
+- Simplified the crc32() interface. The pre- and post-conditioning
+ (one's complement) is now done inside crc32(). WARNING: this is
+ incompatible with previous versions; see zlib.h for the new usage.
+
+Changes in 0.61 (12 April 95)
+- workaround for a bug in TurboC. example and minigzip now work on MSDOS.
+
+Changes in 0.6 (11 April 95)
+- added minigzip.c
+- added gzdopen to reopen a file descriptor as gzFile
+- added transparent reading of non-gziped files in gzread.
+- fixed bug in gzread (don't read crc as data)
+- fixed bug in destroy (gzio.c) (don't return Z_STREAM_END for gzclose).
+- don't allocate big arrays in the stack (for MSDOS)
+- fix some MSDOS compilation problems
+
+Changes in 0.5:
+- do real compression in deflate.c. Z_PARTIAL_FLUSH is supported but
+ not yet Z_FULL_FLUSH.
+- support decompression but only in a single step (forced Z_FINISH)
+- added opaque object for zalloc and zfree.
+- added deflateReset and inflateReset
+- added a variable zlib_version for consistency checking.
+- renamed the 'filter' parameter of deflateInit2 as 'strategy'.
+ Added Z_FILTERED and Z_HUFFMAN_ONLY constants.
+
+Changes in 0.4:
+- avoid "zip" everywhere, use zlib instead of ziplib.
+- suppress Z_BLOCK_FLUSH, interpret Z_PARTIAL_FLUSH as block flush
+ if compression method == 8.
+- added adler32 and crc32
+- renamed deflateOptions as deflateInit2, call one or the other but not both
+- added the method parameter for deflateInit2.
+- added inflateInit2
+- simplied considerably deflateInit and inflateInit by not supporting
+ user-provided history buffer. This is supported only in deflateInit2
+ and inflateInit2.
+
+Changes in 0.3:
+- prefix all macro names with Z_
+- use Z_FINISH instead of deflateEnd to finish compression.
+- added Z_HUFFMAN_ONLY
+- added gzerror()
ADDED compat/zlib/FAQ
Index: compat/zlib/FAQ
==================================================================
--- compat/zlib/FAQ
+++ compat/zlib/FAQ
@@ -0,0 +1,368 @@
+
+ Frequently Asked Questions about zlib
+
+
+If your question is not there, please check the zlib home page
+http://zlib.net/ which may have more recent information.
+The lastest zlib FAQ is at http://zlib.net/zlib_faq.html
+
+
+ 1. Is zlib Y2K-compliant?
+
+ Yes. zlib doesn't handle dates.
+
+ 2. Where can I get a Windows DLL version?
+
+ The zlib sources can be compiled without change to produce a DLL. See the
+ file win32/DLL_FAQ.txt in the zlib distribution. Pointers to the
+ precompiled DLL are found in the zlib web site at http://zlib.net/ .
+
+ 3. Where can I get a Visual Basic interface to zlib?
+
+ See
+ * http://marknelson.us/1997/01/01/zlib-engine/
+ * win32/DLL_FAQ.txt in the zlib distribution
+
+ 4. compress() returns Z_BUF_ERROR.
+
+ Make sure that before the call of compress(), the length of the compressed
+ buffer is equal to the available size of the compressed buffer and not
+ zero. For Visual Basic, check that this parameter is passed by reference
+ ("as any"), not by value ("as long").
+
+ 5. deflate() or inflate() returns Z_BUF_ERROR.
+
+ Before making the call, make sure that avail_in and avail_out are not zero.
+ When setting the parameter flush equal to Z_FINISH, also make sure that
+ avail_out is big enough to allow processing all pending input. Note that a
+ Z_BUF_ERROR is not fatal--another call to deflate() or inflate() can be
+ made with more input or output space. A Z_BUF_ERROR may in fact be
+ unavoidable depending on how the functions are used, since it is not
+ possible to tell whether or not there is more output pending when
+ strm.avail_out returns with zero. See http://zlib.net/zlib_how.html for a
+ heavily annotated example.
+
+ 6. Where's the zlib documentation (man pages, etc.)?
+
+ It's in zlib.h . Examples of zlib usage are in the files test/example.c
+ and test/minigzip.c, with more in examples/ .
+
+ 7. Why don't you use GNU autoconf or libtool or ...?
+
+ Because we would like to keep zlib as a very small and simple package.
+ zlib is rather portable and doesn't need much configuration.
+
+ 8. I found a bug in zlib.
+
+ Most of the time, such problems are due to an incorrect usage of zlib.
+ Please try to reproduce the problem with a small program and send the
+ corresponding source to us at zlib@gzip.org . Do not send multi-megabyte
+ data files without prior agreement.
+
+ 9. Why do I get "undefined reference to gzputc"?
+
+ If "make test" produces something like
+
+ example.o(.text+0x154): undefined reference to `gzputc'
+
+ check that you don't have old files libz.* in /usr/lib, /usr/local/lib or
+ /usr/X11R6/lib. Remove any old versions, then do "make install".
+
+10. I need a Delphi interface to zlib.
+
+ See the contrib/delphi directory in the zlib distribution.
+
+11. Can zlib handle .zip archives?
+
+ Not by itself, no. See the directory contrib/minizip in the zlib
+ distribution.
+
+12. Can zlib handle .Z files?
+
+ No, sorry. You have to spawn an uncompress or gunzip subprocess, or adapt
+ the code of uncompress on your own.
+
+13. How can I make a Unix shared library?
+
+ By default a shared (and a static) library is built for Unix. So:
+
+ make distclean
+ ./configure
+ make
+
+14. How do I install a shared zlib library on Unix?
+
+ After the above, then:
+
+ make install
+
+ However, many flavors of Unix come with a shared zlib already installed.
+ Before going to the trouble of compiling a shared version of zlib and
+ trying to install it, you may want to check if it's already there! If you
+ can #include , it's there. The -lz option will probably link to
+ it. You can check the version at the top of zlib.h or with the
+ ZLIB_VERSION symbol defined in zlib.h .
+
+15. I have a question about OttoPDF.
+
+ We are not the authors of OttoPDF. The real author is on the OttoPDF web
+ site: Joel Hainley, jhainley@myndkryme.com.
+
+16. Can zlib decode Flate data in an Adobe PDF file?
+
+ Yes. See http://www.pdflib.com/ . To modify PDF forms, see
+ http://sourceforge.net/projects/acroformtool/ .
+
+17. Why am I getting this "register_frame_info not found" error on Solaris?
+
+ After installing zlib 1.1.4 on Solaris 2.6, running applications using zlib
+ generates an error such as:
+
+ ld.so.1: rpm: fatal: relocation error: file /usr/local/lib/libz.so:
+ symbol __register_frame_info: referenced symbol not found
+
+ The symbol __register_frame_info is not part of zlib, it is generated by
+ the C compiler (cc or gcc). You must recompile applications using zlib
+ which have this problem. This problem is specific to Solaris. See
+ http://www.sunfreeware.com for Solaris versions of zlib and applications
+ using zlib.
+
+18. Why does gzip give an error on a file I make with compress/deflate?
+
+ The compress and deflate functions produce data in the zlib format, which
+ is different and incompatible with the gzip format. The gz* functions in
+ zlib on the other hand use the gzip format. Both the zlib and gzip formats
+ use the same compressed data format internally, but have different headers
+ and trailers around the compressed data.
+
+19. Ok, so why are there two different formats?
+
+ The gzip format was designed to retain the directory information about a
+ single file, such as the name and last modification date. The zlib format
+ on the other hand was designed for in-memory and communication channel
+ applications, and has a much more compact header and trailer and uses a
+ faster integrity check than gzip.
+
+20. Well that's nice, but how do I make a gzip file in memory?
+
+ You can request that deflate write the gzip format instead of the zlib
+ format using deflateInit2(). You can also request that inflate decode the
+ gzip format using inflateInit2(). Read zlib.h for more details.
+
+21. Is zlib thread-safe?
+
+ Yes. However any library routines that zlib uses and any application-
+ provided memory allocation routines must also be thread-safe. zlib's gz*
+ functions use stdio library routines, and most of zlib's functions use the
+ library memory allocation routines by default. zlib's *Init* functions
+ allow for the application to provide custom memory allocation routines.
+
+ Of course, you should only operate on any given zlib or gzip stream from a
+ single thread at a time.
+
+22. Can I use zlib in my commercial application?
+
+ Yes. Please read the license in zlib.h.
+
+23. Is zlib under the GNU license?
+
+ No. Please read the license in zlib.h.
+
+24. The license says that altered source versions must be "plainly marked". So
+ what exactly do I need to do to meet that requirement?
+
+ You need to change the ZLIB_VERSION and ZLIB_VERNUM #defines in zlib.h. In
+ particular, the final version number needs to be changed to "f", and an
+ identification string should be appended to ZLIB_VERSION. Version numbers
+ x.x.x.f are reserved for modifications to zlib by others than the zlib
+ maintainers. For example, if the version of the base zlib you are altering
+ is "1.2.3.4", then in zlib.h you should change ZLIB_VERNUM to 0x123f, and
+ ZLIB_VERSION to something like "1.2.3.f-zachary-mods-v3". You can also
+ update the version strings in deflate.c and inftrees.c.
+
+ For altered source distributions, you should also note the origin and
+ nature of the changes in zlib.h, as well as in ChangeLog and README, along
+ with the dates of the alterations. The origin should include at least your
+ name (or your company's name), and an email address to contact for help or
+ issues with the library.
+
+ Note that distributing a compiled zlib library along with zlib.h and
+ zconf.h is also a source distribution, and so you should change
+ ZLIB_VERSION and ZLIB_VERNUM and note the origin and nature of the changes
+ in zlib.h as you would for a full source distribution.
+
+25. Will zlib work on a big-endian or little-endian architecture, and can I
+ exchange compressed data between them?
+
+ Yes and yes.
+
+26. Will zlib work on a 64-bit machine?
+
+ Yes. It has been tested on 64-bit machines, and has no dependence on any
+ data types being limited to 32-bits in length. If you have any
+ difficulties, please provide a complete problem report to zlib@gzip.org
+
+27. Will zlib decompress data from the PKWare Data Compression Library?
+
+ No. The PKWare DCL uses a completely different compressed data format than
+ does PKZIP and zlib. However, you can look in zlib's contrib/blast
+ directory for a possible solution to your problem.
+
+28. Can I access data randomly in a compressed stream?
+
+ No, not without some preparation. If when compressing you periodically use
+ Z_FULL_FLUSH, carefully write all the pending data at those points, and
+ keep an index of those locations, then you can start decompression at those
+ points. You have to be careful to not use Z_FULL_FLUSH too often, since it
+ can significantly degrade compression. Alternatively, you can scan a
+ deflate stream once to generate an index, and then use that index for
+ random access. See examples/zran.c .
+
+29. Does zlib work on MVS, OS/390, CICS, etc.?
+
+ It has in the past, but we have not heard of any recent evidence. There
+ were working ports of zlib 1.1.4 to MVS, but those links no longer work.
+ If you know of recent, successful applications of zlib on these operating
+ systems, please let us know. Thanks.
+
+30. Is there some simpler, easier to read version of inflate I can look at to
+ understand the deflate format?
+
+ First off, you should read RFC 1951. Second, yes. Look in zlib's
+ contrib/puff directory.
+
+31. Does zlib infringe on any patents?
+
+ As far as we know, no. In fact, that was originally the whole point behind
+ zlib. Look here for some more information:
+
+ http://www.gzip.org/#faq11
+
+32. Can zlib work with greater than 4 GB of data?
+
+ Yes. inflate() and deflate() will process any amount of data correctly.
+ Each call of inflate() or deflate() is limited to input and output chunks
+ of the maximum value that can be stored in the compiler's "unsigned int"
+ type, but there is no limit to the number of chunks. Note however that the
+ strm.total_in and strm_total_out counters may be limited to 4 GB. These
+ counters are provided as a convenience and are not used internally by
+ inflate() or deflate(). The application can easily set up its own counters
+ updated after each call of inflate() or deflate() to count beyond 4 GB.
+ compress() and uncompress() may be limited to 4 GB, since they operate in a
+ single call. gzseek() and gztell() may be limited to 4 GB depending on how
+ zlib is compiled. See the zlibCompileFlags() function in zlib.h.
+
+ The word "may" appears several times above since there is a 4 GB limit only
+ if the compiler's "long" type is 32 bits. If the compiler's "long" type is
+ 64 bits, then the limit is 16 exabytes.
+
+33. Does zlib have any security vulnerabilities?
+
+ The only one that we are aware of is potentially in gzprintf(). If zlib is
+ compiled to use sprintf() or vsprintf(), then there is no protection
+ against a buffer overflow of an 8K string space (or other value as set by
+ gzbuffer()), other than the caller of gzprintf() assuring that the output
+ will not exceed 8K. On the other hand, if zlib is compiled to use
+ snprintf() or vsnprintf(), which should normally be the case, then there is
+ no vulnerability. The ./configure script will display warnings if an
+ insecure variation of sprintf() will be used by gzprintf(). Also the
+ zlibCompileFlags() function will return information on what variant of
+ sprintf() is used by gzprintf().
+
+ If you don't have snprintf() or vsnprintf() and would like one, you can
+ find a portable implementation here:
+
+ http://www.ijs.si/software/snprintf/
+
+ Note that you should be using the most recent version of zlib. Versions
+ 1.1.3 and before were subject to a double-free vulnerability, and versions
+ 1.2.1 and 1.2.2 were subject to an access exception when decompressing
+ invalid compressed data.
+
+34. Is there a Java version of zlib?
+
+ Probably what you want is to use zlib in Java. zlib is already included
+ as part of the Java SDK in the java.util.zip package. If you really want
+ a version of zlib written in the Java language, look on the zlib home
+ page for links: http://zlib.net/ .
+
+35. I get this or that compiler or source-code scanner warning when I crank it
+ up to maximally-pedantic. Can't you guys write proper code?
+
+ Many years ago, we gave up attempting to avoid warnings on every compiler
+ in the universe. It just got to be a waste of time, and some compilers
+ were downright silly as well as contradicted each other. So now, we simply
+ make sure that the code always works.
+
+36. Valgrind (or some similar memory access checker) says that deflate is
+ performing a conditional jump that depends on an uninitialized value.
+ Isn't that a bug?
+
+ No. That is intentional for performance reasons, and the output of deflate
+ is not affected. This only started showing up recently since zlib 1.2.x
+ uses malloc() by default for allocations, whereas earlier versions used
+ calloc(), which zeros out the allocated memory. Even though the code was
+ correct, versions 1.2.4 and later was changed to not stimulate these
+ checkers.
+
+37. Will zlib read the (insert any ancient or arcane format here) compressed
+ data format?
+
+ Probably not. Look in the comp.compression FAQ for pointers to various
+ formats and associated software.
+
+38. How can I encrypt/decrypt zip files with zlib?
+
+ zlib doesn't support encryption. The original PKZIP encryption is very
+ weak and can be broken with freely available programs. To get strong
+ encryption, use GnuPG, http://www.gnupg.org/ , which already includes zlib
+ compression. For PKZIP compatible "encryption", look at
+ http://www.info-zip.org/
+
+39. What's the difference between the "gzip" and "deflate" HTTP 1.1 encodings?
+
+ "gzip" is the gzip format, and "deflate" is the zlib format. They should
+ probably have called the second one "zlib" instead to avoid confusion with
+ the raw deflate compressed data format. While the HTTP 1.1 RFC 2616
+ correctly points to the zlib specification in RFC 1950 for the "deflate"
+ transfer encoding, there have been reports of servers and browsers that
+ incorrectly produce or expect raw deflate data per the deflate
+ specification in RFC 1951, most notably Microsoft. So even though the
+ "deflate" transfer encoding using the zlib format would be the more
+ efficient approach (and in fact exactly what the zlib format was designed
+ for), using the "gzip" transfer encoding is probably more reliable due to
+ an unfortunate choice of name on the part of the HTTP 1.1 authors.
+
+ Bottom line: use the gzip format for HTTP 1.1 encoding.
+
+40. Does zlib support the new "Deflate64" format introduced by PKWare?
+
+ No. PKWare has apparently decided to keep that format proprietary, since
+ they have not documented it as they have previous compression formats. In
+ any case, the compression improvements are so modest compared to other more
+ modern approaches, that it's not worth the effort to implement.
+
+41. I'm having a problem with the zip functions in zlib, can you help?
+
+ There are no zip functions in zlib. You are probably using minizip by
+ Giles Vollant, which is found in the contrib directory of zlib. It is not
+ part of zlib. In fact none of the stuff in contrib is part of zlib. The
+ files in there are not supported by the zlib authors. You need to contact
+ the authors of the respective contribution for help.
+
+42. The match.asm code in contrib is under the GNU General Public License.
+ Since it's part of zlib, doesn't that mean that all of zlib falls under the
+ GNU GPL?
+
+ No. The files in contrib are not part of zlib. They were contributed by
+ other authors and are provided as a convenience to the user within the zlib
+ distribution. Each item in contrib has its own license.
+
+43. Is zlib subject to export controls? What is its ECCN?
+
+ zlib is not subject to export controls, and so is classified as EAR99.
+
+44. Can you please sign these lengthy legal documents and fax them back to us
+ so that we can use your software in our product?
+
+ No. Go away. Shoo.
ADDED compat/zlib/INDEX
Index: compat/zlib/INDEX
==================================================================
--- compat/zlib/INDEX
+++ compat/zlib/INDEX
@@ -0,0 +1,68 @@
+CMakeLists.txt cmake build file
+ChangeLog history of changes
+FAQ Frequently Asked Questions about zlib
+INDEX this file
+Makefile dummy Makefile that tells you to ./configure
+Makefile.in template for Unix Makefile
+README guess what
+configure configure script for Unix
+make_vms.com makefile for VMS
+test/example.c zlib usages examples for build testing
+test/minigzip.c minimal gzip-like functionality for build testing
+test/infcover.c inf*.c code coverage for build coverage testing
+treebuild.xml XML description of source file dependencies
+zconf.h.cmakein zconf.h template for cmake
+zconf.h.in zconf.h template for configure
+zlib.3 Man page for zlib
+zlib.3.pdf Man page in PDF format
+zlib.map Linux symbol information
+zlib.pc.in Template for pkg-config descriptor
+zlib.pc.cmakein zlib.pc template for cmake
+zlib2ansi perl script to convert source files for C++ compilation
+
+amiga/ makefiles for Amiga SAS C
+as400/ makefiles for AS/400
+doc/ documentation for formats and algorithms
+msdos/ makefiles for MSDOS
+nintendods/ makefile for Nintendo DS
+old/ makefiles for various architectures and zlib documentation
+ files that have not yet been updated for zlib 1.2.x
+qnx/ makefiles for QNX
+watcom/ makefiles for OpenWatcom
+win32/ makefiles for Windows
+
+ zlib public header files (required for library use):
+zconf.h
+zlib.h
+
+ private source files used to build the zlib library:
+adler32.c
+compress.c
+crc32.c
+crc32.h
+deflate.c
+deflate.h
+gzclose.c
+gzguts.h
+gzlib.c
+gzread.c
+gzwrite.c
+infback.c
+inffast.c
+inffast.h
+inffixed.h
+inflate.c
+inflate.h
+inftrees.c
+inftrees.h
+trees.c
+trees.h
+uncompr.c
+zutil.c
+zutil.h
+
+ source files for sample programs
+See examples/README.examples
+
+ unsupported contributions by third parties
+See contrib/README.contrib
ADDED compat/zlib/Makefile
Index: compat/zlib/Makefile
==================================================================
--- compat/zlib/Makefile
+++ compat/zlib/Makefile
@@ -0,0 +1,5 @@
+all:
+ -@echo "Please use ./configure first. Thank you."
+
+distclean:
+ make -f Makefile.in distclean
ADDED compat/zlib/Makefile.in
Index: compat/zlib/Makefile.in
==================================================================
--- compat/zlib/Makefile.in
+++ compat/zlib/Makefile.in
@@ -0,0 +1,288 @@
+# Makefile for zlib
+# Copyright (C) 1995-2013 Jean-loup Gailly, Mark Adler
+# For conditions of distribution and use, see copyright notice in zlib.h
+
+# To compile and test, type:
+# ./configure; make test
+# Normally configure builds both a static and a shared library.
+# If you want to build just a static library, use: ./configure --static
+
+# To use the asm code, type:
+# cp contrib/asm?86/match.S ./match.S
+# make LOC=-DASMV OBJA=match.o
+
+# To install /usr/local/lib/libz.* and /usr/local/include/zlib.h, type:
+# make install
+# To install in $HOME instead of /usr/local, use:
+# make install prefix=$HOME
+
+CC=cc
+
+CFLAGS=-O
+#CFLAGS=-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7
+#CFLAGS=-g -DDEBUG
+#CFLAGS=-O3 -Wall -Wwrite-strings -Wpointer-arith -Wconversion \
+# -Wstrict-prototypes -Wmissing-prototypes
+
+SFLAGS=-O
+LDFLAGS=
+TEST_LDFLAGS=-L. libz.a
+LDSHARED=$(CC)
+CPP=$(CC) -E
+
+STATICLIB=libz.a
+SHAREDLIB=libz.so
+SHAREDLIBV=libz.so.1.2.8
+SHAREDLIBM=libz.so.1
+LIBS=$(STATICLIB) $(SHAREDLIBV)
+
+AR=ar
+ARFLAGS=rc
+RANLIB=ranlib
+LDCONFIG=ldconfig
+LDSHAREDLIBC=-lc
+TAR=tar
+SHELL=/bin/sh
+EXE=
+
+prefix = /usr/local
+exec_prefix = ${prefix}
+libdir = ${exec_prefix}/lib
+sharedlibdir = ${libdir}
+includedir = ${prefix}/include
+mandir = ${prefix}/share/man
+man3dir = ${mandir}/man3
+pkgconfigdir = ${libdir}/pkgconfig
+
+OBJZ = adler32.o crc32.o deflate.o infback.o inffast.o inflate.o inftrees.o trees.o zutil.o
+OBJG = compress.o uncompr.o gzclose.o gzlib.o gzread.o gzwrite.o
+OBJC = $(OBJZ) $(OBJG)
+
+PIC_OBJZ = adler32.lo crc32.lo deflate.lo infback.lo inffast.lo inflate.lo inftrees.lo trees.lo zutil.lo
+PIC_OBJG = compress.lo uncompr.lo gzclose.lo gzlib.lo gzread.lo gzwrite.lo
+PIC_OBJC = $(PIC_OBJZ) $(PIC_OBJG)
+
+# to use the asm code: make OBJA=match.o, PIC_OBJA=match.lo
+OBJA =
+PIC_OBJA =
+
+OBJS = $(OBJC) $(OBJA)
+
+PIC_OBJS = $(PIC_OBJC) $(PIC_OBJA)
+
+all: static shared
+
+static: example$(EXE) minigzip$(EXE)
+
+shared: examplesh$(EXE) minigzipsh$(EXE)
+
+all64: example64$(EXE) minigzip64$(EXE)
+
+check: test
+
+test: all teststatic testshared
+
+teststatic: static
+ @TMPST=tmpst_$$; \
+ if echo hello world | ./minigzip | ./minigzip -d && ./example $$TMPST ; then \
+ echo ' *** zlib test OK ***'; \
+ else \
+ echo ' *** zlib test FAILED ***'; false; \
+ fi; \
+ rm -f $$TMPST
+
+testshared: shared
+ @LD_LIBRARY_PATH=`pwd`:$(LD_LIBRARY_PATH) ; export LD_LIBRARY_PATH; \
+ LD_LIBRARYN32_PATH=`pwd`:$(LD_LIBRARYN32_PATH) ; export LD_LIBRARYN32_PATH; \
+ DYLD_LIBRARY_PATH=`pwd`:$(DYLD_LIBRARY_PATH) ; export DYLD_LIBRARY_PATH; \
+ SHLIB_PATH=`pwd`:$(SHLIB_PATH) ; export SHLIB_PATH; \
+ TMPSH=tmpsh_$$; \
+ if echo hello world | ./minigzipsh | ./minigzipsh -d && ./examplesh $$TMPSH; then \
+ echo ' *** zlib shared test OK ***'; \
+ else \
+ echo ' *** zlib shared test FAILED ***'; false; \
+ fi; \
+ rm -f $$TMPSH
+
+test64: all64
+ @TMP64=tmp64_$$; \
+ if echo hello world | ./minigzip64 | ./minigzip64 -d && ./example64 $$TMP64; then \
+ echo ' *** zlib 64-bit test OK ***'; \
+ else \
+ echo ' *** zlib 64-bit test FAILED ***'; false; \
+ fi; \
+ rm -f $$TMP64
+
+infcover.o: test/infcover.c zlib.h zconf.h
+ $(CC) $(CFLAGS) -I. -c -o $@ test/infcover.c
+
+infcover: infcover.o libz.a
+ $(CC) $(CFLAGS) -o $@ infcover.o libz.a
+
+cover: infcover
+ rm -f *.gcda
+ ./infcover
+ gcov inf*.c
+
+libz.a: $(OBJS)
+ $(AR) $(ARFLAGS) $@ $(OBJS)
+ -@ ($(RANLIB) $@ || true) >/dev/null 2>&1
+
+match.o: match.S
+ $(CPP) match.S > _match.s
+ $(CC) -c _match.s
+ mv _match.o match.o
+ rm -f _match.s
+
+match.lo: match.S
+ $(CPP) match.S > _match.s
+ $(CC) -c -fPIC _match.s
+ mv _match.o match.lo
+ rm -f _match.s
+
+example.o: test/example.c zlib.h zconf.h
+ $(CC) $(CFLAGS) -I. -c -o $@ test/example.c
+
+minigzip.o: test/minigzip.c zlib.h zconf.h
+ $(CC) $(CFLAGS) -I. -c -o $@ test/minigzip.c
+
+example64.o: test/example.c zlib.h zconf.h
+ $(CC) $(CFLAGS) -I. -D_FILE_OFFSET_BITS=64 -c -o $@ test/example.c
+
+minigzip64.o: test/minigzip.c zlib.h zconf.h
+ $(CC) $(CFLAGS) -I. -D_FILE_OFFSET_BITS=64 -c -o $@ test/minigzip.c
+
+.SUFFIXES: .lo
+
+.c.lo:
+ -@mkdir objs 2>/dev/null || test -d objs
+ $(CC) $(SFLAGS) -DPIC -c -o objs/$*.o $<
+ -@mv objs/$*.o $@
+
+placebo $(SHAREDLIBV): $(PIC_OBJS) libz.a
+ $(LDSHARED) $(SFLAGS) -o $@ $(PIC_OBJS) $(LDSHAREDLIBC) $(LDFLAGS)
+ rm -f $(SHAREDLIB) $(SHAREDLIBM)
+ ln -s $@ $(SHAREDLIB)
+ ln -s $@ $(SHAREDLIBM)
+ -@rmdir objs
+
+example$(EXE): example.o $(STATICLIB)
+ $(CC) $(CFLAGS) -o $@ example.o $(TEST_LDFLAGS)
+
+minigzip$(EXE): minigzip.o $(STATICLIB)
+ $(CC) $(CFLAGS) -o $@ minigzip.o $(TEST_LDFLAGS)
+
+examplesh$(EXE): example.o $(SHAREDLIBV)
+ $(CC) $(CFLAGS) -o $@ example.o -L. $(SHAREDLIBV)
+
+minigzipsh$(EXE): minigzip.o $(SHAREDLIBV)
+ $(CC) $(CFLAGS) -o $@ minigzip.o -L. $(SHAREDLIBV)
+
+example64$(EXE): example64.o $(STATICLIB)
+ $(CC) $(CFLAGS) -o $@ example64.o $(TEST_LDFLAGS)
+
+minigzip64$(EXE): minigzip64.o $(STATICLIB)
+ $(CC) $(CFLAGS) -o $@ minigzip64.o $(TEST_LDFLAGS)
+
+install-libs: $(LIBS)
+ -@if [ ! -d $(DESTDIR)$(exec_prefix) ]; then mkdir -p $(DESTDIR)$(exec_prefix); fi
+ -@if [ ! -d $(DESTDIR)$(libdir) ]; then mkdir -p $(DESTDIR)$(libdir); fi
+ -@if [ ! -d $(DESTDIR)$(sharedlibdir) ]; then mkdir -p $(DESTDIR)$(sharedlibdir); fi
+ -@if [ ! -d $(DESTDIR)$(man3dir) ]; then mkdir -p $(DESTDIR)$(man3dir); fi
+ -@if [ ! -d $(DESTDIR)$(pkgconfigdir) ]; then mkdir -p $(DESTDIR)$(pkgconfigdir); fi
+ cp $(STATICLIB) $(DESTDIR)$(libdir)
+ chmod 644 $(DESTDIR)$(libdir)/$(STATICLIB)
+ -@($(RANLIB) $(DESTDIR)$(libdir)/libz.a || true) >/dev/null 2>&1
+ -@if test -n "$(SHAREDLIBV)"; then \
+ cp $(SHAREDLIBV) $(DESTDIR)$(sharedlibdir); \
+ echo "cp $(SHAREDLIBV) $(DESTDIR)$(sharedlibdir)"; \
+ chmod 755 $(DESTDIR)$(sharedlibdir)/$(SHAREDLIBV); \
+ echo "chmod 755 $(DESTDIR)$(sharedlibdir)/$(SHAREDLIBV)"; \
+ rm -f $(DESTDIR)$(sharedlibdir)/$(SHAREDLIB) $(DESTDIR)$(sharedlibdir)/$(SHAREDLIBM); \
+ ln -s $(SHAREDLIBV) $(DESTDIR)$(sharedlibdir)/$(SHAREDLIB); \
+ ln -s $(SHAREDLIBV) $(DESTDIR)$(sharedlibdir)/$(SHAREDLIBM); \
+ ($(LDCONFIG) || true) >/dev/null 2>&1; \
+ fi
+ cp zlib.3 $(DESTDIR)$(man3dir)
+ chmod 644 $(DESTDIR)$(man3dir)/zlib.3
+ cp zlib.pc $(DESTDIR)$(pkgconfigdir)
+ chmod 644 $(DESTDIR)$(pkgconfigdir)/zlib.pc
+# The ranlib in install is needed on NeXTSTEP which checks file times
+# ldconfig is for Linux
+
+install: install-libs
+ -@if [ ! -d $(DESTDIR)$(includedir) ]; then mkdir -p $(DESTDIR)$(includedir); fi
+ cp zlib.h zconf.h $(DESTDIR)$(includedir)
+ chmod 644 $(DESTDIR)$(includedir)/zlib.h $(DESTDIR)$(includedir)/zconf.h
+
+uninstall:
+ cd $(DESTDIR)$(includedir) && rm -f zlib.h zconf.h
+ cd $(DESTDIR)$(libdir) && rm -f libz.a; \
+ if test -n "$(SHAREDLIBV)" -a -f $(SHAREDLIBV); then \
+ rm -f $(SHAREDLIBV) $(SHAREDLIB) $(SHAREDLIBM); \
+ fi
+ cd $(DESTDIR)$(man3dir) && rm -f zlib.3
+ cd $(DESTDIR)$(pkgconfigdir) && rm -f zlib.pc
+
+docs: zlib.3.pdf
+
+zlib.3.pdf: zlib.3
+ groff -mandoc -f H -T ps zlib.3 | ps2pdf - zlib.3.pdf
+
+zconf.h.cmakein: zconf.h.in
+ -@ TEMPFILE=zconfh_$$; \
+ echo "/#define ZCONF_H/ a\\\\\n#cmakedefine Z_PREFIX\\\\\n#cmakedefine Z_HAVE_UNISTD_H\n" >> $$TEMPFILE &&\
+ sed -f $$TEMPFILE zconf.h.in > zconf.h.cmakein &&\
+ touch -r zconf.h.in zconf.h.cmakein &&\
+ rm $$TEMPFILE
+
+zconf: zconf.h.in
+ cp -p zconf.h.in zconf.h
+
+mostlyclean: clean
+clean:
+ rm -f *.o *.lo *~ \
+ example$(EXE) minigzip$(EXE) examplesh$(EXE) minigzipsh$(EXE) \
+ example64$(EXE) minigzip64$(EXE) \
+ infcover \
+ libz.* foo.gz so_locations \
+ _match.s maketree contrib/infback9/*.o
+ rm -rf objs
+ rm -f *.gcda *.gcno *.gcov
+ rm -f contrib/infback9/*.gcda contrib/infback9/*.gcno contrib/infback9/*.gcov
+
+maintainer-clean: distclean
+distclean: clean zconf zconf.h.cmakein docs
+ rm -f Makefile zlib.pc configure.log
+ -@rm -f .DS_Store
+ -@printf 'all:\n\t-@echo "Please use ./configure first. Thank you."\n' > Makefile
+ -@printf '\ndistclean:\n\tmake -f Makefile.in distclean\n' >> Makefile
+ -@touch -r Makefile.in Makefile
+
+tags:
+ etags *.[ch]
+
+depend:
+ makedepend -- $(CFLAGS) -- *.[ch]
+
+# DO NOT DELETE THIS LINE -- make depend depends on it.
+
+adler32.o zutil.o: zutil.h zlib.h zconf.h
+gzclose.o gzlib.o gzread.o gzwrite.o: zlib.h zconf.h gzguts.h
+compress.o example.o minigzip.o uncompr.o: zlib.h zconf.h
+crc32.o: zutil.h zlib.h zconf.h crc32.h
+deflate.o: deflate.h zutil.h zlib.h zconf.h
+infback.o inflate.o: zutil.h zlib.h zconf.h inftrees.h inflate.h inffast.h inffixed.h
+inffast.o: zutil.h zlib.h zconf.h inftrees.h inflate.h inffast.h
+inftrees.o: zutil.h zlib.h zconf.h inftrees.h
+trees.o: deflate.h zutil.h zlib.h zconf.h trees.h
+
+adler32.lo zutil.lo: zutil.h zlib.h zconf.h
+gzclose.lo gzlib.lo gzread.lo gzwrite.lo: zlib.h zconf.h gzguts.h
+compress.lo example.lo minigzip.lo uncompr.lo: zlib.h zconf.h
+crc32.lo: zutil.h zlib.h zconf.h crc32.h
+deflate.lo: deflate.h zutil.h zlib.h zconf.h
+infback.lo inflate.lo: zutil.h zlib.h zconf.h inftrees.h inflate.h inffast.h inffixed.h
+inffast.lo: zutil.h zlib.h zconf.h inftrees.h inflate.h inffast.h
+inftrees.lo: zutil.h zlib.h zconf.h inftrees.h
+trees.lo: deflate.h zutil.h zlib.h zconf.h trees.h
ADDED compat/zlib/README
Index: compat/zlib/README
==================================================================
--- compat/zlib/README
+++ compat/zlib/README
@@ -0,0 +1,115 @@
+ZLIB DATA COMPRESSION LIBRARY
+
+zlib 1.2.8 is a general purpose data compression library. All the code is
+thread safe. The data format used by the zlib library is described by RFCs
+(Request for Comments) 1950 to 1952 in the files
+http://tools.ietf.org/html/rfc1950 (zlib format), rfc1951 (deflate format) and
+rfc1952 (gzip format).
+
+All functions of the compression library are documented in the file zlib.h
+(volunteer to write man pages welcome, contact zlib@gzip.org). A usage example
+of the library is given in the file test/example.c which also tests that
+the library is working correctly. Another example is given in the file
+test/minigzip.c. The compression library itself is composed of all source
+files in the root directory.
+
+To compile all files and run the test program, follow the instructions given at
+the top of Makefile.in. In short "./configure; make test", and if that goes
+well, "make install" should work for most flavors of Unix. For Windows, use
+one of the special makefiles in win32/ or contrib/vstudio/ . For VMS, use
+make_vms.com.
+
+Questions about zlib should be sent to , or to Gilles Vollant
+ for the Windows DLL version. The zlib home page is
+http://zlib.net/ . Before reporting a problem, please check this site to
+verify that you have the latest version of zlib; otherwise get the latest
+version and check whether the problem still exists or not.
+
+PLEASE read the zlib FAQ http://zlib.net/zlib_faq.html before asking for help.
+
+Mark Nelson wrote an article about zlib for the Jan. 1997
+issue of Dr. Dobb's Journal; a copy of the article is available at
+http://marknelson.us/1997/01/01/zlib-engine/ .
+
+The changes made in version 1.2.8 are documented in the file ChangeLog.
+
+Unsupported third party contributions are provided in directory contrib/ .
+
+zlib is available in Java using the java.util.zip package, documented at
+http://java.sun.com/developer/technicalArticles/Programming/compression/ .
+
+A Perl interface to zlib written by Paul Marquess is available
+at CPAN (Comprehensive Perl Archive Network) sites, including
+http://search.cpan.org/~pmqs/IO-Compress-Zlib/ .
+
+A Python interface to zlib written by A.M. Kuchling is
+available in Python 1.5 and later versions, see
+http://docs.python.org/library/zlib.html .
+
+zlib is built into tcl: http://wiki.tcl.tk/4610 .
+
+An experimental package to read and write files in .zip format, written on top
+of zlib by Gilles Vollant , is available in the
+contrib/minizip directory of zlib.
+
+
+Notes for some targets:
+
+- For Windows DLL versions, please see win32/DLL_FAQ.txt
+
+- For 64-bit Irix, deflate.c must be compiled without any optimization. With
+ -O, one libpng test fails. The test works in 32 bit mode (with the -n32
+ compiler flag). The compiler bug has been reported to SGI.
+
+- zlib doesn't work with gcc 2.6.3 on a DEC 3000/300LX under OSF/1 2.1 it works
+ when compiled with cc.
+
+- On Digital Unix 4.0D (formely OSF/1) on AlphaServer, the cc option -std1 is
+ necessary to get gzprintf working correctly. This is done by configure.
+
+- zlib doesn't work on HP-UX 9.05 with some versions of /bin/cc. It works with
+ other compilers. Use "make test" to check your compiler.
+
+- gzdopen is not supported on RISCOS or BEOS.
+
+- For PalmOs, see http://palmzlib.sourceforge.net/
+
+
+Acknowledgments:
+
+ The deflate format used by zlib was defined by Phil Katz. The deflate and
+ zlib specifications were written by L. Peter Deutsch. Thanks to all the
+ people who reported problems and suggested various improvements in zlib; they
+ are too numerous to cite here.
+
+Copyright notice:
+
+ (C) 1995-2013 Jean-loup Gailly and Mark Adler
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ Jean-loup Gailly Mark Adler
+ jloup@gzip.org madler@alumni.caltech.edu
+
+If you use the zlib library in a product, we would appreciate *not* receiving
+lengthy legal documents to sign. The sources are provided for free but without
+warranty of any kind. The library has been entirely written by Jean-loup
+Gailly and Mark Adler; it does not include third-party code.
+
+If you redistribute modified sources, we would appreciate that you include in
+the file ChangeLog history information documenting your changes. Please read
+the FAQ for more information on the distribution of modified source versions.
ADDED compat/zlib/adler32.c
Index: compat/zlib/adler32.c
==================================================================
--- compat/zlib/adler32.c
+++ compat/zlib/adler32.c
@@ -0,0 +1,179 @@
+/* adler32.c -- compute the Adler-32 checksum of a data stream
+ * Copyright (C) 1995-2011 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id$ */
+
+#include "zutil.h"
+
+#define local static
+
+local uLong adler32_combine_ OF((uLong adler1, uLong adler2, z_off64_t len2));
+
+#define BASE 65521 /* largest prime smaller than 65536 */
+#define NMAX 5552
+/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */
+
+#define DO1(buf,i) {adler += (buf)[i]; sum2 += adler;}
+#define DO2(buf,i) DO1(buf,i); DO1(buf,i+1);
+#define DO4(buf,i) DO2(buf,i); DO2(buf,i+2);
+#define DO8(buf,i) DO4(buf,i); DO4(buf,i+4);
+#define DO16(buf) DO8(buf,0); DO8(buf,8);
+
+/* use NO_DIVIDE if your processor does not do division in hardware --
+ try it both ways to see which is faster */
+#ifdef NO_DIVIDE
+/* note that this assumes BASE is 65521, where 65536 % 65521 == 15
+ (thank you to John Reiser for pointing this out) */
+# define CHOP(a) \
+ do { \
+ unsigned long tmp = a >> 16; \
+ a &= 0xffffUL; \
+ a += (tmp << 4) - tmp; \
+ } while (0)
+# define MOD28(a) \
+ do { \
+ CHOP(a); \
+ if (a >= BASE) a -= BASE; \
+ } while (0)
+# define MOD(a) \
+ do { \
+ CHOP(a); \
+ MOD28(a); \
+ } while (0)
+# define MOD63(a) \
+ do { /* this assumes a is not negative */ \
+ z_off64_t tmp = a >> 32; \
+ a &= 0xffffffffL; \
+ a += (tmp << 8) - (tmp << 5) + tmp; \
+ tmp = a >> 16; \
+ a &= 0xffffL; \
+ a += (tmp << 4) - tmp; \
+ tmp = a >> 16; \
+ a &= 0xffffL; \
+ a += (tmp << 4) - tmp; \
+ if (a >= BASE) a -= BASE; \
+ } while (0)
+#else
+# define MOD(a) a %= BASE
+# define MOD28(a) a %= BASE
+# define MOD63(a) a %= BASE
+#endif
+
+/* ========================================================================= */
+uLong ZEXPORT adler32(adler, buf, len)
+ uLong adler;
+ const Bytef *buf;
+ uInt len;
+{
+ unsigned long sum2;
+ unsigned n;
+
+ /* split Adler-32 into component sums */
+ sum2 = (adler >> 16) & 0xffff;
+ adler &= 0xffff;
+
+ /* in case user likes doing a byte at a time, keep it fast */
+ if (len == 1) {
+ adler += buf[0];
+ if (adler >= BASE)
+ adler -= BASE;
+ sum2 += adler;
+ if (sum2 >= BASE)
+ sum2 -= BASE;
+ return adler | (sum2 << 16);
+ }
+
+ /* initial Adler-32 value (deferred check for len == 1 speed) */
+ if (buf == Z_NULL)
+ return 1L;
+
+ /* in case short lengths are provided, keep it somewhat fast */
+ if (len < 16) {
+ while (len--) {
+ adler += *buf++;
+ sum2 += adler;
+ }
+ if (adler >= BASE)
+ adler -= BASE;
+ MOD28(sum2); /* only added so many BASE's */
+ return adler | (sum2 << 16);
+ }
+
+ /* do length NMAX blocks -- requires just one modulo operation */
+ while (len >= NMAX) {
+ len -= NMAX;
+ n = NMAX / 16; /* NMAX is divisible by 16 */
+ do {
+ DO16(buf); /* 16 sums unrolled */
+ buf += 16;
+ } while (--n);
+ MOD(adler);
+ MOD(sum2);
+ }
+
+ /* do remaining bytes (less than NMAX, still just one modulo) */
+ if (len) { /* avoid modulos if none remaining */
+ while (len >= 16) {
+ len -= 16;
+ DO16(buf);
+ buf += 16;
+ }
+ while (len--) {
+ adler += *buf++;
+ sum2 += adler;
+ }
+ MOD(adler);
+ MOD(sum2);
+ }
+
+ /* return recombined sums */
+ return adler | (sum2 << 16);
+}
+
+/* ========================================================================= */
+local uLong adler32_combine_(adler1, adler2, len2)
+ uLong adler1;
+ uLong adler2;
+ z_off64_t len2;
+{
+ unsigned long sum1;
+ unsigned long sum2;
+ unsigned rem;
+
+ /* for negative len, return invalid adler32 as a clue for debugging */
+ if (len2 < 0)
+ return 0xffffffffUL;
+
+ /* the derivation of this formula is left as an exercise for the reader */
+ MOD63(len2); /* assumes len2 >= 0 */
+ rem = (unsigned)len2;
+ sum1 = adler1 & 0xffff;
+ sum2 = rem * sum1;
+ MOD(sum2);
+ sum1 += (adler2 & 0xffff) + BASE - 1;
+ sum2 += ((adler1 >> 16) & 0xffff) + ((adler2 >> 16) & 0xffff) + BASE - rem;
+ if (sum1 >= BASE) sum1 -= BASE;
+ if (sum1 >= BASE) sum1 -= BASE;
+ if (sum2 >= (BASE << 1)) sum2 -= (BASE << 1);
+ if (sum2 >= BASE) sum2 -= BASE;
+ return sum1 | (sum2 << 16);
+}
+
+/* ========================================================================= */
+uLong ZEXPORT adler32_combine(adler1, adler2, len2)
+ uLong adler1;
+ uLong adler2;
+ z_off_t len2;
+{
+ return adler32_combine_(adler1, adler2, len2);
+}
+
+uLong ZEXPORT adler32_combine64(adler1, adler2, len2)
+ uLong adler1;
+ uLong adler2;
+ z_off64_t len2;
+{
+ return adler32_combine_(adler1, adler2, len2);
+}
ADDED compat/zlib/amiga/Makefile.pup
Index: compat/zlib/amiga/Makefile.pup
==================================================================
--- compat/zlib/amiga/Makefile.pup
+++ compat/zlib/amiga/Makefile.pup
@@ -0,0 +1,69 @@
+# Amiga powerUP (TM) Makefile
+# makefile for libpng and SAS C V6.58/7.00 PPC compiler
+# Copyright (C) 1998 by Andreas R. Kleinert
+
+LIBNAME = libzip.a
+
+CC = scppc
+CFLAGS = NOSTKCHK NOSINT OPTIMIZE OPTGO OPTPEEP OPTINLOCAL OPTINL \
+ OPTLOOP OPTRDEP=8 OPTDEP=8 OPTCOMP=8 NOVER
+AR = ppc-amigaos-ar cr
+RANLIB = ppc-amigaos-ranlib
+LD = ppc-amigaos-ld -r
+LDFLAGS = -o
+LDLIBS = LIB:scppc.a LIB:end.o
+RM = delete quiet
+
+OBJS = adler32.o compress.o crc32.o gzclose.o gzlib.o gzread.o gzwrite.o \
+ uncompr.o deflate.o trees.o zutil.o inflate.o infback.o inftrees.o inffast.o
+
+TEST_OBJS = example.o minigzip.o
+
+all: example minigzip
+
+check: test
+test: all
+ example
+ echo hello world | minigzip | minigzip -d
+
+$(LIBNAME): $(OBJS)
+ $(AR) $@ $(OBJS)
+ -$(RANLIB) $@
+
+example: example.o $(LIBNAME)
+ $(LD) $(LDFLAGS) $@ LIB:c_ppc.o $@.o $(LIBNAME) $(LDLIBS)
+
+minigzip: minigzip.o $(LIBNAME)
+ $(LD) $(LDFLAGS) $@ LIB:c_ppc.o $@.o $(LIBNAME) $(LDLIBS)
+
+mostlyclean: clean
+clean:
+ $(RM) *.o example minigzip $(LIBNAME) foo.gz
+
+zip:
+ zip -ul9 zlib README ChangeLog Makefile Make????.??? Makefile.?? \
+ descrip.mms *.[ch]
+
+tgz:
+ cd ..; tar cfz zlib/zlib.tgz zlib/README zlib/ChangeLog zlib/Makefile \
+ zlib/Make????.??? zlib/Makefile.?? zlib/descrip.mms zlib/*.[ch]
+
+# DO NOT DELETE THIS LINE -- make depend depends on it.
+
+adler32.o: zlib.h zconf.h
+compress.o: zlib.h zconf.h
+crc32.o: crc32.h zlib.h zconf.h
+deflate.o: deflate.h zutil.h zlib.h zconf.h
+example.o: zlib.h zconf.h
+gzclose.o: zlib.h zconf.h gzguts.h
+gzlib.o: zlib.h zconf.h gzguts.h
+gzread.o: zlib.h zconf.h gzguts.h
+gzwrite.o: zlib.h zconf.h gzguts.h
+inffast.o: zutil.h zlib.h zconf.h inftrees.h inflate.h inffast.h
+inflate.o: zutil.h zlib.h zconf.h inftrees.h inflate.h inffast.h
+infback.o: zutil.h zlib.h zconf.h inftrees.h inflate.h inffast.h
+inftrees.o: zutil.h zlib.h zconf.h inftrees.h
+minigzip.o: zlib.h zconf.h
+trees.o: deflate.h zutil.h zlib.h zconf.h trees.h
+uncompr.o: zlib.h zconf.h
+zutil.o: zutil.h zlib.h zconf.h
ADDED compat/zlib/amiga/Makefile.sas
Index: compat/zlib/amiga/Makefile.sas
==================================================================
--- compat/zlib/amiga/Makefile.sas
+++ compat/zlib/amiga/Makefile.sas
@@ -0,0 +1,68 @@
+# SMakefile for zlib
+# Modified from the standard UNIX Makefile Copyright Jean-loup Gailly
+# Osma Ahvenlampi
+# Amiga, SAS/C 6.56 & Smake
+
+CC=sc
+CFLAGS=OPT
+#CFLAGS=OPT CPU=68030
+#CFLAGS=DEBUG=LINE
+LDFLAGS=LIB z.lib
+
+SCOPTIONS=OPTSCHED OPTINLINE OPTALIAS OPTTIME OPTINLOCAL STRMERGE \
+ NOICONS PARMS=BOTH NOSTACKCHECK UTILLIB NOVERSION ERRORREXX \
+ DEF=POSTINC
+
+OBJS = adler32.o compress.o crc32.o gzclose.o gzlib.o gzread.o gzwrite.o \
+ uncompr.o deflate.o trees.o zutil.o inflate.o infback.o inftrees.o inffast.o
+
+TEST_OBJS = example.o minigzip.o
+
+all: SCOPTIONS example minigzip
+
+check: test
+test: all
+ example
+ echo hello world | minigzip | minigzip -d
+
+install: z.lib
+ copy clone zlib.h zconf.h INCLUDE:
+ copy clone z.lib LIB:
+
+z.lib: $(OBJS)
+ oml z.lib r $(OBJS)
+
+example: example.o z.lib
+ $(CC) $(CFLAGS) LINK TO $@ example.o $(LDFLAGS)
+
+minigzip: minigzip.o z.lib
+ $(CC) $(CFLAGS) LINK TO $@ minigzip.o $(LDFLAGS)
+
+mostlyclean: clean
+clean:
+ -delete force quiet example minigzip *.o z.lib foo.gz *.lnk SCOPTIONS
+
+SCOPTIONS: Makefile.sas
+ copy to $@ 64K on 16-bit machine: */
+ if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR;
+#endif
+ stream.next_out = dest;
+ stream.avail_out = (uInt)*destLen;
+ if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR;
+
+ stream.zalloc = (alloc_func)0;
+ stream.zfree = (free_func)0;
+ stream.opaque = (voidpf)0;
+
+ err = deflateInit(&stream, level);
+ if (err != Z_OK) return err;
+
+ err = deflate(&stream, Z_FINISH);
+ if (err != Z_STREAM_END) {
+ deflateEnd(&stream);
+ return err == Z_OK ? Z_BUF_ERROR : err;
+ }
+ *destLen = stream.total_out;
+
+ err = deflateEnd(&stream);
+ return err;
+}
+
+/* ===========================================================================
+ */
+int ZEXPORT compress (dest, destLen, source, sourceLen)
+ Bytef *dest;
+ uLongf *destLen;
+ const Bytef *source;
+ uLong sourceLen;
+{
+ return compress2(dest, destLen, source, sourceLen, Z_DEFAULT_COMPRESSION);
+}
+
+/* ===========================================================================
+ If the default memLevel or windowBits for deflateInit() is changed, then
+ this function needs to be updated.
+ */
+uLong ZEXPORT compressBound (sourceLen)
+ uLong sourceLen;
+{
+ return sourceLen + (sourceLen >> 12) + (sourceLen >> 14) +
+ (sourceLen >> 25) + 13;
+}
ADDED compat/zlib/configure
Index: compat/zlib/configure
==================================================================
--- compat/zlib/configure
+++ compat/zlib/configure
@@ -0,0 +1,831 @@
+#!/bin/sh
+# configure script for zlib.
+#
+# Normally configure builds both a static and a shared library.
+# If you want to build just a static library, use: ./configure --static
+#
+# To impose specific compiler or flags or install directory, use for example:
+# prefix=$HOME CC=cc CFLAGS="-O4" ./configure
+# or for csh/tcsh users:
+# (setenv prefix $HOME; setenv CC cc; setenv CFLAGS "-O4"; ./configure)
+
+# Incorrect settings of CC or CFLAGS may prevent creating a shared library.
+# If you have problems, try without defining CC and CFLAGS before reporting
+# an error.
+
+# start off configure.log
+echo -------------------- >> configure.log
+echo $0 $* >> configure.log
+date >> configure.log
+
+# set command prefix for cross-compilation
+if [ -n "${CHOST}" ]; then
+ uname="`echo "${CHOST}" | sed -e 's/^[^-]*-\([^-]*\)$/\1/' -e 's/^[^-]*-[^-]*-\([^-]*\)$/\1/' -e 's/^[^-]*-[^-]*-\([^-]*\)-.*$/\1/'`"
+ CROSS_PREFIX="${CHOST}-"
+fi
+
+# destination name for static library
+STATICLIB=libz.a
+
+# extract zlib version numbers from zlib.h
+VER=`sed -n -e '/VERSION "/s/.*"\(.*\)".*/\1/p' < zlib.h`
+VER3=`sed -n -e '/VERSION "/s/.*"\([0-9]*\\.[0-9]*\\.[0-9]*\).*/\1/p' < zlib.h`
+VER2=`sed -n -e '/VERSION "/s/.*"\([0-9]*\\.[0-9]*\)\\..*/\1/p' < zlib.h`
+VER1=`sed -n -e '/VERSION "/s/.*"\([0-9]*\)\\..*/\1/p' < zlib.h`
+
+# establish commands for library building
+if "${CROSS_PREFIX}ar" --version >/dev/null 2>/dev/null || test $? -lt 126; then
+ AR=${AR-"${CROSS_PREFIX}ar"}
+ test -n "${CROSS_PREFIX}" && echo Using ${AR} | tee -a configure.log
+else
+ AR=${AR-"ar"}
+ test -n "${CROSS_PREFIX}" && echo Using ${AR} | tee -a configure.log
+fi
+ARFLAGS=${ARFLAGS-"rc"}
+if "${CROSS_PREFIX}ranlib" --version >/dev/null 2>/dev/null || test $? -lt 126; then
+ RANLIB=${RANLIB-"${CROSS_PREFIX}ranlib"}
+ test -n "${CROSS_PREFIX}" && echo Using ${RANLIB} | tee -a configure.log
+else
+ RANLIB=${RANLIB-"ranlib"}
+fi
+if "${CROSS_PREFIX}nm" --version >/dev/null 2>/dev/null || test $? -lt 126; then
+ NM=${NM-"${CROSS_PREFIX}nm"}
+ test -n "${CROSS_PREFIX}" && echo Using ${NM} | tee -a configure.log
+else
+ NM=${NM-"nm"}
+fi
+
+# set defaults before processing command line options
+LDCONFIG=${LDCONFIG-"ldconfig"}
+LDSHAREDLIBC="${LDSHAREDLIBC--lc}"
+ARCHS=
+prefix=${prefix-/usr/local}
+exec_prefix=${exec_prefix-'${prefix}'}
+libdir=${libdir-'${exec_prefix}/lib'}
+sharedlibdir=${sharedlibdir-'${libdir}'}
+includedir=${includedir-'${prefix}/include'}
+mandir=${mandir-'${prefix}/share/man'}
+shared_ext='.so'
+shared=1
+solo=0
+cover=0
+zprefix=0
+zconst=0
+build64=0
+gcc=0
+old_cc="$CC"
+old_cflags="$CFLAGS"
+OBJC='$(OBJZ) $(OBJG)'
+PIC_OBJC='$(PIC_OBJZ) $(PIC_OBJG)'
+
+# leave this script, optionally in a bad way
+leave()
+{
+ if test "$*" != "0"; then
+ echo "** $0 aborting." | tee -a configure.log
+ fi
+ rm -f $test.[co] $test $test$shared_ext $test.gcno ./--version
+ echo -------------------- >> configure.log
+ echo >> configure.log
+ echo >> configure.log
+ exit $1
+}
+
+# process command line options
+while test $# -ge 1
+do
+case "$1" in
+ -h* | --help)
+ echo 'usage:' | tee -a configure.log
+ echo ' configure [--const] [--zprefix] [--prefix=PREFIX] [--eprefix=EXPREFIX]' | tee -a configure.log
+ echo ' [--static] [--64] [--libdir=LIBDIR] [--sharedlibdir=LIBDIR]' | tee -a configure.log
+ echo ' [--includedir=INCLUDEDIR] [--archs="-arch i386 -arch x86_64"]' | tee -a configure.log
+ exit 0 ;;
+ -p*=* | --prefix=*) prefix=`echo $1 | sed 's/.*=//'`; shift ;;
+ -e*=* | --eprefix=*) exec_prefix=`echo $1 | sed 's/.*=//'`; shift ;;
+ -l*=* | --libdir=*) libdir=`echo $1 | sed 's/.*=//'`; shift ;;
+ --sharedlibdir=*) sharedlibdir=`echo $1 | sed 's/.*=//'`; shift ;;
+ -i*=* | --includedir=*) includedir=`echo $1 | sed 's/.*=//'`;shift ;;
+ -u*=* | --uname=*) uname=`echo $1 | sed 's/.*=//'`;shift ;;
+ -p* | --prefix) prefix="$2"; shift; shift ;;
+ -e* | --eprefix) exec_prefix="$2"; shift; shift ;;
+ -l* | --libdir) libdir="$2"; shift; shift ;;
+ -i* | --includedir) includedir="$2"; shift; shift ;;
+ -s* | --shared | --enable-shared) shared=1; shift ;;
+ -t | --static) shared=0; shift ;;
+ --solo) solo=1; shift ;;
+ --cover) cover=1; shift ;;
+ -z* | --zprefix) zprefix=1; shift ;;
+ -6* | --64) build64=1; shift ;;
+ -a*=* | --archs=*) ARCHS=`echo $1 | sed 's/.*=//'`; shift ;;
+ --sysconfdir=*) echo "ignored option: --sysconfdir" | tee -a configure.log; shift ;;
+ --localstatedir=*) echo "ignored option: --localstatedir" | tee -a configure.log; shift ;;
+ -c* | --const) zconst=1; shift ;;
+ *)
+ echo "unknown option: $1" | tee -a configure.log
+ echo "$0 --help for help" | tee -a configure.log
+ leave 1;;
+ esac
+done
+
+# temporary file name
+test=ztest$$
+
+# put arguments in log, also put test file in log if used in arguments
+show()
+{
+ case "$*" in
+ *$test.c*)
+ echo === $test.c === >> configure.log
+ cat $test.c >> configure.log
+ echo === >> configure.log;;
+ esac
+ echo $* >> configure.log
+}
+
+# check for gcc vs. cc and set compile and link flags based on the system identified by uname
+cat > $test.c <&1` in
+ *gcc*) gcc=1 ;;
+esac
+
+show $cc -c $test.c
+if test "$gcc" -eq 1 && ($cc -c $test.c) >> configure.log 2>&1; then
+ echo ... using gcc >> configure.log
+ CC="$cc"
+ CFLAGS="${CFLAGS--O3} ${ARCHS}"
+ SFLAGS="${CFLAGS--O3} -fPIC"
+ LDFLAGS="${LDFLAGS} ${ARCHS}"
+ if test $build64 -eq 1; then
+ CFLAGS="${CFLAGS} -m64"
+ SFLAGS="${SFLAGS} -m64"
+ fi
+ if test "${ZLIBGCCWARN}" = "YES"; then
+ if test "$zconst" -eq 1; then
+ CFLAGS="${CFLAGS} -Wall -Wextra -Wcast-qual -pedantic -DZLIB_CONST"
+ else
+ CFLAGS="${CFLAGS} -Wall -Wextra -pedantic"
+ fi
+ fi
+ if test -z "$uname"; then
+ uname=`(uname -s || echo unknown) 2>/dev/null`
+ fi
+ case "$uname" in
+ Linux* | linux* | GNU | GNU/* | solaris*)
+ LDSHARED=${LDSHARED-"$cc -shared -Wl,-soname,libz.so.1,--version-script,zlib.map"} ;;
+ *BSD | *bsd* | DragonFly)
+ LDSHARED=${LDSHARED-"$cc -shared -Wl,-soname,libz.so.1,--version-script,zlib.map"}
+ LDCONFIG="ldconfig -m" ;;
+ CYGWIN* | Cygwin* | cygwin* | OS/2*)
+ EXE='.exe' ;;
+ MINGW* | mingw*)
+# temporary bypass
+ rm -f $test.[co] $test $test$shared_ext
+ echo "Please use win32/Makefile.gcc instead." | tee -a configure.log
+ leave 1
+ LDSHARED=${LDSHARED-"$cc -shared"}
+ LDSHAREDLIBC=""
+ EXE='.exe' ;;
+ QNX*) # This is for QNX6. I suppose that the QNX rule below is for QNX2,QNX4
+ # (alain.bonnefoy@icbt.com)
+ LDSHARED=${LDSHARED-"$cc -shared -Wl,-hlibz.so.1"} ;;
+ HP-UX*)
+ LDSHARED=${LDSHARED-"$cc -shared $SFLAGS"}
+ case `(uname -m || echo unknown) 2>/dev/null` in
+ ia64)
+ shared_ext='.so'
+ SHAREDLIB='libz.so' ;;
+ *)
+ shared_ext='.sl'
+ SHAREDLIB='libz.sl' ;;
+ esac ;;
+ Darwin* | darwin*)
+ shared_ext='.dylib'
+ SHAREDLIB=libz$shared_ext
+ SHAREDLIBV=libz.$VER$shared_ext
+ SHAREDLIBM=libz.$VER1$shared_ext
+ LDSHARED=${LDSHARED-"$cc -dynamiclib -install_name $libdir/$SHAREDLIBM -compatibility_version $VER1 -current_version $VER3"}
+ if libtool -V 2>&1 | grep Apple > /dev/null; then
+ AR="libtool"
+ else
+ AR="/usr/bin/libtool"
+ fi
+ ARFLAGS="-o" ;;
+ *) LDSHARED=${LDSHARED-"$cc -shared"} ;;
+ esac
+else
+ # find system name and corresponding cc options
+ CC=${CC-cc}
+ gcc=0
+ echo ... using $CC >> configure.log
+ if test -z "$uname"; then
+ uname=`(uname -sr || echo unknown) 2>/dev/null`
+ fi
+ case "$uname" in
+ HP-UX*) SFLAGS=${CFLAGS-"-O +z"}
+ CFLAGS=${CFLAGS-"-O"}
+# LDSHARED=${LDSHARED-"ld -b +vnocompatwarnings"}
+ LDSHARED=${LDSHARED-"ld -b"}
+ case `(uname -m || echo unknown) 2>/dev/null` in
+ ia64)
+ shared_ext='.so'
+ SHAREDLIB='libz.so' ;;
+ *)
+ shared_ext='.sl'
+ SHAREDLIB='libz.sl' ;;
+ esac ;;
+ IRIX*) SFLAGS=${CFLAGS-"-ansi -O2 -rpath ."}
+ CFLAGS=${CFLAGS-"-ansi -O2"}
+ LDSHARED=${LDSHARED-"cc -shared -Wl,-soname,libz.so.1"} ;;
+ OSF1\ V4*) SFLAGS=${CFLAGS-"-O -std1"}
+ CFLAGS=${CFLAGS-"-O -std1"}
+ LDFLAGS="${LDFLAGS} -Wl,-rpath,."
+ LDSHARED=${LDSHARED-"cc -shared -Wl,-soname,libz.so -Wl,-msym -Wl,-rpath,$(libdir) -Wl,-set_version,${VER}:1.0"} ;;
+ OSF1*) SFLAGS=${CFLAGS-"-O -std1"}
+ CFLAGS=${CFLAGS-"-O -std1"}
+ LDSHARED=${LDSHARED-"cc -shared -Wl,-soname,libz.so.1"} ;;
+ QNX*) SFLAGS=${CFLAGS-"-4 -O"}
+ CFLAGS=${CFLAGS-"-4 -O"}
+ LDSHARED=${LDSHARED-"cc"}
+ RANLIB=${RANLIB-"true"}
+ AR="cc"
+ ARFLAGS="-A" ;;
+ SCO_SV\ 3.2*) SFLAGS=${CFLAGS-"-O3 -dy -KPIC "}
+ CFLAGS=${CFLAGS-"-O3"}
+ LDSHARED=${LDSHARED-"cc -dy -KPIC -G"} ;;
+ SunOS\ 5* | solaris*)
+ LDSHARED=${LDSHARED-"cc -G -h libz$shared_ext.$VER1"}
+ SFLAGS=${CFLAGS-"-fast -KPIC"}
+ CFLAGS=${CFLAGS-"-fast"}
+ if test $build64 -eq 1; then
+ # old versions of SunPRO/Workshop/Studio don't support -m64,
+ # but newer ones do. Check for it.
+ flag64=`$CC -flags | egrep -- '^-m64'`
+ if test x"$flag64" != x"" ; then
+ CFLAGS="${CFLAGS} -m64"
+ SFLAGS="${SFLAGS} -m64"
+ else
+ case `(uname -m || echo unknown) 2>/dev/null` in
+ i86*)
+ SFLAGS="$SFLAGS -xarch=amd64"
+ CFLAGS="$CFLAGS -xarch=amd64" ;;
+ *)
+ SFLAGS="$SFLAGS -xarch=v9"
+ CFLAGS="$CFLAGS -xarch=v9" ;;
+ esac
+ fi
+ fi
+ ;;
+ SunOS\ 4*) SFLAGS=${CFLAGS-"-O2 -PIC"}
+ CFLAGS=${CFLAGS-"-O2"}
+ LDSHARED=${LDSHARED-"ld"} ;;
+ SunStudio\ 9*) SFLAGS=${CFLAGS-"-fast -xcode=pic32 -xtarget=ultra3 -xarch=v9b"}
+ CFLAGS=${CFLAGS-"-fast -xtarget=ultra3 -xarch=v9b"}
+ LDSHARED=${LDSHARED-"cc -xarch=v9b"} ;;
+ UNIX_System_V\ 4.2.0)
+ SFLAGS=${CFLAGS-"-KPIC -O"}
+ CFLAGS=${CFLAGS-"-O"}
+ LDSHARED=${LDSHARED-"cc -G"} ;;
+ UNIX_SV\ 4.2MP)
+ SFLAGS=${CFLAGS-"-Kconform_pic -O"}
+ CFLAGS=${CFLAGS-"-O"}
+ LDSHARED=${LDSHARED-"cc -G"} ;;
+ OpenUNIX\ 5)
+ SFLAGS=${CFLAGS-"-KPIC -O"}
+ CFLAGS=${CFLAGS-"-O"}
+ LDSHARED=${LDSHARED-"cc -G"} ;;
+ AIX*) # Courtesy of dbakker@arrayasolutions.com
+ SFLAGS=${CFLAGS-"-O -qmaxmem=8192"}
+ CFLAGS=${CFLAGS-"-O -qmaxmem=8192"}
+ LDSHARED=${LDSHARED-"xlc -G"} ;;
+ # send working options for other systems to zlib@gzip.org
+ *) SFLAGS=${CFLAGS-"-O"}
+ CFLAGS=${CFLAGS-"-O"}
+ LDSHARED=${LDSHARED-"cc -shared"} ;;
+ esac
+fi
+
+# destination names for shared library if not defined above
+SHAREDLIB=${SHAREDLIB-"libz$shared_ext"}
+SHAREDLIBV=${SHAREDLIBV-"libz$shared_ext.$VER"}
+SHAREDLIBM=${SHAREDLIBM-"libz$shared_ext.$VER1"}
+
+echo >> configure.log
+
+# define functions for testing compiler and library characteristics and logging the results
+
+cat > $test.c </dev/null; then
+ try()
+ {
+ show $*
+ test "`( $* ) 2>&1 | tee -a configure.log`" = ""
+ }
+ echo - using any output from compiler to indicate an error >> configure.log
+else
+try()
+{
+ show $*
+ ( $* ) >> configure.log 2>&1
+ ret=$?
+ if test $ret -ne 0; then
+ echo "(exit code "$ret")" >> configure.log
+ fi
+ return $ret
+}
+fi
+
+tryboth()
+{
+ show $*
+ got=`( $* ) 2>&1`
+ ret=$?
+ printf %s "$got" >> configure.log
+ if test $ret -ne 0; then
+ return $ret
+ fi
+ test "$got" = ""
+}
+
+cat > $test.c << EOF
+int foo() { return 0; }
+EOF
+echo "Checking for obsessive-compulsive compiler options..." >> configure.log
+if try $CC -c $CFLAGS $test.c; then
+ :
+else
+ echo "Compiler error reporting is too harsh for $0 (perhaps remove -Werror)." | tee -a configure.log
+ leave 1
+fi
+
+echo >> configure.log
+
+# see if shared library build supported
+cat > $test.c <> configure.log
+ show "$NM $test.o | grep _hello"
+ if test "`$NM $test.o | grep _hello | tee -a configure.log`" = ""; then
+ CPP="$CPP -DNO_UNDERLINE"
+ echo Checking for underline in external names... No. | tee -a configure.log
+ else
+ echo Checking for underline in external names... Yes. | tee -a configure.log
+ fi ;;
+esac
+
+echo >> configure.log
+
+# check for large file support, and if none, check for fseeko()
+cat > $test.c <
+off64_t dummy = 0;
+EOF
+if try $CC -c $CFLAGS -D_LARGEFILE64_SOURCE=1 $test.c; then
+ CFLAGS="${CFLAGS} -D_LARGEFILE64_SOURCE=1"
+ SFLAGS="${SFLAGS} -D_LARGEFILE64_SOURCE=1"
+ ALL="${ALL} all64"
+ TEST="${TEST} test64"
+ echo "Checking for off64_t... Yes." | tee -a configure.log
+ echo "Checking for fseeko... Yes." | tee -a configure.log
+else
+ echo "Checking for off64_t... No." | tee -a configure.log
+ echo >> configure.log
+ cat > $test.c <
+int main(void) {
+ fseeko(NULL, 0, 0);
+ return 0;
+}
+EOF
+ if try $CC $CFLAGS -o $test $test.c; then
+ echo "Checking for fseeko... Yes." | tee -a configure.log
+ else
+ CFLAGS="${CFLAGS} -DNO_FSEEKO"
+ SFLAGS="${SFLAGS} -DNO_FSEEKO"
+ echo "Checking for fseeko... No." | tee -a configure.log
+ fi
+fi
+
+echo >> configure.log
+
+# check for strerror() for use by gz* functions
+cat > $test.c <
+#include
+int main() { return strlen(strerror(errno)); }
+EOF
+if try $CC $CFLAGS -o $test $test.c; then
+ echo "Checking for strerror... Yes." | tee -a configure.log
+else
+ CFLAGS="${CFLAGS} -DNO_STRERROR"
+ SFLAGS="${SFLAGS} -DNO_STRERROR"
+ echo "Checking for strerror... No." | tee -a configure.log
+fi
+
+# copy clean zconf.h for subsequent edits
+cp -p zconf.h.in zconf.h
+
+echo >> configure.log
+
+# check for unistd.h and save result in zconf.h
+cat > $test.c <
+int main() { return 0; }
+EOF
+if try $CC -c $CFLAGS $test.c; then
+ sed < zconf.h "/^#ifdef HAVE_UNISTD_H.* may be/s/def HAVE_UNISTD_H\(.*\) may be/ 1\1 was/" > zconf.temp.h
+ mv zconf.temp.h zconf.h
+ echo "Checking for unistd.h... Yes." | tee -a configure.log
+else
+ echo "Checking for unistd.h... No." | tee -a configure.log
+fi
+
+echo >> configure.log
+
+# check for stdarg.h and save result in zconf.h
+cat > $test.c <
+int main() { return 0; }
+EOF
+if try $CC -c $CFLAGS $test.c; then
+ sed < zconf.h "/^#ifdef HAVE_STDARG_H.* may be/s/def HAVE_STDARG_H\(.*\) may be/ 1\1 was/" > zconf.temp.h
+ mv zconf.temp.h zconf.h
+ echo "Checking for stdarg.h... Yes." | tee -a configure.log
+else
+ echo "Checking for stdarg.h... No." | tee -a configure.log
+fi
+
+# if the z_ prefix was requested, save that in zconf.h
+if test $zprefix -eq 1; then
+ sed < zconf.h "/#ifdef Z_PREFIX.* may be/s/def Z_PREFIX\(.*\) may be/ 1\1 was/" > zconf.temp.h
+ mv zconf.temp.h zconf.h
+ echo >> configure.log
+ echo "Using z_ prefix on all symbols." | tee -a configure.log
+fi
+
+# if --solo compilation was requested, save that in zconf.h and remove gz stuff from object lists
+if test $solo -eq 1; then
+ sed '/#define ZCONF_H/a\
+#define Z_SOLO
+
+' < zconf.h > zconf.temp.h
+ mv zconf.temp.h zconf.h
+OBJC='$(OBJZ)'
+PIC_OBJC='$(PIC_OBJZ)'
+fi
+
+# if code coverage testing was requested, use older gcc if defined, e.g. "gcc-4.2" on Mac OS X
+if test $cover -eq 1; then
+ CFLAGS="${CFLAGS} -fprofile-arcs -ftest-coverage"
+ if test -n "$GCC_CLASSIC"; then
+ CC=$GCC_CLASSIC
+ fi
+fi
+
+echo >> configure.log
+
+# conduct a series of tests to resolve eight possible cases of using "vs" or "s" printf functions
+# (using stdarg or not), with or without "n" (proving size of buffer), and with or without a
+# return value. The most secure result is vsnprintf() with a return value. snprintf() with a
+# return value is secure as well, but then gzprintf() will be limited to 20 arguments.
+cat > $test.c <
+#include
+#include "zconf.h"
+int main()
+{
+#ifndef STDC
+ choke me
+#endif
+ return 0;
+}
+EOF
+if try $CC -c $CFLAGS $test.c; then
+ echo "Checking whether to use vs[n]printf() or s[n]printf()... using vs[n]printf()." | tee -a configure.log
+
+ echo >> configure.log
+ cat > $test.c <
+#include
+int mytest(const char *fmt, ...)
+{
+ char buf[20];
+ va_list ap;
+ va_start(ap, fmt);
+ vsnprintf(buf, sizeof(buf), fmt, ap);
+ va_end(ap);
+ return 0;
+}
+int main()
+{
+ return (mytest("Hello%d\n", 1));
+}
+EOF
+ if try $CC $CFLAGS -o $test $test.c; then
+ echo "Checking for vsnprintf() in stdio.h... Yes." | tee -a configure.log
+
+ echo >> configure.log
+ cat >$test.c <
+#include
+int mytest(const char *fmt, ...)
+{
+ int n;
+ char buf[20];
+ va_list ap;
+ va_start(ap, fmt);
+ n = vsnprintf(buf, sizeof(buf), fmt, ap);
+ va_end(ap);
+ return n;
+}
+int main()
+{
+ return (mytest("Hello%d\n", 1));
+}
+EOF
+
+ if try $CC -c $CFLAGS $test.c; then
+ echo "Checking for return value of vsnprintf()... Yes." | tee -a configure.log
+ else
+ CFLAGS="$CFLAGS -DHAS_vsnprintf_void"
+ SFLAGS="$SFLAGS -DHAS_vsnprintf_void"
+ echo "Checking for return value of vsnprintf()... No." | tee -a configure.log
+ echo " WARNING: apparently vsnprintf() does not return a value. zlib" | tee -a configure.log
+ echo " can build but will be open to possible string-format security" | tee -a configure.log
+ echo " vulnerabilities." | tee -a configure.log
+ fi
+ else
+ CFLAGS="$CFLAGS -DNO_vsnprintf"
+ SFLAGS="$SFLAGS -DNO_vsnprintf"
+ echo "Checking for vsnprintf() in stdio.h... No." | tee -a configure.log
+ echo " WARNING: vsnprintf() not found, falling back to vsprintf(). zlib" | tee -a configure.log
+ echo " can build but will be open to possible buffer-overflow security" | tee -a configure.log
+ echo " vulnerabilities." | tee -a configure.log
+
+ echo >> configure.log
+ cat >$test.c <
+#include
+int mytest(const char *fmt, ...)
+{
+ int n;
+ char buf[20];
+ va_list ap;
+ va_start(ap, fmt);
+ n = vsprintf(buf, fmt, ap);
+ va_end(ap);
+ return n;
+}
+int main()
+{
+ return (mytest("Hello%d\n", 1));
+}
+EOF
+
+ if try $CC -c $CFLAGS $test.c; then
+ echo "Checking for return value of vsprintf()... Yes." | tee -a configure.log
+ else
+ CFLAGS="$CFLAGS -DHAS_vsprintf_void"
+ SFLAGS="$SFLAGS -DHAS_vsprintf_void"
+ echo "Checking for return value of vsprintf()... No." | tee -a configure.log
+ echo " WARNING: apparently vsprintf() does not return a value. zlib" | tee -a configure.log
+ echo " can build but will be open to possible string-format security" | tee -a configure.log
+ echo " vulnerabilities." | tee -a configure.log
+ fi
+ fi
+else
+ echo "Checking whether to use vs[n]printf() or s[n]printf()... using s[n]printf()." | tee -a configure.log
+
+ echo >> configure.log
+ cat >$test.c <
+int mytest()
+{
+ char buf[20];
+ snprintf(buf, sizeof(buf), "%s", "foo");
+ return 0;
+}
+int main()
+{
+ return (mytest());
+}
+EOF
+
+ if try $CC $CFLAGS -o $test $test.c; then
+ echo "Checking for snprintf() in stdio.h... Yes." | tee -a configure.log
+
+ echo >> configure.log
+ cat >$test.c <
+int mytest()
+{
+ char buf[20];
+ return snprintf(buf, sizeof(buf), "%s", "foo");
+}
+int main()
+{
+ return (mytest());
+}
+EOF
+
+ if try $CC -c $CFLAGS $test.c; then
+ echo "Checking for return value of snprintf()... Yes." | tee -a configure.log
+ else
+ CFLAGS="$CFLAGS -DHAS_snprintf_void"
+ SFLAGS="$SFLAGS -DHAS_snprintf_void"
+ echo "Checking for return value of snprintf()... No." | tee -a configure.log
+ echo " WARNING: apparently snprintf() does not return a value. zlib" | tee -a configure.log
+ echo " can build but will be open to possible string-format security" | tee -a configure.log
+ echo " vulnerabilities." | tee -a configure.log
+ fi
+ else
+ CFLAGS="$CFLAGS -DNO_snprintf"
+ SFLAGS="$SFLAGS -DNO_snprintf"
+ echo "Checking for snprintf() in stdio.h... No." | tee -a configure.log
+ echo " WARNING: snprintf() not found, falling back to sprintf(). zlib" | tee -a configure.log
+ echo " can build but will be open to possible buffer-overflow security" | tee -a configure.log
+ echo " vulnerabilities." | tee -a configure.log
+
+ echo >> configure.log
+ cat >$test.c <
+int mytest()
+{
+ char buf[20];
+ return sprintf(buf, "%s", "foo");
+}
+int main()
+{
+ return (mytest());
+}
+EOF
+
+ if try $CC -c $CFLAGS $test.c; then
+ echo "Checking for return value of sprintf()... Yes." | tee -a configure.log
+ else
+ CFLAGS="$CFLAGS -DHAS_sprintf_void"
+ SFLAGS="$SFLAGS -DHAS_sprintf_void"
+ echo "Checking for return value of sprintf()... No." | tee -a configure.log
+ echo " WARNING: apparently sprintf() does not return a value. zlib" | tee -a configure.log
+ echo " can build but will be open to possible string-format security" | tee -a configure.log
+ echo " vulnerabilities." | tee -a configure.log
+ fi
+ fi
+fi
+
+# see if we can hide zlib internal symbols that are linked between separate source files
+if test "$gcc" -eq 1; then
+ echo >> configure.log
+ cat > $test.c <> configure.log
+echo ALL = $ALL >> configure.log
+echo AR = $AR >> configure.log
+echo ARFLAGS = $ARFLAGS >> configure.log
+echo CC = $CC >> configure.log
+echo CFLAGS = $CFLAGS >> configure.log
+echo CPP = $CPP >> configure.log
+echo EXE = $EXE >> configure.log
+echo LDCONFIG = $LDCONFIG >> configure.log
+echo LDFLAGS = $LDFLAGS >> configure.log
+echo LDSHARED = $LDSHARED >> configure.log
+echo LDSHAREDLIBC = $LDSHAREDLIBC >> configure.log
+echo OBJC = $OBJC >> configure.log
+echo PIC_OBJC = $PIC_OBJC >> configure.log
+echo RANLIB = $RANLIB >> configure.log
+echo SFLAGS = $SFLAGS >> configure.log
+echo SHAREDLIB = $SHAREDLIB >> configure.log
+echo SHAREDLIBM = $SHAREDLIBM >> configure.log
+echo SHAREDLIBV = $SHAREDLIBV >> configure.log
+echo STATICLIB = $STATICLIB >> configure.log
+echo TEST = $TEST >> configure.log
+echo VER = $VER >> configure.log
+echo Z_U4 = $Z_U4 >> configure.log
+echo exec_prefix = $exec_prefix >> configure.log
+echo includedir = $includedir >> configure.log
+echo libdir = $libdir >> configure.log
+echo mandir = $mandir >> configure.log
+echo prefix = $prefix >> configure.log
+echo sharedlibdir = $sharedlibdir >> configure.log
+echo uname = $uname >> configure.log
+
+# udpate Makefile with the configure results
+sed < Makefile.in "
+/^CC *=/s#=.*#=$CC#
+/^CFLAGS *=/s#=.*#=$CFLAGS#
+/^SFLAGS *=/s#=.*#=$SFLAGS#
+/^LDFLAGS *=/s#=.*#=$LDFLAGS#
+/^LDSHARED *=/s#=.*#=$LDSHARED#
+/^CPP *=/s#=.*#=$CPP#
+/^STATICLIB *=/s#=.*#=$STATICLIB#
+/^SHAREDLIB *=/s#=.*#=$SHAREDLIB#
+/^SHAREDLIBV *=/s#=.*#=$SHAREDLIBV#
+/^SHAREDLIBM *=/s#=.*#=$SHAREDLIBM#
+/^AR *=/s#=.*#=$AR#
+/^ARFLAGS *=/s#=.*#=$ARFLAGS#
+/^RANLIB *=/s#=.*#=$RANLIB#
+/^LDCONFIG *=/s#=.*#=$LDCONFIG#
+/^LDSHAREDLIBC *=/s#=.*#=$LDSHAREDLIBC#
+/^EXE *=/s#=.*#=$EXE#
+/^prefix *=/s#=.*#=$prefix#
+/^exec_prefix *=/s#=.*#=$exec_prefix#
+/^libdir *=/s#=.*#=$libdir#
+/^sharedlibdir *=/s#=.*#=$sharedlibdir#
+/^includedir *=/s#=.*#=$includedir#
+/^mandir *=/s#=.*#=$mandir#
+/^OBJC *=/s#=.*#= $OBJC#
+/^PIC_OBJC *=/s#=.*#= $PIC_OBJC#
+/^all: */s#:.*#: $ALL#
+/^test: */s#:.*#: $TEST#
+" > Makefile
+
+# create zlib.pc with the configure results
+sed < zlib.pc.in "
+/^CC *=/s#=.*#=$CC#
+/^CFLAGS *=/s#=.*#=$CFLAGS#
+/^CPP *=/s#=.*#=$CPP#
+/^LDSHARED *=/s#=.*#=$LDSHARED#
+/^STATICLIB *=/s#=.*#=$STATICLIB#
+/^SHAREDLIB *=/s#=.*#=$SHAREDLIB#
+/^SHAREDLIBV *=/s#=.*#=$SHAREDLIBV#
+/^SHAREDLIBM *=/s#=.*#=$SHAREDLIBM#
+/^AR *=/s#=.*#=$AR#
+/^ARFLAGS *=/s#=.*#=$ARFLAGS#
+/^RANLIB *=/s#=.*#=$RANLIB#
+/^EXE *=/s#=.*#=$EXE#
+/^prefix *=/s#=.*#=$prefix#
+/^exec_prefix *=/s#=.*#=$exec_prefix#
+/^libdir *=/s#=.*#=$libdir#
+/^sharedlibdir *=/s#=.*#=$sharedlibdir#
+/^includedir *=/s#=.*#=$includedir#
+/^mandir *=/s#=.*#=$mandir#
+/^LDFLAGS *=/s#=.*#=$LDFLAGS#
+" | sed -e "
+s/\@VERSION\@/$VER/g;
+" > zlib.pc
+
+# done
+leave 0
ADDED compat/zlib/contrib/README.contrib
Index: compat/zlib/contrib/README.contrib
==================================================================
--- compat/zlib/contrib/README.contrib
+++ compat/zlib/contrib/README.contrib
@@ -0,0 +1,78 @@
+All files under this contrib directory are UNSUPPORTED. There were
+provided by users of zlib and were not tested by the authors of zlib.
+Use at your own risk. Please contact the authors of the contributions
+for help about these, not the zlib authors. Thanks.
+
+
+ada/ by Dmitriy Anisimkov
+ Support for Ada
+ See http://zlib-ada.sourceforge.net/
+
+amd64/ by Mikhail Teterin
+ asm code for AMD64
+ See patch at http://www.freebsd.org/cgi/query-pr.cgi?pr=bin/96393
+
+asm686/ by Brian Raiter
+ asm code for Pentium and PPro/PII, using the AT&T (GNU as) syntax
+ See http://www.muppetlabs.com/~breadbox/software/assembly.html
+
+blast/ by Mark Adler
+ Decompressor for output of PKWare Data Compression Library (DCL)
+
+delphi/ by Cosmin Truta
+ Support for Delphi and C++ Builder
+
+dotzlib/ by Henrik Ravn
+ Support for Microsoft .Net and Visual C++ .Net
+
+gcc_gvmat64/by Gilles Vollant
+ GCC Version of x86 64-bit (AMD64 and Intel EM64t) code for x64
+ assembler to replace longest_match() and inflate_fast()
+
+infback9/ by Mark Adler
+ Unsupported diffs to infback to decode the deflate64 format
+
+inflate86/ by Chris Anderson
+ Tuned x86 gcc asm code to replace inflate_fast()
+
+iostream/ by Kevin Ruland
+ A C++ I/O streams interface to the zlib gz* functions
+
+iostream2/ by Tyge Løvset
+ Another C++ I/O streams interface
+
+iostream3/ by Ludwig Schwardt
+ and Kevin Ruland
+ Yet another C++ I/O streams interface
+
+masmx64/ by Gilles Vollant
+ x86 64-bit (AMD64 and Intel EM64t) code for x64 assembler to
+ replace longest_match() and inflate_fast(), also masm x86
+ 64-bits translation of Chris Anderson inflate_fast()
+
+masmx86/ by Gilles Vollant
+ x86 asm code to replace longest_match() and inflate_fast(),
+ for Visual C++ and MASM (32 bits).
+ Based on Brian Raiter (asm686) and Chris Anderson (inflate86)
+
+minizip/ by Gilles Vollant
+ Mini zip and unzip based on zlib
+ Includes Zip64 support by Mathias Svensson
+ See http://www.winimage.com/zLibDll/unzip.html
+
+pascal/ by Bob Dellaca et al.
+ Support for Pascal
+
+puff/ by Mark Adler
+ Small, low memory usage inflate. Also serves to provide an
+ unambiguous description of the deflate format.
+
+testzlib/ by Gilles Vollant
+ Example of the use of zlib
+
+untgz/ by Pedro A. Aranda Gutierrez
+ A very simple tar.gz file extractor using zlib
+
+vstudio/ by Gilles Vollant
+ Building a minizip-enhanced zlib with Microsoft Visual Studio
+ Includes vc11 from kreuzerkrieg and vc12 from davispuh
ADDED compat/zlib/contrib/ada/buffer_demo.adb
Index: compat/zlib/contrib/ada/buffer_demo.adb
==================================================================
--- compat/zlib/contrib/ada/buffer_demo.adb
+++ compat/zlib/contrib/ada/buffer_demo.adb
@@ -0,0 +1,106 @@
+----------------------------------------------------------------
+-- ZLib for Ada thick binding. --
+-- --
+-- Copyright (C) 2002-2004 Dmitriy Anisimkov --
+-- --
+-- Open source license information is in the zlib.ads file. --
+----------------------------------------------------------------
+--
+-- $Id: buffer_demo.adb,v 1.3 2004/09/06 06:55:35 vagul Exp $
+
+-- This demo program provided by Dr Steve Sangwine
+--
+-- Demonstration of a problem with Zlib-Ada (already fixed) when a buffer
+-- of exactly the correct size is used for decompressed data, and the last
+-- few bytes passed in to Zlib are checksum bytes.
+
+-- This program compresses a string of text, and then decompresses the
+-- compressed text into a buffer of the same size as the original text.
+
+with Ada.Streams; use Ada.Streams;
+with Ada.Text_IO;
+
+with ZLib; use ZLib;
+
+procedure Buffer_Demo is
+ EOL : Character renames ASCII.LF;
+ Text : constant String
+ := "Four score and seven years ago our fathers brought forth," & EOL &
+ "upon this continent, a new nation, conceived in liberty," & EOL &
+ "and dedicated to the proposition that `all men are created equal'.";
+
+ Source : Stream_Element_Array (1 .. Text'Length);
+ for Source'Address use Text'Address;
+
+begin
+ Ada.Text_IO.Put (Text);
+ Ada.Text_IO.New_Line;
+ Ada.Text_IO.Put_Line
+ ("Uncompressed size : " & Positive'Image (Text'Length) & " bytes");
+
+ declare
+ Compressed_Data : Stream_Element_Array (1 .. Text'Length);
+ L : Stream_Element_Offset;
+ begin
+ Compress : declare
+ Compressor : Filter_Type;
+ I : Stream_Element_Offset;
+ begin
+ Deflate_Init (Compressor);
+
+ -- Compress the whole of T at once.
+
+ Translate (Compressor, Source, I, Compressed_Data, L, Finish);
+ pragma Assert (I = Source'Last);
+
+ Close (Compressor);
+
+ Ada.Text_IO.Put_Line
+ ("Compressed size : "
+ & Stream_Element_Offset'Image (L) & " bytes");
+ end Compress;
+
+ -- Now we decompress the data, passing short blocks of data to Zlib
+ -- (because this demonstrates the problem - the last block passed will
+ -- contain checksum information and there will be no output, only a
+ -- check inside Zlib that the checksum is correct).
+
+ Decompress : declare
+ Decompressor : Filter_Type;
+
+ Uncompressed_Data : Stream_Element_Array (1 .. Text'Length);
+
+ Block_Size : constant := 4;
+ -- This makes sure that the last block contains
+ -- only Adler checksum data.
+
+ P : Stream_Element_Offset := Compressed_Data'First - 1;
+ O : Stream_Element_Offset;
+ begin
+ Inflate_Init (Decompressor);
+
+ loop
+ Translate
+ (Decompressor,
+ Compressed_Data
+ (P + 1 .. Stream_Element_Offset'Min (P + Block_Size, L)),
+ P,
+ Uncompressed_Data
+ (Total_Out (Decompressor) + 1 .. Uncompressed_Data'Last),
+ O,
+ No_Flush);
+
+ Ada.Text_IO.Put_Line
+ ("Total in : " & Count'Image (Total_In (Decompressor)) &
+ ", out : " & Count'Image (Total_Out (Decompressor)));
+
+ exit when P = L;
+ end loop;
+
+ Ada.Text_IO.New_Line;
+ Ada.Text_IO.Put_Line
+ ("Decompressed text matches original text : "
+ & Boolean'Image (Uncompressed_Data = Source));
+ end Decompress;
+ end;
+end Buffer_Demo;
ADDED compat/zlib/contrib/ada/mtest.adb
Index: compat/zlib/contrib/ada/mtest.adb
==================================================================
--- compat/zlib/contrib/ada/mtest.adb
+++ compat/zlib/contrib/ada/mtest.adb
@@ -0,0 +1,156 @@
+----------------------------------------------------------------
+-- ZLib for Ada thick binding. --
+-- --
+-- Copyright (C) 2002-2003 Dmitriy Anisimkov --
+-- --
+-- Open source license information is in the zlib.ads file. --
+----------------------------------------------------------------
+-- Continuous test for ZLib multithreading. If the test would fail
+-- we should provide thread safe allocation routines for the Z_Stream.
+--
+-- $Id: mtest.adb,v 1.4 2004/07/23 07:49:54 vagul Exp $
+
+with ZLib;
+with Ada.Streams;
+with Ada.Numerics.Discrete_Random;
+with Ada.Text_IO;
+with Ada.Exceptions;
+with Ada.Task_Identification;
+
+procedure MTest is
+ use Ada.Streams;
+ use ZLib;
+
+ Stop : Boolean := False;
+
+ pragma Atomic (Stop);
+
+ subtype Visible_Symbols is Stream_Element range 16#20# .. 16#7E#;
+
+ package Random_Elements is
+ new Ada.Numerics.Discrete_Random (Visible_Symbols);
+
+ task type Test_Task;
+
+ task body Test_Task is
+ Buffer : Stream_Element_Array (1 .. 100_000);
+ Gen : Random_Elements.Generator;
+
+ Buffer_First : Stream_Element_Offset;
+ Compare_First : Stream_Element_Offset;
+
+ Deflate : Filter_Type;
+ Inflate : Filter_Type;
+
+ procedure Further (Item : in Stream_Element_Array);
+
+ procedure Read_Buffer
+ (Item : out Ada.Streams.Stream_Element_Array;
+ Last : out Ada.Streams.Stream_Element_Offset);
+
+ -------------
+ -- Further --
+ -------------
+
+ procedure Further (Item : in Stream_Element_Array) is
+
+ procedure Compare (Item : in Stream_Element_Array);
+
+ -------------
+ -- Compare --
+ -------------
+
+ procedure Compare (Item : in Stream_Element_Array) is
+ Next_First : Stream_Element_Offset := Compare_First + Item'Length;
+ begin
+ if Buffer (Compare_First .. Next_First - 1) /= Item then
+ raise Program_Error;
+ end if;
+
+ Compare_First := Next_First;
+ end Compare;
+
+ procedure Compare_Write is new ZLib.Write (Write => Compare);
+ begin
+ Compare_Write (Inflate, Item, No_Flush);
+ end Further;
+
+ -----------------
+ -- Read_Buffer --
+ -----------------
+
+ procedure Read_Buffer
+ (Item : out Ada.Streams.Stream_Element_Array;
+ Last : out Ada.Streams.Stream_Element_Offset)
+ is
+ Buff_Diff : Stream_Element_Offset := Buffer'Last - Buffer_First;
+ Next_First : Stream_Element_Offset;
+ begin
+ if Item'Length <= Buff_Diff then
+ Last := Item'Last;
+
+ Next_First := Buffer_First + Item'Length;
+
+ Item := Buffer (Buffer_First .. Next_First - 1);
+
+ Buffer_First := Next_First;
+ else
+ Last := Item'First + Buff_Diff;
+ Item (Item'First .. Last) := Buffer (Buffer_First .. Buffer'Last);
+ Buffer_First := Buffer'Last + 1;
+ end if;
+ end Read_Buffer;
+
+ procedure Translate is new Generic_Translate
+ (Data_In => Read_Buffer,
+ Data_Out => Further);
+
+ begin
+ Random_Elements.Reset (Gen);
+
+ Buffer := (others => 20);
+
+ Main : loop
+ for J in Buffer'Range loop
+ Buffer (J) := Random_Elements.Random (Gen);
+
+ Deflate_Init (Deflate);
+ Inflate_Init (Inflate);
+
+ Buffer_First := Buffer'First;
+ Compare_First := Buffer'First;
+
+ Translate (Deflate);
+
+ if Compare_First /= Buffer'Last + 1 then
+ raise Program_Error;
+ end if;
+
+ Ada.Text_IO.Put_Line
+ (Ada.Task_Identification.Image
+ (Ada.Task_Identification.Current_Task)
+ & Stream_Element_Offset'Image (J)
+ & ZLib.Count'Image (Total_Out (Deflate)));
+
+ Close (Deflate);
+ Close (Inflate);
+
+ exit Main when Stop;
+ end loop;
+ end loop Main;
+ exception
+ when E : others =>
+ Ada.Text_IO.Put_Line (Ada.Exceptions.Exception_Information (E));
+ Stop := True;
+ end Test_Task;
+
+ Test : array (1 .. 4) of Test_Task;
+
+ pragma Unreferenced (Test);
+
+ Dummy : Character;
+
+begin
+ Ada.Text_IO.Get_Immediate (Dummy);
+ Stop := True;
+end MTest;
ADDED compat/zlib/contrib/ada/read.adb
Index: compat/zlib/contrib/ada/read.adb
==================================================================
--- compat/zlib/contrib/ada/read.adb
+++ compat/zlib/contrib/ada/read.adb
@@ -0,0 +1,156 @@
+----------------------------------------------------------------
+-- ZLib for Ada thick binding. --
+-- --
+-- Copyright (C) 2002-2003 Dmitriy Anisimkov --
+-- --
+-- Open source license information is in the zlib.ads file. --
+----------------------------------------------------------------
+
+-- $Id: read.adb,v 1.8 2004/05/31 10:53:40 vagul Exp $
+
+-- Test/demo program for the generic read interface.
+
+with Ada.Numerics.Discrete_Random;
+with Ada.Streams;
+with Ada.Text_IO;
+
+with ZLib;
+
+procedure Read is
+
+ use Ada.Streams;
+
+ ------------------------------------
+ -- Test configuration parameters --
+ ------------------------------------
+
+ File_Size : Stream_Element_Offset := 100_000;
+
+ Continuous : constant Boolean := False;
+ -- If this constant is True, the test would be repeated again and again,
+ -- with increment File_Size for every iteration.
+
+ Header : constant ZLib.Header_Type := ZLib.Default;
+ -- Do not use Header other than Default in ZLib versions 1.1.4 and older.
+
+ Init_Random : constant := 8;
+ -- We are using the same random sequence, in case of we catch bug,
+ -- so we would be able to reproduce it.
+
+ -- End --
+
+ Pack_Size : Stream_Element_Offset;
+ Offset : Stream_Element_Offset;
+
+ Filter : ZLib.Filter_Type;
+
+ subtype Visible_Symbols
+ is Stream_Element range 16#20# .. 16#7E#;
+
+ package Random_Elements is new
+ Ada.Numerics.Discrete_Random (Visible_Symbols);
+
+ Gen : Random_Elements.Generator;
+ Period : constant Stream_Element_Offset := 200;
+ -- Period constant variable for random generator not to be very random.
+ -- Bigger period, harder random.
+
+ Read_Buffer : Stream_Element_Array (1 .. 2048);
+ Read_First : Stream_Element_Offset;
+ Read_Last : Stream_Element_Offset;
+
+ procedure Reset;
+
+ procedure Read
+ (Item : out Stream_Element_Array;
+ Last : out Stream_Element_Offset);
+ -- this procedure is for generic instantiation of
+ -- ZLib.Read
+ -- reading data from the File_In.
+
+ procedure Read is new ZLib.Read
+ (Read,
+ Read_Buffer,
+ Rest_First => Read_First,
+ Rest_Last => Read_Last);
+
+ ----------
+ -- Read --
+ ----------
+
+ procedure Read
+ (Item : out Stream_Element_Array;
+ Last : out Stream_Element_Offset) is
+ begin
+ Last := Stream_Element_Offset'Min
+ (Item'Last,
+ Item'First + File_Size - Offset);
+
+ for J in Item'First .. Last loop
+ if J < Item'First + Period then
+ Item (J) := Random_Elements.Random (Gen);
+ else
+ Item (J) := Item (J - Period);
+ end if;
+
+ Offset := Offset + 1;
+ end loop;
+ end Read;
+
+ -----------
+ -- Reset --
+ -----------
+
+ procedure Reset is
+ begin
+ Random_Elements.Reset (Gen, Init_Random);
+ Pack_Size := 0;
+ Offset := 1;
+ Read_First := Read_Buffer'Last + 1;
+ Read_Last := Read_Buffer'Last;
+ end Reset;
+
+begin
+ Ada.Text_IO.Put_Line ("ZLib " & ZLib.Version);
+
+ loop
+ for Level in ZLib.Compression_Level'Range loop
+
+ Ada.Text_IO.Put ("Level ="
+ & ZLib.Compression_Level'Image (Level));
+
+ -- Deflate using generic instantiation.
+
+ ZLib.Deflate_Init
+ (Filter,
+ Level,
+ Header => Header);
+
+ Reset;
+
+ Ada.Text_IO.Put
+ (Stream_Element_Offset'Image (File_Size) & " ->");
+
+ loop
+ declare
+ Buffer : Stream_Element_Array (1 .. 1024);
+ Last : Stream_Element_Offset;
+ begin
+ Read (Filter, Buffer, Last);
+
+ Pack_Size := Pack_Size + Last - Buffer'First + 1;
+
+ exit when Last < Buffer'Last;
+ end;
+ end loop;
+
+ Ada.Text_IO.Put_Line (Stream_Element_Offset'Image (Pack_Size));
+
+ ZLib.Close (Filter);
+ end loop;
+
+ exit when not Continuous;
+
+ File_Size := File_Size + 1;
+ end loop;
+end Read;
ADDED compat/zlib/contrib/ada/readme.txt
Index: compat/zlib/contrib/ada/readme.txt
==================================================================
--- compat/zlib/contrib/ada/readme.txt
+++ compat/zlib/contrib/ada/readme.txt
@@ -0,0 +1,65 @@
+ ZLib for Ada thick binding (ZLib.Ada)
+ Release 1.3
+
+ZLib.Ada is a thick binding interface to the popular ZLib data
+compression library, available at http://www.gzip.org/zlib/.
+It provides Ada-style access to the ZLib C library.
+
+
+ Here are the main changes since ZLib.Ada 1.2:
+
+- Attension: ZLib.Read generic routine have a initialization requirement
+ for Read_Last parameter now. It is a bit incompartible with previous version,
+ but extends functionality, we could use new parameters Allow_Read_Some and
+ Flush now.
+
+- Added Is_Open routines to ZLib and ZLib.Streams packages.
+
+- Add pragma Assert to check Stream_Element is 8 bit.
+
+- Fix extraction to buffer with exact known decompressed size. Error reported by
+ Steve Sangwine.
+
+- Fix definition of ULong (changed to unsigned_long), fix regression on 64 bits
+ computers. Patch provided by Pascal Obry.
+
+- Add Status_Error exception definition.
+
+- Add pragma Assertion that Ada.Streams.Stream_Element size is 8 bit.
+
+
+ How to build ZLib.Ada under GNAT
+
+You should have the ZLib library already build on your computer, before
+building ZLib.Ada. Make the directory of ZLib.Ada sources current and
+issue the command:
+
+ gnatmake test -largs -L -lz
+
+Or use the GNAT project file build for GNAT 3.15 or later:
+
+ gnatmake -Pzlib.gpr -L
+
+
+ How to build ZLib.Ada under Aonix ObjectAda for Win32 7.2.2
+
+1. Make a project with all *.ads and *.adb files from the distribution.
+2. Build the libz.a library from the ZLib C sources.
+3. Rename libz.a to z.lib.
+4. Add the library z.lib to the project.
+5. Add the libc.lib library from the ObjectAda distribution to the project.
+6. Build the executable using test.adb as a main procedure.
+
+
+ How to use ZLib.Ada
+
+The source files test.adb and read.adb are small demo programs that show
+the main functionality of ZLib.Ada.
+
+The routines from the package specifications are commented.
+
+
+Homepage: http://zlib-ada.sourceforge.net/
+Author: Dmitriy Anisimkov
+
+Contributors: Pascal Obry , Steve Sangwine
ADDED compat/zlib/contrib/ada/test.adb
Index: compat/zlib/contrib/ada/test.adb
==================================================================
--- compat/zlib/contrib/ada/test.adb
+++ compat/zlib/contrib/ada/test.adb
@@ -0,0 +1,463 @@
+----------------------------------------------------------------
+-- ZLib for Ada thick binding. --
+-- --
+-- Copyright (C) 2002-2003 Dmitriy Anisimkov --
+-- --
+-- Open source license information is in the zlib.ads file. --
+----------------------------------------------------------------
+
+-- $Id: test.adb,v 1.17 2003/08/12 12:13:30 vagul Exp $
+
+-- The program has a few aims.
+-- 1. Test ZLib.Ada95 thick binding functionality.
+-- 2. Show the example of use main functionality of the ZLib.Ada95 binding.
+-- 3. Build this program automatically compile all ZLib.Ada95 packages under
+-- GNAT Ada95 compiler.
+
+with ZLib.Streams;
+with Ada.Streams.Stream_IO;
+with Ada.Numerics.Discrete_Random;
+
+with Ada.Text_IO;
+
+with Ada.Calendar;
+
+procedure Test is
+
+ use Ada.Streams;
+ use Stream_IO;
+
+ ------------------------------------
+ -- Test configuration parameters --
+ ------------------------------------
+
+ File_Size : Count := 100_000;
+ Continuous : constant Boolean := False;
+
+ Header : constant ZLib.Header_Type := ZLib.Default;
+ -- ZLib.None;
+ -- ZLib.Auto;
+ -- ZLib.GZip;
+ -- Do not use Header other then Default in ZLib versions 1.1.4
+ -- and older.
+
+ Strategy : constant ZLib.Strategy_Type := ZLib.Default_Strategy;
+ Init_Random : constant := 10;
+
+ -- End --
+
+ In_File_Name : constant String := "testzlib.in";
+ -- Name of the input file
+
+ Z_File_Name : constant String := "testzlib.zlb";
+ -- Name of the compressed file.
+
+ Out_File_Name : constant String := "testzlib.out";
+ -- Name of the decompressed file.
+
+ File_In : File_Type;
+ File_Out : File_Type;
+ File_Back : File_Type;
+ File_Z : ZLib.Streams.Stream_Type;
+
+ Filter : ZLib.Filter_Type;
+
+ Time_Stamp : Ada.Calendar.Time;
+
+ procedure Generate_File;
+ -- Generate file of spetsified size with some random data.
+ -- The random data is repeatable, for the good compression.
+
+ procedure Compare_Streams
+ (Left, Right : in out Root_Stream_Type'Class);
+ -- The procedure compearing data in 2 streams.
+ -- It is for compare data before and after compression/decompression.
+
+ procedure Compare_Files (Left, Right : String);
+ -- Compare files. Based on the Compare_Streams.
+
+ procedure Copy_Streams
+ (Source, Target : in out Root_Stream_Type'Class;
+ Buffer_Size : in Stream_Element_Offset := 1024);
+ -- Copying data from one stream to another. It is for test stream
+ -- interface of the library.
+
+ procedure Data_In
+ (Item : out Stream_Element_Array;
+ Last : out Stream_Element_Offset);
+ -- this procedure is for generic instantiation of
+ -- ZLib.Generic_Translate.
+ -- reading data from the File_In.
+
+ procedure Data_Out (Item : in Stream_Element_Array);
+ -- this procedure is for generic instantiation of
+ -- ZLib.Generic_Translate.
+ -- writing data to the File_Out.
+
+ procedure Stamp;
+ -- Store the timestamp to the local variable.
+
+ procedure Print_Statistic (Msg : String; Data_Size : ZLib.Count);
+ -- Print the time statistic with the message.
+
+ procedure Translate is new ZLib.Generic_Translate
+ (Data_In => Data_In,
+ Data_Out => Data_Out);
+ -- This procedure is moving data from File_In to File_Out
+ -- with compression or decompression, depend on initialization of
+ -- Filter parameter.
+
+ -------------------
+ -- Compare_Files --
+ -------------------
+
+ procedure Compare_Files (Left, Right : String) is
+ Left_File, Right_File : File_Type;
+ begin
+ Open (Left_File, In_File, Left);
+ Open (Right_File, In_File, Right);
+ Compare_Streams (Stream (Left_File).all, Stream (Right_File).all);
+ Close (Left_File);
+ Close (Right_File);
+ end Compare_Files;
+
+ ---------------------
+ -- Compare_Streams --
+ ---------------------
+
+ procedure Compare_Streams
+ (Left, Right : in out Ada.Streams.Root_Stream_Type'Class)
+ is
+ Left_Buffer, Right_Buffer : Stream_Element_Array (0 .. 16#FFF#);
+ Left_Last, Right_Last : Stream_Element_Offset;
+ begin
+ loop
+ Read (Left, Left_Buffer, Left_Last);
+ Read (Right, Right_Buffer, Right_Last);
+
+ if Left_Last /= Right_Last then
+ Ada.Text_IO.Put_Line ("Compare error :"
+ & Stream_Element_Offset'Image (Left_Last)
+ & " /= "
+ & Stream_Element_Offset'Image (Right_Last));
+
+ raise Constraint_Error;
+
+ elsif Left_Buffer (0 .. Left_Last)
+ /= Right_Buffer (0 .. Right_Last)
+ then
+ Ada.Text_IO.Put_Line ("ERROR: IN and OUT files is not equal.");
+ raise Constraint_Error;
+
+ end if;
+
+ exit when Left_Last < Left_Buffer'Last;
+ end loop;
+ end Compare_Streams;
+
+ ------------------
+ -- Copy_Streams --
+ ------------------
+
+ procedure Copy_Streams
+ (Source, Target : in out Ada.Streams.Root_Stream_Type'Class;
+ Buffer_Size : in Stream_Element_Offset := 1024)
+ is
+ Buffer : Stream_Element_Array (1 .. Buffer_Size);
+ Last : Stream_Element_Offset;
+ begin
+ loop
+ Read (Source, Buffer, Last);
+ Write (Target, Buffer (1 .. Last));
+
+ exit when Last < Buffer'Last;
+ end loop;
+ end Copy_Streams;
+
+ -------------
+ -- Data_In --
+ -------------
+
+ procedure Data_In
+ (Item : out Stream_Element_Array;
+ Last : out Stream_Element_Offset) is
+ begin
+ Read (File_In, Item, Last);
+ end Data_In;
+
+ --------------
+ -- Data_Out --
+ --------------
+
+ procedure Data_Out (Item : in Stream_Element_Array) is
+ begin
+ Write (File_Out, Item);
+ end Data_Out;
+
+ -------------------
+ -- Generate_File --
+ -------------------
+
+ procedure Generate_File is
+ subtype Visible_Symbols is Stream_Element range 16#20# .. 16#7E#;
+
+ package Random_Elements is
+ new Ada.Numerics.Discrete_Random (Visible_Symbols);
+
+ Gen : Random_Elements.Generator;
+ Buffer : Stream_Element_Array := (1 .. 77 => 16#20#) & 10;
+
+ Buffer_Count : constant Count := File_Size / Buffer'Length;
+ -- Number of same buffers in the packet.
+
+ Density : constant Count := 30; -- from 0 to Buffer'Length - 2;
+
+ procedure Fill_Buffer (J, D : in Count);
+ -- Change the part of the buffer.
+
+ -----------------
+ -- Fill_Buffer --
+ -----------------
+
+ procedure Fill_Buffer (J, D : in Count) is
+ begin
+ for K in 0 .. D loop
+ Buffer
+ (Stream_Element_Offset ((J + K) mod (Buffer'Length - 1) + 1))
+ := Random_Elements.Random (Gen);
+
+ end loop;
+ end Fill_Buffer;
+
+ begin
+ Random_Elements.Reset (Gen, Init_Random);
+
+ Create (File_In, Out_File, In_File_Name);
+
+ Fill_Buffer (1, Buffer'Length - 2);
+
+ for J in 1 .. Buffer_Count loop
+ Write (File_In, Buffer);
+
+ Fill_Buffer (J, Density);
+ end loop;
+
+ -- fill remain size.
+
+ Write
+ (File_In,
+ Buffer
+ (1 .. Stream_Element_Offset
+ (File_Size - Buffer'Length * Buffer_Count)));
+
+ Flush (File_In);
+ Close (File_In);
+ end Generate_File;
+
+ ---------------------
+ -- Print_Statistic --
+ ---------------------
+
+ procedure Print_Statistic (Msg : String; Data_Size : ZLib.Count) is
+ use Ada.Calendar;
+ use Ada.Text_IO;
+
+ package Count_IO is new Integer_IO (ZLib.Count);
+
+ Curr_Dur : Duration := Clock - Time_Stamp;
+ begin
+ Put (Msg);
+
+ Set_Col (20);
+ Ada.Text_IO.Put ("size =");
+
+ Count_IO.Put
+ (Data_Size,
+ Width => Stream_IO.Count'Image (File_Size)'Length);
+
+ Put_Line (" duration =" & Duration'Image (Curr_Dur));
+ end Print_Statistic;
+
+ -----------
+ -- Stamp --
+ -----------
+
+ procedure Stamp is
+ begin
+ Time_Stamp := Ada.Calendar.Clock;
+ end Stamp;
+
+begin
+ Ada.Text_IO.Put_Line ("ZLib " & ZLib.Version);
+
+ loop
+ Generate_File;
+
+ for Level in ZLib.Compression_Level'Range loop
+
+ Ada.Text_IO.Put_Line ("Level ="
+ & ZLib.Compression_Level'Image (Level));
+
+ -- Test generic interface.
+ Open (File_In, In_File, In_File_Name);
+ Create (File_Out, Out_File, Z_File_Name);
+
+ Stamp;
+
+ -- Deflate using generic instantiation.
+
+ ZLib.Deflate_Init
+ (Filter => Filter,
+ Level => Level,
+ Strategy => Strategy,
+ Header => Header);
+
+ Translate (Filter);
+ Print_Statistic ("Generic compress", ZLib.Total_Out (Filter));
+ ZLib.Close (Filter);
+
+ Close (File_In);
+ Close (File_Out);
+
+ Open (File_In, In_File, Z_File_Name);
+ Create (File_Out, Out_File, Out_File_Name);
+
+ Stamp;
+
+ -- Inflate using generic instantiation.
+
+ ZLib.Inflate_Init (Filter, Header => Header);
+
+ Translate (Filter);
+ Print_Statistic ("Generic decompress", ZLib.Total_Out (Filter));
+
+ ZLib.Close (Filter);
+
+ Close (File_In);
+ Close (File_Out);
+
+ Compare_Files (In_File_Name, Out_File_Name);
+
+ -- Test stream interface.
+
+ -- Compress to the back stream.
+
+ Open (File_In, In_File, In_File_Name);
+ Create (File_Back, Out_File, Z_File_Name);
+
+ Stamp;
+
+ ZLib.Streams.Create
+ (Stream => File_Z,
+ Mode => ZLib.Streams.Out_Stream,
+ Back => ZLib.Streams.Stream_Access
+ (Stream (File_Back)),
+ Back_Compressed => True,
+ Level => Level,
+ Strategy => Strategy,
+ Header => Header);
+
+ Copy_Streams
+ (Source => Stream (File_In).all,
+ Target => File_Z);
+
+ -- Flushing internal buffers to the back stream.
+
+ ZLib.Streams.Flush (File_Z, ZLib.Finish);
+
+ Print_Statistic ("Write compress",
+ ZLib.Streams.Write_Total_Out (File_Z));
+
+ ZLib.Streams.Close (File_Z);
+
+ Close (File_In);
+ Close (File_Back);
+
+ -- Compare reading from original file and from
+ -- decompression stream.
+
+ Open (File_In, In_File, In_File_Name);
+ Open (File_Back, In_File, Z_File_Name);
+
+ ZLib.Streams.Create
+ (Stream => File_Z,
+ Mode => ZLib.Streams.In_Stream,
+ Back => ZLib.Streams.Stream_Access
+ (Stream (File_Back)),
+ Back_Compressed => True,
+ Header => Header);
+
+ Stamp;
+ Compare_Streams (Stream (File_In).all, File_Z);
+
+ Print_Statistic ("Read decompress",
+ ZLib.Streams.Read_Total_Out (File_Z));
+
+ ZLib.Streams.Close (File_Z);
+ Close (File_In);
+ Close (File_Back);
+
+ -- Compress by reading from compression stream.
+
+ Open (File_Back, In_File, In_File_Name);
+ Create (File_Out, Out_File, Z_File_Name);
+
+ ZLib.Streams.Create
+ (Stream => File_Z,
+ Mode => ZLib.Streams.In_Stream,
+ Back => ZLib.Streams.Stream_Access
+ (Stream (File_Back)),
+ Back_Compressed => False,
+ Level => Level,
+ Strategy => Strategy,
+ Header => Header);
+
+ Stamp;
+ Copy_Streams
+ (Source => File_Z,
+ Target => Stream (File_Out).all);
+
+ Print_Statistic ("Read compress",
+ ZLib.Streams.Read_Total_Out (File_Z));
+
+ ZLib.Streams.Close (File_Z);
+
+ Close (File_Out);
+ Close (File_Back);
+
+ -- Decompress to decompression stream.
+
+ Open (File_In, In_File, Z_File_Name);
+ Create (File_Back, Out_File, Out_File_Name);
+
+ ZLib.Streams.Create
+ (Stream => File_Z,
+ Mode => ZLib.Streams.Out_Stream,
+ Back => ZLib.Streams.Stream_Access
+ (Stream (File_Back)),
+ Back_Compressed => False,
+ Header => Header);
+
+ Stamp;
+
+ Copy_Streams
+ (Source => Stream (File_In).all,
+ Target => File_Z);
+
+ Print_Statistic ("Write decompress",
+ ZLib.Streams.Write_Total_Out (File_Z));
+
+ ZLib.Streams.Close (File_Z);
+ Close (File_In);
+ Close (File_Back);
+
+ Compare_Files (In_File_Name, Out_File_Name);
+ end loop;
+
+ Ada.Text_IO.Put_Line (Count'Image (File_Size) & " Ok.");
+
+ exit when not Continuous;
+
+ File_Size := File_Size + 1;
+ end loop;
+end Test;
ADDED compat/zlib/contrib/ada/zlib-streams.adb
Index: compat/zlib/contrib/ada/zlib-streams.adb
==================================================================
--- compat/zlib/contrib/ada/zlib-streams.adb
+++ compat/zlib/contrib/ada/zlib-streams.adb
@@ -0,0 +1,225 @@
+----------------------------------------------------------------
+-- ZLib for Ada thick binding. --
+-- --
+-- Copyright (C) 2002-2003 Dmitriy Anisimkov --
+-- --
+-- Open source license information is in the zlib.ads file. --
+----------------------------------------------------------------
+
+-- $Id: zlib-streams.adb,v 1.10 2004/05/31 10:53:40 vagul Exp $
+
+with Ada.Unchecked_Deallocation;
+
+package body ZLib.Streams is
+
+ -----------
+ -- Close --
+ -----------
+
+ procedure Close (Stream : in out Stream_Type) is
+ procedure Free is new Ada.Unchecked_Deallocation
+ (Stream_Element_Array, Buffer_Access);
+ begin
+ if Stream.Mode = Out_Stream or Stream.Mode = Duplex then
+ -- We should flush the data written by the writer.
+
+ Flush (Stream, Finish);
+
+ Close (Stream.Writer);
+ end if;
+
+ if Stream.Mode = In_Stream or Stream.Mode = Duplex then
+ Close (Stream.Reader);
+ Free (Stream.Buffer);
+ end if;
+ end Close;
+
+ ------------
+ -- Create --
+ ------------
+
+ procedure Create
+ (Stream : out Stream_Type;
+ Mode : in Stream_Mode;
+ Back : in Stream_Access;
+ Back_Compressed : in Boolean;
+ Level : in Compression_Level := Default_Compression;
+ Strategy : in Strategy_Type := Default_Strategy;
+ Header : in Header_Type := Default;
+ Read_Buffer_Size : in Ada.Streams.Stream_Element_Offset
+ := Default_Buffer_Size;
+ Write_Buffer_Size : in Ada.Streams.Stream_Element_Offset
+ := Default_Buffer_Size)
+ is
+
+ subtype Buffer_Subtype is Stream_Element_Array (1 .. Read_Buffer_Size);
+
+ procedure Init_Filter
+ (Filter : in out Filter_Type;
+ Compress : in Boolean);
+
+ -----------------
+ -- Init_Filter --
+ -----------------
+
+ procedure Init_Filter
+ (Filter : in out Filter_Type;
+ Compress : in Boolean) is
+ begin
+ if Compress then
+ Deflate_Init
+ (Filter, Level, Strategy, Header => Header);
+ else
+ Inflate_Init (Filter, Header => Header);
+ end if;
+ end Init_Filter;
+
+ begin
+ Stream.Back := Back;
+ Stream.Mode := Mode;
+
+ if Mode = Out_Stream or Mode = Duplex then
+ Init_Filter (Stream.Writer, Back_Compressed);
+ Stream.Buffer_Size := Write_Buffer_Size;
+ else
+ Stream.Buffer_Size := 0;
+ end if;
+
+ if Mode = In_Stream or Mode = Duplex then
+ Init_Filter (Stream.Reader, not Back_Compressed);
+
+ Stream.Buffer := new Buffer_Subtype;
+ Stream.Rest_First := Stream.Buffer'Last + 1;
+ Stream.Rest_Last := Stream.Buffer'Last;
+ end if;
+ end Create;
+
+ -----------
+ -- Flush --
+ -----------
+
+ procedure Flush
+ (Stream : in out Stream_Type;
+ Mode : in Flush_Mode := Sync_Flush)
+ is
+ Buffer : Stream_Element_Array (1 .. Stream.Buffer_Size);
+ Last : Stream_Element_Offset;
+ begin
+ loop
+ Flush (Stream.Writer, Buffer, Last, Mode);
+
+ Ada.Streams.Write (Stream.Back.all, Buffer (1 .. Last));
+
+ exit when Last < Buffer'Last;
+ end loop;
+ end Flush;
+
+ -------------
+ -- Is_Open --
+ -------------
+
+ function Is_Open (Stream : Stream_Type) return Boolean is
+ begin
+ return Is_Open (Stream.Reader) or else Is_Open (Stream.Writer);
+ end Is_Open;
+
+ ----------
+ -- Read --
+ ----------
+
+ procedure Read
+ (Stream : in out Stream_Type;
+ Item : out Stream_Element_Array;
+ Last : out Stream_Element_Offset)
+ is
+
+ procedure Read
+ (Item : out Stream_Element_Array;
+ Last : out Stream_Element_Offset);
+
+ ----------
+ -- Read --
+ ----------
+
+ procedure Read
+ (Item : out Stream_Element_Array;
+ Last : out Stream_Element_Offset) is
+ begin
+ Ada.Streams.Read (Stream.Back.all, Item, Last);
+ end Read;
+
+ procedure Read is new ZLib.Read
+ (Read => Read,
+ Buffer => Stream.Buffer.all,
+ Rest_First => Stream.Rest_First,
+ Rest_Last => Stream.Rest_Last);
+
+ begin
+ Read (Stream.Reader, Item, Last);
+ end Read;
+
+ -------------------
+ -- Read_Total_In --
+ -------------------
+
+ function Read_Total_In (Stream : in Stream_Type) return Count is
+ begin
+ return Total_In (Stream.Reader);
+ end Read_Total_In;
+
+ --------------------
+ -- Read_Total_Out --
+ --------------------
+
+ function Read_Total_Out (Stream : in Stream_Type) return Count is
+ begin
+ return Total_Out (Stream.Reader);
+ end Read_Total_Out;
+
+ -----------
+ -- Write --
+ -----------
+
+ procedure Write
+ (Stream : in out Stream_Type;
+ Item : in Stream_Element_Array)
+ is
+
+ procedure Write (Item : in Stream_Element_Array);
+
+ -----------
+ -- Write --
+ -----------
+
+ procedure Write (Item : in Stream_Element_Array) is
+ begin
+ Ada.Streams.Write (Stream.Back.all, Item);
+ end Write;
+
+ procedure Write is new ZLib.Write
+ (Write => Write,
+ Buffer_Size => Stream.Buffer_Size);
+
+ begin
+ Write (Stream.Writer, Item, No_Flush);
+ end Write;
+
+ --------------------
+ -- Write_Total_In --
+ --------------------
+
+ function Write_Total_In (Stream : in Stream_Type) return Count is
+ begin
+ return Total_In (Stream.Writer);
+ end Write_Total_In;
+
+ ---------------------
+ -- Write_Total_Out --
+ ---------------------
+
+ function Write_Total_Out (Stream : in Stream_Type) return Count is
+ begin
+ return Total_Out (Stream.Writer);
+ end Write_Total_Out;
+
+end ZLib.Streams;
ADDED compat/zlib/contrib/ada/zlib-streams.ads
Index: compat/zlib/contrib/ada/zlib-streams.ads
==================================================================
--- compat/zlib/contrib/ada/zlib-streams.ads
+++ compat/zlib/contrib/ada/zlib-streams.ads
@@ -0,0 +1,114 @@
+----------------------------------------------------------------
+-- ZLib for Ada thick binding. --
+-- --
+-- Copyright (C) 2002-2003 Dmitriy Anisimkov --
+-- --
+-- Open source license information is in the zlib.ads file. --
+----------------------------------------------------------------
+
+-- $Id: zlib-streams.ads,v 1.12 2004/05/31 10:53:40 vagul Exp $
+
+package ZLib.Streams is
+
+ type Stream_Mode is (In_Stream, Out_Stream, Duplex);
+
+ type Stream_Access is access all Ada.Streams.Root_Stream_Type'Class;
+
+ type Stream_Type is
+ new Ada.Streams.Root_Stream_Type with private;
+
+ procedure Read
+ (Stream : in out Stream_Type;
+ Item : out Ada.Streams.Stream_Element_Array;
+ Last : out Ada.Streams.Stream_Element_Offset);
+
+ procedure Write
+ (Stream : in out Stream_Type;
+ Item : in Ada.Streams.Stream_Element_Array);
+
+ procedure Flush
+ (Stream : in out Stream_Type;
+ Mode : in Flush_Mode := Sync_Flush);
+ -- Flush the written data to the back stream,
+ -- all data placed to the compressor is flushing to the Back stream.
+ -- Should not be used untill necessary, becouse it is decreasing
+ -- compression.
+
+ function Read_Total_In (Stream : in Stream_Type) return Count;
+ pragma Inline (Read_Total_In);
+ -- Return total number of bytes read from back stream so far.
+
+ function Read_Total_Out (Stream : in Stream_Type) return Count;
+ pragma Inline (Read_Total_Out);
+ -- Return total number of bytes read so far.
+
+ function Write_Total_In (Stream : in Stream_Type) return Count;
+ pragma Inline (Write_Total_In);
+ -- Return total number of bytes written so far.
+
+ function Write_Total_Out (Stream : in Stream_Type) return Count;
+ pragma Inline (Write_Total_Out);
+ -- Return total number of bytes written to the back stream.
+
+ procedure Create
+ (Stream : out Stream_Type;
+ Mode : in Stream_Mode;
+ Back : in Stream_Access;
+ Back_Compressed : in Boolean;
+ Level : in Compression_Level := Default_Compression;
+ Strategy : in Strategy_Type := Default_Strategy;
+ Header : in Header_Type := Default;
+ Read_Buffer_Size : in Ada.Streams.Stream_Element_Offset
+ := Default_Buffer_Size;
+ Write_Buffer_Size : in Ada.Streams.Stream_Element_Offset
+ := Default_Buffer_Size);
+ -- Create the Comression/Decompression stream.
+ -- If mode is In_Stream then Write operation is disabled.
+ -- If mode is Out_Stream then Read operation is disabled.
+
+ -- If Back_Compressed is true then
+ -- Data written to the Stream is compressing to the Back stream
+ -- and data read from the Stream is decompressed data from the Back stream.
+
+ -- If Back_Compressed is false then
+ -- Data written to the Stream is decompressing to the Back stream
+ -- and data read from the Stream is compressed data from the Back stream.
+
+ -- !!! When the Need_Header is False ZLib-Ada is using undocumented
+ -- ZLib 1.1.4 functionality to do not create/wait for ZLib headers.
+
+ function Is_Open (Stream : Stream_Type) return Boolean;
+
+ procedure Close (Stream : in out Stream_Type);
+
+private
+
+ use Ada.Streams;
+
+ type Buffer_Access is access all Stream_Element_Array;
+
+ type Stream_Type
+ is new Root_Stream_Type with
+ record
+ Mode : Stream_Mode;
+
+ Buffer : Buffer_Access;
+ Rest_First : Stream_Element_Offset;
+ Rest_Last : Stream_Element_Offset;
+ -- Buffer for Read operation.
+ -- We need to have this buffer in the record
+ -- becouse not all read data from back stream
+ -- could be processed during the read operation.
+
+ Buffer_Size : Stream_Element_Offset;
+ -- Buffer size for write operation.
+ -- We do not need to have this buffer
+ -- in the record becouse all data could be
+ -- processed in the write operation.
+
+ Back : Stream_Access;
+ Reader : Filter_Type;
+ Writer : Filter_Type;
+ end record;
+
+end ZLib.Streams;
ADDED compat/zlib/contrib/ada/zlib-thin.adb
Index: compat/zlib/contrib/ada/zlib-thin.adb
==================================================================
--- compat/zlib/contrib/ada/zlib-thin.adb
+++ compat/zlib/contrib/ada/zlib-thin.adb
@@ -0,0 +1,141 @@
+----------------------------------------------------------------
+-- ZLib for Ada thick binding. --
+-- --
+-- Copyright (C) 2002-2003 Dmitriy Anisimkov --
+-- --
+-- Open source license information is in the zlib.ads file. --
+----------------------------------------------------------------
+
+-- $Id: zlib-thin.adb,v 1.8 2003/12/14 18:27:31 vagul Exp $
+
+package body ZLib.Thin is
+
+ ZLIB_VERSION : constant Chars_Ptr := zlibVersion;
+
+ Z_Stream_Size : constant Int := Z_Stream'Size / System.Storage_Unit;
+
+ --------------
+ -- Avail_In --
+ --------------
+
+ function Avail_In (Strm : in Z_Stream) return UInt is
+ begin
+ return Strm.Avail_In;
+ end Avail_In;
+
+ ---------------
+ -- Avail_Out --
+ ---------------
+
+ function Avail_Out (Strm : in Z_Stream) return UInt is
+ begin
+ return Strm.Avail_Out;
+ end Avail_Out;
+
+ ------------------
+ -- Deflate_Init --
+ ------------------
+
+ function Deflate_Init
+ (strm : Z_Streamp;
+ level : Int;
+ method : Int;
+ windowBits : Int;
+ memLevel : Int;
+ strategy : Int)
+ return Int is
+ begin
+ return deflateInit2
+ (strm,
+ level,
+ method,
+ windowBits,
+ memLevel,
+ strategy,
+ ZLIB_VERSION,
+ Z_Stream_Size);
+ end Deflate_Init;
+
+ ------------------
+ -- Inflate_Init --
+ ------------------
+
+ function Inflate_Init (strm : Z_Streamp; windowBits : Int) return Int is
+ begin
+ return inflateInit2 (strm, windowBits, ZLIB_VERSION, Z_Stream_Size);
+ end Inflate_Init;
+
+ ------------------------
+ -- Last_Error_Message --
+ ------------------------
+
+ function Last_Error_Message (Strm : in Z_Stream) return String is
+ use Interfaces.C.Strings;
+ begin
+ if Strm.msg = Null_Ptr then
+ return "";
+ else
+ return Value (Strm.msg);
+ end if;
+ end Last_Error_Message;
+
+ ------------
+ -- Set_In --
+ ------------
+
+ procedure Set_In
+ (Strm : in out Z_Stream;
+ Buffer : in Voidp;
+ Size : in UInt) is
+ begin
+ Strm.Next_In := Buffer;
+ Strm.Avail_In := Size;
+ end Set_In;
+
+ ------------------
+ -- Set_Mem_Func --
+ ------------------
+
+ procedure Set_Mem_Func
+ (Strm : in out Z_Stream;
+ Opaque : in Voidp;
+ Alloc : in alloc_func;
+ Free : in free_func) is
+ begin
+ Strm.opaque := Opaque;
+ Strm.zalloc := Alloc;
+ Strm.zfree := Free;
+ end Set_Mem_Func;
+
+ -------------
+ -- Set_Out --
+ -------------
+
+ procedure Set_Out
+ (Strm : in out Z_Stream;
+ Buffer : in Voidp;
+ Size : in UInt) is
+ begin
+ Strm.Next_Out := Buffer;
+ Strm.Avail_Out := Size;
+ end Set_Out;
+
+ --------------
+ -- Total_In --
+ --------------
+
+ function Total_In (Strm : in Z_Stream) return ULong is
+ begin
+ return Strm.Total_In;
+ end Total_In;
+
+ ---------------
+ -- Total_Out --
+ ---------------
+
+ function Total_Out (Strm : in Z_Stream) return ULong is
+ begin
+ return Strm.Total_Out;
+ end Total_Out;
+
+end ZLib.Thin;
ADDED compat/zlib/contrib/ada/zlib-thin.ads
Index: compat/zlib/contrib/ada/zlib-thin.ads
==================================================================
--- compat/zlib/contrib/ada/zlib-thin.ads
+++ compat/zlib/contrib/ada/zlib-thin.ads
@@ -0,0 +1,450 @@
+----------------------------------------------------------------
+-- ZLib for Ada thick binding. --
+-- --
+-- Copyright (C) 2002-2003 Dmitriy Anisimkov --
+-- --
+-- Open source license information is in the zlib.ads file. --
+----------------------------------------------------------------
+
+-- $Id: zlib-thin.ads,v 1.11 2004/07/23 06:33:11 vagul Exp $
+
+with Interfaces.C.Strings;
+
+with System;
+
+private package ZLib.Thin is
+
+ -- From zconf.h
+
+ MAX_MEM_LEVEL : constant := 9; -- zconf.h:105
+ -- zconf.h:105
+ MAX_WBITS : constant := 15; -- zconf.h:115
+ -- 32K LZ77 window
+ -- zconf.h:115
+ SEEK_SET : constant := 8#0000#; -- zconf.h:244
+ -- Seek from beginning of file.
+ -- zconf.h:244
+ SEEK_CUR : constant := 1; -- zconf.h:245
+ -- Seek from current position.
+ -- zconf.h:245
+ SEEK_END : constant := 2; -- zconf.h:246
+ -- Set file pointer to EOF plus "offset"
+ -- zconf.h:246
+
+ type Byte is new Interfaces.C.unsigned_char; -- 8 bits
+ -- zconf.h:214
+ type UInt is new Interfaces.C.unsigned; -- 16 bits or more
+ -- zconf.h:216
+ type Int is new Interfaces.C.int;
+
+ type ULong is new Interfaces.C.unsigned_long; -- 32 bits or more
+ -- zconf.h:217
+ subtype Chars_Ptr is Interfaces.C.Strings.chars_ptr;
+
+ type ULong_Access is access ULong;
+ type Int_Access is access Int;
+
+ subtype Voidp is System.Address; -- zconf.h:232
+
+ subtype Byte_Access is Voidp;
+
+ Nul : constant Voidp := System.Null_Address;
+ -- end from zconf
+
+ Z_NO_FLUSH : constant := 8#0000#; -- zlib.h:125
+ -- zlib.h:125
+ Z_PARTIAL_FLUSH : constant := 1; -- zlib.h:126
+ -- will be removed, use
+ -- Z_SYNC_FLUSH instead
+ -- zlib.h:126
+ Z_SYNC_FLUSH : constant := 2; -- zlib.h:127
+ -- zlib.h:127
+ Z_FULL_FLUSH : constant := 3; -- zlib.h:128
+ -- zlib.h:128
+ Z_FINISH : constant := 4; -- zlib.h:129
+ -- zlib.h:129
+ Z_OK : constant := 8#0000#; -- zlib.h:132
+ -- zlib.h:132
+ Z_STREAM_END : constant := 1; -- zlib.h:133
+ -- zlib.h:133
+ Z_NEED_DICT : constant := 2; -- zlib.h:134
+ -- zlib.h:134
+ Z_ERRNO : constant := -1; -- zlib.h:135
+ -- zlib.h:135
+ Z_STREAM_ERROR : constant := -2; -- zlib.h:136
+ -- zlib.h:136
+ Z_DATA_ERROR : constant := -3; -- zlib.h:137
+ -- zlib.h:137
+ Z_MEM_ERROR : constant := -4; -- zlib.h:138
+ -- zlib.h:138
+ Z_BUF_ERROR : constant := -5; -- zlib.h:139
+ -- zlib.h:139
+ Z_VERSION_ERROR : constant := -6; -- zlib.h:140
+ -- zlib.h:140
+ Z_NO_COMPRESSION : constant := 8#0000#; -- zlib.h:145
+ -- zlib.h:145
+ Z_BEST_SPEED : constant := 1; -- zlib.h:146
+ -- zlib.h:146
+ Z_BEST_COMPRESSION : constant := 9; -- zlib.h:147
+ -- zlib.h:147
+ Z_DEFAULT_COMPRESSION : constant := -1; -- zlib.h:148
+ -- zlib.h:148
+ Z_FILTERED : constant := 1; -- zlib.h:151
+ -- zlib.h:151
+ Z_HUFFMAN_ONLY : constant := 2; -- zlib.h:152
+ -- zlib.h:152
+ Z_DEFAULT_STRATEGY : constant := 8#0000#; -- zlib.h:153
+ -- zlib.h:153
+ Z_BINARY : constant := 8#0000#; -- zlib.h:156
+ -- zlib.h:156
+ Z_ASCII : constant := 1; -- zlib.h:157
+ -- zlib.h:157
+ Z_UNKNOWN : constant := 2; -- zlib.h:158
+ -- zlib.h:158
+ Z_DEFLATED : constant := 8; -- zlib.h:161
+ -- zlib.h:161
+ Z_NULL : constant := 8#0000#; -- zlib.h:164
+ -- for initializing zalloc, zfree, opaque
+ -- zlib.h:164
+ type gzFile is new Voidp; -- zlib.h:646
+
+ type Z_Stream is private;
+
+ type Z_Streamp is access all Z_Stream; -- zlib.h:89
+
+ type alloc_func is access function
+ (Opaque : Voidp;
+ Items : UInt;
+ Size : UInt)
+ return Voidp; -- zlib.h:63
+
+ type free_func is access procedure (opaque : Voidp; address : Voidp);
+
+ function zlibVersion return Chars_Ptr;
+
+ function Deflate (strm : Z_Streamp; flush : Int) return Int;
+
+ function DeflateEnd (strm : Z_Streamp) return Int;
+
+ function Inflate (strm : Z_Streamp; flush : Int) return Int;
+
+ function InflateEnd (strm : Z_Streamp) return Int;
+
+ function deflateSetDictionary
+ (strm : Z_Streamp;
+ dictionary : Byte_Access;
+ dictLength : UInt)
+ return Int;
+
+ function deflateCopy (dest : Z_Streamp; source : Z_Streamp) return Int;
+ -- zlib.h:478
+
+ function deflateReset (strm : Z_Streamp) return Int; -- zlib.h:495
+
+ function deflateParams
+ (strm : Z_Streamp;
+ level : Int;
+ strategy : Int)
+ return Int; -- zlib.h:506
+
+ function inflateSetDictionary
+ (strm : Z_Streamp;
+ dictionary : Byte_Access;
+ dictLength : UInt)
+ return Int; -- zlib.h:548
+
+ function inflateSync (strm : Z_Streamp) return Int; -- zlib.h:565
+
+ function inflateReset (strm : Z_Streamp) return Int; -- zlib.h:580
+
+ function compress
+ (dest : Byte_Access;
+ destLen : ULong_Access;
+ source : Byte_Access;
+ sourceLen : ULong)
+ return Int; -- zlib.h:601
+
+ function compress2
+ (dest : Byte_Access;
+ destLen : ULong_Access;
+ source : Byte_Access;
+ sourceLen : ULong;
+ level : Int)
+ return Int; -- zlib.h:615
+
+ function uncompress
+ (dest : Byte_Access;
+ destLen : ULong_Access;
+ source : Byte_Access;
+ sourceLen : ULong)
+ return Int;
+
+ function gzopen (path : Chars_Ptr; mode : Chars_Ptr) return gzFile;
+
+ function gzdopen (fd : Int; mode : Chars_Ptr) return gzFile;
+
+ function gzsetparams
+ (file : gzFile;
+ level : Int;
+ strategy : Int)
+ return Int;
+
+ function gzread
+ (file : gzFile;
+ buf : Voidp;
+ len : UInt)
+ return Int;
+
+ function gzwrite
+ (file : in gzFile;
+ buf : in Voidp;
+ len : in UInt)
+ return Int;
+
+ function gzprintf (file : in gzFile; format : in Chars_Ptr) return Int;
+
+ function gzputs (file : in gzFile; s : in Chars_Ptr) return Int;
+
+ function gzgets
+ (file : gzFile;
+ buf : Chars_Ptr;
+ len : Int)
+ return Chars_Ptr;
+
+ function gzputc (file : gzFile; char : Int) return Int;
+
+ function gzgetc (file : gzFile) return Int;
+
+ function gzflush (file : gzFile; flush : Int) return Int;
+
+ function gzseek
+ (file : gzFile;
+ offset : Int;
+ whence : Int)
+ return Int;
+
+ function gzrewind (file : gzFile) return Int;
+
+ function gztell (file : gzFile) return Int;
+
+ function gzeof (file : gzFile) return Int;
+
+ function gzclose (file : gzFile) return Int;
+
+ function gzerror (file : gzFile; errnum : Int_Access) return Chars_Ptr;
+
+ function adler32
+ (adler : ULong;
+ buf : Byte_Access;
+ len : UInt)
+ return ULong;
+
+ function crc32
+ (crc : ULong;
+ buf : Byte_Access;
+ len : UInt)
+ return ULong;
+
+ function deflateInit
+ (strm : Z_Streamp;
+ level : Int;
+ version : Chars_Ptr;
+ stream_size : Int)
+ return Int;
+
+ function deflateInit2
+ (strm : Z_Streamp;
+ level : Int;
+ method : Int;
+ windowBits : Int;
+ memLevel : Int;
+ strategy : Int;
+ version : Chars_Ptr;
+ stream_size : Int)
+ return Int;
+
+ function Deflate_Init
+ (strm : Z_Streamp;
+ level : Int;
+ method : Int;
+ windowBits : Int;
+ memLevel : Int;
+ strategy : Int)
+ return Int;
+ pragma Inline (Deflate_Init);
+
+ function inflateInit
+ (strm : Z_Streamp;
+ version : Chars_Ptr;
+ stream_size : Int)
+ return Int;
+
+ function inflateInit2
+ (strm : in Z_Streamp;
+ windowBits : in Int;
+ version : in Chars_Ptr;
+ stream_size : in Int)
+ return Int;
+
+ function inflateBackInit
+ (strm : in Z_Streamp;
+ windowBits : in Int;
+ window : in Byte_Access;
+ version : in Chars_Ptr;
+ stream_size : in Int)
+ return Int;
+ -- Size of window have to be 2**windowBits.
+
+ function Inflate_Init (strm : Z_Streamp; windowBits : Int) return Int;
+ pragma Inline (Inflate_Init);
+
+ function zError (err : Int) return Chars_Ptr;
+
+ function inflateSyncPoint (z : Z_Streamp) return Int;
+
+ function get_crc_table return ULong_Access;
+
+ -- Interface to the available fields of the z_stream structure.
+ -- The application must update next_in and avail_in when avail_in has
+ -- dropped to zero. It must update next_out and avail_out when avail_out
+ -- has dropped to zero. The application must initialize zalloc, zfree and
+ -- opaque before calling the init function.
+
+ procedure Set_In
+ (Strm : in out Z_Stream;
+ Buffer : in Voidp;
+ Size : in UInt);
+ pragma Inline (Set_In);
+
+ procedure Set_Out
+ (Strm : in out Z_Stream;
+ Buffer : in Voidp;
+ Size : in UInt);
+ pragma Inline (Set_Out);
+
+ procedure Set_Mem_Func
+ (Strm : in out Z_Stream;
+ Opaque : in Voidp;
+ Alloc : in alloc_func;
+ Free : in free_func);
+ pragma Inline (Set_Mem_Func);
+
+ function Last_Error_Message (Strm : in Z_Stream) return String;
+ pragma Inline (Last_Error_Message);
+
+ function Avail_Out (Strm : in Z_Stream) return UInt;
+ pragma Inline (Avail_Out);
+
+ function Avail_In (Strm : in Z_Stream) return UInt;
+ pragma Inline (Avail_In);
+
+ function Total_In (Strm : in Z_Stream) return ULong;
+ pragma Inline (Total_In);
+
+ function Total_Out (Strm : in Z_Stream) return ULong;
+ pragma Inline (Total_Out);
+
+ function inflateCopy
+ (dest : in Z_Streamp;
+ Source : in Z_Streamp)
+ return Int;
+
+ function compressBound (Source_Len : in ULong) return ULong;
+
+ function deflateBound
+ (Strm : in Z_Streamp;
+ Source_Len : in ULong)
+ return ULong;
+
+ function gzungetc (C : in Int; File : in gzFile) return Int;
+
+ function zlibCompileFlags return ULong;
+
+private
+
+ type Z_Stream is record -- zlib.h:68
+ Next_In : Voidp := Nul; -- next input byte
+ Avail_In : UInt := 0; -- number of bytes available at next_in
+ Total_In : ULong := 0; -- total nb of input bytes read so far
+ Next_Out : Voidp := Nul; -- next output byte should be put there
+ Avail_Out : UInt := 0; -- remaining free space at next_out
+ Total_Out : ULong := 0; -- total nb of bytes output so far
+ msg : Chars_Ptr; -- last error message, NULL if no error
+ state : Voidp; -- not visible by applications
+ zalloc : alloc_func := null; -- used to allocate the internal state
+ zfree : free_func := null; -- used to free the internal state
+ opaque : Voidp; -- private data object passed to
+ -- zalloc and zfree
+ data_type : Int; -- best guess about the data type:
+ -- ascii or binary
+ adler : ULong; -- adler32 value of the uncompressed
+ -- data
+ reserved : ULong; -- reserved for future use
+ end record;
+
+ pragma Convention (C, Z_Stream);
+
+ pragma Import (C, zlibVersion, "zlibVersion");
+ pragma Import (C, Deflate, "deflate");
+ pragma Import (C, DeflateEnd, "deflateEnd");
+ pragma Import (C, Inflate, "inflate");
+ pragma Import (C, InflateEnd, "inflateEnd");
+ pragma Import (C, deflateSetDictionary, "deflateSetDictionary");
+ pragma Import (C, deflateCopy, "deflateCopy");
+ pragma Import (C, deflateReset, "deflateReset");
+ pragma Import (C, deflateParams, "deflateParams");
+ pragma Import (C, inflateSetDictionary, "inflateSetDictionary");
+ pragma Import (C, inflateSync, "inflateSync");
+ pragma Import (C, inflateReset, "inflateReset");
+ pragma Import (C, compress, "compress");
+ pragma Import (C, compress2, "compress2");
+ pragma Import (C, uncompress, "uncompress");
+ pragma Import (C, gzopen, "gzopen");
+ pragma Import (C, gzdopen, "gzdopen");
+ pragma Import (C, gzsetparams, "gzsetparams");
+ pragma Import (C, gzread, "gzread");
+ pragma Import (C, gzwrite, "gzwrite");
+ pragma Import (C, gzprintf, "gzprintf");
+ pragma Import (C, gzputs, "gzputs");
+ pragma Import (C, gzgets, "gzgets");
+ pragma Import (C, gzputc, "gzputc");
+ pragma Import (C, gzgetc, "gzgetc");
+ pragma Import (C, gzflush, "gzflush");
+ pragma Import (C, gzseek, "gzseek");
+ pragma Import (C, gzrewind, "gzrewind");
+ pragma Import (C, gztell, "gztell");
+ pragma Import (C, gzeof, "gzeof");
+ pragma Import (C, gzclose, "gzclose");
+ pragma Import (C, gzerror, "gzerror");
+ pragma Import (C, adler32, "adler32");
+ pragma Import (C, crc32, "crc32");
+ pragma Import (C, deflateInit, "deflateInit_");
+ pragma Import (C, inflateInit, "inflateInit_");
+ pragma Import (C, deflateInit2, "deflateInit2_");
+ pragma Import (C, inflateInit2, "inflateInit2_");
+ pragma Import (C, zError, "zError");
+ pragma Import (C, inflateSyncPoint, "inflateSyncPoint");
+ pragma Import (C, get_crc_table, "get_crc_table");
+
+ -- since zlib 1.2.0:
+
+ pragma Import (C, inflateCopy, "inflateCopy");
+ pragma Import (C, compressBound, "compressBound");
+ pragma Import (C, deflateBound, "deflateBound");
+ pragma Import (C, gzungetc, "gzungetc");
+ pragma Import (C, zlibCompileFlags, "zlibCompileFlags");
+
+ pragma Import (C, inflateBackInit, "inflateBackInit_");
+
+ -- I stopped binding the inflateBack routines, becouse realize that
+ -- it does not support zlib and gzip headers for now, and have no
+ -- symmetric deflateBack routines.
+ -- ZLib-Ada is symmetric regarding deflate/inflate data transformation
+ -- and has a similar generic callback interface for the
+ -- deflate/inflate transformation based on the regular Deflate/Inflate
+ -- routines.
+
+ -- pragma Import (C, inflateBack, "inflateBack");
+ -- pragma Import (C, inflateBackEnd, "inflateBackEnd");
+
+end ZLib.Thin;
ADDED compat/zlib/contrib/ada/zlib.adb
Index: compat/zlib/contrib/ada/zlib.adb
==================================================================
--- compat/zlib/contrib/ada/zlib.adb
+++ compat/zlib/contrib/ada/zlib.adb
@@ -0,0 +1,701 @@
+----------------------------------------------------------------
+-- ZLib for Ada thick binding. --
+-- --
+-- Copyright (C) 2002-2004 Dmitriy Anisimkov --
+-- --
+-- Open source license information is in the zlib.ads file. --
+----------------------------------------------------------------
+
+-- $Id: zlib.adb,v 1.31 2004/09/06 06:53:19 vagul Exp $
+
+with Ada.Exceptions;
+with Ada.Unchecked_Conversion;
+with Ada.Unchecked_Deallocation;
+
+with Interfaces.C.Strings;
+
+with ZLib.Thin;
+
+package body ZLib is
+
+ use type Thin.Int;
+
+ type Z_Stream is new Thin.Z_Stream;
+
+ type Return_Code_Enum is
+ (OK,
+ STREAM_END,
+ NEED_DICT,
+ ERRNO,
+ STREAM_ERROR,
+ DATA_ERROR,
+ MEM_ERROR,
+ BUF_ERROR,
+ VERSION_ERROR);
+
+ type Flate_Step_Function is access
+ function (Strm : in Thin.Z_Streamp; Flush : in Thin.Int) return Thin.Int;
+ pragma Convention (C, Flate_Step_Function);
+
+ type Flate_End_Function is access
+ function (Ctrm : in Thin.Z_Streamp) return Thin.Int;
+ pragma Convention (C, Flate_End_Function);
+
+ type Flate_Type is record
+ Step : Flate_Step_Function;
+ Done : Flate_End_Function;
+ end record;
+
+ subtype Footer_Array is Stream_Element_Array (1 .. 8);
+
+ Simple_GZip_Header : constant Stream_Element_Array (1 .. 10)
+ := (16#1f#, 16#8b#, -- Magic header
+ 16#08#, -- Z_DEFLATED
+ 16#00#, -- Flags
+ 16#00#, 16#00#, 16#00#, 16#00#, -- Time
+ 16#00#, -- XFlags
+ 16#03# -- OS code
+ );
+ -- The simplest gzip header is not for informational, but just for
+ -- gzip format compatibility.
+ -- Note that some code below is using assumption
+ -- Simple_GZip_Header'Last > Footer_Array'Last, so do not make
+ -- Simple_GZip_Header'Last <= Footer_Array'Last.
+
+ Return_Code : constant array (Thin.Int range <>) of Return_Code_Enum
+ := (0 => OK,
+ 1 => STREAM_END,
+ 2 => NEED_DICT,
+ -1 => ERRNO,
+ -2 => STREAM_ERROR,
+ -3 => DATA_ERROR,
+ -4 => MEM_ERROR,
+ -5 => BUF_ERROR,
+ -6 => VERSION_ERROR);
+
+ Flate : constant array (Boolean) of Flate_Type
+ := (True => (Step => Thin.Deflate'Access,
+ Done => Thin.DeflateEnd'Access),
+ False => (Step => Thin.Inflate'Access,
+ Done => Thin.InflateEnd'Access));
+
+ Flush_Finish : constant array (Boolean) of Flush_Mode
+ := (True => Finish, False => No_Flush);
+
+ procedure Raise_Error (Stream : in Z_Stream);
+ pragma Inline (Raise_Error);
+
+ procedure Raise_Error (Message : in String);
+ pragma Inline (Raise_Error);
+
+ procedure Check_Error (Stream : in Z_Stream; Code : in Thin.Int);
+
+ procedure Free is new Ada.Unchecked_Deallocation
+ (Z_Stream, Z_Stream_Access);
+
+ function To_Thin_Access is new Ada.Unchecked_Conversion
+ (Z_Stream_Access, Thin.Z_Streamp);
+
+ procedure Translate_GZip
+ (Filter : in out Filter_Type;
+ In_Data : in Ada.Streams.Stream_Element_Array;
+ In_Last : out Ada.Streams.Stream_Element_Offset;
+ Out_Data : out Ada.Streams.Stream_Element_Array;
+ Out_Last : out Ada.Streams.Stream_Element_Offset;
+ Flush : in Flush_Mode);
+ -- Separate translate routine for make gzip header.
+
+ procedure Translate_Auto
+ (Filter : in out Filter_Type;
+ In_Data : in Ada.Streams.Stream_Element_Array;
+ In_Last : out Ada.Streams.Stream_Element_Offset;
+ Out_Data : out Ada.Streams.Stream_Element_Array;
+ Out_Last : out Ada.Streams.Stream_Element_Offset;
+ Flush : in Flush_Mode);
+ -- translate routine without additional headers.
+
+ -----------------
+ -- Check_Error --
+ -----------------
+
+ procedure Check_Error (Stream : in Z_Stream; Code : in Thin.Int) is
+ use type Thin.Int;
+ begin
+ if Code /= Thin.Z_OK then
+ Raise_Error
+ (Return_Code_Enum'Image (Return_Code (Code))
+ & ": " & Last_Error_Message (Stream));
+ end if;
+ end Check_Error;
+
+ -----------
+ -- Close --
+ -----------
+
+ procedure Close
+ (Filter : in out Filter_Type;
+ Ignore_Error : in Boolean := False)
+ is
+ Code : Thin.Int;
+ begin
+ if not Ignore_Error and then not Is_Open (Filter) then
+ raise Status_Error;
+ end if;
+
+ Code := Flate (Filter.Compression).Done (To_Thin_Access (Filter.Strm));
+
+ if Ignore_Error or else Code = Thin.Z_OK then
+ Free (Filter.Strm);
+ else
+ declare
+ Error_Message : constant String
+ := Last_Error_Message (Filter.Strm.all);
+ begin
+ Free (Filter.Strm);
+ Ada.Exceptions.Raise_Exception
+ (ZLib_Error'Identity,
+ Return_Code_Enum'Image (Return_Code (Code))
+ & ": " & Error_Message);
+ end;
+ end if;
+ end Close;
+
+ -----------
+ -- CRC32 --
+ -----------
+
+ function CRC32
+ (CRC : in Unsigned_32;
+ Data : in Ada.Streams.Stream_Element_Array)
+ return Unsigned_32
+ is
+ use Thin;
+ begin
+ return Unsigned_32 (crc32 (ULong (CRC),
+ Data'Address,
+ Data'Length));
+ end CRC32;
+
+ procedure CRC32
+ (CRC : in out Unsigned_32;
+ Data : in Ada.Streams.Stream_Element_Array) is
+ begin
+ CRC := CRC32 (CRC, Data);
+ end CRC32;
+
+ ------------------
+ -- Deflate_Init --
+ ------------------
+
+ procedure Deflate_Init
+ (Filter : in out Filter_Type;
+ Level : in Compression_Level := Default_Compression;
+ Strategy : in Strategy_Type := Default_Strategy;
+ Method : in Compression_Method := Deflated;
+ Window_Bits : in Window_Bits_Type := Default_Window_Bits;
+ Memory_Level : in Memory_Level_Type := Default_Memory_Level;
+ Header : in Header_Type := Default)
+ is
+ use type Thin.Int;
+ Win_Bits : Thin.Int := Thin.Int (Window_Bits);
+ begin
+ if Is_Open (Filter) then
+ raise Status_Error;
+ end if;
+
+ -- We allow ZLib to make header only in case of default header type.
+ -- Otherwise we would either do header by ourselfs, or do not do
+ -- header at all.
+
+ if Header = None or else Header = GZip then
+ Win_Bits := -Win_Bits;
+ end if;
+
+ -- For the GZip CRC calculation and make headers.
+
+ if Header = GZip then
+ Filter.CRC := 0;
+ Filter.Offset := Simple_GZip_Header'First;
+ else
+ Filter.Offset := Simple_GZip_Header'Last + 1;
+ end if;
+
+ Filter.Strm := new Z_Stream;
+ Filter.Compression := True;
+ Filter.Stream_End := False;
+ Filter.Header := Header;
+
+ if Thin.Deflate_Init
+ (To_Thin_Access (Filter.Strm),
+ Level => Thin.Int (Level),
+ method => Thin.Int (Method),
+ windowBits => Win_Bits,
+ memLevel => Thin.Int (Memory_Level),
+ strategy => Thin.Int (Strategy)) /= Thin.Z_OK
+ then
+ Raise_Error (Filter.Strm.all);
+ end if;
+ end Deflate_Init;
+
+ -----------
+ -- Flush --
+ -----------
+
+ procedure Flush
+ (Filter : in out Filter_Type;
+ Out_Data : out Ada.Streams.Stream_Element_Array;
+ Out_Last : out Ada.Streams.Stream_Element_Offset;
+ Flush : in Flush_Mode)
+ is
+ No_Data : Stream_Element_Array := (1 .. 0 => 0);
+ Last : Stream_Element_Offset;
+ begin
+ Translate (Filter, No_Data, Last, Out_Data, Out_Last, Flush);
+ end Flush;
+
+ -----------------------
+ -- Generic_Translate --
+ -----------------------
+
+ procedure Generic_Translate
+ (Filter : in out ZLib.Filter_Type;
+ In_Buffer_Size : in Integer := Default_Buffer_Size;
+ Out_Buffer_Size : in Integer := Default_Buffer_Size)
+ is
+ In_Buffer : Stream_Element_Array
+ (1 .. Stream_Element_Offset (In_Buffer_Size));
+ Out_Buffer : Stream_Element_Array
+ (1 .. Stream_Element_Offset (Out_Buffer_Size));
+ Last : Stream_Element_Offset;
+ In_Last : Stream_Element_Offset;
+ In_First : Stream_Element_Offset;
+ Out_Last : Stream_Element_Offset;
+ begin
+ Main : loop
+ Data_In (In_Buffer, Last);
+
+ In_First := In_Buffer'First;
+
+ loop
+ Translate
+ (Filter => Filter,
+ In_Data => In_Buffer (In_First .. Last),
+ In_Last => In_Last,
+ Out_Data => Out_Buffer,
+ Out_Last => Out_Last,
+ Flush => Flush_Finish (Last < In_Buffer'First));
+
+ if Out_Buffer'First <= Out_Last then
+ Data_Out (Out_Buffer (Out_Buffer'First .. Out_Last));
+ end if;
+
+ exit Main when Stream_End (Filter);
+
+ -- The end of in buffer.
+
+ exit when In_Last = Last;
+
+ In_First := In_Last + 1;
+ end loop;
+ end loop Main;
+
+ end Generic_Translate;
+
+ ------------------
+ -- Inflate_Init --
+ ------------------
+
+ procedure Inflate_Init
+ (Filter : in out Filter_Type;
+ Window_Bits : in Window_Bits_Type := Default_Window_Bits;
+ Header : in Header_Type := Default)
+ is
+ use type Thin.Int;
+ Win_Bits : Thin.Int := Thin.Int (Window_Bits);
+
+ procedure Check_Version;
+ -- Check the latest header types compatibility.
+
+ procedure Check_Version is
+ begin
+ if Version <= "1.1.4" then
+ Raise_Error
+ ("Inflate header type " & Header_Type'Image (Header)
+ & " incompatible with ZLib version " & Version);
+ end if;
+ end Check_Version;
+
+ begin
+ if Is_Open (Filter) then
+ raise Status_Error;
+ end if;
+
+ case Header is
+ when None =>
+ Check_Version;
+
+ -- Inflate data without headers determined
+ -- by negative Win_Bits.
+
+ Win_Bits := -Win_Bits;
+ when GZip =>
+ Check_Version;
+
+ -- Inflate gzip data defined by flag 16.
+
+ Win_Bits := Win_Bits + 16;
+ when Auto =>
+ Check_Version;
+
+ -- Inflate with automatic detection
+ -- of gzip or native header defined by flag 32.
+
+ Win_Bits := Win_Bits + 32;
+ when Default => null;
+ end case;
+
+ Filter.Strm := new Z_Stream;
+ Filter.Compression := False;
+ Filter.Stream_End := False;
+ Filter.Header := Header;
+
+ if Thin.Inflate_Init
+ (To_Thin_Access (Filter.Strm), Win_Bits) /= Thin.Z_OK
+ then
+ Raise_Error (Filter.Strm.all);
+ end if;
+ end Inflate_Init;
+
+ -------------
+ -- Is_Open --
+ -------------
+
+ function Is_Open (Filter : in Filter_Type) return Boolean is
+ begin
+ return Filter.Strm /= null;
+ end Is_Open;
+
+ -----------------
+ -- Raise_Error --
+ -----------------
+
+ procedure Raise_Error (Message : in String) is
+ begin
+ Ada.Exceptions.Raise_Exception (ZLib_Error'Identity, Message);
+ end Raise_Error;
+
+ procedure Raise_Error (Stream : in Z_Stream) is
+ begin
+ Raise_Error (Last_Error_Message (Stream));
+ end Raise_Error;
+
+ ----------
+ -- Read --
+ ----------
+
+ procedure Read
+ (Filter : in out Filter_Type;
+ Item : out Ada.Streams.Stream_Element_Array;
+ Last : out Ada.Streams.Stream_Element_Offset;
+ Flush : in Flush_Mode := No_Flush)
+ is
+ In_Last : Stream_Element_Offset;
+ Item_First : Ada.Streams.Stream_Element_Offset := Item'First;
+ V_Flush : Flush_Mode := Flush;
+
+ begin
+ pragma Assert (Rest_First in Buffer'First .. Buffer'Last + 1);
+ pragma Assert (Rest_Last in Buffer'First - 1 .. Buffer'Last);
+
+ loop
+ if Rest_Last = Buffer'First - 1 then
+ V_Flush := Finish;
+
+ elsif Rest_First > Rest_Last then
+ Read (Buffer, Rest_Last);
+ Rest_First := Buffer'First;
+
+ if Rest_Last < Buffer'First then
+ V_Flush := Finish;
+ end if;
+ end if;
+
+ Translate
+ (Filter => Filter,
+ In_Data => Buffer (Rest_First .. Rest_Last),
+ In_Last => In_Last,
+ Out_Data => Item (Item_First .. Item'Last),
+ Out_Last => Last,
+ Flush => V_Flush);
+
+ Rest_First := In_Last + 1;
+
+ exit when Stream_End (Filter)
+ or else Last = Item'Last
+ or else (Last >= Item'First and then Allow_Read_Some);
+
+ Item_First := Last + 1;
+ end loop;
+ end Read;
+
+ ----------------
+ -- Stream_End --
+ ----------------
+
+ function Stream_End (Filter : in Filter_Type) return Boolean is
+ begin
+ if Filter.Header = GZip and Filter.Compression then
+ return Filter.Stream_End
+ and then Filter.Offset = Footer_Array'Last + 1;
+ else
+ return Filter.Stream_End;
+ end if;
+ end Stream_End;
+
+ --------------
+ -- Total_In --
+ --------------
+
+ function Total_In (Filter : in Filter_Type) return Count is
+ begin
+ return Count (Thin.Total_In (To_Thin_Access (Filter.Strm).all));
+ end Total_In;
+
+ ---------------
+ -- Total_Out --
+ ---------------
+
+ function Total_Out (Filter : in Filter_Type) return Count is
+ begin
+ return Count (Thin.Total_Out (To_Thin_Access (Filter.Strm).all));
+ end Total_Out;
+
+ ---------------
+ -- Translate --
+ ---------------
+
+ procedure Translate
+ (Filter : in out Filter_Type;
+ In_Data : in Ada.Streams.Stream_Element_Array;
+ In_Last : out Ada.Streams.Stream_Element_Offset;
+ Out_Data : out Ada.Streams.Stream_Element_Array;
+ Out_Last : out Ada.Streams.Stream_Element_Offset;
+ Flush : in Flush_Mode) is
+ begin
+ if Filter.Header = GZip and then Filter.Compression then
+ Translate_GZip
+ (Filter => Filter,
+ In_Data => In_Data,
+ In_Last => In_Last,
+ Out_Data => Out_Data,
+ Out_Last => Out_Last,
+ Flush => Flush);
+ else
+ Translate_Auto
+ (Filter => Filter,
+ In_Data => In_Data,
+ In_Last => In_Last,
+ Out_Data => Out_Data,
+ Out_Last => Out_Last,
+ Flush => Flush);
+ end if;
+ end Translate;
+
+ --------------------
+ -- Translate_Auto --
+ --------------------
+
+ procedure Translate_Auto
+ (Filter : in out Filter_Type;
+ In_Data : in Ada.Streams.Stream_Element_Array;
+ In_Last : out Ada.Streams.Stream_Element_Offset;
+ Out_Data : out Ada.Streams.Stream_Element_Array;
+ Out_Last : out Ada.Streams.Stream_Element_Offset;
+ Flush : in Flush_Mode)
+ is
+ use type Thin.Int;
+ Code : Thin.Int;
+
+ begin
+ if not Is_Open (Filter) then
+ raise Status_Error;
+ end if;
+
+ if Out_Data'Length = 0 and then In_Data'Length = 0 then
+ raise Constraint_Error;
+ end if;
+
+ Set_Out (Filter.Strm.all, Out_Data'Address, Out_Data'Length);
+ Set_In (Filter.Strm.all, In_Data'Address, In_Data'Length);
+
+ Code := Flate (Filter.Compression).Step
+ (To_Thin_Access (Filter.Strm),
+ Thin.Int (Flush));
+
+ if Code = Thin.Z_STREAM_END then
+ Filter.Stream_End := True;
+ else
+ Check_Error (Filter.Strm.all, Code);
+ end if;
+
+ In_Last := In_Data'Last
+ - Stream_Element_Offset (Avail_In (Filter.Strm.all));
+ Out_Last := Out_Data'Last
+ - Stream_Element_Offset (Avail_Out (Filter.Strm.all));
+ end Translate_Auto;
+
+ --------------------
+ -- Translate_GZip --
+ --------------------
+
+ procedure Translate_GZip
+ (Filter : in out Filter_Type;
+ In_Data : in Ada.Streams.Stream_Element_Array;
+ In_Last : out Ada.Streams.Stream_Element_Offset;
+ Out_Data : out Ada.Streams.Stream_Element_Array;
+ Out_Last : out Ada.Streams.Stream_Element_Offset;
+ Flush : in Flush_Mode)
+ is
+ Out_First : Stream_Element_Offset;
+
+ procedure Add_Data (Data : in Stream_Element_Array);
+ -- Add data to stream from the Filter.Offset till necessary,
+ -- used for add gzip headr/footer.
+
+ procedure Put_32
+ (Item : in out Stream_Element_Array;
+ Data : in Unsigned_32);
+ pragma Inline (Put_32);
+
+ --------------
+ -- Add_Data --
+ --------------
+
+ procedure Add_Data (Data : in Stream_Element_Array) is
+ Data_First : Stream_Element_Offset renames Filter.Offset;
+ Data_Last : Stream_Element_Offset;
+ Data_Len : Stream_Element_Offset; -- -1
+ Out_Len : Stream_Element_Offset; -- -1
+ begin
+ Out_First := Out_Last + 1;
+
+ if Data_First > Data'Last then
+ return;
+ end if;
+
+ Data_Len := Data'Last - Data_First;
+ Out_Len := Out_Data'Last - Out_First;
+
+ if Data_Len <= Out_Len then
+ Out_Last := Out_First + Data_Len;
+ Data_Last := Data'Last;
+ else
+ Out_Last := Out_Data'Last;
+ Data_Last := Data_First + Out_Len;
+ end if;
+
+ Out_Data (Out_First .. Out_Last) := Data (Data_First .. Data_Last);
+
+ Data_First := Data_Last + 1;
+ Out_First := Out_Last + 1;
+ end Add_Data;
+
+ ------------
+ -- Put_32 --
+ ------------
+
+ procedure Put_32
+ (Item : in out Stream_Element_Array;
+ Data : in Unsigned_32)
+ is
+ D : Unsigned_32 := Data;
+ begin
+ for J in Item'First .. Item'First + 3 loop
+ Item (J) := Stream_Element (D and 16#FF#);
+ D := Shift_Right (D, 8);
+ end loop;
+ end Put_32;
+
+ begin
+ Out_Last := Out_Data'First - 1;
+
+ if not Filter.Stream_End then
+ Add_Data (Simple_GZip_Header);
+
+ Translate_Auto
+ (Filter => Filter,
+ In_Data => In_Data,
+ In_Last => In_Last,
+ Out_Data => Out_Data (Out_First .. Out_Data'Last),
+ Out_Last => Out_Last,
+ Flush => Flush);
+
+ CRC32 (Filter.CRC, In_Data (In_Data'First .. In_Last));
+ end if;
+
+ if Filter.Stream_End and then Out_Last <= Out_Data'Last then
+ -- This detection method would work only when
+ -- Simple_GZip_Header'Last > Footer_Array'Last
+
+ if Filter.Offset = Simple_GZip_Header'Last + 1 then
+ Filter.Offset := Footer_Array'First;
+ end if;
+
+ declare
+ Footer : Footer_Array;
+ begin
+ Put_32 (Footer, Filter.CRC);
+ Put_32 (Footer (Footer'First + 4 .. Footer'Last),
+ Unsigned_32 (Total_In (Filter)));
+ Add_Data (Footer);
+ end;
+ end if;
+ end Translate_GZip;
+
+ -------------
+ -- Version --
+ -------------
+
+ function Version return String is
+ begin
+ return Interfaces.C.Strings.Value (Thin.zlibVersion);
+ end Version;
+
+ -----------
+ -- Write --
+ -----------
+
+ procedure Write
+ (Filter : in out Filter_Type;
+ Item : in Ada.Streams.Stream_Element_Array;
+ Flush : in Flush_Mode := No_Flush)
+ is
+ Buffer : Stream_Element_Array (1 .. Buffer_Size);
+ In_Last : Stream_Element_Offset;
+ Out_Last : Stream_Element_Offset;
+ In_First : Stream_Element_Offset := Item'First;
+ begin
+ if Item'Length = 0 and Flush = No_Flush then
+ return;
+ end if;
+
+ loop
+ Translate
+ (Filter => Filter,
+ In_Data => Item (In_First .. Item'Last),
+ In_Last => In_Last,
+ Out_Data => Buffer,
+ Out_Last => Out_Last,
+ Flush => Flush);
+
+ if Out_Last >= Buffer'First then
+ Write (Buffer (1 .. Out_Last));
+ end if;
+
+ exit when In_Last = Item'Last or Stream_End (Filter);
+
+ In_First := In_Last + 1;
+ end loop;
+ end Write;
+
+end ZLib;
ADDED compat/zlib/contrib/ada/zlib.ads
Index: compat/zlib/contrib/ada/zlib.ads
==================================================================
--- compat/zlib/contrib/ada/zlib.ads
+++ compat/zlib/contrib/ada/zlib.ads
@@ -0,0 +1,328 @@
+------------------------------------------------------------------------------
+-- ZLib for Ada thick binding. --
+-- --
+-- Copyright (C) 2002-2004 Dmitriy Anisimkov --
+-- --
+-- This library is free software; 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. --
+-- --
+-- This library is distributed in the hope that it will be useful, but --
+-- WITHOUT ANY WARRANTY; without even the implied warranty of --
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU --
+-- General Public License for more details. --
+-- --
+-- You should have received a copy of the GNU General Public License --
+-- along with this library; if not, write to the Free Software Foundation, --
+-- Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. --
+-- --
+-- As a special exception, if other files instantiate generics from this --
+-- unit, or you link this unit with other files to produce an executable, --
+-- this unit does not by itself cause the resulting executable to be --
+-- covered by the GNU General Public License. This exception does not --
+-- however invalidate any other reasons why the executable file might be --
+-- covered by the GNU Public License. --
+------------------------------------------------------------------------------
+
+-- $Id: zlib.ads,v 1.26 2004/09/06 06:53:19 vagul Exp $
+
+with Ada.Streams;
+
+with Interfaces;
+
+package ZLib is
+
+ ZLib_Error : exception;
+ Status_Error : exception;
+
+ type Compression_Level is new Integer range -1 .. 9;
+
+ type Flush_Mode is private;
+
+ type Compression_Method is private;
+
+ type Window_Bits_Type is new Integer range 8 .. 15;
+
+ type Memory_Level_Type is new Integer range 1 .. 9;
+
+ type Unsigned_32 is new Interfaces.Unsigned_32;
+
+ type Strategy_Type is private;
+
+ type Header_Type is (None, Auto, Default, GZip);
+ -- Header type usage have a some limitation for inflate.
+ -- See comment for Inflate_Init.
+
+ subtype Count is Ada.Streams.Stream_Element_Count;
+
+ Default_Memory_Level : constant Memory_Level_Type := 8;
+ Default_Window_Bits : constant Window_Bits_Type := 15;
+
+ ----------------------------------
+ -- Compression method constants --
+ ----------------------------------
+
+ Deflated : constant Compression_Method;
+ -- Only one method allowed in this ZLib version
+
+ ---------------------------------
+ -- Compression level constants --
+ ---------------------------------
+
+ No_Compression : constant Compression_Level := 0;
+ Best_Speed : constant Compression_Level := 1;
+ Best_Compression : constant Compression_Level := 9;
+ Default_Compression : constant Compression_Level := -1;
+
+ --------------------------
+ -- Flush mode constants --
+ --------------------------
+
+ No_Flush : constant Flush_Mode;
+ -- Regular way for compression, no flush
+
+ Partial_Flush : constant Flush_Mode;
+ -- Will be removed, use Z_SYNC_FLUSH instead
+
+ Sync_Flush : constant Flush_Mode;
+ -- All pending output is flushed to the output buffer and the output
+ -- is aligned on a byte boundary, so that the decompressor can get all
+ -- input data available so far. (In particular avail_in is zero after the
+ -- call if enough output space has been provided before the call.)
+ -- Flushing may degrade compression for some compression algorithms and so
+ -- it should be used only when necessary.
+
+ Block_Flush : constant Flush_Mode;
+ -- Z_BLOCK requests that inflate() stop
+ -- if and when it get to the next deflate block boundary. When decoding the
+ -- zlib or gzip format, this will cause inflate() to return immediately
+ -- after the header and before the first block. When doing a raw inflate,
+ -- inflate() will go ahead and process the first block, and will return
+ -- when it gets to the end of that block, or when it runs out of data.
+
+ Full_Flush : constant Flush_Mode;
+ -- All output is flushed as with SYNC_FLUSH, and the compression state
+ -- is reset so that decompression can restart from this point if previous
+ -- compressed data has been damaged or if random access is desired. Using
+ -- Full_Flush too often can seriously degrade the compression.
+
+ Finish : constant Flush_Mode;
+ -- Just for tell the compressor that input data is complete.
+
+ ------------------------------------
+ -- Compression strategy constants --
+ ------------------------------------
+
+ -- RLE stategy could be used only in version 1.2.0 and later.
+
+ Filtered : constant Strategy_Type;
+ Huffman_Only : constant Strategy_Type;
+ RLE : constant Strategy_Type;
+ Default_Strategy : constant Strategy_Type;
+
+ Default_Buffer_Size : constant := 4096;
+
+ type Filter_Type is tagged limited private;
+ -- The filter is for compression and for decompression.
+ -- The usage of the type is depend of its initialization.
+
+ function Version return String;
+ pragma Inline (Version);
+ -- Return string representation of the ZLib version.
+
+ procedure Deflate_Init
+ (Filter : in out Filter_Type;
+ Level : in Compression_Level := Default_Compression;
+ Strategy : in Strategy_Type := Default_Strategy;
+ Method : in Compression_Method := Deflated;
+ Window_Bits : in Window_Bits_Type := Default_Window_Bits;
+ Memory_Level : in Memory_Level_Type := Default_Memory_Level;
+ Header : in Header_Type := Default);
+ -- Compressor initialization.
+ -- When Header parameter is Auto or Default, then default zlib header
+ -- would be provided for compressed data.
+ -- When Header is GZip, then gzip header would be set instead of
+ -- default header.
+ -- When Header is None, no header would be set for compressed data.
+
+ procedure Inflate_Init
+ (Filter : in out Filter_Type;
+ Window_Bits : in Window_Bits_Type := Default_Window_Bits;
+ Header : in Header_Type := Default);
+ -- Decompressor initialization.
+ -- Default header type mean that ZLib default header is expecting in the
+ -- input compressed stream.
+ -- Header type None mean that no header is expecting in the input stream.
+ -- GZip header type mean that GZip header is expecting in the
+ -- input compressed stream.
+ -- Auto header type mean that header type (GZip or Native) would be
+ -- detected automatically in the input stream.
+ -- Note that header types parameter values None, GZip and Auto are
+ -- supported for inflate routine only in ZLib versions 1.2.0.2 and later.
+ -- Deflate_Init is supporting all header types.
+
+ function Is_Open (Filter : in Filter_Type) return Boolean;
+ pragma Inline (Is_Open);
+ -- Is the filter opened for compression or decompression.
+
+ procedure Close
+ (Filter : in out Filter_Type;
+ Ignore_Error : in Boolean := False);
+ -- Closing the compression or decompressor.
+ -- If stream is closing before the complete and Ignore_Error is False,
+ -- The exception would be raised.
+
+ generic
+ with procedure Data_In
+ (Item : out Ada.Streams.Stream_Element_Array;
+ Last : out Ada.Streams.Stream_Element_Offset);
+ with procedure Data_Out
+ (Item : in Ada.Streams.Stream_Element_Array);
+ procedure Generic_Translate
+ (Filter : in out Filter_Type;
+ In_Buffer_Size : in Integer := Default_Buffer_Size;
+ Out_Buffer_Size : in Integer := Default_Buffer_Size);
+ -- Compress/decompress data fetch from Data_In routine and pass the result
+ -- to the Data_Out routine. User should provide Data_In and Data_Out
+ -- for compression/decompression data flow.
+ -- Compression or decompression depend on Filter initialization.
+
+ function Total_In (Filter : in Filter_Type) return Count;
+ pragma Inline (Total_In);
+ -- Returns total number of input bytes read so far
+
+ function Total_Out (Filter : in Filter_Type) return Count;
+ pragma Inline (Total_Out);
+ -- Returns total number of bytes output so far
+
+ function CRC32
+ (CRC : in Unsigned_32;
+ Data : in Ada.Streams.Stream_Element_Array)
+ return Unsigned_32;
+ pragma Inline (CRC32);
+ -- Compute CRC32, it could be necessary for make gzip format
+
+ procedure CRC32
+ (CRC : in out Unsigned_32;
+ Data : in Ada.Streams.Stream_Element_Array);
+ pragma Inline (CRC32);
+ -- Compute CRC32, it could be necessary for make gzip format
+
+ -------------------------------------------------
+ -- Below is more complex low level routines. --
+ -------------------------------------------------
+
+ procedure Translate
+ (Filter : in out Filter_Type;
+ In_Data : in Ada.Streams.Stream_Element_Array;
+ In_Last : out Ada.Streams.Stream_Element_Offset;
+ Out_Data : out Ada.Streams.Stream_Element_Array;
+ Out_Last : out Ada.Streams.Stream_Element_Offset;
+ Flush : in Flush_Mode);
+ -- Compress/decompress the In_Data buffer and place the result into
+ -- Out_Data. In_Last is the index of last element from In_Data accepted by
+ -- the Filter. Out_Last is the last element of the received data from
+ -- Filter. To tell the filter that incoming data are complete put the
+ -- Flush parameter to Finish.
+
+ function Stream_End (Filter : in Filter_Type) return Boolean;
+ pragma Inline (Stream_End);
+ -- Return the true when the stream is complete.
+
+ procedure Flush
+ (Filter : in out Filter_Type;
+ Out_Data : out Ada.Streams.Stream_Element_Array;
+ Out_Last : out Ada.Streams.Stream_Element_Offset;
+ Flush : in Flush_Mode);
+ pragma Inline (Flush);
+ -- Flushing the data from the compressor.
+
+ generic
+ with procedure Write
+ (Item : in Ada.Streams.Stream_Element_Array);
+ -- User should provide this routine for accept
+ -- compressed/decompressed data.
+
+ Buffer_Size : in Ada.Streams.Stream_Element_Offset
+ := Default_Buffer_Size;
+ -- Buffer size for Write user routine.
+
+ procedure Write
+ (Filter : in out Filter_Type;
+ Item : in Ada.Streams.Stream_Element_Array;
+ Flush : in Flush_Mode := No_Flush);
+ -- Compress/Decompress data from Item to the generic parameter procedure
+ -- Write. Output buffer size could be set in Buffer_Size generic parameter.
+
+ generic
+ with procedure Read
+ (Item : out Ada.Streams.Stream_Element_Array;
+ Last : out Ada.Streams.Stream_Element_Offset);
+ -- User should provide data for compression/decompression
+ -- thru this routine.
+
+ Buffer : in out Ada.Streams.Stream_Element_Array;
+ -- Buffer for keep remaining data from the previous
+ -- back read.
+
+ Rest_First, Rest_Last : in out Ada.Streams.Stream_Element_Offset;
+ -- Rest_First have to be initialized to Buffer'Last + 1
+ -- Rest_Last have to be initialized to Buffer'Last
+ -- before usage.
+
+ Allow_Read_Some : in Boolean := False;
+ -- Is it allowed to return Last < Item'Last before end of data.
+
+ procedure Read
+ (Filter : in out Filter_Type;
+ Item : out Ada.Streams.Stream_Element_Array;
+ Last : out Ada.Streams.Stream_Element_Offset;
+ Flush : in Flush_Mode := No_Flush);
+ -- Compress/Decompress data from generic parameter procedure Read to the
+ -- Item. User should provide Buffer and initialized Rest_First, Rest_Last
+ -- indicators. If Allow_Read_Some is True, Read routines could return
+ -- Last < Item'Last only at end of stream.
+
+private
+
+ use Ada.Streams;
+
+ pragma Assert (Ada.Streams.Stream_Element'Size = 8);
+ pragma Assert (Ada.Streams.Stream_Element'Modulus = 2**8);
+
+ type Flush_Mode is new Integer range 0 .. 5;
+
+ type Compression_Method is new Integer range 8 .. 8;
+
+ type Strategy_Type is new Integer range 0 .. 3;
+
+ No_Flush : constant Flush_Mode := 0;
+ Partial_Flush : constant Flush_Mode := 1;
+ Sync_Flush : constant Flush_Mode := 2;
+ Full_Flush : constant Flush_Mode := 3;
+ Finish : constant Flush_Mode := 4;
+ Block_Flush : constant Flush_Mode := 5;
+
+ Filtered : constant Strategy_Type := 1;
+ Huffman_Only : constant Strategy_Type := 2;
+ RLE : constant Strategy_Type := 3;
+ Default_Strategy : constant Strategy_Type := 0;
+
+ Deflated : constant Compression_Method := 8;
+
+ type Z_Stream;
+
+ type Z_Stream_Access is access all Z_Stream;
+
+ type Filter_Type is tagged limited record
+ Strm : Z_Stream_Access;
+ Compression : Boolean;
+ Stream_End : Boolean;
+ Header : Header_Type;
+ CRC : Unsigned_32;
+ Offset : Stream_Element_Offset;
+ -- Offset for gzip header/footer output.
+ end record;
+
+end ZLib;
ADDED compat/zlib/contrib/ada/zlib.gpr
Index: compat/zlib/contrib/ada/zlib.gpr
==================================================================
--- compat/zlib/contrib/ada/zlib.gpr
+++ compat/zlib/contrib/ada/zlib.gpr
@@ -0,0 +1,20 @@
+project Zlib is
+
+ for Languages use ("Ada");
+ for Source_Dirs use (".");
+ for Object_Dir use ".";
+ for Main use ("test.adb", "mtest.adb", "read.adb", "buffer_demo");
+
+ package Compiler is
+ for Default_Switches ("ada") use ("-gnatwcfilopru", "-gnatVcdfimorst", "-gnatyabcefhiklmnoprst");
+ end Compiler;
+
+ package Linker is
+ for Default_Switches ("ada") use ("-lz");
+ end Linker;
+
+ package Builder is
+ for Default_Switches ("ada") use ("-s", "-gnatQ");
+ end Builder;
+
+end Zlib;
ADDED compat/zlib/contrib/amd64/amd64-match.S
Index: compat/zlib/contrib/amd64/amd64-match.S
==================================================================
--- compat/zlib/contrib/amd64/amd64-match.S
+++ compat/zlib/contrib/amd64/amd64-match.S
@@ -0,0 +1,452 @@
+/*
+ * match.S -- optimized version of longest_match()
+ * based on the similar work by Gilles Vollant, and Brian Raiter, written 1998
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the BSD License. Use by owners of Che Guevarra
+ * parafernalia is prohibited, where possible, and highly discouraged
+ * elsewhere.
+ */
+
+#ifndef NO_UNDERLINE
+# define match_init _match_init
+# define longest_match _longest_match
+#endif
+
+#define scanend ebx
+#define scanendw bx
+#define chainlenwmask edx /* high word: current chain len low word: s->wmask */
+#define curmatch rsi
+#define curmatchd esi
+#define windowbestlen r8
+#define scanalign r9
+#define scanalignd r9d
+#define window r10
+#define bestlen r11
+#define bestlend r11d
+#define scanstart r12d
+#define scanstartw r12w
+#define scan r13
+#define nicematch r14d
+#define limit r15
+#define limitd r15d
+#define prev rcx
+
+/*
+ * The 258 is a "magic number, not a parameter -- changing it
+ * breaks the hell loose
+ */
+#define MAX_MATCH (258)
+#define MIN_MATCH (3)
+#define MIN_LOOKAHEAD (MAX_MATCH + MIN_MATCH + 1)
+#define MAX_MATCH_8 ((MAX_MATCH + 7) & ~7)
+
+/* stack frame offsets */
+#define LocalVarsSize (112)
+#define _chainlenwmask ( 8-LocalVarsSize)(%rsp)
+#define _windowbestlen (16-LocalVarsSize)(%rsp)
+#define save_r14 (24-LocalVarsSize)(%rsp)
+#define save_rsi (32-LocalVarsSize)(%rsp)
+#define save_rbx (40-LocalVarsSize)(%rsp)
+#define save_r12 (56-LocalVarsSize)(%rsp)
+#define save_r13 (64-LocalVarsSize)(%rsp)
+#define save_r15 (80-LocalVarsSize)(%rsp)
+
+
+.globl match_init, longest_match
+
+/*
+ * On AMD64 the first argument of a function (in our case -- the pointer to
+ * deflate_state structure) is passed in %rdi, hence our offsets below are
+ * all off of that.
+ */
+
+/* you can check the structure offset by running
+
+#include
+#include
+#include "deflate.h"
+
+void print_depl()
+{
+deflate_state ds;
+deflate_state *s=&ds;
+printf("size pointer=%u\n",(int)sizeof(void*));
+
+printf("#define dsWSize (%3u)(%%rdi)\n",(int)(((char*)&(s->w_size))-((char*)s)));
+printf("#define dsWMask (%3u)(%%rdi)\n",(int)(((char*)&(s->w_mask))-((char*)s)));
+printf("#define dsWindow (%3u)(%%rdi)\n",(int)(((char*)&(s->window))-((char*)s)));
+printf("#define dsPrev (%3u)(%%rdi)\n",(int)(((char*)&(s->prev))-((char*)s)));
+printf("#define dsMatchLen (%3u)(%%rdi)\n",(int)(((char*)&(s->match_length))-((char*)s)));
+printf("#define dsPrevMatch (%3u)(%%rdi)\n",(int)(((char*)&(s->prev_match))-((char*)s)));
+printf("#define dsStrStart (%3u)(%%rdi)\n",(int)(((char*)&(s->strstart))-((char*)s)));
+printf("#define dsMatchStart (%3u)(%%rdi)\n",(int)(((char*)&(s->match_start))-((char*)s)));
+printf("#define dsLookahead (%3u)(%%rdi)\n",(int)(((char*)&(s->lookahead))-((char*)s)));
+printf("#define dsPrevLen (%3u)(%%rdi)\n",(int)(((char*)&(s->prev_length))-((char*)s)));
+printf("#define dsMaxChainLen (%3u)(%%rdi)\n",(int)(((char*)&(s->max_chain_length))-((char*)s)));
+printf("#define dsGoodMatch (%3u)(%%rdi)\n",(int)(((char*)&(s->good_match))-((char*)s)));
+printf("#define dsNiceMatch (%3u)(%%rdi)\n",(int)(((char*)&(s->nice_match))-((char*)s)));
+}
+
+*/
+
+
+/*
+ to compile for XCode 3.2 on MacOSX x86_64
+ - run "gcc -g -c -DXCODE_MAC_X64_STRUCTURE amd64-match.S"
+ */
+
+
+#ifndef CURRENT_LINX_XCODE_MAC_X64_STRUCTURE
+#define dsWSize ( 68)(%rdi)
+#define dsWMask ( 76)(%rdi)
+#define dsWindow ( 80)(%rdi)
+#define dsPrev ( 96)(%rdi)
+#define dsMatchLen (144)(%rdi)
+#define dsPrevMatch (148)(%rdi)
+#define dsStrStart (156)(%rdi)
+#define dsMatchStart (160)(%rdi)
+#define dsLookahead (164)(%rdi)
+#define dsPrevLen (168)(%rdi)
+#define dsMaxChainLen (172)(%rdi)
+#define dsGoodMatch (188)(%rdi)
+#define dsNiceMatch (192)(%rdi)
+
+#else
+
+#ifndef STRUCT_OFFSET
+# define STRUCT_OFFSET (0)
+#endif
+
+
+#define dsWSize ( 56 + STRUCT_OFFSET)(%rdi)
+#define dsWMask ( 64 + STRUCT_OFFSET)(%rdi)
+#define dsWindow ( 72 + STRUCT_OFFSET)(%rdi)
+#define dsPrev ( 88 + STRUCT_OFFSET)(%rdi)
+#define dsMatchLen (136 + STRUCT_OFFSET)(%rdi)
+#define dsPrevMatch (140 + STRUCT_OFFSET)(%rdi)
+#define dsStrStart (148 + STRUCT_OFFSET)(%rdi)
+#define dsMatchStart (152 + STRUCT_OFFSET)(%rdi)
+#define dsLookahead (156 + STRUCT_OFFSET)(%rdi)
+#define dsPrevLen (160 + STRUCT_OFFSET)(%rdi)
+#define dsMaxChainLen (164 + STRUCT_OFFSET)(%rdi)
+#define dsGoodMatch (180 + STRUCT_OFFSET)(%rdi)
+#define dsNiceMatch (184 + STRUCT_OFFSET)(%rdi)
+
+#endif
+
+
+
+
+.text
+
+/* uInt longest_match(deflate_state *deflatestate, IPos curmatch) */
+
+longest_match:
+/*
+ * Retrieve the function arguments. %curmatch will hold cur_match
+ * throughout the entire function (passed via rsi on amd64).
+ * rdi will hold the pointer to the deflate_state (first arg on amd64)
+ */
+ mov %rsi, save_rsi
+ mov %rbx, save_rbx
+ mov %r12, save_r12
+ mov %r13, save_r13
+ mov %r14, save_r14
+ mov %r15, save_r15
+
+/* uInt wmask = s->w_mask; */
+/* unsigned chain_length = s->max_chain_length; */
+/* if (s->prev_length >= s->good_match) { */
+/* chain_length >>= 2; */
+/* } */
+
+ movl dsPrevLen, %eax
+ movl dsGoodMatch, %ebx
+ cmpl %ebx, %eax
+ movl dsWMask, %eax
+ movl dsMaxChainLen, %chainlenwmask
+ jl LastMatchGood
+ shrl $2, %chainlenwmask
+LastMatchGood:
+
+/* chainlen is decremented once beforehand so that the function can */
+/* use the sign flag instead of the zero flag for the exit test. */
+/* It is then shifted into the high word, to make room for the wmask */
+/* value, which it will always accompany. */
+
+ decl %chainlenwmask
+ shll $16, %chainlenwmask
+ orl %eax, %chainlenwmask
+
+/* if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead; */
+
+ movl dsNiceMatch, %eax
+ movl dsLookahead, %ebx
+ cmpl %eax, %ebx
+ jl LookaheadLess
+ movl %eax, %ebx
+LookaheadLess: movl %ebx, %nicematch
+
+/* register Bytef *scan = s->window + s->strstart; */
+
+ mov dsWindow, %window
+ movl dsStrStart, %limitd
+ lea (%limit, %window), %scan
+
+/* Determine how many bytes the scan ptr is off from being */
+/* dword-aligned. */
+
+ mov %scan, %scanalign
+ negl %scanalignd
+ andl $3, %scanalignd
+
+/* IPos limit = s->strstart > (IPos)MAX_DIST(s) ? */
+/* s->strstart - (IPos)MAX_DIST(s) : NIL; */
+
+ movl dsWSize, %eax
+ subl $MIN_LOOKAHEAD, %eax
+ xorl %ecx, %ecx
+ subl %eax, %limitd
+ cmovng %ecx, %limitd
+
+/* int best_len = s->prev_length; */
+
+ movl dsPrevLen, %bestlend
+
+/* Store the sum of s->window + best_len in %windowbestlen locally, and in memory. */
+
+ lea (%window, %bestlen), %windowbestlen
+ mov %windowbestlen, _windowbestlen
+
+/* register ush scan_start = *(ushf*)scan; */
+/* register ush scan_end = *(ushf*)(scan+best_len-1); */
+/* Posf *prev = s->prev; */
+
+ movzwl (%scan), %scanstart
+ movzwl -1(%scan, %bestlen), %scanend
+ mov dsPrev, %prev
+
+/* Jump into the main loop. */
+
+ movl %chainlenwmask, _chainlenwmask
+ jmp LoopEntry
+
+.balign 16
+
+/* do {
+ * match = s->window + cur_match;
+ * if (*(ushf*)(match+best_len-1) != scan_end ||
+ * *(ushf*)match != scan_start) continue;
+ * [...]
+ * } while ((cur_match = prev[cur_match & wmask]) > limit
+ * && --chain_length != 0);
+ *
+ * Here is the inner loop of the function. The function will spend the
+ * majority of its time in this loop, and majority of that time will
+ * be spent in the first ten instructions.
+ */
+LookupLoop:
+ andl %chainlenwmask, %curmatchd
+ movzwl (%prev, %curmatch, 2), %curmatchd
+ cmpl %limitd, %curmatchd
+ jbe LeaveNow
+ subl $0x00010000, %chainlenwmask
+ js LeaveNow
+LoopEntry: cmpw -1(%windowbestlen, %curmatch), %scanendw
+ jne LookupLoop
+ cmpw %scanstartw, (%window, %curmatch)
+ jne LookupLoop
+
+/* Store the current value of chainlen. */
+ movl %chainlenwmask, _chainlenwmask
+
+/* %scan is the string under scrutiny, and %prev to the string we */
+/* are hoping to match it up with. In actuality, %esi and %edi are */
+/* both pointed (MAX_MATCH_8 - scanalign) bytes ahead, and %edx is */
+/* initialized to -(MAX_MATCH_8 - scanalign). */
+
+ mov $(-MAX_MATCH_8), %rdx
+ lea (%curmatch, %window), %windowbestlen
+ lea MAX_MATCH_8(%windowbestlen, %scanalign), %windowbestlen
+ lea MAX_MATCH_8(%scan, %scanalign), %prev
+
+/* the prefetching below makes very little difference... */
+ prefetcht1 (%windowbestlen, %rdx)
+ prefetcht1 (%prev, %rdx)
+
+/*
+ * Test the strings for equality, 8 bytes at a time. At the end,
+ * adjust %rdx so that it is offset to the exact byte that mismatched.
+ *
+ * It should be confessed that this loop usually does not represent
+ * much of the total running time. Replacing it with a more
+ * straightforward "rep cmpsb" would not drastically degrade
+ * performance -- unrolling it, for example, makes no difference.
+ */
+
+#undef USE_SSE /* works, but is 6-7% slower, than non-SSE... */
+
+LoopCmps:
+#ifdef USE_SSE
+ /* Preload the SSE registers */
+ movdqu (%windowbestlen, %rdx), %xmm1
+ movdqu (%prev, %rdx), %xmm2
+ pcmpeqb %xmm2, %xmm1
+ movdqu 16(%windowbestlen, %rdx), %xmm3
+ movdqu 16(%prev, %rdx), %xmm4
+ pcmpeqb %xmm4, %xmm3
+ movdqu 32(%windowbestlen, %rdx), %xmm5
+ movdqu 32(%prev, %rdx), %xmm6
+ pcmpeqb %xmm6, %xmm5
+ movdqu 48(%windowbestlen, %rdx), %xmm7
+ movdqu 48(%prev, %rdx), %xmm8
+ pcmpeqb %xmm8, %xmm7
+
+ /* Check the comparisions' results */
+ pmovmskb %xmm1, %rax
+ notw %ax
+ bsfw %ax, %ax
+ jnz LeaveLoopCmps
+
+ /* this is the only iteration of the loop with a possibility of having
+ incremented rdx by 0x108 (each loop iteration add 16*4 = 0x40
+ and (0x40*4)+8=0x108 */
+ add $8, %rdx
+ jz LenMaximum
+ add $8, %rdx
+
+
+ pmovmskb %xmm3, %rax
+ notw %ax
+ bsfw %ax, %ax
+ jnz LeaveLoopCmps
+
+
+ add $16, %rdx
+
+
+ pmovmskb %xmm5, %rax
+ notw %ax
+ bsfw %ax, %ax
+ jnz LeaveLoopCmps
+
+ add $16, %rdx
+
+
+ pmovmskb %xmm7, %rax
+ notw %ax
+ bsfw %ax, %ax
+ jnz LeaveLoopCmps
+
+ add $16, %rdx
+
+ jmp LoopCmps
+LeaveLoopCmps: add %rax, %rdx
+#else
+ mov (%windowbestlen, %rdx), %rax
+ xor (%prev, %rdx), %rax
+ jnz LeaveLoopCmps
+
+ mov 8(%windowbestlen, %rdx), %rax
+ xor 8(%prev, %rdx), %rax
+ jnz LeaveLoopCmps8
+
+ mov 16(%windowbestlen, %rdx), %rax
+ xor 16(%prev, %rdx), %rax
+ jnz LeaveLoopCmps16
+
+ add $24, %rdx
+ jnz LoopCmps
+ jmp LenMaximum
+# if 0
+/*
+ * This three-liner is tantalizingly simple, but bsf is a slow instruction,
+ * and the complicated alternative down below is quite a bit faster. Sad...
+ */
+
+LeaveLoopCmps: bsf %rax, %rax /* find the first non-zero bit */
+ shrl $3, %eax /* divide by 8 to get the byte */
+ add %rax, %rdx
+# else
+LeaveLoopCmps16:
+ add $8, %rdx
+LeaveLoopCmps8:
+ add $8, %rdx
+LeaveLoopCmps: testl $0xFFFFFFFF, %eax /* Check the first 4 bytes */
+ jnz Check16
+ add $4, %rdx
+ shr $32, %rax
+Check16: testw $0xFFFF, %ax
+ jnz LenLower
+ add $2, %rdx
+ shrl $16, %eax
+LenLower: subb $1, %al
+ adc $0, %rdx
+# endif
+#endif
+
+/* Calculate the length of the match. If it is longer than MAX_MATCH, */
+/* then automatically accept it as the best possible match and leave. */
+
+ lea (%prev, %rdx), %rax
+ sub %scan, %rax
+ cmpl $MAX_MATCH, %eax
+ jge LenMaximum
+
+/* If the length of the match is not longer than the best match we */
+/* have so far, then forget it and return to the lookup loop. */
+
+ cmpl %bestlend, %eax
+ jg LongerMatch
+ mov _windowbestlen, %windowbestlen
+ mov dsPrev, %prev
+ movl _chainlenwmask, %edx
+ jmp LookupLoop
+
+/* s->match_start = cur_match; */
+/* best_len = len; */
+/* if (len >= nice_match) break; */
+/* scan_end = *(ushf*)(scan+best_len-1); */
+
+LongerMatch:
+ movl %eax, %bestlend
+ movl %curmatchd, dsMatchStart
+ cmpl %nicematch, %eax
+ jge LeaveNow
+
+ lea (%window, %bestlen), %windowbestlen
+ mov %windowbestlen, _windowbestlen
+
+ movzwl -1(%scan, %rax), %scanend
+ mov dsPrev, %prev
+ movl _chainlenwmask, %chainlenwmask
+ jmp LookupLoop
+
+/* Accept the current string, with the maximum possible length. */
+
+LenMaximum:
+ movl $MAX_MATCH, %bestlend
+ movl %curmatchd, dsMatchStart
+
+/* if ((uInt)best_len <= s->lookahead) return (uInt)best_len; */
+/* return s->lookahead; */
+
+LeaveNow:
+ movl dsLookahead, %eax
+ cmpl %eax, %bestlend
+ cmovngl %bestlend, %eax
+LookaheadRet:
+
+/* Restore the registers and return from whence we came. */
+
+ mov save_rsi, %rsi
+ mov save_rbx, %rbx
+ mov save_r12, %r12
+ mov save_r13, %r13
+ mov save_r14, %r14
+ mov save_r15, %r15
+
+ ret
+
+match_init: ret
ADDED compat/zlib/contrib/asm686/README.686
Index: compat/zlib/contrib/asm686/README.686
==================================================================
--- compat/zlib/contrib/asm686/README.686
+++ compat/zlib/contrib/asm686/README.686
@@ -0,0 +1,51 @@
+This is a patched version of zlib, modified to use
+Pentium-Pro-optimized assembly code in the deflation algorithm. The
+files changed/added by this patch are:
+
+README.686
+match.S
+
+The speedup that this patch provides varies, depending on whether the
+compiler used to build the original version of zlib falls afoul of the
+PPro's speed traps. My own tests show a speedup of around 10-20% at
+the default compression level, and 20-30% using -9, against a version
+compiled using gcc 2.7.2.3. Your mileage may vary.
+
+Note that this code has been tailored for the PPro/PII in particular,
+and will not perform particuarly well on a Pentium.
+
+If you are using an assembler other than GNU as, you will have to
+translate match.S to use your assembler's syntax. (Have fun.)
+
+Brian Raiter
+breadbox@muppetlabs.com
+April, 1998
+
+
+Added for zlib 1.1.3:
+
+The patches come from
+http://www.muppetlabs.com/~breadbox/software/assembly.html
+
+To compile zlib with this asm file, copy match.S to the zlib directory
+then do:
+
+CFLAGS="-O3 -DASMV" ./configure
+make OBJA=match.o
+
+
+Update:
+
+I've been ignoring these assembly routines for years, believing that
+gcc's generated code had caught up with it sometime around gcc 2.95
+and the major rearchitecting of the Pentium 4. However, I recently
+learned that, despite what I believed, this code still has some life
+in it. On the Pentium 4 and AMD64 chips, it continues to run about 8%
+faster than the code produced by gcc 4.1.
+
+In acknowledgement of its continuing usefulness, I've altered the
+license to match that of the rest of zlib. Share and Enjoy!
+
+Brian Raiter
+breadbox@muppetlabs.com
+April, 2007
ADDED compat/zlib/contrib/asm686/match.S
Index: compat/zlib/contrib/asm686/match.S
==================================================================
--- compat/zlib/contrib/asm686/match.S
+++ compat/zlib/contrib/asm686/match.S
@@ -0,0 +1,357 @@
+/* match.S -- x86 assembly version of the zlib longest_match() function.
+ * Optimized for the Intel 686 chips (PPro and later).
+ *
+ * Copyright (C) 1998, 2007 Brian Raiter
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty. In no event will the author be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ * claim that you wrote the original software. If you use this software
+ * in a product, an acknowledgment in the product documentation would be
+ * appreciated but is not required.
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ * misrepresented as being the original software.
+ * 3. This notice may not be removed or altered from any source distribution.
+ */
+
+#ifndef NO_UNDERLINE
+#define match_init _match_init
+#define longest_match _longest_match
+#endif
+
+#define MAX_MATCH (258)
+#define MIN_MATCH (3)
+#define MIN_LOOKAHEAD (MAX_MATCH + MIN_MATCH + 1)
+#define MAX_MATCH_8 ((MAX_MATCH + 7) & ~7)
+
+/* stack frame offsets */
+
+#define chainlenwmask 0 /* high word: current chain len */
+ /* low word: s->wmask */
+#define window 4 /* local copy of s->window */
+#define windowbestlen 8 /* s->window + bestlen */
+#define scanstart 16 /* first two bytes of string */
+#define scanend 12 /* last two bytes of string */
+#define scanalign 20 /* dword-misalignment of string */
+#define nicematch 24 /* a good enough match size */
+#define bestlen 28 /* size of best match so far */
+#define scan 32 /* ptr to string wanting match */
+
+#define LocalVarsSize (36)
+/* saved ebx 36 */
+/* saved edi 40 */
+/* saved esi 44 */
+/* saved ebp 48 */
+/* return address 52 */
+#define deflatestate 56 /* the function arguments */
+#define curmatch 60
+
+/* All the +zlib1222add offsets are due to the addition of fields
+ * in zlib in the deflate_state structure since the asm code was first written
+ * (if you compile with zlib 1.0.4 or older, use "zlib1222add equ (-4)").
+ * (if you compile with zlib between 1.0.5 and 1.2.2.1, use "zlib1222add equ 0").
+ * if you compile with zlib 1.2.2.2 or later , use "zlib1222add equ 8").
+ */
+
+#define zlib1222add (8)
+
+#define dsWSize (36+zlib1222add)
+#define dsWMask (44+zlib1222add)
+#define dsWindow (48+zlib1222add)
+#define dsPrev (56+zlib1222add)
+#define dsMatchLen (88+zlib1222add)
+#define dsPrevMatch (92+zlib1222add)
+#define dsStrStart (100+zlib1222add)
+#define dsMatchStart (104+zlib1222add)
+#define dsLookahead (108+zlib1222add)
+#define dsPrevLen (112+zlib1222add)
+#define dsMaxChainLen (116+zlib1222add)
+#define dsGoodMatch (132+zlib1222add)
+#define dsNiceMatch (136+zlib1222add)
+
+
+.file "match.S"
+
+.globl match_init, longest_match
+
+.text
+
+/* uInt longest_match(deflate_state *deflatestate, IPos curmatch) */
+.cfi_sections .debug_frame
+
+longest_match:
+
+.cfi_startproc
+/* Save registers that the compiler may be using, and adjust %esp to */
+/* make room for our stack frame. */
+
+ pushl %ebp
+ .cfi_def_cfa_offset 8
+ .cfi_offset ebp, -8
+ pushl %edi
+ .cfi_def_cfa_offset 12
+ pushl %esi
+ .cfi_def_cfa_offset 16
+ pushl %ebx
+ .cfi_def_cfa_offset 20
+ subl $LocalVarsSize, %esp
+ .cfi_def_cfa_offset LocalVarsSize+20
+
+/* Retrieve the function arguments. %ecx will hold cur_match */
+/* throughout the entire function. %edx will hold the pointer to the */
+/* deflate_state structure during the function's setup (before */
+/* entering the main loop). */
+
+ movl deflatestate(%esp), %edx
+ movl curmatch(%esp), %ecx
+
+/* uInt wmask = s->w_mask; */
+/* unsigned chain_length = s->max_chain_length; */
+/* if (s->prev_length >= s->good_match) { */
+/* chain_length >>= 2; */
+/* } */
+
+ movl dsPrevLen(%edx), %eax
+ movl dsGoodMatch(%edx), %ebx
+ cmpl %ebx, %eax
+ movl dsWMask(%edx), %eax
+ movl dsMaxChainLen(%edx), %ebx
+ jl LastMatchGood
+ shrl $2, %ebx
+LastMatchGood:
+
+/* chainlen is decremented once beforehand so that the function can */
+/* use the sign flag instead of the zero flag for the exit test. */
+/* It is then shifted into the high word, to make room for the wmask */
+/* value, which it will always accompany. */
+
+ decl %ebx
+ shll $16, %ebx
+ orl %eax, %ebx
+ movl %ebx, chainlenwmask(%esp)
+
+/* if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead; */
+
+ movl dsNiceMatch(%edx), %eax
+ movl dsLookahead(%edx), %ebx
+ cmpl %eax, %ebx
+ jl LookaheadLess
+ movl %eax, %ebx
+LookaheadLess: movl %ebx, nicematch(%esp)
+
+/* register Bytef *scan = s->window + s->strstart; */
+
+ movl dsWindow(%edx), %esi
+ movl %esi, window(%esp)
+ movl dsStrStart(%edx), %ebp
+ lea (%esi,%ebp), %edi
+ movl %edi, scan(%esp)
+
+/* Determine how many bytes the scan ptr is off from being */
+/* dword-aligned. */
+
+ movl %edi, %eax
+ negl %eax
+ andl $3, %eax
+ movl %eax, scanalign(%esp)
+
+/* IPos limit = s->strstart > (IPos)MAX_DIST(s) ? */
+/* s->strstart - (IPos)MAX_DIST(s) : NIL; */
+
+ movl dsWSize(%edx), %eax
+ subl $MIN_LOOKAHEAD, %eax
+ subl %eax, %ebp
+ jg LimitPositive
+ xorl %ebp, %ebp
+LimitPositive:
+
+/* int best_len = s->prev_length; */
+
+ movl dsPrevLen(%edx), %eax
+ movl %eax, bestlen(%esp)
+
+/* Store the sum of s->window + best_len in %esi locally, and in %esi. */
+
+ addl %eax, %esi
+ movl %esi, windowbestlen(%esp)
+
+/* register ush scan_start = *(ushf*)scan; */
+/* register ush scan_end = *(ushf*)(scan+best_len-1); */
+/* Posf *prev = s->prev; */
+
+ movzwl (%edi), %ebx
+ movl %ebx, scanstart(%esp)
+ movzwl -1(%edi,%eax), %ebx
+ movl %ebx, scanend(%esp)
+ movl dsPrev(%edx), %edi
+
+/* Jump into the main loop. */
+
+ movl chainlenwmask(%esp), %edx
+ jmp LoopEntry
+
+.balign 16
+
+/* do {
+ * match = s->window + cur_match;
+ * if (*(ushf*)(match+best_len-1) != scan_end ||
+ * *(ushf*)match != scan_start) continue;
+ * [...]
+ * } while ((cur_match = prev[cur_match & wmask]) > limit
+ * && --chain_length != 0);
+ *
+ * Here is the inner loop of the function. The function will spend the
+ * majority of its time in this loop, and majority of that time will
+ * be spent in the first ten instructions.
+ *
+ * Within this loop:
+ * %ebx = scanend
+ * %ecx = curmatch
+ * %edx = chainlenwmask - i.e., ((chainlen << 16) | wmask)
+ * %esi = windowbestlen - i.e., (window + bestlen)
+ * %edi = prev
+ * %ebp = limit
+ */
+LookupLoop:
+ andl %edx, %ecx
+ movzwl (%edi,%ecx,2), %ecx
+ cmpl %ebp, %ecx
+ jbe LeaveNow
+ subl $0x00010000, %edx
+ js LeaveNow
+LoopEntry: movzwl -1(%esi,%ecx), %eax
+ cmpl %ebx, %eax
+ jnz LookupLoop
+ movl window(%esp), %eax
+ movzwl (%eax,%ecx), %eax
+ cmpl scanstart(%esp), %eax
+ jnz LookupLoop
+
+/* Store the current value of chainlen. */
+
+ movl %edx, chainlenwmask(%esp)
+
+/* Point %edi to the string under scrutiny, and %esi to the string we */
+/* are hoping to match it up with. In actuality, %esi and %edi are */
+/* both pointed (MAX_MATCH_8 - scanalign) bytes ahead, and %edx is */
+/* initialized to -(MAX_MATCH_8 - scanalign). */
+
+ movl window(%esp), %esi
+ movl scan(%esp), %edi
+ addl %ecx, %esi
+ movl scanalign(%esp), %eax
+ movl $(-MAX_MATCH_8), %edx
+ lea MAX_MATCH_8(%edi,%eax), %edi
+ lea MAX_MATCH_8(%esi,%eax), %esi
+
+/* Test the strings for equality, 8 bytes at a time. At the end,
+ * adjust %edx so that it is offset to the exact byte that mismatched.
+ *
+ * We already know at this point that the first three bytes of the
+ * strings match each other, and they can be safely passed over before
+ * starting the compare loop. So what this code does is skip over 0-3
+ * bytes, as much as necessary in order to dword-align the %edi
+ * pointer. (%esi will still be misaligned three times out of four.)
+ *
+ * It should be confessed that this loop usually does not represent
+ * much of the total running time. Replacing it with a more
+ * straightforward "rep cmpsb" would not drastically degrade
+ * performance.
+ */
+LoopCmps:
+ movl (%esi,%edx), %eax
+ xorl (%edi,%edx), %eax
+ jnz LeaveLoopCmps
+ movl 4(%esi,%edx), %eax
+ xorl 4(%edi,%edx), %eax
+ jnz LeaveLoopCmps4
+ addl $8, %edx
+ jnz LoopCmps
+ jmp LenMaximum
+LeaveLoopCmps4: addl $4, %edx
+LeaveLoopCmps: testl $0x0000FFFF, %eax
+ jnz LenLower
+ addl $2, %edx
+ shrl $16, %eax
+LenLower: subb $1, %al
+ adcl $0, %edx
+
+/* Calculate the length of the match. If it is longer than MAX_MATCH, */
+/* then automatically accept it as the best possible match and leave. */
+
+ lea (%edi,%edx), %eax
+ movl scan(%esp), %edi
+ subl %edi, %eax
+ cmpl $MAX_MATCH, %eax
+ jge LenMaximum
+
+/* If the length of the match is not longer than the best match we */
+/* have so far, then forget it and return to the lookup loop. */
+
+ movl deflatestate(%esp), %edx
+ movl bestlen(%esp), %ebx
+ cmpl %ebx, %eax
+ jg LongerMatch
+ movl windowbestlen(%esp), %esi
+ movl dsPrev(%edx), %edi
+ movl scanend(%esp), %ebx
+ movl chainlenwmask(%esp), %edx
+ jmp LookupLoop
+
+/* s->match_start = cur_match; */
+/* best_len = len; */
+/* if (len >= nice_match) break; */
+/* scan_end = *(ushf*)(scan+best_len-1); */
+
+LongerMatch: movl nicematch(%esp), %ebx
+ movl %eax, bestlen(%esp)
+ movl %ecx, dsMatchStart(%edx)
+ cmpl %ebx, %eax
+ jge LeaveNow
+ movl window(%esp), %esi
+ addl %eax, %esi
+ movl %esi, windowbestlen(%esp)
+ movzwl -1(%edi,%eax), %ebx
+ movl dsPrev(%edx), %edi
+ movl %ebx, scanend(%esp)
+ movl chainlenwmask(%esp), %edx
+ jmp LookupLoop
+
+/* Accept the current string, with the maximum possible length. */
+
+LenMaximum: movl deflatestate(%esp), %edx
+ movl $MAX_MATCH, bestlen(%esp)
+ movl %ecx, dsMatchStart(%edx)
+
+/* if ((uInt)best_len <= s->lookahead) return (uInt)best_len; */
+/* return s->lookahead; */
+
+LeaveNow:
+ movl deflatestate(%esp), %edx
+ movl bestlen(%esp), %ebx
+ movl dsLookahead(%edx), %eax
+ cmpl %eax, %ebx
+ jg LookaheadRet
+ movl %ebx, %eax
+LookaheadRet:
+
+/* Restore the stack and return from whence we came. */
+
+ addl $LocalVarsSize, %esp
+ .cfi_def_cfa_offset 20
+ popl %ebx
+ .cfi_def_cfa_offset 16
+ popl %esi
+ .cfi_def_cfa_offset 12
+ popl %edi
+ .cfi_def_cfa_offset 8
+ popl %ebp
+ .cfi_def_cfa_offset 4
+.cfi_endproc
+match_init: ret
ADDED compat/zlib/contrib/blast/Makefile
Index: compat/zlib/contrib/blast/Makefile
==================================================================
--- compat/zlib/contrib/blast/Makefile
+++ compat/zlib/contrib/blast/Makefile
@@ -0,0 +1,8 @@
+blast: blast.c blast.h
+ cc -DTEST -o blast blast.c
+
+test: blast
+ blast < test.pk | cmp - test.txt
+
+clean:
+ rm -f blast blast.o
ADDED compat/zlib/contrib/blast/README
Index: compat/zlib/contrib/blast/README
==================================================================
--- compat/zlib/contrib/blast/README
+++ compat/zlib/contrib/blast/README
@@ -0,0 +1,4 @@
+Read blast.h for purpose and usage.
+
+Mark Adler
+madler@alumni.caltech.edu
ADDED compat/zlib/contrib/blast/blast.c
Index: compat/zlib/contrib/blast/blast.c
==================================================================
--- compat/zlib/contrib/blast/blast.c
+++ compat/zlib/contrib/blast/blast.c
@@ -0,0 +1,446 @@
+/* blast.c
+ * Copyright (C) 2003, 2012 Mark Adler
+ * For conditions of distribution and use, see copyright notice in blast.h
+ * version 1.2, 24 Oct 2012
+ *
+ * blast.c decompresses data compressed by the PKWare Compression Library.
+ * This function provides functionality similar to the explode() function of
+ * the PKWare library, hence the name "blast".
+ *
+ * This decompressor is based on the excellent format description provided by
+ * Ben Rudiak-Gould in comp.compression on August 13, 2001. Interestingly, the
+ * example Ben provided in the post is incorrect. The distance 110001 should
+ * instead be 111000. When corrected, the example byte stream becomes:
+ *
+ * 00 04 82 24 25 8f 80 7f
+ *
+ * which decompresses to "AIAIAIAIAIAIA" (without the quotes).
+ */
+
+/*
+ * Change history:
+ *
+ * 1.0 12 Feb 2003 - First version
+ * 1.1 16 Feb 2003 - Fixed distance check for > 4 GB uncompressed data
+ * 1.2 24 Oct 2012 - Add note about using binary mode in stdio
+ * - Fix comparisons of differently signed integers
+ */
+
+#include /* for setjmp(), longjmp(), and jmp_buf */
+#include "blast.h" /* prototype for blast() */
+
+#define local static /* for local function definitions */
+#define MAXBITS 13 /* maximum code length */
+#define MAXWIN 4096 /* maximum window size */
+
+/* input and output state */
+struct state {
+ /* input state */
+ blast_in infun; /* input function provided by user */
+ void *inhow; /* opaque information passed to infun() */
+ unsigned char *in; /* next input location */
+ unsigned left; /* available input at in */
+ int bitbuf; /* bit buffer */
+ int bitcnt; /* number of bits in bit buffer */
+
+ /* input limit error return state for bits() and decode() */
+ jmp_buf env;
+
+ /* output state */
+ blast_out outfun; /* output function provided by user */
+ void *outhow; /* opaque information passed to outfun() */
+ unsigned next; /* index of next write location in out[] */
+ int first; /* true to check distances (for first 4K) */
+ unsigned char out[MAXWIN]; /* output buffer and sliding window */
+};
+
+/*
+ * Return need bits from the input stream. This always leaves less than
+ * eight bits in the buffer. bits() works properly for need == 0.
+ *
+ * Format notes:
+ *
+ * - Bits are stored in bytes from the least significant bit to the most
+ * significant bit. Therefore bits are dropped from the bottom of the bit
+ * buffer, using shift right, and new bytes are appended to the top of the
+ * bit buffer, using shift left.
+ */
+local int bits(struct state *s, int need)
+{
+ int val; /* bit accumulator */
+
+ /* load at least need bits into val */
+ val = s->bitbuf;
+ while (s->bitcnt < need) {
+ if (s->left == 0) {
+ s->left = s->infun(s->inhow, &(s->in));
+ if (s->left == 0) longjmp(s->env, 1); /* out of input */
+ }
+ val |= (int)(*(s->in)++) << s->bitcnt; /* load eight bits */
+ s->left--;
+ s->bitcnt += 8;
+ }
+
+ /* drop need bits and update buffer, always zero to seven bits left */
+ s->bitbuf = val >> need;
+ s->bitcnt -= need;
+
+ /* return need bits, zeroing the bits above that */
+ return val & ((1 << need) - 1);
+}
+
+/*
+ * Huffman code decoding tables. count[1..MAXBITS] is the number of symbols of
+ * each length, which for a canonical code are stepped through in order.
+ * symbol[] are the symbol values in canonical order, where the number of
+ * entries is the sum of the counts in count[]. The decoding process can be
+ * seen in the function decode() below.
+ */
+struct huffman {
+ short *count; /* number of symbols of each length */
+ short *symbol; /* canonically ordered symbols */
+};
+
+/*
+ * Decode a code from the stream s using huffman table h. Return the symbol or
+ * a negative value if there is an error. If all of the lengths are zero, i.e.
+ * an empty code, or if the code is incomplete and an invalid code is received,
+ * then -9 is returned after reading MAXBITS bits.
+ *
+ * Format notes:
+ *
+ * - The codes as stored in the compressed data are bit-reversed relative to
+ * a simple integer ordering of codes of the same lengths. Hence below the
+ * bits are pulled from the compressed data one at a time and used to
+ * build the code value reversed from what is in the stream in order to
+ * permit simple integer comparisons for decoding.
+ *
+ * - The first code for the shortest length is all ones. Subsequent codes of
+ * the same length are simply integer decrements of the previous code. When
+ * moving up a length, a one bit is appended to the code. For a complete
+ * code, the last code of the longest length will be all zeros. To support
+ * this ordering, the bits pulled during decoding are inverted to apply the
+ * more "natural" ordering starting with all zeros and incrementing.
+ */
+local int decode(struct state *s, struct huffman *h)
+{
+ int len; /* current number of bits in code */
+ int code; /* len bits being decoded */
+ int first; /* first code of length len */
+ int count; /* number of codes of length len */
+ int index; /* index of first code of length len in symbol table */
+ int bitbuf; /* bits from stream */
+ int left; /* bits left in next or left to process */
+ short *next; /* next number of codes */
+
+ bitbuf = s->bitbuf;
+ left = s->bitcnt;
+ code = first = index = 0;
+ len = 1;
+ next = h->count + 1;
+ while (1) {
+ while (left--) {
+ code |= (bitbuf & 1) ^ 1; /* invert code */
+ bitbuf >>= 1;
+ count = *next++;
+ if (code < first + count) { /* if length len, return symbol */
+ s->bitbuf = bitbuf;
+ s->bitcnt = (s->bitcnt - len) & 7;
+ return h->symbol[index + (code - first)];
+ }
+ index += count; /* else update for next length */
+ first += count;
+ first <<= 1;
+ code <<= 1;
+ len++;
+ }
+ left = (MAXBITS+1) - len;
+ if (left == 0) break;
+ if (s->left == 0) {
+ s->left = s->infun(s->inhow, &(s->in));
+ if (s->left == 0) longjmp(s->env, 1); /* out of input */
+ }
+ bitbuf = *(s->in)++;
+ s->left--;
+ if (left > 8) left = 8;
+ }
+ return -9; /* ran out of codes */
+}
+
+/*
+ * Given a list of repeated code lengths rep[0..n-1], where each byte is a
+ * count (high four bits + 1) and a code length (low four bits), generate the
+ * list of code lengths. This compaction reduces the size of the object code.
+ * Then given the list of code lengths length[0..n-1] representing a canonical
+ * Huffman code for n symbols, construct the tables required to decode those
+ * codes. Those tables are the number of codes of each length, and the symbols
+ * sorted by length, retaining their original order within each length. The
+ * return value is zero for a complete code set, negative for an over-
+ * subscribed code set, and positive for an incomplete code set. The tables
+ * can be used if the return value is zero or positive, but they cannot be used
+ * if the return value is negative. If the return value is zero, it is not
+ * possible for decode() using that table to return an error--any stream of
+ * enough bits will resolve to a symbol. If the return value is positive, then
+ * it is possible for decode() using that table to return an error for received
+ * codes past the end of the incomplete lengths.
+ */
+local int construct(struct huffman *h, const unsigned char *rep, int n)
+{
+ int symbol; /* current symbol when stepping through length[] */
+ int len; /* current length when stepping through h->count[] */
+ int left; /* number of possible codes left of current length */
+ short offs[MAXBITS+1]; /* offsets in symbol table for each length */
+ short length[256]; /* code lengths */
+
+ /* convert compact repeat counts into symbol bit length list */
+ symbol = 0;
+ do {
+ len = *rep++;
+ left = (len >> 4) + 1;
+ len &= 15;
+ do {
+ length[symbol++] = len;
+ } while (--left);
+ } while (--n);
+ n = symbol;
+
+ /* count number of codes of each length */
+ for (len = 0; len <= MAXBITS; len++)
+ h->count[len] = 0;
+ for (symbol = 0; symbol < n; symbol++)
+ (h->count[length[symbol]])++; /* assumes lengths are within bounds */
+ if (h->count[0] == n) /* no codes! */
+ return 0; /* complete, but decode() will fail */
+
+ /* check for an over-subscribed or incomplete set of lengths */
+ left = 1; /* one possible code of zero length */
+ for (len = 1; len <= MAXBITS; len++) {
+ left <<= 1; /* one more bit, double codes left */
+ left -= h->count[len]; /* deduct count from possible codes */
+ if (left < 0) return left; /* over-subscribed--return negative */
+ } /* left > 0 means incomplete */
+
+ /* generate offsets into symbol table for each length for sorting */
+ offs[1] = 0;
+ for (len = 1; len < MAXBITS; len++)
+ offs[len + 1] = offs[len] + h->count[len];
+
+ /*
+ * put symbols in table sorted by length, by symbol order within each
+ * length
+ */
+ for (symbol = 0; symbol < n; symbol++)
+ if (length[symbol] != 0)
+ h->symbol[offs[length[symbol]]++] = symbol;
+
+ /* return zero for complete set, positive for incomplete set */
+ return left;
+}
+
+/*
+ * Decode PKWare Compression Library stream.
+ *
+ * Format notes:
+ *
+ * - First byte is 0 if literals are uncoded or 1 if they are coded. Second
+ * byte is 4, 5, or 6 for the number of extra bits in the distance code.
+ * This is the base-2 logarithm of the dictionary size minus six.
+ *
+ * - Compressed data is a combination of literals and length/distance pairs
+ * terminated by an end code. Literals are either Huffman coded or
+ * uncoded bytes. A length/distance pair is a coded length followed by a
+ * coded distance to represent a string that occurs earlier in the
+ * uncompressed data that occurs again at the current location.
+ *
+ * - A bit preceding a literal or length/distance pair indicates which comes
+ * next, 0 for literals, 1 for length/distance.
+ *
+ * - If literals are uncoded, then the next eight bits are the literal, in the
+ * normal bit order in th stream, i.e. no bit-reversal is needed. Similarly,
+ * no bit reversal is needed for either the length extra bits or the distance
+ * extra bits.
+ *
+ * - Literal bytes are simply written to the output. A length/distance pair is
+ * an instruction to copy previously uncompressed bytes to the output. The
+ * copy is from distance bytes back in the output stream, copying for length
+ * bytes.
+ *
+ * - Distances pointing before the beginning of the output data are not
+ * permitted.
+ *
+ * - Overlapped copies, where the length is greater than the distance, are
+ * allowed and common. For example, a distance of one and a length of 518
+ * simply copies the last byte 518 times. A distance of four and a length of
+ * twelve copies the last four bytes three times. A simple forward copy
+ * ignoring whether the length is greater than the distance or not implements
+ * this correctly.
+ */
+local int decomp(struct state *s)
+{
+ int lit; /* true if literals are coded */
+ int dict; /* log2(dictionary size) - 6 */
+ int symbol; /* decoded symbol, extra bits for distance */
+ int len; /* length for copy */
+ unsigned dist; /* distance for copy */
+ int copy; /* copy counter */
+ unsigned char *from, *to; /* copy pointers */
+ static int virgin = 1; /* build tables once */
+ static short litcnt[MAXBITS+1], litsym[256]; /* litcode memory */
+ static short lencnt[MAXBITS+1], lensym[16]; /* lencode memory */
+ static short distcnt[MAXBITS+1], distsym[64]; /* distcode memory */
+ static struct huffman litcode = {litcnt, litsym}; /* length code */
+ static struct huffman lencode = {lencnt, lensym}; /* length code */
+ static struct huffman distcode = {distcnt, distsym};/* distance code */
+ /* bit lengths of literal codes */
+ static const unsigned char litlen[] = {
+ 11, 124, 8, 7, 28, 7, 188, 13, 76, 4, 10, 8, 12, 10, 12, 10, 8, 23, 8,
+ 9, 7, 6, 7, 8, 7, 6, 55, 8, 23, 24, 12, 11, 7, 9, 11, 12, 6, 7, 22, 5,
+ 7, 24, 6, 11, 9, 6, 7, 22, 7, 11, 38, 7, 9, 8, 25, 11, 8, 11, 9, 12,
+ 8, 12, 5, 38, 5, 38, 5, 11, 7, 5, 6, 21, 6, 10, 53, 8, 7, 24, 10, 27,
+ 44, 253, 253, 253, 252, 252, 252, 13, 12, 45, 12, 45, 12, 61, 12, 45,
+ 44, 173};
+ /* bit lengths of length codes 0..15 */
+ static const unsigned char lenlen[] = {2, 35, 36, 53, 38, 23};
+ /* bit lengths of distance codes 0..63 */
+ static const unsigned char distlen[] = {2, 20, 53, 230, 247, 151, 248};
+ static const short base[16] = { /* base for length codes */
+ 3, 2, 4, 5, 6, 7, 8, 9, 10, 12, 16, 24, 40, 72, 136, 264};
+ static const char extra[16] = { /* extra bits for length codes */
+ 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8};
+
+ /* set up decoding tables (once--might not be thread-safe) */
+ if (virgin) {
+ construct(&litcode, litlen, sizeof(litlen));
+ construct(&lencode, lenlen, sizeof(lenlen));
+ construct(&distcode, distlen, sizeof(distlen));
+ virgin = 0;
+ }
+
+ /* read header */
+ lit = bits(s, 8);
+ if (lit > 1) return -1;
+ dict = bits(s, 8);
+ if (dict < 4 || dict > 6) return -2;
+
+ /* decode literals and length/distance pairs */
+ do {
+ if (bits(s, 1)) {
+ /* get length */
+ symbol = decode(s, &lencode);
+ len = base[symbol] + bits(s, extra[symbol]);
+ if (len == 519) break; /* end code */
+
+ /* get distance */
+ symbol = len == 2 ? 2 : dict;
+ dist = decode(s, &distcode) << symbol;
+ dist += bits(s, symbol);
+ dist++;
+ if (s->first && dist > s->next)
+ return -3; /* distance too far back */
+
+ /* copy length bytes from distance bytes back */
+ do {
+ to = s->out + s->next;
+ from = to - dist;
+ copy = MAXWIN;
+ if (s->next < dist) {
+ from += copy;
+ copy = dist;
+ }
+ copy -= s->next;
+ if (copy > len) copy = len;
+ len -= copy;
+ s->next += copy;
+ do {
+ *to++ = *from++;
+ } while (--copy);
+ if (s->next == MAXWIN) {
+ if (s->outfun(s->outhow, s->out, s->next)) return 1;
+ s->next = 0;
+ s->first = 0;
+ }
+ } while (len != 0);
+ }
+ else {
+ /* get literal and write it */
+ symbol = lit ? decode(s, &litcode) : bits(s, 8);
+ s->out[s->next++] = symbol;
+ if (s->next == MAXWIN) {
+ if (s->outfun(s->outhow, s->out, s->next)) return 1;
+ s->next = 0;
+ s->first = 0;
+ }
+ }
+ } while (1);
+ return 0;
+}
+
+/* See comments in blast.h */
+int blast(blast_in infun, void *inhow, blast_out outfun, void *outhow)
+{
+ struct state s; /* input/output state */
+ int err; /* return value */
+
+ /* initialize input state */
+ s.infun = infun;
+ s.inhow = inhow;
+ s.left = 0;
+ s.bitbuf = 0;
+ s.bitcnt = 0;
+
+ /* initialize output state */
+ s.outfun = outfun;
+ s.outhow = outhow;
+ s.next = 0;
+ s.first = 1;
+
+ /* return if bits() or decode() tries to read past available input */
+ if (setjmp(s.env) != 0) /* if came back here via longjmp(), */
+ err = 2; /* then skip decomp(), return error */
+ else
+ err = decomp(&s); /* decompress */
+
+ /* write any leftover output and update the error code if needed */
+ if (err != 1 && s.next && s.outfun(s.outhow, s.out, s.next) && err == 0)
+ err = 1;
+ return err;
+}
+
+#ifdef TEST
+/* Example of how to use blast() */
+#include
+#include
+
+#define CHUNK 16384
+
+local unsigned inf(void *how, unsigned char **buf)
+{
+ static unsigned char hold[CHUNK];
+
+ *buf = hold;
+ return fread(hold, 1, CHUNK, (FILE *)how);
+}
+
+local int outf(void *how, unsigned char *buf, unsigned len)
+{
+ return fwrite(buf, 1, len, (FILE *)how) != len;
+}
+
+/* Decompress a PKWare Compression Library stream from stdin to stdout */
+int main(void)
+{
+ int ret, n;
+
+ /* decompress to stdout */
+ ret = blast(inf, stdin, outf, stdout);
+ if (ret != 0) fprintf(stderr, "blast error: %d\n", ret);
+
+ /* see if there are any leftover bytes */
+ n = 0;
+ while (getchar() != EOF) n++;
+ if (n) fprintf(stderr, "blast warning: %d unused bytes of input\n", n);
+
+ /* return blast() error code */
+ return ret;
+}
+#endif
ADDED compat/zlib/contrib/blast/blast.h
Index: compat/zlib/contrib/blast/blast.h
==================================================================
--- compat/zlib/contrib/blast/blast.h
+++ compat/zlib/contrib/blast/blast.h
@@ -0,0 +1,75 @@
+/* blast.h -- interface for blast.c
+ Copyright (C) 2003, 2012 Mark Adler
+ version 1.2, 24 Oct 2012
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the author be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ Mark Adler madler@alumni.caltech.edu
+ */
+
+
+/*
+ * blast() decompresses the PKWare Data Compression Library (DCL) compressed
+ * format. It provides the same functionality as the explode() function in
+ * that library. (Note: PKWare overused the "implode" verb, and the format
+ * used by their library implode() function is completely different and
+ * incompatible with the implode compression method supported by PKZIP.)
+ *
+ * The binary mode for stdio functions should be used to assure that the
+ * compressed data is not corrupted when read or written. For example:
+ * fopen(..., "rb") and fopen(..., "wb").
+ */
+
+
+typedef unsigned (*blast_in)(void *how, unsigned char **buf);
+typedef int (*blast_out)(void *how, unsigned char *buf, unsigned len);
+/* Definitions for input/output functions passed to blast(). See below for
+ * what the provided functions need to do.
+ */
+
+
+int blast(blast_in infun, void *inhow, blast_out outfun, void *outhow);
+/* Decompress input to output using the provided infun() and outfun() calls.
+ * On success, the return value of blast() is zero. If there is an error in
+ * the source data, i.e. it is not in the proper format, then a negative value
+ * is returned. If there is not enough input available or there is not enough
+ * output space, then a positive error is returned.
+ *
+ * The input function is invoked: len = infun(how, &buf), where buf is set by
+ * infun() to point to the input buffer, and infun() returns the number of
+ * available bytes there. If infun() returns zero, then blast() returns with
+ * an input error. (blast() only asks for input if it needs it.) inhow is for
+ * use by the application to pass an input descriptor to infun(), if desired.
+ *
+ * The output function is invoked: err = outfun(how, buf, len), where the bytes
+ * to be written are buf[0..len-1]. If err is not zero, then blast() returns
+ * with an output error. outfun() is always called with len <= 4096. outhow
+ * is for use by the application to pass an output descriptor to outfun(), if
+ * desired.
+ *
+ * The return codes are:
+ *
+ * 2: ran out of input before completing decompression
+ * 1: output error before completing decompression
+ * 0: successful decompression
+ * -1: literal flag not zero or one
+ * -2: dictionary size not in 4..6
+ * -3: distance is too far back
+ *
+ * At the bottom of blast.c is an example program that uses blast() that can be
+ * compiled to produce a command-line decompression filter by defining TEST.
+ */
ADDED compat/zlib/contrib/blast/test.pk
Index: compat/zlib/contrib/blast/test.pk
==================================================================
--- compat/zlib/contrib/blast/test.pk
+++ compat/zlib/contrib/blast/test.pk
cannot compute difference between binary files
ADDED compat/zlib/contrib/blast/test.txt
Index: compat/zlib/contrib/blast/test.txt
==================================================================
--- compat/zlib/contrib/blast/test.txt
+++ compat/zlib/contrib/blast/test.txt
@@ -0,0 +1,1 @@
+AIAIAIAIAIAIA
ADDED compat/zlib/contrib/delphi/ZLib.pas
Index: compat/zlib/contrib/delphi/ZLib.pas
==================================================================
--- compat/zlib/contrib/delphi/ZLib.pas
+++ compat/zlib/contrib/delphi/ZLib.pas
@@ -0,0 +1,557 @@
+{*******************************************************}
+{ }
+{ Borland Delphi Supplemental Components }
+{ ZLIB Data Compression Interface Unit }
+{ }
+{ Copyright (c) 1997,99 Borland Corporation }
+{ }
+{*******************************************************}
+
+{ Updated for zlib 1.2.x by Cosmin Truta }
+
+unit ZLib;
+
+interface
+
+uses SysUtils, Classes;
+
+type
+ TAlloc = function (AppData: Pointer; Items, Size: Integer): Pointer; cdecl;
+ TFree = procedure (AppData, Block: Pointer); cdecl;
+
+ // Internal structure. Ignore.
+ TZStreamRec = packed record
+ next_in: PChar; // next input byte
+ avail_in: Integer; // number of bytes available at next_in
+ total_in: Longint; // total nb of input bytes read so far
+
+ next_out: PChar; // next output byte should be put here
+ avail_out: Integer; // remaining free space at next_out
+ total_out: Longint; // total nb of bytes output so far
+
+ msg: PChar; // last error message, NULL if no error
+ internal: Pointer; // not visible by applications
+
+ zalloc: TAlloc; // used to allocate the internal state
+ zfree: TFree; // used to free the internal state
+ AppData: Pointer; // private data object passed to zalloc and zfree
+
+ data_type: Integer; // best guess about the data type: ascii or binary
+ adler: Longint; // adler32 value of the uncompressed data
+ reserved: Longint; // reserved for future use
+ end;
+
+ // Abstract ancestor class
+ TCustomZlibStream = class(TStream)
+ private
+ FStrm: TStream;
+ FStrmPos: Integer;
+ FOnProgress: TNotifyEvent;
+ FZRec: TZStreamRec;
+ FBuffer: array [Word] of Char;
+ protected
+ procedure Progress(Sender: TObject); dynamic;
+ property OnProgress: TNotifyEvent read FOnProgress write FOnProgress;
+ constructor Create(Strm: TStream);
+ end;
+
+{ TCompressionStream compresses data on the fly as data is written to it, and
+ stores the compressed data to another stream.
+
+ TCompressionStream is write-only and strictly sequential. Reading from the
+ stream will raise an exception. Using Seek to move the stream pointer
+ will raise an exception.
+
+ Output data is cached internally, written to the output stream only when
+ the internal output buffer is full. All pending output data is flushed
+ when the stream is destroyed.
+
+ The Position property returns the number of uncompressed bytes of
+ data that have been written to the stream so far.
+
+ CompressionRate returns the on-the-fly percentage by which the original
+ data has been compressed: (1 - (CompressedBytes / UncompressedBytes)) * 100
+ If raw data size = 100 and compressed data size = 25, the CompressionRate
+ is 75%
+
+ The OnProgress event is called each time the output buffer is filled and
+ written to the output stream. This is useful for updating a progress
+ indicator when you are writing a large chunk of data to the compression
+ stream in a single call.}
+
+
+ TCompressionLevel = (clNone, clFastest, clDefault, clMax);
+
+ TCompressionStream = class(TCustomZlibStream)
+ private
+ function GetCompressionRate: Single;
+ public
+ constructor Create(CompressionLevel: TCompressionLevel; Dest: TStream);
+ destructor Destroy; override;
+ function Read(var Buffer; Count: Longint): Longint; override;
+ function Write(const Buffer; Count: Longint): Longint; override;
+ function Seek(Offset: Longint; Origin: Word): Longint; override;
+ property CompressionRate: Single read GetCompressionRate;
+ property OnProgress;
+ end;
+
+{ TDecompressionStream decompresses data on the fly as data is read from it.
+
+ Compressed data comes from a separate source stream. TDecompressionStream
+ is read-only and unidirectional; you can seek forward in the stream, but not
+ backwards. The special case of setting the stream position to zero is
+ allowed. Seeking forward decompresses data until the requested position in
+ the uncompressed data has been reached. Seeking backwards, seeking relative
+ to the end of the stream, requesting the size of the stream, and writing to
+ the stream will raise an exception.
+
+ The Position property returns the number of bytes of uncompressed data that
+ have been read from the stream so far.
+
+ The OnProgress event is called each time the internal input buffer of
+ compressed data is exhausted and the next block is read from the input stream.
+ This is useful for updating a progress indicator when you are reading a
+ large chunk of data from the decompression stream in a single call.}
+
+ TDecompressionStream = class(TCustomZlibStream)
+ public
+ constructor Create(Source: TStream);
+ destructor Destroy; override;
+ function Read(var Buffer; Count: Longint): Longint; override;
+ function Write(const Buffer; Count: Longint): Longint; override;
+ function Seek(Offset: Longint; Origin: Word): Longint; override;
+ property OnProgress;
+ end;
+
+
+
+{ CompressBuf compresses data, buffer to buffer, in one call.
+ In: InBuf = ptr to compressed data
+ InBytes = number of bytes in InBuf
+ Out: OutBuf = ptr to newly allocated buffer containing decompressed data
+ OutBytes = number of bytes in OutBuf }
+procedure CompressBuf(const InBuf: Pointer; InBytes: Integer;
+ out OutBuf: Pointer; out OutBytes: Integer);
+
+
+{ DecompressBuf decompresses data, buffer to buffer, in one call.
+ In: InBuf = ptr to compressed data
+ InBytes = number of bytes in InBuf
+ OutEstimate = zero, or est. size of the decompressed data
+ Out: OutBuf = ptr to newly allocated buffer containing decompressed data
+ OutBytes = number of bytes in OutBuf }
+procedure DecompressBuf(const InBuf: Pointer; InBytes: Integer;
+ OutEstimate: Integer; out OutBuf: Pointer; out OutBytes: Integer);
+
+{ DecompressToUserBuf decompresses data, buffer to buffer, in one call.
+ In: InBuf = ptr to compressed data
+ InBytes = number of bytes in InBuf
+ Out: OutBuf = ptr to user-allocated buffer to contain decompressed data
+ BufSize = number of bytes in OutBuf }
+procedure DecompressToUserBuf(const InBuf: Pointer; InBytes: Integer;
+ const OutBuf: Pointer; BufSize: Integer);
+
+const
+ zlib_version = '1.2.8';
+
+type
+ EZlibError = class(Exception);
+ ECompressionError = class(EZlibError);
+ EDecompressionError = class(EZlibError);
+
+implementation
+
+uses ZLibConst;
+
+const
+ Z_NO_FLUSH = 0;
+ Z_PARTIAL_FLUSH = 1;
+ Z_SYNC_FLUSH = 2;
+ Z_FULL_FLUSH = 3;
+ Z_FINISH = 4;
+
+ Z_OK = 0;
+ Z_STREAM_END = 1;
+ Z_NEED_DICT = 2;
+ Z_ERRNO = (-1);
+ Z_STREAM_ERROR = (-2);
+ Z_DATA_ERROR = (-3);
+ Z_MEM_ERROR = (-4);
+ Z_BUF_ERROR = (-5);
+ Z_VERSION_ERROR = (-6);
+
+ Z_NO_COMPRESSION = 0;
+ Z_BEST_SPEED = 1;
+ Z_BEST_COMPRESSION = 9;
+ Z_DEFAULT_COMPRESSION = (-1);
+
+ Z_FILTERED = 1;
+ Z_HUFFMAN_ONLY = 2;
+ Z_RLE = 3;
+ Z_DEFAULT_STRATEGY = 0;
+
+ Z_BINARY = 0;
+ Z_ASCII = 1;
+ Z_UNKNOWN = 2;
+
+ Z_DEFLATED = 8;
+
+
+{$L adler32.obj}
+{$L compress.obj}
+{$L crc32.obj}
+{$L deflate.obj}
+{$L infback.obj}
+{$L inffast.obj}
+{$L inflate.obj}
+{$L inftrees.obj}
+{$L trees.obj}
+{$L uncompr.obj}
+{$L zutil.obj}
+
+procedure adler32; external;
+procedure compressBound; external;
+procedure crc32; external;
+procedure deflateInit2_; external;
+procedure deflateParams; external;
+
+function _malloc(Size: Integer): Pointer; cdecl;
+begin
+ Result := AllocMem(Size);
+end;
+
+procedure _free(Block: Pointer); cdecl;
+begin
+ FreeMem(Block);
+end;
+
+procedure _memset(P: Pointer; B: Byte; count: Integer); cdecl;
+begin
+ FillChar(P^, count, B);
+end;
+
+procedure _memcpy(dest, source: Pointer; count: Integer); cdecl;
+begin
+ Move(source^, dest^, count);
+end;
+
+
+
+// deflate compresses data
+function deflateInit_(var strm: TZStreamRec; level: Integer; version: PChar;
+ recsize: Integer): Integer; external;
+function deflate(var strm: TZStreamRec; flush: Integer): Integer; external;
+function deflateEnd(var strm: TZStreamRec): Integer; external;
+
+// inflate decompresses data
+function inflateInit_(var strm: TZStreamRec; version: PChar;
+ recsize: Integer): Integer; external;
+function inflate(var strm: TZStreamRec; flush: Integer): Integer; external;
+function inflateEnd(var strm: TZStreamRec): Integer; external;
+function inflateReset(var strm: TZStreamRec): Integer; external;
+
+
+function zlibAllocMem(AppData: Pointer; Items, Size: Integer): Pointer; cdecl;
+begin
+// GetMem(Result, Items*Size);
+ Result := AllocMem(Items * Size);
+end;
+
+procedure zlibFreeMem(AppData, Block: Pointer); cdecl;
+begin
+ FreeMem(Block);
+end;
+
+{function zlibCheck(code: Integer): Integer;
+begin
+ Result := code;
+ if code < 0 then
+ raise EZlibError.Create('error'); //!!
+end;}
+
+function CCheck(code: Integer): Integer;
+begin
+ Result := code;
+ if code < 0 then
+ raise ECompressionError.Create('error'); //!!
+end;
+
+function DCheck(code: Integer): Integer;
+begin
+ Result := code;
+ if code < 0 then
+ raise EDecompressionError.Create('error'); //!!
+end;
+
+procedure CompressBuf(const InBuf: Pointer; InBytes: Integer;
+ out OutBuf: Pointer; out OutBytes: Integer);
+var
+ strm: TZStreamRec;
+ P: Pointer;
+begin
+ FillChar(strm, sizeof(strm), 0);
+ strm.zalloc := zlibAllocMem;
+ strm.zfree := zlibFreeMem;
+ OutBytes := ((InBytes + (InBytes div 10) + 12) + 255) and not 255;
+ GetMem(OutBuf, OutBytes);
+ try
+ strm.next_in := InBuf;
+ strm.avail_in := InBytes;
+ strm.next_out := OutBuf;
+ strm.avail_out := OutBytes;
+ CCheck(deflateInit_(strm, Z_BEST_COMPRESSION, zlib_version, sizeof(strm)));
+ try
+ while CCheck(deflate(strm, Z_FINISH)) <> Z_STREAM_END do
+ begin
+ P := OutBuf;
+ Inc(OutBytes, 256);
+ ReallocMem(OutBuf, OutBytes);
+ strm.next_out := PChar(Integer(OutBuf) + (Integer(strm.next_out) - Integer(P)));
+ strm.avail_out := 256;
+ end;
+ finally
+ CCheck(deflateEnd(strm));
+ end;
+ ReallocMem(OutBuf, strm.total_out);
+ OutBytes := strm.total_out;
+ except
+ FreeMem(OutBuf);
+ raise
+ end;
+end;
+
+
+procedure DecompressBuf(const InBuf: Pointer; InBytes: Integer;
+ OutEstimate: Integer; out OutBuf: Pointer; out OutBytes: Integer);
+var
+ strm: TZStreamRec;
+ P: Pointer;
+ BufInc: Integer;
+begin
+ FillChar(strm, sizeof(strm), 0);
+ strm.zalloc := zlibAllocMem;
+ strm.zfree := zlibFreeMem;
+ BufInc := (InBytes + 255) and not 255;
+ if OutEstimate = 0 then
+ OutBytes := BufInc
+ else
+ OutBytes := OutEstimate;
+ GetMem(OutBuf, OutBytes);
+ try
+ strm.next_in := InBuf;
+ strm.avail_in := InBytes;
+ strm.next_out := OutBuf;
+ strm.avail_out := OutBytes;
+ DCheck(inflateInit_(strm, zlib_version, sizeof(strm)));
+ try
+ while DCheck(inflate(strm, Z_NO_FLUSH)) <> Z_STREAM_END do
+ begin
+ P := OutBuf;
+ Inc(OutBytes, BufInc);
+ ReallocMem(OutBuf, OutBytes);
+ strm.next_out := PChar(Integer(OutBuf) + (Integer(strm.next_out) - Integer(P)));
+ strm.avail_out := BufInc;
+ end;
+ finally
+ DCheck(inflateEnd(strm));
+ end;
+ ReallocMem(OutBuf, strm.total_out);
+ OutBytes := strm.total_out;
+ except
+ FreeMem(OutBuf);
+ raise
+ end;
+end;
+
+procedure DecompressToUserBuf(const InBuf: Pointer; InBytes: Integer;
+ const OutBuf: Pointer; BufSize: Integer);
+var
+ strm: TZStreamRec;
+begin
+ FillChar(strm, sizeof(strm), 0);
+ strm.zalloc := zlibAllocMem;
+ strm.zfree := zlibFreeMem;
+ strm.next_in := InBuf;
+ strm.avail_in := InBytes;
+ strm.next_out := OutBuf;
+ strm.avail_out := BufSize;
+ DCheck(inflateInit_(strm, zlib_version, sizeof(strm)));
+ try
+ if DCheck(inflate(strm, Z_FINISH)) <> Z_STREAM_END then
+ raise EZlibError.CreateRes(@sTargetBufferTooSmall);
+ finally
+ DCheck(inflateEnd(strm));
+ end;
+end;
+
+// TCustomZlibStream
+
+constructor TCustomZLibStream.Create(Strm: TStream);
+begin
+ inherited Create;
+ FStrm := Strm;
+ FStrmPos := Strm.Position;
+ FZRec.zalloc := zlibAllocMem;
+ FZRec.zfree := zlibFreeMem;
+end;
+
+procedure TCustomZLibStream.Progress(Sender: TObject);
+begin
+ if Assigned(FOnProgress) then FOnProgress(Sender);
+end;
+
+
+// TCompressionStream
+
+constructor TCompressionStream.Create(CompressionLevel: TCompressionLevel;
+ Dest: TStream);
+const
+ Levels: array [TCompressionLevel] of ShortInt =
+ (Z_NO_COMPRESSION, Z_BEST_SPEED, Z_DEFAULT_COMPRESSION, Z_BEST_COMPRESSION);
+begin
+ inherited Create(Dest);
+ FZRec.next_out := FBuffer;
+ FZRec.avail_out := sizeof(FBuffer);
+ CCheck(deflateInit_(FZRec, Levels[CompressionLevel], zlib_version, sizeof(FZRec)));
+end;
+
+destructor TCompressionStream.Destroy;
+begin
+ FZRec.next_in := nil;
+ FZRec.avail_in := 0;
+ try
+ if FStrm.Position <> FStrmPos then FStrm.Position := FStrmPos;
+ while (CCheck(deflate(FZRec, Z_FINISH)) <> Z_STREAM_END)
+ and (FZRec.avail_out = 0) do
+ begin
+ FStrm.WriteBuffer(FBuffer, sizeof(FBuffer));
+ FZRec.next_out := FBuffer;
+ FZRec.avail_out := sizeof(FBuffer);
+ end;
+ if FZRec.avail_out < sizeof(FBuffer) then
+ FStrm.WriteBuffer(FBuffer, sizeof(FBuffer) - FZRec.avail_out);
+ finally
+ deflateEnd(FZRec);
+ end;
+ inherited Destroy;
+end;
+
+function TCompressionStream.Read(var Buffer; Count: Longint): Longint;
+begin
+ raise ECompressionError.CreateRes(@sInvalidStreamOp);
+end;
+
+function TCompressionStream.Write(const Buffer; Count: Longint): Longint;
+begin
+ FZRec.next_in := @Buffer;
+ FZRec.avail_in := Count;
+ if FStrm.Position <> FStrmPos then FStrm.Position := FStrmPos;
+ while (FZRec.avail_in > 0) do
+ begin
+ CCheck(deflate(FZRec, 0));
+ if FZRec.avail_out = 0 then
+ begin
+ FStrm.WriteBuffer(FBuffer, sizeof(FBuffer));
+ FZRec.next_out := FBuffer;
+ FZRec.avail_out := sizeof(FBuffer);
+ FStrmPos := FStrm.Position;
+ Progress(Self);
+ end;
+ end;
+ Result := Count;
+end;
+
+function TCompressionStream.Seek(Offset: Longint; Origin: Word): Longint;
+begin
+ if (Offset = 0) and (Origin = soFromCurrent) then
+ Result := FZRec.total_in
+ else
+ raise ECompressionError.CreateRes(@sInvalidStreamOp);
+end;
+
+function TCompressionStream.GetCompressionRate: Single;
+begin
+ if FZRec.total_in = 0 then
+ Result := 0
+ else
+ Result := (1.0 - (FZRec.total_out / FZRec.total_in)) * 100.0;
+end;
+
+
+// TDecompressionStream
+
+constructor TDecompressionStream.Create(Source: TStream);
+begin
+ inherited Create(Source);
+ FZRec.next_in := FBuffer;
+ FZRec.avail_in := 0;
+ DCheck(inflateInit_(FZRec, zlib_version, sizeof(FZRec)));
+end;
+
+destructor TDecompressionStream.Destroy;
+begin
+ FStrm.Seek(-FZRec.avail_in, 1);
+ inflateEnd(FZRec);
+ inherited Destroy;
+end;
+
+function TDecompressionStream.Read(var Buffer; Count: Longint): Longint;
+begin
+ FZRec.next_out := @Buffer;
+ FZRec.avail_out := Count;
+ if FStrm.Position <> FStrmPos then FStrm.Position := FStrmPos;
+ while (FZRec.avail_out > 0) do
+ begin
+ if FZRec.avail_in = 0 then
+ begin
+ FZRec.avail_in := FStrm.Read(FBuffer, sizeof(FBuffer));
+ if FZRec.avail_in = 0 then
+ begin
+ Result := Count - FZRec.avail_out;
+ Exit;
+ end;
+ FZRec.next_in := FBuffer;
+ FStrmPos := FStrm.Position;
+ Progress(Self);
+ end;
+ CCheck(inflate(FZRec, 0));
+ end;
+ Result := Count;
+end;
+
+function TDecompressionStream.Write(const Buffer; Count: Longint): Longint;
+begin
+ raise EDecompressionError.CreateRes(@sInvalidStreamOp);
+end;
+
+function TDecompressionStream.Seek(Offset: Longint; Origin: Word): Longint;
+var
+ I: Integer;
+ Buf: array [0..4095] of Char;
+begin
+ if (Offset = 0) and (Origin = soFromBeginning) then
+ begin
+ DCheck(inflateReset(FZRec));
+ FZRec.next_in := FBuffer;
+ FZRec.avail_in := 0;
+ FStrm.Position := 0;
+ FStrmPos := 0;
+ end
+ else if ( (Offset >= 0) and (Origin = soFromCurrent)) or
+ ( ((Offset - FZRec.total_out) > 0) and (Origin = soFromBeginning)) then
+ begin
+ if Origin = soFromBeginning then Dec(Offset, FZRec.total_out);
+ if Offset > 0 then
+ begin
+ for I := 1 to Offset div sizeof(Buf) do
+ ReadBuffer(Buf, sizeof(Buf));
+ ReadBuffer(Buf, Offset mod sizeof(Buf));
+ end;
+ end
+ else
+ raise EDecompressionError.CreateRes(@sInvalidStreamOp);
+ Result := FZRec.total_out;
+end;
+
+
+end.
ADDED compat/zlib/contrib/delphi/ZLibConst.pas
Index: compat/zlib/contrib/delphi/ZLibConst.pas
==================================================================
--- compat/zlib/contrib/delphi/ZLibConst.pas
+++ compat/zlib/contrib/delphi/ZLibConst.pas
@@ -0,0 +1,11 @@
+unit ZLibConst;
+
+interface
+
+resourcestring
+ sTargetBufferTooSmall = 'ZLib error: target buffer may be too small';
+ sInvalidStreamOp = 'Invalid stream operation';
+
+implementation
+
+end.
ADDED compat/zlib/contrib/delphi/readme.txt
Index: compat/zlib/contrib/delphi/readme.txt
==================================================================
--- compat/zlib/contrib/delphi/readme.txt
+++ compat/zlib/contrib/delphi/readme.txt
@@ -0,0 +1,76 @@
+
+Overview
+========
+
+This directory contains an update to the ZLib interface unit,
+distributed by Borland as a Delphi supplemental component.
+
+The original ZLib unit is Copyright (c) 1997,99 Borland Corp.,
+and is based on zlib version 1.0.4. There are a series of bugs
+and security problems associated with that old zlib version, and
+we recommend the users to update their ZLib unit.
+
+
+Summary of modifications
+========================
+
+- Improved makefile, adapted to zlib version 1.2.1.
+
+- Some field types from TZStreamRec are changed from Integer to
+ Longint, for consistency with the zlib.h header, and for 64-bit
+ readiness.
+
+- The zlib_version constant is updated.
+
+- The new Z_RLE strategy has its corresponding symbolic constant.
+
+- The allocation and deallocation functions and function types
+ (TAlloc, TFree, zlibAllocMem and zlibFreeMem) are now cdecl,
+ and _malloc and _free are added as C RTL stubs. As a result,
+ the original C sources of zlib can be compiled out of the box,
+ and linked to the ZLib unit.
+
+
+Suggestions for improvements
+============================
+
+Currently, the ZLib unit provides only a limited wrapper around
+the zlib library, and much of the original zlib functionality is
+missing. Handling compressed file formats like ZIP/GZIP or PNG
+cannot be implemented without having this functionality.
+Applications that handle these formats are either using their own,
+duplicated code, or not using the ZLib unit at all.
+
+Here are a few suggestions:
+
+- Checksum class wrappers around adler32() and crc32(), similar
+ to the Java classes that implement the java.util.zip.Checksum
+ interface.
+
+- The ability to read and write raw deflate streams, without the
+ zlib stream header and trailer. Raw deflate streams are used
+ in the ZIP file format.
+
+- The ability to read and write gzip streams, used in the GZIP
+ file format, and normally produced by the gzip program.
+
+- The ability to select a different compression strategy, useful
+ to PNG and MNG image compression, and to multimedia compression
+ in general. Besides the compression level
+
+ TCompressionLevel = (clNone, clFastest, clDefault, clMax);
+
+ which, in fact, could have used the 'z' prefix and avoided
+ TColor-like symbols
+
+ TCompressionLevel = (zcNone, zcFastest, zcDefault, zcMax);
+
+ there could be a compression strategy
+
+ TCompressionStrategy = (zsDefault, zsFiltered, zsHuffmanOnly, zsRle);
+
+- ZIP and GZIP stream handling via TStreams.
+
+
+--
+Cosmin Truta
ADDED compat/zlib/contrib/delphi/zlibd32.mak
Index: compat/zlib/contrib/delphi/zlibd32.mak
==================================================================
--- compat/zlib/contrib/delphi/zlibd32.mak
+++ compat/zlib/contrib/delphi/zlibd32.mak
@@ -0,0 +1,99 @@
+# Makefile for zlib
+# For use with Delphi and C++ Builder under Win32
+# Updated for zlib 1.2.x by Cosmin Truta
+
+# ------------ Borland C++ ------------
+
+# This project uses the Delphi (fastcall/register) calling convention:
+LOC = -DZEXPORT=__fastcall -DZEXPORTVA=__cdecl
+
+CC = bcc32
+LD = bcc32
+AR = tlib
+# do not use "-pr" in CFLAGS
+CFLAGS = -a -d -k- -O2 $(LOC)
+LDFLAGS =
+
+
+# variables
+ZLIB_LIB = zlib.lib
+
+OBJ1 = adler32.obj compress.obj crc32.obj deflate.obj gzclose.obj gzlib.obj gzread.obj
+OBJ2 = gzwrite.obj infback.obj inffast.obj inflate.obj inftrees.obj trees.obj uncompr.obj zutil.obj
+OBJP1 = +adler32.obj+compress.obj+crc32.obj+deflate.obj+gzclose.obj+gzlib.obj+gzread.obj
+OBJP2 = +gzwrite.obj+infback.obj+inffast.obj+inflate.obj+inftrees.obj+trees.obj+uncompr.obj+zutil.obj
+
+
+# targets
+all: $(ZLIB_LIB) example.exe minigzip.exe
+
+.c.obj:
+ $(CC) -c $(CFLAGS) $*.c
+
+adler32.obj: adler32.c zlib.h zconf.h
+
+compress.obj: compress.c zlib.h zconf.h
+
+crc32.obj: crc32.c zlib.h zconf.h crc32.h
+
+deflate.obj: deflate.c deflate.h zutil.h zlib.h zconf.h
+
+gzclose.obj: gzclose.c zlib.h zconf.h gzguts.h
+
+gzlib.obj: gzlib.c zlib.h zconf.h gzguts.h
+
+gzread.obj: gzread.c zlib.h zconf.h gzguts.h
+
+gzwrite.obj: gzwrite.c zlib.h zconf.h gzguts.h
+
+infback.obj: infback.c zutil.h zlib.h zconf.h inftrees.h inflate.h \
+ inffast.h inffixed.h
+
+inffast.obj: inffast.c zutil.h zlib.h zconf.h inftrees.h inflate.h \
+ inffast.h
+
+inflate.obj: inflate.c zutil.h zlib.h zconf.h inftrees.h inflate.h \
+ inffast.h inffixed.h
+
+inftrees.obj: inftrees.c zutil.h zlib.h zconf.h inftrees.h
+
+trees.obj: trees.c zutil.h zlib.h zconf.h deflate.h trees.h
+
+uncompr.obj: uncompr.c zlib.h zconf.h
+
+zutil.obj: zutil.c zutil.h zlib.h zconf.h
+
+example.obj: test/example.c zlib.h zconf.h
+
+minigzip.obj: test/minigzip.c zlib.h zconf.h
+
+
+# For the sake of the old Borland make,
+# the command line is cut to fit in the MS-DOS 128 byte limit:
+$(ZLIB_LIB): $(OBJ1) $(OBJ2)
+ -del $(ZLIB_LIB)
+ $(AR) $(ZLIB_LIB) $(OBJP1)
+ $(AR) $(ZLIB_LIB) $(OBJP2)
+
+
+# testing
+test: example.exe minigzip.exe
+ example
+ echo hello world | minigzip | minigzip -d
+
+example.exe: example.obj $(ZLIB_LIB)
+ $(LD) $(LDFLAGS) example.obj $(ZLIB_LIB)
+
+minigzip.exe: minigzip.obj $(ZLIB_LIB)
+ $(LD) $(LDFLAGS) minigzip.obj $(ZLIB_LIB)
+
+
+# cleanup
+clean:
+ -del *.obj
+ -del *.exe
+ -del *.lib
+ -del *.tds
+ -del zlib.bak
+ -del foo.gz
+
ADDED compat/zlib/contrib/dotzlib/DotZLib.build
Index: compat/zlib/contrib/dotzlib/DotZLib.build
==================================================================
--- compat/zlib/contrib/dotzlib/DotZLib.build
+++ compat/zlib/contrib/dotzlib/DotZLib.build
@@ -0,0 +1,33 @@
+
+
+ A .Net wrapper library around ZLib1.dll
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
ADDED compat/zlib/contrib/dotzlib/DotZLib.chm
Index: compat/zlib/contrib/dotzlib/DotZLib.chm
==================================================================
--- compat/zlib/contrib/dotzlib/DotZLib.chm
+++ compat/zlib/contrib/dotzlib/DotZLib.chm
cannot compute difference between binary files
ADDED compat/zlib/contrib/dotzlib/DotZLib.sln
Index: compat/zlib/contrib/dotzlib/DotZLib.sln
==================================================================
--- compat/zlib/contrib/dotzlib/DotZLib.sln
+++ compat/zlib/contrib/dotzlib/DotZLib.sln
@@ -0,0 +1,21 @@
+Microsoft Visual Studio Solution File, Format Version 8.00
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DotZLib", "DotZLib\DotZLib.csproj", "{BB1EE0B1-1808-46CB-B786-949D91117FC5}"
+ ProjectSection(ProjectDependencies) = postProject
+ EndProjectSection
+EndProject
+Global
+ GlobalSection(SolutionConfiguration) = preSolution
+ Debug = Debug
+ Release = Release
+ EndGlobalSection
+ GlobalSection(ProjectConfiguration) = postSolution
+ {BB1EE0B1-1808-46CB-B786-949D91117FC5}.Debug.ActiveCfg = Debug|.NET
+ {BB1EE0B1-1808-46CB-B786-949D91117FC5}.Debug.Build.0 = Debug|.NET
+ {BB1EE0B1-1808-46CB-B786-949D91117FC5}.Release.ActiveCfg = Release|.NET
+ {BB1EE0B1-1808-46CB-B786-949D91117FC5}.Release.Build.0 = Release|.NET
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ EndGlobalSection
+ GlobalSection(ExtensibilityAddIns) = postSolution
+ EndGlobalSection
+EndGlobal
ADDED compat/zlib/contrib/dotzlib/DotZLib/AssemblyInfo.cs
Index: compat/zlib/contrib/dotzlib/DotZLib/AssemblyInfo.cs
==================================================================
--- compat/zlib/contrib/dotzlib/DotZLib/AssemblyInfo.cs
+++ compat/zlib/contrib/dotzlib/DotZLib/AssemblyInfo.cs
@@ -0,0 +1,58 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+
+//
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+//
+[assembly: AssemblyTitle("DotZLib")]
+[assembly: AssemblyDescription(".Net bindings for ZLib compression dll 1.2.x")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("Henrik Ravn")]
+[assembly: AssemblyProduct("")]
+[assembly: AssemblyCopyright("(c) 2004 by Henrik Ravn")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+//
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Revision and Build Numbers
+// by using the '*' as shown below:
+
+[assembly: AssemblyVersion("1.0.*")]
+
+//
+// In order to sign your assembly you must specify a key to use. Refer to the
+// Microsoft .NET Framework documentation for more information on assembly signing.
+//
+// Use the attributes below to control which key is used for signing.
+//
+// Notes:
+// (*) If no key is specified, the assembly is not signed.
+// (*) KeyName refers to a key that has been installed in the Crypto Service
+// Provider (CSP) on your machine. KeyFile refers to a file which contains
+// a key.
+// (*) If the KeyFile and the KeyName values are both specified, the
+// following processing occurs:
+// (1) If the KeyName can be found in the CSP, that key is used.
+// (2) If the KeyName does not exist and the KeyFile does exist, the key
+// in the KeyFile is installed into the CSP and used.
+// (*) In order to create a KeyFile, you can use the sn.exe (Strong Name) utility.
+// When specifying the KeyFile, the location of the KeyFile should be
+// relative to the project output directory which is
+// %Project Directory%\obj\. For example, if your KeyFile is
+// located in the project directory, you would specify the AssemblyKeyFile
+// attribute as [assembly: AssemblyKeyFile("..\\..\\mykey.snk")]
+// (*) Delay Signing is an advanced option - see the Microsoft .NET Framework
+// documentation for more information on this.
+//
+[assembly: AssemblyDelaySign(false)]
+[assembly: AssemblyKeyFile("")]
+[assembly: AssemblyKeyName("")]
ADDED compat/zlib/contrib/dotzlib/DotZLib/ChecksumImpl.cs
Index: compat/zlib/contrib/dotzlib/DotZLib/ChecksumImpl.cs
==================================================================
--- compat/zlib/contrib/dotzlib/DotZLib/ChecksumImpl.cs
+++ compat/zlib/contrib/dotzlib/DotZLib/ChecksumImpl.cs
@@ -0,0 +1,202 @@
+//
+// © Copyright Henrik Ravn 2004
+//
+// Use, modification and distribution are subject to the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+using System;
+using System.Runtime.InteropServices;
+using System.Text;
+
+
+namespace DotZLib
+{
+ #region ChecksumGeneratorBase
+ ///
+ /// Implements the common functionality needed for all s
+ ///
+ ///
+ public abstract class ChecksumGeneratorBase : ChecksumGenerator
+ {
+ ///
+ /// The value of the current checksum
+ ///
+ protected uint _current;
+
+ ///
+ /// Initializes a new instance of the checksum generator base - the current checksum is
+ /// set to zero
+ ///
+ public ChecksumGeneratorBase()
+ {
+ _current = 0;
+ }
+
+ ///
+ /// Initializes a new instance of the checksum generator basewith a specified value
+ ///
+ /// The value to set the current checksum to
+ public ChecksumGeneratorBase(uint initialValue)
+ {
+ _current = initialValue;
+ }
+
+ ///
+ /// Resets the current checksum to zero
+ ///
+ public void Reset() { _current = 0; }
+
+ ///
+ /// Gets the current checksum value
+ ///
+ public uint Value { get { return _current; } }
+
+ ///
+ /// Updates the current checksum with part of an array of bytes
+ ///
+ /// The data to update the checksum with
+ /// Where in data to start updating
+ /// The number of bytes from data to use
+ /// The sum of offset and count is larger than the length of data
+ /// data is a null reference
+ /// Offset or count is negative.
+ /// All the other Update methods are implmeneted in terms of this one.
+ /// This is therefore the only method a derived class has to implement
+ public abstract void Update(byte[] data, int offset, int count);
+
+ ///
+ /// Updates the current checksum with an array of bytes.
+ ///
+ /// The data to update the checksum with
+ public void Update(byte[] data)
+ {
+ Update(data, 0, data.Length);
+ }
+
+ ///
+ /// Updates the current checksum with the data from a string
+ ///
+ /// The string to update the checksum with
+ /// The characters in the string are converted by the UTF-8 encoding
+ public void Update(string data)
+ {
+ Update(Encoding.UTF8.GetBytes(data));
+ }
+
+ ///
+ /// Updates the current checksum with the data from a string, using a specific encoding
+ ///
+ /// The string to update the checksum with
+ /// The encoding to use
+ public void Update(string data, Encoding encoding)
+ {
+ Update(encoding.GetBytes(data));
+ }
+
+ }
+ #endregion
+
+ #region CRC32
+ ///
+ /// Implements a CRC32 checksum generator
+ ///
+ public sealed class CRC32Checksum : ChecksumGeneratorBase
+ {
+ #region DLL imports
+
+ [DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl)]
+ private static extern uint crc32(uint crc, int data, uint length);
+
+ #endregion
+
+ ///
+ /// Initializes a new instance of the CRC32 checksum generator
+ ///
+ public CRC32Checksum() : base() {}
+
+ ///
+ /// Initializes a new instance of the CRC32 checksum generator with a specified value
+ ///
+ /// The value to set the current checksum to
+ public CRC32Checksum(uint initialValue) : base(initialValue) {}
+
+ ///
+ /// Updates the current checksum with part of an array of bytes
+ ///
+ /// The data to update the checksum with
+ /// Where in data to start updating
+ /// The number of bytes from data to use
+ /// The sum of offset and count is larger than the length of data
+ /// data is a null reference
+ /// Offset or count is negative.
+ public override void Update(byte[] data, int offset, int count)
+ {
+ if (offset < 0 || count < 0) throw new ArgumentOutOfRangeException();
+ if ((offset+count) > data.Length) throw new ArgumentException();
+ GCHandle hData = GCHandle.Alloc(data, GCHandleType.Pinned);
+ try
+ {
+ _current = crc32(_current, hData.AddrOfPinnedObject().ToInt32()+offset, (uint)count);
+ }
+ finally
+ {
+ hData.Free();
+ }
+ }
+
+ }
+ #endregion
+
+ #region Adler
+ ///
+ /// Implements a checksum generator that computes the Adler checksum on data
+ ///
+ public sealed class AdlerChecksum : ChecksumGeneratorBase
+ {
+ #region DLL imports
+
+ [DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl)]
+ private static extern uint adler32(uint adler, int data, uint length);
+
+ #endregion
+
+ ///
+ /// Initializes a new instance of the Adler checksum generator
+ ///
+ public AdlerChecksum() : base() {}
+
+ ///
+ /// Initializes a new instance of the Adler checksum generator with a specified value
+ ///
+ /// The value to set the current checksum to
+ public AdlerChecksum(uint initialValue) : base(initialValue) {}
+
+ ///
+ /// Updates the current checksum with part of an array of bytes
+ ///
+ /// The data to update the checksum with
+ /// Where in data to start updating
+ /// The number of bytes from data to use
+ /// The sum of offset and count is larger than the length of data
+ /// data is a null reference
+ /// Offset or count is negative.
+ public override void Update(byte[] data, int offset, int count)
+ {
+ if (offset < 0 || count < 0) throw new ArgumentOutOfRangeException();
+ if ((offset+count) > data.Length) throw new ArgumentException();
+ GCHandle hData = GCHandle.Alloc(data, GCHandleType.Pinned);
+ try
+ {
+ _current = adler32(_current, hData.AddrOfPinnedObject().ToInt32()+offset, (uint)count);
+ }
+ finally
+ {
+ hData.Free();
+ }
+ }
+
+ }
+ #endregion
+
+}
ADDED compat/zlib/contrib/dotzlib/DotZLib/CircularBuffer.cs
Index: compat/zlib/contrib/dotzlib/DotZLib/CircularBuffer.cs
==================================================================
--- compat/zlib/contrib/dotzlib/DotZLib/CircularBuffer.cs
+++ compat/zlib/contrib/dotzlib/DotZLib/CircularBuffer.cs
@@ -0,0 +1,83 @@
+//
+// © Copyright Henrik Ravn 2004
+//
+// Use, modification and distribution are subject to the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+using System;
+using System.Diagnostics;
+
+namespace DotZLib
+{
+
+ ///
+ /// This class implements a circular buffer
+ ///
+ internal class CircularBuffer
+ {
+ #region Private data
+ private int _capacity;
+ private int _head;
+ private int _tail;
+ private int _size;
+ private byte[] _buffer;
+ #endregion
+
+ public CircularBuffer(int capacity)
+ {
+ Debug.Assert( capacity > 0 );
+ _buffer = new byte[capacity];
+ _capacity = capacity;
+ _head = 0;
+ _tail = 0;
+ _size = 0;
+ }
+
+ public int Size { get { return _size; } }
+
+ public int Put(byte[] source, int offset, int count)
+ {
+ Debug.Assert( count > 0 );
+ int trueCount = Math.Min(count, _capacity - Size);
+ for (int i = 0; i < trueCount; ++i)
+ _buffer[(_tail+i) % _capacity] = source[offset+i];
+ _tail += trueCount;
+ _tail %= _capacity;
+ _size += trueCount;
+ return trueCount;
+ }
+
+ public bool Put(byte b)
+ {
+ if (Size == _capacity) // no room
+ return false;
+ _buffer[_tail++] = b;
+ _tail %= _capacity;
+ ++_size;
+ return true;
+ }
+
+ public int Get(byte[] destination, int offset, int count)
+ {
+ int trueCount = Math.Min(count,Size);
+ for (int i = 0; i < trueCount; ++i)
+ destination[offset + i] = _buffer[(_head+i) % _capacity];
+ _head += trueCount;
+ _head %= _capacity;
+ _size -= trueCount;
+ return trueCount;
+ }
+
+ public int Get()
+ {
+ if (Size == 0)
+ return -1;
+
+ int result = (int)_buffer[_head++ % _capacity];
+ --_size;
+ return result;
+ }
+
+ }
+}
ADDED compat/zlib/contrib/dotzlib/DotZLib/CodecBase.cs
Index: compat/zlib/contrib/dotzlib/DotZLib/CodecBase.cs
==================================================================
--- compat/zlib/contrib/dotzlib/DotZLib/CodecBase.cs
+++ compat/zlib/contrib/dotzlib/DotZLib/CodecBase.cs
@@ -0,0 +1,198 @@
+//
+// © Copyright Henrik Ravn 2004
+//
+// Use, modification and distribution are subject to the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+using System;
+using System.Runtime.InteropServices;
+
+namespace DotZLib
+{
+ ///
+ /// Implements the common functionality needed for all s
+ ///
+ public abstract class CodecBase : Codec, IDisposable
+ {
+
+ #region Data members
+
+ ///
+ /// Instance of the internal zlib buffer structure that is
+ /// passed to all functions in the zlib dll
+ ///
+ internal ZStream _ztream = new ZStream();
+
+ ///
+ /// True if the object instance has been disposed, false otherwise
+ ///
+ protected bool _isDisposed = false;
+
+ ///
+ /// The size of the internal buffers
+ ///
+ protected const int kBufferSize = 16384;
+
+ private byte[] _outBuffer = new byte[kBufferSize];
+ private byte[] _inBuffer = new byte[kBufferSize];
+
+ private GCHandle _hInput;
+ private GCHandle _hOutput;
+
+ private uint _checksum = 0;
+
+ #endregion
+
+ ///
+ /// Initializes a new instance of the CodeBase class.
+ ///
+ public CodecBase()
+ {
+ try
+ {
+ _hInput = GCHandle.Alloc(_inBuffer, GCHandleType.Pinned);
+ _hOutput = GCHandle.Alloc(_outBuffer, GCHandleType.Pinned);
+ }
+ catch (Exception)
+ {
+ CleanUp(false);
+ throw;
+ }
+ }
+
+
+ #region Codec Members
+
+ ///
+ /// Occurs when more processed data are available.
+ ///
+ public event DataAvailableHandler DataAvailable;
+
+ ///
+ /// Fires the event
+ ///
+ protected void OnDataAvailable()
+ {
+ if (_ztream.total_out > 0)
+ {
+ if (DataAvailable != null)
+ DataAvailable( _outBuffer, 0, (int)_ztream.total_out);
+ resetOutput();
+ }
+ }
+
+ ///
+ /// Adds more data to the codec to be processed.
+ ///
+ /// Byte array containing the data to be added to the codec
+ /// Adding data may, or may not, raise the DataAvailable event
+ public void Add(byte[] data)
+ {
+ Add(data,0,data.Length);
+ }
+
+ ///
+ /// Adds more data to the codec to be processed.
+ ///
+ /// Byte array containing the data to be added to the codec
+ /// The index of the first byte to add from data
+ /// The number of bytes to add
+ /// Adding data may, or may not, raise the DataAvailable event
+ /// This must be implemented by a derived class
+ public abstract void Add(byte[] data, int offset, int count);
+
+ ///
+ /// Finishes up any pending data that needs to be processed and handled.
+ ///
+ /// This must be implemented by a derived class
+ public abstract void Finish();
+
+ ///
+ /// Gets the checksum of the data that has been added so far
+ ///
+ public uint Checksum { get { return _checksum; } }
+
+ #endregion
+
+ #region Destructor & IDisposable stuff
+
+ ///
+ /// Destroys this instance
+ ///
+ ~CodecBase()
+ {
+ CleanUp(false);
+ }
+
+ ///
+ /// Releases any unmanaged resources and calls the method of the derived class
+ ///
+ public void Dispose()
+ {
+ CleanUp(true);
+ }
+
+ ///
+ /// Performs any codec specific cleanup
+ ///
+ /// This must be implemented by a derived class
+ protected abstract void CleanUp();
+
+ // performs the release of the handles and calls the dereived CleanUp()
+ private void CleanUp(bool isDisposing)
+ {
+ if (!_isDisposed)
+ {
+ CleanUp();
+ if (_hInput.IsAllocated)
+ _hInput.Free();
+ if (_hOutput.IsAllocated)
+ _hOutput.Free();
+
+ _isDisposed = true;
+ }
+ }
+
+
+ #endregion
+
+ #region Helper methods
+
+ ///
+ /// Copies a number of bytes to the internal codec buffer - ready for proccesing
+ ///
+ /// The byte array that contains the data to copy
+ /// The index of the first byte to copy
+ /// The number of bytes to copy from data
+ protected void copyInput(byte[] data, int startIndex, int count)
+ {
+ Array.Copy(data, startIndex, _inBuffer,0, count);
+ _ztream.next_in = _hInput.AddrOfPinnedObject();
+ _ztream.total_in = 0;
+ _ztream.avail_in = (uint)count;
+
+ }
+
+ ///
+ /// Resets the internal output buffers to a known state - ready for processing
+ ///
+ protected void resetOutput()
+ {
+ _ztream.total_out = 0;
+ _ztream.avail_out = kBufferSize;
+ _ztream.next_out = _hOutput.AddrOfPinnedObject();
+ }
+
+ ///
+ /// Updates the running checksum property
+ ///
+ /// The new checksum value
+ protected void setChecksum(uint newSum)
+ {
+ _checksum = newSum;
+ }
+ #endregion
+
+ }
+}
ADDED compat/zlib/contrib/dotzlib/DotZLib/Deflater.cs
Index: compat/zlib/contrib/dotzlib/DotZLib/Deflater.cs
==================================================================
--- compat/zlib/contrib/dotzlib/DotZLib/Deflater.cs
+++ compat/zlib/contrib/dotzlib/DotZLib/Deflater.cs
@@ -0,0 +1,106 @@
+//
+// © Copyright Henrik Ravn 2004
+//
+// Use, modification and distribution are subject to the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+using System;
+using System.Diagnostics;
+using System.Runtime.InteropServices;
+
+namespace DotZLib
+{
+
+ ///
+ /// Implements a data compressor, using the deflate algorithm in the ZLib dll
+ ///
+ public sealed class Deflater : CodecBase
+ {
+ #region Dll imports
+ [DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl, CharSet=CharSet.Ansi)]
+ private static extern int deflateInit_(ref ZStream sz, int level, string vs, int size);
+
+ [DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl)]
+ private static extern int deflate(ref ZStream sz, int flush);
+
+ [DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl)]
+ private static extern int deflateReset(ref ZStream sz);
+
+ [DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl)]
+ private static extern int deflateEnd(ref ZStream sz);
+ #endregion
+
+ ///
+ /// Constructs an new instance of the Deflater
+ ///
+ /// The compression level to use for this Deflater
+ public Deflater(CompressLevel level) : base()
+ {
+ int retval = deflateInit_(ref _ztream, (int)level, Info.Version, Marshal.SizeOf(_ztream));
+ if (retval != 0)
+ throw new ZLibException(retval, "Could not initialize deflater");
+
+ resetOutput();
+ }
+
+ ///
+ /// Adds more data to the codec to be processed.
+ ///
+ /// Byte array containing the data to be added to the codec
+ /// The index of the first byte to add from data
+ /// The number of bytes to add
+ /// Adding data may, or may not, raise the DataAvailable event
+ public override void Add(byte[] data, int offset, int count)
+ {
+ if (data == null) throw new ArgumentNullException();
+ if (offset < 0 || count < 0) throw new ArgumentOutOfRangeException();
+ if ((offset+count) > data.Length) throw new ArgumentException();
+
+ int total = count;
+ int inputIndex = offset;
+ int err = 0;
+
+ while (err >= 0 && inputIndex < total)
+ {
+ copyInput(data, inputIndex, Math.Min(total - inputIndex, kBufferSize));
+ while (err >= 0 && _ztream.avail_in > 0)
+ {
+ err = deflate(ref _ztream, (int)FlushTypes.None);
+ if (err == 0)
+ while (_ztream.avail_out == 0)
+ {
+ OnDataAvailable();
+ err = deflate(ref _ztream, (int)FlushTypes.None);
+ }
+ inputIndex += (int)_ztream.total_in;
+ }
+ }
+ setChecksum( _ztream.adler );
+ }
+
+
+ ///
+ /// Finishes up any pending data that needs to be processed and handled.
+ ///
+ public override void Finish()
+ {
+ int err;
+ do
+ {
+ err = deflate(ref _ztream, (int)FlushTypes.Finish);
+ OnDataAvailable();
+ }
+ while (err == 0);
+ setChecksum( _ztream.adler );
+ deflateReset(ref _ztream);
+ resetOutput();
+ }
+
+ ///
+ /// Closes the internal zlib deflate stream
+ ///
+ protected override void CleanUp() { deflateEnd(ref _ztream); }
+
+ }
+}
ADDED compat/zlib/contrib/dotzlib/DotZLib/DotZLib.cs
Index: compat/zlib/contrib/dotzlib/DotZLib/DotZLib.cs
==================================================================
--- compat/zlib/contrib/dotzlib/DotZLib/DotZLib.cs
+++ compat/zlib/contrib/dotzlib/DotZLib/DotZLib.cs
@@ -0,0 +1,288 @@
+//
+// © Copyright Henrik Ravn 2004
+//
+// Use, modification and distribution are subject to the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+using System;
+using System.IO;
+using System.Runtime.InteropServices;
+using System.Text;
+
+
+namespace DotZLib
+{
+
+ #region Internal types
+
+ ///
+ /// Defines constants for the various flush types used with zlib
+ ///
+ internal enum FlushTypes
+ {
+ None, Partial, Sync, Full, Finish, Block
+ }
+
+ #region ZStream structure
+ // internal mapping of the zlib zstream structure for marshalling
+ [StructLayoutAttribute(LayoutKind.Sequential, Pack=4, Size=0, CharSet=CharSet.Ansi)]
+ internal struct ZStream
+ {
+ public IntPtr next_in;
+ public uint avail_in;
+ public uint total_in;
+
+ public IntPtr next_out;
+ public uint avail_out;
+ public uint total_out;
+
+ [MarshalAs(UnmanagedType.LPStr)]
+ string msg;
+ uint state;
+
+ uint zalloc;
+ uint zfree;
+ uint opaque;
+
+ int data_type;
+ public uint adler;
+ uint reserved;
+ }
+
+ #endregion
+
+ #endregion
+
+ #region Public enums
+ ///
+ /// Defines constants for the available compression levels in zlib
+ ///
+ public enum CompressLevel : int
+ {
+ ///
+ /// The default compression level with a reasonable compromise between compression and speed
+ ///
+ Default = -1,
+ ///
+ /// No compression at all. The data are passed straight through.
+ ///
+ None = 0,
+ ///
+ /// The maximum compression rate available.
+ ///
+ Best = 9,
+ ///
+ /// The fastest available compression level.
+ ///
+ Fastest = 1
+ }
+ #endregion
+
+ #region Exception classes
+ ///
+ /// The exception that is thrown when an error occurs on the zlib dll
+ ///
+ public class ZLibException : ApplicationException
+ {
+ ///
+ /// Initializes a new instance of the class with a specified
+ /// error message and error code
+ ///
+ /// The zlib error code that caused the exception
+ /// A message that (hopefully) describes the error
+ public ZLibException(int errorCode, string msg) : base(String.Format("ZLib error {0} {1}", errorCode, msg))
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class with a specified
+ /// error code
+ ///
+ /// The zlib error code that caused the exception
+ public ZLibException(int errorCode) : base(String.Format("ZLib error {0}", errorCode))
+ {
+ }
+ }
+ #endregion
+
+ #region Interfaces
+
+ ///
+ /// Declares methods and properties that enables a running checksum to be calculated
+ ///
+ public interface ChecksumGenerator
+ {
+ ///
+ /// Gets the current value of the checksum
+ ///
+ uint Value { get; }
+
+ ///
+ /// Clears the current checksum to 0
+ ///
+ void Reset();
+
+ ///
+ /// Updates the current checksum with an array of bytes
+ ///
+ /// The data to update the checksum with
+ void Update(byte[] data);
+
+ ///
+ /// Updates the current checksum with part of an array of bytes
+ ///
+ /// The data to update the checksum with
+ /// Where in data to start updating
+ /// The number of bytes from data to use
+ /// The sum of offset and count is larger than the length of data
+ /// data is a null reference
+ /// Offset or count is negative.
+ void Update(byte[] data, int offset, int count);
+
+ ///
+ /// Updates the current checksum with the data from a string
+ ///
+ /// The string to update the checksum with
+ /// The characters in the string are converted by the UTF-8 encoding
+ void Update(string data);
+
+ ///
+ /// Updates the current checksum with the data from a string, using a specific encoding
+ ///
+ /// The string to update the checksum with
+ /// The encoding to use
+ void Update(string data, Encoding encoding);
+ }
+
+
+ ///
+ /// Represents the method that will be called from a codec when new data
+ /// are available.
+ ///
+ /// The byte array containing the processed data
+ /// The index of the first processed byte in data
+ /// The number of processed bytes available
+ /// On return from this method, the data may be overwritten, so grab it while you can.
+ /// You cannot assume that startIndex will be zero.
+ ///
+ public delegate void DataAvailableHandler(byte[] data, int startIndex, int count);
+
+ ///
+ /// Declares methods and events for implementing compressors/decompressors
+ ///
+ public interface Codec
+ {
+ ///
+ /// Occurs when more processed data are available.
+ ///
+ event DataAvailableHandler DataAvailable;
+
+ ///
+ /// Adds more data to the codec to be processed.
+ ///
+ /// Byte array containing the data to be added to the codec
+ /// Adding data may, or may not, raise the DataAvailable event
+ void Add(byte[] data);
+
+ ///
+ /// Adds more data to the codec to be processed.
+ ///
+ /// Byte array containing the data to be added to the codec
+ /// The index of the first byte to add from data
+ /// The number of bytes to add
+ /// Adding data may, or may not, raise the DataAvailable event
+ void Add(byte[] data, int offset, int count);
+
+ ///
+ /// Finishes up any pending data that needs to be processed and handled.
+ ///
+ void Finish();
+
+ ///
+ /// Gets the checksum of the data that has been added so far
+ ///
+ uint Checksum { get; }
+
+
+ }
+
+ #endregion
+
+ #region Classes
+ ///
+ /// Encapsulates general information about the ZLib library
+ ///
+ public class Info
+ {
+ #region DLL imports
+ [DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl)]
+ private static extern uint zlibCompileFlags();
+
+ [DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl)]
+ private static extern string zlibVersion();
+ #endregion
+
+ #region Private stuff
+ private uint _flags;
+
+ // helper function that unpacks a bitsize mask
+ private static int bitSize(uint bits)
+ {
+ switch (bits)
+ {
+ case 0: return 16;
+ case 1: return 32;
+ case 2: return 64;
+ }
+ return -1;
+ }
+ #endregion
+
+ ///
+ /// Constructs an instance of the Info class.
+ ///
+ public Info()
+ {
+ _flags = zlibCompileFlags();
+ }
+
+ ///
+ /// True if the library is compiled with debug info
+ ///
+ public bool HasDebugInfo { get { return 0 != (_flags & 0x100); } }
+
+ ///
+ /// True if the library is compiled with assembly optimizations
+ ///
+ public bool UsesAssemblyCode { get { return 0 != (_flags & 0x200); } }
+
+ ///
+ /// Gets the size of the unsigned int that was compiled into Zlib
+ ///
+ public int SizeOfUInt { get { return bitSize(_flags & 3); } }
+
+ ///
+ /// Gets the size of the unsigned long that was compiled into Zlib
+ ///
+ public int SizeOfULong { get { return bitSize((_flags >> 2) & 3); } }
+
+ ///
+ /// Gets the size of the pointers that were compiled into Zlib
+ ///
+ public int SizeOfPointer { get { return bitSize((_flags >> 4) & 3); } }
+
+ ///
+ /// Gets the size of the z_off_t type that was compiled into Zlib
+ ///
+ public int SizeOfOffset { get { return bitSize((_flags >> 6) & 3); } }
+
+ ///
+ /// Gets the version of ZLib as a string, e.g. "1.2.1"
+ ///
+ public static string Version { get { return zlibVersion(); } }
+ }
+
+ #endregion
+
+}
ADDED compat/zlib/contrib/dotzlib/DotZLib/DotZLib.csproj
Index: compat/zlib/contrib/dotzlib/DotZLib/DotZLib.csproj
==================================================================
--- compat/zlib/contrib/dotzlib/DotZLib/DotZLib.csproj
+++ compat/zlib/contrib/dotzlib/DotZLib/DotZLib.csproj
@@ -0,0 +1,141 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
ADDED compat/zlib/contrib/dotzlib/DotZLib/GZipStream.cs
Index: compat/zlib/contrib/dotzlib/DotZLib/GZipStream.cs
==================================================================
--- compat/zlib/contrib/dotzlib/DotZLib/GZipStream.cs
+++ compat/zlib/contrib/dotzlib/DotZLib/GZipStream.cs
@@ -0,0 +1,301 @@
+//
+// © Copyright Henrik Ravn 2004
+//
+// Use, modification and distribution are subject to the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+using System;
+using System.IO;
+using System.Runtime.InteropServices;
+
+namespace DotZLib
+{
+ ///
+ /// Implements a compressed , in GZip (.gz) format.
+ ///
+ public class GZipStream : Stream, IDisposable
+ {
+ #region Dll Imports
+ [DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl, CharSet=CharSet.Ansi)]
+ private static extern IntPtr gzopen(string name, string mode);
+
+ [DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl)]
+ private static extern int gzclose(IntPtr gzFile);
+
+ [DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl)]
+ private static extern int gzwrite(IntPtr gzFile, int data, int length);
+
+ [DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl)]
+ private static extern int gzread(IntPtr gzFile, int data, int length);
+
+ [DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl)]
+ private static extern int gzgetc(IntPtr gzFile);
+
+ [DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl)]
+ private static extern int gzputc(IntPtr gzFile, int c);
+
+ #endregion
+
+ #region Private data
+ private IntPtr _gzFile;
+ private bool _isDisposed = false;
+ private bool _isWriting;
+ #endregion
+
+ #region Constructors
+ ///
+ /// Creates a new file as a writeable GZipStream
+ ///
+ /// The name of the compressed file to create
+ /// The compression level to use when adding data
+ /// If an error occurred in the internal zlib function
+ public GZipStream(string fileName, CompressLevel level)
+ {
+ _isWriting = true;
+ _gzFile = gzopen(fileName, String.Format("wb{0}", (int)level));
+ if (_gzFile == IntPtr.Zero)
+ throw new ZLibException(-1, "Could not open " + fileName);
+ }
+
+ ///
+ /// Opens an existing file as a readable GZipStream
+ ///
+ /// The name of the file to open
+ /// If an error occurred in the internal zlib function
+ public GZipStream(string fileName)
+ {
+ _isWriting = false;
+ _gzFile = gzopen(fileName, "rb");
+ if (_gzFile == IntPtr.Zero)
+ throw new ZLibException(-1, "Could not open " + fileName);
+
+ }
+ #endregion
+
+ #region Access properties
+ ///
+ /// Returns true of this stream can be read from, false otherwise
+ ///
+ public override bool CanRead
+ {
+ get
+ {
+ return !_isWriting;
+ }
+ }
+
+
+ ///
+ /// Returns false.
+ ///
+ public override bool CanSeek
+ {
+ get
+ {
+ return false;
+ }
+ }
+
+ ///
+ /// Returns true if this tsream is writeable, false otherwise
+ ///
+ public override bool CanWrite
+ {
+ get
+ {
+ return _isWriting;
+ }
+ }
+ #endregion
+
+ #region Destructor & IDispose stuff
+
+ ///
+ /// Destroys this instance
+ ///
+ ~GZipStream()
+ {
+ cleanUp(false);
+ }
+
+ ///
+ /// Closes the external file handle
+ ///
+ public void Dispose()
+ {
+ cleanUp(true);
+ }
+
+ // Does the actual closing of the file handle.
+ private void cleanUp(bool isDisposing)
+ {
+ if (!_isDisposed)
+ {
+ gzclose(_gzFile);
+ _isDisposed = true;
+ }
+ }
+ #endregion
+
+ #region Basic reading and writing
+ ///
+ /// Attempts to read a number of bytes from the stream.
+ ///
+ /// The destination data buffer
+ /// The index of the first destination byte in buffer
+ /// The number of bytes requested
+ /// The number of bytes read
+ /// If buffer is null
+ /// If count or offset are negative
+ /// If offset + count is > buffer.Length
+ /// If this stream is not readable.
+ /// If this stream has been disposed.
+ public override int Read(byte[] buffer, int offset, int count)
+ {
+ if (!CanRead) throw new NotSupportedException();
+ if (buffer == null) throw new ArgumentNullException();
+ if (offset < 0 || count < 0) throw new ArgumentOutOfRangeException();
+ if ((offset+count) > buffer.Length) throw new ArgumentException();
+ if (_isDisposed) throw new ObjectDisposedException("GZipStream");
+
+ GCHandle h = GCHandle.Alloc(buffer, GCHandleType.Pinned);
+ int result;
+ try
+ {
+ result = gzread(_gzFile, h.AddrOfPinnedObject().ToInt32() + offset, count);
+ if (result < 0)
+ throw new IOException();
+ }
+ finally
+ {
+ h.Free();
+ }
+ return result;
+ }
+
+ ///
+ /// Attempts to read a single byte from the stream.
+ ///
+ /// The byte that was read, or -1 in case of error or End-Of-File
+ public override int ReadByte()
+ {
+ if (!CanRead) throw new NotSupportedException();
+ if (_isDisposed) throw new ObjectDisposedException("GZipStream");
+ return gzgetc(_gzFile);
+ }
+
+ ///
+ /// Writes a number of bytes to the stream
+ ///
+ ///
+ ///
+ ///
+ /// If buffer is null
+ /// If count or offset are negative
+ /// If offset + count is > buffer.Length
+ /// If this stream is not writeable.
+ /// If this stream has been disposed.
+ public override void Write(byte[] buffer, int offset, int count)
+ {
+ if (!CanWrite) throw new NotSupportedException();
+ if (buffer == null) throw new ArgumentNullException();
+ if (offset < 0 || count < 0) throw new ArgumentOutOfRangeException();
+ if ((offset+count) > buffer.Length) throw new ArgumentException();
+ if (_isDisposed) throw new ObjectDisposedException("GZipStream");
+
+ GCHandle h = GCHandle.Alloc(buffer, GCHandleType.Pinned);
+ try
+ {
+ int result = gzwrite(_gzFile, h.AddrOfPinnedObject().ToInt32() + offset, count);
+ if (result < 0)
+ throw new IOException();
+ }
+ finally
+ {
+ h.Free();
+ }
+ }
+
+ ///
+ /// Writes a single byte to the stream
+ ///
+ /// The byte to add to the stream.
+ /// If this stream is not writeable.
+ /// If this stream has been disposed.
+ public override void WriteByte(byte value)
+ {
+ if (!CanWrite) throw new NotSupportedException();
+ if (_isDisposed) throw new ObjectDisposedException("GZipStream");
+
+ int result = gzputc(_gzFile, (int)value);
+ if (result < 0)
+ throw new IOException();
+ }
+ #endregion
+
+ #region Position & length stuff
+ ///
+ /// Not supported.
+ ///
+ ///
+ /// Always thrown
+ public override void SetLength(long value)
+ {
+ throw new NotSupportedException();
+ }
+
+ ///
+ /// Not suppported.
+ ///
+ ///
+ ///
+ ///
+ /// Always thrown
+ public override long Seek(long offset, SeekOrigin origin)
+ {
+ throw new NotSupportedException();
+ }
+
+ ///
+ /// Flushes the GZipStream .
+ ///
+ /// In this implementation, this method does nothing. This is because excessive
+ /// flushing may degrade the achievable compression rates.
+ public override void Flush()
+ {
+ // left empty on purpose
+ }
+
+ ///
+ /// Gets/sets the current position in the GZipStream . Not suppported.
+ ///
+ /// In this implementation this property is not supported
+ /// Always thrown
+ public override long Position
+ {
+ get
+ {
+ throw new NotSupportedException();
+ }
+ set
+ {
+ throw new NotSupportedException();
+ }
+ }
+
+ ///
+ /// Gets the size of the stream. Not suppported.
+ ///
+ /// In this implementation this property is not supported
+ /// Always thrown
+ public override long Length
+ {
+ get
+ {
+ throw new NotSupportedException();
+ }
+ }
+ #endregion
+ }
+}
ADDED compat/zlib/contrib/dotzlib/DotZLib/Inflater.cs
Index: compat/zlib/contrib/dotzlib/DotZLib/Inflater.cs
==================================================================
--- compat/zlib/contrib/dotzlib/DotZLib/Inflater.cs
+++ compat/zlib/contrib/dotzlib/DotZLib/Inflater.cs
@@ -0,0 +1,105 @@
+//
+// © Copyright Henrik Ravn 2004
+//
+// Use, modification and distribution are subject to the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+using System;
+using System.Diagnostics;
+using System.Runtime.InteropServices;
+
+namespace DotZLib
+{
+
+ ///
+ /// Implements a data decompressor, using the inflate algorithm in the ZLib dll
+ ///
+ public class Inflater : CodecBase
+ {
+ #region Dll imports
+ [DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl, CharSet=CharSet.Ansi)]
+ private static extern int inflateInit_(ref ZStream sz, string vs, int size);
+
+ [DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl)]
+ private static extern int inflate(ref ZStream sz, int flush);
+
+ [DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl)]
+ private static extern int inflateReset(ref ZStream sz);
+
+ [DllImport("ZLIB1.dll", CallingConvention=CallingConvention.Cdecl)]
+ private static extern int inflateEnd(ref ZStream sz);
+ #endregion
+
+ ///
+ /// Constructs an new instance of the Inflater
+ ///
+ public Inflater() : base()
+ {
+ int retval = inflateInit_(ref _ztream, Info.Version, Marshal.SizeOf(_ztream));
+ if (retval != 0)
+ throw new ZLibException(retval, "Could not initialize inflater");
+
+ resetOutput();
+ }
+
+
+ ///
+ /// Adds more data to the codec to be processed.
+ ///
+ /// Byte array containing the data to be added to the codec
+ /// The index of the first byte to add from data
+ /// The number of bytes to add
+ /// Adding data may, or may not, raise the DataAvailable event
+ public override void Add(byte[] data, int offset, int count)
+ {
+ if (data == null) throw new ArgumentNullException();
+ if (offset < 0 || count < 0) throw new ArgumentOutOfRangeException();
+ if ((offset+count) > data.Length) throw new ArgumentException();
+
+ int total = count;
+ int inputIndex = offset;
+ int err = 0;
+
+ while (err >= 0 && inputIndex < total)
+ {
+ copyInput(data, inputIndex, Math.Min(total - inputIndex, kBufferSize));
+ err = inflate(ref _ztream, (int)FlushTypes.None);
+ if (err == 0)
+ while (_ztream.avail_out == 0)
+ {
+ OnDataAvailable();
+ err = inflate(ref _ztream, (int)FlushTypes.None);
+ }
+
+ inputIndex += (int)_ztream.total_in;
+ }
+ setChecksum( _ztream.adler );
+ }
+
+
+ ///
+ /// Finishes up any pending data that needs to be processed and handled.
+ ///
+ public override void Finish()
+ {
+ int err;
+ do
+ {
+ err = inflate(ref _ztream, (int)FlushTypes.Finish);
+ OnDataAvailable();
+ }
+ while (err == 0);
+ setChecksum( _ztream.adler );
+ inflateReset(ref _ztream);
+ resetOutput();
+ }
+
+ ///
+ /// Closes the internal zlib inflate stream
+ ///
+ protected override void CleanUp() { inflateEnd(ref _ztream); }
+
+
+ }
+}
ADDED compat/zlib/contrib/dotzlib/DotZLib/UnitTests.cs
Index: compat/zlib/contrib/dotzlib/DotZLib/UnitTests.cs
==================================================================
--- compat/zlib/contrib/dotzlib/DotZLib/UnitTests.cs
+++ compat/zlib/contrib/dotzlib/DotZLib/UnitTests.cs
@@ -0,0 +1,274 @@
+//
+// © Copyright Henrik Ravn 2004
+//
+// Use, modification and distribution are subject to the Boost Software License, Version 1.0.
+// (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+//
+
+using System;
+using System.Collections;
+using System.IO;
+
+// uncomment the define below to include unit tests
+//#define nunit
+#if nunit
+using NUnit.Framework;
+
+// Unit tests for the DotZLib class library
+// ----------------------------------------
+//
+// Use this with NUnit 2 from http://www.nunit.org
+//
+
+namespace DotZLibTests
+{
+ using DotZLib;
+
+ // helper methods
+ internal class Utils
+ {
+ public static bool byteArrEqual( byte[] lhs, byte[] rhs )
+ {
+ if (lhs.Length != rhs.Length)
+ return false;
+ for (int i = lhs.Length-1; i >= 0; --i)
+ if (lhs[i] != rhs[i])
+ return false;
+ return true;
+ }
+
+ }
+
+
+ [TestFixture]
+ public class CircBufferTests
+ {
+ #region Circular buffer tests
+ [Test]
+ public void SinglePutGet()
+ {
+ CircularBuffer buf = new CircularBuffer(10);
+ Assert.AreEqual( 0, buf.Size );
+ Assert.AreEqual( -1, buf.Get() );
+
+ Assert.IsTrue(buf.Put( 1 ));
+ Assert.AreEqual( 1, buf.Size );
+ Assert.AreEqual( 1, buf.Get() );
+ Assert.AreEqual( 0, buf.Size );
+ Assert.AreEqual( -1, buf.Get() );
+ }
+
+ [Test]
+ public void BlockPutGet()
+ {
+ CircularBuffer buf = new CircularBuffer(10);
+ byte[] arr = {1,2,3,4,5,6,7,8,9,10};
+ Assert.AreEqual( 10, buf.Put(arr,0,10) );
+ Assert.AreEqual( 10, buf.Size );
+ Assert.IsFalse( buf.Put(11) );
+ Assert.AreEqual( 1, buf.Get() );
+ Assert.IsTrue( buf.Put(11) );
+
+ byte[] arr2 = (byte[])arr.Clone();
+ Assert.AreEqual( 9, buf.Get(arr2,1,9) );
+ Assert.IsTrue( Utils.byteArrEqual(arr,arr2) );
+ }
+
+ #endregion
+ }
+
+ [TestFixture]
+ public class ChecksumTests
+ {
+ #region CRC32 Tests
+ [Test]
+ public void CRC32_Null()
+ {
+ CRC32Checksum crc32 = new CRC32Checksum();
+ Assert.AreEqual( 0, crc32.Value );
+
+ crc32 = new CRC32Checksum(1);
+ Assert.AreEqual( 1, crc32.Value );
+
+ crc32 = new CRC32Checksum(556);
+ Assert.AreEqual( 556, crc32.Value );
+ }
+
+ [Test]
+ public void CRC32_Data()
+ {
+ CRC32Checksum crc32 = new CRC32Checksum();
+ byte[] data = { 1,2,3,4,5,6,7 };
+ crc32.Update(data);
+ Assert.AreEqual( 0x70e46888, crc32.Value );
+
+ crc32 = new CRC32Checksum();
+ crc32.Update("penguin");
+ Assert.AreEqual( 0x0e5c1a120, crc32.Value );
+
+ crc32 = new CRC32Checksum(1);
+ crc32.Update("penguin");
+ Assert.AreEqual(0x43b6aa94, crc32.Value);
+
+ }
+ #endregion
+
+ #region Adler tests
+
+ [Test]
+ public void Adler_Null()
+ {
+ AdlerChecksum adler = new AdlerChecksum();
+ Assert.AreEqual(0, adler.Value);
+
+ adler = new AdlerChecksum(1);
+ Assert.AreEqual( 1, adler.Value );
+
+ adler = new AdlerChecksum(556);
+ Assert.AreEqual( 556, adler.Value );
+ }
+
+ [Test]
+ public void Adler_Data()
+ {
+ AdlerChecksum adler = new AdlerChecksum(1);
+ byte[] data = { 1,2,3,4,5,6,7 };
+ adler.Update(data);
+ Assert.AreEqual( 0x5b001d, adler.Value );
+
+ adler = new AdlerChecksum();
+ adler.Update("penguin");
+ Assert.AreEqual(0x0bcf02f6, adler.Value );
+
+ adler = new AdlerChecksum(1);
+ adler.Update("penguin");
+ Assert.AreEqual(0x0bd602f7, adler.Value);
+
+ }
+ #endregion
+ }
+
+ [TestFixture]
+ public class InfoTests
+ {
+ #region Info tests
+ [Test]
+ public void Info_Version()
+ {
+ Info info = new Info();
+ Assert.AreEqual("1.2.8", Info.Version);
+ Assert.AreEqual(32, info.SizeOfUInt);
+ Assert.AreEqual(32, info.SizeOfULong);
+ Assert.AreEqual(32, info.SizeOfPointer);
+ Assert.AreEqual(32, info.SizeOfOffset);
+ }
+ #endregion
+ }
+
+ [TestFixture]
+ public class DeflateInflateTests
+ {
+ #region Deflate tests
+ [Test]
+ public void Deflate_Init()
+ {
+ using (Deflater def = new Deflater(CompressLevel.Default))
+ {
+ }
+ }
+
+ private ArrayList compressedData = new ArrayList();
+ private uint adler1;
+
+ private ArrayList uncompressedData = new ArrayList();
+ private uint adler2;
+
+ public void CDataAvail(byte[] data, int startIndex, int count)
+ {
+ for (int i = 0; i < count; ++i)
+ compressedData.Add(data[i+startIndex]);
+ }
+
+ [Test]
+ public void Deflate_Compress()
+ {
+ compressedData.Clear();
+
+ byte[] testData = new byte[35000];
+ for (int i = 0; i < testData.Length; ++i)
+ testData[i] = 5;
+
+ using (Deflater def = new Deflater((CompressLevel)5))
+ {
+ def.DataAvailable += new DataAvailableHandler(CDataAvail);
+ def.Add(testData);
+ def.Finish();
+ adler1 = def.Checksum;
+ }
+ }
+ #endregion
+
+ #region Inflate tests
+ [Test]
+ public void Inflate_Init()
+ {
+ using (Inflater inf = new Inflater())
+ {
+ }
+ }
+
+ private void DDataAvail(byte[] data, int startIndex, int count)
+ {
+ for (int i = 0; i < count; ++i)
+ uncompressedData.Add(data[i+startIndex]);
+ }
+
+ [Test]
+ public void Inflate_Expand()
+ {
+ uncompressedData.Clear();
+
+ using (Inflater inf = new Inflater())
+ {
+ inf.DataAvailable += new DataAvailableHandler(DDataAvail);
+ inf.Add((byte[])compressedData.ToArray(typeof(byte)));
+ inf.Finish();
+ adler2 = inf.Checksum;
+ }
+ Assert.AreEqual( adler1, adler2 );
+ }
+ #endregion
+ }
+
+ [TestFixture]
+ public class GZipStreamTests
+ {
+ #region GZipStream test
+ [Test]
+ public void GZipStream_WriteRead()
+ {
+ using (GZipStream gzOut = new GZipStream("gzstream.gz", CompressLevel.Best))
+ {
+ BinaryWriter writer = new BinaryWriter(gzOut);
+ writer.Write("hi there");
+ writer.Write(Math.PI);
+ writer.Write(42);
+ }
+
+ using (GZipStream gzIn = new GZipStream("gzstream.gz"))
+ {
+ BinaryReader reader = new BinaryReader(gzIn);
+ string s = reader.ReadString();
+ Assert.AreEqual("hi there",s);
+ double d = reader.ReadDouble();
+ Assert.AreEqual(Math.PI, d);
+ int i = reader.ReadInt32();
+ Assert.AreEqual(42,i);
+ }
+
+ }
+ #endregion
+ }
+}
+
+#endif
ADDED compat/zlib/contrib/dotzlib/LICENSE_1_0.txt
Index: compat/zlib/contrib/dotzlib/LICENSE_1_0.txt
==================================================================
--- compat/zlib/contrib/dotzlib/LICENSE_1_0.txt
+++ compat/zlib/contrib/dotzlib/LICENSE_1_0.txt
@@ -0,0 +1,23 @@
+Boost Software License - Version 1.0 - August 17th, 2003
+
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
ADDED compat/zlib/contrib/dotzlib/readme.txt
Index: compat/zlib/contrib/dotzlib/readme.txt
==================================================================
--- compat/zlib/contrib/dotzlib/readme.txt
+++ compat/zlib/contrib/dotzlib/readme.txt
@@ -0,0 +1,58 @@
+This directory contains a .Net wrapper class library for the ZLib1.dll
+
+The wrapper includes support for inflating/deflating memory buffers,
+.Net streaming wrappers for the gz streams part of zlib, and wrappers
+for the checksum parts of zlib. See DotZLib/UnitTests.cs for examples.
+
+Directory structure:
+--------------------
+
+LICENSE_1_0.txt - License file.
+readme.txt - This file.
+DotZLib.chm - Class library documentation
+DotZLib.build - NAnt build file
+DotZLib.sln - Microsoft Visual Studio 2003 solution file
+
+DotZLib\*.cs - Source files for the class library
+
+Unit tests:
+-----------
+The file DotZLib/UnitTests.cs contains unit tests for use with NUnit 2.1 or higher.
+To include unit tests in the build, define nunit before building.
+
+
+Build instructions:
+-------------------
+
+1. Using Visual Studio.Net 2003:
+ Open DotZLib.sln in VS.Net and build from there. Output file (DotZLib.dll)
+ will be found ./DotZLib/bin/release or ./DotZLib/bin/debug, depending on
+ you are building the release or debug version of the library. Check
+ DotZLib/UnitTests.cs for instructions on how to include unit tests in the
+ build.
+
+2. Using NAnt:
+ Open a command prompt with access to the build environment and run nant
+ in the same directory as the DotZLib.build file.
+ You can define 2 properties on the nant command-line to control the build:
+ debug={true|false} to toggle between release/debug builds (default=true).
+ nunit={true|false} to include or esclude unit tests (default=true).
+ Also the target clean will remove binaries.
+ Output file (DotZLib.dll) will be found in either ./DotZLib/bin/release
+ or ./DotZLib/bin/debug, depending on whether you are building the release
+ or debug version of the library.
+
+ Examples:
+ nant -D:debug=false -D:nunit=false
+ will build a release mode version of the library without unit tests.
+ nant
+ will build a debug version of the library with unit tests
+ nant clean
+ will remove all previously built files.
+
+
+---------------------------------
+Copyright (c) Henrik Ravn 2004
+
+Use, modification and distribution are subject to the Boost Software License, Version 1.0.
+(See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
ADDED compat/zlib/contrib/gcc_gvmat64/gvmat64.S
Index: compat/zlib/contrib/gcc_gvmat64/gvmat64.S
==================================================================
--- compat/zlib/contrib/gcc_gvmat64/gvmat64.S
+++ compat/zlib/contrib/gcc_gvmat64/gvmat64.S
@@ -0,0 +1,574 @@
+/*
+;uInt longest_match_x64(
+; deflate_state *s,
+; IPos cur_match); // current match
+
+; gvmat64.S -- Asm portion of the optimized longest_match for 32 bits x86_64
+; (AMD64 on Athlon 64, Opteron, Phenom
+; and Intel EM64T on Pentium 4 with EM64T, Pentium D, Core 2 Duo, Core I5/I7)
+; this file is translation from gvmat64.asm to GCC 4.x (for Linux, Mac XCode)
+; Copyright (C) 1995-2010 Jean-loup Gailly, Brian Raiter and Gilles Vollant.
+;
+; File written by Gilles Vollant, by converting to assembly the longest_match
+; from Jean-loup Gailly in deflate.c of zLib and infoZip zip.
+; and by taking inspiration on asm686 with masm, optimised assembly code
+; from Brian Raiter, written 1998
+;
+; This software is provided 'as-is', without any express or implied
+; warranty. In no event will the authors be held liable for any damages
+; arising from the use of this software.
+;
+; Permission is granted to anyone to use this software for any purpose,
+; including commercial applications, and to alter it and redistribute it
+; freely, subject to the following restrictions:
+;
+; 1. The origin of this software must not be misrepresented; you must not
+; claim that you wrote the original software. If you use this software
+; in a product, an acknowledgment in the product documentation would be
+; appreciated but is not required.
+; 2. Altered source versions must be plainly marked as such, and must not be
+; misrepresented as being the original software
+; 3. This notice may not be removed or altered from any source distribution.
+;
+; http://www.zlib.net
+; http://www.winimage.com/zLibDll
+; http://www.muppetlabs.com/~breadbox/software/assembly.html
+;
+; to compile this file for zLib, I use option:
+; gcc -c -arch x86_64 gvmat64.S
+
+
+;uInt longest_match(s, cur_match)
+; deflate_state *s;
+; IPos cur_match; // current match /
+;
+; with XCode for Mac, I had strange error with some jump on intel syntax
+; this is why BEFORE_JMP and AFTER_JMP are used
+ */
+
+
+#define BEFORE_JMP .att_syntax
+#define AFTER_JMP .intel_syntax noprefix
+
+#ifndef NO_UNDERLINE
+# define match_init _match_init
+# define longest_match _longest_match
+#endif
+
+.intel_syntax noprefix
+
+.globl match_init, longest_match
+.text
+longest_match:
+
+
+
+#define LocalVarsSize 96
+/*
+; register used : rax,rbx,rcx,rdx,rsi,rdi,r8,r9,r10,r11,r12
+; free register : r14,r15
+; register can be saved : rsp
+*/
+
+#define chainlenwmask (rsp + 8 - LocalVarsSize)
+#define nicematch (rsp + 16 - LocalVarsSize)
+
+#define save_rdi (rsp + 24 - LocalVarsSize)
+#define save_rsi (rsp + 32 - LocalVarsSize)
+#define save_rbx (rsp + 40 - LocalVarsSize)
+#define save_rbp (rsp + 48 - LocalVarsSize)
+#define save_r12 (rsp + 56 - LocalVarsSize)
+#define save_r13 (rsp + 64 - LocalVarsSize)
+#define save_r14 (rsp + 72 - LocalVarsSize)
+#define save_r15 (rsp + 80 - LocalVarsSize)
+
+
+/*
+; all the +4 offsets are due to the addition of pending_buf_size (in zlib
+; in the deflate_state structure since the asm code was first written
+; (if you compile with zlib 1.0.4 or older, remove the +4).
+; Note : these value are good with a 8 bytes boundary pack structure
+*/
+
+#define MAX_MATCH 258
+#define MIN_MATCH 3
+#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1)
+
+/*
+;;; Offsets for fields in the deflate_state structure. These numbers
+;;; are calculated from the definition of deflate_state, with the
+;;; assumption that the compiler will dword-align the fields. (Thus,
+;;; changing the definition of deflate_state could easily cause this
+;;; program to crash horribly, without so much as a warning at
+;;; compile time. Sigh.)
+
+; all the +zlib1222add offsets are due to the addition of fields
+; in zlib in the deflate_state structure since the asm code was first written
+; (if you compile with zlib 1.0.4 or older, use "zlib1222add equ (-4)").
+; (if you compile with zlib between 1.0.5 and 1.2.2.1, use "zlib1222add equ 0").
+; if you compile with zlib 1.2.2.2 or later , use "zlib1222add equ 8").
+*/
+
+
+
+/* you can check the structure offset by running
+
+#include
+#include
+#include "deflate.h"
+
+void print_depl()
+{
+deflate_state ds;
+deflate_state *s=&ds;
+printf("size pointer=%u\n",(int)sizeof(void*));
+
+printf("#define dsWSize %u\n",(int)(((char*)&(s->w_size))-((char*)s)));
+printf("#define dsWMask %u\n",(int)(((char*)&(s->w_mask))-((char*)s)));
+printf("#define dsWindow %u\n",(int)(((char*)&(s->window))-((char*)s)));
+printf("#define dsPrev %u\n",(int)(((char*)&(s->prev))-((char*)s)));
+printf("#define dsMatchLen %u\n",(int)(((char*)&(s->match_length))-((char*)s)));
+printf("#define dsPrevMatch %u\n",(int)(((char*)&(s->prev_match))-((char*)s)));
+printf("#define dsStrStart %u\n",(int)(((char*)&(s->strstart))-((char*)s)));
+printf("#define dsMatchStart %u\n",(int)(((char*)&(s->match_start))-((char*)s)));
+printf("#define dsLookahead %u\n",(int)(((char*)&(s->lookahead))-((char*)s)));
+printf("#define dsPrevLen %u\n",(int)(((char*)&(s->prev_length))-((char*)s)));
+printf("#define dsMaxChainLen %u\n",(int)(((char*)&(s->max_chain_length))-((char*)s)));
+printf("#define dsGoodMatch %u\n",(int)(((char*)&(s->good_match))-((char*)s)));
+printf("#define dsNiceMatch %u\n",(int)(((char*)&(s->nice_match))-((char*)s)));
+}
+*/
+
+#define dsWSize 68
+#define dsWMask 76
+#define dsWindow 80
+#define dsPrev 96
+#define dsMatchLen 144
+#define dsPrevMatch 148
+#define dsStrStart 156
+#define dsMatchStart 160
+#define dsLookahead 164
+#define dsPrevLen 168
+#define dsMaxChainLen 172
+#define dsGoodMatch 188
+#define dsNiceMatch 192
+
+#define window_size [ rcx + dsWSize]
+#define WMask [ rcx + dsWMask]
+#define window_ad [ rcx + dsWindow]
+#define prev_ad [ rcx + dsPrev]
+#define strstart [ rcx + dsStrStart]
+#define match_start [ rcx + dsMatchStart]
+#define Lookahead [ rcx + dsLookahead] //; 0ffffffffh on infozip
+#define prev_length [ rcx + dsPrevLen]
+#define max_chain_length [ rcx + dsMaxChainLen]
+#define good_match [ rcx + dsGoodMatch]
+#define nice_match [ rcx + dsNiceMatch]
+
+/*
+; windows:
+; parameter 1 in rcx(deflate state s), param 2 in rdx (cur match)
+
+; see http://weblogs.asp.net/oldnewthing/archive/2004/01/14/58579.aspx and
+; http://msdn.microsoft.com/library/en-us/kmarch/hh/kmarch/64bitAMD_8e951dd2-ee77-4728-8702-55ce4b5dd24a.xml.asp
+;
+; All registers must be preserved across the call, except for
+; rax, rcx, rdx, r8, r9, r10, and r11, which are scratch.
+
+;
+; gcc on macosx-linux:
+; see http://www.x86-64.org/documentation/abi-0.99.pdf
+; param 1 in rdi, param 2 in rsi
+; rbx, rsp, rbp, r12 to r15 must be preserved
+
+;;; Save registers that the compiler may be using, and adjust esp to
+;;; make room for our stack frame.
+
+
+;;; Retrieve the function arguments. r8d will hold cur_match
+;;; throughout the entire function. edx will hold the pointer to the
+;;; deflate_state structure during the function's setup (before
+;;; entering the main loop.
+
+; ms: parameter 1 in rcx (deflate_state* s), param 2 in edx -> r8 (cur match)
+; mac: param 1 in rdi, param 2 rsi
+; this clear high 32 bits of r8, which can be garbage in both r8 and rdx
+*/
+ mov [save_rbx],rbx
+ mov [save_rbp],rbp
+
+
+ mov rcx,rdi
+
+ mov r8d,esi
+
+
+ mov [save_r12],r12
+ mov [save_r13],r13
+ mov [save_r14],r14
+ mov [save_r15],r15
+
+
+//;;; uInt wmask = s->w_mask;
+//;;; unsigned chain_length = s->max_chain_length;
+//;;; if (s->prev_length >= s->good_match) {
+//;;; chain_length >>= 2;
+//;;; }
+
+
+ mov edi, prev_length
+ mov esi, good_match
+ mov eax, WMask
+ mov ebx, max_chain_length
+ cmp edi, esi
+ jl LastMatchGood
+ shr ebx, 2
+LastMatchGood:
+
+//;;; chainlen is decremented once beforehand so that the function can
+//;;; use the sign flag instead of the zero flag for the exit test.
+//;;; It is then shifted into the high word, to make room for the wmask
+//;;; value, which it will always accompany.
+
+ dec ebx
+ shl ebx, 16
+ or ebx, eax
+
+//;;; on zlib only
+//;;; if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead;
+
+
+
+ mov eax, nice_match
+ mov [chainlenwmask], ebx
+ mov r10d, Lookahead
+ cmp r10d, eax
+ cmovnl r10d, eax
+ mov [nicematch],r10d
+
+
+
+//;;; register Bytef *scan = s->window + s->strstart;
+ mov r10, window_ad
+ mov ebp, strstart
+ lea r13, [r10 + rbp]
+
+//;;; Determine how many bytes the scan ptr is off from being
+//;;; dword-aligned.
+
+ mov r9,r13
+ neg r13
+ and r13,3
+
+//;;; IPos limit = s->strstart > (IPos)MAX_DIST(s) ?
+//;;; s->strstart - (IPos)MAX_DIST(s) : NIL;
+
+
+ mov eax, window_size
+ sub eax, MIN_LOOKAHEAD
+
+
+ xor edi,edi
+ sub ebp, eax
+
+ mov r11d, prev_length
+
+ cmovng ebp,edi
+
+//;;; int best_len = s->prev_length;
+
+
+//;;; Store the sum of s->window + best_len in esi locally, and in esi.
+
+ lea rsi,[r10+r11]
+
+//;;; register ush scan_start = *(ushf*)scan;
+//;;; register ush scan_end = *(ushf*)(scan+best_len-1);
+//;;; Posf *prev = s->prev;
+
+ movzx r12d,word ptr [r9]
+ movzx ebx, word ptr [r9 + r11 - 1]
+
+ mov rdi, prev_ad
+
+//;;; Jump into the main loop.
+
+ mov edx, [chainlenwmask]
+
+ cmp bx,word ptr [rsi + r8 - 1]
+ jz LookupLoopIsZero
+
+
+
+LookupLoop1:
+ and r8d, edx
+
+ movzx r8d, word ptr [rdi + r8*2]
+ cmp r8d, ebp
+ jbe LeaveNow
+
+
+
+ sub edx, 0x00010000
+ BEFORE_JMP
+ js LeaveNow
+ AFTER_JMP
+
+LoopEntry1:
+ cmp bx,word ptr [rsi + r8 - 1]
+ BEFORE_JMP
+ jz LookupLoopIsZero
+ AFTER_JMP
+
+LookupLoop2:
+ and r8d, edx
+
+ movzx r8d, word ptr [rdi + r8*2]
+ cmp r8d, ebp
+ BEFORE_JMP
+ jbe LeaveNow
+ AFTER_JMP
+ sub edx, 0x00010000
+ BEFORE_JMP
+ js LeaveNow
+ AFTER_JMP
+
+LoopEntry2:
+ cmp bx,word ptr [rsi + r8 - 1]
+ BEFORE_JMP
+ jz LookupLoopIsZero
+ AFTER_JMP
+
+LookupLoop4:
+ and r8d, edx
+
+ movzx r8d, word ptr [rdi + r8*2]
+ cmp r8d, ebp
+ BEFORE_JMP
+ jbe LeaveNow
+ AFTER_JMP
+ sub edx, 0x00010000
+ BEFORE_JMP
+ js LeaveNow
+ AFTER_JMP
+
+LoopEntry4:
+
+ cmp bx,word ptr [rsi + r8 - 1]
+ BEFORE_JMP
+ jnz LookupLoop1
+ jmp LookupLoopIsZero
+ AFTER_JMP
+/*
+;;; do {
+;;; match = s->window + cur_match;
+;;; if (*(ushf*)(match+best_len-1) != scan_end ||
+;;; *(ushf*)match != scan_start) continue;
+;;; [...]
+;;; } while ((cur_match = prev[cur_match & wmask]) > limit
+;;; && --chain_length != 0);
+;;;
+;;; Here is the inner loop of the function. The function will spend the
+;;; majority of its time in this loop, and majority of that time will
+;;; be spent in the first ten instructions.
+;;;
+;;; Within this loop:
+;;; ebx = scanend
+;;; r8d = curmatch
+;;; edx = chainlenwmask - i.e., ((chainlen << 16) | wmask)
+;;; esi = windowbestlen - i.e., (window + bestlen)
+;;; edi = prev
+;;; ebp = limit
+*/
+.balign 16
+LookupLoop:
+ and r8d, edx
+
+ movzx r8d, word ptr [rdi + r8*2]
+ cmp r8d, ebp
+ BEFORE_JMP
+ jbe LeaveNow
+ AFTER_JMP
+ sub edx, 0x00010000
+ BEFORE_JMP
+ js LeaveNow
+ AFTER_JMP
+
+LoopEntry:
+
+ cmp bx,word ptr [rsi + r8 - 1]
+ BEFORE_JMP
+ jnz LookupLoop1
+ AFTER_JMP
+LookupLoopIsZero:
+ cmp r12w, word ptr [r10 + r8]
+ BEFORE_JMP
+ jnz LookupLoop1
+ AFTER_JMP
+
+
+//;;; Store the current value of chainlen.
+ mov [chainlenwmask], edx
+/*
+;;; Point edi to the string under scrutiny, and esi to the string we
+;;; are hoping to match it up with. In actuality, esi and edi are
+;;; both pointed (MAX_MATCH_8 - scanalign) bytes ahead, and edx is
+;;; initialized to -(MAX_MATCH_8 - scanalign).
+*/
+ lea rsi,[r8+r10]
+ mov rdx, 0xfffffffffffffef8 //; -(MAX_MATCH_8)
+ lea rsi, [rsi + r13 + 0x0108] //;MAX_MATCH_8]
+ lea rdi, [r9 + r13 + 0x0108] //;MAX_MATCH_8]
+
+ prefetcht1 [rsi+rdx]
+ prefetcht1 [rdi+rdx]
+
+/*
+;;; Test the strings for equality, 8 bytes at a time. At the end,
+;;; adjust rdx so that it is offset to the exact byte that mismatched.
+;;;
+;;; We already know at this point that the first three bytes of the
+;;; strings match each other, and they can be safely passed over before
+;;; starting the compare loop. So what this code does is skip over 0-3
+;;; bytes, as much as necessary in order to dword-align the edi
+;;; pointer. (rsi will still be misaligned three times out of four.)
+;;;
+;;; It should be confessed that this loop usually does not represent
+;;; much of the total running time. Replacing it with a more
+;;; straightforward "rep cmpsb" would not drastically degrade
+;;; performance.
+*/
+
+LoopCmps:
+ mov rax, [rsi + rdx]
+ xor rax, [rdi + rdx]
+ jnz LeaveLoopCmps
+
+ mov rax, [rsi + rdx + 8]
+ xor rax, [rdi + rdx + 8]
+ jnz LeaveLoopCmps8
+
+
+ mov rax, [rsi + rdx + 8+8]
+ xor rax, [rdi + rdx + 8+8]
+ jnz LeaveLoopCmps16
+
+ add rdx,8+8+8
+
+ BEFORE_JMP
+ jnz LoopCmps
+ jmp LenMaximum
+ AFTER_JMP
+
+LeaveLoopCmps16: add rdx,8
+LeaveLoopCmps8: add rdx,8
+LeaveLoopCmps:
+
+ test eax, 0x0000FFFF
+ jnz LenLower
+
+ test eax,0xffffffff
+
+ jnz LenLower32
+
+ add rdx,4
+ shr rax,32
+ or ax,ax
+ BEFORE_JMP
+ jnz LenLower
+ AFTER_JMP
+
+LenLower32:
+ shr eax,16
+ add rdx,2
+
+LenLower:
+ sub al, 1
+ adc rdx, 0
+//;;; Calculate the length of the match. If it is longer than MAX_MATCH,
+//;;; then automatically accept it as the best possible match and leave.
+
+ lea rax, [rdi + rdx]
+ sub rax, r9
+ cmp eax, MAX_MATCH
+ BEFORE_JMP
+ jge LenMaximum
+ AFTER_JMP
+/*
+;;; If the length of the match is not longer than the best match we
+;;; have so far, then forget it and return to the lookup loop.
+;///////////////////////////////////
+*/
+ cmp eax, r11d
+ jg LongerMatch
+
+ lea rsi,[r10+r11]
+
+ mov rdi, prev_ad
+ mov edx, [chainlenwmask]
+ BEFORE_JMP
+ jmp LookupLoop
+ AFTER_JMP
+/*
+;;; s->match_start = cur_match;
+;;; best_len = len;
+;;; if (len >= nice_match) break;
+;;; scan_end = *(ushf*)(scan+best_len-1);
+*/
+LongerMatch:
+ mov r11d, eax
+ mov match_start, r8d
+ cmp eax, [nicematch]
+ BEFORE_JMP
+ jge LeaveNow
+ AFTER_JMP
+
+ lea rsi,[r10+rax]
+
+ movzx ebx, word ptr [r9 + rax - 1]
+ mov rdi, prev_ad
+ mov edx, [chainlenwmask]
+ BEFORE_JMP
+ jmp LookupLoop
+ AFTER_JMP
+
+//;;; Accept the current string, with the maximum possible length.
+
+LenMaximum:
+ mov r11d,MAX_MATCH
+ mov match_start, r8d
+
+//;;; if ((uInt)best_len <= s->lookahead) return (uInt)best_len;
+//;;; return s->lookahead;
+
+LeaveNow:
+ mov eax, Lookahead
+ cmp r11d, eax
+ cmovng eax, r11d
+
+
+
+//;;; Restore the stack and return from whence we came.
+
+
+// mov rsi,[save_rsi]
+// mov rdi,[save_rdi]
+ mov rbx,[save_rbx]
+ mov rbp,[save_rbp]
+ mov r12,[save_r12]
+ mov r13,[save_r13]
+ mov r14,[save_r14]
+ mov r15,[save_r15]
+
+
+ ret 0
+//; please don't remove this string !
+//; Your can freely use gvmat64 in any free or commercial app
+//; but it is far better don't remove the string in the binary!
+ // db 0dh,0ah,"asm686 with masm, optimised assembly code from Brian Raiter, written 1998, converted to amd 64 by Gilles Vollant 2005",0dh,0ah,0
+
+
+match_init:
+ ret 0
+
+
ADDED compat/zlib/contrib/infback9/README
Index: compat/zlib/contrib/infback9/README
==================================================================
--- compat/zlib/contrib/infback9/README
+++ compat/zlib/contrib/infback9/README
@@ -0,0 +1,1 @@
+See infback9.h for what this is and how to use it.
ADDED compat/zlib/contrib/infback9/infback9.c
Index: compat/zlib/contrib/infback9/infback9.c
==================================================================
--- compat/zlib/contrib/infback9/infback9.c
+++ compat/zlib/contrib/infback9/infback9.c
@@ -0,0 +1,615 @@
+/* infback9.c -- inflate deflate64 data using a call-back interface
+ * Copyright (C) 1995-2008 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#include "zutil.h"
+#include "infback9.h"
+#include "inftree9.h"
+#include "inflate9.h"
+
+#define WSIZE 65536UL
+
+/*
+ strm provides memory allocation functions in zalloc and zfree, or
+ Z_NULL to use the library memory allocation functions.
+
+ window is a user-supplied window and output buffer that is 64K bytes.
+ */
+int ZEXPORT inflateBack9Init_(strm, window, version, stream_size)
+z_stream FAR *strm;
+unsigned char FAR *window;
+const char *version;
+int stream_size;
+{
+ struct inflate_state FAR *state;
+
+ if (version == Z_NULL || version[0] != ZLIB_VERSION[0] ||
+ stream_size != (int)(sizeof(z_stream)))
+ return Z_VERSION_ERROR;
+ if (strm == Z_NULL || window == Z_NULL)
+ return Z_STREAM_ERROR;
+ strm->msg = Z_NULL; /* in case we return an error */
+ if (strm->zalloc == (alloc_func)0) {
+ strm->zalloc = zcalloc;
+ strm->opaque = (voidpf)0;
+ }
+ if (strm->zfree == (free_func)0) strm->zfree = zcfree;
+ state = (struct inflate_state FAR *)ZALLOC(strm, 1,
+ sizeof(struct inflate_state));
+ if (state == Z_NULL) return Z_MEM_ERROR;
+ Tracev((stderr, "inflate: allocated\n"));
+ strm->state = (voidpf)state;
+ state->window = window;
+ return Z_OK;
+}
+
+/*
+ Build and output length and distance decoding tables for fixed code
+ decoding.
+ */
+#ifdef MAKEFIXED
+#include
+
+void makefixed9(void)
+{
+ unsigned sym, bits, low, size;
+ code *next, *lenfix, *distfix;
+ struct inflate_state state;
+ code fixed[544];
+
+ /* literal/length table */
+ sym = 0;
+ while (sym < 144) state.lens[sym++] = 8;
+ while (sym < 256) state.lens[sym++] = 9;
+ while (sym < 280) state.lens[sym++] = 7;
+ while (sym < 288) state.lens[sym++] = 8;
+ next = fixed;
+ lenfix = next;
+ bits = 9;
+ inflate_table9(LENS, state.lens, 288, &(next), &(bits), state.work);
+
+ /* distance table */
+ sym = 0;
+ while (sym < 32) state.lens[sym++] = 5;
+ distfix = next;
+ bits = 5;
+ inflate_table9(DISTS, state.lens, 32, &(next), &(bits), state.work);
+
+ /* write tables */
+ puts(" /* inffix9.h -- table for decoding deflate64 fixed codes");
+ puts(" * Generated automatically by makefixed9().");
+ puts(" */");
+ puts("");
+ puts(" /* WARNING: this file should *not* be used by applications.");
+ puts(" It is part of the implementation of this library and is");
+ puts(" subject to change. Applications should only use zlib.h.");
+ puts(" */");
+ puts("");
+ size = 1U << 9;
+ printf(" static const code lenfix[%u] = {", size);
+ low = 0;
+ for (;;) {
+ if ((low % 6) == 0) printf("\n ");
+ printf("{%u,%u,%d}", lenfix[low].op, lenfix[low].bits,
+ lenfix[low].val);
+ if (++low == size) break;
+ putchar(',');
+ }
+ puts("\n };");
+ size = 1U << 5;
+ printf("\n static const code distfix[%u] = {", size);
+ low = 0;
+ for (;;) {
+ if ((low % 5) == 0) printf("\n ");
+ printf("{%u,%u,%d}", distfix[low].op, distfix[low].bits,
+ distfix[low].val);
+ if (++low == size) break;
+ putchar(',');
+ }
+ puts("\n };");
+}
+#endif /* MAKEFIXED */
+
+/* Macros for inflateBack(): */
+
+/* Clear the input bit accumulator */
+#define INITBITS() \
+ do { \
+ hold = 0; \
+ bits = 0; \
+ } while (0)
+
+/* Assure that some input is available. If input is requested, but denied,
+ then return a Z_BUF_ERROR from inflateBack(). */
+#define PULL() \
+ do { \
+ if (have == 0) { \
+ have = in(in_desc, &next); \
+ if (have == 0) { \
+ next = Z_NULL; \
+ ret = Z_BUF_ERROR; \
+ goto inf_leave; \
+ } \
+ } \
+ } while (0)
+
+/* Get a byte of input into the bit accumulator, or return from inflateBack()
+ with an error if there is no input available. */
+#define PULLBYTE() \
+ do { \
+ PULL(); \
+ have--; \
+ hold += (unsigned long)(*next++) << bits; \
+ bits += 8; \
+ } while (0)
+
+/* Assure that there are at least n bits in the bit accumulator. If there is
+ not enough available input to do that, then return from inflateBack() with
+ an error. */
+#define NEEDBITS(n) \
+ do { \
+ while (bits < (unsigned)(n)) \
+ PULLBYTE(); \
+ } while (0)
+
+/* Return the low n bits of the bit accumulator (n <= 16) */
+#define BITS(n) \
+ ((unsigned)hold & ((1U << (n)) - 1))
+
+/* Remove n bits from the bit accumulator */
+#define DROPBITS(n) \
+ do { \
+ hold >>= (n); \
+ bits -= (unsigned)(n); \
+ } while (0)
+
+/* Remove zero to seven bits as needed to go to a byte boundary */
+#define BYTEBITS() \
+ do { \
+ hold >>= bits & 7; \
+ bits -= bits & 7; \
+ } while (0)
+
+/* Assure that some output space is available, by writing out the window
+ if it's full. If the write fails, return from inflateBack() with a
+ Z_BUF_ERROR. */
+#define ROOM() \
+ do { \
+ if (left == 0) { \
+ put = window; \
+ left = WSIZE; \
+ wrap = 1; \
+ if (out(out_desc, put, (unsigned)left)) { \
+ ret = Z_BUF_ERROR; \
+ goto inf_leave; \
+ } \
+ } \
+ } while (0)
+
+/*
+ strm provides the memory allocation functions and window buffer on input,
+ and provides information on the unused input on return. For Z_DATA_ERROR
+ returns, strm will also provide an error message.
+
+ in() and out() are the call-back input and output functions. When
+ inflateBack() needs more input, it calls in(). When inflateBack() has
+ filled the window with output, or when it completes with data in the
+ window, it calls out() to write out the data. The application must not
+ change the provided input until in() is called again or inflateBack()
+ returns. The application must not change the window/output buffer until
+ inflateBack() returns.
+
+ in() and out() are called with a descriptor parameter provided in the
+ inflateBack() call. This parameter can be a structure that provides the
+ information required to do the read or write, as well as accumulated
+ information on the input and output such as totals and check values.
+
+ in() should return zero on failure. out() should return non-zero on
+ failure. If either in() or out() fails, than inflateBack() returns a
+ Z_BUF_ERROR. strm->next_in can be checked for Z_NULL to see whether it
+ was in() or out() that caused in the error. Otherwise, inflateBack()
+ returns Z_STREAM_END on success, Z_DATA_ERROR for an deflate format
+ error, or Z_MEM_ERROR if it could not allocate memory for the state.
+ inflateBack() can also return Z_STREAM_ERROR if the input parameters
+ are not correct, i.e. strm is Z_NULL or the state was not initialized.
+ */
+int ZEXPORT inflateBack9(strm, in, in_desc, out, out_desc)
+z_stream FAR *strm;
+in_func in;
+void FAR *in_desc;
+out_func out;
+void FAR *out_desc;
+{
+ struct inflate_state FAR *state;
+ z_const unsigned char FAR *next; /* next input */
+ unsigned char FAR *put; /* next output */
+ unsigned have; /* available input */
+ unsigned long left; /* available output */
+ inflate_mode mode; /* current inflate mode */
+ int lastblock; /* true if processing last block */
+ int wrap; /* true if the window has wrapped */
+ unsigned char FAR *window; /* allocated sliding window, if needed */
+ unsigned long hold; /* bit buffer */
+ unsigned bits; /* bits in bit buffer */
+ unsigned extra; /* extra bits needed */
+ unsigned long length; /* literal or length of data to copy */
+ unsigned long offset; /* distance back to copy string from */
+ unsigned long copy; /* number of stored or match bytes to copy */
+ unsigned char FAR *from; /* where to copy match bytes from */
+ code const FAR *lencode; /* starting table for length/literal codes */
+ code const FAR *distcode; /* starting table for distance codes */
+ unsigned lenbits; /* index bits for lencode */
+ unsigned distbits; /* index bits for distcode */
+ code here; /* current decoding table entry */
+ code last; /* parent table entry */
+ unsigned len; /* length to copy for repeats, bits to drop */
+ int ret; /* return code */
+ static const unsigned short order[19] = /* permutation of code lengths */
+ {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
+#include "inffix9.h"
+
+ /* Check that the strm exists and that the state was initialized */
+ if (strm == Z_NULL || strm->state == Z_NULL)
+ return Z_STREAM_ERROR;
+ state = (struct inflate_state FAR *)strm->state;
+
+ /* Reset the state */
+ strm->msg = Z_NULL;
+ mode = TYPE;
+ lastblock = 0;
+ wrap = 0;
+ window = state->window;
+ next = strm->next_in;
+ have = next != Z_NULL ? strm->avail_in : 0;
+ hold = 0;
+ bits = 0;
+ put = window;
+ left = WSIZE;
+ lencode = Z_NULL;
+ distcode = Z_NULL;
+
+ /* Inflate until end of block marked as last */
+ for (;;)
+ switch (mode) {
+ case TYPE:
+ /* determine and dispatch block type */
+ if (lastblock) {
+ BYTEBITS();
+ mode = DONE;
+ break;
+ }
+ NEEDBITS(3);
+ lastblock = BITS(1);
+ DROPBITS(1);
+ switch (BITS(2)) {
+ case 0: /* stored block */
+ Tracev((stderr, "inflate: stored block%s\n",
+ lastblock ? " (last)" : ""));
+ mode = STORED;
+ break;
+ case 1: /* fixed block */
+ lencode = lenfix;
+ lenbits = 9;
+ distcode = distfix;
+ distbits = 5;
+ Tracev((stderr, "inflate: fixed codes block%s\n",
+ lastblock ? " (last)" : ""));
+ mode = LEN; /* decode codes */
+ break;
+ case 2: /* dynamic block */
+ Tracev((stderr, "inflate: dynamic codes block%s\n",
+ lastblock ? " (last)" : ""));
+ mode = TABLE;
+ break;
+ case 3:
+ strm->msg = (char *)"invalid block type";
+ mode = BAD;
+ }
+ DROPBITS(2);
+ break;
+
+ case STORED:
+ /* get and verify stored block length */
+ BYTEBITS(); /* go to byte boundary */
+ NEEDBITS(32);
+ if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) {
+ strm->msg = (char *)"invalid stored block lengths";
+ mode = BAD;
+ break;
+ }
+ length = (unsigned)hold & 0xffff;
+ Tracev((stderr, "inflate: stored length %lu\n",
+ length));
+ INITBITS();
+
+ /* copy stored block from input to output */
+ while (length != 0) {
+ copy = length;
+ PULL();
+ ROOM();
+ if (copy > have) copy = have;
+ if (copy > left) copy = left;
+ zmemcpy(put, next, copy);
+ have -= copy;
+ next += copy;
+ left -= copy;
+ put += copy;
+ length -= copy;
+ }
+ Tracev((stderr, "inflate: stored end\n"));
+ mode = TYPE;
+ break;
+
+ case TABLE:
+ /* get dynamic table entries descriptor */
+ NEEDBITS(14);
+ state->nlen = BITS(5) + 257;
+ DROPBITS(5);
+ state->ndist = BITS(5) + 1;
+ DROPBITS(5);
+ state->ncode = BITS(4) + 4;
+ DROPBITS(4);
+ if (state->nlen > 286) {
+ strm->msg = (char *)"too many length symbols";
+ mode = BAD;
+ break;
+ }
+ Tracev((stderr, "inflate: table sizes ok\n"));
+
+ /* get code length code lengths (not a typo) */
+ state->have = 0;
+ while (state->have < state->ncode) {
+ NEEDBITS(3);
+ state->lens[order[state->have++]] = (unsigned short)BITS(3);
+ DROPBITS(3);
+ }
+ while (state->have < 19)
+ state->lens[order[state->have++]] = 0;
+ state->next = state->codes;
+ lencode = (code const FAR *)(state->next);
+ lenbits = 7;
+ ret = inflate_table9(CODES, state->lens, 19, &(state->next),
+ &(lenbits), state->work);
+ if (ret) {
+ strm->msg = (char *)"invalid code lengths set";
+ mode = BAD;
+ break;
+ }
+ Tracev((stderr, "inflate: code lengths ok\n"));
+
+ /* get length and distance code code lengths */
+ state->have = 0;
+ while (state->have < state->nlen + state->ndist) {
+ for (;;) {
+ here = lencode[BITS(lenbits)];
+ if ((unsigned)(here.bits) <= bits) break;
+ PULLBYTE();
+ }
+ if (here.val < 16) {
+ NEEDBITS(here.bits);
+ DROPBITS(here.bits);
+ state->lens[state->have++] = here.val;
+ }
+ else {
+ if (here.val == 16) {
+ NEEDBITS(here.bits + 2);
+ DROPBITS(here.bits);
+ if (state->have == 0) {
+ strm->msg = (char *)"invalid bit length repeat";
+ mode = BAD;
+ break;
+ }
+ len = (unsigned)(state->lens[state->have - 1]);
+ copy = 3 + BITS(2);
+ DROPBITS(2);
+ }
+ else if (here.val == 17) {
+ NEEDBITS(here.bits + 3);
+ DROPBITS(here.bits);
+ len = 0;
+ copy = 3 + BITS(3);
+ DROPBITS(3);
+ }
+ else {
+ NEEDBITS(here.bits + 7);
+ DROPBITS(here.bits);
+ len = 0;
+ copy = 11 + BITS(7);
+ DROPBITS(7);
+ }
+ if (state->have + copy > state->nlen + state->ndist) {
+ strm->msg = (char *)"invalid bit length repeat";
+ mode = BAD;
+ break;
+ }
+ while (copy--)
+ state->lens[state->have++] = (unsigned short)len;
+ }
+ }
+
+ /* handle error breaks in while */
+ if (mode == BAD) break;
+
+ /* check for end-of-block code (better have one) */
+ if (state->lens[256] == 0) {
+ strm->msg = (char *)"invalid code -- missing end-of-block";
+ mode = BAD;
+ break;
+ }
+
+ /* build code tables -- note: do not change the lenbits or distbits
+ values here (9 and 6) without reading the comments in inftree9.h
+ concerning the ENOUGH constants, which depend on those values */
+ state->next = state->codes;
+ lencode = (code const FAR *)(state->next);
+ lenbits = 9;
+ ret = inflate_table9(LENS, state->lens, state->nlen,
+ &(state->next), &(lenbits), state->work);
+ if (ret) {
+ strm->msg = (char *)"invalid literal/lengths set";
+ mode = BAD;
+ break;
+ }
+ distcode = (code const FAR *)(state->next);
+ distbits = 6;
+ ret = inflate_table9(DISTS, state->lens + state->nlen,
+ state->ndist, &(state->next), &(distbits),
+ state->work);
+ if (ret) {
+ strm->msg = (char *)"invalid distances set";
+ mode = BAD;
+ break;
+ }
+ Tracev((stderr, "inflate: codes ok\n"));
+ mode = LEN;
+
+ case LEN:
+ /* get a literal, length, or end-of-block code */
+ for (;;) {
+ here = lencode[BITS(lenbits)];
+ if ((unsigned)(here.bits) <= bits) break;
+ PULLBYTE();
+ }
+ if (here.op && (here.op & 0xf0) == 0) {
+ last = here;
+ for (;;) {
+ here = lencode[last.val +
+ (BITS(last.bits + last.op) >> last.bits)];
+ if ((unsigned)(last.bits + here.bits) <= bits) break;
+ PULLBYTE();
+ }
+ DROPBITS(last.bits);
+ }
+ DROPBITS(here.bits);
+ length = (unsigned)here.val;
+
+ /* process literal */
+ if (here.op == 0) {
+ Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ?
+ "inflate: literal '%c'\n" :
+ "inflate: literal 0x%02x\n", here.val));
+ ROOM();
+ *put++ = (unsigned char)(length);
+ left--;
+ mode = LEN;
+ break;
+ }
+
+ /* process end of block */
+ if (here.op & 32) {
+ Tracevv((stderr, "inflate: end of block\n"));
+ mode = TYPE;
+ break;
+ }
+
+ /* invalid code */
+ if (here.op & 64) {
+ strm->msg = (char *)"invalid literal/length code";
+ mode = BAD;
+ break;
+ }
+
+ /* length code -- get extra bits, if any */
+ extra = (unsigned)(here.op) & 31;
+ if (extra != 0) {
+ NEEDBITS(extra);
+ length += BITS(extra);
+ DROPBITS(extra);
+ }
+ Tracevv((stderr, "inflate: length %lu\n", length));
+
+ /* get distance code */
+ for (;;) {
+ here = distcode[BITS(distbits)];
+ if ((unsigned)(here.bits) <= bits) break;
+ PULLBYTE();
+ }
+ if ((here.op & 0xf0) == 0) {
+ last = here;
+ for (;;) {
+ here = distcode[last.val +
+ (BITS(last.bits + last.op) >> last.bits)];
+ if ((unsigned)(last.bits + here.bits) <= bits) break;
+ PULLBYTE();
+ }
+ DROPBITS(last.bits);
+ }
+ DROPBITS(here.bits);
+ if (here.op & 64) {
+ strm->msg = (char *)"invalid distance code";
+ mode = BAD;
+ break;
+ }
+ offset = (unsigned)here.val;
+
+ /* get distance extra bits, if any */
+ extra = (unsigned)(here.op) & 15;
+ if (extra != 0) {
+ NEEDBITS(extra);
+ offset += BITS(extra);
+ DROPBITS(extra);
+ }
+ if (offset > WSIZE - (wrap ? 0: left)) {
+ strm->msg = (char *)"invalid distance too far back";
+ mode = BAD;
+ break;
+ }
+ Tracevv((stderr, "inflate: distance %lu\n", offset));
+
+ /* copy match from window to output */
+ do {
+ ROOM();
+ copy = WSIZE - offset;
+ if (copy < left) {
+ from = put + copy;
+ copy = left - copy;
+ }
+ else {
+ from = put - offset;
+ copy = left;
+ }
+ if (copy > length) copy = length;
+ length -= copy;
+ left -= copy;
+ do {
+ *put++ = *from++;
+ } while (--copy);
+ } while (length != 0);
+ break;
+
+ case DONE:
+ /* inflate stream terminated properly -- write leftover output */
+ ret = Z_STREAM_END;
+ if (left < WSIZE) {
+ if (out(out_desc, window, (unsigned)(WSIZE - left)))
+ ret = Z_BUF_ERROR;
+ }
+ goto inf_leave;
+
+ case BAD:
+ ret = Z_DATA_ERROR;
+ goto inf_leave;
+
+ default: /* can't happen, but makes compilers happy */
+ ret = Z_STREAM_ERROR;
+ goto inf_leave;
+ }
+
+ /* Return unused input */
+ inf_leave:
+ strm->next_in = next;
+ strm->avail_in = have;
+ return ret;
+}
+
+int ZEXPORT inflateBack9End(strm)
+z_stream FAR *strm;
+{
+ if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0)
+ return Z_STREAM_ERROR;
+ ZFREE(strm, strm->state);
+ strm->state = Z_NULL;
+ Tracev((stderr, "inflate: end\n"));
+ return Z_OK;
+}
ADDED compat/zlib/contrib/infback9/infback9.h
Index: compat/zlib/contrib/infback9/infback9.h
==================================================================
--- compat/zlib/contrib/infback9/infback9.h
+++ compat/zlib/contrib/infback9/infback9.h
@@ -0,0 +1,37 @@
+/* infback9.h -- header for using inflateBack9 functions
+ * Copyright (C) 2003 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/*
+ * This header file and associated patches provide a decoder for PKWare's
+ * undocumented deflate64 compression method (method 9). Use with infback9.c,
+ * inftree9.h, inftree9.c, and inffix9.h. These patches are not supported.
+ * This should be compiled with zlib, since it uses zutil.h and zutil.o.
+ * This code has not yet been tested on 16-bit architectures. See the
+ * comments in zlib.h for inflateBack() usage. These functions are used
+ * identically, except that there is no windowBits parameter, and a 64K
+ * window must be provided. Also if int's are 16 bits, then a zero for
+ * the third parameter of the "out" function actually means 65536UL.
+ * zlib.h must be included before this header file.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ZEXTERN int ZEXPORT inflateBack9 OF((z_stream FAR *strm,
+ in_func in, void FAR *in_desc,
+ out_func out, void FAR *out_desc));
+ZEXTERN int ZEXPORT inflateBack9End OF((z_stream FAR *strm));
+ZEXTERN int ZEXPORT inflateBack9Init_ OF((z_stream FAR *strm,
+ unsigned char FAR *window,
+ const char *version,
+ int stream_size));
+#define inflateBack9Init(strm, window) \
+ inflateBack9Init_((strm), (window), \
+ ZLIB_VERSION, sizeof(z_stream))
+
+#ifdef __cplusplus
+}
+#endif
ADDED compat/zlib/contrib/infback9/inffix9.h
Index: compat/zlib/contrib/infback9/inffix9.h
==================================================================
--- compat/zlib/contrib/infback9/inffix9.h
+++ compat/zlib/contrib/infback9/inffix9.h
@@ -0,0 +1,107 @@
+ /* inffix9.h -- table for decoding deflate64 fixed codes
+ * Generated automatically by makefixed9().
+ */
+
+ /* WARNING: this file should *not* be used by applications.
+ It is part of the implementation of this library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+ static const code lenfix[512] = {
+ {96,7,0},{0,8,80},{0,8,16},{132,8,115},{130,7,31},{0,8,112},
+ {0,8,48},{0,9,192},{128,7,10},{0,8,96},{0,8,32},{0,9,160},
+ {0,8,0},{0,8,128},{0,8,64},{0,9,224},{128,7,6},{0,8,88},
+ {0,8,24},{0,9,144},{131,7,59},{0,8,120},{0,8,56},{0,9,208},
+ {129,7,17},{0,8,104},{0,8,40},{0,9,176},{0,8,8},{0,8,136},
+ {0,8,72},{0,9,240},{128,7,4},{0,8,84},{0,8,20},{133,8,227},
+ {131,7,43},{0,8,116},{0,8,52},{0,9,200},{129,7,13},{0,8,100},
+ {0,8,36},{0,9,168},{0,8,4},{0,8,132},{0,8,68},{0,9,232},
+ {128,7,8},{0,8,92},{0,8,28},{0,9,152},{132,7,83},{0,8,124},
+ {0,8,60},{0,9,216},{130,7,23},{0,8,108},{0,8,44},{0,9,184},
+ {0,8,12},{0,8,140},{0,8,76},{0,9,248},{128,7,3},{0,8,82},
+ {0,8,18},{133,8,163},{131,7,35},{0,8,114},{0,8,50},{0,9,196},
+ {129,7,11},{0,8,98},{0,8,34},{0,9,164},{0,8,2},{0,8,130},
+ {0,8,66},{0,9,228},{128,7,7},{0,8,90},{0,8,26},{0,9,148},
+ {132,7,67},{0,8,122},{0,8,58},{0,9,212},{130,7,19},{0,8,106},
+ {0,8,42},{0,9,180},{0,8,10},{0,8,138},{0,8,74},{0,9,244},
+ {128,7,5},{0,8,86},{0,8,22},{65,8,0},{131,7,51},{0,8,118},
+ {0,8,54},{0,9,204},{129,7,15},{0,8,102},{0,8,38},{0,9,172},
+ {0,8,6},{0,8,134},{0,8,70},{0,9,236},{128,7,9},{0,8,94},
+ {0,8,30},{0,9,156},{132,7,99},{0,8,126},{0,8,62},{0,9,220},
+ {130,7,27},{0,8,110},{0,8,46},{0,9,188},{0,8,14},{0,8,142},
+ {0,8,78},{0,9,252},{96,7,0},{0,8,81},{0,8,17},{133,8,131},
+ {130,7,31},{0,8,113},{0,8,49},{0,9,194},{128,7,10},{0,8,97},
+ {0,8,33},{0,9,162},{0,8,1},{0,8,129},{0,8,65},{0,9,226},
+ {128,7,6},{0,8,89},{0,8,25},{0,9,146},{131,7,59},{0,8,121},
+ {0,8,57},{0,9,210},{129,7,17},{0,8,105},{0,8,41},{0,9,178},
+ {0,8,9},{0,8,137},{0,8,73},{0,9,242},{128,7,4},{0,8,85},
+ {0,8,21},{144,8,3},{131,7,43},{0,8,117},{0,8,53},{0,9,202},
+ {129,7,13},{0,8,101},{0,8,37},{0,9,170},{0,8,5},{0,8,133},
+ {0,8,69},{0,9,234},{128,7,8},{0,8,93},{0,8,29},{0,9,154},
+ {132,7,83},{0,8,125},{0,8,61},{0,9,218},{130,7,23},{0,8,109},
+ {0,8,45},{0,9,186},{0,8,13},{0,8,141},{0,8,77},{0,9,250},
+ {128,7,3},{0,8,83},{0,8,19},{133,8,195},{131,7,35},{0,8,115},
+ {0,8,51},{0,9,198},{129,7,11},{0,8,99},{0,8,35},{0,9,166},
+ {0,8,3},{0,8,131},{0,8,67},{0,9,230},{128,7,7},{0,8,91},
+ {0,8,27},{0,9,150},{132,7,67},{0,8,123},{0,8,59},{0,9,214},
+ {130,7,19},{0,8,107},{0,8,43},{0,9,182},{0,8,11},{0,8,139},
+ {0,8,75},{0,9,246},{128,7,5},{0,8,87},{0,8,23},{77,8,0},
+ {131,7,51},{0,8,119},{0,8,55},{0,9,206},{129,7,15},{0,8,103},
+ {0,8,39},{0,9,174},{0,8,7},{0,8,135},{0,8,71},{0,9,238},
+ {128,7,9},{0,8,95},{0,8,31},{0,9,158},{132,7,99},{0,8,127},
+ {0,8,63},{0,9,222},{130,7,27},{0,8,111},{0,8,47},{0,9,190},
+ {0,8,15},{0,8,143},{0,8,79},{0,9,254},{96,7,0},{0,8,80},
+ {0,8,16},{132,8,115},{130,7,31},{0,8,112},{0,8,48},{0,9,193},
+ {128,7,10},{0,8,96},{0,8,32},{0,9,161},{0,8,0},{0,8,128},
+ {0,8,64},{0,9,225},{128,7,6},{0,8,88},{0,8,24},{0,9,145},
+ {131,7,59},{0,8,120},{0,8,56},{0,9,209},{129,7,17},{0,8,104},
+ {0,8,40},{0,9,177},{0,8,8},{0,8,136},{0,8,72},{0,9,241},
+ {128,7,4},{0,8,84},{0,8,20},{133,8,227},{131,7,43},{0,8,116},
+ {0,8,52},{0,9,201},{129,7,13},{0,8,100},{0,8,36},{0,9,169},
+ {0,8,4},{0,8,132},{0,8,68},{0,9,233},{128,7,8},{0,8,92},
+ {0,8,28},{0,9,153},{132,7,83},{0,8,124},{0,8,60},{0,9,217},
+ {130,7,23},{0,8,108},{0,8,44},{0,9,185},{0,8,12},{0,8,140},
+ {0,8,76},{0,9,249},{128,7,3},{0,8,82},{0,8,18},{133,8,163},
+ {131,7,35},{0,8,114},{0,8,50},{0,9,197},{129,7,11},{0,8,98},
+ {0,8,34},{0,9,165},{0,8,2},{0,8,130},{0,8,66},{0,9,229},
+ {128,7,7},{0,8,90},{0,8,26},{0,9,149},{132,7,67},{0,8,122},
+ {0,8,58},{0,9,213},{130,7,19},{0,8,106},{0,8,42},{0,9,181},
+ {0,8,10},{0,8,138},{0,8,74},{0,9,245},{128,7,5},{0,8,86},
+ {0,8,22},{65,8,0},{131,7,51},{0,8,118},{0,8,54},{0,9,205},
+ {129,7,15},{0,8,102},{0,8,38},{0,9,173},{0,8,6},{0,8,134},
+ {0,8,70},{0,9,237},{128,7,9},{0,8,94},{0,8,30},{0,9,157},
+ {132,7,99},{0,8,126},{0,8,62},{0,9,221},{130,7,27},{0,8,110},
+ {0,8,46},{0,9,189},{0,8,14},{0,8,142},{0,8,78},{0,9,253},
+ {96,7,0},{0,8,81},{0,8,17},{133,8,131},{130,7,31},{0,8,113},
+ {0,8,49},{0,9,195},{128,7,10},{0,8,97},{0,8,33},{0,9,163},
+ {0,8,1},{0,8,129},{0,8,65},{0,9,227},{128,7,6},{0,8,89},
+ {0,8,25},{0,9,147},{131,7,59},{0,8,121},{0,8,57},{0,9,211},
+ {129,7,17},{0,8,105},{0,8,41},{0,9,179},{0,8,9},{0,8,137},
+ {0,8,73},{0,9,243},{128,7,4},{0,8,85},{0,8,21},{144,8,3},
+ {131,7,43},{0,8,117},{0,8,53},{0,9,203},{129,7,13},{0,8,101},
+ {0,8,37},{0,9,171},{0,8,5},{0,8,133},{0,8,69},{0,9,235},
+ {128,7,8},{0,8,93},{0,8,29},{0,9,155},{132,7,83},{0,8,125},
+ {0,8,61},{0,9,219},{130,7,23},{0,8,109},{0,8,45},{0,9,187},
+ {0,8,13},{0,8,141},{0,8,77},{0,9,251},{128,7,3},{0,8,83},
+ {0,8,19},{133,8,195},{131,7,35},{0,8,115},{0,8,51},{0,9,199},
+ {129,7,11},{0,8,99},{0,8,35},{0,9,167},{0,8,3},{0,8,131},
+ {0,8,67},{0,9,231},{128,7,7},{0,8,91},{0,8,27},{0,9,151},
+ {132,7,67},{0,8,123},{0,8,59},{0,9,215},{130,7,19},{0,8,107},
+ {0,8,43},{0,9,183},{0,8,11},{0,8,139},{0,8,75},{0,9,247},
+ {128,7,5},{0,8,87},{0,8,23},{77,8,0},{131,7,51},{0,8,119},
+ {0,8,55},{0,9,207},{129,7,15},{0,8,103},{0,8,39},{0,9,175},
+ {0,8,7},{0,8,135},{0,8,71},{0,9,239},{128,7,9},{0,8,95},
+ {0,8,31},{0,9,159},{132,7,99},{0,8,127},{0,8,63},{0,9,223},
+ {130,7,27},{0,8,111},{0,8,47},{0,9,191},{0,8,15},{0,8,143},
+ {0,8,79},{0,9,255}
+ };
+
+ static const code distfix[32] = {
+ {128,5,1},{135,5,257},{131,5,17},{139,5,4097},{129,5,5},
+ {137,5,1025},{133,5,65},{141,5,16385},{128,5,3},{136,5,513},
+ {132,5,33},{140,5,8193},{130,5,9},{138,5,2049},{134,5,129},
+ {142,5,32769},{128,5,2},{135,5,385},{131,5,25},{139,5,6145},
+ {129,5,7},{137,5,1537},{133,5,97},{141,5,24577},{128,5,4},
+ {136,5,769},{132,5,49},{140,5,12289},{130,5,13},{138,5,3073},
+ {134,5,193},{142,5,49153}
+ };
ADDED compat/zlib/contrib/infback9/inflate9.h
Index: compat/zlib/contrib/infback9/inflate9.h
==================================================================
--- compat/zlib/contrib/infback9/inflate9.h
+++ compat/zlib/contrib/infback9/inflate9.h
@@ -0,0 +1,47 @@
+/* inflate9.h -- internal inflate state definition
+ * Copyright (C) 1995-2003 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+/* Possible inflate modes between inflate() calls */
+typedef enum {
+ TYPE, /* i: waiting for type bits, including last-flag bit */
+ STORED, /* i: waiting for stored size (length and complement) */
+ TABLE, /* i: waiting for dynamic block table lengths */
+ LEN, /* i: waiting for length/lit code */
+ DONE, /* finished check, done -- remain here until reset */
+ BAD /* got a data error -- remain here until reset */
+} inflate_mode;
+
+/*
+ State transitions between above modes -
+
+ (most modes can go to the BAD mode -- not shown for clarity)
+
+ Read deflate blocks:
+ TYPE -> STORED or TABLE or LEN or DONE
+ STORED -> TYPE
+ TABLE -> LENLENS -> CODELENS -> LEN
+ Read deflate codes:
+ LEN -> LEN or TYPE
+ */
+
+/* state maintained between inflate() calls. Approximately 7K bytes. */
+struct inflate_state {
+ /* sliding window */
+ unsigned char FAR *window; /* allocated sliding window, if needed */
+ /* dynamic table building */
+ unsigned ncode; /* number of code length code lengths */
+ unsigned nlen; /* number of length code lengths */
+ unsigned ndist; /* number of distance code lengths */
+ unsigned have; /* number of code lengths in lens[] */
+ code FAR *next; /* next available space in codes[] */
+ unsigned short lens[320]; /* temporary storage for code lengths */
+ unsigned short work[288]; /* work area for code table building */
+ code codes[ENOUGH]; /* space for code tables */
+};
ADDED compat/zlib/contrib/infback9/inftree9.c
Index: compat/zlib/contrib/infback9/inftree9.c
==================================================================
--- compat/zlib/contrib/infback9/inftree9.c
+++ compat/zlib/contrib/infback9/inftree9.c
@@ -0,0 +1,324 @@
+/* inftree9.c -- generate Huffman trees for efficient decoding
+ * Copyright (C) 1995-2013 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+#include "zutil.h"
+#include "inftree9.h"
+
+#define MAXBITS 15
+
+const char inflate9_copyright[] =
+ " inflate9 1.2.8 Copyright 1995-2013 Mark Adler ";
+/*
+ If you use the zlib library in a product, an acknowledgment is welcome
+ in the documentation of your product. If for some reason you cannot
+ include such an acknowledgment, I would appreciate that you keep this
+ copyright string in the executable of your product.
+ */
+
+/*
+ Build a set of tables to decode the provided canonical Huffman code.
+ The code lengths are lens[0..codes-1]. The result starts at *table,
+ whose indices are 0..2^bits-1. work is a writable array of at least
+ lens shorts, which is used as a work area. type is the type of code
+ to be generated, CODES, LENS, or DISTS. On return, zero is success,
+ -1 is an invalid code, and +1 means that ENOUGH isn't enough. table
+ on return points to the next available entry's address. bits is the
+ requested root table index bits, and on return it is the actual root
+ table index bits. It will differ if the request is greater than the
+ longest code or if it is less than the shortest code.
+ */
+int inflate_table9(type, lens, codes, table, bits, work)
+codetype type;
+unsigned short FAR *lens;
+unsigned codes;
+code FAR * FAR *table;
+unsigned FAR *bits;
+unsigned short FAR *work;
+{
+ unsigned len; /* a code's length in bits */
+ unsigned sym; /* index of code symbols */
+ unsigned min, max; /* minimum and maximum code lengths */
+ unsigned root; /* number of index bits for root table */
+ unsigned curr; /* number of index bits for current table */
+ unsigned drop; /* code bits to drop for sub-table */
+ int left; /* number of prefix codes available */
+ unsigned used; /* code entries in table used */
+ unsigned huff; /* Huffman code */
+ unsigned incr; /* for incrementing code, index */
+ unsigned fill; /* index for replicating entries */
+ unsigned low; /* low bits for current root entry */
+ unsigned mask; /* mask for low root bits */
+ code this; /* table entry for duplication */
+ code FAR *next; /* next available space in table */
+ const unsigned short FAR *base; /* base value table to use */
+ const unsigned short FAR *extra; /* extra bits table to use */
+ int end; /* use base and extra for symbol > end */
+ unsigned short count[MAXBITS+1]; /* number of codes of each length */
+ unsigned short offs[MAXBITS+1]; /* offsets in table for each length */
+ static const unsigned short lbase[31] = { /* Length codes 257..285 base */
+ 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17,
+ 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115,
+ 131, 163, 195, 227, 3, 0, 0};
+ static const unsigned short lext[31] = { /* Length codes 257..285 extra */
+ 128, 128, 128, 128, 128, 128, 128, 128, 129, 129, 129, 129,
+ 130, 130, 130, 130, 131, 131, 131, 131, 132, 132, 132, 132,
+ 133, 133, 133, 133, 144, 72, 78};
+ static const unsigned short dbase[32] = { /* Distance codes 0..31 base */
+ 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49,
+ 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073,
+ 4097, 6145, 8193, 12289, 16385, 24577, 32769, 49153};
+ static const unsigned short dext[32] = { /* Distance codes 0..31 extra */
+ 128, 128, 128, 128, 129, 129, 130, 130, 131, 131, 132, 132,
+ 133, 133, 134, 134, 135, 135, 136, 136, 137, 137, 138, 138,
+ 139, 139, 140, 140, 141, 141, 142, 142};
+
+ /*
+ Process a set of code lengths to create a canonical Huffman code. The
+ code lengths are lens[0..codes-1]. Each length corresponds to the
+ symbols 0..codes-1. The Huffman code is generated by first sorting the
+ symbols by length from short to long, and retaining the symbol order
+ for codes with equal lengths. Then the code starts with all zero bits
+ for the first code of the shortest length, and the codes are integer
+ increments for the same length, and zeros are appended as the length
+ increases. For the deflate format, these bits are stored backwards
+ from their more natural integer increment ordering, and so when the
+ decoding tables are built in the large loop below, the integer codes
+ are incremented backwards.
+
+ This routine assumes, but does not check, that all of the entries in
+ lens[] are in the range 0..MAXBITS. The caller must assure this.
+ 1..MAXBITS is interpreted as that code length. zero means that that
+ symbol does not occur in this code.
+
+ The codes are sorted by computing a count of codes for each length,
+ creating from that a table of starting indices for each length in the
+ sorted table, and then entering the symbols in order in the sorted
+ table. The sorted table is work[], with that space being provided by
+ the caller.
+
+ The length counts are used for other purposes as well, i.e. finding
+ the minimum and maximum length codes, determining if there are any
+ codes at all, checking for a valid set of lengths, and looking ahead
+ at length counts to determine sub-table sizes when building the
+ decoding tables.
+ */
+
+ /* accumulate lengths for codes (assumes lens[] all in 0..MAXBITS) */
+ for (len = 0; len <= MAXBITS; len++)
+ count[len] = 0;
+ for (sym = 0; sym < codes; sym++)
+ count[lens[sym]]++;
+
+ /* bound code lengths, force root to be within code lengths */
+ root = *bits;
+ for (max = MAXBITS; max >= 1; max--)
+ if (count[max] != 0) break;
+ if (root > max) root = max;
+ if (max == 0) return -1; /* no codes! */
+ for (min = 1; min <= MAXBITS; min++)
+ if (count[min] != 0) break;
+ if (root < min) root = min;
+
+ /* check for an over-subscribed or incomplete set of lengths */
+ left = 1;
+ for (len = 1; len <= MAXBITS; len++) {
+ left <<= 1;
+ left -= count[len];
+ if (left < 0) return -1; /* over-subscribed */
+ }
+ if (left > 0 && (type == CODES || max != 1))
+ return -1; /* incomplete set */
+
+ /* generate offsets into symbol table for each length for sorting */
+ offs[1] = 0;
+ for (len = 1; len < MAXBITS; len++)
+ offs[len + 1] = offs[len] + count[len];
+
+ /* sort symbols by length, by symbol order within each length */
+ for (sym = 0; sym < codes; sym++)
+ if (lens[sym] != 0) work[offs[lens[sym]]++] = (unsigned short)sym;
+
+ /*
+ Create and fill in decoding tables. In this loop, the table being
+ filled is at next and has curr index bits. The code being used is huff
+ with length len. That code is converted to an index by dropping drop
+ bits off of the bottom. For codes where len is less than drop + curr,
+ those top drop + curr - len bits are incremented through all values to
+ fill the table with replicated entries.
+
+ root is the number of index bits for the root table. When len exceeds
+ root, sub-tables are created pointed to by the root entry with an index
+ of the low root bits of huff. This is saved in low to check for when a
+ new sub-table should be started. drop is zero when the root table is
+ being filled, and drop is root when sub-tables are being filled.
+
+ When a new sub-table is needed, it is necessary to look ahead in the
+ code lengths to determine what size sub-table is needed. The length
+ counts are used for this, and so count[] is decremented as codes are
+ entered in the tables.
+
+ used keeps track of how many table entries have been allocated from the
+ provided *table space. It is checked for LENS and DIST tables against
+ the constants ENOUGH_LENS and ENOUGH_DISTS to guard against changes in
+ the initial root table size constants. See the comments in inftree9.h
+ for more information.
+
+ sym increments through all symbols, and the loop terminates when
+ all codes of length max, i.e. all codes, have been processed. This
+ routine permits incomplete codes, so another loop after this one fills
+ in the rest of the decoding tables with invalid code markers.
+ */
+
+ /* set up for code type */
+ switch (type) {
+ case CODES:
+ base = extra = work; /* dummy value--not used */
+ end = 19;
+ break;
+ case LENS:
+ base = lbase;
+ base -= 257;
+ extra = lext;
+ extra -= 257;
+ end = 256;
+ break;
+ default: /* DISTS */
+ base = dbase;
+ extra = dext;
+ end = -1;
+ }
+
+ /* initialize state for loop */
+ huff = 0; /* starting code */
+ sym = 0; /* starting code symbol */
+ len = min; /* starting code length */
+ next = *table; /* current table to fill in */
+ curr = root; /* current table index bits */
+ drop = 0; /* current bits to drop from code for index */
+ low = (unsigned)(-1); /* trigger new sub-table when len > root */
+ used = 1U << root; /* use root table entries */
+ mask = used - 1; /* mask for comparing low */
+
+ /* check available table space */
+ if ((type == LENS && used >= ENOUGH_LENS) ||
+ (type == DISTS && used >= ENOUGH_DISTS))
+ return 1;
+
+ /* process all codes and make table entries */
+ for (;;) {
+ /* create table entry */
+ this.bits = (unsigned char)(len - drop);
+ if ((int)(work[sym]) < end) {
+ this.op = (unsigned char)0;
+ this.val = work[sym];
+ }
+ else if ((int)(work[sym]) > end) {
+ this.op = (unsigned char)(extra[work[sym]]);
+ this.val = base[work[sym]];
+ }
+ else {
+ this.op = (unsigned char)(32 + 64); /* end of block */
+ this.val = 0;
+ }
+
+ /* replicate for those indices with low len bits equal to huff */
+ incr = 1U << (len - drop);
+ fill = 1U << curr;
+ do {
+ fill -= incr;
+ next[(huff >> drop) + fill] = this;
+ } while (fill != 0);
+
+ /* backwards increment the len-bit code huff */
+ incr = 1U << (len - 1);
+ while (huff & incr)
+ incr >>= 1;
+ if (incr != 0) {
+ huff &= incr - 1;
+ huff += incr;
+ }
+ else
+ huff = 0;
+
+ /* go to next symbol, update count, len */
+ sym++;
+ if (--(count[len]) == 0) {
+ if (len == max) break;
+ len = lens[work[sym]];
+ }
+
+ /* create new sub-table if needed */
+ if (len > root && (huff & mask) != low) {
+ /* if first time, transition to sub-tables */
+ if (drop == 0)
+ drop = root;
+
+ /* increment past last table */
+ next += 1U << curr;
+
+ /* determine length of next table */
+ curr = len - drop;
+ left = (int)(1 << curr);
+ while (curr + drop < max) {
+ left -= count[curr + drop];
+ if (left <= 0) break;
+ curr++;
+ left <<= 1;
+ }
+
+ /* check for enough space */
+ used += 1U << curr;
+ if ((type == LENS && used >= ENOUGH_LENS) ||
+ (type == DISTS && used >= ENOUGH_DISTS))
+ return 1;
+
+ /* point entry in root table to sub-table */
+ low = huff & mask;
+ (*table)[low].op = (unsigned char)curr;
+ (*table)[low].bits = (unsigned char)root;
+ (*table)[low].val = (unsigned short)(next - *table);
+ }
+ }
+
+ /*
+ Fill in rest of table for incomplete codes. This loop is similar to the
+ loop above in incrementing huff for table indices. It is assumed that
+ len is equal to curr + drop, so there is no loop needed to increment
+ through high index bits. When the current sub-table is filled, the loop
+ drops back to the root table to fill in any remaining entries there.
+ */
+ this.op = (unsigned char)64; /* invalid code marker */
+ this.bits = (unsigned char)(len - drop);
+ this.val = (unsigned short)0;
+ while (huff != 0) {
+ /* when done with sub-table, drop back to root table */
+ if (drop != 0 && (huff & mask) != low) {
+ drop = 0;
+ len = root;
+ next = *table;
+ curr = root;
+ this.bits = (unsigned char)len;
+ }
+
+ /* put invalid code marker in table */
+ next[huff >> drop] = this;
+
+ /* backwards increment the len-bit code huff */
+ incr = 1U << (len - 1);
+ while (huff & incr)
+ incr >>= 1;
+ if (incr != 0) {
+ huff &= incr - 1;
+ huff += incr;
+ }
+ else
+ huff = 0;
+ }
+
+ /* set return parameters */
+ *table += used;
+ *bits = root;
+ return 0;
+}
ADDED compat/zlib/contrib/infback9/inftree9.h
Index: compat/zlib/contrib/infback9/inftree9.h
==================================================================
--- compat/zlib/contrib/infback9/inftree9.h
+++ compat/zlib/contrib/infback9/inftree9.h
@@ -0,0 +1,61 @@
+/* inftree9.h -- header to use inftree9.c
+ * Copyright (C) 1995-2008 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* WARNING: this file should *not* be used by applications. It is
+ part of the implementation of the compression library and is
+ subject to change. Applications should only use zlib.h.
+ */
+
+/* Structure for decoding tables. Each entry provides either the
+ information needed to do the operation requested by the code that
+ indexed that table entry, or it provides a pointer to another
+ table that indexes more bits of the code. op indicates whether
+ the entry is a pointer to another table, a literal, a length or
+ distance, an end-of-block, or an invalid code. For a table
+ pointer, the low four bits of op is the number of index bits of
+ that table. For a length or distance, the low four bits of op
+ is the number of extra bits to get after the code. bits is
+ the number of bits in this code or part of the code to drop off
+ of the bit buffer. val is the actual byte to output in the case
+ of a literal, the base length or distance, or the offset from
+ the current table to the next table. Each entry is four bytes. */
+typedef struct {
+ unsigned char op; /* operation, extra bits, table bits */
+ unsigned char bits; /* bits in this part of the code */
+ unsigned short val; /* offset in table or code value */
+} code;
+
+/* op values as set by inflate_table():
+ 00000000 - literal
+ 0000tttt - table link, tttt != 0 is the number of table index bits
+ 100eeeee - length or distance, eeee is the number of extra bits
+ 01100000 - end of block
+ 01000000 - invalid code
+ */
+
+/* Maximum size of the dynamic table. The maximum number of code structures is
+ 1446, which is the sum of 852 for literal/length codes and 594 for distance
+ codes. These values were found by exhaustive searches using the program
+ examples/enough.c found in the zlib distribtution. The arguments to that
+ program are the number of symbols, the initial root table size, and the
+ maximum bit length of a code. "enough 286 9 15" for literal/length codes
+ returns returns 852, and "enough 32 6 15" for distance codes returns 594.
+ The initial root table size (9 or 6) is found in the fifth argument of the
+ inflate_table() calls in infback9.c. If the root table size is changed,
+ then these maximum sizes would be need to be recalculated and updated. */
+#define ENOUGH_LENS 852
+#define ENOUGH_DISTS 594
+#define ENOUGH (ENOUGH_LENS+ENOUGH_DISTS)
+
+/* Type of code to build for inflate_table9() */
+typedef enum {
+ CODES,
+ LENS,
+ DISTS
+} codetype;
+
+extern int inflate_table9 OF((codetype type, unsigned short FAR *lens,
+ unsigned codes, code FAR * FAR *table,
+ unsigned FAR *bits, unsigned short FAR *work));
ADDED compat/zlib/contrib/inflate86/inffas86.c
Index: compat/zlib/contrib/inflate86/inffas86.c
==================================================================
--- compat/zlib/contrib/inflate86/inffas86.c
+++ compat/zlib/contrib/inflate86/inffas86.c
@@ -0,0 +1,1157 @@
+/* inffas86.c is a hand tuned assembler version of
+ *
+ * inffast.c -- fast decoding
+ * Copyright (C) 1995-2003 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ *
+ * Copyright (C) 2003 Chris Anderson
+ * Please use the copyright conditions above.
+ *
+ * Dec-29-2003 -- I added AMD64 inflate asm support. This version is also
+ * slightly quicker on x86 systems because, instead of using rep movsb to copy
+ * data, it uses rep movsw, which moves data in 2-byte chunks instead of single
+ * bytes. I've tested the AMD64 code on a Fedora Core 1 + the x86_64 updates
+ * from http://fedora.linux.duke.edu/fc1_x86_64
+ * which is running on an Athlon 64 3000+ / Gigabyte GA-K8VT800M system with
+ * 1GB ram. The 64-bit version is about 4% faster than the 32-bit version,
+ * when decompressing mozilla-source-1.3.tar.gz.
+ *
+ * Mar-13-2003 -- Most of this is derived from inffast.S which is derived from
+ * the gcc -S output of zlib-1.2.0/inffast.c. Zlib-1.2.0 is in beta release at
+ * the moment. I have successfully compiled and tested this code with gcc2.96,
+ * gcc3.2, icc5.0, msvc6.0. It is very close to the speed of inffast.S
+ * compiled with gcc -DNO_MMX, but inffast.S is still faster on the P3 with MMX
+ * enabled. I will attempt to merge the MMX code into this version. Newer
+ * versions of this and inffast.S can be found at
+ * http://www.eetbeetee.com/zlib/ and http://www.charm.net/~christop/zlib/
+ */
+
+#include "zutil.h"
+#include "inftrees.h"
+#include "inflate.h"
+#include "inffast.h"
+
+/* Mark Adler's comments from inffast.c: */
+
+/*
+ Decode literal, length, and distance codes and write out the resulting
+ literal and match bytes until either not enough input or output is
+ available, an end-of-block is encountered, or a data error is encountered.
+ When large enough input and output buffers are supplied to inflate(), for
+ example, a 16K input buffer and a 64K output buffer, more than 95% of the
+ inflate execution time is spent in this routine.
+
+ Entry assumptions:
+
+ state->mode == LEN
+ strm->avail_in >= 6
+ strm->avail_out >= 258
+ start >= strm->avail_out
+ state->bits < 8
+
+ On return, state->mode is one of:
+
+ LEN -- ran out of enough output space or enough available input
+ TYPE -- reached end of block code, inflate() to interpret next block
+ BAD -- error in block data
+
+ Notes:
+
+ - The maximum input bits used by a length/distance pair is 15 bits for the
+ length code, 5 bits for the length extra, 15 bits for the distance code,
+ and 13 bits for the distance extra. This totals 48 bits, or six bytes.
+ Therefore if strm->avail_in >= 6, then there is enough input to avoid
+ checking for available input while decoding.
+
+ - The maximum bytes that a single length/distance pair can output is 258
+ bytes, which is the maximum length that can be coded. inflate_fast()
+ requires strm->avail_out >= 258 for each loop to avoid checking for
+ output space.
+ */
+void inflate_fast(strm, start)
+z_streamp strm;
+unsigned start; /* inflate()'s starting value for strm->avail_out */
+{
+ struct inflate_state FAR *state;
+ struct inffast_ar {
+/* 64 32 x86 x86_64 */
+/* ar offset register */
+/* 0 0 */ void *esp; /* esp save */
+/* 8 4 */ void *ebp; /* ebp save */
+/* 16 8 */ unsigned char FAR *in; /* esi rsi local strm->next_in */
+/* 24 12 */ unsigned char FAR *last; /* r9 while in < last */
+/* 32 16 */ unsigned char FAR *out; /* edi rdi local strm->next_out */
+/* 40 20 */ unsigned char FAR *beg; /* inflate()'s init next_out */
+/* 48 24 */ unsigned char FAR *end; /* r10 while out < end */
+/* 56 28 */ unsigned char FAR *window;/* size of window, wsize!=0 */
+/* 64 32 */ code const FAR *lcode; /* ebp rbp local strm->lencode */
+/* 72 36 */ code const FAR *dcode; /* r11 local strm->distcode */
+/* 80 40 */ unsigned long hold; /* edx rdx local strm->hold */
+/* 88 44 */ unsigned bits; /* ebx rbx local strm->bits */
+/* 92 48 */ unsigned wsize; /* window size */
+/* 96 52 */ unsigned write; /* window write index */
+/*100 56 */ unsigned lmask; /* r12 mask for lcode */
+/*104 60 */ unsigned dmask; /* r13 mask for dcode */
+/*108 64 */ unsigned len; /* r14 match length */
+/*112 68 */ unsigned dist; /* r15 match distance */
+/*116 72 */ unsigned status; /* set when state chng*/
+ } ar;
+
+#if defined( __GNUC__ ) && defined( __amd64__ ) && ! defined( __i386 )
+#define PAD_AVAIL_IN 6
+#define PAD_AVAIL_OUT 258
+#else
+#define PAD_AVAIL_IN 5
+#define PAD_AVAIL_OUT 257
+#endif
+
+ /* copy state to local variables */
+ state = (struct inflate_state FAR *)strm->state;
+ ar.in = strm->next_in;
+ ar.last = ar.in + (strm->avail_in - PAD_AVAIL_IN);
+ ar.out = strm->next_out;
+ ar.beg = ar.out - (start - strm->avail_out);
+ ar.end = ar.out + (strm->avail_out - PAD_AVAIL_OUT);
+ ar.wsize = state->wsize;
+ ar.write = state->wnext;
+ ar.window = state->window;
+ ar.hold = state->hold;
+ ar.bits = state->bits;
+ ar.lcode = state->lencode;
+ ar.dcode = state->distcode;
+ ar.lmask = (1U << state->lenbits) - 1;
+ ar.dmask = (1U << state->distbits) - 1;
+
+ /* decode literals and length/distances until end-of-block or not enough
+ input data or output space */
+
+ /* align in on 1/2 hold size boundary */
+ while (((unsigned long)(void *)ar.in & (sizeof(ar.hold) / 2 - 1)) != 0) {
+ ar.hold += (unsigned long)*ar.in++ << ar.bits;
+ ar.bits += 8;
+ }
+
+#if defined( __GNUC__ ) && defined( __amd64__ ) && ! defined( __i386 )
+ __asm__ __volatile__ (
+" leaq %0, %%rax\n"
+" movq %%rbp, 8(%%rax)\n" /* save regs rbp and rsp */
+" movq %%rsp, (%%rax)\n"
+" movq %%rax, %%rsp\n" /* make rsp point to &ar */
+" movq 16(%%rsp), %%rsi\n" /* rsi = in */
+" movq 32(%%rsp), %%rdi\n" /* rdi = out */
+" movq 24(%%rsp), %%r9\n" /* r9 = last */
+" movq 48(%%rsp), %%r10\n" /* r10 = end */
+" movq 64(%%rsp), %%rbp\n" /* rbp = lcode */
+" movq 72(%%rsp), %%r11\n" /* r11 = dcode */
+" movq 80(%%rsp), %%rdx\n" /* rdx = hold */
+" movl 88(%%rsp), %%ebx\n" /* ebx = bits */
+" movl 100(%%rsp), %%r12d\n" /* r12d = lmask */
+" movl 104(%%rsp), %%r13d\n" /* r13d = dmask */
+ /* r14d = len */
+ /* r15d = dist */
+" cld\n"
+" cmpq %%rdi, %%r10\n"
+" je .L_one_time\n" /* if only one decode left */
+" cmpq %%rsi, %%r9\n"
+" je .L_one_time\n"
+" jmp .L_do_loop\n"
+
+".L_one_time:\n"
+" movq %%r12, %%r8\n" /* r8 = lmask */
+" cmpb $32, %%bl\n"
+" ja .L_get_length_code_one_time\n"
+
+" lodsl\n" /* eax = *(uint *)in++ */
+" movb %%bl, %%cl\n" /* cl = bits, needs it for shifting */
+" addb $32, %%bl\n" /* bits += 32 */
+" shlq %%cl, %%rax\n"
+" orq %%rax, %%rdx\n" /* hold |= *((uint *)in)++ << bits */
+" jmp .L_get_length_code_one_time\n"
+
+".align 32,0x90\n"
+".L_while_test:\n"
+" cmpq %%rdi, %%r10\n"
+" jbe .L_break_loop\n"
+" cmpq %%rsi, %%r9\n"
+" jbe .L_break_loop\n"
+
+".L_do_loop:\n"
+" movq %%r12, %%r8\n" /* r8 = lmask */
+" cmpb $32, %%bl\n"
+" ja .L_get_length_code\n" /* if (32 < bits) */
+
+" lodsl\n" /* eax = *(uint *)in++ */
+" movb %%bl, %%cl\n" /* cl = bits, needs it for shifting */
+" addb $32, %%bl\n" /* bits += 32 */
+" shlq %%cl, %%rax\n"
+" orq %%rax, %%rdx\n" /* hold |= *((uint *)in)++ << bits */
+
+".L_get_length_code:\n"
+" andq %%rdx, %%r8\n" /* r8 &= hold */
+" movl (%%rbp,%%r8,4), %%eax\n" /* eax = lcode[hold & lmask] */
+
+" movb %%ah, %%cl\n" /* cl = this.bits */
+" subb %%ah, %%bl\n" /* bits -= this.bits */
+" shrq %%cl, %%rdx\n" /* hold >>= this.bits */
+
+" testb %%al, %%al\n"
+" jnz .L_test_for_length_base\n" /* if (op != 0) 45.7% */
+
+" movq %%r12, %%r8\n" /* r8 = lmask */
+" shrl $16, %%eax\n" /* output this.val char */
+" stosb\n"
+
+".L_get_length_code_one_time:\n"
+" andq %%rdx, %%r8\n" /* r8 &= hold */
+" movl (%%rbp,%%r8,4), %%eax\n" /* eax = lcode[hold & lmask] */
+
+".L_dolen:\n"
+" movb %%ah, %%cl\n" /* cl = this.bits */
+" subb %%ah, %%bl\n" /* bits -= this.bits */
+" shrq %%cl, %%rdx\n" /* hold >>= this.bits */
+
+" testb %%al, %%al\n"
+" jnz .L_test_for_length_base\n" /* if (op != 0) 45.7% */
+
+" shrl $16, %%eax\n" /* output this.val char */
+" stosb\n"
+" jmp .L_while_test\n"
+
+".align 32,0x90\n"
+".L_test_for_length_base:\n"
+" movl %%eax, %%r14d\n" /* len = this */
+" shrl $16, %%r14d\n" /* len = this.val */
+" movb %%al, %%cl\n"
+
+" testb $16, %%al\n"
+" jz .L_test_for_second_level_length\n" /* if ((op & 16) == 0) 8% */
+" andb $15, %%cl\n" /* op &= 15 */
+" jz .L_decode_distance\n" /* if (!op) */
+
+".L_add_bits_to_len:\n"
+" subb %%cl, %%bl\n"
+" xorl %%eax, %%eax\n"
+" incl %%eax\n"
+" shll %%cl, %%eax\n"
+" decl %%eax\n"
+" andl %%edx, %%eax\n" /* eax &= hold */
+" shrq %%cl, %%rdx\n"
+" addl %%eax, %%r14d\n" /* len += hold & mask[op] */
+
+".L_decode_distance:\n"
+" movq %%r13, %%r8\n" /* r8 = dmask */
+" cmpb $32, %%bl\n"
+" ja .L_get_distance_code\n" /* if (32 < bits) */
+
+" lodsl\n" /* eax = *(uint *)in++ */
+" movb %%bl, %%cl\n" /* cl = bits, needs it for shifting */
+" addb $32, %%bl\n" /* bits += 32 */
+" shlq %%cl, %%rax\n"
+" orq %%rax, %%rdx\n" /* hold |= *((uint *)in)++ << bits */
+
+".L_get_distance_code:\n"
+" andq %%rdx, %%r8\n" /* r8 &= hold */
+" movl (%%r11,%%r8,4), %%eax\n" /* eax = dcode[hold & dmask] */
+
+".L_dodist:\n"
+" movl %%eax, %%r15d\n" /* dist = this */
+" shrl $16, %%r15d\n" /* dist = this.val */
+" movb %%ah, %%cl\n"
+" subb %%ah, %%bl\n" /* bits -= this.bits */
+" shrq %%cl, %%rdx\n" /* hold >>= this.bits */
+" movb %%al, %%cl\n" /* cl = this.op */
+
+" testb $16, %%al\n" /* if ((op & 16) == 0) */
+" jz .L_test_for_second_level_dist\n"
+" andb $15, %%cl\n" /* op &= 15 */
+" jz .L_check_dist_one\n"
+
+".L_add_bits_to_dist:\n"
+" subb %%cl, %%bl\n"
+" xorl %%eax, %%eax\n"
+" incl %%eax\n"
+" shll %%cl, %%eax\n"
+" decl %%eax\n" /* (1 << op) - 1 */
+" andl %%edx, %%eax\n" /* eax &= hold */
+" shrq %%cl, %%rdx\n"
+" addl %%eax, %%r15d\n" /* dist += hold & ((1 << op) - 1) */
+
+".L_check_window:\n"
+" movq %%rsi, %%r8\n" /* save in so from can use it's reg */
+" movq %%rdi, %%rax\n"
+" subq 40(%%rsp), %%rax\n" /* nbytes = out - beg */
+
+" cmpl %%r15d, %%eax\n"
+" jb .L_clip_window\n" /* if (dist > nbytes) 4.2% */
+
+" movl %%r14d, %%ecx\n" /* ecx = len */
+" movq %%rdi, %%rsi\n"
+" subq %%r15, %%rsi\n" /* from = out - dist */
+
+" sarl %%ecx\n"
+" jnc .L_copy_two\n" /* if len % 2 == 0 */
+
+" rep movsw\n"
+" movb (%%rsi), %%al\n"
+" movb %%al, (%%rdi)\n"
+" incq %%rdi\n"
+
+" movq %%r8, %%rsi\n" /* move in back to %rsi, toss from */
+" jmp .L_while_test\n"
+
+".L_copy_two:\n"
+" rep movsw\n"
+" movq %%r8, %%rsi\n" /* move in back to %rsi, toss from */
+" jmp .L_while_test\n"
+
+".align 32,0x90\n"
+".L_check_dist_one:\n"
+" cmpl $1, %%r15d\n" /* if dist 1, is a memset */
+" jne .L_check_window\n"
+" cmpq %%rdi, 40(%%rsp)\n" /* if out == beg, outside window */
+" je .L_check_window\n"
+
+" movl %%r14d, %%ecx\n" /* ecx = len */
+" movb -1(%%rdi), %%al\n"
+" movb %%al, %%ah\n"
+
+" sarl %%ecx\n"
+" jnc .L_set_two\n"
+" movb %%al, (%%rdi)\n"
+" incq %%rdi\n"
+
+".L_set_two:\n"
+" rep stosw\n"
+" jmp .L_while_test\n"
+
+".align 32,0x90\n"
+".L_test_for_second_level_length:\n"
+" testb $64, %%al\n"
+" jnz .L_test_for_end_of_block\n" /* if ((op & 64) != 0) */
+
+" xorl %%eax, %%eax\n"
+" incl %%eax\n"
+" shll %%cl, %%eax\n"
+" decl %%eax\n"
+" andl %%edx, %%eax\n" /* eax &= hold */
+" addl %%r14d, %%eax\n" /* eax += len */
+" movl (%%rbp,%%rax,4), %%eax\n" /* eax = lcode[val+(hold&mask[op])]*/
+" jmp .L_dolen\n"
+
+".align 32,0x90\n"
+".L_test_for_second_level_dist:\n"
+" testb $64, %%al\n"
+" jnz .L_invalid_distance_code\n" /* if ((op & 64) != 0) */
+
+" xorl %%eax, %%eax\n"
+" incl %%eax\n"
+" shll %%cl, %%eax\n"
+" decl %%eax\n"
+" andl %%edx, %%eax\n" /* eax &= hold */
+" addl %%r15d, %%eax\n" /* eax += dist */
+" movl (%%r11,%%rax,4), %%eax\n" /* eax = dcode[val+(hold&mask[op])]*/
+" jmp .L_dodist\n"
+
+".align 32,0x90\n"
+".L_clip_window:\n"
+" movl %%eax, %%ecx\n" /* ecx = nbytes */
+" movl 92(%%rsp), %%eax\n" /* eax = wsize, prepare for dist cmp */
+" negl %%ecx\n" /* nbytes = -nbytes */
+
+" cmpl %%r15d, %%eax\n"
+" jb .L_invalid_distance_too_far\n" /* if (dist > wsize) */
+
+" addl %%r15d, %%ecx\n" /* nbytes = dist - nbytes */
+" cmpl $0, 96(%%rsp)\n"
+" jne .L_wrap_around_window\n" /* if (write != 0) */
+
+" movq 56(%%rsp), %%rsi\n" /* from = window */
+" subl %%ecx, %%eax\n" /* eax -= nbytes */
+" addq %%rax, %%rsi\n" /* from += wsize - nbytes */
+
+" movl %%r14d, %%eax\n" /* eax = len */
+" cmpl %%ecx, %%r14d\n"
+" jbe .L_do_copy\n" /* if (nbytes >= len) */
+
+" subl %%ecx, %%eax\n" /* eax -= nbytes */
+" rep movsb\n"
+" movq %%rdi, %%rsi\n"
+" subq %%r15, %%rsi\n" /* from = &out[ -dist ] */
+" jmp .L_do_copy\n"
+
+".align 32,0x90\n"
+".L_wrap_around_window:\n"
+" movl 96(%%rsp), %%eax\n" /* eax = write */
+" cmpl %%eax, %%ecx\n"
+" jbe .L_contiguous_in_window\n" /* if (write >= nbytes) */
+
+" movl 92(%%rsp), %%esi\n" /* from = wsize */
+" addq 56(%%rsp), %%rsi\n" /* from += window */
+" addq %%rax, %%rsi\n" /* from += write */
+" subq %%rcx, %%rsi\n" /* from -= nbytes */
+" subl %%eax, %%ecx\n" /* nbytes -= write */
+
+" movl %%r14d, %%eax\n" /* eax = len */
+" cmpl %%ecx, %%eax\n"
+" jbe .L_do_copy\n" /* if (nbytes >= len) */
+
+" subl %%ecx, %%eax\n" /* len -= nbytes */
+" rep movsb\n"
+" movq 56(%%rsp), %%rsi\n" /* from = window */
+" movl 96(%%rsp), %%ecx\n" /* nbytes = write */
+" cmpl %%ecx, %%eax\n"
+" jbe .L_do_copy\n" /* if (nbytes >= len) */
+
+" subl %%ecx, %%eax\n" /* len -= nbytes */
+" rep movsb\n"
+" movq %%rdi, %%rsi\n"
+" subq %%r15, %%rsi\n" /* from = out - dist */
+" jmp .L_do_copy\n"
+
+".align 32,0x90\n"
+".L_contiguous_in_window:\n"
+" movq 56(%%rsp), %%rsi\n" /* rsi = window */
+" addq %%rax, %%rsi\n"
+" subq %%rcx, %%rsi\n" /* from += write - nbytes */
+
+" movl %%r14d, %%eax\n" /* eax = len */
+" cmpl %%ecx, %%eax\n"
+" jbe .L_do_copy\n" /* if (nbytes >= len) */
+
+" subl %%ecx, %%eax\n" /* len -= nbytes */
+" rep movsb\n"
+" movq %%rdi, %%rsi\n"
+" subq %%r15, %%rsi\n" /* from = out - dist */
+" jmp .L_do_copy\n" /* if (nbytes >= len) */
+
+".align 32,0x90\n"
+".L_do_copy:\n"
+" movl %%eax, %%ecx\n" /* ecx = len */
+" rep movsb\n"
+
+" movq %%r8, %%rsi\n" /* move in back to %esi, toss from */
+" jmp .L_while_test\n"
+
+".L_test_for_end_of_block:\n"
+" testb $32, %%al\n"
+" jz .L_invalid_literal_length_code\n"
+" movl $1, 116(%%rsp)\n"
+" jmp .L_break_loop_with_status\n"
+
+".L_invalid_literal_length_code:\n"
+" movl $2, 116(%%rsp)\n"
+" jmp .L_break_loop_with_status\n"
+
+".L_invalid_distance_code:\n"
+" movl $3, 116(%%rsp)\n"
+" jmp .L_break_loop_with_status\n"
+
+".L_invalid_distance_too_far:\n"
+" movl $4, 116(%%rsp)\n"
+" jmp .L_break_loop_with_status\n"
+
+".L_break_loop:\n"
+" movl $0, 116(%%rsp)\n"
+
+".L_break_loop_with_status:\n"
+/* put in, out, bits, and hold back into ar and pop esp */
+" movq %%rsi, 16(%%rsp)\n" /* in */
+" movq %%rdi, 32(%%rsp)\n" /* out */
+" movl %%ebx, 88(%%rsp)\n" /* bits */
+" movq %%rdx, 80(%%rsp)\n" /* hold */
+" movq (%%rsp), %%rax\n" /* restore rbp and rsp */
+" movq 8(%%rsp), %%rbp\n"
+" movq %%rax, %%rsp\n"
+ :
+ : "m" (ar)
+ : "memory", "%rax", "%rbx", "%rcx", "%rdx", "%rsi", "%rdi",
+ "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15"
+ );
+#elif ( defined( __GNUC__ ) || defined( __ICC ) ) && defined( __i386 )
+ __asm__ __volatile__ (
+" leal %0, %%eax\n"
+" movl %%esp, (%%eax)\n" /* save esp, ebp */
+" movl %%ebp, 4(%%eax)\n"
+" movl %%eax, %%esp\n"
+" movl 8(%%esp), %%esi\n" /* esi = in */
+" movl 16(%%esp), %%edi\n" /* edi = out */
+" movl 40(%%esp), %%edx\n" /* edx = hold */
+" movl 44(%%esp), %%ebx\n" /* ebx = bits */
+" movl 32(%%esp), %%ebp\n" /* ebp = lcode */
+
+" cld\n"
+" jmp .L_do_loop\n"
+
+".align 32,0x90\n"
+".L_while_test:\n"
+" cmpl %%edi, 24(%%esp)\n" /* out < end */
+" jbe .L_break_loop\n"
+" cmpl %%esi, 12(%%esp)\n" /* in < last */
+" jbe .L_break_loop\n"
+
+".L_do_loop:\n"
+" cmpb $15, %%bl\n"
+" ja .L_get_length_code\n" /* if (15 < bits) */
+
+" xorl %%eax, %%eax\n"
+" lodsw\n" /* al = *(ushort *)in++ */
+" movb %%bl, %%cl\n" /* cl = bits, needs it for shifting */
+" addb $16, %%bl\n" /* bits += 16 */
+" shll %%cl, %%eax\n"
+" orl %%eax, %%edx\n" /* hold |= *((ushort *)in)++ << bits */
+
+".L_get_length_code:\n"
+" movl 56(%%esp), %%eax\n" /* eax = lmask */
+" andl %%edx, %%eax\n" /* eax &= hold */
+" movl (%%ebp,%%eax,4), %%eax\n" /* eax = lcode[hold & lmask] */
+
+".L_dolen:\n"
+" movb %%ah, %%cl\n" /* cl = this.bits */
+" subb %%ah, %%bl\n" /* bits -= this.bits */
+" shrl %%cl, %%edx\n" /* hold >>= this.bits */
+
+" testb %%al, %%al\n"
+" jnz .L_test_for_length_base\n" /* if (op != 0) 45.7% */
+
+" shrl $16, %%eax\n" /* output this.val char */
+" stosb\n"
+" jmp .L_while_test\n"
+
+".align 32,0x90\n"
+".L_test_for_length_base:\n"
+" movl %%eax, %%ecx\n" /* len = this */
+" shrl $16, %%ecx\n" /* len = this.val */
+" movl %%ecx, 64(%%esp)\n" /* save len */
+" movb %%al, %%cl\n"
+
+" testb $16, %%al\n"
+" jz .L_test_for_second_level_length\n" /* if ((op & 16) == 0) 8% */
+" andb $15, %%cl\n" /* op &= 15 */
+" jz .L_decode_distance\n" /* if (!op) */
+" cmpb %%cl, %%bl\n"
+" jae .L_add_bits_to_len\n" /* if (op <= bits) */
+
+" movb %%cl, %%ch\n" /* stash op in ch, freeing cl */
+" xorl %%eax, %%eax\n"
+" lodsw\n" /* al = *(ushort *)in++ */
+" movb %%bl, %%cl\n" /* cl = bits, needs it for shifting */
+" addb $16, %%bl\n" /* bits += 16 */
+" shll %%cl, %%eax\n"
+" orl %%eax, %%edx\n" /* hold |= *((ushort *)in)++ << bits */
+" movb %%ch, %%cl\n" /* move op back to ecx */
+
+".L_add_bits_to_len:\n"
+" subb %%cl, %%bl\n"
+" xorl %%eax, %%eax\n"
+" incl %%eax\n"
+" shll %%cl, %%eax\n"
+" decl %%eax\n"
+" andl %%edx, %%eax\n" /* eax &= hold */
+" shrl %%cl, %%edx\n"
+" addl %%eax, 64(%%esp)\n" /* len += hold & mask[op] */
+
+".L_decode_distance:\n"
+" cmpb $15, %%bl\n"
+" ja .L_get_distance_code\n" /* if (15 < bits) */
+
+" xorl %%eax, %%eax\n"
+" lodsw\n" /* al = *(ushort *)in++ */
+" movb %%bl, %%cl\n" /* cl = bits, needs it for shifting */
+" addb $16, %%bl\n" /* bits += 16 */
+" shll %%cl, %%eax\n"
+" orl %%eax, %%edx\n" /* hold |= *((ushort *)in)++ << bits */
+
+".L_get_distance_code:\n"
+" movl 60(%%esp), %%eax\n" /* eax = dmask */
+" movl 36(%%esp), %%ecx\n" /* ecx = dcode */
+" andl %%edx, %%eax\n" /* eax &= hold */
+" movl (%%ecx,%%eax,4), %%eax\n"/* eax = dcode[hold & dmask] */
+
+".L_dodist:\n"
+" movl %%eax, %%ebp\n" /* dist = this */
+" shrl $16, %%ebp\n" /* dist = this.val */
+" movb %%ah, %%cl\n"
+" subb %%ah, %%bl\n" /* bits -= this.bits */
+" shrl %%cl, %%edx\n" /* hold >>= this.bits */
+" movb %%al, %%cl\n" /* cl = this.op */
+
+" testb $16, %%al\n" /* if ((op & 16) == 0) */
+" jz .L_test_for_second_level_dist\n"
+" andb $15, %%cl\n" /* op &= 15 */
+" jz .L_check_dist_one\n"
+" cmpb %%cl, %%bl\n"
+" jae .L_add_bits_to_dist\n" /* if (op <= bits) 97.6% */
+
+" movb %%cl, %%ch\n" /* stash op in ch, freeing cl */
+" xorl %%eax, %%eax\n"
+" lodsw\n" /* al = *(ushort *)in++ */
+" movb %%bl, %%cl\n" /* cl = bits, needs it for shifting */
+" addb $16, %%bl\n" /* bits += 16 */
+" shll %%cl, %%eax\n"
+" orl %%eax, %%edx\n" /* hold |= *((ushort *)in)++ << bits */
+" movb %%ch, %%cl\n" /* move op back to ecx */
+
+".L_add_bits_to_dist:\n"
+" subb %%cl, %%bl\n"
+" xorl %%eax, %%eax\n"
+" incl %%eax\n"
+" shll %%cl, %%eax\n"
+" decl %%eax\n" /* (1 << op) - 1 */
+" andl %%edx, %%eax\n" /* eax &= hold */
+" shrl %%cl, %%edx\n"
+" addl %%eax, %%ebp\n" /* dist += hold & ((1 << op) - 1) */
+
+".L_check_window:\n"
+" movl %%esi, 8(%%esp)\n" /* save in so from can use it's reg */
+" movl %%edi, %%eax\n"
+" subl 20(%%esp), %%eax\n" /* nbytes = out - beg */
+
+" cmpl %%ebp, %%eax\n"
+" jb .L_clip_window\n" /* if (dist > nbytes) 4.2% */
+
+" movl 64(%%esp), %%ecx\n" /* ecx = len */
+" movl %%edi, %%esi\n"
+" subl %%ebp, %%esi\n" /* from = out - dist */
+
+" sarl %%ecx\n"
+" jnc .L_copy_two\n" /* if len % 2 == 0 */
+
+" rep movsw\n"
+" movb (%%esi), %%al\n"
+" movb %%al, (%%edi)\n"
+" incl %%edi\n"
+
+" movl 8(%%esp), %%esi\n" /* move in back to %esi, toss from */
+" movl 32(%%esp), %%ebp\n" /* ebp = lcode */
+" jmp .L_while_test\n"
+
+".L_copy_two:\n"
+" rep movsw\n"
+" movl 8(%%esp), %%esi\n" /* move in back to %esi, toss from */
+" movl 32(%%esp), %%ebp\n" /* ebp = lcode */
+" jmp .L_while_test\n"
+
+".align 32,0x90\n"
+".L_check_dist_one:\n"
+" cmpl $1, %%ebp\n" /* if dist 1, is a memset */
+" jne .L_check_window\n"
+" cmpl %%edi, 20(%%esp)\n"
+" je .L_check_window\n" /* out == beg, if outside window */
+
+" movl 64(%%esp), %%ecx\n" /* ecx = len */
+" movb -1(%%edi), %%al\n"
+" movb %%al, %%ah\n"
+
+" sarl %%ecx\n"
+" jnc .L_set_two\n"
+" movb %%al, (%%edi)\n"
+" incl %%edi\n"
+
+".L_set_two:\n"
+" rep stosw\n"
+" movl 32(%%esp), %%ebp\n" /* ebp = lcode */
+" jmp .L_while_test\n"
+
+".align 32,0x90\n"
+".L_test_for_second_level_length:\n"
+" testb $64, %%al\n"
+" jnz .L_test_for_end_of_block\n" /* if ((op & 64) != 0) */
+
+" xorl %%eax, %%eax\n"
+" incl %%eax\n"
+" shll %%cl, %%eax\n"
+" decl %%eax\n"
+" andl %%edx, %%eax\n" /* eax &= hold */
+" addl 64(%%esp), %%eax\n" /* eax += len */
+" movl (%%ebp,%%eax,4), %%eax\n" /* eax = lcode[val+(hold&mask[op])]*/
+" jmp .L_dolen\n"
+
+".align 32,0x90\n"
+".L_test_for_second_level_dist:\n"
+" testb $64, %%al\n"
+" jnz .L_invalid_distance_code\n" /* if ((op & 64) != 0) */
+
+" xorl %%eax, %%eax\n"
+" incl %%eax\n"
+" shll %%cl, %%eax\n"
+" decl %%eax\n"
+" andl %%edx, %%eax\n" /* eax &= hold */
+" addl %%ebp, %%eax\n" /* eax += dist */
+" movl 36(%%esp), %%ecx\n" /* ecx = dcode */
+" movl (%%ecx,%%eax,4), %%eax\n" /* eax = dcode[val+(hold&mask[op])]*/
+" jmp .L_dodist\n"
+
+".align 32,0x90\n"
+".L_clip_window:\n"
+" movl %%eax, %%ecx\n"
+" movl 48(%%esp), %%eax\n" /* eax = wsize */
+" negl %%ecx\n" /* nbytes = -nbytes */
+" movl 28(%%esp), %%esi\n" /* from = window */
+
+" cmpl %%ebp, %%eax\n"
+" jb .L_invalid_distance_too_far\n" /* if (dist > wsize) */
+
+" addl %%ebp, %%ecx\n" /* nbytes = dist - nbytes */
+" cmpl $0, 52(%%esp)\n"
+" jne .L_wrap_around_window\n" /* if (write != 0) */
+
+" subl %%ecx, %%eax\n"
+" addl %%eax, %%esi\n" /* from += wsize - nbytes */
+
+" movl 64(%%esp), %%eax\n" /* eax = len */
+" cmpl %%ecx, %%eax\n"
+" jbe .L_do_copy\n" /* if (nbytes >= len) */
+
+" subl %%ecx, %%eax\n" /* len -= nbytes */
+" rep movsb\n"
+" movl %%edi, %%esi\n"
+" subl %%ebp, %%esi\n" /* from = out - dist */
+" jmp .L_do_copy\n"
+
+".align 32,0x90\n"
+".L_wrap_around_window:\n"
+" movl 52(%%esp), %%eax\n" /* eax = write */
+" cmpl %%eax, %%ecx\n"
+" jbe .L_contiguous_in_window\n" /* if (write >= nbytes) */
+
+" addl 48(%%esp), %%esi\n" /* from += wsize */
+" addl %%eax, %%esi\n" /* from += write */
+" subl %%ecx, %%esi\n" /* from -= nbytes */
+" subl %%eax, %%ecx\n" /* nbytes -= write */
+
+" movl 64(%%esp), %%eax\n" /* eax = len */
+" cmpl %%ecx, %%eax\n"
+" jbe .L_do_copy\n" /* if (nbytes >= len) */
+
+" subl %%ecx, %%eax\n" /* len -= nbytes */
+" rep movsb\n"
+" movl 28(%%esp), %%esi\n" /* from = window */
+" movl 52(%%esp), %%ecx\n" /* nbytes = write */
+" cmpl %%ecx, %%eax\n"
+" jbe .L_do_copy\n" /* if (nbytes >= len) */
+
+" subl %%ecx, %%eax\n" /* len -= nbytes */
+" rep movsb\n"
+" movl %%edi, %%esi\n"
+" subl %%ebp, %%esi\n" /* from = out - dist */
+" jmp .L_do_copy\n"
+
+".align 32,0x90\n"
+".L_contiguous_in_window:\n"
+" addl %%eax, %%esi\n"
+" subl %%ecx, %%esi\n" /* from += write - nbytes */
+
+" movl 64(%%esp), %%eax\n" /* eax = len */
+" cmpl %%ecx, %%eax\n"
+" jbe .L_do_copy\n" /* if (nbytes >= len) */
+
+" subl %%ecx, %%eax\n" /* len -= nbytes */
+" rep movsb\n"
+" movl %%edi, %%esi\n"
+" subl %%ebp, %%esi\n" /* from = out - dist */
+" jmp .L_do_copy\n" /* if (nbytes >= len) */
+
+".align 32,0x90\n"
+".L_do_copy:\n"
+" movl %%eax, %%ecx\n"
+" rep movsb\n"
+
+" movl 8(%%esp), %%esi\n" /* move in back to %esi, toss from */
+" movl 32(%%esp), %%ebp\n" /* ebp = lcode */
+" jmp .L_while_test\n"
+
+".L_test_for_end_of_block:\n"
+" testb $32, %%al\n"
+" jz .L_invalid_literal_length_code\n"
+" movl $1, 72(%%esp)\n"
+" jmp .L_break_loop_with_status\n"
+
+".L_invalid_literal_length_code:\n"
+" movl $2, 72(%%esp)\n"
+" jmp .L_break_loop_with_status\n"
+
+".L_invalid_distance_code:\n"
+" movl $3, 72(%%esp)\n"
+" jmp .L_break_loop_with_status\n"
+
+".L_invalid_distance_too_far:\n"
+" movl 8(%%esp), %%esi\n"
+" movl $4, 72(%%esp)\n"
+" jmp .L_break_loop_with_status\n"
+
+".L_break_loop:\n"
+" movl $0, 72(%%esp)\n"
+
+".L_break_loop_with_status:\n"
+/* put in, out, bits, and hold back into ar and pop esp */
+" movl %%esi, 8(%%esp)\n" /* save in */
+" movl %%edi, 16(%%esp)\n" /* save out */
+" movl %%ebx, 44(%%esp)\n" /* save bits */
+" movl %%edx, 40(%%esp)\n" /* save hold */
+" movl 4(%%esp), %%ebp\n" /* restore esp, ebp */
+" movl (%%esp), %%esp\n"
+ :
+ : "m" (ar)
+ : "memory", "%eax", "%ebx", "%ecx", "%edx", "%esi", "%edi"
+ );
+#elif defined( _MSC_VER ) && ! defined( _M_AMD64 )
+ __asm {
+ lea eax, ar
+ mov [eax], esp /* save esp, ebp */
+ mov [eax+4], ebp
+ mov esp, eax
+ mov esi, [esp+8] /* esi = in */
+ mov edi, [esp+16] /* edi = out */
+ mov edx, [esp+40] /* edx = hold */
+ mov ebx, [esp+44] /* ebx = bits */
+ mov ebp, [esp+32] /* ebp = lcode */
+
+ cld
+ jmp L_do_loop
+
+ALIGN 4
+L_while_test:
+ cmp [esp+24], edi
+ jbe L_break_loop
+ cmp [esp+12], esi
+ jbe L_break_loop
+
+L_do_loop:
+ cmp bl, 15
+ ja L_get_length_code /* if (15 < bits) */
+
+ xor eax, eax
+ lodsw /* al = *(ushort *)in++ */
+ mov cl, bl /* cl = bits, needs it for shifting */
+ add bl, 16 /* bits += 16 */
+ shl eax, cl
+ or edx, eax /* hold |= *((ushort *)in)++ << bits */
+
+L_get_length_code:
+ mov eax, [esp+56] /* eax = lmask */
+ and eax, edx /* eax &= hold */
+ mov eax, [ebp+eax*4] /* eax = lcode[hold & lmask] */
+
+L_dolen:
+ mov cl, ah /* cl = this.bits */
+ sub bl, ah /* bits -= this.bits */
+ shr edx, cl /* hold >>= this.bits */
+
+ test al, al
+ jnz L_test_for_length_base /* if (op != 0) 45.7% */
+
+ shr eax, 16 /* output this.val char */
+ stosb
+ jmp L_while_test
+
+ALIGN 4
+L_test_for_length_base:
+ mov ecx, eax /* len = this */
+ shr ecx, 16 /* len = this.val */
+ mov [esp+64], ecx /* save len */
+ mov cl, al
+
+ test al, 16
+ jz L_test_for_second_level_length /* if ((op & 16) == 0) 8% */
+ and cl, 15 /* op &= 15 */
+ jz L_decode_distance /* if (!op) */
+ cmp bl, cl
+ jae L_add_bits_to_len /* if (op <= bits) */
+
+ mov ch, cl /* stash op in ch, freeing cl */
+ xor eax, eax
+ lodsw /* al = *(ushort *)in++ */
+ mov cl, bl /* cl = bits, needs it for shifting */
+ add bl, 16 /* bits += 16 */
+ shl eax, cl
+ or edx, eax /* hold |= *((ushort *)in)++ << bits */
+ mov cl, ch /* move op back to ecx */
+
+L_add_bits_to_len:
+ sub bl, cl
+ xor eax, eax
+ inc eax
+ shl eax, cl
+ dec eax
+ and eax, edx /* eax &= hold */
+ shr edx, cl
+ add [esp+64], eax /* len += hold & mask[op] */
+
+L_decode_distance:
+ cmp bl, 15
+ ja L_get_distance_code /* if (15 < bits) */
+
+ xor eax, eax
+ lodsw /* al = *(ushort *)in++ */
+ mov cl, bl /* cl = bits, needs it for shifting */
+ add bl, 16 /* bits += 16 */
+ shl eax, cl
+ or edx, eax /* hold |= *((ushort *)in)++ << bits */
+
+L_get_distance_code:
+ mov eax, [esp+60] /* eax = dmask */
+ mov ecx, [esp+36] /* ecx = dcode */
+ and eax, edx /* eax &= hold */
+ mov eax, [ecx+eax*4]/* eax = dcode[hold & dmask] */
+
+L_dodist:
+ mov ebp, eax /* dist = this */
+ shr ebp, 16 /* dist = this.val */
+ mov cl, ah
+ sub bl, ah /* bits -= this.bits */
+ shr edx, cl /* hold >>= this.bits */
+ mov cl, al /* cl = this.op */
+
+ test al, 16 /* if ((op & 16) == 0) */
+ jz L_test_for_second_level_dist
+ and cl, 15 /* op &= 15 */
+ jz L_check_dist_one
+ cmp bl, cl
+ jae L_add_bits_to_dist /* if (op <= bits) 97.6% */
+
+ mov ch, cl /* stash op in ch, freeing cl */
+ xor eax, eax
+ lodsw /* al = *(ushort *)in++ */
+ mov cl, bl /* cl = bits, needs it for shifting */
+ add bl, 16 /* bits += 16 */
+ shl eax, cl
+ or edx, eax /* hold |= *((ushort *)in)++ << bits */
+ mov cl, ch /* move op back to ecx */
+
+L_add_bits_to_dist:
+ sub bl, cl
+ xor eax, eax
+ inc eax
+ shl eax, cl
+ dec eax /* (1 << op) - 1 */
+ and eax, edx /* eax &= hold */
+ shr edx, cl
+ add ebp, eax /* dist += hold & ((1 << op) - 1) */
+
+L_check_window:
+ mov [esp+8], esi /* save in so from can use it's reg */
+ mov eax, edi
+ sub eax, [esp+20] /* nbytes = out - beg */
+
+ cmp eax, ebp
+ jb L_clip_window /* if (dist > nbytes) 4.2% */
+
+ mov ecx, [esp+64] /* ecx = len */
+ mov esi, edi
+ sub esi, ebp /* from = out - dist */
+
+ sar ecx, 1
+ jnc L_copy_two
+
+ rep movsw
+ mov al, [esi]
+ mov [edi], al
+ inc edi
+
+ mov esi, [esp+8] /* move in back to %esi, toss from */
+ mov ebp, [esp+32] /* ebp = lcode */
+ jmp L_while_test
+
+L_copy_two:
+ rep movsw
+ mov esi, [esp+8] /* move in back to %esi, toss from */
+ mov ebp, [esp+32] /* ebp = lcode */
+ jmp L_while_test
+
+ALIGN 4
+L_check_dist_one:
+ cmp ebp, 1 /* if dist 1, is a memset */
+ jne L_check_window
+ cmp [esp+20], edi
+ je L_check_window /* out == beg, if outside window */
+
+ mov ecx, [esp+64] /* ecx = len */
+ mov al, [edi-1]
+ mov ah, al
+
+ sar ecx, 1
+ jnc L_set_two
+ mov [edi], al /* memset out with from[-1] */
+ inc edi
+
+L_set_two:
+ rep stosw
+ mov ebp, [esp+32] /* ebp = lcode */
+ jmp L_while_test
+
+ALIGN 4
+L_test_for_second_level_length:
+ test al, 64
+ jnz L_test_for_end_of_block /* if ((op & 64) != 0) */
+
+ xor eax, eax
+ inc eax
+ shl eax, cl
+ dec eax
+ and eax, edx /* eax &= hold */
+ add eax, [esp+64] /* eax += len */
+ mov eax, [ebp+eax*4] /* eax = lcode[val+(hold&mask[op])]*/
+ jmp L_dolen
+
+ALIGN 4
+L_test_for_second_level_dist:
+ test al, 64
+ jnz L_invalid_distance_code /* if ((op & 64) != 0) */
+
+ xor eax, eax
+ inc eax
+ shl eax, cl
+ dec eax
+ and eax, edx /* eax &= hold */
+ add eax, ebp /* eax += dist */
+ mov ecx, [esp+36] /* ecx = dcode */
+ mov eax, [ecx+eax*4] /* eax = dcode[val+(hold&mask[op])]*/
+ jmp L_dodist
+
+ALIGN 4
+L_clip_window:
+ mov ecx, eax
+ mov eax, [esp+48] /* eax = wsize */
+ neg ecx /* nbytes = -nbytes */
+ mov esi, [esp+28] /* from = window */
+
+ cmp eax, ebp
+ jb L_invalid_distance_too_far /* if (dist > wsize) */
+
+ add ecx, ebp /* nbytes = dist - nbytes */
+ cmp dword ptr [esp+52], 0
+ jne L_wrap_around_window /* if (write != 0) */
+
+ sub eax, ecx
+ add esi, eax /* from += wsize - nbytes */
+
+ mov eax, [esp+64] /* eax = len */
+ cmp eax, ecx
+ jbe L_do_copy /* if (nbytes >= len) */
+
+ sub eax, ecx /* len -= nbytes */
+ rep movsb
+ mov esi, edi
+ sub esi, ebp /* from = out - dist */
+ jmp L_do_copy
+
+ALIGN 4
+L_wrap_around_window:
+ mov eax, [esp+52] /* eax = write */
+ cmp ecx, eax
+ jbe L_contiguous_in_window /* if (write >= nbytes) */
+
+ add esi, [esp+48] /* from += wsize */
+ add esi, eax /* from += write */
+ sub esi, ecx /* from -= nbytes */
+ sub ecx, eax /* nbytes -= write */
+
+ mov eax, [esp+64] /* eax = len */
+ cmp eax, ecx
+ jbe L_do_copy /* if (nbytes >= len) */
+
+ sub eax, ecx /* len -= nbytes */
+ rep movsb
+ mov esi, [esp+28] /* from = window */
+ mov ecx, [esp+52] /* nbytes = write */
+ cmp eax, ecx
+ jbe L_do_copy /* if (nbytes >= len) */
+
+ sub eax, ecx /* len -= nbytes */
+ rep movsb
+ mov esi, edi
+ sub esi, ebp /* from = out - dist */
+ jmp L_do_copy
+
+ALIGN 4
+L_contiguous_in_window:
+ add esi, eax
+ sub esi, ecx /* from += write - nbytes */
+
+ mov eax, [esp+64] /* eax = len */
+ cmp eax, ecx
+ jbe L_do_copy /* if (nbytes >= len) */
+
+ sub eax, ecx /* len -= nbytes */
+ rep movsb
+ mov esi, edi
+ sub esi, ebp /* from = out - dist */
+ jmp L_do_copy
+
+ALIGN 4
+L_do_copy:
+ mov ecx, eax
+ rep movsb
+
+ mov esi, [esp+8] /* move in back to %esi, toss from */
+ mov ebp, [esp+32] /* ebp = lcode */
+ jmp L_while_test
+
+L_test_for_end_of_block:
+ test al, 32
+ jz L_invalid_literal_length_code
+ mov dword ptr [esp+72], 1
+ jmp L_break_loop_with_status
+
+L_invalid_literal_length_code:
+ mov dword ptr [esp+72], 2
+ jmp L_break_loop_with_status
+
+L_invalid_distance_code:
+ mov dword ptr [esp+72], 3
+ jmp L_break_loop_with_status
+
+L_invalid_distance_too_far:
+ mov esi, [esp+4]
+ mov dword ptr [esp+72], 4
+ jmp L_break_loop_with_status
+
+L_break_loop:
+ mov dword ptr [esp+72], 0
+
+L_break_loop_with_status:
+/* put in, out, bits, and hold back into ar and pop esp */
+ mov [esp+8], esi /* save in */
+ mov [esp+16], edi /* save out */
+ mov [esp+44], ebx /* save bits */
+ mov [esp+40], edx /* save hold */
+ mov ebp, [esp+4] /* restore esp, ebp */
+ mov esp, [esp]
+ }
+#else
+#error "x86 architecture not defined"
+#endif
+
+ if (ar.status > 1) {
+ if (ar.status == 2)
+ strm->msg = "invalid literal/length code";
+ else if (ar.status == 3)
+ strm->msg = "invalid distance code";
+ else
+ strm->msg = "invalid distance too far back";
+ state->mode = BAD;
+ }
+ else if ( ar.status == 1 ) {
+ state->mode = TYPE;
+ }
+
+ /* return unused bytes (on entry, bits < 8, so in won't go too far back) */
+ ar.len = ar.bits >> 3;
+ ar.in -= ar.len;
+ ar.bits -= ar.len << 3;
+ ar.hold &= (1U << ar.bits) - 1;
+
+ /* update state and return */
+ strm->next_in = ar.in;
+ strm->next_out = ar.out;
+ strm->avail_in = (unsigned)(ar.in < ar.last ?
+ PAD_AVAIL_IN + (ar.last - ar.in) :
+ PAD_AVAIL_IN - (ar.in - ar.last));
+ strm->avail_out = (unsigned)(ar.out < ar.end ?
+ PAD_AVAIL_OUT + (ar.end - ar.out) :
+ PAD_AVAIL_OUT - (ar.out - ar.end));
+ state->hold = ar.hold;
+ state->bits = ar.bits;
+ return;
+}
+
ADDED compat/zlib/contrib/inflate86/inffast.S
Index: compat/zlib/contrib/inflate86/inffast.S
==================================================================
--- compat/zlib/contrib/inflate86/inffast.S
+++ compat/zlib/contrib/inflate86/inffast.S
@@ -0,0 +1,1368 @@
+/*
+ * inffast.S is a hand tuned assembler version of:
+ *
+ * inffast.c -- fast decoding
+ * Copyright (C) 1995-2003 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ *
+ * Copyright (C) 2003 Chris Anderson
+ * Please use the copyright conditions above.
+ *
+ * This version (Jan-23-2003) of inflate_fast was coded and tested under
+ * GNU/Linux on a pentium 3, using the gcc-3.2 compiler distribution. On that
+ * machine, I found that gzip style archives decompressed about 20% faster than
+ * the gcc-3.2 -O3 -fomit-frame-pointer compiled version. Your results will
+ * depend on how large of a buffer is used for z_stream.next_in & next_out
+ * (8K-32K worked best for my 256K cpu cache) and how much overhead there is in
+ * stream processing I/O and crc32/addler32. In my case, this routine used
+ * 70% of the cpu time and crc32 used 20%.
+ *
+ * I am confident that this version will work in the general case, but I have
+ * not tested a wide variety of datasets or a wide variety of platforms.
+ *
+ * Jan-24-2003 -- Added -DUSE_MMX define for slightly faster inflating.
+ * It should be a runtime flag instead of compile time flag...
+ *
+ * Jan-26-2003 -- Added runtime check for MMX support with cpuid instruction.
+ * With -DUSE_MMX, only MMX code is compiled. With -DNO_MMX, only non-MMX code
+ * is compiled. Without either option, runtime detection is enabled. Runtime
+ * detection should work on all modern cpus and the recomended algorithm (flip
+ * ID bit on eflags and then use the cpuid instruction) is used in many
+ * multimedia applications. Tested under win2k with gcc-2.95 and gas-2.12
+ * distributed with cygwin3. Compiling with gcc-2.95 -c inffast.S -o
+ * inffast.obj generates a COFF object which can then be linked with MSVC++
+ * compiled code. Tested under FreeBSD 4.7 with gcc-2.95.
+ *
+ * Jan-28-2003 -- Tested Athlon XP... MMX mode is slower than no MMX (and
+ * slower than compiler generated code). Adjusted cpuid check to use the MMX
+ * code only for Pentiums < P4 until I have more data on the P4. Speed
+ * improvment is only about 15% on the Athlon when compared with code generated
+ * with MSVC++. Not sure yet, but I think the P4 will also be slower using the
+ * MMX mode because many of it's x86 ALU instructions execute in .5 cycles and
+ * have less latency than MMX ops. Added code to buffer the last 11 bytes of
+ * the input stream since the MMX code grabs bits in chunks of 32, which
+ * differs from the inffast.c algorithm. I don't think there would have been
+ * read overruns where a page boundary was crossed (a segfault), but there
+ * could have been overruns when next_in ends on unaligned memory (unintialized
+ * memory read).
+ *
+ * Mar-13-2003 -- P4 MMX is slightly slower than P4 NO_MMX. I created a C
+ * version of the non-MMX code so that it doesn't depend on zstrm and zstate
+ * structure offsets which are hard coded in this file. This was last tested
+ * with zlib-1.2.0 which is currently in beta testing, newer versions of this
+ * and inffas86.c can be found at http://www.eetbeetee.com/zlib/ and
+ * http://www.charm.net/~christop/zlib/
+ */
+
+
+/*
+ * if you have underscore linking problems (_inflate_fast undefined), try
+ * using -DGAS_COFF
+ */
+#if ! defined( GAS_COFF ) && ! defined( GAS_ELF )
+
+#if defined( WIN32 ) || defined( __CYGWIN__ )
+#define GAS_COFF /* windows object format */
+#else
+#define GAS_ELF
+#endif
+
+#endif /* ! GAS_COFF && ! GAS_ELF */
+
+
+#if defined( GAS_COFF )
+
+/* coff externals have underscores */
+#define inflate_fast _inflate_fast
+#define inflate_fast_use_mmx _inflate_fast_use_mmx
+
+#endif /* GAS_COFF */
+
+
+.file "inffast.S"
+
+.globl inflate_fast
+
+.text
+.align 4,0
+.L_invalid_literal_length_code_msg:
+.string "invalid literal/length code"
+
+.align 4,0
+.L_invalid_distance_code_msg:
+.string "invalid distance code"
+
+.align 4,0
+.L_invalid_distance_too_far_msg:
+.string "invalid distance too far back"
+
+#if ! defined( NO_MMX )
+.align 4,0
+.L_mask: /* mask[N] = ( 1 << N ) - 1 */
+.long 0
+.long 1
+.long 3
+.long 7
+.long 15
+.long 31
+.long 63
+.long 127
+.long 255
+.long 511
+.long 1023
+.long 2047
+.long 4095
+.long 8191
+.long 16383
+.long 32767
+.long 65535
+.long 131071
+.long 262143
+.long 524287
+.long 1048575
+.long 2097151
+.long 4194303
+.long 8388607
+.long 16777215
+.long 33554431
+.long 67108863
+.long 134217727
+.long 268435455
+.long 536870911
+.long 1073741823
+.long 2147483647
+.long 4294967295
+#endif /* NO_MMX */
+
+.text
+
+/*
+ * struct z_stream offsets, in zlib.h
+ */
+#define next_in_strm 0 /* strm->next_in */
+#define avail_in_strm 4 /* strm->avail_in */
+#define next_out_strm 12 /* strm->next_out */
+#define avail_out_strm 16 /* strm->avail_out */
+#define msg_strm 24 /* strm->msg */
+#define state_strm 28 /* strm->state */
+
+/*
+ * struct inflate_state offsets, in inflate.h
+ */
+#define mode_state 0 /* state->mode */
+#define wsize_state 32 /* state->wsize */
+#define write_state 40 /* state->write */
+#define window_state 44 /* state->window */
+#define hold_state 48 /* state->hold */
+#define bits_state 52 /* state->bits */
+#define lencode_state 68 /* state->lencode */
+#define distcode_state 72 /* state->distcode */
+#define lenbits_state 76 /* state->lenbits */
+#define distbits_state 80 /* state->distbits */
+
+/*
+ * inflate_fast's activation record
+ */
+#define local_var_size 64 /* how much local space for vars */
+#define strm_sp 88 /* first arg: z_stream * (local_var_size + 24) */
+#define start_sp 92 /* second arg: unsigned int (local_var_size + 28) */
+
+/*
+ * offsets for local vars on stack
+ */
+#define out 60 /* unsigned char* */
+#define window 56 /* unsigned char* */
+#define wsize 52 /* unsigned int */
+#define write 48 /* unsigned int */
+#define in 44 /* unsigned char* */
+#define beg 40 /* unsigned char* */
+#define buf 28 /* char[ 12 ] */
+#define len 24 /* unsigned int */
+#define last 20 /* unsigned char* */
+#define end 16 /* unsigned char* */
+#define dcode 12 /* code* */
+#define lcode 8 /* code* */
+#define dmask 4 /* unsigned int */
+#define lmask 0 /* unsigned int */
+
+/*
+ * typedef enum inflate_mode consts, in inflate.h
+ */
+#define INFLATE_MODE_TYPE 11 /* state->mode flags enum-ed in inflate.h */
+#define INFLATE_MODE_BAD 26
+
+
+#if ! defined( USE_MMX ) && ! defined( NO_MMX )
+
+#define RUN_TIME_MMX
+
+#define CHECK_MMX 1
+#define DO_USE_MMX 2
+#define DONT_USE_MMX 3
+
+.globl inflate_fast_use_mmx
+
+.data
+
+.align 4,0
+inflate_fast_use_mmx: /* integer flag for run time control 1=check,2=mmx,3=no */
+.long CHECK_MMX
+
+#if defined( GAS_ELF )
+/* elf info */
+.type inflate_fast_use_mmx,@object
+.size inflate_fast_use_mmx,4
+#endif
+
+#endif /* RUN_TIME_MMX */
+
+#if defined( GAS_COFF )
+/* coff info: scl 2 = extern, type 32 = function */
+.def inflate_fast; .scl 2; .type 32; .endef
+#endif
+
+.text
+
+.align 32,0x90
+inflate_fast:
+ pushl %edi
+ pushl %esi
+ pushl %ebp
+ pushl %ebx
+ pushf /* save eflags (strm_sp, state_sp assumes this is 32 bits) */
+ subl $local_var_size, %esp
+ cld
+
+#define strm_r %esi
+#define state_r %edi
+
+ movl strm_sp(%esp), strm_r
+ movl state_strm(strm_r), state_r
+
+ /* in = strm->next_in;
+ * out = strm->next_out;
+ * last = in + strm->avail_in - 11;
+ * beg = out - (start - strm->avail_out);
+ * end = out + (strm->avail_out - 257);
+ */
+ movl avail_in_strm(strm_r), %edx
+ movl next_in_strm(strm_r), %eax
+
+ addl %eax, %edx /* avail_in += next_in */
+ subl $11, %edx /* avail_in -= 11 */
+
+ movl %eax, in(%esp)
+ movl %edx, last(%esp)
+
+ movl start_sp(%esp), %ebp
+ movl avail_out_strm(strm_r), %ecx
+ movl next_out_strm(strm_r), %ebx
+
+ subl %ecx, %ebp /* start -= avail_out */
+ negl %ebp /* start = -start */
+ addl %ebx, %ebp /* start += next_out */
+
+ subl $257, %ecx /* avail_out -= 257 */
+ addl %ebx, %ecx /* avail_out += out */
+
+ movl %ebx, out(%esp)
+ movl %ebp, beg(%esp)
+ movl %ecx, end(%esp)
+
+ /* wsize = state->wsize;
+ * write = state->write;
+ * window = state->window;
+ * hold = state->hold;
+ * bits = state->bits;
+ * lcode = state->lencode;
+ * dcode = state->distcode;
+ * lmask = ( 1 << state->lenbits ) - 1;
+ * dmask = ( 1 << state->distbits ) - 1;
+ */
+
+ movl lencode_state(state_r), %eax
+ movl distcode_state(state_r), %ecx
+
+ movl %eax, lcode(%esp)
+ movl %ecx, dcode(%esp)
+
+ movl $1, %eax
+ movl lenbits_state(state_r), %ecx
+ shll %cl, %eax
+ decl %eax
+ movl %eax, lmask(%esp)
+
+ movl $1, %eax
+ movl distbits_state(state_r), %ecx
+ shll %cl, %eax
+ decl %eax
+ movl %eax, dmask(%esp)
+
+ movl wsize_state(state_r), %eax
+ movl write_state(state_r), %ecx
+ movl window_state(state_r), %edx
+
+ movl %eax, wsize(%esp)
+ movl %ecx, write(%esp)
+ movl %edx, window(%esp)
+
+ movl hold_state(state_r), %ebp
+ movl bits_state(state_r), %ebx
+
+#undef strm_r
+#undef state_r
+
+#define in_r %esi
+#define from_r %esi
+#define out_r %edi
+
+ movl in(%esp), in_r
+ movl last(%esp), %ecx
+ cmpl in_r, %ecx
+ ja .L_align_long /* if in < last */
+
+ addl $11, %ecx /* ecx = &in[ avail_in ] */
+ subl in_r, %ecx /* ecx = avail_in */
+ movl $12, %eax
+ subl %ecx, %eax /* eax = 12 - avail_in */
+ leal buf(%esp), %edi
+ rep movsb /* memcpy( buf, in, avail_in ) */
+ movl %eax, %ecx
+ xorl %eax, %eax
+ rep stosb /* memset( &buf[ avail_in ], 0, 12 - avail_in ) */
+ leal buf(%esp), in_r /* in = buf */
+ movl in_r, last(%esp) /* last = in, do just one iteration */
+ jmp .L_is_aligned
+
+ /* align in_r on long boundary */
+.L_align_long:
+ testl $3, in_r
+ jz .L_is_aligned
+ xorl %eax, %eax
+ movb (in_r), %al
+ incl in_r
+ movl %ebx, %ecx
+ addl $8, %ebx
+ shll %cl, %eax
+ orl %eax, %ebp
+ jmp .L_align_long
+
+.L_is_aligned:
+ movl out(%esp), out_r
+
+#if defined( NO_MMX )
+ jmp .L_do_loop
+#endif
+
+#if defined( USE_MMX )
+ jmp .L_init_mmx
+#endif
+
+/*** Runtime MMX check ***/
+
+#if defined( RUN_TIME_MMX )
+.L_check_mmx:
+ cmpl $DO_USE_MMX, inflate_fast_use_mmx
+ je .L_init_mmx
+ ja .L_do_loop /* > 2 */
+
+ pushl %eax
+ pushl %ebx
+ pushl %ecx
+ pushl %edx
+ pushf
+ movl (%esp), %eax /* copy eflags to eax */
+ xorl $0x200000, (%esp) /* try toggling ID bit of eflags (bit 21)
+ * to see if cpu supports cpuid...
+ * ID bit method not supported by NexGen but
+ * bios may load a cpuid instruction and
+ * cpuid may be disabled on Cyrix 5-6x86 */
+ popf
+ pushf
+ popl %edx /* copy new eflags to edx */
+ xorl %eax, %edx /* test if ID bit is flipped */
+ jz .L_dont_use_mmx /* not flipped if zero */
+ xorl %eax, %eax
+ cpuid
+ cmpl $0x756e6547, %ebx /* check for GenuineIntel in ebx,ecx,edx */
+ jne .L_dont_use_mmx
+ cmpl $0x6c65746e, %ecx
+ jne .L_dont_use_mmx
+ cmpl $0x49656e69, %edx
+ jne .L_dont_use_mmx
+ movl $1, %eax
+ cpuid /* get cpu features */
+ shrl $8, %eax
+ andl $15, %eax
+ cmpl $6, %eax /* check for Pentium family, is 0xf for P4 */
+ jne .L_dont_use_mmx
+ testl $0x800000, %edx /* test if MMX feature is set (bit 23) */
+ jnz .L_use_mmx
+ jmp .L_dont_use_mmx
+.L_use_mmx:
+ movl $DO_USE_MMX, inflate_fast_use_mmx
+ jmp .L_check_mmx_pop
+.L_dont_use_mmx:
+ movl $DONT_USE_MMX, inflate_fast_use_mmx
+.L_check_mmx_pop:
+ popl %edx
+ popl %ecx
+ popl %ebx
+ popl %eax
+ jmp .L_check_mmx
+#endif
+
+
+/*** Non-MMX code ***/
+
+#if defined ( NO_MMX ) || defined( RUN_TIME_MMX )
+
+#define hold_r %ebp
+#define bits_r %bl
+#define bitslong_r %ebx
+
+.align 32,0x90
+.L_while_test:
+ /* while (in < last && out < end)
+ */
+ cmpl out_r, end(%esp)
+ jbe .L_break_loop /* if (out >= end) */
+
+ cmpl in_r, last(%esp)
+ jbe .L_break_loop
+
+.L_do_loop:
+ /* regs: %esi = in, %ebp = hold, %bl = bits, %edi = out
+ *
+ * do {
+ * if (bits < 15) {
+ * hold |= *((unsigned short *)in)++ << bits;
+ * bits += 16
+ * }
+ * this = lcode[hold & lmask]
+ */
+ cmpb $15, bits_r
+ ja .L_get_length_code /* if (15 < bits) */
+
+ xorl %eax, %eax
+ lodsw /* al = *(ushort *)in++ */
+ movb bits_r, %cl /* cl = bits, needs it for shifting */
+ addb $16, bits_r /* bits += 16 */
+ shll %cl, %eax
+ orl %eax, hold_r /* hold |= *((ushort *)in)++ << bits */
+
+.L_get_length_code:
+ movl lmask(%esp), %edx /* edx = lmask */
+ movl lcode(%esp), %ecx /* ecx = lcode */
+ andl hold_r, %edx /* edx &= hold */
+ movl (%ecx,%edx,4), %eax /* eax = lcode[hold & lmask] */
+
+.L_dolen:
+ /* regs: %esi = in, %ebp = hold, %bl = bits, %edi = out
+ *
+ * dolen:
+ * bits -= this.bits;
+ * hold >>= this.bits
+ */
+ movb %ah, %cl /* cl = this.bits */
+ subb %ah, bits_r /* bits -= this.bits */
+ shrl %cl, hold_r /* hold >>= this.bits */
+
+ /* check if op is a literal
+ * if (op == 0) {
+ * PUP(out) = this.val;
+ * }
+ */
+ testb %al, %al
+ jnz .L_test_for_length_base /* if (op != 0) 45.7% */
+
+ shrl $16, %eax /* output this.val char */
+ stosb
+ jmp .L_while_test
+
+.L_test_for_length_base:
+ /* regs: %esi = in, %ebp = hold, %bl = bits, %edi = out, %edx = len
+ *
+ * else if (op & 16) {
+ * len = this.val
+ * op &= 15
+ * if (op) {
+ * if (op > bits) {
+ * hold |= *((unsigned short *)in)++ << bits;
+ * bits += 16
+ * }
+ * len += hold & mask[op];
+ * bits -= op;
+ * hold >>= op;
+ * }
+ */
+#define len_r %edx
+ movl %eax, len_r /* len = this */
+ shrl $16, len_r /* len = this.val */
+ movb %al, %cl
+
+ testb $16, %al
+ jz .L_test_for_second_level_length /* if ((op & 16) == 0) 8% */
+ andb $15, %cl /* op &= 15 */
+ jz .L_save_len /* if (!op) */
+ cmpb %cl, bits_r
+ jae .L_add_bits_to_len /* if (op <= bits) */
+
+ movb %cl, %ch /* stash op in ch, freeing cl */
+ xorl %eax, %eax
+ lodsw /* al = *(ushort *)in++ */
+ movb bits_r, %cl /* cl = bits, needs it for shifting */
+ addb $16, bits_r /* bits += 16 */
+ shll %cl, %eax
+ orl %eax, hold_r /* hold |= *((ushort *)in)++ << bits */
+ movb %ch, %cl /* move op back to ecx */
+
+.L_add_bits_to_len:
+ movl $1, %eax
+ shll %cl, %eax
+ decl %eax
+ subb %cl, bits_r
+ andl hold_r, %eax /* eax &= hold */
+ shrl %cl, hold_r
+ addl %eax, len_r /* len += hold & mask[op] */
+
+.L_save_len:
+ movl len_r, len(%esp) /* save len */
+#undef len_r
+
+.L_decode_distance:
+ /* regs: %esi = in, %ebp = hold, %bl = bits, %edi = out, %edx = dist
+ *
+ * if (bits < 15) {
+ * hold |= *((unsigned short *)in)++ << bits;
+ * bits += 16
+ * }
+ * this = dcode[hold & dmask];
+ * dodist:
+ * bits -= this.bits;
+ * hold >>= this.bits;
+ * op = this.op;
+ */
+
+ cmpb $15, bits_r
+ ja .L_get_distance_code /* if (15 < bits) */
+
+ xorl %eax, %eax
+ lodsw /* al = *(ushort *)in++ */
+ movb bits_r, %cl /* cl = bits, needs it for shifting */
+ addb $16, bits_r /* bits += 16 */
+ shll %cl, %eax
+ orl %eax, hold_r /* hold |= *((ushort *)in)++ << bits */
+
+.L_get_distance_code:
+ movl dmask(%esp), %edx /* edx = dmask */
+ movl dcode(%esp), %ecx /* ecx = dcode */
+ andl hold_r, %edx /* edx &= hold */
+ movl (%ecx,%edx,4), %eax /* eax = dcode[hold & dmask] */
+
+#define dist_r %edx
+.L_dodist:
+ movl %eax, dist_r /* dist = this */
+ shrl $16, dist_r /* dist = this.val */
+ movb %ah, %cl
+ subb %ah, bits_r /* bits -= this.bits */
+ shrl %cl, hold_r /* hold >>= this.bits */
+
+ /* if (op & 16) {
+ * dist = this.val
+ * op &= 15
+ * if (op > bits) {
+ * hold |= *((unsigned short *)in)++ << bits;
+ * bits += 16
+ * }
+ * dist += hold & mask[op];
+ * bits -= op;
+ * hold >>= op;
+ */
+ movb %al, %cl /* cl = this.op */
+
+ testb $16, %al /* if ((op & 16) == 0) */
+ jz .L_test_for_second_level_dist
+ andb $15, %cl /* op &= 15 */
+ jz .L_check_dist_one
+ cmpb %cl, bits_r
+ jae .L_add_bits_to_dist /* if (op <= bits) 97.6% */
+
+ movb %cl, %ch /* stash op in ch, freeing cl */
+ xorl %eax, %eax
+ lodsw /* al = *(ushort *)in++ */
+ movb bits_r, %cl /* cl = bits, needs it for shifting */
+ addb $16, bits_r /* bits += 16 */
+ shll %cl, %eax
+ orl %eax, hold_r /* hold |= *((ushort *)in)++ << bits */
+ movb %ch, %cl /* move op back to ecx */
+
+.L_add_bits_to_dist:
+ movl $1, %eax
+ shll %cl, %eax
+ decl %eax /* (1 << op) - 1 */
+ subb %cl, bits_r
+ andl hold_r, %eax /* eax &= hold */
+ shrl %cl, hold_r
+ addl %eax, dist_r /* dist += hold & ((1 << op) - 1) */
+ jmp .L_check_window
+
+.L_check_window:
+ /* regs: %esi = from, %ebp = hold, %bl = bits, %edi = out, %edx = dist
+ * %ecx = nbytes
+ *
+ * nbytes = out - beg;
+ * if (dist <= nbytes) {
+ * from = out - dist;
+ * do {
+ * PUP(out) = PUP(from);
+ * } while (--len > 0) {
+ * }
+ */
+
+ movl in_r, in(%esp) /* save in so from can use it's reg */
+ movl out_r, %eax
+ subl beg(%esp), %eax /* nbytes = out - beg */
+
+ cmpl dist_r, %eax
+ jb .L_clip_window /* if (dist > nbytes) 4.2% */
+
+ movl len(%esp), %ecx
+ movl out_r, from_r
+ subl dist_r, from_r /* from = out - dist */
+
+ subl $3, %ecx
+ movb (from_r), %al
+ movb %al, (out_r)
+ movb 1(from_r), %al
+ movb 2(from_r), %dl
+ addl $3, from_r
+ movb %al, 1(out_r)
+ movb %dl, 2(out_r)
+ addl $3, out_r
+ rep movsb
+
+ movl in(%esp), in_r /* move in back to %esi, toss from */
+ jmp .L_while_test
+
+.align 16,0x90
+.L_check_dist_one:
+ cmpl $1, dist_r
+ jne .L_check_window
+ cmpl out_r, beg(%esp)
+ je .L_check_window
+
+ decl out_r
+ movl len(%esp), %ecx
+ movb (out_r), %al
+ subl $3, %ecx
+
+ movb %al, 1(out_r)
+ movb %al, 2(out_r)
+ movb %al, 3(out_r)
+ addl $4, out_r
+ rep stosb
+
+ jmp .L_while_test
+
+.align 16,0x90
+.L_test_for_second_level_length:
+ /* else if ((op & 64) == 0) {
+ * this = lcode[this.val + (hold & mask[op])];
+ * }
+ */
+ testb $64, %al
+ jnz .L_test_for_end_of_block /* if ((op & 64) != 0) */
+
+ movl $1, %eax
+ shll %cl, %eax
+ decl %eax
+ andl hold_r, %eax /* eax &= hold */
+ addl %edx, %eax /* eax += this.val */
+ movl lcode(%esp), %edx /* edx = lcode */
+ movl (%edx,%eax,4), %eax /* eax = lcode[val + (hold&mask[op])] */
+ jmp .L_dolen
+
+.align 16,0x90
+.L_test_for_second_level_dist:
+ /* else if ((op & 64) == 0) {
+ * this = dcode[this.val + (hold & mask[op])];
+ * }
+ */
+ testb $64, %al
+ jnz .L_invalid_distance_code /* if ((op & 64) != 0) */
+
+ movl $1, %eax
+ shll %cl, %eax
+ decl %eax
+ andl hold_r, %eax /* eax &= hold */
+ addl %edx, %eax /* eax += this.val */
+ movl dcode(%esp), %edx /* edx = dcode */
+ movl (%edx,%eax,4), %eax /* eax = dcode[val + (hold&mask[op])] */
+ jmp .L_dodist
+
+.align 16,0x90
+.L_clip_window:
+ /* regs: %esi = from, %ebp = hold, %bl = bits, %edi = out, %edx = dist
+ * %ecx = nbytes
+ *
+ * else {
+ * if (dist > wsize) {
+ * invalid distance
+ * }
+ * from = window;
+ * nbytes = dist - nbytes;
+ * if (write == 0) {
+ * from += wsize - nbytes;
+ */
+#define nbytes_r %ecx
+ movl %eax, nbytes_r
+ movl wsize(%esp), %eax /* prepare for dist compare */
+ negl nbytes_r /* nbytes = -nbytes */
+ movl window(%esp), from_r /* from = window */
+
+ cmpl dist_r, %eax
+ jb .L_invalid_distance_too_far /* if (dist > wsize) */
+
+ addl dist_r, nbytes_r /* nbytes = dist - nbytes */
+ cmpl $0, write(%esp)
+ jne .L_wrap_around_window /* if (write != 0) */
+
+ subl nbytes_r, %eax
+ addl %eax, from_r /* from += wsize - nbytes */
+
+ /* regs: %esi = from, %ebp = hold, %bl = bits, %edi = out, %edx = dist
+ * %ecx = nbytes, %eax = len
+ *
+ * if (nbytes < len) {
+ * len -= nbytes;
+ * do {
+ * PUP(out) = PUP(from);
+ * } while (--nbytes);
+ * from = out - dist;
+ * }
+ * }
+ */
+#define len_r %eax
+ movl len(%esp), len_r
+ cmpl nbytes_r, len_r
+ jbe .L_do_copy1 /* if (nbytes >= len) */
+
+ subl nbytes_r, len_r /* len -= nbytes */
+ rep movsb
+ movl out_r, from_r
+ subl dist_r, from_r /* from = out - dist */
+ jmp .L_do_copy1
+
+ cmpl nbytes_r, len_r
+ jbe .L_do_copy1 /* if (nbytes >= len) */
+
+ subl nbytes_r, len_r /* len -= nbytes */
+ rep movsb
+ movl out_r, from_r
+ subl dist_r, from_r /* from = out - dist */
+ jmp .L_do_copy1
+
+.L_wrap_around_window:
+ /* regs: %esi = from, %ebp = hold, %bl = bits, %edi = out, %edx = dist
+ * %ecx = nbytes, %eax = write, %eax = len
+ *
+ * else if (write < nbytes) {
+ * from += wsize + write - nbytes;
+ * nbytes -= write;
+ * if (nbytes < len) {
+ * len -= nbytes;
+ * do {
+ * PUP(out) = PUP(from);
+ * } while (--nbytes);
+ * from = window;
+ * nbytes = write;
+ * if (nbytes < len) {
+ * len -= nbytes;
+ * do {
+ * PUP(out) = PUP(from);
+ * } while(--nbytes);
+ * from = out - dist;
+ * }
+ * }
+ * }
+ */
+#define write_r %eax
+ movl write(%esp), write_r
+ cmpl write_r, nbytes_r
+ jbe .L_contiguous_in_window /* if (write >= nbytes) */
+
+ addl wsize(%esp), from_r
+ addl write_r, from_r
+ subl nbytes_r, from_r /* from += wsize + write - nbytes */
+ subl write_r, nbytes_r /* nbytes -= write */
+#undef write_r
+
+ movl len(%esp), len_r
+ cmpl nbytes_r, len_r
+ jbe .L_do_copy1 /* if (nbytes >= len) */
+
+ subl nbytes_r, len_r /* len -= nbytes */
+ rep movsb
+ movl window(%esp), from_r /* from = window */
+ movl write(%esp), nbytes_r /* nbytes = write */
+ cmpl nbytes_r, len_r
+ jbe .L_do_copy1 /* if (nbytes >= len) */
+
+ subl nbytes_r, len_r /* len -= nbytes */
+ rep movsb
+ movl out_r, from_r
+ subl dist_r, from_r /* from = out - dist */
+ jmp .L_do_copy1
+
+.L_contiguous_in_window:
+ /* regs: %esi = from, %ebp = hold, %bl = bits, %edi = out, %edx = dist
+ * %ecx = nbytes, %eax = write, %eax = len
+ *
+ * else {
+ * from += write - nbytes;
+ * if (nbytes < len) {
+ * len -= nbytes;
+ * do {
+ * PUP(out) = PUP(from);
+ * } while (--nbytes);
+ * from = out - dist;
+ * }
+ * }
+ */
+#define write_r %eax
+ addl write_r, from_r
+ subl nbytes_r, from_r /* from += write - nbytes */
+#undef write_r
+
+ movl len(%esp), len_r
+ cmpl nbytes_r, len_r
+ jbe .L_do_copy1 /* if (nbytes >= len) */
+
+ subl nbytes_r, len_r /* len -= nbytes */
+ rep movsb
+ movl out_r, from_r
+ subl dist_r, from_r /* from = out - dist */
+
+.L_do_copy1:
+ /* regs: %esi = from, %esi = in, %ebp = hold, %bl = bits, %edi = out
+ * %eax = len
+ *
+ * while (len > 0) {
+ * PUP(out) = PUP(from);
+ * len--;
+ * }
+ * }
+ * } while (in < last && out < end);
+ */
+#undef nbytes_r
+#define in_r %esi
+ movl len_r, %ecx
+ rep movsb
+
+ movl in(%esp), in_r /* move in back to %esi, toss from */
+ jmp .L_while_test
+
+#undef len_r
+#undef dist_r
+
+#endif /* NO_MMX || RUN_TIME_MMX */
+
+
+/*** MMX code ***/
+
+#if defined( USE_MMX ) || defined( RUN_TIME_MMX )
+
+.align 32,0x90
+.L_init_mmx:
+ emms
+
+#undef bits_r
+#undef bitslong_r
+#define bitslong_r %ebp
+#define hold_mm %mm0
+ movd %ebp, hold_mm
+ movl %ebx, bitslong_r
+
+#define used_mm %mm1
+#define dmask2_mm %mm2
+#define lmask2_mm %mm3
+#define lmask_mm %mm4
+#define dmask_mm %mm5
+#define tmp_mm %mm6
+
+ movd lmask(%esp), lmask_mm
+ movq lmask_mm, lmask2_mm
+ movd dmask(%esp), dmask_mm
+ movq dmask_mm, dmask2_mm
+ pxor used_mm, used_mm
+ movl lcode(%esp), %ebx /* ebx = lcode */
+ jmp .L_do_loop_mmx
+
+.align 32,0x90
+.L_while_test_mmx:
+ /* while (in < last && out < end)
+ */
+ cmpl out_r, end(%esp)
+ jbe .L_break_loop /* if (out >= end) */
+
+ cmpl in_r, last(%esp)
+ jbe .L_break_loop
+
+.L_do_loop_mmx:
+ psrlq used_mm, hold_mm /* hold_mm >>= last bit length */
+
+ cmpl $32, bitslong_r
+ ja .L_get_length_code_mmx /* if (32 < bits) */
+
+ movd bitslong_r, tmp_mm
+ movd (in_r), %mm7
+ addl $4, in_r
+ psllq tmp_mm, %mm7
+ addl $32, bitslong_r
+ por %mm7, hold_mm /* hold_mm |= *((uint *)in)++ << bits */
+
+.L_get_length_code_mmx:
+ pand hold_mm, lmask_mm
+ movd lmask_mm, %eax
+ movq lmask2_mm, lmask_mm
+ movl (%ebx,%eax,4), %eax /* eax = lcode[hold & lmask] */
+
+.L_dolen_mmx:
+ movzbl %ah, %ecx /* ecx = this.bits */
+ movd %ecx, used_mm
+ subl %ecx, bitslong_r /* bits -= this.bits */
+
+ testb %al, %al
+ jnz .L_test_for_length_base_mmx /* if (op != 0) 45.7% */
+
+ shrl $16, %eax /* output this.val char */
+ stosb
+ jmp .L_while_test_mmx
+
+.L_test_for_length_base_mmx:
+#define len_r %edx
+ movl %eax, len_r /* len = this */
+ shrl $16, len_r /* len = this.val */
+
+ testb $16, %al
+ jz .L_test_for_second_level_length_mmx /* if ((op & 16) == 0) 8% */
+ andl $15, %eax /* op &= 15 */
+ jz .L_decode_distance_mmx /* if (!op) */
+
+ psrlq used_mm, hold_mm /* hold_mm >>= last bit length */
+ movd %eax, used_mm
+ movd hold_mm, %ecx
+ subl %eax, bitslong_r
+ andl .L_mask(,%eax,4), %ecx
+ addl %ecx, len_r /* len += hold & mask[op] */
+
+.L_decode_distance_mmx:
+ psrlq used_mm, hold_mm /* hold_mm >>= last bit length */
+
+ cmpl $32, bitslong_r
+ ja .L_get_dist_code_mmx /* if (32 < bits) */
+
+ movd bitslong_r, tmp_mm
+ movd (in_r), %mm7
+ addl $4, in_r
+ psllq tmp_mm, %mm7
+ addl $32, bitslong_r
+ por %mm7, hold_mm /* hold_mm |= *((uint *)in)++ << bits */
+
+.L_get_dist_code_mmx:
+ movl dcode(%esp), %ebx /* ebx = dcode */
+ pand hold_mm, dmask_mm
+ movd dmask_mm, %eax
+ movq dmask2_mm, dmask_mm
+ movl (%ebx,%eax,4), %eax /* eax = dcode[hold & lmask] */
+
+.L_dodist_mmx:
+#define dist_r %ebx
+ movzbl %ah, %ecx /* ecx = this.bits */
+ movl %eax, dist_r
+ shrl $16, dist_r /* dist = this.val */
+ subl %ecx, bitslong_r /* bits -= this.bits */
+ movd %ecx, used_mm
+
+ testb $16, %al /* if ((op & 16) == 0) */
+ jz .L_test_for_second_level_dist_mmx
+ andl $15, %eax /* op &= 15 */
+ jz .L_check_dist_one_mmx
+
+.L_add_bits_to_dist_mmx:
+ psrlq used_mm, hold_mm /* hold_mm >>= last bit length */
+ movd %eax, used_mm /* save bit length of current op */
+ movd hold_mm, %ecx /* get the next bits on input stream */
+ subl %eax, bitslong_r /* bits -= op bits */
+ andl .L_mask(,%eax,4), %ecx /* ecx = hold & mask[op] */
+ addl %ecx, dist_r /* dist += hold & mask[op] */
+
+.L_check_window_mmx:
+ movl in_r, in(%esp) /* save in so from can use it's reg */
+ movl out_r, %eax
+ subl beg(%esp), %eax /* nbytes = out - beg */
+
+ cmpl dist_r, %eax
+ jb .L_clip_window_mmx /* if (dist > nbytes) 4.2% */
+
+ movl len_r, %ecx
+ movl out_r, from_r
+ subl dist_r, from_r /* from = out - dist */
+
+ subl $3, %ecx
+ movb (from_r), %al
+ movb %al, (out_r)
+ movb 1(from_r), %al
+ movb 2(from_r), %dl
+ addl $3, from_r
+ movb %al, 1(out_r)
+ movb %dl, 2(out_r)
+ addl $3, out_r
+ rep movsb
+
+ movl in(%esp), in_r /* move in back to %esi, toss from */
+ movl lcode(%esp), %ebx /* move lcode back to %ebx, toss dist */
+ jmp .L_while_test_mmx
+
+.align 16,0x90
+.L_check_dist_one_mmx:
+ cmpl $1, dist_r
+ jne .L_check_window_mmx
+ cmpl out_r, beg(%esp)
+ je .L_check_window_mmx
+
+ decl out_r
+ movl len_r, %ecx
+ movb (out_r), %al
+ subl $3, %ecx
+
+ movb %al, 1(out_r)
+ movb %al, 2(out_r)
+ movb %al, 3(out_r)
+ addl $4, out_r
+ rep stosb
+
+ movl lcode(%esp), %ebx /* move lcode back to %ebx, toss dist */
+ jmp .L_while_test_mmx
+
+.align 16,0x90
+.L_test_for_second_level_length_mmx:
+ testb $64, %al
+ jnz .L_test_for_end_of_block /* if ((op & 64) != 0) */
+
+ andl $15, %eax
+ psrlq used_mm, hold_mm /* hold_mm >>= last bit length */
+ movd hold_mm, %ecx
+ andl .L_mask(,%eax,4), %ecx
+ addl len_r, %ecx
+ movl (%ebx,%ecx,4), %eax /* eax = lcode[hold & lmask] */
+ jmp .L_dolen_mmx
+
+.align 16,0x90
+.L_test_for_second_level_dist_mmx:
+ testb $64, %al
+ jnz .L_invalid_distance_code /* if ((op & 64) != 0) */
+
+ andl $15, %eax
+ psrlq used_mm, hold_mm /* hold_mm >>= last bit length */
+ movd hold_mm, %ecx
+ andl .L_mask(,%eax,4), %ecx
+ movl dcode(%esp), %eax /* ecx = dcode */
+ addl dist_r, %ecx
+ movl (%eax,%ecx,4), %eax /* eax = lcode[hold & lmask] */
+ jmp .L_dodist_mmx
+
+.align 16,0x90
+.L_clip_window_mmx:
+#define nbytes_r %ecx
+ movl %eax, nbytes_r
+ movl wsize(%esp), %eax /* prepare for dist compare */
+ negl nbytes_r /* nbytes = -nbytes */
+ movl window(%esp), from_r /* from = window */
+
+ cmpl dist_r, %eax
+ jb .L_invalid_distance_too_far /* if (dist > wsize) */
+
+ addl dist_r, nbytes_r /* nbytes = dist - nbytes */
+ cmpl $0, write(%esp)
+ jne .L_wrap_around_window_mmx /* if (write != 0) */
+
+ subl nbytes_r, %eax
+ addl %eax, from_r /* from += wsize - nbytes */
+
+ cmpl nbytes_r, len_r
+ jbe .L_do_copy1_mmx /* if (nbytes >= len) */
+
+ subl nbytes_r, len_r /* len -= nbytes */
+ rep movsb
+ movl out_r, from_r
+ subl dist_r, from_r /* from = out - dist */
+ jmp .L_do_copy1_mmx
+
+ cmpl nbytes_r, len_r
+ jbe .L_do_copy1_mmx /* if (nbytes >= len) */
+
+ subl nbytes_r, len_r /* len -= nbytes */
+ rep movsb
+ movl out_r, from_r
+ subl dist_r, from_r /* from = out - dist */
+ jmp .L_do_copy1_mmx
+
+.L_wrap_around_window_mmx:
+#define write_r %eax
+ movl write(%esp), write_r
+ cmpl write_r, nbytes_r
+ jbe .L_contiguous_in_window_mmx /* if (write >= nbytes) */
+
+ addl wsize(%esp), from_r
+ addl write_r, from_r
+ subl nbytes_r, from_r /* from += wsize + write - nbytes */
+ subl write_r, nbytes_r /* nbytes -= write */
+#undef write_r
+
+ cmpl nbytes_r, len_r
+ jbe .L_do_copy1_mmx /* if (nbytes >= len) */
+
+ subl nbytes_r, len_r /* len -= nbytes */
+ rep movsb
+ movl window(%esp), from_r /* from = window */
+ movl write(%esp), nbytes_r /* nbytes = write */
+ cmpl nbytes_r, len_r
+ jbe .L_do_copy1_mmx /* if (nbytes >= len) */
+
+ subl nbytes_r, len_r /* len -= nbytes */
+ rep movsb
+ movl out_r, from_r
+ subl dist_r, from_r /* from = out - dist */
+ jmp .L_do_copy1_mmx
+
+.L_contiguous_in_window_mmx:
+#define write_r %eax
+ addl write_r, from_r
+ subl nbytes_r, from_r /* from += write - nbytes */
+#undef write_r
+
+ cmpl nbytes_r, len_r
+ jbe .L_do_copy1_mmx /* if (nbytes >= len) */
+
+ subl nbytes_r, len_r /* len -= nbytes */
+ rep movsb
+ movl out_r, from_r
+ subl dist_r, from_r /* from = out - dist */
+
+.L_do_copy1_mmx:
+#undef nbytes_r
+#define in_r %esi
+ movl len_r, %ecx
+ rep movsb
+
+ movl in(%esp), in_r /* move in back to %esi, toss from */
+ movl lcode(%esp), %ebx /* move lcode back to %ebx, toss dist */
+ jmp .L_while_test_mmx
+
+#undef hold_r
+#undef bitslong_r
+
+#endif /* USE_MMX || RUN_TIME_MMX */
+
+
+/*** USE_MMX, NO_MMX, and RUNTIME_MMX from here on ***/
+
+.L_invalid_distance_code:
+ /* else {
+ * strm->msg = "invalid distance code";
+ * state->mode = BAD;
+ * }
+ */
+ movl $.L_invalid_distance_code_msg, %ecx
+ movl $INFLATE_MODE_BAD, %edx
+ jmp .L_update_stream_state
+
+.L_test_for_end_of_block:
+ /* else if (op & 32) {
+ * state->mode = TYPE;
+ * break;
+ * }
+ */
+ testb $32, %al
+ jz .L_invalid_literal_length_code /* if ((op & 32) == 0) */
+
+ movl $0, %ecx
+ movl $INFLATE_MODE_TYPE, %edx
+ jmp .L_update_stream_state
+
+.L_invalid_literal_length_code:
+ /* else {
+ * strm->msg = "invalid literal/length code";
+ * state->mode = BAD;
+ * }
+ */
+ movl $.L_invalid_literal_length_code_msg, %ecx
+ movl $INFLATE_MODE_BAD, %edx
+ jmp .L_update_stream_state
+
+.L_invalid_distance_too_far:
+ /* strm->msg = "invalid distance too far back";
+ * state->mode = BAD;
+ */
+ movl in(%esp), in_r /* from_r has in's reg, put in back */
+ movl $.L_invalid_distance_too_far_msg, %ecx
+ movl $INFLATE_MODE_BAD, %edx
+ jmp .L_update_stream_state
+
+.L_update_stream_state:
+ /* set strm->msg = %ecx, strm->state->mode = %edx */
+ movl strm_sp(%esp), %eax
+ testl %ecx, %ecx /* if (msg != NULL) */
+ jz .L_skip_msg
+ movl %ecx, msg_strm(%eax) /* strm->msg = msg */
+.L_skip_msg:
+ movl state_strm(%eax), %eax /* state = strm->state */
+ movl %edx, mode_state(%eax) /* state->mode = edx (BAD | TYPE) */
+ jmp .L_break_loop
+
+.align 32,0x90
+.L_break_loop:
+
+/*
+ * Regs:
+ *
+ * bits = %ebp when mmx, and in %ebx when non-mmx
+ * hold = %hold_mm when mmx, and in %ebp when non-mmx
+ * in = %esi
+ * out = %edi
+ */
+
+#if defined( USE_MMX ) || defined( RUN_TIME_MMX )
+
+#if defined( RUN_TIME_MMX )
+
+ cmpl $DO_USE_MMX, inflate_fast_use_mmx
+ jne .L_update_next_in
+
+#endif /* RUN_TIME_MMX */
+
+ movl %ebp, %ebx
+
+.L_update_next_in:
+
+#endif
+
+#define strm_r %eax
+#define state_r %edx
+
+ /* len = bits >> 3;
+ * in -= len;
+ * bits -= len << 3;
+ * hold &= (1U << bits) - 1;
+ * state->hold = hold;
+ * state->bits = bits;
+ * strm->next_in = in;
+ * strm->next_out = out;
+ */
+ movl strm_sp(%esp), strm_r
+ movl %ebx, %ecx
+ movl state_strm(strm_r), state_r
+ shrl $3, %ecx
+ subl %ecx, in_r
+ shll $3, %ecx
+ subl %ecx, %ebx
+ movl out_r, next_out_strm(strm_r)
+ movl %ebx, bits_state(state_r)
+ movl %ebx, %ecx
+
+ leal buf(%esp), %ebx
+ cmpl %ebx, last(%esp)
+ jne .L_buf_not_used /* if buf != last */
+
+ subl %ebx, in_r /* in -= buf */
+ movl next_in_strm(strm_r), %ebx
+ movl %ebx, last(%esp) /* last = strm->next_in */
+ addl %ebx, in_r /* in += strm->next_in */
+ movl avail_in_strm(strm_r), %ebx
+ subl $11, %ebx
+ addl %ebx, last(%esp) /* last = &strm->next_in[ avail_in - 11 ] */
+
+.L_buf_not_used:
+ movl in_r, next_in_strm(strm_r)
+
+ movl $1, %ebx
+ shll %cl, %ebx
+ decl %ebx
+
+#if defined( USE_MMX ) || defined( RUN_TIME_MMX )
+
+#if defined( RUN_TIME_MMX )
+
+ cmpl $DO_USE_MMX, inflate_fast_use_mmx
+ jne .L_update_hold
+
+#endif /* RUN_TIME_MMX */
+
+ psrlq used_mm, hold_mm /* hold_mm >>= last bit length */
+ movd hold_mm, %ebp
+
+ emms
+
+.L_update_hold:
+
+#endif /* USE_MMX || RUN_TIME_MMX */
+
+ andl %ebx, %ebp
+ movl %ebp, hold_state(state_r)
+
+#define last_r %ebx
+
+ /* strm->avail_in = in < last ? 11 + (last - in) : 11 - (in - last) */
+ movl last(%esp), last_r
+ cmpl in_r, last_r
+ jbe .L_last_is_smaller /* if (in >= last) */
+
+ subl in_r, last_r /* last -= in */
+ addl $11, last_r /* last += 11 */
+ movl last_r, avail_in_strm(strm_r)
+ jmp .L_fixup_out
+.L_last_is_smaller:
+ subl last_r, in_r /* in -= last */
+ negl in_r /* in = -in */
+ addl $11, in_r /* in += 11 */
+ movl in_r, avail_in_strm(strm_r)
+
+#undef last_r
+#define end_r %ebx
+
+.L_fixup_out:
+ /* strm->avail_out = out < end ? 257 + (end - out) : 257 - (out - end)*/
+ movl end(%esp), end_r
+ cmpl out_r, end_r
+ jbe .L_end_is_smaller /* if (out >= end) */
+
+ subl out_r, end_r /* end -= out */
+ addl $257, end_r /* end += 257 */
+ movl end_r, avail_out_strm(strm_r)
+ jmp .L_done
+.L_end_is_smaller:
+ subl end_r, out_r /* out -= end */
+ negl out_r /* out = -out */
+ addl $257, out_r /* out += 257 */
+ movl out_r, avail_out_strm(strm_r)
+
+#undef end_r
+#undef strm_r
+#undef state_r
+
+.L_done:
+ addl $local_var_size, %esp
+ popf
+ popl %ebx
+ popl %ebp
+ popl %esi
+ popl %edi
+ ret
+
+#if defined( GAS_ELF )
+/* elf info */
+.type inflate_fast,@function
+.size inflate_fast,.-inflate_fast
+#endif
ADDED compat/zlib/contrib/iostream/test.cpp
Index: compat/zlib/contrib/iostream/test.cpp
==================================================================
--- compat/zlib/contrib/iostream/test.cpp
+++ compat/zlib/contrib/iostream/test.cpp
@@ -0,0 +1,24 @@
+
+#include "zfstream.h"
+
+int main() {
+
+ // Construct a stream object with this filebuffer. Anything sent
+ // to this stream will go to standard out.
+ gzofstream os( 1, ios::out );
+
+ // This text is getting compressed and sent to stdout.
+ // To prove this, run 'test | zcat'.
+ os << "Hello, Mommy" << endl;
+
+ os << setcompressionlevel( Z_NO_COMPRESSION );
+ os << "hello, hello, hi, ho!" << endl;
+
+ setcompressionlevel( os, Z_DEFAULT_COMPRESSION )
+ << "I'm compressing again" << endl;
+
+ os.close();
+
+ return 0;
+
+}
ADDED compat/zlib/contrib/iostream/zfstream.cpp
Index: compat/zlib/contrib/iostream/zfstream.cpp
==================================================================
--- compat/zlib/contrib/iostream/zfstream.cpp
+++ compat/zlib/contrib/iostream/zfstream.cpp
@@ -0,0 +1,329 @@
+
+#include "zfstream.h"
+
+gzfilebuf::gzfilebuf() :
+ file(NULL),
+ mode(0),
+ own_file_descriptor(0)
+{ }
+
+gzfilebuf::~gzfilebuf() {
+
+ sync();
+ if ( own_file_descriptor )
+ close();
+
+}
+
+gzfilebuf *gzfilebuf::open( const char *name,
+ int io_mode ) {
+
+ if ( is_open() )
+ return NULL;
+
+ char char_mode[10];
+ char *p = char_mode;
+
+ if ( io_mode & ios::in ) {
+ mode = ios::in;
+ *p++ = 'r';
+ } else if ( io_mode & ios::app ) {
+ mode = ios::app;
+ *p++ = 'a';
+ } else {
+ mode = ios::out;
+ *p++ = 'w';
+ }
+
+ if ( io_mode & ios::binary ) {
+ mode |= ios::binary;
+ *p++ = 'b';
+ }
+
+ // Hard code the compression level
+ if ( io_mode & (ios::out|ios::app )) {
+ *p++ = '9';
+ }
+
+ // Put the end-of-string indicator
+ *p = '\0';
+
+ if ( (file = gzopen(name, char_mode)) == NULL )
+ return NULL;
+
+ own_file_descriptor = 1;
+
+ return this;
+
+}
+
+gzfilebuf *gzfilebuf::attach( int file_descriptor,
+ int io_mode ) {
+
+ if ( is_open() )
+ return NULL;
+
+ char char_mode[10];
+ char *p = char_mode;
+
+ if ( io_mode & ios::in ) {
+ mode = ios::in;
+ *p++ = 'r';
+ } else if ( io_mode & ios::app ) {
+ mode = ios::app;
+ *p++ = 'a';
+ } else {
+ mode = ios::out;
+ *p++ = 'w';
+ }
+
+ if ( io_mode & ios::binary ) {
+ mode |= ios::binary;
+ *p++ = 'b';
+ }
+
+ // Hard code the compression level
+ if ( io_mode & (ios::out|ios::app )) {
+ *p++ = '9';
+ }
+
+ // Put the end-of-string indicator
+ *p = '\0';
+
+ if ( (file = gzdopen(file_descriptor, char_mode)) == NULL )
+ return NULL;
+
+ own_file_descriptor = 0;
+
+ return this;
+
+}
+
+gzfilebuf *gzfilebuf::close() {
+
+ if ( is_open() ) {
+
+ sync();
+ gzclose( file );
+ file = NULL;
+
+ }
+
+ return this;
+
+}
+
+int gzfilebuf::setcompressionlevel( int comp_level ) {
+
+ return gzsetparams(file, comp_level, -2);
+
+}
+
+int gzfilebuf::setcompressionstrategy( int comp_strategy ) {
+
+ return gzsetparams(file, -2, comp_strategy);
+
+}
+
+
+streampos gzfilebuf::seekoff( streamoff off, ios::seek_dir dir, int which ) {
+
+ return streampos(EOF);
+
+}
+
+int gzfilebuf::underflow() {
+
+ // If the file hasn't been opened for reading, error.
+ if ( !is_open() || !(mode & ios::in) )
+ return EOF;
+
+ // if a buffer doesn't exists, allocate one.
+ if ( !base() ) {
+
+ if ( (allocate()) == EOF )
+ return EOF;
+ setp(0,0);
+
+ } else {
+
+ if ( in_avail() )
+ return (unsigned char) *gptr();
+
+ if ( out_waiting() ) {
+ if ( flushbuf() == EOF )
+ return EOF;
+ }
+
+ }
+
+ // Attempt to fill the buffer.
+
+ int result = fillbuf();
+ if ( result == EOF ) {
+ // disable get area
+ setg(0,0,0);
+ return EOF;
+ }
+
+ return (unsigned char) *gptr();
+
+}
+
+int gzfilebuf::overflow( int c ) {
+
+ if ( !is_open() || !(mode & ios::out) )
+ return EOF;
+
+ if ( !base() ) {
+ if ( allocate() == EOF )
+ return EOF;
+ setg(0,0,0);
+ } else {
+ if (in_avail()) {
+ return EOF;
+ }
+ if (out_waiting()) {
+ if (flushbuf() == EOF)
+ return EOF;
+ }
+ }
+
+ int bl = blen();
+ setp( base(), base() + bl);
+
+ if ( c != EOF ) {
+
+ *pptr() = c;
+ pbump(1);
+
+ }
+
+ return 0;
+
+}
+
+int gzfilebuf::sync() {
+
+ if ( !is_open() )
+ return EOF;
+
+ if ( out_waiting() )
+ return flushbuf();
+
+ return 0;
+
+}
+
+int gzfilebuf::flushbuf() {
+
+ int n;
+ char *q;
+
+ q = pbase();
+ n = pptr() - q;
+
+ if ( gzwrite( file, q, n) < n )
+ return EOF;
+
+ setp(0,0);
+
+ return 0;
+
+}
+
+int gzfilebuf::fillbuf() {
+
+ int required;
+ char *p;
+
+ p = base();
+
+ required = blen();
+
+ int t = gzread( file, p, required );
+
+ if ( t <= 0) return EOF;
+
+ setg( base(), base(), base()+t);
+
+ return t;
+
+}
+
+gzfilestream_common::gzfilestream_common() :
+ ios( gzfilestream_common::rdbuf() )
+{ }
+
+gzfilestream_common::~gzfilestream_common()
+{ }
+
+void gzfilestream_common::attach( int fd, int io_mode ) {
+
+ if ( !buffer.attach( fd, io_mode) )
+ clear( ios::failbit | ios::badbit );
+ else
+ clear();
+
+}
+
+void gzfilestream_common::open( const char *name, int io_mode ) {
+
+ if ( !buffer.open( name, io_mode ) )
+ clear( ios::failbit | ios::badbit );
+ else
+ clear();
+
+}
+
+void gzfilestream_common::close() {
+
+ if ( !buffer.close() )
+ clear( ios::failbit | ios::badbit );
+
+}
+
+gzfilebuf *gzfilestream_common::rdbuf()
+{
+ return &buffer;
+}
+
+gzifstream::gzifstream() :
+ ios( gzfilestream_common::rdbuf() )
+{
+ clear( ios::badbit );
+}
+
+gzifstream::gzifstream( const char *name, int io_mode ) :
+ ios( gzfilestream_common::rdbuf() )
+{
+ gzfilestream_common::open( name, io_mode );
+}
+
+gzifstream::gzifstream( int fd, int io_mode ) :
+ ios( gzfilestream_common::rdbuf() )
+{
+ gzfilestream_common::attach( fd, io_mode );
+}
+
+gzifstream::~gzifstream() { }
+
+gzofstream::gzofstream() :
+ ios( gzfilestream_common::rdbuf() )
+{
+ clear( ios::badbit );
+}
+
+gzofstream::gzofstream( const char *name, int io_mode ) :
+ ios( gzfilestream_common::rdbuf() )
+{
+ gzfilestream_common::open( name, io_mode );
+}
+
+gzofstream::gzofstream( int fd, int io_mode ) :
+ ios( gzfilestream_common::rdbuf() )
+{
+ gzfilestream_common::attach( fd, io_mode );
+}
+
+gzofstream::~gzofstream() { }
ADDED compat/zlib/contrib/iostream/zfstream.h
Index: compat/zlib/contrib/iostream/zfstream.h
==================================================================
--- compat/zlib/contrib/iostream/zfstream.h
+++ compat/zlib/contrib/iostream/zfstream.h
@@ -0,0 +1,128 @@
+
+#ifndef zfstream_h
+#define zfstream_h
+
+#include
+#include "zlib.h"
+
+class gzfilebuf : public streambuf {
+
+public:
+
+ gzfilebuf( );
+ virtual ~gzfilebuf();
+
+ gzfilebuf *open( const char *name, int io_mode );
+ gzfilebuf *attach( int file_descriptor, int io_mode );
+ gzfilebuf *close();
+
+ int setcompressionlevel( int comp_level );
+ int setcompressionstrategy( int comp_strategy );
+
+ inline int is_open() const { return (file !=NULL); }
+
+ virtual streampos seekoff( streamoff, ios::seek_dir, int );
+
+ virtual int sync();
+
+protected:
+
+ virtual int underflow();
+ virtual int overflow( int = EOF );
+
+private:
+
+ gzFile file;
+ short mode;
+ short own_file_descriptor;
+
+ int flushbuf();
+ int fillbuf();
+
+};
+
+class gzfilestream_common : virtual public ios {
+
+ friend class gzifstream;
+ friend class gzofstream;
+ friend gzofstream &setcompressionlevel( gzofstream &, int );
+ friend gzofstream &setcompressionstrategy( gzofstream &, int );
+
+public:
+ virtual ~gzfilestream_common();
+
+ void attach( int fd, int io_mode );
+ void open( const char *name, int io_mode );
+ void close();
+
+protected:
+ gzfilestream_common();
+
+private:
+ gzfilebuf *rdbuf();
+
+ gzfilebuf buffer;
+
+};
+
+class gzifstream : public gzfilestream_common, public istream {
+
+public:
+
+ gzifstream();
+ gzifstream( const char *name, int io_mode = ios::in );
+ gzifstream( int fd, int io_mode = ios::in );
+
+ virtual ~gzifstream();
+
+};
+
+class gzofstream : public gzfilestream_common, public ostream {
+
+public:
+
+ gzofstream();
+ gzofstream( const char *name, int io_mode = ios::out );
+ gzofstream( int fd, int io_mode = ios::out );
+
+ virtual ~gzofstream();
+
+};
+
+template class gzomanip {
+ friend gzofstream &operator<<(gzofstream &, const gzomanip &);
+public:
+ gzomanip(gzofstream &(*f)(gzofstream &, T), T v) : func(f), val(v) { }
+private:
+ gzofstream &(*func)(gzofstream &, T);
+ T val;
+};
+
+template gzofstream &operator<<(gzofstream &s, const gzomanip &m)
+{
+ return (*m.func)(s, m.val);
+}
+
+inline gzofstream &setcompressionlevel( gzofstream &s, int l )
+{
+ (s.rdbuf())->setcompressionlevel(l);
+ return s;
+}
+
+inline gzofstream &setcompressionstrategy( gzofstream &s, int l )
+{
+ (s.rdbuf())->setcompressionstrategy(l);
+ return s;
+}
+
+inline gzomanip setcompressionlevel(int l)
+{
+ return gzomanip(&setcompressionlevel,l);
+}
+
+inline gzomanip setcompressionstrategy(int l)
+{
+ return gzomanip(&setcompressionstrategy,l);
+}
+
+#endif
ADDED compat/zlib/contrib/iostream2/zstream.h
Index: compat/zlib/contrib/iostream2/zstream.h
==================================================================
--- compat/zlib/contrib/iostream2/zstream.h
+++ compat/zlib/contrib/iostream2/zstream.h
@@ -0,0 +1,307 @@
+/*
+ *
+ * Copyright (c) 1997
+ * Christian Michelsen Research AS
+ * Advanced Computing
+ * Fantoftvegen 38, 5036 BERGEN, Norway
+ * http://www.cmr.no
+ *
+ * Permission to use, copy, modify, distribute and sell this software
+ * and its documentation for any purpose is hereby granted without fee,
+ * provided that the above copyright notice appear in all copies and
+ * that both that copyright notice and this permission notice appear
+ * in supporting documentation. Christian Michelsen Research AS makes no
+ * representations about the suitability of this software for any
+ * purpose. It is provided "as is" without express or implied warranty.
+ *
+ */
+
+#ifndef ZSTREAM__H
+#define ZSTREAM__H
+
+/*
+ * zstream.h - C++ interface to the 'zlib' general purpose compression library
+ * $Id: zstream.h 1.1 1997-06-25 12:00:56+02 tyge Exp tyge $
+ */
+
+#include
+#include
+#include
+#include "zlib.h"
+
+#if defined(_WIN32)
+# include
+# include
+# define SET_BINARY_MODE(file) setmode(fileno(file), O_BINARY)
+#else
+# define SET_BINARY_MODE(file)
+#endif
+
+class zstringlen {
+public:
+ zstringlen(class izstream&);
+ zstringlen(class ozstream&, const char*);
+ size_t value() const { return val.word; }
+private:
+ struct Val { unsigned char byte; size_t word; } val;
+};
+
+// ----------------------------- izstream -----------------------------
+
+class izstream
+{
+ public:
+ izstream() : m_fp(0) {}
+ izstream(FILE* fp) : m_fp(0) { open(fp); }
+ izstream(const char* name) : m_fp(0) { open(name); }
+ ~izstream() { close(); }
+
+ /* Opens a gzip (.gz) file for reading.
+ * open() can be used to read a file which is not in gzip format;
+ * in this case read() will directly read from the file without
+ * decompression. errno can be checked to distinguish two error
+ * cases (if errno is zero, the zlib error is Z_MEM_ERROR).
+ */
+ void open(const char* name) {
+ if (m_fp) close();
+ m_fp = ::gzopen(name, "rb");
+ }
+
+ void open(FILE* fp) {
+ SET_BINARY_MODE(fp);
+ if (m_fp) close();
+ m_fp = ::gzdopen(fileno(fp), "rb");
+ }
+
+ /* Flushes all pending input if necessary, closes the compressed file
+ * and deallocates all the (de)compression state. The return value is
+ * the zlib error number (see function error() below).
+ */
+ int close() {
+ int r = ::gzclose(m_fp);
+ m_fp = 0; return r;
+ }
+
+ /* Binary read the given number of bytes from the compressed file.
+ */
+ int read(void* buf, size_t len) {
+ return ::gzread(m_fp, buf, len);
+ }
+
+ /* Returns the error message for the last error which occurred on the
+ * given compressed file. errnum is set to zlib error number. If an
+ * error occurred in the file system and not in the compression library,
+ * errnum is set to Z_ERRNO and the application may consult errno
+ * to get the exact error code.
+ */
+ const char* error(int* errnum) {
+ return ::gzerror(m_fp, errnum);
+ }
+
+ gzFile fp() { return m_fp; }
+
+ private:
+ gzFile m_fp;
+};
+
+/*
+ * Binary read the given (array of) object(s) from the compressed file.
+ * If the input file was not in gzip format, read() copies the objects number
+ * of bytes into the buffer.
+ * returns the number of uncompressed bytes actually read
+ * (0 for end of file, -1 for error).
+ */
+template
+inline int read(izstream& zs, T* x, Items items) {
+ return ::gzread(zs.fp(), x, items*sizeof(T));
+}
+
+/*
+ * Binary input with the '>' operator.
+ */
+template
+inline izstream& operator>(izstream& zs, T& x) {
+ ::gzread(zs.fp(), &x, sizeof(T));
+ return zs;
+}
+
+
+inline zstringlen::zstringlen(izstream& zs) {
+ zs > val.byte;
+ if (val.byte == 255) zs > val.word;
+ else val.word = val.byte;
+}
+
+/*
+ * Read length of string + the string with the '>' operator.
+ */
+inline izstream& operator>(izstream& zs, char* x) {
+ zstringlen len(zs);
+ ::gzread(zs.fp(), x, len.value());
+ x[len.value()] = '\0';
+ return zs;
+}
+
+inline char* read_string(izstream& zs) {
+ zstringlen len(zs);
+ char* x = new char[len.value()+1];
+ ::gzread(zs.fp(), x, len.value());
+ x[len.value()] = '\0';
+ return x;
+}
+
+// ----------------------------- ozstream -----------------------------
+
+class ozstream
+{
+ public:
+ ozstream() : m_fp(0), m_os(0) {
+ }
+ ozstream(FILE* fp, int level = Z_DEFAULT_COMPRESSION)
+ : m_fp(0), m_os(0) {
+ open(fp, level);
+ }
+ ozstream(const char* name, int level = Z_DEFAULT_COMPRESSION)
+ : m_fp(0), m_os(0) {
+ open(name, level);
+ }
+ ~ozstream() {
+ close();
+ }
+
+ /* Opens a gzip (.gz) file for writing.
+ * The compression level parameter should be in 0..9
+ * errno can be checked to distinguish two error cases
+ * (if errno is zero, the zlib error is Z_MEM_ERROR).
+ */
+ void open(const char* name, int level = Z_DEFAULT_COMPRESSION) {
+ char mode[4] = "wb\0";
+ if (level != Z_DEFAULT_COMPRESSION) mode[2] = '0'+level;
+ if (m_fp) close();
+ m_fp = ::gzopen(name, mode);
+ }
+
+ /* open from a FILE pointer.
+ */
+ void open(FILE* fp, int level = Z_DEFAULT_COMPRESSION) {
+ SET_BINARY_MODE(fp);
+ char mode[4] = "wb\0";
+ if (level != Z_DEFAULT_COMPRESSION) mode[2] = '0'+level;
+ if (m_fp) close();
+ m_fp = ::gzdopen(fileno(fp), mode);
+ }
+
+ /* Flushes all pending output if necessary, closes the compressed file
+ * and deallocates all the (de)compression state. The return value is
+ * the zlib error number (see function error() below).
+ */
+ int close() {
+ if (m_os) {
+ ::gzwrite(m_fp, m_os->str(), m_os->pcount());
+ delete[] m_os->str(); delete m_os; m_os = 0;
+ }
+ int r = ::gzclose(m_fp); m_fp = 0; return r;
+ }
+
+ /* Binary write the given number of bytes into the compressed file.
+ */
+ int write(const void* buf, size_t len) {
+ return ::gzwrite(m_fp, (voidp) buf, len);
+ }
+
+ /* Flushes all pending output into the compressed file. The parameter
+ * _flush is as in the deflate() function. The return value is the zlib
+ * error number (see function gzerror below). flush() returns Z_OK if
+ * the flush_ parameter is Z_FINISH and all output could be flushed.
+ * flush() should be called only when strictly necessary because it can
+ * degrade compression.
+ */
+ int flush(int _flush) {
+ os_flush();
+ return ::gzflush(m_fp, _flush);
+ }
+
+ /* Returns the error message for the last error which occurred on the
+ * given compressed file. errnum is set to zlib error number. If an
+ * error occurred in the file system and not in the compression library,
+ * errnum is set to Z_ERRNO and the application may consult errno
+ * to get the exact error code.
+ */
+ const char* error(int* errnum) {
+ return ::gzerror(m_fp, errnum);
+ }
+
+ gzFile fp() { return m_fp; }
+
+ ostream& os() {
+ if (m_os == 0) m_os = new ostrstream;
+ return *m_os;
+ }
+
+ void os_flush() {
+ if (m_os && m_os->pcount()>0) {
+ ostrstream* oss = new ostrstream;
+ oss->fill(m_os->fill());
+ oss->flags(m_os->flags());
+ oss->precision(m_os->precision());
+ oss->width(m_os->width());
+ ::gzwrite(m_fp, m_os->str(), m_os->pcount());
+ delete[] m_os->str(); delete m_os; m_os = oss;
+ }
+ }
+
+ private:
+ gzFile m_fp;
+ ostrstream* m_os;
+};
+
+/*
+ * Binary write the given (array of) object(s) into the compressed file.
+ * returns the number of uncompressed bytes actually written
+ * (0 in case of error).
+ */
+template
+inline int write(ozstream& zs, const T* x, Items items) {
+ return ::gzwrite(zs.fp(), (voidp) x, items*sizeof(T));
+}
+
+/*
+ * Binary output with the '<' operator.
+ */
+template
+inline ozstream& operator<(ozstream& zs, const T& x) {
+ ::gzwrite(zs.fp(), (voidp) &x, sizeof(T));
+ return zs;
+}
+
+inline zstringlen::zstringlen(ozstream& zs, const char* x) {
+ val.byte = 255; val.word = ::strlen(x);
+ if (val.word < 255) zs < (val.byte = val.word);
+ else zs < val;
+}
+
+/*
+ * Write length of string + the string with the '<' operator.
+ */
+inline ozstream& operator<(ozstream& zs, const char* x) {
+ zstringlen len(zs, x);
+ ::gzwrite(zs.fp(), (voidp) x, len.value());
+ return zs;
+}
+
+#ifdef _MSC_VER
+inline ozstream& operator<(ozstream& zs, char* const& x) {
+ return zs < (const char*) x;
+}
+#endif
+
+/*
+ * Ascii write with the << operator;
+ */
+template
+inline ostream& operator<<(ozstream& zs, const T& x) {
+ zs.os_flush();
+ return zs.os() << x;
+}
+
+#endif
ADDED compat/zlib/contrib/iostream2/zstream_test.cpp
Index: compat/zlib/contrib/iostream2/zstream_test.cpp
==================================================================
--- compat/zlib/contrib/iostream2/zstream_test.cpp
+++ compat/zlib/contrib/iostream2/zstream_test.cpp
@@ -0,0 +1,25 @@
+#include "zstream.h"
+#include
+#include
+#include
+
+void main() {
+ char h[256] = "Hello";
+ char* g = "Goodbye";
+ ozstream out("temp.gz");
+ out < "This works well" < h < g;
+ out.close();
+
+ izstream in("temp.gz"); // read it back
+ char *x = read_string(in), *y = new char[256], z[256];
+ in > y > z;
+ in.close();
+ cout << x << endl << y << endl << z << endl;
+
+ out.open("temp.gz"); // try ascii output; zcat temp.gz to see the results
+ out << setw(50) << setfill('#') << setprecision(20) << x << endl << y << endl << z << endl;
+ out << z << endl << y << endl << x << endl;
+ out << 1.1234567890123456789 << endl;
+
+ delete[] x; delete[] y;
+}
ADDED compat/zlib/contrib/iostream3/README
Index: compat/zlib/contrib/iostream3/README
==================================================================
--- compat/zlib/contrib/iostream3/README
+++ compat/zlib/contrib/iostream3/README
@@ -0,0 +1,35 @@
+These classes provide a C++ stream interface to the zlib library. It allows you
+to do things like:
+
+ gzofstream outf("blah.gz");
+ outf << "These go into the gzip file " << 123 << endl;
+
+It does this by deriving a specialized stream buffer for gzipped files, which is
+the way Stroustrup would have done it. :->
+
+The gzifstream and gzofstream classes were originally written by Kevin Ruland
+and made available in the zlib contrib/iostream directory. The older version still
+compiles under gcc 2.xx, but not under gcc 3.xx, which sparked the development of
+this version.
+
+The new classes are as standard-compliant as possible, closely following the
+approach of the standard library's fstream classes. It compiles under gcc versions
+3.2 and 3.3, but not under gcc 2.xx. This is mainly due to changes in the standard
+library naming scheme. The new version of gzifstream/gzofstream/gzfilebuf differs
+from the previous one in the following respects:
+- added showmanyc
+- added setbuf, with support for unbuffered output via setbuf(0,0)
+- a few bug fixes of stream behavior
+- gzipped output file opened with default compression level instead of maximum level
+- setcompressionlevel()/strategy() members replaced by single setcompression()
+
+The code is provided "as is", with the permission to use, copy, modify, distribute
+and sell it for any purpose without fee.
+
+Ludwig Schwardt
+
+
+DSP Lab
+Electrical & Electronic Engineering Department
+University of Stellenbosch
+South Africa
ADDED compat/zlib/contrib/iostream3/TODO
Index: compat/zlib/contrib/iostream3/TODO
==================================================================
--- compat/zlib/contrib/iostream3/TODO
+++ compat/zlib/contrib/iostream3/TODO
@@ -0,0 +1,17 @@
+Possible upgrades to gzfilebuf:
+
+- The ability to do putback (e.g. putbackfail)
+
+- The ability to seek (zlib supports this, but could be slow/tricky)
+
+- Simultaneous read/write access (does it make sense?)
+
+- Support for ios_base::ate open mode
+
+- Locale support?
+
+- Check public interface to see which calls give problems
+ (due to dependence on library internals)
+
+- Override operator<<(ostream&, gzfilebuf*) to allow direct copying
+ of stream buffer to stream ( i.e. os << is.rdbuf(); )
ADDED compat/zlib/contrib/iostream3/test.cc
Index: compat/zlib/contrib/iostream3/test.cc
==================================================================
--- compat/zlib/contrib/iostream3/test.cc
+++ compat/zlib/contrib/iostream3/test.cc
@@ -0,0 +1,50 @@
+/*
+ * Test program for gzifstream and gzofstream
+ *
+ * by Ludwig Schwardt
+ * original version by Kevin Ruland
+ */
+
+#include "zfstream.h"
+#include // for cout
+
+int main() {
+
+ gzofstream outf;
+ gzifstream inf;
+ char buf[80];
+
+ outf.open("test1.txt.gz");
+ outf << "The quick brown fox sidestepped the lazy canine\n"
+ << 1.3 << "\nPlan " << 9 << std::endl;
+ outf.close();
+ std::cout << "Wrote the following message to 'test1.txt.gz' (check with zcat or zless):\n"
+ << "The quick brown fox sidestepped the lazy canine\n"
+ << 1.3 << "\nPlan " << 9 << std::endl;
+
+ std::cout << "\nReading 'test1.txt.gz' (buffered) produces:\n";
+ inf.open("test1.txt.gz");
+ while (inf.getline(buf,80,'\n')) {
+ std::cout << buf << "\t(" << inf.rdbuf()->in_avail() << " chars left in buffer)\n";
+ }
+ inf.close();
+
+ outf.rdbuf()->pubsetbuf(0,0);
+ outf.open("test2.txt.gz");
+ outf << setcompression(Z_NO_COMPRESSION)
+ << "The quick brown fox sidestepped the lazy canine\n"
+ << 1.3 << "\nPlan " << 9 << std::endl;
+ outf.close();
+ std::cout << "\nWrote the same message to 'test2.txt.gz' in uncompressed form";
+
+ std::cout << "\nReading 'test2.txt.gz' (unbuffered) produces:\n";
+ inf.rdbuf()->pubsetbuf(0,0);
+ inf.open("test2.txt.gz");
+ while (inf.getline(buf,80,'\n')) {
+ std::cout << buf << "\t(" << inf.rdbuf()->in_avail() << " chars left in buffer)\n";
+ }
+ inf.close();
+
+ return 0;
+
+}
ADDED compat/zlib/contrib/iostream3/zfstream.cc
Index: compat/zlib/contrib/iostream3/zfstream.cc
==================================================================
--- compat/zlib/contrib/iostream3/zfstream.cc
+++ compat/zlib/contrib/iostream3/zfstream.cc
@@ -0,0 +1,479 @@
+/*
+ * A C++ I/O streams interface to the zlib gz* functions
+ *
+ * by Ludwig Schwardt
+ * original version by Kevin Ruland
+ *
+ * This version is standard-compliant and compatible with gcc 3.x.
+ */
+
+#include "zfstream.h"
+#include // for strcpy, strcat, strlen (mode strings)
+#include // for BUFSIZ
+
+// Internal buffer sizes (default and "unbuffered" versions)
+#define BIGBUFSIZE BUFSIZ
+#define SMALLBUFSIZE 1
+
+/*****************************************************************************/
+
+// Default constructor
+gzfilebuf::gzfilebuf()
+: file(NULL), io_mode(std::ios_base::openmode(0)), own_fd(false),
+ buffer(NULL), buffer_size(BIGBUFSIZE), own_buffer(true)
+{
+ // No buffers to start with
+ this->disable_buffer();
+}
+
+// Destructor
+gzfilebuf::~gzfilebuf()
+{
+ // Sync output buffer and close only if responsible for file
+ // (i.e. attached streams should be left open at this stage)
+ this->sync();
+ if (own_fd)
+ this->close();
+ // Make sure internal buffer is deallocated
+ this->disable_buffer();
+}
+
+// Set compression level and strategy
+int
+gzfilebuf::setcompression(int comp_level,
+ int comp_strategy)
+{
+ return gzsetparams(file, comp_level, comp_strategy);
+}
+
+// Open gzipped file
+gzfilebuf*
+gzfilebuf::open(const char *name,
+ std::ios_base::openmode mode)
+{
+ // Fail if file already open
+ if (this->is_open())
+ return NULL;
+ // Don't support simultaneous read/write access (yet)
+ if ((mode & std::ios_base::in) && (mode & std::ios_base::out))
+ return NULL;
+
+ // Build mode string for gzopen and check it [27.8.1.3.2]
+ char char_mode[6] = "\0\0\0\0\0";
+ if (!this->open_mode(mode, char_mode))
+ return NULL;
+
+ // Attempt to open file
+ if ((file = gzopen(name, char_mode)) == NULL)
+ return NULL;
+
+ // On success, allocate internal buffer and set flags
+ this->enable_buffer();
+ io_mode = mode;
+ own_fd = true;
+ return this;
+}
+
+// Attach to gzipped file
+gzfilebuf*
+gzfilebuf::attach(int fd,
+ std::ios_base::openmode mode)
+{
+ // Fail if file already open
+ if (this->is_open())
+ return NULL;
+ // Don't support simultaneous read/write access (yet)
+ if ((mode & std::ios_base::in) && (mode & std::ios_base::out))
+ return NULL;
+
+ // Build mode string for gzdopen and check it [27.8.1.3.2]
+ char char_mode[6] = "\0\0\0\0\0";
+ if (!this->open_mode(mode, char_mode))
+ return NULL;
+
+ // Attempt to attach to file
+ if ((file = gzdopen(fd, char_mode)) == NULL)
+ return NULL;
+
+ // On success, allocate internal buffer and set flags
+ this->enable_buffer();
+ io_mode = mode;
+ own_fd = false;
+ return this;
+}
+
+// Close gzipped file
+gzfilebuf*
+gzfilebuf::close()
+{
+ // Fail immediately if no file is open
+ if (!this->is_open())
+ return NULL;
+ // Assume success
+ gzfilebuf* retval = this;
+ // Attempt to sync and close gzipped file
+ if (this->sync() == -1)
+ retval = NULL;
+ if (gzclose(file) < 0)
+ retval = NULL;
+ // File is now gone anyway (postcondition [27.8.1.3.8])
+ file = NULL;
+ own_fd = false;
+ // Destroy internal buffer if it exists
+ this->disable_buffer();
+ return retval;
+}
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+// Convert int open mode to mode string
+bool
+gzfilebuf::open_mode(std::ios_base::openmode mode,
+ char* c_mode) const
+{
+ bool testb = mode & std::ios_base::binary;
+ bool testi = mode & std::ios_base::in;
+ bool testo = mode & std::ios_base::out;
+ bool testt = mode & std::ios_base::trunc;
+ bool testa = mode & std::ios_base::app;
+
+ // Check for valid flag combinations - see [27.8.1.3.2] (Table 92)
+ // Original zfstream hardcoded the compression level to maximum here...
+ // Double the time for less than 1% size improvement seems
+ // excessive though - keeping it at the default level
+ // To change back, just append "9" to the next three mode strings
+ if (!testi && testo && !testt && !testa)
+ strcpy(c_mode, "w");
+ if (!testi && testo && !testt && testa)
+ strcpy(c_mode, "a");
+ if (!testi && testo && testt && !testa)
+ strcpy(c_mode, "w");
+ if (testi && !testo && !testt && !testa)
+ strcpy(c_mode, "r");
+ // No read/write mode yet
+// if (testi && testo && !testt && !testa)
+// strcpy(c_mode, "r+");
+// if (testi && testo && testt && !testa)
+// strcpy(c_mode, "w+");
+
+ // Mode string should be empty for invalid combination of flags
+ if (strlen(c_mode) == 0)
+ return false;
+ if (testb)
+ strcat(c_mode, "b");
+ return true;
+}
+
+// Determine number of characters in internal get buffer
+std::streamsize
+gzfilebuf::showmanyc()
+{
+ // Calls to underflow will fail if file not opened for reading
+ if (!this->is_open() || !(io_mode & std::ios_base::in))
+ return -1;
+ // Make sure get area is in use
+ if (this->gptr() && (this->gptr() < this->egptr()))
+ return std::streamsize(this->egptr() - this->gptr());
+ else
+ return 0;
+}
+
+// Fill get area from gzipped file
+gzfilebuf::int_type
+gzfilebuf::underflow()
+{
+ // If something is left in the get area by chance, return it
+ // (this shouldn't normally happen, as underflow is only supposed
+ // to be called when gptr >= egptr, but it serves as error check)
+ if (this->gptr() && (this->gptr() < this->egptr()))
+ return traits_type::to_int_type(*(this->gptr()));
+
+ // If the file hasn't been opened for reading, produce error
+ if (!this->is_open() || !(io_mode & std::ios_base::in))
+ return traits_type::eof();
+
+ // Attempt to fill internal buffer from gzipped file
+ // (buffer must be guaranteed to exist...)
+ int bytes_read = gzread(file, buffer, buffer_size);
+ // Indicates error or EOF
+ if (bytes_read <= 0)
+ {
+ // Reset get area
+ this->setg(buffer, buffer, buffer);
+ return traits_type::eof();
+ }
+ // Make all bytes read from file available as get area
+ this->setg(buffer, buffer, buffer + bytes_read);
+
+ // Return next character in get area
+ return traits_type::to_int_type(*(this->gptr()));
+}
+
+// Write put area to gzipped file
+gzfilebuf::int_type
+gzfilebuf::overflow(int_type c)
+{
+ // Determine whether put area is in use
+ if (this->pbase())
+ {
+ // Double-check pointer range
+ if (this->pptr() > this->epptr() || this->pptr() < this->pbase())
+ return traits_type::eof();
+ // Add extra character to buffer if not EOF
+ if (!traits_type::eq_int_type(c, traits_type::eof()))
+ {
+ *(this->pptr()) = traits_type::to_char_type(c);
+ this->pbump(1);
+ }
+ // Number of characters to write to file
+ int bytes_to_write = this->pptr() - this->pbase();
+ // Overflow doesn't fail if nothing is to be written
+ if (bytes_to_write > 0)
+ {
+ // If the file hasn't been opened for writing, produce error
+ if (!this->is_open() || !(io_mode & std::ios_base::out))
+ return traits_type::eof();
+ // If gzipped file won't accept all bytes written to it, fail
+ if (gzwrite(file, this->pbase(), bytes_to_write) != bytes_to_write)
+ return traits_type::eof();
+ // Reset next pointer to point to pbase on success
+ this->pbump(-bytes_to_write);
+ }
+ }
+ // Write extra character to file if not EOF
+ else if (!traits_type::eq_int_type(c, traits_type::eof()))
+ {
+ // If the file hasn't been opened for writing, produce error
+ if (!this->is_open() || !(io_mode & std::ios_base::out))
+ return traits_type::eof();
+ // Impromptu char buffer (allows "unbuffered" output)
+ char_type last_char = traits_type::to_char_type(c);
+ // If gzipped file won't accept this character, fail
+ if (gzwrite(file, &last_char, 1) != 1)
+ return traits_type::eof();
+ }
+
+ // If you got here, you have succeeded (even if c was EOF)
+ // The return value should therefore be non-EOF
+ if (traits_type::eq_int_type(c, traits_type::eof()))
+ return traits_type::not_eof(c);
+ else
+ return c;
+}
+
+// Assign new buffer
+std::streambuf*
+gzfilebuf::setbuf(char_type* p,
+ std::streamsize n)
+{
+ // First make sure stuff is sync'ed, for safety
+ if (this->sync() == -1)
+ return NULL;
+ // If buffering is turned off on purpose via setbuf(0,0), still allocate one...
+ // "Unbuffered" only really refers to put [27.8.1.4.10], while get needs at
+ // least a buffer of size 1 (very inefficient though, therefore make it bigger?)
+ // This follows from [27.5.2.4.3]/12 (gptr needs to point at something, it seems)
+ if (!p || !n)
+ {
+ // Replace existing buffer (if any) with small internal buffer
+ this->disable_buffer();
+ buffer = NULL;
+ buffer_size = 0;
+ own_buffer = true;
+ this->enable_buffer();
+ }
+ else
+ {
+ // Replace existing buffer (if any) with external buffer
+ this->disable_buffer();
+ buffer = p;
+ buffer_size = n;
+ own_buffer = false;
+ this->enable_buffer();
+ }
+ return this;
+}
+
+// Write put area to gzipped file (i.e. ensures that put area is empty)
+int
+gzfilebuf::sync()
+{
+ return traits_type::eq_int_type(this->overflow(), traits_type::eof()) ? -1 : 0;
+}
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+// Allocate internal buffer
+void
+gzfilebuf::enable_buffer()
+{
+ // If internal buffer required, allocate one
+ if (own_buffer && !buffer)
+ {
+ // Check for buffered vs. "unbuffered"
+ if (buffer_size > 0)
+ {
+ // Allocate internal buffer
+ buffer = new char_type[buffer_size];
+ // Get area starts empty and will be expanded by underflow as need arises
+ this->setg(buffer, buffer, buffer);
+ // Setup entire internal buffer as put area.
+ // The one-past-end pointer actually points to the last element of the buffer,
+ // so that overflow(c) can safely add the extra character c to the sequence.
+ // These pointers remain in place for the duration of the buffer
+ this->setp(buffer, buffer + buffer_size - 1);
+ }
+ else
+ {
+ // Even in "unbuffered" case, (small?) get buffer is still required
+ buffer_size = SMALLBUFSIZE;
+ buffer = new char_type[buffer_size];
+ this->setg(buffer, buffer, buffer);
+ // "Unbuffered" means no put buffer
+ this->setp(0, 0);
+ }
+ }
+ else
+ {
+ // If buffer already allocated, reset buffer pointers just to make sure no
+ // stale chars are lying around
+ this->setg(buffer, buffer, buffer);
+ this->setp(buffer, buffer + buffer_size - 1);
+ }
+}
+
+// Destroy internal buffer
+void
+gzfilebuf::disable_buffer()
+{
+ // If internal buffer exists, deallocate it
+ if (own_buffer && buffer)
+ {
+ // Preserve unbuffered status by zeroing size
+ if (!this->pbase())
+ buffer_size = 0;
+ delete[] buffer;
+ buffer = NULL;
+ this->setg(0, 0, 0);
+ this->setp(0, 0);
+ }
+ else
+ {
+ // Reset buffer pointers to initial state if external buffer exists
+ this->setg(buffer, buffer, buffer);
+ if (buffer)
+ this->setp(buffer, buffer + buffer_size - 1);
+ else
+ this->setp(0, 0);
+ }
+}
+
+/*****************************************************************************/
+
+// Default constructor initializes stream buffer
+gzifstream::gzifstream()
+: std::istream(NULL), sb()
+{ this->init(&sb); }
+
+// Initialize stream buffer and open file
+gzifstream::gzifstream(const char* name,
+ std::ios_base::openmode mode)
+: std::istream(NULL), sb()
+{
+ this->init(&sb);
+ this->open(name, mode);
+}
+
+// Initialize stream buffer and attach to file
+gzifstream::gzifstream(int fd,
+ std::ios_base::openmode mode)
+: std::istream(NULL), sb()
+{
+ this->init(&sb);
+ this->attach(fd, mode);
+}
+
+// Open file and go into fail() state if unsuccessful
+void
+gzifstream::open(const char* name,
+ std::ios_base::openmode mode)
+{
+ if (!sb.open(name, mode | std::ios_base::in))
+ this->setstate(std::ios_base::failbit);
+ else
+ this->clear();
+}
+
+// Attach to file and go into fail() state if unsuccessful
+void
+gzifstream::attach(int fd,
+ std::ios_base::openmode mode)
+{
+ if (!sb.attach(fd, mode | std::ios_base::in))
+ this->setstate(std::ios_base::failbit);
+ else
+ this->clear();
+}
+
+// Close file
+void
+gzifstream::close()
+{
+ if (!sb.close())
+ this->setstate(std::ios_base::failbit);
+}
+
+/*****************************************************************************/
+
+// Default constructor initializes stream buffer
+gzofstream::gzofstream()
+: std::ostream(NULL), sb()
+{ this->init(&sb); }
+
+// Initialize stream buffer and open file
+gzofstream::gzofstream(const char* name,
+ std::ios_base::openmode mode)
+: std::ostream(NULL), sb()
+{
+ this->init(&sb);
+ this->open(name, mode);
+}
+
+// Initialize stream buffer and attach to file
+gzofstream::gzofstream(int fd,
+ std::ios_base::openmode mode)
+: std::ostream(NULL), sb()
+{
+ this->init(&sb);
+ this->attach(fd, mode);
+}
+
+// Open file and go into fail() state if unsuccessful
+void
+gzofstream::open(const char* name,
+ std::ios_base::openmode mode)
+{
+ if (!sb.open(name, mode | std::ios_base::out))
+ this->setstate(std::ios_base::failbit);
+ else
+ this->clear();
+}
+
+// Attach to file and go into fail() state if unsuccessful
+void
+gzofstream::attach(int fd,
+ std::ios_base::openmode mode)
+{
+ if (!sb.attach(fd, mode | std::ios_base::out))
+ this->setstate(std::ios_base::failbit);
+ else
+ this->clear();
+}
+
+// Close file
+void
+gzofstream::close()
+{
+ if (!sb.close())
+ this->setstate(std::ios_base::failbit);
+}
ADDED compat/zlib/contrib/iostream3/zfstream.h
Index: compat/zlib/contrib/iostream3/zfstream.h
==================================================================
--- compat/zlib/contrib/iostream3/zfstream.h
+++ compat/zlib/contrib/iostream3/zfstream.h
@@ -0,0 +1,466 @@
+/*
+ * A C++ I/O streams interface to the zlib gz* functions
+ *
+ * by Ludwig Schwardt
+ * original version by Kevin Ruland
+ *
+ * This version is standard-compliant and compatible with gcc 3.x.
+ */
+
+#ifndef ZFSTREAM_H
+#define ZFSTREAM_H
+
+#include // not iostream, since we don't need cin/cout
+#include
+#include "zlib.h"
+
+/*****************************************************************************/
+
+/**
+ * @brief Gzipped file stream buffer class.
+ *
+ * This class implements basic_filebuf for gzipped files. It doesn't yet support
+ * seeking (allowed by zlib but slow/limited), putback and read/write access
+ * (tricky). Otherwise, it attempts to be a drop-in replacement for the standard
+ * file streambuf.
+*/
+class gzfilebuf : public std::streambuf
+{
+public:
+ // Default constructor.
+ gzfilebuf();
+
+ // Destructor.
+ virtual
+ ~gzfilebuf();
+
+ /**
+ * @brief Set compression level and strategy on the fly.
+ * @param comp_level Compression level (see zlib.h for allowed values)
+ * @param comp_strategy Compression strategy (see zlib.h for allowed values)
+ * @return Z_OK on success, Z_STREAM_ERROR otherwise.
+ *
+ * Unfortunately, these parameters cannot be modified separately, as the
+ * previous zfstream version assumed. Since the strategy is seldom changed,
+ * it can default and setcompression(level) then becomes like the old
+ * setcompressionlevel(level).
+ */
+ int
+ setcompression(int comp_level,
+ int comp_strategy = Z_DEFAULT_STRATEGY);
+
+ /**
+ * @brief Check if file is open.
+ * @return True if file is open.
+ */
+ bool
+ is_open() const { return (file != NULL); }
+
+ /**
+ * @brief Open gzipped file.
+ * @param name File name.
+ * @param mode Open mode flags.
+ * @return @c this on success, NULL on failure.
+ */
+ gzfilebuf*
+ open(const char* name,
+ std::ios_base::openmode mode);
+
+ /**
+ * @brief Attach to already open gzipped file.
+ * @param fd File descriptor.
+ * @param mode Open mode flags.
+ * @return @c this on success, NULL on failure.
+ */
+ gzfilebuf*
+ attach(int fd,
+ std::ios_base::openmode mode);
+
+ /**
+ * @brief Close gzipped file.
+ * @return @c this on success, NULL on failure.
+ */
+ gzfilebuf*
+ close();
+
+protected:
+ /**
+ * @brief Convert ios open mode int to mode string used by zlib.
+ * @return True if valid mode flag combination.
+ */
+ bool
+ open_mode(std::ios_base::openmode mode,
+ char* c_mode) const;
+
+ /**
+ * @brief Number of characters available in stream buffer.
+ * @return Number of characters.
+ *
+ * This indicates number of characters in get area of stream buffer.
+ * These characters can be read without accessing the gzipped file.
+ */
+ virtual std::streamsize
+ showmanyc();
+
+ /**
+ * @brief Fill get area from gzipped file.
+ * @return First character in get area on success, EOF on error.
+ *
+ * This actually reads characters from gzipped file to stream
+ * buffer. Always buffered.
+ */
+ virtual int_type
+ underflow();
+
+ /**
+ * @brief Write put area to gzipped file.
+ * @param c Extra character to add to buffer contents.
+ * @return Non-EOF on success, EOF on error.
+ *
+ * This actually writes characters in stream buffer to
+ * gzipped file. With unbuffered output this is done one
+ * character at a time.
+ */
+ virtual int_type
+ overflow(int_type c = traits_type::eof());
+
+ /**
+ * @brief Installs external stream buffer.
+ * @param p Pointer to char buffer.
+ * @param n Size of external buffer.
+ * @return @c this on success, NULL on failure.
+ *
+ * Call setbuf(0,0) to enable unbuffered output.
+ */
+ virtual std::streambuf*
+ setbuf(char_type* p,
+ std::streamsize n);
+
+ /**
+ * @brief Flush stream buffer to file.
+ * @return 0 on success, -1 on error.
+ *
+ * This calls underflow(EOF) to do the job.
+ */
+ virtual int
+ sync();
+
+//
+// Some future enhancements
+//
+// virtual int_type uflow();
+// virtual int_type pbackfail(int_type c = traits_type::eof());
+// virtual pos_type
+// seekoff(off_type off,
+// std::ios_base::seekdir way,
+// std::ios_base::openmode mode = std::ios_base::in|std::ios_base::out);
+// virtual pos_type
+// seekpos(pos_type sp,
+// std::ios_base::openmode mode = std::ios_base::in|std::ios_base::out);
+
+private:
+ /**
+ * @brief Allocate internal buffer.
+ *
+ * This function is safe to call multiple times. It will ensure
+ * that a proper internal buffer exists if it is required. If the
+ * buffer already exists or is external, the buffer pointers will be
+ * reset to their original state.
+ */
+ void
+ enable_buffer();
+
+ /**
+ * @brief Destroy internal buffer.
+ *
+ * This function is safe to call multiple times. It will ensure
+ * that the internal buffer is deallocated if it exists. In any
+ * case, it will also reset the buffer pointers.
+ */
+ void
+ disable_buffer();
+
+ /**
+ * Underlying file pointer.
+ */
+ gzFile file;
+
+ /**
+ * Mode in which file was opened.
+ */
+ std::ios_base::openmode io_mode;
+
+ /**
+ * @brief True if this object owns file descriptor.
+ *
+ * This makes the class responsible for closing the file
+ * upon destruction.
+ */
+ bool own_fd;
+
+ /**
+ * @brief Stream buffer.
+ *
+ * For simplicity this remains allocated on the free store for the
+ * entire life span of the gzfilebuf object, unless replaced by setbuf.
+ */
+ char_type* buffer;
+
+ /**
+ * @brief Stream buffer size.
+ *
+ * Defaults to system default buffer size (typically 8192 bytes).
+ * Modified by setbuf.
+ */
+ std::streamsize buffer_size;
+
+ /**
+ * @brief True if this object owns stream buffer.
+ *
+ * This makes the class responsible for deleting the buffer
+ * upon destruction.
+ */
+ bool own_buffer;
+};
+
+/*****************************************************************************/
+
+/**
+ * @brief Gzipped file input stream class.
+ *
+ * This class implements ifstream for gzipped files. Seeking and putback
+ * is not supported yet.
+*/
+class gzifstream : public std::istream
+{
+public:
+ // Default constructor
+ gzifstream();
+
+ /**
+ * @brief Construct stream on gzipped file to be opened.
+ * @param name File name.
+ * @param mode Open mode flags (forced to contain ios::in).
+ */
+ explicit
+ gzifstream(const char* name,
+ std::ios_base::openmode mode = std::ios_base::in);
+
+ /**
+ * @brief Construct stream on already open gzipped file.
+ * @param fd File descriptor.
+ * @param mode Open mode flags (forced to contain ios::in).
+ */
+ explicit
+ gzifstream(int fd,
+ std::ios_base::openmode mode = std::ios_base::in);
+
+ /**
+ * Obtain underlying stream buffer.
+ */
+ gzfilebuf*
+ rdbuf() const
+ { return const_cast(&sb); }
+
+ /**
+ * @brief Check if file is open.
+ * @return True if file is open.
+ */
+ bool
+ is_open() { return sb.is_open(); }
+
+ /**
+ * @brief Open gzipped file.
+ * @param name File name.
+ * @param mode Open mode flags (forced to contain ios::in).
+ *
+ * Stream will be in state good() if file opens successfully;
+ * otherwise in state fail(). This differs from the behavior of
+ * ifstream, which never sets the state to good() and therefore
+ * won't allow you to reuse the stream for a second file unless
+ * you manually clear() the state. The choice is a matter of
+ * convenience.
+ */
+ void
+ open(const char* name,
+ std::ios_base::openmode mode = std::ios_base::in);
+
+ /**
+ * @brief Attach to already open gzipped file.
+ * @param fd File descriptor.
+ * @param mode Open mode flags (forced to contain ios::in).
+ *
+ * Stream will be in state good() if attach succeeded; otherwise
+ * in state fail().
+ */
+ void
+ attach(int fd,
+ std::ios_base::openmode mode = std::ios_base::in);
+
+ /**
+ * @brief Close gzipped file.
+ *
+ * Stream will be in state fail() if close failed.
+ */
+ void
+ close();
+
+private:
+ /**
+ * Underlying stream buffer.
+ */
+ gzfilebuf sb;
+};
+
+/*****************************************************************************/
+
+/**
+ * @brief Gzipped file output stream class.
+ *
+ * This class implements ofstream for gzipped files. Seeking and putback
+ * is not supported yet.
+*/
+class gzofstream : public std::ostream
+{
+public:
+ // Default constructor
+ gzofstream();
+
+ /**
+ * @brief Construct stream on gzipped file to be opened.
+ * @param name File name.
+ * @param mode Open mode flags (forced to contain ios::out).
+ */
+ explicit
+ gzofstream(const char* name,
+ std::ios_base::openmode mode = std::ios_base::out);
+
+ /**
+ * @brief Construct stream on already open gzipped file.
+ * @param fd File descriptor.
+ * @param mode Open mode flags (forced to contain ios::out).
+ */
+ explicit
+ gzofstream(int fd,
+ std::ios_base::openmode mode = std::ios_base::out);
+
+ /**
+ * Obtain underlying stream buffer.
+ */
+ gzfilebuf*
+ rdbuf() const
+ { return const_cast(&sb); }
+
+ /**
+ * @brief Check if file is open.
+ * @return True if file is open.
+ */
+ bool
+ is_open() { return sb.is_open(); }
+
+ /**
+ * @brief Open gzipped file.
+ * @param name File name.
+ * @param mode Open mode flags (forced to contain ios::out).
+ *
+ * Stream will be in state good() if file opens successfully;
+ * otherwise in state fail(). This differs from the behavior of
+ * ofstream, which never sets the state to good() and therefore
+ * won't allow you to reuse the stream for a second file unless
+ * you manually clear() the state. The choice is a matter of
+ * convenience.
+ */
+ void
+ open(const char* name,
+ std::ios_base::openmode mode = std::ios_base::out);
+
+ /**
+ * @brief Attach to already open gzipped file.
+ * @param fd File descriptor.
+ * @param mode Open mode flags (forced to contain ios::out).
+ *
+ * Stream will be in state good() if attach succeeded; otherwise
+ * in state fail().
+ */
+ void
+ attach(int fd,
+ std::ios_base::openmode mode = std::ios_base::out);
+
+ /**
+ * @brief Close gzipped file.
+ *
+ * Stream will be in state fail() if close failed.
+ */
+ void
+ close();
+
+private:
+ /**
+ * Underlying stream buffer.
+ */
+ gzfilebuf sb;
+};
+
+/*****************************************************************************/
+
+/**
+ * @brief Gzipped file output stream manipulator class.
+ *
+ * This class defines a two-argument manipulator for gzofstream. It is used
+ * as base for the setcompression(int,int) manipulator.
+*/
+template
+ class gzomanip2
+ {
+ public:
+ // Allows insertor to peek at internals
+ template
+ friend gzofstream&
+ operator<<(gzofstream&,
+ const gzomanip2&);
+
+ // Constructor
+ gzomanip2(gzofstream& (*f)(gzofstream&, T1, T2),
+ T1 v1,
+ T2 v2);
+ private:
+ // Underlying manipulator function
+ gzofstream&
+ (*func)(gzofstream&, T1, T2);
+
+ // Arguments for manipulator function
+ T1 val1;
+ T2 val2;
+ };
+
+/*****************************************************************************/
+
+// Manipulator function thunks through to stream buffer
+inline gzofstream&
+setcompression(gzofstream &gzs, int l, int s = Z_DEFAULT_STRATEGY)
+{
+ (gzs.rdbuf())->setcompression(l, s);
+ return gzs;
+}
+
+// Manipulator constructor stores arguments
+template
+ inline
+ gzomanip2::gzomanip2(gzofstream &(*f)(gzofstream &, T1, T2),
+ T1 v1,
+ T2 v2)
+ : func(f), val1(v1), val2(v2)
+ { }
+
+// Insertor applies underlying manipulator function to stream
+template
+ inline gzofstream&
+ operator<<(gzofstream& s, const gzomanip2& m)
+ { return (*m.func)(s, m.val1, m.val2); }
+
+// Insert this onto stream to simplify setting of compression level
+inline gzomanip2
+setcompression(int l, int s = Z_DEFAULT_STRATEGY)
+{ return gzomanip2(&setcompression, l, s); }
+
+#endif // ZFSTREAM_H
ADDED compat/zlib/contrib/masmx64/bld_ml64.bat
Index: compat/zlib/contrib/masmx64/bld_ml64.bat
==================================================================
--- compat/zlib/contrib/masmx64/bld_ml64.bat
+++ compat/zlib/contrib/masmx64/bld_ml64.bat
@@ -0,0 +1,2 @@
+ml64.exe /Flinffasx64 /c /Zi inffasx64.asm
+ml64.exe /Flgvmat64 /c /Zi gvmat64.asm
ADDED compat/zlib/contrib/masmx64/gvmat64.asm
Index: compat/zlib/contrib/masmx64/gvmat64.asm
==================================================================
--- compat/zlib/contrib/masmx64/gvmat64.asm
+++ compat/zlib/contrib/masmx64/gvmat64.asm
@@ -0,0 +1,553 @@
+;uInt longest_match_x64(
+; deflate_state *s,
+; IPos cur_match); /* current match */
+
+; gvmat64.asm -- Asm portion of the optimized longest_match for 32 bits x86_64
+; (AMD64 on Athlon 64, Opteron, Phenom
+; and Intel EM64T on Pentium 4 with EM64T, Pentium D, Core 2 Duo, Core I5/I7)
+; Copyright (C) 1995-2010 Jean-loup Gailly, Brian Raiter and Gilles Vollant.
+;
+; File written by Gilles Vollant, by converting to assembly the longest_match
+; from Jean-loup Gailly in deflate.c of zLib and infoZip zip.
+;
+; and by taking inspiration on asm686 with masm, optimised assembly code
+; from Brian Raiter, written 1998
+;
+; This software is provided 'as-is', without any express or implied
+; warranty. In no event will the authors be held liable for any damages
+; arising from the use of this software.
+;
+; Permission is granted to anyone to use this software for any purpose,
+; including commercial applications, and to alter it and redistribute it
+; freely, subject to the following restrictions:
+;
+; 1. The origin of this software must not be misrepresented; you must not
+; claim that you wrote the original software. If you use this software
+; in a product, an acknowledgment in the product documentation would be
+; appreciated but is not required.
+; 2. Altered source versions must be plainly marked as such, and must not be
+; misrepresented as being the original software
+; 3. This notice may not be removed or altered from any source distribution.
+;
+;
+;
+; http://www.zlib.net
+; http://www.winimage.com/zLibDll
+; http://www.muppetlabs.com/~breadbox/software/assembly.html
+;
+; to compile this file for infozip Zip, I use option:
+; ml64.exe /Flgvmat64 /c /Zi /DINFOZIP gvmat64.asm
+;
+; to compile this file for zLib, I use option:
+; ml64.exe /Flgvmat64 /c /Zi gvmat64.asm
+; Be carrefull to adapt zlib1222add below to your version of zLib
+; (if you use a version of zLib before 1.0.4 or after 1.2.2.2, change
+; value of zlib1222add later)
+;
+; This file compile with Microsoft Macro Assembler (x64) for AMD64
+;
+; ml64.exe is given with Visual Studio 2005/2008/2010 and Windows WDK
+;
+; (you can get Windows WDK with ml64 for AMD64 from
+; http://www.microsoft.com/whdc/Devtools/wdk/default.mspx for low price)
+;
+
+
+;uInt longest_match(s, cur_match)
+; deflate_state *s;
+; IPos cur_match; /* current match */
+.code
+longest_match PROC
+
+
+;LocalVarsSize equ 88
+ LocalVarsSize equ 72
+
+; register used : rax,rbx,rcx,rdx,rsi,rdi,r8,r9,r10,r11,r12
+; free register : r14,r15
+; register can be saved : rsp
+
+ chainlenwmask equ rsp + 8 - LocalVarsSize ; high word: current chain len
+ ; low word: s->wmask
+;window equ rsp + xx - LocalVarsSize ; local copy of s->window ; stored in r10
+;windowbestlen equ rsp + xx - LocalVarsSize ; s->window + bestlen , use r10+r11
+;scanstart equ rsp + xx - LocalVarsSize ; first two bytes of string ; stored in r12w
+;scanend equ rsp + xx - LocalVarsSize ; last two bytes of string use ebx
+;scanalign equ rsp + xx - LocalVarsSize ; dword-misalignment of string r13
+;bestlen equ rsp + xx - LocalVarsSize ; size of best match so far -> r11d
+;scan equ rsp + xx - LocalVarsSize ; ptr to string wanting match -> r9
+IFDEF INFOZIP
+ELSE
+ nicematch equ (rsp + 16 - LocalVarsSize) ; a good enough match size
+ENDIF
+
+save_rdi equ rsp + 24 - LocalVarsSize
+save_rsi equ rsp + 32 - LocalVarsSize
+save_rbx equ rsp + 40 - LocalVarsSize
+save_rbp equ rsp + 48 - LocalVarsSize
+save_r12 equ rsp + 56 - LocalVarsSize
+save_r13 equ rsp + 64 - LocalVarsSize
+;save_r14 equ rsp + 72 - LocalVarsSize
+;save_r15 equ rsp + 80 - LocalVarsSize
+
+
+; summary of register usage
+; scanend ebx
+; scanendw bx
+; chainlenwmask edx
+; curmatch rsi
+; curmatchd esi
+; windowbestlen r8
+; scanalign r9
+; scanalignd r9d
+; window r10
+; bestlen r11
+; bestlend r11d
+; scanstart r12d
+; scanstartw r12w
+; scan r13
+; nicematch r14d
+; limit r15
+; limitd r15d
+; prev rcx
+
+; all the +4 offsets are due to the addition of pending_buf_size (in zlib
+; in the deflate_state structure since the asm code was first written
+; (if you compile with zlib 1.0.4 or older, remove the +4).
+; Note : these value are good with a 8 bytes boundary pack structure
+
+
+ MAX_MATCH equ 258
+ MIN_MATCH equ 3
+ MIN_LOOKAHEAD equ (MAX_MATCH+MIN_MATCH+1)
+
+
+;;; Offsets for fields in the deflate_state structure. These numbers
+;;; are calculated from the definition of deflate_state, with the
+;;; assumption that the compiler will dword-align the fields. (Thus,
+;;; changing the definition of deflate_state could easily cause this
+;;; program to crash horribly, without so much as a warning at
+;;; compile time. Sigh.)
+
+; all the +zlib1222add offsets are due to the addition of fields
+; in zlib in the deflate_state structure since the asm code was first written
+; (if you compile with zlib 1.0.4 or older, use "zlib1222add equ (-4)").
+; (if you compile with zlib between 1.0.5 and 1.2.2.1, use "zlib1222add equ 0").
+; if you compile with zlib 1.2.2.2 or later , use "zlib1222add equ 8").
+
+
+IFDEF INFOZIP
+
+_DATA SEGMENT
+COMM window_size:DWORD
+; WMask ; 7fff
+COMM window:BYTE:010040H
+COMM prev:WORD:08000H
+; MatchLen : unused
+; PrevMatch : unused
+COMM strstart:DWORD
+COMM match_start:DWORD
+; Lookahead : ignore
+COMM prev_length:DWORD ; PrevLen
+COMM max_chain_length:DWORD
+COMM good_match:DWORD
+COMM nice_match:DWORD
+prev_ad equ OFFSET prev
+window_ad equ OFFSET window
+nicematch equ nice_match
+_DATA ENDS
+WMask equ 07fffh
+
+ELSE
+
+ IFNDEF zlib1222add
+ zlib1222add equ 8
+ ENDIF
+dsWSize equ 56+zlib1222add+(zlib1222add/2)
+dsWMask equ 64+zlib1222add+(zlib1222add/2)
+dsWindow equ 72+zlib1222add
+dsPrev equ 88+zlib1222add
+dsMatchLen equ 128+zlib1222add
+dsPrevMatch equ 132+zlib1222add
+dsStrStart equ 140+zlib1222add
+dsMatchStart equ 144+zlib1222add
+dsLookahead equ 148+zlib1222add
+dsPrevLen equ 152+zlib1222add
+dsMaxChainLen equ 156+zlib1222add
+dsGoodMatch equ 172+zlib1222add
+dsNiceMatch equ 176+zlib1222add
+
+window_size equ [ rcx + dsWSize]
+WMask equ [ rcx + dsWMask]
+window_ad equ [ rcx + dsWindow]
+prev_ad equ [ rcx + dsPrev]
+strstart equ [ rcx + dsStrStart]
+match_start equ [ rcx + dsMatchStart]
+Lookahead equ [ rcx + dsLookahead] ; 0ffffffffh on infozip
+prev_length equ [ rcx + dsPrevLen]
+max_chain_length equ [ rcx + dsMaxChainLen]
+good_match equ [ rcx + dsGoodMatch]
+nice_match equ [ rcx + dsNiceMatch]
+ENDIF
+
+; parameter 1 in r8(deflate state s), param 2 in rdx (cur match)
+
+; see http://weblogs.asp.net/oldnewthing/archive/2004/01/14/58579.aspx and
+; http://msdn.microsoft.com/library/en-us/kmarch/hh/kmarch/64bitAMD_8e951dd2-ee77-4728-8702-55ce4b5dd24a.xml.asp
+;
+; All registers must be preserved across the call, except for
+; rax, rcx, rdx, r8, r9, r10, and r11, which are scratch.
+
+
+
+;;; Save registers that the compiler may be using, and adjust esp to
+;;; make room for our stack frame.
+
+
+;;; Retrieve the function arguments. r8d will hold cur_match
+;;; throughout the entire function. edx will hold the pointer to the
+;;; deflate_state structure during the function's setup (before
+;;; entering the main loop.
+
+; parameter 1 in rcx (deflate_state* s), param 2 in edx -> r8 (cur match)
+
+; this clear high 32 bits of r8, which can be garbage in both r8 and rdx
+
+ mov [save_rdi],rdi
+ mov [save_rsi],rsi
+ mov [save_rbx],rbx
+ mov [save_rbp],rbp
+IFDEF INFOZIP
+ mov r8d,ecx
+ELSE
+ mov r8d,edx
+ENDIF
+ mov [save_r12],r12
+ mov [save_r13],r13
+; mov [save_r14],r14
+; mov [save_r15],r15
+
+
+;;; uInt wmask = s->w_mask;
+;;; unsigned chain_length = s->max_chain_length;
+;;; if (s->prev_length >= s->good_match) {
+;;; chain_length >>= 2;
+;;; }
+
+ mov edi, prev_length
+ mov esi, good_match
+ mov eax, WMask
+ mov ebx, max_chain_length
+ cmp edi, esi
+ jl LastMatchGood
+ shr ebx, 2
+LastMatchGood:
+
+;;; chainlen is decremented once beforehand so that the function can
+;;; use the sign flag instead of the zero flag for the exit test.
+;;; It is then shifted into the high word, to make room for the wmask
+;;; value, which it will always accompany.
+
+ dec ebx
+ shl ebx, 16
+ or ebx, eax
+
+;;; on zlib only
+;;; if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead;
+
+IFDEF INFOZIP
+ mov [chainlenwmask], ebx
+; on infozip nice_match = [nice_match]
+ELSE
+ mov eax, nice_match
+ mov [chainlenwmask], ebx
+ mov r10d, Lookahead
+ cmp r10d, eax
+ cmovnl r10d, eax
+ mov [nicematch],r10d
+ENDIF
+
+;;; register Bytef *scan = s->window + s->strstart;
+ mov r10, window_ad
+ mov ebp, strstart
+ lea r13, [r10 + rbp]
+
+;;; Determine how many bytes the scan ptr is off from being
+;;; dword-aligned.
+
+ mov r9,r13
+ neg r13
+ and r13,3
+
+;;; IPos limit = s->strstart > (IPos)MAX_DIST(s) ?
+;;; s->strstart - (IPos)MAX_DIST(s) : NIL;
+IFDEF INFOZIP
+ mov eax,07efah ; MAX_DIST = (WSIZE-MIN_LOOKAHEAD) (0x8000-(3+8+1))
+ELSE
+ mov eax, window_size
+ sub eax, MIN_LOOKAHEAD
+ENDIF
+ xor edi,edi
+ sub ebp, eax
+
+ mov r11d, prev_length
+
+ cmovng ebp,edi
+
+;;; int best_len = s->prev_length;
+
+
+;;; Store the sum of s->window + best_len in esi locally, and in esi.
+
+ lea rsi,[r10+r11]
+
+;;; register ush scan_start = *(ushf*)scan;
+;;; register ush scan_end = *(ushf*)(scan+best_len-1);
+;;; Posf *prev = s->prev;
+
+ movzx r12d,word ptr [r9]
+ movzx ebx, word ptr [r9 + r11 - 1]
+
+ mov rdi, prev_ad
+
+;;; Jump into the main loop.
+
+ mov edx, [chainlenwmask]
+
+ cmp bx,word ptr [rsi + r8 - 1]
+ jz LookupLoopIsZero
+
+LookupLoop1:
+ and r8d, edx
+
+ movzx r8d, word ptr [rdi + r8*2]
+ cmp r8d, ebp
+ jbe LeaveNow
+ sub edx, 00010000h
+ js LeaveNow
+
+LoopEntry1:
+ cmp bx,word ptr [rsi + r8 - 1]
+ jz LookupLoopIsZero
+
+LookupLoop2:
+ and r8d, edx
+
+ movzx r8d, word ptr [rdi + r8*2]
+ cmp r8d, ebp
+ jbe LeaveNow
+ sub edx, 00010000h
+ js LeaveNow
+
+LoopEntry2:
+ cmp bx,word ptr [rsi + r8 - 1]
+ jz LookupLoopIsZero
+
+LookupLoop4:
+ and r8d, edx
+
+ movzx r8d, word ptr [rdi + r8*2]
+ cmp r8d, ebp
+ jbe LeaveNow
+ sub edx, 00010000h
+ js LeaveNow
+
+LoopEntry4:
+
+ cmp bx,word ptr [rsi + r8 - 1]
+ jnz LookupLoop1
+ jmp LookupLoopIsZero
+
+
+;;; do {
+;;; match = s->window + cur_match;
+;;; if (*(ushf*)(match+best_len-1) != scan_end ||
+;;; *(ushf*)match != scan_start) continue;
+;;; [...]
+;;; } while ((cur_match = prev[cur_match & wmask]) > limit
+;;; && --chain_length != 0);
+;;;
+;;; Here is the inner loop of the function. The function will spend the
+;;; majority of its time in this loop, and majority of that time will
+;;; be spent in the first ten instructions.
+;;;
+;;; Within this loop:
+;;; ebx = scanend
+;;; r8d = curmatch
+;;; edx = chainlenwmask - i.e., ((chainlen << 16) | wmask)
+;;; esi = windowbestlen - i.e., (window + bestlen)
+;;; edi = prev
+;;; ebp = limit
+
+LookupLoop:
+ and r8d, edx
+
+ movzx r8d, word ptr [rdi + r8*2]
+ cmp r8d, ebp
+ jbe LeaveNow
+ sub edx, 00010000h
+ js LeaveNow
+
+LoopEntry:
+
+ cmp bx,word ptr [rsi + r8 - 1]
+ jnz LookupLoop1
+LookupLoopIsZero:
+ cmp r12w, word ptr [r10 + r8]
+ jnz LookupLoop1
+
+
+;;; Store the current value of chainlen.
+ mov [chainlenwmask], edx
+
+;;; Point edi to the string under scrutiny, and esi to the string we
+;;; are hoping to match it up with. In actuality, esi and edi are
+;;; both pointed (MAX_MATCH_8 - scanalign) bytes ahead, and edx is
+;;; initialized to -(MAX_MATCH_8 - scanalign).
+
+ lea rsi,[r8+r10]
+ mov rdx, 0fffffffffffffef8h; -(MAX_MATCH_8)
+ lea rsi, [rsi + r13 + 0108h] ;MAX_MATCH_8]
+ lea rdi, [r9 + r13 + 0108h] ;MAX_MATCH_8]
+
+ prefetcht1 [rsi+rdx]
+ prefetcht1 [rdi+rdx]
+
+
+;;; Test the strings for equality, 8 bytes at a time. At the end,
+;;; adjust rdx so that it is offset to the exact byte that mismatched.
+;;;
+;;; We already know at this point that the first three bytes of the
+;;; strings match each other, and they can be safely passed over before
+;;; starting the compare loop. So what this code does is skip over 0-3
+;;; bytes, as much as necessary in order to dword-align the edi
+;;; pointer. (rsi will still be misaligned three times out of four.)
+;;;
+;;; It should be confessed that this loop usually does not represent
+;;; much of the total running time. Replacing it with a more
+;;; straightforward "rep cmpsb" would not drastically degrade
+;;; performance.
+
+
+LoopCmps:
+ mov rax, [rsi + rdx]
+ xor rax, [rdi + rdx]
+ jnz LeaveLoopCmps
+
+ mov rax, [rsi + rdx + 8]
+ xor rax, [rdi + rdx + 8]
+ jnz LeaveLoopCmps8
+
+
+ mov rax, [rsi + rdx + 8+8]
+ xor rax, [rdi + rdx + 8+8]
+ jnz LeaveLoopCmps16
+
+ add rdx,8+8+8
+
+ jnz short LoopCmps
+ jmp short LenMaximum
+LeaveLoopCmps16: add rdx,8
+LeaveLoopCmps8: add rdx,8
+LeaveLoopCmps:
+
+ test eax, 0000FFFFh
+ jnz LenLower
+
+ test eax,0ffffffffh
+
+ jnz LenLower32
+
+ add rdx,4
+ shr rax,32
+ or ax,ax
+ jnz LenLower
+
+LenLower32:
+ shr eax,16
+ add rdx,2
+LenLower: sub al, 1
+ adc rdx, 0
+;;; Calculate the length of the match. If it is longer than MAX_MATCH,
+;;; then automatically accept it as the best possible match and leave.
+
+ lea rax, [rdi + rdx]
+ sub rax, r9
+ cmp eax, MAX_MATCH
+ jge LenMaximum
+
+;;; If the length of the match is not longer than the best match we
+;;; have so far, then forget it and return to the lookup loop.
+;///////////////////////////////////
+
+ cmp eax, r11d
+ jg LongerMatch
+
+ lea rsi,[r10+r11]
+
+ mov rdi, prev_ad
+ mov edx, [chainlenwmask]
+ jmp LookupLoop
+
+;;; s->match_start = cur_match;
+;;; best_len = len;
+;;; if (len >= nice_match) break;
+;;; scan_end = *(ushf*)(scan+best_len-1);
+
+LongerMatch:
+ mov r11d, eax
+ mov match_start, r8d
+ cmp eax, [nicematch]
+ jge LeaveNow
+
+ lea rsi,[r10+rax]
+
+ movzx ebx, word ptr [r9 + rax - 1]
+ mov rdi, prev_ad
+ mov edx, [chainlenwmask]
+ jmp LookupLoop
+
+;;; Accept the current string, with the maximum possible length.
+
+LenMaximum:
+ mov r11d,MAX_MATCH
+ mov match_start, r8d
+
+;;; if ((uInt)best_len <= s->lookahead) return (uInt)best_len;
+;;; return s->lookahead;
+
+LeaveNow:
+IFDEF INFOZIP
+ mov eax,r11d
+ELSE
+ mov eax, Lookahead
+ cmp r11d, eax
+ cmovng eax, r11d
+ENDIF
+
+;;; Restore the stack and return from whence we came.
+
+
+ mov rsi,[save_rsi]
+ mov rdi,[save_rdi]
+ mov rbx,[save_rbx]
+ mov rbp,[save_rbp]
+ mov r12,[save_r12]
+ mov r13,[save_r13]
+; mov r14,[save_r14]
+; mov r15,[save_r15]
+
+
+ ret 0
+; please don't remove this string !
+; Your can freely use gvmat64 in any free or commercial app
+; but it is far better don't remove the string in the binary!
+ db 0dh,0ah,"asm686 with masm, optimised assembly code from Brian Raiter, written 1998, converted to amd 64 by Gilles Vollant 2005",0dh,0ah,0
+longest_match ENDP
+
+match_init PROC
+ ret 0
+match_init ENDP
+
+
+END
ADDED compat/zlib/contrib/masmx64/inffas8664.c
Index: compat/zlib/contrib/masmx64/inffas8664.c
==================================================================
--- compat/zlib/contrib/masmx64/inffas8664.c
+++ compat/zlib/contrib/masmx64/inffas8664.c
@@ -0,0 +1,186 @@
+/* inffas8664.c is a hand tuned assembler version of inffast.c - fast decoding
+ * version for AMD64 on Windows using Microsoft C compiler
+ *
+ * Copyright (C) 1995-2003 Mark Adler
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ *
+ * Copyright (C) 2003 Chris Anderson
+ * Please use the copyright conditions above.
+ *
+ * 2005 - Adaptation to Microsoft C Compiler for AMD64 by Gilles Vollant
+ *
+ * inffas8664.c call function inffas8664fnc in inffasx64.asm
+ * inffasx64.asm is automatically convert from AMD64 portion of inffas86.c
+ *
+ * Dec-29-2003 -- I added AMD64 inflate asm support. This version is also
+ * slightly quicker on x86 systems because, instead of using rep movsb to copy
+ * data, it uses rep movsw, which moves data in 2-byte chunks instead of single
+ * bytes. I've tested the AMD64 code on a Fedora Core 1 + the x86_64 updates
+ * from http://fedora.linux.duke.edu/fc1_x86_64
+ * which is running on an Athlon 64 3000+ / Gigabyte GA-K8VT800M system with
+ * 1GB ram. The 64-bit version is about 4% faster than the 32-bit version,
+ * when decompressing mozilla-source-1.3.tar.gz.
+ *
+ * Mar-13-2003 -- Most of this is derived from inffast.S which is derived from
+ * the gcc -S output of zlib-1.2.0/inffast.c. Zlib-1.2.0 is in beta release at
+ * the moment. I have successfully compiled and tested this code with gcc2.96,
+ * gcc3.2, icc5.0, msvc6.0. It is very close to the speed of inffast.S
+ * compiled with gcc -DNO_MMX, but inffast.S is still faster on the P3 with MMX
+ * enabled. I will attempt to merge the MMX code into this version. Newer
+ * versions of this and inffast.S can be found at
+ * http://www.eetbeetee.com/zlib/ and http://www.charm.net/~christop/zlib/
+ *
+ */
+
+#include
+#include "zutil.h"
+#include "inftrees.h"
+#include "inflate.h"
+#include "inffast.h"
+
+/* Mark Adler's comments from inffast.c: */
+
+/*
+ Decode literal, length, and distance codes and write out the resulting
+ literal and match bytes until either not enough input or output is
+ available, an end-of-block is encountered, or a data error is encountered.
+ When large enough input and output buffers are supplied to inflate(), for
+ example, a 16K input buffer and a 64K output buffer, more than 95% of the
+ inflate execution time is spent in this routine.
+
+ Entry assumptions:
+
+ state->mode == LEN
+ strm->avail_in >= 6
+ strm->avail_out >= 258
+ start >= strm->avail_out
+ state->bits < 8
+
+ On return, state->mode is one of:
+
+ LEN -- ran out of enough output space or enough available input
+ TYPE -- reached end of block code, inflate() to interpret next block
+ BAD -- error in block data
+
+ Notes:
+
+ - The maximum input bits used by a length/distance pair is 15 bits for the
+ length code, 5 bits for the length extra, 15 bits for the distance code,
+ and 13 bits for the distance extra. This totals 48 bits, or six bytes.
+ Therefore if strm->avail_in >= 6, then there is enough input to avoid
+ checking for available input while decoding.
+
+ - The maximum bytes that a single length/distance pair can output is 258
+ bytes, which is the maximum length that can be coded. inflate_fast()
+ requires strm->avail_out >= 258 for each loop to avoid checking for
+ output space.
+ */
+
+
+
+ typedef struct inffast_ar {
+/* 64 32 x86 x86_64 */
+/* ar offset register */
+/* 0 0 */ void *esp; /* esp save */
+/* 8 4 */ void *ebp; /* ebp save */
+/* 16 8 */ unsigned char FAR *in; /* esi rsi local strm->next_in */
+/* 24 12 */ unsigned char FAR *last; /* r9 while in < last */
+/* 32 16 */ unsigned char FAR *out; /* edi rdi local strm->next_out */
+/* 40 20 */ unsigned char FAR *beg; /* inflate()'s init next_out */
+/* 48 24 */ unsigned char FAR *end; /* r10 while out < end */
+/* 56 28 */ unsigned char FAR *window;/* size of window, wsize!=0 */
+/* 64 32 */ code const FAR *lcode; /* ebp rbp local strm->lencode */
+/* 72 36 */ code const FAR *dcode; /* r11 local strm->distcode */
+/* 80 40 */ size_t /*unsigned long */hold; /* edx rdx local strm->hold */
+/* 88 44 */ unsigned bits; /* ebx rbx local strm->bits */
+/* 92 48 */ unsigned wsize; /* window size */
+/* 96 52 */ unsigned write; /* window write index */
+/*100 56 */ unsigned lmask; /* r12 mask for lcode */
+/*104 60 */ unsigned dmask; /* r13 mask for dcode */
+/*108 64 */ unsigned len; /* r14 match length */
+/*112 68 */ unsigned dist; /* r15 match distance */
+/*116 72 */ unsigned status; /* set when state chng*/
+ } type_ar;
+#ifdef ASMINF
+
+void inflate_fast(strm, start)
+z_streamp strm;
+unsigned start; /* inflate()'s starting value for strm->avail_out */
+{
+ struct inflate_state FAR *state;
+ type_ar ar;
+ void inffas8664fnc(struct inffast_ar * par);
+
+
+
+#if (defined( __GNUC__ ) && defined( __amd64__ ) && ! defined( __i386 )) || (defined(_MSC_VER) && defined(_M_AMD64))
+#define PAD_AVAIL_IN 6
+#define PAD_AVAIL_OUT 258
+#else
+#define PAD_AVAIL_IN 5
+#define PAD_AVAIL_OUT 257
+#endif
+
+ /* copy state to local variables */
+ state = (struct inflate_state FAR *)strm->state;
+
+ ar.in = strm->next_in;
+ ar.last = ar.in + (strm->avail_in - PAD_AVAIL_IN);
+ ar.out = strm->next_out;
+ ar.beg = ar.out - (start - strm->avail_out);
+ ar.end = ar.out + (strm->avail_out - PAD_AVAIL_OUT);
+ ar.wsize = state->wsize;
+ ar.write = state->wnext;
+ ar.window = state->window;
+ ar.hold = state->hold;
+ ar.bits = state->bits;
+ ar.lcode = state->lencode;
+ ar.dcode = state->distcode;
+ ar.lmask = (1U << state->lenbits) - 1;
+ ar.dmask = (1U << state->distbits) - 1;
+
+ /* decode literals and length/distances until end-of-block or not enough
+ input data or output space */
+
+ /* align in on 1/2 hold size boundary */
+ while (((size_t)(void *)ar.in & (sizeof(ar.hold) / 2 - 1)) != 0) {
+ ar.hold += (unsigned long)*ar.in++ << ar.bits;
+ ar.bits += 8;
+ }
+
+ inffas8664fnc(&ar);
+
+ if (ar.status > 1) {
+ if (ar.status == 2)
+ strm->msg = "invalid literal/length code";
+ else if (ar.status == 3)
+ strm->msg = "invalid distance code";
+ else
+ strm->msg = "invalid distance too far back";
+ state->mode = BAD;
+ }
+ else if ( ar.status == 1 ) {
+ state->mode = TYPE;
+ }
+
+ /* return unused bytes (on entry, bits < 8, so in won't go too far back) */
+ ar.len = ar.bits >> 3;
+ ar.in -= ar.len;
+ ar.bits -= ar.len << 3;
+ ar.hold &= (1U << ar.bits) - 1;
+
+ /* update state and return */
+ strm->next_in = ar.in;
+ strm->next_out = ar.out;
+ strm->avail_in = (unsigned)(ar.in < ar.last ?
+ PAD_AVAIL_IN + (ar.last - ar.in) :
+ PAD_AVAIL_IN - (ar.in - ar.last));
+ strm->avail_out = (unsigned)(ar.out < ar.end ?
+ PAD_AVAIL_OUT + (ar.end - ar.out) :
+ PAD_AVAIL_OUT - (ar.out - ar.end));
+ state->hold = (unsigned long)ar.hold;
+ state->bits = ar.bits;
+ return;
+}
+
+#endif
ADDED compat/zlib/contrib/masmx64/inffasx64.asm
Index: compat/zlib/contrib/masmx64/inffasx64.asm
==================================================================
--- compat/zlib/contrib/masmx64/inffasx64.asm
+++ compat/zlib/contrib/masmx64/inffasx64.asm
@@ -0,0 +1,396 @@
+; inffasx64.asm is a hand tuned assembler version of inffast.c - fast decoding
+; version for AMD64 on Windows using Microsoft C compiler
+;
+; inffasx64.asm is automatically convert from AMD64 portion of inffas86.c
+; inffasx64.asm is called by inffas8664.c, which contain more info.
+
+
+; to compile this file, I use option
+; ml64.exe /Flinffasx64 /c /Zi inffasx64.asm
+; with Microsoft Macro Assembler (x64) for AMD64
+;
+
+; This file compile with Microsoft Macro Assembler (x64) for AMD64
+;
+; ml64.exe is given with Visual Studio 2005/2008/2010 and Windows WDK
+;
+; (you can get Windows WDK with ml64 for AMD64 from
+; http://www.microsoft.com/whdc/Devtools/wdk/default.mspx for low price)
+;
+
+
+.code
+inffas8664fnc PROC
+
+; see http://weblogs.asp.net/oldnewthing/archive/2004/01/14/58579.aspx and
+; http://msdn.microsoft.com/library/en-us/kmarch/hh/kmarch/64bitAMD_8e951dd2-ee77-4728-8702-55ce4b5dd24a.xml.asp
+;
+; All registers must be preserved across the call, except for
+; rax, rcx, rdx, r8, r-9, r10, and r11, which are scratch.
+
+
+ mov [rsp-8],rsi
+ mov [rsp-16],rdi
+ mov [rsp-24],r12
+ mov [rsp-32],r13
+ mov [rsp-40],r14
+ mov [rsp-48],r15
+ mov [rsp-56],rbx
+
+ mov rax,rcx
+
+ mov [rax+8], rbp ; /* save regs rbp and rsp */
+ mov [rax], rsp
+
+ mov rsp, rax ; /* make rsp point to &ar */
+
+ mov rsi, [rsp+16] ; /* rsi = in */
+ mov rdi, [rsp+32] ; /* rdi = out */
+ mov r9, [rsp+24] ; /* r9 = last */
+ mov r10, [rsp+48] ; /* r10 = end */
+ mov rbp, [rsp+64] ; /* rbp = lcode */
+ mov r11, [rsp+72] ; /* r11 = dcode */
+ mov rdx, [rsp+80] ; /* rdx = hold */
+ mov ebx, [rsp+88] ; /* ebx = bits */
+ mov r12d, [rsp+100] ; /* r12d = lmask */
+ mov r13d, [rsp+104] ; /* r13d = dmask */
+ ; /* r14d = len */
+ ; /* r15d = dist */
+
+
+ cld
+ cmp r10, rdi
+ je L_one_time ; /* if only one decode left */
+ cmp r9, rsi
+
+ jne L_do_loop
+
+
+L_one_time:
+ mov r8, r12 ; /* r8 = lmask */
+ cmp bl, 32
+ ja L_get_length_code_one_time
+
+ lodsd ; /* eax = *(uint *)in++ */
+ mov cl, bl ; /* cl = bits, needs it for shifting */
+ add bl, 32 ; /* bits += 32 */
+ shl rax, cl
+ or rdx, rax ; /* hold |= *((uint *)in)++ << bits */
+ jmp L_get_length_code_one_time
+
+ALIGN 4
+L_while_test:
+ cmp r10, rdi
+ jbe L_break_loop
+ cmp r9, rsi
+ jbe L_break_loop
+
+L_do_loop:
+ mov r8, r12 ; /* r8 = lmask */
+ cmp bl, 32
+ ja L_get_length_code ; /* if (32 < bits) */
+
+ lodsd ; /* eax = *(uint *)in++ */
+ mov cl, bl ; /* cl = bits, needs it for shifting */
+ add bl, 32 ; /* bits += 32 */
+ shl rax, cl
+ or rdx, rax ; /* hold |= *((uint *)in)++ << bits */
+
+L_get_length_code:
+ and r8, rdx ; /* r8 &= hold */
+ mov eax, [rbp+r8*4] ; /* eax = lcode[hold & lmask] */
+
+ mov cl, ah ; /* cl = this.bits */
+ sub bl, ah ; /* bits -= this.bits */
+ shr rdx, cl ; /* hold >>= this.bits */
+
+ test al, al
+ jnz L_test_for_length_base ; /* if (op != 0) 45.7% */
+
+ mov r8, r12 ; /* r8 = lmask */
+ shr eax, 16 ; /* output this.val char */
+ stosb
+
+L_get_length_code_one_time:
+ and r8, rdx ; /* r8 &= hold */
+ mov eax, [rbp+r8*4] ; /* eax = lcode[hold & lmask] */
+
+L_dolen:
+ mov cl, ah ; /* cl = this.bits */
+ sub bl, ah ; /* bits -= this.bits */
+ shr rdx, cl ; /* hold >>= this.bits */
+
+ test al, al
+ jnz L_test_for_length_base ; /* if (op != 0) 45.7% */
+
+ shr eax, 16 ; /* output this.val char */
+ stosb
+ jmp L_while_test
+
+ALIGN 4
+L_test_for_length_base:
+ mov r14d, eax ; /* len = this */
+ shr r14d, 16 ; /* len = this.val */
+ mov cl, al
+
+ test al, 16
+ jz L_test_for_second_level_length ; /* if ((op & 16) == 0) 8% */
+ and cl, 15 ; /* op &= 15 */
+ jz L_decode_distance ; /* if (!op) */
+
+L_add_bits_to_len:
+ sub bl, cl
+ xor eax, eax
+ inc eax
+ shl eax, cl
+ dec eax
+ and eax, edx ; /* eax &= hold */
+ shr rdx, cl
+ add r14d, eax ; /* len += hold & mask[op] */
+
+L_decode_distance:
+ mov r8, r13 ; /* r8 = dmask */
+ cmp bl, 32
+ ja L_get_distance_code ; /* if (32 < bits) */
+
+ lodsd ; /* eax = *(uint *)in++ */
+ mov cl, bl ; /* cl = bits, needs it for shifting */
+ add bl, 32 ; /* bits += 32 */
+ shl rax, cl
+ or rdx, rax ; /* hold |= *((uint *)in)++ << bits */
+
+L_get_distance_code:
+ and r8, rdx ; /* r8 &= hold */
+ mov eax, [r11+r8*4] ; /* eax = dcode[hold & dmask] */
+
+L_dodist:
+ mov r15d, eax ; /* dist = this */
+ shr r15d, 16 ; /* dist = this.val */
+ mov cl, ah
+ sub bl, ah ; /* bits -= this.bits */
+ shr rdx, cl ; /* hold >>= this.bits */
+ mov cl, al ; /* cl = this.op */
+
+ test al, 16 ; /* if ((op & 16) == 0) */
+ jz L_test_for_second_level_dist
+ and cl, 15 ; /* op &= 15 */
+ jz L_check_dist_one
+
+L_add_bits_to_dist:
+ sub bl, cl
+ xor eax, eax
+ inc eax
+ shl eax, cl
+ dec eax ; /* (1 << op) - 1 */
+ and eax, edx ; /* eax &= hold */
+ shr rdx, cl
+ add r15d, eax ; /* dist += hold & ((1 << op) - 1) */
+
+L_check_window:
+ mov r8, rsi ; /* save in so from can use it's reg */
+ mov rax, rdi
+ sub rax, [rsp+40] ; /* nbytes = out - beg */
+
+ cmp eax, r15d
+ jb L_clip_window ; /* if (dist > nbytes) 4.2% */
+
+ mov ecx, r14d ; /* ecx = len */
+ mov rsi, rdi
+ sub rsi, r15 ; /* from = out - dist */
+
+ sar ecx, 1
+ jnc L_copy_two ; /* if len % 2 == 0 */
+
+ rep movsw
+ mov al, [rsi]
+ mov [rdi], al
+ inc rdi
+
+ mov rsi, r8 ; /* move in back to %rsi, toss from */
+ jmp L_while_test
+
+L_copy_two:
+ rep movsw
+ mov rsi, r8 ; /* move in back to %rsi, toss from */
+ jmp L_while_test
+
+ALIGN 4
+L_check_dist_one:
+ cmp r15d, 1 ; /* if dist 1, is a memset */
+ jne L_check_window
+ cmp [rsp+40], rdi ; /* if out == beg, outside window */
+ je L_check_window
+
+ mov ecx, r14d ; /* ecx = len */
+ mov al, [rdi-1]
+ mov ah, al
+
+ sar ecx, 1
+ jnc L_set_two
+ mov [rdi], al
+ inc rdi
+
+L_set_two:
+ rep stosw
+ jmp L_while_test
+
+ALIGN 4
+L_test_for_second_level_length:
+ test al, 64
+ jnz L_test_for_end_of_block ; /* if ((op & 64) != 0) */
+
+ xor eax, eax
+ inc eax
+ shl eax, cl
+ dec eax
+ and eax, edx ; /* eax &= hold */
+ add eax, r14d ; /* eax += len */
+ mov eax, [rbp+rax*4] ; /* eax = lcode[val+(hold&mask[op])]*/
+ jmp L_dolen
+
+ALIGN 4
+L_test_for_second_level_dist:
+ test al, 64
+ jnz L_invalid_distance_code ; /* if ((op & 64) != 0) */
+
+ xor eax, eax
+ inc eax
+ shl eax, cl
+ dec eax
+ and eax, edx ; /* eax &= hold */
+ add eax, r15d ; /* eax += dist */
+ mov eax, [r11+rax*4] ; /* eax = dcode[val+(hold&mask[op])]*/
+ jmp L_dodist
+
+ALIGN 4
+L_clip_window:
+ mov ecx, eax ; /* ecx = nbytes */
+ mov eax, [rsp+92] ; /* eax = wsize, prepare for dist cmp */
+ neg ecx ; /* nbytes = -nbytes */
+
+ cmp eax, r15d
+ jb L_invalid_distance_too_far ; /* if (dist > wsize) */
+
+ add ecx, r15d ; /* nbytes = dist - nbytes */
+ cmp dword ptr [rsp+96], 0
+ jne L_wrap_around_window ; /* if (write != 0) */
+
+ mov rsi, [rsp+56] ; /* from = window */
+ sub eax, ecx ; /* eax -= nbytes */
+ add rsi, rax ; /* from += wsize - nbytes */
+
+ mov eax, r14d ; /* eax = len */
+ cmp r14d, ecx
+ jbe L_do_copy ; /* if (nbytes >= len) */
+
+ sub eax, ecx ; /* eax -= nbytes */
+ rep movsb
+ mov rsi, rdi
+ sub rsi, r15 ; /* from = &out[ -dist ] */
+ jmp L_do_copy
+
+ALIGN 4
+L_wrap_around_window:
+ mov eax, [rsp+96] ; /* eax = write */
+ cmp ecx, eax
+ jbe L_contiguous_in_window ; /* if (write >= nbytes) */
+
+ mov esi, [rsp+92] ; /* from = wsize */
+ add rsi, [rsp+56] ; /* from += window */
+ add rsi, rax ; /* from += write */
+ sub rsi, rcx ; /* from -= nbytes */
+ sub ecx, eax ; /* nbytes -= write */
+
+ mov eax, r14d ; /* eax = len */
+ cmp eax, ecx
+ jbe L_do_copy ; /* if (nbytes >= len) */
+
+ sub eax, ecx ; /* len -= nbytes */
+ rep movsb
+ mov rsi, [rsp+56] ; /* from = window */
+ mov ecx, [rsp+96] ; /* nbytes = write */
+ cmp eax, ecx
+ jbe L_do_copy ; /* if (nbytes >= len) */
+
+ sub eax, ecx ; /* len -= nbytes */
+ rep movsb
+ mov rsi, rdi
+ sub rsi, r15 ; /* from = out - dist */
+ jmp L_do_copy
+
+ALIGN 4
+L_contiguous_in_window:
+ mov rsi, [rsp+56] ; /* rsi = window */
+ add rsi, rax
+ sub rsi, rcx ; /* from += write - nbytes */
+
+ mov eax, r14d ; /* eax = len */
+ cmp eax, ecx
+ jbe L_do_copy ; /* if (nbytes >= len) */
+
+ sub eax, ecx ; /* len -= nbytes */
+ rep movsb
+ mov rsi, rdi
+ sub rsi, r15 ; /* from = out - dist */
+ jmp L_do_copy ; /* if (nbytes >= len) */
+
+ALIGN 4
+L_do_copy:
+ mov ecx, eax ; /* ecx = len */
+ rep movsb
+
+ mov rsi, r8 ; /* move in back to %esi, toss from */
+ jmp L_while_test
+
+L_test_for_end_of_block:
+ test al, 32
+ jz L_invalid_literal_length_code
+ mov dword ptr [rsp+116], 1
+ jmp L_break_loop_with_status
+
+L_invalid_literal_length_code:
+ mov dword ptr [rsp+116], 2
+ jmp L_break_loop_with_status
+
+L_invalid_distance_code:
+ mov dword ptr [rsp+116], 3
+ jmp L_break_loop_with_status
+
+L_invalid_distance_too_far:
+ mov dword ptr [rsp+116], 4
+ jmp L_break_loop_with_status
+
+L_break_loop:
+ mov dword ptr [rsp+116], 0
+
+L_break_loop_with_status:
+; /* put in, out, bits, and hold back into ar and pop esp */
+ mov [rsp+16], rsi ; /* in */
+ mov [rsp+32], rdi ; /* out */
+ mov [rsp+88], ebx ; /* bits */
+ mov [rsp+80], rdx ; /* hold */
+
+ mov rax, [rsp] ; /* restore rbp and rsp */
+ mov rbp, [rsp+8]
+ mov rsp, rax
+
+
+
+ mov rsi,[rsp-8]
+ mov rdi,[rsp-16]
+ mov r12,[rsp-24]
+ mov r13,[rsp-32]
+ mov r14,[rsp-40]
+ mov r15,[rsp-48]
+ mov rbx,[rsp-56]
+
+ ret 0
+; :
+; : "m" (ar)
+; : "memory", "%rax", "%rbx", "%rcx", "%rdx", "%rsi", "%rdi",
+; "%r8", "%r9", "%r10", "%r11", "%r12", "%r13", "%r14", "%r15"
+; );
+
+inffas8664fnc ENDP
+;_TEXT ENDS
+END
ADDED compat/zlib/contrib/masmx64/readme.txt
Index: compat/zlib/contrib/masmx64/readme.txt
==================================================================
--- compat/zlib/contrib/masmx64/readme.txt
+++ compat/zlib/contrib/masmx64/readme.txt
@@ -0,0 +1,31 @@
+Summary
+-------
+This directory contains ASM implementations of the functions
+longest_match() and inflate_fast(), for 64 bits x86 (both AMD64 and Intel EM64t),
+for use with Microsoft Macro Assembler (x64) for AMD64 and Microsoft C++ 64 bits.
+
+gvmat64.asm is written by Gilles Vollant (2005), by using Brian Raiter 686/32 bits
+ assembly optimized version from Jean-loup Gailly original longest_match function
+
+inffasx64.asm and inffas8664.c were written by Chris Anderson, by optimizing
+ original function from Mark Adler
+
+Use instructions
+----------------
+Assemble the .asm files using MASM and put the object files into the zlib source
+directory. You can also get object files here:
+
+ http://www.winimage.com/zLibDll/zlib124_masm_obj.zip
+
+define ASMV and ASMINF in your project. Include inffas8664.c in your source tree,
+and inffasx64.obj and gvmat64.obj as object to link.
+
+
+Build instructions
+------------------
+run bld_64.bat with Microsoft Macro Assembler (x64) for AMD64 (ml64.exe)
+
+ml64.exe is given with Visual Studio 2005, Windows 2003 server DDK
+
+You can get Windows 2003 server DDK with ml64 and cl for AMD64 from
+ http://www.microsoft.com/whdc/devtools/ddk/default.mspx for low price)
ADDED compat/zlib/contrib/masmx86/bld_ml32.bat
Index: compat/zlib/contrib/masmx86/bld_ml32.bat
==================================================================
--- compat/zlib/contrib/masmx86/bld_ml32.bat
+++ compat/zlib/contrib/masmx86/bld_ml32.bat
@@ -0,0 +1,2 @@
+ml /coff /Zi /c /Flmatch686.lst match686.asm
+ml /coff /Zi /c /Flinffas32.lst inffas32.asm
ADDED compat/zlib/contrib/masmx86/inffas32.asm
Index: compat/zlib/contrib/masmx86/inffas32.asm
==================================================================
--- compat/zlib/contrib/masmx86/inffas32.asm
+++ compat/zlib/contrib/masmx86/inffas32.asm
@@ -0,0 +1,1080 @@
+;/* inffas32.asm is a hand tuned assembler version of inffast.c -- fast decoding
+; *
+; * inffas32.asm is derivated from inffas86.c, with translation of assembly code
+; *
+; * Copyright (C) 1995-2003 Mark Adler
+; * For conditions of distribution and use, see copyright notice in zlib.h
+; *
+; * Copyright (C) 2003 Chris Anderson
+; * Please use the copyright conditions above.
+; *
+; * Mar-13-2003 -- Most of this is derived from inffast.S which is derived from
+; * the gcc -S output of zlib-1.2.0/inffast.c. Zlib-1.2.0 is in beta release at
+; * the moment. I have successfully compiled and tested this code with gcc2.96,
+; * gcc3.2, icc5.0, msvc6.0. It is very close to the speed of inffast.S
+; * compiled with gcc -DNO_MMX, but inffast.S is still faster on the P3 with MMX
+; * enabled. I will attempt to merge the MMX code into this version. Newer
+; * versions of this and inffast.S can be found at
+; * http://www.eetbeetee.com/zlib/ and http://www.charm.net/~christop/zlib/
+; *
+; * 2005 : modification by Gilles Vollant
+; */
+; For Visual C++ 4.x and higher and ML 6.x and higher
+; ml.exe is in directory \MASM611C of Win95 DDK
+; ml.exe is also distributed in http://www.masm32.com/masmdl.htm
+; and in VC++2003 toolkit at http://msdn.microsoft.com/visualc/vctoolkit2003/
+;
+;
+; compile with command line option
+; ml /coff /Zi /c /Flinffas32.lst inffas32.asm
+
+; if you define NO_GZIP (see inflate.h), compile with
+; ml /coff /Zi /c /Flinffas32.lst /DNO_GUNZIP inffas32.asm
+
+
+; zlib122sup is 0 fort zlib 1.2.2.1 and lower
+; zlib122sup is 8 fort zlib 1.2.2.2 and more (with addition of dmax and head
+; in inflate_state in inflate.h)
+zlib1222sup equ 8
+
+
+IFDEF GUNZIP
+ INFLATE_MODE_TYPE equ 11
+ INFLATE_MODE_BAD equ 26
+ELSE
+ IFNDEF NO_GUNZIP
+ INFLATE_MODE_TYPE equ 11
+ INFLATE_MODE_BAD equ 26
+ ELSE
+ INFLATE_MODE_TYPE equ 3
+ INFLATE_MODE_BAD equ 17
+ ENDIF
+ENDIF
+
+
+; 75 "inffast.S"
+;FILE "inffast.S"
+
+;;;GLOBAL _inflate_fast
+
+;;;SECTION .text
+
+
+
+ .586p
+ .mmx
+
+ name inflate_fast_x86
+ .MODEL FLAT
+
+_DATA segment
+inflate_fast_use_mmx:
+ dd 1
+
+
+_TEXT segment
+
+
+
+ALIGN 4
+ db 'Fast decoding Code from Chris Anderson'
+ db 0
+
+ALIGN 4
+invalid_literal_length_code_msg:
+ db 'invalid literal/length code'
+ db 0
+
+ALIGN 4
+invalid_distance_code_msg:
+ db 'invalid distance code'
+ db 0
+
+ALIGN 4
+invalid_distance_too_far_msg:
+ db 'invalid distance too far back'
+ db 0
+
+
+ALIGN 4
+inflate_fast_mask:
+dd 0
+dd 1
+dd 3
+dd 7
+dd 15
+dd 31
+dd 63
+dd 127
+dd 255
+dd 511
+dd 1023
+dd 2047
+dd 4095
+dd 8191
+dd 16383
+dd 32767
+dd 65535
+dd 131071
+dd 262143
+dd 524287
+dd 1048575
+dd 2097151
+dd 4194303
+dd 8388607
+dd 16777215
+dd 33554431
+dd 67108863
+dd 134217727
+dd 268435455
+dd 536870911
+dd 1073741823
+dd 2147483647
+dd 4294967295
+
+
+mode_state equ 0 ;/* state->mode */
+wsize_state equ (32+zlib1222sup) ;/* state->wsize */
+write_state equ (36+4+zlib1222sup) ;/* state->write */
+window_state equ (40+4+zlib1222sup) ;/* state->window */
+hold_state equ (44+4+zlib1222sup) ;/* state->hold */
+bits_state equ (48+4+zlib1222sup) ;/* state->bits */
+lencode_state equ (64+4+zlib1222sup) ;/* state->lencode */
+distcode_state equ (68+4+zlib1222sup) ;/* state->distcode */
+lenbits_state equ (72+4+zlib1222sup) ;/* state->lenbits */
+distbits_state equ (76+4+zlib1222sup) ;/* state->distbits */
+
+
+;;SECTION .text
+; 205 "inffast.S"
+;GLOBAL inflate_fast_use_mmx
+
+;SECTION .data
+
+
+; GLOBAL inflate_fast_use_mmx:object
+;.size inflate_fast_use_mmx, 4
+; 226 "inffast.S"
+;SECTION .text
+
+ALIGN 4
+_inflate_fast proc near
+.FPO (16, 4, 0, 0, 1, 0)
+ push edi
+ push esi
+ push ebp
+ push ebx
+ pushfd
+ sub esp,64
+ cld
+
+
+
+
+ mov esi, [esp+88]
+ mov edi, [esi+28]
+
+
+
+
+
+
+
+ mov edx, [esi+4]
+ mov eax, [esi+0]
+
+ add edx,eax
+ sub edx,11
+
+ mov [esp+44],eax
+ mov [esp+20],edx
+
+ mov ebp, [esp+92]
+ mov ecx, [esi+16]
+ mov ebx, [esi+12]
+
+ sub ebp,ecx
+ neg ebp
+ add ebp,ebx
+
+ sub ecx,257
+ add ecx,ebx
+
+ mov [esp+60],ebx
+ mov [esp+40],ebp
+ mov [esp+16],ecx
+; 285 "inffast.S"
+ mov eax, [edi+lencode_state]
+ mov ecx, [edi+distcode_state]
+
+ mov [esp+8],eax
+ mov [esp+12],ecx
+
+ mov eax,1
+ mov ecx, [edi+lenbits_state]
+ shl eax,cl
+ dec eax
+ mov [esp+0],eax
+
+ mov eax,1
+ mov ecx, [edi+distbits_state]
+ shl eax,cl
+ dec eax
+ mov [esp+4],eax
+
+ mov eax, [edi+wsize_state]
+ mov ecx, [edi+write_state]
+ mov edx, [edi+window_state]
+
+ mov [esp+52],eax
+ mov [esp+48],ecx
+ mov [esp+56],edx
+
+ mov ebp, [edi+hold_state]
+ mov ebx, [edi+bits_state]
+; 321 "inffast.S"
+ mov esi, [esp+44]
+ mov ecx, [esp+20]
+ cmp ecx,esi
+ ja L_align_long
+
+ add ecx,11
+ sub ecx,esi
+ mov eax,12
+ sub eax,ecx
+ lea edi, [esp+28]
+ rep movsb
+ mov ecx,eax
+ xor eax,eax
+ rep stosb
+ lea esi, [esp+28]
+ mov [esp+20],esi
+ jmp L_is_aligned
+
+
+L_align_long:
+ test esi,3
+ jz L_is_aligned
+ xor eax,eax
+ mov al, [esi]
+ inc esi
+ mov ecx,ebx
+ add ebx,8
+ shl eax,cl
+ or ebp,eax
+ jmp L_align_long
+
+L_is_aligned:
+ mov edi, [esp+60]
+; 366 "inffast.S"
+L_check_mmx:
+ cmp dword ptr [inflate_fast_use_mmx],2
+ je L_init_mmx
+ ja L_do_loop
+
+ push eax
+ push ebx
+ push ecx
+ push edx
+ pushfd
+ mov eax, [esp]
+ xor dword ptr [esp],0200000h
+
+
+
+
+ popfd
+ pushfd
+ pop edx
+ xor edx,eax
+ jz L_dont_use_mmx
+ xor eax,eax
+ cpuid
+ cmp ebx,0756e6547h
+ jne L_dont_use_mmx
+ cmp ecx,06c65746eh
+ jne L_dont_use_mmx
+ cmp edx,049656e69h
+ jne L_dont_use_mmx
+ mov eax,1
+ cpuid
+ shr eax,8
+ and eax,15
+ cmp eax,6
+ jne L_dont_use_mmx
+ test edx,0800000h
+ jnz L_use_mmx
+ jmp L_dont_use_mmx
+L_use_mmx:
+ mov dword ptr [inflate_fast_use_mmx],2
+ jmp L_check_mmx_pop
+L_dont_use_mmx:
+ mov dword ptr [inflate_fast_use_mmx],3
+L_check_mmx_pop:
+ pop edx
+ pop ecx
+ pop ebx
+ pop eax
+ jmp L_check_mmx
+; 426 "inffast.S"
+ALIGN 4
+L_do_loop:
+; 437 "inffast.S"
+ cmp bl,15
+ ja L_get_length_code
+
+ xor eax,eax
+ lodsw
+ mov cl,bl
+ add bl,16
+ shl eax,cl
+ or ebp,eax
+
+L_get_length_code:
+ mov edx, [esp+0]
+ mov ecx, [esp+8]
+ and edx,ebp
+ mov eax, [ecx+edx*4]
+
+L_dolen:
+
+
+
+
+
+
+ mov cl,ah
+ sub bl,ah
+ shr ebp,cl
+
+
+
+
+
+
+ test al,al
+ jnz L_test_for_length_base
+
+ shr eax,16
+ stosb
+
+L_while_test:
+
+
+ cmp [esp+16],edi
+ jbe L_break_loop
+
+ cmp [esp+20],esi
+ ja L_do_loop
+ jmp L_break_loop
+
+L_test_for_length_base:
+; 502 "inffast.S"
+ mov edx,eax
+ shr edx,16
+ mov cl,al
+
+ test al,16
+ jz L_test_for_second_level_length
+ and cl,15
+ jz L_save_len
+ cmp bl,cl
+ jae L_add_bits_to_len
+
+ mov ch,cl
+ xor eax,eax
+ lodsw
+ mov cl,bl
+ add bl,16
+ shl eax,cl
+ or ebp,eax
+ mov cl,ch
+
+L_add_bits_to_len:
+ mov eax,1
+ shl eax,cl
+ dec eax
+ sub bl,cl
+ and eax,ebp
+ shr ebp,cl
+ add edx,eax
+
+L_save_len:
+ mov [esp+24],edx
+
+
+L_decode_distance:
+; 549 "inffast.S"
+ cmp bl,15
+ ja L_get_distance_code
+
+ xor eax,eax
+ lodsw
+ mov cl,bl
+ add bl,16
+ shl eax,cl
+ or ebp,eax
+
+L_get_distance_code:
+ mov edx, [esp+4]
+ mov ecx, [esp+12]
+ and edx,ebp
+ mov eax, [ecx+edx*4]
+
+
+L_dodist:
+ mov edx,eax
+ shr edx,16
+ mov cl,ah
+ sub bl,ah
+ shr ebp,cl
+; 584 "inffast.S"
+ mov cl,al
+
+ test al,16
+ jz L_test_for_second_level_dist
+ and cl,15
+ jz L_check_dist_one
+ cmp bl,cl
+ jae L_add_bits_to_dist
+
+ mov ch,cl
+ xor eax,eax
+ lodsw
+ mov cl,bl
+ add bl,16
+ shl eax,cl
+ or ebp,eax
+ mov cl,ch
+
+L_add_bits_to_dist:
+ mov eax,1
+ shl eax,cl
+ dec eax
+ sub bl,cl
+ and eax,ebp
+ shr ebp,cl
+ add edx,eax
+ jmp L_check_window
+
+L_check_window:
+; 625 "inffast.S"
+ mov [esp+44],esi
+ mov eax,edi
+ sub eax, [esp+40]
+
+ cmp eax,edx
+ jb L_clip_window
+
+ mov ecx, [esp+24]
+ mov esi,edi
+ sub esi,edx
+
+ sub ecx,3
+ mov al, [esi]
+ mov [edi],al
+ mov al, [esi+1]
+ mov dl, [esi+2]
+ add esi,3
+ mov [edi+1],al
+ mov [edi+2],dl
+ add edi,3
+ rep movsb
+
+ mov esi, [esp+44]
+ jmp L_while_test
+
+ALIGN 4
+L_check_dist_one:
+ cmp edx,1
+ jne L_check_window
+ cmp [esp+40],edi
+ je L_check_window
+
+ dec edi
+ mov ecx, [esp+24]
+ mov al, [edi]
+ sub ecx,3
+
+ mov [edi+1],al
+ mov [edi+2],al
+ mov [edi+3],al
+ add edi,4
+ rep stosb
+
+ jmp L_while_test
+
+ALIGN 4
+L_test_for_second_level_length:
+
+
+
+
+ test al,64
+ jnz L_test_for_end_of_block
+
+ mov eax,1
+ shl eax,cl
+ dec eax
+ and eax,ebp
+ add eax,edx
+ mov edx, [esp+8]
+ mov eax, [edx+eax*4]
+ jmp L_dolen
+
+ALIGN 4
+L_test_for_second_level_dist:
+
+
+
+
+ test al,64
+ jnz L_invalid_distance_code
+
+ mov eax,1
+ shl eax,cl
+ dec eax
+ and eax,ebp
+ add eax,edx
+ mov edx, [esp+12]
+ mov eax, [edx+eax*4]
+ jmp L_dodist
+
+ALIGN 4
+L_clip_window:
+; 721 "inffast.S"
+ mov ecx,eax
+ mov eax, [esp+52]
+ neg ecx
+ mov esi, [esp+56]
+
+ cmp eax,edx
+ jb L_invalid_distance_too_far
+
+ add ecx,edx
+ cmp dword ptr [esp+48],0
+ jne L_wrap_around_window
+
+ sub eax,ecx
+ add esi,eax
+; 749 "inffast.S"
+ mov eax, [esp+24]
+ cmp eax,ecx
+ jbe L_do_copy1
+
+ sub eax,ecx
+ rep movsb
+ mov esi,edi
+ sub esi,edx
+ jmp L_do_copy1
+
+ cmp eax,ecx
+ jbe L_do_copy1
+
+ sub eax,ecx
+ rep movsb
+ mov esi,edi
+ sub esi,edx
+ jmp L_do_copy1
+
+L_wrap_around_window:
+; 793 "inffast.S"
+ mov eax, [esp+48]
+ cmp ecx,eax
+ jbe L_contiguous_in_window
+
+ add esi, [esp+52]
+ add esi,eax
+ sub esi,ecx
+ sub ecx,eax
+
+
+ mov eax, [esp+24]
+ cmp eax,ecx
+ jbe L_do_copy1
+
+ sub eax,ecx
+ rep movsb
+ mov esi, [esp+56]
+ mov ecx, [esp+48]
+ cmp eax,ecx
+ jbe L_do_copy1
+
+ sub eax,ecx
+ rep movsb
+ mov esi,edi
+ sub esi,edx
+ jmp L_do_copy1
+
+L_contiguous_in_window:
+; 836 "inffast.S"
+ add esi,eax
+ sub esi,ecx
+
+
+ mov eax, [esp+24]
+ cmp eax,ecx
+ jbe L_do_copy1
+
+ sub eax,ecx
+ rep movsb
+ mov esi,edi
+ sub esi,edx
+
+L_do_copy1:
+; 862 "inffast.S"
+ mov ecx,eax
+ rep movsb
+
+ mov esi, [esp+44]
+ jmp L_while_test
+; 878 "inffast.S"
+ALIGN 4
+L_init_mmx:
+ emms
+
+
+
+
+
+ movd mm0,ebp
+ mov ebp,ebx
+; 896 "inffast.S"
+ movd mm4,dword ptr [esp+0]
+ movq mm3,mm4
+ movd mm5,dword ptr [esp+4]
+ movq mm2,mm5
+ pxor mm1,mm1
+ mov ebx, [esp+8]
+ jmp L_do_loop_mmx
+
+ALIGN 4
+L_do_loop_mmx:
+ psrlq mm0,mm1
+
+ cmp ebp,32
+ ja L_get_length_code_mmx
+
+ movd mm6,ebp
+ movd mm7,dword ptr [esi]
+ add esi,4
+ psllq mm7,mm6
+ add ebp,32
+ por mm0,mm7
+
+L_get_length_code_mmx:
+ pand mm4,mm0
+ movd eax,mm4
+ movq mm4,mm3
+ mov eax, [ebx+eax*4]
+
+L_dolen_mmx:
+ movzx ecx,ah
+ movd mm1,ecx
+ sub ebp,ecx
+
+ test al,al
+ jnz L_test_for_length_base_mmx
+
+ shr eax,16
+ stosb
+
+L_while_test_mmx:
+
+
+ cmp [esp+16],edi
+ jbe L_break_loop
+
+ cmp [esp+20],esi
+ ja L_do_loop_mmx
+ jmp L_break_loop
+
+L_test_for_length_base_mmx:
+
+ mov edx,eax
+ shr edx,16
+
+ test al,16
+ jz L_test_for_second_level_length_mmx
+ and eax,15
+ jz L_decode_distance_mmx
+
+ psrlq mm0,mm1
+ movd mm1,eax
+ movd ecx,mm0
+ sub ebp,eax
+ and ecx, [inflate_fast_mask+eax*4]
+ add edx,ecx
+
+L_decode_distance_mmx:
+ psrlq mm0,mm1
+
+ cmp ebp,32
+ ja L_get_dist_code_mmx
+
+ movd mm6,ebp
+ movd mm7,dword ptr [esi]
+ add esi,4
+ psllq mm7,mm6
+ add ebp,32
+ por mm0,mm7
+
+L_get_dist_code_mmx:
+ mov ebx, [esp+12]
+ pand mm5,mm0
+ movd eax,mm5
+ movq mm5,mm2
+ mov eax, [ebx+eax*4]
+
+L_dodist_mmx:
+
+ movzx ecx,ah
+ mov ebx,eax
+ shr ebx,16
+ sub ebp,ecx
+ movd mm1,ecx
+
+ test al,16
+ jz L_test_for_second_level_dist_mmx
+ and eax,15
+ jz L_check_dist_one_mmx
+
+L_add_bits_to_dist_mmx:
+ psrlq mm0,mm1
+ movd mm1,eax
+ movd ecx,mm0
+ sub ebp,eax
+ and ecx, [inflate_fast_mask+eax*4]
+ add ebx,ecx
+
+L_check_window_mmx:
+ mov [esp+44],esi
+ mov eax,edi
+ sub eax, [esp+40]
+
+ cmp eax,ebx
+ jb L_clip_window_mmx
+
+ mov ecx,edx
+ mov esi,edi
+ sub esi,ebx
+
+ sub ecx,3
+ mov al, [esi]
+ mov [edi],al
+ mov al, [esi+1]
+ mov dl, [esi+2]
+ add esi,3
+ mov [edi+1],al
+ mov [edi+2],dl
+ add edi,3
+ rep movsb
+
+ mov esi, [esp+44]
+ mov ebx, [esp+8]
+ jmp L_while_test_mmx
+
+ALIGN 4
+L_check_dist_one_mmx:
+ cmp ebx,1
+ jne L_check_window_mmx
+ cmp [esp+40],edi
+ je L_check_window_mmx
+
+ dec edi
+ mov ecx,edx
+ mov al, [edi]
+ sub ecx,3
+
+ mov [edi+1],al
+ mov [edi+2],al
+ mov [edi+3],al
+ add edi,4
+ rep stosb
+
+ mov ebx, [esp+8]
+ jmp L_while_test_mmx
+
+ALIGN 4
+L_test_for_second_level_length_mmx:
+ test al,64
+ jnz L_test_for_end_of_block
+
+ and eax,15
+ psrlq mm0,mm1
+ movd ecx,mm0
+ and ecx, [inflate_fast_mask+eax*4]
+ add ecx,edx
+ mov eax, [ebx+ecx*4]
+ jmp L_dolen_mmx
+
+ALIGN 4
+L_test_for_second_level_dist_mmx:
+ test al,64
+ jnz L_invalid_distance_code
+
+ and eax,15
+ psrlq mm0,mm1
+ movd ecx,mm0
+ and ecx, [inflate_fast_mask+eax*4]
+ mov eax, [esp+12]
+ add ecx,ebx
+ mov eax, [eax+ecx*4]
+ jmp L_dodist_mmx
+
+ALIGN 4
+L_clip_window_mmx:
+
+ mov ecx,eax
+ mov eax, [esp+52]
+ neg ecx
+ mov esi, [esp+56]
+
+ cmp eax,ebx
+ jb L_invalid_distance_too_far
+
+ add ecx,ebx
+ cmp dword ptr [esp+48],0
+ jne L_wrap_around_window_mmx
+
+ sub eax,ecx
+ add esi,eax
+
+ cmp edx,ecx
+ jbe L_do_copy1_mmx
+
+ sub edx,ecx
+ rep movsb
+ mov esi,edi
+ sub esi,ebx
+ jmp L_do_copy1_mmx
+
+ cmp edx,ecx
+ jbe L_do_copy1_mmx
+
+ sub edx,ecx
+ rep movsb
+ mov esi,edi
+ sub esi,ebx
+ jmp L_do_copy1_mmx
+
+L_wrap_around_window_mmx:
+
+ mov eax, [esp+48]
+ cmp ecx,eax
+ jbe L_contiguous_in_window_mmx
+
+ add esi, [esp+52]
+ add esi,eax
+ sub esi,ecx
+ sub ecx,eax
+
+
+ cmp edx,ecx
+ jbe L_do_copy1_mmx
+
+ sub edx,ecx
+ rep movsb
+ mov esi, [esp+56]
+ mov ecx, [esp+48]
+ cmp edx,ecx
+ jbe L_do_copy1_mmx
+
+ sub edx,ecx
+ rep movsb
+ mov esi,edi
+ sub esi,ebx
+ jmp L_do_copy1_mmx
+
+L_contiguous_in_window_mmx:
+
+ add esi,eax
+ sub esi,ecx
+
+
+ cmp edx,ecx
+ jbe L_do_copy1_mmx
+
+ sub edx,ecx
+ rep movsb
+ mov esi,edi
+ sub esi,ebx
+
+L_do_copy1_mmx:
+
+
+ mov ecx,edx
+ rep movsb
+
+ mov esi, [esp+44]
+ mov ebx, [esp+8]
+ jmp L_while_test_mmx
+; 1174 "inffast.S"
+L_invalid_distance_code:
+
+
+
+
+
+ mov ecx, invalid_distance_code_msg
+ mov edx,INFLATE_MODE_BAD
+ jmp L_update_stream_state
+
+L_test_for_end_of_block:
+
+
+
+
+
+ test al,32
+ jz L_invalid_literal_length_code
+
+ mov ecx,0
+ mov edx,INFLATE_MODE_TYPE
+ jmp L_update_stream_state
+
+L_invalid_literal_length_code:
+
+
+
+
+
+ mov ecx, invalid_literal_length_code_msg
+ mov edx,INFLATE_MODE_BAD
+ jmp L_update_stream_state
+
+L_invalid_distance_too_far:
+
+
+
+ mov esi, [esp+44]
+ mov ecx, invalid_distance_too_far_msg
+ mov edx,INFLATE_MODE_BAD
+ jmp L_update_stream_state
+
+L_update_stream_state:
+
+ mov eax, [esp+88]
+ test ecx,ecx
+ jz L_skip_msg
+ mov [eax+24],ecx
+L_skip_msg:
+ mov eax, [eax+28]
+ mov [eax+mode_state],edx
+ jmp L_break_loop
+
+ALIGN 4
+L_break_loop:
+; 1243 "inffast.S"
+ cmp dword ptr [inflate_fast_use_mmx],2
+ jne L_update_next_in
+
+
+
+ mov ebx,ebp
+
+L_update_next_in:
+; 1266 "inffast.S"
+ mov eax, [esp+88]
+ mov ecx,ebx
+ mov edx, [eax+28]
+ shr ecx,3
+ sub esi,ecx
+ shl ecx,3
+ sub ebx,ecx
+ mov [eax+12],edi
+ mov [edx+bits_state],ebx
+ mov ecx,ebx
+
+ lea ebx, [esp+28]
+ cmp [esp+20],ebx
+ jne L_buf_not_used
+
+ sub esi,ebx
+ mov ebx, [eax+0]
+ mov [esp+20],ebx
+ add esi,ebx
+ mov ebx, [eax+4]
+ sub ebx,11
+ add [esp+20],ebx
+
+L_buf_not_used:
+ mov [eax+0],esi
+
+ mov ebx,1
+ shl ebx,cl
+ dec ebx
+
+
+
+
+
+ cmp dword ptr [inflate_fast_use_mmx],2
+ jne L_update_hold
+
+
+
+ psrlq mm0,mm1
+ movd ebp,mm0
+
+ emms
+
+L_update_hold:
+
+
+
+ and ebp,ebx
+ mov [edx+hold_state],ebp
+
+
+
+
+ mov ebx, [esp+20]
+ cmp ebx,esi
+ jbe L_last_is_smaller
+
+ sub ebx,esi
+ add ebx,11
+ mov [eax+4],ebx
+ jmp L_fixup_out
+L_last_is_smaller:
+ sub esi,ebx
+ neg esi
+ add esi,11
+ mov [eax+4],esi
+
+
+
+
+L_fixup_out:
+
+ mov ebx, [esp+16]
+ cmp ebx,edi
+ jbe L_end_is_smaller
+
+ sub ebx,edi
+ add ebx,257
+ mov [eax+16],ebx
+ jmp L_done
+L_end_is_smaller:
+ sub edi,ebx
+ neg edi
+ add edi,257
+ mov [eax+16],edi
+
+
+
+
+
+L_done:
+ add esp,64
+ popfd
+ pop ebx
+ pop ebp
+ pop esi
+ pop edi
+ ret
+_inflate_fast endp
+
+_TEXT ends
+end
ADDED compat/zlib/contrib/masmx86/match686.asm
Index: compat/zlib/contrib/masmx86/match686.asm
==================================================================
--- compat/zlib/contrib/masmx86/match686.asm
+++ compat/zlib/contrib/masmx86/match686.asm
@@ -0,0 +1,479 @@
+; match686.asm -- Asm portion of the optimized longest_match for 32 bits x86
+; Copyright (C) 1995-1996 Jean-loup Gailly, Brian Raiter and Gilles Vollant.
+; File written by Gilles Vollant, by converting match686.S from Brian Raiter
+; for MASM. This is as assembly version of longest_match
+; from Jean-loup Gailly in deflate.c
+;
+; http://www.zlib.net
+; http://www.winimage.com/zLibDll
+; http://www.muppetlabs.com/~breadbox/software/assembly.html
+;
+; For Visual C++ 4.x and higher and ML 6.x and higher
+; ml.exe is distributed in
+; http://www.microsoft.com/downloads/details.aspx?FamilyID=7a1c9da0-0510-44a2-b042-7ef370530c64
+;
+; this file contain two implementation of longest_match
+;
+; this longest_match was written by Brian raiter (1998), optimized for Pentium Pro
+; (and the faster known version of match_init on modern Core 2 Duo and AMD Phenom)
+;
+; for using an assembly version of longest_match, you need define ASMV in project
+;
+; compile the asm file running
+; ml /coff /Zi /c /Flmatch686.lst match686.asm
+; and do not include match686.obj in your project
+;
+; note: contrib of zLib 1.2.3 and earlier contained both a deprecated version for
+; Pentium (prior Pentium Pro) and this version for Pentium Pro and modern processor
+; with autoselect (with cpu detection code)
+; if you want support the old pentium optimization, you can still use these version
+;
+; this file is not optimized for old pentium, but it compatible with all x86 32 bits
+; processor (starting 80386)
+;
+;
+; see below : zlib1222add must be adjuster if you use a zlib version < 1.2.2.2
+
+;uInt longest_match(s, cur_match)
+; deflate_state *s;
+; IPos cur_match; /* current match */
+
+ NbStack equ 76
+ cur_match equ dword ptr[esp+NbStack-0]
+ str_s equ dword ptr[esp+NbStack-4]
+; 5 dword on top (ret,ebp,esi,edi,ebx)
+ adrret equ dword ptr[esp+NbStack-8]
+ pushebp equ dword ptr[esp+NbStack-12]
+ pushedi equ dword ptr[esp+NbStack-16]
+ pushesi equ dword ptr[esp+NbStack-20]
+ pushebx equ dword ptr[esp+NbStack-24]
+
+ chain_length equ dword ptr [esp+NbStack-28]
+ limit equ dword ptr [esp+NbStack-32]
+ best_len equ dword ptr [esp+NbStack-36]
+ window equ dword ptr [esp+NbStack-40]
+ prev equ dword ptr [esp+NbStack-44]
+ scan_start equ word ptr [esp+NbStack-48]
+ wmask equ dword ptr [esp+NbStack-52]
+ match_start_ptr equ dword ptr [esp+NbStack-56]
+ nice_match equ dword ptr [esp+NbStack-60]
+ scan equ dword ptr [esp+NbStack-64]
+
+ windowlen equ dword ptr [esp+NbStack-68]
+ match_start equ dword ptr [esp+NbStack-72]
+ strend equ dword ptr [esp+NbStack-76]
+ NbStackAdd equ (NbStack-24)
+
+ .386p
+
+ name gvmatch
+ .MODEL FLAT
+
+
+
+; all the +zlib1222add offsets are due to the addition of fields
+; in zlib in the deflate_state structure since the asm code was first written
+; (if you compile with zlib 1.0.4 or older, use "zlib1222add equ (-4)").
+; (if you compile with zlib between 1.0.5 and 1.2.2.1, use "zlib1222add equ 0").
+; if you compile with zlib 1.2.2.2 or later , use "zlib1222add equ 8").
+
+ zlib1222add equ 8
+
+; Note : these value are good with a 8 bytes boundary pack structure
+ dep_chain_length equ 74h+zlib1222add
+ dep_window equ 30h+zlib1222add
+ dep_strstart equ 64h+zlib1222add
+ dep_prev_length equ 70h+zlib1222add
+ dep_nice_match equ 88h+zlib1222add
+ dep_w_size equ 24h+zlib1222add
+ dep_prev equ 38h+zlib1222add
+ dep_w_mask equ 2ch+zlib1222add
+ dep_good_match equ 84h+zlib1222add
+ dep_match_start equ 68h+zlib1222add
+ dep_lookahead equ 6ch+zlib1222add
+
+
+_TEXT segment
+
+IFDEF NOUNDERLINE
+ public longest_match
+ public match_init
+ELSE
+ public _longest_match
+ public _match_init
+ENDIF
+
+ MAX_MATCH equ 258
+ MIN_MATCH equ 3
+ MIN_LOOKAHEAD equ (MAX_MATCH+MIN_MATCH+1)
+
+
+
+MAX_MATCH equ 258
+MIN_MATCH equ 3
+MIN_LOOKAHEAD equ (MAX_MATCH + MIN_MATCH + 1)
+MAX_MATCH_8_ equ ((MAX_MATCH + 7) AND 0FFF0h)
+
+
+;;; stack frame offsets
+
+chainlenwmask equ esp + 0 ; high word: current chain len
+ ; low word: s->wmask
+window equ esp + 4 ; local copy of s->window
+windowbestlen equ esp + 8 ; s->window + bestlen
+scanstart equ esp + 16 ; first two bytes of string
+scanend equ esp + 12 ; last two bytes of string
+scanalign equ esp + 20 ; dword-misalignment of string
+nicematch equ esp + 24 ; a good enough match size
+bestlen equ esp + 28 ; size of best match so far
+scan equ esp + 32 ; ptr to string wanting match
+
+LocalVarsSize equ 36
+; saved ebx byte esp + 36
+; saved edi byte esp + 40
+; saved esi byte esp + 44
+; saved ebp byte esp + 48
+; return address byte esp + 52
+deflatestate equ esp + 56 ; the function arguments
+curmatch equ esp + 60
+
+;;; Offsets for fields in the deflate_state structure. These numbers
+;;; are calculated from the definition of deflate_state, with the
+;;; assumption that the compiler will dword-align the fields. (Thus,
+;;; changing the definition of deflate_state could easily cause this
+;;; program to crash horribly, without so much as a warning at
+;;; compile time. Sigh.)
+
+dsWSize equ 36+zlib1222add
+dsWMask equ 44+zlib1222add
+dsWindow equ 48+zlib1222add
+dsPrev equ 56+zlib1222add
+dsMatchLen equ 88+zlib1222add
+dsPrevMatch equ 92+zlib1222add
+dsStrStart equ 100+zlib1222add
+dsMatchStart equ 104+zlib1222add
+dsLookahead equ 108+zlib1222add
+dsPrevLen equ 112+zlib1222add
+dsMaxChainLen equ 116+zlib1222add
+dsGoodMatch equ 132+zlib1222add
+dsNiceMatch equ 136+zlib1222add
+
+
+;;; match686.asm -- Pentium-Pro-optimized version of longest_match()
+;;; Written for zlib 1.1.2
+;;; Copyright (C) 1998 Brian Raiter
+;;; You can look at http://www.muppetlabs.com/~breadbox/software/assembly.html
+;;;
+;;
+;; This software is provided 'as-is', without any express or implied
+;; warranty. In no event will the authors be held liable for any damages
+;; arising from the use of this software.
+;;
+;; Permission is granted to anyone to use this software for any purpose,
+;; including commercial applications, and to alter it and redistribute it
+;; freely, subject to the following restrictions:
+;;
+;; 1. The origin of this software must not be misrepresented; you must not
+;; claim that you wrote the original software. If you use this software
+;; in a product, an acknowledgment in the product documentation would be
+;; appreciated but is not required.
+;; 2. Altered source versions must be plainly marked as such, and must not be
+;; misrepresented as being the original software
+;; 3. This notice may not be removed or altered from any source distribution.
+;;
+
+;GLOBAL _longest_match, _match_init
+
+
+;SECTION .text
+
+;;; uInt longest_match(deflate_state *deflatestate, IPos curmatch)
+
+;_longest_match:
+ IFDEF NOUNDERLINE
+ longest_match proc near
+ ELSE
+ _longest_match proc near
+ ENDIF
+.FPO (9, 4, 0, 0, 1, 0)
+
+;;; Save registers that the compiler may be using, and adjust esp to
+;;; make room for our stack frame.
+
+ push ebp
+ push edi
+ push esi
+ push ebx
+ sub esp, LocalVarsSize
+
+;;; Retrieve the function arguments. ecx will hold cur_match
+;;; throughout the entire function. edx will hold the pointer to the
+;;; deflate_state structure during the function's setup (before
+;;; entering the main loop.
+
+ mov edx, [deflatestate]
+ mov ecx, [curmatch]
+
+;;; uInt wmask = s->w_mask;
+;;; unsigned chain_length = s->max_chain_length;
+;;; if (s->prev_length >= s->good_match) {
+;;; chain_length >>= 2;
+;;; }
+
+ mov eax, [edx + dsPrevLen]
+ mov ebx, [edx + dsGoodMatch]
+ cmp eax, ebx
+ mov eax, [edx + dsWMask]
+ mov ebx, [edx + dsMaxChainLen]
+ jl LastMatchGood
+ shr ebx, 2
+LastMatchGood:
+
+;;; chainlen is decremented once beforehand so that the function can
+;;; use the sign flag instead of the zero flag for the exit test.
+;;; It is then shifted into the high word, to make room for the wmask
+;;; value, which it will always accompany.
+
+ dec ebx
+ shl ebx, 16
+ or ebx, eax
+ mov [chainlenwmask], ebx
+
+;;; if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead;
+
+ mov eax, [edx + dsNiceMatch]
+ mov ebx, [edx + dsLookahead]
+ cmp ebx, eax
+ jl LookaheadLess
+ mov ebx, eax
+LookaheadLess: mov [nicematch], ebx
+
+;;; register Bytef *scan = s->window + s->strstart;
+
+ mov esi, [edx + dsWindow]
+ mov [window], esi
+ mov ebp, [edx + dsStrStart]
+ lea edi, [esi + ebp]
+ mov [scan], edi
+
+;;; Determine how many bytes the scan ptr is off from being
+;;; dword-aligned.
+
+ mov eax, edi
+ neg eax
+ and eax, 3
+ mov [scanalign], eax
+
+;;; IPos limit = s->strstart > (IPos)MAX_DIST(s) ?
+;;; s->strstart - (IPos)MAX_DIST(s) : NIL;
+
+ mov eax, [edx + dsWSize]
+ sub eax, MIN_LOOKAHEAD
+ sub ebp, eax
+ jg LimitPositive
+ xor ebp, ebp
+LimitPositive:
+
+;;; int best_len = s->prev_length;
+
+ mov eax, [edx + dsPrevLen]
+ mov [bestlen], eax
+
+;;; Store the sum of s->window + best_len in esi locally, and in esi.
+
+ add esi, eax
+ mov [windowbestlen], esi
+
+;;; register ush scan_start = *(ushf*)scan;
+;;; register ush scan_end = *(ushf*)(scan+best_len-1);
+;;; Posf *prev = s->prev;
+
+ movzx ebx, word ptr [edi]
+ mov [scanstart], ebx
+ movzx ebx, word ptr [edi + eax - 1]
+ mov [scanend], ebx
+ mov edi, [edx + dsPrev]
+
+;;; Jump into the main loop.
+
+ mov edx, [chainlenwmask]
+ jmp short LoopEntry
+
+align 4
+
+;;; do {
+;;; match = s->window + cur_match;
+;;; if (*(ushf*)(match+best_len-1) != scan_end ||
+;;; *(ushf*)match != scan_start) continue;
+;;; [...]
+;;; } while ((cur_match = prev[cur_match & wmask]) > limit
+;;; && --chain_length != 0);
+;;;
+;;; Here is the inner loop of the function. The function will spend the
+;;; majority of its time in this loop, and majority of that time will
+;;; be spent in the first ten instructions.
+;;;
+;;; Within this loop:
+;;; ebx = scanend
+;;; ecx = curmatch
+;;; edx = chainlenwmask - i.e., ((chainlen << 16) | wmask)
+;;; esi = windowbestlen - i.e., (window + bestlen)
+;;; edi = prev
+;;; ebp = limit
+
+LookupLoop:
+ and ecx, edx
+ movzx ecx, word ptr [edi + ecx*2]
+ cmp ecx, ebp
+ jbe LeaveNow
+ sub edx, 00010000h
+ js LeaveNow
+LoopEntry: movzx eax, word ptr [esi + ecx - 1]
+ cmp eax, ebx
+ jnz LookupLoop
+ mov eax, [window]
+ movzx eax, word ptr [eax + ecx]
+ cmp eax, [scanstart]
+ jnz LookupLoop
+
+;;; Store the current value of chainlen.
+
+ mov [chainlenwmask], edx
+
+;;; Point edi to the string under scrutiny, and esi to the string we
+;;; are hoping to match it up with. In actuality, esi and edi are
+;;; both pointed (MAX_MATCH_8 - scanalign) bytes ahead, and edx is
+;;; initialized to -(MAX_MATCH_8 - scanalign).
+
+ mov esi, [window]
+ mov edi, [scan]
+ add esi, ecx
+ mov eax, [scanalign]
+ mov edx, 0fffffef8h; -(MAX_MATCH_8)
+ lea edi, [edi + eax + 0108h] ;MAX_MATCH_8]
+ lea esi, [esi + eax + 0108h] ;MAX_MATCH_8]
+
+;;; Test the strings for equality, 8 bytes at a time. At the end,
+;;; adjust edx so that it is offset to the exact byte that mismatched.
+;;;
+;;; We already know at this point that the first three bytes of the
+;;; strings match each other, and they can be safely passed over before
+;;; starting the compare loop. So what this code does is skip over 0-3
+;;; bytes, as much as necessary in order to dword-align the edi
+;;; pointer. (esi will still be misaligned three times out of four.)
+;;;
+;;; It should be confessed that this loop usually does not represent
+;;; much of the total running time. Replacing it with a more
+;;; straightforward "rep cmpsb" would not drastically degrade
+;;; performance.
+
+LoopCmps:
+ mov eax, [esi + edx]
+ xor eax, [edi + edx]
+ jnz LeaveLoopCmps
+ mov eax, [esi + edx + 4]
+ xor eax, [edi + edx + 4]
+ jnz LeaveLoopCmps4
+ add edx, 8
+ jnz LoopCmps
+ jmp short LenMaximum
+LeaveLoopCmps4: add edx, 4
+LeaveLoopCmps: test eax, 0000FFFFh
+ jnz LenLower
+ add edx, 2
+ shr eax, 16
+LenLower: sub al, 1
+ adc edx, 0
+
+;;; Calculate the length of the match. If it is longer than MAX_MATCH,
+;;; then automatically accept it as the best possible match and leave.
+
+ lea eax, [edi + edx]
+ mov edi, [scan]
+ sub eax, edi
+ cmp eax, MAX_MATCH
+ jge LenMaximum
+
+;;; If the length of the match is not longer than the best match we
+;;; have so far, then forget it and return to the lookup loop.
+
+ mov edx, [deflatestate]
+ mov ebx, [bestlen]
+ cmp eax, ebx
+ jg LongerMatch
+ mov esi, [windowbestlen]
+ mov edi, [edx + dsPrev]
+ mov ebx, [scanend]
+ mov edx, [chainlenwmask]
+ jmp LookupLoop
+
+;;; s->match_start = cur_match;
+;;; best_len = len;
+;;; if (len >= nice_match) break;
+;;; scan_end = *(ushf*)(scan+best_len-1);
+
+LongerMatch: mov ebx, [nicematch]
+ mov [bestlen], eax
+ mov [edx + dsMatchStart], ecx
+ cmp eax, ebx
+ jge LeaveNow
+ mov esi, [window]
+ add esi, eax
+ mov [windowbestlen], esi
+ movzx ebx, word ptr [edi + eax - 1]
+ mov edi, [edx + dsPrev]
+ mov [scanend], ebx
+ mov edx, [chainlenwmask]
+ jmp LookupLoop
+
+;;; Accept the current string, with the maximum possible length.
+
+LenMaximum: mov edx, [deflatestate]
+ mov dword ptr [bestlen], MAX_MATCH
+ mov [edx + dsMatchStart], ecx
+
+;;; if ((uInt)best_len <= s->lookahead) return (uInt)best_len;
+;;; return s->lookahead;
+
+LeaveNow:
+ mov edx, [deflatestate]
+ mov ebx, [bestlen]
+ mov eax, [edx + dsLookahead]
+ cmp ebx, eax
+ jg LookaheadRet
+ mov eax, ebx
+LookaheadRet:
+
+;;; Restore the stack and return from whence we came.
+
+ add esp, LocalVarsSize
+ pop ebx
+ pop esi
+ pop edi
+ pop ebp
+
+ ret
+; please don't remove this string !
+; Your can freely use match686 in any free or commercial app if you don't remove the string in the binary!
+ db 0dh,0ah,"asm686 with masm, optimised assembly code from Brian Raiter, written 1998",0dh,0ah
+
+
+ IFDEF NOUNDERLINE
+ longest_match endp
+ ELSE
+ _longest_match endp
+ ENDIF
+
+ IFDEF NOUNDERLINE
+ match_init proc near
+ ret
+ match_init endp
+ ELSE
+ _match_init proc near
+ ret
+ _match_init endp
+ ENDIF
+
+
+_TEXT ends
+end
ADDED compat/zlib/contrib/masmx86/readme.txt
Index: compat/zlib/contrib/masmx86/readme.txt
==================================================================
--- compat/zlib/contrib/masmx86/readme.txt
+++ compat/zlib/contrib/masmx86/readme.txt
@@ -0,0 +1,27 @@
+
+Summary
+-------
+This directory contains ASM implementations of the functions
+longest_match() and inflate_fast().
+
+
+Use instructions
+----------------
+Assemble using MASM, and copy the object files into the zlib source
+directory, then run the appropriate makefile, as suggested below. You can
+donwload MASM from here:
+
+ http://www.microsoft.com/downloads/details.aspx?displaylang=en&FamilyID=7a1c9da0-0510-44a2-b042-7ef370530c64
+
+You can also get objects files here:
+
+ http://www.winimage.com/zLibDll/zlib124_masm_obj.zip
+
+Build instructions
+------------------
+* With Microsoft C and MASM:
+nmake -f win32/Makefile.msc LOC="-DASMV -DASMINF" OBJA="match686.obj inffas32.obj"
+
+* With Borland C and TASM:
+make -f win32/Makefile.bor LOCAL_ZLIB="-DASMV -DASMINF" OBJA="match686.obj inffas32.obj" OBJPA="+match686c.obj+match686.obj+inffas32.obj"
+
ADDED compat/zlib/contrib/minizip/Makefile
Index: compat/zlib/contrib/minizip/Makefile
==================================================================
--- compat/zlib/contrib/minizip/Makefile
+++ compat/zlib/contrib/minizip/Makefile
@@ -0,0 +1,25 @@
+CC=cc
+CFLAGS=-O -I../..
+
+UNZ_OBJS = miniunz.o unzip.o ioapi.o ../../libz.a
+ZIP_OBJS = minizip.o zip.o ioapi.o ../../libz.a
+
+.c.o:
+ $(CC) -c $(CFLAGS) $*.c
+
+all: miniunz minizip
+
+miniunz: $(UNZ_OBJS)
+ $(CC) $(CFLAGS) -o $@ $(UNZ_OBJS)
+
+minizip: $(ZIP_OBJS)
+ $(CC) $(CFLAGS) -o $@ $(ZIP_OBJS)
+
+test: miniunz minizip
+ ./minizip test readme.txt
+ ./miniunz -l test.zip
+ mv readme.txt readme.old
+ ./miniunz test.zip
+
+clean:
+ /bin/rm -f *.o *~ minizip miniunz
ADDED compat/zlib/contrib/minizip/Makefile.am
Index: compat/zlib/contrib/minizip/Makefile.am
==================================================================
--- compat/zlib/contrib/minizip/Makefile.am
+++ compat/zlib/contrib/minizip/Makefile.am
@@ -0,0 +1,45 @@
+lib_LTLIBRARIES = libminizip.la
+
+if COND_DEMOS
+bin_PROGRAMS = miniunzip minizip
+endif
+
+zlib_top_srcdir = $(top_srcdir)/../..
+zlib_top_builddir = $(top_builddir)/../..
+
+AM_CPPFLAGS = -I$(zlib_top_srcdir)
+AM_LDFLAGS = -L$(zlib_top_builddir)
+
+if WIN32
+iowin32_src = iowin32.c
+iowin32_h = iowin32.h
+endif
+
+libminizip_la_SOURCES = \
+ ioapi.c \
+ mztools.c \
+ unzip.c \
+ zip.c \
+ ${iowin32_src}
+
+libminizip_la_LDFLAGS = $(AM_LDFLAGS) -version-info 1:0:0 -lz
+
+minizip_includedir = $(includedir)/minizip
+minizip_include_HEADERS = \
+ crypt.h \
+ ioapi.h \
+ mztools.h \
+ unzip.h \
+ zip.h \
+ ${iowin32_h}
+
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = minizip.pc
+
+EXTRA_PROGRAMS = miniunzip minizip
+
+miniunzip_SOURCES = miniunz.c
+miniunzip_LDADD = libminizip.la
+
+minizip_SOURCES = minizip.c
+minizip_LDADD = libminizip.la -lz
ADDED compat/zlib/contrib/minizip/MiniZip64_Changes.txt
Index: compat/zlib/contrib/minizip/MiniZip64_Changes.txt
==================================================================
--- compat/zlib/contrib/minizip/MiniZip64_Changes.txt
+++ compat/zlib/contrib/minizip/MiniZip64_Changes.txt
@@ -0,0 +1,6 @@
+
+MiniZip 1.1 was derrived from MiniZip at version 1.01f
+
+Change in 1.0 (Okt 2009)
+ - **TODO - Add history**
+
ADDED compat/zlib/contrib/minizip/MiniZip64_info.txt
Index: compat/zlib/contrib/minizip/MiniZip64_info.txt
==================================================================
--- compat/zlib/contrib/minizip/MiniZip64_info.txt
+++ compat/zlib/contrib/minizip/MiniZip64_info.txt
@@ -0,0 +1,74 @@
+MiniZip - Copyright (c) 1998-2010 - by Gilles Vollant - version 1.1 64 bits from Mathias Svensson
+
+Introduction
+---------------------
+MiniZip 1.1 is built from MiniZip 1.0 by Gilles Vollant ( http://www.winimage.com/zLibDll/minizip.html )
+
+When adding ZIP64 support into minizip it would result into risk of breaking compatibility with minizip 1.0.
+All possible work was done for compatibility.
+
+
+Background
+---------------------
+When adding ZIP64 support Mathias Svensson found that Even Rouault have added ZIP64
+support for unzip.c into minizip for a open source project called gdal ( http://www.gdal.org/ )
+
+That was used as a starting point. And after that ZIP64 support was added to zip.c
+some refactoring and code cleanup was also done.
+
+
+Changed from MiniZip 1.0 to MiniZip 1.1
+---------------------------------------
+* Added ZIP64 support for unzip ( by Even Rouault )
+* Added ZIP64 support for zip ( by Mathias Svensson )
+* Reverted some changed that Even Rouault did.
+* Bunch of patches received from Gulles Vollant that he received for MiniZip from various users.
+* Added unzip patch for BZIP Compression method (patch create by Daniel Borca)
+* Added BZIP Compress method for zip
+* Did some refactoring and code cleanup
+
+
+Credits
+
+ Gilles Vollant - Original MiniZip author
+ Even Rouault - ZIP64 unzip Support
+ Daniel Borca - BZip Compression method support in unzip
+ Mathias Svensson - ZIP64 zip support
+ Mathias Svensson - BZip Compression method support in zip
+
+ Resources
+
+ ZipLayout http://result42.com/projects/ZipFileLayout
+ Command line tool for Windows that shows the layout and information of the headers in a zip archive.
+ Used when debugging and validating the creation of zip files using MiniZip64
+
+
+ ZIP App Note http://www.pkware.com/documents/casestudies/APPNOTE.TXT
+ Zip File specification
+
+
+Notes.
+ * To be able to use BZip compression method in zip64.c or unzip64.c the BZIP2 lib is needed and HAVE_BZIP2 need to be defined.
+
+License
+----------------------------------------------------------
+ Condition of use and distribution are the same than zlib :
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+----------------------------------------------------------
+
ADDED compat/zlib/contrib/minizip/configure.ac
Index: compat/zlib/contrib/minizip/configure.ac
==================================================================
--- compat/zlib/contrib/minizip/configure.ac
+++ compat/zlib/contrib/minizip/configure.ac
@@ -0,0 +1,32 @@
+# -*- Autoconf -*-
+# Process this file with autoconf to produce a configure script.
+
+AC_INIT([minizip], [1.2.8], [bugzilla.redhat.com])
+AC_CONFIG_SRCDIR([minizip.c])
+AM_INIT_AUTOMAKE([foreign])
+LT_INIT
+
+AC_MSG_CHECKING([whether to build example programs])
+AC_ARG_ENABLE([demos], AC_HELP_STRING([--enable-demos], [build example programs]))
+AM_CONDITIONAL([COND_DEMOS], [test "$enable_demos" = yes])
+if test "$enable_demos" = yes
+then
+ AC_MSG_RESULT([yes])
+else
+ AC_MSG_RESULT([no])
+fi
+
+case "${host}" in
+ *-mingw* | mingw*)
+ WIN32="yes"
+ ;;
+ *)
+ ;;
+esac
+AM_CONDITIONAL([WIN32], [test "${WIN32}" = "yes"])
+
+
+AC_SUBST([HAVE_UNISTD_H], [0])
+AC_CHECK_HEADER([unistd.h], [HAVE_UNISTD_H=1], [])
+AC_CONFIG_FILES([Makefile minizip.pc])
+AC_OUTPUT
ADDED compat/zlib/contrib/minizip/crypt.h
Index: compat/zlib/contrib/minizip/crypt.h
==================================================================
--- compat/zlib/contrib/minizip/crypt.h
+++ compat/zlib/contrib/minizip/crypt.h
@@ -0,0 +1,131 @@
+/* crypt.h -- base code for crypt/uncrypt ZIPfile
+
+
+ Version 1.01e, February 12th, 2005
+
+ Copyright (C) 1998-2005 Gilles Vollant
+
+ This code is a modified version of crypting code in Infozip distribution
+
+ The encryption/decryption parts of this source code (as opposed to the
+ non-echoing password parts) were originally written in Europe. The
+ whole source package can be freely distributed, including from the USA.
+ (Prior to January 2000, re-export from the US was a violation of US law.)
+
+ This encryption code is a direct transcription of the algorithm from
+ Roger Schlafly, described by Phil Katz in the file appnote.txt. This
+ file (appnote.txt) is distributed with the PKZIP program (even in the
+ version without encryption capabilities).
+
+ If you don't need crypting in your application, just define symbols
+ NOCRYPT and NOUNCRYPT.
+
+ This code support the "Traditional PKWARE Encryption".
+
+ The new AES encryption added on Zip format by Winzip (see the page
+ http://www.winzip.com/aes_info.htm ) and PKWare PKZip 5.x Strong
+ Encryption is not supported.
+*/
+
+#define CRC32(c, b) ((*(pcrc_32_tab+(((int)(c) ^ (b)) & 0xff))) ^ ((c) >> 8))
+
+/***********************************************************************
+ * Return the next byte in the pseudo-random sequence
+ */
+static int decrypt_byte(unsigned long* pkeys, const z_crc_t* pcrc_32_tab)
+{
+ unsigned temp; /* POTENTIAL BUG: temp*(temp^1) may overflow in an
+ * unpredictable manner on 16-bit systems; not a problem
+ * with any known compiler so far, though */
+
+ temp = ((unsigned)(*(pkeys+2)) & 0xffff) | 2;
+ return (int)(((temp * (temp ^ 1)) >> 8) & 0xff);
+}
+
+/***********************************************************************
+ * Update the encryption keys with the next byte of plain text
+ */
+static int update_keys(unsigned long* pkeys,const z_crc_t* pcrc_32_tab,int c)
+{
+ (*(pkeys+0)) = CRC32((*(pkeys+0)), c);
+ (*(pkeys+1)) += (*(pkeys+0)) & 0xff;
+ (*(pkeys+1)) = (*(pkeys+1)) * 134775813L + 1;
+ {
+ register int keyshift = (int)((*(pkeys+1)) >> 24);
+ (*(pkeys+2)) = CRC32((*(pkeys+2)), keyshift);
+ }
+ return c;
+}
+
+
+/***********************************************************************
+ * Initialize the encryption keys and the random header according to
+ * the given password.
+ */
+static void init_keys(const char* passwd,unsigned long* pkeys,const z_crc_t* pcrc_32_tab)
+{
+ *(pkeys+0) = 305419896L;
+ *(pkeys+1) = 591751049L;
+ *(pkeys+2) = 878082192L;
+ while (*passwd != '\0') {
+ update_keys(pkeys,pcrc_32_tab,(int)*passwd);
+ passwd++;
+ }
+}
+
+#define zdecode(pkeys,pcrc_32_tab,c) \
+ (update_keys(pkeys,pcrc_32_tab,c ^= decrypt_byte(pkeys,pcrc_32_tab)))
+
+#define zencode(pkeys,pcrc_32_tab,c,t) \
+ (t=decrypt_byte(pkeys,pcrc_32_tab), update_keys(pkeys,pcrc_32_tab,c), t^(c))
+
+#ifdef INCLUDECRYPTINGCODE_IFCRYPTALLOWED
+
+#define RAND_HEAD_LEN 12
+ /* "last resort" source for second part of crypt seed pattern */
+# ifndef ZCR_SEED2
+# define ZCR_SEED2 3141592654UL /* use PI as default pattern */
+# endif
+
+static int crypthead(const char* passwd, /* password string */
+ unsigned char* buf, /* where to write header */
+ int bufSize,
+ unsigned long* pkeys,
+ const z_crc_t* pcrc_32_tab,
+ unsigned long crcForCrypting)
+{
+ int n; /* index in random header */
+ int t; /* temporary */
+ int c; /* random byte */
+ unsigned char header[RAND_HEAD_LEN-2]; /* random header */
+ static unsigned calls = 0; /* ensure different random header each time */
+
+ if (bufSize> 7) & 0xff;
+ header[n] = (unsigned char)zencode(pkeys, pcrc_32_tab, c, t);
+ }
+ /* Encrypt random header (last two bytes is high word of crc) */
+ init_keys(passwd, pkeys, pcrc_32_tab);
+ for (n = 0; n < RAND_HEAD_LEN-2; n++)
+ {
+ buf[n] = (unsigned char)zencode(pkeys, pcrc_32_tab, header[n], t);
+ }
+ buf[n++] = (unsigned char)zencode(pkeys, pcrc_32_tab, (int)(crcForCrypting >> 16) & 0xff, t);
+ buf[n++] = (unsigned char)zencode(pkeys, pcrc_32_tab, (int)(crcForCrypting >> 24) & 0xff, t);
+ return n;
+}
+
+#endif
ADDED compat/zlib/contrib/minizip/ioapi.c
Index: compat/zlib/contrib/minizip/ioapi.c
==================================================================
--- compat/zlib/contrib/minizip/ioapi.c
+++ compat/zlib/contrib/minizip/ioapi.c
@@ -0,0 +1,247 @@
+/* ioapi.h -- IO base function header for compress/uncompress .zip
+ part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html )
+
+ Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html )
+
+ Modifications for Zip64 support
+ Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com )
+
+ For more info read MiniZip_info.txt
+
+*/
+
+#if defined(_WIN32) && (!(defined(_CRT_SECURE_NO_WARNINGS)))
+ #define _CRT_SECURE_NO_WARNINGS
+#endif
+
+#if defined(__APPLE__) || defined(IOAPI_NO_64)
+// In darwin and perhaps other BSD variants off_t is a 64 bit value, hence no need for specific 64 bit functions
+#define FOPEN_FUNC(filename, mode) fopen(filename, mode)
+#define FTELLO_FUNC(stream) ftello(stream)
+#define FSEEKO_FUNC(stream, offset, origin) fseeko(stream, offset, origin)
+#else
+#define FOPEN_FUNC(filename, mode) fopen64(filename, mode)
+#define FTELLO_FUNC(stream) ftello64(stream)
+#define FSEEKO_FUNC(stream, offset, origin) fseeko64(stream, offset, origin)
+#endif
+
+
+#include "ioapi.h"
+
+voidpf call_zopen64 (const zlib_filefunc64_32_def* pfilefunc,const void*filename,int mode)
+{
+ if (pfilefunc->zfile_func64.zopen64_file != NULL)
+ return (*(pfilefunc->zfile_func64.zopen64_file)) (pfilefunc->zfile_func64.opaque,filename,mode);
+ else
+ {
+ return (*(pfilefunc->zopen32_file))(pfilefunc->zfile_func64.opaque,(const char*)filename,mode);
+ }
+}
+
+long call_zseek64 (const zlib_filefunc64_32_def* pfilefunc,voidpf filestream, ZPOS64_T offset, int origin)
+{
+ if (pfilefunc->zfile_func64.zseek64_file != NULL)
+ return (*(pfilefunc->zfile_func64.zseek64_file)) (pfilefunc->zfile_func64.opaque,filestream,offset,origin);
+ else
+ {
+ uLong offsetTruncated = (uLong)offset;
+ if (offsetTruncated != offset)
+ return -1;
+ else
+ return (*(pfilefunc->zseek32_file))(pfilefunc->zfile_func64.opaque,filestream,offsetTruncated,origin);
+ }
+}
+
+ZPOS64_T call_ztell64 (const zlib_filefunc64_32_def* pfilefunc,voidpf filestream)
+{
+ if (pfilefunc->zfile_func64.zseek64_file != NULL)
+ return (*(pfilefunc->zfile_func64.ztell64_file)) (pfilefunc->zfile_func64.opaque,filestream);
+ else
+ {
+ uLong tell_uLong = (*(pfilefunc->ztell32_file))(pfilefunc->zfile_func64.opaque,filestream);
+ if ((tell_uLong) == MAXU32)
+ return (ZPOS64_T)-1;
+ else
+ return tell_uLong;
+ }
+}
+
+void fill_zlib_filefunc64_32_def_from_filefunc32(zlib_filefunc64_32_def* p_filefunc64_32,const zlib_filefunc_def* p_filefunc32)
+{
+ p_filefunc64_32->zfile_func64.zopen64_file = NULL;
+ p_filefunc64_32->zopen32_file = p_filefunc32->zopen_file;
+ p_filefunc64_32->zfile_func64.zerror_file = p_filefunc32->zerror_file;
+ p_filefunc64_32->zfile_func64.zread_file = p_filefunc32->zread_file;
+ p_filefunc64_32->zfile_func64.zwrite_file = p_filefunc32->zwrite_file;
+ p_filefunc64_32->zfile_func64.ztell64_file = NULL;
+ p_filefunc64_32->zfile_func64.zseek64_file = NULL;
+ p_filefunc64_32->zfile_func64.zclose_file = p_filefunc32->zclose_file;
+ p_filefunc64_32->zfile_func64.zerror_file = p_filefunc32->zerror_file;
+ p_filefunc64_32->zfile_func64.opaque = p_filefunc32->opaque;
+ p_filefunc64_32->zseek32_file = p_filefunc32->zseek_file;
+ p_filefunc64_32->ztell32_file = p_filefunc32->ztell_file;
+}
+
+
+
+static voidpf ZCALLBACK fopen_file_func OF((voidpf opaque, const char* filename, int mode));
+static uLong ZCALLBACK fread_file_func OF((voidpf opaque, voidpf stream, void* buf, uLong size));
+static uLong ZCALLBACK fwrite_file_func OF((voidpf opaque, voidpf stream, const void* buf,uLong size));
+static ZPOS64_T ZCALLBACK ftell64_file_func OF((voidpf opaque, voidpf stream));
+static long ZCALLBACK fseek64_file_func OF((voidpf opaque, voidpf stream, ZPOS64_T offset, int origin));
+static int ZCALLBACK fclose_file_func OF((voidpf opaque, voidpf stream));
+static int ZCALLBACK ferror_file_func OF((voidpf opaque, voidpf stream));
+
+static voidpf ZCALLBACK fopen_file_func (voidpf opaque, const char* filename, int mode)
+{
+ FILE* file = NULL;
+ const char* mode_fopen = NULL;
+ if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER)==ZLIB_FILEFUNC_MODE_READ)
+ mode_fopen = "rb";
+ else
+ if (mode & ZLIB_FILEFUNC_MODE_EXISTING)
+ mode_fopen = "r+b";
+ else
+ if (mode & ZLIB_FILEFUNC_MODE_CREATE)
+ mode_fopen = "wb";
+
+ if ((filename!=NULL) && (mode_fopen != NULL))
+ file = fopen(filename, mode_fopen);
+ return file;
+}
+
+static voidpf ZCALLBACK fopen64_file_func (voidpf opaque, const void* filename, int mode)
+{
+ FILE* file = NULL;
+ const char* mode_fopen = NULL;
+ if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER)==ZLIB_FILEFUNC_MODE_READ)
+ mode_fopen = "rb";
+ else
+ if (mode & ZLIB_FILEFUNC_MODE_EXISTING)
+ mode_fopen = "r+b";
+ else
+ if (mode & ZLIB_FILEFUNC_MODE_CREATE)
+ mode_fopen = "wb";
+
+ if ((filename!=NULL) && (mode_fopen != NULL))
+ file = FOPEN_FUNC((const char*)filename, mode_fopen);
+ return file;
+}
+
+
+static uLong ZCALLBACK fread_file_func (voidpf opaque, voidpf stream, void* buf, uLong size)
+{
+ uLong ret;
+ ret = (uLong)fread(buf, 1, (size_t)size, (FILE *)stream);
+ return ret;
+}
+
+static uLong ZCALLBACK fwrite_file_func (voidpf opaque, voidpf stream, const void* buf, uLong size)
+{
+ uLong ret;
+ ret = (uLong)fwrite(buf, 1, (size_t)size, (FILE *)stream);
+ return ret;
+}
+
+static long ZCALLBACK ftell_file_func (voidpf opaque, voidpf stream)
+{
+ long ret;
+ ret = ftell((FILE *)stream);
+ return ret;
+}
+
+
+static ZPOS64_T ZCALLBACK ftell64_file_func (voidpf opaque, voidpf stream)
+{
+ ZPOS64_T ret;
+ ret = FTELLO_FUNC((FILE *)stream);
+ return ret;
+}
+
+static long ZCALLBACK fseek_file_func (voidpf opaque, voidpf stream, uLong offset, int origin)
+{
+ int fseek_origin=0;
+ long ret;
+ switch (origin)
+ {
+ case ZLIB_FILEFUNC_SEEK_CUR :
+ fseek_origin = SEEK_CUR;
+ break;
+ case ZLIB_FILEFUNC_SEEK_END :
+ fseek_origin = SEEK_END;
+ break;
+ case ZLIB_FILEFUNC_SEEK_SET :
+ fseek_origin = SEEK_SET;
+ break;
+ default: return -1;
+ }
+ ret = 0;
+ if (fseek((FILE *)stream, offset, fseek_origin) != 0)
+ ret = -1;
+ return ret;
+}
+
+static long ZCALLBACK fseek64_file_func (voidpf opaque, voidpf stream, ZPOS64_T offset, int origin)
+{
+ int fseek_origin=0;
+ long ret;
+ switch (origin)
+ {
+ case ZLIB_FILEFUNC_SEEK_CUR :
+ fseek_origin = SEEK_CUR;
+ break;
+ case ZLIB_FILEFUNC_SEEK_END :
+ fseek_origin = SEEK_END;
+ break;
+ case ZLIB_FILEFUNC_SEEK_SET :
+ fseek_origin = SEEK_SET;
+ break;
+ default: return -1;
+ }
+ ret = 0;
+
+ if(FSEEKO_FUNC((FILE *)stream, offset, fseek_origin) != 0)
+ ret = -1;
+
+ return ret;
+}
+
+
+static int ZCALLBACK fclose_file_func (voidpf opaque, voidpf stream)
+{
+ int ret;
+ ret = fclose((FILE *)stream);
+ return ret;
+}
+
+static int ZCALLBACK ferror_file_func (voidpf opaque, voidpf stream)
+{
+ int ret;
+ ret = ferror((FILE *)stream);
+ return ret;
+}
+
+void fill_fopen_filefunc (pzlib_filefunc_def)
+ zlib_filefunc_def* pzlib_filefunc_def;
+{
+ pzlib_filefunc_def->zopen_file = fopen_file_func;
+ pzlib_filefunc_def->zread_file = fread_file_func;
+ pzlib_filefunc_def->zwrite_file = fwrite_file_func;
+ pzlib_filefunc_def->ztell_file = ftell_file_func;
+ pzlib_filefunc_def->zseek_file = fseek_file_func;
+ pzlib_filefunc_def->zclose_file = fclose_file_func;
+ pzlib_filefunc_def->zerror_file = ferror_file_func;
+ pzlib_filefunc_def->opaque = NULL;
+}
+
+void fill_fopen64_filefunc (zlib_filefunc64_def* pzlib_filefunc_def)
+{
+ pzlib_filefunc_def->zopen64_file = fopen64_file_func;
+ pzlib_filefunc_def->zread_file = fread_file_func;
+ pzlib_filefunc_def->zwrite_file = fwrite_file_func;
+ pzlib_filefunc_def->ztell64_file = ftell64_file_func;
+ pzlib_filefunc_def->zseek64_file = fseek64_file_func;
+ pzlib_filefunc_def->zclose_file = fclose_file_func;
+ pzlib_filefunc_def->zerror_file = ferror_file_func;
+ pzlib_filefunc_def->opaque = NULL;
+}
ADDED compat/zlib/contrib/minizip/ioapi.h
Index: compat/zlib/contrib/minizip/ioapi.h
==================================================================
--- compat/zlib/contrib/minizip/ioapi.h
+++ compat/zlib/contrib/minizip/ioapi.h
@@ -0,0 +1,208 @@
+/* ioapi.h -- IO base function header for compress/uncompress .zip
+ part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html )
+
+ Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html )
+
+ Modifications for Zip64 support
+ Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com )
+
+ For more info read MiniZip_info.txt
+
+ Changes
+
+ Oct-2009 - Defined ZPOS64_T to fpos_t on windows and u_int64_t on linux. (might need to find a better why for this)
+ Oct-2009 - Change to fseeko64, ftello64 and fopen64 so large files would work on linux.
+ More if/def section may be needed to support other platforms
+ Oct-2009 - Defined fxxxx64 calls to normal fopen/ftell/fseek so they would compile on windows.
+ (but you should use iowin32.c for windows instead)
+
+*/
+
+#ifndef _ZLIBIOAPI64_H
+#define _ZLIBIOAPI64_H
+
+#if (!defined(_WIN32)) && (!defined(WIN32)) && (!defined(__APPLE__))
+
+ // Linux needs this to support file operation on files larger then 4+GB
+ // But might need better if/def to select just the platforms that needs them.
+
+ #ifndef __USE_FILE_OFFSET64
+ #define __USE_FILE_OFFSET64
+ #endif
+ #ifndef __USE_LARGEFILE64
+ #define __USE_LARGEFILE64
+ #endif
+ #ifndef _LARGEFILE64_SOURCE
+ #define _LARGEFILE64_SOURCE
+ #endif
+ #ifndef _FILE_OFFSET_BIT
+ #define _FILE_OFFSET_BIT 64
+ #endif
+
+#endif
+
+#include
+#include
+#include "zlib.h"
+
+#if defined(USE_FILE32API)
+#define fopen64 fopen
+#define ftello64 ftell
+#define fseeko64 fseek
+#else
+#ifdef __FreeBSD__
+#define fopen64 fopen
+#define ftello64 ftello
+#define fseeko64 fseeko
+#endif
+#ifdef _MSC_VER
+ #define fopen64 fopen
+ #if (_MSC_VER >= 1400) && (!(defined(NO_MSCVER_FILE64_FUNC)))
+ #define ftello64 _ftelli64
+ #define fseeko64 _fseeki64
+ #else // old MSC
+ #define ftello64 ftell
+ #define fseeko64 fseek
+ #endif
+#endif
+#endif
+
+/*
+#ifndef ZPOS64_T
+ #ifdef _WIN32
+ #define ZPOS64_T fpos_t
+ #else
+ #include
+ #define ZPOS64_T uint64_t
+ #endif
+#endif
+*/
+
+#ifdef HAVE_MINIZIP64_CONF_H
+#include "mz64conf.h"
+#endif
+
+/* a type choosen by DEFINE */
+#ifdef HAVE_64BIT_INT_CUSTOM
+typedef 64BIT_INT_CUSTOM_TYPE ZPOS64_T;
+#else
+#ifdef HAS_STDINT_H
+#include "stdint.h"
+typedef uint64_t ZPOS64_T;
+#else
+
+/* Maximum unsigned 32-bit value used as placeholder for zip64 */
+#define MAXU32 0xffffffff
+
+#if defined(_MSC_VER) || defined(__BORLANDC__)
+typedef unsigned __int64 ZPOS64_T;
+#else
+typedef unsigned long long int ZPOS64_T;
+#endif
+#endif
+#endif
+
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+#define ZLIB_FILEFUNC_SEEK_CUR (1)
+#define ZLIB_FILEFUNC_SEEK_END (2)
+#define ZLIB_FILEFUNC_SEEK_SET (0)
+
+#define ZLIB_FILEFUNC_MODE_READ (1)
+#define ZLIB_FILEFUNC_MODE_WRITE (2)
+#define ZLIB_FILEFUNC_MODE_READWRITEFILTER (3)
+
+#define ZLIB_FILEFUNC_MODE_EXISTING (4)
+#define ZLIB_FILEFUNC_MODE_CREATE (8)
+
+
+#ifndef ZCALLBACK
+ #if (defined(WIN32) || defined(_WIN32) || defined (WINDOWS) || defined (_WINDOWS)) && defined(CALLBACK) && defined (USEWINDOWS_CALLBACK)
+ #define ZCALLBACK CALLBACK
+ #else
+ #define ZCALLBACK
+ #endif
+#endif
+
+
+
+
+typedef voidpf (ZCALLBACK *open_file_func) OF((voidpf opaque, const char* filename, int mode));
+typedef uLong (ZCALLBACK *read_file_func) OF((voidpf opaque, voidpf stream, void* buf, uLong size));
+typedef uLong (ZCALLBACK *write_file_func) OF((voidpf opaque, voidpf stream, const void* buf, uLong size));
+typedef int (ZCALLBACK *close_file_func) OF((voidpf opaque, voidpf stream));
+typedef int (ZCALLBACK *testerror_file_func) OF((voidpf opaque, voidpf stream));
+
+typedef long (ZCALLBACK *tell_file_func) OF((voidpf opaque, voidpf stream));
+typedef long (ZCALLBACK *seek_file_func) OF((voidpf opaque, voidpf stream, uLong offset, int origin));
+
+
+/* here is the "old" 32 bits structure structure */
+typedef struct zlib_filefunc_def_s
+{
+ open_file_func zopen_file;
+ read_file_func zread_file;
+ write_file_func zwrite_file;
+ tell_file_func ztell_file;
+ seek_file_func zseek_file;
+ close_file_func zclose_file;
+ testerror_file_func zerror_file;
+ voidpf opaque;
+} zlib_filefunc_def;
+
+typedef ZPOS64_T (ZCALLBACK *tell64_file_func) OF((voidpf opaque, voidpf stream));
+typedef long (ZCALLBACK *seek64_file_func) OF((voidpf opaque, voidpf stream, ZPOS64_T offset, int origin));
+typedef voidpf (ZCALLBACK *open64_file_func) OF((voidpf opaque, const void* filename, int mode));
+
+typedef struct zlib_filefunc64_def_s
+{
+ open64_file_func zopen64_file;
+ read_file_func zread_file;
+ write_file_func zwrite_file;
+ tell64_file_func ztell64_file;
+ seek64_file_func zseek64_file;
+ close_file_func zclose_file;
+ testerror_file_func zerror_file;
+ voidpf opaque;
+} zlib_filefunc64_def;
+
+void fill_fopen64_filefunc OF((zlib_filefunc64_def* pzlib_filefunc_def));
+void fill_fopen_filefunc OF((zlib_filefunc_def* pzlib_filefunc_def));
+
+/* now internal definition, only for zip.c and unzip.h */
+typedef struct zlib_filefunc64_32_def_s
+{
+ zlib_filefunc64_def zfile_func64;
+ open_file_func zopen32_file;
+ tell_file_func ztell32_file;
+ seek_file_func zseek32_file;
+} zlib_filefunc64_32_def;
+
+
+#define ZREAD64(filefunc,filestream,buf,size) ((*((filefunc).zfile_func64.zread_file)) ((filefunc).zfile_func64.opaque,filestream,buf,size))
+#define ZWRITE64(filefunc,filestream,buf,size) ((*((filefunc).zfile_func64.zwrite_file)) ((filefunc).zfile_func64.opaque,filestream,buf,size))
+//#define ZTELL64(filefunc,filestream) ((*((filefunc).ztell64_file)) ((filefunc).opaque,filestream))
+//#define ZSEEK64(filefunc,filestream,pos,mode) ((*((filefunc).zseek64_file)) ((filefunc).opaque,filestream,pos,mode))
+#define ZCLOSE64(filefunc,filestream) ((*((filefunc).zfile_func64.zclose_file)) ((filefunc).zfile_func64.opaque,filestream))
+#define ZERROR64(filefunc,filestream) ((*((filefunc).zfile_func64.zerror_file)) ((filefunc).zfile_func64.opaque,filestream))
+
+voidpf call_zopen64 OF((const zlib_filefunc64_32_def* pfilefunc,const void*filename,int mode));
+long call_zseek64 OF((const zlib_filefunc64_32_def* pfilefunc,voidpf filestream, ZPOS64_T offset, int origin));
+ZPOS64_T call_ztell64 OF((const zlib_filefunc64_32_def* pfilefunc,voidpf filestream));
+
+void fill_zlib_filefunc64_32_def_from_filefunc32(zlib_filefunc64_32_def* p_filefunc64_32,const zlib_filefunc_def* p_filefunc32);
+
+#define ZOPEN64(filefunc,filename,mode) (call_zopen64((&(filefunc)),(filename),(mode)))
+#define ZTELL64(filefunc,filestream) (call_ztell64((&(filefunc)),(filestream)))
+#define ZSEEK64(filefunc,filestream,pos,mode) (call_zseek64((&(filefunc)),(filestream),(pos),(mode)))
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
ADDED compat/zlib/contrib/minizip/iowin32.c
Index: compat/zlib/contrib/minizip/iowin32.c
==================================================================
--- compat/zlib/contrib/minizip/iowin32.c
+++ compat/zlib/contrib/minizip/iowin32.c
@@ -0,0 +1,461 @@
+/* iowin32.c -- IO base function header for compress/uncompress .zip
+ Version 1.1, February 14h, 2010
+ part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html )
+
+ Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html )
+
+ Modifications for Zip64 support
+ Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com )
+
+ For more info read MiniZip_info.txt
+
+*/
+
+#include
+
+#include "zlib.h"
+#include "ioapi.h"
+#include "iowin32.h"
+
+#ifndef INVALID_HANDLE_VALUE
+#define INVALID_HANDLE_VALUE (0xFFFFFFFF)
+#endif
+
+#ifndef INVALID_SET_FILE_POINTER
+#define INVALID_SET_FILE_POINTER ((DWORD)-1)
+#endif
+
+
+#if defined(WINAPI_FAMILY_PARTITION) && (!(defined(IOWIN32_USING_WINRT_API)))
+#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP)
+#define IOWIN32_USING_WINRT_API 1
+#endif
+#endif
+
+voidpf ZCALLBACK win32_open_file_func OF((voidpf opaque, const char* filename, int mode));
+uLong ZCALLBACK win32_read_file_func OF((voidpf opaque, voidpf stream, void* buf, uLong size));
+uLong ZCALLBACK win32_write_file_func OF((voidpf opaque, voidpf stream, const void* buf, uLong size));
+ZPOS64_T ZCALLBACK win32_tell64_file_func OF((voidpf opaque, voidpf stream));
+long ZCALLBACK win32_seek64_file_func OF((voidpf opaque, voidpf stream, ZPOS64_T offset, int origin));
+int ZCALLBACK win32_close_file_func OF((voidpf opaque, voidpf stream));
+int ZCALLBACK win32_error_file_func OF((voidpf opaque, voidpf stream));
+
+typedef struct
+{
+ HANDLE hf;
+ int error;
+} WIN32FILE_IOWIN;
+
+
+static void win32_translate_open_mode(int mode,
+ DWORD* lpdwDesiredAccess,
+ DWORD* lpdwCreationDisposition,
+ DWORD* lpdwShareMode,
+ DWORD* lpdwFlagsAndAttributes)
+{
+ *lpdwDesiredAccess = *lpdwShareMode = *lpdwFlagsAndAttributes = *lpdwCreationDisposition = 0;
+
+ if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER)==ZLIB_FILEFUNC_MODE_READ)
+ {
+ *lpdwDesiredAccess = GENERIC_READ;
+ *lpdwCreationDisposition = OPEN_EXISTING;
+ *lpdwShareMode = FILE_SHARE_READ;
+ }
+ else if (mode & ZLIB_FILEFUNC_MODE_EXISTING)
+ {
+ *lpdwDesiredAccess = GENERIC_WRITE | GENERIC_READ;
+ *lpdwCreationDisposition = OPEN_EXISTING;
+ }
+ else if (mode & ZLIB_FILEFUNC_MODE_CREATE)
+ {
+ *lpdwDesiredAccess = GENERIC_WRITE | GENERIC_READ;
+ *lpdwCreationDisposition = CREATE_ALWAYS;
+ }
+}
+
+static voidpf win32_build_iowin(HANDLE hFile)
+{
+ voidpf ret=NULL;
+
+ if ((hFile != NULL) && (hFile != INVALID_HANDLE_VALUE))
+ {
+ WIN32FILE_IOWIN w32fiow;
+ w32fiow.hf = hFile;
+ w32fiow.error = 0;
+ ret = malloc(sizeof(WIN32FILE_IOWIN));
+
+ if (ret==NULL)
+ CloseHandle(hFile);
+ else
+ *((WIN32FILE_IOWIN*)ret) = w32fiow;
+ }
+ return ret;
+}
+
+voidpf ZCALLBACK win32_open64_file_func (voidpf opaque,const void* filename,int mode)
+{
+ const char* mode_fopen = NULL;
+ DWORD dwDesiredAccess,dwCreationDisposition,dwShareMode,dwFlagsAndAttributes ;
+ HANDLE hFile = NULL;
+
+ win32_translate_open_mode(mode,&dwDesiredAccess,&dwCreationDisposition,&dwShareMode,&dwFlagsAndAttributes);
+
+#ifdef IOWIN32_USING_WINRT_API
+#ifdef UNICODE
+ if ((filename!=NULL) && (dwDesiredAccess != 0))
+ hFile = CreateFile2((LPCTSTR)filename, dwDesiredAccess, dwShareMode, dwCreationDisposition, NULL);
+#else
+ if ((filename!=NULL) && (dwDesiredAccess != 0))
+ {
+ WCHAR filenameW[FILENAME_MAX + 0x200 + 1];
+ MultiByteToWideChar(CP_ACP,0,(const char*)filename,-1,filenameW,FILENAME_MAX + 0x200);
+ hFile = CreateFile2(filenameW, dwDesiredAccess, dwShareMode, dwCreationDisposition, NULL);
+ }
+#endif
+#else
+ if ((filename!=NULL) && (dwDesiredAccess != 0))
+ hFile = CreateFile((LPCTSTR)filename, dwDesiredAccess, dwShareMode, NULL, dwCreationDisposition, dwFlagsAndAttributes, NULL);
+#endif
+
+ return win32_build_iowin(hFile);
+}
+
+
+voidpf ZCALLBACK win32_open64_file_funcA (voidpf opaque,const void* filename,int mode)
+{
+ const char* mode_fopen = NULL;
+ DWORD dwDesiredAccess,dwCreationDisposition,dwShareMode,dwFlagsAndAttributes ;
+ HANDLE hFile = NULL;
+
+ win32_translate_open_mode(mode,&dwDesiredAccess,&dwCreationDisposition,&dwShareMode,&dwFlagsAndAttributes);
+
+#ifdef IOWIN32_USING_WINRT_API
+ if ((filename!=NULL) && (dwDesiredAccess != 0))
+ {
+ WCHAR filenameW[FILENAME_MAX + 0x200 + 1];
+ MultiByteToWideChar(CP_ACP,0,(const char*)filename,-1,filenameW,FILENAME_MAX + 0x200);
+ hFile = CreateFile2(filenameW, dwDesiredAccess, dwShareMode, dwCreationDisposition, NULL);
+ }
+#else
+ if ((filename!=NULL) && (dwDesiredAccess != 0))
+ hFile = CreateFileA((LPCSTR)filename, dwDesiredAccess, dwShareMode, NULL, dwCreationDisposition, dwFlagsAndAttributes, NULL);
+#endif
+
+ return win32_build_iowin(hFile);
+}
+
+
+voidpf ZCALLBACK win32_open64_file_funcW (voidpf opaque,const void* filename,int mode)
+{
+ const char* mode_fopen = NULL;
+ DWORD dwDesiredAccess,dwCreationDisposition,dwShareMode,dwFlagsAndAttributes ;
+ HANDLE hFile = NULL;
+
+ win32_translate_open_mode(mode,&dwDesiredAccess,&dwCreationDisposition,&dwShareMode,&dwFlagsAndAttributes);
+
+#ifdef IOWIN32_USING_WINRT_API
+ if ((filename!=NULL) && (dwDesiredAccess != 0))
+ hFile = CreateFile2((LPCWSTR)filename, dwDesiredAccess, dwShareMode, dwCreationDisposition,NULL);
+#else
+ if ((filename!=NULL) && (dwDesiredAccess != 0))
+ hFile = CreateFileW((LPCWSTR)filename, dwDesiredAccess, dwShareMode, NULL, dwCreationDisposition, dwFlagsAndAttributes, NULL);
+#endif
+
+ return win32_build_iowin(hFile);
+}
+
+
+voidpf ZCALLBACK win32_open_file_func (voidpf opaque,const char* filename,int mode)
+{
+ const char* mode_fopen = NULL;
+ DWORD dwDesiredAccess,dwCreationDisposition,dwShareMode,dwFlagsAndAttributes ;
+ HANDLE hFile = NULL;
+
+ win32_translate_open_mode(mode,&dwDesiredAccess,&dwCreationDisposition,&dwShareMode,&dwFlagsAndAttributes);
+
+#ifdef IOWIN32_USING_WINRT_API
+#ifdef UNICODE
+ if ((filename!=NULL) && (dwDesiredAccess != 0))
+ hFile = CreateFile2((LPCTSTR)filename, dwDesiredAccess, dwShareMode, dwCreationDisposition, NULL);
+#else
+ if ((filename!=NULL) && (dwDesiredAccess != 0))
+ {
+ WCHAR filenameW[FILENAME_MAX + 0x200 + 1];
+ MultiByteToWideChar(CP_ACP,0,(const char*)filename,-1,filenameW,FILENAME_MAX + 0x200);
+ hFile = CreateFile2(filenameW, dwDesiredAccess, dwShareMode, dwCreationDisposition, NULL);
+ }
+#endif
+#else
+ if ((filename!=NULL) && (dwDesiredAccess != 0))
+ hFile = CreateFile((LPCTSTR)filename, dwDesiredAccess, dwShareMode, NULL, dwCreationDisposition, dwFlagsAndAttributes, NULL);
+#endif
+
+ return win32_build_iowin(hFile);
+}
+
+
+uLong ZCALLBACK win32_read_file_func (voidpf opaque, voidpf stream, void* buf,uLong size)
+{
+ uLong ret=0;
+ HANDLE hFile = NULL;
+ if (stream!=NULL)
+ hFile = ((WIN32FILE_IOWIN*)stream) -> hf;
+
+ if (hFile != NULL)
+ {
+ if (!ReadFile(hFile, buf, size, &ret, NULL))
+ {
+ DWORD dwErr = GetLastError();
+ if (dwErr == ERROR_HANDLE_EOF)
+ dwErr = 0;
+ ((WIN32FILE_IOWIN*)stream) -> error=(int)dwErr;
+ }
+ }
+
+ return ret;
+}
+
+
+uLong ZCALLBACK win32_write_file_func (voidpf opaque,voidpf stream,const void* buf,uLong size)
+{
+ uLong ret=0;
+ HANDLE hFile = NULL;
+ if (stream!=NULL)
+ hFile = ((WIN32FILE_IOWIN*)stream) -> hf;
+
+ if (hFile != NULL)
+ {
+ if (!WriteFile(hFile, buf, size, &ret, NULL))
+ {
+ DWORD dwErr = GetLastError();
+ if (dwErr == ERROR_HANDLE_EOF)
+ dwErr = 0;
+ ((WIN32FILE_IOWIN*)stream) -> error=(int)dwErr;
+ }
+ }
+
+ return ret;
+}
+
+static BOOL MySetFilePointerEx(HANDLE hFile, LARGE_INTEGER pos, LARGE_INTEGER *newPos, DWORD dwMoveMethod)
+{
+#ifdef IOWIN32_USING_WINRT_API
+ return SetFilePointerEx(hFile, pos, newPos, dwMoveMethod);
+#else
+ LONG lHigh = pos.HighPart;
+ DWORD dwNewPos = SetFilePointer(hFile, pos.LowPart, &lHigh, FILE_CURRENT);
+ BOOL fOk = TRUE;
+ if (dwNewPos == 0xFFFFFFFF)
+ if (GetLastError() != NO_ERROR)
+ fOk = FALSE;
+ if ((newPos != NULL) && (fOk))
+ {
+ newPos->LowPart = dwNewPos;
+ newPos->HighPart = lHigh;
+ }
+ return fOk;
+#endif
+}
+
+long ZCALLBACK win32_tell_file_func (voidpf opaque,voidpf stream)
+{
+ long ret=-1;
+ HANDLE hFile = NULL;
+ if (stream!=NULL)
+ hFile = ((WIN32FILE_IOWIN*)stream) -> hf;
+ if (hFile != NULL)
+ {
+ LARGE_INTEGER pos;
+ pos.QuadPart = 0;
+
+ if (!MySetFilePointerEx(hFile, pos, &pos, FILE_CURRENT))
+ {
+ DWORD dwErr = GetLastError();
+ ((WIN32FILE_IOWIN*)stream) -> error=(int)dwErr;
+ ret = -1;
+ }
+ else
+ ret=(long)pos.LowPart;
+ }
+ return ret;
+}
+
+ZPOS64_T ZCALLBACK win32_tell64_file_func (voidpf opaque, voidpf stream)
+{
+ ZPOS64_T ret= (ZPOS64_T)-1;
+ HANDLE hFile = NULL;
+ if (stream!=NULL)
+ hFile = ((WIN32FILE_IOWIN*)stream)->hf;
+
+ if (hFile)
+ {
+ LARGE_INTEGER pos;
+ pos.QuadPart = 0;
+
+ if (!MySetFilePointerEx(hFile, pos, &pos, FILE_CURRENT))
+ {
+ DWORD dwErr = GetLastError();
+ ((WIN32FILE_IOWIN*)stream) -> error=(int)dwErr;
+ ret = (ZPOS64_T)-1;
+ }
+ else
+ ret=pos.QuadPart;
+ }
+ return ret;
+}
+
+
+long ZCALLBACK win32_seek_file_func (voidpf opaque,voidpf stream,uLong offset,int origin)
+{
+ DWORD dwMoveMethod=0xFFFFFFFF;
+ HANDLE hFile = NULL;
+
+ long ret=-1;
+ if (stream!=NULL)
+ hFile = ((WIN32FILE_IOWIN*)stream) -> hf;
+ switch (origin)
+ {
+ case ZLIB_FILEFUNC_SEEK_CUR :
+ dwMoveMethod = FILE_CURRENT;
+ break;
+ case ZLIB_FILEFUNC_SEEK_END :
+ dwMoveMethod = FILE_END;
+ break;
+ case ZLIB_FILEFUNC_SEEK_SET :
+ dwMoveMethod = FILE_BEGIN;
+ break;
+ default: return -1;
+ }
+
+ if (hFile != NULL)
+ {
+ LARGE_INTEGER pos;
+ pos.QuadPart = offset;
+ if (!MySetFilePointerEx(hFile, pos, NULL, dwMoveMethod))
+ {
+ DWORD dwErr = GetLastError();
+ ((WIN32FILE_IOWIN*)stream) -> error=(int)dwErr;
+ ret = -1;
+ }
+ else
+ ret=0;
+ }
+ return ret;
+}
+
+long ZCALLBACK win32_seek64_file_func (voidpf opaque, voidpf stream,ZPOS64_T offset,int origin)
+{
+ DWORD dwMoveMethod=0xFFFFFFFF;
+ HANDLE hFile = NULL;
+ long ret=-1;
+
+ if (stream!=NULL)
+ hFile = ((WIN32FILE_IOWIN*)stream)->hf;
+
+ switch (origin)
+ {
+ case ZLIB_FILEFUNC_SEEK_CUR :
+ dwMoveMethod = FILE_CURRENT;
+ break;
+ case ZLIB_FILEFUNC_SEEK_END :
+ dwMoveMethod = FILE_END;
+ break;
+ case ZLIB_FILEFUNC_SEEK_SET :
+ dwMoveMethod = FILE_BEGIN;
+ break;
+ default: return -1;
+ }
+
+ if (hFile)
+ {
+ LARGE_INTEGER pos;
+ pos.QuadPart = offset;
+ if (!MySetFilePointerEx(hFile, pos, NULL, FILE_CURRENT))
+ {
+ DWORD dwErr = GetLastError();
+ ((WIN32FILE_IOWIN*)stream) -> error=(int)dwErr;
+ ret = -1;
+ }
+ else
+ ret=0;
+ }
+ return ret;
+}
+
+int ZCALLBACK win32_close_file_func (voidpf opaque, voidpf stream)
+{
+ int ret=-1;
+
+ if (stream!=NULL)
+ {
+ HANDLE hFile;
+ hFile = ((WIN32FILE_IOWIN*)stream) -> hf;
+ if (hFile != NULL)
+ {
+ CloseHandle(hFile);
+ ret=0;
+ }
+ free(stream);
+ }
+ return ret;
+}
+
+int ZCALLBACK win32_error_file_func (voidpf opaque,voidpf stream)
+{
+ int ret=-1;
+ if (stream!=NULL)
+ {
+ ret = ((WIN32FILE_IOWIN*)stream) -> error;
+ }
+ return ret;
+}
+
+void fill_win32_filefunc (zlib_filefunc_def* pzlib_filefunc_def)
+{
+ pzlib_filefunc_def->zopen_file = win32_open_file_func;
+ pzlib_filefunc_def->zread_file = win32_read_file_func;
+ pzlib_filefunc_def->zwrite_file = win32_write_file_func;
+ pzlib_filefunc_def->ztell_file = win32_tell_file_func;
+ pzlib_filefunc_def->zseek_file = win32_seek_file_func;
+ pzlib_filefunc_def->zclose_file = win32_close_file_func;
+ pzlib_filefunc_def->zerror_file = win32_error_file_func;
+ pzlib_filefunc_def->opaque = NULL;
+}
+
+void fill_win32_filefunc64(zlib_filefunc64_def* pzlib_filefunc_def)
+{
+ pzlib_filefunc_def->zopen64_file = win32_open64_file_func;
+ pzlib_filefunc_def->zread_file = win32_read_file_func;
+ pzlib_filefunc_def->zwrite_file = win32_write_file_func;
+ pzlib_filefunc_def->ztell64_file = win32_tell64_file_func;
+ pzlib_filefunc_def->zseek64_file = win32_seek64_file_func;
+ pzlib_filefunc_def->zclose_file = win32_close_file_func;
+ pzlib_filefunc_def->zerror_file = win32_error_file_func;
+ pzlib_filefunc_def->opaque = NULL;
+}
+
+
+void fill_win32_filefunc64A(zlib_filefunc64_def* pzlib_filefunc_def)
+{
+ pzlib_filefunc_def->zopen64_file = win32_open64_file_funcA;
+ pzlib_filefunc_def->zread_file = win32_read_file_func;
+ pzlib_filefunc_def->zwrite_file = win32_write_file_func;
+ pzlib_filefunc_def->ztell64_file = win32_tell64_file_func;
+ pzlib_filefunc_def->zseek64_file = win32_seek64_file_func;
+ pzlib_filefunc_def->zclose_file = win32_close_file_func;
+ pzlib_filefunc_def->zerror_file = win32_error_file_func;
+ pzlib_filefunc_def->opaque = NULL;
+}
+
+
+void fill_win32_filefunc64W(zlib_filefunc64_def* pzlib_filefunc_def)
+{
+ pzlib_filefunc_def->zopen64_file = win32_open64_file_funcW;
+ pzlib_filefunc_def->zread_file = win32_read_file_func;
+ pzlib_filefunc_def->zwrite_file = win32_write_file_func;
+ pzlib_filefunc_def->ztell64_file = win32_tell64_file_func;
+ pzlib_filefunc_def->zseek64_file = win32_seek64_file_func;
+ pzlib_filefunc_def->zclose_file = win32_close_file_func;
+ pzlib_filefunc_def->zerror_file = win32_error_file_func;
+ pzlib_filefunc_def->opaque = NULL;
+}
ADDED compat/zlib/contrib/minizip/iowin32.h
Index: compat/zlib/contrib/minizip/iowin32.h
==================================================================
--- compat/zlib/contrib/minizip/iowin32.h
+++ compat/zlib/contrib/minizip/iowin32.h
@@ -0,0 +1,28 @@
+/* iowin32.h -- IO base function header for compress/uncompress .zip
+ Version 1.1, February 14h, 2010
+ part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html )
+
+ Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html )
+
+ Modifications for Zip64 support
+ Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com )
+
+ For more info read MiniZip_info.txt
+
+*/
+
+#include
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void fill_win32_filefunc OF((zlib_filefunc_def* pzlib_filefunc_def));
+void fill_win32_filefunc64 OF((zlib_filefunc64_def* pzlib_filefunc_def));
+void fill_win32_filefunc64A OF((zlib_filefunc64_def* pzlib_filefunc_def));
+void fill_win32_filefunc64W OF((zlib_filefunc64_def* pzlib_filefunc_def));
+
+#ifdef __cplusplus
+}
+#endif
ADDED compat/zlib/contrib/minizip/make_vms.com
Index: compat/zlib/contrib/minizip/make_vms.com
==================================================================
--- compat/zlib/contrib/minizip/make_vms.com
+++ compat/zlib/contrib/minizip/make_vms.com
@@ -0,0 +1,25 @@
+$ if f$search("ioapi.h_orig") .eqs. "" then copy ioapi.h ioapi.h_orig
+$ open/write zdef vmsdefs.h
+$ copy sys$input: zdef
+$ deck
+#define unix
+#define fill_zlib_filefunc64_32_def_from_filefunc32 fillzffunc64from
+#define Write_Zip64EndOfCentralDirectoryLocator Write_Zip64EoDLocator
+#define Write_Zip64EndOfCentralDirectoryRecord Write_Zip64EoDRecord
+#define Write_EndOfCentralDirectoryRecord Write_EoDRecord
+$ eod
+$ close zdef
+$ copy vmsdefs.h,ioapi.h_orig ioapi.h
+$ cc/include=[--]/prefix=all ioapi.c
+$ cc/include=[--]/prefix=all miniunz.c
+$ cc/include=[--]/prefix=all unzip.c
+$ cc/include=[--]/prefix=all minizip.c
+$ cc/include=[--]/prefix=all zip.c
+$ link miniunz,unzip,ioapi,[--]libz.olb/lib
+$ link minizip,zip,ioapi,[--]libz.olb/lib
+$ mcr []minizip test minizip_info.txt
+$ mcr []miniunz -l test.zip
+$ rename minizip_info.txt; minizip_info.txt_old
+$ mcr []miniunz test.zip
+$ delete test.zip;*
+$exit
ADDED compat/zlib/contrib/minizip/miniunz.c
Index: compat/zlib/contrib/minizip/miniunz.c
==================================================================
--- compat/zlib/contrib/minizip/miniunz.c
+++ compat/zlib/contrib/minizip/miniunz.c
@@ -0,0 +1,660 @@
+/*
+ miniunz.c
+ Version 1.1, February 14h, 2010
+ sample part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html )
+
+ Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html )
+
+ Modifications of Unzip for Zip64
+ Copyright (C) 2007-2008 Even Rouault
+
+ Modifications for Zip64 support on both zip and unzip
+ Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com )
+*/
+
+#if (!defined(_WIN32)) && (!defined(WIN32)) && (!defined(__APPLE__))
+ #ifndef __USE_FILE_OFFSET64
+ #define __USE_FILE_OFFSET64
+ #endif
+ #ifndef __USE_LARGEFILE64
+ #define __USE_LARGEFILE64
+ #endif
+ #ifndef _LARGEFILE64_SOURCE
+ #define _LARGEFILE64_SOURCE
+ #endif
+ #ifndef _FILE_OFFSET_BIT
+ #define _FILE_OFFSET_BIT 64
+ #endif
+#endif
+
+#ifdef __APPLE__
+// In darwin and perhaps other BSD variants off_t is a 64 bit value, hence no need for specific 64 bit functions
+#define FOPEN_FUNC(filename, mode) fopen(filename, mode)
+#define FTELLO_FUNC(stream) ftello(stream)
+#define FSEEKO_FUNC(stream, offset, origin) fseeko(stream, offset, origin)
+#else
+#define FOPEN_FUNC(filename, mode) fopen64(filename, mode)
+#define FTELLO_FUNC(stream) ftello64(stream)
+#define FSEEKO_FUNC(stream, offset, origin) fseeko64(stream, offset, origin)
+#endif
+
+
+#include
+#include
+#include
+#include
+#include
+#include