Radish alpha
H
rad:z3QDZAW2FAfuLvihrhiyDC9fAD8G9
HardenedBSD Package Manager
Radicle
Git
Update to Autosetup 7.1
Minsoo Choo committed 2 years ago
commit 1677ad25fed86b253226410b44242c006200b986
parent 8c802c5
11 files changed +6323 -4069
modified autosetup/README.autosetup
@@ -1,4 +1,4 @@
-
README.autosetup created by autosetup v0.7.0+
+
README.autosetup created by autosetup v0.7.1+

This is the autosetup directory for a local install of autosetup.
It contains autosetup, support files and loadable modules.
@@ -8,4 +8,4 @@ can be loaded with the 'use' directive.

*.auto files in this directory are auto-loaded.

-
For more information, see http://msteveb.github.com/autosetup/
+
For more information, see https://msteveb.github.io/autosetup/
modified autosetup/autosetup
@@ -6,7 +6,7 @@
dir=`dirname "$0"`; exec "`$dir/autosetup-find-tclsh`" "$0" "$@"

# Note that the version has a trailing + on unreleased versions
-
set autosetup(version) 0.7.0+
+
set autosetup(version) 0.7.1+

# Can be set to 1 to debug early-init problems
set autosetup(debug) [expr {"--debug" in $argv}]
@@ -204,19 +204,10 @@ proc main {argv} {

	autosetup_add_dep $autosetup(autodef)

-
	# Add $argv to CONFIGURE_OPTS, but ignore duplicates and quote if needed
-
	set configure_opts {}
-
	foreach arg $autosetup(argv) {
-
		set quoted [quote-if-needed $arg]
-
		# O(n^2), but n will be small
-
		if {$quoted ni $configure_opts} {
-
			lappend configure_opts $quoted
-
		}
-
	}
-
	define CONFIGURE_OPTS [join $configure_opts]
-
	define AUTOREMAKE [file-normalize $autosetup(exe)]
-
	define-append AUTOREMAKE [get-define CONFIGURE_OPTS]
-

+
	# Add $argv to CONFIGURE_OPTS
+
	define-append-argv CONFIGURE_OPTS {*}$autosetup(argv)
+
	# Set up AUTOREMAKE to reconfigure with the same args
+
	define-append-argv AUTOREMAKE {*}$autosetup(exe) {*}$autosetup(argv)

	# Log how we were invoked
	configlog "Invoked as: [getenv WRAPPER $::argv0] [quote-argv $autosetup(argv)]"
@@ -240,6 +231,8 @@ proc main {argv} {
	exit 0
}

+
# @section Option Handling
+

# @opt-bool ?-nodefault? option ...
#
# Check each of the named, boolean options and if any have been explicitly enabled
@@ -570,7 +563,7 @@ proc options-show {what} {
		}
		set max [max $max [string length $opt]]
	}
-
	set indent [string repeat " " [expr $max+4]]
+
	set indent [string repeat " " [expr {$max+4}]]
	set cols [getenv COLUMNS 80]
	catch {
		lassign [exec stty size] rows cols
@@ -596,7 +589,7 @@ proc options-show {what} {
			# Output a pre-formatted help description as-is
			puts $desc
		} else {
-
			options-wrap-desc [string trim $desc] $cols "  " $indent [expr $max + 2]
+
			options-wrap-desc [string trim $desc] $cols "  " $indent [expr {$max+2}]
		}
	}
}
@@ -691,6 +684,8 @@ proc config_sub {alias} {
	return $alias
}

+
# @section Variable Definitions (defines)
+

# @define name ?value=1?
#
# Defines the named variable to the given value.
@@ -702,6 +697,29 @@ proc define {name {value 1}} {
	#dputs "$name <= $value"
}

+
# @define-push {name ...} script
+
#
+
# Save the values of the given defines, evaluation the script, then restore.
+
# For example, to avoid updating AS_FLAGS and AS_CXXFLAGS:
+
## define-push {AS_CFLAGS AS_CXXFLAGS} {
+
##   cc-check-flags -Wno-error
+
## }
+
proc define-push {names script} {
+
	array set unset {}
+
	foreach name $names {
+
		if {[is-defined $name]} {
+
			set save($name) [get-define $name]
+
		} else {
+
			set unset($name) 1
+
		}
+
	}
+
	uplevel 1 $script
+
	array set ::define [array get save]
+
	foreach name [array names unset] {
+
		unset -nocomplain ::define($name)
+
	}
+
}
+

# @undefine name
#
# Undefine the named variable.
@@ -717,24 +735,17 @@ proc undefine {name} {
# If the variable is not defined or empty, it is set to '$value'.
# Otherwise the value is appended, separated by a space.
# Any extra values are similarly appended.
-
# If any value is already contained in the variable (as a substring) it is omitted.
+
#
+
# Note that define-append is not designed to add values containing spaces.
+
# If values may contain spaces, consider define-append-argv instead.
#
proc define-append {name args} {
	if {[get-define $name ""] ne ""} {
-
		# Avoid duplicates
		foreach arg $args {
			if {$arg eq ""} {
				continue
			}
-
			set found 0
-
			foreach str [split $::define($name) " "] {
-
				if {$str eq $arg} {
-
					incr found
-
				}
-
			}
-
			if {!$found} {
-
				append ::define($name) " " $arg
-
			}
+
			append ::define($name) " " $arg
		}
	} else {
		set ::define($name) [join $args]
@@ -742,6 +753,27 @@ proc define-append {name args} {
	#dputs "$name += [join $args] => $::define($name)"
}

+
# @define-append-argv name value ...
+
#
+
# Similar to define-append except designed to construct shell command
+
# lines, including correct handling of parameters with spaces.
+
#
+
# Each non-empty value is quoted if necessary and then appended to the given variable
+
# if it does not already exist.
+
#
+
proc define-append-argv {name args} {
+
	set seen {}
+
	set new {}
+
	foreach val [list {*}[get-define $name ""] {*}$args] {
+
		if {$val ne {} && ![dict exists $seen $val]} {
+
			lappend new [quote-if-needed $val]
+
			dict set seen $val 1
+
		}
+
	}
+
	set ::define($name) [join $new " "]
+
	#dputs "$name += [join $args] => $::define($name)"
+
}
+

# @get-define name ?default=0?
#
# Returns the current value of the "defined" variable, or '$default'
@@ -787,6 +819,7 @@ proc all-defines {} {
	array get ::define
}

+
# @section Environment/Helpers

# @get-env name default
#
@@ -870,6 +903,8 @@ proc list-non-empty {list} {
	return $result
}

+
# @section Paths, Searching
+

# @find-executable-path name
#
# Searches the path for an executable with the given name.
@@ -939,6 +974,8 @@ proc find-an-executable {args} {
	return ""
}

+
# @section Logging, Messages and Errors
+

# @configlog msg
#
# Writes the given message to the configuration log, 'config.log'.
@@ -1156,6 +1193,8 @@ proc autosetup_add_dep {filename} {
	lappend ::autosetup(deps) [file-normalize $filename]
}

+
# @section Modules Support
+

##################################################################
#
# Library module support
@@ -1453,7 +1492,7 @@ proc autosetup_help {what} {

    puts "Usage: [file tail $::autosetup(exe)] \[options\] \[settings\]\n"
    puts "This is [autosetup_version], a build environment \"autoconfigurator\""
-
    puts "See the documentation online at http://msteveb.github.com/autosetup/\n"
+
    puts "See the documentation online at https://msteveb.github.io/autosetup/\n"

    if {$what in {all local}} {
        # Need to load auto.def now
@@ -1526,7 +1565,8 @@ proc autosetup_reference {{type text}} {
    section {Introduction}

    p {
-
        See http://msteveb.github.com/autosetup/ for the online documentation for 'autosetup'
+
        See https://msteveb.github.io/autosetup/ for the online documentation for 'autosetup'.
+
        This documentation can also be accessed locally with `autosetup --ref`.
    }

    p {
@@ -1590,6 +1630,11 @@ proc automf_command_reference {} {
        while {![eof $f]} {
            set line [gets $f]

+
            if {[regexp {^#.*@section (.*)$} $line -> section]} {
+
                lappend doc($current) [list section $section]
+
				continue
+
			}
+

            # Find embedded module names
            if {[regexp {^#.*@module ([^ ]*)} $line -> modulename]} {
                continue
@@ -1604,7 +1649,7 @@ proc automf_command_reference {} {
            if {$cmd eq "synopsis:"} {
                set current $modulename
                lappend doc($current) [list section "Module: $modulename"]
-
            } else {
+
			} else {
                lappend doc($current) [list subsection $cmd]
            }

@@ -1884,6 +1929,7 @@ WRAPPER="$0"; export WRAPPER; "autosetup" "$@"
		writefile configure \
{#!/bin/sh
dir="`dirname "$0"`/autosetup"
+
#@@INITCHECK@@#
WRAPPER="$0"; export WRAPPER; exec "`"$dir/autosetup-find-tclsh"`" "$dir/autosetup" "$@"
}
	}
@@ -1930,7 +1976,7 @@ can be loaded with the 'use' directive.

*.auto files in this directory are auto-loaded.

-
For more information, see http://msteveb.github.com/autosetup/
+
For more information, see https://msteveb.github.io/autosetup/
}
	dputs "install: autosetup/README.autosetup"
	writefile $target $readme
@@ -2064,6 +2110,19 @@ if {$autosetup(istcl)} {
	proc isatty? {channel} {
		dict exists [fconfigure $channel] -xchar
	}
+
	# Jim-compatible stacktrace using info frame
+
	proc stacktrace {} {
+
		set stacktrace {}
+
		# 2 to skip the current frame
+
		for {set i 2} {$i < [info frame]} {incr i} {
+
			set frame [info frame -$i]
+
			if {[dict exists $frame file]} {
+
				# We don't need proc, so use ""
+
				lappend stacktrace "" [dict get $frame file] [dict get $frame line]
+
			}
+
		}
+
		return $stacktrace
+
	}
} else {
	if {$autosetup(iswin)} {
		# On Windows, backslash convert all environment variables
@@ -2117,16 +2176,11 @@ proc error-location {msg} {
		return -code error $msg
	}
	# Search back through the stack trace for the first error in a .def file
-
	for {set i 1} {$i < [info level]} {incr i} {
-
		if {$::autosetup(istcl)} {
-
			array set info [info frame -$i]
-
		} else {
-
			lassign [info frame -$i] info(caller) info(file) info(line)
+
	foreach {p f l} [stacktrace] {
+
		if {[string match *.def $f]} {
+
			return "[relative-path $f]:$l: Error: $msg"
		}
-
		if {[string match *.def $info(file)]} {
-
			return "[relative-path $info(file)]:$info(line): Error: $msg"
-
		}
-
		#puts "Skipping $info(file):$info(line)"
+
		#puts "Skipping $f:$l"
	}
	return $msg
}
@@ -2320,6 +2374,8 @@ set modsource(util.tcl) {

# Module which contains miscellaneous utility functions

+
# @section Utilities
+

# @compare-versions version1 version2
#
# Versions are of the form 'a.b.c' (may be any number of numeric components)
modified autosetup/autosetup-config.guess
@@ -1,8 +1,10 @@
#! /bin/sh
# Attempt to guess a canonical system name.
-
#   Copyright 1992-2018 Free Software Foundation, Inc.
+
#   Copyright 1992-2021 Free Software Foundation, Inc.

-
timestamp='2018-03-08'
+
# shellcheck disable=SC2006,SC2268 # see below for rationale
+

+
timestamp='2021-06-03'

# This file is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
@@ -27,11 +29,19 @@ timestamp='2018-03-08'
# Originally written by Per Bothner; maintained since 2000 by Ben Elliston.
#
# You can get the latest version of this script from:
-
# https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess
+
# https://git.savannah.gnu.org/cgit/config.git/plain/config.guess
#
# Please send patches to <config-patches@gnu.org>.


+
# The "shellcheck disable" line above the timestamp inhibits complaints
+
# about features and limitations of the classic Bourne shell that were
+
# superseded or lifted in POSIX.  However, this script identifies a wide
+
# variety of pre-POSIX systems that do not have POSIX shells at all, and
+
# even some reasonably current systems (Solaris 10 as case-in-point) still
+
# have a pre-POSIX /bin/sh.
+

+

me=`echo "$0" | sed -e 's,.*/,,'`

usage="\
@@ -50,7 +60,7 @@ version="\
GNU config.guess ($timestamp)

Originally written by Per Bothner.
-
Copyright 1992-2018 Free Software Foundation, Inc.
+
Copyright 1992-2021 Free Software Foundation, Inc.

This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
@@ -84,7 +94,8 @@ if test $# != 0; then
  exit 1
fi

-
trap 'exit 1' 1 2 15
+
# Just in case it came from the environment.
+
GUESS=

# CC_FOR_BUILD -- compiler used by this script. Note that the use of a
# compiler to aid in system detection is discouraged as it requires
@@ -96,73 +107,90 @@ trap 'exit 1' 1 2 15

# Portable tmp directory creation inspired by the Autoconf team.

-
set_cc_for_build='
-
trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ;
-
trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ;
-
: ${TMPDIR=/tmp} ;
-
 { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } ||
-
 { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } ||
-
 { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } ||
-
 { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ;
-
dummy=$tmp/dummy ;
-
tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ;
-
case $CC_FOR_BUILD,$HOST_CC,$CC in
-
 ,,)    echo "int x;" > "$dummy.c" ;
-
	for c in cc gcc c89 c99 ; do
-
	  if ($c -c -o "$dummy.o" "$dummy.c") >/dev/null 2>&1 ; then
-
	     CC_FOR_BUILD="$c"; break ;
-
	  fi ;
-
	done ;
-
	if test x"$CC_FOR_BUILD" = x ; then
-
	  CC_FOR_BUILD=no_compiler_found ;
-
	fi
-
	;;
-
 ,,*)   CC_FOR_BUILD=$CC ;;
-
 ,*,*)  CC_FOR_BUILD=$HOST_CC ;;
-
esac ; set_cc_for_build= ;'
+
tmp=
+
# shellcheck disable=SC2172
+
trap 'test -z "$tmp" || rm -fr "$tmp"' 0 1 2 13 15
+

+
set_cc_for_build() {
+
    # prevent multiple calls if $tmp is already set
+
    test "$tmp" && return 0
+
    : "${TMPDIR=/tmp}"
+
    # shellcheck disable=SC2039,SC3028
+
    { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } ||
+
	{ test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir "$tmp" 2>/dev/null) ; } ||
+
	{ tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir "$tmp" 2>/dev/null) && echo "Warning: creating insecure temp directory" >&2 ; } ||
+
	{ echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; }
+
    dummy=$tmp/dummy
+
    case ${CC_FOR_BUILD-},${HOST_CC-},${CC-} in
+
	,,)    echo "int x;" > "$dummy.c"
+
	       for driver in cc gcc c89 c99 ; do
+
		   if ($driver -c -o "$dummy.o" "$dummy.c") >/dev/null 2>&1 ; then
+
		       CC_FOR_BUILD=$driver
+
		       break
+
		   fi
+
	       done
+
	       if test x"$CC_FOR_BUILD" = x ; then
+
		   CC_FOR_BUILD=no_compiler_found
+
	       fi
+
	       ;;
+
	,,*)   CC_FOR_BUILD=$CC ;;
+
	,*,*)  CC_FOR_BUILD=$HOST_CC ;;
+
    esac
+
}

# This is needed to find uname on a Pyramid OSx when run in the BSD universe.
# (ghazi@noc.rutgers.edu 1994-08-24)
-
if (test -f /.attbin/uname) >/dev/null 2>&1 ; then
+
if test -f /.attbin/uname ; then
	PATH=$PATH:/.attbin ; export PATH
fi

UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown
UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
-
UNAME_SYSTEM=`(uname -s) 2>/dev/null`  || UNAME_SYSTEM=unknown
+
UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown
UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown

-
case "$UNAME_SYSTEM" in
+
case $UNAME_SYSTEM in
Linux|GNU|GNU/*)
-
	# If the system lacks a compiler, then just pick glibc.
-
	# We could probably try harder.
-
	LIBC=gnu
+
	LIBC=unknown

-
	eval "$set_cc_for_build"
+
	set_cc_for_build
	cat <<-EOF > "$dummy.c"
	#include <features.h>
	#if defined(__UCLIBC__)
	LIBC=uclibc
	#elif defined(__dietlibc__)
	LIBC=dietlibc
-
	#else
+
	#elif defined(__GLIBC__)
	LIBC=gnu
+
	#else
+
	#include <stdarg.h>
+
	/* First heuristic to detect musl libc.  */
+
	#ifdef __DEFINED_va_list
+
	LIBC=musl
+
	#endif
	#endif
	EOF
-
	eval "`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^LIBC' | sed 's, ,,g'`"
+
	cc_set_libc=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^LIBC' | sed 's, ,,g'`
+
	eval "$cc_set_libc"

-
	# If ldd exists, use it to detect musl libc.
-
	if command -v ldd >/dev/null && \
-
		ldd --version 2>&1 | grep -q ^musl
-
	then
-
	    LIBC=musl
+
	# Second heuristic to detect musl libc.
+
	if [ "$LIBC" = unknown ] &&
+
	   command -v ldd >/dev/null &&
+
	   ldd --version 2>&1 | grep -q ^musl; then
+
		LIBC=musl
+
	fi
+

+
	# If the system lacks a compiler, then just pick glibc.
+
	# We could probably try harder.
+
	if [ "$LIBC" = unknown ]; then
+
		LIBC=gnu
	fi
	;;
esac

# Note: order is significant - the case branches are not exclusive.

-
case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in
+
case $UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION in
    *:NetBSD:*:*)
	# NetBSD (nbsd) targets should (where applicable) match one or
	# more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*,
@@ -174,12 +202,12 @@ case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in
	#
	# Note: NetBSD doesn't particularly care about the vendor
	# portion of the name.  We always set it to "unknown".
-
	sysctl="sysctl -n hw.machine_arch"
	UNAME_MACHINE_ARCH=`(uname -p 2>/dev/null || \
-
	    "/sbin/$sysctl" 2>/dev/null || \
-
	    "/usr/sbin/$sysctl" 2>/dev/null || \
+
	    /sbin/sysctl -n hw.machine_arch 2>/dev/null || \
+
	    /usr/sbin/sysctl -n hw.machine_arch 2>/dev/null || \
	    echo unknown)`
-
	case "$UNAME_MACHINE_ARCH" in
+
	case $UNAME_MACHINE_ARCH in
+
	    aarch64eb) machine=aarch64_be-unknown ;;
	    armeb) machine=armeb-unknown ;;
	    arm*) machine=arm-unknown ;;
	    sh3el) machine=shl-unknown ;;
@@ -188,18 +216,18 @@ case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in
	    earmv*)
		arch=`echo "$UNAME_MACHINE_ARCH" | sed -e 's,^e\(armv[0-9]\).*$,\1,'`
		endian=`echo "$UNAME_MACHINE_ARCH" | sed -ne 's,^.*\(eb\)$,\1,p'`
-
		machine="${arch}${endian}"-unknown
+
		machine=${arch}${endian}-unknown
		;;
-
	    *) machine="$UNAME_MACHINE_ARCH"-unknown ;;
+
	    *) machine=$UNAME_MACHINE_ARCH-unknown ;;
	esac
	# The Operating System including object format, if it has switched
	# to ELF recently (or will in the future) and ABI.
-
	case "$UNAME_MACHINE_ARCH" in
+
	case $UNAME_MACHINE_ARCH in
	    earm*)
		os=netbsdelf
		;;
	    arm*|i386|m68k|ns32k|sh3*|sparc|vax)
-
		eval "$set_cc_for_build"
+
		set_cc_for_build
		if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \
			| grep -q __ELF__
		then
@@ -215,7 +243,7 @@ case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in
		;;
	esac
	# Determine ABI tags.
-
	case "$UNAME_MACHINE_ARCH" in
+
	case $UNAME_MACHINE_ARCH in
	    earm*)
		expr='s/^earmv[0-9]/-eabi/;s/eb$//'
		abi=`echo "$UNAME_MACHINE_ARCH" | sed -e "$expr"`
@@ -226,7 +254,7 @@ case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in
	# thus, need a distinct triplet. However, they do not need
	# kernel version information, so it can be replaced with a
	# suitable tag, in the style of linux-gnu.
-
	case "$UNAME_VERSION" in
+
	case $UNAME_VERSION in
	    Debian*)
		release='-gnu'
		;;
@@ -237,45 +265,57 @@ case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in
	# Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM:
	# contains redundant information, the shorter form:
	# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used.
-
	echo "$machine-${os}${release}${abi}"
-
	exit ;;
+
	GUESS=$machine-${os}${release}${abi-}
+
	;;
    *:Bitrig:*:*)
	UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'`
-
	echo "$UNAME_MACHINE_ARCH"-unknown-bitrig"$UNAME_RELEASE"
-
	exit ;;
+
	GUESS=$UNAME_MACHINE_ARCH-unknown-bitrig$UNAME_RELEASE
+
	;;
    *:OpenBSD:*:*)
	UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'`
-
	echo "$UNAME_MACHINE_ARCH"-unknown-openbsd"$UNAME_RELEASE"
-
	exit ;;
+
	GUESS=$UNAME_MACHINE_ARCH-unknown-openbsd$UNAME_RELEASE
+
	;;
+
    *:SecBSD:*:*)
+
	UNAME_MACHINE_ARCH=`arch | sed 's/SecBSD.//'`
+
	GUESS=$UNAME_MACHINE_ARCH-unknown-secbsd$UNAME_RELEASE
+
	;;
    *:LibertyBSD:*:*)
	UNAME_MACHINE_ARCH=`arch | sed 's/^.*BSD\.//'`
-
	echo "$UNAME_MACHINE_ARCH"-unknown-libertybsd"$UNAME_RELEASE"
-
	exit ;;
+
	GUESS=$UNAME_MACHINE_ARCH-unknown-libertybsd$UNAME_RELEASE
+
	;;
    *:MidnightBSD:*:*)
-
	echo "$UNAME_MACHINE"-unknown-midnightbsd"$UNAME_RELEASE"
-
	exit ;;
+
	GUESS=$UNAME_MACHINE-unknown-midnightbsd$UNAME_RELEASE
+
	;;
    *:ekkoBSD:*:*)
-
	echo "$UNAME_MACHINE"-unknown-ekkobsd"$UNAME_RELEASE"
-
	exit ;;
+
	GUESS=$UNAME_MACHINE-unknown-ekkobsd$UNAME_RELEASE
+
	;;
    *:SolidBSD:*:*)
-
	echo "$UNAME_MACHINE"-unknown-solidbsd"$UNAME_RELEASE"
-
	exit ;;
+
	GUESS=$UNAME_MACHINE-unknown-solidbsd$UNAME_RELEASE
+
	;;
+
    *:OS108:*:*)
+
	GUESS=$UNAME_MACHINE-unknown-os108_$UNAME_RELEASE
+
	;;
    macppc:MirBSD:*:*)
-
	echo powerpc-unknown-mirbsd"$UNAME_RELEASE"
-
	exit ;;
+
	GUESS=powerpc-unknown-mirbsd$UNAME_RELEASE
+
	;;
    *:MirBSD:*:*)
-
	echo "$UNAME_MACHINE"-unknown-mirbsd"$UNAME_RELEASE"
-
	exit ;;
+
	GUESS=$UNAME_MACHINE-unknown-mirbsd$UNAME_RELEASE
+
	;;
    *:Sortix:*:*)
-
	echo "$UNAME_MACHINE"-unknown-sortix
-
	exit ;;
+
	GUESS=$UNAME_MACHINE-unknown-sortix
+
	;;
+
    *:Twizzler:*:*)
+
	GUESS=$UNAME_MACHINE-unknown-twizzler
+
	;;
    *:Redox:*:*)
-
	echo "$UNAME_MACHINE"-unknown-redox
-
	exit ;;
+
	GUESS=$UNAME_MACHINE-unknown-redox
+
	;;
    mips:OSF1:*.*)
-
        echo mips-dec-osf1
-
        exit ;;
+
	GUESS=mips-dec-osf1
+
	;;
    alpha:OSF1:*:*)
+
	# Reset EXIT trap before exiting to avoid spurious non-zero exit code.
+
	trap '' 0
	case $UNAME_RELEASE in
	*4.0)
		UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`
@@ -289,7 +329,7 @@ case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in
	# covers most systems running today.  This code pipes the CPU
	# types through head -n 1, so we only detect the type of CPU 0.
	ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^  The alpha \(.*\) processor.*$/\1/p' | head -n 1`
-
	case "$ALPHA_CPU_TYPE" in
+
	case $ALPHA_CPU_TYPE in
	    "EV4 (21064)")
		UNAME_MACHINE=alpha ;;
	    "EV4.5 (21064)")
@@ -326,75 +366,76 @@ case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in
	# A Tn.n version is a released field test version.
	# A Xn.n version is an unreleased experimental baselevel.
	# 1.2 uses "1.2" for uname -r.
-
	echo "$UNAME_MACHINE"-dec-osf"`echo "$UNAME_RELEASE" | sed -e 's/^[PVTX]//' | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz`"
-
	# Reset EXIT trap before exiting to avoid spurious non-zero exit code.
-
	exitcode=$?
-
	trap '' 0
-
	exit $exitcode ;;
+
	OSF_REL=`echo "$UNAME_RELEASE" | sed -e 's/^[PVTX]//' | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz`
+
	GUESS=$UNAME_MACHINE-dec-osf$OSF_REL
+
	;;
    Amiga*:UNIX_System_V:4.0:*)
-
	echo m68k-unknown-sysv4
-
	exit ;;
+
	GUESS=m68k-unknown-sysv4
+
	;;
    *:[Aa]miga[Oo][Ss]:*:*)
-
	echo "$UNAME_MACHINE"-unknown-amigaos
-
	exit ;;
+
	GUESS=$UNAME_MACHINE-unknown-amigaos
+
	;;
    *:[Mm]orph[Oo][Ss]:*:*)
-
	echo "$UNAME_MACHINE"-unknown-morphos
-
	exit ;;
+
	GUESS=$UNAME_MACHINE-unknown-morphos
+
	;;
    *:OS/390:*:*)
-
	echo i370-ibm-openedition
-
	exit ;;
+
	GUESS=i370-ibm-openedition
+
	;;
    *:z/VM:*:*)
-
	echo s390-ibm-zvmoe
-
	exit ;;
+
	GUESS=s390-ibm-zvmoe
+
	;;
    *:OS400:*:*)
-
	echo powerpc-ibm-os400
-
	exit ;;
+
	GUESS=powerpc-ibm-os400
+
	;;
    arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
-
	echo arm-acorn-riscix"$UNAME_RELEASE"
-
	exit ;;
+
	GUESS=arm-acorn-riscix$UNAME_RELEASE
+
	;;
    arm*:riscos:*:*|arm*:RISCOS:*:*)
-
	echo arm-unknown-riscos
-
	exit ;;
+
	GUESS=arm-unknown-riscos
+
	;;
    SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*)
-
	echo hppa1.1-hitachi-hiuxmpp
-
	exit ;;
+
	GUESS=hppa1.1-hitachi-hiuxmpp
+
	;;
    Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*)
	# akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE.
-
	if test "`(/bin/universe) 2>/dev/null`" = att ; then
-
		echo pyramid-pyramid-sysv3
-
	else
-
		echo pyramid-pyramid-bsd
-
	fi
-
	exit ;;
+
	case `(/bin/universe) 2>/dev/null` in
+
	    att) GUESS=pyramid-pyramid-sysv3 ;;
+
	    *)   GUESS=pyramid-pyramid-bsd   ;;
+
	esac
+
	;;
    NILE*:*:*:dcosx)
-
	echo pyramid-pyramid-svr4
-
	exit ;;
+
	GUESS=pyramid-pyramid-svr4
+
	;;
    DRS?6000:unix:4.0:6*)
-
	echo sparc-icl-nx6
-
	exit ;;
+
	GUESS=sparc-icl-nx6
+
	;;
    DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*)
	case `/usr/bin/uname -p` in
-
	    sparc) echo sparc-icl-nx7; exit ;;
-
	esac ;;
+
	    sparc) GUESS=sparc-icl-nx7 ;;
+
	esac
+
	;;
    s390x:SunOS:*:*)
-
	echo "$UNAME_MACHINE"-ibm-solaris2"`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'`"
-
	exit ;;
+
	SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'`
+
	GUESS=$UNAME_MACHINE-ibm-solaris2$SUN_REL
+
	;;
    sun4H:SunOS:5.*:*)
-
	echo sparc-hal-solaris2"`echo "$UNAME_RELEASE"|sed -e 's/[^.]*//'`"
-
	exit ;;
+
	SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'`
+
	GUESS=sparc-hal-solaris2$SUN_REL
+
	;;
    sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
-
	echo sparc-sun-solaris2"`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'`"
-
	exit ;;
+
	SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'`
+
	GUESS=sparc-sun-solaris2$SUN_REL
+
	;;
    i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*)
-
	echo i386-pc-auroraux"$UNAME_RELEASE"
-
	exit ;;
+
	GUESS=i386-pc-auroraux$UNAME_RELEASE
+
	;;
    i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*)
-
	eval "$set_cc_for_build"
+
	set_cc_for_build
	SUN_ARCH=i386
	# If there is a compiler, see if it is configured for 64-bit objects.
	# Note that the Sun cc does not turn __LP64__ into 1 like gcc does.
	# This test works for both compilers.
-
	if [ "$CC_FOR_BUILD" != no_compiler_found ]; then
+
	if test "$CC_FOR_BUILD" != no_compiler_found; then
	    if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \
		(CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \
		grep IS_64BIT_ARCH >/dev/null
@@ -402,41 +443,44 @@ case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in
		SUN_ARCH=x86_64
	    fi
	fi
-
	echo "$SUN_ARCH"-pc-solaris2"`echo "$UNAME_RELEASE"|sed -e 's/[^.]*//'`"
-
	exit ;;
+
	SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'`
+
	GUESS=$SUN_ARCH-pc-solaris2$SUN_REL
+
	;;
    sun4*:SunOS:6*:*)
	# According to config.sub, this is the proper way to canonicalize
	# SunOS6.  Hard to guess exactly what SunOS6 will be like, but
	# it's likely to be more like Solaris than SunOS4.
-
	echo sparc-sun-solaris3"`echo "$UNAME_RELEASE"|sed -e 's/[^.]*//'`"
-
	exit ;;
+
	SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'`
+
	GUESS=sparc-sun-solaris3$SUN_REL
+
	;;
    sun4*:SunOS:*:*)
-
	case "`/usr/bin/arch -k`" in
+
	case `/usr/bin/arch -k` in
	    Series*|S4*)
		UNAME_RELEASE=`uname -v`
		;;
	esac
	# Japanese Language versions have a version number like `4.1.3-JL'.
-
	echo sparc-sun-sunos"`echo "$UNAME_RELEASE"|sed -e 's/-/_/'`"
-
	exit ;;
+
	SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/-/_/'`
+
	GUESS=sparc-sun-sunos$SUN_REL
+
	;;
    sun3*:SunOS:*:*)
-
	echo m68k-sun-sunos"$UNAME_RELEASE"
-
	exit ;;
+
	GUESS=m68k-sun-sunos$UNAME_RELEASE
+
	;;
    sun*:*:4.2BSD:*)
	UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
	test "x$UNAME_RELEASE" = x && UNAME_RELEASE=3
-
	case "`/bin/arch`" in
+
	case `/bin/arch` in
	    sun3)
-
		echo m68k-sun-sunos"$UNAME_RELEASE"
+
		GUESS=m68k-sun-sunos$UNAME_RELEASE
		;;
	    sun4)
-
		echo sparc-sun-sunos"$UNAME_RELEASE"
+
		GUESS=sparc-sun-sunos$UNAME_RELEASE
		;;
	esac
-
	exit ;;
+
	;;
    aushp:SunOS:*:*)
-
	echo sparc-auspex-sunos"$UNAME_RELEASE"
-
	exit ;;
+
	GUESS=sparc-auspex-sunos$UNAME_RELEASE
+
	;;
    # The situation for MiNT is a little confusing.  The machine name
    # can be virtually everything (everything which is not
    # "atarist" or "atariste" at least should have a processor
@@ -446,43 +490,43 @@ case "$UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION" in
    # MiNT.  But MiNT is downward compatible to TOS, so this should
    # be no problem.
    atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*)
-
	echo m68k-atari-mint"$UNAME_RELEASE"
-
	exit ;;
+
	GUESS=m68k-atari-mint$UNAME_RELEASE
+
	;;
    atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*)
-
	echo m68k-atari-mint"$UNAME_RELEASE"
-
	exit ;;
+
	GUESS=m68k-atari-mint$UNAME_RELEASE
+
	;;
    *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*)
-
	echo m68k-atari-mint"$UNAME_RELEASE"
-
	exit ;;
+
	GUESS=m68k-atari-mint$UNAME_RELEASE
+
	;;
    milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*)
-
	echo m68k-milan-mint"$UNAME_RELEASE"
-
	exit ;;
+
	GUESS=m68k-milan-mint$UNAME_RELEASE
+
	;;
    hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*)
-
	echo m68k-hades-mint"$UNAME_RELEASE"
-
	exit ;;
+
	GUESS=m68k-hades-mint$UNAME_RELEASE
+
	;;
    *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*)
-
	echo m68k-unknown-mint"$UNAME_RELEASE"
-
	exit ;;
+
	GUESS=m68k-unknown-mint$UNAME_RELEASE
+
	;;
    m68k:machten:*:*)
-
	echo m68k-apple-machten"$UNAME_RELEASE"
-
	exit ;;
+
	GUESS=m68k-apple-machten$UNAME_RELEASE
+
	;;
    powerpc:machten:*:*)
-
	echo powerpc-apple-machten"$UNAME_RELEASE"
-
	exit ;;
+
	GUESS=powerpc-apple-machten$UNAME_RELEASE
+
	;;
    RISC*:Mach:*:*)
-
	echo mips-dec-mach_bsd4.3
-
	exit ;;
+
	GUESS=mips-dec-mach_bsd4.3
+
	;;
    RISC*:ULTRIX:*:*)
-
	echo mips-dec-ultrix"$UNAME_RELEASE"
-
	exit ;;
+
	GUESS=mips-dec-ultrix$UNAME_RELEASE
+
	;;
    VAX*:ULTRIX*:*:*)
-
	echo vax-dec-ultrix"$UNAME_RELEASE"
-
	exit ;;
+
	GUESS=vax-dec-ultrix$UNAME_RELEASE
+
	;;
    2020:CLIX:*:* | 2430:CLIX:*:*)
-
	echo clipper-intergraph-clix"$UNAME_RELEASE"
-
	exit ;;
+
	GUESS=clipper-intergraph-clix$UNAME_RELEASE
+
	;;
    mips:*:*:UMIPS | mips:*:*:RISCos)
-
	eval "$set_cc_for_build"
+
	set_cc_for_build
	sed 's/^	//' << EOF > "$dummy.c"
#ifdef __cplusplus
#include <stdio.h>  /* for printf() prototype */
@@ -508,78 +552,79 @@ EOF
	  dummyarg=`echo "$UNAME_RELEASE" | sed -n 's/\([0-9]*\).*/\1/p'` &&
	  SYSTEM_NAME=`"$dummy" "$dummyarg"` &&
	    { echo "$SYSTEM_NAME"; exit; }
-
	echo mips-mips-riscos"$UNAME_RELEASE"
-
	exit ;;
+
	GUESS=mips-mips-riscos$UNAME_RELEASE
+
	;;
    Motorola:PowerMAX_OS:*:*)
-
	echo powerpc-motorola-powermax
-
	exit ;;
+
	GUESS=powerpc-motorola-powermax
+
	;;
    Motorola:*:4.3:PL8-*)
-
	echo powerpc-harris-powermax
-
	exit ;;
+
	GUESS=powerpc-harris-powermax
+
	;;
    Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*)
-
	echo powerpc-harris-powermax
-
	exit ;;
+
	GUESS=powerpc-harris-powermax
+
	;;
    Night_Hawk:Power_UNIX:*:*)
-
	echo powerpc-harris-powerunix
-
	exit ;;
+
	GUESS=powerpc-harris-powerunix
+
	;;
    m88k:CX/UX:7*:*)
-
	echo m88k-harris-cxux7
-
	exit ;;
+
	GUESS=m88k-harris-cxux7
+
	;;
    m88k:*:4*:R4*)
-
	echo m88k-motorola-sysv4
-
	exit ;;
+
	GUESS=m88k-motorola-sysv4
+
	;;
    m88k:*:3*:R3*)
-
	echo m88k-motorola-sysv3
-
	exit ;;
+
	GUESS=m88k-motorola-sysv3
+
	;;
    AViiON:dgux:*:*)
	# DG/UX returns AViiON for all architectures
	UNAME_PROCESSOR=`/usr/bin/uname -p`
-
	if [ "$UNAME_PROCESSOR" = mc88100 ] || [ "$UNAME_PROCESSOR" = mc88110 ]
+
	if test "$UNAME_PROCESSOR" = mc88100 || test "$UNAME_PROCESSOR" = mc88110
	then
-
	    if [ "$TARGET_BINARY_INTERFACE"x = m88kdguxelfx ] || \
-
	       [ "$TARGET_BINARY_INTERFACE"x = x ]
+
	    if test "$TARGET_BINARY_INTERFACE"x = m88kdguxelfx || \
+
	       test "$TARGET_BINARY_INTERFACE"x = x
	    then
-
		echo m88k-dg-dgux"$UNAME_RELEASE"
+
		GUESS=m88k-dg-dgux$UNAME_RELEASE
	    else
-
		echo m88k-dg-dguxbcs"$UNAME_RELEASE"
+
		GUESS=m88k-dg-dguxbcs$UNAME_RELEASE
	    fi
	else
-
	    echo i586-dg-dgux"$UNAME_RELEASE"
+
	    GUESS=i586-dg-dgux$UNAME_RELEASE
	fi
-
	exit ;;
+
	;;
    M88*:DolphinOS:*:*)	# DolphinOS (SVR3)
-
	echo m88k-dolphin-sysv3
-
	exit ;;
+
	GUESS=m88k-dolphin-sysv3
+
	;;
    M88*:*:R3*:*)
	# Delta 88k system running SVR3
-
	echo m88k-motorola-sysv3
-
	exit ;;
+
	GUESS=m88k-motorola-sysv3
+
	;;
    XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3)
-
	echo m88k-tektronix-sysv3
-
	exit ;;
+
	GUESS=m88k-tektronix-sysv3
+
	;;
    Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD)
-
	echo m68k-tektronix-bsd
-
	exit ;;
+
	GUESS=m68k-tektronix-bsd
+
	;;
    *:IRIX*:*:*)
-
	echo mips-sgi-irix"`echo "$UNAME_RELEASE"|sed -e 's/-/_/g'`"
-
	exit ;;
+
	IRIX_REL=`echo "$UNAME_RELEASE" | sed -e 's/-/_/g'`
+
	GUESS=mips-sgi-irix$IRIX_REL
+
	;;
    ????????:AIX?:[12].1:2)   # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX.
-
	echo romp-ibm-aix     # uname -m gives an 8 hex-code CPU id
-
	exit ;;               # Note that: echo "'`uname -s`'" gives 'AIX '
+
	GUESS=romp-ibm-aix    # uname -m gives an 8 hex-code CPU id
+
	;;                    # Note that: echo "'`uname -s`'" gives 'AIX '
    i*86:AIX:*:*)
-
	echo i386-ibm-aix
-
	exit ;;
+
	GUESS=i386-ibm-aix
+
	;;
    ia64:AIX:*:*)
-
	if [ -x /usr/bin/oslevel ] ; then
+
	if test -x /usr/bin/oslevel ; then
		IBM_REV=`/usr/bin/oslevel`
	else
-
		IBM_REV="$UNAME_VERSION.$UNAME_RELEASE"
+
		IBM_REV=$UNAME_VERSION.$UNAME_RELEASE
	fi
-
	echo "$UNAME_MACHINE"-ibm-aix"$IBM_REV"
-
	exit ;;
+
	GUESS=$UNAME_MACHINE-ibm-aix$IBM_REV
+
	;;
    *:AIX:2:3)
	if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
-
		eval "$set_cc_for_build"
+
		set_cc_for_build
		sed 's/^		//' << EOF > "$dummy.c"
		#include <sys/systemcfg.h>

@@ -593,16 +638,16 @@ EOF
EOF
		if $CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=`"$dummy"`
		then
-
			echo "$SYSTEM_NAME"
+
			GUESS=$SYSTEM_NAME
		else
-
			echo rs6000-ibm-aix3.2.5
+
			GUESS=rs6000-ibm-aix3.2.5
		fi
	elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then
-
		echo rs6000-ibm-aix3.2.4
+
		GUESS=rs6000-ibm-aix3.2.4
	else
-
		echo rs6000-ibm-aix3.2
+
		GUESS=rs6000-ibm-aix3.2
	fi
-
	exit ;;
+
	;;
    *:AIX:*:[4567])
	IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'`
	if /usr/sbin/lsattr -El "$IBM_CPU_ID" | grep ' POWER' >/dev/null 2>&1; then
@@ -610,57 +655,57 @@ EOF
	else
		IBM_ARCH=powerpc
	fi
-
	if [ -x /usr/bin/lslpp ] ; then
-
		IBM_REV=`/usr/bin/lslpp -Lqc bos.rte.libc |
+
	if test -x /usr/bin/lslpp ; then
+
		IBM_REV=`/usr/bin/lslpp -Lqc bos.rte.libc | \
			   awk -F: '{ print $3 }' | sed s/[0-9]*$/0/`
	else
-
		IBM_REV="$UNAME_VERSION.$UNAME_RELEASE"
+
		IBM_REV=$UNAME_VERSION.$UNAME_RELEASE
	fi
-
	echo "$IBM_ARCH"-ibm-aix"$IBM_REV"
-
	exit ;;
+
	GUESS=$IBM_ARCH-ibm-aix$IBM_REV
+
	;;
    *:AIX:*:*)
-
	echo rs6000-ibm-aix
-
	exit ;;
+
	GUESS=rs6000-ibm-aix
+
	;;
    ibmrt:4.4BSD:*|romp-ibm:4.4BSD:*)
-
	echo romp-ibm-bsd4.4
-
	exit ;;
+
	GUESS=romp-ibm-bsd4.4
+
	;;
    ibmrt:*BSD:*|romp-ibm:BSD:*)            # covers RT/PC BSD and
-
	echo romp-ibm-bsd"$UNAME_RELEASE"   # 4.3 with uname added to
-
	exit ;;                             # report: romp-ibm BSD 4.3
+
	GUESS=romp-ibm-bsd$UNAME_RELEASE    # 4.3 with uname added to
+
	;;                                  # report: romp-ibm BSD 4.3
    *:BOSX:*:*)
-
	echo rs6000-bull-bosx
-
	exit ;;
+
	GUESS=rs6000-bull-bosx
+
	;;
    DPX/2?00:B.O.S.:*:*)
-
	echo m68k-bull-sysv3
-
	exit ;;
+
	GUESS=m68k-bull-sysv3
+
	;;
    9000/[34]??:4.3bsd:1.*:*)
-
	echo m68k-hp-bsd
-
	exit ;;
+
	GUESS=m68k-hp-bsd
+
	;;
    hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*)
-
	echo m68k-hp-bsd4.4
-
	exit ;;
+
	GUESS=m68k-hp-bsd4.4
+
	;;
    9000/[34678]??:HP-UX:*:*)
-
	HPUX_REV=`echo "$UNAME_RELEASE"|sed -e 's/[^.]*.[0B]*//'`
-
	case "$UNAME_MACHINE" in
+
	HPUX_REV=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*.[0B]*//'`
+
	case $UNAME_MACHINE in
	    9000/31?)            HP_ARCH=m68000 ;;
	    9000/[34]??)         HP_ARCH=m68k ;;
	    9000/[678][0-9][0-9])
-
		if [ -x /usr/bin/getconf ]; then
+
		if test -x /usr/bin/getconf; then
		    sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null`
		    sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null`
-
		    case "$sc_cpu_version" in
+
		    case $sc_cpu_version in
		      523) HP_ARCH=hppa1.0 ;; # CPU_PA_RISC1_0
		      528) HP_ARCH=hppa1.1 ;; # CPU_PA_RISC1_1
		      532)                      # CPU_PA_RISC2_0
-
			case "$sc_kernel_bits" in
+
			case $sc_kernel_bits in
			  32) HP_ARCH=hppa2.0n ;;
			  64) HP_ARCH=hppa2.0w ;;
			  '') HP_ARCH=hppa2.0 ;;   # HP-UX 10.20
			esac ;;
		    esac
		fi
-
		if [ "$HP_ARCH" = "" ]; then
-
		    eval "$set_cc_for_build"
+
		if test "$HP_ARCH" = ""; then
+
		    set_cc_for_build
		    sed 's/^		//' << EOF > "$dummy.c"

		#define _HPUX_SOURCE
@@ -698,9 +743,9 @@ EOF
		    test -z "$HP_ARCH" && HP_ARCH=hppa
		fi ;;
	esac
-
	if [ "$HP_ARCH" = hppa2.0w ]
+
	if test "$HP_ARCH" = hppa2.0w
	then
-
	    eval "$set_cc_for_build"
+
	    set_cc_for_build

	    # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating
	    # 32-bit code.  hppa64-hp-hpux* has the same kernel and a compiler
@@ -719,14 +764,14 @@ EOF
		HP_ARCH=hppa64
	    fi
	fi
-
	echo "$HP_ARCH"-hp-hpux"$HPUX_REV"
-
	exit ;;
+
	GUESS=$HP_ARCH-hp-hpux$HPUX_REV
+
	;;
    ia64:HP-UX:*:*)
-
	HPUX_REV=`echo "$UNAME_RELEASE"|sed -e 's/[^.]*.[0B]*//'`
-
	echo ia64-hp-hpux"$HPUX_REV"
-
	exit ;;
+
	HPUX_REV=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*.[0B]*//'`
+
	GUESS=ia64-hp-hpux$HPUX_REV
+
	;;
    3050*:HI-UX:*:*)
-
	eval "$set_cc_for_build"
+
	set_cc_for_build
	sed 's/^	//' << EOF > "$dummy.c"
	#include <unistd.h>
	int
@@ -754,36 +799,36 @@ EOF
EOF
	$CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=`"$dummy"` &&
		{ echo "$SYSTEM_NAME"; exit; }
-
	echo unknown-hitachi-hiuxwe2
-
	exit ;;
+
	GUESS=unknown-hitachi-hiuxwe2
+
	;;
    9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:*)
-
	echo hppa1.1-hp-bsd
-
	exit ;;
+
	GUESS=hppa1.1-hp-bsd
+
	;;
    9000/8??:4.3bsd:*:*)
-
	echo hppa1.0-hp-bsd
-
	exit ;;
+
	GUESS=hppa1.0-hp-bsd
+
	;;
    *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*)
-
	echo hppa1.0-hp-mpeix
-
	exit ;;
+
	GUESS=hppa1.0-hp-mpeix
+
	;;
    hp7??:OSF1:*:* | hp8?[79]:OSF1:*:*)
-
	echo hppa1.1-hp-osf
-
	exit ;;
+
	GUESS=hppa1.1-hp-osf
+
	;;
    hp8??:OSF1:*:*)
-
	echo hppa1.0-hp-osf
-
	exit ;;
+
	GUESS=hppa1.0-hp-osf
+
	;;
    i*86:OSF1:*:*)
-
	if [ -x /usr/sbin/sysversion ] ; then
-
	    echo "$UNAME_MACHINE"-unknown-osf1mk
+
	if test -x /usr/sbin/sysversion ; then
+
	    GUESS=$UNAME_MACHINE-unknown-osf1mk
	else
-
	    echo "$UNAME_MACHINE"-unknown-osf1
+
	    GUESS=$UNAME_MACHINE-unknown-osf1
	fi
-
	exit ;;
+
	;;
    parisc*:Lites*:*:*)
-
	echo hppa1.1-hp-lites
-
	exit ;;
+
	GUESS=hppa1.1-hp-lites
+
	;;
    C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
-
	echo c1-convex-bsd
-
	exit ;;
+
	GUESS=c1-convex-bsd
+
	;;
    C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
	if getsysinfo -f scalar_acc
	then echo c32-convex-bsd
@@ -791,17 +836,18 @@ EOF
	fi
	exit ;;
    C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
-
	echo c34-convex-bsd
-
	exit ;;
+
	GUESS=c34-convex-bsd
+
	;;
    C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
-
	echo c38-convex-bsd
-
	exit ;;
+
	GUESS=c38-convex-bsd
+
	;;
    C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
-
	echo c4-convex-bsd
-
	exit ;;
+
	GUESS=c4-convex-bsd
+
	;;
    CRAY*Y-MP:*:*:*)
-
	echo ymp-cray-unicos"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'
-
	exit ;;
+
	CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'`
+
	GUESS=ymp-cray-unicos$CRAY_REL
+
	;;
    CRAY*[A-Z]90:*:*:*)
	echo "$UNAME_MACHINE"-cray-unicos"$UNAME_RELEASE" \
	| sed -e 's/CRAY.*\([A-Z]90\)/\1/' \
@@ -809,103 +855,126 @@ EOF
	      -e 's/\.[^.]*$/.X/'
	exit ;;
    CRAY*TS:*:*:*)
-
	echo t90-cray-unicos"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'
-
	exit ;;
+
	CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'`
+
	GUESS=t90-cray-unicos$CRAY_REL
+
	;;
    CRAY*T3E:*:*:*)
-
	echo alphaev5-cray-unicosmk"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'
-
	exit ;;
+
	CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'`
+
	GUESS=alphaev5-cray-unicosmk$CRAY_REL
+
	;;
    CRAY*SV1:*:*:*)
-
	echo sv1-cray-unicos"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'
-
	exit ;;
+
	CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'`
+
	GUESS=sv1-cray-unicos$CRAY_REL
+
	;;
    *:UNICOS/mp:*:*)
-
	echo craynv-cray-unicosmp"$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'
-
	exit ;;
+
	CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'`
+
	GUESS=craynv-cray-unicosmp$CRAY_REL
+
	;;
    F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*)
	FUJITSU_PROC=`uname -m | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz`
	FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'`
	FUJITSU_REL=`echo "$UNAME_RELEASE" | sed -e 's/ /_/'`
-
	echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
-
	exit ;;
+
	GUESS=${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}
+
	;;
    5000:UNIX_System_V:4.*:*)
	FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'`
	FUJITSU_REL=`echo "$UNAME_RELEASE" | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/ /_/'`
-
	echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
-
	exit ;;
+
	GUESS=sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}
+
	;;
    i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
-
	echo "$UNAME_MACHINE"-pc-bsdi"$UNAME_RELEASE"
-
	exit ;;
+
	GUESS=$UNAME_MACHINE-pc-bsdi$UNAME_RELEASE
+
	;;
    sparc*:BSD/OS:*:*)
-
	echo sparc-unknown-bsdi"$UNAME_RELEASE"
-
	exit ;;
+
	GUESS=sparc-unknown-bsdi$UNAME_RELEASE
+
	;;
    *:BSD/OS:*:*)
-
	echo "$UNAME_MACHINE"-unknown-bsdi"$UNAME_RELEASE"
-
	exit ;;
+
	GUESS=$UNAME_MACHINE-unknown-bsdi$UNAME_RELEASE
+
	;;
+
    arm:FreeBSD:*:*)
+
	UNAME_PROCESSOR=`uname -p`
+
	set_cc_for_build
+
	if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \
+
	    | grep -q __ARM_PCS_VFP
+
	then
+
	    FREEBSD_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'`
+
	    GUESS=$UNAME_PROCESSOR-unknown-freebsd$FREEBSD_REL-gnueabi
+
	else
+
	    FREEBSD_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'`
+
	    GUESS=$UNAME_PROCESSOR-unknown-freebsd$FREEBSD_REL-gnueabihf
+
	fi
+
	;;
    *:FreeBSD:*:*)
	UNAME_PROCESSOR=`/usr/bin/uname -p`
-
	case "$UNAME_PROCESSOR" in
+
	case $UNAME_PROCESSOR in
	    amd64)
		UNAME_PROCESSOR=x86_64 ;;
	    i386)
		UNAME_PROCESSOR=i586 ;;
	esac
-
	echo "$UNAME_PROCESSOR"-unknown-freebsd"`echo "$UNAME_RELEASE"|sed -e 's/[-(].*//'`"
-
	exit ;;
+
	FREEBSD_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'`
+
	GUESS=$UNAME_PROCESSOR-unknown-freebsd$FREEBSD_REL
+
	;;
    i*:CYGWIN*:*)
-
	echo "$UNAME_MACHINE"-pc-cygwin
-
	exit ;;
+
	GUESS=$UNAME_MACHINE-pc-cygwin
+
	;;
    *:MINGW64*:*)
-
	echo "$UNAME_MACHINE"-pc-mingw64
-
	exit ;;
+
	GUESS=$UNAME_MACHINE-pc-mingw64
+
	;;
    *:MINGW*:*)
-
	echo "$UNAME_MACHINE"-pc-mingw32
-
	exit ;;
+
	GUESS=$UNAME_MACHINE-pc-mingw32
+
	;;
    *:MSYS*:*)
-
	echo "$UNAME_MACHINE"-pc-msys
-
	exit ;;
+
	GUESS=$UNAME_MACHINE-pc-msys
+
	;;
    i*:PW*:*)
-
	echo "$UNAME_MACHINE"-pc-pw32
-
	exit ;;
+
	GUESS=$UNAME_MACHINE-pc-pw32
+
	;;
    *:Interix*:*)
-
	case "$UNAME_MACHINE" in
+
	case $UNAME_MACHINE in
	    x86)
-
		echo i586-pc-interix"$UNAME_RELEASE"
-
		exit ;;
+
		GUESS=i586-pc-interix$UNAME_RELEASE
+
		;;
	    authenticamd | genuineintel | EM64T)
-
		echo x86_64-unknown-interix"$UNAME_RELEASE"
-
		exit ;;
+
		GUESS=x86_64-unknown-interix$UNAME_RELEASE
+
		;;
	    IA64)
-
		echo ia64-unknown-interix"$UNAME_RELEASE"
-
		exit ;;
+
		GUESS=ia64-unknown-interix$UNAME_RELEASE
+
		;;
	esac ;;
    i*:UWIN*:*)
-
	echo "$UNAME_MACHINE"-pc-uwin
-
	exit ;;
+
	GUESS=$UNAME_MACHINE-pc-uwin
+
	;;
    amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*)
-
	echo x86_64-unknown-cygwin
-
	exit ;;
+
	GUESS=x86_64-pc-cygwin
+
	;;
    prep*:SunOS:5.*:*)
-
	echo powerpcle-unknown-solaris2"`echo "$UNAME_RELEASE"|sed -e 's/[^.]*//'`"
-
	exit ;;
+
	SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'`
+
	GUESS=powerpcle-unknown-solaris2$SUN_REL
+
	;;
    *:GNU:*:*)
	# the GNU system
-
	echo "`echo "$UNAME_MACHINE"|sed -e 's,[-/].*$,,'`-unknown-$LIBC`echo "$UNAME_RELEASE"|sed -e 's,/.*$,,'`"
-
	exit ;;
+
	GNU_ARCH=`echo "$UNAME_MACHINE" | sed -e 's,[-/].*$,,'`
+
	GNU_REL=`echo "$UNAME_RELEASE" | sed -e 's,/.*$,,'`
+
	GUESS=$GNU_ARCH-unknown-$LIBC$GNU_REL
+
	;;
    *:GNU/*:*:*)
	# other systems with GNU libc and userland
-
	echo "$UNAME_MACHINE-unknown-`echo "$UNAME_SYSTEM" | sed 's,^[^/]*/,,' | tr "[:upper:]" "[:lower:]"``echo "$UNAME_RELEASE"|sed -e 's/[-(].*//'`-$LIBC"
-
	exit ;;
-
    i*86:Minix:*:*)
-
	echo "$UNAME_MACHINE"-pc-minix
-
	exit ;;
+
	GNU_SYS=`echo "$UNAME_SYSTEM" | sed 's,^[^/]*/,,' | tr "[:upper:]" "[:lower:]"`
+
	GNU_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'`
+
	GUESS=$UNAME_MACHINE-unknown-$GNU_SYS$GNU_REL-$LIBC
+
	;;
+
    *:Minix:*:*)
+
	GUESS=$UNAME_MACHINE-unknown-minix
+
	;;
    aarch64:Linux:*:*)
-
	echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
-
	exit ;;
+
	GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+
	;;
    aarch64_be:Linux:*:*)
	UNAME_MACHINE=aarch64_be
-
	echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
-
	exit ;;
+
	GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+
	;;
    alpha:Linux:*:*)
-
	case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in
+
	case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' /proc/cpuinfo 2>/dev/null` in
	  EV5)   UNAME_MACHINE=alphaev5 ;;
	  EV56)  UNAME_MACHINE=alphaev56 ;;
	  PCA56) UNAME_MACHINE=alphapca56 ;;
@@ -916,183 +985,225 @@ EOF
	esac
	objdump --private-headers /bin/sh | grep -q ld.so.1
	if test "$?" = 0 ; then LIBC=gnulibc1 ; fi
-
	echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
-
	exit ;;
-
    arc:Linux:*:* | arceb:Linux:*:*)
-
	echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
-
	exit ;;
+
	GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+
	;;
+
    arc:Linux:*:* | arceb:Linux:*:* | arc32:Linux:*:* | arc64:Linux:*:*)
+
	GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+
	;;
    arm*:Linux:*:*)
-
	eval "$set_cc_for_build"
+
	set_cc_for_build
	if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \
	    | grep -q __ARM_EABI__
	then
-
	    echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
+
	    GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
	else
	    if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \
		| grep -q __ARM_PCS_VFP
	    then
-
		echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"eabi
+
		GUESS=$UNAME_MACHINE-unknown-linux-${LIBC}eabi
	    else
-
		echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"eabihf
+
		GUESS=$UNAME_MACHINE-unknown-linux-${LIBC}eabihf
	    fi
	fi
-
	exit ;;
+
	;;
    avr32*:Linux:*:*)
-
	echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
-
	exit ;;
+
	GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+
	;;
    cris:Linux:*:*)
-
	echo "$UNAME_MACHINE"-axis-linux-"$LIBC"
-
	exit ;;
+
	GUESS=$UNAME_MACHINE-axis-linux-$LIBC
+
	;;
    crisv32:Linux:*:*)
-
	echo "$UNAME_MACHINE"-axis-linux-"$LIBC"
-
	exit ;;
+
	GUESS=$UNAME_MACHINE-axis-linux-$LIBC
+
	;;
    e2k:Linux:*:*)
-
	echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
-
	exit ;;
+
	GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+
	;;
    frv:Linux:*:*)
-
	echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
-
	exit ;;
+
	GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+
	;;
    hexagon:Linux:*:*)
-
	echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
-
	exit ;;
+
	GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+
	;;
    i*86:Linux:*:*)
-
	echo "$UNAME_MACHINE"-pc-linux-"$LIBC"
-
	exit ;;
+
	GUESS=$UNAME_MACHINE-pc-linux-$LIBC
+
	;;
    ia64:Linux:*:*)
-
	echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
-
	exit ;;
+
	GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+
	;;
    k1om:Linux:*:*)
-
	echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
-
	exit ;;
+
	GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+
	;;
+
    loongarch32:Linux:*:* | loongarch64:Linux:*:* | loongarchx32:Linux:*:*)
+
	GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+
	;;
    m32r*:Linux:*:*)
-
	echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
-
	exit ;;
+
	GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+
	;;
    m68*:Linux:*:*)
-
	echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
-
	exit ;;
+
	GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+
	;;
    mips:Linux:*:* | mips64:Linux:*:*)
-
	eval "$set_cc_for_build"
+
	set_cc_for_build
+
	IS_GLIBC=0
+
	test x"${LIBC}" = xgnu && IS_GLIBC=1
	sed 's/^	//' << EOF > "$dummy.c"
	#undef CPU
-
	#undef ${UNAME_MACHINE}
-
	#undef ${UNAME_MACHINE}el
+
	#undef mips
+
	#undef mipsel
+
	#undef mips64
+
	#undef mips64el
+
	#if ${IS_GLIBC} && defined(_ABI64)
+
	LIBCABI=gnuabi64
+
	#else
+
	#if ${IS_GLIBC} && defined(_ABIN32)
+
	LIBCABI=gnuabin32
+
	#else
+
	LIBCABI=${LIBC}
+
	#endif
+
	#endif
+

+
	#if ${IS_GLIBC} && defined(__mips64) && defined(__mips_isa_rev) && __mips_isa_rev>=6
+
	CPU=mipsisa64r6
+
	#else
+
	#if ${IS_GLIBC} && !defined(__mips64) && defined(__mips_isa_rev) && __mips_isa_rev>=6
+
	CPU=mipsisa32r6
+
	#else
+
	#if defined(__mips64)
+
	CPU=mips64
+
	#else
+
	CPU=mips
+
	#endif
+
	#endif
+
	#endif
+

	#if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
-
	CPU=${UNAME_MACHINE}el
+
	MIPS_ENDIAN=el
	#else
	#if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
-
	CPU=${UNAME_MACHINE}
+
	MIPS_ENDIAN=
	#else
-
	CPU=
+
	MIPS_ENDIAN=
	#endif
	#endif
EOF
-
	eval "`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^CPU'`"
-
	test "x$CPU" != x && { echo "$CPU-unknown-linux-$LIBC"; exit; }
+
	cc_set_vars=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^CPU\|^MIPS_ENDIAN\|^LIBCABI'`
+
	eval "$cc_set_vars"
+
	test "x$CPU" != x && { echo "$CPU${MIPS_ENDIAN}-unknown-linux-$LIBCABI"; exit; }
	;;
    mips64el:Linux:*:*)
-
	echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
-
	exit ;;
+
	GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+
	;;
    openrisc*:Linux:*:*)
-
	echo or1k-unknown-linux-"$LIBC"
-
	exit ;;
+
	GUESS=or1k-unknown-linux-$LIBC
+
	;;
    or32:Linux:*:* | or1k*:Linux:*:*)
-
	echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
-
	exit ;;
+
	GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+
	;;
    padre:Linux:*:*)
-
	echo sparc-unknown-linux-"$LIBC"
-
	exit ;;
+
	GUESS=sparc-unknown-linux-$LIBC
+
	;;
    parisc64:Linux:*:* | hppa64:Linux:*:*)
-
	echo hppa64-unknown-linux-"$LIBC"
-
	exit ;;
+
	GUESS=hppa64-unknown-linux-$LIBC
+
	;;
    parisc:Linux:*:* | hppa:Linux:*:*)
	# Look for CPU level
	case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in
-
	  PA7*) echo hppa1.1-unknown-linux-"$LIBC" ;;
-
	  PA8*) echo hppa2.0-unknown-linux-"$LIBC" ;;
-
	  *)    echo hppa-unknown-linux-"$LIBC" ;;
+
	  PA7*) GUESS=hppa1.1-unknown-linux-$LIBC ;;
+
	  PA8*) GUESS=hppa2.0-unknown-linux-$LIBC ;;
+
	  *)    GUESS=hppa-unknown-linux-$LIBC ;;
	esac
-
	exit ;;
+
	;;
    ppc64:Linux:*:*)
-
	echo powerpc64-unknown-linux-"$LIBC"
-
	exit ;;
+
	GUESS=powerpc64-unknown-linux-$LIBC
+
	;;
    ppc:Linux:*:*)
-
	echo powerpc-unknown-linux-"$LIBC"
-
	exit ;;
+
	GUESS=powerpc-unknown-linux-$LIBC
+
	;;
    ppc64le:Linux:*:*)
-
	echo powerpc64le-unknown-linux-"$LIBC"
-
	exit ;;
+
	GUESS=powerpc64le-unknown-linux-$LIBC
+
	;;
    ppcle:Linux:*:*)
-
	echo powerpcle-unknown-linux-"$LIBC"
-
	exit ;;
-
    riscv32:Linux:*:* | riscv64:Linux:*:*)
-
	echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
-
	exit ;;
+
	GUESS=powerpcle-unknown-linux-$LIBC
+
	;;
+
    riscv32:Linux:*:* | riscv32be:Linux:*:* | riscv64:Linux:*:* | riscv64be:Linux:*:*)
+
	GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+
	;;
    s390:Linux:*:* | s390x:Linux:*:*)
-
	echo "$UNAME_MACHINE"-ibm-linux-"$LIBC"
-
	exit ;;
+
	GUESS=$UNAME_MACHINE-ibm-linux-$LIBC
+
	;;
    sh64*:Linux:*:*)
-
	echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
-
	exit ;;
+
	GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+
	;;
    sh*:Linux:*:*)
-
	echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
-
	exit ;;
+
	GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+
	;;
    sparc:Linux:*:* | sparc64:Linux:*:*)
-
	echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
-
	exit ;;
+
	GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+
	;;
    tile*:Linux:*:*)
-
	echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
-
	exit ;;
+
	GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+
	;;
    vax:Linux:*:*)
-
	echo "$UNAME_MACHINE"-dec-linux-"$LIBC"
-
	exit ;;
+
	GUESS=$UNAME_MACHINE-dec-linux-$LIBC
+
	;;
    x86_64:Linux:*:*)
-
	echo "$UNAME_MACHINE"-pc-linux-"$LIBC"
-
	exit ;;
+
	set_cc_for_build
+
	LIBCABI=$LIBC
+
	if test "$CC_FOR_BUILD" != no_compiler_found; then
+
	    if (echo '#ifdef __ILP32__'; echo IS_X32; echo '#endif') | \
+
		(CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \
+
		grep IS_X32 >/dev/null
+
	    then
+
		LIBCABI=${LIBC}x32
+
	    fi
+
	fi
+
	GUESS=$UNAME_MACHINE-pc-linux-$LIBCABI
+
	;;
    xtensa*:Linux:*:*)
-
	echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
-
	exit ;;
+
	GUESS=$UNAME_MACHINE-unknown-linux-$LIBC
+
	;;
    i*86:DYNIX/ptx:4*:*)
	# ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.
	# earlier versions are messed up and put the nodename in both
	# sysname and nodename.
-
	echo i386-sequent-sysv4
-
	exit ;;
+
	GUESS=i386-sequent-sysv4
+
	;;
    i*86:UNIX_SV:4.2MP:2.*)
	# Unixware is an offshoot of SVR4, but it has its own version
	# number series starting with 2...
	# I am not positive that other SVR4 systems won't match this,
	# I just have to hope.  -- rms.
	# Use sysv4.2uw... so that sysv4* matches it.
-
	echo "$UNAME_MACHINE"-pc-sysv4.2uw"$UNAME_VERSION"
-
	exit ;;
+
	GUESS=$UNAME_MACHINE-pc-sysv4.2uw$UNAME_VERSION
+
	;;
    i*86:OS/2:*:*)
	# If we were able to find `uname', then EMX Unix compatibility
	# is probably installed.
-
	echo "$UNAME_MACHINE"-pc-os2-emx
-
	exit ;;
+
	GUESS=$UNAME_MACHINE-pc-os2-emx
+
	;;
    i*86:XTS-300:*:STOP)
-
	echo "$UNAME_MACHINE"-unknown-stop
-
	exit ;;
+
	GUESS=$UNAME_MACHINE-unknown-stop
+
	;;
    i*86:atheos:*:*)
-
	echo "$UNAME_MACHINE"-unknown-atheos
-
	exit ;;
+
	GUESS=$UNAME_MACHINE-unknown-atheos
+
	;;
    i*86:syllable:*:*)
-
	echo "$UNAME_MACHINE"-pc-syllable
-
	exit ;;
+
	GUESS=$UNAME_MACHINE-pc-syllable
+
	;;
    i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*)
-
	echo i386-unknown-lynxos"$UNAME_RELEASE"
-
	exit ;;
+
	GUESS=i386-unknown-lynxos$UNAME_RELEASE
+
	;;
    i*86:*DOS:*:*)
-
	echo "$UNAME_MACHINE"-pc-msdosdjgpp
-
	exit ;;
+
	GUESS=$UNAME_MACHINE-pc-msdosdjgpp
+
	;;
    i*86:*:4.*:*)
	UNAME_REL=`echo "$UNAME_RELEASE" | sed 's/\/MP$//'`
	if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
-
		echo "$UNAME_MACHINE"-univel-sysv"$UNAME_REL"
+
		GUESS=$UNAME_MACHINE-univel-sysv$UNAME_REL
	else
-
		echo "$UNAME_MACHINE"-pc-sysv"$UNAME_REL"
+
		GUESS=$UNAME_MACHINE-pc-sysv$UNAME_REL
	fi
-
	exit ;;
+
	;;
    i*86:*:5:[678]*)
	# UnixWare 7.x, OpenUNIX and OpenServer 6.
	case `/bin/uname -X | grep "^Machine"` in
@@ -1100,12 +1211,12 @@ EOF
	    *Pentium)	     UNAME_MACHINE=i586 ;;
	    *Pent*|*Celeron) UNAME_MACHINE=i686 ;;
	esac
-
	echo "$UNAME_MACHINE-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}{$UNAME_VERSION}"
-
	exit ;;
+
	GUESS=$UNAME_MACHINE-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION}
+
	;;
    i*86:*:3.2:*)
	if test -f /usr/options/cb.name; then
		UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name`
-
		echo "$UNAME_MACHINE"-pc-isc"$UNAME_REL"
+
		GUESS=$UNAME_MACHINE-pc-isc$UNAME_REL
	elif /bin/uname -X 2>/dev/null >/dev/null ; then
		UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')`
		(/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486
@@ -1115,11 +1226,11 @@ EOF
			&& UNAME_MACHINE=i686
		(/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \
			&& UNAME_MACHINE=i686
-
		echo "$UNAME_MACHINE"-pc-sco"$UNAME_REL"
+
		GUESS=$UNAME_MACHINE-pc-sco$UNAME_REL
	else
-
		echo "$UNAME_MACHINE"-pc-sysv32
+
		GUESS=$UNAME_MACHINE-pc-sysv32
	fi
-
	exit ;;
+
	;;
    pc:*:*:*)
	# Left here for compatibility:
	# uname -m prints for DJGPP always 'pc', but it prints nothing about
@@ -1127,31 +1238,31 @@ EOF
	# Note: whatever this is, it MUST be the same as what config.sub
	# prints for the "djgpp" host, or else GDB configure will decide that
	# this is a cross-build.
-
	echo i586-pc-msdosdjgpp
-
	exit ;;
+
	GUESS=i586-pc-msdosdjgpp
+
	;;
    Intel:Mach:3*:*)
-
	echo i386-pc-mach3
-
	exit ;;
+
	GUESS=i386-pc-mach3
+
	;;
    paragon:*:*:*)
-
	echo i860-intel-osf1
-
	exit ;;
+
	GUESS=i860-intel-osf1
+
	;;
    i860:*:4.*:*) # i860-SVR4
	if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then
-
	  echo i860-stardent-sysv"$UNAME_RELEASE" # Stardent Vistra i860-SVR4
+
	  GUESS=i860-stardent-sysv$UNAME_RELEASE    # Stardent Vistra i860-SVR4
	else # Add other i860-SVR4 vendors below as they are discovered.
-
	  echo i860-unknown-sysv"$UNAME_RELEASE"  # Unknown i860-SVR4
+
	  GUESS=i860-unknown-sysv$UNAME_RELEASE     # Unknown i860-SVR4
	fi
-
	exit ;;
+
	;;
    mini*:CTIX:SYS*5:*)
	# "miniframe"
-
	echo m68010-convergent-sysv
-
	exit ;;
+
	GUESS=m68010-convergent-sysv
+
	;;
    mc68k:UNIX:SYSTEM5:3.51m)
-
	echo m68k-convergent-sysv
-
	exit ;;
+
	GUESS=m68k-convergent-sysv
+
	;;
    M680?0:D-NIX:5.3:*)
-
	echo m68k-diab-dnix
-
	exit ;;
+
	GUESS=m68k-diab-dnix
+
	;;
    M68*:*:R3V[5678]*:*)
	test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;;
    3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0)
@@ -1176,249 +1287,401 @@ EOF
	/bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \
	    && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } ;;
    m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*)
-
	echo m68k-unknown-lynxos"$UNAME_RELEASE"
-
	exit ;;
+
	GUESS=m68k-unknown-lynxos$UNAME_RELEASE
+
	;;
    mc68030:UNIX_System_V:4.*:*)
-
	echo m68k-atari-sysv4
-
	exit ;;
+
	GUESS=m68k-atari-sysv4
+
	;;
    TSUNAMI:LynxOS:2.*:*)
-
	echo sparc-unknown-lynxos"$UNAME_RELEASE"
-
	exit ;;
+
	GUESS=sparc-unknown-lynxos$UNAME_RELEASE
+
	;;
    rs6000:LynxOS:2.*:*)
-
	echo rs6000-unknown-lynxos"$UNAME_RELEASE"
-
	exit ;;
+
	GUESS=rs6000-unknown-lynxos$UNAME_RELEASE
+
	;;
    PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*)
-
	echo powerpc-unknown-lynxos"$UNAME_RELEASE"
-
	exit ;;
+
	GUESS=powerpc-unknown-lynxos$UNAME_RELEASE
+
	;;
    SM[BE]S:UNIX_SV:*:*)
-
	echo mips-dde-sysv"$UNAME_RELEASE"
-
	exit ;;
+
	GUESS=mips-dde-sysv$UNAME_RELEASE
+
	;;
    RM*:ReliantUNIX-*:*:*)
-
	echo mips-sni-sysv4
-
	exit ;;
+
	GUESS=mips-sni-sysv4
+
	;;
    RM*:SINIX-*:*:*)
-
	echo mips-sni-sysv4
-
	exit ;;
+
	GUESS=mips-sni-sysv4
+
	;;
    *:SINIX-*:*:*)
	if uname -p 2>/dev/null >/dev/null ; then
		UNAME_MACHINE=`(uname -p) 2>/dev/null`
-
		echo "$UNAME_MACHINE"-sni-sysv4
+
		GUESS=$UNAME_MACHINE-sni-sysv4
	else
-
		echo ns32k-sni-sysv
+
		GUESS=ns32k-sni-sysv
	fi
-
	exit ;;
+
	;;
    PENTIUM:*:4.0*:*)	# Unisys `ClearPath HMP IX 4000' SVR4/MP effort
			# says <Richard.M.Bartel@ccMail.Census.GOV>
-
	echo i586-unisys-sysv4
-
	exit ;;
+
	GUESS=i586-unisys-sysv4
+
	;;
    *:UNIX_System_V:4*:FTX*)
	# From Gerald Hewes <hewes@openmarket.com>.
	# How about differentiating between stratus architectures? -djm
-
	echo hppa1.1-stratus-sysv4
-
	exit ;;
+
	GUESS=hppa1.1-stratus-sysv4
+
	;;
    *:*:*:FTX*)
	# From seanf@swdc.stratus.com.
-
	echo i860-stratus-sysv4
-
	exit ;;
+
	GUESS=i860-stratus-sysv4
+
	;;
    i*86:VOS:*:*)
	# From Paul.Green@stratus.com.
-
	echo "$UNAME_MACHINE"-stratus-vos
-
	exit ;;
+
	GUESS=$UNAME_MACHINE-stratus-vos
+
	;;
    *:VOS:*:*)
	# From Paul.Green@stratus.com.
-
	echo hppa1.1-stratus-vos
-
	exit ;;
+
	GUESS=hppa1.1-stratus-vos
+
	;;
    mc68*:A/UX:*:*)
-
	echo m68k-apple-aux"$UNAME_RELEASE"
-
	exit ;;
+
	GUESS=m68k-apple-aux$UNAME_RELEASE
+
	;;
    news*:NEWS-OS:6*:*)
-
	echo mips-sony-newsos6
-
	exit ;;
+
	GUESS=mips-sony-newsos6
+
	;;
    R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*)
-
	if [ -d /usr/nec ]; then
-
		echo mips-nec-sysv"$UNAME_RELEASE"
+
	if test -d /usr/nec; then
+
		GUESS=mips-nec-sysv$UNAME_RELEASE
	else
-
		echo mips-unknown-sysv"$UNAME_RELEASE"
+
		GUESS=mips-unknown-sysv$UNAME_RELEASE
	fi
-
	exit ;;
+
	;;
    BeBox:BeOS:*:*)	# BeOS running on hardware made by Be, PPC only.
-
	echo powerpc-be-beos
-
	exit ;;
+
	GUESS=powerpc-be-beos
+
	;;
    BeMac:BeOS:*:*)	# BeOS running on Mac or Mac clone, PPC only.
-
	echo powerpc-apple-beos
-
	exit ;;
+
	GUESS=powerpc-apple-beos
+
	;;
    BePC:BeOS:*:*)	# BeOS running on Intel PC compatible.
-
	echo i586-pc-beos
-
	exit ;;
+
	GUESS=i586-pc-beos
+
	;;
    BePC:Haiku:*:*)	# Haiku running on Intel PC compatible.
-
	echo i586-pc-haiku
-
	exit ;;
+
	GUESS=i586-pc-haiku
+
	;;
    x86_64:Haiku:*:*)
-
	echo x86_64-unknown-haiku
-
	exit ;;
+
	GUESS=x86_64-unknown-haiku
+
	;;
    SX-4:SUPER-UX:*:*)
-
	echo sx4-nec-superux"$UNAME_RELEASE"
-
	exit ;;
+
	GUESS=sx4-nec-superux$UNAME_RELEASE
+
	;;
    SX-5:SUPER-UX:*:*)
-
	echo sx5-nec-superux"$UNAME_RELEASE"
-
	exit ;;
+
	GUESS=sx5-nec-superux$UNAME_RELEASE
+
	;;
    SX-6:SUPER-UX:*:*)
-
	echo sx6-nec-superux"$UNAME_RELEASE"
-
	exit ;;
+
	GUESS=sx6-nec-superux$UNAME_RELEASE
+
	;;
    SX-7:SUPER-UX:*:*)
-
	echo sx7-nec-superux"$UNAME_RELEASE"
-
	exit ;;
+
	GUESS=sx7-nec-superux$UNAME_RELEASE
+
	;;
    SX-8:SUPER-UX:*:*)
-
	echo sx8-nec-superux"$UNAME_RELEASE"
-
	exit ;;
+
	GUESS=sx8-nec-superux$UNAME_RELEASE
+
	;;
    SX-8R:SUPER-UX:*:*)
-
	echo sx8r-nec-superux"$UNAME_RELEASE"
-
	exit ;;
+
	GUESS=sx8r-nec-superux$UNAME_RELEASE
+
	;;
    SX-ACE:SUPER-UX:*:*)
-
	echo sxace-nec-superux"$UNAME_RELEASE"
-
	exit ;;
+
	GUESS=sxace-nec-superux$UNAME_RELEASE
+
	;;
    Power*:Rhapsody:*:*)
-
	echo powerpc-apple-rhapsody"$UNAME_RELEASE"
-
	exit ;;
+
	GUESS=powerpc-apple-rhapsody$UNAME_RELEASE
+
	;;
    *:Rhapsody:*:*)
-
	echo "$UNAME_MACHINE"-apple-rhapsody"$UNAME_RELEASE"
-
	exit ;;
+
	GUESS=$UNAME_MACHINE-apple-rhapsody$UNAME_RELEASE
+
	;;
+
    arm64:Darwin:*:*)
+
	GUESS=aarch64-apple-darwin$UNAME_RELEASE
+
	;;
    *:Darwin:*:*)
-
	UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown
-
	eval "$set_cc_for_build"
-
	if test "$UNAME_PROCESSOR" = unknown ; then
-
	    UNAME_PROCESSOR=powerpc
+
	UNAME_PROCESSOR=`uname -p`
+
	case $UNAME_PROCESSOR in
+
	    unknown) UNAME_PROCESSOR=powerpc ;;
+
	esac
+
	if command -v xcode-select > /dev/null 2> /dev/null && \
+
		! xcode-select --print-path > /dev/null 2> /dev/null ; then
+
	    # Avoid executing cc if there is no toolchain installed as
+
	    # cc will be a stub that puts up a graphical alert
+
	    # prompting the user to install developer tools.
+
	    CC_FOR_BUILD=no_compiler_found
+
	else
+
	    set_cc_for_build
	fi
-
	if test "`echo "$UNAME_RELEASE" | sed -e 's/\..*//'`" -le 10 ; then
-
	    if [ "$CC_FOR_BUILD" != no_compiler_found ]; then
-
		if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \
-
		       (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \
-
		       grep IS_64BIT_ARCH >/dev/null
-
		then
-
		    case $UNAME_PROCESSOR in
-
			i386) UNAME_PROCESSOR=x86_64 ;;
-
			powerpc) UNAME_PROCESSOR=powerpc64 ;;
-
		    esac
-
		fi
-
		# On 10.4-10.6 one might compile for PowerPC via gcc -arch ppc
-
		if (echo '#ifdef __POWERPC__'; echo IS_PPC; echo '#endif') | \
-
		       (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \
-
		       grep IS_PPC >/dev/null
-
		then
-
		    UNAME_PROCESSOR=powerpc
-
		fi
+
	if test "$CC_FOR_BUILD" != no_compiler_found; then
+
	    if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \
+
		   (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \
+
		   grep IS_64BIT_ARCH >/dev/null
+
	    then
+
		case $UNAME_PROCESSOR in
+
		    i386) UNAME_PROCESSOR=x86_64 ;;
+
		    powerpc) UNAME_PROCESSOR=powerpc64 ;;
+
		esac
+
	    fi
+
	    # On 10.4-10.6 one might compile for PowerPC via gcc -arch ppc
+
	    if (echo '#ifdef __POWERPC__'; echo IS_PPC; echo '#endif') | \
+
		   (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \
+
		   grep IS_PPC >/dev/null
+
	    then
+
		UNAME_PROCESSOR=powerpc
	    fi
	elif test "$UNAME_PROCESSOR" = i386 ; then
-
	    # Avoid executing cc on OS X 10.9, as it ships with a stub
-
	    # that puts up a graphical alert prompting to install
-
	    # developer tools.  Any system running Mac OS X 10.7 or
-
	    # later (Darwin 11 and later) is required to have a 64-bit
-
	    # processor. This is not true of the ARM version of Darwin
-
	    # that Apple uses in portable devices.
-
	    UNAME_PROCESSOR=x86_64
+
	    # uname -m returns i386 or x86_64
+
	    UNAME_PROCESSOR=$UNAME_MACHINE
	fi
-
	echo "$UNAME_PROCESSOR"-apple-darwin"$UNAME_RELEASE"
-
	exit ;;
+
	GUESS=$UNAME_PROCESSOR-apple-darwin$UNAME_RELEASE
+
	;;
    *:procnto*:*:* | *:QNX:[0123456789]*:*)
	UNAME_PROCESSOR=`uname -p`
	if test "$UNAME_PROCESSOR" = x86; then
		UNAME_PROCESSOR=i386
		UNAME_MACHINE=pc
	fi
-
	echo "$UNAME_PROCESSOR"-"$UNAME_MACHINE"-nto-qnx"$UNAME_RELEASE"
-
	exit ;;
+
	GUESS=$UNAME_PROCESSOR-$UNAME_MACHINE-nto-qnx$UNAME_RELEASE
+
	;;
    *:QNX:*:4*)
-
	echo i386-pc-qnx
-
	exit ;;
+
	GUESS=i386-pc-qnx
+
	;;
    NEO-*:NONSTOP_KERNEL:*:*)
-
	echo neo-tandem-nsk"$UNAME_RELEASE"
-
	exit ;;
+
	GUESS=neo-tandem-nsk$UNAME_RELEASE
+
	;;
    NSE-*:NONSTOP_KERNEL:*:*)
-
	echo nse-tandem-nsk"$UNAME_RELEASE"
-
	exit ;;
+
	GUESS=nse-tandem-nsk$UNAME_RELEASE
+
	;;
    NSR-*:NONSTOP_KERNEL:*:*)
-
	echo nsr-tandem-nsk"$UNAME_RELEASE"
-
	exit ;;
+
	GUESS=nsr-tandem-nsk$UNAME_RELEASE
+
	;;
    NSV-*:NONSTOP_KERNEL:*:*)
-
	echo nsv-tandem-nsk"$UNAME_RELEASE"
-
	exit ;;
+
	GUESS=nsv-tandem-nsk$UNAME_RELEASE
+
	;;
    NSX-*:NONSTOP_KERNEL:*:*)
-
	echo nsx-tandem-nsk"$UNAME_RELEASE"
-
	exit ;;
+
	GUESS=nsx-tandem-nsk$UNAME_RELEASE
+
	;;
    *:NonStop-UX:*:*)
-
	echo mips-compaq-nonstopux
-
	exit ;;
+
	GUESS=mips-compaq-nonstopux
+
	;;
    BS2000:POSIX*:*:*)
-
	echo bs2000-siemens-sysv
-
	exit ;;
+
	GUESS=bs2000-siemens-sysv
+
	;;
    DS/*:UNIX_System_V:*:*)
-
	echo "$UNAME_MACHINE"-"$UNAME_SYSTEM"-"$UNAME_RELEASE"
-
	exit ;;
+
	GUESS=$UNAME_MACHINE-$UNAME_SYSTEM-$UNAME_RELEASE
+
	;;
    *:Plan9:*:*)
	# "uname -m" is not consistent, so use $cputype instead. 386
	# is converted to i386 for consistency with other x86
	# operating systems.
-
	if test "$cputype" = 386; then
+
	if test "${cputype-}" = 386; then
	    UNAME_MACHINE=i386
-
	else
-
	    UNAME_MACHINE="$cputype"
+
	elif test "x${cputype-}" != x; then
+
	    UNAME_MACHINE=$cputype
	fi
-
	echo "$UNAME_MACHINE"-unknown-plan9
-
	exit ;;
+
	GUESS=$UNAME_MACHINE-unknown-plan9
+
	;;
    *:TOPS-10:*:*)
-
	echo pdp10-unknown-tops10
-
	exit ;;
+
	GUESS=pdp10-unknown-tops10
+
	;;
    *:TENEX:*:*)
-
	echo pdp10-unknown-tenex
-
	exit ;;
+
	GUESS=pdp10-unknown-tenex
+
	;;
    KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*)
-
	echo pdp10-dec-tops20
-
	exit ;;
+
	GUESS=pdp10-dec-tops20
+
	;;
    XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*)
-
	echo pdp10-xkl-tops20
-
	exit ;;
+
	GUESS=pdp10-xkl-tops20
+
	;;
    *:TOPS-20:*:*)
-
	echo pdp10-unknown-tops20
-
	exit ;;
+
	GUESS=pdp10-unknown-tops20
+
	;;
    *:ITS:*:*)
-
	echo pdp10-unknown-its
-
	exit ;;
+
	GUESS=pdp10-unknown-its
+
	;;
    SEI:*:*:SEIUX)
-
	echo mips-sei-seiux"$UNAME_RELEASE"
-
	exit ;;
+
	GUESS=mips-sei-seiux$UNAME_RELEASE
+
	;;
    *:DragonFly:*:*)
-
	echo "$UNAME_MACHINE"-unknown-dragonfly"`echo "$UNAME_RELEASE"|sed -e 's/[-(].*//'`"
-
	exit ;;
+
	DRAGONFLY_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'`
+
	GUESS=$UNAME_MACHINE-unknown-dragonfly$DRAGONFLY_REL
+
	;;
    *:*VMS:*:*)
	UNAME_MACHINE=`(uname -p) 2>/dev/null`
-
	case "$UNAME_MACHINE" in
-
	    A*) echo alpha-dec-vms ; exit ;;
-
	    I*) echo ia64-dec-vms ; exit ;;
-
	    V*) echo vax-dec-vms ; exit ;;
+
	case $UNAME_MACHINE in
+
	    A*) GUESS=alpha-dec-vms ;;
+
	    I*) GUESS=ia64-dec-vms ;;
+
	    V*) GUESS=vax-dec-vms ;;
	esac ;;
    *:XENIX:*:SysV)
-
	echo i386-pc-xenix
-
	exit ;;
+
	GUESS=i386-pc-xenix
+
	;;
    i*86:skyos:*:*)
-
	echo "$UNAME_MACHINE"-pc-skyos"`echo "$UNAME_RELEASE" | sed -e 's/ .*$//'`"
-
	exit ;;
+
	SKYOS_REL=`echo "$UNAME_RELEASE" | sed -e 's/ .*$//'`
+
	GUESS=$UNAME_MACHINE-pc-skyos$SKYOS_REL
+
	;;
    i*86:rdos:*:*)
-
	echo "$UNAME_MACHINE"-pc-rdos
-
	exit ;;
-
    i*86:AROS:*:*)
-
	echo "$UNAME_MACHINE"-pc-aros
-
	exit ;;
+
	GUESS=$UNAME_MACHINE-pc-rdos
+
	;;
+
    *:AROS:*:*)
+
	GUESS=$UNAME_MACHINE-unknown-aros
+
	;;
    x86_64:VMkernel:*:*)
-
	echo "$UNAME_MACHINE"-unknown-esx
-
	exit ;;
+
	GUESS=$UNAME_MACHINE-unknown-esx
+
	;;
    amd64:Isilon\ OneFS:*:*)
-
	echo x86_64-unknown-onefs
-
	exit ;;
+
	GUESS=x86_64-unknown-onefs
+
	;;
+
    *:Unleashed:*:*)
+
	GUESS=$UNAME_MACHINE-unknown-unleashed$UNAME_RELEASE
+
	;;
esac

+
# Do we have a guess based on uname results?
+
if test "x$GUESS" != x; then
+
    echo "$GUESS"
+
    exit
+
fi
+

+
# No uname command or uname output not recognized.
+
set_cc_for_build
+
cat > "$dummy.c" <<EOF
+
#ifdef _SEQUENT_
+
#include <sys/types.h>
+
#include <sys/utsname.h>
+
#endif
+
#if defined(ultrix) || defined(_ultrix) || defined(__ultrix) || defined(__ultrix__)
+
#if defined (vax) || defined (__vax) || defined (__vax__) || defined(mips) || defined(__mips) || defined(__mips__) || defined(MIPS) || defined(__MIPS__)
+
#include <signal.h>
+
#if defined(_SIZE_T_) || defined(SIGLOST)
+
#include <sys/utsname.h>
+
#endif
+
#endif
+
#endif
+
main ()
+
{
+
#if defined (sony)
+
#if defined (MIPSEB)
+
  /* BFD wants "bsd" instead of "newsos".  Perhaps BFD should be changed,
+
     I don't know....  */
+
  printf ("mips-sony-bsd\n"); exit (0);
+
#else
+
#include <sys/param.h>
+
  printf ("m68k-sony-newsos%s\n",
+
#ifdef NEWSOS4
+
  "4"
+
#else
+
  ""
+
#endif
+
  ); exit (0);
+
#endif
+
#endif
+

+
#if defined (NeXT)
+
#if !defined (__ARCHITECTURE__)
+
#define __ARCHITECTURE__ "m68k"
+
#endif
+
  int version;
+
  version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`;
+
  if (version < 4)
+
    printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version);
+
  else
+
    printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version);
+
  exit (0);
+
#endif
+

+
#if defined (MULTIMAX) || defined (n16)
+
#if defined (UMAXV)
+
  printf ("ns32k-encore-sysv\n"); exit (0);
+
#else
+
#if defined (CMU)
+
  printf ("ns32k-encore-mach\n"); exit (0);
+
#else
+
  printf ("ns32k-encore-bsd\n"); exit (0);
+
#endif
+
#endif
+
#endif
+

+
#if defined (__386BSD__)
+
  printf ("i386-pc-bsd\n"); exit (0);
+
#endif
+

+
#if defined (sequent)
+
#if defined (i386)
+
  printf ("i386-sequent-dynix\n"); exit (0);
+
#endif
+
#if defined (ns32000)
+
  printf ("ns32k-sequent-dynix\n"); exit (0);
+
#endif
+
#endif
+

+
#if defined (_SEQUENT_)
+
  struct utsname un;
+

+
  uname(&un);
+
  if (strncmp(un.version, "V2", 2) == 0) {
+
    printf ("i386-sequent-ptx2\n"); exit (0);
+
  }
+
  if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */
+
    printf ("i386-sequent-ptx1\n"); exit (0);
+
  }
+
  printf ("i386-sequent-ptx\n"); exit (0);
+
#endif
+

+
#if defined (vax)
+
#if !defined (ultrix)
+
#include <sys/param.h>
+
#if defined (BSD)
+
#if BSD == 43
+
  printf ("vax-dec-bsd4.3\n"); exit (0);
+
#else
+
#if BSD == 199006
+
  printf ("vax-dec-bsd4.3reno\n"); exit (0);
+
#else
+
  printf ("vax-dec-bsd\n"); exit (0);
+
#endif
+
#endif
+
#else
+
  printf ("vax-dec-bsd\n"); exit (0);
+
#endif
+
#else
+
#if defined(_SIZE_T_) || defined(SIGLOST)
+
  struct utsname un;
+
  uname (&un);
+
  printf ("vax-dec-ultrix%s\n", un.release); exit (0);
+
#else
+
  printf ("vax-dec-ultrix\n"); exit (0);
+
#endif
+
#endif
+
#endif
+
#if defined(ultrix) || defined(_ultrix) || defined(__ultrix) || defined(__ultrix__)
+
#if defined(mips) || defined(__mips) || defined(__mips__) || defined(MIPS) || defined(__MIPS__)
+
#if defined(_SIZE_T_) || defined(SIGLOST)
+
  struct utsname *un;
+
  uname (&un);
+
  printf ("mips-dec-ultrix%s\n", un.release); exit (0);
+
#else
+
  printf ("mips-dec-ultrix\n"); exit (0);
+
#endif
+
#endif
+
#endif
+

+
#if defined (alliant) && defined (i860)
+
  printf ("i860-alliant-bsd\n"); exit (0);
+
#endif
+

+
  exit (1);
+
}
+
EOF
+

+
$CC_FOR_BUILD -o "$dummy" "$dummy.c" 2>/dev/null && SYSTEM_NAME=`"$dummy"` &&
+
	{ echo "$SYSTEM_NAME"; exit; }
+

+
# Apollos put the system type in the environment.
+
test -d /usr/apollo && { echo "$ISP-apollo-$SYSTYPE"; exit; }
+

echo "$0: unable to guess system type" >&2

-
case "$UNAME_MACHINE:$UNAME_SYSTEM" in
+
case $UNAME_MACHINE:$UNAME_SYSTEM in
    mips:Linux | mips64:Linux)
	# If we got here on MIPS GNU/Linux, output extra information.
	cat >&2 <<EOF
@@ -1435,9 +1698,17 @@ This script (version $timestamp), has failed to recognize the
operating system you are using. If your script is old, overwrite *all*
copies of config.guess and config.sub with the latest versions from:

-
  https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess
+
  https://git.savannah.gnu.org/cgit/config.git/plain/config.guess
and
-
  https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub
+
  https://git.savannah.gnu.org/cgit/config.git/plain/config.sub
+
EOF
+

+
our_year=`echo $timestamp | sed 's,-.*,,'`
+
thisyear=`date +%Y`
+
# shellcheck disable=SC2003
+
script_age=`expr "$thisyear" - "$our_year"`
+
if test "$script_age" -lt 3 ; then
+
   cat >&2 <<EOF

If $0 has already been updated, send the following data and any
information you think might be pertinent to config-patches@gnu.org to
@@ -1465,6 +1736,7 @@ UNAME_RELEASE = "$UNAME_RELEASE"
UNAME_SYSTEM  = "$UNAME_SYSTEM"
UNAME_VERSION = "$UNAME_VERSION"
EOF
+
fi

exit 1

modified autosetup/autosetup-config.sub
@@ -1,8 +1,10 @@
#! /bin/sh
# Configuration validation subroutine script.
-
#   Copyright 1992-2018 Free Software Foundation, Inc.
+
#   Copyright 1992-2021 Free Software Foundation, Inc.

-
timestamp='2018-03-08'
+
# shellcheck disable=SC2006,SC2268 # see below for rationale
+

+
timestamp='2021-07-03'

# This file is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by
@@ -33,7 +35,7 @@ timestamp='2018-03-08'
# Otherwise, we print the canonical config type on stdout and succeed.

# You can get the latest version of this script from:
-
# https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub
+
# https://git.savannah.gnu.org/cgit/config.git/plain/config.sub

# This file is supposed to be the same for all GNU packages
# and recognize all the CPU types, system types and aliases
@@ -50,6 +52,13 @@ timestamp='2018-03-08'
#	CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
# It is wrong to echo any other type of specification.

+
# The "shellcheck disable" line above the timestamp inhibits complaints
+
# about features and limitations of the classic Bourne shell that were
+
# superseded or lifted in POSIX.  However, this script identifies a wide
+
# variety of pre-POSIX systems that do not have POSIX shells at all, and
+
# even some reasonably current systems (Solaris 10 as case-in-point) still
+
# have a pre-POSIX /bin/sh.
+

me=`echo "$0" | sed -e 's,.*/,,'`

usage="\
@@ -67,7 +76,7 @@ Report bugs and patches to <config-patches@gnu.org>."
version="\
GNU config.sub ($timestamp)

-
Copyright 1992-2018 Free Software Foundation, Inc.
+
Copyright 1992-2021 Free Software Foundation, Inc.

This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
@@ -89,7 +98,7 @@ while test $# -gt 0 ; do
    - )	# Use stdin as input.
       break ;;
    -* )
-
       echo "$me: invalid option $1$help"
+
       echo "$me: invalid option $1$help" >&2
       exit 1 ;;

    *local*)
@@ -110,1223 +119,1173 @@ case $# in
    exit 1;;
esac

-
# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any).
-
# Here we must recognize all the valid KERNEL-OS combinations.
-
maybe_os=`echo "$1" | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
-
case $maybe_os in
-
  nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \
-
  linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \
-
  knetbsd*-gnu* | netbsd*-gnu* | netbsd*-eabi* | \
-
  kopensolaris*-gnu* | cloudabi*-eabi* | \
-
  storm-chaos* | os2-emx* | rtmk-nova*)
-
    os=-$maybe_os
-
    basic_machine=`echo "$1" | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
-
    ;;
-
  android-linux)
-
    os=-linux-android
-
    basic_machine=`echo "$1" | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`-unknown
-
    ;;
-
  *)
-
    basic_machine=`echo "$1" | sed 's/-[^-]*$//'`
-
    if [ "$basic_machine" != "$1" ]
-
    then os=`echo "$1" | sed 's/.*-/-/'`
-
    else os=; fi
-
    ;;
-
esac
+
# Split fields of configuration type
+
# shellcheck disable=SC2162
+
IFS="-" read field1 field2 field3 field4 <<EOF
+
$1
+
EOF

-
### Let's recognize common machines as not being operating systems so
-
### that things like config.sub decstation-3100 work.  We also
-
### recognize some manufacturers as not being operating systems, so we
-
### can provide default operating systems below.
-
case $os in
-
	-sun*os*)
-
		# Prevent following clause from handling this invalid input.
-
		;;
-
	-dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \
-
	-att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \
-
	-unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \
-
	-convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
-
	-c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
-
	-harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \
-
	-apple | -axis | -knuth | -cray | -microblaze*)
-
		os=
-
		basic_machine=$1
-
		;;
-
	-bluegene*)
-
		os=-cnk
-
		;;
-
	-sim | -cisco | -oki | -wec | -winbond)
-
		os=
-
		basic_machine=$1
-
		;;
-
	-scout)
-
		;;
-
	-wrs)
-
		os=-vxworks
-
		basic_machine=$1
-
		;;
-
	-chorusos*)
-
		os=-chorusos
-
		basic_machine=$1
-
		;;
-
	-chorusrdb)
-
		os=-chorusrdb
-
		basic_machine=$1
-
		;;
-
	-hiux*)
-
		os=-hiuxwe2
-
		;;
-
	-sco6)
-
		os=-sco5v6
-
		basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'`
-
		;;
-
	-sco5)
-
		os=-sco3.2v5
-
		basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'`
-
		;;
-
	-sco4)
-
		os=-sco3.2v4
-
		basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'`
-
		;;
-
	-sco3.2.[4-9]*)
-
		os=`echo $os | sed -e 's/sco3.2./sco3.2v/'`
-
		basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'`
-
		;;
-
	-sco3.2v[4-9]*)
-
		# Don't forget version if it is 3.2v4 or newer.
-
		basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'`
-
		;;
-
	-sco5v6*)
-
		# Don't forget version if it is 3.2v4 or newer.
-
		basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'`
-
		;;
-
	-sco*)
-
		os=-sco3.2v2
-
		basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'`
-
		;;
-
	-udk*)
-
		basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'`
-
		;;
-
	-isc)
-
		os=-isc2.2
-
		basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'`
-
		;;
-
	-clix*)
-
		basic_machine=clipper-intergraph
-
		;;
-
	-isc*)
-
		basic_machine=`echo "$1" | sed -e 's/86-.*/86-pc/'`
-
		;;
-
	-lynx*178)
-
		os=-lynxos178
-
		;;
-
	-lynx*5)
-
		os=-lynxos5
+
# Separate into logical components for further validation
+
case $1 in
+
	*-*-*-*-*)
+
		echo Invalid configuration \`"$1"\': more than four components >&2
+
		exit 1
		;;
-
	-lynx*)
-
		os=-lynxos
+
	*-*-*-*)
+
		basic_machine=$field1-$field2
+
		basic_os=$field3-$field4
		;;
-
	-ptx*)
-
		basic_machine=`echo "$1" | sed -e 's/86-.*/86-sequent/'`
+
	*-*-*)
+
		# Ambiguous whether COMPANY is present, or skipped and KERNEL-OS is two
+
		# parts
+
		maybe_os=$field2-$field3
+
		case $maybe_os in
+
			nto-qnx* | linux-* | uclinux-uclibc* \
+
			| uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* \
+
			| netbsd*-eabi* | kopensolaris*-gnu* | cloudabi*-eabi* \
+
			| storm-chaos* | os2-emx* | rtmk-nova*)
+
				basic_machine=$field1
+
				basic_os=$maybe_os
+
				;;
+
			android-linux)
+
				basic_machine=$field1-unknown
+
				basic_os=linux-android
+
				;;
+
			*)
+
				basic_machine=$field1-$field2
+
				basic_os=$field3
+
				;;
+
		esac
		;;
-
	-psos*)
-
		os=-psos
+
	*-*)
+
		# A lone config we happen to match not fitting any pattern
+
		case $field1-$field2 in
+
			decstation-3100)
+
				basic_machine=mips-dec
+
				basic_os=
+
				;;
+
			*-*)
+
				# Second component is usually, but not always the OS
+
				case $field2 in
+
					# Prevent following clause from handling this valid os
+
					sun*os*)
+
						basic_machine=$field1
+
						basic_os=$field2
+
						;;
+
					# Manufacturers
+
					dec* | mips* | sequent* | encore* | pc533* | sgi* | sony* \
+
					| att* | 7300* | 3300* | delta* | motorola* | sun[234]* \
+
					| unicom* | ibm* | next | hp | isi* | apollo | altos* \
+
					| convergent* | ncr* | news | 32* | 3600* | 3100* \
+
					| hitachi* | c[123]* | convex* | sun | crds | omron* | dg \
+
					| ultra | tti* | harris | dolphin | highlevel | gould \
+
					| cbm | ns | masscomp | apple | axis | knuth | cray \
+
					| microblaze* | sim | cisco \
+
					| oki | wec | wrs | winbond)
+
						basic_machine=$field1-$field2
+
						basic_os=
+
						;;
+
					*)
+
						basic_machine=$field1
+
						basic_os=$field2
+
						;;
+
				esac
+
			;;
+
		esac
		;;
-
	-mint | -mint[0-9]*)
-
		basic_machine=m68k-atari
-
		os=-mint
+
	*)
+
		# Convert single-component short-hands not valid as part of
+
		# multi-component configurations.
+
		case $field1 in
+
			386bsd)
+
				basic_machine=i386-pc
+
				basic_os=bsd
+
				;;
+
			a29khif)
+
				basic_machine=a29k-amd
+
				basic_os=udi
+
				;;
+
			adobe68k)
+
				basic_machine=m68010-adobe
+
				basic_os=scout
+
				;;
+
			alliant)
+
				basic_machine=fx80-alliant
+
				basic_os=
+
				;;
+
			altos | altos3068)
+
				basic_machine=m68k-altos
+
				basic_os=
+
				;;
+
			am29k)
+
				basic_machine=a29k-none
+
				basic_os=bsd
+
				;;
+
			amdahl)
+
				basic_machine=580-amdahl
+
				basic_os=sysv
+
				;;
+
			amiga)
+
				basic_machine=m68k-unknown
+
				basic_os=
+
				;;
+
			amigaos | amigados)
+
				basic_machine=m68k-unknown
+
				basic_os=amigaos
+
				;;
+
			amigaunix | amix)
+
				basic_machine=m68k-unknown
+
				basic_os=sysv4
+
				;;
+
			apollo68)
+
				basic_machine=m68k-apollo
+
				basic_os=sysv
+
				;;
+
			apollo68bsd)
+
				basic_machine=m68k-apollo
+
				basic_os=bsd
+
				;;
+
			aros)
+
				basic_machine=i386-pc
+
				basic_os=aros
+
				;;
+
			aux)
+
				basic_machine=m68k-apple
+
				basic_os=aux
+
				;;
+
			balance)
+
				basic_machine=ns32k-sequent
+
				basic_os=dynix
+
				;;
+
			blackfin)
+
				basic_machine=bfin-unknown
+
				basic_os=linux
+
				;;
+
			cegcc)
+
				basic_machine=arm-unknown
+
				basic_os=cegcc
+
				;;
+
			convex-c1)
+
				basic_machine=c1-convex
+
				basic_os=bsd
+
				;;
+
			convex-c2)
+
				basic_machine=c2-convex
+
				basic_os=bsd
+
				;;
+
			convex-c32)
+
				basic_machine=c32-convex
+
				basic_os=bsd
+
				;;
+
			convex-c34)
+
				basic_machine=c34-convex
+
				basic_os=bsd
+
				;;
+
			convex-c38)
+
				basic_machine=c38-convex
+
				basic_os=bsd
+
				;;
+
			cray)
+
				basic_machine=j90-cray
+
				basic_os=unicos
+
				;;
+
			crds | unos)
+
				basic_machine=m68k-crds
+
				basic_os=
+
				;;
+
			da30)
+
				basic_machine=m68k-da30
+
				basic_os=
+
				;;
+
			decstation | pmax | pmin | dec3100 | decstatn)
+
				basic_machine=mips-dec
+
				basic_os=
+
				;;
+
			delta88)
+
				basic_machine=m88k-motorola
+
				basic_os=sysv3
+
				;;
+
			dicos)
+
				basic_machine=i686-pc
+
				basic_os=dicos
+
				;;
+
			djgpp)
+
				basic_machine=i586-pc
+
				basic_os=msdosdjgpp
+
				;;
+
			ebmon29k)
+
				basic_machine=a29k-amd
+
				basic_os=ebmon
+
				;;
+
			es1800 | OSE68k | ose68k | ose | OSE)
+
				basic_machine=m68k-ericsson
+
				basic_os=ose
+
				;;
+
			gmicro)
+
				basic_machine=tron-gmicro
+
				basic_os=sysv
+
				;;
+
			go32)
+
				basic_machine=i386-pc
+
				basic_os=go32
+
				;;
+
			h8300hms)
+
				basic_machine=h8300-hitachi
+
				basic_os=hms
+
				;;
+
			h8300xray)
+
				basic_machine=h8300-hitachi
+
				basic_os=xray
+
				;;
+
			h8500hms)
+
				basic_machine=h8500-hitachi
+
				basic_os=hms
+
				;;
+
			harris)
+
				basic_machine=m88k-harris
+
				basic_os=sysv3
+
				;;
+
			hp300 | hp300hpux)
+
				basic_machine=m68k-hp
+
				basic_os=hpux
+
				;;
+
			hp300bsd)
+
				basic_machine=m68k-hp
+
				basic_os=bsd
+
				;;
+
			hppaosf)
+
				basic_machine=hppa1.1-hp
+
				basic_os=osf
+
				;;
+
			hppro)
+
				basic_machine=hppa1.1-hp
+
				basic_os=proelf
+
				;;
+
			i386mach)
+
				basic_machine=i386-mach
+
				basic_os=mach
+
				;;
+
			isi68 | isi)
+
				basic_machine=m68k-isi
+
				basic_os=sysv
+
				;;
+
			m68knommu)
+
				basic_machine=m68k-unknown
+
				basic_os=linux
+
				;;
+
			magnum | m3230)
+
				basic_machine=mips-mips
+
				basic_os=sysv
+
				;;
+
			merlin)
+
				basic_machine=ns32k-utek
+
				basic_os=sysv
+
				;;
+
			mingw64)
+
				basic_machine=x86_64-pc
+
				basic_os=mingw64
+
				;;
+
			mingw32)
+
				basic_machine=i686-pc
+
				basic_os=mingw32
+
				;;
+
			mingw32ce)
+
				basic_machine=arm-unknown
+
				basic_os=mingw32ce
+
				;;
+
			monitor)
+
				basic_machine=m68k-rom68k
+
				basic_os=coff
+
				;;
+
			morphos)
+
				basic_machine=powerpc-unknown
+
				basic_os=morphos
+
				;;
+
			moxiebox)
+
				basic_machine=moxie-unknown
+
				basic_os=moxiebox
+
				;;
+
			msdos)
+
				basic_machine=i386-pc
+
				basic_os=msdos
+
				;;
+
			msys)
+
				basic_machine=i686-pc
+
				basic_os=msys
+
				;;
+
			mvs)
+
				basic_machine=i370-ibm
+
				basic_os=mvs
+
				;;
+
			nacl)
+
				basic_machine=le32-unknown
+
				basic_os=nacl
+
				;;
+
			ncr3000)
+
				basic_machine=i486-ncr
+
				basic_os=sysv4
+
				;;
+
			netbsd386)
+
				basic_machine=i386-pc
+
				basic_os=netbsd
+
				;;
+
			netwinder)
+
				basic_machine=armv4l-rebel
+
				basic_os=linux
+
				;;
+
			news | news700 | news800 | news900)
+
				basic_machine=m68k-sony
+
				basic_os=newsos
+
				;;
+
			news1000)
+
				basic_machine=m68030-sony
+
				basic_os=newsos
+
				;;
+
			necv70)
+
				basic_machine=v70-nec
+
				basic_os=sysv
+
				;;
+
			nh3000)
+
				basic_machine=m68k-harris
+
				basic_os=cxux
+
				;;
+
			nh[45]000)
+
				basic_machine=m88k-harris
+
				basic_os=cxux
+
				;;
+
			nindy960)
+
				basic_machine=i960-intel
+
				basic_os=nindy
+
				;;
+
			mon960)
+
				basic_machine=i960-intel
+
				basic_os=mon960
+
				;;
+
			nonstopux)
+
				basic_machine=mips-compaq
+
				basic_os=nonstopux
+
				;;
+
			os400)
+
				basic_machine=powerpc-ibm
+
				basic_os=os400
+
				;;
+
			OSE68000 | ose68000)
+
				basic_machine=m68000-ericsson
+
				basic_os=ose
+
				;;
+
			os68k)
+
				basic_machine=m68k-none
+
				basic_os=os68k
+
				;;
+
			paragon)
+
				basic_machine=i860-intel
+
				basic_os=osf
+
				;;
+
			parisc)
+
				basic_machine=hppa-unknown
+
				basic_os=linux
+
				;;
+
			psp)
+
				basic_machine=mipsallegrexel-sony
+
				basic_os=psp
+
				;;
+
			pw32)
+
				basic_machine=i586-unknown
+
				basic_os=pw32
+
				;;
+
			rdos | rdos64)
+
				basic_machine=x86_64-pc
+
				basic_os=rdos
+
				;;
+
			rdos32)
+
				basic_machine=i386-pc
+
				basic_os=rdos
+
				;;
+
			rom68k)
+
				basic_machine=m68k-rom68k
+
				basic_os=coff
+
				;;
+
			sa29200)
+
				basic_machine=a29k-amd
+
				basic_os=udi
+
				;;
+
			sei)
+
				basic_machine=mips-sei
+
				basic_os=seiux
+
				;;
+
			sequent)
+
				basic_machine=i386-sequent
+
				basic_os=
+
				;;
+
			sps7)
+
				basic_machine=m68k-bull
+
				basic_os=sysv2
+
				;;
+
			st2000)
+
				basic_machine=m68k-tandem
+
				basic_os=
+
				;;
+
			stratus)
+
				basic_machine=i860-stratus
+
				basic_os=sysv4
+
				;;
+
			sun2)
+
				basic_machine=m68000-sun
+
				basic_os=
+
				;;
+
			sun2os3)
+
				basic_machine=m68000-sun
+
				basic_os=sunos3
+
				;;
+
			sun2os4)
+
				basic_machine=m68000-sun
+
				basic_os=sunos4
+
				;;
+
			sun3)
+
				basic_machine=m68k-sun
+
				basic_os=
+
				;;
+
			sun3os3)
+
				basic_machine=m68k-sun
+
				basic_os=sunos3
+
				;;
+
			sun3os4)
+
				basic_machine=m68k-sun
+
				basic_os=sunos4
+
				;;
+
			sun4)
+
				basic_machine=sparc-sun
+
				basic_os=
+
				;;
+
			sun4os3)
+
				basic_machine=sparc-sun
+
				basic_os=sunos3
+
				;;
+
			sun4os4)
+
				basic_machine=sparc-sun
+
				basic_os=sunos4
+
				;;
+
			sun4sol2)
+
				basic_machine=sparc-sun
+
				basic_os=solaris2
+
				;;
+
			sun386 | sun386i | roadrunner)
+
				basic_machine=i386-sun
+
				basic_os=
+
				;;
+
			sv1)
+
				basic_machine=sv1-cray
+
				basic_os=unicos
+
				;;
+
			symmetry)
+
				basic_machine=i386-sequent
+
				basic_os=dynix
+
				;;
+
			t3e)
+
				basic_machine=alphaev5-cray
+
				basic_os=unicos
+
				;;
+
			t90)
+
				basic_machine=t90-cray
+
				basic_os=unicos
+
				;;
+
			toad1)
+
				basic_machine=pdp10-xkl
+
				basic_os=tops20
+
				;;
+
			tpf)
+
				basic_machine=s390x-ibm
+
				basic_os=tpf
+
				;;
+
			udi29k)
+
				basic_machine=a29k-amd
+
				basic_os=udi
+
				;;
+
			ultra3)
+
				basic_machine=a29k-nyu
+
				basic_os=sym1
+
				;;
+
			v810 | necv810)
+
				basic_machine=v810-nec
+
				basic_os=none
+
				;;
+
			vaxv)
+
				basic_machine=vax-dec
+
				basic_os=sysv
+
				;;
+
			vms)
+
				basic_machine=vax-dec
+
				basic_os=vms
+
				;;
+
			vsta)
+
				basic_machine=i386-pc
+
				basic_os=vsta
+
				;;
+
			vxworks960)
+
				basic_machine=i960-wrs
+
				basic_os=vxworks
+
				;;
+
			vxworks68)
+
				basic_machine=m68k-wrs
+
				basic_os=vxworks
+
				;;
+
			vxworks29k)
+
				basic_machine=a29k-wrs
+
				basic_os=vxworks
+
				;;
+
			xbox)
+
				basic_machine=i686-pc
+
				basic_os=mingw32
+
				;;
+
			ymp)
+
				basic_machine=ymp-cray
+
				basic_os=unicos
+
				;;
+
			*)
+
				basic_machine=$1
+
				basic_os=
+
				;;
+
		esac
		;;
esac

-
# Decode aliases for certain CPU-COMPANY combinations.
+
# Decode 1-component or ad-hoc basic machines
case $basic_machine in
-
	# Recognize the basic CPU types without company name.
-
	# Some are omitted here because they have special meanings below.
-
	1750a | 580 \
-
	| a29k \
-
	| aarch64 | aarch64_be \
-
	| alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \
-
	| alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \
-
	| am33_2.0 \
-
	| arc | arceb \
-
	| arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv7[arm] \
-
	| avr | avr32 \
-
	| ba \
-
	| be32 | be64 \
-
	| bfin \
-
	| c4x | c8051 | clipper \
-
	| d10v | d30v | dlx | dsp16xx \
-
	| e2k | epiphany \
-
	| fido | fr30 | frv | ft32 \
-
	| h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
-
	| hexagon \
-
	| i370 | i860 | i960 | ia16 | ia64 \
-
	| ip2k | iq2000 \
-
	| k1om \
-
	| le32 | le64 \
-
	| lm32 \
-
	| m32c | m32r | m32rle | m68000 | m68k | m88k \
-
	| maxq | mb | microblaze | microblazeel | mcore | mep | metag \
-
	| mips | mipsbe | mipseb | mipsel | mipsle \
-
	| mips16 \
-
	| mips64 | mips64el \
-
	| mips64octeon | mips64octeonel \
-
	| mips64orion | mips64orionel \
-
	| mips64r5900 | mips64r5900el \
-
	| mips64vr | mips64vrel \
-
	| mips64vr4100 | mips64vr4100el \
-
	| mips64vr4300 | mips64vr4300el \
-
	| mips64vr5000 | mips64vr5000el \
-
	| mips64vr5900 | mips64vr5900el \
-
	| mipsisa32 | mipsisa32el \
-
	| mipsisa32r2 | mipsisa32r2el \
-
	| mipsisa32r6 | mipsisa32r6el \
-
	| mipsisa64 | mipsisa64el \
-
	| mipsisa64r2 | mipsisa64r2el \
-
	| mipsisa64r6 | mipsisa64r6el \
-
	| mipsisa64sb1 | mipsisa64sb1el \
-
	| mipsisa64sr71k | mipsisa64sr71kel \
-
	| mipsr5900 | mipsr5900el \
-
	| mipstx39 | mipstx39el \
-
	| mn10200 | mn10300 \
-
	| moxie \
-
	| mt \
-
	| msp430 \
-
	| nds32 | nds32le | nds32be \
-
	| nios | nios2 | nios2eb | nios2el \
-
	| ns16k | ns32k \
-
	| open8 | or1k | or1knd | or32 \
-
	| pdp10 | pj | pjl \
-
	| powerpc | powerpc64 | powerpc64le | powerpcle \
-
	| pru \
-
	| pyramid \
-
	| riscv32 | riscv64 \
-
	| rl78 | rx \
-
	| score \
-
	| sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[234]eb | sheb | shbe | shle | sh[1234]le | sh3ele \
-
	| sh64 | sh64le \
-
	| sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \
-
	| sparcv8 | sparcv9 | sparcv9b | sparcv9v \
-
	| spu \
-
	| tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \
-
	| ubicom32 \
-
	| v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \
-
	| visium \
-
	| wasm32 \
-
	| x86 | xc16x | xstormy16 | xtensa \
-
	| z8k | z80)
-
		basic_machine=$basic_machine-unknown
-
		;;
-
	c54x)
-
		basic_machine=tic54x-unknown
-
		;;
-
	c55x)
-
		basic_machine=tic55x-unknown
-
		;;
-
	c6x)
-
		basic_machine=tic6x-unknown
-
		;;
-
	leon|leon[3-9])
-
		basic_machine=sparc-$basic_machine
+
	# Here we handle the default manufacturer of certain CPU types.  It is in
+
	# some cases the only manufacturer, in others, it is the most popular.
+
	w89k)
+
		cpu=hppa1.1
+
		vendor=winbond
		;;
-
	m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | nvptx | picochip)
-
		basic_machine=$basic_machine-unknown
-
		os=-none
+
	op50n)
+
		cpu=hppa1.1
+
		vendor=oki
		;;
-
	m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65)
+
	op60c)
+
		cpu=hppa1.1
+
		vendor=oki
		;;
-
	ms1)
-
		basic_machine=mt-unknown
+
	ibm*)
+
		cpu=i370
+
		vendor=ibm
		;;
-

-
	strongarm | thumb | xscale)
-
		basic_machine=arm-unknown
-
		;;
-
	xgate)
-
		basic_machine=$basic_machine-unknown
-
		os=-none
+
	orion105)
+
		cpu=clipper
+
		vendor=highlevel
		;;
-
	xscaleeb)
-
		basic_machine=armeb-unknown
+
	mac | mpw | mac-mpw)
+
		cpu=m68k
+
		vendor=apple
		;;
-

-
	xscaleel)
-
		basic_machine=armel-unknown
+
	pmac | pmac-mpw)
+
		cpu=powerpc
+
		vendor=apple
		;;

-
	# We use `pc' rather than `unknown'
-
	# because (1) that's what they normally are, and
-
	# (2) the word "unknown" tends to confuse beginning users.
-
	i*86 | x86_64)
-
	  basic_machine=$basic_machine-pc
-
	  ;;
-
	# Object if more than one company name word.
-
	*-*-*)
-
		echo Invalid configuration \`"$1"\': machine \`"$basic_machine"\' not recognized 1>&2
-
		exit 1
-
		;;
-
	# Recognize the basic CPU types with company name.
-
	580-* \
-
	| a29k-* \
-
	| aarch64-* | aarch64_be-* \
-
	| alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \
-
	| alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \
-
	| alphapca5[67]-* | alpha64pca5[67]-* | arc-* | arceb-* \
-
	| arm-*  | armbe-* | armle-* | armeb-* | armv*-* \
-
	| avr-* | avr32-* \
-
	| ba-* \
-
	| be32-* | be64-* \
-
	| bfin-* | bs2000-* \
-
	| c[123]* | c30-* | [cjt]90-* | c4x-* \
-
	| c8051-* | clipper-* | craynv-* | cydra-* \
-
	| d10v-* | d30v-* | dlx-* \
-
	| e2k-* | elxsi-* \
-
	| f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \
-
	| h8300-* | h8500-* \
-
	| hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \
-
	| hexagon-* \
-
	| i*86-* | i860-* | i960-* | ia16-* | ia64-* \
-
	| ip2k-* | iq2000-* \
-
	| k1om-* \
-
	| le32-* | le64-* \
-
	| lm32-* \
-
	| m32c-* | m32r-* | m32rle-* \
-
	| m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \
-
	| m88110-* | m88k-* | maxq-* | mcore-* | metag-* \
-
	| microblaze-* | microblazeel-* \
-
	| mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \
-
	| mips16-* \
-
	| mips64-* | mips64el-* \
-
	| mips64octeon-* | mips64octeonel-* \
-
	| mips64orion-* | mips64orionel-* \
-
	| mips64r5900-* | mips64r5900el-* \
-
	| mips64vr-* | mips64vrel-* \
-
	| mips64vr4100-* | mips64vr4100el-* \
-
	| mips64vr4300-* | mips64vr4300el-* \
-
	| mips64vr5000-* | mips64vr5000el-* \
-
	| mips64vr5900-* | mips64vr5900el-* \
-
	| mipsisa32-* | mipsisa32el-* \
-
	| mipsisa32r2-* | mipsisa32r2el-* \
-
	| mipsisa32r6-* | mipsisa32r6el-* \
-
	| mipsisa64-* | mipsisa64el-* \
-
	| mipsisa64r2-* | mipsisa64r2el-* \
-
	| mipsisa64r6-* | mipsisa64r6el-* \
-
	| mipsisa64sb1-* | mipsisa64sb1el-* \
-
	| mipsisa64sr71k-* | mipsisa64sr71kel-* \
-
	| mipsr5900-* | mipsr5900el-* \
-
	| mipstx39-* | mipstx39el-* \
-
	| mmix-* \
-
	| mt-* \
-
	| msp430-* \
-
	| nds32-* | nds32le-* | nds32be-* \
-
	| nios-* | nios2-* | nios2eb-* | nios2el-* \
-
	| none-* | np1-* | ns16k-* | ns32k-* \
-
	| open8-* \
-
	| or1k*-* \
-
	| orion-* \
-
	| pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
-
	| powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \
-
	| pru-* \
-
	| pyramid-* \
-
	| riscv32-* | riscv64-* \
-
	| rl78-* | romp-* | rs6000-* | rx-* \
-
	| sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \
-
	| shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \
-
	| sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \
-
	| sparclite-* \
-
	| sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx*-* \
-
	| tahoe-* \
-
	| tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \
-
	| tile*-* \
-
	| tron-* \
-
	| ubicom32-* \
-
	| v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \
-
	| vax-* \
-
	| visium-* \
-
	| wasm32-* \
-
	| we32k-* \
-
	| x86-* | x86_64-* | xc16x-* | xps100-* \
-
	| xstormy16-* | xtensa*-* \
-
	| ymp-* \
-
	| z8k-* | z80-*)
-
		;;
-
	# Recognize the basic CPU types without company name, with glob match.
-
	xtensa*)
-
		basic_machine=$basic_machine-unknown
-
		;;
	# Recognize the various machine names and aliases which stand
	# for a CPU type and a company and sometimes even an OS.
-
	386bsd)
-
		basic_machine=i386-pc
-
		os=-bsd
-
		;;
	3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc)
-
		basic_machine=m68000-att
+
		cpu=m68000
+
		vendor=att
		;;
	3b*)
-
		basic_machine=we32k-att
-
		;;
-
	a29khif)
-
		basic_machine=a29k-amd
-
		os=-udi
-
		;;
-
	abacus)
-
		basic_machine=abacus-unknown
-
		;;
-
	adobe68k)
-
		basic_machine=m68010-adobe
-
		os=-scout
-
		;;
-
	alliant | fx80)
-
		basic_machine=fx80-alliant
-
		;;
-
	altos | altos3068)
-
		basic_machine=m68k-altos
-
		;;
-
	am29k)
-
		basic_machine=a29k-none
-
		os=-bsd
-
		;;
-
	amd64)
-
		basic_machine=x86_64-pc
-
		;;
-
	amd64-*)
-
		basic_machine=x86_64-`echo "$basic_machine" | sed 's/^[^-]*-//'`
-
		;;
-
	amdahl)
-
		basic_machine=580-amdahl
-
		os=-sysv
-
		;;
-
	amiga | amiga-*)
-
		basic_machine=m68k-unknown
-
		;;
-
	amigaos | amigados)
-
		basic_machine=m68k-unknown
-
		os=-amigaos
-
		;;
-
	amigaunix | amix)
-
		basic_machine=m68k-unknown
-
		os=-sysv4
-
		;;
-
	apollo68)
-
		basic_machine=m68k-apollo
-
		os=-sysv
-
		;;
-
	apollo68bsd)
-
		basic_machine=m68k-apollo
-
		os=-bsd
-
		;;
-
	aros)
-
		basic_machine=i386-pc
-
		os=-aros
-
		;;
-
	asmjs)
-
		basic_machine=asmjs-unknown
-
		;;
-
	aux)
-
		basic_machine=m68k-apple
-
		os=-aux
-
		;;
-
	balance)
-
		basic_machine=ns32k-sequent
-
		os=-dynix
-
		;;
-
	blackfin)
-
		basic_machine=bfin-unknown
-
		os=-linux
-
		;;
-
	blackfin-*)
-
		basic_machine=bfin-`echo "$basic_machine" | sed 's/^[^-]*-//'`
-
		os=-linux
+
		cpu=we32k
+
		vendor=att
		;;
	bluegene*)
-
		basic_machine=powerpc-ibm
-
		os=-cnk
-
		;;
-
	c54x-*)
-
		basic_machine=tic54x-`echo "$basic_machine" | sed 's/^[^-]*-//'`
-
		;;
-
	c55x-*)
-
		basic_machine=tic55x-`echo "$basic_machine" | sed 's/^[^-]*-//'`
-
		;;
-
	c6x-*)
-
		basic_machine=tic6x-`echo "$basic_machine" | sed 's/^[^-]*-//'`
-
		;;
-
	c90)
-
		basic_machine=c90-cray
-
		os=-unicos
-
		;;
-
	cegcc)
-
		basic_machine=arm-unknown
-
		os=-cegcc
-
		;;
-
	convex-c1)
-
		basic_machine=c1-convex
-
		os=-bsd
-
		;;
-
	convex-c2)
-
		basic_machine=c2-convex
-
		os=-bsd
-
		;;
-
	convex-c32)
-
		basic_machine=c32-convex
-
		os=-bsd
-
		;;
-
	convex-c34)
-
		basic_machine=c34-convex
-
		os=-bsd
-
		;;
-
	convex-c38)
-
		basic_machine=c38-convex
-
		os=-bsd
-
		;;
-
	cray | j90)
-
		basic_machine=j90-cray
-
		os=-unicos
-
		;;
-
	craynv)
-
		basic_machine=craynv-cray
-
		os=-unicosmp
-
		;;
-
	cr16 | cr16-*)
-
		basic_machine=cr16-unknown
-
		os=-elf
-
		;;
-
	crds | unos)
-
		basic_machine=m68k-crds
-
		;;
-
	crisv32 | crisv32-* | etraxfs*)
-
		basic_machine=crisv32-axis
-
		;;
-
	cris | cris-* | etrax*)
-
		basic_machine=cris-axis
-
		;;
-
	crx)
-
		basic_machine=crx-unknown
-
		os=-elf
-
		;;
-
	da30 | da30-*)
-
		basic_machine=m68k-da30
-
		;;
-
	decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn)
-
		basic_machine=mips-dec
+
		cpu=powerpc
+
		vendor=ibm
+
		basic_os=cnk
		;;
	decsystem10* | dec10*)
-
		basic_machine=pdp10-dec
-
		os=-tops10
+
		cpu=pdp10
+
		vendor=dec
+
		basic_os=tops10
		;;
	decsystem20* | dec20*)
-
		basic_machine=pdp10-dec
-
		os=-tops20
+
		cpu=pdp10
+
		vendor=dec
+
		basic_os=tops20
		;;
	delta | 3300 | motorola-3300 | motorola-delta \
	      | 3300-motorola | delta-motorola)
-
		basic_machine=m68k-motorola
-
		;;
-
	delta88)
-
		basic_machine=m88k-motorola
-
		os=-sysv3
-
		;;
-
	dicos)
-
		basic_machine=i686-pc
-
		os=-dicos
-
		;;
-
	djgpp)
-
		basic_machine=i586-pc
-
		os=-msdosdjgpp
-
		;;
-
	dpx20 | dpx20-*)
-
		basic_machine=rs6000-bull
-
		os=-bosx
+
		cpu=m68k
+
		vendor=motorola
		;;
	dpx2*)
-
		basic_machine=m68k-bull
-
		os=-sysv3
-
		;;
-
	e500v[12])
-
		basic_machine=powerpc-unknown
-
		os=$os"spe"
-
		;;
-
	e500v[12]-*)
-
		basic_machine=powerpc-`echo "$basic_machine" | sed 's/^[^-]*-//'`
-
		os=$os"spe"
-
		;;
-
	ebmon29k)
-
		basic_machine=a29k-amd
-
		os=-ebmon
-
		;;
-
	elxsi)
-
		basic_machine=elxsi-elxsi
-
		os=-bsd
+
		cpu=m68k
+
		vendor=bull
+
		basic_os=sysv3
		;;
	encore | umax | mmax)
-
		basic_machine=ns32k-encore
+
		cpu=ns32k
+
		vendor=encore
		;;
-
	es1800 | OSE68k | ose68k | ose | OSE)
-
		basic_machine=m68k-ericsson
-
		os=-ose
+
	elxsi)
+
		cpu=elxsi
+
		vendor=elxsi
+
		basic_os=${basic_os:-bsd}
		;;
	fx2800)
-
		basic_machine=i860-alliant
+
		cpu=i860
+
		vendor=alliant
		;;
	genix)
-
		basic_machine=ns32k-ns
-
		;;
-
	gmicro)
-
		basic_machine=tron-gmicro
-
		os=-sysv
-
		;;
-
	go32)
-
		basic_machine=i386-pc
-
		os=-go32
+
		cpu=ns32k
+
		vendor=ns
		;;
	h3050r* | hiux*)
-
		basic_machine=hppa1.1-hitachi
-
		os=-hiuxwe2
-
		;;
-
	h8300hms)
-
		basic_machine=h8300-hitachi
-
		os=-hms
-
		;;
-
	h8300xray)
-
		basic_machine=h8300-hitachi
-
		os=-xray
-
		;;
-
	h8500hms)
-
		basic_machine=h8500-hitachi
-
		os=-hms
-
		;;
-
	harris)
-
		basic_machine=m88k-harris
-
		os=-sysv3
-
		;;
-
	hp300-*)
-
		basic_machine=m68k-hp
-
		;;
-
	hp300bsd)
-
		basic_machine=m68k-hp
-
		os=-bsd
-
		;;
-
	hp300hpux)
-
		basic_machine=m68k-hp
-
		os=-hpux
+
		cpu=hppa1.1
+
		vendor=hitachi
+
		basic_os=hiuxwe2
		;;
	hp3k9[0-9][0-9] | hp9[0-9][0-9])
-
		basic_machine=hppa1.0-hp
+
		cpu=hppa1.0
+
		vendor=hp
		;;
	hp9k2[0-9][0-9] | hp9k31[0-9])
-
		basic_machine=m68000-hp
+
		cpu=m68000
+
		vendor=hp
		;;
	hp9k3[2-9][0-9])
-
		basic_machine=m68k-hp
+
		cpu=m68k
+
		vendor=hp
		;;
	hp9k6[0-9][0-9] | hp6[0-9][0-9])
-
		basic_machine=hppa1.0-hp
+
		cpu=hppa1.0
+
		vendor=hp
		;;
	hp9k7[0-79][0-9] | hp7[0-79][0-9])
-
		basic_machine=hppa1.1-hp
+
		cpu=hppa1.1
+
		vendor=hp
		;;
	hp9k78[0-9] | hp78[0-9])
		# FIXME: really hppa2.0-hp
-
		basic_machine=hppa1.1-hp
+
		cpu=hppa1.1
+
		vendor=hp
		;;
	hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893)
		# FIXME: really hppa2.0-hp
-
		basic_machine=hppa1.1-hp
+
		cpu=hppa1.1
+
		vendor=hp
		;;
	hp9k8[0-9][13679] | hp8[0-9][13679])
-
		basic_machine=hppa1.1-hp
+
		cpu=hppa1.1
+
		vendor=hp
		;;
	hp9k8[0-9][0-9] | hp8[0-9][0-9])
-
		basic_machine=hppa1.0-hp
-
		;;
-
	hppaosf)
-
		basic_machine=hppa1.1-hp
-
		os=-osf
-
		;;
-
	hppro)
-
		basic_machine=hppa1.1-hp
-
		os=-proelf
-
		;;
-
	i370-ibm* | ibm*)
-
		basic_machine=i370-ibm
+
		cpu=hppa1.0
+
		vendor=hp
		;;
	i*86v32)
-
		basic_machine=`echo "$1" | sed -e 's/86.*/86-pc/'`
-
		os=-sysv32
+
		cpu=`echo "$1" | sed -e 's/86.*/86/'`
+
		vendor=pc
+
		basic_os=sysv32
		;;
	i*86v4*)
-
		basic_machine=`echo "$1" | sed -e 's/86.*/86-pc/'`
-
		os=-sysv4
+
		cpu=`echo "$1" | sed -e 's/86.*/86/'`
+
		vendor=pc
+
		basic_os=sysv4
		;;
	i*86v)
-
		basic_machine=`echo "$1" | sed -e 's/86.*/86-pc/'`
-
		os=-sysv
+
		cpu=`echo "$1" | sed -e 's/86.*/86/'`
+
		vendor=pc
+
		basic_os=sysv
		;;
	i*86sol2)
-
		basic_machine=`echo "$1" | sed -e 's/86.*/86-pc/'`
-
		os=-solaris2
-
		;;
-
	i386mach)
-
		basic_machine=i386-mach
-
		os=-mach
+
		cpu=`echo "$1" | sed -e 's/86.*/86/'`
+
		vendor=pc
+
		basic_os=solaris2
		;;
-
	vsta)
-
		basic_machine=i386-unknown
-
		os=-vsta
+
	j90 | j90-cray)
+
		cpu=j90
+
		vendor=cray
+
		basic_os=${basic_os:-unicos}
		;;
	iris | iris4d)
-
		basic_machine=mips-sgi
-
		case $os in
-
		    -irix*)
+
		cpu=mips
+
		vendor=sgi
+
		case $basic_os in
+
		    irix*)
			;;
		    *)
-
			os=-irix4
+
			basic_os=irix4
			;;
		esac
		;;
-
	isi68 | isi)
-
		basic_machine=m68k-isi
-
		os=-sysv
-
		;;
-
	leon-*|leon[3-9]-*)
-
		basic_machine=sparc-`echo "$basic_machine" | sed 's/-.*//'`
-
		;;
-
	m68knommu)
-
		basic_machine=m68k-unknown
-
		os=-linux
-
		;;
-
	m68knommu-*)
-
		basic_machine=m68k-`echo "$basic_machine" | sed 's/^[^-]*-//'`
-
		os=-linux
-
		;;
-
	magnum | m3230)
-
		basic_machine=mips-mips
-
		os=-sysv
-
		;;
-
	merlin)
-
		basic_machine=ns32k-utek
-
		os=-sysv
-
		;;
-
	microblaze*)
-
		basic_machine=microblaze-xilinx
-
		;;
-
	mingw64)
-
		basic_machine=x86_64-pc
-
		os=-mingw64
-
		;;
-
	mingw32)
-
		basic_machine=i686-pc
-
		os=-mingw32
-
		;;
-
	mingw32ce)
-
		basic_machine=arm-unknown
-
		os=-mingw32ce
-
		;;
	miniframe)
-
		basic_machine=m68000-convergent
-
		;;
-
	*mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*)
-
		basic_machine=m68k-atari
-
		os=-mint
-
		;;
-
	mips3*-*)
-
		basic_machine=`echo "$basic_machine" | sed -e 's/mips3/mips64/'`
-
		;;
-
	mips3*)
-
		basic_machine=`echo "$basic_machine" | sed -e 's/mips3/mips64/'`-unknown
-
		;;
-
	monitor)
-
		basic_machine=m68k-rom68k
-
		os=-coff
-
		;;
-
	morphos)
-
		basic_machine=powerpc-unknown
-
		os=-morphos
-
		;;
-
	moxiebox)
-
		basic_machine=moxie-unknown
-
		os=-moxiebox
-
		;;
-
	msdos)
-
		basic_machine=i386-pc
-
		os=-msdos
-
		;;
-
	ms1-*)
-
		basic_machine=`echo "$basic_machine" | sed -e 's/ms1-/mt-/'`
-
		;;
-
	msys)
-
		basic_machine=i686-pc
-
		os=-msys
-
		;;
-
	mvs)
-
		basic_machine=i370-ibm
-
		os=-mvs
-
		;;
-
	nacl)
-
		basic_machine=le32-unknown
-
		os=-nacl
-
		;;
-
	ncr3000)
-
		basic_machine=i486-ncr
-
		os=-sysv4
-
		;;
-
	netbsd386)
-
		basic_machine=i386-unknown
-
		os=-netbsd
-
		;;
-
	netwinder)
-
		basic_machine=armv4l-rebel
-
		os=-linux
-
		;;
-
	news | news700 | news800 | news900)
-
		basic_machine=m68k-sony
-
		os=-newsos
+
		cpu=m68000
+
		vendor=convergent
		;;
-
	news1000)
-
		basic_machine=m68030-sony
-
		os=-newsos
+
	*mint | mint[0-9]* | *MiNT | *MiNT[0-9]*)
+
		cpu=m68k
+
		vendor=atari
+
		basic_os=mint
		;;
	news-3600 | risc-news)
-
		basic_machine=mips-sony
-
		os=-newsos
-
		;;
-
	necv70)
-
		basic_machine=v70-nec
-
		os=-sysv
+
		cpu=mips
+
		vendor=sony
+
		basic_os=newsos
		;;
	next | m*-next)
-
		basic_machine=m68k-next
-
		case $os in
-
		    -nextstep* )
+
		cpu=m68k
+
		vendor=next
+
		case $basic_os in
+
		    openstep*)
+
		        ;;
+
		    nextstep*)
			;;
-
		    -ns2*)
-
		      os=-nextstep2
+
		    ns2*)
+
		      basic_os=nextstep2
			;;
		    *)
-
		      os=-nextstep3
+
		      basic_os=nextstep3
			;;
		esac
		;;
-
	nh3000)
-
		basic_machine=m68k-harris
-
		os=-cxux
-
		;;
-
	nh[45]000)
-
		basic_machine=m88k-harris
-
		os=-cxux
-
		;;
-
	nindy960)
-
		basic_machine=i960-intel
-
		os=-nindy
-
		;;
-
	mon960)
-
		basic_machine=i960-intel
-
		os=-mon960
-
		;;
-
	nonstopux)
-
		basic_machine=mips-compaq
-
		os=-nonstopux
-
		;;
	np1)
-
		basic_machine=np1-gould
-
		;;
-
	neo-tandem)
-
		basic_machine=neo-tandem
-
		;;
-
	nse-tandem)
-
		basic_machine=nse-tandem
-
		;;
-
	nsr-tandem)
-
		basic_machine=nsr-tandem
-
		;;
-
	nsv-tandem)
-
		basic_machine=nsv-tandem
-
		;;
-
	nsx-tandem)
-
		basic_machine=nsx-tandem
+
		cpu=np1
+
		vendor=gould
		;;
	op50n-* | op60c-*)
-
		basic_machine=hppa1.1-oki
-
		os=-proelf
-
		;;
-
	openrisc | openrisc-*)
-
		basic_machine=or32-unknown
-
		;;
-
	os400)
-
		basic_machine=powerpc-ibm
-
		os=-os400
-
		;;
-
	OSE68000 | ose68000)
-
		basic_machine=m68000-ericsson
-
		os=-ose
-
		;;
-
	os68k)
-
		basic_machine=m68k-none
-
		os=-os68k
+
		cpu=hppa1.1
+
		vendor=oki
+
		basic_os=proelf
		;;
	pa-hitachi)
-
		basic_machine=hppa1.1-hitachi
-
		os=-hiuxwe2
-
		;;
-
	paragon)
-
		basic_machine=i860-intel
-
		os=-osf
-
		;;
-
	parisc)
-
		basic_machine=hppa-unknown
-
		os=-linux
-
		;;
-
	parisc-*)
-
		basic_machine=hppa-`echo "$basic_machine" | sed 's/^[^-]*-//'`
-
		os=-linux
+
		cpu=hppa1.1
+
		vendor=hitachi
+
		basic_os=hiuxwe2
		;;
	pbd)
-
		basic_machine=sparc-tti
+
		cpu=sparc
+
		vendor=tti
		;;
	pbb)
-
		basic_machine=m68k-tti
-
		;;
-
	pc532 | pc532-*)
-
		basic_machine=ns32k-pc532
-
		;;
-
	pc98)
-
		basic_machine=i386-pc
-
		;;
-
	pc98-*)
-
		basic_machine=i386-`echo "$basic_machine" | sed 's/^[^-]*-//'`
+
		cpu=m68k
+
		vendor=tti
		;;
-
	pentium | p5 | k5 | k6 | nexgen | viac3)
-
		basic_machine=i586-pc
-
		;;
-
	pentiumpro | p6 | 6x86 | athlon | athlon_*)
-
		basic_machine=i686-pc
-
		;;
-
	pentiumii | pentium2 | pentiumiii | pentium3)
-
		basic_machine=i686-pc
-
		;;
-
	pentium4)
-
		basic_machine=i786-pc
-
		;;
-
	pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*)
-
		basic_machine=i586-`echo "$basic_machine" | sed 's/^[^-]*-//'`
-
		;;
-
	pentiumpro-* | p6-* | 6x86-* | athlon-*)
-
		basic_machine=i686-`echo "$basic_machine" | sed 's/^[^-]*-//'`
-
		;;
-
	pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*)
-
		basic_machine=i686-`echo "$basic_machine" | sed 's/^[^-]*-//'`
-
		;;
-
	pentium4-*)
-
		basic_machine=i786-`echo "$basic_machine" | sed 's/^[^-]*-//'`
+
	pc532)
+
		cpu=ns32k
+
		vendor=pc532
		;;
	pn)
-
		basic_machine=pn-gould
-
		;;
-
	power)	basic_machine=power-ibm
-
		;;
-
	ppc | ppcbe)	basic_machine=powerpc-unknown
-
		;;
-
	ppc-* | ppcbe-*)
-
		basic_machine=powerpc-`echo "$basic_machine" | sed 's/^[^-]*-//'`
+
		cpu=pn
+
		vendor=gould
		;;
-
	ppcle | powerpclittle)
-
		basic_machine=powerpcle-unknown
+
	power)
+
		cpu=power
+
		vendor=ibm
		;;
-
	ppcle-* | powerpclittle-*)
-
		basic_machine=powerpcle-`echo "$basic_machine" | sed 's/^[^-]*-//'`
-
		;;
-
	ppc64)	basic_machine=powerpc64-unknown
+
	ps2)
+
		cpu=i386
+
		vendor=ibm
		;;
-
	ppc64-*) basic_machine=powerpc64-`echo "$basic_machine" | sed 's/^[^-]*-//'`
+
	rm[46]00)
+
		cpu=mips
+
		vendor=siemens
		;;
-
	ppc64le | powerpc64little)
-
		basic_machine=powerpc64le-unknown
+
	rtpc | rtpc-*)
+
		cpu=romp
+
		vendor=ibm
		;;
-
	ppc64le-* | powerpc64little-*)
-
		basic_machine=powerpc64le-`echo "$basic_machine" | sed 's/^[^-]*-//'`
+
	sde)
+
		cpu=mipsisa32
+
		vendor=sde
+
		basic_os=${basic_os:-elf}
		;;
-
	ps2)
-
		basic_machine=i386-ibm
+
	simso-wrs)
+
		cpu=sparclite
+
		vendor=wrs
+
		basic_os=vxworks
		;;
-
	pw32)
-
		basic_machine=i586-unknown
-
		os=-pw32
+
	tower | tower-32)
+
		cpu=m68k
+
		vendor=ncr
		;;
-
	rdos | rdos64)
-
		basic_machine=x86_64-pc
-
		os=-rdos
+
	vpp*|vx|vx-*)
+
		cpu=f301
+
		vendor=fujitsu
		;;
-
	rdos32)
-
		basic_machine=i386-pc
-
		os=-rdos
+
	w65)
+
		cpu=w65
+
		vendor=wdc
		;;
-
	rom68k)
-
		basic_machine=m68k-rom68k
-
		os=-coff
+
	w89k-*)
+
		cpu=hppa1.1
+
		vendor=winbond
+
		basic_os=proelf
		;;
-
	rm[46]00)
-
		basic_machine=mips-siemens
+
	none)
+
		cpu=none
+
		vendor=none
		;;
-
	rtpc | rtpc-*)
-
		basic_machine=romp-ibm
+
	leon|leon[3-9])
+
		cpu=sparc
+
		vendor=$basic_machine
		;;
-
	s390 | s390-*)
-
		basic_machine=s390-ibm
+
	leon-*|leon[3-9]-*)
+
		cpu=sparc
+
		vendor=`echo "$basic_machine" | sed 's/-.*//'`
		;;
-
	s390x | s390x-*)
-
		basic_machine=s390x-ibm
+

+
	*-*)
+
		# shellcheck disable=SC2162
+
		IFS="-" read cpu vendor <<EOF
+
$basic_machine
+
EOF
		;;
-
	sa29200)
-
		basic_machine=a29k-amd
-
		os=-udi
+
	# We use `pc' rather than `unknown'
+
	# because (1) that's what they normally are, and
+
	# (2) the word "unknown" tends to confuse beginning users.
+
	i*86 | x86_64)
+
		cpu=$basic_machine
+
		vendor=pc
		;;
-
	sb1)
-
		basic_machine=mipsisa64sb1-unknown
+
	# These rules are duplicated from below for sake of the special case above;
+
	# i.e. things that normalized to x86 arches should also default to "pc"
+
	pc98)
+
		cpu=i386
+
		vendor=pc
		;;
-
	sb1el)
-
		basic_machine=mipsisa64sb1el-unknown
+
	x64 | amd64)
+
		cpu=x86_64
+
		vendor=pc
		;;
-
	sde)
-
		basic_machine=mipsisa32-sde
-
		os=-elf
+
	# Recognize the basic CPU types without company name.
+
	*)
+
		cpu=$basic_machine
+
		vendor=unknown
		;;
-
	sei)
-
		basic_machine=mips-sei
-
		os=-seiux
+
esac
+

+
unset -v basic_machine
+

+
# Decode basic machines in the full and proper CPU-Company form.
+
case $cpu-$vendor in
+
	# Here we handle the default manufacturer of certain CPU types in canonical form. It is in
+
	# some cases the only manufacturer, in others, it is the most popular.
+
	craynv-unknown)
+
		vendor=cray
+
		basic_os=${basic_os:-unicosmp}
		;;
-
	sequent)
-
		basic_machine=i386-sequent
+
	c90-unknown | c90-cray)
+
		vendor=cray
+
		basic_os=${Basic_os:-unicos}
		;;
-
	sh5el)
-
		basic_machine=sh5le-unknown
+
	fx80-unknown)
+
		vendor=alliant
		;;
-
	simso-wrs)
-
		basic_machine=sparclite-wrs
-
		os=-vxworks
+
	romp-unknown)
+
		vendor=ibm
		;;
-
	sps7)
-
		basic_machine=m68k-bull
-
		os=-sysv2
+
	mmix-unknown)
+
		vendor=knuth
		;;
-
	spur)
-
		basic_machine=spur-unknown
+
	microblaze-unknown | microblazeel-unknown)
+
		vendor=xilinx
		;;
-
	st2000)
-
		basic_machine=m68k-tandem
+
	rs6000-unknown)
+
		vendor=ibm
		;;
-
	stratus)
-
		basic_machine=i860-stratus
-
		os=-sysv4
+
	vax-unknown)
+
		vendor=dec
		;;
-
	strongarm-* | thumb-*)
-
		basic_machine=arm-`echo "$basic_machine" | sed 's/^[^-]*-//'`
+
	pdp11-unknown)
+
		vendor=dec
		;;
-
	sun2)
-
		basic_machine=m68000-sun
+
	we32k-unknown)
+
		vendor=att
		;;
-
	sun2os3)
-
		basic_machine=m68000-sun
-
		os=-sunos3
+
	cydra-unknown)
+
		vendor=cydrome
		;;
-
	sun2os4)
-
		basic_machine=m68000-sun
-
		os=-sunos4
+
	i370-ibm*)
+
		vendor=ibm
		;;
-
	sun3os3)
-
		basic_machine=m68k-sun
-
		os=-sunos3
+
	orion-unknown)
+
		vendor=highlevel
		;;
-
	sun3os4)
-
		basic_machine=m68k-sun
-
		os=-sunos4
+
	xps-unknown | xps100-unknown)
+
		cpu=xps100
+
		vendor=honeywell
		;;
-
	sun4os3)
-
		basic_machine=sparc-sun
-
		os=-sunos3
+

+
	# Here we normalize CPU types with a missing or matching vendor
+
	dpx20-unknown | dpx20-bull)
+
		cpu=rs6000
+
		vendor=bull
+
		basic_os=${basic_os:-bosx}
		;;
-
	sun4os4)
-
		basic_machine=sparc-sun
-
		os=-sunos4
+

+
	# Here we normalize CPU types irrespective of the vendor
+
	amd64-*)
+
		cpu=x86_64
		;;
-
	sun4sol2)
-
		basic_machine=sparc-sun
-
		os=-solaris2
+
	blackfin-*)
+
		cpu=bfin
+
		basic_os=linux
		;;
-
	sun3 | sun3-*)
-
		basic_machine=m68k-sun
+
	c54x-*)
+
		cpu=tic54x
		;;
-
	sun4)
-
		basic_machine=sparc-sun
+
	c55x-*)
+
		cpu=tic55x
		;;
-
	sun386 | sun386i | roadrunner)
-
		basic_machine=i386-sun
+
	c6x-*)
+
		cpu=tic6x
		;;
-
	sv1)
-
		basic_machine=sv1-cray
-
		os=-unicos
+
	e500v[12]-*)
+
		cpu=powerpc
+
		basic_os=${basic_os}"spe"
		;;
-
	symmetry)
-
		basic_machine=i386-sequent
-
		os=-dynix
+
	mips3*-*)
+
		cpu=mips64
		;;
-
	t3e)
-
		basic_machine=alphaev5-cray
-
		os=-unicos
+
	ms1-*)
+
		cpu=mt
		;;
-
	t90)
-
		basic_machine=t90-cray
-
		os=-unicos
+
	m68knommu-*)
+
		cpu=m68k
+
		basic_os=linux
		;;
-
	tile*)
-
		basic_machine=$basic_machine-unknown
-
		os=-linux-gnu
+
	m9s12z-* | m68hcs12z-* | hcs12z-* | s12z-*)
+
		cpu=s12z
		;;
-
	tx39)
-
		basic_machine=mipstx39-unknown
+
	openrisc-*)
+
		cpu=or32
		;;
-
	tx39el)
-
		basic_machine=mipstx39el-unknown
+
	parisc-*)
+
		cpu=hppa
+
		basic_os=linux
		;;
-
	toad1)
-
		basic_machine=pdp10-xkl
-
		os=-tops20
+
	pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*)
+
		cpu=i586
		;;
-
	tower | tower-32)
-
		basic_machine=m68k-ncr
+
	pentiumpro-* | p6-* | 6x86-* | athlon-* | athalon_*-*)
+
		cpu=i686
		;;
-
	tpf)
-
		basic_machine=s390x-ibm
-
		os=-tpf
+
	pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*)
+
		cpu=i686
		;;
-
	udi29k)
-
		basic_machine=a29k-amd
-
		os=-udi
+
	pentium4-*)
+
		cpu=i786
		;;
-
	ultra3)
-
		basic_machine=a29k-nyu
-
		os=-sym1
+
	pc98-*)
+
		cpu=i386
		;;
-
	v810 | necv810)
-
		basic_machine=v810-nec
-
		os=-none
+
	ppc-* | ppcbe-*)
+
		cpu=powerpc
		;;
-
	vaxv)
-
		basic_machine=vax-dec
-
		os=-sysv
+
	ppcle-* | powerpclittle-*)
+
		cpu=powerpcle
		;;
-
	vms)
-
		basic_machine=vax-dec
-
		os=-vms
+
	ppc64-*)
+
		cpu=powerpc64
		;;
-
	vpp*|vx|vx-*)
-
		basic_machine=f301-fujitsu
+
	ppc64le-* | powerpc64little-*)
+
		cpu=powerpc64le
		;;
-
	vxworks960)
-
		basic_machine=i960-wrs
-
		os=-vxworks
+
	sb1-*)
+
		cpu=mipsisa64sb1
		;;
-
	vxworks68)
-
		basic_machine=m68k-wrs
-
		os=-vxworks
+
	sb1el-*)
+
		cpu=mipsisa64sb1el
		;;
-
	vxworks29k)
-
		basic_machine=a29k-wrs
-
		os=-vxworks
+
	sh5e[lb]-*)
+
		cpu=`echo "$cpu" | sed 's/^\(sh.\)e\(.\)$/\1\2e/'`
		;;
-
	w65*)
-
		basic_machine=w65-wdc
-
		os=-none
+
	spur-*)
+
		cpu=spur
		;;
-
	w89k-*)
-
		basic_machine=hppa1.1-winbond
-
		os=-proelf
+
	strongarm-* | thumb-*)
+
		cpu=arm
		;;
-
	x64)
-
		basic_machine=x86_64-pc
+
	tx39-*)
+
		cpu=mipstx39
		;;
-
	xbox)
-
		basic_machine=i686-pc
-
		os=-mingw32
+
	tx39el-*)
+
		cpu=mipstx39el
		;;
-
	xps | xps100)
-
		basic_machine=xps100-honeywell
+
	x64-*)
+
		cpu=x86_64
		;;
	xscale-* | xscalee[bl]-*)
-
		basic_machine=`echo "$basic_machine" | sed 's/^xscale/arm/'`
+
		cpu=`echo "$cpu" | sed 's/^xscale/arm/'`
		;;
-
	ymp)
-
		basic_machine=ymp-cray
-
		os=-unicos
-
		;;
-
	none)
-
		basic_machine=none-none
-
		os=-none
+
	arm64-*)
+
		cpu=aarch64
		;;

-
# Here we handle the default manufacturer of certain CPU types.  It is in
-
# some cases the only manufacturer, in others, it is the most popular.
-
	w89k)
-
		basic_machine=hppa1.1-winbond
-
		;;
-
	op50n)
-
		basic_machine=hppa1.1-oki
-
		;;
-
	op60c)
-
		basic_machine=hppa1.1-oki
-
		;;
-
	romp)
-
		basic_machine=romp-ibm
+
	# Recognize the canonical CPU Types that limit and/or modify the
+
	# company names they are paired with.
+
	cr16-*)
+
		basic_os=${basic_os:-elf}
		;;
-
	mmix)
-
		basic_machine=mmix-knuth
+
	crisv32-* | etraxfs*-*)
+
		cpu=crisv32
+
		vendor=axis
		;;
-
	rs6000)
-
		basic_machine=rs6000-ibm
+
	cris-* | etrax*-*)
+
		cpu=cris
+
		vendor=axis
		;;
-
	vax)
-
		basic_machine=vax-dec
+
	crx-*)
+
		basic_os=${basic_os:-elf}
		;;
-
	pdp11)
-
		basic_machine=pdp11-dec
-
		;;
-
	we32k)
-
		basic_machine=we32k-att
-
		;;
-
	sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele)
-
		basic_machine=sh-unknown
+
	neo-tandem)
+
		cpu=neo
+
		vendor=tandem
		;;
-
	cydra)
-
		basic_machine=cydra-cydrome
+
	nse-tandem)
+
		cpu=nse
+
		vendor=tandem
		;;
-
	orion)
-
		basic_machine=orion-highlevel
+
	nsr-tandem)
+
		cpu=nsr
+
		vendor=tandem
		;;
-
	orion105)
-
		basic_machine=clipper-highlevel
+
	nsv-tandem)
+
		cpu=nsv
+
		vendor=tandem
		;;
-
	mac | mpw | mac-mpw)
-
		basic_machine=m68k-apple
+
	nsx-tandem)
+
		cpu=nsx
+
		vendor=tandem
		;;
-
	pmac | pmac-mpw)
-
		basic_machine=powerpc-apple
+
	mipsallegrexel-sony)
+
		cpu=mipsallegrexel
+
		vendor=sony
		;;
-
	*-unknown)
-
		# Make sure to match an already-canonicalized machine name.
+
	tile*-*)
+
		basic_os=${basic_os:-linux-gnu}
		;;
+

	*)
-
		echo Invalid configuration \`"$1"\': machine \`"$basic_machine"\' not recognized 1>&2
-
		exit 1
+
		# Recognize the canonical CPU types that are allowed with any
+
		# company name.
+
		case $cpu in
+
			1750a | 580 \
+
			| a29k \
+
			| aarch64 | aarch64_be \
+
			| abacus \
+
			| alpha | alphaev[4-8] | alphaev56 | alphaev6[78] \
+
			| alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] \
+
			| alphapca5[67] | alpha64pca5[67] \
+
			| am33_2.0 \
+
			| amdgcn \
+
			| arc | arceb | arc32 | arc64 \
+
			| arm | arm[lb]e | arme[lb] | armv* \
+
			| avr | avr32 \
+
			| asmjs \
+
			| ba \
+
			| be32 | be64 \
+
			| bfin | bpf | bs2000 \
+
			| c[123]* | c30 | [cjt]90 | c4x \
+
			| c8051 | clipper | craynv | csky | cydra \
+
			| d10v | d30v | dlx | dsp16xx \
+
			| e2k | elxsi | epiphany \
+
			| f30[01] | f700 | fido | fr30 | frv | ft32 | fx80 \
+
			| h8300 | h8500 \
+
			| hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
+
			| hexagon \
+
			| i370 | i*86 | i860 | i960 | ia16 | ia64 \
+
			| ip2k | iq2000 \
+
			| k1om \
+
			| le32 | le64 \
+
			| lm32 \
+
			| loongarch32 | loongarch64 | loongarchx32 \
+
			| m32c | m32r | m32rle \
+
			| m5200 | m68000 | m680[012346]0 | m68360 | m683?2 | m68k \
+
			| m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x \
+
			| m88110 | m88k | maxq | mb | mcore | mep | metag \
+
			| microblaze | microblazeel \
+
			| mips | mipsbe | mipseb | mipsel | mipsle \
+
			| mips16 \
+
			| mips64 | mips64eb | mips64el \
+
			| mips64octeon | mips64octeonel \
+
			| mips64orion | mips64orionel \
+
			| mips64r5900 | mips64r5900el \
+
			| mips64vr | mips64vrel \
+
			| mips64vr4100 | mips64vr4100el \
+
			| mips64vr4300 | mips64vr4300el \
+
			| mips64vr5000 | mips64vr5000el \
+
			| mips64vr5900 | mips64vr5900el \
+
			| mipsisa32 | mipsisa32el \
+
			| mipsisa32r2 | mipsisa32r2el \
+
			| mipsisa32r3 | mipsisa32r3el \
+
			| mipsisa32r5 | mipsisa32r5el \
+
			| mipsisa32r6 | mipsisa32r6el \
+
			| mipsisa64 | mipsisa64el \
+
			| mipsisa64r2 | mipsisa64r2el \
+
			| mipsisa64r3 | mipsisa64r3el \
+
			| mipsisa64r5 | mipsisa64r5el \
+
			| mipsisa64r6 | mipsisa64r6el \
+
			| mipsisa64sb1 | mipsisa64sb1el \
+
			| mipsisa64sr71k | mipsisa64sr71kel \
+
			| mipsr5900 | mipsr5900el \
+
			| mipstx39 | mipstx39el \
+
			| mmix \
+
			| mn10200 | mn10300 \
+
			| moxie \
+
			| mt \
+
			| msp430 \
+
			| nds32 | nds32le | nds32be \
+
			| nfp \
+
			| nios | nios2 | nios2eb | nios2el \
+
			| none | np1 | ns16k | ns32k | nvptx \
+
			| open8 \
+
			| or1k* \
+
			| or32 \
+
			| orion \
+
			| picochip \
+
			| pdp10 | pdp11 | pj | pjl | pn | power \
+
			| powerpc | powerpc64 | powerpc64le | powerpcle | powerpcspe \
+
			| pru \
+
			| pyramid \
+
			| riscv | riscv32 | riscv32be | riscv64 | riscv64be \
+
			| rl78 | romp | rs6000 | rx \
+
			| s390 | s390x \
+
			| score \
+
			| sh | shl \
+
			| sh[1234] | sh[24]a | sh[24]ae[lb] | sh[23]e | she[lb] | sh[lb]e \
+
			| sh[1234]e[lb] |  sh[12345][lb]e | sh[23]ele | sh64 | sh64le \
+
			| sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet \
+
			| sparclite \
+
			| sparcv8 | sparcv9 | sparcv9b | sparcv9v | sv1 | sx* \
+
			| spu \
+
			| tahoe \
+
			| thumbv7* \
+
			| tic30 | tic4x | tic54x | tic55x | tic6x | tic80 \
+
			| tron \
+
			| ubicom32 \
+
			| v70 | v850 | v850e | v850e1 | v850es | v850e2 | v850e2v3 \
+
			| vax \
+
			| visium \
+
			| w65 \
+
			| wasm32 | wasm64 \
+
			| we32k \
+
			| x86 | x86_64 | xc16x | xgate | xps100 \
+
			| xstormy16 | xtensa* \
+
			| ymp \
+
			| z8k | z80)
+
				;;
+

+
			*)
+
				echo Invalid configuration \`"$1"\': machine \`"$cpu-$vendor"\' not recognized 1>&2
+
				exit 1
+
				;;
+
		esac
		;;
esac

# Here we canonicalize certain aliases for manufacturers.
-
case $basic_machine in
-
	*-digital*)
-
		basic_machine=`echo "$basic_machine" | sed 's/digital.*/dec/'`
+
case $vendor in
+
	digital*)
+
		vendor=dec
		;;
-
	*-commodore*)
-
		basic_machine=`echo "$basic_machine" | sed 's/commodore.*/cbm/'`
+
	commodore*)
+
		vendor=cbm
		;;
	*)
		;;
@@ -1334,203 +1293,213 @@ esac

# Decode manufacturer-specific aliases for certain operating systems.

-
if [ x"$os" != x"" ]
+
if test x$basic_os != x
then
+

+
# First recognize some ad-hoc caes, or perhaps split kernel-os, or else just
+
# set os.
+
case $basic_os in
+
	gnu/linux*)
+
		kernel=linux
+
		os=`echo "$basic_os" | sed -e 's|gnu/linux|gnu|'`
+
		;;
+
	os2-emx)
+
		kernel=os2
+
		os=`echo "$basic_os" | sed -e 's|os2-emx|emx|'`
+
		;;
+
	nto-qnx*)
+
		kernel=nto
+
		os=`echo "$basic_os" | sed -e 's|nto-qnx|qnx|'`
+
		;;
+
	*-*)
+
		# shellcheck disable=SC2162
+
		IFS="-" read kernel os <<EOF
+
$basic_os
+
EOF
+
		;;
+
	# Default OS when just kernel was specified
+
	nto*)
+
		kernel=nto
+
		os=`echo "$basic_os" | sed -e 's|nto|qnx|'`
+
		;;
+
	linux*)
+
		kernel=linux
+
		os=`echo "$basic_os" | sed -e 's|linux|gnu|'`
+
		;;
+
	*)
+
		kernel=
+
		os=$basic_os
+
		;;
+
esac
+

+
# Now, normalize the OS (knowing we just have one component, it's not a kernel,
+
# etc.)
case $os in
	# First match some system type aliases that might get confused
	# with valid system types.
-
	# -solaris* is a basic system type, with this one exception.
-
	-auroraux)
-
		os=-auroraux
+
	# solaris* is a basic system type, with this one exception.
+
	auroraux)
+
		os=auroraux
		;;
-
	-solaris1 | -solaris1.*)
-
		os=`echo $os | sed -e 's|solaris1|sunos4|'`
+
	bluegene*)
+
		os=cnk
		;;
-
	-solaris)
-
		os=-solaris2
+
	solaris1 | solaris1.*)
+
		os=`echo "$os" | sed -e 's|solaris1|sunos4|'`
		;;
-
	-unixware*)
-
		os=-sysv4.2uw
+
	solaris)
+
		os=solaris2
		;;
-
	-gnu/linux*)
-
		os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'`
+
	unixware*)
+
		os=sysv4.2uw
		;;
	# es1800 is here to avoid being matched by es* (a different OS)
-
	-es1800*)
-
		os=-ose
+
	es1800*)
+
		os=ose
		;;
-
	# Now accept the basic system types.
-
	# The portable systems comes first.
-
	# Each alternative MUST end in a * to match a version number.
-
	# -sysv* is not here because it comes later, after sysvr4.
-
	-gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \
-
	      | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\
-
	      | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \
-
	      | -sym* | -kopensolaris* | -plan9* \
-
	      | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
-
	      | -aos* | -aros* | -cloudabi* | -sortix* \
-
	      | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
-
	      | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
-
	      | -hiux* | -knetbsd* | -mirbsd* | -netbsd* \
-
	      | -bitrig* | -openbsd* | -solidbsd* | -libertybsd* \
-
	      | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \
-
	      | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
-
	      | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
-
	      | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* | -hcos* \
-
	      | -chorusos* | -chorusrdb* | -cegcc* | -glidix* \
-
	      | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
-
	      | -midipix* | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \
-
	      | -linux-newlib* | -linux-musl* | -linux-uclibc* \
-
	      | -uxpv* | -beos* | -mpeix* | -udk* | -moxiebox* \
-
	      | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* \
-
	      | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \
-
	      | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \
-
	      | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \
-
	      | -morphos* | -superux* | -rtmk* | -windiss* \
-
	      | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \
-
	      | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es* \
-
	      | -onefs* | -tirtos* | -phoenix* | -fuchsia* | -redox* | -bme* \
-
	      | -midnightbsd*)
-
	# Remember, each alternative MUST END IN *, to match a version number.
-
		;;
-
	-qnx*)
-
		case $basic_machine in
-
		    x86-* | i*86-*)
-
			;;
-
		    *)
-
			os=-nto$os
-
			;;
-
		esac
+
	# Some version numbers need modification
+
	chorusos*)
+
		os=chorusos
		;;
-
	-nto-qnx*)
+
	isc)
+
		os=isc2.2
		;;
-
	-nto*)
-
		os=`echo $os | sed -e 's|nto|nto-qnx|'`
+
	sco6)
+
		os=sco5v6
		;;
-
	-sim | -xray | -os68k* | -v88r* \
-
	      | -windows* | -osx | -abug | -netware* | -os9* \
-
	      | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*)
+
	sco5)
+
		os=sco3.2v5
		;;
-
	-mac*)
-
		os=`echo "$os" | sed -e 's|mac|macos|'`
+
	sco4)
+
		os=sco3.2v4
		;;
-
	-linux-dietlibc)
-
		os=-linux-dietlibc
+
	sco3.2.[4-9]*)
+
		os=`echo "$os" | sed -e 's/sco3.2./sco3.2v/'`
		;;
-
	-linux*)
-
		os=`echo $os | sed -e 's|linux|linux-gnu|'`
+
	sco*v* | scout)
+
		# Don't match below
		;;
-
	-sunos5*)
-
		os=`echo "$os" | sed -e 's|sunos5|solaris2|'`
+
	sco*)
+
		os=sco3.2v2
		;;
-
	-sunos6*)
-
		os=`echo "$os" | sed -e 's|sunos6|solaris3|'`
+
	psos*)
+
		os=psos
		;;
-
	-opened*)
-
		os=-openedition
+
	qnx*)
+
		os=qnx
		;;
-
	-os400*)
-
		os=-os400
+
	hiux*)
+
		os=hiuxwe2
		;;
-
	-wince*)
-
		os=-wince
+
	lynx*178)
+
		os=lynxos178
		;;
-
	-utek*)
-
		os=-bsd
+
	lynx*5)
+
		os=lynxos5
		;;
-
	-dynix*)
-
		os=-bsd
+
	lynxos*)
+
		# don't get caught up in next wildcard
		;;
-
	-acis*)
-
		os=-aos
+
	lynx*)
+
		os=lynxos
		;;
-
	-atheos*)
-
		os=-atheos
+
	mac[0-9]*)
+
		os=`echo "$os" | sed -e 's|mac|macos|'`
		;;
-
	-syllable*)
-
		os=-syllable
+
	opened*)
+
		os=openedition
		;;
-
	-386bsd)
-
		os=-bsd
+
	os400*)
+
		os=os400
		;;
-
	-ctix* | -uts*)
-
		os=-sysv
+
	sunos5*)
+
		os=`echo "$os" | sed -e 's|sunos5|solaris2|'`
		;;
-
	-nova*)
-
		os=-rtmk-nova
+
	sunos6*)
+
		os=`echo "$os" | sed -e 's|sunos6|solaris3|'`
		;;
-
	-ns2)
-
		os=-nextstep2
+
	wince*)
+
		os=wince
		;;
-
	-nsk*)
-
		os=-nsk
+
	utek*)
+
		os=bsd
		;;
-
	# Preserve the version number of sinix5.
-
	-sinix5.*)
-
		os=`echo $os | sed -e 's|sinix|sysv|'`
+
	dynix*)
+
		os=bsd
		;;
-
	-sinix*)
-
		os=-sysv4
+
	acis*)
+
		os=aos
		;;
-
	-tpf*)
-
		os=-tpf
+
	atheos*)
+
		os=atheos
		;;
-
	-triton*)
-
		os=-sysv3
+
	syllable*)
+
		os=syllable
		;;
-
	-oss*)
-
		os=-sysv3
+
	386bsd)
+
		os=bsd
		;;
-
	-svr4*)
-
		os=-sysv4
+
	ctix* | uts*)
+
		os=sysv
		;;
-
	-svr3)
-
		os=-sysv3
+
	nova*)
+
		os=rtmk-nova
		;;
-
	-sysvr4)
-
		os=-sysv4
+
	ns2)
+
		os=nextstep2
		;;
-
	# This must come after -sysvr4.
-
	-sysv*)
+
	# Preserve the version number of sinix5.
+
	sinix5.*)
+
		os=`echo "$os" | sed -e 's|sinix|sysv|'`
		;;
-
	-ose*)
-
		os=-ose
+
	sinix*)
+
		os=sysv4
		;;
-
	-*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
-
		os=-mint
+
	tpf*)
+
		os=tpf
		;;
-
	-zvmoe)
-
		os=-zvmoe
+
	triton*)
+
		os=sysv3
		;;
-
	-dicos*)
-
		os=-dicos
+
	oss*)
+
		os=sysv3
		;;
-
	-pikeos*)
+
	svr4*)
+
		os=sysv4
+
		;;
+
	svr3)
+
		os=sysv3
+
		;;
+
	sysvr4)
+
		os=sysv4
+
		;;
+
	ose*)
+
		os=ose
+
		;;
+
	*mint | mint[0-9]* | *MiNT | MiNT[0-9]*)
+
		os=mint
+
		;;
+
	dicos*)
+
		os=dicos
+
		;;
+
	pikeos*)
		# Until real need of OS specific support for
		# particular features comes up, bare metal
		# configurations are quite functional.
-
		case $basic_machine in
+
		case $cpu in
		    arm*)
-
			os=-eabi
+
			os=eabi
			;;
		    *)
-
			os=-elf
+
			os=elf
			;;
		esac
		;;
-
	-nacl*)
-
		;;
-
	-ios)
-
		;;
-
	-none)
-
		;;
	*)
-
		# Get rid of the `-' at the beginning of $os.
-
		os=`echo $os | sed 's/[^-]*-//'`
-
		echo Invalid configuration \`"$1"\': system \`"$os"\' not recognized 1>&2
-
		exit 1
+
		# No normalization, but not necessarily accepted, that comes below.
		;;
esac
+

else

# Here we handle the default operating systems that come with various machines.
@@ -1543,254 +1512,357 @@ else
# will signal an error saying that MANUFACTURER isn't an operating
# system, and we'll never get to this point.

-
case $basic_machine in
+
kernel=
+
case $cpu-$vendor in
	score-*)
-
		os=-elf
+
		os=elf
		;;
	spu-*)
-
		os=-elf
+
		os=elf
		;;
	*-acorn)
-
		os=-riscix1.2
+
		os=riscix1.2
		;;
	arm*-rebel)
-
		os=-linux
+
		kernel=linux
+
		os=gnu
		;;
	arm*-semi)
-
		os=-aout
+
		os=aout
		;;
	c4x-* | tic4x-*)
-
		os=-coff
+
		os=coff
		;;
	c8051-*)
-
		os=-elf
+
		os=elf
+
		;;
+
	clipper-intergraph)
+
		os=clix
		;;
	hexagon-*)
-
		os=-elf
+
		os=elf
		;;
	tic54x-*)
-
		os=-coff
+
		os=coff
		;;
	tic55x-*)
-
		os=-coff
+
		os=coff
		;;
	tic6x-*)
-
		os=-coff
+
		os=coff
		;;
	# This must come before the *-dec entry.
	pdp10-*)
-
		os=-tops20
+
		os=tops20
		;;
	pdp11-*)
-
		os=-none
+
		os=none
		;;
	*-dec | vax-*)
-
		os=-ultrix4.2
+
		os=ultrix4.2
		;;
	m68*-apollo)
-
		os=-domain
+
		os=domain
		;;
	i386-sun)
-
		os=-sunos4.0.2
+
		os=sunos4.0.2
		;;
	m68000-sun)
-
		os=-sunos3
+
		os=sunos3
		;;
	m68*-cisco)
-
		os=-aout
+
		os=aout
		;;
	mep-*)
-
		os=-elf
+
		os=elf
		;;
	mips*-cisco)
-
		os=-elf
+
		os=elf
		;;
	mips*-*)
-
		os=-elf
+
		os=elf
		;;
	or32-*)
-
		os=-coff
+
		os=coff
		;;
	*-tti)	# must be before sparc entry or we get the wrong os.
-
		os=-sysv3
+
		os=sysv3
		;;
	sparc-* | *-sun)
-
		os=-sunos4.1.1
+
		os=sunos4.1.1
		;;
	pru-*)
-
		os=-elf
+
		os=elf
		;;
	*-be)
-
		os=-beos
+
		os=beos
		;;
	*-ibm)
-
		os=-aix
+
		os=aix
		;;
	*-knuth)
-
		os=-mmixware
+
		os=mmixware
		;;
	*-wec)
-
		os=-proelf
+
		os=proelf
		;;
	*-winbond)
-
		os=-proelf
+
		os=proelf
		;;
	*-oki)
-
		os=-proelf
+
		os=proelf
		;;
	*-hp)
-
		os=-hpux
+
		os=hpux
		;;
	*-hitachi)
-
		os=-hiux
+
		os=hiux
		;;
	i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent)
-
		os=-sysv
+
		os=sysv
		;;
	*-cbm)
-
		os=-amigaos
+
		os=amigaos
		;;
	*-dg)
-
		os=-dgux
+
		os=dgux
		;;
	*-dolphin)
-
		os=-sysv3
+
		os=sysv3
		;;
	m68k-ccur)
-
		os=-rtu
+
		os=rtu
		;;
	m88k-omron*)
-
		os=-luna
+
		os=luna
		;;
	*-next)
-
		os=-nextstep
+
		os=nextstep
		;;
	*-sequent)
-
		os=-ptx
+
		os=ptx
		;;
	*-crds)
-
		os=-unos
+
		os=unos
		;;
	*-ns)
-
		os=-genix
+
		os=genix
		;;
	i370-*)
-
		os=-mvs
+
		os=mvs
		;;
	*-gould)
-
		os=-sysv
+
		os=sysv
		;;
	*-highlevel)
-
		os=-bsd
+
		os=bsd
		;;
	*-encore)
-
		os=-bsd
+
		os=bsd
		;;
	*-sgi)
-
		os=-irix
+
		os=irix
		;;
	*-siemens)
-
		os=-sysv4
+
		os=sysv4
		;;
	*-masscomp)
-
		os=-rtu
+
		os=rtu
		;;
	f30[01]-fujitsu | f700-fujitsu)
-
		os=-uxpv
+
		os=uxpv
		;;
	*-rom68k)
-
		os=-coff
+
		os=coff
		;;
	*-*bug)
-
		os=-coff
+
		os=coff
		;;
	*-apple)
-
		os=-macos
+
		os=macos
		;;
	*-atari*)
-
		os=-mint
+
		os=mint
+
		;;
+
	*-wrs)
+
		os=vxworks
		;;
	*)
-
		os=-none
+
		os=none
		;;
esac
+

fi

+
# Now, validate our (potentially fixed-up) OS.
+
case $os in
+
	# Sometimes we do "kernel-libc", so those need to count as OSes.
+
	musl* | newlib* | uclibc*)
+
		;;
+
	# Likewise for "kernel-abi"
+
	eabi* | gnueabi*)
+
		;;
+
	# VxWorks passes extra cpu info in the 4th filed.
+
	simlinux | simwindows | spe)
+
		;;
+
	# Now accept the basic system types.
+
	# The portable systems comes first.
+
	# Each alternative MUST end in a * to match a version number.
+
	gnu* | android* | bsd* | mach* | minix* | genix* | ultrix* | irix* \
+
	     | *vms* | esix* | aix* | cnk* | sunos | sunos[34]* \
+
	     | hpux* | unos* | osf* | luna* | dgux* | auroraux* | solaris* \
+
	     | sym* |  plan9* | psp* | sim* | xray* | os68k* | v88r* \
+
	     | hiux* | abug | nacl* | netware* | windows* \
+
	     | os9* | macos* | osx* | ios* \
+
	     | mpw* | magic* | mmixware* | mon960* | lnews* \
+
	     | amigaos* | amigados* | msdos* | newsos* | unicos* | aof* \
+
	     | aos* | aros* | cloudabi* | sortix* | twizzler* \
+
	     | nindy* | vxsim* | vxworks* | ebmon* | hms* | mvs* \
+
	     | clix* | riscos* | uniplus* | iris* | isc* | rtu* | xenix* \
+
	     | mirbsd* | netbsd* | dicos* | openedition* | ose* \
+
	     | bitrig* | openbsd* | secbsd* | solidbsd* | libertybsd* | os108* \
+
	     | ekkobsd* | freebsd* | riscix* | lynxos* | os400* \
+
	     | bosx* | nextstep* | cxux* | aout* | elf* | oabi* \
+
	     | ptx* | coff* | ecoff* | winnt* | domain* | vsta* \
+
	     | udi* | lites* | ieee* | go32* | aux* | hcos* \
+
	     | chorusrdb* | cegcc* | glidix* | serenity* \
+
	     | cygwin* | msys* | pe* | moss* | proelf* | rtems* \
+
	     | midipix* | mingw32* | mingw64* | mint* \
+
	     | uxpv* | beos* | mpeix* | udk* | moxiebox* \
+
	     | interix* | uwin* | mks* | rhapsody* | darwin* \
+
	     | openstep* | oskit* | conix* | pw32* | nonstopux* \
+
	     | storm-chaos* | tops10* | tenex* | tops20* | its* \
+
	     | os2* | vos* | palmos* | uclinux* | nucleus* | morphos* \
+
	     | scout* | superux* | sysv* | rtmk* | tpf* | windiss* \
+
	     | powermax* | dnix* | nx6 | nx7 | sei* | dragonfly* \
+
	     | skyos* | haiku* | rdos* | toppers* | drops* | es* \
+
	     | onefs* | tirtos* | phoenix* | fuchsia* | redox* | bme* \
+
	     | midnightbsd* | amdhsa* | unleashed* | emscripten* | wasi* \
+
	     | nsk* | powerunix* | genode* | zvmoe* | qnx* | emx*)
+
		;;
+
	# This one is extra strict with allowed versions
+
	sco3.2v2 | sco3.2v[4-9]* | sco5v6*)
+
		# Don't forget version if it is 3.2v4 or newer.
+
		;;
+
	none)
+
		;;
+
	*)
+
		echo Invalid configuration \`"$1"\': OS \`"$os"\' not recognized 1>&2
+
		exit 1
+
		;;
+
esac
+

+
# As a final step for OS-related things, validate the OS-kernel combination
+
# (given a valid OS), if there is a kernel.
+
case $kernel-$os in
+
	linux-gnu* | linux-dietlibc* | linux-android* | linux-newlib* | linux-musl* | linux-uclibc* )
+
		;;
+
	uclinux-uclibc* )
+
		;;
+
	-dietlibc* | -newlib* | -musl* | -uclibc* )
+
		# These are just libc implementations, not actual OSes, and thus
+
		# require a kernel.
+
		echo "Invalid configuration \`$1': libc \`$os' needs explicit kernel." 1>&2
+
		exit 1
+
		;;
+
	kfreebsd*-gnu* | kopensolaris*-gnu*)
+
		;;
+
	vxworks-simlinux | vxworks-simwindows | vxworks-spe)
+
		;;
+
	nto-qnx*)
+
		;;
+
	os2-emx)
+
		;;
+
	*-eabi* | *-gnueabi*)
+
		;;
+
	-*)
+
		# Blank kernel with real OS is always fine.
+
		;;
+
	*-*)
+
		echo "Invalid configuration \`$1': Kernel \`$kernel' not known to work with OS \`$os'." 1>&2
+
		exit 1
+
		;;
+
esac
+

# Here we handle the case where we know the os, and the CPU type, but not the
# manufacturer.  We pick the logical manufacturer.
-
vendor=unknown
-
case $basic_machine in
-
	*-unknown)
-
		case $os in
-
			-riscix*)
+
case $vendor in
+
	unknown)
+
		case $cpu-$os in
+
			*-riscix*)
				vendor=acorn
				;;
-
			-sunos*)
+
			*-sunos*)
				vendor=sun
				;;
-
			-cnk*|-aix*)
+
			*-cnk* | *-aix*)
				vendor=ibm
				;;
-
			-beos*)
+
			*-beos*)
				vendor=be
				;;
-
			-hpux*)
+
			*-hpux*)
				vendor=hp
				;;
-
			-mpeix*)
+
			*-mpeix*)
				vendor=hp
				;;
-
			-hiux*)
+
			*-hiux*)
				vendor=hitachi
				;;
-
			-unos*)
+
			*-unos*)
				vendor=crds
				;;
-
			-dgux*)
+
			*-dgux*)
				vendor=dg
				;;
-
			-luna*)
+
			*-luna*)
				vendor=omron
				;;
-
			-genix*)
+
			*-genix*)
				vendor=ns
				;;
-
			-mvs* | -opened*)
+
			*-clix*)
+
				vendor=intergraph
+
				;;
+
			*-mvs* | *-opened*)
+
				vendor=ibm
+
				;;
+
			*-os400*)
				vendor=ibm
				;;
-
			-os400*)
+
			s390-* | s390x-*)
				vendor=ibm
				;;
-
			-ptx*)
+
			*-ptx*)
				vendor=sequent
				;;
-
			-tpf*)
+
			*-tpf*)
				vendor=ibm
				;;
-
			-vxsim* | -vxworks* | -windiss*)
+
			*-vxsim* | *-vxworks* | *-windiss*)
				vendor=wrs
				;;
-
			-aux*)
+
			*-aux*)
				vendor=apple
				;;
-
			-hms*)
+
			*-hms*)
				vendor=hitachi
				;;
-
			-mpw* | -macos*)
+
			*-mpw* | *-macos*)
				vendor=apple
				;;
-
			-*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+
			*-*mint | *-mint[0-9]* | *-*MiNT | *-MiNT[0-9]*)
				vendor=atari
				;;
-
			-vos*)
+
			*-vos*)
				vendor=stratus
				;;
		esac
-
		basic_machine=`echo "$basic_machine" | sed "s/unknown/$vendor/"`
		;;
esac

-
echo "$basic_machine$os"
+
echo "$cpu-$vendor-${kernel:+$kernel-}$os"
exit

# Local variables:
modified autosetup/autosetup-find-tclsh
@@ -2,14 +2,15 @@
# Looks for a suitable tclsh or jimsh in the PATH
# If not found, builds a bootstrap jimsh in current dir from source
# Prefer $autosetup_tclsh if is set in the environment (unless ./jimsh0 works)
+
# If an argument is given, use that as the test instead of autosetup-test-tclsh
d="`dirname "$0"`"
for tclsh in ./jimsh0 $autosetup_tclsh jimsh tclsh tclsh8.5 tclsh8.6 tclsh8.7; do
-
	{ $tclsh "$d/autosetup-test-tclsh"; } 2>/dev/null && exit 0
+
	{ $tclsh "$d/${1-autosetup-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 jimsh0 "$d/jimsh0.c"; } 2>/dev/null || continue
-
	./jimsh0 "$d/autosetup-test-tclsh" && exit 0
+
	./jimsh0 "$d/${1-autosetup-test-tclsh}" && exit 0
done
echo 1>&2 "No working C compiler found. Tried ${CC_FOR_BUILD:-cc} and gcc."
echo false
modified autosetup/cc-lib.tcl
@@ -78,7 +78,7 @@ proc cc-check-endian {} {
#
# Checks whether the given C/C++ compiler flags can be used. Defines feature
# names prefixed with 'HAVE_CFLAG' and 'HAVE_CXXFLAG' respectively, and
-
# appends working flags to '-cflags' and 'CFLAGS' or 'CXXFLAGS'.
+
# appends working flags to '-cflags' and 'AS_CFLAGS' or 'AS_CXXFLAGS'.
proc cc-check-flags {args} {
	set result 1
	array set opts [cc-get-settings]
@@ -101,7 +101,7 @@ proc cc-check-flags {args} {
			msg-result yes
			define-feature $prefix$flag
			cc-with [list -cflags [list $flag]]
-
			define-append ${prefix}S $flag
+
			define-append AS_${prefix}S $flag
		} else {
			msg-result no
			set result 0
@@ -113,8 +113,8 @@ proc cc-check-flags {args} {
# @cc-check-standards ver ?...?
#
# Checks whether the C/C++ compiler accepts one of the specified '-std=$ver'
-
# options, and appends the first working one to '-cflags' and 'CFLAGS' or
-
# 'CXXFLAGS'.
+
# options, and appends the first working one to '-cflags' and 'AS_CFLAGS' or
+
# 'AS_CXXFLAGS'.
proc cc-check-standards {args} {
	array set opts [cc-get-settings]
	foreach std $args {
modified autosetup/cc.tcl
@@ -13,17 +13,17 @@
## CXX      - C++ compiler
## CPP      - C preprocessor
## CCACHE   - Set to "none" to disable automatic use of ccache
+
## CPPFLAGS  - Additional C preprocessor compiler flags (C and C++), before CFLAGS, CXXFLAGS
## CFLAGS   - Additional C compiler flags
## CXXFLAGS - Additional C++ compiler flags
## LDFLAGS  - Additional compiler flags during linking
+
## LINKFLAGS - ?How is this different from LDFLAGS?
## LIBS     - Additional libraries to use (for all tests)
## CROSS    - Tool prefix for cross compilation
#
# The following variables are defined from the corresponding
# environment variables if set.
#
-
## CPPFLAGS
-
## LINKFLAGS
## CC_FOR_BUILD
## LD

@@ -264,11 +264,11 @@ proc cc-check-tools {args} {
	foreach tool $args {
		set TOOL [string toupper $tool]
		set exe [get-env $TOOL [get-define cross]$tool]
-
		if {[find-executable {*}$exe]} {
+
		if {[find-executable $exe]} {
			define $TOOL $exe
			continue
		}
-
		if {[find-executable {*}$tool]} {
+
		if {[find-executable $tool]} {
			msg-result "Warning: Failed to find $exe, falling back to $tool which may be incorrect"
			define $TOOL $tool
			continue
@@ -418,6 +418,13 @@ proc cc-update-settings {args} {
##     # libs will be in this order: -lsocket -ldl -lc -lm
##   }
## }
+
#
+
# If you wish to invoke something like cc-check-flags but not have -cflags updated,
+
# use the following idiom:
+
#
+
## cc-with {} {
+
##   cc-check-flags ...
+
## }
proc cc-with {settings args} {
	if {[llength $args] == 0} {
		cc-add-settings $settings
@@ -455,14 +462,22 @@ proc cc-with {settings args} {
# Unless '-source' or '-sourcefile' is specified, the C program looks like:
#
## #include <firstinclude>   /* same for remaining includes in the list */
-
##
## declare-code              /* any code in -declare, verbatim */
-
##
## int main(void) {
##   code                    /* any code in -code, verbatim */
##   return 0;
## }
#
+
# And the command line looks like:
+
#
+
## CC -cflags CFLAGS CPPFLAGS conftest.c -o conftest.o
+
## CXX -cflags CXXFLAGS CPPFLAGS conftest.cpp -o conftest.o
+
#
+
# And if linking:
+
#
+
## CC LDFLAGS -cflags CFLAGS conftest.c -o conftest -libs LIBS
+
## CXX LDFLAGS -cflags CXXFLAGS conftest.c -o conftest -libs LIBS
+
#
# Any failures are recorded in 'config.log'
#
proc cctest {args} {
@@ -508,11 +523,13 @@ proc cctest {args} {
	switch -exact -- $opts(-lang) {
		c++ {
			set src conftest__.cpp
-
			lappend cmdline {*}[get-define CXX] {*}[get-define CXXFLAGS]
+
			lappend cmdline {*}[get-define CXX]
+
			set cflags [get-define CXXFLAGS]
		}
		c {
			set src conftest__.c
-
			lappend cmdline {*}[get-define CC] {*}[get-define CFLAGS]
+
			lappend cmdline {*}[get-define CC]
+
			set cflags [get-define CFLAGS]
		}
		default {
			autosetup-error "cctest called with unknown language: $opts(-lang)"
@@ -522,13 +539,14 @@ proc cctest {args} {
	if {$opts(-link)} {
		lappend cmdline {*}[get-define LDFLAGS]
	} else {
+
		lappend cflags {*}[get-define CPPFLAGS]
		set tmp conftest__.o
		lappend cmdline -c
	}
-
	lappend cmdline {*}$opts(-cflags) {*}[get-define cc-default-debug ""]
-
	lappend cmdline $src -o $tmp {*}$opts(-libs)
+
	lappend cmdline {*}$opts(-cflags) {*}[get-define cc-default-debug ""] {*}$cflags
+
	lappend cmdline $src -o $tmp
	if {$opts(-link)} {
-
		lappend cmdline {*}[get-define LIBS]
+
		lappend cmdline {*}$opts(-libs) {*}[get-define LIBS]
	}

	# At this point we have the complete command line and the
@@ -660,7 +678,7 @@ proc calc-define-output-type {name spec} {
}

# Initialise some values from the environment or commandline or default settings
-
foreach i {LDFLAGS LIBS CPPFLAGS LINKFLAGS {CFLAGS "-g -O2"}} {
+
foreach i {LDFLAGS LIBS CPPFLAGS LINKFLAGS CFLAGS} {
	lassign $i var default
	define $var [get-env $var $default]
}
@@ -697,6 +715,11 @@ if {[get-define CC] eq ""} {
	user-error "Could not find a C compiler. Tried: [join $try ", "]"
}

+
# These start empty and never come from the user or environment
+
define AS_CFLAGS ""
+
define AS_CPPFLAGS ""
+
define AS_CXXFLAGS ""
+

define CCACHE [find-an-executable [get-env CCACHE ccache]]

# If any of these are set in the environment, propagate them to the AUTOREMAKE commandline
@@ -704,7 +727,7 @@ foreach i {CC CXX CCACHE CPP CFLAGS CXXFLAGS CXXFLAGS LDFLAGS LIBS CROSS CPPFLAG
	if {[env-is-set $i]} {
		# Note: If the variable is set on the command line, get-env will return that value
		# so the command line will continue to override the environment
-
		define-append AUTOREMAKE [quote-if-needed $i=[get-env $i ""]]
+
		define-append-argv AUTOREMAKE $i=[get-env $i ""]
	}
}

@@ -712,9 +735,9 @@ foreach i {CC CXX CCACHE CPP CFLAGS CXXFLAGS CXXFLAGS LDFLAGS LIBS CROSS CPPFLAG
cc-store-settings {-cflags {} -includes {} -declare {} -link 0 -lang c -libs {} -code {} -nooutput 0}
set autosetup(cc-include-deps) {}

-
msg-result "C compiler...[get-define CCACHE] [get-define CC] [get-define CFLAGS]"
+
msg-result "C compiler...[get-define CCACHE] [get-define CC] [get-define CFLAGS] [get-define CPPFLAGS]"
if {[get-define CXX] ne "false"} {
-
	msg-result "C++ compiler...[get-define CCACHE] [get-define CXX] [get-define CXXFLAGS]"
+
	msg-result "C++ compiler...[get-define CCACHE] [get-define CXX] [get-define CXXFLAGS] [get-define CPPFLAGS]"
}
msg-result "Build C compiler...[get-define CC_FOR_BUILD]"

modified autosetup/jimsh0.c
@@ -12,6 +12,7 @@
#define jim_ext_file
#define jim_ext_glob
#define jim_ext_exec
+
#define jim_ext_posix
#define jim_ext_clock
#define jim_ext_array
#define jim_ext_stdlib
@@ -49,7 +50,7 @@
#else
#define _GNU_SOURCE
#endif
-
#define HAVE_VFORK
+
#define HAVE_FORK
#define HAVE_WAITPID
#define HAVE_ISATTY
#define HAVE_MKSTEMP
@@ -58,8 +59,10 @@
#define HAVE_DIRENT_H
#define HAVE_UNISTD_H
#define HAVE_UMASK
+
#define HAVE_PIPE
+
#define _FILE_OFFSET_BITS 64
#endif
-
#define JIM_VERSION 78
+
#define JIM_VERSION 82
#ifndef JIM_WIN32COMPAT_H
#define JIM_WIN32COMPAT_H

@@ -186,7 +189,6 @@ extern "C" {

#include <time.h>
#include <limits.h>
-
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>

@@ -225,6 +227,9 @@ extern "C" {
#define UCHAR(c) ((unsigned char)(c))


+

+
#define JIM_ABI_VERSION 101
+

#define JIM_OK 0
#define JIM_ERR 1
#define JIM_RETURN 2
@@ -246,6 +251,7 @@ extern "C" {
#define JIM_ENUM_ABBREV 2
#define JIM_UNSHARED 4
#define JIM_MUSTEXIST 8
+
#define JIM_NORESULT 16


#define JIM_SUBST_NOVAR 1
@@ -256,6 +262,7 @@ extern "C" {

#define JIM_CASESENS    0
#define JIM_NOCASE      1
+
#define JIM_OPT_END     2


#define JIM_PATH_LEN 1024
@@ -324,6 +331,8 @@ typedef struct Jim_HashTableIterator {
        (entry)->u.val = (_val_); \
} while(0)

+
#define Jim_SetHashIntVal(ht, entry, _val_) (entry)->u.intval = (_val_)
+

#define Jim_FreeEntryKey(ht, entry) \
    if ((ht)->type->keyDestructor) \
        (ht)->type->keyDestructor((ht)->privdata, (entry)->key)
@@ -344,6 +353,7 @@ typedef struct Jim_HashTableIterator {

#define Jim_GetHashEntryKey(he) ((he)->key)
#define Jim_GetHashEntryVal(he) ((he)->u.val)
+
#define Jim_GetHashEntryIntVal(he) ((he)->u.intval)
#define Jim_GetHashTableCollisions(ht) ((ht)->collisions)
#define Jim_GetHashTableSize(ht) ((ht)->size)
#define Jim_GetHashTableUsed(ht) ((ht)->used)
@@ -377,7 +387,7 @@ typedef struct Jim_Obj {
        } ptrIntValue;

        struct {
-
            struct Jim_Var *varPtr;
+
            struct Jim_VarVal *vv;
            unsigned long callFrameId;
            int global;
        } varValue;
@@ -394,6 +404,8 @@ typedef struct Jim_Obj {
            int maxLen;
        } listValue;

+
        struct Jim_Dict *dictValue;
+

        struct {
            int maxLength;
            int charLength;
@@ -479,29 +491,55 @@ typedef struct Jim_CallFrame {
    Jim_Obj *procBodyObjPtr;
    struct Jim_CallFrame *next;
    Jim_Obj *nsObj;
-
    Jim_Obj *fileNameObj;
-
    int line;
+
    Jim_Obj *unused_fileNameObj;
+
    int unused_line;
    Jim_Stack *localCommands;
    struct Jim_Obj *tailcallObj;
    struct Jim_Cmd *tailcallCmd;
} Jim_CallFrame;

-
typedef struct Jim_Var {
+

+
typedef struct Jim_EvalFrame {
+
    Jim_CallFrame *framePtr;
+
    int level;
+
    int procLevel;
+
    struct Jim_Cmd *cmd;
+
    struct Jim_EvalFrame *parent;
+
    Jim_Obj *const *argv;
+
    int argc;
+
    Jim_Obj *scriptObj;
+
} Jim_EvalFrame;
+

+
typedef struct Jim_VarVal {
    Jim_Obj *objPtr;
    struct Jim_CallFrame *linkFramePtr;
-
} Jim_Var;
+
    int refCount;
+
} Jim_VarVal;


typedef int Jim_CmdProc(struct Jim_Interp *interp, int argc,
    Jim_Obj *const *argv);
typedef void Jim_DelCmdProc(struct Jim_Interp *interp, void *privData);

-

+
typedef struct Jim_Dict {
+
    struct JimDictHashEntry {
+
        int offset;
+
        unsigned hash;
+
    } *ht;
+
    unsigned int size;
+
    unsigned int sizemask;
+
    unsigned int uniq;
+
    Jim_Obj **table;
+
    int len;
+
    int maxLen;
+
    unsigned int dummy;
+
} Jim_Dict;

typedef struct Jim_Cmd {
    int inUse;
    int isproc;
    struct Jim_Cmd *prevCmd;
+
    Jim_Obj *cmdNameObj;
    union {
        struct {

@@ -536,9 +574,9 @@ typedef struct Jim_PrngState {

typedef struct Jim_Interp {
    Jim_Obj *result;
-
    int errorLine;
-
    Jim_Obj *errorFileNameObj;
-
    int addStackTrace;
+
    int unused_errorLine;
+
    Jim_Obj *currentFilenameObj;
+
    int unused_addStackTrace;
    int maxCallFrameDepth;
    int maxEvalDepth;
    int evalDepth;
@@ -560,9 +598,15 @@ typedef struct Jim_Interp {
                'ID' field contained in the Jim_CallFrame
                structure. */
    int local;
+
    int quitting;
+
    int safeexpr;
    Jim_Obj *liveList;
    Jim_Obj *freeList;
-
    Jim_Obj *currentScriptObj;
+
    Jim_Obj *unused_currentScriptObj;
+
    Jim_EvalFrame topEvalFrame;
+
    Jim_EvalFrame *evalFrame;
+
    int procLevel;
+
    Jim_Obj * const *unused_argv;
    Jim_Obj *nullScriptObj;
    Jim_Obj *emptyObj;
    Jim_Obj *trueObj;
@@ -574,16 +618,20 @@ typedef struct Jim_Interp {
                is running as sentinel to avoid to recursive
                calls via the [collect] command inside
                finalizers. */
-
    time_t lastCollectTime;
+
    jim_wide lastCollectTime;
    Jim_Obj *stackTrace;
    Jim_Obj *errorProc;
    Jim_Obj *unknown;
+
    Jim_Obj *defer;
+
    Jim_Obj *traceCmdObj;
    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(). */

+
    Jim_Cmd *oldCmdCache;
+
    int oldCmdCacheSize;
    struct Jim_CallFrame *freeFramesList;
    struct Jim_HashTable assocData;
    Jim_PrngState *prngState;
@@ -591,7 +639,6 @@ typedef struct Jim_Interp {
    Jim_Stack *loadHandles;
} Jim_Interp;

-
#define Jim_InterpIncrProcEpoch(i) (i)->procEpoch++
#define Jim_SetResultString(i,s,l) Jim_SetResult(i, Jim_NewStringObj(i,s,l))
#define Jim_SetResultInt(i,intval) Jim_SetResult(i, Jim_NewIntObj(i,intval))

@@ -623,12 +670,15 @@ typedef struct Jim_Reference {
#define Jim_NewEmptyStringObj(i) Jim_NewStringObj(i, "", 0)
#define Jim_FreeHashTableIterator(iter) Jim_Free(iter)

-
#define JIM_EXPORT
+
#define JIM_EXPORT extern
+



-
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 void *(*Jim_Allocator)(void *ptr, size_t size);
+

+
#define Jim_Free(P) Jim_Allocator((P), 0)
+
#define Jim_Realloc(P, S) Jim_Allocator((P), (S))
+
#define Jim_Alloc(S) Jim_Allocator(NULL, (S))
JIM_EXPORT char * Jim_StrDup (const char *s);
JIM_EXPORT char *Jim_StrDupLen(const char *s, int l);

@@ -636,6 +686,16 @@ JIM_EXPORT char *Jim_StrDupLen(const char *s, int l);
JIM_EXPORT char **Jim_GetEnviron(void);
JIM_EXPORT void Jim_SetEnviron(char **env);
JIM_EXPORT int Jim_MakeTempFile(Jim_Interp *interp, const char *filename_template, int unlink_file);
+
#ifndef CLOCK_REALTIME
+
#  define CLOCK_REALTIME 0
+
#endif
+
#ifndef CLOCK_MONOTONIC
+
#  define CLOCK_MONOTONIC 1
+
#endif
+
#ifndef CLOCK_MONOTONIC_RAW
+
#  define CLOCK_MONOTONIC_RAW CLOCK_MONOTONIC
+
#endif
+
JIM_EXPORT jim_wide Jim_GetTimeUsec(unsigned type);


JIM_EXPORT int Jim_Eval(Jim_Interp *interp, const char *script);
@@ -682,7 +742,6 @@ JIM_EXPORT int Jim_DeleteHashEntry (Jim_HashTable *ht,
JIM_EXPORT int Jim_FreeHashTable (Jim_HashTable *ht);
JIM_EXPORT Jim_HashEntry * Jim_FindHashEntry (Jim_HashTable *ht,
        const void *key);
-
JIM_EXPORT void Jim_ResizeHashTable (Jim_HashTable *ht);
JIM_EXPORT Jim_HashTableIterator *Jim_GetHashTableIterator
        (Jim_HashTable *ht);
JIM_EXPORT Jim_HashEntry * Jim_NextHashEntry
@@ -726,8 +785,6 @@ JIM_EXPORT int Jim_CompareStringImmediate (Jim_Interp *interp,
        Jim_Obj *objPtr, const char *str);
JIM_EXPORT int Jim_StringCompareObj(Jim_Interp *interp, Jim_Obj *firstObjPtr,
        Jim_Obj *secondObjPtr, int nocase);
-
JIM_EXPORT int Jim_StringCompareLenObj(Jim_Interp *interp, Jim_Obj *firstObjPtr,
-
        Jim_Obj *secondObjPtr, int nocase);
JIM_EXPORT int Jim_Utf8Length(Jim_Interp *interp, Jim_Obj *objPtr);


@@ -751,9 +808,9 @@ 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_Obj *cmdNameObj);
JIM_EXPORT int Jim_RenameCommand (Jim_Interp *interp,
-
        const char *oldName, const char *newName);
+
        Jim_Obj *oldNameObj, Jim_Obj *newNameObj);
JIM_EXPORT Jim_Cmd * Jim_GetCommand (Jim_Interp *interp,
        Jim_Obj *objPtr, int flags);
JIM_EXPORT int Jim_SetVariable (Jim_Interp *interp,
@@ -824,8 +881,8 @@ JIM_EXPORT int Jim_DictKeysVector (Jim_Interp *interp,
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 Jim_Obj **Jim_DictPairs(Jim_Interp *interp,
+
        Jim_Obj *dictPtr, int *len);
JIM_EXPORT int Jim_DictAddElement(Jim_Interp *interp, Jim_Obj *objPtr,
        Jim_Obj *keyObjPtr, Jim_Obj *valueObjPtr);

@@ -854,6 +911,8 @@ JIM_EXPORT int Jim_GetBoolean(Jim_Interp *interp, Jim_Obj *objPtr,

JIM_EXPORT int Jim_GetWide (Jim_Interp *interp, Jim_Obj *objPtr,
        jim_wide *widePtr);
+
JIM_EXPORT int Jim_GetWideExpr(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
@@ -885,6 +944,8 @@ JIM_EXPORT void * Jim_GetAssocData(Jim_Interp *interp, const char *key);
JIM_EXPORT int Jim_SetAssocData(Jim_Interp *interp, const char *key,
        Jim_InterpDeleteProc *delProc, void *data);
JIM_EXPORT int Jim_DeleteAssocData(Jim_Interp *interp, const char *key);
+
JIM_EXPORT int Jim_CheckAbiVersion(Jim_Interp *interp, int abi_version);
+




@@ -892,6 +953,9 @@ 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);
+
#define Jim_PackageProvideCheck(INTERP, NAME) \
+
        if (Jim_CheckAbiVersion(INTERP, JIM_ABI_VERSION) == JIM_ERR || Jim_PackageProvide(INTERP, NAME, "1.0", JIM_ERRMSG)) \
+
                return JIM_ERR


JIM_EXPORT void Jim_MakeErrorMessage (Jim_Interp *interp);
@@ -901,9 +965,12 @@ JIM_EXPORT int Jim_InteractivePrompt (Jim_Interp *interp);
JIM_EXPORT void Jim_HistoryLoad(const char *filename);
JIM_EXPORT void Jim_HistorySave(const char *filename);
JIM_EXPORT char *Jim_HistoryGetline(Jim_Interp *interp, const char *prompt);
-
JIM_EXPORT void Jim_HistorySetCompletion(Jim_Interp *interp, Jim_Obj *commandObj);
+
JIM_EXPORT void Jim_HistorySetCompletion(Jim_Interp *interp, Jim_Obj *completionCommandObj);
+
JIM_EXPORT void Jim_HistorySetHints(Jim_Interp *interp, Jim_Obj *hintsCommandObj);
JIM_EXPORT void Jim_HistoryAdd(const char *line);
JIM_EXPORT void Jim_HistoryShow(void);
+
JIM_EXPORT void Jim_HistorySetMaxLen(int length);
+
JIM_EXPORT int Jim_HistoryGetMaxLen(void);


JIM_EXPORT int Jim_InitStaticExtensions(Jim_Interp *interp);
@@ -911,13 +978,14 @@ JIM_EXPORT int Jim_StringToWide(const char *str, jim_wide *widePtr, int base);
JIM_EXPORT int Jim_IsBigEndian(void);

#define Jim_CheckSignal(i) ((i)->signal_level && (i)->sigmask)
+
JIM_EXPORT void Jim_SignalSetIgnored(jim_wide mask);


JIM_EXPORT int Jim_LoadLibrary(Jim_Interp *interp, const char *pathName);
JIM_EXPORT void Jim_FreeLoadHandles(Jim_Interp *interp);


-
JIM_EXPORT FILE *Jim_AioFilehandle(Jim_Interp *interp, Jim_Obj *command);
+
JIM_EXPORT int Jim_AioFilehandle(Jim_Interp *interp, Jim_Obj *command);


JIM_EXPORT int Jim_IsDict(Jim_Obj *objPtr);
@@ -954,6 +1022,9 @@ typedef struct {
	unsigned short flags;
} jim_subcmd_type;

+
#define JIM_DEF_SUBCMD(name, args, minargs, maxargs) { name, args, NULL, minargs, maxargs }
+
#define JIM_DEF_SUBCMD_HIDDEN(name, args, minargs, maxargs) { name, args, NULL, minargs, maxargs, JIM_MODFLAG_HIDDEN }
+

const jim_subcmd_type *
Jim_ParseSubCmd(Jim_Interp *interp, const jim_subcmd_type *command_table, int argc, Jim_Obj *const *argv);

@@ -961,6 +1032,8 @@ int Jim_SubCmdProc(Jim_Interp *interp, int argc, Jim_Obj *const *argv);

int Jim_CallSubCmd(Jim_Interp *interp, const jim_subcmd_type *ct, int argc, Jim_Obj *const *argv);

+
void Jim_SubCmdArgError(Jim_Interp *interp, const jim_subcmd_type *ct, Jim_Obj *subcmd);
+

#ifdef __cplusplus
}
#endif
@@ -1036,16 +1109,17 @@ enum {
	REG_ERR_NESTED_COUNT,
	REG_ERR_INTERNAL,
	REG_ERR_COUNT_FOLLOWS_NOTHING,
-
	REG_ERR_TRAILING_BACKSLASH,
+
	REG_ERR_INVALID_ESCAPE,
	REG_ERR_CORRUPTED,
	REG_ERR_NULL_CHAR,
+
	REG_ERR_UNMATCHED_BRACKET,
	REG_ERR_NUM
};

-
int regcomp(regex_t *preg, const char *regex, int cflags);
-
int regexec(regex_t  *preg,  const  char *string, size_t nmatch, regmatch_t pmatch[], int eflags);
-
size_t regerror(int errcode, const regex_t *preg, char *errbuf,  size_t errbuf_size);
-
void regfree(regex_t *preg);
+
int jim_regcomp(regex_t *preg, const char *regex, int cflags);
+
int jim_regexec(regex_t  *preg,  const  char *string, size_t nmatch, regmatch_t pmatch[], int eflags);
+
size_t jim_regerror(int errcode, const regex_t *preg, char *errbuf,  size_t errbuf_size);
+
void jim_regfree(regex_t *preg);

#ifdef __cplusplus
}
@@ -1072,6 +1146,7 @@ const char *Jim_SignalId(int sig);

#include <stdio.h>
#include <errno.h>
+
#include <sys/stat.h>


void Jim_SetResultErrno(Jim_Interp *interp, const char *msg);
@@ -1090,10 +1165,8 @@ int Jim_OpenForRead(const char *filename);
    #include <io.h>
    #include <process.h>

-
    typedef HANDLE pidtype;
-
    #define JIM_BAD_PID INVALID_HANDLE_VALUE
-

-
    #define JIM_NO_PID INVALID_HANDLE_VALUE
+
    typedef HANDLE phandle_t;
+
    #define JIM_BAD_PHANDLE INVALID_HANDLE_VALUE


    #define WIFEXITED(STATUS) (((STATUS) & 0xff00) == 0)
@@ -1103,27 +1176,71 @@ int Jim_OpenForRead(const char *filename);
    #define WNOHANG 1

    int Jim_Errno(void);
-
    pidtype waitpid(pidtype pid, int *status, int nohang);
+

+
    long waitpid(phandle_t phandle, int *status, int nohang);
+

+
    phandle_t JimWaitPid(long processid, int *status, int nohang);
+

+
    long JimProcessPid(phandle_t phandle);

    #define HAVE_PIPE
    #define pipe(P) _pipe((P), 0, O_NOINHERIT)

-
#elif defined(HAVE_UNISTD_H)
-
    #include <unistd.h>
-
    #include <fcntl.h>
-
    #include <sys/wait.h>
-
    #include <sys/stat.h>
+
    typedef struct __stat64 jim_stat_t;
+
    #define Jim_Stat _stat64
+
    #define Jim_FileStat _fstat64
+
    #define Jim_Lseek _lseeki64
+

+
#else
+
    #if defined(HAVE_STAT64)
+
        typedef struct stat64 jim_stat_t;
+
        #define Jim_Stat stat64
+
        #if defined(HAVE_FSTAT64)
+
            #define Jim_FileStat fstat64
+
        #endif
+
        #if defined(HAVE_LSTAT64)
+
            #define Jim_LinkStat lstat64
+
        #endif
+
    #else
+
        typedef struct stat jim_stat_t;
+
        #define Jim_Stat stat
+
        #if defined(HAVE_FSTAT)
+
            #define Jim_FileStat fstat
+
        #endif
+
        #if defined(HAVE_LSTAT)
+
            #define Jim_LinkStat lstat
+
        #endif
+
    #endif
+
    #if defined(HAVE_LSEEK64)
+
        #define Jim_Lseek lseek64
+
    #else
+
        #define Jim_Lseek lseek
+
    #endif

-
    typedef int pidtype;
-
    #define Jim_Errno() errno
-
    #define JIM_BAD_PID -1
-
    #define JIM_NO_PID 0
+
    #if defined(HAVE_UNISTD_H)
+
        #include <unistd.h>
+
        #include <fcntl.h>
+
        #include <sys/wait.h>

-
    #ifndef HAVE_EXECVPE
-
        #define execvpe(ARG0, ARGV, ENV) execvp(ARG0, ARGV)
+
        typedef int phandle_t;
+
        #define Jim_Errno() errno
+
        #define JIM_BAD_PHANDLE -1
+
        #define JimProcessPid(PIDTYPE) (PIDTYPE)
+
        #define JimWaitPid waitpid
+

+
        #ifndef HAVE_EXECVPE
+
            #define execvpe(ARG0, ARGV, ENV) execvp(ARG0, ARGV)
+
        #endif
    #endif
#endif

+
#ifndef O_TEXT
+
#define O_TEXT 0
+
#endif
+

+

+
int Jim_FileStoreStatData(Jim_Interp *interp, Jim_Obj *varName, const jim_stat_t *sb);
+

#endif
int Jim_bootstrapInit(Jim_Interp *interp)
{
@@ -1132,21 +1249,21 @@ int Jim_bootstrapInit(Jim_Interp *interp)

	return Jim_EvalSource(interp, "bootstrap.tcl", 1,
"\n"
-
"\n"
-
"proc package {cmd pkg args} {\n"
+
"proc package {cmd args} {\n"
"	if {$cmd eq \"require\"} {\n"
"		foreach path $::auto_path {\n"
+
"			lassign $args pkg\n"
"			set pkgpath $path/$pkg.tcl\n"
"			if {$path eq \".\"} {\n"
"				set pkgpath $pkg.tcl\n"
"			}\n"
"			if {[file exists $pkgpath]} {\n"
-
"				uplevel #0 [list source $pkgpath]\n"
-
"				return\n"
+
"				tailcall uplevel #0 [list source $pkgpath]\n"
"			}\n"
"		}\n"
"	}\n"
"}\n"
+
"set tcl_platform(bootstrap) 1\n"
);
}
int Jim_initjimshInit(Jim_Interp *interp)
@@ -1201,7 +1318,7 @@ int Jim_initjimshInit(Jim_Interp *interp)
"}\n"
"\n"
"\n"
-
"set tcl::autocomplete_commands {info tcl::prefix socket namespace array clock file package string dict signal history}\n"
+
"set tcl::autocomplete_commands {array clock debug dict file history info namespace package signal socket string tcl::prefix zlib}\n"
"\n"
"\n"
"\n"
@@ -1233,6 +1350,63 @@ int Jim_initjimshInit(Jim_Interp *interp)
"	}]\n"
"}\n"
"\n"
+
"\n"
+
"set tcl::stdhint_commands {array clock debug dict file history info namespace package signal string zlib}\n"
+
"\n"
+
"set tcl::stdhint_cols {\n"
+
"	none {0}\n"
+
"	black {30}\n"
+
"	red {31}\n"
+
"	green {32}\n"
+
"	yellow {33}\n"
+
"	blue {34}\n"
+
"	purple {35}\n"
+
"	cyan {36}\n"
+
"	normal {37}\n"
+
"	grey {30 1}\n"
+
"	gray {30 1}\n"
+
"	lred {31 1}\n"
+
"	lgreen {32 1}\n"
+
"	lyellow {33 1}\n"
+
"	lblue {34 1}\n"
+
"	lpurple {35 1}\n"
+
"	lcyan {36 1}\n"
+
"	white {37 1}\n"
+
"}\n"
+
"\n"
+
"\n"
+
"set tcl::stdhint_col $tcl::stdhint_cols(lcyan)\n"
+
"\n"
+
"\n"
+
"proc tcl::stdhint {string} {\n"
+
"	set result \"\"\n"
+
"	if {[llength $string] >= 2} {\n"
+
"		lassign $string cmd arg\n"
+
"		if {$cmd in $::tcl::stdhint_commands || [info channel $cmd] ne \"\"} {\n"
+
"			catch {\n"
+
"				set help [$cmd -help $arg]\n"
+
"				if {[string match \"Usage: $cmd *\" $help]} {\n"
+
"					set n [llength $string]\n"
+
"					set subcmd [lindex $help $n]\n"
+
"					incr n\n"
+
"					set hint [join [lrange $help $n end]]\n"
+
"					set prefix \"\"\n"
+
"					if {![string match \"* \" $string]} {\n"
+
"						if {$n == 3 && $subcmd ne $arg} {\n"
+
"\n"
+
"							set prefix \"[string range $subcmd [string length $arg] end] \"\n"
+
"						} else {\n"
+
"							set prefix \" \"\n"
+
"						}\n"
+
"					}\n"
+
"					set result [list $prefix$hint {*}$::tcl::stdhint_col]\n"
+
"				}\n"
+
"			}\n"
+
"		}\n"
+
"	}\n"
+
"	return $result\n"
+
"}\n"
+
"\n"
"_jimsh_init\n"
);
}
@@ -1482,36 +1656,31 @@ int Jim_stdlibInit(Jim_Interp *interp)
"}\n"
"\n"
"\n"
-
"\n"
-
"\n"
-
"proc stacktrace {{skip 0}} {\n"
-
"	set trace {}\n"
-
"	incr skip\n"
-
"	foreach level [range $skip [info level]] {\n"
-
"		lappend trace {*}[info frame -$level]\n"
-
"	}\n"
-
"	return $trace\n"
-
"}\n"
-
"\n"
-
"\n"
"proc stackdump {stacktrace} {\n"
"	set lines {}\n"
-
"	foreach {l f p} [lreverse $stacktrace] {\n"
+
"	lappend lines \"Traceback (most recent call last):\"\n"
+
"	foreach {cmd l f p} [lreverse $stacktrace] {\n"
"		set line {}\n"
-
"		if {$p ne \"\"} {\n"
-
"			append line \"in procedure '$p' \"\n"
-
"			if {$f ne \"\"} {\n"
-
"				append line \"called \"\n"
-
"			}\n"
-
"		}\n"
"		if {$f ne \"\"} {\n"
-
"			append line \"at file \\\"$f\\\", line $l\"\n"
+
"			append line \"  File \\\"$f\\\", line $l\"\n"
+
"		}\n"
+
"		if {$p ne \"\"} {\n"
+
"			append line \", in $p\"\n"
"		}\n"
"		if {$line ne \"\"} {\n"
"			lappend lines $line\n"
+
"			if {$cmd ne \"\"} {\n"
+
"				set nl [string first \\n $cmd 1]\n"
+
"				if {$nl >= 0} {\n"
+
"					set cmd [string range $cmd 0 $nl-1]...\n"
+
"				}\n"
+
"				lappend lines \"    $cmd\"\n"
+
"			}\n"
"		}\n"
"	}\n"
-
"	join $lines \\n\n"
+
"	if {[llength $lines] > 1} {\n"
+
"		return [join $lines \\n]\n"
+
"	}\n"
"}\n"
"\n"
"\n"
@@ -1527,10 +1696,8 @@ int Jim_stdlibInit(Jim_Interp *interp)
"	if {$stacktrace eq \"\"} {\n"
"\n"
"		set stacktrace [info stacktrace]\n"
-
"\n"
-
"		lappend stacktrace {*}[stacktrace 1]\n"
"	}\n"
-
"	lassign $stacktrace p f l\n"
+
"	lassign $stacktrace p f l cmd\n"
"	if {$f ne \"\"} {\n"
"		set result \"$f:$l: Error: \"\n"
"	}\n"
@@ -1643,7 +1810,7 @@ int Jim_tclcompatInit(Jim_Interp *interp)
"set env [env]\n"
"\n"
"\n"
-
"if {[info commands stdout] ne \"\"} {\n"
+
"if {[exists -command stdout]} {\n"
"\n"
"	foreach p {gets flush close eof seek tell} {\n"
"		proc $p {chan args} {p} {\n"
@@ -1817,72 +1984,6 @@ int Jim_tclcompatInit(Jim_Interp *interp)
"\n"
"\n"
"\n"
-
"\n"
-
"\n"
-
"\n"
-
"\n"
-
"\n"
-
"\n"
-
"\n"
-
"proc try {args} {\n"
-
"	set catchopts {}\n"
-
"	while {[string match -* [lindex $args 0]]} {\n"
-
"		set args [lassign $args opt]\n"
-
"		if {$opt eq \"--\"} {\n"
-
"			break\n"
-
"		}\n"
-
"		lappend catchopts $opt\n"
-
"	}\n"
-
"	if {[llength $args] == 0} {\n"
-
"		return -code error {wrong # args: should be \"try ?options? script ?argument ...?\"}\n"
-
"	}\n"
-
"	set args [lassign $args script]\n"
-
"	set code [catch -eval {*}$catchopts {uplevel 1 $script} msg opts]\n"
-
"\n"
-
"	set handled 0\n"
-
"\n"
-
"	foreach {on codes vars script} $args {\n"
-
"		switch -- $on \\\n"
-
"			on {\n"
-
"				if {!$handled && ($codes eq \"*\" || [info returncode $code] in $codes)} {\n"
-
"					lassign $vars msgvar optsvar\n"
-
"					if {$msgvar ne \"\"} {\n"
-
"						upvar $msgvar hmsg\n"
-
"						set hmsg $msg\n"
-
"					}\n"
-
"					if {$optsvar ne \"\"} {\n"
-
"						upvar $optsvar hopts\n"
-
"						set hopts $opts\n"
-
"					}\n"
-
"\n"
-
"					set code [catch {uplevel 1 $script} msg opts]\n"
-
"					incr handled\n"
-
"				}\n"
-
"			} \\\n"
-
"			finally {\n"
-
"				set finalcode [catch {uplevel 1 $codes} finalmsg finalopts]\n"
-
"				if {$finalcode} {\n"
-
"\n"
-
"					set code $finalcode\n"
-
"					set msg $finalmsg\n"
-
"					set opts $finalopts\n"
-
"				}\n"
-
"				break\n"
-
"			} \\\n"
-
"			default {\n"
-
"				return -code error \"try: expected 'on' or 'finally', got '$on'\"\n"
-
"			}\n"
-
"	}\n"
-
"\n"
-
"	if {$code} {\n"
-
"		incr opts(-level)\n"
-
"		return {*}$opts $msg\n"
-
"	}\n"
-
"	return $msg\n"
-
"}\n"
-
"\n"
-
"\n"
-
"\n"
"proc throw {code {msg \"\"}} {\n"
"	return -code $code $msg\n"
"}\n"
@@ -1898,17 +1999,21 @@ int Jim_tclcompatInit(Jim_Interp *interp)
}


-
#ifndef _GNU_SOURCE
-
#define _GNU_SOURCE
-
#endif
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
+
#include <assert.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#include <sys/stat.h>
#endif
+
#ifdef HAVE_UTIL_H
+
#include <util.h>
+
#endif
+
#ifdef HAVE_PTY_H
+
#include <pty.h>
+
#endif


#if defined(HAVE_SYS_SOCKET_H) && defined(HAVE_SELECT) && defined(HAVE_NETINET_IN_H) && defined(HAVE_NETDB_H) && defined(HAVE_ARPA_INET_H)
@@ -1923,8 +2028,6 @@ int Jim_tclcompatInit(Jim_Interp *interp)
#define HAVE_SOCKETS
#elif defined (__MINGW32__)

-
#else
-
#define JIM_ANSIC
#endif

#if defined(JIM_SSL)
@@ -1938,15 +2041,19 @@ int Jim_tclcompatInit(Jim_Interp *interp)

#define AIO_CMD_LEN 32
#define AIO_BUF_LEN 256
-

-
#ifndef HAVE_FTELLO
-
    #define ftello ftell
-
#endif
-
#ifndef HAVE_FSEEKO
-
    #define fseeko fseek
-
#endif
+
#define AIO_WBUF_FULL_SIZE (64 * 1024)

#define AIO_KEEPOPEN 1
+
#define AIO_NODELETE 2
+
#define AIO_EOF 4
+
#define AIO_WBUF_NONE 8
+
#define AIO_NONBLOCK 16
+

+
enum wbuftype {
+
    WBUF_OPT_NONE,
+
    WBUF_OPT_LINE,
+
    WBUF_OPT_FULL,
+
};

#if defined(JIM_IPV6)
#define IPV6 1
@@ -1956,20 +2063,49 @@ int Jim_tclcompatInit(Jim_Interp *interp)
#define PF_INET6 0
#endif
#endif
+
#if defined(HAVE_SYS_UN_H) && defined(PF_UNIX)
+
#define UNIX_SOCKETS 1
+
#else
+
#define UNIX_SOCKETS 0
+
#endif
+

+
#ifndef MAXPATHLEN
+
#define MAXPATHLEN JIM_PATH_LEN
+
#endif
+

+


-
#ifdef JIM_ANSIC

-
#undef HAVE_PIPE
-
#undef HAVE_SOCKETPAIR
+
static int JimReadableTimeout(int fd, long ms)
+
{
+
#ifdef HAVE_SELECT
+
    int retval;
+
    struct timeval tv;
+
    fd_set rfds;
+

+
    FD_ZERO(&rfds);
+

+
    FD_SET(fd, &rfds);
+
    tv.tv_sec = ms / 1000;
+
    tv.tv_usec = (ms % 1000) * 1000;
+

+
    retval = select(fd + 1, &rfds, NULL, NULL, ms == 0 ? NULL : &tv);
+

+
    if (retval > 0) {
+
        return JIM_OK;
+
    }
+
    return JIM_ERR;
+
#else
+
    return JIM_OK;
#endif
+
}


struct AioFile;

typedef struct {
    int (*writer)(struct AioFile *af, const char *buf, int len);
-
    int (*reader)(struct AioFile *af, char *buf, int len);
-
    const char *(*getline)(struct AioFile *af, char *buf, int len);
+
    int (*reader)(struct AioFile *af, char *buf, int len, int pending);
    int (*error)(const struct AioFile *af);
    const char *(*strerror)(struct AioFile *af);
    int (*verify)(struct AioFile *af);
@@ -1977,55 +2113,60 @@ typedef struct {

typedef struct AioFile
{
-
    FILE *fp;
    Jim_Obj *filename;
-
    int type;
-
    int openFlags;
+
    int wbuft;
+
    int flags;
+
    long timeout;
    int fd;
-
    Jim_Obj *rEvent;
-
    Jim_Obj *wEvent;
-
    Jim_Obj *eEvent;
    int addr_family;
    void *ssl;
    const JimAioFopsType *fops;
+
    Jim_Obj *readbuf;
+
    Jim_Obj *writebuf;
} AioFile;

static int stdio_writer(struct AioFile *af, const char *buf, int len)
{
-
    return fwrite(buf, 1, len, af->fp);
+
    return write(af->fd, buf, len);
}

-
static int stdio_reader(struct AioFile *af, char *buf, int len)
+
static int stdio_reader(struct AioFile *af, char *buf, int len, int nb)
{
-
    return fread(buf, 1, len, af->fp);
-
}
+
    if (nb || af->timeout == 0 || JimReadableTimeout(af->fd, af->timeout) == JIM_OK) {

-
static const char *stdio_getline(struct AioFile *af, char *buf, int len)
-
{
-
    return fgets(buf, len, af->fp);
+
        int ret;
+

+
        errno = 0;
+
        ret = read(af->fd, buf, len);
+
        if (ret <= 0 && errno != EAGAIN && errno != EINTR) {
+
            af->flags |= AIO_EOF;
+
        }
+
        return ret;
+
    }
+
    errno = ETIMEDOUT;
+
    return -1;
}

static int stdio_error(const AioFile *af)
{
-
    if (!ferror(af->fp)) {
+
    if (af->flags & AIO_EOF) {
        return JIM_OK;
    }
-
    clearerr(af->fp);

-
    if (feof(af->fp) || errno == EAGAIN || errno == EINTR) {
-
        return JIM_OK;
-
    }
+
    switch (errno) {
+
        case EAGAIN:
+
        case EINTR:
+
        case ETIMEDOUT:
#ifdef ECONNRESET
-
    if (errno == ECONNRESET) {
-
        return JIM_OK;
-
    }
+
        case ECONNRESET:
#endif
#ifdef ECONNABORTED
-
    if (errno == ECONNABORTED) {
-
        return JIM_OK;
-
    }
+
        case ECONNABORTED:
#endif
-
    return JIM_ERR;
+
            return JIM_OK;
+
        default:
+
            return JIM_ERR;
+
    }
}

static const char *stdio_strerror(struct AioFile *af)
@@ -2036,16 +2177,43 @@ static const char *stdio_strerror(struct AioFile *af)
static const JimAioFopsType stdio_fops = {
    stdio_writer,
    stdio_reader,
-
    stdio_getline,
    stdio_error,
    stdio_strerror,
-
    NULL
+
    NULL,
};


+
static void aio_set_nonblocking(AioFile *af, int nb)
+
{
+
#ifdef O_NDELAY
+
    int old = !!(af->flags & AIO_NONBLOCK);
+
    if (old != nb) {
+
        int fmode = fcntl(af->fd, F_GETFL);
+
        if (nb) {
+
            fmode |= O_NDELAY;
+
            af->flags |= AIO_NONBLOCK;
+
        }
+
        else {
+
            fmode &= ~O_NDELAY;
+
            af->flags &= ~AIO_NONBLOCK;
+
        }
+
        (void)fcntl(af->fd, F_SETFL, fmode);
+
    }
+
#endif
+
}
+

+
static int aio_start_nonblocking(AioFile *af)
+
{
+
    int old = !!(af->flags & AIO_NONBLOCK);
+
    if (af->timeout) {
+
        aio_set_nonblocking(af, 1);
+
    }
+
    return old;
+
}
+

static int JimAioSubCmdProc(Jim_Interp *interp, int argc, Jim_Obj *const *argv);
-
static AioFile *JimMakeChannel(Jim_Interp *interp, FILE *fh, int fd, Jim_Obj *filename,
-
    const char *hdlfmt, int family, const char *mode);
+
static AioFile *JimMakeChannel(Jim_Interp *interp, int fd, Jim_Obj *filename,
+
    const char *hdlfmt, int family, int flags);


static const char *JimAioErrorString(AioFile *af)
@@ -2068,66 +2236,95 @@ static void JimAioSetError(Jim_Interp *interp, Jim_Obj *name)
    }
}

+
static int aio_eof(AioFile *af)
+
{
+
    return af->flags & AIO_EOF;
+
}
+

static int JimCheckStreamError(Jim_Interp *interp, AioFile *af)
{
-
	int ret = af->fops->error(af);
-
	if (ret) {
-
		JimAioSetError(interp, af->filename);
-
	}
-
	return ret;
+
    int ret = 0;
+
    if (!aio_eof(af)) {
+
        ret = af->fops->error(af);
+
        if (ret) {
+
            JimAioSetError(interp, af->filename);
+
        }
+
    }
+
    return ret;
}

-
static void JimAioDelProc(Jim_Interp *interp, void *privData)
+
static void aio_consume(Jim_Obj *objPtr, int n)
{
-
    AioFile *af = privData;
+
    assert(objPtr->bytes);
+
    assert(n <= objPtr->length);

-
    JIM_NOTUSED(interp);

-
    Jim_DecrRefCount(interp, af->filename);
+
    memmove(objPtr->bytes, objPtr->bytes + n, objPtr->length - n + 1);
+
    objPtr->length -= n;
+
}
+

+

+
static int aio_autoflush(Jim_Interp *interp, void *clientData, int mask);
+

+
static int aio_flush(Jim_Interp *interp, AioFile *af)
+
{
+
    int len;
+
    const char *pt = Jim_GetString(af->writebuf, &len);
+
    if (len) {
+
        int ret = af->fops->writer(af, pt, len);
+
        if (ret > 0) {

+
            aio_consume(af->writebuf, ret);
+
        }
+
        if (ret < 0) {
+
            return JimCheckStreamError(interp, af);
+
        }
+
        if (Jim_Length(af->writebuf)) {
#ifdef jim_ext_eventloop
+
            void *handler = Jim_FindFileHandler(interp, af->fd, JIM_EVENT_WRITABLE);
+
            if (handler == NULL) {
+
                Jim_CreateFileHandler(interp, af->fd, JIM_EVENT_WRITABLE, aio_autoflush, af, NULL);
+
                return JIM_OK;
+
            }
+
            else if (handler == af) {

-
    Jim_DeleteFileHandler(interp, af->fd, JIM_EVENT_READABLE | JIM_EVENT_WRITABLE | JIM_EVENT_EXCEPTION);
+
                return JIM_OK;
+
            }
#endif

-
#if defined(JIM_SSL)
-
    if (af->ssl != NULL) {
-
        SSL_free(af->ssl);
-
    }
-
#endif
-
    if (!(af->openFlags & AIO_KEEPOPEN)) {
-
        fclose(af->fp);
+
            Jim_SetResultString(interp, "send buffer is full", -1);
+
            return JIM_ERR;
+
        }
    }
-

-
    Jim_Free(af);
+
    return JIM_OK;
}

-
static int aio_cmd_read(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+
static int aio_autoflush(Jim_Interp *interp, void *clientData, int mask)
{
-
    AioFile *af = Jim_CmdPrivData(interp);
-
    char buf[AIO_BUF_LEN];
-
    Jim_Obj *objPtr;
-
    int nonewline = 0;
-
    jim_wide neededLen = -1;
+
    AioFile *af = clientData;

-
    if (argc && Jim_CompareStringImmediate(interp, argv[0], "-nonewline")) {
-
        nonewline = 1;
-
        argv++;
-
        argc--;
+
    aio_flush(interp, af);
+
    if (Jim_Length(af->writebuf) == 0) {
+

+
        return -1;
    }
-
    if (argc == 1) {
-
        if (Jim_GetWide(interp, argv[0], &neededLen) != JIM_OK)
-
            return JIM_ERR;
-
        if (neededLen < 0) {
-
            Jim_SetResultString(interp, "invalid parameter: negative len", -1);
-
            return JIM_ERR;
-
        }
+
    return 0;
+
}
+

+
static int aio_read_len(Jim_Interp *interp, AioFile *af, int nb, char *buf, size_t buflen, int neededLen)
+
{
+
    if (!af->readbuf) {
+
        af->readbuf = Jim_NewStringObj(interp, NULL, 0);
    }
-
    else if (argc) {
-
        return -1;
+

+
    if (neededLen >= 0) {
+
        neededLen -= Jim_Length(af->readbuf);
+
        if (neededLen <= 0) {
+
            return JIM_OK;
+
        }
    }
-
    objPtr = Jim_NewStringObj(interp, NULL, 0);
-
    while (neededLen != 0) {
+

+
    while (neededLen && !aio_eof(af)) {
        int retval;
        int readlen;

@@ -2137,64 +2334,180 @@ static int aio_cmd_read(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
        else {
            readlen = (neededLen > AIO_BUF_LEN ? AIO_BUF_LEN : neededLen);
        }
-
        retval = af->fops->reader(af, buf, readlen);
+
        retval = af->fops->reader(af, buf, readlen, nb);
        if (retval > 0) {
-
            Jim_AppendString(interp, objPtr, buf, retval);
+
            Jim_AppendString(interp, af->readbuf, buf, retval);
            if (neededLen != -1) {
                neededLen -= retval;
            }
+
            continue;
        }
-
        if (retval != readlen)
-
            break;
-
    }
-

-
    if (JimCheckStreamError(interp, af)) {
-
        Jim_FreeNewObj(interp, objPtr);
-
        return JIM_ERR;
-
    }
-
    if (nonewline) {
-
        int len;
-
        const char *s = Jim_GetString(objPtr, &len);
-

-
        if (len > 0 && s[len - 1] == '\n') {
-
            objPtr->length--;
-
            objPtr->bytes[objPtr->length] = '\0';
+
        if (JimCheckStreamError(interp, af)) {
+
            return JIM_ERR;
+
        }
+
        if (nb || af->timeout) {
+
            return JIM_OK;
        }
    }
-
    Jim_SetResult(interp, objPtr);
+

    return JIM_OK;
}

-
AioFile *Jim_AioFile(Jim_Interp *interp, Jim_Obj *command)
+
static Jim_Obj *aio_read_consume(Jim_Interp *interp, AioFile *af, int neededLen)
{
-
    Jim_Cmd *cmdPtr = Jim_GetCommand(interp, command, JIM_ERRMSG);
+
    Jim_Obj *objPtr = NULL;

+
    if (neededLen < 0 || af->readbuf == NULL || Jim_Length(af->readbuf) <= neededLen) {
+
        objPtr = af->readbuf;
+
        af->readbuf = NULL;
+
    }
+
    else if (af->readbuf) {

-
    if (cmdPtr && !cmdPtr->isproc && cmdPtr->u.native.cmdProc == JimAioSubCmdProc) {
-
        return (AioFile *) cmdPtr->u.native.privData;
+
        int len;
+
        const char *pt = Jim_GetString(af->readbuf, &len);
+

+
        objPtr  = Jim_NewStringObj(interp, pt, neededLen);
+
        aio_consume(af->readbuf, neededLen);
    }
-
    Jim_SetResultFormatted(interp, "Not a filehandle: \"%#s\"", command);
-
    return NULL;
+

+
    return objPtr;
}

-
FILE *Jim_AioFilehandle(Jim_Interp *interp, Jim_Obj *command)
+
static void JimAioDelProc(Jim_Interp *interp, void *privData)
{
-
    AioFile *af;
+
    AioFile *af = privData;

-
    af = Jim_AioFile(interp, command);
-
    if (af == NULL) {
-
        return NULL;
+
    JIM_NOTUSED(interp);
+

+

+
    aio_flush(interp, af);
+
    Jim_DecrRefCount(interp, af->writebuf);
+

+
#if UNIX_SOCKETS
+
    if (af->addr_family == PF_UNIX && (af->flags & AIO_NODELETE) == 0) {
+

+
        Jim_Obj *filenameObj = aio_sockname(interp, af->fd);
+
        if (filenameObj) {
+
            if (Jim_Length(filenameObj)) {
+
                remove(Jim_String(filenameObj));
+
            }
+
            Jim_FreeNewObj(interp, filenameObj);
+
        }
+
    }
+
#endif
+

+
    Jim_DecrRefCount(interp, af->filename);
+

+
#ifdef jim_ext_eventloop
+

+
    Jim_DeleteFileHandler(interp, af->fd, JIM_EVENT_READABLE | JIM_EVENT_WRITABLE | JIM_EVENT_EXCEPTION);
+
#endif
+

+
#if defined(JIM_SSL)
+
    if (af->ssl != NULL) {
+
        SSL_free(af->ssl);
+
    }
+
#endif
+
    if (!(af->flags & AIO_KEEPOPEN)) {
+
        close(af->fd);
+
    }
+
    if (af->readbuf) {
+
        Jim_FreeNewObj(interp, af->readbuf);
    }

-
    return af->fp;
+
    Jim_Free(af);
+
}
+

+
static int aio_cmd_read(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+
{
+
    AioFile *af = Jim_CmdPrivData(interp);
+
    int nonewline = 0;
+
    jim_wide neededLen = -1;
+
    static const char * const options[] = { "-pending", "-nonewline", NULL };
+
    enum { OPT_PENDING, OPT_NONEWLINE };
+
    int option;
+
    int nb;
+
    Jim_Obj *objPtr;
+
    char buf[AIO_BUF_LEN];
+

+
    if (argc) {
+
        if (*Jim_String(argv[0]) == '-') {
+
            if (Jim_GetEnum(interp, argv[0], options, &option, NULL, JIM_ERRMSG) != JIM_OK) {
+
                return JIM_ERR;
+
            }
+
            switch (option) {
+
                case OPT_PENDING:
+

+
                    break;
+
                case OPT_NONEWLINE:
+
                    nonewline++;
+
                    break;
+
            }
+
        }
+
        else {
+
            if (Jim_GetWide(interp, argv[0], &neededLen) != JIM_OK)
+
                return JIM_ERR;
+
            if (neededLen < 0) {
+
                Jim_SetResultString(interp, "invalid parameter: negative len", -1);
+
                return JIM_ERR;
+
            }
+
        }
+
        argc--;
+
        argv++;
+
    }
+
    if (argc) {
+
        return -1;
+
    }
+

+

+
    nb = aio_start_nonblocking(af);
+

+
    if (aio_read_len(interp, af, nb, buf, sizeof(buf), neededLen) != JIM_OK) {
+
        aio_set_nonblocking(af, nb);
+
        return JIM_ERR;
+
    }
+
    objPtr = aio_read_consume(interp, af, neededLen);
+

+
    aio_set_nonblocking(af, nb);
+

+
    if (objPtr) {
+
        if (nonewline) {
+
            int len;
+
            const char *s = Jim_GetString(objPtr, &len);
+

+
            if (len > 0 && s[len - 1] == '\n') {
+
                objPtr->length--;
+
                objPtr->bytes[objPtr->length] = '\0';
+
            }
+
        }
+
        Jim_SetResult(interp, objPtr);
+
    }
+
    else {
+
        Jim_SetEmptyResult(interp);
+
    }
+
    return JIM_OK;
+
}
+

+
int Jim_AioFilehandle(Jim_Interp *interp, Jim_Obj *command)
+
{
+
    Jim_Cmd *cmdPtr = Jim_GetCommand(interp, command, JIM_ERRMSG);
+

+

+
    if (cmdPtr && !cmdPtr->isproc && cmdPtr->u.native.cmdProc == JimAioSubCmdProc) {
+
        return ((AioFile *) cmdPtr->u.native.privData)->fd;
+
    }
+
    Jim_SetResultFormatted(interp, "Not a filehandle: \"%#s\"", command);
+
    return -1;
}

static int aio_cmd_getfd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
    AioFile *af = Jim_CmdPrivData(interp);

-
    fflush(af->fp);
-
    Jim_SetResultInt(interp, fileno(af->fp));
+

+
    aio_flush(interp, af);
+

+
    Jim_SetResultInt(interp, af->fd);

    return JIM_OK;
}
@@ -2204,11 +2517,13 @@ static int aio_cmd_copy(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
    AioFile *af = Jim_CmdPrivData(interp);
    jim_wide count = 0;
    jim_wide maxlen = JIM_WIDE_MAX;
-
    AioFile *outf = Jim_AioFile(interp, argv[0]);

-
    if (outf == NULL) {
-
        return JIM_ERR;
-
    }
+
    char buf[AIO_BUF_LEN];
+

+
    char *bufp = buf;
+
    int buflen = sizeof(buf);
+
    int ok = 1;
+
    Jim_Obj *objv[4];

    if (argc == 2) {
        if (Jim_GetWide(interp, argv[1], &maxlen) != JIM_OK) {
@@ -2216,19 +2531,53 @@ static int aio_cmd_copy(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
        }
    }

-
    while (count < maxlen) {
-
        char ch;
+
    objv[0] = argv[0];
+
    objv[1] = Jim_NewStringObj(interp, "flush", -1);
+
    if (Jim_EvalObjVector(interp, 2, objv) != JIM_OK) {
+
        Jim_SetResultFormatted(interp, "Not a filehandle: \"%#s\"", argv[0]);
+
        return JIM_ERR;
+
    }

-
        if (af->fops->reader(af, &ch, 1) != 1) {
+

+
    objv[0] = argv[0];
+
    objv[1] = Jim_NewStringObj(interp, "puts", -1);
+
    objv[2] = Jim_NewStringObj(interp, "-nonewline", -1);
+
    Jim_IncrRefCount(objv[1]);
+
    Jim_IncrRefCount(objv[2]);
+

+
    while (count < maxlen) {
+
        jim_wide len = maxlen - count;
+
        if (len > buflen) {
+
            len = buflen;
+
        }
+
        if (aio_read_len(interp, af, 0, bufp, buflen, len) != JIM_OK) {
+
            ok = 0;
            break;
        }
-
        if (outf->fops->writer(outf, &ch, 1) != 1) {
+
        objv[3] = aio_read_consume(interp, af, len);
+
        count += Jim_Length(objv[3]);
+
        if (Jim_EvalObjVector(interp, 4, objv) != JIM_OK) {
+
            ok = 0;
            break;
        }
-
        count++;
+
        if (aio_eof(af)) {
+
            break;
+
        }
+
        if (count >= 16384 && bufp == buf) {
+

+
            buflen = 65536;
+
            bufp = Jim_Alloc(buflen);
+
        }
    }

-
    if (JimCheckStreamError(interp, af) || JimCheckStreamError(interp, outf)) {
+
    if (bufp != buf) {
+
        Jim_Free(bufp);
+
    }
+

+
    Jim_DecrRefCount(interp, objv[1]);
+
    Jim_DecrRefCount(interp, objv[2]);
+

+
    if (!ok) {
        return JIM_ERR;
    }

@@ -2241,38 +2590,54 @@ 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;
+
    Jim_Obj *objPtr = NULL;
    int len;
+
    int nb;
+
    char *nl = NULL;
+
    int offset = 0;

    errno = 0;

-
    objPtr = Jim_NewStringObj(interp, NULL, 0);
-
    while (1) {
-
        buf[AIO_BUF_LEN - 1] = '_';

-
        if (af->fops->getline(af, buf, AIO_BUF_LEN) == NULL)
-
            break;
+
    nb = aio_start_nonblocking(af);

-
        if (buf[AIO_BUF_LEN - 1] == '\0' && buf[AIO_BUF_LEN - 2] != '\n') {
-
            Jim_AppendString(interp, objPtr, buf, AIO_BUF_LEN - 1);
-
        }
-
        else {
-
            len = strlen(buf);
+
    if (!af->readbuf) {
+
        af->readbuf = Jim_NewStringObj(interp, NULL, 0);
+
    }

-
            if (len && (buf[len - 1] == '\n')) {
+
    while (!aio_eof(af)) {
+
        const char *pt = Jim_GetString(af->readbuf, &len);
+
        nl = memchr(pt + offset, '\n', len - offset);
+
        if (nl) {

-
                len--;
-
            }
+
            objPtr = Jim_NewStringObj(interp, pt, nl - pt);

-
            Jim_AppendString(interp, objPtr, buf, len);
+
            aio_consume(af->readbuf, nl - pt + 1);
            break;
        }
+

+
        offset = len;
+
        len = af->fops->reader(af, buf, AIO_BUF_LEN, nb);
+
        if (len <= 0) {
+
            if (nb || af->timeout) {
+

+
                break;
+
            }
+
        }
+
        else {
+
            Jim_AppendString(interp, af->readbuf, buf, len);
+
        }
    }

-
    if (JimCheckStreamError(interp, af)) {
+
    aio_set_nonblocking(af, nb);

-
        Jim_FreeNewObj(interp, objPtr);
-
        return JIM_ERR;
+
    if (!nl && aio_eof(af)) {
+

+
        objPtr = af->readbuf;
+
        af->readbuf = NULL;
+
    }
+
    else if (!objPtr) {
+
        objPtr = Jim_NewStringObj(interp, NULL, 0);
    }

    if (argc) {
@@ -2283,7 +2648,7 @@ static int aio_cmd_gets(Jim_Interp *interp, int argc, Jim_Obj *const *argv)

        len = Jim_Length(objPtr);

-
        if (len == 0 && feof(af->fp)) {
+
        if (!nl && len == 0) {

            len = -1;
        }
@@ -2301,32 +2666,58 @@ static int aio_cmd_puts(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
    int wlen;
    const char *wdata;
    Jim_Obj *strObj;
+
    int wnow = 0;
+
    int nl = 1;

    if (argc == 2) {
        if (!Jim_CompareStringImmediate(interp, argv[0], "-nonewline")) {
            return -1;
        }
        strObj = argv[1];
+
        nl = 0;
    }
    else {
        strObj = argv[0];
    }

-
    wdata = Jim_GetString(strObj, &wlen);
-
    if (af->fops->writer(af, wdata, wlen) == wlen) {
-
        if (argc == 2 || af->fops->writer(af, "\n", 1) == 1) {
-
            return JIM_OK;
-
        }
+
    Jim_AppendObj(interp, af->writebuf, strObj);
+
    if (nl) {
+
        Jim_AppendString(interp, af->writebuf, "\n", 1);
    }
-
    JimAioSetError(interp, af->filename);
-
    return JIM_ERR;
+

+

+
    wdata = Jim_GetString(af->writebuf, &wlen);
+
    switch (af->wbuft) {
+
        case WBUF_OPT_NONE:
+

+
            wnow = 1;
+
            break;
+

+
        case WBUF_OPT_LINE:
+

+
            if (nl || memchr(wdata, '\n', wlen) != NULL) {
+
                wnow = 1;
+
            }
+
            break;
+

+
        case WBUF_OPT_FULL:
+
            if (wlen >= AIO_WBUF_FULL_SIZE) {
+
                wnow = 1;
+
            }
+
            break;
+
    }
+

+
    if (wnow) {
+
        return aio_flush(interp, af);
+
    }
+
    return JIM_OK;
}

static int aio_cmd_isatty(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
#ifdef HAVE_ISATTY
    AioFile *af = Jim_CmdPrivData(interp);
-
    Jim_SetResultInt(interp, isatty(fileno(af->fp)));
+
    Jim_SetResultInt(interp, isatty(af->fd));
#else
    Jim_SetResultInt(interp, 0);
#endif
@@ -2338,45 +2729,58 @@ static int aio_cmd_isatty(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
static int aio_cmd_flush(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
    AioFile *af = Jim_CmdPrivData(interp);
-

-
    if (fflush(af->fp) == EOF) {
-
        JimAioSetError(interp, af->filename);
-
        return JIM_ERR;
-
    }
-
    return JIM_OK;
+
    return aio_flush(interp, af);
}

static int aio_cmd_eof(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
    AioFile *af = Jim_CmdPrivData(interp);

-
    Jim_SetResultInt(interp, feof(af->fp));
+
    Jim_SetResultInt(interp, !!aio_eof(af));
    return JIM_OK;
}

static int aio_cmd_close(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
+
    AioFile *af = Jim_CmdPrivData(interp);
    if (argc == 3) {
-
#if defined(HAVE_SOCKETS) && defined(HAVE_SHUTDOWN)
-
        static const char * const options[] = { "r", "w", NULL };
-
        enum { OPT_R, OPT_W, };
-
        int option;
-
        AioFile *af = Jim_CmdPrivData(interp);
+
        int option = -1;
+
#if defined(HAVE_SOCKETS)
+
        static const char * const options[] = { "r", "w", "-nodelete", NULL };
+
        enum { OPT_R, OPT_W, OPT_NODELETE };

        if (Jim_GetEnum(interp, argv[2], options, &option, NULL, JIM_ERRMSG) != JIM_OK) {
            return JIM_ERR;
        }
-
        if (shutdown(af->fd, option == OPT_R ? SHUT_RD : SHUT_WR) == 0) {
-
            return JIM_OK;
-
        }
-
        JimAioSetError(interp, NULL);
-
#else
-
        Jim_SetResultString(interp, "async close not supported", -1);
#endif
-
        return JIM_ERR;
+
        switch (option) {
+
#if defined(HAVE_SHUTDOWN)
+
            case OPT_R:
+
            case OPT_W:
+
                if (shutdown(af->fd, option == OPT_R ? SHUT_RD : SHUT_WR) == 0) {
+
                    return JIM_OK;
+
                }
+
                JimAioSetError(interp, NULL);
+
                return JIM_ERR;
+
#endif
+
#if UNIX_SOCKETS
+
            case OPT_NODELETE:
+
                if (af->addr_family == PF_UNIX) {
+
                    af->flags |= AIO_NODELETE;
+
                    break;
+
                }
+

+
#endif
+
            default:
+
                Jim_SetResultString(interp, "not supported", -1);
+
                return JIM_ERR;
+
        }
    }

-
    return Jim_DeleteCommand(interp, Jim_String(argv[0]));
+

+
    af->flags &= ~AIO_KEEPOPEN;
+

+
    return Jim_DeleteCommand(interp, argv[0]);
}

static int aio_cmd_seek(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
@@ -2399,10 +2803,19 @@ static int aio_cmd_seek(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
    if (Jim_GetWide(interp, argv[0], &offset) != JIM_OK) {
        return JIM_ERR;
    }
-
    if (fseeko(af->fp, offset, orig) == -1) {
+
    if (orig != SEEK_CUR || offset != 0) {
+

+
        aio_flush(interp, af);
+
    }
+
    if (Jim_Lseek(af->fd, offset, orig) == -1) {
        JimAioSetError(interp, af->filename);
        return JIM_ERR;
    }
+
    if (af->readbuf) {
+
        Jim_FreeNewObj(interp, af->readbuf);
+
        af->readbuf = NULL;
+
    }
+
    af->flags &= ~AIO_EOF;
    return JIM_OK;
}

@@ -2410,7 +2823,7 @@ static int aio_cmd_tell(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
    AioFile *af = Jim_CmdPrivData(interp);

-
    Jim_SetResultInt(interp, ftello(af->fp));
+
    Jim_SetResultInt(interp, Jim_Lseek(af->fd, 0, SEEK_CUR));
    return JIM_OK;
}

@@ -2427,23 +2840,15 @@ static int aio_cmd_ndelay(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
    AioFile *af = Jim_CmdPrivData(interp);

-
    int fmode = fcntl(af->fd, F_GETFL);
-

    if (argc) {
        long nb;

        if (Jim_GetLong(interp, argv[0], &nb) != JIM_OK) {
            return JIM_ERR;
        }
-
        if (nb) {
-
            fmode |= O_NDELAY;
-
        }
-
        else {
-
            fmode &= ~O_NDELAY;
-
        }
-
        (void)fcntl(af->fd, F_SETFL, fmode);
+
        aio_set_nonblocking(af, nb);
    }
-
    Jim_SetResultInt(interp, (fmode & O_NONBLOCK) ? 1 : 0);
+
    Jim_SetResultInt(interp, (af->flags & AIO_NONBLOCK) ? 1 : 0);
    return JIM_OK;
}
#endif
@@ -2454,7 +2859,9 @@ static int aio_cmd_sync(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
    AioFile *af = Jim_CmdPrivData(interp);

-
    fflush(af->fp);
+
    if (aio_flush(interp, af) != JIM_OK) {
+
        return JIM_ERR;
+
    }
    fsync(af->fd);
    return JIM_OK;
}
@@ -2470,76 +2877,56 @@ static int aio_cmd_buffering(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
        "full",
        NULL
    };
-
    enum
-
    {
-
        OPT_NONE,
-
        OPT_LINE,
-
        OPT_FULL,
-
    };
-
    int option;

-
    if (Jim_GetEnum(interp, argv[0], options, &option, NULL, JIM_ERRMSG) != JIM_OK) {
+
    if (Jim_GetEnum(interp, argv[0], options, &af->wbuft, NULL, JIM_ERRMSG) != JIM_OK) {
        return JIM_ERR;
    }
-
    switch (option) {
-
        case OPT_NONE:
-
            setvbuf(af->fp, NULL, _IONBF, 0);
-
            break;
-
        case OPT_LINE:
-
            setvbuf(af->fp, NULL, _IOLBF, BUFSIZ);
-
            break;
-
        case OPT_FULL:
-
            setvbuf(af->fp, NULL, _IOFBF, BUFSIZ);
-
            break;
-
    }
-
    return JIM_OK;
-
}

-
#ifdef jim_ext_eventloop
-
static void JimAioFileEventFinalizer(Jim_Interp *interp, void *clientData)
-
{
-
    Jim_Obj **objPtrPtr = clientData;
+
    if (af->wbuft == WBUF_OPT_NONE) {
+
        return aio_flush(interp, af);
+
    }

-
    Jim_DecrRefCount(interp, *objPtrPtr);
-
    *objPtrPtr = NULL;
+
    return JIM_OK;
}

-
static int JimAioFileEventHandler(Jim_Interp *interp, void *clientData, int mask)
+
static int aio_cmd_timeout(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
-
    Jim_Obj **objPtrPtr = clientData;
-

-
    return Jim_EvalObjBackground(interp, *objPtrPtr);
+
#ifdef HAVE_SELECT
+
    AioFile *af = Jim_CmdPrivData(interp);
+
    if (argc == 1) {
+
        if (Jim_GetLong(interp, argv[0], &af->timeout) != JIM_OK) {
+
            return JIM_ERR;
+
        }
+
    }
+
    Jim_SetResultInt(interp, af->timeout);
+
    return JIM_OK;
+
#else
+
    Jim_SetResultString(interp, "timeout not supported", -1);
+
    return JIM_ERR;
+
#endif
}

-
static int aio_eventinfo(Jim_Interp *interp, AioFile * af, unsigned mask, Jim_Obj **scriptHandlerObj,
+
#ifdef jim_ext_eventloop
+
static int aio_eventinfo(Jim_Interp *interp, AioFile * af, unsigned mask,
    int argc, Jim_Obj * const *argv)
{
    if (argc == 0) {

-
        if (*scriptHandlerObj) {
-
            Jim_SetResult(interp, *scriptHandlerObj);
+
        Jim_Obj *objPtr = Jim_FindFileHandler(interp, af->fd, mask);
+
        if (objPtr) {
+
            Jim_SetResult(interp, objPtr);
        }
        return JIM_OK;
    }

-
    if (*scriptHandlerObj) {
-

-
        Jim_DeleteFileHandler(interp, af->fd, mask);
-
    }

+
    Jim_DeleteFileHandler(interp, af->fd, mask);

-
    if (Jim_Length(argv[0]) == 0) {

-
        return JIM_OK;
+
    if (Jim_Length(argv[0])) {
+
        Jim_CreateScriptFileHandler(interp, af->fd, mask, argv[0]);
    }

-

-
    Jim_IncrRefCount(argv[0]);
-
    *scriptHandlerObj = argv[0];
-

-
    Jim_CreateFileHandler(interp, af->fd, mask,
-
        JimAioFileEventHandler, scriptHandlerObj, JimAioFileEventFinalizer);
-

    return JIM_OK;
}

@@ -2547,21 +2934,35 @@ static int aio_cmd_readable(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
    AioFile *af = Jim_CmdPrivData(interp);

-
    return aio_eventinfo(interp, af, JIM_EVENT_READABLE, &af->rEvent, argc, argv);
+
    return aio_eventinfo(interp, af, JIM_EVENT_READABLE, argc, argv);
}

static int aio_cmd_writable(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
    AioFile *af = Jim_CmdPrivData(interp);

-
    return aio_eventinfo(interp, af, JIM_EVENT_WRITABLE, &af->wEvent, argc, argv);
+
    return aio_eventinfo(interp, af, JIM_EVENT_WRITABLE, argc, argv);
}

static int aio_cmd_onexception(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
    AioFile *af = Jim_CmdPrivData(interp);

-
    return aio_eventinfo(interp, af, JIM_EVENT_EXCEPTION, &af->eEvent, argc, argv);
+
    return aio_eventinfo(interp, af, JIM_EVENT_EXCEPTION, argc, argv);
+
}
+
#endif
+

+
#if defined(jim_ext_file) && defined(Jim_FileStat)
+
static int aio_cmd_stat(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+
{
+
    jim_stat_t sb;
+
    AioFile *af = Jim_CmdPrivData(interp);
+

+
    if (Jim_FileStat(af->fd, &sb) == -1) {
+
        JimAioSetError(interp, NULL);
+
        return JIM_ERR;
+
    }
+
    return Jim_FileStoreStatData(interp, argc == 0 ? NULL : argv[0], &sb);
}
#endif

@@ -2570,7 +2971,7 @@ static int aio_cmd_onexception(Jim_Interp *interp, int argc, Jim_Obj *const *arg

static const jim_subcmd_type aio_command_table[] = {
    {   "read",
-
        "?-nonewline? ?len?",
+
        "?-nonewline|len?",
        aio_cmd_read,
        0,
        2,
@@ -2679,6 +3080,15 @@ static const jim_subcmd_type aio_command_table[] = {
        1,

    },
+
#if defined(jim_ext_file) && defined(Jim_FileStat)
+
    {   "stat",
+
        "?var?",
+
        aio_cmd_stat,
+
        0,
+
        1,
+

+
    },
+
#endif
#ifdef jim_ext_eventloop
    {   "readable",
        "?readable-script?",
@@ -2701,6 +3111,13 @@ static const jim_subcmd_type aio_command_table[] = {
        1,

    },
+
    {   "timeout",
+
        "?ms?",
+
        aio_cmd_timeout,
+
        0,
+
        1,
+

+
    },
#endif
    { NULL }
};
@@ -2710,112 +3127,214 @@ 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 parse_posix_open_mode(Jim_Interp *interp, Jim_Obj *modeObj)
+
{
+
    int i;
+
    int flags = 0;
+
    #ifndef O_NOCTTY
+

+
        #define O_NOCTTY 0
+
    #endif
+
    static const char * const modetypes[] = {
+
        "RDONLY", "WRONLY", "RDWR", "APPEND", "BINARY", "CREAT", "EXCL", "NOCTTY", "TRUNC", NULL
+
    };
+
    static const int modeflags[] = {
+
        O_RDONLY, O_WRONLY, O_RDWR, O_APPEND, 0, O_CREAT, O_EXCL, O_NOCTTY, O_TRUNC,
+
    };
+

+
    for (i = 0; i < Jim_ListLength(interp, modeObj); i++) {
+
        int opt;
+
        Jim_Obj *objPtr = Jim_ListGetIndex(interp, modeObj, i);
+
        if (Jim_GetEnum(interp, objPtr, modetypes, &opt, "access mode", JIM_ERRMSG) != JIM_OK) {
+
            return -1;
+
        }
+
        flags |= modeflags[opt];
+
    }
+
    return flags;
+
}
+

+
static int parse_open_mode(Jim_Interp *interp, Jim_Obj *filenameObj, Jim_Obj *modeObj)
+
{
+

+
    int flags;
+
    const char *mode = Jim_String(modeObj);
+
    if (*mode == 'R' || *mode == 'W') {
+
        return parse_posix_open_mode(interp, modeObj);
+
    }
+
    if (*mode == 'r') {
+
        flags = O_RDONLY;
+
    }
+
    else if (*mode == 'w') {
+
        flags = O_WRONLY | O_CREAT | O_TRUNC;
+
    }
+
    else if (*mode == 'a') {
+
        flags = O_WRONLY | O_CREAT | O_APPEND;
+
    }
+
    else {
+
        Jim_SetResultFormatted(interp, "%s: invalid open mode '%s'", Jim_String(filenameObj), mode);
+
        return -1;
+
    }
+
    mode++;
+

+
    if (*mode == 'b') {
+
#ifdef O_BINARY
+
        flags |= O_BINARY;
+
#endif
+
        mode++;
+
    }
+

+
    if (*mode == 't') {
+
#ifdef O_TEXT
+
        flags |= O_TEXT;
+
#endif
+
        mode++;
+
    }
+

+
    if (*mode == '+') {
+
        mode++;
+

+
        flags &= ~(O_RDONLY | O_WRONLY);
+
        flags |= O_RDWR;
+
    }
+

+
    if (*mode == 'x') {
+
        mode++;
+
#ifdef O_EXCL
+
        flags |= O_EXCL;
+
#endif
+
    }
+

+
    if (*mode == 'F') {
+
        mode++;
+
#ifdef O_LARGEFILE
+
        flags |= O_LARGEFILE;
+
#endif
+
    }
+

+
    if (*mode == 'e') {
+

+
        mode++;
+
    }
+
    return flags;
+
}
+

static int JimAioOpenCommand(Jim_Interp *interp, int argc,
        Jim_Obj *const *argv)
{
-
    const char *mode;
+
    int openflags;
+
    const char *filename;
+
    int fd = -1;
+
    int n = 0;
+
    int flags = 0;

-
    if (argc != 2 && argc != 3) {
-
        Jim_WrongNumArgs(interp, 1, argv, "filename ?mode?");
+
    if (argc > 2 && Jim_CompareStringImmediate(interp, argv[2], "-noclose")) {
+
        flags = AIO_KEEPOPEN;
+
        n++;
+
    }
+
    if (argc < 2 || argc > 3 + n) {
+
        Jim_WrongNumArgs(interp, 1, argv, "filename ?-noclose? ?mode?");
        return JIM_ERR;
    }

-
    mode = (argc == 3) ? Jim_String(argv[2]) : "r";
+
    filename = Jim_String(argv[1]);

#ifdef jim_ext_tclcompat
    {
-
        const char *filename = Jim_String(argv[1]);


        if (*filename == '|') {
            Jim_Obj *evalObj[3];
+
            int i = 0;

-
            evalObj[0] = Jim_NewStringObj(interp, "::popen", -1);
-
            evalObj[1] = Jim_NewStringObj(interp, filename + 1, -1);
-
            evalObj[2] = Jim_NewStringObj(interp, mode, -1);
+
            evalObj[i++] = Jim_NewStringObj(interp, "::popen", -1);
+
            evalObj[i++] = Jim_NewStringObj(interp, filename + 1, -1);
+
            if (argc == 3 + n) {
+
                evalObj[i++] = argv[2 + n];
+
            }

-
            return Jim_EvalObjVector(interp, 3, evalObj);
+
            return Jim_EvalObjVector(interp, i, evalObj);
        }
    }
#endif
-
    return JimMakeChannel(interp, NULL, -1, argv[1], "aio.handle%ld", 0, mode) ? JIM_OK : JIM_ERR;
+
    if (argc == 3 + n) {
+
        openflags = parse_open_mode(interp, argv[1], argv[2 + n]);
+
        if (openflags == -1) {
+
            return JIM_ERR;
+
        }
+
    }
+
    else {
+
        openflags = O_RDONLY;
+
    }
+
    fd = open(filename, openflags, 0666);
+
    if (fd < 0) {
+
        JimAioSetError(interp, argv[1]);
+
        return JIM_ERR;
+
    }
+

+
    return JimMakeChannel(interp, fd, argv[1], "aio.handle%ld", 0, flags) ? JIM_OK : JIM_ERR;
}


-
static AioFile *JimMakeChannel(Jim_Interp *interp, FILE *fh, int fd, Jim_Obj *filename,
-
    const char *hdlfmt, int family, const char *mode)
+
static AioFile *JimMakeChannel(Jim_Interp *interp, int fd, Jim_Obj *filename,
+
    const char *hdlfmt, int family, int flags)
{
    AioFile *af;
    char buf[AIO_CMD_LEN];
-
    int openFlags = 0;
-

-
    snprintf(buf, sizeof(buf), hdlfmt, Jim_GetId(interp));
-

-
    if (fh) {
-
        openFlags = AIO_KEEPOPEN;
-
    }
+
    Jim_Obj *cmdname;

    snprintf(buf, sizeof(buf), hdlfmt, Jim_GetId(interp));
+
    cmdname = Jim_NewStringObj(interp, buf, -1);
    if (!filename) {
-
        filename = Jim_NewStringObj(interp, buf, -1);
+
        filename = cmdname;
    }
-

    Jim_IncrRefCount(filename);

-
    if (fh == NULL) {
-
        if (fd >= 0) {
-
#ifndef JIM_ANSIC
-
            fh = fdopen(fd, mode);
-
#endif
-
        }
-
        else
-
            fh = fopen(Jim_String(filename), mode);
-

-
        if (fh == NULL) {
-
            JimAioSetError(interp, filename);
-
#ifndef JIM_ANSIC
-
            if (fd >= 0) {
-
                close(fd);
-
            }
-
#endif
-
            Jim_DecrRefCount(interp, filename);
-
            return NULL;
-
        }
-
    }
-


    af = Jim_Alloc(sizeof(*af));
    memset(af, 0, sizeof(*af));
-
    af->fp = fh;
    af->filename = filename;
-
    af->openFlags = openFlags;
-
#ifndef JIM_ANSIC
-
    af->fd = fileno(fh);
+
    af->fd = fd;
+
    af->addr_family = family;
+
    af->fops = &stdio_fops;
+
    af->ssl = NULL;
+
    if (flags & AIO_WBUF_NONE) {
+
        af->wbuft = WBUF_OPT_NONE;
+
    }
+
    else {
+
#ifdef HAVE_ISATTY
+
        af->wbuft = isatty(af->fd) ? WBUF_OPT_LINE : WBUF_OPT_FULL;
+
#else
+
        af->wbuft = WBUF_OPT_FULL;
+
#endif
+
    }
+

#ifdef FD_CLOEXEC
-
    if ((openFlags & AIO_KEEPOPEN) == 0) {
+
    if ((flags & AIO_KEEPOPEN) == 0) {
        (void)fcntl(af->fd, F_SETFD, FD_CLOEXEC);
    }
#endif
-
#endif
-
    af->addr_family = family;
-
    af->fops = &stdio_fops;
-
    af->ssl = NULL;
+
    aio_set_nonblocking(af, !!(flags & AIO_NONBLOCK));
+

+
    af->flags |= flags;
+

+
    af->writebuf = Jim_NewStringObj(interp, NULL, 0);
+
    Jim_IncrRefCount(af->writebuf);

    Jim_CreateCommand(interp, buf, JimAioSubCmdProc, af, JimAioDelProc);

-
    Jim_SetResult(interp, Jim_MakeGlobalNamespaceName(interp, Jim_NewStringObj(interp, buf, -1)));
+
    Jim_SetResult(interp, Jim_MakeGlobalNamespaceName(interp, cmdname));

    return af;
}

-
#if defined(HAVE_PIPE) || (defined(HAVE_SOCKETPAIR) && defined(HAVE_SYS_UN_H))
+
#if defined(HAVE_PIPE) || (defined(HAVE_SOCKETPAIR) && UNIX_SOCKETS) || defined(HAVE_OPENPTY)
static int JimMakeChannelPair(Jim_Interp *interp, int p[2], Jim_Obj *filename,
-
    const char *hdlfmt, int family, const char *mode[2])
+
    const char *hdlfmt, int family, int flags)
{
-
    if (JimMakeChannel(interp, NULL, p[0], filename, hdlfmt, family, mode[0])) {
+
    if (JimMakeChannel(interp, p[0], filename, hdlfmt, family, flags)) {
        Jim_Obj *objPtr = Jim_NewListObj(interp, NULL, 0);
        Jim_ListAppendElement(interp, objPtr, Jim_GetResult(interp));
-
        if (JimMakeChannel(interp, NULL, p[1], filename, hdlfmt, family, mode[1])) {
+
        if (JimMakeChannel(interp, p[1], filename, hdlfmt, family, flags)) {
            Jim_ListAppendElement(interp, objPtr, Jim_GetResult(interp));
            Jim_SetResult(interp, objPtr);
            return JIM_OK;
@@ -2831,22 +3350,48 @@ static int JimMakeChannelPair(Jim_Interp *interp, int p[2], Jim_Obj *filename,
#endif

#ifdef HAVE_PIPE
+
static int JimCreatePipe(Jim_Interp *interp, Jim_Obj *filenameObj, int flags)
+
{
+
    int p[2];
+

+
    if (pipe(p) != 0) {
+
        JimAioSetError(interp, NULL);
+
        return JIM_ERR;
+
    }
+

+
    return JimMakeChannelPair(interp, p, filenameObj, "aio.pipe%ld", 0, flags);
+
}
+

+

static int JimAioPipeCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
+
    if (argc != 1) {
+
        Jim_WrongNumArgs(interp, 1, argv, "");
+
        return JIM_ERR;
+
    }
+
    return JimCreatePipe(interp, argv[0], 0);
+
}
+
#endif
+

+
#ifdef HAVE_OPENPTY
+
static int JimAioOpenPtyCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+
{
    int p[2];
-
    static const char *mode[2] = { "r", "w" };
+
    char path[MAXPATHLEN];

    if (argc != 1) {
        Jim_WrongNumArgs(interp, 1, argv, "");
        return JIM_ERR;
    }

-
    if (pipe(p) != 0) {
+
    if (openpty(&p[0], &p[1], path, NULL, NULL) != 0) {
        JimAioSetError(interp, NULL);
        return JIM_ERR;
    }

-
    return JimMakeChannelPair(interp, p, argv[0], "aio.pipe%ld", 0, mode);
+

+
    return JimMakeChannelPair(interp, p, Jim_NewStringObj(interp, path, -1), "aio.pty%ld", 0, 0);
+
    return JimMakeChannelPair(interp, p, Jim_NewStringObj(interp, path, -1), "aio.pty%ld", 0, 0);
}
#endif

@@ -2870,9 +3415,9 @@ int Jim_aioInit(Jim_Interp *interp)
#endif


-
    JimMakeChannel(interp, stdin, -1, NULL, "stdin", 0, "r");
-
    JimMakeChannel(interp, stdout, -1, NULL, "stdout", 0, "w");
-
    JimMakeChannel(interp, stderr, -1, NULL, "stderr", 0, "w");
+
    JimMakeChannel(interp, fileno(stdin), NULL, "stdin", 0, AIO_KEEPOPEN);
+
    JimMakeChannel(interp, fileno(stdout), NULL, "stdout", 0, AIO_KEEPOPEN);
+
    JimMakeChannel(interp, fileno(stderr), NULL, "stderr", 0, AIO_KEEPOPEN | AIO_WBUF_NONE);

    return JIM_OK;
}
@@ -2934,9 +3479,7 @@ int Jim_ReaddirCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)

int Jim_readdirInit(Jim_Interp *interp)
{
-
    if (Jim_PackageProvide(interp, "readdir", "1.0", JIM_ERRMSG))
-
        return JIM_ERR;
-

+
    Jim_PackageProvideCheck(interp, "readdir");
    Jim_CreateCommand(interp, "readdir", Jim_ReaddirCmd, NULL, NULL);
    return JIM_OK;
}
@@ -2947,11 +3490,15 @@ int Jim_readdirInit(Jim_Interp *interp)
#if defined(JIM_REGEXP)
#else
    #include <regex.h>
+
    #define jim_regcomp regcomp
+
    #define jim_regexec regexec
+
    #define jim_regerror regerror
+
    #define jim_regfree regfree
#endif

static void FreeRegexpInternalRep(Jim_Interp *interp, Jim_Obj *objPtr)
{
-
    regfree(objPtr->internalRep.ptrIntValue.ptr);
+
    jim_regfree(objPtr->internalRep.ptrIntValue.ptr);
    Jim_Free(objPtr->internalRep.ptrIntValue.ptr);
}

@@ -2982,12 +3529,12 @@ static regex_t *SetRegexpFromAny(Jim_Interp *interp, Jim_Obj *objPtr, unsigned f
    pattern = Jim_String(objPtr);
    compre = Jim_Alloc(sizeof(regex_t));

-
    if ((ret = regcomp(compre, pattern, REG_EXTENDED | flags)) != 0) {
+
    if ((ret = jim_regcomp(compre, pattern, REG_EXTENDED | flags)) != 0) {
        char buf[100];

-
        regerror(ret, compre, buf, sizeof(buf));
+
        jim_regerror(ret, compre, buf, sizeof(buf));
        Jim_SetResultFormatted(interp, "couldn't compile regular expression pattern: %s", buf);
-
        regfree(compre);
+
        jim_regfree(compre);
        Jim_Free(compre);
        return NULL;
    }
@@ -3112,7 +3659,7 @@ int Jim_RegexpCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
            source_str += source_len;
        }
        else if (offset > 0) {
-
            source_str += offset;
+
            source_str += utf8_index(source_str, offset);
        }
        eflags |= REG_NOTBOL;
    }
@@ -3122,11 +3669,11 @@ int Jim_RegexpCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
    }

  next_match:
-
    match = regexec(regex, source_str, num_vars + 1, pmatch, eflags);
+
    match = jim_regexec(regex, source_str, num_vars + 1, pmatch, eflags);
    if (match >= REG_BADPAT) {
        char buf[100];

-
        regerror(match, regex, buf, sizeof(buf));
+
        jim_regerror(match, regex, buf, sizeof(buf));
        Jim_SetResultFormatted(interp, "error while matching pattern: %s", buf);
        result = JIM_ERR;
        goto done;
@@ -3162,16 +3709,15 @@ int Jim_RegexpCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
            }
        }
        else {
-
            int len = pmatch[j].rm_eo - pmatch[j].rm_so;
-

            if (opt_indices) {
-
                Jim_ListAppendElement(interp, resultObj, Jim_NewIntObj(interp,
-
                        offset + pmatch[j].rm_so));
-
                Jim_ListAppendElement(interp, resultObj, Jim_NewIntObj(interp,
-
                        offset + pmatch[j].rm_so + len - 1));
+

+
                int so = utf8_strlen(source_str, pmatch[j].rm_so);
+
                int eo = utf8_strlen(source_str, pmatch[j].rm_eo);
+
                Jim_ListAppendElement(interp, resultObj, Jim_NewIntObj(interp, offset + so));
+
                Jim_ListAppendElement(interp, resultObj, Jim_NewIntObj(interp, offset + eo - 1));
            }
            else {
-
                Jim_AppendString(interp, resultObj, source_str + pmatch[j].rm_so, len);
+
                Jim_AppendString(interp, resultObj, source_str + pmatch[j].rm_so, pmatch[j].rm_eo - pmatch[j].rm_so);
            }
        }

@@ -3192,7 +3738,7 @@ int Jim_RegexpCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
  try_next_match:
    if (opt_all && (pattern[0] != '^' || (regcomp_flags & REG_NEWLINE)) && *source_str) {
        if (pmatch[0].rm_eo) {
-
            offset += pmatch[0].rm_eo;
+
            offset += utf8_strlen(source_str, pmatch[0].rm_eo);
            source_str += pmatch[0].rm_eo;
        }
        else {
@@ -3321,6 +3867,8 @@ int Jim_RegsubCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
        }
    }

+
    offset = utf8_index(source_str, offset);
+


    Jim_AppendString(interp, resultObj, source_str, offset);

@@ -3328,12 +3876,12 @@ int Jim_RegsubCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
    n = source_len - offset;
    p = source_str + offset;
    do {
-
        int match = regexec(regex, p, MAX_SUB_MATCHES, pmatch, regexec_flags);
+
        int match = jim_regexec(regex, p, MAX_SUB_MATCHES, pmatch, regexec_flags);

        if (match >= REG_BADPAT) {
            char buf[100];

-
            regerror(match, regex, buf, sizeof(buf));
+
            jim_regerror(match, regex, buf, sizeof(buf));
            Jim_SetResultFormatted(interp, "error while matching pattern: %s", buf);
            return JIM_ERR;
        }
@@ -3398,7 +3946,14 @@ int Jim_RegsubCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
            n--;
        }

-
        regexec_flags |= REG_NOTBOL;
+
        if (pmatch[0].rm_eo == pmatch[0].rm_so) {
+

+
            regexec_flags = REG_NOTBOL;
+
        }
+
        else {
+
            regexec_flags = 0;
+
        }
+

    } while (n);

    Jim_AppendString(interp, resultObj, p, -1);
@@ -3424,9 +3979,7 @@ int Jim_RegsubCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)

int Jim_regexpInit(Jim_Interp *interp)
{
-
    if (Jim_PackageProvide(interp, "regexp", "1.0", JIM_ERRMSG))
-
        return JIM_ERR;
-

+
    Jim_PackageProvideCheck(interp, "regexp");
    Jim_CreateCommand(interp, "regexp", Jim_RegexpCmd, NULL, NULL);
    Jim_CreateCommand(interp, "regsub", Jim_RegsubCmd, NULL, NULL);
    return JIM_OK;
@@ -3437,7 +3990,6 @@ int Jim_regexpInit(Jim_Interp *interp)
#include <string.h>
#include <stdio.h>
#include <errno.h>
-
#include <sys/stat.h>


#ifdef HAVE_UTIMES
@@ -3455,11 +4007,17 @@ int Jim_regexpInit(Jim_Interp *interp)
#endif

# ifndef MAXPATHLEN
+
# ifdef PATH_MAX
+
# define MAXPATHLEN PATH_MAX
+
# else
# define MAXPATHLEN JIM_PATH_LEN
# endif
+
# endif

#if defined(__MINGW32__) || defined(__MSYS__) || defined(_MSC_VER)
#define ISWINDOWS 1
+

+
#undef HAVE_SYMLINK
#else
#define ISWINDOWS 0
#endif
@@ -3472,6 +4030,18 @@ int Jim_regexpInit(Jim_Interp *interp)
#endif


+
static void JimFixPath(char *path)
+
{
+
    if (ISWINDOWS) {
+

+
        char *p = path;
+
        while ((p = strchr(p, '\\')) != NULL) {
+
            *p++ = '/';
+
        }
+
    }
+
}
+

+

static const char *JimGetFileType(int mode)
{
    if (S_ISREG(mode)) {
@@ -3514,7 +4084,7 @@ static void AppendStatElement(Jim_Interp *interp, Jim_Obj *listObj, const char *
    Jim_ListAppendElement(interp, listObj, Jim_NewIntObj(interp, value));
}

-
static int StoreStatData(Jim_Interp *interp, Jim_Obj *varName, const struct stat *sb)
+
int Jim_FileStoreStatData(Jim_Interp *interp, Jim_Obj *varName, const jim_stat_t *sb)
{

    Jim_Obj *listObj = Jim_NewListObj(interp, NULL, 0);
@@ -3568,16 +4138,44 @@ static int StoreStatData(Jim_Interp *interp, Jim_Obj *varName, const struct stat
    return JIM_OK;
}

+
static int JimPathLenNoTrailingSlashes(const char *path, int len)
+
{
+
    int i;
+
    for (i = len; i > 1 && path[i - 1] == '/'; i--) {
+

+
        if (ISWINDOWS && path[i - 2] == ':') {
+

+
            break;
+
        }
+
    }
+
    return i;
+
}
+

+
static Jim_Obj *JimStripTrailingSlashes(Jim_Interp *interp, Jim_Obj *objPtr)
+
{
+
    int len = Jim_Length(objPtr);
+
    const char *path = Jim_String(objPtr);
+
    int i = JimPathLenNoTrailingSlashes(path, len);
+
    if (i != len) {
+
        objPtr = Jim_NewStringObj(interp, path, i);
+
    }
+
    Jim_IncrRefCount(objPtr);
+
    return objPtr;
+
}
+

static int file_cmd_dirname(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
-
    const char *path = Jim_String(argv[0]);
+
    Jim_Obj *objPtr = JimStripTrailingSlashes(interp, argv[0]);
+
    const char *path = Jim_String(objPtr);
    const char *p = strrchr(path, '/');

-
    if (!p && path[0] == '.' && path[1] == '.' && path[2] == '\0') {
-
        Jim_SetResultString(interp, "..", -1);
-
    } else if (!p) {
+
    if (!p) {
        Jim_SetResultString(interp, ".", -1);
    }
+
    else if (p[1] == 0) {
+

+
        Jim_SetResult(interp, objPtr);
+
    }
    else if (p == path) {
        Jim_SetResultString(interp, "/", -1);
    }
@@ -3586,8 +4184,40 @@ static int file_cmd_dirname(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
        Jim_SetResultString(interp, path, p - path + 1);
    }
    else {
-
        Jim_SetResultString(interp, path, p - path);
+

+
        int len = JimPathLenNoTrailingSlashes(path, p - path);
+
        Jim_SetResultString(interp, path, len);
    }
+
    Jim_DecrRefCount(interp, objPtr);
+
    return JIM_OK;
+
}
+

+
static int file_cmd_split(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+
{
+
    Jim_Obj *listObj = Jim_NewListObj(interp, NULL, 0);
+
    const char *path = Jim_String(argv[0]);
+

+
    if (*path == '/') {
+
        Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, "/", 1));
+
    }
+

+
    while (1) {
+

+
        while (*path == '/') {
+
            path++;
+
        }
+
        if (*path) {
+
            const char *pt = strchr(path, '/');
+
            if (pt) {
+
                Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, path, pt - path));
+
                path = pt;
+
                continue;
+
            }
+
            Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, path, -1));
+
        }
+
        break;
+
    }
+
    Jim_SetResult(interp, listObj);
    return JIM_OK;
}

@@ -3608,7 +4238,8 @@ static int file_cmd_rootname(Jim_Interp *interp, int argc, Jim_Obj *const *argv)

static int file_cmd_extension(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
-
    const char *path = Jim_String(argv[0]);
+
    Jim_Obj *objPtr = JimStripTrailingSlashes(interp, argv[0]);
+
    const char *path = Jim_String(objPtr);
    const char *lastSlash = strrchr(path, '/');
    const char *p = strrchr(path, '.');

@@ -3616,42 +4247,54 @@ static int file_cmd_extension(Jim_Interp *interp, int argc, Jim_Obj *const *argv
        p = "";
    }
    Jim_SetResultString(interp, p, -1);
+
    Jim_DecrRefCount(interp, objPtr);
    return JIM_OK;
}

static int file_cmd_tail(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
-
    const char *path = Jim_String(argv[0]);
+
    Jim_Obj *objPtr = JimStripTrailingSlashes(interp, argv[0]);
+
    const char *path = Jim_String(objPtr);
    const char *lastSlash = strrchr(path, '/');

    if (lastSlash) {
        Jim_SetResultString(interp, lastSlash + 1, -1);
    }
    else {
-
        Jim_SetResult(interp, argv[0]);
+
        Jim_SetResult(interp, objPtr);
    }
+
    Jim_DecrRefCount(interp, objPtr);
    return JIM_OK;
}

+
#ifndef HAVE_RESTRICT
+
#define restrict
+
#endif
+

+
static char *JimRealPath(const char *restrict path, char *restrict resolved_path, size_t len)
+
{
+
#if defined(HAVE__FULLPATH)
+
    return _fullpath(resolved_path, path, len);
+
#elif defined(HAVE_REALPATH)
+
    return realpath(path, resolved_path);
+
#else
+
    return NULL;
+
#endif
+
}
+

static int file_cmd_normalize(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
-
#ifdef HAVE_REALPATH
    const char *path = Jim_String(argv[0]);
-
    char *newname = Jim_Alloc(MAXPATHLEN + 1);
+
    char *newname = Jim_Alloc(MAXPATHLEN);

-
    if (realpath(path, newname)) {
+
    if (JimRealPath(path, newname, MAXPATHLEN)) {
+
        JimFixPath(newname);
        Jim_SetResult(interp, Jim_NewStringObjNoAlloc(interp, newname, -1));
        return JIM_OK;
-
    }
-
    else {
-
        Jim_Free(newname);
-
        Jim_SetResultFormatted(interp, "can't normalize \"%#s\": %s", argv[0], strerror(errno));
-
        return JIM_ERR;
-
    }
-
#else
-
    Jim_SetResultString(interp, "Not implemented", -1);
+
    }
+
    Jim_Free(newname);
+
    Jim_SetResultFormatted(interp, "can't normalize \"%#s\": %s", argv[0], strerror(errno));
    return JIM_ERR;
-
#endif
}

static int file_cmd_join(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
@@ -3757,8 +4400,8 @@ static int file_cmd_delete(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
    int force = Jim_CompareStringImmediate(interp, argv[0], "-force");

    if (force || Jim_CompareStringImmediate(interp, argv[0], "--")) {
-
        argc++;
-
        argv--;
+
        argc--;
+
        argv++;
    }

    while (argc--) {
@@ -3815,9 +4458,9 @@ static int mkdir_all(char *path)
        }

        if (errno == EEXIST) {
-
            struct stat sb;
+
            jim_stat_t sb;

-
            if (stat(path, &sb) == 0 && S_ISDIR(sb.st_mode)) {
+
            if (Jim_Stat(path, &sb) == 0 && S_ISDIR(sb.st_mode)) {
                return 0;
            }

@@ -3881,7 +4524,12 @@ static int file_cmd_rename(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
            argv[1]);
        return JIM_ERR;
    }
+
#if ISWINDOWS
+
    if (access(dest, F_OK) == 0) {

+
        remove(dest);
+
    }
+
#endif
    if (rename(source, dest) != 0) {
        Jim_SetResultFormatted(interp, "error renaming \"%#s\" to \"%#s\": %s", argv[0], argv[1],
            strerror(errno));
@@ -3929,23 +4577,23 @@ static int file_cmd_link(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
}
#endif

-
static int file_stat(Jim_Interp *interp, Jim_Obj *filename, struct stat *sb)
+
static int file_stat(Jim_Interp *interp, Jim_Obj *filename, jim_stat_t *sb)
{
    const char *path = Jim_String(filename);

-
    if (stat(path, sb) == -1) {
+
    if (Jim_Stat(path, sb) == -1) {
        Jim_SetResultFormatted(interp, "could not read \"%#s\": %s", filename, strerror(errno));
        return JIM_ERR;
    }
    return JIM_OK;
}

-
#ifdef HAVE_LSTAT
-
static int file_lstat(Jim_Interp *interp, Jim_Obj *filename, struct stat *sb)
+
#ifdef Jim_LinkStat
+
static int file_lstat(Jim_Interp *interp, Jim_Obj *filename, jim_stat_t *sb)
{
    const char *path = Jim_String(filename);

-
    if (lstat(path, sb) == -1) {
+
    if (Jim_LinkStat(path, sb) == -1) {
        Jim_SetResultFormatted(interp, "could not read \"%#s\": %s", filename, strerror(errno));
        return JIM_ERR;
    }
@@ -3957,7 +4605,7 @@ static int file_lstat(Jim_Interp *interp, Jim_Obj *filename, struct stat *sb)

static int file_cmd_atime(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
-
    struct stat sb;
+
    jim_stat_t sb;

    if (file_stat(interp, argv[0], &sb) != JIM_OK) {
        return JIM_ERR;
@@ -3987,7 +4635,7 @@ static int JimSetFileTimes(Jim_Interp *interp, const char *filename, jim_wide us

static int file_cmd_mtime(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
-
    struct stat sb;
+
    jim_stat_t sb;

    if (argc == 2) {
        jim_wide secs;
@@ -4006,7 +4654,7 @@ static int file_cmd_mtime(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
#ifdef STAT_MTIME_US
static int file_cmd_mtimeus(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
-
    struct stat sb;
+
    jim_stat_t sb;

    if (argc == 2) {
        jim_wide us;
@@ -4030,7 +4678,7 @@ static int file_cmd_copy(Jim_Interp *interp, int argc, Jim_Obj *const *argv)

static int file_cmd_size(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
-
    struct stat sb;
+
    jim_stat_t sb;

    if (file_stat(interp, argv[0], &sb) != JIM_OK) {
        return JIM_ERR;
@@ -4041,7 +4689,7 @@ static int file_cmd_size(Jim_Interp *interp, int argc, Jim_Obj *const *argv)

static int file_cmd_isdirectory(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
-
    struct stat sb;
+
    jim_stat_t sb;
    int ret = 0;

    if (file_stat(interp, argv[0], &sb) == JIM_OK) {
@@ -4053,7 +4701,7 @@ static int file_cmd_isdirectory(Jim_Interp *interp, int argc, Jim_Obj *const *ar

static int file_cmd_isfile(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
-
    struct stat sb;
+
    jim_stat_t sb;
    int ret = 0;

    if (file_stat(interp, argv[0], &sb) == JIM_OK) {
@@ -4066,7 +4714,7 @@ static int file_cmd_isfile(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
#ifdef HAVE_GETEUID
static int file_cmd_owned(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
-
    struct stat sb;
+
    jim_stat_t sb;
    int ret = 0;

    if (file_stat(interp, argv[0], &sb) == JIM_OK) {
@@ -4087,7 +4735,7 @@ static int file_cmd_readlink(Jim_Interp *interp, int argc, Jim_Obj *const *argv)

    if (linkLength == -1) {
        Jim_Free(linkValue);
-
        Jim_SetResultFormatted(interp, "couldn't readlink \"%#s\": %s", argv[0], strerror(errno));
+
        Jim_SetResultFormatted(interp, "could not read link \"%#s\": %s", argv[0], strerror(errno));
        return JIM_ERR;
    }
    linkValue[linkLength] = 0;
@@ -4098,7 +4746,7 @@ static int file_cmd_readlink(Jim_Interp *interp, int argc, Jim_Obj *const *argv)

static int file_cmd_type(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
-
    struct stat sb;
+
    jim_stat_t sb;

    if (file_lstat(interp, argv[0], &sb) != JIM_OK) {
        return JIM_ERR;
@@ -4107,15 +4755,15 @@ static int file_cmd_type(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
    return JIM_OK;
}

-
#ifdef HAVE_LSTAT
+
#ifdef Jim_LinkStat
static int file_cmd_lstat(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
-
    struct stat sb;
+
    jim_stat_t sb;

    if (file_lstat(interp, argv[0], &sb) != JIM_OK) {
        return JIM_ERR;
    }
-
    return StoreStatData(interp, argc == 2 ? argv[1] : NULL, &sb);
+
    return Jim_FileStoreStatData(interp, argc == 2 ? argv[1] : NULL, &sb);
}
#else
#define file_cmd_lstat file_cmd_stat
@@ -4123,12 +4771,12 @@ static int file_cmd_lstat(Jim_Interp *interp, int argc, Jim_Obj *const *argv)

static int file_cmd_stat(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
-
    struct stat sb;
+
    jim_stat_t sb;

    if (file_stat(interp, argv[0], &sb) != JIM_OK) {
        return JIM_ERR;
    }
-
    return StoreStatData(interp, argc == 2 ? argv[1] : NULL, &sb);
+
    return Jim_FileStoreStatData(interp, argc == 2 ? argv[1] : NULL, &sb);
}

static const jim_subcmd_type file_command_table[] = {
@@ -4190,6 +4838,13 @@ static const jim_subcmd_type file_command_table[] = {
        1,

    },
+
    {   "split",
+
        "name",
+
        file_cmd_split,
+
        1,
+
        1,
+

+
    },
    {   "normalize",
        "name",
        file_cmd_normalize,
@@ -4362,14 +5017,7 @@ static int Jim_PwdCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
        Jim_Free(cwd);
        return JIM_ERR;
    }
-
    else if (ISWINDOWS) {
-

-
        char *p = cwd;
-
        while ((p = strchr(p, '\\')) != NULL) {
-
            *p++ = '/';
-
        }
-
    }
-

+
    JimFixPath(cwd);
    Jim_SetResultString(interp, cwd, -1);

    Jim_Free(cwd);
@@ -4378,23 +5026,18 @@ static int Jim_PwdCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)

int Jim_fileInit(Jim_Interp *interp)
{
-
    if (Jim_PackageProvide(interp, "file", "1.0", JIM_ERRMSG))
-
        return JIM_ERR;
-

+
    Jim_PackageProvideCheck(interp, "file");
    Jim_CreateCommand(interp, "file", Jim_SubCmdProc, (void *)file_command_table, NULL);
    Jim_CreateCommand(interp, "pwd", Jim_PwdCmd, NULL, NULL);
    Jim_CreateCommand(interp, "cd", Jim_CdCmd, NULL, NULL);
    return JIM_OK;
}

-
#ifndef _GNU_SOURCE
-
#define _GNU_SOURCE
-
#endif
#include <string.h>
#include <ctype.h>


-
#if (!defined(HAVE_VFORK) || !defined(HAVE_WAITPID)) && !defined(__MINGW32__)
+
#if (!(defined(HAVE_VFORK) || defined(HAVE_FORK)) || !defined(HAVE_WAITPID)) && !defined(__MINGW32__)
static int Jim_ExecCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
    Jim_Obj *cmdlineObj = Jim_NewEmptyStringObj(interp);
@@ -4442,9 +5085,7 @@ static int Jim_ExecCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)

int Jim_execInit(Jim_Interp *interp)
{
-
    if (Jim_PackageProvide(interp, "exec", "1.0", JIM_ERRMSG))
-
        return JIM_ERR;
-

+
    Jim_PackageProvideCheck(interp, "exec");
    Jim_CreateCommand(interp, "exec", Jim_ExecCmd, NULL, NULL);
    return JIM_OK;
}
@@ -4461,13 +5102,13 @@ static char **JimOriginalEnviron(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, int *inPipePtr, int *outPipePtr, int *errFilePtr);
-
static void JimDetachPids(struct WaitInfoTable *table, int numPids, const pidtype *pidPtr);
-
static int JimCleanupChildren(Jim_Interp *interp, int numPids, pidtype *pidPtr, Jim_Obj *errStrObj);
+
    phandle_t **pidArrayPtr, int *inPipePtr, int *outPipePtr, int *errFilePtr);
+
static void JimDetachPids(struct WaitInfoTable *table, int numPids, const phandle_t *pidPtr);
+
static int JimCleanupChildren(Jim_Interp *interp, int numPids, phandle_t *pidPtr, Jim_Obj *errStrObj);
static int Jim_WaitCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv);

#if defined(__MINGW32__)
-
static pidtype JimStartWinProcess(Jim_Interp *interp, char **argv, char **env, int inputId, int outputId, int errorId);
+
static phandle_t JimStartWinProcess(Jim_Interp *interp, char **argv, char **env, int inputId, int outputId, int errorId);
#endif

static void Jim_RemoveTrailingNewline(Jim_Obj *objPtr)
@@ -4484,24 +5125,19 @@ static void Jim_RemoveTrailingNewline(Jim_Obj *objPtr)
static int JimAppendStreamToString(Jim_Interp *interp, int fd, Jim_Obj *strObj)
{
    char buf[256];
-
    FILE *fh = fdopen(fd, "r");
    int ret = 0;

-
    if (fh == NULL) {
-
        return -1;
-
    }
-

    while (1) {
-
        int retval = fread(buf, 1, sizeof(buf), fh);
+
        int retval = read(fd, buf, sizeof(buf));
        if (retval > 0) {
            ret = 1;
            Jim_AppendString(interp, strObj, buf, retval);
        }
-
        if (retval != sizeof(buf)) {
+
        if (retval <= 0) {
            break;
        }
    }
-
    fclose(fh);
+
    close(fd);
    return ret;
}

@@ -4560,18 +5196,18 @@ static void JimFreeEnv(char **env, char **original_environ)
    }
}

-
static Jim_Obj *JimMakeErrorCode(Jim_Interp *interp, pidtype pid, int waitStatus, Jim_Obj *errStrObj)
+
static Jim_Obj *JimMakeErrorCode(Jim_Interp *interp, long pid, int waitStatus, Jim_Obj *errStrObj)
{
    Jim_Obj *errorCode = Jim_NewListObj(interp, NULL, 0);

-
    if (pid == JIM_BAD_PID || pid == JIM_NO_PID) {
+
    if (pid <= 0) {
        Jim_ListAppendElement(interp, errorCode, Jim_NewStringObj(interp, "NONE", -1));
-
        Jim_ListAppendElement(interp, errorCode, Jim_NewIntObj(interp, (long)pid));
+
        Jim_ListAppendElement(interp, errorCode, Jim_NewIntObj(interp, pid));
        Jim_ListAppendElement(interp, errorCode, Jim_NewIntObj(interp, -1));
    }
    else if (WIFEXITED(waitStatus)) {
        Jim_ListAppendElement(interp, errorCode, Jim_NewStringObj(interp, "CHILDSTATUS", -1));
-
        Jim_ListAppendElement(interp, errorCode, Jim_NewIntObj(interp, (long)pid));
+
        Jim_ListAppendElement(interp, errorCode, Jim_NewIntObj(interp, pid));
        Jim_ListAppendElement(interp, errorCode, Jim_NewIntObj(interp, WEXITSTATUS(waitStatus)));
    }
    else {
@@ -4596,13 +5232,13 @@ static Jim_Obj *JimMakeErrorCode(Jim_Interp *interp, pidtype pid, int waitStatus
            Jim_AppendStrings(interp, errStrObj, "child ", action, " by signal ", Jim_SignalId(WTERMSIG(waitStatus)), "\n", NULL);
        }

-
        Jim_ListAppendElement(interp, errorCode, Jim_NewIntObj(interp, (long)pid));
+
        Jim_ListAppendElement(interp, errorCode, Jim_NewIntObj(interp, pid));
        Jim_ListAppendElement(interp, errorCode, Jim_NewStringObj(interp, signame, -1));
    }
    return errorCode;
}

-
static int JimCheckWaitStatus(Jim_Interp *interp, pidtype pid, int waitStatus, Jim_Obj *errStrObj)
+
static int JimCheckWaitStatus(Jim_Interp *interp, long pid, int waitStatus, Jim_Obj *errStrObj)
{
    if (WIFEXITED(waitStatus) && WEXITSTATUS(waitStatus) == 0) {
        return JIM_OK;
@@ -4615,7 +5251,7 @@ static int JimCheckWaitStatus(Jim_Interp *interp, pidtype pid, int waitStatus, J

struct WaitInfo
{
-
    pidtype pid;
+
    phandle_t phandle;
    int status;
    int flags;
};
@@ -4653,13 +5289,13 @@ static struct WaitInfoTable *JimAllocWaitInfoTable(void)
    return table;
}

-
static int JimWaitRemove(struct WaitInfoTable *table, pidtype pid)
+
static int JimWaitRemove(struct WaitInfoTable *table, phandle_t phandle)
{
    int i;


    for (i = 0; i < table->used; i++) {
-
        if (pid == table->info[i].pid) {
+
        if (phandle == table->info[i].phandle) {
            if (i != table->used - 1) {
                table->info[i] = table->info[table->used - 1];
            }
@@ -4674,7 +5310,7 @@ static int Jim_ExecCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
    int outputId;
    int errorId;
-
    pidtype *pidPtr;
+
    phandle_t *pidPtr;
    int numPids, result;
    int child_siginfo = 1;
    Jim_Obj *childErrObj;
@@ -4693,7 +5329,7 @@ static int Jim_ExecCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)

        listObj = Jim_NewListObj(interp, NULL, 0);
        for (i = 0; i < numPids; i++) {
-
            Jim_ListAppendElement(interp, listObj, Jim_NewIntObj(interp, (long)pidPtr[i]));
+
            Jim_ListAppendElement(interp, listObj, Jim_NewIntObj(interp, JimProcessPid(pidPtr[i])));
        }
        Jim_SetResult(interp, listObj);
        JimDetachPids(table, numPids, pidPtr);
@@ -4730,7 +5366,7 @@ static int Jim_ExecCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)

    if (errorId != -1) {
        int ret;
-
        lseek(errorId, 0, SEEK_SET);
+
        Jim_Lseek(errorId, 0, SEEK_SET);
        ret = JimAppendStreamToString(interp, errorId, errStrObj);
        if (ret < 0) {
            Jim_SetResultErrno(interp, "error reading from error pipe");
@@ -4757,19 +5393,18 @@ static int Jim_ExecCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
    return result;
}

-
static pidtype JimWaitForProcess(struct WaitInfoTable *table, pidtype pid, int *statusPtr)
+
static long JimWaitForProcess(struct WaitInfoTable *table, phandle_t phandle, int *statusPtr)
{
-
    if (JimWaitRemove(table, pid) == 0) {
+
    if (JimWaitRemove(table, phandle) == 0) {

-
         waitpid(pid, statusPtr, 0);
-
         return pid;
+
         return waitpid(phandle, statusPtr, 0);
    }


-
    return JIM_BAD_PID;
+
    return -1;
}

-
static void JimDetachPids(struct WaitInfoTable *table, int numPids, const pidtype *pidPtr)
+
static void JimDetachPids(struct WaitInfoTable *table, int numPids, const phandle_t *pidPtr)
{
    int j;

@@ -4777,7 +5412,7 @@ static void JimDetachPids(struct WaitInfoTable *table, int numPids, const pidtyp

        int i;
        for (i = 0; i < table->used; i++) {
-
            if (pidPtr[j] == table->info[i].pid) {
+
            if (pidPtr[j] == table->info[i].phandle) {
                table->info[i].flags |= WI_DETACHED;
                break;
            }
@@ -4816,8 +5451,8 @@ static void JimReapDetachedPids(struct WaitInfoTable *table)
    for (count = table->used; count > 0; waitPtr++, count--) {
        if (waitPtr->flags & WI_DETACHED) {
            int status;
-
            pidtype pid = waitpid(waitPtr->pid, &status, WNOHANG);
-
            if (pid == waitPtr->pid) {
+
            long pid = waitpid(waitPtr->phandle, &status, WNOHANG);
+
            if (pid > 0) {

                table->used--;
                continue;
@@ -4834,8 +5469,8 @@ static int Jim_WaitCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
    struct WaitInfoTable *table = Jim_CmdPrivData(interp);
    int nohang = 0;
-
    pidtype pid;
-
    long pidarg;
+
    long pid;
+
    phandle_t phandle;
    int status;
    Jim_Obj *errCodeObj;

@@ -4852,17 +5487,26 @@ static int Jim_WaitCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
        Jim_WrongNumArgs(interp, 1, argv, "?-nohang? ?pid?");
        return JIM_ERR;
    }
-
    if (Jim_GetLong(interp, argv[nohang + 1], &pidarg) != JIM_OK) {
+
    if (Jim_GetLong(interp, argv[nohang + 1], &pid) != JIM_OK) {
        return JIM_ERR;
    }

-
    pid = waitpid((pidtype)pidarg, &status, nohang ? WNOHANG : 0);
+

+
    phandle = JimWaitPid(pid, &status, nohang ? WNOHANG : 0);
+
    if (phandle == JIM_BAD_PHANDLE) {
+
        pid = -1;
+
    }
+
#ifndef __MINGW32__
+
    else if (pid < 0) {
+
        pid = phandle;
+
    }
+
#endif

    errCodeObj = JimMakeErrorCode(interp, pid, status, NULL);

-
    if (pid != JIM_BAD_PID && (WIFEXITED(status) || WIFSIGNALED(status))) {
+
    if (phandle != JIM_BAD_PHANDLE && (WIFEXITED(status) || WIFSIGNALED(status))) {

-
        JimWaitRemove(table, pid);
+
        JimWaitRemove(table, phandle);
    }
    Jim_SetResult(interp, errCodeObj);
    return JIM_OK;
@@ -4880,10 +5524,10 @@ static int Jim_PidCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
}

static int
-
JimCreatePipeline(Jim_Interp *interp, int argc, Jim_Obj *const *argv, pidtype **pidArrayPtr,
+
JimCreatePipeline(Jim_Interp *interp, int argc, Jim_Obj *const *argv, phandle_t **pidArrayPtr,
    int *inPipePtr, int *outPipePtr, int *errFilePtr)
{
-
    pidtype *pidPtr = NULL;         /* Points to malloc-ed array holding all
+
    phandle_t *pidPtr = NULL;         /* Points to alloc-ed array holding all
                                 * the pids of child processes. */
    int numPids = 0;            /* Actual number of processes that exist
                                 * at *pidPtr right now. */
@@ -4927,9 +5571,9 @@ JimCreatePipeline(Jim_Interp *interp, int argc, Jim_Obj *const *argv, pidtype **
                                 * current command. */
    int lastBar;
    int i;
-
    pidtype pid;
+
    phandle_t phandle;
    char **save_environ;
-
#ifndef __MINGW32__
+
#if defined(HAVE_EXECVPE) && !defined(__MINGW32__)
    char **child_environ;
#endif
    struct WaitInfoTable *table = Jim_CmdPrivData(interp);
@@ -5055,7 +5699,7 @@ badargs:
                close(inputId);
                goto error;
            }
-
            lseek(inputId, 0L, SEEK_SET);
+
            Jim_Lseek(inputId, 0L, SEEK_SET);
        }
        else if (inputFile == FILE_HANDLE) {
            int fd = JimGetChannelFd(interp, input);
@@ -5147,9 +5791,6 @@ badargs:


    pidPtr = Jim_Alloc(cmdCount * sizeof(*pidPtr));
-
    for (i = 0; i < numPids; i++) {
-
        pidPtr[i] = JIM_BAD_PID;
-
    }
    for (firstArg = 0; firstArg < arg_count; numPids++, firstArg = lastArg + 1) {
        int pipe_dup_err = 0;
        int origErrorId = errorId;
@@ -5191,42 +5832,48 @@ badargs:


#ifdef __MINGW32__
-
        pid = JimStartWinProcess(interp, &arg_array[firstArg], save_environ, inputId, outputId, errorId);
-
        if (pid == JIM_BAD_PID) {
+
        phandle = JimStartWinProcess(interp, &arg_array[firstArg], save_environ, inputId, outputId, errorId);
+
        if (phandle == JIM_BAD_PHANDLE) {
            Jim_SetResultFormatted(interp, "couldn't exec \"%s\"", arg_array[firstArg]);
            goto error;
        }
#else
        i = strlen(arg_array[firstArg]);

+
#ifdef HAVE_EXECVPE
        child_environ = Jim_GetEnviron();
-
        pid = vfork();
-
        if (pid < 0) {
+
#endif
+
#ifdef HAVE_VFORK
+
        phandle = vfork();
+
#else
+
        phandle = fork();
+
#endif
+
        if (phandle < 0) {
            Jim_SetResultErrno(interp, "couldn't fork child process");
            goto error;
        }
-
        if (pid == 0) {
+
        if (phandle == 0) {


-
            if (inputId != -1) {
+
            if (inputId != -1 && inputId != fileno(stdin)) {
                dup2(inputId, fileno(stdin));
                close(inputId);
            }
-
            if (outputId != -1) {
+
            if (outputId != -1 && outputId != fileno(stdout)) {
                dup2(outputId, fileno(stdout));
                if (outputId != errorId) {
                    close(outputId);
                }
            }
-
            if (errorId != -1) {
+
            if (errorId != -1 && errorId != fileno(stderr)) {
                dup2(errorId, fileno(stderr));
                close(errorId);
            }

-
            if (outPipePtr) {
+
            if (outPipePtr && *outPipePtr != -1) {
                close(*outPipePtr);
            }
-
            if (errFilePtr) {
+
            if (errFilePtr && *errFilePtr != -1) {
                close(*errFilePtr);
            }
            if (pipeIds[0] != -1) {
@@ -5236,9 +5883,6 @@ badargs:
                close(lastOutputId);
            }

-

-
            (void)signal(SIGPIPE, SIG_DFL);
-

            execvpe(arg_array[firstArg], &arg_array[firstArg], child_environ);

            if (write(fileno(stderr), "couldn't exec \"", 15) &&
@@ -5264,11 +5908,11 @@ badargs:
            table->info = Jim_Realloc(table->info, table->size * sizeof(*table->info));
        }

-
        table->info[table->used].pid = pid;
+
        table->info[table->used].phandle = phandle;
        table->info[table->used].flags = 0;
        table->used++;

-
        pidPtr[numPids] = pid;
+
        pidPtr[numPids] = phandle;


        errorId = origErrorId;
@@ -5324,7 +5968,7 @@ badargs:
    }
    if (pidPtr != NULL) {
        for (i = 0; i < numPids; i++) {
-
            if (pidPtr[i] != JIM_BAD_PID) {
+
            if (pidPtr[i] != JIM_BAD_PHANDLE) {
                JimDetachPids(table, 1, &pidPtr[i]);
            }
        }
@@ -5335,7 +5979,7 @@ badargs:
}


-
static int JimCleanupChildren(Jim_Interp *interp, int numPids, pidtype *pidPtr, Jim_Obj *errStrObj)
+
static int JimCleanupChildren(Jim_Interp *interp, int numPids, phandle_t *pidPtr, Jim_Obj *errStrObj)
{
    struct WaitInfoTable *table = Jim_CmdPrivData(interp);
    int result = JIM_OK;
@@ -5344,8 +5988,9 @@ static int JimCleanupChildren(Jim_Interp *interp, int numPids, pidtype *pidPtr,

    for (i = 0; i < numPids; i++) {
        int waitStatus = 0;
-
        if (JimWaitForProcess(table, pidPtr[i], &waitStatus) != JIM_BAD_PID) {
-
            if (JimCheckWaitStatus(interp, pidPtr[i], waitStatus, errStrObj) != JIM_OK) {
+
        long pid = JimWaitForProcess(table, pidPtr[i], &waitStatus);
+
        if (pid > 0) {
+
            if (JimCheckWaitStatus(interp, pid, waitStatus, errStrObj) != JIM_OK) {
                result = JIM_ERR;
            }
        }
@@ -5358,12 +6003,8 @@ static int JimCleanupChildren(Jim_Interp *interp, int numPids, pidtype *pidPtr,
int Jim_execInit(Jim_Interp *interp)
{
    struct WaitInfoTable *waitinfo;
-
    if (Jim_PackageProvide(interp, "exec", "1.0", JIM_ERRMSG))
-
        return JIM_ERR;

-
#ifdef SIGPIPE
-
    (void)signal(SIGPIPE, SIG_IGN);
-
#endif
+
    Jim_PackageProvideCheck(interp, "exec");

    waitinfo = JimAllocWaitInfoTable();
    Jim_CreateCommand(interp, "exec", Jim_ExecCmd, waitinfo, JimFreeWaitInfoTable);
@@ -5485,19 +6126,19 @@ JimWinBuildCommandLine(Jim_Interp *interp, char **argv)
    return strObj;
}

-
static pidtype
+
static phandle_t
JimStartWinProcess(Jim_Interp *interp, char **argv, char **env, int inputId, int outputId, int errorId)
{
    STARTUPINFO startInfo;
    PROCESS_INFORMATION procInfo;
    HANDLE hProcess;
    char execPath[MAX_PATH];
-
    pidtype pid = JIM_BAD_PID;
+
    phandle_t phandle = INVALID_HANDLE_VALUE;
    Jim_Obj *cmdLineObj;
    char *winenv;

    if (JimWinFindExecutable(argv[0], execPath) < 0) {
-
        return JIM_BAD_PID;
+
        return phandle;
    }
    argv[0] = execPath;

@@ -5560,7 +6201,7 @@ JimStartWinProcess(Jim_Interp *interp, char **argv, char **env, int inputId, int
    WaitForInputIdle(procInfo.hProcess, 5000);
    CloseHandle(procInfo.hThread);

-
    pid = procInfo.hProcess;
+
    phandle = procInfo.hProcess;

    end:
    Jim_FreeNewObj(interp, cmdLineObj);
@@ -5573,7 +6214,7 @@ JimStartWinProcess(Jim_Interp *interp, char **argv, char **env, int inputId, int
    if (startInfo.hStdError != INVALID_HANDLE_VALUE) {
        CloseHandle(startInfo.hStdError);
    }
-
    return pid;
+
    return phandle;
}

#else
@@ -5599,18 +6240,6 @@ static void JimRestoreEnv(char **env)
#endif


-

-
#ifdef STRPTIME_NEEDS_XOPEN_SOURCE
-
#ifndef _XOPEN_SOURCE
-
#define _XOPEN_SOURCE 500
-
#endif
-
#endif
-

-

-
#ifndef _GNU_SOURCE
-
#define _GNU_SOURCE
-
#endif
-

#include <stdlib.h>
#include <string.h>
#include <stdio.h>
@@ -5734,37 +6363,32 @@ static int clock_cmd_scan(Jim_Interp *interp, int argc, Jim_Obj *const *argv)

static int clock_cmd_seconds(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
-
    Jim_SetResultInt(interp, time(NULL));
+
    Jim_SetResultInt(interp, Jim_GetTimeUsec(CLOCK_REALTIME) / 1000000);
+
    return JIM_OK;
+
}

+
static int clock_cmd_clicks(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+
{
+
    Jim_SetResultInt(interp, Jim_GetTimeUsec(CLOCK_MONOTONIC_RAW));
    return JIM_OK;
}

static int clock_cmd_micros(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
-
    struct timeval tv;
-

-
    gettimeofday(&tv, NULL);
-

-
    Jim_SetResultInt(interp, (jim_wide) tv.tv_sec * 1000000 + tv.tv_usec);
-

+
    Jim_SetResultInt(interp, Jim_GetTimeUsec(CLOCK_REALTIME));
    return JIM_OK;
}

static int clock_cmd_millis(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
-
    struct timeval tv;
-

-
    gettimeofday(&tv, NULL);
-

-
    Jim_SetResultInt(interp, (jim_wide) tv.tv_sec * 1000 + tv.tv_usec / 1000);
-

+
    Jim_SetResultInt(interp, Jim_GetTimeUsec(CLOCK_REALTIME) / 1000);
    return JIM_OK;
}

static const jim_subcmd_type clock_command_table[] = {
    {   "clicks",
        NULL,
-
        clock_cmd_micros,
+
        clock_cmd_clicks,
        0,
        0,

@@ -5811,9 +6435,7 @@ static const jim_subcmd_type clock_command_table[] = {

int Jim_clockInit(Jim_Interp *interp)
{
-
    if (Jim_PackageProvide(interp, "clock", "1.0", JIM_ERRMSG))
-
        return JIM_ERR;
-

+
    Jim_PackageProvideCheck(interp, "clock");
    Jim_CreateCommand(interp, "clock", Jim_SubCmdProc, (void *)clock_command_table, NULL);
    return JIM_OK;
}
@@ -5888,7 +6510,8 @@ static int array_cmd_unset(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
        return JIM_OK;
    }

-
    if (Jim_DictPairs(interp, objPtr, &dictValuesObj, &len) != JIM_OK) {
+
    dictValuesObj = Jim_DictPairs(interp, objPtr, &len);
+
    if (dictValuesObj == NULL) {

        Jim_SetResultString(interp, "", -1);
        return JIM_OK;
@@ -5902,7 +6525,6 @@ static int array_cmd_unset(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
            Jim_DictAddElement(interp, resultObj, dictValuesObj[i], dictValuesObj[i + 1]);
        }
    }
-
    Jim_Free(dictValuesObj);

    Jim_SetVariable(interp, argv[0], resultObj);
    return JIM_OK;
@@ -6033,10 +6655,55 @@ static const jim_subcmd_type array_command_table[] = {

int Jim_arrayInit(Jim_Interp *interp)
{
-
    if (Jim_PackageProvide(interp, "array", "1.0", JIM_ERRMSG))
+
    Jim_PackageProvideCheck(interp, "array");
+
    Jim_CreateCommand(interp, "array", Jim_SubCmdProc, (void *)array_command_table, NULL);
+
    return JIM_OK;
+
}
+

+
#include <sys/types.h>
+
#include <sys/time.h>
+
#include <sys/wait.h>
+
#include <unistd.h>
+
#include <string.h>
+
#include <errno.h>
+

+

+
#ifdef HAVE_SYS_SYSINFO_H
+
#include <sys/sysinfo.h>
+
#endif
+

+
static void Jim_PosixSetError(Jim_Interp *interp)
+
{
+
    Jim_SetResultString(interp, strerror(errno), -1);
+
}
+

+
#if defined(HAVE_FORK)
+
static int Jim_PosixForkCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+
{
+
    pid_t pid;
+

+
    JIM_NOTUSED(argv);
+

+
    if (argc != 1) {
+
        Jim_WrongNumArgs(interp, 1, argv, "");
+
        return JIM_ERR;
+
    }
+
    if ((pid = fork()) == -1) {
+
        Jim_PosixSetError(interp);
        return JIM_ERR;
+
    }
+
    Jim_SetResultInt(interp, (jim_wide) pid);
+
    return JIM_OK;
+
}
+
#endif

-
    Jim_CreateCommand(interp, "array", Jim_SubCmdProc, (void *)array_command_table, NULL);
+

+
int Jim_posixInit(Jim_Interp *interp)
+
{
+
    Jim_PackageProvideCheck(interp, "posix");
+
#ifdef HAVE_FORK
+
    Jim_CreateCommand(interp, "os.fork", Jim_PosixForkCommand, NULL, NULL);
+
#endif
    return JIM_OK;
}
int Jim_InitStaticExtensions(Jim_Interp *interp)
@@ -6048,6 +6715,7 @@ extern int Jim_regexpInit(Jim_Interp *);
extern int Jim_fileInit(Jim_Interp *);
extern int Jim_globInit(Jim_Interp *);
extern int Jim_execInit(Jim_Interp *);
+
extern int Jim_posixInit(Jim_Interp *);
extern int Jim_clockInit(Jim_Interp *);
extern int Jim_arrayInit(Jim_Interp *);
extern int Jim_stdlibInit(Jim_Interp *);
@@ -6059,6 +6727,7 @@ Jim_regexpInit(interp);
Jim_fileInit(interp);
Jim_globInit(interp);
Jim_execInit(interp);
+
Jim_posixInit(interp);
Jim_clockInit(interp);
Jim_arrayInit(interp);
Jim_stdlibInit(interp);
@@ -6066,9 +6735,6 @@ Jim_tclcompatInit(interp);
return JIM_OK;
}
#define JIM_OPTIMIZATION
-
#ifndef _GNU_SOURCE
-
#define _GNU_SOURCE
-
#endif

#include <stdio.h>
#include <stdlib.h>
@@ -6086,7 +6752,7 @@ return JIM_OK;
#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>
#endif
-
#ifdef HAVE_BACKTRACE
+
#ifdef HAVE_EXECINFO_H
#include <execinfo.h>
#endif
#ifdef HAVE_CRT_EXTERNS_H
@@ -6138,6 +6804,7 @@ static void JimPanicDump(int fail_condition, const char *fmt, ...);
#endif

#ifdef JIM_OPTIMIZATION
+
static int JimIsWide(Jim_Obj *objPtr);
#define JIM_IF_OPTIM(X) X
#else
#define JIM_IF_OPTIM(X)
@@ -6149,18 +6816,25 @@ static char JimEmptyStringRep[] = "";
static void JimFreeCallFrame(Jim_Interp *interp, Jim_CallFrame *cf, int action);
static int ListSetIndex(Jim_Interp *interp, Jim_Obj *listPtr, int listindex, Jim_Obj *newObjPtr,
    int flags);
+
static int Jim_ListIndices(Jim_Interp *interp, Jim_Obj *listPtr, Jim_Obj *const *indexv, int indexc,
+
    Jim_Obj **resultObj, int flags);
static int JimDeleteLocalProcs(Jim_Interp *interp, Jim_Stack *localCommands);
static Jim_Obj *JimExpandDictSugar(Jim_Interp *interp, Jim_Obj *objPtr);
static void SetDictSubstFromAny(Jim_Interp *interp, Jim_Obj *objPtr);
-
static Jim_Obj **JimDictPairs(Jim_Obj *dictPtr, int *len);
static void JimSetFailedEnumResult(Jim_Interp *interp, const char *arg, const char *badtype,
    const char *prefix, const char *const *tablePtr, const char *name);
static int JimCallProcedure(Jim_Interp *interp, Jim_Cmd *cmd, int argc, Jim_Obj *const *argv);
static int JimGetWideNoErr(Jim_Interp *interp, Jim_Obj *objPtr, jim_wide * widePtr);
static int JimSign(jim_wide w);
-
static int JimValidName(Jim_Interp *interp, const char *type, Jim_Obj *nameObjPtr);
static void JimPrngSeed(Jim_Interp *interp, unsigned char *seed, int seedLen);
static void JimRandomBytes(Jim_Interp *interp, void *dest, unsigned int len);
+
static int JimSetNewVariable(Jim_HashTable *ht, Jim_Obj *nameObjPtr, Jim_VarVal *vv);
+
static Jim_VarVal *JimFindVariable(Jim_HashTable *ht, Jim_Obj *nameObjPtr);
+
static void JimSetErrorStack(Jim_Interp *interp);
+
static int SetVariableFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr);
+

+
#define JIM_DICT_SUGAR 100
+




@@ -6177,16 +6851,28 @@ static int utf8_tounicode_case(const char *s, int *uc, int upper)
    return l;
}

+
static Jim_Obj *JimPushInterpObjImpl(Jim_Obj **iop, Jim_Obj *no)
+
{
+
    Jim_Obj *io = *iop;
+
    Jim_IncrRefCount(no);
+
    *iop = no;
+
    return io;
+
}
+

+
#define JimPushInterpObj(IO, NO) JimPushInterpObjImpl(&(IO), NO)
+
#define JimPopInterpObj(I, IO, SO) do { Jim_DecrRefCount(I, IO); IO = SO; } while (0)
+


#define JIM_CHARSET_SCAN 2
#define JIM_CHARSET_GLOB 0

-
static const char *JimCharsetMatch(const char *pattern, int c, int flags)
+
static const char *JimCharsetMatch(const char *pattern, int plen, int c, int flags)
{
    int not = 0;
    int pchar;
    int match = 0;
    int nocase = 0;
+
    int n;

    if (flags & JIM_NOCASE) {
        nocase++;
@@ -6197,6 +6883,7 @@ static const char *JimCharsetMatch(const char *pattern, int c, int flags)
        if (*pattern == '^') {
            not++;
            pattern++;
+
            plen--;
        }


@@ -6205,22 +6892,27 @@ static const char *JimCharsetMatch(const char *pattern, int c, int flags)
        }
    }

-
    while (*pattern && *pattern != ']') {
+
    while (plen && *pattern != ']') {

        if (pattern[0] == '\\') {
first:
-
            pattern += utf8_tounicode_case(pattern, &pchar, nocase);
+
            n = utf8_tounicode_case(pattern, &pchar, nocase);
+
            pattern += n;
+
            plen -= n;
        }
        else {

            int start;
            int end;

-
            pattern += utf8_tounicode_case(pattern, &start, nocase);
-
            if (pattern[0] == '-' && pattern[1]) {
+
            n = utf8_tounicode_case(pattern, &start, nocase);
+
            pattern += n;
+
            plen -= n;
+
            if (pattern[0] == '-' && plen > 1) {

-
                pattern++;
-
                pattern += utf8_tounicode_case(pattern, &end, nocase);
+
                n = 1 + utf8_tounicode_case(pattern + 1, &end, nocase);
+
                pattern += n;
+
                plen -= n;


                if ((c >= start && c <= end) || (c >= end && c <= start)) {
@@ -6244,39 +6936,52 @@ first:



-
static int JimGlobMatch(const char *pattern, const char *string, int nocase)
+
static int JimGlobMatch(const char *pattern, int plen, const char *string, int slen, int nocase)
{
    int c;
    int pchar;
-
    while (*pattern) {
+
    int n;
+
    const char *p;
+
    while (plen) {
        switch (pattern[0]) {
            case '*':
-
                while (pattern[1] == '*') {
+
                while (pattern[1] == '*' && plen) {
                    pattern++;
+
                    plen--;
                }
                pattern++;
-
                if (!pattern[0]) {
+
                plen--;
+
                if (!plen) {
                    return 1;
                }
-
                while (*string) {
+
                while (slen) {

-
                    if (JimGlobMatch(pattern, string, nocase))
+
                    if (JimGlobMatch(pattern, plen, string, slen, nocase))
                        return 1;
-
                    string += utf8_tounicode(string, &c);
+
                    n = utf8_tounicode(string, &c);
+
                    string += n;
+
                    slen -= n;
                }
                return 0;

            case '?':
-
                string += utf8_tounicode(string, &c);
+
                n = utf8_tounicode(string, &c);
+
                string += n;
+
                slen -= n;
                break;

            case '[': {
-
                    string += utf8_tounicode(string, &c);
-
                    pattern = JimCharsetMatch(pattern + 1, c, nocase ? JIM_NOCASE : 0);
-
                    if (!pattern) {
+
                    n = utf8_tounicode(string, &c);
+
                    string += n;
+
                    slen -= n;
+
                    p = JimCharsetMatch(pattern + 1, plen - 1, c, nocase ? JIM_NOCASE : 0);
+
                    if (!p) {
                        return 0;
                    }
-
                    if (!*pattern) {
+
                    plen -= p - pattern;
+
                    pattern = p;
+

+
                    if (!plen) {

                        continue;
                    }
@@ -6285,64 +6990,58 @@ static int JimGlobMatch(const char *pattern, const char *string, int nocase)
            case '\\':
                if (pattern[1]) {
                    pattern++;
+
                    plen--;
                }

            default:
-
                string += utf8_tounicode_case(string, &c, nocase);
+
                n = utf8_tounicode_case(string, &c, nocase);
+
                string += n;
+
                slen -= n;
                utf8_tounicode_case(pattern, &pchar, nocase);
                if (pchar != c) {
                    return 0;
                }
                break;
        }
-
        pattern += utf8_tounicode_case(pattern, &pchar, nocase);
-
        if (!*string) {
-
            while (*pattern == '*') {
+
        n = utf8_tounicode_case(pattern, &pchar, nocase);
+
        pattern += n;
+
        plen -= n;
+
        if (!slen) {
+
            while (*pattern == '*' && plen) {
                pattern++;
+
                plen--;
            }
            break;
        }
    }
-
    if (!*pattern && !*string) {
+
    if (!plen && !slen) {
        return 1;
    }
    return 0;
}

-
static int JimStringCompare(const char *s1, int l1, const char *s2, int l2)
+
static int JimStringCompareUtf8(const char *s1, int l1, const char *s2, int l2, int nocase)
{
-
    if (l1 < l2) {
-
        return memcmp(s1, s2, l1) <= 0 ? -1 : 1;
+
    int minlen = l1;
+
    if (l2 < l1) {
+
        minlen = l2;
    }
-
    else if (l2 < l1) {
-
        return memcmp(s1, s2, l2) >= 0 ? 1 : -1;
-
    }
-
    else {
-
        return JimSign(memcmp(s1, s2, l1));
-
    }
-
}
-

-
static int JimStringCompareLen(const char *s1, const char *s2, int maxchars, int nocase)
-
{
-
    while (*s1 && *s2 && maxchars) {
+
    while (minlen) {
        int c1, c2;
        s1 += utf8_tounicode_case(s1, &c1, nocase);
        s2 += utf8_tounicode_case(s2, &c2, nocase);
        if (c1 != c2) {
            return JimSign(c1 - c2);
        }
-
        maxchars--;
-
    }
-
    if (!maxchars) {
-
        return 0;
+
        minlen--;
    }

-
    if (*s1) {
-
        return 1;
-
    }
-
    if (*s2) {
+
    if (l1 < l2) {
        return -1;
    }
+
    if (l1 > l2) {
+
        return 1;
+
    }
    return 0;
}

@@ -6418,7 +7117,7 @@ static int JimNumberBase(const char *str, int *base, int *sign)
{
    int i = 0;

-
    *base = 10;
+
    *base = 0;

    while (isspace(UCHAR(str[i]))) {
        i++;
@@ -6445,6 +7144,7 @@ static int JimNumberBase(const char *str, int *base, int *sign)
        case 'x': case 'X': *base = 16; break;
        case 'o': case 'O': *base = 8; break;
        case 'b': case 'B': *base = 2; break;
+
        case 'd': case 'D': *base = 10; break;
        default: return 0;
    }
    i += 2;
@@ -6454,7 +7154,7 @@ static int JimNumberBase(const char *str, int *base, int *sign)
        return i;
    }

-
    *base = 10;
+
    *base = 0;
    return 0;
}

@@ -6464,7 +7164,7 @@ static long jim_strtol(const char *str, char **endptr)
    int base;
    int i = JimNumberBase(str, &base, &sign);

-
    if (base != 10) {
+
    if (base != 0) {
        long value = strtol(str + i, endptr, base);
        if (endptr == NULL || *endptr != str + i) {
            return value * sign;
@@ -6483,7 +7183,7 @@ static jim_wide jim_strtoull(const char *str, char **endptr)
    int base;
    int i = JimNumberBase(str, &base, &sign);

-
    if (base != 10) {
+
    if (base != 0) {
        jim_wide value = strtoull(str + i, endptr, base);
        if (endptr == NULL || *endptr != str + i) {
            return value * sign;
@@ -6565,7 +7265,7 @@ static void JimPanicDump(int condition, const char *fmt, ...)
    fprintf(stderr, "\n\n");
    va_end(ap);

-
#ifdef HAVE_BACKTRACE
+
#if defined(HAVE_BACKTRACE)
    {
        void *array[40];
        int size, i;
@@ -6585,47 +7285,63 @@ static void JimPanicDump(int condition, const char *fmt, ...)
#endif


-
void *Jim_Alloc(int size)
-
{
-
    return size ? malloc(size) : NULL;
-
}
-

-
void Jim_Free(void *ptr)
+
void *JimDefaultAllocator(void *ptr, size_t size)
{
-
    free(ptr);
+
    if (size == 0) {
+
        free(ptr);
+
        return NULL;
+
    }
+
    else if (ptr) {
+
        return realloc(ptr, size);
+
    }
+
    else {
+
        return malloc(size);
+
    }
}

-
void *Jim_Realloc(void *ptr, int size)
-
{
-
    return realloc(ptr, size);
-
}
+
void *(*Jim_Allocator)(void *ptr, size_t size) = JimDefaultAllocator;

char *Jim_StrDup(const char *s)
{
-
    return strdup(s);
+
    return Jim_StrDupLen(s, strlen(s));
}

char *Jim_StrDupLen(const char *s, int l)
{
    char *copy = Jim_Alloc(l + 1);

-
    memcpy(copy, s, l + 1);
+
    memcpy(copy, s, l);
    copy[l] = 0;
    return copy;
}


-

-
static jim_wide JimClock(void)
+
jim_wide Jim_GetTimeUsec(unsigned type)
{
+
    long long now;
    struct timeval tv;

-
    gettimeofday(&tv, NULL);
-
    return (jim_wide) tv.tv_sec * 1000000 + tv.tv_usec;
+
#if defined(HAVE_CLOCK_GETTIME)
+
    struct timespec ts;
+

+
    if (clock_gettime(type, &ts) == 0) {
+
        now = ts.tv_sec * 1000000LL + ts.tv_nsec / 1000;
+
    }
+
    else
+
#endif
+
    {
+
        gettimeofday(&tv, NULL);
+

+
        now = tv.tv_sec * 1000000LL + tv.tv_usec;
+
    }
+

+
    return now;
}



+

+

static void JimExpandHashTableIfNeeded(Jim_HashTable *ht);
static unsigned int JimHashTableNextPower(unsigned int size);
static Jim_HashEntry *JimInsertHashEntry(Jim_HashTable *ht, const void *key, int replace);
@@ -6644,18 +7360,19 @@ unsigned int Jim_IntHashFunction(unsigned int key)
    return key;
}

-
unsigned int Jim_GenHashFunction(const unsigned char *buf, int len)
-
{
-
    unsigned int h = 0;

-
    while (len--)
-
        h += (h << 3) + *buf++;
-
    return h;
+
unsigned int Jim_GenHashFunction(const unsigned char *string, int length)
+
{
+
    unsigned result = 0;
+
    string += length;
+
    while (length--) {
+
        result += (result << 3) + (unsigned char)(*--string);
+
    }
+
    return result;
}



-

static void JimResetHashTable(Jim_HashTable *ht)
{
    ht->table = NULL;
@@ -6687,15 +7404,6 @@ int Jim_InitHashTable(Jim_HashTable *ht, const Jim_HashTableType *type, void *pr
    return JIM_OK;
}

-
void Jim_ResizeHashTable(Jim_HashTable *ht)
-
{
-
    int minimal = ht->used;
-

-
    if (minimal < JIM_HT_INITIAL_SIZE)
-
        minimal = JIM_HT_INITIAL_SIZE;
-
    Jim_ExpandHashTable(ht, minimal);
-
}
-


void Jim_ExpandHashTable(Jim_HashTable *ht, unsigned int size)
{
@@ -6744,12 +7452,9 @@ void Jim_ExpandHashTable(Jim_HashTable *ht, unsigned int size)
    *ht = n;
}

-

int Jim_AddHashEntry(Jim_HashTable *ht, const void *key, void *val)
{
-
    Jim_HashEntry *entry;
-

-
    entry = JimInsertHashEntry(ht, key, 0);
+
    Jim_HashEntry *entry = JimInsertHashEntry(ht, key, 0);;
    if (entry == NULL)
        return JIM_ERR;

@@ -6788,39 +7493,35 @@ int Jim_ReplaceHashEntry(Jim_HashTable *ht, const void *key, void *val)
    return existed;
}

-

int Jim_DeleteHashEntry(Jim_HashTable *ht, const void *key)
{
-
    unsigned int h;
-
    Jim_HashEntry *he, *prevHe;
+
    if (ht->used) {
+
        unsigned int h = Jim_HashKey(ht, key) & ht->sizemask;
+
        Jim_HashEntry *prevHe = NULL;
+
        Jim_HashEntry *he = ht->table[h];

-
    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)) {
+
        while (he) {
+
            if (Jim_CompareHashKeys(ht, key, he->key)) {

-
            if (prevHe)
-
                prevHe->next = he->next;
-
            else
-
                ht->table[h] = he->next;
-
            Jim_FreeEntryKey(ht, he);
-
            Jim_FreeEntryVal(ht, he);
-
            Jim_Free(he);
-
            ht->used--;
-
            return JIM_OK;
+
                if (prevHe)
+
                    prevHe->next = he->next;
+
                else
+
                    ht->table[h] = he->next;
+
                ht->used--;
+
                Jim_FreeEntryKey(ht, he);
+
                Jim_FreeEntryVal(ht, he);
+
                Jim_Free(he);
+
                return JIM_OK;
+
            }
+
            prevHe = he;
+
            he = he->next;
        }
-
        prevHe = he;
-
        he = he->next;
    }
+

    return JIM_ERR;
}

-

-
int Jim_FreeHashTable(Jim_HashTable *ht)
+
void Jim_ClearHashTable(Jim_HashTable *ht)
{
    unsigned int i;

@@ -6828,8 +7529,7 @@ int Jim_FreeHashTable(Jim_HashTable *ht)
    for (i = 0; ht->used > 0; i++) {
        Jim_HashEntry *he, *nextHe;

-
        if ((he = ht->table[i]) == NULL)
-
            continue;
+
        he = ht->table[i];
        while (he) {
            nextHe = he->next;
            Jim_FreeEntryKey(ht, he);
@@ -6838,7 +7538,13 @@ int Jim_FreeHashTable(Jim_HashTable *ht)
            ht->used--;
            he = nextHe;
        }
+
        ht->table[i] = NULL;
    }
+
}
+

+
int Jim_FreeHashTable(Jim_HashTable *ht)
+
{
+
    Jim_ClearHashTable(ht);

    Jim_Free(ht->table);

@@ -7142,6 +7848,9 @@ static int JimParseScript(struct JimParserCtx *pc)
            pc->tend = pc->p - 1;
            pc->tline = pc->linenr;
            pc->tt = JIM_TT_EOL;
+
            if (pc->inquote) {
+
                pc->missing.ch = '"';
+
            }
            pc->eof = 1;
            return JIM_OK;
        }
@@ -7356,6 +8065,9 @@ static void JimParseSubCmd(struct JimParserCtx *pc)
            case '"':
                if (startofword) {
                    JimParseSubQuote(pc);
+
                    if (pc->missing.ch == '"') {
+
                        return;
+
                    }
                    continue;
                }
                break;
@@ -8307,33 +9019,24 @@ int Jim_StringEqObj(Jim_Obj *aObjPtr, Jim_Obj *bObjPtr)

int Jim_StringMatchObj(Jim_Interp *interp, Jim_Obj *patternObjPtr, Jim_Obj *objPtr, int nocase)
{
-
    return JimGlobMatch(Jim_String(patternObjPtr), Jim_String(objPtr), nocase);
+
    int plen, slen;
+
    const char *pattern = Jim_GetString(patternObjPtr, &plen);
+
    const char *string = Jim_GetString(objPtr, &slen);
+
    return JimGlobMatch(pattern, plen, string, slen, nocase);
}

int Jim_StringCompareObj(Jim_Interp *interp, Jim_Obj *firstObjPtr, Jim_Obj *secondObjPtr, int nocase)
{
-
    int l1, l2;
-
    const char *s1 = Jim_GetString(firstObjPtr, &l1);
-
    const char *s2 = Jim_GetString(secondObjPtr, &l2);
-

-
    if (nocase) {
-

-
        return JimStringCompareLen(s1, s2, -1, nocase);
-
    }
-
    return JimStringCompare(s1, l1, s2, l2);
-
}
-

-
int Jim_StringCompareLenObj(Jim_Interp *interp, Jim_Obj *firstObjPtr, Jim_Obj *secondObjPtr, int nocase)
-
{
    const char *s1 = Jim_String(firstObjPtr);
+
    int l1 = Jim_Utf8Length(interp, firstObjPtr);
    const char *s2 = Jim_String(secondObjPtr);
-

-
    return JimStringCompareLen(s1, s2, Jim_Utf8Length(interp, firstObjPtr), nocase);
+
    int l2 = Jim_Utf8Length(interp, secondObjPtr);
+
    return JimStringCompareUtf8(s1, l1, s2, l2, nocase);
}

static int JimRelToAbsIndex(int len, int idx)
{
-
    if (idx < 0)
+
    if (idx < 0 && idx > -INT_MAX)
        return len + idx;
    return idx;
}
@@ -8851,7 +9554,7 @@ static const Jim_ObjType scriptObjType = {
    FreeScriptInternalRep,
    DupScriptInternalRep,
    NULL,
-
    JIM_TYPE_REFERENCES,
+
    JIM_TYPE_NONE,
};

typedef struct ScriptToken
@@ -9225,8 +9928,6 @@ static void JimSetScriptFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr)
    objPtr->typePtr = &scriptObjType;
}

-
static void JimAddErrorToStack(Jim_Interp *interp, ScriptObj *script);
-

static ScriptObj *JimGetScript(Jim_Interp *interp, Jim_Obj *objPtr)
{
    if (objPtr == interp->emptyObj) {
@@ -9241,16 +9942,19 @@ static ScriptObj *JimGetScript(Jim_Interp *interp, Jim_Obj *objPtr)
    return (ScriptObj *)Jim_GetIntRepPtr(objPtr);
}

-
static int JimScriptValid(Jim_Interp *interp, ScriptObj *script)
+
void Jim_InterpIncrProcEpoch(Jim_Interp *interp)
{
-
    if (JimParseCheckMissing(interp, script->missing) == JIM_ERR) {
-
        JimAddErrorToStack(interp, script);
-
        return 0;
+
    interp->procEpoch++;
+

+

+
    while (interp->oldCmdCache) {
+
        Jim_Cmd *next = interp->oldCmdCache->prevCmd;
+
        Jim_Free(interp->oldCmdCache);
+
        interp->oldCmdCache = next;
    }
-
    return 1;
+
    interp->oldCmdCacheSize = 0;
}

-

static void JimIncrCmdRefCount(Jim_Cmd *cmdPtr)
{
    cmdPtr->inUse++;
@@ -9276,63 +9980,154 @@ static void JimDecrCmdRefCount(Jim_Interp *interp, Jim_Cmd *cmdPtr)
        }
        if (cmdPtr->prevCmd) {

-
            JimDecrCmdRefCount(interp, cmdPtr->prevCmd);
-
        }
-
        Jim_Free(cmdPtr);
-
    }
+
            JimDecrCmdRefCount(interp, cmdPtr->prevCmd);
+
        }
+

+
        cmdPtr->prevCmd = interp->oldCmdCache;
+
        interp->oldCmdCache = cmdPtr;
+
        if (!interp->quitting && ++interp->oldCmdCacheSize >= 1000) {
+
            Jim_InterpIncrProcEpoch(interp);
+
        }
+
    }
+
}
+

+
static void JimIncrVarRef(Jim_VarVal *vv)
+
{
+
    vv->refCount++;
+
}
+

+
static void JimDecrVarRef(Jim_Interp *interp, Jim_VarVal *vv)
+
{
+
    assert(vv->refCount > 0);
+
    if (--vv->refCount == 0) {
+
        if (vv->objPtr) {
+
            Jim_DecrRefCount(interp, vv->objPtr);
+
        }
+
        Jim_Free(vv);
+
    }
+
}
+

+
static void JimVariablesHTValDestructor(void *interp, void *val)
+
{
+
    JimDecrVarRef(interp, val);
+
}
+

+
static unsigned int JimObjectHTHashFunction(const void *key)
+
{
+
    Jim_Obj *keyObj = (Jim_Obj *)key;
+
    int length;
+
    const char *string;
+

+
#ifdef JIM_OPTIMIZATION
+
    if (JimIsWide(keyObj) && keyObj->bytes == NULL) {
+

+
        jim_wide objValue = JimWideValue(keyObj);
+
        if (objValue > INT_MIN && objValue < INT_MAX) {
+
            unsigned result = 0;
+
            unsigned value = (unsigned)objValue;
+

+
            if (objValue < 0) {
+
                value = (unsigned)-objValue;
+
            }
+

+

+
            do {
+
                result += (result << 3) + (value % 10 + '0');
+
                value /= 10;
+
            } while (value);
+

+
            if (objValue < 0) {
+
                result += (result << 3) + '-';
+
            }
+
            return result;
+
        }
+
    }
+
#endif
+
    string = Jim_GetString(keyObj, &length);
+
    return Jim_GenHashFunction((const unsigned char *)string, length);
+
}
+

+
static int JimObjectHTKeyCompare(void *privdata, const void *key1, const void *key2)
+
{
+
    return Jim_StringEqObj((Jim_Obj *)key1, (Jim_Obj *)key2);
+
}
+

+
static void *JimObjectHTKeyValDup(void *privdata, const void *val)
+
{
+
    Jim_IncrRefCount((Jim_Obj *)val);
+
    return (void *)val;
+
}
+

+
static void JimObjectHTKeyValDestructor(void *interp, void *val)
+
{
+
    Jim_DecrRefCount(interp, (Jim_Obj *)val);
}

-
static void JimVariablesHTValDestructor(void *interp, void *val)
+

+
static void *JimVariablesHTValDup(void *privdata, const void *val)
{
-
    Jim_DecrRefCount(interp, ((Jim_Var *)val)->objPtr);
-
    Jim_Free(val);
+
    JimIncrVarRef((Jim_VarVal *)val);
+
    return (void *)val;
}

static const Jim_HashTableType JimVariablesHashTableType = {
-
    JimStringCopyHTHashFunction,
-
    JimStringCopyHTDup,
-
    NULL,
-
    JimStringCopyHTKeyCompare,
-
    JimStringCopyHTKeyDestructor,
+
    JimObjectHTHashFunction,
+
    JimObjectHTKeyValDup,
+
    JimVariablesHTValDup,
+
    JimObjectHTKeyCompare,
+
    JimObjectHTKeyValDestructor,
    JimVariablesHTValDestructor
};

+

+
static const char *Jim_GetStringNoQualifier(Jim_Obj *objPtr, int *length)
+
{
+
    int len;
+
    const char *str = Jim_GetString(objPtr, &len);
+
    if (len >= 2 && str[0] == ':' && str[1] == ':') {
+
        while (len && *str == ':') {
+
            len--;
+
            str++;
+
        }
+
    }
+
    *length = len;
+
    return str;
+
}
+

+
static unsigned int JimCommandsHT_HashFunction(const void *key)
+
{
+
    int len;
+
    const char *str = Jim_GetStringNoQualifier((Jim_Obj *)key, &len);
+
    return Jim_GenHashFunction((const unsigned char *)str, len);
+
}
+

+
static int JimCommandsHT_KeyCompare(void *privdata, const void *key1, const void *key2)
+
{
+
    int len1, len2;
+
    const char *str1 = Jim_GetStringNoQualifier((Jim_Obj *)key1, &len1);
+
    const char *str2 = Jim_GetStringNoQualifier((Jim_Obj *)key2, &len2);
+
    return len1 == len2 && memcmp(str1, str2, len1) == 0;
+
}
+

static void JimCommandsHT_ValDestructor(void *interp, void *val)
{
    JimDecrCmdRefCount(interp, val);
}

static const Jim_HashTableType JimCommandsHashTableType = {
-
    JimStringCopyHTHashFunction,
-
    JimStringCopyHTDup,
+
    JimCommandsHT_HashFunction,
+
    JimObjectHTKeyValDup,
    NULL,
-
    JimStringCopyHTKeyCompare,
-
    JimStringCopyHTKeyDestructor,
+
    JimCommandsHT_KeyCompare,
+
    JimObjectHTKeyValDestructor,
    JimCommandsHT_ValDestructor
};



-
#ifdef jim_ext_namespace
-
static Jim_Obj *JimQualifyNameObj(Jim_Interp *interp, Jim_Obj *nsObj)
-
{
-
    const char *name = Jim_String(nsObj);
-
    if (name[0] == ':' && name[1] == ':') {
-

-
        while (*++name == ':') {
-
        }
-
        nsObj = Jim_NewStringObj(interp, name, -1);
-
    }
-
    else if (Jim_Length(interp->framePtr->nsObj)) {
-

-
        nsObj = Jim_DuplicateObj(interp, interp->framePtr->nsObj);
-
        Jim_AppendStrings(interp, nsObj, "::", name, NULL);
-
    }
-
    return nsObj;
-
}
-

Jim_Obj *Jim_MakeGlobalNamespaceName(Jim_Interp *interp, Jim_Obj *nameObjPtr)
{
+
#ifdef jim_ext_namespace
    Jim_Obj *resultObj;

    const char *name = Jim_String(nameObjPtr);
@@ -9345,67 +10140,50 @@ Jim_Obj *Jim_MakeGlobalNamespaceName(Jim_Interp *interp, Jim_Obj *nameObjPtr)
    Jim_DecrRefCount(interp, nameObjPtr);

    return resultObj;
+
#else
+
    return nameObjPtr;
+
#endif
}

-
static const char *JimQualifyName(Jim_Interp *interp, const char *name, Jim_Obj **objPtrPtr)
+
static Jim_Obj *JimQualifyName(Jim_Interp *interp, Jim_Obj *objPtr)
{
-
    Jim_Obj *objPtr = interp->emptyObj;
-

-
    if (name[0] == ':' && name[1] == ':') {
+
#ifdef jim_ext_namespace
+
    if (Jim_Length(interp->framePtr->nsObj)) {
+
        int len;
+
        const char *name = Jim_GetString(objPtr, &len);
+
        if (len < 2 || name[0] != ':' || name[1] != ':') {

-
        while (*++name == ':') {
+
            objPtr = Jim_DuplicateObj(interp, interp->framePtr->nsObj);
+
            Jim_AppendStrings(interp, objPtr, "::", name, NULL);
        }
    }
-
    else if (Jim_Length(interp->framePtr->nsObj)) {
-

-
        objPtr = Jim_DuplicateObj(interp, interp->framePtr->nsObj);
-
        Jim_AppendStrings(interp, objPtr, "::", name, NULL);
-
        name = Jim_String(objPtr);
-
    }
+
#endif
    Jim_IncrRefCount(objPtr);
-
    *objPtrPtr = objPtr;
-
    return name;
-
}
-

-
    #define JimFreeQualifiedName(INTERP, OBJ) Jim_DecrRefCount((INTERP), (OBJ))
-

-
#else
-

-
    #define JimQualifyName(INTERP, NAME, DUMMY) (((NAME)[0] == ':' && (NAME)[1] == ':') ? (NAME) + 2 : (NAME))
-
    #define JimFreeQualifiedName(INTERP, DUMMY) (void)(DUMMY)
-

-
Jim_Obj *Jim_MakeGlobalNamespaceName(Jim_Interp *interp, Jim_Obj *nameObjPtr)
-
{
-
    return nameObjPtr;
+
    return objPtr;
}
-
#endif

-
static int JimCreateCommand(Jim_Interp *interp, const char *name, Jim_Cmd *cmd)
+
static void JimCreateCommand(Jim_Interp *interp, Jim_Obj *nameObjPtr, Jim_Cmd *cmd)
{
-
    Jim_HashEntry *he = Jim_FindHashEntry(&interp->commands, name);
-
    if (he) {
+
    JimPanic((nameObjPtr->refCount == 0, "JimCreateCommand called with zero ref count name"));

-
        Jim_InterpIncrProcEpoch(interp);
-
    }
+
    if (interp->local) {
+
        Jim_HashEntry *he = Jim_FindHashEntry(&interp->commands, nameObjPtr);
+
        if (he) {

-
    if (he && interp->local) {
+
            cmd->prevCmd = Jim_GetHashEntryVal(he);
+
            Jim_SetHashVal(&interp->commands, he, cmd);

-
        cmd->prevCmd = Jim_GetHashEntryVal(he);
-
        Jim_SetHashVal(&interp->commands, he, cmd);
+
            Jim_InterpIncrProcEpoch(interp);
+
            return;
+
        }
    }
-
    else {
-
        if (he) {

-
            Jim_DeleteHashEntry(&interp->commands, name);
-
        }

-
        Jim_AddHashEntry(&interp->commands, name, cmd);
-
    }
-
    return JIM_OK;
-
}

+
    Jim_ReplaceHashEntry(&interp->commands, nameObjPtr, cmd);
+
}

-
int Jim_CreateCommand(Jim_Interp *interp, const char *cmdNameStr,
+
int Jim_CreateCommandObj(Jim_Interp *interp, Jim_Obj *cmdNameObj,
    Jim_CmdProc *cmdProc, void *privData, Jim_DelCmdProc *delProc)
{
    Jim_Cmd *cmdPtr = Jim_Alloc(sizeof(*cmdPtr));
@@ -9417,11 +10195,20 @@ int Jim_CreateCommand(Jim_Interp *interp, const char *cmdNameStr,
    cmdPtr->u.native.cmdProc = cmdProc;
    cmdPtr->u.native.privData = privData;

-
    JimCreateCommand(interp, cmdNameStr, cmdPtr);
+
    Jim_IncrRefCount(cmdNameObj);
+
    JimCreateCommand(interp, cmdNameObj, cmdPtr);
+
    Jim_DecrRefCount(interp, cmdNameObj);

    return JIM_OK;
}

+

+
int Jim_CreateCommand(Jim_Interp *interp, const char *cmdNameStr,
+
    Jim_CmdProc *cmdProc, void *privData, Jim_DelCmdProc *delProc)
+
{
+
    return Jim_CreateCommandObj(interp, Jim_NewStringObj(interp, cmdNameStr, -1), cmdProc, privData, delProc);
+
}
+

static int JimCreateProcedureStatics(Jim_Interp *interp, Jim_Cmd *cmdPtr, Jim_Obj *staticsListObjPtr)
{
    int len, i;
@@ -9434,68 +10221,125 @@ static int JimCreateProcedureStatics(Jim_Interp *interp, Jim_Cmd *cmdPtr, Jim_Ob
    cmdPtr->u.proc.staticVars = Jim_Alloc(sizeof(Jim_HashTable));
    Jim_InitHashTable(cmdPtr->u.proc.staticVars, &JimVariablesHashTableType, interp);
    for (i = 0; i < len; i++) {
-
        Jim_Obj *objPtr, *initObjPtr, *nameObjPtr;
-
        Jim_Var *varPtr;
-
        int subLen;
-

-
        objPtr = Jim_ListGetIndex(interp, staticsListObjPtr, i);
-

-
        subLen = Jim_ListLength(interp, objPtr);
-
        if (subLen == 1 || subLen == 2) {
-
            nameObjPtr = Jim_ListGetIndex(interp, objPtr, 0);
-
            if (subLen == 1) {
-
                initObjPtr = Jim_GetVariable(interp, nameObjPtr, JIM_NONE);
-
                if (initObjPtr == NULL) {
+
        Jim_Obj *initObjPtr = NULL;
+
        Jim_Obj *nameObjPtr;
+
        Jim_VarVal *vv = NULL;
+
        Jim_Obj *objPtr = Jim_ListGetIndex(interp, staticsListObjPtr, i);
+
        int subLen = Jim_ListLength(interp, objPtr);
+
        int byref = 0;
+

+

+
        if (subLen != 1 && subLen != 2) {
+
            Jim_SetResultFormatted(interp, "too many fields in static specifier \"%#s\"",
+
                objPtr);
+
            return JIM_ERR;
+
        }
+

+
        nameObjPtr = Jim_ListGetIndex(interp, objPtr, 0);
+

+

+
        if (subLen == 1) {
+
            int len;
+
            const char *pt = Jim_GetString(nameObjPtr, &len);
+
            if (*pt == '&') {
+

+
                nameObjPtr = Jim_NewStringObj(interp, pt + 1, len - 1);
+
                byref = 1;
+
            }
+
        }
+
        Jim_IncrRefCount(nameObjPtr);
+

+
        if (subLen == 1) {
+
            switch (SetVariableFromAny(interp, nameObjPtr)) {
+
                case JIM_DICT_SUGAR:
+

+
                    if (byref) {
+
                        Jim_SetResultFormatted(interp, "Can't link to array element \"%#s\"", nameObjPtr);
+
                    }
+
                    else {
+
                        Jim_SetResultFormatted(interp, "Can't initialise array element \"%#s\"", nameObjPtr);
+
                    }
+
                    Jim_DecrRefCount(interp, nameObjPtr);
+
                    return JIM_ERR;
+

+
                case JIM_OK:
+
                    if (byref) {
+
                        vv = nameObjPtr->internalRep.varValue.vv;
+
                    }
+
                    else {
+
                        initObjPtr = Jim_GetVariable(interp, nameObjPtr, JIM_NONE);
+
                    }
+
                    break;
+

+
                case JIM_ERR:
+

                    Jim_SetResultFormatted(interp,
                        "variable for initialization of static \"%#s\" not found in the local context",
                        nameObjPtr);
+
                    Jim_DecrRefCount(interp, nameObjPtr);
                    return JIM_ERR;
-
                }
-
            }
-
            else {
-
                initObjPtr = Jim_ListGetIndex(interp, objPtr, 1);
-
            }
-
            if (JimValidName(interp, "static variable", nameObjPtr) != JIM_OK) {
-
                return JIM_ERR;
-
            }
-

-
            varPtr = Jim_Alloc(sizeof(*varPtr));
-
            varPtr->objPtr = initObjPtr;
-
            Jim_IncrRefCount(initObjPtr);
-
            varPtr->linkFramePtr = NULL;
-
            if (Jim_AddHashEntry(cmdPtr->u.proc.staticVars,
-
                Jim_String(nameObjPtr), varPtr) != JIM_OK) {
-
                Jim_SetResultFormatted(interp,
-
                    "static variable name \"%#s\" duplicated in statics list", nameObjPtr);
-
                Jim_DecrRefCount(interp, initObjPtr);
-
                Jim_Free(varPtr);
-
                return JIM_ERR;
            }
        }
        else {
-
            Jim_SetResultFormatted(interp, "too many fields in static specifier \"%#s\"",
-
                objPtr);
+
            initObjPtr = Jim_ListGetIndex(interp, objPtr, 1);
+
        }
+

+
        if (vv == NULL) {
+
            vv = Jim_Alloc(sizeof(*vv));
+
            vv->objPtr = initObjPtr;
+
            Jim_IncrRefCount(vv->objPtr);
+
            vv->linkFramePtr = NULL;
+
            vv->refCount = 0;
+
        }
+

+
        if (JimSetNewVariable(cmdPtr->u.proc.staticVars, nameObjPtr, vv) != JIM_OK) {
+
            Jim_SetResultFormatted(interp,
+
                "static variable name \"%#s\" duplicated in statics list", nameObjPtr);
+
            JimIncrVarRef(vv);
+
            JimDecrVarRef(interp, vv);
+
            Jim_DecrRefCount(interp, nameObjPtr);
            return JIM_ERR;
        }
+

+
        Jim_DecrRefCount(interp, nameObjPtr);
    }
    return JIM_OK;
}

-
static void JimUpdateProcNamespace(Jim_Interp *interp, Jim_Cmd *cmdPtr, const char *cmdname)
+

+
#ifdef jim_ext_namespace
+
static const char *Jim_memrchr(const char *p, int c, int len)
+
{
+
    int i;
+
    for (i = len; i > 0; i--) {
+
        if (p[i] == c) {
+
            return p + i;
+
        }
+
    }
+
    return NULL;
+
}
+
#endif
+

+
static void JimUpdateProcNamespace(Jim_Interp *interp, Jim_Cmd *cmdPtr, Jim_Obj *nameObjPtr)
{
#ifdef jim_ext_namespace
    if (cmdPtr->isproc) {
+
        int len;
+
        const char *cmdname = Jim_GetStringNoQualifier(nameObjPtr, &len);

-
        const char *pt = strrchr(cmdname, ':');
+
        const char *pt = Jim_memrchr(cmdname, ':', len);
        if (pt && pt != cmdname && pt[-1] == ':') {
+
            pt++;
            Jim_DecrRefCount(interp, cmdPtr->u.proc.nsObj);
-
            cmdPtr->u.proc.nsObj = Jim_NewStringObj(interp, cmdname, pt - cmdname - 1);
+
            cmdPtr->u.proc.nsObj = Jim_NewStringObj(interp, cmdname, pt - cmdname - 2);
            Jim_IncrRefCount(cmdPtr->u.proc.nsObj);

-
            if (Jim_FindHashEntry(&interp->commands, pt + 1)) {
+
            Jim_Obj *tempObj = Jim_NewStringObj(interp, pt, len - (pt - cmdname));
+
            if (Jim_FindHashEntry(&interp->commands, tempObj)) {

                Jim_InterpIncrProcEpoch(interp);
            }
+
            Jim_FreeNewObj(interp, tempObj);
        }
    }
#endif
@@ -9512,6 +10356,7 @@ static Jim_Cmd *JimCreateProcedureCmd(Jim_Interp *interp, Jim_Obj *argListObjPtr


    cmdPtr = Jim_Alloc(sizeof(*cmdPtr) + sizeof(struct Jim_ProcArg) * argListLen);
+
    assert(cmdPtr);
    memset(cmdPtr, 0, sizeof(*cmdPtr));
    cmdPtr->inUse = 1;
    cmdPtr->isproc = 1;
@@ -9587,68 +10432,67 @@ err:
    return cmdPtr;
}

-
int Jim_DeleteCommand(Jim_Interp *interp, const char *name)
+
int Jim_DeleteCommand(Jim_Interp *interp, Jim_Obj *nameObj)
{
    int ret = JIM_OK;
-
    Jim_Obj *qualifiedNameObj;
-
    const char *qualname = JimQualifyName(interp, name, &qualifiedNameObj);

-
    if (Jim_DeleteHashEntry(&interp->commands, qualname) == JIM_ERR) {
-
        Jim_SetResultFormatted(interp, "can't delete \"%s\": command doesn't exist", name);
+
    nameObj = JimQualifyName(interp, nameObj);
+

+
    if (Jim_DeleteHashEntry(&interp->commands, nameObj) == JIM_ERR) {
+
        Jim_SetResultFormatted(interp, "can't delete \"%#s\": command doesn't exist", nameObj);
        ret = JIM_ERR;
    }
-
    else {
-
        Jim_InterpIncrProcEpoch(interp);
-
    }
-

-
    JimFreeQualifiedName(interp, qualifiedNameObj);
+
    Jim_DecrRefCount(interp, nameObj);

    return ret;
}

-
int Jim_RenameCommand(Jim_Interp *interp, const char *oldName, const char *newName)
+
int Jim_RenameCommand(Jim_Interp *interp, Jim_Obj *oldNameObj, Jim_Obj *newNameObj)
{
    int ret = JIM_ERR;
    Jim_HashEntry *he;
    Jim_Cmd *cmdPtr;
-
    Jim_Obj *qualifiedOldNameObj;
-
    Jim_Obj *qualifiedNewNameObj;
-
    const char *fqold;
-
    const char *fqnew;

-
    if (newName[0] == 0) {
-
        return Jim_DeleteCommand(interp, oldName);
+
    if (Jim_Length(newNameObj) == 0) {
+
        return Jim_DeleteCommand(interp, oldNameObj);
    }

-
    fqold = JimQualifyName(interp, oldName, &qualifiedOldNameObj);
-
    fqnew = JimQualifyName(interp, newName, &qualifiedNewNameObj);


-
    he = Jim_FindHashEntry(&interp->commands, fqold);
+
    oldNameObj = JimQualifyName(interp, oldNameObj);
+
    newNameObj = JimQualifyName(interp, newNameObj);
+

+

+
    he = Jim_FindHashEntry(&interp->commands, oldNameObj);
    if (he == NULL) {
-
        Jim_SetResultFormatted(interp, "can't rename \"%s\": command doesn't exist", oldName);
+
        Jim_SetResultFormatted(interp, "can't rename \"%#s\": command doesn't exist", oldNameObj);
    }
-
    else if (Jim_FindHashEntry(&interp->commands, fqnew)) {
-
        Jim_SetResultFormatted(interp, "can't rename to \"%s\": command already exists", newName);
+
    else if (Jim_FindHashEntry(&interp->commands, newNameObj)) {
+
        Jim_SetResultFormatted(interp, "can't rename to \"%#s\": command already exists", newNameObj);
    }
    else {
-

        cmdPtr = Jim_GetHashEntryVal(he);
-
        JimIncrCmdRefCount(cmdPtr);
-
        JimUpdateProcNamespace(interp, cmdPtr, fqnew);
-
        Jim_AddHashEntry(&interp->commands, fqnew, cmdPtr);
+
        if (cmdPtr->prevCmd) {
+
            Jim_SetResultFormatted(interp, "can't rename local command \"%#s\"", oldNameObj);
+
        }
+
        else {

+
            JimIncrCmdRefCount(cmdPtr);
+
            JimUpdateProcNamespace(interp, cmdPtr, newNameObj);
+
            Jim_AddHashEntry(&interp->commands, newNameObj, cmdPtr);

-
        Jim_DeleteHashEntry(&interp->commands, fqold);

+
            Jim_DeleteHashEntry(&interp->commands, oldNameObj);

-
        Jim_InterpIncrProcEpoch(interp);

-
        ret = JIM_OK;
+
            Jim_InterpIncrProcEpoch(interp);
+

+
            ret = JIM_OK;
+
        }
    }

-
    JimFreeQualifiedName(interp, qualifiedOldNameObj);
-
    JimFreeQualifiedName(interp, qualifiedNewNameObj);
+
    Jim_DecrRefCount(interp, oldNameObj);
+
    Jim_DecrRefCount(interp, newNameObj);

    return ret;
}
@@ -9678,48 +10522,34 @@ Jim_Cmd *Jim_GetCommand(Jim_Interp *interp, Jim_Obj *objPtr, int flags)
{
    Jim_Cmd *cmd;

-
    if (objPtr->typePtr != &commandObjType ||
-
            objPtr->internalRep.cmdValue.procEpoch != interp->procEpoch
+
    if (objPtr->typePtr == &commandObjType
+
        && objPtr->internalRep.cmdValue.procEpoch == interp->procEpoch
#ifdef jim_ext_namespace
-
            || !Jim_StringEqObj(objPtr->internalRep.cmdValue.nsObj, interp->framePtr->nsObj)
+
        && Jim_StringEqObj(objPtr->internalRep.cmdValue.nsObj, interp->framePtr->nsObj)
#endif
-
        ) {
-

-

+
        && objPtr->internalRep.cmdValue.cmdPtr->inUse) {

-
        const char *name = Jim_String(objPtr);
-
        Jim_HashEntry *he;
-

-
        if (name[0] == ':' && name[1] == ':') {
-
            while (*++name == ':') {
-
            }
-
        }
+
        cmd = objPtr->internalRep.cmdValue.cmdPtr;
+
    }
+
    else {
+
        Jim_Obj *qualifiedNameObj = JimQualifyName(interp, objPtr);
+
        Jim_HashEntry *he = Jim_FindHashEntry(&interp->commands, qualifiedNameObj);
#ifdef jim_ext_namespace
-
        else if (Jim_Length(interp->framePtr->nsObj)) {
-

-
            Jim_Obj *nameObj = Jim_DuplicateObj(interp, interp->framePtr->nsObj);
-
            Jim_AppendStrings(interp, nameObj, "::", name, NULL);
-
            he = Jim_FindHashEntry(&interp->commands, Jim_String(nameObj));
-
            Jim_FreeNewObj(interp, nameObj);
-
            if (he) {
-
                goto found;
-
            }
+
        if (he == NULL && Jim_Length(interp->framePtr->nsObj)) {
+
            he = Jim_FindHashEntry(&interp->commands, objPtr);
        }
#endif
-

-

-
        he = Jim_FindHashEntry(&interp->commands, name);
        if (he == NULL) {
            if (flags & JIM_ERRMSG) {
                Jim_SetResultFormatted(interp, "invalid command name \"%#s\"", objPtr);
            }
+
            Jim_DecrRefCount(interp, qualifiedNameObj);
            return NULL;
        }
-
#ifdef jim_ext_namespace
-
found:
-
#endif
        cmd = Jim_GetHashEntryVal(he);

+
        cmd->cmdNameObj = Jim_GetHashEntryKey(he);
+


        Jim_FreeIntRep(interp, objPtr);
        objPtr->typePtr = &commandObjType;
@@ -9727,9 +10557,7 @@ found:
        objPtr->internalRep.cmdValue.cmdPtr = cmd;
        objPtr->internalRep.cmdValue.nsObj = interp->framePtr->nsObj;
        Jim_IncrRefCount(interp->framePtr->nsObj);
-
    }
-
    else {
-
        cmd = objPtr->internalRep.cmdValue.cmdPtr;
+
        Jim_DecrRefCount(interp, qualifiedNameObj);
    }
    while (cmd->u.proc.upcall) {
        cmd = cmd->prevCmd;
@@ -9739,10 +10567,6 @@ found:



-
#define JIM_DICT_SUGAR 100
-

-
static int SetVariableFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr);
-

static const Jim_ObjType variableObjType = {
    "variable",
    NULL,
@@ -9751,27 +10575,13 @@ static const Jim_ObjType variableObjType = {
    JIM_TYPE_REFERENCES,
};

-
static int JimValidName(Jim_Interp *interp, const char *type, Jim_Obj *nameObjPtr)
-
{
-

-
    if (nameObjPtr->typePtr != &variableObjType) {
-
        int len;
-
        const char *str = Jim_GetString(nameObjPtr, &len);
-
        if (memchr(str, '\0', len)) {
-
            Jim_SetResultFormatted(interp, "%s name contains embedded null", type);
-
            return JIM_ERR;
-
        }
-
    }
-
    return JIM_OK;
-
}
-

static int SetVariableFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr)
{
    const char *varName;
    Jim_CallFrame *framePtr;
-
    Jim_HashEntry *he;
    int global;
    int len;
+
    Jim_VarVal *vv;


    if (objPtr->typePtr == &variableObjType) {
@@ -9785,10 +10595,6 @@ static int SetVariableFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr)
    else if (objPtr->typePtr == &dictSubstObjType) {
        return JIM_DICT_SUGAR;
    }
-
    else if (JimValidName(interp, "variable", objPtr) != JIM_OK) {
-
        return JIM_ERR;
-
    }
-


    varName = Jim_GetString(objPtr, &len);

@@ -9798,33 +10604,37 @@ static int SetVariableFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr)
    }

    if (varName[0] == ':' && varName[1] == ':') {
-
        while (*++varName == ':') {
+
        while (*varName == ':') {
+
            varName++;
+
            len--;
        }
        global = 1;
        framePtr = interp->topFramePtr;
+

+
        Jim_Obj *tempObj = Jim_NewStringObj(interp, varName, len);
+
        vv = JimFindVariable(&framePtr->vars, tempObj);
+
        Jim_FreeNewObj(interp, tempObj);
    }
    else {
        global = 0;
        framePtr = interp->framePtr;
-
    }

+
        vv = JimFindVariable(&framePtr->vars, objPtr);
+
        if (vv == NULL && framePtr->staticVars) {

-
    he = Jim_FindHashEntry(&framePtr->vars, varName);
-
    if (he == NULL) {
-
        if (!global && framePtr->staticVars) {
-

-
            he = Jim_FindHashEntry(framePtr->staticVars, varName);
-
        }
-
        if (he == NULL) {
-
            return JIM_ERR;
+
            vv = JimFindVariable(framePtr->staticVars, objPtr);
        }
    }

+
    if (vv == NULL) {
+
        return JIM_ERR;
+
    }
+


    Jim_FreeIntRep(interp, objPtr);
    objPtr->typePtr = &variableObjType;
    objPtr->internalRep.varValue.callFrameId = framePtr->id;
-
    objPtr->internalRep.varValue.varPtr = Jim_GetHashEntryVal(he);
+
    objPtr->internalRep.varValue.vv = vv;
    objPtr->internalRep.varValue.global = global;
    return JIM_OK;
}
@@ -9833,74 +10643,92 @@ static int SetVariableFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr)
static int JimDictSugarSet(Jim_Interp *interp, Jim_Obj *ObjPtr, Jim_Obj *valObjPtr);
static Jim_Obj *JimDictSugarGet(Jim_Interp *interp, Jim_Obj *ObjPtr, int flags);

-
static Jim_Var *JimCreateVariable(Jim_Interp *interp, Jim_Obj *nameObjPtr, Jim_Obj *valObjPtr)
+
static int JimSetNewVariable(Jim_HashTable *ht, Jim_Obj *nameObjPtr, Jim_VarVal *vv)
+
{
+
    return Jim_AddHashEntry(ht, nameObjPtr, vv);
+
}
+

+
static Jim_VarVal *JimFindVariable(Jim_HashTable *ht, Jim_Obj *nameObjPtr)
+
{
+
    Jim_HashEntry *he = Jim_FindHashEntry(ht, nameObjPtr);
+
    if (he) {
+
        return (Jim_VarVal *)Jim_GetHashEntryVal(he);
+
    }
+
    return NULL;
+
}
+

+
static int JimUnsetVariable(Jim_HashTable *ht, Jim_Obj *nameObjPtr)
+
{
+
    return Jim_DeleteHashEntry(ht, nameObjPtr);
+
}
+

+
static Jim_VarVal *JimCreateVariable(Jim_Interp *interp, Jim_Obj *nameObjPtr, Jim_Obj *valObjPtr)
{
    const char *name;
    Jim_CallFrame *framePtr;
    int global;
+
    int len;


-
    Jim_Var *var = Jim_Alloc(sizeof(*var));
+
    Jim_VarVal *vv = Jim_Alloc(sizeof(*vv));

-
    var->objPtr = valObjPtr;
+
    vv->objPtr = valObjPtr;
    Jim_IncrRefCount(valObjPtr);
-
    var->linkFramePtr = NULL;
+
    vv->linkFramePtr = NULL;
+
    vv->refCount = 0;

-
    name = Jim_String(nameObjPtr);
+
    name = Jim_GetString(nameObjPtr, &len);
    if (name[0] == ':' && name[1] == ':') {
-
        while (*++name == ':') {
+
        while (*name == ':') {
+
            name++;
+
            len--;
        }
        framePtr = interp->topFramePtr;
        global = 1;
+
        JimSetNewVariable(&framePtr->vars, Jim_NewStringObj(interp, name, len), vv);
    }
    else {
        framePtr = interp->framePtr;
        global = 0;
+
        JimSetNewVariable(&framePtr->vars, nameObjPtr, vv);
    }


-
    Jim_AddHashEntry(&framePtr->vars, name, var);
-

-

    Jim_FreeIntRep(interp, nameObjPtr);
    nameObjPtr->typePtr = &variableObjType;
    nameObjPtr->internalRep.varValue.callFrameId = framePtr->id;
-
    nameObjPtr->internalRep.varValue.varPtr = var;
+
    nameObjPtr->internalRep.varValue.vv = vv;
    nameObjPtr->internalRep.varValue.global = global;

-
    return var;
+
    return vv;
}

-

int Jim_SetVariable(Jim_Interp *interp, Jim_Obj *nameObjPtr, Jim_Obj *valObjPtr)
{
    int err;
-
    Jim_Var *var;
+
    Jim_VarVal *vv;

    switch (SetVariableFromAny(interp, nameObjPtr)) {
        case JIM_DICT_SUGAR:
            return JimDictSugarSet(interp, nameObjPtr, valObjPtr);

        case JIM_ERR:
-
            if (JimValidName(interp, "variable", nameObjPtr) != JIM_OK) {
-
                return JIM_ERR;
-
            }
            JimCreateVariable(interp, nameObjPtr, valObjPtr);
            break;

        case JIM_OK:
-
            var = nameObjPtr->internalRep.varValue.varPtr;
-
            if (var->linkFramePtr == NULL) {
+
            vv = nameObjPtr->internalRep.varValue.vv;
+
            if (vv->linkFramePtr == NULL) {
                Jim_IncrRefCount(valObjPtr);
-
                Jim_DecrRefCount(interp, var->objPtr);
-
                var->objPtr = valObjPtr;
+
                Jim_DecrRefCount(interp, vv->objPtr);
+
                vv->objPtr = valObjPtr;
            }
            else {
                Jim_CallFrame *savedCallFrame;

                savedCallFrame = interp->framePtr;
-
                interp->framePtr = var->linkFramePtr;
-
                err = Jim_SetVariable(interp, var->objPtr, valObjPtr);
+
                interp->framePtr = vv->linkFramePtr;
+
                err = Jim_SetVariable(interp, vv->objPtr, valObjPtr);
                interp->framePtr = savedCallFrame;
                if (err != JIM_OK)
                    return err;
@@ -9951,7 +10779,9 @@ int Jim_SetVariableLink(Jim_Interp *interp, Jim_Obj *nameObjPtr,
    const char *varName;
    const char *targetName;
    Jim_CallFrame *framePtr;
-
    Jim_Var *varPtr;
+
    Jim_VarVal *vv;
+
    int len;
+
    int varnamelen;


    switch (SetVariableFromAny(interp, nameObjPtr)) {
@@ -9961,24 +10791,26 @@ int Jim_SetVariableLink(Jim_Interp *interp, Jim_Obj *nameObjPtr,
            return JIM_ERR;

        case JIM_OK:
-
            varPtr = nameObjPtr->internalRep.varValue.varPtr;
+
            vv = nameObjPtr->internalRep.varValue.vv;

-
            if (varPtr->linkFramePtr == NULL) {
+
            if (vv->linkFramePtr == NULL) {
                Jim_SetResultFormatted(interp, "variable \"%#s\" already exists", nameObjPtr);
                return JIM_ERR;
            }


-
            varPtr->linkFramePtr = NULL;
+
            vv->linkFramePtr = NULL;
            break;
    }



-
    varName = Jim_String(nameObjPtr);
+
    varName = Jim_GetString(nameObjPtr, &varnamelen);

    if (varName[0] == ':' && varName[1] == ':') {
-
        while (*++varName == ':') {
+
        while (*varName == ':') {
+
            varName++;
+
            varnamelen--;
        }

        framePtr = interp->topFramePtr;
@@ -9987,11 +10819,13 @@ int Jim_SetVariableLink(Jim_Interp *interp, Jim_Obj *nameObjPtr,
        framePtr = interp->framePtr;
    }

-
    targetName = Jim_String(targetNameObjPtr);
+
    targetName = Jim_GetString(targetNameObjPtr, &len);
    if (targetName[0] == ':' && targetName[1] == ':') {
-
        while (*++targetName == ':') {
+
        while (*targetName == ':') {
+
            targetName++;
+
            len--;
        }
-
        targetNameObjPtr = Jim_NewStringObj(interp, targetName, -1);
+
        targetNameObjPtr = Jim_NewStringObj(interp, targetName, len);
        targetCallFrame = interp->topFramePtr;
    }
    Jim_IncrRefCount(targetNameObjPtr);
@@ -10010,36 +10844,39 @@ int Jim_SetVariableLink(Jim_Interp *interp, Jim_Obj *nameObjPtr,


        while (1) {
-
            if (strcmp(Jim_String(objPtr), varName) == 0) {
+
            if (Jim_Length(objPtr) == varnamelen && memcmp(Jim_String(objPtr), varName, varnamelen) == 0) {
                Jim_SetResultString(interp, "can't upvar from variable to itself", -1);
                Jim_DecrRefCount(interp, targetNameObjPtr);
                return JIM_ERR;
            }
            if (SetVariableFromAny(interp, objPtr) != JIM_OK)
                break;
-
            varPtr = objPtr->internalRep.varValue.varPtr;
-
            if (varPtr->linkFramePtr != targetCallFrame)
+
            vv = objPtr->internalRep.varValue.vv;
+
            if (vv->linkFramePtr != targetCallFrame)
                break;
-
            objPtr = varPtr->objPtr;
+
            objPtr = vv->objPtr;
        }
    }


    Jim_SetVariable(interp, nameObjPtr, targetNameObjPtr);

-
    nameObjPtr->internalRep.varValue.varPtr->linkFramePtr = targetCallFrame;
+
    nameObjPtr->internalRep.varValue.vv->linkFramePtr = targetCallFrame;
    Jim_DecrRefCount(interp, targetNameObjPtr);
    return JIM_OK;
}

Jim_Obj *Jim_GetVariable(Jim_Interp *interp, Jim_Obj *nameObjPtr, int flags)
{
+
    if (interp->safeexpr) {
+
        return nameObjPtr;
+
    }
    switch (SetVariableFromAny(interp, nameObjPtr)) {
        case JIM_OK:{
-
                Jim_Var *varPtr = nameObjPtr->internalRep.varValue.varPtr;
+
                Jim_VarVal *vv = nameObjPtr->internalRep.varValue.vv;

-
                if (varPtr->linkFramePtr == NULL) {
-
                    return varPtr->objPtr;
+
                if (vv->linkFramePtr == NULL) {
+
                    return vv->objPtr;
                }
                else {
                    Jim_Obj *objPtr;
@@ -10047,8 +10884,8 @@ Jim_Obj *Jim_GetVariable(Jim_Interp *interp, Jim_Obj *nameObjPtr, int flags)

                    Jim_CallFrame *savedCallFrame = interp->framePtr;

-
                    interp->framePtr = varPtr->linkFramePtr;
-
                    objPtr = Jim_GetVariable(interp, varPtr->objPtr, flags);
+
                    interp->framePtr = vv->linkFramePtr;
+
                    objPtr = Jim_GetVariable(interp, vv->objPtr, flags);
                    interp->framePtr = savedCallFrame;
                    if (objPtr) {
                        return objPtr;
@@ -10107,7 +10944,7 @@ Jim_Obj *Jim_GetGlobalVariableStr(Jim_Interp *interp, const char *name, int flag

int Jim_UnsetVariable(Jim_Interp *interp, Jim_Obj *nameObjPtr, int flags)
{
-
    Jim_Var *varPtr;
+
    Jim_VarVal *vv;
    int retval;
    Jim_CallFrame *framePtr;

@@ -10117,26 +10954,33 @@ int Jim_UnsetVariable(Jim_Interp *interp, Jim_Obj *nameObjPtr, int flags)
        return JimDictSugarSet(interp, nameObjPtr, NULL);
    }
    else if (retval == JIM_OK) {
-
        varPtr = nameObjPtr->internalRep.varValue.varPtr;
+
        vv = nameObjPtr->internalRep.varValue.vv;


-
        if (varPtr->linkFramePtr) {
+
        if (vv->linkFramePtr) {
            framePtr = interp->framePtr;
-
            interp->framePtr = varPtr->linkFramePtr;
-
            retval = Jim_UnsetVariable(interp, varPtr->objPtr, JIM_NONE);
+
            interp->framePtr = vv->linkFramePtr;
+
            retval = Jim_UnsetVariable(interp, vv->objPtr, JIM_NONE);
            interp->framePtr = framePtr;
        }
        else {
-
            const char *name = Jim_String(nameObjPtr);
            if (nameObjPtr->internalRep.varValue.global) {
-
                name += 2;
+
                int len;
+
                const char *name = Jim_GetString(nameObjPtr, &len);
+
                while (*name == ':') {
+
                    name++;
+
                    len--;
+
                }
                framePtr = interp->topFramePtr;
+
                Jim_Obj *tempObj = Jim_NewStringObj(interp, name, len);
+
                retval = JimUnsetVariable(&framePtr->vars, tempObj);
+
                Jim_FreeNewObj(interp, tempObj);
            }
            else {
                framePtr = interp->framePtr;
+
                retval = JimUnsetVariable(&framePtr->vars, nameObjPtr);
            }

-
            retval = Jim_DeleteHashEntry(&framePtr->vars, name);
            if (retval == JIM_OK) {

                framePtr->id = interp->callFrameEpoch++;
@@ -10293,6 +11137,10 @@ static Jim_Obj *JimExpandDictSugar(Jim_Interp *interp, Jim_Obj *objPtr)
    Jim_Obj *resObjPtr = NULL;
    Jim_Obj *substKeyObjPtr = NULL;

+
    if (interp->safeexpr) {
+
        return objPtr;
+
    }
+

    SetDictSubstFromAny(interp, objPtr);

    if (Jim_SubstObj(interp, objPtr->internalRep.dictSubstValue.indexObjPtr,
@@ -10309,14 +11157,6 @@ static Jim_Obj *JimExpandDictSugar(Jim_Interp *interp, Jim_Obj *objPtr)
    return resObjPtr;
}

-
static Jim_Obj *JimExpandExprSugar(Jim_Interp *interp, Jim_Obj *objPtr)
-
{
-
    if (Jim_EvalExpression(interp, objPtr) == JIM_OK) {
-
        return Jim_GetResult(interp);
-
    }
-
    return NULL;
-
}
-


static Jim_CallFrame *JimCreateCallFrame(Jim_Interp *interp, Jim_CallFrame *parent, Jim_Obj *nsObj)
{
@@ -10359,14 +11199,8 @@ static int JimDeleteLocalProcs(Jim_Interp *interp, Jim_Stack *localCommands)
        Jim_Obj *cmdNameObj;

        while ((cmdNameObj = Jim_StackPop(localCommands)) != NULL) {
-
            Jim_HashEntry *he;
-
            Jim_Obj *fqObjName;
            Jim_HashTable *ht = &interp->commands;
-

-
            const char *fqname = JimQualifyName(interp, Jim_String(cmdNameObj), &fqObjName);
-

-
            he = Jim_FindHashEntry(ht, fqname);
-

+
            Jim_HashEntry *he = Jim_FindHashEntry(ht, cmdNameObj);
            if (he) {
                Jim_Cmd *cmd = Jim_GetHashEntryVal(he);
                if (cmd->prevCmd) {
@@ -10380,12 +11214,10 @@ static int JimDeleteLocalProcs(Jim_Interp *interp, Jim_Stack *localCommands)
                    Jim_SetHashVal(ht, he, prevCmd);
                }
                else {
-
                    Jim_DeleteHashEntry(ht, fqname);
+
                    Jim_DeleteHashEntry(ht, cmdNameObj);
                }
-
                Jim_InterpIncrProcEpoch(interp);
            }
            Jim_DecrRefCount(interp, cmdNameObj);
-
            JimFreeQualifiedName(interp, fqObjName);
        }
        Jim_FreeStack(localCommands);
        Jim_Free(localCommands);
@@ -10398,11 +11230,10 @@ static int JimInvokeDefer(Jim_Interp *interp, int retcode)
    Jim_Obj *objPtr;


-
    if (Jim_FindHashEntry(&interp->framePtr->vars, "jim::defer") == NULL) {
+
    if (JimFindVariable(&interp->framePtr->vars, interp->defer) == NULL) {
        return retcode;
    }
-

-
    objPtr = Jim_GetVariableStr(interp, "jim::defer", JIM_NONE);
+
    objPtr = Jim_GetVariable(interp, interp->defer, JIM_NONE);

    if (objPtr) {
        int ret = JIM_OK;
@@ -10454,24 +11285,7 @@ static void JimFreeCallFrame(Jim_Interp *interp, Jim_CallFrame *cf, int action)
    if (action == JIM_FCF_FULL || cf->vars.size != JIM_HT_INITIAL_SIZE)
        Jim_FreeHashTable(&cf->vars);
    else {
-
        int i;
-
        Jim_HashEntry **table = cf->vars.table, *he;
-

-
        for (i = 0; i < JIM_HT_INITIAL_SIZE; i++) {
-
            he = table[i];
-
            while (he != NULL) {
-
                Jim_HashEntry *nextEntry = he->next;
-
                Jim_Var *varPtr = Jim_GetHashEntryVal(he);
-

-
                Jim_DecrRefCount(interp, varPtr->objPtr);
-
                Jim_Free(Jim_GetHashEntryKey(he));
-
                Jim_Free(varPtr);
-
                Jim_Free(he);
-
                table[i] = NULL;
-
                he = nextEntry;
-
            }
-
        }
-
        cf->vars.used = 0;
+
        Jim_ClearHashTable(&cf->vars);
    }
    cf->next = interp->freeFramesList;
    interp->freeFramesList = cf;
@@ -10498,7 +11312,7 @@ Jim_Interp *Jim_CreateInterp(void)

    i->maxCallFrameDepth = JIM_MAX_CALLFRAME_DEPTH;
    i->maxEvalDepth = JIM_MAX_EVAL_DEPTH;
-
    i->lastCollectTime = time(NULL);
+
    i->lastCollectTime = Jim_GetTimeUsec(CLOCK_MONOTONIC_RAW);

    Jim_InitHashTable(&i->commands, &JimCommandsHashTableType, i);
#ifdef JIM_REFERENCES
@@ -10510,23 +11324,24 @@ Jim_Interp *Jim_CreateInterp(void)
    i->trueObj = Jim_NewIntObj(i, 1);
    i->falseObj = Jim_NewIntObj(i, 0);
    i->framePtr = i->topFramePtr = JimCreateCallFrame(i, NULL, i->emptyObj);
-
    i->errorFileNameObj = i->emptyObj;
    i->result = i->emptyObj;
    i->stackTrace = Jim_NewListObj(i, NULL, 0);
    i->unknown = Jim_NewStringObj(i, "unknown", -1);
+
    i->defer = Jim_NewStringObj(i, "jim::defer", -1);
    i->errorProc = i->emptyObj;
-
    i->currentScriptObj = Jim_NewEmptyStringObj(i);
    i->nullScriptObj = Jim_NewEmptyStringObj(i);
+
    i->evalFrame = &i->topEvalFrame;
+
    i->currentFilenameObj = 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->defer);
    Jim_IncrRefCount(i->nullScriptObj);
    Jim_IncrRefCount(i->errorProc);
    Jim_IncrRefCount(i->trueObj);
    Jim_IncrRefCount(i->falseObj);
+
    Jim_IncrRefCount(i->currentFilenameObj);


    Jim_SetVariableStrWithStr(i, JIM_LIBPATH, TCL_LIBRARY);
@@ -10538,8 +11353,10 @@ Jim_Interp *Jim_CreateInterp(void)
    Jim_SetVariableStrWithStr(i, "tcl_platform(pathSeparator)", TCL_PLATFORM_PATH_SEPARATOR);
    Jim_SetVariableStrWithStr(i, "tcl_platform(byteOrder)", Jim_IsBigEndian() ? "bigEndian" : "littleEndian");
    Jim_SetVariableStrWithStr(i, "tcl_platform(threaded)", "0");
+
    Jim_SetVariableStrWithStr(i, "tcl_platform(bootstrap)", "0");
    Jim_SetVariableStr(i, "tcl_platform(pointerSize)", Jim_NewIntObj(i, sizeof(void *)));
    Jim_SetVariableStr(i, "tcl_platform(wordSize)", Jim_NewIntObj(i, sizeof(jim_wide)));
+
    Jim_SetVariableStr(i, "tcl_platform(stackFormat)", Jim_NewIntObj(i, 4));

    return i;
}
@@ -10550,6 +11367,8 @@ void Jim_FreeInterp(Jim_Interp *i)

    Jim_Obj *objPtr, *nextObjPtr;

+
    i->quitting = 1;
+


    for (cf = i->framePtr; cf; cf = cfx) {

@@ -10565,9 +11384,13 @@ void Jim_FreeInterp(Jim_Interp *i)
    Jim_DecrRefCount(i, i->stackTrace);
    Jim_DecrRefCount(i, i->errorProc);
    Jim_DecrRefCount(i, i->unknown);
-
    Jim_DecrRefCount(i, i->errorFileNameObj);
-
    Jim_DecrRefCount(i, i->currentScriptObj);
+
    Jim_DecrRefCount(i, i->defer);
    Jim_DecrRefCount(i, i->nullScriptObj);
+
    Jim_DecrRefCount(i, i->currentFilenameObj);
+

+

+
    Jim_InterpIncrProcEpoch(i);
+

    Jim_FreeHashTable(&i->commands);
#ifdef JIM_REFERENCES
    Jim_FreeHashTable(&i->references);
@@ -10575,6 +11398,9 @@ void Jim_FreeInterp(Jim_Interp *i)
    Jim_FreeHashTable(&i->packages);
    Jim_Free(i->prngState);
    Jim_FreeHashTable(&i->assocData);
+
    if (i->traceCmdObj) {
+
        Jim_DecrRefCount(i, i->traceCmdObj);
+
    }

#ifdef JIM_MAINTAINER
    if (i->liveList != NULL) {
@@ -10673,21 +11499,20 @@ Jim_CallFrame *Jim_GetCallFrameByLevel(Jim_Interp *interp, Jim_Obj *levelObjPtr)
    return NULL;
}

-
static Jim_CallFrame *JimGetCallFrameByInteger(Jim_Interp *interp, Jim_Obj *levelObjPtr)
+
static Jim_CallFrame *JimGetCallFrameByInteger(Jim_Interp *interp, long level)
{
-
    long level;
    Jim_CallFrame *framePtr;

-
    if (Jim_GetLong(interp, levelObjPtr, &level) == JIM_OK) {
-
        if (level <= 0) {
+
    if (level == 0) {
+
        return interp->framePtr;
+
    }

-
            level = interp->framePtr->level + level;
-
        }
+
    if (level < 0) {

-
        if (level == 0) {
-
            return interp->topFramePtr;
-
        }
+
        level = interp->framePtr->level + level;
+
    }

+
    if (level > 0) {

        for (framePtr = interp->framePtr; framePtr; framePtr = framePtr->parent) {
            if (framePtr->level == level) {
@@ -10695,76 +11520,90 @@ static Jim_CallFrame *JimGetCallFrameByInteger(Jim_Interp *interp, Jim_Obj *leve
            }
        }
    }
-

-
    Jim_SetResultFormatted(interp, "bad level \"%#s\"", levelObjPtr);
    return NULL;
}

-
static void JimResetStackTrace(Jim_Interp *interp)
+
static Jim_EvalFrame *JimGetEvalFrameByProcLevel(Jim_Interp *interp, int proclevel)
{
-
    Jim_DecrRefCount(interp, interp->stackTrace);
-
    interp->stackTrace = Jim_NewListObj(interp, NULL, 0);
-
    Jim_IncrRefCount(interp->stackTrace);
-
}
+
    Jim_EvalFrame *evalFrame;

-
static void JimSetStackTrace(Jim_Interp *interp, Jim_Obj *stackTraceObj)
-
{
-
    int len;
+
    if (proclevel == 0) {
+
        return interp->evalFrame;
+
    }

+
    if (proclevel < 0) {

-
    Jim_IncrRefCount(stackTraceObj);
-
    Jim_DecrRefCount(interp, interp->stackTrace);
-
    interp->stackTrace = stackTraceObj;
-
    interp->errorFlag = 1;
+
        proclevel = interp->procLevel + proclevel;
+
    }

-
    len = Jim_ListLength(interp, interp->stackTrace);
-
    if (len >= 3) {
-
        if (Jim_Length(Jim_ListGetIndex(interp, interp->stackTrace, len - 2)) == 0) {
-
            interp->addStackTrace = 1;
+
    if (proclevel >= 0) {
+

+
        for (evalFrame = interp->evalFrame; evalFrame; evalFrame = evalFrame->parent) {
+
            if (evalFrame->procLevel == proclevel) {
+
                return evalFrame;
+
            }
        }
    }
+
    return NULL;
}

-
static void JimAppendStackTrace(Jim_Interp *interp, const char *procname,
-
    Jim_Obj *fileNameObj, int linenr)
+
static Jim_Obj *JimProcForEvalFrame(Jim_Interp *interp, Jim_EvalFrame *frame)
{
-
    if (strcmp(procname, "unknown") == 0) {
-
        procname = "";
+
    if (frame == interp->evalFrame || (frame->cmd && frame->cmd->cmdNameObj)) {
+
        Jim_EvalFrame *e;
+
        for (e = frame->parent; e; e = e->parent) {
+
            if (e->cmd && e->cmd->isproc && e->cmd->cmdNameObj) {
+
                break;
+
            }
+
        }
+
        if (e && e->cmd && e->cmd->cmdNameObj) {
+
            return e->cmd->cmdNameObj;
+
        }
    }
-
    if (!*procname && !Jim_Length(fileNameObj)) {
+
    return NULL;
+
}

-
        return;
-
    }
+
static void JimAddStackFrame(Jim_Interp *interp, Jim_EvalFrame *frame, Jim_Obj *listObj)
+
{
+
    Jim_Obj *procNameObj = JimProcForEvalFrame(interp, frame);
+
    Jim_Obj *fileNameObj = interp->emptyObj;
+
    int linenr = 1;

-
    if (Jim_IsShared(interp->stackTrace)) {
-
        Jim_DecrRefCount(interp, interp->stackTrace);
-
        interp->stackTrace = Jim_DuplicateObj(interp, interp->stackTrace);
-
        Jim_IncrRefCount(interp->stackTrace);
+
    if (frame->scriptObj) {
+
        ScriptObj *script = JimGetScript(interp, frame->scriptObj);
+
        fileNameObj = script->fileNameObj;
+
        linenr = script->linenr;
    }

+
    Jim_ListAppendElement(interp, listObj, procNameObj ? procNameObj : interp->emptyObj);
+
    Jim_ListAppendElement(interp, listObj, fileNameObj);
+
    Jim_ListAppendElement(interp, listObj, Jim_NewIntObj(interp, linenr));
+
    Jim_ListAppendElement(interp, listObj, Jim_NewListObj(interp, frame->argv, frame->argc));
+
}

-
    if (!*procname && Jim_Length(fileNameObj)) {
-

-
        int len = Jim_ListLength(interp, interp->stackTrace);
+
static void JimSetStackTrace(Jim_Interp *interp, Jim_Obj *stackTraceObj)
+
{

-
        if (len >= 3) {
-
            Jim_Obj *objPtr = Jim_ListGetIndex(interp, interp->stackTrace, len - 3);
-
            if (Jim_Length(objPtr)) {
+
    Jim_IncrRefCount(stackTraceObj);
+
    Jim_DecrRefCount(interp, interp->stackTrace);
+
    interp->stackTrace = stackTraceObj;
+
    interp->errorFlag = 1;
+
}

-
                objPtr = Jim_ListGetIndex(interp, interp->stackTrace, len - 2);
-
                if (Jim_Length(objPtr) == 0) {
+
static void JimSetErrorStack(Jim_Interp *interp)
+
{
+
    if (!interp->errorFlag) {
+
        int i;
+
        Jim_Obj *stackTrace = Jim_NewListObj(interp, NULL, 0);

-
                    ListSetIndex(interp, interp->stackTrace, len - 2, fileNameObj, 0);
-
                    ListSetIndex(interp, interp->stackTrace, len - 1, Jim_NewIntObj(interp, linenr), 0);
-
                    return;
-
                }
+
        for (i = 0; i <= interp->procLevel; i++) {
+
            Jim_EvalFrame *frame = JimGetEvalFrameByProcLevel(interp, -i);
+
            if (frame) {
+
                JimAddStackFrame(interp, frame, stackTrace);
            }
        }
+
        JimSetStackTrace(interp, stackTrace);
    }
-

-
    Jim_ListAppendElement(interp, interp->stackTrace, Jim_NewStringObj(interp, procname, -1));
-
    Jim_ListAppendElement(interp, interp->stackTrace, fileNameObj);
-
    Jim_ListAppendElement(interp, interp->stackTrace, Jim_NewIntObj(interp, linenr));
}

int Jim_SetAssocData(Jim_Interp *interp, const char *key, Jim_InterpDeleteProc * delProc,
@@ -10899,6 +11738,32 @@ int Jim_GetWide(Jim_Interp *interp, Jim_Obj *objPtr, jim_wide * widePtr)
    return JIM_OK;
}

+
int Jim_GetWideExpr(Jim_Interp *interp, Jim_Obj *objPtr, jim_wide * widePtr)
+
{
+
    int ret = JIM_OK;
+

+
    if (objPtr->typePtr == &sourceObjType || objPtr->typePtr == NULL) {
+
        SetIntFromAny(interp, objPtr, 0);
+
    }
+
    if (objPtr->typePtr == &intObjType) {
+
        *widePtr = JimWideValue(objPtr);
+
    }
+
    else {
+
        JimPanic((interp->safeexpr, "interp->safeexpr is set"));
+
        interp->safeexpr++;
+
        ret = Jim_EvalExpression(interp, objPtr);
+
        interp->safeexpr--;
+

+
        if (ret == JIM_OK) {
+
            ret = Jim_GetWide(interp, Jim_GetResult(interp), widePtr);
+
        }
+
        if (ret != JIM_OK) {
+
            Jim_SetResultFormatted(interp, "expected integer expression but got \"%#s\"", objPtr);
+
        }
+
    }
+
    return ret;
+
}
+


static int JimGetWideNoErr(Jim_Interp *interp, Jim_Obj *objPtr, jim_wide * widePtr)
{
@@ -10945,11 +11810,11 @@ static const Jim_ObjType doubleObjType = {
    JIM_TYPE_NONE,
};

-
#ifndef HAVE_ISNAN
+
#if !HAVE_DECL_ISNAN
#undef isnan
#define isnan(X) ((X) != (X))
#endif
-
#ifndef HAVE_ISINF
+
#if !HAVE_DECL_ISINF
#undef isinf
#define isinf(X) (1.0 / (X) == 0.0)
#endif
@@ -11081,23 +11946,21 @@ int Jim_GetBoolean(Jim_Interp *interp, Jim_Obj *objPtr, int * booleanPtr)
    return JIM_OK;
}

-
static int SetBooleanFromAny(Jim_Interp *interp, Jim_Obj *objPtr, int flags)
-
{
-
    static const char * const falses[] = {
-
        "0", "false", "no", "off", NULL
-
    };
-
    static const char * const trues[] = {
-
        "1", "true", "yes", "on", NULL
-
    };
+
static const char * const jim_true_false_strings[8] = {
+
    "1", "true", "yes", "on",
+
    "0", "false", "no", "off"
+
};

-
    int boolean;
+
static const int jim_true_false_lens[8] = {
+
    1, 4, 3, 2,
+
    1, 5, 2, 3,
+
};

-
    int index;
-
    if (Jim_GetEnum(interp, objPtr, falses, &index, NULL, 0) == JIM_OK) {
-
        boolean = 0;
-
    } else if (Jim_GetEnum(interp, objPtr, trues, &index, NULL, 0) == JIM_OK) {
-
        boolean = 1;
-
    } else {
+
static int SetBooleanFromAny(Jim_Interp *interp, Jim_Obj *objPtr, int flags)
+
{
+
    int index = Jim_FindByName(Jim_String(objPtr), jim_true_false_strings,
+
        sizeof(jim_true_false_strings) / sizeof(*jim_true_false_strings));
+
    if (index < 0) {
        if (flags & JIM_ERRMSG) {
            Jim_SetResultFormatted(interp, "expected boolean but got \"%#s\"", objPtr);
        }
@@ -11107,7 +11970,8 @@ static int SetBooleanFromAny(Jim_Interp *interp, Jim_Obj *objPtr, int flags)

    Jim_FreeIntRep(interp, objPtr);
    objPtr->typePtr = &intObjType;
-
    objPtr->internalRep.wideValue = boolean;
+

+
    objPtr->internalRep.wideValue = index < 4 ? 1 : 0;
    return JIM_OK;
}

@@ -11407,23 +12271,21 @@ static int SetListFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr)
        return JIM_OK;
    }

-
    if (Jim_IsDict(objPtr) && objPtr->bytes == NULL) {
-
        Jim_Obj **listObjPtrPtr;
-
        int len;
-
        int i;

-
        listObjPtrPtr = JimDictPairs(objPtr, &len);
-
        for (i = 0; i < len; i++) {
-
            Jim_IncrRefCount(listObjPtrPtr[i]);
-
        }
+
    if (Jim_IsDict(objPtr) && objPtr->bytes == NULL) {
+
        Jim_Dict *dict = objPtr->internalRep.dictValue;


-
        Jim_FreeIntRep(interp, objPtr);
        objPtr->typePtr = &listObjType;
-
        objPtr->internalRep.listValue.len = len;
-
        objPtr->internalRep.listValue.maxLen = len;
-
        objPtr->internalRep.listValue.ele = listObjPtrPtr;
+
        objPtr->internalRep.listValue.len = dict->len;
+
        objPtr->internalRep.listValue.maxLen = dict->maxLen;
+
        objPtr->internalRep.listValue.ele = dict->table;
+

+

+
        Jim_Free(dict->ht);

+

+
        Jim_Free(dict);
        return JIM_OK;
    }

@@ -11515,8 +12377,8 @@ struct lsort_info {
        JIM_LSORT_COMMAND
    } type;
    int order;
-
    int index;
-
    int indexed;
+
    Jim_Obj **indexv;
+
    int indexc;
    int unique;
    int (*subfn)(Jim_Obj **, Jim_Obj **);
};
@@ -11527,8 +12389,8 @@ static int ListSortIndexHelper(Jim_Obj **lhsObj, Jim_Obj **rhsObj)
{
    Jim_Obj *lObj, *rObj;

-
    if (Jim_ListIndex(sort_info->interp, *lhsObj, sort_info->index, &lObj, JIM_ERRMSG) != JIM_OK ||
-
        Jim_ListIndex(sort_info->interp, *rhsObj, sort_info->index, &rObj, JIM_ERRMSG) != JIM_OK) {
+
    if (Jim_ListIndices(sort_info->interp, *lhsObj, sort_info->indexv, sort_info->indexc, &lObj, JIM_ERRMSG) != JIM_OK ||
+
        Jim_ListIndices(sort_info->interp, *rhsObj, sort_info->indexv, sort_info->indexc, &rObj, JIM_ERRMSG) != JIM_OK) {
        longjmp(sort_info->jmpbuf, JIM_ERR);
    }
    return sort_info->subfn(&lObj, &rObj);
@@ -11665,7 +12527,7 @@ static int ListSortElements(Jim_Interp *interp, Jim_Obj *listObjPtr, struct lsor
            return -1;
    }

-
    if (info->indexed) {
+
    if (info->indexc) {

        info->subfn = fn;
        fn = ListSortIndexHelper;
@@ -11685,6 +12547,22 @@ static int ListSortElements(Jim_Interp *interp, Jim_Obj *listObjPtr, struct lsor
    return rc;
}

+

+
static void ListEnsureLength(Jim_Obj *listPtr, int idx)
+
{
+
    assert(idx >= 0);
+
    if (idx >= listPtr->internalRep.listValue.maxLen) {
+
        if (idx < 4) {
+

+
            idx = 4;
+
        }
+
        listPtr->internalRep.listValue.ele = Jim_Realloc(listPtr->internalRep.listValue.ele,
+
            sizeof(Jim_Obj *) * idx);
+

+
        listPtr->internalRep.listValue.maxLen = idx;
+
    }
+
}
+

static void ListInsertElements(Jim_Obj *listPtr, int idx, int elemc, Jim_Obj *const *elemVec)
{
    int currentLen = listPtr->internalRep.listValue.len;
@@ -11693,18 +12571,11 @@ static void ListInsertElements(Jim_Obj *listPtr, int idx, int elemc, Jim_Obj *co
    Jim_Obj **point;

    if (requiredLen > listPtr->internalRep.listValue.maxLen) {
-
        if (requiredLen < 2) {
+
        if (currentLen) {

-
            requiredLen = 4;
-
        }
-
        else {
            requiredLen *= 2;
        }
-

-
        listPtr->internalRep.listValue.ele = Jim_Realloc(listPtr->internalRep.listValue.ele,
-
            sizeof(Jim_Obj *) * requiredLen);
-

-
        listPtr->internalRep.listValue.maxLen = requiredLen;
+
        ListEnsureLength(listPtr, requiredLen);
    }
    if (idx < 0) {
        idx = currentLen;
@@ -11789,6 +12660,47 @@ int Jim_ListIndex(Jim_Interp *interp, Jim_Obj *listPtr, int idx, Jim_Obj **objPt
    return JIM_OK;
}

+
static int Jim_ListIndices(Jim_Interp *interp, Jim_Obj *listPtr,
+
    Jim_Obj *const *indexv, int indexc, Jim_Obj **resultObj, int flags)
+
{
+
    int i;
+
    int static_idxes[5];
+
    int *idxes = static_idxes;
+
    int ret = JIM_OK;
+

+
    if (indexc > sizeof(static_idxes) / sizeof(*static_idxes)) {
+
        idxes = Jim_Alloc(indexc * sizeof(*idxes));
+
    }
+

+
    for (i = 0; i < indexc; i++) {
+
        ret = Jim_GetIndex(interp, indexv[i], &idxes[i]);
+
        if (ret != JIM_OK) {
+
            goto err;
+
        }
+
    }
+

+
    for (i = 0; i < indexc; i++) {
+
        Jim_Obj *objPtr = Jim_ListGetIndex(interp, listPtr, idxes[i]);
+
        if (!objPtr) {
+
            if (flags & JIM_ERRMSG) {
+
                if (idxes[i] < 0 || idxes[i] > Jim_ListLength(interp, listPtr)) {
+
                    Jim_SetResultFormatted(interp, "index \"%#s\" out of range", indexv[i]);
+
                }
+
                else {
+
                    Jim_SetResultFormatted(interp, "element %#s missing from sublist \"%#s\"", indexv[i], listPtr);
+
                }
+
            }
+
            return -1;
+
        }
+
        listPtr = objPtr;
+
    }
+
    *resultObj = listPtr;
+
err:
+
    if (idxes != static_idxes)
+
        Jim_Free(idxes);
+
    return ret;
+
}
+

static int ListSetIndex(Jim_Interp *interp, Jim_Obj *listPtr, int idx,
    Jim_Obj *newObjPtr, int flags)
{
@@ -11823,7 +12735,10 @@ int Jim_ListSetIndex(Jim_Interp *interp, Jim_Obj *varNamePtr,
        listObjPtr = objPtr;
        if (Jim_GetIndex(interp, indexv[i], &idx) != JIM_OK)
            goto err;
-
        if (Jim_ListIndex(interp, listObjPtr, idx, &objPtr, JIM_ERRMSG) != JIM_OK) {
+

+
        objPtr = Jim_ListGetIndex(interp, listObjPtr, idx);
+
        if (objPtr == NULL) {
+
            Jim_SetResultFormatted(interp, "index \"%#s\" out of range", indexv[i]);
            goto err;
        }
        if (Jim_IsShared(objPtr)) {
@@ -11950,38 +12865,6 @@ static void UpdateStringOfDict(struct Jim_Obj *objPtr);
static int SetDictFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr);


-
static unsigned int JimObjectHTHashFunction(const void *key)
-
{
-
    int len;
-
    const char *str = Jim_GetString((Jim_Obj *)key, &len);
-
    return Jim_GenHashFunction((const unsigned char *)str, len);
-
}
-

-
static int JimObjectHTKeyCompare(void *privdata, const void *key1, const void *key2)
-
{
-
    return Jim_StringEqObj((Jim_Obj *)key1, (Jim_Obj *)key2);
-
}
-

-
static void *JimObjectHTKeyValDup(void *privdata, const void *val)
-
{
-
    Jim_IncrRefCount((Jim_Obj *)val);
-
    return (void *)val;
-
}
-

-
static void JimObjectHTKeyValDestructor(void *interp, void *val)
-
{
-
    Jim_DecrRefCount(interp, (Jim_Obj *)val);
-
}
-

-
static const Jim_HashTableType JimDictHashTableType = {
-
    JimObjectHTHashFunction,
-
    JimObjectHTKeyValDup,
-
    JimObjectHTKeyValDup,
-
    JimObjectHTKeyCompare,
-
    JimObjectHTKeyValDestructor,
-
    JimObjectHTKeyValDestructor
-
};
-

static const Jim_ObjType dictObjType = {
    "dict",
    FreeDictInternalRep,
@@ -11990,68 +12873,174 @@ static const Jim_ObjType dictObjType = {
    JIM_TYPE_NONE,
};

-
void FreeDictInternalRep(Jim_Interp *interp, Jim_Obj *objPtr)
+
static void JimFreeDict(Jim_Interp *interp, Jim_Dict *dict)
{
-
    JIM_NOTUSED(interp);
-

-
    Jim_FreeHashTable(objPtr->internalRep.ptr);
-
    Jim_Free(objPtr->internalRep.ptr);
+
    int i;
+
    for (i = 0; i < dict->len; i++) {
+
        Jim_DecrRefCount(interp, dict->table[i]);
+
    }
+
    Jim_Free(dict->table);
+
    Jim_Free(dict->ht);
+
    Jim_Free(dict);
}

-
void DupDictInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr)
+
enum {
+
    DICT_HASH_FIND = -1,
+
    DICT_HASH_REMOVE = -2,
+
    DICT_HASH_ADD = -3,
+
};
+

+
static int JimDictHashFind(Jim_Dict *dict, Jim_Obj *keyObjPtr, int op_tvoffset)
{
-
    Jim_HashTable *ht, *dupHt;
-
    Jim_HashTableIterator htiter;
-
    Jim_HashEntry *he;
+
    unsigned h = (JimObjectHTHashFunction(keyObjPtr) + dict->uniq);
+
    unsigned idx = h & dict->sizemask;
+
    int tvoffset = 0;
+
    unsigned peturb = h;
+
    unsigned first_removed = ~0;
+

+
    if (dict->len) {
+
        while ((tvoffset = dict->ht[idx].offset)) {
+
            if (tvoffset == -1) {
+
                if (first_removed == ~0) {
+
                    first_removed = idx;
+
                }
+
            }
+
            else if (dict->ht[idx].hash == h) {
+
                if (Jim_StringEqObj(keyObjPtr, dict->table[tvoffset - 1])) {
+
                    break;
+
                }
+
            }
+

+
            peturb >>= 5;
+
            idx = (5 * idx + 1 + peturb) & dict->sizemask;
+
        }
+
    }
+

+
    switch (op_tvoffset) {
+
        case DICT_HASH_FIND:
+

+
            break;
+
        case DICT_HASH_REMOVE:
+
            if (tvoffset) {
+

+
                dict->ht[idx].offset = -1;
+
                dict->dummy++;
+
            }
+

+
            break;
+
        case DICT_HASH_ADD:
+
            if (tvoffset == 0) {

+
                if (first_removed != ~0) {
+
                    idx = first_removed;
+
                    dict->dummy--;
+
                }
+
                dict->ht[idx].offset = dict->len + 1;
+
                dict->ht[idx].hash = h;
+
            }

-
    ht = srcPtr->internalRep.ptr;
-
    dupHt = Jim_Alloc(sizeof(*dupHt));
-
    Jim_InitHashTable(dupHt, &JimDictHashTableType, interp);
-
    if (ht->size != 0)
-
        Jim_ExpandHashTable(dupHt, ht->size);
+
            break;
+
        default:
+
            assert(tvoffset);

-
    JimInitHashTableIterator(ht, &htiter);
-
    while ((he = Jim_NextHashEntry(&htiter)) != NULL) {
-
        Jim_AddHashEntry(dupHt, he->key, he->u.val);
+
            dict->ht[idx].offset = op_tvoffset;
+
            break;
    }

-
    dupPtr->internalRep.ptr = dupHt;
-
    dupPtr->typePtr = &dictObjType;
+
    return tvoffset;
}

-
static Jim_Obj **JimDictPairs(Jim_Obj *dictPtr, int *len)
+
static void JimDictExpandHashTable(Jim_Dict *dict, unsigned int size)
{
-
    Jim_HashTable *ht;
-
    Jim_HashTableIterator htiter;
-
    Jim_HashEntry *he;
-
    Jim_Obj **objv;
    int i;
+
    struct JimDictHashEntry *prevht = dict->ht;
+
    int prevsize = dict->size;
+

+
    dict->size = JimHashTableNextPower(size);
+
    dict->sizemask = dict->size - 1;
+

+

+
    dict->ht = Jim_Alloc(dict->size * sizeof(*dict->ht));
+
    memset(dict->ht, 0, dict->size * sizeof(*dict->ht));

-
    ht = dictPtr->internalRep.ptr;

+
    for (i = 0; i < prevsize; i++) {
+
        if (prevht[i].offset > 0) {

-
    objv = Jim_Alloc((ht->used * 2) * sizeof(Jim_Obj *));
-
    JimInitHashTableIterator(ht, &htiter);
-
    i = 0;
-
    while ((he = Jim_NextHashEntry(&htiter)) != NULL) {
-
        objv[i++] = Jim_GetHashEntryKey(he);
-
        objv[i++] = Jim_GetHashEntryVal(he);
+
            unsigned h = prevht[i].hash;
+
            unsigned idx = h & dict->sizemask;
+
            unsigned peturb = h;
+

+
            while (dict->ht[idx].offset) {
+
                peturb >>= 5;
+
                idx = (5 * idx + 1 + peturb) & dict->sizemask;
+
            }
+
            dict->ht[idx].offset = prevht[i].offset;
+
            dict->ht[idx].hash = h;
+
        }
    }
-
    *len = i;
-
    return objv;
+
    Jim_Free(prevht);
}

-
static void UpdateStringOfDict(struct Jim_Obj *objPtr)
+
static int JimDictAdd(Jim_Dict *dict, Jim_Obj *keyObjPtr)
{
+
    if (dict->size <= dict->len + dict->dummy) {
+
        JimDictExpandHashTable(dict, dict->size ? dict->size * 2 : 8);
+
    }
+
    return JimDictHashFind(dict, keyObjPtr, DICT_HASH_ADD);
+
}

-
    int len;
-
    Jim_Obj **objv = JimDictPairs(objPtr, &len);
+
static Jim_Dict *JimDictNew(Jim_Interp *interp, int table_size, int ht_size)
+
{
+
    Jim_Dict *dict = Jim_Alloc(sizeof(*dict));
+
    memset(dict, 0, sizeof(*dict));
+

+
    if (ht_size) {
+
        JimDictExpandHashTable(dict, ht_size);
+
    }
+
    if (table_size) {
+
        dict->table = Jim_Alloc(table_size * sizeof(*dict->table));
+
        dict->maxLen = table_size;
+
    }
+
#ifdef JIM_RANDOMISE_HASH
+
    dict->uniq = (rand() ^ time(NULL) ^ clock());
+
#endif
+
    return dict;
+
}
+

+
static void FreeDictInternalRep(Jim_Interp *interp, Jim_Obj *objPtr)
+
{
+
    JimFreeDict(interp, objPtr->internalRep.dictValue);
+
}
+

+
static void DupDictInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr)
+
{
+
    Jim_Dict *oldDict = srcPtr->internalRep.dictValue;
+
    int i;


-
    JimMakeListStringRep(objPtr, objv, len);
+
    Jim_Dict *newDict = JimDictNew(interp, oldDict->maxLen, oldDict->size);

-
    Jim_Free(objv);
+

+
    for (i = 0; i < oldDict->len; i++) {
+
        newDict->table[i] = oldDict->table[i];
+
        Jim_IncrRefCount(newDict->table[i]);
+
    }
+
    newDict->len = oldDict->len;
+

+

+
    newDict->uniq = oldDict->uniq;
+

+

+
    memcpy(newDict->ht, oldDict->ht, sizeof(*oldDict->ht) * oldDict->size);
+

+
    dupPtr->internalRep.dictValue = newDict;
+
    dupPtr->typePtr = &dictObjType;
+
}
+

+
static void UpdateStringOfDict(struct Jim_Obj *objPtr)
+
{
+
    JimMakeListStringRep(objPtr, objPtr->internalRep.dictValue->table, objPtr->internalRep.dictValue->len);
}

static int SetDictFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr)
@@ -12066,7 +13055,6 @@ static int SetDictFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr)
        Jim_String(objPtr);
    }

-

    listlen = Jim_ListLength(interp, objPtr);
    if (listlen % 2) {
        Jim_SetResultString(interp, "missing value to go with key", -1);
@@ -12074,22 +13062,38 @@ static int SetDictFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr)
    }
    else {

-
        Jim_HashTable *ht;
+
        Jim_Dict *dict = JimDictNew(interp, 0, listlen);
        int i;

-
        ht = Jim_Alloc(sizeof(*ht));
-
        Jim_InitHashTable(ht, &JimDictHashTableType, interp);
+

+
        dict->table = objPtr->internalRep.listValue.ele;
+
        dict->maxLen = objPtr->internalRep.listValue.maxLen;
+


        for (i = 0; i < listlen; i += 2) {
-
            Jim_Obj *keyObjPtr = Jim_ListGetIndex(interp, objPtr, i);
-
            Jim_Obj *valObjPtr = Jim_ListGetIndex(interp, objPtr, i + 1);
+
            int tvoffset = JimDictAdd(dict, dict->table[i]);
+
            if (tvoffset) {
+


-
            Jim_ReplaceHashEntry(ht, keyObjPtr, valObjPtr);
+
                Jim_DecrRefCount(interp, dict->table[tvoffset]);
+

+
                dict->table[tvoffset] = dict->table[i + 1];
+

+
                Jim_DecrRefCount(interp, dict->table[i]);
+
            }
+
            else {
+
                if (dict->len != i) {
+
                    dict->table[dict->len++] = dict->table[i];
+
                    dict->table[dict->len++] = dict->table[i + 1];
+
                }
+
                else {
+
                    dict->len += 2;
+
                }
+
            }
        }

-
        Jim_FreeIntRep(interp, objPtr);
        objPtr->typePtr = &dictObjType;
-
        objPtr->internalRep.ptr = ht;
+
        objPtr->internalRep.dictValue = dict;

        return JIM_OK;
    }
@@ -12100,13 +13104,56 @@ static int SetDictFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr)
static int DictAddElement(Jim_Interp *interp, Jim_Obj *objPtr,
    Jim_Obj *keyObjPtr, Jim_Obj *valueObjPtr)
{
-
    Jim_HashTable *ht = objPtr->internalRep.ptr;
+
    Jim_Dict *dict = objPtr->internalRep.dictValue;
+
    if (valueObjPtr == NULL) {
+

+
        int tvoffset = JimDictHashFind(dict, keyObjPtr, DICT_HASH_REMOVE);
+
        if (tvoffset) {
+

+
            Jim_DecrRefCount(interp, dict->table[tvoffset - 1]);
+
            Jim_DecrRefCount(interp, dict->table[tvoffset]);
+
            dict->len -= 2;
+
            if (tvoffset != dict->len + 1) {
+

+
                dict->table[tvoffset - 1] = dict->table[dict->len];
+
                dict->table[tvoffset] = dict->table[dict->len + 1];
+

+

+
                JimDictHashFind(dict, dict->table[tvoffset - 1], tvoffset);
+
            }
+
            return JIM_OK;
+
        }
+
        return JIM_ERR;
+
    }
+
    else {
+

+
        int tvoffset = JimDictAdd(dict, keyObjPtr);
+
        if (tvoffset) {
+

+
            Jim_IncrRefCount(valueObjPtr);
+
            Jim_DecrRefCount(interp, dict->table[tvoffset]);
+
            dict->table[tvoffset] = valueObjPtr;
+
        }
+
        else {
+
            if (dict->maxLen == dict->len) {
+

+
                if (dict->maxLen < 4) {
+
                    dict->maxLen = 4;
+
                }
+
                else {
+
                    dict->maxLen *= 2;
+
                }
+
                dict->table = Jim_Realloc(dict->table, dict->maxLen * sizeof(*dict->table));
+
            }
+
            Jim_IncrRefCount(keyObjPtr);
+
            Jim_IncrRefCount(valueObjPtr);
+

+
            dict->table[dict->len++] = keyObjPtr;
+
            dict->table[dict->len++] = valueObjPtr;

-
    if (valueObjPtr == NULL) {
-
        return Jim_DeleteHashEntry(ht, keyObjPtr);
+
        }
+
        return JIM_OK;
    }
-
    Jim_ReplaceHashEntry(ht, keyObjPtr, valueObjPtr);
-
    return JIM_OK;
}

int Jim_DictAddElement(Jim_Interp *interp, Jim_Obj *objPtr,
@@ -12130,8 +13177,8 @@ Jim_Obj *Jim_NewDictObj(Jim_Interp *interp, Jim_Obj *const *elements, int len)
    objPtr = Jim_NewObj(interp);
    objPtr->typePtr = &dictObjType;
    objPtr->bytes = NULL;
-
    objPtr->internalRep.ptr = Jim_Alloc(sizeof(Jim_HashTable));
-
    Jim_InitHashTable(objPtr->internalRep.ptr, &JimDictHashTableType, interp);
+

+
    objPtr->internalRep.dictValue = JimDictNew(interp, len, len);
    for (i = 0; i < len; i += 2)
        DictAddElement(interp, objPtr, elements[i], elements[i + 1]);
    return objPtr;
@@ -12140,38 +13187,45 @@ Jim_Obj *Jim_NewDictObj(Jim_Interp *interp, Jim_Obj *const *elements, int len)
int Jim_DictKey(Jim_Interp *interp, Jim_Obj *dictPtr, Jim_Obj *keyPtr,
    Jim_Obj **objPtrPtr, int flags)
{
-
    Jim_HashEntry *he;
-
    Jim_HashTable *ht;
+
    int tvoffset;
+
    Jim_Dict *dict;

    if (SetDictFromAny(interp, dictPtr) != JIM_OK) {
        return -1;
    }
-
    ht = dictPtr->internalRep.ptr;
-
    if ((he = Jim_FindHashEntry(ht, keyPtr)) == NULL) {
+
    dict = dictPtr->internalRep.dictValue;
+
    tvoffset = JimDictHashFind(dict, keyPtr, DICT_HASH_FIND);
+
    if (tvoffset == 0) {
        if (flags & JIM_ERRMSG) {
            Jim_SetResultFormatted(interp, "key \"%#s\" not known in dictionary", keyPtr);
        }
        return JIM_ERR;
    }
-
    else {
-
        *objPtrPtr = Jim_GetHashEntryVal(he);
-
        return JIM_OK;
-
    }
+
    *objPtrPtr = dict->table[tvoffset];
+
    return JIM_OK;
}

-

-
int Jim_DictPairs(Jim_Interp *interp, Jim_Obj *dictPtr, Jim_Obj ***objPtrPtr, int *len)
+
Jim_Obj **Jim_DictPairs(Jim_Interp *interp, Jim_Obj *dictPtr, int *len)
{
-
    if (SetDictFromAny(interp, dictPtr) != JIM_OK) {
-
        return JIM_ERR;
+

+
    if (Jim_IsList(dictPtr)) {
+
        Jim_Obj **table;
+
        JimListGetElements(interp, dictPtr, len, &table);
+
        if (*len % 2 == 0) {
+
            return table;
+
        }
+

    }
-
    *objPtrPtr = JimDictPairs(dictPtr, len);
+
    if (SetDictFromAny(interp, dictPtr) != JIM_OK) {

-
    return JIM_OK;
+
        *len = 1;
+
        return NULL;
+
    }
+
    *len = dictPtr->internalRep.dictValue->len;
+
    return dictPtr->internalRep.dictValue->table;
}


-

int Jim_DictKeysVector(Jim_Interp *interp, Jim_Obj *dictPtr,
    Jim_Obj *const *keyv, int keyc, Jim_Obj **objPtrPtr, int flags)
{
@@ -12256,7 +13310,10 @@ int Jim_SetDictKeysVector(Jim_Interp *interp, Jim_Obj *varNamePtr,
    if (Jim_SetVariable(interp, varNamePtr, varObjPtr) != JIM_OK) {
        goto err;
    }
-
    Jim_SetResult(interp, varObjPtr);
+

+
    if (!(flags & JIM_NORESULT)) {
+
        Jim_SetResult(interp, varObjPtr);
+
    }
    return JIM_OK;
  err:
    if (shared) {
@@ -12283,7 +13340,7 @@ static void UpdateStringOfIndex(struct Jim_Obj *objPtr)
    }
    else {
        char buf[JIM_INTEGER_SPACE + 1];
-
        if (objPtr->internalRep.intValue >= 0) {
+
        if (objPtr->internalRep.intValue >= 0 || objPtr->internalRep.intValue == -INT_MAX) {
            sprintf(buf, "%d", objPtr->internalRep.intValue);
        }
        else {
@@ -12296,9 +13353,12 @@ static void UpdateStringOfIndex(struct Jim_Obj *objPtr)

static int SetIndexFromAny(Jim_Interp *interp, Jim_Obj *objPtr)
{
-
    int idx, end = 0;
+
    jim_wide idx;
+
    int end = 0;
    const char *str;
-
    char *endptr;
+
    Jim_Obj *exprObj = objPtr;
+

+
    JimPanic((objPtr->refCount == 0, "SetIndexFromAny() called with zero refcount object"));


    str = Jim_String(objPtr);
@@ -12308,33 +13368,30 @@ static int SetIndexFromAny(Jim_Interp *interp, Jim_Obj *objPtr)
        end = 1;
        str += 3;
        idx = 0;
-
    }
-
    else {
-
        idx = jim_strtol(str, &endptr);
+
        switch (*str) {
+
            case '\0':
+
                exprObj = NULL;
+
                break;

-
        if (endptr == str) {
-
            goto badindex;
+
            case '-':
+
            case '+':
+
                exprObj = Jim_NewStringObj(interp, str, -1);
+
                break;
+

+
            default:
+
                goto badindex;
        }
-
        str = endptr;
    }
-

-

-
    if (*str == '+' || *str == '-') {
-
        int sign = (*str == '+' ? 1 : -1);
-

-
        idx += sign * jim_strtol(++str, &endptr);
-
        if (str == endptr || *endptr) {
+
    if (exprObj) {
+
        int ret;
+
        Jim_IncrRefCount(exprObj);
+
        ret = Jim_GetWideExpr(interp, exprObj, &idx);
+
        Jim_DecrRefCount(interp, exprObj);
+
        if (ret != JIM_OK) {
            goto badindex;
        }
-
        str = endptr;
    }

-
    while (isspace(UCHAR(*str))) {
-
        str++;
-
    }
-
    if (*str) {
-
        goto badindex;
-
    }
    if (end) {
        if (idx > 0) {
            idx = INT_MAX;
@@ -12356,7 +13413,7 @@ static int SetIndexFromAny(Jim_Interp *interp, Jim_Obj *objPtr)

  badindex:
    Jim_SetResultFormatted(interp,
-
        "bad index \"%#s\": must be integer?[+-]integer? or end?[+-]integer?", objPtr);
+
        "bad index \"%#s\": must be intexpr or end?[+-]intexpr?", objPtr);
    return JIM_ERR;
}

@@ -12481,6 +13538,10 @@ enum
    JIM_EXPROP_STRNE,
    JIM_EXPROP_STRIN,
    JIM_EXPROP_STRNI,
+
    JIM_EXPROP_STRLT,
+
    JIM_EXPROP_STRGT,
+
    JIM_EXPROP_STRLE,
+
    JIM_EXPROP_STRGE,


    JIM_EXPROP_NOT,
@@ -12546,7 +13607,7 @@ static int JimExprEvalTermNode(Jim_Interp *interp, struct JimExprNode *node);
static int JimExprOpNumUnary(Jim_Interp *interp, struct JimExprNode *node)
{
    int intresult = 1;
-
    int rc;
+
    int rc, bA = 0;
    double dA, dC = 0;
    jim_wide wA, wC = 0;
    Jim_Obj *A;
@@ -12613,6 +13674,15 @@ static int JimExprOpNumUnary(Jim_Interp *interp, struct JimExprNode *node)
                abort();
        }
    }
+
    else if ((rc = Jim_GetBoolean(interp, A, &bA)) == JIM_OK) {
+
        switch (node->type) {
+
            case JIM_EXPROP_NOT:
+
                wC = !bA;
+
                break;
+
            default:
+
                abort();
+
        }
+
    }

    if (rc == JIM_OK) {
        if (intresult) {
@@ -12633,7 +13703,7 @@ static double JimRandDouble(Jim_Interp *interp)
    unsigned long x;
    JimRandomBytes(interp, &x, sizeof(x));

-
    return (double)x / (unsigned long)~0;
+
    return (double)x / (double)~0UL;
}

static int JimExprOpIntUnary(Jim_Interp *interp, struct JimExprNode *node)
@@ -13042,7 +14112,7 @@ static int JimExprOpStrBin(Jim_Interp *interp, struct JimExprNode *node)
{
    Jim_Obj *A, *B;
    jim_wide wC;
-
    int rc;
+
    int comp, rc;

    if ((rc = JimExprGetTerm(interp, node->left, &A)) != JIM_OK) {
        return rc;
@@ -13060,6 +14130,21 @@ static int JimExprOpStrBin(Jim_Interp *interp, struct JimExprNode *node)
                wC = !wC;
            }
            break;
+
        case JIM_EXPROP_STRLT:
+
        case JIM_EXPROP_STRGT:
+
        case JIM_EXPROP_STRLE:
+
        case JIM_EXPROP_STRGE:
+
            comp = Jim_StringCompareObj(interp, A, B, 0);
+
            if (node->type == JIM_EXPROP_STRLT) {
+
                wC = comp == -1;
+
            } else if (node->type == JIM_EXPROP_STRGT) {
+
                wC = comp == 1;
+
            } else if (node->type == JIM_EXPROP_STRLE) {
+
                wC = comp == -1 || comp == 0;
+
            } else {
+
                wC = comp == 0 || comp == 1;
+
            }
+
            break;
        case JIM_EXPROP_STRIN:
            wC = JimSearchList(interp, B, A);
            break;
@@ -13199,6 +14284,11 @@ static const struct Jim_ExprOperator Jim_ExprOperators[] = {
    OPRINIT("in", 55, 2, JimExprOpStrBin),
    OPRINIT("ni", 55, 2, JimExprOpStrBin),

+
    OPRINIT("lt", 75, 2, JimExprOpStrBin),
+
    OPRINIT("gt", 75, 2, JimExprOpStrBin),
+
    OPRINIT("le", 75, 2, JimExprOpStrBin),
+
    OPRINIT("ge", 75, 2, JimExprOpStrBin),
+

    OPRINIT_ATTR("!", 150, 1, JimExprOpNumUnary, OP_RIGHT_ASSOC),
    OPRINIT_ATTR("~", 150, 1, JimExprOpIntUnary, OP_RIGHT_ASSOC),
    OPRINIT_ATTR(" -", 150, 1, JimExprOpNumUnary, OP_RIGHT_ASSOC),
@@ -13244,13 +14334,22 @@ static const struct Jim_ExprOperator Jim_ExprOperators[] = {

static int JimParseExpression(struct JimParserCtx *pc)
{
+
    while (1) {

-
    while (isspace(UCHAR(*pc->p)) || (*(pc->p) == '\\' && *(pc->p + 1) == '\n')) {
-
        if (*pc->p == '\n') {
-
            pc->linenr++;
+
        while (isspace(UCHAR(*pc->p)) || (*(pc->p) == '\\' && *(pc->p + 1) == '\n')) {
+
            if (*pc->p == '\n') {
+
                pc->linenr++;
+
            }
+
            pc->p++;
+
            pc->len--;
        }
-
        pc->p++;
-
        pc->len--;
+

+
        if (*pc->p == '#') {
+
            JimParseComment(pc);
+

+
            continue;
+
        }
+
        break;
    }


@@ -13374,17 +14473,11 @@ static int JimParseExprIrrational(struct JimParserCtx *pc)

static int JimParseExprBoolean(struct JimParserCtx *pc)
{
-
    const char *booleans[] = { "false", "no", "off", "true", "yes", "on", NULL };
-
    const int lengths[] = { 5, 2, 3, 4, 3, 2, 0 };
    int i;
-

-
    for (i = 0; booleans[i]; i++) {
-
        const char *boolean = booleans[i];
-
        int length = lengths[i];
-

-
        if (strncmp(boolean, pc->p, length) == 0) {
-
            pc->p += length;
-
            pc->len -= length;
+
    for (i = 0; i < sizeof(jim_true_false_strings) / sizeof(*jim_true_false_strings); i++) {
+
        if (strncmp(pc->p, jim_true_false_strings[i], jim_true_false_lens[i]) == 0) {
+
            pc->p += jim_true_false_lens[i];
+
            pc->len -= jim_true_false_lens[i];
            pc->tend = pc->p - 1;
            pc->tt = JIM_TT_EXPR_BOOLEAN;
            return JIM_OK;
@@ -13481,7 +14574,7 @@ static const Jim_ObjType exprObjType = {
    FreeExprInternalRep,
    DupExprInternalRep,
    NULL,
-
    JIM_TYPE_REFERENCES,
+
    JIM_TYPE_NONE,
};


@@ -13573,8 +14666,7 @@ static void JimShowExprNode(struct JimExprNode *node, int level)
#define EXPR_FUNC_ARGS   0x0002
#define EXPR_TERNARY     0x0004

-
static int ExprTreeBuildTree(Jim_Interp *interp, struct ExprBuilder *builder, int precedence, int flags, int exp_numterms)
-
{
+
static int ExprTreeBuildTree(Jim_Interp *interp, struct ExprBuilder *builder, int precedence, int flags, int exp_numterms) {
    int rc;
    struct JimExprNode *node;

@@ -13828,7 +14920,7 @@ static struct ExprTree *ExprTreeCreateTree(Jim_Interp *interp, const ParseTokenL
    builder.exprObjPtr = exprObjPtr;
    builder.fileNameObj = fileNameObj;

-
    builder.nodes = malloc(sizeof(struct JimExprNode) * (tokenlist->count - 1));
+
    builder.nodes = Jim_Alloc(sizeof(struct JimExprNode) * (tokenlist->count - 1));
    memset(builder.nodes, 0, sizeof(struct JimExprNode) * (tokenlist->count - 1));
    builder.next = builder.nodes;
    Jim_InitStack(&builder.stack);
@@ -14006,6 +15098,9 @@ static int JimExprEvalTermNode(Jim_Interp *interp, struct JimExprNode *node)
                return JIM_ERR;

            case JIM_TT_ESC:
+
                if (interp->safeexpr) {
+
                    return JIM_ERR;
+
                }
                if (Jim_SubstObj(interp, node->objPtr, &objPtr, JIM_NONE) == JIM_OK) {
                    Jim_SetResult(interp, objPtr);
                    return JIM_OK;
@@ -14013,6 +15108,9 @@ static int JimExprEvalTermNode(Jim_Interp *interp, struct JimExprNode *node)
                return JIM_ERR;

            case JIM_TT_CMD:
+
                if (interp->safeexpr) {
+
                    return JIM_ERR;
+
                }
                return Jim_EvalObj(interp, node->objPtr);

            default:
@@ -14045,13 +15143,15 @@ int Jim_EvalExpression(Jim_Interp *interp, Jim_Obj *exprObjPtr)
    struct ExprTree *expr;
    int retcode = JIM_OK;

+
    Jim_IncrRefCount(exprObjPtr);
    expr = JimGetExpression(interp, exprObjPtr);
    if (!expr) {
-
        return JIM_ERR;
+
        retcode = JIM_ERR;
+
        goto done;
    }

#ifdef JIM_OPTIMIZATION
-
    {
+
    if (!interp->safeexpr) {
        Jim_Obj *objPtr;


@@ -14060,7 +15160,7 @@ int Jim_EvalExpression(Jim_Interp *interp, Jim_Obj *exprObjPtr)
                objPtr = JimExprIntValOrVar(interp, expr->expr);
                if (objPtr) {
                    Jim_SetResult(interp, objPtr);
-
                    return JIM_OK;
+
                    goto done;
                }
                break;

@@ -14070,7 +15170,7 @@ int Jim_EvalExpression(Jim_Interp *interp, Jim_Obj *exprObjPtr)

                    if (objPtr && JimIsWide(objPtr)) {
                        Jim_SetResult(interp, JimWideValue(objPtr) ? interp->falseObj : interp->trueObj);
-
                        return JIM_OK;
+
                        goto done;
                    }
                }
                break;
@@ -14106,7 +15206,7 @@ int Jim_EvalExpression(Jim_Interp *interp, Jim_Obj *exprObjPtr)
                                goto noopt;
                        }
                        Jim_SetResult(interp, cmpRes ? interp->trueObj : interp->falseObj);
-
                        return JIM_OK;
+
                        goto done;
                    }
                }
                break;
@@ -14120,7 +15220,13 @@ noopt:

    retcode = JimExprEvalTermNode(interp, expr->expr);

-
    expr->inUse--;
+

+
    Jim_FreeIntRep(interp, exprObjPtr);
+
    exprObjPtr->typePtr = &exprObjType;
+
    Jim_SetIntRepPtr(exprObjPtr, expr);
+

+
done:
+
    Jim_DecrRefCount(interp, exprObjPtr);

    return retcode;
}
@@ -14407,7 +15513,7 @@ static Jim_Obj *JimScanAString(Jim_Interp *interp, const char *sdescr, const cha
            break;

        n = utf8_tounicode(str, &c);
-
        if (sdescr && !JimCharsetMatch(sdescr, c, JIM_CHARSET_SCAN))
+
        if (sdescr && !JimCharsetMatch(sdescr, strlen(sdescr), c, JIM_CHARSET_SCAN))
            break;
        while (n--)
            *p++ = *str++;
@@ -14417,7 +15523,7 @@ static Jim_Obj *JimScanAString(Jim_Interp *interp, const char *sdescr, const cha
}


-
static int ScanOneEntry(Jim_Interp *interp, const char *str, int pos, int strLen,
+
static int ScanOneEntry(Jim_Interp *interp, const char *str, int pos, int str_bytelen,
    ScanFmtStringObj * fmtObj, long idx, Jim_Obj **valObjPtr)
{
    const char *tok;
@@ -14430,17 +15536,17 @@ static int ScanOneEntry(Jim_Interp *interp, const char *str, int pos, int strLen

    *valObjPtr = 0;
    if (descr->prefix) {
-
        for (i = 0; pos < strLen && descr->prefix[i]; ++i) {
+
        for (i = 0; pos < str_bytelen && descr->prefix[i]; ++i) {

            if (isspace(UCHAR(descr->prefix[i])))
-
                while (pos < strLen && isspace(UCHAR(str[pos])))
+
                while (pos < str_bytelen && isspace(UCHAR(str[pos])))
                    ++pos;
            else if (descr->prefix[i] != str[pos])
                break;
            else
                ++pos;
        }
-
        if (pos >= strLen) {
+
        if (pos >= str_bytelen) {
            return -1;
        }
        else if (descr->prefix[i] != 0)
@@ -14451,6 +15557,7 @@ static int ScanOneEntry(Jim_Interp *interp, const char *str, int pos, int strLen
        while (isspace(UCHAR(str[pos])))
            ++pos;

+

    scanned = pos - anchor;


@@ -14458,20 +15565,20 @@ static int ScanOneEntry(Jim_Interp *interp, const char *str, int pos, int strLen

        *valObjPtr = Jim_NewIntObj(interp, anchor + scanned);
    }
-
    else if (pos >= strLen) {
+
    else if (pos >= str_bytelen) {

        return -1;
    }
    else if (descr->type == 'c') {
-
            int c;
-
            scanned += utf8_tounicode(&str[pos], &c);
-
            *valObjPtr = Jim_NewIntObj(interp, c);
-
            return scanned;
+
        int c;
+
        scanned += utf8_tounicode(&str[pos], &c);
+
        *valObjPtr = Jim_NewIntObj(interp, c);
+
        return scanned;
    }
    else {

        if (descr->width > 0) {
-
            size_t sLen = utf8_strlen(&str[pos], strLen - pos);
+
            size_t sLen = utf8_strlen(&str[pos], str_bytelen - pos);
            size_t tLen = descr->width > sLen ? sLen : descr->width;

            tmpObj = Jim_NewStringObjUtf8(interp, str + pos, tLen);
@@ -14550,7 +15657,7 @@ Jim_Obj *Jim_ScanString(Jim_Interp *interp, Jim_Obj *strObjPtr, Jim_Obj *fmtObjP
    size_t i, pos;
    int scanned = 1;
    const char *str = Jim_String(strObjPtr);
-
    int strLen = Jim_Utf8Length(interp, strObjPtr);
+
    int str_bytelen = Jim_Length(strObjPtr);
    Jim_Obj *resultList = 0;
    Jim_Obj **resultVec = 0;
    int resultc;
@@ -14587,7 +15694,7 @@ Jim_Obj *Jim_ScanString(Jim_Interp *interp, Jim_Obj *strObjPtr, Jim_Obj *fmtObjP
            continue;

        if (scanned > 0)
-
            scanned = ScanOneEntry(interp, str, pos, strLen, fmtObj, i, &value);
+
            scanned = ScanOneEntry(interp, str, pos, str_bytelen, fmtObj, i, &value);

        if (scanned == -1 && i == 0)
            goto eof;
@@ -14709,7 +15816,7 @@ static int Jim_IncrCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *arg
        return JIM_ERR;
    }
    if (argc == 3) {
-
        if (Jim_GetWide(interp, argv[2], &increment) != JIM_OK)
+
        if (Jim_GetWideExpr(interp, argv[2], &increment) != JIM_OK)
            return JIM_ERR;
    }
    intObjPtr = Jim_GetVariable(interp, argv[1], JIM_UNSHARED);
@@ -14745,6 +15852,45 @@ static int Jim_IncrCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *arg
#define JIM_EVAL_SARGV_LEN 8
#define JIM_EVAL_SINTV_LEN 8

+
static int JimTraceCallback(Jim_Interp *interp, const char *type, int argc, Jim_Obj *const *argv)
+
{
+
    JimPanic((interp->traceCmdObj == NULL, "xtrace invoked with no object"));
+

+
    int ret;
+
    Jim_Obj *nargv[7];
+
    Jim_Obj *traceCmdObj = interp->traceCmdObj;
+
    Jim_Obj *resultObj = Jim_GetResult(interp);
+

+
    ScriptObj *script = JimGetScript(interp, interp->evalFrame->scriptObj);
+

+
    nargv[0] = traceCmdObj;
+
    nargv[1] = Jim_NewStringObj(interp, type, -1);
+
    nargv[2] = script->fileNameObj;
+
    nargv[3] = Jim_NewIntObj(interp, script->linenr);
+
    nargv[4] = resultObj;
+
    nargv[5] = argv[0];
+
    nargv[6] = Jim_NewListObj(interp, argv + 1, argc - 1);
+

+

+
    interp->traceCmdObj = NULL;
+

+
    Jim_IncrRefCount(resultObj);
+
    ret = Jim_EvalObjVector(interp, 7, nargv);
+
    Jim_DecrRefCount(interp, resultObj);
+

+
    if (ret == JIM_OK || ret == JIM_RETURN) {
+

+
        interp->traceCmdObj = traceCmdObj;
+
        Jim_SetEmptyResult(interp);
+
        ret = JIM_OK;
+
    }
+
    else {
+

+
        Jim_DecrRefCount(interp, traceCmdObj);
+
    }
+
    return ret;
+
}
+


static int JimUnknown(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
@@ -14767,11 +15913,39 @@ static int JimUnknown(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
    return retcode;
}

+
static void JimPushEvalFrame(Jim_Interp *interp, Jim_EvalFrame *frame, Jim_Obj *scriptObj)
+
{
+
    memset(frame, 0, sizeof(*frame));
+
    frame->parent = interp->evalFrame;
+
    frame->level = frame->parent->level + 1;
+
    frame->procLevel = interp->procLevel;
+
    frame->framePtr = interp->framePtr;
+
    if (scriptObj) {
+
        frame->scriptObj = scriptObj;
+
    }
+
    else {
+
        frame->scriptObj = frame->parent->scriptObj;
+
    }
+
    interp->evalFrame = frame;
+
#if 0
+
    if (frame->scriptObj) {
+
        printf("script: %.*s\n", 20, Jim_String(frame->scriptObj));
+
    }
+
#endif
+
}
+

+
static void JimPopEvalFrame(Jim_Interp *interp)
+
{
+
    interp->evalFrame = interp->evalFrame->parent;
+
}
+

+

static int JimInvokeCommand(Jim_Interp *interp, int objc, Jim_Obj *const *objv)
{
    int retcode;
    Jim_Cmd *cmdPtr;
    void *prevPrivData;
+
    Jim_Obj *tailcallObj = NULL;

#if 0
    printf("invoke");
@@ -14782,18 +15956,11 @@ static int JimInvokeCommand(Jim_Interp *interp, int objc, Jim_Obj *const *objv)
    printf("\n");
#endif

-
    if (interp->framePtr->tailcallCmd) {
-

-
        cmdPtr = interp->framePtr->tailcallCmd;
-
        interp->framePtr->tailcallCmd = NULL;
-
    }
-
    else {
-
        cmdPtr = Jim_GetCommand(interp, objv[0], JIM_ERRMSG);
-
        if (cmdPtr == NULL) {
-
            return JimUnknown(interp, objc, objv);
-
        }
-
        JimIncrCmdRefCount(cmdPtr);
+
    cmdPtr = Jim_GetCommand(interp, objv[0], JIM_ERRMSG);
+
    if (cmdPtr == NULL) {
+
        return JimUnknown(interp, objc, objv);
    }
+
    JimIncrCmdRefCount(cmdPtr);

    if (interp->evalDepth == interp->maxEvalDepth) {
        Jim_SetResultString(interp, "Infinite eval recursion", -1);
@@ -14803,34 +15970,87 @@ static int JimInvokeCommand(Jim_Interp *interp, int objc, Jim_Obj *const *objv)
    interp->evalDepth++;
    prevPrivData = interp->cmdPrivData;

+
tailcall:

-
    Jim_SetEmptyResult(interp);
-
    if (cmdPtr->isproc) {
-
        retcode = JimCallProcedure(interp, cmdPtr, objc, objv);
+
    interp->evalFrame->argc = objc;
+
    interp->evalFrame->argv = objv;
+
    interp->evalFrame->cmd = cmdPtr;
+

+
    if (!interp->traceCmdObj ||
+
        (retcode = JimTraceCallback(interp, "cmd", objc, objv)) == JIM_OK) {
+

+
        Jim_SetEmptyResult(interp);
+
        if (cmdPtr->isproc) {
+
            retcode = JimCallProcedure(interp, cmdPtr, objc, objv);
+
        }
+
        else {
+
            interp->cmdPrivData = cmdPtr->u.native.privData;
+
            retcode = cmdPtr->u.native.cmdProc(interp, objc, objv);
+
        }
+
        if (retcode == JIM_ERR) {
+
            JimSetErrorStack(interp);
+
        }
    }
-
    else {
-
        interp->cmdPrivData = cmdPtr->u.native.privData;
-
        retcode = cmdPtr->u.native.cmdProc(interp, objc, objv);
+

+
    if (tailcallObj) {
+

+
        Jim_DecrRefCount(interp, tailcallObj);
+
        tailcallObj = NULL;
+
    }
+

+

+
    interp->evalFrame->argc = 0;
+
    interp->evalFrame->argv = NULL;
+

+

+
    if (retcode == JIM_EVAL && interp->framePtr->tailcallObj) {
+
        JimDecrCmdRefCount(interp, cmdPtr);
+

+

+
        cmdPtr = interp->framePtr->tailcallCmd;
+
        interp->framePtr->tailcallCmd = NULL;
+
        tailcallObj = interp->framePtr->tailcallObj;
+
        interp->framePtr->tailcallObj = NULL;
+
        objc = tailcallObj->internalRep.listValue.len;
+
        objv = tailcallObj->internalRep.listValue.ele;
+
        goto tailcall;
    }
+

    interp->cmdPrivData = prevPrivData;
    interp->evalDepth--;

out:
    JimDecrCmdRefCount(interp, cmdPtr);

+
    if (retcode == JIM_ERR) {
+
        JimSetErrorStack(interp);
+
    }
+

+
    if (interp->framePtr->tailcallObj) {
+
        JimDecrCmdRefCount(interp, interp->framePtr->tailcallCmd);
+
        Jim_DecrRefCount(interp, interp->framePtr->tailcallObj);
+
        interp->framePtr->tailcallCmd = NULL;
+
        interp->framePtr->tailcallObj = NULL;
+
    }
+

    return retcode;
}

int Jim_EvalObjVector(Jim_Interp *interp, int objc, Jim_Obj *const *objv)
{
    int i, retcode;
+
    Jim_EvalFrame frame;


    for (i = 0; i < objc; i++)
        Jim_IncrRefCount(objv[i]);

+
    JimPushEvalFrame(interp, &frame, NULL);
+

    retcode = JimInvokeCommand(interp, objc, objv);

+
    JimPopEvalFrame(interp);
+


    for (i = 0; i < objc; i++)
        Jim_DecrRefCount(interp, objv[i]);
@@ -14850,40 +16070,10 @@ int Jim_EvalObjPrefix(Jim_Interp *interp, Jim_Obj *prefix, int objc, Jim_Obj *co
    return ret;
}

-
static void JimAddErrorToStack(Jim_Interp *interp, ScriptObj *script)
-
{
-
    if (!interp->errorFlag) {
-

-
        interp->errorFlag = 1;
-
        Jim_IncrRefCount(script->fileNameObj);
-
        Jim_DecrRefCount(interp, interp->errorFileNameObj);
-
        interp->errorFileNameObj = script->fileNameObj;
-
        interp->errorLine = script->linenr;
-

-
        JimResetStackTrace(interp);
-

-
        interp->addStackTrace++;
-
    }
-

-

-
    if (interp->addStackTrace > 0) {
-

-

-
        JimAppendStackTrace(interp, Jim_String(interp->errorProc), script->fileNameObj, script->linenr);
-

-
        if (Jim_Length(script->fileNameObj)) {
-
            interp->addStackTrace = 0;
-
        }
-

-
        Jim_DecrRefCount(interp, interp->errorProc);
-
        interp->errorProc = interp->emptyObj;
-
        Jim_IncrRefCount(interp->errorProc);
-
    }
-
}
-

static int JimSubstOneToken(Jim_Interp *interp, const ScriptToken *token, Jim_Obj **objPtrPtr)
{
    Jim_Obj *objPtr;
+
    int ret = JIM_ERR;

    switch (token->type) {
        case JIM_TT_STR:
@@ -14897,22 +16087,21 @@ static int JimSubstOneToken(Jim_Interp *interp, const ScriptToken *token, Jim_Ob
            objPtr = JimExpandDictSugar(interp, token->objPtr);
            break;
        case JIM_TT_EXPRSUGAR:
-
            objPtr = JimExpandExprSugar(interp, token->objPtr);
+
            ret = Jim_EvalExpression(interp, token->objPtr);
+
            if (ret == JIM_OK) {
+
                objPtr = Jim_GetResult(interp);
+
            }
+
            else {
+
                objPtr = NULL;
+
            }
            break;
        case JIM_TT_CMD:
-
            switch (Jim_EvalObj(interp, token->objPtr)) {
-
                case JIM_OK:
-
                case JIM_RETURN:
-
                    objPtr = interp->result;
-
                    break;
-
                case JIM_BREAK:
-

-
                    return JIM_BREAK;
-
                case JIM_CONTINUE:
+
            ret = Jim_EvalObj(interp, token->objPtr);
+
            if (ret == JIM_OK || ret == JIM_RETURN) {
+
                objPtr = interp->result;
+
            } else {

-
                    return JIM_CONTINUE;
-
                default:
-
                    return JIM_ERR;
+
                objPtr = NULL;
            }
            break;
        default:
@@ -14925,7 +16114,7 @@ static int JimSubstOneToken(Jim_Interp *interp, const ScriptToken *token, Jim_Ob
        *objPtrPtr = objPtr;
        return JIM_OK;
    }
-
    return JIM_ERR;
+
    return ret;
}

static Jim_Obj *JimInterpolateTokens(Jim_Interp *interp, const ScriptToken * token, int tokens, int flags)
@@ -15020,9 +16209,12 @@ static Jim_Obj *JimInterpolateTokens(Jim_Interp *interp, const ScriptToken * tok
static int JimEvalObjList(Jim_Interp *interp, Jim_Obj *listPtr)
{
    int retcode = JIM_OK;
+
    Jim_EvalFrame frame;

    JimPanic((Jim_IsList(listPtr) == 0, "JimEvalObjList() invoked on non-list."));

+
    JimPushEvalFrame(interp, &frame, NULL);
+

    if (listPtr->internalRep.listValue.len) {
        Jim_IncrRefCount(listPtr);
        retcode = JimInvokeCommand(interp,
@@ -15030,6 +16222,9 @@ static int JimEvalObjList(Jim_Interp *interp, Jim_Obj *listPtr)
            listPtr->internalRep.listValue.ele);
        Jim_DecrRefCount(interp, listPtr);
    }
+

+
    JimPopEvalFrame(interp);
+

    return retcode;
}

@@ -15046,7 +16241,7 @@ int Jim_EvalObj(Jim_Interp *interp, Jim_Obj *scriptObjPtr)
    ScriptToken *token;
    int retcode = JIM_OK;
    Jim_Obj *sargv[JIM_EVAL_SARGV_LEN], **argv = NULL;
-
    Jim_Obj *prevScriptObj;
+
    Jim_EvalFrame frame;

    if (Jim_IsList(scriptObjPtr) && scriptObjPtr->bytes == NULL) {
        return JimEvalObjList(interp, scriptObjPtr);
@@ -15054,7 +16249,8 @@ int Jim_EvalObj(Jim_Interp *interp, Jim_Obj *scriptObjPtr)

    Jim_IncrRefCount(scriptObjPtr);
    script = JimGetScript(interp, scriptObjPtr);
-
    if (!JimScriptValid(interp, script)) {
+
    if (JimParseCheckMissing(interp, script->missing) == JIM_ERR) {
+
        JimSetErrorStack(interp);
        Jim_DecrRefCount(interp, scriptObjPtr);
        return JIM_ERR;
    }
@@ -15088,9 +16284,8 @@ int Jim_EvalObj(Jim_Interp *interp, Jim_Obj *scriptObjPtr)

    script->inUse++;

+
    JimPushEvalFrame(interp, &frame, scriptObjPtr);

-
    prevScriptObj = interp->currentScriptObj;
-
    interp->currentScriptObj = scriptObjPtr;

    interp->errorFlag = 0;
    argv = sargv;
@@ -15134,7 +16329,13 @@ int Jim_EvalObj(Jim_Interp *interp, Jim_Obj *scriptObjPtr)
                        wordObjPtr = Jim_GetVariable(interp, token[i].objPtr, JIM_ERRMSG);
                        break;
                    case JIM_TT_EXPRSUGAR:
-
                        wordObjPtr = JimExpandExprSugar(interp, token[i].objPtr);
+
                        retcode = Jim_EvalExpression(interp, token[i].objPtr);
+
                        if (retcode == JIM_OK) {
+
                            wordObjPtr = Jim_GetResult(interp);
+
                        }
+
                        else {
+
                            wordObjPtr = NULL;
+
                        }
                        break;
                    case JIM_TT_DICTSUGAR:
                        wordObjPtr = JimExpandDictSugar(interp, token[i].objPtr);
@@ -15221,16 +16422,10 @@ int Jim_EvalObj(Jim_Interp *interp, Jim_Obj *scriptObjPtr)


    if (retcode == JIM_ERR) {
-
        JimAddErrorToStack(interp, script);
-
    }
-

-
    else if (retcode != JIM_RETURN || interp->returnCode != JIM_ERR) {
-

-
        interp->addStackTrace = 0;
+
        JimSetErrorStack(interp);
    }

-

-
    interp->currentScriptObj = prevScriptObj;
+
    JimPopEvalFrame(interp);

    Jim_FreeIntRep(interp, scriptObjPtr);
    scriptObjPtr->typePtr = &scriptObjType;
@@ -15287,7 +16482,7 @@ static void JimSetProcWrongArgs(Jim_Interp *interp, Jim_Obj *procNameObj, Jim_Cm
            }
            else {

-
                Jim_AppendString(interp, argmsg, "?arg...?", -1);
+
                Jim_AppendString(interp, argmsg, "?arg ...?", -1);
            }
        }
        else {
@@ -15316,13 +16511,11 @@ int Jim_EvalNamespace(Jim_Interp *interp, Jim_Obj *scriptObj, Jim_Obj *nsObj)


    callFramePtr = JimCreateCallFrame(interp, interp->framePtr, nsObj);
-
    callFramePtr->argv = &interp->emptyObj;
-
    callFramePtr->argc = 0;
+
    callFramePtr->argv = interp->evalFrame->argv;
+
    callFramePtr->argc = interp->evalFrame->argc;
    callFramePtr->procArgsObjPtr = NULL;
    callFramePtr->procBodyObjPtr = scriptObj;
    callFramePtr->staticVars = NULL;
-
    callFramePtr->fileNameObj = interp->emptyObj;
-
    callFramePtr->line = 0;
    Jim_IncrRefCount(scriptObj);
    interp->framePtr = callFramePtr;

@@ -15348,7 +16541,6 @@ static int JimCallProcedure(Jim_Interp *interp, Jim_Cmd *cmd, int argc, Jim_Obj
{
    Jim_CallFrame *callFramePtr;
    int i, d, retcode, optargs;
-
    ScriptObj *script;


    if (argc - 1 < cmd->u.proc.reqArity ||
@@ -15376,10 +16568,7 @@ static int JimCallProcedure(Jim_Interp *interp, Jim_Cmd *cmd, int argc, Jim_Obj
    callFramePtr->procBodyObjPtr = cmd->u.proc.bodyObjPtr;
    callFramePtr->staticVars = cmd->u.proc.staticVars;

-

-
    script = JimGetScript(interp, interp->currentScriptObj);
-
    callFramePtr->fileNameObj = script->fileNameObj;
-
    callFramePtr->line = script->linenr;
+
    interp->procLevel++;

    Jim_IncrRefCount(cmd->u.proc.argListObjPtr);
    Jim_IncrRefCount(cmd->u.proc.bodyObjPtr);
@@ -15427,8 +16616,11 @@ static int JimCallProcedure(Jim_Interp *interp, Jim_Cmd *cmd, int argc, Jim_Obj
        }
    }

+
    if (interp->traceCmdObj == NULL ||
+
        (retcode = JimTraceCallback(interp, "proc", argc, argv)) == JIM_OK) {

-
    retcode = Jim_EvalObj(interp, cmd->u.proc.bodyObjPtr);
+
        retcode = Jim_EvalObj(interp, cmd->u.proc.bodyObjPtr);
+
    }

badargset:

@@ -15438,29 +16630,6 @@ badargset:
    JimFreeCallFrame(interp, callFramePtr, JIM_FCF_REUSE);


-
    if (interp->framePtr->tailcallObj) {
-
        do {
-
            Jim_Obj *tailcallObj = interp->framePtr->tailcallObj;
-

-
            interp->framePtr->tailcallObj = NULL;
-

-
            if (retcode == JIM_EVAL) {
-
                retcode = Jim_EvalObjList(interp, tailcallObj);
-
                if (retcode == JIM_RETURN) {
-
                    interp->returnLevel++;
-
                }
-
            }
-
            Jim_DecrRefCount(interp, tailcallObj);
-
        } while (interp->framePtr->tailcallObj);
-

-

-
        if (interp->framePtr->tailcallCmd) {
-
            JimDecrCmdRefCount(interp, interp->framePtr->tailcallCmd);
-
            interp->framePtr->tailcallCmd = NULL;
-
        }
-
    }
-

-

    if (retcode == JIM_RETURN) {
        if (--interp->returnLevel <= 0) {
            retcode = interp->returnCode;
@@ -15468,12 +16637,7 @@ badargset:
            interp->returnLevel = 0;
        }
    }
-
    else if (retcode == JIM_ERR) {
-
        interp->addStackTrace++;
-
        Jim_DecrRefCount(interp, interp->errorProc);
-
        interp->errorProc = argv[0];
-
        Jim_IncrRefCount(interp->errorProc);
-
    }
+
    interp->procLevel--;

    return retcode;
}
@@ -15485,22 +16649,10 @@ int Jim_EvalSource(Jim_Interp *interp, const char *filename, int lineno, const c

    scriptObjPtr = Jim_NewStringObj(interp, script, -1);
    Jim_IncrRefCount(scriptObjPtr);
-

    if (filename) {
-
        Jim_Obj *prevScriptObj;
-

        JimSetSourceInfo(interp, scriptObjPtr, Jim_NewStringObj(interp, filename, -1), lineno);
-

-
        prevScriptObj = interp->currentScriptObj;
-
        interp->currentScriptObj = scriptObjPtr;
-

-
        retval = Jim_EvalObj(interp, scriptObjPtr);
-

-
        interp->currentScriptObj = prevScriptObj;
-
    }
-
    else {
-
        retval = Jim_EvalObj(interp, scriptObjPtr);
    }
+
    retval = Jim_EvalObj(interp, scriptObjPtr);
    Jim_DecrRefCount(interp, scriptObjPtr);
    return retval;
}
@@ -15532,50 +16684,62 @@ int Jim_EvalFileGlobal(Jim_Interp *interp, const char *filename)
    retval = Jim_EvalFile(interp, filename);
    interp->framePtr = savedFramePtr;

-
    return retval;
+
    return retval;
+
}
+

+
#include <sys/stat.h>
+

+
static Jim_Obj *JimReadTextFile(Jim_Interp *interp, const char *filename)
+
{
+
    jim_stat_t sb;
+
    int fd;
+
    char *buf;
+
    int readlen;
+

+
    if (Jim_Stat(filename, &sb) == -1 || (fd = open(filename, O_RDONLY | O_TEXT, 0666)) < 0) {
+
        Jim_SetResultFormatted(interp, "couldn't read file \"%s\": %s", filename, strerror(errno));
+
        return NULL;
+
    }
+
    buf = Jim_Alloc(sb.st_size + 1);
+
    readlen = read(fd, buf, sb.st_size);
+
    close(fd);
+
    if (readlen < 0) {
+
        Jim_Free(buf);
+
        Jim_SetResultFormatted(interp, "failed to load file \"%s\": %s", filename, strerror(errno));
+
        return NULL;
+
    }
+
    else {
+
        Jim_Obj *objPtr;
+
        buf[readlen] = 0;
+

+
        objPtr = Jim_NewStringObjNoAlloc(interp, buf, readlen);
+

+
        return objPtr;
+
    }
}

-
#include <sys/stat.h>

int Jim_EvalFile(Jim_Interp *interp, const char *filename)
{
-
    FILE *fp;
-
    char *buf;
+
    Jim_Obj *filenameObj;
+
    Jim_Obj *oldFilenameObj;
    Jim_Obj *scriptObjPtr;
-
    Jim_Obj *prevScriptObj;
-
    struct stat sb;
    int retcode;
-
    int readlen;

-
    if (stat(filename, &sb) != 0 || (fp = fopen(filename, "rt")) == NULL) {
-
        Jim_SetResultFormatted(interp, "couldn't read file \"%s\": %s", filename, strerror(errno));
-
        return JIM_ERR;
-
    }
-
    if (sb.st_size == 0) {
-
        fclose(fp);
-
        return JIM_OK;
-
    }
-

-
    buf = Jim_Alloc(sb.st_size + 1);
-
    readlen = fread(buf, 1, sb.st_size, fp);
-
    if (ferror(fp)) {
-
        fclose(fp);
-
        Jim_Free(buf);
-
        Jim_SetResultFormatted(interp, "failed to load file \"%s\": %s", filename, strerror(errno));
+
    scriptObjPtr = JimReadTextFile(interp, filename);
+
    if (!scriptObjPtr) {
        return JIM_ERR;
    }
-
    fclose(fp);
-
    buf[readlen] = 0;

-
    scriptObjPtr = Jim_NewStringObjNoAlloc(interp, buf, readlen);
-
    JimSetSourceInfo(interp, scriptObjPtr, Jim_NewStringObj(interp, filename, -1), 1);
-
    Jim_IncrRefCount(scriptObjPtr);
+
    filenameObj = Jim_NewStringObj(interp, filename, -1);
+
    JimSetSourceInfo(interp, scriptObjPtr, filenameObj, 1);

-
    prevScriptObj = interp->currentScriptObj;
-
    interp->currentScriptObj = scriptObjPtr;
+
    oldFilenameObj = JimPushInterpObj(interp->currentFilenameObj, filenameObj);

    retcode = Jim_EvalObj(interp, scriptObjPtr);

+
    JimPopInterpObj(interp, interp->currentFilenameObj, oldFilenameObj);
+


    if (retcode == JIM_RETURN) {
        if (--interp->returnLevel <= 0) {
@@ -15584,14 +16748,6 @@ int Jim_EvalFile(Jim_Interp *interp, const char *filename)
            interp->returnLevel = 0;
        }
    }
-
    if (retcode == JIM_ERR) {
-

-
        interp->addStackTrace++;
-
    }
-

-
    interp->currentScriptObj = prevScriptObj;
-

-
    Jim_DecrRefCount(interp, scriptObjPtr);

    return retcode;
}
@@ -15698,7 +16854,11 @@ static ScriptObj *Jim_GetSubst(Jim_Interp *interp, Jim_Obj *objPtr, int flags)

int Jim_SubstObj(Jim_Interp *interp, Jim_Obj *substObjPtr, Jim_Obj **resObjPtrPtr, int flags)
{
-
    ScriptObj *script = Jim_GetSubst(interp, substObjPtr, flags);
+
    ScriptObj *script;
+

+
    JimPanic((substObjPtr->refCount == 0, "Jim_SubstObj() called with zero refcount object"));
+

+
    script = Jim_GetSubst(interp, substObjPtr, flags);

    Jim_IncrRefCount(substObjPtr);
    script->inUse++;
@@ -15733,7 +16893,7 @@ void Jim_WrongNumArgs(Jim_Interp *interp, int argc, Jim_Obj *const *argv, const
}

typedef void JimHashtableIteratorCallbackType(Jim_Interp *interp, Jim_Obj *listObjPtr,
-
    Jim_HashEntry *he, int type);
+
    Jim_Obj *keyObjPtr, void *value, Jim_Obj *patternObjPtr, int type);

#define JimTrivialMatch(pattern)    (strpbrk((pattern), "*[?\\") == NULL)

@@ -15745,18 +16905,18 @@ static Jim_Obj *JimHashtablePatternMatch(Jim_Interp *interp, Jim_HashTable *ht,


    if (patternObjPtr && JimTrivialMatch(Jim_String(patternObjPtr))) {
-
        he = Jim_FindHashEntry(ht, Jim_String(patternObjPtr));
+
        he = Jim_FindHashEntry(ht, patternObjPtr);
        if (he) {
-
            callback(interp, listObjPtr, he, type);
+
            callback(interp, listObjPtr, Jim_GetHashEntryKey(he), Jim_GetHashEntryVal(he),
+
                patternObjPtr, type);
        }
    }
    else {
        Jim_HashTableIterator htiter;
        JimInitHashTableIterator(ht, &htiter);
        while ((he = Jim_NextHashEntry(&htiter)) != NULL) {
-
            if (patternObjPtr == NULL || JimGlobMatch(Jim_String(patternObjPtr), he->key, 0)) {
-
                callback(interp, listObjPtr, he, type);
-
            }
+
            callback(interp, listObjPtr, Jim_GetHashEntryKey(he), Jim_GetHashEntryVal(he),
+
                patternObjPtr, type);
        }
    }
    return listObjPtr;
@@ -15768,26 +16928,37 @@ static Jim_Obj *JimHashtablePatternMatch(Jim_Interp *interp, Jim_HashTable *ht,
#define JIM_CMDLIST_CHANNELS 2

static void JimCommandMatch(Jim_Interp *interp, Jim_Obj *listObjPtr,
-
    Jim_HashEntry *he, int type)
+
    Jim_Obj *keyObj, void *value, Jim_Obj *patternObj, int type)
{
-
    Jim_Cmd *cmdPtr = Jim_GetHashEntryVal(he);
-
    Jim_Obj *objPtr;
+
    Jim_Cmd *cmdPtr = (Jim_Cmd *)value;

    if (type == JIM_CMDLIST_PROCS && !cmdPtr->isproc) {

        return;
    }

-
    objPtr = Jim_NewStringObj(interp, he->key, -1);
-
    Jim_IncrRefCount(objPtr);
+
    Jim_IncrRefCount(keyObj);
+

+
    if (type != JIM_CMDLIST_CHANNELS || Jim_AioFilehandle(interp, keyObj) >= 0) {
+
        int match = 1;
+
        if (patternObj) {
+
            int plen, slen;
+
            const char *pattern = Jim_GetStringNoQualifier(patternObj, &plen);
+
            const char *str = Jim_GetStringNoQualifier(keyObj, &slen);
+
#ifdef JIM_NO_INTROSPECTION

-
    if (type != JIM_CMDLIST_CHANNELS || Jim_AioFilehandle(interp, objPtr)) {
-
        Jim_ListAppendElement(interp, listObjPtr, objPtr);
+
            match = (JimStringCompareUtf8(pattern, plen, str, slen, 0) == 0);
+
#else
+
            match = JimGlobMatch(pattern, plen, str, slen, 0);
+
#endif
+
        }
+
        if (match) {
+
            Jim_ListAppendElement(interp, listObjPtr, keyObj);
+
        }
    }
-
    Jim_DecrRefCount(interp, objPtr);
+
    Jim_DecrRefCount(interp, keyObj);
}

-

static Jim_Obj *JimCommandsList(Jim_Interp *interp, Jim_Obj *patternObjPtr, int type)
{
    return JimHashtablePatternMatch(interp, &interp->commands, patternObjPtr, JimCommandMatch, type);
@@ -15797,18 +16968,21 @@ static Jim_Obj *JimCommandsList(Jim_Interp *interp, Jim_Obj *patternObjPtr, int
#define JIM_VARLIST_GLOBALS 0
#define JIM_VARLIST_LOCALS 1
#define JIM_VARLIST_VARS 2
+
#define JIM_VARLIST_MASK 0x000f

#define JIM_VARLIST_VALUES 0x1000

static void JimVariablesMatch(Jim_Interp *interp, Jim_Obj *listObjPtr,
-
    Jim_HashEntry *he, int type)
+
    Jim_Obj *keyObj, void *value, Jim_Obj *patternObj, int type)
{
-
    Jim_Var *varPtr = Jim_GetHashEntryVal(he);
+
    Jim_VarVal *vv = (Jim_VarVal *)value;

-
    if (type != JIM_VARLIST_LOCALS || varPtr->linkFramePtr == NULL) {
-
        Jim_ListAppendElement(interp, listObjPtr, Jim_NewStringObj(interp, he->key, -1));
-
        if (type & JIM_VARLIST_VALUES) {
-
            Jim_ListAppendElement(interp, listObjPtr, varPtr->objPtr);
+
    if ((type & JIM_VARLIST_MASK) != JIM_VARLIST_LOCALS || vv->linkFramePtr == NULL) {
+
        if (patternObj == NULL || Jim_StringMatchObj(interp, patternObj, keyObj, 0)) {
+
            Jim_ListAppendElement(interp, listObjPtr, keyObj);
+
            if (type & JIM_VARLIST_VALUES) {
+
                Jim_ListAppendElement(interp, listObjPtr, vv->objPtr);
+
            }
        }
    }
}
@@ -15821,40 +16995,76 @@ static Jim_Obj *JimVariablesList(Jim_Interp *interp, Jim_Obj *patternObjPtr, int
    }
    else {
        Jim_CallFrame *framePtr = (mode == JIM_VARLIST_GLOBALS) ? interp->topFramePtr : interp->framePtr;
-
        return JimHashtablePatternMatch(interp, &framePtr->vars, patternObjPtr, JimVariablesMatch, mode);
+
        return JimHashtablePatternMatch(interp, &framePtr->vars, patternObjPtr, JimVariablesMatch,
+
            mode);
    }
}

-
static int JimInfoLevel(Jim_Interp *interp, Jim_Obj *levelObjPtr,
-
    Jim_Obj **objPtrPtr, int info_level_cmd)
+
static int JimInfoLevel(Jim_Interp *interp, Jim_Obj *levelObjPtr, Jim_Obj **objPtrPtr)
{
-
    Jim_CallFrame *targetCallFrame;
+
    long level;

-
    targetCallFrame = JimGetCallFrameByInteger(interp, levelObjPtr);
-
    if (targetCallFrame == NULL) {
-
        return JIM_ERR;
-
    }
+
    if (Jim_GetLong(interp, levelObjPtr, &level) == JIM_OK) {
+
        Jim_CallFrame *targetCallFrame = JimGetCallFrameByInteger(interp, level);
+
        if (targetCallFrame && targetCallFrame != interp->topFramePtr) {
+
#ifdef JIM_NO_INTROSPECTION

-
    if (targetCallFrame == interp->topFramePtr) {
-
        Jim_SetResultFormatted(interp, "bad level \"%#s\"", levelObjPtr);
-
        return JIM_ERR;
-
    }
-
    if (info_level_cmd) {
-
        *objPtrPtr = Jim_NewListObj(interp, targetCallFrame->argv, targetCallFrame->argc);
+
            *objPtrPtr = Jim_NewListObj(interp, targetCallFrame->argv, 1);
+
#else
+
            *objPtrPtr = Jim_NewListObj(interp, targetCallFrame->argv, targetCallFrame->argc);
+
#endif
+
            return JIM_OK;
+
        }
    }
-
    else {
-
        Jim_Obj *listObj = Jim_NewListObj(interp, NULL, 0);
+
    Jim_SetResultFormatted(interp, "bad level \"%#s\"", levelObjPtr);
+
    return JIM_ERR;
+
}
+

+
static int JimInfoFrame(Jim_Interp *interp, Jim_Obj *levelObjPtr, Jim_Obj **objPtrPtr)
+
{
+
    long level;
+

+
    if (Jim_GetLong(interp, levelObjPtr, &level) == JIM_OK) {
+
        Jim_EvalFrame *frame = JimGetEvalFrameByProcLevel(interp, level);
+
        if (frame) {
+
            Jim_Obj *listObj = Jim_NewListObj(interp, NULL, 0);
+

+
            Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, "type", -1));
+
            Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, "source", -1));
+
            if (frame->scriptObj) {
+
                ScriptObj *script = JimGetScript(interp, frame->scriptObj);
+
                Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, "line", -1));
+
                Jim_ListAppendElement(interp, listObj, Jim_NewIntObj(interp, script->linenr));
+
                Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, "file", -1));
+
                Jim_ListAppendElement(interp, listObj, script->fileNameObj);
+
            }
+
#ifndef JIM_NO_INTROSPECTION
+
            {
+
                Jim_Obj *cmdObj = Jim_NewListObj(interp, frame->argv, frame->argc);
+

+
                Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, "cmd", -1));
+
                Jim_ListAppendElement(interp, listObj, cmdObj);
+
            }
+
#endif
+
            {
+
                Jim_Obj *procNameObj = JimProcForEvalFrame(interp, frame);
+
                if (procNameObj) {
+
                    Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, "proc", -1));
+
                    Jim_ListAppendElement(interp, listObj, procNameObj);
+
                 }
+
            }
+
            Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, "level", -1));
+
            Jim_ListAppendElement(interp, listObj, Jim_NewIntObj(interp, interp->framePtr->level - frame->framePtr->level));

-
        Jim_ListAppendElement(interp, listObj, targetCallFrame->argv[0]);
-
        Jim_ListAppendElement(interp, listObj, targetCallFrame->fileNameObj);
-
        Jim_ListAppendElement(interp, listObj, Jim_NewIntObj(interp, targetCallFrame->line));
-
        *objPtrPtr = listObj;
+
            *objPtrPtr = listObj;
+
            return JIM_OK;
+
        }
    }
-
    return JIM_OK;
+
    Jim_SetResultFormatted(interp, "bad level \"%#s\"", levelObjPtr);
+
    return JIM_ERR;
}


-

static int Jim_PutsCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
    if (argc != 2 && argc != 3) {
@@ -16058,9 +17268,21 @@ static int Jim_UnsetCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *ar
        }
        i++;
    }
+

+
    Jim_SetEmptyResult(interp);
    return JIM_OK;
}

+
static int JimCheckLoopRetcode(Jim_Interp *interp, int retval)
+
{
+
    if (retval == JIM_BREAK || retval == JIM_CONTINUE) {
+
        if (--interp->returnLevel > 0) {
+
            return 1;
+
        }
+
    }
+
    return 0;
+
}
+


static int Jim_WhileCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
@@ -16071,7 +17293,7 @@ static int Jim_WhileCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *ar


    while (1) {
-
        int boolean, retval;
+
        int boolean = 0, retval;

        if ((retval = Jim_GetBoolFromExpr(interp, argv[1], &boolean)) != JIM_OK)
            return retval;
@@ -16079,13 +17301,14 @@ static int Jim_WhileCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *ar
            break;

        if ((retval = Jim_EvalObj(interp, argv[2])) != JIM_OK) {
+
            if (JimCheckLoopRetcode(interp, retval)) {
+
                return retval;
+
            }
            switch (retval) {
                case JIM_BREAK:
                    goto out;
-
                    break;
                case JIM_CONTINUE:
                    continue;
-
                    break;
                default:
                    return retval;
            }
@@ -16101,6 +17324,7 @@ static int Jim_ForCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv
{
    int retval;
    int boolean = 1;
+
    int immediate = 0;
    Jim_Obj *varNamePtr = NULL;
    Jim_Obj *stopVarNamePtr = NULL;

@@ -16168,7 +17392,7 @@ static int Jim_ForCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv


        if (expr->expr->right->type == JIM_TT_EXPR_INT) {
-
            if (Jim_GetWide(interp, expr->expr->right->objPtr, &stop) == JIM_ERR) {
+
            if (Jim_GetWideExpr(interp, expr->expr->right->objPtr, &stop) == JIM_ERR) {
                goto evalstart;
            }
        }
@@ -16207,6 +17431,10 @@ static int Jim_ForCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv


            retval = Jim_EvalObj(interp, argv[4]);
+
            if (JimCheckLoopRetcode(interp, retval)) {
+
                immediate++;
+
                goto out;
+
            }
            if (retval == JIM_OK || retval == JIM_CONTINUE) {
                retval = JIM_OK;

@@ -16243,6 +17471,10 @@ static int Jim_ForCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv

JIM_IF_OPTIM(evalnext:)
            retval = Jim_EvalObj(interp, argv[3]);
+
            if (JimCheckLoopRetcode(interp, retval)) {
+
                immediate++;
+
                goto out;
+
            }
            if (retval == JIM_OK || retval == JIM_CONTINUE) {

JIM_IF_OPTIM(testcond:)
@@ -16258,9 +17490,11 @@ JIM_IF_OPTIM(out:)
        Jim_DecrRefCount(interp, varNamePtr);
    }

-
    if (retval == JIM_CONTINUE || retval == JIM_BREAK || retval == JIM_OK) {
-
        Jim_SetEmptyResult(interp);
-
        return JIM_OK;
+
    if (!immediate) {
+
        if (retval == JIM_CONTINUE || retval == JIM_BREAK || retval == JIM_OK) {
+
            Jim_SetEmptyResult(interp);
+
            return JIM_OK;
+
        }
    }

    return retval;
@@ -16275,22 +17509,34 @@ static int Jim_LoopCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *arg
    jim_wide incr = 1;
    Jim_Obj *bodyObjPtr;

-
    if (argc != 5 && argc != 6) {
-
        Jim_WrongNumArgs(interp, 1, argv, "var first limit ?incr? body");
+
    if (argc < 4 || argc > 6) {
+
        Jim_WrongNumArgs(interp, 1, argv, "var ?first? limit ?incr? body");
        return JIM_ERR;
    }

-
    if (Jim_GetWide(interp, argv[2], &i) != JIM_OK ||
-
        Jim_GetWide(interp, argv[3], &limit) != JIM_OK ||
-
          (argc == 6 && Jim_GetWide(interp, argv[4], &incr) != JIM_OK)) {
-
        return JIM_ERR;
+
    retval = Jim_GetWideExpr(interp, argv[2], &i);
+
    if (argc > 4 && retval == JIM_OK) {
+
        retval = Jim_GetWideExpr(interp, argv[3], &limit);
+
    }
+
    if (argc > 5 && retval == JIM_OK) {
+
        Jim_GetWideExpr(interp, argv[4], &incr);
+
    }
+
    if (retval != JIM_OK) {
+
        return retval;
    }
-
    bodyObjPtr = (argc == 5) ? argv[4] : argv[5];
+
    if (argc == 4) {
+
        limit = i;
+
        i = 0;
+
    }
+
    bodyObjPtr = argv[argc - 1];

-
    retval = Jim_SetVariable(interp, argv[1], argv[2]);
+
    retval = Jim_SetVariable(interp, argv[1], Jim_NewIntObj(interp, i));

    while (((i < limit && incr > 0) || (i > limit && incr < 0)) && retval == JIM_OK) {
        retval = Jim_EvalObj(interp, bodyObjPtr);
+
        if (JimCheckLoopRetcode(interp, retval)) {
+
            return retval;
+
        }
        if (retval == JIM_OK || retval == JIM_CONTINUE) {
            Jim_Obj *objPtr = Jim_GetVariable(interp, argv[1], JIM_ERRMSG);

@@ -16431,7 +17677,11 @@ static int JimForeachMapHelper(Jim_Interp *interp, int argc, Jim_Obj *const *arg
                }
            }
        }
-
        switch (result = Jim_EvalObj(interp, script)) {
+
        result = Jim_EvalObj(interp, script);
+
        if (JimCheckLoopRetcode(interp, result)) {
+
            goto err;
+
        }
+
        switch (result) {
            case JIM_OK:
                if (doMap) {
                    Jim_ListAppendElement(interp, resultObj, interp->result);
@@ -16552,19 +17802,21 @@ static int Jim_IfCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
}


-

int Jim_CommandMatchObj(Jim_Interp *interp, Jim_Obj *commandObj, Jim_Obj *patternObj,
-
    Jim_Obj *stringObj, int nocase)
+
    Jim_Obj *stringObj, int flags)
{
-
    Jim_Obj *parms[4];
+
    Jim_Obj *parms[5];
    int argc = 0;
    long eq;
    int rc;

    parms[argc++] = commandObj;
-
    if (nocase) {
+
    if (flags & JIM_NOCASE) {
        parms[argc++] = Jim_NewStringObj(interp, "-nocase", -1);
    }
+
    if (flags & JIM_OPT_END) {
+
        parms[argc++] = Jim_NewStringObj(interp, "--", -1);
+
    }
    parms[argc++] = patternObj;
    parms[argc++] = stringObj;

@@ -16582,6 +17834,7 @@ static int Jim_SwitchCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *a
{
    enum { SWITCH_EXACT, SWITCH_GLOB, SWITCH_RE, SWITCH_CMD };
    int matchOpt = SWITCH_EXACT, opt = 1, patCount, i;
+
    int match_flags = 0;
    Jim_Obj *command = NULL, *scriptObj = NULL, *strObj;
    Jim_Obj **caseList;

@@ -16604,8 +17857,10 @@ static int Jim_SwitchCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *a
            matchOpt = SWITCH_EXACT;
        else if (strncmp(option, "-glob", 2) == 0)
            matchOpt = SWITCH_GLOB;
-
        else if (strncmp(option, "-regexp", 2) == 0)
+
        else if (strncmp(option, "-regexp", 2) == 0) {
            matchOpt = SWITCH_RE;
+
            match_flags |= JIM_OPT_END;
+
        }
        else if (strncmp(option, "-command", 2) == 0) {
            matchOpt = SWITCH_CMD;
            if ((argc - opt) < 2)
@@ -16648,7 +17903,7 @@ static int Jim_SwitchCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *a
                    command = Jim_NewStringObj(interp, "regexp", -1);

                case SWITCH_CMD:{
-
                        int rc = Jim_CommandMatchObj(interp, command, patObj, strObj, 0);
+
                        int rc = Jim_CommandMatchObj(interp, command, patObj, strObj, match_flags);

                        if (argc - opt == 1) {
                            JimListGetElements(interp, argv[opt], &patCount, &caseList);
@@ -16693,33 +17948,22 @@ static int Jim_ListCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *arg

static int Jim_LindexCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
-
    Jim_Obj *objPtr, *listObjPtr;
-
    int i;
-
    int idx;
+
    Jim_Obj *objPtr;
+
    int ret;

    if (argc < 2) {
        Jim_WrongNumArgs(interp, 1, argv, "list ?index ...?");
        return JIM_ERR;
    }
-
    objPtr = argv[1];
-
    Jim_IncrRefCount(objPtr);
-
    for (i = 2; i < argc; i++) {
-
        listObjPtr = objPtr;
-
        if (Jim_GetIndex(interp, argv[i], &idx) != JIM_OK) {
-
            Jim_DecrRefCount(interp, listObjPtr);
-
            return JIM_ERR;
-
        }
-
        if (Jim_ListIndex(interp, listObjPtr, idx, &objPtr, JIM_NONE) != JIM_OK) {
-
            Jim_DecrRefCount(interp, listObjPtr);
-
            Jim_SetEmptyResult(interp);
-
            return JIM_OK;
-
        }
-
        Jim_IncrRefCount(objPtr);
-
        Jim_DecrRefCount(interp, listObjPtr);
+
    ret = Jim_ListIndices(interp, argv[1], argv + 2, argc - 2, &objPtr, JIM_NONE);
+
    if (ret < 0) {
+
        ret = JIM_OK;
+
        Jim_SetEmptyResult(interp);
    }
-
    Jim_SetResult(interp, objPtr);
-
    Jim_DecrRefCount(interp, objPtr);
-
    return JIM_OK;
+
    else if (ret == JIM_OK) {
+
        Jim_SetResult(interp, objPtr);
+
    }
+
    return ret;
}


@@ -16738,15 +17982,14 @@ static int Jim_LsearchCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *
{
    static const char * const options[] = {
        "-bool", "-not", "-nocase", "-exact", "-glob", "-regexp", "-all", "-inline", "-command",
-
            NULL
+
        "-stride", "-index", NULL
    };
    enum
    { OPT_BOOL, OPT_NOT, OPT_NOCASE, OPT_EXACT, OPT_GLOB, OPT_REGEXP, OPT_ALL, OPT_INLINE,
-
            OPT_COMMAND };
+
            OPT_COMMAND, OPT_STRIDE, OPT_INDEX };
    int i;
    int opt_bool = 0;
    int opt_not = 0;
-
    int opt_nocase = 0;
    int opt_all = 0;
    int opt_inline = 0;
    int opt_match = OPT_EXACT;
@@ -16754,11 +17997,14 @@ static int Jim_LsearchCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *
    int rc = JIM_OK;
    Jim_Obj *listObjPtr = NULL;
    Jim_Obj *commandObj = NULL;
+
    Jim_Obj *indexObj = NULL;
+
    int match_flags = 0;
+
    long stride = 1;

    if (argc < 3) {
      wrongargs:
        Jim_WrongNumArgs(interp, 1, argv,
-
            "?-exact|-glob|-regexp|-command 'command'? ?-bool|-inline? ?-not? ?-nocase? ?-all? list value");
+
            "?-exact|-glob|-regexp|-command 'command'? ?-bool|-inline? ?-not? ?-nocase? ?-all? ?-stride len? ?-index val? list value");
        return JIM_ERR;
    }

@@ -16777,7 +18023,7 @@ static int Jim_LsearchCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *
                opt_not = 1;
                break;
            case OPT_NOCASE:
-
                opt_nocase = 1;
+
                match_flags |= JIM_NOCASE;
                break;
            case OPT_INLINE:
                opt_inline = 1;
@@ -16786,6 +18032,10 @@ static int Jim_LsearchCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *
            case OPT_ALL:
                opt_all = 1;
                break;
+
            case OPT_REGEXP:
+
                opt_match = option;
+
                match_flags |= JIM_OPT_END;
+
                break;
            case OPT_COMMAND:
                if (i >= argc - 2) {
                    goto wrongargs;
@@ -16794,14 +18044,41 @@ static int Jim_LsearchCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *

            case OPT_EXACT:
            case OPT_GLOB:
-
            case OPT_REGEXP:
                opt_match = option;
                break;
+
            case OPT_INDEX:
+
                if (i >= argc - 2) {
+
                    goto wrongargs;
+
                }
+
                indexObj = argv[++i];
+
                break;
+
            case OPT_STRIDE:
+
                if (i >= argc - 2) {
+
                    goto wrongargs;
+
                }
+
                if (Jim_GetLong(interp, argv[++i], &stride) != JIM_OK) {
+
                    return JIM_ERR;
+
                }
+
                if (stride < 1) {
+
                    Jim_SetResultString(interp, "stride length must be at least 1", -1);
+
                    return JIM_ERR;
+
                }
+
                break;
        }
    }

+
    argc -= i;
+
    if (argc < 2) {
+
        goto wrongargs;
+
    }
    argv += i;

+
    listlen = Jim_ListLength(interp, argv[0]);
+
    if (listlen % stride) {
+
        Jim_SetResultString(interp, "list size must be a multiple of the stride length", -1);
+
        return JIM_ERR;
+
    }
+

    if (opt_all) {
        listObjPtr = Jim_NewListObj(interp, NULL, 0);
    }
@@ -16812,27 +18089,52 @@ static int Jim_LsearchCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *
        Jim_IncrRefCount(commandObj);
    }

-
    listlen = Jim_ListLength(interp, argv[0]);
-
    for (i = 0; i < listlen; i++) {
+
    for (i = 0; i < listlen; i += stride) {
        int eq = 0;
-
        Jim_Obj *objPtr = Jim_ListGetIndex(interp, argv[0], i);
+
        Jim_Obj *searchListObj;
+
        Jim_Obj *objPtr;
+
        int offset;
+

+
        if (indexObj) {
+
            int indexlen = Jim_ListLength(interp, indexObj);
+
            if (stride == 1) {
+
                searchListObj = Jim_ListGetIndex(interp, argv[0], i);
+
            }
+
            else {
+
                searchListObj = Jim_NewListObj(interp, argv[0]->internalRep.listValue.ele + i, stride);
+
            }
+
            Jim_IncrRefCount(searchListObj);
+
            rc = Jim_ListIndices(interp, searchListObj, indexObj->internalRep.listValue.ele, indexlen, &objPtr, JIM_ERRMSG);
+
            if (rc != JIM_OK) {
+
                Jim_DecrRefCount(interp, searchListObj);
+
                rc = JIM_ERR;
+
                goto done;
+
            }
+

+
            offset = 0;
+
        }
+
        else {
+

+
            searchListObj = argv[0];
+
            offset = i;
+
            objPtr = Jim_ListGetIndex(interp, searchListObj, i);
+
            Jim_IncrRefCount(searchListObj);
+
        }

        switch (opt_match) {
            case OPT_EXACT:
-
                eq = Jim_StringCompareObj(interp, argv[1], objPtr, opt_nocase) == 0;
+
                eq = Jim_StringCompareObj(interp, argv[1], objPtr, match_flags) == 0;
                break;

            case OPT_GLOB:
-
                eq = Jim_StringMatchObj(interp, argv[1], objPtr, opt_nocase);
+
                eq = Jim_StringMatchObj(interp, argv[1], objPtr, match_flags);
                break;

            case OPT_REGEXP:
            case OPT_COMMAND:
-
                eq = Jim_CommandMatchObj(interp, commandObj, argv[1], objPtr, opt_nocase);
+
                eq = Jim_CommandMatchObj(interp, commandObj, argv[1], objPtr, match_flags);
                if (eq < 0) {
-
                    if (listObjPtr) {
-
                        Jim_FreeNewObj(interp, listObjPtr);
-
                    }
+
                    Jim_DecrRefCount(interp, searchListObj);
                    rc = JIM_ERR;
                    goto done;
                }
@@ -16840,12 +18142,7 @@ static int Jim_LsearchCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *
        }


-
        if (!eq && opt_bool && opt_not && !opt_all) {
-
            continue;
-
        }
-

        if ((!opt_bool && eq == !opt_not) || (opt_bool && (eq || opt_all))) {
-

            Jim_Obj *resultObj;

            if (opt_bool) {
@@ -16854,22 +18151,38 @@ static int Jim_LsearchCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *
            else if (!opt_inline) {
                resultObj = Jim_NewIntObj(interp, i);
            }
-
            else {
+
            else if (stride == 1) {
                resultObj = objPtr;
            }
+
            else if (opt_all) {
+

+
                ListInsertElements(listObjPtr, -1, stride,
+
                    searchListObj->internalRep.listValue.ele + offset);
+

+
                resultObj = NULL;
+
            }
+
            else {
+
                resultObj = Jim_NewListObj(interp, searchListObj->internalRep.listValue.ele + offset, stride);
+
            }

            if (opt_all) {
-
                Jim_ListAppendElement(interp, listObjPtr, resultObj);
+

+
                if (stride == 1) {
+
                    Jim_ListAppendElement(interp, listObjPtr, resultObj);
+
                }
            }
            else {
                Jim_SetResult(interp, resultObj);
+
                Jim_DecrRefCount(interp, searchListObj);
                goto done;
            }
        }
+
        Jim_DecrRefCount(interp, searchListObj);
    }

    if (opt_all) {
        Jim_SetResult(interp, listObjPtr);
+
        listObjPtr = NULL;
    }
    else {

@@ -16882,6 +18195,9 @@ static int Jim_LsearchCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *
    }

  done:
+
    if (listObjPtr) {
+
        Jim_FreeNewObj(interp, listObjPtr);
+
    }
    if (commandObj) {
        Jim_DecrRefCount(interp, commandObj);
    }
@@ -16995,7 +18311,7 @@ static int Jim_LreplaceCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const
static int Jim_LsetCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
    if (argc < 3) {
-
        Jim_WrongNumArgs(interp, 1, argv, "listVar ?index...? newVal");
+
        Jim_WrongNumArgs(interp, 1, argv, "listVar ?index ...? value");
        return JIM_ERR;
    }
    else if (argc == 3) {
@@ -17012,25 +18328,30 @@ static int Jim_LsetCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *arg
static int Jim_LsortCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const argv[])
{
    static const char * const options[] = {
-
        "-ascii", "-nocase", "-increasing", "-decreasing", "-command", "-integer", "-real", "-index", "-unique", NULL
+
        "-ascii", "-nocase", "-increasing", "-decreasing", "-command", "-integer", "-real", "-index", "-unique",
+
        "-stride", NULL
+
    };
+
    enum {
+
        OPT_ASCII, OPT_NOCASE, OPT_INCREASING, OPT_DECREASING, OPT_COMMAND, OPT_INTEGER, OPT_REAL, OPT_INDEX, OPT_UNIQUE,
+
        OPT_STRIDE
    };
-
    enum
-
    { OPT_ASCII, OPT_NOCASE, OPT_INCREASING, OPT_DECREASING, OPT_COMMAND, OPT_INTEGER, OPT_REAL, OPT_INDEX, OPT_UNIQUE };
    Jim_Obj *resObj;
    int i;
    int retCode;
    int shared;
+
    long stride = 1;

    struct lsort_info info;

    if (argc < 2) {
+
wrongargs:
        Jim_WrongNumArgs(interp, 1, argv, "?options? list");
        return JIM_ERR;
    }

    info.type = JIM_LSORT_ASCII;
    info.order = 1;
-
    info.indexed = 0;
+
    info.indexc = 0;
    info.unique = 0;
    info.command = NULL;
    info.interp = interp;
@@ -17072,28 +18393,72 @@ static int Jim_LsortCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const arg
                info.command = argv[i + 1];
                i++;
                break;
+
            case OPT_STRIDE:
+
                if (i >= argc - 2) {
+
                    goto wrongargs;
+
                }
+
                if (Jim_GetLong(interp, argv[++i], &stride) != JIM_OK) {
+
                    return JIM_ERR;
+
                }
+
                if (stride < 2) {
+
                    Jim_SetResultString(interp, "stride length must be at least 2", -1);
+
                    return JIM_ERR;
+
                }
+
                break;
            case OPT_INDEX:
                if (i >= (argc - 2)) {
+
badindex:
                    Jim_SetResultString(interp, "\"-index\" option must be followed by list index", -1);
                    return JIM_ERR;
                }
-
                if (Jim_GetIndex(interp, argv[i + 1], &info.index) != JIM_OK) {
-
                    return JIM_ERR;
+
                JimListGetElements(interp, argv[i + 1], &info.indexc, &info.indexv);
+
                if (info.indexc == 0) {
+
                    goto badindex;
                }
-
                info.indexed = 1;
                i++;
                break;
        }
    }
    resObj = argv[argc - 1];
-
    if ((shared = Jim_IsShared(resObj)))
-
        resObj = Jim_DuplicateObj(interp, resObj);
-
    retCode = ListSortElements(interp, resObj, &info);
-
    if (retCode == JIM_OK) {
-
        Jim_SetResult(interp, resObj);
+
    if (stride > 1) {
+
        Jim_Obj *tmpListObj;
+
        Jim_Obj **elements;
+
        int listlen;
+
        int i;
+

+
        JimListGetElements(interp, resObj, &listlen, &elements);
+
        if (listlen % stride) {
+
            Jim_SetResultString(interp, "list size must be a multiple of the stride length", -1);
+
            return JIM_ERR;
+
        }
+

+
        tmpListObj = Jim_NewListObj(interp, NULL, 0);
+
        Jim_IncrRefCount(tmpListObj);
+
        for (i = 0; i < listlen; i += stride) {
+
            Jim_ListAppendElement(interp, tmpListObj, Jim_NewListObj(interp, elements + i, stride));
+
        }
+
        retCode = ListSortElements(interp, tmpListObj, &info);
+
        if (retCode == JIM_OK) {
+
            resObj = Jim_NewListObj(interp, NULL, 0);
+

+
            for (i = 0; i < listlen; i += stride) {
+
                Jim_ListAppendList(interp, resObj, Jim_ListGetIndex(interp, tmpListObj, i / stride));
+
            }
+
            Jim_SetResult(interp, resObj);
+
        }
+
        Jim_DecrRefCount(interp, tmpListObj);
    }
-
    else if (shared) {
-
        Jim_FreeNewObj(interp, resObj);
+
    else {
+
        if ((shared = Jim_IsShared(resObj))) {
+
            resObj = Jim_DuplicateObj(interp, resObj);
+
        }
+
        retCode = ListSortElements(interp, resObj, &info);
+
        if (retCode == JIM_OK) {
+
            Jim_SetResult(interp, resObj);
+
        }
+
        else if (shared) {
+
            Jim_FreeNewObj(interp, resObj);
+
        }
    }
    return retCode;
}
@@ -17141,13 +18506,6 @@ static int Jim_AppendCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *a



-
static int Jim_DebugCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
-
{
-
#if !defined(JIM_DEBUG_COMMAND)
-
    Jim_SetResultString(interp, "unsupported", -1);
-
    return JIM_ERR;
-
#endif
-
}


static int Jim_EvalCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
@@ -17166,10 +18524,6 @@ static int Jim_EvalCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *arg
        rc = Jim_EvalObj(interp, Jim_ConcatObj(interp, argc - 1, argv + 1));
    }

-
    if (rc == JIM_ERR) {
-

-
        interp->addStackTrace++;
-
    }
    return rc;
}

@@ -17226,6 +18580,12 @@ static int Jim_ExprCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *arg
    if (argc == 2) {
        retcode = Jim_EvalExpression(interp, argv[1]);
    }
+
#ifndef JIM_COMPAT
+
    else {
+
        Jim_WrongNumArgs(interp, 1, argv, "expression");
+
        retcode = JIM_ERR;
+
    }
+
#else
    else if (argc > 2) {
        Jim_Obj *objPtr;

@@ -17238,29 +18598,68 @@ static int Jim_ExprCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *arg
        Jim_WrongNumArgs(interp, 1, argv, "expression ?...?");
        return JIM_ERR;
    }
-
    if (retcode != JIM_OK)
-
        return retcode;
-
    return JIM_OK;
+
#endif
+
    return retcode;
}

-

-
static int Jim_BreakCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+
static int JimBreakContinueHelper(Jim_Interp *interp, int argc, Jim_Obj *const *argv, int retcode)
{
-
    if (argc != 1) {
-
        Jim_WrongNumArgs(interp, 1, argv, "");
+
    if (argc != 1 && argc != 2) {
+
        Jim_WrongNumArgs(interp, 1, argv, "?level?");
        return JIM_ERR;
    }
-
    return JIM_BREAK;
+
    if (argc == 2) {
+
        long level;
+
        int ret = Jim_GetLong(interp, argv[1], &level);
+
        if (ret != JIM_OK) {
+
            return ret;
+
        }
+
        interp->returnLevel = level;
+
    }
+
    return retcode;
+
}
+

+

+
static int Jim_BreakCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+
{
+
    return JimBreakContinueHelper(interp, argc, argv, JIM_BREAK);
+
}
+

+

+
static int Jim_ContinueCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+
{
+
    return JimBreakContinueHelper(interp, argc, argv, JIM_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;
+
static int Jim_StacktraceCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+
{
+
    Jim_Obj *listObj;
+
    int i;
+
    jim_wide skip = 0;
+
    jim_wide last = 0;
+

+
    if (argc > 1) {
+
        if (Jim_GetWideExpr(interp, argv[1], &skip) != JIM_OK) {
+
            return JIM_ERR;
+
        }
+
    }
+
    if (argc > 2) {
+
        if (Jim_GetWideExpr(interp, argv[2], &last) != JIM_OK) {
+
            return JIM_ERR;
+
        }
+
    }
+

+
    listObj = Jim_NewListObj(interp, NULL, 0);
+
    for (i = skip; i <= interp->procLevel; i++) {
+
        Jim_EvalFrame *frame = JimGetEvalFrameByProcLevel(interp, -i);
+
        if (frame->procLevel < last) {
+
            break;
+
        }
+
        JimAddStackFrame(interp, frame, listObj);
    }
-
    return JIM_CONTINUE;
+
    Jim_SetResult(interp, listObj);
+
    return JIM_OK;
}


@@ -17314,7 +18713,7 @@ static int Jim_ReturnCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *a
    if (i == argc - 1) {
        Jim_SetResult(interp, argv[i]);
    }
-
    return JIM_RETURN;
+
    return level == 0 ? returnCode : JIM_RETURN;
}


@@ -17372,7 +18771,6 @@ static void JimAliasCmdDelete(Jim_Interp *interp, void *privData)
static int Jim_AliasCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
    Jim_Obj *prefixListObj;
-
    const char *newname;

    if (argc < 3) {
        Jim_WrongNumArgs(interp, 1, argv, "newname command ?args ...?");
@@ -17381,15 +18779,9 @@ static int Jim_AliasCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *ar

    prefixListObj = Jim_NewListObj(interp, argv + 2, argc - 2);
    Jim_IncrRefCount(prefixListObj);
-
    newname = Jim_String(argv[1]);
-
    if (newname[0] == ':' && newname[1] == ':') {
-
        while (*++newname == ':') {
-
        }
-
    }
-

    Jim_SetResult(interp, argv[1]);

-
    return Jim_CreateCommand(interp, newname, JimAliasCmd, prefixListObj, JimAliasCmdDelete);
+
    return Jim_CreateCommandObj(interp, argv[1], JimAliasCmd, prefixListObj, JimAliasCmdDelete);
}


@@ -17402,10 +18794,6 @@ static int Jim_ProcCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *arg
        return JIM_ERR;
    }

-
    if (JimValidName(interp, "procedure", argv[1]) != JIM_OK) {
-
        return JIM_ERR;
-
    }
-

    if (argc == 4) {
        cmd = JimCreateProcedureCmd(interp, argv[2], NULL, argv[3], NULL);
    }
@@ -17415,15 +18803,12 @@ static int Jim_ProcCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *arg

    if (cmd) {

-
        Jim_Obj *qualifiedCmdNameObj;
-
        const char *cmdname = JimQualifyName(interp, Jim_String(argv[1]), &qualifiedCmdNameObj);
-

-
        JimCreateCommand(interp, cmdname, cmd);
+
        Jim_Obj *nameObjPtr = JimQualifyName(interp, argv[1]);
+
        JimCreateCommand(interp, nameObjPtr, cmd);


-
        JimUpdateProcNamespace(interp, cmd, cmdname);
-

-
        JimFreeQualifiedName(interp, qualifiedCmdNameObj);
+
        JimUpdateProcNamespace(interp, cmd, nameObjPtr);
+
        Jim_DecrRefCount(interp, nameObjPtr);


        Jim_SetResult(interp, argv[1]);
@@ -17433,6 +18818,27 @@ static int Jim_ProcCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *arg
}


+
static int Jim_XtraceCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+
{
+
    if (argc != 2) {
+
        Jim_WrongNumArgs(interp, 1, argv, "callback");
+
        return JIM_ERR;
+
    }
+

+
    if (interp->traceCmdObj) {
+
        Jim_DecrRefCount(interp, interp->traceCmdObj);
+
        interp->traceCmdObj = NULL;
+
    }
+

+
    if (Jim_Length(argv[1])) {
+

+
        interp->traceCmdObj = argv[1];
+
        Jim_IncrRefCount(interp->traceCmdObj);
+
    }
+
    return JIM_OK;
+
}
+

+

static int Jim_LocalCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
    int retcode;
@@ -17520,7 +18926,7 @@ static int Jim_ApplyCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *ar
        if (len == 3) {
#ifdef jim_ext_namespace

-
            nsObj = JimQualifyNameObj(interp, Jim_ListGetIndex(interp, argv[1], 2));
+
            nsObj = Jim_ListGetIndex(interp, argv[1], 2);
#else
            Jim_SetResultString(interp, "namespaces not enabled", -1);
            return JIM_ERR;
@@ -17643,7 +19049,7 @@ static Jim_Obj *JimStringMap(Jim_Interp *interp, Jim_Obj *mapListObjPtr,

            if (strLen >= kl && kl) {
                int rc;
-
                rc = JimStringCompareLen(str, k, kl, nocase);
+
                rc = JimStringCompareUtf8(str, kl, k, kl, nocase);
                if (rc == 0) {
                    if (noMatchStart) {
                        Jim_AppendString(interp, resultObjPtr, noMatchStart, str - noMatchStart);
@@ -17676,17 +19082,6 @@ static int Jim_StringCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *a
    int len;
    int opt_case = 1;
    int option;
-
    static const char * const options[] = {
-
        "bytelength", "length", "compare", "match", "equal", "is", "byterange", "range", "replace",
-
        "map", "repeat", "reverse", "index", "first", "last", "cat",
-
        "trim", "trimleft", "trimright", "tolower", "toupper", "totitle", NULL
-
    };
-
    enum
-
    {
-
        OPT_BYTELENGTH, OPT_LENGTH, OPT_COMPARE, OPT_MATCH, OPT_EQUAL, OPT_IS, OPT_BYTERANGE, OPT_RANGE, OPT_REPLACE,
-
        OPT_MAP, OPT_REPEAT, OPT_REVERSE, OPT_INDEX, OPT_FIRST, OPT_LAST, OPT_CAT,
-
        OPT_TRIM, OPT_TRIMLEFT, OPT_TRIMRIGHT, OPT_TOLOWER, OPT_TOUPPER, OPT_TOTITLE
-
    };
    static const char * const nocase_options[] = {
        "-nocase", NULL
    };
@@ -17694,28 +19089,74 @@ static int Jim_StringCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *a
        "-nocase", "-length", NULL
    };

-
    if (argc < 2) {
-
        Jim_WrongNumArgs(interp, 1, argv, "option ?arguments ...?");
+
    enum {
+
        OPT_BYTELENGTH,
+
        OPT_BYTERANGE,
+
        OPT_CAT,
+
        OPT_COMPARE,
+
        OPT_EQUAL,
+
        OPT_FIRST,
+
        OPT_INDEX,
+
        OPT_IS,
+
        OPT_LAST,
+
        OPT_LENGTH,
+
        OPT_MAP,
+
        OPT_MATCH,
+
        OPT_RANGE,
+
        OPT_REPEAT,
+
        OPT_REPLACE,
+
        OPT_REVERSE,
+
        OPT_TOLOWER,
+
        OPT_TOTITLE,
+
        OPT_TOUPPER,
+
        OPT_TRIM,
+
        OPT_TRIMLEFT,
+
        OPT_TRIMRIGHT,
+
        OPT_COUNT
+
    };
+
    static const jim_subcmd_type cmds[OPT_COUNT + 1] = {
+
        JIM_DEF_SUBCMD("bytelength", "string", 1, 1),
+
        JIM_DEF_SUBCMD("byterange", "string first last", 3, 3),
+
        JIM_DEF_SUBCMD("cat", "?...?", 0, -1),
+
        JIM_DEF_SUBCMD("compare", "?-nocase? ?-length int? string1 string2", 2, 5),
+
        JIM_DEF_SUBCMD("equal", "?-nocase? ?-length int? string1 string2", 2, 5),
+
        JIM_DEF_SUBCMD("first", "subString string ?index?", 2, 3),
+
        JIM_DEF_SUBCMD("index", "string index", 2, 2),
+
        JIM_DEF_SUBCMD("is", "class ?-strict? str", 2, 3),
+
        JIM_DEF_SUBCMD("last", "subString string ?index?", 2, 3),
+
        JIM_DEF_SUBCMD("length","string", 1, 1),
+
        JIM_DEF_SUBCMD("map", "?-nocase? mapList string", 2, 3),
+
        JIM_DEF_SUBCMD("match", "?-nocase? pattern string", 2, 3),
+
        JIM_DEF_SUBCMD("range", "string first last", 3, 3),
+
        JIM_DEF_SUBCMD("repeat", "string count", 2, 2),
+
        JIM_DEF_SUBCMD("replace", "string first last ?string?", 3, 4),
+
        JIM_DEF_SUBCMD("reverse", "string", 1, 1),
+
        JIM_DEF_SUBCMD("tolower", "string", 1, 1),
+
        JIM_DEF_SUBCMD("totitle", "string", 1, 1),
+
        JIM_DEF_SUBCMD("toupper", "string", 1, 1),
+
        JIM_DEF_SUBCMD("trim", "string ?trimchars?", 1, 2),
+
        JIM_DEF_SUBCMD("trimleft", "string ?trimchars?", 1, 2),
+
        JIM_DEF_SUBCMD("trimright", "string ?trimchars?", 1, 2),
+
        { }
+
    };
+
    const jim_subcmd_type *ct = Jim_ParseSubCmd(interp, cmds, argc, argv);
+
    if (!ct) {
        return JIM_ERR;
    }
-
    if (Jim_GetEnum(interp, argv[1], options, &option, NULL,
-
            JIM_ERRMSG | JIM_ENUM_ABBREV) != JIM_OK)
-
        return Jim_CheckShowCommands(interp, argv[1], options);
+
    if (ct->function) {
+

+
        return ct->function(interp, argc, argv);
+
    }
+

+
    option = ct - cmds;

    switch (option) {
        case OPT_LENGTH:
+
            Jim_SetResultInt(interp, Jim_Utf8Length(interp, argv[2]));
+
            return JIM_OK;
+

        case OPT_BYTELENGTH:
-
            if (argc != 3) {
-
                Jim_WrongNumArgs(interp, 2, argv, "string");
-
                return JIM_ERR;
-
            }
-
            if (option == OPT_LENGTH) {
-
                len = Jim_Utf8Length(interp, argv[2]);
-
            }
-
            else {
-
                len = Jim_Length(argv[2]);
-
            }
-
            Jim_SetResultInt(interp, len);
+
            Jim_SetResultInt(interp, Jim_Length(argv[2]));
            return JIM_OK;

        case OPT_CAT:{
@@ -17749,7 +19190,7 @@ static int Jim_StringCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *a
                    if (Jim_GetEnum(interp, argv[i++], nocase_length_options, &subopt, NULL,
                            JIM_ENUM_ABBREV) != JIM_OK) {
badcompareargs:
-
                        Jim_WrongNumArgs(interp, 2, argv, "?-nocase? ?-length int? string1 string2");
+
                        Jim_SubCmdArgError(interp, ct, argv[0]);
                        return JIM_ERR;
                    }
                    if (subopt == 0) {
@@ -17777,12 +19218,19 @@ badcompareargs:
                    Jim_SetResultBool(interp, Jim_StringEqObj(argv[0], argv[1]));
                }
                else {
+
                    const char *s1 = Jim_String(argv[0]);
+
                    int l1 = Jim_Utf8Length(interp, argv[0]);
+
                    const char *s2 = Jim_String(argv[1]);
+
                    int l2 = Jim_Utf8Length(interp, argv[1]);
                    if (opt_length >= 0) {
-
                        n = JimStringCompareLen(Jim_String(argv[0]), Jim_String(argv[1]), opt_length, !opt_case);
-
                    }
-
                    else {
-
                        n = Jim_StringCompareObj(interp, argv[0], argv[1], !opt_case);
+
                        if (l1 > opt_length) {
+
                            l1 = opt_length;
+
                        }
+
                        if (l2 > opt_length) {
+
                            l2 = opt_length;
+
                        }
                    }
+
                    n = JimStringCompareUtf8(s1, l1, s2, l2, !opt_case);
                    Jim_SetResultInt(interp, option == OPT_COMPARE ? n : n == 0);
                }
                return JIM_OK;
@@ -17824,22 +19272,17 @@ badcompareargs:
                return JIM_OK;
            }

-
        case OPT_RANGE:
-
        case OPT_BYTERANGE:{
-
                Jim_Obj *objPtr;
-

-
                if (argc != 5) {
-
                    Jim_WrongNumArgs(interp, 2, argv, "string first last");
+
        case OPT_RANGE:{
+
                Jim_Obj *objPtr = Jim_StringRangeObj(interp, argv[2], argv[3], argv[4]);
+
                if (objPtr == NULL) {
                    return JIM_ERR;
                }
-
                if (option == OPT_RANGE) {
-
                    objPtr = Jim_StringRangeObj(interp, argv[2], argv[3], argv[4]);
-
                }
-
                else
-
                {
-
                    objPtr = Jim_StringByteRangeObj(interp, argv[2], argv[3], argv[4]);
-
                }
+
                Jim_SetResult(interp, objPtr);
+
                return JIM_OK;
+
            }

+
        case OPT_BYTERANGE:{
+
                Jim_Obj *objPtr = Jim_StringByteRangeObj(interp, argv[2], argv[3], argv[4]);
                if (objPtr == NULL) {
                    return JIM_ERR;
                }
@@ -17848,13 +19291,7 @@ badcompareargs:
            }

        case OPT_REPLACE:{
-
                Jim_Obj *objPtr;
-

-
                if (argc != 5 && argc != 6) {
-
                    Jim_WrongNumArgs(interp, 2, argv, "string first last ?string?");
-
                    return JIM_ERR;
-
                }
-
                objPtr = JimStringReplaceObj(interp, argv[2], argv[3], argv[4], argc == 6 ? argv[5] : NULL);
+
                Jim_Obj *objPtr = JimStringReplaceObj(interp, argv[2], argv[3], argv[4], argc == 6 ? argv[5] : NULL);
                if (objPtr == NULL) {
                    return JIM_ERR;
                }
@@ -17867,11 +19304,7 @@ badcompareargs:
                Jim_Obj *objPtr;
                jim_wide count;

-
                if (argc != 4) {
-
                    Jim_WrongNumArgs(interp, 2, argv, "string count");
-
                    return JIM_ERR;
-
                }
-
                if (Jim_GetWide(interp, argv[3], &count) != JIM_OK) {
+
                if (Jim_GetWideExpr(interp, argv[3], &count) != JIM_OK) {
                    return JIM_ERR;
                }
                objPtr = Jim_NewStringObj(interp, "", 0);
@@ -17889,13 +19322,9 @@ badcompareargs:
                const char *str;
                int i;

-
                if (argc != 3) {
-
                    Jim_WrongNumArgs(interp, 2, argv, "string");
-
                    return JIM_ERR;
-
                }
-

                str = Jim_GetString(argv[2], &len);
                buf = Jim_Alloc(len + 1);
+
                assert(buf);
                p = buf + len;
                *p = 0;
                for (i = 0; i < len; ) {
@@ -17914,18 +19343,12 @@ badcompareargs:
                int idx;
                const char *str;

-
                if (argc != 4) {
-
                    Jim_WrongNumArgs(interp, 2, argv, "string index");
-
                    return JIM_ERR;
-
                }
                if (Jim_GetIndex(interp, argv[3], &idx) != JIM_OK) {
                    return JIM_ERR;
                }
                str = Jim_String(argv[2]);
                len = Jim_Utf8Length(interp, argv[2]);
-
                if (idx != INT_MIN && idx != INT_MAX) {
-
                    idx = JimRelToAbsIndex(len, idx);
-
                }
+
                idx = JimRelToAbsIndex(len, idx);
                if (idx < 0 || idx >= len || str == NULL) {
                    Jim_SetResultString(interp, "", 0);
                }
@@ -17946,10 +19369,6 @@ badcompareargs:
                int idx = 0, l1, l2;
                const char *s1, *s2;

-
                if (argc != 4 && argc != 5) {
-
                    Jim_WrongNumArgs(interp, 2, argv, "subString string ?index?");
-
                    return JIM_ERR;
-
                }
                s1 = Jim_String(argv[2]);
                s2 = Jim_String(argv[3]);
                l1 = Jim_Utf8Length(interp, argv[2]);
@@ -17959,6 +19378,9 @@ badcompareargs:
                        return JIM_ERR;
                    }
                    idx = JimRelToAbsIndex(l2, idx);
+
                    if (idx < 0) {
+
                        idx = 0;
+
                    }
                }
                else if (option == OPT_LAST) {
                    idx = l2;
@@ -17977,51 +19399,32 @@ badcompareargs:
            }

        case OPT_TRIM:
+
                Jim_SetResult(interp, JimStringTrim(interp, argv[2], argc == 4 ? argv[3] : NULL));
+
                return JIM_OK;
        case OPT_TRIMLEFT:
+
                Jim_SetResult(interp, JimStringTrimLeft(interp, argv[2], argc == 4 ? argv[3] : NULL));
+
                return JIM_OK;
        case OPT_TRIMRIGHT:{
-
                Jim_Obj *trimchars;
-

-
                if (argc != 3 && argc != 4) {
-
                    Jim_WrongNumArgs(interp, 2, argv, "string ?trimchars?");
-
                    return JIM_ERR;
-
                }
-
                trimchars = (argc == 4 ? argv[3] : NULL);
-
                if (option == OPT_TRIM) {
-
                    Jim_SetResult(interp, JimStringTrim(interp, argv[2], trimchars));
-
                }
-
                else if (option == OPT_TRIMLEFT) {
-
                    Jim_SetResult(interp, JimStringTrimLeft(interp, argv[2], trimchars));
-
                }
-
                else if (option == OPT_TRIMRIGHT) {
-
                    Jim_SetResult(interp, JimStringTrimRight(interp, argv[2], trimchars));
-
                }
+
                Jim_SetResult(interp, JimStringTrimRight(interp, argv[2], argc == 4 ? argv[3] : NULL));
                return JIM_OK;
-
            }
+
        }

        case OPT_TOLOWER:
-
        case OPT_TOUPPER:
-
        case OPT_TOTITLE:
-
            if (argc != 3) {
-
                Jim_WrongNumArgs(interp, 2, argv, "string");
-
                return JIM_ERR;
-
            }
-
            if (option == OPT_TOLOWER) {
                Jim_SetResult(interp, JimStringToLower(interp, argv[2]));
-
            }
-
            else if (option == OPT_TOUPPER) {
+
                return JIM_OK;
+
        case OPT_TOUPPER:
                Jim_SetResult(interp, JimStringToUpper(interp, argv[2]));
-
            }
-
            else {
+
                return JIM_OK;
+
        case OPT_TOTITLE:
                Jim_SetResult(interp, JimStringToTitle(interp, argv[2]));
-
            }
-
            return JIM_OK;
+
                return JIM_OK;

        case OPT_IS:
-
            if (argc == 4 || (argc == 5 && Jim_CompareStringImmediate(interp, argv[3], "-strict"))) {
-
                return JimStringIs(interp, argv[argc - 1], argv[2], argc == 5);
+
            if (argc == 5 && !Jim_CompareStringImmediate(interp, argv[3], "-strict")) {
+
                Jim_SubCmdArgError(interp, ct, argv[0]);
+
                return JIM_ERR;
            }
-
            Jim_WrongNumArgs(interp, 2, argv, "class ?-strict? str");
-
            return JIM_ERR;
+
            return JimStringIs(interp, argv[argc - 1], argv[2], argc == 5);
    }
    return JIM_OK;
}
@@ -18031,8 +19434,6 @@ static int Jim_TimeCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *arg
{
    long i, count = 1;
    jim_wide start, elapsed;
-
    char buf[60];
-
    const char *fmt = "%" JIM_WIDE_MODIFIER " microseconds per iteration";

    if (argc < 2) {
        Jim_WrongNumArgs(interp, 1, argv, "script ?count?");
@@ -18045,7 +19446,7 @@ static int Jim_TimeCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *arg
    if (count < 0)
        return JIM_OK;
    i = count;
-
    start = JimClock();
+
    start = Jim_GetTimeUsec(CLOCK_MONOTONIC_RAW);
    while (i-- > 0) {
        int retval;

@@ -18054,9 +19455,79 @@ static int Jim_TimeCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *arg
            return retval;
        }
    }
-
    elapsed = JimClock() - start;
-
    sprintf(buf, fmt, count == 0 ? 0 : elapsed / count);
-
    Jim_SetResultString(interp, buf, -1);
+
    elapsed = Jim_GetTimeUsec(CLOCK_MONOTONIC_RAW) - start;
+
    if (elapsed < count * 10) {
+
        Jim_SetResult(interp, Jim_NewDoubleObj(interp, elapsed * 1.0 / count));
+
    }
+
    else {
+
        Jim_SetResultInt(interp, count == 0 ? 0 : elapsed / count);
+
    }
+
    Jim_AppendString(interp, Jim_GetResult(interp)," microseconds per iteration", -1);
+
    return JIM_OK;
+
}
+

+

+
static int Jim_TimeRateCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+
{
+
    long us = 0;
+
    jim_wide start, delta, overhead;
+
    Jim_Obj *objPtr;
+
    double us_per_iter;
+
    int count;
+
    int n;
+

+
    if (argc < 2) {
+
        Jim_WrongNumArgs(interp, 1, argv, "script ?milliseconds?");
+
        return JIM_ERR;
+
    }
+
    if (argc == 3) {
+
        if (Jim_GetLong(interp, argv[2], &us) != JIM_OK)
+
            return JIM_ERR;
+
        us *= 1000;
+
    }
+
    if (us < 1) {
+

+
        us = 1000 * 1000;
+
    }
+

+

+
    start = Jim_GetTimeUsec(CLOCK_MONOTONIC_RAW);
+
    count = 0;
+
    do {
+
        int retval = Jim_EvalObj(interp, argv[1]);
+
        delta = Jim_GetTimeUsec(CLOCK_MONOTONIC_RAW) - start;
+
        if (retval != JIM_OK) {
+
            return retval;
+
        }
+
        count++;
+
    } while (delta < us);
+

+

+
    start = Jim_GetTimeUsec(CLOCK_MONOTONIC_RAW);
+
    n = 0;
+
    do {
+
        int retval = Jim_EvalObj(interp, interp->nullScriptObj);
+
        overhead = Jim_GetTimeUsec(CLOCK_MONOTONIC_RAW) - start;
+
        if (retval != JIM_OK) {
+
            return retval;
+
        }
+
        n++;
+
    } while (n < count);
+

+
    delta -= overhead;
+

+
    us_per_iter = (double)delta / count;
+
    objPtr = Jim_NewListObj(interp, NULL, 0);
+

+
    Jim_ListAppendElement(interp, objPtr, Jim_NewStringObj(interp, "us_per_iter", -1));
+
    Jim_ListAppendElement(interp, objPtr, Jim_NewDoubleObj(interp, us_per_iter));
+
    Jim_ListAppendElement(interp, objPtr, Jim_NewStringObj(interp, "iters_per_sec", -1));
+
    Jim_ListAppendElement(interp, objPtr, Jim_NewDoubleObj(interp, 1e6 / us_per_iter));
+
    Jim_ListAppendElement(interp, objPtr, Jim_NewStringObj(interp, "count", -1));
+
    Jim_ListAppendElement(interp, objPtr, Jim_NewIntObj(interp, count));
+
    Jim_ListAppendElement(interp, objPtr, Jim_NewStringObj(interp, "elapsed_us", -1));
+
    Jim_ListAppendElement(interp, objPtr, Jim_NewIntObj(interp, delta));
+
    Jim_SetResult(interp, objPtr);
    return JIM_OK;
}

@@ -18072,22 +19543,52 @@ static int Jim_ExitCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *arg
    if (argc == 2) {
        if (Jim_GetLong(interp, argv[1], &exitCode) != JIM_OK)
            return JIM_ERR;
+
        Jim_SetResult(interp, argv[1]);
    }
    interp->exitCode = exitCode;
    return JIM_EXIT;
}

+
static int JimMatchReturnCodes(Jim_Interp *interp, Jim_Obj *retcodeListObj, int rc)
+
{
+
    int len = Jim_ListLength(interp, retcodeListObj);
+
    int i;
+
    for (i = 0; i < len; i++) {
+
        int returncode;
+
        if (Jim_GetReturnCode(interp, Jim_ListGetIndex(interp, retcodeListObj, i), &returncode) != JIM_OK) {
+
            return JIM_ERR;
+
        }
+
        if (rc == returncode) {
+
            return JIM_OK;
+
        }
+
    }
+
    return -1;
+
}
+


-
static int Jim_CatchCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+
static int JimCatchTryHelper(Jim_Interp *interp, int istry, int argc, Jim_Obj *const *argv)
{
+
    static const char * const wrongargs_catchtry[2] = {
+
        "?-?no?code ... --? script ?resultVarName? ?optionVarName?",
+
        "?-?no?code ... --? script ?on|trap codes vars script? ... ?finally script?"
+
    };
    int exitCode = 0;
    int i;
    int sig = 0;
+
    int ok;
+
    Jim_Obj *finallyScriptObj = NULL;
+
    Jim_Obj *msgVarObj = NULL;
+
    Jim_Obj *optsVarObj = NULL;
+
    Jim_Obj *handlerScriptObj = NULL;
+
    Jim_Obj *errorCodeObj;
+
    int idx;


    jim_wide ignore_mask = (1 << JIM_EXIT) | (1 << JIM_EVAL) | (1 << JIM_SIGNAL);
    static const int max_ignore_code = sizeof(ignore_mask) * 8;

+
    JimPanic((istry != 0 && istry != 1, "wrong args to JimCatchTryHelper"));
+

    Jim_SetGlobalVariableStr(interp, "errorCode", Jim_NewStringObj(interp, "NONE", -1));

    for (i = 1; i < argc - 1; i++) {
@@ -18131,14 +19632,13 @@ static int Jim_CatchCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *ar
        }
    }

-
    argc -= i;
-
    if (argc < 1 || argc > 3) {
-
      wrongargs:
-
        Jim_WrongNumArgs(interp, 1, argv,
-
            "?-?no?code ... --? script ?resultVarName? ?optionVarName?");
+
    idx = i;
+

+
    if (argc - idx < 1) {
+
wrongargs:
+
        Jim_WrongNumArgs(interp, 1, argv, wrongargs_catchtry[istry]);
        return JIM_ERR;
    }
-
    argv += i;

    if ((ignore_mask & (1 << JIM_SIGNAL)) == 0) {
        sig++;
@@ -18150,15 +19650,91 @@ static int Jim_CatchCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *ar
        exitCode = JIM_SIGNAL;
    }
    else {
-
        exitCode = Jim_EvalObj(interp, argv[0]);
+
        exitCode = Jim_EvalObj(interp, argv[idx]);

        interp->errorFlag = 0;
    }
    interp->signal_level -= sig;

+
    errorCodeObj = Jim_GetGlobalVariableStr(interp, "errorCode", JIM_NONE);
+

+
    idx++;
+
    if (istry) {
+
        while (idx < argc) {
+
            int option;
+
            int ret;
+
            static const char * const try_options[] = { "on", "trap", "finally", NULL };
+
            enum { TRY_ON, TRY_TRAP, TRY_FINALLY, };
+

+
            if (Jim_GetEnum(interp, argv[idx], try_options, &option, "handler", JIM_ERRMSG) != JIM_OK) {
+
                return JIM_ERR;
+
            }
+
            switch (option) {
+
                case TRY_ON:
+
                case TRY_TRAP:
+
                    if (idx + 4 > argc) {
+
                        goto wrongargs;
+
                    }
+
                    if (option == TRY_ON) {
+
                        ret = JimMatchReturnCodes(interp, argv[idx + 1], exitCode);
+
                        if (ret > JIM_OK) {
+
                            goto wrongargs;
+
                        }
+
                    }
+
                    else if (errorCodeObj) {
+
                        int len = Jim_ListLength(interp, argv[idx + 1]);
+
                        int i;
+

+
                        ret = JIM_OK;
+

+
                        for (i = 0; i < len; i++) {
+
                            Jim_Obj *matchObj = Jim_ListGetIndex(interp, argv[idx + 1], i);
+
                            Jim_Obj *objPtr = Jim_ListGetIndex(interp, errorCodeObj, i);
+
                            if (Jim_StringCompareObj(interp, matchObj, objPtr, 0) != 0) {
+
                                ret = -1;
+
                                break;
+
                            }
+
                        }
+
                    }
+
                    else {
+

+
                        ret = -1;
+
                    }
+

+
                    if (ret == JIM_OK && handlerScriptObj == NULL) {
+
                        msgVarObj = Jim_ListGetIndex(interp, argv[idx + 2], 0);
+
                        optsVarObj = Jim_ListGetIndex(interp, argv[idx + 2], 1);
+
                        handlerScriptObj = argv[idx + 3];
+
                    }
+
                    idx += 4;
+
                    break;
+
                case TRY_FINALLY:
+
                    if (idx + 2 != argc) {
+
                        goto wrongargs;
+
                    }
+
                    finallyScriptObj = argv[idx + 1];
+
                    idx += 2;
+
                    break;
+
            }
+
        }
+
    }
+
    else {
+
        if (argc - idx >= 1) {
+
            msgVarObj = argv[idx];
+
            idx++;
+
            if (argc - idx >= 1) {
+
                optsVarObj = argv[idx];
+
                idx++;
+
            }
+
        }
+
    }
+


    if (exitCode >= 0 && exitCode < max_ignore_code && (((unsigned jim_wide)1 << exitCode) & ignore_mask)) {

+
        if (finallyScriptObj) {
+
            Jim_EvalObj(interp, finallyScriptObj);
+
        }
        return exitCode;
    }

@@ -18167,43 +19743,75 @@ static int Jim_CatchCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *ar
        if (interp->signal_set_result) {
            interp->signal_set_result(interp, interp->sigmask);
        }
-
        else {
+
        else if (!istry) {
            Jim_SetResultInt(interp, interp->sigmask);
        }
        interp->sigmask = 0;
    }

-
    if (argc >= 2) {
-
        if (Jim_SetVariable(interp, argv[1], Jim_GetResult(interp)) != JIM_OK) {
-
            return JIM_ERR;
+
    ok = 1;
+
    if (msgVarObj && Jim_Length(msgVarObj)) {
+
        if (Jim_SetVariable(interp, msgVarObj, Jim_GetResult(interp)) != JIM_OK) {
+
            ok = 0;
        }
-
        if (argc == 3) {
-
            Jim_Obj *optListObj = Jim_NewListObj(interp, NULL, 0);
-

-
            Jim_ListAppendElement(interp, optListObj, Jim_NewStringObj(interp, "-code", -1));
-
            Jim_ListAppendElement(interp, optListObj,
-
                Jim_NewIntObj(interp, exitCode == JIM_RETURN ? interp->returnCode : exitCode));
-
            Jim_ListAppendElement(interp, optListObj, Jim_NewStringObj(interp, "-level", -1));
-
            Jim_ListAppendElement(interp, optListObj, Jim_NewIntObj(interp, interp->returnLevel));
-
            if (exitCode == JIM_ERR) {
-
                Jim_Obj *errorCode;
-
                Jim_ListAppendElement(interp, optListObj, Jim_NewStringObj(interp, "-errorinfo",
-
                    -1));
-
                Jim_ListAppendElement(interp, optListObj, interp->stackTrace);
-

-
                errorCode = Jim_GetGlobalVariableStr(interp, "errorCode", JIM_NONE);
-
                if (errorCode) {
-
                    Jim_ListAppendElement(interp, optListObj, Jim_NewStringObj(interp, "-errorcode", -1));
-
                    Jim_ListAppendElement(interp, optListObj, errorCode);
-
                }
-
            }
-
            if (Jim_SetVariable(interp, argv[2], optListObj) != JIM_OK) {
-
                return JIM_ERR;
+
    }
+
    if (ok && optsVarObj && Jim_Length(optsVarObj)) {
+
        Jim_Obj *optListObj = Jim_NewListObj(interp, NULL, 0);
+

+
        Jim_ListAppendElement(interp, optListObj, Jim_NewStringObj(interp, "-code", -1));
+
        Jim_ListAppendElement(interp, optListObj,
+
            Jim_NewIntObj(interp, exitCode == JIM_RETURN ? interp->returnCode : exitCode));
+
        Jim_ListAppendElement(interp, optListObj, Jim_NewStringObj(interp, "-level", -1));
+
        Jim_ListAppendElement(interp, optListObj, Jim_NewIntObj(interp, interp->returnLevel));
+
        if (exitCode == JIM_ERR) {
+
            Jim_ListAppendElement(interp, optListObj, Jim_NewStringObj(interp, "-errorinfo",
+
                -1));
+
            Jim_ListAppendElement(interp, optListObj, interp->stackTrace);
+

+
            if (errorCodeObj) {
+
                Jim_ListAppendElement(interp, optListObj, Jim_NewStringObj(interp, "-errorcode", -1));
+
                Jim_ListAppendElement(interp, optListObj, errorCodeObj);
            }
        }
+
        if (Jim_SetVariable(interp, optsVarObj, optListObj) != JIM_OK) {
+
            ok = 0;
+
        }
    }
-
    Jim_SetResultInt(interp, exitCode);
-
    return JIM_OK;
+
    if (ok && handlerScriptObj) {
+

+
        exitCode = Jim_EvalObj(interp, handlerScriptObj);
+
    }
+

+
    if (finallyScriptObj) {
+

+
        Jim_Obj *prevResultObj = Jim_GetResult(interp);
+
        Jim_IncrRefCount(prevResultObj);
+
        int ret = Jim_EvalObj(interp, finallyScriptObj);
+
        if (ret == JIM_OK) {
+
            Jim_SetResult(interp, prevResultObj);
+
        }
+
        else {
+
            exitCode = ret;
+
        }
+
        Jim_DecrRefCount(interp, prevResultObj);
+
    }
+
    if (!istry) {
+
        Jim_SetResultInt(interp, exitCode);
+
        exitCode = JIM_OK;
+
    }
+
    return exitCode;
+
}
+

+

+
static int Jim_CatchCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+
{
+
    return JimCatchTryHelper(interp, 0, argc, argv);
+
}
+

+

+
static int Jim_TryCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+
{
+
    return JimCatchTryHelper(interp, 1, argc, argv);
}


@@ -18215,11 +19823,7 @@ static int Jim_RenameCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *a
        return JIM_ERR;
    }

-
    if (JimValidName(interp, "new procedure", argv[2])) {
-
        return JIM_ERR;
-
    }
-

-
    return Jim_RenameCommand(interp, Jim_String(argv[1]), Jim_String(argv[2]));
+
    return Jim_RenameCommand(interp, argv[1], argv[2]);
}

#define JIM_DICTMATCH_KEYS 0x0001
@@ -18227,30 +19831,32 @@ static int Jim_RenameCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *a

int Jim_DictMatchTypes(Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj *patternObj, int match_type, int return_types)
{
-
    Jim_HashEntry *he;
    Jim_Obj *listObjPtr;
-
    Jim_HashTableIterator htiter;
+
    Jim_Dict *dict;
+
    int i;

    if (SetDictFromAny(interp, objPtr) != JIM_OK) {
        return JIM_ERR;
    }
+
    dict = objPtr->internalRep.dictValue;

    listObjPtr = Jim_NewListObj(interp, NULL, 0);

-
    JimInitHashTableIterator(objPtr->internalRep.ptr, &htiter);
-
    while ((he = Jim_NextHashEntry(&htiter)) != NULL) {
+
    for (i = 0; i < dict->len; i += 2 ) {
+
        Jim_Obj *keyObj = dict->table[i];
+
        Jim_Obj *valObj = dict->table[i + 1];
        if (patternObj) {
-
            Jim_Obj *matchObj = (match_type == JIM_DICTMATCH_KEYS) ? (Jim_Obj *)he->key : Jim_GetHashEntryVal(he);
-
            if (!JimGlobMatch(Jim_String(patternObj), Jim_String(matchObj), 0)) {
+
            Jim_Obj *matchObj = (match_type == JIM_DICTMATCH_KEYS) ? keyObj : valObj;
+
            if (!Jim_StringMatchObj(interp, patternObj, matchObj, 0)) {

                continue;
            }
        }
        if (return_types & JIM_DICTMATCH_KEYS) {
-
            Jim_ListAppendElement(interp, listObjPtr, (Jim_Obj *)he->key);
+
            Jim_ListAppendElement(interp, listObjPtr, keyObj);
        }
        if (return_types & JIM_DICTMATCH_VALUES) {
-
            Jim_ListAppendElement(interp, listObjPtr, Jim_GetHashEntryVal(he));
+
            Jim_ListAppendElement(interp, listObjPtr, valObj);
        }
    }

@@ -18263,7 +19869,7 @@ int Jim_DictSize(Jim_Interp *interp, Jim_Obj *objPtr)
    if (SetDictFromAny(interp, objPtr) != JIM_OK) {
        return -1;
    }
-
    return ((Jim_HashTable *)objPtr->internalRep.ptr)->used;
+
    return objPtr->internalRep.dictValue->len / 2;
}

Jim_Obj *Jim_DictMerge(Jim_Interp *interp, int objc, Jim_Obj *const *objv)
@@ -18276,18 +19882,17 @@ Jim_Obj *Jim_DictMerge(Jim_Interp *interp, int objc, Jim_Obj *const *objv)


    for (i = 0; i < objc; i++) {
-
        Jim_HashTable *ht;
-
        Jim_HashTableIterator htiter;
-
        Jim_HashEntry *he;
+
        Jim_Obj **table;
+
        int tablelen;
+
        int j;

-
        if (SetDictFromAny(interp, objv[i]) != JIM_OK) {
+
        table = Jim_DictPairs(interp, objv[i], &tablelen);
+
        if (tablelen && !table) {
            Jim_FreeNewObj(interp, objPtr);
            return NULL;
        }
-
        ht = objv[i]->internalRep.ptr;
-
        JimInitHashTableIterator(ht, &htiter);
-
        while ((he = Jim_NextHashEntry(&htiter)) != NULL) {
-
            Jim_ReplaceHashEntry(objPtr->internalRep.ptr, Jim_GetHashEntryKey(he), Jim_GetHashEntryVal(he));
+
        for (j = 0; j < tablelen; j += 2) {
+
            DictAddElement(interp, objPtr, table[j], table[j + 1]);
        }
    }
    return objPtr;
@@ -18295,50 +19900,19 @@ Jim_Obj *Jim_DictMerge(Jim_Interp *interp, int objc, Jim_Obj *const *objv)

int Jim_DictInfo(Jim_Interp *interp, Jim_Obj *objPtr)
{
-
    Jim_HashTable *ht;
-
    unsigned int i;
    char buffer[100];
-
    int sum = 0;
-
    int nonzero_count = 0;
    Jim_Obj *output;
-
    int bucket_counts[11] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+
    Jim_Dict *dict;

    if (SetDictFromAny(interp, objPtr) != JIM_OK) {
        return JIM_ERR;
    }

-
    ht = (Jim_HashTable *)objPtr->internalRep.ptr;
+
    dict = objPtr->internalRep.dictValue;


-
    snprintf(buffer, sizeof(buffer), "%d entries in table, %d buckets\n", ht->used, ht->size);
+
    snprintf(buffer, sizeof(buffer), "%d entries in table, %d buckets", dict->len, dict->size);
    output = Jim_NewStringObj(interp, buffer, -1);
-

-
    for (i = 0; i < ht->size; i++) {
-
        Jim_HashEntry *he = ht->table[i];
-
        int entries = 0;
-
        while (he) {
-
            entries++;
-
            he = he->next;
-
        }
-
        if (entries > 9) {
-
            bucket_counts[10]++;
-
        }
-
        else {
-
            bucket_counts[entries]++;
-
        }
-
        if (entries) {
-
            sum += entries;
-
            nonzero_count++;
-
        }
-
    }
-
    for (i = 0; i < 10; i++) {
-
        snprintf(buffer, sizeof(buffer), "number of buckets with %d entries: %d\n", i, bucket_counts[i]);
-
        Jim_AppendString(interp, output, buffer, -1);
-
    }
-
    snprintf(buffer, sizeof(buffer), "number of buckets with 10 or more entries: %d\n", bucket_counts[10]);
-
    Jim_AppendString(interp, output, buffer, -1);
-
    snprintf(buffer, sizeof(buffer), "average search distance for entry: %.1f", nonzero_count ? (double)sum / nonzero_count : 0.0);
-
    Jim_AppendString(interp, output, buffer, -1);
    Jim_SetResult(interp, output);
    return JIM_OK;
}
@@ -18368,12 +19942,12 @@ static int JimDictWith(Jim_Interp *interp, Jim_Obj *dictVarName, Jim_Obj *const
        return JIM_ERR;
    }

-
    if (Jim_DictPairs(interp, objPtr, &dictValues, &len) == JIM_ERR) {
+
    dictValues = Jim_DictPairs(interp, objPtr, &len);
+
    if (len && dictValues == NULL) {
        return JIM_ERR;
    }
    for (i = 0; i < len; i += 2) {
        if (Jim_SetVariable(interp, dictValues[i], dictValues[i + 1]) == JIM_ERR) {
-
            Jim_Free(dictValues);
            return JIM_ERR;
        }
    }
@@ -18392,16 +19966,17 @@ static int JimDictWith(Jim_Interp *interp, Jim_Obj *dictVarName, Jim_Obj *const

            for (i = 0; i < len; i += 2) {

-
                objPtr = Jim_GetVariable(interp, dictValues[i], 0);
-
                newkeyv[keyc] = dictValues[i];
-
                Jim_SetDictKeysVector(interp, dictVarName, newkeyv, keyc + 1, objPtr, 0);
+
                if (Jim_StringCompareObj(interp, dictVarName, dictValues[i], 0) != 0) {
+

+
                    objPtr = Jim_GetVariable(interp, dictValues[i], 0);
+
                    newkeyv[keyc] = dictValues[i];
+
                    Jim_SetDictKeysVector(interp, dictVarName, newkeyv, keyc + 1, objPtr, JIM_NORESULT);
+
                }
            }
            Jim_Free(newkeyv);
        }
    }

-
    Jim_Free(dictValues);
-

    return ret;
}

@@ -18409,35 +19984,66 @@ static int JimDictWith(Jim_Interp *interp, Jim_Obj *dictVarName, Jim_Obj *const
static int Jim_DictCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
    Jim_Obj *objPtr;
-
    int types = JIM_DICTMATCH_KEYS;
-
    int option;
-
    static const char * const options[] = {
-
        "create", "get", "set", "unset", "exists", "keys", "size", "info",
-
        "merge", "with", "append", "lappend", "incr", "remove", "values", "for",
-
        "replace", "update", NULL
+
    int types = JIM_DICTMATCH_KEYS;
+

+
    enum {
+
        OPT_CREATE,
+
        OPT_GET,
+
        OPT_GETDEF,
+
        OPT_GETWITHDEFAULT,
+
        OPT_SET,
+
        OPT_UNSET,
+
        OPT_EXISTS,
+
        OPT_KEYS,
+
        OPT_SIZE,
+
        OPT_INFO,
+
        OPT_MERGE,
+
        OPT_WITH,
+
        OPT_APPEND,
+
        OPT_LAPPEND,
+
        OPT_INCR,
+
        OPT_REMOVE,
+
        OPT_VALUES,
+
        OPT_FOR,
+
        OPT_REPLACE,
+
        OPT_UPDATE,
+
        OPT_COUNT
    };
-
    enum
-
    {
-
        OPT_CREATE, OPT_GET, OPT_SET, OPT_UNSET, OPT_EXISTS, OPT_KEYS, OPT_SIZE, OPT_INFO,
-
        OPT_MERGE, OPT_WITH, OPT_APPEND, OPT_LAPPEND, OPT_INCR, OPT_REMOVE, OPT_VALUES, OPT_FOR,
-
        OPT_REPLACE, OPT_UPDATE,
+
    static const jim_subcmd_type cmds[OPT_COUNT + 1] = {
+
        JIM_DEF_SUBCMD("create", "?key value ...?", 0, -2),
+
        JIM_DEF_SUBCMD("get", "dictionary ?key ...?", 1, -1),
+
        JIM_DEF_SUBCMD_HIDDEN("getdef", "dictionary ?key ...? key default", 3, -1),
+
        JIM_DEF_SUBCMD("getwithdefault", "dictionary ?key ...? key default", 3, -1),
+
        JIM_DEF_SUBCMD("set", "varName key ?key ...? value", 3, -1),
+
        JIM_DEF_SUBCMD("unset", "varName key ?key ...?", 2, -1),
+
        JIM_DEF_SUBCMD("exists", "dictionary key ?key ...?", 2, -1),
+
        JIM_DEF_SUBCMD("keys", "dictionary ?pattern?", 1, 2),
+
        JIM_DEF_SUBCMD("size", "dictionary", 1, 1),
+
        JIM_DEF_SUBCMD("info", "dictionary", 1, 1),
+
        JIM_DEF_SUBCMD("merge", "?...?", 0, -1),
+
        JIM_DEF_SUBCMD("with", "dictVar ?key ...? script", 2, -1),
+
        JIM_DEF_SUBCMD("append", "varName key ?value ...?", 2, -1),
+
        JIM_DEF_SUBCMD("lappend",  "varName key ?value ...?", 2, -1),
+
        JIM_DEF_SUBCMD("incr", "varName key ?increment?", 2, 3),
+
        JIM_DEF_SUBCMD("remove", "dictionary ?key ...?", 1, -1),
+
        JIM_DEF_SUBCMD("values", "dictionary ?pattern?", 1, 2),
+
        JIM_DEF_SUBCMD("for", "vars dictionary script", 3, 3),
+
        JIM_DEF_SUBCMD("replace", "dictionary ?key value ...?", 1, -1),
+
        JIM_DEF_SUBCMD("update", "varName ?arg ...? script", 2, -1),
+
        { }
    };
-

-
    if (argc < 2) {
-
        Jim_WrongNumArgs(interp, 1, argv, "subcommand ?arguments ...?");
+
    const jim_subcmd_type *ct = Jim_ParseSubCmd(interp, cmds, argc, argv);
+
    if (!ct) {
        return JIM_ERR;
    }
+
    if (ct->function) {

-
    if (Jim_GetEnum(interp, argv[1], options, &option, "subcommand", JIM_ERRMSG) != JIM_OK) {
-
        return Jim_CheckShowCommands(interp, argv[1], options);
+
        return ct->function(interp, argc, argv);
    }

-
    switch (option) {
+

+
    switch (ct - cmds) {
        case OPT_GET:
-
            if (argc < 3) {
-
                Jim_WrongNumArgs(interp, 2, argv, "dictionary ?key ...?");
-
                return JIM_ERR;
-
            }
            if (Jim_DictKeysVector(interp, argv[2], argv + 3, argc - 3, &objPtr,
                    JIM_ERRMSG) != JIM_OK) {
                return JIM_ERR;
@@ -18445,20 +20051,27 @@ static int Jim_DictCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *arg
            Jim_SetResult(interp, objPtr);
            return JIM_OK;

-
        case OPT_SET:
-
            if (argc < 5) {
-
                Jim_WrongNumArgs(interp, 2, argv, "varName key ?key ...? value");
-
                return JIM_ERR;
-
            }
-
            return Jim_SetDictKeysVector(interp, argv[2], argv + 3, argc - 4, argv[argc - 1], JIM_ERRMSG);
+
        case OPT_GETDEF:
+
        case OPT_GETWITHDEFAULT:{
+
            int rc = Jim_DictKeysVector(interp, argv[2], argv + 3, argc - 4, &objPtr, JIM_ERRMSG);
+
            if (rc == -1) {

-
        case OPT_EXISTS:
-
            if (argc < 4) {
-
                Jim_WrongNumArgs(interp, 2, argv, "dictionary key ?key ...?");
                return JIM_ERR;
            }
+
            if (rc == JIM_ERR) {
+
                Jim_SetResult(interp, argv[argc - 1]);
+
            }
            else {
-
                int rc = Jim_DictKeysVector(interp, argv[2], argv + 3, argc - 3, &objPtr, JIM_ERRMSG);
+
                Jim_SetResult(interp, objPtr);
+
            }
+
            return JIM_OK;
+
        }
+

+
        case OPT_SET:
+
            return Jim_SetDictKeysVector(interp, argv[2], argv + 3, argc - 4, argv[argc - 1], JIM_ERRMSG);
+

+
        case OPT_EXISTS:{
+
                int rc = Jim_DictKeysVector(interp, argv[2], argv + 3, argc - 3, &objPtr, JIM_NONE);
                if (rc < 0) {
                    return JIM_ERR;
                }
@@ -18467,11 +20080,7 @@ static int Jim_DictCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *arg
            }

        case OPT_UNSET:
-
            if (argc < 4) {
-
                Jim_WrongNumArgs(interp, 2, argv, "varName key ?key ...?");
-
                return JIM_ERR;
-
            }
-
            if (Jim_SetDictKeysVector(interp, argv[2], argv + 3, argc - 3, NULL, 0) != JIM_OK) {
+
            if (Jim_SetDictKeysVector(interp, argv[2], argv + 3, argc - 3, NULL, JIM_NONE) != JIM_OK) {
                return JIM_ERR;
            }
            return JIM_OK;
@@ -18480,18 +20089,10 @@ static int Jim_DictCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *arg
            types = JIM_DICTMATCH_VALUES;

        case OPT_KEYS:
-
            if (argc != 3 && argc != 4) {
-
                Jim_WrongNumArgs(interp, 2, argv, "dictionary ?pattern?");
-
                return JIM_ERR;
-
            }
            return Jim_DictMatchTypes(interp, argv[2], argc == 4 ? argv[3] : NULL, types, types);

        case OPT_SIZE:
-
            if (argc != 3) {
-
                Jim_WrongNumArgs(interp, 2, argv, "dictionary");
-
                return JIM_ERR;
-
            }
-
            else if (Jim_DictSize(interp, argv[2]) < 0) {
+
            if (Jim_DictSize(interp, argv[2]) < 0) {
                return JIM_ERR;
            }
            Jim_SetResultInt(interp, Jim_DictSize(interp, argv[2]));
@@ -18508,38 +20109,26 @@ static int Jim_DictCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *arg
            Jim_SetResult(interp, objPtr);
            return JIM_OK;

-
        case OPT_UPDATE:
-
            if (argc < 6 || argc % 2) {
-

-
                argc = 2;
-
            }
-
            break;
-

        case OPT_CREATE:
-
            if (argc % 2) {
-
                Jim_WrongNumArgs(interp, 2, argv, "?key value ...?");
-
                return JIM_ERR;
-
            }
            objPtr = Jim_NewDictObj(interp, argv + 2, argc - 2);
            Jim_SetResult(interp, objPtr);
            return JIM_OK;

        case OPT_INFO:
-
            if (argc != 3) {
-
                Jim_WrongNumArgs(interp, 2, argv, "dictionary");
-
                return JIM_ERR;
-
            }
            return Jim_DictInfo(interp, argv[2]);

        case OPT_WITH:
-
            if (argc < 4) {
-
                Jim_WrongNumArgs(interp, 2, argv, "dictVar ?key ...? script");
-
                return JIM_ERR;
-
            }
            return JimDictWith(interp, argv[2], argv + 3, argc - 4, argv[argc - 1]);
-
    }

-
    return Jim_EvalEnsemble(interp, "dict", options[option], argc - 2, argv + 2);
+
        case OPT_UPDATE:
+
            if (argc < 6 || argc % 2) {
+

+
                argc = 2;
+
            }
+

+
        default:
+
            return Jim_EvalEnsemble(interp, "dict", Jim_String(argv[1]), argc - 2, argv + 2);
+
    }
}


@@ -18584,26 +20173,75 @@ static int Jim_SubstCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *ar
    return JIM_OK;
}

+
#ifdef jim_ext_namespace
+
static int JimIsGlobalNamespace(Jim_Obj *objPtr)
+
{
+
    int len;
+
    const char *str = Jim_GetString(objPtr, &len);
+
    return len >= 2 && str[0] == ':' && str[1] == ':';
+
}
+
#endif
+


static int Jim_InfoCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
-
    int cmd;
    Jim_Obj *objPtr;
    int mode = 0;

-
    static const char * const commands[] = {
-
        "body", "statics", "commands", "procs", "channels", "exists", "globals", "level", "frame", "locals",
-
        "vars", "version", "patchlevel", "complete", "args", "hostname",
-
        "script", "source", "stacktrace", "nameofexecutable", "returncodes",
-
        "references", "alias", NULL
+

+
    enum {
+
        INFO_ALIAS,
+
        INFO_ARGS,
+
        INFO_BODY,
+
        INFO_CHANNELS,
+
        INFO_COMMANDS,
+
        INFO_COMPLETE,
+
        INFO_EXISTS,
+
        INFO_FRAME,
+
        INFO_GLOBALS,
+
        INFO_HOSTNAME,
+
        INFO_LEVEL,
+
        INFO_LOCALS,
+
        INFO_NAMEOFEXECUTABLE,
+
        INFO_PATCHLEVEL,
+
        INFO_PROCS,
+
        INFO_REFERENCES,
+
        INFO_RETURNCODES,
+
        INFO_SCRIPT,
+
        INFO_SOURCE,
+
        INFO_STACKTRACE,
+
        INFO_STATICS,
+
        INFO_VARS,
+
        INFO_VERSION,
+
        INFO_COUNT
    };
-
    enum
-
    { INFO_BODY, INFO_STATICS, INFO_COMMANDS, INFO_PROCS, INFO_CHANNELS, INFO_EXISTS, INFO_GLOBALS, INFO_LEVEL,
-
        INFO_FRAME, INFO_LOCALS, INFO_VARS, INFO_VERSION, INFO_PATCHLEVEL, INFO_COMPLETE, INFO_ARGS,
-
        INFO_HOSTNAME, INFO_SCRIPT, INFO_SOURCE, INFO_STACKTRACE, INFO_NAMEOFEXECUTABLE,
-
        INFO_RETURNCODES, INFO_REFERENCES, INFO_ALIAS,
+
    static const jim_subcmd_type cmds[INFO_COUNT + 1] = {
+
        JIM_DEF_SUBCMD("alias", "command", 1, 1),
+
        JIM_DEF_SUBCMD("args", "procname", 1, 1),
+
        JIM_DEF_SUBCMD("body", "procname", 1, 1),
+
        JIM_DEF_SUBCMD("channels", "?pattern?", 0, 1),
+
        JIM_DEF_SUBCMD("commands", "?pattern?", 0, 1),
+
        JIM_DEF_SUBCMD("complete", "script ?missing?", 1, 2),
+
        JIM_DEF_SUBCMD("exists", "varName", 1, 1),
+
        JIM_DEF_SUBCMD("frame", "?levelNum?", 0, 1),
+
        JIM_DEF_SUBCMD("globals", "?pattern?", 0, 1),
+
        JIM_DEF_SUBCMD("hostname", NULL, 0, 0),
+
        JIM_DEF_SUBCMD("level", "?levelNum?", 0, 1),
+
        JIM_DEF_SUBCMD("locals", "?pattern?", 0, 1),
+
        JIM_DEF_SUBCMD("nameofexecutable", NULL, 0, 0),
+
        JIM_DEF_SUBCMD("patchlevel", NULL, 0, 0),
+
        JIM_DEF_SUBCMD("procs", "?pattern?", 0, 1),
+
        JIM_DEF_SUBCMD("references", NULL, 0, 0),
+
        JIM_DEF_SUBCMD("returncodes", "?code?", 0, 1),
+
        JIM_DEF_SUBCMD("script", "?filename?", 0, 1),
+
        JIM_DEF_SUBCMD("source", "source ?filename line?", 1, 3),
+
        JIM_DEF_SUBCMD("stacktrace", NULL, 0, 0),
+
        JIM_DEF_SUBCMD("statics", "procname", 1, 1),
+
        JIM_DEF_SUBCMD("vars", "?pattern?", 0, 1),
+
        JIM_DEF_SUBCMD("version", NULL, 0, 0),
+
        { }
    };
-

+
    const jim_subcmd_type *ct;
#ifdef jim_ext_namespace
    int nons = 0;

@@ -18614,32 +20252,25 @@ static int Jim_InfoCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *arg
        nons = 1;
    }
#endif
-

-
    if (argc < 2) {
-
        Jim_WrongNumArgs(interp, 1, argv, "subcommand ?args ...?");
+
    ct = Jim_ParseSubCmd(interp, cmds, argc, argv);
+
    if (!ct) {
        return JIM_ERR;
    }
-
    if (Jim_GetEnum(interp, argv[1], commands, &cmd, "subcommand", JIM_ERRMSG | JIM_ENUM_ABBREV) != JIM_OK) {
-
        return Jim_CheckShowCommands(interp, argv[1], commands);
+
    if (ct->function) {
+

+
        return ct->function(interp, argc, argv);
    }

+
    int option = ct - cmds;

-
    switch (cmd) {
+
    switch (option) {
        case INFO_EXISTS:
-
            if (argc != 3) {
-
                Jim_WrongNumArgs(interp, 2, argv, "varName");
-
                return JIM_ERR;
-
            }
            Jim_SetResultBool(interp, Jim_GetVariable(interp, argv[2], 0) != NULL);
-
            break;
+
            return JIM_OK;

        case INFO_ALIAS:{
            Jim_Cmd *cmdPtr;

-
            if (argc != 3) {
-
                Jim_WrongNumArgs(interp, 2, argv, "command");
-
                return JIM_ERR;
-
            }
            if ((cmdPtr = Jim_GetCommand(interp, argv[2], JIM_ERRMSG)) == NULL) {
                return JIM_ERR;
            }
@@ -18663,19 +20294,15 @@ static int Jim_InfoCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *arg

        case INFO_COMMANDS:

-
            if (argc != 2 && argc != 3) {
-
                Jim_WrongNumArgs(interp, 2, argv, "?pattern?");
-
                return JIM_ERR;
-
            }
#ifdef jim_ext_namespace
            if (!nons) {
-
                if (Jim_Length(interp->framePtr->nsObj) || (argc == 3 && JimGlobMatch("::*", Jim_String(argv[2]), 0))) {
+
                if (Jim_Length(interp->framePtr->nsObj) || (argc == 3 && JimIsGlobalNamespace(argv[2]))) {
                    return Jim_EvalPrefix(interp, "namespace info", argc - 1, argv + 1);
                }
            }
#endif
            Jim_SetResult(interp, JimCommandsList(interp, (argc == 3) ? argv[2] : NULL, mode));
-
            break;
+
            return JIM_OK;

        case INFO_VARS:
            mode++;
@@ -18685,35 +20312,32 @@ static int Jim_InfoCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *arg

        case INFO_GLOBALS:

-
            if (argc != 2 && argc != 3) {
-
                Jim_WrongNumArgs(interp, 2, argv, "?pattern?");
-
                return JIM_ERR;
-
            }
#ifdef jim_ext_namespace
            if (!nons) {
-
                if (Jim_Length(interp->framePtr->nsObj) || (argc == 3 && JimGlobMatch("::*", Jim_String(argv[2]), 0))) {
+
                if (Jim_Length(interp->framePtr->nsObj) || (argc == 3 && JimIsGlobalNamespace(argv[2]))) {
                    return Jim_EvalPrefix(interp, "namespace info", argc - 1, argv + 1);
                }
            }
#endif
            Jim_SetResult(interp, JimVariablesList(interp, argc == 3 ? argv[2] : NULL, mode));
-
            break;
+
            return JIM_OK;

        case INFO_SCRIPT:
-
            if (argc != 2) {
-
                Jim_WrongNumArgs(interp, 2, argv, "");
-
                return JIM_ERR;
+
            if (argc == 3) {
+
                Jim_IncrRefCount(argv[2]);
+
                Jim_DecrRefCount(interp, interp->currentFilenameObj);
+
                interp->currentFilenameObj = argv[2];
            }
-
            Jim_SetResult(interp, JimGetScript(interp, interp->currentScriptObj)->fileNameObj);
-
            break;
+
            Jim_SetResult(interp, interp->currentFilenameObj);
+
            return JIM_OK;

        case INFO_SOURCE:{
                jim_wide line;
                Jim_Obj *resObjPtr;
                Jim_Obj *fileNameObj;

-
                if (argc != 3 && argc != 5) {
-
                    Jim_WrongNumArgs(interp, 2, argv, "source ?filename line?");
+
                if (argc == 4) {
+
                    Jim_SubCmdArgError(interp, ct, argv[0]);
                    return JIM_ERR;
                }
                if (argc == 5) {
@@ -18742,42 +20366,42 @@ static int Jim_InfoCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *arg
                    Jim_ListAppendElement(interp, resObjPtr, Jim_NewIntObj(interp, line));
                }
                Jim_SetResult(interp, resObjPtr);
-
                break;
+
                return JIM_OK;
            }

        case INFO_STACKTRACE:
            Jim_SetResult(interp, interp->stackTrace);
-
            break;
+
            return JIM_OK;

        case INFO_LEVEL:
-
        case INFO_FRAME:
-
            switch (argc) {
-
                case 2:
-
                    Jim_SetResultInt(interp, interp->framePtr->level);
-
                    break;
-

-
                case 3:
-
                    if (JimInfoLevel(interp, argv[2], &objPtr, cmd == INFO_LEVEL) != JIM_OK) {
-
                        return JIM_ERR;
-
                    }
-
                    Jim_SetResult(interp, objPtr);
-
                    break;
+
            if (argc == 2) {
+
                Jim_SetResultInt(interp, interp->framePtr->level);
+
            }
+
            else {
+
                if (JimInfoLevel(interp, argv[2], &objPtr) != JIM_OK) {
+
                    return JIM_ERR;
+
                }
+
                Jim_SetResult(interp, objPtr);
+
            }
+
            return JIM_OK;

-
                default:
-
                    Jim_WrongNumArgs(interp, 2, argv, "?levelNum?");
+
        case INFO_FRAME:
+
            if (argc == 2) {
+
                Jim_SetResultInt(interp, interp->procLevel + 1);
+
            }
+
            else {
+
                if (JimInfoFrame(interp, argv[2], &objPtr) != JIM_OK) {
                    return JIM_ERR;
+
                }
+
                Jim_SetResult(interp, objPtr);
            }
-
            break;
+
            return JIM_OK;

        case INFO_BODY:
        case INFO_STATICS:
        case INFO_ARGS:{
                Jim_Cmd *cmdPtr;

-
                if (argc != 3) {
-
                    Jim_WrongNumArgs(interp, 2, argv, "procname");
-
                    return JIM_ERR;
-
                }
                if ((cmdPtr = Jim_GetCommand(interp, argv[2], JIM_ERRMSG)) == NULL) {
                    return JIM_ERR;
                }
@@ -18785,13 +20409,19 @@ static int Jim_InfoCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *arg
                    Jim_SetResultFormatted(interp, "command \"%#s\" is not a procedure", argv[2]);
                    return JIM_ERR;
                }
-
                switch (cmd) {
+
                switch (option) {
+
#ifdef JIM_NO_INTROSPECTION
+
                    default:
+
                        Jim_SetResultString(interp, "unsupported", -1);
+
                        return JIM_ERR;
+
#else
                    case INFO_BODY:
                        Jim_SetResult(interp, cmdPtr->u.proc.bodyObjPtr);
                        break;
                    case INFO_ARGS:
                        Jim_SetResult(interp, cmdPtr->u.proc.argListObjPtr);
                        break;
+
#endif
                    case INFO_STATICS:
                        if (cmdPtr->u.proc.staticVars) {
                            Jim_SetResult(interp, JimHashtablePatternMatch(interp, cmdPtr->u.proc.staticVars,
@@ -18799,7 +20429,7 @@ static int Jim_InfoCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *arg
                        }
                        break;
                }
-
                break;
+
                return JIM_OK;
            }

        case INFO_VERSION:
@@ -18808,23 +20438,18 @@ static int Jim_InfoCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *arg

                sprintf(buf, "%d.%d", JIM_VERSION / 100, JIM_VERSION % 100);
                Jim_SetResultString(interp, buf, -1);
-
                break;
+
                return JIM_OK;
            }

-
        case INFO_COMPLETE:
-
            if (argc != 3 && argc != 4) {
-
                Jim_WrongNumArgs(interp, 2, argv, "script ?missing?");
-
                return JIM_ERR;
-
            }
-
            else {
+
        case INFO_COMPLETE: {
                char missing;

                Jim_SetResultBool(interp, Jim_ScriptIsComplete(interp, argv[2], &missing));
                if (missing != ' ' && argc == 4) {
                    Jim_SetVariable(interp, argv[3], Jim_NewStringObj(interp, &missing, 1));
                }
+
                return JIM_OK;
            }
-
            break;

        case INFO_HOSTNAME:

@@ -18862,11 +20487,7 @@ static int Jim_InfoCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *arg
                    Jim_SetResultString(interp, name, -1);
                }
            }
-
            else {
-
                Jim_WrongNumArgs(interp, 2, argv, "?code?");
-
                return JIM_ERR;
-
            }
-
            break;
+
            return JIM_OK;
        case INFO_REFERENCES:
#ifdef JIM_REFERENCES
            return JimInfoReferences(interp, argc, argv);
@@ -18874,8 +20495,9 @@ static int Jim_InfoCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *arg
            Jim_SetResultString(interp, "not supported", -1);
            return JIM_ERR;
#endif
+
        default:
+
            abort();
    }
-
    return JIM_OK;
}


@@ -19147,7 +20769,6 @@ static int Jim_ErrorCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *ar
        JimSetStackTrace(interp, argv[2]);
        return JIM_ERR;
    }
-
    interp->addStackTrace++;
    return JIM_ERR;
}

@@ -19170,22 +20791,23 @@ static int Jim_LrangeCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *a
static int Jim_LrepeatCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
    Jim_Obj *objPtr;
-
    long count;
+
    jim_wide count;

-
    if (argc < 2 || Jim_GetLong(interp, argv[1], &count) != JIM_OK || count < 0) {
+
    if (argc < 2 || Jim_GetWideExpr(interp, argv[1], &count) != JIM_OK || count < 0) {
        Jim_WrongNumArgs(interp, 1, argv, "count ?value ...?");
        return JIM_ERR;
    }
-

    if (count == 0 || argc == 2) {
+
        Jim_SetEmptyResult(interp);
        return JIM_OK;
    }

    argc -= 2;
    argv += 2;

-
    objPtr = Jim_NewListObj(interp, argv, argc);
-
    while (--count) {
+
    objPtr = Jim_NewListObj(interp, NULL, 0);
+
    ListEnsureLength(objPtr, argc * count);
+
    while (count--) {
        ListInsertElements(objPtr, -1, argc, argv);
    }

@@ -19245,7 +20867,7 @@ static int Jim_EnvCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv
        return JIM_OK;
    }

-
    if (argc < 2) {
+
    if (argc > 3) {
        Jim_WrongNumArgs(interp, 1, argv, "varName ?default?");
        return JIM_ERR;
    }
@@ -19288,8 +20910,9 @@ static int Jim_LreverseCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const
        return JIM_ERR;
    }
    JimListGetElements(interp, argv[1], &len, &ele);
-
    len--;
    revObjPtr = Jim_NewListObj(interp, NULL, 0);
+
    ListEnsureLength(revObjPtr, len);
+
    len--;
    while (len >= 0)
        ListAppendElement(revObjPtr, ele[len--]);
    Jim_SetResult(interp, revObjPtr);
@@ -19331,14 +20954,14 @@ static int Jim_RangeCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *ar
        return JIM_ERR;
    }
    if (argc == 2) {
-
        if (Jim_GetWide(interp, argv[1], &end) != JIM_OK)
+
        if (Jim_GetWideExpr(interp, argv[1], &end) != JIM_OK)
            return JIM_ERR;
    }
    else {
-
        if (Jim_GetWide(interp, argv[1], &start) != JIM_OK ||
-
            Jim_GetWide(interp, argv[2], &end) != JIM_OK)
+
        if (Jim_GetWideExpr(interp, argv[1], &start) != JIM_OK ||
+
            Jim_GetWideExpr(interp, argv[2], &end) != JIM_OK)
            return JIM_ERR;
-
        if (argc == 4 && Jim_GetWide(interp, argv[3], &step) != JIM_OK)
+
        if (argc == 4 && Jim_GetWideExpr(interp, argv[3], &step) != JIM_OK)
            return JIM_ERR;
    }
    if ((len = JimRangeLen(start, end, step)) == -1) {
@@ -19346,6 +20969,7 @@ static int Jim_RangeCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *ar
        return JIM_ERR;
    }
    objPtr = Jim_NewListObj(interp, NULL, 0);
+
    ListEnsureLength(objPtr, len);
    for (i = 0; i < len; i++)
        ListAppendElement(objPtr, Jim_NewIntObj(interp, start + i * step));
    Jim_SetResult(interp, objPtr);
@@ -19364,11 +20988,11 @@ static int Jim_RandCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *arg
    if (argc == 1) {
        max = JIM_WIDE_MAX;
    } else if (argc == 2) {
-
        if (Jim_GetWide(interp, argv[1], &max) != JIM_OK)
+
        if (Jim_GetWideExpr(interp, argv[1], &max) != JIM_OK)
            return JIM_ERR;
    } else if (argc == 3) {
-
        if (Jim_GetWide(interp, argv[1], &min) != JIM_OK ||
-
            Jim_GetWide(interp, argv[2], &max) != JIM_OK)
+
        if (Jim_GetWideExpr(interp, argv[1], &min) != JIM_OK ||
+
            Jim_GetWideExpr(interp, argv[2], &max) != JIM_OK)
            return JIM_ERR;
    }
    len = max-min;
@@ -19419,21 +21043,23 @@ static const struct {
    {"lreplace", Jim_LreplaceCoreCommand},
    {"lsort", Jim_LsortCoreCommand},
    {"append", Jim_AppendCoreCommand},
-
    {"debug", Jim_DebugCoreCommand},
    {"eval", Jim_EvalCoreCommand},
    {"uplevel", Jim_UplevelCoreCommand},
    {"expr", Jim_ExprCoreCommand},
    {"break", Jim_BreakCoreCommand},
    {"continue", Jim_ContinueCoreCommand},
    {"proc", Jim_ProcCoreCommand},
+
    {"xtrace", Jim_XtraceCoreCommand},
    {"concat", Jim_ConcatCoreCommand},
    {"return", Jim_ReturnCoreCommand},
    {"upvar", Jim_UpvarCoreCommand},
    {"global", Jim_GlobalCoreCommand},
    {"string", Jim_StringCoreCommand},
    {"time", Jim_TimeCoreCommand},
+
    {"timerate", Jim_TimeRateCoreCommand},
    {"exit", Jim_ExitCoreCommand},
    {"catch", Jim_CatchCoreCommand},
+
    {"try", Jim_TryCoreCommand},
#ifdef JIM_REFERENCES
    {"ref", Jim_RefCoreCommand},
    {"getref", Jim_GetrefCoreCommand},
@@ -19462,6 +21088,7 @@ static const struct {
    {"local", Jim_LocalCoreCommand},
    {"upcall", Jim_UpcallCoreCommand},
    {"apply", Jim_ApplyCoreCommand},
+
    {"stacktrace", Jim_StacktraceCoreCommand},
    {NULL, NULL},
};

@@ -19689,6 +21316,15 @@ void Jim_SetResultFormatted(Jim_Interp *interp, const char *format, ...)
    }
}

+
int Jim_CheckAbiVersion(Jim_Interp *interp, int abi_version)
+
{
+
    if (abi_version != JIM_ABI_VERSION) {
+
        Jim_SetResultString(interp, "ABI version mismatch", -1);
+
        return JIM_ERR;
+
    }
+
    return JIM_OK;
+
}
+


#ifndef jim_ext_package
int Jim_PackageProvide(Jim_Interp *interp, const char *name, const char *ver, int flags)
@@ -19697,10 +21333,9 @@ int Jim_PackageProvide(Jim_Interp *interp, const char *name, const char *ver, in
}
#endif
#ifndef jim_ext_aio
-
FILE *Jim_AioFilehandle(Jim_Interp *interp, Jim_Obj *fhObj)
+
int Jim_AioFilehandle(Jim_Interp *interp, Jim_Obj *fhObj)
{
-
    Jim_SetResultString(interp, "aio not enabled", -1);
-
    return NULL;
+
    return -1;
}
#endif

@@ -19719,30 +21354,41 @@ static const jim_subcmd_type dummy_subcmd = {
    "dummy", NULL, subcmd_null, 0, 0, JIM_MODFLAG_HIDDEN
};

-
static void add_commands(Jim_Interp *interp, const jim_subcmd_type * ct, const char *sep)
+
static Jim_Obj *subcmd_cmd_list(Jim_Interp *interp, const jim_subcmd_type * ct, const char *sep)
{
-
    const char *s = "";
+

+
    Jim_Obj *listObj = Jim_NewListObj(interp, NULL, 0);
+
    Jim_Obj *sortCmd[2];

    for (; ct->cmd; ct++) {
        if (!(ct->flags & JIM_MODFLAG_HIDDEN)) {
-
            Jim_AppendStrings(interp, Jim_GetResult(interp), s, ct->cmd, NULL);
-
            s = sep;
+
            Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, ct->cmd, -1));
        }
    }
+

+

+
    sortCmd[0] = Jim_NewStringObj(interp, "lsort", -1);
+
    sortCmd[1] = listObj;
+

+
    if (Jim_EvalObjVector(interp, 2, sortCmd) == JIM_OK) {
+
        return Jim_ListJoin(interp, Jim_GetResult(interp), sep, strlen(sep));
+
    }
+

+
    return Jim_GetResult(interp);
}

static void bad_subcmd(Jim_Interp *interp, const jim_subcmd_type * command_table, const char *type,
    Jim_Obj *cmd, Jim_Obj *subcmd)
{
-
    Jim_SetResultFormatted(interp, "%#s, %s command \"%#s\": should be ", cmd, type, subcmd);
-
    add_commands(interp, command_table, ", ");
+
    Jim_SetResultFormatted(interp, "%#s, %s command \"%#s\": should be %#s", cmd, type,
+
        subcmd, subcmd_cmd_list(interp, command_table, ", "));
}

static void show_cmd_usage(Jim_Interp *interp, const jim_subcmd_type * command_table, int argc,
    Jim_Obj *const *argv)
{
-
    Jim_SetResultFormatted(interp, "Usage: \"%#s command ... \", where command is one of: ", argv[0]);
-
    add_commands(interp, command_table, ", ");
+
    Jim_SetResultFormatted(interp, "Usage: \"%#s command ... \", where command is one of: %#s",
+
        argv[0], subcmd_cmd_list(interp, command_table, ", "));
}

static void add_cmd_usage(Jim_Interp *interp, const jim_subcmd_type * ct, Jim_Obj *cmd)
@@ -19756,10 +21402,10 @@ static void add_cmd_usage(Jim_Interp *interp, const jim_subcmd_type * ct, Jim_Ob
    }
}

-
static void set_wrong_args(Jim_Interp *interp, const jim_subcmd_type * command_table, Jim_Obj *subcmd)
+
void Jim_SubCmdArgError(Jim_Interp *interp, const jim_subcmd_type * ct, Jim_Obj *subcmd)
{
    Jim_SetResultString(interp, "wrong # args: should be \"", -1);
-
    add_cmd_usage(interp, command_table, subcmd);
+
    add_cmd_usage(interp, ct, subcmd);
    Jim_AppendStrings(interp, Jim_GetResult(interp), "\"", NULL);
}

@@ -19780,6 +21426,7 @@ const jim_subcmd_type *Jim_ParseSubCmd(Jim_Interp *interp, const jim_subcmd_type
    Jim_Obj *cmd;
    const char *cmdstr;
    int help = 0;
+
    int argsok = 1;

    if (argc < 2) {
        Jim_SetResultFormatted(interp, "wrong # args: should be \"%#s command ...\"\n"
@@ -19812,9 +21459,7 @@ const jim_subcmd_type *Jim_ParseSubCmd(Jim_Interp *interp, const jim_subcmd_type


    if (Jim_CompareStringImmediate(interp, cmd, "-commands")) {
-

-
        Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
-
        add_commands(interp, command_table, " ");
+
        Jim_SetResult(interp, subcmd_cmd_list(interp, command_table, " "));
        return &dummy_subcmd;
    }

@@ -19872,7 +21517,18 @@ const jim_subcmd_type *Jim_ParseSubCmd(Jim_Interp *interp, const jim_subcmd_type

found:

-
    if (argc - 2 < ct->minargs || (ct->maxargs >= 0 && argc - 2 > ct->maxargs)) {
+

+
    if (argc - 2 < ct->minargs) {
+
        argsok = 0;
+
    }
+
    else if (ct->maxargs >= 0 && argc - 2 > ct->maxargs) {
+
        argsok = 0;
+
    }
+
    else if (ct->maxargs < -1 && (argc - 2) % -ct->maxargs != 0) {
+

+
        argsok = 0;
+
    }
+
    if (!argsok) {
        Jim_SetResultString(interp, "wrong # args: should be \"", -1);

        add_cmd_usage(interp, ct, argv[0]);
@@ -19897,7 +21553,7 @@ int Jim_CallSubCmd(Jim_Interp *interp, const jim_subcmd_type * ct, int argc, Jim
            ret = ct->function(interp, argc - 2, argv + 2);
        }
        if (ret < 0) {
-
            set_wrong_args(interp, ct, argv[0]);
+
            Jim_SubCmdArgError(interp, ct, argv[0]);
            ret = JIM_ERR;
        }
    }
@@ -19948,6 +21604,7 @@ int utf8_fromunicode(char *p, unsigned uc)

#include <ctype.h>
#include <string.h>
+
#include <stdio.h>


#define JIM_INTEGER_SPACE 24
@@ -20194,7 +21851,7 @@ Jim_Obj *Jim_FormatString(Jim_Interp *interp, Jim_Obj *fmtObjPtr, int objc, Jim_
                j = 0;
                for (i = length; i > 0; ) {
                        i--;
-
                    if (w & ((unsigned jim_wide)1 << i)) {
+
                        if (w & ((unsigned jim_wide)1 << i)) {
                                num_buffer[j++] = '1';
                        }
                        else if (j || i == 0) {
@@ -20430,7 +22087,7 @@ static int str_int_len(const int *seq)
	return n;
}

-
int regcomp(regex_t *preg, const char *exp, int cflags)
+
int jim_regcomp(regex_t *preg, const char *exp, int cflags)
{
	int scan;
	int longest;
@@ -20845,7 +22502,7 @@ static int regatom(regex_t *preg, int *flagp)
				pattern++;
			}

-
			while (*pattern && *pattern != ']') {
+
			while (*pattern != ']') {

				int start;
				int end;
@@ -20857,6 +22514,11 @@ static int regatom(regex_t *preg, int *flagp)
				};
				int cc;

+
				if (!*pattern) {
+
					preg->err = REG_ERR_UNMATCHED_BRACKET;
+
					return 0;
+
				}
+

				pattern += reg_utf8_tounicode_case(pattern, &start, nocase);
				if (start == '\\') {

@@ -20880,6 +22542,10 @@ static int regatom(regex_t *preg, int *flagp)
						preg->err = REG_ERR_NULL_CHAR;
						return 0;
					}
+
					if (start == '\\' && *pattern == 0) {
+
						preg->err = REG_ERR_INVALID_ESCAPE;
+
						return 0;
+
					}
				}
				if (pattern[0] == '-' && pattern[1] && pattern[1] != ']') {

@@ -20891,6 +22557,10 @@ static int regatom(regex_t *preg, int *flagp)
							preg->err = REG_ERR_NULL_CHAR;
							return 0;
						}
+
						if (end == '\\' && *pattern == 0) {
+
							preg->err = REG_ERR_INVALID_ESCAPE;
+
							return 0;
+
						}
					}

					reg_addrange(preg, start, end);
@@ -20905,6 +22575,10 @@ static int regatom(regex_t *preg, int *flagp)
					for (cc = 0; cc < CC_NUM; cc++) {
						n = strlen(character_class[cc]);
						if (strncmp(pattern, character_class[cc], n) == 0) {
+
							if (pattern[n] != ']') {
+
								preg->err = REG_ERR_UNMATCHED_BRACKET;
+
								return 0;
+
							}

							pattern += n + 1;
							break;
@@ -20995,7 +22669,7 @@ cc_switch:
		ch = *preg->regparse++;
		switch (ch) {
		case '\0':
-
			preg->err = REG_ERR_TRAILING_BACKSLASH;
+
			preg->err = REG_ERR_INVALID_ESCAPE;
			return 0;
		case 'A':
			ret = regnode(preg, BOLX);
@@ -21182,7 +22856,7 @@ 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)
+
int jim_regexec(regex_t  *preg,  const  char *string, size_t nmatch, regmatch_t pmatch[], int eflags)
{
	const char *s;
	int scan;
@@ -21523,7 +23197,7 @@ static int regmatch(regex_t *preg, int prog)

			if (preg->reginput > preg->regbol) {

-
				if (reg_iseol(preg, c) || !isalnum(UCHAR(c)) || c != '_') {
+
				if (reg_iseol(preg, c) || !(isalnum(UCHAR(c)) || c == '_')) {
					c = preg->reginput[-1];

					if (isalnum(UCHAR(c)) || c == '_') {
@@ -21619,6 +23293,8 @@ static int regmatch(regex_t *preg, int prog)
					}
					return(1);
				}
+

+
				preg->reginput = save;
				return(0);
			}
			return REG_ERR_INTERNAL;
@@ -21642,10 +23318,9 @@ static int regrepeat(regex_t *preg, int p, int max)
	opnd = OPERAND(p);
	switch (OP(preg, p)) {
	case ANY:
-

		while (!reg_iseol(preg, *scan) && count < max) {
			count++;
-
			scan++;
+
			scan += utf8_charlen(*scan);
		}
		break;
	case EXACTLY:
@@ -21726,7 +23401,7 @@ static int regopsize(regex_t *preg, int p )
}


-
size_t regerror(int errcode, const regex_t *preg, char *errbuf,  size_t errbuf_size)
+
size_t jim_regerror(int errcode, const regex_t *preg, char *errbuf,  size_t errbuf_size)
{
	static const char *error_strings[] = {
		"success",
@@ -21745,9 +23420,10 @@ size_t regerror(int errcode, const regex_t *preg, char *errbuf, size_t errbuf_s
		"nested count",
		"internal error",
		"count follows nothing",
-
		"trailing backslash",
+
		"invalid escape \\ sequence",
		"corrupted program",
		"contains null char",
+
		"brackets [] not balanced",
	};
	const char *err;

@@ -21761,7 +23437,7 @@ size_t regerror(int errcode, const regex_t *preg, char *errbuf, size_t errbuf_s
	return snprintf(errbuf, errbuf_size, "%s", err);
}

-
void regfree(regex_t *preg)
+
void jim_regfree(regex_t *preg)
{
	free(preg->program);
}
@@ -21858,16 +23534,42 @@ int Jim_Errno(void)
    return EINVAL;
}

-
pidtype waitpid(pidtype pid, int *status, int nohang)
+
long JimProcessPid(phandle_t pid)
+
{
+
    if (pid == INVALID_HANDLE_VALUE) {
+
        return -1;
+
    }
+
    return GetProcessId(pid);
+
}
+

+
phandle_t JimWaitPid(long pid, int *status, int nohang)
+
{
+
    if (pid > 0) {
+
        HANDLE h = OpenProcess(PROCESS_QUERY_INFORMATION | SYNCHRONIZE, FALSE, pid);
+
        if (h) {
+
            long pid = waitpid(h, status, nohang);
+
            CloseHandle(h);
+
            if (pid > 0) {
+
                return h;
+
            }
+
        }
+
    }
+
    return JIM_BAD_PHANDLE;
+
}
+

+
long waitpid(phandle_t phandle, int *status, int nohang)
{
-
    DWORD ret = WaitForSingleObject(pid, nohang ? 0 : INFINITE);
+
    long pid;
+
    DWORD ret = WaitForSingleObject(phandle, nohang ? 0 : INFINITE);
    if (ret == WAIT_TIMEOUT || ret == WAIT_FAILED) {

-
        return JIM_BAD_PID;
+
        return -1;
    }
-
    GetExitCodeProcess(pid, &ret);
+
    GetExitCodeProcess(phandle, &ret);
    *status = ret;
-
    CloseHandle(pid);
+

+
    pid = GetProcessId(phandle);
+
    CloseHandle(phandle);
    return pid;
}

@@ -21889,7 +23591,7 @@ int Jim_MakeTempFile(Jim_Interp *interp, const char *filename_template, int unli
    }

    Jim_SetResultString(interp, name, -1);
-
    return _open_osfhandle((int)handle, _O_RDWR | _O_TEXT);
+
    return _open_osfhandle((intptr_t)handle, _O_RDWR | _O_TEXT);

  error:
    Jim_SetResultErrno(interp, name);
@@ -22127,6 +23829,7 @@ const char *Jim_SignalId(int sig)
#ifndef JIM_BOOTSTRAP_LIB_ONLY
#include <errno.h>
#include <string.h>
+
#include <stdio.h>


#ifdef USE_LINENOISE
@@ -22142,20 +23845,34 @@ const char *Jim_SignalId(int sig)
#endif

#ifdef USE_LINENOISE
+
struct JimCompletionInfo {
+
    Jim_Interp *interp;
+
    Jim_Obj *completion_command;
+
    Jim_Obj *hints_command;
+

+
};
+

+
static struct JimCompletionInfo *JimGetCompletionInfo(Jim_Interp *interp);
static void JimCompletionCallback(const char *prefix, linenoiseCompletions *comp, void *userdata);
static const char completion_callback_assoc_key[] = "interactive-completion";
+
static char *JimHintsCallback(const char *prefix, int *color, int *bold, void *userdata);
+
static void JimFreeHintsCallback(void *hint, void *userdata);
#endif

char *Jim_HistoryGetline(Jim_Interp *interp, const char *prompt)
{
#ifdef USE_LINENOISE
-
    struct JimCompletionInfo *compinfo = Jim_GetAssocData(interp, completion_callback_assoc_key);
+
    struct JimCompletionInfo *compinfo = JimGetCompletionInfo(interp);
    char *result;
    Jim_Obj *objPtr;
    long mlmode = 0;
-
    if (compinfo) {
+
    if (compinfo->completion_command) {
        linenoiseSetCompletionCallback(JimCompletionCallback, compinfo);
    }
+
    if (compinfo->hints_command) {
+
        linenoiseSetHintsCallback(JimHintsCallback, compinfo);
+
        linenoiseSetFreeHintsCallback(JimFreeHintsCallback);
+
    }
    objPtr = Jim_GetVariableStr(interp, "history::multiline", JIM_NONE);
    if (objPtr && Jim_GetLong(interp, objPtr, &mlmode) == JIM_NONE) {
        linenoiseSetMultiLine(mlmode);
@@ -22164,16 +23881,18 @@ char *Jim_HistoryGetline(Jim_Interp *interp, const char *prompt)
    result = linenoise(prompt);

    linenoiseSetCompletionCallback(NULL, NULL);
+
    linenoiseSetHintsCallback(NULL, NULL);
+
    linenoiseSetFreeHintsCallback(NULL);
    return result;
#else
    int len;
-
    char *line = malloc(MAX_LINE_LEN);
+
    char *line = Jim_Alloc(MAX_LINE_LEN);

    fputs(prompt, stdout);
    fflush(stdout);

    if (fgets(line, MAX_LINE_LEN, stdin) == NULL) {
-
        free(line);
+
        Jim_Free(line);
        return NULL;
    }
    len = strlen(line);
@@ -22226,19 +23945,29 @@ void Jim_HistoryShow(void)
#endif
}

+
void Jim_HistorySetMaxLen(int length)
+
{
#ifdef USE_LINENOISE
-
struct JimCompletionInfo {
-
    Jim_Interp *interp;
-
    Jim_Obj *command;
-
};
+
    linenoiseHistorySetMaxLen(length);
+
#endif
+
}

+
int Jim_HistoryGetMaxLen(void)
+
{
+
#ifdef USE_LINENOISE
+
    return linenoiseHistoryGetMaxLen();
+
#endif
+
    return 0;
+
}
+

+
#ifdef USE_LINENOISE
static void JimCompletionCallback(const char *prefix, linenoiseCompletions *comp, void *userdata)
{
    struct JimCompletionInfo *info = (struct JimCompletionInfo *)userdata;
    Jim_Obj *objv[2];
    int ret;

-
    objv[0] = info->command;
+
    objv[0] = info->completion_command;
    objv[1] = Jim_NewStringObj(info->interp, prefix, -1);

    ret = Jim_EvalObjVector(info->interp, 2, objv);
@@ -22254,33 +23983,101 @@ static void JimCompletionCallback(const char *prefix, linenoiseCompletions *comp
    }
}

+
static char *JimHintsCallback(const char *prefix, int *color, int *bold, void *userdata)
+
{
+
    struct JimCompletionInfo *info = (struct JimCompletionInfo *)userdata;
+
    Jim_Obj *objv[2];
+
    int ret;
+
    char *result = NULL;
+

+
    objv[0] = info->hints_command;
+
    objv[1] = Jim_NewStringObj(info->interp, prefix, -1);
+

+
    ret = Jim_EvalObjVector(info->interp, 2, objv);
+

+

+
    if (ret == JIM_OK) {
+
        Jim_Obj *listObj = Jim_GetResult(info->interp);
+
        Jim_IncrRefCount(listObj);
+

+
        int len = Jim_ListLength(info->interp, listObj);
+
        if (len >= 1) {
+
            long x;
+
            result = Jim_StrDup(Jim_String(Jim_ListGetIndex(info->interp, listObj, 0)));
+
            if (len >= 2 && Jim_GetLong(info->interp, Jim_ListGetIndex(info->interp, listObj, 1), &x) == JIM_OK) {
+
                *color = x;
+
            }
+
            if (len >= 3 && Jim_GetLong(info->interp, Jim_ListGetIndex(info->interp, listObj, 2), &x) == JIM_OK) {
+
                *bold = x;
+
            }
+
        }
+
        Jim_DecrRefCount(info->interp, listObj);
+
    }
+
    return result;
+
}
+

+
static void JimFreeHintsCallback(void *hint, void *userdata)
+
{
+
    Jim_Free(hint);
+
}
+

static void JimHistoryFreeCompletion(Jim_Interp *interp, void *data)
{
    struct JimCompletionInfo *compinfo = data;

-
    Jim_DecrRefCount(interp, compinfo->command);
+
    if (compinfo->completion_command) {
+
        Jim_DecrRefCount(interp, compinfo->completion_command);
+
    }
+
    if (compinfo->hints_command) {
+
        Jim_DecrRefCount(interp, compinfo->hints_command);
+
    }

    Jim_Free(compinfo);
}
+

+
static struct JimCompletionInfo *JimGetCompletionInfo(Jim_Interp *interp)
+
{
+
    struct JimCompletionInfo *compinfo = Jim_GetAssocData(interp, completion_callback_assoc_key);
+
    if (compinfo == NULL) {
+
        compinfo = Jim_Alloc(sizeof(*compinfo));
+
        compinfo->interp = interp;
+
        compinfo->completion_command = NULL;
+
        compinfo->hints_command = NULL;
+
        Jim_SetAssocData(interp, completion_callback_assoc_key, JimHistoryFreeCompletion, compinfo);
+
    }
+
    return compinfo;
+
}
#endif

-
void Jim_HistorySetCompletion(Jim_Interp *interp, Jim_Obj *commandObj)
+
void Jim_HistorySetCompletion(Jim_Interp *interp, Jim_Obj *completionCommandObj)
{
#ifdef USE_LINENOISE
-
    if (commandObj) {
+
    struct JimCompletionInfo *compinfo = JimGetCompletionInfo(interp);

-
        Jim_IncrRefCount(commandObj);
+
    if (completionCommandObj) {
+

+
        Jim_IncrRefCount(completionCommandObj);
+
    }
+
    if (compinfo->completion_command) {
+
        Jim_DecrRefCount(interp, compinfo->completion_command);
    }
+
    compinfo->completion_command = completionCommandObj;
+
#endif
+
}

-
    Jim_DeleteAssocData(interp, completion_callback_assoc_key);
+
void Jim_HistorySetHints(Jim_Interp *interp, Jim_Obj *hintsCommandObj)
+
{
+
#ifdef USE_LINENOISE
+
    struct JimCompletionInfo *compinfo = JimGetCompletionInfo(interp);

-
    if (commandObj) {
-
        struct JimCompletionInfo *compinfo = Jim_Alloc(sizeof(*compinfo));
-
        compinfo->interp = interp;
-
        compinfo->command = commandObj;
+
    if (hintsCommandObj) {

-
        Jim_SetAssocData(interp, completion_callback_assoc_key, JimHistoryFreeCompletion, compinfo);
+
        Jim_IncrRefCount(hintsCommandObj);
+
    }
+
    if (compinfo->hints_command) {
+
        Jim_DecrRefCount(interp, compinfo->hints_command);
    }
+
    compinfo->hints_command = hintsCommandObj;
#endif
}

@@ -22300,6 +24097,7 @@ int Jim_InteractivePrompt(Jim_Interp *interp)
    }

    Jim_HistorySetCompletion(interp, Jim_NewStringObj(interp, "tcl::autocomplete", -1));
+
    Jim_HistorySetHints(interp, Jim_NewStringObj(interp, "tcl::stdhint", -1));
#endif

    printf("Welcome to Jim version %d.%d\n",
@@ -22346,7 +24144,7 @@ int Jim_InteractivePrompt(Jim_Interp *interp)
                Jim_AppendString(interp, scriptObjPtr, "\n", 1);
            }
            Jim_AppendString(interp, scriptObjPtr, line, -1);
-
            free(line);
+
            Jim_Free(line);
            if (Jim_ScriptIsComplete(interp, scriptObjPtr, &state))
                break;

@@ -22376,7 +24174,10 @@ int Jim_InteractivePrompt(Jim_Interp *interp)
        }
        result = Jim_GetString(Jim_GetResult(interp), &reslen);
        if (reslen) {
-
            printf("%s\n", result);
+
            if (fwrite(result, reslen, 1, stdout) == 0) {
+

+
            }
+
            putchar('\n');
        }
    }
  out:
@@ -22478,7 +24279,12 @@ int main(int argc, char *const argv[])
            JimSetArgv(interp, argc - 3, argv + 3);
            retcode = Jim_Eval(interp, argv[2]);
            if (retcode != JIM_ERR) {
-
                printf("%s\n", Jim_String(Jim_GetResult(interp)));
+
                int len;
+
                const char *msg = Jim_GetString(Jim_GetResult(interp), &len);
+
                if (fwrite(msg, len, 1, stdout) == 0) {
+

+
                }
+
                putchar('\n');
            }
        }
        else {
modified autosetup/system.tcl
@@ -19,7 +19,7 @@
## mandir
## includedir
#
-
# If '--prefix' is not supplied, it defaults to '/usr/local' unless 'defaultprefix' is defined *before*
+
# If '--prefix' is not supplied, it defaults to '/usr/local' unless 'options-defaults { prefix ... }' is used *before*
# including the 'system' module.

if {[is-defined defaultprefix]} {
@@ -52,6 +52,9 @@ options {
	maintainer-mode=0
	dependency-tracking=0
	silent-rules=0
+
	program-prefix:
+
	program-suffix:
+
	program-transform-name:
}

# @check-feature name { script }
@@ -206,7 +209,12 @@ proc include-file {infile mapping} {
				}
			}
			continue
-
		} elseif {[regexp {^@include\s+(.*)} $line -> filearg]} {
+
		}
+
		# Only continue if the stack contains all "true"
+
		if {"0" in $condstack} {
+
			continue
+
		}
+
		if {[regexp {^@include\s+(.*)} $line -> filearg]} {
			set incfile [string map $mapping $filearg]
			if {[file exists $incfile]} {
				lappend ::autosetup(deps) [file-normalize $incfile]
@@ -215,12 +223,9 @@ proc include-file {infile mapping} {
				user-error "$infile:$linenum: Include file $incfile is missing"
			}
			continue
-
		} elseif {[regexp {^@define\s+(\w+)\s+(.*)} $line -> var val]} {
-
			define $var $val
-
			continue
		}
-
		# Only output this line if the stack contains all "true"
-
		if {"0" in $condstack} {
+
		if {[regexp {^@define\s+(\w+)\s+(.*)} $line -> var val]} {
+
			define $var $val
			continue
		}
		lappend result $line
modified autosetup/tmake.auto
@@ -49,6 +49,24 @@ ifconfig !CONFIGURED {
}
}

+
	set configure [readfile configure]
+
	# XXX Do we need also need to support a system install of tmake?
+
	if {[string first {#@TMAKEUPDATED@} $configure] < 0} {
+
		if {[regsub {#@@INITCHECK@@#} $configure \
+
			{test -z "$TMAKE" -a -x "$dir/tmake" \&\& exec "$dir/tmake" --force --configure "$@"; #@TMAKEUPDATED@} configure]} {
+
			writefile configure $configure\n
+
			exec chmod +x configure
+
			puts "Updated configure to invoke local tmake."
+
			if {![file exec autosetup/tmake]} {
+
				puts "Warning: autosetup/tmake is missing."
+
				puts "   Install it with: tmake --install=autosetup"
+
			}
+
		} else {
+
			puts "Warning: configure isn't created by a recent autosetup, not updating."
+
		}
+
	} else {
+
		puts "I see configure for tmake already exists."
+
	}
	if {![file exists build.spec]} {
		puts "Note: I don't see build.spec. Try running: tmake --genie"
	}
modified configure
@@ -1,3 +1,4 @@
#!/bin/sh
dir="`dirname "$0"`/autosetup"
+
#@@INITCHECK@@#
WRAPPER="$0"; export WRAPPER; exec "`"$dir/autosetup-find-tclsh"`" "$dir/autosetup" "$@"