Changes On Branch jimtcl
Not logged in

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Changes In Branch jimtcl Excluding Merge-Ins

This is equivalent to a diff from 238b761afa to de9c2f08d7

2012-01-24
13:28
Fix several blob leaks that can lead to out of memory conditions for very large push operations. Revise the order of error messages so that simple HTTP timeout produces a better diagnostic. The HTTP trace files need to be opened in binary mode. check-in: 1e39808853 user: mistachkin tags: trunk
2012-01-23
03:51
Merge latest trunk changes into jimtcl branch. Lightly tested. Should allow xfer scripts to be written in Jim Tcl. Leaf check-in: de9c2f08d7 user: steveb tags: jimtcl
2012-01-22
06:59
Revise previous commit: since the FOSSIL_ENABLE_TCL macro is used in source files as well as the Makefile itself, it cannot be initially set to an empty string in auto.def. check-in: 238b761afa user: mistachkin tags: trunk
06:52
Make sure that autosetup ends up defining FOSSIL_ENABLE_TCL in the Makefile when necessary. check-in: 21555be397 user: mistachkin tags: trunk
2011-11-07
07:07
fossil already provides compatibility wrappers for dirent and struct timeval check-in: 5905232d45 user: steveb tags: jimtcl

Changes to auto.def.

    85     85   }
    86     86   if {![cc-check-includes zlib.h] || ![cc-check-function-in-lib inflateEnd z]} {
    87     87       user-error "zlib not found please install it or specify the location with --with-zlib"
    88     88   }
    89     89   
    90     90   set tclpath [opt-val with-tcl]
    91     91   if {$tclpath ne ""} {
    92         -	# Note parse-tclconfig-sh is in autosetup/local.tcl
           92  +    # Note parse-tclconfig-sh is in autosetup/local.tcl
    93     93       if {$tclpath eq "1"} {
    94     94           # Use the system Tcl. Look in some likely places.
    95     95           array set tclconfig [parse-tclconfig-sh /usr /usr/local /usr/share /opt/local]
    96         -		set msg "on your system"
    97         -	} else {
           96  +        set msg "on your system"
           97  +    } else {
    98     98           array set tclconfig [parse-tclconfig-sh $tclpath]
    99         -		set msg "at $tclpath"
   100         -	}
   101         -	if {![info exists tclconfig(TCL_INCLUDE_SPEC)]} {
   102         -		user-error "Cannot find Tcl $msg"
   103         -	}
   104         -	set cflags $tclconfig(TCL_INCLUDE_SPEC)
   105         -	set libs "$tclconfig(TCL_LIB_SPEC) $tclconfig(TCL_LIBS)"
   106         -	cc-with [list -cflags $cflags -libs $libs] {
   107         -		if {![cc-check-functions Tcl_CreateInterp]} {
   108         -			user-error "Cannot find a usable Tcl $msg"
   109         -		}
   110         -	}
   111         -	set version $tclconfig(TCL_VERSION)$tclconfig(TCL_PATCH_LEVEL)
   112         -	msg-result "Found Tcl $version at $tclconfig(TCL_PREFIX)"
   113         -	define-append LIBS $libs
   114         -	define-append EXTRA_CFLAGS $cflags
   115         -	define-append EXTRA_LDFLAGS $tclconfig(TCL_LD_FLAGS)
           99  +        set msg "at $tclpath"
          100  +    }
          101  +    if {![info exists tclconfig(TCL_INCLUDE_SPEC)]} {
          102  +        user-error "Cannot find Tcl $msg"
          103  +    }
          104  +    set cflags $tclconfig(TCL_INCLUDE_SPEC)
          105  +    set libs "$tclconfig(TCL_LIB_SPEC) $tclconfig(TCL_LIBS)"
          106  +    cc-with [list -cflags $cflags -libs $libs] {
          107  +        if {![cc-check-functions Tcl_CreateInterp]} {
          108  +            user-error "Cannot find a usable Tcl $msg"
          109  +        }
          110  +    }
          111  +    set version $tclconfig(TCL_VERSION)$tclconfig(TCL_PATCH_LEVEL)
          112  +    msg-result "Found Tcl $version at $tclconfig(TCL_PREFIX)"
          113  +    define-append LIBS $libs
          114  +    define-append EXTRA_CFLAGS $cflags
          115  +    define-append EXTRA_LDFLAGS $tclconfig(TCL_LD_FLAGS)
   116    116   
   117    117       define FOSSIL_ENABLE_TCL
   118    118   }
   119    119   
   120    120   # Helper for openssl checking
   121    121   proc check-for-openssl {msg {cflags {}}} {
   122    122       msg-checking "Checking for $msg..."

Changes to autosetup/README.autosetup.

     1         -This is autosetup v0.6.2. See http://msteveb.github.com/autosetup/
            1  +This is autosetup v0.6.3. See http://msteveb.github.com/autosetup/

Changes to autosetup/autosetup.

     1      1   #!/bin/sh
     2      2   # Copyright (c) 2006-2011 WorkWare Systems http://www.workware.net.au/
     3      3   # All rights reserved
     4      4   # vim:se syntax=tcl:
     5      5   # \
     6      6   dir=`dirname "$0"`; exec "`$dir/find-tclsh`" "$0" "$@"
     7      7   
     8         -set autosetup(version) 0.6.2
            8  +set autosetup(version) 0.6.3
     9      9   
    10     10   # Can be set to 1 to debug early-init problems
    11     11   set autosetup(debug) 0
    12     12   
    13     13   ##################################################################
    14     14   #
    15     15   # Main flow of control, option handling
................................................................................
   514    514   	}
   515    515   	getenv $name $default
   516    516   }
   517    517   
   518    518   # @env-is-set name
   519    519   #
   520    520   # Returns 1 if the $name was specified on the command line or in the environment.
          521  +# Note that an empty environment variable is not considered to be set.
   521    522   #
   522    523   proc env-is-set {name} {
   523    524   	if {[dict exists $::autosetup(cmdline) $name]} {
   524    525   		return 1
   525    526   	}
   526         -	info exists ::env($name)
          527  +	if {[getenv $name ""] ne ""} {
          528  +		return 1
          529  +	}
          530  +	return 0
   527    531   }
   528    532   
   529    533   # @readfile filename ?default=""?
   530    534   #
   531    535   # Return the contents of the file, without the trailing newline.
   532    536   # If the doesn't exist or can't be read, returns $default.
   533    537   #
................................................................................
  1539   1543   	}
  1540   1544   } elseif {$autosetup(iswin)} {
  1541   1545   	# On Windows, backslash convert all environment variables
  1542   1546   	# (Assume that Tcl does this for us)
  1543   1547   	proc getenv {name args} {
  1544   1548   		string map {\\ /} [env $name {*}$args]
  1545   1549   	}
  1546         -	# Jim uses system() for exec under mingw, so
  1547         -	# we need to fetch the output ourselves
  1548         -	proc exec-with-stderr {args} {
  1549         -			set tmpfile auto[format %04x [rand 10000]].tmp
  1550         -			set rc [catch [list exec {*}$args >$tmpfile 2>&1] result]
  1551         -			set result [readfile $tmpfile]
  1552         -			file delete $tmpfile
  1553         -			return -code $rc $result
  1554         -	}
  1555   1550   } else {
  1556   1551   	# Jim on unix is simple
  1557   1552   	alias getenv env
  1558   1553   }
  1559   1554   
  1560   1555   # In case 'file normalize' doesn't exist
  1561   1556   #

Changes to autosetup/cc-shared.tcl.

    54     54   	}
    55     55   	* {
    56     56   		# Generic Unix settings
    57     57   		define SH_LINKFLAGS -rdynamic
    58     58   		define SH_CFLAGS -fpic
    59     59   		define SH_LDFLAGS -shared
    60     60   		define SHOBJ_CFLAGS -fpic
    61         -		define SHOBJ_LDFLAGS "-shared -nostartfiles"
           61  +		define SHOBJ_LDFLAGS -shared
    62     62   	}
    63     63   }

Changes to autosetup/cc.tcl.

   370    370   	} elseif {[llength $args] > 1} {
   371    371   		autosetup-error "usage: cc-with settings ?script?"
   372    372   	} else {
   373    373   		set save [cc-add-settings $settings]
   374    374   		set rc [catch {uplevel 1 [lindex $args 0]} result info]
   375    375   		cc-store-settings $save
   376    376   		if {$rc != 0} {
   377         -			return $result -code [dict get $info -code]
          377  +			return -code [dict get $info -code] $result
   378    378   		}
   379    379   		return $result
   380    380   	}
   381    381   }
   382    382   
   383    383   # @cctest ?settings?
   384    384   # 

Changes to autosetup/find-tclsh.

     1      1   #!/bin/sh
     2      2   # Looks for a suitable tclsh or jimsh in the PATH
     3      3   # If not found, builds a bootstrap jimsh from source
     4      4   d=`dirname "$0"`
            5  +{ "$d/jimsh0" "$d/test-tclsh"; } 2>/dev/null && exit 0
     5      6   PATH="$PATH:$d"
     6         -for tclsh in jimsh tclsh tclsh8.5 tclsh8.6 jimsh0; do
            7  +for tclsh in jimsh tclsh tclsh8.5 tclsh8.6; do
     7      8   	{ $tclsh "$d/test-tclsh"; } 2>/dev/null && exit 0
     8      9   done
     9     10   echo 1>&2 "No installed jimsh or tclsh, building local bootstrap jimsh0"
    10     11   for cc in ${CC_FOR_BUILD:-cc} gcc; do
    11     12   	{ $cc -o "$d/jimsh0" "$d/jimsh0.c"; } 2>/dev/null || continue
    12     13   	"$d/jimsh0" "$d/test-tclsh" && exit 0
    13     14   done
    14     15   echo 1>&2 "No working C compiler found. Tried ${CC_FOR_BUILD:-cc} and gcc."
    15     16   echo false

Changes to autosetup/jimsh0.c.

more than 10,000 changes

Changes to autosetup/system.tcl.

   224    224   define prefix $prefix
   225    225   define builddir $autosetup(builddir)
   226    226   define srcdir $autosetup(srcdir)
   227    227   # Allow this to come from the environment
   228    228   define top_srcdir [get-env top_srcdir [get-define srcdir]]
   229    229   
   230    230   # autoconf supports all of these
   231         -define exec_prefix [opt-val exec-prefix [get-env exec-prefix \${prefix}]]
          231  +set exec_prefix [opt-val exec-prefix $prefix]
          232  +define exec_prefix $exec_prefix
          233  +foreach {name defpath} {
          234  +	bindir /bin
          235  +	sbindir /sbin
          236  +	libexecdir /libexec
          237  +	libdir /lib
          238  +} {
          239  +	define $name [opt-val $name $exec_prefix$defpath]
          240  +}
   232    241   foreach {name defpath} {
   233         -	bindir \${exec_prefix}/bin
   234         -	sbindir \${exec_prefix}/sbin
   235         -	libexecdir \${exec_prefix}/libexec
   236         -	libdir \${exec_prefix}/lib
   237         -	datadir \${prefix}/share
   238         -	sysconfdir \${prefix}/etc
   239         -	sharedstatedir \${prefix}/com
   240         -	localstatedir \${prefix}/var
   241         -	infodir \${prefix}/share/info
   242         -	mandir \${prefix}/share/man
   243         -	includedir \${prefix}/include
          242  +	datadir /share
          243  +	sysconfdir /etc
          244  +	sharedstatedir /com
          245  +	localstatedir /var
          246  +	infodir /share/info
          247  +	mandir /share/man
          248  +	includedir /include
   244    249   } {
   245         -	define $name [opt-val $name [get-env $name $defpath]]
          250  +	define $name [opt-val $name $prefix$defpath]
   246    251   }
   247    252   
   248    253   define SHELL [get-env SHELL [find-an-executable sh bash ksh]]
   249    254   
   250    255   # Windows vs. non-Windows
   251    256   switch -glob -- [get-define host] {
   252    257   	*-*-ming* - *-*-cygwin {

Changes to autosetup/test-tclsh.

     1      1   # A small Tcl script to verify that the chosen
     2      2   # interpreter works. Sometimes we might e.g. pick up
     3      3   # an interpreter for a different arch.
     4      4   # Outputs the full path to the interpreter
     5      5   
     6      6   if {[catch {info version} version] == 0} {
     7      7   	# This is Jim Tcl
     8         -	if {$version >= 0.70} {
            8  +	if {$version >= 0.72} {
     9      9   		# Ensure that regexp works
    10     10   		regexp (a.*?) a
    11         -
    12         -		# Older versions of jimsh may return a relative path for [info nameofexecutable]
    13         -		puts [file join [pwd] [info nameofexecutable]]
           11  +		puts [info nameofexecutable]
    14     12   		exit 0
    15     13   	}
    16     14   } elseif {[catch {info tclversion} version] == 0} {
    17     15   	if {$version >= 8.5 && ![string match 8.5a* [info patchlevel]]} {
    18     16   		puts [info nameofexecutable]
    19     17   		exit 0
    20     18   	}
    21     19   }
    22     20   exit 1

Added src/jim-config.h.

            1  +#ifndef _JIM_CONFIG_H
            2  +#define _JIM_CONFIG_H
            3  +/*#undef HAVE_LONG_LONG*/
            4  +/*#undef JIM_UTF8*/
            5  +#endif

Added src/jim-win32compat.h.

            1  +#ifndef JIM_WIN32COMPAT_H
            2  +#define JIM_WIN32COMPAT_H
            3  +
            4  +/* Compatibility for Windows (mingw and msvc, not cygwin */
            5  +
            6  +/* Note that at this point we don't yet have access to jimautoconf.h */
            7  +#if defined(_WIN32) || defined(WIN32)
            8  +
            9  +#define HAVE_DLOPEN
           10  +void *dlopen(const char *path, int mode);
           11  +int dlclose(void *handle);
           12  +void *dlsym(void *handle, const char *symbol);
           13  +char *dlerror(void);
           14  +
           15  +#ifdef _MSC_VER
           16  +/* These are msvc vs gcc */
           17  +
           18  +#if _MSC_VER >= 1000
           19  +	#pragma warning(disable:4146)
           20  +#endif
           21  +
           22  +#include <limits.h>
           23  +#define jim_wide _int64
           24  +#ifndef LLONG_MAX
           25  +	#define LLONG_MAX    9223372036854775807I64
           26  +#endif
           27  +#ifndef LLONG_MIN
           28  +	#define LLONG_MIN    (-LLONG_MAX - 1I64)
           29  +#endif
           30  +#define JIM_WIDE_MIN LLONG_MIN
           31  +#define JIM_WIDE_MAX LLONG_MAX
           32  +#define JIM_WIDE_MODIFIER "I64d"
           33  +#define strcasecmp _stricmp
           34  +#define strtoull _strtoui64
           35  +#define snprintf _snprintf
           36  +
           37  +#include <io.h>
           38  +
           39  +#ifndef NO_TIMEVAL
           40  +struct timeval {
           41  +	long tv_sec;
           42  +	long tv_usec;
           43  +};
           44  +#endif
           45  +
           46  +int gettimeofday(struct timeval *tv, void *unused);
           47  +
           48  +#define HAVE_OPENDIR
           49  +#ifndef NO_DIRENT
           50  +struct dirent {
           51  +	char *d_name;
           52  +};
           53  +
           54  +typedef struct DIR {
           55  +	long                handle; /* -1 for failed rewind */
           56  +	struct _finddata_t  info;
           57  +	struct dirent       result; /* d_name null iff first time */
           58  +	char                *name;  /* null-terminated char string */
           59  +} DIR;
           60  +
           61  +DIR *opendir(const char *name);
           62  +int closedir(DIR *dir);
           63  +struct dirent *readdir(DIR *dir);
           64  +#endif
           65  +#endif /* _MSC_VER */
           66  +
           67  +#endif /* WIN32 */
           68  +
           69  +#endif

Added src/jim.h.

            1  +/* Jim - A small embeddable Tcl interpreter
            2  + *
            3  + * Copyright 2005 Salvatore Sanfilippo <antirez@invece.org>
            4  + * Copyright 2005 Clemens Hintze <c.hintze@gmx.net>
            5  + * Copyright 2005 patthoyts - Pat Thoyts <patthoyts@users.sf.net>
            6  + * Copyright 2008 oharboe - �yvind Harboe - oyvind.harboe@zylin.com
            7  + * Copyright 2008 Andrew Lunn <andrew@lunn.ch>
            8  + * Copyright 2008 Duane Ellis <openocd@duaneellis.com>
            9  + * Copyright 2008 Uwe Klein <uklein@klein-messgeraete.de>
           10  + *
           11  + * Redistribution and use in source and binary forms, with or without
           12  + * modification, are permitted provided that the following conditions
           13  + * are met:
           14  + *
           15  + * 1. Redistributions of source code must retain the above copyright
           16  + *    notice, this list of conditions and the following disclaimer.
           17  + * 2. Redistributions in binary form must reproduce the above
           18  + *    copyright notice, this list of conditions and the following
           19  + *    disclaimer in the documentation and/or other materials
           20  + *    provided with the distribution.
           21  + *
           22  + * THIS SOFTWARE IS PROVIDED BY THE JIM TCL PROJECT ``AS IS'' AND ANY
           23  + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
           24  + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
           25  + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
           26  + * JIM TCL PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
           27  + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
           28  + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
           29  + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
           30  + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
           31  + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
           32  + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
           33  + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
           34  + *
           35  + * The views and conclusions contained in the software and documentation
           36  + * are those of the authors and should not be interpreted as representing
           37  + * official policies, either expressed or implied, of the Jim Tcl Project.
           38  + *
           39  + *--- Inline Header File Documentation ---
           40  + *    [By Duane Ellis, openocd@duaneellis.com, 8/18/8]
           41  + *
           42  + * Belief is "Jim" would greatly benifit if Jim Internals where
           43  + * documented in some way - form whatever, and perhaps - the package:
           44  + * 'doxygen' is the correct approach to do that.
           45  + *
           46  + *   Details, see: http://www.stack.nl/~dimitri/doxygen/
           47  + *
           48  + * To that end please follow these guide lines:
           49  + *
           50  + *    (A) Document the PUBLIC api in the .H file.
           51  + *
           52  + *    (B) Document JIM Internals, in the .C file.
           53  + *
           54  + *    (C) Remember JIM is embedded in other packages, to that end do
           55  + *    not assume that your way of documenting is the right way, Jim's
           56  + *    public documentation should be agnostic, such that it is some
           57  + *    what agreeable with the "package" that is embedding JIM inside
           58  + *    of it's own doxygen documentation.
           59  + *
           60  + *    (D) Use minimal Doxygen tags.
           61  + *
           62  + * This will be an "ongoing work in progress" for some time.
           63  + **/
           64  +
           65  +#ifndef __JIM__H
           66  +#define __JIM__H
           67  +
           68  +#ifdef __cplusplus
           69  +extern "C" {
           70  +#endif
           71  +
           72  +#include <time.h>
           73  +#include <limits.h>
           74  +#include <stdio.h>  /* for the FILE typedef definition */
           75  +#include <stdlib.h> /* In order to export the Jim_Free() macro */
           76  +#include <stdarg.h> /* In order to get type va_list */
           77  +
           78  +/* -----------------------------------------------------------------------------
           79  + * System configuration
           80  + * autoconf (configure) will set these
           81  + * ---------------------------------------------------------------------------*/
           82  +#include <jim-win32compat.h>
           83  +
           84  +#ifndef HAVE_NO_AUTOCONF
           85  +#include <jim-config.h>
           86  +#endif
           87  +
           88  +/* -----------------------------------------------------------------------------
           89  + * Compiler specific fixes.
           90  + * ---------------------------------------------------------------------------*/
           91  +
           92  +/* Long Long type and related issues */
           93  +#ifndef jim_wide
           94  +#  ifdef HAVE_LONG_LONG
           95  +#    define jim_wide long long
           96  +#    ifndef LLONG_MAX
           97  +#      define LLONG_MAX    9223372036854775807LL
           98  +#    endif
           99  +#    ifndef LLONG_MIN
          100  +#      define LLONG_MIN    (-LLONG_MAX - 1LL)
          101  +#    endif
          102  +#    define JIM_WIDE_MIN LLONG_MIN
          103  +#    define JIM_WIDE_MAX LLONG_MAX
          104  +#  else
          105  +#    define jim_wide long
          106  +#    define JIM_WIDE_MIN LONG_MIN
          107  +#    define JIM_WIDE_MAX LONG_MAX
          108  +#  endif
          109  +
          110  +/* -----------------------------------------------------------------------------
          111  + * LIBC specific fixes
          112  + * ---------------------------------------------------------------------------*/
          113  +
          114  +#  ifdef HAVE_LONG_LONG
          115  +#    define JIM_WIDE_MODIFIER "lld"
          116  +#  else
          117  +#    define JIM_WIDE_MODIFIER "ld"
          118  +#    define strtoull strtoul
          119  +#  endif
          120  +#endif
          121  +
          122  +#define UCHAR(c) ((unsigned char)(c))
          123  +
          124  +/* -----------------------------------------------------------------------------
          125  + * Exported defines
          126  + * ---------------------------------------------------------------------------*/
          127  +
          128  +/* Jim version numbering: every version of jim is marked with a
          129  + * successive integer number. This is version 0. The first
          130  + * stable version will be 1, then 2, 3, and so on. */
          131  +#define JIM_VERSION 73
          132  +
          133  +#define JIM_OK 0
          134  +#define JIM_ERR 1
          135  +#define JIM_RETURN 2
          136  +#define JIM_BREAK 3
          137  +#define JIM_CONTINUE 4
          138  +#define JIM_SIGNAL 5
          139  +#define JIM_EXIT 6
          140  +/* The following are internal codes and should never been seen/used */
          141  +#define JIM_EVAL 7
          142  +
          143  +#define JIM_MAX_NESTING_DEPTH 1000 /* default max nesting depth */
          144  +
          145  +/* Some function get an integer argument with flags to change
          146  + * the behaviour. */
          147  +#define JIM_NONE 0    /* no flags set */
          148  +#define JIM_ERRMSG 1    /* set an error message in the interpreter. */
          149  +
          150  +#define JIM_UNSHARED 4 /* Flag to Jim_GetVariable() */
          151  +
          152  +/* Flags for Jim_SubstObj() */
          153  +#define JIM_SUBST_NOVAR 1 /* don't perform variables substitutions */
          154  +#define JIM_SUBST_NOCMD 2 /* don't perform command substitutions */
          155  +#define JIM_SUBST_NOESC 4 /* don't perform escapes substitutions */
          156  +#define JIM_SUBST_FLAG 128 /* flag to indicate that this is a real substition object */
          157  +
          158  +/* Unused arguments generate annoying warnings... */
          159  +#define JIM_NOTUSED(V) ((void) V)
          160  +
          161  +/* Flags for Jim_GetEnum() */
          162  +#define JIM_ENUM_ABBREV 2    /* Allow unambiguous abbreviation */
          163  +
          164  +/* Flags used by API calls getting a 'nocase' argument. */
          165  +#define JIM_CASESENS    0   /* case sensitive */
          166  +#define JIM_NOCASE      1   /* no case */
          167  +
          168  +/* Filesystem related */
          169  +#define JIM_PATH_LEN 1024
          170  +
          171  +/* Newline, some embedded system may need -DJIM_CRLF */
          172  +#ifdef JIM_CRLF
          173  +#define JIM_NL "\r\n"
          174  +#else
          175  +#define JIM_NL "\n"
          176  +#endif
          177  +
          178  +#define JIM_LIBPATH "auto_path"
          179  +#define JIM_INTERACTIVE "tcl_interactive"
          180  +
          181  +/* -----------------------------------------------------------------------------
          182  + * Stack
          183  + * ---------------------------------------------------------------------------*/
          184  +
          185  +typedef struct Jim_Stack {
          186  +    int len;
          187  +    int maxlen;
          188  +    void **vector;
          189  +} Jim_Stack;
          190  +
          191  +/* -----------------------------------------------------------------------------
          192  + * Hash table
          193  + * ---------------------------------------------------------------------------*/
          194  +
          195  +typedef struct Jim_HashEntry {
          196  +    const void *key;
          197  +    union {
          198  +        void *val;
          199  +        int intval;
          200  +    } u;
          201  +    struct Jim_HashEntry *next;
          202  +} Jim_HashEntry;
          203  +
          204  +typedef struct Jim_HashTableType {
          205  +    unsigned int (*hashFunction)(const void *key);
          206  +    const void *(*keyDup)(void *privdata, const void *key);
          207  +    void *(*valDup)(void *privdata, const void *obj);
          208  +    int (*keyCompare)(void *privdata, const void *key1, const void *key2);
          209  +    void (*keyDestructor)(void *privdata, const void *key);
          210  +    void (*valDestructor)(void *privdata, void *obj);
          211  +} Jim_HashTableType;
          212  +
          213  +typedef struct Jim_HashTable {
          214  +    Jim_HashEntry **table;
          215  +    const Jim_HashTableType *type;
          216  +    unsigned int size;
          217  +    unsigned int sizemask;
          218  +    unsigned int used;
          219  +    unsigned int collisions;
          220  +    void *privdata;
          221  +} Jim_HashTable;
          222  +
          223  +typedef struct Jim_HashTableIterator {
          224  +    Jim_HashTable *ht;
          225  +    int index;
          226  +    Jim_HashEntry *entry, *nextEntry;
          227  +} Jim_HashTableIterator;
          228  +
          229  +/* This is the initial size of every hash table */
          230  +#define JIM_HT_INITIAL_SIZE     16
          231  +
          232  +/* ------------------------------- Macros ------------------------------------*/
          233  +#define Jim_FreeEntryVal(ht, entry) \
          234  +    if ((ht)->type->valDestructor) \
          235  +        (ht)->type->valDestructor((ht)->privdata, (entry)->u.val)
          236  +
          237  +#define Jim_SetHashVal(ht, entry, _val_) do { \
          238  +    if ((ht)->type->valDup) \
          239  +        entry->u.val = (ht)->type->valDup((ht)->privdata, _val_); \
          240  +    else \
          241  +        entry->u.val = (_val_); \
          242  +} while(0)
          243  +
          244  +#define Jim_FreeEntryKey(ht, entry) \
          245  +    if ((ht)->type->keyDestructor) \
          246  +        (ht)->type->keyDestructor((ht)->privdata, (entry)->key)
          247  +
          248  +#define Jim_SetHashKey(ht, entry, _key_) do { \
          249  +    if ((ht)->type->keyDup) \
          250  +        entry->key = (ht)->type->keyDup((ht)->privdata, _key_); \
          251  +    else \
          252  +        entry->key = (_key_); \
          253  +} while(0)
          254  +
          255  +#define Jim_CompareHashKeys(ht, key1, key2) \
          256  +    (((ht)->type->keyCompare) ? \
          257  +        (ht)->type->keyCompare((ht)->privdata, key1, key2) : \
          258  +        (key1) == (key2))
          259  +
          260  +#define Jim_HashKey(ht, key) (ht)->type->hashFunction(key)
          261  +
          262  +#define Jim_GetHashEntryKey(he) ((he)->key)
          263  +#define Jim_GetHashEntryVal(he) ((he)->val)
          264  +#define Jim_GetHashTableCollisions(ht) ((ht)->collisions)
          265  +#define Jim_GetHashTableSize(ht) ((ht)->size)
          266  +#define Jim_GetHashTableUsed(ht) ((ht)->used)
          267  +
          268  +/* -----------------------------------------------------------------------------
          269  + * Jim_Obj structure
          270  + * ---------------------------------------------------------------------------*/
          271  +
          272  +/* -----------------------------------------------------------------------------
          273  + * Jim object. This is mostly the same as Tcl_Obj itself,
          274  + * with the addition of the 'prev' and 'next' pointers.
          275  + * In Jim all the objects are stored into a linked list for GC purposes,
          276  + * so that it's possible to access every object living in a given interpreter
          277  + * sequentially. When an object is freed, it's moved into a different
          278  + * linked list, used as object pool.
          279  + *
          280  + * The refcount of a freed object is always -1.
          281  + * ---------------------------------------------------------------------------*/
          282  +typedef struct Jim_Obj {
          283  +    int refCount; /* reference count */
          284  +    char *bytes; /* string representation buffer. NULL = no string repr. */
          285  +    int length; /* number of bytes in 'bytes', not including the numterm. */
          286  +    const struct Jim_ObjType *typePtr; /* object type. */
          287  +    /* Internal representation union */
          288  +    union {
          289  +        /* integer number type */
          290  +        jim_wide wideValue;
          291  +        /* hashed object type value */
          292  +        int hashValue;
          293  +        /* index type */
          294  +        int indexValue;
          295  +        /* return code type */
          296  +        int returnCode;
          297  +        /* double number type */
          298  +        double doubleValue;
          299  +        /* Generic pointer */
          300  +        void *ptr;
          301  +        /* Generic two pointers value */
          302  +        struct {
          303  +            void *ptr1;
          304  +            void *ptr2;
          305  +        } twoPtrValue;
          306  +        /* Variable object */
          307  +        struct {
          308  +            unsigned jim_wide callFrameId;
          309  +            struct Jim_Var *varPtr;
          310  +        } varValue;
          311  +        /* Command object */
          312  +        struct {
          313  +            unsigned jim_wide procEpoch;
          314  +            struct Jim_Cmd *cmdPtr;
          315  +        } cmdValue;
          316  +        /* List object */
          317  +        struct {
          318  +            struct Jim_Obj **ele;    /* Elements vector */
          319  +            int len;        /* Length */
          320  +            int maxLen;        /* Allocated 'ele' length */
          321  +        } listValue;
          322  +        /* String type */
          323  +        struct {
          324  +            int maxLength;
          325  +            int charLength;     /* utf-8 char length. -1 if unknown */
          326  +        } strValue;
          327  +        /* Reference type */
          328  +        struct {
          329  +            jim_wide id;
          330  +            struct Jim_Reference *refPtr;
          331  +        } refValue;
          332  +        /* Source type */
          333  +        struct {
          334  +            struct Jim_Obj *fileNameObj;
          335  +            int lineNumber;
          336  +        } sourceValue;
          337  +        /* Dict substitution type */
          338  +        struct {
          339  +            struct Jim_Obj *varNameObjPtr;
          340  +            struct Jim_Obj *indexObjPtr;
          341  +        } dictSubstValue;
          342  +        /* tagged binary type */
          343  +        struct {
          344  +            unsigned char *data;
          345  +            size_t         len;
          346  +        } binaryValue;
          347  +        /* Regular expression pattern */
          348  +        struct {
          349  +            unsigned flags;
          350  +            void *compre;       /* really an allocated (regex_t *) */
          351  +        } regexpValue;
          352  +        struct {
          353  +            int line;
          354  +            int argc;
          355  +        } scriptLineValue;
          356  +    } internalRep;
          357  +    /* This are 8 or 16 bytes more for every object
          358  +     * but this is required for efficient garbage collection
          359  +     * of Jim references. */
          360  +    struct Jim_Obj *prevObjPtr; /* pointer to the prev object. */
          361  +    struct Jim_Obj *nextObjPtr; /* pointer to the next object. */
          362  +} Jim_Obj;
          363  +
          364  +/* Jim_Obj related macros */
          365  +#define Jim_IncrRefCount(objPtr) \
          366  +    ++(objPtr)->refCount
          367  +#define Jim_DecrRefCount(interp, objPtr) \
          368  +    if (--(objPtr)->refCount <= 0) Jim_FreeObj(interp, objPtr)
          369  +#define Jim_IsShared(objPtr) \
          370  +    ((objPtr)->refCount > 1)
          371  +
          372  +/* This macro is used when we allocate a new object using
          373  + * Jim_New...Obj(), but for some error we need to destroy it.
          374  + * Instead to use Jim_IncrRefCount() + Jim_DecrRefCount() we
          375  + * can just call Jim_FreeNewObj. To call Jim_Free directly
          376  + * seems too raw, the object handling may change and we want
          377  + * that Jim_FreeNewObj() can be called only against objects
          378  + * that are belived to have refcount == 0. */
          379  +#define Jim_FreeNewObj Jim_FreeObj
          380  +
          381  +/* Free the internal representation of the object. */
          382  +#define Jim_FreeIntRep(i,o) \
          383  +    if ((o)->typePtr && (o)->typePtr->freeIntRepProc) \
          384  +        (o)->typePtr->freeIntRepProc(i, o)
          385  +
          386  +/* Get the internal representation pointer */
          387  +#define Jim_GetIntRepPtr(o) (o)->internalRep.ptr
          388  +
          389  +/* Set the internal representation pointer */
          390  +#define Jim_SetIntRepPtr(o, p) \
          391  +    (o)->internalRep.ptr = (p)
          392  +
          393  +/* The object type structure.
          394  + * There are four methods.
          395  + *
          396  + * - FreeIntRep is used to free the internal representation of the object.
          397  + *   Can be NULL if there is nothing to free.
          398  + * - DupIntRep is used to duplicate the internal representation of the object.
          399  + *   If NULL, when an object is duplicated, the internalRep union is
          400  + *   directly copied from an object to another.
          401  + *   Note that it's up to the caller to free the old internal repr of the
          402  + *   object before to call the Dup method.
          403  + * - UpdateString is used to create the string from the internal repr.
          404  + * - setFromAny is used to convert the current object into one of this type.
          405  + */
          406  +
          407  +struct Jim_Interp;
          408  +
          409  +typedef void (Jim_FreeInternalRepProc)(struct Jim_Interp *interp,
          410  +        struct Jim_Obj *objPtr);
          411  +typedef void (Jim_DupInternalRepProc)(struct Jim_Interp *interp,
          412  +        struct Jim_Obj *srcPtr, Jim_Obj *dupPtr);
          413  +typedef void (Jim_UpdateStringProc)(struct Jim_Obj *objPtr);
          414  +
          415  +typedef struct Jim_ObjType {
          416  +    const char *name; /* The name of the type. */
          417  +    Jim_FreeInternalRepProc *freeIntRepProc;
          418  +    Jim_DupInternalRepProc *dupIntRepProc;
          419  +    Jim_UpdateStringProc *updateStringProc;
          420  +    int flags;
          421  +} Jim_ObjType;
          422  +
          423  +/* Jim_ObjType flags */
          424  +#define JIM_TYPE_NONE 0        /* No flags */
          425  +#define JIM_TYPE_REFERENCES 1    /* The object may contain referneces. */
          426  +
          427  +/* Starting from 1 << 20 flags are reserved for private uses of
          428  + * different calls. This way the same 'flags' argument may be used
          429  + * to pass both global flags and private flags. */
          430  +#define JIM_PRIV_FLAG_SHIFT 20
          431  +
          432  +/* -----------------------------------------------------------------------------
          433  + * Call frame, vars, commands structures
          434  + * ---------------------------------------------------------------------------*/
          435  +
          436  +/* Call frame */
          437  +typedef struct Jim_CallFrame {
          438  +    unsigned jim_wide id; /* Call Frame ID. Used for caching. */
          439  +    int level; /* Level of this call frame. 0 = global */
          440  +    struct Jim_HashTable vars; /* Where local vars are stored */
          441  +    struct Jim_HashTable *staticVars; /* pointer to procedure static vars */
          442  +    struct Jim_CallFrame *parentCallFrame;
          443  +    Jim_Obj *const *argv; /* object vector of the current procedure call. */
          444  +    int argc; /* number of args of the current procedure call. */
          445  +    Jim_Obj *procArgsObjPtr; /* arglist object of the running procedure */
          446  +    Jim_Obj *procBodyObjPtr; /* body object of the running procedure */
          447  +    struct Jim_CallFrame *nextFramePtr;
          448  +    Jim_Obj *fileNameObj;       /* file and line of caller of this proc (if available) */
          449  +    int line;
          450  +} Jim_CallFrame;
          451  +
          452  +/* The var structure. It just holds the pointer of the referenced
          453  + * object. If linkFramePtr is not NULL the variable is a link
          454  + * to a variable of name store on objPtr living on the given callframe
          455  + * (this happens when the [global] or [upvar] command is used).
          456  + * The interp in order to always know how to free the Jim_Obj associated
          457  + * with a given variable because In Jim objects memory managment is
          458  + * bound to interpreters. */
          459  +typedef struct Jim_Var {
          460  +    Jim_Obj *objPtr;
          461  +    struct Jim_CallFrame *linkFramePtr;
          462  +} Jim_Var;
          463  +
          464  +/* The cmd structure. */
          465  +typedef int (*Jim_CmdProc)(struct Jim_Interp *interp, int argc,
          466  +    Jim_Obj *const *argv);
          467  +typedef void (*Jim_DelCmdProc)(struct Jim_Interp *interp, void *privData);
          468  +
          469  +
          470  +
          471  +/* A command is implemented in C if funcPtr is != NULL, otherwise
          472  + * it's a Tcl procedure with the arglist and body represented by the
          473  + * two objects referenced by arglistObjPtr and bodyoObjPtr. */
          474  +typedef struct Jim_Cmd {
          475  +    int inUse;           /* Reference count */
          476  +    int isproc;          /* Is this a procedure? */
          477  +    union {
          478  +        struct {
          479  +            /* native (C) command */
          480  +            Jim_CmdProc cmdProc; /* The command implementation */
          481  +            Jim_DelCmdProc delProc; /* Called when the command is deleted if != NULL */
          482  +            void *privData; /* command-private data available via Jim_CmdPrivData() */
          483  +        } native;
          484  +        struct {
          485  +            /* Tcl procedure */
          486  +            Jim_Obj *argListObjPtr;
          487  +            Jim_Obj *bodyObjPtr;
          488  +            Jim_HashTable *staticVars;  /* Static vars hash table. NULL if no statics. */
          489  +            struct Jim_Cmd *prevCmd;    /* Previous command defn if proc created 'local' */
          490  +            int argListLen;             /* Length of argListObjPtr */
          491  +            int reqArity;               /* Number of required parameters */
          492  +            int optArity;               /* Number of optional parameters */
          493  +            int argsPos;                /* Position of 'args', if specified, or -1 */
          494  +            int upcall;                 /* True if proc is currently in upcall */
          495  +            struct Jim_ProcArg {
          496  +                Jim_Obj *nameObjPtr;    /* Name of this arg */
          497  +                Jim_Obj *defaultObjPtr; /* Default value, (or rename for $args) */
          498  +            } *arglist;
          499  +        } proc;
          500  +    } u;
          501  +} Jim_Cmd;
          502  +
          503  +/* Pseudo Random Number Generator State structure */
          504  +typedef struct Jim_PrngState {
          505  +    unsigned char sbox[256];
          506  +    unsigned int i, j;
          507  +} Jim_PrngState;
          508  +
          509  +/* -----------------------------------------------------------------------------
          510  + * Jim interpreter structure.
          511  + * Fields similar to the real Tcl interpreter structure have the same names.
          512  + * ---------------------------------------------------------------------------*/
          513  +typedef struct Jim_Interp {
          514  +    Jim_Obj *result; /* object returned by the last command called. */
          515  +    int errorLine; /* Error line where an error occurred. */
          516  +    Jim_Obj *errorFileNameObj; /* Error file where an error occurred. */
          517  +    int addStackTrace; /* > 0 If a level should be added to the stack trace */
          518  +    int maxNestingDepth; /* Used for infinite loop detection. */
          519  +    int returnCode; /* Completion code to return on JIM_RETURN. */
          520  +    int returnLevel; /* Current level of 'return -level' */
          521  +    int exitCode; /* Code to return to the OS on JIM_EXIT. */
          522  +    long id; /* Hold unique id for various purposes */
          523  +    int signal_level; /* A nesting level of catch -signal */
          524  +    jim_wide sigmask;  /* Bit mask of caught signals, or 0 if none */
          525  +    int (*signal_set_result)(struct Jim_Interp *interp, jim_wide sigmask); /* Set a result for the sigmask */
          526  +    Jim_CallFrame *framePtr; /* Pointer to the current call frame */
          527  +    Jim_CallFrame *topFramePtr; /* toplevel/global frame pointer. */
          528  +    struct Jim_HashTable commands; /* Commands hash table */
          529  +    unsigned jim_wide procEpoch; /* Incremented every time the result
          530  +                of procedures names lookup caching
          531  +                may no longer be valid. */
          532  +    unsigned jim_wide callFrameEpoch; /* Incremented every time a new
          533  +                callframe is created. This id is used for the
          534  +                'ID' field contained in the Jim_CallFrame
          535  +                structure. */
          536  +    int local; /* If 'local' is in effect, newly defined procs keep a reference to the old defn */
          537  +    Jim_Obj *liveList; /* Linked list of all the live objects. */
          538  +    Jim_Obj *freeList; /* Linked list of all the unused objects. */
          539  +    Jim_Obj *currentScriptObj; /* Script currently in execution. */
          540  +    Jim_Obj *emptyObj; /* Shared empty string object. */
          541  +    Jim_Obj *trueObj; /* Shared true int object. */
          542  +    Jim_Obj *falseObj; /* Shared false int object. */
          543  +    unsigned jim_wide referenceNextId; /* Next id for reference. */
          544  +    struct Jim_HashTable references; /* References hash table. */
          545  +    jim_wide lastCollectId; /* reference max Id of the last GC
          546  +                execution. It's set to -1 while the collection
          547  +                is running as sentinel to avoid to recursive
          548  +                calls via the [collect] command inside
          549  +                finalizers. */
          550  +    time_t lastCollectTime; /* unix time of the last GC execution */
          551  +    Jim_Obj *stackTrace; /* Stack trace object. */
          552  +    Jim_Obj *errorProc; /* Name of last procedure which returned an error */
          553  +    Jim_Obj *unknown; /* Unknown command cache */
          554  +    int unknown_called; /* The unknown command has been invoked */
          555  +    int errorFlag; /* Set if an error occurred during execution. */
          556  +    void *cmdPrivData; /* Used to pass the private data pointer to
          557  +                  a command. It is set to what the user specified
          558  +                  via Jim_CreateCommand(). */
          559  +
          560  +    struct Jim_CallFrame *freeFramesList; /* list of CallFrame structures. */
          561  +    struct Jim_HashTable assocData; /* per-interp storage for use by packages */
          562  +    Jim_PrngState *prngState; /* per interpreter Random Number Gen. state. */
          563  +    struct Jim_HashTable packages; /* Provided packages hash table */
          564  +    Jim_Stack *localProcs; /* procs to be destroyed on end of evaluation */
          565  +    Jim_Stack *loadHandles; /* handles of loaded modules [load] */
          566  +} Jim_Interp;
          567  +
          568  +/* Currently provided as macro that performs the increment.
          569  + * At some point may be a real function doing more work.
          570  + * The proc epoch is used in order to know when a command lookup
          571  + * cached can no longer considered valid. */
          572  +#define Jim_InterpIncrProcEpoch(i) (i)->procEpoch++
          573  +#define Jim_SetResultString(i,s,l) Jim_SetResult(i, Jim_NewStringObj(i,s,l))
          574  +#define Jim_SetResultInt(i,intval) Jim_SetResult(i, Jim_NewIntObj(i,intval))
          575  +/* Note: Using trueObj and falseObj here makes some things slower...*/
          576  +#define Jim_SetResultBool(i,b) Jim_SetResultInt(i, b)
          577  +#define Jim_SetEmptyResult(i) Jim_SetResult(i, (i)->emptyObj)
          578  +#define Jim_GetResult(i) ((i)->result)
          579  +#define Jim_CmdPrivData(i) ((i)->cmdPrivData)
          580  +#define Jim_String(o) Jim_GetString((o), NULL)
          581  +
          582  +/* Note that 'o' is expanded only one time inside this macro,
          583  + * so it's safe to use side effects. */
          584  +#define Jim_SetResult(i,o) do {     \
          585  +    Jim_Obj *_resultObjPtr_ = (o);    \
          586  +    Jim_IncrRefCount(_resultObjPtr_); \
          587  +    Jim_DecrRefCount(i,(i)->result);  \
          588  +    (i)->result = _resultObjPtr_;     \
          589  +} while(0)
          590  +
          591  +/* Use this for filehandles, etc. which need a unique id */
          592  +#define Jim_GetId(i) (++(i)->id)
          593  +
          594  +/* Reference structure. The interpreter pointer is held within privdata member in HashTable */
          595  +#define JIM_REFERENCE_TAGLEN 7 /* The tag is fixed-length, because the reference
          596  +                                  string representation must be fixed length. */
          597  +typedef struct Jim_Reference {
          598  +    Jim_Obj *objPtr;
          599  +    Jim_Obj *finalizerCmdNamePtr;
          600  +    char tag[JIM_REFERENCE_TAGLEN+1];
          601  +} Jim_Reference;
          602  +
          603  +/* -----------------------------------------------------------------------------
          604  + * Exported API prototypes.
          605  + * ---------------------------------------------------------------------------*/
          606  +
          607  +/* Macros that are common for extensions and core. */
          608  +#define Jim_NewEmptyStringObj(i) Jim_NewStringObj(i, "", 0)
          609  +
          610  +/* The core includes real prototypes, extensions instead
          611  + * include a global function pointer for every function exported.
          612  + * Once the extension calls Jim_InitExtension(), the global
          613  + * functon pointers are set to the value of the STUB table
          614  + * contained in the Jim_Interp structure.
          615  + *
          616  + * This makes Jim able to load extensions even if it is statically
          617  + * linked itself, and to load extensions compiled with different
          618  + * versions of Jim (as long as the API is still compatible.) */
          619  +
          620  +/* Macros are common for core and extensions */
          621  +#define Jim_FreeHashTableIterator(iter) Jim_Free(iter)
          622  +
          623  +#define JIM_EXPORT
          624  +
          625  +/* Memory allocation */
          626  +JIM_EXPORT void *Jim_Alloc (int size);
          627  +JIM_EXPORT void *Jim_Realloc(void *ptr, int size);
          628  +JIM_EXPORT void Jim_Free (void *ptr);
          629  +JIM_EXPORT char * Jim_StrDup (const char *s);
          630  +JIM_EXPORT char *Jim_StrDupLen(const char *s, int l);
          631  +
          632  +/* environment */
          633  +JIM_EXPORT char **Jim_GetEnviron(void);
          634  +JIM_EXPORT void Jim_SetEnviron(char **env);
          635  +
          636  +/* evaluation */
          637  +JIM_EXPORT int Jim_Eval(Jim_Interp *interp, const char *script);
          638  +/* in C code, you can do this and get better error messages */
          639  +/*   Jim_EvalSource( interp, __FILE__, __LINE__ , "some tcl commands"); */
          640  +JIM_EXPORT int Jim_EvalSource(Jim_Interp *interp, const char *filename, int lineno, const char *script);
          641  +/* Backwards compatibility */
          642  +#define Jim_Eval_Named(I, S, F, L) Jim_EvalSource((I), (F), (L), (S))
          643  +
          644  +JIM_EXPORT int Jim_EvalGlobal(Jim_Interp *interp, const char *script);
          645  +JIM_EXPORT int Jim_EvalFile(Jim_Interp *interp, const char *filename);
          646  +JIM_EXPORT int Jim_EvalFileGlobal(Jim_Interp *interp, const char *filename);
          647  +JIM_EXPORT int Jim_EvalObj (Jim_Interp *interp, Jim_Obj *scriptObjPtr);
          648  +JIM_EXPORT int Jim_EvalObjVector (Jim_Interp *interp, int objc,
          649  +        Jim_Obj *const *objv);
          650  +JIM_EXPORT int Jim_EvalObjPrefix(Jim_Interp *interp, Jim_Obj *prefix,
          651  +        int objc, Jim_Obj *const *objv);
          652  +#define Jim_EvalPrefix(i, p, oc, ov) Jim_EvalObjPrefix((i), Jim_NewStringObj((i), (p), -1), (oc), (ov))
          653  +JIM_EXPORT int Jim_SubstObj (Jim_Interp *interp, Jim_Obj *substObjPtr,
          654  +        Jim_Obj **resObjPtrPtr, int flags);
          655  +
          656  +/* stack */
          657  +JIM_EXPORT void Jim_InitStack(Jim_Stack *stack);
          658  +JIM_EXPORT void Jim_FreeStack(Jim_Stack *stack);
          659  +JIM_EXPORT int Jim_StackLen(Jim_Stack *stack);
          660  +JIM_EXPORT void Jim_StackPush(Jim_Stack *stack, void *element);
          661  +JIM_EXPORT void * Jim_StackPop(Jim_Stack *stack);
          662  +JIM_EXPORT void * Jim_StackPeek(Jim_Stack *stack);
          663  +JIM_EXPORT void Jim_FreeStackElements(Jim_Stack *stack, void (*freeFunc)(void *ptr));
          664  +
          665  +/* hash table */
          666  +JIM_EXPORT int Jim_InitHashTable (Jim_HashTable *ht,
          667  +        const Jim_HashTableType *type, void *privdata);
          668  +JIM_EXPORT int Jim_ExpandHashTable (Jim_HashTable *ht,
          669  +        unsigned int size);
          670  +JIM_EXPORT int Jim_AddHashEntry (Jim_HashTable *ht, const void *key,
          671  +        void *val);
          672  +JIM_EXPORT int Jim_ReplaceHashEntry (Jim_HashTable *ht,
          673  +        const void *key, void *val);
          674  +JIM_EXPORT int Jim_DeleteHashEntry (Jim_HashTable *ht,
          675  +        const void *key);
          676  +JIM_EXPORT int Jim_FreeHashTable (Jim_HashTable *ht);
          677  +JIM_EXPORT Jim_HashEntry * Jim_FindHashEntry (Jim_HashTable *ht,
          678  +        const void *key);
          679  +JIM_EXPORT int Jim_ResizeHashTable (Jim_HashTable *ht);
          680  +JIM_EXPORT Jim_HashTableIterator *Jim_GetHashTableIterator
          681  +        (Jim_HashTable *ht);
          682  +JIM_EXPORT Jim_HashEntry * Jim_NextHashEntry
          683  +        (Jim_HashTableIterator *iter);
          684  +
          685  +/* objects */
          686  +JIM_EXPORT Jim_Obj * Jim_NewObj (Jim_Interp *interp);
          687  +JIM_EXPORT void Jim_FreeObj (Jim_Interp *interp, Jim_Obj *objPtr);
          688  +JIM_EXPORT void Jim_InvalidateStringRep (Jim_Obj *objPtr);
          689  +JIM_EXPORT void Jim_InitStringRep (Jim_Obj *objPtr, const char *bytes,
          690  +        int length);
          691  +JIM_EXPORT Jim_Obj * Jim_DuplicateObj (Jim_Interp *interp,
          692  +        Jim_Obj *objPtr);
          693  +JIM_EXPORT const char * Jim_GetString(Jim_Obj *objPtr,
          694  +        int *lenPtr);
          695  +JIM_EXPORT int Jim_Length(Jim_Obj *objPtr);
          696  +
          697  +/* string object */
          698  +JIM_EXPORT Jim_Obj * Jim_NewStringObj (Jim_Interp *interp,
          699  +        const char *s, int len);
          700  +JIM_EXPORT Jim_Obj *Jim_NewStringObjUtf8(Jim_Interp *interp,
          701  +        const char *s, int charlen);
          702  +JIM_EXPORT Jim_Obj * Jim_NewStringObjNoAlloc (Jim_Interp *interp,
          703  +        char *s, int len);
          704  +JIM_EXPORT void Jim_AppendString (Jim_Interp *interp, Jim_Obj *objPtr,
          705  +        const char *str, int len);
          706  +JIM_EXPORT void Jim_AppendObj (Jim_Interp *interp, Jim_Obj *objPtr,
          707  +        Jim_Obj *appendObjPtr);
          708  +JIM_EXPORT void Jim_AppendStrings (Jim_Interp *interp,
          709  +        Jim_Obj *objPtr, ...);
          710  +JIM_EXPORT int Jim_StringEqObj(Jim_Obj *aObjPtr, Jim_Obj *bObjPtr);
          711  +JIM_EXPORT int Jim_StringMatchObj (Jim_Interp *interp, Jim_Obj *patternObjPtr,
          712  +        Jim_Obj *objPtr, int nocase);
          713  +JIM_EXPORT Jim_Obj * Jim_StringRangeObj (Jim_Interp *interp,
          714  +        Jim_Obj *strObjPtr, Jim_Obj *firstObjPtr,
          715  +        Jim_Obj *lastObjPtr);
          716  +JIM_EXPORT Jim_Obj * Jim_FormatString (Jim_Interp *interp,
          717  +        Jim_Obj *fmtObjPtr, int objc, Jim_Obj *const *objv);
          718  +JIM_EXPORT Jim_Obj * Jim_ScanString (Jim_Interp *interp, Jim_Obj *strObjPtr,
          719  +        Jim_Obj *fmtObjPtr, int flags);
          720  +JIM_EXPORT int Jim_CompareStringImmediate (Jim_Interp *interp,
          721  +        Jim_Obj *objPtr, const char *str);
          722  +JIM_EXPORT int Jim_StringCompareObj(Jim_Interp *interp, Jim_Obj *firstObjPtr,
          723  +        Jim_Obj *secondObjPtr, int nocase);
          724  +JIM_EXPORT int Jim_Utf8Length(Jim_Interp *interp, Jim_Obj *objPtr);
          725  +
          726  +/* reference object */
          727  +JIM_EXPORT Jim_Obj * Jim_NewReference (Jim_Interp *interp,
          728  +        Jim_Obj *objPtr, Jim_Obj *tagPtr, Jim_Obj *cmdNamePtr);
          729  +JIM_EXPORT Jim_Reference * Jim_GetReference (Jim_Interp *interp,
          730  +        Jim_Obj *objPtr);
          731  +JIM_EXPORT int Jim_SetFinalizer (Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj *cmdNamePtr);
          732  +JIM_EXPORT int Jim_GetFinalizer (Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj **cmdNamePtrPtr);
          733  +
          734  +/* interpreter */
          735  +JIM_EXPORT Jim_Interp * Jim_CreateInterp (void);
          736  +JIM_EXPORT void Jim_FreeInterp (Jim_Interp *i);
          737  +JIM_EXPORT int Jim_GetExitCode (Jim_Interp *interp);
          738  +JIM_EXPORT const char *Jim_ReturnCode(int code);
          739  +JIM_EXPORT void Jim_SetResultFormatted(Jim_Interp *interp, const char *format, ...);
          740  +
          741  +/* commands */
          742  +JIM_EXPORT void Jim_RegisterCoreCommands (Jim_Interp *interp);
          743  +JIM_EXPORT int Jim_CreateCommand (Jim_Interp *interp,
          744  +        const char *cmdName, Jim_CmdProc cmdProc, void *privData,
          745  +         Jim_DelCmdProc delProc);
          746  +JIM_EXPORT int Jim_DeleteCommand (Jim_Interp *interp,
          747  +        const char *cmdName);
          748  +JIM_EXPORT int Jim_RenameCommand (Jim_Interp *interp,
          749  +        const char *oldName, const char *newName);
          750  +JIM_EXPORT Jim_Cmd * Jim_GetCommand (Jim_Interp *interp,
          751  +        Jim_Obj *objPtr, int flags);
          752  +JIM_EXPORT int Jim_SetVariable (Jim_Interp *interp,
          753  +        Jim_Obj *nameObjPtr, Jim_Obj *valObjPtr);
          754  +JIM_EXPORT int Jim_SetVariableStr (Jim_Interp *interp,
          755  +        const char *name, Jim_Obj *objPtr);
          756  +JIM_EXPORT int Jim_SetGlobalVariableStr (Jim_Interp *interp,
          757  +        const char *name, Jim_Obj *objPtr);
          758  +JIM_EXPORT int Jim_SetVariableStrWithStr (Jim_Interp *interp,
          759  +        const char *name, const char *val);
          760  +JIM_EXPORT int Jim_SetVariableLink (Jim_Interp *interp,
          761  +        Jim_Obj *nameObjPtr, Jim_Obj *targetNameObjPtr,
          762  +        Jim_CallFrame *targetCallFrame);
          763  +JIM_EXPORT Jim_Obj * Jim_GetVariable (Jim_Interp *interp,
          764  +        Jim_Obj *nameObjPtr, int flags);
          765  +JIM_EXPORT Jim_Obj * Jim_GetGlobalVariable (Jim_Interp *interp,
          766  +        Jim_Obj *nameObjPtr, int flags);
          767  +JIM_EXPORT Jim_Obj * Jim_GetVariableStr (Jim_Interp *interp,
          768  +        const char *name, int flags);
          769  +JIM_EXPORT Jim_Obj * Jim_GetGlobalVariableStr (Jim_Interp *interp,
          770  +        const char *name, int flags);
          771  +JIM_EXPORT int Jim_UnsetVariable (Jim_Interp *interp,
          772  +        Jim_Obj *nameObjPtr, int flags);
          773  +
          774  +/* call frame */
          775  +JIM_EXPORT Jim_CallFrame *Jim_GetCallFrameByLevel(Jim_Interp *interp,
          776  +        Jim_Obj *levelObjPtr);
          777  +
          778  +/* garbage collection */
          779  +JIM_EXPORT int Jim_Collect (Jim_Interp *interp);
          780  +JIM_EXPORT void Jim_CollectIfNeeded (Jim_Interp *interp);
          781  +
          782  +/* index object */
          783  +JIM_EXPORT int Jim_GetIndex (Jim_Interp *interp, Jim_Obj *objPtr,
          784  +        int *indexPtr);
          785  +
          786  +/* list object */
          787  +JIM_EXPORT Jim_Obj * Jim_NewListObj (Jim_Interp *interp,
          788  +        Jim_Obj *const *elements, int len);
          789  +JIM_EXPORT void Jim_ListInsertElements (Jim_Interp *interp,
          790  +        Jim_Obj *listPtr, int listindex, int objc, Jim_Obj *const *objVec);
          791  +JIM_EXPORT void Jim_ListAppendElement (Jim_Interp *interp,
          792  +        Jim_Obj *listPtr, Jim_Obj *objPtr);
          793  +JIM_EXPORT void Jim_ListAppendList (Jim_Interp *interp,
          794  +        Jim_Obj *listPtr, Jim_Obj *appendListPtr);
          795  +JIM_EXPORT int Jim_ListLength (Jim_Interp *interp, Jim_Obj *objPtr);
          796  +JIM_EXPORT int Jim_ListIndex (Jim_Interp *interp, Jim_Obj *listPrt,
          797  +        int listindex, Jim_Obj **objPtrPtr, int seterr);
          798  +JIM_EXPORT int Jim_SetListIndex (Jim_Interp *interp,
          799  +        Jim_Obj *varNamePtr, Jim_Obj *const *indexv, int indexc,
          800  +        Jim_Obj *newObjPtr);
          801  +JIM_EXPORT Jim_Obj * Jim_ConcatObj (Jim_Interp *interp, int objc,
          802  +        Jim_Obj *const *objv);
          803  +
          804  +/* dict object */
          805  +JIM_EXPORT Jim_Obj * Jim_NewDictObj (Jim_Interp *interp,
          806  +        Jim_Obj *const *elements, int len);
          807  +JIM_EXPORT int Jim_DictKey (Jim_Interp *interp, Jim_Obj *dictPtr,
          808  +        Jim_Obj *keyPtr, Jim_Obj **objPtrPtr, int flags);
          809  +JIM_EXPORT int Jim_DictKeysVector (Jim_Interp *interp,
          810  +        Jim_Obj *dictPtr, Jim_Obj *const *keyv, int keyc,
          811  +        Jim_Obj **objPtrPtr, int flags);
          812  +JIM_EXPORT int Jim_SetDictKeysVector (Jim_Interp *interp,
          813  +        Jim_Obj *varNamePtr, Jim_Obj *const *keyv, int keyc,
          814  +        Jim_Obj *newObjPtr, int flags);
          815  +JIM_EXPORT int Jim_DictPairs(Jim_Interp *interp,
          816  +        Jim_Obj *dictPtr, Jim_Obj ***objPtrPtr, int *len);
          817  +JIM_EXPORT int Jim_DictAddElement(Jim_Interp *interp, Jim_Obj *objPtr,
          818  +        Jim_Obj *keyObjPtr, Jim_Obj *valueObjPtr);
          819  +JIM_EXPORT int Jim_DictKeys(Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj *patternObj);
          820  +JIM_EXPORT int Jim_DictSize(Jim_Interp *interp, Jim_Obj *objPtr);
          821  +
          822  +/* return code object */
          823  +JIM_EXPORT int Jim_GetReturnCode (Jim_Interp *interp, Jim_Obj *objPtr,
          824  +        int *intPtr);
          825  +
          826  +/* expression object */
          827  +JIM_EXPORT int Jim_EvalExpression (Jim_Interp *interp,
          828  +        Jim_Obj *exprObjPtr, Jim_Obj **exprResultPtrPtr);
          829  +JIM_EXPORT int Jim_GetBoolFromExpr (Jim_Interp *interp,
          830  +        Jim_Obj *exprObjPtr, int *boolPtr);
          831  +
          832  +/* integer object */
          833  +JIM_EXPORT int Jim_GetWide (Jim_Interp *interp, Jim_Obj *objPtr,
          834  +        jim_wide *widePtr);
          835  +JIM_EXPORT int Jim_GetLong (Jim_Interp *interp, Jim_Obj *objPtr,
          836  +        long *longPtr);
          837  +#define Jim_NewWideObj  Jim_NewIntObj
          838  +JIM_EXPORT Jim_Obj * Jim_NewIntObj (Jim_Interp *interp,
          839  +        jim_wide wideValue);
          840  +
          841  +/* double object */
          842  +JIM_EXPORT int Jim_GetDouble(Jim_Interp *interp, Jim_Obj *objPtr,
          843  +        double *doublePtr);
          844  +JIM_EXPORT void Jim_SetDouble(Jim_Interp *interp, Jim_Obj *objPtr,
          845  +        double doubleValue);
          846  +JIM_EXPORT Jim_Obj * Jim_NewDoubleObj(Jim_Interp *interp, double doubleValue);
          847  +
          848  +/* shared strings */
          849  +JIM_EXPORT const char * Jim_GetSharedString (Jim_Interp *interp,
          850  +        const char *str);
          851  +JIM_EXPORT void Jim_ReleaseSharedString (Jim_Interp *interp,
          852  +        const char *str);
          853  +
          854  +/* commands utilities */
          855  +JIM_EXPORT void Jim_WrongNumArgs (Jim_Interp *interp, int argc,
          856  +        Jim_Obj *const *argv, const char *msg);
          857  +JIM_EXPORT int Jim_GetEnum (Jim_Interp *interp, Jim_Obj *objPtr,
          858  +        const char * const *tablePtr, int *indexPtr, const char *name, int flags);
          859  +JIM_EXPORT int Jim_ScriptIsComplete (const char *s, int len,
          860  +        char *stateCharPtr);
          861  +/**
          862  + * Find a matching name in the array of the given length.
          863  + *
          864  + * NULL entries are ignored.
          865  + *
          866  + * Returns the matching index if found, or -1 if not.
          867  + */
          868  +JIM_EXPORT int Jim_FindByName(const char *name, const char * const array[], size_t len);
          869  +
          870  +/* package utilities */
          871  +typedef void (Jim_InterpDeleteProc)(Jim_Interp *interp, void *data);
          872  +JIM_EXPORT void * Jim_GetAssocData(Jim_Interp *interp, const char *key);
          873  +JIM_EXPORT int Jim_SetAssocData(Jim_Interp *interp, const char *key,
          874  +        Jim_InterpDeleteProc *delProc, void *data);
          875  +JIM_EXPORT int Jim_DeleteAssocData(Jim_Interp *interp, const char *key);
          876  +
          877  +/* Packages C API */
          878  +/* jim-package.c */
          879  +JIM_EXPORT int Jim_PackageProvide (Jim_Interp *interp,
          880  +        const char *name, const char *ver, int flags);
          881  +JIM_EXPORT int Jim_PackageRequire (Jim_Interp *interp,
          882  +        const char *name, int flags);
          883  +
          884  +/* error messages */
          885  +JIM_EXPORT void Jim_MakeErrorMessage (Jim_Interp *interp);
          886  +
          887  +/* interactive mode */
          888  +JIM_EXPORT int Jim_InteractivePrompt (Jim_Interp *interp);
          889  +
          890  +/* Misc */
          891  +JIM_EXPORT int Jim_InitStaticExtensions(Jim_Interp *interp);
          892  +JIM_EXPORT int Jim_StringToWide(const char *str, jim_wide *widePtr, int base);
          893  +
          894  +/* jim-load.c */
          895  +JIM_EXPORT int Jim_LoadLibrary(Jim_Interp *interp, const char *pathName);
          896  +JIM_EXPORT void Jim_FreeLoadHandles(Jim_Interp *interp);
          897  +
          898  +/* jim-aio.c */
          899  +JIM_EXPORT FILE *Jim_AioFilehandle(Jim_Interp *interp, Jim_Obj *command);
          900  +
          901  +
          902  +/* type inspection - avoid where possible */
          903  +JIM_EXPORT int Jim_IsDict(Jim_Obj *objPtr);
          904  +JIM_EXPORT int Jim_IsList(Jim_Obj *objPtr);
          905  +
          906  +#ifdef __cplusplus
          907  +}
          908  +#endif
          909  +
          910  +#endif /* __JIM__H */
          911  +
          912  +/*
          913  + * Local Variables: ***
          914  + * c-basic-offset: 4 ***
          915  + * tab-width: 4 ***
          916  + * End: ***
          917  + */

Changes to src/main.c.

    24     24   #include <time.h>
    25     25   #include <fcntl.h>
    26     26   #include <sys/types.h>
    27     27   #include <sys/stat.h>
    28     28   #include <stdlib.h> /* atexit() */
    29     29   
    30     30   #if INTERFACE
           31  +#include <jim.h>
           32  +
    31     33   #ifdef FOSSIL_ENABLE_JSON
    32     34   #  include "cson_amalgamation.h" /* JSON API. Needed inside the INTERFACE block! */
    33     35   #  include "json_detail.h"
    34     36   #endif
    35     37   #ifdef FOSSIL_ENABLE_TCL
    36     38   #include "tcl.h"
    37     39   #endif
................................................................................
   125    127     int iErrPriority;       /* Priority of current error message */
   126    128     char *zErrMsg;          /* Text of an error message */
   127    129     int sslNotAvailable;    /* SSL is not available.  Do not redirect to https: */
   128    130     Blob cgiIn;             /* Input to an xfer www method */
   129    131     int cgiOutput;          /* Write error and status messages to CGI */
   130    132     int xferPanic;          /* Write error messages in XFER protocol */
   131    133     int fullHttpReply;      /* True for full HTTP reply.  False for CGI reply */
   132         -  Th_Interp *interp;      /* The TH1 interpreter */
          134  +  Jim_Interp *interp;     /* The script interpreter */
   133    135     FILE *httpIn;           /* Accept HTTP input from here */
   134    136     FILE *httpOut;          /* Send HTTP output here */
   135    137     int xlinkClusterOnly;   /* Set when cloning.  Only process clusters */
   136    138     int fTimeFormat;        /* 1 for UTC.  2 for localtime.  0 not yet selected */
   137    139     int *aCommitFile;       /* Array of files to be committed */
   138    140     int markPrivate;        /* All new artifacts are private if true */
   139    141     int clockSkewSeen;      /* True if clocks on client and server out of sync */
................................................................................
   176    178   
   177    179     /* For defense against Cross-site Request Forgery attacks */
   178    180     char zCsrfToken[12];    /* Value of the anti-CSRF token */
   179    181     int okCsrf;             /* Anti-CSRF token is present and valid */
   180    182   
   181    183     int parseCnt[10];       /* Counts of artifacts parsed */
   182    184     FILE *fDebug;           /* Write debug information here, if the file exists */
   183         -  int thTrace;            /* True to enable TH1 debugging output */
   184         -  Blob thLog;             /* Text of the TH1 debugging output */
          185  +  int thTrace;            /* True to enable script debugging output */
          186  +  Blob thLog;             /* Text of the script debugging output */
   185    187   
   186    188     int isHome;             /* True if rendering the "home" page */
   187    189   
   188    190     /* Storage for the aux() and/or option() SQL function arguments */
   189    191     int nAux;                    /* Number of distinct aux() or option() values */
   190    192     const char *azAuxName[MX_AUX]; /* Name of each aux() or option() value */
   191    193     char *azAuxParam[MX_AUX];      /* Param of each aux() or option() value */

Changes to src/main.mk.

   345    345   # The FOSSIL_ENABLE_TCL variable may be undefined, set to 0, or set to 1.
   346    346   # If it is set to 1, then we need to build the Tcl integration code and
   347    347   # link to the Tcl library.
   348    348   TCL_OBJ.0 = 
   349    349   TCL_OBJ.1 = $(OBJDIR)/th_tcl.o
   350    350   TCL_OBJ. = $(TCL_OBJ.0)
   351    351   
   352         -EXTRAOBJ =  $(SQLITE3_OBJ.$(USE_SYSTEM_SQLITE))  $(OBJDIR)/shell.o  $(OBJDIR)/th.o  $(OBJDIR)/th_lang.o  $(TCL_OBJ.$(FOSSIL_ENABLE_TCL))  $(OBJDIR)/cson_amalgamation.o
          352  +EXTRAOBJ =  $(SQLITE3_OBJ.$(USE_SYSTEM_SQLITE))  $(OBJDIR)/shell.o  $(OBJDIR)/jimtcl.o  $(TCL_OBJ.$(FOSSIL_ENABLE_TCL))  $(OBJDIR)/cson_amalgamation.o
   353    353   
   354    354   $(APPNAME):	$(OBJDIR)/headers $(OBJ) $(EXTRAOBJ)
   355    355   	$(TCC) -o $(APPNAME) $(OBJ) $(EXTRAOBJ) $(LIB)
   356    356   
   357    357   # This rule prevents make from using its default rules to try build
   358    358   # an executable named "manifest" out of the file named "manifest.c"
   359    359   #
................................................................................
   363    363   clean:	
   364    364   	rm -rf $(OBJDIR)/* $(APPNAME)
   365    365   
   366    366   
   367    367   $(OBJDIR)/page_index.h: $(TRANS_SRC) $(OBJDIR)/mkindex
   368    368   	$(OBJDIR)/mkindex $(TRANS_SRC) >$@
   369    369   $(OBJDIR)/headers:	$(OBJDIR)/page_index.h $(OBJDIR)/makeheaders $(OBJDIR)/VERSION.h
   370         -	$(OBJDIR)/makeheaders  $(OBJDIR)/add_.c:$(OBJDIR)/add.h $(OBJDIR)/allrepo_.c:$(OBJDIR)/allrepo.h $(OBJDIR)/attach_.c:$(OBJDIR)/attach.h $(OBJDIR)/bag_.c:$(OBJDIR)/bag.h $(OBJDIR)/bisect_.c:$(OBJDIR)/bisect.h $(OBJDIR)/blob_.c:$(OBJDIR)/blob.h $(OBJDIR)/branch_.c:$(OBJDIR)/branch.h $(OBJDIR)/browse_.c:$(OBJDIR)/browse.h $(OBJDIR)/captcha_.c:$(OBJDIR)/captcha.h $(OBJDIR)/cgi_.c:$(OBJDIR)/cgi.h $(OBJDIR)/checkin_.c:$(OBJDIR)/checkin.h $(OBJDIR)/checkout_.c:$(OBJDIR)/checkout.h $(OBJDIR)/clearsign_.c:$(OBJDIR)/clearsign.h $(OBJDIR)/clone_.c:$(OBJDIR)/clone.h $(OBJDIR)/comformat_.c:$(OBJDIR)/comformat.h $(OBJDIR)/configure_.c:$(OBJDIR)/configure.h $(OBJDIR)/content_.c:$(OBJDIR)/content.h $(OBJDIR)/db_.c:$(OBJDIR)/db.h $(OBJDIR)/delta_.c:$(OBJDIR)/delta.h $(OBJDIR)/deltacmd_.c:$(OBJDIR)/deltacmd.h $(OBJDIR)/descendants_.c:$(OBJDIR)/descendants.h $(OBJDIR)/diff_.c:$(OBJDIR)/diff.h $(OBJDIR)/diffcmd_.c:$(OBJDIR)/diffcmd.h $(OBJDIR)/doc_.c:$(OBJDIR)/doc.h $(OBJDIR)/encode_.c:$(OBJDIR)/encode.h $(OBJDIR)/event_.c:$(OBJDIR)/event.h $(OBJDIR)/export_.c:$(OBJDIR)/export.h $(OBJDIR)/file_.c:$(OBJDIR)/file.h $(OBJDIR)/finfo_.c:$(OBJDIR)/finfo.h $(OBJDIR)/glob_.c:$(OBJDIR)/glob.h $(OBJDIR)/graph_.c:$(OBJDIR)/graph.h $(OBJDIR)/gzip_.c:$(OBJDIR)/gzip.h $(OBJDIR)/http_.c:$(OBJDIR)/http.h $(OBJDIR)/http_socket_.c:$(OBJDIR)/http_socket.h $(OBJDIR)/http_ssl_.c:$(OBJDIR)/http_ssl.h $(OBJDIR)/http_transport_.c:$(OBJDIR)/http_transport.h $(OBJDIR)/import_.c:$(OBJDIR)/import.h $(OBJDIR)/info_.c:$(OBJDIR)/info.h $(OBJDIR)/json_.c:$(OBJDIR)/json.h $(OBJDIR)/json_artifact_.c:$(OBJDIR)/json_artifact.h $(OBJDIR)/json_branch_.c:$(OBJDIR)/json_branch.h $(OBJDIR)/json_diff_.c:$(OBJDIR)/json_diff.h $(OBJDIR)/json_login_.c:$(OBJDIR)/json_login.h $(OBJDIR)/json_query_.c:$(OBJDIR)/json_query.h $(OBJDIR)/json_report_.c:$(OBJDIR)/json_report.h $(OBJDIR)/json_tag_.c:$(OBJDIR)/json_tag.h $(OBJDIR)/json_timeline_.c:$(OBJDIR)/json_timeline.h $(OBJDIR)/json_user_.c:$(OBJDIR)/json_user.h $(OBJDIR)/json_wiki_.c:$(OBJDIR)/json_wiki.h $(OBJDIR)/leaf_.c:$(OBJDIR)/leaf.h $(OBJDIR)/login_.c:$(OBJDIR)/login.h $(OBJDIR)/main_.c:$(OBJDIR)/main.h $(OBJDIR)/manifest_.c:$(OBJDIR)/manifest.h $(OBJDIR)/md5_.c:$(OBJDIR)/md5.h $(OBJDIR)/merge_.c:$(OBJDIR)/merge.h $(OBJDIR)/merge3_.c:$(OBJDIR)/merge3.h $(OBJDIR)/name_.c:$(OBJDIR)/name.h $(OBJDIR)/path_.c:$(OBJDIR)/path.h $(OBJDIR)/pivot_.c:$(OBJDIR)/pivot.h $(OBJDIR)/popen_.c:$(OBJDIR)/popen.h $(OBJDIR)/pqueue_.c:$(OBJDIR)/pqueue.h $(OBJDIR)/printf_.c:$(OBJDIR)/printf.h $(OBJDIR)/rebuild_.c:$(OBJDIR)/rebuild.h $(OBJDIR)/report_.c:$(OBJDIR)/report.h $(OBJDIR)/rss_.c:$(OBJDIR)/rss.h $(OBJDIR)/schema_.c:$(OBJDIR)/schema.h $(OBJDIR)/search_.c:$(OBJDIR)/search.h $(OBJDIR)/setup_.c:$(OBJDIR)/setup.h $(OBJDIR)/sha1_.c:$(OBJDIR)/sha1.h $(OBJDIR)/shun_.c:$(OBJDIR)/shun.h $(OBJDIR)/skins_.c:$(OBJDIR)/skins.h $(OBJDIR)/sqlcmd_.c:$(OBJDIR)/sqlcmd.h $(OBJDIR)/stash_.c:$(OBJDIR)/stash.h $(OBJDIR)/stat_.c:$(OBJDIR)/stat.h $(OBJDIR)/style_.c:$(OBJDIR)/style.h $(OBJDIR)/sync_.c:$(OBJDIR)/sync.h $(OBJDIR)/tag_.c:$(OBJDIR)/tag.h $(OBJDIR)/tar_.c:$(OBJDIR)/tar.h $(OBJDIR)/th_main_.c:$(OBJDIR)/th_main.h $(OBJDIR)/timeline_.c:$(OBJDIR)/timeline.h $(OBJDIR)/tkt_.c:$(OBJDIR)/tkt.h $(OBJDIR)/tktsetup_.c:$(OBJDIR)/tktsetup.h $(OBJDIR)/undo_.c:$(OBJDIR)/undo.h $(OBJDIR)/update_.c:$(OBJDIR)/update.h $(OBJDIR)/url_.c:$(OBJDIR)/url.h $(OBJDIR)/user_.c:$(OBJDIR)/user.h $(OBJDIR)/verify_.c:$(OBJDIR)/verify.h $(OBJDIR)/vfile_.c:$(OBJDIR)/vfile.h $(OBJDIR)/wiki_.c:$(OBJDIR)/wiki.h $(OBJDIR)/wikiformat_.c:$(OBJDIR)/wikiformat.h $(OBJDIR)/winhttp_.c:$(OBJDIR)/winhttp.h $(OBJDIR)/xfer_.c:$(OBJDIR)/xfer.h $(OBJDIR)/xfersetup_.c:$(OBJDIR)/xfersetup.h $(OBJDIR)/zip_.c:$(OBJDIR)/zip.h $(SRCDIR)/sqlite3.h $(SRCDIR)/th.h $(OBJDIR)/VERSION.h
          370  +	$(OBJDIR)/makeheaders  $(OBJDIR)/add_.c:$(OBJDIR)/add.h $(OBJDIR)/allrepo_.c:$(OBJDIR)/allrepo.h $(OBJDIR)/attach_.c:$(OBJDIR)/attach.h $(OBJDIR)/bag_.c:$(OBJDIR)/bag.h $(OBJDIR)/bisect_.c:$(OBJDIR)/bisect.h $(OBJDIR)/blob_.c:$(OBJDIR)/blob.h $(OBJDIR)/branch_.c:$(OBJDIR)/branch.h $(OBJDIR)/browse_.c:$(OBJDIR)/browse.h $(OBJDIR)/captcha_.c:$(OBJDIR)/captcha.h $(OBJDIR)/cgi_.c:$(OBJDIR)/cgi.h $(OBJDIR)/checkin_.c:$(OBJDIR)/checkin.h $(OBJDIR)/checkout_.c:$(OBJDIR)/checkout.h $(OBJDIR)/clearsign_.c:$(OBJDIR)/clearsign.h $(OBJDIR)/clone_.c:$(OBJDIR)/clone.h $(OBJDIR)/comformat_.c:$(OBJDIR)/comformat.h $(OBJDIR)/configure_.c:$(OBJDIR)/configure.h $(OBJDIR)/content_.c:$(OBJDIR)/content.h $(OBJDIR)/db_.c:$(OBJDIR)/db.h $(OBJDIR)/delta_.c:$(OBJDIR)/delta.h $(OBJDIR)/deltacmd_.c:$(OBJDIR)/deltacmd.h $(OBJDIR)/descendants_.c:$(OBJDIR)/descendants.h $(OBJDIR)/diff_.c:$(OBJDIR)/diff.h $(OBJDIR)/diffcmd_.c:$(OBJDIR)/diffcmd.h $(OBJDIR)/doc_.c:$(OBJDIR)/doc.h $(OBJDIR)/encode_.c:$(OBJDIR)/encode.h $(OBJDIR)/event_.c:$(OBJDIR)/event.h $(OBJDIR)/export_.c:$(OBJDIR)/export.h $(OBJDIR)/file_.c:$(OBJDIR)/file.h $(OBJDIR)/finfo_.c:$(OBJDIR)/finfo.h $(OBJDIR)/glob_.c:$(OBJDIR)/glob.h $(OBJDIR)/graph_.c:$(OBJDIR)/graph.h $(OBJDIR)/gzip_.c:$(OBJDIR)/gzip.h $(OBJDIR)/http_.c:$(OBJDIR)/http.h $(OBJDIR)/http_socket_.c:$(OBJDIR)/http_socket.h $(OBJDIR)/http_ssl_.c:$(OBJDIR)/http_ssl.h $(OBJDIR)/http_transport_.c:$(OBJDIR)/http_transport.h $(OBJDIR)/import_.c:$(OBJDIR)/import.h $(OBJDIR)/info_.c:$(OBJDIR)/info.h $(OBJDIR)/json_.c:$(OBJDIR)/json.h $(OBJDIR)/json_artifact_.c:$(OBJDIR)/json_artifact.h $(OBJDIR)/json_branch_.c:$(OBJDIR)/json_branch.h $(OBJDIR)/json_diff_.c:$(OBJDIR)/json_diff.h $(OBJDIR)/json_login_.c:$(OBJDIR)/json_login.h $(OBJDIR)/json_query_.c:$(OBJDIR)/json_query.h $(OBJDIR)/json_report_.c:$(OBJDIR)/json_report.h $(OBJDIR)/json_tag_.c:$(OBJDIR)/json_tag.h $(OBJDIR)/json_timeline_.c:$(OBJDIR)/json_timeline.h $(OBJDIR)/json_user_.c:$(OBJDIR)/json_user.h $(OBJDIR)/json_wiki_.c:$(OBJDIR)/json_wiki.h $(OBJDIR)/leaf_.c:$(OBJDIR)/leaf.h $(OBJDIR)/login_.c:$(OBJDIR)/login.h $(OBJDIR)/main_.c:$(OBJDIR)/main.h $(OBJDIR)/manifest_.c:$(OBJDIR)/manifest.h $(OBJDIR)/md5_.c:$(OBJDIR)/md5.h $(OBJDIR)/merge_.c:$(OBJDIR)/merge.h $(OBJDIR)/merge3_.c:$(OBJDIR)/merge3.h $(OBJDIR)/name_.c:$(OBJDIR)/name.h $(OBJDIR)/path_.c:$(OBJDIR)/path.h $(OBJDIR)/pivot_.c:$(OBJDIR)/pivot.h $(OBJDIR)/popen_.c:$(OBJDIR)/popen.h $(OBJDIR)/pqueue_.c:$(OBJDIR)/pqueue.h $(OBJDIR)/printf_.c:$(OBJDIR)/printf.h $(OBJDIR)/rebuild_.c:$(OBJDIR)/rebuild.h $(OBJDIR)/report_.c:$(OBJDIR)/report.h $(OBJDIR)/rss_.c:$(OBJDIR)/rss.h $(OBJDIR)/schema_.c:$(OBJDIR)/schema.h $(OBJDIR)/search_.c:$(OBJDIR)/search.h $(OBJDIR)/setup_.c:$(OBJDIR)/setup.h $(OBJDIR)/sha1_.c:$(OBJDIR)/sha1.h $(OBJDIR)/shun_.c:$(OBJDIR)/shun.h $(OBJDIR)/skins_.c:$(OBJDIR)/skins.h $(OBJDIR)/sqlcmd_.c:$(OBJDIR)/sqlcmd.h $(OBJDIR)/stash_.c:$(OBJDIR)/stash.h $(OBJDIR)/stat_.c:$(OBJDIR)/stat.h $(OBJDIR)/style_.c:$(OBJDIR)/style.h $(OBJDIR)/sync_.c:$(OBJDIR)/sync.h $(OBJDIR)/tag_.c:$(OBJDIR)/tag.h $(OBJDIR)/tar_.c:$(OBJDIR)/tar.h $(OBJDIR)/th_main_.c:$(OBJDIR)/th_main.h $(OBJDIR)/timeline_.c:$(OBJDIR)/timeline.h $(OBJDIR)/tkt_.c:$(OBJDIR)/tkt.h $(OBJDIR)/tktsetup_.c:$(OBJDIR)/tktsetup.h $(OBJDIR)/undo_.c:$(OBJDIR)/undo.h $(OBJDIR)/update_.c:$(OBJDIR)/update.h $(OBJDIR)/url_.c:$(OBJDIR)/url.h $(OBJDIR)/user_.c:$(OBJDIR)/user.h $(OBJDIR)/verify_.c:$(OBJDIR)/verify.h $(OBJDIR)/vfile_.c:$(OBJDIR)/vfile.h $(OBJDIR)/wiki_.c:$(OBJDIR)/wiki.h $(OBJDIR)/wikiformat_.c:$(OBJDIR)/wikiformat.h $(OBJDIR)/winhttp_.c:$(OBJDIR)/winhttp.h $(OBJDIR)/xfer_.c:$(OBJDIR)/xfer.h $(OBJDIR)/xfersetup_.c:$(OBJDIR)/xfersetup.h $(OBJDIR)/zip_.c:$(OBJDIR)/zip.h $(SRCDIR)/sqlite3.h $(SRCDIR)/jim.h $(OBJDIR)/VERSION.h
   371    371   	touch $(OBJDIR)/headers
   372    372   $(OBJDIR)/headers: Makefile
   373    373   $(OBJDIR)/json.o $(OBJDIR)/json_artifact.o $(OBJDIR)/json_branch.o $(OBJDIR)/json_diff.o $(OBJDIR)/json_login.o $(OBJDIR)/json_query.o $(OBJDIR)/json_report.o $(OBJDIR)/json_tag.o $(OBJDIR)/json_timeline.o $(OBJDIR)/json_user.o $(OBJDIR)/json_wiki.o : $(SRCDIR)/json_detail.h
   374    374   Makefile:
   375    375   $(OBJDIR)/add_.c:	$(SRCDIR)/add.c $(OBJDIR)/translate
   376    376   	$(OBJDIR)/translate $(SRCDIR)/add.c >$(OBJDIR)/add_.c
   377    377   
................................................................................
  1038   1038   
  1039   1039   $(OBJDIR)/th.o:	$(SRCDIR)/th.c
  1040   1040   	$(XTCC) -I$(SRCDIR) -c $(SRCDIR)/th.c -o $(OBJDIR)/th.o
  1041   1041   
  1042   1042   $(OBJDIR)/th_lang.o:	$(SRCDIR)/th_lang.c
  1043   1043   	$(XTCC) -I$(SRCDIR) -c $(SRCDIR)/th_lang.c -o $(OBJDIR)/th_lang.o
  1044   1044   
         1045  +$(OBJDIR)/jimtcl.o:	$(SRCDIR)/../autosetup/jimsh0.c
         1046  +	$(XTCC) -I$(SRCDIR) -DJIM_BOOTSTRAP_LIB_ONLY -c $(SRCDIR)/../autosetup/jimsh0.c -o $(OBJDIR)/jimtcl.o
         1047  +
  1045   1048   $(OBJDIR)/th_tcl.o:	$(SRCDIR)/th_tcl.c
  1046   1049   	$(XTCC) -I$(SRCDIR) -c $(SRCDIR)/th_tcl.c -o $(OBJDIR)/th_tcl.o
  1047   1050   
  1048   1051   
  1049   1052   $(OBJDIR)/cson_amalgamation.o: $(SRCDIR)/cson_amalgamation.c
  1050   1053   	$(XTCC) -I$(SRCDIR) -c $(SRCDIR)/cson_amalgamation.c -o $(OBJDIR)/cson_amalgamation.o -DCSON_FOSSIL_MODE
  1051   1054   

Changes to src/makemake.tcl.

   221    221   TCL_OBJ.0 = 
   222    222   TCL_OBJ.1 = $(OBJDIR)/th_tcl.o
   223    223   TCL_OBJ. = $(TCL_OBJ.0)
   224    224   
   225    225   EXTRAOBJ = \
   226    226     $(SQLITE3_OBJ.$(USE_SYSTEM_SQLITE)) \
   227    227     $(OBJDIR)/shell.o \
   228         -  $(OBJDIR)/th.o \
   229         -  $(OBJDIR)/th_lang.o \
          228  +  $(OBJDIR)/jimtcl.o \
   230    229     $(TCL_OBJ.$(FOSSIL_ENABLE_TCL)) \
   231    230     $(OBJDIR)/cson_amalgamation.o
   232    231   
   233    232   $(APPNAME):	$(OBJDIR)/headers $(OBJ) $(EXTRAOBJ)
   234    233   	$(TCC) -o $(APPNAME) $(OBJ) $(EXTRAOBJ) $(LIB)
   235    234   
   236    235   # This rule prevents make from using its default rules to try build
................................................................................
   246    245   
   247    246   set mhargs {}
   248    247   foreach s [lsort $src] {
   249    248     append mhargs " \$(OBJDIR)/${s}_.c:\$(OBJDIR)/$s.h"
   250    249     set extra_h($s) {}
   251    250   }
   252    251   append mhargs " \$(SRCDIR)/sqlite3.h"
   253         -append mhargs " \$(SRCDIR)/th.h"
          252  +append mhargs " \$(SRCDIR)/jim.h"
   254    253   #append mhargs " \$(SRCDIR)/cson_amalgamation.h"
   255    254   append mhargs " \$(OBJDIR)/VERSION.h"
   256    255   writeln "\$(OBJDIR)/page_index.h: \$(TRANS_SRC) \$(OBJDIR)/mkindex"
   257    256   writeln "\t\$(OBJDIR)/mkindex \$(TRANS_SRC) >$@"
   258    257   writeln "\$(OBJDIR)/headers:\t\$(OBJDIR)/page_index.h \$(OBJDIR)/makeheaders \$(OBJDIR)/VERSION.h"
   259    258   writeln "\t\$(OBJDIR)/makeheaders $mhargs"
   260    259   writeln "\ttouch \$(OBJDIR)/headers"
................................................................................
   289    288   
   290    289   writeln "\$(OBJDIR)/th.o:\t\$(SRCDIR)/th.c"
   291    290   writeln "\t\$(XTCC) -I\$(SRCDIR) -c \$(SRCDIR)/th.c -o \$(OBJDIR)/th.o\n"
   292    291   
   293    292   writeln "\$(OBJDIR)/th_lang.o:\t\$(SRCDIR)/th_lang.c"
   294    293   writeln "\t\$(XTCC) -I\$(SRCDIR) -c \$(SRCDIR)/th_lang.c -o \$(OBJDIR)/th_lang.o\n"
   295    294   
          295  +writeln "\$(OBJDIR)/jimtcl.o:\t\$(SRCDIR)/../autosetup/jimsh0.c"
          296  +writeln "\t\$(XTCC) -I\$(SRCDIR) -DJIM_BOOTSTRAP_LIB_ONLY -c \$(SRCDIR)/../autosetup/jimsh0.c -o \$(OBJDIR)/jimtcl.o\n"
          297  +
   296    298   writeln "\$(OBJDIR)/th_tcl.o:\t\$(SRCDIR)/th_tcl.c"
   297    299   writeln "\t\$(XTCC) -I\$(SRCDIR) -c \$(SRCDIR)/th_tcl.c -o \$(OBJDIR)/th_tcl.o\n"
   298    300   
   299    301   set opt {}
   300    302   writeln {
   301    303   $(OBJDIR)/cson_amalgamation.o: $(SRCDIR)/cson_amalgamation.c
   302    304   	$(XTCC) -I$(SRCDIR) -c $(SRCDIR)/cson_amalgamation.c -o $(OBJDIR)/cson_amalgamation.o -DCSON_FOSSIL_MODE
................................................................................
   569    571   
   570    572   set mhargs {}
   571    573   foreach s [lsort $src] {
   572    574     append mhargs " \$(OBJDIR)/${s}_.c:\$(OBJDIR)/$s.h"
   573    575     set extra_h($s) {}
   574    576   }
   575    577   append mhargs " \$(SRCDIR)/sqlite3.h"
   576         -append mhargs " \$(SRCDIR)/th.h"
          578  +append mhargs " \$(SRCDIR)/jim.h"
   577    579   append mhargs " \$(OBJDIR)/VERSION.h"
   578    580   writeln "\$(OBJDIR)/page_index.h: \$(TRANS_SRC) \$(OBJDIR)/mkindex"
   579    581   writeln "\t\$(MKINDEX) \$(TRANS_SRC) >$@"
   580    582   writeln "\$(OBJDIR)/headers:\t\$(OBJDIR)/page_index.h \$(OBJDIR)/makeheaders \$(OBJDIR)/VERSION.h"
   581    583   writeln "\t\$(MAKEHEADERS) $mhargs"
   582    584   writeln "\techo Done >\$(OBJDIR)/headers"
   583    585   writeln ""
................................................................................
   761    763     writeln "\t+translate\$E \$** > \$@\n"
   762    764   }
   763    765   
   764    766   writeln -nonewline "headers: makeheaders\$E page_index.h VERSION.h\n\t +makeheaders\$E "
   765    767   foreach s [lsort $src] {
   766    768     writeln -nonewline "${s}_.c:$s.h "
   767    769   }
   768         -writeln "\$(SRCDIR)\\sqlite3.h \$(SRCDIR)\\th.h VERSION.h \$(SRCDIR)\\cson_amalgamation.h"
          770  +writeln "\$(SRCDIR)\\sqlite3.h \$(SRCDIR)\\jim.h VERSION.h"
          771  +writeln "\$(SRCDIR)\\sqlite3.h \$(SRCDIR)\\jim.h VERSION.h \$(SRCDIR)\\cson_amalgamation.h"
   769    772   writeln "\t@copy /Y nul: headers"
   770    773   
   771    774   close $output_file
   772    775   #
   773    776   # End of the win/Makefile.dmc output
   774    777   ##############################################################################
   775    778   ##############################################################################
................................................................................
   917    920     writeln "\ttranslate\$E \$** > \$@\n"
   918    921   }
   919    922   
   920    923   writeln -nonewline "headers: makeheaders\$E page_index.h VERSION.h\n\tmakeheaders\$E "
   921    924   foreach s [lsort $src] {
   922    925     writeln -nonewline "${s}_.c:$s.h "
   923    926   }
   924         -writeln "\$(SRCDIR)\\sqlite3.h \$(SRCDIR)\\th.h VERSION.h \$(SRCDIR)\\cson_amalgamation.h"
          927  +writeln "\$(SRCDIR)\\sqlite3.h \$(SRCDIR)\\jim.h VERSION.h \$(SRCDIR)\\cson_amalgamation.h"
   925    928   writeln "\t@copy /Y nul: headers"
   926    929   
   927    930   
   928    931   close $output_file
   929    932   #
   930    933   # End of the win/Makefile.msc output
   931    934   ##############################################################################
................................................................................
  1082   1085   	mkindex.exe $(TRANSLATEDSRC) >$@
  1083   1086   
  1084   1087   # extracting version info from manifest
  1085   1088   VERSION.h:	version.exe ..\manifest.uuid ..\manifest ..\VERSION
  1086   1089   	version.exe ..\manifest.uuid ..\manifest ..\VERSION  > $@
  1087   1090   
  1088   1091   # generate the simplified headers
  1089         -headers: makeheaders.exe page_index.h VERSION.h ../src/sqlite3.h ../src/th.h VERSION.h
  1090         -	makeheaders.exe $(foreach ts,$(TRANSLATEDSRC),$(ts):$(ts:_.c=.h)) ../src/sqlite3.h ../src/th.h VERSION.h
         1092  +headers: makeheaders.exe page_index.h VERSION.h ../src/sqlite3.h ../src/jim.h VERSION.h
         1093  +	makeheaders.exe $(foreach ts,$(TRANSLATEDSRC),$(ts):$(ts:_.c=.h)) ../src/sqlite3.h ../src/jim.h VERSION.h
  1091   1094   	echo Done >$@
  1092   1095   
  1093   1096   # compile C sources with relevant options
  1094   1097   
  1095   1098   $(TRANSLATEDOBJ):	%_.obj:	%_.c %.h
  1096   1099   	$(CC) $(CCFLAGS) $(INCLUDE) "$<" -Fo"$@"
  1097   1100   
  1098   1101   $(SQLITEOBJ):	%.obj:	$(SRCDIR)%.c $(SRCDIR)%.h
  1099   1102   	$(CC) $(CCFLAGS) $(SQLITEDEFINES) $(INCLUDE) "$<" -Fo"$@"
  1100   1103   
  1101   1104   $(SQLITESHELLOBJ):	%.obj:	$(SRCDIR)%.c
  1102   1105   	$(CC) $(CCFLAGS) $(SQLITESHELLDEFINES) $(INCLUDE) "$<" -Fo"$@"
  1103   1106   
  1104         -$(THOBJ):	%.obj:	$(SRCDIR)%.c $(SRCDIR)th.h
         1107  +$(THOBJ):	%.obj:	$(SRCDIR)%.c $(SRCDIR)jim.h
  1105   1108   	$(CC) $(CCFLAGS) $(INCLUDE) "$<" -Fo"$@"
  1106   1109   
  1107   1110   $(ZLIBOBJ):	%.obj:	$(ZLIBSRCDIR)%.c
  1108   1111   	$(CC) $(CCFLAGS) $(INCLUDE) "$<" -Fo"$@"
  1109   1112   
  1110   1113   # create the windows resource with icon and version info
  1111   1114   $(RESOURCE):	%.res:	../win/%.rc ../win/*.ico

Changes to src/name.c.

   424    424       }
   425    425       db_finalize(&q);
   426    426       db_prepare(&q,
   427    427          "SELECT type, datetime(mtime,'localtime'),"
   428    428          "       coalesce(euser,user), coalesce(ecomment,comment)"
   429    429          "  FROM event WHERE objid=%d", rid);
   430    430       if( db_step(&q)==SQLITE_ROW ){
   431         -      const char *zType;
          431  +      const char *zType = 0;
   432    432         switch( db_column_text(&q,0)[0] ){
   433    433           case 'c':  zType = "Check-in";       break;
   434    434           case 'w':  zType = "Wiki-edit";      break;
   435    435           case 'e':  zType = "Event";          break;
   436    436           case 't':  zType = "Ticket-change";  break;
   437    437           case 'g':  zType = "Tag-change";     break;
   438    438           default:   zType = "Unknown";        break;

Deleted src/th.c.

     1         -
     2         -/*
     3         -** The implementation of the TH core. This file contains the parser, and 
     4         -** the implementation of the interface in th.h.
     5         -*/
     6         -
     7         -#include "th.h"
     8         -#include <string.h>
     9         -#include <assert.h>
    10         -
    11         -typedef struct Th_Command   Th_Command;
    12         -typedef struct Th_Frame     Th_Frame;
    13         -typedef struct Th_Variable  Th_Variable;
    14         -
    15         -/*
    16         -** Interpreter structure.
    17         -*/
    18         -struct Th_Interp {
    19         -  Th_Vtab *pVtab;     /* Copy of the argument passed to Th_CreateInterp() */
    20         -  char *zResult;     /* Current interpreter result (Th_Malloc()ed) */
    21         -  int nResult;        /* number of bytes in zResult */
    22         -  Th_Hash *paCmd;     /* Table of registered commands */
    23         -  Th_Frame *pFrame;   /* Current execution frame */
    24         -  int isListMode;     /* True if thSplitList() should operate in "list" mode */
    25         -};
    26         -
    27         -/*
    28         -** Each TH command registered using Th_CreateCommand() is represented
    29         -** by an instance of the following structure stored in the Th_Interp.paCmd
    30         -** hash-table.
    31         -*/
    32         -struct Th_Command {
    33         -  int (*xProc)(Th_Interp *, void *, int, const char **, int *);
    34         -  void *pContext;
    35         -  void (*xDel)(Th_Interp *, void *);
    36         -};
    37         -
    38         -/*
    39         -** Each stack frame (variable scope) is represented by an instance
    40         -** of this structure. Variable values set using the Th_SetVar command
    41         -** are stored in the Th_Frame.paVar hash table member of the associated
    42         -** stack frame object.
    43         -**
    44         -** When an interpreter is created, a single Th_Frame structure is also
    45         -** allocated - the global variable scope. Th_Interp.pFrame (the current
    46         -** interpreter frame) is initialised to point to this Th_Frame. It is 
    47         -** not deleted for the lifetime of the interpreter (because the global 
    48         -** frame never goes out of scope).
    49         -**
    50         -** New stack frames are created by the Th_InFrame() function. Before
    51         -** invoking its callback function, Th_InFrame() allocates a new Th_Frame
    52         -** structure with pCaller set to the current frame (Th_Interp.pFrame),
    53         -** and sets the current frame to the new frame object. After the callback
    54         -** has been invoked, the allocated Th_Frame is deleted and the value
    55         -** of the current frame pointer restored.
    56         -** 
    57         -** By default, the Th_SetVar(), Th_UnsetVar() and Th_GetVar() functions 
    58         -** access variable values in the current frame. If they need to access 
    59         -** the global frame, they do so by traversing the pCaller pointer list.
    60         -** Likewise, the Th_LinkVar() function uses the pCaller pointers to 
    61         -** link to variables located in the global or other stack frames.
    62         -*/
    63         -struct Th_Frame {
    64         -  Th_Hash *paVar;               /* Variables defined in this scope */
    65         -  Th_Frame *pCaller;            /* Calling frame */
    66         -};
    67         -
    68         -/*
    69         -** This structure represents a value assigned to a th1 variable.
    70         -**
    71         -** The Th_Frame.paVar hash table maps from variable name (a th1 string)
    72         -** to a pointer to an instance of the following structure. More than
    73         -** one hash table entry may map to a single structure if variable
    74         -** links have been created using Th_LinkVar(). The number of references
    75         -** is stored in Th_Variable.nRef.
    76         -**
    77         -** For scalar variables, Th_Variable.zData is never 0. Th_Variable.nData
    78         -** stores the number of bytes in the value pointed to by zData.
    79         -**
    80         -** For an array variable, Th_Variable.zData is 0 and pHash points to
    81         -** a hash table mapping between array key name (a th1 string) and
    82         -** a the pointer to the Th_Variable structure holding the scalar
    83         -** value.
    84         -*/
    85         -struct Th_Variable {
    86         -  int nRef;                   /* Number of references to this structure */
    87         -  int nData;                  /* Number of bytes at Th_Variable.zData */
    88         -  char *zData;               /* Data for scalar variables */
    89         -  Th_Hash *pHash;             /* Data for array variables */
    90         -};
    91         -
    92         -/*
    93         -** Hash table API:
    94         -*/
    95         -#define TH_HASHSIZE 257
    96         -struct Th_Hash {
    97         -  Th_HashEntry *a[TH_HASHSIZE];
    98         -};
    99         -
   100         -static int thEvalLocal(Th_Interp *, const char *, int);
   101         -static int thSplitList(Th_Interp*, const char*, int, char***, int **, int*);
   102         -
   103         -static int thHexdigit(char c);
   104         -static int thEndOfLine(const char *, int);
   105         -
   106         -static int  thPushFrame(Th_Interp*, Th_Frame*);
   107         -static void thPopFrame(Th_Interp*);
   108         -
   109         -static void thFreeVariable(Th_HashEntry*, void*);
   110         -static void thFreeCommand(Th_HashEntry*, void*);
   111         -
   112         -/*
   113         -** The following are used by both the expression and language parsers.
   114         -** Given that the start of the input string (z, n) is a language 
   115         -** construct of the relevant type (a command enclosed in [], an escape
   116         -** sequence etc.), these functions determine the number of bytes
   117         -** of the input consumed by the construct. For example:
   118         -**
   119         -**   int nByte;
   120         -**   thNextCommand(interp, "[expr $a+1] $nIter", 18, &nByte);
   121         -**
   122         -** results in variable nByte being set to 11. Or, 
   123         -**
   124         -**   thNextVarname(interp, "$a+1", 4, &nByte);
   125         -**
   126         -** results in nByte being set to 2.
   127         -*/
   128         -static int thNextCommand(Th_Interp*, const char *z, int n, int *pN);
   129         -static int thNextEscape (Th_Interp*, const char *z, int n, int *pN);
   130         -static int thNextVarname(Th_Interp*, const char *z, int n, int *pN);
   131         -static int thNextNumber (Th_Interp*, const char *z, int n, int *pN);
   132         -static int thNextSpace  (Th_Interp*, const char *z, int n, int *pN);
   133         -
   134         -/*
   135         -** Given that the input string (z, n) contains a language construct of
   136         -** the relevant type (a command enclosed in [], an escape sequence 
   137         -** like "\xFF" or a variable reference like "${varname}", perform
   138         -** substitution on the string and store the resulting string in
   139         -** the interpreter result.
   140         -*/
   141         -static int thSubstCommand(Th_Interp*, const char *z, int n);
   142         -static int thSubstEscape (Th_Interp*, const char *z, int n);
   143         -static int thSubstVarname(Th_Interp*, const char *z, int n);
   144         -
   145         -/*
   146         -** Given that there is a th1 word located at the start of the input 
   147         -** string (z, n), determine the length in bytes of that word. If the
   148         -** isCmd argument is non-zero, then an unescaped ";" byte not 
   149         -** located inside of a block or quoted string is considered to mark 
   150         -** the end of the word.
   151         -*/
   152         -static int thNextWord(Th_Interp*, const char *z, int n, int *pN, int isCmd);
   153         -
   154         -/*
   155         -** Perform substitution on the word contained in the input string (z, n).
   156         -** Store the resulting string in the interpreter result.
   157         -*/
   158         -static int thSubstWord(Th_Interp*, const char *z, int n);
   159         -
   160         -/*
   161         -** The Buffer structure and the thBufferXXX() functions are used to make
   162         -** memory allocation easier when building up a result.
   163         -*/
   164         -struct Buffer {
   165         -  char *zBuf;
   166         -  int nBuf;
   167         -  int nBufAlloc;
   168         -};
   169         -typedef struct Buffer Buffer;
   170         -static int  thBufferWrite(Th_Interp *interp, Buffer *, const char *, int);
   171         -static void thBufferInit(Buffer *);
   172         -static void thBufferFree(Th_Interp *interp, Buffer *);
   173         -
   174         -/*
   175         -** Append nAdd bytes of content copied from zAdd to the end of buffer
   176         -** pBuffer. If there is not enough space currently allocated, resize
   177         -** the allocation to make space.
   178         -*/
   179         -static int thBufferWrite(
   180         -  Th_Interp *interp, 
   181         -  Buffer *pBuffer, 
   182         -  const char *zAdd, 
   183         -  int nAdd
   184         -){
   185         -  int nReq;
   186         -
   187         -  if( nAdd<0 ){
   188         -    nAdd = th_strlen(zAdd);
   189         -  }
   190         -  nReq = pBuffer->nBuf+nAdd+1;
   191         -
   192         -  if( nReq>pBuffer->nBufAlloc ){
   193         -    char *zNew;
   194         -    int nNew;
   195         -
   196         -    nNew = nReq*2;
   197         -    zNew = (char *)Th_Malloc(interp, nNew);
   198         -    memcpy(zNew, pBuffer->zBuf, pBuffer->nBuf);
   199         -    Th_Free(interp, pBuffer->zBuf);
   200         -    pBuffer->nBufAlloc = nNew;
   201         -    pBuffer->zBuf = zNew;
   202         -  }
   203         -
   204         -  memcpy(&pBuffer->zBuf[pBuffer->nBuf], zAdd, nAdd);
   205         -  pBuffer->nBuf += nAdd;
   206         -  pBuffer->zBuf[pBuffer->nBuf] = '\0';
   207         -
   208         -  return TH_OK;
   209         -}
   210         -#define thBufferWrite(a,b,c,d) thBufferWrite(a,b,(const char *)c,d)
   211         -
   212         -/*
   213         -** Initialize the Buffer structure pointed to by pBuffer.
   214         -*/
   215         -static void thBufferInit(Buffer *pBuffer){
   216         -  memset(pBuffer, 0, sizeof(Buffer));
   217         -}
   218         -
   219         -/*
   220         -** Zero the buffer pointed to by pBuffer and free the associated memory
   221         -** allocation.
   222         -*/
   223         -static void thBufferFree(Th_Interp *interp, Buffer *pBuffer){
   224         -  Th_Free(interp, pBuffer->zBuf);
   225         -  thBufferInit(pBuffer);
   226         -}
   227         -
   228         -/*
   229         -** Assuming parameter c contains a hexadecimal digit character,
   230         -** return the corresponding value of that digit. If c is not
   231         -** a hexadecimal digit character, -1 is returned.
   232         -*/
   233         -static int thHexdigit(char c){
   234         -  switch (c) {
   235         -    case '0': return 0;
   236         -    case '1': return 1;
   237         -    case '2': return 2;
   238         -    case '3': return 3;
   239         -    case '4': return 4;
   240         -    case '5': return 5;
   241         -    case '6': return 6;
   242         -    case '7': return 7;
   243         -    case '8': return 8;
   244         -    case '9': return 9;
   245         -    case 'a': case 'A': return 10;
   246         -    case 'b': case 'B': return 11;
   247         -    case 'c': case 'C': return 12;
   248         -    case 'd': case 'D': return 13;
   249         -    case 'e': case 'E': return 14;
   250         -    case 'f': case 'F': return 15;
   251         -  }
   252         -  return -1;
   253         -}
   254         -
   255         -/*
   256         -** Argument pEntry points to an entry in a stack frame hash table
   257         -** (Th_Frame.paVar). Decrement the refrerence count of the Th_Variable
   258         -** structure that the entry points to. Free the Th_Variable if its
   259         -** reference count reaches 0.
   260         -**
   261         -** Argument pContext is a pointer to the interpreter structure.
   262         -*/
   263         -static void thFreeVariable(Th_HashEntry *pEntry, void *pContext){
   264         -  Th_Variable *pValue = (Th_Variable *)pEntry->pData;
   265         -  pValue->nRef--;
   266         -  assert( pValue->nRef>=0 );
   267         -  if( pValue->nRef==0 ){
   268         -    Th_Interp *interp = (Th_Interp *)pContext;
   269         -    Th_Free(interp, pValue->zData);
   270         -    if( pValue->pHash ){
   271         -      Th_HashIterate(interp, pValue->pHash, thFreeVariable, pContext);
   272         -      Th_HashDelete(interp, pValue->pHash);
   273         -    }
   274         -    Th_Free(interp, pValue);
   275         -  }
   276         -}
   277         -
   278         -/*
   279         -** Argument pEntry points to an entry in the command hash table
   280         -** (Th_Interp.paCmd). Delete the Th_Command structure that the
   281         -** entry points to.
   282         -**
   283         -** Argument pContext is a pointer to the interpreter structure.
   284         -*/
   285         -static void thFreeCommand(Th_HashEntry *pEntry, void *pContext){
   286         -  Th_Command *pCommand = (Th_Command *)pEntry->pData;
   287         -  if( pCommand->xDel ){
   288         -    pCommand->xDel((Th_Interp *)pContext, pCommand->pContext);
   289         -  }
   290         -  Th_Free((Th_Interp *)pContext, pEntry->pData);
   291         -  pEntry->pData = 0;
   292         -}
   293         -
   294         -/*
   295         -** Push a new frame onto the stack.
   296         -*/
   297         -static int thPushFrame(Th_Interp *interp, Th_Frame *pFrame){
   298         -  pFrame->paVar = Th_HashNew(interp);
   299         -  pFrame->pCaller = interp->pFrame;
   300         -  interp->pFrame = pFrame;
   301         -  return TH_OK;
   302         -}
   303         -
   304         -/*
   305         -** Pop a frame off the top of the stack.
   306         -*/
   307         -static void thPopFrame(Th_Interp *interp){
   308         -  Th_Frame *pFrame = interp->pFrame;
   309         -  Th_HashIterate(interp, pFrame->paVar, thFreeVariable, (void *)interp);
   310         -  Th_HashDelete(interp, pFrame->paVar);
   311         -  interp->pFrame = pFrame->pCaller;
   312         -}
   313         -
   314         -/*
   315         -** The first part of the string (zInput,nInput) contains an escape 
   316         -** sequence. Set *pnEscape to the number of bytes in the escape sequence.
   317         -** If there is a parse error, return TH_ERROR and set the interpreter
   318         -** result to an error message. Otherwise return TH_OK.
   319         -*/
   320         -static int thNextEscape(
   321         -  Th_Interp *interp,
   322         -  const char *zInput, 
   323         -  int nInput, 
   324         -  int *pnEscape
   325         -){
   326         -  int i = 2;
   327         -
   328         -  assert(nInput>0);
   329         -  assert(zInput[0]=='\\');
   330         -
   331         -  if( nInput<=1 ){
   332         -    return TH_ERROR;
   333         -  }
   334         -
   335         -  switch( zInput[1] ){
   336         -    case 'x': i = 4;
   337         -  }
   338         -
   339         -  if( i>nInput ){
   340         -    return TH_ERROR;
   341         -  }
   342         -  *pnEscape = i;
   343         -  return TH_OK;
   344         -}
   345         -
   346         -/*
   347         -** The first part of the string (zInput,nInput) contains a variable
   348         -** reference. Set *pnVarname to the number of bytes in the variable 
   349         -** reference. If there is a parse error, return TH_ERROR and set the 
   350         -** interpreter result to an error message. Otherwise return TH_OK.
   351         -*/
   352         -int thNextVarname(
   353         -  Th_Interp *interp,
   354         -  const char *zInput, 
   355         -  int nInput, 
   356         -  int *pnVarname
   357         -){
   358         -  int i;
   359         -
   360         -  assert(nInput>0);
   361         -  assert(zInput[0]=='$');
   362         -
   363         -  if( nInput>0 && zInput[1]=='{' ){
   364         -    for(i=2; i<nInput && zInput[i]!='}'; i++);
   365         -    if( i==nInput ){
   366         -      return TH_ERROR;
   367         -    }
   368         -    i++;
   369         -  }else{
   370         -    i = 1;
   371         -    if( nInput>2 && zInput[1]==':' && zInput[2]==':' ){
   372         -      i += 2;
   373         -    }
   374         -    for(; i<nInput; i++){
   375         -      if( zInput[i]=='(' ){
   376         -        for(i++; i<nInput; i++){
   377         -          if( zInput[i]==')' ) break;
   378         -          if( zInput[i]=='\\' ) i++;
   379         -          if( zInput[i]=='{' || zInput[i]=='[' || zInput[i]=='"' ){
   380         -            int nWord;
   381         -            int rc = thNextWord(interp, &zInput[i], nInput-i, &nWord, 0);
   382         -            if( rc!=TH_OK ){
   383         -              return rc;
   384         -            }
   385         -            i += nWord;
   386         -          }
   387         -        }
   388         -        if( i>=nInput ){
   389         -          Th_ErrorMessage(interp, "Unmatched brackets:", zInput, nInput);
   390         -          return TH_ERROR;
   391         -        }
   392         -        i++;
   393         -        break;
   394         -      }
   395         -      if( !th_isalnum(zInput[i]) && zInput[i]!='_' ) break;
   396         -    }
   397         -  }
   398         -
   399         -  *pnVarname = i;
   400         -  return TH_OK;
   401         -}
   402         -
   403         -/*
   404         -** The first part of the string (zInput,nInput) contains a command
   405         -** enclosed in a "[]" block. Set *pnCommand to the number of bytes in 
   406         -** the variable reference. If there is a parse error, return TH_ERROR 
   407         -** and set the interpreter result to an error message. Otherwise return 
   408         -** TH_OK.
   409         -*/
   410         -int thNextCommand(
   411         -  Th_Interp *interp,
   412         -  const char *zInput, 
   413         -  int nInput, 
   414         -  int *pnCommand
   415         -){
   416         -  int nBrace = 0;
   417         -  int nSquare = 0;
   418         -  int i;
   419         -
   420         -  assert(nInput>0);
   421         -  assert( zInput[0]=='[' || zInput[0]=='{' );
   422         -
   423         -  for(i=0; i<nInput && (i==0 || nBrace>0 || nSquare>0); i++){
   424         -    switch( zInput[i] ){
   425         -      case '\\': i++; break;
   426         -      case '{': nBrace++; break;
   427         -      case '}': nBrace--; break;
   428         -      case '[': nSquare++; break;
   429         -      case ']': nSquare--; break;
   430         -    }
   431         -  }
   432         -  if( nBrace || nSquare ){
   433         -    return TH_ERROR;
   434         -  }
   435         -
   436         -  *pnCommand = i;
   437         -
   438         -  return TH_OK;
   439         -}
   440         -
   441         -/*
   442         -** Set *pnSpace to the number of whitespace bytes at the start of 
   443         -** input string (zInput, nInput). Always return TH_OK.
   444         -*/
   445         -int thNextSpace(
   446         -  Th_Interp *interp,
   447         -  const char *zInput, 
   448         -  int nInput, 
   449         -  int *pnSpace
   450         -){
   451         -  int i;
   452         -  for(i=0; i<nInput && th_isspace(zInput[i]); i++);
   453         -  *pnSpace = i;
   454         -  return TH_OK;
   455         -}
   456         -
   457         -/*
   458         -** The first byte of the string (zInput,nInput) is not white-space.
   459         -** Set *pnWord to the number of bytes in the th1 word that starts
   460         -** with this byte. If a complete word cannot be parsed or some other
   461         -** error occurs, return TH_ERROR and set the interpreter result to 
   462         -** an error message. Otherwise return TH_OK.
   463         -**
   464         -** If the isCmd argument is non-zero, then an unescaped ";" byte not 
   465         -** located inside of a block or quoted string is considered to mark 
   466         -** the end of the word.
   467         -*/
   468         -static int thNextWord(
   469         -  Th_Interp *interp,
   470         -  const char *zInput, 
   471         -  int nInput, 
   472         -  int *pnWord,
   473         -  int isCmd
   474         -){
   475         -  int iEnd = 0;
   476         -
   477         -  assert( !th_isspace(zInput[0]) );
   478         -
   479         -  if( zInput[0]=='"' ){
   480         -    /* The word is terminated by the next unescaped '"' character. */
   481         -    iEnd++;
   482         -    while( iEnd<nInput && zInput[iEnd]!='"' ){
   483         -      if( zInput[iEnd]=='\\' ){
   484         -        iEnd++;
   485         -      }
   486         -      iEnd++;
   487         -    }
   488         -    iEnd++;
   489         -  }else{
   490         -    int nBrace = 0;
   491         -    int nSq = 0;
   492         -    while( iEnd<nInput && (nBrace>0 || nSq>0 ||
   493         -      (!th_isspace(zInput[iEnd]) && (!isCmd || zInput[iEnd]!=';'))
   494         -    )){
   495         -      switch( zInput[iEnd] ){
   496         -        case '\\': iEnd++; break;
   497         -        case '{': if( nSq==0 ) nBrace++; break;
   498         -        case '}': if( nSq==0 ) nBrace--; break;
   499         -        case '[': if( nBrace==0 ) nSq++; break;
   500         -        case ']': if( nBrace==0 ) nSq--; break;
   501         -      }
   502         -      iEnd++;
   503         -    }
   504         -    if( nBrace>0 || nSq>0 ){
   505         -      /* Parse error */
   506         -      return TH_ERROR;
   507         -    }
   508         -  }
   509         -
   510         -  if( iEnd>nInput ){
   511         -    /* Parse error */
   512         -    return TH_ERROR;
   513         -  }
   514         -  *pnWord = iEnd;
   515         -  return TH_OK;
   516         -}
   517         -
   518         -/*
   519         -** The input string (zWord, nWord) contains a th1 script enclosed in
   520         -** a [] block. Perform substitution on the input string and store the
   521         -** resulting string in the interpreter result.
   522         -*/
   523         -static int thSubstCommand(
   524         -  Th_Interp *interp,
   525         -  const char *zWord,
   526         -  int nWord
   527         -){
   528         -  assert(nWord>=2);
   529         -  assert(zWord[0]=='[' && zWord[nWord-1]==']');
   530         -  return thEvalLocal(interp, &zWord[1], nWord-2);
   531         -}
   532         -
   533         -/*
   534         -** The input string (zWord, nWord) contains a th1 variable reference
   535         -** (a '$' byte followed by a variable name). Perform substitution on 
   536         -** the input string and store the resulting string in the interpreter 
   537         -** result.
   538         -*/
   539         -static int thSubstVarname(
   540         -  Th_Interp *interp,
   541         -  const char *zWord,
   542         -  int nWord
   543         -){
   544         -  assert(nWord>=1);
   545         -  assert(zWord[0]=='$');
   546         -  assert(nWord==1 || zWord[1]!='{' || zWord[nWord-1]=='}');
   547         -  if( nWord>1 && zWord[1]=='{' ){
   548         -    zWord++;
   549         -    nWord -= 2;
   550         -  }else if( zWord[nWord-1]==')' ){
   551         -    int i;
   552         -    for(i=1; i<nWord && zWord[i]!='('; i++);
   553         -    if( i<nWord ){
   554         -      Buffer varname;
   555         -      int nInner;
   556         -      const char *zInner;
   557         -
   558         -      int rc = thSubstWord(interp, &zWord[i+1], nWord-i-2);
   559         -      if( rc!=TH_OK ) return rc;
   560         -
   561         -      zInner = Th_GetResult(interp, &nInner);
   562         -      thBufferInit(&varname);
   563         -      thBufferWrite(interp, &varname, &zWord[1], i);
   564         -      thBufferWrite(interp, &varname, zInner, nInner);
   565         -      thBufferWrite(interp, &varname, ")", 1);
   566         -      rc = Th_GetVar(interp, varname.zBuf, varname.nBuf);
   567         -      thBufferFree(interp, &varname);
   568         -      return rc;
   569         -    }
   570         -  }
   571         -  return Th_GetVar(interp, &zWord[1], nWord-1);
   572         -}
   573         -
   574         -/*
   575         -** The input string (zWord, nWord) contains a th1 escape sequence.
   576         -** Perform substitution on the input string and store the resulting 
   577         -** string in the interpreter result.
   578         -*/
   579         -static int thSubstEscape(
   580         -  Th_Interp *interp,
   581         -  const char *zWord,
   582         -  int nWord
   583         -){
   584         -  char c;
   585         -
   586         -  assert(nWord>=2);
   587         -  assert(zWord[0]=='\\');
   588         -
   589         -  switch( zWord[1] ){
   590         -    case 'x': {
   591         -      assert(nWord==4);
   592         -      c = ((thHexdigit(zWord[2])<<4) + thHexdigit(zWord[3]));
   593         -      break;
   594         -    }
   595         -    case 'n': {
   596         -      c = '\n';
   597         -      break;
   598         -    }
   599         -    default: {
   600         -      assert(nWord==2);
   601         -      c = zWord[1];
   602         -      break;
   603         -    }
   604         -  }
   605         -
   606         -  Th_SetResult(interp, &c, 1);
   607         -  return TH_OK;
   608         -}
   609         -
   610         -/*
   611         -** The input string (zWord, nWord) contains a th1 word. Perform
   612         -** substitution on the input string and store the resulting 
   613         -** string in the interpreter result.
   614         -*/
   615         -static int thSubstWord(
   616         -  Th_Interp *interp,
   617         -  const char *zWord,
   618         -  int nWord
   619         -){
   620         -  int rc = TH_OK;
   621         -  Buffer output;
   622         -  int i;
   623         -
   624         -  thBufferInit(&output);
   625         -
   626         -  if( nWord>1 && (zWord[0]=='{' && zWord[nWord-1]=='}') ){
   627         -    rc = thBufferWrite(interp, &output, &zWord[1], nWord-2);
   628         -  }else{
   629         -
   630         -    /* If the word is surrounded by double-quotes strip these away. */
   631         -    if( nWord>1 && (zWord[0]=='"' && zWord[nWord-1]=='"') ){
   632         -      zWord++;
   633         -      nWord -= 2;
   634         -    }
   635         -
   636         -    for(i=0; rc==TH_OK && i<nWord; i++){
   637         -      int nGet;
   638         -
   639         -      int (*xGet)(Th_Interp *, const char*, int, int *) = 0;
   640         -      int (*xSubst)(Th_Interp *, const char*, int) = 0;
   641         -
   642         -      switch( zWord[i] ){
   643         -        case '\\':
   644         -          xGet = thNextEscape; xSubst = thSubstEscape; 
   645         -          break;
   646         -        case '[':
   647         -          if( !interp->isListMode ){
   648         -            xGet = thNextCommand; xSubst = thSubstCommand; 
   649         -            break;
   650         -          }
   651         -        case '$':
   652         -          if( !interp->isListMode ){
   653         -            xGet = thNextVarname; xSubst = thSubstVarname; 
   654         -            break;
   655         -          }
   656         -        default: {
   657         -          thBufferWrite(interp, &output, &zWord[i], 1);
   658         -          continue; /* Go to the next iteration of the for(...) loop */
   659         -        }
   660         -      }
   661         -
   662         -      rc = xGet(interp, &zWord[i], nWord-i, &nGet);
   663         -      if( rc==TH_OK ){
   664         -        rc = xSubst(interp, &zWord[i], nGet);
   665         -      }
   666         -      if( rc==TH_OK ){
   667         -        const char *zRes;
   668         -        int nRes;
   669         -        zRes = Th_GetResult(interp, &nRes);
   670         -        rc = thBufferWrite(interp, &output, zRes, nRes);
   671         -        i += (nGet-1);
   672         -      }
   673         -    }
   674         -  }
   675         -
   676         -  if( rc==TH_OK ){
   677         -    Th_SetResult(interp, output.zBuf, output.nBuf);
   678         -  }
   679         -  thBufferFree(interp, &output);
   680         -  return rc;
   681         -}
   682         -
   683         -/*
   684         -** Return true if one of the following is true of the buffer pointed
   685         -** to by zInput, length nInput:
   686         -**
   687         -**   + It is empty, or
   688         -**   + It contains nothing but white-space, or
   689         -**   + It contains no non-white-space characters before the first 
   690         -**     newline character.
   691         -**
   692         -** Otherwise return false.
   693         -*/
   694         -static int thEndOfLine(const char *zInput, int nInput){
   695         -  int i;
   696         -  for(i=0; i<nInput && zInput[i]!='\n' && th_isspace(zInput[i]); i++);
   697         -  return ((i==nInput || zInput[i]=='\n')?1:0);
   698         -}
   699         -
   700         -/*
   701         -** This function splits the supplied th1 list (contained in buffer zList,
   702         -** size nList) into elements and performs word-substitution on each
   703         -** element. If the Th_Interp.isListMode variable is true, then only
   704         -** escape sequences are substituted (used by the Th_SplitList() function).
   705         -** If Th_Interp.isListMode is false, then variable and command substitution
   706         -** is also performed (used by Th_Eval()).
   707         -**
   708         -** If zList/nList does not contain a valid list, TH_ERROR is returned
   709         -** and an error message stored in interp.
   710         -**
   711         -** If TH_OK is returned and pazElem is not NULL, the caller should free the
   712         -** pointer written to (*pazElem) using Th_Free(). This releases memory
   713         -** allocated for both the (*pazElem) and (*panElem) arrays. Example:
   714         -**
   715         -**     char **argv;
   716         -**     int *argl;
   717         -**     int argc;
   718         -**
   719         -**     // After this call, argv and argl point to valid arrays. The
   720         -**     // number of elements in each is argc.
   721         -**     //
   722         -**     Th_SplitList(interp, zList, nList, &argv, &argl, &argc);
   723         -**
   724         -**     // Free all memory allocated by Th_SplitList(). The arrays pointed
   725         -**     // to by argv and argl are invalidated by this call.
   726         -**     //
   727         -**     Th_Free(interp, argv);
   728         -**
   729         -*/ 
   730         -static int thSplitList(
   731         -  Th_Interp *interp,      /* Interpreter context */
   732         -  const char *zList,     /* Pointer to buffer containing input list */
   733         -  int nList,              /* Size of buffer pointed to by zList */
   734         -  char ***pazElem,       /* OUT: Array of list elements */
   735         -  int **panElem,          /* OUT: Lengths of each list element */
   736         -  int *pnCount            /* OUT: Number of list elements */
   737         -){
   738         -  int rc = TH_OK;
   739         -
   740         -  Buffer strbuf;
   741         -  Buffer lenbuf;
   742         -  int nCount = 0;
   743         -
   744         -  const char *zInput = zList;
   745         -  int nInput = nList;
   746         -
   747         -  thBufferInit(&strbuf);
   748         -  thBufferInit(&lenbuf);
   749         -
   750         -  while( nInput>0 ){
   751         -    const char *zWord;
   752         -    int nWord;
   753         -
   754         -    thNextSpace(interp, zInput, nInput, &nWord);
   755         -    zInput += nWord;
   756         -    nInput = nList-(zInput-zList);
   757         -
   758         -    if( TH_OK!=(rc = thNextWord(interp, zInput, nInput, &nWord, 0))
   759         -     || TH_OK!=(rc = thSubstWord(interp, zInput, nWord))
   760         -    ){
   761         -      goto finish;
   762         -    }
   763         -    zInput = &zInput[nWord];
   764         -    nInput = nList-(zInput-zList);
   765         -    if( nWord>0 ){
   766         -      zWord = Th_GetResult(interp, &nWord);
   767         -      thBufferWrite(interp, &strbuf, zWord, nWord);
   768         -      thBufferWrite(interp, &strbuf, "\0", 1);
   769         -      thBufferWrite(interp, &lenbuf, &nWord, sizeof(int));
   770         -      nCount++;
   771         -    }
   772         -  }
   773         -  assert((lenbuf.nBuf/sizeof(int))==nCount);
   774         -
   775         -  assert((pazElem && panElem) || (!pazElem && !panElem));
   776         -  if( pazElem && rc==TH_OK ){
   777         -    int i;
   778         -    char *zElem; 
   779         -    int *anElem;
   780         -    char **azElem = Th_Malloc(interp,
   781         -      sizeof(char*) * nCount +      /* azElem */
   782         -      sizeof(int) * nCount +         /* anElem */
   783         -      strbuf.nBuf                    /* space for list element strings */
   784         -    );
   785         -    anElem = (int *)&azElem[nCount];
   786         -    zElem = (char *)&anElem[nCount];
   787         -    memcpy(anElem, lenbuf.zBuf, lenbuf.nBuf);
   788         -    memcpy(zElem, strbuf.zBuf, strbuf.nBuf);
   789         -    for(i=0; i<nCount;i++){
   790         -      azElem[i] = zElem;
   791         -      zElem += (anElem[i] + 1);
   792         -    }
   793         -    *pazElem = azElem;
   794         -    *panElem = anElem;
   795         -  }
   796         -  if( pnCount ){
   797         -    *pnCount = nCount;
   798         -  }
   799         -  
   800         - finish:
   801         -  thBufferFree(interp, &strbuf);
   802         -  thBufferFree(interp, &lenbuf);
   803         -  return rc;
   804         -}
   805         -
   806         -/*
   807         -** Evaluate the th1 script contained in the string (zProgram, nProgram)
   808         -** in the current stack frame.
   809         -*/
   810         -static int thEvalLocal(Th_Interp *interp, const char *zProgram, int nProgram){
   811         -  int rc = TH_OK;
   812         -  const char *zInput = zProgram;
   813         -  int nInput = nProgram;
   814         -
   815         -  while( rc==TH_OK && nInput ){
   816         -    Th_HashEntry *pEntry;
   817         -    int nSpace;
   818         -    const char *zFirst;
   819         -
   820         -    char **argv;
   821         -    int *argl;
   822         -    int argc;
   823         -
   824         -    assert(nInput>=0);
   825         -
   826         -    /* Skip a semi-colon */
   827         -    if( *zInput==';' ){
   828         -      zInput++;
   829         -      nInput--;
   830         -    }
   831         -
   832         -    /* Skip past leading white-space. */
   833         -    thNextSpace(interp, zInput, nInput, &nSpace);
   834         -    zInput += nSpace;
   835         -    nInput -= nSpace;
   836         -    zFirst = zInput;
   837         -
   838         -    /* Check for a comment. If found, skip to the end of the line. */
   839         -    if( zInput[0]=='#' ){
   840         -      while( !thEndOfLine(zInput, nInput) ){
   841         -        zInput++;
   842         -        nInput--;
   843         -      }
   844         -      continue;
   845         -    }
   846         -
   847         -    /* Gobble up input a word at a time until the end of the command
   848         -    ** (a semi-colon or end of line).
   849         -    */
   850         -    while( rc==TH_OK && *zInput!=';' && !thEndOfLine(zInput, nInput) ){
   851         -      int nWord=0;
   852         -      thNextSpace(interp, zInput, nInput, &nSpace);
   853         -      rc = thNextWord(interp, &zInput[nSpace], nInput-nSpace, &nWord, 1);
   854         -      zInput += (nSpace+nWord);
   855         -      nInput -= (nSpace+nWord);
   856         -    }
   857         -    if( rc!=TH_OK ) continue;
   858         -
   859         -    /* Split the command into an array of words. This call also does
   860         -    ** substitution of each individual word.
   861         -    */
   862         -    rc = thSplitList(interp, zFirst, zInput-zFirst, &argv, &argl, &argc);
   863         -    if( rc!=TH_OK ) continue;
   864         -
   865         -    if( argc>0 ){
   866         -
   867         -      /* Look up the command name in the command hash-table. */
   868         -      pEntry = Th_HashFind(interp, interp->paCmd, argv[0], argl[0], 0);
   869         -      if( !pEntry ){
   870         -        Th_ErrorMessage(interp, "no such command: ", argv[0], argl[0]);
   871         -        rc = TH_ERROR;
   872         -      }
   873         -
   874         -      /* Call the command procedure. */
   875         -      if( rc==TH_OK ){
   876         -        Th_Command *p = (Th_Command *)(pEntry->pData);
   877         -        const char **azArg = (const char **)argv;
   878         -        rc = p->xProc(interp, p->pContext, argc, azArg, argl);
   879         -      }
   880         -  
   881         -      /* If an error occured, add this command to the stack trace report. */
   882         -      if( rc==TH_ERROR ){
   883         -        char *zRes;
   884         -        int nRes;
   885         -        char *zStack = 0;
   886         -        int nStack = 0;
   887         -  
   888         -        zRes = Th_TakeResult(interp, &nRes);
   889         -        if( TH_OK==Th_GetVar(interp, (char *)"::th_stack_trace", -1) ){
   890         -          zStack = Th_TakeResult(interp, &nStack);
   891         -        }
   892         -        Th_ListAppend(interp, &zStack, &nStack, zFirst, zInput-zFirst);
   893         -        Th_SetVar(interp, (char *)"::th_stack_trace", -1, zStack, nStack);
   894         -        Th_SetResult(interp, zRes, nRes);
   895         -        Th_Free(interp, zRes);
   896         -        Th_Free(interp, zStack);
   897         -      }
   898         -    }
   899         -
   900         -    Th_Free(interp, argv);
   901         -  }
   902         -
   903         -  return rc;
   904         -}
   905         -
   906         -/*
   907         -** Interpret an integer frame identifier passed to either Th_Eval() or
   908         -** Th_LinkVar(). If successful, return a pointer to the identified
   909         -** Th_Frame structure. If unsuccessful (no such frame), return 0 and
   910         -** leave an error message in the interpreter result.
   911         -**
   912         -** Argument iFrame is interpreted as follows:
   913         -**
   914         -**   * If iFrame is 0, this means the current frame.
   915         -**
   916         -**   * If iFrame is negative, then the nth frame up the stack, where 
   917         -**     n is the absolute value of iFrame. A value of -1 means the 
   918         -**     calling procedure.
   919         -**
   920         -**   * If iFrame is +ve, then the nth frame from the bottom of the 
   921         -**     stack. An iFrame value of 1 means the toplevel (global) frame.
   922         -*/
   923         -static Th_Frame *getFrame(Th_Interp *interp, int iFrame){
   924         -  Th_Frame *p = interp->pFrame;
   925         -  int i;
   926         -  if( iFrame>0 ){
   927         -    for(i=0; p; i++){
   928         -      p = p->pCaller;
   929         -    }
   930         -    iFrame = (i*-1) + iFrame;
   931         -    p = interp->pFrame;
   932         -  }
   933         -  for(i=0; p && i<(iFrame*-1); i++){
   934         -    p = p->pCaller;
   935         -  }
   936         -
   937         -  if( !p ){
   938         -    char *zFrame;
   939         -    int nFrame;
   940         -    Th_SetResultInt(interp, iFrame);
   941         -    zFrame = Th_TakeResult(interp, &nFrame);
   942         -    Th_ErrorMessage(interp, "no such frame:", zFrame, nFrame);
   943         -    Th_Free(interp, zFrame);
   944         -  }
   945         -  return p;
   946         -}
   947         -
   948         -
   949         -/*
   950         -** Evaluate th1 script (zProgram, nProgram) in the frame identified by
   951         -** argument iFrame. Leave either an error message or a result in the
   952         -** interpreter result and return a th1 error code (TH_OK, TH_ERROR, 
   953         -** TH_RETURN, TH_CONTINUE or TH_BREAK).
   954         -*/
   955         -int Th_Eval(Th_Interp *interp, int iFrame, const char *zProgram, int nProgram){
   956         -  int rc = TH_OK;
   957         -  Th_Frame *pSavedFrame = interp->pFrame;
   958         -
   959         -  /* Set Th_Interp.pFrame to the frame that this script is to be 
   960         -  ** evaluated in. The current frame is saved in pSavedFrame and will
   961         -  ** be restored before this function returns.
   962         -  */
   963         -  interp->pFrame = getFrame(interp, iFrame);
   964         -
   965         -  if( !interp->pFrame ){
   966         -    rc = TH_ERROR;
   967         -  }else{
   968         -    int nInput = nProgram;
   969         -  
   970         -    if( nInput<0 ){
   971         -      nInput = th_strlen(zProgram);
   972         -    }
   973         -    rc = thEvalLocal(interp, zProgram, nInput);
   974         -  }
   975         -
   976         -  interp->pFrame = pSavedFrame;
   977         -  return rc;
   978         -}
   979         -
   980         -/*
   981         -** Input string (zVarname, nVarname) contains a th1 variable name. It
   982         -** may be a simple scalar variable name or it may be a reference
   983         -** to an array member. The variable name may or may not begin with
   984         -** "::", indicating that the name refers to a global variable, not
   985         -** a local scope one.
   986         -**
   987         -** This function inspects and categorizes the supplied variable name.
   988         -**
   989         -** If the name is a global reference, *pisGlobal is set to true. Otherwise
   990         -** false. Output string (*pzOuter, *pnOuter) is set to the variable name
   991         -** if it is a scalar reference, or the name of the array if it is an
   992         -** array variable. If the variable is a scalar, *pzInner is set to 0.
   993         -** If it is an array variable, (*pzInner, *pnInner) is set to the
   994         -** array key name.
   995         -*/
   996         -static int thAnalyseVarname(
   997         -  const char *zVarname,
   998         -  int nVarname,
   999         -  const char **pzOuter,     /* OUT: Pointer to scalar/array name */
  1000         -  int *pnOuter,              /* OUT: Number of bytes at *pzOuter */
  1001         -  const char **pzInner,     /* OUT: Pointer to array key (or null) */
  1002         -  int *pnInner,              /* OUT: Number of bytes at *pzInner */
  1003         -  int *pisGlobal             /* OUT: Set to true if this is a global ref */
  1004         -){
  1005         -  const char *zOuter = zVarname;
  1006         -  int nOuter;
  1007         -  const char *zInner = 0;
  1008         -  int nInner = 0;
  1009         -  int isGlobal = 0;
  1010         -  int i;
  1011         -
  1012         -  if( nVarname<0 ){
  1013         -    nVarname = th_strlen(zVarname);
  1014         -  }
  1015         -  nOuter = nVarname;
  1016         -
  1017         -  /* If the variable name starts with "::", then do the lookup is in the
  1018         -  ** uppermost (global) frame.
  1019         -  */
  1020         -  if( nVarname>2 && zVarname[0]==':' && zVarname[1]==':' ){
  1021         -    zOuter += 2;
  1022         -    nOuter -= 2;
  1023         -    isGlobal = 1;
  1024         -  }
  1025         -
  1026         -  /* Check if this is an array reference. */
  1027         -  if( zOuter[nOuter-1]==')' ){
  1028         -    for(i=0; i<nOuter; i++){
  1029         -      if( zOuter[i]=='(' ){
  1030         -        zInner = &zOuter[i+1];
  1031         -        nInner = nOuter-i-2;
  1032         -        nOuter = i;
  1033         -        break;
  1034         -      }
  1035         -    }
  1036         -  }
  1037         -
  1038         -  *pzOuter = zOuter;
  1039         -  *pnOuter = nOuter;
  1040         -  *pzInner = zInner;
  1041         -  *pnInner = nInner;
  1042         -  *pisGlobal = isGlobal;
  1043         -  return TH_OK;
  1044         -}
  1045         -
  1046         -/*
  1047         -** Input string (zVar, nVar) contains a variable name. This function locates
  1048         -** the Th_Variable structure associated with the named variable. The 
  1049         -** variable name may be a global or local scalar or array variable
  1050         -**
  1051         -** If the create argument is non-zero and the named variable does not exist
  1052         -** it is created. Otherwise, an error is left in the interpreter result
  1053         -** and NULL returned.
  1054         -**
  1055         -** If the arrayok argument is false and the named variable is an array,
  1056         -** an error is left in the interpreter result and NULL returned. If
  1057         -** arrayok is true an array name is Ok.
  1058         -*/
  1059         -static Th_Variable *thFindValue(
  1060         -  Th_Interp *interp,
  1061         -  const char *zVar,     /* Pointer to variable name */
  1062         -  int nVar,              /* Number of bytes at nVar */
  1063         -  int create,            /* If true, create the variable if not found */
  1064         -  int arrayok            /* If true, an array is Ok. Othewise array==error */
  1065         -){
  1066         -  const char *zOuter;
  1067         -  int nOuter;
  1068         -  const char *zInner;
  1069         -  int nInner;
  1070         -  int isGlobal;
  1071         -
  1072         -  Th_HashEntry *pEntry;
  1073         -  Th_Frame *pFrame = interp->pFrame;
  1074         -  Th_Variable *pValue;
  1075         -
  1076         -  thAnalyseVarname(zVar, nVar, &zOuter, &nOuter, &zInner, &nInner, &isGlobal);
  1077         -  if( isGlobal ){
  1078         -    while( pFrame->pCaller ) pFrame = pFrame->pCaller;
  1079         -  }
  1080         -
  1081         -  pEntry = Th_HashFind(interp, pFrame->paVar, zOuter, nOuter, create);
  1082         -  assert(pEntry || !create);
  1083         -  if( !pEntry ){
  1084         -    goto no_such_var;
  1085         -  }
  1086         -
  1087         -  pValue = (Th_Variable *)pEntry->pData;
  1088         -  if( !pValue ){
  1089         -    assert(create);
  1090         -    pValue = Th_Malloc(interp, sizeof(Th_Variable));
  1091         -    pValue->nRef = 1;
  1092         -    pEntry->pData = (void *)pValue;
  1093         -  }
  1094         -
  1095         -  if( zInner ){
  1096         -    if( pValue->zData ){
  1097         -      Th_ErrorMessage(interp, "variable is a scalar:", zOuter, nOuter);
  1098         -      return 0;
  1099         -    }
  1100         -    if( !pValue->pHash ){
  1101         -      if( !create ){
  1102         -        goto no_such_var;
  1103         -      }
  1104         -      pValue->pHash = Th_HashNew(interp);
  1105         -    }
  1106         -    pEntry = Th_HashFind(interp, pValue->pHash, zInner, nInner, create);
  1107         -    if( !pEntry ){
  1108         -      goto no_such_var;
  1109         -    }
  1110         -    pValue = (Th_Variable *)pEntry->pData;
  1111         -    if( !pValue ){
  1112         -      assert(create);
  1113         -      pValue = Th_Malloc(interp, sizeof(Th_Variable));
  1114         -      pValue->nRef = 1;
  1115         -      pEntry->pData = (void *)pValue;
  1116         -    }
  1117         -  }else{
  1118         -    if( pValue->pHash && !arrayok ){
  1119         -      Th_ErrorMessage(interp, "variable is an array:", zOuter, nOuter);
  1120         -      return 0;
  1121         -    }
  1122         -  }
  1123         -
  1124         -  return pValue;
  1125         -
  1126         -no_such_var:
  1127         -  Th_ErrorMessage(interp, "no such variable:", zVar, nVar);
  1128         -  return 0;
  1129         -}
  1130         -
  1131         -/*
  1132         -** String (zVar, nVar) must contain the name of a scalar variable or 
  1133         -** array member. Look up the variable, store its current value in 
  1134         -** the interpreter result and return TH_OK.
  1135         -**
  1136         -** If the named variable does not exist, return TH_ERROR and leave
  1137         -** an error message in the interpreter result.
  1138         -*/
  1139         -int Th_GetVar(Th_Interp *interp, const char *zVar, int nVar){
  1140         -  Th_Variable *pValue;
  1141         -
  1142         -  pValue = thFindValue(interp, zVar, nVar, 0, 0);
  1143         -  if( !pValue ){
  1144         -    return TH_ERROR;
  1145         -  }
  1146         -  if( !pValue->zData ){
  1147         -    Th_ErrorMessage(interp, "no such variable:", zVar, nVar);
  1148         -    return TH_ERROR;
  1149         -  }
  1150         -
  1151         -  return Th_SetResult(interp, pValue->zData, pValue->nData);
  1152         -}
  1153         -
  1154         -/*
  1155         -** String (zVar, nVar) must contain the name of a scalar variable or
  1156         -** array member. If the variable does not exist it is created. The
  1157         -** variable is set to the value supplied in string (zValue, nValue).
  1158         -**
  1159         -** If (zVar, nVar) refers to an existing array, TH_ERROR is returned
  1160         -** and an error message left in the interpreter result.
  1161         -*/
  1162         -int Th_SetVar(
  1163         -  Th_Interp *interp, 
  1164         -  const char *zVar, 
  1165         -  int nVar,
  1166         -  const char *zValue,
  1167         -  int nValue
  1168         -){
  1169         -  Th_Variable *pValue;
  1170         -
  1171         -  pValue = thFindValue(interp, zVar, nVar, 1, 0);
  1172         -  if( !pValue ){
  1173         -    return TH_ERROR;
  1174         -  }
  1175         -
  1176         -  if( nValue<0 ){
  1177         -    nValue = th_strlen(zValue);
  1178         -  }
  1179         -  if( pValue->zData ){
  1180         -    Th_Free(interp, pValue->zData);
  1181         -    pValue->zData = 0;
  1182         -  }
  1183         -
  1184         -  assert(zValue || nValue==0);
  1185         -  pValue->zData = Th_Malloc(interp, nValue+1);
  1186         -  pValue->zData[nValue] = '\0';
  1187         -  memcpy(pValue->zData, zValue, nValue);
  1188         -  pValue->nData = nValue;
  1189         -
  1190         -  return TH_OK;
  1191         -}
  1192         -
  1193         -/*
  1194         -** Create a variable link so that accessing variable (zLocal, nLocal) is
  1195         -** the same as accessing variable (zLink, nLink) in stack frame iFrame.
  1196         -*/
  1197         -int Th_LinkVar(
  1198         -  Th_Interp *interp,                 /* Interpreter */
  1199         -  const char *zLocal, int nLocal,   /* Local varname */
  1200         -  int iFrame,                        /* Stack frame of linked var */
  1201         -  const char *zLink, int nLink      /* Linked varname */
  1202         -){
  1203         -  Th_Frame *pSavedFrame = interp->pFrame;
  1204         -  Th_Frame *pFrame;
  1205         -  Th_HashEntry *pEntry;
  1206         -  Th_Variable *pValue;
  1207         -
  1208         -  pFrame = getFrame(interp, iFrame);
  1209         -  if( !pFrame ){
  1210         -    return TH_ERROR;
  1211         -  }
  1212         -  pSavedFrame = interp->pFrame;
  1213         -  interp->pFrame = pFrame;
  1214         -  pValue = thFindValue(interp, zLink, nLink, 1, 1);
  1215         -  interp->pFrame = pSavedFrame;
  1216         -
  1217         -  pEntry = Th_HashFind(interp, interp->pFrame->paVar, zLocal, nLocal, 1);
  1218         -  if( pEntry->pData ){
  1219         -    Th_ErrorMessage(interp, "variable exists:", zLocal, nLocal);
  1220         -    return TH_ERROR;
  1221         -  }
  1222         -  pEntry->pData = (void *)pValue;
  1223         -  pValue->nRef++;
  1224         -
  1225         -  return TH_OK;
  1226         -}
  1227         -
  1228         -/*
  1229         -** Input string (zVar, nVar) must contain the name of a scalar variable,
  1230         -** an array, or an array member. If the identified variable exists, it
  1231         -** is deleted and TH_OK returned. Otherwise, an error message is left
  1232         -** in the interpreter result and TH_ERROR is returned.
  1233         -*/
  1234         -int Th_UnsetVar(Th_Interp *interp, const char *zVar, int nVar){
  1235         -  Th_Variable *pValue;
  1236         -
  1237         -  pValue = thFindValue(interp, zVar, nVar, 1, 1);
  1238         -  if( !pValue ){
  1239         -    return TH_ERROR;
  1240         -  }
  1241         -
  1242         -  Th_Free(interp, pValue->zData);
  1243         -  pValue->zData = 0;
  1244         -  if( pValue->pHash ){
  1245         -    Th_HashIterate(interp, pValue->pHash, thFreeVariable, (void *)interp);
  1246         -    Th_HashDelete(interp, pValue->pHash);
  1247         -    pValue->pHash = 0;
  1248         -  }
  1249         -  return TH_OK;
  1250         -}
  1251         -
  1252         -/*
  1253         -** Return an allocated buffer containing a copy of string (z, n). The
  1254         -** caller is responsible for eventually calling Th_Free() to free
  1255         -** the returned buffer.
  1256         -*/
  1257         -char *th_strdup(Th_Interp *interp, const char *z, int n){
  1258         -  char *zRes;
  1259         -  if( n<0 ){
  1260         -    n = th_strlen(z);
  1261         -  }
  1262         -  zRes = Th_Malloc(interp, n+1);
  1263         -  memcpy(zRes, z, n);
  1264         -  zRes[n] = '\0';
  1265         -  return zRes;
  1266         -}
  1267         -
  1268         -/*
  1269         -** Argument zPre must be a nul-terminated string. Set the interpreter
  1270         -** result to a string containing the contents of zPre, followed by
  1271         -** a space (" ") character, followed by a copy of string (z, n).
  1272         -**
  1273         -** In other words, the equivalent of:
  1274         -*
  1275         -**     printf("%s %.*s", zPre, n, z);
  1276         -**
  1277         -** Example:
  1278         -**
  1279         -**     Th_ErrorMessage(interp, "no such variable:", zVarname, nVarname);
  1280         -**
  1281         -*/
  1282         -int Th_ErrorMessage(Th_Interp *interp, const char *zPre, const char *z, int n){
  1283         -  if( interp ){
  1284         -    char *zRes = 0;
  1285         -    int nRes = 0;
  1286         -
  1287         -    Th_SetVar(interp, (char *)"::th_stack_trace", -1, 0, 0);
  1288         -  
  1289         -    Th_StringAppend(interp, &zRes, &nRes, zPre, -1);
  1290         -    if( zRes[nRes-1]=='"' ){
  1291         -      Th_StringAppend(interp, &zRes, &nRes, z, n);
  1292         -      Th_StringAppend(interp, &zRes, &nRes, (const char *)"\"", 1);
  1293         -    }else{
  1294         -      Th_StringAppend(interp, &zRes, &nRes, (const char *)" ", 1);
  1295         -      Th_StringAppend(interp, &zRes, &nRes, z, n);
  1296         -    }
  1297         -
  1298         -    Th_SetResult(interp, zRes, nRes);
  1299         -    Th_Free(interp, zRes);
  1300         -  }
  1301         -
  1302         -  return TH_OK;
  1303         -}
  1304         -
  1305         -/*
  1306         -** Set the current interpreter result by taking a copy of the buffer
  1307         -** pointed to by z, size n bytes. TH_OK is always returned.
  1308         -*/
  1309         -int Th_SetResult(Th_Interp *pInterp, const char *z, int n){
  1310         -
  1311         -  /* Free the current result */
  1312         -  Th_Free(pInterp, pInterp->zResult);
  1313         -  pInterp->zResult = 0;
  1314         -  pInterp->nResult = 0;
  1315         -
  1316         -  if( n<0 ){
  1317         -    n = th_strlen(z);
  1318         -  }
  1319         -
  1320         -  if( z && n>0 ){
  1321         -    char *zResult;
  1322         -    zResult = Th_Malloc(pInterp, n+1);
  1323         -    memcpy(zResult, z, n);
  1324         -    zResult[n] = '\0';
  1325         -    pInterp->zResult = zResult;
  1326         -    pInterp->nResult = n;
  1327         -  }
  1328         -
  1329         -  return TH_OK;
  1330         -}
  1331         -
  1332         -/*
  1333         -** Return a pointer to the buffer containing the current interpreter
  1334         -** result. If pN is not NULL, set *pN to the size of the returned
  1335         -** buffer.
  1336         -*/
  1337         -const char *Th_GetResult(Th_Interp *pInterp, int *pN){
  1338         -  assert(pInterp->zResult || pInterp->nResult==0);
  1339         -  if( pN ){
  1340         -    *pN = pInterp->nResult;
  1341         -  }
  1342         -  return (pInterp->zResult ? pInterp->zResult : (const char *)"");
  1343         -}
  1344         -
  1345         -/*
  1346         -** Return a pointer to the buffer containing the current interpreter
  1347         -** result. If pN is not NULL, set *pN to the size of the returned
  1348         -** buffer.
  1349         -**
  1350         -** This function is the same as Th_GetResult() except that the
  1351         -** caller is responsible for eventually calling Th_Free() on the
  1352         -** returned buffer. The internal interpreter result is cleared
  1353         -** after this function is called.
  1354         -*/
  1355         -char *Th_TakeResult(Th_Interp *pInterp, int *pN){
  1356         -  if( pN ){
  1357         -    *pN = pInterp->nResult;
  1358         -  }
  1359         -  if( pInterp->zResult ){
  1360         -    char *zResult = pInterp->zResult;
  1361         -    pInterp->zResult = 0;
  1362         -    pInterp->nResult = 0;
  1363         -    return zResult;
  1364         -  }else{
  1365         -    return (char *)Th_Malloc(pInterp, 1);
  1366         -  }
  1367         -}
  1368         -
  1369         -
  1370         -/* 
  1371         -** Wrappers around the supplied malloc() and free() 
  1372         -*/
  1373         -void *Th_Malloc(Th_Interp *pInterp, int nByte){
  1374         -  void *p = pInterp->pVtab->xMalloc(nByte);
  1375         -  if( p ){
  1376         -    memset(p, 0, nByte);
  1377         -  }
  1378         -  return p;
  1379         -}
  1380         -void Th_Free(Th_Interp *pInterp, void *z){
  1381         -  if( z ){
  1382         -    pInterp->pVtab->xFree(z);
  1383         -  }
  1384         -}
  1385         -
  1386         -/*
  1387         -** Install a new th1 command. 
  1388         -**
  1389         -** If a command of the same name already exists, it is deleted automatically.
  1390         -*/
  1391         -int Th_CreateCommand(
  1392         -  Th_Interp *interp, 
  1393         -  const char *zName,                 /* New command name */
  1394         -  Th_CommandProc xProc,              /* Command callback proc */
  1395         -  void *pContext,                    /* Value to pass as second arg to xProc */
  1396         -  void (*xDel)(Th_Interp *, void *)  /* Command destructor callback */
  1397         -){
  1398         -  Th_HashEntry *pEntry;
  1399         -  Th_Command *pCommand;
  1400         -
  1401         -  pEntry = Th_HashFind(interp, interp->paCmd, (const char *)zName, -1, 1);
  1402         -  if( pEntry->pData ){
  1403         -    pCommand = pEntry->pData;
  1404         -    if( pCommand->xDel ){
  1405         -      pCommand->xDel(interp, pCommand->pContext);
  1406         -    }
  1407         -  }else{
  1408         -    pCommand = Th_Malloc(interp, sizeof(Th_Command));
  1409         -  }
  1410         -  pCommand->xProc = xProc;
  1411         -  pCommand->pContext = pContext;
  1412         -  pCommand->xDel = xDel;
  1413         -  pEntry->pData = (void *)pCommand;
  1414         - 
  1415         -  return TH_OK;
  1416         -}
  1417         -
  1418         -/*
  1419         -** Rename the existing command (zName, nName) to (zNew, nNew). If nNew is 0, 
  1420         -** the command is deleted instead of renamed.
  1421         -**
  1422         -** If successful, TH_OK is returned. If command zName does not exist, or
  1423         -** if command zNew already exists, an error message is left in the 
  1424         -** interpreter result and TH_ERROR is returned.
  1425         -*/
  1426         -int Th_RenameCommand(
  1427         -  Th_Interp *interp, 
  1428         -  const char *zName,            /* Existing command name */
  1429         -  int nName,                     /* Number of bytes at zName */
  1430         -  const char *zNew,             /* New command name */
  1431         -  int nNew                       /* Number of bytes at zNew */
  1432         -){
  1433         -  Th_HashEntry *pEntry;
  1434         -  Th_HashEntry *pNewEntry;
  1435         -
  1436         -  pEntry = Th_HashFind(interp, interp->paCmd, zName, nName, 0);
  1437         -  if( !pEntry ){
  1438         -    Th_ErrorMessage(interp, "no such command:", zName, nName);
  1439         -    return TH_ERROR;
  1440         -  }
  1441         -  assert(pEntry->pData);
  1442         -
  1443         -  if( nNew>0 ){
  1444         -    pNewEntry = Th_HashFind(interp, interp->paCmd, zNew, nNew, 1);
  1445         -    if( pNewEntry->pData ){
  1446         -      Th_ErrorMessage(interp, "command exists:", zNew, nNew);
  1447         -      return TH_ERROR;
  1448         -    }
  1449         -    pNewEntry->pData = pEntry->pData;
  1450         -  }else{
  1451         -    Th_Command *pCommand = (Th_Command *)(pEntry->pData);
  1452         -    if( pCommand->xDel ){
  1453         -      pCommand->xDel(interp, pCommand->pContext);
  1454         -    }
  1455         -    Th_Free(interp, pCommand);
  1456         -  }
  1457         -
  1458         -  Th_HashFind(interp, interp->paCmd, zName, nName, -1);
  1459         -  return TH_OK;
  1460         -}
  1461         -
  1462         -/*
  1463         -** Push a stack frame onto the interpreter stack, invoke the
  1464         -** callback, and pop the frame back off again. See the implementation
  1465         -** of [proc] (th_lang.c) for an example.
  1466         -*/
  1467         -int Th_InFrame(Th_Interp *interp,
  1468         -  int (*xCall)(Th_Interp *, void *pContext1, void *pContext2),
  1469         -  void *pContext1,
  1470         -  void *pContext2
  1471         -){
  1472         -  Th_Frame frame;
  1473         -  int rc;
  1474         -  thPushFrame(interp, &frame);
  1475         -  rc = xCall(interp, pContext1, pContext2);
  1476         -  thPopFrame(interp);
  1477         -  return rc;
  1478         -}
  1479         -
  1480         -/*
  1481         -** Split a th1 list into its component elements. The list to split is
  1482         -** passed via arguments (zList, nList). If successful, TH_OK is returned.
  1483         -** If an error occurs (if (zList, nList) is not a valid list) an error
  1484         -** message is left in the interpreter result and TH_ERROR returned.
  1485         -**
  1486         -** If successful, *pnCount is set to the number of elements in the list.
  1487         -** panElem is set to point at an array of *pnCount integers - the lengths
  1488         -** of the element values. *pazElem is set to point at an array of 
  1489         -** pointers to buffers containing the array element's data.
  1490         -**
  1491         -** To free the arrays allocated at *pazElem and *panElem, the caller
  1492         -** should call Th_Free() on *pazElem only. Exactly one such call to
  1493         -** Th_Free() must be made per call to Th_SplitList().
  1494         -**
  1495         -** Example:
  1496         -**
  1497         -**     int nElem;
  1498         -**     int *anElem;
  1499         -**     char **azElem;
  1500         -**     int i;
  1501         -**
  1502         -**     Th_SplitList(interp, zList, nList, &azElem, &anElem, &nElem);
  1503         -**     for(i=0; i<nElem; i++){
  1504         -**       int nData = anElem[i];
  1505         -**       char *zData = azElem[i];
  1506         -**       ...
  1507         -**     }
  1508         -**
  1509         -**     Th_Free(interp, azElem);
  1510         -**
  1511         -*/
  1512         -int Th_SplitList(
  1513         -  Th_Interp *interp,
  1514         -  const char *zList,             /* Pointer to buffer containing list */
  1515         -  int nList,                      /* Number of bytes at zList */
  1516         -  char ***pazElem,               /* OUT: Array of pointers to element data */
  1517         -  int **panElem,                  /* OUT: Array of element data lengths */
  1518         -  int *pnCount                    /* OUT: Number of elements in list */
  1519         -){
  1520         -  int rc;
  1521         -  interp->isListMode = 1;
  1522         -  rc = thSplitList(interp, zList, nList, pazElem, panElem, pnCount);
  1523         -  interp->isListMode = 0;
  1524         -  if( rc ){
  1525         -    Th_ErrorMessage(interp, "Expected list, got: \"", zList, nList);
  1526         -  }
  1527         -  return rc;
  1528         -}
  1529         -
  1530         -/*
  1531         -** Append a new element to an existing th1 list. The element to append 
  1532         -** to the list is (zElem, nElem).
  1533         -**
  1534         -** A pointer to the existing list must be stored at *pzList when this
  1535         -** function is called. The length must be stored in *pnList. The value 
  1536         -** of *pzList must either be NULL (in which case *pnList must be 0), or 
  1537         -** a pointer to memory obtained from Th_Malloc().
  1538         -**
  1539         -** This function calls Th_Free() to free the buffer at *pzList and sets
  1540         -** *pzList to point to a new buffer containing the new list value. *pnList
  1541         -** is similarly updated before returning. The return value is always TH_OK.
  1542         -**
  1543         -** Example:
  1544         -**
  1545         -**     char *zList = 0;
  1546         -**     int nList = 0;
  1547         -**     for (...) {
  1548         -**       char *zElem = <some expression>;
  1549         -**       Th_ListAppend(interp, &zList, &nList, zElem, -1);
  1550         -**     }
  1551         -**     Th_SetResult(interp, zList, nList);
  1552         -**     Th_Free(interp, zList);
  1553         -**
  1554         -*/
  1555         -int Th_ListAppend(
  1556         -  Th_Interp *interp,           /* Interpreter context */
  1557         -  char **pzList,              /* IN/OUT: Ptr to ptr to list */
  1558         -  int *pnList,                 /* IN/OUT: Current length of *pzList */
  1559         -  const char *zElem,          /* Data to append */
  1560         -  int nElem                    /* Length of nElem */
  1561         -){
  1562         -  Buffer output;
  1563         -  int i;
  1564         -
  1565         -  int hasSpecialChar = 0;
  1566         -  int hasEscapeChar = 0;
  1567         -  int nBrace = 0;
  1568         -
  1569         -  output.zBuf = *pzList;
  1570         -  output.nBuf = *pnList;
  1571         -  output.nBufAlloc = output.nBuf;
  1572         -
  1573         -  if( nElem<0 ){
  1574         -    nElem = th_strlen(zElem);
  1575         -  }
  1576         -  if( output.nBuf>0 ){
  1577         -    thBufferWrite(interp, &output, " ", 1);
  1578         -  }
  1579         -
  1580         -  for(i=0; i<nElem; i++){
  1581         -    char c = zElem[i];
  1582         -    if( th_isspecial(c) ) hasSpecialChar = 1;
  1583         -    if( c=='\\' ) hasEscapeChar = 1;
  1584         -    if( c=='{' ) nBrace++;
  1585         -    if( c=='}' ) nBrace--;
  1586         -  }
  1587         -
  1588         -  if( nElem==0 || (!hasEscapeChar && hasSpecialChar && nBrace==0) ){
  1589         -    thBufferWrite(interp, &output, "{", 1);
  1590         -    thBufferWrite(interp, &output, zElem, nElem);
  1591         -    thBufferWrite(interp, &output, "}", 1);
  1592         -  }else{
  1593         -    for(i=0; i<nElem; i++){
  1594         -      char c = zElem[i];
  1595         -      if( th_isspecial(c) ) thBufferWrite(interp, &output, "\\", 1);
  1596         -      thBufferWrite(interp, &output, &c, 1);
  1597         -    }
  1598         -  }
  1599         -
  1600         -  *pzList = output.zBuf;
  1601         -  *pnList = output.nBuf;
  1602         -
  1603         -  return TH_OK;
  1604         -}
  1605         -
  1606         -/*
  1607         -** Append a new element to an existing th1 string. This function uses
  1608         -** the same interface as the Th_ListAppend() function.
  1609         -*/
  1610         -int Th_StringAppend(
  1611         -  Th_Interp *interp,           /* Interpreter context */
  1612         -  char **pzStr,               /* IN/OUT: Ptr to ptr to list */
  1613         -  int *pnStr,                  /* IN/OUT: Current length of *pzStr */
  1614         -  const char *zElem,          /* Data to append */
  1615         -  int nElem                    /* Length of nElem */
  1616         -){
  1617         -  char *zNew;
  1618         -  int nNew;
  1619         -
  1620         -  if( nElem<0 ){
  1621         -    nElem = th_strlen(zElem);
  1622         -  }
  1623         -
  1624         -  nNew = *pnStr + nElem;
  1625         -  zNew = Th_Malloc(interp, nNew);
  1626         -  memcpy(zNew, *pzStr, *pnStr);
  1627         -  memcpy(&zNew[*pnStr], zElem, nElem);
  1628         -
  1629         -  Th_Free(interp, *pzStr);
  1630         -  *pzStr = zNew;
  1631         -  *pnStr = nNew;
  1632         -
  1633         -  return TH_OK;
  1634         -}
  1635         -
  1636         -/* 
  1637         -** Delete an interpreter.
  1638         -*/
  1639         -void Th_DeleteInterp(Th_Interp *interp){
  1640         -  assert(interp->pFrame);
  1641         -  assert(0==interp->pFrame->pCaller);
  1642         -
  1643         -  /* Delete the contents of the global frame. */
  1644         -  thPopFrame(interp);
  1645         -
  1646         -  /* Delete any result currently stored in the interpreter. */
  1647         -  Th_SetResult(interp, 0, 0);
  1648         -
  1649         -  /* Delete all registered commands and the command hash-table itself. */
  1650         -  Th_HashIterate(interp, interp->paCmd, thFreeCommand, (void *)interp);
  1651         -  Th_HashDelete(interp, interp->paCmd);
  1652         -
  1653         -  /* Delete the interpreter structure itself. */
  1654         -  Th_Free(interp, (void *)interp);
  1655         -}
  1656         -
  1657         -/* 
  1658         -** Create a new interpreter.
  1659         -*/
  1660         -Th_Interp * Th_CreateInterp(Th_Vtab *pVtab){
  1661         -  Th_Interp *p;
  1662         -
  1663         -  /* Allocate and initialise the interpreter and the global frame */
  1664         -  p = pVtab->xMalloc(sizeof(Th_Interp) + sizeof(Th_Frame));
  1665         -  memset(p, 0, sizeof(Th_Interp));
  1666         -  p->pVtab = pVtab;
  1667         -  p->paCmd = Th_HashNew(p);
  1668         -  thPushFrame(p, (Th_Frame *)&p[1]);
  1669         -
  1670         -  return p;
  1671         -}
  1672         -
  1673         -/*
  1674         -** These two types are used only by the expression module, where
  1675         -** the expression module means the Th_Expr() and exprXXX() functions.
  1676         -*/
  1677         -typedef struct Operator Operator;
  1678         -struct Operator {
  1679         -  const char *zOp;
  1680         -  int eOp;
  1681         -  int iPrecedence;
  1682         -  int eArgType;
  1683         -};
  1684         -typedef struct Expr Expr;
  1685         -struct Expr {
  1686         -  Operator *pOp;
  1687         -  Expr *pParent;
  1688         -  Expr *pLeft;
  1689         -  Expr *pRight;
  1690         -
  1691         -  char *zValue;     /* Pointer to literal value */
  1692         -  int nValue;        /* Length of literal value buffer */
  1693         -};
  1694         -
  1695         -/* Unary operators */
  1696         -#define OP_UNARY_MINUS  2
  1697         -#define OP_UNARY_PLUS   3
  1698         -#define OP_BITWISE_NOT  4
  1699         -#define OP_LOGICAL_NOT  5
  1700         -
  1701         -/* Binary operators */
  1702         -#define OP_MULTIPLY     6
  1703         -#define OP_DIVIDE       7
  1704         -#define OP_MODULUS      8
  1705         -#define OP_ADD          9
  1706         -#define OP_SUBTRACT    10
  1707         -#define OP_LEFTSHIFT   11
  1708         -#define OP_RIGHTSHIFT  12
  1709         -#define OP_LT          13
  1710         -#define OP_GT          14
  1711         -#define OP_LE          15
  1712         -#define OP_GE          16
  1713         -#define OP_EQ          17
  1714         -#define OP_NE          18
  1715         -#define OP_SEQ         19
  1716         -#define OP_SNE         20
  1717         -#define OP_BITWISE_AND 21
  1718         -#define OP_BITWISE_XOR 22
  1719         -#define OP_BITWISE_OR  24
  1720         -#define OP_LOGICAL_AND 25
  1721         -#define OP_LOGICAL_OR  26
  1722         -
  1723         -/* Other symbols */
  1724         -#define OP_OPEN_BRACKET  27
  1725         -#define OP_CLOSE_BRACKET 28
  1726         -
  1727         -/* Argument types. Each operator in the expression syntax is defined
  1728         -** as requiring either integer, number (real or integer) or string
  1729         -** operands.
  1730         -*/
  1731         -#define ARG_INTEGER 1
  1732         -#define ARG_NUMBER  2
  1733         -#define ARG_STRING  3
  1734         -
  1735         -static Operator aOperator[] = {
  1736         -
  1737         -  {"(",  OP_OPEN_BRACKET,   -1, 0},
  1738         -  {")",  OP_CLOSE_BRACKET, -1, 0},
  1739         -
  1740         -  /* Note: all unary operators have (iPrecedence==1) */
  1741         -  {"-",  OP_UNARY_MINUS,    1, ARG_NUMBER},
  1742         -  {"+",  OP_UNARY_PLUS,     1, ARG_NUMBER},
  1743         -  {"~",  OP_BITWISE_NOT,    1, ARG_INTEGER},
  1744         -  {"!",  OP_LOGICAL_NOT,    1, ARG_INTEGER},
  1745         -
  1746         -  /* Binary operators. It is important to the parsing in Th_Expr() that
  1747         -   * the two-character symbols ("==") appear before the one-character 
  1748         -   * ones ("="). And that the priorities of all binary operators are
  1749         -   * integers between 2 and 12.
  1750         -   */
  1751         -  {"<<", OP_LEFTSHIFT,      4, ARG_INTEGER},
  1752         -  {">>", OP_RIGHTSHIFT,     4, ARG_INTEGER},
  1753         -  {"<=", OP_LE,             5, ARG_NUMBER},
  1754         -  {">=", OP_GE,             5, ARG_NUMBER},
  1755         -  {"==", OP_EQ,             6, ARG_NUMBER},
  1756         -  {"!=", OP_NE,             6, ARG_NUMBER},
  1757         -  {"eq", OP_SEQ,            7, ARG_STRING},
  1758         -  {"ne", OP_SNE,            7, ARG_STRING},
  1759         -  {"&&", OP_LOGICAL_AND,   11, ARG_INTEGER},
  1760         -  {"||", OP_LOGICAL_OR,    12, ARG_INTEGER},
  1761         -
  1762         -  {"*",  OP_MULTIPLY,       2, ARG_NUMBER},
  1763         -  {"/",  OP_DIVIDE,         2, ARG_NUMBER},
  1764         -  {"%",  OP_MODULUS,        2, ARG_INTEGER},
  1765         -  {"+",  OP_ADD,            3, ARG_NUMBER},
  1766         -  {"-",  OP_SUBTRACT,       3, ARG_NUMBER},
  1767         -  {"<",  OP_LT,             5, ARG_NUMBER},
  1768         -  {">",  OP_GT,             5, ARG_NUMBER},
  1769         -  {"&",  OP_BITWISE_AND,    8, ARG_INTEGER},
  1770         -  {"^",  OP_BITWISE_XOR,    9, ARG_INTEGER},
  1771         -  {"|",  OP_BITWISE_OR,    10, ARG_INTEGER},
  1772         -
  1773         -  {0,0,0}
  1774         -};
  1775         -
  1776         -/*
  1777         -** The first part of the string (zInput,nInput) contains a number.
  1778         -** Set *pnVarname to the number of bytes in the numeric string. 
  1779         -*/
  1780         -static int thNextNumber(
  1781         -  Th_Interp *interp, 
  1782         -  const char *zInput, 
  1783         -  int nInput, 
  1784         -  int *pnLiteral
  1785         -){
  1786         -  int i;
  1787         -  int seenDot = 0;
  1788         -  for(i=0; i<nInput; i++){
  1789         -    char c = zInput[i];
  1790         -    if( (seenDot || c!='.') && !th_isdigit(c) ) break;
  1791         -    if( c=='.' ) seenDot = 1;
  1792         -  }
  1793         -  *pnLiteral = i;
  1794         -  return TH_OK;
  1795         -}
  1796         -
  1797         -/*
  1798         -** Free an expression tree.
  1799         -*/
  1800         -static void exprFree(Th_Interp *interp, Expr *pExpr){
  1801         -  if( pExpr ){
  1802         -    exprFree(interp, pExpr->pLeft);
  1803         -    exprFree(interp, pExpr->pRight);
  1804         -    Th_Free(interp, pExpr->zValue);
  1805         -    Th_Free(interp, pExpr);
  1806         -  }
  1807         -}
  1808         -
  1809         -/*
  1810         -** Evaluate an expression tree.
  1811         -*/
  1812         -static int exprEval(Th_Interp *interp, Expr *pExpr){
  1813         -  int rc = TH_OK;
  1814         -
  1815         -  if( pExpr->pOp==0 ){
  1816         -    /* A literal */
  1817         -    rc = thSubstWord(interp, pExpr->zValue, pExpr->nValue);
  1818         -  }else{
  1819         -    int eArgType = 0;           /* Actual type of arguments */
  1820         -
  1821         -    /* Argument values */
  1822         -    int iLeft = 0;
  1823         -    int iRight = 0;
  1824         -    double fLeft;
  1825         -    double fRight;
  1826         -
  1827         -    /* Left and right arguments as strings */
  1828         -    char *zLeft = 0; int nLeft = 0;
  1829         -    char *zRight = 0; int nRight = 0;
  1830         -
  1831         -    /* Evaluate left and right arguments, if they exist. */
  1832         -    if( pExpr->pLeft ){
  1833         -      rc = exprEval(interp, pExpr->pLeft);
  1834         -      if( rc==TH_OK ){
  1835         -        zLeft = Th_TakeResult(interp, &nLeft);
  1836         -      }
  1837         -    }
  1838         -    if( rc==TH_OK && pExpr->pRight ){
  1839         -      rc = exprEval(interp, pExpr->pRight);
  1840         -      if( rc==TH_OK ){
  1841         -        zRight = Th_TakeResult(interp, &nRight);
  1842         -      }
  1843         -    }
  1844         -
  1845         -    /* Convert arguments to their required forms. */
  1846         -    if( rc==TH_OK ){
  1847         -      eArgType = pExpr->pOp->eArgType;
  1848         -      if( eArgType==ARG_NUMBER ){
  1849         -        if( (zLeft==0 || TH_OK==Th_ToInt(0, zLeft, nLeft, &iLeft))
  1850         -         && (zRight==0 || TH_OK==Th_ToInt(0, zRight, nRight, &iRight))
  1851         -        ){
  1852         -          eArgType = ARG_INTEGER;
  1853         -        }else if( 
  1854         -          (zLeft && TH_OK!=Th_ToDouble(interp, zLeft, nLeft, &fLeft)) ||
  1855         -          (zRight && TH_OK!=Th_ToDouble(interp, zRight, nRight, &fRight))
  1856         -        ){
  1857         -          /* A type error. */
  1858         -          rc = TH_ERROR;
  1859         -        }
  1860         -      }else if( eArgType==ARG_INTEGER ){
  1861         -        rc = Th_ToInt(interp, zLeft, nLeft, &iLeft);
  1862         -        if( rc==TH_OK && zRight ){
  1863         -          rc = Th_ToInt(interp, zRight, nRight, &iRight);
  1864         -        }
  1865         -      }  
  1866         -    }
  1867         -
  1868         -    if( rc==TH_OK && eArgType==ARG_INTEGER ){
  1869         -      int iRes = 0;
  1870         -      switch( pExpr->pOp->eOp ) {
  1871         -        case OP_MULTIPLY:     iRes = iLeft*iRight;  break;
  1872         -        case OP_DIVIDE:       iRes = iLeft/iRight;  break;
  1873         -        case OP_MODULUS:      iRes = iLeft%iRight;  break;
  1874         -        case OP_ADD:          iRes = iLeft+iRight;  break;
  1875         -        case OP_SUBTRACT:     iRes = iLeft-iRight;  break;
  1876         -        case OP_LEFTSHIFT:    iRes = iLeft<<iRight; break;
  1877         -        case OP_RIGHTSHIFT:   iRes = iLeft>>iRight; break;
  1878         -        case OP_LT:           iRes = iLeft<iRight;  break;
  1879         -        case OP_GT:           iRes = iLeft>iRight;  break;
  1880         -        case OP_LE:           iRes = iLeft<=iRight; break;
  1881         -        case OP_GE:           iRes = iLeft>=iRight; break;
  1882         -        case OP_EQ:           iRes = iLeft==iRight; break;
  1883         -        case OP_NE:           iRes = iLeft!=iRight; break;
  1884         -        case OP_BITWISE_AND:  iRes = iLeft&iRight;  break;
  1885         -        case OP_BITWISE_XOR:  iRes = iLeft^iRight;  break;
  1886         -        case OP_BITWISE_OR:   iRes = iLeft|iRight;  break;
  1887         -        case OP_LOGICAL_AND:  iRes = iLeft&&iRight; break;
  1888         -        case OP_LOGICAL_OR:   iRes = iLeft||iRight; break;
  1889         -        case OP_UNARY_MINUS:  iRes = -iLeft;        break;
  1890         -        case OP_UNARY_PLUS:   iRes = +iLeft;        break;
  1891         -        case OP_LOGICAL_NOT:  iRes = !iLeft;        break;
  1892         -        default: assert(!"Internal error");
  1893         -      }
  1894         -      Th_SetResultInt(interp, iRes);
  1895         -    }else if( rc==TH_OK && eArgType==ARG_NUMBER ){
  1896         -      switch( pExpr->pOp->eOp ) {
  1897         -        case OP_MULTIPLY: Th_SetResultDouble(interp, fLeft*fRight);  break;
  1898         -        case OP_DIVIDE:   Th_SetResultDouble(interp, fLeft/fRight);  break;
  1899         -        case OP_ADD:      Th_SetResultDouble(interp, fLeft+fRight);  break;
  1900         -        case OP_SUBTRACT: Th_SetResultDouble(interp, fLeft-fRight);  break;
  1901         -        case OP_LT:       Th_SetResultInt(interp, fLeft<fRight);  break;
  1902         -        case OP_GT:       Th_SetResultInt(interp, fLeft>fRight);  break;
  1903         -        case OP_LE:       Th_SetResultInt(interp, fLeft<=fRight); break;
  1904         -        case OP_GE:       Th_SetResultInt(interp, fLeft>=fRight); break;
  1905         -        case OP_EQ:       Th_SetResultInt(interp, fLeft==fRight); break;
  1906         -        case OP_NE:       Th_SetResultInt(interp, fLeft!=fRight); break;
  1907         -        default: assert(!"Internal error");
  1908         -      }
  1909         -    }else if( rc==TH_OK ){
  1910         -      int iEqual = 0;
  1911         -      assert( eArgType==ARG_STRING );
  1912         -      if( nRight==nLeft && 0==memcmp(zRight, zLeft, nRight) ){
  1913         -        iEqual = 1;
  1914         -      }
  1915         -      switch( pExpr->pOp->eOp ) {
  1916         -        case OP_SEQ:       Th_SetResultInt(interp, iEqual); break;
  1917         -        case OP_SNE:       Th_SetResultInt(interp, !iEqual); break;
  1918         -        default: assert(!"Internal error");
  1919         -      }
  1920         -    }
  1921         -
  1922         -    Th_Free(interp, zLeft);
  1923         -    Th_Free(interp, zRight);
  1924         -  }
  1925         -
  1926         -  return rc;
  1927         -}
  1928         -
  1929         -/*
  1930         -** Create an expression tree from an array of tokens. If successful,
  1931         -** the root of the tree is stored in apToken[0].
  1932         -*/
  1933         -int exprMakeTree(Th_Interp *interp, Expr **apToken, int nToken){
  1934         -  int iLeft;
  1935         -  int i;
  1936         -  int jj;
  1937         -
  1938         -  assert(nToken>0);
  1939         -#define ISTERM(x) (apToken[x] && (!apToken[x]->pOp || apToken[x]->pLeft))
  1940         -
  1941         -  for(jj=0; jj<nToken; jj++){
  1942         -    if( apToken[jj]->pOp && apToken[jj]->pOp->eOp==OP_OPEN_BRACKET ){
  1943         -      int nNest = 1;
  1944         -      int iLeft = jj; 
  1945         -
  1946         -      for(jj++; jj<nToken; jj++){
  1947         -        Operator *pOp = apToken[jj]->pOp;
  1948         -        if( pOp && pOp->eOp==OP_OPEN_BRACKET ) nNest++;
  1949         -        if( pOp && pOp->eOp==OP_CLOSE_BRACKET ) nNest--;
  1950         -        if( nNest==0 ) break;
  1951         -      }
  1952         -      if( jj==nToken ){
  1953         -        return TH_ERROR;
  1954         -      }
  1955         -      if( (jj-iLeft)>1 ){
  1956         -        if( exprMakeTree(interp, &apToken[iLeft+1], jj-iLeft-1) ){
  1957         -          return TH_ERROR;
  1958         -        }
  1959         -        exprFree(interp, apToken[jj]);
  1960         -        exprFree(interp, apToken[iLeft]);
  1961         -        apToken[jj] = 0;
  1962         -        apToken[iLeft] = 0;
  1963         -      }
  1964         -    }
  1965         -  }
  1966         -
  1967         -  iLeft = 0;
  1968         -  for(jj=nToken-1; jj>=0; jj--){
  1969         -    if( apToken[jj] ){
  1970         -      if( apToken[jj]->pOp && apToken[jj]->pOp->iPrecedence==1 && iLeft>0 ){
  1971         -        apToken[jj]->pLeft = apToken[iLeft];
  1972         -        apToken[jj]->pLeft->pParent = apToken[jj];
  1973         -        apToken[iLeft] = 0;
  1974         -      }
  1975         -      iLeft = jj;
  1976         -    }
  1977         -  }
  1978         -  for(i=2; i<=12; i++){
  1979         -    iLeft = -1;
  1980         -    for(jj=0; jj<nToken; jj++){
  1981         -      Expr *pToken = apToken[jj];
  1982         -      if( apToken[jj] ){
  1983         -        if( pToken->pOp && !pToken->pLeft && pToken->pOp->iPrecedence==i ){
  1984         -          int iRight = jj+1;
  1985         -
  1986         -          iRight = jj+1;
  1987         -          for(iRight=jj+1; !apToken[iRight] && iRight<nToken; iRight++);
  1988         -          if( iRight==nToken || iLeft<0 || !ISTERM(iRight) || !ISTERM(iLeft) ){
  1989         -            return TH_ERROR;
  1990         -          }
  1991         -          pToken->pLeft = apToken[iLeft];
  1992         -          apToken[iLeft] = 0;
  1993         -          pToken->pLeft->pParent = pToken;
  1994         -          pToken->pRight = apToken[iRight];
  1995         -          apToken[iRight] = 0;
  1996         -          pToken->pRight->pParent = pToken;
  1997         -        }
  1998         -        iLeft = jj;
  1999         -      }
  2000         -    }
  2001         -  }
  2002         -  for(jj=1; jj<nToken; jj++){
  2003         -    assert( !apToken[jj] || !apToken[0] );
  2004         -    if( apToken[jj] ){
  2005         -      apToken[0] = apToken[jj];
  2006         -      apToken[jj] = 0;
  2007         -    }
  2008         -  }
  2009         -
  2010         -  return TH_OK;
  2011         -}
  2012         -
  2013         -/*
  2014         -** Parse a string containing a TH expression to a list of tokens.
  2015         -*/
  2016         -static int exprParse(
  2017         -  Th_Interp *interp,        /* Interpreter to leave error message in */
  2018         -  const char *zExpr,       /* Pointer to input string */
  2019         -  int nExpr,                /* Number of bytes at zExpr */
  2020         -  Expr ***papToken,         /* OUT: Array of tokens. */
  2021         -  int *pnToken              /* OUT: Size of token array */
  2022         -){
  2023         -  int i;
  2024         -
  2025         -  int rc = TH_OK;
  2026         -  int nToken = 0;
  2027         -  Expr **apToken = 0;
  2028         -
  2029         -  for(i=0; rc==TH_OK && i<nExpr; ){
  2030         -    char c = zExpr[i];
  2031         -    if( th_isspace(c) ){                                /* White-space     */
  2032         -      i++;
  2033         -    }else{
  2034         -      Expr *pNew = (Expr *)Th_Malloc(interp, sizeof(Expr));
  2035         -      const char *z = &zExpr[i];
  2036         -
  2037         -      switch (c) {
  2038         -        case '0': case '1': case '2': case '3': case '4':
  2039         -        case '5': case '6': case '7': case '8': case '9':
  2040         -          thNextNumber(interp, z, nExpr-i, &pNew->nValue);
  2041         -          break;
  2042         -
  2043         -        case '$':
  2044         -          thNextVarname(interp, z, nExpr-i, &pNew->nValue);
  2045         -          break;
  2046         -
  2047         -        case '{': case '[': {
  2048         -          thNextCommand(interp, z, nExpr-i, &pNew->nValue);
  2049         -          break;
  2050         -        }
  2051         -
  2052         -        case '"': {
  2053         -          int iEnd = i;
  2054         -          while( ++iEnd<nExpr && zExpr[iEnd]!='"' ){
  2055         -            if( zExpr[iEnd]=='\\' ) iEnd++;
  2056         -          }
  2057         -          if( iEnd<nExpr ){
  2058         -            pNew->nValue = iEnd+1-i;
  2059         -          }
  2060         -          break;
  2061         -        }
  2062         -
  2063         -        default: {
  2064         -          int j;
  2065         -          for(j=0; aOperator[j].zOp; j++){
  2066         -            int nOp;
  2067         -            if( aOperator[j].iPrecedence==1 && nToken>0 ){
  2068         -              Expr *pPrev = apToken[nToken-1];
  2069         -              if( !pPrev->pOp || pPrev->pOp->eOp==OP_CLOSE_BRACKET ){
  2070         -                continue;
  2071         -              }
  2072         -            }
  2073         -            nOp = th_strlen((const char *)aOperator[j].zOp);
  2074         -            if( (nExpr-i)>=nOp && 0==memcmp(aOperator[j].zOp, &zExpr[i], nOp) ){
  2075         -              pNew->pOp = &aOperator[j];
  2076         -              i += nOp;
  2077         -              break;
  2078         -            }
  2079         -          }
  2080         -        }
  2081         -      }
  2082         -
  2083         -      if( pNew->pOp || pNew->nValue ){
  2084         -        if( pNew->nValue ){
  2085         -          /* A terminal. Copy the string value. */
  2086         -          assert( !pNew->pOp );
  2087         -          pNew->zValue = Th_Malloc(interp, pNew->nValue);
  2088         -          memcpy(pNew->zValue, z, pNew->nValue);
  2089         -          i += pNew->nValue;
  2090         -        }
  2091         -        if( (nToken%16)==0 ){
  2092         -          /* Grow the apToken array. */
  2093         -          Expr **apTokenOld = apToken; 
  2094         -          apToken = Th_Malloc(interp, sizeof(Expr *)*(nToken+16));
  2095         -          memcpy(apToken, apTokenOld, sizeof(Expr *)*nToken);
  2096         -        }
  2097         -
  2098         -        /* Put the new token at the end of the apToken array */
  2099         -        apToken[nToken] = pNew;
  2100         -        nToken++;
  2101         -      }else{
  2102         -        Th_Free(interp, pNew);
  2103         -        rc = TH_ERROR;
  2104         -      }
  2105         -    }
  2106         -  }
  2107         -
  2108         -  *papToken = apToken;
  2109         -  *pnToken = nToken;
  2110         -  return rc;
  2111         -}
  2112         -
  2113         -/*
  2114         -** Evaluate the string (zExpr, nExpr) as a Th expression. Store
  2115         -** the result in the interpreter interp and return TH_OK if
  2116         -** successful. If an error occurs, store an error message in
  2117         -** the interpreter result and return an error code.
  2118         -*/ 
  2119         -int Th_Expr(Th_Interp *interp, const char *zExpr, int nExpr){
  2120         -  int rc;                           /* Return Code */
  2121         -  int i;                            /* Loop counter */
  2122         -
  2123         -  int nToken = 0;
  2124         -  Expr **apToken = 0;
  2125         -
  2126         -  if( nExpr<0 ){
  2127         -    nExpr = th_strlen(zExpr);
  2128         -  }
  2129         -
  2130         -  /* Parse the expression to a list of tokens. */
  2131         -  rc = exprParse(interp, zExpr, nExpr, &apToken, &nToken);
  2132         -
  2133         -  /* If the parsing was successful, create an expression tree from
  2134         -  ** the parsed list of tokens. If successful, apToken[0] is set
  2135         -  ** to point to the root of the expression tree. 
  2136         -  */
  2137         -  if( rc==TH_OK ){
  2138         -    rc = exprMakeTree(interp, apToken, nToken);
  2139         -  }
  2140         -
  2141         -  if( rc!=TH_OK ){
  2142         -    Th_ErrorMessage(interp, "syntax error in expression: \"", zExpr, nExpr);
  2143         -  }
  2144         -
  2145         -  /* Evaluate the expression tree. */
  2146         -  if( rc==TH_OK ){
  2147         -    rc = exprEval(interp, apToken[0]);
  2148         -  }
  2149         -
  2150         -  /* Free memory allocated by exprParse(). */
  2151         -  for(i=0; i<nToken; i++){
  2152         -    exprFree(interp, apToken[i]);
  2153         -  }
  2154         -  Th_Free(interp, apToken);
  2155         -
  2156         -  return rc;
  2157         -}
  2158         -
  2159         -/*
  2160         -** Allocate and return a pointer to a new hash-table. The caller should
  2161         -** (eventually) delete the hash-table by passing it to Th_HashDelete().
  2162         -*/
  2163         -Th_Hash *Th_HashNew(Th_Interp *interp){
  2164         -  Th_Hash *p;
  2165         -  p = Th_Malloc(interp, sizeof(Th_Hash));
  2166         -  return p;
  2167         -}
  2168         -
  2169         -/*
  2170         -** Iterate through all values currently stored in the hash table. Invoke
  2171         -** the callback function xCallback for each entry. The second argument
  2172         -** passed to xCallback is a copy of the fourth argument passed to this
  2173         -** function.
  2174         -*/
  2175         -void Th_HashIterate(
  2176         -  Th_Interp *interp, 
  2177         -  Th_Hash *pHash,
  2178         -  void (*xCallback)(Th_HashEntry *pEntry, void *pContext),
  2179         -  void *pContext
  2180         -){
  2181         -  int i;
  2182         -  for(i=0; i<TH_HASHSIZE; i++){
  2183         -    Th_HashEntry *pEntry;
  2184         -    Th_HashEntry *pNext;
  2185         -    for(pEntry=pHash->a[i]; pEntry; pEntry=pNext){
  2186         -      pNext = pEntry->pNext;
  2187         -      xCallback(pEntry, pContext);
  2188         -    }
  2189         -  }
  2190         -}
  2191         -
  2192         -/*
  2193         -** Helper function for Th_HashDelete().
  2194         -*/
  2195         -static void xFreeHashEntry(Th_HashEntry *pEntry, void *pContext){
  2196         -  Th_Free((Th_Interp *)pContext, (void *)pEntry);
  2197         -}
  2198         -
  2199         -/*
  2200         -** Free a hash-table previously allocated by Th_HashNew().
  2201         -*/
  2202         -void Th_HashDelete(Th_Interp *interp, Th_Hash *pHash){
  2203         -  if( pHash ){
  2204         -    Th_HashIterate(interp, pHash, xFreeHashEntry, (void *)interp);
  2205         -    Th_Free(interp, pHash);
  2206         -  }
  2207         -}
  2208         -
  2209         -/*
  2210         -** This function is used to insert or delete hash table items, or to 
  2211         -** query a hash table for an existing item.
  2212         -**
  2213         -** If parameter op is less than zero, then the hash-table element 
  2214         -** identified by (zKey, nKey) is removed from the hash-table if it
  2215         -** exists. NULL is returned.
  2216         -**
  2217         -** Otherwise, if the hash-table contains an item with key (zKey, nKey),
  2218         -** a pointer to the associated Th_HashEntry is returned. If parameter
  2219         -** op is greater than zero, then a new entry is added if one cannot
  2220         -** be found. If op is zero, then NULL is returned if the item is
  2221         -** not already present in the hash-table.
  2222         -*/
  2223         -Th_HashEntry *Th_HashFind(
  2224         -  Th_Interp *interp, 
  2225         -  Th_Hash *pHash,
  2226         -  const char *zKey,
  2227         -  int nKey,
  2228         -  int op                      /* -ve = delete, 0 = find, +ve = insert */
  2229         -){
  2230         -  unsigned int iKey = 0;
  2231         -  int i;
  2232         -  Th_HashEntry *pRet;
  2233         -  Th_HashEntry **ppRet;
  2234         -
  2235         -  if( nKey<0 ){
  2236         -    nKey = th_strlen(zKey);
  2237         -  }
  2238         -
  2239         -  for(i=0; i<nKey; i++){
  2240         -    iKey = (iKey<<3) ^ iKey ^ zKey[i];
  2241         -  }
  2242         -  iKey = iKey % TH_HASHSIZE;
  2243         -
  2244         -  for(ppRet=&pHash->a[iKey]; (pRet=*ppRet); ppRet=&pRet->pNext){
  2245         -    assert( pRet && ppRet && *ppRet==pRet );
  2246         -    if( pRet->nKey==nKey && 0==memcmp(pRet->zKey, zKey, nKey) ) break;
  2247         -  }
  2248         -
  2249         -  if( op<0 && pRet ){
  2250         -    assert( ppRet && *ppRet==pRet );
  2251         -    *ppRet = pRet->pNext;
  2252         -    Th_Free(interp, pRet);
  2253         -    pRet = 0;
  2254         -  }
  2255         -
  2256         -  if( op>0 && !pRet ){
  2257         -    pRet = (Th_HashEntry *)Th_Malloc(interp, sizeof(Th_HashEntry) + nKey);
  2258         -    pRet->zKey = (char *)&pRet[1];
  2259         -    pRet->nKey = nKey;
  2260         -    memcpy(pRet->zKey, zKey, nKey);
  2261         -    pRet->pNext = pHash->a[iKey];
  2262         -    pHash->a[iKey] = pRet;
  2263         -  }
  2264         -
  2265         -  return pRet;
  2266         -}
  2267         -
  2268         -/*
  2269         -** This function is the same as the standard strlen() function, except
  2270         -** that it returns 0 (instead of being undefined) if the argument is
  2271         -** a null pointer.
  2272         -*/
  2273         -int th_strlen(const char *zStr){
  2274         -  int n = 0;
  2275         -  if( zStr ){
  2276         -    while( zStr[n] ) n++;
  2277         -  }
  2278         -  return n;
  2279         -}
  2280         -
  2281         -/* Whitespace characters:
  2282         -**
  2283         -**     ' '    0x20
  2284         -**     '\t'   0x09
  2285         -**     '\n'   0x0A
  2286         -**     '\v'   0x0B
  2287         -**     '\f'   0x0C
  2288         -**     '\r'   0x0D
  2289         -**
  2290         -** Whitespace characters have the 0x01 flag set. Decimal digits have the
  2291         -** 0x2 flag set. Single byte printable characters have the 0x4 flag set.
  2292         -** Alphabet characters have the 0x8 bit set. 
  2293         -**
  2294         -** The special list characters have the 0x10 flag set
  2295         -**
  2296         -**    { } [ ] \ ; ' "
  2297         -**
  2298         -**    " 0x22
  2299         -**
  2300         -*/
  2301         -static unsigned char aCharProp[256] = {
  2302         -  0,  0,  0,  0,  0,  0,  0,  0,     0,  1,  1,  1,  1,  1,  0,  0,   /* 0x0. */
  2303         -  0,  0,  1,  1,  0,  0,  0,  0,     0,  0,  0,  0,  0,  0,  0,  0,   /* 0x1. */
  2304         -  5,  4, 20,  4,  4,  4,  4,  4,     4,  4,  4,  4,  4,  4,  4,  4,   /* 0x2. */
  2305         -  6,  6,  6,  6,  6,  6,  6,  6,     6,  6,  4, 20,  4,  4,  4,  4,   /* 0x3. */
  2306         -  4, 12, 12, 12, 12, 12, 12, 12,    12, 12, 12, 12, 12, 12, 12, 12,   /* 0x4. */
  2307         - 12, 12, 12, 12, 12, 12, 12, 12,    12, 12, 12, 20, 20, 20,  4,  4,   /* 0x5. */
  2308         -  4, 12, 12, 12, 12, 12, 12, 12,    12, 12, 12, 12, 12, 12, 12, 12,   /* 0x6. */
  2309         - 12, 12, 12, 12, 12, 12, 12, 12,    12, 12, 12, 20,  4, 20,  4,  4,   /* 0x7. */
  2310         -
  2311         -  0,  0,  0,  0,  0,  0,  0,  0,     0,  0,  0,  0,  0,  0,  0,  0,   /* 0x8. */
  2312         -  0,  0,  0,  0,  0,  0,  0,  0,     0,  0,  0,  0,  0,  0,  0,  0,   /* 0x9. */
  2313         -  0,  0,  0,  0,  0,  0,  0,  0,     0,  0,  0,  0,  0,  0,  0,  0,   /* 0xA. */
  2314         -  0,  0,  0,  0,  0,  0,  0,  0,     0,  0,  0,  0,  0,  0,  0,  0,   /* 0xB. */
  2315         -  0,  0,  0,  0,  0,  0,  0,  0,     0,  0,  0,  0,  0,  0,  0,  0,   /* 0xC. */
  2316         -  0,  0,  0,  0,  0,  0,  0,  0,     0,  0,  0,  0,  0,  0,  0,  0,   /* 0xD. */
  2317         -  0,  0,  0,  0,  0,  0,  0,  0,     0,  0,  0,  0,  0,  0,  0,  0,   /* 0xE. */
  2318         -  0,  0,  0,  0,  0,  0,  0,  0,     0,  0,  0,  0,  0,  0,  0,  0    /* 0xF. */
  2319         -};
  2320         -
  2321         -/*
  2322         -** Clone of the standard isspace() and isdigit function/macros.
  2323         -*/
  2324         -int th_isspace(char c){
  2325         -  return (aCharProp[(unsigned char)c] & 0x01);
  2326         -}
  2327         -int th_isdigit(char c){
  2328         -  return (aCharProp[(unsigned char)c] & 0x02);
  2329         -}
  2330         -int th_isspecial(char c){
  2331         -  return (aCharProp[(unsigned char)c] & 0x11);
  2332         -}
  2333         -int th_isalnum(char c){
  2334         -  return (aCharProp[(unsigned char)c] & 0x0A);
  2335         -}
  2336         -
  2337         -#ifndef LONGDOUBLE_TYPE
  2338         -# define LONGDOUBLE_TYPE long double
  2339         -#endif
  2340         -typedef char u8;
  2341         -
  2342         -
  2343         -/*
  2344         -** Return TRUE if z is a pure numeric string.  Return FALSE if the
  2345         -** string contains any character which is not part of a number. If
  2346         -** the string is numeric and contains the '.' character, set *realnum
  2347         -** to TRUE (otherwise FALSE).
  2348         -**
  2349         -** An empty string is considered non-numeric.
  2350         -*/
  2351         -static int sqlite3IsNumber(const char *z, int *realnum){
  2352         -  int incr = 1;
  2353         -  if( *z=='-' || *z=='+' ) z += incr;
  2354         -  if( !th_isdigit(*(u8*)z) ){
  2355         -    return 0;
  2356         -  }
  2357         -  z += incr;
  2358         -  if( realnum ) *realnum = 0;
  2359         -  while( th_isdigit(*(u8*)z) ){ z += incr; }
  2360         -  if( *z=='.' ){
  2361         -    z += incr;
  2362         -    if( !th_isdigit(*(u8*)z) ) return 0;
  2363         -    while( th_isdigit(*(u8*)z) ){ z += incr; }
  2364         -    if( realnum ) *realnum = 1;
  2365         -  }
  2366         -  if( *z=='e' || *z=='E' ){
  2367         -    z += incr;
  2368         -    if( *z=='+' || *z=='-' ) z += incr;
  2369         -    if( !th_isdigit(*(u8*)z) ) return 0;
  2370         -    while( th_isdigit(*(u8*)z) ){ z += incr; }
  2371         -    if( realnum ) *realnum = 1;
  2372         -  }
  2373         -  return *z==0;
  2374         -}
  2375         -
  2376         -/*
  2377         -** The string z[] is an ascii representation of a real number.
  2378         -** Convert this string to a double.
  2379         -**
  2380         -** This routine assumes that z[] really is a valid number.  If it
  2381         -** is not, the result is undefined.
  2382         -**
  2383         -** This routine is used instead of the library atof() function because
  2384         -** the library atof() might want to use "," as the decimal point instead
  2385         -** of "." depending on how locale is set.  But that would cause problems
  2386         -** for SQL.  So this routine always uses "." regardless of locale.
  2387         -*/
  2388         -static int sqlite3AtoF(const char *z, double *pResult){
  2389         -  int sign = 1;
  2390         -  const char *zBegin = z;
  2391         -  LONGDOUBLE_TYPE v1 = 0.0;
  2392         -  while( th_isspace(*(u8*)z) ) z++;
  2393         -  if( *z=='-' ){
  2394         -    sign = -1;
  2395         -    z++;
  2396         -  }else if( *z=='+' ){
  2397         -    z++;
  2398         -  }
  2399         -  while( th_isdigit(*(u8*)z) ){
  2400         -    v1 = v1*10.0 + (*z - '0');
  2401         -    z++;
  2402         -  }
  2403         -  if( *z=='.' ){
  2404         -    LONGDOUBLE_TYPE divisor = 1.0;
  2405         -    z++;
  2406         -    while( th_isdigit(*(u8*)z) ){
  2407         -      v1 = v1*10.0 + (*z - '0');
  2408         -      divisor *= 10.0;
  2409         -      z++;
  2410         -    }
  2411         -    v1 /= divisor;
  2412         -  }
  2413         -  if( *z=='e' || *z=='E' ){
  2414         -    int esign = 1;
  2415         -    int eval = 0;
  2416         -    LONGDOUBLE_TYPE scale = 1.0;
  2417         -    z++;
  2418         -    if( *z=='-' ){
  2419         -      esign = -1;
  2420         -      z++;
  2421         -    }else if( *z=='+' ){
  2422         -      z++;
  2423         -    }
  2424         -    while( th_isdigit(*(u8*)z) ){
  2425         -      eval = eval*10 + *z - '0';
  2426         -      z++;
  2427         -    }
  2428         -    while( eval>=64 ){ scale *= 1.0e+64; eval -= 64; }
  2429         -    while( eval>=16 ){ scale *= 1.0e+16; eval -= 16; }
  2430         -    while( eval>=4 ){ scale *= 1.0e+4; eval -= 4; }
  2431         -    while( eval>=1 ){ scale *= 1.0e+1; eval -= 1; }
  2432         -    if( esign<0 ){
  2433         -      v1 /= scale;
  2434         -    }else{
  2435         -      v1 *= scale;
  2436         -    }
  2437         -  }
  2438         -  *pResult = sign<0 ? -v1 : v1;
  2439         -  return z - zBegin;
  2440         -}
  2441         -
  2442         -/*
  2443         -** Try to convert the string passed as arguments (z, n) to an integer.
  2444         -** If successful, store the result in *piOut and return TH_OK. 
  2445         -**
  2446         -** If the string cannot be converted to an integer, return TH_ERROR. 
  2447         -** If the interp argument is not NULL, leave an error message in the 
  2448         -** interpreter result too.
  2449         -*/
  2450         -int Th_ToInt(Th_Interp *interp, const char *z, int n, int *piOut){
  2451         -  int i = 0;
  2452         -  int iOut = 0;
  2453         -
  2454         -  if( n<0 ){
  2455         -    n = th_strlen(z);
  2456         -  }
  2457         -
  2458         -  if( n>0 && (z[0]=='-' || z[0]=='+') ){
  2459         -    i = 1;
  2460         -  }
  2461         -  for(; i<n; i++){
  2462         -    if( !th_isdigit(z[i]) ){
  2463         -      Th_ErrorMessage(interp, "expected integer, got: \"", z, n);
  2464         -      return TH_ERROR;
  2465         -    }
  2466         -    iOut = iOut * 10 + (z[i] - 48);
  2467         -  }
  2468         -
  2469         -  if( n>0 && z[0]=='-' ){
  2470         -    iOut *= -1;
  2471         -  }
  2472         -
  2473         -  *piOut = iOut;
  2474         -  return TH_OK;
  2475         -}
  2476         -
  2477         -/*
  2478         -** Try to convert the string passed as arguments (z, n) to a double.
  2479         -** If successful, store the result in *pfOut and return TH_OK. 
  2480         -**
  2481         -** If the string cannot be converted to a double, return TH_ERROR. 
  2482         -** If the interp argument is not NULL, leave an error message in the 
  2483         -** interpreter result too.
  2484         -*/
  2485         -int Th_ToDouble(
  2486         -  Th_Interp *interp, 
  2487         -  const char *z, 
  2488         -  int n, 
  2489         -  double *pfOut
  2490         -){
  2491         -  if( !sqlite3IsNumber((const char *)z, 0) ){
  2492         -    Th_ErrorMessage(interp, "expected number, got: \"", z, n);
  2493         -    return TH_ERROR;
  2494         -  }
  2495         -
  2496         -  sqlite3AtoF((const char *)z, pfOut);
  2497         -  return TH_OK;
  2498         -}
  2499         -
  2500         -/*
  2501         -** Set the result of the interpreter to the th1 representation of
  2502         -** the integer iVal and return TH_OK.
  2503         -*/
  2504         -int Th_SetResultInt(Th_Interp *interp, int iVal){
  2505         -  int isNegative = 0;
  2506         -  char zBuf[32];
  2507         -  char *z = &zBuf[32];
  2508         -
  2509         -  if( iVal<0 ){
  2510         -    isNegative = 1;
  2511         -    iVal = iVal * -1;
  2512         -  }
  2513         -  *(--z) = '\0';
  2514         -  *(--z) = (char)(48+(iVal%10));
  2515         -  while( (iVal = (iVal/10))>0 ){
  2516         -    *(--z) = (char)(48+(iVal%10));
  2517         -    assert(z>zBuf);
  2518         -  }
  2519         -  if( isNegative ){
  2520         -    *(--z) = '-';
  2521         -  }
  2522         -
  2523         -  return Th_SetResult(interp, z, -1);
  2524         -}
  2525         -
  2526         -/*
  2527         -** Set the result of the interpreter to the th1 representation of
  2528         -** the double fVal and return TH_OK.
  2529         -*/
  2530         -int Th_SetResultDouble(Th_Interp *interp, double fVal){
  2531         -  int i;                /* Iterator variable */
  2532         -  double v = fVal;      /* Input value */
  2533         -  char zBuf[128];      /* Output buffer */
  2534         -  char *z = zBuf;      /* Output cursor */
  2535         -  int iDot = 0;         /* Digit after which to place decimal point */
  2536         -  int iExp = 0;         /* Exponent (NN in eNN) */
  2537         -  const char *zExp;    /* String representation of iExp */
  2538         -
  2539         -  /* Precision: */
  2540         -  #define INSIGNIFICANT 0.000000000001
  2541         -  #define ROUNDER       0.0000000000005
  2542         -  double insignificant = INSIGNIFICANT;
  2543         -
  2544         -  /* If the real value is negative, write a '-' character to the
  2545         -   * output and transform v to the corresponding positive number.
  2546         -   */ 
  2547         -  if( v<0.0 ){
  2548         -    *z++ = '-';
  2549         -    v *= -1.0;
  2550         -  }
  2551         -
  2552         -  /* Normalize v to a value between 1.0 and 10.0. Integer 
  2553         -   * variable iExp is set to the exponent. i.e the original
  2554         -   * value is (v * 10^iExp) (or the negative thereof).
  2555         -   */ 
  2556         -  if( v>0.0 ){
  2557         -    while( (v+ROUNDER)>=10.0 ) { iExp++; v *= 0.1; }
  2558         -    while( (v+ROUNDER)<1.0 )   { iExp--; v *= 10.0; }
  2559         -  }
  2560         -  v += ROUNDER;
  2561         -
  2562         -  /* For a small (<12) positive exponent, move the decimal point
  2563         -   * instead of using the "eXX" notation.
  2564         -   */
  2565         -  if( iExp>0 && iExp<12 ){
  2566         -    iDot = iExp;
  2567         -    iExp = 0;
  2568         -  }
  2569         -
  2570         -  /* For a small (>-4) negative exponent, write leading zeroes
  2571         -   * instead of using the "eXX" notation.
  2572         -   */
  2573         -  if( iExp<0 && iExp>-4 ){
  2574         -    *z++ = '0';
  2575         -    *z++ = '.';
  2576         -    for(i=0; i>(iExp+1); i--){
  2577         -      *z++ = '0';
  2578         -    }
  2579         -    iDot = -1;
  2580         -    iExp = 0;
  2581         -  }
  2582         -
  2583         -  /* Output the digits in real value v. The value of iDot determines
  2584         -   * where (if at all) the decimal point is placed.
  2585         -   */
  2586         -  for(i=0; i<=(iDot+1) || v>=insignificant; i++){
  2587         -    *z++ = (char)(48 + (int)v);
  2588         -    v = (v - ((double)(int)v)) * 10.0;
  2589         -    insignificant *= 10.0;
  2590         -    if( iDot==i ){
  2591         -      *z++ = '.';
  2592         -    }
  2593         -  }
  2594         -
  2595         -  /* If the exponent is not zero, add the "eXX" notation to the
  2596         -   * end of the string.
  2597         -   */
  2598         -  if( iExp!=0 ){
  2599         -    *z++ = 'e';
  2600         -    Th_SetResultInt(interp, iExp);
  2601         -    zExp = Th_GetResult(interp, 0);
  2602         -    for(i=0; zExp[i]; i++){
  2603         -      *z++ = zExp[i];
  2604         -    }
  2605         -  }
  2606         -
  2607         -  *z = '\0';
  2608         -  return Th_SetResult(interp, zBuf, -1);
  2609         -}

Deleted src/th.h.

     1         -
     2         -/* This header file defines the external interface to the custom Scripting
     3         -** Language (TH) interpreter.  TH is very similar to TCL but is not an
     4         -** exact clone.
     5         -*/
     6         -
     7         -/*
     8         -** Before creating an interpreter, the application must allocate and
     9         -** populate an instance of the following structure. It must remain valid
    10         -** for the lifetime of the interpreter.
    11         -*/
    12         -struct Th_Vtab {
    13         -  void *(*xMalloc)(unsigned int);
    14         -  void (*xFree)(void *);
    15         -};
    16         -typedef struct Th_Vtab Th_Vtab;
    17         -
    18         -/*
    19         -** Opaque handle for interpeter.
    20         -*/
    21         -typedef struct Th_Interp Th_Interp;
    22         -
    23         -/* 
    24         -** Create and delete interpreters. 
    25         -*/
    26         -Th_Interp * Th_CreateInterp(Th_Vtab *pVtab);
    27         -void Th_DeleteInterp(Th_Interp *);
    28         -
    29         -/* 
    30         -** Evaluate an TH program in the stack frame identified by parameter
    31         -** iFrame, according to the following rules:
    32         -**
    33         -**   * If iFrame is 0, this means the current frame.
    34         -**
    35         -**   * If iFrame is negative, then the nth frame up the stack, where n is 
    36         -**     the absolute value of iFrame. A value of -1 means the calling
    37         -**     procedure.
    38         -**
    39         -**   * If iFrame is +ve, then the nth frame from the bottom of the stack.
    40         -**     An iFrame value of 1 means the toplevel (global) frame.
    41         -*/
    42         -int Th_Eval(Th_Interp *interp, int iFrame, const char *zProg, int nProg);
    43         -
    44         -/*
    45         -** Evaluate a TH expression. The result is stored in the 
    46         -** interpreter result.
    47         -*/
    48         -int Th_Expr(Th_Interp *interp, const char *, int);
    49         -
    50         -/* 
    51         -** Access TH variables in the current stack frame. If the variable name
    52         -** begins with "::", the lookup is in the top level (global) frame. 
    53         -*/
    54         -int Th_GetVar(Th_Interp *, const char *, int);
    55         -int Th_SetVar(Th_Interp *, const char *, int, const char *, int);
    56         -int Th_LinkVar(Th_Interp *, const char *, int, int, const char *, int);
    57         -int Th_UnsetVar(Th_Interp *, const char *, int);
    58         -
    59         -typedef int (*Th_CommandProc)(Th_Interp *, void *, int, const char **, int *);
    60         -
    61         -/* 
    62         -** Register new commands. 
    63         -*/
    64         -int Th_CreateCommand(
    65         -  Th_Interp *interp, 
    66         -  const char *zName, 
    67         -  /* int (*xProc)(Th_Interp *, void *, int, const char **, int *), */
    68         -  Th_CommandProc xProc,
    69         -  void *pContext,
    70         -  void (*xDel)(Th_Interp *, void *)
    71         -);
    72         -
    73         -/* 
    74         -** Delete or rename commands.
    75         -*/
    76         -int Th_RenameCommand(Th_Interp *, const char *, int, const char *, int);
    77         -
    78         -/* 
    79         -** Push a new stack frame (local variable context) onto the interpreter 
    80         -** stack, call the function supplied as parameter xCall with the two 
    81         -** context arguments, 
    82         -**
    83         -**   xCall(interp, pContext1, pContext2)
    84         -**
    85         -** , then pop the frame off of the interpreter stack. The value returned
    86         -** by the xCall() function is returned as the result of this function.
    87         -**
    88         -** This is intended for use by the implementation of commands such as
    89         -** those created by [proc].
    90         -*/
    91         -int Th_InFrame(Th_Interp *interp,
    92         -  int (*xCall)(Th_Interp *, void *pContext1, void *pContext2),
    93         -  void *pContext1,
    94         -  void *pContext2
    95         -);
    96         -
    97         -/* 
    98         -** Valid return codes for xProc callbacks.
    99         -*/
   100         -#define TH_OK       0
   101         -#define TH_ERROR    1
   102         -#define TH_BREAK    2
   103         -#define TH_RETURN   3
   104         -#define TH_CONTINUE 4
   105         -
   106         -/* 
   107         -** Set and get the interpreter result. 
   108         -*/
   109         -int Th_SetResult(Th_Interp *, const char *, int);
   110         -const char *Th_GetResult(Th_Interp *, int *);
   111         -char *Th_TakeResult(Th_Interp *, int *);
   112         -
   113         -/*
   114         -** Set an error message as the interpreter result. This also
   115         -** sets the global stack-trace variable $::th_stack_trace.
   116         -*/
   117         -int Th_ErrorMessage(Th_Interp *, const char *, const char *, int);
   118         -
   119         -/* 
   120         -** Access the memory management functions associated with the specified
   121         -** interpreter.
   122         -*/
   123         -void *Th_Malloc(Th_Interp *, int);
   124         -void Th_Free(Th_Interp *, void *);
   125         -
   126         -/* 
   127         -** Functions for handling TH lists.
   128         -*/
   129         -int Th_ListAppend(Th_Interp *, char **, int *, const char *, int);
   130         -int Th_SplitList(Th_Interp *, const char *, int, char ***, int **, int *);
   131         -
   132         -int Th_StringAppend(Th_Interp *, char **, int *, const char *, int);
   133         -
   134         -/* 
   135         -** Functions for handling numbers and pointers.
   136         -*/
   137         -int Th_ToInt(Th_Interp *, const char *, int, int *);
   138         -int Th_ToDouble(Th_Interp *, const char *, int, double *);
   139         -int Th_SetResultInt(Th_Interp *, int);
   140         -int Th_SetResultDouble(Th_Interp *, double);
   141         -
   142         -/*
   143         -** Drop in replacements for the corresponding standard library functions.
   144         -*/
   145         -int th_strlen(const char *);
   146         -int th_isdigit(char);
   147         -int th_isspace(char);
   148         -int th_isalnum(char);
   149         -int th_isspecial(char);
   150         -char *th_strdup(Th_Interp *interp, const char *z, int n);
   151         -
   152         -/*
   153         -** Interfaces to register the language extensions.
   154         -*/
   155         -int th_register_language(Th_Interp *interp);            /* th_lang.c */
   156         -int th_register_sqlite(Th_Interp *interp);              /* th_sqlite.c */
   157         -int th_register_vfs(Th_Interp *interp);                 /* th_vfs.c */
   158         -int th_register_testvfs(Th_Interp *interp);             /* th_testvfs.c */
   159         -int th_register_tcl(Th_Interp *interp, void *pContext); /* th_tcl.c */
   160         -
   161         -/*
   162         -** General purpose hash table from th_lang.c.
   163         -*/
   164         -typedef struct Th_Hash      Th_Hash;
   165         -typedef struct Th_HashEntry Th_HashEntry;
   166         -struct Th_HashEntry {
   167         -  void *pData;
   168         -  char *zKey;
   169         -  int nKey;
   170         -  Th_HashEntry *pNext;     /* Internal use only */
   171         -};
   172         -Th_Hash *Th_HashNew(Th_Interp *);
   173         -void Th_HashDelete(Th_Interp *, Th_Hash *);
   174         -void Th_HashIterate(Th_Interp*,Th_Hash*,void (*x)(Th_HashEntry*, void*),void*);
   175         -Th_HashEntry *Th_HashFind(Th_Interp*, Th_Hash*, const char*, int, int);
   176         -
   177         -/*
   178         -** Useful functions from th_lang.c.
   179         -*/
   180         -int Th_WrongNumArgs(Th_Interp *interp, const char *zMsg);
   181         -
   182         -typedef struct Th_SubCommand {char *zName; Th_CommandProc xProc;} Th_SubCommand;
   183         -int Th_CallSubCommand(Th_Interp*,void*,int,const char**,int*,Th_SubCommand*);

Deleted src/th_lang.c.

     1         -
     2         -/*
     3         -** This file contains the implementation of all of the TH language 
     4         -** built-in commands. 
     5         -**
     6         -** All built-in commands are implemented using the public interface 
     7         -** declared in th.h, so this file serves as both a part of the language 
     8         -** implementation and an example of how to extend the language with
     9         -** new commands.
    10         -*/
    11         -
    12         -#include "config.h"
    13         -#include "th.h"
    14         -#include <string.h>
    15         -#include <assert.h>
    16         -
    17         -int Th_WrongNumArgs(Th_Interp *interp, const char *zMsg){
    18         -  Th_ErrorMessage(interp, "wrong # args: should be \"", zMsg, -1);
    19         -  return TH_ERROR;
    20         -}
    21         -
    22         -/*
    23         -** Syntax: 
    24         -**
    25         -**   catch script ?varname?
    26         -*/
    27         -static int catch_command(
    28         -  Th_Interp *interp, 
    29         -  void *ctx, 
    30         -  int argc, 
    31         -  const char **argv, 
    32         -  int *argl
    33         -){
    34         -  int rc;
    35         -
    36         -  if( argc!=2 && argc!=3 ){
    37         -    return Th_WrongNumArgs(interp, "catch script ?varname?");
    38         -  }
    39         -
    40         -  rc = Th_Eval(interp, 0, argv[1], -1);
    41         -  if( argc==3 ){
    42         -    int nResult;
    43         -    const char *zResult = Th_GetResult(interp, &nResult);
    44         -    Th_SetVar(interp, argv[2], argl[2], zResult, nResult);
    45         -  }
    46         -
    47         -  Th_SetResultInt(interp, rc);
    48         -  return TH_OK;
    49         -}
    50         -
    51         -/*
    52         -** TH Syntax: 
    53         -**
    54         -**   if expr1 body1 ?elseif expr2 body2? ? ?else? bodyN?
    55         -*/
    56         -static int if_command(
    57         -  Th_Interp *interp, 
    58         -  void *ctx, 
    59         -  int argc, 
    60         -  const char **argv, 
    61         -  int *argl
    62         -){
    63         -  int rc = TH_OK;
    64         -
    65         -  int iCond;           /* Result of evaluating expression */
    66         -  int i;
    67         -
    68         -  const char *zResult;
    69         -  int nResult;
    70         -
    71         -  if( argc<3 ){
    72         -    goto wrong_args;
    73         -  }
    74         -
    75         -  for(i=0; i<argc && rc==TH_OK; i+=3){
    76         -    if( i>argc-3 ){
    77         -      i = argc-3;
    78         -      iCond = 1;
    79         -    }else{
    80         -      if( TH_OK!=Th_Expr(interp, argv[i+1], argl[i+1]) ){
    81         -        return TH_ERROR;
    82         -      }
    83         -      zResult = Th_GetResult(interp, &nResult);
    84         -      rc = Th_ToInt(interp, zResult, nResult, &iCond);
    85         -    }
    86         -    if( iCond && rc==TH_OK ){
    87         -      rc = Th_Eval(interp, 0, argv[i+2], -1);
    88         -      break;
    89         -    }
    90         -  }
    91         -
    92         -  return rc;
    93         -
    94         -wrong_args:
    95         -  return Th_WrongNumArgs(interp, "if ...");
    96         -}
    97         -
    98         -/*
    99         -** TH Syntax: 
   100         -**
   101         -**   expr expr
   102         -*/
   103         -static int expr_command(
   104         -  Th_Interp *interp, 
   105         -  void *ctx, 
   106         -  int argc, 
   107         -  const char **argv, 
   108         -  int *argl
   109         -){
   110         -  if( argc!=2 ){
   111         -    return Th_WrongNumArgs(interp, "expr expression");
   112         -  }
   113         -
   114         -  return Th_Expr(interp, argv[1], argl[1]);
   115         -}
   116         -
   117         -/*
   118         -** Evaluate the th1 script (zBody, nBody) in the local stack frame. 
   119         -** Return the result of the evaluation, except if the result
   120         -** is TH_CONTINUE, return TH_OK instead.
   121         -*/
   122         -static int eval_loopbody(Th_Interp *interp, const char *zBody, int nBody){
   123         -  int rc = Th_Eval(interp, 0, zBody, nBody);
   124         -  if( rc==TH_CONTINUE ){
   125         -    rc = TH_OK;
   126         -  }
   127         -  return rc;
   128         -}
   129         -
   130         -/*
   131         -** TH Syntax: 
   132         -**
   133         -**   for init condition incr script
   134         -*/
   135         -static int for_command(
   136         -  Th_Interp *interp, 
   137         -  void *ctx, 
   138         -  int argc, 
   139         -  const char **argv, 
   140         -  int *argl
   141         -){
   142         -  int rc;
   143         -  int iCond;
   144         -
   145         -  if( argc!=5 ){
   146         -    return Th_WrongNumArgs(interp, "for init condition incr script");
   147         -  }
   148         -
   149         -  /* Evaluate the 'init' script */
   150         -  rc = Th_Eval(interp, 0, argv[1], -1);
   151         -
   152         -  while( rc==TH_OK 
   153         -     && TH_OK==(rc = Th_Expr(interp, argv[2], -1))
   154         -     && TH_OK==(rc = Th_ToInt(interp, Th_GetResult(interp, 0), -1, &iCond))
   155         -     && iCond
   156         -     && TH_OK==(rc = eval_loopbody(interp, argv[4], argl[4]))
   157         -  ){
   158         -    rc = Th_Eval(interp, 0, argv[3], -1);
   159         -  }
   160         -
   161         -  if( rc==TH_BREAK ) rc = TH_OK;
   162         -  return rc;
   163         -}
   164         -
   165         -/*
   166         -** TH Syntax: 
   167         -**
   168         -**   list ?arg1 ?arg2? ...?
   169         -*/
   170         -static int list_command(
   171         -  Th_Interp *interp, 
   172         -  void *ctx, 
   173         -  int argc, 
   174         -  const char **argv, 
   175         -  int *argl
   176         -){
   177         -  char *zList = 0;
   178         -  int nList = 0;
   179         -  int i;
   180         -
   181         -  for(i=1; i<argc; i++){
   182         -    Th_ListAppend(interp, &zList, &nList, argv[i], argl[i]);
   183         -  }
   184         - 
   185         -  Th_SetResult(interp, zList, nList);
   186         -  Th_Free(interp, zList);
   187         -
   188         -  return TH_OK;
   189         -}
   190         -
   191         -/*
   192         -** TH Syntax: 
   193         -**
   194         -**   lindex list index
   195         -*/
   196         -static int lindex_command(
   197         -  Th_Interp *interp, 
   198         -  void *ctx, 
   199         -  int argc, 
   200         -  const char **argv, 
   201         -  int *argl
   202         -){
   203         -  int iElem;
   204         -  int rc;
   205         -
   206         -  char **azElem;
   207         -  int *anElem;
   208         -  int nCount;
   209         -
   210         -  if( argc!=3 ){
   211         -    return Th_WrongNumArgs(interp, "lindex list index");
   212         -  }
   213         -
   214         -  if( TH_OK!=Th_ToInt(interp, argv[2], argl[2], &iElem) ){
   215         -    return TH_ERROR;
   216         -  }
   217         -
   218         -  rc = Th_SplitList(interp, argv[1], argl[1], &azElem, &anElem, &nCount);
   219         -  if( rc==TH_OK ){
   220         -    if( iElem<nCount && iElem>=0 ){
   221         -      Th_SetResult(interp, azElem[iElem], anElem[iElem]);
   222         -    }else{
   223         -      Th_SetResult(interp, 0, 0);
   224         -    }
   225         -    Th_Free(interp, azElem);
   226         -  }
   227         -
   228         -  return rc;
   229         -}
   230         -
   231         -/*
   232         -** TH Syntax: 
   233         -**
   234         -**   llength list
   235         -*/
   236         -static int llength_command(
   237         -  Th_Interp *interp, 
   238         -  void *ctx, 
   239         -  int argc, 
   240         -  const char **argv, 
   241         -  int *argl
   242         -){
   243         -  int nElem;
   244         -  int rc;
   245         -
   246         -  if( argc!=2 ){
   247         -    return Th_WrongNumArgs(interp, "llength list");
   248         -  }
   249         -
   250         -  rc = Th_SplitList(interp, argv[1], argl[1], 0, 0, &nElem);
   251         -  if( rc==TH_OK ){
   252         -    Th_SetResultInt(interp, nElem);
   253         -  }
   254         -
   255         -  return rc;
   256         -}
   257         -
   258         -/*
   259         -** TH Syntax: 
   260         -**
   261         -**   set varname ?value?
   262         -*/
   263         -static int set_command(
   264         -  Th_Interp *interp, 
   265         -  void *ctx, 
   266         -  int argc, 
   267         -  const char **argv, 
   268         -  int *argl
   269         -){
   270         -  if( argc!=2 && argc!=3 ){
   271         -    return Th_WrongNumArgs(interp, "set varname ?value?");
   272         -  }
   273         -
   274         -  if( argc==3 ){
   275         -    Th_SetVar(interp, argv[1], argl[1], argv[2], argl[2]);
   276         -  }
   277         -  return Th_GetVar(interp, argv[1], argl[1]);
   278         -}
   279         -
   280         -/*
   281         -** When a new command is created using the built-in [proc] command, an
   282         -** instance of the following structure is allocated and populated. A 
   283         -** pointer to the structure is passed as the context (second) argument 
   284         -** to function proc_call1() when the new command is executed.
   285         -*/
   286         -typedef struct ProcDefn ProcDefn;
   287         -struct ProcDefn {
   288         -  int nParam;                /* Number of formal (non "args") parameters */
   289         -  char **azParam;           /* Parameter names */
   290         -  int *anParam;              /* Lengths of parameter names */
   291         -  char **azDefault;         /* Default values */
   292         -  int *anDefault;            /* Lengths of default values */
   293         -  int hasArgs;               /* True if there is an "args" parameter */
   294         -  char *zProgram;           /* Body of proc */
   295         -  int nProgram;              /* Number of bytes at zProgram */
   296         -  char *zUsage;             /* Usage message */
   297         -  int nUsage;                /* Number of bytes at zUsage */
   298         -};
   299         -
   300         -/* This structure is used to temporarily store arguments passed to an 
   301         -** invocation of a command created using [proc]. A pointer to an 
   302         -** instance is passed as the second argument to the proc_call2() function.
   303         -*/
   304         -typedef struct ProcArgs ProcArgs;
   305         -struct ProcArgs {
   306         -  int argc;
   307         -  const char **argv;
   308         -  int *argl;
   309         -};
   310         -
   311         -/*
   312         -** Each time a command created using [proc] is invoked, a new
   313         -** th1 stack frame is allocated (for the proc's local variables) and
   314         -** this function invoked.
   315         -**
   316         -** Argument pContext1 points to the associated ProcDefn structure.
   317         -** Argument pContext2  points to a ProcArgs structure that contains
   318         -** the arguments passed to this specific invocation of the proc.
   319         -*/
   320         -static int proc_call2(Th_Interp *interp, void *pContext1, void *pContext2){
   321         -  int i;
   322         -  ProcDefn *p = (ProcDefn *)pContext1;
   323         -  ProcArgs *pArgs = (ProcArgs *)pContext2;
   324         -
   325         -  /* Check if there are the right number of arguments. If there are
   326         -  ** not, generate a usage message for the command.
   327         -  */
   328         -  if( (pArgs->argc>(p->nParam+1) && !p->hasArgs) 
   329         -   || (pArgs->argc<=(p->nParam) && !p->azDefault[pArgs->argc-1])
   330         -  ){
   331         -    char *zUsage = 0;
   332         -    int nUsage = 0;
   333         -    Th_StringAppend(interp, &zUsage, &nUsage, pArgs->argv[0], pArgs->argl[0]);
   334         -    Th_StringAppend(interp, &zUsage, &nUsage, p->zUsage, p->nUsage);
   335         -    Th_StringAppend(interp, &zUsage, &nUsage, (const char *)"", 1);
   336         -    Th_WrongNumArgs(interp, zUsage);
   337         -    Th_Free(interp, zUsage);
   338         -    return TH_ERROR;
   339         -  }
   340         -
   341         -  /* Populate the formal proc parameters. */
   342         -  for(i=0; i<p->nParam; i++){
   343         -    const char *zVal;
   344         -    int nVal;
   345         -    if( pArgs->argc>(i+1) ){
   346         -      zVal = pArgs->argv[i+1];
   347         -      nVal = pArgs->argl[i+1];
   348         -    }else{
   349         -      zVal = p->azDefault[i];
   350         -      nVal = p->anDefault[i];
   351         -    }
   352         -    Th_SetVar(interp, p->azParam[i], p->anParam[i], zVal, nVal);
   353         -  }
   354         -
   355         -  /* Populate the "args" parameter, if it exists */
   356         -  if( p->hasArgs ){
   357         -    char *zArgs = 0;
   358         -    int nArgs = 0;
   359         -    for(i=p->nParam+1; i<pArgs->argc; i++){
   360         -      Th_ListAppend(interp, &zArgs, &nArgs, pArgs->argv[i], pArgs->argl[i]);
   361         -    }
   362         -    Th_SetVar(interp, (const char *)"args", -1, zArgs, nArgs);
   363         -  }
   364         -
   365         -  Th_SetResult(interp, 0, 0);
   366         -  return Th_Eval(interp, 0, p->zProgram, p->nProgram);
   367         -}
   368         -
   369         -/*
   370         -** This function is the command callback registered for all commands
   371         -** created using the [proc] command. The second argument, pContext,
   372         -** is a pointer to the associated ProcDefn structure.
   373         -*/
   374         -static int proc_call1(
   375         -  Th_Interp *interp,
   376         -  void *pContext, 
   377         -  int argc, 
   378         -  const char **argv,
   379         -  int *argl
   380         -){
   381         -  int rc;
   382         -
   383         -  ProcDefn *p = (ProcDefn *)pContext;
   384         -  ProcArgs procargs;
   385         -
   386         -  /* Call function proc_call2(), which will call Th_Eval() to evaluate
   387         -  ** the body of the [proc], in a new Th stack frame. This is so that
   388         -  ** the proc body has its own local variable context.
   389         -  */
   390         -  procargs.argc = argc;
   391         -  procargs.argv = argv;
   392         -  procargs.argl = argl;
   393         -  rc = Th_InFrame(interp, proc_call2, (void *)p, (void *)&procargs);
   394         -
   395         -  if( rc==TH_RETURN ){
   396         -    rc = TH_OK;
   397         -  }
   398         -  return rc;
   399         -}
   400         -
   401         -/*
   402         -** This function is registered as the delete callback for all commands 
   403         -** created using the built-in [proc] command. It is called automatically 
   404         -** when a command created using [proc] is deleted. 
   405         -**
   406         -** It frees the ProcDefn structure allocated when the command was created.
   407         -*/ 
   408         -static void proc_del(Th_Interp *interp, void *pContext){
   409         -  ProcDefn *p = (ProcDefn *)pContext;
   410         -  Th_Free(interp, (void *)p->zUsage);
   411         -  Th_Free(interp, (void *)p);
   412         -}
   413         -
   414         -/*
   415         -** TH Syntax: 
   416         -**
   417         -**   proc name arglist code
   418         -*/
   419         -static int proc_command(
   420         -  Th_Interp *interp, 
   421         -  void *ctx, 
   422         -  int argc,
   423         -  const char **argv, 
   424         -  int *argl
   425         -){
   426         -  int rc;
   427         -  char *zName;
   428         -
   429         -  ProcDefn *p;
   430         -  int nByte;
   431         -  int i;
   432         -  char *zSpace;
   433         -
   434         -  char **azParam;
   435         -  int *anParam;
   436         -  int nParam;
   437         -
   438         -  char *zUsage = 0;               /* Build up a usage message here */
   439         -  int nUsage = 0;                  /* Number of bytes at zUsage */
   440         -
   441         -  if( argc!=4 ){
   442         -    return Th_WrongNumArgs(interp, "proc name arglist code");
   443         -  }
   444         -  if( Th_SplitList(interp, argv[2], argl[2], &azParam, &anParam, &nParam) ){
   445         -    return TH_ERROR;
   446         -  }
   447         -
   448         -  /* Allocate the new ProcDefn structure. */
   449         -  nByte = sizeof(ProcDefn) +                        /* ProcDefn structure */
   450         -      (sizeof(char *) + sizeof(int)) * nParam +    /* azParam, anParam */
   451         -      (sizeof(char *) + sizeof(int)) * nParam +    /* azDefault, anDefault */
   452         -      argl[3] +                                     /* zProgram */
   453         -      argl[2];     /* Space for copies of parameter names and default values */
   454         -  p = (ProcDefn *)Th_Malloc(interp, nByte);
   455         -
   456         -  /* If the last parameter in the parameter list is "args", then set the
   457         -  ** ProcDefn.hasArgs flag. The "args" parameter does not require an
   458         -  ** entry in the ProcDefn.azParam[] or ProcDefn.azDefault[] arrays.
   459         -  */
   460         -  if( anParam[nParam-1]==4 && 0==memcmp(azParam[nParam-1], "args", 4) ){
   461         -    p->hasArgs = 1;
   462         -    nParam--;
   463         -  }
   464         -
   465         -  p->nParam    = nParam;
   466         -  p->azParam   = (char **)&p[1];
   467         -  p->anParam   = (int *)&p->azParam[nParam];
   468         -  p->azDefault = (char **)&p->anParam[nParam];
   469         -  p->anDefault = (int *)&p->azDefault[nParam];
   470         -  p->zProgram = (char *)&p->anDefault[nParam];
   471         -  memcpy(p->zProgram, argv[3], argl[3]);
   472         -  p->nProgram = argl[3];
   473         -  zSpace = &p->zProgram[p->nProgram];
   474         -  
   475         -  for(i=0; i<nParam; i++){
   476         -    char **az;
   477         -    int *an;
   478         -    int n;
   479         -    if( Th_SplitList(interp, azParam[i], anParam[i], &az, &an, &n) ){
   480         -      goto error_out;
   481         -    }
   482         -    if( n<1 || n>2 ){
   483         -      const char expected[] = "expected parameter, got \"";
   484         -      Th_ErrorMessage(interp, expected, azParam[i], anParam[i]);
   485         -      Th_Free(interp, az);
   486         -      goto error_out;
   487         -    }
   488         -    p->anParam[i] = an[0];
   489         -    p->azParam[i] = zSpace;
   490         -    memcpy(zSpace, az[0], an[0]);
   491         -    zSpace += an[0];
   492         -    if( n==2 ){
   493         -      p->anDefault[i] = an[1];
   494         -      p->azDefault[i] = zSpace;
   495         -      memcpy(zSpace, az[1], an[1]);
   496         -      zSpace += an[1];
   497         -    }
   498         -
   499         -    Th_StringAppend(interp, &zUsage, &nUsage, (const char *)" ", 1);
   500         -    if( n==2 ){
   501         -      Th_StringAppend(interp, &zUsage, &nUsage, (const char *)"?", 1);
   502         -      Th_StringAppend(interp, &zUsage, &nUsage, az[0], an[0]);
   503         -      Th_StringAppend(interp, &zUsage, &nUsage, (const char *)"?", 1);
   504         -    }else{
   505         -      Th_StringAppend(interp, &zUsage, &nUsage, az[0], an[0]);
   506         -    }
   507         -
   508         -    Th_Free(interp, az);
   509         -  }
   510         -  assert( zSpace-(char *)p<=nByte );
   511         -
   512         -  /* If there is an "args" parameter, append it to the end of the usage
   513         -  ** message. Set ProcDefn.zUsage to point at the usage message. It will
   514         -  ** be freed along with the rest of the proc-definition by proc_del().
   515         -  */
   516         -  if( p->hasArgs ){
   517         -    Th_StringAppend(interp, &zUsage, &nUsage, (const char *)" ?args...?", -1);
   518         -  }
   519         -  p->zUsage = zUsage;
   520         -  p->nUsage = nUsage;
   521         -
   522         -  /* Register the new command with the th1 interpreter. */
   523         -  zName = (char *)argv[1];
   524         -  rc = Th_CreateCommand(interp, zName, proc_call1, (void *)p, proc_del);
   525         -  if( rc==TH_OK ){
   526         -    Th_SetResult(interp, 0, 0);
   527         -  }
   528         -
   529         -  Th_Free(interp, azParam);
   530         -  return TH_OK;
   531         -
   532         - error_out:
   533         -  Th_Free(interp, azParam);
   534         -  Th_Free(interp, zUsage);
   535         -  return TH_ERROR;
   536         -}
   537         -
   538         -/*
   539         -** TH Syntax: 
   540         -**
   541         -**   rename oldcmd newcmd
   542         -*/
   543         -static int rename_command(
   544         -  Th_Interp *interp, 
   545         -  void *ctx, 
   546         -  int argc,
   547         -  const char **argv, 
   548         -  int *argl
   549         -){
   550         -  if( argc!=3 ){
   551         -    return Th_WrongNumArgs(interp, "rename oldcmd newcmd");
   552         -  }
   553         -  return Th_RenameCommand(interp, argv[1], argl[1], argv[2], argl[2]);
   554         -}
   555         -
   556         -/*
   557         -** TH Syntax: 
   558         -**
   559         -**   break    ?value...?
   560         -**   continue ?value...?
   561         -**   ok       ?value...?
   562         -**   error    ?value...?
   563         -*/
   564         -static int simple_command(
   565         -  Th_Interp *interp, 
   566         -  void *ctx, 
   567         -  int argc, 
   568         -  const char **argv, 
   569         -  int *argl
   570         -){
   571         -  if( argc!=1 && argc!=2 ){
   572         -    return Th_WrongNumArgs(interp, "return ?value?");
   573         -  }
   574         -  if( argc==2 ){
   575         -    Th_SetResult(interp, argv[1], argl[1]);
   576         -  }
   577         -  return FOSSIL_PTR_TO_INT(ctx);
   578         -}
   579         -
   580         -/*
   581         -** TH Syntax: 
   582         -**
   583         -**   return ?-code code? ?value?
   584         -*/
   585         -static int return_command(
   586         -  Th_Interp *interp, 
   587         -  void *ctx, 
   588         -  int argc, 
   589         -  const char **argv, 
   590         -  int *argl
   591         -){
   592         -  int iCode = TH_RETURN;
   593         -  if( argc<1 || argc>4 ){
   594         -    return Th_WrongNumArgs(interp, "return ?-code code? ?value?");
   595         -  }
   596         -  if( argc>2 ){
   597         -    int rc = Th_ToInt(interp, argv[2], argl[2], &iCode);
   598         -    if( rc!=TH_OK ){
   599         -      return rc;
   600         -    }
   601         -  }
   602         -  if( argc==2 || argc==4 ){
   603         -    Th_SetResult(interp, argv[argc-1], argl[argc-1]);
   604         -  }
   605         -  return iCode;
   606         -}
   607         -
   608         -/*
   609         -** TH Syntax:
   610         -**
   611         -**   string compare STRING1 STRING2
   612         -*/
   613         -static int string_compare_command(
   614         -  Th_Interp *interp, void *ctx, int argc, const char **argv, int *argl
   615         -){
   616         -  const char *zRight; int nRight;
   617         -  const char *zLeft; int nLeft;
   618         -
   619         -  int i;
   620         -  int iRes = 0;
   621         -
   622         -  if( argc!=4 ){
   623         -    return Th_WrongNumArgs(interp, "string compare str1 str2");
   624         -  }
   625         -
   626         -  zLeft = argv[2];
   627         -  nLeft = argl[2];
   628         -  zRight = argv[3];
   629         -  nRight = argl[3];
   630         -
   631         -  for(i=0; iRes==0 && i<nLeft && i<nRight; i++){
   632         -    iRes = zLeft[i]-zRight[i];
   633         -  }
   634         -  if( iRes==0 ){
   635         -    iRes = nLeft-nRight;
   636         -  }
   637         -
   638         -  if( iRes<0 ) iRes = -1;
   639         -  if( iRes>0 ) iRes = 1;
   640         -  
   641         -  return Th_SetResultInt(interp, iRes);
   642         -}
   643         -
   644         -/*
   645         -** TH Syntax:
   646         -**
   647         -**   string first NEEDLE HAYSTACK
   648         -*/
   649         -static int string_first_command(
   650         -  Th_Interp *interp, void *ctx, int argc, const char **argv, int *argl
   651         -){
   652         -  const char *zNeedle;
   653         -  int nNeedle;
   654         -  const char *zHaystack;
   655         -  int nHaystack;
   656         -  int i;
   657         -  int iRes = -1;
   658         -
   659         -  if( argc!=4 ){
   660         -    return Th_WrongNumArgs(interp, "string first needle haystack");
   661         -  }
   662         -
   663         -  zNeedle = argv[2];
   664         -  nNeedle = argl[2];
   665         -  zHaystack = argv[3];
   666         -  nHaystack = argl[3];
   667         -
   668         -  for(i=0; i<(nHaystack-nNeedle); i++){
   669         -    if( 0==memcmp(zNeedle, &zHaystack[i], nNeedle) ){
   670         -      iRes = i;
   671         -      break;
   672         -    }
   673         -  }
   674         -  
   675         -  return Th_SetResultInt(interp, iRes);
   676         -}
   677         -
   678         -/*
   679         -** TH Syntax:
   680         -**
   681         -**   string is CLASS STRING
   682         -*/
   683         -static int string_is_command(
   684         -  Th_Interp *interp, void *ctx, int argc, const char **argv, int *argl
   685         -){
   686         -  int i;
   687         -  int iRes = 1;
   688         -  if( argc!=4 ){
   689         -    return Th_WrongNumArgs(interp, "string is class string");
   690         -  }
   691         -  if( argl[2]!=5 || 0!=memcmp(argv[2], "alnum", 5) ){
   692         -    Th_ErrorMessage(interp, "Expected alnum, got: ", argv[2], argl[2]);
   693         -    return TH_ERROR;
   694         -  }
   695         -
   696         -  for(i=0; i<argl[3]; i++){
   697         -    if( !th_isalnum(argv[3][i]) ){
   698         -      iRes = 0;
   699         -    }
   700         -  }
   701         -
   702         -  return Th_SetResultInt(interp, iRes);
   703         -}
   704         -
   705         -/*
   706         -** TH Syntax:
   707         -**
   708         -**   string last NEEDLE HAYSTACK
   709         -*/
   710         -static int string_last_command(
   711         -  Th_Interp *interp, void *ctx, int argc, const char **argv, int *argl
   712         -){
   713         -  const char *zNeedle;
   714         -  int nNeedle;
   715         -  const char *zHaystack;
   716         -  int nHaystack;
   717         -  int i;
   718         -  int iRes = -1;
   719         -
   720         -  if( argc!=4 ){
   721         -    return Th_WrongNumArgs(interp, "string first needle haystack");
   722         -  }
   723         -
   724         -  zNeedle = argv[2];
   725         -  nNeedle = argl[2];
   726         -  zHaystack = argv[3];
   727         -  nHaystack = argl[3];
   728         -
   729         -  for(i=nHaystack-nNeedle-1; i>=0; i--){
   730         -    if( 0==memcmp(zNeedle, &zHaystack[i], nNeedle) ){
   731         -      iRes = i;
   732         -      break;
   733         -    }
   734         -  }
   735         -  
   736         -  return Th_SetResultInt(interp, iRes);
   737         -}
   738         -
   739         -/*
   740         -** TH Syntax:
   741         -**
   742         -**   string length STRING
   743         -*/
   744         -static int string_length_command(
   745         -  Th_Interp *interp, void *ctx, int argc, const char **argv, int *argl
   746         -){
   747         -  if( argc!=3 ){
   748         -    return Th_WrongNumArgs(interp, "string length string");
   749         -  }
   750         -  return Th_SetResultInt(interp, argl[2]);
   751         -}
   752         -
   753         -/*
   754         -** TH Syntax:
   755         -**
   756         -**   string range STRING FIRST LAST
   757         -*/
   758         -static int string_range_command(
   759         -  Th_Interp *interp, void *ctx, int argc, const char **argv, int *argl
   760         -){
   761         -  int iStart;
   762         -  int iEnd;
   763         -
   764         -  if( argc!=5 ){
   765         -    return Th_WrongNumArgs(interp, "string range string first last");
   766         -  }
   767         -
   768         -  if( argl[4]==3 && 0==memcmp("end", argv[4], 3) ){
   769         -    iEnd = argl[2];
   770         -  }else if( Th_ToInt(interp, argv[4], argl[4], &iEnd) ){
   771         -    Th_ErrorMessage(
   772         -        interp, "Expected \"end\" or integer, got:", argv[4], argl[4]);
   773         -    return TH_ERROR;
   774         -  }
   775         -  if( Th_ToInt(interp, argv[3], argl[3], &iStart) ){
   776         -    return TH_ERROR;
   777         -  }
   778         -
   779         -  if( iStart<0 ) iStart = 0;
   780         -  if( iEnd>=argl[2] ) iEnd = argl[2]-1;
   781         -  if( iStart>iEnd ) iEnd = iStart-1;
   782         -
   783         -  return Th_SetResult(interp, &argv[2][iStart], iEnd-iStart+1);
   784         -}
   785         -
   786         -/*
   787         -** TH Syntax:
   788         -**
   789         -**   string repeat STRING COUNT
   790         -*/
   791         -static int string_repeat_command(
   792         -  Th_Interp *interp, void *ctx, int argc, const char **argv, int *argl
   793         -){
   794         -  int n;
   795         -  int i;
   796         -  int nByte;
   797         -  char *zByte;
   798         -
   799         -  if( argc!=4 ){
   800         -    return Th_WrongNumArgs(interp, "string repeat string n");
   801         -  }
   802         -  if( Th_ToInt(interp, argv[3], argl[3], &n) ){
   803         -    return TH_ERROR;
   804         -  }
   805         -
   806         -  nByte = argl[2] * n;
   807         -  zByte = Th_Malloc(interp, nByte+1);
   808         -  for(i=0; i<nByte; i+=argl[2]){
   809         -    memcpy(&zByte[i], argv[2], argl[2]);
   810         -  }
   811         -
   812         -  Th_SetResult(interp, zByte, nByte);
   813         -  Th_Free(interp, zByte);
   814         -  return TH_OK;
   815         -}
   816         -
   817         -/*
   818         -** TH Syntax:
   819         -**
   820         -**   info exists VAR
   821         -*/
   822         -static int info_exists_command(
   823         -  Th_Interp *interp, void *ctx, int argc, const char **argv, int *argl
   824         -){
   825         -  int rc;
   826         -
   827         -  if( argc!=3 ){
   828         -    return Th_WrongNumArgs(interp, "info exists var");
   829         -  }
   830         -  rc = Th_GetVar(interp, argv[2], argl[2]);
   831         -  Th_SetResultInt(interp, rc?0:1);
   832         -  return TH_OK;
   833         -}
   834         -
   835         -/*
   836         -** TH Syntax:
   837         -**
   838         -**   unset VAR
   839         -*/
   840         -static int unset_command(
   841         -  Th_Interp *interp, 
   842         -  void *ctx,
   843         -  int argc,
   844         -  const char **argv,
   845         -  int *argl
   846         -){
   847         -  if( argc!=2 ){
   848         -    return Th_WrongNumArgs(interp, "unset var");
   849         -  }
   850         -  return Th_UnsetVar(interp, argv[1], argl[1]);
   851         -}
   852         -
   853         -int Th_CallSubCommand(
   854         -  Th_Interp *interp, 
   855         -  void *ctx,
   856         -  int argc,
   857         -  const char **argv,
   858         -  int *argl,
   859         -  Th_SubCommand *aSub
   860         -){
   861         -  int i;
   862         -  for(i=0; aSub[i].zName; i++){
   863         -    char *zName = (char *)aSub[i].zName;
   864         -    if( th_strlen(zName)==argl[1] && 0==memcmp(zName, argv[1], argl[1]) ){
   865         -      return aSub[i].xProc(interp, ctx, argc, argv, argl);
   866         -    }
   867         -  }
   868         -
   869         -  Th_ErrorMessage(interp, "Expected sub-command, got:", argv[1], argl[1]);
   870         -  return TH_ERROR;
   871         -}
   872         -
   873         -/*
   874         -** TH Syntax:
   875         -**
   876         -**   string compare STR1 STR2
   877         -**   string first   NEEDLE HAYSTACK ?STARTINDEX?
   878         -**   string is      CLASS STRING
   879         -**   string last    NEEDLE HAYSTACK ?STARTINDEX?
   880         -**   string length  STRING
   881         -**   string range   STRING FIRST LAST
   882         -**   string repeat  STRING COUNT
   883         -*/
   884         -static int string_command(
   885         -  Th_Interp *interp, 
   886         -  void *ctx,
   887         -  int argc,
   888         -  const char **argv,
   889         -  int *argl
   890         -){
   891         -  Th_SubCommand aSub[] = {
   892         -    { "compare", string_compare_command },
   893         -    { "first",   string_first_command },
   894         -    { "is",      string_is_command },
   895         -    { "last",    string_last_command },
   896         -    { "length",  string_length_command },
   897         -    { "range",   string_range_command },
   898         -    { "repeat",  string_repeat_command },
   899         -    { 0, 0 }
   900         -  };
   901         -  return Th_CallSubCommand(interp, ctx, argc, argv, argl, aSub);
   902         -}
   903         -
   904         -/*
   905         -** TH Syntax:
   906         -**
   907         -**   info exists VARNAME
   908         -*/
   909         -static int info_command(
   910         -  Th_Interp *interp, 
   911         -  void *ctx,
   912         -  int argc,
   913         -  const char **argv,
   914         -  int *argl
   915         -){
   916         -  Th_SubCommand aSub[] = {
   917         -    { "exists",  info_exists_command },
   918         -    { 0, 0 }
   919         -  };
   920         -  return Th_CallSubCommand(interp, ctx, argc, argv, argl, aSub);
   921         -}
   922         -
   923         -/*
   924         -** Convert the script level frame specification (used by the commands 
   925         -** [uplevel] and [upvar]) in (zFrame, nFrame) to an integer frame as 
   926         -** used by Th_LinkVar() and Th_Eval(). If successful, write the integer
   927         -** frame level to *piFrame and return TH_OK. Otherwise, return TH_ERROR
   928         -** and leave an error message in the interpreter result.
   929         -*/
   930         -static int thToFrame(
   931         -  Th_Interp *interp, 
   932         -  const char *zFrame, 
   933         -  int nFrame, 
   934         -  int *piFrame
   935         -){
   936         -  int iFrame;
   937         -  if( th_isdigit(zFrame[0]) ){
   938         -    int rc = Th_ToInt(interp, zFrame, nFrame, &iFrame);
   939         -    if( rc!=TH_OK ) return rc;
   940         -    iFrame = iFrame * -1;
   941         -  }else if( zFrame[0]=='#' ){
   942         -    int rc = Th_ToInt(interp, &zFrame[1], nFrame-1, &iFrame);
   943         -    if( rc!=TH_OK ) return rc;
   944         -    iFrame = iFrame + 1;
   945         -  }else{
   946         -    return TH_ERROR;
   947         -  }
   948         -  *piFrame = iFrame;
   949         -  return TH_OK;
   950         -}
   951         -
   952         -/*
   953         -** TH Syntax:
   954         -**
   955         -**   uplevel ?LEVEL? SCRIPT
   956         -*/
   957         -static int uplevel_command(
   958         -  Th_Interp *interp, 
   959         -  void *ctx,
   960         -  int argc,
   961         -  const char **argv,
   962         -  int *argl
   963         -){
   964         -  int iFrame = -1;
   965         -
   966         -  if( argc!=2 && argc!=3 ){
   967         -    return Th_WrongNumArgs(interp, "uplevel ?level? script...");
   968         -  }
   969         -  if( argc==3 && TH_OK!=thToFrame(interp, argv[1], argl[1], &iFrame) ){
   970         -    return TH_ERROR;
   971         -  }
   972         -  return Th_Eval(interp, iFrame, argv[argc-1], -1);
   973         -}
   974         -
   975         -/*
   976         -** TH Syntax: 
   977         -**
   978         -**   upvar ?FRAME? OTHERVAR MYVAR ?OTHERVAR MYVAR ...?
   979         -*/
   980         -static int upvar_command(
   981         -  Th_Interp *interp, 
   982         -  void *ctx, 
   983         -  int argc, 
   984         -  const char **argv, 
   985         -  int *argl
   986         -){
   987         -  int iVar = 1;
   988         -  int iFrame = -1;
   989         -  int rc = TH_OK;
   990         -  int i;
   991         -
   992         -  if( TH_OK==thToFrame(0, argv[1], argl[1], &iFrame) ){
   993         -    iVar++;
   994         -  }
   995         -  if( argc==iVar || (argc-iVar)%2 ){
   996         -    return Th_WrongNumArgs(interp, 
   997         -        "upvar frame othervar myvar ?othervar myvar...?");
   998         -  }
   999         -  for(i=iVar; rc==TH_OK && i<argc; i=i+2){
  1000         -    rc = Th_LinkVar(interp, argv[i+1], argl[i+1], iFrame, argv[i], argl[i]);
  1001         -  }
  1002         -  return rc;
  1003         -}
  1004         -
  1005         -/*
  1006         -** TH Syntax: 
  1007         -**
  1008         -**   breakpoint ARGS
  1009         -**
  1010         -** This command does nothing at all. Its purpose in life is to serve
  1011         -** as a point for setting breakpoints in a debugger.
  1012         -*/
  1013         -static int breakpoint_command(
  1014         -  Th_Interp *interp, 
  1015         -  void *ctx, 
  1016         -  int argc, 
  1017         -  const char **argv, 
  1018         -  int *argl
  1019         -){
  1020         -  int cnt = 0;
  1021         -  cnt++;
  1022         -  return TH_OK;
  1023         -}
  1024         -
  1025         -/*
  1026         -** Register the built-in th1 language commands with interpreter interp.
  1027         -** Usually this is called soon after interpreter creation.
  1028         -*/
  1029         -int th_register_language(Th_Interp *interp){
  1030         -  /* Array of built-in commands. */
  1031         -  struct _Command {
  1032         -    const char *zName;
  1033         -    Th_CommandProc xProc;
  1034         -    void *pContext;
  1035         -  } aCommand[] = {
  1036         -    {"catch",    catch_command,   0},
  1037         -    {"expr",     expr_command,    0},
  1038         -    {"for",      for_command,     0},
  1039         -    {"if",       if_command,      0},
  1040         -    {"info",     info_command,    0},
  1041         -    {"lindex",   lindex_command,  0},
  1042         -    {"list",     list_command,    0},
  1043         -    {"llength",  llength_command, 0},
  1044         -    {"proc",     proc_command,    0}, 
  1045         -    {"rename",   rename_command,  0},
  1046         -    {"set",      set_command,     0},
  1047         -    {"string",   string_command,  0},
  1048         -    {"unset",    unset_command,   0},
  1049         -    {"uplevel",  uplevel_command, 0},
  1050         -    {"upvar",    upvar_command,   0},
  1051         -
  1052         -    {"breakpoint", breakpoint_command, 0},
  1053         -
  1054         -    {"return",   return_command, 0},
  1055         -    {"break",    simple_command, (void *)TH_BREAK}, 
  1056         -    {"continue", simple_command, (void *)TH_CONTINUE}, 
  1057         -    {"error",    simple_command, (void *)TH_ERROR}, 
  1058         -
  1059         -    {0, 0, 0}
  1060         -  };
  1061         -  int i;
  1062         -
  1063         -  /* Add the language commands. */
  1064         -  for(i=0; i<(sizeof(aCommand)/sizeof(aCommand[0])); i++){
  1065         -    void *ctx;
  1066         -    if ( !aCommand[i].zName || !aCommand[i].xProc ) continue;
  1067         -    ctx = aCommand[i].pContext;
  1068         -    Th_CreateCommand(interp, aCommand[i].zName, aCommand[i].xProc, ctx, 0);
  1069         -  }
  1070         -
  1071         -  return TH_OK;
  1072         -}

Changes to src/th_main.c.

    18     18   ** This file contains an interface between the TH scripting language
    19     19   ** (an independent project) and fossil.
    20     20   */
    21     21   #include "config.h"
    22     22   #include "th_main.h"
    23     23   
    24     24   /*
    25         -** Global variable counting the number of outstanding calls to malloc()
    26         -** made by the th1 implementation. This is used to catch memory leaks
    27         -** in the interpreter. Obviously, it also means th1 is not threadsafe.
           25  +** Interfaces to register the scripting language extensions.
    28     26   */
    29         -static int nOutstandingMalloc = 0;
    30         -
    31         -/*
    32         -** Implementations of malloc() and free() to pass to the interpreter.
    33         -*/
    34         -static void *xMalloc(unsigned int n){
    35         -  void *p = fossil_malloc(n);
    36         -  if( p ){
    37         -    nOutstandingMalloc++;
    38         -  }
    39         -  return p;
    40         -}
    41         -static void xFree(void *p){
    42         -  if( p ){
    43         -    nOutstandingMalloc--;
    44         -  }
    45         -  free(p);
    46         -}
    47         -static Th_Vtab vtab = { xMalloc, xFree };
           27  +int register_tcl(Jim_Interp *interp, void *pContext); /* th_tcl.c */
    48     28   
    49     29   /*
    50     30   ** Generate a TH1 trace message if debugging is enabled.
    51     31   */
    52     32   void Th_Trace(const char *zFormat, ...){
    53     33     va_list ap;
    54     34     va_start(ap, zFormat);
................................................................................
    56     36     va_end(ap);
    57     37   }
    58     38   
    59     39   
    60     40   /*
    61     41   ** True if output is enabled.  False if disabled.
    62     42   */
    63         -static int enableOutput = 1;
           43  +static long enableOutput = 1;
    64     44   
    65     45   /*
    66     46   ** TH command:     enable_output BOOLEAN
    67     47   **
    68     48   ** Enable or disable the puts and hputs commands.
    69     49   */
    70         -static int enableOutputCmd(
    71         -  Th_Interp *interp, 
    72         -  void *p, 
    73         -  int argc, 
    74         -  const char **argv, 
    75         -  int *argl
    76         -){
           50  +static int enableOutputCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
           51  +{
    77     52     if( argc!=2 ){
    78         -    return Th_WrongNumArgs(interp, "enable_output BOOLEAN");
           53  +    Jim_WrongNumArgs(interp, 1, argv, "BOOLEAN");
           54  +    return JIM_ERR;
    79     55     }
    80         -  return Th_ToInt(interp, argv[1], argl[1], &enableOutput);
           56  +  return Jim_GetLong(interp, argv[1], &enableOutput);
    81     57   }
    82     58   
    83     59   /*
    84     60   ** Send text to the appropriate output:  Either to the console
    85     61   ** or to the CGI reply buffer.
    86     62   */
    87     63   static void sendText(const char *z, int n, int encode){
................................................................................
    96     72       }else{
    97     73         fwrite(z, 1, n, stdout);
    98     74         fflush(stdout);
    99     75       }
   100     76       if( encode ) free((char*)z);
   101     77     }
   102     78   }
           79  +
           80  +static void sendTextObj(Jim_Obj *objPtr, int encode)
           81  +{
           82  +  sendText(Jim_String(objPtr), Jim_Length(objPtr), encode);
           83  +}
   103     84   
   104     85   /*
   105     86   ** TH command:     puts STRING
           87  +**
           88  +** Output STRING as HTML
           89  +*/
           90  +static int putsCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
           91  +{
           92  +  if( argc!=2 ){
           93  +    Jim_WrongNumArgs(interp, 1, argv, "STRING");
           94  +    return JIM_ERR;
           95  +  }
           96  +  sendText(Jim_String(argv[1]), -1, 1);
           97  +  return JIM_OK;
           98  +}
           99  +
          100  +/*
   106    101   ** TH command:     html STRING
   107    102   **
   108         -** Output STRING as HTML (html) or unchanged (puts).  
          103  +** Output STRING unchanged
   109    104   */
   110         -static int putsCmd(
   111         -  Th_Interp *interp, 
   112         -  void *pConvert, 
   113         -  int argc, 
   114         -  const char **argv, 
   115         -  int *argl
   116         -){
          105  +static int htmlCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
          106  +{
   117    107     if( argc!=2 ){
   118         -    return Th_WrongNumArgs(interp, "puts STRING");
          108  +    Jim_WrongNumArgs(interp, 1, argv, "STRING");
          109  +    return JIM_ERR;
   119    110     }
   120         -  sendText((char*)argv[1], argl[1], pConvert!=0);
   121         -  return TH_OK;
          111  +  sendText(Jim_String(argv[1]), -1, 0);
          112  +  return JIM_OK;
   122    113   }
   123    114   
   124    115   /*
   125    116   ** TH command:      wiki STRING
   126    117   **
   127    118   ** Render the input string as wiki.
   128    119   */
   129         -static int wikiCmd(
   130         -  Th_Interp *interp, 
   131         -  void *p, 
   132         -  int argc, 
   133         -  const char **argv, 
   134         -  int *argl
   135         -){
          120  +static int wikiCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
          121  +{
   136    122     if( argc!=2 ){
   137         -    return Th_WrongNumArgs(interp, "wiki STRING");
          123  +    Jim_WrongNumArgs(interp, 1, argv, "STRING");
          124  +    return JIM_ERR;
   138    125     }
   139    126     if( enableOutput ){
   140    127       Blob src;
   141         -    blob_init(&src, (char*)argv[1], argl[1]);
          128  +    blob_init(&src, Jim_String(argv[1]), Jim_Length(argv[1]));
   142    129       wiki_convert(&src, 0, WIKI_INLINE);
   143    130       blob_reset(&src);
   144    131     }
   145         -  return TH_OK;
          132  +  return JIM_OK;
   146    133   }
   147    134   
   148    135   /*
   149    136   ** TH command:      htmlize STRING
   150    137   **
   151    138   ** Escape all characters of STRING which have special meaning in HTML.
   152    139   ** Return a new string result.
   153    140   */
   154         -static int htmlizeCmd(
   155         -  Th_Interp *interp, 
   156         -  void *p, 
   157         -  int argc, 
   158         -  const char **argv, 
   159         -  int *argl
   160         -){
          141  +static int htmlizeCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
          142  +{
   161    143     char *zOut;
   162    144     if( argc!=2 ){
   163         -    return Th_WrongNumArgs(interp, "htmlize STRING");
          145  +    Jim_WrongNumArgs(interp, 1, argv, "STRING");
          146  +    return JIM_ERR;
   164    147     }
   165         -  zOut = htmlize((char*)argv[1], argl[1]);
   166         -  Th_SetResult(interp, zOut, -1);
          148  +  zOut = htmlize(Jim_String(argv[1]), Jim_Length(argv[1]));
          149  +  Jim_SetResultString(interp, zOut, -1);
   167    150     free(zOut);
   168         -  return TH_OK;
          151  +  return JIM_OK;
   169    152   }
   170    153   
   171    154   /*
   172    155   ** TH command:      date
   173    156   **
   174    157   ** Return a string which is the current time and date.  If the
   175    158   ** -local option is used, the date appears using localtime instead
   176    159   ** of UTC.
   177    160   */
   178         -static int dateCmd(
   179         -  Th_Interp *interp, 
   180         -  void *p, 
   181         -  int argc, 
   182         -  const char **argv, 
   183         -  int *argl
   184         -){
          161  +static int dateCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
          162  +{
   185    163     char *zOut;
   186         -  if( argc>=2 && argl[1]==6 && memcmp(argv[1],"-local",6)==0 ){
          164  +  if( argc>=2 && Jim_CompareStringImmediate(interp, argv[1], "-local")) {
   187    165       zOut = db_text("??", "SELECT datetime('now','localtime')");
   188    166     }else{
   189    167       zOut = db_text("??", "SELECT datetime('now')");
   190    168     }
   191         -  Th_SetResult(interp, zOut, -1);
          169  +  Jim_SetResultString(interp, zOut, -1);
   192    170     free(zOut);
   193         -  return TH_OK;
          171  +  return JIM_OK;
   194    172   }
   195    173   
   196    174   /*
   197    175   ** TH command:     hascap STRING
   198    176   **
   199    177   ** Return true if the user has all of the capabilities listed in STRING.
   200    178   */
   201         -static int hascapCmd(
   202         -  Th_Interp *interp, 
   203         -  void *p, 
   204         -  int argc, 
   205         -  const char **argv, 
   206         -  int *argl
   207         -){
          179  +static int hascapCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
          180  +{
   208    181     int rc;
          182  +  const char *str;
          183  +  int len;
   209    184     if( argc!=2 ){
   210         -    return Th_WrongNumArgs(interp, "hascap STRING");
          185  +    Jim_WrongNumArgs(interp, 1, argv, "STRING");
          186  +    return JIM_ERR;
   211    187     }
   212         -  rc = login_has_capability((char*)argv[1],argl[1]);
          188  +  str = Jim_GetString(argv[1], &len);
          189  +  rc = login_has_capability(str, len);
   213    190     if( g.thTrace ){
   214         -    Th_Trace("[hascap %#h] => %d<br />\n", argl[1], argv[1], rc);
          191  +    Th_Trace("[hascap %#h] => %d<br />\n", len, str, rc);
   215    192     }
   216         -  Th_SetResultInt(interp, rc);
   217         -  return TH_OK;
          193  +  Jim_SetResultInt(interp, rc);
          194  +  return JIM_OK;
   218    195   }
   219    196   
   220    197   /*
   221    198   ** TH command:     anycap STRING
   222    199   **
   223    200   ** Return true if the user has any one of the capabilities listed in STRING.
   224    201   */
   225         -static int anycapCmd(
   226         -  Th_Interp *interp, 
   227         -  void *p, 
   228         -  int argc, 
   229         -  const char **argv, 
   230         -  int *argl
   231         -){
          202  +static int anycapCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
          203  +{
   232    204     int rc = 0;
   233    205     int i;
          206  +  const char *str;
          207  +  int len;
   234    208     if( argc!=2 ){
   235         -    return Th_WrongNumArgs(interp, "anycap STRING");
          209  +    Jim_WrongNumArgs(interp, 1, argv, "STRING");
          210  +    return JIM_ERR;
   236    211     }
   237         -  for(i=0; rc==0 && i<argl[1]; i++){
   238         -    rc = login_has_capability((char*)&argv[1][i],1);
          212  +  str = Jim_GetString(argv[1], &len);
          213  +  for(i=0; rc==0 && i<len; i++){
          214  +    rc = login_has_capability(&str[i],1);
   239    215     }
   240    216     if( g.thTrace ){
   241         -    Th_Trace("[hascap %#h] => %d<br />\n", argl[1], argv[1], rc);
          217  +    Th_Trace("[hascap %#h] => %d<br />\n", len, str, rc);
   242    218     }
   243         -  Th_SetResultInt(interp, rc);
   244         -  return TH_OK;
          219  +  Jim_SetResultInt(interp, rc);
          220  +  return JIM_OK;
   245    221   }
   246    222   
   247    223   /*
   248    224   ** TH1 command:  combobox NAME TEXT-LIST NUMLINES
   249    225   **
   250    226   ** Generate an HTML combobox.  NAME is both the name of the
   251    227   ** CGI parameter and the name of a variable that contains the
   252    228   ** currently selected value.  TEXT-LIST is a list of possible
   253    229   ** values for the combobox.  NUMLINES is 1 for a true combobox.
   254    230   ** If NUMLINES is greater than one then the display is a listbox
   255    231   ** with the number of lines given.
   256    232   */
   257         -static int comboboxCmd(
   258         -  Th_Interp *interp,
   259         -  void *p, 
   260         -  int argc, 
   261         -  const char **argv, 
   262         -  int *argl
   263         -){
          233  +static int comboboxCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
          234  +{
   264    235     if( argc!=4 ){
   265         -    return Th_WrongNumArgs(interp, "combobox NAME TEXT-LIST NUMLINES");
          236  +    Jim_WrongNumArgs(interp, 1, argv, "NAME TEXT-LIST NUMLINES");
          237  +    return JIM_ERR;
   266    238     }
   267    239     if( enableOutput ){
   268         -    int height;
   269         -    Blob name;
   270         -    int nValue;
   271         -    const char *zValue;
          240  +    long height;
   272    241       char *z, *zH;
   273    242       int nElem;
   274         -    int *aszElem;
   275         -    char **azElem;
   276    243       int i;
          244  +    Jim_Obj *objPtr;
          245  +    Jim_Obj *varObjPtr;
   277    246   
   278         -    if( Th_ToInt(interp, argv[3], argl[3], &height) ) return TH_ERROR;
   279         -    Th_SplitList(interp, argv[2], argl[2], &azElem, &aszElem, &nElem);
   280         -    blob_init(&name, (char*)argv[1], argl[1]);
   281         -    zValue = Th_Fetch(blob_str(&name), &nValue);
          247  +    if( Jim_GetLong(interp, argv[3], &height) ) return JIM_ERR;
          248  +    nElem = Jim_ListLength(interp, argv[2]);
          249  +
          250  +    varObjPtr = Jim_GetVariable(g.interp, argv[1], JIM_NONE);
   282    251       z = mprintf("<select name=\"%z\" size=\"%d\">", 
   283         -                 htmlize(blob_buffer(&name), blob_size(&name)), height);
          252  +                 htmlize(Jim_String(varObjPtr), Jim_Length(varObjPtr)), height);
   284    253       sendText(z, -1, 0);
   285    254       free(z);
   286         -    blob_reset(&name);
   287    255       for(i=0; i<nElem; i++){
   288         -      zH = htmlize((char*)azElem[i], aszElem[i]);
   289         -      if( zValue && aszElem[i]==nValue 
   290         -             && memcmp(zValue, azElem[i], nValue)==0 ){
          256  +      Jim_ListIndex(interp, argv[2], i, &objPtr, JIM_NONE);
          257  +      zH = htmlize(Jim_String(objPtr), Jim_Length(objPtr));
          258  +      if( varObjPtr && Jim_StringEqObj(varObjPtr, objPtr)) {
   291    259           z = mprintf("<option value=\"%s\" selected=\"selected\">%s</option>",
   292    260                        zH, zH);
   293    261         }else{
   294    262           z = mprintf("<option value=\"%s\">%s</option>", zH, zH);
   295    263         }
   296    264         free(zH);
   297    265         sendText(z, -1, 0);
   298    266         free(z);
   299    267       }
   300    268       sendText("</select>", -1, 0);
   301         -    Th_Free(interp, azElem);
   302    269     }
   303         -  return TH_OK;
          270  +  return JIM_OK;
   304    271   }
   305    272   
   306    273   /*
   307    274   ** TH1 command:     linecount STRING MAX MIN
   308    275   **
   309    276   ** Return one more than the number of \n characters in STRING.  But
   310    277   ** never return less than MIN or more than MAX.
   311    278   */
   312         -static int linecntCmd(
   313         -  Th_Interp *interp,
   314         -  void *p, 
   315         -  int argc, 
   316         -  const char **argv, 
   317         -  int *argl
   318         -){
          279  +static int linecntCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
          280  +{
   319    281     const char *z;
   320    282     int size, n, i;
   321         -  int iMin, iMax;
          283  +  jim_wide iMin, iMax;
   322    284     if( argc!=4 ){
   323         -    return Th_WrongNumArgs(interp, "linecount STRING MAX MIN");
          285  +    Jim_WrongNumArgs(interp, 1, argv, "STRING MAX MIN");
          286  +    return JIM_ERR;
   324    287     }
   325         -  if( Th_ToInt(interp, argv[2], argl[2], &iMax) ) return TH_ERROR;
   326         -  if( Th_ToInt(interp, argv[3], argl[3], &iMin) ) return TH_ERROR;
   327         -  z = argv[1];
   328         -  size = argl[1];
          288  +  if( Jim_GetWide(interp, argv[2], &iMax) ) return JIM_ERR;
          289  +  if( Jim_GetWide(interp, argv[3], &iMin) ) return JIM_ERR;
          290  +  z = Jim_GetString(argv[1], &size);
   329    291     for(n=1, i=0; i<size; i++){
   330    292       if( z[i]=='\n' ){
   331    293         n++;
   332    294         if( n>=iMax ) break;
   333    295       }
   334    296     }
   335    297     if( n<iMin ) n = iMin;
   336    298     if( n>iMax ) n = iMax;
   337         -  Th_SetResultInt(interp, n);
   338         -  return TH_OK;
          299  +  Jim_SetResultInt(interp, n);
          300  +  return JIM_OK;
   339    301   }
   340    302   
   341    303   /*
   342    304   ** TH1 command:     repository ?BOOLEAN?
   343    305   **
   344    306   ** Return the fully qualified file name of the open repository or an empty
   345    307   ** string if one is not currently open.  Optionally, it will attempt to open
   346    308   ** the repository if the boolean argument is non-zero.
   347    309   */
   348         -static int repositoryCmd(
   349         -  Th_Interp *interp,
   350         -  void *p, 
   351         -  int argc, 
   352         -  const char **argv, 
   353         -  int *argl
   354         -){
   355         -  int openRepository;
          310  +static int repositoryCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
          311  +{
          312  +  long openRepository;
   356    313   
   357    314     if( argc!=1 && argc!=2 ){
   358         -    return Th_WrongNumArgs(interp, "repository ?BOOLEAN?");
          315  +    Jim_WrongNumArgs(interp, 1, argv, "BOOLEAN");
          316  +    return JIM_ERR;
   359    317     }
   360    318     if( argc==2 ){
   361         -    if( Th_ToInt(interp, argv[1], argl[1], &openRepository) ){
   362         -      return TH_ERROR;
          319  +    if( Jim_GetLong(interp, argv[1], &openRepository) != JIM_OK){
          320  +      return JIM_ERR;
   363    321       }
   364    322       if( openRepository ) db_find_and_open_repository(OPEN_OK_NOT_FOUND, 0);
   365    323     }
   366         -  Th_SetResult(interp, g.zRepositoryName, -1);
   367         -  return TH_OK;
          324  +  Jim_SetResultString(interp, g.zRepositoryName, -1);
          325  +  return JIM_OK;
   368    326   }
   369    327   
   370    328   /*
   371    329   ** Make sure the interpreter has been initialized.  Initialize it if
   372    330   ** it has not been already.
   373    331   **
   374    332   ** The interpreter is stored in the g.interp global variable.
   375    333   */
   376    334   void Th_FossilInit(void){
   377    335     static struct _Command {
   378    336       const char *zName;
   379         -    Th_CommandProc xProc;
   380         -    void *pContext;
          337  +    Jim_CmdProc xProc;
   381    338     } aCommand[] = {
   382         -    {"anycap",        anycapCmd,            0},
   383         -    {"combobox",      comboboxCmd,          0},
   384         -    {"enable_output", enableOutputCmd,      0},
   385         -    {"linecount",     linecntCmd,           0},
   386         -    {"hascap",        hascapCmd,            0},
   387         -    {"htmlize",       htmlizeCmd,           0},
   388         -    {"date",          dateCmd,              0},
   389         -    {"html",          putsCmd,              0},
   390         -    {"puts",          putsCmd,       (void*)1},
   391         -    {"wiki",          wikiCmd,              0},
   392         -    {"repository",    repositoryCmd,        0},
   393         -    {0, 0, 0}
          339  +    {"anycap",        anycapCmd,            },
          340  +    {"combobox",      comboboxCmd,          },
          341  +    {"enable_output", enableOutputCmd,      },
          342  +    {"linecount",     linecntCmd,           },
          343  +    {"hascap",        hascapCmd,            },
          344  +    {"htmlize",       htmlizeCmd,           },
          345  +    {"date",          dateCmd,              },
          346  +    {"html",          htmlCmd,              },
          347  +    {"puts",          putsCmd,              },
          348  +    {"wiki",          wikiCmd,              },
          349  +    {"repository",    repositoryCmd,        },
          350  +    {0, 0}
   394    351     };
   395    352     if( g.interp==0 ){
   396    353       int i;
   397         -    g.interp = Th_CreateInterp(&vtab);
   398         -    th_register_language(g.interp);       /* Basic scripting commands. */
          354  +    /* Create and initialize the interpreter */
          355  +    g.interp = Jim_CreateInterp();
          356  +    Jim_RegisterCoreCommands(g.interp);
          357  +
          358  +    /* Register static extensions */
          359  +    Jim_InitStaticExtensions(g.interp);
          360  +
   399    361   #ifdef FOSSIL_ENABLE_TCL
   400         -    if( getenv("TH1_ENABLE_TCL")!=0 || db_get_boolean("tcl", 0) ){
   401         -      th_register_tcl(g.interp, &g.tcl);  /* Tcl integration commands. */
          362  +    if( getenv("FOSSIL_ENABLE_TCL")!=0 || db_get_boolean("tcl", 0) ){
          363  +      register_tcl(g.interp, &g.tcl);  /* Tcl integration commands. */
   402    364       }
   403    365   #endif
   404    366       for(i=0; i<sizeof(aCommand)/sizeof(aCommand[0]); i++){
   405    367         if ( !aCommand[i].zName || !aCommand[i].xProc ) continue;
   406         -      Th_CreateCommand(g.interp, aCommand[i].zName, aCommand[i].xProc,
   407         -                       aCommand[i].pContext, 0);
          368  +      Jim_CreateCommand(g.interp, aCommand[i].zName, aCommand[i].xProc, NULL,
          369  +          NULL);
   408    370       }
   409    371     }
   410    372   }
   411    373   
   412    374   /*
   413    375   ** Store a string value in a variable in the interpreter.
   414    376   */
   415    377   void Th_Store(const char *zName, const char *zValue){
   416    378     Th_FossilInit();
   417    379     if( zValue ){
   418    380       if( g.thTrace ){
   419    381         Th_Trace("set %h {%h}<br />\n", zName, zValue);
   420    382       }
   421         -    Th_SetVar(g.interp, zName, -1, zValue, strlen(zValue));
          383  +    Jim_SetVariableStrWithStr(g.interp, zName, zValue);
   422    384     }
   423    385   }
   424    386   
   425    387   /*
   426    388   ** Unset a variable.
   427    389   */
   428    390   void Th_Unstore(const char *zName){
   429    391     if( g.interp ){
   430         -    Th_UnsetVar(g.interp, (char*)zName, -1);
          392  +    Jim_Obj *nameObjPtr = Jim_NewStringObj(g.interp, zName, -1);
          393  +    Jim_UnsetVariable(g.interp, nameObjPtr, JIM_NONE);
          394  +    Jim_FreeNewObj(g.interp, nameObjPtr);
   431    395     }
   432    396   }
   433    397   
   434    398   /*
   435         -** Retrieve a string value from the interpreter.  If no such
          399  +** Retrieve a string value (variable) from the interpreter.  If no such
   436    400   ** variable exists, return NULL.
   437    401   */
   438         -char *Th_Fetch(const char *zName, int *pSize){
   439         -  int rc;
          402  +const char *Th_Fetch(const char *zName){
          403  +  Jim_Obj *objPtr;
          404  +
   440    405     Th_FossilInit();
   441         -  rc = Th_GetVar(g.interp, (char*)zName, -1);
   442         -  if( rc==TH_OK ){
   443         -    return (char*)Th_GetResult(g.interp, pSize);
   444         -  }else{
   445         -    return 0;
   446         -  }
          406  +
          407  +  objPtr = Jim_GetVariableStr(g.interp, zName, JIM_NONE);
          408  +
          409  +  return objPtr ? Jim_String(objPtr) : NULL;
          410  +}
          411  +
          412  +/**
          413  + * Like Th_Fetch() except the variable name may not be null terminated.
          414  + * Instead, the length of the name is supplied as 'namelen'.
          415  + */
          416  +const char *Th_GetVar(Jim_Interp *interp, const char *name, int namelen){
          417  +    Jim_Obj *nameObjPtr, *varObjPtr;
          418  +
          419  +    nameObjPtr = Jim_NewStringObj(interp, name, namelen);
          420  +    Jim_IncrRefCount(nameObjPtr);
          421  +    varObjPtr = Jim_GetVariable(interp, nameObjPtr, 0);
          422  +    Jim_DecrRefCount(interp, nameObjPtr);
          423  +
          424  +    return varObjPtr ? Jim_String(varObjPtr) : NULL;
   447    425   }
   448    426   
   449    427   /*
   450    428   ** Return true if the string begins with the TH1 begin-script
   451    429   ** tag:  <th1>.
   452    430   */
   453    431   static int isBeginScriptTag(const char *z){
          432  +  /* XXX: Should we also allow <tcl>? */
   454    433     return z[0]=='<'
   455    434         && (z[1]=='t' || z[1]=='T')
   456    435         && (z[2]=='h' || z[2]=='H')
   457    436         && z[3]=='1'
   458    437         && z[4]=='>';
   459    438   }
   460    439   
   461    440   /*
   462    441   ** Return true if the string begins with the TH1 end-script
   463    442   ** tag:  </th1>.
   464    443   */
   465    444   static int isEndScriptTag(const char *z){
          445  +  /* XXX: Should we also allow </tcl>? */
   466    446     return z[0]=='<'
   467    447         && z[1]=='/'
   468    448         && (z[2]=='t' || z[2]=='T')
   469    449         && (z[3]=='h' || z[3]=='H')
   470    450         && z[4]=='1'
   471    451         && z[5]=='>';
   472    452   }
................................................................................
   511    491   **
   512    492   ** This routine processes the template and writes the results
   513    493   ** on either stdout or into CGI.
   514    494   */
   515    495   int Th_Render(const char *z){
   516    496     int i = 0;
   517    497     int n;
   518         -  int rc = TH_OK;
   519         -  char *zResult;
          498  +  int rc = JIM_OK;
          499  +  const char *zResult;
   520    500     Th_FossilInit();
   521    501     while( z[i] ){
   522    502       if( z[i]=='$' && (n = validVarName(&z[i+1]))>0 ){
   523    503         const char *zVar;
   524    504         int nVar;
   525    505         int encode = 1;
   526    506         sendText(z, i, 0);
................................................................................
   530    510           nVar = n-2;
   531    511         }else{
   532    512           /* Variables of the form $aaa are output raw */
   533    513           zVar = &z[i+1];
   534    514           nVar = n;
   535    515           encode = 0;
   536    516         }
   537         -      rc = Th_GetVar(g.interp, (char*)zVar, nVar);
          517  +      zResult = Th_GetVar(g.interp, zVar, nVar);
   538    518         z += i+1+n;
   539    519         i = 0;
   540         -      zResult = (char*)Th_GetResult(g.interp, &n);
   541         -      sendText((char*)zResult, n, encode);
          520  +      if (zResult) {
          521  +        sendText(zResult, -1, encode);
          522  +      }
   542    523       }else if( z[i]=='<' && isBeginScriptTag(&z[i]) ){
          524  +      Jim_Obj *objPtr;
   543    525         sendText(z, i, 0);
   544    526         z += i+5;
   545    527         for(i=0; z[i] && (z[i]!='<' || !isEndScriptTag(&z[i])); i++){}
   546         -      rc = Th_Eval(g.interp, 0, (const char*)z, i);
   547         -      if( rc!=TH_OK ) break;
          528  +      /* XXX: Would be nice to record the source location in case of error */
          529  +      objPtr = Jim_NewStringObj(g.interp, z, i);
          530  +      rc = Jim_EvalObj(g.interp, objPtr);
          531  +      if( rc!=JIM_OK ) break;
   548    532         z += i;
   549    533         if( z[0] ){ z += 6; }
   550    534         i = 0;
   551    535       }else{
   552    536         i++;
   553    537       }
   554    538     }
   555         -  if( rc==TH_ERROR ){
          539  +  if( rc==JIM_ERR ){
   556    540       sendText("<hr><p class=\"thmainError\">ERROR: ", -1, 0);
   557         -    zResult = (char*)Th_GetResult(g.interp, &n);
   558         -    sendText((char*)zResult, n, 1);
          541  +    sendTextObj(Jim_GetResult(g.interp), 1);
   559    542       sendText("</p>", -1, 0);
   560    543     }else{
   561    544       sendText(z, i, 0);
   562    545     }
   563    546     return rc;
   564    547   }
   565    548   
   566    549   /*
   567         -** COMMAND: test-th-render
          550  +** COMMAND: test-script-render
   568    551   */
   569         -void test_th_render(void){
          552  +void test_script_render(void){
   570    553     Blob in;
   571    554     if( g.argc<3 ){
   572    555       usage("FILE");
   573    556     }
   574    557     db_open_config(0); /* Needed for global "tcl" setting. */
   575    558     blob_zero(&in);
   576    559     blob_read_from_file(&in, g.argv[2]);
   577    560     Th_Render(blob_str(&in));
   578    561   }

Changes to src/th_tcl.c.

     4      4   ** known as the "2-Clause License" or "FreeBSD License".)
     5      5   **
     6      6   ** This program is distributed in the hope that it will be useful,
     7      7   ** but without any warranty; without even the implied warranty of
     8      8   ** merchantability or fitness for a particular purpose.
     9      9   **
    10     10   *******************************************************************************
    11         -** This file contains code used to bridge the TH1 and Tcl scripting languages.
           11  +** This file contains code used to bridge the Jim and Tcl scripting languages.
    12     12   */
    13     13   
    14     14   #include "config.h"
    15     15   
    16     16   #ifdef FOSSIL_ENABLE_TCL
    17     17   
    18         -#include "th.h"
           18  +#include "jim.h"
    19     19   #include "tcl.h"
    20     20   
    21     21   /*
    22     22   ** Are we being compiled against Tcl 8.6 or higher?
    23     23    */
    24     24   #if (TCL_MAJOR_VERSION > 8) || \
    25     25       ((TCL_MAJOR_VERSION == 8) && (TCL_MINOR_VERSION >= 6))
................................................................................
    28     28   ** Tcl_EvalObjv instead of invoking the objProc directly.
    29     29    */
    30     30   #define USE_TCL_EVALOBJV   1
    31     31   #endif
    32     32   
    33     33   /*
    34     34   ** These macros are designed to reduce the redundant code required to marshal
    35         -** arguments from TH1 to Tcl.
           35  +** arguments from Jim to Tcl.
    36     36    */
    37     37   #define USE_ARGV_TO_OBJV() \
    38     38     int objc;                \
    39     39     Tcl_Obj **objv;          \
    40     40     int i;
    41     41   
    42         -#define COPY_ARGV_TO_OBJV()                                         \
    43         -  objc = argc-1;                                                    \
    44         -  objv = (Tcl_Obj **)ckalloc((unsigned)(objc * sizeof(Tcl_Obj *))); \
    45         -  for(i=1; i<argc; i++){                                            \
    46         -    objv[i-1] = Tcl_NewStringObj(argv[i], argl[i]);                 \
    47         -    Tcl_IncrRefCount(objv[i-1]);                                    \
           42  +#define COPY_ARGV_TO_OBJV()                                                 \
           43  +  objc = argc-1;                                                            \
           44  +  objv = (Tcl_Obj **)ckalloc((unsigned)(objc * sizeof(Tcl_Obj *)));         \
           45  +  for(i=1; i<argc; i++){                                                    \
           46  +    objv[i-1] = Tcl_NewStringObj(Jim_String(argv[i]), Jim_Length(argv[i])); \
           47  +    Tcl_IncrRefCount(objv[i-1]);                                            \
    48     48     }
    49     49   
    50     50   #define FREE_ARGV_TO_OBJV()      \
    51     51     for(i=1; i<argc; i++){         \
    52     52       Tcl_DecrRefCount(objv[i-1]); \
    53     53     }                              \
    54     54     ckfree((char *)objv);
................................................................................
    57     57   ** Fetch the Tcl interpreter from the specified void pointer, cast to a Tcl
    58     58   ** context.
    59     59    */
    60     60   #define GET_CTX_TCL_INTERP(ctx) \
    61     61     ((struct TclContext *)(ctx))->interp
    62     62   
    63     63   /*
    64         -** Creates and initializes a Tcl interpreter for use with the specified TH1
           64  +** Creates and initializes a Tcl interpreter for use with the specified Jim
    65     65   ** interpreter.  Stores the created Tcl interpreter in the Tcl context supplied
    66     66   ** by the caller.  This must be declared here because quite a few functions in
    67     67   ** this file need to use it before it can be defined.
    68     68    */
    69         -static int createTclInterp(Th_Interp *interp, void *pContext);
           69  +static int createTclInterp(Jim_Interp *interp, void *pContext);
    70     70   
    71     71   /*
    72     72   ** Returns the Tcl interpreter result as a string with the associated length.
    73     73   ** If the Tcl interpreter or the Tcl result are NULL, the length will be 0.
    74     74   ** If the length pointer is NULL, the length will not be stored.
    75     75    */
    76     76   static char *getTclResult(
................................................................................
    87     87       if( pN ) *pN = 0;
    88     88       return 0;
    89     89     }
    90     90     return Tcl_GetStringFromObj(resultPtr, pN);
    91     91   }
    92     92   
    93     93   /*
    94         -** Tcl context information used by TH1.  This structure definition has been
           94  +** Tcl context information used by Jim.  This structure definition has been
    95     95   ** copied from and should be kept in sync with the one in "main.c".
    96     96   */
    97     97   struct TclContext {
    98     98     int argc;
    99     99     char **argv;
   100    100     Tcl_Interp *interp;
   101    101   };
................................................................................
   102    102   
   103    103   /*
   104    104   ** Syntax:
   105    105   **
   106    106   **   tclEval arg ?arg ...?
   107    107   */
   108    108   static int tclEval_command(
   109         -  Th_Interp *interp,
   110         -  void *ctx,
          109  +  Jim_Interp *interp,
   111    110     int argc,
   112         -  const char **argv,
   113         -  int *argl
          111  +  Jim_Obj *const *argv
   114    112   ){
   115    113     Tcl_Interp *tclInterp;
   116    114     Tcl_Obj *objPtr;
   117    115     int rc;
   118    116     int nResult;
   119    117     const char *zResult;
          118  +  void *ctx = Jim_CmdPrivData(interp);
   120    119   
   121         -  if ( createTclInterp(interp, ctx)!=TH_OK ){
   122         -    return TH_ERROR;
          120  +  if ( createTclInterp(interp, ctx)!=JIM_OK ){
          121  +    return JIM_ERR;
   123    122     }
   124    123     if( argc<2 ){
   125         -    return Th_WrongNumArgs(interp, "tclEval arg ?arg ...?");
          124  +    Jim_WrongNumArgs(interp, 1, argv, "arg ?arg ...?");
          125  +    return JIM_ERR;
   126    126     }
   127    127     tclInterp = GET_CTX_TCL_INTERP(ctx);
   128    128     if( !tclInterp || Tcl_InterpDeleted(tclInterp) ){
   129         -    Th_ErrorMessage(interp, "invalid Tcl interpreter", (const char *)"", 0);
   130         -    return TH_ERROR;
          129  +    Jim_SetResultString(interp, "invalid Tcl interpreter", -1);
          130  +    return JIM_ERR;
   131    131     }
   132    132     Tcl_Preserve((ClientData)tclInterp);
   133    133     if( argc==2 ){
   134         -    objPtr = Tcl_NewStringObj(argv[1], argl[1]);
          134  +    objPtr = Tcl_NewStringObj(Jim_String(argv[1]), Jim_Length(argv[1]));
   135    135       Tcl_IncrRefCount(objPtr);
   136    136       rc = Tcl_EvalObjEx(tclInterp, objPtr, 0);
   137    137       Tcl_DecrRefCount(objPtr);
   138    138     }else{
   139    139       USE_ARGV_TO_OBJV();
   140    140       COPY_ARGV_TO_OBJV();
   141    141       objPtr = Tcl_ConcatObj(objc, objv);
   142    142       Tcl_IncrRefCount(objPtr);
   143    143       rc = Tcl_EvalObjEx(tclInterp, objPtr, 0);
   144    144       Tcl_DecrRefCount(objPtr);
   145    145       FREE_ARGV_TO_OBJV();
   146    146     }
   147    147     zResult = getTclResult(tclInterp, &nResult);
   148         -  Th_SetResult(interp, zResult, nResult);
          148  +  Jim_SetResultString(interp, zResult, nResult);
   149    149     Tcl_Release((ClientData)tclInterp);
   150    150     return rc;
   151    151   }
   152    152   
   153    153   /*
   154    154   ** Syntax:
   155    155   **
   156    156   **   tclExpr arg ?arg ...?
   157    157   */
   158    158   static int tclExpr_command(
   159         -  Th_Interp *interp,
   160         -  void *ctx,
          159  +  Jim_Interp *interp,
   161    160     int argc,
   162         -  const char **argv,
   163         -  int *argl
          161  +  Jim_Obj *const *argv
   164    162   ){
   165    163     Tcl_Interp *tclInterp;
   166    164     Tcl_Obj *objPtr;
   167    165     Tcl_Obj *resultObjPtr;
   168    166     int rc;
   169    167     int nResult;
   170    168     const char *zResult;
          169  +  void *ctx = Jim_CmdPrivData(interp);
   171    170   
   172         -  if ( createTclInterp(interp, ctx)!=TH_OK ){
   173         -    return TH_ERROR;
          171  +  if ( createTclInterp(interp, ctx)!=JIM_OK ){
          172  +    return JIM_ERR;
   174    173     }
   175    174     if( argc<2 ){
   176         -    return Th_WrongNumArgs(interp, "tclExpr arg ?arg ...?");
          175  +    Jim_WrongNumArgs(interp, 1, argv, "arg ?arg ...?");
          176  +    return JIM_ERR;
   177    177     }
   178    178     tclInterp = GET_CTX_TCL_INTERP(ctx);
   179    179     if( !tclInterp || Tcl_InterpDeleted(tclInterp) ){
   180         -    Th_ErrorMessage(interp, "invalid Tcl interpreter", (const char *)"", 0);
   181         -    return TH_ERROR;
          180  +    Jim_SetResultString(interp, "invalid Tcl interpreter", -1);
          181  +    return JIM_ERR;
   182    182     }
   183    183     Tcl_Preserve((ClientData)tclInterp);
   184    184     if( argc==2 ){
   185         -    objPtr = Tcl_NewStringObj(argv[1], argl[1]);
          185  +    objPtr = Tcl_NewStringObj(Jim_String(argv[1]), Jim_Length(argv[1]));
   186    186       Tcl_IncrRefCount(objPtr);
   187    187       rc = Tcl_ExprObj(tclInterp, objPtr, &resultObjPtr);
   188    188       Tcl_DecrRefCount(objPtr);
   189    189     }else{
   190    190       USE_ARGV_TO_OBJV();
   191    191       COPY_ARGV_TO_OBJV();
   192    192       objPtr = Tcl_ConcatObj(objc, objv);
................................................................................
   196    196       FREE_ARGV_TO_OBJV();
   197    197     }
   198    198     if( rc==TCL_OK ){
   199    199       zResult = Tcl_GetStringFromObj(resultObjPtr, &nResult);
   200    200     }else{
   201    201       zResult = getTclResult(tclInterp, &nResult);
   202    202     }
   203         -  Th_SetResult(interp, zResult, nResult);
          203  +  Jim_SetResultString(interp, zResult, nResult);
   204    204     if( rc==TCL_OK ) Tcl_DecrRefCount(resultObjPtr);
   205    205     Tcl_Release((ClientData)tclInterp);
   206    206     return rc;
   207    207   }
   208    208   
   209    209   /*
   210    210   ** Syntax:
   211    211   **
   212    212   **   tclInvoke command ?arg ...?
   213    213   */
   214    214   static int tclInvoke_command(
   215         -  Th_Interp *interp,
   216         -  void *ctx,
          215  +  Jim_Interp *interp,
   217    216     int argc,
   218         -  const char **argv,
   219         -  int *argl
          217  +  Jim_Obj *const *argv
   220    218   ){
   221    219     Tcl_Interp *tclInterp;
   222    220   #ifndef USE_TCL_EVALOBJV
   223    221     Tcl_Command command;
   224    222     Tcl_CmdInfo cmdInfo;
   225    223   #endif
   226    224     int rc;
   227    225     int nResult;
   228    226     const char *zResult;
          227  +  void *ctx = Jim_CmdPrivData(interp);
   229    228   #ifndef USE_TCL_EVALOBJV
   230    229     Tcl_Obj *objPtr;
   231    230   #endif
   232    231     USE_ARGV_TO_OBJV();
   233    232   
   234         -  if ( createTclInterp(interp, ctx)!=TH_OK ){
   235         -    return TH_ERROR;
          233  +  if ( createTclInterp(interp, ctx)!=JIM_OK ){
          234  +    return JIM_ERR;
   236    235     }
   237    236     if( argc<2 ){
   238         -    return Th_WrongNumArgs(interp, "tclInvoke command ?arg ...?");
          237  +    Jim_WrongNumArgs(interp, 1, argv, "command ?arg ...?");
          238  +    return JIM_ERR;
   239    239     }
   240    240     tclInterp = GET_CTX_TCL_INTERP(ctx);
   241    241     if( !tclInterp || Tcl_InterpDeleted(tclInterp) ){
   242         -    Th_ErrorMessage(interp, "invalid Tcl interpreter", (const char *)"", 0);
   243         -    return TH_ERROR;
          242  +    Jim_SetResultString(interp, "invalid Tcl interpreter", -1);
          243  +    return JIM_ERR;
   244    244     }
   245    245     Tcl_Preserve((ClientData)tclInterp);
   246    246   #ifndef USE_TCL_EVALOBJV
   247         -  objPtr = Tcl_NewStringObj(argv[1], argl[1]);
          247  +  objPtr = Tcl_NewStringObj(Jim_String(argv[1]), Jim_Length(argv[1]));
   248    248     Tcl_IncrRefCount(objPtr);
   249    249     command = Tcl_GetCommandFromObj(tclInterp, objPtr);
   250    250     if( !command || Tcl_GetCommandInfoFromToken(command,&cmdInfo)==0 ){
   251         -    Th_ErrorMessage(interp, "Tcl command not found:", argv[1], argl[1]);
          251  +    Jim_SetResultFormatted(interp, "Tcl command not found: %#s", argv[1]);
   252    252       Tcl_DecrRefCount(objPtr);
   253    253       Tcl_Release((ClientData)tclInterp);
   254         -    return TH_ERROR;
          254  +    return JIM_ERR;
   255    255     }
   256    256     if( !cmdInfo.objProc ){
   257         -    Th_ErrorMessage(interp, "Cannot invoke Tcl command:", argv[1], argl[1]);
          257  +    Jim_SetResultFormatted(interp, "Cannot invoke command not found: %#s",
          258  +        argv[1]);
   258    259       Tcl_DecrRefCount(objPtr);
   259    260       Tcl_Release((ClientData)tclInterp);
   260         -    return TH_ERROR;
          261  +    return JIM_ERR;
   261    262     }
   262    263     Tcl_DecrRefCount(objPtr);
   263    264   #endif
   264    265     COPY_ARGV_TO_OBJV();
   265    266   #ifdef USE_TCL_EVALOBJV
   266    267     rc = Tcl_EvalObjv(tclInterp, objc, objv, 0);
   267    268   #else
   268    269     Tcl_ResetResult(tclInterp);
   269    270     rc = cmdInfo.objProc(cmdInfo.objClientData, tclInterp, objc, objv);
   270    271   #endif
   271    272     FREE_ARGV_TO_OBJV();
   272    273     zResult = getTclResult(tclInterp, &nResult);
   273         -  Th_SetResult(interp, zResult, nResult);
          274  +  Jim_SetResultString(interp, zResult, nResult);
   274    275     Tcl_Release((ClientData)tclInterp);
   275    276     return rc;
   276    277   }
   277    278   
   278    279   /*
   279    280   ** Syntax:
   280    281   **
   281         -**   th1Eval arg
          282  +**   bridgeEval arg
   282    283   */
   283         -static int Th1EvalObjCmd(
          284  +static int BridgeEvalObjCmd(
   284    285     ClientData clientData,
   285    286     Tcl_Interp *interp,
   286    287     int objc,
   287    288     Tcl_Obj *CONST objv[]
   288    289   ){
   289         -  Th_Interp *th1Interp;
          290  +  Jim_Interp *jimInterp;
   290    291     int nArg;
   291    292     const char *arg;
   292    293     int rc;
          294  +  Jim_Obj *argObj;
          295  +  Jim_Obj *resultObj;
   293    296   
   294    297     if( objc!=2 ){
   295    298       Tcl_WrongNumArgs(interp, 1, objv, "arg");
   296    299       return TCL_ERROR;
   297    300     }
   298         -  th1Interp = (Th_Interp *)clientData;
   299         -  if( !th1Interp ){
   300         -    Tcl_AppendResult(interp, "invalid TH1 interpreter", NULL);
          301  +  jimInterp = (Jim_Interp *)clientData;
          302  +  if( !jimInterp ){
          303  +    Tcl_AppendResult(interp, "invalid bridge interpreter", NULL);
   301    304       return TCL_ERROR;
   302    305     }
   303    306     arg = Tcl_GetStringFromObj(objv[1], &nArg);
   304         -  rc = Th_Eval(th1Interp, 0, arg, nArg);
   305         -  arg = Th_GetResult(th1Interp, &nArg);
          307  +  argObj = Jim_NewStringObj(jimInterp, arg, nArg);
          308  +  Jim_IncrRefCount(argObj);
          309  +  rc = Jim_EvalObj(jimInterp, argObj);
          310  +  Jim_DecrRefCount(jimInterp, argObj);
          311  +  resultObj = Jim_GetResult(jimInterp);
          312  +  arg = Jim_GetString(resultObj, &nArg);
   306    313     Tcl_SetObjResult(interp, Tcl_NewStringObj(arg, nArg));
   307    314     return rc;
   308    315   }
   309    316   
   310    317   /*
   311    318   ** Syntax:
   312    319   **
   313         -**   th1Expr arg
          320  +**   bridgeExpr arg
   314    321   */
   315         -static int Th1ExprObjCmd(
          322  +static int BridgeExprObjCmd(
   316    323     ClientData clientData,
   317    324     Tcl_Interp *interp,
   318    325     int objc,
   319    326     Tcl_Obj *CONST objv[]
   320    327   ){
   321         -  Th_Interp *th1Interp;
          328  +  Jim_Interp *jimInterp;
   322    329     int nArg;
   323    330     const char *arg;
   324    331     int rc;
          332  +  Jim_Obj *argObj;
          333  +  Jim_Obj *resultObj;
   325    334   
   326    335     if( objc!=2 ){
   327    336       Tcl_WrongNumArgs(interp, 1, objv, "arg");
   328    337       return TCL_ERROR;
   329    338     }
   330         -  th1Interp = (Th_Interp *)clientData;
   331         -  if( !th1Interp ){
   332         -    Tcl_AppendResult(interp, "invalid TH1 interpreter", NULL);
          339  +  jimInterp = (Jim_Interp *)clientData;
          340  +  if( !jimInterp ){
          341  +    Tcl_AppendResult(interp, "invalid bridge interpreter", NULL);
   333    342       return TCL_ERROR;
   334    343     }
   335    344     arg = Tcl_GetStringFromObj(objv[1], &nArg);
   336         -  rc = Th_Expr(th1Interp, arg, nArg);
   337         -  arg = Th_GetResult(th1Interp, &nArg);
   338         -  Tcl_SetObjResult(interp, Tcl_NewStringObj(arg, nArg));
          345  +  argObj = Jim_NewStringObj(jimInterp, arg, nArg);
          346  +  Jim_IncrRefCount(argObj);
          347  +  rc = Jim_EvalExpression(jimInterp, argObj, &resultObj);
          348  +  Jim_DecrRefCount(jimInterp, argObj);
          349  +  if (rc == JIM_OK) {
          350  +    arg = Jim_GetString(resultObj, &nArg);
          351  +    Tcl_SetObjResult(interp, Tcl_NewStringObj(arg, nArg));
          352  +  }
   339    353     return rc;
   340    354   }
   341    355   
   342    356   /*
   343    357   ** Array of Tcl integration commands.  Used when adding or removing the Tcl
   344         -** integration commands from TH1.
          358  +** integration commands from Jim.
   345    359   */
   346    360   static struct _Command {
   347    361     const char *zName;
   348         -  Th_CommandProc xProc;
          362  +  Jim_CmdProc xProc;
   349    363     void *pContext;
   350    364   } aCommand[] = {
   351    365     {"tclEval",   tclEval_command,   0},
   352    366     {"tclExpr",   tclExpr_command,   0},
   353    367     {"tclInvoke", tclInvoke_command, 0},
   354    368     {0, 0, 0}
   355    369   };
   356    370   
   357    371   /*
   358    372   ** Called if the Tcl interpreter is deleted.  Removes the Tcl integration
   359         -** commands from the TH1 interpreter.
          373  +** commands from the Jim interpreter.
   360    374    */
   361         -static void Th1DeleteProc(
          375  +static void BridgeDeleteProc(
   362    376     ClientData clientData,
   363    377     Tcl_Interp *interp
   364    378   ){
   365    379     int i;
   366         -  Th_Interp *th1Interp = (Th_Interp *)clientData;
   367         -  if( !th1Interp ) return;
          380  +  Jim_Interp *jimInterp = (Jim_Interp *)clientData;
          381  +  if( !jimInterp ) return;
   368    382     /* Remove the Tcl integration commands. */
   369    383     for(i=0; i<(sizeof(aCommand)/sizeof(aCommand[0])); i++){
   370         -    Th_RenameCommand(th1Interp, aCommand[i].zName, -1, NULL, 0);
          384  +    Jim_DeleteCommand(jimInterp, aCommand[i].zName);
   371    385     }
   372    386   }
   373    387   
   374    388   /*
   375         -** Creates and initializes a Tcl interpreter for use with the specified TH1
          389  +** Creates and initializes a Tcl interpreter for use with the specified Jim
   376    390   ** interpreter.  Stores the created Tcl interpreter in the Tcl context supplied
   377    391   ** by the caller.
   378    392    */
   379    393   static int createTclInterp(
   380         -  Th_Interp *interp,
          394  +  Jim_Interp *interp,
   381    395     void *pContext
   382    396   ){
   383    397     struct TclContext *tclContext = (struct TclContext *)pContext;
   384    398     Tcl_Interp *tclInterp;
   385    399   
   386    400     if ( !tclContext ){
   387         -    Th_ErrorMessage(interp,
   388         -        "Invalid Tcl context", (const char *)"", 0);
   389         -    return TH_ERROR;
          401  +    Jim_SetResultString(interp, "Invalid Tcl context", -1);
          402  +    return JIM_ERR;
   390    403     }
   391    404     if ( tclContext->interp ){
   392         -    return TH_OK;
          405  +    return JIM_OK;
   393    406     }
   394    407     if ( tclContext->argc>0 && tclContext->argv ) {
   395    408       Tcl_FindExecutable(tclContext->argv[0]);
   396    409     }
   397    410     tclInterp = tclContext->interp = Tcl_CreateInterp();
   398    411     if( !tclInterp || Tcl_InterpDeleted(tclInterp) ){
   399         -    Th_ErrorMessage(interp,
   400         -        "Could not create Tcl interpreter", (const char *)"", 0);
   401         -    return TH_ERROR;
          412  +    Jim_SetResultString(interp, "Could not create Tcl interpreter", -1);
          413  +    return JIM_ERR;
   402    414     }
   403    415     if( Tcl_Init(tclInterp)!=TCL_OK ){
   404         -    Th_ErrorMessage(interp,
   405         -        "Tcl initialization error:", Tcl_GetStringResult(tclInterp), -1);
          416  +    Jim_SetResultFormatted(interp, "Tcl initialization error: %s",
          417  +        Tcl_GetStringResult(tclInterp));
   406    418       Tcl_DeleteInterp(tclInterp);
   407    419       tclContext->interp = tclInterp = 0;
   408         -    return TH_ERROR;
          420  +    return JIM_ERR;
   409    421     }
   410         -  /* Add the TH1 integration commands to Tcl. */
   411         -  Tcl_CallWhenDeleted(tclInterp, Th1DeleteProc, interp);
   412         -  Tcl_CreateObjCommand(tclInterp, "th1Eval", Th1EvalObjCmd, interp, NULL);
   413         -  Tcl_CreateObjCommand(tclInterp, "th1Expr", Th1ExprObjCmd, interp, NULL);
   414         -  return TH_OK;
          422  +  /* Add the Jim integration commands to Tcl. */
          423  +  Tcl_CallWhenDeleted(tclInterp, BridgeDeleteProc, interp);
          424  +  Tcl_CreateObjCommand(tclInterp, "bridgeEval", BridgeEvalObjCmd, interp, NULL);
          425  +  Tcl_CreateObjCommand(tclInterp, "bridgeExpr", BridgeExprObjCmd, interp, NULL);
          426  +  return JIM_OK;
   415    427   }
   416    428   
   417    429   /*
   418    430   ** Register the Tcl language commands with interpreter interp.
   419    431   ** Usually this is called soon after interpreter creation.
   420    432   */
   421         -int th_register_tcl(
   422         -  Th_Interp *interp,
          433  +int register_tcl(
          434  +  Jim_Interp *interp,
   423    435     void *pContext
   424    436   ){
   425    437     int i;
   426         -  /* Add the Tcl integration commands to TH1. */
          438  +  /* Add the Tcl integration commands to Jim. */
   427    439     for(i=0; i<(sizeof(aCommand)/sizeof(aCommand[0])); i++){
   428    440       void *ctx;
   429    441       if ( !aCommand[i].zName || !aCommand[i].xProc ) continue;
   430    442       ctx = aCommand[i].pContext;
   431    443       /* Use Tcl interpreter for context? */
   432    444       if( !ctx ) ctx = pContext;
   433         -    Th_CreateCommand(interp, aCommand[i].zName, aCommand[i].xProc, ctx, 0);
          445  +    Jim_CreateCommand(interp, aCommand[i].zName, aCommand[i].xProc, ctx, NULL);
   434    446     }
   435         -  return TH_OK;
          447  +  return JIM_OK;
   436    448   }
   437    449   
   438    450   #endif /* FOSSIL_ENABLE_TCL */

Changes to src/tkt.c.

    96     96   ** using the CONCEALED table so that the content legable.
    97     97   ** Otherwise, db_reveal() is a no-op and the content remains
    98     98   ** obscured.
    99     99   */
   100    100   static void initializeVariablesFromDb(void){
   101    101     const char *zName;
   102    102     Stmt q;
   103         -  int i, n, size, j;
          103  +  int i, n, j;
   104    104   
   105    105     zName = PD("name","-none-");
   106    106     db_prepare(&q, "SELECT datetime(tkt_mtime,'localtime') AS tkt_datetime, *"
   107    107                    "  FROM ticket WHERE tkt_uuid GLOB '%q*'", zName);
   108    108     if( db_step(&q)==SQLITE_ROW ){
   109    109       n = db_column_count(&q);
   110    110       for(i=0; i<n; i++){
................................................................................
   118    118         }
   119    119         for(j=0; j<nField; j++){
   120    120           if( fossil_strcmp(azField[j],zName)==0 ){
   121    121             azValue[j] = mprintf("%s", zVal);
   122    122             break;
   123    123           }
   124    124         }
   125         -      if( Th_Fetch(zName, &size)==0 ){
          125  +      if( Th_Fetch(zName)==0 ){
   126    126           Th_Store(zName, zVal);
   127    127         }
   128    128         free(zRevealed);
   129    129       }
   130    130     }else{
   131    131       db_finalize(&q);
   132    132       db_prepare(&q, "PRAGMA table_info(ticket)");
   133         -    if( Th_Fetch("tkt_uuid",&size)==0 ){
          133  +    if( Th_Fetch("tkt_uuid")==0 ){
   134    134         Th_Store("tkt_uuid",zName);
   135    135       }
   136    136       while( db_step(&q)==SQLITE_ROW ){
   137    137         const char *zField = db_column_text(&q, 1);
   138         -      if( Th_Fetch(zField, &size)==0 ){
          138  +      if( Th_Fetch(zField)==0 ){
   139    139           Th_Store(zField, "");
   140    140         }
   141    141       }
   142         -    if( Th_Fetch("tkt_datetime",&size)==0 ){
          142  +    if( Th_Fetch("tkt_datetime")==0 ){
   143    143         Th_Store("tkt_datetime","");
   144    144       }
   145    145     }
   146    146     db_finalize(&q);
   147    147   }
   148    148   
   149    149   /*
................................................................................
   238    238   /*
   239    239   ** Create the subscript interpreter and load the "common" code.
   240    240   */
   241    241   void ticket_init(void){
   242    242     const char *zConfig;
   243    243     Th_FossilInit();
   244    244     zConfig = ticket_common_code();
   245         -  Th_Eval(g.interp, 0, zConfig, -1);
          245  +  Jim_Eval(g.interp, zConfig);
   246    246   }
   247    247   
   248    248   /*
   249    249   ** Recreate the ticket table.
   250    250   */
   251    251   void ticket_create_table(int separateConnection){
   252    252     const char *zSql;
................................................................................
   371    371   ** TH command:   append_field FIELD STRING
   372    372   **
   373    373   ** FIELD is the name of a database column to which we might want
   374    374   ** to append text.  STRING is the text to be appended to that
   375    375   ** column.  The append does not actually occur until the
   376    376   ** submit_ticket command is run.
   377    377   */
   378         -static int appendRemarkCmd(
   379         -  Th_Interp *interp, 
   380         -  void *p, 
   381         -  int argc, 
   382         -  const char **argv, 
   383         -  int *argl
   384         -){
          378  +static int appendRemarkCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
          379  +{
   385    380     int idx;
          381  +  const char *str;
          382  +  int len;
   386    383   
   387    384     if( argc!=3 ){
   388         -    return Th_WrongNumArgs(interp, "append_field FIELD STRING");
          385  +    Jim_WrongNumArgs(interp, 1, argv, "FIELD STRING");
          386  +    return JIM_ERR;
   389    387     }
          388  +  str = Jim_GetString(argv[1], &len);
   390    389     if( g.thTrace ){
   391    390       Th_Trace("append_field %#h {%#h}<br />\n",
   392         -              argl[1], argv[1], argl[2], argv[2]);
          391  +              len, str, Jim_Length(argv[2]), Jim_String(argv[2]));
   393    392     }
   394    393     for(idx=0; idx<nField; idx++){
   395         -    if( strncmp(azField[idx], argv[1], argl[1])==0
   396         -        && azField[idx][argl[1]]==0 ){
          394  +    if( strncmp(azField[idx], str, len)==0
          395  +        && azField[idx][len]==0 ){
   397    396         break;
   398    397       }
   399    398     }
   400    399     if( idx>=nField ){
   401         -    Th_ErrorMessage(g.interp, "no such TICKET column: ", argv[1], argl[1]);
   402         -    return TH_ERROR;
          400  +    Jim_SetResultFormatted(g.interp, "no such TICKET column: %#s", argv[1]);
          401  +    return JIM_ERR;
   403    402     }
   404         -  azAppend[idx] = mprintf("%.*s", argl[2], argv[2]);
   405         -  return TH_OK;
          403  +  azAppend[idx] = mprintf("%.*s", Jim_Length(argv[2]), Jim_String(argv[2]));
          404  +  return JIM_OK;
   406    405   }
   407    406   
   408    407   /*
   409    408   ** Subscript command:   submit_ticket
   410    409   **
   411    410   ** Construct and submit a new ticket artifact.  The fields of the artifact
   412    411   ** are the names of the columns in the TICKET table.  The content is
   413    412   ** taken from TH variables.  If the content is unchanged, the field is
   414    413   ** omitted from the artifact.  Fields whose names begin with "private_"
   415    414   ** are concealed using the db_conceal() function.
   416    415   */
   417         -static int submitTicketCmd(
   418         -  Th_Interp *interp, 
   419         -  void *pUuid, 
   420         -  int argc, 
   421         -  const char **argv, 
   422         -  int *argl
   423         -){
          416  +static int submitTicketCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
          417  +{
   424    418     char *zDate;
          419  +  void *pUuid = Jim_CmdPrivData(interp);
   425    420     const char *zUuid;
   426    421     int i;
   427    422     int rid;
   428    423     Blob tktchng, cksum;
   429    424   
   430    425     login_verify_csrf_secret();
   431    426     zUuid = (const char *)pUuid;
................................................................................
   439    434                      fossilize(azAppend[i], -1));
   440    435       }
   441    436     }
   442    437     for(i=0; i<nField; i++){
   443    438       const char *zValue;
   444    439       int nValue;
   445    440       if( azAppend[i] ) continue;
   446         -    zValue = Th_Fetch(azField[i], &nValue);
          441  +    zValue = Th_Fetch(azField[i]);
   447    442       if( zValue ){
          443  +      nValue = strlen(zValue);
   448    444         while( nValue>0 && fossil_isspace(zValue[nValue-1]) ){ nValue--; }
   449    445         if( strncmp(zValue, azValue[i], nValue) || strlen(azValue[i])!=nValue ){
   450    446           if( strncmp(azField[i], "private_", 8)==0 ){
   451    447             zValue = db_conceal(zValue, nValue);
   452    448             blob_appendf(&tktchng, "J %s %s\n", azField[i], zValue);
   453    449           }else{
   454    450             blob_appendf(&tktchng, "J %s %#F\n", azField[i], nValue, zValue);
................................................................................
   470    466     blob_appendf(&tktchng, "Z %b\n", &cksum);
   471    467     if( g.zPath[0]=='d' ){
   472    468       /* If called from /debug_tktnew or /debug_tktedit... */
   473    469       @ <font color="blue">
   474    470       @ <p>Ticket artifact that would have been submitted:</p>
   475    471       @ <blockquote><pre>%h(blob_str(&tktchng))</pre></blockquote>
   476    472       @ <hr /></font>
   477         -    return TH_OK;
          473  +    return JIM_OK;
   478    474     }else if( g.thTrace ){
   479    475       Th_Trace("submit_ticket {\n<blockquote><pre>\n%h\n</pre></blockquote>\n"
   480    476                "}<br />\n",
   481    477          blob_str(&tktchng));
   482    478     }else{
   483    479       rid = content_put(&tktchng);
   484    480       if( rid==0 ){
................................................................................
   485    481         fossil_panic("trouble committing ticket: %s", g.zErrMsg);
   486    482       }
   487    483       manifest_crosslink_begin();
   488    484       manifest_crosslink(rid, &tktchng);
   489    485       assert( blob_is_reset(&tktchng) );
   490    486       manifest_crosslink_end();
   491    487     }
   492         -  return TH_RETURN;
          488  +  return JIM_RETURN;
   493    489   }
   494    490   
   495    491   
   496    492   /*
   497    493   ** WEBPAGE: tktnew
   498    494   ** WEBPAGE: debug_tktnew
   499    495   **
................................................................................
   525    521     if( P("date_override") && g.perm.Setup ){
   526    522       @ <input type="hidden" name="date_override" value="%h(P("date_override"))">
   527    523     }
   528    524     @ </p>
   529    525     zScript = ticket_newpage_code();
   530    526     Th_Store("login", g.zLogin);
   531    527     Th_Store("date", db_text(0, "SELECT datetime('now')"));
   532         -  Th_CreateCommand(g.interp, "submit_ticket", submitTicketCmd,
   533         -                   (void*)&zNewUuid, 0);
          528  +  Jim_CreateCommand(g.interp, "submit_ticket", submitTicketCmd, (void *)&zNewUuid, NULL);
   534    529     if( g.thTrace ) Th_Trace("BEGIN_TKTNEW_SCRIPT<br />\n", -1);
   535         -  if( Th_Render(zScript)==TH_RETURN && !g.thTrace && zNewUuid ){
          530  +  if( Th_Render(zScript)==JIM_RETURN && !g.thTrace && zNewUuid ){
   536    531       cgi_redirect(mprintf("%s/tktview/%s", g.zTop, zNewUuid));
   537    532       return;
   538    533     }
   539    534     @ </form>
   540    535     if( g.thTrace ) Th_Trace("END_TKTVIEW<br />\n", -1);
   541    536     style_footer();
   542    537   }
................................................................................
   592    587     @ <form method="post" action="%s(g.zTop)/%s(g.zPath)"><p>
   593    588     @ <input type="hidden" name="name" value="%s(zName)" />
   594    589     login_insert_csrf_secret();
   595    590     @ </p>
   596    591     zScript = ticket_editpage_code();
   597    592     Th_Store("login", g.zLogin);
   598    593     Th_Store("date", db_text(0, "SELECT datetime('now')"));
   599         -  Th_CreateCommand(g.interp, "append_field", appendRemarkCmd, 0, 0);
   600         -  Th_CreateCommand(g.interp, "submit_ticket", submitTicketCmd, (void*)&zName,0);
          594  +  Jim_CreateCommand(g.interp, "append_field", appendRemarkCmd, NULL, NULL);
          595  +  Jim_CreateCommand(g.interp, "submit_ticket", submitTicketCmd, (void*)&zName, NULL);
   601    596     if( g.thTrace ) Th_Trace("BEGIN_TKTEDIT_SCRIPT<br />\n", -1);
   602         -  if( Th_Render(zScript)==TH_RETURN && !g.thTrace && zName ){
          597  +  if( Th_Render(zScript)==JIM_RETURN && !g.thTrace && zName ){
   603    598       cgi_redirect(mprintf("%s/tktview/%s", g.zTop, zName));
   604    599       return;
   605    600     }
   606    601     @ </form>
   607    602     if( g.thTrace ) Th_Trace("BEGIN_TKTEDIT<br />\n", -1);
   608    603     style_footer();
   609    604   }

Changes to src/xfer.c.

   789    789   ** from a server without authorization.
   790    790   */
   791    791   static void server_private_xfer_not_authorized(void){
   792    792     @ error not\sauthorized\sto\ssync\sprivate\scontent
   793    793   }
   794    794   
   795    795   /*
   796         -** Run the specified TH1 script, if any, and returns the return code or TH_OK
          796  +** Run the specified TH1 script, if any, and returns the return code or JIM_OK
   797    797   ** when there is no script.
   798    798   */
   799    799   static int run_script(const char *zScript){
   800    800     if( !zScript ){
   801         -    return TH_OK; /* No script, return success. */
          801  +    return JIM_OK; /* No script, return success. */
   802    802     }
   803    803     Th_FossilInit(); /* Make sure TH1 is ready. */
   804         -  return Th_Eval(g.interp, 0, zScript, -1);
          804  +  return Jim_Eval(g.interp, zScript);
   805    805   }
   806    806   
   807    807   /*
   808    808   ** Run the pre-transfer TH1 script, if any, and returns the return code.
   809    809   */
   810    810   static int run_common_script(void){
   811    811     return run_script(db_get("xfer-common-script", 0));
................................................................................
   870    870     g.xferPanic = 1;
   871    871   
   872    872     db_begin_transaction();
   873    873     db_multi_exec(
   874    874        "CREATE TEMP TABLE onremote(rid INTEGER PRIMARY KEY);"
   875    875     );
   876    876     manifest_crosslink_begin();
   877         -  if( run_common_script()==TH_ERROR ){
          877  +  if( run_common_script()!=JIM_OK ){
   878    878       cgi_reset_content();
   879         -    @ error common\sscript\sfailed:\s%F(Th_GetResult(g.interp, 0))
          879  +    @ error common\sscript\sfailed:\s%F(Jim_String(Jim_GetResult(g.interp)))
   880    880       nErr++;
   881    881     }
   882    882     while( blob_line(xfer.pIn, &xfer.line) ){
   883    883       if( blob_buffer(&xfer.line)[0]=='#' ) continue;
   884    884       if( blob_size(&xfer.line)==0 ) continue;
   885    885       xfer.nToken = blob_tokenize(&xfer.line, xfer.aToken, count(xfer.aToken));
   886    886   
................................................................................
  1188   1188       {
  1189   1189         cgi_reset_content();
  1190   1190         @ error bad\scommand:\s%F(blob_str(&xfer.line))
  1191   1191       }
  1192   1192       blobarray_reset(xfer.aToken, xfer.nToken);
  1193   1193     }
  1194   1194     if( isPush ){
  1195         -    if( run_push_script()==TH_ERROR ){
         1195  +    if( run_push_script()!=JIM_OK ){
  1196   1196         cgi_reset_content();
  1197         -      @ error push\sscript\sfailed:\s%F(Th_GetResult(g.interp, 0))
         1197  +      @ error push\sscript\sfailed:\s%F(Jim_String(Jim_GetResult(g.interp)))
  1198   1198         nErr++;
  1199   1199       }
  1200   1200       request_phantoms(&xfer, 500);
  1201   1201     }
  1202   1202     if( isClone && nGimme==0 ){
  1203   1203       /* The initial "clone" message from client to server contains no
  1204   1204       ** "gimme" cards. On that initial message, send the client an "igot"

Changes to test/th1-tcl.test.

    22     22   
    23     23   ###############################################################################
    24     24   
    25     25   set env(TH1_ENABLE_TCL) 1; # Tcl integration must be enabled for this test.
    26     26   
    27     27   ###############################################################################
    28     28   
    29         -fossil test-th-render [file nativename [file join $dir th1-tcl1.txt]]
           29  +fossil test-script-render [file nativename [file join $dir th1-tcl1.txt]]
    30     30   
    31     31   test th1-tcl-1 {[regexp -- {^\d+
    32     32   \d+
    33     33   \d+
    34     34   via Tcl invoke
    35     35   4
    36     36   4
................................................................................
    46     46   \d+
    47     47   one_word
    48     48   three words now
    49     49   $} [string map [list \r\n \n] $RESULT]]}
    50     50   
    51     51   ###############################################################################
    52     52   
    53         -fossil test-th-render [file nativename [file join $dir th1-tcl2.txt]]
           53  +fossil test-script-render [file nativename [file join $dir th1-tcl2.txt]]
    54     54   
    55     55   test th1-tcl-2 {[regexp -- {^\d+
    56     56   $} [string map [list \r\n \n] $RESULT]]}
    57     57   
    58     58   ###############################################################################
    59     59   
    60         -fossil test-th-render [file nativename [file join $dir th1-tcl3.txt]]
           60  +fossil test-script-render [file nativename [file join $dir th1-tcl3.txt]]
    61     61   
    62     62   test th1-tcl-3 {$RESULT eq {<hr><p class="thmainError">ERROR:\
    63     63   invalid command name &quot;bad_command&quot;</p>}}
    64     64   
    65     65   ###############################################################################
    66     66   
    67         -fossil test-th-render [file nativename [file join $dir th1-tcl4.txt]]
           67  +fossil test-script-render [file nativename [file join $dir th1-tcl4.txt]]
    68     68   
    69     69   test th1-tcl-4 {$RESULT eq {<hr><p class="thmainError">ERROR:\
    70     70   divide by zero</p>}}
    71     71   
    72     72   ###############################################################################
    73     73   
    74         -fossil test-th-render [file nativename [file join $dir th1-tcl5.txt]]
           74  +fossil test-script-render [file nativename [file join $dir th1-tcl5.txt]]
    75     75   
    76     76   test th1-tcl-5 {$RESULT eq {<hr><p class="thmainError">ERROR:\
    77     77   Tcl command not found: bad_command</p>} || $RESULT eq {<hr><p\
    78     78   class="thmainError">ERROR: invalid command name &quot;bad_command&quot;</p>}}
    79     79   
    80     80   ###############################################################################
    81     81   
    82         -fossil test-th-render [file nativename [file join $dir th1-tcl6.txt]]
           82  +fossil test-script-render [file nativename [file join $dir th1-tcl6.txt]]
    83     83   
    84     84   test th1-tcl-6 {$RESULT eq {<hr><p class="thmainError">ERROR:\
    85     85   no such command:  bad_command</p>}}
    86     86   
    87     87   ###############################################################################
    88     88   
    89         -fossil test-th-render [file nativename [file join $dir th1-tcl7.txt]]
           89  +fossil test-script-render [file nativename [file join $dir th1-tcl7.txt]]
    90     90   
    91     91   test th1-tcl-7 {$RESULT eq {<hr><p class="thmainError">ERROR:\
    92     92   syntax error in expression: &quot;2**0&quot;</p>}}
    93     93   
    94     94   ###############################################################################
    95     95   
    96         -fossil test-th-render [file nativename [file join $dir th1-tcl8.txt]]
           96  +fossil test-script-render [file nativename [file join $dir th1-tcl8.txt]]
    97     97   
    98     98   test th1-tcl-8 {$RESULT eq {<hr><p class="thmainError">ERROR:\
    99     99   Cannot invoke Tcl command: tailcall</p>} || $RESULT eq {<hr><p\
   100    100   class="thmainError">ERROR: tailcall can only be called from a proc or\
   101    101   lambda</p>}}
   102    102   

Changes to test/th1-tcl1.txt.

     1      1   <th1>
     2      2     #
     3         -  # This is a "TH1 fragment" used to test the Tcl integration features of TH1.
     4         -  # The corresponding test file executes this file using the test-th-render
     5         -  # Fossil command.
            3  +  # This is a "script fragment" used to test the Tcl integration features of
            4  +  # Fossil.  The corresponding test file executes this file using the
            5  +  # test-script-render Fossil command.
     6      6     #
     7      7     set channel stdout; tclInvoke set channel $channel
     8      8     proc doOut {msg} {puts $msg; puts \n}
     9      9     doOut [tclEval clock seconds]
    10     10     doOut [tclEval {set x [clock seconds]}]
    11     11     tclEval {puts $channel "[clock seconds]"}
    12     12     tclInvoke puts $channel "via Tcl invoke"
    13     13     doOut [tclExpr 2+2]
    14     14     doOut [tclExpr 2 + 2]
    15     15     doOut [tclInvoke set x "two words"]
    16     16     doOut [tclInvoke eval set y one_word]
    17     17     doOut [tclInvoke eval {set z "three words now"}]
    18     18     doOut [set x [tclEval {set x [clock seconds]}]]
    19         -  doOut [tclInvoke th1Eval {set y "two words"}]
    20         -  doOut [set z [tclInvoke th1Expr {2+2}]]
           19  +  doOut [tclInvoke bridgeEval {set y "two words"}]
           20  +  doOut [set z [tclInvoke bridgeExpr {2+2}]]
    21     21     doOut $x
    22     22     doOut $y
    23     23     doOut $z
    24     24     doOut [tclEval set x]
    25     25     doOut [tclEval set y]
    26     26     doOut [tclEval set z]
    27     27   </th1>

Changes to test/th1-tcl2.txt.

     1      1   <th1>
     2      2     #
     3         -  # This is a "TH1 fragment" used to test the Tcl integration features of TH1.
     4         -  # The corresponding test file executes this file using the test-th-render
     5         -  # Fossil command.
            3  +  # This is a "script fragment" used to test the Tcl integration features of
            4  +  # Fossil.  The corresponding test file executes this file using the
            5  +  # test-script-render Fossil command.
     6      6     #
     7      7     # NOTE: This test requires that the SQLite package be available for the Tcl
     8      8     #       interpreter that is linked to the Fossil executable.
     9      9     #
    10     10     tclInvoke set repository_name [repository 1]
    11     11     proc doOut {msg} {puts $msg; puts \n}
    12     12     doOut [tclEval {

Changes to test/th1-tcl3.txt.

     1      1   <th1>
     2      2     #
     3         -  # This is a "TH1 fragment" used to test the Tcl integration features of TH1.
     4         -  # The corresponding test file executes this file using the test-th-render
     5         -  # Fossil command.
            3  +  # This is a "script fragment" used to test the Tcl integration features of
            4  +  # Fossil.  The corresponding test file executes this file using the
            5  +  # test-script-render Fossil command.
     6      6     #
     7      7     proc doOut {msg} {puts $msg; puts \n}
     8      8     doOut [tclEval bad_command]
     9      9   </th1>

Changes to test/th1-tcl4.txt.

     1      1   <th1>
     2      2     #
     3         -  # This is a "TH1 fragment" used to test the Tcl integration features of TH1.
     4         -  # The corresponding test file executes this file using the test-th-render
     5         -  # Fossil command.
            3  +  # This is a "script fragment" used to test the Tcl integration features of
            4  +  # Fossil.  The corresponding test file executes this file using the
            5  +  # test-script-render Fossil command.
     6      6     #
     7      7     proc doOut {msg} {puts $msg; puts \n}
     8      8     doOut [tclExpr 2/0]
     9      9   </th1>

Changes to test/th1-tcl5.txt.

     1      1   <th1>
     2      2     #
     3         -  # This is a "TH1 fragment" used to test the Tcl integration features of TH1.
     4         -  # The corresponding test file executes this file using the test-th-render
     5         -  # Fossil command.
            3  +  # This is a "script fragment" used to test the Tcl integration features of
            4  +  # Fossil.  The corresponding test file executes this file using the
            5  +  # test-script-render Fossil command.
     6      6     #
     7      7     proc doOut {msg} {puts $msg; puts \n}
     8      8     doOut [tclInvoke bad_command]
     9      9   </th1>

Changes to test/th1-tcl6.txt.

     1      1   <th1>
     2      2     #
     3         -  # This is a "TH1 fragment" used to test the Tcl integration features of TH1.
     4         -  # The corresponding test file executes this file using the test-th-render
     5         -  # Fossil command.
            3  +  # This is a "script fragment" used to test the Tcl integration features of
            4  +  # Fossil.  The corresponding test file executes this file using the
            5  +  # test-script-render Fossil command.
     6      6     #
     7      7     proc doOut {msg} {puts $msg; puts \n}
     8         -  doOut [tclEval th1Eval bad_command]
            8  +  doOut [tclEval bridgeEval bad_command]
     9      9   </th1>

Changes to test/th1-tcl7.txt.

     1      1   <th1>
     2      2     #
     3         -  # This is a "TH1 fragment" used to test the Tcl integration features of TH1.
     4         -  # The corresponding test file executes this file using the test-th-render
     5         -  # Fossil command.
            3  +  # This is a "script fragment" used to test the Tcl integration features of
            4  +  # Fossil.  The corresponding test file executes this file using the
            5  +  # test-script-render Fossil command.
     6      6     #
     7      7     proc doOut {msg} {puts $msg; puts \n}
     8      8   
     9      9     #
    10     10     # BUGBUG: Attempting to divide by zero will crash TH1 with the error:
    11     11     #         "child killed: floating-point exception"
    12     12     #
    13         -  # doOut [tclEval th1Expr 2/0]
           13  +  # doOut [tclEval bridgeExpr 2/0]
    14     14   
    15     15     #
    16     16     # NOTE: For now, just cause an expression syntax error.
    17     17     #
    18         -  doOut [tclEval th1Expr 2**0]
           18  +  doOut [tclEval bridgeExpr 2**0]
    19     19   </th1>

Changes to test/th1-tcl8.txt.

     1      1   <th1>
     2      2     #
     3         -  # This is a "TH1 fragment" used to test the Tcl integration features of TH1.
     4         -  # The corresponding test file executes this file using the test-th-render
     5         -  # Fossil command.
            3  +  # This is a "script fragment" used to test the Tcl integration features of
            4  +  # Fossil.  The corresponding test file executes this file using the
            5  +  # test-script-render Fossil command.
     6      6     #
     7      7     proc doOut {msg} {puts $msg; puts \n}
     8      8   
     9      9     if {[tclInvoke set tcl_version] >= 8.6} {
    10     10       doOut [tclInvoke tailcall set x 1]
    11     11     } else {
    12     12       doOut "This test requires Tcl 8.6 or higher."
    13     13     }
    14     14   </th1>

Changes to win/Makefile.PellesCGMake.

   143    143   	mkindex.exe $(TRANSLATEDSRC) >$@
   144    144   
   145    145   # extracting version info from manifest
   146    146   VERSION.h:	version.exe ..\manifest.uuid ..\manifest ..\VERSION
   147    147   	version.exe ..\manifest.uuid ..\manifest ..\VERSION  > $@
   148    148   
   149    149   # generate the simplified headers
   150         -headers: makeheaders.exe page_index.h VERSION.h ../src/sqlite3.h ../src/th.h VERSION.h
   151         -	makeheaders.exe $(foreach ts,$(TRANSLATEDSRC),$(ts):$(ts:_.c=.h)) ../src/sqlite3.h ../src/th.h VERSION.h
          150  +headers: makeheaders.exe page_index.h VERSION.h ../src/sqlite3.h ../src/jim.h VERSION.h
          151  +	makeheaders.exe $(foreach ts,$(TRANSLATEDSRC),$(ts):$(ts:_.c=.h)) ../src/sqlite3.h ../src/jim.h VERSION.h
   152    152   	echo Done >$@
   153    153   
   154    154   # compile C sources with relevant options
   155    155   
   156    156   $(TRANSLATEDOBJ):	%_.obj:	%_.c %.h
   157    157   	$(CC) $(CCFLAGS) $(INCLUDE) "$<" -Fo"$@"
   158    158   
   159    159   $(SQLITEOBJ):	%.obj:	$(SRCDIR)%.c $(SRCDIR)%.h
   160    160   	$(CC) $(CCFLAGS) $(SQLITEDEFINES) $(INCLUDE) "$<" -Fo"$@"
   161    161   
   162    162   $(SQLITESHELLOBJ):	%.obj:	$(SRCDIR)%.c
   163    163   	$(CC) $(CCFLAGS) $(SQLITESHELLDEFINES) $(INCLUDE) "$<" -Fo"$@"
   164    164   
   165         -$(THOBJ):	%.obj:	$(SRCDIR)%.c $(SRCDIR)th.h
          165  +$(THOBJ):	%.obj:	$(SRCDIR)%.c $(SRCDIR)jim.h
   166    166   	$(CC) $(CCFLAGS) $(INCLUDE) "$<" -Fo"$@"
   167    167   
   168    168   $(ZLIBOBJ):	%.obj:	$(ZLIBSRCDIR)%.c
   169    169   	$(CC) $(CCFLAGS) $(INCLUDE) "$<" -Fo"$@"
   170    170   
   171    171   # create the windows resource with icon and version info
   172    172   $(RESOURCE):	%.res:	../win/%.rc ../win/*.ico

Changes to win/Makefile.dmc.

   670    670   $(OBJDIR)\zip$O : zip_.c zip.h
   671    671   	$(TCC) -o$@ -c zip_.c
   672    672   
   673    673   zip_.c : $(SRCDIR)\zip.c
   674    674   	+translate$E $** > $@
   675    675   
   676    676   headers: makeheaders$E page_index.h VERSION.h
   677         -	 +makeheaders$E add_.c:add.h allrepo_.c:allrepo.h attach_.c:attach.h bag_.c:bag.h bisect_.c:bisect.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h captcha_.c:captcha.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h configure_.c:configure.h content_.c:content.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h descendants_.c:descendants.h diff_.c:diff.h diffcmd_.c:diffcmd.h doc_.c:doc.h encode_.c:encode.h event_.c:event.h export_.c:export.h file_.c:file.h finfo_.c:finfo.h glob_.c:glob.h graph_.c:graph.h gzip_.c:gzip.h http_.c:http.h http_socket_.c:http_socket.h http_ssl_.c:http_ssl.h http_transport_.c:http_transport.h import_.c:import.h info_.c:info.h json_.c:json.h json_artifact_.c:json_artifact.h json_branch_.c:json_branch.h json_diff_.c:json_diff.h json_login_.c:json_login.h json_query_.c:json_query.h json_report_.c:json_report.h json_tag_.c:json_tag.h json_timeline_.c:json_timeline.h json_user_.c:json_user.h json_wiki_.c:json_wiki.h leaf_.c:leaf.h login_.c:login.h main_.c:main.h manifest_.c:manifest.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h name_.c:name.h path_.c:path.h pivot_.c:pivot.h popen_.c:popen.h pqueue_.c:pqueue.h printf_.c:printf.h rebuild_.c:rebuild.h report_.c:report.h rss_.c:rss.h schema_.c:schema.h search_.c:search.h setup_.c:setup.h sha1_.c:sha1.h shun_.c:shun.h skins_.c:skins.h sqlcmd_.c:sqlcmd.h stash_.c:stash.h stat_.c:stat.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h tar_.c:tar.h th_main_.c:th_main.h timeline_.c:timeline.h tkt_.c:tkt.h tktsetup_.c:tktsetup.h undo_.c:undo.h update_.c:update.h url_.c:url.h user_.c:user.h verify_.c:verify.h vfile_.c:vfile.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h winhttp_.c:winhttp.h xfer_.c:xfer.h xfersetup_.c:xfersetup.h zip_.c:zip.h $(SRCDIR)\sqlite3.h $(SRCDIR)\th.h VERSION.h $(SRCDIR)\cson_amalgamation.h
          677  +	 +makeheaders$E add_.c:add.h allrepo_.c:allrepo.h attach_.c:attach.h bag_.c:bag.h bisect_.c:bisect.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h captcha_.c:captcha.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h configure_.c:configure.h content_.c:content.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h descendants_.c:descendants.h diff_.c:diff.h diffcmd_.c:diffcmd.h doc_.c:doc.h encode_.c:encode.h event_.c:event.h export_.c:export.h file_.c:file.h finfo_.c:finfo.h glob_.c:glob.h graph_.c:graph.h gzip_.c:gzip.h http_.c:http.h http_socket_.c:http_socket.h http_ssl_.c:http_ssl.h http_transport_.c:http_transport.h import_.c:import.h info_.c:info.h json_.c:json.h json_artifact_.c:json_artifact.h json_branch_.c:json_branch.h json_diff_.c:json_diff.h json_login_.c:json_login.h json_query_.c:json_query.h json_report_.c:json_report.h json_tag_.c:json_tag.h json_timeline_.c:json_timeline.h json_user_.c:json_user.h json_wiki_.c:json_wiki.h leaf_.c:leaf.h login_.c:login.h main_.c:main.h manifest_.c:manifest.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h name_.c:name.h path_.c:path.h pivot_.c:pivot.h popen_.c:popen.h pqueue_.c:pqueue.h printf_.c:printf.h rebuild_.c:rebuild.h report_.c:report.h rss_.c:rss.h schema_.c:schema.h search_.c:search.h setup_.c:setup.h sha1_.c:sha1.h shun_.c:shun.h skins_.c:skins.h sqlcmd_.c:sqlcmd.h stash_.c:stash.h stat_.c:stat.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h tar_.c:tar.h th_main_.c:th_main.h timeline_.c:timeline.h tkt_.c:tkt.h tktsetup_.c:tktsetup.h undo_.c:undo.h update_.c:update.h url_.c:url.h user_.c:user.h verify_.c:verify.h vfile_.c:vfile.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h winhttp_.c:winhttp.h xfer_.c:xfer.h xfersetup_.c:xfersetup.h zip_.c:zip.h $(SRCDIR)\sqlite3.h $(SRCDIR)\jim.h VERSION.h
          678  +$(SRCDIR)\sqlite3.h $(SRCDIR)\jim.h VERSION.h $(SRCDIR)\cson_amalgamation.h
   678    679   	@copy /Y nul: headers

Changes to win/Makefile.mingw.

   516    516   setup: $(OBJDIR) $(APPNAME)
   517    517   	$(MAKENSIS) ./fossil.nsi
   518    518   
   519    519   
   520    520   $(OBJDIR)/page_index.h: $(TRANS_SRC) $(OBJDIR)/mkindex
   521    521   	$(MKINDEX) $(TRANS_SRC) >$@
   522    522   $(OBJDIR)/headers:	$(OBJDIR)/page_index.h $(OBJDIR)/makeheaders $(OBJDIR)/VERSION.h
   523         -	$(MAKEHEADERS)  $(OBJDIR)/add_.c:$(OBJDIR)/add.h $(OBJDIR)/allrepo_.c:$(OBJDIR)/allrepo.h $(OBJDIR)/attach_.c:$(OBJDIR)/attach.h $(OBJDIR)/bag_.c:$(OBJDIR)/bag.h $(OBJDIR)/bisect_.c:$(OBJDIR)/bisect.h $(OBJDIR)/blob_.c:$(OBJDIR)/blob.h $(OBJDIR)/branch_.c:$(OBJDIR)/branch.h $(OBJDIR)/browse_.c:$(OBJDIR)/browse.h $(OBJDIR)/captcha_.c:$(OBJDIR)/captcha.h $(OBJDIR)/cgi_.c:$(OBJDIR)/cgi.h $(OBJDIR)/checkin_.c:$(OBJDIR)/checkin.h $(OBJDIR)/checkout_.c:$(OBJDIR)/checkout.h $(OBJDIR)/clearsign_.c:$(OBJDIR)/clearsign.h $(OBJDIR)/clone_.c:$(OBJDIR)/clone.h $(OBJDIR)/comformat_.c:$(OBJDIR)/comformat.h $(OBJDIR)/configure_.c:$(OBJDIR)/configure.h $(OBJDIR)/content_.c:$(OBJDIR)/content.h $(OBJDIR)/db_.c:$(OBJDIR)/db.h $(OBJDIR)/delta_.c:$(OBJDIR)/delta.h $(OBJDIR)/deltacmd_.c:$(OBJDIR)/deltacmd.h $(OBJDIR)/descendants_.c:$(OBJDIR)/descendants.h $(OBJDIR)/diff_.c:$(OBJDIR)/diff.h $(OBJDIR)/diffcmd_.c:$(OBJDIR)/diffcmd.h $(OBJDIR)/doc_.c:$(OBJDIR)/doc.h $(OBJDIR)/encode_.c:$(OBJDIR)/encode.h $(OBJDIR)/event_.c:$(OBJDIR)/event.h $(OBJDIR)/export_.c:$(OBJDIR)/export.h $(OBJDIR)/file_.c:$(OBJDIR)/file.h $(OBJDIR)/finfo_.c:$(OBJDIR)/finfo.h $(OBJDIR)/glob_.c:$(OBJDIR)/glob.h $(OBJDIR)/graph_.c:$(OBJDIR)/graph.h $(OBJDIR)/gzip_.c:$(OBJDIR)/gzip.h $(OBJDIR)/http_.c:$(OBJDIR)/http.h $(OBJDIR)/http_socket_.c:$(OBJDIR)/http_socket.h $(OBJDIR)/http_ssl_.c:$(OBJDIR)/http_ssl.h $(OBJDIR)/http_transport_.c:$(OBJDIR)/http_transport.h $(OBJDIR)/import_.c:$(OBJDIR)/import.h $(OBJDIR)/info_.c:$(OBJDIR)/info.h $(OBJDIR)/json_.c:$(OBJDIR)/json.h $(OBJDIR)/json_artifact_.c:$(OBJDIR)/json_artifact.h $(OBJDIR)/json_branch_.c:$(OBJDIR)/json_branch.h $(OBJDIR)/json_diff_.c:$(OBJDIR)/json_diff.h $(OBJDIR)/json_login_.c:$(OBJDIR)/json_login.h $(OBJDIR)/json_query_.c:$(OBJDIR)/json_query.h $(OBJDIR)/json_report_.c:$(OBJDIR)/json_report.h $(OBJDIR)/json_tag_.c:$(OBJDIR)/json_tag.h $(OBJDIR)/json_timeline_.c:$(OBJDIR)/json_timeline.h $(OBJDIR)/json_user_.c:$(OBJDIR)/json_user.h $(OBJDIR)/json_wiki_.c:$(OBJDIR)/json_wiki.h $(OBJDIR)/leaf_.c:$(OBJDIR)/leaf.h $(OBJDIR)/login_.c:$(OBJDIR)/login.h $(OBJDIR)/main_.c:$(OBJDIR)/main.h $(OBJDIR)/manifest_.c:$(OBJDIR)/manifest.h $(OBJDIR)/md5_.c:$(OBJDIR)/md5.h $(OBJDIR)/merge_.c:$(OBJDIR)/merge.h $(OBJDIR)/merge3_.c:$(OBJDIR)/merge3.h $(OBJDIR)/name_.c:$(OBJDIR)/name.h $(OBJDIR)/path_.c:$(OBJDIR)/path.h $(OBJDIR)/pivot_.c:$(OBJDIR)/pivot.h $(OBJDIR)/popen_.c:$(OBJDIR)/popen.h $(OBJDIR)/pqueue_.c:$(OBJDIR)/pqueue.h $(OBJDIR)/printf_.c:$(OBJDIR)/printf.h $(OBJDIR)/rebuild_.c:$(OBJDIR)/rebuild.h $(OBJDIR)/report_.c:$(OBJDIR)/report.h $(OBJDIR)/rss_.c:$(OBJDIR)/rss.h $(OBJDIR)/schema_.c:$(OBJDIR)/schema.h $(OBJDIR)/search_.c:$(OBJDIR)/search.h $(OBJDIR)/setup_.c:$(OBJDIR)/setup.h $(OBJDIR)/sha1_.c:$(OBJDIR)/sha1.h $(OBJDIR)/shun_.c:$(OBJDIR)/shun.h $(OBJDIR)/skins_.c:$(OBJDIR)/skins.h $(OBJDIR)/sqlcmd_.c:$(OBJDIR)/sqlcmd.h $(OBJDIR)/stash_.c:$(OBJDIR)/stash.h $(OBJDIR)/stat_.c:$(OBJDIR)/stat.h $(OBJDIR)/style_.c:$(OBJDIR)/style.h $(OBJDIR)/sync_.c:$(OBJDIR)/sync.h $(OBJDIR)/tag_.c:$(OBJDIR)/tag.h $(OBJDIR)/tar_.c:$(OBJDIR)/tar.h $(OBJDIR)/th_main_.c:$(OBJDIR)/th_main.h $(OBJDIR)/timeline_.c:$(OBJDIR)/timeline.h $(OBJDIR)/tkt_.c:$(OBJDIR)/tkt.h $(OBJDIR)/tktsetup_.c:$(OBJDIR)/tktsetup.h $(OBJDIR)/undo_.c:$(OBJDIR)/undo.h $(OBJDIR)/update_.c:$(OBJDIR)/update.h $(OBJDIR)/url_.c:$(OBJDIR)/url.h $(OBJDIR)/user_.c:$(OBJDIR)/user.h $(OBJDIR)/verify_.c:$(OBJDIR)/verify.h $(OBJDIR)/vfile_.c:$(OBJDIR)/vfile.h $(OBJDIR)/wiki_.c:$(OBJDIR)/wiki.h $(OBJDIR)/wikiformat_.c:$(OBJDIR)/wikiformat.h $(OBJDIR)/winhttp_.c:$(OBJDIR)/winhttp.h $(OBJDIR)/xfer_.c:$(OBJDIR)/xfer.h $(OBJDIR)/xfersetup_.c:$(OBJDIR)/xfersetup.h $(OBJDIR)/zip_.c:$(OBJDIR)/zip.h $(SRCDIR)/sqlite3.h $(SRCDIR)/th.h $(OBJDIR)/VERSION.h
          523  +	$(MAKEHEADERS)  $(OBJDIR)/add_.c:$(OBJDIR)/add.h $(OBJDIR)/allrepo_.c:$(OBJDIR)/allrepo.h $(OBJDIR)/attach_.c:$(OBJDIR)/attach.h $(OBJDIR)/bag_.c:$(OBJDIR)/bag.h $(OBJDIR)/bisect_.c:$(OBJDIR)/bisect.h $(OBJDIR)/blob_.c:$(OBJDIR)/blob.h $(OBJDIR)/branch_.c:$(OBJDIR)/branch.h $(OBJDIR)/browse_.c:$(OBJDIR)/browse.h $(OBJDIR)/captcha_.c:$(OBJDIR)/captcha.h $(OBJDIR)/cgi_.c:$(OBJDIR)/cgi.h $(OBJDIR)/checkin_.c:$(OBJDIR)/checkin.h $(OBJDIR)/checkout_.c:$(OBJDIR)/checkout.h $(OBJDIR)/clearsign_.c:$(OBJDIR)/clearsign.h $(OBJDIR)/clone_.c:$(OBJDIR)/clone.h $(OBJDIR)/comformat_.c:$(OBJDIR)/comformat.h $(OBJDIR)/configure_.c:$(OBJDIR)/configure.h $(OBJDIR)/content_.c:$(OBJDIR)/content.h $(OBJDIR)/db_.c:$(OBJDIR)/db.h $(OBJDIR)/delta_.c:$(OBJDIR)/delta.h $(OBJDIR)/deltacmd_.c:$(OBJDIR)/deltacmd.h $(OBJDIR)/descendants_.c:$(OBJDIR)/descendants.h $(OBJDIR)/diff_.c:$(OBJDIR)/diff.h $(OBJDIR)/diffcmd_.c:$(OBJDIR)/diffcmd.h $(OBJDIR)/doc_.c:$(OBJDIR)/doc.h $(OBJDIR)/encode_.c:$(OBJDIR)/encode.h $(OBJDIR)/event_.c:$(OBJDIR)/event.h $(OBJDIR)/export_.c:$(OBJDIR)/export.h $(OBJDIR)/file_.c:$(OBJDIR)/file.h $(OBJDIR)/finfo_.c:$(OBJDIR)/finfo.h $(OBJDIR)/glob_.c:$(OBJDIR)/glob.h $(OBJDIR)/graph_.c:$(OBJDIR)/graph.h $(OBJDIR)/gzip_.c:$(OBJDIR)/gzip.h $(OBJDIR)/http_.c:$(OBJDIR)/http.h $(OBJDIR)/http_socket_.c:$(OBJDIR)/http_socket.h $(OBJDIR)/http_ssl_.c:$(OBJDIR)/http_ssl.h $(OBJDIR)/http_transport_.c:$(OBJDIR)/http_transport.h $(OBJDIR)/import_.c:$(OBJDIR)/import.h $(OBJDIR)/info_.c:$(OBJDIR)/info.h $(OBJDIR)/json_.c:$(OBJDIR)/json.h $(OBJDIR)/json_artifact_.c:$(OBJDIR)/json_artifact.h $(OBJDIR)/json_branch_.c:$(OBJDIR)/json_branch.h $(OBJDIR)/json_diff_.c:$(OBJDIR)/json_diff.h $(OBJDIR)/json_login_.c:$(OBJDIR)/json_login.h $(OBJDIR)/json_query_.c:$(OBJDIR)/json_query.h $(OBJDIR)/json_report_.c:$(OBJDIR)/json_report.h $(OBJDIR)/json_tag_.c:$(OBJDIR)/json_tag.h $(OBJDIR)/json_timeline_.c:$(OBJDIR)/json_timeline.h $(OBJDIR)/json_user_.c:$(OBJDIR)/json_user.h $(OBJDIR)/json_wiki_.c:$(OBJDIR)/json_wiki.h $(OBJDIR)/leaf_.c:$(OBJDIR)/leaf.h $(OBJDIR)/login_.c:$(OBJDIR)/login.h $(OBJDIR)/main_.c:$(OBJDIR)/main.h $(OBJDIR)/manifest_.c:$(OBJDIR)/manifest.h $(OBJDIR)/md5_.c:$(OBJDIR)/md5.h $(OBJDIR)/merge_.c:$(OBJDIR)/merge.h $(OBJDIR)/merge3_.c:$(OBJDIR)/merge3.h $(OBJDIR)/name_.c:$(OBJDIR)/name.h $(OBJDIR)/path_.c:$(OBJDIR)/path.h $(OBJDIR)/pivot_.c:$(OBJDIR)/pivot.h $(OBJDIR)/popen_.c:$(OBJDIR)/popen.h $(OBJDIR)/pqueue_.c:$(OBJDIR)/pqueue.h $(OBJDIR)/printf_.c:$(OBJDIR)/printf.h $(OBJDIR)/rebuild_.c:$(OBJDIR)/rebuild.h $(OBJDIR)/report_.c:$(OBJDIR)/report.h $(OBJDIR)/rss_.c:$(OBJDIR)/rss.h $(OBJDIR)/schema_.c:$(OBJDIR)/schema.h $(OBJDIR)/search_.c:$(OBJDIR)/search.h $(OBJDIR)/setup_.c:$(OBJDIR)/setup.h $(OBJDIR)/sha1_.c:$(OBJDIR)/sha1.h $(OBJDIR)/shun_.c:$(OBJDIR)/shun.h $(OBJDIR)/skins_.c:$(OBJDIR)/skins.h $(OBJDIR)/sqlcmd_.c:$(OBJDIR)/sqlcmd.h $(OBJDIR)/stash_.c:$(OBJDIR)/stash.h $(OBJDIR)/stat_.c:$(OBJDIR)/stat.h $(OBJDIR)/style_.c:$(OBJDIR)/style.h $(OBJDIR)/sync_.c:$(OBJDIR)/sync.h $(OBJDIR)/tag_.c:$(OBJDIR)/tag.h $(OBJDIR)/tar_.c:$(OBJDIR)/tar.h $(OBJDIR)/th_main_.c:$(OBJDIR)/th_main.h $(OBJDIR)/timeline_.c:$(OBJDIR)/timeline.h $(OBJDIR)/tkt_.c:$(OBJDIR)/tkt.h $(OBJDIR)/tktsetup_.c:$(OBJDIR)/tktsetup.h $(OBJDIR)/undo_.c:$(OBJDIR)/undo.h $(OBJDIR)/update_.c:$(OBJDIR)/update.h $(OBJDIR)/url_.c:$(OBJDIR)/url.h $(OBJDIR)/user_.c:$(OBJDIR)/user.h $(OBJDIR)/verify_.c:$(OBJDIR)/verify.h $(OBJDIR)/vfile_.c:$(OBJDIR)/vfile.h $(OBJDIR)/wiki_.c:$(OBJDIR)/wiki.h $(OBJDIR)/wikiformat_.c:$(OBJDIR)/wikiformat.h $(OBJDIR)/winhttp_.c:$(OBJDIR)/winhttp.h $(OBJDIR)/xfer_.c:$(OBJDIR)/xfer.h $(OBJDIR)/xfersetup_.c:$(OBJDIR)/xfersetup.h $(OBJDIR)/zip_.c:$(OBJDIR)/zip.h $(SRCDIR)/sqlite3.h $(SRCDIR)/jim.h $(OBJDIR)/VERSION.h
   524    524   	echo Done >$(OBJDIR)/headers
   525    525   
   526    526   $(OBJDIR)/headers: Makefile
   527    527   Makefile:
   528    528   $(OBJDIR)/add_.c:	$(SRCDIR)/add.c $(OBJDIR)/translate
   529    529   	$(TRANSLATE) $(SRCDIR)/add.c >$(OBJDIR)/add_.c
   530    530   

Changes to win/Makefile.mingw.mistachkin.

   487    487   # the repository after running the tests.
   488    488   test:	$(OBJDIR) $(APPNAME)
   489    489   	$(TCLSH) $(SRCDIR)/../test/tester.tcl $(APPNAME)
   490    490   
   491    491   $(OBJDIR)/VERSION.h:	$(SRCDIR)/../manifest.uuid $(SRCDIR)/../manifest $(VERSION)
   492    492   	$(VERSION) $(SRCDIR)/../manifest.uuid $(SRCDIR)/../manifest $(SRCDIR)/../VERSION >$(OBJDIR)/VERSION.h
   493    493   
   494         -EXTRAOBJ =  $(OBJDIR)/sqlite3.o  $(OBJDIR)/shell.o  $(OBJDIR)/th.o  $(OBJDIR)/th_lang.o  $(OBJDIR)/cson_amalgamation.o
          494  +EXTRAOBJ =  $(OBJDIR)/sqlite3.o  $(OBJDIR)/shell.o  $(OBJDIR)/jimtcl.o  $(OBJDIR)/cson_amalgamation.o
   495    495   
   496    496   ifdef FOSSIL_ENABLE_TCL
   497    497   EXTRAOBJ +=  $(OBJDIR)/th_tcl.o
   498    498   endif
   499    499   
   500    500   $(APPNAME):	$(OBJDIR)/headers $(OBJ) $(EXTRAOBJ) $(OBJDIR)/icon.o
   501    501   	$(TCC) -o $(APPNAME) $(OBJ) $(EXTRAOBJ) $(LIB) $(OBJDIR)/icon.o
................................................................................
   516    516   setup: $(OBJDIR) $(APPNAME)
   517    517   	$(MAKENSIS) ./fossil.nsi
   518    518   
   519    519   
   520    520   $(OBJDIR)/page_index.h: $(TRANS_SRC) $(OBJDIR)/mkindex
   521    521   	$(MKINDEX) $(TRANS_SRC) >$@
   522    522   $(OBJDIR)/headers:	$(OBJDIR)/page_index.h $(OBJDIR)/makeheaders $(OBJDIR)/VERSION.h
   523         -	$(MAKEHEADERS)  $(OBJDIR)/add_.c:$(OBJDIR)/add.h $(OBJDIR)/allrepo_.c:$(OBJDIR)/allrepo.h $(OBJDIR)/attach_.c:$(OBJDIR)/attach.h $(OBJDIR)/bag_.c:$(OBJDIR)/bag.h $(OBJDIR)/bisect_.c:$(OBJDIR)/bisect.h $(OBJDIR)/blob_.c:$(OBJDIR)/blob.h $(OBJDIR)/branch_.c:$(OBJDIR)/branch.h $(OBJDIR)/browse_.c:$(OBJDIR)/browse.h $(OBJDIR)/captcha_.c:$(OBJDIR)/captcha.h $(OBJDIR)/cgi_.c:$(OBJDIR)/cgi.h $(OBJDIR)/checkin_.c:$(OBJDIR)/checkin.h $(OBJDIR)/checkout_.c:$(OBJDIR)/checkout.h $(OBJDIR)/clearsign_.c:$(OBJDIR)/clearsign.h $(OBJDIR)/clone_.c:$(OBJDIR)/clone.h $(OBJDIR)/comformat_.c:$(OBJDIR)/comformat.h $(OBJDIR)/configure_.c:$(OBJDIR)/configure.h $(OBJDIR)/content_.c:$(OBJDIR)/content.h $(OBJDIR)/db_.c:$(OBJDIR)/db.h $(OBJDIR)/delta_.c:$(OBJDIR)/delta.h $(OBJDIR)/deltacmd_.c:$(OBJDIR)/deltacmd.h $(OBJDIR)/descendants_.c:$(OBJDIR)/descendants.h $(OBJDIR)/diff_.c:$(OBJDIR)/diff.h $(OBJDIR)/diffcmd_.c:$(OBJDIR)/diffcmd.h $(OBJDIR)/doc_.c:$(OBJDIR)/doc.h $(OBJDIR)/encode_.c:$(OBJDIR)/encode.h $(OBJDIR)/event_.c:$(OBJDIR)/event.h $(OBJDIR)/export_.c:$(OBJDIR)/export.h $(OBJDIR)/file_.c:$(OBJDIR)/file.h $(OBJDIR)/finfo_.c:$(OBJDIR)/finfo.h $(OBJDIR)/glob_.c:$(OBJDIR)/glob.h $(OBJDIR)/graph_.c:$(OBJDIR)/graph.h $(OBJDIR)/gzip_.c:$(OBJDIR)/gzip.h $(OBJDIR)/http_.c:$(OBJDIR)/http.h $(OBJDIR)/http_socket_.c:$(OBJDIR)/http_socket.h $(OBJDIR)/http_ssl_.c:$(OBJDIR)/http_ssl.h $(OBJDIR)/http_transport_.c:$(OBJDIR)/http_transport.h $(OBJDIR)/import_.c:$(OBJDIR)/import.h $(OBJDIR)/info_.c:$(OBJDIR)/info.h $(OBJDIR)/json_.c:$(OBJDIR)/json.h $(OBJDIR)/json_artifact_.c:$(OBJDIR)/json_artifact.h $(OBJDIR)/json_branch_.c:$(OBJDIR)/json_branch.h $(OBJDIR)/json_diff_.c:$(OBJDIR)/json_diff.h $(OBJDIR)/json_login_.c:$(OBJDIR)/json_login.h $(OBJDIR)/json_query_.c:$(OBJDIR)/json_query.h $(OBJDIR)/json_report_.c:$(OBJDIR)/json_report.h $(OBJDIR)/json_tag_.c:$(OBJDIR)/json_tag.h $(OBJDIR)/json_timeline_.c:$(OBJDIR)/json_timeline.h $(OBJDIR)/json_user_.c:$(OBJDIR)/json_user.h $(OBJDIR)/json_wiki_.c:$(OBJDIR)/json_wiki.h $(OBJDIR)/leaf_.c:$(OBJDIR)/leaf.h $(OBJDIR)/login_.c:$(OBJDIR)/login.h $(OBJDIR)/main_.c:$(OBJDIR)/main.h $(OBJDIR)/manifest_.c:$(OBJDIR)/manifest.h $(OBJDIR)/md5_.c:$(OBJDIR)/md5.h $(OBJDIR)/merge_.c:$(OBJDIR)/merge.h $(OBJDIR)/merge3_.c:$(OBJDIR)/merge3.h $(OBJDIR)/name_.c:$(OBJDIR)/name.h $(OBJDIR)/path_.c:$(OBJDIR)/path.h $(OBJDIR)/pivot_.c:$(OBJDIR)/pivot.h $(OBJDIR)/popen_.c:$(OBJDIR)/popen.h $(OBJDIR)/pqueue_.c:$(OBJDIR)/pqueue.h $(OBJDIR)/printf_.c:$(OBJDIR)/printf.h $(OBJDIR)/rebuild_.c:$(OBJDIR)/rebuild.h $(OBJDIR)/report_.c:$(OBJDIR)/report.h $(OBJDIR)/rss_.c:$(OBJDIR)/rss.h $(OBJDIR)/schema_.c:$(OBJDIR)/schema.h $(OBJDIR)/search_.c:$(OBJDIR)/search.h $(OBJDIR)/setup_.c:$(OBJDIR)/setup.h $(OBJDIR)/sha1_.c:$(OBJDIR)/sha1.h $(OBJDIR)/shun_.c:$(OBJDIR)/shun.h $(OBJDIR)/skins_.c:$(OBJDIR)/skins.h $(OBJDIR)/sqlcmd_.c:$(OBJDIR)/sqlcmd.h $(OBJDIR)/stash_.c:$(OBJDIR)/stash.h $(OBJDIR)/stat_.c:$(OBJDIR)/stat.h $(OBJDIR)/style_.c:$(OBJDIR)/style.h $(OBJDIR)/sync_.c:$(OBJDIR)/sync.h $(OBJDIR)/tag_.c:$(OBJDIR)/tag.h $(OBJDIR)/tar_.c:$(OBJDIR)/tar.h $(OBJDIR)/th_main_.c:$(OBJDIR)/th_main.h $(OBJDIR)/timeline_.c:$(OBJDIR)/timeline.h $(OBJDIR)/tkt_.c:$(OBJDIR)/tkt.h $(OBJDIR)/tktsetup_.c:$(OBJDIR)/tktsetup.h $(OBJDIR)/undo_.c:$(OBJDIR)/undo.h $(OBJDIR)/update_.c:$(OBJDIR)/update.h $(OBJDIR)/url_.c:$(OBJDIR)/url.h $(OBJDIR)/user_.c:$(OBJDIR)/user.h $(OBJDIR)/verify_.c:$(OBJDIR)/verify.h $(OBJDIR)/vfile_.c:$(OBJDIR)/vfile.h $(OBJDIR)/wiki_.c:$(OBJDIR)/wiki.h $(OBJDIR)/wikiformat_.c:$(OBJDIR)/wikiformat.h $(OBJDIR)/winhttp_.c:$(OBJDIR)/winhttp.h $(OBJDIR)/xfer_.c:$(OBJDIR)/xfer.h $(OBJDIR)/xfersetup_.c:$(OBJDIR)/xfersetup.h $(OBJDIR)/zip_.c:$(OBJDIR)/zip.h $(SRCDIR)/sqlite3.h $(SRCDIR)/th.h $(OBJDIR)/VERSION.h
          523  +	$(MAKEHEADERS)  $(OBJDIR)/add_.c:$(OBJDIR)/add.h $(OBJDIR)/allrepo_.c:$(OBJDIR)/allrepo.h $(OBJDIR)/attach_.c:$(OBJDIR)/attach.h $(OBJDIR)/bag_.c:$(OBJDIR)/bag.h $(OBJDIR)/bisect_.c:$(OBJDIR)/bisect.h $(OBJDIR)/blob_.c:$(OBJDIR)/blob.h $(OBJDIR)/branch_.c:$(OBJDIR)/branch.h $(OBJDIR)/browse_.c:$(OBJDIR)/browse.h $(OBJDIR)/captcha_.c:$(OBJDIR)/captcha.h $(OBJDIR)/cgi_.c:$(OBJDIR)/cgi.h $(OBJDIR)/checkin_.c:$(OBJDIR)/checkin.h $(OBJDIR)/checkout_.c:$(OBJDIR)/checkout.h $(OBJDIR)/clearsign_.c:$(OBJDIR)/clearsign.h $(OBJDIR)/clone_.c:$(OBJDIR)/clone.h $(OBJDIR)/comformat_.c:$(OBJDIR)/comformat.h $(OBJDIR)/configure_.c:$(OBJDIR)/configure.h $(OBJDIR)/content_.c:$(OBJDIR)/content.h $(OBJDIR)/db_.c:$(OBJDIR)/db.h $(OBJDIR)/delta_.c:$(OBJDIR)/delta.h $(OBJDIR)/deltacmd_.c:$(OBJDIR)/deltacmd.h $(OBJDIR)/descendants_.c:$(OBJDIR)/descendants.h $(OBJDIR)/diff_.c:$(OBJDIR)/diff.h $(OBJDIR)/diffcmd_.c:$(OBJDIR)/diffcmd.h $(OBJDIR)/doc_.c:$(OBJDIR)/doc.h $(OBJDIR)/encode_.c:$(OBJDIR)/encode.h $(OBJDIR)/event_.c:$(OBJDIR)/event.h $(OBJDIR)/export_.c:$(OBJDIR)/export.h $(OBJDIR)/file_.c:$(OBJDIR)/file.h $(OBJDIR)/finfo_.c:$(OBJDIR)/finfo.h $(OBJDIR)/glob_.c:$(OBJDIR)/glob.h $(OBJDIR)/graph_.c:$(OBJDIR)/graph.h $(OBJDIR)/gzip_.c:$(OBJDIR)/gzip.h $(OBJDIR)/http_.c:$(OBJDIR)/http.h $(OBJDIR)/http_socket_.c:$(OBJDIR)/http_socket.h $(OBJDIR)/http_ssl_.c:$(OBJDIR)/http_ssl.h $(OBJDIR)/http_transport_.c:$(OBJDIR)/http_transport.h $(OBJDIR)/import_.c:$(OBJDIR)/import.h $(OBJDIR)/info_.c:$(OBJDIR)/info.h $(OBJDIR)/json_.c:$(OBJDIR)/json.h $(OBJDIR)/json_artifact_.c:$(OBJDIR)/json_artifact.h $(OBJDIR)/json_branch_.c:$(OBJDIR)/json_branch.h $(OBJDIR)/json_diff_.c:$(OBJDIR)/json_diff.h $(OBJDIR)/json_login_.c:$(OBJDIR)/json_login.h $(OBJDIR)/json_query_.c:$(OBJDIR)/json_query.h $(OBJDIR)/json_report_.c:$(OBJDIR)/json_report.h $(OBJDIR)/json_tag_.c:$(OBJDIR)/json_tag.h $(OBJDIR)/json_timeline_.c:$(OBJDIR)/json_timeline.h $(OBJDIR)/json_user_.c:$(OBJDIR)/json_user.h $(OBJDIR)/json_wiki_.c:$(OBJDIR)/json_wiki.h $(OBJDIR)/leaf_.c:$(OBJDIR)/leaf.h $(OBJDIR)/login_.c:$(OBJDIR)/login.h $(OBJDIR)/main_.c:$(OBJDIR)/main.h $(OBJDIR)/manifest_.c:$(OBJDIR)/manifest.h $(OBJDIR)/md5_.c:$(OBJDIR)/md5.h $(OBJDIR)/merge_.c:$(OBJDIR)/merge.h $(OBJDIR)/merge3_.c:$(OBJDIR)/merge3.h $(OBJDIR)/name_.c:$(OBJDIR)/name.h $(OBJDIR)/path_.c:$(OBJDIR)/path.h $(OBJDIR)/pivot_.c:$(OBJDIR)/pivot.h $(OBJDIR)/popen_.c:$(OBJDIR)/popen.h $(OBJDIR)/pqueue_.c:$(OBJDIR)/pqueue.h $(OBJDIR)/printf_.c:$(OBJDIR)/printf.h $(OBJDIR)/rebuild_.c:$(OBJDIR)/rebuild.h $(OBJDIR)/report_.c:$(OBJDIR)/report.h $(OBJDIR)/rss_.c:$(OBJDIR)/rss.h $(OBJDIR)/schema_.c:$(OBJDIR)/schema.h $(OBJDIR)/search_.c:$(OBJDIR)/search.h $(OBJDIR)/setup_.c:$(OBJDIR)/setup.h $(OBJDIR)/sha1_.c:$(OBJDIR)/sha1.h $(OBJDIR)/shun_.c:$(OBJDIR)/shun.h $(OBJDIR)/skins_.c:$(OBJDIR)/skins.h $(OBJDIR)/sqlcmd_.c:$(OBJDIR)/sqlcmd.h $(OBJDIR)/stash_.c:$(OBJDIR)/stash.h $(OBJDIR)/stat_.c:$(OBJDIR)/stat.h $(OBJDIR)/style_.c:$(OBJDIR)/style.h $(OBJDIR)/sync_.c:$(OBJDIR)/sync.h $(OBJDIR)/tag_.c:$(OBJDIR)/tag.h $(OBJDIR)/tar_.c:$(OBJDIR)/tar.h $(OBJDIR)/th_main_.c:$(OBJDIR)/th_main.h $(OBJDIR)/timeline_.c:$(OBJDIR)/timeline.h $(OBJDIR)/tkt_.c:$(OBJDIR)/tkt.h $(OBJDIR)/tktsetup_.c:$(OBJDIR)/tktsetup.h $(OBJDIR)/undo_.c:$(OBJDIR)/undo.h $(OBJDIR)/update_.c:$(OBJDIR)/update.h $(OBJDIR)/url_.c:$(OBJDIR)/url.h $(OBJDIR)/user_.c:$(OBJDIR)/user.h $(OBJDIR)/verify_.c:$(OBJDIR)/verify.h $(OBJDIR)/vfile_.c:$(OBJDIR)/vfile.h $(OBJDIR)/wiki_.c:$(OBJDIR)/wiki.h $(OBJDIR)/wikiformat_.c:$(OBJDIR)/wikiformat.h $(OBJDIR)/winhttp_.c:$(OBJDIR)/winhttp.h $(OBJDIR)/xfer_.c:$(OBJDIR)/xfer.h $(OBJDIR)/xfersetup_.c:$(OBJDIR)/xfersetup.h $(OBJDIR)/zip_.c:$(OBJDIR)/zip.h $(SRCDIR)/sqlite3.h $(SRCDIR)/jim.h $(OBJDIR)/VERSION.h
   524    524   	echo Done >$(OBJDIR)/headers
   525    525   
   526    526   $(OBJDIR)/headers: Makefile
   527    527   Makefile:
   528    528   $(OBJDIR)/add_.c:	$(SRCDIR)/add.c $(OBJDIR)/translate
   529    529   	$(TRANSLATE) $(SRCDIR)/add.c >$(OBJDIR)/add_.c
   530    530   
................................................................................
  1190   1190   	$(XTCC)  -c $(SRCDIR)/cson_amalgamation.c -o $(OBJDIR)/cson_amalgamation.o -DCSON_FOSSIL_MODE
  1191   1191   
  1192   1192   $(OBJDIR)/json.o $(OBJDIR)/json_artifact.o $(OBJDIR)/json_branch.o $(OBJDIR)/json_diff.o $(OBJDIR)/json_login.o $(OBJDIR)/json_query.o $(OBJDIR)/json_report.o $(OBJDIR)/json_tag.o $(OBJDIR)/json_timeline.o $(OBJDIR)/json_user.o $(OBJDIR)/json_wiki.o : $(SRCDIR)/json_detail.h
  1193   1193   
  1194   1194   $(OBJDIR)/shell.o:	$(SRCDIR)/shell.c $(SRCDIR)/sqlite3.h
  1195   1195   	$(XTCC) -Dmain=sqlite3_shell -DSQLITE_OMIT_LOAD_EXTENSION=1 -c $(SRCDIR)/shell.c -o $(OBJDIR)/shell.o
  1196   1196   
  1197         -$(OBJDIR)/th.o:	$(SRCDIR)/th.c
  1198         -	$(XTCC) -I$(SRCDIR) -c $(SRCDIR)/th.c -o $(OBJDIR)/th.o
  1199         -
  1200         -$(OBJDIR)/th_lang.o:	$(SRCDIR)/th_lang.c
  1201         -	$(XTCC) -I$(SRCDIR) -c $(SRCDIR)/th_lang.c -o $(OBJDIR)/th_lang.o
         1197  +$(OBJDIR)/jimtcl.o:	$(SRCDIR)/../autosetup/jimsh0.c
         1198  +	$(XTCC) -I$(SRCDIR) -DJIM_BOOTSTRAP_LIB_ONLY -c $(SRCDIR)/../autosetup/jimsh0.c -o $(OBJDIR)/jimtcl.o
  1202   1199   
  1203   1200   ifdef FOSSIL_ENABLE_TCL
  1204   1201   $(OBJDIR)/th_tcl.o:	$(SRCDIR)/th_tcl.c
  1205   1202   	$(XTCC) -I$(SRCDIR) -c $(SRCDIR)/th_tcl.c -o $(OBJDIR)/th_tcl.o
  1206   1203   endif
  1207   1204   

Changes to win/Makefile.msc.

   776    776   $(OX)\zip$O : zip_.c zip.h
   777    777   	$(TCC) /Fo$@ -c zip_.c
   778    778   
   779    779   zip_.c : $(SRCDIR)\zip.c
   780    780   	translate$E $** > $@
   781    781   
   782    782   headers: makeheaders$E page_index.h VERSION.h
   783         -	makeheaders$E add_.c:add.h allrepo_.c:allrepo.h attach_.c:attach.h bag_.c:bag.h bisect_.c:bisect.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h captcha_.c:captcha.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h configure_.c:configure.h content_.c:content.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h descendants_.c:descendants.h diff_.c:diff.h diffcmd_.c:diffcmd.h doc_.c:doc.h encode_.c:encode.h event_.c:event.h export_.c:export.h file_.c:file.h finfo_.c:finfo.h glob_.c:glob.h graph_.c:graph.h gzip_.c:gzip.h http_.c:http.h http_socket_.c:http_socket.h http_ssl_.c:http_ssl.h http_transport_.c:http_transport.h import_.c:import.h info_.c:info.h json_.c:json.h json_artifact_.c:json_artifact.h json_branch_.c:json_branch.h json_diff_.c:json_diff.h json_login_.c:json_login.h json_query_.c:json_query.h json_report_.c:json_report.h json_tag_.c:json_tag.h json_timeline_.c:json_timeline.h json_user_.c:json_user.h json_wiki_.c:json_wiki.h leaf_.c:leaf.h login_.c:login.h main_.c:main.h manifest_.c:manifest.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h name_.c:name.h path_.c:path.h pivot_.c:pivot.h popen_.c:popen.h pqueue_.c:pqueue.h printf_.c:printf.h rebuild_.c:rebuild.h report_.c:report.h rss_.c:rss.h schema_.c:schema.h search_.c:search.h setup_.c:setup.h sha1_.c:sha1.h shun_.c:shun.h skins_.c:skins.h sqlcmd_.c:sqlcmd.h stash_.c:stash.h stat_.c:stat.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h tar_.c:tar.h th_main_.c:th_main.h timeline_.c:timeline.h tkt_.c:tkt.h tktsetup_.c:tktsetup.h undo_.c:undo.h update_.c:update.h url_.c:url.h user_.c:user.h verify_.c:verify.h vfile_.c:vfile.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h winhttp_.c:winhttp.h xfer_.c:xfer.h xfersetup_.c:xfersetup.h zip_.c:zip.h $(SRCDIR)\sqlite3.h $(SRCDIR)\th.h VERSION.h $(SRCDIR)\cson_amalgamation.h
          783  +	makeheaders$E add_.c:add.h allrepo_.c:allrepo.h attach_.c:attach.h bag_.c:bag.h bisect_.c:bisect.h blob_.c:blob.h branch_.c:branch.h browse_.c:browse.h captcha_.c:captcha.h cgi_.c:cgi.h checkin_.c:checkin.h checkout_.c:checkout.h clearsign_.c:clearsign.h clone_.c:clone.h comformat_.c:comformat.h configure_.c:configure.h content_.c:content.h db_.c:db.h delta_.c:delta.h deltacmd_.c:deltacmd.h descendants_.c:descendants.h diff_.c:diff.h diffcmd_.c:diffcmd.h doc_.c:doc.h encode_.c:encode.h event_.c:event.h export_.c:export.h file_.c:file.h finfo_.c:finfo.h glob_.c:glob.h graph_.c:graph.h gzip_.c:gzip.h http_.c:http.h http_socket_.c:http_socket.h http_ssl_.c:http_ssl.h http_transport_.c:http_transport.h import_.c:import.h info_.c:info.h json_.c:json.h json_artifact_.c:json_artifact.h json_branch_.c:json_branch.h json_diff_.c:json_diff.h json_login_.c:json_login.h json_query_.c:json_query.h json_report_.c:json_report.h json_tag_.c:json_tag.h json_timeline_.c:json_timeline.h json_user_.c:json_user.h json_wiki_.c:json_wiki.h leaf_.c:leaf.h login_.c:login.h main_.c:main.h manifest_.c:manifest.h md5_.c:md5.h merge_.c:merge.h merge3_.c:merge3.h name_.c:name.h path_.c:path.h pivot_.c:pivot.h popen_.c:popen.h pqueue_.c:pqueue.h printf_.c:printf.h rebuild_.c:rebuild.h report_.c:report.h rss_.c:rss.h schema_.c:schema.h search_.c:search.h setup_.c:setup.h sha1_.c:sha1.h shun_.c:shun.h skins_.c:skins.h sqlcmd_.c:sqlcmd.h stash_.c:stash.h stat_.c:stat.h style_.c:style.h sync_.c:sync.h tag_.c:tag.h tar_.c:tar.h th_main_.c:th_main.h timeline_.c:timeline.h tkt_.c:tkt.h tktsetup_.c:tktsetup.h undo_.c:undo.h update_.c:update.h url_.c:url.h user_.c:user.h verify_.c:verify.h vfile_.c:vfile.h wiki_.c:wiki.h wikiformat_.c:wikiformat.h winhttp_.c:winhttp.h xfer_.c:xfer.h xfersetup_.c:xfersetup.h zip_.c:zip.h $(SRCDIR)\sqlite3.h $(SRCDIR)\jim.h VERSION.h $(SRCDIR)\cson_amalgamation.h
   784    784   	@copy /Y nul: headers