diff -Nru jimtcl-0.73/auto.def jimtcl-0.74/auto.def --- jimtcl-0.73/auto.def 2011-12-19 22:11:37.000000000 +0000 +++ jimtcl-0.74/auto.def 2013-07-24 05:36:47.000000000 +0000 @@ -2,7 +2,7 @@ # # Note: modules which support options *must* be included before 'options' -use cc cc-shared cc-db +use cc cc-shared cc-db cc-lib use local options { @@ -15,6 +15,7 @@ full => "Enable some optional features: ipv6, math, utf8, binary, oo, tree" with-jim-shared shared => "build a shared library instead of a static library" jim-regexp=1 => "prefer POSIX regex if over the the built-in (Tcl-compatible) regex" + docs=1 => "don't build or install the documentation" with-jim-ext: {with-ext:"ext1 ext2 ..."} => { Specify additional jim extensions to include. These are enabled by default: @@ -36,6 +37,7 @@ stdlib - Built-in commands including lassign, lambda, alias syslog - System logging with syslog tclcompat - Tcl compatible read, gets, puts, parray, case, ... + namespace - Tcl compatible namespace support These are disabled by default: @@ -80,7 +82,7 @@ } cc-check-functions ualarm lstat fork vfork system select execvpe -cc-check-functions backtrace geteuid mkstemp realpath strptime +cc-check-functions backtrace geteuid mkstemp realpath strptime isatty cc-check-functions regcomp waitpid sigaction sys_signame sys_siglist cc-check-functions syslog opendir readlink sleep usleep pipe getaddrinfo utimes if {[cc-check-functions sysinfo]} { @@ -89,6 +91,9 @@ } } +cc-check-lfs +cc-check-functions fseeko ftello + define TCL_LIBRARY [get-define prefix]/lib/jim lassign [split [get-define host] -] host_cpu host_vendor host_os @@ -167,7 +172,7 @@ define JIM_IPV6 } if {[opt-bool lineedit full]} { - if {([cc-check-includes termios.h] && [cc-check-functions isatty]) || [have-feature winconsole]} { + if {([cc-check-includes termios.h] && [have-feature isatty]) || [have-feature winconsole]} { msg-result "Enabling line editing" define USE_LINENOISE lappend extra_objs linenoise.o @@ -184,6 +189,7 @@ define JIM_STATICLIB } define JIM_INSTALL [opt-bool install-jim] +define JIM_DOCS [opt-bool docs] # Attributes of the extensions # tcl=Pure Tcl extension @@ -237,14 +243,14 @@ namespace { dep nshelper } posix { check {[have-feature waitpid]} } readdir { check {[have-feature opendir]} } - readline { check {[cc-check-function-in-lib readline readline]} } + readline { check {[cc-check-function-in-lib readline readline]} libdep lib_readline} rlprompt { dep readline } tree { dep oo } sdl { check {[cc-check-function-in-lib SDL_SetVideoMode SDL] && [cc-check-function-in-lib rectangleRGBA SDL_gfx]} libdep {lib_SDL_SetVideoMode lib_rectangleRGBA} } signal { check {[have-feature sigaction] && [have-feature vfork]} } - sqlite3 { check {[cc-check-function-in-lib sqlite3_open sqlite3]} libdep lib_sqlite3_open } + sqlite3 { check {[cc-check-function-in-lib sqlite3_prepare_v2 sqlite3]} libdep lib_sqlite3_prepare_v2 } syslog { check {[have-feature syslog]} } tree { dep oo } win32 { check {[have-feature windows]} } @@ -328,7 +334,7 @@ define EXTRA_OBJS $extra_objs make-config-header jim-config.h -auto {HAVE_LONG_LONG* JIM_UTF8} -none * -make-config-header jimautoconf.h -auto {jim_ext_* TCL_PLATFORM_* TCL_LIBRARY USE_* JIM_*} +make-config-header jimautoconf.h -auto {jim_ext_* TCL_PLATFORM_* TCL_LIBRARY USE_* JIM_* _FILE_OFFSET*} make-template Makefile.in make-template build-jim-ext.in diff -Nru jimtcl-0.73/autosetup/autosetup jimtcl-0.74/autosetup/autosetup --- jimtcl-0.73/autosetup/autosetup 2011-12-19 22:11:37.000000000 +0000 +++ jimtcl-0.74/autosetup/autosetup 2013-07-24 05:36:47.000000000 +0000 @@ -5,7 +5,7 @@ # \ dir=`dirname "$0"`; exec "`$dir/find-tclsh`" "$0" "$@" -set autosetup(version) 0.6.3 +set autosetup(version) 0.6.5 # Can be set to 1 to debug early-init problems set autosetup(debug) 0 @@ -87,7 +87,7 @@ reference:=text => "display the autosetup command reference. 'text', 'wiki', 'asciidoc' or 'markdown'" debug => "display debugging output as autosetup runs" install:=. => "install autosetup to the current or given directory (in the 'autosetup/' subdirectory)" - force init => "create an initial 'configure' script if none exists" + force init:=help => "create initial auto.def, etc. Use --init=help for known types" # Undocumented options option-checking=1 nopager @@ -119,6 +119,11 @@ use local } + # Now any auto-load modules + foreach file [glob -nocomplain $autosetup(libdir)/*.auto $autosetup(libdir)/*/*.auto] { + automf_load source $file + } + if {[opt-val help] ne ""} { incr autosetup(showhelp) use help @@ -130,9 +135,9 @@ autosetup_reference [opt-val {manual ref reference}] } - if {[opt-bool init]} { + if {[opt-val init] ne ""} { use init - autosetup_init + autosetup_init [opt-val init] } if {[opt-val install] ne ""} { @@ -143,7 +148,7 @@ if {![file exists $autosetup(autodef)]} { # Check for invalid option first options {} - user-error "No auto.def found in $autosetup(srcdir)" + user-error "No auto.def found in \"$autosetup(srcdir)\" (use [file tail $::autosetup(exe)] --init to create one)" } # Parse extra arguments into autosetup(cmdline) @@ -167,6 +172,7 @@ # Log how we were invoked configlog "Invoked as: [getenv WRAPPER $::argv0] [quote-argv $autosetup(argv)]" + # Note that auto.def is *not* loaded in the global scope source $autosetup(autodef) # Could warn here if options {} was not specified @@ -174,7 +180,11 @@ show-notices if {$autosetup(debug)} { - parray define + msg-result "Writing all defines to config.log" + configlog "================ defines ======================" + foreach n [lsort [array names define]] { + configlog "define $n $define($n)" + } } exit 0 @@ -421,6 +431,10 @@ proc config_guess {} { if {[file-isexec $::autosetup(dir)/config.guess]} { exec-with-stderr sh $::autosetup(dir)/config.guess + if {[catch {exec-with-stderr sh $::autosetup(dir)/config.guess} alias]} { + user-error $alias + } + return $alias } else { configlog "No config.guess, so using uname" string tolower [exec uname -p]-unknown-[exec uname -s][exec uname -r] @@ -429,10 +443,11 @@ proc config_sub {alias} { if {[file-isexec $::autosetup(dir)/config.sub]} { - exec-with-stderr sh $::autosetup(dir)/config.sub $alias - } else { - return $alias + if {[catch {exec-with-stderr sh $::autosetup(dir)/config.sub $alias} alias]} { + user-error $alias + } } + return $alias } # @define name ?value=1? @@ -754,8 +769,13 @@ # Incorrect usage in the auto.def file. Identify the location. proc autosetup-error {msg} { + autosetup-full-error [error-location $msg] +} + +# Like autosetup-error, except $msg is the full error message. +proc autosetup-full-error {msg} { show-notices - puts stderr [error-location $msg] + puts stderr $msg exit 1 } @@ -865,7 +885,14 @@ # @use module ... # # Load the given library modules. -# e.g. use cc cc-shared +# e.g. 'use cc cc-shared' +# +# Note that module 'X' is implemented in either 'autosetup/X.tcl' +# or 'autosetup/X/init.tcl' +# +# The latter form is useful for a complex module which requires additional +# support file. In this form, '$::usedir' is set to the module directory +# when it is loaded. # proc use {args} { foreach m $args { @@ -874,20 +901,36 @@ } set ::libmodule($m) 1 if {[info exists ::modsource($m)]} { - uplevel #0 eval $::modsource($m) + automf_load eval $::modsource($m) } else { - set source $::autosetup(libdir)/${m}.tcl - if {[file exists $source]} { - uplevel #0 [list source $source] + set sources [list $::autosetup(libdir)/${m}.tcl $::autosetup(libdir)/${m}/init.tcl] + set found 0 + foreach source $sources { + if {[file exists $source]} { + incr found + break + } + } + if {$found} { + # For the convenience of the "use" source, point to the directory + # it is being loaded from + set ::usedir [file dirname $source] + automf_load source $source autosetup_add_dep $source } else { - puts "Looking for $source" autosetup-error "use: No such module: $m" } } } } +# Load module source in the global scope by executing the given command +proc automf_load {args} { + if {[catch [list uplevel #0 $args] msg opts] ni {0 2 3}} { + autosetup-full-error [error-dump $msg $opts] + } +} + # Initial settings set autosetup(exe) $::argv0 set autosetup(istcl) 1 @@ -1146,9 +1189,9 @@ # If not already paged and stdout is a tty, pipe the output through the pager # This is done by reinvoking autosetup with --nopager added proc use_pager {} { - if {![opt-bool nopager] && [getenv PAGER ""] ne "" && ![string match "not a tty" [exec tty]]} { + if {![opt-bool nopager] && [getenv PAGER ""] ne "" && [isatty? stdin] && [isatty? stdout]} { catch { - exec [info nameofexecutable] $::argv0 --nopager {*}$::argv | [getenv PAGER] >@stdout <@stdin 2>/dev/null + exec [info nameofexecutable] $::argv0 --nopager {*}$::argv |& [getenv PAGER] >@stdout <@stdin } exit 0 } @@ -1278,55 +1321,56 @@ # Module to help create auto.def and configure -proc autosetup_init {} { - set create_configure 1 - if {[file exists configure]} { - if {!$::autosetup(force)} { - # Could this be an autosetup configure? - if {![string match "*\nWRAPPER=*" [readfile configure]]} { - puts "I see configure, but not created by autosetup, so I won't overwrite it." - puts "Use autosetup --init --force to overwrite." - set create_configure 0 - } - } else { - puts "I will overwrite the existing configure because you used --force." +proc autosetup_init {type} { + set help 0 + if {$type in {? help}} { + incr help + } elseif {![dict exists $::autosetup(inittypes) $type]} { + puts "Unknown type, --init=$type" + incr help + } + if {$help} { + puts "Use one of the following types (e.g. --init=make)\n" + foreach type [lsort [dict keys $::autosetup(inittypes)]] { + lassign [dict get $::autosetup(inittypes) $type] desc + # XXX: Use the options-show code to wrap the description + puts [format "%-10s %s" $type $desc] } - } else { - puts "I don't see configure, so I will create it." + exit 0 } - if {$create_configure} { - if {!$::autosetup(installed)} { - user-notice "Warning: Initialising from the development version of autosetup" + lassign [dict get $::autosetup(inittypes) $type] desc script - writefile configure "#!/bin/sh\nWRAPPER=\"\$0\" exec $::autosetup(dir)/autosetup \"\$@\"\n" - } else { - writefile configure \ -{#!/bin/sh -dir="`dirname "$0"`/autosetup" -WRAPPER="$0" exec "`$dir/find-tclsh`" "$dir/autosetup" "$@" -} - } - catch {exec chmod 755 configure} - } - if {![file exists auto.def]} { - puts "I don't see auto.def, so I will create a default one." - writefile auto.def {# Initial auto.def created by 'autosetup --init' + puts "Initialising $type: $desc\n" -use cc + # All initialisations happens in the top level srcdir + cd $::autosetup(srcdir) -# Add any user options here -options { + uplevel #0 $script + + exit 0 } -make-config-header config.h -make-template Makefile.in +proc autosetup_add_init_type {type desc script} { + dict set ::autosetup(inittypes) $type [list $desc $script] } - } - if {![file exists Makefile.in]} { - puts "Note: I don't see Makefile.in. You will probably need to create one." - } - exit 0 +# This is for in creating build-system init scripts +# +# If the file doesn't exist, create it containing $contents +# If the file does exist, only overwrite if --force is specified. +# +proc autosetup_check_create {filename contents} { + if {[file exists $filename]} { + if {!$::autosetup(force)} { + puts "I see $filename already exists." + return + } else { + puts "I will overwrite the existing $filename because you used --force." + } + } else { + puts "I don't see $filename, so I will create it." + } + writefile $filename $contents } } @@ -1345,7 +1389,7 @@ set f [open autosetup/autosetup w] - set publicmodules {} + set publicmodules $::autosetup(libdir)/default.auto # First the main script, but only up until "CUT HERE" set in [open $::autosetup(dir)/autosetup] @@ -1393,11 +1437,36 @@ user-error "Failed to install autosetup: $error" } puts "Installed [autosetup_version] to autosetup/" - catch {exec [info nameofexecutable] autosetup/autosetup --init >@stdout 2>@stderr} + + # Now create 'configure' if necessary + autosetup_create_configure exit 0 } +proc autosetup_create_configure {} { + if {[file exists configure]} { + if {!$::autosetup(force)} { + # Could this be an autosetup configure? + if {![string match "*\nWRAPPER=*" [readfile configure]]} { + puts "I see configure, but not created by autosetup, so I won't overwrite it." + puts "Remove it or use --force to overwrite." + return + } + } else { + puts "I will overwrite the existing configure because you used --force." + } + } else { + puts "I don't see configure, so I will create it." + } + writefile configure \ +{#!/bin/sh +dir="`dirname "$0"`/autosetup" +WRAPPER="$0"; export WRAPPER; exec "`$dir/find-tclsh`" "$dir/autosetup" "$@" +} + catch {exec chmod 755 configure} +} + # Append the contents of $file to filehandle $f proc autosetup_install_append {f file} { set in [open $file] @@ -1541,15 +1610,28 @@ } return -code error "environment variable \"$name\" does not exist" } -} elseif {$autosetup(iswin)} { - # On Windows, backslash convert all environment variables - # (Assume that Tcl does this for us) - proc getenv {name args} { - string map {\\ /} [env $name {*}$args] + proc isatty? {channel} { + dict exists [fconfigure $channel] -xchar } } else { - # Jim on unix is simple - alias getenv env + if {$autosetup(iswin)} { + # On Windows, backslash convert all environment variables + # (Assume that Tcl does this for us) + proc getenv {name args} { + string map {\\ /} [env $name {*}$args] + } + } else { + # Jim on unix is simple + alias getenv env + } + proc isatty? {channel} { + set tty 0 + catch { + # isatty is a recent addition to Jim Tcl + set tty [$channel isatty] + } + return $tty + } } # In case 'file normalize' doesn't exist @@ -1598,46 +1680,42 @@ return $msg } -# Similar to error-location, but called when user code generates an error -# In this case we want to show the stack trace in user code, but not in autosetup code -# (unless --debug is enabled) +# If everything is working properly, the only errors which occur +# should be generated in user code (e.g. auto.def). +# By default, we only want to show the error location in user code. +# We use [info frame] to achieve this, but it works differently on Tcl and Jim. +# +# This is designed to be called for incorrect usage in auto.def, via autosetup-error # proc error-stacktrace {msg} { - if {$::autosetup(istcl)} { - if {[regexp {file "([^ ]*)" line ([0-9]*)} $::errorInfo dummy file line]} { - return "[relative-path $file]:$line $msg\n$::errorInfo" - } - return $::errorInfo - } else { - # Prepend a live stacktrace to the error stacktrace, omitting the current level - set stacktrace [concat [info stacktrace] [lrange [stacktrace] 3 end]] - - if {!$::autosetup(debug)} { - # Omit any levels from autosetup or with no file - set newstacktrace {} - foreach {p f l} $stacktrace { - if {[string match "*autosetup" $f] || $f eq ""} { - #puts "Skipping $p $f:$l" - continue - } - lappend newstacktrace $p $f $l - } - set stacktrace $newstacktrace - } - - # Convert filenames to relative paths - set newstacktrace {} - foreach {p f l} $stacktrace { - lappend newstacktrace $p [relative-path $f] $l - } - lassign $newstacktrace p f l - if {$f ne ""} { - set prefix "$f:$l: " + if {$::autosetup(debug)} { + return -code error $msg + } + # Search back through the stack trace for the first error in a .def file + for {set i 1} {$i < [info level]} {incr i} { + if {$::autosetup(istcl)} { + array set info [info frame -$i] } else { - set prefix "" + lassign [info frame -$i] info(caller) info(file) info(line) } + if {[string match *.def $info(file)]} { + return "[relative-path $info(file)]:$info(line): Error: $msg" + } + #puts "Skipping $info(file):$info(line)" + } + return $msg +} - return "${prefix}Error: $msg\n[stackdump $newstacktrace]" +# Given the return from [catch {...} msg opts], returns an appropriate +# error message. A nice one for Jim and a less-nice one for Tcl. +# +# This is designed for developer errors, e.g. in module code +# +proc error-dump {msg opts} { + if {$::autosetup(istcl)} { + return "Error: [dict get $opts -errorinfo]" + } else { + return "Error: $msg\n[stackdump $opts(-errorinfo)]" } } } diff -Nru jimtcl-0.73/autosetup/cc-lib.tcl jimtcl-0.74/autosetup/cc-lib.tcl --- jimtcl-0.73/autosetup/cc-lib.tcl 2011-12-19 22:11:37.000000000 +0000 +++ jimtcl-0.74/autosetup/cc-lib.tcl 2013-07-24 05:36:47.000000000 +0000 @@ -75,3 +75,87 @@ } return $rc } + +# @cc-check-flags flag ?...? +# +# Checks whether the given C/C++ compiler flags can be used. Defines feature +# names prefixed with 'HAVE_CFLAG' and 'HAVE_CXXFLAG' respectively, and +# appends working flags to '-cflags' and 'CFLAGS' or 'CXXFLAGS'. +proc cc-check-flags {args} { + set result 1 + array set opts [cc-get-settings] + switch -exact -- $opts(-lang) { + c++ { + set lang C++ + set prefix CXXFLAG + } + c { + set lang C + set prefix CFLAG + } + default { + autosetup-error "cc-check-flags failed with unknown language: $opts(-lang)" + } + } + foreach flag $args { + msg-checking "Checking whether the $lang compiler accepts $flag..." + if {[cctest -cflags $flag]} { + msg-result yes + define-feature $prefix$flag + cc-with [list -cflags [list $flag]] + define-append ${prefix}S $flag + } else { + msg-result no + set result 0 + } + } + return $result +} + +# @cc-check-standards ver ?...? +# +# Checks whether the C/C++ compiler accepts one of the specified '-std=$ver' +# options, and appends the first working one to '-cflags' and 'CFLAGS' or +# 'CXXFLAGS'. +proc cc-check-standards {args} { + array set opts [cc-get-settings] + foreach std $args { + if {[cc-check-flags -std=$std]} { + return $std + } + } + return "" +} + +# Checks whether $keyword is usable as alignof +proc cctest_alignof {keyword} { + msg-checking "Checking for $keyword..." + if {[cctest -code [subst -nobackslashes { + printf("minimum alignment is %d == %d\n", ${keyword}(char), ${keyword}('x')); + }]]} then { + msg-result ok + define-feature $keyword + } else { + msg-result "not found" + } +} + +# @cc-check-c11 +# +# Checks for several C11/C++11 extensions and their alternatives. Currently +# checks for '_Static_assert', '_Alignof', '__alignof__', '__alignof'. +proc cc-check-c11 {} { + msg-checking "Checking for _Static_assert..." + if {[cctest -code { + _Static_assert(1, "static assertions are available"); + }]} then { + msg-result ok + define-feature _Static_assert + } else { + msg-result "not found" + } + + cctest_alignof _Alignof + cctest_alignof __alignof__ + cctest_alignof __alignof +} diff -Nru jimtcl-0.73/autosetup/cc-shared.tcl jimtcl-0.74/autosetup/cc-shared.tcl --- jimtcl-0.73/autosetup/cc-shared.tcl 2011-12-19 22:11:37.000000000 +0000 +++ jimtcl-0.74/autosetup/cc-shared.tcl 2013-07-24 05:36:47.000000000 +0000 @@ -7,70 +7,95 @@ # It defines the following variables: # ## SH_CFLAGS Flags to use compiling sources destined for a shared library -## SH_LDFLAGS Flags to use linking a shared library +## SH_LDFLAGS Flags to use linking (creating) a shared library +## SH_SOPREFIX Prefix to use to set the soname when creating a shared library +## SH_SOEXT Extension for shared libs +## SH_SOEXTVER Format for versioned shared libs - %s = version ## SHOBJ_CFLAGS Flags to use compiling sources destined for a shared object ## SHOBJ_LDFLAGS Flags to use linking a shared object, undefined symbols allowed ## SHOBJ_LDFLAGS_R - as above, but all symbols must be resolved ## SH_LINKFLAGS Flags to use linking an executable which will load shared objects ## LD_LIBRARY_PATH Environment variable which specifies path to shared libraries +## STRIPLIBFLAGS Arguments to strip to strip a dynamic library module-options {} -foreach i {SH_LINKFLAGS SH_CFLAGS SH_LDFLAGS SHOBJ_CFLAGS SHOBJ_LDFLAGS} { - define $i "" -} - +# Defaults: gcc on unix +define SHOBJ_CFLAGS -fpic +define SHOBJ_LDFLAGS -shared +define SH_CFLAGS -fpic +define SH_LDFLAGS -shared +define SH_LINKFLAGS -rdynamic +define SH_SOEXT .so +define SH_SOEXTVER .so.%s +define SH_SOPREFIX -Wl,-soname, define LD_LIBRARY_PATH LD_LIBRARY_PATH +define STRIPLIBFLAGS --strip-unneeded + +# Note: This is a helpful reference for identifying the toolchain +# http://sourceforge.net/apps/mediawiki/predef/index.php?title=Compilers switch -glob -- [get-define host] { *-*-darwin* { - define SH_CFLAGS -dynamic - define SH_LDFLAGS "-dynamiclib" define SHOBJ_CFLAGS "-dynamic -fno-common" define SHOBJ_LDFLAGS "-bundle -undefined dynamic_lookup" - define SHOBJ_LDFLAGS_R "-bundle" + define SHOBJ_LDFLAGS_R -bundle + define SH_CFLAGS -dynamic + define SH_LDFLAGS -dynamiclib + define SH_LINKFLAGS "" + define SH_SOEXT .dylib + define SH_SOEXTVER .%s.dylib + define SH_SOPREFIX -Wl,-install_name, define LD_LIBRARY_PATH DYLD_LIBRARY_PATH + define STRIPLIBFLAGS -x } - *-*-ming* { - define SH_LDFLAGS -shared + *-*-ming* - *-*-cygwin - *-*-msys { + define SHOBJ_CFLAGS "" define SHOBJ_LDFLAGS -shared - define SHOBJ_LDFLAGS_R -shared - } - *-*-cygwin { + define SH_CFLAGS "" define SH_LDFLAGS -shared - define SHOBJ_LDFLAGS -shared + define SH_LINKFLAGS "" + define SH_SOEXT .dll + define SH_SOEXTVER .dll + define SH_SOPREFIX "" + define LD_LIBRARY_PATH PATH + } + sparc* { + if {[msg-quiet cc-check-decls __SUNPRO_C]} { + msg-result "Found sun stdio compiler" + # sun stdio compiler + # XXX: These haven't been fully tested. + define SHOBJ_CFLAGS -KPIC + define SHOBJ_LDFLAGS "-G" + define SH_CFLAGS -KPIC + define SH_LINKFLAGS -Wl,-export-dynamic + define SH_SOPREFIX -Wl,-h, + } else { + # sparc has a very small GOT table limit, so use -fPIC + define SH_CFLAGS -fPIC + define SHOBJ_CFLAGS -fPIC + } } *-*-solaris* { - # XXX: These haven't been fully tested. - #define SH_LINKFLAGS -Wl,-export-dynamic - define SH_CFLAGS -Kpic - define SHOBJ_CFLAGS -Kpic - define SHOBJ_LDFLAGS "-G" + if {[msg-quiet cc-check-decls __SUNPRO_C]} { + msg-result "Found sun stdio compiler" + # sun stdio compiler + # XXX: These haven't been fully tested. + define SHOBJ_CFLAGS -KPIC + define SHOBJ_LDFLAGS "-G" + define SH_CFLAGS -KPIC + define SH_LINKFLAGS -Wl,-export-dynamic + define SH_SOPREFIX -Wl,-h, + } } *-*-hpux { # XXX: These haven't been tested - define SH_LINKFLAGS -Wl,+s - define SH_CFLAGS +z define SHOBJ_CFLAGS "+O3 +z" define SHOBJ_LDFLAGS -b + define SH_CFLAGS +z + define SH_LINKFLAGS -Wl,+s define LD_LIBRARY_PATH SHLIB_PATH } - sparc* { - # sparc has a very small GOT table limit, so use -fPIC - define SH_LINKFLAGS -rdynamic - define SH_CFLAGS -fPIC - define SH_LDFLAGS -shared - define SHOBJ_CFLAGS -fPIC - define SHOBJ_LDFLAGS -shared - } - * { - # Generic Unix settings - define SH_LINKFLAGS -rdynamic - define SH_CFLAGS -fpic - define SH_LDFLAGS -shared - define SHOBJ_CFLAGS -fpic - define SHOBJ_LDFLAGS -shared - } } if {![is-defined SHOBJ_LDFLAGS_R]} { diff -Nru jimtcl-0.73/autosetup/cc.tcl jimtcl-0.74/autosetup/cc.tcl --- jimtcl-0.73/autosetup/cc.tcl 2011-12-19 22:11:37.000000000 +0000 +++ jimtcl-0.74/autosetup/cc.tcl 2013-07-24 05:36:47.000000000 +0000 @@ -116,7 +116,7 @@ set with {} if {[dict exists $::autosetup(cc-include-deps) $each]} { set deps [dict keys [dict get $::autosetup(cc-include-deps) $each]] - msg-quiet cc-check-includes $deps + msg-quiet cc-check-includes {*}$deps foreach i $deps { if {[have-feature $i]} { lappend with $i @@ -133,12 +133,14 @@ } } -# @cc-include-needs include required +# @cc-include-needs include required ... # # Ensures that when checking for 'include', a check is first -# made for 'required', and if found, it is #included -proc cc-include-needs {file depfile} { - dict set ::autosetup(cc-include-deps) $file $depfile 1 +# made for each 'required' file, and if found, it is #included +proc cc-include-needs {file args} { + foreach depfile $args { + dict set ::autosetup(cc-include-deps) $file $depfile 1 + } } # @cc-check-types type ... @@ -256,6 +258,8 @@ # simply "ar" is assumed depending upon whether cross compiling. # The path is searched for this executable, and if found AR is defined # to the executable name. +# Note that even when cross compiling, the simple "ar" is used as a fallback, +# but a warning is generated. This is necessary for some toolchains. # # It is an error if the executable is not found. # @@ -263,10 +267,16 @@ foreach tool $args { set TOOL [string toupper $tool] set exe [get-env $TOOL [get-define cross]$tool] - if {![find-executable $exe]} { - user-error "Failed to find $exe" + if {[find-executable {*}$exe]} { + define $TOOL $exe + continue + } + if {[find-executable {*}$tool]} { + msg-result "Warning: Failed to find $exe, falling back to $tool which may be incorrect" + define $TOOL $tool + continue } - define $TOOL $exe + user-error "Failed to find $exe" } } @@ -491,14 +501,8 @@ set tmp conftest__.o lappend cmdline -c } - lappend cmdline {*}$opts(-cflags) + lappend cmdline {*}$opts(-cflags) {*}[get-define cc-default-debug ""] - switch -glob -- [get-define host] { - *-*-darwin* { - # Don't generate .dSYM directories - lappend cmdline -gstabs - } - } lappend cmdline $src -o $tmp {*}$opts(-libs) # At this point we have the complete command line and the @@ -589,7 +593,7 @@ continue } -str { - set value \"$value\" + set value \"[string map [list \\ \\\\ \" \\\"] $value]\" } -auto { # Automatically determine the type @@ -598,7 +602,7 @@ continue } if {![string is integer -strict $value]} { - set value \"$value\" + set value \"[string map [list \\ \\\\ \" \\\"] $value]\" } } "" { @@ -659,8 +663,6 @@ # CXXFLAGS default to CFLAGS if not specified define CXXFLAGS [get-env CXXFLAGS [get-define CFLAGS]] -cc-check-tools ld - # May need a CC_FOR_BUILD, so look for one define CC_FOR_BUILD [find-an-executable [get-env CC_FOR_BUILD ""] cc gcc false] @@ -680,6 +682,16 @@ } msg-result "Build C compiler...[get-define CC_FOR_BUILD]" +# On Darwin, we prefer to use -gstabs to avoid creating .dSYM directories +# but some compilers don't support -gstabs, so test for it here. +switch -glob -- [get-define host] { + *-*-darwin* { + if {[cctest -cflags {-gstabs}]} { + define cc-default-debug -gstabs + } + } +} + if {![cc-check-includes stdlib.h]} { user-error "Compiler does not work. See config.log" } diff -Nru jimtcl-0.73/autosetup/config.guess jimtcl-0.74/autosetup/config.guess --- jimtcl-0.73/autosetup/config.guess 2011-12-19 22:11:37.000000000 +0000 +++ jimtcl-0.74/autosetup/config.guess 2013-07-24 05:36:47.000000000 +0000 @@ -804,6 +804,9 @@ *:MINGW*:*) echo ${UNAME_MACHINE}-pc-mingw32 exit ;; + i*:MSYS*:*) + echo ${UNAME_MACHINE}-pc-msys + exit ;; i*:windows32*:*) # uname -m includes "-pc" on this system. echo ${UNAME_MACHINE}-mingw32 diff -Nru jimtcl-0.73/autosetup/config.sub jimtcl-0.74/autosetup/config.sub --- jimtcl-0.73/autosetup/config.sub 2011-12-19 22:11:37.000000000 +0000 +++ jimtcl-0.74/autosetup/config.sub 2013-07-24 05:36:47.000000000 +0000 @@ -798,6 +798,10 @@ basic_machine=i370-ibm os=-mvs ;; + msys) + basic_machine=i386-pc + os=-msys + ;; ncr3000) basic_machine=i486-ncr os=-sysv4 @@ -1315,7 +1319,7 @@ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ | -chorusos* | -chorusrdb* | -cegcc* \ - | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ + | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ | -mingw32* | -linux-gnu* | -linux-android* \ | -linux-newlib* | -linux-uclibc* \ | -uxpv* | -beos* | -mpeix* | -udk* \ diff -Nru jimtcl-0.73/autosetup/default.auto jimtcl-0.74/autosetup/default.auto --- jimtcl-0.73/autosetup/default.auto 1970-01-01 00:00:00.000000000 +0000 +++ jimtcl-0.74/autosetup/default.auto 2013-07-24 05:36:47.000000000 +0000 @@ -0,0 +1,25 @@ +# Copyright (c) 2012 WorkWare Systems http://www.workware.net.au/ +# All rights reserved + +# Auto-load module for 'make' build system integration + +use init + +autosetup_add_init_type make {Simple "make" build system} { + autosetup_check_create auto.def \ +{# Initial auto.def created by 'autosetup --init=make' + +use cc + +# Add any user options here +options { +} + +make-config-header config.h +make-template Makefile.in +} + + if {![file exists Makefile.in]} { + puts "Note: I don't see Makefile.in. You will probably need to create one." + } +} diff -Nru jimtcl-0.73/autosetup/find-tclsh jimtcl-0.74/autosetup/find-tclsh --- jimtcl-0.73/autosetup/find-tclsh 2011-12-19 22:11:37.000000000 +0000 +++ jimtcl-0.74/autosetup/find-tclsh 2013-07-24 05:36:47.000000000 +0000 @@ -3,7 +3,7 @@ # If not found, builds a bootstrap jimsh from source d=`dirname "$0"` { "$d/jimsh0" "$d/test-tclsh"; } 2>/dev/null && exit 0 -PATH="$PATH:$d" +PATH="$PATH:$d"; export PATH for tclsh in jimsh tclsh tclsh8.5 tclsh8.6; do { $tclsh "$d/test-tclsh"; } 2>/dev/null && exit 0 done diff -Nru jimtcl-0.73/autosetup/jimsh0.c jimtcl-0.74/autosetup/jimsh0.c --- jimtcl-0.73/autosetup/jimsh0.c 2011-12-19 22:11:37.000000000 +0000 +++ jimtcl-0.74/autosetup/jimsh0.c 2013-07-24 05:36:47.000000000 +0000 @@ -39,6 +39,7 @@ #define TCL_PLATFORM_PATH_SEPARATOR ":" #define HAVE_VFORK #define HAVE_WAITPID +#define HAVE_ISATTY #define HAVE_SYS_TIME_H #define HAVE_DIRENT_H #define HAVE_UNISTD_H @@ -57,6 +58,9 @@ void *dlsym(void *handle, const char *symbol); char *dlerror(void); + +#define JIM_SPRINTF_DOUBLE_NEEDS_FIX + #ifdef _MSC_VER @@ -111,7 +115,10 @@ #ifndef UTF8_UTIL_H #define UTF8_UTIL_H -int utf8_fromunicode(char *p, unsigned short uc); + +#define MAX_UTF8_LEN 4 + +int utf8_fromunicode(char *p, unsigned uc); #ifndef JIM_UTF8 #include @@ -120,6 +127,7 @@ #define utf8_strlen(S, B) ((B) < 0 ? strlen(S) : (B)) #define utf8_tounicode(S, CP) (*(CP) = (unsigned char)*(S), 1) #define utf8_upper(C) toupper(C) +#define utf8_title(C) toupper(C) #define utf8_lower(C) tolower(C) #define utf8_index(C, I) (I) #define utf8_charlen(C) 1 @@ -179,7 +187,7 @@ #define UCHAR(c) ((unsigned char)(c)) -#define JIM_VERSION 73 +#define JIM_VERSION 74 #define JIM_OK 0 #define JIM_ERR 1 @@ -191,12 +199,17 @@ #define JIM_EVAL 7 -#define JIM_MAX_NESTING_DEPTH 1000 +#define JIM_MAX_CALLFRAME_DEPTH 1000 +#define JIM_MAX_EVAL_DEPTH 2000 #define JIM_NONE 0 #define JIM_ERRMSG 1 #define JIM_UNSHARED 4 +#define JIM_MUSTEXIST 8 + + +#define JIM_GLOBAL_ONLY 0x100 #define JIM_SUBST_NOVAR 1 @@ -236,7 +249,7 @@ typedef struct Jim_HashEntry { - const void *key; + void *key; union { void *val; int intval; @@ -246,10 +259,10 @@ typedef struct Jim_HashTableType { unsigned int (*hashFunction)(const void *key); - const void *(*keyDup)(void *privdata, const void *key); + void *(*keyDup)(void *privdata, const void *key); void *(*valDup)(void *privdata, const void *obj); int (*keyCompare)(void *privdata, const void *key1, const void *key2); - void (*keyDestructor)(void *privdata, const void *key); + void (*keyDestructor)(void *privdata, void *key); void (*valDestructor)(void *privdata, void *obj); } Jim_HashTableType; @@ -292,7 +305,7 @@ if ((ht)->type->keyDup) \ entry->key = (ht)->type->keyDup((ht)->privdata, _key_); \ else \ - entry->key = (_key_); \ + entry->key = (void *)(_key_); \ } while(0) #define Jim_CompareHashKeys(ht, key1, key2) \ @@ -310,20 +323,16 @@ typedef struct Jim_Obj { - int refCount; char *bytes; - int length; const struct Jim_ObjType *typePtr; + int refCount; + int length; union { jim_wide wideValue; - int hashValue; - - int indexValue; - - int returnCode; + int intValue; double doubleValue; @@ -335,12 +344,14 @@ } twoPtrValue; struct { - unsigned jim_wide callFrameId; + unsigned long callFrameId; struct Jim_Var *varPtr; + int global; } varValue; struct { - unsigned jim_wide procEpoch; + unsigned long procEpoch; + struct Jim_Obj *nsObj; struct Jim_Cmd *cmdPtr; } cmdValue; @@ -356,7 +367,7 @@ } strValue; struct { - jim_wide id; + unsigned long id; struct Jim_Reference *refPtr; } refValue; @@ -371,11 +382,6 @@ } dictSubstValue; struct { - unsigned char *data; - size_t len; - } binaryValue; - - struct { unsigned flags; void *compre; } regexpValue; @@ -436,18 +442,20 @@ typedef struct Jim_CallFrame { - unsigned jim_wide id; + unsigned long id; int level; struct Jim_HashTable vars; struct Jim_HashTable *staticVars; - struct Jim_CallFrame *parentCallFrame; + struct Jim_CallFrame *parent; Jim_Obj *const *argv; int argc; Jim_Obj *procArgsObjPtr; Jim_Obj *procBodyObjPtr; - struct Jim_CallFrame *nextFramePtr; + struct Jim_CallFrame *next; + Jim_Obj *nsObj; Jim_Obj *fileNameObj; int line; + Jim_Stack *localCommands; } Jim_CallFrame; typedef struct Jim_Var { @@ -465,6 +473,7 @@ typedef struct Jim_Cmd { int inUse; int isproc; + struct Jim_Cmd *prevCmd; union { struct { @@ -477,7 +486,6 @@ Jim_Obj *argListObjPtr; Jim_Obj *bodyObjPtr; Jim_HashTable *staticVars; - struct Jim_Cmd *prevCmd; int argListLen; int reqArity; int optArity; @@ -487,6 +495,7 @@ Jim_Obj *nameObjPtr; Jim_Obj *defaultObjPtr; } *arglist; + Jim_Obj *nsObj; } proc; } u; } Jim_Cmd; @@ -502,7 +511,9 @@ int errorLine; Jim_Obj *errorFileNameObj; int addStackTrace; - int maxNestingDepth; + int maxCallFrameDepth; + int maxEvalDepth; + int evalDepth; int returnCode; int returnLevel; int exitCode; @@ -513,10 +524,10 @@ Jim_CallFrame *framePtr; Jim_CallFrame *topFramePtr; struct Jim_HashTable commands; - unsigned jim_wide procEpoch; /* Incremented every time the result + unsigned long procEpoch; /* Incremented every time the result of procedures names lookup caching may no longer be valid. */ - unsigned jim_wide callFrameEpoch; /* Incremented every time a new + unsigned long callFrameEpoch; /* Incremented every time a new callframe is created. This id is used for the 'ID' field contained in the Jim_CallFrame structure. */ @@ -524,12 +535,13 @@ Jim_Obj *liveList; Jim_Obj *freeList; Jim_Obj *currentScriptObj; + Jim_Obj *nullScriptObj; Jim_Obj *emptyObj; Jim_Obj *trueObj; Jim_Obj *falseObj; - unsigned jim_wide referenceNextId; + unsigned long referenceNextId; struct Jim_HashTable references; - jim_wide lastCollectId; /* reference max Id of the last GC + unsigned long lastCollectId; /* reference max Id of the last GC execution. It's set to -1 while the collection is running as sentinel to avoid to recursive calls via the [collect] command inside @@ -548,7 +560,6 @@ struct Jim_HashTable assocData; Jim_PrngState *prngState; struct Jim_HashTable packages; - Jim_Stack *localProcs; Jim_Stack *loadHandles; } Jim_Interp; @@ -560,7 +571,6 @@ #define Jim_SetEmptyResult(i) Jim_SetResult(i, (i)->emptyObj) #define Jim_GetResult(i) ((i)->result) #define Jim_CmdPrivData(i) ((i)->cmdPrivData) -#define Jim_String(o) Jim_GetString((o), NULL) #define Jim_SetResult(i,o) do { \ Jim_Obj *_resultObjPtr_ = (o); \ @@ -616,9 +626,11 @@ JIM_EXPORT int Jim_EvalObj (Jim_Interp *interp, Jim_Obj *scriptObjPtr); JIM_EXPORT int Jim_EvalObjVector (Jim_Interp *interp, int objc, Jim_Obj *const *objv); +JIM_EXPORT int Jim_EvalObjList(Jim_Interp *interp, Jim_Obj *listObj); JIM_EXPORT int Jim_EvalObjPrefix(Jim_Interp *interp, Jim_Obj *prefix, int objc, Jim_Obj *const *objv); #define Jim_EvalPrefix(i, p, oc, ov) Jim_EvalObjPrefix((i), Jim_NewStringObj((i), (p), -1), (oc), (ov)) +JIM_EXPORT int Jim_EvalNamespace(Jim_Interp *interp, Jim_Obj *scriptObj, Jim_Obj *nsObj); JIM_EXPORT int Jim_SubstObj (Jim_Interp *interp, Jim_Obj *substObjPtr, Jim_Obj **resObjPtrPtr, int flags); @@ -634,7 +646,7 @@ JIM_EXPORT int Jim_InitHashTable (Jim_HashTable *ht, const Jim_HashTableType *type, void *privdata); -JIM_EXPORT int Jim_ExpandHashTable (Jim_HashTable *ht, +JIM_EXPORT void Jim_ExpandHashTable (Jim_HashTable *ht, unsigned int size); JIM_EXPORT int Jim_AddHashEntry (Jim_HashTable *ht, const void *key, void *val); @@ -645,7 +657,7 @@ JIM_EXPORT int Jim_FreeHashTable (Jim_HashTable *ht); JIM_EXPORT Jim_HashEntry * Jim_FindHashEntry (Jim_HashTable *ht, const void *key); -JIM_EXPORT int Jim_ResizeHashTable (Jim_HashTable *ht); +JIM_EXPORT void Jim_ResizeHashTable (Jim_HashTable *ht); JIM_EXPORT Jim_HashTableIterator *Jim_GetHashTableIterator (Jim_HashTable *ht); JIM_EXPORT Jim_HashEntry * Jim_NextHashEntry @@ -655,12 +667,11 @@ JIM_EXPORT Jim_Obj * Jim_NewObj (Jim_Interp *interp); JIM_EXPORT void Jim_FreeObj (Jim_Interp *interp, Jim_Obj *objPtr); JIM_EXPORT void Jim_InvalidateStringRep (Jim_Obj *objPtr); -JIM_EXPORT void Jim_InitStringRep (Jim_Obj *objPtr, const char *bytes, - int length); JIM_EXPORT Jim_Obj * Jim_DuplicateObj (Jim_Interp *interp, Jim_Obj *objPtr); JIM_EXPORT const char * Jim_GetString(Jim_Obj *objPtr, int *lenPtr); +JIM_EXPORT const char *Jim_String(Jim_Obj *objPtr); JIM_EXPORT int Jim_Length(Jim_Obj *objPtr); @@ -690,6 +701,8 @@ 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); @@ -729,6 +742,9 @@ JIM_EXPORT int Jim_SetVariableLink (Jim_Interp *interp, Jim_Obj *nameObjPtr, Jim_Obj *targetNameObjPtr, Jim_CallFrame *targetCallFrame); +JIM_EXPORT int Jim_CreateNamespaceVariable(Jim_Interp *interp, + Jim_Obj *varNameObj, Jim_Obj *targetNameObj); +JIM_EXPORT int Jim_DiscardNamespaceVars(Jim_Interp *interp); JIM_EXPORT Jim_Obj * Jim_GetVariable (Jim_Interp *interp, Jim_Obj *nameObjPtr, int flags); JIM_EXPORT Jim_Obj * Jim_GetGlobalVariable (Jim_Interp *interp, @@ -764,11 +780,14 @@ JIM_EXPORT int Jim_ListLength (Jim_Interp *interp, Jim_Obj *objPtr); JIM_EXPORT int Jim_ListIndex (Jim_Interp *interp, Jim_Obj *listPrt, int listindex, Jim_Obj **objPtrPtr, int seterr); +JIM_EXPORT Jim_Obj *Jim_ListGetIndex(Jim_Interp *interp, Jim_Obj *listPtr, int idx); JIM_EXPORT int Jim_SetListIndex (Jim_Interp *interp, Jim_Obj *varNamePtr, Jim_Obj *const *indexv, int indexc, Jim_Obj *newObjPtr); JIM_EXPORT Jim_Obj * Jim_ConcatObj (Jim_Interp *interp, int objc, Jim_Obj *const *objv); +JIM_EXPORT Jim_Obj *Jim_ListJoin(Jim_Interp *interp, + Jim_Obj *listObjPtr, const char *joinStr, int joinStrLen); JIM_EXPORT Jim_Obj * Jim_NewDictObj (Jim_Interp *interp, @@ -786,6 +805,7 @@ JIM_EXPORT int Jim_DictAddElement(Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj *keyObjPtr, Jim_Obj *valueObjPtr); JIM_EXPORT int Jim_DictKeys(Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj *patternObj); +JIM_EXPORT int Jim_DictValues(Jim_Interp *interp, Jim_Obj *dictObjPtr, Jim_Obj *patternObjPtr); JIM_EXPORT int Jim_DictSize(Jim_Interp *interp, Jim_Obj *objPtr); @@ -848,10 +868,17 @@ JIM_EXPORT int Jim_InteractivePrompt (Jim_Interp *interp); +JIM_EXPORT void Jim_HistoryLoad(const char *filename); +JIM_EXPORT void Jim_HistorySave(const char *filename); +JIM_EXPORT char *Jim_HistoryGetline(const char *prompt); +JIM_EXPORT void Jim_HistoryAdd(const char *line); +JIM_EXPORT void Jim_HistoryShow(void); JIM_EXPORT int Jim_InitStaticExtensions(Jim_Interp *interp); JIM_EXPORT int Jim_StringToWide(const char *str, jim_wide *widePtr, int base); +JIM_EXPORT int Jim_CheckSignal(Jim_Interp *interp); +#define Jim_CheckSignal(i) ((i)->signal_level && (i)->sigmask) JIM_EXPORT int Jim_LoadLibrary(Jim_Interp *interp, const char *pathName); @@ -1056,124 +1083,180 @@ "\n" "\n" "\n" +"\n" "package require readdir\n" "\n" "\n" +"proc glob.globdir {dir pattern} {\n" +" set result {}\n" +" set files [readdir $dir]\n" +" lappend files . ..\n" "\n" +" foreach name $files {\n" +" if {[string match $pattern $name]} {\n" "\n" +" if {[string index $name 0] eq \".\" && [string index $pattern 0] ne \".\"} {\n" +" continue\n" +" }\n" +" lappend result $name\n" +" }\n" +" }\n" "\n" +" return $result\n" +"}\n" "\n" "\n" "\n" "\n" +"proc glob.explode {pattern} {\n" +" set oldexp {}\n" +" set newexp {\"\"}\n" +"\n" +" while 1 {\n" +" set oldexp $newexp\n" +" set newexp {}\n" +" set ob [string first \\{ $pattern]\n" +" set cb [string first \\} $pattern]\n" +"\n" +" if {$ob < $cb && $ob != -1} {\n" +" set mid [string range $pattern 0 $ob-1]\n" +" set subexp [lassign [glob.explode [string range $pattern $ob+1 end]] pattern]\n" +" if {$pattern eq \"\"} {\n" +" error \"unmatched open brace in glob pattern\"\n" +" }\n" +" set pattern [string range $pattern 1 end]\n" "\n" +" foreach subs $subexp {\n" +" foreach sub [split $subs ,] {\n" +" foreach old $oldexp {\n" +" lappend newexp $old$mid$sub\n" +" }\n" +" }\n" +" }\n" +" } elseif {$cb != -1} {\n" +" set suf [string range $pattern 0 $cb-1]\n" +" set rest [string range $pattern $cb end]\n" +" break\n" +" } else {\n" +" set suf $pattern\n" +" set rest \"\"\n" +" break\n" +" }\n" +" }\n" "\n" +" foreach old $oldexp {\n" +" lappend newexp $old$suf\n" +" }\n" +" linsert $newexp 0 $rest\n" +"}\n" "\n" -"proc glob {args} {\n" "\n" "\n" +"proc glob.glob {base pattern} {\n" +" set dir [file dirname $pattern]\n" +" if {$pattern eq $dir || $pattern eq \"\"} {\n" +" return [list [file join $base $dir] $pattern]\n" +" } elseif {$pattern eq [file tail $pattern]} {\n" +" set dir \"\"\n" +" }\n" "\n" "\n" -" local proc glob.readdir_pattern {dir pattern} {\n" -" set result {}\n" +" set dirlist [glob.glob $base $dir]\n" +" set pattern [file tail $pattern]\n" "\n" "\n" -" if {$pattern in {. ..}} {\n" -" return $pattern\n" +" set result {}\n" +" foreach {realdir dir} $dirlist {\n" +" if {![file isdir $realdir]} {\n" +" continue\n" " }\n" -"\n" -"\n" -" if {[string match {*[*?]*} $pattern]} {\n" -"\n" -" set files [readdir -nocomplain $dir]\n" -" } elseif {[file isdir $dir] && [file exists $dir/$pattern]} {\n" -" set files [list $pattern]\n" -" } else {\n" -" set files \"\"\n" +" if {[string index $dir end] ne \"/\" && $dir ne \"\"} {\n" +" append dir /\n" " }\n" -"\n" -" foreach name $files {\n" -" if {[string match $pattern $name]} {\n" -"\n" -" if {[string index $name 0] eq \".\" && [string index $pattern 0] ne \".\"} {\n" -" continue\n" -" }\n" -" lappend result $name\n" -" }\n" +" foreach name [glob.globdir $realdir $pattern] {\n" +" lappend result [file join $realdir $name] $dir$name\n" " }\n" -"\n" -" return $result\n" " }\n" +" return $result\n" +"}\n" "\n" "\n" "\n" "\n" "\n" -" proc glob.expandbraces {pattern} {\n" "\n" "\n" -" if {[set fb [string first \"\\{\" $pattern]] < 0} {\n" -" return $pattern\n" -" }\n" -" if {[set nb [string first \"\\}\" $pattern $fb]] < 0} {\n" -" return $pattern\n" -" }\n" -" set before [string range $pattern 0 $fb-1]\n" -" set braced [string range $pattern $fb+1 $nb-1]\n" -" set after [string range $pattern $nb+1 end]\n" "\n" -" lmap part [split $braced ,] {\n" -" set pat $before$part$after\n" -" }\n" -" }\n" "\n" "\n" -" proc glob.glob {pattern} {\n" -" set dir [file dirname $pattern]\n" -" if {$dir eq $pattern} {\n" "\n" -" return [list $dir]\n" -" }\n" "\n" +"proc glob {args} {\n" +" set nocomplain 0\n" +" set base \"\"\n" "\n" -" set dirlist [glob.glob $dir]\n" -" set pattern [file tail $pattern]\n" +" set n 0\n" +" foreach arg $args {\n" +" if {[info exists param]} {\n" +" set $param $arg\n" +" unset param\n" +" incr n\n" +" continue\n" +" }\n" +" switch -glob -- $arg {\n" +" -d* {\n" +" set switch $arg\n" +" set param base\n" +" }\n" +" -n* {\n" +" set nocomplain 1\n" +" }\n" +" -t* {\n" "\n" +" }\n" "\n" -" set result {}\n" -" foreach dir $dirlist {\n" -" set globdir $dir\n" -" if {[string match \"*/\" $dir]} {\n" -" set sep \"\"\n" -" } elseif {$dir eq \".\"} {\n" -" set globdir \"\"\n" -" set sep \"\"\n" -" } else {\n" -" set sep /\n" +" -* {\n" +" return -code error \"bad option \\\"$switch\\\": must be -directory, -nocomplain, -tails, or --\"\n" " }\n" -" foreach pat [glob.expandbraces $pattern] {\n" -" foreach name [glob.readdir_pattern $dir $pat] {\n" -" lappend result $globdir$sep$name\n" -" }\n" +" -- {\n" +" incr n\n" +" break\n" +" }\n" +" * {\n" +" break\n" " }\n" " }\n" -" return $result\n" +" incr n\n" " }\n" -"\n" -"\n" -" set nocomplain 0\n" -"\n" -" if {[lindex $args 0] eq \"-nocomplain\"} {\n" -" set nocomplain 1\n" -" set args [lrange $args 1 end]\n" +" if {[info exists param]} {\n" +" return -code error \"missing argument to \\\"$switch\\\"\"\n" +" }\n" +" if {[llength $args] <= $n} {\n" +" return -code error \"wrong # args: should be \\\"glob ?options? pattern ?pattern ...?\\\"\"\n" " }\n" "\n" +" set args [lrange $args $n end]\n" +"\n" " set result {}\n" " foreach pattern $args {\n" -" lappend result {*}[glob.glob $pattern]\n" +" set pattern [string map {\n" +" \\\\\\\\ \\x01 \\\\\\{ \\x02 \\\\\\} \\x03 \\\\, \\x04\n" +" } $pattern]\n" +" set patexps [lassign [glob.explode $pattern] rest]\n" +" if {$rest ne \"\"} {\n" +" return -code error \"unmatched close brace in glob pattern\"\n" +" }\n" +" foreach patexp $patexps {\n" +" set patexp [string map {\n" +" \\x01 \\\\\\\\ \\x02 \\{ \\x03 \\} \\x04 ,\n" +" } $patexp]\n" +" foreach {realname name} [glob.glob $base $patexp] {\n" +" lappend result $name\n" +" }\n" +" }\n" " }\n" "\n" -" if {$nocomplain == 0 && [llength $result] == 0} {\n" +" if {!$nocomplain && [llength $result] == 0} {\n" " return -code error \"no files matched glob patterns\"\n" " }\n" "\n" @@ -1188,19 +1271,8 @@ return Jim_EvalSource(interp, "stdlib.tcl", 1, "\n" -"\n" -"\n" -"proc alias {name args} {\n" -" set prefix $args\n" -" proc $name args prefix {\n" -" tailcall {*}$prefix {*}$args\n" -" }\n" -"}\n" -"\n" -"\n" "proc lambda {arglist args} {\n" -" set name [ref {} function lambda.finalizer]\n" -" tailcall proc $name $arglist {*}$args\n" +" tailcall proc [ref {} function lambda.finalizer] $arglist {*}$args\n" "}\n" "\n" "proc lambda.finalizer {name val} {\n" @@ -1209,10 +1281,7 @@ "\n" "\n" "proc curry {args} {\n" -" set prefix $args\n" -" lambda args prefix {\n" -" tailcall {*}$prefix {*}$args\n" -" }\n" +" alias [ref {} function lambda.finalizer] {*}$args\n" "}\n" "\n" "\n" @@ -1228,14 +1297,6 @@ "}\n" "\n" "\n" -"proc lassign {list args} {\n" -"\n" -" lappend list {}\n" -" uplevel 1 [list foreach $args $list break]\n" -" lrange $list [llength $args] end-1\n" -"}\n" -"\n" -"\n" "\n" "\n" "proc stacktrace {} {\n" @@ -1387,7 +1448,7 @@ " foreach {n v} $args {\n" " switch -glob -- $n {\n" " -bl* {\n" -" $f ndelay $v\n" +" $f ndelay $(!$v)\n" " }\n" " -bu* {\n" " $f buffering $v\n" @@ -1628,6 +1689,7 @@ } + #include #include #include @@ -1651,6 +1713,13 @@ #define AIO_CMD_LEN 32 #define AIO_BUF_LEN 256 +#ifndef HAVE_FTELLO + #define ftello ftell +#endif +#ifndef HAVE_FSEEKO + #define fseeko fseek +#endif + #define AIO_KEEPOPEN 1 #if defined(JIM_IPV6) @@ -1721,13 +1790,37 @@ Jim_Free(af); } +static int JimCheckStreamError(Jim_Interp *interp, AioFile *af) +{ + if (!ferror(af->fp)) { + return JIM_OK; + } + clearerr(af->fp); + + if (feof(af->fp) || errno == EAGAIN || errno == EINTR) { + return JIM_OK; + } +#ifdef ECONNRESET + if (errno == ECONNRESET) { + return JIM_OK; + } +#endif +#ifdef ECONNABORTED + if (errno != ECONNABORTED) { + return JIM_OK; + } +#endif + JimAioSetError(interp, af->filename); + return JIM_ERR; +} + static int aio_cmd_read(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { AioFile *af = Jim_CmdPrivData(interp); char buf[AIO_BUF_LEN]; Jim_Obj *objPtr; int nonewline = 0; - int neededLen = -1; + jim_wide neededLen = -1; if (argc && Jim_CompareStringImmediate(interp, argv[0], "-nonewline")) { nonewline = 1; @@ -1735,15 +1828,12 @@ argc--; } if (argc == 1) { - jim_wide wideValue; - - if (Jim_GetWide(interp, argv[0], &wideValue) != JIM_OK) + if (Jim_GetWide(interp, argv[0], &neededLen) != JIM_OK) return JIM_ERR; - if (wideValue < 0) { + if (neededLen < 0) { Jim_SetResultString(interp, "invalid parameter: negative len", -1); return JIM_ERR; } - neededLen = (int)wideValue; } else if (argc) { return -1; @@ -1770,15 +1860,9 @@ break; } - if (ferror(af->fp)) { - clearerr(af->fp); - - if (!feof(af->fp) && errno != EAGAIN) { - - Jim_FreeNewObj(interp, objPtr); - JimAioSetError(interp, af->filename); - return JIM_ERR; - } + if (JimCheckStreamError(interp, af)) { + Jim_FreeNewObj(interp, objPtr); + return JIM_ERR; } if (nonewline) { int len; @@ -1796,8 +1880,8 @@ static int aio_cmd_copy(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { AioFile *af = Jim_CmdPrivData(interp); - long count = 0; - long maxlen = LONG_MAX; + jim_wide count = 0; + jim_wide maxlen = JIM_WIDE_MAX; FILE *outfh = Jim_AioFilehandle(interp, argv[0]); if (outfh == NULL) { @@ -1805,7 +1889,7 @@ } if (argc == 2) { - if (Jim_GetLong(interp, argv[1], &maxlen) != JIM_OK) { + if (Jim_GetWide(interp, argv[1], &maxlen) != JIM_OK) { return JIM_ERR; } } @@ -1866,11 +1950,9 @@ break; } } - if (ferror(af->fp) && errno != EAGAIN && errno != EINTR) { + if (JimCheckStreamError(interp, af)) { Jim_FreeNewObj(interp, objPtr); - JimAioSetError(interp, af->filename); - clearerr(af->fp); return JIM_ERR; } @@ -1921,6 +2003,18 @@ return JIM_ERR; } +static int aio_cmd_isatty(Jim_Interp *interp, int argc, Jim_Obj *const *argv) +{ +#ifdef HAVE_ISATTY + AioFile *af = Jim_CmdPrivData(interp); + Jim_SetResultInt(interp, isatty(fileno(af->fp))); +#else + Jim_SetResultInt(interp, 0); +#endif + + return JIM_OK; +} + static int aio_cmd_flush(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { @@ -1951,7 +2045,7 @@ { AioFile *af = Jim_CmdPrivData(interp); int orig = SEEK_SET; - long offset; + jim_wide offset; if (argc == 2) { if (Jim_CompareStringImmediate(interp, argv[1], "start")) @@ -1964,10 +2058,10 @@ return -1; } } - if (Jim_GetLong(interp, argv[0], &offset) != JIM_OK) { + if (Jim_GetWide(interp, argv[0], &offset) != JIM_OK) { return JIM_ERR; } - if (fseek(af->fp, offset, orig) == -1) { + if (fseeko(af->fp, offset, orig) == -1) { JimAioSetError(interp, af->filename); return JIM_ERR; } @@ -1978,7 +2072,7 @@ { AioFile *af = Jim_CmdPrivData(interp); - Jim_SetResultInt(interp, ftell(af->fp)); + Jim_SetResultInt(interp, ftello(af->fp)); return JIM_OK; } @@ -2154,6 +2248,13 @@ 2, }, + { "isatty", + NULL, + aio_cmd_isatty, + 0, + 0, + + }, { "flush", NULL, aio_cmd_flush, @@ -2300,9 +2401,11 @@ if (fh == NULL) { JimAioSetError(interp, filename); +#if !defined(JIM_ANSIC) if (fd >= 0) { close(fd); } +#endif Jim_DecrRefCount(interp, filename); return JIM_ERR; } @@ -3007,7 +3110,7 @@ static int StoreStatData(Jim_Interp *interp, Jim_Obj *varName, const struct stat *sb) { if (set_array_int_value(interp, varName, "dev", sb->st_dev) != JIM_OK) { - Jim_SetResultFormatted(interp, "can't set \"%#s(dev)\": variables isn't array", varName); + Jim_SetResultFormatted(interp, "can't set \"%#s(dev)\": variable isn't array", varName); return JIM_ERR; } set_array_int_value(interp, varName, "ino", sb->st_ino); @@ -3032,7 +3135,9 @@ const char *path = Jim_String(argv[0]); const char *p = strrchr(path, '/'); - if (!p) { + if (!p && path[0] == '.' && path[1] == '.' && path[2] == '\0') { + Jim_SetResultString(interp, "..", -1); + } else if (!p) { Jim_SetResultString(interp, ".", -1); } else if (p == path) { @@ -3100,12 +3205,13 @@ if (realpath(path, newname)) { Jim_SetResult(interp, Jim_NewStringObjNoAlloc(interp, newname, -1)); + return JIM_OK; } else { Jim_Free(newname); - Jim_SetResult(interp, argv[0]); + Jim_SetResultFormatted(interp, "can't normalize \"%#s\": %s", argv[0], strerror(errno)); + return JIM_ERR; } - return JIM_OK; #else Jim_SetResultString(interp, "Not implemented", -1); return JIM_ERR; @@ -3253,14 +3359,16 @@ while (ok--) { - char *slash = strrchr(path, '/'); + { + char *slash = strrchr(path, '/'); - if (slash && slash != path) { - *slash = 0; - if (mkdir_all(path) != 0) { - return -1; + if (slash && slash != path) { + *slash = 0; + if (mkdir_all(path) != 0) { + return -1; + } + *slash = '/'; } - *slash = '/'; } first: if (MKDIR_DEFAULT(path) == 0) { @@ -3886,6 +3994,10 @@ #define JimDupFd dup #define JimFdOpenForRead(FD) fdopen((FD), "r") #define JimOpenForRead(NAME) open((NAME), O_RDONLY, 0) + + #ifndef HAVE_EXECVPE + #define execvpe(ARG0, ARGV, ENV) execvp(ARG0, ARGV) + #endif #endif static const char *JimStrError(void); @@ -3974,8 +4086,7 @@ if (num % 2) { num--; } - size = Jim_Length(objPtr); - size++; + size = Jim_Length(objPtr) + 2; envptr = Jim_Alloc(sizeof(*envptr) * (num / 2 + 1) + size); envdata = (char *)&envptr[num / 2 + 1]; @@ -4212,6 +4323,19 @@ } } +static FILE *JimGetAioFilehandle(Jim_Interp *interp, const char *name) +{ + FILE *fh; + Jim_Obj *fhObj; + + fhObj = Jim_NewStringObj(interp, name, -1); + Jim_IncrRefCount(fhObj); + fh = Jim_AioFilehandle(interp, fhObj); + Jim_DecrRefCount(interp, fhObj); + + return fh; +} + static int JimCreatePipeline(Jim_Interp *interp, int argc, Jim_Obj *const *argv, pidtype **pidArrayPtr, fdtype *inPipePtr, fdtype *outPipePtr, fdtype *errFilePtr) @@ -4383,10 +4507,8 @@ } else if (inputFile == FILE_HANDLE) { - Jim_Obj *fhObj = Jim_NewStringObj(interp, input, -1); - FILE *fh = Jim_AioFilehandle(interp, fhObj); + FILE *fh = JimGetAioFilehandle(interp, input); - Jim_FreeNewObj(interp, fhObj); if (fh == NULL) { goto error; } @@ -4412,10 +4534,7 @@ if (output != NULL) { if (outputFile == FILE_HANDLE) { - Jim_Obj *fhObj = Jim_NewStringObj(interp, output, -1); - FILE *fh = Jim_AioFilehandle(interp, fhObj); - - Jim_FreeNewObj(interp, fhObj); + FILE *fh = JimGetAioFilehandle(interp, output); if (fh == NULL) { goto error; } @@ -4453,10 +4572,7 @@ } } if (errorId == JIM_BAD_FD) { - Jim_Obj *fhObj = Jim_NewStringObj(interp, error, -1); - FILE *fh = Jim_AioFilehandle(interp, fhObj); - - Jim_FreeNewObj(interp, fhObj); + FILE *fh = JimGetAioFilehandle(interp, error); if (fh == NULL) { goto error; } @@ -4544,7 +4660,7 @@ close(i); } - execvp(arg_array[firstArg], &arg_array[firstArg]); + execvpe(arg_array[firstArg], &arg_array[firstArg], Jim_GetEnviron()); fprintf(stderr, "couldn't exec \"%s\"", arg_array[firstArg]); @@ -4908,7 +5024,7 @@ static void JimRestoreEnv(char **env) { - JimFreeEnv(env, NULL); + JimFreeEnv(env, Jim_GetEnviron()); } static Jim_Obj * @@ -5294,58 +5410,30 @@ static int array_cmd_get(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { - int i; - int len; - int all = 0; - Jim_Obj *resultObj; Jim_Obj *objPtr = Jim_GetVariable(interp, argv[0], JIM_NONE); - Jim_Obj *dictObj; - Jim_Obj **dictValuesObj; if (!objPtr) { return JIM_OK; } if (argc == 1 || Jim_CompareStringImmediate(interp, argv[1], "*")) { - all = 1; - } - - - if (all) { - if (Jim_IsDict(objPtr) || (Jim_IsList(objPtr) && Jim_ListLength(interp, objPtr) % 2 == 0)) { - Jim_SetResult(interp, objPtr); - return JIM_OK; - } - } - - if (Jim_DictKeysVector(interp, objPtr, NULL, 0, &dictObj, JIM_ERRMSG) != JIM_OK) { - return JIM_ERR; - } - - if (Jim_DictPairs(interp, dictObj, &dictValuesObj, &len) != JIM_OK) { - return JIM_ERR; - } - - if (all) { - - Jim_SetResult(interp, dictObj); - } - else { - resultObj = Jim_NewListObj(interp, NULL, 0); - - for (i = 0; i < len; i += 2) { - if (Jim_StringMatchObj(interp, argv[1], dictValuesObj[i], 0)) { - Jim_ListAppendElement(interp, resultObj, dictValuesObj[i]); - Jim_ListAppendElement(interp, resultObj, dictValuesObj[i + 1]); + if (Jim_IsList(objPtr)) { + if (Jim_ListLength(interp, objPtr) % 2 != 0) { + + return JIM_ERR; } } - - Jim_SetResult(interp, resultObj); + else if (Jim_DictSize(interp, objPtr) < 0) { + + return JIM_ERR; + } + Jim_SetResult(interp, objPtr); + return JIM_OK; } - Jim_Free(dictValuesObj); - return JIM_OK; + + return Jim_DictValues(interp, objPtr, argv[1]); } static int array_cmd_names(Jim_Interp *interp, int argc, Jim_Obj *const *argv) @@ -5365,7 +5453,6 @@ int len; Jim_Obj *resultObj; Jim_Obj *objPtr; - Jim_Obj *dictObj; Jim_Obj **dictValuesObj; if (argc == 1 || Jim_CompareStringImmediate(interp, argv[1], "*")) { @@ -5376,11 +5463,7 @@ objPtr = Jim_GetVariable(interp, argv[0], JIM_NONE); - if (Jim_DictKeysVector(interp, objPtr, NULL, 0, &dictObj, JIM_ERRMSG) != JIM_OK) { - return JIM_ERR; - } - - if (Jim_DictPairs(interp, dictObj, &dictValuesObj, &len) != JIM_OK) { + if (Jim_DictPairs(interp, objPtr, &dictValuesObj, &len) != JIM_OK) { return JIM_ERR; } @@ -5421,30 +5504,35 @@ { int i; int len; - int rc = JIM_OK; Jim_Obj *listObj = argv[1]; - - if (Jim_GetVariable(interp, argv[0], JIM_NONE) == NULL) { - - return Jim_SetVariable(interp, argv[0], listObj); - } + Jim_Obj *dictObj; len = Jim_ListLength(interp, listObj); if (len % 2) { Jim_SetResultString(interp, "list must have an even number of elements", -1); return JIM_ERR; } - for (i = 0; i < len && rc == JIM_OK; i += 2) { + + dictObj = Jim_GetVariable(interp, argv[0], JIM_UNSHARED); + if (!dictObj) { + + return Jim_SetVariable(interp, argv[0], listObj); + } + + if (Jim_IsShared(dictObj)) { + dictObj = Jim_DuplicateObj(interp, dictObj); + } + + for (i = 0; i < len; i += 2) { Jim_Obj *nameObj; Jim_Obj *valueObj; Jim_ListIndex(interp, listObj, i, &nameObj, JIM_NONE); Jim_ListIndex(interp, listObj, i + 1, &valueObj, JIM_NONE); - rc = Jim_SetDictKeysVector(interp, argv[0], &nameObj, 1, valueObj, JIM_ERRMSG); + Jim_DictAddElement(interp, dictObj, nameObj, valueObj); } - - return rc; + return Jim_SetVariable(interp, argv[0], dictObj); } static const jim_subcmd_type array_command_table[] = { @@ -5585,6 +5673,9 @@ #define JIM_DEBUG_PANIC #endif + +#define JIM_INTEGER_SPACE 24 + const char *jim_tt_name(int type); #ifdef JIM_DEBUG_PANIC @@ -5601,15 +5692,13 @@ static void JimFreeCallFrame(Jim_Interp *interp, Jim_CallFrame *cf, int flags); static int ListSetIndex(Jim_Interp *interp, Jim_Obj *listPtr, int listindex, Jim_Obj *newObjPtr, int flags); +static int JimDeleteLocalProcs(Jim_Interp *interp, Jim_Stack *localCommands); static Jim_Obj *JimExpandDictSugar(Jim_Interp *interp, Jim_Obj *objPtr); static void SetDictSubstFromAny(Jim_Interp *interp, Jim_Obj *objPtr); +static 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 void JimDeleteLocalProcs(Jim_Interp *interp); -static int JimCallProcedure(Jim_Interp *interp, Jim_Cmd *cmd, Jim_Obj *fileNameObj, int linenr, - int argc, Jim_Obj *const *argv); -static int JimEvalObjVector(Jim_Interp *interp, int objc, Jim_Obj *const *objv, - Jim_Obj *fileNameObj, int linenr); +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); @@ -5617,8 +5706,6 @@ static void JimRandomBytes(Jim_Interp *interp, void *dest, unsigned int len); -static const Jim_HashTableType JimVariablesHashTableType; - #define JimWideValue(objPtr) (objPtr)->internalRep.wideValue @@ -5700,7 +5787,7 @@ -static int GlobMatch(const char *pattern, const char *string, int nocase) +static int JimGlobMatch(const char *pattern, const char *string, int nocase) { int c; int pchar; @@ -5716,7 +5803,7 @@ } while (*string) { - if (GlobMatch(pattern, string, nocase)) + if (JimGlobMatch(pattern, string, nocase)) return 1; string += utf8_tounicode(string, &c); } @@ -5765,11 +5852,6 @@ return 0; } -static int JimStringMatch(Jim_Interp *interp, Jim_Obj *patternObj, const char *string, int nocase) -{ - return GlobMatch(Jim_String(patternObj), string, nocase); -} - static int JimStringCompare(const char *s1, int l1, const char *s2, int l2) { if (l1 < l2) { @@ -5783,12 +5865,12 @@ } } -static int JimStringCompareNoCase(const char *s1, const char *s2, int maxchars) +static int JimStringCompareLen(const char *s1, const char *s2, int maxchars, int nocase) { while (*s1 && *s2 && maxchars) { int c1, c2; - s1 += utf8_tounicode_case(s1, &c1, 1); - s2 += utf8_tounicode_case(s2, &c2, 1); + s1 += utf8_tounicode_case(s1, &c1, nocase); + s2 += utf8_tounicode_case(s2, &c2, nocase); if (c1 != c2) { return JimSign(c1 - c2); } @@ -5858,11 +5940,38 @@ } #endif -int Jim_WideToString(char *buf, jim_wide wideValue) +static int JimWideToString(char *buf, jim_wide wideValue) { - const char *fmt = "%" JIM_WIDE_MODIFIER; + int pos = 0; + + if (wideValue == 0) { + buf[pos++] = '0'; + } + else { + char tmp[JIM_INTEGER_SPACE]; + int num = 0; + int i; + + if (wideValue < 0) { + buf[pos++] = '-'; + + i = wideValue % 10; + tmp[num++] = (i > 0) ? (10 - i) : -i; + wideValue /= -10; + } + + while (wideValue) { + tmp[num++] = wideValue % 10; + wideValue /= 10; + } + + for (i = 0; i < num; i++) { + buf[pos++] = '0' + tmp[num - i - 1]; + } + } + buf[pos] = 0; - return sprintf(buf, fmt, wideValue); + return pos; } static int JimCheckConversion(const char *str, const char *endptr) @@ -5882,48 +5991,142 @@ return JIM_OK; } -int Jim_StringToWide(const char *str, jim_wide * widePtr, int base) +static int JimNumberBase(const char *str, int *base, int *sign) { - char *endptr; - - *widePtr = strtoull(str, &endptr, base); - - return JimCheckConversion(str, endptr); -} + int i = 0; -int Jim_DoubleToString(char *buf, double doubleValue) -{ - int len; - char *buf0 = buf; + *base = 10; - len = sprintf(buf, "%.12g", doubleValue); + while (isspace(UCHAR(str[i]))) { + i++; + } - while (*buf) { - if (*buf == '.' || isalpha(UCHAR(*buf))) { - - if (*buf == 'i' || *buf == 'n') { - *buf = toupper(UCHAR(*buf)); - } - if (*buf == 'I') { - - buf[3] = '\0'; - len = buf - buf0 + 3; - } - return len; + if (str[i] == '-') { + *sign = -1; + i++; + } + else { + if (str[i] == '+') { + i++; } - buf++; + *sign = 1; } - *buf++ = '.'; - *buf++ = '0'; - *buf = '\0'; - - return len + 2; -} + if (str[i] != '0') { + + return 0; + } -int Jim_StringToDouble(const char *str, double *doublePtr) -{ - char *endptr; + + switch (str[i + 1]) { + case 'x': case 'X': *base = 16; break; + case 'o': case 'O': *base = 8; break; + case 'b': case 'B': *base = 2; break; + default: return 0; + } + i += 2; + + if (str[i] != '-' && str[i] != '+' && !isspace(UCHAR(str[i]))) { + + return i; + } + + *base = 10; + return 0; +} + +static long jim_strtol(const char *str, char **endptr) +{ + int sign; + int base; + int i = JimNumberBase(str, &base, &sign); + + if (base != 10) { + long value = strtol(str + i, endptr, base); + if (endptr == NULL || *endptr != str + i) { + return value * sign; + } + } + + + return strtol(str, endptr, 10); +} + + +static jim_wide jim_strtoull(const char *str, char **endptr) +{ +#ifdef HAVE_LONG_LONG + int sign; + int base; + int i = JimNumberBase(str, &base, &sign); + + if (base != 10) { + jim_wide value = strtoull(str + i, endptr, base); + if (endptr == NULL || *endptr != str + i) { + return value * sign; + } + } + + + return strtoull(str, endptr, 10); +#else + return (unsigned long)jim_strtol(str, endptr); +#endif +} + +int Jim_StringToWide(const char *str, jim_wide * widePtr, int base) +{ + char *endptr; + + if (base) { + *widePtr = strtoull(str, &endptr, base); + } + else { + *widePtr = jim_strtoull(str, &endptr); + } + + return JimCheckConversion(str, endptr); +} + +int Jim_DoubleToString(char *buf, double doubleValue) +{ + int len; + int i; + + len = sprintf(buf, "%.12g", doubleValue); + + + for (i = 0; i < len; i++) { + if (buf[i] == '.' || buf[i] == 'e') { +#if defined(JIM_SPRINTF_DOUBLE_NEEDS_FIX) + char *e = strchr(buf, 'e'); + if (e && (e[1] == '-' || e[1] == '+') && e[2] == '0') { + + e += 2; + memmove(e, e + 1, len - (e - buf)); + return len - 1; + } +#endif + return len; + } + + if (buf[i] == 'i' || buf[i] == 'I' || buf[i] == 'n' || buf[i] == 'N') { + buf[i] = toupper(UCHAR(buf[i])); + buf[i + 3] = 0; + return i + 3; + } + } + + buf[i++] = '.'; + buf[i++] = '0'; + buf[i] = '\0'; + + return i; +} + +int Jim_StringToDouble(const char *str, double *doublePtr) +{ + char *endptr; errno = 0; @@ -5976,14 +6179,14 @@ } #endif - abort(); + exit(1); } #endif void *Jim_Alloc(int size) { - return malloc(size); + return size ? malloc(size) : NULL; } void Jim_Free(void *ptr) @@ -6022,9 +6225,9 @@ -static int JimExpandHashTableIfNeeded(Jim_HashTable *ht); +static void JimExpandHashTableIfNeeded(Jim_HashTable *ht); static unsigned int JimHashTableNextPower(unsigned int size); -static int JimInsertHashEntry(Jim_HashTable *ht, const void *key); +static Jim_HashEntry *JimInsertHashEntry(Jim_HashTable *ht, const void *key, int replace); @@ -6060,6 +6263,14 @@ ht->collisions = 0; } +static void JimInitHashTableIterator(Jim_HashTable *ht, Jim_HashTableIterator *iter) +{ + iter->ht = ht; + iter->index = -1; + iter->entry = NULL; + iter->nextEntry = NULL; +} + int Jim_InitHashTable(Jim_HashTable *ht, const Jim_HashTableType *type, void *privDataPtr) { @@ -6069,23 +6280,23 @@ return JIM_OK; } -int Jim_ResizeHashTable(Jim_HashTable *ht) +void Jim_ResizeHashTable(Jim_HashTable *ht) { int minimal = ht->used; if (minimal < JIM_HT_INITIAL_SIZE) minimal = JIM_HT_INITIAL_SIZE; - return Jim_ExpandHashTable(ht, minimal); + Jim_ExpandHashTable(ht, minimal); } -int Jim_ExpandHashTable(Jim_HashTable *ht, unsigned int size) +void Jim_ExpandHashTable(Jim_HashTable *ht, unsigned int size) { Jim_HashTable n; unsigned int realsize = JimHashTableNextPower(size), i; - if (ht->used >= size) - return JIM_ERR; + if (size <= ht->used) + return; Jim_InitHashTable(&n, ht->type, ht->privdata); n.size = realsize; @@ -6122,43 +6333,43 @@ *ht = n; - return JIM_OK; } int Jim_AddHashEntry(Jim_HashTable *ht, const void *key, void *val) { - int idx; Jim_HashEntry *entry; - if ((idx = JimInsertHashEntry(ht, key)) == -1) + entry = JimInsertHashEntry(ht, key, 0); + if (entry == NULL) return JIM_ERR; - entry = Jim_Alloc(sizeof(*entry)); - entry->next = ht->table[idx]; - ht->table[idx] = entry; - - Jim_SetHashKey(ht, entry, key); Jim_SetHashVal(ht, entry, val); - ht->used++; return JIM_OK; } int Jim_ReplaceHashEntry(Jim_HashTable *ht, const void *key, void *val) { + int existed; Jim_HashEntry *entry; - if (Jim_AddHashEntry(ht, key, val) == JIM_OK) - return JIM_OK; - - entry = Jim_FindHashEntry(ht, key); - - Jim_FreeEntryVal(ht, entry); + entry = JimInsertHashEntry(ht, key, 1); + if (entry->key) { + + Jim_FreeEntryVal(ht, entry); + existed = 1; + } + else { + + Jim_SetHashKey(ht, entry, key); + existed = 0; + } Jim_SetHashVal(ht, entry, val); - return JIM_OK; + + return existed; } @@ -6239,11 +6450,7 @@ Jim_HashTableIterator *Jim_GetHashTableIterator(Jim_HashTable *ht) { Jim_HashTableIterator *iter = Jim_Alloc(sizeof(*iter)); - - iter->ht = ht; - iter->index = -1; - iter->entry = NULL; - iter->nextEntry = NULL; + JimInitHashTableIterator(ht, iter); return iter; } @@ -6270,13 +6477,12 @@ -static int JimExpandHashTableIfNeeded(Jim_HashTable *ht) +static void JimExpandHashTableIfNeeded(Jim_HashTable *ht) { if (ht->size == 0) - return Jim_ExpandHashTable(ht, JIM_HT_INITIAL_SIZE); + Jim_ExpandHashTable(ht, JIM_HT_INITIAL_SIZE); if (ht->size == ht->used) - return Jim_ExpandHashTable(ht, ht->size * 2); - return JIM_OK; + Jim_ExpandHashTable(ht, ht->size * 2); } @@ -6293,24 +6499,32 @@ } } -static int JimInsertHashEntry(Jim_HashTable *ht, const void *key) +static Jim_HashEntry *JimInsertHashEntry(Jim_HashTable *ht, const void *key, int replace) { unsigned int h; Jim_HashEntry *he; - if (JimExpandHashTableIfNeeded(ht) == JIM_ERR) - return -1; + JimExpandHashTableIfNeeded(ht); + h = Jim_HashKey(ht, key) & ht->sizemask; he = ht->table[h]; while (he) { if (Jim_CompareHashKeys(ht, key, he->key)) - return -1; + return replace ? he : NULL; he = he->next; } - return h; + + + he = Jim_Alloc(sizeof(*he)); + he->next = ht->table[h]; + ht->table[h] = he; + ht->used++; + he->key = NULL; + + return he; } @@ -6320,78 +6534,28 @@ return Jim_GenHashFunction(key, strlen(key)); } -static const void *JimStringCopyHTKeyDup(void *privdata, const void *key) -{ - int len = strlen(key); - char *copy = Jim_Alloc(len + 1); - - JIM_NOTUSED(privdata); - - memcpy(copy, key, len); - copy[len] = '\0'; - return copy; -} - -static void *JimStringKeyValCopyHTValDup(void *privdata, const void *val) +static void *JimStringCopyHTDup(void *privdata, const void *key) { - int len = strlen(val); - char *copy = Jim_Alloc(len + 1); - - JIM_NOTUSED(privdata); - - memcpy(copy, val, len); - copy[len] = '\0'; - return copy; + return strdup(key); } static int JimStringCopyHTKeyCompare(void *privdata, const void *key1, const void *key2) { - JIM_NOTUSED(privdata); - return strcmp(key1, key2) == 0; } -static void JimStringCopyHTKeyDestructor(void *privdata, const void *key) -{ - JIM_NOTUSED(privdata); - - Jim_Free((void *)key); -} - -static void JimStringKeyValCopyHTValDestructor(void *privdata, void *val) +static void JimStringCopyHTKeyDestructor(void *privdata, void *key) { - JIM_NOTUSED(privdata); - - Jim_Free((void *)val); + Jim_Free(key); } -#if 0 -static Jim_HashTableType JimStringCopyHashTableType = { - JimStringCopyHTHashFunction, - JimStringCopyHTKeyDup, - NULL, - JimStringCopyHTKeyCompare, - JimStringCopyHTKeyDestructor, - NULL -}; -#endif - -static const Jim_HashTableType JimSharedStringsHashTableType = { - JimStringCopyHTHashFunction, - NULL, - NULL, - JimStringCopyHTKeyCompare, - JimStringCopyHTKeyDestructor, - NULL -}; - -static const Jim_HashTableType JimStringKeyValCopyHashTableType = { - JimStringCopyHTHashFunction, - JimStringCopyHTKeyDup, - JimStringKeyValCopyHTValDup, - JimStringCopyHTKeyCompare, - JimStringCopyHTKeyDestructor, - JimStringKeyValCopyHTValDestructor, +static const Jim_HashTableType JimPackageHashTableType = { + JimStringCopyHTHashFunction, + JimStringCopyHTDup, + NULL, + JimStringCopyHTKeyCompare, + JimStringCopyHTKeyDestructor, + NULL }; typedef struct AssocDataValue @@ -6410,11 +6574,11 @@ } static const Jim_HashTableType JimAssocDataHashTableType = { - JimStringCopyHTHashFunction, - JimStringCopyHTKeyDup, - NULL, - JimStringCopyHTKeyCompare, - JimStringCopyHTKeyDestructor, + JimStringCopyHTHashFunction, + JimStringCopyHTDup, + NULL, + JimStringCopyHTKeyCompare, + JimStringCopyHTKeyDestructor, JimAssocDataHashTableValueDestructor }; @@ -6572,57 +6736,43 @@ if (*(pc->p + 1) == '\n' && pc->state == JIM_PS_DEF) { return JimParseSep(pc); } - else { - pc->comment = 0; - return JimParseStr(pc); - } - break; + pc->comment = 0; + return JimParseStr(pc); case ' ': case '\t': case '\r': + case '\f': if (pc->state == JIM_PS_DEF) return JimParseSep(pc); - else { - pc->comment = 0; - return JimParseStr(pc); - } - break; + pc->comment = 0; + return JimParseStr(pc); case '\n': case ';': pc->comment = 1; if (pc->state == JIM_PS_DEF) return JimParseEol(pc); - else - return JimParseStr(pc); - break; + return JimParseStr(pc); case '[': pc->comment = 0; return JimParseCmd(pc); - break; case '$': pc->comment = 0; if (JimParseVar(pc) == JIM_ERR) { + pc->tstart = pc->tend = pc->p++; pc->len--; - pc->tline = pc->linenr; - pc->tt = JIM_TT_STR; - return JIM_OK; + pc->tt = JIM_TT_ESC; } - else - return JIM_OK; - break; + return JIM_OK; case '#': if (pc->comment) { JimParseComment(pc); continue; } - else { - return JimParseStr(pc); - } + return JimParseStr(pc); default: pc->comment = 0; return JimParseStr(pc); - break; } return JIM_OK; } @@ -6632,8 +6782,10 @@ { pc->tstart = pc->p; pc->tline = pc->linenr; - while (*pc->p == ' ' || *pc->p == '\t' || *pc->p == '\r' || - (*pc->p == '\\' && *(pc->p + 1) == '\n')) { + while (isspace(UCHAR(*pc->p)) || (*pc->p == '\\' && *(pc->p + 1) == '\n')) { + if (*pc->p == '\n') { + break; + } if (*pc->p == '\\') { pc->p++; pc->len--; @@ -6651,7 +6803,7 @@ { pc->tstart = pc->p; pc->tline = pc->linenr; - while (*pc->p == ' ' || *pc->p == '\n' || *pc->p == '\t' || *pc->p == '\r' || *pc->p == ';') { + while (isspace(UCHAR(*pc->p)) || *pc->p == ';') { if (*pc->p == '\n') pc->linenr++; pc->p++; @@ -6878,11 +7030,13 @@ while (1) { if (pc->p[0] == ':' && pc->p[1] == ':') { - pc->p += 2; - pc->len -= 2; + while (*pc->p == ':') { + pc->p++; + pc->len--; + } continue; } - if (isalnum(UCHAR(*pc->p)) || *pc->p == '_') { + if (isalnum(UCHAR(*pc->p)) || *pc->p == '_' || UCHAR(*pc->p) >= 0x80) { pc->p++; pc->len--; continue; @@ -6939,17 +7093,19 @@ static int JimParseStr(struct JimParserCtx *pc) { - int newword = (pc->tt == JIM_TT_SEP || pc->tt == JIM_TT_EOL || - pc->tt == JIM_TT_NONE || pc->tt == JIM_TT_STR); - if (newword && *pc->p == '{') { - return JimParseBrace(pc); - } - else if (newword && *pc->p == '"') { - pc->state = JIM_PS_QUOTE; - pc->p++; - pc->len--; + if (pc->tt == JIM_TT_SEP || pc->tt == JIM_TT_EOL || + pc->tt == JIM_TT_NONE || pc->tt == JIM_TT_STR) { - pc->missingline = pc->tline; + if (*pc->p == '{') { + return JimParseBrace(pc); + } + if (*pc->p == '"') { + pc->state = JIM_PS_QUOTE; + pc->p++; + pc->len--; + + pc->missingline = pc->tline; + } } pc->tstart = pc->p; pc->tline = pc->linenr; @@ -7005,6 +7161,7 @@ case '\t': case '\n': case '\r': + case '\f': case ';': if (pc->state == JIM_PS_DEF) { pc->tend = pc->p - 1; @@ -7105,27 +7262,54 @@ i++; break; case 'u': + case 'U': case 'x': { - int val = 0; + unsigned val = 0; int k; + int maxchars = 2; i++; - for (k = 0; k < (s[i] == 'u' ? 4 : 2); k++) { + if (s[i] == 'U') { + maxchars = 8; + } + else if (s[i] == 'u') { + if (s[i + 1] == '{') { + maxchars = 6; + i++; + } + else { + maxchars = 4; + } + } + + for (k = 0; k < maxchars; k++) { int c = xdigitval(s[i + k + 1]); if (c == -1) { break; } val = (val << 4) | c; } + + if (s[i] == '{') { + if (k == 0 || val > 0x1fffff || s[i + k + 1] != '}') { + + i--; + k = 0; + } + else { + + k++; + } + } if (k) { - if (s[i] == 'u') { - p += utf8_fromunicode(p, val); + if (s[i] == 'x') { + *p++ = val; } else { - *p++ = val; + p += utf8_fromunicode(p, val); } i += k; break; @@ -7247,13 +7431,10 @@ static int JimParseList(struct JimParserCtx *pc) { + if (isspace(UCHAR(*pc->p))) { + return JimParseListSep(pc); + } switch (*pc->p) { - case ' ': - case '\n': - case '\t': - case '\r': - return JimParseListSep(pc); - case '"': return JimParseListQuote(pc); @@ -7278,7 +7459,7 @@ { pc->tstart = pc->p; pc->tline = pc->linenr; - while (*pc->p == ' ' || *pc->p == '\t' || *pc->p == '\r' || *pc->p == '\n') { + while (isspace(UCHAR(*pc->p))) { if (*pc->p == '\n') { pc->linenr++; } @@ -7334,22 +7515,18 @@ pc->tt = JIM_TT_STR; while (pc->len) { - switch (*pc->p) { - case '\\': - if (--pc->len == 0) { - - pc->tend = pc->p; - return JIM_OK; - } - pc->tt = JIM_TT_ESC; - pc->p++; - break; - case ' ': - case '\t': - case '\n': - case '\r': - pc->tend = pc->p - 1; + if (isspace(UCHAR(*pc->p))) { + pc->tend = pc->p - 1; + return JIM_OK; + } + if (*pc->p == '\\') { + if (--pc->len == 0) { + + pc->tend = pc->p; return JIM_OK; + } + pc->tt = JIM_TT_ESC; + pc->p++; } pc->p++; pc->len--; @@ -7426,23 +7603,6 @@ objPtr->bytes = NULL; } -#define Jim_SetStringRep(o, b, l) \ - do { (o)->bytes = b; (o)->length = l; } while (0) - -void Jim_InitStringRep(Jim_Obj *objPtr, const char *bytes, int length) -{ - if (length == 0) { - objPtr->bytes = JimEmptyStringRep; - objPtr->length = 0; - } - else { - objPtr->bytes = Jim_Alloc(length + 1); - objPtr->length = length; - memcpy(objPtr->bytes, bytes, length); - objPtr->bytes[length] = '\0'; - } -} - Jim_Obj *Jim_DuplicateObj(Jim_Interp *interp, Jim_Obj *objPtr) { @@ -7453,8 +7613,18 @@ dupPtr->bytes = NULL; } + else if (objPtr->length == 0) { + + dupPtr->bytes = JimEmptyStringRep; + dupPtr->length = 0; + dupPtr->typePtr = NULL; + return dupPtr; + } else { - Jim_InitStringRep(dupPtr, objPtr->bytes, objPtr->length); + dupPtr->bytes = Jim_Alloc(objPtr->length + 1); + dupPtr->length = objPtr->length; + + memcpy(dupPtr->bytes, objPtr->bytes, objPtr->length + 1); } @@ -7486,17 +7656,30 @@ int Jim_Length(Jim_Obj *objPtr) { - int len; - - Jim_GetString(objPtr, &len); - return len; + if (objPtr->bytes == NULL) { + + JimPanic((objPtr->typePtr->updateStringProc == NULL, "UpdateStringProc called against '%s' type.", objPtr->typePtr->name)); + objPtr->typePtr->updateStringProc(objPtr); + } + return objPtr->length; } -static void FreeDictSubstInternalRep(Jim_Interp *interp, Jim_Obj *objPtr); -static void DupDictSubstInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr); -static const Jim_ObjType dictSubstObjType = { - "dict-substitution", +const char *Jim_String(Jim_Obj *objPtr) +{ + if (objPtr->bytes == NULL) { + + JimPanic((objPtr->typePtr->updateStringProc == NULL, "UpdateStringProc called against '%s' type.", objPtr->typePtr->name)); + objPtr->typePtr->updateStringProc(objPtr); + } + return objPtr->bytes; +} + +static void FreeDictSubstInternalRep(Jim_Interp *interp, Jim_Obj *objPtr); +static void DupDictSubstInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr); + +static const Jim_ObjType dictSubstObjType = { + "dict-substitution", FreeDictSubstInternalRep, DupDictSubstInternalRep, NULL, @@ -7505,7 +7688,7 @@ static void FreeInterpolatedInternalRep(Jim_Interp *interp, Jim_Obj *objPtr) { - Jim_DecrRefCount(interp, (Jim_Obj *)objPtr->internalRep.twoPtrValue.ptr2); + Jim_DecrRefCount(interp, objPtr->internalRep.dictSubstValue.indexObjPtr); } static const Jim_ObjType interpolatedObjType = { @@ -7538,23 +7721,28 @@ static int SetStringFromAny(Jim_Interp *interp, Jim_Obj *objPtr) { - - (void)Jim_String(objPtr); - - Jim_FreeIntRep(interp, objPtr); - - objPtr->typePtr = &stringObjType; - objPtr->internalRep.strValue.maxLength = objPtr->length; - - objPtr->internalRep.strValue.charLength = -1; + if (objPtr->typePtr != &stringObjType) { + + if (objPtr->bytes == NULL) { + + JimPanic((objPtr->typePtr->updateStringProc == NULL, "UpdateStringProc called against '%s' type.", objPtr->typePtr->name)); + objPtr->typePtr->updateStringProc(objPtr); + } + + Jim_FreeIntRep(interp, objPtr); + + objPtr->typePtr = &stringObjType; + objPtr->internalRep.strValue.maxLength = objPtr->length; + + objPtr->internalRep.strValue.charLength = -1; + } return JIM_OK; } int Jim_Utf8Length(Jim_Interp *interp, Jim_Obj *objPtr) { #ifdef JIM_UTF8 - if (objPtr->typePtr != &stringObjType) - SetStringFromAny(interp, objPtr); + SetStringFromAny(interp, objPtr); if (objPtr->internalRep.strValue.charLength < 0) { objPtr->internalRep.strValue.charLength = utf8_strlen(objPtr->bytes, objPtr->length); @@ -7614,9 +7802,8 @@ { Jim_Obj *objPtr = Jim_NewObj(interp); - if (len == -1) - len = strlen(s); - Jim_SetStringRep(objPtr, s, len); + objPtr->bytes = s; + objPtr->length = len == -1 ? strlen(s) : len; objPtr->typePtr = NULL; return objPtr; } @@ -7656,8 +7843,7 @@ void Jim_AppendString(Jim_Interp *interp, Jim_Obj *objPtr, const char *str, int len) { JimPanic((Jim_IsShared(objPtr), "Jim_AppendString called with shared object")); - if (objPtr->typePtr != &stringObjType) - SetStringFromAny(interp, objPtr); + SetStringFromAny(interp, objPtr); StringAppendString(objPtr, str, len); } @@ -7674,8 +7860,7 @@ { va_list ap; - if (objPtr->typePtr != &stringObjType) - SetStringFromAny(interp, objPtr); + SetStringFromAny(interp, objPtr); va_start(ap, objPtr); while (1) { char *s = va_arg(ap, char *); @@ -7703,23 +7888,30 @@ int Jim_StringMatchObj(Jim_Interp *interp, Jim_Obj *patternObjPtr, Jim_Obj *objPtr, int nocase) { - return JimStringMatch(interp, patternObjPtr, Jim_String(objPtr), nocase); + return JimGlobMatch(Jim_String(patternObjPtr), Jim_String(objPtr), nocase); } int Jim_StringCompareObj(Jim_Interp *interp, Jim_Obj *firstObjPtr, Jim_Obj *secondObjPtr, int nocase) { - const char *s1, *s2; int l1, l2; - - s1 = Jim_GetString(firstObjPtr, &l1); - s2 = Jim_GetString(secondObjPtr, &l2); + const char *s1 = Jim_GetString(firstObjPtr, &l1); + const char *s2 = Jim_GetString(secondObjPtr, &l2); if (nocase) { - return JimStringCompareNoCase(s1, s2, -1); + + return JimStringCompareLen(s1, s2, -1, nocase); } return JimStringCompare(s1, l1, s2, l2); } +int Jim_StringCompareLenObj(Jim_Interp *interp, Jim_Obj *firstObjPtr, Jim_Obj *secondObjPtr, int nocase) +{ + const char *s1 = Jim_String(firstObjPtr); + const char *s2 = Jim_String(secondObjPtr); + + return JimStringCompareLen(s1, s2, Jim_Utf8Length(interp, firstObjPtr), nocase); +} + static int JimRelToAbsIndex(int len, int idx) { if (idx < 0) @@ -7727,35 +7919,47 @@ return idx; } -static void JimRelToAbsRange(int len, int first, int last, - int *firstPtr, int *lastPtr, int *rangeLenPtr) +static void JimRelToAbsRange(int len, int *firstPtr, int *lastPtr, int *rangeLenPtr) { int rangeLen; - if (first > last) { + if (*firstPtr > *lastPtr) { rangeLen = 0; } else { - rangeLen = last - first + 1; + rangeLen = *lastPtr - *firstPtr + 1; if (rangeLen) { - if (first < 0) { - rangeLen += first; - first = 0; - } - if (last >= len) { - rangeLen -= (last - (len - 1)); - last = len - 1; + if (*firstPtr < 0) { + rangeLen += *firstPtr; + *firstPtr = 0; + } + if (*lastPtr >= len) { + rangeLen -= (*lastPtr - (len - 1)); + *lastPtr = len - 1; } } } if (rangeLen < 0) rangeLen = 0; - *firstPtr = first; - *lastPtr = last; *rangeLenPtr = rangeLen; } +static int JimStringGetRange(Jim_Interp *interp, Jim_Obj *firstObjPtr, Jim_Obj *lastObjPtr, + int len, int *first, int *last, int *range) +{ + if (Jim_GetIndex(interp, firstObjPtr, first) != JIM_OK) { + return JIM_ERR; + } + if (Jim_GetIndex(interp, lastObjPtr, last) != JIM_OK) { + return JIM_ERR; + } + *first = JimRelToAbsIndex(len, *first); + *last = JimRelToAbsIndex(len, *last); + JimRelToAbsRange(len, first, last, range); + return JIM_OK; +} + Jim_Obj *Jim_StringByteRangeObj(Jim_Interp *interp, Jim_Obj *strObjPtr, Jim_Obj *firstObjPtr, Jim_Obj *lastObjPtr) { @@ -7764,13 +7968,12 @@ int rangeLen; int bytelen; - if (Jim_GetIndex(interp, firstObjPtr, &first) != JIM_OK || - Jim_GetIndex(interp, lastObjPtr, &last) != JIM_OK) - return NULL; str = Jim_GetString(strObjPtr, &bytelen); - first = JimRelToAbsIndex(bytelen, first); - last = JimRelToAbsIndex(bytelen, last); - JimRelToAbsRange(bytelen, first, last, &first, &last, &rangeLen); + + if (JimStringGetRange(interp, firstObjPtr, lastObjPtr, bytelen, &first, &last, &rangeLen) != JIM_OK) { + return NULL; + } + if (first == 0 && rangeLen == bytelen) { return strObjPtr; } @@ -7786,14 +7989,13 @@ int len, rangeLen; int bytelen; - if (Jim_GetIndex(interp, firstObjPtr, &first) != JIM_OK || - Jim_GetIndex(interp, lastObjPtr, &last) != JIM_OK) - return NULL; str = Jim_GetString(strObjPtr, &bytelen); len = Jim_Utf8Length(interp, strObjPtr); - first = JimRelToAbsIndex(len, first); - last = JimRelToAbsIndex(len, last); - JimRelToAbsRange(len, first, last, &first, &last, &rangeLen); + + if (JimStringGetRange(interp, firstObjPtr, lastObjPtr, len, &first, &last, &rangeLen) != JIM_OK) { + return NULL; + } + if (first == 0 && rangeLen == len) { return strObjPtr; } @@ -7807,48 +8009,110 @@ #endif } -static Jim_Obj *JimStringToLower(Jim_Interp *interp, Jim_Obj *strObjPtr) +Jim_Obj *JimStringReplaceObj(Jim_Interp *interp, + Jim_Obj *strObjPtr, Jim_Obj *firstObjPtr, Jim_Obj *lastObjPtr, Jim_Obj *newStrObj) { - char *buf, *p; - int len; + int first, last; const char *str; + int len, rangeLen; + Jim_Obj *objPtr; - if (strObjPtr->typePtr != &stringObjType) { - SetStringFromAny(interp, strObjPtr); + len = Jim_Utf8Length(interp, strObjPtr); + + if (JimStringGetRange(interp, firstObjPtr, lastObjPtr, len, &first, &last, &rangeLen) != JIM_OK) { + return NULL; } - str = Jim_GetString(strObjPtr, &len); + if (last < first) { + return strObjPtr; + } - buf = p = Jim_Alloc(len + 1); + str = Jim_String(strObjPtr); + + + objPtr = Jim_NewStringObjUtf8(interp, str, first); + + + if (newStrObj) { + Jim_AppendObj(interp, objPtr, newStrObj); + } + + + Jim_AppendString(interp, objPtr, str + utf8_index(str, last + 1), len - last - 1); + + return objPtr; +} + +static void JimStrCopyUpperLower(char *dest, const char *str, int uc) +{ while (*str) { int c; str += utf8_tounicode(str, &c); - p += utf8_fromunicode(p, utf8_lower(c)); + dest += utf8_fromunicode(dest, uc ? utf8_upper(c) : utf8_lower(c)); } - *p = 0; - return Jim_NewStringObjNoAlloc(interp, buf, len); + *dest = 0; } -static Jim_Obj *JimStringToUpper(Jim_Interp *interp, Jim_Obj *strObjPtr) +static Jim_Obj *JimStringToLower(Jim_Interp *interp, Jim_Obj *strObjPtr) { - char *buf, *p; + char *buf; int len; const char *str; + SetStringFromAny(interp, strObjPtr); + + str = Jim_GetString(strObjPtr, &len); + +#ifdef JIM_UTF8 + len *= 2; +#endif + buf = Jim_Alloc(len + 1); + JimStrCopyUpperLower(buf, str, 0); + return Jim_NewStringObjNoAlloc(interp, buf, -1); +} + +static Jim_Obj *JimStringToUpper(Jim_Interp *interp, Jim_Obj *strObjPtr) +{ + char *buf; + const char *str; + int len; + if (strObjPtr->typePtr != &stringObjType) { SetStringFromAny(interp, strObjPtr); } str = Jim_GetString(strObjPtr, &len); - buf = p = Jim_Alloc(len + 1); - while (*str) { - int c; - str += utf8_tounicode(str, &c); - p += utf8_fromunicode(p, utf8_upper(c)); +#ifdef JIM_UTF8 + len *= 2; +#endif + buf = Jim_Alloc(len + 1); + JimStrCopyUpperLower(buf, str, 1); + return Jim_NewStringObjNoAlloc(interp, buf, -1); +} + +static Jim_Obj *JimStringToTitle(Jim_Interp *interp, Jim_Obj *strObjPtr) +{ + char *buf, *p; + int len; + int c; + const char *str; + + str = Jim_GetString(strObjPtr, &len); + if (len == 0) { + return strObjPtr; } - *p = 0; - return Jim_NewStringObjNoAlloc(interp, buf, len); +#ifdef JIM_UTF8 + len *= 2; +#endif + buf = p = Jim_Alloc(len + 1); + + str += utf8_tounicode(str, &c); + p += utf8_fromunicode(p, utf8_title(c)); + + JimStrCopyUpperLower(p, str, 0); + + return Jim_NewStringObjNoAlloc(interp, buf, -1); } static const char *utf8_memchr(const char *str, int len, int c) @@ -7941,9 +8205,8 @@ trimchars = Jim_GetString(trimcharsObjPtr, &trimcharslen); } - if (strObjPtr->typePtr != &stringObjType) { - SetStringFromAny(interp, strObjPtr); - } + SetStringFromAny(interp, strObjPtr); + len = Jim_Length(strObjPtr); nontrim = JimFindTrimRight(strObjPtr->bytes, len, trimchars, trimcharslen); @@ -8111,7 +8374,7 @@ void DupSourceInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr) { - dupPtr->internalRep = srcPtr->internalRep; + dupPtr->internalRep.sourceValue = srcPtr->internalRep.sourceValue; Jim_IncrRefCount(dupPtr->internalRep.sourceValue.fileNameObj); } @@ -8119,7 +8382,7 @@ Jim_Obj *fileNameObj, int lineNumber) { JimPanic((Jim_IsShared(objPtr), "JimSetSourceInfo called with shared object")); - JimPanic((objPtr->typePtr != NULL, "JimSetSourceInfo called with typePtr != NULL")); + JimPanic((objPtr->typePtr == &sourceObjType, "JimSetSourceInfo called with non-source object")); Jim_IncrRefCount(fileNameObj); objPtr->internalRep.sourceValue.fileNameObj = fileNameObj; objPtr->internalRep.sourceValue.lineNumber = lineNumber; @@ -8182,7 +8445,8 @@ only used by Jim_EvalObj() as protection against shimmering of the currently evaluated object. */ Jim_Obj *fileNameObj; - int line; + int firstline; + int linenr; } ScriptObj; void FreeScriptInternalRep(Jim_Interp *interp, Jim_Obj *objPtr) @@ -8334,7 +8598,7 @@ count++; } } - linenr = script->line = tokenlist->list[0].line; + linenr = script->firstline = tokenlist->list[0].line; token = script->token = Jim_Alloc(sizeof(ScriptToken) * count); @@ -8475,7 +8739,6 @@ script = Jim_Alloc(sizeof(*script)); memset(script, 0, sizeof(*script)); script->inUse = 1; - script->line = line; if (objPtr->typePtr == &sourceObjType) { script->fileNameObj = objPtr->internalRep.sourceValue.fileNameObj; } @@ -8499,9 +8762,12 @@ ScriptObj *Jim_GetScript(Jim_Interp *interp, Jim_Obj *objPtr) { - struct ScriptObj *script = Jim_GetIntRepPtr(objPtr); + if (objPtr == interp->emptyObj) { + + objPtr = interp->nullScriptObj; + } - if (objPtr->typePtr != &scriptObjType || script->substFlags) { + if (objPtr->typePtr != &scriptObjType || ((struct ScriptObj *)Jim_GetIntRepPtr(objPtr))->substFlags) { SetScriptFromAny(interp, objPtr, NULL); } return (ScriptObj *) Jim_GetIntRepPtr(objPtr); @@ -8518,14 +8784,11 @@ if (cmdPtr->isproc) { Jim_DecrRefCount(interp, cmdPtr->u.proc.argListObjPtr); Jim_DecrRefCount(interp, cmdPtr->u.proc.bodyObjPtr); + Jim_DecrRefCount(interp, cmdPtr->u.proc.nsObj); if (cmdPtr->u.proc.staticVars) { Jim_FreeHashTable(cmdPtr->u.proc.staticVars); Jim_Free(cmdPtr->u.proc.staticVars); } - if (cmdPtr->u.proc.prevCmd) { - - JimDecrCmdRefCount(interp, cmdPtr->u.proc.prevCmd); - } } else { @@ -8533,37 +8796,121 @@ cmdPtr->u.native.delProc(interp, cmdPtr->u.native.privData); } } + if (cmdPtr->prevCmd) { + + JimDecrCmdRefCount(interp, cmdPtr->prevCmd); + } Jim_Free(cmdPtr); } } -static void JimCommandsHT_ValDestructor(void *interp, void *val) + +static void JimVariablesHTValDestructor(void *interp, void *val) { - JimDecrCmdRefCount(interp, val); + Jim_DecrRefCount(interp, ((Jim_Var *)val)->objPtr); + Jim_Free(val); } -static const Jim_HashTableType JimCommandsHashTableType = { +static const Jim_HashTableType JimVariablesHashTableType = { JimStringCopyHTHashFunction, - JimStringCopyHTKeyDup, - NULL, + JimStringCopyHTDup, + NULL, JimStringCopyHTKeyCompare, JimStringCopyHTKeyDestructor, - JimCommandsHT_ValDestructor + JimVariablesHTValDestructor +}; + +static void JimCommandsHT_ValDestructor(void *interp, void *val) +{ + JimDecrCmdRefCount(interp, val); +} + +static const Jim_HashTableType JimCommandsHashTableType = { + JimStringCopyHTHashFunction, + JimStringCopyHTDup, + NULL, + JimStringCopyHTKeyCompare, + JimStringCopyHTKeyDestructor, + JimCommandsHT_ValDestructor }; -int Jim_CreateCommand(Jim_Interp *interp, const char *cmdName, - Jim_CmdProc cmdProc, void *privData, Jim_DelCmdProc delProc) +#ifdef jim_ext_namespace +static Jim_Obj *JimQualifyNameObj(Jim_Interp *interp, Jim_Obj *nsObj) { - Jim_Cmd *cmdPtr; + 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; +} - if (Jim_DeleteHashEntry(&interp->commands, cmdName) != JIM_ERR) { +static const char *JimQualifyName(Jim_Interp *interp, const char *name, Jim_Obj **objPtrPtr) +{ + Jim_Obj *objPtr = interp->emptyObj; + + if (name[0] == ':' && name[1] == ':') { + + while (*++name == ':') { + } + } + else if (Jim_Length(interp->framePtr->nsObj)) { + objPtr = Jim_DuplicateObj(interp, interp->framePtr->nsObj); + Jim_AppendStrings(interp, objPtr, "::", name, NULL); + name = Jim_String(objPtr); + } + Jim_IncrRefCount(objPtr); + *objPtrPtr = objPtr; + return name; +} + + #define JimFreeQualifiedName(INTERP, OBJ) Jim_DecrRefCount((INTERP), (OBJ)) + +#else + + #define JimQualifyName(INTERP, NAME, DUMMY) (((NAME)[0] == ':' && (NAME)[1] == ':') ? (NAME) + 2 : (NAME)) + #define JimFreeQualifiedName(INTERP, DUMMY) (void)(DUMMY) +#endif + +static int JimCreateCommand(Jim_Interp *interp, const char *name, Jim_Cmd *cmd) +{ + Jim_HashEntry *he = Jim_FindHashEntry(&interp->commands, name); + if (he) { + Jim_InterpIncrProcEpoch(interp); } - cmdPtr = Jim_Alloc(sizeof(*cmdPtr)); + if (he && interp->local) { + + cmd->prevCmd = he->u.val; + he->u.val = cmd; + } + else { + if (he) { + + Jim_DeleteHashEntry(&interp->commands, name); + } + + Jim_AddHashEntry(&interp->commands, name, cmd); + } + return JIM_OK; +} + + +int Jim_CreateCommand(Jim_Interp *interp, const char *cmdNameStr, + Jim_CmdProc cmdProc, void *privData, Jim_DelCmdProc delProc) +{ + Jim_Cmd *cmdPtr = Jim_Alloc(sizeof(*cmdPtr)); memset(cmdPtr, 0, sizeof(*cmdPtr)); @@ -8572,23 +8919,97 @@ cmdPtr->u.native.cmdProc = cmdProc; cmdPtr->u.native.privData = privData; - Jim_AddHashEntry(&interp->commands, cmdName, cmdPtr); + JimCreateCommand(interp, cmdNameStr, cmdPtr); return JIM_OK; } -static int JimCreateProcedure(Jim_Interp *interp, Jim_Obj *cmdName, - Jim_Obj *argListObjPtr, Jim_Obj *staticsListObjPtr, Jim_Obj *bodyObjPtr) +static int JimCreateProcedureStatics(Jim_Interp *interp, Jim_Cmd *cmdPtr, Jim_Obj *staticsListObjPtr) +{ + int len, i; + + len = Jim_ListLength(interp, staticsListObjPtr); + if (len == 0) { + return JIM_OK; + } + + cmdPtr->u.proc.staticVars = Jim_Alloc(sizeof(Jim_HashTable)); + Jim_InitHashTable(cmdPtr->u.proc.staticVars, &JimVariablesHashTableType, interp); + for (i = 0; i < len; i++) { + Jim_Obj *objPtr = NULL, *initObjPtr = NULL, *nameObjPtr = NULL; + Jim_Var *varPtr; + int subLen; + + Jim_ListIndex(interp, staticsListObjPtr, i, &objPtr, JIM_NONE); + + subLen = Jim_ListLength(interp, objPtr); + if (subLen == 1 || subLen == 2) { + Jim_ListIndex(interp, objPtr, 0, &nameObjPtr, JIM_NONE); + if (subLen == 1) { + initObjPtr = Jim_GetVariable(interp, nameObjPtr, JIM_NONE); + if (initObjPtr == NULL) { + Jim_SetResultFormatted(interp, + "variable for initialization of static \"%#s\" not found in the local context", + nameObjPtr); + return JIM_ERR; + } + } + else { + Jim_ListIndex(interp, objPtr, 1, &initObjPtr, JIM_NONE); + } + if (JimValidName(interp, "static variable", nameObjPtr) != JIM_OK) { + return JIM_ERR; + } + + varPtr = Jim_Alloc(sizeof(*varPtr)); + varPtr->objPtr = initObjPtr; + Jim_IncrRefCount(initObjPtr); + varPtr->linkFramePtr = NULL; + if (Jim_AddHashEntry(cmdPtr->u.proc.staticVars, + Jim_String(nameObjPtr), varPtr) != JIM_OK) { + Jim_SetResultFormatted(interp, + "static variable name \"%#s\" duplicated in statics list", nameObjPtr); + Jim_DecrRefCount(interp, initObjPtr); + Jim_Free(varPtr); + return JIM_ERR; + } + } + else { + Jim_SetResultFormatted(interp, "too many fields in static specifier \"%#s\"", + objPtr); + return JIM_ERR; + } + } + return JIM_OK; +} + +static void JimUpdateProcNamespace(Jim_Interp *interp, Jim_Cmd *cmdPtr, const char *cmdname) +{ +#ifdef jim_ext_namespace + if (cmdPtr->isproc) { + + const char *pt = strrchr(cmdname, ':'); + if (pt && pt != cmdname && pt[-1] == ':') { + Jim_DecrRefCount(interp, cmdPtr->u.proc.nsObj); + cmdPtr->u.proc.nsObj = Jim_NewStringObj(interp, cmdname, pt - cmdname - 1); + Jim_IncrRefCount(cmdPtr->u.proc.nsObj); + + if (Jim_FindHashEntry(&interp->commands, pt + 1)) { + + Jim_InterpIncrProcEpoch(interp); + } + } + } +#endif +} + +static Jim_Cmd *JimCreateProcedureCmd(Jim_Interp *interp, Jim_Obj *argListObjPtr, + Jim_Obj *staticsListObjPtr, Jim_Obj *bodyObjPtr, Jim_Obj *nsObj) { Jim_Cmd *cmdPtr; - Jim_HashEntry *he; int argListLen; int i; - if (JimValidName(interp, "procedure", cmdName) != JIM_OK) { - return JIM_ERR; - } - argListLen = Jim_ListLength(interp, argListObjPtr); @@ -8601,63 +9022,14 @@ cmdPtr->u.proc.bodyObjPtr = bodyObjPtr; cmdPtr->u.proc.argsPos = -1; cmdPtr->u.proc.arglist = (struct Jim_ProcArg *)(cmdPtr + 1); + cmdPtr->u.proc.nsObj = nsObj ? nsObj : interp->emptyObj; Jim_IncrRefCount(argListObjPtr); Jim_IncrRefCount(bodyObjPtr); + Jim_IncrRefCount(cmdPtr->u.proc.nsObj); - if (staticsListObjPtr) { - int len, i; - - len = Jim_ListLength(interp, staticsListObjPtr); - if (len != 0) { - 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 = 0, *initObjPtr = 0, *nameObjPtr = 0; - Jim_Var *varPtr; - int subLen; - - Jim_ListIndex(interp, staticsListObjPtr, i, &objPtr, JIM_NONE); - - subLen = Jim_ListLength(interp, objPtr); - if (subLen == 1 || subLen == 2) { - Jim_ListIndex(interp, objPtr, 0, &nameObjPtr, JIM_NONE); - if (subLen == 1) { - initObjPtr = Jim_GetVariable(interp, nameObjPtr, JIM_NONE); - if (initObjPtr == NULL) { - Jim_SetResultFormatted(interp, - "variable for initialization of static \"%#s\" not found in the local context", - nameObjPtr); - goto err; - } - } - else { - Jim_ListIndex(interp, objPtr, 1, &initObjPtr, JIM_NONE); - } - if (JimValidName(interp, "static variable", nameObjPtr) != JIM_OK) { - goto 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); - goto err; - } - } - else { - Jim_SetResultFormatted(interp, "too many fields in static specifier \"%#s\"", - objPtr); - goto err; - } - } - } + if (staticsListObjPtr && JimCreateProcedureStatics(interp, cmdPtr, staticsListObjPtr) != JIM_OK) { + goto err; } @@ -8667,17 +9039,18 @@ Jim_Obj *nameObjPtr; Jim_Obj *defaultObjPtr; int len; - int n = 1; Jim_ListIndex(interp, argListObjPtr, i, &argPtr, JIM_NONE); len = Jim_ListLength(interp, argPtr); if (len == 0) { - Jim_SetResultString(interp, "procedure has argument with no name", -1); - goto err; + Jim_SetResultString(interp, "argument with no name", -1); +err: + JimDecrCmdRefCount(interp, cmdPtr); + return NULL; } if (len > 2) { - Jim_SetResultString(interp, "procedure has argument with too many fields", -1); + Jim_SetResultFormatted(interp, "too many fields in argument specifier \"%#s\"", argPtr); goto err; } @@ -8695,17 +9068,17 @@ if (Jim_CompareStringImmediate(interp, nameObjPtr, "args")) { if (cmdPtr->u.proc.argsPos >= 0) { - Jim_SetResultString(interp, "procedure has 'args' specified more than once", -1); + Jim_SetResultString(interp, "'args' specified more than once", -1); goto err; } cmdPtr->u.proc.argsPos = i; } else { if (len == 2) { - cmdPtr->u.proc.optArity += n; + cmdPtr->u.proc.optArity++; } else { - cmdPtr->u.proc.reqArity += n; + cmdPtr->u.proc.reqArity++; } } @@ -8713,152 +9086,160 @@ cmdPtr->u.proc.arglist[i].defaultObjPtr = defaultObjPtr; } - - - he = Jim_FindHashEntry(&interp->commands, Jim_String(cmdName)); - if (he) { + return cmdPtr; +} - Jim_InterpIncrProcEpoch(interp); - } +int Jim_DeleteCommand(Jim_Interp *interp, const char *name) +{ + int ret = JIM_OK; + Jim_Obj *qualifiedNameObj; + const char *qualname = JimQualifyName(interp, name, &qualifiedNameObj); - if (he && interp->local) { - - cmdPtr->u.proc.prevCmd = he->u.val; - he->u.val = cmdPtr; + if (Jim_DeleteHashEntry(&interp->commands, qualname) == JIM_ERR) { + Jim_SetResultFormatted(interp, "can't delete \"%s\": command doesn't exist", name); + ret = JIM_ERR; } else { - if (he) { - - Jim_DeleteHashEntry(&interp->commands, Jim_String(cmdName)); - } - - Jim_AddHashEntry(&interp->commands, Jim_String(cmdName), cmdPtr); + Jim_InterpIncrProcEpoch(interp); } - - Jim_SetResult(interp, cmdName); - return JIM_OK; - - err: - if (cmdPtr->u.proc.staticVars) { - Jim_FreeHashTable(cmdPtr->u.proc.staticVars); - } - Jim_Free(cmdPtr->u.proc.staticVars); - Jim_DecrRefCount(interp, argListObjPtr); - Jim_DecrRefCount(interp, bodyObjPtr); - Jim_Free(cmdPtr); - return JIM_ERR; -} + JimFreeQualifiedName(interp, qualifiedNameObj); -int Jim_DeleteCommand(Jim_Interp *interp, const char *cmdName) -{ - if (Jim_DeleteHashEntry(&interp->commands, cmdName) == JIM_ERR) - return JIM_ERR; - Jim_InterpIncrProcEpoch(interp); - return JIM_OK; + return ret; } int Jim_RenameCommand(Jim_Interp *interp, const char *oldName, const char *newName) { + int ret = JIM_ERR; Jim_HashEntry *he; + Jim_Cmd *cmdPtr; + Jim_Obj *qualifiedOldNameObj; + Jim_Obj *qualifiedNewNameObj; + const char *fqold; + const char *fqnew; - - he = Jim_FindHashEntry(&interp->commands, oldName); - if (he == NULL) { - Jim_SetResultFormatted(interp, "can't %s \"%s\": command doesn't exist", - newName[0] ? "rename" : "delete", oldName); - return JIM_ERR; + if (newName[0] == 0) { + return Jim_DeleteCommand(interp, oldName); } - if (newName[0] == '\0') - return Jim_DeleteCommand(interp, oldName); + fqold = JimQualifyName(interp, oldName, &qualifiedOldNameObj); + fqnew = JimQualifyName(interp, newName, &qualifiedNewNameObj); - if (Jim_FindHashEntry(&interp->commands, newName)) { + he = Jim_FindHashEntry(&interp->commands, fqold); + if (he == NULL) { + Jim_SetResultFormatted(interp, "can't rename \"%s\": command doesn't exist", oldName); + } + else if (Jim_FindHashEntry(&interp->commands, fqnew)) { Jim_SetResultFormatted(interp, "can't rename to \"%s\": command already exists", newName); - return JIM_ERR; } + else { + + cmdPtr = he->u.val; + JimIncrCmdRefCount(cmdPtr); + JimUpdateProcNamespace(interp, cmdPtr, fqnew); + Jim_AddHashEntry(&interp->commands, fqnew, cmdPtr); - - JimIncrCmdRefCount(he->u.val); - Jim_AddHashEntry(&interp->commands, newName, he->u.val); + + Jim_DeleteHashEntry(&interp->commands, fqold); - - Jim_DeleteHashEntry(&interp->commands, oldName); + + Jim_InterpIncrProcEpoch(interp); - - Jim_InterpIncrProcEpoch(interp); - return JIM_OK; + ret = JIM_OK; + } + + JimFreeQualifiedName(interp, qualifiedOldNameObj); + JimFreeQualifiedName(interp, qualifiedNewNameObj); + + return ret; } -static int SetCommandFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr); +static void FreeCommandInternalRep(Jim_Interp *interp, Jim_Obj *objPtr) +{ + Jim_DecrRefCount(interp, objPtr->internalRep.cmdValue.nsObj); +} + +static void DupCommandInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr) +{ + dupPtr->internalRep.cmdValue = srcPtr->internalRep.cmdValue; + dupPtr->typePtr = srcPtr->typePtr; + Jim_IncrRefCount(dupPtr->internalRep.cmdValue.nsObj); +} static const Jim_ObjType commandObjType = { "command", - NULL, - NULL, + FreeCommandInternalRep, + DupCommandInternalRep, NULL, JIM_TYPE_REFERENCES, }; -int SetCommandFromAny(Jim_Interp *interp, Jim_Obj *objPtr) +Jim_Cmd *Jim_GetCommand(Jim_Interp *interp, Jim_Obj *objPtr, int flags) { - Jim_HashEntry *he; - const char *cmdName; + Jim_Cmd *cmd; - - cmdName = Jim_String(objPtr); - - he = Jim_FindHashEntry(&interp->commands, cmdName); - if (he == NULL) - return JIM_ERR; + if (objPtr->typePtr != &commandObjType || + objPtr->internalRep.cmdValue.procEpoch != interp->procEpoch +#ifdef jim_ext_namespace + || !Jim_StringEqObj(objPtr->internalRep.cmdValue.nsObj, interp->framePtr->nsObj) +#endif + ) { + - - Jim_FreeIntRep(interp, objPtr); - objPtr->typePtr = &commandObjType; - objPtr->internalRep.cmdValue.procEpoch = interp->procEpoch; - objPtr->internalRep.cmdValue.cmdPtr = (void *)he->u.val; - return JIM_OK; -} + + const char *name = Jim_String(objPtr); + Jim_HashEntry *he; -Jim_Cmd *Jim_GetCommand(Jim_Interp *interp, Jim_Obj *objPtr, int flags) -{ - Jim_Cmd *cmd; + if (name[0] == ':' && name[1] == ':') { + while (*++name == ':') { + } + } +#ifdef jim_ext_namespace + else if (Jim_Length(interp->framePtr->nsObj)) { + + Jim_Obj *nameObj = Jim_DuplicateObj(interp, interp->framePtr->nsObj); + Jim_AppendStrings(interp, nameObj, "::", name, NULL); + he = Jim_FindHashEntry(&interp->commands, Jim_String(nameObj)); + Jim_FreeNewObj(interp, nameObj); + if (he) { + goto found; + } + } +#endif - if ((objPtr->typePtr != &commandObjType || - objPtr->internalRep.cmdValue.procEpoch != interp->procEpoch) && - SetCommandFromAny(interp, objPtr) == JIM_ERR) { - if (flags & JIM_ERRMSG) { - Jim_SetResultFormatted(interp, "invalid command name \"%#s\"", objPtr); + + he = Jim_FindHashEntry(&interp->commands, name); + if (he == NULL) { + if (flags & JIM_ERRMSG) { + Jim_SetResultFormatted(interp, "invalid command name \"%#s\"", objPtr); + } + return NULL; } - return NULL; +#ifdef jim_ext_namespace +found: +#endif + cmd = (Jim_Cmd *)he->u.val; + + + Jim_FreeIntRep(interp, objPtr); + objPtr->typePtr = &commandObjType; + objPtr->internalRep.cmdValue.procEpoch = interp->procEpoch; + objPtr->internalRep.cmdValue.cmdPtr = cmd; + objPtr->internalRep.cmdValue.nsObj = interp->framePtr->nsObj; + Jim_IncrRefCount(interp->framePtr->nsObj); } - cmd = objPtr->internalRep.cmdValue.cmdPtr; - while (cmd->isproc && cmd->u.proc.upcall) { - cmd = cmd->u.proc.prevCmd; + else { + cmd = objPtr->internalRep.cmdValue.cmdPtr; + } + while (cmd->u.proc.upcall) { + cmd = cmd->prevCmd; } return cmd; } -static void JimVariablesHTValDestructor(void *interp, void *val) -{ - Jim_Var *varPtr = (void *)val; - - Jim_DecrRefCount(interp, varPtr->objPtr); - Jim_Free(val); -} - -static const Jim_HashTableType JimVariablesHashTableType = { - JimStringCopyHTHashFunction, - JimStringCopyHTKeyDup, - NULL, - JimStringCopyHTKeyCompare, - JimStringCopyHTKeyDestructor, - JimVariablesHTValDestructor -}; - #define JIM_DICT_SUGAR 100 @@ -8872,13 +9253,6 @@ JIM_TYPE_REFERENCES, }; -static int JimNameIsDictSugar(const char *str, int len) -{ - if (len && str[len - 1] == ')' && strchr(str, '(') != NULL) - return 1; - return 0; -} - static int JimValidName(Jim_Interp *interp, const char *type, Jim_Obj *nameObjPtr) { @@ -8895,56 +9269,65 @@ static int SetVariableFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr) { - Jim_HashEntry *he; const char *varName; + Jim_CallFrame *framePtr; + Jim_HashEntry *he; + int global; int len; - Jim_CallFrame *framePtr = interp->framePtr; - if (objPtr->typePtr == &variableObjType && - objPtr->internalRep.varValue.callFrameId == framePtr->id) { - return JIM_OK; + if (objPtr->typePtr == &variableObjType) { + framePtr = objPtr->internalRep.varValue.global ? interp->topFramePtr : interp->framePtr; + if (objPtr->internalRep.varValue.callFrameId == framePtr->id) { + + return JIM_OK; + } + } - - if (objPtr->typePtr == &dictSubstObjType) { + else if (objPtr->typePtr == &dictSubstObjType) { return JIM_DICT_SUGAR; } - - if (JimValidName(interp, "variable", objPtr) != JIM_OK) { + else if (JimValidName(interp, "variable", objPtr) != JIM_OK) { return JIM_ERR; } - + varName = Jim_GetString(objPtr, &len); - if (JimNameIsDictSugar(varName, len)) { + if (len && varName[len - 1] == ')' && strchr(varName, '(') != NULL) { return JIM_DICT_SUGAR; } if (varName[0] == ':' && varName[1] == ':') { - framePtr = interp->topFramePtr; - he = Jim_FindHashEntry(&framePtr->vars, varName + 2); - if (he == NULL) { - return JIM_ERR; + while (*++varName == ':') { } + global = 1; + framePtr = interp->topFramePtr; } else { - - he = Jim_FindHashEntry(&framePtr->vars, varName); - if (he == NULL) { + global = 0; + framePtr = interp->framePtr; + } + + + he = Jim_FindHashEntry(&framePtr->vars, varName); + if (he == NULL) { + if (!global && framePtr->staticVars) { - if (framePtr->staticVars == NULL) - return JIM_ERR; - if (!(he = Jim_FindHashEntry(framePtr->staticVars, varName))) - return JIM_ERR; + he = Jim_FindHashEntry(framePtr->staticVars, varName); + } + if (he == NULL) { + return JIM_ERR; } } + Jim_FreeIntRep(interp, objPtr); objPtr->typePtr = &variableObjType; objPtr->internalRep.varValue.callFrameId = framePtr->id; - objPtr->internalRep.varValue.varPtr = (void *)he->u.val; + objPtr->internalRep.varValue.varPtr = he->u.val; + objPtr->internalRep.varValue.global = global; return JIM_OK; } @@ -8952,63 +9335,78 @@ static int JimDictSugarSet(Jim_Interp *interp, Jim_Obj *ObjPtr, Jim_Obj *valObjPtr); static Jim_Obj *JimDictSugarGet(Jim_Interp *interp, Jim_Obj *ObjPtr, int flags); - -int Jim_SetVariable(Jim_Interp *interp, Jim_Obj *nameObjPtr, Jim_Obj *valObjPtr) +static Jim_Var *JimCreateVariable(Jim_Interp *interp, Jim_Obj *nameObjPtr, Jim_Obj *valObjPtr) { const char *name; - Jim_Var *var; - int err; - - if ((err = SetVariableFromAny(interp, nameObjPtr)) != JIM_OK) { - Jim_CallFrame *framePtr = interp->framePtr; - - - if (err == JIM_DICT_SUGAR) - return JimDictSugarSet(interp, nameObjPtr, valObjPtr); + Jim_CallFrame *framePtr; + int global; - if (JimValidName(interp, "variable", nameObjPtr) != JIM_OK) { - return JIM_ERR; - } + + Jim_Var *var = Jim_Alloc(sizeof(*var)); - - name = Jim_String(nameObjPtr); + var->objPtr = valObjPtr; + Jim_IncrRefCount(valObjPtr); + var->linkFramePtr = NULL; - var = Jim_Alloc(sizeof(*var)); - var->objPtr = valObjPtr; - Jim_IncrRefCount(valObjPtr); - var->linkFramePtr = NULL; - - if (name[0] == ':' && name[1] == ':') { - - framePtr = interp->topFramePtr; - Jim_AddHashEntry(&framePtr->vars, name + 2, var); - } - else { - Jim_AddHashEntry(&framePtr->vars, name, var); + name = Jim_String(nameObjPtr); + if (name[0] == ':' && name[1] == ':') { + while (*++name == ':') { } - - Jim_FreeIntRep(interp, nameObjPtr); - nameObjPtr->typePtr = &variableObjType; - nameObjPtr->internalRep.varValue.callFrameId = framePtr->id; - nameObjPtr->internalRep.varValue.varPtr = var; + framePtr = interp->topFramePtr; + global = 1; } else { - var = nameObjPtr->internalRep.varValue.varPtr; - if (var->linkFramePtr == NULL) { - Jim_IncrRefCount(valObjPtr); - Jim_DecrRefCount(interp, var->objPtr); - var->objPtr = valObjPtr; - } - else { - Jim_CallFrame *savedCallFrame; + framePtr = interp->framePtr; + global = 0; + } - savedCallFrame = interp->framePtr; - interp->framePtr = var->linkFramePtr; - err = Jim_SetVariable(interp, var->objPtr, valObjPtr); - interp->framePtr = savedCallFrame; - if (err != JIM_OK) - return err; - } + + Jim_AddHashEntry(&framePtr->vars, name, var); + + + Jim_FreeIntRep(interp, nameObjPtr); + nameObjPtr->typePtr = &variableObjType; + nameObjPtr->internalRep.varValue.callFrameId = framePtr->id; + nameObjPtr->internalRep.varValue.varPtr = var; + nameObjPtr->internalRep.varValue.global = global; + + return var; +} + + +int Jim_SetVariable(Jim_Interp *interp, Jim_Obj *nameObjPtr, Jim_Obj *valObjPtr) +{ + int err; + Jim_Var *var; + + switch (SetVariableFromAny(interp, nameObjPtr)) { + case JIM_DICT_SUGAR: + return JimDictSugarSet(interp, nameObjPtr, valObjPtr); + + case JIM_ERR: + if (JimValidName(interp, "variable", nameObjPtr) != JIM_OK) { + return JIM_ERR; + } + JimCreateVariable(interp, nameObjPtr, valObjPtr); + break; + + case JIM_OK: + var = nameObjPtr->internalRep.varValue.varPtr; + if (var->linkFramePtr == NULL) { + Jim_IncrRefCount(valObjPtr); + Jim_DecrRefCount(interp, var->objPtr); + var->objPtr = valObjPtr; + } + else { + Jim_CallFrame *savedCallFrame; + + savedCallFrame = interp->framePtr; + interp->framePtr = var->linkFramePtr; + err = Jim_SetVariable(interp, var->objPtr, valObjPtr); + interp->framePtr = savedCallFrame; + if (err != JIM_OK) + return err; + } } return JIM_OK; } @@ -9056,42 +9454,70 @@ Jim_Obj *targetNameObjPtr, Jim_CallFrame *targetCallFrame) { const char *varName; - int len; + const char *targetName; + Jim_CallFrame *framePtr; + Jim_Var *varPtr; - varName = Jim_GetString(nameObjPtr, &len); + + switch (SetVariableFromAny(interp, nameObjPtr)) { + case JIM_DICT_SUGAR: + + Jim_SetResultFormatted(interp, "bad variable name \"%#s\": upvar won't create a scalar variable that looks like an array element", nameObjPtr); + return JIM_ERR; - if (varName[0] == ':' && varName[1] == ':') { - - return JIM_OK; - } + case JIM_OK: + varPtr = nameObjPtr->internalRep.varValue.varPtr; - if (JimNameIsDictSugar(varName, len)) { - Jim_SetResultString(interp, "Dict key syntax invalid as link source", -1); - return JIM_ERR; + if (varPtr->linkFramePtr == NULL) { + Jim_SetResultFormatted(interp, "variable \"%#s\" already exists", nameObjPtr); + return JIM_ERR; + } + + + varPtr->linkFramePtr = NULL; + break; } - if (SetVariableFromAny(interp, nameObjPtr) == JIM_OK) { - Jim_Var *varPtr = nameObjPtr->internalRep.varValue.varPtr; + + varName = Jim_String(nameObjPtr); - if (varPtr->linkFramePtr == NULL) { - Jim_SetResultFormatted(interp, "variable \"%#s\" already exists", nameObjPtr); - return JIM_ERR; + if (varName[0] == ':' && varName[1] == ':') { + while (*++varName == ':') { } - - varPtr->linkFramePtr = NULL; + framePtr = interp->topFramePtr; + } + else { + framePtr = interp->framePtr; + } + + targetName = Jim_String(targetNameObjPtr); + if (targetName[0] == ':' && targetName[1] == ':') { + while (*++targetName == ':') { + } + targetNameObjPtr = Jim_NewStringObj(interp, targetName, -1); + targetCallFrame = interp->topFramePtr; + } + Jim_IncrRefCount(targetNameObjPtr); + + if (framePtr->level < targetCallFrame->level) { + Jim_SetResultFormatted(interp, + "bad variable name \"%#s\": upvar won't create namespace variable that refers to procedure variable", + nameObjPtr); + Jim_DecrRefCount(interp, targetNameObjPtr); + return JIM_ERR; } - if (interp->framePtr == targetCallFrame) { + if (framePtr == targetCallFrame) { Jim_Obj *objPtr = targetNameObjPtr; - Jim_Var *varPtr; while (1) { - if (Jim_StringEqObj(objPtr, nameObjPtr)) { + if (strcmp(Jim_String(objPtr), varName) == 0) { Jim_SetResultString(interp, "can't upvar from variable to itself", -1); + Jim_DecrRefCount(interp, targetNameObjPtr); return JIM_ERR; } if (SetVariableFromAny(interp, objPtr) != JIM_OK) @@ -9107,6 +9533,7 @@ Jim_SetVariable(interp, nameObjPtr, targetNameObjPtr); nameObjPtr->internalRep.varValue.varPtr->linkFramePtr = targetCallFrame; + Jim_DecrRefCount(interp, targetNameObjPtr); return JIM_OK; } @@ -9185,9 +9612,9 @@ int Jim_UnsetVariable(Jim_Interp *interp, Jim_Obj *nameObjPtr, int flags) { - const char *name; Jim_Var *varPtr; int retval; + Jim_CallFrame *framePtr; retval = SetVariableFromAny(interp, nameObjPtr); if (retval == JIM_DICT_SUGAR) { @@ -9199,21 +9626,21 @@ if (varPtr->linkFramePtr) { - Jim_CallFrame *savedCallFrame; - - savedCallFrame = interp->framePtr; + framePtr = interp->framePtr; interp->framePtr = varPtr->linkFramePtr; retval = Jim_UnsetVariable(interp, varPtr->objPtr, JIM_NONE); - interp->framePtr = savedCallFrame; + interp->framePtr = framePtr; } else { - Jim_CallFrame *framePtr = interp->framePtr; - - name = Jim_String(nameObjPtr); - if (name[0] == ':' && name[1] == ':') { - framePtr = interp->topFramePtr; + const char *name = Jim_String(nameObjPtr); + if (nameObjPtr->internalRep.varValue.global) { name += 2; + framePtr = interp->topFramePtr; + } + else { + framePtr = interp->framePtr; } + retval = Jim_DeleteHashEntry(&framePtr->vars, name); if (retval == JIM_OK) { @@ -9265,7 +9692,7 @@ SetDictSubstFromAny(interp, objPtr); err = Jim_SetDictKeysVector(interp, objPtr->internalRep.dictSubstValue.varNameObjPtr, - &objPtr->internalRep.dictSubstValue.indexObjPtr, 1, valObjPtr, JIM_ERRMSG); + &objPtr->internalRep.dictSubstValue.indexObjPtr, 1, valObjPtr, JIM_MUSTEXIST); if (err == JIM_OK) { @@ -9361,10 +9788,8 @@ if (objPtr->typePtr == &interpolatedObjType) { - const ScriptToken *token = objPtr->internalRep.twoPtrValue.ptr1; - - varObjPtr = token[0].objPtr; - keyObjPtr = objPtr->internalRep.twoPtrValue.ptr2; + varObjPtr = objPtr->internalRep.dictSubstValue.varNameObjPtr; + keyObjPtr = objPtr->internalRep.dictSubstValue.indexObjPtr; Jim_IncrRefCount(varObjPtr); Jim_IncrRefCount(keyObjPtr); @@ -9414,13 +9839,13 @@ } -static Jim_CallFrame *JimCreateCallFrame(Jim_Interp *interp, Jim_CallFrame *parent) +static Jim_CallFrame *JimCreateCallFrame(Jim_Interp *interp, Jim_CallFrame *parent, Jim_Obj *nsObj) { Jim_CallFrame *cf; if (interp->freeFramesList) { cf = interp->freeFramesList; - interp->freeFramesList = cf->nextFramePtr; + interp->freeFramesList = cf->next; } else { cf = Jim_Alloc(sizeof(*cf)); @@ -9428,14 +9853,18 @@ } cf->id = interp->callFrameEpoch++; - cf->parentCallFrame = parent; + cf->parent = parent; cf->level = parent ? parent->level + 1 : 0; cf->argv = NULL; cf->argc = 0; cf->procArgsObjPtr = NULL; cf->procBodyObjPtr = NULL; - cf->nextFramePtr = NULL; + cf->next = NULL; cf->staticVars = NULL; + cf->localCommands = NULL; + + cf->nsObj = nsObj; + Jim_IncrRefCount(nsObj); if (cf->vars.table == NULL) Jim_InitHashTable(&cf->vars, &JimVariablesHashTableType, interp); return cf; @@ -9447,6 +9876,47 @@ cf->id = interp->callFrameEpoch++; } +static int JimDeleteLocalProcs(Jim_Interp *interp, Jim_Stack *localCommands) +{ + + if (localCommands) { + Jim_Obj *cmdNameObj; + + while ((cmdNameObj = Jim_StackPop(localCommands)) != NULL) { + Jim_HashEntry *he; + Jim_Obj *fqObjName; + + const char *fqname = JimQualifyName(interp, Jim_String(cmdNameObj), &fqObjName); + + he = Jim_FindHashEntry(&interp->commands, fqname); + + if (he) { + Jim_Cmd *cmd = he->u.val; + if (cmd->prevCmd) { + Jim_Cmd *prevCmd = cmd->prevCmd; + cmd->prevCmd = NULL; + + + JimDecrCmdRefCount(interp, cmd); + + + he->u.val = prevCmd; + } + else { + Jim_DeleteHashEntry(&interp->commands, fqname); + Jim_InterpIncrProcEpoch(interp); + } + } + Jim_DecrRefCount(interp, cmdNameObj); + JimFreeQualifiedName(interp, fqObjName); + } + Jim_FreeStack(localCommands); + Jim_Free(localCommands); + } + return JIM_OK; +} + + #define JIM_FCF_NONE 0 #define JIM_FCF_NOHT 1 static void JimFreeCallFrame(Jim_Interp *interp, Jim_CallFrame *cf, int flags) @@ -9455,6 +9925,7 @@ Jim_DecrRefCount(interp, cf->procArgsObjPtr); if (cf->procBodyObjPtr) Jim_DecrRefCount(interp, cf->procBodyObjPtr); + Jim_DecrRefCount(interp, cf->nsObj); if (!(flags & JIM_FCF_NOHT)) Jim_FreeHashTable(&cf->vars); else { @@ -9477,10 +9948,15 @@ } cf->vars.used = 0; } - cf->nextFramePtr = interp->freeFramesList; + + JimDeleteLocalProcs(interp, cf->localCommands); + + cf->next = interp->freeFramesList; interp->freeFramesList = cf; + } + #ifdef JIM_REFERENCES static void JimReferencesHTValDestructor(void *interp, void *val) @@ -9497,19 +9973,19 @@ static unsigned int JimReferencesHTHashFunction(const void *key) { - const jim_wide *widePtr = key; + const unsigned long *widePtr = key; unsigned int intValue = (unsigned int)*widePtr; return Jim_IntHashFunction(intValue); } -static const void *JimReferencesHTKeyDup(void *privdata, const void *key) +static void *JimReferencesHTKeyDup(void *privdata, const void *key) { - void *copy = Jim_Alloc(sizeof(jim_wide)); + void *copy = Jim_Alloc(sizeof(unsigned long)); JIM_NOTUSED(privdata); - memcpy(copy, key, sizeof(jim_wide)); + memcpy(copy, key, sizeof(unsigned long)); return copy; } @@ -9517,14 +9993,14 @@ { JIM_NOTUSED(privdata); - return memcmp(key1, key2, sizeof(jim_wide)) == 0; + return memcmp(key1, key2, sizeof(unsigned long)) == 0; } -static void JimReferencesHTKeyDestructor(void *privdata, const void *key) +static void JimReferencesHTKeyDestructor(void *privdata, void *key) { JIM_NOTUSED(privdata); - Jim_Free((void *)key); + Jim_Free(key); } static const Jim_HashTableType JimReferencesHashTableType = { @@ -9540,9 +10016,9 @@ #define JIM_REFERENCE_SPACE (35+JIM_REFERENCE_TAGLEN) -static int JimFormatReference(char *buf, Jim_Reference *refPtr, jim_wide id) +static int JimFormatReference(char *buf, Jim_Reference *refPtr, unsigned long id) { - const char *fmt = ".%020" JIM_WIDE_MODIFIER ">"; + const char *fmt = ".%020lu>"; sprintf(buf, fmt, refPtr->tag, id); return JIM_REFERENCE_SPACE; @@ -9578,12 +10054,13 @@ static int SetReferenceFromAny(Jim_Interp *interp, Jim_Obj *objPtr) { - jim_wide wideValue; + unsigned long value; int i, len; const char *str, *start, *end; char refId[21]; Jim_Reference *refPtr; Jim_HashEntry *he; + char *endptr; str = Jim_GetString(objPtr, &len); @@ -9613,10 +10090,11 @@ memcpy(refId, start + 14 + JIM_REFERENCE_TAGLEN, 20); refId[20] = '\0'; - if (Jim_StringToWide(refId, &wideValue, 10) != JIM_OK) + value = strtoul(refId, &endptr, 10); + if (JimCheckConversion(refId, endptr) != JIM_OK) goto badformat; - he = Jim_FindHashEntry(&interp->references, &wideValue); + he = Jim_FindHashEntry(&interp->references, &value); if (he == NULL) { Jim_SetResultFormatted(interp, "invalid reference id \"%#s\"", objPtr); return JIM_ERR; @@ -9625,7 +10103,7 @@ Jim_FreeIntRep(interp, objPtr); objPtr->typePtr = &referenceObjType; - objPtr->internalRep.refValue.id = wideValue; + objPtr->internalRep.refValue.id = value; objPtr->internalRep.refValue.refPtr = refPtr; return JIM_OK; @@ -9637,7 +10115,7 @@ Jim_Obj *Jim_NewReference(Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj *tagPtr, Jim_Obj *cmdNamePtr) { struct Jim_Reference *refPtr; - jim_wide wideValue = interp->referenceNextId; + unsigned long id; Jim_Obj *refObjPtr; const char *tag; int tagLen, i; @@ -9651,11 +10129,12 @@ refPtr->finalizerCmdNamePtr = cmdNamePtr; if (cmdNamePtr) Jim_IncrRefCount(cmdNamePtr); - Jim_AddHashEntry(&interp->references, &wideValue, refPtr); + id = interp->referenceNextId++; + Jim_AddHashEntry(&interp->references, &id, refPtr); refObjPtr = Jim_NewObj(interp); refObjPtr->typePtr = &referenceObjType; refObjPtr->bytes = NULL; - refObjPtr->internalRep.refValue.id = interp->referenceNextId; + refObjPtr->internalRep.refValue.id = id; refObjPtr->internalRep.refValue.refPtr = refPtr; interp->referenceNextId++; tag = Jim_GetString(tagPtr, &tagLen); @@ -9724,7 +10203,7 @@ void Jim_CollectIfNeeded(Jim_Interp *interp) { - jim_wide elapsedId; + unsigned long elapsedId; int elapsedTime; elapsedId = interp->referenceNextId - interp->lastCollectId; @@ -9754,7 +10233,8 @@ memset(i, 0, sizeof(*i)); - i->maxNestingDepth = JIM_MAX_NESTING_DEPTH; + i->maxCallFrameDepth = JIM_MAX_CALLFRAME_DEPTH; + i->maxEvalDepth = JIM_MAX_EVAL_DEPTH; i->lastCollectTime = time(NULL); Jim_InitHashTable(&i->commands, &JimCommandsHashTableType, i); @@ -9762,23 +10242,25 @@ Jim_InitHashTable(&i->references, &JimReferencesHashTableType, i); #endif Jim_InitHashTable(&i->assocData, &JimAssocDataHashTableType, i); - Jim_InitHashTable(&i->packages, &JimStringKeyValCopyHashTableType, NULL); - i->framePtr = i->topFramePtr = JimCreateCallFrame(i, NULL); + Jim_InitHashTable(&i->packages, &JimPackageHashTableType, NULL); i->emptyObj = Jim_NewEmptyStringObj(i); i->trueObj = Jim_NewIntObj(i, 1); i->falseObj = Jim_NewIntObj(i, 0); + i->framePtr = i->topFramePtr = JimCreateCallFrame(i, NULL, i->emptyObj); i->errorFileNameObj = i->emptyObj; i->result = i->emptyObj; i->stackTrace = Jim_NewListObj(i, NULL, 0); i->unknown = Jim_NewStringObj(i, "unknown", -1); i->errorProc = i->emptyObj; i->currentScriptObj = Jim_NewEmptyStringObj(i); + i->nullScriptObj = Jim_NewEmptyStringObj(i); Jim_IncrRefCount(i->emptyObj); Jim_IncrRefCount(i->errorFileNameObj); Jim_IncrRefCount(i->result); Jim_IncrRefCount(i->stackTrace); Jim_IncrRefCount(i->unknown); Jim_IncrRefCount(i->currentScriptObj); + Jim_IncrRefCount(i->nullScriptObj); Jim_IncrRefCount(i->errorProc); Jim_IncrRefCount(i->trueObj); Jim_IncrRefCount(i->falseObj); @@ -9812,6 +10294,7 @@ Jim_DecrRefCount(i, i->unknown); Jim_DecrRefCount(i, i->errorFileNameObj); Jim_DecrRefCount(i, i->currentScriptObj); + Jim_DecrRefCount(i, i->nullScriptObj); Jim_FreeHashTable(&i->commands); #ifdef JIM_REFERENCES Jim_FreeHashTable(&i->references); @@ -9819,11 +10302,10 @@ Jim_FreeHashTable(&i->packages); Jim_Free(i->prngState); Jim_FreeHashTable(&i->assocData); - JimDeleteLocalProcs(i); while (cf) { - prevcf = cf->parentCallFrame; + prevcf = cf->parent; JimFreeCallFrame(i, cf, JIM_FCF_NONE); cf = prevcf; } @@ -9835,8 +10317,14 @@ while (objPtr) { const char *type = objPtr->typePtr ? objPtr->typePtr->name : "string"; - printf("%p (%d) %-10s: '%.20s'" JIM_NL, - (void *)objPtr, objPtr->refCount, type, objPtr->bytes ? objPtr->bytes : "(null)"); + if (objPtr->bytes && strlen(objPtr->bytes) > 20) { + printf("%p (%d) %-10s: '%.20s...'" JIM_NL, + (void *)objPtr, objPtr->refCount, type, objPtr->bytes); + } + else { + printf("%p (%d) %-10s: '%s'" JIM_NL, + (void *)objPtr, objPtr->refCount, type, objPtr->bytes ? objPtr->bytes : "(null)"); + } if (objPtr->typePtr == &sourceObjType) { printf("FILE %s LINE %d" JIM_NL, Jim_String(objPtr->internalRep.sourceValue.fileNameObj), @@ -9857,7 +10345,7 @@ cf = i->freeFramesList; while (cf) { - nextcf = cf->nextFramePtr; + nextcf = cf->next; if (cf->vars.table != NULL) Jim_Free(cf->vars.table); Jim_Free(cf); @@ -9882,7 +10370,7 @@ if (str[0] == '#') { char *endptr; - level = strtol(str + 1, &endptr, 0); + level = jim_strtol(str + 1, &endptr); if (str[1] == '\0' || endptr[0] != '\0') { level = -1; } @@ -9907,7 +10395,7 @@ } if (level > 0) { - for (framePtr = interp->framePtr; framePtr; framePtr = framePtr->parentCallFrame) { + for (framePtr = interp->framePtr; framePtr; framePtr = framePtr->parent) { if (framePtr->level == level) { return framePtr; } @@ -9934,7 +10422,7 @@ } - for (framePtr = interp->framePtr; framePtr; framePtr = framePtr->parentCallFrame) { + for (framePtr = interp->framePtr; framePtr; framePtr = framePtr->parent) { if (framePtr->level == level) { return framePtr; } @@ -10050,8 +10538,6 @@ return interp->exitCode; } -#define JIM_INTEGER_SPACE 24 - static void UpdateStringOfInt(struct Jim_Obj *objPtr); static int SetIntFromAny(Jim_Interp *interp, Jim_Obj *objPtr, int flags); @@ -10072,12 +10558,12 @@ }; -void UpdateStringOfInt(struct Jim_Obj *objPtr) +static void UpdateStringOfInt(struct Jim_Obj *objPtr) { int len; char buf[JIM_INTEGER_SPACE + 1]; - len = Jim_WideToString(buf, JimWideValue(objPtr)); + len = JimWideToString(buf, JimWideValue(objPtr)); objPtr->bytes = Jim_Alloc(len + 1); memcpy(objPtr->bytes, buf, len + 1); objPtr->length = len; @@ -10305,15 +10791,13 @@ #define JIM_ELESTR_SIMPLE 0 #define JIM_ELESTR_BRACE 1 #define JIM_ELESTR_QUOTE 2 -static int ListElementQuotingType(const char *s, int len) +static unsigned char ListElementQuotingType(const char *s, int len) { int i, level, blevel, trySimple = 1; if (len == 0) return JIM_ELESTR_BRACE; - if (s[0] == '#') - return JIM_ELESTR_BRACE; if (s[0] == '"' || s[0] == '{') { trySimple = 0; goto testbrace; @@ -10400,11 +10884,10 @@ return JIM_ELESTR_QUOTE; } -static char *BackslashQuoteString(const char *s, int len, int *qlenPtr) +static int BackslashQuoteString(const char *s, char *q) { - char *q = Jim_Alloc(len * 2 + 1), *p; + char *p = q; - p = q; while (*s) { switch (*s) { case ' ': @@ -10450,30 +10933,40 @@ } } *p = '\0'; - *qlenPtr = p - q; - return q; + + return p - q; } -static void UpdateStringOfList(struct Jim_Obj *objPtr) +static void JimMakeListStringRep(Jim_Obj *objPtr, Jim_Obj **objv, int objc) { + #define STATIC_QUOTING_LEN 32 int i, bufLen, realLength; const char *strRep; char *p; - int *quotingType; - Jim_Obj **ele = objPtr->internalRep.listValue.ele; + unsigned char *quotingType, staticQuoting[STATIC_QUOTING_LEN]; - quotingType = Jim_Alloc(sizeof(int) * objPtr->internalRep.listValue.len + 1); + if (objc > STATIC_QUOTING_LEN) { + quotingType = Jim_Alloc(objc); + } + else { + quotingType = staticQuoting; + } bufLen = 0; - for (i = 0; i < objPtr->internalRep.listValue.len; i++) { + for (i = 0; i < objc; i++) { int len; - strRep = Jim_GetString(ele[i], &len); + strRep = Jim_GetString(objv[i], &len); quotingType[i] = ListElementQuotingType(strRep, len); switch (quotingType[i]) { case JIM_ELESTR_SIMPLE: - bufLen += len; - break; + if (i != 0 || strRep[0] != '#') { + bufLen += len; + break; + } + + quotingType[i] = JIM_ELESTR_BRACE; + case JIM_ELESTR_BRACE: bufLen += len + 2; break; @@ -10488,11 +10981,10 @@ p = objPtr->bytes = Jim_Alloc(bufLen + 1); realLength = 0; - for (i = 0; i < objPtr->internalRep.listValue.len; i++) { + for (i = 0; i < objc; i++) { int len, qlen; - char *q; - strRep = Jim_GetString(ele[i], &len); + strRep = Jim_GetString(objv[i], &len); switch (quotingType[i]) { case JIM_ELESTR_SIMPLE: @@ -10508,22 +11000,32 @@ realLength += len + 2; break; case JIM_ELESTR_QUOTE: - q = BackslashQuoteString(strRep, len, &qlen); - memcpy(p, q, qlen); - Jim_Free(q); + if (i == 0 && strRep[0] == '#') { + *p++ = '\\'; + realLength++; + } + qlen = BackslashQuoteString(strRep, p); p += qlen; realLength += qlen; break; } - if (i + 1 != objPtr->internalRep.listValue.len) { + if (i + 1 != objc) { *p++ = ' '; realLength++; } } *p = '\0'; objPtr->length = realLength; - Jim_Free(quotingType); + + if (quotingType != staticQuoting) { + Jim_Free(quotingType); + } +} + +static void UpdateStringOfList(struct Jim_Obj *objPtr) +{ + JimMakeListStringRep(objPtr, objPtr->internalRep.listValue.ele, objPtr->internalRep.listValue.len); } static int SetListFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr) @@ -10534,6 +11036,30 @@ Jim_Obj *fileNameObj; int linenr; + if (objPtr->typePtr == &listObjType) { + return JIM_OK; + } + + if (Jim_IsDict(objPtr) && !Jim_IsShared(objPtr)) { + Jim_Obj **listObjPtrPtr; + int len; + int i; + + listObjPtrPtr = JimDictPairs(objPtr, &len); + for (i = 0; i < len; i++) { + Jim_IncrRefCount(listObjPtrPtr[i]); + } + + + Jim_FreeIntRep(interp, objPtr); + objPtr->typePtr = &listObjType; + objPtr->internalRep.listValue.len = len; + objPtr->internalRep.listValue.maxLen = len; + objPtr->internalRep.listValue.ele = listObjPtrPtr; + + return JIM_OK; + } + if (objPtr->typePtr == &sourceObjType) { fileNameObj = objPtr->internalRep.sourceValue.fileNameObj; @@ -10555,16 +11081,18 @@ objPtr->internalRep.listValue.ele = NULL; - JimParserInit(&parser, str, strLen, linenr); - while (!parser.eof) { - Jim_Obj *elementPtr; + if (strLen) { + JimParserInit(&parser, str, strLen, linenr); + while (!parser.eof) { + Jim_Obj *elementPtr; - JimParseList(&parser); - if (parser.tt != JIM_TT_STR && parser.tt != JIM_TT_ESC) - continue; - elementPtr = JimParserGetTokenObj(interp, &parser); - JimSetSourceInfo(interp, elementPtr, fileNameObj, parser.tline); - ListAppendElement(objPtr, elementPtr); + JimParseList(&parser); + if (parser.tt != JIM_TT_STR && parser.tt != JIM_TT_ESC) + continue; + elementPtr = JimParserGetTokenObj(interp, &parser); + JimSetSourceInfo(interp, elementPtr, fileNameObj, parser.tline); + ListAppendElement(objPtr, elementPtr); + } } Jim_DecrRefCount(interp, fileNameObj); return JIM_OK; @@ -10693,8 +11221,7 @@ int rc; JimPanic((Jim_IsShared(listObjPtr), "Jim_ListSortElements called with shared object")); - if (!Jim_IsList(listObjPtr)) - SetListFromAny(interp, listObjPtr); + SetListFromAny(interp, listObjPtr); prev_info = sort_info; @@ -10743,10 +11270,18 @@ Jim_Obj **point; if (requiredLen > listPtr->internalRep.listValue.maxLen) { - listPtr->internalRep.listValue.maxLen = requiredLen * 2; + if (requiredLen < 2) { + + requiredLen = 4; + } + else { + requiredLen *= 2; + } listPtr->internalRep.listValue.ele = Jim_Realloc(listPtr->internalRep.listValue.ele, - sizeof(Jim_Obj *) * listPtr->internalRep.listValue.maxLen); + sizeof(Jim_Obj *) * requiredLen); + + listPtr->internalRep.listValue.maxLen = requiredLen; } if (idx < 0) { idx = currentLen; @@ -10774,8 +11309,7 @@ void Jim_ListAppendElement(Jim_Interp *interp, Jim_Obj *listPtr, Jim_Obj *objPtr) { JimPanic((Jim_IsShared(listPtr), "Jim_ListAppendElement called with shared object")); - if (!Jim_IsList(listPtr)) - SetListFromAny(interp, listPtr); + SetListFromAny(interp, listPtr); Jim_InvalidateStringRep(listPtr); ListAppendElement(listPtr, objPtr); } @@ -10783,16 +11317,15 @@ void Jim_ListAppendList(Jim_Interp *interp, Jim_Obj *listPtr, Jim_Obj *appendListPtr) { JimPanic((Jim_IsShared(listPtr), "Jim_ListAppendList called with shared object")); - if (!Jim_IsList(listPtr)) - SetListFromAny(interp, listPtr); + SetListFromAny(interp, listPtr); + SetListFromAny(interp, appendListPtr); Jim_InvalidateStringRep(listPtr); ListAppendList(listPtr, appendListPtr); } int Jim_ListLength(Jim_Interp *interp, Jim_Obj *objPtr) { - if (!Jim_IsList(objPtr)) - SetListFromAny(interp, objPtr); + SetListFromAny(interp, objPtr); return objPtr->internalRep.listValue.len; } @@ -10800,8 +11333,7 @@ int objc, Jim_Obj *const *objVec) { JimPanic((Jim_IsShared(listPtr), "Jim_ListInsertElement called with shared object")); - if (!Jim_IsList(listPtr)) - SetListFromAny(interp, listPtr); + SetListFromAny(interp, listPtr); if (idx >= 0 && idx > listPtr->internalRep.listValue.len) idx = listPtr->internalRep.listValue.len; else if (idx < 0) @@ -10810,29 +11342,34 @@ ListInsertElements(listPtr, idx, objc, objVec); } -int Jim_ListIndex(Jim_Interp *interp, Jim_Obj *listPtr, int idx, Jim_Obj **objPtrPtr, int flags) +Jim_Obj *Jim_ListGetIndex(Jim_Interp *interp, Jim_Obj *listPtr, int idx) { - if (!Jim_IsList(listPtr)) - SetListFromAny(interp, listPtr); + SetListFromAny(interp, listPtr); if ((idx >= 0 && idx >= listPtr->internalRep.listValue.len) || (idx < 0 && (-idx - 1) >= listPtr->internalRep.listValue.len)) { + return NULL; + } + if (idx < 0) + idx = listPtr->internalRep.listValue.len + idx; + return listPtr->internalRep.listValue.ele[idx]; +} + +int Jim_ListIndex(Jim_Interp *interp, Jim_Obj *listPtr, int idx, Jim_Obj **objPtrPtr, int flags) +{ + *objPtrPtr = Jim_ListGetIndex(interp, listPtr, idx); + if (*objPtrPtr == NULL) { if (flags & JIM_ERRMSG) { Jim_SetResultString(interp, "list index out of range", -1); } - *objPtrPtr = NULL; return JIM_ERR; } - if (idx < 0) - idx = listPtr->internalRep.listValue.len + idx; - *objPtrPtr = listPtr->internalRep.listValue.ele[idx]; return JIM_OK; } static int ListSetIndex(Jim_Interp *interp, Jim_Obj *listPtr, int idx, Jim_Obj *newObjPtr, int flags) { - if (!Jim_IsList(listPtr)) - SetListFromAny(interp, listPtr); + SetListFromAny(interp, listPtr); if ((idx >= 0 && idx >= listPtr->internalRep.listValue.len) || (idx < 0 && (-idx - 1) >= listPtr->internalRep.listValue.len)) { if (flags & JIM_ERRMSG) { @@ -10889,6 +11426,24 @@ return JIM_ERR; } +Jim_Obj *Jim_ListJoin(Jim_Interp *interp, Jim_Obj *listObjPtr, const char *joinStr, int joinStrLen) +{ + int i; + int listLen = Jim_ListLength(interp, listObjPtr); + Jim_Obj *resObjPtr = Jim_NewEmptyStringObj(interp); + + for (i = 0; i < listLen; ) { + Jim_Obj *objPtr; + + Jim_ListIndex(interp, listObjPtr, i, &objPtr, JIM_NONE); + Jim_AppendObj(interp, resObjPtr, objPtr); + if (++i != listLen) { + Jim_AppendString(interp, resObjPtr, joinStr, joinStrLen); + } + } + return resObjPtr; +} + Jim_Obj *Jim_ConcatObj(Jim_Interp *interp, int objc, Jim_Obj *const *objv) { int i; @@ -10963,7 +11518,7 @@ len = Jim_ListLength(interp, listObjPtr); first = JimRelToAbsIndex(len, first); last = JimRelToAbsIndex(len, last); - JimRelToAbsRange(len, first, last, &first, &last, &rangeLen); + JimRelToAbsRange(len, &first, &last, &rangeLen); if (first == 0 && last == len) { return listObjPtr; } @@ -10978,26 +11533,19 @@ static unsigned int JimObjectHTHashFunction(const void *key) { - const char *str; - Jim_Obj *objPtr = (Jim_Obj *)key; int len; - - str = Jim_GetString(objPtr, &len); - return Jim_GenHashFunction((unsigned char *)str, 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) { - JIM_NOTUSED(privdata); - return Jim_StringEqObj((Jim_Obj *)key1, (Jim_Obj *)key2); } static void JimObjectHTKeyValDestructor(void *interp, void *val) { - Jim_Obj *objPtr = val; - - Jim_DecrRefCount(interp, objPtr); + Jim_DecrRefCount(interp, (Jim_Obj *)val); } static const Jim_HashTableType JimDictHashTableType = { @@ -11005,8 +11553,7 @@ NULL, NULL, JimObjectHTKeyCompare, - (void (*)(void *, const void *)) - JimObjectHTKeyValDestructor, + JimObjectHTKeyValDestructor, JimObjectHTKeyValDestructor }; @@ -11029,7 +11576,7 @@ void DupDictInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr) { Jim_HashTable *ht, *dupHt; - Jim_HashTableIterator *htiter; + Jim_HashTableIterator htiter; Jim_HashEntry *he; @@ -11039,8 +11586,8 @@ if (ht->size != 0) Jim_ExpandHashTable(dupHt, ht->size); - htiter = Jim_GetHashTableIterator(ht); - while ((he = Jim_NextHashEntry(htiter)) != NULL) { + JimInitHashTableIterator(ht, &htiter); + while ((he = Jim_NextHashEntry(&htiter)) != NULL) { const Jim_Obj *keyObjPtr = he->key; Jim_Obj *valObjPtr = he->u.val; @@ -11048,96 +11595,41 @@ Jim_IncrRefCount(valObjPtr); Jim_AddHashEntry(dupHt, keyObjPtr, valObjPtr); } - Jim_FreeHashTableIterator(htiter); dupPtr->internalRep.ptr = dupHt; dupPtr->typePtr = &dictObjType; -} - -void UpdateStringOfDict(struct Jim_Obj *objPtr) -{ - int i, bufLen, realLength; - const char *strRep; - char *p; - int *quotingType, objc; - Jim_HashTable *ht; - Jim_HashTableIterator *htiter; - Jim_HashEntry *he; - Jim_Obj **objv; - - - ht = objPtr->internalRep.ptr; - objc = ht->used * 2; - objv = Jim_Alloc(objc * sizeof(Jim_Obj *)); - htiter = Jim_GetHashTableIterator(ht); - i = 0; - while ((he = Jim_NextHashEntry(htiter)) != NULL) { - objv[i++] = (Jim_Obj *)he->key; - objv[i++] = he->u.val; - } - Jim_FreeHashTableIterator(htiter); - - quotingType = Jim_Alloc(sizeof(int) * objc); - bufLen = 0; - for (i = 0; i < objc; i++) { - int len; - - strRep = Jim_GetString(objv[i], &len); - quotingType[i] = ListElementQuotingType(strRep, len); - switch (quotingType[i]) { - case JIM_ELESTR_SIMPLE: - bufLen += len; - break; - case JIM_ELESTR_BRACE: - bufLen += len + 2; - break; - case JIM_ELESTR_QUOTE: - bufLen += len * 2; - break; - } - bufLen++; +} + +static Jim_Obj **JimDictPairs(Jim_Obj *dictPtr, int *len) +{ + Jim_HashTable *ht; + Jim_HashTableIterator htiter; + Jim_HashEntry *he; + Jim_Obj **objv; + int i; + + ht = dictPtr->internalRep.ptr; + + + objv = Jim_Alloc((ht->used * 2) * sizeof(Jim_Obj *)); + JimInitHashTableIterator(ht, &htiter); + i = 0; + while ((he = Jim_NextHashEntry(&htiter)) != NULL) { + objv[i++] = (Jim_Obj *)he->key; + objv[i++] = he->u.val; } - bufLen++; + *len = i; + return objv; +} +static void UpdateStringOfDict(struct Jim_Obj *objPtr) +{ - p = objPtr->bytes = Jim_Alloc(bufLen + 1); - realLength = 0; - for (i = 0; i < objc; i++) { - int len, qlen; - char *q; + int len; + Jim_Obj **objv = JimDictPairs(objPtr, &len); - strRep = Jim_GetString(objv[i], &len); + JimMakeListStringRep(objPtr, objv, len); - switch (quotingType[i]) { - case JIM_ELESTR_SIMPLE: - memcpy(p, strRep, len); - p += len; - realLength += len; - break; - case JIM_ELESTR_BRACE: - *p++ = '{'; - memcpy(p, strRep, len); - p += len; - *p++ = '}'; - realLength += len + 2; - break; - case JIM_ELESTR_QUOTE: - q = BackslashQuoteString(strRep, len, &qlen); - memcpy(p, q, qlen); - Jim_Free(q); - p += qlen; - realLength += qlen; - break; - } - - if (i + 1 != objc) { - *p++ = ' '; - realLength++; - } - } - *p = '\0'; - objPtr->length = realLength; - Jim_Free(quotingType); Jim_Free(objv); } @@ -11145,13 +11637,16 @@ { int listlen; + if (objPtr->typePtr == &dictObjType) { + return JIM_OK; + } + Jim_String(objPtr); listlen = Jim_ListLength(interp, objPtr); if (listlen % 2) { - Jim_SetResultString(interp, - "invalid dictionary value: must be a list with an even number of elements", -1); + Jim_SetResultString(interp, "missing value to go with key", -1); return JIM_ERR; } else { @@ -11203,13 +11698,9 @@ } Jim_IncrRefCount(keyObjPtr); Jim_IncrRefCount(valueObjPtr); - if (Jim_AddHashEntry(ht, keyObjPtr, valueObjPtr) != JIM_OK) { - Jim_HashEntry *he = Jim_FindHashEntry(ht, keyObjPtr); - - Jim_DecrRefCount(interp, keyObjPtr); + if (Jim_ReplaceHashEntry(ht, keyObjPtr, valueObjPtr)) { - Jim_DecrRefCount(interp, (Jim_Obj *)he->u.val); - he->u.val = valueObjPtr; + Jim_DecrRefCount(interp, keyObjPtr); } return JIM_OK; } @@ -11220,9 +11711,8 @@ int retcode; JimPanic((Jim_IsShared(objPtr), "Jim_DictAddElement called with shared object")); - if (objPtr->typePtr != &dictObjType) { - if (SetDictFromAny(interp, objPtr) != JIM_OK) - return JIM_ERR; + if (SetDictFromAny(interp, objPtr) != JIM_OK) { + return JIM_ERR; } retcode = DictAddElement(interp, objPtr, keyObjPtr, valueObjPtr); Jim_InvalidateStringRep(objPtr); @@ -11252,14 +11742,13 @@ Jim_HashEntry *he; Jim_HashTable *ht; - if (dictPtr->typePtr != &dictObjType) { - if (SetDictFromAny(interp, dictPtr) != JIM_OK) - return -1; + if (SetDictFromAny(interp, dictPtr) != JIM_OK) { + return -1; } ht = dictPtr->internalRep.ptr; if ((he = Jim_FindHashEntry(ht, keyPtr)) == NULL) { if (flags & JIM_ERRMSG) { - Jim_SetResultFormatted(interp, "key \"%#s\" not found in dictionary", keyPtr); + Jim_SetResultFormatted(interp, "key \"%#s\" not known in dictionary", keyPtr); } return JIM_ERR; } @@ -11270,29 +11759,11 @@ int Jim_DictPairs(Jim_Interp *interp, Jim_Obj *dictPtr, Jim_Obj ***objPtrPtr, int *len) { - Jim_HashTable *ht; - Jim_HashTableIterator *htiter; - Jim_HashEntry *he; - Jim_Obj **objv; - int i; - - if (dictPtr->typePtr != &dictObjType) { - if (SetDictFromAny(interp, dictPtr) != JIM_OK) - return JIM_ERR; + if (SetDictFromAny(interp, dictPtr) != JIM_OK) { + return JIM_ERR; } - ht = dictPtr->internalRep.ptr; + *objPtrPtr = JimDictPairs(dictPtr, len); - - objv = Jim_Alloc((ht->used * 2) * sizeof(Jim_Obj *)); - htiter = Jim_GetHashTableIterator(ht); - i = 0; - while ((he = Jim_NextHashEntry(htiter)) != NULL) { - objv[i++] = (Jim_Obj *)he->key; - objv[i++] = he->u.val; - } - *len = i; - Jim_FreeHashTableIterator(htiter); - *objPtrPtr = objv; return JIM_OK; } @@ -11311,9 +11782,10 @@ for (i = 0; i < keyc; i++) { Jim_Obj *objPtr; - if (Jim_DictKey(interp, dictPtr, keyv[i], &objPtr, flags) - != JIM_OK) - return JIM_ERR; + int rc = Jim_DictKey(interp, dictPtr, keyv[i], &objPtr, flags); + if (rc != JIM_OK) { + return rc; + } dictPtr = objPtr; } *objPtrPtr = dictPtr; @@ -11326,10 +11798,10 @@ Jim_Obj *varObjPtr, *objPtr, *dictObjPtr; int shared, i; - varObjPtr = objPtr = - Jim_GetVariable(interp, varNamePtr, newObjPtr == NULL ? JIM_ERRMSG : JIM_NONE); + varObjPtr = objPtr = Jim_GetVariable(interp, varNamePtr, flags); if (objPtr == NULL) { - if (newObjPtr == NULL) { + if (newObjPtr == NULL && (flags & JIM_MUSTEXIST)) { + return JIM_ERR; } varObjPtr = objPtr = Jim_NewDictObj(interp, NULL, 0); @@ -11340,15 +11812,24 @@ } if ((shared = Jim_IsShared(objPtr))) varObjPtr = objPtr = Jim_DuplicateObj(interp, objPtr); - for (i = 0; i < keyc - 1; i++) { + for (i = 0; i < keyc; i++) { dictObjPtr = objPtr; - if (dictObjPtr->typePtr != &dictObjType) { - if (SetDictFromAny(interp, dictObjPtr) != JIM_OK) { - goto err; + if (SetDictFromAny(interp, dictObjPtr) != JIM_OK) { + goto err; + } + + if (i == keyc - 1) { + + if (Jim_DictAddElement(interp, objPtr, keyv[keyc - 1], newObjPtr) != JIM_OK) { + if (newObjPtr || (flags & JIM_MUSTEXIST)) { + goto err; + } } + break; } + Jim_InvalidateStringRep(dictObjPtr); if (Jim_DictKey(interp, dictObjPtr, keyv[i], &objPtr, @@ -11366,12 +11847,6 @@ DictAddElement(interp, dictObjPtr, keyv[i], objPtr); } } - - if (Jim_DictAddElement(interp, objPtr, keyv[keyc - 1], newObjPtr) != JIM_OK) { - if (newObjPtr || (flags & JIM_ERRMSG)) { - goto err; - } - } Jim_InvalidateStringRep(objPtr); Jim_InvalidateStringRep(varObjPtr); if (Jim_SetVariable(interp, varNamePtr, varObjPtr) != JIM_OK) { @@ -11402,12 +11877,12 @@ int len; char buf[JIM_INTEGER_SPACE + 1]; - if (objPtr->internalRep.indexValue >= 0) - len = sprintf(buf, "%d", objPtr->internalRep.indexValue); - else if (objPtr->internalRep.indexValue == -1) + if (objPtr->internalRep.intValue >= 0) + len = sprintf(buf, "%d", objPtr->internalRep.intValue); + else if (objPtr->internalRep.intValue == -1) len = sprintf(buf, "end"); else { - len = sprintf(buf, "end%d", objPtr->internalRep.indexValue + 1); + len = sprintf(buf, "end%d", objPtr->internalRep.intValue + 1); } objPtr->bytes = Jim_Alloc(len + 1); memcpy(objPtr->bytes, buf, len + 1); @@ -11430,7 +11905,7 @@ idx = 0; } else { - idx = strtol(str, &endptr, 10); + idx = jim_strtol(str, &endptr); if (endptr == str) { goto badindex; @@ -11442,7 +11917,7 @@ if (*str == '+' || *str == '-') { int sign = (*str == '+' ? 1 : -1); - idx += sign * strtol(++str, &endptr, 10); + idx += sign * jim_strtol(++str, &endptr); if (str == endptr || *endptr) { goto badindex; } @@ -11471,7 +11946,7 @@ Jim_FreeIntRep(interp, objPtr); objPtr->typePtr = &indexObjType; - objPtr->internalRep.indexValue = idx; + objPtr->internalRep.intValue = idx; return JIM_OK; badindex: @@ -11493,7 +11968,7 @@ } if (objPtr->typePtr != &indexObjType && SetIndexFromAny(interp, objPtr) == JIM_ERR) return JIM_ERR; - *indexPtr = objPtr->internalRep.indexValue; + *indexPtr = objPtr->internalRep.intValue; return JIM_OK; } @@ -11548,7 +12023,7 @@ Jim_FreeIntRep(interp, objPtr); objPtr->typePtr = &returnCodeObjType; - objPtr->internalRep.returnCode = returnCode; + objPtr->internalRep.intValue = returnCode; return JIM_OK; } @@ -11556,7 +12031,7 @@ { if (objPtr->typePtr != &returnCodeObjType && SetReturnCodeFromAny(interp, objPtr) == JIM_ERR) return JIM_ERR; - *intPtr = objPtr->internalRep.returnCode; + *intPtr = objPtr->internalRep.intValue; return JIM_OK; } @@ -11665,10 +12140,11 @@ typedef struct Jim_ExprOperator { const char *name; - int precedence; - int arity; int (*funcop) (Jim_Interp *interp, struct JimExprState * e); - int lazy; + unsigned char precedence; + unsigned char arity; + unsigned char lazy; + unsigned char namelen; } Jim_ExprOperator; static void ExprPush(struct JimExprState *e, Jim_Obj *obj) @@ -12350,89 +12826,92 @@ LAZY_RIGHT }; +#define OPRINIT(N, P, A, F, L) {N, F, P, A, L, sizeof(N) - 1} + static const struct Jim_ExprOperator Jim_ExprOperators[] = { - {"*", 200, 2, JimExprOpBin, LAZY_NONE}, - {"/", 200, 2, JimExprOpBin, LAZY_NONE}, - {"%", 200, 2, JimExprOpIntBin, LAZY_NONE}, + OPRINIT("*", 110, 2, JimExprOpBin, LAZY_NONE), + OPRINIT("/", 110, 2, JimExprOpBin, LAZY_NONE), + OPRINIT("%", 110, 2, JimExprOpIntBin, LAZY_NONE), - {"-", 100, 2, JimExprOpBin, LAZY_NONE}, - {"+", 100, 2, JimExprOpBin, LAZY_NONE}, + OPRINIT("-", 100, 2, JimExprOpBin, LAZY_NONE), + OPRINIT("+", 100, 2, JimExprOpBin, LAZY_NONE), - {"<<", 90, 2, JimExprOpIntBin, LAZY_NONE}, - {">>", 90, 2, JimExprOpIntBin, LAZY_NONE}, + OPRINIT("<<", 90, 2, JimExprOpIntBin, LAZY_NONE), + OPRINIT(">>", 90, 2, JimExprOpIntBin, LAZY_NONE), - {"<<<", 90, 2, JimExprOpIntBin, LAZY_NONE}, - {">>>", 90, 2, JimExprOpIntBin, LAZY_NONE}, + OPRINIT("<<<", 90, 2, JimExprOpIntBin, LAZY_NONE), + OPRINIT(">>>", 90, 2, JimExprOpIntBin, LAZY_NONE), - {"<", 80, 2, JimExprOpBin, LAZY_NONE}, - {">", 80, 2, JimExprOpBin, LAZY_NONE}, - {"<=", 80, 2, JimExprOpBin, LAZY_NONE}, - {">=", 80, 2, JimExprOpBin, LAZY_NONE}, + OPRINIT("<", 80, 2, JimExprOpBin, LAZY_NONE), + OPRINIT(">", 80, 2, JimExprOpBin, LAZY_NONE), + OPRINIT("<=", 80, 2, JimExprOpBin, LAZY_NONE), + OPRINIT(">=", 80, 2, JimExprOpBin, LAZY_NONE), - {"==", 70, 2, JimExprOpBin, LAZY_NONE}, - {"!=", 70, 2, JimExprOpBin, LAZY_NONE}, + OPRINIT("==", 70, 2, JimExprOpBin, LAZY_NONE), + OPRINIT("!=", 70, 2, JimExprOpBin, LAZY_NONE), - {"&", 50, 2, JimExprOpIntBin, LAZY_NONE}, - {"^", 49, 2, JimExprOpIntBin, LAZY_NONE}, - {"|", 48, 2, JimExprOpIntBin, LAZY_NONE}, + OPRINIT("&", 50, 2, JimExprOpIntBin, LAZY_NONE), + OPRINIT("^", 49, 2, JimExprOpIntBin, LAZY_NONE), + OPRINIT("|", 48, 2, JimExprOpIntBin, LAZY_NONE), - {"&&", 10, 2, NULL, LAZY_OP}, - {NULL, 10, 2, JimExprOpAndLeft, LAZY_LEFT}, - {NULL, 10, 2, JimExprOpAndOrRight, LAZY_RIGHT}, + OPRINIT("&&", 10, 2, NULL, LAZY_OP), + OPRINIT(NULL, 10, 2, JimExprOpAndLeft, LAZY_LEFT), + OPRINIT(NULL, 10, 2, JimExprOpAndOrRight, LAZY_RIGHT), - {"||", 9, 2, NULL, LAZY_OP}, - {NULL, 9, 2, JimExprOpOrLeft, LAZY_LEFT}, - {NULL, 9, 2, JimExprOpAndOrRight, LAZY_RIGHT}, + OPRINIT("||", 9, 2, NULL, LAZY_OP), + OPRINIT(NULL, 9, 2, JimExprOpOrLeft, LAZY_LEFT), + OPRINIT(NULL, 9, 2, JimExprOpAndOrRight, LAZY_RIGHT), - {"?", 5, 2, JimExprOpNull, LAZY_OP}, - {NULL, 5, 2, JimExprOpTernaryLeft, LAZY_LEFT}, - {NULL, 5, 2, JimExprOpNull, LAZY_RIGHT}, + OPRINIT("?", 5, 2, JimExprOpNull, LAZY_OP), + OPRINIT(NULL, 5, 2, JimExprOpTernaryLeft, LAZY_LEFT), + OPRINIT(NULL, 5, 2, JimExprOpNull, LAZY_RIGHT), - {":", 5, 2, JimExprOpNull, LAZY_OP}, - {NULL, 5, 2, JimExprOpColonLeft, LAZY_LEFT}, - {NULL, 5, 2, JimExprOpNull, LAZY_RIGHT}, + OPRINIT(":", 5, 2, JimExprOpNull, LAZY_OP), + OPRINIT(NULL, 5, 2, JimExprOpColonLeft, LAZY_LEFT), + OPRINIT(NULL, 5, 2, JimExprOpNull, LAZY_RIGHT), - {"**", 250, 2, JimExprOpBin, LAZY_NONE}, + OPRINIT("**", 250, 2, JimExprOpBin, LAZY_NONE), - {"eq", 60, 2, JimExprOpStrBin, LAZY_NONE}, - {"ne", 60, 2, JimExprOpStrBin, LAZY_NONE}, + OPRINIT("eq", 60, 2, JimExprOpStrBin, LAZY_NONE), + OPRINIT("ne", 60, 2, JimExprOpStrBin, LAZY_NONE), - {"in", 55, 2, JimExprOpStrBin, LAZY_NONE}, - {"ni", 55, 2, JimExprOpStrBin, LAZY_NONE}, + OPRINIT("in", 55, 2, JimExprOpStrBin, LAZY_NONE), + OPRINIT("ni", 55, 2, JimExprOpStrBin, LAZY_NONE), - {"!", 300, 1, JimExprOpNumUnary, LAZY_NONE}, - {"~", 300, 1, JimExprOpIntUnary, LAZY_NONE}, - {NULL, 300, 1, JimExprOpNumUnary, LAZY_NONE}, - {NULL, 300, 1, JimExprOpNumUnary, LAZY_NONE}, + OPRINIT("!", 150, 1, JimExprOpNumUnary, LAZY_NONE), + OPRINIT("~", 150, 1, JimExprOpIntUnary, LAZY_NONE), + OPRINIT(NULL, 150, 1, JimExprOpNumUnary, LAZY_NONE), + OPRINIT(NULL, 150, 1, JimExprOpNumUnary, LAZY_NONE), - {"int", 400, 1, JimExprOpNumUnary, LAZY_NONE}, - {"abs", 400, 1, JimExprOpNumUnary, LAZY_NONE}, - {"double", 400, 1, JimExprOpNumUnary, LAZY_NONE}, - {"round", 400, 1, JimExprOpNumUnary, LAZY_NONE}, - {"rand", 400, 0, JimExprOpNone, LAZY_NONE}, - {"srand", 400, 1, JimExprOpIntUnary, LAZY_NONE}, + OPRINIT("int", 200, 1, JimExprOpNumUnary, LAZY_NONE), + OPRINIT("abs", 200, 1, JimExprOpNumUnary, LAZY_NONE), + OPRINIT("double", 200, 1, JimExprOpNumUnary, LAZY_NONE), + OPRINIT("round", 200, 1, JimExprOpNumUnary, LAZY_NONE), + OPRINIT("rand", 200, 0, JimExprOpNone, LAZY_NONE), + OPRINIT("srand", 200, 1, JimExprOpIntUnary, LAZY_NONE), #ifdef JIM_MATH_FUNCTIONS - {"sin", 400, 1, JimExprOpDoubleUnary, LAZY_NONE}, - {"cos", 400, 1, JimExprOpDoubleUnary, LAZY_NONE}, - {"tan", 400, 1, JimExprOpDoubleUnary, LAZY_NONE}, - {"asin", 400, 1, JimExprOpDoubleUnary, LAZY_NONE}, - {"acos", 400, 1, JimExprOpDoubleUnary, LAZY_NONE}, - {"atan", 400, 1, JimExprOpDoubleUnary, LAZY_NONE}, - {"sinh", 400, 1, JimExprOpDoubleUnary, LAZY_NONE}, - {"cosh", 400, 1, JimExprOpDoubleUnary, LAZY_NONE}, - {"tanh", 400, 1, JimExprOpDoubleUnary, LAZY_NONE}, - {"ceil", 400, 1, JimExprOpDoubleUnary, LAZY_NONE}, - {"floor", 400, 1, JimExprOpDoubleUnary, LAZY_NONE}, - {"exp", 400, 1, JimExprOpDoubleUnary, LAZY_NONE}, - {"log", 400, 1, JimExprOpDoubleUnary, LAZY_NONE}, - {"log10", 400, 1, JimExprOpDoubleUnary, LAZY_NONE}, - {"sqrt", 400, 1, JimExprOpDoubleUnary, LAZY_NONE}, - {"pow", 400, 2, JimExprOpBin, LAZY_NONE}, + OPRINIT("sin", 200, 1, JimExprOpDoubleUnary, LAZY_NONE), + OPRINIT("cos", 200, 1, JimExprOpDoubleUnary, LAZY_NONE), + OPRINIT("tan", 200, 1, JimExprOpDoubleUnary, LAZY_NONE), + OPRINIT("asin", 200, 1, JimExprOpDoubleUnary, LAZY_NONE), + OPRINIT("acos", 200, 1, JimExprOpDoubleUnary, LAZY_NONE), + OPRINIT("atan", 200, 1, JimExprOpDoubleUnary, LAZY_NONE), + OPRINIT("sinh", 200, 1, JimExprOpDoubleUnary, LAZY_NONE), + OPRINIT("cosh", 200, 1, JimExprOpDoubleUnary, LAZY_NONE), + OPRINIT("tanh", 200, 1, JimExprOpDoubleUnary, LAZY_NONE), + OPRINIT("ceil", 200, 1, JimExprOpDoubleUnary, LAZY_NONE), + OPRINIT("floor", 200, 1, JimExprOpDoubleUnary, LAZY_NONE), + OPRINIT("exp", 200, 1, JimExprOpDoubleUnary, LAZY_NONE), + OPRINIT("log", 200, 1, JimExprOpDoubleUnary, LAZY_NONE), + OPRINIT("log10", 200, 1, JimExprOpDoubleUnary, LAZY_NONE), + OPRINIT("sqrt", 200, 1, JimExprOpDoubleUnary, LAZY_NONE), + OPRINIT("pow", 200, 2, JimExprOpBin, LAZY_NONE), #endif }; +#undef OPRINIT #define JIM_EXPR_OPERATORS_NUM \ (sizeof(Jim_ExprOperators)/sizeof(struct Jim_ExprOperator)) @@ -12517,28 +12996,53 @@ static int JimParseExprNumber(struct JimParserCtx *pc) { int allowdot = 1; - int allowhex = 0; + int base = 10; pc->tt = JIM_TT_EXPR_INT; pc->tstart = pc->p; pc->tline = pc->linenr; + + + if (pc->p[0] == '0') { + switch (pc->p[1]) { + case 'x': + case 'X': + base = 16; + allowdot = 0; + pc->p += 2; + pc->len -= 2; + break; + case 'o': + case 'O': + base = 8; + allowdot = 0; + pc->p += 2; + pc->len -= 2; + break; + case 'b': + case 'B': + base = 2; + allowdot = 0; + pc->p += 2; + pc->len -= 2; + break; + } + } + while (isdigit(UCHAR(*pc->p)) - || (allowhex && isxdigit(UCHAR(*pc->p))) + || (base == 16 && isxdigit(UCHAR(*pc->p))) + || (base == 8 && *pc->p >= '0' && *pc->p <= '7') + || (base == 2 && (*pc->p == '0' || *pc->p == '1')) || (allowdot && *pc->p == '.') - || (pc->p - pc->tstart == 1 && *pc->tstart == '0' && (*pc->p == 'x' || *pc->p == 'X')) ) { - if ((*pc->p == 'x') || (*pc->p == 'X')) { - allowhex = 1; - allowdot = 0; - } if (*pc->p == '.') { allowdot = 0; pc->tt = JIM_TT_EXPR_DOUBLE; } pc->p++; pc->len--; - if (!allowhex && (*pc->p == 'e' || *pc->p == 'E') && (pc->p[1] == '-' || pc->p[1] == '+' + if (base == 10 && (*pc->p == 'e' || *pc->p == 'E') && (pc->p[1] == '-' || pc->p[1] == '+' || isdigit(UCHAR(pc->p[1])))) { pc->p += 2; pc->len -= 2; @@ -12577,16 +13081,14 @@ for (i = 0; i < (signed)JIM_EXPR_OPERATORS_NUM; i++) { - const char *opname; - int oplen; + const char * const opname = Jim_ExprOperators[i].name; + const int oplen = Jim_ExprOperators[i].namelen; - opname = Jim_ExprOperators[i].name; - if (opname == NULL) { + if (opname == NULL || opname[0] != pc->p[0]) { continue; } - oplen = strlen(opname); - if (strncmp(opname, pc->p, oplen) == 0 && oplen > bestLen) { + if (oplen > bestLen && strncmp(opname, pc->p, oplen) == 0) { bestIdx = i + JIM_TT_EXPR_OP; bestLen = oplen; } @@ -12662,8 +13164,8 @@ typedef struct ExprByteCode { - int len; ScriptToken *token; + int len; int inUse; } ExprByteCode; @@ -12931,8 +13433,9 @@ case JIM_TT_DICTSUGAR: case JIM_TT_EXPRSUGAR: case JIM_TT_CMD: - token->objPtr = Jim_NewStringObj(interp, t->token, t->len); token->type = t->type; +strexpr: + token->objPtr = Jim_NewStringObj(interp, t->token, t->len); if (t->type == JIM_TT_CMD) { JimSetSourceInfo(interp, token->objPtr, fileNameObj, t->line); @@ -12941,15 +13444,24 @@ break; case JIM_TT_EXPR_INT: - token->objPtr = Jim_NewIntObj(interp, strtoull(t->token, NULL, 0)); - token->type = t->type; - expr->len++; - break; - case JIM_TT_EXPR_DOUBLE: - token->objPtr = Jim_NewDoubleObj(interp, strtod(t->token, NULL)); - token->type = t->type; - expr->len++; + { + char *endptr; + if (t->type == JIM_TT_EXPR_INT) { + token->objPtr = Jim_NewIntObj(interp, jim_strtoull(t->token, &endptr)); + } + else { + token->objPtr = Jim_NewDoubleObj(interp, strtod(t->token, &endptr)); + } + if (endptr != t->token + t->len) { + + Jim_FreeNewObj(interp, token->objPtr); + token->type = JIM_TT_STR; + goto strexpr; + } + token->type = t->type; + expr->len++; + } break; case JIM_TT_SUBEXPR_START: @@ -13396,12 +13908,12 @@ typedef struct ScanFmtPartDescr { - char type; - char modifier; - size_t width; - int pos; char *arg; char *prefix; + size_t width; + int pos; + char type; + char modifier; } ScanFmtPartDescr; @@ -13732,9 +14244,11 @@ : descr->type == 'x' ? 16 : descr->type == 'i' ? 0 : 10; - w = strtoull(tok, &endp, base); - if (endp == tok && base == 0) { - w = strtoull(tok, &endp, 10); + if (base == 0) { + w = jim_strtoull(tok, &endp); + } + else { + w = strtoull(tok, &endp, base); } if (endp != tok) { @@ -13982,101 +14496,97 @@ #define JIM_EVAL_SINTV_LEN 8 -static int JimUnknown(Jim_Interp *interp, int argc, Jim_Obj *const *argv, Jim_Obj *fileNameObj, - int linenr) +static int JimUnknown(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { - Jim_Obj **v, *sv[JIM_EVAL_SARGV_LEN]; - int retCode; + int retcode; if (interp->unknown_called > 50) { return JIM_ERR; } + + if (Jim_GetCommand(interp, interp->unknown, JIM_NONE) == NULL) return JIM_ERR; - if (argc + 1 <= JIM_EVAL_SARGV_LEN) - v = sv; - else - v = Jim_Alloc(sizeof(Jim_Obj *) * (argc + 1)); - memcpy(v + 1, argv, sizeof(Jim_Obj *) * argc); - v[0] = interp->unknown; - interp->unknown_called++; - retCode = JimEvalObjVector(interp, argc + 1, v, fileNameObj, linenr); + + retcode = Jim_EvalObjPrefix(interp, interp->unknown, argc, argv); interp->unknown_called--; - - if (v != sv) - Jim_Free(v); - return retCode; + return retcode; } -static int JimEvalObjVector(Jim_Interp *interp, int objc, Jim_Obj *const *objv, - Jim_Obj *fileNameObj, int linenr) +static int JimInvokeCommand(Jim_Interp *interp, int objc, Jim_Obj *const *objv) { - int i, retcode; - Jim_Cmd *cmdPtr; + int retcode; + Jim_Cmd *cmdPtr = Jim_GetCommand(interp, objv[0], JIM_ERRMSG); - - for (i = 0; i < objc; i++) - Jim_IncrRefCount(objv[i]); - - cmdPtr = Jim_GetCommand(interp, objv[0], JIM_ERRMSG); if (cmdPtr == NULL) { - retcode = JimUnknown(interp, objc, objv, fileNameObj, linenr); + return JimUnknown(interp, objc, objv); } - else { - - JimIncrCmdRefCount(cmdPtr); - Jim_SetEmptyResult(interp); - if (cmdPtr->isproc) { - retcode = JimCallProcedure(interp, cmdPtr, fileNameObj, linenr, objc, objv); - } - else { - interp->cmdPrivData = cmdPtr->u.native.privData; - retcode = cmdPtr->u.native.cmdProc(interp, objc, objv); - } - JimDecrCmdRefCount(interp, cmdPtr); + if (interp->evalDepth == interp->maxEvalDepth) { + Jim_SetResultString(interp, "Infinite eval recursion", -1); + return JIM_ERR; } + interp->evalDepth++; + - for (i = 0; i < objc; i++) - Jim_DecrRefCount(interp, objv[i]); + JimIncrCmdRefCount(cmdPtr); + Jim_SetEmptyResult(interp); + if (cmdPtr->isproc) { + retcode = JimCallProcedure(interp, cmdPtr, objc, objv); + } + else { + interp->cmdPrivData = cmdPtr->u.native.privData; + retcode = cmdPtr->u.native.cmdProc(interp, objc, objv); + } + JimDecrCmdRefCount(interp, cmdPtr); + interp->evalDepth--; return retcode; } int Jim_EvalObjVector(Jim_Interp *interp, int objc, Jim_Obj *const *objv) { - return JimEvalObjVector(interp, objc, objv, interp->emptyObj, 1); + int i, retcode; + + + for (i = 0; i < objc; i++) + Jim_IncrRefCount(objv[i]); + + retcode = JimInvokeCommand(interp, objc, objv); + + + for (i = 0; i < objc; i++) + Jim_DecrRefCount(interp, objv[i]); + + return retcode; } int Jim_EvalObjPrefix(Jim_Interp *interp, Jim_Obj *prefix, int objc, Jim_Obj *const *objv) { - int i; int ret; Jim_Obj **nargv = Jim_Alloc((objc + 1) * sizeof(*nargv)); nargv[0] = prefix; - for (i = 0; i < objc; i++) { - nargv[i + 1] = objv[i]; - } + memcpy(&nargv[1], &objv[0], sizeof(nargv[0]) * objc); ret = Jim_EvalObjVector(interp, objc + 1, nargv); Jim_Free(nargv); return ret; } -static void JimAddErrorToStack(Jim_Interp *interp, int retcode, Jim_Obj *fileNameObj, int line) +static void JimAddErrorToStack(Jim_Interp *interp, int retcode, ScriptObj *script) { int rc = retcode; if (rc == JIM_ERR && !interp->errorFlag) { interp->errorFlag = 1; - Jim_IncrRefCount(fileNameObj); + Jim_IncrRefCount(script->fileNameObj); Jim_DecrRefCount(interp, interp->errorFileNameObj); - interp->errorFileNameObj = fileNameObj; - interp->errorLine = line; + interp->errorFileNameObj = script->fileNameObj; + interp->errorLine = script->linenr; JimResetStackTrace(interp); @@ -14087,9 +14597,9 @@ if (rc == JIM_ERR && interp->addStackTrace > 0) { - JimAppendStackTrace(interp, Jim_String(interp->errorProc), fileNameObj, line); + JimAppendStackTrace(interp, Jim_String(interp->errorProc), script->fileNameObj, script->linenr); - if (Jim_Length(fileNameObj)) { + if (Jim_Length(script->fileNameObj)) { interp->addStackTrace = 0; } @@ -14105,39 +14615,6 @@ } } - -static void JimDeleteLocalProcs(Jim_Interp *interp) -{ - if (interp->localProcs) { - char *procname; - - while ((procname = Jim_StackPop(interp->localProcs)) != NULL) { - - Jim_Cmd *prevCmd = NULL; - Jim_HashEntry *he = Jim_FindHashEntry(&interp->commands, procname); - if (he) { - Jim_Cmd *cmd = (Jim_Cmd *)he->u.val; - if (cmd->isproc && cmd->u.proc.prevCmd) { - prevCmd = cmd->u.proc.prevCmd; - cmd->u.proc.prevCmd = NULL; - } - } - - - Jim_DeleteCommand(interp, procname); - - if (prevCmd) { - - Jim_AddHashEntry(&interp->commands, procname, prevCmd); - } - Jim_Free(procname); - } - Jim_FreeStack(interp->localProcs); - Jim_Free(interp->localProcs); - interp->localProcs = NULL; - } -} - static int JimSubstOneToken(Jim_Interp *interp, const ScriptToken *token, Jim_Obj **objPtrPtr) { Jim_Obj *objPtr; @@ -14244,8 +14721,8 @@ && token[2].type == JIM_TT_VAR) { objPtr->typePtr = &interpolatedObjType; - objPtr->internalRep.twoPtrValue.ptr1 = (void *)token; - objPtr->internalRep.twoPtrValue.ptr2 = intv[2]; + objPtr->internalRep.dictSubstValue.varNameObjPtr = token[0].objPtr; + objPtr->internalRep.dictSubstValue.indexObjPtr = intv[2]; Jim_IncrRefCount(intv[2]); } @@ -14268,22 +14745,26 @@ } -static int JimEvalObjList(Jim_Interp *interp, Jim_Obj *listPtr, Jim_Obj *fileNameObj, int linenr) +static int JimEvalObjList(Jim_Interp *interp, Jim_Obj *listPtr) { int retcode = JIM_OK; - JimPanic((!Jim_IsList(listPtr), "JimEvalObjList() called without list arg")); - if (listPtr->internalRep.listValue.len) { Jim_IncrRefCount(listPtr); - retcode = JimEvalObjVector(interp, + retcode = JimInvokeCommand(interp, listPtr->internalRep.listValue.len, - listPtr->internalRep.listValue.ele, fileNameObj, linenr); + listPtr->internalRep.listValue.ele); Jim_DecrRefCount(interp, listPtr); } return retcode; } +int Jim_EvalObjList(Jim_Interp *interp, Jim_Obj *listPtr) +{ + SetListFromAny(interp, listPtr); + return JimEvalObjList(interp, listPtr); +} + int Jim_EvalObj(Jim_Interp *interp, Jim_Obj *scriptObjPtr) { int i; @@ -14291,12 +14772,10 @@ ScriptToken *token; int retcode = JIM_OK; Jim_Obj *sargv[JIM_EVAL_SARGV_LEN], **argv = NULL; - int linenr = 0; - - interp->errorFlag = 0; + Jim_Obj *prevScriptObj; if (Jim_IsList(scriptObjPtr) && scriptObjPtr->bytes == NULL) { - return JimEvalObjList(interp, scriptObjPtr, interp->emptyObj, 1); + return JimEvalObjList(interp, scriptObjPtr); } Jim_IncrRefCount(scriptObjPtr); @@ -14304,18 +14783,20 @@ Jim_SetEmptyResult(interp); + token = script->token; + #ifdef JIM_OPTIMIZATION if (script->len == 0) { Jim_DecrRefCount(interp, scriptObjPtr); return JIM_OK; } if (script->len == 3 - && script->token[1].objPtr->typePtr == &commandObjType - && script->token[1].objPtr->internalRep.cmdValue.cmdPtr->isproc == 0 - && script->token[1].objPtr->internalRep.cmdValue.cmdPtr->u.native.cmdProc == Jim_IncrCoreCommand - && script->token[2].objPtr->typePtr == &variableObjType) { + && token[1].objPtr->typePtr == &commandObjType + && token[1].objPtr->internalRep.cmdValue.cmdPtr->isproc == 0 + && token[1].objPtr->internalRep.cmdValue.cmdPtr->u.native.cmdProc == Jim_IncrCoreCommand + && token[2].objPtr->typePtr == &variableObjType) { - Jim_Obj *objPtr = Jim_GetVariable(interp, script->token[2].objPtr, JIM_NONE); + Jim_Obj *objPtr = Jim_GetVariable(interp, token[2].objPtr, JIM_NONE); if (objPtr && !Jim_IsShared(objPtr) && objPtr->typePtr == &intObjType) { JimWideValue(objPtr)++; @@ -14329,17 +14810,20 @@ script->inUse++; - token = script->token; + + prevScriptObj = interp->currentScriptObj; + interp->currentScriptObj = scriptObjPtr; + + interp->errorFlag = 0; argv = sargv; for (i = 0; i < script->len && retcode == JIM_OK; ) { int argc; int j; - Jim_Cmd *cmd; argc = token[i].objPtr->internalRep.scriptLineValue.argc; - linenr = token[i].objPtr->internalRep.scriptLineValue.line; + script->linenr = token[i].objPtr->internalRep.scriptLineValue.line; if (argc > JIM_EVAL_SARGV_LEN) @@ -14439,26 +14923,9 @@ if (retcode == JIM_OK && argc) { - cmd = Jim_GetCommand(interp, argv[0], JIM_ERRMSG); - if (cmd != NULL) { - - JimIncrCmdRefCount(cmd); - Jim_SetEmptyResult(interp); - if (cmd->isproc) { - retcode = - JimCallProcedure(interp, cmd, script->fileNameObj, linenr, argc, argv); - } else { - interp->cmdPrivData = cmd->u.native.privData; - retcode = cmd->u.native.cmdProc(interp, argc, argv); - } - JimDecrCmdRefCount(interp, cmd); - } - else { - - retcode = JimUnknown(interp, argc, argv, script->fileNameObj, linenr); - } - if (interp->signal_level && interp->sigmask) { - + retcode = JimInvokeCommand(interp, argc, argv); + + if (Jim_CheckSignal(interp)) { retcode = JIM_SIGNAL; } } @@ -14475,7 +14942,10 @@ } - JimAddErrorToStack(interp, retcode, script->fileNameObj, linenr); + JimAddErrorToStack(interp, retcode, script); + + + interp->currentScriptObj = prevScriptObj; Jim_FreeIntRep(interp, scriptObjPtr); scriptObjPtr->typePtr = &scriptObjType; @@ -14495,7 +14965,7 @@ Jim_Obj *objPtr; Jim_CallFrame *savedCallFrame = interp->framePtr; - interp->framePtr = interp->framePtr->parentCallFrame; + interp->framePtr = interp->framePtr->parent; objPtr = Jim_GetVariable(interp, argValObj, JIM_ERRMSG); interp->framePtr = savedCallFrame; if (!objPtr) { @@ -14505,7 +14975,7 @@ objPtr = Jim_NewStringObj(interp, varname + 1, -1); Jim_IncrRefCount(objPtr); - retcode = Jim_SetVariableLink(interp, objPtr, argValObj, interp->framePtr->parentCallFrame); + retcode = Jim_SetVariableLink(interp, objPtr, argValObj, interp->framePtr->parent); Jim_DecrRefCount(interp, objPtr); } else { @@ -14532,7 +15002,7 @@ } else { - Jim_AppendString(interp, argmsg, "?argument ...?", -1); + Jim_AppendString(interp, argmsg, "?arg...?", -1); } } else { @@ -14542,20 +15012,65 @@ Jim_AppendString(interp, argmsg, "?", 1); } else { - Jim_AppendObj(interp, argmsg, cmd->u.proc.arglist[i].nameObjPtr); + const char *arg = Jim_String(cmd->u.proc.arglist[i].nameObjPtr); + if (*arg == '&') { + arg++; + } + Jim_AppendString(interp, argmsg, arg, -1); } } } - Jim_SetResultFormatted(interp, "wrong # args: should be \"%#s%#s\"", procNameObj, argmsg); - Jim_FreeNewObj(interp, argmsg); + Jim_SetResultFormatted(interp, "wrong # args: should be \"%#s%#s\"", procNameObj, argmsg); + Jim_FreeNewObj(interp, argmsg); +} + +#ifdef jim_ext_namespace +int Jim_EvalNamespace(Jim_Interp *interp, Jim_Obj *scriptObj, Jim_Obj *nsObj) +{ + Jim_CallFrame *callFramePtr; + int retcode; + + + callFramePtr = JimCreateCallFrame(interp, interp->framePtr, nsObj); + callFramePtr->argv = &interp->emptyObj; + callFramePtr->argc = 0; + callFramePtr->procArgsObjPtr = NULL; + callFramePtr->procBodyObjPtr = scriptObj; + callFramePtr->staticVars = NULL; + callFramePtr->fileNameObj = interp->emptyObj; + callFramePtr->line = 0; + Jim_IncrRefCount(scriptObj); + interp->framePtr = callFramePtr; + + + if (interp->framePtr->level == interp->maxCallFrameDepth) { + Jim_SetResultString(interp, "Too many nested calls. Infinite recursion?", -1); + retcode = JIM_ERR; + } + else { + + retcode = Jim_EvalObj(interp, scriptObj); + } + + + interp->framePtr = interp->framePtr->parent; + if (callFramePtr->vars.size != JIM_HT_INITIAL_SIZE) { + JimFreeCallFrame(interp, callFramePtr, JIM_FCF_NONE); + } + else { + JimFreeCallFrame(interp, callFramePtr, JIM_FCF_NOHT); + } + + return retcode; } +#endif -static int JimCallProcedure(Jim_Interp *interp, Jim_Cmd *cmd, Jim_Obj *fileNameObj, int linenr, int argc, - Jim_Obj *const *argv) +static int JimCallProcedure(Jim_Interp *interp, Jim_Cmd *cmd, int argc, Jim_Obj *const *argv) { Jim_CallFrame *callFramePtr; - Jim_Stack *prevLocalProcs; int i, d, retcode, optargs; + Jim_Stack *localCommands; + ScriptObj *script; if (argc - 1 < cmd->u.proc.reqArity || @@ -14564,30 +15079,35 @@ return JIM_ERR; } + if (Jim_Length(cmd->u.proc.bodyObjPtr) == 0) { + + return JIM_OK; + } + - if (interp->framePtr->level == interp->maxNestingDepth) { + if (interp->framePtr->level == interp->maxCallFrameDepth) { Jim_SetResultString(interp, "Too many nested calls. Infinite recursion?", -1); return JIM_ERR; } - callFramePtr = JimCreateCallFrame(interp, interp->framePtr); + callFramePtr = JimCreateCallFrame(interp, interp->framePtr, cmd->u.proc.nsObj); callFramePtr->argv = argv; callFramePtr->argc = argc; callFramePtr->procArgsObjPtr = cmd->u.proc.argListObjPtr; callFramePtr->procBodyObjPtr = cmd->u.proc.bodyObjPtr; callFramePtr->staticVars = cmd->u.proc.staticVars; - callFramePtr->fileNameObj = fileNameObj; - callFramePtr->line = linenr; + + + script = Jim_GetScript(interp, interp->currentScriptObj); + callFramePtr->fileNameObj = script->fileNameObj; + callFramePtr->line = script->linenr; + Jim_IncrRefCount(cmd->u.proc.argListObjPtr); Jim_IncrRefCount(cmd->u.proc.bodyObjPtr); interp->framePtr = callFramePtr; - prevLocalProcs = interp->localProcs; - interp->localProcs = NULL; - - optargs = (argc - 1 - cmd->u.proc.reqArity); @@ -14634,20 +15154,27 @@ badargset: - interp->framePtr = interp->framePtr->parentCallFrame; + + localCommands = callFramePtr->localCommands; + callFramePtr->localCommands = NULL; + + interp->framePtr = interp->framePtr->parent; if (callFramePtr->vars.size != JIM_HT_INITIAL_SIZE) { JimFreeCallFrame(interp, callFramePtr, JIM_FCF_NONE); } else { JimFreeCallFrame(interp, callFramePtr, JIM_FCF_NOHT); } + while (retcode == JIM_EVAL) { Jim_Obj *resultScriptObjPtr = Jim_GetResult(interp); Jim_IncrRefCount(resultScriptObjPtr); - retcode = JimEvalObjList(interp, resultScriptObjPtr, fileNameObj, linenr); + JimPanic((!Jim_IsList(resultScriptObjPtr), "tailcall (JIM_EVAL) returned non-list")); + + retcode = JimEvalObjList(interp, resultScriptObjPtr); if (retcode == JIM_RETURN) { interp->returnLevel++; } @@ -14669,8 +15196,7 @@ } - JimDeleteLocalProcs(interp); - interp->localProcs = prevLocalProcs; + JimDeleteLocalProcs(interp, localCommands); return retcode; } @@ -14820,74 +15346,45 @@ return retcode; } -static int JimParseSubstStr(struct JimParserCtx *pc) +static void JimParseSubst(struct JimParserCtx *pc, int flags) { pc->tstart = pc->p; pc->tline = pc->linenr; - while (pc->len && *pc->p != '$' && *pc->p != '[') { - if (*pc->p == '\\' && pc->len > 1) { - pc->p++; - pc->len--; - } - pc->p++; - pc->len--; - } - pc->tend = pc->p - 1; - pc->tt = JIM_TT_ESC; - return JIM_OK; -} - -static int JimParseSubst(struct JimParserCtx *pc, int flags) -{ - int retval; if (pc->len == 0) { - pc->tstart = pc->tend = pc->p; - pc->tline = pc->linenr; + pc->tend = pc->p; pc->tt = JIM_TT_EOL; pc->eof = 1; - return JIM_OK; + return; } - switch (*pc->p) { - case '[': - retval = JimParseCmd(pc); - if (flags & JIM_SUBST_NOCMD) { - pc->tstart--; - pc->tend++; - pc->tt = (flags & JIM_SUBST_NOESC) ? JIM_TT_STR : JIM_TT_ESC; - } - return retval; - break; - case '$': - if (JimParseVar(pc) == JIM_ERR) { - pc->tstart = pc->tend = pc->p++; - pc->len--; - pc->tline = pc->linenr; - pc->tt = JIM_TT_STR; - } - else { - if (flags & JIM_SUBST_NOVAR) { - pc->tstart--; - if (flags & JIM_SUBST_NOESC) - pc->tt = JIM_TT_STR; - else - pc->tt = JIM_TT_ESC; - if (*pc->tstart == '{') { - pc->tstart--; - if (*(pc->tend + 1)) - pc->tend++; - } - } - } + if (*pc->p == '[' && !(flags & JIM_SUBST_NOCMD)) { + JimParseCmd(pc); + return; + } + if (*pc->p == '$' && !(flags & JIM_SUBST_NOVAR)) { + if (JimParseVar(pc) == JIM_OK) { + return; + } + + pc->tstart = pc->p; + flags |= JIM_SUBST_NOVAR; + } + while (pc->len) { + if (*pc->p == '$' && !(flags & JIM_SUBST_NOVAR)) { break; - default: - retval = JimParseSubstStr(pc); - if (flags & JIM_SUBST_NOESC) - pc->tt = JIM_TT_STR; - return retval; + } + if (*pc->p == '[' && !(flags & JIM_SUBST_NOCMD)) { break; + } + if (*pc->p == '\\' && pc->len > 1) { + pc->p++; + pc->len--; + } + pc->p++; + pc->len--; } - return JIM_OK; + pc->tend = pc->p - 1; + pc->tt = (flags & JIM_SUBST_NOESC) ? JIM_TT_STR : JIM_TT_ESC; } @@ -14968,70 +15465,80 @@ void Jim_WrongNumArgs(Jim_Interp *interp, int argc, Jim_Obj *const *argv, const char *msg) { - int i; - Jim_Obj *objPtr = Jim_NewEmptyStringObj(interp); + Jim_Obj *objPtr; + Jim_Obj *listObjPtr = Jim_NewListObj(interp, argv, argc); - Jim_AppendString(interp, objPtr, "wrong # args: should be \"", -1); - for (i = 0; i < argc; i++) { - Jim_AppendObj(interp, objPtr, argv[i]); - if (!(i + 1 == argc && msg[0] == '\0')) - Jim_AppendString(interp, objPtr, " ", 1); + if (*msg) { + Jim_ListAppendElement(interp, listObjPtr, Jim_NewStringObj(interp, msg, -1)); } - Jim_AppendString(interp, objPtr, msg, -1); - Jim_AppendString(interp, objPtr, "\"", 1); - Jim_SetResult(interp, objPtr); + Jim_IncrRefCount(listObjPtr); + objPtr = Jim_ListJoin(interp, listObjPtr, " ", 1); + Jim_DecrRefCount(interp, listObjPtr); + + Jim_IncrRefCount(objPtr); + Jim_SetResultFormatted(interp, "wrong # args: should be \"%#s\"", objPtr); + Jim_DecrRefCount(interp, objPtr); } -#define JimTrivialMatch(pattern) (strpbrk((pattern), "*[?\\") == NULL) +typedef void JimHashtableIteratorCallbackType(Jim_Interp *interp, Jim_Obj *listObjPtr, + Jim_HashEntry *he, int type); +#define JimTrivialMatch(pattern) (strpbrk((pattern), "*[?\\") == NULL) -static Jim_Obj *JimCommandsList(Jim_Interp *interp, Jim_Obj *patternObjPtr, int type) +static Jim_Obj *JimHashtablePatternMatch(Jim_Interp *interp, Jim_HashTable *ht, Jim_Obj *patternObjPtr, + JimHashtableIteratorCallbackType *callback, int type) { - Jim_HashTableIterator *htiter; Jim_HashEntry *he; Jim_Obj *listObjPtr = Jim_NewListObj(interp, NULL, 0); if (patternObjPtr && JimTrivialMatch(Jim_String(patternObjPtr))) { - Jim_Cmd *cmdPtr = Jim_GetCommand(interp, patternObjPtr, JIM_NONE); - if (cmdPtr) { - if (type == 1 && !cmdPtr->isproc) { - - } - else if (type == 2 && !Jim_AioFilehandle(interp, patternObjPtr)) { - - } - else { - Jim_ListAppendElement(interp, listObjPtr, patternObjPtr); + he = Jim_FindHashEntry(ht, Jim_String(patternObjPtr)); + if (he) { + callback(interp, listObjPtr, he, 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); } } - return listObjPtr; } + return listObjPtr; +} - htiter = Jim_GetHashTableIterator(&interp->commands); - while ((he = Jim_NextHashEntry(htiter)) != NULL) { - Jim_Cmd *cmdPtr = he->u.val; - Jim_Obj *cmdNameObj; - if (type == 1 && !cmdPtr->isproc) { - - continue; - } - if (patternObjPtr && !JimStringMatch(interp, patternObjPtr, he->key, 0)) - continue; +#define JIM_CMDLIST_COMMANDS 0 +#define JIM_CMDLIST_PROCS 1 +#define JIM_CMDLIST_CHANNELS 2 - cmdNameObj = Jim_NewStringObj(interp, he->key, -1); +static void JimCommandMatch(Jim_Interp *interp, Jim_Obj *listObjPtr, + Jim_HashEntry *he, int type) +{ + Jim_Cmd *cmdPtr = (Jim_Cmd *)he->u.val; + Jim_Obj *objPtr; + if (type == JIM_CMDLIST_PROCS && !cmdPtr->isproc) { - if (type == 2 && !Jim_AioFilehandle(interp, cmdNameObj)) { - Jim_FreeNewObj(interp, cmdNameObj); - continue; - } + return; + } + + objPtr = Jim_NewStringObj(interp, he->key, -1); + Jim_IncrRefCount(objPtr); - Jim_ListAppendElement(interp, listObjPtr, cmdNameObj); + if (type != JIM_CMDLIST_CHANNELS || Jim_AioFilehandle(interp, objPtr)) { + Jim_ListAppendElement(interp, listObjPtr, objPtr); } - Jim_FreeHashTableIterator(htiter); - return listObjPtr; + Jim_DecrRefCount(interp, objPtr); +} + + +static Jim_Obj *JimCommandsList(Jim_Interp *interp, Jim_Obj *patternObjPtr, int type) +{ + return JimHashtablePatternMatch(interp, &interp->commands, patternObjPtr, JimCommandMatch, type); } @@ -15039,33 +15546,31 @@ #define JIM_VARLIST_LOCALS 1 #define JIM_VARLIST_VARS 2 -static Jim_Obj *JimVariablesList(Jim_Interp *interp, Jim_Obj *patternObjPtr, int mode) +#define JIM_VARLIST_VALUES 0x1000 + +static void JimVariablesMatch(Jim_Interp *interp, Jim_Obj *listObjPtr, + Jim_HashEntry *he, int type) { - Jim_HashTableIterator *htiter; - Jim_HashEntry *he; - Jim_Obj *listObjPtr = Jim_NewListObj(interp, NULL, 0); + Jim_Var *varPtr = (Jim_Var *)he->u.val; - if (mode == JIM_VARLIST_GLOBALS) { - htiter = Jim_GetHashTableIterator(&interp->topFramePtr->vars); - } - else { - if (mode == JIM_VARLIST_LOCALS && interp->framePtr == interp->topFramePtr) - return listObjPtr; - htiter = Jim_GetHashTableIterator(&interp->framePtr->vars); + 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); + } } - while ((he = Jim_NextHashEntry(htiter)) != NULL) { - Jim_Var *varPtr = (Jim_Var *)he->u.val; +} - if (mode == JIM_VARLIST_LOCALS) { - if (varPtr->linkFramePtr != NULL) - continue; - } - if (patternObjPtr && !JimStringMatch(interp, patternObjPtr, he->key, 0)) - continue; - Jim_ListAppendElement(interp, listObjPtr, Jim_NewStringObj(interp, he->key, -1)); + +static Jim_Obj *JimVariablesList(Jim_Interp *interp, Jim_Obj *patternObjPtr, int mode) +{ + if (mode == JIM_VARLIST_LOCALS && interp->framePtr == interp->topFramePtr) { + return interp->emptyObj; + } + else { + Jim_CallFrame *framePtr = (mode == JIM_VARLIST_GLOBALS) ? interp->topFramePtr : interp->framePtr; + return JimHashtablePatternMatch(interp, &framePtr->vars, patternObjPtr, JimVariablesMatch, mode); } - Jim_FreeHashTableIterator(htiter); - return listObjPtr; } static int JimInfoLevel(Jim_Interp *interp, Jim_Obj *levelObjPtr, @@ -15360,7 +15865,6 @@ ScriptObj *incrScript; ExprByteCode *expr; jim_wide stop, currentVal; - unsigned jim_wide procEpoch; Jim_Obj *objPtr; int cmpOffset; @@ -15413,7 +15917,6 @@ } - procEpoch = interp->procEpoch; varNamePtr = expr->token[0].objPtr; Jim_IncrRefCount(varNamePtr); @@ -15443,9 +15946,6 @@ retval = Jim_EvalObj(interp, argv[4]); if (retval == JIM_OK || retval == JIM_CONTINUE) { retval = JIM_OK; - if (procEpoch != interp->procEpoch) { - goto evalnext; - } objPtr = Jim_GetVariable(interp, varNamePtr, JIM_ERRMSG); @@ -15569,100 +16069,124 @@ return retval; } +typedef struct { + Jim_Obj *objPtr; + int idx; +} Jim_ListIter; + +static void JimListIterInit(Jim_ListIter *iter, Jim_Obj *objPtr) +{ + iter->objPtr = objPtr; + iter->idx = 0; +} + +static Jim_Obj *JimListIterNext(Jim_Interp *interp, Jim_ListIter *iter) +{ + if (iter->idx >= Jim_ListLength(interp, iter->objPtr)) { + return NULL; + } + return iter->objPtr->internalRep.listValue.ele[iter->idx++]; +} + +static int JimListIterDone(Jim_Interp *interp, Jim_ListIter *iter) +{ + return iter->idx >= Jim_ListLength(interp, iter->objPtr); +} + static int JimForeachMapHelper(Jim_Interp *interp, int argc, Jim_Obj *const *argv, int doMap) { - int result = JIM_ERR, i, nbrOfLists, *listsIdx, *listsEnd; - int nbrOfLoops = 0; - Jim_Obj *emptyStr, *script, *mapRes = NULL; + int result = JIM_ERR; + int i, numargs; + Jim_ListIter twoiters[2]; + Jim_ListIter *iters; + Jim_Obj *script; + Jim_Obj *resultObj; if (argc < 4 || argc % 2 != 0) { Jim_WrongNumArgs(interp, 1, argv, "varList list ?varList list ...? script"); return JIM_ERR; } - if (doMap) { - mapRes = Jim_NewListObj(interp, NULL, 0); - Jim_IncrRefCount(mapRes); - } - emptyStr = Jim_NewEmptyStringObj(interp); - Jim_IncrRefCount(emptyStr); script = argv[argc - 1]; - nbrOfLists = (argc - 1 - 1) / 2; - listsIdx = (int *)Jim_Alloc(nbrOfLists * sizeof(int)); - listsEnd = (int *)Jim_Alloc(nbrOfLists * 2 * sizeof(int)); - - memset(listsIdx, 0, nbrOfLists * sizeof(int)); - - for (i = 0; i < nbrOfLists * 2; i += 2) { - div_t cnt; - int count; - - listsEnd[i] = Jim_ListLength(interp, argv[i + 1]); - listsEnd[i + 1] = Jim_ListLength(interp, argv[i + 2]); - if (listsEnd[i] == 0) { + numargs = (argc - 1 - 1); + + if (numargs == 2) { + iters = twoiters; + } + else { + iters = Jim_Alloc(numargs * sizeof(*iters)); + } + for (i = 0; i < numargs; i++) { + JimListIterInit(&iters[i], argv[i + 1]); + if (i % 2 == 0 && JimListIterDone(interp, &iters[i])) { Jim_SetResultString(interp, "foreach varlist is empty", -1); - goto err; + return JIM_ERR; } - cnt = div(listsEnd[i + 1], listsEnd[i]); - count = cnt.quot + (cnt.rem ? 1 : 0); - if (count > nbrOfLoops) - nbrOfLoops = count; - } - for (; nbrOfLoops-- > 0;) { - for (i = 0; i < nbrOfLists; ++i) { - int varIdx = 0, var = i * 2; - - while (varIdx < listsEnd[var]) { - Jim_Obj *varName, *ele; - int lst = i * 2 + 1; + } - - Jim_ListIndex(interp, argv[var + 1], varIdx, &varName, JIM_NONE); - if (listsIdx[i] < listsEnd[lst]) { - Jim_ListIndex(interp, argv[lst + 1], listsIdx[i], &ele, JIM_NONE); + if (doMap) { + resultObj = Jim_NewListObj(interp, NULL, 0); + } + else { + resultObj = interp->emptyObj; + } + Jim_IncrRefCount(resultObj); + + while (1) { + + for (i = 0; i < numargs; i += 2) { + if (!JimListIterDone(interp, &iters[i + 1])) { + break; + } + } + if (i == numargs) { + + break; + } + + + for (i = 0; i < numargs; i += 2) { + Jim_Obj *varName; + + + JimListIterInit(&iters[i], argv[i + 1]); + while ((varName = JimListIterNext(interp, &iters[i])) != NULL) { + Jim_Obj *valObj = JimListIterNext(interp, &iters[i + 1]); + if (!valObj) { - Jim_IncrRefCount(ele); - result = Jim_SetVariable(interp, varName, ele); - Jim_DecrRefCount(interp, ele); - if (result == JIM_OK) { - ++listsIdx[i]; - ++varIdx; - continue; - } + valObj = interp->emptyObj; } - else if (Jim_SetVariable(interp, varName, emptyStr) == JIM_OK) { - ++varIdx; - continue; + + Jim_IncrRefCount(valObj); + result = Jim_SetVariable(interp, varName, valObj); + Jim_DecrRefCount(interp, valObj); + if (result != JIM_OK) { + goto err; } - goto err; } } switch (result = Jim_EvalObj(interp, script)) { case JIM_OK: - if (doMap) - Jim_ListAppendElement(interp, mapRes, interp->result); + if (doMap) { + Jim_ListAppendElement(interp, resultObj, interp->result); + } break; case JIM_CONTINUE: break; case JIM_BREAK: goto out; - break; default: goto err; } } out: result = JIM_OK; - if (doMap) - Jim_SetResult(interp, mapRes); - else - Jim_SetEmptyResult(interp); + Jim_SetResult(interp, resultObj); err: - if (doMap) - Jim_DecrRefCount(interp, mapRes); - Jim_DecrRefCount(interp, emptyStr); - Jim_Free(listsIdx); - Jim_Free(listsEnd); + Jim_DecrRefCount(interp, resultObj); + if (numargs > 2) { + Jim_Free(iters); + } return result; } @@ -15679,6 +16203,39 @@ } +static int Jim_LassignCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) +{ + int result = JIM_ERR; + int i; + Jim_ListIter iter; + Jim_Obj *resultObj; + + if (argc < 2) { + Jim_WrongNumArgs(interp, 1, argv, "varList list ?varName ...?"); + return JIM_ERR; + } + + JimListIterInit(&iter, argv[1]); + + for (i = 2; i < argc; i++) { + Jim_Obj *valObj = JimListIterNext(interp, &iter); + result = Jim_SetVariable(interp, argv[i], valObj ? valObj : interp->emptyObj); + if (result != JIM_OK) { + return result; + } + } + + resultObj = Jim_NewListObj(interp, NULL, 0); + while (!JimListIterDone(interp, &iter)) { + Jim_ListAppendElement(interp, resultObj, JimListIterNext(interp, &iter)); + } + + Jim_SetResult(interp, resultObj); + + return JIM_OK; +} + + static int Jim_IfCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { int boolean, retval, current = 1, falsebody = 0; @@ -16004,7 +16561,7 @@ Jim_ListIndex(interp, argv[0], i, &objPtr, JIM_NONE); switch (opt_match) { case OPT_EXACT: - eq = Jim_StringCompareObj(interp, objPtr, argv[1], opt_nocase) == 0; + eq = Jim_StringCompareObj(interp, argv[1], objPtr, opt_nocase) == 0; break; case OPT_GLOB: @@ -16112,8 +16669,8 @@ int idx, len; Jim_Obj *listPtr; - if (argc < 4) { - Jim_WrongNumArgs(interp, 1, argv, "list index element " "?element ...?"); + if (argc < 3) { + Jim_WrongNumArgs(interp, 1, argv, "list index ?element ...?"); return JIM_ERR; } listPtr = argv[1]; @@ -16144,7 +16701,7 @@ Jim_Obj *newListObj; if (argc < 4) { - Jim_WrongNumArgs(interp, 1, argv, "list first last ?element element ...?"); + Jim_WrongNumArgs(interp, 1, argv, "list first last ?element ...?"); return JIM_ERR; } if (Jim_GetIndex(interp, argv[2], &first) != JIM_OK || @@ -16157,7 +16714,7 @@ first = JimRelToAbsIndex(len, first); last = JimRelToAbsIndex(len, last); - JimRelToAbsRange(len, first, last, &first, &last, &rangeLen); + JimRelToAbsRange(len, &first, &last, &rangeLen); @@ -16515,27 +17072,89 @@ static int Jim_TailcallCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { - Jim_Obj *objPtr; - - objPtr = Jim_NewListObj(interp, argv + 1, argc - 1); - Jim_SetResult(interp, objPtr); + Jim_SetResult(interp, Jim_NewListObj(interp, argv + 1, argc - 1)); return JIM_EVAL; } +static int JimAliasCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv) +{ + Jim_Obj *cmdList; + Jim_Obj *prefixListObj = Jim_CmdPrivData(interp); + + + cmdList = Jim_DuplicateObj(interp, prefixListObj); + ListInsertElements(cmdList, -1, argc - 1, argv + 1); + + return JimEvalObjList(interp, cmdList); +} + +static void JimAliasCmdDelete(Jim_Interp *interp, void *privData) +{ + Jim_Obj *prefixListObj = privData; + Jim_DecrRefCount(interp, prefixListObj); +} + +static int Jim_AliasCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) +{ + Jim_Obj *prefixListObj; + const char *newname; + + if (argc < 3) { + Jim_WrongNumArgs(interp, 1, argv, "newname command ?args ...?"); + return JIM_ERR; + } + + prefixListObj = Jim_NewListObj(interp, argv + 2, argc - 2); + Jim_IncrRefCount(prefixListObj); + newname = Jim_String(argv[1]); + if (newname[0] == ':' && newname[1] == ':') { + while (*++newname == ':') { + } + } + + Jim_SetResult(interp, argv[1]); + + return Jim_CreateCommand(interp, newname, JimAliasCmd, prefixListObj, JimAliasCmdDelete); +} + static int Jim_ProcCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { + Jim_Cmd *cmd; + if (argc != 4 && argc != 5) { Jim_WrongNumArgs(interp, 1, argv, "name arglist ?statics? body"); return JIM_ERR; } + if (JimValidName(interp, "procedure", argv[1]) != JIM_OK) { + return JIM_ERR; + } + if (argc == 4) { - return JimCreateProcedure(interp, argv[1], argv[2], NULL, argv[3]); + cmd = JimCreateProcedureCmd(interp, argv[2], NULL, argv[3], NULL); } else { - return JimCreateProcedure(interp, argv[1], argv[2], argv[3], argv[4]); + cmd = JimCreateProcedureCmd(interp, argv[2], argv[3], argv[4], NULL); + } + + if (cmd) { + + Jim_Obj *qualifiedCmdNameObj; + const char *cmdname = JimQualifyName(interp, Jim_String(argv[1]), &qualifiedCmdNameObj); + + JimCreateCommand(interp, cmdname, cmd); + + + JimUpdateProcNamespace(interp, cmd, cmdname); + + JimFreeQualifiedName(interp, qualifiedCmdNameObj); + + + Jim_SetResult(interp, argv[1]); + return JIM_OK; } + return JIM_ERR; } @@ -16551,17 +17170,17 @@ if (retcode == 0) { - const char *procname = Jim_String(Jim_GetResult(interp)); + Jim_Obj *cmdNameObj = Jim_GetResult(interp); - if (Jim_FindHashEntry(&interp->commands, procname) == NULL) { - Jim_SetResultFormatted(interp, "not a proc: \"%s\"", procname); + if (Jim_GetCommand(interp, cmdNameObj, JIM_ERRMSG) == NULL) { return JIM_ERR; } - if (interp->localProcs == NULL) { - interp->localProcs = Jim_Alloc(sizeof(*interp->localProcs)); - Jim_InitStack(interp->localProcs); + if (interp->framePtr->localCommands == NULL) { + interp->framePtr->localCommands = Jim_Alloc(sizeof(*interp->framePtr->localCommands)); + Jim_InitStack(interp->framePtr->localCommands); } - Jim_StackPush(interp->localProcs, Jim_StrDup(procname)); + Jim_IncrRefCount(cmdNameObj); + Jim_StackPush(interp->framePtr->localCommands, cmdNameObj); } return retcode; @@ -16578,8 +17197,8 @@ int retcode; Jim_Cmd *cmdPtr = Jim_GetCommand(interp, argv[1], JIM_ERRMSG); - if (cmdPtr == NULL || !cmdPtr->isproc || !cmdPtr->u.proc.prevCmd) { - Jim_SetResultFormatted(interp, "no previous proc: \"%#s\"", argv[1]); + if (cmdPtr == NULL || !cmdPtr->isproc || !cmdPtr->prevCmd) { + Jim_SetResultFormatted(interp, "no previous command: \"%#s\"", argv[1]); return JIM_ERR; } @@ -16598,6 +17217,59 @@ } +static int Jim_ApplyCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) +{ + if (argc < 2) { + Jim_WrongNumArgs(interp, 1, argv, "lambdaExpr ?arg ...?"); + return JIM_ERR; + } + else { + int ret; + Jim_Cmd *cmd; + Jim_Obj *argListObjPtr; + Jim_Obj *bodyObjPtr; + Jim_Obj *nsObj = NULL; + Jim_Obj **nargv; + + int len = Jim_ListLength(interp, argv[1]); + if (len != 2 && len != 3) { + Jim_SetResultFormatted(interp, "can't interpret \"%#s\" as a lambda expression", argv[1]); + return JIM_ERR; + } + + if (len == 3) { +#ifdef jim_ext_namespace + + nsObj = JimQualifyNameObj(interp, Jim_ListGetIndex(interp, argv[1], 2)); +#else + Jim_SetResultString(interp, "namespaces not enabled", -1); + return JIM_ERR; +#endif + } + argListObjPtr = Jim_ListGetIndex(interp, argv[1], 0); + bodyObjPtr = Jim_ListGetIndex(interp, argv[1], 1); + + cmd = JimCreateProcedureCmd(interp, argListObjPtr, NULL, bodyObjPtr, nsObj); + + if (cmd) { + + nargv = Jim_Alloc((argc - 2 + 1) * sizeof(*nargv)); + nargv[0] = Jim_NewStringObj(interp, "apply lambdaExpr", -1); + Jim_IncrRefCount(nargv[0]); + memcpy(&nargv[1], argv + 2, (argc - 2) * sizeof(*nargv)); + ret = JimCallProcedure(interp, cmd, argc - 2 + 1, nargv); + Jim_DecrRefCount(interp, nargv[0]); + Jim_Free(nargv); + + JimDecrCmdRefCount(interp, cmd); + return ret; + } + return JIM_ERR; + } +} + + + static int Jim_ConcatCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { Jim_SetResult(interp, Jim_ConcatObj(interp, argc - 1, argv + 1)); @@ -16650,8 +17322,12 @@ if (interp->framePtr->level == 0) return JIM_OK; for (i = 1; i < argc; i++) { - if (Jim_SetVariableLink(interp, argv[i], argv[i], interp->topFramePtr) != JIM_OK) - return JIM_ERR; + + const char *name = Jim_String(argv[i]); + if (name[0] != ':' || name[1] != ':') { + if (Jim_SetVariableLink(interp, argv[i], argv[i], interp->topFramePtr) != JIM_OK) + return JIM_ERR; + } } return JIM_OK; } @@ -16687,12 +17363,7 @@ if (strLen >= kl && kl) { int rc; - if (nocase) { - rc = JimStringCompareNoCase(str, k, kl); - } - else { - rc = JimStringCompare(str, kl, k, kl); - } + rc = JimStringCompareLen(str, k, kl, nocase); if (rc == 0) { if (noMatchStart) { Jim_AppendString(interp, resultObjPtr, noMatchStart, str - noMatchStart); @@ -16727,19 +17398,22 @@ int opt_case = 1; int option; static const char * const options[] = { - "bytelength", "length", "compare", "match", "equal", "is", "byterange", "range", "map", - "repeat", "reverse", "index", "first", "last", - "trim", "trimleft", "trimright", "tolower", "toupper", NULL + "bytelength", "length", "compare", "match", "equal", "is", "byterange", "range", "replace", + "map", "repeat", "reverse", "index", "first", "last", + "trim", "trimleft", "trimright", "tolower", "toupper", "totitle", NULL }; enum { - OPT_BYTELENGTH, OPT_LENGTH, OPT_COMPARE, OPT_MATCH, OPT_EQUAL, OPT_IS, OPT_BYTERANGE, OPT_RANGE, OPT_MAP, - OPT_REPEAT, OPT_REVERSE, OPT_INDEX, OPT_FIRST, OPT_LAST, - OPT_TRIM, OPT_TRIMLEFT, OPT_TRIMRIGHT, OPT_TOLOWER, OPT_TOUPPER + OPT_BYTELENGTH, OPT_LENGTH, OPT_COMPARE, OPT_MATCH, OPT_EQUAL, OPT_IS, OPT_BYTERANGE, OPT_RANGE, OPT_REPLACE, + OPT_MAP, OPT_REPEAT, OPT_REVERSE, OPT_INDEX, OPT_FIRST, OPT_LAST, + OPT_TRIM, OPT_TRIMLEFT, OPT_TRIMRIGHT, OPT_TOLOWER, OPT_TOUPPER, OPT_TOTITLE }; static const char * const nocase_options[] = { "-nocase", NULL }; + static const char * const nocase_length_options[] = { + "-nocase", "-length", NULL + }; if (argc < 2) { Jim_WrongNumArgs(interp, 1, argv, "option ?arguments ...?"); @@ -16767,23 +17441,54 @@ case OPT_COMPARE: case OPT_EQUAL: - if (argc != 4 && - (argc != 5 || - Jim_GetEnum(interp, argv[2], nocase_options, &opt_case, NULL, - JIM_ENUM_ABBREV) != JIM_OK)) { - Jim_WrongNumArgs(interp, 2, argv, "?-nocase? string1 string2"); - return JIM_ERR; - } - if (opt_case == 0) { - argv++; - } - if (option == OPT_COMPARE || !opt_case) { - Jim_SetResultInt(interp, Jim_StringCompareObj(interp, argv[2], argv[3], !opt_case)); - } - else { - Jim_SetResultBool(interp, Jim_StringEqObj(argv[2], argv[3])); + { + + long opt_length = -1; + int n = argc - 4; + int i = 2; + while (n > 0) { + int subopt; + if (Jim_GetEnum(interp, argv[i++], nocase_length_options, &subopt, NULL, + JIM_ENUM_ABBREV) != JIM_OK) { +badcompareargs: + Jim_WrongNumArgs(interp, 2, argv, "?-nocase? ?-length int? string1 string2"); + return JIM_ERR; + } + if (subopt == 0) { + + opt_case = 0; + n--; + } + else { + + if (n < 2) { + goto badcompareargs; + } + if (Jim_GetLong(interp, argv[i++], &opt_length) != JIM_OK) { + return JIM_ERR; + } + n -= 2; + } + } + if (n) { + goto badcompareargs; + } + argv += argc - 2; + if (opt_length < 0 && option != OPT_COMPARE && opt_case) { + + Jim_SetResultBool(interp, Jim_StringEqObj(argv[0], argv[1])); + } + else { + if (opt_length >= 0) { + n = JimStringCompareLen(Jim_String(argv[0]), Jim_String(argv[1]), opt_length, !opt_case); + } + else { + n = Jim_StringCompareObj(interp, argv[0], argv[1], !opt_case); + } + Jim_SetResultInt(interp, option == OPT_COMPARE ? n : n == 0); + } + return JIM_OK; } - return JIM_OK; case OPT_MATCH: if (argc != 4 && @@ -16844,6 +17549,22 @@ return JIM_OK; } + case OPT_REPLACE:{ + Jim_Obj *objPtr; + + if (argc != 5 && argc != 6) { + Jim_WrongNumArgs(interp, 2, argv, "string first last ?string?"); + return JIM_ERR; + } + objPtr = JimStringReplaceObj(interp, argv[2], argv[3], argv[4], argc == 6 ? argv[5] : NULL); + if (objPtr == NULL) { + return JIM_ERR; + } + Jim_SetResult(interp, objPtr); + return JIM_OK; + } + + case OPT_REPEAT:{ Jim_Obj *objPtr; jim_wide count; @@ -16982,6 +17703,7 @@ case OPT_TOLOWER: case OPT_TOUPPER: + case OPT_TOTITLE: if (argc != 3) { Jim_WrongNumArgs(interp, 2, argv, "string"); return JIM_ERR; @@ -16989,9 +17711,12 @@ if (option == OPT_TOLOWER) { Jim_SetResult(interp, JimStringToLower(interp, argv[2])); } - else { + else if (option == OPT_TOUPPER) { Jim_SetResult(interp, JimStringToUpper(interp, argv[2])); } + else { + Jim_SetResult(interp, JimStringToTitle(interp, argv[2])); + } return JIM_OK; case OPT_IS: @@ -17123,7 +17848,7 @@ } interp->signal_level += sig; - if (interp->signal_level && interp->sigmask) { + if (Jim_CheckSignal(interp)) { exitCode = JIM_SIGNAL; } @@ -17279,21 +18004,20 @@ static int JimInfoReferences(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { Jim_Obj *listObjPtr; - Jim_HashTableIterator *htiter; + Jim_HashTableIterator htiter; Jim_HashEntry *he; listObjPtr = Jim_NewListObj(interp, NULL, 0); - htiter = Jim_GetHashTableIterator(&interp->references); - while ((he = Jim_NextHashEntry(htiter)) != NULL) { - char buf[JIM_REFERENCE_SPACE]; + JimInitHashTableIterator(&interp->references, &htiter); + while ((he = Jim_NextHashEntry(&htiter)) != NULL) { + char buf[JIM_REFERENCE_SPACE + 1]; Jim_Reference *refPtr = he->u.val; - const jim_wide *refId = he->key; + const unsigned long *refId = he->key; JimFormatReference(buf, refPtr, *refId); Jim_ListAppendElement(interp, listObjPtr, Jim_NewStringObj(interp, buf, -1)); } - Jim_FreeHashTableIterator(htiter); Jim_SetResult(interp, listObjPtr); return JIM_OK; } @@ -17302,8 +18026,6 @@ static int Jim_RenameCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { - const char *oldName, *newName; - if (argc != 3) { Jim_WrongNumArgs(interp, 1, argv, "oldName newName"); return JIM_ERR; @@ -17313,38 +18035,55 @@ return JIM_ERR; } - oldName = Jim_String(argv[1]); - newName = Jim_String(argv[2]); - return Jim_RenameCommand(interp, oldName, newName); + return Jim_RenameCommand(interp, Jim_String(argv[1]), Jim_String(argv[2])); } -int Jim_DictKeys(Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj *patternObj) -{ - int i; - int len; - Jim_Obj *resultObj; - Jim_Obj *dictObj; - Jim_Obj **dictValuesObj; +#define JIM_DICTMATCH_VALUES 0x0001 - if (Jim_DictKeysVector(interp, objPtr, NULL, 0, &dictObj, JIM_ERRMSG) != JIM_OK) { - return JIM_ERR; - } +typedef void JimDictMatchCallbackType(Jim_Interp *interp, Jim_Obj *listObjPtr, Jim_HashEntry *he, int type); - if (Jim_DictPairs(interp, dictObj, &dictValuesObj, &len) != JIM_OK) { - return JIM_ERR; +static void JimDictMatchKeys(Jim_Interp *interp, Jim_Obj *listObjPtr, Jim_HashEntry *he, int type) +{ + Jim_ListAppendElement(interp, listObjPtr, (Jim_Obj *)he->key); + if (type & JIM_DICTMATCH_VALUES) { + Jim_ListAppendElement(interp, listObjPtr, (Jim_Obj *)he->u.val); } +} - - resultObj = Jim_NewListObj(interp, NULL, 0); +static Jim_Obj *JimDictPatternMatch(Jim_Interp *interp, Jim_HashTable *ht, Jim_Obj *patternObjPtr, + JimDictMatchCallbackType *callback, int type) +{ + Jim_HashEntry *he; + Jim_Obj *listObjPtr = Jim_NewListObj(interp, NULL, 0); - for (i = 0; i < len; i += 2) { - if (patternObj == NULL || Jim_StringMatchObj(interp, patternObj, dictValuesObj[i], 0)) { - Jim_ListAppendElement(interp, resultObj, dictValuesObj[i]); + + Jim_HashTableIterator htiter; + JimInitHashTableIterator(ht, &htiter); + while ((he = Jim_NextHashEntry(&htiter)) != NULL) { + if (patternObjPtr == NULL || JimGlobMatch(Jim_String(patternObjPtr), Jim_String((Jim_Obj *)he->key), 0)) { + callback(interp, listObjPtr, he, type); } } - Jim_Free(dictValuesObj); - Jim_SetResult(interp, resultObj); + return listObjPtr; +} + + +int Jim_DictKeys(Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj *patternObjPtr) +{ + if (SetDictFromAny(interp, objPtr) != JIM_OK) { + return JIM_ERR; + } + Jim_SetResult(interp, JimDictPatternMatch(interp, objPtr->internalRep.ptr, patternObjPtr, JimDictMatchKeys, 0)); + return JIM_OK; +} + +int Jim_DictValues(Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj *patternObjPtr) +{ + if (SetDictFromAny(interp, objPtr) != JIM_OK) { + return JIM_ERR; + } + Jim_SetResult(interp, JimDictPatternMatch(interp, objPtr->internalRep.ptr, patternObjPtr, JimDictMatchKeys, JIM_DICTMATCH_VALUES)); return JIM_OK; } @@ -17441,7 +18180,7 @@ if (argc == 2) { return JIM_OK; } - else if (argv[2]->typePtr != &dictObjType && SetDictFromAny(interp, argv[2]) != JIM_OK) { + else if (SetDictFromAny(interp, argv[2]) != JIM_OK) { return JIM_ERR; } else { @@ -17522,18 +18261,29 @@ int mode = 0; static const char * const commands[] = { - "body", "commands", "procs", "channels", "exists", "globals", "level", "frame", "locals", + "body", "statics", "commands", "procs", "channels", "exists", "globals", "level", "frame", "locals", "vars", "version", "patchlevel", "complete", "args", "hostname", "script", "source", "stacktrace", "nameofexecutable", "returncodes", - "references", NULL + "references", "alias", NULL }; enum - { INFO_BODY, INFO_COMMANDS, INFO_PROCS, INFO_CHANNELS, INFO_EXISTS, INFO_GLOBALS, INFO_LEVEL, + { 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_RETURNCODES, INFO_REFERENCES, INFO_ALIAS }; +#ifdef jim_ext_namespace + int nons = 0; + + if (argc > 2 && Jim_CompareStringImmediate(interp, argv[1], "-nons")) { + + argc--; + argv++; + nons = 1; + } +#endif + if (argc < 2) { Jim_WrongNumArgs(interp, 1, argv, "subcommand ?args ...?"); return JIM_ERR; @@ -17545,28 +18295,54 @@ switch (cmd) { - case INFO_EXISTS:{ - if (argc != 3) { - Jim_WrongNumArgs(interp, 2, argv, "varName"); - return JIM_ERR; - } - Jim_SetResultBool(interp, Jim_GetVariable(interp, argv[2], 0) != NULL); - break; + case INFO_EXISTS: + if (argc != 3) { + Jim_WrongNumArgs(interp, 2, argv, "varName"); + return JIM_ERR; + } + Jim_SetResultBool(interp, Jim_GetVariable(interp, argv[2], 0) != NULL); + break; + + case INFO_ALIAS:{ + Jim_Cmd *cmdPtr; + + if (argc != 3) { + Jim_WrongNumArgs(interp, 2, argv, "command"); + return JIM_ERR; + } + if ((cmdPtr = Jim_GetCommand(interp, argv[2], JIM_ERRMSG)) == NULL) { + return JIM_ERR; + } + if (cmdPtr->isproc || cmdPtr->u.native.cmdProc != JimAliasCmd) { + Jim_SetResultFormatted(interp, "command \"%#s\" is not an alias", argv[2]); + return JIM_ERR; } + Jim_SetResult(interp, (Jim_Obj *)cmdPtr->u.native.privData); + return JIM_OK; + } case INFO_CHANNELS: + mode++; #ifndef jim_ext_aio Jim_SetResultString(interp, "aio not enabled", -1); return JIM_ERR; #endif - case INFO_COMMANDS: case INFO_PROCS: + mode++; + case INFO_COMMANDS: + if (argc != 2 && argc != 3) { Jim_WrongNumArgs(interp, 2, argv, "?pattern?"); return JIM_ERR; } - Jim_SetResult(interp, JimCommandsList(interp, (argc == 3) ? argv[2] : NULL, - (cmd - INFO_COMMANDS))); +#ifdef jim_ext_namespace + if (!nons) { + if (Jim_Length(interp->framePtr->nsObj) || (argc == 3 && JimGlobMatch("::*", Jim_String(argv[2]), 0))) { + return Jim_EvalPrefix(interp, "namespace info", argc - 1, argv + 1); + } + } +#endif + Jim_SetResult(interp, JimCommandsList(interp, (argc == 3) ? argv[2] : NULL, mode)); break; case INFO_VARS: @@ -17579,6 +18355,13 @@ Jim_WrongNumArgs(interp, 2, argv, "?pattern?"); return JIM_ERR; } +#ifdef jim_ext_namespace + if (!nons) { + if (Jim_Length(interp->framePtr->nsObj) || (argc == 3 && JimGlobMatch("::*", Jim_String(argv[2]), 0))) { + return Jim_EvalPrefix(interp, "namespace info", argc - 1, argv + 1); + } + } +#endif Jim_SetResult(interp, JimVariablesList(interp, argc == 3 ? argv[2] : NULL, mode)); break; @@ -17606,7 +18389,7 @@ else if (argv[2]->typePtr == &scriptObjType) { ScriptObj *script = Jim_GetScript(interp, argv[2]); fileNameObj = script->fileNameObj; - line = script->line; + line = script->firstline; } else { fileNameObj = interp->emptyObj; @@ -17644,6 +18427,7 @@ break; case INFO_BODY: + case INFO_STATICS: case INFO_ARGS:{ Jim_Cmd *cmdPtr; @@ -17658,8 +18442,21 @@ Jim_SetResultFormatted(interp, "command \"%#s\" is not a procedure", argv[2]); return JIM_ERR; } - Jim_SetResult(interp, - cmd == INFO_BODY ? cmdPtr->u.proc.bodyObjPtr : cmdPtr->u.proc.argListObjPtr); + switch (cmd) { + case INFO_BODY: + Jim_SetResult(interp, cmdPtr->u.proc.bodyObjPtr); + break; + case INFO_ARGS: + Jim_SetResult(interp, cmdPtr->u.proc.argListObjPtr); + break; + case INFO_STATICS: + if (cmdPtr->u.proc.staticVars) { + int mode = JIM_VARLIST_LOCALS | JIM_VARLIST_VALUES; + Jim_SetResult(interp, JimHashtablePatternMatch(interp, cmdPtr->u.proc.staticVars, + NULL, JimVariablesMatch, mode)); + } + break; + } break; } @@ -17745,13 +18542,14 @@ static int Jim_ExistsCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { Jim_Obj *objPtr; + int result = 0; static const char * const options[] = { - "-command", "-proc", "-var", NULL + "-command", "-proc", "-alias", "-var", NULL }; enum { - OPT_COMMAND, OPT_PROC, OPT_VAR + OPT_COMMAND, OPT_PROC, OPT_ALIAS, OPT_VAR }; int option; @@ -17770,19 +18568,30 @@ return JIM_ERR; } - - switch (option) { - case OPT_VAR: - Jim_SetResultBool(interp, Jim_GetVariable(interp, objPtr, 0) != NULL); - break; + if (option == OPT_VAR) { + result = Jim_GetVariable(interp, objPtr, 0) != NULL; + } + else { + + Jim_Cmd *cmd = Jim_GetCommand(interp, objPtr, JIM_NONE); - case OPT_COMMAND: - case OPT_PROC: { - Jim_Cmd *cmd = Jim_GetCommand(interp, objPtr, JIM_NONE); - Jim_SetResultBool(interp, cmd != NULL && (option == OPT_COMMAND || cmd->isproc)); - break; + if (cmd) { + switch (option) { + case OPT_COMMAND: + result = 1; + break; + + case OPT_ALIAS: + result = cmd->isproc == 0 && cmd->u.native.cmdProc == JimAliasCmd; + break; + + case OPT_PROC: + result = cmd->isproc; + break; + } } } + Jim_SetResultBool(interp, result); return JIM_OK; } @@ -17876,8 +18685,7 @@ static int Jim_JoinCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { const char *joinStr; - int joinStrLen, i, listLen; - Jim_Obj *resObjPtr; + int joinStrLen; if (argc != 2 && argc != 3) { Jim_WrongNumArgs(interp, 1, argv, "list ?joinString?"); @@ -17891,19 +18699,7 @@ else { joinStr = Jim_GetString(argv[2], &joinStrLen); } - listLen = Jim_ListLength(interp, argv[1]); - resObjPtr = Jim_NewStringObj(interp, NULL, 0); - - for (i = 0; i < listLen; i++) { - Jim_Obj *objPtr = 0; - - Jim_ListIndex(interp, argv[1], i, &objPtr, JIM_NONE); - Jim_AppendObj(interp, resObjPtr, objPtr); - if (i + 1 != listLen) { - Jim_AppendString(interp, resObjPtr, joinStr, joinStrLen); - } - } - Jim_SetResult(interp, resObjPtr); + Jim_SetResult(interp, Jim_ListJoin(interp, argv[1], joinStr, joinStrLen)); return JIM_OK; } @@ -18256,6 +19052,7 @@ const char *name; Jim_CmdProc cmdProc; } Jim_CoreCommandsTable[] = { + {"alias", Jim_AliasCoreCommand}, {"set", Jim_SetCoreCommand}, {"unset", Jim_UnsetCoreCommand}, {"puts", Jim_PutsCoreCommand}, @@ -18269,6 +19066,7 @@ {"for", Jim_ForCoreCommand}, {"foreach", Jim_ForeachCoreCommand}, {"lmap", Jim_LmapCoreCommand}, + {"lassign", Jim_LassignCoreCommand}, {"if", Jim_IfCoreCommand}, {"switch", Jim_SwitchCoreCommand}, {"list", Jim_ListCoreCommand}, @@ -18323,6 +19121,7 @@ {"tailcall", Jim_TailcallCoreCommand}, {"local", Jim_LocalCoreCommand}, {"upcall", Jim_UpcallCoreCommand}, + {"apply", Jim_ApplyCoreCommand}, {NULL, NULL}, }; @@ -18560,7 +19359,7 @@ static void set_wrong_args(Jim_Interp *interp, const jim_subcmd_type * command_table, Jim_Obj *subcmd) { - Jim_SetResultString(interp, "wrong # args: must be \"", -1); + Jim_SetResultString(interp, "wrong # args: should be \"", -1); add_cmd_usage(interp, command_table, subcmd); Jim_AppendStrings(interp, Jim_GetResult(interp), "\"", NULL); } @@ -18657,7 +19456,7 @@ if (argc - 2 < ct->minargs || (ct->maxargs >= 0 && argc - 2 > ct->maxargs)) { - Jim_SetResultString(interp, "wrong # args: must be \"", -1); + Jim_SetResultString(interp, "wrong # args: should be \"", -1); add_cmd_usage(interp, ct, argv[0]); Jim_AppendStrings(interp, Jim_GetResult(interp), "\"", NULL); @@ -18703,7 +19502,7 @@ #include -int utf8_fromunicode(char *p, unsigned short uc) +int utf8_fromunicode(char *p, unsigned uc) { if (uc <= 0x7f) { *p = uc; @@ -18714,12 +19513,20 @@ *p = 0x80 | (uc & 0x3f); return 2; } - else { + else if (uc <= 0xffff) { *p++ = 0xe0 | ((uc & 0xf000) >> 12); *p++ = 0x80 | ((uc & 0xfc0) >> 6); *p = 0x80 | (uc & 0x3f); return 3; } + + else { + *p++ = 0xf0 | ((uc & 0x1c0000) >> 18); + *p++ = 0x80 | ((uc & 0x3f000) >> 12); + *p++ = 0x80 | ((uc & 0xfc0) >> 6); + *p = 0x80 | (uc & 0x3f); + return 4; + } } #include @@ -19102,10 +19909,12 @@ #define WORDA 15 #define WORDZ 16 +#define OPENNC 19 #define OPEN 20 -#define CLOSE (OPEN+REG_MAX_PAREN) +#define CLOSE (OPEN+REG_MAX_PAREN+1) #define CLOSE_END (CLOSE+REG_MAX_PAREN) +#define CLOSENC (CLOSE-1) #define REG_MAGIC 0xFADED00D @@ -19146,7 +19955,7 @@ #ifdef DEBUG -int regnarrate = 0; +static int regnarrate = 0; static void regdump(regex_t *preg); static const char *regprop( int op ); #endif @@ -19183,13 +19992,11 @@ preg->program = NULL; preg->proglen = 0; -#if 1 preg->proglen = (strlen(exp) + 1) * 5; preg->program = malloc(preg->proglen * sizeof(int)); if (preg->program == NULL) FAIL(preg, REG_ERR_NOMEM); -#endif regc(preg, REG_MAGIC); if (reg(preg, 0, &flags) == 0) { @@ -19252,7 +20059,14 @@ if (paren) { - parno = ++preg->re_nsub; + if (preg->regparse[0] == '?' && preg->regparse[1] == ':') { + + preg->regparse += 2; + parno = -1; + } + else { + parno = ++preg->re_nsub; + } ret = regnode(preg, OPEN+parno); } else ret = 0; @@ -19499,10 +20313,25 @@ case 't': *ch = '\t'; break; case 'v': *ch = '\v'; break; case 'u': - if ((n = parse_hex(s, 4, ch)) > 0) { + if (*s == '{') { + + n = parse_hex(s + 1, 6, ch); + if (n > 0 && s[n + 1] == '}' && *ch >= 0 && *ch <= 0x1fffff) { + s += n + 2; + } + else { + + *ch = 'u'; + } + } + else if ((n = parse_hex(s, 4, ch)) > 0) { s += n; } break; + case 'U': + if ((n = parse_hex(s, 8, ch)) > 0) { + s += n; + } case 'x': if ((n = parse_hex(s, 2, ch)) > 0) { s += n; @@ -19568,7 +20397,7 @@ return 0; } } - if (pattern[0] == '-' && pattern[1]) { + if (pattern[0] == '-' && pattern[1] && pattern[1] != ']') { pattern += utf8_tounicode(pattern, &end); pattern += reg_utf8_tounicode_case(pattern, &end, nocase); @@ -19843,13 +20672,30 @@ preg->start = string; - for (scan = OPERAND(1); scan != 0; scan = regnext(preg, scan)) { + for (scan = OPERAND(1); scan != 0; ) { switch (OP(preg, scan)) { case REP: case REPMIN: case REPX: case REPXMIN: preg->program[scan + 4] = 0; + scan += 5; + break; + + case ANYOF: + case ANYBUT: + case EXACTLY: + scan += 2; + while (preg->program[scan++]) { + } + break; + + case END: + scan = 0; + break; + + default: + scan += 2; break; } } @@ -19877,8 +20723,7 @@ goto nextline; } while (1) { - int ret = regtry(preg, string); - if (ret) { + if (regtry(preg, string)) { return REG_NOERROR; } if (*string) { @@ -19914,7 +20759,10 @@ if (*s == '\0') { break; } - s += utf8_charlen(*s); + else { + int c; + s += utf8_tounicode(s, &c); + } } @@ -20223,6 +21071,14 @@ case END: return(1); break; + + case OPENNC: + case CLOSENC: + if (regmatch(preg, next)) { + return 1; + } + return 0; + default: if (OP(preg, scan) >= OPEN+1 && OP(preg, scan) < CLOSE_END) { const char *save; @@ -20493,15 +21349,19 @@ #include #include + #ifdef USE_LINENOISE #include #include "linenoise.h" #else - #define MAX_LINE_LEN 512 +#endif -static char *linenoise(const char *prompt) +char *Jim_HistoryGetline(const char *prompt) { +#ifdef USE_LINENOISE + return linenoise(prompt); +#else char *line = malloc(MAX_LINE_LEN); fputs(prompt, stdout); @@ -20512,8 +21372,42 @@ return NULL; } return line; +#endif +} + +void Jim_HistoryLoad(const char *filename) +{ +#ifdef USE_LINENOISE + linenoiseHistoryLoad(filename); +#endif +} + +void Jim_HistoryAdd(const char *line) +{ +#ifdef USE_LINENOISE + linenoiseHistoryAdd(line); +#endif +} + +void Jim_HistorySave(const char *filename) +{ +#ifdef USE_LINENOISE + linenoiseHistorySave(filename); +#endif } + +void Jim_HistoryShow(void) +{ +#ifdef USE_LINENOISE + + int i; + int len; + char **history = linenoiseHistory(&len); + for (i = 0; i < len; i++) { + printf("%4d %s\n", i + 1, history[i]); + } #endif +} int Jim_InteractivePrompt(Jim_Interp *interp) { @@ -20527,7 +21421,7 @@ int history_len = strlen(home) + sizeof("/.jim_history"); history_file = Jim_Alloc(history_len); snprintf(history_file, history_len, "%s/.jim_history", home); - linenoiseHistoryLoad(history_file); + Jim_HistoryLoad(history_file); } #endif @@ -20564,12 +21458,13 @@ int len; char *line; - line = linenoise(prompt); + line = Jim_HistoryGetline(prompt); if (line == NULL) { if (errno == EINTR) { continue; } Jim_DecrRefCount(interp, scriptObjPtr); + retcode = JIM_OK; goto out; } if (Jim_Length(scriptObjPtr) != 0) { @@ -20589,29 +21484,22 @@ #ifdef USE_LINENOISE if (strcmp(str, "h") == 0) { - int i; - int len; - char **history = linenoiseHistory(&len); - for (i = 0; i < len; i++) { - printf("%4d %s\n", i + 1, history[i]); - } + Jim_HistoryShow(); Jim_DecrRefCount(interp, scriptObjPtr); continue; } - linenoiseHistoryAdd(Jim_String(scriptObjPtr)); + Jim_HistoryAdd(Jim_String(scriptObjPtr)); if (history_file) { - linenoiseHistorySave(history_file); + Jim_HistorySave(history_file); } #endif retcode = Jim_EvalObj(interp, scriptObjPtr); Jim_DecrRefCount(interp, scriptObjPtr); - - if (retcode == JIM_EXIT) { - Jim_Free(history_file); - return JIM_EXIT; + retcode = JIM_EXIT; + break; } if (retcode == JIM_ERR) { Jim_MakeErrorMessage(interp); @@ -20623,7 +21511,7 @@ } out: Jim_Free(history_file); - return JIM_OK; + return retcode; } #include diff -Nru jimtcl-0.73/autosetup/README.autosetup jimtcl-0.74/autosetup/README.autosetup --- jimtcl-0.73/autosetup/README.autosetup 2011-12-19 22:11:37.000000000 +0000 +++ jimtcl-0.74/autosetup/README.autosetup 2013-07-24 05:36:47.000000000 +0000 @@ -1 +1 @@ -This is autosetup v0.6.3. See http://msteveb.github.com/autosetup/ +This is autosetup v0.6.5. See http://msteveb.github.com/autosetup/ diff -Nru jimtcl-0.73/autosetup/system.tcl jimtcl-0.74/autosetup/system.tcl --- jimtcl-0.73/autosetup/system.tcl 2011-12-19 22:11:37.000000000 +0000 +++ jimtcl-0.74/autosetup/system.tcl 2013-07-24 05:36:47.000000000 +0000 @@ -217,7 +217,8 @@ } define cross [get-env CROSS $cross] -set prefix [opt-val prefix /usr/local] +# Do "define defaultprefix myvalue" to set the default prefix *before* the first "use" +set prefix [opt-val prefix [get-define defaultprefix /usr/local]] # These are for compatibility with autoconf define target [get-define host] @@ -254,7 +255,7 @@ # Windows vs. non-Windows switch -glob -- [get-define host] { - *-*-ming* - *-*-cygwin { + *-*-ming* - *-*-cygwin - *-*-msys { define-feature windows define EXEEXT .exe } diff -Nru jimtcl-0.73/binary.tcl jimtcl-0.74/binary.tcl --- jimtcl-0.73/binary.tcl 2011-12-19 22:11:37.000000000 +0000 +++ jimtcl-0.74/binary.tcl 2013-07-24 05:36:47.000000000 +0000 @@ -125,7 +125,7 @@ set n 1 } if {$n > $rembytes} { - continue + break } set var [binary.nextarg varName] @@ -148,7 +148,7 @@ } } if {$n * $size > $rembytes * 8} { - continue + break } if {$type ne "int"} { diff -Nru jimtcl-0.73/configure jimtcl-0.74/configure --- jimtcl-0.73/configure 2011-12-19 22:11:37.000000000 +0000 +++ jimtcl-0.74/configure 2013-07-24 05:36:47.000000000 +0000 @@ -1,3 +1,3 @@ #!/bin/sh dir="`dirname "$0"`/autosetup" -WRAPPER="$0" exec "`$dir/find-tclsh`" "$dir/autosetup" "$@" +WRAPPER="$0"; export WRAPPER; exec "`$dir/find-tclsh`" "$dir/autosetup" "$@" diff -Nru jimtcl-0.73/debian/changelog jimtcl-0.74/debian/changelog --- jimtcl-0.73/debian/changelog 2014-03-22 19:26:55.000000000 +0000 +++ jimtcl-0.74/debian/changelog 2014-04-14 07:02:34.000000000 +0000 @@ -1,8 +1,40 @@ -jimtcl (0.73-3ubuntu1) trusty; urgency=low +jimtcl (0.74-3) unstable; urgency=medium - * Use autotools-dev helper for arm64, resolving FTBFS. + * In autosetup, use config.guess and config.sub from autotools-dev + (Closes: #744441) - -- Daniel T Chen Sat, 22 Mar 2014 15:26:40 -0400 + -- Didier Raboud Mon, 14 Apr 2014 09:01:33 +0200 + +jimtcl (0.74-2) unstable; urgency=medium + + * Correct version number in 0.74-1 changelog entry + * Update debian/copyright for 0.74 (Closes: #738727) + - Add missing examples/dns.tcl license from src:tcllib + - Correct wrong apache-2.0 mentions; the files have been re-licensed + by upstream + - Update years + Thanks to Thorsten Alteholz + * Bump debhelper Build-Depends to 9, drop source lintian override + + -- Didier Raboud Wed, 12 Feb 2014 15:48:26 +0100 + +jimtcl (0.74-1) unstable; urgency=medium + + * New 0.74 upstream release. + - Space allocated for exec env may be one byte short + - Fix glob with patterns containing spaces + - Give libjim.so an soname + + * Update Homepage to cope with BerliOS closing. + * Append CPPFLAGS to CFLAGS + * Update Copyright-format Format URL + * Drop the two backported fixes from upstream + * Rename libjim0debian2 to libjim0.74 as upstream gave the library a + soname; also update the symbols' list + * Rewrite the workarounds to create libjim-dev's .so symlink + * Bump Standards-Version to 3.9.5 without changes needed + + -- Didier Raboud Mon, 10 Feb 2014 14:12:45 +0100 jimtcl (0.73-3) unstable; urgency=low diff -Nru jimtcl-0.73/debian/control jimtcl-0.74/debian/control --- jimtcl-0.73/debian/control 2014-03-22 19:27:20.000000000 +0000 +++ jimtcl-0.74/debian/control 2014-04-14 07:02:34.000000000 +0000 @@ -1,11 +1,13 @@ Source: jimtcl Section: devel Priority: extra -Maintainer: Ubuntu Developers -XSBC-Original-Maintainer: Didier Raboud -Build-Depends: debhelper (>= 8.9.0~), autotools-dev, dpkg-dev (>= 1.16.1), asciidoc -Standards-Version: 3.9.3 -Homepage: http://jim.berlios.de/ +Maintainer: Didier Raboud +Build-Depends: debhelper (>= 9), + autotools-dev, + dpkg-dev (>= 1.16.1), + asciidoc +Standards-Version: 3.9.5 +Homepage: http://jim.tcl.tk/ Vcs-Git: git://git.debian.org/collab-maint/jimtcl.git Vcs-Browser: http://git.debian.org/?p=collab-maint/jimtcl.git @@ -22,7 +24,7 @@ . This package provides the Jim interactive shell. -Package: libjim0debian2 +Package: libjim0.74 Architecture: any Section: libs Depends: ${shlibs:Depends}, ${misc:Depends} @@ -36,13 +38,12 @@ UTF-8 support. All this with a binary size of about 100-200kB (depending upon selected options). . - This package provides the libjim shared library, shipped with a - Debian-specific SONAME. + This package provides the libjim shared library. Package: libjim-dev Architecture: any Section: libdevel -Depends: libjim0debian2 (= ${binary:Version}), ${misc:Depends} +Depends: libjim0.74 (= ${binary:Version}), ${misc:Depends} Description: small-footprint implementation of Tcl - development files Jim is an opensource small-footprint implementation of the Tcl programming language. It implements a large subset of Tcl and adds new features like diff -Nru jimtcl-0.73/debian/copyright jimtcl-0.74/debian/copyright --- jimtcl-0.73/debian/copyright 2012-01-03 13:42:42.000000000 +0000 +++ jimtcl-0.74/debian/copyright 2014-02-12 14:51:33.000000000 +0000 @@ -1,33 +1,74 @@ -Format: http://dep.debian.net/deps/dep5 +Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ Upstream-Name: jimtcl Source: http://jim.berlios.de/ Files: * -Copyright: 2011 Salvatore Sanfilippo - 2011 Pat Thoyts - 2011 Øyvind Harboe - 2011 Andrew Lunn - 2011 Duane Ellis - 2011 Uwe Klein - 2011 Clemens Hintze -License: BSD-2-clause - -Files: jim-posix.c jim-readline.c jim-sdl.c jimsh.c jim-sqlite3.c jim-sqlite.c jim-win32.c Copyright: 2005 Salvatore Sanfilippo - 2005 Pat Thoyts - 2009 Steve Bennett -License: Apache-2.0 - On Debian systems, the complete text of the Apache 2.0 license - can be found in "/usr/share/common-licenses/Apache-2.0". + 2005 Clemens Hintze + 2005 patthoyts - Pat Thoyts + 2008 oharboe - Øyvind Harboe - oyvind.harboe@zylin.com + 2008 Andrew Lunn + 2008 Duane Ellis + 2008 Uwe Klein + 2008 Steve Bennett + 2009 Nico Coesel + 2009 Zachary T Welch zw@superlucidity.net + 2009 David Brownell +License: BSD-2-clause Files: autosetup/ Copyright: 2006-2011, WorkWare Systems License: BSD-2-clause +Files: examples/dns.tcl +Copyright: 2000-2007 Ajuba Solutions and other parties + 2002 Pat Thoyts +Comment: This license text is not directly available from the jimtcl + source package; it comes from tcllib. +License: TCL + This software is copyrighted by Ajuba Solutions and other parties. + The following terms apply to all files associated with the software unless + explicitly disclaimed in individual files. + . + The authors hereby grant permission to use, copy, modify, distribute, + and license this software and its documentation for any purpose, provided + that existing copyright notices are retained in all copies and that this + notice is included verbatim in any distributions. No written agreement, + license, or royalty fee is required for any of the authorized uses. + Modifications to this software may be copyrighted by their authors + and need not follow the licensing terms described here, provided that + the new terms are clearly indicated on the first page of each file where + they apply. + . + IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY + FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY + DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. + . + THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. THIS SOFTWARE + IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE + NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR + MODIFICATIONS. + . + GOVERNMENT USE: If you are acquiring this software on behalf of the + U.S. government, the Government shall have only "Restricted Rights" + in the software and related documentation as defined in the Federal + Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you + are acquiring the software on behalf of the Department of Defense, the + software shall be classified as "Commercial Computer Software" and the + Government shall have only "Restricted Rights" as defined in Clause + 252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the + authors grant the U.S. Government and others acting in its behalf + permission to use and distribute the software in accordance with the + terms specified in this license. + Files: debian/ Copyright: 2011 Edgar Grimberg 2011 Steve Bennett - 2011 Didier Raboud + 2011-2014 Didier Raboud License: BSD-2-clause License: BSD-2-clause diff -Nru jimtcl-0.73/debian/libjim0.74.install jimtcl-0.74/debian/libjim0.74.install --- jimtcl-0.73/debian/libjim0.74.install 1970-01-01 00:00:00.000000000 +0000 +++ jimtcl-0.74/debian/libjim0.74.install 2014-02-10 13:16:31.000000000 +0000 @@ -0,0 +1 @@ +usr/lib/*/libjim.so.* diff -Nru jimtcl-0.73/debian/libjim0.74.symbols jimtcl-0.74/debian/libjim0.74.symbols --- jimtcl-0.73/debian/libjim0.74.symbols 1970-01-01 00:00:00.000000000 +0000 +++ jimtcl-0.74/debian/libjim0.74.symbols 2014-02-10 13:16:31.000000000 +0000 @@ -0,0 +1,203 @@ +libjim.so.0.74 libjim0.74 #MINVER# + JimCanonicalNamespace@Base 0.73 + JimStringReplaceObj@Base 0.73 + Jim_AddHashEntry@Base 0.72 + Jim_AioFilehandle@Base 0.72 + Jim_Alloc@Base 0.72 + Jim_AppendObj@Base 0.72 + Jim_AppendString@Base 0.72 + Jim_AppendStrings@Base 0.72 + Jim_CallSubCmd@Base 0.72 + Jim_Collect@Base 0.72 + Jim_CollectIfNeeded@Base 0.72 + Jim_CommandMatchObj@Base 0.72 + Jim_CompareStringImmediate@Base 0.72 + Jim_ConcatObj@Base 0.72 + Jim_CreateCommand@Base 0.72 + Jim_CreateFileHandler@Base 0.72 + Jim_CreateInterp@Base 0.72 + Jim_CreateNamespaceVariable@Base 0.73 + Jim_CreateTimeHandler@Base 0.72 + Jim_DeleteAssocData@Base 0.72 + Jim_DeleteCommand@Base 0.72 + Jim_DeleteFileHandler@Base 0.72 + Jim_DeleteHashEntry@Base 0.72 + Jim_DeleteTimeHandler@Base 0.72 + Jim_DictAddElement@Base 0.72 + Jim_DictKey@Base 0.72 + Jim_DictKeys@Base 0.72 + Jim_DictKeysVector@Base 0.72 + Jim_DictPairs@Base 0.72 + Jim_DictSize@Base 0.72 + Jim_DictValues@Base 0.73 + Jim_DoubleToString@Base 0.72 + Jim_DuplicateObj@Base 0.72 + Jim_Eval@Base 0.72 + Jim_EvalExpression@Base 0.72 + Jim_EvalFile@Base 0.72 + Jim_EvalFileGlobal@Base 0.72 + Jim_EvalGlobal@Base 0.72 + Jim_EvalNamespace@Base 0.73 + Jim_EvalObj@Base 0.72 + Jim_EvalObjBackground@Base 0.72 + Jim_EvalObjList@Base 0.73 + Jim_EvalObjPrefix@Base 0.72 + Jim_EvalObjVector@Base 0.72 + Jim_EvalSource@Base 0.72 + Jim_ExpandHashTable@Base 0.72 + Jim_FindByName@Base 0.72 + Jim_FindHashEntry@Base 0.72 + Jim_FormatString@Base 0.72 + Jim_Free@Base 0.72 + Jim_FreeHashTable@Base 0.72 + Jim_FreeInterp@Base 0.72 + Jim_FreeLoadHandles@Base 0.72 + Jim_FreeObj@Base 0.72 + Jim_FreeStack@Base 0.72 + Jim_FreeStackElements@Base 0.72 + Jim_GenHashFunction@Base 0.72 + Jim_GetAssocData@Base 0.72 + Jim_GetBoolFromExpr@Base 0.72 + Jim_GetCallFrameByLevel@Base 0.72 + Jim_GetCommand@Base 0.72 + Jim_GetDouble@Base 0.72 + Jim_GetEnum@Base 0.72 + Jim_GetEnviron@Base 0.72 + Jim_GetExitCode@Base 0.72 + Jim_GetFinalizer@Base 0.72 + Jim_GetGlobalVariable@Base 0.72 + Jim_GetGlobalVariableStr@Base 0.72 + Jim_GetHashTableIterator@Base 0.72 + Jim_GetIndex@Base 0.72 + Jim_GetLong@Base 0.72 + Jim_GetReference@Base 0.72 + Jim_GetReturnCode@Base 0.72 + Jim_GetScript@Base 0.72 + Jim_GetString@Base 0.72 + Jim_GetVariable@Base 0.72 + Jim_GetVariableStr@Base 0.72 + Jim_GetWide@Base 0.72 + Jim_HistoryAdd@Base 0.73 + Jim_HistoryGetline@Base 0.73 + Jim_HistoryLoad@Base 0.73 + Jim_HistorySave@Base 0.73 + Jim_HistoryShow@Base 0.73 + Jim_InitHashTable@Base 0.72 + Jim_InitStack@Base 0.72 + Jim_InitStaticExtensions@Base 0.72 + Jim_IntHashFunction@Base 0.72 + Jim_InteractivePrompt@Base 0.72 + Jim_InvalidateStringRep@Base 0.72 + Jim_IsDict@Base 0.72 + Jim_IsList@Base 0.72 + Jim_Length@Base 0.72 + Jim_ListAppendElement@Base 0.72 + Jim_ListAppendList@Base 0.72 + Jim_ListGetIndex@Base 0.73 + Jim_ListIndex@Base 0.72 + Jim_ListInsertElements@Base 0.72 + Jim_ListJoin@Base 0.73 + Jim_ListLength@Base 0.72 + Jim_ListRange@Base 0.72 + Jim_LoadLibrary@Base 0.72 + Jim_MakeErrorMessage@Base 0.72 + Jim_NamespaceQualifiers@Base 0.73 + Jim_NamespaceTail@Base 0.73 + Jim_NewDictObj@Base 0.72 + Jim_NewDoubleObj@Base 0.72 + Jim_NewIntObj@Base 0.72 + Jim_NewListObj@Base 0.72 + Jim_NewObj@Base 0.72 + Jim_NewReference@Base 0.72 + Jim_NewStringObj@Base 0.72 + Jim_NewStringObjNoAlloc@Base 0.72 + Jim_NewStringObjUtf8@Base 0.72 + Jim_NextHashEntry@Base 0.72 + Jim_PackageProvide@Base 0.72 + Jim_PackageRequire@Base 0.72 + Jim_ParseSubCmd@Base 0.72 + Jim_ProcessEvents@Base 0.72 + Jim_ReaddirCmd@Base 0.72 + Jim_Realloc@Base 0.72 + Jim_RegexpCmd@Base 0.72 + Jim_RegisterCoreCommands@Base 0.72 + Jim_RegsubCmd@Base 0.72 + Jim_RenameCommand@Base 0.72 + Jim_ReplaceHashEntry@Base 0.72 + Jim_ResizeHashTable@Base 0.72 + Jim_ReturnCode@Base 0.72 + Jim_ScanString@Base 0.72 + Jim_ScriptIsComplete@Base 0.72 + Jim_SetAssocData@Base 0.72 + Jim_SetDictKeysVector@Base 0.72 + Jim_SetEnviron@Base 0.72 + Jim_SetFinalizer@Base 0.72 + Jim_SetGlobalVariableStr@Base 0.72 + Jim_SetListIndex@Base 0.72 + Jim_SetResultFormatted@Base 0.72 + Jim_SetVariable@Base 0.72 + Jim_SetVariableLink@Base 0.72 + Jim_SetVariableStr@Base 0.72 + Jim_SetVariableStrWithStr@Base 0.72 + Jim_SignalId@Base 0.72 + Jim_SignalName@Base 0.72 + Jim_StackLen@Base 0.72 + Jim_StackPeek@Base 0.72 + Jim_StackPop@Base 0.72 + Jim_StackPush@Base 0.72 + Jim_StrDup@Base 0.72 + Jim_StrDupLen@Base 0.72 + Jim_String@Base 0.73 + Jim_StringByteRangeObj@Base 0.72 + Jim_StringCompareLenObj@Base 0.73 + Jim_StringCompareObj@Base 0.72 + Jim_StringEqObj@Base 0.72 + Jim_StringMatchObj@Base 0.72 + Jim_StringRangeObj@Base 0.72 + Jim_StringToDouble@Base 0.72 + Jim_StringToWide@Base 0.72 + Jim_SubCmdProc@Base 0.72 + Jim_SubstObj@Base 0.72 + Jim_SyslogCmd@Base 0.72 + Jim_UnsetVariable@Base 0.72 + Jim_Utf8Length@Base 0.72 + Jim_WrongNumArgs@Base 0.72 + Jim_aioInit@Base 0.72 + Jim_arrayInit@Base 0.72 + Jim_binaryInit@Base 0.73 + Jim_clockInit@Base 0.72 + Jim_eventloopInit@Base 0.72 + Jim_execInit@Base 0.72 + Jim_fileInit@Base 0.72 + Jim_globInit@Base 0.72 + Jim_historyInit@Base 0.73 + Jim_loadInit@Base 0.72 + Jim_namespaceInit@Base 0.73 + Jim_nshelperInit@Base 0.73 + Jim_ooInit@Base 0.73 + Jim_packInit@Base 0.73 + Jim_packageInit@Base 0.72 + Jim_posixInit@Base 0.72 + Jim_readdirInit@Base 0.72 + Jim_regexpInit@Base 0.72 + Jim_signalInit@Base 0.72 + Jim_stdlibInit@Base 0.72 + Jim_syslogInit@Base 0.72 + Jim_tclcompatInit@Base 0.72 + Jim_tclprefixInit@Base 0.73 + Jim_treeInit@Base 0.73 + jim_tt_name@Base 0.72 + linenoise@Base 0.72 + linenoiseColumns@Base 0.74 + linenoiseHistory@Base 0.72 + linenoiseHistoryAdd@Base 0.72 + linenoiseHistoryFree@Base 0.72 + linenoiseHistoryGetMaxLen@Base 0.74 + linenoiseHistoryLoad@Base 0.72 + linenoiseHistorySave@Base 0.72 + linenoiseHistorySetMaxLen@Base 0.72 + regcomp@Base 0.73 + regerror@Base 0.73 + regexec@Base 0.73 + regfree@Base 0.73 + utf8_fromunicode@Base 0.72 diff -Nru jimtcl-0.73/debian/libjim0debian2.install jimtcl-0.74/debian/libjim0debian2.install --- jimtcl-0.73/debian/libjim0debian2.install 2012-01-03 14:18:04.000000000 +0000 +++ jimtcl-0.74/debian/libjim0debian2.install 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -usr/lib/*/libjim.so.* diff -Nru jimtcl-0.73/debian/libjim0debian2.symbols jimtcl-0.74/debian/libjim0debian2.symbols --- jimtcl-0.73/debian/libjim0debian2.symbols 2012-01-03 14:18:04.000000000 +0000 +++ jimtcl-0.74/debian/libjim0debian2.symbols 1970-01-01 00:00:00.000000000 +0000 @@ -1,203 +0,0 @@ -libjim.so.0debian2 libjim0debian2 #MINVER# - JimCanonicalNamespace@Base 0.73 - JimStringReplaceObj@Base 0.73 - Jim_AddHashEntry@Base 0.72 - Jim_AioFilehandle@Base 0.72 - Jim_Alloc@Base 0.72 - Jim_AppendObj@Base 0.72 - Jim_AppendString@Base 0.72 - Jim_AppendStrings@Base 0.72 - Jim_CallSubCmd@Base 0.72 - Jim_Collect@Base 0.72 - Jim_CollectIfNeeded@Base 0.72 - Jim_CommandMatchObj@Base 0.72 - Jim_CompareStringImmediate@Base 0.72 - Jim_ConcatObj@Base 0.72 - Jim_CreateCommand@Base 0.72 - Jim_CreateFileHandler@Base 0.72 - Jim_CreateInterp@Base 0.72 - Jim_CreateNamespaceVariable@Base 0.73 - Jim_CreateTimeHandler@Base 0.72 - Jim_DeleteAssocData@Base 0.72 - Jim_DeleteCommand@Base 0.72 - Jim_DeleteFileHandler@Base 0.72 - Jim_DeleteHashEntry@Base 0.72 - Jim_DeleteTimeHandler@Base 0.72 - Jim_DictAddElement@Base 0.72 - Jim_DictKey@Base 0.72 - Jim_DictKeys@Base 0.72 - Jim_DictKeysVector@Base 0.72 - Jim_DictPairs@Base 0.72 - Jim_DictSize@Base 0.72 - Jim_DictValues@Base 0.73 - Jim_DoubleToString@Base 0.72 - Jim_DuplicateObj@Base 0.72 - Jim_Eval@Base 0.72 - Jim_EvalExpression@Base 0.72 - Jim_EvalFile@Base 0.72 - Jim_EvalFileGlobal@Base 0.72 - Jim_EvalGlobal@Base 0.72 - Jim_EvalNamespace@Base 0.73 - Jim_EvalObj@Base 0.72 - Jim_EvalObjBackground@Base 0.72 - Jim_EvalObjList@Base 0.73 - Jim_EvalObjPrefix@Base 0.72 - Jim_EvalObjVector@Base 0.72 - Jim_EvalSource@Base 0.72 - Jim_ExpandHashTable@Base 0.72 - Jim_FindByName@Base 0.72 - Jim_FindHashEntry@Base 0.72 - Jim_FormatString@Base 0.72 - Jim_Free@Base 0.72 - Jim_FreeHashTable@Base 0.72 - Jim_FreeInterp@Base 0.72 - Jim_FreeLoadHandles@Base 0.72 - Jim_FreeObj@Base 0.72 - Jim_FreeStack@Base 0.72 - Jim_FreeStackElements@Base 0.72 - Jim_GenHashFunction@Base 0.72 - Jim_GetAssocData@Base 0.72 - Jim_GetBoolFromExpr@Base 0.72 - Jim_GetCallFrameByLevel@Base 0.72 - Jim_GetCommand@Base 0.72 - Jim_GetDouble@Base 0.72 - Jim_GetEnum@Base 0.72 - Jim_GetEnviron@Base 0.72 - Jim_GetExitCode@Base 0.72 - Jim_GetFinalizer@Base 0.72 - Jim_GetGlobalVariable@Base 0.72 - Jim_GetGlobalVariableStr@Base 0.72 - Jim_GetHashTableIterator@Base 0.72 - Jim_GetIndex@Base 0.72 - Jim_GetLong@Base 0.72 - Jim_GetReference@Base 0.72 - Jim_GetReturnCode@Base 0.72 - Jim_GetScript@Base 0.72 - Jim_GetString@Base 0.72 - Jim_GetVariable@Base 0.72 - Jim_GetVariableStr@Base 0.72 - Jim_GetWide@Base 0.72 - Jim_HistoryAdd@Base 0.73 - Jim_HistoryGetline@Base 0.73 - Jim_HistoryLoad@Base 0.73 - Jim_HistorySave@Base 0.73 - Jim_HistoryShow@Base 0.73 - Jim_InitHashTable@Base 0.72 - Jim_InitStack@Base 0.72 - Jim_InitStaticExtensions@Base 0.72 - Jim_InitStringRep@Base 0.72 - Jim_IntHashFunction@Base 0.72 - Jim_InteractivePrompt@Base 0.72 - Jim_InvalidateStringRep@Base 0.72 - Jim_IsDict@Base 0.72 - Jim_IsList@Base 0.72 - Jim_Length@Base 0.72 - Jim_ListAppendElement@Base 0.72 - Jim_ListAppendList@Base 0.72 - Jim_ListGetIndex@Base 0.73 - Jim_ListIndex@Base 0.72 - Jim_ListInsertElements@Base 0.72 - Jim_ListJoin@Base 0.73 - Jim_ListLength@Base 0.72 - Jim_ListRange@Base 0.72 - Jim_LoadLibrary@Base 0.72 - Jim_MakeErrorMessage@Base 0.72 - Jim_NamespaceQualifiers@Base 0.73 - Jim_NamespaceTail@Base 0.73 - Jim_NewDictObj@Base 0.72 - Jim_NewDoubleObj@Base 0.72 - Jim_NewIntObj@Base 0.72 - Jim_NewListObj@Base 0.72 - Jim_NewObj@Base 0.72 - Jim_NewReference@Base 0.72 - Jim_NewStringObj@Base 0.72 - Jim_NewStringObjNoAlloc@Base 0.72 - Jim_NewStringObjUtf8@Base 0.72 - Jim_NextHashEntry@Base 0.72 - Jim_PackageProvide@Base 0.72 - Jim_PackageRequire@Base 0.72 - Jim_ParseSubCmd@Base 0.72 - Jim_ProcessEvents@Base 0.72 - Jim_ReaddirCmd@Base 0.72 - Jim_Realloc@Base 0.72 - Jim_RegexpCmd@Base 0.72 - Jim_RegisterCoreCommands@Base 0.72 - Jim_RegsubCmd@Base 0.72 - Jim_RenameCommand@Base 0.72 - Jim_ReplaceHashEntry@Base 0.72 - Jim_ResizeHashTable@Base 0.72 - Jim_ReturnCode@Base 0.72 - Jim_ScanString@Base 0.72 - Jim_ScriptIsComplete@Base 0.72 - Jim_SetAssocData@Base 0.72 - Jim_SetDictKeysVector@Base 0.72 - Jim_SetEnviron@Base 0.72 - Jim_SetFinalizer@Base 0.72 - Jim_SetGlobalVariableStr@Base 0.72 - Jim_SetListIndex@Base 0.72 - Jim_SetResultFormatted@Base 0.72 - Jim_SetVariable@Base 0.72 - Jim_SetVariableLink@Base 0.72 - Jim_SetVariableStr@Base 0.72 - Jim_SetVariableStrWithStr@Base 0.72 - Jim_SignalId@Base 0.72 - Jim_SignalName@Base 0.72 - Jim_StackLen@Base 0.72 - Jim_StackPeek@Base 0.72 - Jim_StackPop@Base 0.72 - Jim_StackPush@Base 0.72 - Jim_StrDup@Base 0.72 - Jim_StrDupLen@Base 0.72 - Jim_String@Base 0.73 - Jim_StringByteRangeObj@Base 0.72 - Jim_StringCompareLenObj@Base 0.73 - Jim_StringCompareObj@Base 0.72 - Jim_StringEqObj@Base 0.72 - Jim_StringMatchObj@Base 0.72 - Jim_StringRangeObj@Base 0.72 - Jim_StringToDouble@Base 0.72 - Jim_StringToWide@Base 0.72 - Jim_SubCmdProc@Base 0.72 - Jim_SubstObj@Base 0.72 - Jim_SyslogCmd@Base 0.72 - Jim_UnsetVariable@Base 0.72 - Jim_Utf8Length@Base 0.72 - Jim_WideToString@Base 0.72 - Jim_WrongNumArgs@Base 0.72 - Jim_aioInit@Base 0.72 - Jim_arrayInit@Base 0.72 - Jim_binaryInit@Base 0.73 - Jim_clockInit@Base 0.72 - Jim_eventloopInit@Base 0.72 - Jim_execInit@Base 0.72 - Jim_fileInit@Base 0.72 - Jim_globInit@Base 0.72 - Jim_historyInit@Base 0.73 - Jim_loadInit@Base 0.72 - Jim_namespaceInit@Base 0.73 - Jim_nshelperInit@Base 0.73 - Jim_ooInit@Base 0.73 - Jim_packInit@Base 0.73 - Jim_packageInit@Base 0.72 - Jim_posixInit@Base 0.72 - Jim_readdirInit@Base 0.72 - Jim_regexpInit@Base 0.72 - Jim_signalInit@Base 0.72 - Jim_stdlibInit@Base 0.72 - Jim_syslogInit@Base 0.72 - Jim_tclcompatInit@Base 0.72 - Jim_tclprefixInit@Base 0.73 - Jim_treeInit@Base 0.73 - jim_tt_name@Base 0.72 - linenoise@Base 0.72 - linenoiseHistory@Base 0.72 - linenoiseHistoryAdd@Base 0.72 - linenoiseHistoryFree@Base 0.72 - linenoiseHistoryLoad@Base 0.72 - linenoiseHistorySave@Base 0.72 - linenoiseHistorySetMaxLen@Base 0.72 - regcomp@Base 0.73 - regerror@Base 0.73 - regexec@Base 0.73 - regfree@Base 0.73 - utf8_fromunicode@Base 0.72 diff -Nru jimtcl-0.73/debian/libjim-dev.install jimtcl-0.74/debian/libjim-dev.install --- jimtcl-0.73/debian/libjim-dev.install 2012-06-19 06:53:56.000000000 +0000 +++ jimtcl-0.74/debian/libjim-dev.install 2014-02-10 13:16:31.000000000 +0000 @@ -1,3 +1,2 @@ usr/include/jim* -usr/lib/*/libjim.so usr/lib/*/libjim.a diff -Nru jimtcl-0.73/debian/patches/series jimtcl-0.74/debian/patches/series --- jimtcl-0.73/debian/patches/series 2012-01-30 22:22:58.000000000 +0000 +++ jimtcl-0.74/debian/patches/series 1970-01-01 00:00:00.000000000 +0000 @@ -1,2 +0,0 @@ -u695c66c_Fix-glob-with-patterns-containing-spaces.patch -ub5fcd96_Space-allocated-for-exec-env-may-be-one-byte-short.patch diff -Nru jimtcl-0.73/debian/patches/u695c66c_Fix-glob-with-patterns-containing-spaces.patch jimtcl-0.74/debian/patches/u695c66c_Fix-glob-with-patterns-containing-spaces.patch --- jimtcl-0.73/debian/patches/u695c66c_Fix-glob-with-patterns-containing-spaces.patch 2012-01-30 22:22:58.000000000 +0000 +++ jimtcl-0.74/debian/patches/u695c66c_Fix-glob-with-patterns-containing-spaces.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,26 +0,0 @@ -commit 695c66cf85db881c430ccb0c54d41678ef770c33 -Author: Steve Bennett -Date: Sun Jan 29 08:37:08 2012 +1000 - - Fix glob with patterns containing spaces - - Signed-off-by: Steve Bennett - Reported-by: af123 - -diff --git a/glob.tcl b/glob.tcl -index cd94d8d..3e8a3fd 100644 ---- a/glob.tcl -+++ b/glob.tcl -@@ -61,10 +61,10 @@ proc glob {args} { - # Avoid regexp for dependency reasons. - # XXX: Doesn't handle backslashed braces - if {[set fb [string first "\{" $pattern]] < 0} { -- return $pattern -+ return [list $pattern] - } - if {[set nb [string first "\}" $pattern $fb]] < 0} { -- return $pattern -+ return [list $pattern] - } - set before [string range $pattern 0 $fb-1] - set braced [string range $pattern $fb+1 $nb-1] diff -Nru jimtcl-0.73/debian/patches/ub5fcd96_Space-allocated-for-exec-env-may-be-one-byte-short.patch jimtcl-0.74/debian/patches/ub5fcd96_Space-allocated-for-exec-env-may-be-one-byte-short.patch --- jimtcl-0.73/debian/patches/ub5fcd96_Space-allocated-for-exec-env-may-be-one-byte-short.patch 2012-01-30 22:22:58.000000000 +0000 +++ jimtcl-0.74/debian/patches/ub5fcd96_Space-allocated-for-exec-env-may-be-one-byte-short.patch 1970-01-01 00:00:00.000000000 +0000 @@ -1,28 +0,0 @@ -commit b5fcd968ec90c01d077f1d4884a38379c0981e65 -Author: Steve Bennett -Date: Sun Jan 29 08:29:24 2012 +1000 - - Space allocated for exec env may be one byte short - - Signed-off-by: Steve Bennett - Reported-by: af123 - -diff --git a/jim-exec.c b/jim-exec.c -index 7da97dc..e22c220 100644 ---- a/jim-exec.c -+++ b/jim-exec.c -@@ -255,12 +255,11 @@ static char **JimBuildEnv(Jim_Interp *interp) - if (num % 2) { - num--; - } -- size = Jim_Length(objPtr); - /* We need one \0 and one equal sign for each element. - * A list has at least one space for each element except the first. -- * We only need one extra char for the extra null terminator. -+ * We need one extra char for the extra null terminator and one for the equal sign. - */ -- size++; -+ size = Jim_Length(objPtr) + 2; - - envptr = Jim_Alloc(sizeof(*envptr) * (num / 2 + 1) + size); - envdata = (char *)&envptr[num / 2 + 1]; diff -Nru jimtcl-0.73/debian/rules jimtcl-0.74/debian/rules --- jimtcl-0.73/debian/rules 2014-03-22 19:26:39.000000000 +0000 +++ jimtcl-0.74/debian/rules 2014-04-14 07:02:34.000000000 +0000 @@ -5,44 +5,44 @@ # That's needed for DEB_HOST_MULTIARCH -include /usr/share/dpkg/architecture.mk -# Debian-specific SONAME and VERSION -DEB_SONAME ?= 0debian2 -DEB_LIBVER ?= $(DEB_SONAME).$(DEB_VERSION_UPSTREAM) +export DEB_CFLAGS_MAINT_APPEND = $(shell dpkg-buildflags --get CPPFLAGS) # Convenience shortcuts MA_DESTDIR ?= debian/tmp/usr/lib/$(DEB_HOST_MULTIARCH) MA_DEV_DESTDIR ?= debian/libjim-dev/usr/lib/$(DEB_HOST_MULTIARCH) -MA_SRCDIR ?= debian/tmp/usr/lib %: - dh $@ --list-missing --with autotools_dev + dh $@ --list-missing override_dh_auto_configure: + # Backup config.guess and config.sub + $(cd autosetup; mv config.guess config.guess.bkp; mv config.sub config.sub.bkp) + # Use autotools-dev's + cp /usr/share/misc/config.guess /usr/share/misc/config.sub autosetup/. dh_auto_configure --builddirectory=static/ dh_auto_configure -- --shared override_dh_auto_build: dh_auto_build --builddirectory=static/ - SH_LDFLAGS="-shared -Wl,-soname,libjim.so.$(DEB_SONAME)" \ - dh_auto_build - ln -sf libjim.so libjim.so.$(DEB_SONAME) + dh_auto_build override_dh_auto_test: dh_auto_test --builddirectory=static/ dh_auto_test override_dh_auto_install: - mkdir -p $(MA_DESTDIR) - # Now install the static version dh_auto_install --builddirectory=static/ - mv $(MA_SRCDIR)/libjim.a $(MA_DESTDIR)/libjim.a dh_auto_install - mv $(MA_SRCDIR)/libjim.so $(MA_DESTDIR)/libjim.so.$(DEB_LIBVER) - ln -sf libjim.so.$(DEB_LIBVER) $(MA_DESTDIR)/libjim.so.$(DEB_SONAME) - ln -sf libjim.so.$(DEB_SONAME) $(MA_DESTDIR)/libjim.so + +override_dh_install: + dh_install + set -e; rootdir=`pwd` ;\ + cd ${MA_DESTDIR}; libfile=`ls *.so.*`; cd $${rootdir};\ + cd ${MA_DEV_DESTDIR}; ln -sf $${libfile} libjim.so override_dh_auto_clean: dh_auto_clean + $(cd autosetup; mv config.guess.bkp config.guess; mv config.sub.bkp config.sub) rm -f libjim.so* rm -f tests/exec.tmp1 rm -Rf static/ diff -Nru jimtcl-0.73/debian/source.lintian-overrides jimtcl-0.74/debian/source.lintian-overrides --- jimtcl-0.73/debian/source.lintian-overrides 2012-01-03 13:42:42.000000000 +0000 +++ jimtcl-0.74/debian/source.lintian-overrides 1970-01-01 00:00:00.000000000 +0000 @@ -1,2 +0,0 @@ -# This is needed for multiarch and "auto-buildflags" -package-needs-versioned-debhelper-build-depends 9 diff -Nru jimtcl-0.73/examples/dns.tcl jimtcl-0.74/examples/dns.tcl --- jimtcl-0.73/examples/dns.tcl 2011-12-19 22:11:37.000000000 +0000 +++ jimtcl-0.74/examples/dns.tcl 2013-07-24 05:36:47.000000000 +0000 @@ -3,8 +3,10 @@ # Modified for Jim Tcl to: # - use udp transport by default # - use sendto/recvfrom -# - remove use of namespaces +# - don't try to determine local nameservers # - remove support for dns uris and finding local nameservers +# - remove logging calls +# (both of these in order to remove dependencies on tcllib) # Based on: @@ -44,29 +46,42 @@ package require binary package require namespace -set dns::version 1.3.3 -set dns::rcsid {$Id: dns.tcl,v 1.36 2008/11/22 12:28:54 mic42 Exp $} +namespace eval ::dns { + variable version 1.3.3-jim2 + variable rcsid {$Id: dns.tcl,v 1.36 2008/11/22 12:28:54 mic42 Exp $} -array set dns::options { - port 53 - timeout 30000 - protocol udp - search {} - nameserver {localhost} - loglevel warn -} + namespace export configure resolve name address cname \ + status reset wait cleanup errorcode -array set dns::types { - A 1 NS 2 MD 3 MF 4 CNAME 5 SOA 6 MB 7 MG 8 MR 9 - NULL 10 WKS 11 PTR 12 HINFO 13 MINFO 14 MX 15 TXT 16 - SPF 16 AAAA 28 SRV 33 IXFR 251 AXFR 252 MAILB 253 MAILA 254 - ANY 255 * 255 -} + variable options + if {![info exists options]} { + array set options { + port 53 + timeout 30000 + protocol udp + search {} + nameserver {localhost} + loglevel warn + } + #variable log [logger::init dns] + #${log}::setlevel $options(loglevel) + } -array set dns::classes { IN 1 CS 2 CH 3 HS 4 * 255} + variable types + array set types { + A 1 NS 2 MD 3 MF 4 CNAME 5 SOA 6 MB 7 MG 8 MR 9 + NULL 10 WKS 11 PTR 12 HINFO 13 MINFO 14 MX 15 TXT 16 + SPF 16 AAAA 28 SRV 33 IXFR 251 AXFR 252 MAILB 253 MAILA 254 + ANY 255 * 255 + } + + variable classes + array set classes { IN 1 CS 2 CH 3 HS 4 * 255} -if {![info exists dns::uid]} { - set dns::uid 0 + variable uid + if {![info exists uid]} { + set uid 0 + } } # ------------------------------------------------------------------------- @@ -75,7 +90,7 @@ # Configure the DNS package. In particular the local nameserver will need # to be set. With no options, returns a list of all current settings. # -proc dns::configure {args} { +proc ::dns::configure {args} { variable options variable log @@ -91,67 +106,67 @@ if {[llength $args] == 1} { set cget 1 } - + while {[string match -* [lindex $args 0]]} { switch -glob -- [lindex $args 0] { -n* - -ser* { if {$cget} { - return $options(nameserver) + return $options(nameserver) } else { - set options(nameserver) [dns::Pop args 1] + set options(nameserver) [Pop args 1] } } - -po* { + -po* { if {$cget} { return $options(port) } else { - set options(port) [dns::Pop args 1] + set options(port) [Pop args 1] } } - -ti* { + -ti* { if {$cget} { return $options(timeout) } else { - set options(timeout) [dns::Pop args 1] + set options(timeout) [Pop args 1] } } -pr* { if {$cget} { return $options(protocol) } else { - set proto [string tolower [dns::Pop args 1]] + set proto [string tolower [Pop args 1]] if {[string compare udp $proto] == 0 \ && [string compare tcp $proto] == 0} { return -code error "invalid protocol \"$proto\":\ protocol must be either \"udp\" or \"tcp\"" } - set options(protocol) $proto + set options(protocol) $proto } } - -sea* { + -sea* { if {$cget} { return $options(search) } else { - set options(search) [dns::Pop args 1] + set options(search) [Pop args 1] } } -log* { if {$cget} { return $options(loglevel) } else { - set options(loglevel) [dns::Pop args 1] + set options(loglevel) [Pop args 1] ${log}::setlevel $options(loglevel) } } - -- { dns::Pop args ; break } + -- { Pop args ; break } default { set opts [join [lsort [array names options]] ", -"] return -code error "bad option [lindex $args 0]:\ must be one of -$opts" } } - dns::Pop args + Pop args } return @@ -163,17 +178,18 @@ # Create a DNS query and send to the specified name server. Returns a token # to be used to obtain any further information about this query. # -proc dns::resolve {query args} { +proc ::dns::resolve {query args} { variable uid variable options variable log # get a guaranteed unique and non-present token id. set id [incr uid] - while {[info exists [set token ::dns::$id]]} { + while {[info exists [set token [namespace current]::$id]]} { set id [incr uid] } # FRINK: nocheck + variable $token upvar 0 $token state # Setup token/state defaults. @@ -191,28 +207,30 @@ set state(-search) $options(search); # domain search list set state(-protocol) $options(protocol); # which protocol udp/tcp + # Support for DNS URL's removed + while {[string match -* [lindex $args 0]]} { switch -glob -- [lindex $args 0] { -n* - ns - - -ser* { set state(-nameserver) [dns::Pop args 1] } - -po* { set state(-port) [dns::Pop args 1] } - -ti* { set state(-timeout) [dns::Pop args 1] } - -co* { set state(-command) [dns::Pop args 1] } - -cl* { set state(-class) [dns::Pop args 1] } - -ty* { set state(-type) [dns::Pop args 1] } - -pr* { set state(-protocol) [dns::Pop args 1] } - -sea* { set state(-search) [dns::Pop args 1] } - -re* { set state(-recurse) [dns::Pop args 1] } + -ser* { set state(-nameserver) [Pop args 1] } + -po* { set state(-port) [Pop args 1] } + -ti* { set state(-timeout) [Pop args 1] } + -co* { set state(-command) [Pop args 1] } + -cl* { set state(-class) [Pop args 1] } + -ty* { set state(-type) [Pop args 1] } + -pr* { set state(-protocol) [Pop args 1] } + -sea* { set state(-search) [Pop args 1] } + -re* { set state(-recurse) [Pop args 1] } -inv* { set state(opcode) 1 } -status {set state(opcode) 2} - -data { set state(qdata) [dns::Pop args 1] } + -data { set state(qdata) [Pop args 1] } default { set opts [join [lsort [array names state -*]] ", "] return -code error "bad option [lindex $args 0]: \ must be $opts" } } - dns::Pop args + Pop args } if {$state(-nameserver) == {}} { @@ -220,25 +238,25 @@ } # Check for reverse lookups -# if {[regexp {^(?:\d{0,3}\.){3}\d{0,3}$} $state(query)]} { -# set addr [lreverse [split $state(query) .]] -# lappend addr in-addr arpa -# set state(query) [join $addr .] -# set state(-type) PTR -# } - - dns::BuildMessage $token + if {[regexp {^(?:\d{0,3}\.){3}\d{0,3}$} $state(query)]} { + set addr [lreverse [split $state(query) .]] + lappend addr in-addr arpa + set state(query) [join $addr .] + set state(-type) PTR + } + BuildMessage $token + if {$state(-protocol) == "tcp"} { - dns::TcpTransmit $token + TcpTransmit $token if {$state(-command) == {}} { - dns::wait $token + wait $token } } else { - dns::UdpTransmit $token - dns::wait $token + UdpTransmit $token + wait $token } - + return $token } @@ -247,10 +265,10 @@ # Description: # Return a list of domain names returned as results for the last query. # -proc dns::name {token} { +proc ::dns::name {token} { set r {} - dns::Flags $token flags - array set reply [dns::Decode $token] + Flags $token flags + array set reply [Decode $token] switch -exact -- $flags(opcode) { 0 { @@ -288,9 +306,9 @@ # Description: # Return a list of the IP addresses returned for this query. # -proc dns::address {token} { +proc ::dns::address {token} { set r {} - array set reply [dns::Decode $token] + array set reply [Decode $token] foreach answer $reply(AN) { array set AN $answer @@ -311,9 +329,9 @@ # Description: # Return a list of all CNAME results returned for this query. # -proc dns::cname {token} { +proc ::dns::cname {token} { set r {} - array set reply [dns::Decode $token] + array set reply [Decode $token] foreach answer $reply(AN) { array set AN $answer @@ -329,8 +347,8 @@ # Description: # Return the decoded answer records. This can be used for more complex # queries where the answer isn't supported byb cname/address/name. -proc dns::result {token args} { - array set reply [eval [linsert $args 0 dns::Decode $token]] +proc ::dns::result {token args} { + array set reply [eval [linsert $args 0 Decode $token]] return $reply(AN) } @@ -339,7 +357,7 @@ # Description: # Get the status of the request. # -proc dns::status {token} { +proc ::dns::status {token} { upvar #0 $token state return $state(status) } @@ -347,7 +365,7 @@ # Description: # Get the error message. Empty if no error. # -proc dns::error {token} { +proc ::dns::error {token} { upvar #0 $token state if {[info exists state(error)]} { return $state(error) @@ -358,9 +376,9 @@ # Description # Get the error code. This is 0 for a successful transaction. # -proc dns::errorcode {token} { +proc ::dns::errorcode {token} { upvar #0 $token state - set flags [dns::Flags $token] + set flags [Flags $token] set ndx [lsearch -exact $flags errorcode] incr ndx return [lindex $flags $ndx] @@ -369,20 +387,20 @@ # Description: # Reset a connection with optional reason. # -proc dns::reset {token {why reset} {errormsg {}}} { +proc ::dns::reset {token {why reset} {errormsg {}}} { upvar #0 $token state set state(status) $why if {[string length $errormsg] > 0 && ![info exists state(error)]} { set state(error) $errormsg } catch {fileevent $state(sock) readable {}} - dns::Finish $token + Finish $token } # Description: # Wait for a request to complete and return the status. # -proc dns::wait {token} { +proc ::dns::wait {token} { upvar #0 $token state if {$state(status) == "connect"} { @@ -395,7 +413,7 @@ # Description: # Remove any state associated with this token. # -proc dns::cleanup {token} { +proc ::dns::cleanup {token} { upvar #0 $token state if {[info exists state]} { catch {close $state(sock)} @@ -409,7 +427,7 @@ # Description: # Dump the raw data of the request and reply packets. # -proc dns::dump {args} { +proc ::dns::dump {args} { if {[llength $args] == 1} { set type -reply set token [lindex $args 0] @@ -424,7 +442,7 @@ # FRINK: nocheck variable $token upvar 0 $token state - + set result {} switch -glob -- $type { -qu* - @@ -446,7 +464,7 @@ # Description: # Perform a hex dump of binary data. # -proc dns::DumpMessage {data} { +proc ::dns::DumpMessage {data} { set result {} binary scan $data c* r foreach c $r { @@ -460,7 +478,7 @@ # Description: # Contruct a DNS query packet. # -proc dns::BuildMessage {token} { +proc ::dns::BuildMessage {token} { # FRINK: nocheck variable $token upvar 0 $token state @@ -487,7 +505,7 @@ # Pack the query: QNAME QTYPE QCLASS - set qsection [dns::PackName $state(query)] + set qsection [PackName $state(query)] append qsection [binary format SS \ $types($state(-type))\ $classes($state(-class))] @@ -507,7 +525,7 @@ append state(request) $qsection $nsdata } 1 { - # IQUERY + # IQUERY set state(request) [binary format SSSSSS $state(id) \ [expr {($state(opcode) << 11) | ($state(-recurse) << 8)}] \ 0 $qdcount 0 0 0] @@ -537,7 +555,7 @@ } # Pack a human readable dns name into a DNS resource record format. -proc dns::PackName {name} { +proc ::dns::PackName {name} { set data "" foreach part [split [string trim $name .] .] { set len [string length $part] @@ -548,7 +566,7 @@ } # Pack a character string - byte length prefixed -proc dns::PackString {text} { +proc ::dns::PackString {text} { set len [string length $text] set data [binary format ca$len $len $text] return $data @@ -558,18 +576,18 @@ # of each type. # eg: PackRecord name wiki.tcl.tk type MX class IN rdata {10 mail.example.com} # -proc dns::PackRecord {args} { +proc ::dns::PackRecord {args} { variable types variable classes array set rr {name "" type A class IN ttl 0 rdlength 0 rdata ""} array set rr $args - set data [dns::PackName $rr(name)] + set data [PackName $rr(name)] switch -exact -- $rr(type) { CNAME - MB - MD - MF - MG - MR - NS - PTR { - set rr(rdata) [dns::PackName $rr(rdata)] + set rr(rdata) [PackName $rr(rdata)] } - HINFO { + HINFO { array set r {CPU {} OS {}} array set r $rr(rdata) set rr(rdata) [PackString $r(CPU)] @@ -584,7 +602,7 @@ MX { foreach {pref exch} $rr(rdata) break set rr(rdata) [binary format S $pref] - append rr(rdata) [dns::PackName $exch] + append rr(rdata) [PackName $exch] } TXT { set str $rr(rdata) @@ -594,14 +612,14 @@ set s [string range $str $n [incr n 253]] append rr(rdata) [PackString $s] } - } + } NULL {} SOA { array set r {MNAME {} RNAME {} SERIAL 0 REFRESH 0 RETRY 0 EXPIRE 0 MINIMUM 0} array set r $rr(rdata) - set rr(rdata) [dns::PackName $r(MNAME)] - append rr(rdata) [dns::PackName $r(RNAME)] + set rr(rdata) [PackName $r(MNAME)] + append rr(rdata) [PackName $r(RNAME)] append rr(rdata) [binary format IIIII $r(SERIAL) \ $r(REFRESH) $r(RETRY) $r(EXPIRE) $r(MINIMUM)] } @@ -619,7 +637,7 @@ # Description: # Transmit a DNS request over a tcp connection. # -proc dns::TcpTransmit {token} { +proc ::dns::TcpTransmit {token} { # FRINK: nocheck variable $token upvar 0 $token state @@ -627,42 +645,43 @@ # setup the timeout if {$state(-timeout) > 0} { set state(after) [after $state(-timeout) \ - [list dns::reset \ + [list [namespace origin reset] \ $token timeout\ "operation timed out"]] } + # Jim Tcl has no async connect ... + set s [socket stream $state(-nameserver):$state(-port)] - fileevent $s writable [list dns::TcpConnected $token $s] + fileevent $s writable [list [namespace origin TcpConnected] $token $s] set state(sock) $s set state(status) connect return $token } -proc dns::TcpConnected {token s} { +proc ::dns::TcpConnected {token s} { variable $token upvar 0 $token state fileevent $s writable {} + # Jim Tcl has no async connect ... # if {[catch {fconfigure $s -peername}]} { # # TCP connection failed -# dns::Finish $token "can't connect to server" +# Finish $token "can't connect to server" # return # } -# fconfigure $s -blocking 0 -translation binary -buffering none - $s ndelay 1 + fconfigure $s -blocking 0 -translation binary -buffering none # For TCP the message must be prefixed with a 16bit length field. set req [binary format S [string length $state(request)]] append req $state(request) puts -nonewline $s $req - $s flush - fileevent $s readable [list dns::TcpEvent $token] + fileevent $s readable [list [namespace current]::TcpEvent $token] } # ------------------------------------------------------------------------- @@ -674,7 +693,7 @@ # As yet I have been unable to test this myself and the tcludp package # cannot do this. # -proc dns::UdpTransmit {token} { +proc ::dns::UdpTransmit {token} { # FRINK: nocheck variable $token upvar 0 $token state @@ -682,19 +701,18 @@ # setup the timeout if {$state(-timeout) > 0} { set state(after) [after $state(-timeout) \ - [list dns::reset \ + [list [namespace origin reset] \ $token timeout\ "operation timed out"]] } - + set state(sock) [socket dgram] - #fconfigure $state(sock) -translation binary -buffering none set state(status) connect $state(sock) sendto $state(request) $state(-nameserver):$state(-port) - - fileevent $state(sock) readable [list dns::UdpEvent $token] - + + fileevent $state(sock) readable [list [namespace current]::UdpEvent $token] + return $token } @@ -703,7 +721,7 @@ # Description: # Tidy up after a tcp transaction. # -proc dns::Finish {token {errormsg ""}} { +proc ::dns::Finish {token {errormsg ""}} { # FRINK: nocheck variable $token upvar 0 $token state @@ -733,12 +751,12 @@ # Description: # Handle end-of-file on a tcp connection. # -proc dns::Eof {token} { +proc ::dns::Eof {token} { # FRINK: nocheck variable $token upvar 0 $token state set state(status) eof - dns::Finish $token + Finish $token } # ------------------------------------------------------------------------- @@ -746,7 +764,7 @@ # Description: # Process a DNS reply packet (protocol independent) # -proc dns::Receive {token} { +proc ::dns::Receive {token} { # FRINK: nocheck variable $token upvar 0 $token state @@ -757,15 +775,15 @@ switch -- $status { 0 { set state(status) ok - dns::Finish $token + Finish $token } - 1 { dns::Finish $token "Format error - unable to interpret the query." } - 2 { dns::Finish $token "Server failure - internal server error." } - 3 { dns::Finish $token "Name Error - domain does not exist" } - 4 { dns::Finish $token "Not implemented - the query type is not available." } - 5 { dns::Finish $token "Refused - your request has been refused by the server." } + 1 { Finish $token "Format error - unable to interpret the query." } + 2 { Finish $token "Server failure - internal server error." } + 3 { Finish $token "Name Error - domain does not exist" } + 4 { Finish $token "Not implemented - the query type is not available." } + 5 { Finish $token "Refused - your request has been refused by the server." } default { - dns::Finish $token "unrecognised error code: $err" + Finish $token "unrecognised error code: $err" } } } @@ -775,7 +793,7 @@ # Description: # file event handler for tcp socket. Wait for the reply data. # -proc dns::TcpEvent {token} { +proc ::dns::TcpEvent {token} { variable log # FRINK: nocheck variable $token @@ -790,16 +808,16 @@ set status [catch {read $state(sock)} result] if {$status != 0} { ${log}::debug "Event error: $result" - dns::Finish $token "error reading data: $result" + Finish $token "error reading data: $result" } elseif { [string length $result] >= 0 } { if {[catch { # Handle incomplete reads - check the size and keep reading. if {![info exists state(size)]} { binary scan $result S state(size) - set result [string range $result 2 end] + set result [string range $result 2 end] } append state(reply) $result - + # check the length and flags and chop off the tcp length prefix. if {[string length $state(reply)] >= $state(size)} { binary scan $result S id @@ -808,14 +826,14 @@ ${log}::error "received packed with incorrect id" } # bug #1158037 - doing this causes problems > 65535 requests! - #Receive dns::$id - dns::Receive $token + #Receive [namespace current]::$id + Receive $token } else { ${log}::debug "Incomplete tcp read:\ [string length $state(reply)] should be $state(size)" } } err]} { - dns::Finish $token "Event error: $err" + Finish $token "Event error: $err" } } elseif { [eof $state(sock)] } { Eof $token @@ -823,7 +841,7 @@ ${log}::debug "Event blocked" } else { ${log}::critical "Event error: this can't happen!" - dns::Finish $token "Event error: this can't happen!" + Finish $token "Event error: this can't happen!" } } @@ -831,7 +849,7 @@ # Description: # file event handler for udp sockets. -proc dns::UdpEvent {token} { +proc ::dns::UdpEvent {token} { # FRINK: nocheck variable $token upvar 0 $token state @@ -846,17 +864,17 @@ ${log}::error "received packed with incorrect id" } # bug #1158037 - doing this causes problems > 65535 requests! - #dns::Receive dns::$id - dns::Receive $token + #Receive [namespace current]::$id + Receive $token } - + # ------------------------------------------------------------------------- -proc dns::Flags {token {varname {}}} { +proc ::dns::Flags {token {varname {}}} { # FRINK: nocheck variable $token upvar 0 $token state - + if {$varname != {}} { upvar $varname flags } @@ -882,7 +900,7 @@ # Description: # Decode a DNS packet (either query or response). # -proc dns::Decode {token args} { +proc ::dns::Decode {token args} { variable log # FRINK: nocheck variable $token @@ -898,7 +916,7 @@ must be -rdata" } } - dns::Pop args + Pop args } if {$opts(-query)} { @@ -930,24 +948,24 @@ NA: $nAN\ NS: $nNS\ AR: $nAR" - #puts $info + #${log}::debug $info set ndx 12 set r {} - set QD [dns::ReadQuestion $nQD $state(reply) ndx] + set QD [ReadQuestion $nQD $state(reply) ndx] lappend r QD $QD - set AN [dns::ReadAnswer $nAN $state(reply) ndx $opts(-rdata)] + set AN [ReadAnswer $nAN $state(reply) ndx $opts(-rdata)] lappend r AN $AN - set NS [dns::ReadAnswer $nNS $state(reply) ndx $opts(-rdata)] + set NS [ReadAnswer $nNS $state(reply) ndx $opts(-rdata)] lappend r NS $NS - set AR [dns::ReadAnswer $nAR $state(reply) ndx $opts(-rdata)] + set AR [ReadAnswer $nAR $state(reply) ndx $opts(-rdata)] lappend r AR $AR return $r } # ------------------------------------------------------------------------- -proc dns::Expand {data} { +proc ::dns::Expand {data} { set r {} binary scan $data c* d foreach c $d { @@ -961,20 +979,26 @@ # Description: # Pop the nth element off a list. Used in options processing. # -proc dns::Pop {&list {nth 0}} { - set r [lindex $list $nth] - set list [lreplace $list $nth $nth] +proc ::dns::Pop {varname {nth 0}} { + upvar $varname args + set r [lindex $args $nth] + set args [lreplace $args $nth $nth] return $r } # ------------------------------------------------------------------------- -proc dns::KeyOf {&array value {default {}}} { - try { - dict get [lreverse $array] $value - } on error msg { - return $default +proc ::dns::KeyOf {arrayname value {default {}}} { + upvar $arrayname array + set lst [array get array] + set ndx [lsearch -exact $lst $value] + if {$ndx != -1} { + incr ndx -1 + set r [lindex $lst $ndx] + } else { + set r $default } + return $r } @@ -982,7 +1006,7 @@ # Read the question section from a DNS message. This always starts at index # 12 of a message but may be of variable length. # -proc dns::ReadQuestion {nitems data indexvar} { +proc ::dns::ReadQuestion {nitems data indexvar} { variable types variable classes upvar $indexvar index @@ -990,9 +1014,9 @@ for {set cn 0} {$cn < $nitems} {incr cn} { set r {} - lappend r name [dns::ReadName data $index offset] + lappend r name [ReadName data $index offset] incr index $offset - + # Read off QTYPE and QCLASS for this query. set ndx $index incr index 3 @@ -1000,18 +1024,18 @@ set qtype [expr {$qtype & 0xFFFF}] set qclass [expr {$qclass & 0xFFFF}] incr index - lappend r type [dns::KeyOf types $qtype $qtype] \ - class [dns::KeyOf classes $qclass $qclass] + lappend r type [KeyOf types $qtype $qtype] \ + class [KeyOf classes $qclass $qclass] lappend result $r } return $result } - + # ------------------------------------------------------------------------- -# Read an answer section from a DNS message. +# Read an answer section from a DNS message. # -proc dns::ReadAnswer {nitems data indexvar {raw 0}} { +proc ::dns::ReadAnswer {nitems data indexvar {raw 0}} { variable types variable classes upvar $indexvar index @@ -1019,17 +1043,17 @@ for {set cn 0} {$cn < $nitems} {incr cn} { set r {} - lappend r name [dns::ReadName data $index offset] + lappend r name [ReadName data $index offset] incr index $offset - + # Read off TYPE, CLASS, TTL and RDLENGTH binary scan [string range $data $index end] SSIS type class ttl rdlength set type [expr {$type & 0xFFFF}] - set type [dns::KeyOf types $type $type] + set type [KeyOf types $type $type] set class [expr {$class & 0xFFFF}] - set class [dns::KeyOf classes $class $class] + set class [KeyOf classes $class $class] set ttl [expr {$ttl & 0xFFFFFFFF}] set rdlength [expr {$rdlength & 0xFFFF}] @@ -1039,17 +1063,17 @@ if {! $raw} { switch -- $type { A { - set rdata [join [dns::Expand $rdata] .] + set rdata [join [Expand $rdata] .] } AAAA { set rdata [ip::contract [ip::ToString $rdata]] } NS - CNAME - PTR { - set rdata [dns::ReadName data $index off] + set rdata [ReadName data $index off] } MX { binary scan $rdata S preference - set exchange [dns::ReadName data [expr {$index + 2}] off] + set exchange [ReadName data [expr {$index + 2}] off] set rdata [list $preference $exchange] } SRV { @@ -1060,7 +1084,7 @@ incr x $off lappend rdata port [ReadUShort data $x off] incr x $off - lappend rdata target [dns::ReadName data $x off] + lappend rdata target [ReadName data $x off] incr x $off } TXT { @@ -1068,9 +1092,9 @@ } SOA { set x $index - set rdata [list MNAME [dns::ReadName data $x off]] - incr x $off - lappend rdata RNAME [dns::ReadName data $x off] + set rdata [list MNAME [ReadName data $x off]] + incr x $off + lappend rdata RNAME [ReadName data $x off] incr x $off lappend rdata SERIAL [ReadULong data $x off] incr x $off @@ -1095,10 +1119,10 @@ # Read a 32bit integer from a DNS packet. These are compatible with -# the ReadName proc. Additionally - ReadULong takes measures to ensure +# the ReadName proc. Additionally - ReadULong takes measures to ensure # the unsignedness of the value obtained. # -proc dns::ReadLong {datavar index usedvar} { +proc ::dns::ReadLong {datavar index usedvar} { upvar $datavar data upvar $usedvar used set r {} @@ -1109,7 +1133,7 @@ return $r } -proc dns::ReadULong {datavar index usedvar} { +proc ::dns::ReadULong {datavar index usedvar} { upvar $datavar data upvar $usedvar used set r {} @@ -1117,13 +1141,13 @@ if {[binary scan $data @${index}cccc b1 b2 b3 b4]} { set used 4 # This gets us an unsigned value. - set r [expr {($b4 & 0xFF) + (($b3 & 0xFF) << 8) - + (($b2 & 0xFF) << 16) + ($b1 << 24)}] + set r [expr {($b4 & 0xFF) + (($b3 & 0xFF) << 8) + + (($b2 & 0xFF) << 16) + ($b1 << 24)}] } return $r } -proc dns::ReadUShort {datavar index usedvar} { +proc ::dns::ReadUShort {datavar index usedvar} { upvar $datavar data upvar $usedvar used set r {} @@ -1131,16 +1155,16 @@ if {[binary scan [string range $data $index end] cc b1 b2]} { set used 2 # This gets us an unsigned value. - set r [expr {(($b2 & 0xff) + (($b1 & 0xff) << 8)) & 0xffff}] + set r [expr {(($b2 & 0xff) + (($b1 & 0xff) << 8)) & 0xffff}] } return $r } -# Read off the NAME or QNAME element. This reads off each label in turn, +# Read off the NAME or QNAME element. This reads off each label in turn, # dereferencing pointer labels until we have finished. The length of data # used is passed back using the usedvar variable. # -proc dns::ReadName {datavar index usedvar} { +proc ::dns::ReadName {datavar index usedvar} { upvar $datavar data upvar $usedvar used set startindex $index @@ -1148,18 +1172,18 @@ set r {} set len 1 set max [string length $data] - + while {$len != 0 && $index < $max} { # Read the label length (and preread the pointer offset) binary scan [string range $data $index end] cc len lenb set len [expr {$len & 0xFF}] incr index - + if {$len != 0} { if {[expr {$len & 0xc0}]} { binary scan [binary format cc [expr {$len & 0x3f}] [expr {$lenb & 0xff}]] S offset incr index - lappend r [dns::ReadName data $offset junk] + lappend r [ReadName data $offset junk] set len 0 } else { lappend r [string range $data $index [expr {$index + $len - 1}]] @@ -1171,7 +1195,7 @@ return [join $r .] } -proc dns::ReadString {datavar index length} { +proc ::dns::ReadString {datavar index length} { upvar $datavar data set startindex $index @@ -1193,7 +1217,8 @@ # ------------------------------------------------------------------------- -catch {dns::configure -nameserver [lindex [dns::nameservers] 0]} + +package provide dns $dns::version # ------------------------------------------------------------------------- # Local Variables: diff -Nru jimtcl-0.73/examples.api/jim_obj.c jimtcl-0.74/examples.api/jim_obj.c --- jimtcl-0.73/examples.api/jim_obj.c 2011-12-19 22:11:37.000000000 +0000 +++ jimtcl-0.74/examples.api/jim_obj.c 2013-07-24 05:36:47.000000000 +0000 @@ -56,12 +56,8 @@ /* And initialise any static extensions */ Jim_InitStaticExtensions(interp); - - /* Create some empty object */ - obj = Jim_NewObj(interp); - - /* Name the object */ - Jim_InitStringRep(obj, OBJ_DESC, strlen(OBJ_DESC)) ; + /* Create a string object */ + obj = Jim_NewStringObj(interp, OBJ_DESC, strlen(OBJ_DESC)); /* Obtain internal representation of an object */ obj_desc = Jim_GetString(obj, &obj_size); diff -Nru jimtcl-0.73/examples.api/jim_return.c jimtcl-0.74/examples.api/jim_return.c --- jimtcl-0.73/examples.api/jim_return.c 2011-12-19 22:11:37.000000000 +0000 +++ jimtcl-0.74/examples.api/jim_return.c 2013-07-24 05:36:47.000000000 +0000 @@ -45,15 +45,11 @@ static int CountCharsFunc(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { - const char *str; - int len; - if (argc != 2) { Jim_WrongNumArgs(interp, 1, argv, "string"); return (JIM_ERR); } - str = Jim_GetString(argv[1], &len); - Jim_SetResult(interp, Jim_NewIntObj(interp, (jim_wide)len)); + Jim_SetResult(interp, Jim_NewIntObj(interp, Jim_Length(argv[1]))); return (JIM_OK); } diff -Nru jimtcl-0.73/.gitignore jimtcl-0.74/.gitignore --- jimtcl-0.73/.gitignore 2011-12-19 22:11:37.000000000 +0000 +++ jimtcl-0.74/.gitignore 2013-07-24 05:36:47.000000000 +0000 @@ -13,7 +13,7 @@ jimsh *.exe libjim.a -*.so +*.so.* *.dll *.o configure.gnu diff -Nru jimtcl-0.73/glob.tcl jimtcl-0.74/glob.tcl --- jimtcl-0.73/glob.tcl 2011-12-19 22:11:37.000000000 +0000 +++ jimtcl-0.74/glob.tcl 2013-07-24 05:36:47.000000000 +0000 @@ -1,127 +1,183 @@ -# Implements a Tcl-compatible glob command based on readdir +# Implements a mostly Tcl-compatible glob command based on readdir # # (c) 2008 Steve Bennett +# (c) 2012 Alexander Shpilkin # # See LICENCE in this directory for licensing. package require readdir +# Return a list of all entries in $dir that match the pattern. +proc glob.globdir {dir pattern} { + set result {} + set files [readdir $dir] + lappend files . .. + + foreach name $files { + if {[string match $pattern $name]} { + # Starting dots match only explicitly + if {[string index $name 0] eq "." && [string index $pattern 0] ne "."} { + continue + } + lappend result $name + } + } + + return $result +} + +# Return the list of patterns resulting from expanding any braced +# alternatives inside the given pattern, prepending the unprocessed +# part of the pattern. Does _not_ handle escaped braces or commas. +proc glob.explode {pattern} { + set oldexp {} + set newexp {""} + + while 1 { + set oldexp $newexp + set newexp {} + set ob [string first \{ $pattern] + set cb [string first \} $pattern] + + if {$ob < $cb && $ob != -1} { + set mid [string range $pattern 0 $ob-1] + set subexp [lassign [glob.explode [string range $pattern $ob+1 end]] pattern] + if {$pattern eq ""} { + error "unmatched open brace in glob pattern" + } + set pattern [string range $pattern 1 end] + + foreach subs $subexp { + foreach sub [split $subs ,] { + foreach old $oldexp { + lappend newexp $old$mid$sub + } + } + } + } elseif {$cb != -1} { + set suf [string range $pattern 0 $cb-1] + set rest [string range $pattern $cb end] + break + } else { + set suf $pattern + set rest "" + break + } + } + + foreach old $oldexp { + lappend newexp $old$suf + } + linsert $newexp 0 $rest +} + +# Core glob implementation. Returns a list of files/directories inside +# base matching pattern, in {realname name} pairs. +proc glob.glob {base pattern} { + set dir [file dirname $pattern] + if {$pattern eq $dir || $pattern eq ""} { + return [list [file join $base $dir] $pattern] + } elseif {$pattern eq [file tail $pattern]} { + set dir "" + } + + # Recursively expand the parent directory + set dirlist [glob.glob $base $dir] + set pattern [file tail $pattern] + + # Collect the files/directories + set result {} + foreach {realdir dir} $dirlist { + if {![file isdir $realdir]} { + continue + } + if {[string index $dir end] ne "/" && $dir ne ""} { + append dir / + } + foreach name [glob.globdir $realdir $pattern] { + lappend result [file join $realdir $name] $dir$name + } + } + return $result +} + # Implements the Tcl glob command # -# Usage: glob ?-nocomplain? pattern ... +# Usage: glob ?-nocomplain? ?-directory dir? ?--? pattern ... # # Patterns use 'string match' (glob) pattern matching for each # directory level, plus support for braced alternations. # -# e.g. glob "te[a-e]*/*.{c,tcl}" +# e.g. glob {te[a-e]*/*.{c,tcl}} # # Note: files starting with . will only be returned if matching component # of the pattern starts with . proc glob {args} { + set nocomplain 0 + set base "" - # If $dir is a directory, return a list of all entries - # it contains which match $pattern - # - local proc glob.readdir_pattern {dir pattern} { - set result {} - - # readdir doesn't return . or .., so simulate it here - if {$pattern in {. ..}} { - return $pattern - } - - # If the pattern isn't actually a pattern... - if {[string match {*[*?]*} $pattern]} { - # Use -nocomplain here to return nothing if $dir is not a directory - set files [readdir -nocomplain $dir] - } elseif {[file isdir $dir] && [file exists $dir/$pattern]} { - set files [list $pattern] - } else { - set files "" - } + set n 0 + foreach arg $args { + if {[info exists param]} { + set $param $arg + unset param + incr n + continue + } + switch -glob -- $arg { + -d* { + set switch $arg + set param base + } + -n* { + set nocomplain 1 + } + -t* { + # Ignored for Tcl compatibility + } - foreach name $files { - if {[string match $pattern $name]} { - # Only include entries starting with . if the pattern starts with . - if {[string index $name 0] eq "." && [string index $pattern 0] ne "."} { - continue - } - lappend result $name + -* { + return -code error "bad option \"$switch\": must be -directory, -nocomplain, -tails, or --" + } + -- { + incr n + break + } + * { + break } } - - return $result + incr n } - - # If the pattern contains a braced expression, return a list of - # patterns with the braces expanded. {c,b}* => c* b* - # Otherwise just return the pattern - # Note: Only supports one braced expression. i.e. not {a,b}*{c,d}* - proc glob.expandbraces {pattern} { - # Avoid regexp for dependency reasons. - # XXX: Doesn't handle backslashed braces - if {[set fb [string first "\{" $pattern]] < 0} { - return $pattern - } - if {[set nb [string first "\}" $pattern $fb]] < 0} { - return $pattern - } - set before [string range $pattern 0 $fb-1] - set braced [string range $pattern $fb+1 $nb-1] - set after [string range $pattern $nb+1 end] - - lmap part [split $braced ,] { - set pat $before$part$after - } + if {[info exists param]} { + return -code error "missing argument to \"$switch\"" } - - # Core glob implementation. Returns a list of files/directories matching the pattern - proc glob.glob {pattern} { - set dir [file dirname $pattern] - if {$dir eq $pattern} { - # At the top level - return [list $dir] - } - - # Recursively expand the parent directory - set dirlist [glob.glob $dir] - set pattern [file tail $pattern] - - # Now collect the fiels/directories - set result {} - foreach dir $dirlist { - set globdir $dir - if {[string match "*/" $dir]} { - set sep "" - } elseif {$dir eq "."} { - set globdir "" - set sep "" - } else { - set sep / - } - foreach pat [glob.expandbraces $pattern] { - foreach name [glob.readdir_pattern $dir $pat] { - lappend result $globdir$sep$name - } - } - } - return $result + if {[llength $args] <= $n} { + return -code error "wrong # args: should be \"glob ?options? pattern ?pattern ...?\"" } - # Start of main glob - set nocomplain 0 - - if {[lindex $args 0] eq "-nocomplain"} { - set nocomplain 1 - set args [lrange $args 1 end] - } + set args [lrange $args $n end] set result {} foreach pattern $args { - lappend result {*}[glob.glob $pattern] + set pattern [string map { + \\\\ \x01 \\\{ \x02 \\\} \x03 \\, \x04 + } $pattern] + set patexps [lassign [glob.explode $pattern] rest] + if {$rest ne ""} { + return -code error "unmatched close brace in glob pattern" + } + foreach patexp $patexps { + set patexp [string map { + \x01 \\\\ \x02 \{ \x03 \} \x04 , + } $patexp] + foreach {realname name} [glob.glob $base $patexp] { + lappend result $name + } + } } - if {$nocomplain == 0 && [llength $result] == 0} { + if {!$nocomplain && [llength $result] == 0} { return -code error "no files matched glob patterns" } diff -Nru jimtcl-0.73/jim-aio.c jimtcl-0.74/jim-aio.c --- jimtcl-0.73/jim-aio.c 2011-12-19 22:11:37.000000000 +0000 +++ jimtcl-0.74/jim-aio.c 2013-07-24 05:36:47.000000000 +0000 @@ -38,13 +38,14 @@ * official policies, either expressed or implied, of the Jim Tcl Project. **/ +#include "jimautoconf.h" + #include #include #include #include #include "jim.h" -#include "jimautoconf.h" #if defined(HAVE_SYS_SOCKET_H) && defined(HAVE_SELECT) && defined(HAVE_NETINET_IN_H) && defined(HAVE_NETDB_H) && defined(HAVE_ARPA_INET_H) #include @@ -65,6 +66,13 @@ #define AIO_CMD_LEN 32 /* e.g. aio.handleXXXXXX */ #define AIO_BUF_LEN 256 /* Can keep this small and rely on stdio buffering */ +#ifndef HAVE_FTELLO + #define ftello ftell +#endif +#ifndef HAVE_FSEEKO + #define fseeko fseek +#endif + #define AIO_KEEPOPEN 1 #if defined(JIM_IPV6) @@ -328,7 +336,7 @@ char buf[AIO_BUF_LEN]; Jim_Obj *objPtr; int nonewline = 0; - int neededLen = -1; /* -1 is "read as much as possible" */ + jim_wide neededLen = -1; /* -1 is "read as much as possible" */ if (argc && Jim_CompareStringImmediate(interp, argv[0], "-nonewline")) { nonewline = 1; @@ -336,15 +344,12 @@ argc--; } if (argc == 1) { - jim_wide wideValue; - - if (Jim_GetWide(interp, argv[0], &wideValue) != JIM_OK) + if (Jim_GetWide(interp, argv[0], &neededLen) != JIM_OK) return JIM_ERR; - if (wideValue < 0) { + if (neededLen < 0) { Jim_SetResultString(interp, "invalid parameter: negative len", -1); return JIM_ERR; } - neededLen = (int)wideValue; } else if (argc) { return -1; @@ -391,8 +396,8 @@ static int aio_cmd_copy(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { AioFile *af = Jim_CmdPrivData(interp); - long count = 0; - long maxlen = LONG_MAX; + jim_wide count = 0; + jim_wide maxlen = JIM_WIDE_MAX; FILE *outfh = Jim_AioFilehandle(interp, argv[0]); if (outfh == NULL) { @@ -400,7 +405,7 @@ } if (argc == 2) { - if (Jim_GetLong(interp, argv[1], &maxlen) != JIM_OK) { + if (Jim_GetWide(interp, argv[1], &maxlen) != JIM_OK) { return JIM_ERR; } } @@ -514,6 +519,18 @@ return JIM_ERR; } +static int aio_cmd_isatty(Jim_Interp *interp, int argc, Jim_Obj *const *argv) +{ +#ifdef HAVE_ISATTY + AioFile *af = Jim_CmdPrivData(interp); + Jim_SetResultInt(interp, isatty(fileno(af->fp))); +#else + Jim_SetResultInt(interp, 0); +#endif + + return JIM_OK; +} + #if !defined(JIM_ANSIC) && !defined(JIM_BOOTSTRAP) static int aio_cmd_recvfrom(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { @@ -662,7 +679,7 @@ { AioFile *af = Jim_CmdPrivData(interp); int orig = SEEK_SET; - long offset; + jim_wide offset; if (argc == 2) { if (Jim_CompareStringImmediate(interp, argv[1], "start")) @@ -675,10 +692,10 @@ return -1; } } - if (Jim_GetLong(interp, argv[0], &offset) != JIM_OK) { + if (Jim_GetWide(interp, argv[0], &offset) != JIM_OK) { return JIM_ERR; } - if (fseek(af->fp, offset, orig) == -1) { + if (fseeko(af->fp, offset, orig) == -1) { JimAioSetError(interp, af->filename); return JIM_ERR; } @@ -689,7 +706,7 @@ { AioFile *af = Jim_CmdPrivData(interp); - Jim_SetResultInt(interp, ftell(af->fp)); + Jim_SetResultInt(interp, ftello(af->fp)); return JIM_OK; } @@ -865,6 +882,13 @@ 2, /* Description: Write the string, with newline unless -nonewline */ }, + { "isatty", + NULL, + aio_cmd_isatty, + 0, + 0, + /* Description: Is the file descriptor a tty? */ + }, #if !defined(JIM_ANSIC) && !defined(JIM_BOOTSTRAP) { "recvfrom", "len ?addrvar?", diff -Nru jimtcl-0.73/jim.c jimtcl-0.74/jim.c --- jimtcl-0.73/jim.c 2011-12-19 22:11:37.000000000 +0000 +++ jimtcl-0.74/jim.c 2013-07-24 05:36:47.000000000 +0000 @@ -100,6 +100,9 @@ #define JIM_DEBUG_PANIC #endif +/* Maximum size of an integer */ +#define JIM_INTEGER_SPACE 24 + const char *jim_tt_name(int type); #ifdef JIM_DEBUG_PANIC @@ -127,6 +130,7 @@ 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); @@ -409,11 +413,38 @@ } #endif -int Jim_WideToString(char *buf, jim_wide wideValue) +static int JimWideToString(char *buf, jim_wide wideValue) { - const char *fmt = "%" JIM_WIDE_MODIFIER; + int pos = 0; + + if (wideValue == 0) { + buf[pos++] = '0'; + } + else { + char tmp[JIM_INTEGER_SPACE]; + int num = 0; + int i; + + if (wideValue < 0) { + buf[pos++] = '-'; + /* -106 % 10 may be -6 or 4! */ + i = wideValue % 10; + tmp[num++] = (i > 0) ? (10 - i) : -i; + wideValue /= -10; + } - return sprintf(buf, fmt, wideValue); + while (wideValue) { + tmp[num++] = wideValue % 10; + wideValue /= 10; + } + + for (i = 0; i < num; i++) { + buf[pos++] = '0' + tmp[num - i - 1]; + } + } + buf[pos] = 0; + + return pos; } /** @@ -440,11 +471,108 @@ return JIM_OK; } +/* Parses the front of a number to determine it's sign and base + * Returns the index to start parsing according to the given base + */ +static int JimNumberBase(const char *str, int *base, int *sign) +{ + int i = 0; + + *base = 10; + + while (isspace(UCHAR(str[i]))) { + i++; + } + + if (str[i] == '-') { + *sign = -1; + i++; + } + else { + if (str[i] == '+') { + i++; + } + *sign = 1; + } + + if (str[i] != '0') { + /* base 10 */ + return 0; + } + + /* We have 0, so see if we can convert it */ + switch (str[i + 1]) { + case 'x': case 'X': *base = 16; break; + case 'o': case 'O': *base = 8; break; + case 'b': case 'B': *base = 2; break; + default: return 0; + } + i += 2; + /* Ensure that (e.g.) 0x-5 fails to parse */ + if (str[i] != '-' && str[i] != '+' && !isspace(UCHAR(str[i]))) { + /* Parse according to this base */ + return i; + } + /* Parse as base 10 */ + *base = 10; + return 0; +} + +/* Converts a number as per strtol(..., 0) except leading zeros do *not* + * imply octal. Instead, decimal is assumed unless the number begins with 0x, 0o or 0b + */ +static long jim_strtol(const char *str, char **endptr) +{ + int sign; + int base; + int i = JimNumberBase(str, &base, &sign); + + if (base != 10) { + long value = strtol(str + i, endptr, base); + if (endptr == NULL || *endptr != str + i) { + return value * sign; + } + } + + /* Can just do a regular base-10 conversion */ + return strtol(str, endptr, 10); +} + + +/* Converts a number as per strtoull(..., 0) except leading zeros do *not* + * imply octal. Instead, decimal is assumed unless the number begins with 0x, 0o or 0b + */ +static jim_wide jim_strtoull(const char *str, char **endptr) +{ +#ifdef HAVE_LONG_LONG + int sign; + int base; + int i = JimNumberBase(str, &base, &sign); + + if (base != 10) { + jim_wide value = strtoull(str + i, endptr, base); + if (endptr == NULL || *endptr != str + i) { + return value * sign; + } + } + + /* Can just do a regular base-10 conversion */ + return strtoull(str, endptr, 10); +#else + return (unsigned long)jim_strtol(str, endptr); +#endif +} + int Jim_StringToWide(const char *str, jim_wide * widePtr, int base) { char *endptr; - *widePtr = strtoull(str, &endptr, base); + if (base) { + *widePtr = strtoull(str, &endptr, base); + } + else { + *widePtr = jim_strtoull(str, &endptr); + } return JimCheckConversion(str, endptr); } @@ -643,6 +771,14 @@ ht->collisions = 0; } +static void JimInitHashTableIterator(Jim_HashTable *ht, Jim_HashTableIterator *iter) +{ + iter->ht = ht; + iter->index = -1; + iter->entry = NULL; + iter->nextEntry = NULL; +} + /* Initialize the hash table */ int Jim_InitHashTable(Jim_HashTable *ht, const Jim_HashTableType *type, void *privDataPtr) { @@ -833,11 +969,7 @@ Jim_HashTableIterator *Jim_GetHashTableIterator(Jim_HashTable *ht) { Jim_HashTableIterator *iter = Jim_Alloc(sizeof(*iter)); - - iter->ht = ht; - iter->index = -1; - iter->entry = NULL; - iter->nextEntry = NULL; + JimInitHashTableIterator(ht, iter); return iter; } @@ -2122,25 +2254,6 @@ objPtr->bytes = NULL; } -#define Jim_SetStringRep(o, b, l) \ - do { (o)->bytes = b; (o)->length = l; } while (0) - -/* Set the initial string representation for an object. - * Does not try to free an old one. */ -void Jim_InitStringRep(Jim_Obj *objPtr, const char *bytes, int length) -{ - if (length == 0) { - objPtr->bytes = JimEmptyStringRep; - objPtr->length = 0; - } - else { - objPtr->bytes = Jim_Alloc(length + 1); - objPtr->length = length; - memcpy(objPtr->bytes, bytes, length); - objPtr->bytes[length] = '\0'; - } -} - /* Duplicate an object. The returned object has refcount = 0. */ Jim_Obj *Jim_DuplicateObj(Jim_Interp *interp, Jim_Obj *objPtr) { @@ -2151,8 +2264,18 @@ /* Object does not have a valid string representation. */ dupPtr->bytes = NULL; } + else if (objPtr->length == 0) { + /* Zero length, so don't even bother with the type-specific dup, since all zero length objects look the same */ + dupPtr->bytes = JimEmptyStringRep; + dupPtr->length = 0; + dupPtr->typePtr = NULL; + return dupPtr; + } else { - Jim_InitStringRep(dupPtr, objPtr->bytes, objPtr->length); + dupPtr->bytes = Jim_Alloc(objPtr->length + 1); + dupPtr->length = objPtr->length; + /* Copy the null byte too */ + memcpy(dupPtr->bytes, objPtr->bytes, objPtr->length + 1); } /* By default, the new object has the same type as the old object */ @@ -2348,9 +2471,8 @@ { Jim_Obj *objPtr = Jim_NewObj(interp); - if (len == -1) - len = strlen(s); - Jim_SetStringRep(objPtr, s, len); + objPtr->bytes = s; + objPtr->length = len == -1 ? strlen(s) : len; objPtr->typePtr = NULL; return objPtr; } @@ -2587,7 +2709,7 @@ return NULL; } - if (last <= first) { + if (last < first) { return strObjPtr; } @@ -3004,7 +3126,7 @@ void DupSourceInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr) { - dupPtr->internalRep = srcPtr->internalRep; + dupPtr->internalRep.sourceValue = srcPtr->internalRep.sourceValue; Jim_IncrRefCount(dupPtr->internalRep.sourceValue.fileNameObj); } @@ -3012,7 +3134,7 @@ Jim_Obj *fileNameObj, int lineNumber) { JimPanic((Jim_IsShared(objPtr), "JimSetSourceInfo called with shared object")); - JimPanic((objPtr->typePtr != NULL, "JimSetSourceInfo called with typePtr != NULL")); + JimPanic((objPtr->typePtr == &sourceObjType, "JimSetSourceInfo called with non-source object")); Jim_IncrRefCount(fileNameObj); objPtr->internalRep.sourceValue.fileNameObj = fileNameObj; objPtr->internalRep.sourceValue.lineNumber = lineNumber; @@ -3509,9 +3631,12 @@ ScriptObj *Jim_GetScript(Jim_Interp *interp, Jim_Obj *objPtr) { - struct ScriptObj *script = Jim_GetIntRepPtr(objPtr); + if (objPtr == interp->emptyObj) { + /* Avoid converting emptyObj to a script. use nullScriptObj instead. */ + objPtr = interp->nullScriptObj; + } - if (objPtr->typePtr != &scriptObjType || script->substFlags) { + if (objPtr->typePtr != &scriptObjType || ((struct ScriptObj *)Jim_GetIntRepPtr(objPtr))->substFlags) { SetScriptFromAny(interp, objPtr, NULL); } return (ScriptObj *) Jim_GetIntRepPtr(objPtr); @@ -3822,7 +3947,6 @@ Jim_Obj *nameObjPtr; Jim_Obj *defaultObjPtr; int len; - int n = 1; /* Examine a parameter */ Jim_ListIndex(interp, argListObjPtr, i, &argPtr, JIM_NONE); @@ -3859,10 +3983,10 @@ } else { if (len == 2) { - cmdPtr->u.proc.optArity += n; + cmdPtr->u.proc.optArity++; } else { - cmdPtr->u.proc.reqArity += n; + cmdPtr->u.proc.reqArity++; } } @@ -5081,7 +5205,7 @@ int collected = 0; #ifndef JIM_BOOTSTRAP Jim_HashTable marks; - Jim_HashTableIterator *htiter; + Jim_HashTableIterator htiter; Jim_HashEntry *he; Jim_Obj *objPtr; @@ -5153,8 +5277,8 @@ /* Run the references hash table to destroy every reference that * is not referenced outside (not present in the mark HT). */ - htiter = Jim_GetHashTableIterator(&interp->references); - while ((he = Jim_NextHashEntry(htiter)) != NULL) { + JimInitHashTableIterator(&interp->references, &htiter); + while ((he = Jim_NextHashEntry(&htiter)) != NULL) { const unsigned long *refId; Jim_Reference *refPtr; @@ -5176,13 +5300,15 @@ JimFormatReference(refstr, refPtr, *refId); objv[0] = refPtr->finalizerCmdNamePtr; - objv[1] = Jim_NewStringObjNoAlloc(interp, refstr, 32); + objv[1] = Jim_NewStringObjNoAlloc(interp, refstr, JIM_REFERENCE_SPACE); objv[2] = refPtr->objPtr; /* Drop the reference itself */ /* Avoid the finaliser being freed here */ Jim_IncrRefCount(objv[0]); - Jim_DeleteHashEntry(&interp->references, refId); + /* Don't remove the reference from the hash table just yet + * since that will free refPtr, and hence refPtr->objPtr + */ /* Call the finalizer. Errors ignored. */ oldResult = interp->result; @@ -5190,6 +5316,7 @@ Jim_EvalObjVector(interp, 3, objv); Jim_SetResult(interp, oldResult); Jim_DecrRefCount(interp, oldResult); + Jim_DeleteHashEntry(&interp->references, refId); Jim_DecrRefCount(interp, objv[0]); } @@ -5198,7 +5325,6 @@ } } } - Jim_FreeHashTableIterator(htiter); Jim_FreeHashTable(&marks); interp->lastCollectId = interp->referenceNextId; interp->lastCollectTime = time(NULL); @@ -5267,12 +5393,14 @@ i->unknown = Jim_NewStringObj(i, "unknown", -1); i->errorProc = i->emptyObj; i->currentScriptObj = Jim_NewEmptyStringObj(i); + i->nullScriptObj = Jim_NewEmptyStringObj(i); Jim_IncrRefCount(i->emptyObj); Jim_IncrRefCount(i->errorFileNameObj); Jim_IncrRefCount(i->result); Jim_IncrRefCount(i->stackTrace); Jim_IncrRefCount(i->unknown); Jim_IncrRefCount(i->currentScriptObj); + Jim_IncrRefCount(i->nullScriptObj); Jim_IncrRefCount(i->errorProc); Jim_IncrRefCount(i->trueObj); Jim_IncrRefCount(i->falseObj); @@ -5306,6 +5434,7 @@ Jim_DecrRefCount(i, i->unknown); Jim_DecrRefCount(i, i->errorFileNameObj); Jim_DecrRefCount(i, i->currentScriptObj); + Jim_DecrRefCount(i, i->nullScriptObj); Jim_FreeHashTable(&i->commands); #ifdef JIM_REFERENCES Jim_FreeHashTable(&i->references); @@ -5395,7 +5524,7 @@ if (str[0] == '#') { char *endptr; - level = strtol(str + 1, &endptr, 0); + level = jim_strtol(str + 1, &endptr); if (str[1] == '\0' || endptr[0] != '\0') { level = -1; } @@ -5573,8 +5702,6 @@ /* ----------------------------------------------------------------------------- * Integer object * ---------------------------------------------------------------------------*/ -#define JIM_INTEGER_SPACE 24 - static void UpdateStringOfInt(struct Jim_Obj *objPtr); static int SetIntFromAny(Jim_Interp *interp, Jim_Obj *objPtr, int flags); @@ -5600,12 +5727,12 @@ }; -void UpdateStringOfInt(struct Jim_Obj *objPtr) +static void UpdateStringOfInt(struct Jim_Obj *objPtr) { int len; char buf[JIM_INTEGER_SPACE + 1]; - len = Jim_WideToString(buf, JimWideValue(objPtr)); + len = JimWideToString(buf, JimWideValue(objPtr)); objPtr->bytes = Jim_Alloc(len + 1); memcpy(objPtr->bytes, buf, len + 1); objPtr->length = len; @@ -5849,7 +5976,7 @@ #define JIM_ELESTR_SIMPLE 0 #define JIM_ELESTR_BRACE 1 #define JIM_ELESTR_QUOTE 2 -static int ListElementQuotingType(const char *s, int len) +static unsigned char ListElementQuotingType(const char *s, int len) { int i, level, blevel, trySimple = 1; @@ -6002,13 +6129,19 @@ static void JimMakeListStringRep(Jim_Obj *objPtr, Jim_Obj **objv, int objc) { + #define STATIC_QUOTING_LEN 32 int i, bufLen, realLength; const char *strRep; char *p; - int *quotingType; + unsigned char *quotingType, staticQuoting[STATIC_QUOTING_LEN]; - /* (Over) Estimate the space needed. */ - quotingType = Jim_Alloc(sizeof(int) * objc + 1); + /* Estimate the space needed. */ + if (objc > STATIC_QUOTING_LEN) { + quotingType = Jim_Alloc(objc); + } + else { + quotingType = staticQuoting; + } bufLen = 0; for (i = 0; i < objc; i++) { int len; @@ -6074,7 +6207,10 @@ } *p = '\0'; /* nul term. */ objPtr->length = realLength; - Jim_Free(quotingType); + + if (quotingType != staticQuoting) { + Jim_Free(quotingType); + } } static void UpdateStringOfList(struct Jim_Obj *objPtr) @@ -6094,14 +6230,16 @@ return JIM_OK; } -#if 0 - /* Optimise dict -> list. XXX: Is it worth it? */ - if (Jim_IsDict(objPtr)) { + /* Optimise dict -> list for unshared object. Note that this may only save a little time, but + * it also preserves any source location of the dict elements + * which can be very useful + */ + if (Jim_IsDict(objPtr) && !Jim_IsShared(objPtr)) { Jim_Obj **listObjPtrPtr; int len; int i; - Jim_DictPairs(interp, objPtr, &listObjPtrPtr, &len); + listObjPtrPtr = JimDictPairs(objPtr, &len); for (i = 0; i < len; i++) { Jim_IncrRefCount(listObjPtrPtr[i]); } @@ -6115,7 +6253,6 @@ return JIM_OK; } -#endif /* Try to preserve information about filename / line number */ if (objPtr->typePtr == &sourceObjType) { @@ -6140,16 +6277,18 @@ objPtr->internalRep.listValue.ele = NULL; /* Convert into a list */ - JimParserInit(&parser, str, strLen, linenr); - while (!parser.eof) { - Jim_Obj *elementPtr; + if (strLen) { + JimParserInit(&parser, str, strLen, linenr); + while (!parser.eof) { + Jim_Obj *elementPtr; - JimParseList(&parser); - if (parser.tt != JIM_TT_STR && parser.tt != JIM_TT_ESC) - continue; - elementPtr = JimParserGetTokenObj(interp, &parser); - JimSetSourceInfo(interp, elementPtr, fileNameObj, parser.tline); - ListAppendElement(objPtr, elementPtr); + JimParseList(&parser); + if (parser.tt != JIM_TT_STR && parser.tt != JIM_TT_ESC) + continue; + elementPtr = JimParserGetTokenObj(interp, &parser); + JimSetSourceInfo(interp, elementPtr, fileNameObj, parser.tline); + ListAppendElement(objPtr, elementPtr); + } } Jim_DecrRefCount(interp, fileNameObj); return JIM_OK; @@ -6343,10 +6482,18 @@ Jim_Obj **point; if (requiredLen > listPtr->internalRep.listValue.maxLen) { - listPtr->internalRep.listValue.maxLen = requiredLen * 2; + if (requiredLen < 2) { + /* Don't do allocations of under 4 pointers. */ + requiredLen = 4; + } + else { + requiredLen *= 2; + } listPtr->internalRep.listValue.ele = Jim_Realloc(listPtr->internalRep.listValue.ele, - sizeof(Jim_Obj *) * listPtr->internalRep.listValue.maxLen); + sizeof(Jim_Obj *) * requiredLen); + + listPtr->internalRep.listValue.maxLen = requiredLen; } if (idx < 0) { idx = currentLen; @@ -6668,7 +6815,7 @@ void DupDictInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr) { Jim_HashTable *ht, *dupHt; - Jim_HashTableIterator *htiter; + Jim_HashTableIterator htiter; Jim_HashEntry *he; /* Create a new hash table */ @@ -6678,8 +6825,8 @@ if (ht->size != 0) Jim_ExpandHashTable(dupHt, ht->size); /* Copy every element from the source to the dup hash table */ - htiter = Jim_GetHashTableIterator(ht); - while ((he = Jim_NextHashEntry(htiter)) != NULL) { + JimInitHashTableIterator(ht, &htiter); + while ((he = Jim_NextHashEntry(&htiter)) != NULL) { const Jim_Obj *keyObjPtr = he->key; Jim_Obj *valObjPtr = he->u.val; @@ -6687,7 +6834,6 @@ Jim_IncrRefCount(valObjPtr); Jim_AddHashEntry(dupHt, keyObjPtr, valObjPtr); } - Jim_FreeHashTableIterator(htiter); dupPtr->internalRep.ptr = dupHt; dupPtr->typePtr = &dictObjType; @@ -6696,7 +6842,7 @@ static Jim_Obj **JimDictPairs(Jim_Obj *dictPtr, int *len) { Jim_HashTable *ht; - Jim_HashTableIterator *htiter; + Jim_HashTableIterator htiter; Jim_HashEntry *he; Jim_Obj **objv; int i; @@ -6705,14 +6851,13 @@ /* Turn the hash table into a flat vector of Jim_Objects. */ objv = Jim_Alloc((ht->used * 2) * sizeof(Jim_Obj *)); - htiter = Jim_GetHashTableIterator(ht); + JimInitHashTableIterator(ht, &htiter); i = 0; - while ((he = Jim_NextHashEntry(htiter)) != NULL) { + while ((he = Jim_NextHashEntry(&htiter)) != NULL) { objv[i++] = (Jim_Obj *)he->key; objv[i++] = he->u.val; } *len = i; - Jim_FreeHashTableIterator(htiter); return objv; } @@ -7033,7 +7178,7 @@ idx = 0; } else { - idx = strtol(str, &endptr, 0); + idx = jim_strtol(str, &endptr); if (endptr == str) { goto badindex; @@ -7045,7 +7190,7 @@ if (*str == '+' || *str == '-') { int sign = (*str == '+' ? 1 : -1); - idx += sign * strtol(++str, &endptr, 0); + idx += sign * jim_strtol(++str, &endptr); if (str == endptr || *endptr) { goto badindex; } @@ -7277,10 +7422,11 @@ typedef struct Jim_ExprOperator { const char *name; - int precedence; - int arity; int (*funcop) (Jim_Interp *interp, struct JimExprState * e); - int lazy; + unsigned char precedence; + unsigned char arity; + unsigned char lazy; + unsigned char namelen; } Jim_ExprOperator; static void ExprPush(struct JimExprState *e, Jim_Obj *obj) @@ -7980,91 +8126,96 @@ /* name - precedence - arity - opcode * - * This array *must* be kept in sync with the JIM_EXPROP enum + * This array *must* be kept in sync with the JIM_EXPROP enum. + * + * The following macro pre-computes the string length at compile time. */ +#define OPRINIT(N, P, A, F, L) {N, F, P, A, L, sizeof(N) - 1} + static const struct Jim_ExprOperator Jim_ExprOperators[] = { - {"*", 200, 2, JimExprOpBin, LAZY_NONE}, - {"/", 200, 2, JimExprOpBin, LAZY_NONE}, - {"%", 200, 2, JimExprOpIntBin, LAZY_NONE}, + OPRINIT("*", 110, 2, JimExprOpBin, LAZY_NONE), + OPRINIT("/", 110, 2, JimExprOpBin, LAZY_NONE), + OPRINIT("%", 110, 2, JimExprOpIntBin, LAZY_NONE), - {"-", 100, 2, JimExprOpBin, LAZY_NONE}, - {"+", 100, 2, JimExprOpBin, LAZY_NONE}, + OPRINIT("-", 100, 2, JimExprOpBin, LAZY_NONE), + OPRINIT("+", 100, 2, JimExprOpBin, LAZY_NONE), - {"<<", 90, 2, JimExprOpIntBin, LAZY_NONE}, - {">>", 90, 2, JimExprOpIntBin, LAZY_NONE}, + OPRINIT("<<", 90, 2, JimExprOpIntBin, LAZY_NONE), + OPRINIT(">>", 90, 2, JimExprOpIntBin, LAZY_NONE), - {"<<<", 90, 2, JimExprOpIntBin, LAZY_NONE}, - {">>>", 90, 2, JimExprOpIntBin, LAZY_NONE}, + OPRINIT("<<<", 90, 2, JimExprOpIntBin, LAZY_NONE), + OPRINIT(">>>", 90, 2, JimExprOpIntBin, LAZY_NONE), - {"<", 80, 2, JimExprOpBin, LAZY_NONE}, - {">", 80, 2, JimExprOpBin, LAZY_NONE}, - {"<=", 80, 2, JimExprOpBin, LAZY_NONE}, - {">=", 80, 2, JimExprOpBin, LAZY_NONE}, + OPRINIT("<", 80, 2, JimExprOpBin, LAZY_NONE), + OPRINIT(">", 80, 2, JimExprOpBin, LAZY_NONE), + OPRINIT("<=", 80, 2, JimExprOpBin, LAZY_NONE), + OPRINIT(">=", 80, 2, JimExprOpBin, LAZY_NONE), - {"==", 70, 2, JimExprOpBin, LAZY_NONE}, - {"!=", 70, 2, JimExprOpBin, LAZY_NONE}, + OPRINIT("==", 70, 2, JimExprOpBin, LAZY_NONE), + OPRINIT("!=", 70, 2, JimExprOpBin, LAZY_NONE), - {"&", 50, 2, JimExprOpIntBin, LAZY_NONE}, - {"^", 49, 2, JimExprOpIntBin, LAZY_NONE}, - {"|", 48, 2, JimExprOpIntBin, LAZY_NONE}, + OPRINIT("&", 50, 2, JimExprOpIntBin, LAZY_NONE), + OPRINIT("^", 49, 2, JimExprOpIntBin, LAZY_NONE), + OPRINIT("|", 48, 2, JimExprOpIntBin, LAZY_NONE), - {"&&", 10, 2, NULL, LAZY_OP}, - {NULL, 10, 2, JimExprOpAndLeft, LAZY_LEFT}, - {NULL, 10, 2, JimExprOpAndOrRight, LAZY_RIGHT}, + OPRINIT("&&", 10, 2, NULL, LAZY_OP), + OPRINIT(NULL, 10, 2, JimExprOpAndLeft, LAZY_LEFT), + OPRINIT(NULL, 10, 2, JimExprOpAndOrRight, LAZY_RIGHT), - {"||", 9, 2, NULL, LAZY_OP}, - {NULL, 9, 2, JimExprOpOrLeft, LAZY_LEFT}, - {NULL, 9, 2, JimExprOpAndOrRight, LAZY_RIGHT}, + OPRINIT("||", 9, 2, NULL, LAZY_OP), + OPRINIT(NULL, 9, 2, JimExprOpOrLeft, LAZY_LEFT), + OPRINIT(NULL, 9, 2, JimExprOpAndOrRight, LAZY_RIGHT), - {"?", 5, 2, JimExprOpNull, LAZY_OP}, - {NULL, 5, 2, JimExprOpTernaryLeft, LAZY_LEFT}, - {NULL, 5, 2, JimExprOpNull, LAZY_RIGHT}, + OPRINIT("?", 5, 2, JimExprOpNull, LAZY_OP), + OPRINIT(NULL, 5, 2, JimExprOpTernaryLeft, LAZY_LEFT), + OPRINIT(NULL, 5, 2, JimExprOpNull, LAZY_RIGHT), - {":", 5, 2, JimExprOpNull, LAZY_OP}, - {NULL, 5, 2, JimExprOpColonLeft, LAZY_LEFT}, - {NULL, 5, 2, JimExprOpNull, LAZY_RIGHT}, + OPRINIT(":", 5, 2, JimExprOpNull, LAZY_OP), + OPRINIT(NULL, 5, 2, JimExprOpColonLeft, LAZY_LEFT), + OPRINIT(NULL, 5, 2, JimExprOpNull, LAZY_RIGHT), - {"**", 250, 2, JimExprOpBin, LAZY_NONE}, + OPRINIT("**", 250, 2, JimExprOpBin, LAZY_NONE), - {"eq", 60, 2, JimExprOpStrBin, LAZY_NONE}, - {"ne", 60, 2, JimExprOpStrBin, LAZY_NONE}, + OPRINIT("eq", 60, 2, JimExprOpStrBin, LAZY_NONE), + OPRINIT("ne", 60, 2, JimExprOpStrBin, LAZY_NONE), - {"in", 55, 2, JimExprOpStrBin, LAZY_NONE}, - {"ni", 55, 2, JimExprOpStrBin, LAZY_NONE}, + OPRINIT("in", 55, 2, JimExprOpStrBin, LAZY_NONE), + OPRINIT("ni", 55, 2, JimExprOpStrBin, LAZY_NONE), - {"!", 300, 1, JimExprOpNumUnary, LAZY_NONE}, - {"~", 300, 1, JimExprOpIntUnary, LAZY_NONE}, - {NULL, 300, 1, JimExprOpNumUnary, LAZY_NONE}, - {NULL, 300, 1, JimExprOpNumUnary, LAZY_NONE}, + OPRINIT("!", 150, 1, JimExprOpNumUnary, LAZY_NONE), + OPRINIT("~", 150, 1, JimExprOpIntUnary, LAZY_NONE), + OPRINIT(NULL, 150, 1, JimExprOpNumUnary, LAZY_NONE), + OPRINIT(NULL, 150, 1, JimExprOpNumUnary, LAZY_NONE), - {"int", 400, 1, JimExprOpNumUnary, LAZY_NONE}, - {"abs", 400, 1, JimExprOpNumUnary, LAZY_NONE}, - {"double", 400, 1, JimExprOpNumUnary, LAZY_NONE}, - {"round", 400, 1, JimExprOpNumUnary, LAZY_NONE}, - {"rand", 400, 0, JimExprOpNone, LAZY_NONE}, - {"srand", 400, 1, JimExprOpIntUnary, LAZY_NONE}, + OPRINIT("int", 200, 1, JimExprOpNumUnary, LAZY_NONE), + OPRINIT("abs", 200, 1, JimExprOpNumUnary, LAZY_NONE), + OPRINIT("double", 200, 1, JimExprOpNumUnary, LAZY_NONE), + OPRINIT("round", 200, 1, JimExprOpNumUnary, LAZY_NONE), + OPRINIT("rand", 200, 0, JimExprOpNone, LAZY_NONE), + OPRINIT("srand", 200, 1, JimExprOpIntUnary, LAZY_NONE), #ifdef JIM_MATH_FUNCTIONS - {"sin", 400, 1, JimExprOpDoubleUnary, LAZY_NONE}, - {"cos", 400, 1, JimExprOpDoubleUnary, LAZY_NONE}, - {"tan", 400, 1, JimExprOpDoubleUnary, LAZY_NONE}, - {"asin", 400, 1, JimExprOpDoubleUnary, LAZY_NONE}, - {"acos", 400, 1, JimExprOpDoubleUnary, LAZY_NONE}, - {"atan", 400, 1, JimExprOpDoubleUnary, LAZY_NONE}, - {"sinh", 400, 1, JimExprOpDoubleUnary, LAZY_NONE}, - {"cosh", 400, 1, JimExprOpDoubleUnary, LAZY_NONE}, - {"tanh", 400, 1, JimExprOpDoubleUnary, LAZY_NONE}, - {"ceil", 400, 1, JimExprOpDoubleUnary, LAZY_NONE}, - {"floor", 400, 1, JimExprOpDoubleUnary, LAZY_NONE}, - {"exp", 400, 1, JimExprOpDoubleUnary, LAZY_NONE}, - {"log", 400, 1, JimExprOpDoubleUnary, LAZY_NONE}, - {"log10", 400, 1, JimExprOpDoubleUnary, LAZY_NONE}, - {"sqrt", 400, 1, JimExprOpDoubleUnary, LAZY_NONE}, - {"pow", 400, 2, JimExprOpBin, LAZY_NONE}, + OPRINIT("sin", 200, 1, JimExprOpDoubleUnary, LAZY_NONE), + OPRINIT("cos", 200, 1, JimExprOpDoubleUnary, LAZY_NONE), + OPRINIT("tan", 200, 1, JimExprOpDoubleUnary, LAZY_NONE), + OPRINIT("asin", 200, 1, JimExprOpDoubleUnary, LAZY_NONE), + OPRINIT("acos", 200, 1, JimExprOpDoubleUnary, LAZY_NONE), + OPRINIT("atan", 200, 1, JimExprOpDoubleUnary, LAZY_NONE), + OPRINIT("sinh", 200, 1, JimExprOpDoubleUnary, LAZY_NONE), + OPRINIT("cosh", 200, 1, JimExprOpDoubleUnary, LAZY_NONE), + OPRINIT("tanh", 200, 1, JimExprOpDoubleUnary, LAZY_NONE), + OPRINIT("ceil", 200, 1, JimExprOpDoubleUnary, LAZY_NONE), + OPRINIT("floor", 200, 1, JimExprOpDoubleUnary, LAZY_NONE), + OPRINIT("exp", 200, 1, JimExprOpDoubleUnary, LAZY_NONE), + OPRINIT("log", 200, 1, JimExprOpDoubleUnary, LAZY_NONE), + OPRINIT("log10", 200, 1, JimExprOpDoubleUnary, LAZY_NONE), + OPRINIT("sqrt", 200, 1, JimExprOpDoubleUnary, LAZY_NONE), + OPRINIT("pow", 200, 2, JimExprOpBin, LAZY_NONE), #endif }; +#undef OPRINIT #define JIM_EXPR_OPERATORS_NUM \ (sizeof(Jim_ExprOperators)/sizeof(struct Jim_ExprOperator)) @@ -8149,28 +8300,53 @@ static int JimParseExprNumber(struct JimParserCtx *pc) { int allowdot = 1; - int allowhex = 0; + int base = 10; /* Assume an integer for now */ pc->tt = JIM_TT_EXPR_INT; pc->tstart = pc->p; pc->tline = pc->linenr; + + /* Parse initial 0 */ + if (pc->p[0] == '0') { + switch (pc->p[1]) { + case 'x': + case 'X': + base = 16; + allowdot = 0; + pc->p += 2; + pc->len -= 2; + break; + case 'o': + case 'O': + base = 8; + allowdot = 0; + pc->p += 2; + pc->len -= 2; + break; + case 'b': + case 'B': + base = 2; + allowdot = 0; + pc->p += 2; + pc->len -= 2; + break; + } + } + while (isdigit(UCHAR(*pc->p)) - || (allowhex && isxdigit(UCHAR(*pc->p))) + || (base == 16 && isxdigit(UCHAR(*pc->p))) + || (base == 8 && *pc->p >= '0' && *pc->p <= '7') + || (base == 2 && (*pc->p == '0' || *pc->p == '1')) || (allowdot && *pc->p == '.') - || (pc->p - pc->tstart == 1 && *pc->tstart == '0' && (*pc->p == 'x' || *pc->p == 'X')) ) { - if ((*pc->p == 'x') || (*pc->p == 'X')) { - allowhex = 1; - allowdot = 0; - } if (*pc->p == '.') { allowdot = 0; pc->tt = JIM_TT_EXPR_DOUBLE; } pc->p++; pc->len--; - if (!allowhex && (*pc->p == 'e' || *pc->p == 'E') && (pc->p[1] == '-' || pc->p[1] == '+' + if (base == 10 && (*pc->p == 'e' || *pc->p == 'E') && (pc->p[1] == '-' || pc->p[1] == '+' || isdigit(UCHAR(pc->p[1])))) { pc->p += 2; pc->len -= 2; @@ -8209,16 +8385,14 @@ /* Try to get the longest match. */ for (i = 0; i < (signed)JIM_EXPR_OPERATORS_NUM; i++) { - const char *opname; - int oplen; + const char * const opname = Jim_ExprOperators[i].name; + const int oplen = Jim_ExprOperators[i].namelen; - opname = Jim_ExprOperators[i].name; - if (opname == NULL) { + if (opname == NULL || opname[0] != pc->p[0]) { continue; } - oplen = strlen(opname); - if (strncmp(opname, pc->p, oplen) == 0 && oplen > bestLen) { + if (oplen > bestLen && strncmp(opname, pc->p, oplen) == 0) { bestIdx = i + JIM_TT_EXPR_OP; bestLen = oplen; } @@ -8297,8 +8471,8 @@ /* Expr bytecode structure */ typedef struct ExprByteCode { - int len; /* Length as number of tokens. */ ScriptToken *token; /* Tokens array. */ + int len; /* Length as number of tokens. */ int inUse; /* Used for sharing. */ } ExprByteCode; @@ -8679,8 +8853,9 @@ case JIM_TT_DICTSUGAR: case JIM_TT_EXPRSUGAR: case JIM_TT_CMD: - token->objPtr = Jim_NewStringObj(interp, t->token, t->len); token->type = t->type; +strexpr: + token->objPtr = Jim_NewStringObj(interp, t->token, t->len); if (t->type == JIM_TT_CMD) { /* Only commands need source info */ JimSetSourceInfo(interp, token->objPtr, fileNameObj, t->line); @@ -8689,15 +8864,24 @@ break; case JIM_TT_EXPR_INT: - token->objPtr = Jim_NewIntObj(interp, strtoull(t->token, NULL, 0)); - token->type = t->type; - expr->len++; - break; - case JIM_TT_EXPR_DOUBLE: - token->objPtr = Jim_NewDoubleObj(interp, strtod(t->token, NULL)); - token->type = t->type; - expr->len++; + { + char *endptr; + if (t->type == JIM_TT_EXPR_INT) { + token->objPtr = Jim_NewIntObj(interp, jim_strtoull(t->token, &endptr)); + } + else { + token->objPtr = Jim_NewDoubleObj(interp, strtod(t->token, &endptr)); + } + if (endptr != t->token + t->len) { + /* Conversion failed, so just store it as a string */ + Jim_FreeNewObj(interp, token->objPtr); + token->type = JIM_TT_STR; + goto strexpr; + } + token->type = t->type; + expr->len++; + } break; case JIM_TT_SUBEXPR_START: @@ -9192,12 +9376,12 @@ typedef struct ScanFmtPartDescr { - char type; /* Type of conversion (e.g. c, d, f) */ - char modifier; /* Modify type (e.g. l - long, h - short */ - size_t width; /* Maximal width of input to be converted */ - int pos; /* -1 - no assign, 0 - natural pos, >0 - XPG3 pos */ char *arg; /* Specification of a CHARSET conversion */ char *prefix; /* Prefix to be scanned literally before conversion */ + size_t width; /* Maximal width of input to be converted */ + int pos; /* -1 - no assign, 0 - natural pos, >0 - XPG3 pos */ + char type; /* Type of conversion (e.g. c, d, f) */ + char modifier; /* Modify type (e.g. l - long, h - short */ } ScanFmtPartDescr; /* The ScanFmtStringObj will hold the internal representation of a scanformat @@ -9563,14 +9747,11 @@ : descr->type == 'x' ? 16 : descr->type == 'i' ? 0 : 10; /* Try to scan a number with the given base */ - w = strtoull(tok, &endp, base); - if (endp == tok && base == 0) { - /* If scanning failed, and base was undetermined, simply - * put it to 10 and try once more. This should catch the - * case where %i begin to parse a number prefix (e.g. - * '0x' but no further digits follows. This will be - * handled as a ZERO followed by a char 'x' by Tcl) */ - w = strtoull(tok, &endp, 10); + if (base == 0) { + w = jim_strtoull(tok, &endp); + } + else { + w = strtoull(tok, &endp, base); } if (endp != tok) { @@ -10336,8 +10517,8 @@ if (retcode == JIM_OK && argc) { /* Invoke the command */ retcode = JimInvokeCommand(interp, argc, argv); - if (interp->signal_level && interp->sigmask) { - /* Check for a signal after each command */ + /* Check for a signal after each command */ + if (Jim_CheckSignal(interp)) { retcode = JIM_SIGNAL; } } @@ -10508,6 +10689,11 @@ return JIM_ERR; } + if (Jim_Length(cmd->u.proc.bodyObjPtr) == 0) { + /* Optimise for procedure with no body - useful for optional debugging */ + return JIM_OK; + } + /* Check if there are too nested calls */ if (interp->framePtr->level == interp->maxCallFrameDepth) { Jim_SetResultString(interp, "Too many nested calls. Infinite recursion?", -1); @@ -10776,74 +10962,45 @@ /* ----------------------------------------------------------------------------- * Subst * ---------------------------------------------------------------------------*/ -static int JimParseSubstStr(struct JimParserCtx *pc) +static void JimParseSubst(struct JimParserCtx *pc, int flags) { pc->tstart = pc->p; pc->tline = pc->linenr; - while (pc->len && *pc->p != '$' && *pc->p != '[') { - if (*pc->p == '\\' && pc->len > 1) { - pc->p++; - pc->len--; - } - pc->p++; - pc->len--; - } - pc->tend = pc->p - 1; - pc->tt = JIM_TT_ESC; - return JIM_OK; -} - -static int JimParseSubst(struct JimParserCtx *pc, int flags) -{ - int retval; if (pc->len == 0) { - pc->tstart = pc->tend = pc->p; - pc->tline = pc->linenr; + pc->tend = pc->p; pc->tt = JIM_TT_EOL; pc->eof = 1; - return JIM_OK; + return; } - switch (*pc->p) { - case '[': - retval = JimParseCmd(pc); - if (flags & JIM_SUBST_NOCMD) { - pc->tstart--; - pc->tend++; - pc->tt = (flags & JIM_SUBST_NOESC) ? JIM_TT_STR : JIM_TT_ESC; - } - return retval; - break; - case '$': - if (JimParseVar(pc) == JIM_ERR) { - pc->tstart = pc->tend = pc->p++; - pc->len--; - pc->tline = pc->linenr; - pc->tt = JIM_TT_STR; - } - else { - if (flags & JIM_SUBST_NOVAR) { - pc->tstart--; - if (flags & JIM_SUBST_NOESC) - pc->tt = JIM_TT_STR; - else - pc->tt = JIM_TT_ESC; - if (*pc->tstart == '{') { - pc->tstart--; - if (*(pc->tend + 1)) - pc->tend++; - } - } - } + if (*pc->p == '[' && !(flags & JIM_SUBST_NOCMD)) { + JimParseCmd(pc); + return; + } + if (*pc->p == '$' && !(flags & JIM_SUBST_NOVAR)) { + if (JimParseVar(pc) == JIM_OK) { + return; + } + /* Not a var, so treat as a string */ + pc->tstart = pc->p; + flags |= JIM_SUBST_NOVAR; + } + while (pc->len) { + if (*pc->p == '$' && !(flags & JIM_SUBST_NOVAR)) { break; - default: - retval = JimParseSubstStr(pc); - if (flags & JIM_SUBST_NOESC) - pc->tt = JIM_TT_STR; - return retval; + } + if (*pc->p == '[' && !(flags & JIM_SUBST_NOCMD)) { break; + } + if (*pc->p == '\\' && pc->len > 1) { + pc->p++; + pc->len--; + } + pc->p++; + pc->len--; } - return JIM_OK; + pc->tend = pc->p - 1; + pc->tt = (flags & JIM_SUBST_NOESC) ? JIM_TT_STR : JIM_TT_ESC; } /* The subst object type reuses most of the data structures and functions @@ -10982,13 +11139,13 @@ } } else { - Jim_HashTableIterator *htiter = Jim_GetHashTableIterator(ht); - while ((he = Jim_NextHashEntry(htiter)) != NULL) { + 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); } } - Jim_FreeHashTableIterator(htiter); } return listObjPtr; } @@ -13154,6 +13311,9 @@ static const char * const nocase_options[] = { "-nocase", NULL }; + static const char * const nocase_length_options[] = { + "-nocase", "-length", NULL + }; if (argc < 2) { Jim_WrongNumArgs(interp, 1, argv, "option ?arguments ...?"); @@ -13181,23 +13341,54 @@ case OPT_COMPARE: case OPT_EQUAL: - if (argc != 4 && - (argc != 5 || - Jim_GetEnum(interp, argv[2], nocase_options, &opt_case, NULL, - JIM_ENUM_ABBREV) != JIM_OK)) { - Jim_WrongNumArgs(interp, 2, argv, "?-nocase? string1 string2"); - return JIM_ERR; - } - if (opt_case == 0) { - argv++; - } - if (option == OPT_COMPARE || !opt_case) { - Jim_SetResultInt(interp, Jim_StringCompareObj(interp, argv[2], argv[3], !opt_case)); - } - else { - Jim_SetResultBool(interp, Jim_StringEqObj(argv[2], argv[3])); + { + /* n is the number of remaining option args */ + long opt_length = -1; + int n = argc - 4; + int i = 2; + while (n > 0) { + int subopt; + if (Jim_GetEnum(interp, argv[i++], nocase_length_options, &subopt, NULL, + JIM_ENUM_ABBREV) != JIM_OK) { +badcompareargs: + Jim_WrongNumArgs(interp, 2, argv, "?-nocase? ?-length int? string1 string2"); + return JIM_ERR; + } + if (subopt == 0) { + /* -nocase */ + opt_case = 0; + n--; + } + else { + /* -length */ + if (n < 2) { + goto badcompareargs; + } + if (Jim_GetLong(interp, argv[i++], &opt_length) != JIM_OK) { + return JIM_ERR; + } + n -= 2; + } + } + if (n) { + goto badcompareargs; + } + argv += argc - 2; + if (opt_length < 0 && option != OPT_COMPARE && opt_case) { + /* Fast version - [string equal], case sensitive, no length */ + Jim_SetResultBool(interp, Jim_StringEqObj(argv[0], argv[1])); + } + else { + if (opt_length >= 0) { + n = JimStringCompareLen(Jim_String(argv[0]), Jim_String(argv[1]), opt_length, !opt_case); + } + else { + n = Jim_StringCompareObj(interp, argv[0], argv[1], !opt_case); + } + Jim_SetResultInt(interp, option == OPT_COMPARE ? n : n == 0); + } + return JIM_OK; } - return JIM_OK; case OPT_MATCH: if (argc != 4 && @@ -13262,7 +13453,7 @@ Jim_Obj *objPtr; if (argc != 5 && argc != 6) { - Jim_WrongNumArgs(interp, 2, argv, "string first last ?newstring?"); + 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); @@ -13560,7 +13751,7 @@ } interp->signal_level += sig; - if (interp->signal_level && interp->sigmask) { + if (Jim_CheckSignal(interp)) { /* If a signal is set, don't even try to execute the body */ exitCode = JIM_SIGNAL; } @@ -13716,21 +13907,20 @@ static int JimInfoReferences(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { Jim_Obj *listObjPtr; - Jim_HashTableIterator *htiter; + Jim_HashTableIterator htiter; Jim_HashEntry *he; listObjPtr = Jim_NewListObj(interp, NULL, 0); - htiter = Jim_GetHashTableIterator(&interp->references); - while ((he = Jim_NextHashEntry(htiter)) != NULL) { - char buf[JIM_REFERENCE_SPACE]; + JimInitHashTableIterator(&interp->references, &htiter); + while ((he = Jim_NextHashEntry(&htiter)) != NULL) { + char buf[JIM_REFERENCE_SPACE + 1]; Jim_Reference *refPtr = he->u.val; - const jim_wide *refId = he->key; + const unsigned long *refId = he->key; JimFormatReference(buf, refPtr, *refId); Jim_ListAppendElement(interp, listObjPtr, Jim_NewStringObj(interp, buf, -1)); } - Jim_FreeHashTableIterator(htiter); Jim_SetResult(interp, listObjPtr); return JIM_OK; } @@ -13773,13 +13963,13 @@ Jim_Obj *listObjPtr = Jim_NewListObj(interp, NULL, 0); /* Check for the non-pattern case. We can do this much more efficiently. */ - Jim_HashTableIterator *htiter = Jim_GetHashTableIterator(ht); - while ((he = Jim_NextHashEntry(htiter)) != NULL) { + Jim_HashTableIterator htiter; + JimInitHashTableIterator(ht, &htiter); + while ((he = Jim_NextHashEntry(&htiter)) != NULL) { if (patternObjPtr == NULL || JimGlobMatch(Jim_String(patternObjPtr), Jim_String((Jim_Obj *)he->key), 0)) { callback(interp, listObjPtr, he, type); } } - Jim_FreeHashTableIterator(htiter); return listObjPtr; } @@ -13975,7 +14165,6 @@ int cmd; Jim_Obj *objPtr; int mode = 0; - int nons = 0; static const char * const commands[] = { "body", "statics", "commands", "procs", "channels", "exists", "globals", "level", "frame", "locals", @@ -13990,16 +14179,21 @@ INFO_RETURNCODES, INFO_REFERENCES, INFO_ALIAS }; - if (argc < 2) { - Jim_WrongNumArgs(interp, 1, argv, "subcommand ?args ...?"); - return JIM_ERR; - } +#ifdef jim_ext_namespace + int nons = 0; + if (argc > 2 && Jim_CompareStringImmediate(interp, argv[1], "-nons")) { /* This is for internal use only */ argc--; argv++; nons = 1; } +#endif + + if (argc < 2) { + Jim_WrongNumArgs(interp, 1, argv, "subcommand ?args ...?"); + return JIM_ERR; + } if (Jim_GetEnum(interp, argv[1], commands, &cmd, "subcommand", JIM_ERRMSG | JIM_ENUM_ABBREV) != JIM_OK) { return JIM_ERR; diff -Nru jimtcl-0.73/jim-eventloop.c jimtcl-0.74/jim-eventloop.c --- jimtcl-0.73/jim-eventloop.c 2011-12-19 22:11:37.000000000 +0000 +++ jimtcl-0.74/jim-eventloop.c 2013-07-24 05:36:47.000000000 +0000 @@ -567,16 +567,19 @@ Jim_Obj *currValue; currValue = Jim_GetGlobalVariable(interp, argv[1], JIM_NONE); /* Stop the loop if the vwait-ed variable changed value, - * or if was unset and now is set (or the contrary). */ + * or if was unset and now is set (or the contrary) + * or if a signal was caught + */ if ((oldValue && !currValue) || (!oldValue && currValue) || - (oldValue && currValue && !Jim_StringEqObj(oldValue, currValue))) + (oldValue && currValue && !Jim_StringEqObj(oldValue, currValue)) || + Jim_CheckSignal(interp)) { break; + } } if (oldValue) Jim_DecrRefCount(interp, oldValue); - if (rc == -2) { return JIM_ERR; } diff -Nru jimtcl-0.73/jim-exec.c jimtcl-0.74/jim-exec.c --- jimtcl-0.73/jim-exec.c 2011-12-19 22:11:37.000000000 +0000 +++ jimtcl-0.74/jim-exec.c 2013-07-24 05:36:47.000000000 +0000 @@ -255,12 +255,11 @@ if (num % 2) { num--; } - size = Jim_Length(objPtr); /* We need one \0 and one equal sign for each element. * A list has at least one space for each element except the first. - * We only need one extra char for the extra null terminator. + * We need one extra char for the extra null terminator and one for the equal sign. */ - size++; + size = Jim_Length(objPtr) + 2; envptr = Jim_Alloc(sizeof(*envptr) * (num / 2 + 1) + size); envdata = (char *)&envptr[num / 2 + 1]; @@ -1393,7 +1392,7 @@ static void JimRestoreEnv(char **env) { - JimFreeEnv(env, NULL); + JimFreeEnv(env, Jim_GetEnviron()); } static Jim_Obj * diff -Nru jimtcl-0.73/jim-file.c jimtcl-0.74/jim-file.c --- jimtcl-0.73/jim-file.c 2011-12-19 22:11:37.000000000 +0000 +++ jimtcl-0.74/jim-file.c 2013-07-24 05:36:47.000000000 +0000 @@ -199,7 +199,9 @@ const char *path = Jim_String(argv[0]); const char *p = strrchr(path, '/'); - if (!p) { + if (!p && path[0] == '.' && path[1] == '.' && path[2] == '\0') { + Jim_SetResultString(interp, "..", -1); + } else if (!p) { Jim_SetResultString(interp, ".", -1); } else if (p == path) { @@ -267,12 +269,13 @@ if (realpath(path, newname)) { Jim_SetResult(interp, Jim_NewStringObjNoAlloc(interp, newname, -1)); + return JIM_OK; } else { Jim_Free(newname); - Jim_SetResult(interp, argv[0]); + Jim_SetResultFormatted(interp, "can't normalize \"%#s\": %s", argv[0], strerror(errno)); + return JIM_ERR; } - return JIM_OK; #else Jim_SetResultString(interp, "Not implemented", -1); return JIM_ERR; @@ -430,14 +433,16 @@ while (ok--) { /* Must have failed the first time, so recursively make the parent and try again */ - char *slash = strrchr(path, '/'); + { + char *slash = strrchr(path, '/'); - if (slash && slash != path) { - *slash = 0; - if (mkdir_all(path) != 0) { - return -1; + if (slash && slash != path) { + *slash = 0; + if (mkdir_all(path) != 0) { + return -1; + } + *slash = '/'; } - *slash = '/'; } first: if (MKDIR_DEFAULT(path) == 0) { diff -Nru jimtcl-0.73/jim.h jimtcl-0.74/jim.h --- jimtcl-0.73/jim.h 2011-12-19 22:11:37.000000000 +0000 +++ jimtcl-0.74/jim.h 2013-07-24 05:36:47.000000000 +0000 @@ -128,7 +128,7 @@ /* Jim version numbering: every version of jim is marked with a * successive integer number. This is version 0. The first * stable version will be 1, then 2, 3, and so on. */ -#define JIM_VERSION 73 +#define JIM_VERSION 74 #define JIM_OK 0 #define JIM_ERR 1 @@ -285,10 +285,10 @@ * The refcount of a freed object is always -1. * ---------------------------------------------------------------------------*/ typedef struct Jim_Obj { - int refCount; /* reference count */ char *bytes; /* string representation buffer. NULL = no string repr. */ - int length; /* number of bytes in 'bytes', not including the null term. */ const struct Jim_ObjType *typePtr; /* object type. */ + int refCount; /* reference count */ + int length; /* number of bytes in 'bytes', not including the null term. */ /* Internal representation union */ union { /* integer number type */ @@ -540,6 +540,7 @@ Jim_Obj *liveList; /* Linked list of all the live objects. */ Jim_Obj *freeList; /* Linked list of all the unused objects. */ Jim_Obj *currentScriptObj; /* Script currently in execution. */ + Jim_Obj *nullScriptObj; /* script representation of an empty string */ Jim_Obj *emptyObj; /* Shared empty string object. */ Jim_Obj *trueObj; /* Shared true int object. */ Jim_Obj *falseObj; /* Shared false int object. */ @@ -689,8 +690,6 @@ JIM_EXPORT Jim_Obj * Jim_NewObj (Jim_Interp *interp); JIM_EXPORT void Jim_FreeObj (Jim_Interp *interp, Jim_Obj *objPtr); JIM_EXPORT void Jim_InvalidateStringRep (Jim_Obj *objPtr); -JIM_EXPORT void Jim_InitStringRep (Jim_Obj *objPtr, const char *bytes, - int length); JIM_EXPORT Jim_Obj * Jim_DuplicateObj (Jim_Interp *interp, Jim_Obj *objPtr); JIM_EXPORT const char * Jim_GetString(Jim_Obj *objPtr, @@ -908,6 +907,12 @@ /* Misc */ JIM_EXPORT int Jim_InitStaticExtensions(Jim_Interp *interp); JIM_EXPORT int Jim_StringToWide(const char *str, jim_wide *widePtr, int base); +JIM_EXPORT int Jim_CheckSignal(Jim_Interp *interp); +/** + * Returns 1 if a signal has been received while + * in a catch -signal {} clause. + */ +#define Jim_CheckSignal(i) ((i)->signal_level && (i)->sigmask) /* jim-load.c */ JIM_EXPORT int Jim_LoadLibrary(Jim_Interp *interp, const char *pathName); diff -Nru jimtcl-0.73/jim-history.c jimtcl-0.74/jim-history.c --- jimtcl-0.73/jim-history.c 2011-12-19 22:11:37.000000000 +0000 +++ jimtcl-0.74/jim-history.c 2013-07-24 05:36:47.000000000 +0000 @@ -103,6 +103,11 @@ return Jim_CallSubCmd(interp, Jim_ParseSubCmd(interp, history_command_table, argc, argv), argc, argv); } +static void JimHistoryDelProc(Jim_Interp *interp, void *privData) +{ + Jim_Free(privData); +} + int Jim_historyInit(Jim_Interp *interp) { void **history; @@ -112,6 +117,6 @@ history = Jim_Alloc(sizeof(*history)); *history = NULL; - Jim_CreateCommand(interp, "history", JimHistorySubCmdProc, history, NULL); + Jim_CreateCommand(interp, "history", JimHistorySubCmdProc, history, JimHistoryDelProc); return JIM_OK; } diff -Nru jimtcl-0.73/jim-load.c jimtcl-0.74/jim-load.c --- jimtcl-0.73/jim-load.c 2011-12-19 22:11:37.000000000 +0000 +++ jimtcl-0.74/jim-load.c 2013-07-24 05:36:47.000000000 +0000 @@ -41,7 +41,8 @@ const char *pkgname; int pkgnamelen; char initsym[40]; - int (*onload) (Jim_Interp *); + typedef int jim_module_init_func_type(Jim_Interp *); + jim_module_init_func_type *onload; pt = strrchr(pathName, '/'); if (pt) { @@ -59,7 +60,7 @@ } snprintf(initsym, sizeof(initsym), "Jim_%.*sInit", pkgnamelen, pkgname); - if ((onload = dlsym(handle, initsym)) == NULL) { + if ((onload = (jim_module_init_func_type *)dlsym(handle, initsym)) == NULL) { Jim_SetResultFormatted(interp, "No %s symbol found in extension %s", initsym, pathName); } diff -Nru jimtcl-0.73/jimregexp.c jimtcl-0.74/jimregexp.c --- jimtcl-0.73/jimregexp.c 2011-12-19 22:11:37.000000000 +0000 +++ jimtcl-0.74/jimregexp.c 2013-07-24 05:36:47.000000000 +0000 @@ -1095,8 +1095,7 @@ goto nextline; } while (1) { - int ret = regtry(preg, string); - if (ret) { + if (regtry(preg, string)) { return REG_NOERROR; } if (*string) { diff -Nru jimtcl-0.73/jim-sqlite3.c jimtcl-0.74/jim-sqlite3.c --- jimtcl-0.73/jim-sqlite3.c 2011-12-19 22:11:37.000000000 +0000 +++ jimtcl-0.74/jim-sqlite3.c 2013-07-24 05:36:47.000000000 +0000 @@ -124,8 +124,8 @@ Jim_AppendString(interp, resObjPtr, "%", 1); break; default: - spec[1] = *fmt; - spec[2] = '\0'; + spec[0] = *fmt; + spec[1] = '\0'; Jim_FreeNewObj(interp, resObjPtr); Jim_SetResultFormatted(interp, "bad field specifier \"%s\", only %%s and %%%% are valid", spec); @@ -193,7 +193,7 @@ query = Jim_GetString(objPtr, &len); Jim_IncrRefCount(objPtr); /* Compile the query into VM code */ - if (sqlite3_prepare(sh->db, query, len, &stmt, &tail) != SQLITE_OK) { + if (sqlite3_prepare_v2(sh->db, query, len, &stmt, &tail) != SQLITE_OK) { Jim_DecrRefCount(interp, objPtr); Jim_SetResultString(interp, sqlite3_errmsg(sh->db), -1); Jim_Free(nullstr); diff -Nru jimtcl-0.73/jim_tcl.txt jimtcl-0.74/jim_tcl.txt --- jimtcl-0.73/jim_tcl.txt 2011-12-19 22:11:37.000000000 +0000 +++ jimtcl-0.74/jim_tcl.txt 2013-07-24 05:36:47.000000000 +0000 @@ -3,7 +3,7 @@ NAME ---- -Jim Tcl v0.73 - reference manual for the Jim Tcl scripting language +Jim Tcl v0.74 - reference manual for the Jim Tcl scripting language SYNOPSIS -------- @@ -52,6 +52,14 @@ RECENT CHANGES -------------- +Changes between 0.73 and 0.74 +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +1. Numbers with leading zeros are treated as decimal, not octal +2. Add `aio isatty` +3. Add LFS (64 bit) support for `aio seek`, `aio tell`, `aio copyto`, `file copy` +4. `string compare` and `string equal` now support '-length' +5. `glob` now supports '-directory' + Changes between 0.72 and 0.73 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 1. Built-in regexp now support non-capturing parentheses: (?:...) @@ -96,20 +104,6 @@ 11. Add `string byterange` 12. Built-in regexp now support non-greedy repetition (*?, +?, ??) -Changes between 0.63 and 0.70 -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -1. +platform_tcl()+ settings are now automatically determined -2. Add aio `$handle filename` -3. Add `info channels` -4. The 'bio' extension is gone. Now `aio` supports 'copyto'. -5. Add `exists` command -6. Add the pure-Tcl 'oo' extension -7. The `exec` command now only uses vfork(), not fork() -8. Unit test framework is less verbose and more Tcl-compatible -9. Optional UTF-8 support -10. Optional built-in regexp engine for better Tcl compatibility and UTF-8 support -11. Command line editing in interactive mode, e.g. 'jimsh' - TCL INTRODUCTION ----------------- Tcl stands for 'tool command language' and is pronounced 'tickle.' @@ -671,9 +665,9 @@ parentheses; it is ignored by the expression processor. Where possible, operands are interpreted as integer values. -Integer values may be specified in decimal (the normal case), in octal (if the -first character of the operand is '0'), or in hexadecimal (if the first -two characters of the operand are '0x'). +Integer values may be specified in decimal (the normal case) or in +hexadecimal (if the first two characters of the operand are '0x'). +Note that Jim Tcl does *not* treat numbers with leading zeros as octal. If an operand does not have one of the integer formats given above, then it is treated as a floating-point number if that is @@ -2525,7 +2519,7 @@ glob ~~~~ -+*glob* ?*-nocomplain*? 'pattern ?pattern \...?'+ ++*glob* ?*-nocomplain*? ?*-directory* 'dir'? ?*--*? 'pattern ?pattern \...?'+ This command performs filename globbing, using csh rules. The returned value from `glob` is the list of expanded filenames. @@ -2535,6 +2529,11 @@ list is empty. The +-nocomplain+ argument must be provided exactly: an abbreviation will not be accepted. +If +-directory+ is given, the +'dir'+ is understood to contain a +directory name to search in. This allows globbing inside directories +whose names may contain glob-sensitive characters. The returned names +are specified relative to this directory. + global ~~~~~~ @@ -3793,15 +3792,19 @@ Like `string range` except works on bytes rather than characters. These commands are identical if UTF-8 support is not enabled. -+*string compare ?-nocase?* 'string1 string2'+:: ++*string compare ?-nocase?* ?*-length* 'len? string1 string2'+:: Perform a character-by-character comparison of strings +'string1'+ and +'string2'+ in the same way as the C 'strcmp' procedure. Return -1, 0, or 1, depending on whether +'string1'+ is lexicographically - less than, equal to, or greater than +'string2'+. + less than, equal to, or greater than +'string2'+. If +-length+ + is specified, then only the first +'len'+ characters are used + in the comparison. If +'len'+ is negative, it is ignored. Performs a case-insensitive comparison if +-nocase+ is specified. -+*string equal ?-nocase?* 'string1 string2'+:: - Returns 1 if the strings are equal, or 0 otherwise. ++*string equal ?-nocase?* '?*-length* len?' 'string1 string2'+:: + Returns 1 if the strings are equal, or 0 otherwise. If +-length+ + is specified, then only the first +'len'+ characters are used + in the comparison. If +'len'+ is negative, it is ignored. Performs a case-insensitive comparison if +-nocase+ is specified. +*string first* 'string1 string2 ?firstIndex?'+:: @@ -4405,54 +4408,55 @@ aio ~~~ -+$handle *read ?-nonewline?* '?len?'+:: - Read and return bytes from the stream. To eof if no len. ++$handle *accept*+:: + Server socket only: Accept a connection and return stream -+$handle *gets* '?var?'+:: - Read one line and return it or store it in the var ++$handle *buffering none|line|full*+:: + Sets the buffering mode of the stream. -+$handle *puts ?-nonewline?* 'str'+:: - Write the string, with newline unless -nonewline ++$handle *close*+:: + Closes the stream +$handle *copyto* 'tofd ?size?'+:: Copy bytes to the file descriptor +'tofd'+. If +'size'+ is specified, at most that many bytes will be copied. Otherwise copying continues until the end of the input file. Returns the number of bytes actually copied. -+$handle *flush*+:: - Flush the stream ++$handle *eof*+:: + Returns 1 if stream is at eof +$handle *filename*+:: Returns the original filename associated with the handle. Handles returned by `socket` give the socket type instead of a filename. -+$handle *eof*+:: - Returns 1 if stream is at eof - -+$handle *close*+:: - Closes the stream - -+$handle *seek* 'offset' *?start|current|end?*+:: - Seeks in the stream (default 'current') ++$handle *flush*+:: + Flush the stream -+$handle *tell*+:: - Returns the current seek position ++$handle *gets* '?var?'+:: + Read one line and return it or store it in the var -+$handle *filename*+:: - Returns the original filename used when opening the file. - If the handle was returned from `socket`, the type of the - handle is returned instead. ++$handle *isatty*+:: + Returns 1 if the stream is a tty device. +$handle *ndelay ?0|1?*+:: Set O_NDELAY (if arg). Returns current/new setting. Note that in general ANSI I/O interacts badly with non-blocking I/O. Use with care. -+$handle *buffering none|line|full*+:: - Sets the buffering mode of the stream. ++$handle *puts ?-nonewline?* 'str'+:: + Write the string, with newline unless -nonewline -+$handle *accept*+:: - Server socket only: Accept a connection and return stream ++$handle *read ?-nonewline?* '?len?'+:: + Read and return bytes from the stream. To eof if no len. + ++$handle *recvfrom* 'maxlen ?addrvar?'+:: + Receives a message from the handle via recvfrom(2) and returns it. + At most +'maxlen'+ bytes are read. + If +'addrvar'+ is specified, the sending address of the message is stored in + the named variable in the form 'addr:port'. See `socket` for details. + ++$handle *seek* 'offset' *?start|current|end?*+:: + Seeks in the stream (default 'current') +$handle *sendto* 'str ?hostname:?port'+:: Sends the string, +'str'+, to the given address via the socket using sendto(2). @@ -4460,11 +4464,8 @@ ways for other handle types. Returns the number of bytes written. -+$handle *recvfrom* 'maxlen ?addrvar?'+:: - Receives a message from the handle via recvfrom(2) and returns it. - At most +'maxlen'+ bytes are read. - If +'addrvar'+ is specified, the sending address of the message is stored in - the named variable in the form 'addr:port'. See `socket` for details. ++$handle *tell*+:: + Returns the current seek position fconfigure ~~~~~~~~~~ @@ -4778,18 +4779,13 @@ exactly one element, the matched element is returned. If not, the result depends on the +-error+ option. - +-exact+:: - Accept only exact matches. - - +-message 'string'+:: - Use +'string'+ in the error message at a mismatch. Default is "option". - - +-error 'options'+:: - The options are used when no match is found. If +'options'+ is - empty, no error is generated and an empty string is returned. - Otherwise the options are used as return options when - generating the error message. The default corresponds to - setting +-level 0+. + * +*-exact*+ Accept only exact matches. + * +*-message* 'string'+ Use +'string'+ in the error message at a mismatch. Default is "option". + * +*-error* 'options'+ The options are used when no match is found. If +'options'+ is + empty, no error is generated and an empty string is returned. + Otherwise the options are used as return options when + generating the error message. The default corresponds to + setting +-level 0+. history ~~~~~~~ @@ -4837,7 +4833,7 @@ +*namespace origin* 'command'+:: Returns the fully-qualified name of the original command to which the imported command +'command'+ refers. -+*namespace parent* ?namespace?:: ++*namespace parent* ?namespace?+:: Returns the fully-qualified name of the parent namespace for namespace +'namespace'+, if given, otherwise for the current namespace. @@ -4931,6 +4927,20 @@ CHANGES IN PREVIOUS RELEASES ---------------------------- +=== In v0.70 === + +1. +platform_tcl()+ settings are now automatically determined +2. Add aio `$handle filename` +3. Add `info channels` +4. The 'bio' extension is gone. Now `aio` supports 'copyto'. +5. Add `exists` command +6. Add the pure-Tcl 'oo' extension +7. The `exec` command now only uses vfork(), not fork() +8. Unit test framework is less verbose and more Tcl-compatible +9. Optional UTF-8 support +10. Optional built-in regexp engine for better Tcl compatibility and UTF-8 support +11. Command line editing in interactive mode, e.g. 'jimsh' + === In v0.63 === 1. `source` now checks that a script is complete (.i.e. not missing a brace) diff -Nru jimtcl-0.73/linenoise.c jimtcl-0.74/linenoise.c --- jimtcl-0.73/linenoise.c 2011-12-19 22:11:37.000000000 +0000 +++ jimtcl-0.74/linenoise.c 2013-07-24 05:36:47.000000000 +0000 @@ -56,10 +56,6 @@ * flickering effect with some slow terminal, but the lesser sequences * the more compatible. * - * CHA (Cursor Horizontal Absolute) - * Sequence: ESC [ n G - * Effect: moves cursor to column n (1 based) - * * EL (Erase Line) * Sequence: ESC [ n K * Effect: if n is 0 or missing, clear from cursor to end of line @@ -70,6 +66,10 @@ * Sequence: ESC [ n C * Effect: moves cursor forward of n chars * + * CR (Carriage Return) + * Sequence: \r + * Effect: moves cursor to column 1 + * * The following are used to clear the screen: ESC [ H ESC [ 2 J * This is actually composed of two sequences: * @@ -102,18 +102,28 @@ * This support based in part on work by Jon Griffiths. */ -#ifdef __MINGW32__ +#ifdef _WIN32 /* Windows platform, either MinGW or Visual Studio (MSVC) */ #include #include #define USE_WINCONSOLE +#ifdef __MINGW32__ +#define HAVE_UNISTD_H +#else +/* Microsoft headers don't like old POSIX names */ +#define strdup _strdup +#define snprintf _snprintf +#endif #else #include #include #include #define USE_TERMIOS +#define HAVE_UNISTD_H #endif +#ifdef HAVE_UNISTD_H #include +#endif #include #include #include @@ -121,7 +131,6 @@ #include #include #include -#include #include "linenoise.h" @@ -146,6 +155,9 @@ SPECIAL_DELETE = -24, SPECIAL_HOME = -25, SPECIAL_END = -26, + SPECIAL_INSERT = -27, + SPECIAL_PAGE_UP = -28, + SPECIAL_PAGE_DOWN = -29 }; static int history_max_len = LINENOISE_DEFAULT_HISTORY_MAX_LEN; @@ -161,6 +173,7 @@ int pos; /* Cursor position, measured in chars */ int cols; /* Size of the window, in chars */ const char *prompt; + char *capture; /* Allocated capture buffer, or NULL for none. Always null terminated */ #if defined(USE_TERMIOS) int fd; /* Terminal fd */ #elif defined(USE_WINCONSOLE) @@ -183,6 +196,7 @@ free(history[j]); free(history); history = NULL; + history_len = 0; } } @@ -200,7 +214,7 @@ if (term) { int j; for (j = 0; unsupported_term[j]; j++) { - if (strcasecmp(term, unsupported_term[j]) == 0) { + if (strcmp(term, unsupported_term[j]) == 0) { return 1; } } @@ -264,7 +278,10 @@ linenoiseHistoryFree(); } -/* gcc/glibc insists that we care about the return code of write! */ +/* gcc/glibc insists that we care about the return code of write! + * Clarification: This means that a void-cast like "(void) (EXPR)" + * does not work. + */ #define IGNORE_RC(EXPR) if (EXPR) {} /* This is fdprintf() on some systems, but use a different @@ -289,7 +306,7 @@ static void cursorToLeft(struct current *current) { - fd_printf(current->fd, "\x1b[1G"); + fd_printf(current->fd, "\r"); } static int outputChars(struct current *current, const char *buf, int len) @@ -299,7 +316,7 @@ static void outputControlChar(struct current *current, char ch) { - fd_printf(current->fd, "\033[7m^%c\033[0m", ch); + fd_printf(current->fd, "\x1b[7m^%c\x1b[0m", ch); } static void eraseEol(struct current *current) @@ -309,7 +326,7 @@ static void setCursorPos(struct current *current, int x) { - fd_printf(current->fd, "\x1b[1G\x1b[%dC", x); + fd_printf(current->fd, "\r\x1b[%dC", x); } /** @@ -370,6 +387,70 @@ #endif } +static int countColorControlChars(const char* prompt, int plen) +{ + /* ANSI color control sequences have the form: + * "\x1b" "[" [0-9;]+ "m" + * We parse them with a simple state machine. + */ + + enum { + search_esc, + expect_bracket, + expect_inner, + expect_trail + } state = search_esc; + int len, found = 0; + char ch; + + /* XXX: Strictly we should be checking utf8 chars rather than + * bytes in case of the extremely unlikely scenario where + * an ANSI sequence is part of a utf8 sequence. + */ + for (; plen ; plen--, prompt++) { + ch = *prompt; + + switch (state) { + case search_esc: + len = 0; + if (ch == '\x1b') { + state = expect_bracket; + len++; + } + break; + case expect_bracket: + if (ch == '[') { + state = expect_inner; + len++; + } else { + state = search_esc; + } + break; + case expect_inner: + if (ch >= '0' && ch <= '9') { + len++; + state = expect_trail; + } else { + state = search_esc; + } + break; + case expect_trail: + if (ch == 'm') { + len++; + found += len; + state = search_esc; + } else if ((ch != ';') && ((ch < '0') || (ch > '9'))) { + state = search_esc; + } + /* 0-9, or semicolon */ + len++; + break; + } + } + + return found; +} + static int getWindowSize(struct current *current) { struct winsize ws; @@ -388,8 +469,8 @@ if (current->cols == 0) { current->cols = 80; - /* Move cursor far right and report cursor position */ - fd_printf(current->fd, "\x1b[999G" "\x1b[6n"); + /* Move cursor far right and report cursor position, then back to the left */ + fd_printf(current->fd, "\x1b[999C" "\x1b[6n"); /* Parse the response: ESC [ rows ; cols R */ if (fd_read_char(current->fd, 100) == 0x1b && fd_read_char(current->fd, 100) == '[') { @@ -463,8 +544,14 @@ c = fd_read_char(fd, 50); if (c == '~') { switch (c2) { + case '2': + return SPECIAL_INSERT; case '3': return SPECIAL_DELETE; + case '5': + return SPECIAL_PAGE_UP; + case '6': + return SPECIAL_PAGE_DOWN; case '7': return SPECIAL_HOME; case '8': @@ -522,7 +609,7 @@ static void cursorToLeft(struct current *current) { - COORD pos = { 0, current->y }; + COORD pos = { 0, (SHORT)current->y }; DWORD n; FillConsoleOutputAttribute(current->outh, @@ -532,15 +619,17 @@ static int outputChars(struct current *current, const char *buf, int len) { - COORD pos = { current->x, current->y }; - WriteConsoleOutputCharacter(current->outh, buf, len, pos, 0); + COORD pos = { (SHORT)current->x, (SHORT)current->y }; + DWORD n; + + WriteConsoleOutputCharacter(current->outh, buf, len, pos, &n); current->x += len; return 0; } static void outputControlChar(struct current *current, char ch) { - COORD pos = { current->x, current->y }; + COORD pos = { (SHORT)current->x, (SHORT)current->y }; DWORD n; FillConsoleOutputAttribute(current->outh, BACKGROUND_INTENSITY, 2, pos, &n); @@ -550,7 +639,7 @@ static void eraseEol(struct current *current) { - COORD pos = { current->x, current->y }; + COORD pos = { (SHORT)current->x, (SHORT)current->y }; DWORD n; FillConsoleOutputCharacter(current->outh, ' ', current->cols - current->x, pos, &n); @@ -558,7 +647,7 @@ static void setCursorPos(struct current *current, int x) { - COORD pos = { x, current->y }; + COORD pos = { (SHORT)x, (SHORT)current->y }; SetConsoleCursorPosition(current->outh, pos); current->x = x; @@ -587,12 +676,18 @@ return SPECIAL_UP; case VK_DOWN: return SPECIAL_DOWN; + case VK_INSERT: + return SPECIAL_INSERT; case VK_DELETE: return SPECIAL_DELETE; case VK_HOME: return SPECIAL_HOME; case VK_END: return SPECIAL_END; + case VK_PRIOR: + return SPECIAL_PAGE_UP; + case VK_NEXT: + return SPECIAL_PAGE_DOWN; } } /* Note that control characters are already translated in AsciiChar */ @@ -608,6 +703,14 @@ return -1; } +static int countColorControlChars(char* prompt, int plen) +{ + /* For windows we assume that there are no embedded ansi color + * control sequences. + */ + return 0; +} + static int getWindowSize(struct current *current) { CONSOLE_SCREEN_BUFFER_INFO info; @@ -670,6 +773,11 @@ plen = strlen(prompt); pchars = utf8_strlen(prompt, plen); + /* Scan the prompt for embedded ansi color control sequences and + * discount them as characters/columns. + */ + pchars -= countColorControlChars(prompt, plen); + /* Account for a line which is too long to fit in the window. * Note that control chars require an extra column */ @@ -686,7 +794,7 @@ } } - /* If too many are need, strip chars off the front of 'buf' + /* If too many are needed, strip chars off the front of 'buf' * until it fits. Note that if the current char is a control character, * we need one extra col. */ @@ -694,7 +802,7 @@ n++; } - while (n >= current->cols) { + while (n >= current->cols && pos > 0) { b = utf8_tounicode(buf, &ch); if (ch < ' ') { n--; @@ -837,16 +945,64 @@ } /** + * Captures up to 'n' characters starting at 'pos' for the cut buffer. + * + * This replaces any existing characters in the cut buffer. + */ +static void capture_chars(struct current *current, int pos, int n) +{ + if (pos >= 0 && (pos + n - 1) < current->chars) { + int p1 = utf8_index(current->buf, pos); + int nbytes = utf8_index(current->buf + p1, n); + + if (nbytes) { + free(current->capture); + /* Include space for the null terminator */ + current->capture = (char *)malloc(nbytes + 1); + memcpy(current->capture, current->buf + p1, nbytes); + current->capture[nbytes] = '\0'; + } + } +} + +/** + * Removes up to 'n' characters at cursor position 'pos'. + * * Returns 0 if no chars were removed or non-zero otherwise. */ static int remove_chars(struct current *current, int pos, int n) { int removed = 0; + + /* First save any chars which will be removed */ + capture_chars(current, pos, n); + while (n-- && remove_char(current, pos)) { removed++; } return removed; } +/** + * Inserts the characters (string) 'chars' at the cursor position 'pos'. + * + * Returns 0 if no chars were inserted or non-zero otherwise. + */ +static int insert_chars(struct current *current, int pos, const char *chars) +{ + int inserted = 0; + + while (*chars) { + int ch; + int n = utf8_tounicode(chars, &ch); + if (insert_char(current, pos, ch) == 0) { + break; + } + inserted++; + pos++; + chars += n; + } + return inserted; +} #ifndef NO_COMPLETION static linenoiseCompletionCallback *completionCallback = NULL; @@ -931,7 +1087,7 @@ #endif -static int linenoisePrompt(struct current *current) { +static int linenoiseEdit(struct current *current) { int history_index = 0; /* The latest history entry is always our current buffer, that @@ -949,7 +1105,7 @@ /* Only autocomplete when the callback is set. It returns < 0 when * there was an error reading from fd. Otherwise it will return the * character that should be handled next. */ - if (c == 9 && completionCallback != NULL) { + if (c == '\t' && current->pos == current->chars && completionCallback != NULL) { c = completeLine(current); /* Return on errors */ if (c < 0) return current->len; @@ -992,7 +1148,12 @@ refreshLine(current->prompt, current); } break; - case ctrl('W'): /* ctrl-w */ + case SPECIAL_INSERT: + /* Ignore. Expansion Hook. + * Future possibility: Toggle Insert/Overwrite Modes + */ + break; + case ctrl('W'): /* ctrl-w, delete word at left. save deleted chars */ /* eat any spaces on the left */ { int pos = current->pos; @@ -1112,9 +1273,11 @@ } break; case ctrl('T'): /* ctrl-t */ - if (current->pos > 0 && current->pos < current->chars) { - c = get_char(current, current->pos); - remove_char(current, current->pos); + if (current->pos > 0 && current->pos <= current->chars) { + /* If cursor is at end, transpose the previous two chars */ + int fixer = (current->pos == current->chars); + c = get_char(current, current->pos - fixer); + remove_char(current, current->pos - fixer); insert_char(current, current->pos - 1, c); refreshLine(current->prompt, current); } @@ -1151,26 +1314,34 @@ refreshLine(current->prompt, current); } break; + case SPECIAL_PAGE_UP: + dir = history_len - history_index - 1; /* move to start of history */ + goto history_navigation; + case SPECIAL_PAGE_DOWN: + dir = -history_index; /* move to 0 == end of history, i.e. current */ + goto history_navigation; case ctrl('P'): case SPECIAL_UP: dir = 1; + goto history_navigation; case ctrl('N'): case SPECIAL_DOWN: +history_navigation: if (history_len > 1) { /* Update the current history entry before to * overwrite it with tne next one. */ - free(history[history_len-1-history_index]); - history[history_len-1-history_index] = strdup(current->buf); + free(history[history_len - 1 - history_index]); + history[history_len - 1 - history_index] = strdup(current->buf); /* Show the new entry */ history_index += dir; if (history_index < 0) { history_index = 0; break; } else if (history_index >= history_len) { - history_index = history_len-1; + history_index = history_len - 1; break; } - set_current(current, history[history_len-1-history_index]); + set_current(current, history[history_len - 1 - history_index]); refreshLine(current->prompt, current); } break; @@ -1184,16 +1355,21 @@ current->pos = current->chars; refreshLine(current->prompt, current); break; - case ctrl('U'): /* Ctrl+u, delete to beginning of line. */ + case ctrl('U'): /* Ctrl+u, delete to beginning of line, save deleted chars. */ if (remove_chars(current, 0, current->pos)) { refreshLine(current->prompt, current); } break; - case ctrl('K'): /* Ctrl+k, delete from current to end of line. */ + case ctrl('K'): /* Ctrl+k, delete from current to end of line, save deleted chars. */ if (remove_chars(current, current->pos, current->chars - current->pos)) { refreshLine(current->prompt, current); } break; + case ctrl('Y'): /* Ctrl+y, insert saved chars at current position */ + if (current->capture && insert_chars(current, current->pos, current->capture)) { + refreshLine(current->prompt, current); + } + break; case ctrl('L'): /* Ctrl+L, clear screen */ clearScreen(current); /* Force recalc of window size for serial terminals */ @@ -1213,6 +1389,15 @@ return current->len; } +int linenoiseColumns(void) +{ + struct current current; + enableRawMode (¤t); + getWindowSize (¤t); + disableRawMode (¤t); + return current.cols; +} + char *linenoise(const char *prompt) { int count; @@ -1220,10 +1405,10 @@ char buf[LINENOISE_MAX_LINE]; if (enableRawMode(¤t) == -1) { - printf("%s", prompt); + printf("%s", prompt); fflush(stdout); if (fgets(buf, sizeof(buf), stdin) == NULL) { - return NULL; + return NULL; } count = strlen(buf); if (count && buf[count-1] == '\n') { @@ -1239,10 +1424,14 @@ current.chars = 0; current.pos = 0; current.prompt = prompt; + current.capture = NULL; + + count = linenoiseEdit(¤t); - count = linenoisePrompt(¤t); disableRawMode(¤t); printf("\n"); + + free(current.capture); if (count == -1) { return NULL; } @@ -1278,6 +1467,10 @@ return 1; } +int linenoiseHistoryGetMaxLen(void) { + return history_max_len; +} + int linenoiseHistorySetMaxLen(int len) { char **newHistory; @@ -1287,8 +1480,16 @@ newHistory = (char **)malloc(sizeof(char*)*len); if (newHistory == NULL) return 0; - if (len < tocopy) tocopy = len; - memcpy(newHistory,history+(history_max_len-tocopy), sizeof(char*)*tocopy); + + /* If we can't copy everything, free the elements we'll not use. */ + if (len < tocopy) { + int j; + + for (j = 0; j < tocopy-len; j++) free(history[j]); + tocopy = len; + } + memset(newHistory,0,sizeof(char*)*len); + memcpy(newHistory,history+(history_len-tocopy), sizeof(char*)*tocopy); free(history); history = newHistory; } diff -Nru jimtcl-0.73/linenoise.h jimtcl-0.74/linenoise.h --- jimtcl-0.73/linenoise.h 2011-12-19 22:11:37.000000000 +0000 +++ jimtcl-0.74/linenoise.h 2013-07-24 05:36:47.000000000 +0000 @@ -54,9 +54,11 @@ char *linenoise(const char *prompt); int linenoiseHistoryAdd(const char *line); int linenoiseHistorySetMaxLen(int len); +int linenoiseHistoryGetMaxLen(void); int linenoiseHistorySave(const char *filename); int linenoiseHistoryLoad(const char *filename); void linenoiseHistoryFree(void); char **linenoiseHistory(int *len); +int linenoiseColumns(void); #endif /* __LINENOISE_H */ diff -Nru jimtcl-0.73/make-bootstrap-jim jimtcl-0.74/make-bootstrap-jim --- jimtcl-0.73/make-bootstrap-jim 2011-12-19 22:11:37.000000000 +0000 +++ jimtcl-0.74/make-bootstrap-jim 2013-07-24 05:36:47.000000000 +0000 @@ -80,6 +80,7 @@ #define TCL_PLATFORM_PATH_SEPARATOR ":" #define HAVE_VFORK #define HAVE_WAITPID +#define HAVE_ISATTY #define HAVE_SYS_TIME_H #define HAVE_DIRENT_H #define HAVE_UNISTD_H diff -Nru jimtcl-0.73/Makefile.in jimtcl-0.74/Makefile.in --- jimtcl-0.73/Makefile.in 2011-12-19 22:11:37.000000000 +0000 +++ jimtcl-0.74/Makefile.in 2013-07-24 05:36:47.000000000 +0000 @@ -8,7 +8,7 @@ # Configuration SH_CFLAGS ?= @SH_CFLAGS@ -SH_LDFLAGS ?= @SH_LDFLAGS@ +SH_LDFLAGS ?= @SH_LDFLAGS@ @SH_SOPREFIX@libjim.@LIBSOEXT@.0.74 SHOBJ_CFLAGS ?= @SHOBJ_CFLAGS@ @if JIM_STATICLIB SHOBJ_LDFLAGS ?= @SHOBJ_LDFLAGS@ @@ -33,7 +33,7 @@ @if JIM_STATICLIB LIBJIM := libjim.a @else -LIBJIM := libjim.@LIBSOEXT@ +LIBJIM := libjim.@LIBSOEXT@.0.74 SH_LIBJIM := $(LIBJIM) CC += $(SH_CFLAGS) CXX += $(SH_CFLAGS) @@ -51,45 +51,51 @@ JIMSH := jimsh@EXEEXT@ -all: $(JIMSH) @C_EXT_SHOBJS@ build-jim-ext +all: $(JIMSH) @C_EXT_SHOBJS@ # Create C extensions from pure Tcl extensions .SUFFIXES: .tcl .tcl.o: - @tclsh@ @srcdir@/make-c-ext.tcl $< >_$*.c || ( rm _$*.c; exit 1) - $(CC) $(CFLAGS) -c -o $@ _$*.c || ( rm _$*.c; exit 1) - @rm -f _$*.c + @tclsh@ @srcdir@/make-c-ext.tcl $< >_$*.c + $(CC) $(CFLAGS) -c -o $@ _$*.c docs: Tcl.html +@if JIM_DOCS +install-docs: docs + mkdir -p $(DESTDIR)$(prefix)/doc/jim + cp Tcl.html $(DESTDIR)$(prefix)/doc/jim +@else +install-docs: +@endif + $(JIMSH): $(LIBJIM) jimsh.o initjimsh.o $(JIMSH_CC) @SH_LINKFLAGS@ $(LDFLAGS) -o $@ jimsh.o initjimsh.o $(LIBJIM) $(LDLIBS) @if JIM_INSTALL -install: all docs @TCL_EXTS@ install-exec - mkdir -p $(DESTDIR)$(prefix)/lib/jim - cp $(LIBJIM) $(DESTDIR)$(prefix)/lib - cp @srcdir@/README.extensions @C_EXT_SHOBJS@ @TCL_EXTS@ $(DESTDIR)$(prefix)/lib/jim - mkdir -p $(DESTDIR)$(prefix)/include +install: all @TCL_EXTS@ install-exec install-docs + mkdir -p $(DESTDIR)@libdir@/jim + cp $(LIBJIM) $(DESTDIR)@libdir@ + cp @srcdir@/README.extensions @C_EXT_SHOBJS@ $(DESTDIR)@libdir@/jim + for i in @TCL_EXTS@; do cp @srcdir@/$$i $(DESTDIR)@libdir@/jim; done + mkdir -p $(DESTDIR)@includedir@ cp @srcdir@/jim.h @srcdir@/jim-eventloop.h @srcdir@/jim-signal.h \ - @srcdir@/jim-subcmd.h @srcdir@/jim-win32compat.h $(DESTDIR)$(prefix)/include - cp jim-config.h $(DESTDIR)$(prefix)/include - mkdir -p $(DESTDIR)$(prefix)/doc/jim - cp Tcl.html $(DESTDIR)$(prefix)/doc/jim - mkdir -p $(DESTDIR)$(prefix)/bin - cp build-jim-ext $(DESTDIR)$(prefix)/bin + @srcdir@/jim-subcmd.h @srcdir@/jim-win32compat.h $(DESTDIR)@includedir@ + cp jim-config.h $(DESTDIR)@includedir@ + mkdir -p $(DESTDIR)@bindir@ + cp build-jim-ext $(DESTDIR)@bindir@ install-exec: all - mkdir -p $(DESTDIR)$(prefix)/bin - cp $(JIMSH) $(DESTDIR)$(prefix)/bin + mkdir -p $(DESTDIR)@bindir@ + cp $(JIMSH) $(DESTDIR)@bindir@ uninstall: - rm -f $(DESTDIR)$(prefix)/bin/$(JIMSH) - rm -f $(DESTDIR)$(prefix)/bin/build-jim-ext - rm -f $(DESTDIR)$(prefix)/lib/$(LIBJIM) - for i in README.extensions @C_EXT_SHOBJS@ @TCL_EXTS@; do rm -f $(DESTDIR)$(prefix)/lib/jim/$$i; done - rm -f $(DESTDIR)$(prefix)/include/jim*.h - rm -f $(DESTDIR)$(prefix)/doc/jim/Tcl.html + rm -f $(DESTDIR)@bindir@/$(JIMSH) + rm -f $(DESTDIR)@bindir@/build-jim-ext + rm -f $(DESTDIR)@libdir@/$(LIBJIM) + for i in README.extensions @C_EXT_SHOBJS@ @TCL_EXTS@; do rm -f $(DESTDIR)@libdir@/jim/$$i; done + rm -f $(DESTDIR)@includedir@/jim*.h + rm -f $(DESTDIR)@datadir@/doc/jim/Tcl.html @else install install-exec: all uninstall: @@ -98,7 +104,7 @@ test: $(JIMSH) cd @srcdir@/tests; $(DEF_LD_PATH) $(MAKE) jimsh=@builddir@/jimsh -$(OBJS): Makefile +$(OBJS): Makefile $(wildcard *.h) @if JIM_UTF8 # Generate the unicode case mapping @@ -181,10 +187,10 @@ @tclsh@ @srcdir@/make-index $> $^ | asciidoc -o $@ -d manpage - || cp @srcdir@/Tcl_shipped.html Tcl.html clean: - rm -f *.o *.so *.dll *.exe lib*.a $(JIMSH) Tcl.html _*.c build-jim-ext + rm -f *.o *.so *.dll *.exe lib*.a $(JIMSH) Tcl.html _*.c distclean: clean - rm -f jimautoconf.h jim-config.h Makefile config.log autosetup/jimsh0@EXEEXT@ + rm -f jimautoconf.h jim-config.h Makefile config.log autosetup/jimsh0@EXEEXT@ build-jim-ext ship: Tcl.html cp $< Tcl_shipped.html diff -Nru jimtcl-0.73/make-index jimtcl-0.74/make-index --- jimtcl-0.73/make-index 2011-12-19 22:11:37.000000000 +0000 +++ jimtcl-0.74/make-index 2013-07-24 05:36:47.000000000 +0000 @@ -68,5 +68,9 @@ # Output the result foreach line $lines { - puts [string map $mapping $line] + if {[string first ` $line] >= 0 || [string first @ $line] >= 0} { + puts [string map $mapping $line] + } else { + puts $line + } } diff -Nru jimtcl-0.73/regtest.tcl jimtcl-0.74/regtest.tcl --- jimtcl-0.73/regtest.tcl 2011-12-19 22:11:37.000000000 +0000 +++ jimtcl-0.74/regtest.tcl 2013-07-24 05:36:47.000000000 +0000 @@ -204,6 +204,12 @@ } puts "TEST 28 PASSED" +# REGTEST 29 +# Reference counting problem at exit +set x [lindex {} 0] +info source $x +eval $x + # TAKE THE FOLLOWING puts AS LAST LINE puts "--- ALL TESTS PASSED ---" diff -Nru jimtcl-0.73/tclcompat.tcl jimtcl-0.74/tclcompat.tcl --- jimtcl-0.73/tclcompat.tcl 2011-12-19 22:11:37.000000000 +0000 +++ jimtcl-0.74/tclcompat.tcl 2013-07-24 05:36:47.000000000 +0000 @@ -40,7 +40,7 @@ foreach {n v} $args { switch -glob -- $n { -bl* { - $f ndelay $v + $f ndelay $(!$v) } -bu* { $f buffering $v diff -Nru jimtcl-0.73/Tcl_shipped.html jimtcl-0.74/Tcl_shipped.html --- jimtcl-0.73/Tcl_shipped.html 2011-12-19 22:11:37.000000000 +0000 +++ jimtcl-0.74/Tcl_shipped.html 2013-07-24 05:36:47.000000000 +0000 @@ -3,7 +3,7 @@ - + Jim Tcl(n)