Index: auto.def
==================================================================
--- auto.def
+++ auto.def
@@ -87,34 +87,34 @@
     user-error "zlib not found please install it or specify the location with --with-zlib"
 }
 
 set tclpath [opt-val with-tcl]
 if {$tclpath ne ""} {
-	# Note parse-tclconfig-sh is in autosetup/local.tcl
+    # Note parse-tclconfig-sh is in autosetup/local.tcl
     if {$tclpath eq "1"} {
         # Use the system Tcl. Look in some likely places.
         array set tclconfig [parse-tclconfig-sh /usr /usr/local /usr/share /opt/local]
-		set msg "on your system"
-	} else {
+        set msg "on your system"
+    } else {
         array set tclconfig [parse-tclconfig-sh $tclpath]
-		set msg "at $tclpath"
-	}
-	if {![info exists tclconfig(TCL_INCLUDE_SPEC)]} {
-		user-error "Cannot find Tcl $msg"
-	}
-	set cflags $tclconfig(TCL_INCLUDE_SPEC)
-	set libs "$tclconfig(TCL_LIB_SPEC) $tclconfig(TCL_LIBS)"
-	cc-with [list -cflags $cflags -libs $libs] {
-		if {![cc-check-functions Tcl_CreateInterp]} {
-			user-error "Cannot find a usable Tcl $msg"
-		}
-	}
-	set version $tclconfig(TCL_VERSION)$tclconfig(TCL_PATCH_LEVEL)
-	msg-result "Found Tcl $version at $tclconfig(TCL_PREFIX)"
-	define-append LIBS $libs
-	define-append EXTRA_CFLAGS $cflags
-	define-append EXTRA_LDFLAGS $tclconfig(TCL_LD_FLAGS)
+        set msg "at $tclpath"
+    }
+    if {![info exists tclconfig(TCL_INCLUDE_SPEC)]} {
+        user-error "Cannot find Tcl $msg"
+    }
+    set cflags $tclconfig(TCL_INCLUDE_SPEC)
+    set libs "$tclconfig(TCL_LIB_SPEC) $tclconfig(TCL_LIBS)"
+    cc-with [list -cflags $cflags -libs $libs] {
+        if {![cc-check-functions Tcl_CreateInterp]} {
+            user-error "Cannot find a usable Tcl $msg"
+        }
+    }
+    set version $tclconfig(TCL_VERSION)$tclconfig(TCL_PATCH_LEVEL)
+    msg-result "Found Tcl $version at $tclconfig(TCL_PREFIX)"
+    define-append LIBS $libs
+    define-append EXTRA_CFLAGS $cflags
+    define-append EXTRA_LDFLAGS $tclconfig(TCL_LD_FLAGS)
 
     define FOSSIL_ENABLE_TCL
 }
 
 # Helper for openssl checking

Index: autosetup/README.autosetup
==================================================================
--- autosetup/README.autosetup
+++ autosetup/README.autosetup
@@ -1,1 +1,1 @@
-This is autosetup v0.6.2. See http://msteveb.github.com/autosetup/
+This is autosetup v0.6.3. See http://msteveb.github.com/autosetup/

Index: autosetup/autosetup
==================================================================
--- autosetup/autosetup
+++ autosetup/autosetup
@@ -3,11 +3,11 @@
 # All rights reserved
 # vim:se syntax=tcl:
 # \
 dir=`dirname "$0"`; exec "`$dir/find-tclsh`" "$0" "$@"
 
-set autosetup(version) 0.6.2
+set autosetup(version) 0.6.3
 
 # Can be set to 1 to debug early-init problems
 set autosetup(debug) 0
 
 ##################################################################
@@ -516,16 +516,20 @@
 }
 
 # @env-is-set name
 #
 # Returns 1 if the $name was specified on the command line or in the environment.
+# Note that an empty environment variable is not considered to be set.
 #
 proc env-is-set {name} {
 	if {[dict exists $::autosetup(cmdline) $name]} {
 		return 1
 	}
-	info exists ::env($name)
+	if {[getenv $name ""] ne ""} {
+		return 1
+	}
+	return 0
 }
 
 # @readfile filename ?default=""?
 #
 # Return the contents of the file, without the trailing newline.
@@ -1541,19 +1545,10 @@
 	# On Windows, backslash convert all environment variables
 	# (Assume that Tcl does this for us)
 	proc getenv {name args} {
 		string map {\\ /} [env $name {*}$args]
 	}
-	# Jim uses system() for exec under mingw, so
-	# we need to fetch the output ourselves
-	proc exec-with-stderr {args} {
-			set tmpfile auto[format %04x [rand 10000]].tmp
-			set rc [catch [list exec {*}$args >$tmpfile 2>&1] result]
-			set result [readfile $tmpfile]
-			file delete $tmpfile
-			return -code $rc $result
-	}
 } else {
 	# Jim on unix is simple
 	alias getenv env
 }
 

Index: autosetup/cc-shared.tcl
==================================================================
--- autosetup/cc-shared.tcl
+++ autosetup/cc-shared.tcl
@@ -56,8 +56,8 @@
 		# Generic Unix settings
 		define SH_LINKFLAGS -rdynamic
 		define SH_CFLAGS -fpic
 		define SH_LDFLAGS -shared
 		define SHOBJ_CFLAGS -fpic
-		define SHOBJ_LDFLAGS "-shared -nostartfiles"
+		define SHOBJ_LDFLAGS -shared
 	}
 }

Index: autosetup/cc.tcl
==================================================================
--- autosetup/cc.tcl
+++ autosetup/cc.tcl
@@ -372,11 +372,11 @@
 	} else {
 		set save [cc-add-settings $settings]
 		set rc [catch {uplevel 1 [lindex $args 0]} result info]
 		cc-store-settings $save
 		if {$rc != 0} {
-			return $result -code [dict get $info -code]
+			return -code [dict get $info -code] $result
 		}
 		return $result
 	}
 }
 

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

Index: autosetup/jimsh0.c
==================================================================
--- autosetup/jimsh0.c
+++ autosetup/jimsh0.c
@@ -16,193 +16,122 @@
 #define jim_ext_exec
 #define jim_ext_clock
 #define jim_ext_array
 #define jim_ext_stdlib
 #define jim_ext_tclcompat
-#if defined(__MINGW32__)
+#if defined(_MSC_VER)
+#define TCL_PLATFORM_OS "windows"
+#define TCL_PLATFORM_PLATFORM "windows"
+#define TCL_PLATFORM_PATH_SEPARATOR ";"
+#define HAVE_MKDIR_ONE_ARG
+#define HAVE_SYSTEM
+#elif defined(__MINGW32__)
 #define TCL_PLATFORM_OS "mingw"
 #define TCL_PLATFORM_PLATFORM "windows"
 #define TCL_PLATFORM_PATH_SEPARATOR ";"
 #define HAVE_MKDIR_ONE_ARG
 #define HAVE_SYSTEM
+#define HAVE_SYS_TIME_H
+#define HAVE_DIRENT_H
+#define HAVE_UNISTD_H
 #else
 #define TCL_PLATFORM_OS "unknown"
 #define TCL_PLATFORM_PLATFORM "unix"
 #define TCL_PLATFORM_PATH_SEPARATOR ":"
 #define HAVE_VFORK
 #define HAVE_WAITPID
+#define HAVE_SYS_TIME_H
+#define HAVE_DIRENT_H
+#define HAVE_UNISTD_H
+#endif
+#ifndef JIM_WIN32COMPAT_H
+#define JIM_WIN32COMPAT_H
+
+
+
+
+#if defined(_WIN32) || defined(WIN32)
+
+#define HAVE_DLOPEN
+void *dlopen(const char *path, int mode);
+int dlclose(void *handle);
+void *dlsym(void *handle, const char *symbol);
+char *dlerror(void);
+
+#ifdef _MSC_VER
+
+
+#if _MSC_VER >= 1000
+	#pragma warning(disable:4146)
+#endif
+
+#include <limits.h>
+#define jim_wide _int64
+#ifndef LLONG_MAX
+	#define LLONG_MAX    9223372036854775807I64
+#endif
+#ifndef LLONG_MIN
+	#define LLONG_MIN    (-LLONG_MAX - 1I64)
+#endif
+#define JIM_WIDE_MIN LLONG_MIN
+#define JIM_WIDE_MAX LLONG_MAX
+#define JIM_WIDE_MODIFIER "I64d"
+#define strcasecmp _stricmp
+#define strtoull _strtoui64
+#define snprintf _snprintf
+
+#include <io.h>
+
+struct timeval {
+	long tv_sec;
+	long tv_usec;
+};
+
+int gettimeofday(struct timeval *tv, void *unused);
+
+#define HAVE_OPENDIR
+struct dirent {
+	char *d_name;
+};
+
+typedef struct DIR {
+	long                handle; 
+	struct _finddata_t  info;
+	struct dirent       result; 
+	char                *name;  
+} DIR;
+
+DIR *opendir(const char *name);
+int closedir(DIR *dir);
+struct dirent *readdir(DIR *dir);
+#endif 
+
+#endif 
+
 #endif
 #ifndef UTF8_UTIL_H
 #define UTF8_UTIL_H
-/**
- * UTF-8 utility functions
- *
- * (c) 2010 Steve Bennett <steveb@workware.net.au>
- *
- * See LICENCE for licence details.
- */
 
-/**
- * Converts the given unicode codepoint (0 - 0xffff) to utf-8
- * and stores the result at 'p'.
- * 
- * Returns the number of utf-8 characters (1-3).
- */
 int utf8_fromunicode(char *p, unsigned short uc);
 
 #ifndef JIM_UTF8
 #include <ctype.h>
 
-/* No utf-8 support. 1 byte = 1 char */
-#define utf8_strlen(S, B) (B) < 0 ? strlen(S) : (B)
-#define utf8_tounicode(S, CP) (*(CP) = *(S), 1)
+
+#define utf8_strlen(S, B) ((B) < 0 ? strlen(S) : (B))
+#define utf8_tounicode(S, CP) (*(CP) = (unsigned char)*(S), 1)
 #define utf8_upper(C) toupper(C)
 #define utf8_lower(C) tolower(C)
 #define utf8_index(C, I) (I)
 #define utf8_charlen(C) 1
 #define utf8_prev_len(S, L) 1
 
 #else
-/**
- * Returns the length of the utf-8 sequence starting with 'c'.
- * 
- * Returns 1-4, or -1 if this is not a valid start byte.
- *
- * Note that charlen=4 is not supported by the rest of the API.
- */
-int utf8_charlen(int c);
-
-/**
- * Returns the number of characters in the utf-8 
- * string of the given byte length.
- *
- * Any bytes which are not part of an valid utf-8
- * sequence are treated as individual characters.
- *
- * The string *must* be null terminated.
- *
- * Does not support unicode code points > \uffff
- */
-int utf8_strlen(const char *str, int bytelen);
-
-/**
- * Returns the byte index of the given character in the utf-8 string.
- * 
- * The string *must* be null terminated.
- *
- * This will return the byte length of a utf-8 string
- * if given the char length.
- */
-int utf8_index(const char *str, int charindex);
-
-/**
- * Returns the unicode codepoint corresponding to the
- * utf-8 sequence 'str'.
- * 
- * Stores the result in *uc and returns the number of bytes
- * consumed.
- *
- * If 'str' is null terminated, then an invalid utf-8 sequence
- * at the end of the string will be returned as individual bytes.
- *
- * If it is not null terminated, the length *must* be checked first.
- *
- * Does not support unicode code points > \uffff
- */
-int utf8_tounicode(const char *str, int *uc);
-
-/**
- * Returns the number of bytes before 'str' that the previous
- * utf-8 character sequence starts (which may be the middle of a sequence).
- *
- * Looks back at most 'len' bytes backwards, which must be > 0.
- * If no start char is found, returns -len
- */
-int utf8_prev_len(const char *str, int len);
-
-/**
- * Returns the upper-case variant of the given unicode codepoint.
- *
- * Does not support unicode code points > \uffff
- */
-int utf8_upper(int uc);
-
-/**
- * Returns the lower-case variant of the given unicode codepoint.
- *
- * NOTE: Use utf8_upper() in preference for case-insensitive matching.
- *
- * Does not support unicode code points > \uffff
- */
-int utf8_lower(int uc);
-
-#endif
-
-#endif
-/* Jim - A small embeddable Tcl interpreter
- *
- * Copyright 2005 Salvatore Sanfilippo <antirez@invece.org>
- * Copyright 2005 Clemens Hintze <c.hintze@gmx.net>
- * Copyright 2005 patthoyts - Pat Thoyts <patthoyts@users.sf.net> 
- * Copyright 2008 oharboe - �yvind Harboe - oyvind.harboe@zylin.com
- * Copyright 2008 Andrew Lunn <andrew@lunn.ch>
- * Copyright 2008 Duane Ellis <openocd@duaneellis.com>
- * Copyright 2008 Uwe Klein <uklein@klein-messgeraete.de>
- * 
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above
- *    copyright notice, this list of conditions and the following
- *    disclaimer in the documentation and/or other materials
- *    provided with the distribution.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE JIM TCL PROJECT ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
- * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * JIM TCL PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
- * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- * 
- * The views and conclusions contained in the software and documentation
- * are those of the authors and should not be interpreted as representing
- * official policies, either expressed or implied, of the Jim Tcl Project.
- *
- *--- Inline Header File Documentation --- 
- *    [By Duane Ellis, openocd@duaneellis.com, 8/18/8]
- *
- * Belief is "Jim" would greatly benifit if Jim Internals where
- * documented in some way - form whatever, and perhaps - the package:
- * 'doxygen' is the correct approach to do that.
- *
- *   Details, see: http://www.stack.nl/~dimitri/doxygen/
- *
- * To that end please follow these guide lines:
- *
- *    (A) Document the PUBLIC api in the .H file.
- *
- *    (B) Document JIM Internals, in the .C file.
- *
- *    (C) Remember JIM is embedded in other packages, to that end do
- *    not assume that your way of documenting is the right way, Jim's
- *    public documentation should be agnostic, such that it is some
- *    what agreeable with the "package" that is embedding JIM inside
- *    of it's own doxygen documentation.
- *
- *    (D) Use minimal Doxygen tags.
- *
- * This will be an "ongoing work in progress" for some time.
- **/
+
+#endif
+
+#endif
 
 #ifndef __JIM__H
 #define __JIM__H
 
 #ifdef __cplusplus
@@ -209,27 +138,20 @@
 extern "C" {
 #endif
 
 #include <time.h>
 #include <limits.h>
-#include <stdio.h>  /* for the FILE typedef definition */
-#include <stdlib.h> /* In order to export the Jim_Free() macro */
-#include <stdarg.h> /* In order to get type va_list */
+#include <stdio.h>  
+#include <stdlib.h> 
+#include <stdarg.h> 
 
-/* -----------------------------------------------------------------------------
- * System configuration
- * autoconf (configure) will set these
- * ---------------------------------------------------------------------------*/
 
 #ifndef HAVE_NO_AUTOCONF
 #endif
 
-/* -----------------------------------------------------------------------------
- * Compiler specific fixes.
- * ---------------------------------------------------------------------------*/
 
-/* Long Long type and related issues */
+
 #ifndef jim_wide
 #  ifdef HAVE_LONG_LONG
 #    define jim_wide long long
 #    ifndef LLONG_MAX
 #      define LLONG_MAX    9223372036854775807LL
@@ -243,13 +165,10 @@
 #    define jim_wide long
 #    define JIM_WIDE_MIN LONG_MIN
 #    define JIM_WIDE_MAX LONG_MAX
 #  endif
 
-/* -----------------------------------------------------------------------------
- * LIBC specific fixes
- * ---------------------------------------------------------------------------*/
 
 #  ifdef HAVE_LONG_LONG
 #    define JIM_WIDE_MODIFIER "lld"
 #  else
 #    define JIM_WIDE_MODIFIER "ld"
@@ -257,80 +176,66 @@
 #  endif
 #endif
 
 #define UCHAR(c) ((unsigned char)(c))
 
-/* -----------------------------------------------------------------------------
- * Exported defines
- * ---------------------------------------------------------------------------*/
 
-/* Jim version numbering: every version of jim is marked with a
- * successive integer number. This is version 0. The first
- * stable version will be 1, then 2, 3, and so on. */
-#define JIM_VERSION 71
+#define JIM_VERSION 73
 
 #define JIM_OK 0
 #define JIM_ERR 1
 #define JIM_RETURN 2
 #define JIM_BREAK 3
 #define JIM_CONTINUE 4
 #define JIM_SIGNAL 5
 #define JIM_EXIT 6
-/* The following are internal codes and should never been seen/used */
+
 #define JIM_EVAL 7
 
-#define JIM_MAX_NESTING_DEPTH 1000 /* default max nesting depth */
+#define JIM_MAX_NESTING_DEPTH 1000 
 
-/* Some function get an integer argument with flags to change
- * the behaviour. */
-#define JIM_NONE 0    /* no flags set */
-#define JIM_ERRMSG 1    /* set an error message in the interpreter. */
+#define JIM_NONE 0    
+#define JIM_ERRMSG 1    
 
-#define JIM_UNSHARED 4 /* Flag to Jim_GetVariable() */
+#define JIM_UNSHARED 4 
 
-/* Flags for Jim_SubstObj() */
-#define JIM_SUBST_NOVAR 1 /* don't perform variables substitutions */
-#define JIM_SUBST_NOCMD 2 /* don't perform command substitutions */
-#define JIM_SUBST_NOESC 4 /* don't perform escapes substitutions */
-#define JIM_SUBST_FLAG 128 /* flag to indicate that this is a real substition object */
 
-/* Unused arguments generate annoying warnings... */
+#define JIM_SUBST_NOVAR 1 
+#define JIM_SUBST_NOCMD 2 
+#define JIM_SUBST_NOESC 4 
+#define JIM_SUBST_FLAG 128 
+
+
 #define JIM_NOTUSED(V) ((void) V)
 
-/* Flags for Jim_GetEnum() */
-#define JIM_ENUM_ABBREV 2    /* Allow unambiguous abbreviation */
 
-/* Flags used by API calls getting a 'nocase' argument. */
-#define JIM_CASESENS    0   /* case sensitive */
-#define JIM_NOCASE      1   /* no case */
+#define JIM_ENUM_ABBREV 2    
 
-/* Filesystem related */
+
+#define JIM_CASESENS    0   
+#define JIM_NOCASE      1   
+
+
 #define JIM_PATH_LEN 1024
 
-/* Newline, some embedded system may need -DJIM_CRLF */
+
 #ifdef JIM_CRLF
 #define JIM_NL "\r\n"
 #else
 #define JIM_NL "\n"
 #endif
 
 #define JIM_LIBPATH "auto_path"
 #define JIM_INTERACTIVE "tcl_interactive"
 
-/* -----------------------------------------------------------------------------
- * Stack
- * ---------------------------------------------------------------------------*/
 
 typedef struct Jim_Stack {
     int len;
     int maxlen;
     void **vector;
 } Jim_Stack;
 
-/* -----------------------------------------------------------------------------
- * Hash table
- * ---------------------------------------------------------------------------*/
 
 typedef struct Jim_HashEntry {
     const void *key;
     union {
         void *val;
@@ -362,14 +267,14 @@
     Jim_HashTable *ht;
     int index;
     Jim_HashEntry *entry, *nextEntry;
 } Jim_HashTableIterator;
 
-/* This is the initial size of every hash table */
+
 #define JIM_HT_INITIAL_SIZE     16
 
-/* ------------------------------- Macros ------------------------------------*/
+
 #define Jim_FreeEntryVal(ht, entry) \
     if ((ht)->type->valDestructor) \
         (ht)->type->valDestructor((ht)->privdata, (entry)->u.val)
 
 #define Jim_SetHashVal(ht, entry, _val_) do { \
@@ -401,405 +306,334 @@
 #define Jim_GetHashEntryVal(he) ((he)->val)
 #define Jim_GetHashTableCollisions(ht) ((ht)->collisions)
 #define Jim_GetHashTableSize(ht) ((ht)->size)
 #define Jim_GetHashTableUsed(ht) ((ht)->used)
 
-/* -----------------------------------------------------------------------------
- * Jim_Obj structure
- * ---------------------------------------------------------------------------*/
 
-/* -----------------------------------------------------------------------------
- * Jim object. This is mostly the same as Tcl_Obj itself,
- * with the addition of the 'prev' and 'next' pointers.
- * In Jim all the objects are stored into a linked list for GC purposes,
- * so that it's possible to access every object living in a given interpreter
- * sequentially. When an object is freed, it's moved into a different
- * linked list, used as object pool.
- *
- * The refcount of a freed object is always -1.
- * ---------------------------------------------------------------------------*/
 typedef struct Jim_Obj {
-    int refCount; /* reference count */
-    char *bytes; /* string representation buffer. NULL = no string repr. */
-    int length; /* number of bytes in 'bytes', not including the numterm. */
-    const struct Jim_ObjType *typePtr; /* object type. */
-    /* Internal representation union */
+    int refCount; 
+    char *bytes; 
+    int length; 
+    const struct Jim_ObjType *typePtr; 
+    
     union {
-        /* integer number type */
+        
         jim_wide wideValue;
-        /* hashed object type value */
+        
         int hashValue;
-        /* index type */
+        
         int indexValue;
-        /* return code type */
+        
         int returnCode;
-        /* double number type */
+        
         double doubleValue;
-        /* Generic pointer */
+        
         void *ptr;
-        /* Generic two pointers value */
+        
         struct {
             void *ptr1;
             void *ptr2;
         } twoPtrValue;
-        /* Variable object */
+        
         struct {
             unsigned jim_wide callFrameId;
             struct Jim_Var *varPtr;
         } varValue;
-        /* Command object */
+        
         struct {
             unsigned jim_wide procEpoch;
             struct Jim_Cmd *cmdPtr;
         } cmdValue;
-        /* List object */
+        
         struct {
-            struct Jim_Obj **ele;    /* Elements vector */
-            int len;        /* Length */
-            int maxLen;        /* Allocated 'ele' length */
+            struct Jim_Obj **ele;    
+            int len;        
+            int maxLen;        
         } listValue;
-        /* String type */
+        
         struct {
             int maxLength;
-            int charLength;     /* utf-8 char length. -1 if unknown */
+            int charLength;     
         } strValue;
-        /* Reference type */
+        
         struct {
             jim_wide id;
             struct Jim_Reference *refPtr;
         } refValue;
-        /* Source type */
+        
         struct {
-            const char *fileName;
+            struct Jim_Obj *fileNameObj;
             int lineNumber;
         } sourceValue;
-        /* Dict substitution type */
+        
         struct {
             struct Jim_Obj *varNameObjPtr;
             struct Jim_Obj *indexObjPtr;
         } dictSubstValue;
-        /* tagged binary type */
+        
         struct {
             unsigned char *data;
             size_t         len;
         } binaryValue;
-        /* Regular expression pattern */
+        
         struct {
             unsigned flags;
-            void *compre;       /* really an allocated (regex_t *) */
+            void *compre;       
         } regexpValue;
         struct {
             int line;
             int argc;
         } scriptLineValue;
     } internalRep;
-    /* This are 8 or 16 bytes more for every object
-     * but this is required for efficient garbage collection
-     * of Jim references. */
-    struct Jim_Obj *prevObjPtr; /* pointer to the prev object. */
-    struct Jim_Obj *nextObjPtr; /* pointer to the next object. */
+    struct Jim_Obj *prevObjPtr; 
+    struct Jim_Obj *nextObjPtr; 
 } Jim_Obj;
 
-/* Jim_Obj related macros */
+
 #define Jim_IncrRefCount(objPtr) \
     ++(objPtr)->refCount
 #define Jim_DecrRefCount(interp, objPtr) \
     if (--(objPtr)->refCount <= 0) Jim_FreeObj(interp, objPtr)
 #define Jim_IsShared(objPtr) \
     ((objPtr)->refCount > 1)
 
-/* This macro is used when we allocate a new object using
- * Jim_New...Obj(), but for some error we need to destroy it.
- * Instead to use Jim_IncrRefCount() + Jim_DecrRefCount() we
- * can just call Jim_FreeNewObj. To call Jim_Free directly
- * seems too raw, the object handling may change and we want
- * that Jim_FreeNewObj() can be called only against objects
- * that are belived to have refcount == 0. */
 #define Jim_FreeNewObj Jim_FreeObj
 
-/* Free the internal representation of the object. */
+
 #define Jim_FreeIntRep(i,o) \
     if ((o)->typePtr && (o)->typePtr->freeIntRepProc) \
         (o)->typePtr->freeIntRepProc(i, o)
 
-/* Get the internal representation pointer */
+
 #define Jim_GetIntRepPtr(o) (o)->internalRep.ptr
 
-/* Set the internal representation pointer */
+
 #define Jim_SetIntRepPtr(o, p) \
     (o)->internalRep.ptr = (p)
 
-/* The object type structure.
- * There are four methods.
- *
- * - FreeIntRep is used to free the internal representation of the object.
- *   Can be NULL if there is nothing to free.
- * - DupIntRep is used to duplicate the internal representation of the object.
- *   If NULL, when an object is duplicated, the internalRep union is
- *   directly copied from an object to another.
- *   Note that it's up to the caller to free the old internal repr of the
- *   object before to call the Dup method.
- * - UpdateString is used to create the string from the internal repr.
- * - setFromAny is used to convert the current object into one of this type.
- */
 
 struct Jim_Interp;
 
 typedef void (Jim_FreeInternalRepProc)(struct Jim_Interp *interp,
         struct Jim_Obj *objPtr);
 typedef void (Jim_DupInternalRepProc)(struct Jim_Interp *interp,
         struct Jim_Obj *srcPtr, Jim_Obj *dupPtr);
 typedef void (Jim_UpdateStringProc)(struct Jim_Obj *objPtr);
-    
+
 typedef struct Jim_ObjType {
-    const char *name; /* The name of the type. */
+    const char *name; 
     Jim_FreeInternalRepProc *freeIntRepProc;
     Jim_DupInternalRepProc *dupIntRepProc;
     Jim_UpdateStringProc *updateStringProc;
     int flags;
 } Jim_ObjType;
 
-/* Jim_ObjType flags */
-#define JIM_TYPE_NONE 0        /* No flags */
-#define JIM_TYPE_REFERENCES 1    /* The object may contain referneces. */
 
-/* Starting from 1 << 20 flags are reserved for private uses of
- * different calls. This way the same 'flags' argument may be used
- * to pass both global flags and private flags. */
+#define JIM_TYPE_NONE 0        
+#define JIM_TYPE_REFERENCES 1    
+
 #define JIM_PRIV_FLAG_SHIFT 20
 
-/* -----------------------------------------------------------------------------
- * Call frame, vars, commands structures
- * ---------------------------------------------------------------------------*/
 
-/* Call frame */
+
 typedef struct Jim_CallFrame {
-    unsigned jim_wide id; /* Call Frame ID. Used for caching. */
-    int level; /* Level of this call frame. 0 = global */
-    struct Jim_HashTable vars; /* Where local vars are stored */
-    struct Jim_HashTable *staticVars; /* pointer to procedure static vars */
+    unsigned jim_wide id; 
+    int level; 
+    struct Jim_HashTable vars; 
+    struct Jim_HashTable *staticVars; 
     struct Jim_CallFrame *parentCallFrame;
-    Jim_Obj *const *argv; /* object vector of the current procedure call. */
-    int argc; /* number of args of the current procedure call. */
-    Jim_Obj *procArgsObjPtr; /* arglist object of the running procedure */
-    Jim_Obj *procBodyObjPtr; /* body object of the running procedure */
+    Jim_Obj *const *argv; 
+    int argc; 
+    Jim_Obj *procArgsObjPtr; 
+    Jim_Obj *procBodyObjPtr; 
     struct Jim_CallFrame *nextFramePtr;
-    const char *filename;       /* file and line of caller of this proc (if available) */
+    Jim_Obj *fileNameObj;       
     int line;
 } Jim_CallFrame;
 
-/* The var structure. It just holds the pointer of the referenced
- * object. If linkFramePtr is not NULL the variable is a link
- * to a variable of name store on objPtr living on the given callframe
- * (this happens when the [global] or [upvar] command is used).
- * The interp in order to always know how to free the Jim_Obj associated
- * with a given variable because In Jim objects memory managment is
- * bound to interpreters. */
 typedef struct Jim_Var {
     Jim_Obj *objPtr;
     struct Jim_CallFrame *linkFramePtr;
 } Jim_Var;
 
-/* The cmd structure. */
+
 typedef int (*Jim_CmdProc)(struct Jim_Interp *interp, int argc,
     Jim_Obj *const *argv);
 typedef void (*Jim_DelCmdProc)(struct Jim_Interp *interp, void *privData);
 
 
 
-/* A command is implemented in C if funcPtr is != NULL, otherwise
- * it's a Tcl procedure with the arglist and body represented by the
- * two objects referenced by arglistObjPtr and bodyoObjPtr. */
 typedef struct Jim_Cmd {
-    int inUse;           /* Reference count */
-    int isproc;          /* Is this a procedure? */
+    int inUse;           
+    int isproc;          
     union {
         struct {
-            /* native (C) command */
-            Jim_CmdProc cmdProc; /* The command implementation */
-            Jim_DelCmdProc delProc; /* Called when the command is deleted if != NULL */
-            void *privData; /* command-private data available via Jim_CmdPrivData() */
+            
+            Jim_CmdProc cmdProc; 
+            Jim_DelCmdProc delProc; 
+            void *privData; 
         } native;
         struct {
-            /* Tcl procedure */
+            
             Jim_Obj *argListObjPtr;
             Jim_Obj *bodyObjPtr;
-            Jim_HashTable *staticVars;  /* Static vars hash table. NULL if no statics. */
-            struct Jim_Cmd *prevCmd;    /* Previous command defn if proc created 'local' */
-            int argListLen;             /* Length of argListObjPtr */
-            int reqArity;               /* Number of required parameters */
-            int optArity;               /* Number of optional parameters */
-            int argsPos;                /* Position of 'args', if specified, or -1 */
-            int upcall;                 /* True if proc is currently in upcall */
+            Jim_HashTable *staticVars;  
+            struct Jim_Cmd *prevCmd;    
+            int argListLen;             
+            int reqArity;               
+            int optArity;               
+            int argsPos;                
+            int upcall;                 
             struct Jim_ProcArg {
-                Jim_Obj *nameObjPtr;    /* Name of this arg */
-                Jim_Obj *defaultObjPtr; /* Default value, (or rename for $args) */
+                Jim_Obj *nameObjPtr;    
+                Jim_Obj *defaultObjPtr; 
             } *arglist;
         } proc;
     } u;
 } Jim_Cmd;
 
-/* Pseudo Random Number Generator State structure */
+
 typedef struct Jim_PrngState {
     unsigned char sbox[256];
     unsigned int i, j;
 } Jim_PrngState;
 
-/* -----------------------------------------------------------------------------
- * Jim interpreter structure.
- * Fields similar to the real Tcl interpreter structure have the same names.
- * ---------------------------------------------------------------------------*/
 typedef struct Jim_Interp {
-    Jim_Obj *result; /* object returned by the last command called. */
-    int errorLine; /* Error line where an error occurred. */
-    char *errorFileName; /* Error file where an error occurred. */
-    int addStackTrace; /* > 0 If a level should be added to the stack trace */
-    int maxNestingDepth; /* Used for infinite loop detection. */
-    int returnCode; /* Completion code to return on JIM_RETURN. */
-    int returnLevel; /* Current level of 'return -level' */
-    int exitCode; /* Code to return to the OS on JIM_EXIT. */
-    long id; /* Hold unique id for various purposes */
-    int signal_level; /* A nesting level of catch -signal */
-    jim_wide sigmask;  /* Bit mask of caught signals, or 0 if none */
-    int (*signal_set_result)(struct Jim_Interp *interp, jim_wide sigmask); /* Set a result for the sigmask */
-    Jim_CallFrame *framePtr; /* Pointer to the current call frame */
-    Jim_CallFrame *topFramePtr; /* toplevel/global frame pointer. */
-    struct Jim_HashTable commands; /* Commands hash table */
+    Jim_Obj *result; 
+    int errorLine; 
+    Jim_Obj *errorFileNameObj; 
+    int addStackTrace; 
+    int maxNestingDepth; 
+    int returnCode; 
+    int returnLevel; 
+    int exitCode; 
+    long id; 
+    int signal_level; 
+    jim_wide sigmask;  
+    int (*signal_set_result)(struct Jim_Interp *interp, jim_wide sigmask); 
+    Jim_CallFrame *framePtr; 
+    Jim_CallFrame *topFramePtr; 
+    struct Jim_HashTable commands; 
     unsigned jim_wide procEpoch; /* Incremented every time the result
                 of procedures names lookup caching
                 may no longer be valid. */
     unsigned jim_wide callFrameEpoch; /* Incremented every time a new
                 callframe is created. This id is used for the
                 'ID' field contained in the Jim_CallFrame
                 structure. */
-    int local; /* If 'local' is in effect, newly defined procs keep a reference to the old defn */ 
-    Jim_Obj *liveList; /* Linked list of all the live objects. */
-    Jim_Obj *freeList; /* Linked list of all the unused objects. */
-    Jim_Obj *currentScriptObj; /* Script currently in execution. */
-    Jim_Obj *emptyObj; /* Shared empty string object. */
-    Jim_Obj *trueObj; /* Shared true int object. */
-    Jim_Obj *falseObj; /* Shared false int object. */
-    unsigned jim_wide referenceNextId; /* Next id for reference. */
-    struct Jim_HashTable references; /* References hash table. */
+    int local; 
+    Jim_Obj *liveList; 
+    Jim_Obj *freeList; 
+    Jim_Obj *currentScriptObj; 
+    Jim_Obj *emptyObj; 
+    Jim_Obj *trueObj; 
+    Jim_Obj *falseObj; 
+    unsigned jim_wide referenceNextId; 
+    struct Jim_HashTable references; 
     jim_wide lastCollectId; /* reference max Id of the last GC
                 execution. It's set to -1 while the collection
                 is running as sentinel to avoid to recursive
                 calls via the [collect] command inside
                 finalizers. */
-    time_t lastCollectTime; /* unix time of the last GC execution */
-    struct Jim_HashTable sharedStrings; /* Shared Strings hash table */
-    Jim_Obj *stackTrace; /* Stack trace object. */
-    Jim_Obj *errorProc; /* Name of last procedure which returned an error */
-    Jim_Obj *unknown; /* Unknown command cache */
-    int unknown_called; /* The unknown command has been invoked */
-    int errorFlag; /* Set if an error occurred during execution. */
+    time_t lastCollectTime; 
+    Jim_Obj *stackTrace; 
+    Jim_Obj *errorProc; 
+    Jim_Obj *unknown; 
+    int unknown_called; 
+    int errorFlag; 
     void *cmdPrivData; /* Used to pass the private data pointer to
                   a command. It is set to what the user specified
                   via Jim_CreateCommand(). */
 
-    struct Jim_CallFrame *freeFramesList; /* list of CallFrame structures. */
-    struct Jim_HashTable assocData; /* per-interp storage for use by packages */
-    Jim_PrngState *prngState; /* per interpreter Random Number Gen. state. */
-    struct Jim_HashTable packages; /* Provided packages hash table */
-    Jim_Stack *localProcs; /* procs to be destroyed on end of evaluation */
-    Jim_Stack *loadHandles; /* handles of loaded modules [load] */
+    struct Jim_CallFrame *freeFramesList; 
+    struct Jim_HashTable assocData; 
+    Jim_PrngState *prngState; 
+    struct Jim_HashTable packages; 
+    Jim_Stack *localProcs; 
+    Jim_Stack *loadHandles; 
 } Jim_Interp;
 
-/* Currently provided as macro that performs the increment.
- * At some point may be a real function doing more work.
- * The proc epoch is used in order to know when a command lookup
- * cached can no longer considered valid. */
 #define Jim_InterpIncrProcEpoch(i) (i)->procEpoch++
 #define Jim_SetResultString(i,s,l) Jim_SetResult(i, Jim_NewStringObj(i,s,l))
 #define Jim_SetResultInt(i,intval) Jim_SetResult(i, Jim_NewIntObj(i,intval))
-/* Note: Using trueObj and falseObj here makes some things slower...*/
+
 #define Jim_SetResultBool(i,b) Jim_SetResultInt(i, b)
 #define Jim_SetEmptyResult(i) Jim_SetResult(i, (i)->emptyObj)
 #define Jim_GetResult(i) ((i)->result)
 #define Jim_CmdPrivData(i) ((i)->cmdPrivData)
 #define Jim_String(o) Jim_GetString((o), NULL)
 
-/* Note that 'o' is expanded only one time inside this macro,
- * so it's safe to use side effects. */
 #define Jim_SetResult(i,o) do {     \
     Jim_Obj *_resultObjPtr_ = (o);    \
     Jim_IncrRefCount(_resultObjPtr_); \
     Jim_DecrRefCount(i,(i)->result);  \
     (i)->result = _resultObjPtr_;     \
 } while(0)
 
-/* Use this for filehandles, etc. which need a unique id */
+
 #define Jim_GetId(i) (++(i)->id)
 
-/* Reference structure. The interpreter pointer is held within privdata member in HashTable */
+
 #define JIM_REFERENCE_TAGLEN 7 /* The tag is fixed-length, because the reference
                                   string representation must be fixed length. */
 typedef struct Jim_Reference {
     Jim_Obj *objPtr;
     Jim_Obj *finalizerCmdNamePtr;
     char tag[JIM_REFERENCE_TAGLEN+1];
 } Jim_Reference;
 
-/* -----------------------------------------------------------------------------
- * Exported API prototypes.
- * ---------------------------------------------------------------------------*/
 
-/* Macros that are common for extensions and core. */
+
 #define Jim_NewEmptyStringObj(i) Jim_NewStringObj(i, "", 0)
 
-/* The core includes real prototypes, extensions instead
- * include a global function pointer for every function exported.
- * Once the extension calls Jim_InitExtension(), the global
- * functon pointers are set to the value of the STUB table
- * contained in the Jim_Interp structure.
- *
- * This makes Jim able to load extensions even if it is statically
- * linked itself, and to load extensions compiled with different
- * versions of Jim (as long as the API is still compatible.) */
 
-/* Macros are common for core and extensions */
+
 #define Jim_FreeHashTableIterator(iter) Jim_Free(iter)
 
 #define JIM_EXPORT
 
-/* Memory allocation */
+
 JIM_EXPORT void *Jim_Alloc (int size);
 JIM_EXPORT void *Jim_Realloc(void *ptr, int size);
 JIM_EXPORT void Jim_Free (void *ptr);
 JIM_EXPORT char * Jim_StrDup (const char *s);
 JIM_EXPORT char *Jim_StrDupLen(const char *s, int l);
 
-/* environment */
+
 JIM_EXPORT char **Jim_GetEnviron(void);
 JIM_EXPORT void Jim_SetEnviron(char **env);
 
-/* evaluation */
+
 JIM_EXPORT int Jim_Eval(Jim_Interp *interp, const char *script);
-/* in C code, you can do this and get better error messages */
-/*   Jim_Eval_Named( interp, "some tcl commands", __FILE__, __LINE__ ); */
-JIM_EXPORT int Jim_Eval_Named(Jim_Interp *interp, const char *script,const char *filename, int lineno);
+
+
+JIM_EXPORT int Jim_EvalSource(Jim_Interp *interp, const char *filename, int lineno, const char *script);
+
+#define Jim_Eval_Named(I, S, F, L) Jim_EvalSource((I), (F), (L), (S))
+
 JIM_EXPORT int Jim_EvalGlobal(Jim_Interp *interp, const char *script);
 JIM_EXPORT int Jim_EvalFile(Jim_Interp *interp, const char *filename);
 JIM_EXPORT int Jim_EvalFileGlobal(Jim_Interp *interp, const char *filename);
 JIM_EXPORT int Jim_EvalObj (Jim_Interp *interp, Jim_Obj *scriptObjPtr);
 JIM_EXPORT int Jim_EvalObjVector (Jim_Interp *interp, int objc,
         Jim_Obj *const *objv);
-JIM_EXPORT int Jim_EvalObjPrefix(Jim_Interp *interp, const char *prefix,
+JIM_EXPORT int Jim_EvalObjPrefix(Jim_Interp *interp, Jim_Obj *prefix,
         int objc, Jim_Obj *const *objv);
+#define Jim_EvalPrefix(i, p, oc, ov) Jim_EvalObjPrefix((i), Jim_NewStringObj((i), (p), -1), (oc), (ov))
 JIM_EXPORT int Jim_SubstObj (Jim_Interp *interp, Jim_Obj *substObjPtr,
         Jim_Obj **resObjPtrPtr, int flags);
 
-/* stack */
+
 JIM_EXPORT void Jim_InitStack(Jim_Stack *stack);
 JIM_EXPORT void Jim_FreeStack(Jim_Stack *stack);
 JIM_EXPORT int Jim_StackLen(Jim_Stack *stack);
 JIM_EXPORT void Jim_StackPush(Jim_Stack *stack, void *element);
 JIM_EXPORT void * Jim_StackPop(Jim_Stack *stack);
 JIM_EXPORT void * Jim_StackPeek(Jim_Stack *stack);
 JIM_EXPORT void Jim_FreeStackElements(Jim_Stack *stack, void (*freeFunc)(void *ptr));
 
-/* hash table */
+
 JIM_EXPORT int Jim_InitHashTable (Jim_HashTable *ht,
         const Jim_HashTableType *type, void *privdata);
 JIM_EXPORT int Jim_ExpandHashTable (Jim_HashTable *ht,
         unsigned int size);
 JIM_EXPORT int Jim_AddHashEntry (Jim_HashTable *ht, const void *key,
@@ -815,11 +649,11 @@
 JIM_EXPORT Jim_HashTableIterator *Jim_GetHashTableIterator
         (Jim_HashTable *ht);
 JIM_EXPORT Jim_HashEntry * Jim_NextHashEntry
         (Jim_HashTableIterator *iter);
 
-/* objects */
+
 JIM_EXPORT Jim_Obj * Jim_NewObj (Jim_Interp *interp);
 JIM_EXPORT void Jim_FreeObj (Jim_Interp *interp, Jim_Obj *objPtr);
 JIM_EXPORT void Jim_InvalidateStringRep (Jim_Obj *objPtr);
 JIM_EXPORT void Jim_InitStringRep (Jim_Obj *objPtr, const char *bytes,
         int length);
@@ -827,11 +661,11 @@
         Jim_Obj *objPtr);
 JIM_EXPORT const char * Jim_GetString(Jim_Obj *objPtr,
         int *lenPtr);
 JIM_EXPORT int Jim_Length(Jim_Obj *objPtr);
 
-/* string object */
+
 JIM_EXPORT Jim_Obj * Jim_NewStringObj (Jim_Interp *interp,
         const char *s, int len);
 JIM_EXPORT Jim_Obj *Jim_NewStringObjUtf8(Jim_Interp *interp,
         const char *s, int charlen);
 JIM_EXPORT Jim_Obj * Jim_NewStringObjNoAlloc (Jim_Interp *interp,
@@ -856,33 +690,33 @@
         Jim_Obj *objPtr, const char *str);
 JIM_EXPORT int Jim_StringCompareObj(Jim_Interp *interp, Jim_Obj *firstObjPtr,
         Jim_Obj *secondObjPtr, int nocase);
 JIM_EXPORT int Jim_Utf8Length(Jim_Interp *interp, Jim_Obj *objPtr);
 
-/* reference object */
+
 JIM_EXPORT Jim_Obj * Jim_NewReference (Jim_Interp *interp,
         Jim_Obj *objPtr, Jim_Obj *tagPtr, Jim_Obj *cmdNamePtr);
 JIM_EXPORT Jim_Reference * Jim_GetReference (Jim_Interp *interp,
         Jim_Obj *objPtr);
 JIM_EXPORT int Jim_SetFinalizer (Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj *cmdNamePtr);
 JIM_EXPORT int Jim_GetFinalizer (Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj **cmdNamePtrPtr);
 
-/* interpreter */
+
 JIM_EXPORT Jim_Interp * Jim_CreateInterp (void);
 JIM_EXPORT void Jim_FreeInterp (Jim_Interp *i);
 JIM_EXPORT int Jim_GetExitCode (Jim_Interp *interp);
 JIM_EXPORT const char *Jim_ReturnCode(int code);
 JIM_EXPORT void Jim_SetResultFormatted(Jim_Interp *interp, const char *format, ...);
 
-/* commands */
+
 JIM_EXPORT void Jim_RegisterCoreCommands (Jim_Interp *interp);
-JIM_EXPORT int Jim_CreateCommand (Jim_Interp *interp, 
+JIM_EXPORT int Jim_CreateCommand (Jim_Interp *interp,
         const char *cmdName, Jim_CmdProc cmdProc, void *privData,
          Jim_DelCmdProc delProc);
 JIM_EXPORT int Jim_DeleteCommand (Jim_Interp *interp,
         const char *cmdName);
-JIM_EXPORT int Jim_RenameCommand (Jim_Interp *interp, 
+JIM_EXPORT int Jim_RenameCommand (Jim_Interp *interp,
         const char *oldName, const char *newName);
 JIM_EXPORT Jim_Cmd * Jim_GetCommand (Jim_Interp *interp,
         Jim_Obj *objPtr, int flags);
 JIM_EXPORT int Jim_SetVariable (Jim_Interp *interp,
         Jim_Obj *nameObjPtr, Jim_Obj *valObjPtr);
@@ -904,23 +738,23 @@
 JIM_EXPORT Jim_Obj * Jim_GetGlobalVariableStr (Jim_Interp *interp,
         const char *name, int flags);
 JIM_EXPORT int Jim_UnsetVariable (Jim_Interp *interp,
         Jim_Obj *nameObjPtr, int flags);
 
-/* call frame */
+
 JIM_EXPORT Jim_CallFrame *Jim_GetCallFrameByLevel(Jim_Interp *interp,
         Jim_Obj *levelObjPtr);
 
-/* garbage collection */
+
 JIM_EXPORT int Jim_Collect (Jim_Interp *interp);
 JIM_EXPORT void Jim_CollectIfNeeded (Jim_Interp *interp);
 
-/* index object */
+
 JIM_EXPORT int Jim_GetIndex (Jim_Interp *interp, Jim_Obj *objPtr,
         int *indexPtr);
 
-/* list object */
+
 JIM_EXPORT Jim_Obj * Jim_NewListObj (Jim_Interp *interp,
         Jim_Obj *const *elements, int len);
 JIM_EXPORT void Jim_ListInsertElements (Jim_Interp *interp,
         Jim_Obj *listPtr, int listindex, int objc, Jim_Obj *const *objVec);
 JIM_EXPORT void Jim_ListAppendElement (Jim_Interp *interp,
@@ -934,204 +768,146 @@
         Jim_Obj *varNamePtr, Jim_Obj *const *indexv, int indexc,
         Jim_Obj *newObjPtr);
 JIM_EXPORT Jim_Obj * Jim_ConcatObj (Jim_Interp *interp, int objc,
         Jim_Obj *const *objv);
 
-/* dict object */
+
 JIM_EXPORT Jim_Obj * Jim_NewDictObj (Jim_Interp *interp,
         Jim_Obj *const *elements, int len);
 JIM_EXPORT int Jim_DictKey (Jim_Interp *interp, Jim_Obj *dictPtr,
         Jim_Obj *keyPtr, Jim_Obj **objPtrPtr, int flags);
 JIM_EXPORT int Jim_DictKeysVector (Jim_Interp *interp,
         Jim_Obj *dictPtr, Jim_Obj *const *keyv, int keyc,
         Jim_Obj **objPtrPtr, int flags);
 JIM_EXPORT int Jim_SetDictKeysVector (Jim_Interp *interp,
         Jim_Obj *varNamePtr, Jim_Obj *const *keyv, int keyc,
-        Jim_Obj *newObjPtr);
+        Jim_Obj *newObjPtr, int flags);
 JIM_EXPORT int Jim_DictPairs(Jim_Interp *interp,
         Jim_Obj *dictPtr, Jim_Obj ***objPtrPtr, int *len);
 JIM_EXPORT int Jim_DictAddElement(Jim_Interp *interp, Jim_Obj *objPtr,
         Jim_Obj *keyObjPtr, Jim_Obj *valueObjPtr);
 JIM_EXPORT int Jim_DictKeys(Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj *patternObj);
 JIM_EXPORT int Jim_DictSize(Jim_Interp *interp, Jim_Obj *objPtr);
 
-/* return code object */
+
 JIM_EXPORT int Jim_GetReturnCode (Jim_Interp *interp, Jim_Obj *objPtr,
         int *intPtr);
 
-/* expression object */
+
 JIM_EXPORT int Jim_EvalExpression (Jim_Interp *interp,
         Jim_Obj *exprObjPtr, Jim_Obj **exprResultPtrPtr);
 JIM_EXPORT int Jim_GetBoolFromExpr (Jim_Interp *interp,
         Jim_Obj *exprObjPtr, int *boolPtr);
 
-/* integer object */
+
 JIM_EXPORT int Jim_GetWide (Jim_Interp *interp, Jim_Obj *objPtr,
         jim_wide *widePtr);
 JIM_EXPORT int Jim_GetLong (Jim_Interp *interp, Jim_Obj *objPtr,
         long *longPtr);
 #define Jim_NewWideObj  Jim_NewIntObj
 JIM_EXPORT Jim_Obj * Jim_NewIntObj (Jim_Interp *interp,
         jim_wide wideValue);
 
-/* double object */
+
 JIM_EXPORT int Jim_GetDouble(Jim_Interp *interp, Jim_Obj *objPtr,
         double *doublePtr);
 JIM_EXPORT void Jim_SetDouble(Jim_Interp *interp, Jim_Obj *objPtr,
         double doubleValue);
 JIM_EXPORT Jim_Obj * Jim_NewDoubleObj(Jim_Interp *interp, double doubleValue);
 
-/* shared strings */
-JIM_EXPORT const char * Jim_GetSharedString (Jim_Interp *interp, 
+
+JIM_EXPORT const char * Jim_GetSharedString (Jim_Interp *interp,
         const char *str);
 JIM_EXPORT void Jim_ReleaseSharedString (Jim_Interp *interp,
         const char *str);
 
-/* commands utilities */
+
 JIM_EXPORT void Jim_WrongNumArgs (Jim_Interp *interp, int argc,
         Jim_Obj *const *argv, const char *msg);
 JIM_EXPORT int Jim_GetEnum (Jim_Interp *interp, Jim_Obj *objPtr,
         const char * const *tablePtr, int *indexPtr, const char *name, int flags);
 JIM_EXPORT int Jim_ScriptIsComplete (const char *s, int len,
         char *stateCharPtr);
-/**
- * Find a matching name in the array of the given length.
- * 
- * NULL entries are ignored.
- *
- * Returns the matching index if found, or -1 if not.
- */
 JIM_EXPORT int Jim_FindByName(const char *name, const char * const array[], size_t len);
 
-/* package utilities */
+
 typedef void (Jim_InterpDeleteProc)(Jim_Interp *interp, void *data);
 JIM_EXPORT void * Jim_GetAssocData(Jim_Interp *interp, const char *key);
 JIM_EXPORT int Jim_SetAssocData(Jim_Interp *interp, const char *key,
         Jim_InterpDeleteProc *delProc, void *data);
 JIM_EXPORT int Jim_DeleteAssocData(Jim_Interp *interp, const char *key);
 
-/* Packages C API */
-/* jim-package.c */
+
+
 JIM_EXPORT int Jim_PackageProvide (Jim_Interp *interp,
         const char *name, const char *ver, int flags);
 JIM_EXPORT int Jim_PackageRequire (Jim_Interp *interp,
         const char *name, int flags);
 
-/* error messages */
+
 JIM_EXPORT void Jim_MakeErrorMessage (Jim_Interp *interp);
 
-/* interactive mode */
+
 JIM_EXPORT int Jim_InteractivePrompt (Jim_Interp *interp);
 
-/* Misc */
+
 JIM_EXPORT int Jim_InitStaticExtensions(Jim_Interp *interp);
 JIM_EXPORT int Jim_StringToWide(const char *str, jim_wide *widePtr, int base);
 
-/* jim-load.c */
+
 JIM_EXPORT int Jim_LoadLibrary(Jim_Interp *interp, const char *pathName);
 JIM_EXPORT void Jim_FreeLoadHandles(Jim_Interp *interp);
 
-/* jim-aio.c */
+
 JIM_EXPORT FILE *Jim_AioFilehandle(Jim_Interp *interp, Jim_Obj *command);
 
 
-/* type inspection - avoid where possible */
+
 JIM_EXPORT int Jim_IsDict(Jim_Obj *objPtr);
 JIM_EXPORT int Jim_IsList(Jim_Obj *objPtr);
 
 #ifdef __cplusplus
 }
 #endif
 
-#endif /* __JIM__H */
+#endif 
 
-/*
- * Local Variables: ***
- * c-basic-offset: 4 ***
- * tab-width: 4 ***
- * End: ***
- */
-/* Provides a common approach to implementing Tcl commands
- * which implement subcommands
- */
 #ifndef JIM_SUBCMD_H
 #define JIM_SUBCMD_H
 
 
-#define JIM_MODFLAG_HIDDEN   0x0001		/* Don't show the subcommand in usage or commands */
-#define JIM_MODFLAG_FULLARGV 0x0002		/* Subcmd proc gets called with full argv */
+#ifdef __cplusplus
+extern "C" {
+#endif
 
-/* Custom flags start at 0x0100 */
 
-/**
- * Returns JIM_OK if OK, JIM_ERR (etc.) on error, break, continue, etc.
- * Returns -1 if invalid args.
- */
+#define JIM_MODFLAG_HIDDEN   0x0001		
+#define JIM_MODFLAG_FULLARGV 0x0002		
+
+
+
 typedef int tclmod_cmd_function(Jim_Interp *interp, int argc, Jim_Obj *const *argv);
 
 typedef struct {
-	const char *cmd;				/* Name of the (sub)command */
-	const char *args;				/* Textual description of allowed args */
-	tclmod_cmd_function *function;	/* Function implementing the subcommand */
-	short minargs;					/* Minimum required arguments */
-	short maxargs;					/* Maximum allowed arguments or -1 if no limit */
-	unsigned flags;					/* JIM_MODFLAG_... plus custom flags */
-	const char *description;		/* Description of the subcommand */
+	const char *cmd;				
+	const char *args;				
+	tclmod_cmd_function *function;	
+	short minargs;					
+	short maxargs;					
+	unsigned short flags;			
 } jim_subcmd_type;
 
-/**
- * Looks up the appropriate subcommand in the given command table and return
- * the command function which implements the subcommand.
- * NULL will be returned and an appropriate error will be set if the subcommand or 
- * arguments are invalid.
- *
- * Typical usage is:
- *  {
- *    const jim_subcmd_type *ct = Jim_ParseSubCmd(interp, command_table, argc, argv);
- *
- *    return Jim_CallSubCmd(interp, ct, argc, argv);
- *  }
- *
- */
 const jim_subcmd_type *
 Jim_ParseSubCmd(Jim_Interp *interp, const jim_subcmd_type *command_table, int argc, Jim_Obj *const *argv);
 
-/**
- * Parses the args against the given command table and executes the subcommand if found
- * or sets an appropriate error if the subcommand or arguments is invalid.
- *
- * Can be used directly with Jim_CreateCommand() where the ClientData is the command table.
- *
- * e.g. Jim_CreateCommand(interp, "mycmd", Jim_SubCmdProc, command_table, NULL);
- */
 int Jim_SubCmdProc(Jim_Interp *interp, int argc, Jim_Obj *const *argv);
 
-/**
- * Invokes the given subcmd with the given args as returned
- * by Jim_ParseSubCmd()
- * 
- * If ct is NULL, returns JIM_ERR, leaving any message.
- * Otherwise invokes ct->function
- *
- * If ct->function returns -1, sets an error message and returns JIM_ERR.
- * Otherwise returns the result of ct->function.
- */
 int Jim_CallSubCmd(Jim_Interp *interp, const jim_subcmd_type *ct, int argc, Jim_Obj *const *argv);
 
-/**
- * Standard processing for a command.
- * 
- * This does the '-help' and '-usage' check and the number of args checks.
- * for a top level command against a single 'jim_subcmd_type' structure.
- *
- * Additionally, if command_table->function is set, it should point to a sub command table
- * and '-subhelp ?subcmd?', '-subusage' and '-subcommands' are then also recognised.
- * 
- * Returns 0 if user requested usage, -1 on arg error, 1 if OK to process.
- */
-int
-Jim_CheckCmdUsage(Jim_Interp *interp, const jim_subcmd_type *command_table, int argc, Jim_Obj *const *argv);
+#ifdef __cplusplus
+}
+#endif
 
 #endif
 #ifndef JIMREGEXP_H
 #define JIMREGEXP_H
 
@@ -1138,78 +914,51 @@
 #ifndef _JIMAUTOCONF_H
 #error Need jimautoconf.h
 #endif
 
 #if defined(HAVE_REGCOMP) && !defined(JIM_REGEXP)
-/* Use POSIX regex */
+
 #include <regex.h>
 
 #else
 
 #include <stdlib.h>
 
-/*
- * Definitions etc. for regexp(3) routines.
- *
- * Caveat:  this is V8 regexp(3) [actually, a reimplementation thereof],
- * not the System V one.
- *
- * 11/04/02 (seiwald) - const-ing for string literals
- */
 
 typedef struct {
 	int rm_so;
 	int rm_eo;
 } regmatch_t;
 
-/*
- * The "internal use only" fields in regexp.h are present to pass info from
- * compile to execute that permits the execute phase to run lots faster on
- * simple cases.  They are:
- *
- * regstart	char that must begin a match; '\0' if none obvious
- * reganch	is the match anchored (at beginning-of-line only)?
- * regmust	string (pointer into program) that match must include, or NULL
- * regmlen	length of regmust string
- *
- * Regstart and reganch permit very fast decisions on suitable starting points
- * for a match, cutting down the work a lot.  Regmust permits fast rejection
- * of lines that cannot possibly match.  The regmust tests are costly enough
- * that regcomp() supplies a regmust only if the r.e. contains something
- * potentially expensive (at present, the only such thing detected is * or +
- * at the start of the r.e., which can involve a lot of backup).  Regmlen is
- * supplied because the test in regexec() needs it and regcomp() is computing
- * it anyway.
- */
 
 typedef struct regexp {
-	/* -- public -- */
-	int re_nsub;		/* number of parenthesized subexpressions */
-
-	/* -- private -- */
-	int cflags;			/* Flags used when compiling */
-	int err;			/* Any error which occurred during compile */
-	int regstart;		/* Internal use only. */
-	int reganch;		/* Internal use only. */
-	int regmust;		/* Internal use only. */
-	int regmlen;		/* Internal use only. */
-	int *program;		/* Allocated */
-
-	/* working state - compile */
-	const char *regparse;		/* Input-scan pointer. */
-	int p;				/* Current output pos in program */
-	int proglen;		/* Allocated program size */
-
-	/* working state - exec */
-	int eflags;				/* Flags used when executing */
-	const char *start;		/* Initial string pointer. */
-	const char *reginput;	/* Current input pointer. */
-	const char *regbol;		/* Beginning of input, for ^ check. */
-
-	/* Input to regexec() */
-	regmatch_t *pmatch;		/* submatches will be stored here */
-	int nmatch;				/* size of pmatch[] */
+	
+	int re_nsub;		
+
+	
+	int cflags;			
+	int err;			
+	int regstart;		
+	int reganch;		
+	int regmust;		
+	int regmlen;		
+	int *program;		
+
+	
+	const char *regparse;		
+	int p;				
+	int proglen;		
+
+	
+	int eflags;				
+	const char *start;		
+	const char *reginput;	
+	const char *regbol;		
+
+	
+	regmatch_t *pmatch;		
+	int nmatch;				
 } regexp;
 
 typedef regexp regex_t;
 
 #define REG_EXTENDED 0
@@ -1217,13 +966,13 @@
 #define REG_ICASE 2
 
 #define REG_NOTBOL 16
 
 enum {
-	REG_NOERROR,      /* Success.  */
-	REG_NOMATCH,      /* Didn't find a match (for regexec).  */
-	REG_BADPAT,		  /* >= REG_BADPAT is an error */
+	REG_NOERROR,      
+	REG_NOMATCH,      
+	REG_BADPAT,		  
 	REG_ERR_NULL_ARGUMENT,
 	REG_ERR_UNKNOWN,
 	REG_ERR_TOO_BIG,
 	REG_ERR_NOMEM,
 	REG_ERR_TOO_MANY_PAREN,
@@ -1252,22 +1001,22 @@
 int Jim_bootstrapInit(Jim_Interp *interp)
 {
 	if (Jim_PackageProvide(interp, "bootstrap", "1.0", JIM_ERRMSG))
 		return JIM_ERR;
 
-	return Jim_Eval_Named(interp, 
+	return Jim_EvalSource(interp, "bootstrap.tcl", 1,
 "\n"
 "\n"
 "proc package {args} {}\n"
-,"bootstrap.tcl", 1);
+);
 }
 int Jim_initjimshInit(Jim_Interp *interp)
 {
 	if (Jim_PackageProvide(interp, "initjimsh", "1.0", JIM_ERRMSG))
 		return JIM_ERR;
 
-	return Jim_Eval_Named(interp, 
+	return Jim_EvalSource(interp, "initjimsh.tcl", 1,
 "\n"
 "\n"
 "\n"
 "proc _jimsh_init {} {\n"
 "	rename _jimsh_init {}\n"
@@ -1291,18 +1040,18 @@
 "if {$tcl_platform(platform) eq \"windows\"} {\n"
 "	set jim_argv0 [string map {\\\\ /} $jim_argv0]\n"
 "}\n"
 "\n"
 "_jimsh_init\n"
-,"initjimsh.tcl", 1);
+);
 }
 int Jim_globInit(Jim_Interp *interp)
 {
 	if (Jim_PackageProvide(interp, "glob", "1.0", JIM_ERRMSG))
 		return JIM_ERR;
 
-	return Jim_Eval_Named(interp, 
+	return Jim_EvalSource(interp, "glob.tcl", 1,
 "\n"
 "\n"
 "\n"
 "\n"
 "\n"
@@ -1428,18 +1177,18 @@
 "		return -code error \"no files matched glob patterns\"\n"
 "	}\n"
 "\n"
 "	return $result\n"
 "}\n"
-,"glob.tcl", 1);
+);
 }
 int Jim_stdlibInit(Jim_Interp *interp)
 {
 	if (Jim_PackageProvide(interp, "stdlib", "1.0", JIM_ERRMSG))
 		return JIM_ERR;
 
-	return Jim_Eval_Named(interp, 
+	return Jim_EvalSource(interp, "stdlib.tcl", 1,
 "\n"
 "\n"
 "\n"
 "proc alias {name args} {\n"
 "	set prefix $args\n"
@@ -1543,11 +1292,11 @@
 "	if {[info exists ::jim_argv0]} {\n"
 "		if {[string match \"*/*\" $::jim_argv0]} {\n"
 "			return [file join [pwd] $::jim_argv0]\n"
 "		}\n"
 "		foreach path [split [env PATH \"\"] $::tcl_platform(pathSeparator)] {\n"
-"			set exec [file join [pwd] $path $::jim_argv0]\n"
+"			set exec [file join [pwd] [string map {\\\\ /} $path] $::jim_argv0]\n"
 "			if {[file executable $exec]} {\n"
 "				return $exec\n"
 "			}\n"
 "		}\n"
 "	}\n"
@@ -1586,18 +1335,18 @@
 "			dict set dict $k $v\n"
 "		}\n"
 "	}\n"
 "	return $dict\n"
 "}\n"
-,"stdlib.tcl", 1);
+);
 }
 int Jim_tclcompatInit(Jim_Interp *interp)
 {
 	if (Jim_PackageProvide(interp, "tclcompat", "1.0", JIM_ERRMSG))
 		return JIM_ERR;
 
-	return Jim_Eval_Named(interp, 
+	return Jim_EvalSource(interp, "tclcompat.tcl", 1,
 "\n"
 "\n"
 "\n"
 "\n"
 "\n"
@@ -1873,53 +1622,14 @@
 "	foreach e [readdir $path] {\n"
 "		file delete -force $path/$e\n"
 "	}\n"
 "	file delete $path\n"
 "}\n"
-,"tclcompat.tcl", 1);
+);
 }
 
-/* Jim - A small embeddable Tcl interpreter
- *
- * Copyright 2005 Salvatore Sanfilippo <antirez@invece.org>
- * Copyright 2005 Clemens Hintze <c.hintze@gmx.net>
- * Copyright 2005 patthoyts - Pat Thoyts <patthoyts@users.sf.net> 
- * Copyright 2008 oharboe - Øyvind Harboe - oyvind.harboe@zylin.com
- * Copyright 2008 Andrew Lunn <andrew@lunn.ch>
- * Copyright 2008 Duane Ellis <openocd@duaneellis.com>
- * Copyright 2008 Uwe Klein <uklein@klein-messgeraete.de>
- * 
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above
- *    copyright notice, this list of conditions and the following
- *    disclaimer in the documentation and/or other materials
- *    provided with the distribution.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE JIM TCL PROJECT ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
- * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * JIM TCL PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
- * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- * 
- * The views and conclusions contained in the software and documentation
- * are those of the authors and should not be interpreted as representing
- * official policies, either expressed or implied, of the Jim Tcl Project.
- **/
 
-#include <unistd.h>
 #include <stdio.h>
 #include <string.h>
 #include <errno.h>
 #include <fcntl.h>
 
@@ -1927,20 +1637,21 @@
 #if defined(HAVE_SYS_SOCKET_H) && defined(HAVE_SELECT) && defined(HAVE_NETINET_IN_H) && defined(HAVE_NETDB_H) && defined(HAVE_ARPA_INET_H)
 #include <sys/socket.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
 #include <netdb.h>
+#include <unistd.h>
 #ifdef HAVE_SYS_UN_H
 #include <sys/un.h>
 #endif
 #else
 #define JIM_ANSIC
 #endif
 
 
-#define AIO_CMD_LEN 32      /* e.g. aio.handleXXXXXX */
-#define AIO_BUF_LEN 256     /* Can keep this small and rely on stdio buffering */
+#define AIO_CMD_LEN 32      
+#define AIO_BUF_LEN 256     
 
 #define AIO_KEEPOPEN 1
 
 #if defined(JIM_IPV6)
 #define IPV6 1
@@ -1949,194 +1660,31 @@
 #ifndef PF_INET6
 #define PF_INET6 0
 #endif
 #endif
 
-#ifndef JIM_ANSIC
-union sockaddr_any {
-    struct sockaddr sa;
-    struct sockaddr_in sin;
-#if IPV6
-    struct sockaddr_in6 sin6;
-#endif
-};
-
-#ifndef HAVE_INET_NTOP
-const char *inet_ntop(int af, const void *src, char *dst, int size)
-{
-    if (af != PF_INET) {
-        return NULL;
-    }
-    snprintf(dst, size, "%s", inet_ntoa(((struct sockaddr_in *)src)->sin_addr));
-    return dst;
-}
-#endif
-#endif
 
 typedef struct AioFile
 {
     FILE *fp;
     Jim_Obj *filename;
     int type;
-    int OpenFlags;              /* AIO_KEEPOPEN? keep FILE* */
+    int OpenFlags;              
     int fd;
 #ifdef O_NDELAY
     int flags;
 #endif
     Jim_Obj *rEvent;
     Jim_Obj *wEvent;
     Jim_Obj *eEvent;
-#ifndef JIM_ANSIC
     int addr_family;
-#endif
 } AioFile;
 
 static int JimAioSubCmdProc(Jim_Interp *interp, int argc, Jim_Obj *const *argv);
-
-#ifndef JIM_ANSIC
-static int JimParseIPv6Address(Jim_Interp *interp, const char *hostport, union sockaddr_any *sa, int *salen)
-{
-#if IPV6
-    /*
-     * An IPv6 addr/port looks like:
-     *   [::1]
-     *   [::1]:2000
-     *   [fe80::223:6cff:fe95:bdc0%en1]:2000
-     *   [::]:2000
-     *   2000
-     *
-     *   Note that the "any" address is ::, which is the same as when no address is specified.
-     */
-     char *sthost = NULL;
-     const char *stport;
-     int ret = JIM_OK;
-     struct addrinfo req;
-     struct addrinfo *ai;
-
-    stport = strrchr(hostport, ':');
-    if (!stport) {
-        /* No : so, the whole thing is the port */
-        stport = hostport;
-        hostport = "::";
-        sthost = Jim_StrDup(hostport);
-    }
-    else {
-        stport++;
-    }
-
-    if (*hostport == '[') {
-        /* This is a numeric ipv6 address */
-        char *pt = strchr(++hostport, ']');
-        if (pt) {
-            sthost = Jim_StrDupLen(hostport, pt - hostport);
-        }
-    }
-
-    if (!sthost) {
-        sthost = Jim_StrDupLen(hostport, stport - hostport - 1);
-    }
-
-    memset(&req, '\0', sizeof(req));
-    req.ai_family = PF_INET6;
-    
-    if (getaddrinfo(sthost, NULL, &req, &ai)) {
-        Jim_SetResultFormatted(interp, "Not a valid address: %s", hostport);
-        ret = JIM_ERR;
-    }
-    else {
-        memcpy(&sa->sin, ai->ai_addr, ai->ai_addrlen);
-        *salen = ai->ai_addrlen;
-
-        sa->sin.sin_port = htons(atoi(stport));
-
-        freeaddrinfo(ai);
-    }
-    Jim_Free(sthost);
-
-    return ret;
-#else
-    Jim_SetResultString(interp, "ipv6 not supported", -1);
-    return JIM_ERR;
-#endif
-}
-
-static int JimParseIpAddress(Jim_Interp *interp, const char *hostport, union sockaddr_any *sa, int *salen)
-{
-    /* An IPv4 addr/port looks like:
-     *   192.168.1.5
-     *   192.168.1.5:2000
-     *   2000
-     *
-     * If the address is missing, INADDR_ANY is used.
-     * If the port is missing, 0 is used (only useful for server sockets).
-     */
-    char *sthost = NULL;
-    const char *stport;
-    int ret = JIM_OK;
-
-    stport = strrchr(hostport, ':');
-    if (!stport) {
-        /* No : so, the whole thing is the port */
-        stport = hostport;
-        sthost = Jim_StrDup("0.0.0.0");
-    }
-    else {
-        sthost = Jim_StrDupLen(hostport, stport - hostport);
-        stport++;
-    }
-
-    {
-#ifdef HAVE_GETADDRINFO
-        struct addrinfo req;
-        struct addrinfo *ai;
-        memset(&req, '\0', sizeof(req));
-        req.ai_family = PF_INET;
-        
-        if (getaddrinfo(sthost, NULL, &req, &ai)) {
-            ret = JIM_ERR;
-        }
-        else {
-            memcpy(&sa->sin, ai->ai_addr, ai->ai_addrlen);
-            *salen = ai->ai_addrlen;
-            freeaddrinfo(ai);
-        }
-#else
-        struct hostent *he;
-
-        ret = JIM_ERR;
-
-        if ((he = gethostbyname(sthost)) != NULL) {
-            if (he->h_length == sizeof(sa->sin.sin_addr)) {
-                *salen = sizeof(sa->sin);
-                sa->sin.sin_family= he->h_addrtype;
-                memcpy(&sa->sin.sin_addr, he->h_addr, he->h_length); /* set address */
-                ret = JIM_OK;
-            }
-        }
-#endif
-
-        sa->sin.sin_port = htons(atoi(stport));
-    }
-    Jim_Free(sthost);
-
-    if (ret != JIM_OK) {
-        Jim_SetResultFormatted(interp, "Not a valid address: %s", hostport);
-    }
-
-    return ret;
-}
-
-#ifdef HAVE_SYS_UN_H
-static int JimParseDomainAddress(Jim_Interp *interp, const char *path, struct sockaddr_un *sa)
-{
-    sa->sun_family = PF_UNIX;
-    snprintf(sa->sun_path, sizeof(sa->sun_path), "%s", path);
-
-    return JIM_OK;
-}
-#endif
-#endif
+static int JimMakeChannel(Jim_Interp *interp, FILE *fh, int fd, Jim_Obj *filename,
+    const char *hdlfmt, int family, const char *mode);
+
 
 static void JimAioSetError(Jim_Interp *interp, Jim_Obj *name)
 {
     if (name) {
         Jim_SetResultFormatted(interp, "%#s: %s", name, strerror(errno));
@@ -2150,17 +1698,18 @@
 {
     AioFile *af = privData;
 
     JIM_NOTUSED(interp);
 
-    Jim_DecrRefCount(interp, af->filename);
-
     if (!(af->OpenFlags & AIO_KEEPOPEN)) {
         fclose(af->fp);
     }
+
+    Jim_DecrRefCount(interp, af->filename);
+
 #ifdef jim_ext_eventloop
-    /* remove existing EventHandlers */
+    
     if (af->rEvent) {
         Jim_DeleteFileHandler(interp, af->fp);
     }
     if (af->wEvent) {
         Jim_DeleteFileHandler(interp, af->fp);
@@ -2176,11 +1725,11 @@
 {
     AioFile *af = Jim_CmdPrivData(interp);
     char buf[AIO_BUF_LEN];
     Jim_Obj *objPtr;
     int nonewline = 0;
-    int neededLen = -1;         /* -1 is "read as much as possible" */
+    int neededLen = -1;         
 
     if (argc && Jim_CompareStringImmediate(interp, argv[0], "-nonewline")) {
         nonewline = 1;
         argv++;
         argc--;
@@ -2218,16 +1767,16 @@
             }
         }
         if (retval != readlen)
             break;
     }
-    /* Check for error conditions */
+    
     if (ferror(af->fp)) {
         clearerr(af->fp);
-        /* eof and EAGAIN are not error conditions */
+        
         if (!feof(af->fp) && errno != EAGAIN) {
-            /* I/O error */
+            
             Jim_FreeNewObj(interp, objPtr);
             JimAioSetError(interp, af->filename);
             return JIM_ERR;
         }
     }
@@ -2290,62 +1839,56 @@
 static int aio_cmd_gets(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
 {
     AioFile *af = Jim_CmdPrivData(interp);
     char buf[AIO_BUF_LEN];
     Jim_Obj *objPtr;
+    int len;
 
     errno = 0;
 
     objPtr = Jim_NewStringObj(interp, NULL, 0);
     while (1) {
-        int more = 0;
-
         buf[AIO_BUF_LEN - 1] = '_';
         if (fgets(buf, AIO_BUF_LEN, af->fp) == NULL)
             break;
-        if (buf[AIO_BUF_LEN - 1] == '\0' && buf[AIO_BUF_LEN - 2] != '\n')
-            more = 1;
-        if (more) {
+
+        if (buf[AIO_BUF_LEN - 1] == '\0' && buf[AIO_BUF_LEN - 2] != '\n') {
             Jim_AppendString(interp, objPtr, buf, AIO_BUF_LEN - 1);
         }
         else {
-            int len = strlen(buf);
+            len = strlen(buf);
 
-            if (len) {
-                int hasnl = (buf[len - 1] == '\n');
+            if (len && (buf[len - 1] == '\n')) {
+                
+                len--;
+            }
 
-                /* strip "\n" */
-                Jim_AppendString(interp, objPtr, buf, strlen(buf) - hasnl);
-            }
+            Jim_AppendString(interp, objPtr, buf, len);
+            break;
         }
-        if (!more)
-            break;
     }
     if (ferror(af->fp) && errno != EAGAIN && errno != EINTR) {
-        /* I/O error */
+        
         Jim_FreeNewObj(interp, objPtr);
         JimAioSetError(interp, af->filename);
         clearerr(af->fp);
         return JIM_ERR;
     }
-    /* On EOF returns -1 if varName was specified, or the empty string. */
-    if (feof(af->fp) && Jim_Length(objPtr) == 0) {
-        Jim_FreeNewObj(interp, objPtr);
-        if (argc) {
-            Jim_SetResultInt(interp, -1);
-        }
-        return JIM_OK;
-    }
+
     if (argc) {
-        int totLen;
-
-        Jim_GetString(objPtr, &totLen);
         if (Jim_SetVariable(interp, argv[0], objPtr) != JIM_OK) {
             Jim_FreeNewObj(interp, objPtr);
             return JIM_ERR;
         }
-        Jim_SetResultInt(interp, totLen);
+
+        len = Jim_Length(objPtr);
+
+        if (len == 0 && feof(af->fp)) {
+            
+            len = -1;
+        }
+        Jim_SetResultInt(interp, len);
     }
     else {
         Jim_SetResult(interp, objPtr);
     }
     return JIM_OK;
@@ -2376,131 +1919,10 @@
     }
     JimAioSetError(interp, af->filename);
     return JIM_ERR;
 }
 
-#ifndef JIM_ANSIC
-static int aio_cmd_recvfrom(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
-{
-    AioFile *af = Jim_CmdPrivData(interp);
-    char *buf;
-    union sockaddr_any sa;
-    long len;
-    socklen_t salen = sizeof(sa);
-    int rlen;
-
-    if (Jim_GetLong(interp, argv[0], &len) != JIM_OK) {
-        return JIM_ERR;
-    }
-
-    buf = Jim_Alloc(len + 1);
-
-    rlen = recvfrom(fileno(af->fp), buf, len, 0, &sa.sa, &salen);
-    if (rlen < 0) {
-        Jim_Free(buf);
-        JimAioSetError(interp, NULL);
-        return JIM_ERR;
-    }
-    buf[rlen] = 0;
-    Jim_SetResult(interp, Jim_NewStringObjNoAlloc(interp, buf, rlen));
-
-    if (argc > 1) {
-        /* INET6_ADDRSTRLEN is 46. Add some for [] and port */
-        char addrbuf[60];
-
-#if IPV6
-        if (sa.sa.sa_family == PF_INET6) {
-            addrbuf[0] = '[';
-            /* Allow 9 for []:65535\0 */
-            inet_ntop(sa.sa.sa_family, &sa.sin6.sin6_addr, addrbuf + 1, sizeof(addrbuf) - 9);
-            snprintf(addrbuf + strlen(addrbuf), 8, "]:%d", ntohs(sa.sin.sin_port));
-        }
-        else
-#endif
-        {
-            /* Allow 7 for :65535\0 */
-            inet_ntop(sa.sa.sa_family, &sa.sin.sin_addr, addrbuf, sizeof(addrbuf) - 7);
-            snprintf(addrbuf + strlen(addrbuf), 7, ":%d", ntohs(sa.sin.sin_port));
-        }
-
-        if (Jim_SetVariable(interp, argv[1], Jim_NewStringObj(interp, addrbuf, -1)) != JIM_OK) {
-            return JIM_ERR;
-        }
-    }
-
-    return JIM_OK;
-}
-
-
-static int aio_cmd_sendto(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
-{
-    AioFile *af = Jim_CmdPrivData(interp);
-    int wlen;
-    int len;
-    const char *wdata;
-    union sockaddr_any sa;
-    const char *addr = Jim_String(argv[1]);
-    int salen;
-
-    if (IPV6 && af->addr_family == PF_INET6) {
-        if (JimParseIPv6Address(interp, addr, &sa, &salen) != JIM_OK) {
-            return JIM_ERR;
-        }
-    }
-    else if (JimParseIpAddress(interp, addr, &sa, &salen) != JIM_OK) {
-        return JIM_ERR;
-    }
-    wdata = Jim_GetString(argv[0], &wlen);
-
-    /* Note that we don't validate the socket type. Rely on sendto() failing if appropriate */
-    len = sendto(fileno(af->fp), wdata, wlen, 0, &sa.sa, salen);
-    if (len < 0) {
-        JimAioSetError(interp, NULL);
-        return JIM_ERR;
-    }
-    Jim_SetResultInt(interp, len);
-    return JIM_OK;
-}
-
-static int aio_cmd_accept(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
-{
-    AioFile *serv_af = Jim_CmdPrivData(interp);
-    int sock;
-    union sockaddr_any sa;
-    socklen_t addrlen = sizeof(sa);
-    AioFile *af;
-    char buf[AIO_CMD_LEN];
-
-    sock = accept(serv_af->fd, &sa.sa, &addrlen);
-    if (sock < 0)
-        return JIM_ERR;
-
-    /* Create the file command */
-    af = Jim_Alloc(sizeof(*af));
-    af->fd = sock;
-#ifdef FD_CLOEXEC
-    fcntl(af->fd, F_SETFD, FD_CLOEXEC);
-#endif
-    af->filename = Jim_NewStringObj(interp, "accept", -1);
-    Jim_IncrRefCount(af->filename);
-    af->fp = fdopen(sock, "r+");
-
-    af->OpenFlags = 0;
-#ifdef O_NDELAY
-    af->flags = fcntl(af->fd, F_GETFL);
-#endif
-    af->rEvent = NULL;
-    af->wEvent = NULL;
-    af->eEvent = NULL;
-    af->addr_family = serv_af->addr_family;
-    snprintf(buf, sizeof(buf), "aio.sockstream%ld", Jim_GetId(interp));
-    Jim_CreateCommand(interp, buf, JimAioSubCmdProc, af, JimAioDelProc);
-    Jim_SetResultString(interp, buf, -1);
-    return JIM_OK;
-}
-
-#endif
 
 static int aio_cmd_flush(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
 {
     AioFile *af = Jim_CmdPrivData(interp);
 
@@ -2649,31 +2071,31 @@
     int argc, Jim_Obj * const *argv)
 {
     int scriptlen = 0;
 
     if (argc == 0) {
-        /* Return current script */
+        
         if (*scriptHandlerObj) {
             Jim_SetResult(interp, *scriptHandlerObj);
         }
         return JIM_OK;
     }
 
     if (*scriptHandlerObj) {
-        /* Delete old handler */
+        
         Jim_DeleteFileHandler(interp, af->fp);
         *scriptHandlerObj = NULL;
     }
 
-    /* Now possibly add the new script(s) */
+    
     Jim_GetString(argv[0], &scriptlen);
     if (scriptlen == 0) {
-        /* Empty script, so done */
+        
         return JIM_OK;
     }
 
-    /* A new script to add */
+    
     Jim_IncrRefCount(argv[0]);
     *scriptHandlerObj = argv[0];
 
     Jim_CreateFileHandler(interp, af->fp, mask,
         JimAioFileEventHandler, *scriptHandlerObj, JimAioFileEventFinalizer);
@@ -2702,512 +2124,215 @@
     return aio_eventinfo(interp, af, JIM_EVENT_EXCEPTION, &af->wEvent, argc, argv);
 }
 #endif
 
 static const jim_subcmd_type aio_command_table[] = {
-    {   .cmd = "read",
-        .args = "?-nonewline? ?len?",
-        .function = aio_cmd_read,
-        .minargs = 0,
-        .maxargs = 2,
-        .description = "Read and return bytes from the stream. To eof if no len."
-    },
-    {   .cmd = "copyto",
-        .args = "handle ?size?",
-        .function = aio_cmd_copy,
-        .minargs = 1,
-        .maxargs = 2,
-        .description = "Copy up to 'size' bytes to the given filehandle, or to eof if no size."
-    },
-    {   .cmd = "gets",
-        .args = "?var?",
-        .function = aio_cmd_gets,
-        .minargs = 0,
-        .maxargs = 1,
-        .description = "Read one line and return it or store it in the var"
-    },
-    {   .cmd = "puts",
-        .args = "?-nonewline? str",
-        .function = aio_cmd_puts,
-        .minargs = 1,
-        .maxargs = 2,
-        .description = "Write the string, with newline unless -nonewline"
-    },
-#ifndef JIM_ANSIC
-    {   .cmd = "recvfrom",
-        .args = "len ?addrvar?",
-        .function = aio_cmd_recvfrom,
-        .minargs = 1,
-        .maxargs = 2,
-        .description = "Receive up to 'len' bytes on the socket. Sets 'addrvar' with receive address, if set"
-    },
-    {   .cmd = "sendto",
-        .args = "str address",
-        .function = aio_cmd_sendto,
-        .minargs = 2,
-        .maxargs = 2,
-        .description = "Send 'str' to the given address (dgram only)"
-    },
-    {   .cmd = "accept",
-        .function = aio_cmd_accept,
-        .description = "Server socket only: Accept a connection and return stream"
-    },
-#endif
-    {   .cmd = "flush",
-        .function = aio_cmd_flush,
-        .description = "Flush the stream"
-    },
-    {   .cmd = "eof",
-        .function = aio_cmd_eof,
-        .description = "Returns 1 if stream is at eof"
-    },
-    {   .cmd = "close",
-        .flags = JIM_MODFLAG_FULLARGV,
-        .function = aio_cmd_close,
-        .description = "Closes the stream"
-    },
-    {   .cmd = "seek",
-        .args = "offset ?start|current|end",
-        .function = aio_cmd_seek,
-        .minargs = 1,
-        .maxargs = 2,
-        .description = "Seeks in the stream (default 'current')"
-    },
-    {   .cmd = "tell",
-        .function = aio_cmd_tell,
-        .description = "Returns the current seek position"
-    },
-    {   .cmd = "filename",
-        .function = aio_cmd_filename,
-        .description = "Returns the original filename"
+    {   "read",
+        "?-nonewline? ?len?",
+        aio_cmd_read,
+        0,
+        2,
+        
+    },
+    {   "copyto",
+        "handle ?size?",
+        aio_cmd_copy,
+        1,
+        2,
+        
+    },
+    {   "gets",
+        "?var?",
+        aio_cmd_gets,
+        0,
+        1,
+        
+    },
+    {   "puts",
+        "?-nonewline? str",
+        aio_cmd_puts,
+        1,
+        2,
+        
+    },
+    {   "flush",
+        NULL,
+        aio_cmd_flush,
+        0,
+        0,
+        
+    },
+    {   "eof",
+        NULL,
+        aio_cmd_eof,
+        0,
+        0,
+        
+    },
+    {   "close",
+        NULL,
+        aio_cmd_close,
+        0,
+        0,
+        JIM_MODFLAG_FULLARGV,
+        
+    },
+    {   "seek",
+        "offset ?start|current|end",
+        aio_cmd_seek,
+        1,
+        2,
+        
+    },
+    {   "tell",
+        NULL,
+        aio_cmd_tell,
+        0,
+        0,
+        
+    },
+    {   "filename",
+        NULL,
+        aio_cmd_filename,
+        0,
+        0,
+        
     },
 #ifdef O_NDELAY
-    {   .cmd = "ndelay",
-        .args = "?0|1?",
-        .function = aio_cmd_ndelay,
-        .minargs = 0,
-        .maxargs = 1,
-        .description = "Set O_NDELAY (if arg). Returns current/new setting."
+    {   "ndelay",
+        "?0|1?",
+        aio_cmd_ndelay,
+        0,
+        1,
+        
     },
 #endif
-    {   .cmd = "buffering",
-        .args = "none|line|full",
-        .function = aio_cmd_buffering,
-        .minargs = 1,
-        .maxargs = 1,
-        .description = "Sets buffering"
+    {   "buffering",
+        "none|line|full",
+        aio_cmd_buffering,
+        1,
+        1,
+        
     },
 #ifdef jim_ext_eventloop
-    {   .cmd = "readable",
-        .args = "?readable-script?",
-        .minargs = 0,
-        .maxargs = 1,
-        .function = aio_cmd_readable,
-        .description = "Returns script, or invoke readable-script when readable, {} to remove",
-    },
-    {   .cmd = "writable",
-        .args = "?writable-script?",
-        .minargs = 0,
-        .maxargs = 1,
-        .function = aio_cmd_writable,
-        .description = "Returns script, or invoke writable-script when writable, {} to remove",
-    },
-    {   .cmd = "onexception",
-        .args = "?exception-script?",
-        .minargs = 0,
-        .maxargs = 1,
-        .function = aio_cmd_onexception,
-        .description = "Returns script, or invoke exception-script when oob data, {} to remove",
-    },
-#endif
-    { 0 }
+    {   "readable",
+        "?readable-script?",
+        aio_cmd_readable,
+        0,
+        1,
+        
+    },
+    {   "writable",
+        "?writable-script?",
+        aio_cmd_writable,
+        0,
+        1,
+        
+    },
+    {   "onexception",
+        "?exception-script?",
+        aio_cmd_onexception,
+        0,
+        1,
+        
+    },
+#endif
+    { NULL }
 };
 
 static int JimAioSubCmdProc(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
 {
     return Jim_CallSubCmd(interp, Jim_ParseSubCmd(interp, aio_command_table, argc, argv), argc, argv);
 }
 
-static int JimAioOpenCommand(Jim_Interp *interp, int argc, 
+static int JimAioOpenCommand(Jim_Interp *interp, int argc,
         Jim_Obj *const *argv)
 {
-    FILE *fp;
-    AioFile *af;
-    char buf[AIO_CMD_LEN];
-    int OpenFlags = 0;
-    const char *cmdname;
+    const char *mode;
+    const char *filename;
 
     if (argc != 2 && argc != 3) {
         Jim_WrongNumArgs(interp, 1, argv, "filename ?mode?");
         return JIM_ERR;
     }
-    cmdname = Jim_String(argv[1]);
-    if (Jim_CompareStringImmediate(interp, argv[1], "stdin")) {
-        OpenFlags |= AIO_KEEPOPEN;
-        fp = stdin;
-    }
-    else if (Jim_CompareStringImmediate(interp, argv[1], "stdout")) {
-        OpenFlags |= AIO_KEEPOPEN;
-        fp = stdout;
-    }
-    else if (Jim_CompareStringImmediate(interp, argv[1], "stderr")) {
-        OpenFlags |= AIO_KEEPOPEN;
-        fp = stderr;
-    }
-    else {
-        const char *mode = (argc == 3) ? Jim_String(argv[2]) : "r";
-        const char *filename = Jim_String(argv[1]);
+
+    mode = (argc == 3) ? Jim_String(argv[2]) : "r";
+    filename = Jim_String(argv[1]);
 
 #ifdef jim_ext_tclcompat
-        /* If the filename starts with '|', use popen instead */
-        if (*filename == '|') {
-            Jim_Obj *evalObj[3];
-
-            evalObj[0] = Jim_NewStringObj(interp, "popen", -1);
-            evalObj[1] = Jim_NewStringObj(interp, filename + 1, -1);
-            evalObj[2] = Jim_NewStringObj(interp, mode, -1);
-
-            return Jim_EvalObjVector(interp, 3, evalObj);
-        }
-#endif
-        fp = fopen(filename, mode);
-        if (fp == NULL) {
-            JimAioSetError(interp, argv[1]);
-            return JIM_ERR;
-        }
-        /* Get the next file id */
-        snprintf(buf, sizeof(buf), "aio.handle%ld", Jim_GetId(interp));
-        cmdname = buf;
-    }
-
-    /* Create the file command */
+    
+    if (*filename == '|') {
+        Jim_Obj *evalObj[3];
+
+        evalObj[0] = Jim_NewStringObj(interp, "popen", -1);
+        evalObj[1] = Jim_NewStringObj(interp, filename + 1, -1);
+        evalObj[2] = Jim_NewStringObj(interp, mode, -1);
+
+        return Jim_EvalObjVector(interp, 3, evalObj);
+    }
+#endif
+    return JimMakeChannel(interp, NULL, -1, argv[1], "aio.handle%ld", 0, mode);
+}
+
+static int JimMakeChannel(Jim_Interp *interp, FILE *fh, int fd, Jim_Obj *filename,
+    const char *hdlfmt, int family, const char *mode)
+{
+    AioFile *af;
+    char buf[AIO_CMD_LEN];
+    int OpenFlags = 0;
+
+    if (filename == NULL) {
+        filename = Jim_NewStringObj(interp, hdlfmt, -1);
+    }
+
+    Jim_IncrRefCount(filename);
+
+    if (fh == NULL) {
+        if (fd < 0) {
+            fh = fopen(Jim_String(filename), mode);
+        }
+        else {
+            fh = fdopen(fd, mode);
+        }
+    }
+    else {
+        OpenFlags = AIO_KEEPOPEN;
+    }
+
+    if (fh == NULL) {
+        JimAioSetError(interp, filename);
+        if (fd >= 0) {
+            close(fd);
+        }
+        Jim_DecrRefCount(interp, filename);
+        return JIM_ERR;
+    }
+
+    
     af = Jim_Alloc(sizeof(*af));
-    af->fp = fp;
-    af->fd = fileno(fp);
+    memset(af, 0, sizeof(*af));
+    af->fp = fh;
+    af->fd = fileno(fh);
+    af->filename = filename;
 #ifdef FD_CLOEXEC
     if ((OpenFlags & AIO_KEEPOPEN) == 0) {
         fcntl(af->fd, F_SETFD, FD_CLOEXEC);
     }
 #endif
+    af->OpenFlags = OpenFlags;
 #ifdef O_NDELAY
     af->flags = fcntl(af->fd, F_GETFL);
 #endif
-    af->filename = argv[1];
-    Jim_IncrRefCount(af->filename);
-    af->OpenFlags = OpenFlags;
-    af->rEvent = NULL;
-    af->wEvent = NULL;
-    af->eEvent = NULL;
-    Jim_CreateCommand(interp, cmdname, JimAioSubCmdProc, af, JimAioDelProc);
-    Jim_SetResultString(interp, cmdname, -1);
-    return JIM_OK;
-}
-
-#ifndef JIM_ANSIC
-
-/**
- * Creates a channel for fd.
- * 
- * hdlfmt is a sprintf format for the filehandle. Anything with %ld at the end will do.
- * mode is usual "r+", but may be another fdopen() mode as required.
- *
- * Creates the command and lappends the name of the command to the current result.
- *
- */
-static int JimMakeChannel(Jim_Interp *interp, Jim_Obj *filename, const char *hdlfmt, int fd, int family,
-    const char *mode)
-{
-    AioFile *af;
-    char buf[AIO_CMD_LEN];
-
-    FILE *fp = fdopen(fd, mode);
-
-    if (fp == NULL) {
-        close(fd);
-        JimAioSetError(interp, NULL);
-        return JIM_ERR;
-    }
-
-    /* Create the file command */
-    af = Jim_Alloc(sizeof(*af));
-    af->fp = fp;
-    af->fd = fd;
-    fcntl(af->fd, F_SETFD, FD_CLOEXEC);
-    af->OpenFlags = 0;
-    af->filename = filename;
-    Jim_IncrRefCount(af->filename);
-#ifdef O_NDELAY
-    af->flags = fcntl(af->fd, F_GETFL);
-#endif
-    af->rEvent = NULL;
-    af->wEvent = NULL;
-    af->eEvent = NULL;
     af->addr_family = family;
     snprintf(buf, sizeof(buf), hdlfmt, Jim_GetId(interp));
     Jim_CreateCommand(interp, buf, JimAioSubCmdProc, af, JimAioDelProc);
 
-    Jim_ListAppendElement(interp, Jim_GetResult(interp), Jim_NewStringObj(interp, buf, -1));
-
-    return JIM_OK;
-}
-
-static int JimAioSockCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
-{
-    const char *hdlfmt = "aio.unknown%ld";
-    const char *socktypes[] = {
-        "unix",
-        "unix.server",
-        "dgram",
-        "dgram.server",
-        "stream",
-        "stream.server",
-        "pipe",
-        NULL
-    };
-    enum
-    {
-        SOCK_UNIX,
-        SOCK_UNIX_SERVER,
-        SOCK_DGRAM_CLIENT,
-        SOCK_DGRAM_SERVER,
-        SOCK_STREAM_CLIENT,
-        SOCK_STREAM_SERVER,
-        SOCK_STREAM_PIPE,
-        SOCK_DGRAM6_CLIENT,
-        SOCK_DGRAM6_SERVER,
-        SOCK_STREAM6_CLIENT,
-        SOCK_STREAM6_SERVER,
-    };
-    int socktype;
-    int sock;
-    const char *hostportarg = NULL;
-    int res;
-    int on = 1;
-    const char *mode = "r+";
-    int family = PF_INET;
-    Jim_Obj *argv0 = argv[0];
-    int ipv6 = 0;
-
-    if (argc > 1 && Jim_CompareStringImmediate(interp, argv[1], "-ipv6")) {
-        if (!IPV6) {
-            Jim_SetResultString(interp, "ipv6 not supported", -1);
-            return JIM_ERR;
-        }
-        ipv6 = 1;
-        family = PF_INET6;
-    }
-    argc -= ipv6;
-    argv += ipv6;
-
-    if (argc < 2) {
-      wrongargs:
-        Jim_WrongNumArgs(interp, 1, &argv0, "?-ipv6? type ?address?");
-        return JIM_ERR;
-    }
-
-    if (Jim_GetEnum(interp, argv[1], socktypes, &socktype, "socket type", JIM_ERRMSG) != JIM_OK)
-        return JIM_ERR;
-
-    Jim_SetResultString(interp, "", 0);
-
-    hdlfmt = "aio.sock%ld";
-
-    if (argc > 2) {
-        hostportarg = Jim_String(argv[2]);
-    }
-
-    switch (socktype) {
-        case SOCK_DGRAM_CLIENT:
-            if (argc == 2) {
-                /* No address, so an unconnected dgram socket */
-                sock = socket(family, SOCK_DGRAM, 0);
-                if (sock < 0) {
-                    JimAioSetError(interp, NULL);
-                    return JIM_ERR;
-                }
-                break;
-            }
-            /* fall through */
-        case SOCK_STREAM_CLIENT:
-            {
-                union sockaddr_any sa;
-                int salen;
-
-                if (argc != 3) {
-                    goto wrongargs;
-                }
-
-                if (ipv6) {
-                    if (JimParseIPv6Address(interp, hostportarg, &sa, &salen) != JIM_OK) {
-                        return JIM_ERR;
-                    }
-                }
-                else if (JimParseIpAddress(interp, hostportarg, &sa, &salen) != JIM_OK) {
-                    return JIM_ERR;
-                }
-                sock = socket(family, (socktype == SOCK_DGRAM_CLIENT) ? SOCK_DGRAM : SOCK_STREAM, 0);
-                if (sock < 0) {
-                    JimAioSetError(interp, NULL);
-                    return JIM_ERR;
-                }
-                res = connect(sock, &sa.sa, salen);
-                if (res) {
-                    JimAioSetError(interp, argv[2]);
-                    close(sock);
-                    return JIM_ERR;
-                }
-            }
-            break;
-
-        case SOCK_STREAM_SERVER:
-        case SOCK_DGRAM_SERVER:
-            {
-                union sockaddr_any sa;
-                int salen;
-
-                if (argc != 3) {
-                    goto wrongargs;
-                }
-
-                if (ipv6) {
-                    if (JimParseIPv6Address(interp, hostportarg, &sa, &salen) != JIM_OK) {
-                        return JIM_ERR;
-                    }
-                }
-                else if (JimParseIpAddress(interp, hostportarg, &sa, &salen) != JIM_OK) {
-                    return JIM_ERR;
-                }
-                sock = socket(family, (socktype == SOCK_DGRAM_SERVER) ? SOCK_DGRAM : SOCK_STREAM, 0);
-                if (sock < 0) {
-                    JimAioSetError(interp, NULL);
-                    return JIM_ERR;
-                }
-
-                /* Enable address reuse */
-                setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *)&on, sizeof(on));
-
-                res = bind(sock, &sa.sa, salen);
-                if (res) {
-                    JimAioSetError(interp, argv[2]);
-                    close(sock);
-                    return JIM_ERR;
-                }
-                if (socktype == SOCK_STREAM_SERVER) {
-                    res = listen(sock, 5);
-                    if (res) {
-                        JimAioSetError(interp, NULL);
-                        close(sock);
-                        return JIM_ERR;
-                    }
-                }
-                hdlfmt = "aio.socksrv%ld";
-            }
-            break;
-
-#ifdef HAVE_SYS_UN_H
-        case SOCK_UNIX:
-            {
-                struct sockaddr_un sa;
-                socklen_t len;
-
-                if (argc != 3 || ipv6) {
-                    goto wrongargs;
-                }
-
-                if (JimParseDomainAddress(interp, hostportarg, &sa) != JIM_OK) {
-                    JimAioSetError(interp, argv[2]);
-                    return JIM_ERR;
-                }
-                family = PF_UNIX;
-                sock = socket(PF_UNIX, SOCK_STREAM, 0);
-                if (sock < 0) {
-                    JimAioSetError(interp, NULL);
-                    return JIM_ERR;
-                }
-                len = strlen(sa.sun_path) + 1 + sizeof(sa.sun_family);
-                res = connect(sock, (struct sockaddr *)&sa, len);
-                if (res) {
-                    JimAioSetError(interp, argv[2]);
-                    close(sock);
-                    return JIM_ERR;
-                }
-                hdlfmt = "aio.sockunix%ld";
-                break;
-            }
-
-        case SOCK_UNIX_SERVER:
-            {
-                struct sockaddr_un sa;
-                socklen_t len;
-
-                if (argc != 3 || ipv6) {
-                    goto wrongargs;
-                }
-
-                if (JimParseDomainAddress(interp, hostportarg, &sa) != JIM_OK) {
-                    JimAioSetError(interp, argv[2]);
-                    return JIM_ERR;
-                }
-                family = PF_UNIX;
-                sock = socket(PF_UNIX, SOCK_STREAM, 0);
-                if (sock < 0) {
-                    JimAioSetError(interp, NULL);
-                    return JIM_ERR;
-                }
-                len = strlen(sa.sun_path) + 1 + sizeof(sa.sun_family);
-                res = bind(sock, (struct sockaddr *)&sa, len);
-                if (res) {
-                    JimAioSetError(interp, argv[2]);
-                    close(sock);
-                    return JIM_ERR;
-                }
-                res = listen(sock, 5);
-                if (res) {
-                    JimAioSetError(interp, NULL);
-                    close(sock);
-                    return JIM_ERR;
-                }
-                hdlfmt = "aio.sockunixsrv%ld";
-                break;
-            }
-#endif
-
-#ifdef HAVE_PIPE
-        case SOCK_STREAM_PIPE:
-            {
-                int p[2];
-
-                if (argc != 2 || ipv6) {
-                    goto wrongargs;
-                }
-
-                if (pipe(p) < 0) {
-                    JimAioSetError(interp, NULL);
-                    return JIM_ERR;
-                }
-
-                hdlfmt = "aio.pipe%ld";
-                if (JimMakeChannel(interp, argv[1], hdlfmt, p[0], family, "r") != JIM_OK) {
-                    close(p[0]);
-                    close(p[1]);
-                    JimAioSetError(interp, NULL);
-                    return JIM_ERR;
-                }
-                /* Note, if this fails it will leave p[0] open, but this should never happen */
-                mode = "w";
-                sock = p[1];
-            }
-            break;
-#endif
-        default:
-            Jim_SetResultString(interp, "Unsupported socket type", -1);
-            return JIM_ERR;
-    }
-
-    return JimMakeChannel(interp, argv[1], hdlfmt, sock, family, mode);
-}
-#endif
+    Jim_SetResultString(interp, buf, -1);
+
+    return JIM_OK;
+}
+
 
 FILE *Jim_AioFilehandle(Jim_Interp *interp, Jim_Obj *command)
 {
     Jim_Cmd *cmdPtr = Jim_GetCommand(interp, command, JIM_ERRMSG);
 
@@ -3226,79 +2351,28 @@
     Jim_CreateCommand(interp, "open", JimAioOpenCommand, NULL, NULL);
 #ifndef JIM_ANSIC
     Jim_CreateCommand(interp, "socket", JimAioSockCommand, NULL, NULL);
 #endif
 
-    /* Takeover stdin, stdout and stderr */
-    Jim_EvalGlobal(interp, "open stdin; open stdout; open stderr");
-
-    return JIM_OK;
-}
-
-/*
- * Tcl readdir command.
- *
- * (c) 2008 Steve Bennett <steveb@worware.net.au>
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above
- *    copyright notice, this list of conditions and the following
- *    disclaimer in the documentation and/or other materials
- *    provided with the distribution.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE JIM TCL PROJECT ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
- * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * JIM TCL PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
- * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- * 
- * The views and conclusions contained in the software and documentation
- * are those of the authors and should not be interpreted as representing
- * official policies, either expressed or implied, of the Jim Tcl Project.
- *
- * Based on original work by:
- *-----------------------------------------------------------------------------
- * Copyright 1991-1994 Karl Lehenbauer and Mark Diekhans.
- *
- * Permission to use, copy, modify, and distribute this software and its
- * documentation for any purpose and without fee is hereby granted, provided
- * that the above copyright notice appear in all copies.  Karl Lehenbauer and
- * Mark Diekhans make no representations about the suitability of this
- * software for any purpose.  It is provided "as is" without express or
- * implied warranty.
- *-----------------------------------------------------------------------------
- */
+    
+    JimMakeChannel(interp, stdin, -1, NULL, "stdin", 0, "r");
+    JimMakeChannel(interp, stdout, -1, NULL, "stdout", 0, "w");
+    JimMakeChannel(interp, stderr, -1, NULL, "stderr", 0, "w");
+
+    return JIM_OK;
+}
+
 
 #include <errno.h>
 #include <stdio.h>
 #include <string.h>
+
+
+#ifdef HAVE_DIRENT_H
 #include <dirent.h>
+#endif
 
-
-/*
- *-----------------------------------------------------------------------------
- *
- * Jim_ReaddirCmd --
- *     Implements the rename TCL command:
- *         readdir ?-nocomplain? dirPath
- *
- * Results:
- *      Standard TCL result.
- *-----------------------------------------------------------------------------
- */
 int Jim_ReaddirCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
 {
     const char *dirPath;
     DIR *dirPtr;
     struct dirent *entryPtr;
@@ -3348,56 +2422,10 @@
         return JIM_ERR;
 
     Jim_CreateCommand(interp, "readdir", Jim_ReaddirCmd, NULL, NULL);
     return JIM_OK;
 }
-/* 
- * Implements the regexp and regsub commands for Jim
- *
- * (c) 2008 Steve Bennett <steveb@workware.net.au>
- *
- * Uses C library regcomp()/regexec() for the matching.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above
- *    copyright notice, this list of conditions and the following
- *    disclaimer in the documentation and/or other materials
- *    provided with the distribution.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE JIM TCL PROJECT ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
- * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * JIM TCL PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
- * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- * 
- * The views and conclusions contained in the software and documentation
- * are those of the authors and should not be interpreted as representing
- * official policies, either expressed or implied, of the Jim Tcl Project.
- *
- * Based on code originally from Tcl 6.7:
- *
- * Copyright 1987-1991 Regents of the University of California
- * Permission to use, copy, modify, and distribute this
- * software and its documentation for any purpose and without
- * fee is hereby granted, provided that the above copyright
- * notice appear in all copies.  The University of California
- * makes no representations about the suitability of this
- * software for any purpose.  It is provided "as is" without
- * express or implied warranty.
- */
 
 #include <stdlib.h>
 #include <string.h>
 
 
@@ -3419,24 +2447,20 @@
 {
     regex_t *compre;
     const char *pattern;
     int ret;
 
-    /* Check if the object is already an uptodate variable */
+    
     if (objPtr->typePtr == &regexpObjType &&
         objPtr->internalRep.regexpValue.compre && objPtr->internalRep.regexpValue.flags == flags) {
-        /* nothing to do */
+        
         return objPtr->internalRep.regexpValue.compre;
     }
 
-    /* Not a regexp or the flags do not match */
-    if (objPtr->typePtr == &regexpObjType) {
-        FreeRegexpInternalRep(interp, objPtr);
-        objPtr->typePtr = NULL;
-    }
+    
 
-    /* Get the string representation */
+    
     pattern = Jim_String(objPtr);
     compre = Jim_Alloc(sizeof(regex_t));
 
     if ((ret = regcomp(compre, pattern, REG_EXTENDED | flags)) != 0) {
         char buf[100];
@@ -3445,10 +2469,12 @@
         Jim_SetResultFormatted(interp, "couldn't compile regular expression pattern: %s", buf);
         regfree(compre);
         Jim_Free(compre);
         return NULL;
     }
+
+    Jim_FreeIntRep(interp, objPtr);
 
     objPtr->typePtr = &regexpObjType;
     objPtr->internalRep.regexpValue.flags = flags;
     objPtr->internalRep.regexpValue.compre = compre;
 
@@ -3556,13 +2582,10 @@
         num_vars = regex->re_nsub + 1;
     }
 
     pmatch = Jim_Alloc((num_vars + 1) * sizeof(*pmatch));
 
-    /* If an offset has been specified, adjust for that now.
-     * If it points past the end of the string, point to the terminating null
-     */
     if (offset) {
         if (offset < 0) {
             offset += source_len + 1;
         }
         if (offset > source_len) {
@@ -3594,18 +2617,14 @@
     }
 
     num_matches++;
 
     if (opt_all && !opt_inline) {
-        /* Just count the number of matches, so skip the substitution h */
+        
         goto try_next_match;
     }
 
-    /*
-     * If additional variable names have been specified, return
-     * index information in those variables.
-     */
 
     j = 0;
     for (i += 2; opt_inline ? j < num_vars : i < argc; i++, j++) {
         Jim_Obj *resultObj;
 
@@ -3638,11 +2657,11 @@
 
         if (opt_inline) {
             Jim_ListAppendElement(interp, resultListObj, resultObj);
         }
         else {
-            /* And now set the result variable */
+            
             result = Jim_SetVariable(interp, argv[i], resultObj);
 
             if (result != JIM_OK) {
                 Jim_FreeObj(interp, resultObj);
                 break;
@@ -3765,16 +2784,13 @@
 
     source_str = Jim_GetString(argv[i + 1], &source_len);
     replace_str = Jim_GetString(argv[i + 2], &replace_len);
     varname = argv[i + 3];
 
-    /* Create the result string */
+    
     resultObj = Jim_NewStringObj(interp, "", 0);
 
-    /* If an offset has been specified, adjust for that now.
-     * If it points past the end of the string, point to the terminating null
-     */
     if (offset) {
         if (offset < 0) {
             offset += source_len + 1;
         }
         if (offset > source_len) {
@@ -3783,19 +2799,13 @@
         else if (offset < 0) {
             offset = 0;
         }
     }
 
-    /* Copy the part before -start */
+    
     Jim_AppendString(interp, resultObj, source_str, offset);
 
-    /*
-     * The following loop is to handle multiple matches within the
-     * same source string;  each iteration handles one match and its
-     * corresponding substitution.  If "-all" hasn't been specified
-     * then the loop body only gets executed once.
-     */
 
     n = source_len - offset;
     p = source_str + offset;
     do {
         int match = regexec(regex, p, MAX_SUB_MATCHES, pmatch, regexec_flags);
@@ -3811,22 +2821,12 @@
             break;
         }
 
         num_matches++;
 
-        /*
-         * Copy the portion of the source string before the match to the
-         * result variable.
-         */
         Jim_AppendString(interp, resultObj, p, pmatch[0].rm_so);
 
-        /*
-         * Append the subSpec (replace_str) argument to the variable, making appropriate
-         * substitutions.  This code is a bit hairy because of the backslash
-         * conventions and because the code saves up ranges of characters in
-         * subSpec to reduce the number of calls to Jim_SetVar.
-         */
 
         for (j = 0; j < replace_len; j++) {
             int idx;
             int c = replace_str[j];
 
@@ -3858,38 +2858,34 @@
         }
 
         p += pmatch[0].rm_eo;
         n -= pmatch[0].rm_eo;
 
-        /* If -all is not specified, or there is no source left, we are done */
+        
         if (!opt_all || n == 0) {
             break;
         }
 
-        /* An anchored pattern without -line must be done */
+        
         if ((regcomp_flags & REG_NEWLINE) == 0 && pattern[0] == '^') {
             break;
         }
 
-        /* If the pattern is empty, need to step forwards */
+        
         if (pattern[0] == '\0' && n) {
-            /* Need to copy the char we are moving over */
+            
             Jim_AppendString(interp, resultObj, p, 1);
             p++;
             n--;
         }
-        
+
         regexec_flags |= REG_NOTBOL;
     } while (n);
 
-    /*
-     * Copy the portion of the string after the last match to the
-     * result variable.
-     */
     Jim_AppendString(interp, resultObj, p, -1);
 
-    /* And now set or return the result variable */
+    
     if (argc - i == 4) {
         result = Jim_SetVariable(interp, varname, resultObj);
 
         if (result == JIM_OK) {
             Jim_SetResultInt(interp, num_matches);
@@ -3913,142 +2909,82 @@
 
     Jim_CreateCommand(interp, "regexp", Jim_RegexpCmd, NULL, NULL);
     Jim_CreateCommand(interp, "regsub", Jim_RegsubCmd, NULL, NULL);
     return JIM_OK;
 }
-/* 
- * Implements the file command for jim
- *
- * (c) 2008 Steve Bennett <steveb@workware.net.au>
- * 
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above
- *    copyright notice, this list of conditions and the following
- *    disclaimer in the documentation and/or other materials
- *    provided with the distribution.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE JIM TCL PROJECT ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
- * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * JIM TCL PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
- * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- * 
- * The views and conclusions contained in the software and documentation
- * are those of the authors and should not be interpreted as representing
- * official policies, either expressed or implied, of the Jim Tcl Project.
- *
- * Based on code originally from Tcl 6.7:
- *
- * Copyright 1987-1991 Regents of the University of California
- * Permission to use, copy, modify, and distribute this
- * software and its documentation for any purpose and without
- * fee is hereby granted, provided that the above copyright
- * notice appear in all copies.  The University of California
- * makes no representations about the suitability of this
- * software for any purpose.  It is provided "as is" without
- * express or implied warranty.
- */
 
 #include <limits.h>
 #include <stdlib.h>
 #include <string.h>
 #include <stdio.h>
-#include <unistd.h>
 #include <errno.h>
 #include <sys/stat.h>
-#include <sys/param.h>
 
+
+#ifdef HAVE_UTIMES
+#include <sys/time.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#elif defined(_MSC_VER)
+#include <direct.h>
+#define F_OK 0
+#define W_OK 2
+#define R_OK 4
+#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
+#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
+#endif
 
 # ifndef MAXPATHLEN
 # define MAXPATHLEN JIM_PATH_LEN
 # endif
 
-/*
- *----------------------------------------------------------------------
- *
- * JimGetFileType --
- *
- *  Given a mode word, returns a string identifying the type of a
- *  file.
- *
- * Results:
- *  A static text string giving the file type from mode.
- *
- * Side effects:
- *  None.
- *
- *----------------------------------------------------------------------
- */
 
 static const char *JimGetFileType(int mode)
 {
     if (S_ISREG(mode)) {
         return "file";
     }
     else if (S_ISDIR(mode)) {
         return "directory";
     }
+#ifdef S_ISCHR
     else if (S_ISCHR(mode)) {
         return "characterSpecial";
     }
+#endif
+#ifdef S_ISBLK
     else if (S_ISBLK(mode)) {
         return "blockSpecial";
     }
+#endif
+#ifdef S_ISFIFO
     else if (S_ISFIFO(mode)) {
         return "fifo";
+    }
+#endif
 #ifdef S_ISLNK
-    }
     else if (S_ISLNK(mode)) {
         return "link";
+    }
 #endif
 #ifdef S_ISSOCK
-    }
     else if (S_ISSOCK(mode)) {
         return "socket";
+    }
 #endif
-    }
     return "unknown";
 }
 
-/*
- *----------------------------------------------------------------------
- *
- * StoreStatData --
- *
- *  This is a utility procedure that breaks out the fields of a
- *  "stat" structure and stores them in textual form into the
- *  elements of an associative array.
- *
- * Results:
- *  Returns a standard Tcl return value.  If an error occurs then
- *  a message is left in interp->result.
- *
- * Side effects:
- *  Elements of the associative array given by "varName" are modified.
- *
- *----------------------------------------------------------------------
- */
 
 static int set_array_int_value(Jim_Interp *interp, Jim_Obj *container, const char *key,
     jim_wide value)
 {
     Jim_Obj *nameobj = Jim_NewStringObj(interp, key, -1);
     Jim_Obj *valobj = Jim_NewWideObj(interp, value);
 
-    if (Jim_SetDictKeysVector(interp, container, &nameobj, 1, valobj) != JIM_OK) {
+    if (Jim_SetDictKeysVector(interp, container, &nameobj, 1, valobj, JIM_ERRMSG) != JIM_OK) {
         Jim_FreeObj(interp, nameobj);
         Jim_FreeObj(interp, valobj);
         return JIM_ERR;
     }
     return JIM_OK;
@@ -4058,11 +2994,11 @@
     const char *value)
 {
     Jim_Obj *nameobj = Jim_NewStringObj(interp, key, -1);
     Jim_Obj *valobj = Jim_NewStringObj(interp, value, -1);
 
-    if (Jim_SetDictKeysVector(interp, container, &nameobj, 1, valobj) != JIM_OK) {
+    if (Jim_SetDictKeysVector(interp, container, &nameobj, 1, valobj, JIM_ERRMSG) != JIM_OK) {
         Jim_FreeObj(interp, nameobj);
         Jim_FreeObj(interp, valobj);
         return JIM_ERR;
     }
     return JIM_OK;
@@ -4083,11 +3019,11 @@
     set_array_int_value(interp, varName, "atime", sb->st_atime);
     set_array_int_value(interp, varName, "mtime", sb->st_mtime);
     set_array_int_value(interp, varName, "ctime", sb->st_ctime);
     set_array_string_value(interp, varName, "type", JimGetFileType((int)sb->st_mode));
 
-    /* And also return the value */
+    
     Jim_SetResult(interp, Jim_GetVariable(interp, varName, 0));
 
     return JIM_OK;
 }
 
@@ -4100,13 +3036,13 @@
         Jim_SetResultString(interp, ".", -1);
     }
     else if (p == path) {
         Jim_SetResultString(interp, "/", -1);
     }
-#if defined(__MINGW32__)
+#if defined(__MINGW32__) || defined(_MSC_VER)
     else if (p[-1] == ':') {
-        /* z:/dir => z:/ */
+        
         Jim_SetResultString(interp, path, p - path + 1);
     }
 #endif
     else {
         Jim_SetResultString(interp, path, p - path);
@@ -4182,37 +3118,37 @@
     char *newname = Jim_Alloc(MAXPATHLEN + 1);
     char *last = newname;
 
     *newname = 0;
 
-    /* Simple implementation for now */
+    
     for (i = 0; i < argc; i++) {
         int len;
         const char *part = Jim_GetString(argv[i], &len);
 
         if (*part == '/') {
-            /* Absolute component, so go back to the start */
+            
             last = newname;
         }
-#if defined(__MINGW32__)
+#if defined(__MINGW32__) || defined(_MSC_VER)
         else if (strchr(part, ':')) {
-            /* Absolute compontent on mingw, so go back to the start */
+            
             last = newname;
         }
 #endif
         else if (part[0] == '.') {
             if (part[1] == '/') {
                 part += 2;
                 len -= 2;
             }
             else if (part[1] == 0 && last != newname) {
-                /* Adding '.' to an existing path does nothing */
+                
                 continue;
             }
         }
 
-        /* Add a slash if needed */
+        
         if (last != newname && last[-1] != '/') {
             *last++ = '/';
         }
 
         if (len) {
@@ -4223,19 +3159,19 @@
             }
             memcpy(last, part, len);
             last += len;
         }
 
-        /* Remove a slash if needed */
+        
         if (last > newname + 1 && last[-1] == '/') {
             *--last = 0;
         }
     }
 
     *last = 0;
 
-    /* Probably need to handle some special cases ... */
+    
 
     Jim_SetResult(interp, Jim_NewStringObjNoAlloc(interp, newname, last - newname));
 
     return JIM_OK;
 }
@@ -4260,11 +3196,16 @@
     return file_access(interp, argv[0], W_OK);
 }
 
 static int file_cmd_executable(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
 {
+#ifdef X_OK
     return file_access(interp, argv[0], X_OK);
+#else
+    Jim_SetResultBool(interp, 1);
+    return JIM_OK;
+#endif
 }
 
 static int file_cmd_exists(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
 {
     return file_access(interp, argv[0], F_OK);
@@ -4282,12 +3223,12 @@
     while (argc--) {
         const char *path = Jim_String(argv[0]);
 
         if (unlink(path) == -1 && errno != ENOENT) {
             if (rmdir(path) == -1) {
-                /* Maybe try using the script helper */
-                if (!force || Jim_EvalObjPrefix(interp, "file delete force", 1, argv) != JIM_OK) {
+                
+                if (!force || Jim_EvalPrefix(interp, "file delete force", 1, argv) != JIM_OK) {
                     Jim_SetResultFormatted(interp, "couldn't delete file \"%s\": %s", path,
                         strerror(errno));
                     return JIM_ERR;
                 }
             }
@@ -4301,26 +3242,19 @@
 #define MKDIR_DEFAULT(PATHNAME) mkdir(PATHNAME)
 #else
 #define MKDIR_DEFAULT(PATHNAME) mkdir(PATHNAME, 0755)
 #endif
 
-/**
- * Create directory, creating all intermediate paths if necessary.
- *
- * Returns 0 if OK or -1 on failure (and sets errno)
- *
- * Note: The path may be modified.
- */
 static int mkdir_all(char *path)
 {
     int ok = 1;
 
-    /* First time just try to make the dir */
+    
     goto first;
 
     while (ok--) {
-        /* Must have failed the first time, so recursively make the parent and try again */
+        
         char *slash = strrchr(path, '/');
 
         if (slash && slash != path) {
             *slash = 0;
             if (mkdir_all(path) != 0) {
@@ -4331,24 +3265,24 @@
       first:
         if (MKDIR_DEFAULT(path) == 0) {
             return 0;
         }
         if (errno == ENOENT) {
-            /* Create the parent and try again */
+            
             continue;
         }
-        /* Maybe it already exists as a directory */
+        
         if (errno == EEXIST) {
             struct stat sb;
 
             if (stat(path, &sb) == 0 && S_ISDIR(sb.st_mode)) {
                 return 0;
             }
-            /* Restore errno */
+            
             errno = EEXIST;
         }
-        /* Failed */
+        
         break;
     }
     return -1;
 }
 
@@ -4465,20 +3399,41 @@
 
 static int file_cmd_mtime(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
 {
     struct stat sb;
 
+    if (argc == 2) {
+#ifdef HAVE_UTIMES
+        jim_wide newtime;
+        struct timeval times[2];
+
+        if (Jim_GetWide(interp, argv[1], &newtime) != JIM_OK) {
+            return JIM_ERR;
+        }
+
+        times[1].tv_sec = times[0].tv_sec = newtime;
+        times[1].tv_usec = times[0].tv_usec = 0;
+
+        if (utimes(Jim_String(argv[0]), times) != 0) {
+            Jim_SetResultFormatted(interp, "can't set time on \"%#s\": %s", argv[0], strerror(errno));
+            return JIM_ERR;
+        }
+#else
+        Jim_SetResultString(interp, "Not implemented", -1);
+        return JIM_ERR;
+#endif
+    }
     if (file_stat(interp, argv[0], &sb) != JIM_OK) {
         return JIM_ERR;
     }
     Jim_SetResultInt(interp, sb.st_mtime);
     return JIM_OK;
 }
 
 static int file_cmd_copy(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
 {
-    return Jim_EvalObjPrefix(interp, "file copy", argc, argv);
+    return Jim_EvalPrefix(interp, "file copy", argc, argv);
 }
 
 static int file_cmd_size(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
 {
     struct stat sb;
@@ -4536,11 +3491,11 @@
 
     int linkLength = readlink(path, linkValue, MAXPATHLEN);
 
     if (linkLength == -1) {
         Jim_Free(linkValue);
-        Jim_SetResultFormatted(interp, "couldn't readlink \"%s\": %s", argv[0], strerror(errno));
+        Jim_SetResultFormatted(interp, "couldn't readlink \"%#s\": %s", argv[0], strerror(errno));
         return JIM_ERR;
     }
     linkValue[linkLength] = 0;
     Jim_SetResult(interp, Jim_NewStringObjNoAlloc(interp, linkValue, linkLength));
     return JIM_OK;
@@ -4577,193 +3532,193 @@
     }
     return StoreStatData(interp, argv[1], &sb);
 }
 
 static const jim_subcmd_type file_command_table[] = {
-    {   .cmd = "atime",
-        .args = "name",
-        .function = file_cmd_atime,
-        .minargs = 1,
-        .maxargs = 1,
-        .description = "Last access time"
-    },
-    {   .cmd = "mtime",
-        .args = "name",
-        .function = file_cmd_mtime,
-        .minargs = 1,
-        .maxargs = 1,
-        .description = "Last modification time"
-    },
-    {   .cmd = "copy",
-        .args = "?-force? source dest",
-        .function = file_cmd_copy,
-        .minargs = 2,
-        .maxargs = 3,
-        .description = "Copy source file to destination file"
-    },
-    {   .cmd = "dirname",
-        .args = "name",
-        .function = file_cmd_dirname,
-        .minargs = 1,
-        .maxargs = 1,
-        .description = "Directory part of the name"
-    },
-    {   .cmd = "rootname",
-        .args = "name",
-        .function = file_cmd_rootname,
-        .minargs = 1,
-        .maxargs = 1,
-        .description = "Name without any extension"
-    },
-    {   .cmd = "extension",
-        .args = "name",
-        .function = file_cmd_extension,
-        .minargs = 1,
-        .maxargs = 1,
-        .description = "Last extension including the dot"
-    },
-    {   .cmd = "tail",
-        .args = "name",
-        .function = file_cmd_tail,
-        .minargs = 1,
-        .maxargs = 1,
-        .description = "Last component of the name"
-    },
-    {   .cmd = "normalize",
-        .args = "name",
-        .function = file_cmd_normalize,
-        .minargs = 1,
-        .maxargs = 1,
-        .description = "Normalized path of name"
-    },
-    {   .cmd = "join",
-        .args = "name ?name ...?",
-        .function = file_cmd_join,
-        .minargs = 1,
-        .maxargs = -1,
-        .description = "Join multiple path components"
-    },
-    {   .cmd = "readable",
-        .args = "name",
-        .function = file_cmd_readable,
-        .minargs = 1,
-        .maxargs = 1,
-        .description = "Is file readable"
-    },
-    {   .cmd = "writable",
-        .args = "name",
-        .function = file_cmd_writable,
-        .minargs = 1,
-        .maxargs = 1,
-        .description = "Is file writable"
-    },
-    {   .cmd = "executable",
-        .args = "name",
-        .function = file_cmd_executable,
-        .minargs = 1,
-        .maxargs = 1,
-        .description = "Is file executable"
-    },
-    {   .cmd = "exists",
-        .args = "name",
-        .function = file_cmd_exists,
-        .minargs = 1,
-        .maxargs = 1,
-        .description = "Does file exist"
-    },
-    {   .cmd = "delete",
-        .args = "?-force|--? name ...",
-        .function = file_cmd_delete,
-        .minargs = 1,
-        .maxargs = -1,
-        .description = "Deletes the files or directories (must be empty unless -force)"
-    },
-    {   .cmd = "mkdir",
-        .args = "dir ...",
-        .function = file_cmd_mkdir,
-        .minargs = 1,
-        .maxargs = -1,
-        .description = "Creates the directories"
+    {   "atime",
+        "name",
+        file_cmd_atime,
+        1,
+        1,
+        
+    },
+    {   "mtime",
+        "name ?time?",
+        file_cmd_mtime,
+        1,
+        2,
+        
+    },
+    {   "copy",
+        "?-force? source dest",
+        file_cmd_copy,
+        2,
+        3,
+        
+    },
+    {   "dirname",
+        "name",
+        file_cmd_dirname,
+        1,
+        1,
+        
+    },
+    {   "rootname",
+        "name",
+        file_cmd_rootname,
+        1,
+        1,
+        
+    },
+    {   "extension",
+        "name",
+        file_cmd_extension,
+        1,
+        1,
+        
+    },
+    {   "tail",
+        "name",
+        file_cmd_tail,
+        1,
+        1,
+        
+    },
+    {   "normalize",
+        "name",
+        file_cmd_normalize,
+        1,
+        1,
+        
+    },
+    {   "join",
+        "name ?name ...?",
+        file_cmd_join,
+        1,
+        -1,
+        
+    },
+    {   "readable",
+        "name",
+        file_cmd_readable,
+        1,
+        1,
+        
+    },
+    {   "writable",
+        "name",
+        file_cmd_writable,
+        1,
+        1,
+        
+    },
+    {   "executable",
+        "name",
+        file_cmd_executable,
+        1,
+        1,
+        
+    },
+    {   "exists",
+        "name",
+        file_cmd_exists,
+        1,
+        1,
+        
+    },
+    {   "delete",
+        "?-force|--? name ...",
+        file_cmd_delete,
+        1,
+        -1,
+        
+    },
+    {   "mkdir",
+        "dir ...",
+        file_cmd_mkdir,
+        1,
+        -1,
+        
     },
 #ifdef HAVE_MKSTEMP
-    {   .cmd = "tempfile",
-        .args = "?template?",
-        .function = file_cmd_tempfile,
-        .minargs = 0,
-        .maxargs = 1,
-        .description = "Creates a temporary filename"
+    {   "tempfile",
+        "?template?",
+        file_cmd_tempfile,
+        0,
+        1,
+        
     },
 #endif
-    {   .cmd = "rename",
-        .args = "?-force? source dest",
-        .function = file_cmd_rename,
-        .minargs = 2,
-        .maxargs = 3,
-        .description = "Renames a file"
+    {   "rename",
+        "?-force? source dest",
+        file_cmd_rename,
+        2,
+        3,
+        
     },
 #if defined(HAVE_READLINK)
-    {   .cmd = "readlink",
-        .args = "name",
-        .function = file_cmd_readlink,
-        .minargs = 1,
-        .maxargs = 1,
-        .description = "Value of the symbolic link"
+    {   "readlink",
+        "name",
+        file_cmd_readlink,
+        1,
+        1,
+        
     },
 #endif
-    {   .cmd = "size",
-        .args = "name",
-        .function = file_cmd_size,
-        .minargs = 1,
-        .maxargs = 1,
-        .description = "Size of file"
+    {   "size",
+        "name",
+        file_cmd_size,
+        1,
+        1,
+        
+    },
+    {   "stat",
+        "name var",
+        file_cmd_stat,
+        2,
+        2,
+        
     },
-    {   .cmd = "stat",
-        .args = "name var",
-        .function = file_cmd_stat,
-        .minargs = 2,
-        .maxargs = 2,
-        .description = "Stores results of stat in var array"
+    {   "lstat",
+        "name var",
+        file_cmd_lstat,
+        2,
+        2,
+        
     },
-    {   .cmd = "lstat",
-        .args = "name var",
-        .function = file_cmd_lstat,
-        .minargs = 2,
-        .maxargs = 2,
-        .description = "Stores results of lstat in var array"
-    },
-    {   .cmd = "type",
-        .args = "name",
-        .function = file_cmd_type,
-        .minargs = 1,
-        .maxargs = 1,
-        .description = "Returns type of the file"
+    {   "type",
+        "name",
+        file_cmd_type,
+        1,
+        1,
+        
     },
 #ifdef HAVE_GETEUID
-    {   .cmd = "owned",
-        .args = "name",
-        .function = file_cmd_owned,
-        .minargs = 1,
-        .maxargs = 1,
-        .description = "Returns 1 if owned by the current owner"
+    {   "owned",
+        "name",
+        file_cmd_owned,
+        1,
+        1,
+        
     },
 #endif
-    {   .cmd = "isdirectory",
-        .args = "name",
-        .function = file_cmd_isdirectory,
-        .minargs = 1,
-        .maxargs = 1,
-        .description = "Returns 1 if name is a directory"
+    {   "isdirectory",
+        "name",
+        file_cmd_isdirectory,
+        1,
+        1,
+        
     },
-    {   .cmd = "isfile",
-        .args = "name",
-        .function = file_cmd_isfile,
-        .minargs = 1,
-        .maxargs = 1,
-        .description = "Returns 1 if name is a file"
+    {   "isfile",
+        "name",
+        file_cmd_isfile,
+        1,
+        1,
+        
     },
     {
-        .cmd = 0
+        NULL
     }
 };
 
 static int Jim_CdCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
 {
@@ -4791,13 +3746,13 @@
 
     if (getcwd(cwd, cwd_len) == NULL) {
         Jim_SetResultString(interp, "Failed to get pwd", -1);
         return JIM_ERR;
     }
-#if defined(__MINGW32__)
+#if defined(__MINGW32__) || defined(_MSC_VER)
     {
-        /* Try to keep backlashes out of paths */
+        
         char *p = cwd;
         while ((p = strchr(p, '\\')) != NULL) {
             *p++ = '/';
         }
     }
@@ -4818,54 +3773,142 @@
     Jim_CreateCommand(interp, "pwd", Jim_PwdCmd, NULL, NULL);
     Jim_CreateCommand(interp, "cd", Jim_CdCmd, NULL, NULL);
     return JIM_OK;
 }
 
-/* 
- * (c) 2008 Steve Bennett <steveb@workware.net.au>
- *
- * Implements the exec command for Jim
- *
- * Based on code originally from Tcl 6.7 by John Ousterhout.
- * From that code:
- *
- * The Tcl_Fork and Tcl_WaitPids procedures are based on code
- * contributed by Karl Lehenbauer, Mark Diekhans and Peter
- * da Silva.
- *
- * Copyright 1987-1991 Regents of the University of California
- * Permission to use, copy, modify, and distribute this
- * software and its documentation for any purpose and without
- * fee is hereby granted, provided that the above copyright
- * notice appear in all copies.  The University of California
- * makes no representations about the suitability of this
- * software for any purpose.  It is provided "as is" without
- * express or implied warranty.
- */
-
 #include <string.h>
+#include <ctype.h>
+
+
+#if (!defined(HAVE_VFORK) || !defined(HAVE_WAITPID)) && !defined(__MINGW32__)
+static int Jim_ExecCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+    Jim_Obj *cmdlineObj = Jim_NewEmptyStringObj(interp);
+    int i, j;
+    int rc;
+
+    
+    for (i = 1; i < argc; i++) {
+        int len;
+        const char *arg = Jim_GetString(argv[i], &len);
+
+        if (i > 1) {
+            Jim_AppendString(interp, cmdlineObj, " ", 1);
+        }
+        if (strpbrk(arg, "\\\" ") == NULL) {
+            
+            Jim_AppendString(interp, cmdlineObj, arg, len);
+            continue;
+        }
+
+        Jim_AppendString(interp, cmdlineObj, "\"", 1);
+        for (j = 0; j < len; j++) {
+            if (arg[j] == '\\' || arg[j] == '"') {
+                Jim_AppendString(interp, cmdlineObj, "\\", 1);
+            }
+            Jim_AppendString(interp, cmdlineObj, &arg[j], 1);
+        }
+        Jim_AppendString(interp, cmdlineObj, "\"", 1);
+    }
+    rc = system(Jim_String(cmdlineObj));
+
+    Jim_FreeNewObj(interp, cmdlineObj);
+
+    if (rc) {
+        Jim_Obj *errorCode = Jim_NewListObj(interp, NULL, 0);
+        Jim_ListAppendElement(interp, errorCode, Jim_NewStringObj(interp, "CHILDSTATUS", -1));
+        Jim_ListAppendElement(interp, errorCode, Jim_NewIntObj(interp, 0));
+        Jim_ListAppendElement(interp, errorCode, Jim_NewIntObj(interp, rc));
+        Jim_SetGlobalVariableStr(interp, "errorCode", errorCode);
+        return JIM_ERR;
+    }
+
+    return JIM_OK;
+}
+
+int Jim_execInit(Jim_Interp *interp)
+{
+    if (Jim_PackageProvide(interp, "exec", "1.0", JIM_ERRMSG))
+        return JIM_ERR;
+    Jim_CreateCommand(interp, "exec", Jim_ExecCmd, NULL, NULL);
+    return JIM_OK;
+}
+#else
+
+
+#include <errno.h>
 #include <signal.h>
 
-
-#if defined(HAVE_VFORK) && defined(HAVE_WAITPID)
-
-
-#include <unistd.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <sys/wait.h>
-
-#if defined(__GNUC__) && !defined(__clang__)
-#define IGNORE_RC(EXPR) ((EXPR) < 0 ? -1 : 0)
-#else
-#define IGNORE_RC(EXPR) EXPR
-#endif
-
-/* These two could be moved into the Tcl core */
+#if defined(__MINGW32__)
+    
+    #ifndef STRICT
+    #define STRICT
+    #endif
+    #define WIN32_LEAN_AND_MEAN
+    #include <windows.h>
+    #include <fcntl.h>
+
+    typedef HANDLE fdtype;
+    typedef HANDLE pidtype;
+    #define JIM_BAD_FD INVALID_HANDLE_VALUE
+    #define JIM_BAD_PID INVALID_HANDLE_VALUE
+    #define JimCloseFd CloseHandle
+
+    #define WIFEXITED(STATUS) 1
+    #define WEXITSTATUS(STATUS) (STATUS)
+    #define WIFSIGNALED(STATUS) 0
+    #define WTERMSIG(STATUS) 0
+    #define WNOHANG 1
+
+    static fdtype JimFileno(FILE *fh);
+    static pidtype JimWaitPid(pidtype pid, int *status, int nohang);
+    static fdtype JimDupFd(fdtype infd);
+    static fdtype JimOpenForRead(const char *filename);
+    static FILE *JimFdOpenForRead(fdtype fd);
+    static int JimPipe(fdtype pipefd[2]);
+    static pidtype JimStartWinProcess(Jim_Interp *interp, char **argv, char *env,
+        fdtype inputId, fdtype outputId, fdtype errorId);
+    static int JimErrno(void);
+#else
+    #include <unistd.h>
+    #include <fcntl.h>
+    #include <sys/wait.h>
+
+    typedef int fdtype;
+    typedef int pidtype;
+    #define JimPipe pipe
+    #define JimErrno() errno
+    #define JIM_BAD_FD -1
+    #define JIM_BAD_PID -1
+    #define JimFileno fileno
+    #define JimReadFd read
+    #define JimCloseFd close
+    #define JimWaitPid waitpid
+    #define JimDupFd dup
+    #define JimFdOpenForRead(FD) fdopen((FD), "r")
+    #define JimOpenForRead(NAME) open((NAME), O_RDONLY, 0)
+#endif
+
+static const char *JimStrError(void);
+static char **JimSaveEnv(char **env);
+static void JimRestoreEnv(char **env);
+static int JimCreatePipeline(Jim_Interp *interp, int argc, Jim_Obj *const *argv,
+    pidtype **pidArrayPtr, fdtype *inPipePtr, fdtype *outPipePtr, fdtype *errFilePtr);
+static void JimDetachPids(Jim_Interp *interp, int numPids, const pidtype *pidPtr);
+static int JimCleanupChildren(Jim_Interp *interp, int numPids, pidtype *pidPtr, fdtype errorId);
+static fdtype JimCreateTemp(Jim_Interp *interp, const char *contents);
+static fdtype JimOpenForWrite(const char *filename, int append);
+static int JimRewindFd(fdtype fd);
+
 static void Jim_SetResultErrno(Jim_Interp *interp, const char *msg)
 {
-    Jim_SetResultFormatted(interp, "%s: %s", msg, strerror(errno));
+    Jim_SetResultFormatted(interp, "%s: %s", msg, JimStrError());
+}
+
+static const char *JimStrError(void)
+{
+    return strerror(JimErrno());
 }
 
 static void Jim_RemoveTrailingNewline(Jim_Obj *objPtr)
 {
     int len;
@@ -4875,40 +3918,32 @@
         objPtr->length--;
         objPtr->bytes[objPtr->length] = '\0';
     }
 }
 
-/**
- * Read from 'fd' and append the data to strObj
- * Returns JIM_OK if OK, or JIM_ERR on error.
- */
-static int JimAppendStreamToString(Jim_Interp *interp, int fd, Jim_Obj *strObj)
+static int JimAppendStreamToString(Jim_Interp *interp, fdtype fd, Jim_Obj *strObj)
 {
+    char buf[256];
+    FILE *fh = JimFdOpenForRead(fd);
+    if (fh == NULL) {
+        return JIM_ERR;
+    }
+
     while (1) {
-        char buffer[256];
-        int count;
-
-        count = read(fd, buffer, sizeof(buffer));
-
-        if (count == 0) {
-            Jim_RemoveTrailingNewline(strObj);
-            return JIM_OK;
+        int retval = fread(buf, 1, sizeof(buf), fh);
+        if (retval > 0) {
+            Jim_AppendString(interp, strObj, buf, retval);
         }
-        if (count < 0) {
-            return JIM_ERR;
+        if (retval != sizeof(buf)) {
+            break;
         }
-        Jim_AppendString(interp, strObj, buffer, count);
     }
+    Jim_RemoveTrailingNewline(strObj);
+    fclose(fh);
+    return JIM_OK;
 }
 
-/*
- * If the last character of the result is a newline, then remove
- * the newline character (the newline would just confuse things).
- *
- * Note: Ideally we could do this by just reducing the length of stringrep
- *       by 1, but there is no API for this :-(
- */
 static void JimTrimTrailingNewline(Jim_Interp *interp)
 {
     int len;
     const char *p = Jim_GetString(Jim_GetResult(interp), &len);
 
@@ -4915,89 +3950,72 @@
     if (len > 0 && p[len - 1] == '\n') {
         Jim_SetResultString(interp, p, len - 1);
     }
 }
 
-/**
- * Builds the environment array from $::env
- *
- * If $::env is not set, simply returns environ.
- *
- * Otherwise allocates the environ array from the contents of $::env
- *
- * If the exec fails, memory can be freed via JimFreeEnv()
- */
 static char **JimBuildEnv(Jim_Interp *interp)
 {
-#ifdef jim_ext_tclcompat
+#if defined(jim_ext_tclcompat)
     int i;
-    int len;
+    int size;
+    int num;
     int n;
-    char **env;
+    char **envptr;
+    char *envdata;
 
     Jim_Obj *objPtr = Jim_GetGlobalVariableStr(interp, "env", JIM_NONE);
 
     if (!objPtr) {
         return Jim_GetEnviron();
     }
 
-    /* Calculate the required size */
-    len = Jim_ListLength(interp, objPtr);
-    if (len % 2) {
-        len--;
+
+    
+    num = Jim_ListLength(interp, objPtr);
+    if (num % 2) {
+        num--;
     }
+    size = Jim_Length(objPtr);
+    size++;
 
-    env = Jim_Alloc(sizeof(*env) * (len / 2 + 1));
+    envptr = Jim_Alloc(sizeof(*envptr) * (num / 2 + 1) + size);
+    envdata = (char *)&envptr[num / 2 + 1];
 
     n = 0;
-    for (i = 0; i < len; i += 2) {
-        int l1, l2;
+    for (i = 0; i < num; i += 2) {
         const char *s1, *s2;
         Jim_Obj *elemObj;
 
         Jim_ListIndex(interp, objPtr, i, &elemObj, JIM_NONE);
-        s1 = Jim_GetString(elemObj, &l1);
+        s1 = Jim_String(elemObj);
         Jim_ListIndex(interp, objPtr, i + 1, &elemObj, JIM_NONE);
-        s2 = Jim_GetString(elemObj, &l2);
+        s2 = Jim_String(elemObj);
 
-        env[n] = Jim_Alloc(l1 + l2 + 2);
-        sprintf(env[n], "%s=%s", s1, s2);
+        envptr[n] = envdata;
+        envdata += sprintf(envdata, "%s=%s", s1, s2);
+        envdata++;
         n++;
     }
-    env[n] = NULL;
+    envptr[n] = NULL;
+    *envdata = 0;
 
-    return env;
+    return envptr;
 #else
     return Jim_GetEnviron();
 #endif
 }
 
-/**
- * Frees the environment allocated by JimBuildEnv()
- *
- * Must pass original_environ.
- */
-static void JimFreeEnv(Jim_Interp *interp, char **env, char **original_environ)
+static void JimFreeEnv(char **env, char **original_environ)
 {
 #ifdef jim_ext_tclcompat
     if (env != original_environ) {
-        int i;
-        for (i = 0; env[i]; i++) {
-            Jim_Free(env[i]);
-        }
         Jim_Free(env);
     }
 #endif
 }
 
-/*
- * Create error messages for unusual process exits.  An
- * extra newline gets appended to each error message, but
- * it gets removed below (in the same fashion that an
- * extra newline in the command's output is removed).
- */
-static int JimCheckWaitStatus(Jim_Interp *interp, int pid, int waitStatus)
+static int JimCheckWaitStatus(Jim_Interp *interp, pidtype pid, int waitStatus)
 {
     Jim_Obj *errorCode = Jim_NewListObj(interp, NULL, 0);
     int rc = JIM_ERR;
 
     if (WIFEXITED(waitStatus)) {
@@ -5005,11 +4023,11 @@
             Jim_ListAppendElement(interp, errorCode, Jim_NewStringObj(interp, "NONE", -1));
             rc = JIM_OK;
         }
         else {
             Jim_ListAppendElement(interp, errorCode, Jim_NewStringObj(interp, "CHILDSTATUS", -1));
-            Jim_ListAppendElement(interp, errorCode, Jim_NewIntObj(interp, pid));
+            Jim_ListAppendElement(interp, errorCode, Jim_NewIntObj(interp, (long)pid));
             Jim_ListAppendElement(interp, errorCode, Jim_NewIntObj(interp, WEXITSTATUS(waitStatus)));
         }
     }
     else {
         const char *type;
@@ -5032,43 +4050,32 @@
         Jim_ListAppendElement(interp, errorCode, Jim_NewIntObj(interp, pid));
         Jim_ListAppendElement(interp, errorCode, Jim_NewStringObj(interp, Jim_SignalName(WTERMSIG(waitStatus)), -1));
 #else
         Jim_SetResultFormatted(interp, "child %s by signal %d", action, WTERMSIG(waitStatus));
         Jim_ListAppendElement(interp, errorCode, Jim_NewIntObj(interp, WTERMSIG(waitStatus)));
-        Jim_ListAppendElement(interp, errorCode, Jim_NewIntObj(interp, pid));
+        Jim_ListAppendElement(interp, errorCode, Jim_NewIntObj(interp, (long)pid));
         Jim_ListAppendElement(interp, errorCode, Jim_NewIntObj(interp, WTERMSIG(waitStatus)));
 #endif
     }
     Jim_SetGlobalVariableStr(interp, "errorCode", errorCode);
     return rc;
 }
 
-/*
- * Data structures of the following type are used by JimFork and
- * JimWaitPids to keep track of child processes.
- */
 
 struct WaitInfo
 {
-    int pid;                    /* Process id of child. */
-    int status;                 /* Status returned when child exited or suspended. */
-    int flags;                  /* Various flag bits;  see below for definitions. */
+    pidtype pid;                    
+    int status;                 
+    int flags;                  
 };
 
 struct WaitInfoTable {
     struct WaitInfo *info;
     int size;
     int used;
 };
 
-/*
- * Flag bits in WaitInfo structures:
- *
- * WI_DETACHED -        Non-zero means no-one cares about the
- *                      process anymore.  Ignore it until it
- *                      exits, then forget about it.
- */
 
 #define WI_DETACHED 2
 
 #define WAIT_TABLE_GROW_BY 4
 
@@ -5087,78 +4094,63 @@
     table->size = table->used = 0;
 
     return table;
 }
 
-static int Jim_CreatePipeline(Jim_Interp *interp, int argc, Jim_Obj *const *argv,
-    int **pidArrayPtr, int *inPipePtr, int *outPipePtr, int *errFilePtr);
-static void JimDetachPids(Jim_Interp *interp, int numPids, const int *pidPtr);
-static int Jim_CleanupChildren(Jim_Interp *interp, int numPids, int *pidPtr, int errorId);
-
 static int Jim_ExecCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
 {
-    int outputId;               /* File id for output pipe.  -1
+    fdtype outputId;               /* File id for output pipe.  -1
                                  * means command overrode. */
-    int errorId;                /* File id for temporary file
+    fdtype errorId;                /* File id for temporary file
                                  * containing error output. */
-    int *pidPtr;
+    pidtype *pidPtr;
     int numPids, result;
 
-    /*
-     * See if the command is to be run in background;  if so, create
-     * the command, detach it, and return.
-     */
     if (argc > 1 && Jim_CompareStringImmediate(interp, argv[argc - 1], "&")) {
         Jim_Obj *listObj;
         int i;
 
         argc--;
-        numPids = Jim_CreatePipeline(interp, argc - 1, argv + 1, &pidPtr, NULL, NULL, NULL);
+        numPids = JimCreatePipeline(interp, argc - 1, argv + 1, &pidPtr, NULL, NULL, NULL);
         if (numPids < 0) {
             return JIM_ERR;
         }
-        /* The return value is a list of the pids */
+        
         listObj = Jim_NewListObj(interp, NULL, 0);
         for (i = 0; i < numPids; i++) {
-            Jim_ListAppendElement(interp, listObj, Jim_NewIntObj(interp, pidPtr[i]));
+            Jim_ListAppendElement(interp, listObj, Jim_NewIntObj(interp, (long)pidPtr[i]));
         }
         Jim_SetResult(interp, listObj);
         JimDetachPids(interp, numPids, pidPtr);
         Jim_Free(pidPtr);
         return JIM_OK;
     }
 
-    /*
-     * Create the command's pipeline.
-     */
     numPids =
-        Jim_CreatePipeline(interp, argc - 1, argv + 1, &pidPtr, (int *)NULL, &outputId, &errorId);
+        JimCreatePipeline(interp, argc - 1, argv + 1, &pidPtr, NULL, &outputId, &errorId);
+
     if (numPids < 0) {
         return JIM_ERR;
     }
 
-    /*
-     * Read the child's output (if any) and put it into the result.
-     */
     Jim_SetResultString(interp, "", 0);
 
     result = JIM_OK;
-    if (outputId != -1) {
+    if (outputId != JIM_BAD_FD) {
         result = JimAppendStreamToString(interp, outputId, Jim_GetResult(interp));
         if (result < 0) {
             Jim_SetResultErrno(interp, "error reading from output pipe");
         }
-        close(outputId);
     }
 
-    if (Jim_CleanupChildren(interp, numPids, pidPtr, errorId) != JIM_OK) {
+    if (JimCleanupChildren(interp, numPids, pidPtr, errorId) != JIM_OK) {
         result = JIM_ERR;
     }
     return result;
 }
 
-void Jim_ReapDetachedPids(struct WaitInfoTable *table)
+static void JimReapDetachedPids(struct WaitInfoTable *table)
 {
     struct WaitInfo *waitPtr;
     int count;
 
     if (!table) {
@@ -5166,76 +4158,52 @@
     }
 
     for (waitPtr = table->info, count = table->used; count > 0; waitPtr++, count--) {
         if (waitPtr->flags & WI_DETACHED) {
             int status;
-            int pid = waitpid(waitPtr->pid, &status, WNOHANG);
-            if (pid > 0) {
+            pidtype pid = JimWaitPid(waitPtr->pid, &status, WNOHANG);
+            if (pid != JIM_BAD_PID) {
                 if (waitPtr != &table->info[table->used - 1]) {
                     *waitPtr = table->info[table->used - 1];
                 }
                 table->used--;
             }
         }
     }
 }
 
-/**
- * Does waitpid() on the given pid, and then removes the
- * entry from the wait table.
- * 
- * Returns the pid if OK and updates *statusPtr with the status,
- * or -1 if the pid was not in the table.
- */
-static int JimWaitPid(struct WaitInfoTable *table, int pid, int *statusPtr)
+static pidtype JimWaitForProcess(struct WaitInfoTable *table, pidtype pid, int *statusPtr)
 {
     int i;
 
-    /* Find it in the table */
+    
     for (i = 0; i < table->used; i++) {
         if (pid == table->info[i].pid) {
-            /* wait for it */
-            waitpid(pid, statusPtr, 0);
+            
+            JimWaitPid(pid, statusPtr, 0);
 
-            /* Remove it from the table */
+            
             if (i != table->used - 1) {
                 table->info[i] = table->info[table->used - 1];
             }
             table->used--;
             return pid;
         }
     }
 
-    /* Not found */
-    return -1;
+    
+    return JIM_BAD_PID;
 }
 
-/*
- *----------------------------------------------------------------------
- *
- * JimDetachPids --
- *
- *  This procedure is called to indicate that one or more child
- *  processes have been placed in background and are no longer
- *  cared about.  These children can be cleaned up with JimReapDetachedPids().
- *
- * Results:
- *  None.
- *
- * Side effects:
- *  None.
- *
- *----------------------------------------------------------------------
- */
 
-static void JimDetachPids(Jim_Interp *interp, int numPids, const int *pidPtr)
+static void JimDetachPids(Jim_Interp *interp, int numPids, const pidtype *pidPtr)
 {
     int j;
     struct WaitInfoTable *table = Jim_CmdPrivData(interp);
 
     for (j = 0; j < numPids; j++) {
-        /* Find it in the table */
+        
         int i;
         for (i = 0; i < table->used; i++) {
             if (pidPtr[j] == table->info[i].pid) {
                 table->info[i].flags |= WI_DETACHED;
                 break;
@@ -5242,56 +4210,28 @@
             }
         }
     }
 }
 
-/*
- *----------------------------------------------------------------------
- *
- * Jim_CreatePipeline --
- *
- *  Given an argc/argv array, instantiate a pipeline of processes
- *  as described by the argv.
- *
- * Results:
- *  The return value is a count of the number of new processes
- *  created, or -1 if an error occurred while creating the pipeline.
- *  *pidArrayPtr is filled in with the address of a dynamically
- *  allocated array giving the ids of all of the processes.  It
- *  is up to the caller to free this array when it isn't needed
- *  anymore.  If inPipePtr is non-NULL, *inPipePtr is filled in
- *  with the file id for the input pipe for the pipeline (if any):
- *  the caller must eventually close this file.  If outPipePtr
- *  isn't NULL, then *outPipePtr is filled in with the file id
- *  for the output pipe from the pipeline:  the caller must close
- *  this file.  If errFilePtr isn't NULL, then *errFilePtr is filled
- *  with a file id that may be used to read error output after the
- *  pipeline completes.
- *
- * Side effects:
- *  Processes and pipes are created.
- *
- *----------------------------------------------------------------------
- */
 static int
-Jim_CreatePipeline(Jim_Interp *interp, int argc, Jim_Obj *const *argv, int **pidArrayPtr,
-    int *inPipePtr, int *outPipePtr, int *errFilePtr)
+JimCreatePipeline(Jim_Interp *interp, int argc, Jim_Obj *const *argv, pidtype **pidArrayPtr,
+    fdtype *inPipePtr, fdtype *outPipePtr, fdtype *errFilePtr)
 {
-    int *pidPtr = NULL;         /* Points to malloc-ed array holding all
+    pidtype *pidPtr = NULL;         /* Points to malloc-ed array holding all
                                  * the pids of child processes. */
     int numPids = 0;            /* Actual number of processes that exist
                                  * at *pidPtr right now. */
     int cmdCount;               /* Count of number of distinct commands
                                  * found in argc/argv. */
     const char *input = NULL;   /* Describes input for pipeline, depending
                                  * on "inputFile".  NULL means take input
                                  * from stdin/pipe. */
 
-#define FILE_NAME   0           /* input/output: filename */
-#define FILE_APPEND 1           /* output only:  filename, append */
-#define FILE_HANDLE 2           /* input/output: filehandle */
-#define FILE_TEXT   3           /* input only:   input is actual text */
+#define FILE_NAME   0           
+#define FILE_APPEND 1           
+#define FILE_HANDLE 2           
+#define FILE_TEXT   3           
 
     int inputFile = FILE_NAME;  /* 1 means input is name of input file.
                                  * 2 means input is filehandle name.
                                  * 0 means input holds actual
                                  * text to be input to command. */
@@ -5308,55 +4248,40 @@
                                  */
     const char *output = NULL;  /* Holds name of output file to pipe to,
                                  * or NULL if output goes to stdout/pipe. */
     const char *error = NULL;   /* Holds name of stderr file to pipe to,
                                  * or NULL if stderr goes to stderr/pipe. */
-    int inputId = -1;           /* Readable file id input to current command in
-                                 * pipeline (could be file or pipe).  -1
-                                 * means use stdin. */
-    int outputId = -1;          /* Writable file id for output from current
-                                 * command in pipeline (could be file or pipe).
-                                 * -1 means use stdout. */
-    int errorId = -1;           /* Writable file id for all standard error
-                                 * output from all commands in pipeline.  -1
-                                 * means use stderr. */
-    int lastOutputId = -1;      /* Write file id for output from last command
-                                 * in pipeline (could be file or pipe).
-                                 * -1 means use stdout. */
-    int pipeIds[2];             /* File ids for pipe that's being created. */
+    fdtype inputId = JIM_BAD_FD;
+    fdtype outputId = JIM_BAD_FD;
+    fdtype errorId = JIM_BAD_FD;
+    fdtype lastOutputId = JIM_BAD_FD;
+    fdtype pipeIds[2];           
     int firstArg, lastArg;      /* Indexes of first and last arguments in
                                  * current command. */
     int lastBar;
-    char *execName;
-    int i, pid;
-    char **orig_environ;
+    int i;
+    pidtype pid;
+    char **save_environ;
     struct WaitInfoTable *table = Jim_CmdPrivData(interp);
 
-    /* Holds the args which will be used to exec */
+    
     char **arg_array = Jim_Alloc(sizeof(*arg_array) * (argc + 1));
     int arg_count = 0;
 
-    Jim_ReapDetachedPids(table);
+    JimReapDetachedPids(table);
 
     if (inPipePtr != NULL) {
-        *inPipePtr = -1;
+        *inPipePtr = JIM_BAD_FD;
     }
     if (outPipePtr != NULL) {
-        *outPipePtr = -1;
+        *outPipePtr = JIM_BAD_FD;
     }
     if (errFilePtr != NULL) {
-        *errFilePtr = -1;
+        *errFilePtr = JIM_BAD_FD;
     }
-    pipeIds[0] = pipeIds[1] = -1;
+    pipeIds[0] = pipeIds[1] = JIM_BAD_FD;
 
-    /*
-     * First, scan through all the arguments to figure out the structure
-     * of the pipeline.  Count the number of distinct processes (it's the
-     * number of "|" arguments).  If there are "<", "<<", or ">" arguments
-     * then make note of input and output redirection and remove these
-     * arguments and the arguments that follow them.
-     */
     cmdCount = 1;
     lastBar = -1;
     for (i = 0; i < argc; i++) {
         const char *arg = Jim_String(argv[i]);
 
@@ -5385,11 +4310,11 @@
             if (*output == '>') {
                 outputFile = FILE_APPEND;
                 output++;
             }
             if (*output == '&') {
-                /* Redirect stderr too */
+                
                 output++;
                 dup_error = 1;
             }
             if (*output == '@') {
                 outputFile = FILE_HANDLE;
@@ -5426,11 +4351,11 @@
                     goto badargs;
                 }
                 lastBar = i;
                 cmdCount++;
             }
-            /* Either |, |& or a "normal" arg, so store it in the arg array */
+            
             arg_array[arg_count++] = (char *)arg;
             continue;
         }
 
         if (i >= argc) {
@@ -5444,82 +4369,49 @@
 badargs:
         Jim_Free(arg_array);
         return -1;
     }
 
-    /* Must do this before vfork(), so do it now */
-    orig_environ = Jim_GetEnviron();
-    Jim_SetEnviron(JimBuildEnv(interp));
+    
+    save_environ = JimSaveEnv(JimBuildEnv(interp));
 
-    /*
-     * Set up the redirected input source for the pipeline, if
-     * so requested.
-     */
     if (input != NULL) {
         if (inputFile == FILE_TEXT) {
-            /*
-             * Immediate data in command.  Create temporary file and
-             * put data into file.
-             */
-
-#define TMP_STDIN_NAME "/tmp/tcl.in.XXXXXX"
-            char inName[sizeof(TMP_STDIN_NAME) + 1];
-            int length;
-
-            strcpy(inName, TMP_STDIN_NAME);
-            inputId = mkstemp(inName);
-            if (inputId < 0) {
-                Jim_SetResultErrno(interp, "couldn't create input file for command");
-                goto error;
-            }
-            length = strlen(input);
-            if (write(inputId, input, length) != length) {
-                Jim_SetResultErrno(interp, "couldn't write file input for command");
-                goto error;
-            }
-            if (lseek(inputId, 0L, SEEK_SET) == -1 || unlink(inName) == -1) {
-                Jim_SetResultErrno(interp, "couldn't reset or remove input file for command");
+            inputId = JimCreateTemp(interp, input);
+            if (inputId == JIM_BAD_FD) {
                 goto error;
             }
         }
         else if (inputFile == FILE_HANDLE) {
-            /* Should be a file descriptor */
+            
             Jim_Obj *fhObj = Jim_NewStringObj(interp, input, -1);
             FILE *fh = Jim_AioFilehandle(interp, fhObj);
 
             Jim_FreeNewObj(interp, fhObj);
             if (fh == NULL) {
                 goto error;
             }
-            inputId = dup(fileno(fh));
+            inputId = JimDupFd(JimFileno(fh));
         }
         else {
-            /*
-             * File redirection.  Just open the file.
-             */
-            inputId = open(input, O_RDONLY, 0);
-            if (inputId < 0) {
-                Jim_SetResultFormatted(interp, "couldn't read file \"%s\": %s", input,
-                    strerror(errno));
+            inputId = JimOpenForRead(input);
+            if (inputId == JIM_BAD_FD) {
+                Jim_SetResultFormatted(interp, "couldn't read file \"%s\": %s", input, JimStrError());
                 goto error;
             }
         }
     }
     else if (inPipePtr != NULL) {
-        if (pipe(pipeIds) != 0) {
+        if (JimPipe(pipeIds) != 0) {
             Jim_SetResultErrno(interp, "couldn't create input pipe for command");
             goto error;
         }
         inputId = pipeIds[0];
         *inPipePtr = pipeIds[1];
-        pipeIds[0] = pipeIds[1] = -1;
+        pipeIds[0] = pipeIds[1] = JIM_BAD_FD;
     }
 
-    /*
-     * Set up the redirected output sink for the pipeline from one
-     * of two places, if requested.
-     */
     if (output != NULL) {
         if (outputFile == FILE_HANDLE) {
             Jim_Obj *fhObj = Jim_NewStringObj(interp, output, -1);
             FILE *fh = Jim_AioFilehandle(interp, fhObj);
 
@@ -5526,207 +4418,144 @@
             Jim_FreeNewObj(interp, fhObj);
             if (fh == NULL) {
                 goto error;
             }
             fflush(fh);
-            lastOutputId = dup(fileno(fh));
+            lastOutputId = JimDupFd(JimFileno(fh));
         }
         else {
-            /*
-             * Output is to go to a file.
-             */
-            int mode = O_WRONLY | O_CREAT | O_TRUNC;
-
-            if (outputFile == FILE_APPEND) {
-                mode = O_WRONLY | O_CREAT | O_APPEND;
-            }
-
-            lastOutputId = open(output, mode, 0666);
-            if (lastOutputId < 0) {
-                Jim_SetResultFormatted(interp, "couldn't write file \"%s\": %s", output,
-                    strerror(errno));
+            lastOutputId = JimOpenForWrite(output, outputFile == FILE_APPEND);
+            if (lastOutputId == JIM_BAD_FD) {
+                Jim_SetResultFormatted(interp, "couldn't write file \"%s\": %s", output, JimStrError());
                 goto error;
             }
         }
     }
     else if (outPipePtr != NULL) {
-        /*
-         * Output is to go to a pipe.
-         */
-        if (pipe(pipeIds) != 0) {
+        if (JimPipe(pipeIds) != 0) {
             Jim_SetResultErrno(interp, "couldn't create output pipe");
             goto error;
         }
         lastOutputId = pipeIds[1];
         *outPipePtr = pipeIds[0];
-        pipeIds[0] = pipeIds[1] = -1;
+        pipeIds[0] = pipeIds[1] = JIM_BAD_FD;
     }
-
-    /* If we are redirecting stderr with 2>filename or 2>@fileId, then we ignore errFilePtr */
+    
     if (error != NULL) {
         if (errorFile == FILE_HANDLE) {
             if (strcmp(error, "1") == 0) {
-                /* Special 2>@1 */
-                if (lastOutputId >= 0) {
-                    errorId = dup(lastOutputId);
+                
+                if (lastOutputId != JIM_BAD_FD) {
+                    errorId = JimDupFd(lastOutputId);
                 }
                 else {
-                    /* No redirection of stdout, so just use 2>@stdout */
+                    
                     error = "stdout";
                 }
             }
-            if (errorId < 0) {
+            if (errorId == JIM_BAD_FD) {
                 Jim_Obj *fhObj = Jim_NewStringObj(interp, error, -1);
                 FILE *fh = Jim_AioFilehandle(interp, fhObj);
 
                 Jim_FreeNewObj(interp, fhObj);
                 if (fh == NULL) {
                     goto error;
                 }
                 fflush(fh);
-                errorId = dup(fileno(fh));
+                errorId = JimDupFd(JimFileno(fh));
             }
         }
         else {
-            /*
-             * Output is to go to a file.
-             */
-            int mode = O_WRONLY | O_CREAT | O_TRUNC;
-
-            if (errorFile == FILE_APPEND) {
-                mode = O_WRONLY | O_CREAT | O_APPEND;
-            }
-
-            errorId = open(error, mode, 0666);
-            if (errorId < 0) {
-                Jim_SetResultFormatted(interp, "couldn't write file \"%s\": %s", error,
-                    strerror(errno));
+            errorId = JimOpenForWrite(error, errorFile == FILE_APPEND);
+            if (errorId == JIM_BAD_FD) {
+                Jim_SetResultFormatted(interp, "couldn't write file \"%s\": %s", error, JimStrError());
+                goto error;
             }
         }
     }
     else if (errFilePtr != NULL) {
-        /*
-         * Set up the standard error output sink for the pipeline, if
-         * requested.  Use a temporary file which is opened, then deleted.
-         * Could potentially just use pipe, but if it filled up it could
-         * cause the pipeline to deadlock:  we'd be waiting for processes
-         * to complete before reading stderr, and processes couldn't complete
-         * because stderr was backed up.
-         */
-
-#define TMP_STDERR_NAME "/tmp/tcl.err.XXXXXX"
-        char errName[sizeof(TMP_STDERR_NAME) + 1];
-
-        strcpy(errName, TMP_STDERR_NAME);
-        errorId = mkstemp(errName);
-        if (errorId < 0) {
-          errFileError:
-            Jim_SetResultErrno(interp, "couldn't create error file for command");
+        errorId = JimCreateTemp(interp, NULL);
+        if (errorId == JIM_BAD_FD) {
             goto error;
         }
-        *errFilePtr = open(errName, O_RDONLY, 0);
-        if (*errFilePtr < 0) {
-            goto errFileError;
-        }
-        if (unlink(errName) == -1) {
-            Jim_SetResultErrno(interp, "couldn't remove error file for command");
-            goto error;
-        }
+        *errFilePtr = JimDupFd(errorId);
     }
 
-    /*
-     * Scan through the argc array, forking off a process for each
-     * group of arguments between "|" arguments.
-     */
 
-    pidPtr = (int *)Jim_Alloc(cmdCount * sizeof(*pidPtr));
+    pidPtr = Jim_Alloc(cmdCount * sizeof(*pidPtr));
     for (i = 0; i < numPids; i++) {
-        pidPtr[i] = -1;
+        pidPtr[i] = JIM_BAD_PID;
     }
     for (firstArg = 0; firstArg < arg_count; numPids++, firstArg = lastArg + 1) {
         int pipe_dup_err = 0;
-        int origErrorId = errorId;
-        char execerr[64];
-        int execerrlen;
+        fdtype origErrorId = errorId;
 
         for (lastArg = firstArg; lastArg < arg_count; lastArg++) {
             if (arg_array[lastArg][0] == '|') {
                 if (arg_array[lastArg][1] == '&') {
                     pipe_dup_err = 1;
                 }
                 break;
             }
         }
-        /* Replace | with NULL for execv() */
+        
         arg_array[lastArg] = NULL;
         if (lastArg == arg_count) {
             outputId = lastOutputId;
         }
         else {
-            if (pipe(pipeIds) != 0) {
+            if (JimPipe(pipeIds) != 0) {
                 Jim_SetResultErrno(interp, "couldn't create pipe");
                 goto error;
             }
             outputId = pipeIds[1];
         }
-        execName = arg_array[firstArg];
 
-        /* Now fork the child */
+        
 
-        /*
-         * Disable SIGPIPE signals:  if they were allowed, this process
-         * might go away unexpectedly if children misbehave.  This code
-         * can potentially interfere with other application code that
-         * expects to handle SIGPIPEs;  what's really needed is an
-         * arbiter for signals to allow them to be "shared".
-         */
+#ifdef __MINGW32__
+        pid = JimStartWinProcess(interp, &arg_array[firstArg], save_environ ? save_environ[0] : NULL, inputId, outputId, errorId);
+        if (pid == JIM_BAD_PID) {
+            Jim_SetResultFormatted(interp, "couldn't exec \"%s\"", arg_array[firstArg]);
+            goto error;
+        }
+#else
         if (table->info == NULL) {
             (void)signal(SIGPIPE, SIG_IGN);
         }
 
-        /* Need to do this befor vfork() */
+        
         if (pipe_dup_err) {
             errorId = outputId;
         }
 
-        /* Need to prep an error message before vfork(), just in case */
-        snprintf(execerr, sizeof(execerr), "couldn't exec \"%s\"", execName);
-        execerrlen = strlen(execerr);
-
-        /*
-         * Make a new process and enter it into the table if the fork
-         * is successful.
-         */
         pid = vfork();
         if (pid < 0) {
             Jim_SetResultErrno(interp, "couldn't fork child process");
             goto error;
         }
         if (pid == 0) {
-            /* Child */
+            
 
             if (inputId != -1) dup2(inputId, 0);
             if (outputId != -1) dup2(outputId, 1);
             if (errorId != -1) dup2(errorId, 2);
 
             for (i = 3; (i <= outputId) || (i <= inputId) || (i <= errorId); i++) {
                 close(i);
             }
 
-            execvp(execName, &arg_array[firstArg]);
+            execvp(arg_array[firstArg], &arg_array[firstArg]);
 
-            /* we really can ignore the error here! */
-            IGNORE_RC(write(2, execerr, execerrlen));
+            
+            fprintf(stderr, "couldn't exec \"%s\"", arg_array[firstArg]);
             _exit(127);
         }
+#endif
 
-        /* parent */
+        
 
-        /*
-         * Enlarge the wait table if there isn't enough space for a new
-         * entry.
-         */
         if (table->used == table->size) {
             table->size += WAIT_TABLE_GROW_BY;
             table->info = Jim_Realloc(table->info, table->size * sizeof(*table->info));
         }
 
@@ -5734,136 +4563,96 @@
         table->info[table->used].flags = 0;
         table->used++;
 
         pidPtr[numPids] = pid;
 
-        /* Restore in case of pipe_dup_err */
+        
         errorId = origErrorId;
 
-        /*
-         * Close off our copies of file descriptors that were set up for
-         * this child, then set up the input for the next child.
-         */
 
-        if (inputId != -1) {
-            close(inputId);
+        if (inputId != JIM_BAD_FD) {
+            JimCloseFd(inputId);
         }
-        if (outputId != -1) {
-            close(outputId);
+        if (outputId != JIM_BAD_FD) {
+            JimCloseFd(outputId);
         }
         inputId = pipeIds[0];
-        pipeIds[0] = pipeIds[1] = -1;
+        pipeIds[0] = pipeIds[1] = JIM_BAD_FD;
     }
     *pidArrayPtr = pidPtr;
 
-    /*
-     * All done.  Cleanup open files lying around and then return.
-     */
 
   cleanup:
-    if (inputId != -1) {
-        close(inputId);
+    if (inputId != JIM_BAD_FD) {
+        JimCloseFd(inputId);
     }
-    if (lastOutputId != -1) {
-        close(lastOutputId);
+    if (lastOutputId != JIM_BAD_FD) {
+        JimCloseFd(lastOutputId);
     }
-    if (errorId != -1) {
-        close(errorId);
+    if (errorId != JIM_BAD_FD) {
+        JimCloseFd(errorId);
     }
     Jim_Free(arg_array);
 
-    JimFreeEnv(interp, Jim_GetEnviron(), orig_environ);
-    Jim_SetEnviron(orig_environ);
+    JimRestoreEnv(save_environ);
 
     return numPids;
 
-    /*
-     * An error occurred.  There could have been extra files open, such
-     * as pipes between children.  Clean them all up.  Detach any child
-     * processes that have been created.
-     */
 
   error:
-    if ((inPipePtr != NULL) && (*inPipePtr != -1)) {
-        close(*inPipePtr);
-        *inPipePtr = -1;
+    if ((inPipePtr != NULL) && (*inPipePtr != JIM_BAD_FD)) {
+        JimCloseFd(*inPipePtr);
+        *inPipePtr = JIM_BAD_FD;
     }
-    if ((outPipePtr != NULL) && (*outPipePtr != -1)) {
-        close(*outPipePtr);
-        *outPipePtr = -1;
+    if ((outPipePtr != NULL) && (*outPipePtr != JIM_BAD_FD)) {
+        JimCloseFd(*outPipePtr);
+        *outPipePtr = JIM_BAD_FD;
     }
-    if ((errFilePtr != NULL) && (*errFilePtr != -1)) {
-        close(*errFilePtr);
-        *errFilePtr = -1;
+    if ((errFilePtr != NULL) && (*errFilePtr != JIM_BAD_FD)) {
+        JimCloseFd(*errFilePtr);
+        *errFilePtr = JIM_BAD_FD;
     }
-    if (pipeIds[0] != -1) {
-        close(pipeIds[0]);
+    if (pipeIds[0] != JIM_BAD_FD) {
+        JimCloseFd(pipeIds[0]);
     }
-    if (pipeIds[1] != -1) {
-        close(pipeIds[1]);
+    if (pipeIds[1] != JIM_BAD_FD) {
+        JimCloseFd(pipeIds[1]);
     }
     if (pidPtr != NULL) {
         for (i = 0; i < numPids; i++) {
-            if (pidPtr[i] != -1) {
+            if (pidPtr[i] != JIM_BAD_PID) {
                 JimDetachPids(interp, 1, &pidPtr[i]);
             }
         }
         Jim_Free(pidPtr);
     }
     numPids = -1;
     goto cleanup;
 }
 
-/*
- *----------------------------------------------------------------------
- *
- * CleanupChildren --
- *
- *  This is a utility procedure used to wait for child processes
- *  to exit, record information about abnormal exits, and then
- *  collect any stderr output generated by them.
- *
- * Results:
- *  The return value is a standard Tcl result.  If anything at
- *  weird happened with the child processes, JIM_ERROR is returned
- *  and a message is left in interp->result.
- *
- * Side effects:
- *  If the last character of interp->result is a newline, then it
- *  is removed.  File errorId gets closed, and pidPtr is freed
- *  back to the storage allocator.
- *
- *----------------------------------------------------------------------
- */
 
-static int Jim_CleanupChildren(Jim_Interp *interp, int numPids, int *pidPtr, int errorId)
+static int JimCleanupChildren(Jim_Interp *interp, int numPids, pidtype *pidPtr, fdtype errorId)
 {
     struct WaitInfoTable *table = Jim_CmdPrivData(interp);
     int result = JIM_OK;
     int i;
 
     for (i = 0; i < numPids; i++) {
         int waitStatus = 0;
-        if (JimWaitPid(table, pidPtr[i], &waitStatus) > 0) {
+        if (JimWaitForProcess(table, pidPtr[i], &waitStatus) != JIM_BAD_PID) {
             if (JimCheckWaitStatus(interp, pidPtr[i], waitStatus) != JIM_OK) {
                 result = JIM_ERR;
             }
         }
     }
     Jim_Free(pidPtr);
 
-    /*
-     * Read the standard error file.  If there's anything there,
-     * then add the file's contents to the result
-     * string.
-     */
-    if (errorId >= 0) {
+    if (errorId != JIM_BAD_FD) {
+        JimRewindFd(errorId);
         if (JimAppendStreamToString(interp, errorId, Jim_GetResult(interp)) != JIM_OK) {
-            Jim_SetResultErrno(interp, "error reading from stderr output file");
             result = JIM_ERR;
         }
-        close(errorId);
     }
 
     JimTrimTrailingNewline(interp);
 
     return result;
@@ -5871,96 +4660,486 @@
 
 int Jim_execInit(Jim_Interp *interp)
 {
     if (Jim_PackageProvide(interp, "exec", "1.0", JIM_ERRMSG))
         return JIM_ERR;
-
     Jim_CreateCommand(interp, "exec", Jim_ExecCmd, JimAllocWaitInfoTable(), JimFreeWaitInfoTable);
     return JIM_OK;
 }
-#else
-/* e.g. Windows. Poor mans implementation of exec with system()
- *      The system() call *may* do command line redirection, etc.
- *      The standard output is not available.
- *      Can't redirect filehandles.
- */
-static int Jim_ExecCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
-{
-    Jim_Obj *cmdlineObj = Jim_NewEmptyStringObj(interp);
-    int i, j;
-    int rc;
-
-    /* Create a quoted command line */
-    for (i = 1; i < argc; i++) {
-        int len;
-        const char *arg = Jim_GetString(argv[i], &len);
-
-        if (i > 1) {
-            Jim_AppendString(interp, cmdlineObj, " ", 1);
-        }
-        if (strpbrk(arg, "\\\" ") == NULL) {
-            /* No quoting required */
-            Jim_AppendString(interp, cmdlineObj, arg, len);
-            continue;
-        }
-
-        Jim_AppendString(interp, cmdlineObj, "\"", 1);
-        for (j = 0; j < len; j++) {
-            if (arg[j] == '\\' || arg[j] == '"') {
-                Jim_AppendString(interp, cmdlineObj, "\\", 1);
-            }
-            Jim_AppendString(interp, cmdlineObj, &arg[j], 1);
-        }
-        Jim_AppendString(interp, cmdlineObj, "\"", 1);
-    }
-    rc = system(Jim_String(cmdlineObj));
-
-    Jim_FreeNewObj(interp, cmdlineObj);
-
-    if (rc) {
-        Jim_Obj *errorCode = Jim_NewListObj(interp, NULL, 0);
-        Jim_ListAppendElement(interp, errorCode, Jim_NewStringObj(interp, "CHILDSTATUS", -1));
-        Jim_ListAppendElement(interp, errorCode, Jim_NewIntObj(interp, 0));
-        Jim_ListAppendElement(interp, errorCode, Jim_NewIntObj(interp, rc));
-        Jim_SetGlobalVariableStr(interp, "errorCode", errorCode);
-        return JIM_ERR;
-    }
-
-    return JIM_OK;
-}
-
-int Jim_execInit(Jim_Interp *interp)
-{
-    if (Jim_PackageProvide(interp, "exec", "1.0", JIM_ERRMSG))
-        return JIM_ERR;
-
-    Jim_CreateCommand(interp, "exec", Jim_ExecCmd, NULL, NULL);
-    return JIM_OK;
-}
-#endif
-
-/*
- * tcl_clock.c
- *
- * Implements the clock command
- */
-
-/* For strptime() */
+
+#if defined(__MINGW32__)
+
+
+static SECURITY_ATTRIBUTES *JimStdSecAttrs(void)
+{
+    static SECURITY_ATTRIBUTES secAtts;
+
+    secAtts.nLength = sizeof(SECURITY_ATTRIBUTES);
+    secAtts.lpSecurityDescriptor = NULL;
+    secAtts.bInheritHandle = TRUE;
+    return &secAtts;
+}
+
+static int JimErrno(void)
+{
+    switch (GetLastError()) {
+    case ERROR_FILE_NOT_FOUND: return ENOENT;
+    case ERROR_PATH_NOT_FOUND: return ENOENT;
+    case ERROR_TOO_MANY_OPEN_FILES: return EMFILE;
+    case ERROR_ACCESS_DENIED: return EACCES;
+    case ERROR_INVALID_HANDLE: return EBADF;
+    case ERROR_BAD_ENVIRONMENT: return E2BIG;
+    case ERROR_BAD_FORMAT: return ENOEXEC;
+    case ERROR_INVALID_ACCESS: return EACCES;
+    case ERROR_INVALID_DRIVE: return ENOENT;
+    case ERROR_CURRENT_DIRECTORY: return EACCES;
+    case ERROR_NOT_SAME_DEVICE: return EXDEV;
+    case ERROR_NO_MORE_FILES: return ENOENT;
+    case ERROR_WRITE_PROTECT: return EROFS;
+    case ERROR_BAD_UNIT: return ENXIO;
+    case ERROR_NOT_READY: return EBUSY;
+    case ERROR_BAD_COMMAND: return EIO;
+    case ERROR_CRC: return EIO;
+    case ERROR_BAD_LENGTH: return EIO;
+    case ERROR_SEEK: return EIO;
+    case ERROR_WRITE_FAULT: return EIO;
+    case ERROR_READ_FAULT: return EIO;
+    case ERROR_GEN_FAILURE: return EIO;
+    case ERROR_SHARING_VIOLATION: return EACCES;
+    case ERROR_LOCK_VIOLATION: return EACCES;
+    case ERROR_SHARING_BUFFER_EXCEEDED: return ENFILE;
+    case ERROR_HANDLE_DISK_FULL: return ENOSPC;
+    case ERROR_NOT_SUPPORTED: return ENODEV;
+    case ERROR_REM_NOT_LIST: return EBUSY;
+    case ERROR_DUP_NAME: return EEXIST;
+    case ERROR_BAD_NETPATH: return ENOENT;
+    case ERROR_NETWORK_BUSY: return EBUSY;
+    case ERROR_DEV_NOT_EXIST: return ENODEV;
+    case ERROR_TOO_MANY_CMDS: return EAGAIN;
+    case ERROR_ADAP_HDW_ERR: return EIO;
+    case ERROR_BAD_NET_RESP: return EIO;
+    case ERROR_UNEXP_NET_ERR: return EIO;
+    case ERROR_NETNAME_DELETED: return ENOENT;
+    case ERROR_NETWORK_ACCESS_DENIED: return EACCES;
+    case ERROR_BAD_DEV_TYPE: return ENODEV;
+    case ERROR_BAD_NET_NAME: return ENOENT;
+    case ERROR_TOO_MANY_NAMES: return ENFILE;
+    case ERROR_TOO_MANY_SESS: return EIO;
+    case ERROR_SHARING_PAUSED: return EAGAIN;
+    case ERROR_REDIR_PAUSED: return EAGAIN;
+    case ERROR_FILE_EXISTS: return EEXIST;
+    case ERROR_CANNOT_MAKE: return ENOSPC;
+    case ERROR_OUT_OF_STRUCTURES: return ENFILE;
+    case ERROR_ALREADY_ASSIGNED: return EEXIST;
+    case ERROR_INVALID_PASSWORD: return EPERM;
+    case ERROR_NET_WRITE_FAULT: return EIO;
+    case ERROR_NO_PROC_SLOTS: return EAGAIN;
+    case ERROR_DISK_CHANGE: return EXDEV;
+    case ERROR_BROKEN_PIPE: return EPIPE;
+    case ERROR_OPEN_FAILED: return ENOENT;
+    case ERROR_DISK_FULL: return ENOSPC;
+    case ERROR_NO_MORE_SEARCH_HANDLES: return EMFILE;
+    case ERROR_INVALID_TARGET_HANDLE: return EBADF;
+    case ERROR_INVALID_NAME: return ENOENT;
+    case ERROR_PROC_NOT_FOUND: return ESRCH;
+    case ERROR_WAIT_NO_CHILDREN: return ECHILD;
+    case ERROR_CHILD_NOT_COMPLETE: return ECHILD;
+    case ERROR_DIRECT_ACCESS_HANDLE: return EBADF;
+    case ERROR_SEEK_ON_DEVICE: return ESPIPE;
+    case ERROR_BUSY_DRIVE: return EAGAIN;
+    case ERROR_DIR_NOT_EMPTY: return EEXIST;
+    case ERROR_NOT_LOCKED: return EACCES;
+    case ERROR_BAD_PATHNAME: return ENOENT;
+    case ERROR_LOCK_FAILED: return EACCES;
+    case ERROR_ALREADY_EXISTS: return EEXIST;
+    case ERROR_FILENAME_EXCED_RANGE: return ENAMETOOLONG;
+    case ERROR_BAD_PIPE: return EPIPE;
+    case ERROR_PIPE_BUSY: return EAGAIN;
+    case ERROR_PIPE_NOT_CONNECTED: return EPIPE;
+    case ERROR_DIRECTORY: return ENOTDIR;
+    }
+    return EINVAL;
+}
+
+static int JimPipe(fdtype pipefd[2])
+{
+    if (CreatePipe(&pipefd[0], &pipefd[1], NULL, 0)) {
+        return 0;
+    }
+    return -1;
+}
+
+static fdtype JimDupFd(fdtype infd)
+{
+    fdtype dupfd;
+    pidtype pid = GetCurrentProcess();
+
+    if (DuplicateHandle(pid, infd, pid, &dupfd, 0, TRUE, DUPLICATE_SAME_ACCESS)) {
+        return dupfd;
+    }
+    return JIM_BAD_FD;
+}
+
+static int JimRewindFd(fdtype fd)
+{
+    return SetFilePointer(fd, 0, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER ? -1 : 0;
+}
+
+#if 0
+static int JimReadFd(fdtype fd, char *buffer, size_t len)
+{
+    DWORD num;
+
+    if (ReadFile(fd, buffer, len, &num, NULL)) {
+        return num;
+    }
+    if (GetLastError() == ERROR_HANDLE_EOF || GetLastError() == ERROR_BROKEN_PIPE) {
+        return 0;
+    }
+    return -1;
+}
+#endif
+
+static FILE *JimFdOpenForRead(fdtype fd)
+{
+    return _fdopen(_open_osfhandle((int)fd, _O_RDONLY | _O_TEXT), "r");
+}
+
+static fdtype JimFileno(FILE *fh)
+{
+    return (fdtype)_get_osfhandle(_fileno(fh));
+}
+
+static fdtype JimOpenForRead(const char *filename)
+{
+    return CreateFile(filename, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
+        JimStdSecAttrs(), OPEN_EXISTING, 0, NULL);
+}
+
+static fdtype JimOpenForWrite(const char *filename, int append)
+{
+    return CreateFile(filename, append ? FILE_APPEND_DATA : GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
+        JimStdSecAttrs(), append ? OPEN_ALWAYS : CREATE_ALWAYS, 0, (HANDLE) NULL);
+}
+
+static FILE *JimFdOpenForWrite(fdtype fd)
+{
+    return _fdopen(_open_osfhandle((int)fd, _O_TEXT), "w");
+}
+
+static pidtype JimWaitPid(pidtype pid, int *status, int nohang)
+{
+    DWORD ret = WaitForSingleObject(pid, nohang ? 0 : INFINITE);
+    if (ret == WAIT_TIMEOUT || ret == WAIT_FAILED) {
+        
+        return JIM_BAD_PID;
+    }
+    GetExitCodeProcess(pid, &ret);
+    *status = ret;
+    CloseHandle(pid);
+    return pid;
+}
+
+static HANDLE JimCreateTemp(Jim_Interp *interp, const char *contents)
+{
+    char name[MAX_PATH];
+    HANDLE handle;
+
+    if (!GetTempPath(MAX_PATH, name) || !GetTempFileName(name, "JIM", 0, name)) {
+        return JIM_BAD_FD;
+    }
+
+    handle = CreateFile(name, GENERIC_READ | GENERIC_WRITE, 0, JimStdSecAttrs(),
+            CREATE_ALWAYS, FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE,
+            NULL);
+
+    if (handle == INVALID_HANDLE_VALUE) {
+        goto error;
+    }
+
+    if (contents != NULL) {
+        
+        FILE *fh = JimFdOpenForWrite(JimDupFd(handle));
+        if (fh == NULL) {
+            goto error;
+        }
+
+        if (fwrite(contents, strlen(contents), 1, fh) != 1) {
+            fclose(fh);
+            goto error;
+        }
+        fseek(fh, 0, SEEK_SET);
+        fclose(fh);
+    }
+    return handle;
+
+  error:
+    Jim_SetResultErrno(interp, "failed to create temp file");
+    CloseHandle(handle);
+    DeleteFile(name);
+    return JIM_BAD_FD;
+}
+
+static int
+JimWinFindExecutable(const char *originalName, char fullPath[MAX_PATH])
+{
+    int i;
+    static char extensions[][5] = {".exe", "", ".bat"};
+
+    for (i = 0; i < (int) (sizeof(extensions) / sizeof(extensions[0])); i++) {
+        lstrcpyn(fullPath, originalName, MAX_PATH - 5);
+        lstrcat(fullPath, extensions[i]);
+
+        if (SearchPath(NULL, fullPath, NULL, MAX_PATH, fullPath, NULL) == 0) {
+            continue;
+        }
+        if (GetFileAttributes(fullPath) & FILE_ATTRIBUTE_DIRECTORY) {
+            continue;
+        }
+        return 0;
+    }
+
+    return -1;
+}
+
+static char **JimSaveEnv(char **env)
+{
+    return env;
+}
+
+static void JimRestoreEnv(char **env)
+{
+    JimFreeEnv(env, NULL);
+}
+
+static Jim_Obj *
+JimWinBuildCommandLine(Jim_Interp *interp, char **argv)
+{
+    char *start, *special;
+    int quote, i;
+
+    Jim_Obj *strObj = Jim_NewStringObj(interp, "", 0);
+
+    for (i = 0; argv[i]; i++) {
+        if (i > 0) {
+            Jim_AppendString(interp, strObj, " ", 1);
+        }
+
+        if (argv[i][0] == '\0') {
+            quote = 1;
+        }
+        else {
+            quote = 0;
+            for (start = argv[i]; *start != '\0'; start++) {
+                if (isspace(UCHAR(*start))) {
+                    quote = 1;
+                    break;
+                }
+            }
+        }
+        if (quote) {
+            Jim_AppendString(interp, strObj, "\"" , 1);
+        }
+
+        start = argv[i];
+        for (special = argv[i]; ; ) {
+            if ((*special == '\\') && (special[1] == '\\' ||
+                    special[1] == '"' || (quote && special[1] == '\0'))) {
+                Jim_AppendString(interp, strObj, start, special - start);
+                start = special;
+                while (1) {
+                    special++;
+                    if (*special == '"' || (quote && *special == '\0')) {
+
+                        Jim_AppendString(interp, strObj, start, special - start);
+                        break;
+                    }
+                    if (*special != '\\') {
+                        break;
+                    }
+                }
+                Jim_AppendString(interp, strObj, start, special - start);
+                start = special;
+            }
+            if (*special == '"') {
+        if (special == start) {
+            Jim_AppendString(interp, strObj, "\"", 1);
+        }
+        else {
+            Jim_AppendString(interp, strObj, start, special - start);
+        }
+                Jim_AppendString(interp, strObj, "\\\"", 2);
+                start = special + 1;
+            }
+            if (*special == '\0') {
+                break;
+            }
+            special++;
+        }
+        Jim_AppendString(interp, strObj, start, special - start);
+        if (quote) {
+            Jim_AppendString(interp, strObj, "\"", 1);
+        }
+    }
+    return strObj;
+}
+
+static pidtype
+JimStartWinProcess(Jim_Interp *interp, char **argv, char *env, fdtype inputId, fdtype outputId, fdtype errorId)
+{
+    STARTUPINFO startInfo;
+    PROCESS_INFORMATION procInfo;
+    HANDLE hProcess, h;
+    char execPath[MAX_PATH];
+    char *originalName;
+    pidtype pid = JIM_BAD_PID;
+    Jim_Obj *cmdLineObj;
+
+    if (JimWinFindExecutable(argv[0], execPath) < 0) {
+        return JIM_BAD_PID;
+    }
+    originalName = argv[0];
+    argv[0] = execPath;
+
+    hProcess = GetCurrentProcess();
+    cmdLineObj = JimWinBuildCommandLine(interp, argv);
+
+
+    ZeroMemory(&startInfo, sizeof(startInfo));
+    startInfo.cb = sizeof(startInfo);
+    startInfo.dwFlags   = STARTF_USESTDHANDLES;
+    startInfo.hStdInput	= INVALID_HANDLE_VALUE;
+    startInfo.hStdOutput= INVALID_HANDLE_VALUE;
+    startInfo.hStdError = INVALID_HANDLE_VALUE;
+
+    if (inputId == JIM_BAD_FD) {
+        if (CreatePipe(&startInfo.hStdInput, &h, JimStdSecAttrs(), 0) != FALSE) {
+            CloseHandle(h);
+        }
+    } else {
+        DuplicateHandle(hProcess, inputId, hProcess, &startInfo.hStdInput,
+                0, TRUE, DUPLICATE_SAME_ACCESS);
+    }
+    if (startInfo.hStdInput == JIM_BAD_FD) {
+        goto end;
+    }
+
+    if (outputId == JIM_BAD_FD) {
+        startInfo.hStdOutput = CreateFile("NUL:", GENERIC_WRITE, 0,
+                JimStdSecAttrs(), OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
+    } else {
+        DuplicateHandle(hProcess, outputId, hProcess, &startInfo.hStdOutput,
+                0, TRUE, DUPLICATE_SAME_ACCESS);
+    }
+    if (startInfo.hStdOutput == JIM_BAD_FD) {
+        goto end;
+    }
+
+    if (errorId == JIM_BAD_FD) {
+
+        startInfo.hStdError = CreateFile("NUL:", GENERIC_WRITE, 0,
+                JimStdSecAttrs(), OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+    } else {
+        DuplicateHandle(hProcess, errorId, hProcess, &startInfo.hStdError,
+                0, TRUE, DUPLICATE_SAME_ACCESS);
+    }
+    if (startInfo.hStdError == JIM_BAD_FD) {
+        goto end;
+    }
+
+    if (!CreateProcess(NULL, (char *)Jim_String(cmdLineObj), NULL, NULL, TRUE,
+            0, env, NULL, &startInfo, &procInfo)) {
+        goto end;
+    }
+
+
+    WaitForInputIdle(procInfo.hProcess, 5000);
+    CloseHandle(procInfo.hThread);
+
+    pid = procInfo.hProcess;
+
+    end:
+    Jim_FreeNewObj(interp, cmdLineObj);
+    if (startInfo.hStdInput != JIM_BAD_FD) {
+        CloseHandle(startInfo.hStdInput);
+    }
+    if (startInfo.hStdOutput != JIM_BAD_FD) {
+        CloseHandle(startInfo.hStdOutput);
+    }
+    if (startInfo.hStdError != JIM_BAD_FD) {
+        CloseHandle(startInfo.hStdError);
+    }
+    return pid;
+}
+#else
+
+static int JimOpenForWrite(const char *filename, int append)
+{
+    return open(filename, O_WRONLY | O_CREAT | (append ? O_APPEND : O_TRUNC), 0666);
+}
+
+static int JimRewindFd(int fd)
+{
+    return lseek(fd, 0L, SEEK_SET);
+}
+
+static int JimCreateTemp(Jim_Interp *interp, const char *contents)
+{
+    char inName[] = "/tmp/tcl.tmp.XXXXXX";
+
+    int fd = mkstemp(inName);
+    if (fd == JIM_BAD_FD) {
+        Jim_SetResultErrno(interp, "couldn't create temp file");
+        return -1;
+    }
+    unlink(inName);
+    if (contents) {
+        int length = strlen(contents);
+        if (write(fd, contents, length) != length) {
+            Jim_SetResultErrno(interp, "couldn't write temp file");
+            close(fd);
+            return -1;
+        }
+        lseek(fd, 0L, SEEK_SET);
+    }
+    return fd;
+}
+
+static char **JimSaveEnv(char **env)
+{
+    char **saveenv = Jim_GetEnviron();
+    Jim_SetEnviron(env);
+    return saveenv;
+}
+
+static void JimRestoreEnv(char **env)
+{
+    JimFreeEnv(Jim_GetEnviron(), env);
+    Jim_SetEnviron(env);
+}
+#endif
+#endif
+
+
+
 #ifndef _XOPEN_SOURCE
 #define _XOPEN_SOURCE 500
 #endif
 
 #include <stdlib.h>
 #include <string.h>
 #include <stdio.h>
 #include <time.h>
+
+
+#ifdef HAVE_SYS_TIME_H
 #include <sys/time.h>
-
+#endif
 
 static int clock_cmd_format(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
 {
-    /* How big is big enough? */
+    
     char buf[100];
     time_t t;
     long seconds;
 
     const char *format = "%a %b  %d %H:%M:%S %Z %Y";
@@ -5994,20 +5173,20 @@
 
     if (!Jim_CompareStringImmediate(interp, argv[1], "-format")) {
         return -1;
     }
 
-    /* Initialise with the current date/time */
+    
     localtime_r(&now, &tm);
 
     pt = strptime(Jim_String(argv[0]), Jim_String(argv[2]), &tm);
     if (pt == 0 || *pt != 0) {
         Jim_SetResultString(interp, "Failed to parse time according to format", -1);
         return JIM_ERR;
     }
 
-    /* Now convert into a time_t */
+    
     Jim_SetResultInt(interp, mktime(&tm));
 
     return JIM_OK;
 }
 #endif
@@ -6040,51 +5219,55 @@
 
     return JIM_OK;
 }
 
 static const jim_subcmd_type clock_command_table[] = {
-    {   .cmd = "seconds",
-        .function = clock_cmd_seconds,
-        .minargs = 0,
-        .maxargs = 0,
-        .description = "Returns the current time as seconds since the epoch"
+    {   "seconds",
+        NULL,
+        clock_cmd_seconds,
+        0,
+        0,
+        
+    },
+    {   "clicks",
+        NULL,
+        clock_cmd_micros,
+        0,
+        0,
+        
     },
-    {   .cmd = "clicks",
-        .function = clock_cmd_micros,
-        .minargs = 0,
-        .maxargs = 0,
-        .description = "Returns the current time in 'clicks'"
+    {   "microseconds",
+        NULL,
+        clock_cmd_micros,
+        0,
+        0,
+        
     },
-    {   .cmd = "microseconds",
-        .function = clock_cmd_micros,
-        .minargs = 0,
-        .maxargs = 0,
-        .description = "Returns the current time in microseconds"
+    {   "milliseconds",
+        NULL,
+        clock_cmd_millis,
+        0,
+        0,
+        
     },
-    {   .cmd = "milliseconds",
-        .function = clock_cmd_millis,
-        .minargs = 0,
-        .maxargs = 0,
-        .description = "Returns the current time in milliseconds"
-    },
-    {   .cmd = "format",
-        .args = "seconds ?-format format?",
-        .function = clock_cmd_format,
-        .minargs = 1,
-        .maxargs = 3,
-        .description = "Format the given time"
+    {   "format",
+        "seconds ?-format format?",
+        clock_cmd_format,
+        1,
+        3,
+        
     },
 #ifdef HAVE_STRPTIME
-    {   .cmd = "scan",
-        .args = "str -format format",
-        .function = clock_cmd_scan,
-        .minargs = 3,
-        .maxargs = 3,
-        .description = "Determine the time according to the given format"
+    {   "scan",
+        "str -format format",
+        clock_cmd_scan,
+        3,
+        3,
+        
     },
 #endif
-    { 0 }
+    { NULL }
 };
 
 int Jim_clockInit(Jim_Interp *interp)
 {
     if (Jim_PackageProvide(interp, "clock", "1.0", JIM_ERRMSG))
@@ -6092,66 +5275,21 @@
 
     Jim_CreateCommand(interp, "clock", Jim_SubCmdProc, (void *)clock_command_table, NULL);
     return JIM_OK;
 }
 
-/* 
- * Implements the array command for jim
- *
- * (c) 2008 Steve Bennett <steveb@workware.net.au>
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above
- *    copyright notice, this list of conditions and the following
- *    disclaimer in the documentation and/or other materials
- *    provided with the distribution.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE JIM TCL PROJECT ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
- * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * JIM TCL PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
- * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- * 
- * The views and conclusions contained in the software and documentation
- * are those of the authors and should not be interpreted as representing
- * official policies, either expressed or implied, of the Jim Tcl Project.
- *
- * Based on code originally from Tcl 6.7:
- *
- * Copyright 1987-1991 Regents of the University of California
- * Permission to use, copy, modify, and distribute this
- * software and its documentation for any purpose and without
- * fee is hereby granted, provided that the above copyright
- * notice appear in all copies.  The University of California
- * makes no representations about the suitability of this
- * software for any purpose.  It is provided "as is" without
- * express or implied warranty.
- */
 
 #include <limits.h>
 #include <stdlib.h>
 #include <string.h>
 #include <stdio.h>
-#include <unistd.h>
 #include <errno.h>
 
 
 static int array_cmd_exists(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
 {
-    /* Just a regular [info exists] */
+    
     Jim_SetResultInt(interp, Jim_GetVariable(interp, argv[0], 0) != 0);
     return JIM_OK;
 }
 
 static int array_cmd_get(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
@@ -6170,11 +5308,11 @@
 
     if (argc == 1 || Jim_CompareStringImmediate(interp, argv[1], "*")) {
         all = 1;
     }
 
-    /* If it is a dictionary or list with an even number of elements, nothing else to do */
+    
     if (all) {
         if (Jim_IsDict(objPtr) || (Jim_IsList(objPtr) && Jim_ListLength(interp, objPtr) % 2 == 0)) {
             Jim_SetResult(interp, objPtr);
             return JIM_OK;
         }
@@ -6187,15 +5325,15 @@
     if (Jim_DictPairs(interp, dictObj, &dictValuesObj, &len) != JIM_OK) {
         return JIM_ERR;
     }
 
     if (all) {
-        /* Return the whole array */
+        
         Jim_SetResult(interp, dictObj);
     }
     else {
-        /* Only return the matching values */
+        
         resultObj = Jim_NewListObj(interp, NULL, 0);
 
         for (i = 0; i < len; i += 2) {
             if (Jim_StringMatchObj(interp, argv[1], dictValuesObj[i], 0)) {
                 Jim_ListAppendElement(interp, resultObj, dictValuesObj[i]);
@@ -6229,11 +5367,11 @@
     Jim_Obj *objPtr;
     Jim_Obj *dictObj;
     Jim_Obj **dictValuesObj;
 
     if (argc == 1 || Jim_CompareStringImmediate(interp, argv[1], "*")) {
-        /* Unset the whole array */
+        
         Jim_UnsetVariable(interp, argv[0], JIM_NONE);
         return JIM_OK;
     }
 
     objPtr = Jim_GetVariable(interp, argv[0], JIM_NONE);
@@ -6244,11 +5382,11 @@
 
     if (Jim_DictPairs(interp, dictObj, &dictValuesObj, &len) != JIM_OK) {
         return JIM_ERR;
     }
 
-    /* Create a new object with the values which don't match */
+    
     resultObj = Jim_NewDictObj(interp, NULL, 0);
 
     for (i = 0; i < len; i += 2) {
         if (!Jim_StringMatchObj(interp, argv[1], dictValuesObj[i], 0)) {
             Jim_DictAddElement(interp, resultObj, dictValuesObj[i], dictValuesObj[i + 1]);
@@ -6263,11 +5401,11 @@
 static int array_cmd_size(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
 {
     Jim_Obj *objPtr;
     int len = 0;
 
-    /* Not found means zero length */
+    
     objPtr = Jim_GetVariable(interp, argv[0], JIM_NONE);
     if (objPtr) {
         len = Jim_DictSize(interp, objPtr);
         if (len < 0) {
             return JIM_ERR;
@@ -6285,11 +5423,11 @@
     int len;
     int rc = JIM_OK;
     Jim_Obj *listObj = argv[1];
 
     if (Jim_GetVariable(interp, argv[0], JIM_NONE) == NULL) {
-        /* Doesn't exist, so just set the list directly */
+        
         return Jim_SetVariable(interp, argv[0], listObj);
     }
 
     len = Jim_ListLength(interp, listObj);
     if (len % 2) {
@@ -6301,60 +5439,60 @@
         Jim_Obj *valueObj;
 
         Jim_ListIndex(interp, listObj, i, &nameObj, JIM_NONE);
         Jim_ListIndex(interp, listObj, i + 1, &valueObj, JIM_NONE);
 
-        rc = Jim_SetDictKeysVector(interp, argv[0], &nameObj, 1, valueObj);
+        rc = Jim_SetDictKeysVector(interp, argv[0], &nameObj, 1, valueObj, JIM_ERRMSG);
     }
 
     return rc;
 }
 
 static const jim_subcmd_type array_command_table[] = {
-        {       .cmd = "exists",
-                .args = "arrayName",
-                .function = array_cmd_exists,
-                .minargs = 1,
-                .maxargs = 1,
-                .description = "Does array exist?"
+        {       "exists",
+                "arrayName",
+                array_cmd_exists,
+                1,
+                1,
+                
+        },
+        {       "get",
+                "arrayName ?pattern?",
+                array_cmd_get,
+                1,
+                2,
+                
+        },
+        {       "names",
+                "arrayName ?pattern?",
+                array_cmd_names,
+                1,
+                2,
+                
+        },
+        {       "set",
+                "arrayName list",
+                array_cmd_set,
+                2,
+                2,
+                
         },
-        {       .cmd = "get",
-                .args = "arrayName ?pattern?",
-                .function = array_cmd_get,
-                .minargs = 1,
-                .maxargs = 2,
-                .description = "Array contents as name value list"
+        {       "size",
+                "arrayName",
+                array_cmd_size,
+                1,
+                1,
+                
         },
-        {       .cmd = "names",
-                .args = "arrayName ?pattern?",
-                .function = array_cmd_names,
-                .minargs = 1,
-                .maxargs = 2,
-                .description = "Array keys as a list"
-        },
-        {       .cmd = "set",
-                .args = "arrayName list",
-                .function = array_cmd_set,
-                .minargs = 2,
-                .maxargs = 2,
-                .description = "Set array from list"
+        {       "unset",
+                "arrayName ?pattern?",
+                array_cmd_unset,
+                1,
+                2,
+                
         },
-        {       .cmd = "size",
-                .args = "arrayName",
-                .function = array_cmd_size,
-                .minargs = 1,
-                .maxargs = 1,
-                .description = "Number of elements in array"
-        },
-        {       .cmd = "unset",
-                .args = "arrayName ?pattern?",
-                .function = array_cmd_unset,
-                .minargs = 1,
-                .maxargs = 2,
-                .description = "Unset elements of an array"
-        },
-        {       .cmd = 0,
+        {       NULL
         }
 };
 
 int Jim_arrayInit(Jim_Interp *interp)
 {
@@ -6389,53 +5527,11 @@
 Jim_stdlibInit(interp);
 Jim_tclcompatInit(interp);
 return JIM_OK;
 }
 
-/* Jim - A small embeddable Tcl interpreter
- *
- * Copyright 2005 Salvatore Sanfilippo <antirez@invece.org>
- * Copyright 2005 Clemens Hintze <c.hintze@gmx.net>
- * Copyright 2005 patthoyts - Pat Thoyts <patthoyts@users.sf.net>
- * Copyright 2008,2009 oharboe - Øyvind Harboe - oyvind.harboe@zylin.com
- * Copyright 2008 Andrew Lunn <andrew@lunn.ch>
- * Copyright 2008 Duane Ellis <openocd@duaneellis.com>
- * Copyright 2008 Uwe Klein <uklein@klein-messgeraete.de>
- * Copyright 2008 Steve Bennett <steveb@workware.net.au>
- * Copyright 2009 Nico Coesel <ncoesel@dealogic.nl>
- * Copyright 2009 Zachary T Welch zw@superlucidity.net
- * Copyright 2009 David Brownell
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above
- *    copyright notice, this list of conditions and the following
- *    disclaimer in the documentation and/or other materials
- *    provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE JIM TCL PROJECT ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
- * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * JIM TCL PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
- * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * The views and conclusions contained in the software and documentation
- * are those of the authors and should not be interpreted as representing
- * official policies, either expressed or implied, of the Jim Tcl Project.
- **/
-#define JIM_OPTIMIZATION        /* comment to avoid optimizations and reduce size */
+#define JIM_OPTIMIZATION        
 
 #include <stdio.h>
 #include <stdlib.h>
 
 #include <string.h>
@@ -6445,28 +5541,28 @@
 #include <assert.h>
 #include <errno.h>
 #include <time.h>
 #include <setjmp.h>
 
-#include <unistd.h>
+
+#ifdef HAVE_SYS_TIME_H
 #include <sys/time.h>
-
-
+#endif
 #ifdef HAVE_BACKTRACE
 #include <execinfo.h>
 #endif
 #ifdef HAVE_CRT_EXTERNS_H
 #include <crt_externs.h>
 #endif
 
-/* For INFINITY, even if math functions are not enabled */
+
 #include <math.h>
 
-/* We may decide to switch to using $[...] after all, so leave it as an option */
-/*#define EXPRSUGAR_BRACKET*/
 
-/* For the no-autoconf case */
+
+
+
 #ifndef TCL_LIBRARY
 #define TCL_LIBRARY "."
 #endif
 #ifndef TCL_PLATFORM_OS
 #define TCL_PLATFORM_OS "unknown"
@@ -6476,67 +5572,59 @@
 #endif
 #ifndef TCL_PLATFORM_PATH_SEPARATOR
 #define TCL_PLATFORM_PATH_SEPARATOR ":"
 #endif
 
-/*#define DEBUG_SHOW_SCRIPT*/
-/*#define DEBUG_SHOW_SCRIPT_TOKENS*/
-/*#define DEBUG_SHOW_SUBST*/
-/*#define DEBUG_SHOW_EXPR*/
-/*#define DEBUG_SHOW_EXPR_TOKENS*/
-/*#define JIM_DEBUG_GC*/
+
+
+
+
+
+
 #ifdef JIM_MAINTAINER
 #define JIM_DEBUG_COMMAND
 #define JIM_DEBUG_PANIC
 #endif
 
 const char *jim_tt_name(int type);
 
 #ifdef JIM_DEBUG_PANIC
-static void JimPanicDump(int panic_condition, Jim_Interp *interp, const char *fmt, ...);
+static void JimPanicDump(int panic_condition, const char *fmt, ...);
 #define JimPanic(X) JimPanicDump X
 #else
 #define JimPanic(X)
 #endif
 
-/* -----------------------------------------------------------------------------
- * Global variables
- * ---------------------------------------------------------------------------*/
 
-/* A shared empty string for the objects string representation.
- * Jim_InvalidateStringRep knows about it and doesn't try to free it. */
 static char JimEmptyStringRep[] = "";
 
-/* -----------------------------------------------------------------------------
- * Required prototypes of not exported functions
- * ---------------------------------------------------------------------------*/
 static void JimChangeCallFrameId(Jim_Interp *interp, Jim_CallFrame *cf);
 static void JimFreeCallFrame(Jim_Interp *interp, Jim_CallFrame *cf, int flags);
 static int ListSetIndex(Jim_Interp *interp, Jim_Obj *listPtr, int listindex, Jim_Obj *newObjPtr,
     int flags);
 static Jim_Obj *JimExpandDictSugar(Jim_Interp *interp, Jim_Obj *objPtr);
 static void SetDictSubstFromAny(Jim_Interp *interp, Jim_Obj *objPtr);
 static void JimSetFailedEnumResult(Jim_Interp *interp, const char *arg, const char *badtype,
     const char *prefix, const char *const *tablePtr, const char *name);
 static void JimDeleteLocalProcs(Jim_Interp *interp);
-static int JimCallProcedure(Jim_Interp *interp, Jim_Cmd *cmd, const char *filename, int linenr,
+static int JimCallProcedure(Jim_Interp *interp, Jim_Cmd *cmd, Jim_Obj *fileNameObj, int linenr,
     int argc, Jim_Obj *const *argv);
 static int JimEvalObjVector(Jim_Interp *interp, int objc, Jim_Obj *const *objv,
-    const char *filename, int linenr);
+    Jim_Obj *fileNameObj, int linenr);
 static int JimGetWideNoErr(Jim_Interp *interp, Jim_Obj *objPtr, jim_wide * widePtr);
 static int JimSign(jim_wide w);
 static int JimValidName(Jim_Interp *interp, const char *type, Jim_Obj *nameObjPtr);
 static void JimPrngSeed(Jim_Interp *interp, unsigned char *seed, int seedLen);
 static void JimRandomBytes(Jim_Interp *interp, void *dest, unsigned int len);
 
 
 static const Jim_HashTableType JimVariablesHashTableType;
 
-/* Fast access to the int (wide) value of an object which is known to be of int type */
+
 #define JimWideValue(objPtr) (objPtr)->internalRep.wideValue
 
-#define JimObjTypeName(O) (objPtr->typePtr ? objPtr->typePtr->name : "none")
+#define JimObjTypeName(O) ((O)->typePtr ? (O)->typePtr->name : "none")
 
 static int utf8_tounicode_case(const char *s, int *uc, int upper)
 {
     int l = utf8_tounicode(s, uc);
     if (upper) {
@@ -6543,30 +5631,14 @@
         *uc = utf8_upper(*uc);
     }
     return l;
 }
 
-/* These can be used in addition to JIM_CASESENS/JIM_NOCASE */
+
 #define JIM_CHARSET_SCAN 2
 #define JIM_CHARSET_GLOB 0
 
-/**
- * pattern points to a string like "[^a-z\ub5]"
- *
- * The pattern may contain trailing chars, which are ignored.
- *
- * The pattern is matched against unicode char 'c'.
- *
- * If (flags & JIM_NOCASE), case is ignored when matching.
- * If (flags & JIM_CHARSET_SCAN), the considers ^ and ] special at the start
- * of the charset, per scan, rather than glob/string match.
- *
- * If the unicode char 'c' matches that set, returns a pointer to the ']' character,
- * or the null character if the ']' is missing.
- *
- * Returns NULL on no match.
- */
 static const char *JimCharsetMatch(const char *pattern, int c, int flags)
 {
     int not = 0;
     int pchar;
     int match = 0;
@@ -6581,34 +5653,34 @@
         if (*pattern == '^') {
             not++;
             pattern++;
         }
 
-        /* Special case. If the first char is ']', it is part of the set */
+        
         if (*pattern == ']') {
             goto first;
         }
     }
 
     while (*pattern && *pattern != ']') {
-        /* Exact match */
+        
         if (pattern[0] == '\\') {
 first:
             pattern += utf8_tounicode_case(pattern, &pchar, nocase);
         }
         else {
-            /* Is this a range? a-z */
+            
             int start;
             int end;
 
             pattern += utf8_tounicode_case(pattern, &start, nocase);
             if (pattern[0] == '-' && pattern[1]) {
-                /* skip '-' */
+                
                 pattern += utf8_tounicode(pattern, &pchar);
                 pattern += utf8_tounicode_case(pattern, &end, nocase);
 
-                /* Handle reversed range too */
+                
                 if ((c >= start && c <= end) || (c >= end && c <= start)) {
                     match = 1;
                 }
                 continue;
             }
@@ -6624,15 +5696,12 @@
     }
 
     return match ? pattern : NULL;
 }
 
-/* Glob-style pattern matching. */
 
-/* Note: string *must* be valid UTF-8 sequences
- *       slen is a char length, not byte counts.
- */
+
 static int GlobMatch(const char *pattern, const char *string, int nocase)
 {
     int c;
     int pchar;
     while (*pattern) {
@@ -6641,19 +5710,19 @@
                 while (pattern[1] == '*') {
                     pattern++;
                 }
                 pattern++;
                 if (!pattern[0]) {
-                    return 1;   /* match */
+                    return 1;   
                 }
                 while (*string) {
-                    /* Recursive call - Does the remaining pattern match anywhere? */
+                    
                     if (GlobMatch(pattern, string, nocase))
-                        return 1;       /* match */
+                        return 1;       
                     string += utf8_tounicode(string, &c);
                 }
-                return 0;       /* no match */
+                return 0;       
 
             case '?':
                 string += utf8_tounicode(string, &c);
                 break;
 
@@ -6662,20 +5731,20 @@
                     pattern = JimCharsetMatch(pattern + 1, c, nocase ? JIM_NOCASE : 0);
                     if (!pattern) {
                         return 0;
                     }
                     if (!*pattern) {
-                        /* Ran out of pattern (no ']') */
+                        
                         continue;
                     }
                     break;
                 }
             case '\\':
                 if (pattern[1]) {
                     pattern++;
                 }
-                /* fall through */
+                
             default:
                 string += utf8_tounicode_case(string, &c, nocase);
                 utf8_tounicode_case(pattern, &pchar, nocase);
                 if (pchar != c) {
                     return 0;
@@ -6699,15 +5768,10 @@
 static int JimStringMatch(Jim_Interp *interp, Jim_Obj *patternObj, const char *string, int nocase)
 {
     return GlobMatch(Jim_String(patternObj), string, nocase);
 }
 
-/**
- * string comparison works on binary data.
- *
- * Note that the lengths are byte lengths, not char lengths.
- */
 static int JimStringCompare(const char *s1, int l1, const char *s2, int l2)
 {
     if (l1 < l2) {
         return memcmp(s1, s2, l1) <= 0 ? -1 : 1;
     }
@@ -6717,16 +5781,10 @@
     else {
         return JimSign(memcmp(s1, s2, l1));
     }
 }
 
-/**
- * No-case version.
- *
- * If maxchars is -1, compares to end of string.
- * Otherwise compares at most 'maxchars' characters.
- */
 static int JimStringCompareNoCase(const char *s1, const char *s2, int maxchars)
 {
     while (*s1 && *s2 && maxchars) {
         int c1, c2;
         s1 += utf8_tounicode_case(s1, &c1, 1);
@@ -6737,23 +5795,20 @@
         maxchars--;
     }
     if (!maxchars) {
         return 0;
     }
-    /* One string or both terminated */
+    
     if (*s1) {
         return 1;
     }
     if (*s2) {
         return -1;
     }
     return 0;
 }
 
-/* Search 's1' inside 's2', starting to search from char 'index' of 's2'.
- * The index of the first occurrence of s1 in s2 is returned.
- * If s1 is not found inside s2, -1 is returned. */
 static int JimStringFirst(const char *s1, int l1, const char *s2, int l2, int idx)
 {
     int i;
     int l1bytelen;
 
@@ -6774,33 +5829,27 @@
         s2 += utf8_tounicode(s2, &c);
     }
     return -1;
 }
 
-/**
- * Note: Lengths and return value are in bytes, not chars.
- */
 static int JimStringLast(const char *s1, int l1, const char *s2, int l2)
 {
     const char *p;
 
     if (!l1 || !l2 || l1 > l2)
         return -1;
 
-    /* Now search for the needle */
+    
     for (p = s2 + l2 - 1; p != s2 - 1; p--) {
         if (*p == *s1 && memcmp(s1, p, l1) == 0) {
             return p - s2;
         }
     }
     return -1;
 }
 
 #ifdef JIM_UTF8
-/**
- * Note: Lengths and return value are in chars.
- */
 static int JimStringLastUtf8(const char *s1, int l1, const char *s2, int l2)
 {
     int n = JimStringLast(s1, utf8_index(s1, l1), s2, utf8_index(s2, l2));
     if (n > 0) {
         n = utf8_strlen(s2, n);
@@ -6814,17 +5863,10 @@
     const char *fmt = "%" JIM_WIDE_MODIFIER;
 
     return sprintf(buf, fmt, wideValue);
 }
 
-/**
- * After an strtol()/strtod()-like conversion,
- * check whether something was converted and that
- * the only thing left is white space.
- *
- * Returns JIM_OK or JIM_ERR.
- */
 static int JimCheckConversion(const char *str, const char *endptr)
 {
     if (str[0] == '\0' || str == endptr) {
         return JIM_ERR;
     }
@@ -6854,20 +5896,18 @@
     int len;
     char *buf0 = buf;
 
     len = sprintf(buf, "%.12g", doubleValue);
 
-    /* Add a final ".0" if it's a number. But not
-     * for NaN or InF */
     while (*buf) {
         if (*buf == '.' || isalpha(UCHAR(*buf))) {
-            /* inf -> Inf, nan -> Nan */
+            
             if (*buf == 'i' || *buf == 'n') {
                 *buf = toupper(UCHAR(*buf));
             }
             if (*buf == 'I') {
-                /* Infinity -> Inf */
+                
                 buf[3] = '\0';
                 len = buf - buf0 + 3;
             }
             return len;
         }
@@ -6883,11 +5923,11 @@
 
 int Jim_StringToDouble(const char *str, double *doublePtr)
 {
     char *endptr;
 
-    /* Callers can check for underflow via ERANGE */
+    
     errno = 0;
 
     *doublePtr = strtod(str, &endptr);
 
     return JimCheckConversion(str, endptr);
@@ -6903,29 +5943,21 @@
         res *= b;
     }
     return res;
 }
 
-/* -----------------------------------------------------------------------------
- * Special functions
- * ---------------------------------------------------------------------------*/
 #ifdef JIM_DEBUG_PANIC
-/* Note that 'interp' may be NULL if not available in the
- * context of the panic. It's only useful to get the error
- * file descriptor, it will default to stderr otherwise. */
-void JimPanicDump(int condition, Jim_Interp *interp, const char *fmt, ...)
+void JimPanicDump(int condition, const char *fmt, ...)
 {
     va_list ap;
 
     if (!condition) {
         return;
     }
 
     va_start(ap, fmt);
-    /*
-     * Send it here first.. Assuming STDIO still works
-     */
+
     fprintf(stderr, JIM_NL "JIM INTERPRETER PANIC: ");
     vfprintf(stderr, fmt, ap);
     fprintf(stderr, JIM_NL JIM_NL);
     va_end(ap);
 
@@ -6946,13 +5978,10 @@
 
     abort();
 }
 #endif
 
-/* -----------------------------------------------------------------------------
- * Memory allocation
- * ---------------------------------------------------------------------------*/
 
 void *Jim_Alloc(int size)
 {
     return malloc(size);
 }
@@ -6975,39 +6004,33 @@
 char *Jim_StrDupLen(const char *s, int l)
 {
     char *copy = Jim_Alloc(l + 1);
 
     memcpy(copy, s, l + 1);
-    copy[l] = 0;                /* Just to be sure, original could be substring */
+    copy[l] = 0;                
     return copy;
 }
 
-/* -----------------------------------------------------------------------------
- * Time related functions
- * ---------------------------------------------------------------------------*/
 
-/* Returns microseconds of CPU used since start. */
+
 static jim_wide JimClock(void)
 {
     struct timeval tv;
 
     gettimeofday(&tv, NULL);
     return (jim_wide) tv.tv_sec * 1000000 + tv.tv_usec;
 }
 
-/* -----------------------------------------------------------------------------
- * Hash Tables
- * ---------------------------------------------------------------------------*/
 
-/* -------------------------- private prototypes ---------------------------- */
+
 static int JimExpandHashTableIfNeeded(Jim_HashTable *ht);
 static unsigned int JimHashTableNextPower(unsigned int size);
 static int JimInsertHashEntry(Jim_HashTable *ht, const void *key);
 
-/* -------------------------- hash functions -------------------------------- */
 
-/* Thomas Wang's 32 bit Mix Function */
+
+
 unsigned int Jim_IntHashFunction(unsigned int key)
 {
     key += ~(key << 15);
     key ^= (key >> 10);
     key += (key << 3);
@@ -7015,161 +6038,146 @@
     key += ~(key << 11);
     key ^= (key >> 16);
     return key;
 }
 
-/* Generic hash function (we are using to multiply by 9 and add the byte
- * as Tcl) */
 unsigned int Jim_GenHashFunction(const unsigned char *buf, int len)
 {
     unsigned int h = 0;
 
     while (len--)
         h += (h << 3) + *buf++;
     return h;
 }
 
-/* ----------------------------- API implementation ------------------------- */
 
-/* reset a hashtable already initialized with ht_init().
- * NOTE: This function should only called by ht_destroy(). */
+
 static void JimResetHashTable(Jim_HashTable *ht)
 {
     ht->table = NULL;
     ht->size = 0;
     ht->sizemask = 0;
     ht->used = 0;
     ht->collisions = 0;
 }
 
-/* Initialize the hash table */
+
 int Jim_InitHashTable(Jim_HashTable *ht, const Jim_HashTableType *type, void *privDataPtr)
 {
     JimResetHashTable(ht);
     ht->type = type;
     ht->privdata = privDataPtr;
     return JIM_OK;
 }
 
-/* Resize the table to the minimal size that contains all the elements,
- * but with the invariant of a USER/BUCKETS ration near to <= 1 */
 int Jim_ResizeHashTable(Jim_HashTable *ht)
 {
     int minimal = ht->used;
 
     if (minimal < JIM_HT_INITIAL_SIZE)
         minimal = JIM_HT_INITIAL_SIZE;
     return Jim_ExpandHashTable(ht, minimal);
 }
 
-/* Expand or create the hashtable */
+
 int Jim_ExpandHashTable(Jim_HashTable *ht, unsigned int size)
 {
-    Jim_HashTable n;            /* the new hashtable */
+    Jim_HashTable n;            
     unsigned int realsize = JimHashTableNextPower(size), i;
 
-    /* the size is invalid if it is smaller than the number of
-     * elements already inside the hashtable */
     if (ht->used >= size)
         return JIM_ERR;
 
     Jim_InitHashTable(&n, ht->type, ht->privdata);
     n.size = realsize;
     n.sizemask = realsize - 1;
     n.table = Jim_Alloc(realsize * sizeof(Jim_HashEntry *));
 
-    /* Initialize all the pointers to NULL */
+    
     memset(n.table, 0, realsize * sizeof(Jim_HashEntry *));
 
-    /* Copy all the elements from the old to the new table:
-     * note that if the old hash table is empty ht->size is zero,
-     * so Jim_ExpandHashTable just creates an hash table. */
     n.used = ht->used;
-    for (i = 0; i < ht->size && ht->used > 0; i++) {
+    for (i = 0; ht->used > 0; i++) {
         Jim_HashEntry *he, *nextHe;
 
         if (ht->table[i] == NULL)
             continue;
 
-        /* For each hash entry on this slot... */
+        
         he = ht->table[i];
         while (he) {
             unsigned int h;
 
             nextHe = he->next;
-            /* Get the new element index */
+            
             h = Jim_HashKey(ht, he->key) & n.sizemask;
             he->next = n.table[h];
             n.table[h] = he;
             ht->used--;
-            /* Pass to the next element */
+            
             he = nextHe;
         }
     }
     assert(ht->used == 0);
     Jim_Free(ht->table);
 
-    /* Remap the new hashtable in the old */
+    
     *ht = n;
     return JIM_OK;
 }
 
-/* Add an element to the target hash table */
+
 int Jim_AddHashEntry(Jim_HashTable *ht, const void *key, void *val)
 {
     int idx;
     Jim_HashEntry *entry;
 
-    /* Get the index of the new element, or -1 if
-     * the element already exists. */
     if ((idx = JimInsertHashEntry(ht, key)) == -1)
         return JIM_ERR;
 
-    /* Allocates the memory and stores key */
+    
     entry = Jim_Alloc(sizeof(*entry));
     entry->next = ht->table[idx];
     ht->table[idx] = entry;
 
-    /* Set the hash entry fields. */
+    
     Jim_SetHashKey(ht, entry, key);
     Jim_SetHashVal(ht, entry, val);
     ht->used++;
     return JIM_OK;
 }
 
-/* Add an element, discarding the old if the key already exists */
+
 int Jim_ReplaceHashEntry(Jim_HashTable *ht, const void *key, void *val)
 {
     Jim_HashEntry *entry;
 
-    /* Try to add the element. If the key
-     * does not exists Jim_AddHashEntry will suceed. */
     if (Jim_AddHashEntry(ht, key, val) == JIM_OK)
         return JIM_OK;
-    /* It already exists, get the entry */
+    
     entry = Jim_FindHashEntry(ht, key);
-    /* Free the old value and set the new one */
+    
     Jim_FreeEntryVal(ht, entry);
     Jim_SetHashVal(ht, entry, val);
     return JIM_OK;
 }
 
-/* Search and remove an element */
+
 int Jim_DeleteHashEntry(Jim_HashTable *ht, const void *key)
 {
     unsigned int h;
     Jim_HashEntry *he, *prevHe;
 
-    if (ht->size == 0)
+    if (ht->used == 0)
         return JIM_ERR;
     h = Jim_HashKey(ht, key) & ht->sizemask;
     he = ht->table[h];
 
     prevHe = NULL;
     while (he) {
         if (Jim_CompareHashKeys(ht, key, he->key)) {
-            /* Unlink the element from the list */
+            
             if (prevHe)
                 prevHe->next = he->next;
             else
                 ht->table[h] = he->next;
             Jim_FreeEntryKey(ht, he);
@@ -7179,20 +6187,20 @@
             return JIM_OK;
         }
         prevHe = he;
         he = he->next;
     }
-    return JIM_ERR;             /* not found */
+    return JIM_ERR;             
 }
 
-/* Destroy an entire hash table */
+
 int Jim_FreeHashTable(Jim_HashTable *ht)
 {
     unsigned int i;
 
-    /* Free all the elements */
-    for (i = 0; i < ht->size && ht->used > 0; i++) {
+    
+    for (i = 0; ht->used > 0; i++) {
         Jim_HashEntry *he, *nextHe;
 
         if ((he = ht->table[i]) == NULL)
             continue;
         while (he) {
@@ -7202,23 +6210,23 @@
             Jim_Free(he);
             ht->used--;
             he = nextHe;
         }
     }
-    /* Free the table and the allocated cache structure */
+    
     Jim_Free(ht->table);
-    /* Re-initialize the table */
+    
     JimResetHashTable(ht);
-    return JIM_OK;              /* never fails */
+    return JIM_OK;              
 }
 
 Jim_HashEntry *Jim_FindHashEntry(Jim_HashTable *ht, const void *key)
 {
     Jim_HashEntry *he;
     unsigned int h;
 
-    if (ht->size == 0)
+    if (ht->used == 0)
         return NULL;
     h = Jim_HashKey(ht, key) & ht->sizemask;
     he = ht->table[h];
     while (he) {
         if (Jim_CompareHashKeys(ht, key, he->key))
@@ -7250,34 +6258,30 @@
         }
         else {
             iter->entry = iter->nextEntry;
         }
         if (iter->entry) {
-            /* We need to save the 'next' here, the iterator user
-             * may delete the entry we are returning. */
             iter->nextEntry = iter->entry->next;
             return iter->entry;
         }
     }
     return NULL;
 }
 
-/* ------------------------- private functions ------------------------------ */
 
-/* Expand the hash table if needed */
+
+
 static int JimExpandHashTableIfNeeded(Jim_HashTable *ht)
 {
-    /* If the hash table is empty expand it to the intial size,
-     * if the table is "full" dobule its size. */
     if (ht->size == 0)
         return Jim_ExpandHashTable(ht, JIM_HT_INITIAL_SIZE);
     if (ht->size == ht->used)
         return Jim_ExpandHashTable(ht, ht->size * 2);
     return JIM_OK;
 }
 
-/* Our hash table capability is a power of two */
+
 static unsigned int JimHashTableNextPower(unsigned int size)
 {
     unsigned int i = JIM_HT_INITIAL_SIZE;
 
     if (size >= 2147483648U)
@@ -7287,34 +6291,31 @@
             return i;
         i *= 2;
     }
 }
 
-/* Returns the index of a free slot that can be populated with
- * an hash entry for the given 'key'.
- * If the key already exists, -1 is returned. */
 static int JimInsertHashEntry(Jim_HashTable *ht, const void *key)
 {
     unsigned int h;
     Jim_HashEntry *he;
 
-    /* Expand the hashtable if needed */
+    
     if (JimExpandHashTableIfNeeded(ht) == JIM_ERR)
         return -1;
-    /* Compute the key hash value */
+    
     h = Jim_HashKey(ht, key) & ht->sizemask;
-    /* Search if this slot does not already contain the given key */
+    
     he = ht->table[h];
     while (he) {
         if (Jim_CompareHashKeys(ht, key, he->key))
             return -1;
         he = he->next;
     }
     return h;
 }
 
-/* ----------------------- StringCopy Hash Table Type ------------------------*/
+
 
 static unsigned int JimStringCopyHTHashFunction(const void *key)
 {
     return Jim_GenHashFunction(key, strlen(key));
 }
@@ -7352,51 +6353,47 @@
 
 static void JimStringCopyHTKeyDestructor(void *privdata, const void *key)
 {
     JIM_NOTUSED(privdata);
 
-    Jim_Free((void *)key);      /* ATTENTION: const cast */
+    Jim_Free((void *)key);      
 }
 
 static void JimStringKeyValCopyHTValDestructor(void *privdata, void *val)
 {
     JIM_NOTUSED(privdata);
 
-    Jim_Free((void *)val);      /* ATTENTION: const cast */
+    Jim_Free((void *)val);      
 }
 
 #if 0
 static Jim_HashTableType JimStringCopyHashTableType = {
-    JimStringCopyHTHashFunction,        /* hash function */
-    JimStringCopyHTKeyDup,      /* key dup */
-    NULL,                       /* val dup */
-    JimStringCopyHTKeyCompare,  /* key compare */
-    JimStringCopyHTKeyDestructor,       /* key destructor */
-    NULL                        /* val destructor */
+    JimStringCopyHTHashFunction,        
+    JimStringCopyHTKeyDup,      
+    NULL,                       
+    JimStringCopyHTKeyCompare,  
+    JimStringCopyHTKeyDestructor,       
+    NULL                        
 };
 #endif
 
-/* This is like StringCopy but does not auto-duplicate the key.
- * It's used for intepreter's shared strings. */
 static const Jim_HashTableType JimSharedStringsHashTableType = {
-    JimStringCopyHTHashFunction,        /* hash function */
-    NULL,                       /* key dup */
-    NULL,                       /* val dup */
-    JimStringCopyHTKeyCompare,  /* key compare */
-    JimStringCopyHTKeyDestructor,       /* key destructor */
-    NULL                        /* val destructor */
+    JimStringCopyHTHashFunction,        
+    NULL,                       
+    NULL,                       
+    JimStringCopyHTKeyCompare,  
+    JimStringCopyHTKeyDestructor,       
+    NULL                        
 };
 
-/* This is like StringCopy but also automatically handle dynamic
- * allocated C strings as values. */
 static const Jim_HashTableType JimStringKeyValCopyHashTableType = {
-    JimStringCopyHTHashFunction,        /* hash function */
-    JimStringCopyHTKeyDup,      /* key dup */
-    JimStringKeyValCopyHTValDup,        /* val dup */
-    JimStringCopyHTKeyCompare,  /* key compare */
-    JimStringCopyHTKeyDestructor,       /* key destructor */
-    JimStringKeyValCopyHTValDestructor, /* val destructor */
+    JimStringCopyHTHashFunction,        
+    JimStringCopyHTKeyDup,      
+    JimStringKeyValCopyHTValDup,        
+    JimStringCopyHTKeyCompare,  
+    JimStringCopyHTKeyDestructor,       
+    JimStringKeyValCopyHTValDestructor, 
 };
 
 typedef struct AssocDataValue
 {
     Jim_InterpDeleteProc *delProc;
@@ -7411,22 +6408,18 @@
         assocPtr->delProc((Jim_Interp *)privdata, assocPtr->data);
     Jim_Free(data);
 }
 
 static const Jim_HashTableType JimAssocDataHashTableType = {
-    JimStringCopyHTHashFunction,        /* hash function */
-    JimStringCopyHTKeyDup,      /* key dup */
-    NULL,                       /* val dup */
-    JimStringCopyHTKeyCompare,  /* key compare */
-    JimStringCopyHTKeyDestructor,       /* key destructor */
-    JimAssocDataHashTableValueDestructor        /* val destructor */
+    JimStringCopyHTHashFunction,        
+    JimStringCopyHTKeyDup,      
+    NULL,                       
+    JimStringCopyHTKeyCompare,  
+    JimStringCopyHTKeyDestructor,       
+    JimAssocDataHashTableValueDestructor        
 };
 
-/* -----------------------------------------------------------------------------
- * Stack - This is a simple generic stack implementation. It is used for
- * example in the 'expr' expression compiler.
- * ---------------------------------------------------------------------------*/
 void Jim_InitStack(Jim_Stack *stack)
 {
     stack->len = 0;
     stack->maxlen = 0;
     stack->vector = NULL;
@@ -7475,71 +6468,64 @@
 
     for (i = 0; i < stack->len; i++)
         freeFunc(stack->vector[i]);
 }
 
-/* -----------------------------------------------------------------------------
- * Parser
- * ---------------------------------------------------------------------------*/
 
-/* Token types */
-#define JIM_TT_NONE    0           /* No token returned */
-#define JIM_TT_STR     1          /* simple string */
-#define JIM_TT_ESC     2          /* string that needs escape chars conversion */
-#define JIM_TT_VAR     3          /* var substitution */
-#define JIM_TT_DICTSUGAR   4      /* Syntax sugar for [dict get], $foo(bar) */
-#define JIM_TT_CMD     5          /* command substitution */
-/* Note: Keep these three together for TOKEN_IS_SEP() */
-#define JIM_TT_SEP     6          /* word separator. arg is # of tokens. -ve if {*} */
-#define JIM_TT_EOL     7          /* line separator */
-#define JIM_TT_EOF     8          /* end of script */
 
-#define JIM_TT_LINE    9          /* special 'start-of-line' token. arg is # of arguments to the command. -ve if {*} */
-#define JIM_TT_WORD   10          /* special 'start-of-word' token. arg is # of tokens to combine. -ve if {*} */
+#define JIM_TT_NONE    0           
+#define JIM_TT_STR     1          
+#define JIM_TT_ESC     2          
+#define JIM_TT_VAR     3          
+#define JIM_TT_DICTSUGAR   4      
+#define JIM_TT_CMD     5          
 
-/* Additional token types needed for expressions */
+#define JIM_TT_SEP     6          
+#define JIM_TT_EOL     7          
+#define JIM_TT_EOF     8          
+
+#define JIM_TT_LINE    9          
+#define JIM_TT_WORD   10          
+
+
 #define JIM_TT_SUBEXPR_START  11
 #define JIM_TT_SUBEXPR_END    12
-#define JIM_TT_EXPR_INT       13
-#define JIM_TT_EXPR_DOUBLE    14
+#define JIM_TT_SUBEXPR_COMMA  13
+#define JIM_TT_EXPR_INT       14
+#define JIM_TT_EXPR_DOUBLE    15
 
-#define JIM_TT_EXPRSUGAR      15  /* $(expression) */
+#define JIM_TT_EXPRSUGAR      16  
 
-/* Operator token types start here */
+
 #define JIM_TT_EXPR_OP        20
 
 #define TOKEN_IS_SEP(type) (type >= JIM_TT_SEP && type <= JIM_TT_EOF)
 
-/* Parser states */
-#define JIM_PS_DEF 0            /* Default state */
-#define JIM_PS_QUOTE 1          /* Inside "" */
-#define JIM_PS_DICTSUGAR 2      /* Tokenising abc(def) into 4 separate tokens */
 
-/* Parser context structure. The same context is used both to parse
- * Tcl scripts and lists. */
+#define JIM_PS_DEF 0            
+#define JIM_PS_QUOTE 1          
+#define JIM_PS_DICTSUGAR 2      
+
 struct JimParserCtx
 {
-    const char *p;              /* Pointer to the point of the program we are parsing */
-    int len;                    /* Remaining length */
-    int linenr;                 /* Current line number */
+    const char *p;              
+    int len;                    
+    int linenr;                 
     const char *tstart;
-    const char *tend;           /* Returned token is at tstart-tend in 'prg'. */
-    int tline;                  /* Line number of the returned token */
-    int tt;                     /* Token type */
-    int eof;                    /* Non zero if EOF condition is true. */
-    int state;                  /* Parser state */
-    int comment;                /* Non zero if the next chars may be a comment. */
-    char missing;               /* At end of parse, ' ' if complete, '{' if braces incomplete, '"' if quotes incomplete */
-    int missingline;            /* Line number starting the missing token */
+    const char *tend;           
+    int tline;                  
+    int tt;                     
+    int eof;                    
+    int state;                  
+    int comment;                
+    char missing;               
+    int missingline;            
 };
 
-/**
- * Results of missing quotes, braces, etc. from parsing.
- */
 struct JimParseResult {
-    char missing;               /* From JimParserCtx.missing */
-    int line;                   /* From JimParserCtx.missingline */
+    char missing;               
+    int line;                   
 };
 
 static int JimParseScript(struct JimParserCtx *pc);
 static int JimParseSep(struct JimParserCtx *pc);
 static int JimParseEol(struct JimParserCtx *pc);
@@ -7552,13 +6538,10 @@
 static void JimParseSubCmd(struct JimParserCtx *pc);
 static int JimParseSubQuote(struct JimParserCtx *pc);
 static void JimParseSubCmd(struct JimParserCtx *pc);
 static Jim_Obj *JimParserGetTokenObj(Jim_Interp *interp, struct JimParserCtx *pc);
 
-/* Initialize a parser context.
- * 'prg' is a pointer to the program text, linenr is the line
- * number of the first line contained in the program. */
 static void JimParserInit(struct JimParserCtx *pc, const char *prg, int len, int linenr)
 {
     pc->p = prg;
     pc->len = len;
     pc->tstart = NULL;
@@ -7573,11 +6556,11 @@
     pc->missingline = linenr;
 }
 
 static int JimParseScript(struct JimParserCtx *pc)
 {
-    while (1) {                 /* the while is used to reiterate with continue if needed */
+    while (1) {                 
         if (!pc->len) {
             pc->tstart = pc->p;
             pc->tend = pc->p - 1;
             pc->tline = pc->linenr;
             pc->tt = JIM_TT_EOL;
@@ -7677,43 +6660,16 @@
     pc->tend = pc->p - 1;
     pc->tt = JIM_TT_EOL;
     return JIM_OK;
 }
 
-/*
-** Here are the rules for parsing:
-** {braced expression}
-** - Count open and closing braces
-** - Backslash escapes meaning of braces
-**
-** "quoted expression"
-** - First double quote at start of word terminates the expression
-** - Backslash escapes quote and bracket
-** - [commands brackets] are counted/nested
-** - command rules apply within [brackets], not quoting rules (i.e. quotes have their own rules)
-** 
-** [command expression]
-** - Count open and closing brackets
-** - Backslash escapes quote, bracket and brace
-** - [commands brackets] are counted/nested
-** - "quoted expressions" are parsed according to quoting rules
-** - {braced expressions} are parsed according to brace rules
-**
-** For everything, backslash escapes the next char, newline increments current line
-*/
 
-/**
- * Parses a braced expression starting at pc->p.
- * 
- * Positions the parser at the end of the braced expression,
- * sets pc->tend and possibly pc->missing.
- */
 static void JimParseSubBrace(struct JimParserCtx *pc)
 {
     int level = 1;
 
-    /* Skip the brace */
+    
     pc->p++;
     pc->len--;
     while (pc->len) {
         switch (*pc->p) {
             case '\\':
@@ -7748,26 +6704,16 @@
     pc->missing = '{';
     pc->missingline = pc->tline;
     pc->tend = pc->p - 1;
 }
 
-/**
- * Parses a quoted expression starting at pc->p.
- * 
- * Positions the parser at the end of the quoted expression,
- * sets pc->tend and possibly pc->missing.
- *
- * Returns the type of the token of the string,
- * either JIM_TT_ESC (if it contains values which need to be [subst]ed)
- * or JIM_TT_STR.
- */
 static int JimParseSubQuote(struct JimParserCtx *pc)
 {
     int tt = JIM_TT_STR;
     int line = pc->tline;
 
-    /* Skip the quote */
+    
     pc->p++;
     pc->len--;
     while (pc->len) {
         switch (*pc->p) {
             case '\\':
@@ -7806,23 +6752,17 @@
     pc->missingline = line;
     pc->tend = pc->p - 1;
     return tt;
 }
 
-/**
- * Parses a [command] expression starting at pc->p.
- * 
- * Positions the parser at the end of the command expression,
- * sets pc->tend and possibly pc->missing.
- */
 static void JimParseSubCmd(struct JimParserCtx *pc)
 {
     int level = 1;
     int startofword = 1;
     int line = pc->tline;
 
-    /* Skip the bracket */
+    
     pc->p++;
     pc->len--;
     while (pc->len) {
         switch (*pc->p) {
             case '\\':
@@ -7898,17 +6838,17 @@
     return JIM_OK;
 }
 
 static int JimParseVar(struct JimParserCtx *pc)
 {
-    /* skip the $ */
+    
     pc->p++;
     pc->len--;
 
 #ifdef EXPRSUGAR_BRACKET
     if (*pc->p == '[') {
-        /* Parse $[...] expr shorthand syntax */
+        
         JimParseCmd(pc);
         pc->tt = JIM_TT_EXPRSUGAR;
         return JIM_OK;
     }
 #endif
@@ -7934,11 +6874,11 @@
             pc->len--;
         }
     }
     else {
         while (1) {
-            /* Skip double colon, but not single colon! */
+            
             if (pc->p[0] == ':' && pc->p[1] == ':') {
                 pc->p += 2;
                 pc->len -= 2;
                 continue;
             }
@@ -7947,11 +6887,11 @@
                 pc->len--;
                 continue;
             }
             break;
         }
-        /* Parse [dict get] syntax sugar. */
+        
         if (*pc->p == '(') {
             int count = 1;
             const char *paren = NULL;
 
             pc->tt = JIM_TT_DICTSUGAR;
@@ -7974,11 +6914,11 @@
             if (count == 0) {
                 pc->p++;
                 pc->len--;
             }
             else if (paren) {
-                /* Did not find a matching paren. Back up */
+                
                 paren++;
                 pc->len += (pc->p - paren);
                 pc->p = paren;
             }
 #ifndef EXPRSUGAR_BRACKET
@@ -7987,14 +6927,10 @@
             }
 #endif
         }
         pc->tend = pc->p - 1;
     }
-    /* Check if we parsed just the '$' character.
-     * That's not a variable so an error is returned
-     * to tell the state machine to consider this '$' just
-     * a string. */
     if (pc->tstart == pc->p) {
         pc->p--;
         pc->len++;
         return JIM_ERR;
     }
@@ -8010,11 +6946,11 @@
     }
     else if (newword && *pc->p == '"') {
         pc->state = JIM_PS_QUOTE;
         pc->p++;
         pc->len--;
-        /* In case the end quote is missing */
+        
         pc->missingline = pc->tline;
     }
     pc->tstart = pc->p;
     pc->tline = pc->linenr;
     while (1) {
@@ -8040,19 +6976,19 @@
                     pc->p++;
                     pc->len--;
                 }
                 break;
             case '(':
-                /* If the following token is not '$' just keep going */
+                
                 if (pc->len > 1 && pc->p[1] != '$') {
                     break;
                 }
             case ')':
-                /* Only need a separate ')' token if the previous was a var */
+                
                 if (*pc->p == '(' || pc->tt == JIM_TT_VAR) {
                     if (pc->p == pc->tstart) {
-                        /* At the start of the token, so just return this char */
+                        
                         pc->p++;
                         pc->len--;
                     }
                     pc->tend = pc->p - 1;
                     pc->tt = JIM_TT_ESC;
@@ -8091,11 +7027,11 @@
                 break;
         }
         pc->p++;
         pc->len--;
     }
-    return JIM_OK;              /* unreached */
+    return JIM_OK;              
 }
 
 static int JimParseComment(struct JimParserCtx *pc)
 {
     while (*pc->p) {
@@ -8111,11 +7047,11 @@
         pc->len--;
     }
     return JIM_OK;
 }
 
-/* xdigitval and odigitval are helper functions for JimEscape() */
+
 static int xdigitval(int c)
 {
     if (c >= '0' && c <= '9')
         return c - '0';
     if (c >= 'a' && c <= 'f')
@@ -8130,17 +7066,10 @@
     if (c >= '0' && c <= '7')
         return c - '0';
     return -1;
 }
 
-/* Perform Tcl escape substitution of 's', storing the result
- * string into 'dest'. The escaped string is guaranteed to
- * be the same length or shorted than the source string.
- * Slen is the length of the string at 's', if it's -1 the string
- * length will be calculated by the function.
- *
- * The function returns the length of the resulting string. */
 static int JimEscape(char *dest, const char *s, int slen)
 {
     char *p = dest;
     int i, len;
 
@@ -8175,15 +7104,10 @@
                         *p++ = 0x9;
                         i++;
                         break;
                     case 'u':
                     case 'x':
-                        /* A unicode or hex sequence.
-                         * \u Expect 1-4 hex chars and convert to utf-8.
-                         * \x Expect 1-2 hex chars and convert to hex.
-                         * An invalid sequence means simply the escaped char.
-                         */
                         {
                             int val = 0;
                             int k;
 
                             i++;
@@ -8194,21 +7118,21 @@
                                     break;
                                 }
                                 val = (val << 4) | c;
                             }
                             if (k) {
-                                /* Got a valid sequence, so convert */
+                                
                                 if (s[i] == 'u') {
                                     p += utf8_fromunicode(p, val);
                                 }
                                 else {
                                     *p++ = val;
                                 }
                                 i += k;
                                 break;
                             }
-                            /* Not a valid codepoint, just an escaped char */
+                            
                             *p++ = s[i];
                         }
                         break;
                     case 'v':
                         *p++ = 0xb;
@@ -8217,11 +7141,11 @@
                     case '\0':
                         *p++ = '\\';
                         i++;
                         break;
                     case '\n':
-                        /* Replace all spaces and tabs after backslash newline with a single space*/
+                        
                         *p++ = ' ';
                         do {
                             i++;
                         } while (s[i + 1] == ' ' || s[i + 1] == '\t');
                         break;
@@ -8231,11 +7155,11 @@
                     case '3':
                     case '4':
                     case '5':
                     case '6':
                     case '7':
-                        /* octal escape */
+                        
                         {
                             int val = 0;
                             int c = odigitval(s[i + 1]);
 
                             val = c;
@@ -8271,30 +7195,10 @@
     len = p - dest;
     *p = '\0';
     return len;
 }
 
-/* Returns a dynamically allocated copy of the current token in the
- * parser context. The function performs conversion of escapes if
- * the token is of type JIM_TT_ESC.
- *
- * Note that after the conversion, tokens that are grouped with
- * braces in the source code, are always recognizable from the
- * identical string obtained in a different way from the type.
- *
- * For example the string:
- *
- * {*}$a
- *
- * will return as first token "*", of type JIM_TT_STR
- *
- * While the string:
- *
- * *$a
- *
- * will return as first token "*", of type JIM_TT_ESC
- */
 static Jim_Obj *JimParserGetTokenObj(Jim_Interp *interp, struct JimParserCtx *pc)
 {
     const char *start, *end;
     char *token;
     int len;
@@ -8308,34 +7212,23 @@
     }
     else {
         len = (end - start) + 1;
         token = Jim_Alloc(len + 1);
         if (pc->tt != JIM_TT_ESC) {
-            /* No escape conversion needed? Just copy it. */
+            
             memcpy(token, start, len);
             token[len] = '\0';
         }
         else {
-            /* Else convert the escape chars. */
+            
             len = JimEscape(token, start, len);
         }
     }
 
     return Jim_NewStringObjNoAlloc(interp, token, len);
 }
 
-/* Parses the given string to determine if it represents a complete script.
- *
- * This is useful for interactive shells implementation, for [info complete].
- *
- * If 'stateCharPtr' != NULL, the function stores ' ' on complete script,
- * '{' on scripts incomplete missing one or more '}' to be balanced.
- * '[' on scripts incomplete missing one or more ']' to be balanced.
- * '"' on scripts incomplete missing a '"' char.
- *
- * If the script is complete, 1 is returned, otherwise 0.
- */
 int Jim_ScriptIsComplete(const char *s, int len, char *stateCharPtr)
 {
     struct JimParserCtx parser;
 
     JimParserInit(&parser, s, len, 1);
@@ -8346,13 +7239,10 @@
         *stateCharPtr = parser.missing;
     }
     return parser.missing == ' ';
 }
 
-/* -----------------------------------------------------------------------------
- * Tcl Lists parsing
- * ---------------------------------------------------------------------------*/
 static int JimParseListSep(struct JimParserCtx *pc);
 static int JimParseListStr(struct JimParserCtx *pc);
 static int JimParseListQuote(struct JimParserCtx *pc);
 
 static int JimParseList(struct JimParserCtx *pc)
@@ -8412,11 +7302,11 @@
     while (pc->len) {
         switch (*pc->p) {
             case '\\':
                 pc->tt = JIM_TT_ESC;
                 if (--pc->len == 0) {
-                    /* Trailing backslash */
+                    
                     pc->tend = pc->p;
                     return JIM_OK;
                 }
                 pc->p++;
                 break;
@@ -8445,11 +7335,11 @@
 
     while (pc->len) {
         switch (*pc->p) {
             case '\\':
                 if (--pc->len == 0) {
-                    /* Trailing backslash */
+                    
                     pc->tend = pc->p;
                     return JIM_OK;
                 }
                 pc->tt = JIM_TT_ESC;
                 pc->p++;
@@ -8466,81 +7356,69 @@
     }
     pc->tend = pc->p - 1;
     return JIM_OK;
 }
 
-/* -----------------------------------------------------------------------------
- * Jim_Obj related functions
- * ---------------------------------------------------------------------------*/
 
-/* Return a new initialized object. */
+
 Jim_Obj *Jim_NewObj(Jim_Interp *interp)
 {
     Jim_Obj *objPtr;
 
-    /* -- Check if there are objects in the free list -- */
+    
     if (interp->freeList != NULL) {
-        /* -- Unlink the object from the free list -- */
+        
         objPtr = interp->freeList;
         interp->freeList = objPtr->nextObjPtr;
     }
     else {
-        /* -- No ready to use objects: allocate a new one -- */
+        
         objPtr = Jim_Alloc(sizeof(*objPtr));
     }
 
-    /* Object is returned with refCount of 0. Every
-     * kind of GC implemented should take care to don't try
-     * to scan objects with refCount == 0. */
     objPtr->refCount = 0;
-    /* All the other fields are left not initialized to save time.
-     * The caller will probably want to set them to the right
-     * value anyway. */
 
-    /* -- Put the object into the live list -- */
+    
     objPtr->prevObjPtr = NULL;
     objPtr->nextObjPtr = interp->liveList;
     if (interp->liveList)
         interp->liveList->prevObjPtr = objPtr;
     interp->liveList = objPtr;
 
     return objPtr;
 }
 
-/* Free an object. Actually objects are never freed, but
- * just moved to the free objects list, where they will be
- * reused by Jim_NewObj(). */
 void Jim_FreeObj(Jim_Interp *interp, Jim_Obj *objPtr)
 {
-    /* Check if the object was already freed, panic. */
-    JimPanic((objPtr->refCount != 0, interp, "!!!Object %p freed with bad refcount %d, type=%s", objPtr,
+    
+    JimPanic((objPtr->refCount != 0, "!!!Object %p freed with bad refcount %d, type=%s", objPtr,
         objPtr->refCount, objPtr->typePtr ? objPtr->typePtr->name : "<none>"));
 
-    /* Free the internal representation */
+    
     Jim_FreeIntRep(interp, objPtr);
-    /* Free the string representation */
+    
     if (objPtr->bytes != NULL) {
         if (objPtr->bytes != JimEmptyStringRep)
             Jim_Free(objPtr->bytes);
     }
-    /* Unlink the object from the live objects list */
+    
     if (objPtr->prevObjPtr)
         objPtr->prevObjPtr->nextObjPtr = objPtr->nextObjPtr;
     if (objPtr->nextObjPtr)
         objPtr->nextObjPtr->prevObjPtr = objPtr->prevObjPtr;
     if (interp->liveList == objPtr)
         interp->liveList = objPtr->nextObjPtr;
-    /* Link the object into the free objects list */
+    
     objPtr->prevObjPtr = NULL;
     objPtr->nextObjPtr = interp->freeList;
     if (interp->freeList)
         interp->freeList->prevObjPtr = objPtr;
     interp->freeList = objPtr;
     objPtr->refCount = -1;
 }
 
-/* Invalidate the string representation of an object. */
+
 void Jim_InvalidateStringRep(Jim_Obj *objPtr)
 {
     if (objPtr->bytes != NULL) {
         if (objPtr->bytes != JimEmptyStringRep)
             Jim_Free(objPtr->bytes);
@@ -8549,12 +7427,10 @@
 }
 
 #define Jim_SetStringRep(o, b, l) \
     do { (o)->bytes = b; (o)->length = l; } while (0)
 
-/* Set the initial string representation for an object.
- * Does not try to free an old one. */
 void Jim_InitStringRep(Jim_Obj *objPtr, const char *bytes, int length)
 {
     if (length == 0) {
         objPtr->bytes = JimEmptyStringRep;
         objPtr->length = 0;
@@ -8565,54 +7441,51 @@
         memcpy(objPtr->bytes, bytes, length);
         objPtr->bytes[length] = '\0';
     }
 }
 
-/* Duplicate an object. The returned object has refcount = 0. */
+
 Jim_Obj *Jim_DuplicateObj(Jim_Interp *interp, Jim_Obj *objPtr)
 {
     Jim_Obj *dupPtr;
 
     dupPtr = Jim_NewObj(interp);
     if (objPtr->bytes == NULL) {
-        /* Object does not have a valid string representation. */
+        
         dupPtr->bytes = NULL;
     }
     else {
         Jim_InitStringRep(dupPtr, objPtr->bytes, objPtr->length);
     }
 
-    /* By default, the new object has the same type as the old object */
+    
     dupPtr->typePtr = objPtr->typePtr;
     if (objPtr->typePtr != NULL) {
         if (objPtr->typePtr->dupIntRepProc == NULL) {
             dupPtr->internalRep = objPtr->internalRep;
         }
         else {
-            /* The dup proc may set a different type, e.g. NULL */
+            
             objPtr->typePtr->dupIntRepProc(interp, objPtr, dupPtr);
         }
     }
     return dupPtr;
 }
 
-/* Return the string representation for objPtr. If the object
- * string representation is invalid, calls the method to create
- * a new one starting from the internal representation of the object. */
 const char *Jim_GetString(Jim_Obj *objPtr, int *lenPtr)
 {
     if (objPtr->bytes == NULL) {
-        /* Invalid string repr. Generate it. */
-        JimPanic((objPtr->typePtr->updateStringProc == NULL, NULL, "UpdateStringProc called against '%s' type.", objPtr->typePtr->name));
+        
+        JimPanic((objPtr->typePtr->updateStringProc == NULL, "UpdateStringProc called against '%s' type.", objPtr->typePtr->name));
         objPtr->typePtr->updateStringProc(objPtr);
     }
     if (lenPtr)
         *lenPtr = objPtr->length;
     return objPtr->bytes;
 }
 
-/* Just returns the length of the object's string rep */
+
 int Jim_Length(Jim_Obj *objPtr)
 {
     int len;
 
     Jim_GetString(objPtr, &len);
@@ -8641,13 +7514,10 @@
     NULL,
     NULL,
     JIM_TYPE_NONE,
 };
 
-/* -----------------------------------------------------------------------------
- * String Object
- * ---------------------------------------------------------------------------*/
 static void DupStringInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr);
 static int SetStringFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr);
 
 static const Jim_ObjType stringObjType = {
     "string",
@@ -8659,39 +7529,29 @@
 
 static void DupStringInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr)
 {
     JIM_NOTUSED(interp);
 
-    /* This is a bit subtle: the only caller of this function
-     * should be Jim_DuplicateObj(), that will copy the
-     * string representaion. After the copy, the duplicated
-     * object will not have more room in teh buffer than
-     * srcPtr->length bytes. So we just set it to length. */
     dupPtr->internalRep.strValue.maxLength = srcPtr->length;
 
     dupPtr->internalRep.strValue.charLength = srcPtr->internalRep.strValue.charLength;
 }
 
 static int SetStringFromAny(Jim_Interp *interp, Jim_Obj *objPtr)
 {
-    /* Get a fresh string representation. */
+    
     (void)Jim_String(objPtr);
-    /* Free any other internal representation. */
+    
     Jim_FreeIntRep(interp, objPtr);
-    /* Set it as string, i.e. just set the maxLength field. */
+    
     objPtr->typePtr = &stringObjType;
     objPtr->internalRep.strValue.maxLength = objPtr->length;
-    /* Don't know the utf-8 length yet */
+    
     objPtr->internalRep.strValue.charLength = -1;
     return JIM_OK;
 }
 
-/**
- * Returns the length of the object string in chars, not bytes.
- *
- * These may be different for a utf-8 string.
- */
 int Jim_Utf8Length(Jim_Interp *interp, Jim_Obj *objPtr)
 {
 #ifdef JIM_UTF8
     if (objPtr->typePtr != &stringObjType)
         SetStringFromAny(interp, objPtr);
@@ -8703,19 +7563,19 @@
 #else
     return Jim_Length(objPtr);
 #endif
 }
 
-/* len is in bytes -- see also Jim_NewStringObjUtf8() */
+
 Jim_Obj *Jim_NewStringObj(Jim_Interp *interp, const char *s, int len)
 {
     Jim_Obj *objPtr = Jim_NewObj(interp);
 
-    /* Need to find out how many bytes the string requires */
+    
     if (len == -1)
         len = strlen(s);
-    /* Alloc/Set the string rep. */
+    
     if (len == 0) {
         objPtr->bytes = JimEmptyStringRep;
         objPtr->length = 0;
     }
     else {
@@ -8723,25 +7583,25 @@
         objPtr->length = len;
         memcpy(objPtr->bytes, s, len);
         objPtr->bytes[len] = '\0';
     }
 
-    /* No typePtr field for the vanilla string object. */
+    
     objPtr->typePtr = NULL;
     return objPtr;
 }
 
-/* charlen is in characters -- see also Jim_NewStringObj() */
+
 Jim_Obj *Jim_NewStringObjUtf8(Jim_Interp *interp, const char *s, int charlen)
 {
 #ifdef JIM_UTF8
-    /* Need to find out how many bytes the string requires */
+    
     int bytelen = utf8_index(s, charlen);
 
     Jim_Obj *objPtr = Jim_NewStringObj(interp, s, bytelen);
 
-    /* Remember the utf8 length, so set the type */
+    
     objPtr->typePtr = &stringObjType;
     objPtr->internalRep.strValue.maxLength = bytelen;
     objPtr->internalRep.strValue.charLength = charlen;
 
     return objPtr;
@@ -8748,12 +7608,10 @@
 #else
     return Jim_NewStringObj(interp, s, charlen);
 #endif
 }
 
-/* This version does not try to duplicate the 's' pointer, but
- * use it directly. */
 Jim_Obj *Jim_NewStringObjNoAlloc(Jim_Interp *interp, char *s, int len)
 {
     Jim_Obj *objPtr = Jim_NewObj(interp);
 
     if (len == -1)
@@ -8761,12 +7619,10 @@
     Jim_SetStringRep(objPtr, s, len);
     objPtr->typePtr = NULL;
     return objPtr;
 }
 
-/* Low-level string append. Use it only against objects
- * of type "string". */
 static void StringAppendString(Jim_Obj *objPtr, const char *str, int len)
 {
     int needlen;
 
     if (len == -1)
@@ -8773,11 +7629,11 @@
         len = strlen(str);
     needlen = objPtr->length + len;
     if (objPtr->internalRep.strValue.maxLength < needlen ||
         objPtr->internalRep.strValue.maxLength == 0) {
         needlen *= 2;
-        /* Inefficient to malloc() for less than 8 bytes */
+        
         if (needlen < 7) {
             needlen = 7;
         }
         if (objPtr->bytes == JimEmptyStringRep) {
             objPtr->bytes = Jim_Alloc(needlen + 1);
@@ -8788,20 +7644,20 @@
         objPtr->internalRep.strValue.maxLength = needlen;
     }
     memcpy(objPtr->bytes + objPtr->length, str, len);
     objPtr->bytes[objPtr->length + len] = '\0';
     if (objPtr->internalRep.strValue.charLength >= 0) {
-        /* Update the utf-8 char length */
+        
         objPtr->internalRep.strValue.charLength += utf8_strlen(objPtr->bytes + objPtr->length, len);
     }
     objPtr->length += len;
 }
 
-/* Higher level API to append strings to objects. */
+
 void Jim_AppendString(Jim_Interp *interp, Jim_Obj *objPtr, const char *str, int len)
 {
-    JimPanic((Jim_IsShared(objPtr), interp, "Jim_AppendString called with shared object"));
+    JimPanic((Jim_IsShared(objPtr), "Jim_AppendString called with shared object"));
     if (objPtr->typePtr != &stringObjType)
         SetStringFromAny(interp, objPtr);
     StringAppendString(objPtr, str, len);
 }
 
@@ -8862,28 +7718,17 @@
         return JimStringCompareNoCase(s1, s2, -1);
     }
     return JimStringCompare(s1, l1, s2, l2);
 }
 
-/* Convert a range, as returned by Jim_GetRange(), into
- * an absolute index into an object of the specified length.
- * This function may return negative values, or values
- * bigger or equal to the length of the list if the index
- * is out of range. */
 static int JimRelToAbsIndex(int len, int idx)
 {
     if (idx < 0)
         return len + idx;
     return idx;
 }
 
-/* Convert a pair of index as normalize by JimRelToAbsIndex(),
- * into a range stored in *firstPtr, *lastPtr, *rangeLenPtr, suitable
- * for implementation of commands like [string range] and [lrange].
- *
- * The resulting range is guaranteed to address valid elements of
- * the structure. */
 static void JimRelToAbsRange(int len, int first, int last,
     int *firstPtr, int *lastPtr, int *rangeLenPtr)
 {
     int rangeLen;
 
@@ -8951,11 +7796,11 @@
     JimRelToAbsRange(len, first, last, &first, &last, &rangeLen);
     if (first == 0 && rangeLen == len) {
         return strObjPtr;
     }
     if (len == bytelen) {
-        /* ASCII optimisation */
+        
         return Jim_NewStringObj(interp, str + first, rangeLen);
     }
     return Jim_NewStringObjUtf8(interp, str + utf8_index(str, first), rangeLen);
 #else
     return Jim_StringByteRangeObj(interp, strObjPtr, firstObjPtr, lastObjPtr);
@@ -9004,14 +7849,10 @@
     }
     *p = 0;
     return Jim_NewStringObjNoAlloc(interp, buf, len);
 }
 
-/* Similar to memchr() except searches a UTF-8 string 'str' of byte length 'len'
- * for unicode character 'c'.
- * Returns the position if found or NULL if not
- */
 static const char *utf8_memchr(const char *str, int len, int c)
 {
 #ifdef JIM_UTF8
     while (len) {
         int sc;
@@ -9026,40 +7867,26 @@
 #else
     return memchr(str, c, len);
 #endif
 }
 
-/**
- * Searches for the first non-trim char in string (str, len)
- *
- * If none is found, returns just past the last char.
- *
- * Lengths are in bytes.
- */
 static const char *JimFindTrimLeft(const char *str, int len, const char *trimchars, int trimlen)
 {
     while (len) {
         int c;
         int n = utf8_tounicode(str, &c);
 
         if (utf8_memchr(trimchars, trimlen, c) == NULL) {
-            /* Not a trim char, so stop */
+            
             break;
         }
         str += n;
         len -= n;
     }
     return str;
 }
 
-/**
- * Searches backwards for a non-trim char in string (str, len).
- *
- * Returns a pointer to just after the non-trim char, or NULL if not found.
- *
- * Lengths are in bytes.
- */
 static const char *JimFindTrimRight(const char *str, int len, const char *trimchars, int trimlen)
 {
     str += len;
 
     while (len) {
@@ -9078,11 +7905,11 @@
 
     return NULL;
 }
 
 static const char default_trim_chars[] = " \t\n\r";
-/* sizeof() here includes the null byte */
+
 static int default_trim_chars_len = sizeof(default_trim_chars);
 
 static Jim_Obj *JimStringTrimLeft(Jim_Interp *interp, Jim_Obj *strObjPtr, Jim_Obj *trimcharsObjPtr)
 {
     int len;
@@ -9115,15 +7942,15 @@
     }
 
     if (strObjPtr->typePtr != &stringObjType) {
         SetStringFromAny(interp, strObjPtr);
     }
-    Jim_GetString(strObjPtr, &len);
+    len = Jim_Length(strObjPtr);
     nontrim = JimFindTrimRight(strObjPtr->bytes, len, trimchars, trimcharslen);
 
     if (nontrim == NULL) {
-        /* All trim, so return a zero-length string */
+        
         return Jim_NewEmptyStringObj(interp);
     }
     if (nontrim == strObjPtr->bytes + len) {
         return strObjPtr;
     }
@@ -9130,28 +7957,28 @@
 
     if (Jim_IsShared(strObjPtr)) {
         strObjPtr = Jim_NewStringObj(interp, strObjPtr->bytes, (nontrim - strObjPtr->bytes));
     }
     else {
-        /* Can modify this string in place */
+        
         strObjPtr->bytes[nontrim - strObjPtr->bytes] = 0;
         strObjPtr->length = (nontrim - strObjPtr->bytes);
     }
 
     return strObjPtr;
 }
 
 static Jim_Obj *JimStringTrim(Jim_Interp *interp, Jim_Obj *strObjPtr, Jim_Obj *trimcharsObjPtr)
 {
-    /* First trim left. */
+    
     Jim_Obj *objPtr = JimStringTrimLeft(interp, strObjPtr, trimcharsObjPtr);
 
-    /* Now trim right */
+    
     strObjPtr = JimStringTrimRight(interp, objPtr, trimcharsObjPtr);
 
     if (objPtr != strObjPtr) {
-        /* Note that we don't want this object to be leaked */
+        
         Jim_IncrRefCount(objPtr);
         Jim_DecrRefCount(interp, objPtr);
     }
 
     return strObjPtr;
@@ -9226,38 +8053,20 @@
     }
     Jim_SetResultInt(interp, 1);
     return JIM_OK;
 }
 
-/* -----------------------------------------------------------------------------
- * Compared String Object
- * ---------------------------------------------------------------------------*/
 
-/* This is strange object that allows to compare a C literal string
- * with a Jim object in very short time if the same comparison is done
- * multiple times. For example every time the [if] command is executed,
- * Jim has to check if a given argument is "else". This comparions if
- * the code has no errors are true most of the times, so we can cache
- * inside the object the pointer of the string of the last matching
- * comparison. Because most C compilers perform literal sharing,
- * so that: char *x = "foo", char *y = "foo", will lead to x == y,
- * this works pretty well even if comparisons are at different places
- * inside the C code. */
 
 static const Jim_ObjType comparedStringObjType = {
     "compared-string",
     NULL,
     NULL,
     NULL,
     JIM_TYPE_REFERENCES,
 };
 
-/* The only way this object is exposed to the API is via the following
- * function. Returns true if the string and the object string repr.
- * are the same, otherwise zero is returned.
- *
- * Note: this isn't binary safe, but it hardly needs to be.*/
 int Jim_CompareStringImmediate(Jim_Interp *interp, Jim_Obj *objPtr, const char *str)
 {
     if (objPtr->typePtr == &comparedStringObjType && objPtr->internalRep.ptr == str)
         return 1;
     else {
@@ -9267,11 +8076,11 @@
             return 0;
         if (objPtr->typePtr != &comparedStringObjType) {
             Jim_FreeIntRep(interp, objPtr);
             objPtr->typePtr = &comparedStringObjType;
         }
-        objPtr->internalRep.ptr = (char *)str;  /*ATTENTION: const cast */
+        objPtr->internalRep.ptr = (char *)str;  
         return 1;
     }
 }
 
 static int qsortCompareStringPointers(const void *a, const void *b)
@@ -9281,31 +8090,10 @@
 
     return strcmp(*sa, *sb);
 }
 
 
-/* -----------------------------------------------------------------------------
- * Source Object
- *
- * This object is just a string from the language point of view, but
- * in the internal representation it contains the filename and line number
- * where this given token was read. This information is used by
- * Jim_EvalObj() if the object passed happens to be of type "source".
- *
- * This allows to propagate the information about line numbers and file
- * names and give error messages with absolute line numbers.
- *
- * Note that this object uses shared strings for filenames, and the
- * pointer to the filename together with the line number is taken into
- * the space for the "inline" internal representation of the Jim_Object,
- * so there is almost memory zero-overhead.
- *
- * Also the object will be converted to something else if the given
- * token it represents in the source file is not something to be
- * evaluated (not a script), and will be specialized in some other way,
- * so the time overhead is also null.
- * ---------------------------------------------------------------------------*/
 
 static void FreeSourceInternalRep(Jim_Interp *interp, Jim_Obj *objPtr);
 static void DupSourceInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr);
 
 static const Jim_ObjType sourceObjType = {
@@ -9316,36 +8104,30 @@
     JIM_TYPE_REFERENCES,
 };
 
 void FreeSourceInternalRep(Jim_Interp *interp, Jim_Obj *objPtr)
 {
-    Jim_ReleaseSharedString(interp, objPtr->internalRep.sourceValue.fileName);
+    Jim_DecrRefCount(interp, objPtr->internalRep.sourceValue.fileNameObj);
 }
 
 void DupSourceInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr)
 {
-    dupPtr->internalRep.sourceValue.fileName =
-        Jim_GetSharedString(interp, srcPtr->internalRep.sourceValue.fileName);
-    dupPtr->internalRep.sourceValue.lineNumber = dupPtr->internalRep.sourceValue.lineNumber;
-    dupPtr->typePtr = &sourceObjType;
+    dupPtr->internalRep = srcPtr->internalRep;
+    Jim_IncrRefCount(dupPtr->internalRep.sourceValue.fileNameObj);
 }
 
 static void JimSetSourceInfo(Jim_Interp *interp, Jim_Obj *objPtr,
-    const char *fileName, int lineNumber)
+    Jim_Obj *fileNameObj, int lineNumber)
 {
-    if (fileName) {
-        JimPanic((Jim_IsShared(objPtr), interp, "JimSetSourceInfo called with shared object"));
-        JimPanic((objPtr->typePtr != NULL, interp, "JimSetSourceInfo called with typePtr != NULL"));
-        objPtr->internalRep.sourceValue.fileName = Jim_GetSharedString(interp, fileName);
-        objPtr->internalRep.sourceValue.lineNumber = lineNumber;
-        objPtr->typePtr = &sourceObjType;
-    }
+    JimPanic((Jim_IsShared(objPtr), "JimSetSourceInfo called with shared object"));
+    JimPanic((objPtr->typePtr != NULL, "JimSetSourceInfo called with typePtr != NULL"));
+    Jim_IncrRefCount(fileNameObj);
+    objPtr->internalRep.sourceValue.fileNameObj = fileNameObj;
+    objPtr->internalRep.sourceValue.lineNumber = lineNumber;
+    objPtr->typePtr = &sourceObjType;
 }
 
-/* -----------------------------------------------------------------------------
- * Script Object
- * ---------------------------------------------------------------------------*/
 
 static const Jim_ObjType scriptLineObjType = {
     "scriptline",
     NULL,
     NULL,
@@ -9383,98 +8165,26 @@
     DupScriptInternalRep,
     NULL,
     JIM_TYPE_REFERENCES,
 };
 
-/* The ScriptToken structure represents every token into a scriptObj.
- * Every token contains an associated Jim_Obj that can be specialized
- * by commands operating on it. */
 typedef struct ScriptToken
 {
     int type;
     Jim_Obj *objPtr;
 } ScriptToken;
 
-/* This is the script object internal representation. An array of
- * ScriptToken structures, including a pre-computed representation of the
- * command length and arguments.
- *
- * For example the script:
- *
- * puts hello
- * set $i $x$y [foo]BAR
- *
- * will produce a ScriptObj with the following Tokens:
- *
- * LIN 2
- * ESC puts
- * ESC hello
- * LIN 4
- * ESC set
- * VAR i
- * WRD 2
- * VAR x
- * VAR y
- * WRD 2
- * CMD foo
- * ESC BAR
- *
- * "puts hello" has two args (LIN 2), composed of single tokens.
- * (Note that the WRD token is omitted for the common case of a single token.)
- *
- * "set $i $x$y [foo]BAR" has four (LIN 4) args, the first word
- * has 1 token (ESC SET), and the last has two tokens (WRD 2 CMD foo ESC BAR)
- *
- * The precomputation of the command structure makes Jim_Eval() faster,
- * and simpler because there aren't dynamic lengths / allocations.
- *
- * -- {expand}/{*} handling --
- *
- * Expand is handled in a special way.
- *
- *   If a "word" begins with {*}, the word token count is -ve.
- *
- * For example the command:
- *
- * list {*}{a b}
- *
- * Will produce the following cmdstruct array:
- *
- * LIN 2
- * ESC list
- * WRD -1
- * STR a b
- *
- * Note that the 'LIN' token also contains the source information for the
- * first word of the line for error reporting purposes
- *
- * -- the substFlags field of the structure --
- *
- * The scriptObj structure is used to represent both "script" objects
- * and "subst" objects. In the second case, the there are no LIN and WRD
- * tokens. Instead SEP and EOL tokens are added as-is.
- * In addition, the field 'substFlags' is used to represent the flags used to turn
- * the string into the internal representation used to perform the
- * substitution. If this flags are not what the application requires
- * the scriptObj is created again. For example the script:
- *
- * subst -nocommands $string
- * subst -novariables $string
- *
- * Will recreate the internal representation of the $string object
- * two times.
- */
 typedef struct ScriptObj
 {
-    int len;                    /* Length as number of tokens. */
-    ScriptToken *token;         /* Tokens array. */
-    int substFlags;             /* flags used for the compilation of "subst" objects */
+    int len;                    
+    ScriptToken *token;         
+    int substFlags;             
     int inUse;                  /* Used to share a ScriptObj. Currently
                                    only used by Jim_EvalObj() as protection against
                                    shimmering of the currently evaluated object. */
-    const char *fileName;
-    int line;                   /* Line number of the first line */
+    Jim_Obj *fileNameObj;
+    int line;                   
 } ScriptObj;
 
 void FreeScriptInternalRep(Jim_Interp *interp, Jim_Obj *objPtr)
 {
     int i;
@@ -9485,47 +8195,38 @@
         return;
     for (i = 0; i < script->len; i++) {
         Jim_DecrRefCount(interp, script->token[i].objPtr);
     }
     Jim_Free(script->token);
-    if (script->fileName) {
-        Jim_ReleaseSharedString(interp, script->fileName);
-    }
+    Jim_DecrRefCount(interp, script->fileNameObj);
     Jim_Free(script);
 }
 
 void DupScriptInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr)
 {
     JIM_NOTUSED(interp);
     JIM_NOTUSED(srcPtr);
 
-    /* Just returns an simple string. */
+    
     dupPtr->typePtr = NULL;
 }
 
-/* A simple parser token.
- * All the simple tokens for the script point into the same script string rep.
- */
 typedef struct
 {
-    const char *token;          /* Pointer to the start of the token */
-    int len;                    /* Length of this token */
-    int type;                   /* Token type */
-    int line;                   /* Line number */
+    const char *token;          
+    int len;                    
+    int type;                   
+    int line;                   
 } ParseToken;
 
-/* A list of parsed tokens representing a script.
- * Tokens are added to this list as the script is parsed.
- * It grows as needed.
- */
 typedef struct
 {
-    /* Start with a statically allocated list of tokens which will be expanded with realloc if needed */
-    ParseToken *list;           /* Array of tokens */
-    int size;                   /* Current size of the list */
-    int count;                  /* Number of entries used */
-    ParseToken static_list[20]; /* Small initial token space to avoid allocation */
+    
+    ParseToken *list;           
+    int size;                   
+    int count;                  
+    ParseToken static_list[20]; 
 } ParseTokenList;
 
 static void ScriptTokenListInit(ParseTokenList *tokenlist)
 {
     tokenlist->list = tokenlist->static_list;
@@ -9538,29 +8239,24 @@
     if (tokenlist->list != tokenlist->static_list) {
         Jim_Free(tokenlist->list);
     }
 }
 
-/**
- * Adds the new token to the tokenlist.
- * The token has the given length, type and line number.
- * The token list is resized as necessary.
- */
 static void ScriptAddToken(ParseTokenList *tokenlist, const char *token, int len, int type,
     int line)
 {
     ParseToken *t;
 
     if (tokenlist->count == tokenlist->size) {
-        /* Resize the list */
+        
         tokenlist->size *= 2;
         if (tokenlist->list != tokenlist->static_list) {
             tokenlist->list =
                 Jim_Realloc(tokenlist->list, tokenlist->size * sizeof(*tokenlist->list));
         }
         else {
-            /* The list needs to become allocated */
+            
             tokenlist->list = Jim_Alloc(tokenlist->size * sizeof(*tokenlist->list));
             memcpy(tokenlist->list, tokenlist->static_list,
                 tokenlist->count * sizeof(*tokenlist->list));
         }
     }
@@ -9569,79 +8265,58 @@
     t->len = len;
     t->type = type;
     t->line = line;
 }
 
-/* Counts the number of adjoining non-separator.
- *
- * Returns -ve if the first token is the expansion
- * operator (in which case the count doesn't include
- * that token).
- */
 static int JimCountWordTokens(ParseToken *t)
 {
     int expand = 1;
     int count = 0;
 
-    /* Is the first word {*} or {expand}? */
+    
     if (t->type == JIM_TT_STR && !TOKEN_IS_SEP(t[1].type)) {
         if ((t->len == 1 && *t->token == '*') || (t->len == 6 && strncmp(t->token, "expand", 6) == 0)) {
-            /* Create an expand token */
+            
             expand = -1;
             t++;
         }
     }
 
-    /* Now count non-separator words */
+    
     while (!TOKEN_IS_SEP(t->type)) {
         t++;
         count++;
     }
 
     return count * expand;
 }
 
-/**
- * Create a script/subst object from the given token.
- */
 static Jim_Obj *JimMakeScriptObj(Jim_Interp *interp, const ParseToken *t)
 {
     Jim_Obj *objPtr;
 
     if (t->type == JIM_TT_ESC && memchr(t->token, '\\', t->len) != NULL) {
-        /* Convert the backlash escapes . */
+        
         int len = t->len;
         char *str = Jim_Alloc(len + 1);
         len = JimEscape(str, t->token, len);
         objPtr = Jim_NewStringObjNoAlloc(interp, str, len);
     }
     else {
-        /* REVIST: Strictly, JIM_TT_STR should replace <backslash><newline><whitespace>
-         *         with a single space. This is currently not done.
-         */
         objPtr = Jim_NewStringObj(interp, t->token, t->len);
     }
     return objPtr;
 }
 
-/**
- * Takes a tokenlist and creates the allocated list of script tokens
- * in script->token, of length script->len.
- *
- * Unnecessary tokens are discarded, and LINE and WORD tokens are inserted
- * as required.
- *
- * Also sets script->line to the line number of the first token
- */
 static void ScriptObjAddTokens(Jim_Interp *interp, struct ScriptObj *script,
     ParseTokenList *tokenlist)
 {
     int i;
     struct ScriptToken *token;
-    /* Number of tokens so far for the current command */
+    
     int lineargs = 0;
-    /* This is the first token for the current command */
+    
     ScriptToken *linefirst;
     int count;
     int linenr;
 
 #ifdef DEBUG_SHOW_SCRIPT_TOKENS
@@ -9650,11 +8325,11 @@
         printf("[%2d]@%d %s '%.*s'\n", i, tokenlist->list[i].line, jim_tt_name(tokenlist->list[i].type),
             tokenlist->list[i].len, tokenlist->list[i].token);
     }
 #endif
 
-    /* May need up to one extra script token for each EOL in the worst case */
+    
     count = tokenlist->count;
     for (i = 0; i < tokenlist->count; i++) {
         if (tokenlist->list[i].type == JIM_TT_EOL) {
             count++;
         }
@@ -9661,70 +8336,67 @@
     }
     linenr = script->line = tokenlist->list[0].line;
 
     token = script->token = Jim_Alloc(sizeof(ScriptToken) * count);
 
-    /* This is the first token for the current command */
+    
     linefirst = token++;
 
     for (i = 0; i < tokenlist->count; ) {
-        /* Look ahead to find out how many tokens make up the next word */
+        
         int wordtokens;
 
-        /* Skip any leading separators */
+        
         while (tokenlist->list[i].type == JIM_TT_SEP) {
             i++;
         }
 
         wordtokens = JimCountWordTokens(tokenlist->list + i);
 
         if (wordtokens == 0) {
-            /* None, so at end of line */
+            
             if (lineargs) {
                 linefirst->type = JIM_TT_LINE;
                 linefirst->objPtr = JimNewScriptLineObj(interp, lineargs, linenr);
                 Jim_IncrRefCount(linefirst->objPtr);
 
-                /* Reset for new line */
+                
                 lineargs = 0;
                 linefirst = token++;
             }
             i++;
             continue;
         }
         else if (wordtokens != 1) {
-            /* More than 1, or {expand}, so insert a WORD token */
+            
             token->type = JIM_TT_WORD;
             token->objPtr = Jim_NewIntObj(interp, wordtokens);
             Jim_IncrRefCount(token->objPtr);
             token++;
             if (wordtokens < 0) {
-                /* Skip the expand token */
+                
                 i++;
                 wordtokens = -wordtokens - 1;
                 lineargs--;
             }
         }
 
         if (lineargs == 0) {
-            /* First real token on the line, so record the line number */
+            
             linenr = tokenlist->list[i].line;
         }
         lineargs++;
 
-        /* Add each non-separator word token to the line */
+        
         while (wordtokens--) {
             const ParseToken *t = &tokenlist->list[i++];
 
             token->type = t->type;
             token->objPtr = JimMakeScriptObj(interp, t);
             Jim_IncrRefCount(token->objPtr);
 
-            /* Every object is initially a string, but the
-             * internal type may be specialized during execution of the
-             * script. */
-            JimSetSourceInfo(interp, token->objPtr, script->fileName, t->line);
+            JimSetSourceInfo(interp, token->objPtr, script->fileNameObj, t->line);
             token++;
         }
     }
 
     if (lineargs == 0) {
@@ -9734,22 +8406,19 @@
     script->len = token - script->token;
 
     assert(script->len < count);
 
 #ifdef DEBUG_SHOW_SCRIPT
-    printf("==== Script (%s) ====\n", script->fileName);
+    printf("==== Script (%s) ====\n", Jim_String(script->fileNameObj));
     for (i = 0; i < script->len; i++) {
         const ScriptToken *t = &script->token[i];
         printf("[%2d] %s %s\n", i, jim_tt_name(t->type), Jim_String(t->objPtr));
     }
 #endif
 
 }
 
-/**
- * Similar to ScriptObjAddTokens(), but for subst objects.
- */
 static void SubstObjAddTokens(Jim_Interp *interp, struct ScriptObj *script,
     ParseTokenList *tokenlist)
 {
     int i;
     struct ScriptToken *token;
@@ -9757,38 +8426,35 @@
     token = script->token = Jim_Alloc(sizeof(ScriptToken) * tokenlist->count);
 
     for (i = 0; i < tokenlist->count; i++) {
         const ParseToken *t = &tokenlist->list[i];
 
-        /* Create a token for 't' */
+        
         token->type = t->type;
         token->objPtr = JimMakeScriptObj(interp, t);
         Jim_IncrRefCount(token->objPtr);
         token++;
     }
 
     script->len = i;
 }
 
-/* This method takes the string representation of an object
- * as a Tcl script, and generates the pre-parsed internal representation
- * of the script. */
 static int SetScriptFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr, struct JimParseResult *result)
 {
     int scriptTextLen;
     const char *scriptText = Jim_GetString(objPtr, &scriptTextLen);
     struct JimParserCtx parser;
     struct ScriptObj *script;
     ParseTokenList tokenlist;
     int line = 1;
 
-    /* Try to get information about filename / line number */
+    
     if (objPtr->typePtr == &sourceObjType) {
         line = objPtr->internalRep.sourceValue.lineNumber;
     }
 
-    /* Initially parse the script into tokens (in tokenlist) */
+    
     ScriptTokenListInit(&tokenlist);
 
     JimParserInit(&parser, scriptText, scriptTextLen, line);
     while (!parser.eof) {
         JimParseScript(&parser);
@@ -9800,32 +8466,32 @@
         result->missing = parser.missing;
         result->line = parser.missingline;
         return JIM_ERR;
     }
 
-    /* Add a final EOF token */
+    
     ScriptAddToken(&tokenlist, scriptText + scriptTextLen, 0, JIM_TT_EOF, 0);
 
-    /* Create the "real" script tokens from the initial token list */
+    
     script = Jim_Alloc(sizeof(*script));
     memset(script, 0, sizeof(*script));
     script->inUse = 1;
     script->line = line;
     if (objPtr->typePtr == &sourceObjType) {
-        script->fileName = Jim_GetSharedString(interp, objPtr->internalRep.sourceValue.fileName);
+        script->fileNameObj = objPtr->internalRep.sourceValue.fileNameObj;
     }
+    else {
+        script->fileNameObj = interp->emptyObj;
+    }
+    Jim_IncrRefCount(script->fileNameObj);
 
     ScriptObjAddTokens(interp, script, &tokenlist);
 
-    /* No longer need the token list */
+    
     ScriptTokenListFree(&tokenlist);
 
-    if (!script->fileName) {
-        script->fileName = Jim_GetSharedString(interp, "");
-    }
-
-    /* Free the old internal rep and set the new one. */
+    
     Jim_FreeIntRep(interp, objPtr);
     Jim_SetIntRepPtr(objPtr, script);
     objPtr->typePtr = &scriptObjType;
 
     return JIM_OK;
@@ -9839,13 +8505,10 @@
         SetScriptFromAny(interp, objPtr, NULL);
     }
     return (ScriptObj *) Jim_GetIntRepPtr(objPtr);
 }
 
-/* -----------------------------------------------------------------------------
- * Commands
- * ---------------------------------------------------------------------------*/
 static void JimIncrCmdRefCount(Jim_Cmd *cmdPtr)
 {
     cmdPtr->inUse++;
 }
 
@@ -9858,67 +8521,61 @@
             if (cmdPtr->u.proc.staticVars) {
                 Jim_FreeHashTable(cmdPtr->u.proc.staticVars);
                 Jim_Free(cmdPtr->u.proc.staticVars);
             }
             if (cmdPtr->u.proc.prevCmd) {
-                /* Delete any pushed command too */
+                
                 JimDecrCmdRefCount(interp, cmdPtr->u.proc.prevCmd);
             }
         }
         else {
-            /* native (C) */
+            
             if (cmdPtr->u.native.delProc) {
                 cmdPtr->u.native.delProc(interp, cmdPtr->u.native.privData);
             }
         }
         Jim_Free(cmdPtr);
     }
 }
 
-/* Commands HashTable Type.
- *
- * Keys are dynamic allocated strings, Values are Jim_Cmd structures. */
 static void JimCommandsHT_ValDestructor(void *interp, void *val)
 {
     JimDecrCmdRefCount(interp, val);
 }
 
 static const Jim_HashTableType JimCommandsHashTableType = {
-    JimStringCopyHTHashFunction,        /* hash function */
-    JimStringCopyHTKeyDup,      /* key dup */
-    NULL,                       /* val dup */
-    JimStringCopyHTKeyCompare,  /* key compare */
-    JimStringCopyHTKeyDestructor,       /* key destructor */
-    JimCommandsHT_ValDestructor        /* val destructor */
+    JimStringCopyHTHashFunction,        
+    JimStringCopyHTKeyDup,      
+    NULL,                       
+    JimStringCopyHTKeyCompare,  
+    JimStringCopyHTKeyDestructor,       
+    JimCommandsHT_ValDestructor        
 };
 
-/* ------------------------- Commands related functions --------------------- */
+
 
 int Jim_CreateCommand(Jim_Interp *interp, const char *cmdName,
     Jim_CmdProc cmdProc, void *privData, Jim_DelCmdProc delProc)
 {
     Jim_Cmd *cmdPtr;
 
     if (Jim_DeleteHashEntry(&interp->commands, cmdName) != JIM_ERR) {
-        /* Command existed so incr proc epoch */
+        
         Jim_InterpIncrProcEpoch(interp);
     }
 
     cmdPtr = Jim_Alloc(sizeof(*cmdPtr));
 
-    /* Store the new details for this proc */
+    
     memset(cmdPtr, 0, sizeof(*cmdPtr));
     cmdPtr->inUse = 1;
     cmdPtr->u.native.delProc = delProc;
     cmdPtr->u.native.cmdProc = cmdProc;
     cmdPtr->u.native.privData = privData;
 
     Jim_AddHashEntry(&interp->commands, cmdName, cmdPtr);
 
-    /* There is no need to increment the 'proc epoch' because
-     * creation of a new procedure can never affect existing
-     * cached commands. We don't do negative caching. */
     return JIM_OK;
 }
 
 static int JimCreateProcedure(Jim_Interp *interp, Jim_Obj *cmdName,
     Jim_Obj *argListObjPtr, Jim_Obj *staticsListObjPtr, Jim_Obj *bodyObjPtr)
@@ -9932,11 +8589,11 @@
         return JIM_ERR;
     }
 
     argListLen = Jim_ListLength(interp, argListObjPtr);
 
-    /* Allocate space for both the command pointer and the arg list */
+    
     cmdPtr = Jim_Alloc(sizeof(*cmdPtr) + sizeof(struct Jim_ProcArg) * argListLen);
     memset(cmdPtr, 0, sizeof(*cmdPtr));
     cmdPtr->inUse = 1;
     cmdPtr->isproc = 1;
     cmdPtr->u.proc.argListObjPtr = argListObjPtr;
@@ -9945,11 +8602,11 @@
     cmdPtr->u.proc.argsPos = -1;
     cmdPtr->u.proc.arglist = (struct Jim_ProcArg *)(cmdPtr + 1);
     Jim_IncrRefCount(argListObjPtr);
     Jim_IncrRefCount(bodyObjPtr);
 
-    /* Create the statics hash table. */
+    
     if (staticsListObjPtr) {
         int len, i;
 
         len = Jim_ListLength(interp, staticsListObjPtr);
         if (len != 0) {
@@ -9959,15 +8616,13 @@
                 Jim_Obj *objPtr = 0, *initObjPtr = 0, *nameObjPtr = 0;
                 Jim_Var *varPtr;
                 int subLen;
 
                 Jim_ListIndex(interp, staticsListObjPtr, i, &objPtr, JIM_NONE);
-                /* Check if it's composed of two elements. */
+                
                 subLen = Jim_ListLength(interp, objPtr);
                 if (subLen == 1 || subLen == 2) {
-                    /* Try to get the variable value from the current
-                     * environment. */
                     Jim_ListIndex(interp, objPtr, 0, &nameObjPtr, JIM_NONE);
                     if (subLen == 1) {
                         initObjPtr = Jim_GetVariable(interp, nameObjPtr, JIM_NONE);
                         if (initObjPtr == NULL) {
                             Jim_SetResultFormatted(interp,
@@ -10003,20 +8658,20 @@
                 }
             }
         }
     }
 
-    /* Parse the args out into arglist, validating as we go */
-    /* Examine the argument list for default parameters and 'args' */
+    
+    
     for (i = 0; i < argListLen; i++) {
         Jim_Obj *argPtr;
         Jim_Obj *nameObjPtr;
         Jim_Obj *defaultObjPtr;
         int len;
         int n = 1;
 
-        /* Examine a parameter */
+        
         Jim_ListIndex(interp, argListObjPtr, i, &argPtr, JIM_NONE);
         len = Jim_ListLength(interp, argPtr);
         if (len == 0) {
             Jim_SetResultString(interp, "procedure has argument with no name", -1);
             goto err;
@@ -10025,16 +8680,16 @@
             Jim_SetResultString(interp, "procedure has argument with too many fields", -1);
             goto err;
         }
 
         if (len == 2) {
-            /* Optional parameter */
+            
             Jim_ListIndex(interp, argPtr, 0, &nameObjPtr, JIM_NONE);
             Jim_ListIndex(interp, argPtr, 1, &defaultObjPtr, JIM_NONE);
         }
         else {
-            /* Required parameter */
+            
             nameObjPtr = argPtr;
             defaultObjPtr = NULL;
         }
 
 
@@ -10056,46 +8711,33 @@
 
         cmdPtr->u.proc.arglist[i].nameObjPtr = nameObjPtr;
         cmdPtr->u.proc.arglist[i].defaultObjPtr = defaultObjPtr;
     }
 
-    /* Add the new command */
+    
 
-    /* It may already exist, so we try to delete the old one.
-     * Note that reference count means that it won't be deleted yet if
-     * it exists in the call stack.
-     *
-     * BUT, if 'local' is in force, instead of deleting the existing
-     * proc, we stash a reference to the old proc here.
-     */
     he = Jim_FindHashEntry(&interp->commands, Jim_String(cmdName));
     if (he) {
-        /* There was an old procedure with the same name, this requires
-         * a 'proc epoch' update. */
 
-        /* If a procedure with the same name didn't existed there is no need
-         * to increment the 'proc epoch' because creation of a new procedure
-         * can never affect existing cached commands. We don't do
-         * negative caching. */
         Jim_InterpIncrProcEpoch(interp);
     }
 
     if (he && interp->local) {
-        /* Just push this proc over the top of the previous one */
+        
         cmdPtr->u.proc.prevCmd = he->u.val;
         he->u.val = cmdPtr;
     }
     else {
         if (he) {
-            /* Replace the existing proc */
+            
             Jim_DeleteHashEntry(&interp->commands, Jim_String(cmdName));
         }
 
         Jim_AddHashEntry(&interp->commands, Jim_String(cmdName), cmdPtr);
     }
 
-    /* Unlike Tcl, set the name of the proc as the result */
+    
     Jim_SetResult(interp, cmdName);
     return JIM_OK;
 
   err:
     if (cmdPtr->u.proc.staticVars) {
@@ -10118,42 +8760,39 @@
 
 int Jim_RenameCommand(Jim_Interp *interp, const char *oldName, const char *newName)
 {
     Jim_HashEntry *he;
 
-    /* Does it exist? */
+    
     he = Jim_FindHashEntry(&interp->commands, oldName);
     if (he == NULL) {
         Jim_SetResultFormatted(interp, "can't %s \"%s\": command doesn't exist",
             newName[0] ? "rename" : "delete", oldName);
         return JIM_ERR;
     }
 
-    if (newName[0] == '\0')     /* Delete! */
+    if (newName[0] == '\0')     
         return Jim_DeleteCommand(interp, oldName);
 
-    /* rename */
+    
     if (Jim_FindHashEntry(&interp->commands, newName)) {
         Jim_SetResultFormatted(interp, "can't rename to \"%s\": command already exists", newName);
         return JIM_ERR;
     }
 
-    /* Add the new name first */
+    
     JimIncrCmdRefCount(he->u.val);
     Jim_AddHashEntry(&interp->commands, newName, he->u.val);
 
-    /* Now remove the old name */
+    
     Jim_DeleteHashEntry(&interp->commands, oldName);
 
-    /* Increment the epoch */
+    
     Jim_InterpIncrProcEpoch(interp);
     return JIM_OK;
 }
 
-/* -----------------------------------------------------------------------------
- * Command object
- * ---------------------------------------------------------------------------*/
 
 static int SetCommandFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr);
 
 static const Jim_ObjType commandObjType = {
     "command",
@@ -10166,33 +8805,25 @@
 int SetCommandFromAny(Jim_Interp *interp, Jim_Obj *objPtr)
 {
     Jim_HashEntry *he;
     const char *cmdName;
 
-    /* Get the string representation */
+    
     cmdName = Jim_String(objPtr);
-    /* Lookup this name into the commands hash table */
+    
     he = Jim_FindHashEntry(&interp->commands, cmdName);
     if (he == NULL)
         return JIM_ERR;
 
-    /* Free the old internal repr and set the new one. */
+    
     Jim_FreeIntRep(interp, objPtr);
     objPtr->typePtr = &commandObjType;
     objPtr->internalRep.cmdValue.procEpoch = interp->procEpoch;
     objPtr->internalRep.cmdValue.cmdPtr = (void *)he->u.val;
     return JIM_OK;
 }
 
-/* This function returns the command structure for the command name
- * stored in objPtr. It tries to specialize the objPtr to contain
- * a cached info instead to perform the lookup into the hash table
- * every time. The information cached may not be uptodate, in such
- * a case the lookup is performed and the cache updated.
- *
- * Respects the 'upcall' setting
- */
 Jim_Cmd *Jim_GetCommand(Jim_Interp *interp, Jim_Obj *objPtr, int flags)
 {
     Jim_Cmd *cmd;
 
     if ((objPtr->typePtr != &commandObjType ||
@@ -10208,39 +8839,30 @@
         cmd = cmd->u.proc.prevCmd;
     }
     return cmd;
 }
 
-/* -----------------------------------------------------------------------------
- * Variables
- * ---------------------------------------------------------------------------*/
 
-/* Variables HashTable Type.
- *
- * Keys are dynamic allocated strings, Values are Jim_Var structures. */
 static void JimVariablesHTValDestructor(void *interp, void *val)
 {
     Jim_Var *varPtr = (void *)val;
 
     Jim_DecrRefCount(interp, varPtr->objPtr);
     Jim_Free(val);
 }
 
 static const Jim_HashTableType JimVariablesHashTableType = {
-    JimStringCopyHTHashFunction,        /* hash function */
-    JimStringCopyHTKeyDup,      /* key dup */
-    NULL,                       /* val dup */
-    JimStringCopyHTKeyCompare,  /* key compare */
-    JimStringCopyHTKeyDestructor,       /* key destructor */
-    JimVariablesHTValDestructor /* val destructor */
+    JimStringCopyHTHashFunction,        
+    JimStringCopyHTKeyDup,      
+    NULL,                       
+    JimStringCopyHTKeyCompare,  
+    JimStringCopyHTKeyDestructor,       
+    JimVariablesHTValDestructor 
 };
 
-/* -----------------------------------------------------------------------------
- * Variable object
- * ---------------------------------------------------------------------------*/
 
-#define JIM_DICT_SUGAR 100      /* Only returned by SetVariableFromAny() */
+#define JIM_DICT_SUGAR 100      
 
 static int SetVariableFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr);
 
 static const Jim_ObjType variableObjType = {
     "variable",
@@ -10248,28 +8870,20 @@
     NULL,
     NULL,
     JIM_TYPE_REFERENCES,
 };
 
-/* Return true if the string "str" looks like syntax sugar for [dict]. I.e.
- * is in the form "varname(key)". */
 static int JimNameIsDictSugar(const char *str, int len)
 {
     if (len && str[len - 1] == ')' && strchr(str, '(') != NULL)
         return 1;
     return 0;
 }
 
-/**
- * Check that the name does not contain embedded nulls.
- *
- * Variable and procedure names are maniplated as null terminated strings, so
- * don't allow names with embedded nulls.
- */
 static int JimValidName(Jim_Interp *interp, const char *type, Jim_Obj *nameObjPtr)
 {
-    /* Variable names and proc names can't contain embedded nulls */
+    
     if (nameObjPtr->typePtr != &variableObjType) {
         int len;
         const char *str = Jim_GetString(nameObjPtr, &len);
         if (memchr(str, '\0', len)) {
             Jim_SetResultFormatted(interp, "%s name contains embedded null", type);
@@ -10277,26 +8891,21 @@
         }
     }
     return JIM_OK;
 }
 
-/* This method should be called only by the variable API.
- * It returns JIM_OK on success (variable already exists),
- * JIM_ERR if it does not exists, JIM_DICT_SUGAR if it's not
- * a variable name, but syntax glue for [dict] i.e. the last
- * character is ')' */
 static int SetVariableFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr)
 {
     Jim_HashEntry *he;
     const char *varName;
     int len;
     Jim_CallFrame *framePtr = interp->framePtr;
 
-    /* Check if the object is already an uptodate variable */
+    
     if (objPtr->typePtr == &variableObjType &&
         objPtr->internalRep.varValue.callFrameId == framePtr->id) {
-        return JIM_OK;          /* nothing to do */
+        return JIM_OK;          
     }
 
     if (objPtr->typePtr == &dictSubstObjType) {
         return JIM_DICT_SUGAR;
     }
@@ -10303,14 +8912,14 @@
 
     if (JimValidName(interp, "variable", objPtr) != JIM_OK) {
         return JIM_ERR;
     }
 
-    /* Get the string representation */
+    
     varName = Jim_GetString(objPtr, &len);
 
-    /* Make sure it's not syntax glue to get/set dict. */
+    
     if (JimNameIsDictSugar(varName, len)) {
         return JIM_DICT_SUGAR;
     }
 
     if (varName[0] == ':' && varName[1] == ':') {
@@ -10319,37 +8928,32 @@
         if (he == NULL) {
             return JIM_ERR;
         }
     }
     else {
-        /* Lookup this name into the variables hash table */
+        
         he = Jim_FindHashEntry(&framePtr->vars, varName);
         if (he == NULL) {
-            /* Try with static vars. */
+            
             if (framePtr->staticVars == NULL)
                 return JIM_ERR;
             if (!(he = Jim_FindHashEntry(framePtr->staticVars, varName)))
                 return JIM_ERR;
         }
     }
-    /* Free the old internal repr and set the new one. */
+    
     Jim_FreeIntRep(interp, objPtr);
     objPtr->typePtr = &variableObjType;
     objPtr->internalRep.varValue.callFrameId = framePtr->id;
     objPtr->internalRep.varValue.varPtr = (void *)he->u.val;
     return JIM_OK;
 }
 
-/* -------------------- Variables related functions ------------------------- */
+
 static int JimDictSugarSet(Jim_Interp *interp, Jim_Obj *ObjPtr, Jim_Obj *valObjPtr);
 static Jim_Obj *JimDictSugarGet(Jim_Interp *interp, Jim_Obj *ObjPtr, int flags);
 
-/* For now that's dummy. Variables lookup should be optimized
- * in many ways, with caching of lookups, and possibly with
- * a table of pre-allocated vars in every CallFrame for local vars.
- * All the caching should also have an 'epoch' mechanism similar
- * to the one used by Tcl for procedures lookup caching. */
 
 int Jim_SetVariable(Jim_Interp *interp, Jim_Obj *nameObjPtr, Jim_Obj *valObjPtr)
 {
     const char *name;
     Jim_Var *var;
@@ -10356,35 +8960,35 @@
     int err;
 
     if ((err = SetVariableFromAny(interp, nameObjPtr)) != JIM_OK) {
         Jim_CallFrame *framePtr = interp->framePtr;
 
-        /* Check for [dict] syntax sugar. */
+        
         if (err == JIM_DICT_SUGAR)
             return JimDictSugarSet(interp, nameObjPtr, valObjPtr);
 
         if (JimValidName(interp, "variable", nameObjPtr) != JIM_OK) {
             return JIM_ERR;
         }
 
-        /* New variable to create */
+        
         name = Jim_String(nameObjPtr);
 
         var = Jim_Alloc(sizeof(*var));
         var->objPtr = valObjPtr;
         Jim_IncrRefCount(valObjPtr);
         var->linkFramePtr = NULL;
-        /* Insert the new variable */
+        
         if (name[0] == ':' && name[1] == ':') {
-            /* Into the top level frame */
+            
             framePtr = interp->topFramePtr;
             Jim_AddHashEntry(&framePtr->vars, name + 2, var);
         }
         else {
             Jim_AddHashEntry(&framePtr->vars, name, var);
         }
-        /* Make the object int rep a variable */
+        
         Jim_FreeIntRep(interp, nameObjPtr);
         nameObjPtr->typePtr = &variableObjType;
         nameObjPtr->internalRep.varValue.callFrameId = framePtr->id;
         nameObjPtr->internalRep.varValue.varPtr = var;
     }
@@ -10393,11 +8997,11 @@
         if (var->linkFramePtr == NULL) {
             Jim_IncrRefCount(valObjPtr);
             Jim_DecrRefCount(interp, var->objPtr);
             var->objPtr = valObjPtr;
         }
-        else {                  /* Else handle the link */
+        else {                  
             Jim_CallFrame *savedCallFrame;
 
             savedCallFrame = interp->framePtr;
             interp->framePtr = var->linkFramePtr;
             err = Jim_SetVariable(interp, var->objPtr, valObjPtr);
@@ -10455,38 +9059,38 @@
     int len;
 
     varName = Jim_GetString(nameObjPtr, &len);
 
     if (varName[0] == ':' && varName[1] == ':') {
-        /* Linking a global var does nothing */
+        
         return JIM_OK;
     }
 
     if (JimNameIsDictSugar(varName, len)) {
         Jim_SetResultString(interp, "Dict key syntax invalid as link source", -1);
         return JIM_ERR;
     }
 
-    /* Check for an existing variable or link */
+    
     if (SetVariableFromAny(interp, nameObjPtr) == JIM_OK) {
         Jim_Var *varPtr = nameObjPtr->internalRep.varValue.varPtr;
 
         if (varPtr->linkFramePtr == NULL) {
             Jim_SetResultFormatted(interp, "variable \"%#s\" already exists", nameObjPtr);
             return JIM_ERR;
         }
 
-        /* It exists, but is a link, so delete the link */
+        
         varPtr->linkFramePtr = NULL;
     }
 
-    /* Check for cycles. */
+    
     if (interp->framePtr == targetCallFrame) {
         Jim_Obj *objPtr = targetNameObjPtr;
         Jim_Var *varPtr;
 
-        /* Cycles are only possible with 'uplevel 0' */
+        
         while (1) {
             if (Jim_StringEqObj(objPtr, nameObjPtr)) {
                 Jim_SetResultString(interp, "can't upvar from variable to itself", -1);
                 return JIM_ERR;
             }
@@ -10497,27 +9101,17 @@
                 break;
             objPtr = varPtr->objPtr;
         }
     }
 
-    /* Perform the binding */
+    
     Jim_SetVariable(interp, nameObjPtr, targetNameObjPtr);
-    /* We are now sure 'nameObjPtr' type is variableObjType */
+    
     nameObjPtr->internalRep.varValue.varPtr->linkFramePtr = targetCallFrame;
     return JIM_OK;
 }
 
-/* Return the Jim_Obj pointer associated with a variable name,
- * or NULL if the variable was not found in the current context.
- * The same optimization discussed in the comment to the
- * 'SetVariable' function should apply here.
- *
- * If JIM_UNSHARED is set and the variable is an array element (dict sugar)
- * in a dictionary which is shared, the array variable value is duplicated first.
- * This allows the array element to be updated (e.g. append, lappend) without
- * affecting other references to the dictionary.
- */
 Jim_Obj *Jim_GetVariable(Jim_Interp *interp, Jim_Obj *nameObjPtr, int flags)
 {
     switch (SetVariableFromAny(interp, nameObjPtr)) {
         case JIM_OK:{
                 Jim_Var *varPtr = nameObjPtr->internalRep.varValue.varPtr;
@@ -10526,26 +9120,26 @@
                     return varPtr->objPtr;
                 }
                 else {
                     Jim_Obj *objPtr;
 
-                    /* The variable is a link? Resolve it. */
+                    
                     Jim_CallFrame *savedCallFrame = interp->framePtr;
 
                     interp->framePtr = varPtr->linkFramePtr;
                     objPtr = Jim_GetVariable(interp, varPtr->objPtr, flags);
                     interp->framePtr = savedCallFrame;
                     if (objPtr) {
                         return objPtr;
                     }
-                    /* Error, so fall through to the error message */
+                    
                 }
             }
             break;
 
         case JIM_DICT_SUGAR:
-            /* [dict] syntax sugar. */
+            
             return JimDictSugarGet(interp, nameObjPtr, flags);
     }
     if (flags & JIM_ERRMSG) {
         Jim_SetResultFormatted(interp, "can't read \"%#s\": no such variable", nameObjPtr);
     }
@@ -10587,28 +9181,25 @@
     interp->framePtr = savedFramePtr;
 
     return objPtr;
 }
 
-/* Unset a variable.
- * Note: On success unset invalidates all the variable objects created
- * in the current call frame incrementing. */
 int Jim_UnsetVariable(Jim_Interp *interp, Jim_Obj *nameObjPtr, int flags)
 {
     const char *name;
     Jim_Var *varPtr;
     int retval;
 
     retval = SetVariableFromAny(interp, nameObjPtr);
     if (retval == JIM_DICT_SUGAR) {
-        /* [dict] syntax sugar. */
+        
         return JimDictSugarSet(interp, nameObjPtr, NULL);
     }
     else if (retval == JIM_OK) {
         varPtr = nameObjPtr->internalRep.varValue.varPtr;
 
-        /* If it's a link call UnsetVariable recursively */
+        
         if (varPtr->linkFramePtr) {
             Jim_CallFrame *savedCallFrame;
 
             savedCallFrame = interp->framePtr;
             interp->framePtr = varPtr->linkFramePtr;
@@ -10623,11 +9214,11 @@
                 framePtr = interp->topFramePtr;
                 name += 2;
             }
             retval = Jim_DeleteHashEntry(&framePtr->vars, name);
             if (retval == JIM_OK) {
-                /* Change the callframe id, invalidating var lookup caching */
+                
                 JimChangeCallFrameId(interp, framePtr);
             }
         }
     }
     if (retval != JIM_OK && (flags & JIM_ERRMSG)) {
@@ -10634,19 +9225,12 @@
         Jim_SetResultFormatted(interp, "can't unset \"%#s\": no such variable", nameObjPtr);
     }
     return retval;
 }
 
-/* ----------  Dict syntax sugar (similar to array Tcl syntax) -------------- */
 
-/* Given a variable name for [dict] operation syntax sugar,
- * this function returns two objects, the first with the name
- * of the variable to set, and the second with the rispective key.
- * For example "foo(bar)" will return objects with string repr. of
- * "foo" and "bar".
- *
- * The returned objects have refcount = 1. The function can't fail. */
+
 static void JimDictSugarParseVarKey(Jim_Interp *interp, Jim_Obj *objPtr,
     Jim_Obj **varPtrPtr, Jim_Obj **keyPtrPtr)
 {
     const char *str, *p;
     int len, keyLen;
@@ -10653,66 +9237,58 @@
     Jim_Obj *varObjPtr, *keyObjPtr;
 
     str = Jim_GetString(objPtr, &len);
 
     p = strchr(str, '(');
-    JimPanic((p == NULL, interp, "JimDictSugarParseVarKey() called for non-dict-sugar (%s)", str));
+    JimPanic((p == NULL, "JimDictSugarParseVarKey() called for non-dict-sugar (%s)", str));
 
     varObjPtr = Jim_NewStringObj(interp, str, p - str);
 
     p++;
     keyLen = (str + len) - p;
     if (str[len - 1] == ')') {
         keyLen--;
     }
 
-    /* Create the objects with the variable name and key. */
+    
     keyObjPtr = Jim_NewStringObj(interp, p, keyLen);
 
     Jim_IncrRefCount(varObjPtr);
     Jim_IncrRefCount(keyObjPtr);
     *varPtrPtr = varObjPtr;
     *keyPtrPtr = keyObjPtr;
 }
 
-/* Helper of Jim_SetVariable() to deal with dict-syntax variable names.
- * Also used by Jim_UnsetVariable() with valObjPtr = NULL. */
 static int JimDictSugarSet(Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj *valObjPtr)
 {
     int err;
 
     SetDictSubstFromAny(interp, objPtr);
 
     err = Jim_SetDictKeysVector(interp, objPtr->internalRep.dictSubstValue.varNameObjPtr,
-        &objPtr->internalRep.dictSubstValue.indexObjPtr, 1, valObjPtr);
+        &objPtr->internalRep.dictSubstValue.indexObjPtr, 1, valObjPtr, JIM_ERRMSG);
 
     if (err == JIM_OK) {
-        /* Don't keep an extra ref to the result */
+        
         Jim_SetEmptyResult(interp);
     }
     else {
         if (!valObjPtr) {
-            /* Better error message for unset a(2) where a exists but a(2) doesn't */
+            
             if (Jim_GetVariable(interp, objPtr->internalRep.dictSubstValue.varNameObjPtr, JIM_NONE)) {
                 Jim_SetResultFormatted(interp, "can't unset \"%#s\": no such element in array",
                     objPtr);
                 return err;
             }
         }
-        /* Make the error more informative and Tcl-compatible */
+        
         Jim_SetResultFormatted(interp, "can't %s \"%#s\": variable isn't array",
             (valObjPtr ? "set" : "unset"), objPtr);
     }
     return err;
 }
 
-/**
- * Expands the array variable (dict sugar) and returns the result, or NULL on error.
- *
- * If JIM_UNSHARED is set and the dictionary is shared, it will be duplicated
- * and stored back to the variable before expansion.
- */
 static Jim_Obj *JimDictExpandArrayVariable(Jim_Interp *interp, Jim_Obj *varObjPtr,
     Jim_Obj *keyObjPtr, int flags)
 {
     Jim_Obj *dictObjPtr;
     Jim_Obj *resObjPtr = NULL;
@@ -10736,31 +9312,31 @@
         }
     }
     else if ((flags & JIM_UNSHARED) && Jim_IsShared(dictObjPtr)) {
         dictObjPtr = Jim_DuplicateObj(interp, dictObjPtr);
         if (Jim_SetVariable(interp, varObjPtr, dictObjPtr) != JIM_OK) {
-            /* This can probably never happen */
-            JimPanic((1, interp, "SetVariable failed for JIM_UNSHARED"));
+            
+            JimPanic((1, "SetVariable failed for JIM_UNSHARED"));
         }
-        /* We know that the key exists. Get the result in the now-unshared dictionary */
+        
         Jim_DictKey(interp, dictObjPtr, keyObjPtr, &resObjPtr, JIM_NONE);
     }
 
     return resObjPtr;
 }
 
-/* Helper of Jim_GetVariable() to deal with dict-syntax variable names */
+
 static Jim_Obj *JimDictSugarGet(Jim_Interp *interp, Jim_Obj *objPtr, int flags)
 {
     SetDictSubstFromAny(interp, objPtr);
 
     return JimDictExpandArrayVariable(interp,
         objPtr->internalRep.dictSubstValue.varNameObjPtr,
         objPtr->internalRep.dictSubstValue.indexObjPtr, flags);
 }
 
-/* --------- $var(INDEX) substitution, using a specialized object ----------- */
+
 
 void FreeDictSubstInternalRep(Jim_Interp *interp, Jim_Obj *objPtr)
 {
     Jim_DecrRefCount(interp, objPtr->internalRep.dictSubstValue.varNameObjPtr);
     Jim_DecrRefCount(interp, objPtr->internalRep.dictSubstValue.indexObjPtr);
@@ -10774,18 +9350,18 @@
         srcPtr->internalRep.dictSubstValue.varNameObjPtr;
     dupPtr->internalRep.dictSubstValue.indexObjPtr = srcPtr->internalRep.dictSubstValue.indexObjPtr;
     dupPtr->typePtr = &dictSubstObjType;
 }
 
-/* Note: The object *must* be in dict-sugar format */
+
 static void SetDictSubstFromAny(Jim_Interp *interp, Jim_Obj *objPtr)
 {
     if (objPtr->typePtr != &dictSubstObjType) {
         Jim_Obj *varObjPtr, *keyObjPtr;
 
         if (objPtr->typePtr == &interpolatedObjType) {
-            /* An interpolated object in dict-sugar form */
+            
 
             const ScriptToken *token = objPtr->internalRep.twoPtrValue.ptr1;
 
             varObjPtr = token[0].objPtr;
             keyObjPtr = objPtr->internalRep.twoPtrValue.ptr2;
@@ -10802,16 +9378,10 @@
         objPtr->internalRep.dictSubstValue.varNameObjPtr = varObjPtr;
         objPtr->internalRep.dictSubstValue.indexObjPtr = keyObjPtr;
     }
 }
 
-/* This function is used to expand [dict get] sugar in the form
- * of $var(INDEX). The function is mainly used by Jim_EvalObj()
- * to deal with tokens of type JIM_TT_DICTSUGAR. objPtr points to an
- * object that is *guaranteed* to be in the form VARNAME(INDEX).
- * The 'index' part is [subst]ituted, and is used to lookup a key inside
- * the [dict]ionary contained in variable VARNAME. */
 static Jim_Obj *JimExpandDictSugar(Jim_Interp *interp, Jim_Obj *objPtr)
 {
     Jim_Obj *resObjPtr = NULL;
     Jim_Obj *substKeyObjPtr = NULL;
 
@@ -10834,20 +9404,17 @@
 static Jim_Obj *JimExpandExprSugar(Jim_Interp *interp, Jim_Obj *objPtr)
 {
     Jim_Obj *resultObjPtr;
 
     if (Jim_EvalExpression(interp, objPtr, &resultObjPtr) == JIM_OK) {
-        /* Note that the result has a ref count of 1, but we need a ref count of 0 */
+        
         resultObjPtr->refCount--;
         return resultObjPtr;
     }
     return NULL;
 }
 
-/* -----------------------------------------------------------------------------
- * CallFrame
- * ---------------------------------------------------------------------------*/
 
 static Jim_CallFrame *JimCreateCallFrame(Jim_Interp *interp, Jim_CallFrame *parent)
 {
     Jim_CallFrame *cf;
 
@@ -10872,18 +9439,18 @@
     if (cf->vars.table == NULL)
         Jim_InitHashTable(&cf->vars, &JimVariablesHashTableType, interp);
     return cf;
 }
 
-/* Used to invalidate every caching related to callframe stability. */
+
 static void JimChangeCallFrameId(Jim_Interp *interp, Jim_CallFrame *cf)
 {
     cf->id = interp->callFrameEpoch++;
 }
 
-#define JIM_FCF_NONE 0          /* no flags */
-#define JIM_FCF_NOHT 1          /* don't free the hash table */
+#define JIM_FCF_NONE 0          
+#define JIM_FCF_NOHT 1          
 static void JimFreeCallFrame(Jim_Interp *interp, Jim_CallFrame *cf, int flags)
 {
     if (cf->procArgsObjPtr)
         Jim_DecrRefCount(interp, cf->procArgsObjPtr);
     if (cf->procBodyObjPtr)
@@ -10900,11 +9467,11 @@
                 Jim_HashEntry *nextEntry = he->next;
                 Jim_Var *varPtr = (void *)he->u.val;
 
                 Jim_DecrRefCount(interp, varPtr->objPtr);
                 Jim_Free(he->u.val);
-                Jim_Free((void *)he->key);      /* ATTENTION: const cast */
+                Jim_Free((void *)he->key);      
                 Jim_Free(he);
                 table[i] = NULL;
                 he = nextEntry;
             }
         }
@@ -10912,20 +9479,12 @@
     }
     cf->nextFramePtr = interp->freeFramesList;
     interp->freeFramesList = cf;
 }
 
-/* -----------------------------------------------------------------------------
- * References
- * ---------------------------------------------------------------------------*/
 #ifdef JIM_REFERENCES
 
-/* References HashTable Type.
- *
- * Keys are jim_wide integers, dynamically allocated for now but in the
- * future it's worth to cache this 8 bytes objects. Values are poitners
- * to Jim_References. */
 static void JimReferencesHTValDestructor(void *interp, void *val)
 {
     Jim_Reference *refPtr = (void *)val;
 
     Jim_DecrRefCount(interp, refPtr->objPtr);
@@ -10935,11 +9494,11 @@
     Jim_Free(val);
 }
 
 static unsigned int JimReferencesHTHashFunction(const void *key)
 {
-    /* Only the least significant bits are used. */
+    
     const jim_wide *widePtr = key;
     unsigned int intValue = (unsigned int)*widePtr;
 
     return Jim_IntHashFunction(intValue);
 }
@@ -10967,28 +9526,19 @@
 
     Jim_Free((void *)key);
 }
 
 static const Jim_HashTableType JimReferencesHashTableType = {
-    JimReferencesHTHashFunction,        /* hash function */
-    JimReferencesHTKeyDup,      /* key dup */
-    NULL,                       /* val dup */
-    JimReferencesHTKeyCompare,  /* key compare */
-    JimReferencesHTKeyDestructor,       /* key destructor */
-    JimReferencesHTValDestructor        /* val destructor */
+    JimReferencesHTHashFunction,        
+    JimReferencesHTKeyDup,      
+    NULL,                       
+    JimReferencesHTKeyCompare,  
+    JimReferencesHTKeyDestructor,       
+    JimReferencesHTValDestructor        
 };
 
-/* -----------------------------------------------------------------------------
- * Reference object type and References API
- * ---------------------------------------------------------------------------*/
 
-/* The string representation of references has two features in order
- * to make the GC faster. The first is that every reference starts
- * with a non common character '<', in order to make the string matching
- * faster. The second is that the reference string rep is 42 characters
- * in length, this allows to avoid to check every object with a string
- * repr < 42, and usually there aren't many of these objects. */
 
 #define JIM_REFERENCE_SPACE (35+JIM_REFERENCE_TAGLEN)
 
 static int JimFormatReference(char *buf, Jim_Reference *refPtr, jim_wide id)
 {
@@ -11019,12 +9569,10 @@
     objPtr->bytes = Jim_Alloc(len + 1);
     memcpy(objPtr->bytes, buf, len + 1);
     objPtr->length = len;
 }
 
-/* returns true if 'c' is a valid reference tag character.
- * i.e. inside the range [_a-zA-Z0-9] */
 static int isrefchar(int c)
 {
     return (c == '_' || isalnum(c));
 }
 
@@ -11035,48 +9583,48 @@
     const char *str, *start, *end;
     char refId[21];
     Jim_Reference *refPtr;
     Jim_HashEntry *he;
 
-    /* Get the string representation */
+    
     str = Jim_GetString(objPtr, &len);
-    /* Check if it looks like a reference */
+    
     if (len < JIM_REFERENCE_SPACE)
         goto badformat;
-    /* Trim spaces */
+    
     start = str;
     end = str + len - 1;
     while (*start == ' ')
         start++;
     while (*end == ' ' && end > start)
         end--;
     if (end - start + 1 != JIM_REFERENCE_SPACE)
         goto badformat;
-    /* <reference.<1234567>.%020> */
+    
     if (memcmp(start, "<reference.<", 12) != 0)
         goto badformat;
     if (start[12 + JIM_REFERENCE_TAGLEN] != '>' || end[0] != '>')
         goto badformat;
-    /* The tag can't contain chars other than a-zA-Z0-9 + '_'. */
+    
     for (i = 0; i < JIM_REFERENCE_TAGLEN; i++) {
         if (!isrefchar(start[12 + i]))
             goto badformat;
     }
-    /* Extract info from the reference. */
+    
     memcpy(refId, start + 14 + JIM_REFERENCE_TAGLEN, 20);
     refId[20] = '\0';
-    /* Try to convert the ID into a jim_wide */
+    
     if (Jim_StringToWide(refId, &wideValue, 10) != JIM_OK)
         goto badformat;
-    /* Check if the reference really exists! */
+    
     he = Jim_FindHashEntry(&interp->references, &wideValue);
     if (he == NULL) {
         Jim_SetResultFormatted(interp, "invalid reference id \"%#s\"", objPtr);
         return JIM_ERR;
     }
     refPtr = he->u.val;
-    /* Free the old internal repr and set the new one. */
+    
     Jim_FreeIntRep(interp, objPtr);
     objPtr->typePtr = &referenceObjType;
     objPtr->internalRep.refValue.id = wideValue;
     objPtr->internalRep.refValue.refPtr = refPtr;
     return JIM_OK;
@@ -11084,22 +9632,19 @@
   badformat:
     Jim_SetResultFormatted(interp, "expected reference but got \"%#s\"", objPtr);
     return JIM_ERR;
 }
 
-/* Returns a new reference pointing to objPtr, having cmdNamePtr
- * as finalizer command (or NULL if there is no finalizer).
- * The returned reference object has refcount = 0. */
 Jim_Obj *Jim_NewReference(Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj *tagPtr, Jim_Obj *cmdNamePtr)
 {
     struct Jim_Reference *refPtr;
     jim_wide wideValue = interp->referenceNextId;
     Jim_Obj *refObjPtr;
     const char *tag;
     int tagLen, i;
 
-    /* Perform the Garbage Collection if needed. */
+    
     Jim_CollectIfNeeded(interp);
 
     refPtr = Jim_Alloc(sizeof(*refPtr));
     refPtr->objPtr = objPtr;
     Jim_IncrRefCount(objPtr);
@@ -11111,12 +9656,10 @@
     refObjPtr->typePtr = &referenceObjType;
     refObjPtr->bytes = NULL;
     refObjPtr->internalRep.refValue.id = interp->referenceNextId;
     refObjPtr->internalRep.refValue.refPtr = refPtr;
     interp->referenceNextId++;
-    /* Set the tag. Trimmed at JIM_REFERENCE_TAGLEN. Everything
-     * that does not pass the 'isrefchar' test is replaced with '_' */
     tag = Jim_GetString(tagPtr, &tagLen);
     if (tagLen > JIM_REFERENCE_TAGLEN)
         tagLen = JIM_REFERENCE_TAGLEN;
     for (i = 0; i < JIM_REFERENCE_TAGLEN; i++) {
         if (i < tagLen && isrefchar(tag[i]))
@@ -11156,156 +9699,25 @@
         return JIM_ERR;
     *cmdNamePtrPtr = refPtr->finalizerCmdNamePtr;
     return JIM_OK;
 }
 
-/* -----------------------------------------------------------------------------
- * References Garbage Collection
- * ---------------------------------------------------------------------------*/
 
-/* This the hash table type for the "MARK" phase of the GC */
+
 static const Jim_HashTableType JimRefMarkHashTableType = {
-    JimReferencesHTHashFunction,        /* hash function */
-    JimReferencesHTKeyDup,      /* key dup */
-    NULL,                       /* val dup */
-    JimReferencesHTKeyCompare,  /* key compare */
-    JimReferencesHTKeyDestructor,       /* key destructor */
-    NULL                        /* val destructor */
+    JimReferencesHTHashFunction,        
+    JimReferencesHTKeyDup,      
+    NULL,                       
+    JimReferencesHTKeyCompare,  
+    JimReferencesHTKeyDestructor,       
+    NULL                        
 };
 
-/* Performs the garbage collection. */
+
 int Jim_Collect(Jim_Interp *interp)
 {
-    Jim_HashTable marks;
-    Jim_HashTableIterator *htiter;
-    Jim_HashEntry *he;
-    Jim_Obj *objPtr;
     int collected = 0;
-
-    /* Avoid recursive calls */
-    if (interp->lastCollectId == -1) {
-        /* Jim_Collect() already running. Return just now. */
-        return 0;
-    }
-    interp->lastCollectId = -1;
-
-    /* Mark all the references found into the 'mark' hash table.
-     * The references are searched in every live object that
-     * is of a type that can contain references. */
-    Jim_InitHashTable(&marks, &JimRefMarkHashTableType, NULL);
-    objPtr = interp->liveList;
-    while (objPtr) {
-        if (objPtr->typePtr == NULL || objPtr->typePtr->flags & JIM_TYPE_REFERENCES) {
-            const char *str, *p;
-            int len;
-
-            /* If the object is of type reference, to get the
-             * Id is simple... */
-            if (objPtr->typePtr == &referenceObjType) {
-                Jim_AddHashEntry(&marks, &objPtr->internalRep.refValue.id, NULL);
-#ifdef JIM_DEBUG_GC
-                printf("MARK (reference): %d refcount: %d" JIM_NL,
-                    (int)objPtr->internalRep.refValue.id, objPtr->refCount);
-#endif
-                objPtr = objPtr->nextObjPtr;
-                continue;
-            }
-            /* Get the string repr of the object we want
-             * to scan for references. */
-            p = str = Jim_GetString(objPtr, &len);
-            /* Skip objects too little to contain references. */
-            if (len < JIM_REFERENCE_SPACE) {
-                objPtr = objPtr->nextObjPtr;
-                continue;
-            }
-            /* Extract references from the object string repr. */
-            while (1) {
-                int i;
-                jim_wide id;
-                char buf[21];
-
-                if ((p = strstr(p, "<reference.<")) == NULL)
-                    break;
-                /* Check if it's a valid reference. */
-                if (len - (p - str) < JIM_REFERENCE_SPACE)
-                    break;
-                if (p[41] != '>' || p[19] != '>' || p[20] != '.')
-                    break;
-                for (i = 21; i <= 40; i++)
-                    if (!isdigit(UCHAR(p[i])))
-                        break;
-                /* Get the ID */
-                memcpy(buf, p + 21, 20);
-                buf[20] = '\0';
-                Jim_StringToWide(buf, &id, 10);
-
-                /* Ok, a reference for the given ID
-                 * was found. Mark it. */
-                Jim_AddHashEntry(&marks, &id, NULL);
-#ifdef JIM_DEBUG_GC
-                printf("MARK: %d" JIM_NL, (int)id);
-#endif
-                p += JIM_REFERENCE_SPACE;
-            }
-        }
-        objPtr = objPtr->nextObjPtr;
-    }
-
-    /* Run the references hash table to destroy every reference that
-     * is not referenced outside (not present in the mark HT). */
-    htiter = Jim_GetHashTableIterator(&interp->references);
-    while ((he = Jim_NextHashEntry(htiter)) != NULL) {
-        const jim_wide *refId;
-        Jim_Reference *refPtr;
-
-        refId = he->key;
-        /* Check if in the mark phase we encountered
-         * this reference. */
-        if (Jim_FindHashEntry(&marks, refId) == NULL) {
-#ifdef JIM_DEBUG_GC
-            printf("COLLECTING %d" JIM_NL, (int)*refId);
-#endif
-            collected++;
-            /* Drop the reference, but call the
-             * finalizer first if registered. */
-            refPtr = he->u.val;
-            if (refPtr->finalizerCmdNamePtr) {
-                char *refstr = Jim_Alloc(JIM_REFERENCE_SPACE + 1);
-                Jim_Obj *objv[3], *oldResult;
-
-                JimFormatReference(refstr, refPtr, *refId);
-
-                objv[0] = refPtr->finalizerCmdNamePtr;
-                objv[1] = Jim_NewStringObjNoAlloc(interp, refstr, 32);
-                objv[2] = refPtr->objPtr;
-                Jim_IncrRefCount(objv[0]);
-                Jim_IncrRefCount(objv[1]);
-                Jim_IncrRefCount(objv[2]);
-
-                /* Drop the reference itself */
-                Jim_DeleteHashEntry(&interp->references, refId);
-
-                /* Call the finalizer. Errors ignored. */
-                oldResult = interp->result;
-                Jim_IncrRefCount(oldResult);
-                Jim_EvalObjVector(interp, 3, objv);
-                Jim_SetResult(interp, oldResult);
-                Jim_DecrRefCount(interp, oldResult);
-
-                Jim_DecrRefCount(interp, objv[0]);
-                Jim_DecrRefCount(interp, objv[1]);
-                Jim_DecrRefCount(interp, objv[2]);
-            }
-            else {
-                Jim_DeleteHashEntry(&interp->references, refId);
-            }
-        }
-    }
-    Jim_FreeHashTableIterator(htiter);
-    Jim_FreeHashTable(&marks);
-    interp->lastCollectId = interp->referenceNextId;
-    interp->lastCollectTime = time(NULL);
     return collected;
 }
 
 #define JIM_COLLECT_ID_PERIOD 5000
 #define JIM_COLLECT_TIME_PERIOD 300
@@ -11333,53 +9745,47 @@
     } uval = {0x0102};
 
     return uval.c[0] == 1;
 }
 
-/* -----------------------------------------------------------------------------
- * Interpreter related functions
- * ---------------------------------------------------------------------------*/
 
 Jim_Interp *Jim_CreateInterp(void)
 {
     Jim_Interp *i = Jim_Alloc(sizeof(*i));
 
     memset(i, 0, sizeof(*i));
 
-    i->errorFileName = Jim_StrDup("");
     i->maxNestingDepth = JIM_MAX_NESTING_DEPTH;
     i->lastCollectTime = time(NULL);
 
-    /* Note that we can create objects only after the
-     * interpreter liveList and freeList pointers are
-     * initialized to NULL. */
     Jim_InitHashTable(&i->commands, &JimCommandsHashTableType, i);
 #ifdef JIM_REFERENCES
     Jim_InitHashTable(&i->references, &JimReferencesHashTableType, i);
 #endif
-    Jim_InitHashTable(&i->sharedStrings, &JimSharedStringsHashTableType, NULL);
     Jim_InitHashTable(&i->assocData, &JimAssocDataHashTableType, i);
     Jim_InitHashTable(&i->packages, &JimStringKeyValCopyHashTableType, NULL);
     i->framePtr = i->topFramePtr = JimCreateCallFrame(i, NULL);
     i->emptyObj = Jim_NewEmptyStringObj(i);
     i->trueObj = Jim_NewIntObj(i, 1);
     i->falseObj = Jim_NewIntObj(i, 0);
+    i->errorFileNameObj = i->emptyObj;
     i->result = i->emptyObj;
     i->stackTrace = Jim_NewListObj(i, NULL, 0);
     i->unknown = Jim_NewStringObj(i, "unknown", -1);
     i->errorProc = i->emptyObj;
     i->currentScriptObj = Jim_NewEmptyStringObj(i);
     Jim_IncrRefCount(i->emptyObj);
+    Jim_IncrRefCount(i->errorFileNameObj);
     Jim_IncrRefCount(i->result);
     Jim_IncrRefCount(i->stackTrace);
     Jim_IncrRefCount(i->unknown);
     Jim_IncrRefCount(i->currentScriptObj);
     Jim_IncrRefCount(i->errorProc);
     Jim_IncrRefCount(i->trueObj);
     Jim_IncrRefCount(i->falseObj);
 
-    /* Initialize key variables every interpreter should contain */
+    
     Jim_SetVariableStrWithStr(i, JIM_LIBPATH, TCL_LIBRARY);
     Jim_SetVariableStrWithStr(i, JIM_INTERACTIVE, "0");
 
     Jim_SetVariableStrWithStr(i, "tcl_platform(os)", TCL_PLATFORM_OS);
     Jim_SetVariableStrWithStr(i, "tcl_platform(platform)", TCL_PLATFORM_PLATFORM);
@@ -11402,11 +9808,11 @@
     Jim_DecrRefCount(i, i->falseObj);
     Jim_DecrRefCount(i, i->result);
     Jim_DecrRefCount(i, i->stackTrace);
     Jim_DecrRefCount(i, i->errorProc);
     Jim_DecrRefCount(i, i->unknown);
-    Jim_Free((void *)i->errorFileName);
+    Jim_DecrRefCount(i, i->errorFileNameObj);
     Jim_DecrRefCount(i, i->currentScriptObj);
     Jim_FreeHashTable(&i->commands);
 #ifdef JIM_REFERENCES
     Jim_FreeHashTable(&i->references);
 #endif
@@ -11413,18 +9819,16 @@
     Jim_FreeHashTable(&i->packages);
     Jim_Free(i->prngState);
     Jim_FreeHashTable(&i->assocData);
     JimDeleteLocalProcs(i);
 
-    /* Free the call frames list */
+    
     while (cf) {
         prevcf = cf->parentCallFrame;
         JimFreeCallFrame(i, cf, JIM_FCF_NONE);
         cf = prevcf;
     }
-    /* Check that the live object list is empty, otherwise
-     * there is a memory leak. */
     if (i->liveList != NULL) {
         objPtr = i->liveList;
 
         printf(JIM_NL "-------------------------------------" JIM_NL);
         printf("Objects still in the free list:" JIM_NL);
@@ -11433,26 +9837,26 @@
 
             printf("%p (%d) %-10s: '%.20s'" JIM_NL,
                 (void *)objPtr, objPtr->refCount, type, objPtr->bytes ? objPtr->bytes : "(null)");
             if (objPtr->typePtr == &sourceObjType) {
                 printf("FILE %s LINE %d" JIM_NL,
-                    objPtr->internalRep.sourceValue.fileName,
+                    Jim_String(objPtr->internalRep.sourceValue.fileNameObj),
                     objPtr->internalRep.sourceValue.lineNumber);
             }
             objPtr = objPtr->nextObjPtr;
         }
         printf("-------------------------------------" JIM_NL JIM_NL);
-        JimPanic((1, i, "Live list non empty freeing the interpreter! Leak?"));
+        JimPanic((1, "Live list non empty freeing the interpreter! Leak?"));
     }
-    /* Free all the freed objects. */
+    
     objPtr = i->freeList;
     while (objPtr) {
         nextObjPtr = objPtr->nextObjPtr;
         Jim_Free(objPtr);
         objPtr = nextObjPtr;
     }
-    /* Free cached CallFrame structures */
+    
     cf = i->freeFramesList;
     while (cf) {
         nextcf = cf->nextFramePtr;
         if (cf->vars.table != NULL)
             Jim_Free(cf->vars.table);
@@ -11461,29 +9865,14 @@
     }
 #ifdef jim_ext_load
     Jim_FreeLoadHandles(i);
 #endif
 
-    /* Free the sharedString hash table. Make sure to free it
-     * after every other Jim_Object was freed. */
-    Jim_FreeHashTable(&i->sharedStrings);
-    /* Free the interpreter structure. */
+    
     Jim_Free(i);
 }
 
-/* Returns the call frame relative to the level represented by
- * levelObjPtr. If levelObjPtr == NULL, the * level is assumed to be '1'.
- *
- * This function accepts the 'level' argument in the form
- * of the commands [uplevel] and [upvar].
- *
- * For a function accepting a relative integer as level suitable
- * for implementation of [info level ?level?] check the
- * JimGetCallFrameByInteger() function.
- *
- * Returns NULL on error.
- */
 Jim_CallFrame *Jim_GetCallFrameByLevel(Jim_Interp *interp, Jim_Obj *levelObjPtr)
 {
     long level;
     const char *str;
     Jim_CallFrame *framePtr;
@@ -11501,25 +9890,25 @@
         else {
             if (Jim_GetLong(interp, levelObjPtr, &level) != JIM_OK || level < 0) {
                 level = -1;
             }
             else {
-                /* Convert from a relative to an absolute level */
+                
                 level = interp->framePtr->level - level;
             }
         }
     }
     else {
-        str = "1";              /* Needed to format the error message. */
+        str = "1";              
         level = interp->framePtr->level - 1;
     }
 
     if (level == 0) {
         return interp->topFramePtr;
     }
     if (level > 0) {
-        /* Lookup */
+        
         for (framePtr = interp->framePtr; framePtr; framePtr = framePtr->parentCallFrame) {
             if (framePtr->level == level) {
                 return framePtr;
             }
         }
@@ -11527,29 +9916,26 @@
 
     Jim_SetResultFormatted(interp, "bad level \"%s\"", str);
     return NULL;
 }
 
-/* Similar to Jim_GetCallFrameByLevel() but the level is specified
- * as a relative integer like in the [info level ?level?] command.
- **/
 static Jim_CallFrame *JimGetCallFrameByInteger(Jim_Interp *interp, Jim_Obj *levelObjPtr)
 {
     long level;
     Jim_CallFrame *framePtr;
 
     if (Jim_GetLong(interp, levelObjPtr, &level) == JIM_OK) {
         if (level <= 0) {
-            /* Convert from a relative to an absolute level */
+            
             level = interp->framePtr->level + level;
         }
 
         if (level == 0) {
             return interp->topFramePtr;
         }
 
-        /* Lookup */
+        
         for (framePtr = interp->framePtr; framePtr; framePtr = framePtr->parentCallFrame) {
             if (framePtr->level == level) {
                 return framePtr;
             }
         }
@@ -11557,21 +9943,10 @@
 
     Jim_SetResultFormatted(interp, "bad level \"%#s\"", levelObjPtr);
     return NULL;
 }
 
-static void JimSetErrorFileName(Jim_Interp *interp, const char *filename)
-{
-    Jim_Free((void *)interp->errorFileName);
-    interp->errorFileName = Jim_StrDup(filename);
-}
-
-static void JimSetErrorLineNumber(Jim_Interp *interp, int linenr)
-{
-    interp->errorLine = linenr;
-}
-
 static void JimResetStackTrace(Jim_Interp *interp)
 {
     Jim_DecrRefCount(interp, interp->stackTrace);
     interp->stackTrace = Jim_NewListObj(interp, NULL, 0);
     Jim_IncrRefCount(interp->stackTrace);
@@ -11579,81 +9954,69 @@
 
 static void JimSetStackTrace(Jim_Interp *interp, Jim_Obj *stackTraceObj)
 {
     int len;
 
-    /* Increment reference first in case these are the same object */
+    
     Jim_IncrRefCount(stackTraceObj);
     Jim_DecrRefCount(interp, interp->stackTrace);
     interp->stackTrace = stackTraceObj;
     interp->errorFlag = 1;
 
-    /* This is a bit ugly.
-     * If the filename of the last entry of the stack trace is empty,
-     * the next stack level should be added.
-     */
     len = Jim_ListLength(interp, interp->stackTrace);
     if (len >= 3) {
         Jim_Obj *filenameObj;
 
         Jim_ListIndex(interp, interp->stackTrace, len - 2, &filenameObj, JIM_NONE);
 
         Jim_GetString(filenameObj, &len);
 
-        if (len == 0) {
+        if (!Jim_Length(filenameObj)) {
             interp->addStackTrace = 1;
         }
     }
 }
 
-/* Returns 1 if the stack trace information was used or 0 if not */
+
 static void JimAppendStackTrace(Jim_Interp *interp, const char *procname,
-    const char *filename, int linenr)
+    Jim_Obj *fileNameObj, int linenr)
 {
     if (strcmp(procname, "unknown") == 0) {
         procname = "";
     }
-    if (!*procname && !*filename) {
-        /* No useful info here */
+    if (!*procname && !Jim_Length(fileNameObj)) {
+        
         return;
     }
 
     if (Jim_IsShared(interp->stackTrace)) {
         Jim_DecrRefCount(interp, interp->stackTrace);
         interp->stackTrace = Jim_DuplicateObj(interp, interp->stackTrace);
         Jim_IncrRefCount(interp->stackTrace);
     }
 
-    /* If we have no procname but the previous element did, merge with that frame */
-    if (!*procname && *filename) {
-        /* Just a filename. Check the previous entry */
+    
+    if (!*procname && Jim_Length(fileNameObj)) {
+        
         int len = Jim_ListLength(interp, interp->stackTrace);
 
         if (len >= 3) {
-            Jim_Obj *procnameObj;
-            Jim_Obj *filenameObj;
-
-            if (Jim_ListIndex(interp, interp->stackTrace, len - 3, &procnameObj, JIM_NONE) == JIM_OK
-                && Jim_ListIndex(interp, interp->stackTrace, len - 2, &filenameObj,
-                    JIM_NONE) == JIM_OK) {
-
-                const char *prev_procname = Jim_String(procnameObj);
-                const char *prev_filename = Jim_String(filenameObj);
-
-                if (*prev_procname && !*prev_filename) {
-                    ListSetIndex(interp, interp->stackTrace, len - 2, Jim_NewStringObj(interp,
-                            filename, -1), 0);
-                    ListSetIndex(interp, interp->stackTrace, len - 1, Jim_NewIntObj(interp, linenr),
-                        0);
+            Jim_Obj *objPtr;
+            if (Jim_ListIndex(interp, interp->stackTrace, len - 3, &objPtr, JIM_NONE) == JIM_OK && Jim_Length(objPtr)) {
+                
+                if (Jim_ListIndex(interp, interp->stackTrace, len - 2, &objPtr, JIM_NONE) == JIM_OK && !Jim_Length(objPtr)) {
+                    
+                    ListSetIndex(interp, interp->stackTrace, len - 2, fileNameObj, 0);
+                    ListSetIndex(interp, interp->stackTrace, len - 1, Jim_NewIntObj(interp, linenr), 0);
                     return;
                 }
             }
         }
     }
 
     Jim_ListAppendElement(interp, interp->stackTrace, Jim_NewStringObj(interp, procname, -1));
-    Jim_ListAppendElement(interp, interp->stackTrace, Jim_NewStringObj(interp, filename, -1));
+    Jim_ListAppendElement(interp, interp->stackTrace, fileNameObj);
     Jim_ListAppendElement(interp, interp->stackTrace, Jim_NewIntObj(interp, linenr));
 }
 
 int Jim_SetAssocData(Jim_Interp *interp, const char *key, Jim_InterpDeleteProc * delProc,
     void *data)
@@ -11685,57 +10048,10 @@
 int Jim_GetExitCode(Jim_Interp *interp)
 {
     return interp->exitCode;
 }
 
-/* -----------------------------------------------------------------------------
- * Shared strings.
- * Every interpreter has an hash table where to put shared dynamically
- * allocate strings that are likely to be used a lot of times.
- * For example, in the 'source' object type, there is a pointer to
- * the filename associated with that object. Every script has a lot
- * of this objects with the identical file name, so it is wise to share
- * this info.
- *
- * The API is trivial: Jim_GetSharedString(interp, "foobar")
- * returns the pointer to the shared string. Every time a reference
- * to the string is no longer used, the user should call
- * Jim_ReleaseSharedString(interp, stringPointer). Once no one is using
- * a given string, it is removed from the hash table.
- * ---------------------------------------------------------------------------*/
-const char *Jim_GetSharedString(Jim_Interp *interp, const char *str)
-{
-    Jim_HashEntry *he = Jim_FindHashEntry(&interp->sharedStrings, str);
-
-    if (he == NULL) {
-        char *strCopy = Jim_StrDup(str);
-
-        Jim_AddHashEntry(&interp->sharedStrings, strCopy, NULL);
-	he = Jim_FindHashEntry(&interp->sharedStrings, strCopy);
-	he->u.intval = 1;
-        return strCopy;
-    }
-    else {
-        he->u.intval++;
-        return he->key;
-    }
-}
-
-void Jim_ReleaseSharedString(Jim_Interp *interp, const char *str)
-{
-    Jim_HashEntry *he = Jim_FindHashEntry(&interp->sharedStrings, str);
-
-    JimPanic((he == NULL, interp, "Jim_ReleaseSharedString called with " "unknown shared string '%s'", str));
-
-    if (--he->u.intval == 0) {
-        Jim_DeleteHashEntry(&interp->sharedStrings, str);
-    }
-}
-
-/* -----------------------------------------------------------------------------
- * Integer object
- * ---------------------------------------------------------------------------*/
 #define JIM_INTEGER_SPACE 24
 
 static void UpdateStringOfInt(struct Jim_Obj *objPtr);
 static int SetIntFromAny(Jim_Interp *interp, Jim_Obj *objPtr, int flags);
 
@@ -11745,15 +10061,10 @@
     NULL,
     UpdateStringOfInt,
     JIM_TYPE_NONE,
 };
 
-/* A coerced double is closer to an int than a double.
- * It is an int value temporarily masquerading as a double value.
- * i.e. it has the same string value as an int and Jim_GetWide()
- * succeeds, but also Jim_GetDouble() returns the value directly.
- */
 static const Jim_ObjType coercedDoubleObjType = {
     "coerced-double",
     NULL,
     NULL,
     UpdateStringOfInt,
@@ -11776,18 +10087,18 @@
 {
     jim_wide wideValue;
     const char *str;
 
     if (objPtr->typePtr == &coercedDoubleObjType) {
-        /* Simple switcheroo */
+        
         objPtr->typePtr = &intObjType;
         return JIM_OK;
     }
 
-    /* Get the string representation */
+    
     str = Jim_String(objPtr);
-    /* Try to convert into a jim_wide */
+    
     if (Jim_StringToWide(str, &wideValue, 0) != JIM_OK) {
         if (flags & JIM_ERRMSG) {
             Jim_SetResultFormatted(interp, "expected integer but got \"%#s\"", objPtr);
         }
         return JIM_ERR;
@@ -11794,11 +10105,11 @@
     }
     if ((wideValue == JIM_WIDE_MIN || wideValue == JIM_WIDE_MAX) && errno == ERANGE) {
         Jim_SetResultString(interp, "Integer value too big to be represented", -1);
         return JIM_ERR;
     }
-    /* Free the old internal repr and set the new one. */
+    
     Jim_FreeIntRep(interp, objPtr);
     objPtr->typePtr = &intObjType;
     objPtr->internalRep.wideValue = wideValue;
     return JIM_OK;
 }
@@ -11816,11 +10127,11 @@
         return JIM_ERR;
     *widePtr = JimWideValue(objPtr);
     return JIM_OK;
 }
 
-/* Get a wide but does not set an error if the format is bad. */
+
 static int JimGetWideNoErr(Jim_Interp *interp, Jim_Obj *objPtr, jim_wide * widePtr)
 {
     if (objPtr->typePtr != &intObjType && SetIntFromAny(interp, objPtr, JIM_NONE) == JIM_ERR)
         return JIM_ERR;
     *widePtr = JimWideValue(objPtr);
@@ -11849,13 +10160,10 @@
     objPtr->bytes = NULL;
     objPtr->internalRep.wideValue = wideValue;
     return objPtr;
 }
 
-/* -----------------------------------------------------------------------------
- * Double object
- * ---------------------------------------------------------------------------*/
 #define JIM_DOUBLE_SPACE 30
 
 static void UpdateStringOfDouble(struct Jim_Obj *objPtr);
 static int SetDoubleFromAny(Jim_Interp *interp, Jim_Obj *objPtr);
 
@@ -11882,44 +10190,41 @@
 {
     double doubleValue;
     jim_wide wideValue;
     const char *str;
 
-    /* Preserve the string representation.
-     * Needed so we can convert back to int without loss
-     */
     str = Jim_String(objPtr);
 
 #ifdef HAVE_LONG_LONG
-    /* Assume a 53 bit mantissa */
+    
 #define MIN_INT_IN_DOUBLE -(1LL << 53)
 #define MAX_INT_IN_DOUBLE -(MIN_INT_IN_DOUBLE + 1)
 
     if (objPtr->typePtr == &intObjType
         && JimWideValue(objPtr) >= MIN_INT_IN_DOUBLE
         && JimWideValue(objPtr) <= MAX_INT_IN_DOUBLE) {
 
-        /* Direct conversion to coerced double */
+        
         objPtr->typePtr = &coercedDoubleObjType;
         return JIM_OK;
     }
     else
 #endif
     if (Jim_StringToWide(str, &wideValue, 10) == JIM_OK) {
-        /* Managed to convert to an int, so we can use this as a cooerced double */
+        
         Jim_FreeIntRep(interp, objPtr);
         objPtr->typePtr = &coercedDoubleObjType;
         objPtr->internalRep.wideValue = wideValue;
         return JIM_OK;
     }
     else {
-        /* Try to convert into a double */
+        
         if (Jim_StringToDouble(str, &doubleValue) != JIM_OK) {
             Jim_SetResultFormatted(interp, "expected number but got \"%#s\"", objPtr);
             return JIM_ERR;
         }
-        /* Free the old internal repr and set the new one. */
+        
         Jim_FreeIntRep(interp, objPtr);
     }
     objPtr->typePtr = &doubleObjType;
     objPtr->internalRep.doubleValue = doubleValue;
     return JIM_OK;
@@ -11952,23 +10257,17 @@
     objPtr->bytes = NULL;
     objPtr->internalRep.doubleValue = doubleValue;
     return objPtr;
 }
 
-/* -----------------------------------------------------------------------------
- * List object
- * ---------------------------------------------------------------------------*/
+static void ListInsertElements(Jim_Obj *listPtr, int idx, int elemc, Jim_Obj *const *elemVec);
 static void ListAppendElement(Jim_Obj *listPtr, Jim_Obj *objPtr);
 static void FreeListInternalRep(Jim_Interp *interp, Jim_Obj *objPtr);
 static void DupListInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr);
 static void UpdateStringOfList(struct Jim_Obj *objPtr);
 static int SetListFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr);
 
-/* Note that while the elements of the list may contain references,
- * the list object itself can't. This basically means that the
- * list object string representation as a whole can't contain references
- * that are not presents in the single elements. */
 static const Jim_ObjType listObjType = {
     "list",
     FreeListInternalRep,
     DupListInternalRep,
     UpdateStringOfList,
@@ -12001,21 +10300,18 @@
         Jim_IncrRefCount(dupPtr->internalRep.listValue.ele[i]);
     }
     dupPtr->typePtr = &listObjType;
 }
 
-/* The following function checks if a given string can be encoded
- * into a list element without any kind of quoting, surrounded by braces,
- * or using escapes to quote. */
 #define JIM_ELESTR_SIMPLE 0
 #define JIM_ELESTR_BRACE 1
 #define JIM_ELESTR_QUOTE 2
 static int ListElementQuotingType(const char *s, int len)
 {
     int i, level, blevel, trySimple = 1;
 
-    /* Try with the SIMPLE case */
+    
     if (len == 0)
         return JIM_ELESTR_BRACE;
     if (s[0] == '#')
         return JIM_ELESTR_BRACE;
     if (s[0] == '"' || s[0] == '{') {
@@ -12043,11 +10339,11 @@
         }
     }
     return JIM_ELESTR_SIMPLE;
 
   testbrace:
-    /* Test if it's possible to do with braces */
+    
     if (s[len - 1] == '\\')
         return JIM_ELESTR_QUOTE;
     level = 0;
     blevel = 0;
     for (i = 0; i < len; i++) {
@@ -12102,12 +10398,10 @@
         return JIM_ELESTR_SIMPLE;
     }
     return JIM_ELESTR_QUOTE;
 }
 
-/* Returns the malloc-ed representation of a string
- * using backslash to quote special chars. */
 static char *BackslashQuoteString(const char *s, int len, int *qlenPtr)
 {
     char *q = Jim_Alloc(len * 2 + 1), *p;
 
     p = q;
@@ -12166,11 +10460,11 @@
     const char *strRep;
     char *p;
     int *quotingType;
     Jim_Obj **ele = objPtr->internalRep.listValue.ele;
 
-    /* (Over) Estimate the space needed. */
+    
     quotingType = Jim_Alloc(sizeof(int) * objPtr->internalRep.listValue.len + 1);
     bufLen = 0;
     for (i = 0; i < objPtr->internalRep.listValue.len; i++) {
         int len;
 
@@ -12185,15 +10479,15 @@
                 break;
             case JIM_ELESTR_QUOTE:
                 bufLen += len * 2;
                 break;
         }
-        bufLen++;               /* elements separator. */
+        bufLen++;               
     }
     bufLen++;
 
-    /* Generate the string rep. */
+    
     p = objPtr->bytes = Jim_Alloc(bufLen + 1);
     realLength = 0;
     for (i = 0; i < objPtr->internalRep.listValue.len; i++) {
         int len, qlen;
         char *q;
@@ -12219,95 +10513,91 @@
                 Jim_Free(q);
                 p += qlen;
                 realLength += qlen;
                 break;
         }
-        /* Add a separating space */
+        
         if (i + 1 != objPtr->internalRep.listValue.len) {
             *p++ = ' ';
             realLength++;
         }
     }
-    *p = '\0';                  /* nul term. */
+    *p = '\0';                  
     objPtr->length = realLength;
     Jim_Free(quotingType);
 }
 
-int SetListFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr)
+static int SetListFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr)
 {
     struct JimParserCtx parser;
     const char *str;
     int strLen;
-    const char *filename = NULL;
-    int linenr = 1;
+    Jim_Obj *fileNameObj;
+    int linenr;
 
-    /* Try to preserve information about filename / line number */
+    
     if (objPtr->typePtr == &sourceObjType) {
-        filename = Jim_GetSharedString(interp, objPtr->internalRep.sourceValue.fileName);
+        fileNameObj = objPtr->internalRep.sourceValue.fileNameObj;
         linenr = objPtr->internalRep.sourceValue.lineNumber;
     }
+    else {
+        fileNameObj = interp->emptyObj;
+        linenr = 1;
+    }
+    Jim_IncrRefCount(fileNameObj);
 
-    /* Get the string representation */
+    
     str = Jim_GetString(objPtr, &strLen);
 
-    /* Free the old internal repr just now and initialize the
-     * new one just now. The string->list conversion can't fail. */
     Jim_FreeIntRep(interp, objPtr);
     objPtr->typePtr = &listObjType;
     objPtr->internalRep.listValue.len = 0;
     objPtr->internalRep.listValue.maxLen = 0;
     objPtr->internalRep.listValue.ele = NULL;
 
-    /* Convert into a list */
+    
     JimParserInit(&parser, str, strLen, linenr);
     while (!parser.eof) {
         Jim_Obj *elementPtr;
 
         JimParseList(&parser);
         if (parser.tt != JIM_TT_STR && parser.tt != JIM_TT_ESC)
             continue;
         elementPtr = JimParserGetTokenObj(interp, &parser);
-        JimSetSourceInfo(interp, elementPtr, filename, parser.tline);
+        JimSetSourceInfo(interp, elementPtr, fileNameObj, parser.tline);
         ListAppendElement(objPtr, elementPtr);
     }
-    if (filename) {
-        Jim_ReleaseSharedString(interp, filename);
-    }
+    Jim_DecrRefCount(interp, fileNameObj);
     return JIM_OK;
 }
 
 Jim_Obj *Jim_NewListObj(Jim_Interp *interp, Jim_Obj *const *elements, int len)
 {
     Jim_Obj *objPtr;
-    int i;
 
     objPtr = Jim_NewObj(interp);
     objPtr->typePtr = &listObjType;
     objPtr->bytes = NULL;
     objPtr->internalRep.listValue.ele = NULL;
     objPtr->internalRep.listValue.len = 0;
     objPtr->internalRep.listValue.maxLen = 0;
-    for (i = 0; i < len; i++) {
-        ListAppendElement(objPtr, elements[i]);
+
+    if (len) {
+        ListInsertElements(objPtr, 0, len, elements);
     }
+
     return objPtr;
 }
 
-/* Return a vector of Jim_Obj with the elements of a Jim list, and the
- * length of the vector. Note that the user of this function should make
- * sure that the list object can't shimmer while the vector returned
- * is in use, this vector is the one stored inside the internal representation
- * of the list object. This function is not exported, extensions should
- * always access to the List object elements using Jim_ListIndex(). */
 static void JimListGetElements(Jim_Interp *interp, Jim_Obj *listObj, int *listLen,
     Jim_Obj ***listVec)
 {
     *listLen = Jim_ListLength(interp, listObj);
     *listVec = listObj->internalRep.listValue.ele;
 }
 
-/* Sorting uses ints, but commands may return wide */
+
 static int JimSign(jim_wide w)
 {
     if (w == 0) {
         return 0;
     }
@@ -12315,11 +10605,11 @@
         return -1;
     }
     return 1;
 }
 
-/* ListSortElements type values */
+
 struct lsort_info {
     jmp_buf jmpbuf;
     Jim_Obj *command;
     Jim_Interp *interp;
     enum {
@@ -12345,11 +10635,11 @@
         longjmp(sort_info->jmpbuf, JIM_ERR);
     }
     return sort_info->subfn(&lObj, &rObj);
 }
 
-/* Sort the internal rep of a list. */
+
 static int ListSortString(Jim_Obj **lhsObj, Jim_Obj **rhsObj)
 {
     return Jim_StringCompareObj(sort_info->interp, *lhsObj, *rhsObj, 0) * sort_info->order;
 }
 
@@ -12375,11 +10665,11 @@
     Jim_Obj *compare_script;
     int rc;
 
     jim_wide ret = 0;
 
-    /* This must be a valid list */
+    
     compare_script = Jim_DuplicateObj(sort_info->interp, sort_info->command);
     Jim_ListAppendElement(sort_info->interp, compare_script, *lhsObj);
     Jim_ListAppendElement(sort_info->interp, compare_script, *rhsObj);
 
     rc = Jim_EvalObj(sort_info->interp, compare_script);
@@ -12389,11 +10679,11 @@
     }
 
     return JimSign(ret) * sort_info->order;
 }
 
-/* Sort a list *in place*. MUST be called with non-shared objects. */
+
 static int ListSortElements(Jim_Interp *interp, Jim_Obj *listObjPtr, struct lsort_info *info)
 {
     struct lsort_info *prev_info;
 
     typedef int (qsort_comparator) (const void *, const void *);
@@ -12400,15 +10690,15 @@
     int (*fn) (Jim_Obj **, Jim_Obj **);
     Jim_Obj **vector;
     int len;
     int rc;
 
-    JimPanic((Jim_IsShared(listObjPtr), interp, "Jim_ListSortElements called with shared object"));
+    JimPanic((Jim_IsShared(listObjPtr), "Jim_ListSortElements called with shared object"));
     if (!Jim_IsList(listObjPtr))
         SetListFromAny(interp, listObjPtr);
 
-    /* Allow lsort to be called reentrantly */
+    
     prev_info = sort_info;
     sort_info = info;
 
     vector = listObjPtr->internalRep.listValue.ele;
     len = listObjPtr->internalRep.listValue.len;
@@ -12424,16 +10714,16 @@
             break;
         case JIM_LSORT_COMMAND:
             fn = ListSortCommand;
             break;
         default:
-            fn = NULL;          /* avoid warning */
-            JimPanic((1, interp, "ListSort called with invalid sort type"));
+            fn = NULL;          
+            JimPanic((1, "ListSort called with invalid sort type"));
     }
 
     if (info->indexed) {
-        /* Need to interpose a "list index" function */
+        
         info->subfn = fn;
         fn = ListSortIndexHelper;
     }
 
     if ((rc = setjmp(info->jmpbuf)) == 0) {
@@ -12443,30 +10733,25 @@
     sort_info = prev_info;
 
     return rc;
 }
 
-/* This is the low-level function to insert elements into a list.
- * The higher-level Jim_ListInsertElements() performs shared object
- * check and invalidate the string repr. This version is used
- * in the internals of the List Object and is not exported.
- *
- * NOTE: this function can be called only against objects
- * with internal type of List. */
 static void ListInsertElements(Jim_Obj *listPtr, int idx, int elemc, Jim_Obj *const *elemVec)
 {
     int currentLen = listPtr->internalRep.listValue.len;
     int requiredLen = currentLen + elemc;
     int i;
     Jim_Obj **point;
 
     if (requiredLen > listPtr->internalRep.listValue.maxLen) {
-        int maxLen = requiredLen * 2;
+        listPtr->internalRep.listValue.maxLen = requiredLen * 2;
 
-        listPtr->internalRep.listValue.ele =
-            Jim_Realloc(listPtr->internalRep.listValue.ele, sizeof(Jim_Obj *) * maxLen);
-        listPtr->internalRep.listValue.maxLen = maxLen;
+        listPtr->internalRep.listValue.ele = Jim_Realloc(listPtr->internalRep.listValue.ele,
+            sizeof(Jim_Obj *) * listPtr->internalRep.listValue.maxLen);
+    }
+    if (idx < 0) {
+        idx = currentLen;
     }
     point = listPtr->internalRep.listValue.ele + idx;
     memmove(point + elemc, point, (currentLen - idx) * sizeof(Jim_Obj *));
     for (i = 0; i < elemc; ++i) {
         point[i] = elemVec[i];
@@ -12473,40 +10758,33 @@
         Jim_IncrRefCount(point[i]);
     }
     listPtr->internalRep.listValue.len += elemc;
 }
 
-/* Convenience call to ListInsertElements() to append a single element.
- */
 static void ListAppendElement(Jim_Obj *listPtr, Jim_Obj *objPtr)
 {
-    ListInsertElements(listPtr, listPtr->internalRep.listValue.len, 1, &objPtr);
+    ListInsertElements(listPtr, -1, 1, &objPtr);
 }
 
-
-/* Appends every element of appendListPtr into listPtr.
- * Both have to be of the list type.
- * Convenience call to ListInsertElements()
- */
 static void ListAppendList(Jim_Obj *listPtr, Jim_Obj *appendListPtr)
 {
-    ListInsertElements(listPtr, listPtr->internalRep.listValue.len,
+    ListInsertElements(listPtr, -1,
         appendListPtr->internalRep.listValue.len, appendListPtr->internalRep.listValue.ele);
 }
 
 void Jim_ListAppendElement(Jim_Interp *interp, Jim_Obj *listPtr, Jim_Obj *objPtr)
 {
-    JimPanic((Jim_IsShared(listPtr), interp, "Jim_ListAppendElement called with shared object"));
+    JimPanic((Jim_IsShared(listPtr), "Jim_ListAppendElement called with shared object"));
     if (!Jim_IsList(listPtr))
         SetListFromAny(interp, listPtr);
     Jim_InvalidateStringRep(listPtr);
     ListAppendElement(listPtr, objPtr);
 }
 
 void Jim_ListAppendList(Jim_Interp *interp, Jim_Obj *listPtr, Jim_Obj *appendListPtr)
 {
-    JimPanic((Jim_IsShared(listPtr), interp, "Jim_ListAppendList called with shared object"));
+    JimPanic((Jim_IsShared(listPtr), "Jim_ListAppendList called with shared object"));
     if (!Jim_IsList(listPtr))
         SetListFromAny(interp, listPtr);
     Jim_InvalidateStringRep(listPtr);
     ListAppendList(listPtr, appendListPtr);
 }
@@ -12519,11 +10797,11 @@
 }
 
 void Jim_ListInsertElements(Jim_Interp *interp, Jim_Obj *listPtr, int idx,
     int objc, Jim_Obj *const *objVec)
 {
-    JimPanic((Jim_IsShared(listPtr), interp, "Jim_ListInsertElement called with shared object"));
+    JimPanic((Jim_IsShared(listPtr), "Jim_ListInsertElement called with shared object"));
     if (!Jim_IsList(listPtr))
         SetListFromAny(interp, listPtr);
     if (idx >= 0 && idx > listPtr->internalRep.listValue.len)
         idx = listPtr->internalRep.listValue.len;
     else if (idx < 0)
@@ -12568,13 +10846,10 @@
     listPtr->internalRep.listValue.ele[idx] = newObjPtr;
     Jim_IncrRefCount(newObjPtr);
     return JIM_OK;
 }
 
-/* Modify the list stored into the variable named 'varNamePtr'
- * setting the element specified by the 'indexc' indexes objects in 'indexv',
- * with the new element 'newObjptr'. */
 int Jim_SetListIndex(Jim_Interp *interp, Jim_Obj *varNamePtr,
     Jim_Obj *const *indexv, int indexc, Jim_Obj *newObjPtr)
 {
     Jim_Obj *varObjPtr, *objPtr, *listObjPtr;
     int shared, i, idx;
@@ -12616,51 +10891,48 @@
 
 Jim_Obj *Jim_ConcatObj(Jim_Interp *interp, int objc, Jim_Obj *const *objv)
 {
     int i;
 
-    /* If all the objects in objv are lists,
-     * it's possible to return a list as result, that's the
-     * concatenation of all the lists. */
     for (i = 0; i < objc; i++) {
         if (!Jim_IsList(objv[i]))
             break;
     }
     if (i == objc) {
         Jim_Obj *objPtr = Jim_NewListObj(interp, NULL, 0);
 
         for (i = 0; i < objc; i++)
-            Jim_ListAppendList(interp, objPtr, objv[i]);
+            ListAppendList(objPtr, objv[i]);
         return objPtr;
     }
     else {
-        /* Else... we have to glue strings together */
+        
         int len = 0, objLen;
         char *bytes, *p;
 
-        /* Compute the length */
+        
         for (i = 0; i < objc; i++) {
             Jim_GetString(objv[i], &objLen);
             len += objLen;
         }
         if (objc)
             len += objc - 1;
-        /* Create the string rep, and a string object holding it. */
+        
         p = bytes = Jim_Alloc(len + 1);
         for (i = 0; i < objc; i++) {
             const char *s = Jim_GetString(objv[i], &objLen);
 
-            /* Remove leading space */
+            
             while (objLen && (*s == ' ' || *s == '\t' || *s == '\n')) {
                 s++;
                 objLen--;
                 len--;
             }
-            /* And trailing space */
+            
             while (objLen && (s[objLen - 1] == ' ' ||
                     s[objLen - 1] == '\n' || s[objLen - 1] == '\t')) {
-                /* Handle trailing backslash-space case */
+                
                 if (objLen > 1 && s[objLen - 2] == '\\') {
                     break;
                 }
                 objLen--;
                 len--;
@@ -12669,63 +10941,51 @@
             p += objLen;
             if (objLen && i + 1 != objc) {
                 *p++ = ' ';
             }
             else if (i + 1 != objc) {
-                /* Drop the space calcuated for this
-                 * element that is instead null. */
                 len--;
             }
         }
         *p = '\0';
         return Jim_NewStringObjNoAlloc(interp, bytes, len);
     }
 }
 
-/* Returns a list composed of the elements in the specified range.
- * first and start are directly accepted as Jim_Objects and
- * processed for the end?-index? case. */
 Jim_Obj *Jim_ListRange(Jim_Interp *interp, Jim_Obj *listObjPtr, Jim_Obj *firstObjPtr,
     Jim_Obj *lastObjPtr)
 {
     int first, last;
     int len, rangeLen;
 
     if (Jim_GetIndex(interp, firstObjPtr, &first) != JIM_OK ||
         Jim_GetIndex(interp, lastObjPtr, &last) != JIM_OK)
         return NULL;
-    len = Jim_ListLength(interp, listObjPtr);   /* will convert into list */
+    len = Jim_ListLength(interp, listObjPtr);   
     first = JimRelToAbsIndex(len, first);
     last = JimRelToAbsIndex(len, last);
     JimRelToAbsRange(len, first, last, &first, &last, &rangeLen);
     if (first == 0 && last == len) {
         return listObjPtr;
     }
     return Jim_NewListObj(interp, listObjPtr->internalRep.listValue.ele + first, rangeLen);
 }
 
-/* -----------------------------------------------------------------------------
- * Dict object
- * ---------------------------------------------------------------------------*/
 static void FreeDictInternalRep(Jim_Interp *interp, Jim_Obj *objPtr);
 static void DupDictInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr);
 static void UpdateStringOfDict(struct Jim_Obj *objPtr);
 static int SetDictFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr);
 
-/* Dict HashTable Type.
- *
- * Keys and Values are Jim objects. */
 
 static unsigned int JimObjectHTHashFunction(const void *key)
 {
     const char *str;
     Jim_Obj *objPtr = (Jim_Obj *)key;
-    int len, h;
+    int len;
 
     str = Jim_GetString(objPtr, &len);
-    h = Jim_GenHashFunction((unsigned char *)str, len);
-    return h;
+    return Jim_GenHashFunction((unsigned char *)str, len);
 }
 
 static int JimObjectHTKeyCompare(void *privdata, const void *key1, const void *key2)
 {
     JIM_NOTUSED(privdata);
@@ -12739,23 +10999,19 @@
 
     Jim_DecrRefCount(interp, objPtr);
 }
 
 static const Jim_HashTableType JimDictHashTableType = {
-    JimObjectHTHashFunction,    /* hash function */
-    NULL,                       /* key dup */
-    NULL,                       /* val dup */
-    JimObjectHTKeyCompare,      /* key compare */
-    (void (*)(void *, const void *))    /* ATTENTION: const cast */
-        JimObjectHTKeyValDestructor,    /* key destructor */
-    JimObjectHTKeyValDestructor /* val destructor */
+    JimObjectHTHashFunction,    
+    NULL,                       
+    NULL,                       
+    JimObjectHTKeyCompare,      
+    (void (*)(void *, const void *))    
+        JimObjectHTKeyValDestructor,    
+    JimObjectHTKeyValDestructor 
 };
 
-/* Note that while the elements of the dict may contain references,
- * the list object itself can't. This basically means that the
- * dict object string representation as a whole can't contain references
- * that are not presents in the single elements. */
 static const Jim_ObjType dictObjType = {
     "dict",
     FreeDictInternalRep,
     DupDictInternalRep,
     UpdateStringOfDict,
@@ -12774,23 +11030,23 @@
 {
     Jim_HashTable *ht, *dupHt;
     Jim_HashTableIterator *htiter;
     Jim_HashEntry *he;
 
-    /* Create a new hash table */
+    
     ht = srcPtr->internalRep.ptr;
     dupHt = Jim_Alloc(sizeof(*dupHt));
     Jim_InitHashTable(dupHt, &JimDictHashTableType, interp);
     if (ht->size != 0)
         Jim_ExpandHashTable(dupHt, ht->size);
-    /* Copy every element from the source to the dup hash table */
+    
     htiter = Jim_GetHashTableIterator(ht);
     while ((he = Jim_NextHashEntry(htiter)) != NULL) {
         const Jim_Obj *keyObjPtr = he->key;
         Jim_Obj *valObjPtr = he->u.val;
 
-        Jim_IncrRefCount((Jim_Obj *)keyObjPtr); /* ATTENTION: const cast */
+        Jim_IncrRefCount((Jim_Obj *)keyObjPtr); 
         Jim_IncrRefCount(valObjPtr);
         Jim_AddHashEntry(dupHt, keyObjPtr, valObjPtr);
     }
     Jim_FreeHashTableIterator(htiter);
 
@@ -12807,22 +11063,22 @@
     Jim_HashTable *ht;
     Jim_HashTableIterator *htiter;
     Jim_HashEntry *he;
     Jim_Obj **objv;
 
-    /* Trun the hash table into a flat vector of Jim_Objects. */
+    
     ht = objPtr->internalRep.ptr;
     objc = ht->used * 2;
     objv = Jim_Alloc(objc * sizeof(Jim_Obj *));
     htiter = Jim_GetHashTableIterator(ht);
     i = 0;
     while ((he = Jim_NextHashEntry(htiter)) != NULL) {
-        objv[i++] = (Jim_Obj *)he->key; /* ATTENTION: const cast */
+        objv[i++] = (Jim_Obj *)he->key; 
         objv[i++] = he->u.val;
     }
     Jim_FreeHashTableIterator(htiter);
-    /* (Over) Estimate the space needed. */
+    
     quotingType = Jim_Alloc(sizeof(int) * objc);
     bufLen = 0;
     for (i = 0; i < objc; i++) {
         int len;
 
@@ -12837,15 +11093,15 @@
                 break;
             case JIM_ELESTR_QUOTE:
                 bufLen += len * 2;
                 break;
         }
-        bufLen++;               /* elements separator. */
+        bufLen++;               
     }
     bufLen++;
 
-    /* Generate the string rep. */
+    
     p = objPtr->bytes = Jim_Alloc(bufLen + 1);
     realLength = 0;
     for (i = 0; i < objc; i++) {
         int len, qlen;
         char *q;
@@ -12871,40 +11127,37 @@
                 Jim_Free(q);
                 p += qlen;
                 realLength += qlen;
                 break;
         }
-        /* Add a separating space */
+        
         if (i + 1 != objc) {
             *p++ = ' ';
             realLength++;
         }
     }
-    *p = '\0';                  /* nul term. */
+    *p = '\0';                  
     objPtr->length = realLength;
     Jim_Free(quotingType);
     Jim_Free(objv);
 }
 
 static int SetDictFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr)
 {
     int listlen;
 
-    /* Get the string representation. Do this first so we don't
-     * change order in case of fast conversion to dict.
-     */
     Jim_String(objPtr);
 
-    /* For simplicity, convert a non-list object to a list and then to a dict */
+    
     listlen = Jim_ListLength(interp, objPtr);
     if (listlen % 2) {
         Jim_SetResultString(interp,
             "invalid dictionary value: must be a list with an even number of elements", -1);
         return JIM_ERR;
     }
     else {
-        /* Now it is easy to convert to a dict from a list, and it can't fail */
+        
         Jim_HashTable *ht;
         int i;
 
         ht = Jim_Alloc(sizeof(*ht));
         Jim_InitHashTable(ht, &JimDictHashTableType, interp);
@@ -12922,11 +11175,11 @@
             if (Jim_AddHashEntry(ht, keyObjPtr, valObjPtr) != JIM_OK) {
                 Jim_HashEntry *he;
 
                 he = Jim_FindHashEntry(ht, keyObjPtr);
                 Jim_DecrRefCount(interp, keyObjPtr);
-                /* ATTENTION: const cast */
+                
                 Jim_DecrRefCount(interp, (Jim_Obj *)he->u.val);
                 he->u.val = valObjPtr;
             }
         }
 
@@ -12936,47 +11189,39 @@
 
         return JIM_OK;
     }
 }
 
-/* Dict object API */
 
-/* Add an element to a dict. objPtr must be of the "dict" type.
- * The higer-level exported function is Jim_DictAddElement().
- * If an element with the specified key already exists, the value
- * associated is replaced with the new one.
- *
- * if valueObjPtr == NULL, the key is instead removed if it exists. */
+
 static int DictAddElement(Jim_Interp *interp, Jim_Obj *objPtr,
     Jim_Obj *keyObjPtr, Jim_Obj *valueObjPtr)
 {
     Jim_HashTable *ht = objPtr->internalRep.ptr;
 
-    if (valueObjPtr == NULL) {  /* unset */
+    if (valueObjPtr == NULL) {  
         return Jim_DeleteHashEntry(ht, keyObjPtr);
     }
     Jim_IncrRefCount(keyObjPtr);
     Jim_IncrRefCount(valueObjPtr);
     if (Jim_AddHashEntry(ht, keyObjPtr, valueObjPtr) != JIM_OK) {
         Jim_HashEntry *he = Jim_FindHashEntry(ht, keyObjPtr);
 
         Jim_DecrRefCount(interp, keyObjPtr);
-        /* ATTENTION: const cast */
+        
         Jim_DecrRefCount(interp, (Jim_Obj *)he->u.val);
         he->u.val = valueObjPtr;
     }
     return JIM_OK;
 }
 
-/* Add an element, higher-level interface for DictAddElement().
- * If valueObjPtr == NULL, the key is removed if it exists. */
 int Jim_DictAddElement(Jim_Interp *interp, Jim_Obj *objPtr,
     Jim_Obj *keyObjPtr, Jim_Obj *valueObjPtr)
 {
     int retcode;
 
-    JimPanic((Jim_IsShared(objPtr), interp, "Jim_DictAddElement called with shared object"));
+    JimPanic((Jim_IsShared(objPtr), "Jim_DictAddElement called with shared object"));
     if (objPtr->typePtr != &dictObjType) {
         if (SetDictFromAny(interp, objPtr) != JIM_OK)
             return JIM_ERR;
     }
     retcode = DictAddElement(interp, objPtr, keyObjPtr, valueObjPtr);
@@ -12987,11 +11232,11 @@
 Jim_Obj *Jim_NewDictObj(Jim_Interp *interp, Jim_Obj *const *elements, int len)
 {
     Jim_Obj *objPtr;
     int i;
 
-    JimPanic((len % 2, interp, "Jim_NewDictObj() 'len' argument must be even"));
+    JimPanic((len % 2, "Jim_NewDictObj() 'len' argument must be even"));
 
     objPtr = Jim_NewObj(interp);
     objPtr->typePtr = &dictObjType;
     objPtr->bytes = NULL;
     objPtr->internalRep.ptr = Jim_Alloc(sizeof(Jim_HashTable));
@@ -12999,13 +11244,10 @@
     for (i = 0; i < len; i += 2)
         DictAddElement(interp, objPtr, elements[i], elements[i + 1]);
     return objPtr;
 }
 
-/* Return the value associated to the specified dict key
- * Note: Returns JIM_OK if OK, JIM_ERR if entry not found or -1 if can't create dict value
- */
 int Jim_DictKey(Jim_Interp *interp, Jim_Obj *dictPtr, Jim_Obj *keyPtr,
     Jim_Obj **objPtrPtr, int flags)
 {
     Jim_HashEntry *he;
     Jim_HashTable *ht;
@@ -13023,11 +11265,11 @@
     }
     *objPtrPtr = he->u.val;
     return JIM_OK;
 }
 
-/* Return an allocated array of key/value pairs for the dictionary. Stores the length in *len */
+
 int Jim_DictPairs(Jim_Interp *interp, Jim_Obj *dictPtr, Jim_Obj ***objPtrPtr, int *len)
 {
     Jim_HashTable *ht;
     Jim_HashTableIterator *htiter;
     Jim_HashEntry *he;
@@ -13038,26 +11280,26 @@
         if (SetDictFromAny(interp, dictPtr) != JIM_OK)
             return JIM_ERR;
     }
     ht = dictPtr->internalRep.ptr;
 
-    /* Turn the hash table into a flat vector of Jim_Objects. */
+    
     objv = Jim_Alloc((ht->used * 2) * sizeof(Jim_Obj *));
     htiter = Jim_GetHashTableIterator(ht);
     i = 0;
     while ((he = Jim_NextHashEntry(htiter)) != NULL) {
-        objv[i++] = (Jim_Obj *)he->key; /* ATTENTION: const cast */
+        objv[i++] = (Jim_Obj *)he->key; 
         objv[i++] = he->u.val;
     }
     *len = i;
     Jim_FreeHashTableIterator(htiter);
     *objPtrPtr = objv;
     return JIM_OK;
 }
 
 
-/* Return the value associated to the specified dict keys */
+
 int Jim_DictKeysVector(Jim_Interp *interp, Jim_Obj *dictPtr,
     Jim_Obj *const *keyv, int keyc, Jim_Obj **objPtrPtr, int flags)
 {
     int i;
 
@@ -13076,27 +11318,22 @@
     }
     *objPtrPtr = dictPtr;
     return JIM_OK;
 }
 
-/* Modify the dict stored into the variable named 'varNamePtr'
- * setting the element specified by the 'keyc' keys objects in 'keyv',
- * with the new value of the element 'newObjPtr'.
- *
- * If newObjPtr == NULL the operation is to remove the given key
- * from the dictionary. */
 int Jim_SetDictKeysVector(Jim_Interp *interp, Jim_Obj *varNamePtr,
-    Jim_Obj *const *keyv, int keyc, Jim_Obj *newObjPtr)
+    Jim_Obj *const *keyv, int keyc, Jim_Obj *newObjPtr, int flags)
 {
     Jim_Obj *varObjPtr, *objPtr, *dictObjPtr;
     int shared, i;
 
     varObjPtr = objPtr =
         Jim_GetVariable(interp, varNamePtr, newObjPtr == NULL ? JIM_ERRMSG : JIM_NONE);
     if (objPtr == NULL) {
-        if (newObjPtr == NULL)  /* Cannot remove a key from non existing var */
+        if (newObjPtr == NULL)   {
             return JIM_ERR;
+        }
         varObjPtr = objPtr = Jim_NewDictObj(interp, NULL, 0);
         if (Jim_SetVariable(interp, varNamePtr, objPtr) != JIM_OK) {
             Jim_FreeNewObj(interp, varObjPtr);
             return JIM_ERR;
         }
@@ -13104,57 +11341,53 @@
     if ((shared = Jim_IsShared(objPtr)))
         varObjPtr = objPtr = Jim_DuplicateObj(interp, objPtr);
     for (i = 0; i < keyc - 1; i++) {
         dictObjPtr = objPtr;
 
-        /* Check if it's a valid dictionary */
+        
         if (dictObjPtr->typePtr != &dictObjType) {
-            if (SetDictFromAny(interp, dictObjPtr) != JIM_OK)
+            if (SetDictFromAny(interp, dictObjPtr) != JIM_OK) {
                 goto err;
+            }
         }
-        /* Check if the given key exists. */
+        
         Jim_InvalidateStringRep(dictObjPtr);
         if (Jim_DictKey(interp, dictObjPtr, keyv[i], &objPtr,
                 newObjPtr ? JIM_NONE : JIM_ERRMSG) == JIM_OK) {
-            /* This key exists at the current level.
-             * Make sure it's not shared!. */
             if (Jim_IsShared(objPtr)) {
                 objPtr = Jim_DuplicateObj(interp, objPtr);
                 DictAddElement(interp, dictObjPtr, keyv[i], objPtr);
             }
         }
         else {
-            /* Key not found. If it's an [unset] operation
-             * this is an error. Only the last key may not
-             * exist. */
-            if (newObjPtr == NULL)
+            if (newObjPtr == NULL) {
                 goto err;
-            /* Otherwise set an empty dictionary
-             * as key's value. */
+            }
             objPtr = Jim_NewDictObj(interp, NULL, 0);
             DictAddElement(interp, dictObjPtr, keyv[i], objPtr);
         }
     }
+    
     if (Jim_DictAddElement(interp, objPtr, keyv[keyc - 1], newObjPtr) != JIM_OK) {
-        goto err;
+        if (newObjPtr || (flags & JIM_ERRMSG)) {
+            goto err;
+        }
     }
     Jim_InvalidateStringRep(objPtr);
     Jim_InvalidateStringRep(varObjPtr);
-    if (Jim_SetVariable(interp, varNamePtr, varObjPtr) != JIM_OK)
+    if (Jim_SetVariable(interp, varNamePtr, varObjPtr) != JIM_OK) {
         goto err;
+    }
     Jim_SetResult(interp, varObjPtr);
     return JIM_OK;
   err:
     if (shared) {
         Jim_FreeNewObj(interp, varObjPtr);
     }
     return JIM_ERR;
 }
 
-/* -----------------------------------------------------------------------------
- * Index object
- * ---------------------------------------------------------------------------*/
 static void UpdateStringOfIndex(struct Jim_Obj *objPtr);
 static int SetIndexFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr);
 
 static const Jim_ObjType indexObjType = {
     "index",
@@ -13185,14 +11418,14 @@
 {
     int idx, end = 0;
     const char *str;
     char *endptr;
 
-    /* Get the string representation */
+    
     str = Jim_String(objPtr);
 
-    /* Try to convert into an index */
+    
     if (strncmp(str, "end", 3) == 0) {
         end = 1;
         str += 3;
         idx = 0;
     }
@@ -13203,21 +11436,21 @@
             goto badindex;
         }
         str = endptr;
     }
 
-    /* Now str may include or +<num> or -<num> */
+    
     if (*str == '+' || *str == '-') {
         int sign = (*str == '+' ? 1 : -1);
 
         idx += sign * strtol(++str, &endptr, 10);
         if (str == endptr || *endptr) {
             goto badindex;
         }
         str = endptr;
     }
-    /* The only thing left should be spaces */
+    
     while (isspace(UCHAR(*str))) {
         str++;
     }
     if (*str) {
         goto badindex;
@@ -13225,19 +11458,19 @@
     if (end) {
         if (idx > 0) {
             idx = INT_MAX;
         }
         else {
-            /* end-1 is repesented as -2 */
+            
             idx--;
         }
     }
     else if (idx < 0) {
         idx = -INT_MAX;
     }
 
-    /* Free the old internal repr and set the new one. */
+    
     Jim_FreeIntRep(interp, objPtr);
     objPtr->typePtr = &indexObjType;
     objPtr->internalRep.indexValue = idx;
     return JIM_OK;
 
@@ -13247,11 +11480,11 @@
     return JIM_ERR;
 }
 
 int Jim_GetIndex(Jim_Interp *interp, Jim_Obj *objPtr, int *indexPtr)
 {
-    /* Avoid shimmering if the object is an integer. */
+    
     if (objPtr->typePtr == &intObjType) {
         jim_wide val = JimWideValue(objPtr);
 
         if (!(val < LONG_MIN) && !(val > LONG_MAX)) {
             *indexPtr = (val < 0) ? -INT_MAX : (long)val;;
@@ -13262,24 +11495,21 @@
         return JIM_ERR;
     *indexPtr = objPtr->internalRep.indexValue;
     return JIM_OK;
 }
 
-/* -----------------------------------------------------------------------------
- * Return Code Object.
- * ---------------------------------------------------------------------------*/
 
-/* NOTE: These must be kept in the same order as JIM_OK, JIM_ERR, ... */
+
 static const char * const jimReturnCodes[] = {
-    [JIM_OK] = "ok",
-    [JIM_ERR] = "error",
-    [JIM_RETURN] = "return",
-    [JIM_BREAK] = "break",
-    [JIM_CONTINUE] = "continue",
-    [JIM_SIGNAL] = "signal",
-    [JIM_EXIT] = "exit",
-    [JIM_EVAL] = "eval",
+    "ok",
+    "error",
+    "return",
+    "break",
+    "continue",
+    "signal",
+    "exit",
+    "eval",
     NULL
 };
 
 #define jimReturnCodesSize (sizeof(jimReturnCodes)/sizeof(*jimReturnCodes))
 
@@ -13291,13 +11521,10 @@
     NULL,
     NULL,
     JIM_TYPE_NONE,
 };
 
-/* Converts a (standard) return code to a string. Returns "?" for
- * non-standard return codes.
- */
 const char *Jim_ReturnCode(int code)
 {
     if (code < 0 || code >= (int)jimReturnCodesSize) {
         return "?";
     }
@@ -13309,18 +11536,18 @@
 int SetReturnCodeFromAny(Jim_Interp *interp, Jim_Obj *objPtr)
 {
     int returnCode;
     jim_wide wideValue;
 
-    /* Try to convert into an integer */
+    
     if (JimGetWideNoErr(interp, objPtr, &wideValue) != JIM_ERR)
         returnCode = (int)wideValue;
     else if (Jim_GetEnum(interp, objPtr, jimReturnCodes, &returnCode, NULL, JIM_NONE) != JIM_OK) {
         Jim_SetResultFormatted(interp, "expected return code but got \"%#s\"", objPtr);
         return JIM_ERR;
     }
-    /* Free the old internal repr and set the new one. */
+    
     Jim_FreeIntRep(interp, objPtr);
     objPtr->typePtr = &returnCodeObjType;
     objPtr->internalRep.returnCode = returnCode;
     return JIM_OK;
 }
@@ -13331,25 +11558,22 @@
         return JIM_ERR;
     *intPtr = objPtr->internalRep.returnCode;
     return JIM_OK;
 }
 
-/* -----------------------------------------------------------------------------
- * Expression Parsing
- * ---------------------------------------------------------------------------*/
 static int JimParseExprOperator(struct JimParserCtx *pc);
 static int JimParseExprNumber(struct JimParserCtx *pc);
 static int JimParseExprIrrational(struct JimParserCtx *pc);
 
-/* Exrp's Stack machine operators opcodes. */
 
-/* Binary operators (numbers) */
+
+
 enum
 {
-    /* Continues on from the JIM_TT_ space */
-    /* Operations */
-    JIM_EXPROP_MUL = JIM_TT_EXPR_OP,    /* 15 */
+    
+    
+    JIM_EXPROP_MUL = JIM_TT_EXPR_OP,             
     JIM_EXPROP_DIV,
     JIM_EXPROP_MOD,
     JIM_EXPROP_SUB,
     JIM_EXPROP_ADD,
     JIM_EXPROP_LSHIFT,
@@ -13360,61 +11584,60 @@
     JIM_EXPROP_GT,
     JIM_EXPROP_LTE,
     JIM_EXPROP_GTE,
     JIM_EXPROP_NUMEQ,
     JIM_EXPROP_NUMNE,
-    JIM_EXPROP_BITAND,          /* 30 */
+    JIM_EXPROP_BITAND,          
     JIM_EXPROP_BITXOR,
     JIM_EXPROP_BITOR,
 
-    /* Note must keep these together */
-    JIM_EXPROP_LOGICAND,        /* 33 */
+    
+    JIM_EXPROP_LOGICAND,        
     JIM_EXPROP_LOGICAND_LEFT,
     JIM_EXPROP_LOGICAND_RIGHT,
 
-    /* and these */
-    JIM_EXPROP_LOGICOR,         /* 36 */
+    
+    JIM_EXPROP_LOGICOR,         
     JIM_EXPROP_LOGICOR_LEFT,
     JIM_EXPROP_LOGICOR_RIGHT,
 
-    /* and these */
-    /* Ternary operators */
-    JIM_EXPROP_TERNARY,         /* 39 */
+    
+    
+    JIM_EXPROP_TERNARY,         
     JIM_EXPROP_TERNARY_LEFT,
     JIM_EXPROP_TERNARY_RIGHT,
 
-    /* and these */
-    JIM_EXPROP_COLON,           /* 42 */
+    
+    JIM_EXPROP_COLON,           
     JIM_EXPROP_COLON_LEFT,
     JIM_EXPROP_COLON_RIGHT,
 
-    JIM_EXPROP_POW,             /* 45 */
+    JIM_EXPROP_POW,             
 
-/* Binary operators (strings) */
-    JIM_EXPROP_STREQ,
+
+    JIM_EXPROP_STREQ,           
     JIM_EXPROP_STRNE,
     JIM_EXPROP_STRIN,
     JIM_EXPROP_STRNI,
 
-/* Unary operators (numbers) */
-    JIM_EXPROP_NOT,
+
+    JIM_EXPROP_NOT,             
     JIM_EXPROP_BITNOT,
     JIM_EXPROP_UNARYMINUS,
     JIM_EXPROP_UNARYPLUS,
 
-    /* Functions */
-    JIM_EXPROP_FUNC_FIRST,
+    
+    JIM_EXPROP_FUNC_FIRST,      
     JIM_EXPROP_FUNC_INT = JIM_EXPROP_FUNC_FIRST,
     JIM_EXPROP_FUNC_ABS,
     JIM_EXPROP_FUNC_DOUBLE,
     JIM_EXPROP_FUNC_ROUND,
     JIM_EXPROP_FUNC_RAND,
     JIM_EXPROP_FUNC_SRAND,
 
-#ifdef JIM_MATH_FUNCTIONS
-    /* math functions from libm */
-    JIM_EXPROP_FUNC_SIN,
+    
+    JIM_EXPROP_FUNC_SIN,        
     JIM_EXPROP_FUNC_COS,
     JIM_EXPROP_FUNC_TAN,
     JIM_EXPROP_FUNC_ASIN,
     JIM_EXPROP_FUNC_ACOS,
     JIM_EXPROP_FUNC_ATAN,
@@ -13425,11 +11648,11 @@
     JIM_EXPROP_FUNC_FLOOR,
     JIM_EXPROP_FUNC_EXP,
     JIM_EXPROP_FUNC_LOG,
     JIM_EXPROP_FUNC_LOG10,
     JIM_EXPROP_FUNC_SQRT,
-#endif
+    JIM_EXPROP_FUNC_POW,
 };
 
 struct JimExprState
 {
     Jim_Obj **stack;
@@ -13436,11 +11659,11 @@
     int stacklen;
     int opcode;
     int skip;
 };
 
-/* Operators table */
+
 typedef struct Jim_ExprOperator
 {
     const char *name;
     int precedence;
     int arity;
@@ -13575,11 +11798,11 @@
     return rc;
 }
 
 static int JimExprOpNone(Jim_Interp *interp, struct JimExprState *e)
 {
-    JimPanic((e->opcode != JIM_EXPROP_FUNC_RAND));
+    JimPanic((e->opcode != JIM_EXPROP_FUNC_RAND, "JimExprOpNone only support rand()"));
 
     ExprPush(e, Jim_NewDoubleObj(interp, JimRandDouble(interp)));
 
     return JIM_OK;
 }
@@ -13649,11 +11872,11 @@
 
     return rc;
 }
 #endif
 
-/* A binary operation on two ints */
+
 static int JimExprOpIntBin(Jim_Interp *interp, struct JimExprState *e)
 {
     Jim_Obj *B = ExprPop(e);
     Jim_Obj *A = ExprPop(e);
     jim_wide wA, wB;
@@ -13685,18 +11908,10 @@
                     wC = 0;
                     Jim_SetResultString(interp, "Division by zero", -1);
                     rc = JIM_ERR;
                 }
                 else {
-                    /*
-                     * From Tcl 8.x
-                     *
-                     * This code is tricky: C doesn't guarantee much
-                     * about the quotient or remainder, but Tcl does.
-                     * The remainder always has the same sign as the
-                     * divisor and a smaller absolute value.
-                     */
                     int negative = 0;
 
                     if (wB < 0) {
                         wB = -wB;
                         wA = -wA;
@@ -13711,16 +11926,16 @@
                     }
                 }
                 break;
             case JIM_EXPROP_ROTL:
             case JIM_EXPROP_ROTR:{
-                    /* uint32_t would be better. But not everyone has inttypes.h? */
+                    
                     unsigned long uA = (unsigned long)wA;
                     unsigned long uB = (unsigned long)wB;
                     const unsigned int S = sizeof(unsigned long) * 8;
 
-                    /* Shift left by the word size or more is undefined. */
+                    
                     uB %= S;
 
                     if (e->opcode == JIM_EXPROP_ROTR) {
                         uB = S - uB;
                     }
@@ -13739,11 +11954,11 @@
 
     return rc;
 }
 
 
-/* A binary operation on two ints or two doubles (or two strings for some ops) */
+
 static int JimExprOpBin(Jim_Interp *interp, struct JimExprState *e)
 {
     int intresult = 0;
     int rc = JIM_OK;
     double dA, dB, dC = 0;
@@ -13754,16 +11969,17 @@
 
     if ((A->typePtr != &doubleObjType || A->bytes) &&
         (B->typePtr != &doubleObjType || B->bytes) &&
         JimGetWideNoErr(interp, A, &wA) == JIM_OK && JimGetWideNoErr(interp, B, &wB) == JIM_OK) {
 
-        /* Both are ints */
+        
 
         intresult = 1;
 
         switch (e->opcode) {
             case JIM_EXPROP_POW:
+            case JIM_EXPROP_FUNC_POW:
                 wC = JimPowWide(wA, wB);
                 break;
             case JIM_EXPROP_ADD:
                 wC = wA + wB;
                 break;
@@ -13777,18 +11993,10 @@
                 if (wB == 0) {
                     Jim_SetResultString(interp, "Division by zero", -1);
                     rc = JIM_ERR;
                 }
                 else {
-                    /*
-                     * From Tcl 8.x
-                     *
-                     * This code is tricky: C doesn't guarantee much
-                     * about the quotient or remainder, but Tcl does.
-                     * The remainder always has the same sign as the
-                     * divisor and a smaller absolute value.
-                     */
                     if (wB < 0) {
                         wB = -wB;
                         wA = -wA;
                     }
                     wC = wA / wB;
@@ -13820,10 +12028,11 @@
         }
     }
     else if (Jim_GetDouble(interp, A, &dA) == JIM_OK && Jim_GetDouble(interp, B, &dB) == JIM_OK) {
         switch (e->opcode) {
             case JIM_EXPROP_POW:
+            case JIM_EXPROP_FUNC_POW:
 #ifdef JIM_MATH_FUNCTIONS
                 dC = pow(dA, dB);
 #else
                 Jim_SetResultString(interp, "unsupported", -1);
                 rc = JIM_ERR;
@@ -13877,13 +12086,13 @@
             default:
                 abort();
         }
     }
     else {
-        /* Handle the string case */
+        
 
-        /* REVISIT: Could optimise the eq/ne case by checking lengths */
+        
         int i = Jim_StringCompareObj(interp, A, B, 0);
 
         intresult = 1;
 
         switch (e->opcode) {
@@ -14003,21 +12212,21 @@
     Jim_Obj *A = ExprPop(e);
     int rc = JIM_OK;
 
     switch (ExprBool(interp, A)) {
         case 0:
-            /* false, so skip RHS opcodes with a 0 result */
+            
             e->skip = JimWideValue(skip);
             ExprPush(e, Jim_NewIntObj(interp, 0));
             break;
 
         case 1:
-            /* true so continue */
+            
             break;
 
         case -1:
-            /* Invalid */
+            
             rc = JIM_ERR;
     }
     Jim_DecrRefCount(interp, A);
     Jim_DecrRefCount(interp, skip);
 
@@ -14030,21 +12239,21 @@
     Jim_Obj *A = ExprPop(e);
     int rc = JIM_OK;
 
     switch (ExprBool(interp, A)) {
         case 0:
-            /* false, so do nothing */
+            
             break;
 
         case 1:
-            /* true so skip RHS opcodes with a 1 result */
+            
             e->skip = JimWideValue(skip);
             ExprPush(e, Jim_NewIntObj(interp, 1));
             break;
 
         case -1:
-            /* Invalid */
+            
             rc = JIM_ERR;
             break;
     }
     Jim_DecrRefCount(interp, A);
     Jim_DecrRefCount(interp, skip);
@@ -14065,11 +12274,11 @@
         case 1:
             ExprPush(e, Jim_NewIntObj(interp, 1));
             break;
 
         case -1:
-            /* Invalid */
+            
             rc = JIM_ERR;
             break;
     }
     Jim_DecrRefCount(interp, A);
 
@@ -14080,27 +12289,27 @@
 {
     Jim_Obj *skip = ExprPop(e);
     Jim_Obj *A = ExprPop(e);
     int rc = JIM_OK;
 
-    /* Repush A */
+    
     ExprPush(e, A);
 
     switch (ExprBool(interp, A)) {
         case 0:
-            /* false, skip RHS opcodes */
+            
             e->skip = JimWideValue(skip);
-            /* Push a dummy value */
+            
             ExprPush(e, Jim_NewIntObj(interp, 0));
             break;
 
         case 1:
-            /* true so do nothing */
+            
             break;
 
         case -1:
-            /* Invalid */
+            
             rc = JIM_ERR;
             break;
     }
     Jim_DecrRefCount(interp, A);
     Jim_DecrRefCount(interp, skip);
@@ -14112,15 +12321,15 @@
 {
     Jim_Obj *skip = ExprPop(e);
     Jim_Obj *B = ExprPop(e);
     Jim_Obj *A = ExprPop(e);
 
-    /* No need to check for A as non-boolean */
+    
     if (ExprBool(interp, A)) {
-        /* true, so skip RHS opcodes */
+        
         e->skip = JimWideValue(skip);
-        /* Repush B as the answer */
+        
         ExprPush(e, B);
     }
 
     Jim_DecrRefCount(interp, skip);
     Jim_DecrRefCount(interp, A);
@@ -14139,98 +12348,104 @@
     LAZY_OP,
     LAZY_LEFT,
     LAZY_RIGHT
 };
 
-/* name - precedence - arity - opcode */
 static const struct Jim_ExprOperator Jim_ExprOperators[] = {
-    [JIM_EXPROP_FUNC_INT] = {"int", 400, 1, JimExprOpNumUnary, LAZY_NONE},
-    [JIM_EXPROP_FUNC_DOUBLE] = {"double", 400, 1, JimExprOpNumUnary, LAZY_NONE},
-    [JIM_EXPROP_FUNC_ABS] = {"abs", 400, 1, JimExprOpNumUnary, LAZY_NONE},
-    [JIM_EXPROP_FUNC_ROUND] = {"round", 400, 1, JimExprOpNumUnary, LAZY_NONE},
-    [JIM_EXPROP_FUNC_RAND] = {"rand", 400, 0, JimExprOpNone, LAZY_NONE},
-    [JIM_EXPROP_FUNC_SRAND] = {"srand", 400, 1, JimExprOpIntUnary, LAZY_NONE},
+    {"*", 200, 2, JimExprOpBin, LAZY_NONE},
+    {"/", 200, 2, JimExprOpBin, LAZY_NONE},
+    {"%", 200, 2, JimExprOpIntBin, LAZY_NONE},
+
+    {"-", 100, 2, JimExprOpBin, LAZY_NONE},
+    {"+", 100, 2, JimExprOpBin, LAZY_NONE},
+
+    {"<<", 90, 2, JimExprOpIntBin, LAZY_NONE},
+    {">>", 90, 2, JimExprOpIntBin, LAZY_NONE},
+
+    {"<<<", 90, 2, JimExprOpIntBin, LAZY_NONE},
+    {">>>", 90, 2, JimExprOpIntBin, LAZY_NONE},
+
+    {"<", 80, 2, JimExprOpBin, LAZY_NONE},
+    {">", 80, 2, JimExprOpBin, LAZY_NONE},
+    {"<=", 80, 2, JimExprOpBin, LAZY_NONE},
+    {">=", 80, 2, JimExprOpBin, LAZY_NONE},
+
+    {"==", 70, 2, JimExprOpBin, LAZY_NONE},
+    {"!=", 70, 2, JimExprOpBin, LAZY_NONE},
+
+    {"&", 50, 2, JimExprOpIntBin, LAZY_NONE},
+    {"^", 49, 2, JimExprOpIntBin, LAZY_NONE},
+    {"|", 48, 2, JimExprOpIntBin, LAZY_NONE},
+
+    {"&&", 10, 2, NULL, LAZY_OP},
+    {NULL, 10, 2, JimExprOpAndLeft, LAZY_LEFT},
+    {NULL, 10, 2, JimExprOpAndOrRight, LAZY_RIGHT},
+
+    {"||", 9, 2, NULL, LAZY_OP},
+    {NULL, 9, 2, JimExprOpOrLeft, LAZY_LEFT},
+    {NULL, 9, 2, JimExprOpAndOrRight, LAZY_RIGHT},
+
+    {"?", 5, 2, JimExprOpNull, LAZY_OP},
+    {NULL, 5, 2, JimExprOpTernaryLeft, LAZY_LEFT},
+    {NULL, 5, 2, JimExprOpNull, LAZY_RIGHT},
+
+    {":", 5, 2, JimExprOpNull, LAZY_OP},
+    {NULL, 5, 2, JimExprOpColonLeft, LAZY_LEFT},
+    {NULL, 5, 2, JimExprOpNull, LAZY_RIGHT},
+
+    {"**", 250, 2, JimExprOpBin, LAZY_NONE},
+
+    {"eq", 60, 2, JimExprOpStrBin, LAZY_NONE},
+    {"ne", 60, 2, JimExprOpStrBin, LAZY_NONE},
+
+    {"in", 55, 2, JimExprOpStrBin, LAZY_NONE},
+    {"ni", 55, 2, JimExprOpStrBin, LAZY_NONE},
+
+    {"!", 300, 1, JimExprOpNumUnary, LAZY_NONE},
+    {"~", 300, 1, JimExprOpIntUnary, LAZY_NONE},
+    {NULL, 300, 1, JimExprOpNumUnary, LAZY_NONE},
+    {NULL, 300, 1, JimExprOpNumUnary, LAZY_NONE},
+
+
+
+    {"int", 400, 1, JimExprOpNumUnary, LAZY_NONE},
+    {"abs", 400, 1, JimExprOpNumUnary, LAZY_NONE},
+    {"double", 400, 1, JimExprOpNumUnary, LAZY_NONE},
+    {"round", 400, 1, JimExprOpNumUnary, LAZY_NONE},
+    {"rand", 400, 0, JimExprOpNone, LAZY_NONE},
+    {"srand", 400, 1, JimExprOpIntUnary, LAZY_NONE},
 
 #ifdef JIM_MATH_FUNCTIONS
-    [JIM_EXPROP_FUNC_SIN] = {"sin", 400, 1, JimExprOpDoubleUnary, LAZY_NONE},
-    [JIM_EXPROP_FUNC_COS] = {"cos", 400, 1, JimExprOpDoubleUnary, LAZY_NONE},
-    [JIM_EXPROP_FUNC_TAN] = {"tan", 400, 1, JimExprOpDoubleUnary, LAZY_NONE},
-    [JIM_EXPROP_FUNC_ASIN] = {"asin", 400, 1, JimExprOpDoubleUnary, LAZY_NONE},
-    [JIM_EXPROP_FUNC_ACOS] = {"acos", 400, 1, JimExprOpDoubleUnary, LAZY_NONE},
-    [JIM_EXPROP_FUNC_ATAN] = {"atan", 400, 1, JimExprOpDoubleUnary, LAZY_NONE},
-    [JIM_EXPROP_FUNC_SINH] = {"sinh", 400, 1, JimExprOpDoubleUnary, LAZY_NONE},
-    [JIM_EXPROP_FUNC_COSH] = {"cosh", 400, 1, JimExprOpDoubleUnary, LAZY_NONE},
-    [JIM_EXPROP_FUNC_TANH] = {"tanh", 400, 1, JimExprOpDoubleUnary, LAZY_NONE},
-    [JIM_EXPROP_FUNC_CEIL] = {"ceil", 400, 1, JimExprOpDoubleUnary, LAZY_NONE},
-    [JIM_EXPROP_FUNC_FLOOR] = {"floor", 400, 1, JimExprOpDoubleUnary, LAZY_NONE},
-    [JIM_EXPROP_FUNC_EXP] = {"exp", 400, 1, JimExprOpDoubleUnary, LAZY_NONE},
-    [JIM_EXPROP_FUNC_LOG] = {"log", 400, 1, JimExprOpDoubleUnary, LAZY_NONE},
-    [JIM_EXPROP_FUNC_LOG10] = {"log10", 400, 1, JimExprOpDoubleUnary, LAZY_NONE},
-    [JIM_EXPROP_FUNC_SQRT] = {"sqrt", 400, 1, JimExprOpDoubleUnary, LAZY_NONE},
-#endif
-
-    [JIM_EXPROP_NOT] = {"!", 300, 1, JimExprOpNumUnary, LAZY_NONE},
-    [JIM_EXPROP_BITNOT] = {"~", 300, 1, JimExprOpIntUnary, LAZY_NONE},
-    [JIM_EXPROP_UNARYMINUS] = {NULL, 300, 1, JimExprOpNumUnary, LAZY_NONE},
-    [JIM_EXPROP_UNARYPLUS] = {NULL, 300, 1, JimExprOpNumUnary, LAZY_NONE},
-
-    [JIM_EXPROP_POW] = {"**", 250, 2, JimExprOpBin, LAZY_NONE},
-
-    [JIM_EXPROP_MUL] = {"*", 200, 2, JimExprOpBin, LAZY_NONE},
-    [JIM_EXPROP_DIV] = {"/", 200, 2, JimExprOpBin, LAZY_NONE},
-    [JIM_EXPROP_MOD] = {"%", 200, 2, JimExprOpIntBin, LAZY_NONE},
-
-    [JIM_EXPROP_SUB] = {"-", 100, 2, JimExprOpBin, LAZY_NONE},
-    [JIM_EXPROP_ADD] = {"+", 100, 2, JimExprOpBin, LAZY_NONE},
-
-    [JIM_EXPROP_ROTL] = {"<<<", 90, 2, JimExprOpIntBin, LAZY_NONE},
-    [JIM_EXPROP_ROTR] = {">>>", 90, 2, JimExprOpIntBin, LAZY_NONE},
-    [JIM_EXPROP_LSHIFT] = {"<<", 90, 2, JimExprOpIntBin, LAZY_NONE},
-    [JIM_EXPROP_RSHIFT] = {">>", 90, 2, JimExprOpIntBin, LAZY_NONE},
-
-    [JIM_EXPROP_LT] = {"<", 80, 2, JimExprOpBin, LAZY_NONE},
-    [JIM_EXPROP_GT] = {">", 80, 2, JimExprOpBin, LAZY_NONE},
-    [JIM_EXPROP_LTE] = {"<=", 80, 2, JimExprOpBin, LAZY_NONE},
-    [JIM_EXPROP_GTE] = {">=", 80, 2, JimExprOpBin, LAZY_NONE},
-
-    [JIM_EXPROP_NUMEQ] = {"==", 70, 2, JimExprOpBin, LAZY_NONE},
-    [JIM_EXPROP_NUMNE] = {"!=", 70, 2, JimExprOpBin, LAZY_NONE},
-
-    [JIM_EXPROP_STREQ] = {"eq", 60, 2, JimExprOpStrBin, LAZY_NONE},
-    [JIM_EXPROP_STRNE] = {"ne", 60, 2, JimExprOpStrBin, LAZY_NONE},
-
-    [JIM_EXPROP_STRIN] = {"in", 55, 2, JimExprOpStrBin, LAZY_NONE},
-    [JIM_EXPROP_STRNI] = {"ni", 55, 2, JimExprOpStrBin, LAZY_NONE},
-
-    [JIM_EXPROP_BITAND] = {"&", 50, 2, JimExprOpIntBin, LAZY_NONE},
-    [JIM_EXPROP_BITXOR] = {"^", 49, 2, JimExprOpIntBin, LAZY_NONE},
-    [JIM_EXPROP_BITOR] = {"|", 48, 2, JimExprOpIntBin, LAZY_NONE},
-
-    [JIM_EXPROP_LOGICAND] = {"&&", 10, 2, NULL, LAZY_OP},
-    [JIM_EXPROP_LOGICOR] = {"||", 9, 2, NULL, LAZY_OP},
-
-    [JIM_EXPROP_TERNARY] = {"?", 5, 2, JimExprOpNull, LAZY_OP},
-    [JIM_EXPROP_COLON] = {":", 5, 2, JimExprOpNull, LAZY_OP},
-
-    /* private operators */
-    [JIM_EXPROP_TERNARY_LEFT] = {NULL, 5, 2, JimExprOpTernaryLeft, LAZY_LEFT},
-    [JIM_EXPROP_TERNARY_RIGHT] = {NULL, 5, 2, JimExprOpNull, LAZY_RIGHT},
-    [JIM_EXPROP_COLON_LEFT] = {NULL, 5, 2, JimExprOpColonLeft, LAZY_LEFT},
-    [JIM_EXPROP_COLON_RIGHT] = {NULL, 5, 2, JimExprOpNull, LAZY_RIGHT},
-    [JIM_EXPROP_LOGICAND_LEFT] = {NULL, 10, 2, JimExprOpAndLeft, LAZY_LEFT},
-    [JIM_EXPROP_LOGICAND_RIGHT] = {NULL, 10, 2, JimExprOpAndOrRight, LAZY_RIGHT},
-    [JIM_EXPROP_LOGICOR_LEFT] = {NULL, 9, 2, JimExprOpOrLeft, LAZY_LEFT},
-    [JIM_EXPROP_LOGICOR_RIGHT] = {NULL, 9, 2, JimExprOpAndOrRight, LAZY_RIGHT},
+    {"sin", 400, 1, JimExprOpDoubleUnary, LAZY_NONE},
+    {"cos", 400, 1, JimExprOpDoubleUnary, LAZY_NONE},
+    {"tan", 400, 1, JimExprOpDoubleUnary, LAZY_NONE},
+    {"asin", 400, 1, JimExprOpDoubleUnary, LAZY_NONE},
+    {"acos", 400, 1, JimExprOpDoubleUnary, LAZY_NONE},
+    {"atan", 400, 1, JimExprOpDoubleUnary, LAZY_NONE},
+    {"sinh", 400, 1, JimExprOpDoubleUnary, LAZY_NONE},
+    {"cosh", 400, 1, JimExprOpDoubleUnary, LAZY_NONE},
+    {"tanh", 400, 1, JimExprOpDoubleUnary, LAZY_NONE},
+    {"ceil", 400, 1, JimExprOpDoubleUnary, LAZY_NONE},
+    {"floor", 400, 1, JimExprOpDoubleUnary, LAZY_NONE},
+    {"exp", 400, 1, JimExprOpDoubleUnary, LAZY_NONE},
+    {"log", 400, 1, JimExprOpDoubleUnary, LAZY_NONE},
+    {"log10", 400, 1, JimExprOpDoubleUnary, LAZY_NONE},
+    {"sqrt", 400, 1, JimExprOpDoubleUnary, LAZY_NONE},
+    {"pow", 400, 2, JimExprOpBin, LAZY_NONE},
+#endif
 };
 
 #define JIM_EXPR_OPERATORS_NUM \
     (sizeof(Jim_ExprOperators)/sizeof(struct Jim_ExprOperator))
 
 static int JimParseExpression(struct JimParserCtx *pc)
 {
-    /* Discard spaces and quoted newline */
+    
     while (isspace(UCHAR(*pc->p)) || (*(pc->p) == '\\' && *(pc->p + 1) == '\n')) {
+        if (*pc->p == '\n') {
+            pc->linenr++;
+        }
         pc->p++;
         pc->len--;
     }
 
     if (pc->len == 0) {
@@ -14240,30 +12455,30 @@
         pc->eof = 1;
         return JIM_OK;
     }
     switch (*(pc->p)) {
         case '(':
-            pc->tstart = pc->tend = pc->p;
-            pc->tline = pc->linenr;
-            pc->tt = JIM_TT_SUBEXPR_START;
-            pc->p++;
-            pc->len--;
-            break;
+                pc->tt = JIM_TT_SUBEXPR_START;
+                goto singlechar;
         case ')':
+                pc->tt = JIM_TT_SUBEXPR_END;
+                goto singlechar;
+        case ',':
+            pc->tt = JIM_TT_SUBEXPR_COMMA;
+singlechar:
             pc->tstart = pc->tend = pc->p;
             pc->tline = pc->linenr;
-            pc->tt = JIM_TT_SUBEXPR_END;
             pc->p++;
             pc->len--;
             break;
         case '[':
             return JimParseCmd(pc);
         case '$':
             if (JimParseVar(pc) == JIM_ERR)
                 return JimParseExprOperator(pc);
             else {
-                /* Don't allow expr sugar in expressions */
+                
                 if (pc->tt == JIM_TT_EXPRSUGAR) {
                     return JIM_ERR;
                 }
                 return JIM_OK;
             }
@@ -14302,11 +12517,11 @@
 static int JimParseExprNumber(struct JimParserCtx *pc)
 {
     int allowdot = 1;
     int allowhex = 0;
 
-    /* Assume an integer for now */
+    
     pc->tt = JIM_TT_EXPR_INT;
     pc->tstart = pc->p;
     pc->tline = pc->linenr;
     while (isdigit(UCHAR(*pc->p))
         || (allowhex && isxdigit(UCHAR(*pc->p)))
@@ -14358,12 +12573,12 @@
 static int JimParseExprOperator(struct JimParserCtx *pc)
 {
     int i;
     int bestIdx = -1, bestLen = 0;
 
-    /* Try to get the longest match. */
-    for (i = JIM_TT_EXPR_OP; i < (signed)JIM_EXPR_OPERATORS_NUM; i++) {
+    
+    for (i = 0; i < (signed)JIM_EXPR_OPERATORS_NUM; i++) {
         const char *opname;
         int oplen;
 
         opname = Jim_ExprOperators[i].name;
         if (opname == NULL) {
@@ -14370,19 +12585,19 @@
             continue;
         }
         oplen = strlen(opname);
 
         if (strncmp(opname, pc->p, oplen) == 0 && oplen > bestLen) {
-            bestIdx = i;
+            bestIdx = i + JIM_TT_EXPR_OP;
             bestLen = oplen;
         }
     }
     if (bestIdx == -1) {
         return JIM_ERR;
     }
 
-    /* Validate paretheses around function arguments */
+    
     if (bestIdx >= JIM_EXPROP_FUNC_FIRST) {
         const char *p = pc->p + bestLen;
         int len = pc->len - bestLen;
 
         while (len && isspace(UCHAR(*p))) {
@@ -14403,36 +12618,37 @@
     return JIM_OK;
 }
 
 static const struct Jim_ExprOperator *JimExprOperatorInfoByOpcode(int opcode)
 {
-    return &Jim_ExprOperators[opcode];
+    static Jim_ExprOperator dummy_op;
+    if (opcode < JIM_TT_EXPR_OP) {
+        return &dummy_op;
+    }
+    return &Jim_ExprOperators[opcode - JIM_TT_EXPR_OP];
 }
 
 const char *jim_tt_name(int type)
 {
     static const char * const tt_names[JIM_TT_EXPR_OP] =
-        { "NIL", "STR", "ESC", "VAR", "ARY", "CMD", "SEP", "EOL", "EOF", "LIN", "WRD", "(((", ")))", "INT",
+        { "NIL", "STR", "ESC", "VAR", "ARY", "CMD", "SEP", "EOL", "EOF", "LIN", "WRD", "(((", ")))", ",,,", "INT",
             "DBL", "$()" };
     if (type < JIM_TT_EXPR_OP) {
         return tt_names[type];
     }
     else {
         const struct Jim_ExprOperator *op = JimExprOperatorInfoByOpcode(type);
         static char buf[20];
 
-        if (op && op->name) {
+        if (op->name) {
             return op->name;
         }
         sprintf(buf, "(%d)", type);
         return buf;
     }
 }
 
-/* -----------------------------------------------------------------------------
- * Expression Object
- * ---------------------------------------------------------------------------*/
 static void FreeExprInternalRep(Jim_Interp *interp, Jim_Obj *objPtr);
 static void DupExprInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr);
 static int SetExprFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr);
 
 static const Jim_ObjType exprObjType = {
@@ -14441,16 +12657,16 @@
     DupExprInternalRep,
     NULL,
     JIM_TYPE_REFERENCES,
 };
 
-/* Expr bytecode structure */
+
 typedef struct ExprByteCode
 {
-    int len;                    /* Length as number of tokens. */
-    ScriptToken *token;         /* Tokens array. */
-    int inUse;                  /* Used for sharing. */
+    int len;                    
+    ScriptToken *token;         
+    int inUse;                  
 } ExprByteCode;
 
 static void ExprFreeByteCode(Jim_Interp *interp, ExprByteCode * expr)
 {
     int i;
@@ -14478,82 +12694,52 @@
 static void DupExprInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr)
 {
     JIM_NOTUSED(interp);
     JIM_NOTUSED(srcPtr);
 
-    /* Just returns an simple string. */
+    
     dupPtr->typePtr = NULL;
 }
 
-/* Check if an expr program looks correct. */
+
 static int ExprCheckCorrectness(ExprByteCode * expr)
 {
     int i;
     int stacklen = 0;
     int ternary = 0;
 
-    /* Try to check if there are stack underflows,
-     * and make sure at the end of the program there is
-     * a single result on the stack. */
     for (i = 0; i < expr->len; i++) {
         ScriptToken *t = &expr->token[i];
         const struct Jim_ExprOperator *op = JimExprOperatorInfoByOpcode(t->type);
 
-        if (op) {
-            stacklen -= op->arity;
-            if (stacklen < 0) {
-                break;
-            }
-            if (t->type == JIM_EXPROP_TERNARY || t->type == JIM_EXPROP_TERNARY_LEFT) {
-                ternary++;
-            }
-            else if (t->type == JIM_EXPROP_COLON || t->type == JIM_EXPROP_COLON_LEFT) {
-                ternary--;
-            }
+        stacklen -= op->arity;
+        if (stacklen < 0) {
+            break;
+        }
+        if (t->type == JIM_EXPROP_TERNARY || t->type == JIM_EXPROP_TERNARY_LEFT) {
+            ternary++;
+        }
+        else if (t->type == JIM_EXPROP_COLON || t->type == JIM_EXPROP_COLON_LEFT) {
+            ternary--;
         }
 
-        /* All operations and operands add one to the stack */
+        
         stacklen++;
     }
     if (stacklen != 1 || ternary != 0) {
         return JIM_ERR;
     }
     return JIM_OK;
 }
 
-/* This procedure converts every occurrence of || and && opereators
- * in lazy unary versions.
- *
- * a b || is converted into:
- *
- * a <offset> |L b |R
- *
- * a b && is converted into:
- *
- * a <offset> &L b &R
- *
- * "|L" checks if 'a' is true:
- *   1) if it is true pushes 1 and skips <offset> instructions to reach
- *      the opcode just after |R.
- *   2) if it is false does nothing.
- * "|R" checks if 'b' is true:
- *   1) if it is true pushes 1, otherwise pushes 0.
- *
- * "&L" checks if 'a' is true:
- *   1) if it is true does nothing.
- *   2) If it is false pushes 0 and skips <offset> instructions to reach
- *      the opcode just after &R
- * "&R" checks if 'a' is true:
- *      if it is true pushes 1, otherwise pushes 0.
- */
 static int ExprAddLazyOperator(Jim_Interp *interp, ExprByteCode * expr, ParseToken *t)
 {
     int i;
 
     int leftindex, arity, offset;
 
-    /* Search for the end of the first operator */
+    
     leftindex = expr->len - 1;
 
     arity = 1;
     while (arity) {
         ScriptToken *tt = &expr->token[leftindex];
@@ -14566,33 +12752,31 @@
             return JIM_ERR;
         }
     }
     leftindex++;
 
-    /* Move them up */
+    
     memmove(&expr->token[leftindex + 2], &expr->token[leftindex],
         sizeof(*expr->token) * (expr->len - leftindex));
     expr->len += 2;
     offset = (expr->len - leftindex) - 1;
 
-    /* Now we rely on the fact the the left and right version have opcodes
-     * 1 and 2 after the main opcode respectively
-     */
     expr->token[leftindex + 1].type = t->type + 1;
     expr->token[leftindex + 1].objPtr = interp->emptyObj;
 
     expr->token[leftindex].type = JIM_TT_EXPR_INT;
     expr->token[leftindex].objPtr = Jim_NewIntObj(interp, offset);
 
-    /* Now add the 'R' operator */
+    
     expr->token[expr->len].objPtr = interp->emptyObj;
     expr->token[expr->len].type = t->type + 2;
     expr->len++;
 
-    /* Do we need to adjust the skip count for any &L, |L, ?L or :L in the left operand? */
+    
     for (i = leftindex - 1; i > 0; i--) {
-        if (JimExprOperatorInfoByOpcode(expr->token[i].type)->lazy == LAZY_LEFT) {
+        const struct Jim_ExprOperator *op = JimExprOperatorInfoByOpcode(expr->token[i].type);
+        if (op->lazy == LAZY_LEFT) {
             if (JimWideValue(expr->token[i - 1].objPtr) + i - 1 >= leftindex) {
                 JimWideValue(expr->token[i - 1].objPtr) += 2;
             }
         }
     }
@@ -14616,16 +12800,10 @@
         expr->len++;
     }
     return JIM_OK;
 }
 
-/**
- * Returns the index of the COLON_LEFT to the left of 'right_index'
- * taking into account nesting.
- *
- * The expression *must* be well formed, thus a COLON_LEFT will always be found.
- */
 static int ExprTernaryGetColonLeftIndex(ExprByteCode *expr, int right_index)
 {
     int ternary_count = 1;
 
     right_index--;
@@ -14641,20 +12819,14 @@
             return right_index;
         }
         right_index--;
     }
 
-    /*notreached*/
+    
     return -1;
 }
 
-/**
- * Find the left/right indices for the ternary expression to the left of 'right_index'.
- *
- * Returns 1 if found, and fills in *prev_right_index and *prev_left_index.
- * Otherwise returns 0.
- */
 static int ExprTernaryGetMoveIndices(ExprByteCode *expr, int right_index, int *prev_right_index, int *prev_left_index)
 {
     int i = right_index - 1;
     int ternary_count = 1;
 
@@ -14675,55 +12847,10 @@
         i--;
     }
     return 0;
 }
 
-/*
-* ExprTernaryReorderExpression description
-* ========================================
-*
-* ?: is right-to-left associative which doesn't work with the stack-based
-* expression engine. The fix is to reorder the bytecode.
-*
-* The expression:
-*
-*    expr 1?2:0?3:4
-*
-* Has initial bytecode:
-*
-*    '1' '2' (40=TERNARY_LEFT) '2' (41=TERNARY_RIGHT) '2' (43=COLON_LEFT) '0' (44=COLON_RIGHT)
-*    '2' (40=TERNARY_LEFT) '3' (41=TERNARY_RIGHT) '2' (43=COLON_LEFT) '4' (44=COLON_RIGHT)
-*
-* The fix involves simulating this expression instead:
-*
-*    expr 1?2:(0?3:4)
-*
-* With the following bytecode:
-*
-*    '1' '2' (40=TERNARY_LEFT) '2' (41=TERNARY_RIGHT) '10' (43=COLON_LEFT) '0' '2' (40=TERNARY_LEFT)
-*    '3' (41=TERNARY_RIGHT) '2' (43=COLON_LEFT) '4' (44=COLON_RIGHT) (44=COLON_RIGHT)
-*
-* i.e. The token COLON_RIGHT at index 8 is moved towards the end of the stack, all tokens above 8
-*      are shifted down and the skip count of the token JIM_EXPROP_COLON_LEFT at index 5 is
-*      incremented by the amount tokens shifted down. The token JIM_EXPROP_COLON_RIGHT that is moved
-*      is identified as immediately preceeding a token JIM_EXPROP_TERNARY_LEFT
-*
-* ExprTernaryReorderExpression works thus as follows :
-* - start from the end of the stack
-* - while walking towards the beginning of the stack
-*     if token=JIM_EXPROP_COLON_RIGHT then
-*        find the associated token JIM_EXPROP_TERNARY_LEFT, which allows to
-*            find the associated token previous(JIM_EXPROP_COLON_RIGHT)
-*            find the associated token previous(JIM_EXPROP_LEFT_RIGHT)
-*        if all found then
-*            perform the rotation
-*            update the skip count of the token previous(JIM_EXPROP_LEFT_RIGHT)
-*        end if
-*    end if
-*
-* Note: care has to be taken for nested ternary constructs!!!
-*/
 static void ExprTernaryReorderExpression(Jim_Interp *interp, ExprByteCode *expr)
 {
     int i;
 
     for (i = expr->len - 1; i > 1; i--) {
@@ -14734,77 +12861,53 @@
 
         if (expr->token[i].type != JIM_EXPROP_COLON_RIGHT) {
             continue;
         }
 
-        /* COLON_RIGHT found: get the indexes needed to move the tokens in the stack (if any) */
+        
         if (ExprTernaryGetMoveIndices(expr, i, &prev_right_index, &prev_left_index) == 0) {
             continue;
         }
 
-        /*
-        ** rotate tokens down
-        **
-        ** +->  [i]                         : JIM_EXPROP_COLON_RIGHT
-        ** |     |                             |
-        ** |     V                             V
-        ** |   [...]                        : ...
-        ** |     |                             |
-        ** |     V                             V
-        ** |   [...]                        : ...
-        ** |     |                             |
-        ** |     V                             V
-        ** +-  [prev_right_index]           : JIM_EXPROP_COLON_RIGHT
-        */
         tmp = expr->token[prev_right_index];
         for (j = prev_right_index; j < i; j++) {
             expr->token[j] = expr->token[j + 1];
         }
         expr->token[i] = tmp;
 
-        /* Increment the 'skip' count associated to the previous JIM_EXPROP_COLON_LEFT token
-         *
-         * This is 'colon left increment' = i - prev_right_index
-         *
-         * [prev_left_index]      : JIM_EXPROP_LEFT_RIGHT
-         * [prev_left_index-1]    : skip_count
-         *
-         */
         JimWideValue(expr->token[prev_left_index-1].objPtr) += (i - prev_right_index);
 
-        /* Adjust for i-- in the loop */
+        
         i++;
     }
 }
 
-static ExprByteCode *ExprCreateByteCode(Jim_Interp *interp, const ParseTokenList *tokenlist)
+static ExprByteCode *ExprCreateByteCode(Jim_Interp *interp, const ParseTokenList *tokenlist, Jim_Obj *fileNameObj)
 {
     Jim_Stack stack;
     ExprByteCode *expr;
     int ok = 1;
     int i;
     int prevtt = JIM_TT_NONE;
     int have_ternary = 0;
 
-    /* -1 for EOL */
+    
     int count = tokenlist->count - 1;
 
     expr = Jim_Alloc(sizeof(*expr));
     expr->inUse = 1;
     expr->len = 0;
 
     Jim_InitStack(&stack);
 
-    /* Need extra bytecodes for lazy operators.
-     * Also check for the ternary operator
-     */
     for (i = 0; i < tokenlist->count; i++) {
         ParseToken *t = &tokenlist->list[i];
+        const struct Jim_ExprOperator *op = JimExprOperatorInfoByOpcode(t->type);
 
-        if (JimExprOperatorInfoByOpcode(t->type)->lazy == LAZY_OP) {
+        if (op->lazy == LAZY_OP) {
             count += 2;
-            /* Ternary is a lazy op but also needs reordering */
+            
             if (t->type == JIM_EXPROP_TERNARY) {
                 have_ternary = 1;
             }
         }
     }
@@ -14812,11 +12915,11 @@
     expr->token = Jim_Alloc(sizeof(ScriptToken) * count);
 
     for (i = 0; i < tokenlist->count && ok; i++) {
         ParseToken *t = &tokenlist->list[i];
 
-        /* Next token will be stored here */
+        
         struct ScriptToken *token = &expr->token[expr->len];
 
         if (t->type == JIM_TT_EOL) {
             break;
         }
@@ -14828,10 +12931,14 @@
             case JIM_TT_DICTSUGAR:
             case JIM_TT_EXPRSUGAR:
             case JIM_TT_CMD:
                 token->objPtr = Jim_NewStringObj(interp, t->token, t->len);
                 token->type = t->type;
+                if (t->type == JIM_TT_CMD) {
+                    
+                    JimSetSourceInfo(interp, token->objPtr, fileNameObj, t->line);
+                }
                 expr->len++;
                 break;
 
             case JIM_TT_EXPR_INT:
                 token->objPtr = Jim_NewIntObj(interp, strtoull(t->token, NULL, 0));
@@ -14847,10 +12954,14 @@
 
             case JIM_TT_SUBEXPR_START:
                 Jim_StackPush(&stack, t);
                 prevtt = JIM_TT_NONE;
                 continue;
+
+            case JIM_TT_SUBEXPR_COMMA:
+                
+                continue;
 
             case JIM_TT_SUBEXPR_END:
                 ok = 0;
                 while (Jim_StackLen(&stack)) {
                     ParseToken *tt = Jim_StackPop(&stack);
@@ -14870,15 +12981,15 @@
                 }
                 break;
 
 
             default:{
-                    /* Must be an operator */
+                    
                     const struct Jim_ExprOperator *op;
                     ParseToken *tt;
 
-                    /* Convert -/+ to unary minus or unary plus if necessary */
+                    
                     if (prevtt == JIM_TT_NONE || prevtt >= JIM_TT_EXPR_OP) {
                         if (t->type == JIM_EXPROP_SUB) {
                             t->type = JIM_EXPROP_UNARYMINUS;
                         }
                         else if (t->type == JIM_EXPROP_ADD) {
@@ -14886,16 +12997,16 @@
                         }
                     }
 
                     op = JimExprOperatorInfoByOpcode(t->type);
 
-                    /* Now handle precedence */
+                    
                     while ((tt = Jim_StackPeek(&stack)) != NULL) {
                         const struct Jim_ExprOperator *tt_op =
                             JimExprOperatorInfoByOpcode(tt->type);
 
-                        /* Note that right-to-left associativity of ?: operator is handled later */
+                        
 
                         if (op->arity != 1 && tt_op->precedence >= op->precedence) {
                             if (ExprAddOperator(interp, expr, tt) != JIM_OK) {
                                 ok = 0;
                                 goto err;
@@ -14911,11 +13022,11 @@
                 }
         }
         prevtt = t->type;
     }
 
-    /* Reduce any remaining subexpr */
+    
     while (Jim_StackLen(&stack)) {
         ParseToken *tt = Jim_StackPop(&stack);
 
         if (tt->type == JIM_TT_SUBEXPR_START) {
             ok = 0;
@@ -14931,11 +13042,11 @@
     if (have_ternary) {
         ExprTernaryReorderExpression(interp, expr);
     }
 
   err:
-    /* Free the stack used for the compilation. */
+    
     Jim_FreeStack(&stack);
 
     for (i = 0; i < expr->len; i++) {
         Jim_IncrRefCount(expr->token[i].objPtr);
     }
@@ -14947,30 +13058,35 @@
 
     return expr;
 }
 
 
-/* This method takes the string representation of an expression
- * and generates a program for the Expr's stack-based VM. */
-int SetExprFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr)
+static int SetExprFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr)
 {
     int exprTextLen;
     const char *exprText;
     struct JimParserCtx parser;
     struct ExprByteCode *expr;
     ParseTokenList tokenlist;
+    int line;
+    Jim_Obj *fileNameObj;
     int rc = JIM_ERR;
-    int line = 1;
 
-    /* Try to get information about filename / line number */
+    
     if (objPtr->typePtr == &sourceObjType) {
+        fileNameObj = objPtr->internalRep.sourceValue.fileNameObj;
         line = objPtr->internalRep.sourceValue.lineNumber;
     }
+    else {
+        fileNameObj = interp->emptyObj;
+        line = 1;
+    }
+    Jim_IncrRefCount(fileNameObj);
 
     exprText = Jim_GetString(objPtr, &exprTextLen);
 
-    /* Initially tokenise the expression into tokenlist */
+    
     ScriptTokenListInit(&tokenlist);
 
     JimParserInit(&parser, exprText, exprTextLen, line);
     while (!parser.eof) {
         if (JimParseExpression(&parser) != JIM_OK) {
@@ -14994,14 +13110,14 @@
                 tokenlist.list[i].len, tokenlist.list[i].token);
         }
     }
 #endif
 
-    /* Now create the expression bytecode from the tokenlist */
-    expr = ExprCreateByteCode(interp, &tokenlist);
+    
+    expr = ExprCreateByteCode(interp, &tokenlist, fileNameObj);
 
-    /* No longer need the token list */
+    
     ScriptTokenListFree(&tokenlist);
 
     if (!expr) {
         goto err;
     }
@@ -15017,20 +13133,21 @@
             printf("[%2d] %s '%s'\n", i, jim_tt_name(t->type), Jim_String(t->objPtr));
         }
     }
 #endif
 
-    /* Check program correctness. */
+    
     if (ExprCheckCorrectness(expr) != JIM_OK) {
         ExprFreeByteCode(interp, expr);
         goto invalidexpr;
     }
 
     rc = JIM_OK;
 
   err:
-    /* Free the old internal rep and set the new one. */
+    
+    Jim_DecrRefCount(interp, fileNameObj);
     Jim_FreeIntRep(interp, objPtr);
     Jim_SetIntRepPtr(objPtr, expr);
     objPtr->typePtr = &exprObjType;
     return rc;
 }
@@ -15043,25 +13160,10 @@
         }
     }
     return (ExprByteCode *) Jim_GetIntRepPtr(objPtr);
 }
 
-/* -----------------------------------------------------------------------------
- * Expressions evaluation.
- * Jim uses a specialized stack-based virtual machine for expressions,
- * that takes advantage of the fact that expr's operators
- * can't be redefined.
- *
- * Jim_EvalExpression() uses the bytecode compiled by
- * SetExprFromAny() method of the "expression" object.
- *
- * On success a Tcl Object containing the result of the evaluation
- * is stored into expResultPtrPtr (having refcount of 1), and JIM_OK is
- * returned.
- * On error the function returns a retcode != to JIM_OK and set a suitable
- * error on the interp.
- * ---------------------------------------------------------------------------*/
 #define JIM_EE_STATICSTACK_LEN 10
 
 int Jim_EvalExpression(Jim_Interp *interp, Jim_Obj *exprObjPtr, Jim_Obj **exprResultPtrPtr)
 {
     ExprByteCode *expr;
@@ -15070,31 +13172,17 @@
     int retcode = JIM_OK;
     struct JimExprState e;
 
     expr = JimGetExpression(interp, exprObjPtr);
     if (!expr) {
-        return JIM_ERR;         /* error in expression. */
+        return JIM_ERR;         
     }
 
 #ifdef JIM_OPTIMIZATION
-    /* Check for one of the following common expressions used by while/for
-     *
-     *   CONST
-     *   $a
-     *   !$a
-     *   $a < CONST, $a < $b
-     *   $a <= CONST, $a <= $b
-     *   $a > CONST, $a > $b
-     *   $a >= CONST, $a >= $b
-     *   $a != CONST, $a != $b
-     *   $a == CONST, $a == $b
-     */
     {
         Jim_Obj *objPtr;
 
-        /* STEP 1 -- Check if there are the conditions to run the specialized
-         * version of while */
 
         switch (expr->len) {
             case 1:
                 if (expr->token[0].type == JIM_TT_EXPR_INT) {
                     *exprResultPtrPtr = expr->token[0].objPtr;
@@ -15133,11 +13221,11 @@
                         case JIM_EXPROP_LTE:
                         case JIM_EXPROP_GT:
                         case JIM_EXPROP_GTE:
                         case JIM_EXPROP_NUMEQ:
                         case JIM_EXPROP_NUMNE:{
-                                /* optimise ok */
+                                
                                 jim_wide wideValueA;
                                 jim_wide wideValueB;
 
                                 objPtr = Jim_GetVariable(interp, expr->token[0].objPtr, JIM_NONE);
                                 if (objPtr && JimIsWide(objPtr)
@@ -15171,11 +13259,11 @@
                                                 cmpRes = wideValueA == wideValueB;
                                                 break;
                                             case JIM_EXPROP_NUMNE:
                                                 cmpRes = wideValueA != wideValueB;
                                                 break;
-                                            default:   /*notreached */
+                                            default:   
                                                 cmpRes = 0;
                                         }
                                         *exprResultPtrPtr =
                                             cmpRes ? interp->trueObj : interp->falseObj;
                                         Jim_IncrRefCount(*exprResultPtrPtr);
@@ -15188,28 +13276,22 @@
                 break;
         }
     }
 #endif
 
-    /* In order to avoid that the internal repr gets freed due to
-     * shimmering of the exprObjPtr's object, we make the internal rep
-     * shared. */
     expr->inUse++;
 
-    /* The stack-based expr VM itself */
+    
 
-    /* Stack allocation. Expr programs have the feature that
-     * a program of length N can't require a stack longer than
-     * N. */
     if (expr->len > JIM_EE_STATICSTACK_LEN)
         e.stack = Jim_Alloc(sizeof(Jim_Obj *) * expr->len);
     else
         e.stack = staticStack;
 
     e.stacklen = 0;
 
-    /* Execute every instruction */
+    
     for (i = 0; i < expr->len && retcode == JIM_OK; i++) {
         Jim_Obj *objPtr;
 
         switch (expr->token[i].type) {
             case JIM_TT_EXPR_INT:
@@ -15251,16 +13333,16 @@
                     ExprPush(&e, Jim_GetResult(interp));
                 }
                 break;
 
             default:{
-                    /* Find and execute the operation */
+                    
                     e.skip = 0;
                     e.opcode = expr->token[i].type;
 
                     retcode = JimExprOperatorInfoByOpcode(e.opcode)->funcop(interp, &e);
-                    /* Skip some opcodes if necessary */
+                    
                     i += e.skip;
                     continue;
                 }
         }
     }
@@ -15307,61 +13389,34 @@
 
     Jim_DecrRefCount(interp, exprResultPtr);
     return JIM_OK;
 }
 
-/* -----------------------------------------------------------------------------
- * ScanFormat String Object
- * ---------------------------------------------------------------------------*/
 
-/* This Jim_Obj will held a parsed representation of a format string passed to
- * the Jim_ScanString command. For error diagnostics, the scanformat string has
- * to be parsed in its entirely first and then, if correct, can be used for
- * scanning. To avoid endless re-parsing, the parsed representation will be
- * stored in an internal representation and re-used for performance reason. */
 
-/* A ScanFmtPartDescr will held the information of /one/ part of the whole
- * scanformat string. This part will later be used to extract information
- * out from the string to be parsed by Jim_ScanString */
 
 typedef struct ScanFmtPartDescr
 {
-    char type;                  /* Type of conversion (e.g. c, d, f) */
-    char modifier;              /* Modify type (e.g. l - long, h - short */
-    size_t width;               /* Maximal width of input to be converted */
-    int pos;                    /* -1 - no assign, 0 - natural pos, >0 - XPG3 pos */
-    char *arg;                  /* Specification of a CHARSET conversion */
-    char *prefix;               /* Prefix to be scanned literally before conversion */
+    char type;                  
+    char modifier;              
+    size_t width;               
+    int pos;                    
+    char *arg;                  
+    char *prefix;               
 } ScanFmtPartDescr;
 
-/* The ScanFmtStringObj will hold the internal representation of a scanformat
- * string parsed and separated in part descriptions. Furthermore it contains
- * the original string representation of the scanformat string to allow for
- * fast update of the Jim_Obj's string representation part.
- *
- * As an add-on the internal object representation adds some scratch pad area
- * for usage by Jim_ScanString to avoid endless allocating and freeing of
- * memory for purpose of string scanning.
- *
- * The error member points to a static allocated string in case of a mal-
- * formed scanformat string or it contains '0' (NULL) in case of a valid
- * parse representation.
- *
- * The whole memory of the internal representation is allocated as a single
- * area of memory that will be internally separated. So freeing and duplicating
- * of such an object is cheap */
 
 typedef struct ScanFmtStringObj
 {
-    jim_wide size;              /* Size of internal repr in bytes */
-    char *stringRep;            /* Original string representation */
-    size_t count;               /* Number of ScanFmtPartDescr contained */
-    size_t convCount;           /* Number of conversions that will assign */
-    size_t maxPos;              /* Max position index if XPG3 is used */
-    const char *error;          /* Ptr to error text (NULL if no error */
-    char *scratch;              /* Some scratch pad used by Jim_ScanString */
-    ScanFmtPartDescr descr[1];  /* The vector of partial descriptions */
+    jim_wide size;              
+    char *stringRep;            
+    size_t count;               
+    size_t convCount;           
+    size_t maxPos;              
+    const char *error;          
+    char *scratch;              
+    ScanFmtPartDescr descr[1];  
 } ScanFmtStringObj;
 
 
 static void FreeScanFmtInternalRep(Jim_Interp *interp, Jim_Obj *objPtr);
 static void DupScanFmtInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr);
@@ -15399,16 +13454,10 @@
 
     objPtr->bytes = Jim_StrDup(bytes);
     objPtr->length = strlen(bytes);
 }
 
-/* SetScanFmtFromAny will parse a given string and create the internal
- * representation of the format specification. In case of an error
- * the error data member of the internal representation will be set
- * to an descriptive error text and the function will be left with
- * JIM_ERR to indicate unsucessful parsing (aka. malformed scanformat
- * specification */
 
 static int SetScanFmtFromAny(Jim_Interp *interp, Jim_Obj *objPtr)
 {
     ScanFmtStringObj *fmtObj;
     char *buffer;
@@ -15417,22 +13466,22 @@
     int maxFmtLen = objPtr->length;
     const char *fmtEnd = fmt + maxFmtLen;
     int curr;
 
     Jim_FreeIntRep(interp, objPtr);
-    /* Count how many conversions could take place maximally */
+    
     for (i = 0, maxCount = 0; i < maxFmtLen; ++i)
         if (fmt[i] == '%')
             ++maxCount;
-    /* Calculate an approximation of the memory necessary */
-    approxSize = sizeof(ScanFmtStringObj)       /* Size of the container */
-        +(maxCount + 1) * sizeof(ScanFmtPartDescr)      /* Size of all partials */
-        +maxFmtLen * sizeof(char) + 3 + 1       /* Scratch + "%n" + '\0' */
-        + maxFmtLen * sizeof(char) + 1  /* Original stringrep */
-        + maxFmtLen * sizeof(char)      /* Arg for CHARSETs */
-        +(maxCount + 1) * sizeof(char)  /* '\0' for every partial */
-        +1;                     /* safety byte */
+    
+    approxSize = sizeof(ScanFmtStringObj)       
+        +(maxCount + 1) * sizeof(ScanFmtPartDescr)      
+        +maxFmtLen * sizeof(char) + 3 + 1       
+        + maxFmtLen * sizeof(char) + 1  
+        + maxFmtLen * sizeof(char)      
+        +(maxCount + 1) * sizeof(char)  
+        +1;                     
     fmtObj = (ScanFmtStringObj *) Jim_Alloc(approxSize);
     memset(fmtObj, 0, approxSize);
     fmtObj->size = approxSize;
     fmtObj->maxPos = 0;
     fmtObj->scratch = (char *)&fmtObj->descr[maxCount + 1];
@@ -15444,12 +13493,12 @@
     for (i = 0, curr = 0; fmt < fmtEnd; ++fmt) {
         int width = 0, skip;
         ScanFmtPartDescr *descr = &fmtObj->descr[curr];
 
         fmtObj->count++;
-        descr->width = 0;       /* Assume width unspecified */
-        /* Overread and store any "literal" prefix */
+        descr->width = 0;       
+        
         if (*fmt != '%' || fmt[1] == '%') {
             descr->type = 0;
             descr->prefix = &buffer[i];
             for (; fmt < fmtEnd; ++fmt) {
                 if (*fmt == '%') {
@@ -15459,65 +13508,65 @@
                 }
                 buffer[i++] = *fmt;
             }
             buffer[i++] = 0;
         }
-        /* Skip the conversion introducing '%' sign */
+        
         ++fmt;
-        /* End reached due to non-conversion literal only? */
+        
         if (fmt >= fmtEnd)
             goto done;
-        descr->pos = 0;         /* Assume "natural" positioning */
+        descr->pos = 0;         
         if (*fmt == '*') {
-            descr->pos = -1;    /* Okay, conversion will not be assigned */
+            descr->pos = -1;    
             ++fmt;
         }
         else
-            fmtObj->convCount++;        /* Otherwise count as assign-conversion */
-        /* Check if next token is a number (could be width or pos */
+            fmtObj->convCount++;        
+        
         if (sscanf(fmt, "%d%n", &width, &skip) == 1) {
             fmt += skip;
-            /* Was the number a XPG3 position specifier? */
+            
             if (descr->pos != -1 && *fmt == '$') {
                 int prev;
 
                 ++fmt;
                 descr->pos = width;
                 width = 0;
-                /* Look if "natural" postioning and XPG3 one was mixed */
+                
                 if ((lastPos == 0 && descr->pos > 0)
                     || (lastPos > 0 && descr->pos == 0)) {
                     fmtObj->error = "cannot mix \"%\" and \"%n$\" conversion specifiers";
                     return JIM_ERR;
                 }
-                /* Look if this position was already used */
+                
                 for (prev = 0; prev < curr; ++prev) {
                     if (fmtObj->descr[prev].pos == -1)
                         continue;
                     if (fmtObj->descr[prev].pos == descr->pos) {
                         fmtObj->error =
                             "variable is assigned by multiple \"%n$\" conversion specifiers";
                         return JIM_ERR;
                     }
                 }
-                /* Try to find a width after the XPG3 specifier */
+                
                 if (sscanf(fmt, "%d%n", &width, &skip) == 1) {
                     descr->width = width;
                     fmt += skip;
                 }
                 if (descr->pos > 0 && (size_t) descr->pos > fmtObj->maxPos)
                     fmtObj->maxPos = descr->pos;
             }
             else {
-                /* Number was not a XPG3, so it has to be a width */
+                
                 descr->width = width;
             }
         }
-        /* If positioning mode was undetermined yet, fix this */
+        
         if (lastPos == -1)
             lastPos = descr->pos;
-        /* Handle CHARSET conversion type ... */
+        
         if (*fmt == '[') {
             int swapped = 1, beg = i, end, j;
 
             descr->type = '[';
             descr->arg = &buffer[i];
@@ -15532,11 +13581,11 @@
                 fmtObj->error = "unmatched [ in format string";
                 return JIM_ERR;
             }
             end = i;
             buffer[i++] = 0;
-            /* In case a range fence was given "backwards", swap it */
+            
             while (swapped) {
                 swapped = 0;
                 for (j = beg + 1; j < end - 1; ++j) {
                     if (buffer[j] == '-' && buffer[j - 1] > buffer[j + 1]) {
                         char tmp = buffer[j - 1];
@@ -15547,11 +13596,11 @@
                     }
                 }
             }
         }
         else {
-            /* Remember any valid modifier if given */
+            
             if (strchr("hlL", *fmt) != 0)
                 descr->modifier = tolower((int)*fmt++);
 
             descr->type = *fmt;
             if (strchr("efgcsndoxui", *fmt) == 0) {
@@ -15571,23 +13620,19 @@
     }
   done:
     return JIM_OK;
 }
 
-/* Some accessor macros to allow lowlevel access to fields of internal repr */
+
 
 #define FormatGetCnvCount(_fo_) \
     ((ScanFmtStringObj*)((_fo_)->internalRep.ptr))->convCount
 #define FormatGetMaxPos(_fo_) \
     ((ScanFmtStringObj*)((_fo_)->internalRep.ptr))->maxPos
 #define FormatGetError(_fo_) \
     ((ScanFmtStringObj*)((_fo_)->internalRep.ptr))->error
 
-/* JimScanAString is used to scan an unspecified string that ends with
- * next WS, or a string that is specified via a charset.
- *
- */
 static Jim_Obj *JimScanAString(Jim_Interp *interp, const char *sdescr, const char *str)
 {
     char *buffer = Jim_StrDup(str);
     char *p = buffer;
 
@@ -15594,11 +13639,11 @@
     while (*str) {
         int c;
         int n;
 
         if (!sdescr && isspace(UCHAR(*str)))
-            break;              /* EOS via WS if unspecified */
+            break;              
 
         n = utf8_tounicode(str, &c);
         if (sdescr && !JimCharsetMatch(sdescr, c, JIM_CHARSET_SCAN))
             break;
         while (n--)
@@ -15606,15 +13651,10 @@
     }
     *p = 0;
     return Jim_NewStringObjNoAlloc(interp, buffer, p - buffer);
 }
 
-/* ScanOneEntry will scan one entry out of the string passed as argument.
- * It use the sscanf() function for this task. After extracting and
- * converting of the value, the count of scanned characters will be
- * returned of -1 in case of no conversion tool place and string was
- * already scanned thru */
 
 static int ScanOneEntry(Jim_Interp *interp, const char *str, int pos, int strLen,
     ScanFmtStringObj * fmtObj, long idx, Jim_Obj **valObjPtr)
 {
     const char *tok;
@@ -15622,103 +13662,91 @@
     size_t scanned = 0;
     size_t anchor = pos;
     int i;
     Jim_Obj *tmpObj = NULL;
 
-    /* First pessimistically assume, we will not scan anything :-) */
+    
     *valObjPtr = 0;
     if (descr->prefix) {
-        /* There was a prefix given before the conversion, skip it and adjust
-         * the string-to-be-parsed accordingly */
-        /* XXX: Should be checking strLen, not str[pos] */
+        
         for (i = 0; pos < strLen && descr->prefix[i]; ++i) {
-            /* If prefix require, skip WS */
+            
             if (isspace(UCHAR(descr->prefix[i])))
                 while (pos < strLen && isspace(UCHAR(str[pos])))
                     ++pos;
             else if (descr->prefix[i] != str[pos])
-                break;          /* Prefix do not match here, leave the loop */
+                break;          
             else
-                ++pos;          /* Prefix matched so far, next round */
+                ++pos;          
         }
         if (pos >= strLen) {
-            return -1;          /* All of str consumed: EOF condition */
+            return -1;          
         }
         else if (descr->prefix[i] != 0)
-            return 0;           /* Not whole prefix consumed, no conversion possible */
+            return 0;           
     }
-    /* For all but following conversion, skip leading WS */
+    
     if (descr->type != 'c' && descr->type != '[' && descr->type != 'n')
         while (isspace(UCHAR(str[pos])))
             ++pos;
-    /* Determine how much skipped/scanned so far */
+    
     scanned = pos - anchor;
 
-    /* %c is a special, simple case. no width */
+    
     if (descr->type == 'n') {
-        /* Return pseudo conversion means: how much scanned so far? */
+        
         *valObjPtr = Jim_NewIntObj(interp, anchor + scanned);
     }
     else if (pos >= strLen) {
-        /* Cannot scan anything, as str is totally consumed */
+        
         return -1;
     }
     else if (descr->type == 'c') {
             int c;
             scanned += utf8_tounicode(&str[pos], &c);
             *valObjPtr = Jim_NewIntObj(interp, c);
             return scanned;
     }
     else {
-        /* Processing of conversions follows ... */
+        
         if (descr->width > 0) {
-            /* Do not try to scan as fas as possible but only the given width.
-             * To ensure this, we copy the part that should be scanned. */
             size_t sLen = utf8_strlen(&str[pos], strLen - pos);
             size_t tLen = descr->width > sLen ? sLen : descr->width;
 
             tmpObj = Jim_NewStringObjUtf8(interp, str + pos, tLen);
             tok = tmpObj->bytes;
         }
         else {
-            /* As no width was given, simply refer to the original string */
+            
             tok = &str[pos];
         }
         switch (descr->type) {
             case 'd':
             case 'o':
             case 'x':
             case 'u':
             case 'i':{
-                    char *endp; /* Position where the number finished */
+                    char *endp; 
                     jim_wide w;
 
                     int base = descr->type == 'o' ? 8
                         : descr->type == 'x' ? 16 : descr->type == 'i' ? 0 : 10;
 
-                    /* Try to scan a number with the given base */
+                    
                     w = strtoull(tok, &endp, base);
                     if (endp == tok && base == 0) {
-                        /* If scanning failed, and base was undetermined, simply
-                         * put it to 10 and try once more. This should catch the
-                         * case where %i begin to parse a number prefix (e.g.
-                         * '0x' but no further digits follows. This will be
-                         * handled as a ZERO followed by a char 'x' by Tcl */
                         w = strtoull(tok, &endp, 10);
                     }
 
                     if (endp != tok) {
-                        /* There was some number sucessfully scanned! */
+                        
                         *valObjPtr = Jim_NewIntObj(interp, w);
 
-                        /* Adjust the number-of-chars scanned so far */
+                        
                         scanned += endp - tok;
                     }
                     else {
-                        /* Nothing was scanned. We have to determine if this
-                         * happened due to e.g. prefix mismatch or input str
-                         * exhausted */
                         scanned = *tok ? 0 : -1;
                     }
                     break;
                 }
             case 's':
@@ -15732,36 +13760,28 @@
             case 'g':{
                     char *endp;
                     double value = strtod(tok, &endp);
 
                     if (endp != tok) {
-                        /* There was some number sucessfully scanned! */
+                        
                         *valObjPtr = Jim_NewDoubleObj(interp, value);
-                        /* Adjust the number-of-chars scanned so far */
+                        
                         scanned += endp - tok;
                     }
                     else {
-                        /* Nothing was scanned. We have to determine if this
-                         * happened due to e.g. prefix mismatch or input str
-                         * exhausted */
                         scanned = *tok ? 0 : -1;
                     }
                     break;
                 }
         }
-        /* If a substring was allocated (due to pre-defined width) do not
-         * forget to free it */
         if (tmpObj) {
             Jim_FreeNewObj(interp, tmpObj);
         }
     }
     return scanned;
 }
 
-/* Jim_ScanString is the workhorse of string scanning. It will scan a given
- * string and returns all converted (and not ignored) values in a list back
- * to the caller. If an error occured, a NULL pointer will be returned */
 
 Jim_Obj *Jim_ScanString(Jim_Interp *interp, Jim_Obj *strObjPtr, Jim_Obj *fmtObjPtr, int flags)
 {
     size_t i, pos;
     int scanned = 1;
@@ -15771,65 +13791,65 @@
     Jim_Obj **resultVec = 0;
     int resultc;
     Jim_Obj *emptyStr = 0;
     ScanFmtStringObj *fmtObj;
 
-    /* This should never happen. The format object should already be of the correct type */
-    JimPanic((fmtObjPtr->typePtr != &scanFmtStringObjType, interp, "Jim_ScanString() for non-scan format"));
+    
+    JimPanic((fmtObjPtr->typePtr != &scanFmtStringObjType, "Jim_ScanString() for non-scan format"));
 
     fmtObj = (ScanFmtStringObj *) fmtObjPtr->internalRep.ptr;
-    /* Check if format specification was valid */
+    
     if (fmtObj->error != 0) {
         if (flags & JIM_ERRMSG)
             Jim_SetResultString(interp, fmtObj->error, -1);
         return 0;
     }
-    /* Allocate a new "shared" empty string for all unassigned conversions */
+    
     emptyStr = Jim_NewEmptyStringObj(interp);
     Jim_IncrRefCount(emptyStr);
-    /* Create a list and fill it with empty strings up to max specified XPG3 */
-    resultList = Jim_NewListObj(interp, 0, 0);
+    
+    resultList = Jim_NewListObj(interp, NULL, 0);
     if (fmtObj->maxPos > 0) {
         for (i = 0; i < fmtObj->maxPos; ++i)
             Jim_ListAppendElement(interp, resultList, emptyStr);
         JimListGetElements(interp, resultList, &resultc, &resultVec);
     }
-    /* Now handle every partial format description */
+    
     for (i = 0, pos = 0; i < fmtObj->count; ++i) {
         ScanFmtPartDescr *descr = &(fmtObj->descr[i]);
         Jim_Obj *value = 0;
 
-        /* Only last type may be "literal" w/o conversion - skip it! */
+        
         if (descr->type == 0)
             continue;
-        /* As long as any conversion could be done, we will proceed */
+        
         if (scanned > 0)
             scanned = ScanOneEntry(interp, str, pos, strLen, fmtObj, i, &value);
-        /* In case our first try results in EOF, we will leave */
+        
         if (scanned == -1 && i == 0)
             goto eof;
-        /* Advance next pos-to-be-scanned for the amount scanned already */
+        
         pos += scanned;
 
-        /* value == 0 means no conversion took place so take empty string */
+        
         if (value == 0)
             value = Jim_NewEmptyStringObj(interp);
-        /* If value is a non-assignable one, skip it */
+        
         if (descr->pos == -1) {
             Jim_FreeNewObj(interp, value);
         }
         else if (descr->pos == 0)
-            /* Otherwise append it to the result list if no XPG3 was given */
+            
             Jim_ListAppendElement(interp, resultList, value);
         else if (resultVec[descr->pos - 1] == emptyStr) {
-            /* But due to given XPG3, put the value into the corr. slot */
+            
             Jim_DecrRefCount(interp, resultVec[descr->pos - 1]);
             Jim_IncrRefCount(value);
             resultVec[descr->pos - 1] = value;
         }
         else {
-            /* Otherwise, the slot was already used - free obj and ERROR */
+            
             Jim_FreeNewObj(interp, value);
             goto err;
         }
     }
     Jim_DecrRefCount(interp, emptyStr);
@@ -15842,14 +13862,11 @@
     Jim_DecrRefCount(interp, emptyStr);
     Jim_FreeNewObj(interp, resultList);
     return 0;
 }
 
-/* -----------------------------------------------------------------------------
- * Pseudo Random Number Generation
- * ---------------------------------------------------------------------------*/
-/* Initialize the sbox with the numbers from 0 to 255 */
+
 static void JimPrngInit(Jim_Interp *interp)
 {
 #define PRNG_SEED_SIZE 256
     int i;
     unsigned int *seed;
@@ -15863,22 +13880,22 @@
     }
     JimPrngSeed(interp, (unsigned char *)seed, PRNG_SEED_SIZE * sizeof(*seed));
     Jim_Free(seed);
 }
 
-/* Generates N bytes of random data */
+
 static void JimRandomBytes(Jim_Interp *interp, void *dest, unsigned int len)
 {
     Jim_PrngState *prng;
     unsigned char *destByte = (unsigned char *)dest;
     unsigned int si, sj, x;
 
-    /* initialization, only needed the first time */
+    
     if (interp->prngState == NULL)
         JimPrngInit(interp);
     prng = interp->prngState;
-    /* generates 'len' bytes of pseudo-random numbers */
+    
     for (x = 0; x < len; x++) {
         prng->i = (prng->i + 1) & 0xff;
         si = prng->sbox[prng->i];
         prng->j = (prng->j + si) & 0xff;
         sj = prng->sbox[prng->j];
@@ -15886,43 +13903,40 @@
         prng->sbox[prng->j] = si;
         *destByte++ = prng->sbox[(si + sj) & 0xff];
     }
 }
 
-/* Re-seed the generator with user-provided bytes */
+
 static void JimPrngSeed(Jim_Interp *interp, unsigned char *seed, int seedLen)
 {
     int i;
     Jim_PrngState *prng;
 
-    /* initialization, only needed the first time */
+    
     if (interp->prngState == NULL)
         JimPrngInit(interp);
     prng = interp->prngState;
 
-    /* Set the sbox[i] with i */
+    
     for (i = 0; i < 256; i++)
         prng->sbox[i] = i;
-    /* Now use the seed to perform a random permutation of the sbox */
+    
     for (i = 0; i < seedLen; i++) {
         unsigned char t;
 
         t = prng->sbox[i & 0xFF];
         prng->sbox[i & 0xFF] = prng->sbox[seed[i]];
         prng->sbox[seed[i]] = t;
     }
     prng->i = prng->j = 0;
 
-    /* discard at least the first 256 bytes of stream.
-     * borrow the seed buffer for this
-     */
     for (i = 0; i < 256; i += seedLen) {
         JimRandomBytes(interp, seed, seedLen);
     }
 }
 
-/* [incr] */
+
 static int Jim_IncrCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
 {
     jim_wide wideValue, increment = 1;
     Jim_Obj *intObjPtr;
 
@@ -15934,11 +13948,11 @@
         if (Jim_GetWide(interp, argv[2], &increment) != JIM_OK)
             return JIM_ERR;
     }
     intObjPtr = Jim_GetVariable(interp, argv[1], JIM_UNSHARED);
     if (!intObjPtr) {
-        /* Set missing variable to 0 */
+        
         wideValue = 0;
     }
     else if (Jim_GetWide(interp, intObjPtr, &wideValue) != JIM_OK) {
         return JIM_ERR;
     }
@@ -15948,191 +13962,159 @@
             Jim_FreeNewObj(interp, intObjPtr);
             return JIM_ERR;
         }
     }
     else {
-        /* Can do it the quick way */
+        
         Jim_InvalidateStringRep(intObjPtr);
         JimWideValue(intObjPtr) = wideValue + increment;
 
-        /* The following step is required in order to invalidate the
-         * string repr of "FOO" if the var name is on the form of "FOO(IDX)" */
         if (argv[1]->typePtr != &variableObjType) {
-            /* Note that this can't fail since GetVariable already succeeded */
+            
             Jim_SetVariable(interp, argv[1], intObjPtr);
         }
     }
     Jim_SetResult(interp, intObjPtr);
     return JIM_OK;
 }
 
 
-/* -----------------------------------------------------------------------------
- * Eval
- * ---------------------------------------------------------------------------*/
-#define JIM_EVAL_SARGV_LEN 8    /* static arguments vector length */
-#define JIM_EVAL_SINTV_LEN 8    /* static interpolation vector length */
+#define JIM_EVAL_SARGV_LEN 8    
+#define JIM_EVAL_SINTV_LEN 8    
 
-/* Handle calls to the [unknown] command */
-static int JimUnknown(Jim_Interp *interp, int argc, Jim_Obj *const *argv, const char *filename,
+
+static int JimUnknown(Jim_Interp *interp, int argc, Jim_Obj *const *argv, Jim_Obj *fileNameObj,
     int linenr)
 {
     Jim_Obj **v, *sv[JIM_EVAL_SARGV_LEN];
     int retCode;
 
-    /* If JimUnknown() is recursively called too many times...
-     * done here
-     */
     if (interp->unknown_called > 50) {
         return JIM_ERR;
     }
 
-    /* If the [unknown] command does not exists returns
-     * just now */
     if (Jim_GetCommand(interp, interp->unknown, JIM_NONE) == NULL)
         return JIM_ERR;
 
-    /* The object interp->unknown just contains
-     * the "unknown" string, it is used in order to
-     * avoid to lookup the unknown command every time
-     * but instread to cache the result. */
     if (argc + 1 <= JIM_EVAL_SARGV_LEN)
         v = sv;
     else
         v = Jim_Alloc(sizeof(Jim_Obj *) * (argc + 1));
-    /* Make a copy of the arguments vector, but shifted on
-     * the right of one position. The command name of the
-     * command will be instead the first argument of the
-     * [unknown] call. */
     memcpy(v + 1, argv, sizeof(Jim_Obj *) * argc);
     v[0] = interp->unknown;
-    /* Call it */
+    
     interp->unknown_called++;
-    retCode = JimEvalObjVector(interp, argc + 1, v, filename, linenr);
+    retCode = JimEvalObjVector(interp, argc + 1, v, fileNameObj, linenr);
     interp->unknown_called--;
 
-    /* Clean up */
+    
     if (v != sv)
         Jim_Free(v);
     return retCode;
 }
 
-/* Eval the object vector 'objv' composed of 'objc' elements.
- * Every element is used as single argument.
- * Jim_EvalObj() will call this function every time its object
- * argument is of "list" type, with no string representation.
- *
- * This is possible because the string representation of a
- * list object generated by the UpdateStringOfList is made
- * in a way that ensures that every list element is a different
- * command argument. */
 static int JimEvalObjVector(Jim_Interp *interp, int objc, Jim_Obj *const *objv,
-    const char *filename, int linenr)
+    Jim_Obj *fileNameObj, int linenr)
 {
     int i, retcode;
     Jim_Cmd *cmdPtr;
 
-    /* Incr refcount of arguments. */
+    
     for (i = 0; i < objc; i++)
         Jim_IncrRefCount(objv[i]);
-    /* Command lookup */
+    
     cmdPtr = Jim_GetCommand(interp, objv[0], JIM_ERRMSG);
     if (cmdPtr == NULL) {
-        retcode = JimUnknown(interp, objc, objv, filename, linenr);
+        retcode = JimUnknown(interp, objc, objv, fileNameObj, linenr);
     }
     else {
-        /* Call it -- Make sure result is an empty object. */
+        
         JimIncrCmdRefCount(cmdPtr);
         Jim_SetEmptyResult(interp);
         if (cmdPtr->isproc) {
-            retcode = JimCallProcedure(interp, cmdPtr, filename, linenr, objc, objv);
+            retcode = JimCallProcedure(interp, cmdPtr, fileNameObj, linenr, objc, objv);
         }
         else {
             interp->cmdPrivData = cmdPtr->u.native.privData;
             retcode = cmdPtr->u.native.cmdProc(interp, objc, objv);
         }
         JimDecrCmdRefCount(interp, cmdPtr);
     }
-    /* Decr refcount of arguments and return the retcode */
+    
     for (i = 0; i < objc; i++)
         Jim_DecrRefCount(interp, objv[i]);
 
     return retcode;
 }
 
 int Jim_EvalObjVector(Jim_Interp *interp, int objc, Jim_Obj *const *objv)
 {
-    return JimEvalObjVector(interp, objc, objv, NULL, 0);
+    return JimEvalObjVector(interp, objc, objv, interp->emptyObj, 1);
 }
 
-/**
- * Invokes 'prefix' as a command with the objv array as arguments.
- */
-int Jim_EvalObjPrefix(Jim_Interp *interp, const char *prefix, int objc, Jim_Obj *const *objv)
+int Jim_EvalObjPrefix(Jim_Interp *interp, Jim_Obj *prefix, int objc, Jim_Obj *const *objv)
 {
     int i;
     int ret;
     Jim_Obj **nargv = Jim_Alloc((objc + 1) * sizeof(*nargv));
 
-    nargv[0] = Jim_NewStringObj(interp, prefix, -1);
+    nargv[0] = prefix;
     for (i = 0; i < objc; i++) {
         nargv[i + 1] = objv[i];
     }
     ret = Jim_EvalObjVector(interp, objc + 1, nargv);
     Jim_Free(nargv);
     return ret;
 }
 
-static void JimAddErrorToStack(Jim_Interp *interp, int retcode, const char *filename, int line)
+static void JimAddErrorToStack(Jim_Interp *interp, int retcode, Jim_Obj *fileNameObj, int line)
 {
     int rc = retcode;
 
     if (rc == JIM_ERR && !interp->errorFlag) {
-        /* This is the first error, so save the file/line information and reset the stack */
+        
         interp->errorFlag = 1;
-        JimSetErrorFileName(interp, filename);
-        JimSetErrorLineNumber(interp, line);
+        Jim_IncrRefCount(fileNameObj);
+        Jim_DecrRefCount(interp, interp->errorFileNameObj);
+        interp->errorFileNameObj = fileNameObj;
+        interp->errorLine = line;
 
         JimResetStackTrace(interp);
-        /* Always add a level where the error first occurs */
+        
         interp->addStackTrace++;
     }
 
-    /* Now if this is an "interesting" level, add it to the stack trace */
+    
     if (rc == JIM_ERR && interp->addStackTrace > 0) {
-        /* Add the stack info for the current level */
+        
 
-        JimAppendStackTrace(interp, Jim_String(interp->errorProc), filename, line);
+        JimAppendStackTrace(interp, Jim_String(interp->errorProc), fileNameObj, line);
 
-        /* Note: if we didn't have a filename for this level,
-         * don't clear the addStackTrace flag
-         * so we can pick it up at the next level
-         */
-        if (*filename) {
+        if (Jim_Length(fileNameObj)) {
             interp->addStackTrace = 0;
         }
 
         Jim_DecrRefCount(interp, interp->errorProc);
         interp->errorProc = interp->emptyObj;
         Jim_IncrRefCount(interp->errorProc);
     }
     else if (rc == JIM_RETURN && interp->returnCode == JIM_ERR) {
-        /* Propagate the addStackTrace value through 'return -code error' */
+        
     }
     else {
         interp->addStackTrace = 0;
     }
 }
 
-/* And delete any local procs */
+
 static void JimDeleteLocalProcs(Jim_Interp *interp)
 {
     if (interp->localProcs) {
         char *procname;
 
         while ((procname = Jim_StackPop(interp->localProcs)) != NULL) {
-            /* If there is a pushed command, find it */
+            
             Jim_Cmd *prevCmd = NULL;
             Jim_HashEntry *he = Jim_FindHashEntry(&interp->commands, procname);
             if (he) {
                 Jim_Cmd *cmd = (Jim_Cmd *)he->u.val;
                 if (cmd->isproc && cmd->u.proc.prevCmd) {
@@ -16139,15 +14121,15 @@
                     prevCmd = cmd->u.proc.prevCmd;
                     cmd->u.proc.prevCmd = NULL;
                 }
             }
 
-            /* Delete the local proc */
+            
             Jim_DeleteCommand(interp, procname);
 
             if (prevCmd) {
-                /* And restore the pushed command */
+                
                 Jim_AddHashEntry(&interp->commands, procname, prevCmd);
             }
             Jim_Free(procname);
         }
         Jim_FreeStack(interp->localProcs);
@@ -16179,21 +14161,21 @@
                 case JIM_OK:
                 case JIM_RETURN:
                     objPtr = interp->result;
                     break;
                 case JIM_BREAK:
-                    /* Stop substituting */
+                    
                     return JIM_BREAK;
                 case JIM_CONTINUE:
-                    /* just skip this one */
+                    
                     return JIM_CONTINUE;
                 default:
                     return JIM_ERR;
             }
             break;
         default:
-            JimPanic((1, interp,
+            JimPanic((1,
                 "default token type (%d) reached " "in Jim_SubstObj().", token->type));
             objPtr = NULL;
             break;
     }
     if (objPtr) {
@@ -16201,14 +14183,10 @@
         return JIM_OK;
     }
     return JIM_ERR;
 }
 
-/* Interpolate the given tokens into a unique Jim_Obj returned by reference
- * via *objPtrPtr. This function is only called by Jim_EvalObj() and Jim_SubstObj()
- * The returned object has refcount = 0.
- */
 static Jim_Obj *JimInterpolateTokens(Jim_Interp *interp, const ScriptToken * token, int tokens, int flags)
 {
     int totlen = 0, i;
     Jim_Obj **intv;
     Jim_Obj *sintv[JIM_EVAL_SINTV_LEN];
@@ -16218,32 +14196,30 @@
     if (tokens <= JIM_EVAL_SINTV_LEN)
         intv = sintv;
     else
         intv = Jim_Alloc(sizeof(Jim_Obj *) * tokens);
 
-    /* Compute every token forming the argument
-     * in the intv objects vector. */
     for (i = 0; i < tokens; i++) {
         switch (JimSubstOneToken(interp, &token[i], &intv[i])) {
             case JIM_OK:
             case JIM_RETURN:
                 break;
             case JIM_BREAK:
                 if (flags & JIM_SUBST_FLAG) {
-                    /* Stop here */
+                    
                     tokens = i;
                     continue;
                 }
-                /* XXX: Should probably set an error about break outside loop */
-                /* fall through to error */
+                
+                
             case JIM_CONTINUE:
                 if (flags & JIM_SUBST_FLAG) {
                     intv[i] = NULL;
                     continue;
                 }
-                /* XXX: Ditto continue outside loop */
-                /* fall through to error */
+                
+                
             default:
                 while (i--) {
                     Jim_DecrRefCount(interp, intv[i]);
                 }
                 if (intv != sintv) {
@@ -16254,23 +14230,21 @@
         Jim_IncrRefCount(intv[i]);
         Jim_String(intv[i]);
         totlen += intv[i]->length;
     }
 
-    /* Fast path return for a single token */
+    
     if (tokens == 1 && intv[0] && intv == sintv) {
         Jim_DecrRefCount(interp, intv[0]);
         return intv[0];
     }
 
-    /* Concatenate every token in an unique
-     * object. */
     objPtr = Jim_NewStringObjNoAlloc(interp, NULL, 0);
 
     if (tokens == 4 && token[0].type == JIM_TT_ESC && token[1].type == JIM_TT_ESC
         && token[2].type == JIM_TT_VAR) {
-        /* May be able to do fast interpolated object -> dictSubst */
+        
         objPtr->typePtr = &interpolatedObjType;
         objPtr->internalRep.twoPtrValue.ptr1 = (void *)token;
         objPtr->internalRep.twoPtrValue.ptr2 = intv[2];
         Jim_IncrRefCount(intv[2]);
     }
@@ -16283,39 +14257,33 @@
             s += intv[i]->length;
             Jim_DecrRefCount(interp, intv[i]);
         }
     }
     objPtr->bytes[totlen] = '\0';
-    /* Free the intv vector if not static. */
+    
     if (intv != sintv) {
         Jim_Free(intv);
     }
 
     return objPtr;
 }
 
 
-/* If listPtr is a list, call JimEvalObjVector() with the given source info.
- * Otherwise eval with Jim_EvalObj()
- */
-int Jim_EvalObjList(Jim_Interp *interp, Jim_Obj *listPtr, const char *filename, int linenr)
+static int JimEvalObjList(Jim_Interp *interp, Jim_Obj *listPtr, Jim_Obj *fileNameObj, int linenr)
 {
-    if (!Jim_IsList(listPtr)) {
-        return Jim_EvalObj(interp, listPtr);
+    int retcode = JIM_OK;
+
+    JimPanic((!Jim_IsList(listPtr), "JimEvalObjList() called without list arg"));
+
+    if (listPtr->internalRep.listValue.len) {
+        Jim_IncrRefCount(listPtr);
+        retcode = JimEvalObjVector(interp,
+            listPtr->internalRep.listValue.len,
+            listPtr->internalRep.listValue.ele, fileNameObj, linenr);
+        Jim_DecrRefCount(interp, listPtr);
     }
-    else {
-        int retcode = JIM_OK;
-
-        if (listPtr->internalRep.listValue.len) {
-            Jim_IncrRefCount(listPtr);
-            retcode = JimEvalObjVector(interp,
-                listPtr->internalRep.listValue.len,
-                listPtr->internalRep.listValue.ele, filename, linenr);
-            Jim_DecrRefCount(interp, listPtr);
-        }
-        return retcode;
-    }
+    return retcode;
 }
 
 int Jim_EvalObj(Jim_Interp *interp, Jim_Obj *scriptObjPtr)
 {
     int i;
@@ -16325,29 +14293,20 @@
     Jim_Obj *sargv[JIM_EVAL_SARGV_LEN], **argv = NULL;
     int linenr = 0;
 
     interp->errorFlag = 0;
 
-    /* If the object is of type "list", we can call
-     * a specialized version of Jim_EvalObj() */
-    if (Jim_IsList(scriptObjPtr)) {
-        return Jim_EvalObjList(interp, scriptObjPtr, NULL, 0);
+    if (Jim_IsList(scriptObjPtr) && scriptObjPtr->bytes == NULL) {
+        return JimEvalObjList(interp, scriptObjPtr, interp->emptyObj, 1);
     }
 
-    Jim_IncrRefCount(scriptObjPtr);     /* Make sure it's shared. */
+    Jim_IncrRefCount(scriptObjPtr);     
     script = Jim_GetScript(interp, scriptObjPtr);
 
-    /* Reset the interpreter result. This is useful to
-     * return the empty result in the case of empty program. */
     Jim_SetEmptyResult(interp);
 
 #ifdef JIM_OPTIMIZATION
-    /* Check for one of the following common scripts used by for, while
-     *
-     *   {}
-     *   incr a
-     */
     if (script->len == 0) {
         Jim_DecrRefCount(interp, scriptObjPtr);
         return JIM_OK;
     }
     if (script->len == 3
@@ -16366,47 +14325,31 @@
             return JIM_OK;
         }
     }
 #endif
 
-    /* Now we have to make sure the internal repr will not be
-     * freed on shimmering.
-     *
-     * Think for example to this:
-     *
-     * set x {llength $x; ... some more code ...}; eval $x
-     *
-     * In order to preserve the internal rep, we increment the
-     * inUse field of the script internal rep structure. */
     script->inUse++;
 
     token = script->token;
     argv = sargv;
 
-    /* Execute every command sequentially until the end of the script
-     * or an error occurs.
-     */
     for (i = 0; i < script->len && retcode == JIM_OK; ) {
         int argc;
         int j;
         Jim_Cmd *cmd;
 
-        /* First token of the line is always JIM_TT_LINE */
+        
         argc = token[i].objPtr->internalRep.scriptLineValue.argc;
         linenr = token[i].objPtr->internalRep.scriptLineValue.line;
 
-        /* Allocate the arguments vector if required */
+        
         if (argc > JIM_EVAL_SARGV_LEN)
             argv = Jim_Alloc(sizeof(Jim_Obj *) * argc);
 
-        /* Skip the JIM_TT_LINE token */
+        
         i++;
 
-        /* Populate the arguments objects.
-         * If an error occurs, retcode will be set and
-         * 'j' will be set to the number of args expanded
-         */
         for (j = 0; j < argc; j++) {
             long wordtokens = 1;
             int expand = 0;
             Jim_Obj *wordObjPtr = NULL;
 
@@ -16417,12 +14360,10 @@
                     wordtokens = -wordtokens;
                 }
             }
 
             if (wordtokens == 1) {
-                /* Fast path if the token does not
-                 * need interpolation */
 
                 switch (token[i].type) {
                     case JIM_TT_ESC:
                     case JIM_TT_STR:
                         wordObjPtr = token[i].objPtr;
@@ -16441,16 +14382,14 @@
                         if (retcode == JIM_OK) {
                             wordObjPtr = Jim_GetResult(interp);
                         }
                         break;
                     default:
-                        JimPanic((1, interp, "default token type reached " "in Jim_EvalObj()."));
+                        JimPanic((1, "default token type reached " "in Jim_EvalObj()."));
                 }
             }
             else {
-                /* For interpolation we call a helper
-                 * function to do the work for us. */
                 wordObjPtr = JimInterpolateTokens(interp, token + i, wordtokens, JIM_NONE);
             }
 
             if (!wordObjPtr) {
                 if (retcode == JIM_OK) {
@@ -16464,11 +14403,11 @@
 
             if (!expand) {
                 argv[j] = wordObjPtr;
             }
             else {
-                /* Need to expand wordObjPtr into multiple args from argv[j] ... */
+                
                 int len = Jim_ListLength(interp, wordObjPtr);
                 int newargc = argc + len - 1;
                 int k;
 
                 if (len > 1) {
@@ -16477,60 +14416,56 @@
                             argv = Jim_Alloc(sizeof(*argv) * newargc);
                             memcpy(argv, sargv, sizeof(*argv) * j);
                         }
                     }
                     else {
-                        /* Need to realloc to make room for (len - 1) more entries */
+                        
                         argv = Jim_Realloc(argv, sizeof(*argv) * newargc);
                     }
                 }
 
-                /* Now copy in the expanded version */
+                
                 for (k = 0; k < len; k++) {
                     argv[j++] = wordObjPtr->internalRep.listValue.ele[k];
                     Jim_IncrRefCount(wordObjPtr->internalRep.listValue.ele[k]);
                 }
 
-                /* The original object reference is no longer needed,
-                 * after the expansion it is no longer present on
-                 * the argument vector, but the single elements are
-                 * in its place. */
                 Jim_DecrRefCount(interp, wordObjPtr);
 
-                /* And update the indexes */
+                
                 j--;
                 argc += len - 1;
             }
         }
 
         if (retcode == JIM_OK && argc) {
-            /* Lookup the command to call */
+            
             cmd = Jim_GetCommand(interp, argv[0], JIM_ERRMSG);
             if (cmd != NULL) {
-                /* Call it -- Make sure result is an empty object. */
+                
                 JimIncrCmdRefCount(cmd);
                 Jim_SetEmptyResult(interp);
                 if (cmd->isproc) {
                     retcode =
-                        JimCallProcedure(interp, cmd, script->fileName, linenr, argc, argv);
+                        JimCallProcedure(interp, cmd, script->fileNameObj, linenr, argc, argv);
                 } else {
                     interp->cmdPrivData = cmd->u.native.privData;
                     retcode = cmd->u.native.cmdProc(interp, argc, argv);
                 }
                 JimDecrCmdRefCount(interp, cmd);
             }
             else {
-                /* Call [unknown] */
-                retcode = JimUnknown(interp, argc, argv, script->fileName, linenr);
+                
+                retcode = JimUnknown(interp, argc, argv, script->fileNameObj, linenr);
             }
             if (interp->signal_level && interp->sigmask) {
-                /* Check for a signal after each command */
+                
                 retcode = JIM_SIGNAL;
             }
         }
 
-        /* Finished with the command, so decrement ref counts of each argument */
+        
         while (j-- > 0) {
             Jim_DecrRefCount(interp, argv[j]);
         }
 
         if (argv != sargv) {
@@ -16537,16 +14472,13 @@
             Jim_Free(argv);
             argv = sargv;
         }
     }
 
-    /* Possibly add to the error stack trace */
-    JimAddErrorToStack(interp, retcode, script->fileName, linenr);
+    
+    JimAddErrorToStack(interp, retcode, script->fileNameObj, linenr);
 
-    /* Note that we don't have to decrement inUse, because the
-     * following code transfers our use of the reference again to
-     * the script object. */
     Jim_FreeIntRep(interp, scriptObjPtr);
     scriptObjPtr->typePtr = &scriptObjType;
     Jim_SetIntRepPtr(scriptObjPtr, script);
     Jim_DecrRefCount(interp, scriptObjPtr);
 
@@ -16554,14 +14486,14 @@
 }
 
 static int JimSetProcArg(Jim_Interp *interp, Jim_Obj *argNameObj, Jim_Obj *argValObj)
 {
     int retcode;
-    /* If argObjPtr begins with '&', do an automatic upvar */
+    
     const char *varname = Jim_String(argNameObj);
     if (*varname == '&') {
-        /* First check that the target variable exists */
+        
         Jim_Obj *objPtr;
         Jim_CallFrame *savedCallFrame = interp->framePtr;
 
         interp->framePtr = interp->framePtr->parentCallFrame;
         objPtr = Jim_GetVariable(interp, argValObj, JIM_ERRMSG);
@@ -16568,11 +14500,11 @@
         interp->framePtr = savedCallFrame;
         if (!objPtr) {
             return JIM_ERR;
         }
 
-        /* It exists, so perform the binding. */
+        
         objPtr = Jim_NewStringObj(interp, varname + 1, -1);
         Jim_IncrRefCount(objPtr);
         retcode = Jim_SetVariableLink(interp, objPtr, argValObj, interp->framePtr->parentCallFrame);
         Jim_DecrRefCount(interp, objPtr);
     }
@@ -16580,31 +14512,28 @@
         retcode = Jim_SetVariable(interp, argNameObj, argValObj);
     }
     return retcode;
 }
 
-/**
- * Sets the interp result to be an error message indicating the required proc args.
- */
 static void JimSetProcWrongArgs(Jim_Interp *interp, Jim_Obj *procNameObj, Jim_Cmd *cmd)
 {
-    /* Create a nice error message, consistent with Tcl 8.5 */
+    
     Jim_Obj *argmsg = Jim_NewStringObj(interp, "", 0);
     int i;
 
     for (i = 0; i < cmd->u.proc.argListLen; i++) {
         Jim_AppendString(interp, argmsg, " ", 1);
 
         if (i == cmd->u.proc.argsPos) {
             if (cmd->u.proc.arglist[i].defaultObjPtr) {
-                /* Renamed args */
+                
                 Jim_AppendString(interp, argmsg, "?", 1);
                 Jim_AppendObj(interp, argmsg, cmd->u.proc.arglist[i].defaultObjPtr);
                 Jim_AppendString(interp, argmsg, " ...?", -1);
             }
             else {
-                /* We have plain args */
+                
                 Jim_AppendString(interp, argmsg, "?argument ...?", -1);
             }
         }
         else {
             if (cmd->u.proc.arglist[i].defaultObjPtr) {
@@ -16619,68 +14548,64 @@
     }
     Jim_SetResultFormatted(interp, "wrong # args: should be \"%#s%#s\"", procNameObj, argmsg);
     Jim_FreeNewObj(interp, argmsg);
 }
 
-/* Call a procedure implemented in Tcl.
- * It's possible to speed-up a lot this function, currently
- * the callframes are not cached, but allocated and
- * destroied every time. What is expecially costly is
- * to create/destroy the local vars hash table every time.
- *
- * This can be fixed just implementing callframes caching
- * in JimCreateCallFrame() and JimFreeCallFrame(). */
-static int JimCallProcedure(Jim_Interp *interp, Jim_Cmd *cmd, const char *filename, int linenr, int argc,
+static int JimCallProcedure(Jim_Interp *interp, Jim_Cmd *cmd, Jim_Obj *fileNameObj, int linenr, int argc,
     Jim_Obj *const *argv)
 {
     Jim_CallFrame *callFramePtr;
     Jim_Stack *prevLocalProcs;
     int i, d, retcode, optargs;
 
-    /* Check arity */
+    
     if (argc - 1 < cmd->u.proc.reqArity ||
         (cmd->u.proc.argsPos < 0 && argc - 1 > cmd->u.proc.reqArity + cmd->u.proc.optArity)) {
         JimSetProcWrongArgs(interp, argv[0], cmd);
         return JIM_ERR;
     }
 
-    /* Check if there are too nested calls */
+    
     if (interp->framePtr->level == interp->maxNestingDepth) {
         Jim_SetResultString(interp, "Too many nested calls. Infinite recursion?", -1);
         return JIM_ERR;
     }
 
-    /* Create a new callframe */
+    
     callFramePtr = JimCreateCallFrame(interp, interp->framePtr);
     callFramePtr->argv = argv;
     callFramePtr->argc = argc;
     callFramePtr->procArgsObjPtr = cmd->u.proc.argListObjPtr;
     callFramePtr->procBodyObjPtr = cmd->u.proc.bodyObjPtr;
     callFramePtr->staticVars = cmd->u.proc.staticVars;
-    callFramePtr->filename = filename;
+    callFramePtr->fileNameObj = fileNameObj;
     callFramePtr->line = linenr;
     Jim_IncrRefCount(cmd->u.proc.argListObjPtr);
     Jim_IncrRefCount(cmd->u.proc.bodyObjPtr);
     interp->framePtr = callFramePtr;
 
-    /* How many optional args are available */
+    
+    prevLocalProcs = interp->localProcs;
+    interp->localProcs = NULL;
+
+    
     optargs = (argc - 1 - cmd->u.proc.reqArity);
 
-    /* Step 'i' along the actual args, and step 'd' along the formal args */
+    
     i = 1;
     for (d = 0; d < cmd->u.proc.argListLen; d++) {
         Jim_Obj *nameObjPtr = cmd->u.proc.arglist[d].nameObjPtr;
         if (d == cmd->u.proc.argsPos) {
-            /* assign $args */
+            
             Jim_Obj *listObjPtr;
             int argsLen = 0;
             if (cmd->u.proc.reqArity + cmd->u.proc.optArity < argc - 1) {
                 argsLen = argc - 1 - (cmd->u.proc.reqArity + cmd->u.proc.optArity);
             }
             listObjPtr = Jim_NewListObj(interp, &argv[i], argsLen);
 
-            /* It is possible to rename args. */
+            
             if (cmd->u.proc.arglist[d].defaultObjPtr) {
                 nameObjPtr =cmd->u.proc.arglist[d].defaultObjPtr;
             }
             retcode = Jim_SetVariable(interp, nameObjPtr, listObjPtr);
             if (retcode != JIM_OK) {
@@ -16689,53 +14614,48 @@
 
             i += argsLen;
             continue;
         }
 
-        /* Optional or required? */
+        
         if (cmd->u.proc.arglist[d].defaultObjPtr == NULL || optargs-- > 0) {
             retcode = JimSetProcArg(interp, nameObjPtr, argv[i++]);
         }
         else {
-            /* Ran out, so use the default */
+            
             retcode = Jim_SetVariable(interp, nameObjPtr, cmd->u.proc.arglist[d].defaultObjPtr);
         }
         if (retcode != JIM_OK) {
             goto badargset;
         }
     }
 
-    /* Install a new stack for local procs */
-    prevLocalProcs = interp->localProcs;
-    interp->localProcs = NULL;
-
-    /* Eval the body */
+    
     retcode = Jim_EvalObj(interp, cmd->u.proc.bodyObjPtr);
 
-    /* Delete any local procs */
-    JimDeleteLocalProcs(interp);
-    interp->localProcs = prevLocalProcs;
-
 badargset:
-    /* Destroy the callframe */
+    
     interp->framePtr = interp->framePtr->parentCallFrame;
     if (callFramePtr->vars.size != JIM_HT_INITIAL_SIZE) {
         JimFreeCallFrame(interp, callFramePtr, JIM_FCF_NONE);
     }
     else {
         JimFreeCallFrame(interp, callFramePtr, JIM_FCF_NOHT);
     }
-    /* Handle the JIM_EVAL return code */
+    
     while (retcode == JIM_EVAL) {
         Jim_Obj *resultScriptObjPtr = Jim_GetResult(interp);
 
         Jim_IncrRefCount(resultScriptObjPtr);
-        /* Should be a list! */
-        retcode = Jim_EvalObjList(interp, resultScriptObjPtr, filename, linenr);
+        
+        retcode = JimEvalObjList(interp, resultScriptObjPtr, fileNameObj, linenr);
+        if (retcode == JIM_RETURN) {
+            interp->returnLevel++;
+        }
         Jim_DecrRefCount(interp, resultScriptObjPtr);
     }
-    /* Handle the JIM_RETURN return code */
+    
     if (retcode == JIM_RETURN) {
         if (--interp->returnLevel <= 0) {
             retcode = interp->returnCode;
             interp->returnCode = JIM_OK;
             interp->returnLevel = 0;
@@ -16745,26 +14665,30 @@
         interp->addStackTrace++;
         Jim_DecrRefCount(interp, interp->errorProc);
         interp->errorProc = argv[0];
         Jim_IncrRefCount(interp->errorProc);
     }
+
+    
+    JimDeleteLocalProcs(interp);
+    interp->localProcs = prevLocalProcs;
+
     return retcode;
 }
 
-int Jim_Eval_Named(Jim_Interp *interp, const char *script, const char *filename, int lineno)
+int Jim_EvalSource(Jim_Interp *interp, const char *filename, int lineno, const char *script)
 {
     int retval;
     Jim_Obj *scriptObjPtr;
 
     scriptObjPtr = Jim_NewStringObj(interp, script, -1);
     Jim_IncrRefCount(scriptObjPtr);
 
-
     if (filename) {
         Jim_Obj *prevScriptObj;
 
-        JimSetSourceInfo(interp, scriptObjPtr, filename, lineno);
+        JimSetSourceInfo(interp, scriptObjPtr, Jim_NewStringObj(interp, filename, -1), lineno);
 
         prevScriptObj = interp->currentScriptObj;
         interp->currentScriptObj = scriptObjPtr;
 
         retval = Jim_EvalObj(interp, scriptObjPtr);
@@ -16778,14 +14702,14 @@
     return retval;
 }
 
 int Jim_Eval(Jim_Interp *interp, const char *script)
 {
-    return Jim_Eval_Named(interp, script, NULL, 0);
+    return Jim_EvalObj(interp, Jim_NewStringObj(interp, script, -1));
 }
 
-/* Execute script in the scope of the global level */
+
 int Jim_EvalGlobal(Jim_Interp *interp, const char *script)
 {
     int retval;
     Jim_CallFrame *savedFramePtr = interp->framePtr;
 
@@ -16840,14 +14764,14 @@
     }
     fclose(fp);
     buf[readlen] = 0;
 
     scriptObjPtr = Jim_NewStringObjNoAlloc(interp, buf, readlen);
-    JimSetSourceInfo(interp, scriptObjPtr, filename, 1);
+    JimSetSourceInfo(interp, scriptObjPtr, Jim_NewStringObj(interp, filename, -1), 1);
     Jim_IncrRefCount(scriptObjPtr);
 
-    /* Now check the script for unmatched braces, etc. */
+    
     if (SetScriptFromAny(interp, scriptObjPtr, &result) == JIM_ERR) {
         const char *msg;
         char linebuf[20];
 
         switch (result.missing) {
@@ -16874,20 +14798,20 @@
     prevScriptObj = interp->currentScriptObj;
     interp->currentScriptObj = scriptObjPtr;
 
     retcode = Jim_EvalObj(interp, scriptObjPtr);
 
-    /* Handle the JIM_RETURN return code */
+    
     if (retcode == JIM_RETURN) {
         if (--interp->returnLevel <= 0) {
             retcode = interp->returnCode;
             interp->returnCode = JIM_OK;
             interp->returnLevel = 0;
         }
     }
     if (retcode == JIM_ERR) {
-        /* EvalFile changes context, so add a stack frame here */
+        
         interp->addStackTrace++;
     }
 
     interp->currentScriptObj = prevScriptObj;
 
@@ -16894,13 +14818,10 @@
     Jim_DecrRefCount(interp, scriptObjPtr);
 
     return retcode;
 }
 
-/* -----------------------------------------------------------------------------
- * Subst
- * ---------------------------------------------------------------------------*/
 static int JimParseSubstStr(struct JimParserCtx *pc)
 {
     pc->tstart = pc->p;
     pc->tline = pc->linenr;
     while (pc->len && *pc->p != '$' && *pc->p != '[') {
@@ -16967,48 +14888,41 @@
             break;
     }
     return JIM_OK;
 }
 
-/* The subst object type reuses most of the data structures and functions
- * of the script object. Script's data structures are a bit more complex
- * for what is needed for [subst]itution tasks, but the reuse helps to
- * deal with a single data structure at the cost of some more memory
- * usage for substitutions. */
 
-/* This method takes the string representation of an object
- * as a Tcl string where to perform [subst]itution, and generates
- * the pre-parsed internal representation. */
 static int SetSubstFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr, int flags)
 {
     int scriptTextLen;
     const char *scriptText = Jim_GetString(objPtr, &scriptTextLen);
     struct JimParserCtx parser;
     struct ScriptObj *script = Jim_Alloc(sizeof(*script));
     ParseTokenList tokenlist;
 
-    /* Initially parse the subst into tokens (in tokenlist) */
+    
     ScriptTokenListInit(&tokenlist);
 
     JimParserInit(&parser, scriptText, scriptTextLen, 1);
     while (1) {
         JimParseSubst(&parser, flags);
         if (parser.eof) {
-            /* Note that subst doesn't need the EOL token */
+            
             break;
         }
         ScriptAddToken(&tokenlist, parser.tstart, parser.tend - parser.tstart + 1, parser.tt,
             parser.tline);
     }
 
-    /* Create the "real" subst/script tokens from the initial token list */
+    
     script->inUse = 1;
     script->substFlags = flags;
-    script->fileName = NULL;
+    script->fileNameObj = interp->emptyObj;
+    Jim_IncrRefCount(script->fileNameObj);
     SubstObjAddTokens(interp, script, &tokenlist);
 
-    /* No longer need the token list */
+    
     ScriptTokenListFree(&tokenlist);
 
 #ifdef DEBUG_SHOW_SUBST
     {
         int i;
@@ -17019,11 +14933,11 @@
                 Jim_String(script->token[i].objPtr));
         }
     }
 #endif
 
-    /* Free the old internal rep and set the new one. */
+    
     Jim_FreeIntRep(interp, objPtr);
     Jim_SetIntRepPtr(objPtr, script);
     objPtr->typePtr = &scriptObjType;
     return JIM_OK;
 }
@@ -17033,20 +14947,15 @@
     if (objPtr->typePtr != &scriptObjType || ((ScriptObj *)Jim_GetIntRepPtr(objPtr))->substFlags != flags)
         SetSubstFromAny(interp, objPtr, flags);
     return (ScriptObj *) Jim_GetIntRepPtr(objPtr);
 }
 
-/* Performs commands,variables,blackslashes substitution,
- * storing the result object (with refcount 0) into
- * resObjPtrPtr. */
 int Jim_SubstObj(Jim_Interp *interp, Jim_Obj *substObjPtr, Jim_Obj **resObjPtrPtr, int flags)
 {
     ScriptObj *script = Jim_GetSubst(interp, substObjPtr, flags);
 
-    Jim_IncrRefCount(substObjPtr);      /* Make sure it's shared. */
-    /* In order to preserve the internal rep, we increment the
-     * inUse field of the script internal rep structure. */
+    Jim_IncrRefCount(substObjPtr);      
     script->inUse++;
 
     *resObjPtrPtr = JimInterpolateTokens(interp, script->token, script->len, flags);
 
     script->inUse--;
@@ -17055,13 +14964,10 @@
         return JIM_ERR;
     }
     return JIM_OK;
 }
 
-/* -----------------------------------------------------------------------------
- * Core commands utility functions
- * ---------------------------------------------------------------------------*/
 void Jim_WrongNumArgs(Jim_Interp *interp, int argc, Jim_Obj *const *argv, const char *msg)
 {
     int i;
     Jim_Obj *objPtr = Jim_NewEmptyStringObj(interp);
 
@@ -17076,26 +14982,26 @@
     Jim_SetResult(interp, objPtr);
 }
 
 #define JimTrivialMatch(pattern)	(strpbrk((pattern), "*[?\\") == NULL)
 
-/* type is: 0=commands, 1=procs, 2=channels */
+
 static Jim_Obj *JimCommandsList(Jim_Interp *interp, Jim_Obj *patternObjPtr, int type)
 {
     Jim_HashTableIterator *htiter;
     Jim_HashEntry *he;
     Jim_Obj *listObjPtr = Jim_NewListObj(interp, NULL, 0);
 
-    /* Check for the non-pattern case. We can do this much more efficiently. */
+    
     if (patternObjPtr && JimTrivialMatch(Jim_String(patternObjPtr))) {
         Jim_Cmd *cmdPtr = Jim_GetCommand(interp, patternObjPtr, JIM_NONE);
         if (cmdPtr) {
             if (type == 1 && !cmdPtr->isproc) {
-                /* not a proc */
+                
             }
             else if (type == 2 && !Jim_AioFilehandle(interp, patternObjPtr)) {
-                /* not a channel */
+                
             }
             else {
                 Jim_ListAppendElement(interp, listObjPtr, patternObjPtr);
             }
         }
@@ -17106,19 +15012,19 @@
     while ((he = Jim_NextHashEntry(htiter)) != NULL) {
         Jim_Cmd *cmdPtr = he->u.val;
         Jim_Obj *cmdNameObj;
 
         if (type == 1 && !cmdPtr->isproc) {
-            /* not a proc */
+            
             continue;
         }
         if (patternObjPtr && !JimStringMatch(interp, patternObjPtr, he->key, 0))
             continue;
 
         cmdNameObj = Jim_NewStringObj(interp, he->key, -1);
 
-        /* Is it a channel? */
+        
         if (type == 2 && !Jim_AioFilehandle(interp, cmdNameObj)) {
             Jim_FreeNewObj(interp, cmdNameObj);
             continue;
         }
 
@@ -17126,11 +15032,11 @@
     }
     Jim_FreeHashTableIterator(htiter);
     return listObjPtr;
 }
 
-/* Keep this in order */
+
 #define JIM_VARLIST_GLOBALS 0
 #define JIM_VARLIST_LOCALS 1
 #define JIM_VARLIST_VARS 2
 
 static Jim_Obj *JimVariablesList(Jim_Interp *interp, Jim_Obj *patternObjPtr, int mode)
@@ -17141,12 +15047,10 @@
 
     if (mode == JIM_VARLIST_GLOBALS) {
         htiter = Jim_GetHashTableIterator(&interp->topFramePtr->vars);
     }
     else {
-        /* For [info locals], if we are at top level an emtpy list
-         * is returned. I don't agree, but we aim at compatibility (SS) */
         if (mode == JIM_VARLIST_LOCALS && interp->framePtr == interp->topFramePtr)
             return listObjPtr;
         htiter = Jim_GetHashTableIterator(&interp->framePtr->vars);
     }
     while ((he = Jim_NextHashEntry(htiter)) != NULL) {
@@ -17171,11 +15075,11 @@
 
     targetCallFrame = JimGetCallFrameByInteger(interp, levelObjPtr);
     if (targetCallFrame == NULL) {
         return JIM_ERR;
     }
-    /* No proc call at toplevel callframe */
+    
     if (targetCallFrame == interp->topFramePtr) {
         Jim_SetResultFormatted(interp, "bad level \"%#s\"", levelObjPtr);
         return JIM_ERR;
     }
     if (info_level_cmd) {
@@ -17183,23 +15087,19 @@
     }
     else {
         Jim_Obj *listObj = Jim_NewListObj(interp, NULL, 0);
 
         Jim_ListAppendElement(interp, listObj, targetCallFrame->argv[0]);
-        Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp,
-                targetCallFrame->filename ? targetCallFrame->filename : "", -1));
+        Jim_ListAppendElement(interp, listObj, targetCallFrame->fileNameObj);
         Jim_ListAppendElement(interp, listObj, Jim_NewIntObj(interp, targetCallFrame->line));
         *objPtrPtr = listObj;
     }
     return JIM_OK;
 }
 
-/* -----------------------------------------------------------------------------
- * Core commands
- * ---------------------------------------------------------------------------*/
 
-/* fake [puts] -- not the real puts, just for debugging. */
+
 static int Jim_PutsCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
 {
     if (argc != 2 && argc != 3) {
         Jim_WrongNumArgs(interp, 1, argv, "?-nonewline? string");
         return JIM_ERR;
@@ -17217,11 +15117,11 @@
         puts(Jim_String(argv[1]));
     }
     return JIM_OK;
 }
 
-/* Helper for [+] and [*] */
+
 static int JimAddMulHelper(Jim_Interp *interp, int argc, Jim_Obj *const *argv, int op)
 {
     jim_wide wideValue, res;
     double doubleValue, doubleRes;
     int i;
@@ -17250,11 +15150,11 @@
     }
     Jim_SetResult(interp, Jim_NewDoubleObj(interp, doubleRes));
     return JIM_OK;
 }
 
-/* Helper for [-] and [/] */
+
 static int JimSubDivHelper(Jim_Interp *interp, int argc, Jim_Obj *const *argv, int op)
 {
     jim_wide wideValue, res = 0;
     double doubleValue, doubleRes = 0;
     int i = 2;
@@ -17262,12 +15162,10 @@
     if (argc < 2) {
         Jim_WrongNumArgs(interp, 1, argv, "number ?number ... number?");
         return JIM_ERR;
     }
     else if (argc == 2) {
-        /* The arity = 2 case is different. For [- x] returns -x,
-         * while [/ x] returns 1/x. */
         if (Jim_GetWide(interp, argv[1], &wideValue) != JIM_OK) {
             if (Jim_GetDouble(interp, argv[1], &doubleValue) != JIM_OK) {
                 return JIM_ERR;
             }
             else {
@@ -17324,35 +15222,35 @@
     Jim_SetResult(interp, Jim_NewDoubleObj(interp, doubleRes));
     return JIM_OK;
 }
 
 
-/* [+] */
+
 static int Jim_AddCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
 {
     return JimAddMulHelper(interp, argc, argv, JIM_EXPROP_ADD);
 }
 
-/* [*] */
+
 static int Jim_MulCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
 {
     return JimAddMulHelper(interp, argc, argv, JIM_EXPROP_MUL);
 }
 
-/* [-] */
+
 static int Jim_SubCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
 {
     return JimSubDivHelper(interp, argc, argv, JIM_EXPROP_SUB);
 }
 
-/* [/] */
+
 static int Jim_DivCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
 {
     return JimSubDivHelper(interp, argc, argv, JIM_EXPROP_DIV);
 }
 
-/* [set] */
+
 static int Jim_SetCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
 {
     if (argc != 2 && argc != 3) {
         Jim_WrongNumArgs(interp, 1, argv, "varName ?newValue?");
         return JIM_ERR;
@@ -17364,21 +15262,17 @@
         if (!objPtr)
             return JIM_ERR;
         Jim_SetResult(interp, objPtr);
         return JIM_OK;
     }
-    /* argc == 3 case. */
+    
     if (Jim_SetVariable(interp, argv[1], argv[2]) != JIM_OK)
         return JIM_ERR;
     Jim_SetResult(interp, argv[2]);
     return JIM_OK;
 }
 
-/* [unset]
- *
- * unset ?-nocomplain? ?--? ?varName ...?
- */
 static int Jim_UnsetCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
 {
     int i = 1;
     int complain = 1;
 
@@ -17403,19 +15297,19 @@
         i++;
     }
     return JIM_OK;
 }
 
-/* [while] */
+
 static int Jim_WhileCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
 {
     if (argc != 3) {
         Jim_WrongNumArgs(interp, 1, argv, "condition body");
         return JIM_ERR;
     }
 
-    /* The general purpose implementation of while starts here */
+    
     while (1) {
         int boolean, retval;
 
         if ((retval = Jim_GetBoolFromExpr(interp, argv[1], &boolean)) != JIM_OK)
             return retval;
@@ -17438,11 +15332,11 @@
   out:
     Jim_SetEmptyResult(interp);
     return JIM_OK;
 }
 
-/* [for] */
+
 static int Jim_ForCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
 {
     int retval;
     int boolean = 1;
     Jim_Obj *varNamePtr = NULL;
@@ -17451,50 +15345,36 @@
     if (argc != 5) {
         Jim_WrongNumArgs(interp, 1, argv, "start test next body");
         return JIM_ERR;
     }
 
-    /* Do the initialisation */
+    
     if ((retval = Jim_EvalObj(interp, argv[1])) != JIM_OK) {
         return retval;
     }
 
-    /* And do the first test now. Better for optimisation
-     * if we can do next/test at the bottom of the loop
-     */
     retval = Jim_GetBoolFromExpr(interp, argv[2], &boolean);
 
-    /* Ready to do the body as follows:
-     * while (1) {
-     *     body // check retcode
-     *     next // check retcode
-     *     test // check retcode/test bool
-     * }
-     */
 
 #ifdef JIM_OPTIMIZATION
-    /* Check if the for is on the form:
-     *      for ... {$i < CONST} {incr i}
-     *      for ... {$i < $j} {incr i}
-     */
     if (retval == JIM_OK && boolean) {
         ScriptObj *incrScript;
         ExprByteCode *expr;
         jim_wide stop, currentVal;
         unsigned jim_wide procEpoch;
         Jim_Obj *objPtr;
         int cmpOffset;
 
-        /* Do it only if there aren't shared arguments */
+        
         expr = JimGetExpression(interp, argv[2]);
         incrScript = Jim_GetScript(interp, argv[3]);
 
-        /* Ensure proper lengths to start */
+        
         if (incrScript->len != 3 || !expr || expr->len != 3) {
             goto evalstart;
         }
-        /* Ensure proper token types. */
+        
         if (incrScript->token[1].type != JIM_TT_ESC ||
             expr->token[0].type != JIM_TT_VAR ||
             (expr->token[1].type != JIM_TT_EXPR_INT && expr->token[1].type != JIM_TT_VAR)) {
             goto evalstart;
         }
@@ -17507,49 +15387,49 @@
         }
         else {
             goto evalstart;
         }
 
-        /* Update command must be incr */
+        
         if (!Jim_CompareStringImmediate(interp, incrScript->token[1].objPtr, "incr")) {
             goto evalstart;
         }
 
-        /* incr, expression must be about the same variable */
+        
         if (!Jim_StringEqObj(incrScript->token[2].objPtr, expr->token[0].objPtr)) {
             goto evalstart;
         }
 
-        /* Get the stop condition (must be a variable or integer) */
+        
         if (expr->token[1].type == JIM_TT_EXPR_INT) {
             if (Jim_GetWide(interp, expr->token[1].objPtr, &stop) == JIM_ERR) {
                 goto evalstart;
             }
         }
         else {
             stopVarNamePtr = expr->token[1].objPtr;
             Jim_IncrRefCount(stopVarNamePtr);
-            /* Keep the compiler happy */
+            
             stop = 0;
         }
 
-        /* Initialization */
+        
         procEpoch = interp->procEpoch;
         varNamePtr = expr->token[0].objPtr;
         Jim_IncrRefCount(varNamePtr);
 
         objPtr = Jim_GetVariable(interp, varNamePtr, JIM_NONE);
         if (objPtr == NULL || Jim_GetWide(interp, objPtr, &currentVal) != JIM_OK) {
             goto testcond;
         }
 
-        /* --- OPTIMIZED FOR --- */
+        
         while (retval == JIM_OK) {
-            /* === Check condition === */
-            /* Note that currentVal is already set here */
+            
+            
 
-            /* Immediate or Variable? get the 'stop' value if the latter. */
+            
             if (stopVarNamePtr) {
                 objPtr = Jim_GetVariable(interp, stopVarNamePtr, JIM_NONE);
                 if (objPtr == NULL || Jim_GetWide(interp, objPtr, &stop) != JIM_OK) {
                     goto testcond;
                 }
@@ -17557,23 +15437,21 @@
 
             if (currentVal >= stop + cmpOffset) {
                 break;
             }
 
-            /* Eval body */
+            
             retval = Jim_EvalObj(interp, argv[4]);
             if (retval == JIM_OK || retval == JIM_CONTINUE) {
                 retval = JIM_OK;
-                /* If there was a change in procedures/command continue
-                 * with the usual [for] command implementation */
                 if (procEpoch != interp->procEpoch) {
                     goto evalnext;
                 }
 
                 objPtr = Jim_GetVariable(interp, varNamePtr, JIM_ERRMSG);
 
-                /* Increment */
+                
                 if (objPtr == NULL) {
                     retval = JIM_ERR;
                     goto out;
                 }
                 if (!Jim_IsShared(objPtr) && objPtr->typePtr == &intObjType) {
@@ -17593,19 +15471,19 @@
     }
   evalstart:
 #endif
 
     while (boolean && (retval == JIM_OK || retval == JIM_CONTINUE)) {
-        /* Body */
+        
         retval = Jim_EvalObj(interp, argv[4]);
 
         if (retval == JIM_OK || retval == JIM_CONTINUE) {
-            /* increment */
+            
           evalnext:
             retval = Jim_EvalObj(interp, argv[3]);
             if (retval == JIM_OK || retval == JIM_CONTINUE) {
-                /* test */
+                
               testcond:
                 retval = Jim_GetBoolFromExpr(interp, argv[2], &boolean);
             }
         }
     }
@@ -17623,11 +15501,11 @@
     }
 
     return retval;
 }
 
-/* [loop] */
+
 static int Jim_LoopCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
 {
     int retval;
     jim_wide i;
     jim_wide limit;
@@ -17653,11 +15531,11 @@
         if (retval == JIM_OK || retval == JIM_CONTINUE) {
             Jim_Obj *objPtr = Jim_GetVariable(interp, argv[1], JIM_ERRMSG);
 
             retval = JIM_OK;
 
-            /* Increment */
+            
             i += incr;
 
             if (objPtr && !Jim_IsShared(objPtr) && objPtr->typePtr == &intObjType) {
                 if (argv[1]->typePtr != &variableObjType) {
                     if (Jim_SetVariable(interp, argv[1], objPtr) != JIM_OK) {
@@ -17665,12 +15543,10 @@
                     }
                 }
                 JimWideValue(objPtr) = i;
                 Jim_InvalidateStringRep(objPtr);
 
-                /* The following step is required in order to invalidate the
-                 * string repr of "FOO" if the var name is of the form of "FOO(IDX)" */
                 if (argv[1]->typePtr != &variableObjType) {
                     if (Jim_SetVariable(interp, argv[1], objPtr) != JIM_OK) {
                         retval = JIM_ERR;
                         break;
                     }
@@ -17691,11 +15567,11 @@
         return JIM_OK;
     }
     return retval;
 }
 
-/* foreach + lmap implementation. */
+
 static int JimForeachMapHelper(Jim_Interp *interp, int argc, Jim_Obj *const *argv, int doMap)
 {
     int result = JIM_ERR, i, nbrOfLists, *listsIdx, *listsEnd;
     int nbrOfLoops = 0;
     Jim_Obj *emptyStr, *script, *mapRes = NULL;
@@ -17708,17 +15584,17 @@
         mapRes = Jim_NewListObj(interp, NULL, 0);
         Jim_IncrRefCount(mapRes);
     }
     emptyStr = Jim_NewEmptyStringObj(interp);
     Jim_IncrRefCount(emptyStr);
-    script = argv[argc - 1];    /* Last argument is a script */
-    nbrOfLists = (argc - 1 - 1) / 2;    /* argc - 'foreach' - script */
+    script = argv[argc - 1];    
+    nbrOfLists = (argc - 1 - 1) / 2;    
     listsIdx = (int *)Jim_Alloc(nbrOfLists * sizeof(int));
     listsEnd = (int *)Jim_Alloc(nbrOfLists * 2 * sizeof(int));
-    /* Initialize iterators and remember max nbr elements each list */
+    
     memset(listsIdx, 0, nbrOfLists * sizeof(int));
-    /* Remember lengths of all lists and calculate how much rounds to loop */
+    
     for (i = 0; i < nbrOfLists * 2; i += 2) {
         div_t cnt;
         int count;
 
         listsEnd[i] = Jim_ListLength(interp, argv[i + 1]);
@@ -17738,26 +15614,26 @@
 
             while (varIdx < listsEnd[var]) {
                 Jim_Obj *varName, *ele;
                 int lst = i * 2 + 1;
 
-                /* List index operations below can't fail */
+                
                 Jim_ListIndex(interp, argv[var + 1], varIdx, &varName, JIM_NONE);
                 if (listsIdx[i] < listsEnd[lst]) {
                     Jim_ListIndex(interp, argv[lst + 1], listsIdx[i], &ele, JIM_NONE);
-                    /* Avoid shimmering */
+                    
                     Jim_IncrRefCount(ele);
                     result = Jim_SetVariable(interp, varName, ele);
                     Jim_DecrRefCount(interp, ele);
                     if (result == JIM_OK) {
-                        ++listsIdx[i];  /* Remember next iterator of current list */
-                        ++varIdx;       /* Next variable */
+                        ++listsIdx[i];  
+                        ++varIdx;       
                         continue;
                     }
                 }
                 else if (Jim_SetVariable(interp, varName, emptyStr) == JIM_OK) {
-                    ++varIdx;   /* Next variable */
+                    ++varIdx;   
                     continue;
                 }
                 goto err;
             }
         }
@@ -17788,62 +15664,60 @@
     Jim_Free(listsIdx);
     Jim_Free(listsEnd);
     return result;
 }
 
-/* [foreach] */
+
 static int Jim_ForeachCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
 {
     return JimForeachMapHelper(interp, argc, argv, 0);
 }
 
-/* [lmap] */
+
 static int Jim_LmapCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
 {
     return JimForeachMapHelper(interp, argc, argv, 1);
 }
 
-/* [if] */
+
 static int Jim_IfCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
 {
     int boolean, retval, current = 1, falsebody = 0;
 
     if (argc >= 3) {
         while (1) {
-            /* Far not enough arguments given! */
+            
             if (current >= argc)
                 goto err;
             if ((retval = Jim_GetBoolFromExpr(interp, argv[current++], &boolean))
                 != JIM_OK)
                 return retval;
-            /* There lacks something, isn't it? */
+            
             if (current >= argc)
                 goto err;
             if (Jim_CompareStringImmediate(interp, argv[current], "then"))
                 current++;
-            /* Tsk tsk, no then-clause? */
+            
             if (current >= argc)
                 goto err;
             if (boolean)
                 return Jim_EvalObj(interp, argv[current]);
-            /* Ok: no else-clause follows */
+            
             if (++current >= argc) {
                 Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
                 return JIM_OK;
             }
             falsebody = current++;
             if (Jim_CompareStringImmediate(interp, argv[falsebody], "else")) {
-                /* IIICKS - else-clause isn't last cmd? */
+                
                 if (current != argc - 1)
                     goto err;
                 return Jim_EvalObj(interp, argv[current]);
             }
             else if (Jim_CompareStringImmediate(interp, argv[falsebody], "elseif"))
-                /* Ok: elseif follows meaning all the stuff
-                 * again (how boring...) */
                 continue;
-            /* OOPS - else-clause is not last cmd? */
+            
             else if (falsebody != argc - 1)
                 goto err;
             return Jim_EvalObj(interp, argv[falsebody]);
         }
         return JIM_OK;
@@ -17852,11 +15726,11 @@
     Jim_WrongNumArgs(interp, 1, argv, "condition ?then? trueBody ?elseif ...? ?else? falseBody");
     return JIM_ERR;
 }
 
 
-/* Returns 1 if match, 0 if no match or -<error> on error (e.g. -JIM_ERR, -JIM_BREAK)*/
+
 int Jim_CommandMatchObj(Jim_Interp *interp, Jim_Obj *commandObj, Jim_Obj *patternObj,
     Jim_Obj *stringObj, int nocase)
 {
     Jim_Obj *parms[4];
     int argc = 0;
@@ -17880,11 +15754,11 @@
 }
 
 enum
 { SWITCH_EXACT, SWITCH_GLOB, SWITCH_RE, SWITCH_CMD };
 
-/* [switch] */
+
 static int Jim_SwitchCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
 {
     int matchOpt = SWITCH_EXACT, opt = 1, patCount, i;
     Jim_Obj *command = 0, *const *caseList = 0, *strObj;
     Jim_Obj *script = 0;
@@ -17894,11 +15768,11 @@
         Jim_WrongNumArgs(interp, 1, argv, "?options? string "
             "pattern body ... ?default body?   or   " "{pattern body ?pattern body ...?}");
         return JIM_ERR;
     }
     for (opt = 1; opt < argc; ++opt) {
-        const char *option = Jim_GetString(argv[opt], 0);
+        const char *option = Jim_String(argv[opt]);
 
         if (*option != '-')
             break;
         else if (strncmp(option, "--", 2) == 0) {
             ++opt;
@@ -17951,24 +15825,21 @@
                     if (Jim_StringMatchObj(interp, patObj, strObj, 0))
                         script = caseList[i + 1];
                     break;
                 case SWITCH_RE:
                     command = Jim_NewStringObj(interp, "regexp", -1);
-                    /* Fall thru intentionally */
+                    
                 case SWITCH_CMD:{
                         int rc = Jim_CommandMatchObj(interp, command, patObj, strObj, 0);
 
-                        /* After the execution of a command we need to
-                         * make sure to reconvert the object into a list
-                         * again. Only for the single-list style [switch]. */
                         if (argc - opt == 1) {
                             Jim_Obj **vector;
 
                             JimListGetElements(interp, argv[opt], &patCount, &vector);
                             caseList = vector;
                         }
-                        /* command is here already decref'd */
+                        
                         if (rc < 0) {
                             return -rc;
                         }
                         if (rc)
                             script = caseList[i + 1];
@@ -17991,21 +15862,21 @@
         return Jim_EvalObj(interp, script);
     }
     return JIM_OK;
 }
 
-/* [list] */
+
 static int Jim_ListCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
 {
     Jim_Obj *listObjPtr;
 
     listObjPtr = Jim_NewListObj(interp, argv + 1, argc - 1);
     Jim_SetResult(interp, listObjPtr);
     return JIM_OK;
 }
 
-/* [lindex] */
+
 static int Jim_LindexCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
 {
     Jim_Obj *objPtr, *listObjPtr;
     int i;
     int idx;
@@ -18021,12 +15892,10 @@
         if (Jim_GetIndex(interp, argv[i], &idx) != JIM_OK) {
             Jim_DecrRefCount(interp, listObjPtr);
             return JIM_ERR;
         }
         if (Jim_ListIndex(interp, listObjPtr, idx, &objPtr, JIM_NONE) != JIM_OK) {
-            /* Returns an empty object if the index
-             * is out of range. */
             Jim_DecrRefCount(interp, listObjPtr);
             Jim_SetEmptyResult(interp);
             return JIM_OK;
         }
         Jim_IncrRefCount(objPtr);
@@ -18035,11 +15904,11 @@
     Jim_SetResult(interp, objPtr);
     Jim_DecrRefCount(interp, objPtr);
     return JIM_OK;
 }
 
-/* [llength] */
+
 static int Jim_LlengthCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
 {
     if (argc != 2) {
         Jim_WrongNumArgs(interp, 1, argv, "list");
         return JIM_ERR;
@@ -18046,11 +15915,11 @@
     }
     Jim_SetResultInt(interp, Jim_ListLength(interp, argv[1]));
     return JIM_OK;
 }
 
-/* [lsearch] */
+
 static int Jim_LsearchCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
 {
     static const char * const options[] = {
         "-bool", "-not", "-nocase", "-exact", "-glob", "-regexp", "-all", "-inline", "-command",
             NULL
@@ -18104,11 +15973,11 @@
             case OPT_COMMAND:
                 if (i >= argc - 2) {
                     goto wrongargs;
                 }
                 commandObj = argv[++i];
-                /* fallthru */
+                
             case OPT_EXACT:
             case OPT_GLOB:
             case OPT_REGEXP:
                 opt_match = option;
                 break;
@@ -18153,17 +16022,17 @@
                     goto done;
                 }
                 break;
         }
 
-        /* If we have a non-match with opt_bool, opt_not, !opt_all, can't exit early */
+        
         if (!eq && opt_bool && opt_not && !opt_all) {
             continue;
         }
 
         if ((!opt_bool && eq == !opt_not) || (opt_bool && (eq || opt_all))) {
-            /* Got a match (or non-match for opt_not), or (opt_bool && opt_all) */
+            
             Jim_Obj *resultObj;
 
             if (opt_bool) {
                 resultObj = Jim_NewIntObj(interp, eq ^ opt_not);
             }
@@ -18186,11 +16055,11 @@
 
     if (opt_all) {
         Jim_SetResult(interp, listObjPtr);
     }
     else {
-        /* No match */
+        
         if (opt_bool) {
             Jim_SetResultBool(interp, opt_not);
         }
         else if (!opt_inline) {
             Jim_SetResultInt(interp, -1);
@@ -18202,11 +16071,11 @@
         Jim_DecrRefCount(interp, commandObj);
     }
     return rc;
 }
 
-/* [lappend] */
+
 static int Jim_LappendCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
 {
     Jim_Obj *listObjPtr;
     int shared, i;
 
@@ -18214,11 +16083,11 @@
         Jim_WrongNumArgs(interp, 1, argv, "varName ?value value ...?");
         return JIM_ERR;
     }
     listObjPtr = Jim_GetVariable(interp, argv[1], JIM_UNSHARED);
     if (!listObjPtr) {
-        /* Create the list if it does not exists */
+        
         listObjPtr = Jim_NewListObj(interp, NULL, 0);
         if (Jim_SetVariable(interp, argv[1], listObjPtr) != JIM_OK) {
             Jim_FreeNewObj(interp, listObjPtr);
             return JIM_ERR;
         }
@@ -18235,11 +16104,11 @@
     }
     Jim_SetResult(interp, listObjPtr);
     return JIM_OK;
 }
 
-/* [linsert] */
+
 static int Jim_LinsertCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
 {
     int idx, len;
     Jim_Obj *listPtr;
 
@@ -18265,18 +16134,16 @@
         Jim_FreeNewObj(interp, listPtr);
     }
     return JIM_ERR;
 }
 
-/* [lreplace] */
+
 static int Jim_LreplaceCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
 {
     int first, last, len, rangeLen;
     Jim_Obj *listObj;
     Jim_Obj *newListObj;
-    int i;
-    int shared;
 
     if (argc < 4) {
         Jim_WrongNumArgs(interp, 1, argv, "list first last ?element element ...?");
         return JIM_ERR;
     }
@@ -18290,57 +16157,39 @@
 
     first = JimRelToAbsIndex(len, first);
     last = JimRelToAbsIndex(len, last);
     JimRelToAbsRange(len, first, last, &first, &last, &rangeLen);
 
-    /* Now construct a new list which consists of:
-     * <elements before first> <supplied elements> <elements after last>
-     */
 
-    /* Check to see if trying to replace past the end of the list */
+    
     if (first < len) {
-        /* OK. Not past the end */
+        
     }
     else if (len == 0) {
-        /* Special for empty list, adjust first to 0 */
+        
         first = 0;
     }
     else {
         Jim_SetResultString(interp, "list doesn't contain element ", -1);
         Jim_AppendObj(interp, Jim_GetResult(interp), argv[2]);
         return JIM_ERR;
     }
 
-    newListObj = Jim_NewListObj(interp, NULL, 0);
+    
+    newListObj = Jim_NewListObj(interp, listObj->internalRep.listValue.ele, first);
 
-    shared = Jim_IsShared(listObj);
-    if (shared) {
-        listObj = Jim_DuplicateObj(interp, listObj);
-    }
+    
+    ListInsertElements(newListObj, -1, argc - 4, argv + 4);
 
-    /* Add the first set of elements */
-    for (i = 0; i < first; i++) {
-        Jim_ListAppendElement(interp, newListObj, listObj->internalRep.listValue.ele[i]);
-    }
+    
+    ListInsertElements(newListObj, -1, len - first - rangeLen, listObj->internalRep.listValue.ele + first + rangeLen);
 
-    /* Add supplied elements */
-    for (i = 4; i < argc; i++) {
-        Jim_ListAppendElement(interp, newListObj, argv[i]);
-    }
-
-    /* Add the remaining elements */
-    for (i = first + rangeLen; i < len; i++) {
-        Jim_ListAppendElement(interp, newListObj, listObj->internalRep.listValue.ele[i]);
-    }
     Jim_SetResult(interp, newListObj);
-    if (shared) {
-        Jim_FreeNewObj(interp, listObj);
-    }
     return JIM_OK;
 }
 
-/* [lset] */
+
 static int Jim_LsetCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
 {
     if (argc < 3) {
         Jim_WrongNumArgs(interp, 1, argv, "listVar ?index...? newVal");
         return JIM_ERR;
@@ -18355,11 +16204,11 @@
         == JIM_ERR)
         return JIM_ERR;
     return JIM_OK;
 }
 
-/* [lsort] */
+
 static int Jim_LsortCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const argv[])
 {
     static const char * const options[] = {
         "-ascii", "-nocase", "-increasing", "-decreasing", "-command", "-integer", "-index", NULL
     };
@@ -18435,11 +16284,11 @@
         Jim_FreeNewObj(interp, resObj);
     }
     return retCode;
 }
 
-/* [append] */
+
 static int Jim_AppendCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
 {
     Jim_Obj *stringObjPtr;
     int i;
 
@@ -18454,11 +16303,11 @@
     }
     else {
         int freeobj = 0;
         stringObjPtr = Jim_GetVariable(interp, argv[1], JIM_UNSHARED);
         if (!stringObjPtr) {
-            /* Create the string if it doesn't exist */
+            
             stringObjPtr = Jim_NewEmptyStringObj(interp);
             freeobj = 1;
         }
         else if (Jim_IsShared(stringObjPtr)) {
             freeobj = 1;
@@ -18476,216 +16325,20 @@
     }
     Jim_SetResult(interp, stringObjPtr);
     return JIM_OK;
 }
 
-/* [debug] */
+
 static int Jim_DebugCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
 {
-#ifdef JIM_DEBUG_COMMAND
-    static const char * const options[] = {
-        "refcount", "objcount", "objects", "invstr", "scriptlen", "exprlen",
-        "exprbc", "show",
-        NULL
-    };
-    enum
-    {
-        OPT_REFCOUNT, OPT_OBJCOUNT, OPT_OBJECTS, OPT_INVSTR, OPT_SCRIPTLEN,
-        OPT_EXPRLEN, OPT_EXPRBC, OPT_SHOW,
-    };
-    int option;
-
-    if (argc < 2) {
-        Jim_WrongNumArgs(interp, 1, argv, "subcommand ?...?");
-        return JIM_ERR;
-    }
-    if (Jim_GetEnum(interp, argv[1], options, &option, "subcommand", JIM_ERRMSG) != JIM_OK)
-        return JIM_ERR;
-    if (option == OPT_REFCOUNT) {
-        if (argc != 3) {
-            Jim_WrongNumArgs(interp, 2, argv, "object");
-            return JIM_ERR;
-        }
-        Jim_SetResultInt(interp, argv[2]->refCount);
-        return JIM_OK;
-    }
-    else if (option == OPT_OBJCOUNT) {
-        int freeobj = 0, liveobj = 0;
-        char buf[256];
-        Jim_Obj *objPtr;
-
-        if (argc != 2) {
-            Jim_WrongNumArgs(interp, 2, argv, "");
-            return JIM_ERR;
-        }
-        /* Count the number of free objects. */
-        objPtr = interp->freeList;
-        while (objPtr) {
-            freeobj++;
-            objPtr = objPtr->nextObjPtr;
-        }
-        /* Count the number of live objects. */
-        objPtr = interp->liveList;
-        while (objPtr) {
-            liveobj++;
-            objPtr = objPtr->nextObjPtr;
-        }
-        /* Set the result string and return. */
-        sprintf(buf, "free %d used %d", freeobj, liveobj);
-        Jim_SetResultString(interp, buf, -1);
-        return JIM_OK;
-    }
-    else if (option == OPT_OBJECTS) {
-        Jim_Obj *objPtr, *listObjPtr, *subListObjPtr;
-
-        /* Count the number of live objects. */
-        objPtr = interp->liveList;
-        listObjPtr = Jim_NewListObj(interp, NULL, 0);
-        while (objPtr) {
-            char buf[128];
-            const char *type = objPtr->typePtr ? objPtr->typePtr->name : "";
-
-            subListObjPtr = Jim_NewListObj(interp, NULL, 0);
-            sprintf(buf, "%p", objPtr);
-            Jim_ListAppendElement(interp, subListObjPtr, Jim_NewStringObj(interp, buf, -1));
-            Jim_ListAppendElement(interp, subListObjPtr, Jim_NewStringObj(interp, type, -1));
-            Jim_ListAppendElement(interp, subListObjPtr, Jim_NewIntObj(interp, objPtr->refCount));
-            Jim_ListAppendElement(interp, subListObjPtr, objPtr);
-            Jim_ListAppendElement(interp, listObjPtr, subListObjPtr);
-            objPtr = objPtr->nextObjPtr;
-        }
-        Jim_SetResult(interp, listObjPtr);
-        return JIM_OK;
-    }
-    else if (option == OPT_INVSTR) {
-        Jim_Obj *objPtr;
-
-        if (argc != 3) {
-            Jim_WrongNumArgs(interp, 2, argv, "object");
-            return JIM_ERR;
-        }
-        objPtr = argv[2];
-        if (objPtr->typePtr != NULL)
-            Jim_InvalidateStringRep(objPtr);
-        Jim_SetEmptyResult(interp);
-        return JIM_OK;
-    }
-    else if (option == OPT_SHOW) {
-        const char *s;
-        int len, charlen;
-
-        if (argc != 3) {
-            Jim_WrongNumArgs(interp, 2, argv, "object");
-            return JIM_ERR;
-        }
-        s = Jim_GetString(argv[2], &len);
-        charlen = Jim_Utf8Length(interp, argv[2]);
-        printf("chars (%d): <<%s>>\n", charlen, s);
-        printf("bytes (%d):", len);
-        while (len--) {
-            printf(" %02x", (unsigned char)*s++);
-        }
-        printf("\n");
-        return JIM_OK;
-    }
-    else if (option == OPT_SCRIPTLEN) {
-        ScriptObj *script;
-
-        if (argc != 3) {
-            Jim_WrongNumArgs(interp, 2, argv, "script");
-            return JIM_ERR;
-        }
-        script = Jim_GetScript(interp, argv[2]);
-        Jim_SetResultInt(interp, script->len);
-        return JIM_OK;
-    }
-    else if (option == OPT_EXPRLEN) {
-        ExprByteCode *expr;
-
-        if (argc != 3) {
-            Jim_WrongNumArgs(interp, 2, argv, "expression");
-            return JIM_ERR;
-        }
-        expr = JimGetExpression(interp, argv[2]);
-        if (expr == NULL)
-            return JIM_ERR;
-        Jim_SetResultInt(interp, expr->len);
-        return JIM_OK;
-    }
-    else if (option == OPT_EXPRBC) {
-        Jim_Obj *objPtr;
-        ExprByteCode *expr;
-        int i;
-
-        if (argc != 3) {
-            Jim_WrongNumArgs(interp, 2, argv, "expression");
-            return JIM_ERR;
-        }
-        expr = JimGetExpression(interp, argv[2]);
-        if (expr == NULL)
-            return JIM_ERR;
-        objPtr = Jim_NewListObj(interp, NULL, 0);
-        for (i = 0; i < expr->len; i++) {
-            const char *type;
-            const Jim_ExprOperator *op;
-            Jim_Obj *obj = expr->token[i].objPtr;
-
-            switch (expr->token[i].type) {
-                case JIM_TT_EXPR_INT:
-                    type = "int";
-                    break;
-                case JIM_TT_EXPR_DOUBLE:
-                    type = "double";
-                    break;
-                case JIM_TT_CMD:
-                    type = "command";
-                    break;
-                case JIM_TT_VAR:
-                    type = "variable";
-                    break;
-                case JIM_TT_DICTSUGAR:
-                    type = "dictsugar";
-                    break;
-                case JIM_TT_EXPRSUGAR:
-                    type = "exprsugar";
-                    break;
-                case JIM_TT_ESC:
-                    type = "subst";
-                    break;
-                case JIM_TT_STR:
-                    type = "string";
-                    break;
-                default:
-                    op = JimExprOperatorInfoByOpcode(expr->token[i].type);
-                    if (op == NULL) {
-                        type = "private";
-                    }
-                    else {
-                        type = "operator";
-                    }
-                    obj = Jim_NewStringObj(interp, op ? op->name : "", -1);
-                    break;
-            }
-            Jim_ListAppendElement(interp, objPtr, Jim_NewStringObj(interp, type, -1));
-            Jim_ListAppendElement(interp, objPtr, obj);
-        }
-        Jim_SetResult(interp, objPtr);
-        return JIM_OK;
-    }
-    else {
-        Jim_SetResultString(interp,
-            "bad option. Valid options are refcount, " "objcount, objects, invstr", -1);
-        return JIM_ERR;
-    }
-    /* unreached */
-#else
+#if !defined(JIM_DEBUG_COMMAND)
     Jim_SetResultString(interp, "unsupported", -1);
     return JIM_ERR;
 #endif
 }
 
-/* [eval] */
+
 static int Jim_EvalCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
 {
     int rc;
 
     if (argc < 2) {
@@ -18699,29 +16352,29 @@
     else {
         rc = Jim_EvalObj(interp, Jim_ConcatObj(interp, argc - 1, argv + 1));
     }
 
     if (rc == JIM_ERR) {
-        /* eval is "interesting", so add a stack frame here */
+        
         interp->addStackTrace++;
     }
     return rc;
 }
 
-/* [uplevel] */
+
 static int Jim_UplevelCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
 {
     if (argc >= 2) {
         int retcode;
         Jim_CallFrame *savedCallFrame, *targetCallFrame;
         Jim_Obj *objPtr;
         const char *str;
 
-        /* Save the old callframe pointer */
+        
         savedCallFrame = interp->framePtr;
 
-        /* Lookup the target frame pointer */
+        
         str = Jim_String(argv[1]);
         if ((str[0] >= '0' && str[0] <= '9') || str[0] == '#') {
             targetCallFrame =Jim_GetCallFrameByLevel(interp, argv[1]);
             argc--;
             argv++;
@@ -18735,11 +16388,11 @@
         if (argc < 2) {
             argv--;
             Jim_WrongNumArgs(interp, 1, argv, "?level? command ?arg ...?");
             return JIM_ERR;
         }
-        /* Eval the code in the target callframe. */
+        
         interp->framePtr = targetCallFrame;
         if (argc == 2) {
             retcode = Jim_EvalObj(interp, argv[1]);
         }
         else {
@@ -18755,11 +16408,11 @@
         Jim_WrongNumArgs(interp, 1, argv, "?level? command ?arg ...?");
         return JIM_ERR;
     }
 }
 
-/* [expr] */
+
 static int Jim_ExprCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
 {
     Jim_Obj *exprResultPtr;
     int retcode;
 
@@ -18783,31 +16436,31 @@
     Jim_SetResult(interp, exprResultPtr);
     Jim_DecrRefCount(interp, exprResultPtr);
     return JIM_OK;
 }
 
-/* [break] */
+
 static int Jim_BreakCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
 {
     if (argc != 1) {
         Jim_WrongNumArgs(interp, 1, argv, "");
         return JIM_ERR;
     }
     return JIM_BREAK;
 }
 
-/* [continue] */
+
 static int Jim_ContinueCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
 {
     if (argc != 1) {
         Jim_WrongNumArgs(interp, 1, argv, "");
         return JIM_ERR;
     }
     return JIM_CONTINUE;
 }
 
-/* [return] */
+
 static int Jim_ReturnCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
 {
     int i;
     Jim_Obj *stackTraceObj = NULL;
     Jim_Obj *errorCodeObj = NULL;
@@ -18840,15 +16493,15 @@
     if (i != argc - 1 && i != argc) {
         Jim_WrongNumArgs(interp, 1, argv,
             "?-code code? ?-errorinfo stacktrace? ?-level level? ?result?");
     }
 
-    /* If a stack trace is supplied and code is error, set the stack trace */
+    
     if (stackTraceObj && returnCode == JIM_ERR) {
         JimSetStackTrace(interp, stackTraceObj);
     }
-    /* If an error code list is supplied, set the global $errorCode */
+    
     if (errorCodeObj && returnCode == JIM_ERR) {
         Jim_SetGlobalVariableStr(interp, "errorCode", errorCodeObj);
     }
     interp->returnCode = returnCode;
     interp->returnLevel = level;
@@ -18857,21 +16510,21 @@
         Jim_SetResult(interp, argv[i]);
     }
     return JIM_RETURN;
 }
 
-/* [tailcall] */
+
 static int Jim_TailcallCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
 {
     Jim_Obj *objPtr;
 
     objPtr = Jim_NewListObj(interp, argv + 1, argc - 1);
     Jim_SetResult(interp, objPtr);
     return JIM_EVAL;
 }
 
-/* [proc] */
+
 static int Jim_ProcCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
 {
     if (argc != 4 && argc != 5) {
         Jim_WrongNumArgs(interp, 1, argv, "name arglist ?statics? body");
         return JIM_ERR;
@@ -18883,22 +16536,22 @@
     else {
         return JimCreateProcedure(interp, argv[1], argv[2], argv[3], argv[4]);
     }
 }
 
-/* [local] */
+
 static int Jim_LocalCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
 {
     int retcode;
 
-    /* Evaluate the arguments with 'local' in force */
+    
     interp->local++;
     retcode = Jim_EvalObjVector(interp, argc - 1, argv + 1);
     interp->local--;
 
 
-    /* If OK, and the result is a proc, add it to the list of local procs */
+    
     if (retcode == 0) {
         const char *procname = Jim_String(Jim_GetResult(interp));
 
         if (Jim_FindHashEntry(&interp->commands, procname) == NULL) {
             Jim_SetResultFormatted(interp, "not a proc: \"%s\"", procname);
@@ -18912,11 +16565,11 @@
     }
 
     return retcode;
 }
 
-/* [upcall] */
+
 static int Jim_UpcallCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
 {
     if (argc < 2) {
         Jim_WrongNumArgs(interp, 1, argv, "cmd ?args ...?");
         return JIM_ERR;
@@ -18927,39 +16580,39 @@
         Jim_Cmd *cmdPtr = Jim_GetCommand(interp, argv[1], JIM_ERRMSG);
         if (cmdPtr == NULL || !cmdPtr->isproc || !cmdPtr->u.proc.prevCmd) {
             Jim_SetResultFormatted(interp, "no previous proc: \"%#s\"", argv[1]);
             return JIM_ERR;
         }
-        /* OK. Mark this command as being in an upcall */
+        
         cmdPtr->u.proc.upcall++;
         JimIncrCmdRefCount(cmdPtr);
 
-        /* Invoke the command as normal */
+        
         retcode = Jim_EvalObjVector(interp, argc - 1, argv + 1);
 
-        /* No longer in an upcall */
+        
         cmdPtr->u.proc.upcall--;
         JimDecrCmdRefCount(interp, cmdPtr);
 
         return retcode;
     }
 }
 
-/* [concat] */
+
 static int Jim_ConcatCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
 {
     Jim_SetResult(interp, Jim_ConcatObj(interp, argc - 1, argv + 1));
     return JIM_OK;
 }
 
-/* [upvar] */
+
 static int Jim_UpvarCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
 {
     int i;
     Jim_CallFrame *targetCallFrame;
 
-    /* Lookup the target frame pointer */
+    
     if (argc > 3 && (argc % 2 == 0)) {
         targetCallFrame = Jim_GetCallFrameByLevel(interp, argv[1]);
         argc--;
         argv++;
     }
@@ -18968,46 +16621,43 @@
     }
     if (targetCallFrame == NULL) {
         return JIM_ERR;
     }
 
-    /* Check for arity */
+    
     if (argc < 3) {
         Jim_WrongNumArgs(interp, 1, argv, "?level? otherVar localVar ?otherVar localVar ...?");
         return JIM_ERR;
     }
 
-    /* Now... for every other/local couple: */
+    
     for (i = 1; i < argc; i += 2) {
         if (Jim_SetVariableLink(interp, argv[i + 1], argv[i], targetCallFrame) != JIM_OK)
             return JIM_ERR;
     }
     return JIM_OK;
 }
 
-/* [global] */
+
 static int Jim_GlobalCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
 {
     int i;
 
     if (argc < 2) {
         Jim_WrongNumArgs(interp, 1, argv, "varName ?varName ...?");
         return JIM_ERR;
     }
-    /* Link every var to the toplevel having the same name */
+    
     if (interp->framePtr->level == 0)
-        return JIM_OK;          /* global at toplevel... */
+        return JIM_OK;          
     for (i = 1; i < argc; i++) {
         if (Jim_SetVariableLink(interp, argv[i], argv[i], interp->topFramePtr) != JIM_OK)
             return JIM_ERR;
     }
     return JIM_OK;
 }
 
-/* does the [string map] operation. On error NULL is returned,
- * otherwise a new string object with the result, having refcount = 0,
- * is returned. */
 static Jim_Obj *JimStringMap(Jim_Interp *interp, Jim_Obj *mapListObjPtr,
     Jim_Obj *objPtr, int nocase)
 {
     int numMaps;
     const char *str, *noMatchStart = NULL;
@@ -19021,11 +16671,11 @@
     }
 
     str = Jim_String(objPtr);
     strLen = Jim_Utf8Length(interp, objPtr);
 
-    /* Map it */
+    
     resultObjPtr = Jim_NewStringObj(interp, "", 0);
     while (strLen) {
         for (i = 0; i < numMaps; i += 2) {
             Jim_Obj *objPtr;
             const char *k;
@@ -19054,11 +16704,11 @@
                     strLen -= kl;
                     break;
                 }
             }
         }
-        if (i == numMaps) {     /* no match */
+        if (i == numMaps) {     
             int c;
             if (noMatchStart == NULL)
                 noMatchStart = str;
             str += utf8_tounicode(str, &c);
             strLen--;
@@ -19068,11 +16718,11 @@
         Jim_AppendString(interp, resultObjPtr, noMatchStart, str - noMatchStart);
     }
     return resultObjPtr;
 }
 
-/* [string] */
+
 static int Jim_StringCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
 {
     int len;
     int opt_case = 1;
     int option;
@@ -19225,14 +16875,10 @@
                     Jim_WrongNumArgs(interp, 2, argv, "string");
                     return JIM_ERR;
                 }
 
                 str = Jim_GetString(argv[2], &len);
-                if (!str) {
-                    return JIM_ERR;
-                }
-
                 buf = Jim_Alloc(len + 1);
                 p = buf + len;
                 *p = 0;
                 for (i = 0; i < len; ) {
                     int c;
@@ -19264,11 +16910,11 @@
                 }
                 if (idx < 0 || idx >= len || str == NULL) {
                     Jim_SetResultString(interp, "", 0);
                 }
                 else if (len == Jim_Length(argv[2])) {
-                    /* ASCII optimisation */
+                    
                     Jim_SetResultString(interp, str + idx, 1);
                 }
                 else {
                     int c;
                     int i = utf8_index(str, idx);
@@ -19356,11 +17002,11 @@
             return JIM_ERR;
     }
     return JIM_OK;
 }
 
-/* [time] */
+
 static int Jim_TimeCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
 {
     long i, count = 1;
     jim_wide start, elapsed;
     char buf[60];
@@ -19390,11 +17036,11 @@
     sprintf(buf, fmt, count == 0 ? 0 : elapsed / count);
     Jim_SetResultString(interp, buf, -1);
     return JIM_OK;
 }
 
-/* [exit] */
+
 static int Jim_ExitCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
 {
     long exitCode = 0;
 
     if (argc > 2) {
@@ -19407,32 +17053,29 @@
     }
     interp->exitCode = exitCode;
     return JIM_EXIT;
 }
 
-/* [catch] */
+
 static int Jim_CatchCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
 {
     int exitCode = 0;
     int i;
     int sig = 0;
 
-    /* Which return codes are caught? These are the defaults */
-    jim_wide mask =
-        (1 << JIM_OK | 1 << JIM_ERR | 1 << JIM_BREAK | 1 << JIM_CONTINUE | 1 << JIM_RETURN);
+    
+    jim_wide ignore_mask = (1 << JIM_EXIT) | (1 << JIM_EVAL) | (1 << JIM_SIGNAL);
+    static const int max_ignore_code = sizeof(ignore_mask) * 8;
 
-    /* Reset the error code before catch.
-     * Note that this is not strictly correct.
-     */
     Jim_SetGlobalVariableStr(interp, "errorCode", Jim_NewStringObj(interp, "NONE", -1));
 
     for (i = 1; i < argc - 1; i++) {
         const char *arg = Jim_String(argv[i]);
         jim_wide option;
-        int add;
+        int ignore;
 
-        /* It's a pity we can't use Jim_GetEnum here :-( */
+        
         if (strcmp(arg, "--") == 0) {
             i++;
             break;
         }
         if (*arg != '-') {
@@ -19439,15 +17082,15 @@
             break;
         }
 
         if (strncmp(arg, "-no", 3) == 0) {
             arg += 3;
-            add = 0;
+            ignore = 1;
         }
         else {
             arg++;
-            add = 1;
+            ignore = 0;
         }
 
         if (Jim_StringToWide(arg, &option, 10) != JIM_OK) {
             option = -1;
         }
@@ -19456,15 +17099,15 @@
         }
         if (option < 0) {
             goto wrongargs;
         }
 
-        if (add) {
-            mask |= (1 << option);
+        if (ignore) {
+            ignore_mask |= (1 << option);
         }
         else {
-            mask &= ~(1 << option);
+            ignore_mask &= ~(1 << option);
         }
     }
 
     argc -= i;
     if (argc < 1 || argc > 3) {
@@ -19473,32 +17116,32 @@
             "?-?no?code ... --? script ?resultVarName? ?optionVarName?");
         return JIM_ERR;
     }
     argv += i;
 
-    if (mask & (1 << JIM_SIGNAL)) {
+    if ((ignore_mask & (1 << JIM_SIGNAL)) == 0) {
         sig++;
     }
 
     interp->signal_level += sig;
     if (interp->signal_level && interp->sigmask) {
-        /* If a signal is set, don't even try to execute the body */
+        
         exitCode = JIM_SIGNAL;
     }
     else {
         exitCode = Jim_EvalObj(interp, argv[0]);
     }
     interp->signal_level -= sig;
 
-    /* Catch or pass through? Only the first 32/64 codes can be passed through */
-    if (exitCode >= 0 && exitCode < (int)sizeof(mask) * 8 && ((1 << exitCode) & mask) == 0) {
-        /* Not caught, pass it up */
+    
+    if (exitCode >= 0 && exitCode < max_ignore_code && ((1 << exitCode) & ignore_mask)) {
+        
         return exitCode;
     }
 
     if (sig && exitCode == JIM_SIGNAL) {
-        /* Catch the signal at this level */
+        
         if (interp->signal_set_result) {
             interp->signal_set_result(interp, interp->sigmask);
         }
         else {
             Jim_SetResultInt(interp, interp->sigmask);
@@ -19539,11 +17182,11 @@
     return JIM_OK;
 }
 
 #ifdef JIM_REFERENCES
 
-/* [ref] */
+
 static int Jim_RefCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
 {
     if (argc != 3 && argc != 4) {
         Jim_WrongNumArgs(interp, 1, argv, "string tag ?finalizer?");
         return JIM_ERR;
@@ -19555,11 +17198,11 @@
         Jim_SetResult(interp, Jim_NewReference(interp, argv[1], argv[2], argv[3]));
     }
     return JIM_OK;
 }
 
-/* [getref] */
+
 static int Jim_GetrefCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
 {
     Jim_Reference *refPtr;
 
     if (argc != 2) {
@@ -19570,11 +17213,11 @@
         return JIM_ERR;
     Jim_SetResult(interp, refPtr->objPtr);
     return JIM_OK;
 }
 
-/* [setref] */
+
 static int Jim_SetrefCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
 {
     Jim_Reference *refPtr;
 
     if (argc != 3) {
@@ -19588,30 +17231,30 @@
     refPtr->objPtr = argv[2];
     Jim_SetResult(interp, argv[2]);
     return JIM_OK;
 }
 
-/* [collect] */
+
 static int Jim_CollectCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
 {
     if (argc != 1) {
         Jim_WrongNumArgs(interp, 1, argv, "");
         return JIM_ERR;
     }
     Jim_SetResultInt(interp, Jim_Collect(interp));
 
-    /* Free all the freed objects. */
+    
     while (interp->freeList) {
         Jim_Obj *nextObjPtr = interp->freeList->nextObjPtr;
         Jim_Free(interp->freeList);
         interp->freeList = nextObjPtr;
     }
 
     return JIM_OK;
 }
 
-/* [finalize] reference ?newValue? */
+
 static int Jim_FinalizeCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
 {
     if (argc != 2 && argc != 3) {
         Jim_WrongNumArgs(interp, 1, argv, "reference ?finalizerProc?");
         return JIM_ERR;
@@ -19619,11 +17262,11 @@
     if (argc == 2) {
         Jim_Obj *cmdNamePtr;
 
         if (Jim_GetFinalizer(interp, argv[1], &cmdNamePtr) != JIM_OK)
             return JIM_ERR;
-        if (cmdNamePtr != NULL) /* otherwise the null string is returned. */
+        if (cmdNamePtr != NULL) 
             Jim_SetResult(interp, cmdNamePtr);
     }
     else {
         if (Jim_SetFinalizer(interp, argv[1], argv[2]) != JIM_OK)
             return JIM_ERR;
@@ -19630,11 +17273,11 @@
         Jim_SetResult(interp, argv[2]);
     }
     return JIM_OK;
 }
 
-/* [info references] */
+
 static int JimInfoReferences(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
 {
     Jim_Obj *listObjPtr;
     Jim_HashTableIterator *htiter;
     Jim_HashEntry *he;
@@ -19654,11 +17297,11 @@
     Jim_SetResult(interp, listObjPtr);
     return JIM_OK;
 }
 #endif
 
-/* [rename] */
+
 static int Jim_RenameCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
 {
     const char *oldName, *newName;
 
     if (argc != 3) {
@@ -19685,18 +17328,15 @@
 
     if (Jim_DictKeysVector(interp, objPtr, NULL, 0, &dictObj, JIM_ERRMSG) != JIM_OK) {
         return JIM_ERR;
     }
 
-    /* XXX: Could make the exact-match case much more efficient here.
-     *      See JimCommandsList()
-     */
     if (Jim_DictPairs(interp, dictObj, &dictValuesObj, &len) != JIM_OK) {
         return JIM_ERR;
     }
 
-    /* Only return the matching values */
+    
     resultObj = Jim_NewListObj(interp, NULL, 0);
 
     for (i = 0; i < len; i += 2) {
         if (patternObj == NULL || Jim_StringMatchObj(interp, patternObj, dictValuesObj[i], 0)) {
             Jim_ListAppendElement(interp, resultObj, dictValuesObj[i]);
@@ -19714,11 +17354,11 @@
         return -1;
     }
     return ((Jim_HashTable *)objPtr->internalRep.ptr)->used;
 }
 
-/* [dict] */
+
 static int Jim_DictCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
 {
     Jim_Obj *objPtr;
     int option;
     static const char * const options[] = {
@@ -19754,11 +17394,11 @@
         case OPT_SET:
             if (argc < 5) {
                 Jim_WrongNumArgs(interp, 2, argv, "varName key ?key ...? value");
                 return JIM_ERR;
             }
-            return Jim_SetDictKeysVector(interp, argv[2], argv + 3, argc - 4, argv[argc - 1]);
+            return Jim_SetDictKeysVector(interp, argv[2], argv + 3, argc - 4, argv[argc - 1], JIM_ERRMSG);
 
         case OPT_EXIST:
             if (argc < 3) {
                 Jim_WrongNumArgs(interp, 2, argv, "varName ?key ...?");
                 return JIM_ERR;
@@ -19770,11 +17410,11 @@
         case OPT_UNSET:
             if (argc < 4) {
                 Jim_WrongNumArgs(interp, 2, argv, "varName key ?key ...?");
                 return JIM_ERR;
             }
-            return Jim_SetDictKeysVector(interp, argv[2], argv + 3, argc - 3, NULL);
+            return Jim_SetDictKeysVector(interp, argv[2], argv + 3, argc - 3, NULL, JIM_NONE);
 
         case OPT_KEYS:
             if (argc != 3 && argc != 4) {
                 Jim_WrongNumArgs(interp, 2, argv, "dictVar ?pattern?");
                 return JIM_ERR;
@@ -19803,11 +17443,11 @@
             }
             else if (argv[2]->typePtr != &dictObjType && SetDictFromAny(interp, argv[2]) != JIM_OK) {
                 return JIM_ERR;
             }
             else {
-                return Jim_EvalObjPrefix(interp, "dict merge", argc - 2, argv + 2);
+                return Jim_EvalPrefix(interp, "dict merge", argc - 2, argv + 2);
             }
 
         case OPT_WITH:
             if (argc < 4) {
                 Jim_WrongNumArgs(interp, 2, argv, "dictVar ?key ...? script");
@@ -19815,11 +17455,11 @@
             }
             else if (Jim_GetVariable(interp, argv[2], JIM_ERRMSG) == NULL) {
                 return JIM_ERR;
             }
             else {
-                return Jim_EvalObjPrefix(interp, "dict with", argc - 2, argv + 2);
+                return Jim_EvalPrefix(interp, "dict with", argc - 2, argv + 2);
             }
 
         case OPT_CREATE:
             if (argc % 2) {
                 Jim_WrongNumArgs(interp, 2, argv, "?key value ...?");
@@ -19826,17 +17466,15 @@
                 return JIM_ERR;
             }
             objPtr = Jim_NewDictObj(interp, argv + 2, argc - 2);
             Jim_SetResult(interp, objPtr);
             return JIM_OK;
-
-        default:
-            abort();
     }
+    return JIM_ERR;
 }
 
-/* [subst] */
+
 static int Jim_SubstCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
 {
     static const char * const options[] = {
         "-nobackslashes", "-nocommands", "-novariables", NULL
     };
@@ -19874,11 +17512,11 @@
     }
     Jim_SetResult(interp, objPtr);
     return JIM_OK;
 }
 
-/* [info] */
+
 static int Jim_InfoCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
 {
     int cmd;
     Jim_Obj *objPtr;
     int mode = 0;
@@ -19903,11 +17541,11 @@
     if (Jim_GetEnum(interp, argv[1], commands, &cmd, "subcommand", JIM_ERRMSG | JIM_ENUM_ABBREV)
         != JIM_OK) {
         return JIM_ERR;
     }
 
-    /* Test for the the most common commands first, just in case it makes a difference */
+    
     switch (cmd) {
         case INFO_EXISTS:{
                 if (argc != 3) {
                     Jim_WrongNumArgs(interp, 2, argv, "varName");
                     return JIM_ERR;
@@ -19930,15 +17568,15 @@
             Jim_SetResult(interp, JimCommandsList(interp, (argc == 3) ? argv[2] : NULL,
                     (cmd - INFO_COMMANDS)));
             break;
 
         case INFO_VARS:
-            mode++;             /* JIM_VARLIST_VARS */
+            mode++;             
         case INFO_LOCALS:
-            mode++;             /* JIM_VARLIST_LOCALS */
+            mode++;             
         case INFO_GLOBALS:
-            /* mode 0 => JIM_VARLIST_GLOBALS */
+            
             if (argc != 2 && argc != 3) {
                 Jim_WrongNumArgs(interp, 2, argv, "?pattern?");
                 return JIM_ERR;
             }
             Jim_SetResult(interp, JimVariablesList(interp, argc == 3 ? argv[2] : NULL, mode));
@@ -19947,34 +17585,37 @@
         case INFO_SCRIPT:
             if (argc != 2) {
                 Jim_WrongNumArgs(interp, 2, argv, "");
                 return JIM_ERR;
             }
-            Jim_SetResultString(interp, Jim_GetScript(interp, interp->currentScriptObj)->fileName,
-                -1);
+            Jim_SetResult(interp, Jim_GetScript(interp, interp->currentScriptObj)->fileNameObj);
             break;
 
         case INFO_SOURCE:{
-                const char *filename = "";
-                int line = 0;
+                int line;
                 Jim_Obj *resObjPtr;
+                Jim_Obj *fileNameObj;
 
                 if (argc != 3) {
                     Jim_WrongNumArgs(interp, 2, argv, "source");
                     return JIM_ERR;
                 }
                 if (argv[2]->typePtr == &sourceObjType) {
-                    filename = argv[2]->internalRep.sourceValue.fileName;
+                    fileNameObj = argv[2]->internalRep.sourceValue.fileNameObj;
                     line = argv[2]->internalRep.sourceValue.lineNumber;
                 }
                 else if (argv[2]->typePtr == &scriptObjType) {
                     ScriptObj *script = Jim_GetScript(interp, argv[2]);
-                    filename = script->fileName;
+                    fileNameObj = script->fileNameObj;
                     line = script->line;
                 }
+                else {
+                    fileNameObj = interp->emptyObj;
+                    line = 1;
+                }
                 resObjPtr = Jim_NewListObj(interp, NULL, 0);
-                Jim_ListAppendElement(interp, resObjPtr, Jim_NewStringObj(interp, filename, -1));
+                Jim_ListAppendElement(interp, resObjPtr, fileNameObj);
                 Jim_ListAppendElement(interp, resObjPtr, Jim_NewIntObj(interp, line));
                 Jim_SetResult(interp, resObjPtr);
                 break;
             }
 
@@ -20047,15 +17688,15 @@
                 }
             }
             break;
 
         case INFO_HOSTNAME:
-            /* Redirect to os.gethostname if it exists */
+            
             return Jim_Eval(interp, "os.gethostname");
 
         case INFO_NAMEOFEXECUTABLE:
-            /* Redirect to Tcl proc */
+            
             return Jim_Eval(interp, "{info nameofexecutable}");
 
         case INFO_RETURNCODES:
             if (argc == 2) {
                 int i;
@@ -20098,11 +17739,11 @@
 #endif
     }
     return JIM_OK;
 }
 
-/* [exists] */
+
 static int Jim_ExistsCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
 {
     Jim_Obj *objPtr;
 
     static const char * const options[] = {
@@ -20127,11 +17768,11 @@
     else {
         Jim_WrongNumArgs(interp, 1, argv, "?option? name");
         return JIM_ERR;
     }
 
-    /* Test for the the most common commands first, just in case it makes a difference */
+    
     switch (option) {
         case OPT_VAR:
             Jim_SetResultBool(interp, Jim_GetVariable(interp, objPtr, 0) != NULL);
             break;
 
@@ -20143,11 +17784,11 @@
         }
     }
     return JIM_OK;
 }
 
-/* [split] */
+
 static int Jim_SplitCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
 {
     const char *str, *splitChars, *noMatchStart;
     int splitLen, strLen;
     Jim_Obj *resObjPtr;
@@ -20163,11 +17804,11 @@
     if (len == 0) {
         return JIM_OK;
     }
     strLen = Jim_Utf8Length(interp, argv[1]);
 
-    /* Init */
+    
     if (argc == 2) {
         splitChars = " \n\t\r";
         splitLen = 4;
     }
     else {
@@ -20176,11 +17817,11 @@
     }
 
     noMatchStart = str;
     resObjPtr = Jim_NewListObj(interp, NULL, 0);
 
-    /* Split */
+    
     if (splitLen) {
         Jim_Obj *objPtr;
         while (strLen--) {
             const char *sc = splitChars;
             int scLen = splitLen;
@@ -20199,20 +17840,17 @@
         }
         objPtr = Jim_NewStringObj(interp, noMatchStart, (str - noMatchStart));
         Jim_ListAppendElement(interp, resObjPtr, objPtr);
     }
     else {
-        /* This handles the special case of splitchars eq {}
-         * Optimise by sharing common (ASCII) characters
-         */
         Jim_Obj **commonObj = NULL;
 #define NUM_COMMON (128 - 9)
         while (strLen--) {
             int n = utf8_tounicode(str, &c);
 #ifdef JIM_OPTIMIZATION
             if (c >= 9 && c < 128) {
-                /* Common ASCII char. Note that 9 is the tab character */
+                
                 c -= 9;
                 if (!commonObj) {
                     commonObj = Jim_Alloc(sizeof(*commonObj) * NUM_COMMON);
                     memset(commonObj, 0, sizeof(*commonObj) * NUM_COMMON);
                 }
@@ -20232,11 +17870,11 @@
 
     Jim_SetResult(interp, resObjPtr);
     return JIM_OK;
 }
 
-/* [join] */
+
 static int Jim_JoinCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
 {
     const char *joinStr;
     int joinStrLen, i, listLen;
     Jim_Obj *resObjPtr;
@@ -20243,21 +17881,21 @@
 
     if (argc != 2 && argc != 3) {
         Jim_WrongNumArgs(interp, 1, argv, "list ?joinString?");
         return JIM_ERR;
     }
-    /* Init */
+    
     if (argc == 2) {
         joinStr = " ";
         joinStrLen = 1;
     }
     else {
         joinStr = Jim_GetString(argv[2], &joinStrLen);
     }
     listLen = Jim_ListLength(interp, argv[1]);
     resObjPtr = Jim_NewStringObj(interp, NULL, 0);
-    /* Split */
+    
     for (i = 0; i < listLen; i++) {
         Jim_Obj *objPtr = 0;
 
         Jim_ListIndex(interp, argv[1], i, &objPtr, JIM_NONE);
         Jim_AppendObj(interp, resObjPtr, objPtr);
@@ -20267,11 +17905,11 @@
     }
     Jim_SetResult(interp, resObjPtr);
     return JIM_OK;
 }
 
-/* [format] */
+
 static int Jim_FormatCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
 {
     Jim_Obj *objPtr;
 
     if (argc < 2) {
@@ -20283,11 +17921,11 @@
         return JIM_ERR;
     Jim_SetResult(interp, objPtr);
     return JIM_OK;
 }
 
-/* [scan] */
+
 static int Jim_ScanCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
 {
     Jim_Obj *listPtr, **outVec;
     int outc, i;
 
@@ -20359,11 +17997,11 @@
         Jim_SetResult(interp, listPtr);
     }
     return JIM_OK;
 }
 
-/* [error] */
+
 static int Jim_ErrorCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
 {
     if (argc != 2 && argc != 3) {
         Jim_WrongNumArgs(interp, 1, argv, "message ?stacktrace?");
         return JIM_ERR;
@@ -20375,11 +18013,11 @@
     }
     interp->addStackTrace++;
     return JIM_ERR;
 }
 
-/* [lrange] */
+
 static int Jim_LrangeCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
 {
     Jim_Obj *objPtr;
 
     if (argc != 4) {
@@ -20390,11 +18028,11 @@
         return JIM_ERR;
     Jim_SetResult(interp, objPtr);
     return JIM_OK;
 }
 
-/* [lrepeat] */
+
 static int Jim_LrepeatCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
 {
     Jim_Obj *objPtr;
     long count;
 
@@ -20410,15 +18048,11 @@
     argc -= 2;
     argv += 2;
 
     objPtr = Jim_NewListObj(interp, argv, argc);
     while (--count) {
-        int i;
-
-        for (i = 0; i < argc; i++) {
-            ListAppendElement(objPtr, argv[i]);
-        }
+        ListInsertElements(objPtr, -1, argc, argv);
     }
 
     Jim_SetResult(interp, objPtr);
     return JIM_OK;
 }
@@ -20447,11 +18081,11 @@
 
     environ = env;
 #endif
 }
 
-/* [env] */
+
 static int Jim_EnvCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
 {
     const char *key;
     const char *val;
 
@@ -20490,11 +18124,11 @@
     }
     Jim_SetResult(interp, Jim_NewStringObj(interp, val, -1));
     return JIM_OK;
 }
 
-/* [source] */
+
 static int Jim_SourceCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
 {
     int retval;
 
     if (argc != 2) {
@@ -20505,11 +18139,11 @@
     if (retval == JIM_RETURN)
         return JIM_OK;
     return retval;
 }
 
-/* [lreverse] */
+
 static int Jim_LreverseCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
 {
     Jim_Obj *revObjPtr, **ele;
     int len;
 
@@ -20538,23 +18172,20 @@
         return -1;
     else if (step < 0 && end > start)
         return -1;
     len = end - start;
     if (len < 0)
-        len = -len;             /* abs(len) */
+        len = -len;             
     if (step < 0)
-        step = -step;           /* abs(step) */
+        step = -step;           
     len = 1 + ((len - 1) / step);
-    /* We can truncate safely to INT_MAX, the range command
-     * will always return an error for a such long range
-     * because Tcl lists can't be so long. */
     if (len > INT_MAX)
         len = INT_MAX;
     return (int)((len < 0) ? -1 : len);
 }
 
-/* [range] */
+
 static int Jim_RangeCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
 {
     jim_wide start = 0, end, step = 1;
     int len, i;
     Jim_Obj *objPtr;
@@ -20583,11 +18214,11 @@
         ListAppendElement(objPtr, Jim_NewIntObj(interp, start + i * step));
     Jim_SetResult(interp, objPtr);
     return JIM_OK;
 }
 
-/* [rand] */
+
 static int Jim_RandCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
 {
     jim_wide min = 0, max = 0, len, maxMul;
 
     if (argc < 1 || argc > 3) {
@@ -20704,13 +18335,10 @@
             Jim_CoreCommandsTable[i].name, Jim_CoreCommandsTable[i].cmdProc, NULL, NULL);
         i++;
     }
 }
 
-/* -----------------------------------------------------------------------------
- * Interactive prompt
- * ---------------------------------------------------------------------------*/
 void Jim_MakeErrorMessage(Jim_Interp *interp)
 {
     Jim_Obj *argv[2];
 
     argv[0] = Jim_NewStringObj(interp, "errorInfo", -1);
@@ -20761,18 +18389,15 @@
 
     *indexPtr = -1;
 
     for (entryPtr = tablePtr, i = 0; *entryPtr != NULL; entryPtr++, i++) {
         if (Jim_CompareStringImmediate(interp, objPtr, *entryPtr)) {
-            /* Found an exact match */
+            
             *indexPtr = i;
             return JIM_OK;
         }
         if (flags & JIM_ENUM_ABBREV) {
-            /* Accept an unambiguous abbreviation.
-             * Note that '-' doesnt' consitute a valid abbreviation
-             */
             if (strncmp(arg, *entryPtr, arglen) == 0) {
                 if (*arg == '-' && arglen == 1) {
                     break;
                 }
                 if (match >= 0) {
@@ -20782,11 +18407,11 @@
                 match = i;
             }
         }
     }
 
-    /* If we had an unambiguous partial match */
+    
     if (match >= 0) {
         *indexPtr = match;
         return JIM_OK;
     }
 
@@ -20817,27 +18442,13 @@
 int Jim_IsList(Jim_Obj *objPtr)
 {
     return objPtr->typePtr == &listObjType;
 }
 
-/**
- * Very simple printf-like formatting, designed for error messages.
- *
- * The format may contain up to 5 '%s' or '%#s', corresponding to variable arguments.
- * The resulting string is created and set as the result.
- *
- * Each '%s' should correspond to a regular string parameter.
- * Each '%#s' should correspond to a (Jim_Obj *) parameter.
- * Any other printf specifier is not allowed (but %% is allowed for the % character).
- *
- * e.g. Jim_SetResultFormatted(interp, "Bad option \"%#s\" in proc \"%#s\"", optionObjPtr, procNamePtr);
- *
- * Note: We take advantage of the fact that printf has the same behaviour for both %s and %#s
- */
 void Jim_SetResultFormatted(Jim_Interp *interp, const char *format, ...)
 {
-    /* Initial space needed */
+    
     int len = strlen(format);
     int extra = 0;
     int n = 0;
     const char *params[5];
     char *buf;
@@ -20874,11 +18485,11 @@
     len = snprintf(buf, len + 1, format, params[0], params[1], params[2], params[3], params[4]);
 
     Jim_SetResult(interp, Jim_NewStringObjNoAlloc(interp, buf, len));
 }
 
-/* stubs */
+
 #ifndef jim_ext_package
 int Jim_PackageProvide(Jim_Interp *interp, const char *name, const char *ver, int flags)
 {
     return JIM_OK;
 }
@@ -20890,36 +18501,22 @@
     return NULL;
 }
 #endif
 
 
-/*
- * Local Variables: ***
- * c-basic-offset: 4 ***
- * tab-width: 4 ***
- * End: ***
- */
 #include <stdio.h>
 #include <string.h>
 
 
-/**
- * Implements the common 'commands' subcommand
- */
 static int subcmd_null(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
 {
-    /* Nothing to do, since the result has already been created */
+    
     return JIM_OK;
 }
 
-/**
- * Do-nothing command to support -commands and -usage
- */
 static const jim_subcmd_type dummy_subcmd = {
-    .cmd = "dummy",
-    .function = subcmd_null,
-    .flags = JIM_MODFLAG_HIDDEN,
+    "dummy", NULL, subcmd_null, 0, 0, JIM_MODFLAG_HIDDEN
 };
 
 static void add_commands(Jim_Interp *interp, const jim_subcmd_type * ct, const char *sep)
 {
     const char *s = "";
@@ -20959,26 +18556,10 @@
     if (ct->args && *ct->args) {
         Jim_AppendStrings(interp, Jim_GetResult(interp), " ", ct->args, NULL);
     }
 }
 
-static void show_full_usage(Jim_Interp *interp, const jim_subcmd_type * ct, int argc,
-    Jim_Obj *const *argv)
-{
-    Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
-    for (; ct->cmd; ct++) {
-        if (!(ct->flags & JIM_MODFLAG_HIDDEN)) {
-            /* subcmd */
-            add_cmd_usage(interp, ct, argv[0]);
-            if (ct->description) {
-                Jim_AppendStrings(interp, Jim_GetResult(interp), "\n\n    ", ct->description, NULL);
-            }
-            Jim_AppendStrings(interp, Jim_GetResult(interp), "\n\n", NULL);
-        }
-    }
-}
-
 static void set_wrong_args(Jim_Interp *interp, const jim_subcmd_type * command_table, Jim_Obj *subcmd)
 {
     Jim_SetResultString(interp, "wrong # args: must be \"", -1);
     add_cmd_usage(interp, command_table, subcmd);
     Jim_AppendStrings(interp, Jim_GetResult(interp), "\"", NULL);
@@ -20999,56 +18580,49 @@
 
     if (argc < 2) {
         Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
         Jim_AppendStrings(interp, Jim_GetResult(interp), "wrong # args: should be \"", cmdname,
             " command ...\"\n", NULL);
-        Jim_AppendStrings(interp, Jim_GetResult(interp), "Use \"", cmdname, " -help\" or \"",
-            cmdname, " -help command\" for help", NULL);
+        Jim_AppendStrings(interp, Jim_GetResult(interp), "Use \"", cmdname, " -help ?command?\" for help", NULL);
         return 0;
     }
 
     cmd = argv[1];
 
-    if (argc == 2 && Jim_CompareStringImmediate(interp, cmd, "-usage")) {
-        /* Show full usage */
-        show_full_usage(interp, command_table, argc, argv);
-        return &dummy_subcmd;
-    }
-
-    /* Check for the help command */
+    
     if (Jim_CompareStringImmediate(interp, cmd, "-help")) {
         if (argc == 2) {
-            /* Usage for the command, not the subcommand */
+            
             show_cmd_usage(interp, command_table, argc, argv);
             return &dummy_subcmd;
         }
         help = 1;
 
-        /* Skip the 'help' command */
+        
         cmd = argv[2];
     }
 
-    /* Check for special builtin '-commands' command first */
+    
     if (Jim_CompareStringImmediate(interp, cmd, "-commands")) {
-        /* Build the result here */
+        
         Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
         add_commands(interp, command_table, " ");
         return &dummy_subcmd;
     }
 
     cmdstr = Jim_GetString(cmd, &cmdlen);
 
     for (ct = command_table; ct->cmd; ct++) {
         if (Jim_CompareStringImmediate(interp, cmd, ct->cmd)) {
-            /* Found an exact match */
+            
             break;
         }
         if (strncmp(cmdstr, ct->cmd, cmdlen) == 0) {
             if (partial) {
-                /* Ambiguous */
+                
                 if (help) {
-                    /* Just show the top level help here */
+                    
                     show_cmd_usage(interp, command_table, argc, argv);
                     return &dummy_subcmd;
                 }
                 bad_subcmd(interp, command_table, "ambiguous", argv[0], argv[1 + help]);
                 return 0;
@@ -21056,47 +18630,44 @@
             partial = ct;
         }
         continue;
     }
 
-    /* If we had an unambiguous partial match */
+    
     if (partial && !ct->cmd) {
         ct = partial;
     }
 
     if (!ct->cmd) {
-        /* No matching command */
+        
         if (help) {
-            /* Just show the top level help here */
+            
             show_cmd_usage(interp, command_table, argc, argv);
             return &dummy_subcmd;
         }
         bad_subcmd(interp, command_table, "unknown", argv[0], argv[1 + help]);
         return 0;
     }
 
     if (help) {
         Jim_SetResultString(interp, "Usage: ", -1);
-        /* subcmd */
+        
         add_cmd_usage(interp, ct, argv[0]);
-        if (ct->description) {
-            Jim_AppendStrings(interp, Jim_GetResult(interp), "\n\n", ct->description, NULL);
-        }
         return &dummy_subcmd;
     }
 
-    /* Check the number of args */
+    
     if (argc - 2 < ct->minargs || (ct->maxargs >= 0 && argc - 2 > ct->maxargs)) {
         Jim_SetResultString(interp, "wrong # args: must be \"", -1);
-        /* subcmd */
+        
         add_cmd_usage(interp, ct, argv[0]);
         Jim_AppendStrings(interp, Jim_GetResult(interp), "\"", NULL);
 
         return 0;
     }
 
-    /* Good command */
+    
     return ct;
 }
 
 int Jim_CallSubCmd(Jim_Interp *interp, const jim_subcmd_type * ct, int argc, Jim_Obj *const *argv)
 {
@@ -21123,89 +18694,17 @@
         Jim_ParseSubCmd(interp, (const jim_subcmd_type *)Jim_CmdPrivData(interp), argc, argv);
 
     return Jim_CallSubCmd(interp, ct, argc, argv);
 }
 
-/* The following two functions are for normal commands */
-int
-Jim_CheckCmdUsage(Jim_Interp *interp, const jim_subcmd_type * command_table, int argc,
-    Jim_Obj *const *argv)
-{
-    /* -usage or -help */
-    if (argc == 2) {
-        if (Jim_CompareStringImmediate(interp, argv[1], "-usage")
-            || Jim_CompareStringImmediate(interp, argv[1], "-help")) {
-            Jim_SetResultString(interp, "Usage: ", -1);
-            add_cmd_usage(interp, command_table, NULL);
-            if (command_table->description) {
-                Jim_AppendStrings(interp, Jim_GetResult(interp), "\n\n", command_table->description,
-                    NULL);
-            }
-            return JIM_OK;
-        }
-    }
-    if (argc >= 2 && command_table->function) {
-        /* This is actually a sub command table */
-
-        Jim_Obj *nargv[4];
-        int nargc = 0;
-        const char *subcmd = NULL;
-
-        if (Jim_CompareStringImmediate(interp, argv[1], "-subcommands")) {
-            Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
-            add_commands(interp, (jim_subcmd_type *) command_table->function, " ");
-            return JIM_OK;
-        }
-
-        if (Jim_CompareStringImmediate(interp, argv[1], "-subhelp")
-            || Jim_CompareStringImmediate(interp, argv[1], "-help")) {
-            subcmd = "-help";
-        }
-        else if (Jim_CompareStringImmediate(interp, argv[1], "-subusage")) {
-            subcmd = "-usage";
-        }
-
-        if (subcmd) {
-            nargv[nargc++] = Jim_NewStringObj(interp, "$handle", -1);
-            nargv[nargc++] = Jim_NewStringObj(interp, subcmd, -1);
-            if (argc >= 3) {
-                nargv[nargc++] = argv[2];
-            }
-            Jim_ParseSubCmd(interp, (jim_subcmd_type *) command_table->function, nargc, nargv);
-            Jim_FreeNewObj(interp, nargv[0]);
-            Jim_FreeNewObj(interp, nargv[1]);
-            return 0;
-        }
-    }
-
-    /* Check the number of args */
-    if (argc - 1 < command_table->minargs || (command_table->maxargs >= 0
-            && argc - 1 > command_table->maxargs)) {
-        set_wrong_args(interp, command_table, NULL);
-        Jim_AppendStrings(interp, Jim_GetResult(interp), "\nUse \"", Jim_String(argv[0]),
-            " -help\" for help", NULL);
-        return JIM_ERR;
-    }
-
-    /* Not usage, but passed arg checking */
-    return -1;
-}
-/**
- * UTF-8 utility functions
- *
- * (c) 2010 Steve Bennett <steveb@workware.net.au>
- *
- * See LICENCE for licence details.
- */
-
 #include <ctype.h>
 #include <stdlib.h>
 #include <string.h>
 #include <stdio.h>
 #include <assert.h>
 
-/* This one is always implemented */
+
 int utf8_fromunicode(char *p, unsigned short uc)
 {
     if (uc <= 0x7f) {
         *p = uc;
         return 1;
@@ -21221,167 +18720,1778 @@
         *p = 0x80 | (uc & 0x3f);
         return 3;
     }
 }
 
-#ifdef JIM_UTF8
-int utf8_charlen(int c)
+#include <ctype.h>
+#include <string.h>
+
+
+#define JIM_UTF_MAX 3
+#define JIM_INTEGER_SPACE 24
+#define MAX_FLOAT_WIDTH 320
+
+Jim_Obj *Jim_FormatString(Jim_Interp *interp, Jim_Obj *fmtObjPtr, int objc, Jim_Obj *const *objv)
+{
+    const char *span, *format, *formatEnd, *msg;
+    int numBytes = 0, objIndex = 0, gotXpg = 0, gotSequential = 0;
+    static const char * const mixedXPG =
+	    "cannot mix \"%\" and \"%n$\" conversion specifiers";
+    static const char * const badIndex[2] = {
+	"not enough arguments for all format specifiers",
+	"\"%n$\" argument index out of range"
+    };
+    int formatLen;
+    Jim_Obj *resultPtr;
+
+    char *num_buffer = NULL;
+    int num_buffer_size = 0;
+
+    span = format = Jim_GetString(fmtObjPtr, &formatLen);
+    formatEnd = format + formatLen;
+    resultPtr = Jim_NewStringObj(interp, "", 0);
+
+    while (format != formatEnd) {
+	char *end;
+	int gotMinus, sawFlag;
+	int gotPrecision, useShort;
+	long width, precision;
+	int newXpg;
+	int ch;
+	int step;
+	int doubleType;
+	char pad = ' ';
+	char spec[2*JIM_INTEGER_SPACE + 12];
+	char *p;
+
+	int formatted_chars;
+	int formatted_bytes;
+	const char *formatted_buf;
+
+	step = utf8_tounicode(format, &ch);
+	format += step;
+	if (ch != '%') {
+	    numBytes += step;
+	    continue;
+	}
+	if (numBytes) {
+	    Jim_AppendString(interp, resultPtr, span, numBytes);
+	    numBytes = 0;
+	}
+
+
+	step = utf8_tounicode(format, &ch);
+	if (ch == '%') {
+	    span = format;
+	    numBytes = step;
+	    format += step;
+	    continue;
+	}
+
+
+	newXpg = 0;
+	if (isdigit(ch)) {
+	    int position = strtoul(format, &end, 10);
+	    if (*end == '$') {
+		newXpg = 1;
+		objIndex = position - 1;
+		format = end + 1;
+		step = utf8_tounicode(format, &ch);
+	    }
+	}
+	if (newXpg) {
+	    if (gotSequential) {
+		msg = mixedXPG;
+		goto errorMsg;
+	    }
+	    gotXpg = 1;
+	} else {
+	    if (gotXpg) {
+		msg = mixedXPG;
+		goto errorMsg;
+	    }
+	    gotSequential = 1;
+	}
+	if ((objIndex < 0) || (objIndex >= objc)) {
+	    msg = badIndex[gotXpg];
+	    goto errorMsg;
+	}
+
+	p = spec;
+	*p++ = '%';
+
+	gotMinus = 0;
+	sawFlag = 1;
+	do {
+	    switch (ch) {
+	    case '-':
+		gotMinus = 1;
+		break;
+	    case '0':
+		pad = ch;
+		break;
+	    case ' ':
+	    case '+':
+	    case '#':
+		break;
+	    default:
+		sawFlag = 0;
+		continue;
+	    }
+	    *p++ = ch;
+	    format += step;
+	    step = utf8_tounicode(format, &ch);
+	} while (sawFlag);
+
+
+	width = 0;
+	if (isdigit(ch)) {
+	    width = strtoul(format, &end, 10);
+	    format = end;
+	    step = utf8_tounicode(format, &ch);
+	} else if (ch == '*') {
+	    if (objIndex >= objc - 1) {
+		msg = badIndex[gotXpg];
+		goto errorMsg;
+	    }
+	    if (Jim_GetLong(interp, objv[objIndex], &width) != JIM_OK) {
+		goto error;
+	    }
+	    if (width < 0) {
+		width = -width;
+		if (!gotMinus) {
+		    *p++ = '-';
+		    gotMinus = 1;
+		}
+	    }
+	    objIndex++;
+	    format += step;
+	    step = utf8_tounicode(format, &ch);
+	}
+
+
+	gotPrecision = precision = 0;
+	if (ch == '.') {
+	    gotPrecision = 1;
+	    format += step;
+	    step = utf8_tounicode(format, &ch);
+	}
+	if (isdigit(ch)) {
+	    precision = strtoul(format, &end, 10);
+	    format = end;
+	    step = utf8_tounicode(format, &ch);
+	} else if (ch == '*') {
+	    if (objIndex >= objc - 1) {
+		msg = badIndex[gotXpg];
+		goto errorMsg;
+	    }
+	    if (Jim_GetLong(interp, objv[objIndex], &precision) != JIM_OK) {
+		goto error;
+	    }
+
+
+	    if (precision < 0) {
+		precision = 0;
+	    }
+	    objIndex++;
+	    format += step;
+	    step = utf8_tounicode(format, &ch);
+	}
+
+
+	useShort = 0;
+	if (ch == 'h') {
+	    useShort = 1;
+	    format += step;
+	    step = utf8_tounicode(format, &ch);
+	} else if (ch == 'l') {
+	    
+	    format += step;
+	    step = utf8_tounicode(format, &ch);
+	    if (ch == 'l') {
+		format += step;
+		step = utf8_tounicode(format, &ch);
+	    }
+	}
+
+	format += step;
+	span = format;
+
+
+	if (ch == 'i') {
+	    ch = 'd';
+	}
+
+	doubleType = 0;
+
+	switch (ch) {
+	case '\0':
+	    msg = "format string ended in middle of field specifier";
+	    goto errorMsg;
+	case 's': {
+	    formatted_buf = Jim_GetString(objv[objIndex], &formatted_bytes);
+	    formatted_chars = Jim_Utf8Length(interp, objv[objIndex]);
+	    if (gotPrecision && (precision < formatted_chars)) {
+		
+		formatted_chars = precision;
+		formatted_bytes = utf8_index(formatted_buf, precision);
+	    }
+	    break;
+	}
+	case 'c': {
+	    jim_wide code;
+
+	    if (Jim_GetWide(interp, objv[objIndex], &code) != JIM_OK) {
+		goto error;
+	    }
+	    
+	    formatted_bytes = utf8_fromunicode(spec, code);
+	    formatted_buf = spec;
+	    formatted_chars = 1;
+	    break;
+	}
+
+	case 'e':
+	case 'E':
+	case 'f':
+	case 'g':
+	case 'G':
+	    doubleType = 1;
+	    
+	case 'd':
+	case 'u':
+	case 'o':
+	case 'x':
+	case 'X': {
+	    jim_wide w;
+	    double d;
+	    int length;
+
+	    
+	    if (width) {
+		p += sprintf(p, "%ld", width);
+	    }
+	    if (gotPrecision) {
+		p += sprintf(p, ".%ld", precision);
+	    }
+
+	    
+	    if (doubleType) {
+		if (Jim_GetDouble(interp, objv[objIndex], &d) != JIM_OK) {
+		    goto error;
+		}
+		length = MAX_FLOAT_WIDTH;
+	    }
+	    else {
+		if (Jim_GetWide(interp, objv[objIndex], &w) != JIM_OK) {
+		    goto error;
+		}
+		length = JIM_INTEGER_SPACE;
+		if (useShort) {
+		    *p++ = 'h';
+		    if (ch == 'd') {
+			w = (short)w;
+		    }
+		    else {
+			w = (unsigned short)w;
+		    }
+		}
+		else {
+		    *p++ = 'l';
+#ifdef HAVE_LONG_LONG
+		    if (sizeof(long long) == sizeof(jim_wide)) {
+			*p++ = 'l';
+		    }
+#endif
+		}
+	    }
+
+	    *p++ = (char) ch;
+	    *p = '\0';
+
+	    
+	    if (width > length) {
+		length = width;
+	    }
+	    if (gotPrecision) {
+		length += precision;
+	    }
+
+	    
+	    if (num_buffer_size < length + 1) {
+		num_buffer_size = length + 1;
+		num_buffer = Jim_Realloc(num_buffer, num_buffer_size);
+	    }
+
+	    if (doubleType) {
+		snprintf(num_buffer, length + 1, spec, d);
+	    }
+	    else {
+		formatted_bytes = snprintf(num_buffer, length + 1, spec, w);
+	    }
+	    formatted_chars = formatted_bytes = strlen(num_buffer);
+	    formatted_buf = num_buffer;
+	    break;
+	}
+
+	default: {
+	    
+	    spec[0] = ch;
+	    spec[1] = '\0';
+	    Jim_SetResultFormatted(interp, "bad field specifier \"%s\"", spec);
+	    goto error;
+	}
+	}
+
+	if (!gotMinus) {
+	    while (formatted_chars < width) {
+		Jim_AppendString(interp, resultPtr, &pad, 1);
+		formatted_chars++;
+	    }
+	}
+
+	Jim_AppendString(interp, resultPtr, formatted_buf, formatted_bytes);
+
+	while (formatted_chars < width) {
+	    Jim_AppendString(interp, resultPtr, &pad, 1);
+	    formatted_chars++;
+	}
+
+	objIndex += gotSequential;
+    }
+    if (numBytes) {
+	Jim_AppendString(interp, resultPtr, span, numBytes);
+    }
+
+    Jim_Free(num_buffer);
+    return resultPtr;
+
+  errorMsg:
+    Jim_SetResultString(interp, msg, -1);
+  error:
+    Jim_FreeNewObj(interp, resultPtr);
+    Jim_Free(num_buffer);
+    return NULL;
+}
+#include <stdio.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+#if !defined(HAVE_REGCOMP) || defined(JIM_REGEXP)
+
+
+
+#define REG_MAX_PAREN 100
+
+
+#define	END	0	
+#define	BOL	1	
+#define	EOL	2	
+#define	ANY	3	
+#define	ANYOF	4	
+#define	ANYBUT	5	
+#define	BRANCH	6	
+#define	BACK	7	
+#define	EXACTLY	8	
+#define	NOTHING	9	
+#define	REP		10	
+#define	REPMIN	11	
+#define	REPX	12	
+#define	REPXMIN	13	
+
+#define	WORDA	15	
+#define	WORDZ	16	
+#define	OPEN	20	
+			
+#define	CLOSE	(OPEN+REG_MAX_PAREN)	
+#define	CLOSE_END	(CLOSE+REG_MAX_PAREN)
+
+#define	REG_MAGIC	0xFADED00D
+
+
+#define	OP(preg, p)	(preg->program[p])
+#define	NEXT(preg, p)	(preg->program[p + 1])
+#define	OPERAND(p)	((p) + 2)
+
+
+
+
+#define	FAIL(R,M)	{ (R)->err = (M); return (M); }
+#define	ISMULT(c)	((c) == '*' || (c) == '+' || (c) == '?' || (c) == '{')
+#define	META	"^$.[()|?{+*"
+
+#define	HASWIDTH	01	
+#define	SIMPLE		02	
+#define	SPSTART		04	
+#define	WORST		0	
+
+#define MAX_REP_COUNT 1000000
+
+static int reg(regex_t *preg, int paren , int *flagp );
+static int regpiece(regex_t *preg, int *flagp );
+static int regbranch(regex_t *preg, int *flagp );
+static int regatom(regex_t *preg, int *flagp );
+static int regnode(regex_t *preg, int op );
+static int regnext(regex_t *preg, int p );
+static void regc(regex_t *preg, int b );
+static int reginsert(regex_t *preg, int op, int size, int opnd );
+static void regtail_(regex_t *preg, int p, int val, int line );
+static void regoptail(regex_t *preg, int p, int val );
+#define regtail(PREG, P, VAL) regtail_(PREG, P, VAL, __LINE__)
+
+static int reg_range_find(const int *string, int c);
+static const char *str_find(const char *string, int c, int nocase);
+static int prefix_cmp(const int *prog, int proglen, const char *string, int nocase);
+
+
+#ifdef DEBUG
+int regnarrate = 0;
+static void regdump(regex_t *preg);
+static const char *regprop( int op );
+#endif
+
+
+static int str_int_len(const int *seq)
+{
+	int n = 0;
+	while (*seq++) {
+		n++;
+	}
+	return n;
+}
+
+int regcomp(regex_t *preg, const char *exp, int cflags)
+{
+	int scan;
+	int longest;
+	unsigned len;
+	int flags;
+
+#ifdef DEBUG
+	fprintf(stderr, "Compiling: '%s'\n", exp);
+#endif
+	memset(preg, 0, sizeof(*preg));
+
+	if (exp == NULL)
+		FAIL(preg, REG_ERR_NULL_ARGUMENT);
+
+	
+	preg->cflags = cflags;
+	preg->regparse = exp;
+	
+	preg->program = NULL;
+	preg->proglen = 0;
+
+#if 1
+	
+	preg->proglen = (strlen(exp) + 1) * 5;
+	preg->program = malloc(preg->proglen * sizeof(int));
+	if (preg->program == NULL)
+		FAIL(preg, REG_ERR_NOMEM);
+#endif
+
+	regc(preg, REG_MAGIC);
+	if (reg(preg, 0, &flags) == 0) {
+		return preg->err;
+	}
+
+	
+	if (preg->re_nsub >= REG_MAX_PAREN)		
+		FAIL(preg,REG_ERR_TOO_BIG);
+
+	
+	preg->regstart = 0;	
+	preg->reganch = 0;
+	preg->regmust = 0;
+	preg->regmlen = 0;
+	scan = 1;			
+	if (OP(preg, regnext(preg, scan)) == END) {		
+		scan = OPERAND(scan);
+
+		
+		if (OP(preg, scan) == EXACTLY) {
+			preg->regstart = preg->program[OPERAND(scan)];
+		}
+		else if (OP(preg, scan) == BOL)
+			preg->reganch++;
+
+		if (flags&SPSTART) {
+			longest = 0;
+			len = 0;
+			for (; scan != 0; scan = regnext(preg, scan)) {
+				if (OP(preg, scan) == EXACTLY) {
+					int plen = str_int_len(preg->program + OPERAND(scan));
+					if (plen >= len) {
+						longest = OPERAND(scan);
+						len = plen;
+					}
+				}
+			}
+			preg->regmust = longest;
+			preg->regmlen = len;
+		}
+	}
+
+#ifdef DEBUG
+	regdump(preg);
+#endif
+
+	return 0;
+}
+
+static int reg(regex_t *preg, int paren , int *flagp )
+{
+	int ret;
+	int br;
+	int ender;
+	int parno = 0;
+	int flags;
+
+	*flagp = HASWIDTH;	
+
+	
+	if (paren) {
+		parno = ++preg->re_nsub;
+		ret = regnode(preg, OPEN+parno);
+	} else
+		ret = 0;
+
+	
+	br = regbranch(preg, &flags);
+	if (br == 0)
+		return 0;
+	if (ret != 0)
+		regtail(preg, ret, br);	
+	else
+		ret = br;
+	if (!(flags&HASWIDTH))
+		*flagp &= ~HASWIDTH;
+	*flagp |= flags&SPSTART;
+	while (*preg->regparse == '|') {
+		preg->regparse++;
+		br = regbranch(preg, &flags);
+		if (br == 0)
+			return 0;
+		regtail(preg, ret, br);	
+		if (!(flags&HASWIDTH))
+			*flagp &= ~HASWIDTH;
+		*flagp |= flags&SPSTART;
+	}
+
+	
+	ender = regnode(preg, (paren) ? CLOSE+parno : END);
+	regtail(preg, ret, ender);
+
+	
+	for (br = ret; br != 0; br = regnext(preg, br))
+		regoptail(preg, br, ender);
+
+	
+	if (paren && *preg->regparse++ != ')') {
+		preg->err = REG_ERR_UNMATCHED_PAREN;
+		return 0;
+	} else if (!paren && *preg->regparse != '\0') {
+		if (*preg->regparse == ')') {
+			preg->err = REG_ERR_UNMATCHED_PAREN;
+			return 0;
+		} else {
+			preg->err = REG_ERR_JUNK_ON_END;
+			return 0;
+		}
+	}
+
+	return(ret);
+}
+
+static int regbranch(regex_t *preg, int *flagp )
+{
+	int ret;
+	int chain;
+	int latest;
+	int flags;
+
+	*flagp = WORST;		
+
+	ret = regnode(preg, BRANCH);
+	chain = 0;
+	while (*preg->regparse != '\0' && *preg->regparse != ')' &&
+	       *preg->regparse != '|') {
+		latest = regpiece(preg, &flags);
+		if (latest == 0)
+			return 0;
+		*flagp |= flags&HASWIDTH;
+		if (chain == 0) {
+			*flagp |= flags&SPSTART;
+		}
+		else {
+			regtail(preg, chain, latest);
+		}
+		chain = latest;
+	}
+	if (chain == 0)	
+		(void) regnode(preg, NOTHING);
+
+	return(ret);
+}
+
+static int regpiece(regex_t *preg, int *flagp)
+{
+	int ret;
+	char op;
+	int next;
+	int flags;
+	int chain = 0;
+	int min;
+	int max;
+
+	ret = regatom(preg, &flags);
+	if (ret == 0)
+		return 0;
+
+	op = *preg->regparse;
+	if (!ISMULT(op)) {
+		*flagp = flags;
+		return(ret);
+	}
+
+	if (!(flags&HASWIDTH) && op != '?') {
+		preg->err = REG_ERR_OPERAND_COULD_BE_EMPTY;
+		return 0;
+	}
+
+	
+	if (op == '{') {
+		char *end;
+
+		min = strtoul(preg->regparse + 1, &end, 10);
+		if (end == preg->regparse + 1) {
+			preg->err = REG_ERR_BAD_COUNT;
+			return 0;
+		}
+		if (*end == '}') {
+			max = min;
+		}
+		else {
+			preg->regparse = end;
+			max = strtoul(preg->regparse + 1, &end, 10);
+			if (*end != '}') {
+				preg->err = REG_ERR_UNMATCHED_BRACES;
+				return 0;
+			}
+		}
+		if (end == preg->regparse + 1) {
+			max = MAX_REP_COUNT;
+		}
+		else if (max < min || max >= 100) {
+			preg->err = REG_ERR_BAD_COUNT;
+			return 0;
+		}
+		if (min >= 100) {
+			preg->err = REG_ERR_BAD_COUNT;
+			return 0;
+		}
+
+		preg->regparse = strchr(preg->regparse, '}');
+	}
+	else {
+		min = (op == '+');
+		max = (op == '?' ? 1 : MAX_REP_COUNT);
+	}
+
+	if (preg->regparse[1] == '?') {
+		preg->regparse++;
+		next = reginsert(preg, flags & SIMPLE ? REPMIN : REPXMIN, 5, ret);
+	}
+	else {
+		next = reginsert(preg, flags & SIMPLE ? REP: REPX, 5, ret);
+	}
+	preg->program[ret + 2] = max;
+	preg->program[ret + 3] = min;
+	preg->program[ret + 4] = 0;
+
+	*flagp = (min) ? (WORST|HASWIDTH) : (WORST|SPSTART);
+
+	if (!(flags & SIMPLE)) {
+		int back = regnode(preg, BACK);
+		regtail(preg, back, ret);
+		regtail(preg, next, back);
+	}
+
+	preg->regparse++;
+	if (ISMULT(*preg->regparse)) {
+		preg->err = REG_ERR_NESTED_COUNT;
+		return 0;
+	}
+
+	return chain ? chain : ret;
+}
+
+static void reg_addrange(regex_t *preg, int lower, int upper)
+{
+	if (lower > upper) {
+		reg_addrange(preg, upper, lower);
+	}
+	
+	regc(preg, upper - lower + 1);
+	regc(preg, lower);
+}
+
+static void reg_addrange_str(regex_t *preg, const char *str)
+{
+	while (*str) {
+		reg_addrange(preg, *str, *str);
+		str++;
+	}
+}
+
+static int reg_utf8_tounicode_case(const char *s, int *uc, int upper)
+{
+	int l = utf8_tounicode(s, uc);
+	if (upper) {
+		*uc = utf8_upper(*uc);
+	}
+	return l;
+}
+
+static int hexdigitval(int c)
+{
+	if (c >= '0' && c <= '9')
+		return c - '0';
+	if (c >= 'a' && c <= 'f')
+		return c - 'a' + 10;
+	if (c >= 'A' && c <= 'F')
+		return c - 'A' + 10;
+	return -1;
+}
+
+static int parse_hex(const char *s, int n, int *uc)
+{
+	int val = 0;
+	int k;
+
+	for (k = 0; k < n; k++) {
+		int c = hexdigitval(*s++);
+		if (c == -1) {
+			break;
+		}
+		val = (val << 4) | c;
+	}
+	if (k) {
+		*uc = val;
+	}
+	return k;
+}
+
+static int reg_decode_escape(const char *s, int *ch)
+{
+	int n;
+	const char *s0 = s;
+
+	*ch = *s++;
+
+	switch (*ch) {
+		case 'b': *ch = '\b'; break;
+		case 'e': *ch = 27; break;
+		case 'f': *ch = '\f'; break;
+		case 'n': *ch = '\n'; break;
+		case 'r': *ch = '\r'; break;
+		case 't': *ch = '\t'; break;
+		case 'v': *ch = '\v'; break;
+		case 'u':
+			if ((n = parse_hex(s, 4, ch)) > 0) {
+				s += n;
+			}
+			break;
+		case 'x':
+			if ((n = parse_hex(s, 2, ch)) > 0) {
+				s += n;
+			}
+			break;
+		case '\0':
+			s--;
+			*ch = '\\';
+			break;
+	}
+	return s - s0;
+}
+
+static int regatom(regex_t *preg, int *flagp)
+{
+	int ret;
+	int flags;
+	int nocase = (preg->cflags & REG_ICASE);
+
+	int ch;
+	int n = reg_utf8_tounicode_case(preg->regparse, &ch, nocase);
+
+	*flagp = WORST;		
+
+	preg->regparse += n;
+	switch (ch) {
+	
+	case '^':
+		ret = regnode(preg, BOL);
+		break;
+	case '$':
+		ret = regnode(preg, EOL);
+		break;
+	case '.':
+		ret = regnode(preg, ANY);
+		*flagp |= HASWIDTH|SIMPLE;
+		break;
+	case '[': {
+			const char *pattern = preg->regparse;
+
+			if (*pattern == '^') {	
+				ret = regnode(preg, ANYBUT);
+				pattern++;
+			} else
+				ret = regnode(preg, ANYOF);
+
+			
+			if (*pattern == ']' || *pattern == '-') {
+				reg_addrange(preg, *pattern, *pattern);
+				pattern++;
+			}
+
+			while (*pattern && *pattern != ']') {
+				
+				int start;
+				int end;
+
+				pattern += reg_utf8_tounicode_case(pattern, &start, nocase);
+				if (start == '\\') {
+					pattern += reg_decode_escape(pattern, &start);
+					if (start == 0) {
+						preg->err = REG_ERR_NULL_CHAR;
+						return 0;
+					}
+				}
+				if (pattern[0] == '-' && pattern[1]) {
+					
+					pattern += utf8_tounicode(pattern, &end);
+					pattern += reg_utf8_tounicode_case(pattern, &end, nocase);
+					if (end == '\\') {
+						pattern += reg_decode_escape(pattern, &end);
+						if (end == 0) {
+							preg->err = REG_ERR_NULL_CHAR;
+							return 0;
+						}
+					}
+
+					reg_addrange(preg, start, end);
+					continue;
+				}
+				if (start == '[') {
+					if (strncmp(pattern, ":alpha:]", 8) == 0) {
+						if ((preg->cflags & REG_ICASE) == 0) {
+							reg_addrange(preg, 'a', 'z');
+						}
+						reg_addrange(preg, 'A', 'Z');
+						pattern += 8;
+						continue;
+					}
+					if (strncmp(pattern, ":alnum:]", 8) == 0) {
+						if ((preg->cflags & REG_ICASE) == 0) {
+							reg_addrange(preg, 'a', 'z');
+						}
+						reg_addrange(preg, 'A', 'Z');
+						reg_addrange(preg, '0', '9');
+						pattern += 8;
+						continue;
+					}
+					if (strncmp(pattern, ":space:]", 8) == 0) {
+						reg_addrange_str(preg, " \t\r\n\f\v");
+						pattern += 8;
+						continue;
+					}
+				}
+				
+				reg_addrange(preg, start, start);
+			}
+			regc(preg, '\0');
+
+			if (*pattern) {
+				pattern++;
+			}
+			preg->regparse = pattern;
+
+			*flagp |= HASWIDTH|SIMPLE;
+		}
+		break;
+	case '(':
+		ret = reg(preg, 1, &flags);
+		if (ret == 0)
+			return 0;
+		*flagp |= flags&(HASWIDTH|SPSTART);
+		break;
+	case '\0':
+	case '|':
+	case ')':
+		preg->err = REG_ERR_INTERNAL;
+		return 0;	
+	case '?':
+	case '+':
+	case '*':
+	case '{':
+		preg->err = REG_ERR_COUNT_FOLLOWS_NOTHING;
+		return 0;
+	case '\\':
+		switch (*preg->regparse++) {
+		case '\0':
+			preg->err = REG_ERR_TRAILING_BACKSLASH;
+			return 0;
+		case '<':
+		case 'm':
+			ret = regnode(preg, WORDA);
+			break;
+		case '>':
+		case 'M':
+			ret = regnode(preg, WORDZ);
+			break;
+		case 'd':
+			ret = regnode(preg, ANYOF);
+			reg_addrange(preg, '0', '9');
+			regc(preg, '\0');
+			*flagp |= HASWIDTH|SIMPLE;
+			break;
+		case 'w':
+			ret = regnode(preg, ANYOF);
+			if ((preg->cflags & REG_ICASE) == 0) {
+				reg_addrange(preg, 'a', 'z');
+			}
+			reg_addrange(preg, 'A', 'Z');
+			reg_addrange(preg, '0', '9');
+			reg_addrange(preg, '_', '_');
+			regc(preg, '\0');
+			*flagp |= HASWIDTH|SIMPLE;
+			break;
+		case 's':
+			ret = regnode(preg, ANYOF);
+			reg_addrange_str(preg," \t\r\n\f\v");
+			regc(preg, '\0');
+			*flagp |= HASWIDTH|SIMPLE;
+			break;
+		
+		default:
+			
+			
+			preg->regparse--;
+			goto de_fault;
+		}
+		break;
+	de_fault:
+	default: {
+			int added = 0;
+
+			
+			preg->regparse -= n;
+
+			ret = regnode(preg, EXACTLY);
+
+
+			
+			while (*preg->regparse && strchr(META, *preg->regparse) == NULL) {
+				n = reg_utf8_tounicode_case(preg->regparse, &ch, (preg->cflags & REG_ICASE));
+				if (ch == '\\' && preg->regparse[n]) {
+					if (strchr("<>mMwds", preg->regparse[n])) {
+						
+						break;
+					}
+					n += reg_decode_escape(preg->regparse + n, &ch);
+					if (ch == 0) {
+						preg->err = REG_ERR_NULL_CHAR;
+						return 0;
+					}
+				}
+
+
+				if (ISMULT(preg->regparse[n])) {
+					
+					if (added) {
+						
+						break;
+					}
+					
+					regc(preg, ch);
+					added++;
+					preg->regparse += n;
+					break;
+				}
+
+				
+				regc(preg, ch);
+				added++;
+				preg->regparse += n;
+			}
+			regc(preg, '\0');
+
+			*flagp |= HASWIDTH;
+			if (added == 1)
+				*flagp |= SIMPLE;
+			break;
+		}
+		break;
+	}
+
+	return(ret);
+}
+
+static void reg_grow(regex_t *preg, int n)
+{
+	if (preg->p + n >= preg->proglen) {
+		preg->proglen = (preg->p + n) * 2;
+		preg->program = realloc(preg->program, preg->proglen * sizeof(int));
+	}
+}
+
+
+static int regnode(regex_t *preg, int op)
+{
+	reg_grow(preg, 2);
+
+	preg->program[preg->p++] = op;
+	preg->program[preg->p++] = 0;
+
+	
+	return preg->p - 2;
+}
+
+static void regc(regex_t *preg, int b )
+{
+	reg_grow(preg, 1);
+	preg->program[preg->p++] = b;
+}
+
+static int reginsert(regex_t *preg, int op, int size, int opnd )
+{
+	reg_grow(preg, size);
+
+	
+	memmove(preg->program + opnd + size, preg->program + opnd, sizeof(int) * (preg->p - opnd));
+	
+	memset(preg->program + opnd, 0, sizeof(int) * size);
+
+	preg->program[opnd] = op;
+
+	preg->p += size;
+
+	return opnd + size;
+}
+
+static void regtail_(regex_t *preg, int p, int val, int line )
+{
+	int scan;
+	int temp;
+	int offset;
+
+	
+	scan = p;
+	for (;;) {
+		temp = regnext(preg, scan);
+		if (temp == 0)
+			break;
+		scan = temp;
+	}
+
+	if (OP(preg, scan) == BACK)
+		offset = scan - val;
+	else
+		offset = val - scan;
+
+	preg->program[scan + 1] = offset;
+}
+
+
+static void regoptail(regex_t *preg, int p, int val )
+{
+	
+	if (p != 0 && OP(preg, p) == BRANCH) {
+		regtail(preg, OPERAND(p), val);
+	}
+}
+
+
+static int regtry(regex_t *preg, const char *string );
+static int regmatch(regex_t *preg, int prog);
+static int regrepeat(regex_t *preg, int p, int max);
+
+int regexec(regex_t  *preg,  const  char *string, size_t nmatch, regmatch_t pmatch[], int eflags)
+{
+	const char *s;
+	int scan;
+
+	
+	if (preg == NULL || preg->program == NULL || string == NULL) {
+		return REG_ERR_NULL_ARGUMENT;
+	}
+
+	
+	if (*preg->program != REG_MAGIC) {
+		return REG_ERR_CORRUPTED;
+	}
+
+#ifdef DEBUG
+	fprintf(stderr, "regexec: %s\n", string);
+	regdump(preg);
+#endif
+
+	preg->eflags = eflags;
+	preg->pmatch = pmatch;
+	preg->nmatch = nmatch;
+	preg->start = string;	
+
+	
+	for (scan = OPERAND(1); scan != 0; scan = regnext(preg, scan)) {
+		switch (OP(preg, scan)) {
+		case REP:
+		case REPMIN:
+		case REPX:
+		case REPXMIN:
+			preg->program[scan + 4] = 0;
+			break;
+		}
+	}
+
+	
+	if (preg->regmust != 0) {
+		s = string;
+		while ((s = str_find(s, preg->program[preg->regmust], preg->cflags & REG_ICASE)) != NULL) {
+			if (prefix_cmp(preg->program + preg->regmust, preg->regmlen, s, preg->cflags & REG_ICASE) >= 0) {
+				break;
+			}
+			s++;
+		}
+		if (s == NULL)	
+			return REG_NOMATCH;
+	}
+
+	
+	preg->regbol = string;
+
+	
+	if (preg->reganch) {
+		if (eflags & REG_NOTBOL) {
+			
+			goto nextline;
+		}
+		while (1) {
+			int ret = regtry(preg, string);
+			if (ret) {
+				return REG_NOERROR;
+			}
+			if (*string) {
+nextline:
+				if (preg->cflags & REG_NEWLINE) {
+					
+					string = strchr(string, '\n');
+					if (string) {
+						preg->regbol = ++string;
+						continue;
+					}
+				}
+			}
+			return REG_NOMATCH;
+		}
+	}
+
+	
+	s = string;
+	if (preg->regstart != '\0') {
+		
+		while ((s = str_find(s, preg->regstart, preg->cflags & REG_ICASE)) != NULL) {
+			if (regtry(preg, s))
+				return REG_NOERROR;
+			s++;
+		}
+	}
+	else
+		
+		while (1) {
+			if (regtry(preg, s))
+				return REG_NOERROR;
+			if (*s == '\0') {
+				break;
+			}
+			s += utf8_charlen(*s);
+		}
+
+	
+	return REG_NOMATCH;
+}
+
+			
+static int regtry( regex_t *preg, const char *string )
+{
+	int i;
+
+	preg->reginput = string;
+
+	for (i = 0; i < preg->nmatch; i++) {
+		preg->pmatch[i].rm_so = -1;
+		preg->pmatch[i].rm_eo = -1;
+	}
+	if (regmatch(preg, 1)) {
+		preg->pmatch[0].rm_so = string - preg->start;
+		preg->pmatch[0].rm_eo = preg->reginput - preg->start;
+		return(1);
+	} else
+		return(0);
+}
+
+static int prefix_cmp(const int *prog, int proglen, const char *string, int nocase)
+{
+	const char *s = string;
+	while (proglen && *s) {
+		int ch;
+		int n = reg_utf8_tounicode_case(s, &ch, nocase);
+		if (ch != *prog) {
+			return -1;
+		}
+		prog++;
+		s += n;
+		proglen--;
+	}
+	if (proglen == 0) {
+		return s - string;
+	}
+	return -1;
+}
+
+static int reg_range_find(const int *range, int c)
+{
+	while (*range) {
+		
+		if (c >= range[1] && c <= (range[0] + range[1] - 1)) {
+			return 1;
+		}
+		range += 2;
+	}
+	return 0;
+}
+
+static const char *str_find(const char *string, int c, int nocase)
+{
+	if (nocase) {
+		
+		c = utf8_upper(c);
+	}
+	while (*string) {
+		int ch;
+		int n = reg_utf8_tounicode_case(string, &ch, nocase);
+		if (c == ch) {
+			return string;
+		}
+		string += n;
+	}
+	return NULL;
+}
+
+static int reg_iseol(regex_t *preg, int ch)
+{
+	if (preg->cflags & REG_NEWLINE) {
+		return ch == '\0' || ch == '\n';
+	}
+	else {
+		return ch == '\0';
+	}
+}
+
+static int regmatchsimplerepeat(regex_t *preg, int scan, int matchmin)
+{
+	int nextch = '\0';
+	const char *save;
+	int no;
+	int c;
+
+	int max = preg->program[scan + 2];
+	int min = preg->program[scan + 3];
+	int next = regnext(preg, scan);
+
+	if (OP(preg, next) == EXACTLY) {
+		nextch = preg->program[OPERAND(next)];
+	}
+	save = preg->reginput;
+	no = regrepeat(preg, scan + 5, max);
+	if (no < min) {
+		return 0;
+	}
+	if (matchmin) {
+		
+		max = no;
+		no = min;
+	}
+	
+	while (1) {
+		if (matchmin) {
+			if (no > max) {
+				break;
+			}
+		}
+		else {
+			if (no < min) {
+				break;
+			}
+		}
+		preg->reginput = save + utf8_index(save, no);
+		reg_utf8_tounicode_case(preg->reginput, &c, (preg->cflags & REG_ICASE));
+		
+		if (reg_iseol(preg, nextch) || c == nextch) {
+			if (regmatch(preg, next)) {
+				return(1);
+			}
+		}
+		if (matchmin) {
+			
+			no++;
+		}
+		else {
+			
+			no--;
+		}
+	}
+	return(0);
+}
+
+static int regmatchrepeat(regex_t *preg, int scan, int matchmin)
+{
+	int *scanpt = preg->program + scan;
+
+	int max = scanpt[2];
+	int min = scanpt[3];
+
+	
+	if (scanpt[4] < min) {
+		
+		scanpt[4]++;
+		if (regmatch(preg, scan + 5)) {
+			return 1;
+		}
+		scanpt[4]--;
+		return 0;
+	}
+	if (scanpt[4] > max) {
+		return 0;
+	}
+
+	if (matchmin) {
+		
+		if (regmatch(preg, regnext(preg, scan))) {
+			return 1;
+		}
+		
+		scanpt[4]++;
+		if (regmatch(preg, scan + 5)) {
+			return 1;
+		}
+		scanpt[4]--;
+		return 0;
+	}
+	
+	if (scanpt[4] < max) {
+		scanpt[4]++;
+		if (regmatch(preg, scan + 5)) {
+			return 1;
+		}
+		scanpt[4]--;
+	}
+	
+	return regmatch(preg, regnext(preg, scan));
+}
+
+
+static int regmatch(regex_t *preg, int prog)
+{
+	int scan;	
+	int next;		
+
+	scan = prog;
+
+#ifdef DEBUG
+	if (scan != 0 && regnarrate)
+		fprintf(stderr, "%s(\n", regprop(scan));
+#endif
+	while (scan != 0) {
+		int n;
+		int c;
+#ifdef DEBUG
+		if (regnarrate) {
+			fprintf(stderr, "%3d: %s...\n", scan, regprop(OP(preg, scan)));	
+		}
+#endif
+		next = regnext(preg, scan);
+		n = reg_utf8_tounicode_case(preg->reginput, &c, (preg->cflags & REG_ICASE));
+
+		switch (OP(preg, scan)) {
+		case BOL:
+			if (preg->reginput != preg->regbol)
+				return(0);
+			break;
+		case EOL:
+			if (!reg_iseol(preg, c)) {
+				return(0);
+			}
+			break;
+		case WORDA:
+			
+			if ((!isalnum(UCHAR(c))) && c != '_')
+				return(0);
+			
+			if (preg->reginput > preg->regbol &&
+				(isalnum(UCHAR(preg->reginput[-1])) || preg->reginput[-1] == '_'))
+				return(0);
+			break;
+		case WORDZ:
+			
+			if (preg->reginput > preg->regbol) {
+				
+				if (reg_iseol(preg, c) || !isalnum(UCHAR(c)) || c != '_') {
+					c = preg->reginput[-1];
+					
+					if (isalnum(UCHAR(c)) || c == '_') {
+						break;
+					}
+				}
+			}
+			
+			return(0);
+
+		case ANY:
+			if (reg_iseol(preg, c))
+				return 0;
+			preg->reginput += n;
+			break;
+		case EXACTLY: {
+				int opnd;
+				int len;
+				int slen;
+
+				opnd = OPERAND(scan);
+				len = str_int_len(preg->program + opnd);
+
+				slen = prefix_cmp(preg->program + opnd, len, preg->reginput, preg->cflags & REG_ICASE);
+				if (slen < 0) {
+					return(0);
+				}
+				preg->reginput += slen;
+			}
+			break;
+		case ANYOF:
+			if (reg_iseol(preg, c) || reg_range_find(preg->program + OPERAND(scan), c) == 0) {
+				return(0);
+			}
+			preg->reginput += n;
+			break;
+		case ANYBUT:
+			if (reg_iseol(preg, c) || reg_range_find(preg->program + OPERAND(scan), c) != 0) {
+				return(0);
+			}
+			preg->reginput += n;
+			break;
+		case NOTHING:
+			break;
+		case BACK:
+			break;
+		case BRANCH: {
+				const char *save;
+
+				if (OP(preg, next) != BRANCH)		
+					next = OPERAND(scan);	
+				else {
+					do {
+						save = preg->reginput;
+						if (regmatch(preg, OPERAND(scan))) {
+							return(1);
+						}
+						preg->reginput = save;
+						scan = regnext(preg, scan);
+					} while (scan != 0 && OP(preg, scan) == BRANCH);
+					return(0);
+					
+				}
+			}
+			break;
+		case REP:
+		case REPMIN:
+			return regmatchsimplerepeat(preg, scan, OP(preg, scan) == REPMIN);
+
+		case REPX:
+		case REPXMIN:
+			return regmatchrepeat(preg, scan, OP(preg, scan) == REPXMIN);
+
+		case END:
+			return(1);	
+			break;
+		default:
+			if (OP(preg, scan) >= OPEN+1 && OP(preg, scan) < CLOSE_END) {
+				const char *save;
+
+				save = preg->reginput;
+
+				if (regmatch(preg, next)) {
+					int no;
+					if (OP(preg, scan) < CLOSE) {
+						no = OP(preg, scan) - OPEN;
+						if (no < preg->nmatch && preg->pmatch[no].rm_so == -1) {
+							preg->pmatch[no].rm_so = save - preg->start;
+						}
+					}
+					else {
+						no = OP(preg, scan) - CLOSE;
+						if (no < preg->nmatch && preg->pmatch[no].rm_eo == -1) {
+							preg->pmatch[no].rm_eo = save - preg->start;
+						}
+					}
+					return(1);
+				} else
+					return(0);
+			}
+			return REG_ERR_INTERNAL;
+		}
+
+		scan = next;
+	}
+
+	return REG_ERR_INTERNAL;
+}
+
+static int regrepeat(regex_t *preg, int p, int max)
+{
+	int count = 0;
+	const char *scan;
+	int opnd;
+	int ch;
+	int n;
+
+	scan = preg->reginput;
+	opnd = OPERAND(p);
+	switch (OP(preg, p)) {
+	case ANY:
+		
+		while (!reg_iseol(preg, *scan) && count < max) {
+			count++;
+			scan++;
+		}
+		break;
+	case EXACTLY:
+		while (count < max) {
+			n = reg_utf8_tounicode_case(scan, &ch, preg->cflags & REG_ICASE);
+			if (preg->program[opnd] != ch) {
+				break;
+			}
+			count++;
+			scan += n;
+		}
+		break;
+	case ANYOF:
+		while (count < max) {
+			n = reg_utf8_tounicode_case(scan, &ch, preg->cflags & REG_ICASE);
+			if (reg_iseol(preg, ch) || reg_range_find(preg->program + opnd, ch) == 0) {
+				break;
+			}
+			count++;
+			scan += n;
+		}
+		break;
+	case ANYBUT:
+		while (count < max) {
+			n = reg_utf8_tounicode_case(scan, &ch, preg->cflags & REG_ICASE);
+			if (reg_iseol(preg, ch) || reg_range_find(preg->program + opnd, ch) != 0) {
+				break;
+			}
+			count++;
+			scan += n;
+		}
+		break;
+	default:		
+		preg->err = REG_ERR_INTERNAL;
+		count = 0;	
+		break;
+	}
+	preg->reginput = scan;
+
+	return(count);
+}
+
+static int regnext(regex_t *preg, int p )
+{
+	int offset;
+
+	offset = NEXT(preg, p);
+
+	if (offset == 0)
+		return 0;
+
+	if (OP(preg, p) == BACK)
+		return(p-offset);
+	else
+		return(p+offset);
+}
+
+
+size_t regerror(int errcode, const regex_t *preg, char *errbuf,  size_t errbuf_size)
+{
+	static const char *error_strings[] = {
+		"success",
+		"no match",
+		"bad pattern",
+		"null argument",
+		"unknown error",
+		"too big",
+		"out of memory",
+		"too many ()",
+		"parentheses () not balanced",
+		"braces {} not balanced",
+		"invalid repetition count(s)",
+		"extra characters",
+		"*+ of empty atom",
+		"nested count",
+		"internal error",
+		"count follows nothing",
+		"trailing backslash",
+		"corrupted program",
+		"contains null char",
+	};
+	const char *err;
+
+	if (errcode < 0 || errcode >= REG_ERR_NUM) {
+		err = "Bad error code";
+	}
+	else {
+		err = error_strings[errcode];
+	}
+
+	return snprintf(errbuf, errbuf_size, "%s", err);
+}
+
+void regfree(regex_t *preg)
+{
+	free(preg->program);
+}
+
+#endif
+
+#if defined(_WIN32) || defined(WIN32)
+#ifndef STRICT
+#define STRICT
+#endif
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+
+#if defined(HAVE_DLOPEN_COMPAT)
+void *dlopen(const char *path, int mode)
+{
+    JIM_NOTUSED(mode);
+
+    return (void *)LoadLibraryA(path);
+}
+
+int dlclose(void *handle)
+{
+    FreeLibrary((HANDLE)handle);
+    return 0;
+}
+
+void *dlsym(void *handle, const char *symbol)
+{
+    return GetProcAddress((HMODULE)handle, symbol);
+}
+
+char *dlerror(void)
 {
-    if ((c & 0x80) == 0) {
-        return 1;
-    }
-    if ((c & 0xe0) == 0xc0) {
-        return 2;
-    }
-    if ((c & 0xf0) == 0xe0) {
-        return 3;
-    }
-    if ((c & 0xf8) == 0xf0) {
-        return 4;
-    }
-    /* Invalid sequence */
-    return -1;
+    static char msg[121];
+    FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(),
+                   LANG_NEUTRAL, msg, sizeof(msg) - 1, NULL);
+    return msg;
 }
+#endif
 
-int utf8_strlen(const char *str, int bytelen)
+#ifdef _MSC_VER
+
+#include <sys/timeb.h>
+
+
+int gettimeofday(struct timeval *tv, void *unused)
 {
-    int charlen = 0;
-    if (bytelen < 0) {
-        bytelen = strlen(str);
-    }
-    while (bytelen) {
-        int c;
-        int l = utf8_tounicode(str, &c);
-        charlen++;
-        str += l;
-        bytelen -= l;
-    }
-    return charlen;
+    struct _timeb tb;
+
+    _ftime(&tb);
+    tv->tv_sec = tb.time;
+    tv->tv_usec = tb.millitm * 1000;
+
+    return 0;
 }
 
-int utf8_index(const char *str, int index)
+
+DIR *opendir(const char *name)
 {
-    const char *s = str;
-    while (index--) {
-        int c;
-        s += utf8_tounicode(s, &c);
+    DIR *dir = 0;
+
+    if (name && name[0]) {
+        size_t base_length = strlen(name);
+        const char *all =       
+            strchr("/\\", name[base_length - 1]) ? "*" : "/*";
+
+        if ((dir = (DIR *) Jim_Alloc(sizeof *dir)) != 0 &&
+            (dir->name = (char *)Jim_Alloc(base_length + strlen(all) + 1)) != 0) {
+            strcat(strcpy(dir->name, name), all);
+
+            if ((dir->handle = (long)_findfirst(dir->name, &dir->info)) != -1)
+                dir->result.d_name = 0;
+            else {              
+                Jim_Free(dir->name);
+                Jim_Free(dir);
+                dir = 0;
+            }
+        }
+        else {                  
+            Jim_Free(dir);
+            dir = 0;
+            errno = ENOMEM;
+        }
     }
-    return s - str;
+    else {
+        errno = EINVAL;
+    }
+    return dir;
 }
 
-int utf8_charequal(const char *s1, const char *s2)
+int closedir(DIR * dir)
 {
-    int c1, c2;
+    int result = -1;
 
-    utf8_tounicode(s1, &c1);
-    utf8_tounicode(s2, &c2);
-
-    return c1 == c2;
-}
-
-int utf8_prev_len(const char *str, int len)
-{
-    int n = 1;
-
-    assert(len > 0);
-
-    /* Look up to len chars backward for a start-of-char byte */
-    while (--len) {
-        if ((str[-n] & 0x80) == 0) {
-            /* Start of a 1-byte char */
-            break;
-        }
-        if ((str[-n] & 0xc0) == 0xc0) {
-            /* Start of a multi-byte char */
-            break;
-        }
-        n++;
+    if (dir) {
+        if (dir->handle != -1)
+            result = _findclose(dir->handle);
+        Jim_Free(dir->name);
+        Jim_Free(dir);
     }
-    return n;
+    if (result == -1)           
+        errno = EBADF;
+    return result;
 }
 
-int utf8_tounicode(const char *str, int *uc)
-{
-    unsigned const char *s = (unsigned const char *)str;
-
-    if (s[0] < 0xc0) {
-        *uc = s[0];
-        return 1;
-    }
-    if (s[0] < 0xe0) {
-        if ((s[1] & 0xc0) == 0x80) {
-            *uc = ((s[0] & ~0xc0) << 6) | (s[1] & ~0x80);
-            return 2;
-        }
-    }
-    else if (s[0] < 0xf0) {
-        if (((str[1] & 0xc0) == 0x80) && ((str[2] & 0xc0) == 0x80)) {
-            *uc = ((s[0] & ~0xe0) << 12) | ((s[1] & ~0x80) << 6) | (s[2] & ~0x80);
-            return 3;
-        }
-    }
-
-    /* Invalid sequence, so just return the byte */
-    *uc = *s;
-    return 1;
-}
-
-struct casemap {
-    unsigned short code;    /* code point */
-    signed char lowerdelta; /* add for lowercase, or if -128 use the ext table */
-    signed char upperdelta; /* add for uppercase, or offset into the ext table */
-};
-
-/* Extended table for codepoints where |delta| > 127 */
-struct caseextmap {
-    unsigned short lower;
-    unsigned short upper;
-};
-
-/* Generated mapping tables */
-#include "_unicode_mapping.c"
-
-#define NUMCASEMAP sizeof(unicode_case_mapping) / sizeof(*unicode_case_mapping)
-
-static int cmp_casemap(const void *key, const void *cm)
+struct dirent *readdir(DIR * dir)
 {
-    return *(int *)key - (int)((const struct casemap *)cm)->code;
-}
+    struct dirent *result = 0;
 
-static int utf8_map_case(int uc, int upper)
-{
-    const struct casemap *cm = bsearch(&uc, unicode_case_mapping, NUMCASEMAP, sizeof(*unicode_case_mapping), cmp_casemap);
-
-    if (cm) {
-        if (cm->lowerdelta == -128) {
-            uc = upper ? unicode_extmap[cm->upperdelta].upper : unicode_extmap[cm->upperdelta].lower;
+    if (dir && dir->handle != -1) {
+        if (!dir->result.d_name || _findnext(dir->handle, &dir->info) != -1) {
+            result = &dir->result;
+            result->d_name = dir->info.name;
         }
-        else {
-            uc += upper ? cm->upperdelta : cm->lowerdelta;
-        }
+    }
+    else {
+        errno = EBADF;
     }
-    return uc;
+    return result;
 }
-
-int utf8_upper(int uc)
-{
-    if (isascii(uc)) {
-        return toupper(uc);
-    }
-    return utf8_map_case(uc, 1);
-}
-
-int utf8_lower(int uc)
-{
-    if (isascii(uc)) {
-        return tolower(uc);
-    }
-
-    return utf8_map_case(uc, 0);
-}
-
+#endif
 #endif
+#ifndef JIM_BOOTSTRAP_LIB_ONLY
 #include <errno.h>
 #include <string.h>
 
 #ifdef USE_LINENOISE
 #include <unistd.h>
@@ -21476,11 +20586,11 @@
 
             snprintf(prompt, sizeof(prompt), "%c> ", state);
         }
 #ifdef USE_LINENOISE
         if (strcmp(str, "h") == 0) {
-            /* built-in history command */
+            
             int i;
             int len;
             char **history = linenoiseHistory(&len);
             for (i = 0; i < len; i++) {
                 printf("%4d %s\n", i + 1, history[i]);
@@ -21513,2228 +20623,25 @@
     }
   out:
     Jim_Free(history_file);
     return JIM_OK;
 }
-/* 
- * Implements the internals of the format command for jim
- *
- * The FreeBSD license
- * 
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above
- *    copyright notice, this list of conditions and the following
- *    disclaimer in the documentation and/or other materials
- *    provided with the distribution.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE JIM TCL PROJECT ``AS IS'' AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
- * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
- * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
- * JIM TCL PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
- * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
- * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- * 
- * The views and conclusions contained in the software and documentation
- * are those of the authors and should not be interpreted as representing
- * official policies, either expressed or implied, of the Jim Tcl Project.
- *
- * Based on code originally from Tcl 8.5:
- *
- * Copyright (c) 1995-1997 Sun Microsystems, Inc.
- * Copyright (c) 1999 by Scriptics Corporation.
- *
- * See the file "tcl.license.terms" for information on usage and redistribution of
- * this file, and for a DISCLAIMER OF ALL WARRANTIES.
- */
-#include <ctype.h>
-#include <string.h>
-
-
-#define JIM_UTF_MAX 3
-#define JIM_INTEGER_SPACE 24
-#define MAX_FLOAT_WIDTH 320
-
-/**
- * Apply the printf-like format in fmtObjPtr with the given arguments.
- *
- * Returns a new object with zero reference count if OK, or NULL on error.
- */
-Jim_Obj *Jim_FormatString(Jim_Interp *interp, Jim_Obj *fmtObjPtr, int objc, Jim_Obj *const *objv)
-{
-    const char *span, *format, *formatEnd, *msg;
-    int numBytes = 0, objIndex = 0, gotXpg = 0, gotSequential = 0;
-    static const char *mixedXPG =
-	    "cannot mix \"%\" and \"%n$\" conversion specifiers";
-    static const char *badIndex[2] = {
-	"not enough arguments for all format specifiers",
-	"\"%n$\" argument index out of range"
-    };
-    int formatLen;
-    Jim_Obj *resultPtr;
-
-    /* A single buffer is used to store numeric fields (with sprintf())
-     * This buffer is allocated/reallocated as necessary
-     */
-    char *num_buffer = NULL;
-    int num_buffer_size = 0;
-
-    span = format = Jim_GetString(fmtObjPtr, &formatLen);
-    formatEnd = format + formatLen;
-    resultPtr = Jim_NewStringObj(interp, "", 0);
-
-    while (format != formatEnd) {
-	char *end;
-	int gotMinus, sawFlag;
-	int gotPrecision, useShort;
-	long width, precision;
-	int newXpg;
-	int ch;
-	int step;
-	int doubleType;
-	char pad = ' ';
-	char spec[2*JIM_INTEGER_SPACE + 12];
-	char *p;
-
-	int formatted_chars;
-	int formatted_bytes;
-	const char *formatted_buf;
-
-	step = utf8_tounicode(format, &ch);
-	format += step;
-	if (ch != '%') {
-	    numBytes += step;
-	    continue;
-	}
-	if (numBytes) {
-	    Jim_AppendString(interp, resultPtr, span, numBytes);
-	    numBytes = 0;
-	}
-
-	/*
-	 * Saw a % : process the format specifier.
-	 *
-	 * Step 0. Handle special case of escaped format marker (i.e., %%).
-	 */
-
-	step = utf8_tounicode(format, &ch);
-	if (ch == '%') {
-	    span = format;
-	    numBytes = step;
-	    format += step;
-	    continue;
-	}
-
-	/*
-	 * Step 1. XPG3 position specifier
-	 */
-
-	newXpg = 0;
-	if (isdigit(ch)) {
-	    int position = strtoul(format, &end, 10);
-	    if (*end == '$') {
-		newXpg = 1;
-		objIndex = position - 1;
-		format = end + 1;
-		step = utf8_tounicode(format, &ch);
-	    }
-	}
-	if (newXpg) {
-	    if (gotSequential) {
-		msg = mixedXPG;
-		goto errorMsg;
-	    }
-	    gotXpg = 1;
-	} else {
-	    if (gotXpg) {
-		msg = mixedXPG;
-		goto errorMsg;
-	    }
-	    gotSequential = 1;
-	}
-	if ((objIndex < 0) || (objIndex >= objc)) {
-	    msg = badIndex[gotXpg];
-	    goto errorMsg;
-	}
-
-	/*
-	 * Step 2. Set of flags. Also build up the sprintf spec.
-	 */
-	p = spec;
-	*p++ = '%';
-
-	gotMinus = 0;
-	sawFlag = 1;
-	do {
-	    switch (ch) {
-	    case '-':
-		gotMinus = 1;
-		break;
-	    case '0':
-		pad = ch;
-		break;
-	    case ' ':
-	    case '+':
-	    case '#':
-		break;
-	    default:
-		sawFlag = 0;
-		continue;
-	    }
-	    *p++ = ch;
-	    format += step;
-	    step = utf8_tounicode(format, &ch);
-	} while (sawFlag);
-
-	/*
-	 * Step 3. Minimum field width.
-	 */
-
-	width = 0;
-	if (isdigit(ch)) {
-	    width = strtoul(format, &end, 10);
-	    format = end;
-	    step = utf8_tounicode(format, &ch);
-	} else if (ch == '*') {
-	    if (objIndex >= objc - 1) {
-		msg = badIndex[gotXpg];
-		goto errorMsg;
-	    }
-	    if (Jim_GetLong(interp, objv[objIndex], &width) != JIM_OK) {
-		goto error;
-	    }
-	    if (width < 0) {
-		width = -width;
-		if (!gotMinus) {
-		    *p++ = '-';
-		    gotMinus = 1;
-		}
-	    }
-	    objIndex++;
-	    format += step;
-	    step = utf8_tounicode(format, &ch);
-	}
-
-	/*
-	 * Step 4. Precision.
-	 */
-
-	gotPrecision = precision = 0;
-	if (ch == '.') {
-	    gotPrecision = 1;
-	    format += step;
-	    step = utf8_tounicode(format, &ch);
-	}
-	if (isdigit(ch)) {
-	    precision = strtoul(format, &end, 10);
-	    format = end;
-	    step = utf8_tounicode(format, &ch);
-	} else if (ch == '*') {
-	    if (objIndex >= objc - 1) {
-		msg = badIndex[gotXpg];
-		goto errorMsg;
-	    }
-	    if (Jim_GetLong(interp, objv[objIndex], &precision) != JIM_OK) {
-		goto error;
-	    }
-
-	    /*
-	     * TODO: Check this truncation logic.
-	     */
-
-	    if (precision < 0) {
-		precision = 0;
-	    }
-	    objIndex++;
-	    format += step;
-	    step = utf8_tounicode(format, &ch);
-	}
-
-	/*
-	 * Step 5. Length modifier.
-	 */
-
-	useShort = 0;
-	if (ch == 'h') {
-	    useShort = 1;
-	    format += step;
-	    step = utf8_tounicode(format, &ch);
-	} else if (ch == 'l') {
-	    /* Just for compatibility. All non-short integers are wide. */
-	    format += step;
-	    step = utf8_tounicode(format, &ch);
-	    if (ch == 'l') {
-		format += step;
-		step = utf8_tounicode(format, &ch);
-	    }
-	}
-
-	format += step;
-	span = format;
-
-	/*
-	 * Step 6. The actual conversion character.
-	 */
-
-	if (ch == 'i') {
-	    ch = 'd';
-	}
-
-	doubleType = 0;
-
-	/* Each valid conversion will set:
-	 * formatted_buf   - the result to be added
-	 * formatted_chars - the length of formatted_buf in characters 
-	 * formatted_bytes - the length of formatted_buf in bytes
-	 */
-	switch (ch) {
-	case '\0':
-	    msg = "format string ended in middle of field specifier";
-	    goto errorMsg;
-	case 's': {
-	    formatted_buf = Jim_GetString(objv[objIndex], &formatted_bytes);
-	    formatted_chars = Jim_Utf8Length(interp, objv[objIndex]);
-	    if (gotPrecision && (precision < formatted_chars)) {
-		/* Need to build a (null terminated) truncated string */
-		formatted_chars = precision;
-		formatted_bytes = utf8_index(formatted_buf, precision);
-	    }
-	    break;
-	}
-	case 'c': {
-	    jim_wide code;
-
-	    if (Jim_GetWide(interp, objv[objIndex], &code) != JIM_OK) {
-		goto error;
-	    }
-	    /* Just store the value in the 'spec' buffer */
-	    formatted_bytes = utf8_fromunicode(spec, code);
-	    formatted_buf = spec;
-	    formatted_chars = 1;
-	    break;
-	}
-
-	case 'e':
-	case 'E':
-	case 'f':
-	case 'g':
-	case 'G':
-	    doubleType = 1;
-	    /* fall through */
-	case 'd':
-	case 'u':
-	case 'o':
-	case 'x':
-	case 'X': {
-	    jim_wide w;
-	    double d;
-	    int length;
-
-	    /* Fill in the width and precision */
-	    if (width) {
-		p += sprintf(p, "%ld", width);
-	    }
-	    if (gotPrecision) {
-		p += sprintf(p, ".%ld", precision);
-	    }
-
-	    /* Now the modifier, and get the actual value here */
-	    if (doubleType) {
-		if (Jim_GetDouble(interp, objv[objIndex], &d) != JIM_OK) {
-		    goto error;
-		}
-		length = MAX_FLOAT_WIDTH;
-	    }
-	    else {
-		if (Jim_GetWide(interp, objv[objIndex], &w) != JIM_OK) {
-		    goto error;
-		}
-		length = JIM_INTEGER_SPACE;
-		if (useShort) {
-		    *p++ = 'h';
-		    if (ch == 'd') {
-			w = (short)w;
-		    }
-		    else {
-			w = (unsigned short)w;
-		    }
-		}
-		else {
-		    *p++ = 'l';
-#ifdef HAVE_LONG_LONG
-		    if (sizeof(long long) == sizeof(jim_wide)) {
-			*p++ = 'l';
-		    }
-#endif
-		}
-	    }
-
-	    *p++ = (char) ch;
-	    *p = '\0';
-
-	    /* Adjust length for width and precision */
-	    if (width > length) {
-		length = width;
-	    }
-	    if (gotPrecision) {
-		length += precision;
-	    }
-
-	    /* Increase the size of the buffer if needed */
-	    if (num_buffer_size < length + 1) {
-		num_buffer_size = length + 1;
-		num_buffer = Jim_Realloc(num_buffer, num_buffer_size);
-	    }
-
-	    if (doubleType) {
-		snprintf(num_buffer, length + 1, spec, d);
-	    }
-	    else {
-		formatted_bytes = snprintf(num_buffer, length + 1, spec, w);
-	    }
-	    formatted_chars = formatted_bytes = strlen(num_buffer);
-	    formatted_buf = num_buffer;
-	    break;
-	}
-
-	default: {
-	    /* Just reuse the 'spec' buffer */
-	    spec[0] = ch;
-	    spec[1] = '\0';
-	    Jim_SetResultFormatted(interp, "bad field specifier \"%s\"", spec);
-	    goto error;
-	}
-	}
-
-	if (!gotMinus) {
-	    while (formatted_chars < width) {
-		Jim_AppendString(interp, resultPtr, &pad, 1);
-		formatted_chars++;
-	    }
-	}
-
-	Jim_AppendString(interp, resultPtr, formatted_buf, formatted_bytes);
-
-	while (formatted_chars < width) {
-	    Jim_AppendString(interp, resultPtr, &pad, 1);
-	    formatted_chars++;
-	}
-
-	objIndex += gotSequential;
-    }
-    if (numBytes) {
-	Jim_AppendString(interp, resultPtr, span, numBytes);
-    }
-
-    Jim_Free(num_buffer);
-    return resultPtr;
-
-  errorMsg:
-    Jim_SetResultString(interp, msg, -1);
-  error:
-    Jim_FreeNewObj(interp, resultPtr);
-    Jim_Free(num_buffer);
-    return NULL;
-}
-/*
- * regcomp and regexec -- regsub and regerror are elsewhere
- *
- *	Copyright (c) 1986 by University of Toronto.
- *	Written by Henry Spencer.  Not derived from licensed software.
- *
- *	Permission is granted to anyone to use this software for any
- *	purpose on any computer system, and to redistribute it freely,
- *	subject to the following restrictions:
- *
- *	1. The author is not responsible for the consequences of use of
- *		this software, no matter how awful, even if they arise
- *		from defects in it.
- *
- *	2. The origin of this software must not be misrepresented, either
- *		by explicit claim or by omission.
- *
- *	3. Altered versions must be plainly marked as such, and must not
- *		be misrepresented as being the original software.
- *** THIS IS AN ALTERED VERSION.  It was altered by John Gilmore,
- *** hoptoad!gnu, on 27 Dec 1986, to add \n as an alternative to |
- *** to assist in implementing egrep.
- *** THIS IS AN ALTERED VERSION.  It was altered by John Gilmore,
- *** hoptoad!gnu, on 27 Dec 1986, to add \< and \> for word-matching
- *** as in BSD grep and ex.
- *** THIS IS AN ALTERED VERSION.  It was altered by John Gilmore,
- *** hoptoad!gnu, on 28 Dec 1986, to optimize characters quoted with \.
- *** THIS IS AN ALTERED VERSION.  It was altered by James A. Woods,
- *** ames!jaw, on 19 June 1987, to quash a regcomp() redundancy.
- *** THIS IS AN ALTERED VERSION.  It was altered by Christopher Seiwald
- *** seiwald@vix.com, on 28 August 1993, for use in jam.  Regmagic.h
- *** was moved into regexp.h, and the include of regexp.h now uses "'s
- *** to avoid conflicting with the system regexp.h.  Const, bless its
- *** soul, was removed so it can compile everywhere.  The declaration
- *** of strchr() was in conflict on AIX, so it was removed (as it is
- *** happily defined in string.h).
- *** THIS IS AN ALTERED VERSION.  It was altered by Christopher Seiwald
- *** seiwald@perforce.com, on 20 January 2000, to use function prototypes.
- *** THIS IS AN ALTERED VERSION.  It was altered by Christopher Seiwald
- *** seiwald@perforce.com, on 05 November 2002, to const string literals.
- *
- *   THIS IS AN ALTERED VERSION.  It was altered by Steve Bennett <steveb@workware.net.au>
- *   on 16 October 2010, to remove static state and add better Tcl ARE compatibility.
- *   This includes counted repetitions, UTF-8 support, character classes,
- *   shorthand character classes, increased number of parentheses to 100,
- *   backslash escape sequences. It also removes \n as an alternative to |.
- *
- * Beware that some of this code is subtly aware of the way operator
- * precedence is structured in regular expressions.  Serious changes in
- * regular-expression syntax might require a total rethink.
- */
-#include <stdio.h>
-#include <ctype.h>
-#include <stdlib.h>
-#include <string.h>
-
-
-#if !defined(HAVE_REGCOMP) || defined(JIM_REGEXP)
-
-/*
- * Structure for regexp "program".  This is essentially a linear encoding
- * of a nondeterministic finite-state machine (aka syntax charts or
- * "railroad normal form" in parsing technology).  Each node is an opcode
- * plus a "next" pointer, possibly plus an operand.  "Next" pointers of
- * all nodes except BRANCH implement concatenation; a "next" pointer with
- * a BRANCH on both ends of it is connecting two alternatives.  (Here we
- * have one of the subtle syntax dependencies:  an individual BRANCH (as
- * opposed to a collection of them) is never concatenated with anything
- * because of operator precedence.)  The operand of some types of node is
- * a literal string; for others, it is a node leading into a sub-FSM.  In
- * particular, the operand of a BRANCH node is the first node of the branch.
- * (NB this is *not* a tree structure:  the tail of the branch connects
- * to the thing following the set of BRANCHes.)  The opcodes are:
- */
-
-/* This *MUST* be less than (255-20)/2=117 */
-#define REG_MAX_PAREN 100
-
-/* definition	number	opnd?	meaning */
-#define	END	0	/* no	End of program. */
-#define	BOL	1	/* no	Match "" at beginning of line. */
-#define	EOL	2	/* no	Match "" at end of line. */
-#define	ANY	3	/* no	Match any one character. */
-#define	ANYOF	4	/* str	Match any character in this string. */
-#define	ANYBUT	5	/* str	Match any character not in this string. */
-#define	BRANCH	6	/* node	Match this alternative, or the next... */
-#define	BACK	7	/* no	Match "", "next" ptr points backward. */
-#define	EXACTLY	8	/* str	Match this string. */
-#define	NOTHING	9	/* no	Match empty string. */
-#define	REP		10	/* max,min	Match this (simple) thing [min,max] times. */
-#define	REPMIN	11	/* max,min	Match this (simple) thing [min,max] times, mininal match. */
-#define	REPX	12	/* max,min	Match this (complex) thing [min,max] times. */
-#define	REPXMIN	13	/* max,min	Match this (complex) thing [min,max] times, minimal match. */
-
-#define	WORDA	15	/* no	Match "" at wordchar, where prev is nonword */
-#define	WORDZ	16	/* no	Match "" at nonwordchar, where prev is word */
-#define	OPEN	20	/* no	Mark this point in input as start of #n. */
-			/*	OPEN+1 is number 1, etc. */
-#define	CLOSE	(OPEN+REG_MAX_PAREN)	/* no	Analogous to OPEN. */
-#define	CLOSE_END	(CLOSE+REG_MAX_PAREN)
-
-/*
- * The first byte of the regexp internal "program" is actually this magic
- * number; the start node begins in the second byte.
- */
-#define	REG_MAGIC	0xFADED00D
-
-/*
- * Opcode notes:
- *
- * BRANCH	The set of branches constituting a single choice are hooked
- *		together with their "next" pointers, since precedence prevents
- *		anything being concatenated to any individual branch.  The
- *		"next" pointer of the last BRANCH in a choice points to the
- *		thing following the whole choice.  This is also where the
- *		final "next" pointer of each individual branch points; each
- *		branch starts with the operand node of a BRANCH node.
- *
- * BACK		Normal "next" pointers all implicitly point forward; BACK
- *		exists to make loop structures possible.
- *
- * STAR,PLUS	'?', and complex '*' and '+', are implemented as circular
- *		BRANCH structures using BACK.  Simple cases (one character
- *		per match) are implemented with STAR and PLUS for speed
- *		and to minimize recursive plunges.
- *
- * OPEN,CLOSE	...are numbered at compile time.
- */
-
-/*
- * A node is one char of opcode followed by two chars of "next" pointer.
- * "Next" pointers are stored as two 8-bit pieces, high order first.  The
- * value is a positive offset from the opcode of the node containing it.
- * An operand, if any, simply follows the node.  (Note that much of the
- * code generation knows about this implicit relationship.)
- *
- * Using two bytes for the "next" pointer is vast overkill for most things,
- * but allows patterns to get big without disasters.
- */
-#define	OP(preg, p)	(preg->program[p])
-#define	NEXT(preg, p)	(preg->program[p + 1])
-#define	OPERAND(p)	((p) + 2)
-
-/*
- * See regmagic.h for one further detail of program structure.
- */
-
-
-/*
- * Utility definitions.
- */
-
-#define	FAIL(R,M)	{ (R)->err = (M); return (M); }
-#define	ISMULT(c)	((c) == '*' || (c) == '+' || (c) == '?' || (c) == '{')
-#define	META	"^$.[()|?{+*"
-
-/*
- * Flags to be passed up and down.
- */
-#define	HASWIDTH	01	/* Known never to match null string. */
-#define	SIMPLE		02	/* Simple enough to be STAR/PLUS operand. */
-#define	SPSTART		04	/* Starts with * or +. */
-#define	WORST		0	/* Worst case. */
-
-#define MAX_REP_COUNT 1000000
-
-/*
- * Forward declarations for regcomp()'s friends.
- */
-static int reg(regex_t *preg, int paren /* Parenthesized? */, int *flagp );
-static int regpiece(regex_t *preg, int *flagp );
-static int regbranch(regex_t *preg, int *flagp );
-static int regatom(regex_t *preg, int *flagp );
-static int regnode(regex_t *preg, int op );
-static int regnext(regex_t *preg, int p );
-static void regc(regex_t *preg, int b );
-static int reginsert(regex_t *preg, int op, int size, int opnd );
-static void regtail_(regex_t *preg, int p, int val, int line );
-static void regoptail(regex_t *preg, int p, int val );
-#define regtail(PREG, P, VAL) regtail_(PREG, P, VAL, __LINE__)
-
-static int reg_range_find(const int *string, int c);
-static const char *str_find(const char *string, int c, int nocase);
-static int prefix_cmp(const int *prog, int proglen, const char *string, int nocase);
-
-/*#define DEBUG*/
-#ifdef DEBUG
-int regnarrate = 0;
-static void regdump(regex_t *preg);
-static const char *regprop( int op );
-#endif
-
-
-/**
- * Returns the length of the null-terminated integer sequence.
- */
-static int str_int_len(const int *seq)
-{
-	int n = 0;
-	while (*seq++) {
-		n++;
-	}
-	return n;
-}
-
-/*
- - regcomp - compile a regular expression into internal code
- *
- * We can't allocate space until we know how big the compiled form will be,
- * but we can't compile it (and thus know how big it is) until we've got a
- * place to put the code.  So we cheat:  we compile it twice, once with code
- * generation turned off and size counting turned on, and once "for real".
- * This also means that we don't allocate space until we are sure that the
- * thing really will compile successfully, and we never have to move the
- * code and thus invalidate pointers into it.  (Note that it has to be in
- * one piece because free() must be able to free it all.)
- *
- * Beware that the optimization-preparation code in here knows about some
- * of the structure of the compiled regexp.
- */
-int regcomp(regex_t *preg, const char *exp, int cflags)
-{
-	int scan;
-	int longest;
-	unsigned len;
-	int flags;
-
-#ifdef DEBUG
-	fprintf(stderr, "Compiling: '%s'\n", exp);
-#endif
-	memset(preg, 0, sizeof(*preg));
-
-	if (exp == NULL)
-		FAIL(preg, REG_ERR_NULL_ARGUMENT);
-
-	/* First pass: determine size, legality. */
-	preg->cflags = cflags;
-	preg->regparse = exp;
-	/* XXX: For now, start unallocated */
-	preg->program = NULL;
-	preg->proglen = 0;
-
-#if 1
-	/* Allocate space. */
-	preg->proglen = (strlen(exp) + 1) * 5;
-	preg->program = malloc(preg->proglen * sizeof(int));
-	if (preg->program == NULL)
-		FAIL(preg, REG_ERR_NOMEM);
-#endif
-
-	/* Note that since we store a magic value as the first item in the program,
-	 * program offsets will never be 0
-	 */
-	regc(preg, REG_MAGIC);
-	if (reg(preg, 0, &flags) == 0) {
-		return preg->err;
-	}
-
-	/* Small enough for pointer-storage convention? */
-	if (preg->re_nsub >= REG_MAX_PAREN)		/* Probably could be 65535L. */
-		FAIL(preg,REG_ERR_TOO_BIG);
-
-	/* Dig out information for optimizations. */
-	preg->regstart = 0;	/* Worst-case defaults. */
-	preg->reganch = 0;
-	preg->regmust = 0;
-	preg->regmlen = 0;
-	scan = 1;			/* First BRANCH. */
-	if (OP(preg, regnext(preg, scan)) == END) {		/* Only one top-level choice. */
-		scan = OPERAND(scan);
-
-		/* Starting-point info. */
-		if (OP(preg, scan) == EXACTLY) {
-			preg->regstart = preg->program[OPERAND(scan)];
-		}
-		else if (OP(preg, scan) == BOL)
-			preg->reganch++;
-
-		/*
-		 * If there's something expensive in the r.e., find the
-		 * longest literal string that must appear and make it the
-		 * regmust.  Resolve ties in favor of later strings, since
-		 * the regstart check works with the beginning of the r.e.
-		 * and avoiding duplication strengthens checking.  Not a
-		 * strong reason, but sufficient in the absence of others.
-		 */
-		if (flags&SPSTART) {
-			longest = 0;
-			len = 0;
-			for (; scan != 0; scan = regnext(preg, scan)) {
-				if (OP(preg, scan) == EXACTLY) {
-					int plen = str_int_len(preg->program + OPERAND(scan));
-					if (plen >= len) {
-						longest = OPERAND(scan);
-						len = plen;
-					}
-				}
-			}
-			preg->regmust = longest;
-			preg->regmlen = len;
-		}
-	}
-
-#ifdef DEBUG
-	regdump(preg);
-#endif
-
-	return 0;
-}
-
-/*
- - reg - regular expression, i.e. main body or parenthesized thing
- *
- * Caller must absorb opening parenthesis.
- *
- * Combining parenthesis handling with the base level of regular expression
- * is a trifle forced, but the need to tie the tails of the branches to what
- * follows makes it hard to avoid.
- */
-static int reg(regex_t *preg, int paren /* Parenthesized? */, int *flagp )
-{
-	int ret;
-	int br;
-	int ender;
-	int parno = 0;
-	int flags;
-
-	*flagp = HASWIDTH;	/* Tentatively. */
-
-	/* Make an OPEN node, if parenthesized. */
-	if (paren) {
-		parno = ++preg->re_nsub;
-		ret = regnode(preg, OPEN+parno);
-	} else
-		ret = 0;
-
-	/* Pick up the branches, linking them together. */
-	br = regbranch(preg, &flags);
-	if (br == 0)
-		return 0;
-	if (ret != 0)
-		regtail(preg, ret, br);	/* OPEN -> first. */
-	else
-		ret = br;
-	if (!(flags&HASWIDTH))
-		*flagp &= ~HASWIDTH;
-	*flagp |= flags&SPSTART;
-	while (*preg->regparse == '|') {
-		preg->regparse++;
-		br = regbranch(preg, &flags);
-		if (br == 0)
-			return 0;
-		regtail(preg, ret, br);	/* BRANCH -> BRANCH. */
-		if (!(flags&HASWIDTH))
-			*flagp &= ~HASWIDTH;
-		*flagp |= flags&SPSTART;
-	}
-
-	/* Make a closing node, and hook it on the end. */
-	ender = regnode(preg, (paren) ? CLOSE+parno : END);
-	regtail(preg, ret, ender);
-
-	/* Hook the tails of the branches to the closing node. */
-	for (br = ret; br != 0; br = regnext(preg, br))
-		regoptail(preg, br, ender);
-
-	/* Check for proper termination. */
-	if (paren && *preg->regparse++ != ')') {
-		preg->err = REG_ERR_UNMATCHED_PAREN;
-		return 0;
-	} else if (!paren && *preg->regparse != '\0') {
-		if (*preg->regparse == ')') {
-			preg->err = REG_ERR_UNMATCHED_PAREN;
-			return 0;
-		} else {
-			preg->err = REG_ERR_JUNK_ON_END;
-			return 0;
-		}
-	}
-
-	return(ret);
-}
-
-/*
- - regbranch - one alternative of an | operator
- *
- * Implements the concatenation operator.
- */
-static int regbranch(regex_t *preg, int *flagp )
-{
-	int ret;
-	int chain;
-	int latest;
-	int flags;
-
-	*flagp = WORST;		/* Tentatively. */
-
-	ret = regnode(preg, BRANCH);
-	chain = 0;
-	while (*preg->regparse != '\0' && *preg->regparse != ')' &&
-	       *preg->regparse != '|') {
-		latest = regpiece(preg, &flags);
-		if (latest == 0)
-			return 0;
-		*flagp |= flags&HASWIDTH;
-		if (chain == 0) {/* First piece. */
-			*flagp |= flags&SPSTART;
-		}
-		else {
-			regtail(preg, chain, latest);
-		}
-		chain = latest;
-	}
-	if (chain == 0)	/* Loop ran zero times. */
-		(void) regnode(preg, NOTHING);
-
-	return(ret);
-}
-
-/*
- - regpiece - something followed by possible [*+?]
- *
- * Note that the branching code sequences used for ? and the general cases
- * of * and + are somewhat optimized:  they use the same NOTHING node as
- * both the endmarker for their branch list and the body of the last branch.
- * It might seem that this node could be dispensed with entirely, but the
- * endmarker role is not redundant.
- */
-static int regpiece(regex_t *preg, int *flagp)
-{
-	int ret;
-	char op;
-	int next;
-	int flags;
-	int chain = 0;
-	int min;
-	int max;
-
-	ret = regatom(preg, &flags);
-	if (ret == 0)
-		return 0;
-
-	op = *preg->regparse;
-	if (!ISMULT(op)) {
-		*flagp = flags;
-		return(ret);
-	}
-
-	if (!(flags&HASWIDTH) && op != '?') {
-		preg->err = REG_ERR_OPERAND_COULD_BE_EMPTY;
-		return 0;
-	}
-
-	/* Handle braces (counted repetition) by expansion */
-	if (op == '{') {
-		char *end;
-
-		min = strtoul(preg->regparse + 1, &end, 10);
-		if (end == preg->regparse + 1) {
-			preg->err = REG_ERR_BAD_COUNT;
-			return 0;
-		}
-		if (*end == '}') {
-			max = min;
-		}
-		else {
-			preg->regparse = end;
-			max = strtoul(preg->regparse + 1, &end, 10);
-			if (*end != '}') {
-				preg->err = REG_ERR_UNMATCHED_BRACES;
-				return 0;
-			}
-		}
-		if (end == preg->regparse + 1) {
-			max = MAX_REP_COUNT;
-		}
-		else if (max < min || max >= 100) {
-			preg->err = REG_ERR_BAD_COUNT;
-			return 0;
-		}
-		if (min >= 100) {
-			preg->err = REG_ERR_BAD_COUNT;
-			return 0;
-		}
-
-		preg->regparse = strchr(preg->regparse, '}');
-	}
-	else {
-		min = (op == '+');
-		max = (op == '?' ? 1 : MAX_REP_COUNT);
-	}
-
-	if (preg->regparse[1] == '?') {
-		preg->regparse++;
-		next = reginsert(preg, flags & SIMPLE ? REPMIN : REPXMIN, 5, ret);
-	}
-	else {
-		next = reginsert(preg, flags & SIMPLE ? REP: REPX, 5, ret);
-	}
-	preg->program[ret + 2] = max;
-	preg->program[ret + 3] = min;
-	preg->program[ret + 4] = 0;
-
-	*flagp = (min) ? (WORST|HASWIDTH) : (WORST|SPSTART);
-
-	if (!(flags & SIMPLE)) {
-		int back = regnode(preg, BACK);
-		regtail(preg, back, ret);
-		regtail(preg, next, back);
-	}
-
-	preg->regparse++;
-	if (ISMULT(*preg->regparse)) {
-		preg->err = REG_ERR_NESTED_COUNT;
-		return 0;
-	}
-
-	return chain ? chain : ret;
-}
-
-/**
- * Add all characters in the inclusive range between lower and upper.
- * 
- * Handles a swapped range (upper < lower).
- */
-static void reg_addrange(regex_t *preg, int lower, int upper)
-{
-	if (lower > upper) {
-		reg_addrange(preg, upper, lower);
-	}
-	/* Add a range as length, start */
-	regc(preg, upper - lower + 1);
-	regc(preg, lower);
-}
-
-/**
- * Add a null-terminated literal string as a set of ranges.
- */
-static void reg_addrange_str(regex_t *preg, const char *str)
-{
-	while (*str) {
-		reg_addrange(preg, *str, *str);
-		str++;
-	}
-}
-
-/**
- * Extracts the next unicode char from utf8.
- * 
- * If 'upper' is set, converts the char to uppercase.
- */
-static int reg_utf8_tounicode_case(const char *s, int *uc, int upper)
-{
-	int l = utf8_tounicode(s, uc);
-	if (upper) {
-		*uc = utf8_upper(*uc);
-	}
-	return l;
-}
-
-/**
- * Converts a hex digit to decimal.
- * 
- * Returns -1 for an invalid hex digit.
- */
-static int hexdigitval(int c)
-{
-	if (c >= '0' && c <= '9')
-		return c - '0';
-	if (c >= 'a' && c <= 'f')
-		return c - 'a' + 10;
-	if (c >= 'A' && c <= 'F')
-		return c - 'A' + 10;
-	return -1;
-}
-
-/**
- * Parses up to 'n' hex digits at 's' and stores the result in *uc.
- *
- * Returns the number of hex digits parsed.
- * If there are no hex digits, returns 0 and stores nothing.
- */
-static int parse_hex(const char *s, int n, int *uc)
-{
-	int val = 0;
-	int k;
-
-	for (k = 0; k < n; k++) {
-		int c = hexdigitval(*s++);
-		if (c == -1) {
-			break;
-		}
-		val = (val << 4) | c;
-	}
-	if (k) {
-		*uc = val;
-	}
-	return k;
-}
-
-/**
- * Call for chars after a backlash to decode the escape sequence.
- * 
- * Stores the result in *ch.
- *
- * Returns the number of bytes consumed.
- */
-static int reg_decode_escape(const char *s, int *ch)
-{
-	int n;
-	const char *s0 = s;
-
-	*ch = *s++;
-
-	switch (*ch) {
-		case 'b': *ch = '\b'; break;
-		case 'e': *ch = 27; break;
-		case 'f': *ch = '\f'; break;
-		case 'n': *ch = '\n'; break;
-		case 'r': *ch = '\r'; break;
-		case 't': *ch = '\t'; break;
-		case 'v': *ch = '\v'; break;
-		case 'u':
-			if ((n = parse_hex(s, 4, ch)) > 0) {
-				s += n;
-			}
-			break;
-		case 'x':
-			if ((n = parse_hex(s, 2, ch)) > 0) {
-				s += n;
-			}
-			break;
-		case '\0':
-			s--;
-			*ch = '\\';
-			break;
-	}
-	return s - s0;
-}
-
-/*
- - regatom - the lowest level
- *
- * Optimization:  gobbles an entire sequence of ordinary characters so that
- * it can turn them into a single node, which is smaller to store and
- * faster to run.  Backslashed characters are exceptions, each becoming a
- * separate node; the code is simpler that way and it's not worth fixing.
- */
-static int regatom(regex_t *preg, int *flagp)
-{
-	int ret;
-	int flags;
-	int nocase = (preg->cflags & REG_ICASE);
-
-	int ch;
-	int n = reg_utf8_tounicode_case(preg->regparse, &ch, nocase);
-
-	*flagp = WORST;		/* Tentatively. */
-
-	preg->regparse += n;
-	switch (ch) {
-	/* FIXME: these chars only have meaning at beg/end of pat? */
-	case '^':
-		ret = regnode(preg, BOL);
-		break;
-	case '$':
-		ret = regnode(preg, EOL);
-		break;
-	case '.':
-		ret = regnode(preg, ANY);
-		*flagp |= HASWIDTH|SIMPLE;
-		break;
-	case '[': {
-			const char *pattern = preg->regparse;
-
-			if (*pattern == '^') {	/* Complement of range. */
-				ret = regnode(preg, ANYBUT);
-				pattern++;
-			} else
-				ret = regnode(preg, ANYOF);
-
-			/* Special case. If the first char is ']' or '-', it is part of the set */
-			if (*pattern == ']' || *pattern == '-') {
-				reg_addrange(preg, *pattern, *pattern);
-				pattern++;
-			}
-
-			while (*pattern && *pattern != ']') {
-				/* Is this a range? a-z */
-				int start;
-				int end;
-
-				pattern += reg_utf8_tounicode_case(pattern, &start, nocase);
-				if (start == '\\') {
-					pattern += reg_decode_escape(pattern, &start);
-					if (start == 0) {
-						preg->err = REG_ERR_NULL_CHAR;
-						return 0;
-					}
-				}
-				if (pattern[0] == '-' && pattern[1]) {
-					/* skip '-' */
-					pattern += utf8_tounicode(pattern, &end);
-					pattern += reg_utf8_tounicode_case(pattern, &end, nocase);
-					if (end == '\\') {
-						pattern += reg_decode_escape(pattern, &end);
-						if (end == 0) {
-							preg->err = REG_ERR_NULL_CHAR;
-							return 0;
-						}
-					}
-
-					reg_addrange(preg, start, end);
-					continue;
-				}
-				if (start == '[') {
-					if (strncmp(pattern, ":alpha:]", 8) == 0) {
-						if ((preg->cflags & REG_ICASE) == 0) {
-							reg_addrange(preg, 'a', 'z');
-						}
-						reg_addrange(preg, 'A', 'Z');
-						pattern += 8;
-						continue;
-					}
-					if (strncmp(pattern, ":alnum:]", 8) == 0) {
-						if ((preg->cflags & REG_ICASE) == 0) {
-							reg_addrange(preg, 'a', 'z');
-						}
-						reg_addrange(preg, 'A', 'Z');
-						reg_addrange(preg, '0', '9');
-						pattern += 8;
-						continue;
-					}
-					if (strncmp(pattern, ":space:]", 8) == 0) {
-						reg_addrange_str(preg, " \t\r\n\f\v");
-						pattern += 8;
-						continue;
-					}
-				}
-				/* Not a range, so just add the char */
-				reg_addrange(preg, start, start);
-			}
-			regc(preg, '\0');
-
-			if (*pattern) {
-				pattern++;
-			}
-			preg->regparse = pattern;
-
-			*flagp |= HASWIDTH|SIMPLE;
-		}
-		break;
-	case '(':
-		ret = reg(preg, 1, &flags);
-		if (ret == 0)
-			return 0;
-		*flagp |= flags&(HASWIDTH|SPSTART);
-		break;
-	case '\0':
-	case '|':
-	case ')':
-		preg->err = REG_ERR_INTERNAL;
-		return 0;	/* Supposed to be caught earlier. */
-	case '?':
-	case '+':
-	case '*':
-	case '{':
-		preg->err = REG_ERR_COUNT_FOLLOWS_NOTHING;
-		return 0;
-	case '\\':
-		switch (*preg->regparse++) {
-		case '\0':
-			preg->err = REG_ERR_TRAILING_BACKSLASH;
-			return 0;
-		case '<':
-		case 'm':
-			ret = regnode(preg, WORDA);
-			break;
-		case '>':
-		case 'M':
-			ret = regnode(preg, WORDZ);
-			break;
-		case 'd':
-			ret = regnode(preg, ANYOF);
-			reg_addrange(preg, '0', '9');
-			regc(preg, '\0');
-			*flagp |= HASWIDTH|SIMPLE;
-			break;
-		case 'w':
-			ret = regnode(preg, ANYOF);
-			if ((preg->cflags & REG_ICASE) == 0) {
-				reg_addrange(preg, 'a', 'z');
-			}
-			reg_addrange(preg, 'A', 'Z');
-			reg_addrange(preg, '0', '9');
-			reg_addrange(preg, '_', '_');
-			regc(preg, '\0');
-			*flagp |= HASWIDTH|SIMPLE;
-			break;
-		case 's':
-			ret = regnode(preg, ANYOF);
-			reg_addrange_str(preg," \t\r\n\f\v");
-			regc(preg, '\0');
-			*flagp |= HASWIDTH|SIMPLE;
-			break;
-		/* FIXME: Someday handle \1, \2, ... */
-		default:
-			/* Handle general quoted chars in exact-match routine */
-			/* Back up to include the backslash */
-			preg->regparse--;
-			goto de_fault;
-		}
-		break;
-	de_fault:
-	default: {
-			/*
-			 * Encode a string of characters to be matched exactly.
-			 */
-			int added = 0;
-
-			/* Back up to pick up the first char of interest */
-			preg->regparse -= n;
-
-			ret = regnode(preg, EXACTLY);
-
-			/* Note that a META operator such as ? or * consumes the
-			 * preceding char.
-			 * Thus we must be careful to look ahead by 2 and add the
-			 * last char as it's own EXACTLY if necessary
-			 */
-
-			/* Until end of string or a META char is reached */
-			while (*preg->regparse && strchr(META, *preg->regparse) == NULL) {
-				n = reg_utf8_tounicode_case(preg->regparse, &ch, (preg->cflags & REG_ICASE));
-				if (ch == '\\' && preg->regparse[n]) {
-					/* Non-trailing backslash.
-					 * Is this a special escape, or a regular escape?
-					 */
-					if (strchr("<>mMwds", preg->regparse[n])) {
-						/* A special escape. All done with EXACTLY */
-						break;
-					}
-					/* Decode it. Note that we add the length for the escape
-					 * sequence to the length for the backlash so we can skip
-					 * the entire sequence, or not as required.
-					 */
-					n += reg_decode_escape(preg->regparse + n, &ch);
-					if (ch == 0) {
-						preg->err = REG_ERR_NULL_CHAR;
-						return 0;
-					}
-				}
-
-				/* Now we have one char 'ch' of length 'n'.
-				 * Check to see if the following char is a MULT
-				 */
-
-				if (ISMULT(preg->regparse[n])) {
-					/* Yes. But do we already have some EXACTLY chars? */
-					if (added) {
-						/* Yes, so return what we have and pick up the current char next time around */
-						break;
-					}
-					/* No, so add this single char and finish */
-					regc(preg, ch);
-					added++;
-					preg->regparse += n;
-					break;
-				}
-
-				/* No, so just add this char normally */
-				regc(preg, ch);
-				added++;
-				preg->regparse += n;
-			}
-			regc(preg, '\0');
-
-			*flagp |= HASWIDTH;
-			if (added == 1)
-				*flagp |= SIMPLE;
-			break;
-		}
-		break;
-	}
-
-	return(ret);
-}
-
-static void reg_grow(regex_t *preg, int n)
-{
-	if (preg->p + n >= preg->proglen) {
-		preg->proglen = (preg->p + n) * 2;
-		preg->program = realloc(preg->program, preg->proglen * sizeof(int));
-	}
-}
-
-/*
- - regnode - emit a node
- */
-/* Location. */
-static int regnode(regex_t *preg, int op)
-{
-	reg_grow(preg, 2);
-
-	preg->program[preg->p++] = op;
-	preg->program[preg->p++] = 0;
-
-	/* Return the start of the node */
-	return preg->p - 2;
-}
-
-/*
- - regc - emit (if appropriate) a byte of code
- */
-static void regc(regex_t *preg, int b )
-{
-	reg_grow(preg, 1);
-	preg->program[preg->p++] = b;
-}
-
-/*
- - reginsert - insert an operator in front of already-emitted operand
- *
- * Means relocating the operand.
- * Returns the new location of the original operand.
- */
-static int reginsert(regex_t *preg, int op, int size, int opnd )
-{
-	reg_grow(preg, size);
-
-	/* Move everything from opnd up */
-	memmove(preg->program + opnd + size, preg->program + opnd, sizeof(int) * (preg->p - opnd));
-	/* Zero out the new space */
-	memset(preg->program + opnd, 0, sizeof(int) * size);
-
-	preg->program[opnd] = op;
-
-	preg->p += size;
-
-	return opnd + size;
-}
-
-/*
- - regtail - set the next-pointer at the end of a node chain
- */
-static void regtail_(regex_t *preg, int p, int val, int line )
-{
-	int scan;
-	int temp;
-	int offset;
-
-	/* Find last node. */
-	scan = p;
-	for (;;) {
-		temp = regnext(preg, scan);
-		if (temp == 0)
-			break;
-		scan = temp;
-	}
-
-	if (OP(preg, scan) == BACK)
-		offset = scan - val;
-	else
-		offset = val - scan;
-
-	preg->program[scan + 1] = offset;
-}
-
-/*
- - regoptail - regtail on operand of first argument; nop if operandless
- */
-
-static void regoptail(regex_t *preg, int p, int val )
-{
-	/* "Operandless" and "op != BRANCH" are synonymous in practice. */
-	if (p != 0 && OP(preg, p) == BRANCH) {
-		regtail(preg, OPERAND(p), val);
-	}
-}
-
-/*
- * regexec and friends
- */
-
-/*
- * Forwards.
- */
-static int regtry(regex_t *preg, const char *string );
-static int regmatch(regex_t *preg, int prog);
-static int regrepeat(regex_t *preg, int p, int max);
-
-/*
- - regexec - match a regexp against a string
- */
-int regexec(regex_t  *preg,  const  char *string, size_t nmatch, regmatch_t pmatch[], int eflags)
-{
-	const char *s;
-	int scan;
-
-	/* Be paranoid... */
-	if (preg == NULL || preg->program == NULL || string == NULL) {
-		return REG_ERR_NULL_ARGUMENT;
-	}
-
-	/* Check validity of program. */
-	if (*preg->program != REG_MAGIC) {
-		return REG_ERR_CORRUPTED;
-	}
-
-#ifdef DEBUG
-	fprintf(stderr, "regexec: %s\n", string);
-	regdump(preg);
-#endif
-
-	preg->eflags = eflags;
-	preg->pmatch = pmatch;
-	preg->nmatch = nmatch;
-	preg->start = string;	/* All offsets are computed from here */
-
-	/* Must clear out the embedded repeat counts */
-	for (scan = OPERAND(1); scan != 0; scan = regnext(preg, scan)) {
-		switch (OP(preg, scan)) {
-		case REP:
-		case REPMIN:
-		case REPX:
-		case REPXMIN:
-			preg->program[scan + 4] = 0;
-			break;
-		}
-	}
-
-	/* If there is a "must appear" string, look for it. */
-	if (preg->regmust != 0) {
-		s = string;
-		while ((s = str_find(s, preg->program[preg->regmust], preg->cflags & REG_ICASE)) != NULL) {
-			if (prefix_cmp(preg->program + preg->regmust, preg->regmlen, s, preg->cflags & REG_ICASE) >= 0) {
-				break;
-			}
-			s++;
-		}
-		if (s == NULL)	/* Not present. */
-			return REG_NOMATCH;
-	}
-
-	/* Mark beginning of line for ^ . */
-	preg->regbol = string;
-
-	/* Simplest case:  anchored match need be tried only once (maybe per line). */
-	if (preg->reganch) {
-		if (eflags & REG_NOTBOL) {
-			/* This is an anchored search, but not an BOL, so possibly skip to the next line */
-			goto nextline;
-		}
-		while (1) {
-			int ret = regtry(preg, string);
-			if (ret) {
-				return REG_NOERROR;
-			}
-			if (*string) {
-nextline:
-				if (preg->cflags & REG_NEWLINE) {
-					/* Try the next anchor? */
-					string = strchr(string, '\n');
-					if (string) {
-						preg->regbol = ++string;
-						continue;
-					}
-				}
-			}
-			return REG_NOMATCH;
-		}
-	}
-
-	/* Messy cases:  unanchored match. */
-	s = string;
-	if (preg->regstart != '\0') {
-		/* We know what char it must start with. */
-		while ((s = str_find(s, preg->regstart, preg->cflags & REG_ICASE)) != NULL) {
-			if (regtry(preg, s))
-				return REG_NOERROR;
-			s++;
-		}
-	}
-	else
-		/* We don't -- general case. */
-		while (1) {
-			if (regtry(preg, s))
-				return REG_NOERROR;
-			if (*s == '\0') {
-				break;
-			}
-			s += utf8_charlen(*s);
-		}
-
-	/* Failure. */
-	return REG_NOMATCH;
-}
-
-/*
- - regtry - try match at specific point
- */
-			/* 0 failure, 1 success */
-static int regtry( regex_t *preg, const char *string )
-{
-	int i;
-
-	preg->reginput = string;
-
-	for (i = 0; i < preg->nmatch; i++) {
-		preg->pmatch[i].rm_so = -1;
-		preg->pmatch[i].rm_eo = -1;
-	}
-	if (regmatch(preg, 1)) {
-		preg->pmatch[0].rm_so = string - preg->start;
-		preg->pmatch[0].rm_eo = preg->reginput - preg->start;
-		return(1);
-	} else
-		return(0);
-}
-
-/**
- * Returns bytes matched if 'pattern' is a prefix of 'string'.
- *
- * If 'nocase' is non-zero, does a case-insensitive match.
- *
- * Returns -1 on not found.
- */
-static int prefix_cmp(const int *prog, int proglen, const char *string, int nocase)
-{
-	const char *s = string;
-	while (proglen && *s) {
-		int ch;
-		int n = reg_utf8_tounicode_case(s, &ch, nocase);
-		if (ch != *prog) {
-			return -1;
-		}
-		prog++;
-		s += n;
-		proglen--;
-	}
-	if (proglen == 0) {
-		return s - string;
-	}
-	return -1;
-}
-
-/**
- * Searchs for 'c' in the range 'range'.
- * 
- * Returns 1 if found, or 0 if not.
- */
-static int reg_range_find(const int *range, int c)
-{
-	while (*range) {
-		/*printf("Checking %d in range [%d,%d]\n", c, range[1], (range[0] + range[1] - 1));*/
-		if (c >= range[1] && c <= (range[0] + range[1] - 1)) {
-			return 1;
-		}
-		range += 2;
-	}
-	return 0;
-}
-
-/**
- * Search for the character 'c' in the utf-8 string 'string'.
- * 
- * If 'nocase' is set, the 'string' is assumed to be uppercase
- * and 'c' is converted to uppercase before matching.
- *
- * Returns the byte position in the string where the 'c' was found, or
- * NULL if not found.
- */
-static const char *str_find(const char *string, int c, int nocase)
-{
-	if (nocase) {
-		/* The "string" should already be converted to uppercase */
-		c = utf8_upper(c);
-	}
-	while (*string) {
-		int ch;
-		int n = reg_utf8_tounicode_case(string, &ch, nocase);
-		if (c == ch) {
-			return string;
-		}
-		string += n;
-	}
-	return NULL;
-}
-
-/**
- * Returns true if 'ch' is an end-of-line char.
- * 
- * In REG_NEWLINE mode, \n is considered EOL in
- * addition to \0
- */
-static int reg_iseol(regex_t *preg, int ch)
-{
-	if (preg->cflags & REG_NEWLINE) {
-		return ch == '\0' || ch == '\n';
-	}
-	else {
-		return ch == '\0';
-	}
-}
-
-static int regmatchsimplerepeat(regex_t *preg, int scan, int matchmin)
-{
-	int nextch = '\0';
-	const char *save;
-	int no;
-	int c;
-
-	int max = preg->program[scan + 2];
-	int min = preg->program[scan + 3];
-	int next = regnext(preg, scan);
-
-	/*
-	 * Lookahead to avoid useless match attempts
-	 * when we know what character comes next.
-	 */
-	if (OP(preg, next) == EXACTLY) {
-		nextch = preg->program[OPERAND(next)];
-	}
-	save = preg->reginput;
-	no = regrepeat(preg, scan + 5, max);
-	if (no < min) {
-		return 0;
-	}
-	if (matchmin) {
-		/* from min up to no */
-		max = no;
-		no = min;
-	}
-	/* else from no down to min */
-	while (1) {
-		if (matchmin) {
-			if (no > max) {
-				break;
-			}
-		}
-		else {
-			if (no < min) {
-				break;
-			}
-		}
-		preg->reginput = save + utf8_index(save, no);
-		reg_utf8_tounicode_case(preg->reginput, &c, (preg->cflags & REG_ICASE));
-		/* If it could work, try it. */
-		if (reg_iseol(preg, nextch) || c == nextch) {
-			if (regmatch(preg, next)) {
-				return(1);
-			}
-		}
-		if (matchmin) {
-			/* Couldn't or didn't, add one more */
-			no++;
-		}
-		else {
-			/* Couldn't or didn't -- back up. */
-			no--;
-		}
-	}
-	return(0);
-}
-
-static int regmatchrepeat(regex_t *preg, int scan, int matchmin)
-{
-	int *scanpt = preg->program + scan;
-
-	int max = scanpt[2];
-	int min = scanpt[3];
-
-	/* Have we reached min? */
-	if (scanpt[4] < min) {
-		/* No, so get another one */
-		scanpt[4]++;
-		if (regmatch(preg, scan + 5)) {
-			return 1;
-		}
-		scanpt[4]--;
-		return 0;
-	}
-	if (scanpt[4] > max) {
-		return 0;
-	}
-
-	if (matchmin) {
-		/* minimal, so try other branch first */
-		if (regmatch(preg, regnext(preg, scan))) {
-			return 1;
-		}
-		/* No, so try one more */
-		scanpt[4]++;
-		if (regmatch(preg, scan + 5)) {
-			return 1;
-		}
-		scanpt[4]--;
-		return 0;
-	}
-	/* maximal, so try this branch again */
-	if (scanpt[4] < max) {
-		scanpt[4]++;
-		if (regmatch(preg, scan + 5)) {
-			return 1;
-		}
-		scanpt[4]--;
-	}
-	/* At this point we are at max with no match. Try the other branch */
-	return regmatch(preg, regnext(preg, scan));
-}
-
-/*
- - regmatch - main matching routine
- *
- * Conceptually the strategy is simple:  check to see whether the current
- * node matches, call self recursively to see whether the rest matches,
- * and then act accordingly.  In practice we make some effort to avoid
- * recursion, in particular by going through "ordinary" nodes (that don't
- * need to know whether the rest of the match failed) by a loop instead of
- * by recursion.
- */
-/* 0 failure, 1 success */
-static int regmatch(regex_t *preg, int prog)
-{
-	int scan;	/* Current node. */
-	int next;		/* Next node. */
-
-	scan = prog;
-
-#ifdef DEBUG
-	if (scan != 0 && regnarrate)
-		fprintf(stderr, "%s(\n", regprop(scan));
-#endif
-	while (scan != 0) {
-		int n;
-		int c;
-#ifdef DEBUG
-		if (regnarrate) {
-			//fprintf(stderr, "%s...\n", regprop(scan));
-			fprintf(stderr, "%3d: %s...\n", scan, regprop(OP(preg, scan)));	/* Where, what. */
-		}
-#endif
-		next = regnext(preg, scan);
-		n = reg_utf8_tounicode_case(preg->reginput, &c, (preg->cflags & REG_ICASE));
-
-		switch (OP(preg, scan)) {
-		case BOL:
-			if (preg->reginput != preg->regbol)
-				return(0);
-			break;
-		case EOL:
-			if (!reg_iseol(preg, c)) {
-				return(0);
-			}
-			break;
-		case WORDA:
-			/* Must be looking at a letter, digit, or _ */
-			if ((!isalnum(UCHAR(c))) && c != '_')
-				return(0);
-			/* Prev must be BOL or nonword */
-			if (preg->reginput > preg->regbol &&
-				(isalnum(UCHAR(preg->reginput[-1])) || preg->reginput[-1] == '_'))
-				return(0);
-			break;
-		case WORDZ:
-			/* Can't match at BOL */
-			if (preg->reginput > preg->regbol) {
-				/* Current must be EOL or nonword */
-				if (reg_iseol(preg, c) || !isalnum(UCHAR(c)) || c != '_') {
-					c = preg->reginput[-1];
-					/* Previous must be word */
-					if (isalnum(UCHAR(c)) || c == '_') {
-						break;
-					}
-				}
-			}
-			/* No */
-			return(0);
-
-		case ANY:
-			if (reg_iseol(preg, c))
-				return 0;
-			preg->reginput += n;
-			break;
-		case EXACTLY: {
-				int opnd;
-				int len;
-				int slen;
-
-				opnd = OPERAND(scan);
-				len = str_int_len(preg->program + opnd);
-
-				slen = prefix_cmp(preg->program + opnd, len, preg->reginput, preg->cflags & REG_ICASE);
-				if (slen < 0) {
-					return(0);
-				}
-				preg->reginput += slen;
-			}
-			break;
-		case ANYOF:
-			if (reg_iseol(preg, c) || reg_range_find(preg->program + OPERAND(scan), c) == 0) {
-				return(0);
-			}
-			preg->reginput += n;
-			break;
-		case ANYBUT:
-			if (reg_iseol(preg, c) || reg_range_find(preg->program + OPERAND(scan), c) != 0) {
-				return(0);
-			}
-			preg->reginput += n;
-			break;
-		case NOTHING:
-			break;
-		case BACK:
-			break;
-		case BRANCH: {
-				const char *save;
-
-				if (OP(preg, next) != BRANCH)		/* No choice. */
-					next = OPERAND(scan);	/* Avoid recursion. */
-				else {
-					do {
-						save = preg->reginput;
-						if (regmatch(preg, OPERAND(scan))) {
-							return(1);
-						}
-						preg->reginput = save;
-						scan = regnext(preg, scan);
-					} while (scan != 0 && OP(preg, scan) == BRANCH);
-					return(0);
-					/* NOTREACHED */
-				}
-			}
-			break;
-		case REP:
-		case REPMIN:
-			return regmatchsimplerepeat(preg, scan, OP(preg, scan) == REPMIN);
-
-		case REPX:
-		case REPXMIN:
-			return regmatchrepeat(preg, scan, OP(preg, scan) == REPXMIN);
-
-		case END:
-			return(1);	/* Success! */
-			break;
-		default:
-			if (OP(preg, scan) >= OPEN+1 && OP(preg, scan) < CLOSE_END) {
-				const char *save;
-
-				save = preg->reginput;
-
-				if (regmatch(preg, next)) {
-					int no;
-					/*
-					 * Don't set startp if some later
-					 * invocation of the same parentheses
-					 * already has.
-					 */
-					if (OP(preg, scan) < CLOSE) {
-						no = OP(preg, scan) - OPEN;
-						if (no < preg->nmatch && preg->pmatch[no].rm_so == -1) {
-							preg->pmatch[no].rm_so = save - preg->start;
-						}
-					}
-					else {
-						no = OP(preg, scan) - CLOSE;
-						if (no < preg->nmatch && preg->pmatch[no].rm_eo == -1) {
-							preg->pmatch[no].rm_eo = save - preg->start;
-						}
-					}
-					return(1);
-				} else
-					return(0);
-			}
-			return REG_ERR_INTERNAL;
-		}
-
-		scan = next;
-	}
-
-	/*
-	 * We get here only if there's trouble -- normally "case END" is
-	 * the terminating point.
-	 */
-	return REG_ERR_INTERNAL;
-}
-
-/*
- - regrepeat - repeatedly match something simple, report how many
- */
-static int regrepeat(regex_t *preg, int p, int max)
-{
-	int count = 0;
-	const char *scan;
-	int opnd;
-	int ch;
-	int n;
-
-	scan = preg->reginput;
-	opnd = OPERAND(p);
-	switch (OP(preg, p)) {
-	case ANY:
-		/* No need to handle utf8 specially here */
-		while (!reg_iseol(preg, *scan) && count < max) {
-			count++;
-			scan++;
-		}
-		break;
-	case EXACTLY:
-		while (count < max) {
-			n = reg_utf8_tounicode_case(scan, &ch, preg->cflags & REG_ICASE);
-			if (preg->program[opnd] != ch) {
-				break;
-			}
-			count++;
-			scan += n;
-		}
-		break;
-	case ANYOF:
-		while (count < max) {
-			n = reg_utf8_tounicode_case(scan, &ch, preg->cflags & REG_ICASE);
-			if (reg_iseol(preg, ch) || reg_range_find(preg->program + opnd, ch) == 0) {
-				break;
-			}
-			count++;
-			scan += n;
-		}
-		break;
-	case ANYBUT:
-		while (count < max) {
-			n = reg_utf8_tounicode_case(scan, &ch, preg->cflags & REG_ICASE);
-			if (reg_iseol(preg, ch) || reg_range_find(preg->program + opnd, ch) != 0) {
-				break;
-			}
-			count++;
-			scan += n;
-		}
-		break;
-	default:		/* Oh dear.  Called inappropriately. */
-		preg->err = REG_ERR_INTERNAL;
-		count = 0;	/* Best compromise. */
-		break;
-	}
-	preg->reginput = scan;
-
-	return(count);
-}
-
-/*
- - regnext - dig the "next" pointer out of a node
- */
-static int regnext(regex_t *preg, int p )
-{
-	int offset;
-
-	offset = NEXT(preg, p);
-
-	if (offset == 0)
-		return 0;
-
-	if (OP(preg, p) == BACK)
-		return(p-offset);
-	else
-		return(p+offset);
-}
-
-#ifdef DEBUG
-
-/*
- - regdump - dump a regexp onto stdout in vaguely comprehensible form
- */
-static void regdump(regex_t *preg)
-{
-	int s;
-	int op = EXACTLY;	/* Arbitrary non-END op. */
-	int next;
-	char buf[4];
-
-	int i;
-	for (i = 1; i < preg->p; i++) {
-		printf("%02x ", preg->program[i]);
-		if (i % 16 == 15) {
-			printf("\n");
-		}
-	}
-	printf("\n");
-
-	s = 1;
-	while (op != END && s < preg->p) {	/* While that wasn't END last time... */
-		op = OP(preg, s);
-		printf("%3d: %s", s, regprop(op));	/* Where, what. */
-		next = regnext(preg, s);
-		if (next == 0)		/* Next ptr. */
-			printf("(0)");
-		else
-			printf("(%d)", next);
-		s += 2;
-		if (op == REP || op == REPMIN || op == REPX || op == REPXMIN) {
-			int max = preg->program[s];
-			int min = preg->program[s + 1];
-			if (max == 65535) {
-				printf("{%d,*}", min);
-			}
-			else {
-				printf("{%d,%d}", min, max);
-			}
-			printf(" %d", preg->program[s + 2]);
-			s += 3;
-		}
-		else if (op == ANYOF || op == ANYBUT) {
-			/* set of ranges */
-
-			while (preg->program[s]) {
-				int len = preg->program[s++];
-				int first = preg->program[s++];
-				buf[utf8_fromunicode(buf, first)] = 0;
-				printf("%s", buf);
-				if (len > 1) {
-					buf[utf8_fromunicode(buf, first + len - 1)] = 0;
-					printf("-%s", buf);
-				}
-			}
-			s++;
-		}
-		else if (op == EXACTLY) {
-			/* Literal string, where present. */
-
-			while (preg->program[s]) {
-				buf[utf8_fromunicode(buf, preg->program[s])] = 0;
-				printf("%s", buf);
-				s++;
-			}
-			s++;
-		}
-		putchar('\n');
-	}
-
-	if (op == END) {
-		/* Header fields of interest. */
-		if (preg->regstart) {
-			buf[utf8_fromunicode(buf, preg->regstart)] = 0;
-			printf("start '%s' ", buf);
-		}
-		if (preg->reganch)
-			printf("anchored ");
-		if (preg->regmust != 0) {
-			int i;
-			printf("must have:");
-			for (i = 0; i < preg->regmlen; i++) {
-				putchar(preg->program[preg->regmust + i]);
-			}
-			putchar('\n');
-		}
-	}
-	printf("\n");
-}
-
-/*
- - regprop - printable representation of opcode
- */
-static const char *regprop( int op )
-{
-	static char buf[50];
-
-	switch (op) {
-	case BOL:
-		return "BOL";
-	case EOL:
-		return "EOL";
-	case ANY:
-		return "ANY";
-	case ANYOF:
-		return "ANYOF";
-	case ANYBUT:
-		return "ANYBUT";
-	case BRANCH:
-		return "BRANCH";
-	case EXACTLY:
-		return "EXACTLY";
-	case NOTHING:
-		return "NOTHING";
-	case BACK:
-		return "BACK";
-	case END:
-		return "END";
-	case REP:
-		return "REP";
-	case REPMIN:
-		return "REPMIN";
-	case REPX:
-		return "REPX";
-	case REPXMIN:
-		return "REPXMIN";
-	case WORDA:
-		return "WORDA";
-	case WORDZ:
-		return "WORDZ";
-	default:
-		if (op >= OPEN && op < CLOSE) {
-			snprintf(buf, sizeof(buf), "OPEN%d", op-OPEN);
-		}
-		else if (op >= CLOSE && op < CLOSE_END) {
-			snprintf(buf, sizeof(buf), "CLOSE%d", op-CLOSE);
-		}
-		else {
-			snprintf(buf, sizeof(buf), "?%d?\n", op);
-		}
-		return(buf);
-	}
-}
-#endif
-
-size_t regerror(int errcode, const regex_t *preg, char *errbuf,  size_t errbuf_size)
-{
-	static const char *error_strings[] = {
-		"success",
-		"no match",
-		"bad pattern",
-		"null argument",
-		"unknown error",
-		"too big",
-		"out of memory",
-		"too many ()",
-		"parentheses () not balanced",
-		"braces {} not balanced",
-		"invalid repetition count(s)",
-		"extra characters",
-		"*+ of empty atom",
-		"nested count",
-		"internal error",
-		"count follows nothing",
-		"trailing backslash",
-		"corrupted program",
-		"contains null char",
-	};
-	const char *err;
-
-	if (errcode < 0 || errcode >= REG_ERR_NUM) {
-		err = "Bad error code";
-	}
-	else {
-		err = error_strings[errcode];
-	}
-
-	return snprintf(errbuf, errbuf_size, "%s", err);
-}
-
-void regfree(regex_t *preg)
-{
-	free(preg->program);
-}
-
-#endif
-
-/* Jimsh - An interactive shell for Jim
- * Copyright 2005 Salvatore Sanfilippo <antirez@invece.org>
- * Copyright 2009 Steve Bennett <steveb@workware.net.au>
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * A copy of the license is also included in the source distribution
- * of Jim, as a TXT file name called LICENSE.
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
 
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 
 
-/* From initjimsh.tcl */
+
 extern int Jim_initjimshInit(Jim_Interp *interp);
 
 static void JimSetArgv(Jim_Interp *interp, int argc, char *const argv[])
 {
     int n;
     Jim_Obj *listObj = Jim_NewListObj(interp, NULL, 0);
 
-    /* Populate argv global var */
+    
     for (n = 0; n < argc; n++) {
         Jim_Obj *obj = Jim_NewStringObj(interp, argv[n], -1);
 
         Jim_ListAppendElement(interp, listObj, obj);
     }
@@ -23751,15 +20658,15 @@
     if (argc > 1 && strcmp(argv[1], "--version") == 0) {
         printf("%d.%d\n", JIM_VERSION / 100, JIM_VERSION % 100);
         return 0;
     }
 
-    /* Create and initialize the interpreter */
+    
     interp = Jim_CreateInterp();
     Jim_RegisterCoreCommands(interp);
 
-    /* Register static extensions */
+    
     if (Jim_InitStaticExtensions(interp) != JIM_OK) {
         Jim_MakeErrorMessage(interp);
         fprintf(stderr, "%s\n", Jim_String(Jim_GetResult(interp)));
     }
 
@@ -23805,5 +20712,6 @@
         retcode = 0;
     }
     Jim_FreeInterp(interp);
     return retcode;
 }
+#endif

Index: autosetup/system.tcl
==================================================================
--- autosetup/system.tcl
+++ autosetup/system.tcl
@@ -226,25 +226,30 @@
 define srcdir $autosetup(srcdir)
 # Allow this to come from the environment
 define top_srcdir [get-env top_srcdir [get-define srcdir]]
 
 # autoconf supports all of these
-define exec_prefix [opt-val exec-prefix [get-env exec-prefix \${prefix}]]
+set exec_prefix [opt-val exec-prefix $prefix]
+define exec_prefix $exec_prefix
+foreach {name defpath} {
+	bindir /bin
+	sbindir /sbin
+	libexecdir /libexec
+	libdir /lib
+} {
+	define $name [opt-val $name $exec_prefix$defpath]
+}
 foreach {name defpath} {
-	bindir \${exec_prefix}/bin
-	sbindir \${exec_prefix}/sbin
-	libexecdir \${exec_prefix}/libexec
-	libdir \${exec_prefix}/lib
-	datadir \${prefix}/share
-	sysconfdir \${prefix}/etc
-	sharedstatedir \${prefix}/com
-	localstatedir \${prefix}/var
-	infodir \${prefix}/share/info
-	mandir \${prefix}/share/man
-	includedir \${prefix}/include
+	datadir /share
+	sysconfdir /etc
+	sharedstatedir /com
+	localstatedir /var
+	infodir /share/info
+	mandir /share/man
+	includedir /include
 } {
-	define $name [opt-val $name [get-env $name $defpath]]
+	define $name [opt-val $name $prefix$defpath]
 }
 
 define SHELL [get-env SHELL [find-an-executable sh bash ksh]]
 
 # Windows vs. non-Windows

Index: autosetup/test-tclsh
==================================================================
--- autosetup/test-tclsh
+++ autosetup/test-tclsh
@@ -3,20 +3,18 @@
 # an interpreter for a different arch.
 # Outputs the full path to the interpreter
 
 if {[catch {info version} version] == 0} {
 	# This is Jim Tcl
-	if {$version >= 0.70} {
+	if {$version >= 0.72} {
 		# Ensure that regexp works
 		regexp (a.*?) a
-
-		# Older versions of jimsh may return a relative path for [info nameofexecutable]
-		puts [file join [pwd] [info nameofexecutable]]
+		puts [info nameofexecutable]
 		exit 0
 	}
 } elseif {[catch {info tclversion} version] == 0} {
 	if {$version >= 8.5 && ![string match 8.5a* [info patchlevel]]} {
 		puts [info nameofexecutable]
 		exit 0
 	}
 }
 exit 1

ADDED   src/jim-config.h
Index: src/jim-config.h
==================================================================
--- src/jim-config.h
+++ src/jim-config.h
@@ -0,0 +1,5 @@
+#ifndef _JIM_CONFIG_H
+#define _JIM_CONFIG_H
+/*#undef HAVE_LONG_LONG*/
+/*#undef JIM_UTF8*/
+#endif

ADDED   src/jim-win32compat.h
Index: src/jim-win32compat.h
==================================================================
--- src/jim-win32compat.h
+++ src/jim-win32compat.h
@@ -0,0 +1,69 @@
+#ifndef JIM_WIN32COMPAT_H
+#define JIM_WIN32COMPAT_H
+
+/* Compatibility for Windows (mingw and msvc, not cygwin */
+
+/* Note that at this point we don't yet have access to jimautoconf.h */
+#if defined(_WIN32) || defined(WIN32)
+
+#define HAVE_DLOPEN
+void *dlopen(const char *path, int mode);
+int dlclose(void *handle);
+void *dlsym(void *handle, const char *symbol);
+char *dlerror(void);
+
+#ifdef _MSC_VER
+/* These are msvc vs gcc */
+
+#if _MSC_VER >= 1000
+	#pragma warning(disable:4146)
+#endif
+
+#include <limits.h>
+#define jim_wide _int64
+#ifndef LLONG_MAX
+	#define LLONG_MAX    9223372036854775807I64
+#endif
+#ifndef LLONG_MIN
+	#define LLONG_MIN    (-LLONG_MAX - 1I64)
+#endif
+#define JIM_WIDE_MIN LLONG_MIN
+#define JIM_WIDE_MAX LLONG_MAX
+#define JIM_WIDE_MODIFIER "I64d"
+#define strcasecmp _stricmp
+#define strtoull _strtoui64
+#define snprintf _snprintf
+
+#include <io.h>
+
+#ifndef NO_TIMEVAL
+struct timeval {
+	long tv_sec;
+	long tv_usec;
+};
+#endif
+
+int gettimeofday(struct timeval *tv, void *unused);
+
+#define HAVE_OPENDIR
+#ifndef NO_DIRENT
+struct dirent {
+	char *d_name;
+};
+
+typedef struct DIR {
+	long                handle; /* -1 for failed rewind */
+	struct _finddata_t  info;
+	struct dirent       result; /* d_name null iff first time */
+	char                *name;  /* null-terminated char string */
+} DIR;
+
+DIR *opendir(const char *name);
+int closedir(DIR *dir);
+struct dirent *readdir(DIR *dir);
+#endif
+#endif /* _MSC_VER */
+
+#endif /* WIN32 */
+
+#endif

ADDED   src/jim.h
Index: src/jim.h
==================================================================
--- src/jim.h
+++ src/jim.h
@@ -0,0 +1,917 @@
+/* Jim - A small embeddable Tcl interpreter
+ *
+ * Copyright 2005 Salvatore Sanfilippo <antirez@invece.org>
+ * Copyright 2005 Clemens Hintze <c.hintze@gmx.net>
+ * Copyright 2005 patthoyts - Pat Thoyts <patthoyts@users.sf.net>
+ * Copyright 2008 oharboe - �yvind Harboe - oyvind.harboe@zylin.com
+ * Copyright 2008 Andrew Lunn <andrew@lunn.ch>
+ * Copyright 2008 Duane Ellis <openocd@duaneellis.com>
+ * Copyright 2008 Uwe Klein <uklein@klein-messgeraete.de>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above
+ *    copyright notice, this list of conditions and the following
+ *    disclaimer in the documentation and/or other materials
+ *    provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE JIM TCL PROJECT ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * JIM TCL PROJECT OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation
+ * are those of the authors and should not be interpreted as representing
+ * official policies, either expressed or implied, of the Jim Tcl Project.
+ *
+ *--- Inline Header File Documentation ---
+ *    [By Duane Ellis, openocd@duaneellis.com, 8/18/8]
+ *
+ * Belief is "Jim" would greatly benifit if Jim Internals where
+ * documented in some way - form whatever, and perhaps - the package:
+ * 'doxygen' is the correct approach to do that.
+ *
+ *   Details, see: http://www.stack.nl/~dimitri/doxygen/
+ *
+ * To that end please follow these guide lines:
+ *
+ *    (A) Document the PUBLIC api in the .H file.
+ *
+ *    (B) Document JIM Internals, in the .C file.
+ *
+ *    (C) Remember JIM is embedded in other packages, to that end do
+ *    not assume that your way of documenting is the right way, Jim's
+ *    public documentation should be agnostic, such that it is some
+ *    what agreeable with the "package" that is embedding JIM inside
+ *    of it's own doxygen documentation.
+ *
+ *    (D) Use minimal Doxygen tags.
+ *
+ * This will be an "ongoing work in progress" for some time.
+ **/
+
+#ifndef __JIM__H
+#define __JIM__H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <time.h>
+#include <limits.h>
+#include <stdio.h>  /* for the FILE typedef definition */
+#include <stdlib.h> /* In order to export the Jim_Free() macro */
+#include <stdarg.h> /* In order to get type va_list */
+
+/* -----------------------------------------------------------------------------
+ * System configuration
+ * autoconf (configure) will set these
+ * ---------------------------------------------------------------------------*/
+#include <jim-win32compat.h>
+
+#ifndef HAVE_NO_AUTOCONF
+#include <jim-config.h>
+#endif
+
+/* -----------------------------------------------------------------------------
+ * Compiler specific fixes.
+ * ---------------------------------------------------------------------------*/
+
+/* Long Long type and related issues */
+#ifndef jim_wide
+#  ifdef HAVE_LONG_LONG
+#    define jim_wide long long
+#    ifndef LLONG_MAX
+#      define LLONG_MAX    9223372036854775807LL
+#    endif
+#    ifndef LLONG_MIN
+#      define LLONG_MIN    (-LLONG_MAX - 1LL)
+#    endif
+#    define JIM_WIDE_MIN LLONG_MIN
+#    define JIM_WIDE_MAX LLONG_MAX
+#  else
+#    define jim_wide long
+#    define JIM_WIDE_MIN LONG_MIN
+#    define JIM_WIDE_MAX LONG_MAX
+#  endif
+
+/* -----------------------------------------------------------------------------
+ * LIBC specific fixes
+ * ---------------------------------------------------------------------------*/
+
+#  ifdef HAVE_LONG_LONG
+#    define JIM_WIDE_MODIFIER "lld"
+#  else
+#    define JIM_WIDE_MODIFIER "ld"
+#    define strtoull strtoul
+#  endif
+#endif
+
+#define UCHAR(c) ((unsigned char)(c))
+
+/* -----------------------------------------------------------------------------
+ * Exported defines
+ * ---------------------------------------------------------------------------*/
+
+/* Jim version numbering: every version of jim is marked with a
+ * successive integer number. This is version 0. The first
+ * stable version will be 1, then 2, 3, and so on. */
+#define JIM_VERSION 73
+
+#define JIM_OK 0
+#define JIM_ERR 1
+#define JIM_RETURN 2
+#define JIM_BREAK 3
+#define JIM_CONTINUE 4
+#define JIM_SIGNAL 5
+#define JIM_EXIT 6
+/* The following are internal codes and should never been seen/used */
+#define JIM_EVAL 7
+
+#define JIM_MAX_NESTING_DEPTH 1000 /* default max nesting depth */
+
+/* Some function get an integer argument with flags to change
+ * the behaviour. */
+#define JIM_NONE 0    /* no flags set */
+#define JIM_ERRMSG 1    /* set an error message in the interpreter. */
+
+#define JIM_UNSHARED 4 /* Flag to Jim_GetVariable() */
+
+/* Flags for Jim_SubstObj() */
+#define JIM_SUBST_NOVAR 1 /* don't perform variables substitutions */
+#define JIM_SUBST_NOCMD 2 /* don't perform command substitutions */
+#define JIM_SUBST_NOESC 4 /* don't perform escapes substitutions */
+#define JIM_SUBST_FLAG 128 /* flag to indicate that this is a real substition object */
+
+/* Unused arguments generate annoying warnings... */
+#define JIM_NOTUSED(V) ((void) V)
+
+/* Flags for Jim_GetEnum() */
+#define JIM_ENUM_ABBREV 2    /* Allow unambiguous abbreviation */
+
+/* Flags used by API calls getting a 'nocase' argument. */
+#define JIM_CASESENS    0   /* case sensitive */
+#define JIM_NOCASE      1   /* no case */
+
+/* Filesystem related */
+#define JIM_PATH_LEN 1024
+
+/* Newline, some embedded system may need -DJIM_CRLF */
+#ifdef JIM_CRLF
+#define JIM_NL "\r\n"
+#else
+#define JIM_NL "\n"
+#endif
+
+#define JIM_LIBPATH "auto_path"
+#define JIM_INTERACTIVE "tcl_interactive"
+
+/* -----------------------------------------------------------------------------
+ * Stack
+ * ---------------------------------------------------------------------------*/
+
+typedef struct Jim_Stack {
+    int len;
+    int maxlen;
+    void **vector;
+} Jim_Stack;
+
+/* -----------------------------------------------------------------------------
+ * Hash table
+ * ---------------------------------------------------------------------------*/
+
+typedef struct Jim_HashEntry {
+    const void *key;
+    union {
+        void *val;
+        int intval;
+    } u;
+    struct Jim_HashEntry *next;
+} Jim_HashEntry;
+
+typedef struct Jim_HashTableType {
+    unsigned int (*hashFunction)(const void *key);
+    const void *(*keyDup)(void *privdata, const void *key);
+    void *(*valDup)(void *privdata, const void *obj);
+    int (*keyCompare)(void *privdata, const void *key1, const void *key2);
+    void (*keyDestructor)(void *privdata, const void *key);
+    void (*valDestructor)(void *privdata, void *obj);
+} Jim_HashTableType;
+
+typedef struct Jim_HashTable {
+    Jim_HashEntry **table;
+    const Jim_HashTableType *type;
+    unsigned int size;
+    unsigned int sizemask;
+    unsigned int used;
+    unsigned int collisions;
+    void *privdata;
+} Jim_HashTable;
+
+typedef struct Jim_HashTableIterator {
+    Jim_HashTable *ht;
+    int index;
+    Jim_HashEntry *entry, *nextEntry;
+} Jim_HashTableIterator;
+
+/* This is the initial size of every hash table */
+#define JIM_HT_INITIAL_SIZE     16
+
+/* ------------------------------- Macros ------------------------------------*/
+#define Jim_FreeEntryVal(ht, entry) \
+    if ((ht)->type->valDestructor) \
+        (ht)->type->valDestructor((ht)->privdata, (entry)->u.val)
+
+#define Jim_SetHashVal(ht, entry, _val_) do { \
+    if ((ht)->type->valDup) \
+        entry->u.val = (ht)->type->valDup((ht)->privdata, _val_); \
+    else \
+        entry->u.val = (_val_); \
+} while(0)
+
+#define Jim_FreeEntryKey(ht, entry) \
+    if ((ht)->type->keyDestructor) \
+        (ht)->type->keyDestructor((ht)->privdata, (entry)->key)
+
+#define Jim_SetHashKey(ht, entry, _key_) do { \
+    if ((ht)->type->keyDup) \
+        entry->key = (ht)->type->keyDup((ht)->privdata, _key_); \
+    else \
+        entry->key = (_key_); \
+} while(0)
+
+#define Jim_CompareHashKeys(ht, key1, key2) \
+    (((ht)->type->keyCompare) ? \
+        (ht)->type->keyCompare((ht)->privdata, key1, key2) : \
+        (key1) == (key2))
+
+#define Jim_HashKey(ht, key) (ht)->type->hashFunction(key)
+
+#define Jim_GetHashEntryKey(he) ((he)->key)
+#define Jim_GetHashEntryVal(he) ((he)->val)
+#define Jim_GetHashTableCollisions(ht) ((ht)->collisions)
+#define Jim_GetHashTableSize(ht) ((ht)->size)
+#define Jim_GetHashTableUsed(ht) ((ht)->used)
+
+/* -----------------------------------------------------------------------------
+ * Jim_Obj structure
+ * ---------------------------------------------------------------------------*/
+
+/* -----------------------------------------------------------------------------
+ * Jim object. This is mostly the same as Tcl_Obj itself,
+ * with the addition of the 'prev' and 'next' pointers.
+ * In Jim all the objects are stored into a linked list for GC purposes,
+ * so that it's possible to access every object living in a given interpreter
+ * sequentially. When an object is freed, it's moved into a different
+ * linked list, used as object pool.
+ *
+ * The refcount of a freed object is always -1.
+ * ---------------------------------------------------------------------------*/
+typedef struct Jim_Obj {
+    int refCount; /* reference count */
+    char *bytes; /* string representation buffer. NULL = no string repr. */
+    int length; /* number of bytes in 'bytes', not including the numterm. */
+    const struct Jim_ObjType *typePtr; /* object type. */
+    /* Internal representation union */
+    union {
+        /* integer number type */
+        jim_wide wideValue;
+        /* hashed object type value */
+        int hashValue;
+        /* index type */
+        int indexValue;
+        /* return code type */
+        int returnCode;
+        /* double number type */
+        double doubleValue;
+        /* Generic pointer */
+        void *ptr;
+        /* Generic two pointers value */
+        struct {
+            void *ptr1;
+            void *ptr2;
+        } twoPtrValue;
+        /* Variable object */
+        struct {
+            unsigned jim_wide callFrameId;
+            struct Jim_Var *varPtr;
+        } varValue;
+        /* Command object */
+        struct {
+            unsigned jim_wide procEpoch;
+            struct Jim_Cmd *cmdPtr;
+        } cmdValue;
+        /* List object */
+        struct {
+            struct Jim_Obj **ele;    /* Elements vector */
+            int len;        /* Length */
+            int maxLen;        /* Allocated 'ele' length */
+        } listValue;
+        /* String type */
+        struct {
+            int maxLength;
+            int charLength;     /* utf-8 char length. -1 if unknown */
+        } strValue;
+        /* Reference type */
+        struct {
+            jim_wide id;
+            struct Jim_Reference *refPtr;
+        } refValue;
+        /* Source type */
+        struct {
+            struct Jim_Obj *fileNameObj;
+            int lineNumber;
+        } sourceValue;
+        /* Dict substitution type */
+        struct {
+            struct Jim_Obj *varNameObjPtr;
+            struct Jim_Obj *indexObjPtr;
+        } dictSubstValue;
+        /* tagged binary type */
+        struct {
+            unsigned char *data;
+            size_t         len;
+        } binaryValue;
+        /* Regular expression pattern */
+        struct {
+            unsigned flags;
+            void *compre;       /* really an allocated (regex_t *) */
+        } regexpValue;
+        struct {
+            int line;
+            int argc;
+        } scriptLineValue;
+    } internalRep;
+    /* This are 8 or 16 bytes more for every object
+     * but this is required for efficient garbage collection
+     * of Jim references. */
+    struct Jim_Obj *prevObjPtr; /* pointer to the prev object. */
+    struct Jim_Obj *nextObjPtr; /* pointer to the next object. */
+} Jim_Obj;
+
+/* Jim_Obj related macros */
+#define Jim_IncrRefCount(objPtr) \
+    ++(objPtr)->refCount
+#define Jim_DecrRefCount(interp, objPtr) \
+    if (--(objPtr)->refCount <= 0) Jim_FreeObj(interp, objPtr)
+#define Jim_IsShared(objPtr) \
+    ((objPtr)->refCount > 1)
+
+/* This macro is used when we allocate a new object using
+ * Jim_New...Obj(), but for some error we need to destroy it.
+ * Instead to use Jim_IncrRefCount() + Jim_DecrRefCount() we
+ * can just call Jim_FreeNewObj. To call Jim_Free directly
+ * seems too raw, the object handling may change and we want
+ * that Jim_FreeNewObj() can be called only against objects
+ * that are belived to have refcount == 0. */
+#define Jim_FreeNewObj Jim_FreeObj
+
+/* Free the internal representation of the object. */
+#define Jim_FreeIntRep(i,o) \
+    if ((o)->typePtr && (o)->typePtr->freeIntRepProc) \
+        (o)->typePtr->freeIntRepProc(i, o)
+
+/* Get the internal representation pointer */
+#define Jim_GetIntRepPtr(o) (o)->internalRep.ptr
+
+/* Set the internal representation pointer */
+#define Jim_SetIntRepPtr(o, p) \
+    (o)->internalRep.ptr = (p)
+
+/* The object type structure.
+ * There are four methods.
+ *
+ * - FreeIntRep is used to free the internal representation of the object.
+ *   Can be NULL if there is nothing to free.
+ * - DupIntRep is used to duplicate the internal representation of the object.
+ *   If NULL, when an object is duplicated, the internalRep union is
+ *   directly copied from an object to another.
+ *   Note that it's up to the caller to free the old internal repr of the
+ *   object before to call the Dup method.
+ * - UpdateString is used to create the string from the internal repr.
+ * - setFromAny is used to convert the current object into one of this type.
+ */
+
+struct Jim_Interp;
+
+typedef void (Jim_FreeInternalRepProc)(struct Jim_Interp *interp,
+        struct Jim_Obj *objPtr);
+typedef void (Jim_DupInternalRepProc)(struct Jim_Interp *interp,
+        struct Jim_Obj *srcPtr, Jim_Obj *dupPtr);
+typedef void (Jim_UpdateStringProc)(struct Jim_Obj *objPtr);
+
+typedef struct Jim_ObjType {
+    const char *name; /* The name of the type. */
+    Jim_FreeInternalRepProc *freeIntRepProc;
+    Jim_DupInternalRepProc *dupIntRepProc;
+    Jim_UpdateStringProc *updateStringProc;
+    int flags;
+} Jim_ObjType;
+
+/* Jim_ObjType flags */
+#define JIM_TYPE_NONE 0        /* No flags */
+#define JIM_TYPE_REFERENCES 1    /* The object may contain referneces. */
+
+/* Starting from 1 << 20 flags are reserved for private uses of
+ * different calls. This way the same 'flags' argument may be used
+ * to pass both global flags and private flags. */
+#define JIM_PRIV_FLAG_SHIFT 20
+
+/* -----------------------------------------------------------------------------
+ * Call frame, vars, commands structures
+ * ---------------------------------------------------------------------------*/
+
+/* Call frame */
+typedef struct Jim_CallFrame {
+    unsigned jim_wide id; /* Call Frame ID. Used for caching. */
+    int level; /* Level of this call frame. 0 = global */
+    struct Jim_HashTable vars; /* Where local vars are stored */
+    struct Jim_HashTable *staticVars; /* pointer to procedure static vars */
+    struct Jim_CallFrame *parentCallFrame;
+    Jim_Obj *const *argv; /* object vector of the current procedure call. */
+    int argc; /* number of args of the current procedure call. */
+    Jim_Obj *procArgsObjPtr; /* arglist object of the running procedure */
+    Jim_Obj *procBodyObjPtr; /* body object of the running procedure */
+    struct Jim_CallFrame *nextFramePtr;
+    Jim_Obj *fileNameObj;       /* file and line of caller of this proc (if available) */
+    int line;
+} Jim_CallFrame;
+
+/* The var structure. It just holds the pointer of the referenced
+ * object. If linkFramePtr is not NULL the variable is a link
+ * to a variable of name store on objPtr living on the given callframe
+ * (this happens when the [global] or [upvar] command is used).
+ * The interp in order to always know how to free the Jim_Obj associated
+ * with a given variable because In Jim objects memory managment is
+ * bound to interpreters. */
+typedef struct Jim_Var {
+    Jim_Obj *objPtr;
+    struct Jim_CallFrame *linkFramePtr;
+} Jim_Var;
+
+/* The cmd structure. */
+typedef int (*Jim_CmdProc)(struct Jim_Interp *interp, int argc,
+    Jim_Obj *const *argv);
+typedef void (*Jim_DelCmdProc)(struct Jim_Interp *interp, void *privData);
+
+
+
+/* A command is implemented in C if funcPtr is != NULL, otherwise
+ * it's a Tcl procedure with the arglist and body represented by the
+ * two objects referenced by arglistObjPtr and bodyoObjPtr. */
+typedef struct Jim_Cmd {
+    int inUse;           /* Reference count */
+    int isproc;          /* Is this a procedure? */
+    union {
+        struct {
+            /* native (C) command */
+            Jim_CmdProc cmdProc; /* The command implementation */
+            Jim_DelCmdProc delProc; /* Called when the command is deleted if != NULL */
+            void *privData; /* command-private data available via Jim_CmdPrivData() */
+        } native;
+        struct {
+            /* Tcl procedure */
+            Jim_Obj *argListObjPtr;
+            Jim_Obj *bodyObjPtr;
+            Jim_HashTable *staticVars;  /* Static vars hash table. NULL if no statics. */
+            struct Jim_Cmd *prevCmd;    /* Previous command defn if proc created 'local' */
+            int argListLen;             /* Length of argListObjPtr */
+            int reqArity;               /* Number of required parameters */
+            int optArity;               /* Number of optional parameters */
+            int argsPos;                /* Position of 'args', if specified, or -1 */
+            int upcall;                 /* True if proc is currently in upcall */
+            struct Jim_ProcArg {
+                Jim_Obj *nameObjPtr;    /* Name of this arg */
+                Jim_Obj *defaultObjPtr; /* Default value, (or rename for $args) */
+            } *arglist;
+        } proc;
+    } u;
+} Jim_Cmd;
+
+/* Pseudo Random Number Generator State structure */
+typedef struct Jim_PrngState {
+    unsigned char sbox[256];
+    unsigned int i, j;
+} Jim_PrngState;
+
+/* -----------------------------------------------------------------------------
+ * Jim interpreter structure.
+ * Fields similar to the real Tcl interpreter structure have the same names.
+ * ---------------------------------------------------------------------------*/
+typedef struct Jim_Interp {
+    Jim_Obj *result; /* object returned by the last command called. */
+    int errorLine; /* Error line where an error occurred. */
+    Jim_Obj *errorFileNameObj; /* Error file where an error occurred. */
+    int addStackTrace; /* > 0 If a level should be added to the stack trace */
+    int maxNestingDepth; /* Used for infinite loop detection. */
+    int returnCode; /* Completion code to return on JIM_RETURN. */
+    int returnLevel; /* Current level of 'return -level' */
+    int exitCode; /* Code to return to the OS on JIM_EXIT. */
+    long id; /* Hold unique id for various purposes */
+    int signal_level; /* A nesting level of catch -signal */
+    jim_wide sigmask;  /* Bit mask of caught signals, or 0 if none */
+    int (*signal_set_result)(struct Jim_Interp *interp, jim_wide sigmask); /* Set a result for the sigmask */
+    Jim_CallFrame *framePtr; /* Pointer to the current call frame */
+    Jim_CallFrame *topFramePtr; /* toplevel/global frame pointer. */
+    struct Jim_HashTable commands; /* Commands hash table */
+    unsigned jim_wide procEpoch; /* Incremented every time the result
+                of procedures names lookup caching
+                may no longer be valid. */
+    unsigned jim_wide callFrameEpoch; /* Incremented every time a new
+                callframe is created. This id is used for the
+                'ID' field contained in the Jim_CallFrame
+                structure. */
+    int local; /* If 'local' is in effect, newly defined procs keep a reference to the old defn */
+    Jim_Obj *liveList; /* Linked list of all the live objects. */
+    Jim_Obj *freeList; /* Linked list of all the unused objects. */
+    Jim_Obj *currentScriptObj; /* Script currently in execution. */
+    Jim_Obj *emptyObj; /* Shared empty string object. */
+    Jim_Obj *trueObj; /* Shared true int object. */
+    Jim_Obj *falseObj; /* Shared false int object. */
+    unsigned jim_wide referenceNextId; /* Next id for reference. */
+    struct Jim_HashTable references; /* References hash table. */
+    jim_wide lastCollectId; /* reference max Id of the last GC
+                execution. It's set to -1 while the collection
+                is running as sentinel to avoid to recursive
+                calls via the [collect] command inside
+                finalizers. */
+    time_t lastCollectTime; /* unix time of the last GC execution */
+    Jim_Obj *stackTrace; /* Stack trace object. */
+    Jim_Obj *errorProc; /* Name of last procedure which returned an error */
+    Jim_Obj *unknown; /* Unknown command cache */
+    int unknown_called; /* The unknown command has been invoked */
+    int errorFlag; /* Set if an error occurred during execution. */
+    void *cmdPrivData; /* Used to pass the private data pointer to
+                  a command. It is set to what the user specified
+                  via Jim_CreateCommand(). */
+
+    struct Jim_CallFrame *freeFramesList; /* list of CallFrame structures. */
+    struct Jim_HashTable assocData; /* per-interp storage for use by packages */
+    Jim_PrngState *prngState; /* per interpreter Random Number Gen. state. */
+    struct Jim_HashTable packages; /* Provided packages hash table */
+    Jim_Stack *localProcs; /* procs to be destroyed on end of evaluation */
+    Jim_Stack *loadHandles; /* handles of loaded modules [load] */
+} Jim_Interp;
+
+/* Currently provided as macro that performs the increment.
+ * At some point may be a real function doing more work.
+ * The proc epoch is used in order to know when a command lookup
+ * cached can no longer considered valid. */
+#define Jim_InterpIncrProcEpoch(i) (i)->procEpoch++
+#define Jim_SetResultString(i,s,l) Jim_SetResult(i, Jim_NewStringObj(i,s,l))
+#define Jim_SetResultInt(i,intval) Jim_SetResult(i, Jim_NewIntObj(i,intval))
+/* Note: Using trueObj and falseObj here makes some things slower...*/
+#define Jim_SetResultBool(i,b) Jim_SetResultInt(i, b)
+#define Jim_SetEmptyResult(i) Jim_SetResult(i, (i)->emptyObj)
+#define Jim_GetResult(i) ((i)->result)
+#define Jim_CmdPrivData(i) ((i)->cmdPrivData)
+#define Jim_String(o) Jim_GetString((o), NULL)
+
+/* Note that 'o' is expanded only one time inside this macro,
+ * so it's safe to use side effects. */
+#define Jim_SetResult(i,o) do {     \
+    Jim_Obj *_resultObjPtr_ = (o);    \
+    Jim_IncrRefCount(_resultObjPtr_); \
+    Jim_DecrRefCount(i,(i)->result);  \
+    (i)->result = _resultObjPtr_;     \
+} while(0)
+
+/* Use this for filehandles, etc. which need a unique id */
+#define Jim_GetId(i) (++(i)->id)
+
+/* Reference structure. The interpreter pointer is held within privdata member in HashTable */
+#define JIM_REFERENCE_TAGLEN 7 /* The tag is fixed-length, because the reference
+                                  string representation must be fixed length. */
+typedef struct Jim_Reference {
+    Jim_Obj *objPtr;
+    Jim_Obj *finalizerCmdNamePtr;
+    char tag[JIM_REFERENCE_TAGLEN+1];
+} Jim_Reference;
+
+/* -----------------------------------------------------------------------------
+ * Exported API prototypes.
+ * ---------------------------------------------------------------------------*/
+
+/* Macros that are common for extensions and core. */
+#define Jim_NewEmptyStringObj(i) Jim_NewStringObj(i, "", 0)
+
+/* The core includes real prototypes, extensions instead
+ * include a global function pointer for every function exported.
+ * Once the extension calls Jim_InitExtension(), the global
+ * functon pointers are set to the value of the STUB table
+ * contained in the Jim_Interp structure.
+ *
+ * This makes Jim able to load extensions even if it is statically
+ * linked itself, and to load extensions compiled with different
+ * versions of Jim (as long as the API is still compatible.) */
+
+/* Macros are common for core and extensions */
+#define Jim_FreeHashTableIterator(iter) Jim_Free(iter)
+
+#define JIM_EXPORT
+
+/* Memory allocation */
+JIM_EXPORT void *Jim_Alloc (int size);
+JIM_EXPORT void *Jim_Realloc(void *ptr, int size);
+JIM_EXPORT void Jim_Free (void *ptr);
+JIM_EXPORT char * Jim_StrDup (const char *s);
+JIM_EXPORT char *Jim_StrDupLen(const char *s, int l);
+
+/* environment */
+JIM_EXPORT char **Jim_GetEnviron(void);
+JIM_EXPORT void Jim_SetEnviron(char **env);
+
+/* evaluation */
+JIM_EXPORT int Jim_Eval(Jim_Interp *interp, const char *script);
+/* in C code, you can do this and get better error messages */
+/*   Jim_EvalSource( interp, __FILE__, __LINE__ , "some tcl commands"); */
+JIM_EXPORT int Jim_EvalSource(Jim_Interp *interp, const char *filename, int lineno, const char *script);
+/* Backwards compatibility */
+#define Jim_Eval_Named(I, S, F, L) Jim_EvalSource((I), (F), (L), (S))
+
+JIM_EXPORT int Jim_EvalGlobal(Jim_Interp *interp, const char *script);
+JIM_EXPORT int Jim_EvalFile(Jim_Interp *interp, const char *filename);
+JIM_EXPORT int Jim_EvalFileGlobal(Jim_Interp *interp, const char *filename);
+JIM_EXPORT int Jim_EvalObj (Jim_Interp *interp, Jim_Obj *scriptObjPtr);
+JIM_EXPORT int Jim_EvalObjVector (Jim_Interp *interp, int objc,
+        Jim_Obj *const *objv);
+JIM_EXPORT int Jim_EvalObjPrefix(Jim_Interp *interp, Jim_Obj *prefix,
+        int objc, Jim_Obj *const *objv);
+#define Jim_EvalPrefix(i, p, oc, ov) Jim_EvalObjPrefix((i), Jim_NewStringObj((i), (p), -1), (oc), (ov))
+JIM_EXPORT int Jim_SubstObj (Jim_Interp *interp, Jim_Obj *substObjPtr,
+        Jim_Obj **resObjPtrPtr, int flags);
+
+/* stack */
+JIM_EXPORT void Jim_InitStack(Jim_Stack *stack);
+JIM_EXPORT void Jim_FreeStack(Jim_Stack *stack);
+JIM_EXPORT int Jim_StackLen(Jim_Stack *stack);
+JIM_EXPORT void Jim_StackPush(Jim_Stack *stack, void *element);
+JIM_EXPORT void * Jim_StackPop(Jim_Stack *stack);
+JIM_EXPORT void * Jim_StackPeek(Jim_Stack *stack);
+JIM_EXPORT void Jim_FreeStackElements(Jim_Stack *stack, void (*freeFunc)(void *ptr));
+
+/* hash table */
+JIM_EXPORT int Jim_InitHashTable (Jim_HashTable *ht,
+        const Jim_HashTableType *type, void *privdata);
+JIM_EXPORT int Jim_ExpandHashTable (Jim_HashTable *ht,
+        unsigned int size);
+JIM_EXPORT int Jim_AddHashEntry (Jim_HashTable *ht, const void *key,
+        void *val);
+JIM_EXPORT int Jim_ReplaceHashEntry (Jim_HashTable *ht,
+        const void *key, void *val);
+JIM_EXPORT int Jim_DeleteHashEntry (Jim_HashTable *ht,
+        const void *key);
+JIM_EXPORT int Jim_FreeHashTable (Jim_HashTable *ht);
+JIM_EXPORT Jim_HashEntry * Jim_FindHashEntry (Jim_HashTable *ht,
+        const void *key);
+JIM_EXPORT int Jim_ResizeHashTable (Jim_HashTable *ht);
+JIM_EXPORT Jim_HashTableIterator *Jim_GetHashTableIterator
+        (Jim_HashTable *ht);
+JIM_EXPORT Jim_HashEntry * Jim_NextHashEntry
+        (Jim_HashTableIterator *iter);
+
+/* objects */
+JIM_EXPORT Jim_Obj * Jim_NewObj (Jim_Interp *interp);
+JIM_EXPORT void Jim_FreeObj (Jim_Interp *interp, Jim_Obj *objPtr);
+JIM_EXPORT void Jim_InvalidateStringRep (Jim_Obj *objPtr);
+JIM_EXPORT void Jim_InitStringRep (Jim_Obj *objPtr, const char *bytes,
+        int length);
+JIM_EXPORT Jim_Obj * Jim_DuplicateObj (Jim_Interp *interp,
+        Jim_Obj *objPtr);
+JIM_EXPORT const char * Jim_GetString(Jim_Obj *objPtr,
+        int *lenPtr);
+JIM_EXPORT int Jim_Length(Jim_Obj *objPtr);
+
+/* string object */
+JIM_EXPORT Jim_Obj * Jim_NewStringObj (Jim_Interp *interp,
+        const char *s, int len);
+JIM_EXPORT Jim_Obj *Jim_NewStringObjUtf8(Jim_Interp *interp,
+        const char *s, int charlen);
+JIM_EXPORT Jim_Obj * Jim_NewStringObjNoAlloc (Jim_Interp *interp,
+        char *s, int len);
+JIM_EXPORT void Jim_AppendString (Jim_Interp *interp, Jim_Obj *objPtr,
+        const char *str, int len);
+JIM_EXPORT void Jim_AppendObj (Jim_Interp *interp, Jim_Obj *objPtr,
+        Jim_Obj *appendObjPtr);
+JIM_EXPORT void Jim_AppendStrings (Jim_Interp *interp,
+        Jim_Obj *objPtr, ...);
+JIM_EXPORT int Jim_StringEqObj(Jim_Obj *aObjPtr, Jim_Obj *bObjPtr);
+JIM_EXPORT int Jim_StringMatchObj (Jim_Interp *interp, Jim_Obj *patternObjPtr,
+        Jim_Obj *objPtr, int nocase);
+JIM_EXPORT Jim_Obj * Jim_StringRangeObj (Jim_Interp *interp,
+        Jim_Obj *strObjPtr, Jim_Obj *firstObjPtr,
+        Jim_Obj *lastObjPtr);
+JIM_EXPORT Jim_Obj * Jim_FormatString (Jim_Interp *interp,
+        Jim_Obj *fmtObjPtr, int objc, Jim_Obj *const *objv);
+JIM_EXPORT Jim_Obj * Jim_ScanString (Jim_Interp *interp, Jim_Obj *strObjPtr,
+        Jim_Obj *fmtObjPtr, int flags);
+JIM_EXPORT int Jim_CompareStringImmediate (Jim_Interp *interp,
+        Jim_Obj *objPtr, const char *str);
+JIM_EXPORT int Jim_StringCompareObj(Jim_Interp *interp, Jim_Obj *firstObjPtr,
+        Jim_Obj *secondObjPtr, int nocase);
+JIM_EXPORT int Jim_Utf8Length(Jim_Interp *interp, Jim_Obj *objPtr);
+
+/* reference object */
+JIM_EXPORT Jim_Obj * Jim_NewReference (Jim_Interp *interp,
+        Jim_Obj *objPtr, Jim_Obj *tagPtr, Jim_Obj *cmdNamePtr);
+JIM_EXPORT Jim_Reference * Jim_GetReference (Jim_Interp *interp,
+        Jim_Obj *objPtr);
+JIM_EXPORT int Jim_SetFinalizer (Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj *cmdNamePtr);
+JIM_EXPORT int Jim_GetFinalizer (Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj **cmdNamePtrPtr);
+
+/* interpreter */
+JIM_EXPORT Jim_Interp * Jim_CreateInterp (void);
+JIM_EXPORT void Jim_FreeInterp (Jim_Interp *i);
+JIM_EXPORT int Jim_GetExitCode (Jim_Interp *interp);
+JIM_EXPORT const char *Jim_ReturnCode(int code);
+JIM_EXPORT void Jim_SetResultFormatted(Jim_Interp *interp, const char *format, ...);
+
+/* commands */
+JIM_EXPORT void Jim_RegisterCoreCommands (Jim_Interp *interp);
+JIM_EXPORT int Jim_CreateCommand (Jim_Interp *interp,
+        const char *cmdName, Jim_CmdProc cmdProc, void *privData,
+         Jim_DelCmdProc delProc);
+JIM_EXPORT int Jim_DeleteCommand (Jim_Interp *interp,
+        const char *cmdName);
+JIM_EXPORT int Jim_RenameCommand (Jim_Interp *interp,
+        const char *oldName, const char *newName);
+JIM_EXPORT Jim_Cmd * Jim_GetCommand (Jim_Interp *interp,
+        Jim_Obj *objPtr, int flags);
+JIM_EXPORT int Jim_SetVariable (Jim_Interp *interp,
+        Jim_Obj *nameObjPtr, Jim_Obj *valObjPtr);
+JIM_EXPORT int Jim_SetVariableStr (Jim_Interp *interp,
+        const char *name, Jim_Obj *objPtr);
+JIM_EXPORT int Jim_SetGlobalVariableStr (Jim_Interp *interp,
+        const char *name, Jim_Obj *objPtr);
+JIM_EXPORT int Jim_SetVariableStrWithStr (Jim_Interp *interp,
+        const char *name, const char *val);
+JIM_EXPORT int Jim_SetVariableLink (Jim_Interp *interp,
+        Jim_Obj *nameObjPtr, Jim_Obj *targetNameObjPtr,
+        Jim_CallFrame *targetCallFrame);
+JIM_EXPORT Jim_Obj * Jim_GetVariable (Jim_Interp *interp,
+        Jim_Obj *nameObjPtr, int flags);
+JIM_EXPORT Jim_Obj * Jim_GetGlobalVariable (Jim_Interp *interp,
+        Jim_Obj *nameObjPtr, int flags);
+JIM_EXPORT Jim_Obj * Jim_GetVariableStr (Jim_Interp *interp,
+        const char *name, int flags);
+JIM_EXPORT Jim_Obj * Jim_GetGlobalVariableStr (Jim_Interp *interp,
+        const char *name, int flags);
+JIM_EXPORT int Jim_UnsetVariable (Jim_Interp *interp,
+        Jim_Obj *nameObjPtr, int flags);
+
+/* call frame */
+JIM_EXPORT Jim_CallFrame *Jim_GetCallFrameByLevel(Jim_Interp *interp,
+        Jim_Obj *levelObjPtr);
+
+/* garbage collection */
+JIM_EXPORT int Jim_Collect (Jim_Interp *interp);
+JIM_EXPORT void Jim_CollectIfNeeded (Jim_Interp *interp);
+
+/* index object */
+JIM_EXPORT int Jim_GetIndex (Jim_Interp *interp, Jim_Obj *objPtr,
+        int *indexPtr);
+
+/* list object */
+JIM_EXPORT Jim_Obj * Jim_NewListObj (Jim_Interp *interp,
+        Jim_Obj *const *elements, int len);
+JIM_EXPORT void Jim_ListInsertElements (Jim_Interp *interp,
+        Jim_Obj *listPtr, int listindex, int objc, Jim_Obj *const *objVec);
+JIM_EXPORT void Jim_ListAppendElement (Jim_Interp *interp,
+        Jim_Obj *listPtr, Jim_Obj *objPtr);
+JIM_EXPORT void Jim_ListAppendList (Jim_Interp *interp,
+        Jim_Obj *listPtr, Jim_Obj *appendListPtr);
+JIM_EXPORT int Jim_ListLength (Jim_Interp *interp, Jim_Obj *objPtr);
+JIM_EXPORT int Jim_ListIndex (Jim_Interp *interp, Jim_Obj *listPrt,
+        int listindex, Jim_Obj **objPtrPtr, int seterr);
+JIM_EXPORT int Jim_SetListIndex (Jim_Interp *interp,
+        Jim_Obj *varNamePtr, Jim_Obj *const *indexv, int indexc,
+        Jim_Obj *newObjPtr);
+JIM_EXPORT Jim_Obj * Jim_ConcatObj (Jim_Interp *interp, int objc,
+        Jim_Obj *const *objv);
+
+/* dict object */
+JIM_EXPORT Jim_Obj * Jim_NewDictObj (Jim_Interp *interp,
+        Jim_Obj *const *elements, int len);
+JIM_EXPORT int Jim_DictKey (Jim_Interp *interp, Jim_Obj *dictPtr,
+        Jim_Obj *keyPtr, Jim_Obj **objPtrPtr, int flags);
+JIM_EXPORT int Jim_DictKeysVector (Jim_Interp *interp,
+        Jim_Obj *dictPtr, Jim_Obj *const *keyv, int keyc,
+        Jim_Obj **objPtrPtr, int flags);
+JIM_EXPORT int Jim_SetDictKeysVector (Jim_Interp *interp,
+        Jim_Obj *varNamePtr, Jim_Obj *const *keyv, int keyc,
+        Jim_Obj *newObjPtr, int flags);
+JIM_EXPORT int Jim_DictPairs(Jim_Interp *interp,
+        Jim_Obj *dictPtr, Jim_Obj ***objPtrPtr, int *len);
+JIM_EXPORT int Jim_DictAddElement(Jim_Interp *interp, Jim_Obj *objPtr,
+        Jim_Obj *keyObjPtr, Jim_Obj *valueObjPtr);
+JIM_EXPORT int Jim_DictKeys(Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj *patternObj);
+JIM_EXPORT int Jim_DictSize(Jim_Interp *interp, Jim_Obj *objPtr);
+
+/* return code object */
+JIM_EXPORT int Jim_GetReturnCode (Jim_Interp *interp, Jim_Obj *objPtr,
+        int *intPtr);
+
+/* expression object */
+JIM_EXPORT int Jim_EvalExpression (Jim_Interp *interp,
+        Jim_Obj *exprObjPtr, Jim_Obj **exprResultPtrPtr);
+JIM_EXPORT int Jim_GetBoolFromExpr (Jim_Interp *interp,
+        Jim_Obj *exprObjPtr, int *boolPtr);
+
+/* integer object */
+JIM_EXPORT int Jim_GetWide (Jim_Interp *interp, Jim_Obj *objPtr,
+        jim_wide *widePtr);
+JIM_EXPORT int Jim_GetLong (Jim_Interp *interp, Jim_Obj *objPtr,
+        long *longPtr);
+#define Jim_NewWideObj  Jim_NewIntObj
+JIM_EXPORT Jim_Obj * Jim_NewIntObj (Jim_Interp *interp,
+        jim_wide wideValue);
+
+/* double object */
+JIM_EXPORT int Jim_GetDouble(Jim_Interp *interp, Jim_Obj *objPtr,
+        double *doublePtr);
+JIM_EXPORT void Jim_SetDouble(Jim_Interp *interp, Jim_Obj *objPtr,
+        double doubleValue);
+JIM_EXPORT Jim_Obj * Jim_NewDoubleObj(Jim_Interp *interp, double doubleValue);
+
+/* shared strings */
+JIM_EXPORT const char * Jim_GetSharedString (Jim_Interp *interp,
+        const char *str);
+JIM_EXPORT void Jim_ReleaseSharedString (Jim_Interp *interp,
+        const char *str);
+
+/* commands utilities */
+JIM_EXPORT void Jim_WrongNumArgs (Jim_Interp *interp, int argc,
+        Jim_Obj *const *argv, const char *msg);
+JIM_EXPORT int Jim_GetEnum (Jim_Interp *interp, Jim_Obj *objPtr,
+        const char * const *tablePtr, int *indexPtr, const char *name, int flags);
+JIM_EXPORT int Jim_ScriptIsComplete (const char *s, int len,
+        char *stateCharPtr);
+/**
+ * Find a matching name in the array of the given length.
+ *
+ * NULL entries are ignored.
+ *
+ * Returns the matching index if found, or -1 if not.
+ */
+JIM_EXPORT int Jim_FindByName(const char *name, const char * const array[], size_t len);
+
+/* package utilities */
+typedef void (Jim_InterpDeleteProc)(Jim_Interp *interp, void *data);
+JIM_EXPORT void * Jim_GetAssocData(Jim_Interp *interp, const char *key);
+JIM_EXPORT int Jim_SetAssocData(Jim_Interp *interp, const char *key,
+        Jim_InterpDeleteProc *delProc, void *data);
+JIM_EXPORT int Jim_DeleteAssocData(Jim_Interp *interp, const char *key);
+
+/* Packages C API */
+/* jim-package.c */
+JIM_EXPORT int Jim_PackageProvide (Jim_Interp *interp,
+        const char *name, const char *ver, int flags);
+JIM_EXPORT int Jim_PackageRequire (Jim_Interp *interp,
+        const char *name, int flags);
+
+/* error messages */
+JIM_EXPORT void Jim_MakeErrorMessage (Jim_Interp *interp);
+
+/* interactive mode */
+JIM_EXPORT int Jim_InteractivePrompt (Jim_Interp *interp);
+
+/* Misc */
+JIM_EXPORT int Jim_InitStaticExtensions(Jim_Interp *interp);
+JIM_EXPORT int Jim_StringToWide(const char *str, jim_wide *widePtr, int base);
+
+/* jim-load.c */
+JIM_EXPORT int Jim_LoadLibrary(Jim_Interp *interp, const char *pathName);
+JIM_EXPORT void Jim_FreeLoadHandles(Jim_Interp *interp);
+
+/* jim-aio.c */
+JIM_EXPORT FILE *Jim_AioFilehandle(Jim_Interp *interp, Jim_Obj *command);
+
+
+/* type inspection - avoid where possible */
+JIM_EXPORT int Jim_IsDict(Jim_Obj *objPtr);
+JIM_EXPORT int Jim_IsList(Jim_Obj *objPtr);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __JIM__H */
+
+/*
+ * Local Variables: ***
+ * c-basic-offset: 4 ***
+ * tab-width: 4 ***
+ * End: ***
+ */

Index: src/main.c
==================================================================
--- src/main.c
+++ src/main.c
@@ -26,10 +26,12 @@
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <stdlib.h> /* atexit() */
 
 #if INTERFACE
+#include <jim.h>
+
 #ifdef FOSSIL_ENABLE_JSON
 #  include "cson_amalgamation.h" /* JSON API. Needed inside the INTERFACE block! */
 #  include "json_detail.h"
 #endif
 #ifdef FOSSIL_ENABLE_TCL
@@ -127,11 +129,11 @@
   int sslNotAvailable;    /* SSL is not available.  Do not redirect to https: */
   Blob cgiIn;             /* Input to an xfer www method */
   int cgiOutput;          /* Write error and status messages to CGI */
   int xferPanic;          /* Write error messages in XFER protocol */
   int fullHttpReply;      /* True for full HTTP reply.  False for CGI reply */
-  Th_Interp *interp;      /* The TH1 interpreter */
+  Jim_Interp *interp;     /* The script interpreter */
   FILE *httpIn;           /* Accept HTTP input from here */
   FILE *httpOut;          /* Send HTTP output here */
   int xlinkClusterOnly;   /* Set when cloning.  Only process clusters */
   int fTimeFormat;        /* 1 for UTC.  2 for localtime.  0 not yet selected */
   int *aCommitFile;       /* Array of files to be committed */
@@ -178,12 +180,12 @@
   char zCsrfToken[12];    /* Value of the anti-CSRF token */
   int okCsrf;             /* Anti-CSRF token is present and valid */
 
   int parseCnt[10];       /* Counts of artifacts parsed */
   FILE *fDebug;           /* Write debug information here, if the file exists */
-  int thTrace;            /* True to enable TH1 debugging output */
-  Blob thLog;             /* Text of the TH1 debugging output */
+  int thTrace;            /* True to enable script debugging output */
+  Blob thLog;             /* Text of the script debugging output */
 
   int isHome;             /* True if rendering the "home" page */
 
   /* Storage for the aux() and/or option() SQL function arguments */
   int nAux;                    /* Number of distinct aux() or option() values */

Index: src/main.mk
==================================================================
--- src/main.mk
+++ src/main.mk
@@ -347,11 +347,11 @@
 # link to the Tcl library.
 TCL_OBJ.0 = 
 TCL_OBJ.1 = $(OBJDIR)/th_tcl.o
 TCL_OBJ. = $(TCL_OBJ.0)
 
-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
+EXTRAOBJ =  $(SQLITE3_OBJ.$(USE_SYSTEM_SQLITE))  $(OBJDIR)/shell.o  $(OBJDIR)/jimtcl.o  $(TCL_OBJ.$(FOSSIL_ENABLE_TCL))  $(OBJDIR)/cson_amalgamation.o
 
 $(APPNAME):	$(OBJDIR)/headers $(OBJ) $(EXTRAOBJ)
 	$(TCC) -o $(APPNAME) $(OBJ) $(EXTRAOBJ) $(LIB)
 
 # This rule prevents make from using its default rules to try build
@@ -365,11 +365,11 @@
 
 
 $(OBJDIR)/page_index.h: $(TRANS_SRC) $(OBJDIR)/mkindex
 	$(OBJDIR)/mkindex $(TRANS_SRC) >$@
 $(OBJDIR)/headers:	$(OBJDIR)/page_index.h $(OBJDIR)/makeheaders $(OBJDIR)/VERSION.h
-	$(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
+	$(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
 	touch $(OBJDIR)/headers
 $(OBJDIR)/headers: Makefile
 $(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
 Makefile:
 $(OBJDIR)/add_.c:	$(SRCDIR)/add.c $(OBJDIR)/translate
@@ -1040,12 +1040,15 @@
 	$(XTCC) -I$(SRCDIR) -c $(SRCDIR)/th.c -o $(OBJDIR)/th.o
 
 $(OBJDIR)/th_lang.o:	$(SRCDIR)/th_lang.c
 	$(XTCC) -I$(SRCDIR) -c $(SRCDIR)/th_lang.c -o $(OBJDIR)/th_lang.o
 
+$(OBJDIR)/jimtcl.o:	$(SRCDIR)/../autosetup/jimsh0.c
+	$(XTCC) -I$(SRCDIR) -DJIM_BOOTSTRAP_LIB_ONLY -c $(SRCDIR)/../autosetup/jimsh0.c -o $(OBJDIR)/jimtcl.o
+
 $(OBJDIR)/th_tcl.o:	$(SRCDIR)/th_tcl.c
 	$(XTCC) -I$(SRCDIR) -c $(SRCDIR)/th_tcl.c -o $(OBJDIR)/th_tcl.o
 
 
 $(OBJDIR)/cson_amalgamation.o: $(SRCDIR)/cson_amalgamation.c
 	$(XTCC) -I$(SRCDIR) -c $(SRCDIR)/cson_amalgamation.c -o $(OBJDIR)/cson_amalgamation.o -DCSON_FOSSIL_MODE
 

Index: src/makemake.tcl
==================================================================
--- src/makemake.tcl
+++ src/makemake.tcl
@@ -223,12 +223,11 @@
 TCL_OBJ. = $(TCL_OBJ.0)
 
 EXTRAOBJ = \
   $(SQLITE3_OBJ.$(USE_SYSTEM_SQLITE)) \
   $(OBJDIR)/shell.o \
-  $(OBJDIR)/th.o \
-  $(OBJDIR)/th_lang.o \
+  $(OBJDIR)/jimtcl.o \
   $(TCL_OBJ.$(FOSSIL_ENABLE_TCL)) \
   $(OBJDIR)/cson_amalgamation.o
 
 $(APPNAME):	$(OBJDIR)/headers $(OBJ) $(EXTRAOBJ)
 	$(TCC) -o $(APPNAME) $(OBJ) $(EXTRAOBJ) $(LIB)
@@ -248,11 +247,11 @@
 foreach s [lsort $src] {
   append mhargs " \$(OBJDIR)/${s}_.c:\$(OBJDIR)/$s.h"
   set extra_h($s) {}
 }
 append mhargs " \$(SRCDIR)/sqlite3.h"
-append mhargs " \$(SRCDIR)/th.h"
+append mhargs " \$(SRCDIR)/jim.h"
 #append mhargs " \$(SRCDIR)/cson_amalgamation.h"
 append mhargs " \$(OBJDIR)/VERSION.h"
 writeln "\$(OBJDIR)/page_index.h: \$(TRANS_SRC) \$(OBJDIR)/mkindex"
 writeln "\t\$(OBJDIR)/mkindex \$(TRANS_SRC) >$@"
 writeln "\$(OBJDIR)/headers:\t\$(OBJDIR)/page_index.h \$(OBJDIR)/makeheaders \$(OBJDIR)/VERSION.h"
@@ -291,10 +290,13 @@
 writeln "\t\$(XTCC) -I\$(SRCDIR) -c \$(SRCDIR)/th.c -o \$(OBJDIR)/th.o\n"
 
 writeln "\$(OBJDIR)/th_lang.o:\t\$(SRCDIR)/th_lang.c"
 writeln "\t\$(XTCC) -I\$(SRCDIR) -c \$(SRCDIR)/th_lang.c -o \$(OBJDIR)/th_lang.o\n"
 
+writeln "\$(OBJDIR)/jimtcl.o:\t\$(SRCDIR)/../autosetup/jimsh0.c"
+writeln "\t\$(XTCC) -I\$(SRCDIR) -DJIM_BOOTSTRAP_LIB_ONLY -c \$(SRCDIR)/../autosetup/jimsh0.c -o \$(OBJDIR)/jimtcl.o\n"
+
 writeln "\$(OBJDIR)/th_tcl.o:\t\$(SRCDIR)/th_tcl.c"
 writeln "\t\$(XTCC) -I\$(SRCDIR) -c \$(SRCDIR)/th_tcl.c -o \$(OBJDIR)/th_tcl.o\n"
 
 set opt {}
 writeln {
@@ -571,11 +573,11 @@
 foreach s [lsort $src] {
   append mhargs " \$(OBJDIR)/${s}_.c:\$(OBJDIR)/$s.h"
   set extra_h($s) {}
 }
 append mhargs " \$(SRCDIR)/sqlite3.h"
-append mhargs " \$(SRCDIR)/th.h"
+append mhargs " \$(SRCDIR)/jim.h"
 append mhargs " \$(OBJDIR)/VERSION.h"
 writeln "\$(OBJDIR)/page_index.h: \$(TRANS_SRC) \$(OBJDIR)/mkindex"
 writeln "\t\$(MKINDEX) \$(TRANS_SRC) >$@"
 writeln "\$(OBJDIR)/headers:\t\$(OBJDIR)/page_index.h \$(OBJDIR)/makeheaders \$(OBJDIR)/VERSION.h"
 writeln "\t\$(MAKEHEADERS) $mhargs"
@@ -763,11 +765,12 @@
 
 writeln -nonewline "headers: makeheaders\$E page_index.h VERSION.h\n\t +makeheaders\$E "
 foreach s [lsort $src] {
   writeln -nonewline "${s}_.c:$s.h "
 }
-writeln "\$(SRCDIR)\\sqlite3.h \$(SRCDIR)\\th.h VERSION.h \$(SRCDIR)\\cson_amalgamation.h"
+writeln "\$(SRCDIR)\\sqlite3.h \$(SRCDIR)\\jim.h VERSION.h"
+writeln "\$(SRCDIR)\\sqlite3.h \$(SRCDIR)\\jim.h VERSION.h \$(SRCDIR)\\cson_amalgamation.h"
 writeln "\t@copy /Y nul: headers"
 
 close $output_file
 #
 # End of the win/Makefile.dmc output
@@ -919,11 +922,11 @@
 
 writeln -nonewline "headers: makeheaders\$E page_index.h VERSION.h\n\tmakeheaders\$E "
 foreach s [lsort $src] {
   writeln -nonewline "${s}_.c:$s.h "
 }
-writeln "\$(SRCDIR)\\sqlite3.h \$(SRCDIR)\\th.h VERSION.h \$(SRCDIR)\\cson_amalgamation.h"
+writeln "\$(SRCDIR)\\sqlite3.h \$(SRCDIR)\\jim.h VERSION.h \$(SRCDIR)\\cson_amalgamation.h"
 writeln "\t@copy /Y nul: headers"
 
 
 close $output_file
 #
@@ -1084,12 +1087,12 @@
 # extracting version info from manifest
 VERSION.h:	version.exe ..\manifest.uuid ..\manifest ..\VERSION
 	version.exe ..\manifest.uuid ..\manifest ..\VERSION  > $@
 
 # generate the simplified headers
-headers: makeheaders.exe page_index.h VERSION.h ../src/sqlite3.h ../src/th.h VERSION.h
-	makeheaders.exe $(foreach ts,$(TRANSLATEDSRC),$(ts):$(ts:_.c=.h)) ../src/sqlite3.h ../src/th.h VERSION.h
+headers: makeheaders.exe page_index.h VERSION.h ../src/sqlite3.h ../src/jim.h VERSION.h
+	makeheaders.exe $(foreach ts,$(TRANSLATEDSRC),$(ts):$(ts:_.c=.h)) ../src/sqlite3.h ../src/jim.h VERSION.h
 	echo Done >$@
 
 # compile C sources with relevant options
 
 $(TRANSLATEDOBJ):	%_.obj:	%_.c %.h
@@ -1099,11 +1102,11 @@
 	$(CC) $(CCFLAGS) $(SQLITEDEFINES) $(INCLUDE) "$<" -Fo"$@"
 
 $(SQLITESHELLOBJ):	%.obj:	$(SRCDIR)%.c
 	$(CC) $(CCFLAGS) $(SQLITESHELLDEFINES) $(INCLUDE) "$<" -Fo"$@"
 
-$(THOBJ):	%.obj:	$(SRCDIR)%.c $(SRCDIR)th.h
+$(THOBJ):	%.obj:	$(SRCDIR)%.c $(SRCDIR)jim.h
 	$(CC) $(CCFLAGS) $(INCLUDE) "$<" -Fo"$@"
 
 $(ZLIBOBJ):	%.obj:	$(ZLIBSRCDIR)%.c
 	$(CC) $(CCFLAGS) $(INCLUDE) "$<" -Fo"$@"
 

Index: src/name.c
==================================================================
--- src/name.c
+++ src/name.c
@@ -426,11 +426,11 @@
     db_prepare(&q,
        "SELECT type, datetime(mtime,'localtime'),"
        "       coalesce(euser,user), coalesce(ecomment,comment)"
        "  FROM event WHERE objid=%d", rid);
     if( db_step(&q)==SQLITE_ROW ){
-      const char *zType;
+      const char *zType = 0;
       switch( db_column_text(&q,0)[0] ){
         case 'c':  zType = "Check-in";       break;
         case 'w':  zType = "Wiki-edit";      break;
         case 'e':  zType = "Event";          break;
         case 't':  zType = "Ticket-change";  break;

DELETED src/th.c
Index: src/th.c
==================================================================
--- src/th.c
+++ src/th.c
@@ -1,2609 +0,0 @@
-
-/*
-** The implementation of the TH core. This file contains the parser, and 
-** the implementation of the interface in th.h.
-*/
-
-#include "th.h"
-#include <string.h>
-#include <assert.h>
-
-typedef struct Th_Command   Th_Command;
-typedef struct Th_Frame     Th_Frame;
-typedef struct Th_Variable  Th_Variable;
-
-/*
-** Interpreter structure.
-*/
-struct Th_Interp {
-  Th_Vtab *pVtab;     /* Copy of the argument passed to Th_CreateInterp() */
-  char *zResult;     /* Current interpreter result (Th_Malloc()ed) */
-  int nResult;        /* number of bytes in zResult */
-  Th_Hash *paCmd;     /* Table of registered commands */
-  Th_Frame *pFrame;   /* Current execution frame */
-  int isListMode;     /* True if thSplitList() should operate in "list" mode */
-};
-
-/*
-** Each TH command registered using Th_CreateCommand() is represented
-** by an instance of the following structure stored in the Th_Interp.paCmd
-** hash-table.
-*/
-struct Th_Command {
-  int (*xProc)(Th_Interp *, void *, int, const char **, int *);
-  void *pContext;
-  void (*xDel)(Th_Interp *, void *);
-};
-
-/*
-** Each stack frame (variable scope) is represented by an instance
-** of this structure. Variable values set using the Th_SetVar command
-** are stored in the Th_Frame.paVar hash table member of the associated
-** stack frame object.
-**
-** When an interpreter is created, a single Th_Frame structure is also
-** allocated - the global variable scope. Th_Interp.pFrame (the current
-** interpreter frame) is initialised to point to this Th_Frame. It is 
-** not deleted for the lifetime of the interpreter (because the global 
-** frame never goes out of scope).
-**
-** New stack frames are created by the Th_InFrame() function. Before
-** invoking its callback function, Th_InFrame() allocates a new Th_Frame
-** structure with pCaller set to the current frame (Th_Interp.pFrame),
-** and sets the current frame to the new frame object. After the callback
-** has been invoked, the allocated Th_Frame is deleted and the value
-** of the current frame pointer restored.
-** 
-** By default, the Th_SetVar(), Th_UnsetVar() and Th_GetVar() functions 
-** access variable values in the current frame. If they need to access 
-** the global frame, they do so by traversing the pCaller pointer list.
-** Likewise, the Th_LinkVar() function uses the pCaller pointers to 
-** link to variables located in the global or other stack frames.
-*/
-struct Th_Frame {
-  Th_Hash *paVar;               /* Variables defined in this scope */
-  Th_Frame *pCaller;            /* Calling frame */
-};
-
-/*
-** This structure represents a value assigned to a th1 variable.
-**
-** The Th_Frame.paVar hash table maps from variable name (a th1 string)
-** to a pointer to an instance of the following structure. More than
-** one hash table entry may map to a single structure if variable
-** links have been created using Th_LinkVar(). The number of references
-** is stored in Th_Variable.nRef.
-**
-** For scalar variables, Th_Variable.zData is never 0. Th_Variable.nData
-** stores the number of bytes in the value pointed to by zData.
-**
-** For an array variable, Th_Variable.zData is 0 and pHash points to
-** a hash table mapping between array key name (a th1 string) and
-** a the pointer to the Th_Variable structure holding the scalar
-** value.
-*/
-struct Th_Variable {
-  int nRef;                   /* Number of references to this structure */
-  int nData;                  /* Number of bytes at Th_Variable.zData */
-  char *zData;               /* Data for scalar variables */
-  Th_Hash *pHash;             /* Data for array variables */
-};
-
-/*
-** Hash table API:
-*/
-#define TH_HASHSIZE 257
-struct Th_Hash {
-  Th_HashEntry *a[TH_HASHSIZE];
-};
-
-static int thEvalLocal(Th_Interp *, const char *, int);
-static int thSplitList(Th_Interp*, const char*, int, char***, int **, int*);
-
-static int thHexdigit(char c);
-static int thEndOfLine(const char *, int);
-
-static int  thPushFrame(Th_Interp*, Th_Frame*);
-static void thPopFrame(Th_Interp*);
-
-static void thFreeVariable(Th_HashEntry*, void*);
-static void thFreeCommand(Th_HashEntry*, void*);
-
-/*
-** The following are used by both the expression and language parsers.
-** Given that the start of the input string (z, n) is a language 
-** construct of the relevant type (a command enclosed in [], an escape
-** sequence etc.), these functions determine the number of bytes
-** of the input consumed by the construct. For example:
-**
-**   int nByte;
-**   thNextCommand(interp, "[expr $a+1] $nIter", 18, &nByte);
-**
-** results in variable nByte being set to 11. Or, 
-**
-**   thNextVarname(interp, "$a+1", 4, &nByte);
-**
-** results in nByte being set to 2.
-*/
-static int thNextCommand(Th_Interp*, const char *z, int n, int *pN);
-static int thNextEscape (Th_Interp*, const char *z, int n, int *pN);
-static int thNextVarname(Th_Interp*, const char *z, int n, int *pN);
-static int thNextNumber (Th_Interp*, const char *z, int n, int *pN);
-static int thNextSpace  (Th_Interp*, const char *z, int n, int *pN);
-
-/*
-** Given that the input string (z, n) contains a language construct of
-** the relevant type (a command enclosed in [], an escape sequence 
-** like "\xFF" or a variable reference like "${varname}", perform
-** substitution on the string and store the resulting string in
-** the interpreter result.
-*/
-static int thSubstCommand(Th_Interp*, const char *z, int n);
-static int thSubstEscape (Th_Interp*, const char *z, int n);
-static int thSubstVarname(Th_Interp*, const char *z, int n);
-
-/*
-** Given that there is a th1 word located at the start of the input 
-** string (z, n), determine the length in bytes of that word. If the
-** isCmd argument is non-zero, then an unescaped ";" byte not 
-** located inside of a block or quoted string is considered to mark 
-** the end of the word.
-*/
-static int thNextWord(Th_Interp*, const char *z, int n, int *pN, int isCmd);
-
-/*
-** Perform substitution on the word contained in the input string (z, n).
-** Store the resulting string in the interpreter result.
-*/
-static int thSubstWord(Th_Interp*, const char *z, int n);
-
-/*
-** The Buffer structure and the thBufferXXX() functions are used to make
-** memory allocation easier when building up a result.
-*/
-struct Buffer {
-  char *zBuf;
-  int nBuf;
-  int nBufAlloc;
-};
-typedef struct Buffer Buffer;
-static int  thBufferWrite(Th_Interp *interp, Buffer *, const char *, int);
-static void thBufferInit(Buffer *);
-static void thBufferFree(Th_Interp *interp, Buffer *);
-
-/*
-** Append nAdd bytes of content copied from zAdd to the end of buffer
-** pBuffer. If there is not enough space currently allocated, resize
-** the allocation to make space.
-*/
-static int thBufferWrite(
-  Th_Interp *interp, 
-  Buffer *pBuffer, 
-  const char *zAdd, 
-  int nAdd
-){
-  int nReq;
-
-  if( nAdd<0 ){
-    nAdd = th_strlen(zAdd);
-  }
-  nReq = pBuffer->nBuf+nAdd+1;
-
-  if( nReq>pBuffer->nBufAlloc ){
-    char *zNew;
-    int nNew;
-
-    nNew = nReq*2;
-    zNew = (char *)Th_Malloc(interp, nNew);
-    memcpy(zNew, pBuffer->zBuf, pBuffer->nBuf);
-    Th_Free(interp, pBuffer->zBuf);
-    pBuffer->nBufAlloc = nNew;
-    pBuffer->zBuf = zNew;
-  }
-
-  memcpy(&pBuffer->zBuf[pBuffer->nBuf], zAdd, nAdd);
-  pBuffer->nBuf += nAdd;
-  pBuffer->zBuf[pBuffer->nBuf] = '\0';
-
-  return TH_OK;
-}
-#define thBufferWrite(a,b,c,d) thBufferWrite(a,b,(const char *)c,d)
-
-/*
-** Initialize the Buffer structure pointed to by pBuffer.
-*/
-static void thBufferInit(Buffer *pBuffer){
-  memset(pBuffer, 0, sizeof(Buffer));
-}
-
-/*
-** Zero the buffer pointed to by pBuffer and free the associated memory
-** allocation.
-*/
-static void thBufferFree(Th_Interp *interp, Buffer *pBuffer){
-  Th_Free(interp, pBuffer->zBuf);
-  thBufferInit(pBuffer);
-}
-
-/*
-** Assuming parameter c contains a hexadecimal digit character,
-** return the corresponding value of that digit. If c is not
-** a hexadecimal digit character, -1 is returned.
-*/
-static int thHexdigit(char c){
-  switch (c) {
-    case '0': return 0;
-    case '1': return 1;
-    case '2': return 2;
-    case '3': return 3;
-    case '4': return 4;
-    case '5': return 5;
-    case '6': return 6;
-    case '7': return 7;
-    case '8': return 8;
-    case '9': return 9;
-    case 'a': case 'A': return 10;
-    case 'b': case 'B': return 11;
-    case 'c': case 'C': return 12;
-    case 'd': case 'D': return 13;
-    case 'e': case 'E': return 14;
-    case 'f': case 'F': return 15;
-  }
-  return -1;
-}
-
-/*
-** Argument pEntry points to an entry in a stack frame hash table
-** (Th_Frame.paVar). Decrement the refrerence count of the Th_Variable
-** structure that the entry points to. Free the Th_Variable if its
-** reference count reaches 0.
-**
-** Argument pContext is a pointer to the interpreter structure.
-*/
-static void thFreeVariable(Th_HashEntry *pEntry, void *pContext){
-  Th_Variable *pValue = (Th_Variable *)pEntry->pData;
-  pValue->nRef--;
-  assert( pValue->nRef>=0 );
-  if( pValue->nRef==0 ){
-    Th_Interp *interp = (Th_Interp *)pContext;
-    Th_Free(interp, pValue->zData);
-    if( pValue->pHash ){
-      Th_HashIterate(interp, pValue->pHash, thFreeVariable, pContext);
-      Th_HashDelete(interp, pValue->pHash);
-    }
-    Th_Free(interp, pValue);
-  }
-}
-
-/*
-** Argument pEntry points to an entry in the command hash table
-** (Th_Interp.paCmd). Delete the Th_Command structure that the
-** entry points to.
-**
-** Argument pContext is a pointer to the interpreter structure.
-*/
-static void thFreeCommand(Th_HashEntry *pEntry, void *pContext){
-  Th_Command *pCommand = (Th_Command *)pEntry->pData;
-  if( pCommand->xDel ){
-    pCommand->xDel((Th_Interp *)pContext, pCommand->pContext);
-  }
-  Th_Free((Th_Interp *)pContext, pEntry->pData);
-  pEntry->pData = 0;
-}
-
-/*
-** Push a new frame onto the stack.
-*/
-static int thPushFrame(Th_Interp *interp, Th_Frame *pFrame){
-  pFrame->paVar = Th_HashNew(interp);
-  pFrame->pCaller = interp->pFrame;
-  interp->pFrame = pFrame;
-  return TH_OK;
-}
-
-/*
-** Pop a frame off the top of the stack.
-*/
-static void thPopFrame(Th_Interp *interp){
-  Th_Frame *pFrame = interp->pFrame;
-  Th_HashIterate(interp, pFrame->paVar, thFreeVariable, (void *)interp);
-  Th_HashDelete(interp, pFrame->paVar);
-  interp->pFrame = pFrame->pCaller;
-}
-
-/*
-** The first part of the string (zInput,nInput) contains an escape 
-** sequence. Set *pnEscape to the number of bytes in the escape sequence.
-** If there is a parse error, return TH_ERROR and set the interpreter
-** result to an error message. Otherwise return TH_OK.
-*/
-static int thNextEscape(
-  Th_Interp *interp,
-  const char *zInput, 
-  int nInput, 
-  int *pnEscape
-){
-  int i = 2;
-
-  assert(nInput>0);
-  assert(zInput[0]=='\\');
-
-  if( nInput<=1 ){
-    return TH_ERROR;
-  }
-
-  switch( zInput[1] ){
-    case 'x': i = 4;
-  }
-
-  if( i>nInput ){
-    return TH_ERROR;
-  }
-  *pnEscape = i;
-  return TH_OK;
-}
-
-/*
-** The first part of the string (zInput,nInput) contains a variable
-** reference. Set *pnVarname to the number of bytes in the variable 
-** reference. If there is a parse error, return TH_ERROR and set the 
-** interpreter result to an error message. Otherwise return TH_OK.
-*/
-int thNextVarname(
-  Th_Interp *interp,
-  const char *zInput, 
-  int nInput, 
-  int *pnVarname
-){
-  int i;
-
-  assert(nInput>0);
-  assert(zInput[0]=='$');
-
-  if( nInput>0 && zInput[1]=='{' ){
-    for(i=2; i<nInput && zInput[i]!='}'; i++);
-    if( i==nInput ){
-      return TH_ERROR;
-    }
-    i++;
-  }else{
-    i = 1;
-    if( nInput>2 && zInput[1]==':' && zInput[2]==':' ){
-      i += 2;
-    }
-    for(; i<nInput; i++){
-      if( zInput[i]=='(' ){
-        for(i++; i<nInput; i++){
-          if( zInput[i]==')' ) break;
-          if( zInput[i]=='\\' ) i++;
-          if( zInput[i]=='{' || zInput[i]=='[' || zInput[i]=='"' ){
-            int nWord;
-            int rc = thNextWord(interp, &zInput[i], nInput-i, &nWord, 0);
-            if( rc!=TH_OK ){
-              return rc;
-            }
-            i += nWord;
-          }
-        }
-        if( i>=nInput ){
-          Th_ErrorMessage(interp, "Unmatched brackets:", zInput, nInput);
-          return TH_ERROR;
-        }
-        i++;
-        break;
-      }
-      if( !th_isalnum(zInput[i]) && zInput[i]!='_' ) break;
-    }
-  }
-
-  *pnVarname = i;
-  return TH_OK;
-}
-
-/*
-** The first part of the string (zInput,nInput) contains a command
-** enclosed in a "[]" block. Set *pnCommand to the number of bytes in 
-** the variable reference. If there is a parse error, return TH_ERROR 
-** and set the interpreter result to an error message. Otherwise return 
-** TH_OK.
-*/
-int thNextCommand(
-  Th_Interp *interp,
-  const char *zInput, 
-  int nInput, 
-  int *pnCommand
-){
-  int nBrace = 0;
-  int nSquare = 0;
-  int i;
-
-  assert(nInput>0);
-  assert( zInput[0]=='[' || zInput[0]=='{' );
-
-  for(i=0; i<nInput && (i==0 || nBrace>0 || nSquare>0); i++){
-    switch( zInput[i] ){
-      case '\\': i++; break;
-      case '{': nBrace++; break;
-      case '}': nBrace--; break;
-      case '[': nSquare++; break;
-      case ']': nSquare--; break;
-    }
-  }
-  if( nBrace || nSquare ){
-    return TH_ERROR;
-  }
-
-  *pnCommand = i;
-
-  return TH_OK;
-}
-
-/*
-** Set *pnSpace to the number of whitespace bytes at the start of 
-** input string (zInput, nInput). Always return TH_OK.
-*/
-int thNextSpace(
-  Th_Interp *interp,
-  const char *zInput, 
-  int nInput, 
-  int *pnSpace
-){
-  int i;
-  for(i=0; i<nInput && th_isspace(zInput[i]); i++);
-  *pnSpace = i;
-  return TH_OK;
-}
-
-/*
-** The first byte of the string (zInput,nInput) is not white-space.
-** Set *pnWord to the number of bytes in the th1 word that starts
-** with this byte. If a complete word cannot be parsed or some other
-** error occurs, return TH_ERROR and set the interpreter result to 
-** an error message. Otherwise return TH_OK.
-**
-** If the isCmd argument is non-zero, then an unescaped ";" byte not 
-** located inside of a block or quoted string is considered to mark 
-** the end of the word.
-*/
-static int thNextWord(
-  Th_Interp *interp,
-  const char *zInput, 
-  int nInput, 
-  int *pnWord,
-  int isCmd
-){
-  int iEnd = 0;
-
-  assert( !th_isspace(zInput[0]) );
-
-  if( zInput[0]=='"' ){
-    /* The word is terminated by the next unescaped '"' character. */
-    iEnd++;
-    while( iEnd<nInput && zInput[iEnd]!='"' ){
-      if( zInput[iEnd]=='\\' ){
-        iEnd++;
-      }
-      iEnd++;
-    }
-    iEnd++;
-  }else{
-    int nBrace = 0;
-    int nSq = 0;
-    while( iEnd<nInput && (nBrace>0 || nSq>0 ||
-      (!th_isspace(zInput[iEnd]) && (!isCmd || zInput[iEnd]!=';'))
-    )){
-      switch( zInput[iEnd] ){
-        case '\\': iEnd++; break;
-        case '{': if( nSq==0 ) nBrace++; break;
-        case '}': if( nSq==0 ) nBrace--; break;
-        case '[': if( nBrace==0 ) nSq++; break;
-        case ']': if( nBrace==0 ) nSq--; break;
-      }
-      iEnd++;
-    }
-    if( nBrace>0 || nSq>0 ){
-      /* Parse error */
-      return TH_ERROR;
-    }
-  }
-
-  if( iEnd>nInput ){
-    /* Parse error */
-    return TH_ERROR;
-  }
-  *pnWord = iEnd;
-  return TH_OK;
-}
-
-/*
-** The input string (zWord, nWord) contains a th1 script enclosed in
-** a [] block. Perform substitution on the input string and store the
-** resulting string in the interpreter result.
-*/
-static int thSubstCommand(
-  Th_Interp *interp,
-  const char *zWord,
-  int nWord
-){
-  assert(nWord>=2);
-  assert(zWord[0]=='[' && zWord[nWord-1]==']');
-  return thEvalLocal(interp, &zWord[1], nWord-2);
-}
-
-/*
-** The input string (zWord, nWord) contains a th1 variable reference
-** (a '$' byte followed by a variable name). Perform substitution on 
-** the input string and store the resulting string in the interpreter 
-** result.
-*/
-static int thSubstVarname(
-  Th_Interp *interp,
-  const char *zWord,
-  int nWord
-){
-  assert(nWord>=1);
-  assert(zWord[0]=='$');
-  assert(nWord==1 || zWord[1]!='{' || zWord[nWord-1]=='}');
-  if( nWord>1 && zWord[1]=='{' ){
-    zWord++;
-    nWord -= 2;
-  }else if( zWord[nWord-1]==')' ){
-    int i;
-    for(i=1; i<nWord && zWord[i]!='('; i++);
-    if( i<nWord ){
-      Buffer varname;
-      int nInner;
-      const char *zInner;
-
-      int rc = thSubstWord(interp, &zWord[i+1], nWord-i-2);
-      if( rc!=TH_OK ) return rc;
-
-      zInner = Th_GetResult(interp, &nInner);
-      thBufferInit(&varname);
-      thBufferWrite(interp, &varname, &zWord[1], i);
-      thBufferWrite(interp, &varname, zInner, nInner);
-      thBufferWrite(interp, &varname, ")", 1);
-      rc = Th_GetVar(interp, varname.zBuf, varname.nBuf);
-      thBufferFree(interp, &varname);
-      return rc;
-    }
-  }
-  return Th_GetVar(interp, &zWord[1], nWord-1);
-}
-
-/*
-** The input string (zWord, nWord) contains a th1 escape sequence.
-** Perform substitution on the input string and store the resulting 
-** string in the interpreter result.
-*/
-static int thSubstEscape(
-  Th_Interp *interp,
-  const char *zWord,
-  int nWord
-){
-  char c;
-
-  assert(nWord>=2);
-  assert(zWord[0]=='\\');
-
-  switch( zWord[1] ){
-    case 'x': {
-      assert(nWord==4);
-      c = ((thHexdigit(zWord[2])<<4) + thHexdigit(zWord[3]));
-      break;
-    }
-    case 'n': {
-      c = '\n';
-      break;
-    }
-    default: {
-      assert(nWord==2);
-      c = zWord[1];
-      break;
-    }
-  }
-
-  Th_SetResult(interp, &c, 1);
-  return TH_OK;
-}
-
-/*
-** The input string (zWord, nWord) contains a th1 word. Perform
-** substitution on the input string and store the resulting 
-** string in the interpreter result.
-*/
-static int thSubstWord(
-  Th_Interp *interp,
-  const char *zWord,
-  int nWord
-){
-  int rc = TH_OK;
-  Buffer output;
-  int i;
-
-  thBufferInit(&output);
-
-  if( nWord>1 && (zWord[0]=='{' && zWord[nWord-1]=='}') ){
-    rc = thBufferWrite(interp, &output, &zWord[1], nWord-2);
-  }else{
-
-    /* If the word is surrounded by double-quotes strip these away. */
-    if( nWord>1 && (zWord[0]=='"' && zWord[nWord-1]=='"') ){
-      zWord++;
-      nWord -= 2;
-    }
-
-    for(i=0; rc==TH_OK && i<nWord; i++){
-      int nGet;
-
-      int (*xGet)(Th_Interp *, const char*, int, int *) = 0;
-      int (*xSubst)(Th_Interp *, const char*, int) = 0;
-
-      switch( zWord[i] ){
-        case '\\':
-          xGet = thNextEscape; xSubst = thSubstEscape; 
-          break;
-        case '[':
-          if( !interp->isListMode ){
-            xGet = thNextCommand; xSubst = thSubstCommand; 
-            break;
-          }
-        case '$':
-          if( !interp->isListMode ){
-            xGet = thNextVarname; xSubst = thSubstVarname; 
-            break;
-          }
-        default: {
-          thBufferWrite(interp, &output, &zWord[i], 1);
-          continue; /* Go to the next iteration of the for(...) loop */
-        }
-      }
-
-      rc = xGet(interp, &zWord[i], nWord-i, &nGet);
-      if( rc==TH_OK ){
-        rc = xSubst(interp, &zWord[i], nGet);
-      }
-      if( rc==TH_OK ){
-        const char *zRes;
-        int nRes;
-        zRes = Th_GetResult(interp, &nRes);
-        rc = thBufferWrite(interp, &output, zRes, nRes);
-        i += (nGet-1);
-      }
-    }
-  }
-
-  if( rc==TH_OK ){
-    Th_SetResult(interp, output.zBuf, output.nBuf);
-  }
-  thBufferFree(interp, &output);
-  return rc;
-}
-
-/*
-** Return true if one of the following is true of the buffer pointed
-** to by zInput, length nInput:
-**
-**   + It is empty, or
-**   + It contains nothing but white-space, or
-**   + It contains no non-white-space characters before the first 
-**     newline character.
-**
-** Otherwise return false.
-*/
-static int thEndOfLine(const char *zInput, int nInput){
-  int i;
-  for(i=0; i<nInput && zInput[i]!='\n' && th_isspace(zInput[i]); i++);
-  return ((i==nInput || zInput[i]=='\n')?1:0);
-}
-
-/*
-** This function splits the supplied th1 list (contained in buffer zList,
-** size nList) into elements and performs word-substitution on each
-** element. If the Th_Interp.isListMode variable is true, then only
-** escape sequences are substituted (used by the Th_SplitList() function).
-** If Th_Interp.isListMode is false, then variable and command substitution
-** is also performed (used by Th_Eval()).
-**
-** If zList/nList does not contain a valid list, TH_ERROR is returned
-** and an error message stored in interp.
-**
-** If TH_OK is returned and pazElem is not NULL, the caller should free the
-** pointer written to (*pazElem) using Th_Free(). This releases memory
-** allocated for both the (*pazElem) and (*panElem) arrays. Example:
-**
-**     char **argv;
-**     int *argl;
-**     int argc;
-**
-**     // After this call, argv and argl point to valid arrays. The
-**     // number of elements in each is argc.
-**     //
-**     Th_SplitList(interp, zList, nList, &argv, &argl, &argc);
-**
-**     // Free all memory allocated by Th_SplitList(). The arrays pointed
-**     // to by argv and argl are invalidated by this call.
-**     //
-**     Th_Free(interp, argv);
-**
-*/ 
-static int thSplitList(
-  Th_Interp *interp,      /* Interpreter context */
-  const char *zList,     /* Pointer to buffer containing input list */
-  int nList,              /* Size of buffer pointed to by zList */
-  char ***pazElem,       /* OUT: Array of list elements */
-  int **panElem,          /* OUT: Lengths of each list element */
-  int *pnCount            /* OUT: Number of list elements */
-){
-  int rc = TH_OK;
-
-  Buffer strbuf;
-  Buffer lenbuf;
-  int nCount = 0;
-
-  const char *zInput = zList;
-  int nInput = nList;
-
-  thBufferInit(&strbuf);
-  thBufferInit(&lenbuf);
-
-  while( nInput>0 ){
-    const char *zWord;
-    int nWord;
-
-    thNextSpace(interp, zInput, nInput, &nWord);
-    zInput += nWord;
-    nInput = nList-(zInput-zList);
-
-    if( TH_OK!=(rc = thNextWord(interp, zInput, nInput, &nWord, 0))
-     || TH_OK!=(rc = thSubstWord(interp, zInput, nWord))
-    ){
-      goto finish;
-    }
-    zInput = &zInput[nWord];
-    nInput = nList-(zInput-zList);
-    if( nWord>0 ){
-      zWord = Th_GetResult(interp, &nWord);
-      thBufferWrite(interp, &strbuf, zWord, nWord);
-      thBufferWrite(interp, &strbuf, "\0", 1);
-      thBufferWrite(interp, &lenbuf, &nWord, sizeof(int));
-      nCount++;
-    }
-  }
-  assert((lenbuf.nBuf/sizeof(int))==nCount);
-
-  assert((pazElem && panElem) || (!pazElem && !panElem));
-  if( pazElem && rc==TH_OK ){
-    int i;
-    char *zElem; 
-    int *anElem;
-    char **azElem = Th_Malloc(interp,
-      sizeof(char*) * nCount +      /* azElem */
-      sizeof(int) * nCount +         /* anElem */
-      strbuf.nBuf                    /* space for list element strings */
-    );
-    anElem = (int *)&azElem[nCount];
-    zElem = (char *)&anElem[nCount];
-    memcpy(anElem, lenbuf.zBuf, lenbuf.nBuf);
-    memcpy(zElem, strbuf.zBuf, strbuf.nBuf);
-    for(i=0; i<nCount;i++){
-      azElem[i] = zElem;
-      zElem += (anElem[i] + 1);
-    }
-    *pazElem = azElem;
-    *panElem = anElem;
-  }
-  if( pnCount ){
-    *pnCount = nCount;
-  }
-  
- finish:
-  thBufferFree(interp, &strbuf);
-  thBufferFree(interp, &lenbuf);
-  return rc;
-}
-
-/*
-** Evaluate the th1 script contained in the string (zProgram, nProgram)
-** in the current stack frame.
-*/
-static int thEvalLocal(Th_Interp *interp, const char *zProgram, int nProgram){
-  int rc = TH_OK;
-  const char *zInput = zProgram;
-  int nInput = nProgram;
-
-  while( rc==TH_OK && nInput ){
-    Th_HashEntry *pEntry;
-    int nSpace;
-    const char *zFirst;
-
-    char **argv;
-    int *argl;
-    int argc;
-
-    assert(nInput>=0);
-
-    /* Skip a semi-colon */
-    if( *zInput==';' ){
-      zInput++;
-      nInput--;
-    }
-
-    /* Skip past leading white-space. */
-    thNextSpace(interp, zInput, nInput, &nSpace);
-    zInput += nSpace;
-    nInput -= nSpace;
-    zFirst = zInput;
-
-    /* Check for a comment. If found, skip to the end of the line. */
-    if( zInput[0]=='#' ){
-      while( !thEndOfLine(zInput, nInput) ){
-        zInput++;
-        nInput--;
-      }
-      continue;
-    }
-
-    /* Gobble up input a word at a time until the end of the command
-    ** (a semi-colon or end of line).
-    */
-    while( rc==TH_OK && *zInput!=';' && !thEndOfLine(zInput, nInput) ){
-      int nWord=0;
-      thNextSpace(interp, zInput, nInput, &nSpace);
-      rc = thNextWord(interp, &zInput[nSpace], nInput-nSpace, &nWord, 1);
-      zInput += (nSpace+nWord);
-      nInput -= (nSpace+nWord);
-    }
-    if( rc!=TH_OK ) continue;
-
-    /* Split the command into an array of words. This call also does
-    ** substitution of each individual word.
-    */
-    rc = thSplitList(interp, zFirst, zInput-zFirst, &argv, &argl, &argc);
-    if( rc!=TH_OK ) continue;
-
-    if( argc>0 ){
-
-      /* Look up the command name in the command hash-table. */
-      pEntry = Th_HashFind(interp, interp->paCmd, argv[0], argl[0], 0);
-      if( !pEntry ){
-        Th_ErrorMessage(interp, "no such command: ", argv[0], argl[0]);
-        rc = TH_ERROR;
-      }
-
-      /* Call the command procedure. */
-      if( rc==TH_OK ){
-        Th_Command *p = (Th_Command *)(pEntry->pData);
-        const char **azArg = (const char **)argv;
-        rc = p->xProc(interp, p->pContext, argc, azArg, argl);
-      }
-  
-      /* If an error occured, add this command to the stack trace report. */
-      if( rc==TH_ERROR ){
-        char *zRes;
-        int nRes;
-        char *zStack = 0;
-        int nStack = 0;
-  
-        zRes = Th_TakeResult(interp, &nRes);
-        if( TH_OK==Th_GetVar(interp, (char *)"::th_stack_trace", -1) ){
-          zStack = Th_TakeResult(interp, &nStack);
-        }
-        Th_ListAppend(interp, &zStack, &nStack, zFirst, zInput-zFirst);
-        Th_SetVar(interp, (char *)"::th_stack_trace", -1, zStack, nStack);
-        Th_SetResult(interp, zRes, nRes);
-        Th_Free(interp, zRes);
-        Th_Free(interp, zStack);
-      }
-    }
-
-    Th_Free(interp, argv);
-  }
-
-  return rc;
-}
-
-/*
-** Interpret an integer frame identifier passed to either Th_Eval() or
-** Th_LinkVar(). If successful, return a pointer to the identified
-** Th_Frame structure. If unsuccessful (no such frame), return 0 and
-** leave an error message in the interpreter result.
-**
-** Argument iFrame is interpreted as follows:
-**
-**   * If iFrame is 0, this means the current frame.
-**
-**   * If iFrame is negative, then the nth frame up the stack, where 
-**     n is the absolute value of iFrame. A value of -1 means the 
-**     calling procedure.
-**
-**   * If iFrame is +ve, then the nth frame from the bottom of the 
-**     stack. An iFrame value of 1 means the toplevel (global) frame.
-*/
-static Th_Frame *getFrame(Th_Interp *interp, int iFrame){
-  Th_Frame *p = interp->pFrame;
-  int i;
-  if( iFrame>0 ){
-    for(i=0; p; i++){
-      p = p->pCaller;
-    }
-    iFrame = (i*-1) + iFrame;
-    p = interp->pFrame;
-  }
-  for(i=0; p && i<(iFrame*-1); i++){
-    p = p->pCaller;
-  }
-
-  if( !p ){
-    char *zFrame;
-    int nFrame;
-    Th_SetResultInt(interp, iFrame);
-    zFrame = Th_TakeResult(interp, &nFrame);
-    Th_ErrorMessage(interp, "no such frame:", zFrame, nFrame);
-    Th_Free(interp, zFrame);
-  }
-  return p;
-}
-
-
-/*
-** Evaluate th1 script (zProgram, nProgram) in the frame identified by
-** argument iFrame. Leave either an error message or a result in the
-** interpreter result and return a th1 error code (TH_OK, TH_ERROR, 
-** TH_RETURN, TH_CONTINUE or TH_BREAK).
-*/
-int Th_Eval(Th_Interp *interp, int iFrame, const char *zProgram, int nProgram){
-  int rc = TH_OK;
-  Th_Frame *pSavedFrame = interp->pFrame;
-
-  /* Set Th_Interp.pFrame to the frame that this script is to be 
-  ** evaluated in. The current frame is saved in pSavedFrame and will
-  ** be restored before this function returns.
-  */
-  interp->pFrame = getFrame(interp, iFrame);
-
-  if( !interp->pFrame ){
-    rc = TH_ERROR;
-  }else{
-    int nInput = nProgram;
-  
-    if( nInput<0 ){
-      nInput = th_strlen(zProgram);
-    }
-    rc = thEvalLocal(interp, zProgram, nInput);
-  }
-
-  interp->pFrame = pSavedFrame;
-  return rc;
-}
-
-/*
-** Input string (zVarname, nVarname) contains a th1 variable name. It
-** may be a simple scalar variable name or it may be a reference
-** to an array member. The variable name may or may not begin with
-** "::", indicating that the name refers to a global variable, not
-** a local scope one.
-**
-** This function inspects and categorizes the supplied variable name.
-**
-** If the name is a global reference, *pisGlobal is set to true. Otherwise
-** false. Output string (*pzOuter, *pnOuter) is set to the variable name
-** if it is a scalar reference, or the name of the array if it is an
-** array variable. If the variable is a scalar, *pzInner is set to 0.
-** If it is an array variable, (*pzInner, *pnInner) is set to the
-** array key name.
-*/
-static int thAnalyseVarname(
-  const char *zVarname,
-  int nVarname,
-  const char **pzOuter,     /* OUT: Pointer to scalar/array name */
-  int *pnOuter,              /* OUT: Number of bytes at *pzOuter */
-  const char **pzInner,     /* OUT: Pointer to array key (or null) */
-  int *pnInner,              /* OUT: Number of bytes at *pzInner */
-  int *pisGlobal             /* OUT: Set to true if this is a global ref */
-){
-  const char *zOuter = zVarname;
-  int nOuter;
-  const char *zInner = 0;
-  int nInner = 0;
-  int isGlobal = 0;
-  int i;
-
-  if( nVarname<0 ){
-    nVarname = th_strlen(zVarname);
-  }
-  nOuter = nVarname;
-
-  /* If the variable name starts with "::", then do the lookup is in the
-  ** uppermost (global) frame.
-  */
-  if( nVarname>2 && zVarname[0]==':' && zVarname[1]==':' ){
-    zOuter += 2;
-    nOuter -= 2;
-    isGlobal = 1;
-  }
-
-  /* Check if this is an array reference. */
-  if( zOuter[nOuter-1]==')' ){
-    for(i=0; i<nOuter; i++){
-      if( zOuter[i]=='(' ){
-        zInner = &zOuter[i+1];
-        nInner = nOuter-i-2;
-        nOuter = i;
-        break;
-      }
-    }
-  }
-
-  *pzOuter = zOuter;
-  *pnOuter = nOuter;
-  *pzInner = zInner;
-  *pnInner = nInner;
-  *pisGlobal = isGlobal;
-  return TH_OK;
-}
-
-/*
-** Input string (zVar, nVar) contains a variable name. This function locates
-** the Th_Variable structure associated with the named variable. The 
-** variable name may be a global or local scalar or array variable
-**
-** If the create argument is non-zero and the named variable does not exist
-** it is created. Otherwise, an error is left in the interpreter result
-** and NULL returned.
-**
-** If the arrayok argument is false and the named variable is an array,
-** an error is left in the interpreter result and NULL returned. If
-** arrayok is true an array name is Ok.
-*/
-static Th_Variable *thFindValue(
-  Th_Interp *interp,
-  const char *zVar,     /* Pointer to variable name */
-  int nVar,              /* Number of bytes at nVar */
-  int create,            /* If true, create the variable if not found */
-  int arrayok            /* If true, an array is Ok. Othewise array==error */
-){
-  const char *zOuter;
-  int nOuter;
-  const char *zInner;
-  int nInner;
-  int isGlobal;
-
-  Th_HashEntry *pEntry;
-  Th_Frame *pFrame = interp->pFrame;
-  Th_Variable *pValue;
-
-  thAnalyseVarname(zVar, nVar, &zOuter, &nOuter, &zInner, &nInner, &isGlobal);
-  if( isGlobal ){
-    while( pFrame->pCaller ) pFrame = pFrame->pCaller;
-  }
-
-  pEntry = Th_HashFind(interp, pFrame->paVar, zOuter, nOuter, create);
-  assert(pEntry || !create);
-  if( !pEntry ){
-    goto no_such_var;
-  }
-
-  pValue = (Th_Variable *)pEntry->pData;
-  if( !pValue ){
-    assert(create);
-    pValue = Th_Malloc(interp, sizeof(Th_Variable));
-    pValue->nRef = 1;
-    pEntry->pData = (void *)pValue;
-  }
-
-  if( zInner ){
-    if( pValue->zData ){
-      Th_ErrorMessage(interp, "variable is a scalar:", zOuter, nOuter);
-      return 0;
-    }
-    if( !pValue->pHash ){
-      if( !create ){
-        goto no_such_var;
-      }
-      pValue->pHash = Th_HashNew(interp);
-    }
-    pEntry = Th_HashFind(interp, pValue->pHash, zInner, nInner, create);
-    if( !pEntry ){
-      goto no_such_var;
-    }
-    pValue = (Th_Variable *)pEntry->pData;
-    if( !pValue ){
-      assert(create);
-      pValue = Th_Malloc(interp, sizeof(Th_Variable));
-      pValue->nRef = 1;
-      pEntry->pData = (void *)pValue;
-    }
-  }else{
-    if( pValue->pHash && !arrayok ){
-      Th_ErrorMessage(interp, "variable is an array:", zOuter, nOuter);
-      return 0;
-    }
-  }
-
-  return pValue;
-
-no_such_var:
-  Th_ErrorMessage(interp, "no such variable:", zVar, nVar);
-  return 0;
-}
-
-/*
-** String (zVar, nVar) must contain the name of a scalar variable or 
-** array member. Look up the variable, store its current value in 
-** the interpreter result and return TH_OK.
-**
-** If the named variable does not exist, return TH_ERROR and leave
-** an error message in the interpreter result.
-*/
-int Th_GetVar(Th_Interp *interp, const char *zVar, int nVar){
-  Th_Variable *pValue;
-
-  pValue = thFindValue(interp, zVar, nVar, 0, 0);
-  if( !pValue ){
-    return TH_ERROR;
-  }
-  if( !pValue->zData ){
-    Th_ErrorMessage(interp, "no such variable:", zVar, nVar);
-    return TH_ERROR;
-  }
-
-  return Th_SetResult(interp, pValue->zData, pValue->nData);
-}
-
-/*
-** String (zVar, nVar) must contain the name of a scalar variable or
-** array member. If the variable does not exist it is created. The
-** variable is set to the value supplied in string (zValue, nValue).
-**
-** If (zVar, nVar) refers to an existing array, TH_ERROR is returned
-** and an error message left in the interpreter result.
-*/
-int Th_SetVar(
-  Th_Interp *interp, 
-  const char *zVar, 
-  int nVar,
-  const char *zValue,
-  int nValue
-){
-  Th_Variable *pValue;
-
-  pValue = thFindValue(interp, zVar, nVar, 1, 0);
-  if( !pValue ){
-    return TH_ERROR;
-  }
-
-  if( nValue<0 ){
-    nValue = th_strlen(zValue);
-  }
-  if( pValue->zData ){
-    Th_Free(interp, pValue->zData);
-    pValue->zData = 0;
-  }
-
-  assert(zValue || nValue==0);
-  pValue->zData = Th_Malloc(interp, nValue+1);
-  pValue->zData[nValue] = '\0';
-  memcpy(pValue->zData, zValue, nValue);
-  pValue->nData = nValue;
-
-  return TH_OK;
-}
-
-/*
-** Create a variable link so that accessing variable (zLocal, nLocal) is
-** the same as accessing variable (zLink, nLink) in stack frame iFrame.
-*/
-int Th_LinkVar(
-  Th_Interp *interp,                 /* Interpreter */
-  const char *zLocal, int nLocal,   /* Local varname */
-  int iFrame,                        /* Stack frame of linked var */
-  const char *zLink, int nLink      /* Linked varname */
-){
-  Th_Frame *pSavedFrame = interp->pFrame;
-  Th_Frame *pFrame;
-  Th_HashEntry *pEntry;
-  Th_Variable *pValue;
-
-  pFrame = getFrame(interp, iFrame);
-  if( !pFrame ){
-    return TH_ERROR;
-  }
-  pSavedFrame = interp->pFrame;
-  interp->pFrame = pFrame;
-  pValue = thFindValue(interp, zLink, nLink, 1, 1);
-  interp->pFrame = pSavedFrame;
-
-  pEntry = Th_HashFind(interp, interp->pFrame->paVar, zLocal, nLocal, 1);
-  if( pEntry->pData ){
-    Th_ErrorMessage(interp, "variable exists:", zLocal, nLocal);
-    return TH_ERROR;
-  }
-  pEntry->pData = (void *)pValue;
-  pValue->nRef++;
-
-  return TH_OK;
-}
-
-/*
-** Input string (zVar, nVar) must contain the name of a scalar variable,
-** an array, or an array member. If the identified variable exists, it
-** is deleted and TH_OK returned. Otherwise, an error message is left
-** in the interpreter result and TH_ERROR is returned.
-*/
-int Th_UnsetVar(Th_Interp *interp, const char *zVar, int nVar){
-  Th_Variable *pValue;
-
-  pValue = thFindValue(interp, zVar, nVar, 1, 1);
-  if( !pValue ){
-    return TH_ERROR;
-  }
-
-  Th_Free(interp, pValue->zData);
-  pValue->zData = 0;
-  if( pValue->pHash ){
-    Th_HashIterate(interp, pValue->pHash, thFreeVariable, (void *)interp);
-    Th_HashDelete(interp, pValue->pHash);
-    pValue->pHash = 0;
-  }
-  return TH_OK;
-}
-
-/*
-** Return an allocated buffer containing a copy of string (z, n). The
-** caller is responsible for eventually calling Th_Free() to free
-** the returned buffer.
-*/
-char *th_strdup(Th_Interp *interp, const char *z, int n){
-  char *zRes;
-  if( n<0 ){
-    n = th_strlen(z);
-  }
-  zRes = Th_Malloc(interp, n+1);
-  memcpy(zRes, z, n);
-  zRes[n] = '\0';
-  return zRes;
-}
-
-/*
-** Argument zPre must be a nul-terminated string. Set the interpreter
-** result to a string containing the contents of zPre, followed by
-** a space (" ") character, followed by a copy of string (z, n).
-**
-** In other words, the equivalent of:
-*
-**     printf("%s %.*s", zPre, n, z);
-**
-** Example:
-**
-**     Th_ErrorMessage(interp, "no such variable:", zVarname, nVarname);
-**
-*/
-int Th_ErrorMessage(Th_Interp *interp, const char *zPre, const char *z, int n){
-  if( interp ){
-    char *zRes = 0;
-    int nRes = 0;
-
-    Th_SetVar(interp, (char *)"::th_stack_trace", -1, 0, 0);
-  
-    Th_StringAppend(interp, &zRes, &nRes, zPre, -1);
-    if( zRes[nRes-1]=='"' ){
-      Th_StringAppend(interp, &zRes, &nRes, z, n);
-      Th_StringAppend(interp, &zRes, &nRes, (const char *)"\"", 1);
-    }else{
-      Th_StringAppend(interp, &zRes, &nRes, (const char *)" ", 1);
-      Th_StringAppend(interp, &zRes, &nRes, z, n);
-    }
-
-    Th_SetResult(interp, zRes, nRes);
-    Th_Free(interp, zRes);
-  }
-
-  return TH_OK;
-}
-
-/*
-** Set the current interpreter result by taking a copy of the buffer
-** pointed to by z, size n bytes. TH_OK is always returned.
-*/
-int Th_SetResult(Th_Interp *pInterp, const char *z, int n){
-
-  /* Free the current result */
-  Th_Free(pInterp, pInterp->zResult);
-  pInterp->zResult = 0;
-  pInterp->nResult = 0;
-
-  if( n<0 ){
-    n = th_strlen(z);
-  }
-
-  if( z && n>0 ){
-    char *zResult;
-    zResult = Th_Malloc(pInterp, n+1);
-    memcpy(zResult, z, n);
-    zResult[n] = '\0';
-    pInterp->zResult = zResult;
-    pInterp->nResult = n;
-  }
-
-  return TH_OK;
-}
-
-/*
-** Return a pointer to the buffer containing the current interpreter
-** result. If pN is not NULL, set *pN to the size of the returned
-** buffer.
-*/
-const char *Th_GetResult(Th_Interp *pInterp, int *pN){
-  assert(pInterp->zResult || pInterp->nResult==0);
-  if( pN ){
-    *pN = pInterp->nResult;
-  }
-  return (pInterp->zResult ? pInterp->zResult : (const char *)"");
-}
-
-/*
-** Return a pointer to the buffer containing the current interpreter
-** result. If pN is not NULL, set *pN to the size of the returned
-** buffer.
-**
-** This function is the same as Th_GetResult() except that the
-** caller is responsible for eventually calling Th_Free() on the
-** returned buffer. The internal interpreter result is cleared
-** after this function is called.
-*/
-char *Th_TakeResult(Th_Interp *pInterp, int *pN){
-  if( pN ){
-    *pN = pInterp->nResult;
-  }
-  if( pInterp->zResult ){
-    char *zResult = pInterp->zResult;
-    pInterp->zResult = 0;
-    pInterp->nResult = 0;
-    return zResult;
-  }else{
-    return (char *)Th_Malloc(pInterp, 1);
-  }
-}
-
-
-/* 
-** Wrappers around the supplied malloc() and free() 
-*/
-void *Th_Malloc(Th_Interp *pInterp, int nByte){
-  void *p = pInterp->pVtab->xMalloc(nByte);
-  if( p ){
-    memset(p, 0, nByte);
-  }
-  return p;
-}
-void Th_Free(Th_Interp *pInterp, void *z){
-  if( z ){
-    pInterp->pVtab->xFree(z);
-  }
-}
-
-/*
-** Install a new th1 command. 
-**
-** If a command of the same name already exists, it is deleted automatically.
-*/
-int Th_CreateCommand(
-  Th_Interp *interp, 
-  const char *zName,                 /* New command name */
-  Th_CommandProc xProc,              /* Command callback proc */
-  void *pContext,                    /* Value to pass as second arg to xProc */
-  void (*xDel)(Th_Interp *, void *)  /* Command destructor callback */
-){
-  Th_HashEntry *pEntry;
-  Th_Command *pCommand;
-
-  pEntry = Th_HashFind(interp, interp->paCmd, (const char *)zName, -1, 1);
-  if( pEntry->pData ){
-    pCommand = pEntry->pData;
-    if( pCommand->xDel ){
-      pCommand->xDel(interp, pCommand->pContext);
-    }
-  }else{
-    pCommand = Th_Malloc(interp, sizeof(Th_Command));
-  }
-  pCommand->xProc = xProc;
-  pCommand->pContext = pContext;
-  pCommand->xDel = xDel;
-  pEntry->pData = (void *)pCommand;
- 
-  return TH_OK;
-}
-
-/*
-** Rename the existing command (zName, nName) to (zNew, nNew). If nNew is 0, 
-** the command is deleted instead of renamed.
-**
-** If successful, TH_OK is returned. If command zName does not exist, or
-** if command zNew already exists, an error message is left in the 
-** interpreter result and TH_ERROR is returned.
-*/
-int Th_RenameCommand(
-  Th_Interp *interp, 
-  const char *zName,            /* Existing command name */
-  int nName,                     /* Number of bytes at zName */
-  const char *zNew,             /* New command name */
-  int nNew                       /* Number of bytes at zNew */
-){
-  Th_HashEntry *pEntry;
-  Th_HashEntry *pNewEntry;
-
-  pEntry = Th_HashFind(interp, interp->paCmd, zName, nName, 0);
-  if( !pEntry ){
-    Th_ErrorMessage(interp, "no such command:", zName, nName);
-    return TH_ERROR;
-  }
-  assert(pEntry->pData);
-
-  if( nNew>0 ){
-    pNewEntry = Th_HashFind(interp, interp->paCmd, zNew, nNew, 1);
-    if( pNewEntry->pData ){
-      Th_ErrorMessage(interp, "command exists:", zNew, nNew);
-      return TH_ERROR;
-    }
-    pNewEntry->pData = pEntry->pData;
-  }else{
-    Th_Command *pCommand = (Th_Command *)(pEntry->pData);
-    if( pCommand->xDel ){
-      pCommand->xDel(interp, pCommand->pContext);
-    }
-    Th_Free(interp, pCommand);
-  }
-
-  Th_HashFind(interp, interp->paCmd, zName, nName, -1);
-  return TH_OK;
-}
-
-/*
-** Push a stack frame onto the interpreter stack, invoke the
-** callback, and pop the frame back off again. See the implementation
-** of [proc] (th_lang.c) for an example.
-*/
-int Th_InFrame(Th_Interp *interp,
-  int (*xCall)(Th_Interp *, void *pContext1, void *pContext2),
-  void *pContext1,
-  void *pContext2
-){
-  Th_Frame frame;
-  int rc;
-  thPushFrame(interp, &frame);
-  rc = xCall(interp, pContext1, pContext2);
-  thPopFrame(interp);
-  return rc;
-}
-
-/*
-** Split a th1 list into its component elements. The list to split is
-** passed via arguments (zList, nList). If successful, TH_OK is returned.
-** If an error occurs (if (zList, nList) is not a valid list) an error
-** message is left in the interpreter result and TH_ERROR returned.
-**
-** If successful, *pnCount is set to the number of elements in the list.
-** panElem is set to point at an array of *pnCount integers - the lengths
-** of the element values. *pazElem is set to point at an array of 
-** pointers to buffers containing the array element's data.
-**
-** To free the arrays allocated at *pazElem and *panElem, the caller
-** should call Th_Free() on *pazElem only. Exactly one such call to
-** Th_Free() must be made per call to Th_SplitList().
-**
-** Example:
-**
-**     int nElem;
-**     int *anElem;
-**     char **azElem;
-**     int i;
-**
-**     Th_SplitList(interp, zList, nList, &azElem, &anElem, &nElem);
-**     for(i=0; i<nElem; i++){
-**       int nData = anElem[i];
-**       char *zData = azElem[i];
-**       ...
-**     }
-**
-**     Th_Free(interp, azElem);
-**
-*/
-int Th_SplitList(
-  Th_Interp *interp,
-  const char *zList,             /* Pointer to buffer containing list */
-  int nList,                      /* Number of bytes at zList */
-  char ***pazElem,               /* OUT: Array of pointers to element data */
-  int **panElem,                  /* OUT: Array of element data lengths */
-  int *pnCount                    /* OUT: Number of elements in list */
-){
-  int rc;
-  interp->isListMode = 1;
-  rc = thSplitList(interp, zList, nList, pazElem, panElem, pnCount);
-  interp->isListMode = 0;
-  if( rc ){
-    Th_ErrorMessage(interp, "Expected list, got: \"", zList, nList);
-  }
-  return rc;
-}
-
-/*
-** Append a new element to an existing th1 list. The element to append 
-** to the list is (zElem, nElem).
-**
-** A pointer to the existing list must be stored at *pzList when this
-** function is called. The length must be stored in *pnList. The value 
-** of *pzList must either be NULL (in which case *pnList must be 0), or 
-** a pointer to memory obtained from Th_Malloc().
-**
-** This function calls Th_Free() to free the buffer at *pzList and sets
-** *pzList to point to a new buffer containing the new list value. *pnList
-** is similarly updated before returning. The return value is always TH_OK.
-**
-** Example:
-**
-**     char *zList = 0;
-**     int nList = 0;
-**     for (...) {
-**       char *zElem = <some expression>;
-**       Th_ListAppend(interp, &zList, &nList, zElem, -1);
-**     }
-**     Th_SetResult(interp, zList, nList);
-**     Th_Free(interp, zList);
-**
-*/
-int Th_ListAppend(
-  Th_Interp *interp,           /* Interpreter context */
-  char **pzList,              /* IN/OUT: Ptr to ptr to list */
-  int *pnList,                 /* IN/OUT: Current length of *pzList */
-  const char *zElem,          /* Data to append */
-  int nElem                    /* Length of nElem */
-){
-  Buffer output;
-  int i;
-
-  int hasSpecialChar = 0;
-  int hasEscapeChar = 0;
-  int nBrace = 0;
-
-  output.zBuf = *pzList;
-  output.nBuf = *pnList;
-  output.nBufAlloc = output.nBuf;
-
-  if( nElem<0 ){
-    nElem = th_strlen(zElem);
-  }
-  if( output.nBuf>0 ){
-    thBufferWrite(interp, &output, " ", 1);
-  }
-
-  for(i=0; i<nElem; i++){
-    char c = zElem[i];
-    if( th_isspecial(c) ) hasSpecialChar = 1;
-    if( c=='\\' ) hasEscapeChar = 1;
-    if( c=='{' ) nBrace++;
-    if( c=='}' ) nBrace--;
-  }
-
-  if( nElem==0 || (!hasEscapeChar && hasSpecialChar && nBrace==0) ){
-    thBufferWrite(interp, &output, "{", 1);
-    thBufferWrite(interp, &output, zElem, nElem);
-    thBufferWrite(interp, &output, "}", 1);
-  }else{
-    for(i=0; i<nElem; i++){
-      char c = zElem[i];
-      if( th_isspecial(c) ) thBufferWrite(interp, &output, "\\", 1);
-      thBufferWrite(interp, &output, &c, 1);
-    }
-  }
-
-  *pzList = output.zBuf;
-  *pnList = output.nBuf;
-
-  return TH_OK;
-}
-
-/*
-** Append a new element to an existing th1 string. This function uses
-** the same interface as the Th_ListAppend() function.
-*/
-int Th_StringAppend(
-  Th_Interp *interp,           /* Interpreter context */
-  char **pzStr,               /* IN/OUT: Ptr to ptr to list */
-  int *pnStr,                  /* IN/OUT: Current length of *pzStr */
-  const char *zElem,          /* Data to append */
-  int nElem                    /* Length of nElem */
-){
-  char *zNew;
-  int nNew;
-
-  if( nElem<0 ){
-    nElem = th_strlen(zElem);
-  }
-
-  nNew = *pnStr + nElem;
-  zNew = Th_Malloc(interp, nNew);
-  memcpy(zNew, *pzStr, *pnStr);
-  memcpy(&zNew[*pnStr], zElem, nElem);
-
-  Th_Free(interp, *pzStr);
-  *pzStr = zNew;
-  *pnStr = nNew;
-
-  return TH_OK;
-}
-
-/* 
-** Delete an interpreter.
-*/
-void Th_DeleteInterp(Th_Interp *interp){
-  assert(interp->pFrame);
-  assert(0==interp->pFrame->pCaller);
-
-  /* Delete the contents of the global frame. */
-  thPopFrame(interp);
-
-  /* Delete any result currently stored in the interpreter. */
-  Th_SetResult(interp, 0, 0);
-
-  /* Delete all registered commands and the command hash-table itself. */
-  Th_HashIterate(interp, interp->paCmd, thFreeCommand, (void *)interp);
-  Th_HashDelete(interp, interp->paCmd);
-
-  /* Delete the interpreter structure itself. */
-  Th_Free(interp, (void *)interp);
-}
-
-/* 
-** Create a new interpreter.
-*/
-Th_Interp * Th_CreateInterp(Th_Vtab *pVtab){
-  Th_Interp *p;
-
-  /* Allocate and initialise the interpreter and the global frame */
-  p = pVtab->xMalloc(sizeof(Th_Interp) + sizeof(Th_Frame));
-  memset(p, 0, sizeof(Th_Interp));
-  p->pVtab = pVtab;
-  p->paCmd = Th_HashNew(p);
-  thPushFrame(p, (Th_Frame *)&p[1]);
-
-  return p;
-}
-
-/*
-** These two types are used only by the expression module, where
-** the expression module means the Th_Expr() and exprXXX() functions.
-*/
-typedef struct Operator Operator;
-struct Operator {
-  const char *zOp;
-  int eOp;
-  int iPrecedence;
-  int eArgType;
-};
-typedef struct Expr Expr;
-struct Expr {
-  Operator *pOp;
-  Expr *pParent;
-  Expr *pLeft;
-  Expr *pRight;
-
-  char *zValue;     /* Pointer to literal value */
-  int nValue;        /* Length of literal value buffer */
-};
-
-/* Unary operators */
-#define OP_UNARY_MINUS  2
-#define OP_UNARY_PLUS   3
-#define OP_BITWISE_NOT  4
-#define OP_LOGICAL_NOT  5
-
-/* Binary operators */
-#define OP_MULTIPLY     6
-#define OP_DIVIDE       7
-#define OP_MODULUS      8
-#define OP_ADD          9
-#define OP_SUBTRACT    10
-#define OP_LEFTSHIFT   11
-#define OP_RIGHTSHIFT  12
-#define OP_LT          13
-#define OP_GT          14
-#define OP_LE          15
-#define OP_GE          16
-#define OP_EQ          17
-#define OP_NE          18
-#define OP_SEQ         19
-#define OP_SNE         20
-#define OP_BITWISE_AND 21
-#define OP_BITWISE_XOR 22
-#define OP_BITWISE_OR  24
-#define OP_LOGICAL_AND 25
-#define OP_LOGICAL_OR  26
-
-/* Other symbols */
-#define OP_OPEN_BRACKET  27
-#define OP_CLOSE_BRACKET 28
-
-/* Argument types. Each operator in the expression syntax is defined
-** as requiring either integer, number (real or integer) or string
-** operands.
-*/
-#define ARG_INTEGER 1
-#define ARG_NUMBER  2
-#define ARG_STRING  3
-
-static Operator aOperator[] = {
-
-  {"(",  OP_OPEN_BRACKET,   -1, 0},
-  {")",  OP_CLOSE_BRACKET, -1, 0},
-
-  /* Note: all unary operators have (iPrecedence==1) */
-  {"-",  OP_UNARY_MINUS,    1, ARG_NUMBER},
-  {"+",  OP_UNARY_PLUS,     1, ARG_NUMBER},
-  {"~",  OP_BITWISE_NOT,    1, ARG_INTEGER},
-  {"!",  OP_LOGICAL_NOT,    1, ARG_INTEGER},
-
-  /* Binary operators. It is important to the parsing in Th_Expr() that
-   * the two-character symbols ("==") appear before the one-character 
-   * ones ("="). And that the priorities of all binary operators are
-   * integers between 2 and 12.
-   */
-  {"<<", OP_LEFTSHIFT,      4, ARG_INTEGER},
-  {">>", OP_RIGHTSHIFT,     4, ARG_INTEGER},
-  {"<=", OP_LE,             5, ARG_NUMBER},
-  {">=", OP_GE,             5, ARG_NUMBER},
-  {"==", OP_EQ,             6, ARG_NUMBER},
-  {"!=", OP_NE,             6, ARG_NUMBER},
-  {"eq", OP_SEQ,            7, ARG_STRING},
-  {"ne", OP_SNE,            7, ARG_STRING},
-  {"&&", OP_LOGICAL_AND,   11, ARG_INTEGER},
-  {"||", OP_LOGICAL_OR,    12, ARG_INTEGER},
-
-  {"*",  OP_MULTIPLY,       2, ARG_NUMBER},
-  {"/",  OP_DIVIDE,         2, ARG_NUMBER},
-  {"%",  OP_MODULUS,        2, ARG_INTEGER},
-  {"+",  OP_ADD,            3, ARG_NUMBER},
-  {"-",  OP_SUBTRACT,       3, ARG_NUMBER},
-  {"<",  OP_LT,             5, ARG_NUMBER},
-  {">",  OP_GT,             5, ARG_NUMBER},
-  {"&",  OP_BITWISE_AND,    8, ARG_INTEGER},
-  {"^",  OP_BITWISE_XOR,    9, ARG_INTEGER},
-  {"|",  OP_BITWISE_OR,    10, ARG_INTEGER},
-
-  {0,0,0}
-};
-
-/*
-** The first part of the string (zInput,nInput) contains a number.
-** Set *pnVarname to the number of bytes in the numeric string. 
-*/
-static int thNextNumber(
-  Th_Interp *interp, 
-  const char *zInput, 
-  int nInput, 
-  int *pnLiteral
-){
-  int i;
-  int seenDot = 0;
-  for(i=0; i<nInput; i++){
-    char c = zInput[i];
-    if( (seenDot || c!='.') && !th_isdigit(c) ) break;
-    if( c=='.' ) seenDot = 1;
-  }
-  *pnLiteral = i;
-  return TH_OK;
-}
-
-/*
-** Free an expression tree.
-*/
-static void exprFree(Th_Interp *interp, Expr *pExpr){
-  if( pExpr ){
-    exprFree(interp, pExpr->pLeft);
-    exprFree(interp, pExpr->pRight);
-    Th_Free(interp, pExpr->zValue);
-    Th_Free(interp, pExpr);
-  }
-}
-
-/*
-** Evaluate an expression tree.
-*/
-static int exprEval(Th_Interp *interp, Expr *pExpr){
-  int rc = TH_OK;
-
-  if( pExpr->pOp==0 ){
-    /* A literal */
-    rc = thSubstWord(interp, pExpr->zValue, pExpr->nValue);
-  }else{
-    int eArgType = 0;           /* Actual type of arguments */
-
-    /* Argument values */
-    int iLeft = 0;
-    int iRight = 0;
-    double fLeft;
-    double fRight;
-
-    /* Left and right arguments as strings */
-    char *zLeft = 0; int nLeft = 0;
-    char *zRight = 0; int nRight = 0;
-
-    /* Evaluate left and right arguments, if they exist. */
-    if( pExpr->pLeft ){
-      rc = exprEval(interp, pExpr->pLeft);
-      if( rc==TH_OK ){
-        zLeft = Th_TakeResult(interp, &nLeft);
-      }
-    }
-    if( rc==TH_OK && pExpr->pRight ){
-      rc = exprEval(interp, pExpr->pRight);
-      if( rc==TH_OK ){
-        zRight = Th_TakeResult(interp, &nRight);
-      }
-    }
-
-    /* Convert arguments to their required forms. */
-    if( rc==TH_OK ){
-      eArgType = pExpr->pOp->eArgType;
-      if( eArgType==ARG_NUMBER ){
-        if( (zLeft==0 || TH_OK==Th_ToInt(0, zLeft, nLeft, &iLeft))
-         && (zRight==0 || TH_OK==Th_ToInt(0, zRight, nRight, &iRight))
-        ){
-          eArgType = ARG_INTEGER;
-        }else if( 
-          (zLeft && TH_OK!=Th_ToDouble(interp, zLeft, nLeft, &fLeft)) ||
-          (zRight && TH_OK!=Th_ToDouble(interp, zRight, nRight, &fRight))
-        ){
-          /* A type error. */
-          rc = TH_ERROR;
-        }
-      }else if( eArgType==ARG_INTEGER ){
-        rc = Th_ToInt(interp, zLeft, nLeft, &iLeft);
-        if( rc==TH_OK && zRight ){
-          rc = Th_ToInt(interp, zRight, nRight, &iRight);
-        }
-      }  
-    }
-
-    if( rc==TH_OK && eArgType==ARG_INTEGER ){
-      int iRes = 0;
-      switch( pExpr->pOp->eOp ) {
-        case OP_MULTIPLY:     iRes = iLeft*iRight;  break;
-        case OP_DIVIDE:       iRes = iLeft/iRight;  break;
-        case OP_MODULUS:      iRes = iLeft%iRight;  break;
-        case OP_ADD:          iRes = iLeft+iRight;  break;
-        case OP_SUBTRACT:     iRes = iLeft-iRight;  break;
-        case OP_LEFTSHIFT:    iRes = iLeft<<iRight; break;
-        case OP_RIGHTSHIFT:   iRes = iLeft>>iRight; break;
-        case OP_LT:           iRes = iLeft<iRight;  break;
-        case OP_GT:           iRes = iLeft>iRight;  break;
-        case OP_LE:           iRes = iLeft<=iRight; break;
-        case OP_GE:           iRes = iLeft>=iRight; break;
-        case OP_EQ:           iRes = iLeft==iRight; break;
-        case OP_NE:           iRes = iLeft!=iRight; break;
-        case OP_BITWISE_AND:  iRes = iLeft&iRight;  break;
-        case OP_BITWISE_XOR:  iRes = iLeft^iRight;  break;
-        case OP_BITWISE_OR:   iRes = iLeft|iRight;  break;
-        case OP_LOGICAL_AND:  iRes = iLeft&&iRight; break;
-        case OP_LOGICAL_OR:   iRes = iLeft||iRight; break;
-        case OP_UNARY_MINUS:  iRes = -iLeft;        break;
-        case OP_UNARY_PLUS:   iRes = +iLeft;        break;
-        case OP_LOGICAL_NOT:  iRes = !iLeft;        break;
-        default: assert(!"Internal error");
-      }
-      Th_SetResultInt(interp, iRes);
-    }else if( rc==TH_OK && eArgType==ARG_NUMBER ){
-      switch( pExpr->pOp->eOp ) {
-        case OP_MULTIPLY: Th_SetResultDouble(interp, fLeft*fRight);  break;
-        case OP_DIVIDE:   Th_SetResultDouble(interp, fLeft/fRight);  break;
-        case OP_ADD:      Th_SetResultDouble(interp, fLeft+fRight);  break;
-        case OP_SUBTRACT: Th_SetResultDouble(interp, fLeft-fRight);  break;
-        case OP_LT:       Th_SetResultInt(interp, fLeft<fRight);  break;
-        case OP_GT:       Th_SetResultInt(interp, fLeft>fRight);  break;
-        case OP_LE:       Th_SetResultInt(interp, fLeft<=fRight); break;
-        case OP_GE:       Th_SetResultInt(interp, fLeft>=fRight); break;
-        case OP_EQ:       Th_SetResultInt(interp, fLeft==fRight); break;
-        case OP_NE:       Th_SetResultInt(interp, fLeft!=fRight); break;
-        default: assert(!"Internal error");
-      }
-    }else if( rc==TH_OK ){
-      int iEqual = 0;
-      assert( eArgType==ARG_STRING );
-      if( nRight==nLeft && 0==memcmp(zRight, zLeft, nRight) ){
-        iEqual = 1;
-      }
-      switch( pExpr->pOp->eOp ) {
-        case OP_SEQ:       Th_SetResultInt(interp, iEqual); break;
-        case OP_SNE:       Th_SetResultInt(interp, !iEqual); break;
-        default: assert(!"Internal error");
-      }
-    }
-
-    Th_Free(interp, zLeft);
-    Th_Free(interp, zRight);
-  }
-
-  return rc;
-}
-
-/*
-** Create an expression tree from an array of tokens. If successful,
-** the root of the tree is stored in apToken[0].
-*/
-int exprMakeTree(Th_Interp *interp, Expr **apToken, int nToken){
-  int iLeft;
-  int i;
-  int jj;
-
-  assert(nToken>0);
-#define ISTERM(x) (apToken[x] && (!apToken[x]->pOp || apToken[x]->pLeft))
-
-  for(jj=0; jj<nToken; jj++){
-    if( apToken[jj]->pOp && apToken[jj]->pOp->eOp==OP_OPEN_BRACKET ){
-      int nNest = 1;
-      int iLeft = jj; 
-
-      for(jj++; jj<nToken; jj++){
-        Operator *pOp = apToken[jj]->pOp;
-        if( pOp && pOp->eOp==OP_OPEN_BRACKET ) nNest++;
-        if( pOp && pOp->eOp==OP_CLOSE_BRACKET ) nNest--;
-        if( nNest==0 ) break;
-      }
-      if( jj==nToken ){
-        return TH_ERROR;
-      }
-      if( (jj-iLeft)>1 ){
-        if( exprMakeTree(interp, &apToken[iLeft+1], jj-iLeft-1) ){
-          return TH_ERROR;
-        }
-        exprFree(interp, apToken[jj]);
-        exprFree(interp, apToken[iLeft]);
-        apToken[jj] = 0;
-        apToken[iLeft] = 0;
-      }
-    }
-  }
-
-  iLeft = 0;
-  for(jj=nToken-1; jj>=0; jj--){
-    if( apToken[jj] ){
-      if( apToken[jj]->pOp && apToken[jj]->pOp->iPrecedence==1 && iLeft>0 ){
-        apToken[jj]->pLeft = apToken[iLeft];
-        apToken[jj]->pLeft->pParent = apToken[jj];
-        apToken[iLeft] = 0;
-      }
-      iLeft = jj;
-    }
-  }
-  for(i=2; i<=12; i++){
-    iLeft = -1;
-    for(jj=0; jj<nToken; jj++){
-      Expr *pToken = apToken[jj];
-      if( apToken[jj] ){
-        if( pToken->pOp && !pToken->pLeft && pToken->pOp->iPrecedence==i ){
-          int iRight = jj+1;
-
-          iRight = jj+1;
-          for(iRight=jj+1; !apToken[iRight] && iRight<nToken; iRight++);
-          if( iRight==nToken || iLeft<0 || !ISTERM(iRight) || !ISTERM(iLeft) ){
-            return TH_ERROR;
-          }
-          pToken->pLeft = apToken[iLeft];
-          apToken[iLeft] = 0;
-          pToken->pLeft->pParent = pToken;
-          pToken->pRight = apToken[iRight];
-          apToken[iRight] = 0;
-          pToken->pRight->pParent = pToken;
-        }
-        iLeft = jj;
-      }
-    }
-  }
-  for(jj=1; jj<nToken; jj++){
-    assert( !apToken[jj] || !apToken[0] );
-    if( apToken[jj] ){
-      apToken[0] = apToken[jj];
-      apToken[jj] = 0;
-    }
-  }
-
-  return TH_OK;
-}
-
-/*
-** Parse a string containing a TH expression to a list of tokens.
-*/
-static int exprParse(
-  Th_Interp *interp,        /* Interpreter to leave error message in */
-  const char *zExpr,       /* Pointer to input string */
-  int nExpr,                /* Number of bytes at zExpr */
-  Expr ***papToken,         /* OUT: Array of tokens. */
-  int *pnToken              /* OUT: Size of token array */
-){
-  int i;
-
-  int rc = TH_OK;
-  int nToken = 0;
-  Expr **apToken = 0;
-
-  for(i=0; rc==TH_OK && i<nExpr; ){
-    char c = zExpr[i];
-    if( th_isspace(c) ){                                /* White-space     */
-      i++;
-    }else{
-      Expr *pNew = (Expr *)Th_Malloc(interp, sizeof(Expr));
-      const char *z = &zExpr[i];
-
-      switch (c) {
-        case '0': case '1': case '2': case '3': case '4':
-        case '5': case '6': case '7': case '8': case '9':
-          thNextNumber(interp, z, nExpr-i, &pNew->nValue);
-          break;
-
-        case '$':
-          thNextVarname(interp, z, nExpr-i, &pNew->nValue);
-          break;
-
-        case '{': case '[': {
-          thNextCommand(interp, z, nExpr-i, &pNew->nValue);
-          break;
-        }
-
-        case '"': {
-          int iEnd = i;
-          while( ++iEnd<nExpr && zExpr[iEnd]!='"' ){
-            if( zExpr[iEnd]=='\\' ) iEnd++;
-          }
-          if( iEnd<nExpr ){
-            pNew->nValue = iEnd+1-i;
-          }
-          break;
-        }
-
-        default: {
-          int j;
-          for(j=0; aOperator[j].zOp; j++){
-            int nOp;
-            if( aOperator[j].iPrecedence==1 && nToken>0 ){
-              Expr *pPrev = apToken[nToken-1];
-              if( !pPrev->pOp || pPrev->pOp->eOp==OP_CLOSE_BRACKET ){
-                continue;
-              }
-            }
-            nOp = th_strlen((const char *)aOperator[j].zOp);
-            if( (nExpr-i)>=nOp && 0==memcmp(aOperator[j].zOp, &zExpr[i], nOp) ){
-              pNew->pOp = &aOperator[j];
-              i += nOp;
-              break;
-            }
-          }
-        }
-      }
-
-      if( pNew->pOp || pNew->nValue ){
-        if( pNew->nValue ){
-          /* A terminal. Copy the string value. */
-          assert( !pNew->pOp );
-          pNew->zValue = Th_Malloc(interp, pNew->nValue);
-          memcpy(pNew->zValue, z, pNew->nValue);
-          i += pNew->nValue;
-        }
-        if( (nToken%16)==0 ){
-          /* Grow the apToken array. */
-          Expr **apTokenOld = apToken; 
-          apToken = Th_Malloc(interp, sizeof(Expr *)*(nToken+16));
-          memcpy(apToken, apTokenOld, sizeof(Expr *)*nToken);
-        }
-
-        /* Put the new token at the end of the apToken array */
-        apToken[nToken] = pNew;
-        nToken++;
-      }else{
-        Th_Free(interp, pNew);
-        rc = TH_ERROR;
-      }
-    }
-  }
-
-  *papToken = apToken;
-  *pnToken = nToken;
-  return rc;
-}
-
-/*
-** Evaluate the string (zExpr, nExpr) as a Th expression. Store
-** the result in the interpreter interp and return TH_OK if
-** successful. If an error occurs, store an error message in
-** the interpreter result and return an error code.
-*/ 
-int Th_Expr(Th_Interp *interp, const char *zExpr, int nExpr){
-  int rc;                           /* Return Code */
-  int i;                            /* Loop counter */
-
-  int nToken = 0;
-  Expr **apToken = 0;
-
-  if( nExpr<0 ){
-    nExpr = th_strlen(zExpr);
-  }
-
-  /* Parse the expression to a list of tokens. */
-  rc = exprParse(interp, zExpr, nExpr, &apToken, &nToken);
-
-  /* If the parsing was successful, create an expression tree from
-  ** the parsed list of tokens. If successful, apToken[0] is set
-  ** to point to the root of the expression tree. 
-  */
-  if( rc==TH_OK ){
-    rc = exprMakeTree(interp, apToken, nToken);
-  }
-
-  if( rc!=TH_OK ){
-    Th_ErrorMessage(interp, "syntax error in expression: \"", zExpr, nExpr);
-  }
-
-  /* Evaluate the expression tree. */
-  if( rc==TH_OK ){
-    rc = exprEval(interp, apToken[0]);
-  }
-
-  /* Free memory allocated by exprParse(). */
-  for(i=0; i<nToken; i++){
-    exprFree(interp, apToken[i]);
-  }
-  Th_Free(interp, apToken);
-
-  return rc;
-}
-
-/*
-** Allocate and return a pointer to a new hash-table. The caller should
-** (eventually) delete the hash-table by passing it to Th_HashDelete().
-*/
-Th_Hash *Th_HashNew(Th_Interp *interp){
-  Th_Hash *p;
-  p = Th_Malloc(interp, sizeof(Th_Hash));
-  return p;
-}
-
-/*
-** Iterate through all values currently stored in the hash table. Invoke
-** the callback function xCallback for each entry. The second argument
-** passed to xCallback is a copy of the fourth argument passed to this
-** function.
-*/
-void Th_HashIterate(
-  Th_Interp *interp, 
-  Th_Hash *pHash,
-  void (*xCallback)(Th_HashEntry *pEntry, void *pContext),
-  void *pContext
-){
-  int i;
-  for(i=0; i<TH_HASHSIZE; i++){
-    Th_HashEntry *pEntry;
-    Th_HashEntry *pNext;
-    for(pEntry=pHash->a[i]; pEntry; pEntry=pNext){
-      pNext = pEntry->pNext;
-      xCallback(pEntry, pContext);
-    }
-  }
-}
-
-/*
-** Helper function for Th_HashDelete().
-*/
-static void xFreeHashEntry(Th_HashEntry *pEntry, void *pContext){
-  Th_Free((Th_Interp *)pContext, (void *)pEntry);
-}
-
-/*
-** Free a hash-table previously allocated by Th_HashNew().
-*/
-void Th_HashDelete(Th_Interp *interp, Th_Hash *pHash){
-  if( pHash ){
-    Th_HashIterate(interp, pHash, xFreeHashEntry, (void *)interp);
-    Th_Free(interp, pHash);
-  }
-}
-
-/*
-** This function is used to insert or delete hash table items, or to 
-** query a hash table for an existing item.
-**
-** If parameter op is less than zero, then the hash-table element 
-** identified by (zKey, nKey) is removed from the hash-table if it
-** exists. NULL is returned.
-**
-** Otherwise, if the hash-table contains an item with key (zKey, nKey),
-** a pointer to the associated Th_HashEntry is returned. If parameter
-** op is greater than zero, then a new entry is added if one cannot
-** be found. If op is zero, then NULL is returned if the item is
-** not already present in the hash-table.
-*/
-Th_HashEntry *Th_HashFind(
-  Th_Interp *interp, 
-  Th_Hash *pHash,
-  const char *zKey,
-  int nKey,
-  int op                      /* -ve = delete, 0 = find, +ve = insert */
-){
-  unsigned int iKey = 0;
-  int i;
-  Th_HashEntry *pRet;
-  Th_HashEntry **ppRet;
-
-  if( nKey<0 ){
-    nKey = th_strlen(zKey);
-  }
-
-  for(i=0; i<nKey; i++){
-    iKey = (iKey<<3) ^ iKey ^ zKey[i];
-  }
-  iKey = iKey % TH_HASHSIZE;
-
-  for(ppRet=&pHash->a[iKey]; (pRet=*ppRet); ppRet=&pRet->pNext){
-    assert( pRet && ppRet && *ppRet==pRet );
-    if( pRet->nKey==nKey && 0==memcmp(pRet->zKey, zKey, nKey) ) break;
-  }
-
-  if( op<0 && pRet ){
-    assert( ppRet && *ppRet==pRet );
-    *ppRet = pRet->pNext;
-    Th_Free(interp, pRet);
-    pRet = 0;
-  }
-
-  if( op>0 && !pRet ){
-    pRet = (Th_HashEntry *)Th_Malloc(interp, sizeof(Th_HashEntry) + nKey);
-    pRet->zKey = (char *)&pRet[1];
-    pRet->nKey = nKey;
-    memcpy(pRet->zKey, zKey, nKey);
-    pRet->pNext = pHash->a[iKey];
-    pHash->a[iKey] = pRet;
-  }
-
-  return pRet;
-}
-
-/*
-** This function is the same as the standard strlen() function, except
-** that it returns 0 (instead of being undefined) if the argument is
-** a null pointer.
-*/
-int th_strlen(const char *zStr){
-  int n = 0;
-  if( zStr ){
-    while( zStr[n] ) n++;
-  }
-  return n;
-}
-
-/* Whitespace characters:
-**
-**     ' '    0x20
-**     '\t'   0x09
-**     '\n'   0x0A
-**     '\v'   0x0B
-**     '\f'   0x0C
-**     '\r'   0x0D
-**
-** Whitespace characters have the 0x01 flag set. Decimal digits have the
-** 0x2 flag set. Single byte printable characters have the 0x4 flag set.
-** Alphabet characters have the 0x8 bit set. 
-**
-** The special list characters have the 0x10 flag set
-**
-**    { } [ ] \ ; ' "
-**
-**    " 0x22
-**
-*/
-static unsigned char aCharProp[256] = {
-  0,  0,  0,  0,  0,  0,  0,  0,     0,  1,  1,  1,  1,  1,  0,  0,   /* 0x0. */
-  0,  0,  1,  1,  0,  0,  0,  0,     0,  0,  0,  0,  0,  0,  0,  0,   /* 0x1. */
-  5,  4, 20,  4,  4,  4,  4,  4,     4,  4,  4,  4,  4,  4,  4,  4,   /* 0x2. */
-  6,  6,  6,  6,  6,  6,  6,  6,     6,  6,  4, 20,  4,  4,  4,  4,   /* 0x3. */
-  4, 12, 12, 12, 12, 12, 12, 12,    12, 12, 12, 12, 12, 12, 12, 12,   /* 0x4. */
- 12, 12, 12, 12, 12, 12, 12, 12,    12, 12, 12, 20, 20, 20,  4,  4,   /* 0x5. */
-  4, 12, 12, 12, 12, 12, 12, 12,    12, 12, 12, 12, 12, 12, 12, 12,   /* 0x6. */
- 12, 12, 12, 12, 12, 12, 12, 12,    12, 12, 12, 20,  4, 20,  4,  4,   /* 0x7. */
-
-  0,  0,  0,  0,  0,  0,  0,  0,     0,  0,  0,  0,  0,  0,  0,  0,   /* 0x8. */
-  0,  0,  0,  0,  0,  0,  0,  0,     0,  0,  0,  0,  0,  0,  0,  0,   /* 0x9. */
-  0,  0,  0,  0,  0,  0,  0,  0,     0,  0,  0,  0,  0,  0,  0,  0,   /* 0xA. */
-  0,  0,  0,  0,  0,  0,  0,  0,     0,  0,  0,  0,  0,  0,  0,  0,   /* 0xB. */
-  0,  0,  0,  0,  0,  0,  0,  0,     0,  0,  0,  0,  0,  0,  0,  0,   /* 0xC. */
-  0,  0,  0,  0,  0,  0,  0,  0,     0,  0,  0,  0,  0,  0,  0,  0,   /* 0xD. */
-  0,  0,  0,  0,  0,  0,  0,  0,     0,  0,  0,  0,  0,  0,  0,  0,   /* 0xE. */
-  0,  0,  0,  0,  0,  0,  0,  0,     0,  0,  0,  0,  0,  0,  0,  0    /* 0xF. */
-};
-
-/*
-** Clone of the standard isspace() and isdigit function/macros.
-*/
-int th_isspace(char c){
-  return (aCharProp[(unsigned char)c] & 0x01);
-}
-int th_isdigit(char c){
-  return (aCharProp[(unsigned char)c] & 0x02);
-}
-int th_isspecial(char c){
-  return (aCharProp[(unsigned char)c] & 0x11);
-}
-int th_isalnum(char c){
-  return (aCharProp[(unsigned char)c] & 0x0A);
-}
-
-#ifndef LONGDOUBLE_TYPE
-# define LONGDOUBLE_TYPE long double
-#endif
-typedef char u8;
-
-
-/*
-** Return TRUE if z is a pure numeric string.  Return FALSE if the
-** string contains any character which is not part of a number. If
-** the string is numeric and contains the '.' character, set *realnum
-** to TRUE (otherwise FALSE).
-**
-** An empty string is considered non-numeric.
-*/
-static int sqlite3IsNumber(const char *z, int *realnum){
-  int incr = 1;
-  if( *z=='-' || *z=='+' ) z += incr;
-  if( !th_isdigit(*(u8*)z) ){
-    return 0;
-  }
-  z += incr;
-  if( realnum ) *realnum = 0;
-  while( th_isdigit(*(u8*)z) ){ z += incr; }
-  if( *z=='.' ){
-    z += incr;
-    if( !th_isdigit(*(u8*)z) ) return 0;
-    while( th_isdigit(*(u8*)z) ){ z += incr; }
-    if( realnum ) *realnum = 1;
-  }
-  if( *z=='e' || *z=='E' ){
-    z += incr;
-    if( *z=='+' || *z=='-' ) z += incr;
-    if( !th_isdigit(*(u8*)z) ) return 0;
-    while( th_isdigit(*(u8*)z) ){ z += incr; }
-    if( realnum ) *realnum = 1;
-  }
-  return *z==0;
-}
-
-/*
-** The string z[] is an ascii representation of a real number.
-** Convert this string to a double.
-**
-** This routine assumes that z[] really is a valid number.  If it
-** is not, the result is undefined.
-**
-** This routine is used instead of the library atof() function because
-** the library atof() might want to use "," as the decimal point instead
-** of "." depending on how locale is set.  But that would cause problems
-** for SQL.  So this routine always uses "." regardless of locale.
-*/
-static int sqlite3AtoF(const char *z, double *pResult){
-  int sign = 1;
-  const char *zBegin = z;
-  LONGDOUBLE_TYPE v1 = 0.0;
-  while( th_isspace(*(u8*)z) ) z++;
-  if( *z=='-' ){
-    sign = -1;
-    z++;
-  }else if( *z=='+' ){
-    z++;
-  }
-  while( th_isdigit(*(u8*)z) ){
-    v1 = v1*10.0 + (*z - '0');
-    z++;
-  }
-  if( *z=='.' ){
-    LONGDOUBLE_TYPE divisor = 1.0;
-    z++;
-    while( th_isdigit(*(u8*)z) ){
-      v1 = v1*10.0 + (*z - '0');
-      divisor *= 10.0;
-      z++;
-    }
-    v1 /= divisor;
-  }
-  if( *z=='e' || *z=='E' ){
-    int esign = 1;
-    int eval = 0;
-    LONGDOUBLE_TYPE scale = 1.0;
-    z++;
-    if( *z=='-' ){
-      esign = -1;
-      z++;
-    }else if( *z=='+' ){
-      z++;
-    }
-    while( th_isdigit(*(u8*)z) ){
-      eval = eval*10 + *z - '0';
-      z++;
-    }
-    while( eval>=64 ){ scale *= 1.0e+64; eval -= 64; }
-    while( eval>=16 ){ scale *= 1.0e+16; eval -= 16; }
-    while( eval>=4 ){ scale *= 1.0e+4; eval -= 4; }
-    while( eval>=1 ){ scale *= 1.0e+1; eval -= 1; }
-    if( esign<0 ){
-      v1 /= scale;
-    }else{
-      v1 *= scale;
-    }
-  }
-  *pResult = sign<0 ? -v1 : v1;
-  return z - zBegin;
-}
-
-/*
-** Try to convert the string passed as arguments (z, n) to an integer.
-** If successful, store the result in *piOut and return TH_OK. 
-**
-** If the string cannot be converted to an integer, return TH_ERROR. 
-** If the interp argument is not NULL, leave an error message in the 
-** interpreter result too.
-*/
-int Th_ToInt(Th_Interp *interp, const char *z, int n, int *piOut){
-  int i = 0;
-  int iOut = 0;
-
-  if( n<0 ){
-    n = th_strlen(z);
-  }
-
-  if( n>0 && (z[0]=='-' || z[0]=='+') ){
-    i = 1;
-  }
-  for(; i<n; i++){
-    if( !th_isdigit(z[i]) ){
-      Th_ErrorMessage(interp, "expected integer, got: \"", z, n);
-      return TH_ERROR;
-    }
-    iOut = iOut * 10 + (z[i] - 48);
-  }
-
-  if( n>0 && z[0]=='-' ){
-    iOut *= -1;
-  }
-
-  *piOut = iOut;
-  return TH_OK;
-}
-
-/*
-** Try to convert the string passed as arguments (z, n) to a double.
-** If successful, store the result in *pfOut and return TH_OK. 
-**
-** If the string cannot be converted to a double, return TH_ERROR. 
-** If the interp argument is not NULL, leave an error message in the 
-** interpreter result too.
-*/
-int Th_ToDouble(
-  Th_Interp *interp, 
-  const char *z, 
-  int n, 
-  double *pfOut
-){
-  if( !sqlite3IsNumber((const char *)z, 0) ){
-    Th_ErrorMessage(interp, "expected number, got: \"", z, n);
-    return TH_ERROR;
-  }
-
-  sqlite3AtoF((const char *)z, pfOut);
-  return TH_OK;
-}
-
-/*
-** Set the result of the interpreter to the th1 representation of
-** the integer iVal and return TH_OK.
-*/
-int Th_SetResultInt(Th_Interp *interp, int iVal){
-  int isNegative = 0;
-  char zBuf[32];
-  char *z = &zBuf[32];
-
-  if( iVal<0 ){
-    isNegative = 1;
-    iVal = iVal * -1;
-  }
-  *(--z) = '\0';
-  *(--z) = (char)(48+(iVal%10));
-  while( (iVal = (iVal/10))>0 ){
-    *(--z) = (char)(48+(iVal%10));
-    assert(z>zBuf);
-  }
-  if( isNegative ){
-    *(--z) = '-';
-  }
-
-  return Th_SetResult(interp, z, -1);
-}
-
-/*
-** Set the result of the interpreter to the th1 representation of
-** the double fVal and return TH_OK.
-*/
-int Th_SetResultDouble(Th_Interp *interp, double fVal){
-  int i;                /* Iterator variable */
-  double v = fVal;      /* Input value */
-  char zBuf[128];      /* Output buffer */
-  char *z = zBuf;      /* Output cursor */
-  int iDot = 0;         /* Digit after which to place decimal point */
-  int iExp = 0;         /* Exponent (NN in eNN) */
-  const char *zExp;    /* String representation of iExp */
-
-  /* Precision: */
-  #define INSIGNIFICANT 0.000000000001
-  #define ROUNDER       0.0000000000005
-  double insignificant = INSIGNIFICANT;
-
-  /* If the real value is negative, write a '-' character to the
-   * output and transform v to the corresponding positive number.
-   */ 
-  if( v<0.0 ){
-    *z++ = '-';
-    v *= -1.0;
-  }
-
-  /* Normalize v to a value between 1.0 and 10.0. Integer 
-   * variable iExp is set to the exponent. i.e the original
-   * value is (v * 10^iExp) (or the negative thereof).
-   */ 
-  if( v>0.0 ){
-    while( (v+ROUNDER)>=10.0 ) { iExp++; v *= 0.1; }
-    while( (v+ROUNDER)<1.0 )   { iExp--; v *= 10.0; }
-  }
-  v += ROUNDER;
-
-  /* For a small (<12) positive exponent, move the decimal point
-   * instead of using the "eXX" notation.
-   */
-  if( iExp>0 && iExp<12 ){
-    iDot = iExp;
-    iExp = 0;
-  }
-
-  /* For a small (>-4) negative exponent, write leading zeroes
-   * instead of using the "eXX" notation.
-   */
-  if( iExp<0 && iExp>-4 ){
-    *z++ = '0';
-    *z++ = '.';
-    for(i=0; i>(iExp+1); i--){
-      *z++ = '0';
-    }
-    iDot = -1;
-    iExp = 0;
-  }
-
-  /* Output the digits in real value v. The value of iDot determines
-   * where (if at all) the decimal point is placed.
-   */
-  for(i=0; i<=(iDot+1) || v>=insignificant; i++){
-    *z++ = (char)(48 + (int)v);
-    v = (v - ((double)(int)v)) * 10.0;
-    insignificant *= 10.0;
-    if( iDot==i ){
-      *z++ = '.';
-    }
-  }
-
-  /* If the exponent is not zero, add the "eXX" notation to the
-   * end of the string.
-   */
-  if( iExp!=0 ){
-    *z++ = 'e';
-    Th_SetResultInt(interp, iExp);
-    zExp = Th_GetResult(interp, 0);
-    for(i=0; zExp[i]; i++){
-      *z++ = zExp[i];
-    }
-  }
-
-  *z = '\0';
-  return Th_SetResult(interp, zBuf, -1);
-}

DELETED src/th.h
Index: src/th.h
==================================================================
--- src/th.h
+++ src/th.h
@@ -1,183 +0,0 @@
-
-/* This header file defines the external interface to the custom Scripting
-** Language (TH) interpreter.  TH is very similar to TCL but is not an
-** exact clone.
-*/
-
-/*
-** Before creating an interpreter, the application must allocate and
-** populate an instance of the following structure. It must remain valid
-** for the lifetime of the interpreter.
-*/
-struct Th_Vtab {
-  void *(*xMalloc)(unsigned int);
-  void (*xFree)(void *);
-};
-typedef struct Th_Vtab Th_Vtab;
-
-/*
-** Opaque handle for interpeter.
-*/
-typedef struct Th_Interp Th_Interp;
-
-/* 
-** Create and delete interpreters. 
-*/
-Th_Interp * Th_CreateInterp(Th_Vtab *pVtab);
-void Th_DeleteInterp(Th_Interp *);
-
-/* 
-** Evaluate an TH program in the stack frame identified by parameter
-** iFrame, according to the following rules:
-**
-**   * If iFrame is 0, this means the current frame.
-**
-**   * If iFrame is negative, then the nth frame up the stack, where n is 
-**     the absolute value of iFrame. A value of -1 means the calling
-**     procedure.
-**
-**   * If iFrame is +ve, then the nth frame from the bottom of the stack.
-**     An iFrame value of 1 means the toplevel (global) frame.
-*/
-int Th_Eval(Th_Interp *interp, int iFrame, const char *zProg, int nProg);
-
-/*
-** Evaluate a TH expression. The result is stored in the 
-** interpreter result.
-*/
-int Th_Expr(Th_Interp *interp, const char *, int);
-
-/* 
-** Access TH variables in the current stack frame. If the variable name
-** begins with "::", the lookup is in the top level (global) frame. 
-*/
-int Th_GetVar(Th_Interp *, const char *, int);
-int Th_SetVar(Th_Interp *, const char *, int, const char *, int);
-int Th_LinkVar(Th_Interp *, const char *, int, int, const char *, int);
-int Th_UnsetVar(Th_Interp *, const char *, int);
-
-typedef int (*Th_CommandProc)(Th_Interp *, void *, int, const char **, int *);
-
-/* 
-** Register new commands. 
-*/
-int Th_CreateCommand(
-  Th_Interp *interp, 
-  const char *zName, 
-  /* int (*xProc)(Th_Interp *, void *, int, const char **, int *), */
-  Th_CommandProc xProc,
-  void *pContext,
-  void (*xDel)(Th_Interp *, void *)
-);
-
-/* 
-** Delete or rename commands.
-*/
-int Th_RenameCommand(Th_Interp *, const char *, int, const char *, int);
-
-/* 
-** Push a new stack frame (local variable context) onto the interpreter 
-** stack, call the function supplied as parameter xCall with the two 
-** context arguments, 
-**
-**   xCall(interp, pContext1, pContext2)
-**
-** , then pop the frame off of the interpreter stack. The value returned
-** by the xCall() function is returned as the result of this function.
-**
-** This is intended for use by the implementation of commands such as
-** those created by [proc].
-*/
-int Th_InFrame(Th_Interp *interp,
-  int (*xCall)(Th_Interp *, void *pContext1, void *pContext2),
-  void *pContext1,
-  void *pContext2
-);
-
-/* 
-** Valid return codes for xProc callbacks.
-*/
-#define TH_OK       0
-#define TH_ERROR    1
-#define TH_BREAK    2
-#define TH_RETURN   3
-#define TH_CONTINUE 4
-
-/* 
-** Set and get the interpreter result. 
-*/
-int Th_SetResult(Th_Interp *, const char *, int);
-const char *Th_GetResult(Th_Interp *, int *);
-char *Th_TakeResult(Th_Interp *, int *);
-
-/*
-** Set an error message as the interpreter result. This also
-** sets the global stack-trace variable $::th_stack_trace.
-*/
-int Th_ErrorMessage(Th_Interp *, const char *, const char *, int);
-
-/* 
-** Access the memory management functions associated with the specified
-** interpreter.
-*/
-void *Th_Malloc(Th_Interp *, int);
-void Th_Free(Th_Interp *, void *);
-
-/* 
-** Functions for handling TH lists.
-*/
-int Th_ListAppend(Th_Interp *, char **, int *, const char *, int);
-int Th_SplitList(Th_Interp *, const char *, int, char ***, int **, int *);
-
-int Th_StringAppend(Th_Interp *, char **, int *, const char *, int);
-
-/* 
-** Functions for handling numbers and pointers.
-*/
-int Th_ToInt(Th_Interp *, const char *, int, int *);
-int Th_ToDouble(Th_Interp *, const char *, int, double *);
-int Th_SetResultInt(Th_Interp *, int);
-int Th_SetResultDouble(Th_Interp *, double);
-
-/*
-** Drop in replacements for the corresponding standard library functions.
-*/
-int th_strlen(const char *);
-int th_isdigit(char);
-int th_isspace(char);
-int th_isalnum(char);
-int th_isspecial(char);
-char *th_strdup(Th_Interp *interp, const char *z, int n);
-
-/*
-** Interfaces to register the language extensions.
-*/
-int th_register_language(Th_Interp *interp);            /* th_lang.c */
-int th_register_sqlite(Th_Interp *interp);              /* th_sqlite.c */
-int th_register_vfs(Th_Interp *interp);                 /* th_vfs.c */
-int th_register_testvfs(Th_Interp *interp);             /* th_testvfs.c */
-int th_register_tcl(Th_Interp *interp, void *pContext); /* th_tcl.c */
-
-/*
-** General purpose hash table from th_lang.c.
-*/
-typedef struct Th_Hash      Th_Hash;
-typedef struct Th_HashEntry Th_HashEntry;
-struct Th_HashEntry {
-  void *pData;
-  char *zKey;
-  int nKey;
-  Th_HashEntry *pNext;     /* Internal use only */
-};
-Th_Hash *Th_HashNew(Th_Interp *);
-void Th_HashDelete(Th_Interp *, Th_Hash *);
-void Th_HashIterate(Th_Interp*,Th_Hash*,void (*x)(Th_HashEntry*, void*),void*);
-Th_HashEntry *Th_HashFind(Th_Interp*, Th_Hash*, const char*, int, int);
-
-/*
-** Useful functions from th_lang.c.
-*/
-int Th_WrongNumArgs(Th_Interp *interp, const char *zMsg);
-
-typedef struct Th_SubCommand {char *zName; Th_CommandProc xProc;} Th_SubCommand;
-int Th_CallSubCommand(Th_Interp*,void*,int,const char**,int*,Th_SubCommand*);

DELETED src/th_lang.c
Index: src/th_lang.c
==================================================================
--- src/th_lang.c
+++ src/th_lang.c
@@ -1,1072 +0,0 @@
-
-/*
-** This file contains the implementation of all of the TH language 
-** built-in commands. 
-**
-** All built-in commands are implemented using the public interface 
-** declared in th.h, so this file serves as both a part of the language 
-** implementation and an example of how to extend the language with
-** new commands.
-*/
-
-#include "config.h"
-#include "th.h"
-#include <string.h>
-#include <assert.h>
-
-int Th_WrongNumArgs(Th_Interp *interp, const char *zMsg){
-  Th_ErrorMessage(interp, "wrong # args: should be \"", zMsg, -1);
-  return TH_ERROR;
-}
-
-/*
-** Syntax: 
-**
-**   catch script ?varname?
-*/
-static int catch_command(
-  Th_Interp *interp, 
-  void *ctx, 
-  int argc, 
-  const char **argv, 
-  int *argl
-){
-  int rc;
-
-  if( argc!=2 && argc!=3 ){
-    return Th_WrongNumArgs(interp, "catch script ?varname?");
-  }
-
-  rc = Th_Eval(interp, 0, argv[1], -1);
-  if( argc==3 ){
-    int nResult;
-    const char *zResult = Th_GetResult(interp, &nResult);
-    Th_SetVar(interp, argv[2], argl[2], zResult, nResult);
-  }
-
-  Th_SetResultInt(interp, rc);
-  return TH_OK;
-}
-
-/*
-** TH Syntax: 
-**
-**   if expr1 body1 ?elseif expr2 body2? ? ?else? bodyN?
-*/
-static int if_command(
-  Th_Interp *interp, 
-  void *ctx, 
-  int argc, 
-  const char **argv, 
-  int *argl
-){
-  int rc = TH_OK;
-
-  int iCond;           /* Result of evaluating expression */
-  int i;
-
-  const char *zResult;
-  int nResult;
-
-  if( argc<3 ){
-    goto wrong_args;
-  }
-
-  for(i=0; i<argc && rc==TH_OK; i+=3){
-    if( i>argc-3 ){
-      i = argc-3;
-      iCond = 1;
-    }else{
-      if( TH_OK!=Th_Expr(interp, argv[i+1], argl[i+1]) ){
-        return TH_ERROR;
-      }
-      zResult = Th_GetResult(interp, &nResult);
-      rc = Th_ToInt(interp, zResult, nResult, &iCond);
-    }
-    if( iCond && rc==TH_OK ){
-      rc = Th_Eval(interp, 0, argv[i+2], -1);
-      break;
-    }
-  }
-
-  return rc;
-
-wrong_args:
-  return Th_WrongNumArgs(interp, "if ...");
-}
-
-/*
-** TH Syntax: 
-**
-**   expr expr
-*/
-static int expr_command(
-  Th_Interp *interp, 
-  void *ctx, 
-  int argc, 
-  const char **argv, 
-  int *argl
-){
-  if( argc!=2 ){
-    return Th_WrongNumArgs(interp, "expr expression");
-  }
-
-  return Th_Expr(interp, argv[1], argl[1]);
-}
-
-/*
-** Evaluate the th1 script (zBody, nBody) in the local stack frame. 
-** Return the result of the evaluation, except if the result
-** is TH_CONTINUE, return TH_OK instead.
-*/
-static int eval_loopbody(Th_Interp *interp, const char *zBody, int nBody){
-  int rc = Th_Eval(interp, 0, zBody, nBody);
-  if( rc==TH_CONTINUE ){
-    rc = TH_OK;
-  }
-  return rc;
-}
-
-/*
-** TH Syntax: 
-**
-**   for init condition incr script
-*/
-static int for_command(
-  Th_Interp *interp, 
-  void *ctx, 
-  int argc, 
-  const char **argv, 
-  int *argl
-){
-  int rc;
-  int iCond;
-
-  if( argc!=5 ){
-    return Th_WrongNumArgs(interp, "for init condition incr script");
-  }
-
-  /* Evaluate the 'init' script */
-  rc = Th_Eval(interp, 0, argv[1], -1);
-
-  while( rc==TH_OK 
-     && TH_OK==(rc = Th_Expr(interp, argv[2], -1))
-     && TH_OK==(rc = Th_ToInt(interp, Th_GetResult(interp, 0), -1, &iCond))
-     && iCond
-     && TH_OK==(rc = eval_loopbody(interp, argv[4], argl[4]))
-  ){
-    rc = Th_Eval(interp, 0, argv[3], -1);
-  }
-
-  if( rc==TH_BREAK ) rc = TH_OK;
-  return rc;
-}
-
-/*
-** TH Syntax: 
-**
-**   list ?arg1 ?arg2? ...?
-*/
-static int list_command(
-  Th_Interp *interp, 
-  void *ctx, 
-  int argc, 
-  const char **argv, 
-  int *argl
-){
-  char *zList = 0;
-  int nList = 0;
-  int i;
-
-  for(i=1; i<argc; i++){
-    Th_ListAppend(interp, &zList, &nList, argv[i], argl[i]);
-  }
- 
-  Th_SetResult(interp, zList, nList);
-  Th_Free(interp, zList);
-
-  return TH_OK;
-}
-
-/*
-** TH Syntax: 
-**
-**   lindex list index
-*/
-static int lindex_command(
-  Th_Interp *interp, 
-  void *ctx, 
-  int argc, 
-  const char **argv, 
-  int *argl
-){
-  int iElem;
-  int rc;
-
-  char **azElem;
-  int *anElem;
-  int nCount;
-
-  if( argc!=3 ){
-    return Th_WrongNumArgs(interp, "lindex list index");
-  }
-
-  if( TH_OK!=Th_ToInt(interp, argv[2], argl[2], &iElem) ){
-    return TH_ERROR;
-  }
-
-  rc = Th_SplitList(interp, argv[1], argl[1], &azElem, &anElem, &nCount);
-  if( rc==TH_OK ){
-    if( iElem<nCount && iElem>=0 ){
-      Th_SetResult(interp, azElem[iElem], anElem[iElem]);
-    }else{
-      Th_SetResult(interp, 0, 0);
-    }
-    Th_Free(interp, azElem);
-  }
-
-  return rc;
-}
-
-/*
-** TH Syntax: 
-**
-**   llength list
-*/
-static int llength_command(
-  Th_Interp *interp, 
-  void *ctx, 
-  int argc, 
-  const char **argv, 
-  int *argl
-){
-  int nElem;
-  int rc;
-
-  if( argc!=2 ){
-    return Th_WrongNumArgs(interp, "llength list");
-  }
-
-  rc = Th_SplitList(interp, argv[1], argl[1], 0, 0, &nElem);
-  if( rc==TH_OK ){
-    Th_SetResultInt(interp, nElem);
-  }
-
-  return rc;
-}
-
-/*
-** TH Syntax: 
-**
-**   set varname ?value?
-*/
-static int set_command(
-  Th_Interp *interp, 
-  void *ctx, 
-  int argc, 
-  const char **argv, 
-  int *argl
-){
-  if( argc!=2 && argc!=3 ){
-    return Th_WrongNumArgs(interp, "set varname ?value?");
-  }
-
-  if( argc==3 ){
-    Th_SetVar(interp, argv[1], argl[1], argv[2], argl[2]);
-  }
-  return Th_GetVar(interp, argv[1], argl[1]);
-}
-
-/*
-** When a new command is created using the built-in [proc] command, an
-** instance of the following structure is allocated and populated. A 
-** pointer to the structure is passed as the context (second) argument 
-** to function proc_call1() when the new command is executed.
-*/
-typedef struct ProcDefn ProcDefn;
-struct ProcDefn {
-  int nParam;                /* Number of formal (non "args") parameters */
-  char **azParam;           /* Parameter names */
-  int *anParam;              /* Lengths of parameter names */
-  char **azDefault;         /* Default values */
-  int *anDefault;            /* Lengths of default values */
-  int hasArgs;               /* True if there is an "args" parameter */
-  char *zProgram;           /* Body of proc */
-  int nProgram;              /* Number of bytes at zProgram */
-  char *zUsage;             /* Usage message */
-  int nUsage;                /* Number of bytes at zUsage */
-};
-
-/* This structure is used to temporarily store arguments passed to an 
-** invocation of a command created using [proc]. A pointer to an 
-** instance is passed as the second argument to the proc_call2() function.
-*/
-typedef struct ProcArgs ProcArgs;
-struct ProcArgs {
-  int argc;
-  const char **argv;
-  int *argl;
-};
-
-/*
-** Each time a command created using [proc] is invoked, a new
-** th1 stack frame is allocated (for the proc's local variables) and
-** this function invoked.
-**
-** Argument pContext1 points to the associated ProcDefn structure.
-** Argument pContext2  points to a ProcArgs structure that contains
-** the arguments passed to this specific invocation of the proc.
-*/
-static int proc_call2(Th_Interp *interp, void *pContext1, void *pContext2){
-  int i;
-  ProcDefn *p = (ProcDefn *)pContext1;
-  ProcArgs *pArgs = (ProcArgs *)pContext2;
-
-  /* Check if there are the right number of arguments. If there are
-  ** not, generate a usage message for the command.
-  */
-  if( (pArgs->argc>(p->nParam+1) && !p->hasArgs) 
-   || (pArgs->argc<=(p->nParam) && !p->azDefault[pArgs->argc-1])
-  ){
-    char *zUsage = 0;
-    int nUsage = 0;
-    Th_StringAppend(interp, &zUsage, &nUsage, pArgs->argv[0], pArgs->argl[0]);
-    Th_StringAppend(interp, &zUsage, &nUsage, p->zUsage, p->nUsage);
-    Th_StringAppend(interp, &zUsage, &nUsage, (const char *)"", 1);
-    Th_WrongNumArgs(interp, zUsage);
-    Th_Free(interp, zUsage);
-    return TH_ERROR;
-  }
-
-  /* Populate the formal proc parameters. */
-  for(i=0; i<p->nParam; i++){
-    const char *zVal;
-    int nVal;
-    if( pArgs->argc>(i+1) ){
-      zVal = pArgs->argv[i+1];
-      nVal = pArgs->argl[i+1];
-    }else{
-      zVal = p->azDefault[i];
-      nVal = p->anDefault[i];
-    }
-    Th_SetVar(interp, p->azParam[i], p->anParam[i], zVal, nVal);
-  }
-
-  /* Populate the "args" parameter, if it exists */
-  if( p->hasArgs ){
-    char *zArgs = 0;
-    int nArgs = 0;
-    for(i=p->nParam+1; i<pArgs->argc; i++){
-      Th_ListAppend(interp, &zArgs, &nArgs, pArgs->argv[i], pArgs->argl[i]);
-    }
-    Th_SetVar(interp, (const char *)"args", -1, zArgs, nArgs);
-  }
-
-  Th_SetResult(interp, 0, 0);
-  return Th_Eval(interp, 0, p->zProgram, p->nProgram);
-}
-
-/*
-** This function is the command callback registered for all commands
-** created using the [proc] command. The second argument, pContext,
-** is a pointer to the associated ProcDefn structure.
-*/
-static int proc_call1(
-  Th_Interp *interp,
-  void *pContext, 
-  int argc, 
-  const char **argv,
-  int *argl
-){
-  int rc;
-
-  ProcDefn *p = (ProcDefn *)pContext;
-  ProcArgs procargs;
-
-  /* Call function proc_call2(), which will call Th_Eval() to evaluate
-  ** the body of the [proc], in a new Th stack frame. This is so that
-  ** the proc body has its own local variable context.
-  */
-  procargs.argc = argc;
-  procargs.argv = argv;
-  procargs.argl = argl;
-  rc = Th_InFrame(interp, proc_call2, (void *)p, (void *)&procargs);
-
-  if( rc==TH_RETURN ){
-    rc = TH_OK;
-  }
-  return rc;
-}
-
-/*
-** This function is registered as the delete callback for all commands 
-** created using the built-in [proc] command. It is called automatically 
-** when a command created using [proc] is deleted. 
-**
-** It frees the ProcDefn structure allocated when the command was created.
-*/ 
-static void proc_del(Th_Interp *interp, void *pContext){
-  ProcDefn *p = (ProcDefn *)pContext;
-  Th_Free(interp, (void *)p->zUsage);
-  Th_Free(interp, (void *)p);
-}
-
-/*
-** TH Syntax: 
-**
-**   proc name arglist code
-*/
-static int proc_command(
-  Th_Interp *interp, 
-  void *ctx, 
-  int argc,
-  const char **argv, 
-  int *argl
-){
-  int rc;
-  char *zName;
-
-  ProcDefn *p;
-  int nByte;
-  int i;
-  char *zSpace;
-
-  char **azParam;
-  int *anParam;
-  int nParam;
-
-  char *zUsage = 0;               /* Build up a usage message here */
-  int nUsage = 0;                  /* Number of bytes at zUsage */
-
-  if( argc!=4 ){
-    return Th_WrongNumArgs(interp, "proc name arglist code");
-  }
-  if( Th_SplitList(interp, argv[2], argl[2], &azParam, &anParam, &nParam) ){
-    return TH_ERROR;
-  }
-
-  /* Allocate the new ProcDefn structure. */
-  nByte = sizeof(ProcDefn) +                        /* ProcDefn structure */
-      (sizeof(char *) + sizeof(int)) * nParam +    /* azParam, anParam */
-      (sizeof(char *) + sizeof(int)) * nParam +    /* azDefault, anDefault */
-      argl[3] +                                     /* zProgram */
-      argl[2];     /* Space for copies of parameter names and default values */
-  p = (ProcDefn *)Th_Malloc(interp, nByte);
-
-  /* If the last parameter in the parameter list is "args", then set the
-  ** ProcDefn.hasArgs flag. The "args" parameter does not require an
-  ** entry in the ProcDefn.azParam[] or ProcDefn.azDefault[] arrays.
-  */
-  if( anParam[nParam-1]==4 && 0==memcmp(azParam[nParam-1], "args", 4) ){
-    p->hasArgs = 1;
-    nParam--;
-  }
-
-  p->nParam    = nParam;
-  p->azParam   = (char **)&p[1];
-  p->anParam   = (int *)&p->azParam[nParam];
-  p->azDefault = (char **)&p->anParam[nParam];
-  p->anDefault = (int *)&p->azDefault[nParam];
-  p->zProgram = (char *)&p->anDefault[nParam];
-  memcpy(p->zProgram, argv[3], argl[3]);
-  p->nProgram = argl[3];
-  zSpace = &p->zProgram[p->nProgram];
-  
-  for(i=0; i<nParam; i++){
-    char **az;
-    int *an;
-    int n;
-    if( Th_SplitList(interp, azParam[i], anParam[i], &az, &an, &n) ){
-      goto error_out;
-    }
-    if( n<1 || n>2 ){
-      const char expected[] = "expected parameter, got \"";
-      Th_ErrorMessage(interp, expected, azParam[i], anParam[i]);
-      Th_Free(interp, az);
-      goto error_out;
-    }
-    p->anParam[i] = an[0];
-    p->azParam[i] = zSpace;
-    memcpy(zSpace, az[0], an[0]);
-    zSpace += an[0];
-    if( n==2 ){
-      p->anDefault[i] = an[1];
-      p->azDefault[i] = zSpace;
-      memcpy(zSpace, az[1], an[1]);
-      zSpace += an[1];
-    }
-
-    Th_StringAppend(interp, &zUsage, &nUsage, (const char *)" ", 1);
-    if( n==2 ){
-      Th_StringAppend(interp, &zUsage, &nUsage, (const char *)"?", 1);
-      Th_StringAppend(interp, &zUsage, &nUsage, az[0], an[0]);
-      Th_StringAppend(interp, &zUsage, &nUsage, (const char *)"?", 1);
-    }else{
-      Th_StringAppend(interp, &zUsage, &nUsage, az[0], an[0]);
-    }
-
-    Th_Free(interp, az);
-  }
-  assert( zSpace-(char *)p<=nByte );
-
-  /* If there is an "args" parameter, append it to the end of the usage
-  ** message. Set ProcDefn.zUsage to point at the usage message. It will
-  ** be freed along with the rest of the proc-definition by proc_del().
-  */
-  if( p->hasArgs ){
-    Th_StringAppend(interp, &zUsage, &nUsage, (const char *)" ?args...?", -1);
-  }
-  p->zUsage = zUsage;
-  p->nUsage = nUsage;
-
-  /* Register the new command with the th1 interpreter. */
-  zName = (char *)argv[1];
-  rc = Th_CreateCommand(interp, zName, proc_call1, (void *)p, proc_del);
-  if( rc==TH_OK ){
-    Th_SetResult(interp, 0, 0);
-  }
-
-  Th_Free(interp, azParam);
-  return TH_OK;
-
- error_out:
-  Th_Free(interp, azParam);
-  Th_Free(interp, zUsage);
-  return TH_ERROR;
-}
-
-/*
-** TH Syntax: 
-**
-**   rename oldcmd newcmd
-*/
-static int rename_command(
-  Th_Interp *interp, 
-  void *ctx, 
-  int argc,
-  const char **argv, 
-  int *argl
-){
-  if( argc!=3 ){
-    return Th_WrongNumArgs(interp, "rename oldcmd newcmd");
-  }
-  return Th_RenameCommand(interp, argv[1], argl[1], argv[2], argl[2]);
-}
-
-/*
-** TH Syntax: 
-**
-**   break    ?value...?
-**   continue ?value...?
-**   ok       ?value...?
-**   error    ?value...?
-*/
-static int simple_command(
-  Th_Interp *interp, 
-  void *ctx, 
-  int argc, 
-  const char **argv, 
-  int *argl
-){
-  if( argc!=1 && argc!=2 ){
-    return Th_WrongNumArgs(interp, "return ?value?");
-  }
-  if( argc==2 ){
-    Th_SetResult(interp, argv[1], argl[1]);
-  }
-  return FOSSIL_PTR_TO_INT(ctx);
-}
-
-/*
-** TH Syntax: 
-**
-**   return ?-code code? ?value?
-*/
-static int return_command(
-  Th_Interp *interp, 
-  void *ctx, 
-  int argc, 
-  const char **argv, 
-  int *argl
-){
-  int iCode = TH_RETURN;
-  if( argc<1 || argc>4 ){
-    return Th_WrongNumArgs(interp, "return ?-code code? ?value?");
-  }
-  if( argc>2 ){
-    int rc = Th_ToInt(interp, argv[2], argl[2], &iCode);
-    if( rc!=TH_OK ){
-      return rc;
-    }
-  }
-  if( argc==2 || argc==4 ){
-    Th_SetResult(interp, argv[argc-1], argl[argc-1]);
-  }
-  return iCode;
-}
-
-/*
-** TH Syntax:
-**
-**   string compare STRING1 STRING2
-*/
-static int string_compare_command(
-  Th_Interp *interp, void *ctx, int argc, const char **argv, int *argl
-){
-  const char *zRight; int nRight;
-  const char *zLeft; int nLeft;
-
-  int i;
-  int iRes = 0;
-
-  if( argc!=4 ){
-    return Th_WrongNumArgs(interp, "string compare str1 str2");
-  }
-
-  zLeft = argv[2];
-  nLeft = argl[2];
-  zRight = argv[3];
-  nRight = argl[3];
-
-  for(i=0; iRes==0 && i<nLeft && i<nRight; i++){
-    iRes = zLeft[i]-zRight[i];
-  }
-  if( iRes==0 ){
-    iRes = nLeft-nRight;
-  }
-
-  if( iRes<0 ) iRes = -1;
-  if( iRes>0 ) iRes = 1;
-  
-  return Th_SetResultInt(interp, iRes);
-}
-
-/*
-** TH Syntax:
-**
-**   string first NEEDLE HAYSTACK
-*/
-static int string_first_command(
-  Th_Interp *interp, void *ctx, int argc, const char **argv, int *argl
-){
-  const char *zNeedle;
-  int nNeedle;
-  const char *zHaystack;
-  int nHaystack;
-  int i;
-  int iRes = -1;
-
-  if( argc!=4 ){
-    return Th_WrongNumArgs(interp, "string first needle haystack");
-  }
-
-  zNeedle = argv[2];
-  nNeedle = argl[2];
-  zHaystack = argv[3];
-  nHaystack = argl[3];
-
-  for(i=0; i<(nHaystack-nNeedle); i++){
-    if( 0==memcmp(zNeedle, &zHaystack[i], nNeedle) ){
-      iRes = i;
-      break;
-    }
-  }
-  
-  return Th_SetResultInt(interp, iRes);
-}
-
-/*
-** TH Syntax:
-**
-**   string is CLASS STRING
-*/
-static int string_is_command(
-  Th_Interp *interp, void *ctx, int argc, const char **argv, int *argl
-){
-  int i;
-  int iRes = 1;
-  if( argc!=4 ){
-    return Th_WrongNumArgs(interp, "string is class string");
-  }
-  if( argl[2]!=5 || 0!=memcmp(argv[2], "alnum", 5) ){
-    Th_ErrorMessage(interp, "Expected alnum, got: ", argv[2], argl[2]);
-    return TH_ERROR;
-  }
-
-  for(i=0; i<argl[3]; i++){
-    if( !th_isalnum(argv[3][i]) ){
-      iRes = 0;
-    }
-  }
-
-  return Th_SetResultInt(interp, iRes);
-}
-
-/*
-** TH Syntax:
-**
-**   string last NEEDLE HAYSTACK
-*/
-static int string_last_command(
-  Th_Interp *interp, void *ctx, int argc, const char **argv, int *argl
-){
-  const char *zNeedle;
-  int nNeedle;
-  const char *zHaystack;
-  int nHaystack;
-  int i;
-  int iRes = -1;
-
-  if( argc!=4 ){
-    return Th_WrongNumArgs(interp, "string first needle haystack");
-  }
-
-  zNeedle = argv[2];
-  nNeedle = argl[2];
-  zHaystack = argv[3];
-  nHaystack = argl[3];
-
-  for(i=nHaystack-nNeedle-1; i>=0; i--){
-    if( 0==memcmp(zNeedle, &zHaystack[i], nNeedle) ){
-      iRes = i;
-      break;
-    }
-  }
-  
-  return Th_SetResultInt(interp, iRes);
-}
-
-/*
-** TH Syntax:
-**
-**   string length STRING
-*/
-static int string_length_command(
-  Th_Interp *interp, void *ctx, int argc, const char **argv, int *argl
-){
-  if( argc!=3 ){
-    return Th_WrongNumArgs(interp, "string length string");
-  }
-  return Th_SetResultInt(interp, argl[2]);
-}
-
-/*
-** TH Syntax:
-**
-**   string range STRING FIRST LAST
-*/
-static int string_range_command(
-  Th_Interp *interp, void *ctx, int argc, const char **argv, int *argl
-){
-  int iStart;
-  int iEnd;
-
-  if( argc!=5 ){
-    return Th_WrongNumArgs(interp, "string range string first last");
-  }
-
-  if( argl[4]==3 && 0==memcmp("end", argv[4], 3) ){
-    iEnd = argl[2];
-  }else if( Th_ToInt(interp, argv[4], argl[4], &iEnd) ){
-    Th_ErrorMessage(
-        interp, "Expected \"end\" or integer, got:", argv[4], argl[4]);
-    return TH_ERROR;
-  }
-  if( Th_ToInt(interp, argv[3], argl[3], &iStart) ){
-    return TH_ERROR;
-  }
-
-  if( iStart<0 ) iStart = 0;
-  if( iEnd>=argl[2] ) iEnd = argl[2]-1;
-  if( iStart>iEnd ) iEnd = iStart-1;
-
-  return Th_SetResult(interp, &argv[2][iStart], iEnd-iStart+1);
-}
-
-/*
-** TH Syntax:
-**
-**   string repeat STRING COUNT
-*/
-static int string_repeat_command(
-  Th_Interp *interp, void *ctx, int argc, const char **argv, int *argl
-){
-  int n;
-  int i;
-  int nByte;
-  char *zByte;
-
-  if( argc!=4 ){
-    return Th_WrongNumArgs(interp, "string repeat string n");
-  }
-  if( Th_ToInt(interp, argv[3], argl[3], &n) ){
-    return TH_ERROR;
-  }
-
-  nByte = argl[2] * n;
-  zByte = Th_Malloc(interp, nByte+1);
-  for(i=0; i<nByte; i+=argl[2]){
-    memcpy(&zByte[i], argv[2], argl[2]);
-  }
-
-  Th_SetResult(interp, zByte, nByte);
-  Th_Free(interp, zByte);
-  return TH_OK;
-}
-
-/*
-** TH Syntax:
-**
-**   info exists VAR
-*/
-static int info_exists_command(
-  Th_Interp *interp, void *ctx, int argc, const char **argv, int *argl
-){
-  int rc;
-
-  if( argc!=3 ){
-    return Th_WrongNumArgs(interp, "info exists var");
-  }
-  rc = Th_GetVar(interp, argv[2], argl[2]);
-  Th_SetResultInt(interp, rc?0:1);
-  return TH_OK;
-}
-
-/*
-** TH Syntax:
-**
-**   unset VAR
-*/
-static int unset_command(
-  Th_Interp *interp, 
-  void *ctx,
-  int argc,
-  const char **argv,
-  int *argl
-){
-  if( argc!=2 ){
-    return Th_WrongNumArgs(interp, "unset var");
-  }
-  return Th_UnsetVar(interp, argv[1], argl[1]);
-}
-
-int Th_CallSubCommand(
-  Th_Interp *interp, 
-  void *ctx,
-  int argc,
-  const char **argv,
-  int *argl,
-  Th_SubCommand *aSub
-){
-  int i;
-  for(i=0; aSub[i].zName; i++){
-    char *zName = (char *)aSub[i].zName;
-    if( th_strlen(zName)==argl[1] && 0==memcmp(zName, argv[1], argl[1]) ){
-      return aSub[i].xProc(interp, ctx, argc, argv, argl);
-    }
-  }
-
-  Th_ErrorMessage(interp, "Expected sub-command, got:", argv[1], argl[1]);
-  return TH_ERROR;
-}
-
-/*
-** TH Syntax:
-**
-**   string compare STR1 STR2
-**   string first   NEEDLE HAYSTACK ?STARTINDEX?
-**   string is      CLASS STRING
-**   string last    NEEDLE HAYSTACK ?STARTINDEX?
-**   string length  STRING
-**   string range   STRING FIRST LAST
-**   string repeat  STRING COUNT
-*/
-static int string_command(
-  Th_Interp *interp, 
-  void *ctx,
-  int argc,
-  const char **argv,
-  int *argl
-){
-  Th_SubCommand aSub[] = {
-    { "compare", string_compare_command },
-    { "first",   string_first_command },
-    { "is",      string_is_command },
-    { "last",    string_last_command },
-    { "length",  string_length_command },
-    { "range",   string_range_command },
-    { "repeat",  string_repeat_command },
-    { 0, 0 }
-  };
-  return Th_CallSubCommand(interp, ctx, argc, argv, argl, aSub);
-}
-
-/*
-** TH Syntax:
-**
-**   info exists VARNAME
-*/
-static int info_command(
-  Th_Interp *interp, 
-  void *ctx,
-  int argc,
-  const char **argv,
-  int *argl
-){
-  Th_SubCommand aSub[] = {
-    { "exists",  info_exists_command },
-    { 0, 0 }
-  };
-  return Th_CallSubCommand(interp, ctx, argc, argv, argl, aSub);
-}
-
-/*
-** Convert the script level frame specification (used by the commands 
-** [uplevel] and [upvar]) in (zFrame, nFrame) to an integer frame as 
-** used by Th_LinkVar() and Th_Eval(). If successful, write the integer
-** frame level to *piFrame and return TH_OK. Otherwise, return TH_ERROR
-** and leave an error message in the interpreter result.
-*/
-static int thToFrame(
-  Th_Interp *interp, 
-  const char *zFrame, 
-  int nFrame, 
-  int *piFrame
-){
-  int iFrame;
-  if( th_isdigit(zFrame[0]) ){
-    int rc = Th_ToInt(interp, zFrame, nFrame, &iFrame);
-    if( rc!=TH_OK ) return rc;
-    iFrame = iFrame * -1;
-  }else if( zFrame[0]=='#' ){
-    int rc = Th_ToInt(interp, &zFrame[1], nFrame-1, &iFrame);
-    if( rc!=TH_OK ) return rc;
-    iFrame = iFrame + 1;
-  }else{
-    return TH_ERROR;
-  }
-  *piFrame = iFrame;
-  return TH_OK;
-}
-
-/*
-** TH Syntax:
-**
-**   uplevel ?LEVEL? SCRIPT
-*/
-static int uplevel_command(
-  Th_Interp *interp, 
-  void *ctx,
-  int argc,
-  const char **argv,
-  int *argl
-){
-  int iFrame = -1;
-
-  if( argc!=2 && argc!=3 ){
-    return Th_WrongNumArgs(interp, "uplevel ?level? script...");
-  }
-  if( argc==3 && TH_OK!=thToFrame(interp, argv[1], argl[1], &iFrame) ){
-    return TH_ERROR;
-  }
-  return Th_Eval(interp, iFrame, argv[argc-1], -1);
-}
-
-/*
-** TH Syntax: 
-**
-**   upvar ?FRAME? OTHERVAR MYVAR ?OTHERVAR MYVAR ...?
-*/
-static int upvar_command(
-  Th_Interp *interp, 
-  void *ctx, 
-  int argc, 
-  const char **argv, 
-  int *argl
-){
-  int iVar = 1;
-  int iFrame = -1;
-  int rc = TH_OK;
-  int i;
-
-  if( TH_OK==thToFrame(0, argv[1], argl[1], &iFrame) ){
-    iVar++;
-  }
-  if( argc==iVar || (argc-iVar)%2 ){
-    return Th_WrongNumArgs(interp, 
-        "upvar frame othervar myvar ?othervar myvar...?");
-  }
-  for(i=iVar; rc==TH_OK && i<argc; i=i+2){
-    rc = Th_LinkVar(interp, argv[i+1], argl[i+1], iFrame, argv[i], argl[i]);
-  }
-  return rc;
-}
-
-/*
-** TH Syntax: 
-**
-**   breakpoint ARGS
-**
-** This command does nothing at all. Its purpose in life is to serve
-** as a point for setting breakpoints in a debugger.
-*/
-static int breakpoint_command(
-  Th_Interp *interp, 
-  void *ctx, 
-  int argc, 
-  const char **argv, 
-  int *argl
-){
-  int cnt = 0;
-  cnt++;
-  return TH_OK;
-}
-
-/*
-** Register the built-in th1 language commands with interpreter interp.
-** Usually this is called soon after interpreter creation.
-*/
-int th_register_language(Th_Interp *interp){
-  /* Array of built-in commands. */
-  struct _Command {
-    const char *zName;
-    Th_CommandProc xProc;
-    void *pContext;
-  } aCommand[] = {
-    {"catch",    catch_command,   0},
-    {"expr",     expr_command,    0},
-    {"for",      for_command,     0},
-    {"if",       if_command,      0},
-    {"info",     info_command,    0},
-    {"lindex",   lindex_command,  0},
-    {"list",     list_command,    0},
-    {"llength",  llength_command, 0},
-    {"proc",     proc_command,    0}, 
-    {"rename",   rename_command,  0},
-    {"set",      set_command,     0},
-    {"string",   string_command,  0},
-    {"unset",    unset_command,   0},
-    {"uplevel",  uplevel_command, 0},
-    {"upvar",    upvar_command,   0},
-
-    {"breakpoint", breakpoint_command, 0},
-
-    {"return",   return_command, 0},
-    {"break",    simple_command, (void *)TH_BREAK}, 
-    {"continue", simple_command, (void *)TH_CONTINUE}, 
-    {"error",    simple_command, (void *)TH_ERROR}, 
-
-    {0, 0, 0}
-  };
-  int i;
-
-  /* Add the language commands. */
-  for(i=0; i<(sizeof(aCommand)/sizeof(aCommand[0])); i++){
-    void *ctx;
-    if ( !aCommand[i].zName || !aCommand[i].xProc ) continue;
-    ctx = aCommand[i].pContext;
-    Th_CreateCommand(interp, aCommand[i].zName, aCommand[i].xProc, ctx, 0);
-  }
-
-  return TH_OK;
-}

Index: src/th_main.c
==================================================================
--- src/th_main.c
+++ src/th_main.c
@@ -20,33 +20,13 @@
 */
 #include "config.h"
 #include "th_main.h"
 
 /*
-** Global variable counting the number of outstanding calls to malloc()
-** made by the th1 implementation. This is used to catch memory leaks
-** in the interpreter. Obviously, it also means th1 is not threadsafe.
+** Interfaces to register the scripting language extensions.
 */
-static int nOutstandingMalloc = 0;
-
-/*
-** Implementations of malloc() and free() to pass to the interpreter.
-*/
-static void *xMalloc(unsigned int n){
-  void *p = fossil_malloc(n);
-  if( p ){
-    nOutstandingMalloc++;
-  }
-  return p;
-}
-static void xFree(void *p){
-  if( p ){
-    nOutstandingMalloc--;
-  }
-  free(p);
-}
-static Th_Vtab vtab = { xMalloc, xFree };
+int register_tcl(Jim_Interp *interp, void *pContext); /* th_tcl.c */
 
 /*
 ** Generate a TH1 trace message if debugging is enabled.
 */
 void Th_Trace(const char *zFormat, ...){
@@ -58,28 +38,24 @@
 
 
 /*
 ** True if output is enabled.  False if disabled.
 */
-static int enableOutput = 1;
+static long enableOutput = 1;
 
 /*
 ** TH command:     enable_output BOOLEAN
 **
 ** Enable or disable the puts and hputs commands.
 */
-static int enableOutputCmd(
-  Th_Interp *interp, 
-  void *p, 
-  int argc, 
-  const char **argv, 
-  int *argl
-){
+static int enableOutputCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
   if( argc!=2 ){
-    return Th_WrongNumArgs(interp, "enable_output BOOLEAN");
+    Jim_WrongNumArgs(interp, 1, argv, "BOOLEAN");
+    return JIM_ERR;
   }
-  return Th_ToInt(interp, argv[1], argl[1], &enableOutput);
+  return Jim_GetLong(interp, argv[1], &enableOutput);
 }
 
 /*
 ** Send text to the appropriate output:  Either to the console
 ** or to the CGI reply buffer.
@@ -98,152 +74,152 @@
       fflush(stdout);
     }
     if( encode ) free((char*)z);
   }
 }
+
+static void sendTextObj(Jim_Obj *objPtr, int encode)
+{
+  sendText(Jim_String(objPtr), Jim_Length(objPtr), encode);
+}
 
 /*
 ** TH command:     puts STRING
+**
+** Output STRING as HTML
+*/
+static int putsCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+  if( argc!=2 ){
+    Jim_WrongNumArgs(interp, 1, argv, "STRING");
+    return JIM_ERR;
+  }
+  sendText(Jim_String(argv[1]), -1, 1);
+  return JIM_OK;
+}
+
+/*
 ** TH command:     html STRING
 **
-** Output STRING as HTML (html) or unchanged (puts).  
+** Output STRING unchanged
 */
-static int putsCmd(
-  Th_Interp *interp, 
-  void *pConvert, 
-  int argc, 
-  const char **argv, 
-  int *argl
-){
+static int htmlCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
   if( argc!=2 ){
-    return Th_WrongNumArgs(interp, "puts STRING");
+    Jim_WrongNumArgs(interp, 1, argv, "STRING");
+    return JIM_ERR;
   }
-  sendText((char*)argv[1], argl[1], pConvert!=0);
-  return TH_OK;
+  sendText(Jim_String(argv[1]), -1, 0);
+  return JIM_OK;
 }
 
 /*
 ** TH command:      wiki STRING
 **
 ** Render the input string as wiki.
 */
-static int wikiCmd(
-  Th_Interp *interp, 
-  void *p, 
-  int argc, 
-  const char **argv, 
-  int *argl
-){
+static int wikiCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
   if( argc!=2 ){
-    return Th_WrongNumArgs(interp, "wiki STRING");
+    Jim_WrongNumArgs(interp, 1, argv, "STRING");
+    return JIM_ERR;
   }
   if( enableOutput ){
     Blob src;
-    blob_init(&src, (char*)argv[1], argl[1]);
+    blob_init(&src, Jim_String(argv[1]), Jim_Length(argv[1]));
     wiki_convert(&src, 0, WIKI_INLINE);
     blob_reset(&src);
   }
-  return TH_OK;
+  return JIM_OK;
 }
 
 /*
 ** TH command:      htmlize STRING
 **
 ** Escape all characters of STRING which have special meaning in HTML.
 ** Return a new string result.
 */
-static int htmlizeCmd(
-  Th_Interp *interp, 
-  void *p, 
-  int argc, 
-  const char **argv, 
-  int *argl
-){
+static int htmlizeCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
   char *zOut;
   if( argc!=2 ){
-    return Th_WrongNumArgs(interp, "htmlize STRING");
+    Jim_WrongNumArgs(interp, 1, argv, "STRING");
+    return JIM_ERR;
   }
-  zOut = htmlize((char*)argv[1], argl[1]);
-  Th_SetResult(interp, zOut, -1);
+  zOut = htmlize(Jim_String(argv[1]), Jim_Length(argv[1]));
+  Jim_SetResultString(interp, zOut, -1);
   free(zOut);
-  return TH_OK;
+  return JIM_OK;
 }
 
 /*
 ** TH command:      date
 **
 ** Return a string which is the current time and date.  If the
 ** -local option is used, the date appears using localtime instead
 ** of UTC.
 */
-static int dateCmd(
-  Th_Interp *interp, 
-  void *p, 
-  int argc, 
-  const char **argv, 
-  int *argl
-){
+static int dateCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
   char *zOut;
-  if( argc>=2 && argl[1]==6 && memcmp(argv[1],"-local",6)==0 ){
+  if( argc>=2 && Jim_CompareStringImmediate(interp, argv[1], "-local")) {
     zOut = db_text("??", "SELECT datetime('now','localtime')");
   }else{
     zOut = db_text("??", "SELECT datetime('now')");
   }
-  Th_SetResult(interp, zOut, -1);
+  Jim_SetResultString(interp, zOut, -1);
   free(zOut);
-  return TH_OK;
+  return JIM_OK;
 }
 
 /*
 ** TH command:     hascap STRING
 **
 ** Return true if the user has all of the capabilities listed in STRING.
 */
-static int hascapCmd(
-  Th_Interp *interp, 
-  void *p, 
-  int argc, 
-  const char **argv, 
-  int *argl
-){
+static int hascapCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
   int rc;
+  const char *str;
+  int len;
   if( argc!=2 ){
-    return Th_WrongNumArgs(interp, "hascap STRING");
+    Jim_WrongNumArgs(interp, 1, argv, "STRING");
+    return JIM_ERR;
   }
-  rc = login_has_capability((char*)argv[1],argl[1]);
+  str = Jim_GetString(argv[1], &len);
+  rc = login_has_capability(str, len);
   if( g.thTrace ){
-    Th_Trace("[hascap %#h] => %d<br />\n", argl[1], argv[1], rc);
+    Th_Trace("[hascap %#h] => %d<br />\n", len, str, rc);
   }
-  Th_SetResultInt(interp, rc);
-  return TH_OK;
+  Jim_SetResultInt(interp, rc);
+  return JIM_OK;
 }
 
 /*
 ** TH command:     anycap STRING
 **
 ** Return true if the user has any one of the capabilities listed in STRING.
 */
-static int anycapCmd(
-  Th_Interp *interp, 
-  void *p, 
-  int argc, 
-  const char **argv, 
-  int *argl
-){
+static int anycapCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
   int rc = 0;
   int i;
+  const char *str;
+  int len;
   if( argc!=2 ){
-    return Th_WrongNumArgs(interp, "anycap STRING");
+    Jim_WrongNumArgs(interp, 1, argv, "STRING");
+    return JIM_ERR;
   }
-  for(i=0; rc==0 && i<argl[1]; i++){
-    rc = login_has_capability((char*)&argv[1][i],1);
+  str = Jim_GetString(argv[1], &len);
+  for(i=0; rc==0 && i<len; i++){
+    rc = login_has_capability(&str[i],1);
   }
   if( g.thTrace ){
-    Th_Trace("[hascap %#h] => %d<br />\n", argl[1], argv[1], rc);
+    Th_Trace("[hascap %#h] => %d<br />\n", len, str, rc);
   }
-  Th_SetResultInt(interp, rc);
-  return TH_OK;
+  Jim_SetResultInt(interp, rc);
+  return JIM_OK;
 }
 
 /*
 ** TH1 command:  combobox NAME TEXT-LIST NUMLINES
 **
@@ -252,44 +228,36 @@
 ** currently selected value.  TEXT-LIST is a list of possible
 ** values for the combobox.  NUMLINES is 1 for a true combobox.
 ** If NUMLINES is greater than one then the display is a listbox
 ** with the number of lines given.
 */
-static int comboboxCmd(
-  Th_Interp *interp,
-  void *p, 
-  int argc, 
-  const char **argv, 
-  int *argl
-){
+static int comboboxCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
   if( argc!=4 ){
-    return Th_WrongNumArgs(interp, "combobox NAME TEXT-LIST NUMLINES");
+    Jim_WrongNumArgs(interp, 1, argv, "NAME TEXT-LIST NUMLINES");
+    return JIM_ERR;
   }
   if( enableOutput ){
-    int height;
-    Blob name;
-    int nValue;
-    const char *zValue;
+    long height;
     char *z, *zH;
     int nElem;
-    int *aszElem;
-    char **azElem;
     int i;
+    Jim_Obj *objPtr;
+    Jim_Obj *varObjPtr;
 
-    if( Th_ToInt(interp, argv[3], argl[3], &height) ) return TH_ERROR;
-    Th_SplitList(interp, argv[2], argl[2], &azElem, &aszElem, &nElem);
-    blob_init(&name, (char*)argv[1], argl[1]);
-    zValue = Th_Fetch(blob_str(&name), &nValue);
+    if( Jim_GetLong(interp, argv[3], &height) ) return JIM_ERR;
+    nElem = Jim_ListLength(interp, argv[2]);
+
+    varObjPtr = Jim_GetVariable(g.interp, argv[1], JIM_NONE);
     z = mprintf("<select name=\"%z\" size=\"%d\">", 
-                 htmlize(blob_buffer(&name), blob_size(&name)), height);
+                 htmlize(Jim_String(varObjPtr), Jim_Length(varObjPtr)), height);
     sendText(z, -1, 0);
     free(z);
-    blob_reset(&name);
     for(i=0; i<nElem; i++){
-      zH = htmlize((char*)azElem[i], aszElem[i]);
-      if( zValue && aszElem[i]==nValue 
-             && memcmp(zValue, azElem[i], nValue)==0 ){
+      Jim_ListIndex(interp, argv[2], i, &objPtr, JIM_NONE);
+      zH = htmlize(Jim_String(objPtr), Jim_Length(objPtr));
+      if( varObjPtr && Jim_StringEqObj(varObjPtr, objPtr)) {
         z = mprintf("<option value=\"%s\" selected=\"selected\">%s</option>",
                      zH, zH);
       }else{
         z = mprintf("<option value=\"%s\">%s</option>", zH, zH);
       }
@@ -296,77 +264,67 @@
       free(zH);
       sendText(z, -1, 0);
       free(z);
     }
     sendText("</select>", -1, 0);
-    Th_Free(interp, azElem);
   }
-  return TH_OK;
+  return JIM_OK;
 }
 
 /*
 ** TH1 command:     linecount STRING MAX MIN
 **
 ** Return one more than the number of \n characters in STRING.  But
 ** never return less than MIN or more than MAX.
 */
-static int linecntCmd(
-  Th_Interp *interp,
-  void *p, 
-  int argc, 
-  const char **argv, 
-  int *argl
-){
+static int linecntCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
   const char *z;
   int size, n, i;
-  int iMin, iMax;
+  jim_wide iMin, iMax;
   if( argc!=4 ){
-    return Th_WrongNumArgs(interp, "linecount STRING MAX MIN");
+    Jim_WrongNumArgs(interp, 1, argv, "STRING MAX MIN");
+    return JIM_ERR;
   }
-  if( Th_ToInt(interp, argv[2], argl[2], &iMax) ) return TH_ERROR;
-  if( Th_ToInt(interp, argv[3], argl[3], &iMin) ) return TH_ERROR;
-  z = argv[1];
-  size = argl[1];
+  if( Jim_GetWide(interp, argv[2], &iMax) ) return JIM_ERR;
+  if( Jim_GetWide(interp, argv[3], &iMin) ) return JIM_ERR;
+  z = Jim_GetString(argv[1], &size);
   for(n=1, i=0; i<size; i++){
     if( z[i]=='\n' ){
       n++;
       if( n>=iMax ) break;
     }
   }
   if( n<iMin ) n = iMin;
   if( n>iMax ) n = iMax;
-  Th_SetResultInt(interp, n);
-  return TH_OK;
+  Jim_SetResultInt(interp, n);
+  return JIM_OK;
 }
 
 /*
 ** TH1 command:     repository ?BOOLEAN?
 **
 ** Return the fully qualified file name of the open repository or an empty
 ** string if one is not currently open.  Optionally, it will attempt to open
 ** the repository if the boolean argument is non-zero.
 */
-static int repositoryCmd(
-  Th_Interp *interp,
-  void *p, 
-  int argc, 
-  const char **argv, 
-  int *argl
-){
-  int openRepository;
+static int repositoryCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+  long openRepository;
 
   if( argc!=1 && argc!=2 ){
-    return Th_WrongNumArgs(interp, "repository ?BOOLEAN?");
+    Jim_WrongNumArgs(interp, 1, argv, "BOOLEAN");
+    return JIM_ERR;
   }
   if( argc==2 ){
-    if( Th_ToInt(interp, argv[1], argl[1], &openRepository) ){
-      return TH_ERROR;
+    if( Jim_GetLong(interp, argv[1], &openRepository) != JIM_OK){
+      return JIM_ERR;
     }
     if( openRepository ) db_find_and_open_repository(OPEN_OK_NOT_FOUND, 0);
   }
-  Th_SetResult(interp, g.zRepositoryName, -1);
-  return TH_OK;
+  Jim_SetResultString(interp, g.zRepositoryName, -1);
+  return JIM_OK;
 }
 
 /*
 ** Make sure the interpreter has been initialized.  Initialize it if
 ** it has not been already.
@@ -374,39 +332,43 @@
 ** The interpreter is stored in the g.interp global variable.
 */
 void Th_FossilInit(void){
   static struct _Command {
     const char *zName;
-    Th_CommandProc xProc;
-    void *pContext;
+    Jim_CmdProc xProc;
   } aCommand[] = {
-    {"anycap",        anycapCmd,            0},
-    {"combobox",      comboboxCmd,          0},
-    {"enable_output", enableOutputCmd,      0},
-    {"linecount",     linecntCmd,           0},
-    {"hascap",        hascapCmd,            0},
-    {"htmlize",       htmlizeCmd,           0},
-    {"date",          dateCmd,              0},
-    {"html",          putsCmd,              0},
-    {"puts",          putsCmd,       (void*)1},
-    {"wiki",          wikiCmd,              0},
-    {"repository",    repositoryCmd,        0},
-    {0, 0, 0}
+    {"anycap",        anycapCmd,            },
+    {"combobox",      comboboxCmd,          },
+    {"enable_output", enableOutputCmd,      },
+    {"linecount",     linecntCmd,           },
+    {"hascap",        hascapCmd,            },
+    {"htmlize",       htmlizeCmd,           },
+    {"date",          dateCmd,              },
+    {"html",          htmlCmd,              },
+    {"puts",          putsCmd,              },
+    {"wiki",          wikiCmd,              },
+    {"repository",    repositoryCmd,        },
+    {0, 0}
   };
   if( g.interp==0 ){
     int i;
-    g.interp = Th_CreateInterp(&vtab);
-    th_register_language(g.interp);       /* Basic scripting commands. */
+    /* Create and initialize the interpreter */
+    g.interp = Jim_CreateInterp();
+    Jim_RegisterCoreCommands(g.interp);
+
+    /* Register static extensions */
+    Jim_InitStaticExtensions(g.interp);
+
 #ifdef FOSSIL_ENABLE_TCL
-    if( getenv("TH1_ENABLE_TCL")!=0 || db_get_boolean("tcl", 0) ){
-      th_register_tcl(g.interp, &g.tcl);  /* Tcl integration commands. */
+    if( getenv("FOSSIL_ENABLE_TCL")!=0 || db_get_boolean("tcl", 0) ){
+      register_tcl(g.interp, &g.tcl);  /* Tcl integration commands. */
     }
 #endif
     for(i=0; i<sizeof(aCommand)/sizeof(aCommand[0]); i++){
       if ( !aCommand[i].zName || !aCommand[i].xProc ) continue;
-      Th_CreateCommand(g.interp, aCommand[i].zName, aCommand[i].xProc,
-                       aCommand[i].pContext, 0);
+      Jim_CreateCommand(g.interp, aCommand[i].zName, aCommand[i].xProc, NULL,
+          NULL);
     }
   }
 }
 
 /*
@@ -416,43 +378,60 @@
   Th_FossilInit();
   if( zValue ){
     if( g.thTrace ){
       Th_Trace("set %h {%h}<br />\n", zName, zValue);
     }
-    Th_SetVar(g.interp, zName, -1, zValue, strlen(zValue));
+    Jim_SetVariableStrWithStr(g.interp, zName, zValue);
   }
 }
 
 /*
 ** Unset a variable.
 */
 void Th_Unstore(const char *zName){
   if( g.interp ){
-    Th_UnsetVar(g.interp, (char*)zName, -1);
+    Jim_Obj *nameObjPtr = Jim_NewStringObj(g.interp, zName, -1);
+    Jim_UnsetVariable(g.interp, nameObjPtr, JIM_NONE);
+    Jim_FreeNewObj(g.interp, nameObjPtr);
   }
 }
 
 /*
-** Retrieve a string value from the interpreter.  If no such
+** Retrieve a string value (variable) from the interpreter.  If no such
 ** variable exists, return NULL.
 */
-char *Th_Fetch(const char *zName, int *pSize){
-  int rc;
+const char *Th_Fetch(const char *zName){
+  Jim_Obj *objPtr;
+
   Th_FossilInit();
-  rc = Th_GetVar(g.interp, (char*)zName, -1);
-  if( rc==TH_OK ){
-    return (char*)Th_GetResult(g.interp, pSize);
-  }else{
-    return 0;
-  }
+
+  objPtr = Jim_GetVariableStr(g.interp, zName, JIM_NONE);
+
+  return objPtr ? Jim_String(objPtr) : NULL;
+}
+
+/**
+ * Like Th_Fetch() except the variable name may not be null terminated.
+ * Instead, the length of the name is supplied as 'namelen'.
+ */
+const char *Th_GetVar(Jim_Interp *interp, const char *name, int namelen){
+    Jim_Obj *nameObjPtr, *varObjPtr;
+
+    nameObjPtr = Jim_NewStringObj(interp, name, namelen);
+    Jim_IncrRefCount(nameObjPtr);
+    varObjPtr = Jim_GetVariable(interp, nameObjPtr, 0);
+    Jim_DecrRefCount(interp, nameObjPtr);
+
+    return varObjPtr ? Jim_String(varObjPtr) : NULL;
 }
 
 /*
 ** Return true if the string begins with the TH1 begin-script
 ** tag:  <th1>.
 */
 static int isBeginScriptTag(const char *z){
+  /* XXX: Should we also allow <tcl>? */
   return z[0]=='<'
       && (z[1]=='t' || z[1]=='T')
       && (z[2]=='h' || z[2]=='H')
       && z[3]=='1'
       && z[4]=='>';
@@ -461,10 +440,11 @@
 /*
 ** Return true if the string begins with the TH1 end-script
 ** tag:  </th1>.
 */
 static int isEndScriptTag(const char *z){
+  /* XXX: Should we also allow </tcl>? */
   return z[0]=='<'
       && z[1]=='/'
       && (z[2]=='t' || z[2]=='T')
       && (z[3]=='h' || z[3]=='H')
       && z[4]=='1'
@@ -513,12 +493,12 @@
 ** on either stdout or into CGI.
 */
 int Th_Render(const char *z){
   int i = 0;
   int n;
-  int rc = TH_OK;
-  char *zResult;
+  int rc = JIM_OK;
+  const char *zResult;
   Th_FossilInit();
   while( z[i] ){
     if( z[i]=='$' && (n = validVarName(&z[i+1]))>0 ){
       const char *zVar;
       int nVar;
@@ -532,47 +512,50 @@
         /* Variables of the form $aaa are output raw */
         zVar = &z[i+1];
         nVar = n;
         encode = 0;
       }
-      rc = Th_GetVar(g.interp, (char*)zVar, nVar);
+      zResult = Th_GetVar(g.interp, zVar, nVar);
       z += i+1+n;
       i = 0;
-      zResult = (char*)Th_GetResult(g.interp, &n);
-      sendText((char*)zResult, n, encode);
+      if (zResult) {
+        sendText(zResult, -1, encode);
+      }
     }else if( z[i]=='<' && isBeginScriptTag(&z[i]) ){
+      Jim_Obj *objPtr;
       sendText(z, i, 0);
       z += i+5;
       for(i=0; z[i] && (z[i]!='<' || !isEndScriptTag(&z[i])); i++){}
-      rc = Th_Eval(g.interp, 0, (const char*)z, i);
-      if( rc!=TH_OK ) break;
+      /* XXX: Would be nice to record the source location in case of error */
+      objPtr = Jim_NewStringObj(g.interp, z, i);
+      rc = Jim_EvalObj(g.interp, objPtr);
+      if( rc!=JIM_OK ) break;
       z += i;
       if( z[0] ){ z += 6; }
       i = 0;
     }else{
       i++;
     }
   }
-  if( rc==TH_ERROR ){
+  if( rc==JIM_ERR ){
     sendText("<hr><p class=\"thmainError\">ERROR: ", -1, 0);
-    zResult = (char*)Th_GetResult(g.interp, &n);
-    sendText((char*)zResult, n, 1);
+    sendTextObj(Jim_GetResult(g.interp), 1);
     sendText("</p>", -1, 0);
   }else{
     sendText(z, i, 0);
   }
   return rc;
 }
 
 /*
-** COMMAND: test-th-render
+** COMMAND: test-script-render
 */
-void test_th_render(void){
+void test_script_render(void){
   Blob in;
   if( g.argc<3 ){
     usage("FILE");
   }
   db_open_config(0); /* Needed for global "tcl" setting. */
   blob_zero(&in);
   blob_read_from_file(&in, g.argv[2]);
   Th_Render(blob_str(&in));
 }

Index: src/th_tcl.c
==================================================================
--- src/th_tcl.c
+++ src/th_tcl.c
@@ -6,18 +6,18 @@
 ** This program is distributed in the hope that it will be useful,
 ** but without any warranty; without even the implied warranty of
 ** merchantability or fitness for a particular purpose.
 **
 *******************************************************************************
-** This file contains code used to bridge the TH1 and Tcl scripting languages.
+** This file contains code used to bridge the Jim and Tcl scripting languages.
 */
 
 #include "config.h"
 
 #ifdef FOSSIL_ENABLE_TCL
 
-#include "th.h"
+#include "jim.h"
 #include "tcl.h"
 
 /*
 ** Are we being compiled against Tcl 8.6 or higher?
  */
@@ -30,23 +30,23 @@
 #define USE_TCL_EVALOBJV   1
 #endif
 
 /*
 ** These macros are designed to reduce the redundant code required to marshal
-** arguments from TH1 to Tcl.
+** arguments from Jim to Tcl.
  */
 #define USE_ARGV_TO_OBJV() \
   int objc;                \
   Tcl_Obj **objv;          \
   int i;
 
-#define COPY_ARGV_TO_OBJV()                                         \
-  objc = argc-1;                                                    \
-  objv = (Tcl_Obj **)ckalloc((unsigned)(objc * sizeof(Tcl_Obj *))); \
-  for(i=1; i<argc; i++){                                            \
-    objv[i-1] = Tcl_NewStringObj(argv[i], argl[i]);                 \
-    Tcl_IncrRefCount(objv[i-1]);                                    \
+#define COPY_ARGV_TO_OBJV()                                                 \
+  objc = argc-1;                                                            \
+  objv = (Tcl_Obj **)ckalloc((unsigned)(objc * sizeof(Tcl_Obj *)));         \
+  for(i=1; i<argc; i++){                                                    \
+    objv[i-1] = Tcl_NewStringObj(Jim_String(argv[i]), Jim_Length(argv[i])); \
+    Tcl_IncrRefCount(objv[i-1]);                                            \
   }
 
 #define FREE_ARGV_TO_OBJV()      \
   for(i=1; i<argc; i++){         \
     Tcl_DecrRefCount(objv[i-1]); \
@@ -59,16 +59,16 @@
  */
 #define GET_CTX_TCL_INTERP(ctx) \
   ((struct TclContext *)(ctx))->interp
 
 /*
-** Creates and initializes a Tcl interpreter for use with the specified TH1
+** Creates and initializes a Tcl interpreter for use with the specified Jim
 ** interpreter.  Stores the created Tcl interpreter in the Tcl context supplied
 ** by the caller.  This must be declared here because quite a few functions in
 ** this file need to use it before it can be defined.
  */
-static int createTclInterp(Th_Interp *interp, void *pContext);
+static int createTclInterp(Jim_Interp *interp, void *pContext);
 
 /*
 ** Returns the Tcl interpreter result as a string with the associated length.
 ** If the Tcl interpreter or the Tcl result are NULL, the length will be 0.
 ** If the length pointer is NULL, the length will not be stored.
@@ -89,11 +89,11 @@
   }
   return Tcl_GetStringFromObj(resultPtr, pN);
 }
 
 /*
-** Tcl context information used by TH1.  This structure definition has been
+** Tcl context information used by Jim.  This structure definition has been
 ** copied from and should be kept in sync with the one in "main.c".
 */
 struct TclContext {
   int argc;
   char **argv;
@@ -104,36 +104,36 @@
 ** Syntax:
 **
 **   tclEval arg ?arg ...?
 */
 static int tclEval_command(
-  Th_Interp *interp,
-  void *ctx,
+  Jim_Interp *interp,
   int argc,
-  const char **argv,
-  int *argl
+  Jim_Obj *const *argv
 ){
   Tcl_Interp *tclInterp;
   Tcl_Obj *objPtr;
   int rc;
   int nResult;
   const char *zResult;
+  void *ctx = Jim_CmdPrivData(interp);
 
-  if ( createTclInterp(interp, ctx)!=TH_OK ){
-    return TH_ERROR;
+  if ( createTclInterp(interp, ctx)!=JIM_OK ){
+    return JIM_ERR;
   }
   if( argc<2 ){
-    return Th_WrongNumArgs(interp, "tclEval arg ?arg ...?");
+    Jim_WrongNumArgs(interp, 1, argv, "arg ?arg ...?");
+    return JIM_ERR;
   }
   tclInterp = GET_CTX_TCL_INTERP(ctx);
   if( !tclInterp || Tcl_InterpDeleted(tclInterp) ){
-    Th_ErrorMessage(interp, "invalid Tcl interpreter", (const char *)"", 0);
-    return TH_ERROR;
+    Jim_SetResultString(interp, "invalid Tcl interpreter", -1);
+    return JIM_ERR;
   }
   Tcl_Preserve((ClientData)tclInterp);
   if( argc==2 ){
-    objPtr = Tcl_NewStringObj(argv[1], argl[1]);
+    objPtr = Tcl_NewStringObj(Jim_String(argv[1]), Jim_Length(argv[1]));
     Tcl_IncrRefCount(objPtr);
     rc = Tcl_EvalObjEx(tclInterp, objPtr, 0);
     Tcl_DecrRefCount(objPtr);
   }else{
     USE_ARGV_TO_OBJV();
@@ -143,11 +143,11 @@
     rc = Tcl_EvalObjEx(tclInterp, objPtr, 0);
     Tcl_DecrRefCount(objPtr);
     FREE_ARGV_TO_OBJV();
   }
   zResult = getTclResult(tclInterp, &nResult);
-  Th_SetResult(interp, zResult, nResult);
+  Jim_SetResultString(interp, zResult, nResult);
   Tcl_Release((ClientData)tclInterp);
   return rc;
 }
 
 /*
@@ -154,37 +154,37 @@
 ** Syntax:
 **
 **   tclExpr arg ?arg ...?
 */
 static int tclExpr_command(
-  Th_Interp *interp,
-  void *ctx,
+  Jim_Interp *interp,
   int argc,
-  const char **argv,
-  int *argl
+  Jim_Obj *const *argv
 ){
   Tcl_Interp *tclInterp;
   Tcl_Obj *objPtr;
   Tcl_Obj *resultObjPtr;
   int rc;
   int nResult;
   const char *zResult;
+  void *ctx = Jim_CmdPrivData(interp);
 
-  if ( createTclInterp(interp, ctx)!=TH_OK ){
-    return TH_ERROR;
+  if ( createTclInterp(interp, ctx)!=JIM_OK ){
+    return JIM_ERR;
   }
   if( argc<2 ){
-    return Th_WrongNumArgs(interp, "tclExpr arg ?arg ...?");
+    Jim_WrongNumArgs(interp, 1, argv, "arg ?arg ...?");
+    return JIM_ERR;
   }
   tclInterp = GET_CTX_TCL_INTERP(ctx);
   if( !tclInterp || Tcl_InterpDeleted(tclInterp) ){
-    Th_ErrorMessage(interp, "invalid Tcl interpreter", (const char *)"", 0);
-    return TH_ERROR;
+    Jim_SetResultString(interp, "invalid Tcl interpreter", -1);
+    return JIM_ERR;
   }
   Tcl_Preserve((ClientData)tclInterp);
   if( argc==2 ){
-    objPtr = Tcl_NewStringObj(argv[1], argl[1]);
+    objPtr = Tcl_NewStringObj(Jim_String(argv[1]), Jim_Length(argv[1]));
     Tcl_IncrRefCount(objPtr);
     rc = Tcl_ExprObj(tclInterp, objPtr, &resultObjPtr);
     Tcl_DecrRefCount(objPtr);
   }else{
     USE_ARGV_TO_OBJV();
@@ -198,11 +198,11 @@
   if( rc==TCL_OK ){
     zResult = Tcl_GetStringFromObj(resultObjPtr, &nResult);
   }else{
     zResult = getTclResult(tclInterp, &nResult);
   }
-  Th_SetResult(interp, zResult, nResult);
+  Jim_SetResultString(interp, zResult, nResult);
   if( rc==TCL_OK ) Tcl_DecrRefCount(resultObjPtr);
   Tcl_Release((ClientData)tclInterp);
   return rc;
 }
 
@@ -210,56 +210,57 @@
 ** Syntax:
 **
 **   tclInvoke command ?arg ...?
 */
 static int tclInvoke_command(
-  Th_Interp *interp,
-  void *ctx,
+  Jim_Interp *interp,
   int argc,
-  const char **argv,
-  int *argl
+  Jim_Obj *const *argv
 ){
   Tcl_Interp *tclInterp;
 #ifndef USE_TCL_EVALOBJV
   Tcl_Command command;
   Tcl_CmdInfo cmdInfo;
 #endif
   int rc;
   int nResult;
   const char *zResult;
+  void *ctx = Jim_CmdPrivData(interp);
 #ifndef USE_TCL_EVALOBJV
   Tcl_Obj *objPtr;
 #endif
   USE_ARGV_TO_OBJV();
 
-  if ( createTclInterp(interp, ctx)!=TH_OK ){
-    return TH_ERROR;
+  if ( createTclInterp(interp, ctx)!=JIM_OK ){
+    return JIM_ERR;
   }
   if( argc<2 ){
-    return Th_WrongNumArgs(interp, "tclInvoke command ?arg ...?");
+    Jim_WrongNumArgs(interp, 1, argv, "command ?arg ...?");
+    return JIM_ERR;
   }
   tclInterp = GET_CTX_TCL_INTERP(ctx);
   if( !tclInterp || Tcl_InterpDeleted(tclInterp) ){
-    Th_ErrorMessage(interp, "invalid Tcl interpreter", (const char *)"", 0);
-    return TH_ERROR;
+    Jim_SetResultString(interp, "invalid Tcl interpreter", -1);
+    return JIM_ERR;
   }
   Tcl_Preserve((ClientData)tclInterp);
 #ifndef USE_TCL_EVALOBJV
-  objPtr = Tcl_NewStringObj(argv[1], argl[1]);
+  objPtr = Tcl_NewStringObj(Jim_String(argv[1]), Jim_Length(argv[1]));
   Tcl_IncrRefCount(objPtr);
   command = Tcl_GetCommandFromObj(tclInterp, objPtr);
   if( !command || Tcl_GetCommandInfoFromToken(command,&cmdInfo)==0 ){
-    Th_ErrorMessage(interp, "Tcl command not found:", argv[1], argl[1]);
+    Jim_SetResultFormatted(interp, "Tcl command not found: %#s", argv[1]);
     Tcl_DecrRefCount(objPtr);
     Tcl_Release((ClientData)tclInterp);
-    return TH_ERROR;
+    return JIM_ERR;
   }
   if( !cmdInfo.objProc ){
-    Th_ErrorMessage(interp, "Cannot invoke Tcl command:", argv[1], argl[1]);
+    Jim_SetResultFormatted(interp, "Cannot invoke command not found: %#s",
+        argv[1]);
     Tcl_DecrRefCount(objPtr);
     Tcl_Release((ClientData)tclInterp);
-    return TH_ERROR;
+    return JIM_ERR;
   }
   Tcl_DecrRefCount(objPtr);
 #endif
   COPY_ARGV_TO_OBJV();
 #ifdef USE_TCL_EVALOBJV
@@ -268,86 +269,99 @@
   Tcl_ResetResult(tclInterp);
   rc = cmdInfo.objProc(cmdInfo.objClientData, tclInterp, objc, objv);
 #endif
   FREE_ARGV_TO_OBJV();
   zResult = getTclResult(tclInterp, &nResult);
-  Th_SetResult(interp, zResult, nResult);
+  Jim_SetResultString(interp, zResult, nResult);
   Tcl_Release((ClientData)tclInterp);
   return rc;
 }
 
 /*
 ** Syntax:
 **
-**   th1Eval arg
+**   bridgeEval arg
 */
-static int Th1EvalObjCmd(
+static int BridgeEvalObjCmd(
   ClientData clientData,
   Tcl_Interp *interp,
   int objc,
   Tcl_Obj *CONST objv[]
 ){
-  Th_Interp *th1Interp;
+  Jim_Interp *jimInterp;
   int nArg;
   const char *arg;
   int rc;
+  Jim_Obj *argObj;
+  Jim_Obj *resultObj;
 
   if( objc!=2 ){
     Tcl_WrongNumArgs(interp, 1, objv, "arg");
     return TCL_ERROR;
   }
-  th1Interp = (Th_Interp *)clientData;
-  if( !th1Interp ){
-    Tcl_AppendResult(interp, "invalid TH1 interpreter", NULL);
+  jimInterp = (Jim_Interp *)clientData;
+  if( !jimInterp ){
+    Tcl_AppendResult(interp, "invalid bridge interpreter", NULL);
     return TCL_ERROR;
   }
   arg = Tcl_GetStringFromObj(objv[1], &nArg);
-  rc = Th_Eval(th1Interp, 0, arg, nArg);
-  arg = Th_GetResult(th1Interp, &nArg);
+  argObj = Jim_NewStringObj(jimInterp, arg, nArg);
+  Jim_IncrRefCount(argObj);
+  rc = Jim_EvalObj(jimInterp, argObj);
+  Jim_DecrRefCount(jimInterp, argObj);
+  resultObj = Jim_GetResult(jimInterp);
+  arg = Jim_GetString(resultObj, &nArg);
   Tcl_SetObjResult(interp, Tcl_NewStringObj(arg, nArg));
   return rc;
 }
 
 /*
 ** Syntax:
 **
-**   th1Expr arg
+**   bridgeExpr arg
 */
-static int Th1ExprObjCmd(
+static int BridgeExprObjCmd(
   ClientData clientData,
   Tcl_Interp *interp,
   int objc,
   Tcl_Obj *CONST objv[]
 ){
-  Th_Interp *th1Interp;
+  Jim_Interp *jimInterp;
   int nArg;
   const char *arg;
   int rc;
+  Jim_Obj *argObj;
+  Jim_Obj *resultObj;
 
   if( objc!=2 ){
     Tcl_WrongNumArgs(interp, 1, objv, "arg");
     return TCL_ERROR;
   }
-  th1Interp = (Th_Interp *)clientData;
-  if( !th1Interp ){
-    Tcl_AppendResult(interp, "invalid TH1 interpreter", NULL);
+  jimInterp = (Jim_Interp *)clientData;
+  if( !jimInterp ){
+    Tcl_AppendResult(interp, "invalid bridge interpreter", NULL);
     return TCL_ERROR;
   }
   arg = Tcl_GetStringFromObj(objv[1], &nArg);
-  rc = Th_Expr(th1Interp, arg, nArg);
-  arg = Th_GetResult(th1Interp, &nArg);
-  Tcl_SetObjResult(interp, Tcl_NewStringObj(arg, nArg));
+  argObj = Jim_NewStringObj(jimInterp, arg, nArg);
+  Jim_IncrRefCount(argObj);
+  rc = Jim_EvalExpression(jimInterp, argObj, &resultObj);
+  Jim_DecrRefCount(jimInterp, argObj);
+  if (rc == JIM_OK) {
+    arg = Jim_GetString(resultObj, &nArg);
+    Tcl_SetObjResult(interp, Tcl_NewStringObj(arg, nArg));
+  }
   return rc;
 }
 
 /*
 ** Array of Tcl integration commands.  Used when adding or removing the Tcl
-** integration commands from TH1.
+** integration commands from Jim.
 */
 static struct _Command {
   const char *zName;
-  Th_CommandProc xProc;
+  Jim_CmdProc xProc;
   void *pContext;
 } aCommand[] = {
   {"tclEval",   tclEval_command,   0},
   {"tclExpr",   tclExpr_command,   0},
   {"tclInvoke", tclInvoke_command, 0},
@@ -354,85 +368,83 @@
   {0, 0, 0}
 };
 
 /*
 ** Called if the Tcl interpreter is deleted.  Removes the Tcl integration
-** commands from the TH1 interpreter.
+** commands from the Jim interpreter.
  */
-static void Th1DeleteProc(
+static void BridgeDeleteProc(
   ClientData clientData,
   Tcl_Interp *interp
 ){
   int i;
-  Th_Interp *th1Interp = (Th_Interp *)clientData;
-  if( !th1Interp ) return;
+  Jim_Interp *jimInterp = (Jim_Interp *)clientData;
+  if( !jimInterp ) return;
   /* Remove the Tcl integration commands. */
   for(i=0; i<(sizeof(aCommand)/sizeof(aCommand[0])); i++){
-    Th_RenameCommand(th1Interp, aCommand[i].zName, -1, NULL, 0);
+    Jim_DeleteCommand(jimInterp, aCommand[i].zName);
   }
 }
 
 /*
-** Creates and initializes a Tcl interpreter for use with the specified TH1
+** Creates and initializes a Tcl interpreter for use with the specified Jim
 ** interpreter.  Stores the created Tcl interpreter in the Tcl context supplied
 ** by the caller.
  */
 static int createTclInterp(
-  Th_Interp *interp,
+  Jim_Interp *interp,
   void *pContext
 ){
   struct TclContext *tclContext = (struct TclContext *)pContext;
   Tcl_Interp *tclInterp;
 
   if ( !tclContext ){
-    Th_ErrorMessage(interp,
-        "Invalid Tcl context", (const char *)"", 0);
-    return TH_ERROR;
+    Jim_SetResultString(interp, "Invalid Tcl context", -1);
+    return JIM_ERR;
   }
   if ( tclContext->interp ){
-    return TH_OK;
+    return JIM_OK;
   }
   if ( tclContext->argc>0 && tclContext->argv ) {
     Tcl_FindExecutable(tclContext->argv[0]);
   }
   tclInterp = tclContext->interp = Tcl_CreateInterp();
   if( !tclInterp || Tcl_InterpDeleted(tclInterp) ){
-    Th_ErrorMessage(interp,
-        "Could not create Tcl interpreter", (const char *)"", 0);
-    return TH_ERROR;
+    Jim_SetResultString(interp, "Could not create Tcl interpreter", -1);
+    return JIM_ERR;
   }
   if( Tcl_Init(tclInterp)!=TCL_OK ){
-    Th_ErrorMessage(interp,
-        "Tcl initialization error:", Tcl_GetStringResult(tclInterp), -1);
+    Jim_SetResultFormatted(interp, "Tcl initialization error: %s",
+        Tcl_GetStringResult(tclInterp));
     Tcl_DeleteInterp(tclInterp);
     tclContext->interp = tclInterp = 0;
-    return TH_ERROR;
+    return JIM_ERR;
   }
-  /* Add the TH1 integration commands to Tcl. */
-  Tcl_CallWhenDeleted(tclInterp, Th1DeleteProc, interp);
-  Tcl_CreateObjCommand(tclInterp, "th1Eval", Th1EvalObjCmd, interp, NULL);
-  Tcl_CreateObjCommand(tclInterp, "th1Expr", Th1ExprObjCmd, interp, NULL);
-  return TH_OK;
+  /* Add the Jim integration commands to Tcl. */
+  Tcl_CallWhenDeleted(tclInterp, BridgeDeleteProc, interp);
+  Tcl_CreateObjCommand(tclInterp, "bridgeEval", BridgeEvalObjCmd, interp, NULL);
+  Tcl_CreateObjCommand(tclInterp, "bridgeExpr", BridgeExprObjCmd, interp, NULL);
+  return JIM_OK;
 }
 
 /*
 ** Register the Tcl language commands with interpreter interp.
 ** Usually this is called soon after interpreter creation.
 */
-int th_register_tcl(
-  Th_Interp *interp,
+int register_tcl(
+  Jim_Interp *interp,
   void *pContext
 ){
   int i;
-  /* Add the Tcl integration commands to TH1. */
+  /* Add the Tcl integration commands to Jim. */
   for(i=0; i<(sizeof(aCommand)/sizeof(aCommand[0])); i++){
     void *ctx;
     if ( !aCommand[i].zName || !aCommand[i].xProc ) continue;
     ctx = aCommand[i].pContext;
     /* Use Tcl interpreter for context? */
     if( !ctx ) ctx = pContext;
-    Th_CreateCommand(interp, aCommand[i].zName, aCommand[i].xProc, ctx, 0);
+    Jim_CreateCommand(interp, aCommand[i].zName, aCommand[i].xProc, ctx, NULL);
   }
-  return TH_OK;
+  return JIM_OK;
 }
 
 #endif /* FOSSIL_ENABLE_TCL */

Index: src/tkt.c
==================================================================
--- src/tkt.c
+++ src/tkt.c
@@ -98,11 +98,11 @@
 ** obscured.
 */
 static void initializeVariablesFromDb(void){
   const char *zName;
   Stmt q;
-  int i, n, size, j;
+  int i, n, j;
 
   zName = PD("name","-none-");
   db_prepare(&q, "SELECT datetime(tkt_mtime,'localtime') AS tkt_datetime, *"
                  "  FROM ticket WHERE tkt_uuid GLOB '%q*'", zName);
   if( db_step(&q)==SQLITE_ROW ){
@@ -120,28 +120,28 @@
         if( fossil_strcmp(azField[j],zName)==0 ){
           azValue[j] = mprintf("%s", zVal);
           break;
         }
       }
-      if( Th_Fetch(zName, &size)==0 ){
+      if( Th_Fetch(zName)==0 ){
         Th_Store(zName, zVal);
       }
       free(zRevealed);
     }
   }else{
     db_finalize(&q);
     db_prepare(&q, "PRAGMA table_info(ticket)");
-    if( Th_Fetch("tkt_uuid",&size)==0 ){
+    if( Th_Fetch("tkt_uuid")==0 ){
       Th_Store("tkt_uuid",zName);
     }
     while( db_step(&q)==SQLITE_ROW ){
       const char *zField = db_column_text(&q, 1);
-      if( Th_Fetch(zField, &size)==0 ){
+      if( Th_Fetch(zField)==0 ){
         Th_Store(zField, "");
       }
     }
-    if( Th_Fetch("tkt_datetime",&size)==0 ){
+    if( Th_Fetch("tkt_datetime")==0 ){
       Th_Store("tkt_datetime","");
     }
   }
   db_finalize(&q);
 }
@@ -240,11 +240,11 @@
 */
 void ticket_init(void){
   const char *zConfig;
   Th_FossilInit();
   zConfig = ticket_common_code();
-  Th_Eval(g.interp, 0, zConfig, -1);
+  Jim_Eval(g.interp, zConfig);
 }
 
 /*
 ** Recreate the ticket table.
 */
@@ -373,38 +373,37 @@
 ** FIELD is the name of a database column to which we might want
 ** to append text.  STRING is the text to be appended to that
 ** column.  The append does not actually occur until the
 ** submit_ticket command is run.
 */
-static int appendRemarkCmd(
-  Th_Interp *interp, 
-  void *p, 
-  int argc, 
-  const char **argv, 
-  int *argl
-){
+static int appendRemarkCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
   int idx;
+  const char *str;
+  int len;
 
   if( argc!=3 ){
-    return Th_WrongNumArgs(interp, "append_field FIELD STRING");
+    Jim_WrongNumArgs(interp, 1, argv, "FIELD STRING");
+    return JIM_ERR;
   }
+  str = Jim_GetString(argv[1], &len);
   if( g.thTrace ){
     Th_Trace("append_field %#h {%#h}<br />\n",
-              argl[1], argv[1], argl[2], argv[2]);
+              len, str, Jim_Length(argv[2]), Jim_String(argv[2]));
   }
   for(idx=0; idx<nField; idx++){
-    if( strncmp(azField[idx], argv[1], argl[1])==0
-        && azField[idx][argl[1]]==0 ){
+    if( strncmp(azField[idx], str, len)==0
+        && azField[idx][len]==0 ){
       break;
     }
   }
   if( idx>=nField ){
-    Th_ErrorMessage(g.interp, "no such TICKET column: ", argv[1], argl[1]);
-    return TH_ERROR;
+    Jim_SetResultFormatted(g.interp, "no such TICKET column: %#s", argv[1]);
+    return JIM_ERR;
   }
-  azAppend[idx] = mprintf("%.*s", argl[2], argv[2]);
-  return TH_OK;
+  azAppend[idx] = mprintf("%.*s", Jim_Length(argv[2]), Jim_String(argv[2]));
+  return JIM_OK;
 }
 
 /*
 ** Subscript command:   submit_ticket
 **
@@ -412,18 +411,14 @@
 ** are the names of the columns in the TICKET table.  The content is
 ** taken from TH variables.  If the content is unchanged, the field is
 ** omitted from the artifact.  Fields whose names begin with "private_"
 ** are concealed using the db_conceal() function.
 */
-static int submitTicketCmd(
-  Th_Interp *interp, 
-  void *pUuid, 
-  int argc, 
-  const char **argv, 
-  int *argl
-){
+static int submitTicketCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
   char *zDate;
+  void *pUuid = Jim_CmdPrivData(interp);
   const char *zUuid;
   int i;
   int rid;
   Blob tktchng, cksum;
 
@@ -441,12 +436,13 @@
   }
   for(i=0; i<nField; i++){
     const char *zValue;
     int nValue;
     if( azAppend[i] ) continue;
-    zValue = Th_Fetch(azField[i], &nValue);
+    zValue = Th_Fetch(azField[i]);
     if( zValue ){
+      nValue = strlen(zValue);
       while( nValue>0 && fossil_isspace(zValue[nValue-1]) ){ nValue--; }
       if( strncmp(zValue, azValue[i], nValue) || strlen(azValue[i])!=nValue ){
         if( strncmp(azField[i], "private_", 8)==0 ){
           zValue = db_conceal(zValue, nValue);
           blob_appendf(&tktchng, "J %s %s\n", azField[i], zValue);
@@ -472,11 +468,11 @@
     /* If called from /debug_tktnew or /debug_tktedit... */
     @ <font color="blue">
     @ <p>Ticket artifact that would have been submitted:</p>
     @ <blockquote><pre>%h(blob_str(&tktchng))</pre></blockquote>
     @ <hr /></font>
-    return TH_OK;
+    return JIM_OK;
   }else if( g.thTrace ){
     Th_Trace("submit_ticket {\n<blockquote><pre>\n%h\n</pre></blockquote>\n"
              "}<br />\n",
        blob_str(&tktchng));
   }else{
@@ -487,11 +483,11 @@
     manifest_crosslink_begin();
     manifest_crosslink(rid, &tktchng);
     assert( blob_is_reset(&tktchng) );
     manifest_crosslink_end();
   }
-  return TH_RETURN;
+  return JIM_RETURN;
 }
 
 
 /*
 ** WEBPAGE: tktnew
@@ -527,14 +523,13 @@
   }
   @ </p>
   zScript = ticket_newpage_code();
   Th_Store("login", g.zLogin);
   Th_Store("date", db_text(0, "SELECT datetime('now')"));
-  Th_CreateCommand(g.interp, "submit_ticket", submitTicketCmd,
-                   (void*)&zNewUuid, 0);
+  Jim_CreateCommand(g.interp, "submit_ticket", submitTicketCmd, (void *)&zNewUuid, NULL);
   if( g.thTrace ) Th_Trace("BEGIN_TKTNEW_SCRIPT<br />\n", -1);
-  if( Th_Render(zScript)==TH_RETURN && !g.thTrace && zNewUuid ){
+  if( Th_Render(zScript)==JIM_RETURN && !g.thTrace && zNewUuid ){
     cgi_redirect(mprintf("%s/tktview/%s", g.zTop, zNewUuid));
     return;
   }
   @ </form>
   if( g.thTrace ) Th_Trace("END_TKTVIEW<br />\n", -1);
@@ -594,14 +589,14 @@
   login_insert_csrf_secret();
   @ </p>
   zScript = ticket_editpage_code();
   Th_Store("login", g.zLogin);
   Th_Store("date", db_text(0, "SELECT datetime('now')"));
-  Th_CreateCommand(g.interp, "append_field", appendRemarkCmd, 0, 0);
-  Th_CreateCommand(g.interp, "submit_ticket", submitTicketCmd, (void*)&zName,0);
+  Jim_CreateCommand(g.interp, "append_field", appendRemarkCmd, NULL, NULL);
+  Jim_CreateCommand(g.interp, "submit_ticket", submitTicketCmd, (void*)&zName, NULL);
   if( g.thTrace ) Th_Trace("BEGIN_TKTEDIT_SCRIPT<br />\n", -1);
-  if( Th_Render(zScript)==TH_RETURN && !g.thTrace && zName ){
+  if( Th_Render(zScript)==JIM_RETURN && !g.thTrace && zName ){
     cgi_redirect(mprintf("%s/tktview/%s", g.zTop, zName));
     return;
   }
   @ </form>
   if( g.thTrace ) Th_Trace("BEGIN_TKTEDIT<br />\n", -1);

Index: src/xfer.c
==================================================================
--- src/xfer.c
+++ src/xfer.c
@@ -791,19 +791,19 @@
 static void server_private_xfer_not_authorized(void){
   @ error not\sauthorized\sto\ssync\sprivate\scontent
 }
 
 /*
-** Run the specified TH1 script, if any, and returns the return code or TH_OK
+** Run the specified TH1 script, if any, and returns the return code or JIM_OK
 ** when there is no script.
 */
 static int run_script(const char *zScript){
   if( !zScript ){
-    return TH_OK; /* No script, return success. */
+    return JIM_OK; /* No script, return success. */
   }
   Th_FossilInit(); /* Make sure TH1 is ready. */
-  return Th_Eval(g.interp, 0, zScript, -1);
+  return Jim_Eval(g.interp, zScript);
 }
 
 /*
 ** Run the pre-transfer TH1 script, if any, and returns the return code.
 */
@@ -872,13 +872,13 @@
   db_begin_transaction();
   db_multi_exec(
      "CREATE TEMP TABLE onremote(rid INTEGER PRIMARY KEY);"
   );
   manifest_crosslink_begin();
-  if( run_common_script()==TH_ERROR ){
+  if( run_common_script()!=JIM_OK ){
     cgi_reset_content();
-    @ error common\sscript\sfailed:\s%F(Th_GetResult(g.interp, 0))
+    @ error common\sscript\sfailed:\s%F(Jim_String(Jim_GetResult(g.interp)))
     nErr++;
   }
   while( blob_line(xfer.pIn, &xfer.line) ){
     if( blob_buffer(&xfer.line)[0]=='#' ) continue;
     if( blob_size(&xfer.line)==0 ) continue;
@@ -1190,13 +1190,13 @@
       @ error bad\scommand:\s%F(blob_str(&xfer.line))
     }
     blobarray_reset(xfer.aToken, xfer.nToken);
   }
   if( isPush ){
-    if( run_push_script()==TH_ERROR ){
+    if( run_push_script()!=JIM_OK ){
       cgi_reset_content();
-      @ error push\sscript\sfailed:\s%F(Th_GetResult(g.interp, 0))
+      @ error push\sscript\sfailed:\s%F(Jim_String(Jim_GetResult(g.interp)))
       nErr++;
     }
     request_phantoms(&xfer, 500);
   }
   if( isClone && nGimme==0 ){

Index: test/th1-tcl.test
==================================================================
--- test/th1-tcl.test
+++ test/th1-tcl.test
@@ -24,11 +24,11 @@
 
 set env(TH1_ENABLE_TCL) 1; # Tcl integration must be enabled for this test.
 
 ###############################################################################
 
-fossil test-th-render [file nativename [file join $dir th1-tcl1.txt]]
+fossil test-script-render [file nativename [file join $dir th1-tcl1.txt]]
 
 test th1-tcl-1 {[regexp -- {^\d+
 \d+
 \d+
 via Tcl invoke
@@ -48,55 +48,55 @@
 three words now
 $} [string map [list \r\n \n] $RESULT]]}
 
 ###############################################################################
 
-fossil test-th-render [file nativename [file join $dir th1-tcl2.txt]]
+fossil test-script-render [file nativename [file join $dir th1-tcl2.txt]]
 
 test th1-tcl-2 {[regexp -- {^\d+
 $} [string map [list \r\n \n] $RESULT]]}
 
 ###############################################################################
 
-fossil test-th-render [file nativename [file join $dir th1-tcl3.txt]]
+fossil test-script-render [file nativename [file join $dir th1-tcl3.txt]]
 
 test th1-tcl-3 {$RESULT eq {<hr><p class="thmainError">ERROR:\
 invalid command name &quot;bad_command&quot;</p>}}
 
 ###############################################################################
 
-fossil test-th-render [file nativename [file join $dir th1-tcl4.txt]]
+fossil test-script-render [file nativename [file join $dir th1-tcl4.txt]]
 
 test th1-tcl-4 {$RESULT eq {<hr><p class="thmainError">ERROR:\
 divide by zero</p>}}
 
 ###############################################################################
 
-fossil test-th-render [file nativename [file join $dir th1-tcl5.txt]]
+fossil test-script-render [file nativename [file join $dir th1-tcl5.txt]]
 
 test th1-tcl-5 {$RESULT eq {<hr><p class="thmainError">ERROR:\
 Tcl command not found: bad_command</p>} || $RESULT eq {<hr><p\
 class="thmainError">ERROR: invalid command name &quot;bad_command&quot;</p>}}
 
 ###############################################################################
 
-fossil test-th-render [file nativename [file join $dir th1-tcl6.txt]]
+fossil test-script-render [file nativename [file join $dir th1-tcl6.txt]]
 
 test th1-tcl-6 {$RESULT eq {<hr><p class="thmainError">ERROR:\
 no such command:  bad_command</p>}}
 
 ###############################################################################
 
-fossil test-th-render [file nativename [file join $dir th1-tcl7.txt]]
+fossil test-script-render [file nativename [file join $dir th1-tcl7.txt]]
 
 test th1-tcl-7 {$RESULT eq {<hr><p class="thmainError">ERROR:\
 syntax error in expression: &quot;2**0&quot;</p>}}
 
 ###############################################################################
 
-fossil test-th-render [file nativename [file join $dir th1-tcl8.txt]]
+fossil test-script-render [file nativename [file join $dir th1-tcl8.txt]]
 
 test th1-tcl-8 {$RESULT eq {<hr><p class="thmainError">ERROR:\
 Cannot invoke Tcl command: tailcall</p>} || $RESULT eq {<hr><p\
 class="thmainError">ERROR: tailcall can only be called from a proc or\
 lambda</p>}}
 

Index: test/th1-tcl1.txt
==================================================================
--- test/th1-tcl1.txt
+++ test/th1-tcl1.txt
@@ -1,10 +1,10 @@
 <th1>
   #
-  # This is a "TH1 fragment" used to test the Tcl integration features of TH1.
-  # The corresponding test file executes this file using the test-th-render
-  # Fossil command.
+  # This is a "script fragment" used to test the Tcl integration features of
+  # Fossil.  The corresponding test file executes this file using the
+  # test-script-render Fossil command.
   #
   set channel stdout; tclInvoke set channel $channel
   proc doOut {msg} {puts $msg; puts \n}
   doOut [tclEval clock seconds]
   doOut [tclEval {set x [clock seconds]}]
@@ -14,14 +14,14 @@
   doOut [tclExpr 2 + 2]
   doOut [tclInvoke set x "two words"]
   doOut [tclInvoke eval set y one_word]
   doOut [tclInvoke eval {set z "three words now"}]
   doOut [set x [tclEval {set x [clock seconds]}]]
-  doOut [tclInvoke th1Eval {set y "two words"}]
-  doOut [set z [tclInvoke th1Expr {2+2}]]
+  doOut [tclInvoke bridgeEval {set y "two words"}]
+  doOut [set z [tclInvoke bridgeExpr {2+2}]]
   doOut $x
   doOut $y
   doOut $z
   doOut [tclEval set x]
   doOut [tclEval set y]
   doOut [tclEval set z]
 </th1>

Index: test/th1-tcl2.txt
==================================================================
--- test/th1-tcl2.txt
+++ test/th1-tcl2.txt
@@ -1,10 +1,10 @@
 <th1>
   #
-  # This is a "TH1 fragment" used to test the Tcl integration features of TH1.
-  # The corresponding test file executes this file using the test-th-render
-  # Fossil command.
+  # This is a "script fragment" used to test the Tcl integration features of
+  # Fossil.  The corresponding test file executes this file using the
+  # test-script-render Fossil command.
   #
   # NOTE: This test requires that the SQLite package be available for the Tcl
   #       interpreter that is linked to the Fossil executable.
   #
   tclInvoke set repository_name [repository 1]

Index: test/th1-tcl3.txt
==================================================================
--- test/th1-tcl3.txt
+++ test/th1-tcl3.txt
@@ -1,9 +1,9 @@
 <th1>
   #
-  # This is a "TH1 fragment" used to test the Tcl integration features of TH1.
-  # The corresponding test file executes this file using the test-th-render
-  # Fossil command.
+  # This is a "script fragment" used to test the Tcl integration features of
+  # Fossil.  The corresponding test file executes this file using the
+  # test-script-render Fossil command.
   #
   proc doOut {msg} {puts $msg; puts \n}
   doOut [tclEval bad_command]
 </th1>

Index: test/th1-tcl4.txt
==================================================================
--- test/th1-tcl4.txt
+++ test/th1-tcl4.txt
@@ -1,9 +1,9 @@
 <th1>
   #
-  # This is a "TH1 fragment" used to test the Tcl integration features of TH1.
-  # The corresponding test file executes this file using the test-th-render
-  # Fossil command.
+  # This is a "script fragment" used to test the Tcl integration features of
+  # Fossil.  The corresponding test file executes this file using the
+  # test-script-render Fossil command.
   #
   proc doOut {msg} {puts $msg; puts \n}
   doOut [tclExpr 2/0]
 </th1>

Index: test/th1-tcl5.txt
==================================================================
--- test/th1-tcl5.txt
+++ test/th1-tcl5.txt
@@ -1,9 +1,9 @@
 <th1>
   #
-  # This is a "TH1 fragment" used to test the Tcl integration features of TH1.
-  # The corresponding test file executes this file using the test-th-render
-  # Fossil command.
+  # This is a "script fragment" used to test the Tcl integration features of
+  # Fossil.  The corresponding test file executes this file using the
+  # test-script-render Fossil command.
   #
   proc doOut {msg} {puts $msg; puts \n}
   doOut [tclInvoke bad_command]
 </th1>

Index: test/th1-tcl6.txt
==================================================================
--- test/th1-tcl6.txt
+++ test/th1-tcl6.txt
@@ -1,9 +1,9 @@
 <th1>
   #
-  # This is a "TH1 fragment" used to test the Tcl integration features of TH1.
-  # The corresponding test file executes this file using the test-th-render
-  # Fossil command.
+  # This is a "script fragment" used to test the Tcl integration features of
+  # Fossil.  The corresponding test file executes this file using the
+  # test-script-render Fossil command.
   #
   proc doOut {msg} {puts $msg; puts \n}
-  doOut [tclEval th1Eval bad_command]
+  doOut [tclEval bridgeEval bad_command]
 </th1>

Index: test/th1-tcl7.txt
==================================================================
--- test/th1-tcl7.txt
+++ test/th1-tcl7.txt
@@ -1,19 +1,19 @@
 <th1>
   #
-  # This is a "TH1 fragment" used to test the Tcl integration features of TH1.
-  # The corresponding test file executes this file using the test-th-render
-  # Fossil command.
+  # This is a "script fragment" used to test the Tcl integration features of
+  # Fossil.  The corresponding test file executes this file using the
+  # test-script-render Fossil command.
   #
   proc doOut {msg} {puts $msg; puts \n}
 
   #
   # BUGBUG: Attempting to divide by zero will crash TH1 with the error:
   #         "child killed: floating-point exception"
   #
-  # doOut [tclEval th1Expr 2/0]
+  # doOut [tclEval bridgeExpr 2/0]
 
   #
   # NOTE: For now, just cause an expression syntax error.
   #
-  doOut [tclEval th1Expr 2**0]
+  doOut [tclEval bridgeExpr 2**0]
 </th1>

Index: test/th1-tcl8.txt
==================================================================
--- test/th1-tcl8.txt
+++ test/th1-tcl8.txt
@@ -1,14 +1,14 @@
 <th1>
   #
-  # This is a "TH1 fragment" used to test the Tcl integration features of TH1.
-  # The corresponding test file executes this file using the test-th-render
-  # Fossil command.
+  # This is a "script fragment" used to test the Tcl integration features of
+  # Fossil.  The corresponding test file executes this file using the
+  # test-script-render Fossil command.
   #
   proc doOut {msg} {puts $msg; puts \n}
 
   if {[tclInvoke set tcl_version] >= 8.6} {
     doOut [tclInvoke tailcall set x 1]
   } else {
     doOut "This test requires Tcl 8.6 or higher."
   }
 </th1>

Index: win/Makefile.PellesCGMake
==================================================================
--- win/Makefile.PellesCGMake
+++ win/Makefile.PellesCGMake
@@ -145,12 +145,12 @@
 # extracting version info from manifest
 VERSION.h:	version.exe ..\manifest.uuid ..\manifest ..\VERSION
 	version.exe ..\manifest.uuid ..\manifest ..\VERSION  > $@
 
 # generate the simplified headers
-headers: makeheaders.exe page_index.h VERSION.h ../src/sqlite3.h ../src/th.h VERSION.h
-	makeheaders.exe $(foreach ts,$(TRANSLATEDSRC),$(ts):$(ts:_.c=.h)) ../src/sqlite3.h ../src/th.h VERSION.h
+headers: makeheaders.exe page_index.h VERSION.h ../src/sqlite3.h ../src/jim.h VERSION.h
+	makeheaders.exe $(foreach ts,$(TRANSLATEDSRC),$(ts):$(ts:_.c=.h)) ../src/sqlite3.h ../src/jim.h VERSION.h
 	echo Done >$@
 
 # compile C sources with relevant options
 
 $(TRANSLATEDOBJ):	%_.obj:	%_.c %.h
@@ -160,11 +160,11 @@
 	$(CC) $(CCFLAGS) $(SQLITEDEFINES) $(INCLUDE) "$<" -Fo"$@"
 
 $(SQLITESHELLOBJ):	%.obj:	$(SRCDIR)%.c
 	$(CC) $(CCFLAGS) $(SQLITESHELLDEFINES) $(INCLUDE) "$<" -Fo"$@"
 
-$(THOBJ):	%.obj:	$(SRCDIR)%.c $(SRCDIR)th.h
+$(THOBJ):	%.obj:	$(SRCDIR)%.c $(SRCDIR)jim.h
 	$(CC) $(CCFLAGS) $(INCLUDE) "$<" -Fo"$@"
 
 $(ZLIBOBJ):	%.obj:	$(ZLIBSRCDIR)%.c
 	$(CC) $(CCFLAGS) $(INCLUDE) "$<" -Fo"$@"
 

Index: win/Makefile.dmc
==================================================================
--- win/Makefile.dmc
+++ win/Makefile.dmc
@@ -672,7 +672,8 @@
 
 zip_.c : $(SRCDIR)\zip.c
 	+translate$E $** > $@
 
 headers: makeheaders$E page_index.h VERSION.h
-	 +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
+	 +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)\sqlite3.h $(SRCDIR)\jim.h VERSION.h $(SRCDIR)\cson_amalgamation.h
 	@copy /Y nul: headers

Index: win/Makefile.mingw
==================================================================
--- win/Makefile.mingw
+++ win/Makefile.mingw
@@ -518,11 +518,11 @@
 
 
 $(OBJDIR)/page_index.h: $(TRANS_SRC) $(OBJDIR)/mkindex
 	$(MKINDEX) $(TRANS_SRC) >$@
 $(OBJDIR)/headers:	$(OBJDIR)/page_index.h $(OBJDIR)/makeheaders $(OBJDIR)/VERSION.h
-	$(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
+	$(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
 	echo Done >$(OBJDIR)/headers
 
 $(OBJDIR)/headers: Makefile
 Makefile:
 $(OBJDIR)/add_.c:	$(SRCDIR)/add.c $(OBJDIR)/translate

Index: win/Makefile.mingw.mistachkin
==================================================================
--- win/Makefile.mingw.mistachkin
+++ win/Makefile.mingw.mistachkin
@@ -489,11 +489,11 @@
 	$(TCLSH) $(SRCDIR)/../test/tester.tcl $(APPNAME)
 
 $(OBJDIR)/VERSION.h:	$(SRCDIR)/../manifest.uuid $(SRCDIR)/../manifest $(VERSION)
 	$(VERSION) $(SRCDIR)/../manifest.uuid $(SRCDIR)/../manifest $(SRCDIR)/../VERSION >$(OBJDIR)/VERSION.h
 
-EXTRAOBJ =  $(OBJDIR)/sqlite3.o  $(OBJDIR)/shell.o  $(OBJDIR)/th.o  $(OBJDIR)/th_lang.o  $(OBJDIR)/cson_amalgamation.o
+EXTRAOBJ =  $(OBJDIR)/sqlite3.o  $(OBJDIR)/shell.o  $(OBJDIR)/jimtcl.o  $(OBJDIR)/cson_amalgamation.o
 
 ifdef FOSSIL_ENABLE_TCL
 EXTRAOBJ +=  $(OBJDIR)/th_tcl.o
 endif
 
@@ -518,11 +518,11 @@
 
 
 $(OBJDIR)/page_index.h: $(TRANS_SRC) $(OBJDIR)/mkindex
 	$(MKINDEX) $(TRANS_SRC) >$@
 $(OBJDIR)/headers:	$(OBJDIR)/page_index.h $(OBJDIR)/makeheaders $(OBJDIR)/VERSION.h
-	$(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
+	$(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
 	echo Done >$(OBJDIR)/headers
 
 $(OBJDIR)/headers: Makefile
 Makefile:
 $(OBJDIR)/add_.c:	$(SRCDIR)/add.c $(OBJDIR)/translate
@@ -1192,16 +1192,13 @@
 $(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
 
 $(OBJDIR)/shell.o:	$(SRCDIR)/shell.c $(SRCDIR)/sqlite3.h
 	$(XTCC) -Dmain=sqlite3_shell -DSQLITE_OMIT_LOAD_EXTENSION=1 -c $(SRCDIR)/shell.c -o $(OBJDIR)/shell.o
 
-$(OBJDIR)/th.o:	$(SRCDIR)/th.c
-	$(XTCC) -I$(SRCDIR) -c $(SRCDIR)/th.c -o $(OBJDIR)/th.o
-
-$(OBJDIR)/th_lang.o:	$(SRCDIR)/th_lang.c
-	$(XTCC) -I$(SRCDIR) -c $(SRCDIR)/th_lang.c -o $(OBJDIR)/th_lang.o
+$(OBJDIR)/jimtcl.o:	$(SRCDIR)/../autosetup/jimsh0.c
+	$(XTCC) -I$(SRCDIR) -DJIM_BOOTSTRAP_LIB_ONLY -c $(SRCDIR)/../autosetup/jimsh0.c -o $(OBJDIR)/jimtcl.o
 
 ifdef FOSSIL_ENABLE_TCL
 $(OBJDIR)/th_tcl.o:	$(SRCDIR)/th_tcl.c
 	$(XTCC) -I$(SRCDIR) -c $(SRCDIR)/th_tcl.c -o $(OBJDIR)/th_tcl.o
 endif
 

Index: win/Makefile.msc
==================================================================
--- win/Makefile.msc
+++ win/Makefile.msc
@@ -778,7 +778,7 @@
 
 zip_.c : $(SRCDIR)\zip.c
 	translate$E $** > $@
 
 headers: makeheaders$E page_index.h VERSION.h
-	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
+	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
 	@copy /Y nul: headers