Fossil SCM

Merged in autosetupAndJimTcl branch (autosetup updates).

stephan 2019-07-31 08:09 trunk merge
Commit 51d006f851c538db609fbe113f248b81d43bdb682f8763d280e82909b3e1707c
--- autosetup/README.autosetup
+++ autosetup/README.autosetup
@@ -1,1 +1,11 @@
1
-This is autosetup v0.6.6. See http://msteveb.github.com/autosetup/
1
+README.autosetup created by autosetup v0.6.9
2
+
3
+This is the autosetup directory for a local install of autosetup.
4
+It contains autosetup, support files and loadable modules.
5
+
6
+*.tcl files in this directory are optional modules which
7
+can be loaded with the 'use' directive.
8
+
9
+*.auto files in this directory are auto-loaded.
10
+
11
+For more information, see http://msteveb.github.com/autosetup/
212
--- autosetup/README.autosetup
+++ autosetup/README.autosetup
@@ -1,1 +1,11 @@
1 This is autosetup v0.6.6. See http://msteveb.github.com/autosetup/
 
 
 
 
 
 
 
 
 
 
2
--- autosetup/README.autosetup
+++ autosetup/README.autosetup
@@ -1,1 +1,11 @@
1 README.autosetup created by autosetup v0.6.9
2
3 This is the autosetup directory for a local install of autosetup.
4 It contains autosetup, support files and loadable modules.
5
6 *.tcl files in this directory are optional modules which
7 can be loaded with the 'use' directive.
8
9 *.auto files in this directory are auto-loaded.
10
11 For more information, see http://msteveb.github.com/autosetup/
12
+709 -235
--- autosetup/autosetup
+++ autosetup/autosetup
@@ -1,16 +1,17 @@
11
#!/bin/sh
22
# Copyright (c) 2006-2011 WorkWare Systems http://www.workware.net.au/
33
# All rights reserved
44
# vim:se syntax=tcl:
55
# \
6
-dir=`dirname "$0"`; exec "`$dir/find-tclsh`" "$0" "$@"
6
+dir=`dirname "$0"`; exec "`$dir/autosetup-find-tclsh`" "$0" "$@"
77
8
-set autosetup(version) 0.6.6
8
+# Note that the version has a trailing + on unreleased versions
9
+set autosetup(version) 0.6.9
910
1011
# Can be set to 1 to debug early-init problems
11
-set autosetup(debug) 0
12
+set autosetup(debug) [expr {"--debug" in $argv}]
1213
1314
##################################################################
1415
#
1516
# Main flow of control, option handling
1617
#
@@ -72,14 +73,18 @@
7273
set autosetup(cmdline) {}
7374
# options is a list of known options
7475
set autosetup(options) {}
7576
# optset is a dictionary of option values set by the user based on getopt
7677
set autosetup(optset) {}
77
- # optdefault is a dictionary of default values for options
78
+ # optdefault is a dictionary of default values
7879
set autosetup(optdefault) {}
80
+ # options-defaults is a dictionary of overrides for default values for options
81
+ set autosetup(options-defaults) {}
7982
set autosetup(optionhelp) {}
8083
set autosetup(showhelp) 0
84
+
85
+ use util
8186
8287
# Parse options
8388
use getopt
8489
8590
# At the is point we don't know what is a valid option
@@ -87,15 +92,28 @@
8792
set autosetup(getopt) [getopt argv]
8893
8994
#"=Core Options:"
9095
options-add {
9196
help:=local => "display help and options. Optionally specify a module name, such as --help=system"
97
+ licence license => "display the autosetup license"
9298
version => "display the version of autosetup"
9399
ref:=text manual:=text
94100
reference:=text => "display the autosetup command reference. 'text', 'wiki', 'asciidoc' or 'markdown'"
95101
debug => "display debugging output as autosetup runs"
96
- install:=. => "install autosetup to the current or given directory (in the 'autosetup/' subdirectory)"
102
+ install:=. => "install autosetup to the current or given directory"
103
+ }
104
+ if {$autosetup(installed)} {
105
+ # hidden options so we can produce a nice error
106
+ options-add {
107
+ sysinstall:path
108
+ }
109
+ } else {
110
+ options-add {
111
+ sysinstall:path => "install standalone autosetup to the given directory (e.g.: /usr/local)"
112
+ }
113
+ }
114
+ options-add {
97115
force init:=help => "create initial auto.def, etc. Use --init=help for known types"
98116
# Undocumented options
99117
option-checking=1
100118
nopager
101119
quiet
@@ -107,12 +125,12 @@
107125
puts $autosetup(version)
108126
exit 0
109127
}
110128
111129
# autosetup --conf=alternate-auto.def
112
- if {[opt-val conf] ne ""} {
113
- set autosetup(autodef) [opt-val conf]
130
+ if {[opt-str conf o]} {
131
+ set autosetup(autodef) $o
114132
}
115133
116134
# Debugging output (set this early)
117135
incr autosetup(debug) [opt-bool debug]
118136
incr autosetup(force) [opt-bool force]
@@ -124,41 +142,50 @@
124142
if {[file exists $autosetup(libdir)/local.tcl]} {
125143
use local
126144
}
127145
128146
# Now any auto-load modules
129
- foreach file [glob -nocomplain $autosetup(libdir)/*.auto $autosetup(libdir)/*/*.auto] {
130
- automf_load source $file
131
- }
147
+ autosetup_load_auto_modules
132148
133
- if {[opt-val help] ne ""} {
149
+ if {[opt-str help o]} {
134150
incr autosetup(showhelp)
135151
use help
136
- autosetup_help [opt-val help]
152
+ autosetup_help $o
137153
}
138154
139
- if {[opt-val {manual ref reference}] ne ""} {
155
+ if {[opt-bool licence license]} {
156
+ use help
157
+ autosetup_show_license
158
+ exit 0
159
+ }
160
+
161
+ if {[opt-str {manual ref reference} o]} {
140162
use help
141
- autosetup_reference [opt-val {manual ref reference}]
163
+ autosetup_reference $o
142164
}
143165
144166
# Allow combining --install and --init
145167
set earlyexit 0
146
- if {[opt-val install] ne ""} {
168
+ if {[opt-str install o]} {
147169
use install
148
- autosetup_install [opt-val install]
170
+ autosetup_install $o
149171
incr earlyexit
150172
}
151173
152
- if {[opt-val init] ne ""} {
174
+ if {[opt-str init o]} {
153175
use init
154
- autosetup_init [opt-val init]
176
+ autosetup_init $o
155177
incr earlyexit
156178
}
157179
158180
if {$earlyexit} {
159181
exit 0
182
+ }
183
+ if {[opt-str sysinstall o]} {
184
+ use install
185
+ autosetup_install $o 1
186
+ exit 0
160187
}
161188
162189
if {![file exists $autosetup(autodef)]} {
163190
# Check for invalid option first
164191
options {}
@@ -185,10 +212,11 @@
185212
define-append AUTOREMAKE [get-define CONFIGURE_OPTS]
186213
187214
188215
# Log how we were invoked
189216
configlog "Invoked as: [getenv WRAPPER $::argv0] [quote-argv $autosetup(argv)]"
217
+ configlog "Tclsh: [info nameofexecutable]"
190218
191219
# Note that auto.def is *not* loaded in the global scope
192220
source $autosetup(autodef)
193221
194222
# Could warn here if options {} was not specified
@@ -210,14 +238,14 @@
210238
#
211239
# Check each of the named, boolean options and if any have been explicitly enabled
212240
# or disabled by the user, return 1 or 0 accordingly.
213241
#
214242
# If the option was specified more than once, the last value wins.
215
-# e.g. With --enable-foo --disable-foo, [opt-bool foo] will return 0
243
+# e.g. With '--enable-foo --disable-foo', '[opt-bool foo]' will return 0
216244
#
217245
# If no value was specified by the user, returns the default value for the
218
-# first option. If -nodefault is given, this behaviour changes and
246
+# first option. If '-nodefault' is given, this behaviour changes and
219247
# -1 is returned instead.
220248
#
221249
proc opt-bool {args} {
222250
set nodefault 0
223251
if {[lindex $args 0] eq "-nodefault"} {
@@ -237,20 +265,19 @@
237265
}
238266
# Default value is the default for the first option
239267
return [dict get $::autosetup(optdefault) [lindex $args 0]]
240268
}
241269
242
-# @opt-val option-list ?default=""?
270
+# @opt-val optionlist ?default=""?
243271
#
244
-# Returns a list containing all the values given for the non-boolean options in 'option-list'.
272
+# Returns a list containing all the values given for the non-boolean options in '$optionlist'.
245273
# There will be one entry in the list for each option given by the user, including if the
246274
# same option was used multiple times.
247
-# If only a single value is required, use something like:
248275
#
249
-## lindex [opt-val $names] end
276
+# If no options were set, '$default' is returned (exactly, not as a list).
250277
#
251
-# If no options were set, $default is returned (exactly, not as a list).
278
+# Note: For most use cases, 'opt-str' should be preferred.
252279
#
253280
proc opt-val {names {default ""}} {
254281
option-check-names {*}$names
255282
256283
foreach opt $names {
@@ -261,10 +288,83 @@
261288
if {[info exists result]} {
262289
return $result
263290
}
264291
return $default
265292
}
293
+
294
+# @opt-str optionlist varname ?default?
295
+#
296
+# Sets '$varname' in the callers scope to the value for one of the given options.
297
+#
298
+# For the list of options given in '$optionlist', if any value is set for any option,
299
+# the option value is taken to be the *last* value of the last option (in the order given).
300
+#
301
+# If no option was given, and a default was specified with 'options-defaults',
302
+# that value is used.
303
+#
304
+# If no 'options-defaults' value was given and '$default' was given, it is used.
305
+#
306
+# If none of the above provided a value, no value is set.
307
+#
308
+# The return value depends on whether '$default' was specified.
309
+# If it was, the option value is returned.
310
+# If it was not, 1 is returns if a value was set, or 0 if not.
311
+#
312
+# Typical usage is as follows:
313
+#
314
+## if {[opt-str {myopt altname} o]} {
315
+## do something with $o
316
+## }
317
+#
318
+# Or:
319
+## define myname [opt-str {myopt altname} o "/usr/local"]
320
+#
321
+proc opt-str {names varname args} {
322
+ global autosetup
323
+
324
+ option-check-names {*}$names
325
+ upvar $varname value
326
+
327
+ if {[llength $args]} {
328
+ # A default was given, so always return the string value of the option
329
+ set default [lindex $args 0]
330
+ set retopt 1
331
+ } else {
332
+ # No default, so return 0 or 1 to indicate if a value was found
333
+ set retopt 0
334
+ }
335
+
336
+ foreach opt $names {
337
+ if {[dict exists $::autosetup(optset) $opt]} {
338
+ set result [lindex [dict get $::autosetup(optset) $opt] end]
339
+ }
340
+ }
341
+
342
+ if {![info exists result]} {
343
+ # No user-specified value. Has options-defaults been set?
344
+ foreach opt $names {
345
+ if {[dict exists $::autosetup(options-defaults) $opt]} {
346
+ set result [dict get $autosetup(options-defaults) $opt]
347
+ }
348
+ }
349
+ }
350
+
351
+ if {[info exists result]} {
352
+ set value $result
353
+ if {$retopt} {
354
+ return $value
355
+ }
356
+ return 1
357
+ }
358
+
359
+ if {$retopt} {
360
+ set value $default
361
+ return $value
362
+ }
363
+
364
+ return 0
365
+}
266366
267367
proc option-check-names {args} {
268368
foreach o $args {
269369
if {$o ni $::autosetup(options)} {
270370
autosetup-error "Request for undeclared option --$o"
@@ -293,10 +393,11 @@
293393
# This is a special heading
294394
lappend autosetup(optionhelp) $opt ""
295395
set header {}
296396
continue
297397
}
398
+ unset -nocomplain defaultvalue equal value
298399
299400
#puts "i=$i, opt=$opt"
300401
regexp {^([^:=]*)(:)?(=)?(.*)$} $opt -> name colon equal value
301402
if {$name in $autosetup(options)} {
302403
autosetup-error "Option $name already specified"
@@ -310,10 +411,16 @@
310411
# This is a documentation-only option, like "-C <dir>"
311412
set opthelp $opt
312413
} elseif {$colon eq ""} {
313414
# Boolean option
314415
lappend autosetup(options) $name
416
+
417
+ # Check for override
418
+ if {[dict exists $autosetup(options-defaults) $name]} {
419
+ # A default was specified with options-defaults, so use it
420
+ set value [dict get $autosetup(options-defaults) $name]
421
+ }
315422
316423
if {$value eq "1"} {
317424
set opthelp "--disable-$name"
318425
} else {
319426
set opthelp "--$name"
@@ -321,11 +428,12 @@
321428
322429
# Set the default
323430
if {$value eq ""} {
324431
set value 0
325432
}
326
- dict set autosetup(optdefault) $name $value
433
+ set defaultvalue $value
434
+ dict set autosetup(optdefault) $name $defaultvalue
327435
328436
if {[dict exists $autosetup(getopt) $name]} {
329437
# The option was specified by the user. Look at the last value.
330438
lassign [lindex [dict get $autosetup(getopt) $name] end] type setvalue
331439
if {$type eq "str"} {
@@ -342,19 +450,39 @@
342450
#puts "Found boolean option --$name=$setvalue"
343451
}
344452
} else {
345453
# String option.
346454
lappend autosetup(options) $name
455
+
456
+ if {$colon eq ":"} {
457
+ # Was ":name=default" given?
458
+ # If so, set $value to the display name and $defaultvalue to the default
459
+ # (This is the preferred way to set a default value for a string option)
460
+ if {[regexp {^([^=]+)=(.*)$} $value -> value defaultvalue]} {
461
+ dict set autosetup(optdefault) $name $defaultvalue
462
+ }
463
+ }
464
+
465
+ # Maybe override the default value
466
+ if {[dict exists $autosetup(options-defaults) $name]} {
467
+ # A default was specified with options-defaults, so use it
468
+ set defaultvalue [dict get $autosetup(options-defaults) $name]
469
+ dict set autosetup(optdefault) $name $defaultvalue
470
+ } elseif {![info exists defaultvalue]} {
471
+ # For backward compatibility, if ":name" was given, use name as both
472
+ # the display text and the default value, but only if the user
473
+ # specified the option without the value
474
+ set defaultvalue $value
475
+ }
347476
348477
if {$equal eq "="} {
349478
# String option with optional value
350479
set opthelp "--$name?=$value?"
351480
} else {
352481
# String option with required value
353482
set opthelp "--$name=$value"
354483
}
355
- dict set autosetup(optdefault) $name $value
356484
357485
# Get the values specified by the user
358486
if {[dict exists $autosetup(getopt) $name]} {
359487
set listvalue {}
360488
@@ -363,11 +491,11 @@
363491
if {$type eq "bool" && $setvalue} {
364492
if {$equal ne "="} {
365493
user-error "Option --$name requires a value"
366494
}
367495
# If given as a boolean, use the default value
368
- set setvalue $value
496
+ set setvalue $defaultvalue
369497
}
370498
lappend listvalue $setvalue
371499
}
372500
373501
#puts "Found string option --$name=$listvalue"
@@ -376,10 +504,13 @@
376504
}
377505
378506
# Now create the help for this option if appropriate
379507
if {[lindex $opts $i+1] eq "=>"} {
380508
set desc [lindex $opts $i+2]
509
+ if {[info exists defaultvalue]} {
510
+ set desc [string map [list @default@ $defaultvalue] $desc]
511
+ }
381512
#string match \n* $desc
382513
if {$header ne ""} {
383514
lappend autosetup(optionhelp) $header ""
384515
set header ""
385516
}
@@ -463,35 +594,39 @@
463594
options-wrap-desc [string trim $desc] $cols " " $indent [expr $max + 2]
464595
}
465596
}
466597
}
467598
468
-# @options options-spec
599
+# @options optionspec
469600
#
470601
# Specifies configuration-time options which may be selected by the user
471
-# and checked with opt-val and opt-bool. The format of options-spec follows.
602
+# and checked with 'opt-str' and 'opt-bool'. '$optionspec' contains a series
603
+# of options specifications separated by newlines, as follows:
472604
#
473605
# A boolean option is of the form:
474606
#
475607
## name[=0|1] => "Description of this boolean option"
476608
#
477
-# The default is name=0, meaning that the option is disabled by default.
478
-# If name=1 is used to make the option enabled by default, the description should reflect
609
+# The default is 'name=0', meaning that the option is disabled by default.
610
+# If 'name=1' is used to make the option enabled by default, the description should reflect
479611
# that with text like "Disable support for ...".
480612
#
481613
# An argument option (one which takes a parameter) is of the form:
482614
#
483615
## name:[=]value => "Description of this option"
484616
#
485
-# If the name:value form is used, the value must be provided with the option (as --name=myvalue).
486
-# If the name:=value form is used, the value is optional and the given value is used as the default
617
+# If the 'name:value' form is used, the value must be provided with the option (as '--name=myvalue').
618
+# If the 'name:=value' form is used, the value is optional and the given value is used as the default
487619
# if it is not provided.
488620
#
489
-# Undocumented options are also supported by omitting the "=> description.
490
-# These options are not displayed with --help and can be useful for internal options or as aliases.
621
+# The description may contain '@default@', in which case it will be replaced with the default
622
+# value for the option (taking into account defaults specified with 'options-defaults'.
491623
#
492
-# For example, --disable-lfs is an alias for --disable=largefile:
624
+# Undocumented options are also supported by omitting the '=> description'.
625
+# These options are not displayed with '--help' and can be useful for internal options or as aliases.
626
+#
627
+# For example, '--disable-lfs' is an alias for '--disable=largefile':
493628
#
494629
## lfs=1 largefile=1 => "Disable large file support"
495630
#
496631
proc options {optlist} {
497632
# Allow options as a list or args
@@ -509,27 +644,37 @@
509644
user-error "Unknown option --$o"
510645
}
511646
}
512647
}
513648
}
649
+
650
+# @options-defaults dictionary
651
+#
652
+# Specifies a dictionary of options and a new default value for each of those options.
653
+# Use before any 'use' statements in 'auto.def' to change the defaults for
654
+# subsequently included modules.
655
+proc options-defaults {dict} {
656
+ foreach {n v} $dict {
657
+ dict set ::autosetup(options-defaults) $n $v
658
+ }
659
+}
514660
515661
proc config_guess {} {
516
- if {[file-isexec $::autosetup(dir)/config.guess]} {
517
- exec-with-stderr sh $::autosetup(dir)/config.guess
518
- if {[catch {exec-with-stderr sh $::autosetup(dir)/config.guess} alias]} {
662
+ if {[file-isexec $::autosetup(dir)/autosetup-config.guess]} {
663
+ if {[catch {exec-with-stderr sh $::autosetup(dir)/autosetup-config.guess} alias]} {
519664
user-error $alias
520665
}
521666
return $alias
522667
} else {
523
- configlog "No config.guess, so using uname"
668
+ configlog "No autosetup-config.guess, so using uname"
524669
string tolower [exec uname -p]-unknown-[exec uname -s][exec uname -r]
525670
}
526671
}
527672
528673
proc config_sub {alias} {
529
- if {[file-isexec $::autosetup(dir)/config.sub]} {
530
- if {[catch {exec-with-stderr sh $::autosetup(dir)/config.sub $alias} alias]} {
674
+ if {[file-isexec $::autosetup(dir)/autosetup-config.sub]} {
675
+ if {[catch {exec-with-stderr sh $::autosetup(dir)/autosetup-config.sub $alias} alias]} {
531676
user-error $alias
532677
}
533678
}
534679
return $alias
535680
}
@@ -536,39 +681,48 @@
536681
537682
# @define name ?value=1?
538683
#
539684
# Defines the named variable to the given value.
540685
# These (name, value) pairs represent the results of the configuration check
541
-# and are available to be checked, modified and substituted.
686
+# and are available to be subsequently checked, modified and substituted.
542687
#
543688
proc define {name {value 1}} {
544689
set ::define($name) $value
545690
#dputs "$name <= $value"
546691
}
547692
548693
# @undefine name
549694
#
550
-# Undefine the named variable
695
+# Undefine the named variable.
551696
#
552697
proc undefine {name} {
553698
unset -nocomplain ::define($name)
554699
#dputs "$name <= <undef>"
555700
}
556701
557702
# @define-append name value ...
558703
#
559
-# Appends the given value(s) to the given 'defined' variable.
560
-# If the variable is not defined or empty, it is set to $value.
704
+# Appends the given value(s) to the given "defined" variable.
705
+# If the variable is not defined or empty, it is set to '$value'.
561706
# Otherwise the value is appended, separated by a space.
562707
# Any extra values are similarly appended.
563708
# If any value is already contained in the variable (as a substring) it is omitted.
564709
#
565710
proc define-append {name args} {
566711
if {[get-define $name ""] ne ""} {
567
- # Make a token attempt to avoid duplicates
712
+ # Avoid duplicates
568713
foreach arg $args {
569
- if {[string first $arg $::define($name)] == -1} {
714
+ if {$arg eq ""} {
715
+ continue
716
+ }
717
+ set found 0
718
+ foreach str [split $::define($name) " "] {
719
+ if {$str eq $arg} {
720
+ incr found
721
+ }
722
+ }
723
+ if {!$found} {
570724
append ::define($name) " " $arg
571725
}
572726
}
573727
} else {
574728
set ::define($name) [join $args]
@@ -576,11 +730,11 @@
576730
#dputs "$name += [join $args] => $::define($name)"
577731
}
578732
579733
# @get-define name ?default=0?
580734
#
581
-# Returns the current value of the 'defined' variable, or $default
735
+# Returns the current value of the "defined" variable, or '$default'
582736
# if not set.
583737
#
584738
proc get-define {name {default 0}} {
585739
if {[info exists ::define($name)]} {
586740
#dputs "$name => $::define($name)"
@@ -595,14 +749,26 @@
595749
# Returns 1 if the given variable is defined.
596750
#
597751
proc is-defined {name} {
598752
info exists ::define($name)
599753
}
754
+
755
+# @is-define-set name
756
+#
757
+# Returns 1 if the given variable is defined and is set
758
+# to a value other than "" or 0
759
+#
760
+proc is-define-set {name} {
761
+ if {[get-define $name] in {0 ""}} {
762
+ return 0
763
+ }
764
+ return 1
765
+}
600766
601767
# @all-defines
602768
#
603
-# Returns a dictionary (name value list) of all defined variables.
769
+# Returns a dictionary (name, value list) of all defined variables.
604770
#
605771
# This is suitable for use with 'dict', 'array set' or 'foreach'
606772
# and allows for arbitrary processing of the defined variables.
607773
#
608774
proc all-defines {} {
@@ -610,13 +776,13 @@
610776
}
611777
612778
613779
# @get-env name default
614780
#
615
-# If $name was specified on the command line, return it.
616
-# If $name was set in the environment, return it.
617
-# Otherwise return $default.
781
+# If '$name' was specified on the command line, return it.
782
+# Otherwise if '$name' was set in the environment, return it.
783
+# Otherwise return '$default'.
618784
#
619785
proc get-env {name default} {
620786
if {[dict exists $::autosetup(cmdline) $name]} {
621787
return [dict get $::autosetup(cmdline) $name]
622788
}
@@ -623,11 +789,11 @@
623789
getenv $name $default
624790
}
625791
626792
# @env-is-set name
627793
#
628
-# Returns 1 if the $name was specified on the command line or in the environment.
794
+# Returns 1 if '$name' was specified on the command line or in the environment.
629795
# Note that an empty environment variable is not considered to be set.
630796
#
631797
proc env-is-set {name} {
632798
if {[dict exists $::autosetup(cmdline) $name]} {
633799
return 1
@@ -639,11 +805,11 @@
639805
}
640806
641807
# @readfile filename ?default=""?
642808
#
643809
# Return the contents of the file, without the trailing newline.
644
-# If the file doesn't exist or can't be read, returns $default.
810
+# If the file doesn't exist or can't be read, returns '$default'.
645811
#
646812
proc readfile {filename {default_value ""}} {
647813
set result $default_value
648814
catch {
649815
set f [open $filename]
@@ -653,11 +819,11 @@
653819
return $result
654820
}
655821
656822
# @writefile filename value
657823
#
658
-# Creates the given file containing $value.
824
+# Creates the given file containing '$value'.
659825
# Does not add an extra newline.
660826
#
661827
proc writefile {filename value} {
662828
set f [open $filename w]
663829
puts -nonewline $f $value
@@ -677,63 +843,60 @@
677843
lappend args [quote-if-needed $arg]
678844
}
679845
join $args
680846
}
681847
682
-# @suffix suf list
683
-#
684
-# Takes a list and returns a new list with $suf appended
685
-# to each element
686
-#
687
-## suffix .c {a b c} => {a.c b.c c.c}
688
-#
689
-proc suffix {suf list} {
848
+# @list-non-empty list
849
+#
850
+# Returns a copy of the given list with empty elements removed
851
+proc list-non-empty {list} {
690852
set result {}
691853
foreach p $list {
692
- lappend result $p$suf
854
+ if {$p ne ""} {
855
+ lappend result $p
856
+ }
693857
}
694858
return $result
695859
}
696860
697
-# @prefix pre list
698
-#
699
-# Takes a list and returns a new list with $pre prepended
700
-# to each element
701
-#
702
-## prefix jim- {a.c b.c} => {jim-a.c jim-b.c}
703
-#
704
-proc prefix {pre list} {
705
- set result {}
706
- foreach p $list {
707
- lappend result $pre$p
708
- }
709
- return $result
861
+# @find-executable-path name
862
+#
863
+# Searches the path for an executable with the given name.
864
+# Note that the name may include some parameters, e.g. 'cc -mbig-endian',
865
+# in which case the parameters are ignored.
866
+# The full path to the executable if found, or "" if not found.
867
+# Returns 1 if found, or 0 if not.
868
+#
869
+proc find-executable-path {name} {
870
+ # Ignore any parameters
871
+ set name [lindex $name 0]
872
+ # The empty string is never a valid executable
873
+ if {$name ne ""} {
874
+ foreach p [split-path] {
875
+ dputs "Looking for $name in $p"
876
+ set exec [file join $p $name]
877
+ if {[file-isexec $exec]} {
878
+ dputs "Found $name -> $exec"
879
+ return $exec
880
+ }
881
+ }
882
+ }
883
+ return {}
710884
}
711885
712886
# @find-executable name
713887
#
714888
# Searches the path for an executable with the given name.
715
-# Note that the name may include some parameters, e.g. "cc -mbig-endian",
889
+# Note that the name may include some parameters, e.g. 'cc -mbig-endian',
716890
# in which case the parameters are ignored.
717891
# Returns 1 if found, or 0 if not.
718892
#
719893
proc find-executable {name} {
720
- # Ignore any parameters
721
- set name [lindex $name 0]
722
- if {$name eq ""} {
723
- # The empty string is never a valid executable
724
- return 0
725
- }
726
- foreach p [split-path] {
727
- dputs "Looking for $name in $p"
728
- set exec [file join $p $name]
729
- if {[file-isexec $exec]} {
730
- dputs "Found $name -> $exec"
731
- return 1
732
- }
733
- }
734
- return 0
894
+ if {[find-executable-path $name] eq {}} {
895
+ return 0
896
+ }
897
+ return 1
735898
}
736899
737900
# @find-an-executable ?-required? name ...
738901
#
739902
# Given a list of possible executable names,
@@ -764,11 +927,11 @@
764927
return ""
765928
}
766929
767930
# @configlog msg
768931
#
769
-# Writes the given message to the configuration log, config.log
932
+# Writes the given message to the configuration log, 'config.log'.
770933
#
771934
proc configlog {msg} {
772935
if {![info exists ::autosetup(logfh)]} {
773936
set ::autosetup(logfh) [open config.log w]
774937
}
@@ -800,12 +963,12 @@
800963
}
801964
}
802965
803966
# @msg-quiet command ...
804967
#
805
-# msg-quiet evaluates it's arguments as a command with output
806
-# from msg-checking and msg-result suppressed.
968
+# 'msg-quiet' evaluates it's arguments as a command with output
969
+# from 'msg-checking' and 'msg-result' suppressed.
807970
#
808971
# This is useful if a check needs to run a subcheck which isn't
809972
# of interest to the user.
810973
proc msg-quiet {args} {
811974
incr ::autosetup(msg-quiet)
@@ -841,11 +1004,11 @@
8411004
8421005
# @user-error msg
8431006
#
8441007
# Indicate incorrect usage to the user, including if required components
8451008
# or features are not found.
846
-# autosetup exits with a non-zero return code.
1009
+# 'autosetup' exits with a non-zero return code.
8471010
#
8481011
proc user-error {msg} {
8491012
show-notices
8501013
puts stderr "Error: $msg"
8511014
puts stderr "Try: '[file tail $::autosetup(exe)] --help' for options"
@@ -887,10 +1050,21 @@
8871050
proc maybe-show-timestamp {} {
8881051
if {$::autosetup(msg-timing) && $::autosetup(msg-checking) == 0} {
8891052
puts -nonewline [format {[%6.2f] } [expr {([clock millis] - $::autosetup(start)) % 10000 / 1000.0}]]
8901053
}
8911054
}
1055
+
1056
+# @autosetup-require-version required
1057
+#
1058
+# Checks the current version of 'autosetup' against '$required'.
1059
+# A fatal error is generated if the current version is less than that required.
1060
+#
1061
+proc autosetup-require-version {required} {
1062
+ if {[compare-versions $::autosetup(version) $required] < 0} {
1063
+ user-error "autosetup version $required is required, but this is $::autosetup(version)"
1064
+ }
1065
+}
8921066
8931067
proc autosetup_version {} {
8941068
return "autosetup v$::autosetup(version)"
8951069
}
8961070
@@ -986,23 +1160,35 @@
9861160
# The latter form is useful for a complex module which requires additional
9871161
# support file. In this form, '$::usedir' is set to the module directory
9881162
# when it is loaded.
9891163
#
9901164
proc use {args} {
1165
+ global autosetup libmodule modsource
1166
+
1167
+ set dirs [list $autosetup(libdir)]
1168
+ if {[info exists autosetup(srcdir)]} {
1169
+ lappend dirs $autosetup(srcdir)/autosetup
1170
+ }
9911171
foreach m $args {
992
- if {[info exists ::libmodule($m)]} {
1172
+ if {[info exists libmodule($m)]} {
9931173
continue
9941174
}
995
- set ::libmodule($m) 1
996
- if {[info exists ::modsource($m)]} {
997
- automf_load eval $::modsource($m)
1175
+ set libmodule($m) 1
1176
+ if {[info exists modsource(${m}.tcl)]} {
1177
+ automf_load eval $modsource(${m}.tcl)
9981178
} else {
999
- set sources [list $::autosetup(libdir)/${m}.tcl $::autosetup(libdir)/${m}/init.tcl]
1179
+ set locs [list ${m}.tcl ${m}/init.tcl]
10001180
set found 0
1001
- foreach source $sources {
1002
- if {[file exists $source]} {
1003
- incr found
1181
+ foreach dir $dirs {
1182
+ foreach loc $locs {
1183
+ set source $dir/$loc
1184
+ if {[file exists $source]} {
1185
+ incr found
1186
+ break
1187
+ }
1188
+ }
1189
+ if {$found} {
10041190
break
10051191
}
10061192
}
10071193
if {$found} {
10081194
# For the convenience of the "use" source, point to the directory
@@ -1014,10 +1200,22 @@
10141200
autosetup-error "use: No such module: $m"
10151201
}
10161202
}
10171203
}
10181204
}
1205
+
1206
+proc autosetup_load_auto_modules {} {
1207
+ global autosetup modsource
1208
+ # First load any embedded auto modules
1209
+ foreach mod [array names modsource *.auto] {
1210
+ automf_load eval $modsource($mod)
1211
+ }
1212
+ # Now any external auto modules
1213
+ foreach file [glob -nocomplain $autosetup(libdir)/*.auto $autosetup(libdir)/*/*.auto] {
1214
+ automf_load source $file
1215
+ }
1216
+}
10191217
10201218
# Load module source in the global scope by executing the given command
10211219
proc automf_load {args} {
10221220
if {[catch [list uplevel #0 $args] msg opts] ni {0 2 3}} {
10231221
autosetup-full-error [error-dump $msg $opts $::autosetup(debug)]
@@ -1027,18 +1225,21 @@
10271225
# Initial settings
10281226
set autosetup(exe) $::argv0
10291227
set autosetup(istcl) 1
10301228
set autosetup(start) [clock millis]
10311229
set autosetup(installed) 0
1230
+set autosetup(sysinstall) 0
10321231
set autosetup(msg-checking) 0
10331232
set autosetup(msg-quiet) 0
1233
+set autosetup(inittypes) {}
10341234
10351235
# Embedded modules are inserted below here
10361236
set autosetup(installed) 1
1037
-# ----- module asciidoc-formatting -----
1237
+set autosetup(sysinstall) 0
1238
+# ----- @module asciidoc-formatting.tcl -----
10381239
1039
-set modsource(asciidoc-formatting) {
1240
+set modsource(asciidoc-formatting.tcl) {
10401241
# Copyright (c) 2010 WorkWare Systems http://www.workware.net.au/
10411242
# All rights reserved
10421243
10431244
# Module which provides text formatting
10441245
# asciidoc format
@@ -1102,19 +1303,19 @@
11021303
regsub -all "\n\n" $defn "\n ::\n" defn
11031304
puts $defn
11041305
}
11051306
}
11061307
1107
-# ----- module formatting -----
1308
+# ----- @module formatting.tcl -----
11081309
1109
-set modsource(formatting) {
1310
+set modsource(formatting.tcl) {
11101311
# Copyright (c) 2010 WorkWare Systems http://www.workware.net.au/
11111312
# All rights reserved
11121313
11131314
# Module which provides common text formatting
11141315
1115
-# This is designed for documenation which looks like:
1316
+# This is designed for documentation which looks like:
11161317
# code {...}
11171318
# or
11181319
# code {
11191320
# ...
11201321
# ...
@@ -1159,13 +1360,13 @@
11591360
# Return the result
11601361
return $lines
11611362
}
11621363
}
11631364
1164
-# ----- module getopt -----
1365
+# ----- @module getopt.tcl -----
11651366
1166
-set modsource(getopt) {
1367
+set modsource(getopt.tcl) {
11671368
# Copyright (c) 2006 WorkWare Systems http://www.workware.net.au/
11681369
# All rights reserved
11691370
11701371
# Simple getopt module
11711372
@@ -1197,11 +1398,11 @@
11971398
11981399
if {[regexp {^--([^=][^=]+)=(.*)$} $arg -> name value]} {
11991400
# --name=value
12001401
dict lappend opts $name [list str $value]
12011402
} elseif {[regexp {^--(enable-|disable-)?([^=]*)$} $arg -> prefix name]} {
1202
- if {$prefix in {enable- with- ""}} {
1403
+ if {$prefix in {enable- ""}} {
12031404
set value 1
12041405
} else {
12051406
set value 0
12061407
}
12071408
dict lappend opts $name [list bool $value]
@@ -1218,13 +1419,13 @@
12181419
12191420
return $opts
12201421
}
12211422
}
12221423
1223
-# ----- module help -----
1424
+# ----- @module help.tcl -----
12241425
1225
-set modsource(help) {
1426
+set modsource(help.tcl) {
12261427
# Copyright (c) 2010 WorkWare Systems http://workware.net.au/
12271428
# All rights reserved
12281429
12291430
# Module which provides usage, help and the command reference
12301431
@@ -1251,10 +1452,28 @@
12511452
options-show
12521453
}
12531454
}
12541455
exit 0
12551456
}
1457
+
1458
+proc autosetup_show_license {} {
1459
+ global modsource autosetup
1460
+ use_pager
1461
+
1462
+ if {[info exists modsource(LICENSE)]} {
1463
+ puts $modsource(LICENSE)
1464
+ return
1465
+ }
1466
+ foreach dir [list $autosetup(libdir) $autosetup(srcdir)] {
1467
+ set path [file join $dir LICENSE]
1468
+ if {[file exists $path]} {
1469
+ puts [readfile $path]
1470
+ return
1471
+ }
1472
+ }
1473
+ puts "LICENSE not found"
1474
+}
12561475
12571476
# If not already paged and stdout is a tty, pipe the output through the pager
12581477
# This is done by reinvoking autosetup with --nopager added
12591478
proc use_pager {} {
12601479
if {![opt-bool nopager] && [getenv PAGER ""] ne "" && [isatty? stdin] && [isatty? stdout]} {
@@ -1304,10 +1523,16 @@
13041523
}
13051524
13061525
proc autosetup_output_block {type lines} {
13071526
if {[llength $lines]} {
13081527
switch $type {
1528
+ section {
1529
+ section $lines
1530
+ }
1531
+ subsection {
1532
+ subsection $lines
1533
+ }
13091534
code {
13101535
codelines $lines
13111536
}
13121537
p {
13131538
p [join $lines]
@@ -1325,30 +1550,45 @@
13251550
# Generate a command reference from inline documentation
13261551
proc automf_command_reference {} {
13271552
lappend files $::autosetup(prog)
13281553
lappend files {*}[lsort [glob -nocomplain $::autosetup(libdir)/*.tcl]]
13291554
1330
- section "Core Commands"
1331
- set type p
1332
- set lines {}
1333
- set cmd {}
1555
+ # We want to process all non-module files before module files
1556
+ # and then modules in alphabetical order.
1557
+ # So examine all files and extract docs into doc($modulename) and doc(_core_)
1558
+ #
1559
+ # Each entry is a list of {type data} where $type is one of: section, subsection, code, list, p
1560
+ # and $data is a string for section, subsection or a list of text lines for other types.
1561
+
1562
+ # XXX: Should commands be in alphabetical order too? Currently they are in file order.
1563
+
1564
+ set doc(_core_) {}
1565
+ lappend doc(_core_) [list section "Core Commands"]
13341566
13351567
foreach file $files {
1568
+ set modulename [file rootname [file tail $file]]
1569
+ set current _core_
13361570
set f [open $file]
13371571
while {![eof $f]} {
13381572
set line [gets $f]
1573
+
1574
+ # Find embedded module names
1575
+ if {[regexp {^#.*@module ([^ ]*)} $line -> modulename]} {
1576
+ continue
1577
+ }
13391578
13401579
# Find lines starting with "# @*" and continuing through the remaining comment lines
13411580
if {![regexp {^# @(.*)} $line -> cmd]} {
13421581
continue
13431582
}
13441583
13451584
# Synopsis or command?
13461585
if {$cmd eq "synopsis:"} {
1347
- section "Module: [file rootname [file tail $file]]"
1586
+ set current $modulename
1587
+ lappend doc($current) [list section "Module: $modulename"]
13481588
} else {
1349
- subsection $cmd
1589
+ lappend doc($current) [list subsection $cmd]
13501590
}
13511591
13521592
set lines {}
13531593
set type p
13541594
@@ -1369,29 +1609,38 @@
13691609
13701610
#puts "hash=$hash, oldhash=$oldhash, lines=[llength $lines], cmd=$cmd"
13711611
13721612
if {$t ne $type || $cmd eq ""} {
13731613
# Finish the current block
1374
- autosetup_output_block $type $lines
1614
+ lappend doc($current) [list $type $lines]
13751615
set lines {}
13761616
set type $t
13771617
}
13781618
if {$cmd ne ""} {
13791619
lappend lines $cmd
13801620
}
13811621
}
13821622
1383
- autosetup_output_block $type $lines
1623
+ lappend doc($current) [list $type $lines]
13841624
}
13851625
close $f
13861626
}
1627
+
1628
+ # Now format and output the results
1629
+
1630
+ # _core_ will sort first
1631
+ foreach module [lsort [array names doc]] {
1632
+ foreach item $doc($module) {
1633
+ autosetup_output_block {*}$item
1634
+ }
1635
+ }
13871636
}
13881637
}
13891638
1390
-# ----- module init -----
1639
+# ----- @module init.tcl -----
13911640
1392
-set modsource(init) {
1641
+set modsource(init.tcl) {
13931642
# Copyright (c) 2010 WorkWare Systems http://www.workware.net.au/
13941643
# All rights reserved
13951644
13961645
# Module to help create auto.def and configure
13971646
@@ -1444,79 +1693,157 @@
14441693
}
14451694
writefile $filename $contents
14461695
}
14471696
}
14481697
1449
-# ----- module install -----
1698
+# ----- @module install.tcl -----
14501699
1451
-set modsource(install) {
1700
+set modsource(install.tcl) {
14521701
# Copyright (c) 2006-2010 WorkWare Systems http://www.workware.net.au/
14531702
# All rights reserved
14541703
14551704
# Module which can install autosetup
14561705
1457
-proc autosetup_install {dir} {
1458
- if {[catch {
1706
+# autosetup(installed)=1 means that autosetup is not running from source
1707
+# autosetup(sysinstall)=1 means that autosetup is running from a sysinstall version
1708
+# shared=1 means that we are trying to do a sysinstall. This is only possible from the development source.
1709
+
1710
+proc autosetup_install {dir {shared 0}} {
1711
+ global autosetup
1712
+ if {$shared} {
1713
+ if {$autosetup(installed) || $autosetup(sysinstall)} {
1714
+ user-error "Can only --sysinstall from development sources"
1715
+ }
1716
+ } elseif {$autosetup(installed) && !$autosetup(sysinstall)} {
1717
+ user-error "Can't --install from project install"
1718
+ }
1719
+
1720
+ if {$autosetup(sysinstall)} {
1721
+ # This is the sysinstall version, so install just uses references
14591722
cd $dir
1723
+
1724
+ puts "[autosetup_version] creating configure to use system-installed autosetup"
1725
+ autosetup_create_configure 1
1726
+ puts "Creating autosetup/README.autosetup"
14601727
file mkdir autosetup
1728
+ autosetup_install_readme autosetup/README.autosetup 1
1729
+ return
1730
+ }
1731
+
1732
+ if {[catch {
1733
+ if {$shared} {
1734
+ set target $dir/bin/autosetup
1735
+ set installedas $target
1736
+ } else {
1737
+ if {$dir eq "."} {
1738
+ set installedas autosetup
1739
+ } else {
1740
+ set installedas $dir/autosetup
1741
+ }
1742
+ cd $dir
1743
+ file mkdir autosetup
1744
+ set target autosetup/autosetup
1745
+ }
1746
+ set targetdir [file dirname $target]
1747
+ file mkdir $targetdir
14611748
1462
- set f [open autosetup/autosetup w]
1749
+ set f [open $target w]
14631750
1464
- set publicmodules [glob $::autosetup(libdir)/*.auto]
1751
+ set publicmodules {}
14651752
14661753
# First the main script, but only up until "CUT HERE"
1467
- set in [open $::autosetup(dir)/autosetup]
1754
+ set in [open $autosetup(dir)/autosetup]
14681755
while {[gets $in buf] >= 0} {
14691756
if {$buf ne "##-- CUT HERE --##"} {
14701757
puts $f $buf
14711758
continue
14721759
}
14731760
14741761
# Insert the static modules here
14751762
# i.e. those which don't contain @synopsis:
1763
+ # All modules are inserted if $shared is set
14761764
puts $f "set autosetup(installed) 1"
1477
- foreach file [lsort [glob $::autosetup(libdir)/*.tcl]] {
1765
+ puts $f "set autosetup(sysinstall) $shared"
1766
+ foreach file [lsort [glob $autosetup(libdir)/*.{tcl,auto}]] {
1767
+ set modname [file tail $file]
1768
+ set ext [file ext $modname]
14781769
set buf [readfile $file]
1479
- if {[string match "*\n# @synopsis:*" $buf]} {
1480
- lappend publicmodules $file
1481
- continue
1770
+ if {!$shared} {
1771
+ if {$ext eq ".auto" || [string match "*\n# @synopsis:*" $buf]} {
1772
+ lappend publicmodules $file
1773
+ continue
1774
+ }
14821775
}
1483
- set modname [file rootname [file tail $file]]
1484
- puts $f "# ----- module $modname -----"
1776
+ dputs "install: importing lib/[file tail $file]"
1777
+ puts $f "# ----- @module $modname -----"
14851778
puts $f "\nset modsource($modname) \{"
14861779
puts $f $buf
14871780
puts $f "\}\n"
14881781
}
1782
+ if {$shared} {
1783
+ foreach {srcname destname} [list $autosetup(libdir)/README.autosetup-lib README.autosetup \
1784
+ $autosetup(srcdir)/LICENSE LICENSE] {
1785
+ dputs "install: importing $srcname as $destname"
1786
+ puts $f "\nset modsource($destname) \\\n[list [readfile $srcname]\n]\n"
1787
+ }
1788
+ }
14891789
}
14901790
close $in
14911791
close $f
1492
- exec chmod 755 autosetup/autosetup
1792
+ catch {exec chmod 755 $target}
1793
+
1794
+ set installfiles {autosetup-config.guess autosetup-config.sub autosetup-test-tclsh}
1795
+ set removefiles {}
1796
+
1797
+ if {!$shared} {
1798
+ autosetup_install_readme $targetdir/README.autosetup 0
14931799
1494
- # Install public modules
1495
- foreach file $publicmodules {
1496
- autosetup_install_file $file autosetup
1800
+ # Install public modules
1801
+ foreach file $publicmodules {
1802
+ set tail [file tail $file]
1803
+ autosetup_install_file $file $targetdir/$tail
1804
+ }
1805
+ lappend installfiles jimsh0.c autosetup-find-tclsh LICENSE
1806
+ lappend removefiles config.guess config.sub test-tclsh find-tclsh
1807
+ } else {
1808
+ lappend installfiles {sys-find-tclsh autosetup-find-tclsh}
14971809
}
14981810
14991811
# Install support files
1500
- foreach file {config.guess config.sub jimsh0.c find-tclsh test-tclsh LICENSE} {
1501
- autosetup_install_file $::autosetup(dir)/$file autosetup
1502
- }
1503
- exec chmod 755 autosetup/config.sub autosetup/config.guess autosetup/find-tclsh
1504
-
1505
- writefile autosetup/README.autosetup \
1506
- "This is [autosetup_version]. See http://msteveb.github.com/autosetup/\n"
1507
-
1812
+ foreach fileinfo $installfiles {
1813
+ if {[llength $fileinfo] == 2} {
1814
+ lassign $fileinfo source dest
1815
+ } else {
1816
+ lassign $fileinfo source
1817
+ set dest $source
1818
+ }
1819
+ autosetup_install_file $autosetup(dir)/$source $targetdir/$dest
1820
+ }
1821
+
1822
+ # Remove obsolete files
1823
+ foreach file $removefiles {
1824
+ if {[file exists $targetdir/$file]} {
1825
+ file delete $targetdir/$file
1826
+ }
1827
+ }
15081828
} error]} {
15091829
user-error "Failed to install autosetup: $error"
15101830
}
1511
- puts "Installed [autosetup_version] to autosetup/"
1831
+ if {$shared} {
1832
+ set type "system"
1833
+ } else {
1834
+ set type "local"
1835
+ }
1836
+ puts "Installed $type [autosetup_version] to $installedas"
15121837
1513
- # Now create 'configure' if necessary
1514
- autosetup_create_configure
1838
+ if {!$shared} {
1839
+ # Now create 'configure' if necessary
1840
+ autosetup_create_configure 0
1841
+ }
15151842
}
15161843
1517
-proc autosetup_create_configure {} {
1844
+proc autosetup_create_configure {shared} {
15181845
if {[file exists configure]} {
15191846
if {!$::autosetup(force)} {
15201847
# Could this be an autosetup configure?
15211848
if {![string match "*\nWRAPPER=*" [readfile configure]]} {
15221849
puts "I see configure, but not created by autosetup, so I won't overwrite it."
@@ -1527,40 +1854,75 @@
15271854
puts "I will overwrite the existing configure because you used --force."
15281855
}
15291856
} else {
15301857
puts "I don't see configure, so I will create it."
15311858
}
1532
- writefile configure \
1859
+ if {$shared} {
1860
+ writefile configure \
1861
+{#!/bin/sh
1862
+WRAPPER="$0"; export WRAPPER; "autosetup" "$@"
1863
+}
1864
+ } else {
1865
+ writefile configure \
15331866
{#!/bin/sh
15341867
dir="`dirname "$0"`/autosetup"
1535
-WRAPPER="$0"; export WRAPPER; exec "`$dir/find-tclsh`" "$dir/autosetup" "$@"
1868
+WRAPPER="$0"; export WRAPPER; exec "`"$dir/autosetup-find-tclsh"`" "$dir/autosetup" "$@"
15361869
}
1870
+ }
15371871
catch {exec chmod 755 configure}
15381872
}
15391873
15401874
# Append the contents of $file to filehandle $f
15411875
proc autosetup_install_append {f file} {
1876
+ dputs "install: include $file"
15421877
set in [open $file]
15431878
puts $f [read $in]
15441879
close $in
15451880
}
15461881
1547
-proc autosetup_install_file {file dir} {
1548
- if {![file exists $file]} {
1549
- error "Missing installation file '$file'"
1550
- }
1551
- writefile [file join $dir [file tail $file]] [readfile $file]\n
1552
-}
1553
-
1554
-if {$::autosetup(installed)} {
1555
- user-error "autosetup can only be installed from development source, not from installed copy"
1882
+proc autosetup_install_file {source target} {
1883
+ dputs "install: $source => $target"
1884
+ if {![file exists $source]} {
1885
+ error "Missing installation file '$source'"
1886
+ }
1887
+ writefile $target [readfile $source]\n
1888
+ # If possible, copy the file mode
1889
+ file stat $source stat
1890
+ set mode [format %o [expr {$stat(mode) & 0x1ff}]]
1891
+ catch {exec chmod $mode $target}
1892
+}
1893
+
1894
+proc autosetup_install_readme {target sysinstall} {
1895
+ set readme "README.autosetup created by [autosetup_version]\n\n"
1896
+ if {$sysinstall} {
1897
+ append readme \
1898
+{This is the autosetup directory for a system install of autosetup.
1899
+Loadable modules can be added here.
1900
+}
1901
+ } else {
1902
+ append readme \
1903
+{This is the autosetup directory for a local install of autosetup.
1904
+It contains autosetup, support files and loadable modules.
1905
+}
1906
+}
1907
+
1908
+ append readme {
1909
+*.tcl files in this directory are optional modules which
1910
+can be loaded with the 'use' directive.
1911
+
1912
+*.auto files in this directory are auto-loaded.
1913
+
1914
+For more information, see http://msteveb.github.com/autosetup/
1915
+}
1916
+ dputs "install: autosetup/README.autosetup"
1917
+ writefile $target $readme
15561918
}
15571919
}
15581920
1559
-# ----- module markdown-formatting -----
1921
+# ----- @module markdown-formatting.tcl -----
15601922
1561
-set modsource(markdown-formatting) {
1923
+set modsource(markdown-formatting.tcl) {
15621924
# Copyright (c) 2010 WorkWare Systems http://www.workware.net.au/
15631925
# All rights reserved
15641926
15651927
# Module which provides text formatting
15661928
# markdown format (kramdown syntax)
@@ -1627,13 +1989,13 @@
16271989
}
16281990
puts "$defn"
16291991
}
16301992
}
16311993
1632
-# ----- module misc -----
1994
+# ----- @module misc.tcl -----
16331995
1634
-set modsource(misc) {
1996
+set modsource(misc.tcl) {
16351997
# Copyright (c) 2007-2010 WorkWare Systems http://www.workware.net.au/
16361998
# All rights reserved
16371999
16382000
# Module containing misc procs useful to modules
16392001
# Largely for platform compatibility
@@ -1805,106 +2167,218 @@
18052167
string trim $result
18062168
}
18072169
}
18082170
}
18092171
1810
-# ----- module text-formatting -----
2172
+# ----- @module text-formatting.tcl -----
18112173
1812
-set modsource(text-formatting) {
2174
+set modsource(text-formatting.tcl) {
18132175
# Copyright (c) 2010 WorkWare Systems http://www.workware.net.au/
18142176
# All rights reserved
18152177
18162178
# Module which provides text formatting
18172179
18182180
use formatting
18192181
18202182
proc wordwrap {text length {firstprefix ""} {nextprefix ""}} {
1821
- set len 0
1822
- set space $firstprefix
1823
- foreach word [split $text] {
1824
- set word [string trim $word]
1825
- if {$word == ""} {
1826
- continue
1827
- }
1828
- if {$len && [string length $space$word] + $len >= $length} {
1829
- puts ""
1830
- set len 0
1831
- set space $nextprefix
1832
- }
1833
- incr len [string length $space$word]
1834
-
1835
- # Use man-page conventions for highlighting 'quoted' and *quoted*
1836
- # single words.
1837
- # Use x^Hx for *bold* and _^Hx for 'underline'.
1838
- #
1839
- # less and more will both understand this.
1840
- # Pipe through 'col -b' to remove them.
1841
- if {[regexp {^'(.*)'([^a-zA-Z0-9_]*)$} $word -> bareword dot]} {
1842
- regsub -all . $bareword "_\b&" word
1843
- append word $dot
1844
- } elseif {[regexp {^[*](.*)[*]([^a-zA-Z0-9_]*)$} $word -> bareword dot]} {
1845
- regsub -all . $bareword "&\b&" word
1846
- append word $dot
1847
- }
1848
- puts -nonewline $space$word
1849
- set space " "
1850
- }
1851
- if {$len} {
1852
- puts ""
1853
- }
2183
+ set len 0
2184
+ set space $firstprefix
2185
+
2186
+ foreach word [split $text] {
2187
+ set word [string trim $word]
2188
+ if {$word eq ""} {
2189
+ continue
2190
+ }
2191
+ if {[info exists partial]} {
2192
+ append partial " " $word
2193
+ if {[string first $quote $word] < 0} {
2194
+ # Haven't found end of quoted word
2195
+ continue
2196
+ }
2197
+ # Finished quoted word
2198
+ set word $partial
2199
+ unset partial
2200
+ unset quote
2201
+ } else {
2202
+ set quote [string index $word 0]
2203
+ if {$quote in {' *}} {
2204
+ if {[string first $quote $word 1] < 0} {
2205
+ # Haven't found end of quoted word
2206
+ # Not a whole word.
2207
+ set first [string index $word 0]
2208
+ # Start of quoted word
2209
+ set partial $word
2210
+ continue
2211
+ }
2212
+ }
2213
+ }
2214
+
2215
+ if {$len && [string length $space$word] + $len >= $length} {
2216
+ puts ""
2217
+ set len 0
2218
+ set space $nextprefix
2219
+ }
2220
+ incr len [string length $space$word]
2221
+
2222
+ # Use man-page conventions for highlighting 'quoted' and *quoted*
2223
+ # single words.
2224
+ # Use x^Hx for *bold* and _^Hx for 'underline'.
2225
+ #
2226
+ # less and more will both understand this.
2227
+ # Pipe through 'col -b' to remove them.
2228
+ if {[regexp {^'(.*)'(.*)} $word -> quoted after]} {
2229
+ set quoted [string map {~ " "} $quoted]
2230
+ regsub -all . $quoted "&\b&" quoted
2231
+ set word $quoted$after
2232
+ } elseif {[regexp {^[*](.*)[*](.*)} $word -> quoted after]} {
2233
+ set quoted [string map {~ " "} $quoted]
2234
+ regsub -all . $quoted "_\b&" quoted
2235
+ set word $quoted$after
2236
+ }
2237
+ puts -nonewline $space$word
2238
+ set space " "
2239
+ }
2240
+ if {[info exists partial]} {
2241
+ # Missing end of quote
2242
+ puts -nonewline $space$partial
2243
+ }
2244
+ if {$len} {
2245
+ puts ""
2246
+ }
18542247
}
18552248
proc title {text} {
1856
- underline [string trim $text] =
1857
- nl
2249
+ underline [string trim $text] =
2250
+ nl
18582251
}
18592252
proc p {text} {
1860
- wordwrap $text 80
1861
- nl
2253
+ wordwrap $text 80
2254
+ nl
18622255
}
18632256
proc codelines {lines} {
1864
- foreach line $lines {
1865
- puts " $line"
1866
- }
1867
- nl
2257
+ foreach line $lines {
2258
+ puts " $line"
2259
+ }
2260
+ nl
18682261
}
18692262
proc nl {} {
1870
- puts ""
2263
+ puts ""
18712264
}
18722265
proc underline {text char} {
1873
- regexp "^(\[ \t\]*)(.*)" $text -> indent words
1874
- puts $text
1875
- puts $indent[string repeat $char [string length $words]]
2266
+ regexp "^(\[ \t\]*)(.*)" $text -> indent words
2267
+ puts $text
2268
+ puts $indent[string repeat $char [string length $words]]
18762269
}
18772270
proc section {text} {
1878
- underline "[string trim $text]" -
1879
- nl
2271
+ underline "[string trim $text]" -
2272
+ nl
18802273
}
18812274
proc subsection {text} {
1882
- underline "$text" ~
1883
- nl
2275
+ underline "$text" ~
2276
+ nl
18842277
}
18852278
proc bullet {text} {
1886
- wordwrap $text 76 " * " " "
2279
+ wordwrap $text 76 " * " " "
18872280
}
18882281
proc indent {text} {
1889
- wordwrap $text 76 " " " "
2282
+ wordwrap $text 76 " " " "
18902283
}
18912284
proc defn {first args} {
1892
- if {$first ne ""} {
1893
- underline " $first" ~
1894
- }
1895
- foreach p $args {
1896
- if {$p ne ""} {
1897
- indent $p
1898
- }
1899
- }
2285
+ if {$first ne ""} {
2286
+ underline " $first" ~
2287
+ }
2288
+ foreach p $args {
2289
+ if {$p ne ""} {
2290
+ indent $p
2291
+ }
2292
+ }
2293
+}
2294
+}
2295
+
2296
+# ----- @module util.tcl -----
2297
+
2298
+set modsource(util.tcl) {
2299
+# Copyright (c) 2012 WorkWare Systems http://www.workware.net.au/
2300
+# All rights reserved
2301
+
2302
+# Module which contains miscellaneous utility functions
2303
+
2304
+# @compare-versions version1 version2
2305
+#
2306
+# Versions are of the form 'a.b.c' (may be any number of numeric components)
2307
+#
2308
+# Compares the two versions and returns:
2309
+## -1 if v1 < v2
2310
+## 0 if v1 == v2
2311
+## 1 if v1 > v2
2312
+#
2313
+# If one version has fewer components than the other, 0 is substituted to the right. e.g.
2314
+## 0.2 < 0.3
2315
+## 0.2.5 > 0.2
2316
+## 1.1 == 1.1.0
2317
+#
2318
+proc compare-versions {v1 v2} {
2319
+ foreach c1 [split $v1 .] c2 [split $v2 .] {
2320
+ if {$c1 eq ""} {
2321
+ set c1 0
2322
+ }
2323
+ if {$c2 eq ""} {
2324
+ set c2 0
2325
+ }
2326
+ if {$c1 < $c2} {
2327
+ return -1
2328
+ }
2329
+ if {$c1 > $c2} {
2330
+ return 1
2331
+ }
2332
+ }
2333
+ return 0
2334
+}
2335
+
2336
+# @suffix suf list
2337
+#
2338
+# Takes a list and returns a new list with '$suf' appended
2339
+# to each element
2340
+#
2341
+## suffix .c {a b c} => {a.c b.c c.c}
2342
+#
2343
+proc suffix {suf list} {
2344
+ set result {}
2345
+ foreach p $list {
2346
+ lappend result $p$suf
2347
+ }
2348
+ return $result
2349
+}
2350
+
2351
+# @prefix pre list
2352
+#
2353
+# Takes a list and returns a new list with '$pre' prepended
2354
+# to each element
2355
+#
2356
+## prefix jim- {a.c b.c} => {jim-a.c jim-b.c}
2357
+#
2358
+proc prefix {pre list} {
2359
+ set result {}
2360
+ foreach p $list {
2361
+ lappend result $pre$p
2362
+ }
2363
+ return $result
2364
+}
2365
+
2366
+# @lpop list
2367
+#
2368
+# Removes the last entry from the given list and returns it.
2369
+proc lpop {listname} {
2370
+ upvar $listname list
2371
+ set val [lindex $list end]
2372
+ set list [lrange $list 0 end-1]
2373
+ return $val
19002374
}
19012375
}
19022376
1903
-# ----- module wiki-formatting -----
2377
+# ----- @module wiki-formatting.tcl -----
19042378
1905
-set modsource(wiki-formatting) {
2379
+set modsource(wiki-formatting.tcl) {
19062380
# Copyright (c) 2010 WorkWare Systems http://www.workware.net.au/
19072381
# All rights reserved
19082382
19092383
# Module which provides text formatting
19102384
# wiki.tcl.tk format output
@@ -1975,11 +2449,11 @@
19752449
if {$autosetup(debug)} {
19762450
main $argv
19772451
}
19782452
if {[catch {main $argv} msg opts] == 1} {
19792453
show-notices
1980
- autosetup-full-error [error-dump $msg $opts $::autosetup(debug)]
2454
+ autosetup-full-error [error-dump $msg $opts $autosetup(debug)]
19812455
if {!$autosetup(debug)} {
19822456
puts stderr "Try: '[file tail $autosetup(exe)] --debug' for a full stack trace"
19832457
}
19842458
exit 1
19852459
}
19862460
19872461
ADDED autosetup/autosetup-config.guess
19882462
ADDED autosetup/autosetup-config.sub
19892463
ADDED autosetup/autosetup-find-tclsh
19902464
ADDED autosetup/autosetup-test-tclsh
--- autosetup/autosetup
+++ autosetup/autosetup
@@ -1,16 +1,17 @@
1 #!/bin/sh
2 # Copyright (c) 2006-2011 WorkWare Systems http://www.workware.net.au/
3 # All rights reserved
4 # vim:se syntax=tcl:
5 # \
6 dir=`dirname "$0"`; exec "`$dir/find-tclsh`" "$0" "$@"
7
8 set autosetup(version) 0.6.6
 
9
10 # Can be set to 1 to debug early-init problems
11 set autosetup(debug) 0
12
13 ##################################################################
14 #
15 # Main flow of control, option handling
16 #
@@ -72,14 +73,18 @@
72 set autosetup(cmdline) {}
73 # options is a list of known options
74 set autosetup(options) {}
75 # optset is a dictionary of option values set by the user based on getopt
76 set autosetup(optset) {}
77 # optdefault is a dictionary of default values for options
78 set autosetup(optdefault) {}
 
 
79 set autosetup(optionhelp) {}
80 set autosetup(showhelp) 0
 
 
81
82 # Parse options
83 use getopt
84
85 # At the is point we don't know what is a valid option
@@ -87,15 +92,28 @@
87 set autosetup(getopt) [getopt argv]
88
89 #"=Core Options:"
90 options-add {
91 help:=local => "display help and options. Optionally specify a module name, such as --help=system"
 
92 version => "display the version of autosetup"
93 ref:=text manual:=text
94 reference:=text => "display the autosetup command reference. 'text', 'wiki', 'asciidoc' or 'markdown'"
95 debug => "display debugging output as autosetup runs"
96 install:=. => "install autosetup to the current or given directory (in the 'autosetup/' subdirectory)"
 
 
 
 
 
 
 
 
 
 
 
 
97 force init:=help => "create initial auto.def, etc. Use --init=help for known types"
98 # Undocumented options
99 option-checking=1
100 nopager
101 quiet
@@ -107,12 +125,12 @@
107 puts $autosetup(version)
108 exit 0
109 }
110
111 # autosetup --conf=alternate-auto.def
112 if {[opt-val conf] ne ""} {
113 set autosetup(autodef) [opt-val conf]
114 }
115
116 # Debugging output (set this early)
117 incr autosetup(debug) [opt-bool debug]
118 incr autosetup(force) [opt-bool force]
@@ -124,41 +142,50 @@
124 if {[file exists $autosetup(libdir)/local.tcl]} {
125 use local
126 }
127
128 # Now any auto-load modules
129 foreach file [glob -nocomplain $autosetup(libdir)/*.auto $autosetup(libdir)/*/*.auto] {
130 automf_load source $file
131 }
132
133 if {[opt-val help] ne ""} {
134 incr autosetup(showhelp)
135 use help
136 autosetup_help [opt-val help]
137 }
138
139 if {[opt-val {manual ref reference}] ne ""} {
 
 
 
 
 
 
140 use help
141 autosetup_reference [opt-val {manual ref reference}]
142 }
143
144 # Allow combining --install and --init
145 set earlyexit 0
146 if {[opt-val install] ne ""} {
147 use install
148 autosetup_install [opt-val install]
149 incr earlyexit
150 }
151
152 if {[opt-val init] ne ""} {
153 use init
154 autosetup_init [opt-val init]
155 incr earlyexit
156 }
157
158 if {$earlyexit} {
159 exit 0
 
 
 
 
 
160 }
161
162 if {![file exists $autosetup(autodef)]} {
163 # Check for invalid option first
164 options {}
@@ -185,10 +212,11 @@
185 define-append AUTOREMAKE [get-define CONFIGURE_OPTS]
186
187
188 # Log how we were invoked
189 configlog "Invoked as: [getenv WRAPPER $::argv0] [quote-argv $autosetup(argv)]"
 
190
191 # Note that auto.def is *not* loaded in the global scope
192 source $autosetup(autodef)
193
194 # Could warn here if options {} was not specified
@@ -210,14 +238,14 @@
210 #
211 # Check each of the named, boolean options and if any have been explicitly enabled
212 # or disabled by the user, return 1 or 0 accordingly.
213 #
214 # If the option was specified more than once, the last value wins.
215 # e.g. With --enable-foo --disable-foo, [opt-bool foo] will return 0
216 #
217 # If no value was specified by the user, returns the default value for the
218 # first option. If -nodefault is given, this behaviour changes and
219 # -1 is returned instead.
220 #
221 proc opt-bool {args} {
222 set nodefault 0
223 if {[lindex $args 0] eq "-nodefault"} {
@@ -237,20 +265,19 @@
237 }
238 # Default value is the default for the first option
239 return [dict get $::autosetup(optdefault) [lindex $args 0]]
240 }
241
242 # @opt-val option-list ?default=""?
243 #
244 # Returns a list containing all the values given for the non-boolean options in 'option-list'.
245 # There will be one entry in the list for each option given by the user, including if the
246 # same option was used multiple times.
247 # If only a single value is required, use something like:
248 #
249 ## lindex [opt-val $names] end
250 #
251 # If no options were set, $default is returned (exactly, not as a list).
252 #
253 proc opt-val {names {default ""}} {
254 option-check-names {*}$names
255
256 foreach opt $names {
@@ -261,10 +288,83 @@
261 if {[info exists result]} {
262 return $result
263 }
264 return $default
265 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
266
267 proc option-check-names {args} {
268 foreach o $args {
269 if {$o ni $::autosetup(options)} {
270 autosetup-error "Request for undeclared option --$o"
@@ -293,10 +393,11 @@
293 # This is a special heading
294 lappend autosetup(optionhelp) $opt ""
295 set header {}
296 continue
297 }
 
298
299 #puts "i=$i, opt=$opt"
300 regexp {^([^:=]*)(:)?(=)?(.*)$} $opt -> name colon equal value
301 if {$name in $autosetup(options)} {
302 autosetup-error "Option $name already specified"
@@ -310,10 +411,16 @@
310 # This is a documentation-only option, like "-C <dir>"
311 set opthelp $opt
312 } elseif {$colon eq ""} {
313 # Boolean option
314 lappend autosetup(options) $name
 
 
 
 
 
 
315
316 if {$value eq "1"} {
317 set opthelp "--disable-$name"
318 } else {
319 set opthelp "--$name"
@@ -321,11 +428,12 @@
321
322 # Set the default
323 if {$value eq ""} {
324 set value 0
325 }
326 dict set autosetup(optdefault) $name $value
 
327
328 if {[dict exists $autosetup(getopt) $name]} {
329 # The option was specified by the user. Look at the last value.
330 lassign [lindex [dict get $autosetup(getopt) $name] end] type setvalue
331 if {$type eq "str"} {
@@ -342,19 +450,39 @@
342 #puts "Found boolean option --$name=$setvalue"
343 }
344 } else {
345 # String option.
346 lappend autosetup(options) $name
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
347
348 if {$equal eq "="} {
349 # String option with optional value
350 set opthelp "--$name?=$value?"
351 } else {
352 # String option with required value
353 set opthelp "--$name=$value"
354 }
355 dict set autosetup(optdefault) $name $value
356
357 # Get the values specified by the user
358 if {[dict exists $autosetup(getopt) $name]} {
359 set listvalue {}
360
@@ -363,11 +491,11 @@
363 if {$type eq "bool" && $setvalue} {
364 if {$equal ne "="} {
365 user-error "Option --$name requires a value"
366 }
367 # If given as a boolean, use the default value
368 set setvalue $value
369 }
370 lappend listvalue $setvalue
371 }
372
373 #puts "Found string option --$name=$listvalue"
@@ -376,10 +504,13 @@
376 }
377
378 # Now create the help for this option if appropriate
379 if {[lindex $opts $i+1] eq "=>"} {
380 set desc [lindex $opts $i+2]
 
 
 
381 #string match \n* $desc
382 if {$header ne ""} {
383 lappend autosetup(optionhelp) $header ""
384 set header ""
385 }
@@ -463,35 +594,39 @@
463 options-wrap-desc [string trim $desc] $cols " " $indent [expr $max + 2]
464 }
465 }
466 }
467
468 # @options options-spec
469 #
470 # Specifies configuration-time options which may be selected by the user
471 # and checked with opt-val and opt-bool. The format of options-spec follows.
 
472 #
473 # A boolean option is of the form:
474 #
475 ## name[=0|1] => "Description of this boolean option"
476 #
477 # The default is name=0, meaning that the option is disabled by default.
478 # If name=1 is used to make the option enabled by default, the description should reflect
479 # that with text like "Disable support for ...".
480 #
481 # An argument option (one which takes a parameter) is of the form:
482 #
483 ## name:[=]value => "Description of this option"
484 #
485 # If the name:value form is used, the value must be provided with the option (as --name=myvalue).
486 # If the name:=value form is used, the value is optional and the given value is used as the default
487 # if it is not provided.
488 #
489 # Undocumented options are also supported by omitting the "=> description.
490 # These options are not displayed with --help and can be useful for internal options or as aliases.
491 #
492 # For example, --disable-lfs is an alias for --disable=largefile:
 
 
 
493 #
494 ## lfs=1 largefile=1 => "Disable large file support"
495 #
496 proc options {optlist} {
497 # Allow options as a list or args
@@ -509,27 +644,37 @@
509 user-error "Unknown option --$o"
510 }
511 }
512 }
513 }
 
 
 
 
 
 
 
 
 
 
 
514
515 proc config_guess {} {
516 if {[file-isexec $::autosetup(dir)/config.guess]} {
517 exec-with-stderr sh $::autosetup(dir)/config.guess
518 if {[catch {exec-with-stderr sh $::autosetup(dir)/config.guess} alias]} {
519 user-error $alias
520 }
521 return $alias
522 } else {
523 configlog "No config.guess, so using uname"
524 string tolower [exec uname -p]-unknown-[exec uname -s][exec uname -r]
525 }
526 }
527
528 proc config_sub {alias} {
529 if {[file-isexec $::autosetup(dir)/config.sub]} {
530 if {[catch {exec-with-stderr sh $::autosetup(dir)/config.sub $alias} alias]} {
531 user-error $alias
532 }
533 }
534 return $alias
535 }
@@ -536,39 +681,48 @@
536
537 # @define name ?value=1?
538 #
539 # Defines the named variable to the given value.
540 # These (name, value) pairs represent the results of the configuration check
541 # and are available to be checked, modified and substituted.
542 #
543 proc define {name {value 1}} {
544 set ::define($name) $value
545 #dputs "$name <= $value"
546 }
547
548 # @undefine name
549 #
550 # Undefine the named variable
551 #
552 proc undefine {name} {
553 unset -nocomplain ::define($name)
554 #dputs "$name <= <undef>"
555 }
556
557 # @define-append name value ...
558 #
559 # Appends the given value(s) to the given 'defined' variable.
560 # If the variable is not defined or empty, it is set to $value.
561 # Otherwise the value is appended, separated by a space.
562 # Any extra values are similarly appended.
563 # If any value is already contained in the variable (as a substring) it is omitted.
564 #
565 proc define-append {name args} {
566 if {[get-define $name ""] ne ""} {
567 # Make a token attempt to avoid duplicates
568 foreach arg $args {
569 if {[string first $arg $::define($name)] == -1} {
 
 
 
 
 
 
 
 
 
570 append ::define($name) " " $arg
571 }
572 }
573 } else {
574 set ::define($name) [join $args]
@@ -576,11 +730,11 @@
576 #dputs "$name += [join $args] => $::define($name)"
577 }
578
579 # @get-define name ?default=0?
580 #
581 # Returns the current value of the 'defined' variable, or $default
582 # if not set.
583 #
584 proc get-define {name {default 0}} {
585 if {[info exists ::define($name)]} {
586 #dputs "$name => $::define($name)"
@@ -595,14 +749,26 @@
595 # Returns 1 if the given variable is defined.
596 #
597 proc is-defined {name} {
598 info exists ::define($name)
599 }
 
 
 
 
 
 
 
 
 
 
 
 
600
601 # @all-defines
602 #
603 # Returns a dictionary (name value list) of all defined variables.
604 #
605 # This is suitable for use with 'dict', 'array set' or 'foreach'
606 # and allows for arbitrary processing of the defined variables.
607 #
608 proc all-defines {} {
@@ -610,13 +776,13 @@
610 }
611
612
613 # @get-env name default
614 #
615 # If $name was specified on the command line, return it.
616 # If $name was set in the environment, return it.
617 # Otherwise return $default.
618 #
619 proc get-env {name default} {
620 if {[dict exists $::autosetup(cmdline) $name]} {
621 return [dict get $::autosetup(cmdline) $name]
622 }
@@ -623,11 +789,11 @@
623 getenv $name $default
624 }
625
626 # @env-is-set name
627 #
628 # Returns 1 if the $name was specified on the command line or in the environment.
629 # Note that an empty environment variable is not considered to be set.
630 #
631 proc env-is-set {name} {
632 if {[dict exists $::autosetup(cmdline) $name]} {
633 return 1
@@ -639,11 +805,11 @@
639 }
640
641 # @readfile filename ?default=""?
642 #
643 # Return the contents of the file, without the trailing newline.
644 # If the file doesn't exist or can't be read, returns $default.
645 #
646 proc readfile {filename {default_value ""}} {
647 set result $default_value
648 catch {
649 set f [open $filename]
@@ -653,11 +819,11 @@
653 return $result
654 }
655
656 # @writefile filename value
657 #
658 # Creates the given file containing $value.
659 # Does not add an extra newline.
660 #
661 proc writefile {filename value} {
662 set f [open $filename w]
663 puts -nonewline $f $value
@@ -677,63 +843,60 @@
677 lappend args [quote-if-needed $arg]
678 }
679 join $args
680 }
681
682 # @suffix suf list
683 #
684 # Takes a list and returns a new list with $suf appended
685 # to each element
686 #
687 ## suffix .c {a b c} => {a.c b.c c.c}
688 #
689 proc suffix {suf list} {
690 set result {}
691 foreach p $list {
692 lappend result $p$suf
 
 
693 }
694 return $result
695 }
696
697 # @prefix pre list
698 #
699 # Takes a list and returns a new list with $pre prepended
700 # to each element
701 #
702 ## prefix jim- {a.c b.c} => {jim-a.c jim-b.c}
703 #
704 proc prefix {pre list} {
705 set result {}
706 foreach p $list {
707 lappend result $pre$p
708 }
709 return $result
 
 
 
 
 
 
 
 
 
 
710 }
711
712 # @find-executable name
713 #
714 # Searches the path for an executable with the given name.
715 # Note that the name may include some parameters, e.g. "cc -mbig-endian",
716 # in which case the parameters are ignored.
717 # Returns 1 if found, or 0 if not.
718 #
719 proc find-executable {name} {
720 # Ignore any parameters
721 set name [lindex $name 0]
722 if {$name eq ""} {
723 # The empty string is never a valid executable
724 return 0
725 }
726 foreach p [split-path] {
727 dputs "Looking for $name in $p"
728 set exec [file join $p $name]
729 if {[file-isexec $exec]} {
730 dputs "Found $name -> $exec"
731 return 1
732 }
733 }
734 return 0
735 }
736
737 # @find-an-executable ?-required? name ...
738 #
739 # Given a list of possible executable names,
@@ -764,11 +927,11 @@
764 return ""
765 }
766
767 # @configlog msg
768 #
769 # Writes the given message to the configuration log, config.log
770 #
771 proc configlog {msg} {
772 if {![info exists ::autosetup(logfh)]} {
773 set ::autosetup(logfh) [open config.log w]
774 }
@@ -800,12 +963,12 @@
800 }
801 }
802
803 # @msg-quiet command ...
804 #
805 # msg-quiet evaluates it's arguments as a command with output
806 # from msg-checking and msg-result suppressed.
807 #
808 # This is useful if a check needs to run a subcheck which isn't
809 # of interest to the user.
810 proc msg-quiet {args} {
811 incr ::autosetup(msg-quiet)
@@ -841,11 +1004,11 @@
841
842 # @user-error msg
843 #
844 # Indicate incorrect usage to the user, including if required components
845 # or features are not found.
846 # autosetup exits with a non-zero return code.
847 #
848 proc user-error {msg} {
849 show-notices
850 puts stderr "Error: $msg"
851 puts stderr "Try: '[file tail $::autosetup(exe)] --help' for options"
@@ -887,10 +1050,21 @@
887 proc maybe-show-timestamp {} {
888 if {$::autosetup(msg-timing) && $::autosetup(msg-checking) == 0} {
889 puts -nonewline [format {[%6.2f] } [expr {([clock millis] - $::autosetup(start)) % 10000 / 1000.0}]]
890 }
891 }
 
 
 
 
 
 
 
 
 
 
 
892
893 proc autosetup_version {} {
894 return "autosetup v$::autosetup(version)"
895 }
896
@@ -986,23 +1160,35 @@
986 # The latter form is useful for a complex module which requires additional
987 # support file. In this form, '$::usedir' is set to the module directory
988 # when it is loaded.
989 #
990 proc use {args} {
 
 
 
 
 
 
991 foreach m $args {
992 if {[info exists ::libmodule($m)]} {
993 continue
994 }
995 set ::libmodule($m) 1
996 if {[info exists ::modsource($m)]} {
997 automf_load eval $::modsource($m)
998 } else {
999 set sources [list $::autosetup(libdir)/${m}.tcl $::autosetup(libdir)/${m}/init.tcl]
1000 set found 0
1001 foreach source $sources {
1002 if {[file exists $source]} {
1003 incr found
 
 
 
 
 
 
1004 break
1005 }
1006 }
1007 if {$found} {
1008 # For the convenience of the "use" source, point to the directory
@@ -1014,10 +1200,22 @@
1014 autosetup-error "use: No such module: $m"
1015 }
1016 }
1017 }
1018 }
 
 
 
 
 
 
 
 
 
 
 
 
1019
1020 # Load module source in the global scope by executing the given command
1021 proc automf_load {args} {
1022 if {[catch [list uplevel #0 $args] msg opts] ni {0 2 3}} {
1023 autosetup-full-error [error-dump $msg $opts $::autosetup(debug)]
@@ -1027,18 +1225,21 @@
1027 # Initial settings
1028 set autosetup(exe) $::argv0
1029 set autosetup(istcl) 1
1030 set autosetup(start) [clock millis]
1031 set autosetup(installed) 0
 
1032 set autosetup(msg-checking) 0
1033 set autosetup(msg-quiet) 0
 
1034
1035 # Embedded modules are inserted below here
1036 set autosetup(installed) 1
1037 # ----- module asciidoc-formatting -----
 
1038
1039 set modsource(asciidoc-formatting) {
1040 # Copyright (c) 2010 WorkWare Systems http://www.workware.net.au/
1041 # All rights reserved
1042
1043 # Module which provides text formatting
1044 # asciidoc format
@@ -1102,19 +1303,19 @@
1102 regsub -all "\n\n" $defn "\n ::\n" defn
1103 puts $defn
1104 }
1105 }
1106
1107 # ----- module formatting -----
1108
1109 set modsource(formatting) {
1110 # Copyright (c) 2010 WorkWare Systems http://www.workware.net.au/
1111 # All rights reserved
1112
1113 # Module which provides common text formatting
1114
1115 # This is designed for documenation which looks like:
1116 # code {...}
1117 # or
1118 # code {
1119 # ...
1120 # ...
@@ -1159,13 +1360,13 @@
1159 # Return the result
1160 return $lines
1161 }
1162 }
1163
1164 # ----- module getopt -----
1165
1166 set modsource(getopt) {
1167 # Copyright (c) 2006 WorkWare Systems http://www.workware.net.au/
1168 # All rights reserved
1169
1170 # Simple getopt module
1171
@@ -1197,11 +1398,11 @@
1197
1198 if {[regexp {^--([^=][^=]+)=(.*)$} $arg -> name value]} {
1199 # --name=value
1200 dict lappend opts $name [list str $value]
1201 } elseif {[regexp {^--(enable-|disable-)?([^=]*)$} $arg -> prefix name]} {
1202 if {$prefix in {enable- with- ""}} {
1203 set value 1
1204 } else {
1205 set value 0
1206 }
1207 dict lappend opts $name [list bool $value]
@@ -1218,13 +1419,13 @@
1218
1219 return $opts
1220 }
1221 }
1222
1223 # ----- module help -----
1224
1225 set modsource(help) {
1226 # Copyright (c) 2010 WorkWare Systems http://workware.net.au/
1227 # All rights reserved
1228
1229 # Module which provides usage, help and the command reference
1230
@@ -1251,10 +1452,28 @@
1251 options-show
1252 }
1253 }
1254 exit 0
1255 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1256
1257 # If not already paged and stdout is a tty, pipe the output through the pager
1258 # This is done by reinvoking autosetup with --nopager added
1259 proc use_pager {} {
1260 if {![opt-bool nopager] && [getenv PAGER ""] ne "" && [isatty? stdin] && [isatty? stdout]} {
@@ -1304,10 +1523,16 @@
1304 }
1305
1306 proc autosetup_output_block {type lines} {
1307 if {[llength $lines]} {
1308 switch $type {
 
 
 
 
 
 
1309 code {
1310 codelines $lines
1311 }
1312 p {
1313 p [join $lines]
@@ -1325,30 +1550,45 @@
1325 # Generate a command reference from inline documentation
1326 proc automf_command_reference {} {
1327 lappend files $::autosetup(prog)
1328 lappend files {*}[lsort [glob -nocomplain $::autosetup(libdir)/*.tcl]]
1329
1330 section "Core Commands"
1331 set type p
1332 set lines {}
1333 set cmd {}
 
 
 
 
 
 
 
1334
1335 foreach file $files {
 
 
1336 set f [open $file]
1337 while {![eof $f]} {
1338 set line [gets $f]
 
 
 
 
 
1339
1340 # Find lines starting with "# @*" and continuing through the remaining comment lines
1341 if {![regexp {^# @(.*)} $line -> cmd]} {
1342 continue
1343 }
1344
1345 # Synopsis or command?
1346 if {$cmd eq "synopsis:"} {
1347 section "Module: [file rootname [file tail $file]]"
 
1348 } else {
1349 subsection $cmd
1350 }
1351
1352 set lines {}
1353 set type p
1354
@@ -1369,29 +1609,38 @@
1369
1370 #puts "hash=$hash, oldhash=$oldhash, lines=[llength $lines], cmd=$cmd"
1371
1372 if {$t ne $type || $cmd eq ""} {
1373 # Finish the current block
1374 autosetup_output_block $type $lines
1375 set lines {}
1376 set type $t
1377 }
1378 if {$cmd ne ""} {
1379 lappend lines $cmd
1380 }
1381 }
1382
1383 autosetup_output_block $type $lines
1384 }
1385 close $f
1386 }
 
 
 
 
 
 
 
 
 
1387 }
1388 }
1389
1390 # ----- module init -----
1391
1392 set modsource(init) {
1393 # Copyright (c) 2010 WorkWare Systems http://www.workware.net.au/
1394 # All rights reserved
1395
1396 # Module to help create auto.def and configure
1397
@@ -1444,79 +1693,157 @@
1444 }
1445 writefile $filename $contents
1446 }
1447 }
1448
1449 # ----- module install -----
1450
1451 set modsource(install) {
1452 # Copyright (c) 2006-2010 WorkWare Systems http://www.workware.net.au/
1453 # All rights reserved
1454
1455 # Module which can install autosetup
1456
1457 proc autosetup_install {dir} {
1458 if {[catch {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1459 cd $dir
 
 
 
 
1460 file mkdir autosetup
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1461
1462 set f [open autosetup/autosetup w]
1463
1464 set publicmodules [glob $::autosetup(libdir)/*.auto]
1465
1466 # First the main script, but only up until "CUT HERE"
1467 set in [open $::autosetup(dir)/autosetup]
1468 while {[gets $in buf] >= 0} {
1469 if {$buf ne "##-- CUT HERE --##"} {
1470 puts $f $buf
1471 continue
1472 }
1473
1474 # Insert the static modules here
1475 # i.e. those which don't contain @synopsis:
 
1476 puts $f "set autosetup(installed) 1"
1477 foreach file [lsort [glob $::autosetup(libdir)/*.tcl]] {
 
 
 
1478 set buf [readfile $file]
1479 if {[string match "*\n# @synopsis:*" $buf]} {
1480 lappend publicmodules $file
1481 continue
 
 
1482 }
1483 set modname [file rootname [file tail $file]]
1484 puts $f "# ----- module $modname -----"
1485 puts $f "\nset modsource($modname) \{"
1486 puts $f $buf
1487 puts $f "\}\n"
1488 }
 
 
 
 
 
 
 
1489 }
1490 close $in
1491 close $f
1492 exec chmod 755 autosetup/autosetup
 
 
 
 
 
 
1493
1494 # Install public modules
1495 foreach file $publicmodules {
1496 autosetup_install_file $file autosetup
 
 
 
 
 
 
1497 }
1498
1499 # Install support files
1500 foreach file {config.guess config.sub jimsh0.c find-tclsh test-tclsh LICENSE} {
1501 autosetup_install_file $::autosetup(dir)/$file autosetup
1502 }
1503 exec chmod 755 autosetup/config.sub autosetup/config.guess autosetup/find-tclsh
1504
1505 writefile autosetup/README.autosetup \
1506 "This is [autosetup_version]. See http://msteveb.github.com/autosetup/\n"
1507
 
 
 
 
 
 
 
 
1508 } error]} {
1509 user-error "Failed to install autosetup: $error"
1510 }
1511 puts "Installed [autosetup_version] to autosetup/"
 
 
 
 
 
1512
1513 # Now create 'configure' if necessary
1514 autosetup_create_configure
 
 
1515 }
1516
1517 proc autosetup_create_configure {} {
1518 if {[file exists configure]} {
1519 if {!$::autosetup(force)} {
1520 # Could this be an autosetup configure?
1521 if {![string match "*\nWRAPPER=*" [readfile configure]]} {
1522 puts "I see configure, but not created by autosetup, so I won't overwrite it."
@@ -1527,40 +1854,75 @@
1527 puts "I will overwrite the existing configure because you used --force."
1528 }
1529 } else {
1530 puts "I don't see configure, so I will create it."
1531 }
1532 writefile configure \
 
 
 
 
 
 
1533 {#!/bin/sh
1534 dir="`dirname "$0"`/autosetup"
1535 WRAPPER="$0"; export WRAPPER; exec "`$dir/find-tclsh`" "$dir/autosetup" "$@"
1536 }
 
1537 catch {exec chmod 755 configure}
1538 }
1539
1540 # Append the contents of $file to filehandle $f
1541 proc autosetup_install_append {f file} {
 
1542 set in [open $file]
1543 puts $f [read $in]
1544 close $in
1545 }
1546
1547 proc autosetup_install_file {file dir} {
1548 if {![file exists $file]} {
1549 error "Missing installation file '$file'"
1550 }
1551 writefile [file join $dir [file tail $file]] [readfile $file]\n
1552 }
1553
1554 if {$::autosetup(installed)} {
1555 user-error "autosetup can only be installed from development source, not from installed copy"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1556 }
1557 }
1558
1559 # ----- module markdown-formatting -----
1560
1561 set modsource(markdown-formatting) {
1562 # Copyright (c) 2010 WorkWare Systems http://www.workware.net.au/
1563 # All rights reserved
1564
1565 # Module which provides text formatting
1566 # markdown format (kramdown syntax)
@@ -1627,13 +1989,13 @@
1627 }
1628 puts "$defn"
1629 }
1630 }
1631
1632 # ----- module misc -----
1633
1634 set modsource(misc) {
1635 # Copyright (c) 2007-2010 WorkWare Systems http://www.workware.net.au/
1636 # All rights reserved
1637
1638 # Module containing misc procs useful to modules
1639 # Largely for platform compatibility
@@ -1805,106 +2167,218 @@
1805 string trim $result
1806 }
1807 }
1808 }
1809
1810 # ----- module text-formatting -----
1811
1812 set modsource(text-formatting) {
1813 # Copyright (c) 2010 WorkWare Systems http://www.workware.net.au/
1814 # All rights reserved
1815
1816 # Module which provides text formatting
1817
1818 use formatting
1819
1820 proc wordwrap {text length {firstprefix ""} {nextprefix ""}} {
1821 set len 0
1822 set space $firstprefix
1823 foreach word [split $text] {
1824 set word [string trim $word]
1825 if {$word == ""} {
1826 continue
1827 }
1828 if {$len && [string length $space$word] + $len >= $length} {
1829 puts ""
1830 set len 0
1831 set space $nextprefix
1832 }
1833 incr len [string length $space$word]
1834
1835 # Use man-page conventions for highlighting 'quoted' and *quoted*
1836 # single words.
1837 # Use x^Hx for *bold* and _^Hx for 'underline'.
1838 #
1839 # less and more will both understand this.
1840 # Pipe through 'col -b' to remove them.
1841 if {[regexp {^'(.*)'([^a-zA-Z0-9_]*)$} $word -> bareword dot]} {
1842 regsub -all . $bareword "_\b&" word
1843 append word $dot
1844 } elseif {[regexp {^[*](.*)[*]([^a-zA-Z0-9_]*)$} $word -> bareword dot]} {
1845 regsub -all . $bareword "&\b&" word
1846 append word $dot
1847 }
1848 puts -nonewline $space$word
1849 set space " "
1850 }
1851 if {$len} {
1852 puts ""
1853 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1854 }
1855 proc title {text} {
1856 underline [string trim $text] =
1857 nl
1858 }
1859 proc p {text} {
1860 wordwrap $text 80
1861 nl
1862 }
1863 proc codelines {lines} {
1864 foreach line $lines {
1865 puts " $line"
1866 }
1867 nl
1868 }
1869 proc nl {} {
1870 puts ""
1871 }
1872 proc underline {text char} {
1873 regexp "^(\[ \t\]*)(.*)" $text -> indent words
1874 puts $text
1875 puts $indent[string repeat $char [string length $words]]
1876 }
1877 proc section {text} {
1878 underline "[string trim $text]" -
1879 nl
1880 }
1881 proc subsection {text} {
1882 underline "$text" ~
1883 nl
1884 }
1885 proc bullet {text} {
1886 wordwrap $text 76 " * " " "
1887 }
1888 proc indent {text} {
1889 wordwrap $text 76 " " " "
1890 }
1891 proc defn {first args} {
1892 if {$first ne ""} {
1893 underline " $first" ~
1894 }
1895 foreach p $args {
1896 if {$p ne ""} {
1897 indent $p
1898 }
1899 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1900 }
1901 }
1902
1903 # ----- module wiki-formatting -----
1904
1905 set modsource(wiki-formatting) {
1906 # Copyright (c) 2010 WorkWare Systems http://www.workware.net.au/
1907 # All rights reserved
1908
1909 # Module which provides text formatting
1910 # wiki.tcl.tk format output
@@ -1975,11 +2449,11 @@
1975 if {$autosetup(debug)} {
1976 main $argv
1977 }
1978 if {[catch {main $argv} msg opts] == 1} {
1979 show-notices
1980 autosetup-full-error [error-dump $msg $opts $::autosetup(debug)]
1981 if {!$autosetup(debug)} {
1982 puts stderr "Try: '[file tail $autosetup(exe)] --debug' for a full stack trace"
1983 }
1984 exit 1
1985 }
1986
1987 DDED autosetup/autosetup-config.guess
1988 DDED autosetup/autosetup-config.sub
1989 DDED autosetup/autosetup-find-tclsh
1990 DDED autosetup/autosetup-test-tclsh
--- autosetup/autosetup
+++ autosetup/autosetup
@@ -1,16 +1,17 @@
1 #!/bin/sh
2 # Copyright (c) 2006-2011 WorkWare Systems http://www.workware.net.au/
3 # All rights reserved
4 # vim:se syntax=tcl:
5 # \
6 dir=`dirname "$0"`; exec "`$dir/autosetup-find-tclsh`" "$0" "$@"
7
8 # Note that the version has a trailing + on unreleased versions
9 set autosetup(version) 0.6.9
10
11 # Can be set to 1 to debug early-init problems
12 set autosetup(debug) [expr {"--debug" in $argv}]
13
14 ##################################################################
15 #
16 # Main flow of control, option handling
17 #
@@ -72,14 +73,18 @@
73 set autosetup(cmdline) {}
74 # options is a list of known options
75 set autosetup(options) {}
76 # optset is a dictionary of option values set by the user based on getopt
77 set autosetup(optset) {}
78 # optdefault is a dictionary of default values
79 set autosetup(optdefault) {}
80 # options-defaults is a dictionary of overrides for default values for options
81 set autosetup(options-defaults) {}
82 set autosetup(optionhelp) {}
83 set autosetup(showhelp) 0
84
85 use util
86
87 # Parse options
88 use getopt
89
90 # At the is point we don't know what is a valid option
@@ -87,15 +92,28 @@
92 set autosetup(getopt) [getopt argv]
93
94 #"=Core Options:"
95 options-add {
96 help:=local => "display help and options. Optionally specify a module name, such as --help=system"
97 licence license => "display the autosetup license"
98 version => "display the version of autosetup"
99 ref:=text manual:=text
100 reference:=text => "display the autosetup command reference. 'text', 'wiki', 'asciidoc' or 'markdown'"
101 debug => "display debugging output as autosetup runs"
102 install:=. => "install autosetup to the current or given directory"
103 }
104 if {$autosetup(installed)} {
105 # hidden options so we can produce a nice error
106 options-add {
107 sysinstall:path
108 }
109 } else {
110 options-add {
111 sysinstall:path => "install standalone autosetup to the given directory (e.g.: /usr/local)"
112 }
113 }
114 options-add {
115 force init:=help => "create initial auto.def, etc. Use --init=help for known types"
116 # Undocumented options
117 option-checking=1
118 nopager
119 quiet
@@ -107,12 +125,12 @@
125 puts $autosetup(version)
126 exit 0
127 }
128
129 # autosetup --conf=alternate-auto.def
130 if {[opt-str conf o]} {
131 set autosetup(autodef) $o
132 }
133
134 # Debugging output (set this early)
135 incr autosetup(debug) [opt-bool debug]
136 incr autosetup(force) [opt-bool force]
@@ -124,41 +142,50 @@
142 if {[file exists $autosetup(libdir)/local.tcl]} {
143 use local
144 }
145
146 # Now any auto-load modules
147 autosetup_load_auto_modules
 
 
148
149 if {[opt-str help o]} {
150 incr autosetup(showhelp)
151 use help
152 autosetup_help $o
153 }
154
155 if {[opt-bool licence license]} {
156 use help
157 autosetup_show_license
158 exit 0
159 }
160
161 if {[opt-str {manual ref reference} o]} {
162 use help
163 autosetup_reference $o
164 }
165
166 # Allow combining --install and --init
167 set earlyexit 0
168 if {[opt-str install o]} {
169 use install
170 autosetup_install $o
171 incr earlyexit
172 }
173
174 if {[opt-str init o]} {
175 use init
176 autosetup_init $o
177 incr earlyexit
178 }
179
180 if {$earlyexit} {
181 exit 0
182 }
183 if {[opt-str sysinstall o]} {
184 use install
185 autosetup_install $o 1
186 exit 0
187 }
188
189 if {![file exists $autosetup(autodef)]} {
190 # Check for invalid option first
191 options {}
@@ -185,10 +212,11 @@
212 define-append AUTOREMAKE [get-define CONFIGURE_OPTS]
213
214
215 # Log how we were invoked
216 configlog "Invoked as: [getenv WRAPPER $::argv0] [quote-argv $autosetup(argv)]"
217 configlog "Tclsh: [info nameofexecutable]"
218
219 # Note that auto.def is *not* loaded in the global scope
220 source $autosetup(autodef)
221
222 # Could warn here if options {} was not specified
@@ -210,14 +238,14 @@
238 #
239 # Check each of the named, boolean options and if any have been explicitly enabled
240 # or disabled by the user, return 1 or 0 accordingly.
241 #
242 # If the option was specified more than once, the last value wins.
243 # e.g. With '--enable-foo --disable-foo', '[opt-bool foo]' will return 0
244 #
245 # If no value was specified by the user, returns the default value for the
246 # first option. If '-nodefault' is given, this behaviour changes and
247 # -1 is returned instead.
248 #
249 proc opt-bool {args} {
250 set nodefault 0
251 if {[lindex $args 0] eq "-nodefault"} {
@@ -237,20 +265,19 @@
265 }
266 # Default value is the default for the first option
267 return [dict get $::autosetup(optdefault) [lindex $args 0]]
268 }
269
270 # @opt-val optionlist ?default=""?
271 #
272 # Returns a list containing all the values given for the non-boolean options in '$optionlist'.
273 # There will be one entry in the list for each option given by the user, including if the
274 # same option was used multiple times.
 
275 #
276 # If no options were set, '$default' is returned (exactly, not as a list).
277 #
278 # Note: For most use cases, 'opt-str' should be preferred.
279 #
280 proc opt-val {names {default ""}} {
281 option-check-names {*}$names
282
283 foreach opt $names {
@@ -261,10 +288,83 @@
288 if {[info exists result]} {
289 return $result
290 }
291 return $default
292 }
293
294 # @opt-str optionlist varname ?default?
295 #
296 # Sets '$varname' in the callers scope to the value for one of the given options.
297 #
298 # For the list of options given in '$optionlist', if any value is set for any option,
299 # the option value is taken to be the *last* value of the last option (in the order given).
300 #
301 # If no option was given, and a default was specified with 'options-defaults',
302 # that value is used.
303 #
304 # If no 'options-defaults' value was given and '$default' was given, it is used.
305 #
306 # If none of the above provided a value, no value is set.
307 #
308 # The return value depends on whether '$default' was specified.
309 # If it was, the option value is returned.
310 # If it was not, 1 is returns if a value was set, or 0 if not.
311 #
312 # Typical usage is as follows:
313 #
314 ## if {[opt-str {myopt altname} o]} {
315 ## do something with $o
316 ## }
317 #
318 # Or:
319 ## define myname [opt-str {myopt altname} o "/usr/local"]
320 #
321 proc opt-str {names varname args} {
322 global autosetup
323
324 option-check-names {*}$names
325 upvar $varname value
326
327 if {[llength $args]} {
328 # A default was given, so always return the string value of the option
329 set default [lindex $args 0]
330 set retopt 1
331 } else {
332 # No default, so return 0 or 1 to indicate if a value was found
333 set retopt 0
334 }
335
336 foreach opt $names {
337 if {[dict exists $::autosetup(optset) $opt]} {
338 set result [lindex [dict get $::autosetup(optset) $opt] end]
339 }
340 }
341
342 if {![info exists result]} {
343 # No user-specified value. Has options-defaults been set?
344 foreach opt $names {
345 if {[dict exists $::autosetup(options-defaults) $opt]} {
346 set result [dict get $autosetup(options-defaults) $opt]
347 }
348 }
349 }
350
351 if {[info exists result]} {
352 set value $result
353 if {$retopt} {
354 return $value
355 }
356 return 1
357 }
358
359 if {$retopt} {
360 set value $default
361 return $value
362 }
363
364 return 0
365 }
366
367 proc option-check-names {args} {
368 foreach o $args {
369 if {$o ni $::autosetup(options)} {
370 autosetup-error "Request for undeclared option --$o"
@@ -293,10 +393,11 @@
393 # This is a special heading
394 lappend autosetup(optionhelp) $opt ""
395 set header {}
396 continue
397 }
398 unset -nocomplain defaultvalue equal value
399
400 #puts "i=$i, opt=$opt"
401 regexp {^([^:=]*)(:)?(=)?(.*)$} $opt -> name colon equal value
402 if {$name in $autosetup(options)} {
403 autosetup-error "Option $name already specified"
@@ -310,10 +411,16 @@
411 # This is a documentation-only option, like "-C <dir>"
412 set opthelp $opt
413 } elseif {$colon eq ""} {
414 # Boolean option
415 lappend autosetup(options) $name
416
417 # Check for override
418 if {[dict exists $autosetup(options-defaults) $name]} {
419 # A default was specified with options-defaults, so use it
420 set value [dict get $autosetup(options-defaults) $name]
421 }
422
423 if {$value eq "1"} {
424 set opthelp "--disable-$name"
425 } else {
426 set opthelp "--$name"
@@ -321,11 +428,12 @@
428
429 # Set the default
430 if {$value eq ""} {
431 set value 0
432 }
433 set defaultvalue $value
434 dict set autosetup(optdefault) $name $defaultvalue
435
436 if {[dict exists $autosetup(getopt) $name]} {
437 # The option was specified by the user. Look at the last value.
438 lassign [lindex [dict get $autosetup(getopt) $name] end] type setvalue
439 if {$type eq "str"} {
@@ -342,19 +450,39 @@
450 #puts "Found boolean option --$name=$setvalue"
451 }
452 } else {
453 # String option.
454 lappend autosetup(options) $name
455
456 if {$colon eq ":"} {
457 # Was ":name=default" given?
458 # If so, set $value to the display name and $defaultvalue to the default
459 # (This is the preferred way to set a default value for a string option)
460 if {[regexp {^([^=]+)=(.*)$} $value -> value defaultvalue]} {
461 dict set autosetup(optdefault) $name $defaultvalue
462 }
463 }
464
465 # Maybe override the default value
466 if {[dict exists $autosetup(options-defaults) $name]} {
467 # A default was specified with options-defaults, so use it
468 set defaultvalue [dict get $autosetup(options-defaults) $name]
469 dict set autosetup(optdefault) $name $defaultvalue
470 } elseif {![info exists defaultvalue]} {
471 # For backward compatibility, if ":name" was given, use name as both
472 # the display text and the default value, but only if the user
473 # specified the option without the value
474 set defaultvalue $value
475 }
476
477 if {$equal eq "="} {
478 # String option with optional value
479 set opthelp "--$name?=$value?"
480 } else {
481 # String option with required value
482 set opthelp "--$name=$value"
483 }
 
484
485 # Get the values specified by the user
486 if {[dict exists $autosetup(getopt) $name]} {
487 set listvalue {}
488
@@ -363,11 +491,11 @@
491 if {$type eq "bool" && $setvalue} {
492 if {$equal ne "="} {
493 user-error "Option --$name requires a value"
494 }
495 # If given as a boolean, use the default value
496 set setvalue $defaultvalue
497 }
498 lappend listvalue $setvalue
499 }
500
501 #puts "Found string option --$name=$listvalue"
@@ -376,10 +504,13 @@
504 }
505
506 # Now create the help for this option if appropriate
507 if {[lindex $opts $i+1] eq "=>"} {
508 set desc [lindex $opts $i+2]
509 if {[info exists defaultvalue]} {
510 set desc [string map [list @default@ $defaultvalue] $desc]
511 }
512 #string match \n* $desc
513 if {$header ne ""} {
514 lappend autosetup(optionhelp) $header ""
515 set header ""
516 }
@@ -463,35 +594,39 @@
594 options-wrap-desc [string trim $desc] $cols " " $indent [expr $max + 2]
595 }
596 }
597 }
598
599 # @options optionspec
600 #
601 # Specifies configuration-time options which may be selected by the user
602 # and checked with 'opt-str' and 'opt-bool'. '$optionspec' contains a series
603 # of options specifications separated by newlines, as follows:
604 #
605 # A boolean option is of the form:
606 #
607 ## name[=0|1] => "Description of this boolean option"
608 #
609 # The default is 'name=0', meaning that the option is disabled by default.
610 # If 'name=1' is used to make the option enabled by default, the description should reflect
611 # that with text like "Disable support for ...".
612 #
613 # An argument option (one which takes a parameter) is of the form:
614 #
615 ## name:[=]value => "Description of this option"
616 #
617 # If the 'name:value' form is used, the value must be provided with the option (as '--name=myvalue').
618 # If the 'name:=value' form is used, the value is optional and the given value is used as the default
619 # if it is not provided.
620 #
621 # The description may contain '@default@', in which case it will be replaced with the default
622 # value for the option (taking into account defaults specified with 'options-defaults'.
623 #
624 # Undocumented options are also supported by omitting the '=> description'.
625 # These options are not displayed with '--help' and can be useful for internal options or as aliases.
626 #
627 # For example, '--disable-lfs' is an alias for '--disable=largefile':
628 #
629 ## lfs=1 largefile=1 => "Disable large file support"
630 #
631 proc options {optlist} {
632 # Allow options as a list or args
@@ -509,27 +644,37 @@
644 user-error "Unknown option --$o"
645 }
646 }
647 }
648 }
649
650 # @options-defaults dictionary
651 #
652 # Specifies a dictionary of options and a new default value for each of those options.
653 # Use before any 'use' statements in 'auto.def' to change the defaults for
654 # subsequently included modules.
655 proc options-defaults {dict} {
656 foreach {n v} $dict {
657 dict set ::autosetup(options-defaults) $n $v
658 }
659 }
660
661 proc config_guess {} {
662 if {[file-isexec $::autosetup(dir)/autosetup-config.guess]} {
663 if {[catch {exec-with-stderr sh $::autosetup(dir)/autosetup-config.guess} alias]} {
 
664 user-error $alias
665 }
666 return $alias
667 } else {
668 configlog "No autosetup-config.guess, so using uname"
669 string tolower [exec uname -p]-unknown-[exec uname -s][exec uname -r]
670 }
671 }
672
673 proc config_sub {alias} {
674 if {[file-isexec $::autosetup(dir)/autosetup-config.sub]} {
675 if {[catch {exec-with-stderr sh $::autosetup(dir)/autosetup-config.sub $alias} alias]} {
676 user-error $alias
677 }
678 }
679 return $alias
680 }
@@ -536,39 +681,48 @@
681
682 # @define name ?value=1?
683 #
684 # Defines the named variable to the given value.
685 # These (name, value) pairs represent the results of the configuration check
686 # and are available to be subsequently checked, modified and substituted.
687 #
688 proc define {name {value 1}} {
689 set ::define($name) $value
690 #dputs "$name <= $value"
691 }
692
693 # @undefine name
694 #
695 # Undefine the named variable.
696 #
697 proc undefine {name} {
698 unset -nocomplain ::define($name)
699 #dputs "$name <= <undef>"
700 }
701
702 # @define-append name value ...
703 #
704 # Appends the given value(s) to the given "defined" variable.
705 # If the variable is not defined or empty, it is set to '$value'.
706 # Otherwise the value is appended, separated by a space.
707 # Any extra values are similarly appended.
708 # If any value is already contained in the variable (as a substring) it is omitted.
709 #
710 proc define-append {name args} {
711 if {[get-define $name ""] ne ""} {
712 # Avoid duplicates
713 foreach arg $args {
714 if {$arg eq ""} {
715 continue
716 }
717 set found 0
718 foreach str [split $::define($name) " "] {
719 if {$str eq $arg} {
720 incr found
721 }
722 }
723 if {!$found} {
724 append ::define($name) " " $arg
725 }
726 }
727 } else {
728 set ::define($name) [join $args]
@@ -576,11 +730,11 @@
730 #dputs "$name += [join $args] => $::define($name)"
731 }
732
733 # @get-define name ?default=0?
734 #
735 # Returns the current value of the "defined" variable, or '$default'
736 # if not set.
737 #
738 proc get-define {name {default 0}} {
739 if {[info exists ::define($name)]} {
740 #dputs "$name => $::define($name)"
@@ -595,14 +749,26 @@
749 # Returns 1 if the given variable is defined.
750 #
751 proc is-defined {name} {
752 info exists ::define($name)
753 }
754
755 # @is-define-set name
756 #
757 # Returns 1 if the given variable is defined and is set
758 # to a value other than "" or 0
759 #
760 proc is-define-set {name} {
761 if {[get-define $name] in {0 ""}} {
762 return 0
763 }
764 return 1
765 }
766
767 # @all-defines
768 #
769 # Returns a dictionary (name, value list) of all defined variables.
770 #
771 # This is suitable for use with 'dict', 'array set' or 'foreach'
772 # and allows for arbitrary processing of the defined variables.
773 #
774 proc all-defines {} {
@@ -610,13 +776,13 @@
776 }
777
778
779 # @get-env name default
780 #
781 # If '$name' was specified on the command line, return it.
782 # Otherwise if '$name' was set in the environment, return it.
783 # Otherwise return '$default'.
784 #
785 proc get-env {name default} {
786 if {[dict exists $::autosetup(cmdline) $name]} {
787 return [dict get $::autosetup(cmdline) $name]
788 }
@@ -623,11 +789,11 @@
789 getenv $name $default
790 }
791
792 # @env-is-set name
793 #
794 # Returns 1 if '$name' was specified on the command line or in the environment.
795 # Note that an empty environment variable is not considered to be set.
796 #
797 proc env-is-set {name} {
798 if {[dict exists $::autosetup(cmdline) $name]} {
799 return 1
@@ -639,11 +805,11 @@
805 }
806
807 # @readfile filename ?default=""?
808 #
809 # Return the contents of the file, without the trailing newline.
810 # If the file doesn't exist or can't be read, returns '$default'.
811 #
812 proc readfile {filename {default_value ""}} {
813 set result $default_value
814 catch {
815 set f [open $filename]
@@ -653,11 +819,11 @@
819 return $result
820 }
821
822 # @writefile filename value
823 #
824 # Creates the given file containing '$value'.
825 # Does not add an extra newline.
826 #
827 proc writefile {filename value} {
828 set f [open $filename w]
829 puts -nonewline $f $value
@@ -677,63 +843,60 @@
843 lappend args [quote-if-needed $arg]
844 }
845 join $args
846 }
847
848 # @list-non-empty list
849 #
850 # Returns a copy of the given list with empty elements removed
851 proc list-non-empty {list} {
 
 
 
 
852 set result {}
853 foreach p $list {
854 if {$p ne ""} {
855 lappend result $p
856 }
857 }
858 return $result
859 }
860
861 # @find-executable-path name
862 #
863 # Searches the path for an executable with the given name.
864 # Note that the name may include some parameters, e.g. 'cc -mbig-endian',
865 # in which case the parameters are ignored.
866 # The full path to the executable if found, or "" if not found.
867 # Returns 1 if found, or 0 if not.
868 #
869 proc find-executable-path {name} {
870 # Ignore any parameters
871 set name [lindex $name 0]
872 # The empty string is never a valid executable
873 if {$name ne ""} {
874 foreach p [split-path] {
875 dputs "Looking for $name in $p"
876 set exec [file join $p $name]
877 if {[file-isexec $exec]} {
878 dputs "Found $name -> $exec"
879 return $exec
880 }
881 }
882 }
883 return {}
884 }
885
886 # @find-executable name
887 #
888 # Searches the path for an executable with the given name.
889 # Note that the name may include some parameters, e.g. 'cc -mbig-endian',
890 # in which case the parameters are ignored.
891 # Returns 1 if found, or 0 if not.
892 #
893 proc find-executable {name} {
894 if {[find-executable-path $name] eq {}} {
895 return 0
896 }
897 return 1
 
 
 
 
 
 
 
 
 
 
 
898 }
899
900 # @find-an-executable ?-required? name ...
901 #
902 # Given a list of possible executable names,
@@ -764,11 +927,11 @@
927 return ""
928 }
929
930 # @configlog msg
931 #
932 # Writes the given message to the configuration log, 'config.log'.
933 #
934 proc configlog {msg} {
935 if {![info exists ::autosetup(logfh)]} {
936 set ::autosetup(logfh) [open config.log w]
937 }
@@ -800,12 +963,12 @@
963 }
964 }
965
966 # @msg-quiet command ...
967 #
968 # 'msg-quiet' evaluates it's arguments as a command with output
969 # from 'msg-checking' and 'msg-result' suppressed.
970 #
971 # This is useful if a check needs to run a subcheck which isn't
972 # of interest to the user.
973 proc msg-quiet {args} {
974 incr ::autosetup(msg-quiet)
@@ -841,11 +1004,11 @@
1004
1005 # @user-error msg
1006 #
1007 # Indicate incorrect usage to the user, including if required components
1008 # or features are not found.
1009 # 'autosetup' exits with a non-zero return code.
1010 #
1011 proc user-error {msg} {
1012 show-notices
1013 puts stderr "Error: $msg"
1014 puts stderr "Try: '[file tail $::autosetup(exe)] --help' for options"
@@ -887,10 +1050,21 @@
1050 proc maybe-show-timestamp {} {
1051 if {$::autosetup(msg-timing) && $::autosetup(msg-checking) == 0} {
1052 puts -nonewline [format {[%6.2f] } [expr {([clock millis] - $::autosetup(start)) % 10000 / 1000.0}]]
1053 }
1054 }
1055
1056 # @autosetup-require-version required
1057 #
1058 # Checks the current version of 'autosetup' against '$required'.
1059 # A fatal error is generated if the current version is less than that required.
1060 #
1061 proc autosetup-require-version {required} {
1062 if {[compare-versions $::autosetup(version) $required] < 0} {
1063 user-error "autosetup version $required is required, but this is $::autosetup(version)"
1064 }
1065 }
1066
1067 proc autosetup_version {} {
1068 return "autosetup v$::autosetup(version)"
1069 }
1070
@@ -986,23 +1160,35 @@
1160 # The latter form is useful for a complex module which requires additional
1161 # support file. In this form, '$::usedir' is set to the module directory
1162 # when it is loaded.
1163 #
1164 proc use {args} {
1165 global autosetup libmodule modsource
1166
1167 set dirs [list $autosetup(libdir)]
1168 if {[info exists autosetup(srcdir)]} {
1169 lappend dirs $autosetup(srcdir)/autosetup
1170 }
1171 foreach m $args {
1172 if {[info exists libmodule($m)]} {
1173 continue
1174 }
1175 set libmodule($m) 1
1176 if {[info exists modsource(${m}.tcl)]} {
1177 automf_load eval $modsource(${m}.tcl)
1178 } else {
1179 set locs [list ${m}.tcl ${m}/init.tcl]
1180 set found 0
1181 foreach dir $dirs {
1182 foreach loc $locs {
1183 set source $dir/$loc
1184 if {[file exists $source]} {
1185 incr found
1186 break
1187 }
1188 }
1189 if {$found} {
1190 break
1191 }
1192 }
1193 if {$found} {
1194 # For the convenience of the "use" source, point to the directory
@@ -1014,10 +1200,22 @@
1200 autosetup-error "use: No such module: $m"
1201 }
1202 }
1203 }
1204 }
1205
1206 proc autosetup_load_auto_modules {} {
1207 global autosetup modsource
1208 # First load any embedded auto modules
1209 foreach mod [array names modsource *.auto] {
1210 automf_load eval $modsource($mod)
1211 }
1212 # Now any external auto modules
1213 foreach file [glob -nocomplain $autosetup(libdir)/*.auto $autosetup(libdir)/*/*.auto] {
1214 automf_load source $file
1215 }
1216 }
1217
1218 # Load module source in the global scope by executing the given command
1219 proc automf_load {args} {
1220 if {[catch [list uplevel #0 $args] msg opts] ni {0 2 3}} {
1221 autosetup-full-error [error-dump $msg $opts $::autosetup(debug)]
@@ -1027,18 +1225,21 @@
1225 # Initial settings
1226 set autosetup(exe) $::argv0
1227 set autosetup(istcl) 1
1228 set autosetup(start) [clock millis]
1229 set autosetup(installed) 0
1230 set autosetup(sysinstall) 0
1231 set autosetup(msg-checking) 0
1232 set autosetup(msg-quiet) 0
1233 set autosetup(inittypes) {}
1234
1235 # Embedded modules are inserted below here
1236 set autosetup(installed) 1
1237 set autosetup(sysinstall) 0
1238 # ----- @module asciidoc-formatting.tcl -----
1239
1240 set modsource(asciidoc-formatting.tcl) {
1241 # Copyright (c) 2010 WorkWare Systems http://www.workware.net.au/
1242 # All rights reserved
1243
1244 # Module which provides text formatting
1245 # asciidoc format
@@ -1102,19 +1303,19 @@
1303 regsub -all "\n\n" $defn "\n ::\n" defn
1304 puts $defn
1305 }
1306 }
1307
1308 # ----- @module formatting.tcl -----
1309
1310 set modsource(formatting.tcl) {
1311 # Copyright (c) 2010 WorkWare Systems http://www.workware.net.au/
1312 # All rights reserved
1313
1314 # Module which provides common text formatting
1315
1316 # This is designed for documentation which looks like:
1317 # code {...}
1318 # or
1319 # code {
1320 # ...
1321 # ...
@@ -1159,13 +1360,13 @@
1360 # Return the result
1361 return $lines
1362 }
1363 }
1364
1365 # ----- @module getopt.tcl -----
1366
1367 set modsource(getopt.tcl) {
1368 # Copyright (c) 2006 WorkWare Systems http://www.workware.net.au/
1369 # All rights reserved
1370
1371 # Simple getopt module
1372
@@ -1197,11 +1398,11 @@
1398
1399 if {[regexp {^--([^=][^=]+)=(.*)$} $arg -> name value]} {
1400 # --name=value
1401 dict lappend opts $name [list str $value]
1402 } elseif {[regexp {^--(enable-|disable-)?([^=]*)$} $arg -> prefix name]} {
1403 if {$prefix in {enable- ""}} {
1404 set value 1
1405 } else {
1406 set value 0
1407 }
1408 dict lappend opts $name [list bool $value]
@@ -1218,13 +1419,13 @@
1419
1420 return $opts
1421 }
1422 }
1423
1424 # ----- @module help.tcl -----
1425
1426 set modsource(help.tcl) {
1427 # Copyright (c) 2010 WorkWare Systems http://workware.net.au/
1428 # All rights reserved
1429
1430 # Module which provides usage, help and the command reference
1431
@@ -1251,10 +1452,28 @@
1452 options-show
1453 }
1454 }
1455 exit 0
1456 }
1457
1458 proc autosetup_show_license {} {
1459 global modsource autosetup
1460 use_pager
1461
1462 if {[info exists modsource(LICENSE)]} {
1463 puts $modsource(LICENSE)
1464 return
1465 }
1466 foreach dir [list $autosetup(libdir) $autosetup(srcdir)] {
1467 set path [file join $dir LICENSE]
1468 if {[file exists $path]} {
1469 puts [readfile $path]
1470 return
1471 }
1472 }
1473 puts "LICENSE not found"
1474 }
1475
1476 # If not already paged and stdout is a tty, pipe the output through the pager
1477 # This is done by reinvoking autosetup with --nopager added
1478 proc use_pager {} {
1479 if {![opt-bool nopager] && [getenv PAGER ""] ne "" && [isatty? stdin] && [isatty? stdout]} {
@@ -1304,10 +1523,16 @@
1523 }
1524
1525 proc autosetup_output_block {type lines} {
1526 if {[llength $lines]} {
1527 switch $type {
1528 section {
1529 section $lines
1530 }
1531 subsection {
1532 subsection $lines
1533 }
1534 code {
1535 codelines $lines
1536 }
1537 p {
1538 p [join $lines]
@@ -1325,30 +1550,45 @@
1550 # Generate a command reference from inline documentation
1551 proc automf_command_reference {} {
1552 lappend files $::autosetup(prog)
1553 lappend files {*}[lsort [glob -nocomplain $::autosetup(libdir)/*.tcl]]
1554
1555 # We want to process all non-module files before module files
1556 # and then modules in alphabetical order.
1557 # So examine all files and extract docs into doc($modulename) and doc(_core_)
1558 #
1559 # Each entry is a list of {type data} where $type is one of: section, subsection, code, list, p
1560 # and $data is a string for section, subsection or a list of text lines for other types.
1561
1562 # XXX: Should commands be in alphabetical order too? Currently they are in file order.
1563
1564 set doc(_core_) {}
1565 lappend doc(_core_) [list section "Core Commands"]
1566
1567 foreach file $files {
1568 set modulename [file rootname [file tail $file]]
1569 set current _core_
1570 set f [open $file]
1571 while {![eof $f]} {
1572 set line [gets $f]
1573
1574 # Find embedded module names
1575 if {[regexp {^#.*@module ([^ ]*)} $line -> modulename]} {
1576 continue
1577 }
1578
1579 # Find lines starting with "# @*" and continuing through the remaining comment lines
1580 if {![regexp {^# @(.*)} $line -> cmd]} {
1581 continue
1582 }
1583
1584 # Synopsis or command?
1585 if {$cmd eq "synopsis:"} {
1586 set current $modulename
1587 lappend doc($current) [list section "Module: $modulename"]
1588 } else {
1589 lappend doc($current) [list subsection $cmd]
1590 }
1591
1592 set lines {}
1593 set type p
1594
@@ -1369,29 +1609,38 @@
1609
1610 #puts "hash=$hash, oldhash=$oldhash, lines=[llength $lines], cmd=$cmd"
1611
1612 if {$t ne $type || $cmd eq ""} {
1613 # Finish the current block
1614 lappend doc($current) [list $type $lines]
1615 set lines {}
1616 set type $t
1617 }
1618 if {$cmd ne ""} {
1619 lappend lines $cmd
1620 }
1621 }
1622
1623 lappend doc($current) [list $type $lines]
1624 }
1625 close $f
1626 }
1627
1628 # Now format and output the results
1629
1630 # _core_ will sort first
1631 foreach module [lsort [array names doc]] {
1632 foreach item $doc($module) {
1633 autosetup_output_block {*}$item
1634 }
1635 }
1636 }
1637 }
1638
1639 # ----- @module init.tcl -----
1640
1641 set modsource(init.tcl) {
1642 # Copyright (c) 2010 WorkWare Systems http://www.workware.net.au/
1643 # All rights reserved
1644
1645 # Module to help create auto.def and configure
1646
@@ -1444,79 +1693,157 @@
1693 }
1694 writefile $filename $contents
1695 }
1696 }
1697
1698 # ----- @module install.tcl -----
1699
1700 set modsource(install.tcl) {
1701 # Copyright (c) 2006-2010 WorkWare Systems http://www.workware.net.au/
1702 # All rights reserved
1703
1704 # Module which can install autosetup
1705
1706 # autosetup(installed)=1 means that autosetup is not running from source
1707 # autosetup(sysinstall)=1 means that autosetup is running from a sysinstall version
1708 # shared=1 means that we are trying to do a sysinstall. This is only possible from the development source.
1709
1710 proc autosetup_install {dir {shared 0}} {
1711 global autosetup
1712 if {$shared} {
1713 if {$autosetup(installed) || $autosetup(sysinstall)} {
1714 user-error "Can only --sysinstall from development sources"
1715 }
1716 } elseif {$autosetup(installed) && !$autosetup(sysinstall)} {
1717 user-error "Can't --install from project install"
1718 }
1719
1720 if {$autosetup(sysinstall)} {
1721 # This is the sysinstall version, so install just uses references
1722 cd $dir
1723
1724 puts "[autosetup_version] creating configure to use system-installed autosetup"
1725 autosetup_create_configure 1
1726 puts "Creating autosetup/README.autosetup"
1727 file mkdir autosetup
1728 autosetup_install_readme autosetup/README.autosetup 1
1729 return
1730 }
1731
1732 if {[catch {
1733 if {$shared} {
1734 set target $dir/bin/autosetup
1735 set installedas $target
1736 } else {
1737 if {$dir eq "."} {
1738 set installedas autosetup
1739 } else {
1740 set installedas $dir/autosetup
1741 }
1742 cd $dir
1743 file mkdir autosetup
1744 set target autosetup/autosetup
1745 }
1746 set targetdir [file dirname $target]
1747 file mkdir $targetdir
1748
1749 set f [open $target w]
1750
1751 set publicmodules {}
1752
1753 # First the main script, but only up until "CUT HERE"
1754 set in [open $autosetup(dir)/autosetup]
1755 while {[gets $in buf] >= 0} {
1756 if {$buf ne "##-- CUT HERE --##"} {
1757 puts $f $buf
1758 continue
1759 }
1760
1761 # Insert the static modules here
1762 # i.e. those which don't contain @synopsis:
1763 # All modules are inserted if $shared is set
1764 puts $f "set autosetup(installed) 1"
1765 puts $f "set autosetup(sysinstall) $shared"
1766 foreach file [lsort [glob $autosetup(libdir)/*.{tcl,auto}]] {
1767 set modname [file tail $file]
1768 set ext [file ext $modname]
1769 set buf [readfile $file]
1770 if {!$shared} {
1771 if {$ext eq ".auto" || [string match "*\n# @synopsis:*" $buf]} {
1772 lappend publicmodules $file
1773 continue
1774 }
1775 }
1776 dputs "install: importing lib/[file tail $file]"
1777 puts $f "# ----- @module $modname -----"
1778 puts $f "\nset modsource($modname) \{"
1779 puts $f $buf
1780 puts $f "\}\n"
1781 }
1782 if {$shared} {
1783 foreach {srcname destname} [list $autosetup(libdir)/README.autosetup-lib README.autosetup \
1784 $autosetup(srcdir)/LICENSE LICENSE] {
1785 dputs "install: importing $srcname as $destname"
1786 puts $f "\nset modsource($destname) \\\n[list [readfile $srcname]\n]\n"
1787 }
1788 }
1789 }
1790 close $in
1791 close $f
1792 catch {exec chmod 755 $target}
1793
1794 set installfiles {autosetup-config.guess autosetup-config.sub autosetup-test-tclsh}
1795 set removefiles {}
1796
1797 if {!$shared} {
1798 autosetup_install_readme $targetdir/README.autosetup 0
1799
1800 # Install public modules
1801 foreach file $publicmodules {
1802 set tail [file tail $file]
1803 autosetup_install_file $file $targetdir/$tail
1804 }
1805 lappend installfiles jimsh0.c autosetup-find-tclsh LICENSE
1806 lappend removefiles config.guess config.sub test-tclsh find-tclsh
1807 } else {
1808 lappend installfiles {sys-find-tclsh autosetup-find-tclsh}
1809 }
1810
1811 # Install support files
1812 foreach fileinfo $installfiles {
1813 if {[llength $fileinfo] == 2} {
1814 lassign $fileinfo source dest
1815 } else {
1816 lassign $fileinfo source
1817 set dest $source
1818 }
1819 autosetup_install_file $autosetup(dir)/$source $targetdir/$dest
1820 }
1821
1822 # Remove obsolete files
1823 foreach file $removefiles {
1824 if {[file exists $targetdir/$file]} {
1825 file delete $targetdir/$file
1826 }
1827 }
1828 } error]} {
1829 user-error "Failed to install autosetup: $error"
1830 }
1831 if {$shared} {
1832 set type "system"
1833 } else {
1834 set type "local"
1835 }
1836 puts "Installed $type [autosetup_version] to $installedas"
1837
1838 if {!$shared} {
1839 # Now create 'configure' if necessary
1840 autosetup_create_configure 0
1841 }
1842 }
1843
1844 proc autosetup_create_configure {shared} {
1845 if {[file exists configure]} {
1846 if {!$::autosetup(force)} {
1847 # Could this be an autosetup configure?
1848 if {![string match "*\nWRAPPER=*" [readfile configure]]} {
1849 puts "I see configure, but not created by autosetup, so I won't overwrite it."
@@ -1527,40 +1854,75 @@
1854 puts "I will overwrite the existing configure because you used --force."
1855 }
1856 } else {
1857 puts "I don't see configure, so I will create it."
1858 }
1859 if {$shared} {
1860 writefile configure \
1861 {#!/bin/sh
1862 WRAPPER="$0"; export WRAPPER; "autosetup" "$@"
1863 }
1864 } else {
1865 writefile configure \
1866 {#!/bin/sh
1867 dir="`dirname "$0"`/autosetup"
1868 WRAPPER="$0"; export WRAPPER; exec "`"$dir/autosetup-find-tclsh"`" "$dir/autosetup" "$@"
1869 }
1870 }
1871 catch {exec chmod 755 configure}
1872 }
1873
1874 # Append the contents of $file to filehandle $f
1875 proc autosetup_install_append {f file} {
1876 dputs "install: include $file"
1877 set in [open $file]
1878 puts $f [read $in]
1879 close $in
1880 }
1881
1882 proc autosetup_install_file {source target} {
1883 dputs "install: $source => $target"
1884 if {![file exists $source]} {
1885 error "Missing installation file '$source'"
1886 }
1887 writefile $target [readfile $source]\n
1888 # If possible, copy the file mode
1889 file stat $source stat
1890 set mode [format %o [expr {$stat(mode) & 0x1ff}]]
1891 catch {exec chmod $mode $target}
1892 }
1893
1894 proc autosetup_install_readme {target sysinstall} {
1895 set readme "README.autosetup created by [autosetup_version]\n\n"
1896 if {$sysinstall} {
1897 append readme \
1898 {This is the autosetup directory for a system install of autosetup.
1899 Loadable modules can be added here.
1900 }
1901 } else {
1902 append readme \
1903 {This is the autosetup directory for a local install of autosetup.
1904 It contains autosetup, support files and loadable modules.
1905 }
1906 }
1907
1908 append readme {
1909 *.tcl files in this directory are optional modules which
1910 can be loaded with the 'use' directive.
1911
1912 *.auto files in this directory are auto-loaded.
1913
1914 For more information, see http://msteveb.github.com/autosetup/
1915 }
1916 dputs "install: autosetup/README.autosetup"
1917 writefile $target $readme
1918 }
1919 }
1920
1921 # ----- @module markdown-formatting.tcl -----
1922
1923 set modsource(markdown-formatting.tcl) {
1924 # Copyright (c) 2010 WorkWare Systems http://www.workware.net.au/
1925 # All rights reserved
1926
1927 # Module which provides text formatting
1928 # markdown format (kramdown syntax)
@@ -1627,13 +1989,13 @@
1989 }
1990 puts "$defn"
1991 }
1992 }
1993
1994 # ----- @module misc.tcl -----
1995
1996 set modsource(misc.tcl) {
1997 # Copyright (c) 2007-2010 WorkWare Systems http://www.workware.net.au/
1998 # All rights reserved
1999
2000 # Module containing misc procs useful to modules
2001 # Largely for platform compatibility
@@ -1805,106 +2167,218 @@
2167 string trim $result
2168 }
2169 }
2170 }
2171
2172 # ----- @module text-formatting.tcl -----
2173
2174 set modsource(text-formatting.tcl) {
2175 # Copyright (c) 2010 WorkWare Systems http://www.workware.net.au/
2176 # All rights reserved
2177
2178 # Module which provides text formatting
2179
2180 use formatting
2181
2182 proc wordwrap {text length {firstprefix ""} {nextprefix ""}} {
2183 set len 0
2184 set space $firstprefix
2185
2186 foreach word [split $text] {
2187 set word [string trim $word]
2188 if {$word eq ""} {
2189 continue
2190 }
2191 if {[info exists partial]} {
2192 append partial " " $word
2193 if {[string first $quote $word] < 0} {
2194 # Haven't found end of quoted word
2195 continue
2196 }
2197 # Finished quoted word
2198 set word $partial
2199 unset partial
2200 unset quote
2201 } else {
2202 set quote [string index $word 0]
2203 if {$quote in {' *}} {
2204 if {[string first $quote $word 1] < 0} {
2205 # Haven't found end of quoted word
2206 # Not a whole word.
2207 set first [string index $word 0]
2208 # Start of quoted word
2209 set partial $word
2210 continue
2211 }
2212 }
2213 }
2214
2215 if {$len && [string length $space$word] + $len >= $length} {
2216 puts ""
2217 set len 0
2218 set space $nextprefix
2219 }
2220 incr len [string length $space$word]
2221
2222 # Use man-page conventions for highlighting 'quoted' and *quoted*
2223 # single words.
2224 # Use x^Hx for *bold* and _^Hx for 'underline'.
2225 #
2226 # less and more will both understand this.
2227 # Pipe through 'col -b' to remove them.
2228 if {[regexp {^'(.*)'(.*)} $word -> quoted after]} {
2229 set quoted [string map {~ " "} $quoted]
2230 regsub -all . $quoted "&\b&" quoted
2231 set word $quoted$after
2232 } elseif {[regexp {^[*](.*)[*](.*)} $word -> quoted after]} {
2233 set quoted [string map {~ " "} $quoted]
2234 regsub -all . $quoted "_\b&" quoted
2235 set word $quoted$after
2236 }
2237 puts -nonewline $space$word
2238 set space " "
2239 }
2240 if {[info exists partial]} {
2241 # Missing end of quote
2242 puts -nonewline $space$partial
2243 }
2244 if {$len} {
2245 puts ""
2246 }
2247 }
2248 proc title {text} {
2249 underline [string trim $text] =
2250 nl
2251 }
2252 proc p {text} {
2253 wordwrap $text 80
2254 nl
2255 }
2256 proc codelines {lines} {
2257 foreach line $lines {
2258 puts " $line"
2259 }
2260 nl
2261 }
2262 proc nl {} {
2263 puts ""
2264 }
2265 proc underline {text char} {
2266 regexp "^(\[ \t\]*)(.*)" $text -> indent words
2267 puts $text
2268 puts $indent[string repeat $char [string length $words]]
2269 }
2270 proc section {text} {
2271 underline "[string trim $text]" -
2272 nl
2273 }
2274 proc subsection {text} {
2275 underline "$text" ~
2276 nl
2277 }
2278 proc bullet {text} {
2279 wordwrap $text 76 " * " " "
2280 }
2281 proc indent {text} {
2282 wordwrap $text 76 " " " "
2283 }
2284 proc defn {first args} {
2285 if {$first ne ""} {
2286 underline " $first" ~
2287 }
2288 foreach p $args {
2289 if {$p ne ""} {
2290 indent $p
2291 }
2292 }
2293 }
2294 }
2295
2296 # ----- @module util.tcl -----
2297
2298 set modsource(util.tcl) {
2299 # Copyright (c) 2012 WorkWare Systems http://www.workware.net.au/
2300 # All rights reserved
2301
2302 # Module which contains miscellaneous utility functions
2303
2304 # @compare-versions version1 version2
2305 #
2306 # Versions are of the form 'a.b.c' (may be any number of numeric components)
2307 #
2308 # Compares the two versions and returns:
2309 ## -1 if v1 < v2
2310 ## 0 if v1 == v2
2311 ## 1 if v1 > v2
2312 #
2313 # If one version has fewer components than the other, 0 is substituted to the right. e.g.
2314 ## 0.2 < 0.3
2315 ## 0.2.5 > 0.2
2316 ## 1.1 == 1.1.0
2317 #
2318 proc compare-versions {v1 v2} {
2319 foreach c1 [split $v1 .] c2 [split $v2 .] {
2320 if {$c1 eq ""} {
2321 set c1 0
2322 }
2323 if {$c2 eq ""} {
2324 set c2 0
2325 }
2326 if {$c1 < $c2} {
2327 return -1
2328 }
2329 if {$c1 > $c2} {
2330 return 1
2331 }
2332 }
2333 return 0
2334 }
2335
2336 # @suffix suf list
2337 #
2338 # Takes a list and returns a new list with '$suf' appended
2339 # to each element
2340 #
2341 ## suffix .c {a b c} => {a.c b.c c.c}
2342 #
2343 proc suffix {suf list} {
2344 set result {}
2345 foreach p $list {
2346 lappend result $p$suf
2347 }
2348 return $result
2349 }
2350
2351 # @prefix pre list
2352 #
2353 # Takes a list and returns a new list with '$pre' prepended
2354 # to each element
2355 #
2356 ## prefix jim- {a.c b.c} => {jim-a.c jim-b.c}
2357 #
2358 proc prefix {pre list} {
2359 set result {}
2360 foreach p $list {
2361 lappend result $pre$p
2362 }
2363 return $result
2364 }
2365
2366 # @lpop list
2367 #
2368 # Removes the last entry from the given list and returns it.
2369 proc lpop {listname} {
2370 upvar $listname list
2371 set val [lindex $list end]
2372 set list [lrange $list 0 end-1]
2373 return $val
2374 }
2375 }
2376
2377 # ----- @module wiki-formatting.tcl -----
2378
2379 set modsource(wiki-formatting.tcl) {
2380 # Copyright (c) 2010 WorkWare Systems http://www.workware.net.au/
2381 # All rights reserved
2382
2383 # Module which provides text formatting
2384 # wiki.tcl.tk format output
@@ -1975,11 +2449,11 @@
2449 if {$autosetup(debug)} {
2450 main $argv
2451 }
2452 if {[catch {main $argv} msg opts] == 1} {
2453 show-notices
2454 autosetup-full-error [error-dump $msg $opts $autosetup(debug)]
2455 if {!$autosetup(debug)} {
2456 puts stderr "Try: '[file tail $autosetup(exe)] --debug' for a full stack trace"
2457 }
2458 exit 1
2459 }
2460
2461 DDED autosetup/autosetup-config.guess
2462 DDED autosetup/autosetup-config.sub
2463 DDED autosetup/autosetup-find-tclsh
2464 DDED autosetup/autosetup-test-tclsh
--- a/autosetup/autosetup-config.guess
+++ b/autosetup/autosetup-config.guess
@@ -1,6 +1,8 @@
11
#! /bin/sh
22
# Attempt to guess a canonical system name.
3
-# Copyright 1992-2014 Free Software Found4-11-04it and/or modify it
3
+# Copyright 1992-2018 Free Software Foundation, Inc.
4
+
5
+timestamp='2018-03-08it and/or modify it
46
# under the terms of the GNU General Public License as published by
57
# t;e Free Software Foundation, either version 3 of the L;cense, or
68
# (at your option) any later version.
@@ -13,7 +15,7 @@
1315
# You should have received a copy of the GNU General Public License
1416
# along with this program; if not, see <https://www.gnu.org/licenses/>.
1517
#
16
-# As a special exceptionto the GNU General Public License, if you
18
+# As a special exception to the GNU General Public License, if you
1719
# distribute this file as part of a program that contains a
1820
# configuration script generated by Autoconf, you may include it under
1921
# the same distribution terms that you use for the rest of that
@@ -23,28 +25,4 @@
2325
# Originally written by Per Bothner; maintained since 2000 by Ben Elliston.
2426
#
2527
# You can get the latest version of this script from:
26
-# https://git.savannah.gnu.org/guess;hb=HEADeration mode4 Free Software Foundation, Inc.
27
-
28
-$dummy.c$dummy.o $dummy.c{UNAME_SYSTEM}
29
- cat <<-EOF > $dummy.c`$CC_FOR_BUILD -E $dummy.c'^LIBC' | sed 's, ,,g'`{UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}/sbin/$sysctl/usr/sbin/$sysctl
30
-# Attempt to guess a canoniAttempt to g! /bin/sh
31
-# Attemp#*) machine=${! /bin/sh
32
-# Attemp#! /bin/sh
33
-# Attempt to guess a canonical system name.
34
-# Copyright 1992-2018canonical system name.
35
-# Copyrig! /bin/sh
36
-# Attemp#! /b{UNAME_VERSION}${UNAME_REL{machine}-${os}${release}${! /bin/sh
37
-# Attemp#! /bin/sh
38
-# Attempt to guess a ${! /bin/sh
39
-# Attemp#! /bin/sh
40
-# Attempt to guess a cekkoBSD:*:*)
41
- echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE}SolidBSD:*:*)
42
- echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE}${UNAME_RELEASE}${UNAME_MACHINE}-unk"alpha""alpha""alpha""alphaev5"A"alphaev56""alphapca56""alphapca57""alphaev6""alphaev67""alphaev68""alphaev68""alphaev68""alphaev69""alphaev7""alphaev79"${UNAME_MACHINE}-dec-osf`echo RELEASE}'' ''` /bin/sh
43
-# Attempt to guess a canonical system name.
44
-# Copyright 1992-2018 Free Software FouAttempt to guess a canonical system name.
45
-# Copyright 1992-2018 Free Software Foundation, Inc.
46
-
47
-timestamp='2018-03-08it and/or modify it
48
-# under the terms of the GNU General Public License as published by
49
-# t;e Free Software Foundation, either version 3 of the L;cense, or
50
-# (at your o
28
+# https://git.savannah.gnu.org/
--- a/autosetup/autosetup-config.guess
+++ b/autosetup/autosetup-config.guess
@@ -1,6 +1,8 @@
1 #! /bin/sh
2 # Attempt to guess a canonical system name.
3 # Copyright 1992-2014 Free Software Found4-11-04it and/or modify it
 
 
4 # under the terms of the GNU General Public License as published by
5 # t;e Free Software Foundation, either version 3 of the L;cense, or
6 # (at your option) any later version.
@@ -13,7 +15,7 @@
13 # You should have received a copy of the GNU General Public License
14 # along with this program; if not, see <https://www.gnu.org/licenses/>.
15 #
16 # As a special exceptionto the GNU General Public License, if you
17 # distribute this file as part of a program that contains a
18 # configuration script generated by Autoconf, you may include it under
19 # the same distribution terms that you use for the rest of that
@@ -23,28 +25,4 @@
23 # Originally written by Per Bothner; maintained since 2000 by Ben Elliston.
24 #
25 # You can get the latest version of this script from:
26 # https://git.savannah.gnu.org/guess;hb=HEADeration mode4 Free Software Foundation, Inc.
27
28 $dummy.c$dummy.o $dummy.c{UNAME_SYSTEM}
29 cat <<-EOF > $dummy.c`$CC_FOR_BUILD -E $dummy.c'^LIBC' | sed 's, ,,g'`{UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}/sbin/$sysctl/usr/sbin/$sysctl
30 # Attempt to guess a canoniAttempt to g! /bin/sh
31 # Attemp#*) machine=${! /bin/sh
32 # Attemp#! /bin/sh
33 # Attempt to guess a canonical system name.
34 # Copyright 1992-2018canonical system name.
35 # Copyrig! /bin/sh
36 # Attemp#! /b{UNAME_VERSION}${UNAME_REL{machine}-${os}${release}${! /bin/sh
37 # Attemp#! /bin/sh
38 # Attempt to guess a ${! /bin/sh
39 # Attemp#! /bin/sh
40 # Attempt to guess a cekkoBSD:*:*)
41 echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE}SolidBSD:*:*)
42 echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE}${UNAME_RELEASE}${UNAME_MACHINE}-unk"alpha""alpha""alpha""alphaev5"A"alphaev56""alphapca56""alphapca57""alphaev6""alphaev67""alphaev68""alphaev68""alphaev68""alphaev69""alphaev7""alphaev79"${UNAME_MACHINE}-dec-osf`echo RELEASE}'' ''` /bin/sh
43 # Attempt to guess a canonical system name.
44 # Copyright 1992-2018 Free Software FouAttempt to guess a canonical system name.
45 # Copyright 1992-2018 Free Software Foundation, Inc.
46
47 timestamp='2018-03-08it and/or modify it
48 # under the terms of the GNU General Public License as published by
49 # t;e Free Software Foundation, either version 3 of the L;cense, or
50 # (at your o
--- a/autosetup/autosetup-config.guess
+++ b/autosetup/autosetup-config.guess
@@ -1,6 +1,8 @@
1 #! /bin/sh
2 # Attempt to guess a canonical system name.
3 # Copyright 1992-2018 Free Software Foundation, Inc.
4
5 timestamp='2018-03-08it and/or modify it
6 # under the terms of the GNU General Public License as published by
7 # t;e Free Software Foundation, either version 3 of the L;cense, or
8 # (at your option) any later version.
@@ -13,7 +15,7 @@
15 # You should have received a copy of the GNU General Public License
16 # along with this program; if not, see <https://www.gnu.org/licenses/>.
17 #
18 # As a special exception to the GNU General Public License, if you
19 # distribute this file as part of a program that contains a
20 # configuration script generated by Autoconf, you may include it under
21 # the same distribution terms that you use for the rest of that
@@ -23,28 +25,4 @@
25 # Originally written by Per Bothner; maintained since 2000 by Ben Elliston.
26 #
27 # You can get the latest version of this script from:
28 # https://git.savannah.gnu.org/
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
--- a/autosetup/autosetup-config.guess
+++ b/autosetup/autosetup-config.guess
@@ -0,0 +1,28 @@
1
+#! /bin/sh
2
+# Attempt to guess a canonical system name.
3
+# Copyright 1992-2018 Free Software Foundation, Inc.
4
+
5
+timestamp='2018-03-08it and/or modify it
6
+# under the terms of the GNU General Public License as published by
7
+# t;e Free Software Foundation, either version 3 of the L;cense, or
8
+# (at your option) any later version.
9
+#
10
+# This program is distributed in the hope that it will be useful, but
11
+# WITHOUT ANY WARRANTY; without even the implied warranty of
12
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
+# General Public License for more details.
14
+#
15
+# You should have received a copy of the GNU General Public License
16
+# along with this program; if not, see <https://www.gnu.org/licenses/>.
17
+#
18
+# As a special exception to the GNU General Public License, if you
19
+# distribute this file as part of a program that contains a
20
+# configuration script generated by Autoconf, you may include it under
21
+# the same distribution terms that you use for the rest of that
22
+# program. This Exception is an additional permission under section 7
23
+# of the GNU General Public License, version 3 ("GPLv3").
24
+#
25
+# Originally written by Per Bothner; maintained since 2000 by Ben Elliston.
26
+#
27
+# You can get the latest version of this script from:
28
+# https://git.savannah.gnu.org/
--- a/autosetup/autosetup-config.guess
+++ b/autosetup/autosetup-config.guess
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
--- a/autosetup/autosetup-config.guess
+++ b/autosetup/autosetup-config.guess
@@ -0,0 +1,28 @@
1 #! /bin/sh
2 # Attempt to guess a canonical system name.
3 # Copyright 1992-2018 Free Software Foundation, Inc.
4
5 timestamp='2018-03-08it and/or modify it
6 # under the terms of the GNU General Public License as published by
7 # t;e Free Software Foundation, either version 3 of the L;cense, or
8 # (at your option) any later version.
9 #
10 # This program is distributed in the hope that it will be useful, but
11 # WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 # General Public License for more details.
14 #
15 # You should have received a copy of the GNU General Public License
16 # along with this program; if not, see <https://www.gnu.org/licenses/>.
17 #
18 # As a special exception to the GNU General Public License, if you
19 # distribute this file as part of a program that contains a
20 # configuration script generated by Autoconf, you may include it under
21 # the same distribution terms that you use for the rest of that
22 # program. This Exception is an additional permission under section 7
23 # of the GNU General Public License, version 3 ("GPLv3").
24 #
25 # Originally written by Per Bothner; maintained since 2000 by Ben Elliston.
26 #
27 # You can get the latest version of this script from:
28 # https://git.savannah.gnu.org/
--- a/autosetup/autosetup-config.sub
+++ b/autosetup/autosetup-config.sub
@@ -1,6 +1,8 @@
11
#! /bin/sh
22
# Configuration validation subroutine script.
3
-# Copyright 1992-2014 Free Software Found4-12-03it and/or modify it
3
+# Copyright 1992-2018 Free Software Foundation, Inc.
4
+
5
+timestamp='2018-03-08it and/or modify it
46
# under the terms of the GNU General Public License as published by
57
# t;e Free Software Foundation, either version 3 of the L;cense, or
68
# (at your option) any later version.
@@ -13,7 +15,6 @@
1315
# You should have received a copy of the GNU General Public License
1416
# along with this program; if not, see <https://www.gnu.org/licenses/>.
1517
#
16
-# As a special exception#
1718
# As a special exception to the GNU General Public License, if you
1819
# distribute this file as part of a program that contains a
1920
# configuration script generated by Autoconf, you may include it under
@@ -30,46 +31,5 @@
3031
3132
'orting which valid configurations
3233
# it does not support. The user should be able to distinguish
33
-# a failure to support;hb=HEAD
34
- $0 [OPTION]f not, see <https:/eration mode a special exception to the GNU General Public License, if you
35
-# distribute this file as part of a program that contains a
36
-# configuration script generated by Autoconf, you may include it under
37
-# the same distribution terms that you use for the rest of that
38
-# program. This Excepti4 Free Software Foundation, Inc.
39
-
40
-er section 7
41
-# of the GNU General Public License, version 3 ("GPLv3").
42
-
43
-
44
-# Please send patches to <[email protected]>.
45
-#
46
-# Configuration subroutine to validate and canonicalize a configuration type.
47
-# Supply the specified configuration type as an argument.
48
-# If it is invalid, we print 1 Free Software Foundation,3 Free Software Foundation, Inc.
49
-
50
-'orting which valid configurations
51
-# it does not support. The user should be able to distinguish
5234
# a failure to support a valid configuration from a meaningless
53
-# configur$1$1$1$1$1$basic_machine !$1$1$1$1$15v6$1$1udk$1! /bin/sh
54
-# Cio$1$1windowsnt/windowsnt/windp11e32k | z8k)
55
- ;;
56
- msbut
57
-# WITHOUT ANY W#! /bin/sh
58
-# Configuration validation subroutine script.
59
-# Copyright 1992-2018 Free Software Foundation, Inc.
60
-
61
-timestamp='2018-03-08it and/or modify it
62
-# under the terms of the GNU General Public License as published by
63
-# t;e Free Software Foundation, either version 3 of the L;cense, or
64
-# (at your option) any later version.
65
-#
66
-# This program is distributed in the hope that it will be useful, but
67
-# WITHOUT ANY WARRANTY; without even the implied warranty of
68
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the $1\': machine \`$basic_machineyramid?unknown$basic_machineu$basic_machine$basic_machine$basic_machine$basic_machinec9c | dpx2*-bull-next)
69
- os=-nextstep3$1$1$1$1i386-vsta | vstabin/sh
70
-# Configuration validation subroutine script.
71
-# Copyright 1992-2018 Free Software Foundation, Inc.
72
-
73
-timestamp='2018-03-08it and/or modify it
74
-# under the terms of the GNU General Public License as published bon subroutine $basic_machine-linuxomron$basic_machine$basic_machine$basic_machine ext$basic_machine$basic_machine$basic_machine$basic_machine$basic_machinepentium4i786-`echo $basic_machinepn$basic_machineppcle | ppc-le | powerpc-littlele$basic_machine$basic_machine | ppc64-le | powerpc64-little64le$basic_machinepsshsh5elh6h64-unknown
75
- ;
35
+# configur
--- a/autosetup/autosetup-config.sub
+++ b/autosetup/autosetup-config.sub
@@ -1,6 +1,8 @@
1 #! /bin/sh
2 # Configuration validation subroutine script.
3 # Copyright 1992-2014 Free Software Found4-12-03it and/or modify it
 
 
4 # under the terms of the GNU General Public License as published by
5 # t;e Free Software Foundation, either version 3 of the L;cense, or
6 # (at your option) any later version.
@@ -13,7 +15,6 @@
13 # You should have received a copy of the GNU General Public License
14 # along with this program; if not, see <https://www.gnu.org/licenses/>.
15 #
16 # As a special exception#
17 # As a special exception to the GNU General Public License, if you
18 # distribute this file as part of a program that contains a
19 # configuration script generated by Autoconf, you may include it under
@@ -30,46 +31,5 @@
30
31 'orting which valid configurations
32 # it does not support. The user should be able to distinguish
33 # a failure to support;hb=HEAD
34 $0 [OPTION]f not, see <https:/eration mode a special exception to the GNU General Public License, if you
35 # distribute this file as part of a program that contains a
36 # configuration script generated by Autoconf, you may include it under
37 # the same distribution terms that you use for the rest of that
38 # program. This Excepti4 Free Software Foundation, Inc.
39
40 er section 7
41 # of the GNU General Public License, version 3 ("GPLv3").
42
43
44 # Please send patches to <[email protected]>.
45 #
46 # Configuration subroutine to validate and canonicalize a configuration type.
47 # Supply the specified configuration type as an argument.
48 # If it is invalid, we print 1 Free Software Foundation,3 Free Software Foundation, Inc.
49
50 'orting which valid configurations
51 # it does not support. The user should be able to distinguish
52 # a failure to support a valid configuration from a meaningless
53 # configur$1$1$1$1$1$basic_machine !$1$1$1$1$15v6$1$1udk$1! /bin/sh
54 # Cio$1$1windowsnt/windowsnt/windp11e32k | z8k)
55 ;;
56 msbut
57 # WITHOUT ANY W#! /bin/sh
58 # Configuration validation subroutine script.
59 # Copyright 1992-2018 Free Software Foundation, Inc.
60
61 timestamp='2018-03-08it and/or modify it
62 # under the terms of the GNU General Public License as published by
63 # t;e Free Software Foundation, either version 3 of the L;cense, or
64 # (at your option) any later version.
65 #
66 # This program is distributed in the hope that it will be useful, but
67 # WITHOUT ANY WARRANTY; without even the implied warranty of
68 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the $1\': machine \`$basic_machineyramid?unknown$basic_machineu$basic_machine$basic_machine$basic_machine$basic_machinec9c | dpx2*-bull-next)
69 os=-nextstep3$1$1$1$1i386-vsta | vstabin/sh
70 # Configuration validation subroutine script.
71 # Copyright 1992-2018 Free Software Foundation, Inc.
72
73 timestamp='2018-03-08it and/or modify it
74 # under the terms of the GNU General Public License as published bon subroutine $basic_machine-linuxomron$basic_machine$basic_machine$basic_machine ext$basic_machine$basic_machine$basic_machine$basic_machine$basic_machinepentium4i786-`echo $basic_machinepn$basic_machineppcle | ppc-le | powerpc-littlele$basic_machine$basic_machine | ppc64-le | powerpc64-little64le$basic_machinepsshsh5elh6h64-unknown
75 ;
--- a/autosetup/autosetup-config.sub
+++ b/autosetup/autosetup-config.sub
@@ -1,6 +1,8 @@
1 #! /bin/sh
2 # Configuration validation subroutine script.
3 # Copyright 1992-2018 Free Software Foundation, Inc.
4
5 timestamp='2018-03-08it and/or modify it
6 # under the terms of the GNU General Public License as published by
7 # t;e Free Software Foundation, either version 3 of the L;cense, or
8 # (at your option) any later version.
@@ -13,7 +15,6 @@
15 # You should have received a copy of the GNU General Public License
16 # along with this program; if not, see <https://www.gnu.org/licenses/>.
17 #
 
18 # As a special exception to the GNU General Public License, if you
19 # distribute this file as part of a program that contains a
20 # configuration script generated by Autoconf, you may include it under
@@ -30,46 +31,5 @@
31
32 'orting which valid configurations
33 # it does not support. The user should be able to distinguish
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
34 # a failure to support a valid configuration from a meaningless
35 # configur
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
--- a/autosetup/autosetup-config.sub
+++ b/autosetup/autosetup-config.sub
@@ -0,0 +1,35 @@
1
+#! /bin/sh
2
+# Configuration validation subroutine script.
3
+# Copyright 1992-2018 Free Software Foundation, Inc.
4
+
5
+timestamp='2018-03-08it and/or modify it
6
+# under the terms of the GNU General Public License as published by
7
+# t;e Free Software Foundation, either version 3 of the L;cense, or
8
+# (at your option) any later version.
9
+#
10
+# This program is distributed in the hope that it will be useful, but
11
+# WITHOUT ANY WARRANTY; without even the implied warranty of
12
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13
+# General Public License for more details.
14
+#
15
+# You should have received a copy of the GNU General Public License
16
+# along with this program; if not, see <https://www.gnu.org/licenses/>.
17
+#
18
+# As a special exception to the GNU General Public License, if you
19
+# distribute this file as part of a program that contains a
20
+# configuration script generated by Autoconf, you may include it under
21
+# the same distribution terms that you use for the rest of that
22
+# program. This Exception is an additional permission under section 7
23
+# of the GNU General Public License, version 3 ("GPLv3").
24
+
25
+
26
+# Please send patches to <[email protected]>.
27
+#
28
+# Configuration subroutine to validate and canonicalize a configuration type.
29
+# Supply the specified configuration type as an argument.
30
+# If it is invalid, we print 1 Free Software Foundation,3 Free Software Foundation, Inc.
31
+
32
+'orting which valid configurations
33
+# it does not support. The user should be able to distinguish
34
+# a failure to support a valid configuration from a meaningless
35
+# configur
--- a/autosetup/autosetup-config.sub
+++ b/autosetup/autosetup-config.sub
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
--- a/autosetup/autosetup-config.sub
+++ b/autosetup/autosetup-config.sub
@@ -0,0 +1,35 @@
1 #! /bin/sh
2 # Configuration validation subroutine script.
3 # Copyright 1992-2018 Free Software Foundation, Inc.
4
5 timestamp='2018-03-08it and/or modify it
6 # under the terms of the GNU General Public License as published by
7 # t;e Free Software Foundation, either version 3 of the L;cense, or
8 # (at your option) any later version.
9 #
10 # This program is distributed in the hope that it will be useful, but
11 # WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 # General Public License for more details.
14 #
15 # You should have received a copy of the GNU General Public License
16 # along with this program; if not, see <https://www.gnu.org/licenses/>.
17 #
18 # As a special exception to the GNU General Public License, if you
19 # distribute this file as part of a program that contains a
20 # configuration script generated by Autoconf, you may include it under
21 # the same distribution terms that you use for the rest of that
22 # program. This Exception is an additional permission under section 7
23 # of the GNU General Public License, version 3 ("GPLv3").
24
25
26 # Please send patches to <[email protected]>.
27 #
28 # Configuration subroutine to validate and canonicalize a configuration type.
29 # Supply the specified configuration type as an argument.
30 # If it is invalid, we print 1 Free Software Foundation,3 Free Software Foundation, Inc.
31
32 'orting which valid configurations
33 # it does not support. The user should be able to distinguish
34 # a failure to support a valid configuration from a meaningless
35 # configur
--- a/autosetup/autosetup-find-tclsh
+++ b/autosetup/autosetup-find-tclsh
@@ -1,10 +1,12 @@
11
#!/bin/sh
22
# Looks for a suitable tclsh or jimsh in the PATH
3
-# If not foundstrap jimsh d=`dirname "$0"`
4
-{ "$d/jimshd/${1-ac"; } 2>&1done
5
-echo 1>&2 bootstrap jimsh0"
6
-for cc in tclsh8.7; do
7
- { $tclsh "$d/c"; } 2>&1 >/dev "$d/${1-autosetup--tclsh}"; } 2>/dev/null && exit 0
3
+# If not foundstrap jimsh in current dir from source
4
+# Prefer $autosetup_tclsh i
5
+d=`dirname "$0"`
6
+{ "$d/jimshd/${1-autosetup-test-tclsh}"; } 2>/dev/null && exit 0
7
+done
8
+echo 1>&2 "No installed jimsh or tclsh, building local bootstrap jimsh0"
9
+for cc in $ { $cc -o jimsh0 "$d/jimsh0.c"; } 2>&1 >/dev "$d/${1-autosetup--tclsh}"; } 2>/dev/null && exit 0
810
done
911
echo 1>&2 "No installed jimsh or tclsh, building local bootstrap jimsh0"
1012
for cc in ${CC_FOR_BUILD:-PATH="$PATH:$d2>/dev/null
--- a/autosetup/autosetup-find-tclsh
+++ b/autosetup/autosetup-find-tclsh
@@ -1,10 +1,12 @@
1 #!/bin/sh
2 # Looks for a suitable tclsh or jimsh in the PATH
3 # If not foundstrap jimsh d=`dirname "$0"`
4 { "$d/jimshd/${1-ac"; } 2>&1done
5 echo 1>&2 bootstrap jimsh0"
6 for cc in tclsh8.7; do
7 { $tclsh "$d/c"; } 2>&1 >/dev "$d/${1-autosetup--tclsh}"; } 2>/dev/null && exit 0
 
 
8 done
9 echo 1>&2 "No installed jimsh or tclsh, building local bootstrap jimsh0"
10 for cc in ${CC_FOR_BUILD:-PATH="$PATH:$d2>/dev/null
--- a/autosetup/autosetup-find-tclsh
+++ b/autosetup/autosetup-find-tclsh
@@ -1,10 +1,12 @@
1 #!/bin/sh
2 # Looks for a suitable tclsh or jimsh in the PATH
3 # If not foundstrap jimsh in current dir from source
4 # Prefer $autosetup_tclsh i
5 d=`dirname "$0"`
6 { "$d/jimshd/${1-autosetup-test-tclsh}"; } 2>/dev/null && exit 0
7 done
8 echo 1>&2 "No installed jimsh or tclsh, building local bootstrap jimsh0"
9 for cc in $ { $cc -o jimsh0 "$d/jimsh0.c"; } 2>&1 >/dev "$d/${1-autosetup--tclsh}"; } 2>/dev/null && exit 0
10 done
11 echo 1>&2 "No installed jimsh or tclsh, building local bootstrap jimsh0"
12 for cc in ${CC_FOR_BUILD:-PATH="$PATH:$d2>/dev/null
--- a/autosetup/autosetup-find-tclsh
+++ b/autosetup/autosetup-find-tclsh
@@ -0,0 +1,12 @@
1
+#!/bin/sh
2
+# Looks for a suitable tclsh or jimsh in the PATH
3
+# If not foundstrap jimsh in current dir from source
4
+# Prefer $autosetup_tclsh i
5
+d=`dirname "$0"`
6
+{ "$d/jimshd/${1-autosetup-test-tclsh}"; } 2>/dev/null && exit 0
7
+done
8
+echo 1>&2 "No installed jimsh or tclsh, building local bootstrap jimsh0"
9
+for cc in $ { $cc -o jimsh0 "$d/jimsh0.c"; } 2>&1 >/dev "$d/${1-autosetup--tclsh}"; } 2>/dev/null && exit 0
10
+done
11
+echo 1>&2 "No installed jimsh or tclsh, building local bootstrap jimsh0"
12
+for cc in ${CC_FOR_BUILD:-PATH="$PATH:$d2>/dev/null
--- a/autosetup/autosetup-find-tclsh
+++ b/autosetup/autosetup-find-tclsh
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
--- a/autosetup/autosetup-find-tclsh
+++ b/autosetup/autosetup-find-tclsh
@@ -0,0 +1,12 @@
1 #!/bin/sh
2 # Looks for a suitable tclsh or jimsh in the PATH
3 # If not foundstrap jimsh in current dir from source
4 # Prefer $autosetup_tclsh i
5 d=`dirname "$0"`
6 { "$d/jimshd/${1-autosetup-test-tclsh}"; } 2>/dev/null && exit 0
7 done
8 echo 1>&2 "No installed jimsh or tclsh, building local bootstrap jimsh0"
9 for cc in $ { $cc -o jimsh0 "$d/jimsh0.c"; } 2>&1 >/dev "$d/${1-autosetup--tclsh}"; } 2>/dev/null && exit 0
10 done
11 echo 1>&2 "No installed jimsh or tclsh, building local bootstrap jimsh0"
12 for cc in ${CC_FOR_BUILD:-PATH="$PATH:$d2>/dev/null

No diff available

--- a/autosetup/autosetup-test-tclsh
+++ b/autosetup/autosetup-test-tclsh
@@ -0,0 +1,20 @@
1
+# A small Tcl script to verify that the chosen
2
+# interpreter works. Sometimes we might e.g. pick up
3
+# an interpreter for a different arch.
4
+# Outputs the full path to the interpreter
5
+
6
+if {[catch {info version} version] == 0} {
7
+ # This is Jim Tcl
8
+ if {$version >= 0.72} {
9
+ # Ensure that regexp works
10
+ regexp (a.*?) a
11
+ puts [info nameofexecutable]
12
+ exit 0
13
+ }
14
+} elseif {[catch {info tclversion} version] == 0} {
15
+ if {$version >= 8.5 && ![string match 8.5a* [info patchlevel]]} {
16
+ puts [info nameofexecutable]
17
+ exit 0
18
+ }
19
+}
20
+exit 1
--- a/autosetup/autosetup-test-tclsh
+++ b/autosetup/autosetup-test-tclsh
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
--- a/autosetup/autosetup-test-tclsh
+++ b/autosetup/autosetup-test-tclsh
@@ -0,0 +1,20 @@
1 # A small Tcl script to verify that the chosen
2 # interpreter works. Sometimes we might e.g. pick up
3 # an interpreter for a different arch.
4 # Outputs the full path to the interpreter
5
6 if {[catch {info version} version] == 0} {
7 # This is Jim Tcl
8 if {$version >= 0.72} {
9 # Ensure that regexp works
10 regexp (a.*?) a
11 puts [info nameofexecutable]
12 exit 0
13 }
14 } elseif {[catch {info tclversion} version] == 0} {
15 if {$version >= 8.5 && ![string match 8.5a* [info patchlevel]]} {
16 puts [info nameofexecutable]
17 exit 0
18 }
19 }
20 exit 1
--- autosetup/cc-db.tcl
+++ autosetup/cc-db.tcl
@@ -1,12 +1,12 @@
11
# Copyright (c) 2011 WorkWare Systems http://www.workware.net.au/
22
# All rights reserved
33
44
# @synopsis:
55
#
6
-# The 'cc-db' module provides a knowledge based of system idiosyncrasies
7
-# In general, this module can always be included
6
+# The 'cc-db' module provides a knowledge-base of system idiosyncrasies.
7
+# In general, this module can always be included.
88
99
use cc
1010
1111
module-options {}
1212
1313
--- autosetup/cc-db.tcl
+++ autosetup/cc-db.tcl
@@ -1,12 +1,12 @@
1 # Copyright (c) 2011 WorkWare Systems http://www.workware.net.au/
2 # All rights reserved
3
4 # @synopsis:
5 #
6 # The 'cc-db' module provides a knowledge based of system idiosyncrasies
7 # In general, this module can always be included
8
9 use cc
10
11 module-options {}
12
13
--- autosetup/cc-db.tcl
+++ autosetup/cc-db.tcl
@@ -1,12 +1,12 @@
1 # Copyright (c) 2011 WorkWare Systems http://www.workware.net.au/
2 # All rights reserved
3
4 # @synopsis:
5 #
6 # The 'cc-db' module provides a knowledge-base of system idiosyncrasies.
7 # In general, this module can always be included.
8
9 use cc
10
11 module-options {}
12
13
--- autosetup/cc-lib.tcl
+++ autosetup/cc-lib.tcl
@@ -9,12 +9,12 @@
99
1010
module-options {}
1111
1212
# @cc-check-lfs
1313
#
14
-# The equivalent of the AC_SYS_LARGEFILE macro
15
-#
14
+# The equivalent of the 'AC_SYS_LARGEFILE' macro.
15
+#
1616
# defines 'HAVE_LFS' if LFS is available,
1717
# and defines '_FILE_OFFSET_BITS=64' if necessary
1818
#
1919
# Returns 1 if 'LFS' is available or 0 otherwise
2020
#
@@ -35,12 +35,12 @@
3535
return $lfs
3636
}
3737
3838
# @cc-check-endian
3939
#
40
-# The equivalent of the AC_C_BIGENDIAN macro
41
-#
40
+# The equivalent of the 'AC_C_BIGENDIAN' macro.
41
+#
4242
# defines 'HAVE_BIG_ENDIAN' if endian is known to be big,
4343
# or 'HAVE_LITTLE_ENDIAN' if endian is known to be little.
4444
#
4545
# Returns 1 if determined, or 0 if not.
4646
#
@@ -80,112 +80,110 @@
8080
#
8181
# Checks whether the given C/C++ compiler flags can be used. Defines feature
8282
# names prefixed with 'HAVE_CFLAG' and 'HAVE_CXXFLAG' respectively, and
8383
# appends working flags to '-cflags' and 'CFLAGS' or 'CXXFLAGS'.
8484
proc cc-check-flags {args} {
85
- set result 1
86
- array set opts [cc-get-settings]
87
- switch -exact -- $opts(-lang) {
88
- c++ {
89
- set lang C++
90
- set prefix CXXFLAG
91
- }
92
- c {
93
- set lang C
94
- set prefix CFLAG
95
- }
96
- default {
97
- autosetup-error "cc-check-flags failed with unknown language: $opts(-lang)"
98
- }
99
- }
100
- foreach flag $args {
101
- msg-checking "Checking whether the $lang compiler accepts $flag..."
102
- if {[cctest -cflags $flag]} {
103
- msg-result yes
104
- define-feature $prefix$flag
105
- cc-with [list -cflags [list $flag]]
106
- define-append ${prefix}S $flag
107
- } else {
108
- msg-result no
109
- set result 0
110
- }
111
- }
112
- return $result
85
+ set result 1
86
+ array set opts [cc-get-settings]
87
+ switch -exact -- $opts(-lang) {
88
+ c++ {
89
+ set lang C++
90
+ set prefix CXXFLAG
91
+ }
92
+ c {
93
+ set lang C
94
+ set prefix CFLAG
95
+ }
96
+ default {
97
+ autosetup-error "cc-check-flags failed with unknown language: $opts(-lang)"
98
+ }
99
+ }
100
+ foreach flag $args {
101
+ msg-checking "Checking whether the $lang compiler accepts $flag..."
102
+ if {[cctest -cflags $flag]} {
103
+ msg-result yes
104
+ define-feature $prefix$flag
105
+ cc-with [list -cflags [list $flag]]
106
+ define-append ${prefix}S $flag
107
+ } else {
108
+ msg-result no
109
+ set result 0
110
+ }
111
+ }
112
+ return $result
113113
}
114114
115115
# @cc-check-standards ver ?...?
116116
#
117117
# Checks whether the C/C++ compiler accepts one of the specified '-std=$ver'
118118
# options, and appends the first working one to '-cflags' and 'CFLAGS' or
119119
# 'CXXFLAGS'.
120120
proc cc-check-standards {args} {
121
- array set opts [cc-get-settings]
122
- foreach std $args {
123
- if {[cc-check-flags -std=$std]} {
124
- return $std
125
- }
126
- }
127
- return ""
121
+ array set opts [cc-get-settings]
122
+ foreach std $args {
123
+ if {[cc-check-flags -std=$std]} {
124
+ return $std
125
+ }
126
+ }
127
+ return ""
128128
}
129129
130130
# Checks whether $keyword is usable as alignof
131131
proc cctest_alignof {keyword} {
132
- msg-checking "Checking for $keyword..."
133
- if {[cctest -code [subst -nobackslashes {
134
- printf("minimum alignment is %d == %d\n", ${keyword}(char), ${keyword}('x'));
135
- }]]} then {
136
- msg-result ok
137
- define-feature $keyword
138
- } else {
139
- msg-result "not found"
140
- }
132
+ msg-checking "Checking for $keyword..."
133
+ if {[cctest -code "int x = ${keyword}(char), y = ${keyword}('x');"]} then {
134
+ msg-result ok
135
+ define-feature $keyword
136
+ } else {
137
+ msg-result "not found"
138
+ }
141139
}
142140
143141
# @cc-check-c11
144142
#
145143
# Checks for several C11/C++11 extensions and their alternatives. Currently
146144
# checks for '_Static_assert', '_Alignof', '__alignof__', '__alignof'.
147145
proc cc-check-c11 {} {
148
- msg-checking "Checking for _Static_assert..."
149
- if {[cctest -code {
150
- _Static_assert(1, "static assertions are available");
151
- }]} then {
152
- msg-result ok
153
- define-feature _Static_assert
154
- } else {
155
- msg-result "not found"
156
- }
157
-
158
- cctest_alignof _Alignof
159
- cctest_alignof __alignof__
160
- cctest_alignof __alignof
146
+ msg-checking "Checking for _Static_assert..."
147
+ if {[cctest -code {
148
+ _Static_assert(1, "static assertions are available");
149
+ }]} then {
150
+ msg-result ok
151
+ define-feature _Static_assert
152
+ } else {
153
+ msg-result "not found"
154
+ }
155
+
156
+ cctest_alignof _Alignof
157
+ cctest_alignof __alignof__
158
+ cctest_alignof __alignof
161159
}
162160
163161
# @cc-check-alloca
164162
#
165
-# The equivalent of the AC_FUNC_ALLOCA macro
163
+# The equivalent of the 'AC_FUNC_ALLOCA' macro.
166164
#
167
-# Checks for the existence of alloca
168
-# defines HAVE_ALLOCA and returns 1 if it exists
165
+# Checks for the existence of 'alloca'
166
+# defines 'HAVE_ALLOCA' and returns 1 if it exists.
169167
proc cc-check-alloca {} {
170
- cc-check-some-feature alloca {
171
- cctest -includes alloca.h -code { alloca (2 * sizeof (int)); }
172
- }
168
+ cc-check-some-feature alloca {
169
+ cctest -includes alloca.h -code { alloca (2 * sizeof (int)); }
170
+ }
173171
}
174172
175173
# @cc-signal-return-type
176174
#
177
-# The equivalent of the AC_TYPE_SIGNAL macro
175
+# The equivalent of the 'AC_TYPE_SIGNAL' macro.
178176
#
179
-# defines RETSIGTYPE to int or void
177
+# defines 'RETSIGTYPE' to 'int' or 'void'.
180178
proc cc-signal-return-type {} {
181
- msg-checking "Checking return type of signal handlers..."
182
- cc-with {-includes {sys/types.h signal.h}} {
183
- if {[cctest -code {return *(signal (0, 0)) (0) == 1;}]} {
184
- set type int
185
- } else {
186
- set type void
187
- }
188
- define RETSIGTYPE $type
189
- msg-result $type
190
- }
179
+ msg-checking "Checking return type of signal handlers..."
180
+ cc-with {-includes {sys/types.h signal.h}} {
181
+ if {[cctest -code {return *(signal (0, 0)) (0) == 1;}]} {
182
+ set type int
183
+ } else {
184
+ set type void
185
+ }
186
+ define RETSIGTYPE $type
187
+ msg-result $type
188
+ }
191189
}
192190
--- autosetup/cc-lib.tcl
+++ autosetup/cc-lib.tcl
@@ -9,12 +9,12 @@
9
10 module-options {}
11
12 # @cc-check-lfs
13 #
14 # The equivalent of the AC_SYS_LARGEFILE macro
15 #
16 # defines 'HAVE_LFS' if LFS is available,
17 # and defines '_FILE_OFFSET_BITS=64' if necessary
18 #
19 # Returns 1 if 'LFS' is available or 0 otherwise
20 #
@@ -35,12 +35,12 @@
35 return $lfs
36 }
37
38 # @cc-check-endian
39 #
40 # The equivalent of the AC_C_BIGENDIAN macro
41 #
42 # defines 'HAVE_BIG_ENDIAN' if endian is known to be big,
43 # or 'HAVE_LITTLE_ENDIAN' if endian is known to be little.
44 #
45 # Returns 1 if determined, or 0 if not.
46 #
@@ -80,112 +80,110 @@
80 #
81 # Checks whether the given C/C++ compiler flags can be used. Defines feature
82 # names prefixed with 'HAVE_CFLAG' and 'HAVE_CXXFLAG' respectively, and
83 # appends working flags to '-cflags' and 'CFLAGS' or 'CXXFLAGS'.
84 proc cc-check-flags {args} {
85 set result 1
86 array set opts [cc-get-settings]
87 switch -exact -- $opts(-lang) {
88 c++ {
89 set lang C++
90 set prefix CXXFLAG
91 }
92 c {
93 set lang C
94 set prefix CFLAG
95 }
96 default {
97 autosetup-error "cc-check-flags failed with unknown language: $opts(-lang)"
98 }
99 }
100 foreach flag $args {
101 msg-checking "Checking whether the $lang compiler accepts $flag..."
102 if {[cctest -cflags $flag]} {
103 msg-result yes
104 define-feature $prefix$flag
105 cc-with [list -cflags [list $flag]]
106 define-append ${prefix}S $flag
107 } else {
108 msg-result no
109 set result 0
110 }
111 }
112 return $result
113 }
114
115 # @cc-check-standards ver ?...?
116 #
117 # Checks whether the C/C++ compiler accepts one of the specified '-std=$ver'
118 # options, and appends the first working one to '-cflags' and 'CFLAGS' or
119 # 'CXXFLAGS'.
120 proc cc-check-standards {args} {
121 array set opts [cc-get-settings]
122 foreach std $args {
123 if {[cc-check-flags -std=$std]} {
124 return $std
125 }
126 }
127 return ""
128 }
129
130 # Checks whether $keyword is usable as alignof
131 proc cctest_alignof {keyword} {
132 msg-checking "Checking for $keyword..."
133 if {[cctest -code [subst -nobackslashes {
134 printf("minimum alignment is %d == %d\n", ${keyword}(char), ${keyword}('x'));
135 }]]} then {
136 msg-result ok
137 define-feature $keyword
138 } else {
139 msg-result "not found"
140 }
141 }
142
143 # @cc-check-c11
144 #
145 # Checks for several C11/C++11 extensions and their alternatives. Currently
146 # checks for '_Static_assert', '_Alignof', '__alignof__', '__alignof'.
147 proc cc-check-c11 {} {
148 msg-checking "Checking for _Static_assert..."
149 if {[cctest -code {
150 _Static_assert(1, "static assertions are available");
151 }]} then {
152 msg-result ok
153 define-feature _Static_assert
154 } else {
155 msg-result "not found"
156 }
157
158 cctest_alignof _Alignof
159 cctest_alignof __alignof__
160 cctest_alignof __alignof
161 }
162
163 # @cc-check-alloca
164 #
165 # The equivalent of the AC_FUNC_ALLOCA macro
166 #
167 # Checks for the existence of alloca
168 # defines HAVE_ALLOCA and returns 1 if it exists
169 proc cc-check-alloca {} {
170 cc-check-some-feature alloca {
171 cctest -includes alloca.h -code { alloca (2 * sizeof (int)); }
172 }
173 }
174
175 # @cc-signal-return-type
176 #
177 # The equivalent of the AC_TYPE_SIGNAL macro
178 #
179 # defines RETSIGTYPE to int or void
180 proc cc-signal-return-type {} {
181 msg-checking "Checking return type of signal handlers..."
182 cc-with {-includes {sys/types.h signal.h}} {
183 if {[cctest -code {return *(signal (0, 0)) (0) == 1;}]} {
184 set type int
185 } else {
186 set type void
187 }
188 define RETSIGTYPE $type
189 msg-result $type
190 }
191 }
192
--- autosetup/cc-lib.tcl
+++ autosetup/cc-lib.tcl
@@ -9,12 +9,12 @@
9
10 module-options {}
11
12 # @cc-check-lfs
13 #
14 # The equivalent of the 'AC_SYS_LARGEFILE' macro.
15 #
16 # defines 'HAVE_LFS' if LFS is available,
17 # and defines '_FILE_OFFSET_BITS=64' if necessary
18 #
19 # Returns 1 if 'LFS' is available or 0 otherwise
20 #
@@ -35,12 +35,12 @@
35 return $lfs
36 }
37
38 # @cc-check-endian
39 #
40 # The equivalent of the 'AC_C_BIGENDIAN' macro.
41 #
42 # defines 'HAVE_BIG_ENDIAN' if endian is known to be big,
43 # or 'HAVE_LITTLE_ENDIAN' if endian is known to be little.
44 #
45 # Returns 1 if determined, or 0 if not.
46 #
@@ -80,112 +80,110 @@
80 #
81 # Checks whether the given C/C++ compiler flags can be used. Defines feature
82 # names prefixed with 'HAVE_CFLAG' and 'HAVE_CXXFLAG' respectively, and
83 # appends working flags to '-cflags' and 'CFLAGS' or 'CXXFLAGS'.
84 proc cc-check-flags {args} {
85 set result 1
86 array set opts [cc-get-settings]
87 switch -exact -- $opts(-lang) {
88 c++ {
89 set lang C++
90 set prefix CXXFLAG
91 }
92 c {
93 set lang C
94 set prefix CFLAG
95 }
96 default {
97 autosetup-error "cc-check-flags failed with unknown language: $opts(-lang)"
98 }
99 }
100 foreach flag $args {
101 msg-checking "Checking whether the $lang compiler accepts $flag..."
102 if {[cctest -cflags $flag]} {
103 msg-result yes
104 define-feature $prefix$flag
105 cc-with [list -cflags [list $flag]]
106 define-append ${prefix}S $flag
107 } else {
108 msg-result no
109 set result 0
110 }
111 }
112 return $result
113 }
114
115 # @cc-check-standards ver ?...?
116 #
117 # Checks whether the C/C++ compiler accepts one of the specified '-std=$ver'
118 # options, and appends the first working one to '-cflags' and 'CFLAGS' or
119 # 'CXXFLAGS'.
120 proc cc-check-standards {args} {
121 array set opts [cc-get-settings]
122 foreach std $args {
123 if {[cc-check-flags -std=$std]} {
124 return $std
125 }
126 }
127 return ""
128 }
129
130 # Checks whether $keyword is usable as alignof
131 proc cctest_alignof {keyword} {
132 msg-checking "Checking for $keyword..."
133 if {[cctest -code "int x = ${keyword}(char), y = ${keyword}('x');"]} then {
134 msg-result ok
135 define-feature $keyword
136 } else {
137 msg-result "not found"
138 }
 
 
139 }
140
141 # @cc-check-c11
142 #
143 # Checks for several C11/C++11 extensions and their alternatives. Currently
144 # checks for '_Static_assert', '_Alignof', '__alignof__', '__alignof'.
145 proc cc-check-c11 {} {
146 msg-checking "Checking for _Static_assert..."
147 if {[cctest -code {
148 _Static_assert(1, "static assertions are available");
149 }]} then {
150 msg-result ok
151 define-feature _Static_assert
152 } else {
153 msg-result "not found"
154 }
155
156 cctest_alignof _Alignof
157 cctest_alignof __alignof__
158 cctest_alignof __alignof
159 }
160
161 # @cc-check-alloca
162 #
163 # The equivalent of the 'AC_FUNC_ALLOCA' macro.
164 #
165 # Checks for the existence of 'alloca'
166 # defines 'HAVE_ALLOCA' and returns 1 if it exists.
167 proc cc-check-alloca {} {
168 cc-check-some-feature alloca {
169 cctest -includes alloca.h -code { alloca (2 * sizeof (int)); }
170 }
171 }
172
173 # @cc-signal-return-type
174 #
175 # The equivalent of the 'AC_TYPE_SIGNAL' macro.
176 #
177 # defines 'RETSIGTYPE' to 'int' or 'void'.
178 proc cc-signal-return-type {} {
179 msg-checking "Checking return type of signal handlers..."
180 cc-with {-includes {sys/types.h signal.h}} {
181 if {[cctest -code {return *(signal (0, 0)) (0) == 1;}]} {
182 set type int
183 } else {
184 set type void
185 }
186 define RETSIGTYPE $type
187 msg-result $type
188 }
189 }
190
--- autosetup/cc-shared.tcl
+++ autosetup/cc-shared.tcl
@@ -7,27 +7,30 @@
77
# It defines the following variables:
88
#
99
## SH_CFLAGS Flags to use compiling sources destined for a shared library
1010
## SH_LDFLAGS Flags to use linking (creating) a shared library
1111
## SH_SOPREFIX Prefix to use to set the soname when creating a shared library
12
+## SH_SOFULLPATH Set to 1 if the shared library soname should include the full install path
1213
## SH_SOEXT Extension for shared libs
1314
## SH_SOEXTVER Format for versioned shared libs - %s = version
1415
## SHOBJ_CFLAGS Flags to use compiling sources destined for a shared object
1516
## SHOBJ_LDFLAGS Flags to use linking a shared object, undefined symbols allowed
1617
## SHOBJ_LDFLAGS_R - as above, but all symbols must be resolved
18
+## SH_LINKRPATH Format for setting the rpath when linking an executable, %s = path
1719
## SH_LINKFLAGS Flags to use linking an executable which will load shared objects
1820
## LD_LIBRARY_PATH Environment variable which specifies path to shared libraries
1921
## STRIPLIBFLAGS Arguments to strip a dynamic library
2022
2123
module-options {}
2224
2325
# Defaults: gcc on unix
24
-define SHOBJ_CFLAGS -fpic
26
+define SHOBJ_CFLAGS -fPIC
2527
define SHOBJ_LDFLAGS -shared
26
-define SH_CFLAGS -fpic
28
+define SH_CFLAGS -fPIC
2729
define SH_LDFLAGS -shared
2830
define SH_LINKFLAGS -rdynamic
31
+define SH_LINKRPATH "-Wl,-rpath -Wl,%s"
2932
define SH_SOEXT .so
3033
define SH_SOEXTVER .so.%s
3134
define SH_SOPREFIX -Wl,-soname,
3235
define LD_LIBRARY_PATH LD_LIBRARY_PATH
3336
define STRIPLIBFLAGS --strip-unneeded
@@ -44,18 +47,20 @@
4447
define SH_LDFLAGS -dynamiclib
4548
define SH_LINKFLAGS ""
4649
define SH_SOEXT .dylib
4750
define SH_SOEXTVER .%s.dylib
4851
define SH_SOPREFIX -Wl,-install_name,
52
+ define SH_SOFULLPATH
4953
define LD_LIBRARY_PATH DYLD_LIBRARY_PATH
5054
define STRIPLIBFLAGS -x
5155
}
5256
*-*-ming* - *-*-cygwin - *-*-msys {
5357
define SHOBJ_CFLAGS ""
5458
define SHOBJ_LDFLAGS -shared
5559
define SH_CFLAGS ""
5660
define SH_LDFLAGS -shared
61
+ define SH_LINKRPATH ""
5762
define SH_LINKFLAGS ""
5863
define SH_SOEXT .dll
5964
define SH_SOEXTVER .dll
6065
define SH_SOPREFIX ""
6166
define LD_LIBRARY_PATH PATH
@@ -62,27 +67,23 @@
6267
}
6368
sparc* {
6469
if {[msg-quiet cc-check-decls __SUNPRO_C]} {
6570
msg-result "Found sun stdio compiler"
6671
# sun stdio compiler
67
- # XXX: These haven't been fully tested.
72
+ # XXX: These haven't been fully tested.
6873
define SHOBJ_CFLAGS -KPIC
6974
define SHOBJ_LDFLAGS "-G"
7075
define SH_CFLAGS -KPIC
7176
define SH_LINKFLAGS -Wl,-export-dynamic
7277
define SH_SOPREFIX -Wl,-h,
73
- } else {
74
- # sparc has a very small GOT table limit, so use -fPIC
75
- define SH_CFLAGS -fPIC
76
- define SHOBJ_CFLAGS -fPIC
7778
}
7879
}
7980
*-*-solaris* {
8081
if {[msg-quiet cc-check-decls __SUNPRO_C]} {
8182
msg-result "Found sun stdio compiler"
8283
# sun stdio compiler
83
- # XXX: These haven't been fully tested.
84
+ # XXX: These haven't been fully tested.
8485
define SHOBJ_CFLAGS -KPIC
8586
define SHOBJ_LDFLAGS "-G"
8687
define SH_CFLAGS -KPIC
8788
define SH_LINKFLAGS -Wl,-export-dynamic
8889
define SH_SOPREFIX -Wl,-h,
@@ -103,15 +104,10 @@
103104
define SH_LDFLAGS -shared
104105
define SH_LINKFLAGS ""
105106
define SH_SOPREFIX ""
106107
define LD_LIBRARY_PATH LIBRARY_PATH
107108
}
108
- microblaze* {
109
- # Microblaze generally needs -fPIC rather than -fpic
110
- define SHOBJ_CFLAGS -fPIC
111
- define SH_CFLAGS -fPIC
112
- }
113109
}
114110
115111
if {![is-defined SHOBJ_LDFLAGS_R]} {
116112
define SHOBJ_LDFLAGS_R [get-define SHOBJ_LDFLAGS]
117113
}
118114
--- autosetup/cc-shared.tcl
+++ autosetup/cc-shared.tcl
@@ -7,27 +7,30 @@
7 # It defines the following variables:
8 #
9 ## SH_CFLAGS Flags to use compiling sources destined for a shared library
10 ## SH_LDFLAGS Flags to use linking (creating) a shared library
11 ## SH_SOPREFIX Prefix to use to set the soname when creating a shared library
 
12 ## SH_SOEXT Extension for shared libs
13 ## SH_SOEXTVER Format for versioned shared libs - %s = version
14 ## SHOBJ_CFLAGS Flags to use compiling sources destined for a shared object
15 ## SHOBJ_LDFLAGS Flags to use linking a shared object, undefined symbols allowed
16 ## SHOBJ_LDFLAGS_R - as above, but all symbols must be resolved
 
17 ## SH_LINKFLAGS Flags to use linking an executable which will load shared objects
18 ## LD_LIBRARY_PATH Environment variable which specifies path to shared libraries
19 ## STRIPLIBFLAGS Arguments to strip a dynamic library
20
21 module-options {}
22
23 # Defaults: gcc on unix
24 define SHOBJ_CFLAGS -fpic
25 define SHOBJ_LDFLAGS -shared
26 define SH_CFLAGS -fpic
27 define SH_LDFLAGS -shared
28 define SH_LINKFLAGS -rdynamic
 
29 define SH_SOEXT .so
30 define SH_SOEXTVER .so.%s
31 define SH_SOPREFIX -Wl,-soname,
32 define LD_LIBRARY_PATH LD_LIBRARY_PATH
33 define STRIPLIBFLAGS --strip-unneeded
@@ -44,18 +47,20 @@
44 define SH_LDFLAGS -dynamiclib
45 define SH_LINKFLAGS ""
46 define SH_SOEXT .dylib
47 define SH_SOEXTVER .%s.dylib
48 define SH_SOPREFIX -Wl,-install_name,
 
49 define LD_LIBRARY_PATH DYLD_LIBRARY_PATH
50 define STRIPLIBFLAGS -x
51 }
52 *-*-ming* - *-*-cygwin - *-*-msys {
53 define SHOBJ_CFLAGS ""
54 define SHOBJ_LDFLAGS -shared
55 define SH_CFLAGS ""
56 define SH_LDFLAGS -shared
 
57 define SH_LINKFLAGS ""
58 define SH_SOEXT .dll
59 define SH_SOEXTVER .dll
60 define SH_SOPREFIX ""
61 define LD_LIBRARY_PATH PATH
@@ -62,27 +67,23 @@
62 }
63 sparc* {
64 if {[msg-quiet cc-check-decls __SUNPRO_C]} {
65 msg-result "Found sun stdio compiler"
66 # sun stdio compiler
67 # XXX: These haven't been fully tested.
68 define SHOBJ_CFLAGS -KPIC
69 define SHOBJ_LDFLAGS "-G"
70 define SH_CFLAGS -KPIC
71 define SH_LINKFLAGS -Wl,-export-dynamic
72 define SH_SOPREFIX -Wl,-h,
73 } else {
74 # sparc has a very small GOT table limit, so use -fPIC
75 define SH_CFLAGS -fPIC
76 define SHOBJ_CFLAGS -fPIC
77 }
78 }
79 *-*-solaris* {
80 if {[msg-quiet cc-check-decls __SUNPRO_C]} {
81 msg-result "Found sun stdio compiler"
82 # sun stdio compiler
83 # XXX: These haven't been fully tested.
84 define SHOBJ_CFLAGS -KPIC
85 define SHOBJ_LDFLAGS "-G"
86 define SH_CFLAGS -KPIC
87 define SH_LINKFLAGS -Wl,-export-dynamic
88 define SH_SOPREFIX -Wl,-h,
@@ -103,15 +104,10 @@
103 define SH_LDFLAGS -shared
104 define SH_LINKFLAGS ""
105 define SH_SOPREFIX ""
106 define LD_LIBRARY_PATH LIBRARY_PATH
107 }
108 microblaze* {
109 # Microblaze generally needs -fPIC rather than -fpic
110 define SHOBJ_CFLAGS -fPIC
111 define SH_CFLAGS -fPIC
112 }
113 }
114
115 if {![is-defined SHOBJ_LDFLAGS_R]} {
116 define SHOBJ_LDFLAGS_R [get-define SHOBJ_LDFLAGS]
117 }
118
--- autosetup/cc-shared.tcl
+++ autosetup/cc-shared.tcl
@@ -7,27 +7,30 @@
7 # It defines the following variables:
8 #
9 ## SH_CFLAGS Flags to use compiling sources destined for a shared library
10 ## SH_LDFLAGS Flags to use linking (creating) a shared library
11 ## SH_SOPREFIX Prefix to use to set the soname when creating a shared library
12 ## SH_SOFULLPATH Set to 1 if the shared library soname should include the full install path
13 ## SH_SOEXT Extension for shared libs
14 ## SH_SOEXTVER Format for versioned shared libs - %s = version
15 ## SHOBJ_CFLAGS Flags to use compiling sources destined for a shared object
16 ## SHOBJ_LDFLAGS Flags to use linking a shared object, undefined symbols allowed
17 ## SHOBJ_LDFLAGS_R - as above, but all symbols must be resolved
18 ## SH_LINKRPATH Format for setting the rpath when linking an executable, %s = path
19 ## SH_LINKFLAGS Flags to use linking an executable which will load shared objects
20 ## LD_LIBRARY_PATH Environment variable which specifies path to shared libraries
21 ## STRIPLIBFLAGS Arguments to strip a dynamic library
22
23 module-options {}
24
25 # Defaults: gcc on unix
26 define SHOBJ_CFLAGS -fPIC
27 define SHOBJ_LDFLAGS -shared
28 define SH_CFLAGS -fPIC
29 define SH_LDFLAGS -shared
30 define SH_LINKFLAGS -rdynamic
31 define SH_LINKRPATH "-Wl,-rpath -Wl,%s"
32 define SH_SOEXT .so
33 define SH_SOEXTVER .so.%s
34 define SH_SOPREFIX -Wl,-soname,
35 define LD_LIBRARY_PATH LD_LIBRARY_PATH
36 define STRIPLIBFLAGS --strip-unneeded
@@ -44,18 +47,20 @@
47 define SH_LDFLAGS -dynamiclib
48 define SH_LINKFLAGS ""
49 define SH_SOEXT .dylib
50 define SH_SOEXTVER .%s.dylib
51 define SH_SOPREFIX -Wl,-install_name,
52 define SH_SOFULLPATH
53 define LD_LIBRARY_PATH DYLD_LIBRARY_PATH
54 define STRIPLIBFLAGS -x
55 }
56 *-*-ming* - *-*-cygwin - *-*-msys {
57 define SHOBJ_CFLAGS ""
58 define SHOBJ_LDFLAGS -shared
59 define SH_CFLAGS ""
60 define SH_LDFLAGS -shared
61 define SH_LINKRPATH ""
62 define SH_LINKFLAGS ""
63 define SH_SOEXT .dll
64 define SH_SOEXTVER .dll
65 define SH_SOPREFIX ""
66 define LD_LIBRARY_PATH PATH
@@ -62,27 +67,23 @@
67 }
68 sparc* {
69 if {[msg-quiet cc-check-decls __SUNPRO_C]} {
70 msg-result "Found sun stdio compiler"
71 # sun stdio compiler
72 # XXX: These haven't been fully tested.
73 define SHOBJ_CFLAGS -KPIC
74 define SHOBJ_LDFLAGS "-G"
75 define SH_CFLAGS -KPIC
76 define SH_LINKFLAGS -Wl,-export-dynamic
77 define SH_SOPREFIX -Wl,-h,
 
 
 
 
78 }
79 }
80 *-*-solaris* {
81 if {[msg-quiet cc-check-decls __SUNPRO_C]} {
82 msg-result "Found sun stdio compiler"
83 # sun stdio compiler
84 # XXX: These haven't been fully tested.
85 define SHOBJ_CFLAGS -KPIC
86 define SHOBJ_LDFLAGS "-G"
87 define SH_CFLAGS -KPIC
88 define SH_LINKFLAGS -Wl,-export-dynamic
89 define SH_SOPREFIX -Wl,-h,
@@ -103,15 +104,10 @@
104 define SH_LDFLAGS -shared
105 define SH_LINKFLAGS ""
106 define SH_SOPREFIX ""
107 define LD_LIBRARY_PATH LIBRARY_PATH
108 }
 
 
 
 
 
109 }
110
111 if {![is-defined SHOBJ_LDFLAGS_R]} {
112 define SHOBJ_LDFLAGS_R [get-define SHOBJ_LDFLAGS]
113 }
114
+80 -52
--- autosetup/cc.tcl
+++ autosetup/cc.tcl
@@ -2,17 +2,18 @@
22
# All rights reserved
33
44
# @synopsis:
55
#
66
# The 'cc' module supports checking various 'features' of the C or C++
7
-# compiler/linker environment. Common commands are cc-check-includes,
8
-# cc-check-types, cc-check-functions, cc-with, make-autoconf-h and make-template.
7
+# compiler/linker environment. Common commands are 'cc-check-includes',
8
+# 'cc-check-types', 'cc-check-functions', 'cc-with', 'make-config-header' and 'make-template'.
99
#
1010
# The following environment variables are used if set:
1111
#
1212
## CC - C compiler
1313
## CXX - C++ compiler
14
+## CPP - C preprocessor
1415
## CCACHE - Set to "none" to disable automatic use of ccache
1516
## CFLAGS - Additional C compiler flags
1617
## CXXFLAGS - Additional C++ compiler flags
1718
## LDFLAGS - Additional compiler flags during linking
1819
## LIBS - Additional libraries to use (for all tests)
@@ -28,15 +29,10 @@
2829
2930
use system
3031
3132
module-options {}
3233
33
-# Note that the return code is not meaningful
34
-proc cc-check-something {name code} {
35
- uplevel 1 $code
36
-}
37
-
3834
# Checks for the existence of the given function by linking
3935
#
4036
proc cctest_function {function} {
4137
cctest -link 1 -declare "extern void $function\(void);" -code "$function\();"
4238
}
@@ -68,12 +64,12 @@
6864
}
6965
7066
# @cc-check-sizeof type ...
7167
#
7268
# Checks the size of the given types (between 1 and 32, inclusive).
73
-# Defines a variable with the size determined, or "unknown" otherwise.
74
-# e.g. for type 'long long', defines SIZEOF_LONG_LONG.
69
+# Defines a variable with the size determined, or 'unknown' otherwise.
70
+# e.g. for type 'long long', defines 'SIZEOF_LONG_LONG'.
7571
# Returns the size of the last type.
7672
#
7773
proc cc-check-sizeof {args} {
7874
foreach type $args {
7975
msg-checking "Checking for sizeof $type..."
@@ -109,11 +105,11 @@
109105
return $ret
110106
}
111107
112108
# @cc-check-includes includes ...
113109
#
114
-# Checks that the given include files can be used
110
+# Checks that the given include files can be used.
115111
proc cc-check-includes {args} {
116112
cc-check-some-feature $args {
117113
set with {}
118114
if {[dict exists $::autosetup(cc-include-deps) $each]} {
119115
set deps [dict keys [dict get $::autosetup(cc-include-deps) $each]]
@@ -134,12 +130,12 @@
134130
}
135131
}
136132
137133
# @cc-include-needs include required ...
138134
#
139
-# Ensures that when checking for 'include', a check is first
140
-# made for each 'required' file, and if found, it is #included
135
+# Ensures that when checking for '$include', a check is first
136
+# made for each '$required' file, and if found, it is included with '#include'.
141137
proc cc-include-needs {file args} {
142138
foreach depfile $args {
143139
dict set ::autosetup(cc-include-deps) $file $depfile 1
144140
}
145141
}
@@ -153,22 +149,22 @@
153149
}
154150
}
155151
156152
# @cc-check-defines define ...
157153
#
158
-# Checks that the given preprocessor symbol is defined
154
+# Checks that the given preprocessor symbols are defined.
159155
proc cc-check-defines {args} {
160156
cc-check-some-feature $args {
161157
cctest_define $each
162158
}
163159
}
164160
165161
# @cc-check-decls name ...
166162
#
167163
# Checks that each given name is either a preprocessor symbol or rvalue
168
-# such as an enum. Note that the define used is HAVE_DECL_xxx
169
-# rather than HAVE_xxx
164
+# such as an enum. Note that the define used is 'HAVE_DECL_xxx'
165
+# rather than 'HAVE_xxx'.
170166
proc cc-check-decls {args} {
171167
set ret 1
172168
foreach name $args {
173169
msg-checking "Checking for $name..."
174170
set r [cctest_decl $name]
@@ -183,21 +179,21 @@
183179
return $ret
184180
}
185181
186182
# @cc-check-functions function ...
187183
#
188
-# Checks that the given functions exist (can be linked)
184
+# Checks that the given functions exist (can be linked).
189185
proc cc-check-functions {args} {
190186
cc-check-some-feature $args {
191187
cctest_function $each
192188
}
193189
}
194190
195191
# @cc-check-members type.member ...
196192
#
197193
# Checks that the given type/structure members exist.
198
-# A structure member is of the form "struct stat.st_mtime"
194
+# A structure member is of the form 'struct stat.st_mtime'.
199195
proc cc-check-members {args} {
200196
cc-check-some-feature $args {
201197
cctest_member $each
202198
}
203199
}
@@ -207,20 +203,20 @@
207203
# Checks that the given function can be found in one of the libs.
208204
#
209205
# First checks for no library required, then checks each of the libraries
210206
# in turn.
211207
#
212
-# If the function is found, the feature is defined and lib_$function is defined
213
-# to -l$lib where the function was found, or "" if no library required.
214
-# In addition, -l$lib is prepended to the LIBS define.
208
+# If the function is found, the feature is defined and 'lib_$function' is defined
209
+# to '-l$lib' where the function was found, or "" if no library required.
210
+# In addition, '-l$lib' is prepended to the 'LIBS' define.
215211
#
216212
# If additional libraries may be needed for linking, they should be specified
217
-# as $extralibs as "-lotherlib1 -lotherlib2".
218
-# These libraries are not automatically added to LIBS.
213
+# with '$extralibs' as '-lotherlib1 -lotherlib2'.
214
+# These libraries are not automatically added to 'LIBS'.
219215
#
220216
# Returns 1 if found or 0 if not.
221
-#
217
+#
222218
proc cc-check-function-in-lib {function libs {otherlibs {}}} {
223219
msg-checking "Checking libs for $function..."
224220
set found 0
225221
cc-with [list -libs $otherlibs] {
226222
if {[cctest_function $function]} {
@@ -240,13 +236,12 @@
240236
}
241237
}
242238
}
243239
}
244240
}
245
- if {$found} {
246
- define [feature-define-name $function]
247
- } else {
241
+ define-feature $function $found
242
+ if {!$found} {
248243
msg-result "no"
249244
}
250245
return $found
251246
}
252247
@@ -253,16 +248,16 @@
253248
# @cc-check-tools tool ...
254249
#
255250
# Checks for existence of the given compiler tools, taking
256251
# into account any cross compilation prefix.
257252
#
258
-# For example, when checking for "ar", first AR is checked on the command
259
-# line and then in the environment. If not found, "${host}-ar" or
260
-# simply "ar" is assumed depending upon whether cross compiling.
261
-# The path is searched for this executable, and if found AR is defined
253
+# For example, when checking for 'ar', first 'AR' is checked on the command
254
+# line and then in the environment. If not found, '${host}-ar' or
255
+# simply 'ar' is assumed depending upon whether cross compiling.
256
+# The path is searched for this executable, and if found 'AR' is defined
262257
# to the executable name.
263
-# Note that even when cross compiling, the simple "ar" is used as a fallback,
258
+# Note that even when cross compiling, the simple 'ar' is used as a fallback,
264259
# but a warning is generated. This is necessary for some toolchains.
265260
#
266261
# It is an error if the executable is not found.
267262
#
268263
proc cc-check-tools {args} {
@@ -284,14 +279,14 @@
284279
285280
# @cc-check-progs prog ...
286281
#
287282
# Checks for existence of the given executables on the path.
288283
#
289
-# For example, when checking for "grep", the path is searched for
290
-# the executable, 'grep', and if found GREP is defined as "grep".
284
+# For example, when checking for 'grep', the path is searched for
285
+# the executable, 'grep', and if found 'GREP' is defined as 'grep'.
291286
#
292
-# If the executable is not found, the variable is defined as false.
287
+# If the executable is not found, the variable is defined as 'false'.
293288
# Returns 1 if all programs were found, or 0 otherwise.
294289
#
295290
proc cc-check-progs {args} {
296291
set failed 0
297292
foreach prog $args {
@@ -303,10 +298,33 @@
303298
incr failed
304299
} else {
305300
msg-result ok
306301
define $PROG $prog
307302
}
303
+ }
304
+ expr {!$failed}
305
+}
306
+
307
+# @cc-path-progs prog ...
308
+#
309
+# Like cc-check-progs, but sets the define to the full path rather
310
+# than just the program name.
311
+#
312
+proc cc-path-progs {args} {
313
+ set failed 0
314
+ foreach prog $args {
315
+ set PROG [string toupper $prog]
316
+ msg-checking "Checking for $prog..."
317
+ set path [find-executable-path $prog]
318
+ if {$path eq ""} {
319
+ msg-result no
320
+ define $PROG false
321
+ incr failed
322
+ } else {
323
+ msg-result $path
324
+ define $PROG $path
325
+ }
308326
}
309327
expr {!$failed}
310328
}
311329
312330
# Adds the given settings to $::autosetup(ccsettings) and
@@ -326,18 +344,18 @@
326344
327345
foreach {name value} $settings {
328346
switch -exact -- $name {
329347
-cflags - -includes {
330348
# These are given as lists
331
- lappend new($name) {*}$value
349
+ lappend new($name) {*}[list-non-empty $value]
332350
}
333351
-declare {
334352
lappend new($name) $value
335353
}
336354
-libs {
337355
# Note that new libraries are added before previous libraries
338
- set new($name) [list {*}$value {*}$new($name)]
356
+ set new($name) [list {*}[list-non-empty $value] {*}$new($name)]
339357
}
340358
-link - -lang - -nooutput {
341359
set new($name) $value
342360
}
343361
-source - -sourcefile - -code {
@@ -373,16 +391,16 @@
373391
return $prev
374392
}
375393
376394
# @cc-with settings ?{ script }?
377395
#
378
-# Sets the given 'cctest' settings and then runs the tests in 'script'.
379
-# Note that settings such as -lang replace the current setting, while
380
-# those such as -includes are appended to the existing setting.
396
+# Sets the given 'cctest' settings and then runs the tests in '$script'.
397
+# Note that settings such as '-lang' replace the current setting, while
398
+# those such as '-includes' are appended to the existing setting.
381399
#
382400
# If no script is given, the settings become the default for the remainder
383
-# of the auto.def file.
401
+# of the 'auto.def' file.
384402
#
385403
## cc-with {-lang c++} {
386404
## # This will check with the C++ compiler
387405
## cc-check-types bool
388406
## cc-with {-includes signal.h} {
@@ -390,11 +408,11 @@
390408
## ...
391409
## }
392410
## # back to just the C++ compiler
393411
## }
394412
#
395
-# The -libs setting is special in that newer values are added *before* earlier ones.
413
+# The '-libs' setting is special in that newer values are added *before* earlier ones.
396414
#
397415
## cc-with {-libs {-lc -lm}} {
398416
## cc-with {-libs -ldl} {
399417
## cctest -libs -lsocket ...
400418
## # libs will be in this order: -lsocket -ldl -lc -lm
@@ -415,12 +433,12 @@
415433
return $result
416434
}
417435
}
418436
419437
# @cctest ?settings?
420
-#
421
-# Low level C compiler checker. Compiles and or links a small C program
438
+#
439
+# Low level C/C++ compiler checker. Compiles and or links a small C program
422440
# according to the arguments and returns 1 if OK, or 0 if not.
423441
#
424442
# Supported settings are:
425443
#
426444
## -cflags cflags A list of flags to pass to the compiler
@@ -432,11 +450,11 @@
432450
## -code code Code to compile in the body of main()
433451
## -source code Compile a complete program. Ignore -includes, -declare and -code
434452
## -sourcefile file Shorthand for -source [readfile [get-define srcdir]/$file]
435453
## -nooutput 1 Treat any compiler output (e.g. a warning) as an error
436454
#
437
-# Unless -source or -sourcefile is specified, the C program looks like:
455
+# Unless '-source' or '-sourcefile' is specified, the C program looks like:
438456
#
439457
## #include <firstinclude> /* same for remaining includes in the list */
440458
##
441459
## declare-code /* any code in -declare, verbatim */
442460
##
@@ -446,11 +464,10 @@
446464
## }
447465
#
448466
# Any failures are recorded in 'config.log'
449467
#
450468
proc cctest {args} {
451
- set src conftest__.c
452469
set tmp conftest__
453470
454471
# Easiest way to merge in the settings
455472
cc-with $args {
456473
array set opts [cc-get-settings]
@@ -488,13 +505,15 @@
488505
# Build the command line
489506
set cmdline {}
490507
lappend cmdline {*}[get-define CCACHE]
491508
switch -exact -- $opts(-lang) {
492509
c++ {
510
+ set src conftest__.cpp
493511
lappend cmdline {*}[get-define CXX] {*}[get-define CXXFLAGS]
494512
}
495513
c {
514
+ set src conftest__.c
496515
lappend cmdline {*}[get-define CC] {*}[get-define CFLAGS]
497516
}
498517
default {
499518
autosetup-error "cctest called with unknown language: $opts(-lang)"
500519
}
@@ -554,32 +573,32 @@
554573
return $ok
555574
}
556575
557576
# @make-autoconf-h outfile ?auto-patterns=HAVE_*? ?bare-patterns=SIZEOF_*?
558577
#
559
-# Deprecated - see make-config-header
578
+# Deprecated - see 'make-config-header'
560579
proc make-autoconf-h {file {autopatterns {HAVE_*}} {barepatterns {SIZEOF_* HAVE_DECL_*}}} {
561580
user-notice "*** make-autoconf-h is deprecated -- use make-config-header instead"
562581
make-config-header $file -auto $autopatterns -bare $barepatterns
563582
}
564583
565584
# @make-config-header outfile ?-auto patternlist? ?-bare patternlist? ?-none patternlist? ?-str patternlist? ...
566585
#
567586
# Examines all defined variables which match the given patterns
568
-# and writes an include file, $file, which defines each of these.
587
+# and writes an include file, '$file', which defines each of these.
569588
# Variables which match '-auto' are output as follows:
570
-# - defines which have the value "0" are ignored.
589
+# - defines which have the value '0' are ignored.
571590
# - defines which have integer values are defined as the integer value.
572
-# - any other value is defined as a string, e.g. "value"
591
+# - any other value is defined as a string, e.g. '"value"'
573592
# Variables which match '-bare' are defined as-is.
574
-# Variables which match '-str' are defined as a string, e.g. "value"
593
+# Variables which match '-str' are defined as a string, e.g. '"value"'
575594
# Variables which match '-none' are omitted.
576595
#
577
-# Note that order is important. The first pattern which matches is selected
596
+# Note that order is important. The first pattern that matches is selected.
578597
# Default behaviour is:
579598
#
580
-# -bare {SIZEOF_* HAVE_DECL_*} -auto HAVE_* -none *
599
+## -bare {SIZEOF_* HAVE_DECL_*} -auto HAVE_* -none *
581600
#
582601
# If the file would be unchanged, it is not written.
583602
proc make-config-header {file args} {
584603
set guard _[string toupper [regsub -all {[^a-zA-Z0-9]} [file tail $file] _]]
585604
file mkdir [file dirname $file]
@@ -677,10 +696,19 @@
677696
if {[get-define CC] eq ""} {
678697
user-error "Could not find a C compiler. Tried: [join $try ", "]"
679698
}
680699
681700
define CCACHE [find-an-executable [get-env CCACHE ccache]]
701
+
702
+# If any of these are set in the environment, propagate them to the AUTOREMAKE commandline
703
+foreach i {CC CXX CCACHE CPP CFLAGS CXXFLAGS CXXFLAGS LDFLAGS LIBS CROSS CPPFLAGS LINKFLAGS CC_FOR_BUILD LD} {
704
+ if {[env-is-set $i]} {
705
+ # Note: If the variable is set on the command line, get-env will return that value
706
+ # so the command line will continue to override the environment
707
+ define-append AUTOREMAKE [quote-if-needed $i=[get-env $i ""]]
708
+ }
709
+}
682710
683711
# Initial cctest settings
684712
cc-store-settings {-cflags {} -includes {} -declare {} -link 0 -lang c -libs {} -code {} -nooutput 0}
685713
set autosetup(cc-include-deps) {}
686714
687715
688716
DELETED autosetup/config.guess
689717
DELETED autosetup/config.sub
690718
DELETED autosetup/find-tclsh
--- autosetup/cc.tcl
+++ autosetup/cc.tcl
@@ -2,17 +2,18 @@
2 # All rights reserved
3
4 # @synopsis:
5 #
6 # The 'cc' module supports checking various 'features' of the C or C++
7 # compiler/linker environment. Common commands are cc-check-includes,
8 # cc-check-types, cc-check-functions, cc-with, make-autoconf-h and make-template.
9 #
10 # The following environment variables are used if set:
11 #
12 ## CC - C compiler
13 ## CXX - C++ compiler
 
14 ## CCACHE - Set to "none" to disable automatic use of ccache
15 ## CFLAGS - Additional C compiler flags
16 ## CXXFLAGS - Additional C++ compiler flags
17 ## LDFLAGS - Additional compiler flags during linking
18 ## LIBS - Additional libraries to use (for all tests)
@@ -28,15 +29,10 @@
28
29 use system
30
31 module-options {}
32
33 # Note that the return code is not meaningful
34 proc cc-check-something {name code} {
35 uplevel 1 $code
36 }
37
38 # Checks for the existence of the given function by linking
39 #
40 proc cctest_function {function} {
41 cctest -link 1 -declare "extern void $function\(void);" -code "$function\();"
42 }
@@ -68,12 +64,12 @@
68 }
69
70 # @cc-check-sizeof type ...
71 #
72 # Checks the size of the given types (between 1 and 32, inclusive).
73 # Defines a variable with the size determined, or "unknown" otherwise.
74 # e.g. for type 'long long', defines SIZEOF_LONG_LONG.
75 # Returns the size of the last type.
76 #
77 proc cc-check-sizeof {args} {
78 foreach type $args {
79 msg-checking "Checking for sizeof $type..."
@@ -109,11 +105,11 @@
109 return $ret
110 }
111
112 # @cc-check-includes includes ...
113 #
114 # Checks that the given include files can be used
115 proc cc-check-includes {args} {
116 cc-check-some-feature $args {
117 set with {}
118 if {[dict exists $::autosetup(cc-include-deps) $each]} {
119 set deps [dict keys [dict get $::autosetup(cc-include-deps) $each]]
@@ -134,12 +130,12 @@
134 }
135 }
136
137 # @cc-include-needs include required ...
138 #
139 # Ensures that when checking for 'include', a check is first
140 # made for each 'required' file, and if found, it is #included
141 proc cc-include-needs {file args} {
142 foreach depfile $args {
143 dict set ::autosetup(cc-include-deps) $file $depfile 1
144 }
145 }
@@ -153,22 +149,22 @@
153 }
154 }
155
156 # @cc-check-defines define ...
157 #
158 # Checks that the given preprocessor symbol is defined
159 proc cc-check-defines {args} {
160 cc-check-some-feature $args {
161 cctest_define $each
162 }
163 }
164
165 # @cc-check-decls name ...
166 #
167 # Checks that each given name is either a preprocessor symbol or rvalue
168 # such as an enum. Note that the define used is HAVE_DECL_xxx
169 # rather than HAVE_xxx
170 proc cc-check-decls {args} {
171 set ret 1
172 foreach name $args {
173 msg-checking "Checking for $name..."
174 set r [cctest_decl $name]
@@ -183,21 +179,21 @@
183 return $ret
184 }
185
186 # @cc-check-functions function ...
187 #
188 # Checks that the given functions exist (can be linked)
189 proc cc-check-functions {args} {
190 cc-check-some-feature $args {
191 cctest_function $each
192 }
193 }
194
195 # @cc-check-members type.member ...
196 #
197 # Checks that the given type/structure members exist.
198 # A structure member is of the form "struct stat.st_mtime"
199 proc cc-check-members {args} {
200 cc-check-some-feature $args {
201 cctest_member $each
202 }
203 }
@@ -207,20 +203,20 @@
207 # Checks that the given function can be found in one of the libs.
208 #
209 # First checks for no library required, then checks each of the libraries
210 # in turn.
211 #
212 # If the function is found, the feature is defined and lib_$function is defined
213 # to -l$lib where the function was found, or "" if no library required.
214 # In addition, -l$lib is prepended to the LIBS define.
215 #
216 # If additional libraries may be needed for linking, they should be specified
217 # as $extralibs as "-lotherlib1 -lotherlib2".
218 # These libraries are not automatically added to LIBS.
219 #
220 # Returns 1 if found or 0 if not.
221 #
222 proc cc-check-function-in-lib {function libs {otherlibs {}}} {
223 msg-checking "Checking libs for $function..."
224 set found 0
225 cc-with [list -libs $otherlibs] {
226 if {[cctest_function $function]} {
@@ -240,13 +236,12 @@
240 }
241 }
242 }
243 }
244 }
245 if {$found} {
246 define [feature-define-name $function]
247 } else {
248 msg-result "no"
249 }
250 return $found
251 }
252
@@ -253,16 +248,16 @@
253 # @cc-check-tools tool ...
254 #
255 # Checks for existence of the given compiler tools, taking
256 # into account any cross compilation prefix.
257 #
258 # For example, when checking for "ar", first AR is checked on the command
259 # line and then in the environment. If not found, "${host}-ar" or
260 # simply "ar" is assumed depending upon whether cross compiling.
261 # The path is searched for this executable, and if found AR is defined
262 # to the executable name.
263 # Note that even when cross compiling, the simple "ar" is used as a fallback,
264 # but a warning is generated. This is necessary for some toolchains.
265 #
266 # It is an error if the executable is not found.
267 #
268 proc cc-check-tools {args} {
@@ -284,14 +279,14 @@
284
285 # @cc-check-progs prog ...
286 #
287 # Checks for existence of the given executables on the path.
288 #
289 # For example, when checking for "grep", the path is searched for
290 # the executable, 'grep', and if found GREP is defined as "grep".
291 #
292 # If the executable is not found, the variable is defined as false.
293 # Returns 1 if all programs were found, or 0 otherwise.
294 #
295 proc cc-check-progs {args} {
296 set failed 0
297 foreach prog $args {
@@ -303,10 +298,33 @@
303 incr failed
304 } else {
305 msg-result ok
306 define $PROG $prog
307 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
308 }
309 expr {!$failed}
310 }
311
312 # Adds the given settings to $::autosetup(ccsettings) and
@@ -326,18 +344,18 @@
326
327 foreach {name value} $settings {
328 switch -exact -- $name {
329 -cflags - -includes {
330 # These are given as lists
331 lappend new($name) {*}$value
332 }
333 -declare {
334 lappend new($name) $value
335 }
336 -libs {
337 # Note that new libraries are added before previous libraries
338 set new($name) [list {*}$value {*}$new($name)]
339 }
340 -link - -lang - -nooutput {
341 set new($name) $value
342 }
343 -source - -sourcefile - -code {
@@ -373,16 +391,16 @@
373 return $prev
374 }
375
376 # @cc-with settings ?{ script }?
377 #
378 # Sets the given 'cctest' settings and then runs the tests in 'script'.
379 # Note that settings such as -lang replace the current setting, while
380 # those such as -includes are appended to the existing setting.
381 #
382 # If no script is given, the settings become the default for the remainder
383 # of the auto.def file.
384 #
385 ## cc-with {-lang c++} {
386 ## # This will check with the C++ compiler
387 ## cc-check-types bool
388 ## cc-with {-includes signal.h} {
@@ -390,11 +408,11 @@
390 ## ...
391 ## }
392 ## # back to just the C++ compiler
393 ## }
394 #
395 # The -libs setting is special in that newer values are added *before* earlier ones.
396 #
397 ## cc-with {-libs {-lc -lm}} {
398 ## cc-with {-libs -ldl} {
399 ## cctest -libs -lsocket ...
400 ## # libs will be in this order: -lsocket -ldl -lc -lm
@@ -415,12 +433,12 @@
415 return $result
416 }
417 }
418
419 # @cctest ?settings?
420 #
421 # Low level C compiler checker. Compiles and or links a small C program
422 # according to the arguments and returns 1 if OK, or 0 if not.
423 #
424 # Supported settings are:
425 #
426 ## -cflags cflags A list of flags to pass to the compiler
@@ -432,11 +450,11 @@
432 ## -code code Code to compile in the body of main()
433 ## -source code Compile a complete program. Ignore -includes, -declare and -code
434 ## -sourcefile file Shorthand for -source [readfile [get-define srcdir]/$file]
435 ## -nooutput 1 Treat any compiler output (e.g. a warning) as an error
436 #
437 # Unless -source or -sourcefile is specified, the C program looks like:
438 #
439 ## #include <firstinclude> /* same for remaining includes in the list */
440 ##
441 ## declare-code /* any code in -declare, verbatim */
442 ##
@@ -446,11 +464,10 @@
446 ## }
447 #
448 # Any failures are recorded in 'config.log'
449 #
450 proc cctest {args} {
451 set src conftest__.c
452 set tmp conftest__
453
454 # Easiest way to merge in the settings
455 cc-with $args {
456 array set opts [cc-get-settings]
@@ -488,13 +505,15 @@
488 # Build the command line
489 set cmdline {}
490 lappend cmdline {*}[get-define CCACHE]
491 switch -exact -- $opts(-lang) {
492 c++ {
 
493 lappend cmdline {*}[get-define CXX] {*}[get-define CXXFLAGS]
494 }
495 c {
 
496 lappend cmdline {*}[get-define CC] {*}[get-define CFLAGS]
497 }
498 default {
499 autosetup-error "cctest called with unknown language: $opts(-lang)"
500 }
@@ -554,32 +573,32 @@
554 return $ok
555 }
556
557 # @make-autoconf-h outfile ?auto-patterns=HAVE_*? ?bare-patterns=SIZEOF_*?
558 #
559 # Deprecated - see make-config-header
560 proc make-autoconf-h {file {autopatterns {HAVE_*}} {barepatterns {SIZEOF_* HAVE_DECL_*}}} {
561 user-notice "*** make-autoconf-h is deprecated -- use make-config-header instead"
562 make-config-header $file -auto $autopatterns -bare $barepatterns
563 }
564
565 # @make-config-header outfile ?-auto patternlist? ?-bare patternlist? ?-none patternlist? ?-str patternlist? ...
566 #
567 # Examines all defined variables which match the given patterns
568 # and writes an include file, $file, which defines each of these.
569 # Variables which match '-auto' are output as follows:
570 # - defines which have the value "0" are ignored.
571 # - defines which have integer values are defined as the integer value.
572 # - any other value is defined as a string, e.g. "value"
573 # Variables which match '-bare' are defined as-is.
574 # Variables which match '-str' are defined as a string, e.g. "value"
575 # Variables which match '-none' are omitted.
576 #
577 # Note that order is important. The first pattern which matches is selected
578 # Default behaviour is:
579 #
580 # -bare {SIZEOF_* HAVE_DECL_*} -auto HAVE_* -none *
581 #
582 # If the file would be unchanged, it is not written.
583 proc make-config-header {file args} {
584 set guard _[string toupper [regsub -all {[^a-zA-Z0-9]} [file tail $file] _]]
585 file mkdir [file dirname $file]
@@ -677,10 +696,19 @@
677 if {[get-define CC] eq ""} {
678 user-error "Could not find a C compiler. Tried: [join $try ", "]"
679 }
680
681 define CCACHE [find-an-executable [get-env CCACHE ccache]]
 
 
 
 
 
 
 
 
 
682
683 # Initial cctest settings
684 cc-store-settings {-cflags {} -includes {} -declare {} -link 0 -lang c -libs {} -code {} -nooutput 0}
685 set autosetup(cc-include-deps) {}
686
687
688 ELETED autosetup/config.guess
689 ELETED autosetup/config.sub
690 ELETED autosetup/find-tclsh
--- autosetup/cc.tcl
+++ autosetup/cc.tcl
@@ -2,17 +2,18 @@
2 # All rights reserved
3
4 # @synopsis:
5 #
6 # The 'cc' module supports checking various 'features' of the C or C++
7 # compiler/linker environment. Common commands are 'cc-check-includes',
8 # 'cc-check-types', 'cc-check-functions', 'cc-with', 'make-config-header' and 'make-template'.
9 #
10 # The following environment variables are used if set:
11 #
12 ## CC - C compiler
13 ## CXX - C++ compiler
14 ## CPP - C preprocessor
15 ## CCACHE - Set to "none" to disable automatic use of ccache
16 ## CFLAGS - Additional C compiler flags
17 ## CXXFLAGS - Additional C++ compiler flags
18 ## LDFLAGS - Additional compiler flags during linking
19 ## LIBS - Additional libraries to use (for all tests)
@@ -28,15 +29,10 @@
29
30 use system
31
32 module-options {}
33
 
 
 
 
 
34 # Checks for the existence of the given function by linking
35 #
36 proc cctest_function {function} {
37 cctest -link 1 -declare "extern void $function\(void);" -code "$function\();"
38 }
@@ -68,12 +64,12 @@
64 }
65
66 # @cc-check-sizeof type ...
67 #
68 # Checks the size of the given types (between 1 and 32, inclusive).
69 # Defines a variable with the size determined, or 'unknown' otherwise.
70 # e.g. for type 'long long', defines 'SIZEOF_LONG_LONG'.
71 # Returns the size of the last type.
72 #
73 proc cc-check-sizeof {args} {
74 foreach type $args {
75 msg-checking "Checking for sizeof $type..."
@@ -109,11 +105,11 @@
105 return $ret
106 }
107
108 # @cc-check-includes includes ...
109 #
110 # Checks that the given include files can be used.
111 proc cc-check-includes {args} {
112 cc-check-some-feature $args {
113 set with {}
114 if {[dict exists $::autosetup(cc-include-deps) $each]} {
115 set deps [dict keys [dict get $::autosetup(cc-include-deps) $each]]
@@ -134,12 +130,12 @@
130 }
131 }
132
133 # @cc-include-needs include required ...
134 #
135 # Ensures that when checking for '$include', a check is first
136 # made for each '$required' file, and if found, it is included with '#include'.
137 proc cc-include-needs {file args} {
138 foreach depfile $args {
139 dict set ::autosetup(cc-include-deps) $file $depfile 1
140 }
141 }
@@ -153,22 +149,22 @@
149 }
150 }
151
152 # @cc-check-defines define ...
153 #
154 # Checks that the given preprocessor symbols are defined.
155 proc cc-check-defines {args} {
156 cc-check-some-feature $args {
157 cctest_define $each
158 }
159 }
160
161 # @cc-check-decls name ...
162 #
163 # Checks that each given name is either a preprocessor symbol or rvalue
164 # such as an enum. Note that the define used is 'HAVE_DECL_xxx'
165 # rather than 'HAVE_xxx'.
166 proc cc-check-decls {args} {
167 set ret 1
168 foreach name $args {
169 msg-checking "Checking for $name..."
170 set r [cctest_decl $name]
@@ -183,21 +179,21 @@
179 return $ret
180 }
181
182 # @cc-check-functions function ...
183 #
184 # Checks that the given functions exist (can be linked).
185 proc cc-check-functions {args} {
186 cc-check-some-feature $args {
187 cctest_function $each
188 }
189 }
190
191 # @cc-check-members type.member ...
192 #
193 # Checks that the given type/structure members exist.
194 # A structure member is of the form 'struct stat.st_mtime'.
195 proc cc-check-members {args} {
196 cc-check-some-feature $args {
197 cctest_member $each
198 }
199 }
@@ -207,20 +203,20 @@
203 # Checks that the given function can be found in one of the libs.
204 #
205 # First checks for no library required, then checks each of the libraries
206 # in turn.
207 #
208 # If the function is found, the feature is defined and 'lib_$function' is defined
209 # to '-l$lib' where the function was found, or "" if no library required.
210 # In addition, '-l$lib' is prepended to the 'LIBS' define.
211 #
212 # If additional libraries may be needed for linking, they should be specified
213 # with '$extralibs' as '-lotherlib1 -lotherlib2'.
214 # These libraries are not automatically added to 'LIBS'.
215 #
216 # Returns 1 if found or 0 if not.
217 #
218 proc cc-check-function-in-lib {function libs {otherlibs {}}} {
219 msg-checking "Checking libs for $function..."
220 set found 0
221 cc-with [list -libs $otherlibs] {
222 if {[cctest_function $function]} {
@@ -240,13 +236,12 @@
236 }
237 }
238 }
239 }
240 }
241 define-feature $function $found
242 if {!$found} {
 
243 msg-result "no"
244 }
245 return $found
246 }
247
@@ -253,16 +248,16 @@
248 # @cc-check-tools tool ...
249 #
250 # Checks for existence of the given compiler tools, taking
251 # into account any cross compilation prefix.
252 #
253 # For example, when checking for 'ar', first 'AR' is checked on the command
254 # line and then in the environment. If not found, '${host}-ar' or
255 # simply 'ar' is assumed depending upon whether cross compiling.
256 # The path is searched for this executable, and if found 'AR' is defined
257 # to the executable name.
258 # Note that even when cross compiling, the simple 'ar' is used as a fallback,
259 # but a warning is generated. This is necessary for some toolchains.
260 #
261 # It is an error if the executable is not found.
262 #
263 proc cc-check-tools {args} {
@@ -284,14 +279,14 @@
279
280 # @cc-check-progs prog ...
281 #
282 # Checks for existence of the given executables on the path.
283 #
284 # For example, when checking for 'grep', the path is searched for
285 # the executable, 'grep', and if found 'GREP' is defined as 'grep'.
286 #
287 # If the executable is not found, the variable is defined as 'false'.
288 # Returns 1 if all programs were found, or 0 otherwise.
289 #
290 proc cc-check-progs {args} {
291 set failed 0
292 foreach prog $args {
@@ -303,10 +298,33 @@
298 incr failed
299 } else {
300 msg-result ok
301 define $PROG $prog
302 }
303 }
304 expr {!$failed}
305 }
306
307 # @cc-path-progs prog ...
308 #
309 # Like cc-check-progs, but sets the define to the full path rather
310 # than just the program name.
311 #
312 proc cc-path-progs {args} {
313 set failed 0
314 foreach prog $args {
315 set PROG [string toupper $prog]
316 msg-checking "Checking for $prog..."
317 set path [find-executable-path $prog]
318 if {$path eq ""} {
319 msg-result no
320 define $PROG false
321 incr failed
322 } else {
323 msg-result $path
324 define $PROG $path
325 }
326 }
327 expr {!$failed}
328 }
329
330 # Adds the given settings to $::autosetup(ccsettings) and
@@ -326,18 +344,18 @@
344
345 foreach {name value} $settings {
346 switch -exact -- $name {
347 -cflags - -includes {
348 # These are given as lists
349 lappend new($name) {*}[list-non-empty $value]
350 }
351 -declare {
352 lappend new($name) $value
353 }
354 -libs {
355 # Note that new libraries are added before previous libraries
356 set new($name) [list {*}[list-non-empty $value] {*}$new($name)]
357 }
358 -link - -lang - -nooutput {
359 set new($name) $value
360 }
361 -source - -sourcefile - -code {
@@ -373,16 +391,16 @@
391 return $prev
392 }
393
394 # @cc-with settings ?{ script }?
395 #
396 # Sets the given 'cctest' settings and then runs the tests in '$script'.
397 # Note that settings such as '-lang' replace the current setting, while
398 # those such as '-includes' are appended to the existing setting.
399 #
400 # If no script is given, the settings become the default for the remainder
401 # of the 'auto.def' file.
402 #
403 ## cc-with {-lang c++} {
404 ## # This will check with the C++ compiler
405 ## cc-check-types bool
406 ## cc-with {-includes signal.h} {
@@ -390,11 +408,11 @@
408 ## ...
409 ## }
410 ## # back to just the C++ compiler
411 ## }
412 #
413 # The '-libs' setting is special in that newer values are added *before* earlier ones.
414 #
415 ## cc-with {-libs {-lc -lm}} {
416 ## cc-with {-libs -ldl} {
417 ## cctest -libs -lsocket ...
418 ## # libs will be in this order: -lsocket -ldl -lc -lm
@@ -415,12 +433,12 @@
433 return $result
434 }
435 }
436
437 # @cctest ?settings?
438 #
439 # Low level C/C++ compiler checker. Compiles and or links a small C program
440 # according to the arguments and returns 1 if OK, or 0 if not.
441 #
442 # Supported settings are:
443 #
444 ## -cflags cflags A list of flags to pass to the compiler
@@ -432,11 +450,11 @@
450 ## -code code Code to compile in the body of main()
451 ## -source code Compile a complete program. Ignore -includes, -declare and -code
452 ## -sourcefile file Shorthand for -source [readfile [get-define srcdir]/$file]
453 ## -nooutput 1 Treat any compiler output (e.g. a warning) as an error
454 #
455 # Unless '-source' or '-sourcefile' is specified, the C program looks like:
456 #
457 ## #include <firstinclude> /* same for remaining includes in the list */
458 ##
459 ## declare-code /* any code in -declare, verbatim */
460 ##
@@ -446,11 +464,10 @@
464 ## }
465 #
466 # Any failures are recorded in 'config.log'
467 #
468 proc cctest {args} {
 
469 set tmp conftest__
470
471 # Easiest way to merge in the settings
472 cc-with $args {
473 array set opts [cc-get-settings]
@@ -488,13 +505,15 @@
505 # Build the command line
506 set cmdline {}
507 lappend cmdline {*}[get-define CCACHE]
508 switch -exact -- $opts(-lang) {
509 c++ {
510 set src conftest__.cpp
511 lappend cmdline {*}[get-define CXX] {*}[get-define CXXFLAGS]
512 }
513 c {
514 set src conftest__.c
515 lappend cmdline {*}[get-define CC] {*}[get-define CFLAGS]
516 }
517 default {
518 autosetup-error "cctest called with unknown language: $opts(-lang)"
519 }
@@ -554,32 +573,32 @@
573 return $ok
574 }
575
576 # @make-autoconf-h outfile ?auto-patterns=HAVE_*? ?bare-patterns=SIZEOF_*?
577 #
578 # Deprecated - see 'make-config-header'
579 proc make-autoconf-h {file {autopatterns {HAVE_*}} {barepatterns {SIZEOF_* HAVE_DECL_*}}} {
580 user-notice "*** make-autoconf-h is deprecated -- use make-config-header instead"
581 make-config-header $file -auto $autopatterns -bare $barepatterns
582 }
583
584 # @make-config-header outfile ?-auto patternlist? ?-bare patternlist? ?-none patternlist? ?-str patternlist? ...
585 #
586 # Examines all defined variables which match the given patterns
587 # and writes an include file, '$file', which defines each of these.
588 # Variables which match '-auto' are output as follows:
589 # - defines which have the value '0' are ignored.
590 # - defines which have integer values are defined as the integer value.
591 # - any other value is defined as a string, e.g. '"value"'
592 # Variables which match '-bare' are defined as-is.
593 # Variables which match '-str' are defined as a string, e.g. '"value"'
594 # Variables which match '-none' are omitted.
595 #
596 # Note that order is important. The first pattern that matches is selected.
597 # Default behaviour is:
598 #
599 ## -bare {SIZEOF_* HAVE_DECL_*} -auto HAVE_* -none *
600 #
601 # If the file would be unchanged, it is not written.
602 proc make-config-header {file args} {
603 set guard _[string toupper [regsub -all {[^a-zA-Z0-9]} [file tail $file] _]]
604 file mkdir [file dirname $file]
@@ -677,10 +696,19 @@
696 if {[get-define CC] eq ""} {
697 user-error "Could not find a C compiler. Tried: [join $try ", "]"
698 }
699
700 define CCACHE [find-an-executable [get-env CCACHE ccache]]
701
702 # If any of these are set in the environment, propagate them to the AUTOREMAKE commandline
703 foreach i {CC CXX CCACHE CPP CFLAGS CXXFLAGS CXXFLAGS LDFLAGS LIBS CROSS CPPFLAGS LINKFLAGS CC_FOR_BUILD LD} {
704 if {[env-is-set $i]} {
705 # Note: If the variable is set on the command line, get-env will return that value
706 # so the command line will continue to override the environment
707 define-append AUTOREMAKE [quote-if-needed $i=[get-env $i ""]]
708 }
709 }
710
711 # Initial cctest settings
712 cc-store-settings {-cflags {} -includes {} -declare {} -link 0 -lang c -libs {} -code {} -nooutput 0}
713 set autosetup(cc-include-deps) {}
714
715
716 ELETED autosetup/config.guess
717 ELETED autosetup/config.sub
718 ELETED autosetup/find-tclsh
D autosetup/config.guess
-50
--- a/autosetup/config.guess
+++ b/autosetup/config.guess
@@ -1,50 +0,0 @@
1
-#! /bin/sh
2
-# Attempt to guess a canonical system name.
3
-# Copyright 1992-2014 Free Software Found4-11-04it and/or modify it
4
-# under the terms of the GNU General Public License as published by
5
-# t;e Free Software Foundation, either version 3 of the L;cense, or
6
-# (at your option) any later version.
7
-#
8
-# This program is distributed in the hope that it will be useful, but
9
-# WITHOUT ANY WARRANTY; without even the implied warranty of
10
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11
-# General Public License for more details.
12
-#
13
-# You should have received a copy of the GNU General Public License
14
-# along with this program; if not, see <https://www.gnu.org/licenses/>.
15
-#
16
-# As a special exceptionto the GNU General Public License, if you
17
-# distribute this file as part of a program that contains a
18
-# configuration script generated by Autoconf, you may include it under
19
-# the same distribution terms that you use for the rest of that
20
-# program. This Exception is an additional permission under section 7
21
-# of the GNU General Public License, version 3 ("GPLv3").
22
-#
23
-# Originally written by Per Bothner; maintained since 2000 by Ben Elliston.
24
-#
25
-# You can get the latest version of this script from:
26
-# https://git.savannah.gnu.org/guess;hb=HEADeration mode4 Free Software Foundation, Inc.
27
-
28
-$dummy.c$dummy.o $dummy.c{UNAME_SYSTEM}
29
- cat <<-EOF > $dummy.c`$CC_FOR_BUILD -E $dummy.c'^LIBC' | sed 's, ,,g'`{UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}/sbin/$sysctl/usr/sbin/$sysctl
30
-# Attempt to guess a canoniAttempt to g! /bin/sh
31
-# Attemp#*) machine=${! /bin/sh
32
-# Attemp#! /bin/sh
33
-# Attempt to guess a canonical system name.
34
-# Copyright 1992-2018canonical system name.
35
-# Copyrig! /bin/sh
36
-# Attemp#! /b{UNAME_VERSION}${UNAME_REL{machine}-${os}${release}${! /bin/sh
37
-# Attemp#! /bin/sh
38
-# Attempt to guess a ${! /bin/sh
39
-# Attemp#! /bin/sh
40
-# Attempt to guess a cekkoBSD:*:*)
41
- echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE}SolidBSD:*:*)
42
- echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE}${UNAME_RELEASE}${UNAME_MACHINE}-unk"alpha""alpha""alpha""alphaev5"A"alphaev56""alphapca56""alphapca57""alphaev6""alphaev67""alphaev68""alphaev68""alphaev68""alphaev69""alphaev7""alphaev79"${UNAME_MACHINE}-dec-osf`echo RELEASE}'' ''` /bin/sh
43
-# Attempt to guess a canonical system name.
44
-# Copyright 1992-2018 Free Software FouAttempt to guess a canonical system name.
45
-# Copyright 1992-2018 Free Software Foundation, Inc.
46
-
47
-timestamp='2018-03-08it and/or modify it
48
-# under the terms of the GNU General Public License as published by
49
-# t;e Free Software Foundation, either version 3 of the L;cense, or
50
-# (at your o
--- a/autosetup/config.guess
+++ b/autosetup/config.guess
@@ -1,50 +0,0 @@
1 #! /bin/sh
2 # Attempt to guess a canonical system name.
3 # Copyright 1992-2014 Free Software Found4-11-04it and/or modify it
4 # under the terms of the GNU General Public License as published by
5 # t;e Free Software Foundation, either version 3 of the L;cense, or
6 # (at your option) any later version.
7 #
8 # This program is distributed in the hope that it will be useful, but
9 # WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 # General Public License for more details.
12 #
13 # You should have received a copy of the GNU General Public License
14 # along with this program; if not, see <https://www.gnu.org/licenses/>.
15 #
16 # As a special exceptionto the GNU General Public License, if you
17 # distribute this file as part of a program that contains a
18 # configuration script generated by Autoconf, you may include it under
19 # the same distribution terms that you use for the rest of that
20 # program. This Exception is an additional permission under section 7
21 # of the GNU General Public License, version 3 ("GPLv3").
22 #
23 # Originally written by Per Bothner; maintained since 2000 by Ben Elliston.
24 #
25 # You can get the latest version of this script from:
26 # https://git.savannah.gnu.org/guess;hb=HEADeration mode4 Free Software Foundation, Inc.
27
28 $dummy.c$dummy.o $dummy.c{UNAME_SYSTEM}
29 cat <<-EOF > $dummy.c`$CC_FOR_BUILD -E $dummy.c'^LIBC' | sed 's, ,,g'`{UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}/sbin/$sysctl/usr/sbin/$sysctl
30 # Attempt to guess a canoniAttempt to g! /bin/sh
31 # Attemp#*) machine=${! /bin/sh
32 # Attemp#! /bin/sh
33 # Attempt to guess a canonical system name.
34 # Copyright 1992-2018canonical system name.
35 # Copyrig! /bin/sh
36 # Attemp#! /b{UNAME_VERSION}${UNAME_REL{machine}-${os}${release}${! /bin/sh
37 # Attemp#! /bin/sh
38 # Attempt to guess a ${! /bin/sh
39 # Attemp#! /bin/sh
40 # Attempt to guess a cekkoBSD:*:*)
41 echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE}SolidBSD:*:*)
42 echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE}${UNAME_RELEASE}${UNAME_MACHINE}-unk"alpha""alpha""alpha""alphaev5"A"alphaev56""alphapca56""alphapca57""alphaev6""alphaev67""alphaev68""alphaev68""alphaev68""alphaev69""alphaev7""alphaev79"${UNAME_MACHINE}-dec-osf`echo RELEASE}'' ''` /bin/sh
43 # Attempt to guess a canonical system name.
44 # Copyright 1992-2018 Free Software FouAttempt to guess a canonical system name.
45 # Copyright 1992-2018 Free Software Foundation, Inc.
46
47 timestamp='2018-03-08it and/or modify it
48 # under the terms of the GNU General Public License as published by
49 # t;e Free Software Foundation, either version 3 of the L;cense, or
50 # (at your o
--- a/autosetup/config.guess
+++ b/autosetup/config.guess
@@ -1,50 +0,0 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
D autosetup/config.sub
-75
--- a/autosetup/config.sub
+++ b/autosetup/config.sub
@@ -1,75 +0,0 @@
1
-#! /bin/sh
2
-# Configuration validation subroutine script.
3
-# Copyright 1992-2014 Free Software Found4-12-03it and/or modify it
4
-# under the terms of the GNU General Public License as published by
5
-# t;e Free Software Foundation, either version 3 of the L;cense, or
6
-# (at your option) any later version.
7
-#
8
-# This program is distributed in the hope that it will be useful, but
9
-# WITHOUT ANY WARRANTY; without even the implied warranty of
10
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11
-# General Public License for more details.
12
-#
13
-# You should have received a copy of the GNU General Public License
14
-# along with this program; if not, see <https://www.gnu.org/licenses/>.
15
-#
16
-# As a special exception#
17
-# As a special exception to the GNU General Public License, if you
18
-# distribute this file as part of a program that contains a
19
-# configuration script generated by Autoconf, you may include it under
20
-# the same distribution terms that you use for the rest of that
21
-# program. This Exception is an additional permission under section 7
22
-# of the GNU General Public License, version 3 ("GPLv3").
23
-
24
-
25
-# Please send patches to <[email protected]>.
26
-#
27
-# Configuration subroutine to validate and canonicalize a configuration type.
28
-# Supply the specified configuration type as an argument.
29
-# If it is invalid, we print 1 Free Software Foundation,3 Free Software Foundation, Inc.
30
-
31
-'orting which valid configurations
32
-# it does not support. The user should be able to distinguish
33
-# a failure to support;hb=HEAD
34
- $0 [OPTION]f not, see <https:/eration mode a special exception to the GNU General Public License, if you
35
-# distribute this file as part of a program that contains a
36
-# configuration script generated by Autoconf, you may include it under
37
-# the same distribution terms that you use for the rest of that
38
-# program. This Excepti4 Free Software Foundation, Inc.
39
-
40
-er section 7
41
-# of the GNU General Public License, version 3 ("GPLv3").
42
-
43
-
44
-# Please send patches to <[email protected]>.
45
-#
46
-# Configuration subroutine to validate and canonicalize a configuration type.
47
-# Supply the specified configuration type as an argument.
48
-# If it is invalid, we print 1 Free Software Foundation,3 Free Software Foundation, Inc.
49
-
50
-'orting which valid configurations
51
-# it does not support. The user should be able to distinguish
52
-# a failure to support a valid configuration from a meaningless
53
-# configur$1$1$1$1$1$basic_machine !$1$1$1$1$15v6$1$1udk$1! /bin/sh
54
-# Cio$1$1windowsnt/windowsnt/windp11e32k | z8k)
55
- ;;
56
- msbut
57
-# WITHOUT ANY W#! /bin/sh
58
-# Configuration validation subroutine script.
59
-# Copyright 1992-2018 Free Software Foundation, Inc.
60
-
61
-timestamp='2018-03-08it and/or modify it
62
-# under the terms of the GNU General Public License as published by
63
-# t;e Free Software Foundation, either version 3 of the L;cense, or
64
-# (at your option) any later version.
65
-#
66
-# This program is distributed in the hope that it will be useful, but
67
-# WITHOUT ANY WARRANTY; without even the implied warranty of
68
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the $1\': machine \`$basic_machineyramid?unknown$basic_machineu$basic_machine$basic_machine$basic_machine$basic_machinec9c | dpx2*-bull-next)
69
- os=-nextstep3$1$1$1$1i386-vsta | vstabin/sh
70
-# Configuration validation subroutine script.
71
-# Copyright 1992-2018 Free Software Foundation, Inc.
72
-
73
-timestamp='2018-03-08it and/or modify it
74
-# under the terms of the GNU General Public License as published bon subroutine $basic_machine-linuxomron$basic_machine$basic_machine$basic_machine ext$basic_machine$basic_machine$basic_machine$basic_machine$basic_machinepentium4i786-`echo $basic_machinepn$basic_machineppcle | ppc-le | powerpc-littlele$basic_machine$basic_machine | ppc64-le | powerpc64-little64le$basic_machinepsshsh5elh6h64-unknown
75
- ;
--- a/autosetup/config.sub
+++ b/autosetup/config.sub
@@ -1,75 +0,0 @@
1 #! /bin/sh
2 # Configuration validation subroutine script.
3 # Copyright 1992-2014 Free Software Found4-12-03it and/or modify it
4 # under the terms of the GNU General Public License as published by
5 # t;e Free Software Foundation, either version 3 of the L;cense, or
6 # (at your option) any later version.
7 #
8 # This program is distributed in the hope that it will be useful, but
9 # WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 # General Public License for more details.
12 #
13 # You should have received a copy of the GNU General Public License
14 # along with this program; if not, see <https://www.gnu.org/licenses/>.
15 #
16 # As a special exception#
17 # As a special exception to the GNU General Public License, if you
18 # distribute this file as part of a program that contains a
19 # configuration script generated by Autoconf, you may include it under
20 # the same distribution terms that you use for the rest of that
21 # program. This Exception is an additional permission under section 7
22 # of the GNU General Public License, version 3 ("GPLv3").
23
24
25 # Please send patches to <[email protected]>.
26 #
27 # Configuration subroutine to validate and canonicalize a configuration type.
28 # Supply the specified configuration type as an argument.
29 # If it is invalid, we print 1 Free Software Foundation,3 Free Software Foundation, Inc.
30
31 'orting which valid configurations
32 # it does not support. The user should be able to distinguish
33 # a failure to support;hb=HEAD
34 $0 [OPTION]f not, see <https:/eration mode a special exception to the GNU General Public License, if you
35 # distribute this file as part of a program that contains a
36 # configuration script generated by Autoconf, you may include it under
37 # the same distribution terms that you use for the rest of that
38 # program. This Excepti4 Free Software Foundation, Inc.
39
40 er section 7
41 # of the GNU General Public License, version 3 ("GPLv3").
42
43
44 # Please send patches to <[email protected]>.
45 #
46 # Configuration subroutine to validate and canonicalize a configuration type.
47 # Supply the specified configuration type as an argument.
48 # If it is invalid, we print 1 Free Software Foundation,3 Free Software Foundation, Inc.
49
50 'orting which valid configurations
51 # it does not support. The user should be able to distinguish
52 # a failure to support a valid configuration from a meaningless
53 # configur$1$1$1$1$1$basic_machine !$1$1$1$1$15v6$1$1udk$1! /bin/sh
54 # Cio$1$1windowsnt/windowsnt/windp11e32k | z8k)
55 ;;
56 msbut
57 # WITHOUT ANY W#! /bin/sh
58 # Configuration validation subroutine script.
59 # Copyright 1992-2018 Free Software Foundation, Inc.
60
61 timestamp='2018-03-08it and/or modify it
62 # under the terms of the GNU General Public License as published by
63 # t;e Free Software Foundation, either version 3 of the L;cense, or
64 # (at your option) any later version.
65 #
66 # This program is distributed in the hope that it will be useful, but
67 # WITHOUT ANY WARRANTY; without even the implied warranty of
68 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the $1\': machine \`$basic_machineyramid?unknown$basic_machineu$basic_machine$basic_machine$basic_machine$basic_machinec9c | dpx2*-bull-next)
69 os=-nextstep3$1$1$1$1i386-vsta | vstabin/sh
70 # Configuration validation subroutine script.
71 # Copyright 1992-2018 Free Software Foundation, Inc.
72
73 timestamp='2018-03-08it and/or modify it
74 # under the terms of the GNU General Public License as published bon subroutine $basic_machine-linuxomron$basic_machine$basic_machine$basic_machine ext$basic_machine$basic_machine$basic_machine$basic_machine$basic_machinepentium4i786-`echo $basic_machinepn$basic_machineppcle | ppc-le | powerpc-littlele$basic_machine$basic_machine | ppc64-le | powerpc64-little64le$basic_machinepsshsh5elh6h64-unknown
75 ;
--- a/autosetup/config.sub
+++ b/autosetup/config.sub
@@ -1,75 +0,0 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
D autosetup/find-tclsh
-10
--- a/autosetup/find-tclsh
+++ b/autosetup/find-tclsh
@@ -1,10 +0,0 @@
1
-#!/bin/sh
2
-# Looks for a suitable tclsh or jimsh in the PATH
3
-# If not foundstrap jimsh d=`dirname "$0"`
4
-{ "$d/jimshd/${1-ac"; } 2>&1done
5
-echo 1>&2 bootstrap jimsh0"
6
-for cc in tclsh8.7; do
7
- { $tclsh "$d/c"; } 2>&1 >/dev "$d/${1-autosetup--tclsh}"; } 2>/dev/null && exit 0
8
-done
9
-echo 1>&2 "No installed jimsh or tclsh, building local bootstrap jimsh0"
10
-for cc in ${CC_FOR_BUILD:-PATH="$PATH:$d2>/dev/null
--- a/autosetup/find-tclsh
+++ b/autosetup/find-tclsh
@@ -1,10 +0,0 @@
1 #!/bin/sh
2 # Looks for a suitable tclsh or jimsh in the PATH
3 # If not foundstrap jimsh d=`dirname "$0"`
4 { "$d/jimshd/${1-ac"; } 2>&1done
5 echo 1>&2 bootstrap jimsh0"
6 for cc in tclsh8.7; do
7 { $tclsh "$d/c"; } 2>&1 >/dev "$d/${1-autosetup--tclsh}"; } 2>/dev/null && exit 0
8 done
9 echo 1>&2 "No installed jimsh or tclsh, building local bootstrap jimsh0"
10 for cc in ${CC_FOR_BUILD:-PATH="$PATH:$d2>/dev/null
--- a/autosetup/find-tclsh
+++ b/autosetup/find-tclsh
@@ -1,10 +0,0 @@
 
 
 
 
 
 
 
 
 
 
+3701 -3421
--- autosetup/jimsh0.c
+++ autosetup/jimsh0.c
@@ -1,9 +1,7 @@
11
/* This is single source file, bootstrap version of Jim Tcl. See http://jim.tcl.tk/ */
2
-#define _GNU_SOURCE
32
#define JIM_TCL_COMPAT
4
-#define JIM_REFERENCES
53
#define JIM_ANSIC
64
#define JIM_REGEXP
75
#define HAVE_NO_AUTOCONF
86
#define _JIMAUTOCONF_H
97
#define TCL_LIBRARY "."
@@ -31,24 +29,39 @@
3129
#define HAVE_MKDIR_ONE_ARG
3230
#define HAVE_SYSTEM
3331
#define HAVE_SYS_TIME_H
3432
#define HAVE_DIRENT_H
3533
#define HAVE_UNISTD_H
34
+#define HAVE_UMASK
35
+#include <sys/stat.h>
36
+#ifndef S_IRWXG
37
+#define S_IRWXG 0
38
+#endif
39
+#ifndef S_IRWXO
40
+#define S_IRWXO 0
41
+#endif
3642
#else
3743
#define TCL_PLATFORM_OS "unknown"
3844
#define TCL_PLATFORM_PLATFORM "unix"
3945
#define TCL_PLATFORM_PATH_SEPARATOR ":"
46
+#ifdef _MINIX
47
+#define vfork fork
48
+#define _POSIX_SOURCE
49
+#else
50
+#define _GNU_SOURCE
51
+#endif
4052
#define HAVE_VFORK
4153
#define HAVE_WAITPID
4254
#define HAVE_ISATTY
4355
#define HAVE_MKSTEMP
4456
#define HAVE_LINK
4557
#define HAVE_SYS_TIME_H
4658
#define HAVE_DIRENT_H
4759
#define HAVE_UNISTD_H
60
+#define HAVE_UMASK
4861
#endif
49
-#define JIM_VERSION 76
62
+#define JIM_VERSION 78
5063
#ifndef JIM_WIN32COMPAT_H
5164
#define JIM_WIN32COMPAT_H
5265
5366
5467
@@ -88,11 +101,10 @@
88101
#define JIM_WIDE_MIN LLONG_MIN
89102
#define JIM_WIDE_MAX LLONG_MAX
90103
#define JIM_WIDE_MODIFIER "I64d"
91104
#define strcasecmp _stricmp
92105
#define strtoull _strtoui64
93
-#define snprintf _snprintf
94106
95107
#include <io.h>
96108
97109
struct timeval {
98110
long tv_sec;
@@ -105,29 +117,24 @@
105117
struct dirent {
106118
char *d_name;
107119
};
108120
109121
typedef struct DIR {
110
- long handle;
122
+ long handle;
111123
struct _finddata_t info;
112
- struct dirent result;
113
- char *name;
124
+ struct dirent result;
125
+ char *name;
114126
} DIR;
115127
116128
DIR *opendir(const char *name);
117129
int closedir(DIR *dir);
118130
struct dirent *readdir(DIR *dir);
119131
120
-#elif defined(__MINGW32__)
121
-
122
-#include <stdlib.h>
123
-#define strtod __strtod
132
+#endif
124133
125134
#endif
126135
127
-#endif
128
-
129136
#ifdef __cplusplus
130137
}
131138
#endif
132139
133140
#endif
@@ -146,19 +153,21 @@
146153
147154
#ifndef JIM_UTF8
148155
#include <ctype.h>
149156
150157
151
-#define utf8_strlen(S, B) ((B) < 0 ? strlen(S) : (B))
158
+#define utf8_strlen(S, B) ((B) < 0 ? (int)strlen(S) : (B))
159
+#define utf8_strwidth(S, B) utf8_strlen((S), (B))
152160
#define utf8_tounicode(S, CP) (*(CP) = (unsigned char)*(S), 1)
153161
#define utf8_getchars(CP, C) (*(CP) = (C), 1)
154162
#define utf8_upper(C) toupper(C)
155163
#define utf8_title(C) toupper(C)
156164
#define utf8_lower(C) tolower(C)
157165
#define utf8_index(C, I) (I)
158166
#define utf8_charlen(C) 1
159167
#define utf8_prev_len(S, L) 1
168
+#define utf8_width(C) 1
160169
161170
#else
162171
163172
#endif
164173
@@ -175,13 +184,13 @@
175184
extern "C" {
176185
#endif
177186
178187
#include <time.h>
179188
#include <limits.h>
180
-#include <stdio.h>
181
-#include <stdlib.h>
182
-#include <stdarg.h>
189
+#include <stdio.h>
190
+#include <stdlib.h>
191
+#include <stdarg.h>
183192
184193
185194
#ifndef HAVE_NO_AUTOCONF
186195
#endif
187196
@@ -224,31 +233,31 @@
224233
#define JIM_SIGNAL 5
225234
#define JIM_EXIT 6
226235
227236
#define JIM_EVAL 7
228237
229
-#define JIM_MAX_CALLFRAME_DEPTH 1000
230
-#define JIM_MAX_EVAL_DEPTH 2000
238
+#define JIM_MAX_CALLFRAME_DEPTH 1000
239
+#define JIM_MAX_EVAL_DEPTH 2000
231240
232241
233242
#define JIM_PRIV_FLAG_SHIFT 20
234243
235
-#define JIM_NONE 0
236
-#define JIM_ERRMSG 1
237
-#define JIM_ENUM_ABBREV 2
238
-#define JIM_UNSHARED 4
239
-#define JIM_MUSTEXIST 8
240
-
241
-
242
-#define JIM_SUBST_NOVAR 1
243
-#define JIM_SUBST_NOCMD 2
244
-#define JIM_SUBST_NOESC 4
245
-#define JIM_SUBST_FLAG 128
246
-
247
-
248
-#define JIM_CASESENS 0
249
-#define JIM_NOCASE 1
244
+#define JIM_NONE 0
245
+#define JIM_ERRMSG 1
246
+#define JIM_ENUM_ABBREV 2
247
+#define JIM_UNSHARED 4
248
+#define JIM_MUSTEXIST 8
249
+
250
+
251
+#define JIM_SUBST_NOVAR 1
252
+#define JIM_SUBST_NOCMD 2
253
+#define JIM_SUBST_NOESC 4
254
+#define JIM_SUBST_FLAG 128
255
+
256
+
257
+#define JIM_CASESENS 0
258
+#define JIM_NOCASE 1
250259
251260
252261
#define JIM_PATH_LEN 1024
253262
254263
@@ -339,79 +348,80 @@
339348
#define Jim_GetHashTableSize(ht) ((ht)->size)
340349
#define Jim_GetHashTableUsed(ht) ((ht)->used)
341350
342351
343352
typedef struct Jim_Obj {
344
- char *bytes;
345
- const struct Jim_ObjType *typePtr;
346
- int refCount;
347
- int length;
348
-
353
+ char *bytes;
354
+ const struct Jim_ObjType *typePtr;
355
+ int refCount;
356
+ int length;
357
+
349358
union {
350
-
359
+
351360
jim_wide wideValue;
352
-
361
+
353362
int intValue;
354
-
363
+
355364
double doubleValue;
356
-
365
+
357366
void *ptr;
358
-
367
+
359368
struct {
360369
void *ptr1;
361370
void *ptr2;
362371
} twoPtrValue;
363
-
372
+
373
+ struct {
374
+ void *ptr;
375
+ int int1;
376
+ int int2;
377
+ } ptrIntValue;
378
+
364379
struct {
365380
struct Jim_Var *varPtr;
366
- unsigned long callFrameId;
367
- int global;
381
+ unsigned long callFrameId;
382
+ int global;
368383
} varValue;
369
-
384
+
370385
struct {
371386
struct Jim_Obj *nsObj;
372387
struct Jim_Cmd *cmdPtr;
373
- unsigned long procEpoch;
388
+ unsigned long procEpoch;
374389
} cmdValue;
375
-
390
+
376391
struct {
377
- struct Jim_Obj **ele;
378
- int len;
379
- int maxLen;
392
+ struct Jim_Obj **ele;
393
+ int len;
394
+ int maxLen;
380395
} listValue;
381
-
396
+
382397
struct {
383398
int maxLength;
384
- int charLength;
399
+ int charLength;
385400
} strValue;
386
-
401
+
387402
struct {
388403
unsigned long id;
389404
struct Jim_Reference *refPtr;
390405
} refValue;
391
-
406
+
392407
struct {
393408
struct Jim_Obj *fileNameObj;
394409
int lineNumber;
395410
} sourceValue;
396
-
411
+
397412
struct {
398413
struct Jim_Obj *varNameObjPtr;
399414
struct Jim_Obj *indexObjPtr;
400415
} dictSubstValue;
401
-
402
- struct {
403
- void *compre;
404
- unsigned flags;
405
- } regexpValue;
406416
struct {
407417
int line;
408418
int argc;
409419
} scriptLineValue;
410420
} internalRep;
411
- struct Jim_Obj *prevObjPtr;
412
- struct Jim_Obj *nextObjPtr;
421
+ struct Jim_Obj *prevObjPtr;
422
+ struct Jim_Obj *nextObjPtr;
413423
} Jim_Obj;
414424
415425
416426
#define Jim_IncrRefCount(objPtr) \
417427
++(objPtr)->refCount
@@ -442,40 +452,40 @@
442452
typedef void (Jim_DupInternalRepProc)(struct Jim_Interp *interp,
443453
struct Jim_Obj *srcPtr, Jim_Obj *dupPtr);
444454
typedef void (Jim_UpdateStringProc)(struct Jim_Obj *objPtr);
445455
446456
typedef struct Jim_ObjType {
447
- const char *name;
457
+ const char *name;
448458
Jim_FreeInternalRepProc *freeIntRepProc;
449459
Jim_DupInternalRepProc *dupIntRepProc;
450460
Jim_UpdateStringProc *updateStringProc;
451461
int flags;
452462
} Jim_ObjType;
453463
454464
455
-#define JIM_TYPE_NONE 0
456
-#define JIM_TYPE_REFERENCES 1
465
+#define JIM_TYPE_NONE 0
466
+#define JIM_TYPE_REFERENCES 1
457467
458468
459469
460470
typedef struct Jim_CallFrame {
461
- unsigned long id;
462
- int level;
463
- struct Jim_HashTable vars;
464
- struct Jim_HashTable *staticVars;
465
- struct Jim_CallFrame *parent;
466
- Jim_Obj *const *argv;
467
- int argc;
468
- Jim_Obj *procArgsObjPtr;
469
- Jim_Obj *procBodyObjPtr;
470
- struct Jim_CallFrame *next;
471
- Jim_Obj *nsObj;
472
- Jim_Obj *fileNameObj;
471
+ unsigned long id;
472
+ int level;
473
+ struct Jim_HashTable vars;
474
+ struct Jim_HashTable *staticVars;
475
+ struct Jim_CallFrame *parent;
476
+ Jim_Obj *const *argv;
477
+ int argc;
478
+ Jim_Obj *procArgsObjPtr;
479
+ Jim_Obj *procBodyObjPtr;
480
+ struct Jim_CallFrame *next;
481
+ Jim_Obj *nsObj;
482
+ Jim_Obj *fileNameObj;
473483
int line;
474
- Jim_Stack *localCommands;
475
- struct Jim_Obj *tailcallObj;
476
- struct Jim_Cmd *tailcallCmd;
484
+ Jim_Stack *localCommands;
485
+ struct Jim_Obj *tailcallObj;
486
+ struct Jim_Cmd *tailcallCmd;
477487
} Jim_CallFrame;
478488
479489
typedef struct Jim_Var {
480490
Jim_Obj *objPtr;
481491
struct Jim_CallFrame *linkFramePtr;
@@ -487,35 +497,35 @@
487497
typedef void Jim_DelCmdProc(struct Jim_Interp *interp, void *privData);
488498
489499
490500
491501
typedef struct Jim_Cmd {
492
- int inUse;
493
- int isproc;
494
- struct Jim_Cmd *prevCmd;
502
+ int inUse;
503
+ int isproc;
504
+ struct Jim_Cmd *prevCmd;
495505
union {
496506
struct {
497
-
498
- Jim_CmdProc *cmdProc;
499
- Jim_DelCmdProc *delProc;
500
- void *privData;
507
+
508
+ Jim_CmdProc *cmdProc;
509
+ Jim_DelCmdProc *delProc;
510
+ void *privData;
501511
} native;
502512
struct {
503
-
513
+
504514
Jim_Obj *argListObjPtr;
505515
Jim_Obj *bodyObjPtr;
506
- Jim_HashTable *staticVars;
507
- int argListLen;
508
- int reqArity;
509
- int optArity;
510
- int argsPos;
511
- int upcall;
516
+ Jim_HashTable *staticVars;
517
+ int argListLen;
518
+ int reqArity;
519
+ int optArity;
520
+ int argsPos;
521
+ int upcall;
512522
struct Jim_ProcArg {
513
- Jim_Obj *nameObjPtr;
514
- Jim_Obj *defaultObjPtr;
523
+ Jim_Obj *nameObjPtr;
524
+ Jim_Obj *defaultObjPtr;
515525
} *arglist;
516
- Jim_Obj *nsObj;
526
+ Jim_Obj *nsObj;
517527
} proc;
518528
} u;
519529
} Jim_Cmd;
520530
521531
@@ -523,64 +533,64 @@
523533
unsigned char sbox[256];
524534
unsigned int i, j;
525535
} Jim_PrngState;
526536
527537
typedef struct Jim_Interp {
528
- Jim_Obj *result;
529
- int errorLine;
530
- Jim_Obj *errorFileNameObj;
531
- int addStackTrace;
532
- int maxCallFrameDepth;
533
- int maxEvalDepth;
534
- int evalDepth;
535
- int returnCode;
536
- int returnLevel;
537
- int exitCode;
538
- long id;
539
- int signal_level;
540
- jim_wide sigmask;
541
- int (*signal_set_result)(struct Jim_Interp *interp, jim_wide sigmask);
542
- Jim_CallFrame *framePtr;
543
- Jim_CallFrame *topFramePtr;
544
- struct Jim_HashTable commands;
538
+ Jim_Obj *result;
539
+ int errorLine;
540
+ Jim_Obj *errorFileNameObj;
541
+ int addStackTrace;
542
+ int maxCallFrameDepth;
543
+ int maxEvalDepth;
544
+ int evalDepth;
545
+ int returnCode;
546
+ int returnLevel;
547
+ int exitCode;
548
+ long id;
549
+ int signal_level;
550
+ jim_wide sigmask;
551
+ int (*signal_set_result)(struct Jim_Interp *interp, jim_wide sigmask);
552
+ Jim_CallFrame *framePtr;
553
+ Jim_CallFrame *topFramePtr;
554
+ struct Jim_HashTable commands;
545555
unsigned long procEpoch; /* Incremented every time the result
546556
of procedures names lookup caching
547557
may no longer be valid. */
548558
unsigned long callFrameEpoch; /* Incremented every time a new
549559
callframe is created. This id is used for the
550560
'ID' field contained in the Jim_CallFrame
551561
structure. */
552
- int local;
553
- Jim_Obj *liveList;
554
- Jim_Obj *freeList;
555
- Jim_Obj *currentScriptObj;
556
- Jim_Obj *nullScriptObj;
557
- Jim_Obj *emptyObj;
558
- Jim_Obj *trueObj;
559
- Jim_Obj *falseObj;
560
- unsigned long referenceNextId;
561
- struct Jim_HashTable references;
562
+ int local;
563
+ Jim_Obj *liveList;
564
+ Jim_Obj *freeList;
565
+ Jim_Obj *currentScriptObj;
566
+ Jim_Obj *nullScriptObj;
567
+ Jim_Obj *emptyObj;
568
+ Jim_Obj *trueObj;
569
+ Jim_Obj *falseObj;
570
+ unsigned long referenceNextId;
571
+ struct Jim_HashTable references;
562572
unsigned long lastCollectId; /* reference max Id of the last GC
563
- execution. It's set to -1 while the collection
573
+ execution. It's set to ~0 while the collection
564574
is running as sentinel to avoid to recursive
565575
calls via the [collect] command inside
566576
finalizers. */
567
- time_t lastCollectTime;
568
- Jim_Obj *stackTrace;
569
- Jim_Obj *errorProc;
570
- Jim_Obj *unknown;
571
- int unknown_called;
572
- int errorFlag;
577
+ time_t lastCollectTime;
578
+ Jim_Obj *stackTrace;
579
+ Jim_Obj *errorProc;
580
+ Jim_Obj *unknown;
581
+ int unknown_called;
582
+ int errorFlag;
573583
void *cmdPrivData; /* Used to pass the private data pointer to
574584
a command. It is set to what the user specified
575585
via Jim_CreateCommand(). */
576586
577
- struct Jim_CallFrame *freeFramesList;
578
- struct Jim_HashTable assocData;
579
- Jim_PrngState *prngState;
580
- struct Jim_HashTable packages;
581
- Jim_Stack *loadHandles;
587
+ struct Jim_CallFrame *freeFramesList;
588
+ struct Jim_HashTable assocData;
589
+ Jim_PrngState *prngState;
590
+ struct Jim_HashTable packages;
591
+ Jim_Stack *loadHandles;
582592
} Jim_Interp;
583593
584594
#define Jim_InterpIncrProcEpoch(i) (i)->procEpoch++
585595
#define Jim_SetResultString(i,s,l) Jim_SetResult(i, Jim_NewStringObj(i,s,l))
586596
#define Jim_SetResultInt(i,intval) Jim_SetResult(i, Jim_NewIntObj(i,intval))
@@ -623,11 +633,11 @@
623633
JIM_EXPORT char *Jim_StrDupLen(const char *s, int l);
624634
625635
626636
JIM_EXPORT char **Jim_GetEnviron(void);
627637
JIM_EXPORT void Jim_SetEnviron(char **env);
628
-JIM_EXPORT int Jim_MakeTempFile(Jim_Interp *interp, const char *template);
638
+JIM_EXPORT int Jim_MakeTempFile(Jim_Interp *interp, const char *filename_template, int unlink_file);
629639
630640
631641
JIM_EXPORT int Jim_Eval(Jim_Interp *interp, const char *script);
632642
633643
@@ -816,25 +826,33 @@
816826
Jim_Obj *newObjPtr, int flags);
817827
JIM_EXPORT int Jim_DictPairs(Jim_Interp *interp,
818828
Jim_Obj *dictPtr, Jim_Obj ***objPtrPtr, int *len);
819829
JIM_EXPORT int Jim_DictAddElement(Jim_Interp *interp, Jim_Obj *objPtr,
820830
Jim_Obj *keyObjPtr, Jim_Obj *valueObjPtr);
821
-JIM_EXPORT int Jim_DictKeys(Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj *patternObj);
822
-JIM_EXPORT int Jim_DictValues(Jim_Interp *interp, Jim_Obj *dictObjPtr, Jim_Obj *patternObjPtr);
831
+
832
+#define JIM_DICTMATCH_KEYS 0x0001
833
+#define JIM_DICTMATCH_VALUES 0x002
834
+
835
+JIM_EXPORT int Jim_DictMatchTypes(Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj *patternObj, int match_type, int return_types);
823836
JIM_EXPORT int Jim_DictSize(Jim_Interp *interp, Jim_Obj *objPtr);
824837
JIM_EXPORT int Jim_DictInfo(Jim_Interp *interp, Jim_Obj *objPtr);
838
+JIM_EXPORT Jim_Obj *Jim_DictMerge(Jim_Interp *interp, int objc, Jim_Obj *const *objv);
825839
826840
827841
JIM_EXPORT int Jim_GetReturnCode (Jim_Interp *interp, Jim_Obj *objPtr,
828842
int *intPtr);
829843
830844
831845
JIM_EXPORT int Jim_EvalExpression (Jim_Interp *interp,
832
- Jim_Obj *exprObjPtr, Jim_Obj **exprResultPtrPtr);
846
+ Jim_Obj *exprObjPtr);
833847
JIM_EXPORT int Jim_GetBoolFromExpr (Jim_Interp *interp,
834848
Jim_Obj *exprObjPtr, int *boolPtr);
835849
850
+
851
+JIM_EXPORT int Jim_GetBoolean(Jim_Interp *interp, Jim_Obj *objPtr,
852
+ int *booleanPtr);
853
+
836854
837855
JIM_EXPORT int Jim_GetWide (Jim_Interp *interp, Jim_Obj *objPtr,
838856
jim_wide *widePtr);
839857
JIM_EXPORT int Jim_GetLong (Jim_Interp *interp, Jim_Obj *objPtr,
840858
long *longPtr);
@@ -852,10 +870,12 @@
852870
853871
JIM_EXPORT void Jim_WrongNumArgs (Jim_Interp *interp, int argc,
854872
Jim_Obj *const *argv, const char *msg);
855873
JIM_EXPORT int Jim_GetEnum (Jim_Interp *interp, Jim_Obj *objPtr,
856874
const char * const *tablePtr, int *indexPtr, const char *name, int flags);
875
+JIM_EXPORT int Jim_CheckShowCommands(Jim_Interp *interp, Jim_Obj *objPtr,
876
+ const char *const *tablePtr);
857877
JIM_EXPORT int Jim_ScriptIsComplete(Jim_Interp *interp,
858878
Jim_Obj *scriptObj, char *stateCharPtr);
859879
860880
JIM_EXPORT int Jim_FindByName(const char *name, const char * const array[], size_t len);
861881
@@ -878,11 +898,12 @@
878898
879899
880900
JIM_EXPORT int Jim_InteractivePrompt (Jim_Interp *interp);
881901
JIM_EXPORT void Jim_HistoryLoad(const char *filename);
882902
JIM_EXPORT void Jim_HistorySave(const char *filename);
883
-JIM_EXPORT char *Jim_HistoryGetline(const char *prompt);
903
+JIM_EXPORT char *Jim_HistoryGetline(Jim_Interp *interp, const char *prompt);
904
+JIM_EXPORT void Jim_HistorySetCompletion(Jim_Interp *interp, Jim_Obj *commandObj);
884905
JIM_EXPORT void Jim_HistoryAdd(const char *line);
885906
JIM_EXPORT void Jim_HistoryShow(void);
886907
887908
888909
JIM_EXPORT int Jim_InitStaticExtensions(Jim_Interp *interp);
@@ -904,11 +925,11 @@
904925
905926
#ifdef __cplusplus
906927
}
907928
#endif
908929
909
-#endif
930
+#endif
910931
911932
#ifndef JIM_SUBCMD_H
912933
#define JIM_SUBCMD_H
913934
914935
@@ -915,24 +936,24 @@
915936
#ifdef __cplusplus
916937
extern "C" {
917938
#endif
918939
919940
920
-#define JIM_MODFLAG_HIDDEN 0x0001
921
-#define JIM_MODFLAG_FULLARGV 0x0002
941
+#define JIM_MODFLAG_HIDDEN 0x0001
942
+#define JIM_MODFLAG_FULLARGV 0x0002
922943
923944
924945
925946
typedef int jim_subcmd_function(Jim_Interp *interp, int argc, Jim_Obj *const *argv);
926947
927948
typedef struct {
928
- const char *cmd;
929
- const char *args;
930
- jim_subcmd_function *function;
931
- short minargs;
932
- short maxargs;
933
- unsigned short flags;
949
+ const char *cmd;
950
+ const char *args;
951
+ jim_subcmd_function *function;
952
+ short minargs;
953
+ short maxargs;
954
+ unsigned short flags;
934955
} jim_subcmd_type;
935956
936957
const jim_subcmd_type *
937958
Jim_ParseSubCmd(Jim_Interp *interp, const jim_subcmd_type *command_table, int argc, Jim_Obj *const *argv);
938959
@@ -960,36 +981,36 @@
960981
int rm_eo;
961982
} regmatch_t;
962983
963984
964985
typedef struct regexp {
965
-
966
- int re_nsub;
967
-
968
-
969
- int cflags;
970
- int err;
971
- int regstart;
972
- int reganch;
973
- int regmust;
974
- int regmlen;
975
- int *program;
976
-
977
-
978
- const char *regparse;
979
- int p;
980
- int proglen;
981
-
982
-
983
- int eflags;
984
- const char *start;
985
- const char *reginput;
986
- const char *regbol;
987
-
988
-
989
- regmatch_t *pmatch;
990
- int nmatch;
986
+
987
+ int re_nsub;
988
+
989
+
990
+ int cflags;
991
+ int err;
992
+ int regstart;
993
+ int reganch;
994
+ int regmust;
995
+ int regmlen;
996
+ int *program;
997
+
998
+
999
+ const char *regparse;
1000
+ int p;
1001
+ int proglen;
1002
+
1003
+
1004
+ int eflags;
1005
+ const char *start;
1006
+ const char *reginput;
1007
+ const char *regbol;
1008
+
1009
+
1010
+ regmatch_t *pmatch;
1011
+ int nmatch;
9911012
} regexp;
9921013
9931014
typedef regexp regex_t;
9941015
9951016
#define REG_EXTENDED 0
@@ -997,13 +1018,13 @@
9971018
#define REG_ICASE 2
9981019
9991020
#define REG_NOTBOL 16
10001021
10011022
enum {
1002
- REG_NOERROR,
1003
- REG_NOMATCH,
1004
- REG_BADPAT,
1023
+ REG_NOERROR,
1024
+ REG_NOMATCH,
1025
+ REG_BADPAT,
10051026
REG_ERR_NULL_ARGUMENT,
10061027
REG_ERR_UNKNOWN,
10071028
REG_ERR_TOO_BIG,
10081029
REG_ERR_NOMEM,
10091030
REG_ERR_TOO_MANY_PAREN,
@@ -1028,24 +1049,101 @@
10281049
10291050
#ifdef __cplusplus
10301051
}
10311052
#endif
10321053
1054
+#endif
1055
+#ifndef JIM_SIGNAL_H
1056
+#define JIM_SIGNAL_H
1057
+
1058
+#ifdef __cplusplus
1059
+extern "C" {
1060
+#endif
1061
+
1062
+const char *Jim_SignalId(int sig);
1063
+
1064
+#ifdef __cplusplus
1065
+}
1066
+#endif
1067
+
1068
+#endif
1069
+#ifndef JIMIOCOMPAT_H
1070
+#define JIMIOCOMPAT_H
1071
+
1072
+
1073
+#include <stdio.h>
1074
+#include <errno.h>
1075
+
1076
+
1077
+void Jim_SetResultErrno(Jim_Interp *interp, const char *msg);
1078
+
1079
+int Jim_OpenForWrite(const char *filename, int append);
1080
+
1081
+int Jim_OpenForRead(const char *filename);
1082
+
1083
+#if defined(__MINGW32__)
1084
+ #ifndef STRICT
1085
+ #define STRICT
1086
+ #endif
1087
+ #define WIN32_LEAN_AND_MEAN
1088
+ #include <windows.h>
1089
+ #include <fcntl.h>
1090
+ #include <io.h>
1091
+ #include <process.h>
1092
+
1093
+ typedef HANDLE pidtype;
1094
+ #define JIM_BAD_PID INVALID_HANDLE_VALUE
1095
+
1096
+ #define JIM_NO_PID INVALID_HANDLE_VALUE
1097
+
1098
+
1099
+ #define WIFEXITED(STATUS) (((STATUS) & 0xff00) == 0)
1100
+ #define WEXITSTATUS(STATUS) ((STATUS) & 0x00ff)
1101
+ #define WIFSIGNALED(STATUS) (((STATUS) & 0xff00) != 0)
1102
+ #define WTERMSIG(STATUS) (((STATUS) >> 8) & 0xff)
1103
+ #define WNOHANG 1
1104
+
1105
+ int Jim_Errno(void);
1106
+ pidtype waitpid(pidtype pid, int *status, int nohang);
1107
+
1108
+ #define HAVE_PIPE
1109
+ #define pipe(P) _pipe((P), 0, O_NOINHERIT)
1110
+
1111
+#elif defined(HAVE_UNISTD_H)
1112
+ #include <unistd.h>
1113
+ #include <fcntl.h>
1114
+ #include <sys/wait.h>
1115
+ #include <sys/stat.h>
1116
+
1117
+ typedef int pidtype;
1118
+ #define Jim_Errno() errno
1119
+ #define JIM_BAD_PID -1
1120
+ #define JIM_NO_PID 0
1121
+
1122
+ #ifndef HAVE_EXECVPE
1123
+ #define execvpe(ARG0, ARGV, ENV) execvp(ARG0, ARGV)
1124
+ #endif
1125
+#endif
1126
+
10331127
#endif
10341128
int Jim_bootstrapInit(Jim_Interp *interp)
10351129
{
10361130
if (Jim_PackageProvide(interp, "bootstrap", "1.0", JIM_ERRMSG))
10371131
return JIM_ERR;
10381132
10391133
return Jim_EvalSource(interp, "bootstrap.tcl", 1,
10401134
"\n"
10411135
"\n"
1042
-"proc package {cmd pkg} {\n"
1136
+"proc package {cmd pkg args} {\n"
10431137
" if {$cmd eq \"require\"} {\n"
10441138
" foreach path $::auto_path {\n"
1045
-" if {[file exists $path/$pkg.tcl]} {\n"
1046
-" uplevel #0 [list source $path/$pkg.tcl]\n"
1139
+" set pkgpath $path/$pkg.tcl\n"
1140
+" if {$path eq \".\"} {\n"
1141
+" set pkgpath $pkg.tcl\n"
1142
+" }\n"
1143
+" if {[file exists $pkgpath]} {\n"
1144
+" uplevel #0 [list source $pkgpath]\n"
10471145
" return\n"
10481146
" }\n"
10491147
" }\n"
10501148
" }\n"
10511149
"}\n"
@@ -1100,10 +1198,43 @@
11001198
"\n"
11011199
"if {$tcl_platform(platform) eq \"windows\"} {\n"
11021200
" set jim::argv0 [string map {\\\\ /} $jim::argv0]\n"
11031201
"}\n"
11041202
"\n"
1203
+"\n"
1204
+"set tcl::autocomplete_commands {info tcl::prefix socket namespace array clock file package string dict signal history}\n"
1205
+"\n"
1206
+"\n"
1207
+"\n"
1208
+"proc tcl::autocomplete {prefix} {\n"
1209
+" if {[set space [string first \" \" $prefix]] != -1} {\n"
1210
+" set cmd [string range $prefix 0 $space-1]\n"
1211
+" if {$cmd in $::tcl::autocomplete_commands || [info channel $cmd] ne \"\"} {\n"
1212
+" set arg [string range $prefix $space+1 end]\n"
1213
+"\n"
1214
+" return [lmap p [$cmd -commands] {\n"
1215
+" if {![string match \"${arg}*\" $p]} continue\n"
1216
+" function \"$cmd $p\"\n"
1217
+" }]\n"
1218
+" }\n"
1219
+" }\n"
1220
+"\n"
1221
+" if {[string match \"source *\" $prefix]} {\n"
1222
+" set path [string range $prefix 7 end]\n"
1223
+" return [lmap p [glob -nocomplain \"${path}*\"] {\n"
1224
+" function \"source $p\"\n"
1225
+" }]\n"
1226
+" }\n"
1227
+"\n"
1228
+" return [lmap p [lsort [info commands $prefix*]] {\n"
1229
+" if {[string match \"* *\" $p]} {\n"
1230
+" continue\n"
1231
+" }\n"
1232
+" function $p\n"
1233
+" }]\n"
1234
+"}\n"
1235
+"\n"
11051236
"_jimsh_init\n"
11061237
);
11071238
}
11081239
int Jim_globInit(Jim_Interp *interp)
11091240
{
@@ -1315,10 +1446,17 @@
13151446
return JIM_ERR;
13161447
13171448
return Jim_EvalSource(interp, "stdlib.tcl", 1,
13181449
"\n"
13191450
"\n"
1451
+"if {![exists -command ref]} {\n"
1452
+"\n"
1453
+" proc ref {args} {{count 0}} {\n"
1454
+" format %08x [incr count]\n"
1455
+" }\n"
1456
+"}\n"
1457
+"\n"
13201458
"\n"
13211459
"proc lambda {arglist args} {\n"
13221460
" tailcall proc [ref {} function lambda.finalizer] $arglist {*}$args\n"
13231461
"}\n"
13241462
"\n"
@@ -1375,10 +1513,17 @@
13751513
" }\n"
13761514
" join $lines \\n\n"
13771515
"}\n"
13781516
"\n"
13791517
"\n"
1518
+"\n"
1519
+"proc defer {script} {\n"
1520
+" upvar jim::defer v\n"
1521
+" lappend v $script\n"
1522
+"}\n"
1523
+"\n"
1524
+"\n"
13801525
"\n"
13811526
"proc errorInfo {msg {stacktrace \"\"}} {\n"
13821527
" if {$stacktrace eq \"\"} {\n"
13831528
"\n"
13841529
" set stacktrace [info stacktrace]\n"
@@ -1402,31 +1547,10 @@
14021547
" if {[exists ::jim::exe]} {\n"
14031548
" return $::jim::exe\n"
14041549
" }\n"
14051550
"}\n"
14061551
"\n"
1407
-"\n"
1408
-"proc {dict with} {&dictVar {args key} script} {\n"
1409
-" set keys {}\n"
1410
-" foreach {n v} [dict get $dictVar {*}$key] {\n"
1411
-" upvar $n var_$n\n"
1412
-" set var_$n $v\n"
1413
-" lappend keys $n\n"
1414
-" }\n"
1415
-" catch {uplevel 1 $script} msg opts\n"
1416
-" if {[info exists dictVar] && ([llength $key] == 0 || [dict exists $dictVar {*}$key])} {\n"
1417
-" foreach n $keys {\n"
1418
-" if {[info exists var_$n]} {\n"
1419
-" dict set dictVar {*}$key $n [set var_$n]\n"
1420
-" } else {\n"
1421
-" dict unset dictVar {*}$key $n\n"
1422
-" }\n"
1423
-" }\n"
1424
-" }\n"
1425
-" return {*}$opts $msg\n"
1426
-"}\n"
1427
-"\n"
14281552
"\n"
14291553
"proc {dict update} {&varName args script} {\n"
14301554
" set keys {}\n"
14311555
" foreach {n v} $args {\n"
14321556
" upvar $v var_$v\n"
@@ -1445,23 +1569,10 @@
14451569
" }\n"
14461570
" }\n"
14471571
" return {*}$opts $msg\n"
14481572
"}\n"
14491573
"\n"
1450
-"\n"
1451
-"\n"
1452
-"proc {dict merge} {dict args} {\n"
1453
-" foreach d $args {\n"
1454
-"\n"
1455
-" dict size $d\n"
1456
-" foreach {k v} $d {\n"
1457
-" dict set dict $k $v\n"
1458
-" }\n"
1459
-" }\n"
1460
-" return $dict\n"
1461
-"}\n"
1462
-"\n"
14631574
"proc {dict replace} {dictionary {args {key value}}} {\n"
14641575
" if {[llength ${key value}] % 2} {\n"
14651576
" tailcall {dict replace}\n"
14661577
" }\n"
14671578
" tailcall dict merge $dictionary ${key value}\n"
@@ -1503,15 +1614,10 @@
15031614
" dict unset dictionary $k\n"
15041615
" }\n"
15051616
" return $dictionary\n"
15061617
"}\n"
15071618
"\n"
1508
-"\n"
1509
-"proc {dict values} {dictionary {pattern *}} {\n"
1510
-" dict keys [lreverse $dictionary] $pattern\n"
1511
-"}\n"
1512
-"\n"
15131619
"\n"
15141620
"proc {dict for} {vars dictionary script} {\n"
15151621
" if {[llength $vars] != 2} {\n"
15161622
" return -code error \"must have exactly two variable names\"\n"
15171623
" }\n"
@@ -1591,11 +1697,10 @@
15911697
" tailcall {*}$args\n"
15921698
"}\n"
15931699
"\n"
15941700
"\n"
15951701
"\n"
1596
-"\n"
15971702
"proc parray {arrayname {pattern *} {puts puts}} {\n"
15981703
" upvar $arrayname a\n"
15991704
"\n"
16001705
" set max 0\n"
16011706
" foreach name [array names a $pattern]] {\n"
@@ -1647,11 +1752,11 @@
16471752
"}\n"
16481753
"\n"
16491754
"\n"
16501755
"\n"
16511756
"proc popen {cmd {mode r}} {\n"
1652
-" lassign [socket pipe] r w\n"
1757
+" lassign [pipe] r w\n"
16531758
" try {\n"
16541759
" if {[string match \"w*\" $mode]} {\n"
16551760
" lappend cmd <@$r &\n"
16561761
" set pids [exec {*}$cmd]\n"
16571762
" $r close\n"
@@ -1663,16 +1768,31 @@
16631768
" set f $r\n"
16641769
" }\n"
16651770
" lambda {cmd args} {f pids} {\n"
16661771
" if {$cmd eq \"pid\"} {\n"
16671772
" return $pids\n"
1773
+" }\n"
1774
+" if {$cmd eq \"getfd\"} {\n"
1775
+" $f getfd\n"
16681776
" }\n"
16691777
" if {$cmd eq \"close\"} {\n"
16701778
" $f close\n"
16711779
"\n"
1672
-" foreach p $pids { os.wait $p }\n"
1673
-" return\n"
1780
+" set retopts {}\n"
1781
+" foreach p $pids {\n"
1782
+" lassign [wait $p] status - rc\n"
1783
+" if {$status eq \"CHILDSTATUS\"} {\n"
1784
+" if {$rc == 0} {\n"
1785
+" continue\n"
1786
+" }\n"
1787
+" set msg \"child process exited abnormally\"\n"
1788
+" } else {\n"
1789
+" set msg \"child killed: received signal\"\n"
1790
+" }\n"
1791
+" set retopts [list -code error -errorcode [list $status $p $rc] $msg]\n"
1792
+" }\n"
1793
+" return {*}$retopts\n"
16741794
" }\n"
16751795
" tailcall $f $cmd {*}$args\n"
16761796
" }\n"
16771797
" } on error {error opts} {\n"
16781798
" $r close\n"
@@ -1692,14 +1812,10 @@
16921812
" if {[catch {$channelId pid} pids]} {\n"
16931813
" return \"\"\n"
16941814
" }\n"
16951815
" return $pids\n"
16961816
"}\n"
1697
-"\n"
1698
-"\n"
1699
-"\n"
1700
-"\n"
17011817
"\n"
17021818
"\n"
17031819
"\n"
17041820
"\n"
17051821
"\n"
@@ -1780,10 +1896,13 @@
17801896
"}\n"
17811897
);
17821898
}
17831899
17841900
1901
+#ifndef _GNU_SOURCE
1902
+#define _GNU_SOURCE
1903
+#endif
17851904
#include <stdio.h>
17861905
#include <string.h>
17871906
#include <errno.h>
17881907
#include <fcntl.h>
17891908
#ifdef HAVE_UNISTD_H
@@ -1793,27 +1912,34 @@
17931912
17941913
17951914
#if defined(HAVE_SYS_SOCKET_H) && defined(HAVE_SELECT) && defined(HAVE_NETINET_IN_H) && defined(HAVE_NETDB_H) && defined(HAVE_ARPA_INET_H)
17961915
#include <sys/socket.h>
17971916
#include <netinet/in.h>
1917
+#include <netinet/tcp.h>
17981918
#include <arpa/inet.h>
17991919
#include <netdb.h>
18001920
#ifdef HAVE_SYS_UN_H
18011921
#include <sys/un.h>
18021922
#endif
1923
+#define HAVE_SOCKETS
1924
+#elif defined (__MINGW32__)
1925
+
18031926
#else
18041927
#define JIM_ANSIC
18051928
#endif
18061929
18071930
#if defined(JIM_SSL)
18081931
#include <openssl/ssl.h>
18091932
#include <openssl/err.h>
18101933
#endif
18111934
1935
+#ifdef HAVE_TERMIOS_H
1936
+#endif
18121937
1813
-#define AIO_CMD_LEN 32
1814
-#define AIO_BUF_LEN 256
1938
+
1939
+#define AIO_CMD_LEN 32
1940
+#define AIO_BUF_LEN 256
18151941
18161942
#ifndef HAVE_FTELLO
18171943
#define ftello ftell
18181944
#endif
18191945
#ifndef HAVE_FSEEKO
@@ -1829,11 +1955,15 @@
18291955
#ifndef PF_INET6
18301956
#define PF_INET6 0
18311957
#endif
18321958
#endif
18331959
1834
-#define JimCheckStreamError(interp, af) af->fops->error(af)
1960
+#ifdef JIM_ANSIC
1961
+
1962
+#undef HAVE_PIPE
1963
+#undef HAVE_SOCKETPAIR
1964
+#endif
18351965
18361966
18371967
struct AioFile;
18381968
18391969
typedef struct {
@@ -1848,11 +1978,11 @@
18481978
typedef struct AioFile
18491979
{
18501980
FILE *fp;
18511981
Jim_Obj *filename;
18521982
int type;
1853
- int openFlags;
1983
+ int openFlags;
18541984
int fd;
18551985
Jim_Obj *rEvent;
18561986
Jim_Obj *wEvent;
18571987
Jim_Obj *eEvent;
18581988
int addr_family;
@@ -1879,21 +2009,21 @@
18792009
{
18802010
if (!ferror(af->fp)) {
18812011
return JIM_OK;
18822012
}
18832013
clearerr(af->fp);
1884
-
2014
+
18852015
if (feof(af->fp) || errno == EAGAIN || errno == EINTR) {
18862016
return JIM_OK;
18872017
}
18882018
#ifdef ECONNRESET
18892019
if (errno == ECONNRESET) {
18902020
return JIM_OK;
18912021
}
18922022
#endif
18932023
#ifdef ECONNABORTED
1894
- if (errno != ECONNABORTED) {
2024
+ if (errno == ECONNABORTED) {
18952025
return JIM_OK;
18962026
}
18972027
#endif
18982028
return JIM_ERR;
18992029
}
@@ -1935,10 +2065,19 @@
19352065
}
19362066
else {
19372067
Jim_SetResultString(interp, JimAioErrorString(af), -1);
19382068
}
19392069
}
2070
+
2071
+static int JimCheckStreamError(Jim_Interp *interp, AioFile *af)
2072
+{
2073
+ int ret = af->fops->error(af);
2074
+ if (ret) {
2075
+ JimAioSetError(interp, af->filename);
2076
+ }
2077
+ return ret;
2078
+}
19402079
19412080
static void JimAioDelProc(Jim_Interp *interp, void *privData)
19422081
{
19432082
AioFile *af = privData;
19442083
@@ -1945,20 +2084,19 @@
19452084
JIM_NOTUSED(interp);
19462085
19472086
Jim_DecrRefCount(interp, af->filename);
19482087
19492088
#ifdef jim_ext_eventloop
1950
-
1951
- Jim_DeleteFileHandler(interp, af->fp, JIM_EVENT_READABLE | JIM_EVENT_WRITABLE | JIM_EVENT_EXCEPTION);
2089
+
2090
+ Jim_DeleteFileHandler(interp, af->fd, JIM_EVENT_READABLE | JIM_EVENT_WRITABLE | JIM_EVENT_EXCEPTION);
19522091
#endif
19532092
19542093
#if defined(JIM_SSL)
19552094
if (af->ssl != NULL) {
19562095
SSL_free(af->ssl);
19572096
}
19582097
#endif
1959
-
19602098
if (!(af->openFlags & AIO_KEEPOPEN)) {
19612099
fclose(af->fp);
19622100
}
19632101
19642102
Jim_Free(af);
@@ -1968,11 +2106,11 @@
19682106
{
19692107
AioFile *af = Jim_CmdPrivData(interp);
19702108
char buf[AIO_BUF_LEN];
19712109
Jim_Obj *objPtr;
19722110
int nonewline = 0;
1973
- jim_wide neededLen = -1;
2111
+ jim_wide neededLen = -1;
19742112
19752113
if (argc && Jim_CompareStringImmediate(interp, argv[0], "-nonewline")) {
19762114
nonewline = 1;
19772115
argv++;
19782116
argc--;
@@ -2007,11 +2145,11 @@
20072145
}
20082146
}
20092147
if (retval != readlen)
20102148
break;
20112149
}
2012
-
2150
+
20132151
if (JimCheckStreamError(interp, af)) {
20142152
Jim_FreeNewObj(interp, objPtr);
20152153
return JIM_ERR;
20162154
}
20172155
if (nonewline) {
@@ -2029,11 +2167,11 @@
20292167
20302168
AioFile *Jim_AioFile(Jim_Interp *interp, Jim_Obj *command)
20312169
{
20322170
Jim_Cmd *cmdPtr = Jim_GetCommand(interp, command, JIM_ERRMSG);
20332171
2034
-
2172
+
20352173
if (cmdPtr && !cmdPtr->isproc && cmdPtr->u.native.cmdProc == JimAioSubCmdProc) {
20362174
return (AioFile *) cmdPtr->u.native.privData;
20372175
}
20382176
Jim_SetResultFormatted(interp, "Not a filehandle: \"%#s\"", command);
20392177
return NULL;
@@ -2048,10 +2186,20 @@
20482186
return NULL;
20492187
}
20502188
20512189
return af->fp;
20522190
}
2191
+
2192
+static int aio_cmd_getfd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
2193
+{
2194
+ AioFile *af = Jim_CmdPrivData(interp);
2195
+
2196
+ fflush(af->fp);
2197
+ Jim_SetResultInt(interp, fileno(af->fp));
2198
+
2199
+ return JIM_OK;
2200
+}
20532201
20542202
static int aio_cmd_copy(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
20552203
{
20562204
AioFile *af = Jim_CmdPrivData(interp);
20572205
jim_wide count = 0;
@@ -2110,21 +2258,21 @@
21102258
}
21112259
else {
21122260
len = strlen(buf);
21132261
21142262
if (len && (buf[len - 1] == '\n')) {
2115
-
2263
+
21162264
len--;
21172265
}
21182266
21192267
Jim_AppendString(interp, objPtr, buf, len);
21202268
break;
21212269
}
21222270
}
21232271
21242272
if (JimCheckStreamError(interp, af)) {
2125
-
2273
+
21262274
Jim_FreeNewObj(interp, objPtr);
21272275
return JIM_ERR;
21282276
}
21292277
21302278
if (argc) {
@@ -2134,11 +2282,11 @@
21342282
}
21352283
21362284
len = Jim_Length(objPtr);
21372285
21382286
if (len == 0 && feof(af->fp)) {
2139
-
2287
+
21402288
len = -1;
21412289
}
21422290
Jim_SetResultInt(interp, len);
21432291
}
21442292
else {
@@ -2207,11 +2355,11 @@
22072355
}
22082356
22092357
static int aio_cmd_close(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
22102358
{
22112359
if (argc == 3) {
2212
-#if !defined(JIM_ANSIC) && defined(HAVE_SHUTDOWN)
2360
+#if defined(HAVE_SOCKETS) && defined(HAVE_SHUTDOWN)
22132361
static const char * const options[] = { "r", "w", NULL };
22142362
enum { OPT_R, OPT_W, };
22152363
int option;
22162364
AioFile *af = Jim_CmdPrivData(interp);
22172365
@@ -2297,10 +2445,11 @@
22972445
}
22982446
Jim_SetResultInt(interp, (fmode & O_NONBLOCK) ? 1 : 0);
22992447
return JIM_OK;
23002448
}
23012449
#endif
2450
+
23022451
23032452
#ifdef HAVE_FSYNC
23042453
static int aio_cmd_sync(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
23052454
{
23062455
AioFile *af = Jim_CmdPrivData(interp);
@@ -2364,33 +2513,33 @@
23642513
23652514
static int aio_eventinfo(Jim_Interp *interp, AioFile * af, unsigned mask, Jim_Obj **scriptHandlerObj,
23662515
int argc, Jim_Obj * const *argv)
23672516
{
23682517
if (argc == 0) {
2369
-
2518
+
23702519
if (*scriptHandlerObj) {
23712520
Jim_SetResult(interp, *scriptHandlerObj);
23722521
}
23732522
return JIM_OK;
23742523
}
23752524
23762525
if (*scriptHandlerObj) {
2377
-
2378
- Jim_DeleteFileHandler(interp, af->fp, mask);
2526
+
2527
+ Jim_DeleteFileHandler(interp, af->fd, mask);
23792528
}
23802529
2381
-
2530
+
23822531
if (Jim_Length(argv[0]) == 0) {
2383
-
2532
+
23842533
return JIM_OK;
23852534
}
23862535
2387
-
2536
+
23882537
Jim_IncrRefCount(argv[0]);
23892538
*scriptHandlerObj = argv[0];
23902539
2391
- Jim_CreateFileHandler(interp, af->fp, mask,
2540
+ Jim_CreateFileHandler(interp, af->fd, mask,
23922541
JimAioFileEventHandler, scriptHandlerObj, JimAioFileEventFinalizer);
23932542
23942543
return JIM_OK;
23952544
}
23962545
@@ -2414,136 +2563,145 @@
24142563
24152564
return aio_eventinfo(interp, af, JIM_EVENT_EXCEPTION, &af->eEvent, argc, argv);
24162565
}
24172566
#endif
24182567
2568
+
2569
+
24192570
24202571
static const jim_subcmd_type aio_command_table[] = {
24212572
{ "read",
24222573
"?-nonewline? ?len?",
24232574
aio_cmd_read,
24242575
0,
24252576
2,
2426
-
2577
+
24272578
},
24282579
{ "copyto",
24292580
"handle ?size?",
24302581
aio_cmd_copy,
24312582
1,
24322583
2,
2433
-
2584
+
2585
+ },
2586
+ { "getfd",
2587
+ NULL,
2588
+ aio_cmd_getfd,
2589
+ 0,
2590
+ 0,
2591
+
24342592
},
24352593
{ "gets",
24362594
"?var?",
24372595
aio_cmd_gets,
24382596
0,
24392597
1,
2440
-
2598
+
24412599
},
24422600
{ "puts",
24432601
"?-nonewline? str",
24442602
aio_cmd_puts,
24452603
1,
24462604
2,
2447
-
2605
+
24482606
},
24492607
{ "isatty",
24502608
NULL,
24512609
aio_cmd_isatty,
24522610
0,
24532611
0,
2454
-
2612
+
24552613
},
24562614
{ "flush",
24572615
NULL,
24582616
aio_cmd_flush,
24592617
0,
24602618
0,
2461
-
2619
+
24622620
},
24632621
{ "eof",
24642622
NULL,
24652623
aio_cmd_eof,
24662624
0,
24672625
0,
2468
-
2626
+
24692627
},
24702628
{ "close",
24712629
"?r(ead)|w(rite)?",
24722630
aio_cmd_close,
24732631
0,
24742632
1,
24752633
JIM_MODFLAG_FULLARGV,
2476
-
2634
+
24772635
},
24782636
{ "seek",
24792637
"offset ?start|current|end",
24802638
aio_cmd_seek,
24812639
1,
24822640
2,
2483
-
2641
+
24842642
},
24852643
{ "tell",
24862644
NULL,
24872645
aio_cmd_tell,
24882646
0,
24892647
0,
2490
-
2648
+
24912649
},
24922650
{ "filename",
24932651
NULL,
24942652
aio_cmd_filename,
24952653
0,
24962654
0,
2497
-
2655
+
24982656
},
24992657
#ifdef O_NDELAY
25002658
{ "ndelay",
25012659
"?0|1?",
25022660
aio_cmd_ndelay,
25032661
0,
25042662
1,
2505
-
2663
+
25062664
},
25072665
#endif
25082666
#ifdef HAVE_FSYNC
25092667
{ "sync",
25102668
NULL,
25112669
aio_cmd_sync,
25122670
0,
25132671
0,
2514
-
2672
+
25152673
},
25162674
#endif
25172675
{ "buffering",
25182676
"none|line|full",
25192677
aio_cmd_buffering,
25202678
1,
25212679
1,
2522
-
2680
+
25232681
},
25242682
#ifdef jim_ext_eventloop
25252683
{ "readable",
25262684
"?readable-script?",
25272685
aio_cmd_readable,
25282686
0,
25292687
1,
2530
-
2688
+
25312689
},
25322690
{ "writable",
25332691
"?writable-script?",
25342692
aio_cmd_writable,
25352693
0,
25362694
1,
2537
-
2695
+
25382696
},
25392697
{ "onexception",
25402698
"?exception-script?",
25412699
aio_cmd_onexception,
25422700
0,
25432701
1,
2544
-
2702
+
25452703
},
25462704
#endif
25472705
{ NULL }
25482706
};
25492707
@@ -2566,11 +2724,11 @@
25662724
25672725
#ifdef jim_ext_tclcompat
25682726
{
25692727
const char *filename = Jim_String(argv[1]);
25702728
2571
-
2729
+
25722730
if (*filename == '|') {
25732731
Jim_Obj *evalObj[3];
25742732
25752733
evalObj[0] = Jim_NewStringObj(interp, "::popen", -1);
25762734
evalObj[1] = Jim_NewStringObj(interp, filename + 1, -1);
@@ -2603,42 +2761,44 @@
26032761
}
26042762
26052763
Jim_IncrRefCount(filename);
26062764
26072765
if (fh == NULL) {
2608
-#if !defined(JIM_ANSIC)
26092766
if (fd >= 0) {
2767
+#ifndef JIM_ANSIC
26102768
fh = fdopen(fd, mode);
2769
+#endif
26112770
}
26122771
else
2613
-#endif
26142772
fh = fopen(Jim_String(filename), mode);
26152773
26162774
if (fh == NULL) {
26172775
JimAioSetError(interp, filename);
2618
-#if !defined(JIM_ANSIC)
2776
+#ifndef JIM_ANSIC
26192777
if (fd >= 0) {
26202778
close(fd);
26212779
}
26222780
#endif
26232781
Jim_DecrRefCount(interp, filename);
26242782
return NULL;
26252783
}
26262784
}
26272785
2628
-
2786
+
26292787
af = Jim_Alloc(sizeof(*af));
26302788
memset(af, 0, sizeof(*af));
26312789
af->fp = fh;
2632
- af->fd = fileno(fh);
26332790
af->filename = filename;
2791
+ af->openFlags = openFlags;
2792
+#ifndef JIM_ANSIC
2793
+ af->fd = fileno(fh);
26342794
#ifdef FD_CLOEXEC
26352795
if ((openFlags & AIO_KEEPOPEN) == 0) {
26362796
(void)fcntl(af->fd, F_SETFD, FD_CLOEXEC);
26372797
}
26382798
#endif
2639
- af->openFlags = openFlags;
2799
+#endif
26402800
af->addr_family = family;
26412801
af->fops = &stdio_fops;
26422802
af->ssl = NULL;
26432803
26442804
Jim_CreateCommand(interp, buf, JimAioSubCmdProc, af, JimAioDelProc);
@@ -2653,72 +2813,45 @@
26532813
const char *hdlfmt, int family, const char *mode[2])
26542814
{
26552815
if (JimMakeChannel(interp, NULL, p[0], filename, hdlfmt, family, mode[0])) {
26562816
Jim_Obj *objPtr = Jim_NewListObj(interp, NULL, 0);
26572817
Jim_ListAppendElement(interp, objPtr, Jim_GetResult(interp));
2658
-
26592818
if (JimMakeChannel(interp, NULL, p[1], filename, hdlfmt, family, mode[1])) {
26602819
Jim_ListAppendElement(interp, objPtr, Jim_GetResult(interp));
26612820
Jim_SetResult(interp, objPtr);
26622821
return JIM_OK;
26632822
}
26642823
}
26652824
2666
-
2825
+
26672826
close(p[0]);
26682827
close(p[1]);
26692828
JimAioSetError(interp, NULL);
26702829
return JIM_ERR;
26712830
}
26722831
#endif
26732832
2674
-
2675
-int Jim_MakeTempFile(Jim_Interp *interp, const char *template)
2676
-{
2677
-#ifdef HAVE_MKSTEMP
2678
- int fd;
2679
- mode_t mask;
2680
- Jim_Obj *filenameObj;
2681
-
2682
- if (template == NULL) {
2683
- const char *tmpdir = getenv("TMPDIR");
2684
- if (tmpdir == NULL || *tmpdir == '\0' || access(tmpdir, W_OK) != 0) {
2685
- tmpdir = "/tmp/";
2686
- }
2687
- filenameObj = Jim_NewStringObj(interp, tmpdir, -1);
2688
- if (tmpdir[0] && tmpdir[strlen(tmpdir) - 1] != '/') {
2689
- Jim_AppendString(interp, filenameObj, "/", 1);
2690
- }
2691
- Jim_AppendString(interp, filenameObj, "tcl.tmp.XXXXXX", -1);
2692
- }
2693
- else {
2694
- filenameObj = Jim_NewStringObj(interp, template, -1);
2695
- }
2696
-
2697
-#if defined(S_IRWXG) && defined(S_IRWXO)
2698
- mask = umask(S_IXUSR | S_IRWXG | S_IRWXO);
2699
-#else
2700
-
2701
- mask = umask(S_IXUSR);
2702
-#endif
2703
-
2704
-
2705
- fd = mkstemp(filenameObj->bytes);
2706
- umask(mask);
2707
- if (fd < 0) {
2708
- JimAioSetError(interp, filenameObj);
2709
- Jim_FreeNewObj(interp, filenameObj);
2710
- return -1;
2711
- }
2712
-
2713
- Jim_SetResult(interp, filenameObj);
2714
- return fd;
2715
-#else
2716
- Jim_SetResultString(interp, "platform has no tempfile support", -1);
2717
- return -1;
2718
-#endif
2719
-}
2833
+#ifdef HAVE_PIPE
2834
+static int JimAioPipeCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
2835
+{
2836
+ int p[2];
2837
+ static const char *mode[2] = { "r", "w" };
2838
+
2839
+ if (argc != 1) {
2840
+ Jim_WrongNumArgs(interp, 1, argv, "");
2841
+ return JIM_ERR;
2842
+ }
2843
+
2844
+ if (pipe(p) != 0) {
2845
+ JimAioSetError(interp, NULL);
2846
+ return JIM_ERR;
2847
+ }
2848
+
2849
+ return JimMakeChannelPair(interp, p, argv[0], "aio.pipe%ld", 0, mode);
2850
+}
2851
+#endif
2852
+
27202853
27212854
27222855
int Jim_aioInit(Jim_Interp *interp)
27232856
{
27242857
if (Jim_PackageProvide(interp, "aio", "1.0", JIM_ERRMSG))
@@ -2727,15 +2860,18 @@
27272860
#if defined(JIM_SSL)
27282861
Jim_CreateCommand(interp, "load_ssl_certs", JimAioLoadSSLCertsCommand, NULL, NULL);
27292862
#endif
27302863
27312864
Jim_CreateCommand(interp, "open", JimAioOpenCommand, NULL, NULL);
2732
-#ifndef JIM_ANSIC
2865
+#ifdef HAVE_SOCKETS
27332866
Jim_CreateCommand(interp, "socket", JimAioSockCommand, NULL, NULL);
27342867
#endif
2868
+#ifdef HAVE_PIPE
2869
+ Jim_CreateCommand(interp, "pipe", JimAioPipeCommand, NULL, NULL);
2870
+#endif
27352871
2736
-
2872
+
27372873
JimMakeChannel(interp, stdin, -1, NULL, "stdin", 0, "r");
27382874
JimMakeChannel(interp, stdout, -1, NULL, "stdout", 0, "w");
27392875
JimMakeChannel(interp, stderr, -1, NULL, "stderr", 0, "w");
27402876
27412877
return JIM_OK;
@@ -2813,12 +2949,12 @@
28132949
#include <regex.h>
28142950
#endif
28152951
28162952
static void FreeRegexpInternalRep(Jim_Interp *interp, Jim_Obj *objPtr)
28172953
{
2818
- regfree(objPtr->internalRep.regexpValue.compre);
2819
- Jim_Free(objPtr->internalRep.regexpValue.compre);
2954
+ regfree(objPtr->internalRep.ptrIntValue.ptr);
2955
+ Jim_Free(objPtr->internalRep.ptrIntValue.ptr);
28202956
}
28212957
28222958
static const Jim_ObjType regexpObjType = {
28232959
"regexp",
28242960
FreeRegexpInternalRep,
@@ -2831,20 +2967,20 @@
28312967
{
28322968
regex_t *compre;
28332969
const char *pattern;
28342970
int ret;
28352971
2836
-
2972
+
28372973
if (objPtr->typePtr == &regexpObjType &&
2838
- objPtr->internalRep.regexpValue.compre && objPtr->internalRep.regexpValue.flags == flags) {
2839
-
2840
- return objPtr->internalRep.regexpValue.compre;
2974
+ objPtr->internalRep.ptrIntValue.ptr && objPtr->internalRep.ptrIntValue.int1 == flags) {
2975
+
2976
+ return objPtr->internalRep.ptrIntValue.ptr;
28412977
}
28422978
2843
-
28442979
2845
-
2980
+
2981
+
28462982
pattern = Jim_String(objPtr);
28472983
compre = Jim_Alloc(sizeof(regex_t));
28482984
28492985
if ((ret = regcomp(compre, pattern, REG_EXTENDED | flags)) != 0) {
28502986
char buf[100];
@@ -2857,12 +2993,12 @@
28572993
}
28582994
28592995
Jim_FreeIntRep(interp, objPtr);
28602996
28612997
objPtr->typePtr = &regexpObjType;
2862
- objPtr->internalRep.regexpValue.flags = flags;
2863
- objPtr->internalRep.regexpValue.compre = compre;
2998
+ objPtr->internalRep.ptrIntValue.int1 = flags;
2999
+ objPtr->internalRep.ptrIntValue.ptr = compre;
28643000
28653001
return compre;
28663002
}
28673003
28683004
int Jim_RegexpCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
@@ -3001,11 +3137,11 @@
30013137
}
30023138
30033139
num_matches++;
30043140
30053141
if (opt_all && !opt_inline) {
3006
-
3142
+
30073143
goto try_next_match;
30083144
}
30093145
30103146
30113147
j = 0;
@@ -3041,11 +3177,11 @@
30413177
30423178
if (opt_inline) {
30433179
Jim_ListAppendElement(interp, resultListObj, resultObj);
30443180
}
30453181
else {
3046
-
3182
+
30473183
result = Jim_SetVariable(interp, argv[i], resultObj);
30483184
30493185
if (result != JIM_OK) {
30503186
Jim_FreeObj(interp, resultObj);
30513187
break;
@@ -3168,11 +3304,11 @@
31683304
31693305
source_str = Jim_GetString(argv[i + 1], &source_len);
31703306
replace_str = Jim_GetString(argv[i + 2], &replace_len);
31713307
varname = argv[i + 3];
31723308
3173
-
3309
+
31743310
resultObj = Jim_NewStringObj(interp, "", 0);
31753311
31763312
if (offset) {
31773313
if (offset < 0) {
31783314
offset += source_len + 1;
@@ -3183,11 +3319,11 @@
31833319
else if (offset < 0) {
31843320
offset = 0;
31853321
}
31863322
}
31873323
3188
-
3324
+
31893325
Jim_AppendString(interp, resultObj, source_str, offset);
31903326
31913327
31923328
n = source_len - offset;
31933329
p = source_str + offset;
@@ -3242,23 +3378,23 @@
32423378
}
32433379
32443380
p += pmatch[0].rm_eo;
32453381
n -= pmatch[0].rm_eo;
32463382
3247
-
3383
+
32483384
if (!opt_all || n == 0) {
32493385
break;
32503386
}
32513387
3252
-
3388
+
32533389
if ((regcomp_flags & REG_NEWLINE) == 0 && pattern[0] == '^') {
32543390
break;
32553391
}
32563392
3257
-
3393
+
32583394
if (pattern[0] == '\0' && n) {
3259
-
3395
+
32603396
Jim_AppendString(interp, resultObj, p, 1);
32613397
p++;
32623398
n--;
32633399
}
32643400
@@ -3265,11 +3401,11 @@
32653401
regexec_flags |= REG_NOTBOL;
32663402
} while (n);
32673403
32683404
Jim_AppendString(interp, resultObj, p, -1);
32693405
3270
-
3406
+
32713407
if (argc - i == 4) {
32723408
result = Jim_SetVariable(interp, varname, resultObj);
32733409
32743410
if (result == JIM_OK) {
32753411
Jim_SetResultInt(interp, num_matches);
@@ -3320,16 +3456,23 @@
33203456
33213457
# ifndef MAXPATHLEN
33223458
# define MAXPATHLEN JIM_PATH_LEN
33233459
# endif
33243460
3325
-#if defined(__MINGW32__) || defined(_MSC_VER)
3461
+#if defined(__MINGW32__) || defined(__MSYS__) || defined(_MSC_VER)
33263462
#define ISWINDOWS 1
33273463
#else
33283464
#define ISWINDOWS 0
33293465
#endif
33303466
3467
+
3468
+#if defined(HAVE_STRUCT_STAT_ST_MTIMESPEC)
3469
+ #define STAT_MTIME_US(STAT) ((STAT).st_mtimespec.tv_sec * 1000000ll + (STAT).st_mtimespec.tv_nsec / 1000)
3470
+#elif defined(HAVE_STRUCT_STAT_ST_MTIM)
3471
+ #define STAT_MTIME_US(STAT) ((STAT).st_mtim.tv_sec * 1000000ll + (STAT).st_mtim.tv_nsec / 1000)
3472
+#endif
3473
+
33313474
33323475
static const char *JimGetFileType(int mode)
33333476
{
33343477
if (S_ISREG(mode)) {
33353478
return "file";
@@ -3371,11 +3514,11 @@
33713514
Jim_ListAppendElement(interp, listObj, Jim_NewIntObj(interp, value));
33723515
}
33733516
33743517
static int StoreStatData(Jim_Interp *interp, Jim_Obj *varName, const struct stat *sb)
33753518
{
3376
-
3519
+
33773520
Jim_Obj *listObj = Jim_NewListObj(interp, NULL, 0);
33783521
33793522
AppendStatElement(interp, listObj, "dev", sb->st_dev);
33803523
AppendStatElement(interp, listObj, "ino", sb->st_ino);
33813524
AppendStatElement(interp, listObj, "mode", sb->st_mode);
@@ -3384,39 +3527,44 @@
33843527
AppendStatElement(interp, listObj, "gid", sb->st_gid);
33853528
AppendStatElement(interp, listObj, "size", sb->st_size);
33863529
AppendStatElement(interp, listObj, "atime", sb->st_atime);
33873530
AppendStatElement(interp, listObj, "mtime", sb->st_mtime);
33883531
AppendStatElement(interp, listObj, "ctime", sb->st_ctime);
3532
+#ifdef STAT_MTIME_US
3533
+ AppendStatElement(interp, listObj, "mtimeus", STAT_MTIME_US(*sb));
3534
+#endif
33893535
Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, "type", -1));
33903536
Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, JimGetFileType((int)sb->st_mode), -1));
33913537
3392
-
3538
+
33933539
if (varName) {
3394
- Jim_Obj *objPtr = Jim_GetVariable(interp, varName, JIM_NONE);
3540
+ Jim_Obj *objPtr;
3541
+ objPtr = Jim_GetVariable(interp, varName, JIM_NONE);
3542
+
33953543
if (objPtr) {
3396
- if (Jim_DictSize(interp, objPtr) < 0) {
3397
-
3544
+ Jim_Obj *objv[2];
3545
+
3546
+ objv[0] = objPtr;
3547
+ objv[1] = listObj;
3548
+
3549
+ objPtr = Jim_DictMerge(interp, 2, objv);
3550
+ if (objPtr == NULL) {
3551
+
33983552
Jim_SetResultFormatted(interp, "can't set \"%#s(dev)\": variable isn't array", varName);
33993553
Jim_FreeNewObj(interp, listObj);
34003554
return JIM_ERR;
34013555
}
34023556
3403
- if (Jim_IsShared(objPtr))
3404
- objPtr = Jim_DuplicateObj(interp, objPtr);
3405
-
3406
-
3407
- Jim_ListAppendList(interp, objPtr, listObj);
3408
- Jim_DictSize(interp, objPtr);
34093557
Jim_InvalidateStringRep(objPtr);
34103558
34113559
Jim_FreeNewObj(interp, listObj);
34123560
listObj = objPtr;
34133561
}
34143562
Jim_SetVariable(interp, varName, listObj);
34153563
}
34163564
3417
-
3565
+
34183566
Jim_SetResult(interp, listObj);
34193567
34203568
return JIM_OK;
34213569
}
34223570
@@ -3432,11 +3580,11 @@
34323580
}
34333581
else if (p == path) {
34343582
Jim_SetResultString(interp, "/", -1);
34353583
}
34363584
else if (ISWINDOWS && p[-1] == ':') {
3437
-
3585
+
34383586
Jim_SetResultString(interp, path, p - path + 1);
34393587
}
34403588
else {
34413589
Jim_SetResultString(interp, path, p - path);
34423590
}
@@ -3512,35 +3660,35 @@
35123660
char *newname = Jim_Alloc(MAXPATHLEN + 1);
35133661
char *last = newname;
35143662
35153663
*newname = 0;
35163664
3517
-
3665
+
35183666
for (i = 0; i < argc; i++) {
35193667
int len;
35203668
const char *part = Jim_GetString(argv[i], &len);
35213669
35223670
if (*part == '/') {
3523
-
3671
+
35243672
last = newname;
35253673
}
35263674
else if (ISWINDOWS && strchr(part, ':')) {
3527
-
3675
+
35283676
last = newname;
35293677
}
35303678
else if (part[0] == '.') {
35313679
if (part[1] == '/') {
35323680
part += 2;
35333681
len -= 2;
35343682
}
35353683
else if (part[1] == 0 && last != newname) {
3536
-
3684
+
35373685
continue;
35383686
}
35393687
}
35403688
3541
-
3689
+
35423690
if (last != newname && last[-1] != '/') {
35433691
*last++ = '/';
35443692
}
35453693
35463694
if (len) {
@@ -3551,22 +3699,22 @@
35513699
}
35523700
memcpy(last, part, len);
35533701
last += len;
35543702
}
35553703
3556
-
3704
+
35573705
if (last > newname + 1 && last[-1] == '/') {
3558
-
3706
+
35593707
if (!ISWINDOWS || !(last > newname + 2 && last[-2] == ':')) {
35603708
*--last = 0;
35613709
}
35623710
}
35633711
}
35643712
35653713
*last = 0;
35663714
3567
-
3715
+
35683716
35693717
Jim_SetResult(interp, Jim_NewStringObjNoAlloc(interp, newname, last - newname));
35703718
35713719
return JIM_OK;
35723720
}
@@ -3591,11 +3739,11 @@
35913739
static int file_cmd_executable(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
35923740
{
35933741
#ifdef X_OK
35943742
return file_access(interp, argv[0], X_OK);
35953743
#else
3596
-
3744
+
35973745
Jim_SetResultBool(interp, 1);
35983746
return JIM_OK;
35993747
#endif
36003748
}
36013749
@@ -3616,11 +3764,11 @@
36163764
while (argc--) {
36173765
const char *path = Jim_String(argv[0]);
36183766
36193767
if (unlink(path) == -1 && errno != ENOENT) {
36203768
if (rmdir(path) == -1) {
3621
-
3769
+
36223770
if (!force || Jim_EvalPrefix(interp, "file delete force", 1, argv) != JIM_OK) {
36233771
Jim_SetResultFormatted(interp, "couldn't delete file \"%s\": %s", path,
36243772
strerror(errno));
36253773
return JIM_ERR;
36263774
}
@@ -3639,15 +3787,15 @@
36393787
36403788
static int mkdir_all(char *path)
36413789
{
36423790
int ok = 1;
36433791
3644
-
3792
+
36453793
goto first;
36463794
36473795
while (ok--) {
3648
-
3796
+
36493797
{
36503798
char *slash = strrchr(path, '/');
36513799
36523800
if (slash && slash != path) {
36533801
*slash = 0;
@@ -3660,24 +3808,24 @@
36603808
first:
36613809
if (MKDIR_DEFAULT(path) == 0) {
36623810
return 0;
36633811
}
36643812
if (errno == ENOENT) {
3665
-
3813
+
36663814
continue;
36673815
}
3668
-
3816
+
36693817
if (errno == EEXIST) {
36703818
struct stat sb;
36713819
36723820
if (stat(path, &sb) == 0 && S_ISDIR(sb.st_mode)) {
36733821
return 0;
36743822
}
3675
-
3823
+
36763824
errno = EEXIST;
36773825
}
3678
-
3826
+
36793827
break;
36803828
}
36813829
return -1;
36823830
}
36833831
@@ -3698,11 +3846,11 @@
36983846
return JIM_OK;
36993847
}
37003848
37013849
static int file_cmd_tempfile(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
37023850
{
3703
- int fd = Jim_MakeTempFile(interp, (argc >= 1) ? Jim_String(argv[0]) : NULL);
3851
+ int fd = Jim_MakeTempFile(interp, (argc >= 1) ? Jim_String(argv[0]) : NULL, 0);
37043852
37053853
if (fd < 0) {
37063854
return JIM_ERR;
37073855
}
37083856
close(fd);
@@ -3815,42 +3963,67 @@
38153963
return JIM_ERR;
38163964
}
38173965
Jim_SetResultInt(interp, sb.st_atime);
38183966
return JIM_OK;
38193967
}
3968
+
3969
+static int JimSetFileTimes(Jim_Interp *interp, const char *filename, jim_wide us)
3970
+{
3971
+#ifdef HAVE_UTIMES
3972
+ struct timeval times[2];
3973
+
3974
+ times[1].tv_sec = times[0].tv_sec = us / 1000000;
3975
+ times[1].tv_usec = times[0].tv_usec = us % 1000000;
3976
+
3977
+ if (utimes(filename, times) != 0) {
3978
+ Jim_SetResultFormatted(interp, "can't set time on \"%s\": %s", filename, strerror(errno));
3979
+ return JIM_ERR;
3980
+ }
3981
+ return JIM_OK;
3982
+#else
3983
+ Jim_SetResultString(interp, "Not implemented", -1);
3984
+ return JIM_ERR;
3985
+#endif
3986
+}
38203987
38213988
static int file_cmd_mtime(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
38223989
{
38233990
struct stat sb;
38243991
38253992
if (argc == 2) {
3826
-#ifdef HAVE_UTIMES
3827
- jim_wide newtime;
3828
- struct timeval times[2];
3829
-
3830
- if (Jim_GetWide(interp, argv[1], &newtime) != JIM_OK) {
3831
- return JIM_ERR;
3832
- }
3833
-
3834
- times[1].tv_sec = times[0].tv_sec = newtime;
3835
- times[1].tv_usec = times[0].tv_usec = 0;
3836
-
3837
- if (utimes(Jim_String(argv[0]), times) != 0) {
3838
- Jim_SetResultFormatted(interp, "can't set time on \"%#s\": %s", argv[0], strerror(errno));
3839
- return JIM_ERR;
3840
- }
3841
-#else
3842
- Jim_SetResultString(interp, "Not implemented", -1);
3843
- return JIM_ERR;
3844
-#endif
3993
+ jim_wide secs;
3994
+ if (Jim_GetWide(interp, argv[1], &secs) != JIM_OK) {
3995
+ return JIM_ERR;
3996
+ }
3997
+ return JimSetFileTimes(interp, Jim_String(argv[0]), secs * 1000000);
38453998
}
38463999
if (file_stat(interp, argv[0], &sb) != JIM_OK) {
38474000
return JIM_ERR;
38484001
}
38494002
Jim_SetResultInt(interp, sb.st_mtime);
38504003
return JIM_OK;
38514004
}
4005
+
4006
+#ifdef STAT_MTIME_US
4007
+static int file_cmd_mtimeus(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
4008
+{
4009
+ struct stat sb;
4010
+
4011
+ if (argc == 2) {
4012
+ jim_wide us;
4013
+ if (Jim_GetWide(interp, argv[1], &us) != JIM_OK) {
4014
+ return JIM_ERR;
4015
+ }
4016
+ return JimSetFileTimes(interp, Jim_String(argv[0]), us);
4017
+ }
4018
+ if (file_stat(interp, argv[0], &sb) != JIM_OK) {
4019
+ return JIM_ERR;
4020
+ }
4021
+ Jim_SetResultInt(interp, STAT_MTIME_US(sb));
4022
+ return JIM_OK;
4023
+}
4024
+#endif
38524025
38534026
static int file_cmd_copy(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
38544027
{
38554028
return Jim_EvalPrefix(interp, "file copy", argc, argv);
38564029
}
@@ -3962,192 +4135,201 @@
39624135
{ "atime",
39634136
"name",
39644137
file_cmd_atime,
39654138
1,
39664139
1,
3967
-
4140
+
39684141
},
39694142
{ "mtime",
39704143
"name ?time?",
39714144
file_cmd_mtime,
39724145
1,
39734146
2,
3974
-
4147
+
4148
+ },
4149
+#ifdef STAT_MTIME_US
4150
+ { "mtimeus",
4151
+ "name ?time?",
4152
+ file_cmd_mtimeus,
4153
+ 1,
4154
+ 2,
4155
+
39754156
},
4157
+#endif
39764158
{ "copy",
39774159
"?-force? source dest",
39784160
file_cmd_copy,
39794161
2,
39804162
3,
3981
-
4163
+
39824164
},
39834165
{ "dirname",
39844166
"name",
39854167
file_cmd_dirname,
39864168
1,
39874169
1,
3988
-
4170
+
39894171
},
39904172
{ "rootname",
39914173
"name",
39924174
file_cmd_rootname,
39934175
1,
39944176
1,
3995
-
4177
+
39964178
},
39974179
{ "extension",
39984180
"name",
39994181
file_cmd_extension,
40004182
1,
40014183
1,
4002
-
4184
+
40034185
},
40044186
{ "tail",
40054187
"name",
40064188
file_cmd_tail,
40074189
1,
40084190
1,
4009
-
4191
+
40104192
},
40114193
{ "normalize",
40124194
"name",
40134195
file_cmd_normalize,
40144196
1,
40154197
1,
4016
-
4198
+
40174199
},
40184200
{ "join",
40194201
"name ?name ...?",
40204202
file_cmd_join,
40214203
1,
40224204
-1,
4023
-
4205
+
40244206
},
40254207
{ "readable",
40264208
"name",
40274209
file_cmd_readable,
40284210
1,
40294211
1,
4030
-
4212
+
40314213
},
40324214
{ "writable",
40334215
"name",
40344216
file_cmd_writable,
40354217
1,
40364218
1,
4037
-
4219
+
40384220
},
40394221
{ "executable",
40404222
"name",
40414223
file_cmd_executable,
40424224
1,
40434225
1,
4044
-
4226
+
40454227
},
40464228
{ "exists",
40474229
"name",
40484230
file_cmd_exists,
40494231
1,
40504232
1,
4051
-
4233
+
40524234
},
40534235
{ "delete",
40544236
"?-force|--? name ...",
40554237
file_cmd_delete,
40564238
1,
40574239
-1,
4058
-
4240
+
40594241
},
40604242
{ "mkdir",
40614243
"dir ...",
40624244
file_cmd_mkdir,
40634245
1,
40644246
-1,
4065
-
4247
+
40664248
},
40674249
{ "tempfile",
40684250
"?template?",
40694251
file_cmd_tempfile,
40704252
0,
40714253
1,
4072
-
4254
+
40734255
},
40744256
{ "rename",
40754257
"?-force? source dest",
40764258
file_cmd_rename,
40774259
2,
40784260
3,
4079
-
4261
+
40804262
},
40814263
#if defined(HAVE_LINK) && defined(HAVE_SYMLINK)
40824264
{ "link",
40834265
"?-symbolic|-hard? newname target",
40844266
file_cmd_link,
40854267
2,
40864268
3,
4087
-
4269
+
40884270
},
40894271
#endif
40904272
#if defined(HAVE_READLINK)
40914273
{ "readlink",
40924274
"name",
40934275
file_cmd_readlink,
40944276
1,
40954277
1,
4096
-
4278
+
40974279
},
40984280
#endif
40994281
{ "size",
41004282
"name",
41014283
file_cmd_size,
41024284
1,
41034285
1,
4104
-
4286
+
41054287
},
41064288
{ "stat",
41074289
"name ?var?",
41084290
file_cmd_stat,
41094291
1,
41104292
2,
4111
-
4293
+
41124294
},
41134295
{ "lstat",
41144296
"name ?var?",
41154297
file_cmd_lstat,
41164298
1,
41174299
2,
4118
-
4300
+
41194301
},
41204302
{ "type",
41214303
"name",
41224304
file_cmd_type,
41234305
1,
41244306
1,
4125
-
4307
+
41264308
},
41274309
#ifdef HAVE_GETEUID
41284310
{ "owned",
41294311
"name",
41304312
file_cmd_owned,
41314313
1,
41324314
1,
4133
-
4315
+
41344316
},
41354317
#endif
41364318
{ "isdirectory",
41374319
"name",
41384320
file_cmd_isdirectory,
41394321
1,
41404322
1,
4141
-
4323
+
41424324
},
41434325
{ "isfile",
41444326
"name",
41454327
file_cmd_isfile,
41464328
1,
41474329
1,
4148
-
4330
+
41494331
},
41504332
{
41514333
NULL
41524334
}
41534335
};
@@ -4179,11 +4361,11 @@
41794361
Jim_SetResultString(interp, "Failed to get pwd", -1);
41804362
Jim_Free(cwd);
41814363
return JIM_ERR;
41824364
}
41834365
else if (ISWINDOWS) {
4184
-
4366
+
41854367
char *p = cwd;
41864368
while ((p = strchr(p, '\\')) != NULL) {
41874369
*p++ = '/';
41884370
}
41894371
}
@@ -4203,10 +4385,13 @@
42034385
Jim_CreateCommand(interp, "pwd", Jim_PwdCmd, NULL, NULL);
42044386
Jim_CreateCommand(interp, "cd", Jim_CdCmd, NULL, NULL);
42054387
return JIM_OK;
42064388
}
42074389
4390
+#ifndef _GNU_SOURCE
4391
+#define _GNU_SOURCE
4392
+#endif
42084393
#include <string.h>
42094394
#include <ctype.h>
42104395
42114396
42124397
#if (!defined(HAVE_VFORK) || !defined(HAVE_WAITPID)) && !defined(__MINGW32__)
@@ -4214,20 +4399,20 @@
42144399
{
42154400
Jim_Obj *cmdlineObj = Jim_NewEmptyStringObj(interp);
42164401
int i, j;
42174402
int rc;
42184403
4219
-
4404
+
42204405
for (i = 1; i < argc; i++) {
42214406
int len;
42224407
const char *arg = Jim_GetString(argv[i], &len);
42234408
42244409
if (i > 1) {
42254410
Jim_AppendString(interp, cmdlineObj, " ", 1);
42264411
}
42274412
if (strpbrk(arg, "\\\" ") == NULL) {
4228
-
4413
+
42294414
Jim_AppendString(interp, cmdlineObj, arg, len);
42304415
continue;
42314416
}
42324417
42334418
Jim_AppendString(interp, cmdlineObj, "\"", 1);
@@ -4266,86 +4451,26 @@
42664451
#else
42674452
42684453
42694454
#include <errno.h>
42704455
#include <signal.h>
4271
-
4272
-#if defined(__MINGW32__)
4273
-
4274
- #ifndef STRICT
4275
- #define STRICT
4276
- #endif
4277
- #define WIN32_LEAN_AND_MEAN
4278
- #include <windows.h>
4279
- #include <fcntl.h>
4280
-
4281
- typedef HANDLE fdtype;
4282
- typedef HANDLE pidtype;
4283
- #define JIM_BAD_FD INVALID_HANDLE_VALUE
4284
- #define JIM_BAD_PID INVALID_HANDLE_VALUE
4285
- #define JimCloseFd CloseHandle
4286
-
4287
- #define WIFEXITED(STATUS) 1
4288
- #define WEXITSTATUS(STATUS) (STATUS)
4289
- #define WIFSIGNALED(STATUS) 0
4290
- #define WTERMSIG(STATUS) 0
4291
- #define WNOHANG 1
4292
-
4293
- static fdtype JimFileno(FILE *fh);
4294
- static pidtype JimWaitPid(pidtype pid, int *status, int nohang);
4295
- static fdtype JimDupFd(fdtype infd);
4296
- static fdtype JimOpenForRead(const char *filename);
4297
- static FILE *JimFdOpenForRead(fdtype fd);
4298
- static int JimPipe(fdtype pipefd[2]);
4299
- static pidtype JimStartWinProcess(Jim_Interp *interp, char **argv, char *env,
4300
- fdtype inputId, fdtype outputId, fdtype errorId);
4301
- static int JimErrno(void);
4302
-#else
4303
- #include <unistd.h>
4304
- #include <fcntl.h>
4305
- #include <sys/wait.h>
4306
- #include <sys/stat.h>
4307
-
4308
- typedef int fdtype;
4309
- typedef int pidtype;
4310
- #define JimPipe pipe
4311
- #define JimErrno() errno
4312
- #define JIM_BAD_FD -1
4313
- #define JIM_BAD_PID -1
4314
- #define JimFileno fileno
4315
- #define JimReadFd read
4316
- #define JimCloseFd close
4317
- #define JimWaitPid waitpid
4318
- #define JimDupFd dup
4319
- #define JimFdOpenForRead(FD) fdopen((FD), "r")
4320
- #define JimOpenForRead(NAME) open((NAME), O_RDONLY, 0)
4321
-
4322
- #ifndef HAVE_EXECVPE
4323
- #define execvpe(ARG0, ARGV, ENV) execvp(ARG0, ARGV)
4324
- #endif
4325
-#endif
4326
-
4327
-static const char *JimStrError(void);
4456
+#include <sys/stat.h>
4457
+
4458
+struct WaitInfoTable;
4459
+
4460
+static char **JimOriginalEnviron(void);
43284461
static char **JimSaveEnv(char **env);
43294462
static void JimRestoreEnv(char **env);
43304463
static int JimCreatePipeline(Jim_Interp *interp, int argc, Jim_Obj *const *argv,
4331
- pidtype **pidArrayPtr, fdtype *inPipePtr, fdtype *outPipePtr, fdtype *errFilePtr);
4332
-static void JimDetachPids(Jim_Interp *interp, int numPids, const pidtype *pidPtr);
4464
+ pidtype **pidArrayPtr, int *inPipePtr, int *outPipePtr, int *errFilePtr);
4465
+static void JimDetachPids(struct WaitInfoTable *table, int numPids, const pidtype *pidPtr);
43334466
static int JimCleanupChildren(Jim_Interp *interp, int numPids, pidtype *pidPtr, Jim_Obj *errStrObj);
4334
-static fdtype JimCreateTemp(Jim_Interp *interp, const char *contents, int len);
4335
-static fdtype JimOpenForWrite(const char *filename, int append);
4336
-static int JimRewindFd(fdtype fd);
4337
-
4338
-static void Jim_SetResultErrno(Jim_Interp *interp, const char *msg)
4339
-{
4340
- Jim_SetResultFormatted(interp, "%s: %s", msg, JimStrError());
4341
-}
4342
-
4343
-static const char *JimStrError(void)
4344
-{
4345
- return strerror(JimErrno());
4346
-}
4467
+static int Jim_WaitCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv);
4468
+
4469
+#if defined(__MINGW32__)
4470
+static pidtype JimStartWinProcess(Jim_Interp *interp, char **argv, char **env, int inputId, int outputId, int errorId);
4471
+#endif
43474472
43484473
static void Jim_RemoveTrailingNewline(Jim_Obj *objPtr)
43494474
{
43504475
int len;
43514476
const char *s = Jim_GetString(objPtr, &len);
@@ -4354,14 +4479,14 @@
43544479
objPtr->length--;
43554480
objPtr->bytes[objPtr->length] = '\0';
43564481
}
43574482
}
43584483
4359
-static int JimAppendStreamToString(Jim_Interp *interp, fdtype fd, Jim_Obj *strObj)
4484
+static int JimAppendStreamToString(Jim_Interp *interp, int fd, Jim_Obj *strObj)
43604485
{
43614486
char buf[256];
4362
- FILE *fh = JimFdOpenForRead(fd);
4487
+ FILE *fh = fdopen(fd, "r");
43634488
int ret = 0;
43644489
43654490
if (fh == NULL) {
43664491
return -1;
43674492
}
@@ -4390,18 +4515,18 @@
43904515
char *envdata;
43914516
43924517
Jim_Obj *objPtr = Jim_GetGlobalVariableStr(interp, "env", JIM_NONE);
43934518
43944519
if (!objPtr) {
4395
- return Jim_GetEnviron();
4520
+ return JimOriginalEnviron();
43964521
}
43974522
43984523
4399
-
4524
+
44004525
num = Jim_ListLength(interp, objPtr);
44014526
if (num % 2) {
4402
-
4527
+
44034528
num--;
44044529
}
44054530
size = Jim_Length(objPtr) + 2;
44064531
44074532
envptr = Jim_Alloc(sizeof(*envptr) * (num / 2 + 1) + size);
@@ -4433,79 +4558,76 @@
44334558
if (env != original_environ) {
44344559
Jim_Free(env);
44354560
}
44364561
}
44374562
4438
-#ifndef jim_ext_signal
4439
-
4440
-const char *Jim_SignalId(int sig)
4441
-{
4442
- static char buf[10];
4443
- snprintf(buf, sizeof(buf), "%d", sig);
4444
- return buf;
4445
-}
4446
-
4447
-const char *Jim_SignalName(int sig)
4448
-{
4449
- return Jim_SignalId(sig);
4450
-}
4451
-#endif
4452
-
4453
-static int JimCheckWaitStatus(Jim_Interp *interp, pidtype pid, int waitStatus, Jim_Obj *errStrObj)
4454
-{
4455
- Jim_Obj *errorCode;
4456
-
4457
- if (WIFEXITED(waitStatus) && WEXITSTATUS(waitStatus) == 0) {
4458
- return JIM_OK;
4459
- }
4460
- errorCode = Jim_NewListObj(interp, NULL, 0);
4461
-
4462
- if (WIFEXITED(waitStatus)) {
4563
+static Jim_Obj *JimMakeErrorCode(Jim_Interp *interp, pidtype pid, int waitStatus, Jim_Obj *errStrObj)
4564
+{
4565
+ Jim_Obj *errorCode = Jim_NewListObj(interp, NULL, 0);
4566
+
4567
+ if (pid == JIM_BAD_PID || pid == JIM_NO_PID) {
4568
+ Jim_ListAppendElement(interp, errorCode, Jim_NewStringObj(interp, "NONE", -1));
4569
+ Jim_ListAppendElement(interp, errorCode, Jim_NewIntObj(interp, (long)pid));
4570
+ Jim_ListAppendElement(interp, errorCode, Jim_NewIntObj(interp, -1));
4571
+ }
4572
+ else if (WIFEXITED(waitStatus)) {
44634573
Jim_ListAppendElement(interp, errorCode, Jim_NewStringObj(interp, "CHILDSTATUS", -1));
44644574
Jim_ListAppendElement(interp, errorCode, Jim_NewIntObj(interp, (long)pid));
44654575
Jim_ListAppendElement(interp, errorCode, Jim_NewIntObj(interp, WEXITSTATUS(waitStatus)));
44664576
}
44674577
else {
44684578
const char *type;
44694579
const char *action;
4580
+ const char *signame;
44704581
44714582
if (WIFSIGNALED(waitStatus)) {
44724583
type = "CHILDKILLED";
44734584
action = "killed";
4585
+ signame = Jim_SignalId(WTERMSIG(waitStatus));
44744586
}
44754587
else {
44764588
type = "CHILDSUSP";
44774589
action = "suspended";
4590
+ signame = "none";
44784591
}
44794592
44804593
Jim_ListAppendElement(interp, errorCode, Jim_NewStringObj(interp, type, -1));
44814594
44824595
if (errStrObj) {
44834596
Jim_AppendStrings(interp, errStrObj, "child ", action, " by signal ", Jim_SignalId(WTERMSIG(waitStatus)), "\n", NULL);
44844597
}
44854598
44864599
Jim_ListAppendElement(interp, errorCode, Jim_NewIntObj(interp, (long)pid));
4487
- Jim_ListAppendElement(interp, errorCode, Jim_NewStringObj(interp, Jim_SignalId(WTERMSIG(waitStatus)), -1));
4488
- Jim_ListAppendElement(interp, errorCode, Jim_NewStringObj(interp, Jim_SignalName(WTERMSIG(waitStatus)), -1));
4600
+ Jim_ListAppendElement(interp, errorCode, Jim_NewStringObj(interp, signame, -1));
44894601
}
4490
- Jim_SetGlobalVariableStr(interp, "errorCode", errorCode);
4602
+ return errorCode;
4603
+}
4604
+
4605
+static int JimCheckWaitStatus(Jim_Interp *interp, pidtype pid, int waitStatus, Jim_Obj *errStrObj)
4606
+{
4607
+ if (WIFEXITED(waitStatus) && WEXITSTATUS(waitStatus) == 0) {
4608
+ return JIM_OK;
4609
+ }
4610
+ Jim_SetGlobalVariableStr(interp, "errorCode", JimMakeErrorCode(interp, pid, waitStatus, errStrObj));
44914611
44924612
return JIM_ERR;
44934613
}
44944614
44954615
44964616
struct WaitInfo
44974617
{
4498
- pidtype pid;
4499
- int status;
4500
- int flags;
4618
+ pidtype pid;
4619
+ int status;
4620
+ int flags;
45014621
};
4622
+
45024623
45034624
struct WaitInfoTable {
4504
- struct WaitInfo *info;
4505
- int size;
4506
- int used;
4625
+ struct WaitInfo *info;
4626
+ int size;
4627
+ int used;
4628
+ int refcount;
45074629
};
45084630
45094631
45104632
#define WI_DETACHED 2
45114633
@@ -4513,32 +4635,53 @@
45134635
45144636
static void JimFreeWaitInfoTable(struct Jim_Interp *interp, void *privData)
45154637
{
45164638
struct WaitInfoTable *table = privData;
45174639
4518
- Jim_Free(table->info);
4519
- Jim_Free(table);
4640
+ if (--table->refcount == 0) {
4641
+ Jim_Free(table->info);
4642
+ Jim_Free(table);
4643
+ }
45204644
}
45214645
45224646
static struct WaitInfoTable *JimAllocWaitInfoTable(void)
45234647
{
45244648
struct WaitInfoTable *table = Jim_Alloc(sizeof(*table));
45254649
table->info = NULL;
45264650
table->size = table->used = 0;
4651
+ table->refcount = 1;
45274652
45284653
return table;
45294654
}
4655
+
4656
+static int JimWaitRemove(struct WaitInfoTable *table, pidtype pid)
4657
+{
4658
+ int i;
4659
+
4660
+
4661
+ for (i = 0; i < table->used; i++) {
4662
+ if (pid == table->info[i].pid) {
4663
+ if (i != table->used - 1) {
4664
+ table->info[i] = table->info[table->used - 1];
4665
+ }
4666
+ table->used--;
4667
+ return 0;
4668
+ }
4669
+ }
4670
+ return -1;
4671
+}
45304672
45314673
static int Jim_ExecCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
45324674
{
4533
- fdtype outputId;
4534
- fdtype errorId;
4675
+ int outputId;
4676
+ int errorId;
45354677
pidtype *pidPtr;
45364678
int numPids, result;
45374679
int child_siginfo = 1;
45384680
Jim_Obj *childErrObj;
45394681
Jim_Obj *errStrObj;
4682
+ struct WaitInfoTable *table = Jim_CmdPrivData(interp);
45404683
45414684
if (argc > 1 && Jim_CompareStringImmediate(interp, argv[argc - 1], "&")) {
45424685
Jim_Obj *listObj;
45434686
int i;
45444687
@@ -4545,17 +4688,17 @@
45454688
argc--;
45464689
numPids = JimCreatePipeline(interp, argc - 1, argv + 1, &pidPtr, NULL, NULL, NULL);
45474690
if (numPids < 0) {
45484691
return JIM_ERR;
45494692
}
4550
-
4693
+
45514694
listObj = Jim_NewListObj(interp, NULL, 0);
45524695
for (i = 0; i < numPids; i++) {
45534696
Jim_ListAppendElement(interp, listObj, Jim_NewIntObj(interp, (long)pidPtr[i]));
45544697
}
45554698
Jim_SetResult(interp, listObj);
4556
- JimDetachPids(interp, numPids, pidPtr);
4699
+ JimDetachPids(table, numPids, pidPtr);
45574700
Jim_Free(pidPtr);
45584701
return JIM_OK;
45594702
}
45604703
45614704
numPids =
@@ -4567,54 +4710,98 @@
45674710
45684711
result = JIM_OK;
45694712
45704713
errStrObj = Jim_NewStringObj(interp, "", 0);
45714714
4572
-
4573
- if (outputId != JIM_BAD_FD) {
4715
+
4716
+ if (outputId != -1) {
45744717
if (JimAppendStreamToString(interp, outputId, errStrObj) < 0) {
45754718
result = JIM_ERR;
45764719
Jim_SetResultErrno(interp, "error reading from output pipe");
45774720
}
45784721
}
45794722
4580
-
4723
+
45814724
childErrObj = Jim_NewStringObj(interp, "", 0);
45824725
Jim_IncrRefCount(childErrObj);
45834726
45844727
if (JimCleanupChildren(interp, numPids, pidPtr, childErrObj) != JIM_OK) {
45854728
result = JIM_ERR;
45864729
}
45874730
4588
- if (errorId != JIM_BAD_FD) {
4731
+ if (errorId != -1) {
45894732
int ret;
4590
- JimRewindFd(errorId);
4733
+ lseek(errorId, 0, SEEK_SET);
45914734
ret = JimAppendStreamToString(interp, errorId, errStrObj);
45924735
if (ret < 0) {
45934736
Jim_SetResultErrno(interp, "error reading from error pipe");
45944737
result = JIM_ERR;
45954738
}
45964739
else if (ret > 0) {
4597
-
4740
+
45984741
child_siginfo = 0;
45994742
}
46004743
}
46014744
46024745
if (child_siginfo) {
4603
-
4746
+
46044747
Jim_AppendObj(interp, errStrObj, childErrObj);
46054748
}
46064749
Jim_DecrRefCount(interp, childErrObj);
46074750
4608
-
4751
+
46094752
Jim_RemoveTrailingNewline(errStrObj);
46104753
4611
-
4754
+
46124755
Jim_SetResult(interp, errStrObj);
46134756
46144757
return result;
46154758
}
4759
+
4760
+static pidtype JimWaitForProcess(struct WaitInfoTable *table, pidtype pid, int *statusPtr)
4761
+{
4762
+ if (JimWaitRemove(table, pid) == 0) {
4763
+
4764
+ waitpid(pid, statusPtr, 0);
4765
+ return pid;
4766
+ }
4767
+
4768
+
4769
+ return JIM_BAD_PID;
4770
+}
4771
+
4772
+static void JimDetachPids(struct WaitInfoTable *table, int numPids, const pidtype *pidPtr)
4773
+{
4774
+ int j;
4775
+
4776
+ for (j = 0; j < numPids; j++) {
4777
+
4778
+ int i;
4779
+ for (i = 0; i < table->used; i++) {
4780
+ if (pidPtr[j] == table->info[i].pid) {
4781
+ table->info[i].flags |= WI_DETACHED;
4782
+ break;
4783
+ }
4784
+ }
4785
+ }
4786
+}
4787
+
4788
+static int JimGetChannelFd(Jim_Interp *interp, const char *name)
4789
+{
4790
+ Jim_Obj *objv[2];
4791
+
4792
+ objv[0] = Jim_NewStringObj(interp, name, -1);
4793
+ objv[1] = Jim_NewStringObj(interp, "getfd", -1);
4794
+
4795
+ if (Jim_EvalObjVector(interp, 2, objv) == JIM_OK) {
4796
+ jim_wide fd;
4797
+ if (Jim_GetWide(interp, Jim_GetResult(interp), &fd) == JIM_OK) {
4798
+ return fd;
4799
+ }
4800
+ }
4801
+ return -1;
4802
+}
46164803
46174804
static void JimReapDetachedPids(struct WaitInfoTable *table)
46184805
{
46194806
struct WaitInfo *waitPtr;
46204807
int count;
@@ -4627,13 +4814,13 @@
46274814
waitPtr = table->info;
46284815
dest = 0;
46294816
for (count = table->used; count > 0; waitPtr++, count--) {
46304817
if (waitPtr->flags & WI_DETACHED) {
46314818
int status;
4632
- pidtype pid = JimWaitPid(waitPtr->pid, &status, WNOHANG);
4819
+ pidtype pid = waitpid(waitPtr->pid, &status, WNOHANG);
46334820
if (pid == waitPtr->pid) {
4634
-
4821
+
46354822
table->used--;
46364823
continue;
46374824
}
46384825
}
46394826
if (waitPtr != &table->info[dest]) {
@@ -4641,66 +4828,62 @@
46414828
}
46424829
dest++;
46434830
}
46444831
}
46454832
4646
-static pidtype JimWaitForProcess(struct WaitInfoTable *table, pidtype pid, int *statusPtr)
4647
-{
4648
- int i;
4649
-
4650
-
4651
- for (i = 0; i < table->used; i++) {
4652
- if (pid == table->info[i].pid) {
4653
-
4654
- JimWaitPid(pid, statusPtr, 0);
4655
-
4656
-
4657
- if (i != table->used - 1) {
4658
- table->info[i] = table->info[table->used - 1];
4659
- }
4660
- table->used--;
4661
- return pid;
4662
- }
4663
- }
4664
-
4665
-
4666
- return JIM_BAD_PID;
4667
-}
4668
-
4669
-static void JimDetachPids(Jim_Interp *interp, int numPids, const pidtype *pidPtr)
4670
-{
4671
- int j;
4833
+static int Jim_WaitCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
4834
+{
46724835
struct WaitInfoTable *table = Jim_CmdPrivData(interp);
4673
-
4674
- for (j = 0; j < numPids; j++) {
4675
-
4676
- int i;
4677
- for (i = 0; i < table->used; i++) {
4678
- if (pidPtr[j] == table->info[i].pid) {
4679
- table->info[i].flags |= WI_DETACHED;
4680
- break;
4681
- }
4682
- }
4683
- }
4684
-}
4685
-
4686
-static FILE *JimGetAioFilehandle(Jim_Interp *interp, const char *name)
4687
-{
4688
- FILE *fh;
4689
- Jim_Obj *fhObj;
4690
-
4691
- fhObj = Jim_NewStringObj(interp, name, -1);
4692
- Jim_IncrRefCount(fhObj);
4693
- fh = Jim_AioFilehandle(interp, fhObj);
4694
- Jim_DecrRefCount(interp, fhObj);
4695
-
4696
- return fh;
4836
+ int nohang = 0;
4837
+ pidtype pid;
4838
+ long pidarg;
4839
+ int status;
4840
+ Jim_Obj *errCodeObj;
4841
+
4842
+
4843
+ if (argc == 1) {
4844
+ JimReapDetachedPids(table);
4845
+ return JIM_OK;
4846
+ }
4847
+
4848
+ if (argc > 1 && Jim_CompareStringImmediate(interp, argv[1], "-nohang")) {
4849
+ nohang = 1;
4850
+ }
4851
+ if (argc != nohang + 2) {
4852
+ Jim_WrongNumArgs(interp, 1, argv, "?-nohang? ?pid?");
4853
+ return JIM_ERR;
4854
+ }
4855
+ if (Jim_GetLong(interp, argv[nohang + 1], &pidarg) != JIM_OK) {
4856
+ return JIM_ERR;
4857
+ }
4858
+
4859
+ pid = waitpid((pidtype)pidarg, &status, nohang ? WNOHANG : 0);
4860
+
4861
+ errCodeObj = JimMakeErrorCode(interp, pid, status, NULL);
4862
+
4863
+ if (pid != JIM_BAD_PID && (WIFEXITED(status) || WIFSIGNALED(status))) {
4864
+
4865
+ JimWaitRemove(table, pid);
4866
+ }
4867
+ Jim_SetResult(interp, errCodeObj);
4868
+ return JIM_OK;
4869
+}
4870
+
4871
+static int Jim_PidCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
4872
+{
4873
+ if (argc != 1) {
4874
+ Jim_WrongNumArgs(interp, 1, argv, "");
4875
+ return JIM_ERR;
4876
+ }
4877
+
4878
+ Jim_SetResultInt(interp, (jim_wide)getpid());
4879
+ return JIM_OK;
46974880
}
46984881
46994882
static int
47004883
JimCreatePipeline(Jim_Interp *interp, int argc, Jim_Obj *const *argv, pidtype **pidArrayPtr,
4701
- fdtype *inPipePtr, fdtype *outPipePtr, fdtype *errFilePtr)
4884
+ int *inPipePtr, int *outPipePtr, int *errFilePtr)
47024885
{
47034886
pidtype *pidPtr = NULL; /* Points to malloc-ed array holding all
47044887
* the pids of child processes. */
47054888
int numPids = 0; /* Actual number of processes that exist
47064889
* at *pidPtr right now. */
@@ -4707,16 +4890,16 @@
47074890
int cmdCount; /* Count of number of distinct commands
47084891
* found in argc/argv. */
47094892
const char *input = NULL; /* Describes input for pipeline, depending
47104893
* on "inputFile". NULL means take input
47114894
* from stdin/pipe. */
4712
- int input_len = 0;
4895
+ int input_len = 0;
47134896
4714
-#define FILE_NAME 0
4715
-#define FILE_APPEND 1
4716
-#define FILE_HANDLE 2
4717
-#define FILE_TEXT 3
4897
+#define FILE_NAME 0
4898
+#define FILE_APPEND 1
4899
+#define FILE_HANDLE 2
4900
+#define FILE_TEXT 3
47184901
47194902
int inputFile = FILE_NAME; /* 1 means input is name of input file.
47204903
* 2 means input is filehandle name.
47214904
* 0 means input holds actual
47224905
* text to be input to command. */
@@ -4733,39 +4916,40 @@
47334916
*/
47344917
const char *output = NULL; /* Holds name of output file to pipe to,
47354918
* or NULL if output goes to stdout/pipe. */
47364919
const char *error = NULL; /* Holds name of stderr file to pipe to,
47374920
* or NULL if stderr goes to stderr/pipe. */
4738
- fdtype inputId = JIM_BAD_FD;
4739
- fdtype outputId = JIM_BAD_FD;
4740
- fdtype errorId = JIM_BAD_FD;
4741
- fdtype lastOutputId = JIM_BAD_FD;
4742
- fdtype pipeIds[2];
4921
+ int inputId = -1;
4922
+ int outputId = -1;
4923
+ int errorId = -1;
4924
+ int lastOutputId = -1;
4925
+ int pipeIds[2];
47434926
int firstArg, lastArg; /* Indexes of first and last arguments in
47444927
* current command. */
47454928
int lastBar;
47464929
int i;
47474930
pidtype pid;
47484931
char **save_environ;
4932
+#ifndef __MINGW32__
4933
+ char **child_environ;
4934
+#endif
47494935
struct WaitInfoTable *table = Jim_CmdPrivData(interp);
47504936
4751
-
4937
+
47524938
char **arg_array = Jim_Alloc(sizeof(*arg_array) * (argc + 1));
47534939
int arg_count = 0;
47544940
4755
- JimReapDetachedPids(table);
4756
-
47574941
if (inPipePtr != NULL) {
4758
- *inPipePtr = JIM_BAD_FD;
4942
+ *inPipePtr = -1;
47594943
}
47604944
if (outPipePtr != NULL) {
4761
- *outPipePtr = JIM_BAD_FD;
4945
+ *outPipePtr = -1;
47624946
}
47634947
if (errFilePtr != NULL) {
4764
- *errFilePtr = JIM_BAD_FD;
4948
+ *errFilePtr = -1;
47654949
}
4766
- pipeIds[0] = pipeIds[1] = JIM_BAD_FD;
4950
+ pipeIds[0] = pipeIds[1] = -1;
47674951
47684952
cmdCount = 1;
47694953
lastBar = -1;
47704954
for (i = 0; i < argc; i++) {
47714955
const char *arg = Jim_String(argv[i]);
@@ -4796,11 +4980,11 @@
47964980
if (*output == '>') {
47974981
outputFile = FILE_APPEND;
47984982
output++;
47994983
}
48004984
if (*output == '&') {
4801
-
4985
+
48024986
output++;
48034987
dup_error = 1;
48044988
}
48054989
if (*output == '@') {
48064990
outputFile = FILE_HANDLE;
@@ -4837,11 +5021,11 @@
48375021
goto badargs;
48385022
}
48395023
lastBar = i;
48405024
cmdCount++;
48415025
}
4842
-
5026
+
48435027
arg_array[arg_count++] = (char *)arg;
48445028
continue;
48455029
}
48465030
48475031
if (i >= argc) {
@@ -4855,183 +5039,227 @@
48555039
badargs:
48565040
Jim_Free(arg_array);
48575041
return -1;
48585042
}
48595043
4860
-
5044
+
48615045
save_environ = JimSaveEnv(JimBuildEnv(interp));
48625046
48635047
if (input != NULL) {
48645048
if (inputFile == FILE_TEXT) {
4865
- inputId = JimCreateTemp(interp, input, input_len);
4866
- if (inputId == JIM_BAD_FD) {
5049
+ inputId = Jim_MakeTempFile(interp, NULL, 1);
5050
+ if (inputId == -1) {
5051
+ goto error;
5052
+ }
5053
+ if (write(inputId, input, input_len) != input_len) {
5054
+ Jim_SetResultErrno(interp, "couldn't write temp file");
5055
+ close(inputId);
48675056
goto error;
48685057
}
5058
+ lseek(inputId, 0L, SEEK_SET);
48695059
}
48705060
else if (inputFile == FILE_HANDLE) {
4871
-
4872
- FILE *fh = JimGetAioFilehandle(interp, input);
5061
+ int fd = JimGetChannelFd(interp, input);
48735062
4874
- if (fh == NULL) {
5063
+ if (fd < 0) {
48755064
goto error;
48765065
}
4877
- inputId = JimDupFd(JimFileno(fh));
5066
+ inputId = dup(fd);
48785067
}
48795068
else {
4880
- inputId = JimOpenForRead(input);
4881
- if (inputId == JIM_BAD_FD) {
4882
- Jim_SetResultFormatted(interp, "couldn't read file \"%s\": %s", input, JimStrError());
5069
+ inputId = Jim_OpenForRead(input);
5070
+ if (inputId == -1) {
5071
+ Jim_SetResultFormatted(interp, "couldn't read file \"%s\": %s", input, strerror(Jim_Errno()));
48835072
goto error;
48845073
}
48855074
}
48865075
}
48875076
else if (inPipePtr != NULL) {
4888
- if (JimPipe(pipeIds) != 0) {
5077
+ if (pipe(pipeIds) != 0) {
48895078
Jim_SetResultErrno(interp, "couldn't create input pipe for command");
48905079
goto error;
48915080
}
48925081
inputId = pipeIds[0];
48935082
*inPipePtr = pipeIds[1];
4894
- pipeIds[0] = pipeIds[1] = JIM_BAD_FD;
5083
+ pipeIds[0] = pipeIds[1] = -1;
48955084
}
48965085
48975086
if (output != NULL) {
48985087
if (outputFile == FILE_HANDLE) {
4899
- FILE *fh = JimGetAioFilehandle(interp, output);
4900
- if (fh == NULL) {
5088
+ int fd = JimGetChannelFd(interp, output);
5089
+ if (fd < 0) {
49015090
goto error;
49025091
}
4903
- fflush(fh);
4904
- lastOutputId = JimDupFd(JimFileno(fh));
5092
+ lastOutputId = dup(fd);
49055093
}
49065094
else {
4907
- lastOutputId = JimOpenForWrite(output, outputFile == FILE_APPEND);
4908
- if (lastOutputId == JIM_BAD_FD) {
4909
- Jim_SetResultFormatted(interp, "couldn't write file \"%s\": %s", output, JimStrError());
5095
+ lastOutputId = Jim_OpenForWrite(output, outputFile == FILE_APPEND);
5096
+ if (lastOutputId == -1) {
5097
+ Jim_SetResultFormatted(interp, "couldn't write file \"%s\": %s", output, strerror(Jim_Errno()));
49105098
goto error;
49115099
}
49125100
}
49135101
}
49145102
else if (outPipePtr != NULL) {
4915
- if (JimPipe(pipeIds) != 0) {
5103
+ if (pipe(pipeIds) != 0) {
49165104
Jim_SetResultErrno(interp, "couldn't create output pipe");
49175105
goto error;
49185106
}
49195107
lastOutputId = pipeIds[1];
49205108
*outPipePtr = pipeIds[0];
4921
- pipeIds[0] = pipeIds[1] = JIM_BAD_FD;
5109
+ pipeIds[0] = pipeIds[1] = -1;
49225110
}
4923
-
5111
+
49245112
if (error != NULL) {
49255113
if (errorFile == FILE_HANDLE) {
49265114
if (strcmp(error, "1") == 0) {
4927
-
4928
- if (lastOutputId != JIM_BAD_FD) {
4929
- errorId = JimDupFd(lastOutputId);
5115
+
5116
+ if (lastOutputId != -1) {
5117
+ errorId = dup(lastOutputId);
49305118
}
49315119
else {
4932
-
5120
+
49335121
error = "stdout";
49345122
}
49355123
}
4936
- if (errorId == JIM_BAD_FD) {
4937
- FILE *fh = JimGetAioFilehandle(interp, error);
4938
- if (fh == NULL) {
5124
+ if (errorId == -1) {
5125
+ int fd = JimGetChannelFd(interp, error);
5126
+ if (fd < 0) {
49395127
goto error;
49405128
}
4941
- fflush(fh);
4942
- errorId = JimDupFd(JimFileno(fh));
5129
+ errorId = dup(fd);
49435130
}
49445131
}
49455132
else {
4946
- errorId = JimOpenForWrite(error, errorFile == FILE_APPEND);
4947
- if (errorId == JIM_BAD_FD) {
4948
- Jim_SetResultFormatted(interp, "couldn't write file \"%s\": %s", error, JimStrError());
5133
+ errorId = Jim_OpenForWrite(error, errorFile == FILE_APPEND);
5134
+ if (errorId == -1) {
5135
+ Jim_SetResultFormatted(interp, "couldn't write file \"%s\": %s", error, strerror(Jim_Errno()));
49495136
goto error;
49505137
}
49515138
}
49525139
}
49535140
else if (errFilePtr != NULL) {
4954
- errorId = JimCreateTemp(interp, NULL, 0);
4955
- if (errorId == JIM_BAD_FD) {
5141
+ errorId = Jim_MakeTempFile(interp, NULL, 1);
5142
+ if (errorId == -1) {
49565143
goto error;
49575144
}
4958
- *errFilePtr = JimDupFd(errorId);
5145
+ *errFilePtr = dup(errorId);
49595146
}
49605147
49615148
49625149
pidPtr = Jim_Alloc(cmdCount * sizeof(*pidPtr));
49635150
for (i = 0; i < numPids; i++) {
49645151
pidPtr[i] = JIM_BAD_PID;
49655152
}
49665153
for (firstArg = 0; firstArg < arg_count; numPids++, firstArg = lastArg + 1) {
49675154
int pipe_dup_err = 0;
4968
- fdtype origErrorId = errorId;
5155
+ int origErrorId = errorId;
49695156
49705157
for (lastArg = firstArg; lastArg < arg_count; lastArg++) {
4971
- if (arg_array[lastArg][0] == '|') {
4972
- if (arg_array[lastArg][1] == '&') {
4973
- pipe_dup_err = 1;
4974
- }
5158
+ if (strcmp(arg_array[lastArg], "|") == 0) {
5159
+ break;
5160
+ }
5161
+ if (strcmp(arg_array[lastArg], "|&") == 0) {
5162
+ pipe_dup_err = 1;
49755163
break;
49765164
}
49775165
}
4978
-
5166
+
5167
+ if (lastArg == firstArg) {
5168
+ Jim_SetResultString(interp, "missing command to exec", -1);
5169
+ goto error;
5170
+ }
5171
+
5172
+
49795173
arg_array[lastArg] = NULL;
49805174
if (lastArg == arg_count) {
49815175
outputId = lastOutputId;
5176
+ lastOutputId = -1;
49825177
}
49835178
else {
4984
- if (JimPipe(pipeIds) != 0) {
5179
+ if (pipe(pipeIds) != 0) {
49855180
Jim_SetResultErrno(interp, "couldn't create pipe");
49865181
goto error;
49875182
}
49885183
outputId = pipeIds[1];
49895184
}
49905185
4991
-
5186
+
49925187
if (pipe_dup_err) {
49935188
errorId = outputId;
49945189
}
49955190
4996
-
5191
+
49975192
49985193
#ifdef __MINGW32__
4999
- pid = JimStartWinProcess(interp, &arg_array[firstArg], save_environ ? save_environ[0] : NULL, inputId, outputId, errorId);
5194
+ pid = JimStartWinProcess(interp, &arg_array[firstArg], save_environ, inputId, outputId, errorId);
50005195
if (pid == JIM_BAD_PID) {
50015196
Jim_SetResultFormatted(interp, "couldn't exec \"%s\"", arg_array[firstArg]);
50025197
goto error;
50035198
}
50045199
#else
5200
+ i = strlen(arg_array[firstArg]);
5201
+
5202
+ child_environ = Jim_GetEnviron();
50055203
pid = vfork();
50065204
if (pid < 0) {
50075205
Jim_SetResultErrno(interp, "couldn't fork child process");
50085206
goto error;
50095207
}
50105208
if (pid == 0) {
5011
-
5012
-
5013
- if (inputId != -1) dup2(inputId, 0);
5014
- if (outputId != -1) dup2(outputId, 1);
5015
- if (errorId != -1) dup2(errorId, 2);
5016
-
5017
- for (i = 3; (i <= outputId) || (i <= inputId) || (i <= errorId); i++) {
5018
- close(i);
5209
+
5210
+
5211
+ if (inputId != -1) {
5212
+ dup2(inputId, fileno(stdin));
5213
+ close(inputId);
5214
+ }
5215
+ if (outputId != -1) {
5216
+ dup2(outputId, fileno(stdout));
5217
+ if (outputId != errorId) {
5218
+ close(outputId);
5219
+ }
5220
+ }
5221
+ if (errorId != -1) {
5222
+ dup2(errorId, fileno(stderr));
5223
+ close(errorId);
50195224
}
50205225
5021
-
5226
+ if (outPipePtr) {
5227
+ close(*outPipePtr);
5228
+ }
5229
+ if (errFilePtr) {
5230
+ close(*errFilePtr);
5231
+ }
5232
+ if (pipeIds[0] != -1) {
5233
+ close(pipeIds[0]);
5234
+ }
5235
+ if (lastOutputId != -1) {
5236
+ close(lastOutputId);
5237
+ }
5238
+
5239
+
50225240
(void)signal(SIGPIPE, SIG_DFL);
50235241
5024
- execvpe(arg_array[firstArg], &arg_array[firstArg], Jim_GetEnviron());
5242
+ execvpe(arg_array[firstArg], &arg_array[firstArg], child_environ);
50255243
5026
-
5027
- fprintf(stderr, "couldn't exec \"%s\"\n", arg_array[firstArg]);
5244
+ if (write(fileno(stderr), "couldn't exec \"", 15) &&
5245
+ write(fileno(stderr), arg_array[firstArg], i) &&
5246
+ write(fileno(stderr), "\"\n", 2)) {
5247
+
5248
+ }
5249
+#ifdef JIM_MAINTAINER
5250
+ {
5251
+
5252
+ static char *const false_argv[2] = {"false", NULL};
5253
+ execvp(false_argv[0],false_argv);
5254
+ }
5255
+#endif
50285256
_exit(127);
50295257
}
50305258
#endif
50315259
5032
-
5260
+
50335261
50345262
if (table->used == table->size) {
50355263
table->size += WAIT_TABLE_GROW_BY;
50365264
table->info = Jim_Realloc(table->info, table->size * sizeof(*table->info));
50375265
}
@@ -5040,66 +5268,66 @@
50405268
table->info[table->used].flags = 0;
50415269
table->used++;
50425270
50435271
pidPtr[numPids] = pid;
50445272
5045
-
5273
+
50465274
errorId = origErrorId;
50475275
50485276
5049
- if (inputId != JIM_BAD_FD) {
5050
- JimCloseFd(inputId);
5277
+ if (inputId != -1) {
5278
+ close(inputId);
50515279
}
5052
- if (outputId != JIM_BAD_FD) {
5053
- JimCloseFd(outputId);
5280
+ if (outputId != -1) {
5281
+ close(outputId);
50545282
}
50555283
inputId = pipeIds[0];
5056
- pipeIds[0] = pipeIds[1] = JIM_BAD_FD;
5284
+ pipeIds[0] = pipeIds[1] = -1;
50575285
}
50585286
*pidArrayPtr = pidPtr;
50595287
50605288
50615289
cleanup:
5062
- if (inputId != JIM_BAD_FD) {
5063
- JimCloseFd(inputId);
5064
- }
5065
- if (lastOutputId != JIM_BAD_FD) {
5066
- JimCloseFd(lastOutputId);
5067
- }
5068
- if (errorId != JIM_BAD_FD) {
5069
- JimCloseFd(errorId);
5290
+ if (inputId != -1) {
5291
+ close(inputId);
5292
+ }
5293
+ if (lastOutputId != -1) {
5294
+ close(lastOutputId);
5295
+ }
5296
+ if (errorId != -1) {
5297
+ close(errorId);
50705298
}
50715299
Jim_Free(arg_array);
50725300
50735301
JimRestoreEnv(save_environ);
50745302
50755303
return numPids;
50765304
50775305
50785306
error:
5079
- if ((inPipePtr != NULL) && (*inPipePtr != JIM_BAD_FD)) {
5080
- JimCloseFd(*inPipePtr);
5081
- *inPipePtr = JIM_BAD_FD;
5082
- }
5083
- if ((outPipePtr != NULL) && (*outPipePtr != JIM_BAD_FD)) {
5084
- JimCloseFd(*outPipePtr);
5085
- *outPipePtr = JIM_BAD_FD;
5086
- }
5087
- if ((errFilePtr != NULL) && (*errFilePtr != JIM_BAD_FD)) {
5088
- JimCloseFd(*errFilePtr);
5089
- *errFilePtr = JIM_BAD_FD;
5090
- }
5091
- if (pipeIds[0] != JIM_BAD_FD) {
5092
- JimCloseFd(pipeIds[0]);
5093
- }
5094
- if (pipeIds[1] != JIM_BAD_FD) {
5095
- JimCloseFd(pipeIds[1]);
5307
+ if ((inPipePtr != NULL) && (*inPipePtr != -1)) {
5308
+ close(*inPipePtr);
5309
+ *inPipePtr = -1;
5310
+ }
5311
+ if ((outPipePtr != NULL) && (*outPipePtr != -1)) {
5312
+ close(*outPipePtr);
5313
+ *outPipePtr = -1;
5314
+ }
5315
+ if ((errFilePtr != NULL) && (*errFilePtr != -1)) {
5316
+ close(*errFilePtr);
5317
+ *errFilePtr = -1;
5318
+ }
5319
+ if (pipeIds[0] != -1) {
5320
+ close(pipeIds[0]);
5321
+ }
5322
+ if (pipeIds[1] != -1) {
5323
+ close(pipeIds[1]);
50965324
}
50975325
if (pidPtr != NULL) {
50985326
for (i = 0; i < numPids; i++) {
50995327
if (pidPtr[i] != JIM_BAD_PID) {
5100
- JimDetachPids(interp, 1, &pidPtr[i]);
5328
+ JimDetachPids(table, 1, &pidPtr[i]);
51015329
}
51025330
}
51035331
Jim_Free(pidPtr);
51045332
}
51055333
numPids = -1;
@@ -5111,11 +5339,11 @@
51115339
{
51125340
struct WaitInfoTable *table = Jim_CmdPrivData(interp);
51135341
int result = JIM_OK;
51145342
int i;
51155343
5116
-
5344
+
51175345
for (i = 0; i < numPids; i++) {
51185346
int waitStatus = 0;
51195347
if (JimWaitForProcess(table, pidPtr[i], &waitStatus) != JIM_BAD_PID) {
51205348
if (JimCheckWaitStatus(interp, pidPtr[i], waitStatus, errStrObj) != JIM_OK) {
51215349
result = JIM_ERR;
@@ -5127,234 +5355,30 @@
51275355
return result;
51285356
}
51295357
51305358
int Jim_execInit(Jim_Interp *interp)
51315359
{
5360
+ struct WaitInfoTable *waitinfo;
51325361
if (Jim_PackageProvide(interp, "exec", "1.0", JIM_ERRMSG))
51335362
return JIM_ERR;
51345363
51355364
#ifdef SIGPIPE
51365365
(void)signal(SIGPIPE, SIG_IGN);
51375366
#endif
51385367
5139
- Jim_CreateCommand(interp, "exec", Jim_ExecCmd, JimAllocWaitInfoTable(), JimFreeWaitInfoTable);
5368
+ waitinfo = JimAllocWaitInfoTable();
5369
+ Jim_CreateCommand(interp, "exec", Jim_ExecCmd, waitinfo, JimFreeWaitInfoTable);
5370
+ waitinfo->refcount++;
5371
+ Jim_CreateCommand(interp, "wait", Jim_WaitCommand, waitinfo, JimFreeWaitInfoTable);
5372
+ Jim_CreateCommand(interp, "pid", Jim_PidCommand, 0, 0);
5373
+
51405374
return JIM_OK;
51415375
}
51425376
51435377
#if defined(__MINGW32__)
51445378
51455379
5146
-static SECURITY_ATTRIBUTES *JimStdSecAttrs(void)
5147
-{
5148
- static SECURITY_ATTRIBUTES secAtts;
5149
-
5150
- secAtts.nLength = sizeof(SECURITY_ATTRIBUTES);
5151
- secAtts.lpSecurityDescriptor = NULL;
5152
- secAtts.bInheritHandle = TRUE;
5153
- return &secAtts;
5154
-}
5155
-
5156
-static int JimErrno(void)
5157
-{
5158
- switch (GetLastError()) {
5159
- case ERROR_FILE_NOT_FOUND: return ENOENT;
5160
- case ERROR_PATH_NOT_FOUND: return ENOENT;
5161
- case ERROR_TOO_MANY_OPEN_FILES: return EMFILE;
5162
- case ERROR_ACCESS_DENIED: return EACCES;
5163
- case ERROR_INVALID_HANDLE: return EBADF;
5164
- case ERROR_BAD_ENVIRONMENT: return E2BIG;
5165
- case ERROR_BAD_FORMAT: return ENOEXEC;
5166
- case ERROR_INVALID_ACCESS: return EACCES;
5167
- case ERROR_INVALID_DRIVE: return ENOENT;
5168
- case ERROR_CURRENT_DIRECTORY: return EACCES;
5169
- case ERROR_NOT_SAME_DEVICE: return EXDEV;
5170
- case ERROR_NO_MORE_FILES: return ENOENT;
5171
- case ERROR_WRITE_PROTECT: return EROFS;
5172
- case ERROR_BAD_UNIT: return ENXIO;
5173
- case ERROR_NOT_READY: return EBUSY;
5174
- case ERROR_BAD_COMMAND: return EIO;
5175
- case ERROR_CRC: return EIO;
5176
- case ERROR_BAD_LENGTH: return EIO;
5177
- case ERROR_SEEK: return EIO;
5178
- case ERROR_WRITE_FAULT: return EIO;
5179
- case ERROR_READ_FAULT: return EIO;
5180
- case ERROR_GEN_FAILURE: return EIO;
5181
- case ERROR_SHARING_VIOLATION: return EACCES;
5182
- case ERROR_LOCK_VIOLATION: return EACCES;
5183
- case ERROR_SHARING_BUFFER_EXCEEDED: return ENFILE;
5184
- case ERROR_HANDLE_DISK_FULL: return ENOSPC;
5185
- case ERROR_NOT_SUPPORTED: return ENODEV;
5186
- case ERROR_REM_NOT_LIST: return EBUSY;
5187
- case ERROR_DUP_NAME: return EEXIST;
5188
- case ERROR_BAD_NETPATH: return ENOENT;
5189
- case ERROR_NETWORK_BUSY: return EBUSY;
5190
- case ERROR_DEV_NOT_EXIST: return ENODEV;
5191
- case ERROR_TOO_MANY_CMDS: return EAGAIN;
5192
- case ERROR_ADAP_HDW_ERR: return EIO;
5193
- case ERROR_BAD_NET_RESP: return EIO;
5194
- case ERROR_UNEXP_NET_ERR: return EIO;
5195
- case ERROR_NETNAME_DELETED: return ENOENT;
5196
- case ERROR_NETWORK_ACCESS_DENIED: return EACCES;
5197
- case ERROR_BAD_DEV_TYPE: return ENODEV;
5198
- case ERROR_BAD_NET_NAME: return ENOENT;
5199
- case ERROR_TOO_MANY_NAMES: return ENFILE;
5200
- case ERROR_TOO_MANY_SESS: return EIO;
5201
- case ERROR_SHARING_PAUSED: return EAGAIN;
5202
- case ERROR_REDIR_PAUSED: return EAGAIN;
5203
- case ERROR_FILE_EXISTS: return EEXIST;
5204
- case ERROR_CANNOT_MAKE: return ENOSPC;
5205
- case ERROR_OUT_OF_STRUCTURES: return ENFILE;
5206
- case ERROR_ALREADY_ASSIGNED: return EEXIST;
5207
- case ERROR_INVALID_PASSWORD: return EPERM;
5208
- case ERROR_NET_WRITE_FAULT: return EIO;
5209
- case ERROR_NO_PROC_SLOTS: return EAGAIN;
5210
- case ERROR_DISK_CHANGE: return EXDEV;
5211
- case ERROR_BROKEN_PIPE: return EPIPE;
5212
- case ERROR_OPEN_FAILED: return ENOENT;
5213
- case ERROR_DISK_FULL: return ENOSPC;
5214
- case ERROR_NO_MORE_SEARCH_HANDLES: return EMFILE;
5215
- case ERROR_INVALID_TARGET_HANDLE: return EBADF;
5216
- case ERROR_INVALID_NAME: return ENOENT;
5217
- case ERROR_PROC_NOT_FOUND: return ESRCH;
5218
- case ERROR_WAIT_NO_CHILDREN: return ECHILD;
5219
- case ERROR_CHILD_NOT_COMPLETE: return ECHILD;
5220
- case ERROR_DIRECT_ACCESS_HANDLE: return EBADF;
5221
- case ERROR_SEEK_ON_DEVICE: return ESPIPE;
5222
- case ERROR_BUSY_DRIVE: return EAGAIN;
5223
- case ERROR_DIR_NOT_EMPTY: return EEXIST;
5224
- case ERROR_NOT_LOCKED: return EACCES;
5225
- case ERROR_BAD_PATHNAME: return ENOENT;
5226
- case ERROR_LOCK_FAILED: return EACCES;
5227
- case ERROR_ALREADY_EXISTS: return EEXIST;
5228
- case ERROR_FILENAME_EXCED_RANGE: return ENAMETOOLONG;
5229
- case ERROR_BAD_PIPE: return EPIPE;
5230
- case ERROR_PIPE_BUSY: return EAGAIN;
5231
- case ERROR_PIPE_NOT_CONNECTED: return EPIPE;
5232
- case ERROR_DIRECTORY: return ENOTDIR;
5233
- }
5234
- return EINVAL;
5235
-}
5236
-
5237
-static int JimPipe(fdtype pipefd[2])
5238
-{
5239
- if (CreatePipe(&pipefd[0], &pipefd[1], NULL, 0)) {
5240
- return 0;
5241
- }
5242
- return -1;
5243
-}
5244
-
5245
-static fdtype JimDupFd(fdtype infd)
5246
-{
5247
- fdtype dupfd;
5248
- pidtype pid = GetCurrentProcess();
5249
-
5250
- if (DuplicateHandle(pid, infd, pid, &dupfd, 0, TRUE, DUPLICATE_SAME_ACCESS)) {
5251
- return dupfd;
5252
- }
5253
- return JIM_BAD_FD;
5254
-}
5255
-
5256
-static int JimRewindFd(fdtype fd)
5257
-{
5258
- return SetFilePointer(fd, 0, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER ? -1 : 0;
5259
-}
5260
-
5261
-#if 0
5262
-static int JimReadFd(fdtype fd, char *buffer, size_t len)
5263
-{
5264
- DWORD num;
5265
-
5266
- if (ReadFile(fd, buffer, len, &num, NULL)) {
5267
- return num;
5268
- }
5269
- if (GetLastError() == ERROR_HANDLE_EOF || GetLastError() == ERROR_BROKEN_PIPE) {
5270
- return 0;
5271
- }
5272
- return -1;
5273
-}
5274
-#endif
5275
-
5276
-static FILE *JimFdOpenForRead(fdtype fd)
5277
-{
5278
- return _fdopen(_open_osfhandle((int)fd, _O_RDONLY | _O_TEXT), "r");
5279
-}
5280
-
5281
-static fdtype JimFileno(FILE *fh)
5282
-{
5283
- return (fdtype)_get_osfhandle(_fileno(fh));
5284
-}
5285
-
5286
-static fdtype JimOpenForRead(const char *filename)
5287
-{
5288
- return CreateFile(filename, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
5289
- JimStdSecAttrs(), OPEN_EXISTING, 0, NULL);
5290
-}
5291
-
5292
-static fdtype JimOpenForWrite(const char *filename, int append)
5293
-{
5294
- return CreateFile(filename, append ? FILE_APPEND_DATA : GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
5295
- JimStdSecAttrs(), append ? OPEN_ALWAYS : CREATE_ALWAYS, 0, (HANDLE) NULL);
5296
-}
5297
-
5298
-static FILE *JimFdOpenForWrite(fdtype fd)
5299
-{
5300
- return _fdopen(_open_osfhandle((int)fd, _O_TEXT), "w");
5301
-}
5302
-
5303
-static pidtype JimWaitPid(pidtype pid, int *status, int nohang)
5304
-{
5305
- DWORD ret = WaitForSingleObject(pid, nohang ? 0 : INFINITE);
5306
- if (ret == WAIT_TIMEOUT || ret == WAIT_FAILED) {
5307
-
5308
- return JIM_BAD_PID;
5309
- }
5310
- GetExitCodeProcess(pid, &ret);
5311
- *status = ret;
5312
- CloseHandle(pid);
5313
- return pid;
5314
-}
5315
-
5316
-static HANDLE JimCreateTemp(Jim_Interp *interp, const char *contents, int len)
5317
-{
5318
- char name[MAX_PATH];
5319
- HANDLE handle;
5320
-
5321
- if (!GetTempPath(MAX_PATH, name) || !GetTempFileName(name, "JIM", 0, name)) {
5322
- return JIM_BAD_FD;
5323
- }
5324
-
5325
- handle = CreateFile(name, GENERIC_READ | GENERIC_WRITE, 0, JimStdSecAttrs(),
5326
- CREATE_ALWAYS, FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE,
5327
- NULL);
5328
-
5329
- if (handle == INVALID_HANDLE_VALUE) {
5330
- goto error;
5331
- }
5332
-
5333
- if (contents != NULL) {
5334
-
5335
- FILE *fh = JimFdOpenForWrite(JimDupFd(handle));
5336
- if (fh == NULL) {
5337
- goto error;
5338
- }
5339
-
5340
- if (fwrite(contents, len, 1, fh) != 1) {
5341
- fclose(fh);
5342
- goto error;
5343
- }
5344
- fseek(fh, 0, SEEK_SET);
5345
- fclose(fh);
5346
- }
5347
- return handle;
5348
-
5349
- error:
5350
- Jim_SetResultErrno(interp, "failed to create temp file");
5351
- CloseHandle(handle);
5352
- DeleteFile(name);
5353
- return JIM_BAD_FD;
5354
-}
5355
-
53565380
static int
53575381
JimWinFindExecutable(const char *originalName, char fullPath[MAX_PATH])
53585382
{
53595383
int i;
53605384
static char extensions[][5] = {".exe", "", ".bat"};
@@ -5381,10 +5405,15 @@
53815405
53825406
static void JimRestoreEnv(char **env)
53835407
{
53845408
JimFreeEnv(env, Jim_GetEnviron());
53855409
}
5410
+
5411
+static char **JimOriginalEnviron(void)
5412
+{
5413
+ return NULL;
5414
+}
53865415
53875416
static Jim_Obj *
53885417
JimWinBuildCommandLine(Jim_Interp *interp, char **argv)
53895418
{
53905419
char *start, *special;
@@ -5455,18 +5484,19 @@
54555484
}
54565485
return strObj;
54575486
}
54585487
54595488
static pidtype
5460
-JimStartWinProcess(Jim_Interp *interp, char **argv, char *env, fdtype inputId, fdtype outputId, fdtype errorId)
5489
+JimStartWinProcess(Jim_Interp *interp, char **argv, char **env, int inputId, int outputId, int errorId)
54615490
{
54625491
STARTUPINFO startInfo;
54635492
PROCESS_INFORMATION procInfo;
5464
- HANDLE hProcess, h;
5493
+ HANDLE hProcess;
54655494
char execPath[MAX_PATH];
54665495
pidtype pid = JIM_BAD_PID;
54675496
Jim_Obj *cmdLineObj;
5497
+ char *winenv;
54685498
54695499
if (JimWinFindExecutable(argv[0], execPath) < 0) {
54705500
return JIM_BAD_PID;
54715501
}
54725502
argv[0] = execPath;
@@ -5480,47 +5510,51 @@
54805510
startInfo.dwFlags = STARTF_USESTDHANDLES;
54815511
startInfo.hStdInput = INVALID_HANDLE_VALUE;
54825512
startInfo.hStdOutput= INVALID_HANDLE_VALUE;
54835513
startInfo.hStdError = INVALID_HANDLE_VALUE;
54845514
5485
- if (inputId == JIM_BAD_FD) {
5486
- if (CreatePipe(&startInfo.hStdInput, &h, JimStdSecAttrs(), 0) != FALSE) {
5487
- CloseHandle(h);
5488
- }
5489
- } else {
5490
- DuplicateHandle(hProcess, inputId, hProcess, &startInfo.hStdInput,
5491
- 0, TRUE, DUPLICATE_SAME_ACCESS);
5492
- }
5493
- if (startInfo.hStdInput == JIM_BAD_FD) {
5494
- goto end;
5495
- }
5496
-
5497
- if (outputId == JIM_BAD_FD) {
5498
- startInfo.hStdOutput = CreateFile("NUL:", GENERIC_WRITE, 0,
5499
- JimStdSecAttrs(), OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
5500
- } else {
5501
- DuplicateHandle(hProcess, outputId, hProcess, &startInfo.hStdOutput,
5502
- 0, TRUE, DUPLICATE_SAME_ACCESS);
5503
- }
5504
- if (startInfo.hStdOutput == JIM_BAD_FD) {
5505
- goto end;
5506
- }
5507
-
5508
- if (errorId == JIM_BAD_FD) {
5509
-
5510
- startInfo.hStdError = CreateFile("NUL:", GENERIC_WRITE, 0,
5511
- JimStdSecAttrs(), OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
5512
- } else {
5513
- DuplicateHandle(hProcess, errorId, hProcess, &startInfo.hStdError,
5514
- 0, TRUE, DUPLICATE_SAME_ACCESS);
5515
- }
5516
- if (startInfo.hStdError == JIM_BAD_FD) {
5517
- goto end;
5518
- }
5519
-
5520
- if (!CreateProcess(NULL, (char *)Jim_String(cmdLineObj), NULL, NULL, TRUE,
5521
- 0, env, NULL, &startInfo, &procInfo)) {
5515
+ if (inputId == -1) {
5516
+ inputId = _fileno(stdin);
5517
+ }
5518
+ DuplicateHandle(hProcess, (HANDLE)_get_osfhandle(inputId), hProcess, &startInfo.hStdInput,
5519
+ 0, TRUE, DUPLICATE_SAME_ACCESS);
5520
+ if (startInfo.hStdInput == INVALID_HANDLE_VALUE) {
5521
+ goto end;
5522
+ }
5523
+
5524
+ if (outputId == -1) {
5525
+ outputId = _fileno(stdout);
5526
+ }
5527
+ DuplicateHandle(hProcess, (HANDLE)_get_osfhandle(outputId), hProcess, &startInfo.hStdOutput,
5528
+ 0, TRUE, DUPLICATE_SAME_ACCESS);
5529
+ if (startInfo.hStdOutput == INVALID_HANDLE_VALUE) {
5530
+ goto end;
5531
+ }
5532
+
5533
+
5534
+ if (errorId == -1) {
5535
+ errorId = _fileno(stderr);
5536
+ }
5537
+ DuplicateHandle(hProcess, (HANDLE)_get_osfhandle(errorId), hProcess, &startInfo.hStdError,
5538
+ 0, TRUE, DUPLICATE_SAME_ACCESS);
5539
+ if (startInfo.hStdError == INVALID_HANDLE_VALUE) {
5540
+ goto end;
5541
+ }
5542
+
5543
+ if (env == NULL) {
5544
+
5545
+ winenv = NULL;
5546
+ }
5547
+ else if (env[0] == NULL) {
5548
+ winenv = (char *)"\0";
5549
+ }
5550
+ else {
5551
+ winenv = env[0];
5552
+ }
5553
+
5554
+ if (!CreateProcess(NULL, (char *)Jim_String(cmdLineObj), NULL, NULL, TRUE,
5555
+ 0, winenv, NULL, &startInfo, &procInfo)) {
55225556
goto end;
55235557
}
55245558
55255559
55265560
WaitForInputIdle(procInfo.hProcess, 5000);
@@ -5528,49 +5562,27 @@
55285562
55295563
pid = procInfo.hProcess;
55305564
55315565
end:
55325566
Jim_FreeNewObj(interp, cmdLineObj);
5533
- if (startInfo.hStdInput != JIM_BAD_FD) {
5567
+ if (startInfo.hStdInput != INVALID_HANDLE_VALUE) {
55345568
CloseHandle(startInfo.hStdInput);
55355569
}
5536
- if (startInfo.hStdOutput != JIM_BAD_FD) {
5570
+ if (startInfo.hStdOutput != INVALID_HANDLE_VALUE) {
55375571
CloseHandle(startInfo.hStdOutput);
55385572
}
5539
- if (startInfo.hStdError != JIM_BAD_FD) {
5573
+ if (startInfo.hStdError != INVALID_HANDLE_VALUE) {
55405574
CloseHandle(startInfo.hStdError);
55415575
}
55425576
return pid;
55435577
}
5578
+
55445579
#else
55455580
5546
-static int JimOpenForWrite(const char *filename, int append)
5547
-{
5548
- return open(filename, O_WRONLY | O_CREAT | (append ? O_APPEND : O_TRUNC), 0666);
5549
-}
5550
-
5551
-static int JimRewindFd(int fd)
5552
-{
5553
- return lseek(fd, 0L, SEEK_SET);
5554
-}
5555
-
5556
-static int JimCreateTemp(Jim_Interp *interp, const char *contents, int len)
5557
-{
5558
- int fd = Jim_MakeTempFile(interp, NULL);
5559
-
5560
- if (fd != JIM_BAD_FD) {
5561
- unlink(Jim_String(Jim_GetResult(interp)));
5562
- if (contents) {
5563
- if (write(fd, contents, len) != len) {
5564
- Jim_SetResultErrno(interp, "couldn't write temp file");
5565
- close(fd);
5566
- return -1;
5567
- }
5568
- lseek(fd, 0L, SEEK_SET);
5569
- }
5570
- }
5571
- return fd;
5581
+static char **JimOriginalEnviron(void)
5582
+{
5583
+ return Jim_GetEnviron();
55725584
}
55735585
55745586
static char **JimSaveEnv(char **env)
55755587
{
55765588
char **saveenv = Jim_GetEnviron();
@@ -5585,13 +5597,21 @@
55855597
}
55865598
#endif
55875599
#endif
55885600
55895601
5602
+
5603
+#ifdef STRPTIME_NEEDS_XOPEN_SOURCE
55905604
#ifndef _XOPEN_SOURCE
55915605
#define _XOPEN_SOURCE 500
55925606
#endif
5607
+#endif
5608
+
5609
+
5610
+#ifndef _GNU_SOURCE
5611
+#define _GNU_SOURCE
5612
+#endif
55935613
55945614
#include <stdlib.h>
55955615
#include <string.h>
55965616
#include <stdio.h>
55975617
#include <time.h>
@@ -5598,65 +5618,117 @@
55985618
55995619
56005620
#ifdef HAVE_SYS_TIME_H
56015621
#include <sys/time.h>
56025622
#endif
5623
+
5624
+struct clock_options {
5625
+ int gmt;
5626
+ const char *format;
5627
+};
5628
+
5629
+static int parse_clock_options(Jim_Interp *interp, int argc, Jim_Obj *const *argv, struct clock_options *opts)
5630
+{
5631
+ static const char * const options[] = { "-gmt", "-format", NULL };
5632
+ enum { OPT_GMT, OPT_FORMAT, };
5633
+ int i;
5634
+
5635
+ for (i = 0; i < argc; i += 2) {
5636
+ int option;
5637
+ if (Jim_GetEnum(interp, argv[i], options, &option, NULL, JIM_ERRMSG | JIM_ENUM_ABBREV) != JIM_OK) {
5638
+ return JIM_ERR;
5639
+ }
5640
+ switch (option) {
5641
+ case OPT_GMT:
5642
+ if (Jim_GetBoolean(interp, argv[i + 1], &opts->gmt) != JIM_OK) {
5643
+ return JIM_ERR;
5644
+ }
5645
+ break;
5646
+ case OPT_FORMAT:
5647
+ opts->format = Jim_String(argv[i + 1]);
5648
+ break;
5649
+ }
5650
+ }
5651
+ return JIM_OK;
5652
+}
56035653
56045654
static int clock_cmd_format(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
56055655
{
5606
-
5656
+
56075657
char buf[100];
56085658
time_t t;
5609
- long seconds;
5659
+ jim_wide seconds;
5660
+ struct clock_options options = { 0, "%a %b %d %H:%M:%S %Z %Y" };
5661
+ struct tm *tm;
56105662
5611
- const char *format = "%a %b %d %H:%M:%S %Z %Y";
5612
-
5613
- if (argc == 2 || (argc == 3 && !Jim_CompareStringImmediate(interp, argv[1], "-format"))) {
5663
+ if (Jim_GetWide(interp, argv[0], &seconds) != JIM_OK) {
5664
+ return JIM_ERR;
5665
+ }
5666
+ if (argc % 2 == 0) {
56145667
return -1;
56155668
}
5616
-
5617
- if (argc == 3) {
5618
- format = Jim_String(argv[2]);
5669
+ if (parse_clock_options(interp, argc - 1, argv + 1, &options) == JIM_ERR) {
5670
+ return JIM_ERR;
56195671
}
56205672
5621
- if (Jim_GetLong(interp, argv[0], &seconds) != JIM_OK) {
5622
- return JIM_ERR;
5623
- }
56245673
t = seconds;
5674
+ tm = options.gmt ? gmtime(&t) : localtime(&t);
56255675
5626
- if (strftime(buf, sizeof(buf), format, localtime(&t)) == 0) {
5627
- Jim_SetResultString(interp, "format string too long", -1);
5676
+ if (tm == NULL || strftime(buf, sizeof(buf), options.format, tm) == 0) {
5677
+ Jim_SetResultString(interp, "format string too long or invalid time", -1);
56285678
return JIM_ERR;
56295679
}
56305680
56315681
Jim_SetResultString(interp, buf, -1);
56325682
56335683
return JIM_OK;
56345684
}
56355685
56365686
#ifdef HAVE_STRPTIME
5687
+static time_t jim_timegm(const struct tm *tm)
5688
+{
5689
+ int m = tm->tm_mon + 1;
5690
+ int y = 1900 + tm->tm_year - (m <= 2);
5691
+ int era = (y >= 0 ? y : y - 399) / 400;
5692
+ unsigned yoe = (unsigned)(y - era * 400);
5693
+ unsigned doy = (153 * (m + (m > 2 ? -3 : 9)) + 2) / 5 + tm->tm_mday - 1;
5694
+ unsigned doe = yoe * 365 + yoe / 4 - yoe / 100 + doy;
5695
+ long days = (era * 146097 + (int)doe - 719468);
5696
+ int secs = tm->tm_hour * 3600 + tm->tm_min * 60 + tm->tm_sec;
5697
+
5698
+ return days * 24 * 60 * 60 + secs;
5699
+}
5700
+
56375701
static int clock_cmd_scan(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
56385702
{
56395703
char *pt;
56405704
struct tm tm;
5641
- time_t now = time(0);
5705
+ time_t now = time(NULL);
56425706
5643
- if (!Jim_CompareStringImmediate(interp, argv[1], "-format")) {
5707
+ struct clock_options options = { 0, NULL };
5708
+
5709
+ if (argc % 2 == 0) {
5710
+ return -1;
5711
+ }
5712
+
5713
+ if (parse_clock_options(interp, argc - 1, argv + 1, &options) == JIM_ERR) {
5714
+ return JIM_ERR;
5715
+ }
5716
+ if (options.format == NULL) {
56445717
return -1;
56455718
}
56465719
5647
-
56485720
localtime_r(&now, &tm);
56495721
5650
- pt = strptime(Jim_String(argv[0]), Jim_String(argv[2]), &tm);
5722
+ pt = strptime(Jim_String(argv[0]), options.format, &tm);
56515723
if (pt == 0 || *pt != 0) {
56525724
Jim_SetResultString(interp, "Failed to parse time according to format", -1);
56535725
return JIM_ERR;
56545726
}
56555727
5656
-
5657
- Jim_SetResultInt(interp, mktime(&tm));
5728
+
5729
+ Jim_SetResultInt(interp, options.gmt ? jim_timegm(&tm) : mktime(&tm));
56585730
56595731
return JIM_OK;
56605732
}
56615733
#endif
56625734
@@ -5688,54 +5760,54 @@
56885760
56895761
return JIM_OK;
56905762
}
56915763
56925764
static const jim_subcmd_type clock_command_table[] = {
5693
- { "seconds",
5694
- NULL,
5695
- clock_cmd_seconds,
5696
- 0,
5697
- 0,
5698
-
5699
- },
57005765
{ "clicks",
57015766
NULL,
57025767
clock_cmd_micros,
57035768
0,
57045769
0,
5705
-
5770
+
5771
+ },
5772
+ { "format",
5773
+ "seconds ?-format string? ?-gmt boolean?",
5774
+ clock_cmd_format,
5775
+ 1,
5776
+ 5,
5777
+
57065778
},
57075779
{ "microseconds",
57085780
NULL,
57095781
clock_cmd_micros,
57105782
0,
57115783
0,
5712
-
5784
+
57135785
},
57145786
{ "milliseconds",
57155787
NULL,
57165788
clock_cmd_millis,
57175789
0,
57185790
0,
5719
-
5720
- },
5721
- { "format",
5722
- "seconds ?-format format?",
5723
- clock_cmd_format,
5724
- 1,
5725
- 3,
5726
-
5791
+
57275792
},
57285793
#ifdef HAVE_STRPTIME
57295794
{ "scan",
5730
- "str -format format",
5795
+ "str -format format ?-gmt boolean?",
57315796
clock_cmd_scan,
57325797
3,
5733
- 3,
5734
-
5798
+ 5,
5799
+
57355800
},
57365801
#endif
5802
+ { "seconds",
5803
+ NULL,
5804
+ clock_cmd_seconds,
5805
+ 0,
5806
+ 0,
5807
+
5808
+ },
57375809
{ NULL }
57385810
};
57395811
57405812
int Jim_clockInit(Jim_Interp *interp)
57415813
{
@@ -5753,12 +5825,13 @@
57535825
#include <errno.h>
57545826
57555827
57565828
static int array_cmd_exists(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
57575829
{
5758
-
5759
- Jim_SetResultInt(interp, Jim_GetVariable(interp, argv[0], 0) != 0);
5830
+
5831
+ Jim_Obj *dictObj = Jim_GetVariable(interp, argv[0], JIM_UNSHARED);
5832
+ Jim_SetResultInt(interp, dictObj && Jim_DictSize(interp, dictObj) != -1);
57605833
return JIM_OK;
57615834
}
57625835
57635836
static int array_cmd_get(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
57645837
{
@@ -5769,21 +5842,20 @@
57695842
return JIM_OK;
57705843
}
57715844
57725845
patternObj = (argc == 1) ? NULL : argv[1];
57735846
5774
-
5847
+
57755848
if (patternObj == NULL || Jim_CompareStringImmediate(interp, patternObj, "*")) {
57765849
if (Jim_IsList(objPtr) && Jim_ListLength(interp, objPtr) % 2 == 0) {
5777
-
5850
+
57785851
Jim_SetResult(interp, objPtr);
57795852
return JIM_OK;
57805853
}
57815854
}
57825855
5783
-
5784
- return Jim_DictValues(interp, objPtr, patternObj);
5856
+ return Jim_DictMatchTypes(interp, objPtr, patternObj, JIM_DICTMATCH_KEYS, JIM_DICTMATCH_KEYS | JIM_DICTMATCH_VALUES);
57855857
}
57865858
57875859
static int array_cmd_names(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
57885860
{
57895861
Jim_Obj *objPtr = Jim_GetVariable(interp, argv[0], JIM_NONE);
@@ -5790,11 +5862,11 @@
57905862
57915863
if (!objPtr) {
57925864
return JIM_OK;
57935865
}
57945866
5795
- return Jim_DictKeys(interp, objPtr, argc == 1 ? NULL : argv[1]);
5867
+ return Jim_DictMatchTypes(interp, objPtr, argc == 1 ? NULL : argv[1], JIM_DICTMATCH_KEYS, JIM_DICTMATCH_KEYS);
57965868
}
57975869
57985870
static int array_cmd_unset(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
57995871
{
58005872
int i;
@@ -5802,27 +5874,29 @@
58025874
Jim_Obj *resultObj;
58035875
Jim_Obj *objPtr;
58045876
Jim_Obj **dictValuesObj;
58055877
58065878
if (argc == 1 || Jim_CompareStringImmediate(interp, argv[1], "*")) {
5807
-
5879
+
58085880
Jim_UnsetVariable(interp, argv[0], JIM_NONE);
58095881
return JIM_OK;
58105882
}
58115883
58125884
objPtr = Jim_GetVariable(interp, argv[0], JIM_NONE);
58135885
58145886
if (objPtr == NULL) {
5815
-
5887
+
58165888
return JIM_OK;
58175889
}
58185890
58195891
if (Jim_DictPairs(interp, objPtr, &dictValuesObj, &len) != JIM_OK) {
5820
- return JIM_ERR;
5892
+
5893
+ Jim_SetResultString(interp, "", -1);
5894
+ return JIM_OK;
58215895
}
58225896
5823
-
5897
+
58245898
resultObj = Jim_NewDictObj(interp, NULL, 0);
58255899
58265900
for (i = 0; i < len; i += 2) {
58275901
if (!Jim_StringMatchObj(interp, argv[1], dictValuesObj[i], 0)) {
58285902
Jim_DictAddElement(interp, resultObj, dictValuesObj[i], dictValuesObj[i + 1]);
@@ -5837,16 +5911,18 @@
58375911
static int array_cmd_size(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
58385912
{
58395913
Jim_Obj *objPtr;
58405914
int len = 0;
58415915
5842
-
5916
+
58435917
objPtr = Jim_GetVariable(interp, argv[0], JIM_NONE);
58445918
if (objPtr) {
58455919
len = Jim_DictSize(interp, objPtr);
58465920
if (len < 0) {
5847
- return JIM_ERR;
5921
+
5922
+ Jim_SetResultInt(interp, 0);
5923
+ return JIM_OK;
58485924
}
58495925
}
58505926
58515927
Jim_SetResultInt(interp, len);
58525928
@@ -5876,11 +5952,11 @@
58765952
return JIM_ERR;
58775953
}
58785954
58795955
dictObj = Jim_GetVariable(interp, argv[0], JIM_UNSHARED);
58805956
if (!dictObj) {
5881
-
5957
+
58825958
return Jim_SetVariable(interp, argv[0], listObj);
58835959
}
58845960
else if (Jim_DictSize(interp, dictObj) < 0) {
58855961
return JIM_ERR;
58865962
}
@@ -5905,53 +5981,53 @@
59055981
{ "exists",
59065982
"arrayName",
59075983
array_cmd_exists,
59085984
1,
59095985
1,
5910
-
5986
+
59115987
},
59125988
{ "get",
59135989
"arrayName ?pattern?",
59145990
array_cmd_get,
59155991
1,
59165992
2,
5917
-
5993
+
59185994
},
59195995
{ "names",
59205996
"arrayName ?pattern?",
59215997
array_cmd_names,
59225998
1,
59235999
2,
5924
-
6000
+
59256001
},
59266002
{ "set",
59276003
"arrayName list",
59286004
array_cmd_set,
59296005
2,
59306006
2,
5931
-
6007
+
59326008
},
59336009
{ "size",
59346010
"arrayName",
59356011
array_cmd_size,
59366012
1,
59376013
1,
5938
-
6014
+
59396015
},
59406016
{ "stat",
59416017
"arrayName",
59426018
array_cmd_stat,
59436019
1,
59446020
1,
5945
-
6021
+
59466022
},
59476023
{ "unset",
59486024
"arrayName ?pattern?",
59496025
array_cmd_unset,
59506026
1,
59516027
2,
5952
-
6028
+
59536029
},
59546030
{ NULL
59556031
}
59566032
};
59576033
@@ -5987,11 +6063,14 @@
59876063
Jim_arrayInit(interp);
59886064
Jim_stdlibInit(interp);
59896065
Jim_tclcompatInit(interp);
59906066
return JIM_OK;
59916067
}
5992
-#define JIM_OPTIMIZATION
6068
+#define JIM_OPTIMIZATION
6069
+#ifndef _GNU_SOURCE
6070
+#define _GNU_SOURCE
6071
+#endif
59936072
59946073
#include <stdio.h>
59956074
#include <stdlib.h>
59966075
59976076
#include <string.h>
@@ -6056,10 +6135,16 @@
60566135
#define JimPanic(X) JimPanicDump X
60576136
#else
60586137
#define JimPanic(X)
60596138
#endif
60606139
6140
+#ifdef JIM_OPTIMIZATION
6141
+#define JIM_IF_OPTIM(X) X
6142
+#else
6143
+#define JIM_IF_OPTIM(X)
6144
+#endif
6145
+
60616146
60626147
static char JimEmptyStringRep[] = "";
60636148
60646149
static void JimFreeCallFrame(Jim_Interp *interp, Jim_CallFrame *cf, int action);
60656150
static int ListSetIndex(Jim_Interp *interp, Jim_Obj *listPtr, int listindex, Jim_Obj *newObjPtr,
@@ -6112,34 +6197,34 @@
61126197
if (*pattern == '^') {
61136198
not++;
61146199
pattern++;
61156200
}
61166201
6117
-
6202
+
61186203
if (*pattern == ']') {
61196204
goto first;
61206205
}
61216206
}
61226207
61236208
while (*pattern && *pattern != ']') {
6124
-
6209
+
61256210
if (pattern[0] == '\\') {
61266211
first:
61276212
pattern += utf8_tounicode_case(pattern, &pchar, nocase);
61286213
}
61296214
else {
6130
-
6215
+
61316216
int start;
61326217
int end;
61336218
61346219
pattern += utf8_tounicode_case(pattern, &start, nocase);
61356220
if (pattern[0] == '-' && pattern[1]) {
6136
-
6137
- pattern += utf8_tounicode(pattern, &pchar);
6221
+
6222
+ pattern++;
61386223
pattern += utf8_tounicode_case(pattern, &end, nocase);
61396224
6140
-
6225
+
61416226
if ((c >= start && c <= end) || (c >= end && c <= start)) {
61426227
match = 1;
61436228
}
61446229
continue;
61456230
}
@@ -6169,19 +6254,19 @@
61696254
while (pattern[1] == '*') {
61706255
pattern++;
61716256
}
61726257
pattern++;
61736258
if (!pattern[0]) {
6174
- return 1;
6259
+ return 1;
61756260
}
61766261
while (*string) {
6177
-
6262
+
61786263
if (JimGlobMatch(pattern, string, nocase))
6179
- return 1;
6264
+ return 1;
61806265
string += utf8_tounicode(string, &c);
61816266
}
6182
- return 0;
6267
+ return 0;
61836268
61846269
case '?':
61856270
string += utf8_tounicode(string, &c);
61866271
break;
61876272
@@ -6190,20 +6275,20 @@
61906275
pattern = JimCharsetMatch(pattern + 1, c, nocase ? JIM_NOCASE : 0);
61916276
if (!pattern) {
61926277
return 0;
61936278
}
61946279
if (!*pattern) {
6195
-
6280
+
61966281
continue;
61976282
}
61986283
break;
61996284
}
62006285
case '\\':
62016286
if (pattern[1]) {
62026287
pattern++;
62036288
}
6204
-
6289
+
62056290
default:
62066291
string += utf8_tounicode_case(string, &c, nocase);
62076292
utf8_tounicode_case(pattern, &pchar, nocase);
62086293
if (pchar != c) {
62096294
return 0;
@@ -6249,11 +6334,11 @@
62496334
maxchars--;
62506335
}
62516336
if (!maxchars) {
62526337
return 0;
62536338
}
6254
-
6339
+
62556340
if (*s1) {
62566341
return 1;
62576342
}
62586343
if (*s2) {
62596344
return -1;
@@ -6290,11 +6375,11 @@
62906375
const char *p;
62916376
62926377
if (!l1 || !l2 || l1 > l2)
62936378
return -1;
62946379
6295
-
6380
+
62966381
for (p = s2 + l2 - 1; p != s2 - 1; p--) {
62976382
if (*p == *s1 && memcmp(s1, p, l1) == 0) {
62986383
return p - s2;
62996384
}
63006385
}
@@ -6349,28 +6434,28 @@
63496434
}
63506435
*sign = 1;
63516436
}
63526437
63536438
if (str[i] != '0') {
6354
-
6439
+
63556440
return 0;
63566441
}
63576442
6358
-
6443
+
63596444
switch (str[i + 1]) {
63606445
case 'x': case 'X': *base = 16; break;
63616446
case 'o': case 'O': *base = 8; break;
63626447
case 'b': case 'B': *base = 2; break;
63636448
default: return 0;
63646449
}
63656450
i += 2;
6366
-
6451
+
63676452
if (str[i] != '-' && str[i] != '+' && !isspace(UCHAR(str[i]))) {
6368
-
6453
+
63696454
return i;
63706455
}
6371
-
6456
+
63726457
*base = 10;
63736458
return 0;
63746459
}
63756460
63766461
static long jim_strtol(const char *str, char **endptr)
@@ -6384,11 +6469,11 @@
63846469
if (endptr == NULL || *endptr != str + i) {
63856470
return value * sign;
63866471
}
63876472
}
63886473
6389
-
6474
+
63906475
return strtol(str, endptr, 10);
63916476
}
63926477
63936478
63946479
static jim_wide jim_strtoull(const char *str, char **endptr)
@@ -6403,11 +6488,11 @@
64036488
if (endptr == NULL || *endptr != str + i) {
64046489
return value * sign;
64056490
}
64066491
}
64076492
6408
-
6493
+
64096494
return strtoull(str, endptr, 10);
64106495
#else
64116496
return (unsigned long)jim_strtol(str, endptr);
64126497
#endif
64136498
}
@@ -6428,26 +6513,40 @@
64286513
64296514
int Jim_StringToDouble(const char *str, double *doublePtr)
64306515
{
64316516
char *endptr;
64326517
6433
-
6518
+
64346519
errno = 0;
64356520
64366521
*doublePtr = strtod(str, &endptr);
64376522
64386523
return JimCheckConversion(str, endptr);
64396524
}
64406525
64416526
static jim_wide JimPowWide(jim_wide b, jim_wide e)
64426527
{
6443
- jim_wide i, res = 1;
6528
+ jim_wide res = 1;
64446529
6445
- if ((b == 0 && e != 0) || (e < 0))
6446
- return 0;
6447
- for (i = 0; i < e; i++) {
6448
- res *= b;
6530
+
6531
+ if (b == 1) {
6532
+
6533
+ return 1;
6534
+ }
6535
+ if (e < 0) {
6536
+ if (b != -1) {
6537
+ return 0;
6538
+ }
6539
+ e = -e;
6540
+ }
6541
+ while (e)
6542
+ {
6543
+ if (e & 1) {
6544
+ res *= b;
6545
+ }
6546
+ e >>= 1;
6547
+ b *= b;
64496548
}
64506549
return res;
64516550
}
64526551
64536552
#ifdef JIM_DEBUG_PANIC
@@ -6509,11 +6608,11 @@
65096608
char *Jim_StrDupLen(const char *s, int l)
65106609
{
65116610
char *copy = Jim_Alloc(l + 1);
65126611
65136612
memcpy(copy, s, l + 1);
6514
- copy[l] = 0;
6613
+ copy[l] = 0;
65156614
return copy;
65166615
}
65176616
65186617
65196618
@@ -6598,52 +6697,52 @@
65986697
}
65996698
66006699
66016700
void Jim_ExpandHashTable(Jim_HashTable *ht, unsigned int size)
66026701
{
6603
- Jim_HashTable n;
6702
+ Jim_HashTable n;
66046703
unsigned int realsize = JimHashTableNextPower(size), i;
66056704
66066705
if (size <= ht->used)
66076706
return;
66086707
66096708
Jim_InitHashTable(&n, ht->type, ht->privdata);
66106709
n.size = realsize;
66116710
n.sizemask = realsize - 1;
66126711
n.table = Jim_Alloc(realsize * sizeof(Jim_HashEntry *));
6613
-
6712
+
66146713
n.uniq = ht->uniq;
66156714
6616
-
6715
+
66176716
memset(n.table, 0, realsize * sizeof(Jim_HashEntry *));
66186717
66196718
n.used = ht->used;
66206719
for (i = 0; ht->used > 0; i++) {
66216720
Jim_HashEntry *he, *nextHe;
66226721
66236722
if (ht->table[i] == NULL)
66246723
continue;
66256724
6626
-
6725
+
66276726
he = ht->table[i];
66286727
while (he) {
66296728
unsigned int h;
66306729
66316730
nextHe = he->next;
6632
-
6731
+
66336732
h = Jim_HashKey(ht, he->key) & n.sizemask;
66346733
he->next = n.table[h];
66356734
n.table[h] = he;
66366735
ht->used--;
6637
-
6736
+
66386737
he = nextHe;
66396738
}
66406739
}
66416740
assert(ht->used == 0);
66426741
Jim_Free(ht->table);
66436742
6644
-
6743
+
66456744
*ht = n;
66466745
}
66476746
66486747
66496748
int Jim_AddHashEntry(Jim_HashTable *ht, const void *key, void *val)
@@ -6652,11 +6751,11 @@
66526751
66536752
entry = JimInsertHashEntry(ht, key, 0);
66546753
if (entry == NULL)
66556754
return JIM_ERR;
66566755
6657
-
6756
+
66586757
Jim_SetHashKey(ht, entry, key);
66596758
Jim_SetHashVal(ht, entry, val);
66606759
return JIM_OK;
66616760
}
66626761
@@ -6678,11 +6777,11 @@
66786777
Jim_SetHashVal(ht, entry, val);
66796778
}
66806779
existed = 1;
66816780
}
66826781
else {
6683
-
6782
+
66846783
Jim_SetHashKey(ht, entry, key);
66856784
Jim_SetHashVal(ht, entry, val);
66866785
existed = 0;
66876786
}
66886787
@@ -6701,11 +6800,11 @@
67016800
he = ht->table[h];
67026801
67036802
prevHe = NULL;
67046803
while (he) {
67056804
if (Jim_CompareHashKeys(ht, key, he->key)) {
6706
-
6805
+
67076806
if (prevHe)
67086807
prevHe->next = he->next;
67096808
else
67106809
ht->table[h] = he->next;
67116810
Jim_FreeEntryKey(ht, he);
@@ -6715,19 +6814,19 @@
67156814
return JIM_OK;
67166815
}
67176816
prevHe = he;
67186817
he = he->next;
67196818
}
6720
- return JIM_ERR;
6819
+ return JIM_ERR;
67216820
}
67226821
67236822
67246823
int Jim_FreeHashTable(Jim_HashTable *ht)
67256824
{
67266825
unsigned int i;
67276826
6728
-
6827
+
67296828
for (i = 0; ht->used > 0; i++) {
67306829
Jim_HashEntry *he, *nextHe;
67316830
67326831
if ((he = ht->table[i]) == NULL)
67336832
continue;
@@ -6738,15 +6837,15 @@
67386837
Jim_Free(he);
67396838
ht->used--;
67406839
he = nextHe;
67416840
}
67426841
}
6743
-
6842
+
67446843
Jim_Free(ht->table);
6745
-
6844
+
67466845
JimResetHashTable(ht);
6747
- return JIM_OK;
6846
+ return JIM_OK;
67486847
}
67496848
67506849
Jim_HashEntry *Jim_FindHashEntry(Jim_HashTable *ht, const void *key)
67516850
{
67526851
Jim_HashEntry *he;
@@ -6819,24 +6918,24 @@
68196918
static Jim_HashEntry *JimInsertHashEntry(Jim_HashTable *ht, const void *key, int replace)
68206919
{
68216920
unsigned int h;
68226921
Jim_HashEntry *he;
68236922
6824
-
6923
+
68256924
JimExpandHashTableIfNeeded(ht);
68266925
6827
-
6926
+
68286927
h = Jim_HashKey(ht, key) & ht->sizemask;
6829
-
6928
+
68306929
he = ht->table[h];
68316930
while (he) {
68326931
if (Jim_CompareHashKeys(ht, key, he->key))
68336932
return replace ? he : NULL;
68346933
he = he->next;
68356934
}
68366935
6837
-
6936
+
68386937
he = Jim_Alloc(sizeof(*he));
68396938
he->next = ht->table[h];
68406939
ht->table[h] = he;
68416940
ht->used++;
68426941
he->key = NULL;
@@ -6865,16 +6964,16 @@
68656964
{
68666965
Jim_Free(key);
68676966
}
68686967
68696968
static const Jim_HashTableType JimPackageHashTableType = {
6870
- JimStringCopyHTHashFunction,
6871
- JimStringCopyHTDup,
6872
- NULL,
6873
- JimStringCopyHTKeyCompare,
6874
- JimStringCopyHTKeyDestructor,
6875
- NULL
6969
+ JimStringCopyHTHashFunction,
6970
+ JimStringCopyHTDup,
6971
+ NULL,
6972
+ JimStringCopyHTKeyCompare,
6973
+ JimStringCopyHTKeyDestructor,
6974
+ NULL
68766975
};
68776976
68786977
typedef struct AssocDataValue
68796978
{
68806979
Jim_InterpDeleteProc *delProc;
@@ -6889,16 +6988,16 @@
68896988
assocPtr->delProc((Jim_Interp *)privdata, assocPtr->data);
68906989
Jim_Free(data);
68916990
}
68926991
68936992
static const Jim_HashTableType JimAssocDataHashTableType = {
6894
- JimStringCopyHTHashFunction,
6895
- JimStringCopyHTDup,
6896
- NULL,
6897
- JimStringCopyHTKeyCompare,
6898
- JimStringCopyHTKeyDestructor,
6899
- JimAssocDataHashTableValueDestructor
6993
+ JimStringCopyHTHashFunction,
6994
+ JimStringCopyHTDup,
6995
+ NULL,
6996
+ JimStringCopyHTKeyCompare,
6997
+ JimStringCopyHTKeyDestructor,
6998
+ JimAssocDataHashTableValueDestructor
69006999
};
69017000
69027001
void Jim_InitStack(Jim_Stack *stack)
69037002
{
69047003
stack->len = 0;
@@ -6951,56 +7050,61 @@
69517050
freeFunc(stack->vector[i]);
69527051
}
69537052
69547053
69557054
6956
-#define JIM_TT_NONE 0
6957
-#define JIM_TT_STR 1
6958
-#define JIM_TT_ESC 2
6959
-#define JIM_TT_VAR 3
6960
-#define JIM_TT_DICTSUGAR 4
6961
-#define JIM_TT_CMD 5
6962
-
6963
-#define JIM_TT_SEP 6
6964
-#define JIM_TT_EOL 7
6965
-#define JIM_TT_EOF 8
6966
-
6967
-#define JIM_TT_LINE 9
6968
-#define JIM_TT_WORD 10
7055
+#define JIM_TT_NONE 0
7056
+#define JIM_TT_STR 1
7057
+#define JIM_TT_ESC 2
7058
+#define JIM_TT_VAR 3
7059
+#define JIM_TT_DICTSUGAR 4
7060
+#define JIM_TT_CMD 5
7061
+
7062
+#define JIM_TT_SEP 6
7063
+#define JIM_TT_EOL 7
7064
+#define JIM_TT_EOF 8
7065
+
7066
+#define JIM_TT_LINE 9
7067
+#define JIM_TT_WORD 10
69697068
69707069
69717070
#define JIM_TT_SUBEXPR_START 11
69727071
#define JIM_TT_SUBEXPR_END 12
69737072
#define JIM_TT_SUBEXPR_COMMA 13
69747073
#define JIM_TT_EXPR_INT 14
69757074
#define JIM_TT_EXPR_DOUBLE 15
7075
+#define JIM_TT_EXPR_BOOLEAN 16
69767076
6977
-#define JIM_TT_EXPRSUGAR 16
7077
+#define JIM_TT_EXPRSUGAR 17
69787078
69797079
69807080
#define JIM_TT_EXPR_OP 20
69817081
69827082
#define TOKEN_IS_SEP(type) (type >= JIM_TT_SEP && type <= JIM_TT_EOF)
69837083
7084
+#define TOKEN_IS_EXPR_START(type) (type == JIM_TT_NONE || type == JIM_TT_SUBEXPR_START || type == JIM_TT_SUBEXPR_COMMA)
7085
+
7086
+#define TOKEN_IS_EXPR_OP(type) (type >= JIM_TT_EXPR_OP)
7087
+
69847088
struct JimParseMissing {
6985
- int ch;
6986
- int line;
7089
+ int ch;
7090
+ int line;
69877091
};
69887092
69897093
struct JimParserCtx
69907094
{
6991
- const char *p;
6992
- int len;
6993
- int linenr;
7095
+ const char *p;
7096
+ int len;
7097
+ int linenr;
69947098
const char *tstart;
6995
- const char *tend;
6996
- int tline;
6997
- int tt;
6998
- int eof;
6999
- int inquote;
7000
- int comment;
7001
- struct JimParseMissing missing;
7099
+ const char *tend;
7100
+ int tline;
7101
+ int tt;
7102
+ int eof;
7103
+ int inquote;
7104
+ int comment;
7105
+ struct JimParseMissing missing;
70027106
};
70037107
70047108
static int JimParseScript(struct JimParserCtx *pc);
70057109
static int JimParseSep(struct JimParserCtx *pc);
70067110
static int JimParseEol(struct JimParserCtx *pc);
@@ -7030,11 +7134,11 @@
70307134
pc->missing.line = linenr;
70317135
}
70327136
70337137
static int JimParseScript(struct JimParserCtx *pc)
70347138
{
7035
- while (1) {
7139
+ while (1) {
70367140
if (!pc->len) {
70377141
pc->tstart = pc->p;
70387142
pc->tend = pc->p - 1;
70397143
pc->tline = pc->linenr;
70407144
pc->tt = JIM_TT_EOL;
@@ -7066,11 +7170,11 @@
70667170
pc->comment = 0;
70677171
return JimParseCmd(pc);
70687172
case '$':
70697173
pc->comment = 0;
70707174
if (JimParseVar(pc) == JIM_ERR) {
7071
-
7175
+
70727176
pc->tstart = pc->tend = pc->p++;
70737177
pc->len--;
70747178
pc->tt = JIM_TT_ESC;
70757179
}
70767180
return JIM_OK;
@@ -7127,11 +7231,11 @@
71277231
71287232
static void JimParseSubBrace(struct JimParserCtx *pc)
71297233
{
71307234
int level = 1;
71317235
7132
-
7236
+
71337237
pc->p++;
71347238
pc->len--;
71357239
while (pc->len) {
71367240
switch (*pc->p) {
71377241
case '\\':
@@ -7171,11 +7275,11 @@
71717275
static int JimParseSubQuote(struct JimParserCtx *pc)
71727276
{
71737277
int tt = JIM_TT_STR;
71747278
int line = pc->tline;
71757279
7176
-
7280
+
71777281
pc->p++;
71787282
pc->len--;
71797283
while (pc->len) {
71807284
switch (*pc->p) {
71817285
case '\\':
@@ -7220,11 +7324,11 @@
72207324
{
72217325
int level = 1;
72227326
int startofword = 1;
72237327
int line = pc->tline;
72247328
7225
-
7329
+
72267330
pc->p++;
72277331
pc->len--;
72287332
while (pc->len) {
72297333
switch (*pc->p) {
72307334
case '\\':
@@ -7300,17 +7404,17 @@
73007404
return JIM_OK;
73017405
}
73027406
73037407
static int JimParseVar(struct JimParserCtx *pc)
73047408
{
7305
-
7409
+
73067410
pc->p++;
73077411
pc->len--;
73087412
73097413
#ifdef EXPRSUGAR_BRACKET
73107414
if (*pc->p == '[') {
7311
-
7415
+
73127416
JimParseCmd(pc);
73137417
pc->tt = JIM_TT_EXPRSUGAR;
73147418
return JIM_OK;
73157419
}
73167420
#endif
@@ -7336,11 +7440,11 @@
73367440
pc->len--;
73377441
}
73387442
}
73397443
else {
73407444
while (1) {
7341
-
7445
+
73427446
if (pc->p[0] == ':' && pc->p[1] == ':') {
73437447
while (*pc->p == ':') {
73447448
pc->p++;
73457449
pc->len--;
73467450
}
@@ -7351,11 +7455,11 @@
73517455
pc->len--;
73527456
continue;
73537457
}
73547458
break;
73557459
}
7356
-
7460
+
73577461
if (*pc->p == '(') {
73587462
int count = 1;
73597463
const char *paren = NULL;
73607464
73617465
pc->tt = JIM_TT_DICTSUGAR;
@@ -7378,11 +7482,11 @@
73787482
if (count == 0) {
73797483
pc->p++;
73807484
pc->len--;
73817485
}
73827486
else if (paren) {
7383
-
7487
+
73847488
paren++;
73857489
pc->len += (pc->p - paren);
73867490
pc->p = paren;
73877491
}
73887492
#ifndef EXPRSUGAR_BRACKET
@@ -7403,19 +7507,19 @@
74037507
74047508
static int JimParseStr(struct JimParserCtx *pc)
74057509
{
74067510
if (pc->tt == JIM_TT_SEP || pc->tt == JIM_TT_EOL ||
74077511
pc->tt == JIM_TT_NONE || pc->tt == JIM_TT_STR) {
7408
-
7512
+
74097513
if (*pc->p == '{') {
74107514
return JimParseBrace(pc);
74117515
}
74127516
if (*pc->p == '"') {
74137517
pc->inquote = 1;
74147518
pc->p++;
74157519
pc->len--;
7416
-
7520
+
74177521
pc->missing.line = pc->tline;
74187522
}
74197523
}
74207524
pc->tstart = pc->p;
74217525
pc->tline = pc->linenr;
@@ -7441,25 +7545,25 @@
74417545
}
74427546
pc->p++;
74437547
pc->len--;
74447548
}
74457549
else if (pc->len == 1) {
7446
-
7550
+
74477551
pc->missing.ch = '\\';
74487552
}
74497553
break;
74507554
case '(':
7451
-
7555
+
74527556
if (pc->len > 1 && pc->p[1] != '$') {
74537557
break;
74547558
}
7455
-
7559
+
74567560
case ')':
7457
-
7561
+
74587562
if (*pc->p == '(' || pc->tt == JIM_TT_VAR) {
74597563
if (pc->p == pc->tstart) {
7460
-
7564
+
74617565
pc->p++;
74627566
pc->len--;
74637567
}
74647568
pc->tend = pc->p - 1;
74657569
pc->tt = JIM_TT_ESC;
@@ -7499,11 +7603,11 @@
74997603
break;
75007604
}
75017605
pc->p++;
75027606
pc->len--;
75037607
}
7504
- return JIM_OK;
7608
+ return JIM_OK;
75057609
}
75067610
75077611
static int JimParseComment(struct JimParserCtx *pc)
75087612
{
75097613
while (*pc->p) {
@@ -7610,34 +7714,34 @@
76107714
if (c == -1) {
76117715
break;
76127716
}
76137717
val = (val << 4) | c;
76147718
}
7615
-
7719
+
76167720
if (s[i] == '{') {
76177721
if (k == 0 || val > 0x1fffff || s[i + k + 1] != '}') {
7618
-
7722
+
76197723
i--;
76207724
k = 0;
76217725
}
76227726
else {
7623
-
7727
+
76247728
k++;
76257729
}
76267730
}
76277731
if (k) {
7628
-
7732
+
76297733
if (s[i] == 'x') {
76307734
*p++ = val;
76317735
}
76327736
else {
76337737
p += utf8_fromunicode(p, val);
76347738
}
76357739
i += k;
76367740
break;
76377741
}
7638
-
7742
+
76397743
*p++ = s[i];
76407744
}
76417745
break;
76427746
case 'v':
76437747
*p++ = 0xb;
@@ -7646,11 +7750,11 @@
76467750
case '\0':
76477751
*p++ = '\\';
76487752
i++;
76497753
break;
76507754
case '\n':
7651
-
7755
+
76527756
*p++ = ' ';
76537757
do {
76547758
i++;
76557759
} while (s[i + 1] == ' ' || s[i + 1] == '\t');
76567760
break;
@@ -7660,11 +7764,11 @@
76607764
case '3':
76617765
case '4':
76627766
case '5':
76637767
case '6':
76647768
case '7':
7665
-
7769
+
76667770
{
76677771
int val = 0;
76687772
int c = odigitval(s[i + 1]);
76697773
76707774
val = c;
@@ -7708,27 +7812,23 @@
77087812
char *token;
77097813
int len;
77107814
77117815
start = pc->tstart;
77127816
end = pc->tend;
7713
- if (start > end) {
7817
+ len = (end - start) + 1;
7818
+ if (len < 0) {
77147819
len = 0;
7715
- token = Jim_Alloc(1);
7716
- token[0] = '\0';
7717
- }
7718
- else {
7719
- len = (end - start) + 1;
7720
- token = Jim_Alloc(len + 1);
7721
- if (pc->tt != JIM_TT_ESC) {
7722
-
7723
- memcpy(token, start, len);
7724
- token[len] = '\0';
7725
- }
7726
- else {
7727
-
7728
- len = JimEscape(token, start, len);
7729
- }
7820
+ }
7821
+ token = Jim_Alloc(len + 1);
7822
+ if (pc->tt != JIM_TT_ESC) {
7823
+
7824
+ memcpy(token, start, len);
7825
+ token[len] = '\0';
7826
+ }
7827
+ else {
7828
+
7829
+ len = JimEscape(token, start, len);
77307830
}
77317831
77327832
return Jim_NewStringObjNoAlloc(interp, token, len);
77337833
}
77347834
@@ -7790,11 +7890,11 @@
77907890
while (pc->len) {
77917891
switch (*pc->p) {
77927892
case '\\':
77937893
pc->tt = JIM_TT_ESC;
77947894
if (--pc->len == 0) {
7795
-
7895
+
77967896
pc->tend = pc->p;
77977897
return JIM_OK;
77987898
}
77997899
pc->p++;
78007900
break;
@@ -7826,11 +7926,11 @@
78267926
pc->tend = pc->p - 1;
78277927
return JIM_OK;
78287928
}
78297929
if (*pc->p == '\\') {
78307930
if (--pc->len == 0) {
7831
-
7931
+
78327932
pc->tend = pc->p;
78337933
return JIM_OK;
78347934
}
78357935
pc->tt = JIM_TT_ESC;
78367936
pc->p++;
@@ -7846,24 +7946,24 @@
78467946
78477947
Jim_Obj *Jim_NewObj(Jim_Interp *interp)
78487948
{
78497949
Jim_Obj *objPtr;
78507950
7851
-
7951
+
78527952
if (interp->freeList != NULL) {
7853
-
7953
+
78547954
objPtr = interp->freeList;
78557955
interp->freeList = objPtr->nextObjPtr;
78567956
}
78577957
else {
7858
-
7958
+
78597959
objPtr = Jim_Alloc(sizeof(*objPtr));
78607960
}
78617961
78627962
objPtr->refCount = 0;
78637963
7864
-
7964
+
78657965
objPtr->prevObjPtr = NULL;
78667966
objPtr->nextObjPtr = interp->liveList;
78677967
if (interp->liveList)
78687968
interp->liveList->prevObjPtr = objPtr;
78697969
interp->liveList = objPtr;
@@ -7871,32 +7971,32 @@
78717971
return objPtr;
78727972
}
78737973
78747974
void Jim_FreeObj(Jim_Interp *interp, Jim_Obj *objPtr)
78757975
{
7876
-
7976
+
78777977
JimPanic((objPtr->refCount != 0, "!!!Object %p freed with bad refcount %d, type=%s", objPtr,
78787978
objPtr->refCount, objPtr->typePtr ? objPtr->typePtr->name : "<none>"));
78797979
7880
-
7980
+
78817981
Jim_FreeIntRep(interp, objPtr);
7882
-
7982
+
78837983
if (objPtr->bytes != NULL) {
78847984
if (objPtr->bytes != JimEmptyStringRep)
78857985
Jim_Free(objPtr->bytes);
78867986
}
7887
-
7987
+
78887988
if (objPtr->prevObjPtr)
78897989
objPtr->prevObjPtr->nextObjPtr = objPtr->nextObjPtr;
78907990
if (objPtr->nextObjPtr)
78917991
objPtr->nextObjPtr->prevObjPtr = objPtr->prevObjPtr;
78927992
if (interp->liveList == objPtr)
78937993
interp->liveList = objPtr->nextObjPtr;
78947994
#ifdef JIM_DISABLE_OBJECT_POOL
78957995
Jim_Free(objPtr);
78967996
#else
7897
-
7997
+
78987998
objPtr->prevObjPtr = NULL;
78997999
objPtr->nextObjPtr = interp->freeList;
79008000
if (interp->freeList)
79018001
interp->freeList->prevObjPtr = objPtr;
79028002
interp->freeList = objPtr;
@@ -7919,45 +8019,44 @@
79198019
{
79208020
Jim_Obj *dupPtr;
79218021
79228022
dupPtr = Jim_NewObj(interp);
79238023
if (objPtr->bytes == NULL) {
7924
-
8024
+
79258025
dupPtr->bytes = NULL;
79268026
}
79278027
else if (objPtr->length == 0) {
7928
-
79298028
dupPtr->bytes = JimEmptyStringRep;
79308029
dupPtr->length = 0;
79318030
dupPtr->typePtr = NULL;
79328031
return dupPtr;
79338032
}
79348033
else {
79358034
dupPtr->bytes = Jim_Alloc(objPtr->length + 1);
79368035
dupPtr->length = objPtr->length;
7937
-
8036
+
79388037
memcpy(dupPtr->bytes, objPtr->bytes, objPtr->length + 1);
79398038
}
79408039
7941
-
8040
+
79428041
dupPtr->typePtr = objPtr->typePtr;
79438042
if (objPtr->typePtr != NULL) {
79448043
if (objPtr->typePtr->dupIntRepProc == NULL) {
79458044
dupPtr->internalRep = objPtr->internalRep;
79468045
}
79478046
else {
7948
-
8047
+
79498048
objPtr->typePtr->dupIntRepProc(interp, objPtr, dupPtr);
79508049
}
79518050
}
79528051
return dupPtr;
79538052
}
79548053
79558054
const char *Jim_GetString(Jim_Obj *objPtr, int *lenPtr)
79568055
{
79578056
if (objPtr->bytes == NULL) {
7958
-
8057
+
79598058
JimPanic((objPtr->typePtr->updateStringProc == NULL, "UpdateStringProc called against '%s' type.", objPtr->typePtr->name));
79608059
objPtr->typePtr->updateStringProc(objPtr);
79618060
}
79628061
if (lenPtr)
79638062
*lenPtr = objPtr->length;
@@ -7966,25 +8065,22 @@
79668065
79678066
79688067
int Jim_Length(Jim_Obj *objPtr)
79698068
{
79708069
if (objPtr->bytes == NULL) {
7971
-
7972
- JimPanic((objPtr->typePtr->updateStringProc == NULL, "UpdateStringProc called against '%s' type.", objPtr->typePtr->name));
7973
- objPtr->typePtr->updateStringProc(objPtr);
8070
+
8071
+ Jim_GetString(objPtr, NULL);
79748072
}
79758073
return objPtr->length;
79768074
}
79778075
79788076
79798077
const char *Jim_String(Jim_Obj *objPtr)
79808078
{
79818079
if (objPtr->bytes == NULL) {
7982
-
7983
- JimPanic((objPtr->typePtr == NULL, "UpdateStringProc called against typeless value."));
7984
- JimPanic((objPtr->typePtr->updateStringProc == NULL, "UpdateStringProc called against '%s' type.", objPtr->typePtr->name));
7985
- objPtr->typePtr->updateStringProc(objPtr);
8080
+
8081
+ Jim_GetString(objPtr, NULL);
79868082
}
79878083
return objPtr->bytes;
79888084
}
79898085
79908086
static void JimSetStringBytes(Jim_Obj *objPtr, const char *str)
@@ -8001,23 +8097,34 @@
80018097
FreeDictSubstInternalRep,
80028098
DupDictSubstInternalRep,
80038099
NULL,
80048100
JIM_TYPE_NONE,
80058101
};
8102
+
8103
+static void FreeInterpolatedInternalRep(Jim_Interp *interp, Jim_Obj *objPtr);
8104
+static void DupInterpolatedInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr);
8105
+
8106
+static const Jim_ObjType interpolatedObjType = {
8107
+ "interpolated",
8108
+ FreeInterpolatedInternalRep,
8109
+ DupInterpolatedInternalRep,
8110
+ NULL,
8111
+ JIM_TYPE_NONE,
8112
+};
80068113
80078114
static void FreeInterpolatedInternalRep(Jim_Interp *interp, Jim_Obj *objPtr)
80088115
{
80098116
Jim_DecrRefCount(interp, objPtr->internalRep.dictSubstValue.indexObjPtr);
80108117
}
80118118
8012
-static const Jim_ObjType interpolatedObjType = {
8013
- "interpolated",
8014
- FreeInterpolatedInternalRep,
8015
- NULL,
8016
- NULL,
8017
- JIM_TYPE_NONE,
8018
-};
8119
+static void DupInterpolatedInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr)
8120
+{
8121
+
8122
+ dupPtr->internalRep = srcPtr->internalRep;
8123
+
8124
+ Jim_IncrRefCount(dupPtr->internalRep.dictSubstValue.indexObjPtr);
8125
+}
80198126
80208127
static void DupStringInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr);
80218128
static int SetStringFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr);
80228129
80238130
static const Jim_ObjType stringObjType = {
@@ -8037,22 +8144,22 @@
80378144
}
80388145
80398146
static int SetStringFromAny(Jim_Interp *interp, Jim_Obj *objPtr)
80408147
{
80418148
if (objPtr->typePtr != &stringObjType) {
8042
-
8149
+
80438150
if (objPtr->bytes == NULL) {
8044
-
8151
+
80458152
JimPanic((objPtr->typePtr->updateStringProc == NULL, "UpdateStringProc called against '%s' type.", objPtr->typePtr->name));
80468153
objPtr->typePtr->updateStringProc(objPtr);
80478154
}
8048
-
8155
+
80498156
Jim_FreeIntRep(interp, objPtr);
8050
-
8157
+
80518158
objPtr->typePtr = &stringObjType;
80528159
objPtr->internalRep.strValue.maxLength = objPtr->length;
8053
-
8160
+
80548161
objPtr->internalRep.strValue.charLength = -1;
80558162
}
80568163
return JIM_OK;
80578164
}
80588165
@@ -8073,39 +8180,37 @@
80738180
80748181
Jim_Obj *Jim_NewStringObj(Jim_Interp *interp, const char *s, int len)
80758182
{
80768183
Jim_Obj *objPtr = Jim_NewObj(interp);
80778184
8078
-
8185
+
80798186
if (len == -1)
80808187
len = strlen(s);
8081
-
8188
+
80828189
if (len == 0) {
80838190
objPtr->bytes = JimEmptyStringRep;
80848191
}
80858192
else {
8086
- objPtr->bytes = Jim_Alloc(len + 1);
8087
- memcpy(objPtr->bytes, s, len);
8088
- objPtr->bytes[len] = '\0';
8193
+ objPtr->bytes = Jim_StrDupLen(s, len);
80898194
}
80908195
objPtr->length = len;
80918196
8092
-
8197
+
80938198
objPtr->typePtr = NULL;
80948199
return objPtr;
80958200
}
80968201
80978202
80988203
Jim_Obj *Jim_NewStringObjUtf8(Jim_Interp *interp, const char *s, int charlen)
80998204
{
81008205
#ifdef JIM_UTF8
8101
-
8206
+
81028207
int bytelen = utf8_index(s, charlen);
81038208
81048209
Jim_Obj *objPtr = Jim_NewStringObj(interp, s, bytelen);
81058210
8106
-
8211
+
81078212
objPtr->typePtr = &stringObjType;
81088213
objPtr->internalRep.strValue.maxLength = bytelen;
81098214
objPtr->internalRep.strValue.charLength = charlen;
81108215
81118216
return objPtr;
@@ -8132,11 +8237,11 @@
81328237
len = strlen(str);
81338238
needlen = objPtr->length + len;
81348239
if (objPtr->internalRep.strValue.maxLength < needlen ||
81358240
objPtr->internalRep.strValue.maxLength == 0) {
81368241
needlen *= 2;
8137
-
8242
+
81388243
if (needlen < 7) {
81398244
needlen = 7;
81408245
}
81418246
if (objPtr->bytes == JimEmptyStringRep) {
81428247
objPtr->bytes = Jim_Alloc(needlen + 1);
@@ -8148,11 +8253,11 @@
81488253
}
81498254
memcpy(objPtr->bytes + objPtr->length, str, len);
81508255
objPtr->bytes[objPtr->length + len] = '\0';
81518256
81528257
if (objPtr->internalRep.strValue.charLength >= 0) {
8153
-
8258
+
81548259
objPtr->internalRep.strValue.charLength += utf8_strlen(objPtr->bytes + objPtr->length, len);
81558260
}
81568261
objPtr->length += len;
81578262
}
81588263
@@ -8210,11 +8315,11 @@
82108315
int l1, l2;
82118316
const char *s1 = Jim_GetString(firstObjPtr, &l1);
82128317
const char *s2 = Jim_GetString(secondObjPtr, &l2);
82138318
82148319
if (nocase) {
8215
-
8320
+
82168321
return JimStringCompareLen(s1, s2, -1, nocase);
82178322
}
82188323
return JimStringCompare(s1, l1, s2, l2);
82198324
}
82208325
@@ -8312,11 +8417,11 @@
83128417
83138418
if (first == 0 && rangeLen == len) {
83148419
return strObjPtr;
83158420
}
83168421
if (len == bytelen) {
8317
-
8422
+
83188423
return Jim_NewStringObj(interp, str + first, rangeLen);
83198424
}
83208425
return Jim_NewStringObjUtf8(interp, str + utf8_index(str, first), rangeLen);
83218426
#else
83228427
return Jim_StringByteRangeObj(interp, strObjPtr, firstObjPtr, lastObjPtr);
@@ -8341,19 +8446,19 @@
83418446
return strObjPtr;
83428447
}
83438448
83448449
str = Jim_String(strObjPtr);
83458450
8346
-
8451
+
83478452
objPtr = Jim_NewStringObjUtf8(interp, str, first);
83488453
8349
-
8454
+
83508455
if (newStrObj) {
83518456
Jim_AppendObj(interp, objPtr, newStrObj);
83528457
}
83538458
8354
-
8459
+
83558460
Jim_AppendString(interp, objPtr, str + utf8_index(str, last + 1), len - last - 1);
83568461
83578462
return objPtr;
83588463
}
83598464
@@ -8371,12 +8476,10 @@
83718476
{
83728477
char *buf;
83738478
int len;
83748479
const char *str;
83758480
8376
- SetStringFromAny(interp, strObjPtr);
8377
-
83788481
str = Jim_GetString(strObjPtr, &len);
83798482
83808483
#ifdef JIM_UTF8
83818484
len *= 2;
83828485
#endif
@@ -8389,14 +8492,10 @@
83898492
{
83908493
char *buf;
83918494
const char *str;
83928495
int len;
83938496
8394
- if (strObjPtr->typePtr != &stringObjType) {
8395
- SetStringFromAny(interp, strObjPtr);
8396
- }
8397
-
83988497
str = Jim_GetString(strObjPtr, &len);
83998498
84008499
#ifdef JIM_UTF8
84018500
len *= 2;
84028501
#endif
@@ -8411,13 +8510,11 @@
84118510
int len;
84128511
int c;
84138512
const char *str;
84148513
84158514
str = Jim_GetString(strObjPtr, &len);
8416
- if (len == 0) {
8417
- return strObjPtr;
8418
- }
8515
+
84198516
#ifdef JIM_UTF8
84208517
len *= 2;
84218518
#endif
84228519
buf = p = Jim_Alloc(len + 1);
84238520
@@ -8452,11 +8549,11 @@
84528549
while (len) {
84538550
int c;
84548551
int n = utf8_tounicode(str, &c);
84558552
84568553
if (utf8_memchr(trimchars, trimlen, c) == NULL) {
8457
-
8554
+
84588555
break;
84598556
}
84608557
str += n;
84618558
len -= n;
84628559
}
@@ -8523,41 +8620,41 @@
85238620
85248621
len = Jim_Length(strObjPtr);
85258622
nontrim = JimFindTrimRight(strObjPtr->bytes, len, trimchars, trimcharslen);
85268623
85278624
if (nontrim == NULL) {
8528
-
8625
+
85298626
return Jim_NewEmptyStringObj(interp);
85308627
}
85318628
if (nontrim == strObjPtr->bytes + len) {
8532
-
8629
+
85338630
return strObjPtr;
85348631
}
85358632
85368633
if (Jim_IsShared(strObjPtr)) {
85378634
strObjPtr = Jim_NewStringObj(interp, strObjPtr->bytes, (nontrim - strObjPtr->bytes));
85388635
}
85398636
else {
8540
-
8637
+
85418638
strObjPtr->bytes[nontrim - strObjPtr->bytes] = 0;
85428639
strObjPtr->length = (nontrim - strObjPtr->bytes);
85438640
}
85448641
85458642
return strObjPtr;
85468643
}
85478644
85488645
static Jim_Obj *JimStringTrim(Jim_Interp *interp, Jim_Obj *strObjPtr, Jim_Obj *trimcharsObjPtr)
85498646
{
8550
-
8647
+
85518648
Jim_Obj *objPtr = JimStringTrimLeft(interp, strObjPtr, trimcharsObjPtr);
85528649
8553
-
8650
+
85548651
strObjPtr = JimStringTrimRight(interp, objPtr, trimcharsObjPtr);
85558652
8556
-
8653
+
85578654
if (objPtr != strObjPtr && objPtr->refCount == 0) {
8558
-
8655
+
85598656
Jim_FreeNewObj(interp, objPtr);
85608657
}
85618658
85628659
return strObjPtr;
85638660
}
@@ -8575,17 +8672,17 @@
85758672
static int JimStringIs(Jim_Interp *interp, Jim_Obj *strObjPtr, Jim_Obj *strClass, int strict)
85768673
{
85778674
static const char * const strclassnames[] = {
85788675
"integer", "alpha", "alnum", "ascii", "digit",
85798676
"double", "lower", "upper", "space", "xdigit",
8580
- "control", "print", "graph", "punct",
8677
+ "control", "print", "graph", "punct", "boolean",
85818678
NULL
85828679
};
85838680
enum {
85848681
STR_IS_INTEGER, STR_IS_ALPHA, STR_IS_ALNUM, STR_IS_ASCII, STR_IS_DIGIT,
85858682
STR_IS_DOUBLE, STR_IS_LOWER, STR_IS_UPPER, STR_IS_SPACE, STR_IS_XDIGIT,
8586
- STR_IS_CONTROL, STR_IS_PRINT, STR_IS_GRAPH, STR_IS_PUNCT
8683
+ STR_IS_CONTROL, STR_IS_PRINT, STR_IS_GRAPH, STR_IS_PUNCT, STR_IS_BOOLEAN,
85878684
};
85888685
int strclass;
85898686
int len;
85908687
int i;
85918688
const char *str;
@@ -8613,10 +8710,17 @@
86138710
{
86148711
double d;
86158712
Jim_SetResultBool(interp, Jim_GetDouble(interp, strObjPtr, &d) == JIM_OK && errno != ERANGE);
86168713
return JIM_OK;
86178714
}
8715
+
8716
+ case STR_IS_BOOLEAN:
8717
+ {
8718
+ int b;
8719
+ Jim_SetResultBool(interp, Jim_GetBoolean(interp, strObjPtr, &b) == JIM_OK);
8720
+ return JIM_OK;
8721
+ }
86188722
86198723
case STR_IS_ALPHA: isclassfunc = isalpha; break;
86208724
case STR_IS_ALNUM: isclassfunc = isalnum; break;
86218725
case STR_IS_ASCII: isclassfunc = jim_isascii; break;
86228726
case STR_IS_DIGIT: isclassfunc = isdigit; break;
@@ -8631,11 +8735,11 @@
86318735
default:
86328736
return JIM_ERR;
86338737
}
86348738
86358739
for (i = 0; i < len; i++) {
8636
- if (!isclassfunc(str[i])) {
8740
+ if (!isclassfunc(UCHAR(str[i]))) {
86378741
Jim_SetResultBool(interp, 0);
86388742
return JIM_OK;
86398743
}
86408744
}
86418745
Jim_SetResultBool(interp, 1);
@@ -8656,20 +8760,18 @@
86568760
{
86578761
if (objPtr->typePtr == &comparedStringObjType && objPtr->internalRep.ptr == str) {
86588762
return 1;
86598763
}
86608764
else {
8661
- const char *objStr = Jim_String(objPtr);
8662
-
8663
- if (strcmp(str, objStr) != 0)
8765
+ if (strcmp(str, Jim_String(objPtr)) != 0)
86648766
return 0;
86658767
86668768
if (objPtr->typePtr != &comparedStringObjType) {
86678769
Jim_FreeIntRep(interp, objPtr);
86688770
objPtr->typePtr = &comparedStringObjType;
86698771
}
8670
- objPtr->internalRep.ptr = (char *)str;
8772
+ objPtr->internalRep.ptr = (char *)str;
86718773
return 1;
86728774
}
86738775
}
86748776
86758777
static int qsortCompareStringPointers(const void *a, const void *b)
@@ -8758,20 +8860,20 @@
87588860
int type;
87598861
} ScriptToken;
87608862
87618863
typedef struct ScriptObj
87628864
{
8763
- ScriptToken *token;
8764
- Jim_Obj *fileNameObj;
8765
- int len;
8766
- int substFlags;
8865
+ ScriptToken *token;
8866
+ Jim_Obj *fileNameObj;
8867
+ int len;
8868
+ int substFlags;
87678869
int inUse; /* Used to share a ScriptObj. Currently
87688870
only used by Jim_EvalObj() as protection against
87698871
shimmering of the currently evaluated object. */
8770
- int firstline;
8771
- int linenr;
8772
- int missing;
8872
+ int firstline;
8873
+ int linenr;
8874
+ int missing;
87738875
} ScriptObj;
87748876
87758877
static void JimSetScriptFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr);
87768878
static int JimParseCheckMissing(Jim_Interp *interp, int ch);
87778879
static ScriptObj *JimGetScript(Jim_Interp *interp, Jim_Obj *objPtr);
@@ -8799,23 +8901,23 @@
87998901
dupPtr->typePtr = NULL;
88008902
}
88018903
88028904
typedef struct
88038905
{
8804
- const char *token;
8805
- int len;
8806
- int type;
8807
- int line;
8906
+ const char *token;
8907
+ int len;
8908
+ int type;
8909
+ int line;
88088910
} ParseToken;
88098911
88108912
typedef struct
88118913
{
8812
-
8813
- ParseToken *list;
8814
- int size;
8815
- int count;
8816
- ParseToken static_list[20];
8914
+
8915
+ ParseToken *list;
8916
+ int size;
8917
+ int count;
8918
+ ParseToken static_list[20];
88178919
} ParseTokenList;
88188920
88198921
static void ScriptTokenListInit(ParseTokenList *tokenlist)
88208922
{
88218923
tokenlist->list = tokenlist->static_list;
@@ -8834,18 +8936,18 @@
88348936
int line)
88358937
{
88368938
ParseToken *t;
88378939
88388940
if (tokenlist->count == tokenlist->size) {
8839
-
8941
+
88408942
tokenlist->size *= 2;
88418943
if (tokenlist->list != tokenlist->static_list) {
88428944
tokenlist->list =
88438945
Jim_Realloc(tokenlist->list, tokenlist->size * sizeof(*tokenlist->list));
88448946
}
88458947
else {
8846
-
8948
+
88478949
tokenlist->list = Jim_Alloc(tokenlist->size * sizeof(*tokenlist->list));
88488950
memcpy(tokenlist->list, tokenlist->static_list,
88498951
tokenlist->count * sizeof(*tokenlist->list));
88508952
}
88518953
}
@@ -8854,25 +8956,32 @@
88548956
t->len = len;
88558957
t->type = type;
88568958
t->line = line;
88578959
}
88588960
8859
-static int JimCountWordTokens(ParseToken *t)
8961
+static int JimCountWordTokens(struct ScriptObj *script, ParseToken *t)
88608962
{
88618963
int expand = 1;
88628964
int count = 0;
88638965
8864
-
8966
+
88658967
if (t->type == JIM_TT_STR && !TOKEN_IS_SEP(t[1].type)) {
88668968
if ((t->len == 1 && *t->token == '*') || (t->len == 6 && strncmp(t->token, "expand", 6) == 0)) {
8867
-
8969
+
88688970
expand = -1;
88698971
t++;
88708972
}
8973
+ else {
8974
+ if (script->missing == ' ') {
8975
+
8976
+ script->missing = '}';
8977
+ script->linenr = t[1].line;
8978
+ }
8979
+ }
88718980
}
88728981
8873
-
8982
+
88748983
while (!TOKEN_IS_SEP(t->type)) {
88758984
t++;
88768985
count++;
88778986
}
88788987
@@ -8882,11 +8991,11 @@
88828991
static Jim_Obj *JimMakeScriptObj(Jim_Interp *interp, const ParseToken *t)
88838992
{
88848993
Jim_Obj *objPtr;
88858994
88868995
if (t->type == JIM_TT_ESC && memchr(t->token, '\\', t->len) != NULL) {
8887
-
8996
+
88888997
int len = t->len;
88898998
char *str = Jim_Alloc(len + 1);
88908999
len = JimEscape(str, t->token, len);
88919000
objPtr = Jim_NewStringObjNoAlloc(interp, str, len);
88929001
}
@@ -8899,13 +9008,13 @@
88999008
static void ScriptObjAddTokens(Jim_Interp *interp, struct ScriptObj *script,
89009009
ParseTokenList *tokenlist)
89019010
{
89029011
int i;
89039012
struct ScriptToken *token;
8904
-
9013
+
89059014
int lineargs = 0;
8906
-
9015
+
89079016
ScriptToken *linefirst;
89089017
int count;
89099018
int linenr;
89109019
89119020
#ifdef DEBUG_SHOW_SCRIPT_TOKENS
@@ -8914,11 +9023,11 @@
89149023
printf("[%2d]@%d %s '%.*s'\n", i, tokenlist->list[i].line, jim_tt_name(tokenlist->list[i].type),
89159024
tokenlist->list[i].len, tokenlist->list[i].token);
89169025
}
89179026
#endif
89189027
8919
-
9028
+
89209029
count = tokenlist->count;
89219030
for (i = 0; i < tokenlist->count; i++) {
89229031
if (tokenlist->list[i].type == JIM_TT_EOL) {
89239032
count++;
89249033
}
@@ -8925,59 +9034,59 @@
89259034
}
89269035
linenr = script->firstline = tokenlist->list[0].line;
89279036
89289037
token = script->token = Jim_Alloc(sizeof(ScriptToken) * count);
89299038
8930
-
9039
+
89319040
linefirst = token++;
89329041
89339042
for (i = 0; i < tokenlist->count; ) {
8934
-
9043
+
89359044
int wordtokens;
89369045
8937
-
9046
+
89389047
while (tokenlist->list[i].type == JIM_TT_SEP) {
89399048
i++;
89409049
}
89419050
8942
- wordtokens = JimCountWordTokens(tokenlist->list + i);
9051
+ wordtokens = JimCountWordTokens(script, tokenlist->list + i);
89439052
89449053
if (wordtokens == 0) {
8945
-
9054
+
89469055
if (lineargs) {
89479056
linefirst->type = JIM_TT_LINE;
89489057
linefirst->objPtr = JimNewScriptLineObj(interp, lineargs, linenr);
89499058
Jim_IncrRefCount(linefirst->objPtr);
89509059
8951
-
9060
+
89529061
lineargs = 0;
89539062
linefirst = token++;
89549063
}
89559064
i++;
89569065
continue;
89579066
}
89589067
else if (wordtokens != 1) {
8959
-
9068
+
89609069
token->type = JIM_TT_WORD;
89619070
token->objPtr = Jim_NewIntObj(interp, wordtokens);
89629071
Jim_IncrRefCount(token->objPtr);
89639072
token++;
89649073
if (wordtokens < 0) {
8965
-
9074
+
89669075
i++;
89679076
wordtokens = -wordtokens - 1;
89689077
lineargs--;
89699078
}
89709079
}
89719080
89729081
if (lineargs == 0) {
8973
-
9082
+
89749083
linenr = tokenlist->list[i].line;
89759084
}
89769085
lineargs++;
89779086
8978
-
9087
+
89799088
while (wordtokens--) {
89809089
const ParseToken *t = &tokenlist->list[i++];
89819090
89829091
token->type = t->type;
89839092
token->objPtr = JimMakeScriptObj(interp, t);
@@ -9010,11 +9119,11 @@
90109119
{
90119120
ScriptObj *script = JimGetScript(interp, scriptObj);
90129121
if (stateCharPtr) {
90139122
*stateCharPtr = script->missing;
90149123
}
9015
- return (script->missing == ' ');
9124
+ return script->missing == ' ' || script->missing == '}';
90169125
}
90179126
90189127
static int JimParseCheckMissing(Jim_Interp *interp, int ch)
90199128
{
90209129
const char *msg;
@@ -9028,10 +9137,13 @@
90289137
msg = "unmatched \"[\"";
90299138
break;
90309139
case '{':
90319140
msg = "missing close-brace";
90329141
break;
9142
+ case '}':
9143
+ msg = "extra characters after close-brace";
9144
+ break;
90339145
case '"':
90349146
default:
90359147
msg = "missing quote";
90369148
break;
90379149
}
@@ -9049,11 +9161,11 @@
90499161
token = script->token = Jim_Alloc(sizeof(ScriptToken) * tokenlist->count);
90509162
90519163
for (i = 0; i < tokenlist->count; i++) {
90529164
const ParseToken *t = &tokenlist->list[i];
90539165
9054
-
9166
+
90559167
token->type = t->type;
90569168
token->objPtr = JimMakeScriptObj(interp, t);
90579169
Jim_IncrRefCount(token->objPtr);
90589170
token++;
90599171
}
@@ -9068,29 +9180,29 @@
90689180
struct JimParserCtx parser;
90699181
struct ScriptObj *script;
90709182
ParseTokenList tokenlist;
90719183
int line = 1;
90729184
9073
-
9185
+
90749186
if (objPtr->typePtr == &sourceObjType) {
90759187
line = objPtr->internalRep.sourceValue.lineNumber;
90769188
}
90779189
9078
-
9190
+
90799191
ScriptTokenListInit(&tokenlist);
90809192
90819193
JimParserInit(&parser, scriptText, scriptTextLen, line);
90829194
while (!parser.eof) {
90839195
JimParseScript(&parser);
90849196
ScriptAddToken(&tokenlist, parser.tstart, parser.tend - parser.tstart + 1, parser.tt,
90859197
parser.tline);
90869198
}
90879199
9088
-
9200
+
90899201
ScriptAddToken(&tokenlist, scriptText + scriptTextLen, 0, JIM_TT_EOF, 0);
90909202
9091
-
9203
+
90929204
script = Jim_Alloc(sizeof(*script));
90939205
memset(script, 0, sizeof(*script));
90949206
script->inUse = 1;
90959207
if (objPtr->typePtr == &sourceObjType) {
90969208
script->fileNameObj = objPtr->internalRep.sourceValue.fileNameObj;
@@ -9102,14 +9214,14 @@
91029214
script->missing = parser.missing.ch;
91039215
script->linenr = parser.missing.line;
91049216
91059217
ScriptObjAddTokens(interp, script, &tokenlist);
91069218
9107
-
9219
+
91089220
ScriptTokenListFree(&tokenlist);
91099221
9110
-
9222
+
91119223
Jim_FreeIntRep(interp, objPtr);
91129224
Jim_SetIntRepPtr(objPtr, script);
91139225
objPtr->typePtr = &scriptObjType;
91149226
}
91159227
@@ -9116,11 +9228,11 @@
91169228
static void JimAddErrorToStack(Jim_Interp *interp, ScriptObj *script);
91179229
91189230
static ScriptObj *JimGetScript(Jim_Interp *interp, Jim_Obj *objPtr)
91199231
{
91209232
if (objPtr == interp->emptyObj) {
9121
-
9233
+
91229234
objPtr = interp->nullScriptObj;
91239235
}
91249236
91259237
if (objPtr->typePtr != &scriptObjType || ((struct ScriptObj *)Jim_GetIntRepPtr(objPtr))->substFlags) {
91269238
JimSetScriptFromAny(interp, objPtr);
@@ -9155,67 +9267,66 @@
91559267
Jim_FreeHashTable(cmdPtr->u.proc.staticVars);
91569268
Jim_Free(cmdPtr->u.proc.staticVars);
91579269
}
91589270
}
91599271
else {
9160
-
9272
+
91619273
if (cmdPtr->u.native.delProc) {
91629274
cmdPtr->u.native.delProc(interp, cmdPtr->u.native.privData);
91639275
}
91649276
}
91659277
if (cmdPtr->prevCmd) {
9166
-
9278
+
91679279
JimDecrCmdRefCount(interp, cmdPtr->prevCmd);
91689280
}
91699281
Jim_Free(cmdPtr);
91709282
}
91719283
}
9172
-
91739284
91749285
static void JimVariablesHTValDestructor(void *interp, void *val)
91759286
{
91769287
Jim_DecrRefCount(interp, ((Jim_Var *)val)->objPtr);
91779288
Jim_Free(val);
91789289
}
91799290
91809291
static const Jim_HashTableType JimVariablesHashTableType = {
9181
- JimStringCopyHTHashFunction,
9182
- JimStringCopyHTDup,
9183
- NULL,
9184
- JimStringCopyHTKeyCompare,
9185
- JimStringCopyHTKeyDestructor,
9186
- JimVariablesHTValDestructor
9292
+ JimStringCopyHTHashFunction,
9293
+ JimStringCopyHTDup,
9294
+ NULL,
9295
+ JimStringCopyHTKeyCompare,
9296
+ JimStringCopyHTKeyDestructor,
9297
+ JimVariablesHTValDestructor
91879298
};
91889299
91899300
static void JimCommandsHT_ValDestructor(void *interp, void *val)
91909301
{
91919302
JimDecrCmdRefCount(interp, val);
91929303
}
91939304
91949305
static const Jim_HashTableType JimCommandsHashTableType = {
9195
- JimStringCopyHTHashFunction,
9196
- JimStringCopyHTDup,
9197
- NULL,
9198
- JimStringCopyHTKeyCompare,
9199
- JimStringCopyHTKeyDestructor,
9200
- JimCommandsHT_ValDestructor
9306
+ JimStringCopyHTHashFunction,
9307
+ JimStringCopyHTDup,
9308
+ NULL,
9309
+ JimStringCopyHTKeyCompare,
9310
+ JimStringCopyHTKeyDestructor,
9311
+ JimCommandsHT_ValDestructor
92019312
};
92029313
92039314
92049315
92059316
#ifdef jim_ext_namespace
92069317
static Jim_Obj *JimQualifyNameObj(Jim_Interp *interp, Jim_Obj *nsObj)
92079318
{
92089319
const char *name = Jim_String(nsObj);
92099320
if (name[0] == ':' && name[1] == ':') {
9210
-
9321
+
92119322
while (*++name == ':') {
92129323
}
92139324
nsObj = Jim_NewStringObj(interp, name, -1);
92149325
}
92159326
else if (Jim_Length(interp->framePtr->nsObj)) {
9216
-
9327
+
92179328
nsObj = Jim_DuplicateObj(interp, interp->framePtr->nsObj);
92189329
Jim_AppendStrings(interp, nsObj, "::", name, NULL);
92199330
}
92209331
return nsObj;
92219332
}
@@ -9239,16 +9350,16 @@
92399350
static const char *JimQualifyName(Jim_Interp *interp, const char *name, Jim_Obj **objPtrPtr)
92409351
{
92419352
Jim_Obj *objPtr = interp->emptyObj;
92429353
92439354
if (name[0] == ':' && name[1] == ':') {
9244
-
9355
+
92459356
while (*++name == ':') {
92469357
}
92479358
}
92489359
else if (Jim_Length(interp->framePtr->nsObj)) {
9249
-
9360
+
92509361
objPtr = Jim_DuplicateObj(interp, interp->framePtr->nsObj);
92519362
Jim_AppendStrings(interp, objPtr, "::", name, NULL);
92529363
name = Jim_String(objPtr);
92539364
}
92549365
Jim_IncrRefCount(objPtr);
@@ -9257,11 +9368,11 @@
92579368
}
92589369
92599370
#define JimFreeQualifiedName(INTERP, OBJ) Jim_DecrRefCount((INTERP), (OBJ))
92609371
92619372
#else
9262
-
9373
+
92639374
#define JimQualifyName(INTERP, NAME, DUMMY) (((NAME)[0] == ':' && (NAME)[1] == ':') ? (NAME) + 2 : (NAME))
92649375
#define JimFreeQualifiedName(INTERP, DUMMY) (void)(DUMMY)
92659376
92669377
Jim_Obj *Jim_MakeGlobalNamespaceName(Jim_Interp *interp, Jim_Obj *nameObjPtr)
92679378
{
@@ -9276,17 +9387,17 @@
92769387
92779388
Jim_InterpIncrProcEpoch(interp);
92789389
}
92799390
92809391
if (he && interp->local) {
9281
-
9392
+
92829393
cmd->prevCmd = Jim_GetHashEntryVal(he);
92839394
Jim_SetHashVal(&interp->commands, he, cmd);
92849395
}
92859396
else {
92869397
if (he) {
9287
-
9398
+
92889399
Jim_DeleteHashEntry(&interp->commands, name);
92899400
}
92909401
92919402
Jim_AddHashEntry(&interp->commands, name, cmd);
92929403
}
@@ -9297,11 +9408,11 @@
92979408
int Jim_CreateCommand(Jim_Interp *interp, const char *cmdNameStr,
92989409
Jim_CmdProc *cmdProc, void *privData, Jim_DelCmdProc *delProc)
92999410
{
93009411
Jim_Cmd *cmdPtr = Jim_Alloc(sizeof(*cmdPtr));
93019412
9302
-
9413
+
93039414
memset(cmdPtr, 0, sizeof(*cmdPtr));
93049415
cmdPtr->inUse = 1;
93059416
cmdPtr->u.native.delProc = delProc;
93069417
cmdPtr->u.native.cmdProc = cmdProc;
93079418
cmdPtr->u.native.privData = privData;
@@ -9326,11 +9437,11 @@
93269437
Jim_Obj *objPtr, *initObjPtr, *nameObjPtr;
93279438
Jim_Var *varPtr;
93289439
int subLen;
93299440
93309441
objPtr = Jim_ListGetIndex(interp, staticsListObjPtr, i);
9331
-
9442
+
93329443
subLen = Jim_ListLength(interp, objPtr);
93339444
if (subLen == 1 || subLen == 2) {
93349445
nameObjPtr = Jim_ListGetIndex(interp, objPtr, 0);
93359446
if (subLen == 1) {
93369447
initObjPtr = Jim_GetVariable(interp, nameObjPtr, JIM_NONE);
@@ -9372,19 +9483,19 @@
93729483
93739484
static void JimUpdateProcNamespace(Jim_Interp *interp, Jim_Cmd *cmdPtr, const char *cmdname)
93749485
{
93759486
#ifdef jim_ext_namespace
93769487
if (cmdPtr->isproc) {
9377
-
9488
+
93789489
const char *pt = strrchr(cmdname, ':');
93799490
if (pt && pt != cmdname && pt[-1] == ':') {
93809491
Jim_DecrRefCount(interp, cmdPtr->u.proc.nsObj);
93819492
cmdPtr->u.proc.nsObj = Jim_NewStringObj(interp, cmdname, pt - cmdname - 1);
93829493
Jim_IncrRefCount(cmdPtr->u.proc.nsObj);
93839494
93849495
if (Jim_FindHashEntry(&interp->commands, pt + 1)) {
9385
-
9496
+
93869497
Jim_InterpIncrProcEpoch(interp);
93879498
}
93889499
}
93899500
}
93909501
#endif
@@ -9397,11 +9508,11 @@
93979508
int argListLen;
93989509
int i;
93999510
94009511
argListLen = Jim_ListLength(interp, argListObjPtr);
94019512
9402
-
9513
+
94039514
cmdPtr = Jim_Alloc(sizeof(*cmdPtr) + sizeof(struct Jim_ProcArg) * argListLen);
94049515
memset(cmdPtr, 0, sizeof(*cmdPtr));
94059516
cmdPtr->inUse = 1;
94069517
cmdPtr->isproc = 1;
94079518
cmdPtr->u.proc.argListObjPtr = argListObjPtr;
@@ -9412,24 +9523,24 @@
94129523
cmdPtr->u.proc.nsObj = nsObj ? nsObj : interp->emptyObj;
94139524
Jim_IncrRefCount(argListObjPtr);
94149525
Jim_IncrRefCount(bodyObjPtr);
94159526
Jim_IncrRefCount(cmdPtr->u.proc.nsObj);
94169527
9417
-
9528
+
94189529
if (staticsListObjPtr && JimCreateProcedureStatics(interp, cmdPtr, staticsListObjPtr) != JIM_OK) {
94199530
goto err;
94209531
}
94219532
9422
-
9423
-
9533
+
9534
+
94249535
for (i = 0; i < argListLen; i++) {
94259536
Jim_Obj *argPtr;
94269537
Jim_Obj *nameObjPtr;
94279538
Jim_Obj *defaultObjPtr;
94289539
int len;
94299540
9430
-
9541
+
94319542
argPtr = Jim_ListGetIndex(interp, argListObjPtr, i);
94329543
len = Jim_ListLength(interp, argPtr);
94339544
if (len == 0) {
94349545
Jim_SetResultString(interp, "argument with no name", -1);
94359546
err:
@@ -9440,16 +9551,16 @@
94409551
Jim_SetResultFormatted(interp, "too many fields in argument specifier \"%#s\"", argPtr);
94419552
goto err;
94429553
}
94439554
94449555
if (len == 2) {
9445
-
9556
+
94469557
nameObjPtr = Jim_ListGetIndex(interp, argPtr, 0);
94479558
defaultObjPtr = Jim_ListGetIndex(interp, argPtr, 1);
94489559
}
94499560
else {
9450
-
9561
+
94519562
nameObjPtr = argPtr;
94529563
defaultObjPtr = NULL;
94539564
}
94549565
94559566
@@ -9510,29 +9621,29 @@
95109621
}
95119622
95129623
fqold = JimQualifyName(interp, oldName, &qualifiedOldNameObj);
95139624
fqnew = JimQualifyName(interp, newName, &qualifiedNewNameObj);
95149625
9515
-
9626
+
95169627
he = Jim_FindHashEntry(&interp->commands, fqold);
95179628
if (he == NULL) {
95189629
Jim_SetResultFormatted(interp, "can't rename \"%s\": command doesn't exist", oldName);
95199630
}
95209631
else if (Jim_FindHashEntry(&interp->commands, fqnew)) {
95219632
Jim_SetResultFormatted(interp, "can't rename to \"%s\": command already exists", newName);
95229633
}
95239634
else {
9524
-
9635
+
95259636
cmdPtr = Jim_GetHashEntryVal(he);
95269637
JimIncrCmdRefCount(cmdPtr);
95279638
JimUpdateProcNamespace(interp, cmdPtr, fqnew);
95289639
Jim_AddHashEntry(&interp->commands, fqnew, cmdPtr);
95299640
9530
-
9641
+
95319642
Jim_DeleteHashEntry(&interp->commands, fqold);
95329643
9533
-
9644
+
95349645
Jim_InterpIncrProcEpoch(interp);
95359646
95369647
ret = JIM_OK;
95379648
}
95389649
@@ -9571,23 +9682,23 @@
95719682
objPtr->internalRep.cmdValue.procEpoch != interp->procEpoch
95729683
#ifdef jim_ext_namespace
95739684
|| !Jim_StringEqObj(objPtr->internalRep.cmdValue.nsObj, interp->framePtr->nsObj)
95749685
#endif
95759686
) {
9576
-
95779687
9578
-
9688
+
9689
+
95799690
const char *name = Jim_String(objPtr);
95809691
Jim_HashEntry *he;
95819692
95829693
if (name[0] == ':' && name[1] == ':') {
95839694
while (*++name == ':') {
95849695
}
95859696
}
95869697
#ifdef jim_ext_namespace
95879698
else if (Jim_Length(interp->framePtr->nsObj)) {
9588
-
9699
+
95899700
Jim_Obj *nameObj = Jim_DuplicateObj(interp, interp->framePtr->nsObj);
95909701
Jim_AppendStrings(interp, nameObj, "::", name, NULL);
95919702
he = Jim_FindHashEntry(&interp->commands, Jim_String(nameObj));
95929703
Jim_FreeNewObj(interp, nameObj);
95939704
if (he) {
@@ -9594,11 +9705,11 @@
95949705
goto found;
95959706
}
95969707
}
95979708
#endif
95989709
9599
-
9710
+
96009711
he = Jim_FindHashEntry(&interp->commands, name);
96019712
if (he == NULL) {
96029713
if (flags & JIM_ERRMSG) {
96039714
Jim_SetResultFormatted(interp, "invalid command name \"%#s\"", objPtr);
96049715
}
@@ -9607,11 +9718,11 @@
96079718
#ifdef jim_ext_namespace
96089719
found:
96099720
#endif
96109721
cmd = Jim_GetHashEntryVal(he);
96119722
9612
-
9723
+
96139724
Jim_FreeIntRep(interp, objPtr);
96149725
objPtr->typePtr = &commandObjType;
96159726
objPtr->internalRep.cmdValue.procEpoch = interp->procEpoch;
96169727
objPtr->internalRep.cmdValue.cmdPtr = cmd;
96179728
objPtr->internalRep.cmdValue.nsObj = interp->framePtr->nsObj;
@@ -9626,11 +9737,11 @@
96269737
return cmd;
96279738
}
96289739
96299740
96309741
9631
-#define JIM_DICT_SUGAR 100
9742
+#define JIM_DICT_SUGAR 100
96329743
96339744
static int SetVariableFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr);
96349745
96359746
static const Jim_ObjType variableObjType = {
96369747
"variable",
@@ -9640,11 +9751,11 @@
96409751
JIM_TYPE_REFERENCES,
96419752
};
96429753
96439754
static int JimValidName(Jim_Interp *interp, const char *type, Jim_Obj *nameObjPtr)
96449755
{
9645
-
9756
+
96469757
if (nameObjPtr->typePtr != &variableObjType) {
96479758
int len;
96489759
const char *str = Jim_GetString(nameObjPtr, &len);
96499760
if (memchr(str, '\0', len)) {
96509761
Jim_SetResultFormatted(interp, "%s name contains embedded null", type);
@@ -9660,18 +9771,18 @@
96609771
Jim_CallFrame *framePtr;
96619772
Jim_HashEntry *he;
96629773
int global;
96639774
int len;
96649775
9665
-
9776
+
96669777
if (objPtr->typePtr == &variableObjType) {
96679778
framePtr = objPtr->internalRep.varValue.global ? interp->topFramePtr : interp->framePtr;
96689779
if (objPtr->internalRep.varValue.callFrameId == framePtr->id) {
9669
-
9780
+
96709781
return JIM_OK;
96719782
}
9672
-
9783
+
96739784
}
96749785
else if (objPtr->typePtr == &dictSubstObjType) {
96759786
return JIM_DICT_SUGAR;
96769787
}
96779788
else if (JimValidName(interp, "variable", objPtr) != JIM_OK) {
@@ -9679,11 +9790,11 @@
96799790
}
96809791
96819792
96829793
varName = Jim_GetString(objPtr, &len);
96839794
9684
-
9795
+
96859796
if (len && varName[len - 1] == ')' && strchr(varName, '(') != NULL) {
96869797
return JIM_DICT_SUGAR;
96879798
}
96889799
96899800
if (varName[0] == ':' && varName[1] == ':') {
@@ -9695,23 +9806,23 @@
96959806
else {
96969807
global = 0;
96979808
framePtr = interp->framePtr;
96989809
}
96999810
9700
-
9811
+
97019812
he = Jim_FindHashEntry(&framePtr->vars, varName);
97029813
if (he == NULL) {
97039814
if (!global && framePtr->staticVars) {
9704
-
9815
+
97059816
he = Jim_FindHashEntry(framePtr->staticVars, varName);
97069817
}
97079818
if (he == NULL) {
97089819
return JIM_ERR;
97099820
}
97109821
}
97119822
9712
-
9823
+
97139824
Jim_FreeIntRep(interp, objPtr);
97149825
objPtr->typePtr = &variableObjType;
97159826
objPtr->internalRep.varValue.callFrameId = framePtr->id;
97169827
objPtr->internalRep.varValue.varPtr = Jim_GetHashEntryVal(he);
97179828
objPtr->internalRep.varValue.global = global;
@@ -9726,11 +9837,11 @@
97269837
{
97279838
const char *name;
97289839
Jim_CallFrame *framePtr;
97299840
int global;
97309841
9731
-
9842
+
97329843
Jim_Var *var = Jim_Alloc(sizeof(*var));
97339844
97349845
var->objPtr = valObjPtr;
97359846
Jim_IncrRefCount(valObjPtr);
97369847
var->linkFramePtr = NULL;
@@ -9745,14 +9856,14 @@
97459856
else {
97469857
framePtr = interp->framePtr;
97479858
global = 0;
97489859
}
97499860
9750
-
9861
+
97519862
Jim_AddHashEntry(&framePtr->vars, name, var);
97529863
9753
-
9864
+
97549865
Jim_FreeIntRep(interp, nameObjPtr);
97559866
nameObjPtr->typePtr = &variableObjType;
97569867
nameObjPtr->internalRep.varValue.callFrameId = framePtr->id;
97579868
nameObjPtr->internalRep.varValue.varPtr = var;
97589869
nameObjPtr->internalRep.varValue.global = global;
@@ -9782,11 +9893,11 @@
97829893
if (var->linkFramePtr == NULL) {
97839894
Jim_IncrRefCount(valObjPtr);
97849895
Jim_DecrRefCount(interp, var->objPtr);
97859896
var->objPtr = valObjPtr;
97869897
}
9787
- else {
9898
+ else {
97889899
Jim_CallFrame *savedCallFrame;
97899900
97909901
savedCallFrame = interp->framePtr;
97919902
interp->framePtr = var->linkFramePtr;
97929903
err = Jim_SetVariable(interp, var->objPtr, valObjPtr);
@@ -9822,19 +9933,16 @@
98229933
return result;
98239934
}
98249935
98259936
int Jim_SetVariableStrWithStr(Jim_Interp *interp, const char *name, const char *val)
98269937
{
9827
- Jim_Obj *nameObjPtr, *valObjPtr;
9938
+ Jim_Obj *valObjPtr;
98289939
int result;
98299940
9830
- nameObjPtr = Jim_NewStringObj(interp, name, -1);
98319941
valObjPtr = Jim_NewStringObj(interp, val, -1);
9832
- Jim_IncrRefCount(nameObjPtr);
98339942
Jim_IncrRefCount(valObjPtr);
9834
- result = Jim_SetVariable(interp, nameObjPtr, valObjPtr);
9835
- Jim_DecrRefCount(interp, nameObjPtr);
9943
+ result = Jim_SetVariableStr(interp, name, valObjPtr);
98369944
Jim_DecrRefCount(interp, valObjPtr);
98379945
return result;
98389946
}
98399947
98409948
int Jim_SetVariableLink(Jim_Interp *interp, Jim_Obj *nameObjPtr,
@@ -9843,14 +9951,14 @@
98439951
const char *varName;
98449952
const char *targetName;
98459953
Jim_CallFrame *framePtr;
98469954
Jim_Var *varPtr;
98479955
9848
-
9956
+
98499957
switch (SetVariableFromAny(interp, nameObjPtr)) {
98509958
case JIM_DICT_SUGAR:
9851
-
9959
+
98529960
Jim_SetResultFormatted(interp, "bad variable name \"%#s\": upvar won't create a scalar variable that looks like an array element", nameObjPtr);
98539961
return JIM_ERR;
98549962
98559963
case JIM_OK:
98569964
varPtr = nameObjPtr->internalRep.varValue.varPtr;
@@ -9858,23 +9966,23 @@
98589966
if (varPtr->linkFramePtr == NULL) {
98599967
Jim_SetResultFormatted(interp, "variable \"%#s\" already exists", nameObjPtr);
98609968
return JIM_ERR;
98619969
}
98629970
9863
-
9971
+
98649972
varPtr->linkFramePtr = NULL;
98659973
break;
98669974
}
98679975
9868
-
9869
-
9976
+
9977
+
98709978
varName = Jim_String(nameObjPtr);
98719979
98729980
if (varName[0] == ':' && varName[1] == ':') {
98739981
while (*++varName == ':') {
98749982
}
9875
-
9983
+
98769984
framePtr = interp->topFramePtr;
98779985
}
98789986
else {
98799987
framePtr = interp->framePtr;
98809988
}
@@ -9894,15 +10002,15 @@
989410002
nameObjPtr);
989510003
Jim_DecrRefCount(interp, targetNameObjPtr);
989610004
return JIM_ERR;
989710005
}
989810006
9899
-
10007
+
990010008
if (framePtr == targetCallFrame) {
990110009
Jim_Obj *objPtr = targetNameObjPtr;
990210010
9903
-
10011
+
990410012
while (1) {
990510013
if (strcmp(Jim_String(objPtr), varName) == 0) {
990610014
Jim_SetResultString(interp, "can't upvar from variable to itself", -1);
990710015
Jim_DecrRefCount(interp, targetNameObjPtr);
990810016
return JIM_ERR;
@@ -9914,13 +10022,13 @@
991410022
break;
991510023
objPtr = varPtr->objPtr;
991610024
}
991710025
}
991810026
9919
-
10027
+
992010028
Jim_SetVariable(interp, nameObjPtr, targetNameObjPtr);
9921
-
10029
+
992210030
nameObjPtr->internalRep.varValue.varPtr->linkFramePtr = targetCallFrame;
992310031
Jim_DecrRefCount(interp, targetNameObjPtr);
992410032
return JIM_OK;
992510033
}
992610034
@@ -9934,26 +10042,26 @@
993410042
return varPtr->objPtr;
993510043
}
993610044
else {
993710045
Jim_Obj *objPtr;
993810046
9939
-
10047
+
994010048
Jim_CallFrame *savedCallFrame = interp->framePtr;
994110049
994210050
interp->framePtr = varPtr->linkFramePtr;
994310051
objPtr = Jim_GetVariable(interp, varPtr->objPtr, flags);
994410052
interp->framePtr = savedCallFrame;
994510053
if (objPtr) {
994610054
return objPtr;
994710055
}
9948
-
10056
+
994910057
}
995010058
}
995110059
break;
995210060
995310061
case JIM_DICT_SUGAR:
9954
-
10062
+
995510063
return JimDictSugarGet(interp, nameObjPtr, flags);
995610064
}
995710065
if (flags & JIM_ERRMSG) {
995810066
Jim_SetResultFormatted(interp, "can't read \"%#s\": no such variable", nameObjPtr);
995910067
}
@@ -10003,17 +10111,17 @@
1000310111
int retval;
1000410112
Jim_CallFrame *framePtr;
1000510113
1000610114
retval = SetVariableFromAny(interp, nameObjPtr);
1000710115
if (retval == JIM_DICT_SUGAR) {
10008
-
10116
+
1000910117
return JimDictSugarSet(interp, nameObjPtr, NULL);
1001010118
}
1001110119
else if (retval == JIM_OK) {
1001210120
varPtr = nameObjPtr->internalRep.varValue.varPtr;
1001310121
10014
-
10122
+
1001510123
if (varPtr->linkFramePtr) {
1001610124
framePtr = interp->framePtr;
1001710125
interp->framePtr = varPtr->linkFramePtr;
1001810126
retval = Jim_UnsetVariable(interp, varPtr->objPtr, JIM_NONE);
1001910127
interp->framePtr = framePtr;
@@ -10028,11 +10136,11 @@
1002810136
framePtr = interp->framePtr;
1002910137
}
1003010138
1003110139
retval = Jim_DeleteHashEntry(&framePtr->vars, name);
1003210140
if (retval == JIM_OK) {
10033
-
10141
+
1003410142
framePtr->id = interp->callFrameEpoch++;
1003510143
}
1003610144
}
1003710145
}
1003810146
if (retval != JIM_OK && (flags & JIM_ERRMSG)) {
@@ -10061,11 +10169,11 @@
1006110169
keyLen = (str + len) - p;
1006210170
if (str[len - 1] == ')') {
1006310171
keyLen--;
1006410172
}
1006510173
10066
-
10174
+
1006710175
keyObjPtr = Jim_NewStringObj(interp, p, keyLen);
1006810176
1006910177
Jim_IncrRefCount(varObjPtr);
1007010178
Jim_IncrRefCount(keyObjPtr);
1007110179
*varPtrPtr = varObjPtr;
@@ -10080,23 +10188,23 @@
1008010188
1008110189
err = Jim_SetDictKeysVector(interp, objPtr->internalRep.dictSubstValue.varNameObjPtr,
1008210190
&objPtr->internalRep.dictSubstValue.indexObjPtr, 1, valObjPtr, JIM_MUSTEXIST);
1008310191
1008410192
if (err == JIM_OK) {
10085
-
10193
+
1008610194
Jim_SetEmptyResult(interp);
1008710195
}
1008810196
else {
1008910197
if (!valObjPtr) {
10090
-
10198
+
1009110199
if (Jim_GetVariable(interp, objPtr->internalRep.dictSubstValue.varNameObjPtr, JIM_NONE)) {
1009210200
Jim_SetResultFormatted(interp, "can't unset \"%#s\": no such element in array",
1009310201
objPtr);
1009410202
return err;
1009510203
}
1009610204
}
10097
-
10205
+
1009810206
Jim_SetResultFormatted(interp, "can't %s \"%#s\": variable isn't array",
1009910207
(valObjPtr ? "set" : "unset"), objPtr);
1010010208
}
1010110209
return err;
1010210210
}
@@ -10118,11 +10226,11 @@
1011810226
Jim_SetResultFormatted(interp,
1011910227
"can't read \"%#s(%#s)\": %s array", varObjPtr, keyObjPtr,
1012010228
ret < 0 ? "variable isn't" : "no such element in");
1012110229
}
1012210230
else if ((flags & JIM_UNSHARED) && Jim_IsShared(dictObjPtr)) {
10123
-
10231
+
1012410232
Jim_SetVariable(interp, varObjPtr, Jim_DuplicateObj(interp, dictObjPtr));
1012510233
}
1012610234
1012710235
return resObjPtr;
1012810236
}
@@ -10143,28 +10251,27 @@
1014310251
{
1014410252
Jim_DecrRefCount(interp, objPtr->internalRep.dictSubstValue.varNameObjPtr);
1014510253
Jim_DecrRefCount(interp, objPtr->internalRep.dictSubstValue.indexObjPtr);
1014610254
}
1014710255
10148
-void DupDictSubstInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr)
10149
-{
10150
- JIM_NOTUSED(interp);
10151
-
10152
- dupPtr->internalRep.dictSubstValue.varNameObjPtr =
10153
- srcPtr->internalRep.dictSubstValue.varNameObjPtr;
10154
- dupPtr->internalRep.dictSubstValue.indexObjPtr = srcPtr->internalRep.dictSubstValue.indexObjPtr;
10155
- dupPtr->typePtr = &dictSubstObjType;
10256
+static void DupDictSubstInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr)
10257
+{
10258
+
10259
+ dupPtr->internalRep = srcPtr->internalRep;
10260
+
10261
+ Jim_IncrRefCount(dupPtr->internalRep.dictSubstValue.varNameObjPtr);
10262
+ Jim_IncrRefCount(dupPtr->internalRep.dictSubstValue.indexObjPtr);
1015610263
}
1015710264
1015810265
1015910266
static void SetDictSubstFromAny(Jim_Interp *interp, Jim_Obj *objPtr)
1016010267
{
1016110268
if (objPtr->typePtr != &dictSubstObjType) {
1016210269
Jim_Obj *varObjPtr, *keyObjPtr;
1016310270
1016410271
if (objPtr->typePtr == &interpolatedObjType) {
10165
-
10272
+
1016610273
1016710274
varObjPtr = objPtr->internalRep.dictSubstValue.varNameObjPtr;
1016810275
keyObjPtr = objPtr->internalRep.dictSubstValue.indexObjPtr;
1016910276
1017010277
Jim_IncrRefCount(varObjPtr);
@@ -10202,16 +10309,12 @@
1020210309
return resObjPtr;
1020310310
}
1020410311
1020510312
static Jim_Obj *JimExpandExprSugar(Jim_Interp *interp, Jim_Obj *objPtr)
1020610313
{
10207
- Jim_Obj *resultObjPtr;
10208
-
10209
- if (Jim_EvalExpression(interp, objPtr, &resultObjPtr) == JIM_OK) {
10210
-
10211
- resultObjPtr->refCount--;
10212
- return resultObjPtr;
10314
+ if (Jim_EvalExpression(interp, objPtr) == JIM_OK) {
10315
+ return Jim_GetResult(interp);
1021310316
}
1021410317
return NULL;
1021510318
}
1021610319
1021710320
@@ -10249,11 +10352,11 @@
1024910352
return cf;
1025010353
}
1025110354
1025210355
static int JimDeleteLocalProcs(Jim_Interp *interp, Jim_Stack *localCommands)
1025310356
{
10254
-
10357
+
1025510358
if (localCommands) {
1025610359
Jim_Obj *cmdNameObj;
1025710360
1025810361
while ((cmdNameObj = Jim_StackPop(localCommands)) != NULL) {
1025910362
Jim_HashEntry *he;
@@ -10268,20 +10371,20 @@
1026810371
Jim_Cmd *cmd = Jim_GetHashEntryVal(he);
1026910372
if (cmd->prevCmd) {
1027010373
Jim_Cmd *prevCmd = cmd->prevCmd;
1027110374
cmd->prevCmd = NULL;
1027210375
10273
-
10376
+
1027410377
JimDecrCmdRefCount(interp, cmd);
1027510378
10276
-
10379
+
1027710380
Jim_SetHashVal(ht, he, prevCmd);
1027810381
}
1027910382
else {
1028010383
Jim_DeleteHashEntry(ht, fqname);
10281
- Jim_InterpIncrProcEpoch(interp);
1028210384
}
10385
+ Jim_InterpIncrProcEpoch(interp);
1028310386
}
1028410387
Jim_DecrRefCount(interp, cmdNameObj);
1028510388
JimFreeQualifiedName(interp, fqObjName);
1028610389
}
1028710390
Jim_FreeStack(localCommands);
@@ -10288,13 +10391,59 @@
1028810391
Jim_Free(localCommands);
1028910392
}
1029010393
return JIM_OK;
1029110394
}
1029210395
10396
+static int JimInvokeDefer(Jim_Interp *interp, int retcode)
10397
+{
10398
+ Jim_Obj *objPtr;
1029310399
10294
-#define JIM_FCF_FULL 0
10295
-#define JIM_FCF_REUSE 1
10400
+
10401
+ if (Jim_FindHashEntry(&interp->framePtr->vars, "jim::defer") == NULL) {
10402
+ return retcode;
10403
+ }
10404
+
10405
+ objPtr = Jim_GetVariableStr(interp, "jim::defer", JIM_NONE);
10406
+
10407
+ if (objPtr) {
10408
+ int ret = JIM_OK;
10409
+ int i;
10410
+ int listLen = Jim_ListLength(interp, objPtr);
10411
+ Jim_Obj *resultObjPtr;
10412
+
10413
+ Jim_IncrRefCount(objPtr);
10414
+
10415
+ resultObjPtr = Jim_GetResult(interp);
10416
+ Jim_IncrRefCount(resultObjPtr);
10417
+ Jim_SetEmptyResult(interp);
10418
+
10419
+
10420
+ for (i = listLen; i > 0; i--) {
10421
+
10422
+ Jim_Obj *scriptObjPtr = Jim_ListGetIndex(interp, objPtr, i - 1);
10423
+ ret = Jim_EvalObj(interp, scriptObjPtr);
10424
+ if (ret != JIM_OK) {
10425
+ break;
10426
+ }
10427
+ }
10428
+
10429
+ if (ret == JIM_OK || retcode == JIM_ERR) {
10430
+
10431
+ Jim_SetResult(interp, resultObjPtr);
10432
+ }
10433
+ else {
10434
+ retcode = ret;
10435
+ }
10436
+
10437
+ Jim_DecrRefCount(interp, resultObjPtr);
10438
+ Jim_DecrRefCount(interp, objPtr);
10439
+ }
10440
+ return retcode;
10441
+}
10442
+
10443
+#define JIM_FCF_FULL 0
10444
+#define JIM_FCF_REUSE 1
1029610445
static void JimFreeCallFrame(Jim_Interp *interp, Jim_CallFrame *cf, int action)
1029710446
{
1029810447
JimDeleteLocalProcs(interp, cf->localCommands);
1029910448
1030010449
if (cf->procArgsObjPtr)
@@ -10327,263 +10476,10 @@
1032710476
cf->next = interp->freeFramesList;
1032810477
interp->freeFramesList = cf;
1032910478
}
1033010479
1033110480
10332
-#ifdef JIM_REFERENCES
10333
-
10334
-static void JimReferencesHTValDestructor(void *interp, void *val)
10335
-{
10336
- Jim_Reference *refPtr = (void *)val;
10337
-
10338
- Jim_DecrRefCount(interp, refPtr->objPtr);
10339
- if (refPtr->finalizerCmdNamePtr != NULL) {
10340
- Jim_DecrRefCount(interp, refPtr->finalizerCmdNamePtr);
10341
- }
10342
- Jim_Free(val);
10343
-}
10344
-
10345
-static unsigned int JimReferencesHTHashFunction(const void *key)
10346
-{
10347
-
10348
- const unsigned long *widePtr = key;
10349
- unsigned int intValue = (unsigned int)*widePtr;
10350
-
10351
- return Jim_IntHashFunction(intValue);
10352
-}
10353
-
10354
-static void *JimReferencesHTKeyDup(void *privdata, const void *key)
10355
-{
10356
- void *copy = Jim_Alloc(sizeof(unsigned long));
10357
-
10358
- JIM_NOTUSED(privdata);
10359
-
10360
- memcpy(copy, key, sizeof(unsigned long));
10361
- return copy;
10362
-}
10363
-
10364
-static int JimReferencesHTKeyCompare(void *privdata, const void *key1, const void *key2)
10365
-{
10366
- JIM_NOTUSED(privdata);
10367
-
10368
- return memcmp(key1, key2, sizeof(unsigned long)) == 0;
10369
-}
10370
-
10371
-static void JimReferencesHTKeyDestructor(void *privdata, void *key)
10372
-{
10373
- JIM_NOTUSED(privdata);
10374
-
10375
- Jim_Free(key);
10376
-}
10377
-
10378
-static const Jim_HashTableType JimReferencesHashTableType = {
10379
- JimReferencesHTHashFunction,
10380
- JimReferencesHTKeyDup,
10381
- NULL,
10382
- JimReferencesHTKeyCompare,
10383
- JimReferencesHTKeyDestructor,
10384
- JimReferencesHTValDestructor
10385
-};
10386
-
10387
-
10388
-
10389
-#define JIM_REFERENCE_SPACE (35+JIM_REFERENCE_TAGLEN)
10390
-
10391
-static int JimFormatReference(char *buf, Jim_Reference *refPtr, unsigned long id)
10392
-{
10393
- const char *fmt = "<reference.<%s>.%020lu>";
10394
-
10395
- sprintf(buf, fmt, refPtr->tag, id);
10396
- return JIM_REFERENCE_SPACE;
10397
-}
10398
-
10399
-static void UpdateStringOfReference(struct Jim_Obj *objPtr);
10400
-
10401
-static const Jim_ObjType referenceObjType = {
10402
- "reference",
10403
- NULL,
10404
- NULL,
10405
- UpdateStringOfReference,
10406
- JIM_TYPE_REFERENCES,
10407
-};
10408
-
10409
-static void UpdateStringOfReference(struct Jim_Obj *objPtr)
10410
-{
10411
- char buf[JIM_REFERENCE_SPACE + 1];
10412
-
10413
- JimFormatReference(buf, objPtr->internalRep.refValue.refPtr, objPtr->internalRep.refValue.id);
10414
- JimSetStringBytes(objPtr, buf);
10415
-}
10416
-
10417
-static int isrefchar(int c)
10418
-{
10419
- return (c == '_' || isalnum(c));
10420
-}
10421
-
10422
-static int SetReferenceFromAny(Jim_Interp *interp, Jim_Obj *objPtr)
10423
-{
10424
- unsigned long value;
10425
- int i, len;
10426
- const char *str, *start, *end;
10427
- char refId[21];
10428
- Jim_Reference *refPtr;
10429
- Jim_HashEntry *he;
10430
- char *endptr;
10431
-
10432
-
10433
- str = Jim_GetString(objPtr, &len);
10434
-
10435
- if (len < JIM_REFERENCE_SPACE)
10436
- goto badformat;
10437
-
10438
- start = str;
10439
- end = str + len - 1;
10440
- while (*start == ' ')
10441
- start++;
10442
- while (*end == ' ' && end > start)
10443
- end--;
10444
- if (end - start + 1 != JIM_REFERENCE_SPACE)
10445
- goto badformat;
10446
-
10447
- if (memcmp(start, "<reference.<", 12) != 0)
10448
- goto badformat;
10449
- if (start[12 + JIM_REFERENCE_TAGLEN] != '>' || end[0] != '>')
10450
- goto badformat;
10451
-
10452
- for (i = 0; i < JIM_REFERENCE_TAGLEN; i++) {
10453
- if (!isrefchar(start[12 + i]))
10454
- goto badformat;
10455
- }
10456
-
10457
- memcpy(refId, start + 14 + JIM_REFERENCE_TAGLEN, 20);
10458
- refId[20] = '\0';
10459
-
10460
- value = strtoul(refId, &endptr, 10);
10461
- if (JimCheckConversion(refId, endptr) != JIM_OK)
10462
- goto badformat;
10463
-
10464
- he = Jim_FindHashEntry(&interp->references, &value);
10465
- if (he == NULL) {
10466
- Jim_SetResultFormatted(interp, "invalid reference id \"%#s\"", objPtr);
10467
- return JIM_ERR;
10468
- }
10469
- refPtr = Jim_GetHashEntryVal(he);
10470
-
10471
- Jim_FreeIntRep(interp, objPtr);
10472
- objPtr->typePtr = &referenceObjType;
10473
- objPtr->internalRep.refValue.id = value;
10474
- objPtr->internalRep.refValue.refPtr = refPtr;
10475
- return JIM_OK;
10476
-
10477
- badformat:
10478
- Jim_SetResultFormatted(interp, "expected reference but got \"%#s\"", objPtr);
10479
- return JIM_ERR;
10480
-}
10481
-
10482
-Jim_Obj *Jim_NewReference(Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj *tagPtr, Jim_Obj *cmdNamePtr)
10483
-{
10484
- struct Jim_Reference *refPtr;
10485
- unsigned long id;
10486
- Jim_Obj *refObjPtr;
10487
- const char *tag;
10488
- int tagLen, i;
10489
-
10490
-
10491
- Jim_CollectIfNeeded(interp);
10492
-
10493
- refPtr = Jim_Alloc(sizeof(*refPtr));
10494
- refPtr->objPtr = objPtr;
10495
- Jim_IncrRefCount(objPtr);
10496
- refPtr->finalizerCmdNamePtr = cmdNamePtr;
10497
- if (cmdNamePtr)
10498
- Jim_IncrRefCount(cmdNamePtr);
10499
- id = interp->referenceNextId++;
10500
- Jim_AddHashEntry(&interp->references, &id, refPtr);
10501
- refObjPtr = Jim_NewObj(interp);
10502
- refObjPtr->typePtr = &referenceObjType;
10503
- refObjPtr->bytes = NULL;
10504
- refObjPtr->internalRep.refValue.id = id;
10505
- refObjPtr->internalRep.refValue.refPtr = refPtr;
10506
- interp->referenceNextId++;
10507
- tag = Jim_GetString(tagPtr, &tagLen);
10508
- if (tagLen > JIM_REFERENCE_TAGLEN)
10509
- tagLen = JIM_REFERENCE_TAGLEN;
10510
- for (i = 0; i < JIM_REFERENCE_TAGLEN; i++) {
10511
- if (i < tagLen && isrefchar(tag[i]))
10512
- refPtr->tag[i] = tag[i];
10513
- else
10514
- refPtr->tag[i] = '_';
10515
- }
10516
- refPtr->tag[JIM_REFERENCE_TAGLEN] = '\0';
10517
- return refObjPtr;
10518
-}
10519
-
10520
-Jim_Reference *Jim_GetReference(Jim_Interp *interp, Jim_Obj *objPtr)
10521
-{
10522
- if (objPtr->typePtr != &referenceObjType && SetReferenceFromAny(interp, objPtr) == JIM_ERR)
10523
- return NULL;
10524
- return objPtr->internalRep.refValue.refPtr;
10525
-}
10526
-
10527
-int Jim_SetFinalizer(Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj *cmdNamePtr)
10528
-{
10529
- Jim_Reference *refPtr;
10530
-
10531
- if ((refPtr = Jim_GetReference(interp, objPtr)) == NULL)
10532
- return JIM_ERR;
10533
- Jim_IncrRefCount(cmdNamePtr);
10534
- if (refPtr->finalizerCmdNamePtr)
10535
- Jim_DecrRefCount(interp, refPtr->finalizerCmdNamePtr);
10536
- refPtr->finalizerCmdNamePtr = cmdNamePtr;
10537
- return JIM_OK;
10538
-}
10539
-
10540
-int Jim_GetFinalizer(Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj **cmdNamePtrPtr)
10541
-{
10542
- Jim_Reference *refPtr;
10543
-
10544
- if ((refPtr = Jim_GetReference(interp, objPtr)) == NULL)
10545
- return JIM_ERR;
10546
- *cmdNamePtrPtr = refPtr->finalizerCmdNamePtr;
10547
- return JIM_OK;
10548
-}
10549
-
10550
-
10551
-
10552
-static const Jim_HashTableType JimRefMarkHashTableType = {
10553
- JimReferencesHTHashFunction,
10554
- JimReferencesHTKeyDup,
10555
- NULL,
10556
- JimReferencesHTKeyCompare,
10557
- JimReferencesHTKeyDestructor,
10558
- NULL
10559
-};
10560
-
10561
-
10562
-int Jim_Collect(Jim_Interp *interp)
10563
-{
10564
- int collected = 0;
10565
- return collected;
10566
-}
10567
-
10568
-#define JIM_COLLECT_ID_PERIOD 5000
10569
-#define JIM_COLLECT_TIME_PERIOD 300
10570
-
10571
-void Jim_CollectIfNeeded(Jim_Interp *interp)
10572
-{
10573
- unsigned long elapsedId;
10574
- int elapsedTime;
10575
-
10576
- elapsedId = interp->referenceNextId - interp->lastCollectId;
10577
- elapsedTime = time(NULL) - interp->lastCollectTime;
10578
-
10579
-
10580
- if (elapsedId > JIM_COLLECT_ID_PERIOD || elapsedTime > JIM_COLLECT_TIME_PERIOD) {
10581
- Jim_Collect(interp);
10582
- }
10583
-}
10584
-#endif
1058510481
1058610482
int Jim_IsBigEndian(void)
1058710483
{
1058810484
union {
1058910485
unsigned short s;
@@ -10630,11 +10526,11 @@
1063010526
Jim_IncrRefCount(i->nullScriptObj);
1063110527
Jim_IncrRefCount(i->errorProc);
1063210528
Jim_IncrRefCount(i->trueObj);
1063310529
Jim_IncrRefCount(i->falseObj);
1063410530
10635
-
10531
+
1063610532
Jim_SetVariableStrWithStr(i, JIM_LIBPATH, TCL_LIBRARY);
1063710533
Jim_SetVariableStrWithStr(i, JIM_INTERACTIVE, "0");
1063810534
1063910535
Jim_SetVariableStrWithStr(i, "tcl_platform(engine)", "Jim");
1064010536
Jim_SetVariableStrWithStr(i, "tcl_platform(os)", TCL_PLATFORM_OS);
@@ -10652,12 +10548,14 @@
1065210548
{
1065310549
Jim_CallFrame *cf, *cfx;
1065410550
1065510551
Jim_Obj *objPtr, *nextObjPtr;
1065610552
10657
-
10553
+
1065810554
for (cf = i->framePtr; cf; cf = cfx) {
10555
+
10556
+ JimInvokeDefer(i, JIM_OK);
1065910557
cfx = cf->parent;
1066010558
JimFreeCallFrame(i, cf, JIM_FCF_FULL);
1066110559
}
1066210560
1066310561
Jim_DecrRefCount(i, i->emptyObj);
@@ -10684,10 +10582,11 @@
1068410582
1068510583
printf("\n-------------------------------------\n");
1068610584
printf("Objects still in the free list:\n");
1068710585
while (objPtr) {
1068810586
const char *type = objPtr->typePtr ? objPtr->typePtr->name : "string";
10587
+ Jim_String(objPtr);
1068910588
1069010589
if (objPtr->bytes && strlen(objPtr->bytes) > 20) {
1069110590
printf("%p (%d) %-10s: '%.20s...'\n",
1069210591
(void *)objPtr, objPtr->refCount, type, objPtr->bytes);
1069310592
}
@@ -10705,27 +10604,27 @@
1070510604
printf("-------------------------------------\n\n");
1070610605
JimPanic((1, "Live list non empty freeing the interpreter! Leak?"));
1070710606
}
1070810607
#endif
1070910608
10710
-
10609
+
1071110610
objPtr = i->freeList;
1071210611
while (objPtr) {
1071310612
nextObjPtr = objPtr->nextObjPtr;
1071410613
Jim_Free(objPtr);
1071510614
objPtr = nextObjPtr;
1071610615
}
1071710616
10718
-
10617
+
1071910618
for (cf = i->freeFramesList; cf; cf = cfx) {
1072010619
cfx = cf->next;
1072110620
if (cf->vars.table)
1072210621
Jim_FreeHashTable(&cf->vars);
1072310622
Jim_Free(cf);
1072410623
}
1072510624
10726
-
10625
+
1072710626
Jim_Free(i);
1072810627
}
1072910628
1073010629
Jim_CallFrame *Jim_GetCallFrameByLevel(Jim_Interp *interp, Jim_Obj *levelObjPtr)
1073110630
{
@@ -10746,25 +10645,25 @@
1074610645
else {
1074710646
if (Jim_GetLong(interp, levelObjPtr, &level) != JIM_OK || level < 0) {
1074810647
level = -1;
1074910648
}
1075010649
else {
10751
-
10650
+
1075210651
level = interp->framePtr->level - level;
1075310652
}
1075410653
}
1075510654
}
1075610655
else {
10757
- str = "1";
10656
+ str = "1";
1075810657
level = interp->framePtr->level - 1;
1075910658
}
1076010659
1076110660
if (level == 0) {
1076210661
return interp->topFramePtr;
1076310662
}
1076410663
if (level > 0) {
10765
-
10664
+
1076610665
for (framePtr = interp->framePtr; framePtr; framePtr = framePtr->parent) {
1076710666
if (framePtr->level == level) {
1076810667
return framePtr;
1076910668
}
1077010669
}
@@ -10779,19 +10678,19 @@
1077910678
long level;
1078010679
Jim_CallFrame *framePtr;
1078110680
1078210681
if (Jim_GetLong(interp, levelObjPtr, &level) == JIM_OK) {
1078310682
if (level <= 0) {
10784
-
10683
+
1078510684
level = interp->framePtr->level + level;
1078610685
}
1078710686
1078810687
if (level == 0) {
1078910688
return interp->topFramePtr;
1079010689
}
1079110690
10792
-
10691
+
1079310692
for (framePtr = interp->framePtr; framePtr; framePtr = framePtr->parent) {
1079410693
if (framePtr->level == level) {
1079510694
return framePtr;
1079610695
}
1079710696
}
@@ -10810,11 +10709,11 @@
1081010709
1081110710
static void JimSetStackTrace(Jim_Interp *interp, Jim_Obj *stackTraceObj)
1081210711
{
1081310712
int len;
1081410713
10815
-
10714
+
1081610715
Jim_IncrRefCount(stackTraceObj);
1081710716
Jim_DecrRefCount(interp, interp->stackTrace);
1081810717
interp->stackTrace = stackTraceObj;
1081910718
interp->errorFlag = 1;
1082010719
@@ -10831,32 +10730,32 @@
1083110730
{
1083210731
if (strcmp(procname, "unknown") == 0) {
1083310732
procname = "";
1083410733
}
1083510734
if (!*procname && !Jim_Length(fileNameObj)) {
10836
-
10735
+
1083710736
return;
1083810737
}
1083910738
1084010739
if (Jim_IsShared(interp->stackTrace)) {
1084110740
Jim_DecrRefCount(interp, interp->stackTrace);
1084210741
interp->stackTrace = Jim_DuplicateObj(interp, interp->stackTrace);
1084310742
Jim_IncrRefCount(interp->stackTrace);
1084410743
}
1084510744
10846
-
10745
+
1084710746
if (!*procname && Jim_Length(fileNameObj)) {
10848
-
10747
+
1084910748
int len = Jim_ListLength(interp, interp->stackTrace);
1085010749
1085110750
if (len >= 3) {
1085210751
Jim_Obj *objPtr = Jim_ListGetIndex(interp, interp->stackTrace, len - 3);
1085310752
if (Jim_Length(objPtr)) {
10854
-
10753
+
1085510754
objPtr = Jim_ListGetIndex(interp, interp->stackTrace, len - 2);
1085610755
if (Jim_Length(objPtr) == 0) {
10857
-
10756
+
1085810757
ListSetIndex(interp, interp->stackTrace, len - 2, fileNameObj, 0);
1085910758
ListSetIndex(interp, interp->stackTrace, len - 1, Jim_NewIntObj(interp, linenr), 0);
1086010759
return;
1086110760
}
1086210761
}
@@ -10958,18 +10857,18 @@
1095810857
{
1095910858
jim_wide wideValue;
1096010859
const char *str;
1096110860
1096210861
if (objPtr->typePtr == &coercedDoubleObjType) {
10963
-
10862
+
1096410863
objPtr->typePtr = &intObjType;
1096510864
return JIM_OK;
1096610865
}
1096710866
10968
-
10867
+
1096910868
str = Jim_String(objPtr);
10970
-
10869
+
1097110870
if (Jim_StringToWide(str, &wideValue, 0) != JIM_OK) {
1097210871
if (flags & JIM_ERRMSG) {
1097310872
Jim_SetResultFormatted(interp, "expected integer but got \"%#s\"", objPtr);
1097410873
}
1097510874
return JIM_ERR;
@@ -10976,11 +10875,11 @@
1097610875
}
1097710876
if ((wideValue == JIM_WIDE_MIN || wideValue == JIM_WIDE_MAX) && errno == ERANGE) {
1097810877
Jim_SetResultString(interp, "Integer value too big to be represented", -1);
1097910878
return JIM_ERR;
1098010879
}
10981
-
10880
+
1098210881
Jim_FreeIntRep(interp, objPtr);
1098310882
objPtr->typePtr = &intObjType;
1098410883
objPtr->internalRep.wideValue = wideValue;
1098510884
return JIM_OK;
1098610885
}
@@ -11075,17 +10974,17 @@
1107510974
{
1107610975
char buf[JIM_DOUBLE_SPACE + 1];
1107710976
int i;
1107810977
int len = sprintf(buf, "%.12g", value);
1107910978
11080
-
10979
+
1108110980
for (i = 0; i < len; i++) {
1108210981
if (buf[i] == '.' || buf[i] == 'e') {
1108310982
#if defined(JIM_SPRINTF_DOUBLE_NEEDS_FIX)
1108410983
char *e = strchr(buf, 'e');
1108510984
if (e && (e[1] == '-' || e[1] == '+') && e[2] == '0') {
11086
-
10985
+
1108710986
e += 2;
1108810987
memmove(e, e + 1, len - (e - buf));
1108910988
}
1109010989
#endif
1109110990
break;
@@ -11104,41 +11003,40 @@
1110411003
{
1110511004
double doubleValue;
1110611005
jim_wide wideValue;
1110711006
const char *str;
1110811007
11109
- str = Jim_String(objPtr);
11110
-
1111111008
#ifdef HAVE_LONG_LONG
11112
-
11009
+
1111311010
#define MIN_INT_IN_DOUBLE -(1LL << 53)
1111411011
#define MAX_INT_IN_DOUBLE -(MIN_INT_IN_DOUBLE + 1)
1111511012
1111611013
if (objPtr->typePtr == &intObjType
1111711014
&& JimWideValue(objPtr) >= MIN_INT_IN_DOUBLE
1111811015
&& JimWideValue(objPtr) <= MAX_INT_IN_DOUBLE) {
1111911016
11120
-
11017
+
1112111018
objPtr->typePtr = &coercedDoubleObjType;
1112211019
return JIM_OK;
1112311020
}
11124
- else
1112511021
#endif
11022
+ str = Jim_String(objPtr);
11023
+
1112611024
if (Jim_StringToWide(str, &wideValue, 10) == JIM_OK) {
11127
-
11025
+
1112811026
Jim_FreeIntRep(interp, objPtr);
1112911027
objPtr->typePtr = &coercedDoubleObjType;
1113011028
objPtr->internalRep.wideValue = wideValue;
1113111029
return JIM_OK;
1113211030
}
1113311031
else {
11134
-
11032
+
1113511033
if (Jim_StringToDouble(str, &doubleValue) != JIM_OK) {
1113611034
Jim_SetResultFormatted(interp, "expected floating-point number but got \"%#s\"", objPtr);
1113711035
return JIM_ERR;
1113811036
}
11139
-
11037
+
1114011038
Jim_FreeIntRep(interp, objPtr);
1114111039
}
1114211040
objPtr->typePtr = &doubleObjType;
1114311041
objPtr->internalRep.doubleValue = doubleValue;
1114411042
return JIM_OK;
@@ -11170,10 +11068,50 @@
1117011068
objPtr->typePtr = &doubleObjType;
1117111069
objPtr->bytes = NULL;
1117211070
objPtr->internalRep.doubleValue = doubleValue;
1117311071
return objPtr;
1117411072
}
11073
+
11074
+static int SetBooleanFromAny(Jim_Interp *interp, Jim_Obj *objPtr, int flags);
11075
+
11076
+int Jim_GetBoolean(Jim_Interp *interp, Jim_Obj *objPtr, int * booleanPtr)
11077
+{
11078
+ if (objPtr->typePtr != &intObjType && SetBooleanFromAny(interp, objPtr, JIM_ERRMSG) == JIM_ERR)
11079
+ return JIM_ERR;
11080
+ *booleanPtr = (int) JimWideValue(objPtr);
11081
+ return JIM_OK;
11082
+}
11083
+
11084
+static int SetBooleanFromAny(Jim_Interp *interp, Jim_Obj *objPtr, int flags)
11085
+{
11086
+ static const char * const falses[] = {
11087
+ "0", "false", "no", "off", NULL
11088
+ };
11089
+ static const char * const trues[] = {
11090
+ "1", "true", "yes", "on", NULL
11091
+ };
11092
+
11093
+ int boolean;
11094
+
11095
+ int index;
11096
+ if (Jim_GetEnum(interp, objPtr, falses, &index, NULL, 0) == JIM_OK) {
11097
+ boolean = 0;
11098
+ } else if (Jim_GetEnum(interp, objPtr, trues, &index, NULL, 0) == JIM_OK) {
11099
+ boolean = 1;
11100
+ } else {
11101
+ if (flags & JIM_ERRMSG) {
11102
+ Jim_SetResultFormatted(interp, "expected boolean but got \"%#s\"", objPtr);
11103
+ }
11104
+ return JIM_ERR;
11105
+ }
11106
+
11107
+
11108
+ Jim_FreeIntRep(interp, objPtr);
11109
+ objPtr->typePtr = &intObjType;
11110
+ objPtr->internalRep.wideValue = boolean;
11111
+ return JIM_OK;
11112
+}
1117511113
1117611114
static void ListInsertElements(Jim_Obj *listPtr, int idx, int elemc, Jim_Obj *const *elemVec);
1117711115
static void ListAppendElement(Jim_Obj *listPtr, Jim_Obj *objPtr);
1117811116
static void FreeListInternalRep(Jim_Interp *interp, Jim_Obj *objPtr);
1117911117
static void DupListInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr);
@@ -11221,11 +11159,11 @@
1122111159
#define JIM_ELESTR_QUOTE 2
1122211160
static unsigned char ListElementQuotingType(const char *s, int len)
1122311161
{
1122411162
int i, level, blevel, trySimple = 1;
1122511163
11226
-
11164
+
1122711165
if (len == 0)
1122811166
return JIM_ELESTR_BRACE;
1122911167
if (s[0] == '"' || s[0] == '{') {
1123011168
trySimple = 0;
1123111169
goto testbrace;
@@ -11243,20 +11181,20 @@
1124311181
case '\n':
1124411182
case '\t':
1124511183
case '\f':
1124611184
case '\v':
1124711185
trySimple = 0;
11248
-
11186
+
1124911187
case '{':
1125011188
case '}':
1125111189
goto testbrace;
1125211190
}
1125311191
}
1125411192
return JIM_ELESTR_SIMPLE;
1125511193
1125611194
testbrace:
11257
-
11195
+
1125811196
if (s[len - 1] == '\\')
1125911197
return JIM_ELESTR_QUOTE;
1126011198
level = 0;
1126111199
blevel = 0;
1126211200
for (i = 0; i < len; i++) {
@@ -11372,11 +11310,11 @@
1137211310
int i, bufLen, realLength;
1137311311
const char *strRep;
1137411312
char *p;
1137511313
unsigned char *quotingType, staticQuoting[STATIC_QUOTING_LEN];
1137611314
11377
-
11315
+
1137811316
if (objc > STATIC_QUOTING_LEN) {
1137911317
quotingType = Jim_Alloc(objc);
1138011318
}
1138111319
else {
1138211320
quotingType = staticQuoting;
@@ -11391,25 +11329,25 @@
1139111329
case JIM_ELESTR_SIMPLE:
1139211330
if (i != 0 || strRep[0] != '#') {
1139311331
bufLen += len;
1139411332
break;
1139511333
}
11396
-
11334
+
1139711335
quotingType[i] = JIM_ELESTR_BRACE;
11398
-
11336
+
1139911337
case JIM_ELESTR_BRACE:
1140011338
bufLen += len + 2;
1140111339
break;
1140211340
case JIM_ELESTR_QUOTE:
1140311341
bufLen += len * 2;
1140411342
break;
1140511343
}
11406
- bufLen++;
11344
+ bufLen++;
1140711345
}
1140811346
bufLen++;
1140911347
11410
-
11348
+
1141111349
p = objPtr->bytes = Jim_Alloc(bufLen + 1);
1141211350
realLength = 0;
1141311351
for (i = 0; i < objc; i++) {
1141411352
int len, qlen;
1141511353
@@ -11436,17 +11374,17 @@
1143611374
qlen = BackslashQuoteString(strRep, len, p);
1143711375
p += qlen;
1143811376
realLength += qlen;
1143911377
break;
1144011378
}
11441
-
11379
+
1144211380
if (i + 1 != objc) {
1144311381
*p++ = ' ';
1144411382
realLength++;
1144511383
}
1144611384
}
11447
- *p = '\0';
11385
+ *p = '\0';
1144811386
objPtr->length = realLength;
1144911387
1145011388
if (quotingType != staticQuoting) {
1145111389
Jim_Free(quotingType);
1145211390
}
@@ -11477,21 +11415,21 @@
1147711415
listObjPtrPtr = JimDictPairs(objPtr, &len);
1147811416
for (i = 0; i < len; i++) {
1147911417
Jim_IncrRefCount(listObjPtrPtr[i]);
1148011418
}
1148111419
11482
-
11420
+
1148311421
Jim_FreeIntRep(interp, objPtr);
1148411422
objPtr->typePtr = &listObjType;
1148511423
objPtr->internalRep.listValue.len = len;
1148611424
objPtr->internalRep.listValue.maxLen = len;
1148711425
objPtr->internalRep.listValue.ele = listObjPtrPtr;
1148811426
1148911427
return JIM_OK;
1149011428
}
1149111429
11492
-
11430
+
1149311431
if (objPtr->typePtr == &sourceObjType) {
1149411432
fileNameObj = objPtr->internalRep.sourceValue.fileNameObj;
1149511433
linenr = objPtr->internalRep.sourceValue.lineNumber;
1149611434
}
1149711435
else {
@@ -11498,20 +11436,20 @@
1149811436
fileNameObj = interp->emptyObj;
1149911437
linenr = 1;
1150011438
}
1150111439
Jim_IncrRefCount(fileNameObj);
1150211440
11503
-
11441
+
1150411442
str = Jim_GetString(objPtr, &strLen);
1150511443
1150611444
Jim_FreeIntRep(interp, objPtr);
1150711445
objPtr->typePtr = &listObjType;
1150811446
objPtr->internalRep.listValue.len = 0;
1150911447
objPtr->internalRep.listValue.maxLen = 0;
1151011448
objPtr->internalRep.listValue.ele = NULL;
1151111449
11512
-
11450
+
1151311451
if (strLen) {
1151411452
JimParserInit(&parser, str, strLen, linenr);
1151511453
while (!parser.eof) {
1151611454
Jim_Obj *elementPtr;
1151711455
@@ -11641,11 +11579,11 @@
1164111579
Jim_Obj *compare_script;
1164211580
int rc;
1164311581
1164411582
jim_wide ret = 0;
1164511583
11646
-
11584
+
1164711585
compare_script = Jim_DuplicateObj(sort_info->interp, sort_info->command);
1164811586
Jim_ListAppendElement(sort_info->interp, compare_script, *lhsObj);
1164911587
Jim_ListAppendElement(sort_info->interp, compare_script, *rhsObj);
1165011588
1165111589
rc = Jim_EvalObj(sort_info->interp, compare_script);
@@ -11663,23 +11601,27 @@
1166311601
int dst = 0;
1166411602
Jim_Obj **ele = listObjPtr->internalRep.listValue.ele;
1166511603
1166611604
for (src = 1; src < listObjPtr->internalRep.listValue.len; src++) {
1166711605
if (comp(&ele[dst], &ele[src]) == 0) {
11668
-
11606
+
1166911607
Jim_DecrRefCount(sort_info->interp, ele[dst]);
1167011608
}
1167111609
else {
11672
-
11610
+
1167311611
dst++;
1167411612
}
1167511613
ele[dst] = ele[src];
1167611614
}
11677
-
11678
- ele[++dst] = ele[src];
1167911615
11680
-
11616
+
11617
+ dst++;
11618
+ if (dst < listObjPtr->internalRep.listValue.len) {
11619
+ ele[dst] = ele[src];
11620
+ }
11621
+
11622
+
1168111623
listObjPtr->internalRep.listValue.len = dst;
1168211624
}
1168311625
1168411626
1168511627
static int ListSortElements(Jim_Interp *interp, Jim_Obj *listObjPtr, struct lsort_info *info)
@@ -11693,11 +11635,11 @@
1169311635
int rc;
1169411636
1169511637
JimPanic((Jim_IsShared(listObjPtr), "ListSortElements called with shared object"));
1169611638
SetListFromAny(interp, listObjPtr);
1169711639
11698
-
11640
+
1169911641
prev_info = sort_info;
1170011642
sort_info = info;
1170111643
1170211644
vector = listObjPtr->internalRep.listValue.ele;
1170311645
len = listObjPtr->internalRep.listValue.len;
@@ -11716,17 +11658,17 @@
1171611658
break;
1171711659
case JIM_LSORT_COMMAND:
1171811660
fn = ListSortCommand;
1171911661
break;
1172011662
default:
11721
- fn = NULL;
11663
+ fn = NULL;
1172211664
JimPanic((1, "ListSort called with invalid sort type"));
11723
- return -1;
11665
+ return -1;
1172411666
}
1172511667
1172611668
if (info->indexed) {
11727
-
11669
+
1172811670
info->subfn = fn;
1172911671
fn = ListSortIndexHelper;
1173011672
}
1173111673
1173211674
if ((rc = setjmp(info->jmpbuf)) == 0) {
@@ -11750,11 +11692,11 @@
1175011692
int i;
1175111693
Jim_Obj **point;
1175211694
1175311695
if (requiredLen > listPtr->internalRep.listValue.maxLen) {
1175411696
if (requiredLen < 2) {
11755
-
11697
+
1175611698
requiredLen = 4;
1175711699
}
1175811700
else {
1175911701
requiredLen *= 2;
1176011702
}
@@ -11936,34 +11878,34 @@
1193611878
for (i = 0; i < objc; i++)
1193711879
ListAppendList(objPtr, objv[i]);
1193811880
return objPtr;
1193911881
}
1194011882
else {
11941
-
11883
+
1194211884
int len = 0, objLen;
1194311885
char *bytes, *p;
1194411886
11945
-
11887
+
1194611888
for (i = 0; i < objc; i++) {
1194711889
len += Jim_Length(objv[i]);
1194811890
}
1194911891
if (objc)
1195011892
len += objc - 1;
11951
-
11893
+
1195211894
p = bytes = Jim_Alloc(len + 1);
1195311895
for (i = 0; i < objc; i++) {
1195411896
const char *s = Jim_GetString(objv[i], &objLen);
1195511897
11956
-
11898
+
1195711899
while (objLen && isspace(UCHAR(*s))) {
1195811900
s++;
1195911901
objLen--;
1196011902
len--;
1196111903
}
11962
-
11904
+
1196311905
while (objLen && isspace(UCHAR(s[objLen - 1]))) {
11964
-
11906
+
1196511907
if (objLen > 1 && s[objLen - 2] == '\\') {
1196611908
break;
1196711909
}
1196811910
objLen--;
1196911911
len--;
@@ -11990,11 +11932,11 @@
1199011932
int len, rangeLen;
1199111933
1199211934
if (Jim_GetIndex(interp, firstObjPtr, &first) != JIM_OK ||
1199311935
Jim_GetIndex(interp, lastObjPtr, &last) != JIM_OK)
1199411936
return NULL;
11995
- len = Jim_ListLength(interp, listObjPtr);
11937
+ len = Jim_ListLength(interp, listObjPtr);
1199611938
first = JimRelToAbsIndex(len, first);
1199711939
last = JimRelToAbsIndex(len, last);
1199811940
JimRelToAbsRange(len, &first, &last, &rangeLen);
1199911941
if (first == 0 && last == len) {
1200011942
return listObjPtr;
@@ -12030,16 +11972,16 @@
1203011972
{
1203111973
Jim_DecrRefCount(interp, (Jim_Obj *)val);
1203211974
}
1203311975
1203411976
static const Jim_HashTableType JimDictHashTableType = {
12035
- JimObjectHTHashFunction,
12036
- JimObjectHTKeyValDup,
12037
- JimObjectHTKeyValDup,
12038
- JimObjectHTKeyCompare,
12039
- JimObjectHTKeyValDestructor,
12040
- JimObjectHTKeyValDestructor
11977
+ JimObjectHTHashFunction,
11978
+ JimObjectHTKeyValDup,
11979
+ JimObjectHTKeyValDup,
11980
+ JimObjectHTKeyCompare,
11981
+ JimObjectHTKeyValDestructor,
11982
+ JimObjectHTKeyValDestructor
1204111983
};
1204211984
1204311985
static const Jim_ObjType dictObjType = {
1204411986
"dict",
1204511987
FreeDictInternalRep,
@@ -12060,17 +12002,17 @@
1206012002
{
1206112003
Jim_HashTable *ht, *dupHt;
1206212004
Jim_HashTableIterator htiter;
1206312005
Jim_HashEntry *he;
1206412006
12065
-
12007
+
1206612008
ht = srcPtr->internalRep.ptr;
1206712009
dupHt = Jim_Alloc(sizeof(*dupHt));
1206812010
Jim_InitHashTable(dupHt, &JimDictHashTableType, interp);
1206912011
if (ht->size != 0)
1207012012
Jim_ExpandHashTable(dupHt, ht->size);
12071
-
12013
+
1207212014
JimInitHashTableIterator(ht, &htiter);
1207312015
while ((he = Jim_NextHashEntry(&htiter)) != NULL) {
1207412016
Jim_AddHashEntry(dupHt, he->key, he->u.val);
1207512017
}
1207612018
@@ -12086,11 +12028,11 @@
1208612028
Jim_Obj **objv;
1208712029
int i;
1208812030
1208912031
ht = dictPtr->internalRep.ptr;
1209012032
12091
-
12033
+
1209212034
objv = Jim_Alloc((ht->used * 2) * sizeof(Jim_Obj *));
1209312035
JimInitHashTableIterator(ht, &htiter);
1209412036
i = 0;
1209512037
while ((he = Jim_NextHashEntry(&htiter)) != NULL) {
1209612038
objv[i++] = Jim_GetHashEntryKey(he);
@@ -12100,15 +12042,15 @@
1210012042
return objv;
1210112043
}
1210212044
1210312045
static void UpdateStringOfDict(struct Jim_Obj *objPtr)
1210412046
{
12105
-
12047
+
1210612048
int len;
1210712049
Jim_Obj **objv = JimDictPairs(objPtr, &len);
1210812050
12109
-
12051
+
1211012052
JimMakeListStringRep(objPtr, objv, len);
1211112053
1211212054
Jim_Free(objv);
1211312055
}
1211412056
@@ -12122,18 +12064,18 @@
1212212064
1212312065
if (Jim_IsList(objPtr) && Jim_IsShared(objPtr)) {
1212412066
Jim_String(objPtr);
1212512067
}
1212612068
12127
-
12069
+
1212812070
listlen = Jim_ListLength(interp, objPtr);
1212912071
if (listlen % 2) {
1213012072
Jim_SetResultString(interp, "missing value to go with key", -1);
1213112073
return JIM_ERR;
1213212074
}
1213312075
else {
12134
-
12076
+
1213512077
Jim_HashTable *ht;
1213612078
int i;
1213712079
1213812080
ht = Jim_Alloc(sizeof(*ht));
1213912081
Jim_InitHashTable(ht, &JimDictHashTableType, interp);
@@ -12158,11 +12100,11 @@
1215812100
static int DictAddElement(Jim_Interp *interp, Jim_Obj *objPtr,
1215912101
Jim_Obj *keyObjPtr, Jim_Obj *valueObjPtr)
1216012102
{
1216112103
Jim_HashTable *ht = objPtr->internalRep.ptr;
1216212104
12163
- if (valueObjPtr == NULL) {
12105
+ if (valueObjPtr == NULL) {
1216412106
return Jim_DeleteHashEntry(ht, keyObjPtr);
1216512107
}
1216612108
Jim_ReplaceHashEntry(ht, keyObjPtr, valueObjPtr);
1216712109
return JIM_OK;
1216812110
}
@@ -12209,12 +12151,14 @@
1220912151
if (flags & JIM_ERRMSG) {
1221012152
Jim_SetResultFormatted(interp, "key \"%#s\" not known in dictionary", keyPtr);
1221112153
}
1221212154
return JIM_ERR;
1221312155
}
12214
- *objPtrPtr = he->u.val;
12215
- return JIM_OK;
12156
+ else {
12157
+ *objPtrPtr = Jim_GetHashEntryVal(he);
12158
+ return JIM_OK;
12159
+ }
1221612160
}
1221712161
1221812162
1221912163
int Jim_DictPairs(Jim_Interp *interp, Jim_Obj *dictPtr, Jim_Obj ***objPtrPtr, int *len)
1222012164
{
@@ -12258,11 +12202,11 @@
1225812202
int shared, i;
1225912203
1226012204
varObjPtr = objPtr = Jim_GetVariable(interp, varNamePtr, flags);
1226112205
if (objPtr == NULL) {
1226212206
if (newObjPtr == NULL && (flags & JIM_MUSTEXIST)) {
12263
-
12207
+
1226412208
return JIM_ERR;
1226512209
}
1226612210
varObjPtr = objPtr = Jim_NewDictObj(interp, NULL, 0);
1226712211
if (Jim_SetVariable(interp, varNamePtr, objPtr) != JIM_OK) {
1226812212
Jim_FreeNewObj(interp, varObjPtr);
@@ -12272,26 +12216,26 @@
1227212216
if ((shared = Jim_IsShared(objPtr)))
1227312217
varObjPtr = objPtr = Jim_DuplicateObj(interp, objPtr);
1227412218
for (i = 0; i < keyc; i++) {
1227512219
dictObjPtr = objPtr;
1227612220
12277
-
12221
+
1227812222
if (SetDictFromAny(interp, dictObjPtr) != JIM_OK) {
1227912223
goto err;
1228012224
}
1228112225
1228212226
if (i == keyc - 1) {
12283
-
12227
+
1228412228
if (Jim_DictAddElement(interp, objPtr, keyv[keyc - 1], newObjPtr) != JIM_OK) {
1228512229
if (newObjPtr || (flags & JIM_MUSTEXIST)) {
1228612230
goto err;
1228712231
}
1228812232
}
1228912233
break;
1229012234
}
1229112235
12292
-
12236
+
1229312237
Jim_InvalidateStringRep(dictObjPtr);
1229412238
if (Jim_DictKey(interp, dictObjPtr, keyv[i], &objPtr,
1229512239
newObjPtr ? JIM_NONE : JIM_ERRMSG) == JIM_OK) {
1229612240
if (Jim_IsShared(objPtr)) {
1229712241
objPtr = Jim_DuplicateObj(interp, objPtr);
@@ -12304,11 +12248,11 @@
1230412248
}
1230512249
objPtr = Jim_NewDictObj(interp, NULL, 0);
1230612250
DictAddElement(interp, dictObjPtr, keyv[i], objPtr);
1230712251
}
1230812252
}
12309
-
12253
+
1231012254
Jim_InvalidateStringRep(objPtr);
1231112255
Jim_InvalidateStringRep(varObjPtr);
1231212256
if (Jim_SetVariable(interp, varNamePtr, varObjPtr) != JIM_OK) {
1231312257
goto err;
1231412258
}
@@ -12341,11 +12285,11 @@
1234112285
char buf[JIM_INTEGER_SPACE + 1];
1234212286
if (objPtr->internalRep.intValue >= 0) {
1234312287
sprintf(buf, "%d", objPtr->internalRep.intValue);
1234412288
}
1234512289
else {
12346
-
12290
+
1234712291
sprintf(buf, "end%d", objPtr->internalRep.intValue + 1);
1234812292
}
1234912293
JimSetStringBytes(objPtr, buf);
1235012294
}
1235112295
}
@@ -12354,14 +12298,14 @@
1235412298
{
1235512299
int idx, end = 0;
1235612300
const char *str;
1235712301
char *endptr;
1235812302
12359
-
12303
+
1236012304
str = Jim_String(objPtr);
1236112305
12362
-
12306
+
1236312307
if (strncmp(str, "end", 3) == 0) {
1236412308
end = 1;
1236512309
str += 3;
1236612310
idx = 0;
1236712311
}
@@ -12372,21 +12316,21 @@
1237212316
goto badindex;
1237312317
}
1237412318
str = endptr;
1237512319
}
1237612320
12377
-
12321
+
1237812322
if (*str == '+' || *str == '-') {
1237912323
int sign = (*str == '+' ? 1 : -1);
1238012324
1238112325
idx += sign * jim_strtol(++str, &endptr);
1238212326
if (str == endptr || *endptr) {
1238312327
goto badindex;
1238412328
}
1238512329
str = endptr;
1238612330
}
12387
-
12331
+
1238812332
while (isspace(UCHAR(*str))) {
1238912333
str++;
1239012334
}
1239112335
if (*str) {
1239212336
goto badindex;
@@ -12394,19 +12338,19 @@
1239412338
if (end) {
1239512339
if (idx > 0) {
1239612340
idx = INT_MAX;
1239712341
}
1239812342
else {
12399
-
12343
+
1240012344
idx--;
1240112345
}
1240212346
}
1240312347
else if (idx < 0) {
1240412348
idx = -INT_MAX;
1240512349
}
1240612350
12407
-
12351
+
1240812352
Jim_FreeIntRep(interp, objPtr);
1240912353
objPtr->typePtr = &indexObjType;
1241012354
objPtr->internalRep.intValue = idx;
1241112355
return JIM_OK;
1241212356
@@ -12416,11 +12360,11 @@
1241612360
return JIM_ERR;
1241712361
}
1241812362
1241912363
int Jim_GetIndex(Jim_Interp *interp, Jim_Obj *objPtr, int *indexPtr)
1242012364
{
12421
-
12365
+
1242212366
if (objPtr->typePtr == &intObjType) {
1242312367
jim_wide val = JimWideValue(objPtr);
1242412368
1242512369
if (val < 0)
1242612370
*indexPtr = -INT_MAX;
@@ -12448,11 +12392,11 @@
1244812392
"exit",
1244912393
"eval",
1245012394
NULL
1245112395
};
1245212396
12453
-#define jimReturnCodesSize (sizeof(jimReturnCodes)/sizeof(*jimReturnCodes))
12397
+#define jimReturnCodesSize (sizeof(jimReturnCodes)/sizeof(*jimReturnCodes) - 1)
1245412398
1245512399
static const Jim_ObjType returnCodeObjType = {
1245612400
"return-code",
1245712401
NULL,
1245812402
NULL,
@@ -12473,18 +12417,18 @@
1247312417
static int SetReturnCodeFromAny(Jim_Interp *interp, Jim_Obj *objPtr)
1247412418
{
1247512419
int returnCode;
1247612420
jim_wide wideValue;
1247712421
12478
-
12422
+
1247912423
if (JimGetWideNoErr(interp, objPtr, &wideValue) != JIM_ERR)
1248012424
returnCode = (int)wideValue;
1248112425
else if (Jim_GetEnum(interp, objPtr, jimReturnCodes, &returnCode, NULL, JIM_NONE) != JIM_OK) {
1248212426
Jim_SetResultFormatted(interp, "expected return code but got \"%#s\"", objPtr);
1248312427
return JIM_ERR;
1248412428
}
12485
-
12429
+
1248612430
Jim_FreeIntRep(interp, objPtr);
1248712431
objPtr->typePtr = &returnCodeObjType;
1248812432
objPtr->internalRep.intValue = returnCode;
1248912433
return JIM_OK;
1249012434
}
@@ -12498,19 +12442,19 @@
1249812442
}
1249912443
1250012444
static int JimParseExprOperator(struct JimParserCtx *pc);
1250112445
static int JimParseExprNumber(struct JimParserCtx *pc);
1250212446
static int JimParseExprIrrational(struct JimParserCtx *pc);
12503
-
12504
-
12447
+static int JimParseExprBoolean(struct JimParserCtx *pc);
1250512448
1250612449
1250712450
enum
1250812451
{
12509
-
12510
-
12511
- JIM_EXPROP_MUL = JIM_TT_EXPR_OP,
12452
+
12453
+
12454
+
12455
+ JIM_EXPROP_MUL = JIM_TT_EXPR_OP,
1251212456
JIM_EXPROP_DIV,
1251312457
JIM_EXPROP_MOD,
1251412458
JIM_EXPROP_SUB,
1251512459
JIM_EXPROP_ADD,
1251612460
JIM_EXPROP_LSHIFT,
@@ -12521,66 +12465,48 @@
1252112465
JIM_EXPROP_GT,
1252212466
JIM_EXPROP_LTE,
1252312467
JIM_EXPROP_GTE,
1252412468
JIM_EXPROP_NUMEQ,
1252512469
JIM_EXPROP_NUMNE,
12526
- JIM_EXPROP_BITAND,
12470
+ JIM_EXPROP_BITAND,
1252712471
JIM_EXPROP_BITXOR,
1252812472
JIM_EXPROP_BITOR,
12529
-
12530
-
12531
- JIM_EXPROP_LOGICAND,
12532
- JIM_EXPROP_LOGICAND_LEFT,
12533
- JIM_EXPROP_LOGICAND_RIGHT,
12534
-
12535
-
12536
- JIM_EXPROP_LOGICOR,
12537
- JIM_EXPROP_LOGICOR_LEFT,
12538
- JIM_EXPROP_LOGICOR_RIGHT,
12539
-
12540
-
12541
-
12542
- JIM_EXPROP_TERNARY,
12543
- JIM_EXPROP_TERNARY_LEFT,
12544
- JIM_EXPROP_TERNARY_RIGHT,
12545
-
12546
-
12547
- JIM_EXPROP_COLON,
12548
- JIM_EXPROP_COLON_LEFT,
12549
- JIM_EXPROP_COLON_RIGHT,
12550
-
12551
- JIM_EXPROP_POW,
12552
-
12553
-
12554
- JIM_EXPROP_STREQ,
12473
+ JIM_EXPROP_LOGICAND,
12474
+ JIM_EXPROP_LOGICOR,
12475
+ JIM_EXPROP_TERNARY,
12476
+ JIM_EXPROP_COLON,
12477
+ JIM_EXPROP_POW,
12478
+
12479
+
12480
+ JIM_EXPROP_STREQ,
1255512481
JIM_EXPROP_STRNE,
1255612482
JIM_EXPROP_STRIN,
1255712483
JIM_EXPROP_STRNI,
1255812484
1255912485
12560
- JIM_EXPROP_NOT,
12486
+ JIM_EXPROP_NOT,
1256112487
JIM_EXPROP_BITNOT,
1256212488
JIM_EXPROP_UNARYMINUS,
1256312489
JIM_EXPROP_UNARYPLUS,
1256412490
12565
-
12566
- JIM_EXPROP_FUNC_FIRST,
12567
- JIM_EXPROP_FUNC_INT = JIM_EXPROP_FUNC_FIRST,
12491
+
12492
+ JIM_EXPROP_FUNC_INT,
1256812493
JIM_EXPROP_FUNC_WIDE,
1256912494
JIM_EXPROP_FUNC_ABS,
1257012495
JIM_EXPROP_FUNC_DOUBLE,
1257112496
JIM_EXPROP_FUNC_ROUND,
1257212497
JIM_EXPROP_FUNC_RAND,
1257312498
JIM_EXPROP_FUNC_SRAND,
1257412499
12575
-
12576
- JIM_EXPROP_FUNC_SIN,
12500
+
12501
+ JIM_EXPROP_FUNC_SIN,
1257712502
JIM_EXPROP_FUNC_COS,
1257812503
JIM_EXPROP_FUNC_TAN,
1257912504
JIM_EXPROP_FUNC_ASIN,
1258012505
JIM_EXPROP_FUNC_ACOS,
1258112506
JIM_EXPROP_FUNC_ATAN,
12507
+ JIM_EXPROP_FUNC_ATAN2,
1258212508
JIM_EXPROP_FUNC_SINH,
1258312509
JIM_EXPROP_FUNC_COSH,
1258412510
JIM_EXPROP_FUNC_TANH,
1258512511
JIM_EXPROP_FUNC_CEIL,
1258612512
JIM_EXPROP_FUNC_FLOOR,
@@ -12587,52 +12513,52 @@
1258712513
JIM_EXPROP_FUNC_EXP,
1258812514
JIM_EXPROP_FUNC_LOG,
1258912515
JIM_EXPROP_FUNC_LOG10,
1259012516
JIM_EXPROP_FUNC_SQRT,
1259112517
JIM_EXPROP_FUNC_POW,
12518
+ JIM_EXPROP_FUNC_HYPOT,
12519
+ JIM_EXPROP_FUNC_FMOD,
1259212520
};
1259312521
12594
-struct JimExprState
12595
-{
12596
- Jim_Obj **stack;
12597
- int stacklen;
12598
- int opcode;
12599
- int skip;
12522
+struct JimExprNode {
12523
+ int type;
12524
+ struct Jim_Obj *objPtr;
12525
+
12526
+ struct JimExprNode *left;
12527
+ struct JimExprNode *right;
12528
+ struct JimExprNode *ternary;
1260012529
};
1260112530
1260212531
1260312532
typedef struct Jim_ExprOperator
1260412533
{
1260512534
const char *name;
12606
- int (*funcop) (Jim_Interp *interp, struct JimExprState * e);
12535
+ int (*funcop) (Jim_Interp *interp, struct JimExprNode *opnode);
1260712536
unsigned char precedence;
1260812537
unsigned char arity;
12609
- unsigned char lazy;
12538
+ unsigned char attr;
1261012539
unsigned char namelen;
1261112540
} Jim_ExprOperator;
1261212541
12613
-static void ExprPush(struct JimExprState *e, Jim_Obj *obj)
12614
-{
12615
- Jim_IncrRefCount(obj);
12616
- e->stack[e->stacklen++] = obj;
12617
-}
12618
-
12619
-static Jim_Obj *ExprPop(struct JimExprState *e)
12620
-{
12621
- return e->stack[--e->stacklen];
12622
-}
12623
-
12624
-static int JimExprOpNumUnary(Jim_Interp *interp, struct JimExprState *e)
12542
+static int JimExprGetTerm(Jim_Interp *interp, struct JimExprNode *node, Jim_Obj **objPtrPtr);
12543
+static int JimExprGetTermBoolean(Jim_Interp *interp, struct JimExprNode *node);
12544
+static int JimExprEvalTermNode(Jim_Interp *interp, struct JimExprNode *node);
12545
+
12546
+static int JimExprOpNumUnary(Jim_Interp *interp, struct JimExprNode *node)
1262512547
{
1262612548
int intresult = 1;
12627
- int rc = JIM_OK;
12628
- Jim_Obj *A = ExprPop(e);
12549
+ int rc;
1262912550
double dA, dC = 0;
1263012551
jim_wide wA, wC = 0;
12552
+ Jim_Obj *A;
12553
+
12554
+ if ((rc = JimExprGetTerm(interp, node->left, &A)) != JIM_OK) {
12555
+ return rc;
12556
+ }
1263112557
1263212558
if ((A->typePtr != &doubleObjType || A->bytes) && JimGetWideNoErr(interp, A, &wA) == JIM_OK) {
12633
- switch (e->opcode) {
12559
+ switch (node->type) {
1263412560
case JIM_EXPROP_FUNC_INT:
1263512561
case JIM_EXPROP_FUNC_WIDE:
1263612562
case JIM_EXPROP_FUNC_ROUND:
1263712563
case JIM_EXPROP_UNARYPLUS:
1263812564
wC = wA;
@@ -12653,11 +12579,11 @@
1265312579
default:
1265412580
abort();
1265512581
}
1265612582
}
1265712583
else if ((rc = Jim_GetDouble(interp, A, &dA)) == JIM_OK) {
12658
- switch (e->opcode) {
12584
+ switch (node->type) {
1265912585
case JIM_EXPROP_FUNC_INT:
1266012586
case JIM_EXPROP_FUNC_WIDE:
1266112587
wC = dA;
1266212588
break;
1266312589
case JIM_EXPROP_FUNC_ROUND:
@@ -12667,11 +12593,15 @@
1266712593
case JIM_EXPROP_UNARYPLUS:
1266812594
dC = dA;
1266912595
intresult = 0;
1267012596
break;
1267112597
case JIM_EXPROP_FUNC_ABS:
12598
+#ifdef JIM_MATH_FUNCTIONS
12599
+ dC = fabs(dA);
12600
+#else
1267212601
dC = dA >= 0 ? dA : -dA;
12602
+#endif
1267312603
intresult = 0;
1267412604
break;
1267512605
case JIM_EXPROP_UNARYMINUS:
1267612606
dC = -dA;
1267712607
intresult = 0;
@@ -12684,14 +12614,14 @@
1268412614
}
1268512615
}
1268612616
1268712617
if (rc == JIM_OK) {
1268812618
if (intresult) {
12689
- ExprPush(e, Jim_NewIntObj(interp, wC));
12619
+ Jim_SetResultInt(interp, wC);
1269012620
}
1269112621
else {
12692
- ExprPush(e, Jim_NewDoubleObj(interp, dC));
12622
+ Jim_SetResult(interp, Jim_NewDoubleObj(interp, dC));
1269312623
}
1269412624
}
1269512625
1269612626
Jim_DecrRefCount(interp, A);
1269712627
@@ -12704,24 +12634,29 @@
1270412634
JimRandomBytes(interp, &x, sizeof(x));
1270512635
1270612636
return (double)x / (unsigned long)~0;
1270712637
}
1270812638
12709
-static int JimExprOpIntUnary(Jim_Interp *interp, struct JimExprState *e)
12639
+static int JimExprOpIntUnary(Jim_Interp *interp, struct JimExprNode *node)
1271012640
{
12711
- Jim_Obj *A = ExprPop(e);
1271212641
jim_wide wA;
12642
+ Jim_Obj *A;
12643
+ int rc;
1271312644
12714
- int rc = Jim_GetWide(interp, A, &wA);
12645
+ if ((rc = JimExprGetTerm(interp, node->left, &A)) != JIM_OK) {
12646
+ return rc;
12647
+ }
12648
+
12649
+ rc = Jim_GetWide(interp, A, &wA);
1271512650
if (rc == JIM_OK) {
12716
- switch (e->opcode) {
12651
+ switch (node->type) {
1271712652
case JIM_EXPROP_BITNOT:
12718
- ExprPush(e, Jim_NewIntObj(interp, ~wA));
12653
+ Jim_SetResultInt(interp, ~wA);
1271912654
break;
1272012655
case JIM_EXPROP_FUNC_SRAND:
1272112656
JimPrngSeed(interp, (unsigned char *)&wA, sizeof(wA));
12722
- ExprPush(e, Jim_NewDoubleObj(interp, JimRandDouble(interp)));
12657
+ Jim_SetResult(interp, Jim_NewDoubleObj(interp, JimRandDouble(interp)));
1272312658
break;
1272412659
default:
1272512660
abort();
1272612661
}
1272712662
}
@@ -12729,29 +12664,33 @@
1272912664
Jim_DecrRefCount(interp, A);
1273012665
1273112666
return rc;
1273212667
}
1273312668
12734
-static int JimExprOpNone(Jim_Interp *interp, struct JimExprState *e)
12669
+static int JimExprOpNone(Jim_Interp *interp, struct JimExprNode *node)
1273512670
{
12736
- JimPanic((e->opcode != JIM_EXPROP_FUNC_RAND, "JimExprOpNone only support rand()"));
12671
+ JimPanic((node->type != JIM_EXPROP_FUNC_RAND, "JimExprOpNone only support rand()"));
1273712672
12738
- ExprPush(e, Jim_NewDoubleObj(interp, JimRandDouble(interp)));
12673
+ Jim_SetResult(interp, Jim_NewDoubleObj(interp, JimRandDouble(interp)));
1273912674
1274012675
return JIM_OK;
1274112676
}
1274212677
1274312678
#ifdef JIM_MATH_FUNCTIONS
12744
-static int JimExprOpDoubleUnary(Jim_Interp *interp, struct JimExprState *e)
12679
+static int JimExprOpDoubleUnary(Jim_Interp *interp, struct JimExprNode *node)
1274512680
{
1274612681
int rc;
12747
- Jim_Obj *A = ExprPop(e);
1274812682
double dA, dC;
12683
+ Jim_Obj *A;
12684
+
12685
+ if ((rc = JimExprGetTerm(interp, node->left, &A)) != JIM_OK) {
12686
+ return rc;
12687
+ }
1274912688
1275012689
rc = Jim_GetDouble(interp, A, &dA);
1275112690
if (rc == JIM_OK) {
12752
- switch (e->opcode) {
12691
+ switch (node->type) {
1275312692
case JIM_EXPROP_FUNC_SIN:
1275412693
dC = sin(dA);
1275512694
break;
1275612695
case JIM_EXPROP_FUNC_COS:
1275712696
dC = cos(dA);
@@ -12796,33 +12735,42 @@
1279612735
dC = sqrt(dA);
1279712736
break;
1279812737
default:
1279912738
abort();
1280012739
}
12801
- ExprPush(e, Jim_NewDoubleObj(interp, dC));
12740
+ Jim_SetResult(interp, Jim_NewDoubleObj(interp, dC));
1280212741
}
1280312742
1280412743
Jim_DecrRefCount(interp, A);
1280512744
1280612745
return rc;
1280712746
}
1280812747
#endif
1280912748
1281012749
12811
-static int JimExprOpIntBin(Jim_Interp *interp, struct JimExprState *e)
12750
+static int JimExprOpIntBin(Jim_Interp *interp, struct JimExprNode *node)
1281212751
{
12813
- Jim_Obj *B = ExprPop(e);
12814
- Jim_Obj *A = ExprPop(e);
1281512752
jim_wide wA, wB;
12816
- int rc = JIM_ERR;
12753
+ int rc;
12754
+ Jim_Obj *A, *B;
12755
+
12756
+ if ((rc = JimExprGetTerm(interp, node->left, &A)) != JIM_OK) {
12757
+ return rc;
12758
+ }
12759
+ if ((rc = JimExprGetTerm(interp, node->right, &B)) != JIM_OK) {
12760
+ Jim_DecrRefCount(interp, A);
12761
+ return rc;
12762
+ }
12763
+
12764
+ rc = JIM_ERR;
1281712765
1281812766
if (Jim_GetWide(interp, A, &wA) == JIM_OK && Jim_GetWide(interp, B, &wB) == JIM_OK) {
1281912767
jim_wide wC;
1282012768
1282112769
rc = JIM_OK;
1282212770
12823
- switch (e->opcode) {
12771
+ switch (node->type) {
1282412772
case JIM_EXPROP_LSHIFT:
1282512773
wC = wA << wB;
1282612774
break;
1282712775
case JIM_EXPROP_RSHIFT:
1282812776
wC = wA >> wB;
@@ -12859,29 +12807,28 @@
1285912807
}
1286012808
}
1286112809
break;
1286212810
case JIM_EXPROP_ROTL:
1286312811
case JIM_EXPROP_ROTR:{
12864
-
12812
+
1286512813
unsigned long uA = (unsigned long)wA;
1286612814
unsigned long uB = (unsigned long)wB;
1286712815
const unsigned int S = sizeof(unsigned long) * 8;
1286812816
12869
-
12817
+
1287012818
uB %= S;
1287112819
12872
- if (e->opcode == JIM_EXPROP_ROTR) {
12820
+ if (node->type == JIM_EXPROP_ROTR) {
1287312821
uB = S - uB;
1287412822
}
1287512823
wC = (unsigned long)(uA << uB) | (uA >> (S - uB));
1287612824
break;
1287712825
}
1287812826
default:
1287912827
abort();
1288012828
}
12881
- ExprPush(e, Jim_NewIntObj(interp, wC));
12882
-
12829
+ Jim_SetResultInt(interp, wC);
1288312830
}
1288412831
1288512832
Jim_DecrRefCount(interp, A);
1288612833
Jim_DecrRefCount(interp, B);
1288712834
@@ -12888,44 +12835,55 @@
1288812835
return rc;
1288912836
}
1289012837
1289112838
1289212839
12893
-static int JimExprOpBin(Jim_Interp *interp, struct JimExprState *e)
12840
+static int JimExprOpBin(Jim_Interp *interp, struct JimExprNode *node)
1289412841
{
12895
- int intresult = 1;
1289612842
int rc = JIM_OK;
1289712843
double dA, dB, dC = 0;
1289812844
jim_wide wA, wB, wC = 0;
12845
+ Jim_Obj *A, *B;
1289912846
12900
- Jim_Obj *B = ExprPop(e);
12901
- Jim_Obj *A = ExprPop(e);
12847
+ if ((rc = JimExprGetTerm(interp, node->left, &A)) != JIM_OK) {
12848
+ return rc;
12849
+ }
12850
+ if ((rc = JimExprGetTerm(interp, node->right, &B)) != JIM_OK) {
12851
+ Jim_DecrRefCount(interp, A);
12852
+ return rc;
12853
+ }
1290212854
1290312855
if ((A->typePtr != &doubleObjType || A->bytes) &&
1290412856
(B->typePtr != &doubleObjType || B->bytes) &&
1290512857
JimGetWideNoErr(interp, A, &wA) == JIM_OK && JimGetWideNoErr(interp, B, &wB) == JIM_OK) {
1290612858
12907
-
1290812859
12909
- switch (e->opcode) {
12860
+
12861
+ switch (node->type) {
1291012862
case JIM_EXPROP_POW:
1291112863
case JIM_EXPROP_FUNC_POW:
12864
+ if (wA == 0 && wB < 0) {
12865
+ Jim_SetResultString(interp, "exponentiation of zero by negative power", -1);
12866
+ rc = JIM_ERR;
12867
+ goto done;
12868
+ }
1291212869
wC = JimPowWide(wA, wB);
12913
- break;
12870
+ goto intresult;
1291412871
case JIM_EXPROP_ADD:
1291512872
wC = wA + wB;
12916
- break;
12873
+ goto intresult;
1291712874
case JIM_EXPROP_SUB:
1291812875
wC = wA - wB;
12919
- break;
12876
+ goto intresult;
1292012877
case JIM_EXPROP_MUL:
1292112878
wC = wA * wB;
12922
- break;
12879
+ goto intresult;
1292312880
case JIM_EXPROP_DIV:
1292412881
if (wB == 0) {
1292512882
Jim_SetResultString(interp, "Division by zero", -1);
1292612883
rc = JIM_ERR;
12884
+ goto done;
1292712885
}
1292812886
else {
1292912887
if (wB < 0) {
1293012888
wB = -wB;
1293112889
wA = -wA;
@@ -12932,55 +12890,67 @@
1293212890
}
1293312891
wC = wA / wB;
1293412892
if (wA % wB < 0) {
1293512893
wC--;
1293612894
}
12895
+ goto intresult;
1293712896
}
12938
- break;
1293912897
case JIM_EXPROP_LT:
1294012898
wC = wA < wB;
12941
- break;
12899
+ goto intresult;
1294212900
case JIM_EXPROP_GT:
1294312901
wC = wA > wB;
12944
- break;
12902
+ goto intresult;
1294512903
case JIM_EXPROP_LTE:
1294612904
wC = wA <= wB;
12947
- break;
12905
+ goto intresult;
1294812906
case JIM_EXPROP_GTE:
1294912907
wC = wA >= wB;
12950
- break;
12908
+ goto intresult;
1295112909
case JIM_EXPROP_NUMEQ:
1295212910
wC = wA == wB;
12953
- break;
12911
+ goto intresult;
1295412912
case JIM_EXPROP_NUMNE:
1295512913
wC = wA != wB;
12956
- break;
12957
- default:
12958
- abort();
12914
+ goto intresult;
1295912915
}
1296012916
}
12961
- else if (Jim_GetDouble(interp, A, &dA) == JIM_OK && Jim_GetDouble(interp, B, &dB) == JIM_OK) {
12962
- intresult = 0;
12963
- switch (e->opcode) {
12917
+ if (Jim_GetDouble(interp, A, &dA) == JIM_OK && Jim_GetDouble(interp, B, &dB) == JIM_OK) {
12918
+ switch (node->type) {
12919
+#ifndef JIM_MATH_FUNCTIONS
1296412920
case JIM_EXPROP_POW:
1296512921
case JIM_EXPROP_FUNC_POW:
12966
-#ifdef JIM_MATH_FUNCTIONS
12967
- dC = pow(dA, dB);
12968
-#else
12922
+ case JIM_EXPROP_FUNC_ATAN2:
12923
+ case JIM_EXPROP_FUNC_HYPOT:
12924
+ case JIM_EXPROP_FUNC_FMOD:
1296912925
Jim_SetResultString(interp, "unsupported", -1);
1297012926
rc = JIM_ERR;
12927
+ goto done;
12928
+#else
12929
+ case JIM_EXPROP_POW:
12930
+ case JIM_EXPROP_FUNC_POW:
12931
+ dC = pow(dA, dB);
12932
+ goto doubleresult;
12933
+ case JIM_EXPROP_FUNC_ATAN2:
12934
+ dC = atan2(dA, dB);
12935
+ goto doubleresult;
12936
+ case JIM_EXPROP_FUNC_HYPOT:
12937
+ dC = hypot(dA, dB);
12938
+ goto doubleresult;
12939
+ case JIM_EXPROP_FUNC_FMOD:
12940
+ dC = fmod(dA, dB);
12941
+ goto doubleresult;
1297112942
#endif
12972
- break;
1297312943
case JIM_EXPROP_ADD:
1297412944
dC = dA + dB;
12975
- break;
12945
+ goto doubleresult;
1297612946
case JIM_EXPROP_SUB:
1297712947
dC = dA - dB;
12978
- break;
12948
+ goto doubleresult;
1297912949
case JIM_EXPROP_MUL:
1298012950
dC = dA * dB;
12981
- break;
12951
+ goto doubleresult;
1298212952
case JIM_EXPROP_DIV:
1298312953
if (dB == 0) {
1298412954
#ifdef INFINITY
1298512955
dC = dA < 0 ? -INFINITY : INFINITY;
1298612956
#else
@@ -12988,83 +12958,70 @@
1298812958
#endif
1298912959
}
1299012960
else {
1299112961
dC = dA / dB;
1299212962
}
12993
- break;
12963
+ goto doubleresult;
1299412964
case JIM_EXPROP_LT:
1299512965
wC = dA < dB;
12996
- intresult = 1;
12997
- break;
12966
+ goto intresult;
1299812967
case JIM_EXPROP_GT:
1299912968
wC = dA > dB;
13000
- intresult = 1;
13001
- break;
12969
+ goto intresult;
1300212970
case JIM_EXPROP_LTE:
1300312971
wC = dA <= dB;
13004
- intresult = 1;
13005
- break;
12972
+ goto intresult;
1300612973
case JIM_EXPROP_GTE:
1300712974
wC = dA >= dB;
13008
- intresult = 1;
13009
- break;
12975
+ goto intresult;
1301012976
case JIM_EXPROP_NUMEQ:
1301112977
wC = dA == dB;
13012
- intresult = 1;
13013
- break;
12978
+ goto intresult;
1301412979
case JIM_EXPROP_NUMNE:
1301512980
wC = dA != dB;
13016
- intresult = 1;
13017
- break;
13018
- default:
13019
- abort();
12981
+ goto intresult;
1302012982
}
1302112983
}
1302212984
else {
13023
-
1302412985
13025
-
12986
+
12987
+
1302612988
int i = Jim_StringCompareObj(interp, A, B, 0);
1302712989
13028
- switch (e->opcode) {
12990
+ switch (node->type) {
1302912991
case JIM_EXPROP_LT:
1303012992
wC = i < 0;
13031
- break;
12993
+ goto intresult;
1303212994
case JIM_EXPROP_GT:
1303312995
wC = i > 0;
13034
- break;
12996
+ goto intresult;
1303512997
case JIM_EXPROP_LTE:
1303612998
wC = i <= 0;
13037
- break;
12999
+ goto intresult;
1303813000
case JIM_EXPROP_GTE:
1303913001
wC = i >= 0;
13040
- break;
13002
+ goto intresult;
1304113003
case JIM_EXPROP_NUMEQ:
1304213004
wC = i == 0;
13043
- break;
13005
+ goto intresult;
1304413006
case JIM_EXPROP_NUMNE:
1304513007
wC = i != 0;
13046
- break;
13047
- default:
13048
- rc = JIM_ERR;
13049
- break;
13008
+ goto intresult;
1305013009
}
1305113010
}
1305213011
13053
- if (rc == JIM_OK) {
13054
- if (intresult) {
13055
- ExprPush(e, Jim_NewIntObj(interp, wC));
13056
- }
13057
- else {
13058
- ExprPush(e, Jim_NewDoubleObj(interp, dC));
13059
- }
13060
- }
13061
-
13012
+ rc = JIM_ERR;
13013
+done:
1306213014
Jim_DecrRefCount(interp, A);
1306313015
Jim_DecrRefCount(interp, B);
13064
-
1306513016
return rc;
13017
+intresult:
13018
+ Jim_SetResultInt(interp, wC);
13019
+ goto done;
13020
+doubleresult:
13021
+ Jim_SetResult(interp, Jim_NewDoubleObj(interp, dC));
13022
+ goto done;
1306613023
}
1306713024
1306813025
static int JimSearchList(Jim_Interp *interp, Jim_Obj *listObjPtr, Jim_Obj *valObj)
1306913026
{
1307013027
int listlen;
@@ -13077,22 +13034,31 @@
1307713034
}
1307813035
}
1307913036
return 0;
1308013037
}
1308113038
13082
-static int JimExprOpStrBin(Jim_Interp *interp, struct JimExprState *e)
13039
+
13040
+
13041
+static int JimExprOpStrBin(Jim_Interp *interp, struct JimExprNode *node)
1308313042
{
13084
- Jim_Obj *B = ExprPop(e);
13085
- Jim_Obj *A = ExprPop(e);
13086
-
13043
+ Jim_Obj *A, *B;
1308713044
jim_wide wC;
13045
+ int rc;
1308813046
13089
- switch (e->opcode) {
13047
+ if ((rc = JimExprGetTerm(interp, node->left, &A)) != JIM_OK) {
13048
+ return rc;
13049
+ }
13050
+ if ((rc = JimExprGetTerm(interp, node->right, &B)) != JIM_OK) {
13051
+ Jim_DecrRefCount(interp, A);
13052
+ return rc;
13053
+ }
13054
+
13055
+ switch (node->type) {
1309013056
case JIM_EXPROP_STREQ:
1309113057
case JIM_EXPROP_STRNE:
1309213058
wC = Jim_StringEqObj(A, B);
13093
- if (e->opcode == JIM_EXPROP_STRNE) {
13059
+ if (node->type == JIM_EXPROP_STRNE) {
1309413060
wC = !wC;
1309513061
}
1309613062
break;
1309713063
case JIM_EXPROP_STRIN:
1309813064
wC = JimSearchList(interp, B, A);
@@ -13101,178 +13067,99 @@
1310113067
wC = !JimSearchList(interp, B, A);
1310213068
break;
1310313069
default:
1310413070
abort();
1310513071
}
13106
- ExprPush(e, Jim_NewIntObj(interp, wC));
13072
+ Jim_SetResultInt(interp, wC);
1310713073
1310813074
Jim_DecrRefCount(interp, A);
1310913075
Jim_DecrRefCount(interp, B);
1311013076
13111
- return JIM_OK;
13077
+ return rc;
1311213078
}
1311313079
1311413080
static int ExprBool(Jim_Interp *interp, Jim_Obj *obj)
1311513081
{
1311613082
long l;
1311713083
double d;
13084
+ int b;
13085
+ int ret = -1;
13086
+
13087
+
13088
+ Jim_IncrRefCount(obj);
1311813089
1311913090
if (Jim_GetLong(interp, obj, &l) == JIM_OK) {
13120
- return l != 0;
13121
- }
13122
- if (Jim_GetDouble(interp, obj, &d) == JIM_OK) {
13123
- return d != 0;
13124
- }
13125
- return -1;
13126
-}
13127
-
13128
-static int JimExprOpAndLeft(Jim_Interp *interp, struct JimExprState *e)
13129
-{
13130
- Jim_Obj *skip = ExprPop(e);
13131
- Jim_Obj *A = ExprPop(e);
13132
- int rc = JIM_OK;
13133
-
13134
- switch (ExprBool(interp, A)) {
13135
- case 0:
13136
-
13137
- e->skip = JimWideValue(skip);
13138
- ExprPush(e, Jim_NewIntObj(interp, 0));
13139
- break;
13140
-
13141
- case 1:
13142
-
13143
- break;
13144
-
13145
- case -1:
13146
-
13147
- rc = JIM_ERR;
13148
- }
13149
- Jim_DecrRefCount(interp, A);
13150
- Jim_DecrRefCount(interp, skip);
13151
-
13152
- return rc;
13153
-}
13154
-
13155
-static int JimExprOpOrLeft(Jim_Interp *interp, struct JimExprState *e)
13156
-{
13157
- Jim_Obj *skip = ExprPop(e);
13158
- Jim_Obj *A = ExprPop(e);
13159
- int rc = JIM_OK;
13160
-
13161
- switch (ExprBool(interp, A)) {
13162
- case 0:
13163
-
13164
- break;
13165
-
13166
- case 1:
13167
-
13168
- e->skip = JimWideValue(skip);
13169
- ExprPush(e, Jim_NewIntObj(interp, 1));
13170
- break;
13171
-
13172
- case -1:
13173
-
13174
- rc = JIM_ERR;
13175
- break;
13176
- }
13177
- Jim_DecrRefCount(interp, A);
13178
- Jim_DecrRefCount(interp, skip);
13179
-
13180
- return rc;
13181
-}
13182
-
13183
-static int JimExprOpAndOrRight(Jim_Interp *interp, struct JimExprState *e)
13184
-{
13185
- Jim_Obj *A = ExprPop(e);
13186
- int rc = JIM_OK;
13187
-
13188
- switch (ExprBool(interp, A)) {
13189
- case 0:
13190
- ExprPush(e, Jim_NewIntObj(interp, 0));
13191
- break;
13192
-
13193
- case 1:
13194
- ExprPush(e, Jim_NewIntObj(interp, 1));
13195
- break;
13196
-
13197
- case -1:
13198
-
13199
- rc = JIM_ERR;
13200
- break;
13201
- }
13202
- Jim_DecrRefCount(interp, A);
13203
-
13204
- return rc;
13205
-}
13206
-
13207
-static int JimExprOpTernaryLeft(Jim_Interp *interp, struct JimExprState *e)
13208
-{
13209
- Jim_Obj *skip = ExprPop(e);
13210
- Jim_Obj *A = ExprPop(e);
13211
- int rc = JIM_OK;
13212
-
13213
-
13214
- ExprPush(e, A);
13215
-
13216
- switch (ExprBool(interp, A)) {
13217
- case 0:
13218
-
13219
- e->skip = JimWideValue(skip);
13220
-
13221
- ExprPush(e, Jim_NewIntObj(interp, 0));
13222
- break;
13223
-
13224
- case 1:
13225
-
13226
- break;
13227
-
13228
- case -1:
13229
-
13230
- rc = JIM_ERR;
13231
- break;
13232
- }
13233
- Jim_DecrRefCount(interp, A);
13234
- Jim_DecrRefCount(interp, skip);
13235
-
13236
- return rc;
13237
-}
13238
-
13239
-static int JimExprOpColonLeft(Jim_Interp *interp, struct JimExprState *e)
13240
-{
13241
- Jim_Obj *skip = ExprPop(e);
13242
- Jim_Obj *B = ExprPop(e);
13243
- Jim_Obj *A = ExprPop(e);
13244
-
13245
-
13246
- if (ExprBool(interp, A)) {
13247
-
13248
- e->skip = JimWideValue(skip);
13249
-
13250
- ExprPush(e, B);
13251
- }
13252
-
13253
- Jim_DecrRefCount(interp, skip);
13254
- Jim_DecrRefCount(interp, A);
13255
- Jim_DecrRefCount(interp, B);
13256
- return JIM_OK;
13257
-}
13258
-
13259
-static int JimExprOpNull(Jim_Interp *interp, struct JimExprState *e)
13260
-{
13261
- return JIM_OK;
13091
+ ret = (l != 0);
13092
+ }
13093
+ else if (Jim_GetDouble(interp, obj, &d) == JIM_OK) {
13094
+ ret = (d != 0);
13095
+ }
13096
+ else if (Jim_GetBoolean(interp, obj, &b) == JIM_OK) {
13097
+ ret = (b != 0);
13098
+ }
13099
+
13100
+ Jim_DecrRefCount(interp, obj);
13101
+ return ret;
13102
+}
13103
+
13104
+static int JimExprOpAnd(Jim_Interp *interp, struct JimExprNode *node)
13105
+{
13106
+
13107
+ int result = JimExprGetTermBoolean(interp, node->left);
13108
+
13109
+ if (result == 1) {
13110
+
13111
+ result = JimExprGetTermBoolean(interp, node->right);
13112
+ }
13113
+ if (result == -1) {
13114
+ return JIM_ERR;
13115
+ }
13116
+ Jim_SetResultInt(interp, result);
13117
+ return JIM_OK;
13118
+}
13119
+
13120
+static int JimExprOpOr(Jim_Interp *interp, struct JimExprNode *node)
13121
+{
13122
+
13123
+ int result = JimExprGetTermBoolean(interp, node->left);
13124
+
13125
+ if (result == 0) {
13126
+
13127
+ result = JimExprGetTermBoolean(interp, node->right);
13128
+ }
13129
+ if (result == -1) {
13130
+ return JIM_ERR;
13131
+ }
13132
+ Jim_SetResultInt(interp, result);
13133
+ return JIM_OK;
13134
+}
13135
+
13136
+static int JimExprOpTernary(Jim_Interp *interp, struct JimExprNode *node)
13137
+{
13138
+
13139
+ int result = JimExprGetTermBoolean(interp, node->left);
13140
+
13141
+ if (result == 1) {
13142
+
13143
+ return JimExprEvalTermNode(interp, node->right);
13144
+ }
13145
+ else if (result == 0) {
13146
+
13147
+ return JimExprEvalTermNode(interp, node->ternary);
13148
+ }
13149
+
13150
+ return JIM_ERR;
1326213151
}
1326313152
1326413153
enum
1326513154
{
13266
- LAZY_NONE,
13267
- LAZY_OP,
13268
- LAZY_LEFT,
13269
- LAZY_RIGHT
13155
+ OP_FUNC = 0x0001,
13156
+ OP_RIGHT_ASSOC = 0x0002,
1327013157
};
1327113158
13272
-#define OPRINIT(N, P, A, F) {N, F, P, A, LAZY_NONE, sizeof(N) - 1}
13273
-#define OPRINIT_LAZY(N, P, A, F, L) {N, F, P, A, L, sizeof(N) - 1}
13159
+#define OPRINIT_ATTR(N, P, ARITY, F, ATTR) {N, F, P, ARITY, ATTR, sizeof(N) - 1}
13160
+#define OPRINIT(N, P, ARITY, F) OPRINIT_ATTR(N, P, ARITY, F, 0)
1327413161
1327513162
static const struct Jim_ExprOperator Jim_ExprOperators[] = {
1327613163
OPRINIT("*", 110, 2, JimExprOpBin),
1327713164
OPRINIT("/", 110, 2, JimExprOpBin),
1327813165
OPRINIT("%", 110, 2, JimExprOpIntBin),
@@ -13296,86 +13183,79 @@
1329613183
1329713184
OPRINIT("&", 50, 2, JimExprOpIntBin),
1329813185
OPRINIT("^", 49, 2, JimExprOpIntBin),
1329913186
OPRINIT("|", 48, 2, JimExprOpIntBin),
1330013187
13301
- OPRINIT_LAZY("&&", 10, 2, NULL, LAZY_OP),
13302
- OPRINIT_LAZY(NULL, 10, 2, JimExprOpAndLeft, LAZY_LEFT),
13303
- OPRINIT_LAZY(NULL, 10, 2, JimExprOpAndOrRight, LAZY_RIGHT),
13304
-
13305
- OPRINIT_LAZY("||", 9, 2, NULL, LAZY_OP),
13306
- OPRINIT_LAZY(NULL, 9, 2, JimExprOpOrLeft, LAZY_LEFT),
13307
- OPRINIT_LAZY(NULL, 9, 2, JimExprOpAndOrRight, LAZY_RIGHT),
13308
-
13309
- OPRINIT_LAZY("?", 5, 2, JimExprOpNull, LAZY_OP),
13310
- OPRINIT_LAZY(NULL, 5, 2, JimExprOpTernaryLeft, LAZY_LEFT),
13311
- OPRINIT_LAZY(NULL, 5, 2, JimExprOpNull, LAZY_RIGHT),
13312
-
13313
- OPRINIT_LAZY(":", 5, 2, JimExprOpNull, LAZY_OP),
13314
- OPRINIT_LAZY(NULL, 5, 2, JimExprOpColonLeft, LAZY_LEFT),
13315
- OPRINIT_LAZY(NULL, 5, 2, JimExprOpNull, LAZY_RIGHT),
13316
-
13317
- OPRINIT("**", 250, 2, JimExprOpBin),
13188
+ OPRINIT("&&", 10, 2, JimExprOpAnd),
13189
+ OPRINIT("||", 9, 2, JimExprOpOr),
13190
+ OPRINIT_ATTR("?", 5, 3, JimExprOpTernary, OP_RIGHT_ASSOC),
13191
+ OPRINIT_ATTR(":", 5, 3, NULL, OP_RIGHT_ASSOC),
13192
+
13193
+
13194
+ OPRINIT_ATTR("**", 120, 2, JimExprOpBin, OP_RIGHT_ASSOC),
1331813195
1331913196
OPRINIT("eq", 60, 2, JimExprOpStrBin),
1332013197
OPRINIT("ne", 60, 2, JimExprOpStrBin),
1332113198
1332213199
OPRINIT("in", 55, 2, JimExprOpStrBin),
1332313200
OPRINIT("ni", 55, 2, JimExprOpStrBin),
1332413201
13325
- OPRINIT("!", 150, 1, JimExprOpNumUnary),
13326
- OPRINIT("~", 150, 1, JimExprOpIntUnary),
13327
- OPRINIT(NULL, 150, 1, JimExprOpNumUnary),
13328
- OPRINIT(NULL, 150, 1, JimExprOpNumUnary),
13202
+ OPRINIT_ATTR("!", 150, 1, JimExprOpNumUnary, OP_RIGHT_ASSOC),
13203
+ OPRINIT_ATTR("~", 150, 1, JimExprOpIntUnary, OP_RIGHT_ASSOC),
13204
+ OPRINIT_ATTR(" -", 150, 1, JimExprOpNumUnary, OP_RIGHT_ASSOC),
13205
+ OPRINIT_ATTR(" +", 150, 1, JimExprOpNumUnary, OP_RIGHT_ASSOC),
1332913206
1333013207
1333113208
13332
- OPRINIT("int", 200, 1, JimExprOpNumUnary),
13333
- OPRINIT("wide", 200, 1, JimExprOpNumUnary),
13334
- OPRINIT("abs", 200, 1, JimExprOpNumUnary),
13335
- OPRINIT("double", 200, 1, JimExprOpNumUnary),
13336
- OPRINIT("round", 200, 1, JimExprOpNumUnary),
13337
- OPRINIT("rand", 200, 0, JimExprOpNone),
13338
- OPRINIT("srand", 200, 1, JimExprOpIntUnary),
13209
+ OPRINIT_ATTR("int", 200, 1, JimExprOpNumUnary, OP_FUNC),
13210
+ OPRINIT_ATTR("wide", 200, 1, JimExprOpNumUnary, OP_FUNC),
13211
+ OPRINIT_ATTR("abs", 200, 1, JimExprOpNumUnary, OP_FUNC),
13212
+ OPRINIT_ATTR("double", 200, 1, JimExprOpNumUnary, OP_FUNC),
13213
+ OPRINIT_ATTR("round", 200, 1, JimExprOpNumUnary, OP_FUNC),
13214
+ OPRINIT_ATTR("rand", 200, 0, JimExprOpNone, OP_FUNC),
13215
+ OPRINIT_ATTR("srand", 200, 1, JimExprOpIntUnary, OP_FUNC),
1333913216
1334013217
#ifdef JIM_MATH_FUNCTIONS
13341
- OPRINIT("sin", 200, 1, JimExprOpDoubleUnary),
13342
- OPRINIT("cos", 200, 1, JimExprOpDoubleUnary),
13343
- OPRINIT("tan", 200, 1, JimExprOpDoubleUnary),
13344
- OPRINIT("asin", 200, 1, JimExprOpDoubleUnary),
13345
- OPRINIT("acos", 200, 1, JimExprOpDoubleUnary),
13346
- OPRINIT("atan", 200, 1, JimExprOpDoubleUnary),
13347
- OPRINIT("sinh", 200, 1, JimExprOpDoubleUnary),
13348
- OPRINIT("cosh", 200, 1, JimExprOpDoubleUnary),
13349
- OPRINIT("tanh", 200, 1, JimExprOpDoubleUnary),
13350
- OPRINIT("ceil", 200, 1, JimExprOpDoubleUnary),
13351
- OPRINIT("floor", 200, 1, JimExprOpDoubleUnary),
13352
- OPRINIT("exp", 200, 1, JimExprOpDoubleUnary),
13353
- OPRINIT("log", 200, 1, JimExprOpDoubleUnary),
13354
- OPRINIT("log10", 200, 1, JimExprOpDoubleUnary),
13355
- OPRINIT("sqrt", 200, 1, JimExprOpDoubleUnary),
13356
- OPRINIT("pow", 200, 2, JimExprOpBin),
13218
+ OPRINIT_ATTR("sin", 200, 1, JimExprOpDoubleUnary, OP_FUNC),
13219
+ OPRINIT_ATTR("cos", 200, 1, JimExprOpDoubleUnary, OP_FUNC),
13220
+ OPRINIT_ATTR("tan", 200, 1, JimExprOpDoubleUnary, OP_FUNC),
13221
+ OPRINIT_ATTR("asin", 200, 1, JimExprOpDoubleUnary, OP_FUNC),
13222
+ OPRINIT_ATTR("acos", 200, 1, JimExprOpDoubleUnary, OP_FUNC),
13223
+ OPRINIT_ATTR("atan", 200, 1, JimExprOpDoubleUnary, OP_FUNC),
13224
+ OPRINIT_ATTR("atan2", 200, 2, JimExprOpBin, OP_FUNC),
13225
+ OPRINIT_ATTR("sinh", 200, 1, JimExprOpDoubleUnary, OP_FUNC),
13226
+ OPRINIT_ATTR("cosh", 200, 1, JimExprOpDoubleUnary, OP_FUNC),
13227
+ OPRINIT_ATTR("tanh", 200, 1, JimExprOpDoubleUnary, OP_FUNC),
13228
+ OPRINIT_ATTR("ceil", 200, 1, JimExprOpDoubleUnary, OP_FUNC),
13229
+ OPRINIT_ATTR("floor", 200, 1, JimExprOpDoubleUnary, OP_FUNC),
13230
+ OPRINIT_ATTR("exp", 200, 1, JimExprOpDoubleUnary, OP_FUNC),
13231
+ OPRINIT_ATTR("log", 200, 1, JimExprOpDoubleUnary, OP_FUNC),
13232
+ OPRINIT_ATTR("log10", 200, 1, JimExprOpDoubleUnary, OP_FUNC),
13233
+ OPRINIT_ATTR("sqrt", 200, 1, JimExprOpDoubleUnary, OP_FUNC),
13234
+ OPRINIT_ATTR("pow", 200, 2, JimExprOpBin, OP_FUNC),
13235
+ OPRINIT_ATTR("hypot", 200, 2, JimExprOpBin, OP_FUNC),
13236
+ OPRINIT_ATTR("fmod", 200, 2, JimExprOpBin, OP_FUNC),
1335713237
#endif
1335813238
};
1335913239
#undef OPRINIT
13360
-#undef OPRINIT_LAZY
13240
+#undef OPRINIT_ATTR
1336113241
1336213242
#define JIM_EXPR_OPERATORS_NUM \
1336313243
(sizeof(Jim_ExprOperators)/sizeof(struct Jim_ExprOperator))
1336413244
1336513245
static int JimParseExpression(struct JimParserCtx *pc)
1336613246
{
13367
-
13247
+
1336813248
while (isspace(UCHAR(*pc->p)) || (*(pc->p) == '\\' && *(pc->p + 1) == '\n')) {
1336913249
if (*pc->p == '\n') {
1337013250
pc->linenr++;
1337113251
}
1337213252
pc->p++;
1337313253
pc->len--;
1337413254
}
1337513255
13376
-
13256
+
1337713257
pc->tline = pc->linenr;
1337813258
pc->tstart = pc->p;
1337913259
1338013260
if (pc->len == 0) {
1338113261
pc->tend = pc->p;
@@ -13401,11 +13281,11 @@
1340113281
return JimParseCmd(pc);
1340213282
case '$':
1340313283
if (JimParseVar(pc) == JIM_ERR)
1340413284
return JimParseExprOperator(pc);
1340513285
else {
13406
-
13286
+
1340713287
if (pc->tt == JIM_TT_EXPRSUGAR) {
1340813288
return JIM_ERR;
1340913289
}
1341013290
return JIM_OK;
1341113291
}
@@ -13430,10 +13310,18 @@
1343013310
case 'N':
1343113311
case 'I':
1343213312
case 'n':
1343313313
case 'i':
1343413314
if (JimParseExprIrrational(pc) == JIM_ERR)
13315
+ if (JimParseExprBoolean(pc) == JIM_ERR)
13316
+ return JimParseExprOperator(pc);
13317
+ break;
13318
+ case 't':
13319
+ case 'f':
13320
+ case 'o':
13321
+ case 'y':
13322
+ if (JimParseExprBoolean(pc) == JIM_ERR)
1343513323
return JimParseExprOperator(pc);
1343613324
break;
1343713325
default:
1343813326
return JimParseExprOperator(pc);
1343913327
break;
@@ -13443,21 +13331,21 @@
1344313331
1344413332
static int JimParseExprNumber(struct JimParserCtx *pc)
1344513333
{
1344613334
char *end;
1344713335
13448
-
13336
+
1344913337
pc->tt = JIM_TT_EXPR_INT;
1345013338
1345113339
jim_strtoull(pc->p, (char **)&pc->p);
13452
-
13340
+
1345313341
if (strchr("eENnIi.", *pc->p) || pc->p == pc->tstart) {
13454
- if (strtod(pc->tstart, &end)) { }
13342
+ if (strtod(pc->tstart, &end)) { }
1345513343
if (end == pc->tstart)
1345613344
return JIM_ERR;
1345713345
if (end > pc->p) {
13458
-
13346
+
1345913347
pc->tt = JIM_TT_EXPR_DOUBLE;
1346013348
pc->p = end;
1346113349
}
1346213350
}
1346313351
pc->tend = pc->p - 1;
@@ -13481,36 +13369,66 @@
1348113369
return JIM_OK;
1348213370
}
1348313371
}
1348413372
return JIM_ERR;
1348513373
}
13374
+
13375
+static int JimParseExprBoolean(struct JimParserCtx *pc)
13376
+{
13377
+ const char *booleans[] = { "false", "no", "off", "true", "yes", "on", NULL };
13378
+ const int lengths[] = { 5, 2, 3, 4, 3, 2, 0 };
13379
+ int i;
13380
+
13381
+ for (i = 0; booleans[i]; i++) {
13382
+ const char *boolean = booleans[i];
13383
+ int length = lengths[i];
13384
+
13385
+ if (strncmp(boolean, pc->p, length) == 0) {
13386
+ pc->p += length;
13387
+ pc->len -= length;
13388
+ pc->tend = pc->p - 1;
13389
+ pc->tt = JIM_TT_EXPR_BOOLEAN;
13390
+ return JIM_OK;
13391
+ }
13392
+ }
13393
+ return JIM_ERR;
13394
+}
13395
+
13396
+static const struct Jim_ExprOperator *JimExprOperatorInfoByOpcode(int opcode)
13397
+{
13398
+ static Jim_ExprOperator dummy_op;
13399
+ if (opcode < JIM_TT_EXPR_OP) {
13400
+ return &dummy_op;
13401
+ }
13402
+ return &Jim_ExprOperators[opcode - JIM_TT_EXPR_OP];
13403
+}
1348613404
1348713405
static int JimParseExprOperator(struct JimParserCtx *pc)
1348813406
{
1348913407
int i;
13490
- int bestIdx = -1, bestLen = 0;
13408
+ const struct Jim_ExprOperator *bestOp = NULL;
13409
+ int bestLen = 0;
1349113410
13492
-
13411
+
1349313412
for (i = 0; i < (signed)JIM_EXPR_OPERATORS_NUM; i++) {
13494
- const char * const opname = Jim_ExprOperators[i].name;
13495
- const int oplen = Jim_ExprOperators[i].namelen;
13413
+ const struct Jim_ExprOperator *op = &Jim_ExprOperators[i];
1349613414
13497
- if (opname == NULL || opname[0] != pc->p[0]) {
13415
+ if (op->name[0] != pc->p[0]) {
1349813416
continue;
1349913417
}
1350013418
13501
- if (oplen > bestLen && strncmp(opname, pc->p, oplen) == 0) {
13502
- bestIdx = i + JIM_TT_EXPR_OP;
13503
- bestLen = oplen;
13419
+ if (op->namelen > bestLen && strncmp(op->name, pc->p, op->namelen) == 0) {
13420
+ bestOp = op;
13421
+ bestLen = op->namelen;
1350413422
}
1350513423
}
13506
- if (bestIdx == -1) {
13424
+ if (bestOp == NULL) {
1350713425
return JIM_ERR;
1350813426
}
1350913427
13510
-
13511
- if (bestIdx >= JIM_EXPROP_FUNC_FIRST) {
13428
+
13429
+ if (bestOp->attr & OP_FUNC) {
1351213430
const char *p = pc->p + bestLen;
1351313431
int len = pc->len - bestLen;
1351413432
1351513433
while (len && isspace(UCHAR(*p))) {
1351613434
len--;
@@ -13522,30 +13440,27 @@
1352213440
}
1352313441
pc->tend = pc->p + bestLen - 1;
1352413442
pc->p += bestLen;
1352513443
pc->len -= bestLen;
1352613444
13527
- pc->tt = bestIdx;
13445
+ pc->tt = (bestOp - Jim_ExprOperators) + JIM_TT_EXPR_OP;
1352813446
return JIM_OK;
1352913447
}
1353013448
13531
-static const struct Jim_ExprOperator *JimExprOperatorInfoByOpcode(int opcode)
13532
-{
13533
- static Jim_ExprOperator dummy_op;
13534
- if (opcode < JIM_TT_EXPR_OP) {
13535
- return &dummy_op;
13536
- }
13537
- return &Jim_ExprOperators[opcode - JIM_TT_EXPR_OP];
13538
-}
13539
-
1354013449
const char *jim_tt_name(int type)
1354113450
{
1354213451
static const char * const tt_names[JIM_TT_EXPR_OP] =
1354313452
{ "NIL", "STR", "ESC", "VAR", "ARY", "CMD", "SEP", "EOL", "EOF", "LIN", "WRD", "(((", ")))", ",,,", "INT",
13544
- "DBL", "$()" };
13453
+ "DBL", "BOO", "$()" };
1354513454
if (type < JIM_TT_EXPR_OP) {
1354613455
return tt_names[type];
13456
+ }
13457
+ else if (type == JIM_EXPROP_UNARYMINUS) {
13458
+ return "-VE";
13459
+ }
13460
+ else if (type == JIM_EXPROP_UNARYPLUS) {
13461
+ return "+VE";
1354713462
}
1354813463
else {
1354913464
const struct Jim_ExprOperator *op = JimExprOperatorInfoByOpcode(type);
1355013465
static char buf[20];
1355113466
@@ -13568,432 +13483,400 @@
1356813483
NULL,
1356913484
JIM_TYPE_REFERENCES,
1357013485
};
1357113486
1357213487
13573
-typedef struct ExprByteCode
13574
-{
13575
- ScriptToken *token;
13576
- int len;
13577
- int inUse;
13578
-} ExprByteCode;
13579
-
13580
-static void ExprFreeByteCode(Jim_Interp *interp, ExprByteCode * expr)
13488
+struct ExprTree
13489
+{
13490
+ struct JimExprNode *expr;
13491
+ struct JimExprNode *nodes;
13492
+ int len;
13493
+ int inUse;
13494
+};
13495
+
13496
+static void ExprTreeFreeNodes(Jim_Interp *interp, struct JimExprNode *nodes, int num)
1358113497
{
1358213498
int i;
13499
+ for (i = 0; i < num; i++) {
13500
+ if (nodes[i].objPtr) {
13501
+ Jim_DecrRefCount(interp, nodes[i].objPtr);
13502
+ }
13503
+ }
13504
+ Jim_Free(nodes);
13505
+}
1358313506
13584
- for (i = 0; i < expr->len; i++) {
13585
- Jim_DecrRefCount(interp, expr->token[i].objPtr);
13586
- }
13587
- Jim_Free(expr->token);
13507
+static void ExprTreeFree(Jim_Interp *interp, struct ExprTree *expr)
13508
+{
13509
+ ExprTreeFreeNodes(interp, expr->nodes, expr->len);
1358813510
Jim_Free(expr);
1358913511
}
1359013512
1359113513
static void FreeExprInternalRep(Jim_Interp *interp, Jim_Obj *objPtr)
1359213514
{
13593
- ExprByteCode *expr = (void *)objPtr->internalRep.ptr;
13515
+ struct ExprTree *expr = (void *)objPtr->internalRep.ptr;
1359413516
1359513517
if (expr) {
1359613518
if (--expr->inUse != 0) {
1359713519
return;
1359813520
}
1359913521
13600
- ExprFreeByteCode(interp, expr);
13522
+ ExprTreeFree(interp, expr);
1360113523
}
1360213524
}
1360313525
1360413526
static void DupExprInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr)
1360513527
{
1360613528
JIM_NOTUSED(interp);
1360713529
JIM_NOTUSED(srcPtr);
1360813530
13609
-
13531
+
1361013532
dupPtr->typePtr = NULL;
1361113533
}
1361213534
13613
-
13614
-static int ExprCheckCorrectness(ExprByteCode * expr)
13615
-{
13616
- int i;
13617
- int stacklen = 0;
13618
- int ternary = 0;
13619
-
13620
- for (i = 0; i < expr->len; i++) {
13621
- ScriptToken *t = &expr->token[i];
13622
- const struct Jim_ExprOperator *op = JimExprOperatorInfoByOpcode(t->type);
13623
-
13624
- stacklen -= op->arity;
13625
- if (stacklen < 0) {
13626
- break;
13627
- }
13628
- if (t->type == JIM_EXPROP_TERNARY || t->type == JIM_EXPROP_TERNARY_LEFT) {
13629
- ternary++;
13630
- }
13631
- else if (t->type == JIM_EXPROP_COLON || t->type == JIM_EXPROP_COLON_LEFT) {
13632
- ternary--;
13633
- }
13634
-
13635
-
13636
- stacklen++;
13637
- }
13638
- if (stacklen != 1 || ternary != 0) {
13639
- return JIM_ERR;
13640
- }
13641
- return JIM_OK;
13642
-}
13643
-
13644
-static int ExprAddLazyOperator(Jim_Interp *interp, ExprByteCode * expr, ParseToken *t)
13645
-{
13646
- int i;
13647
-
13648
- int leftindex, arity, offset;
13649
-
13650
-
13651
- leftindex = expr->len - 1;
13652
-
13653
- arity = 1;
13654
- while (arity) {
13655
- ScriptToken *tt = &expr->token[leftindex];
13656
-
13657
- if (tt->type >= JIM_TT_EXPR_OP) {
13658
- arity += JimExprOperatorInfoByOpcode(tt->type)->arity;
13659
- }
13660
- arity--;
13661
- if (--leftindex < 0) {
13662
- return JIM_ERR;
13663
- }
13664
- }
13665
- leftindex++;
13666
-
13667
-
13668
- memmove(&expr->token[leftindex + 2], &expr->token[leftindex],
13669
- sizeof(*expr->token) * (expr->len - leftindex));
13670
- expr->len += 2;
13671
- offset = (expr->len - leftindex) - 1;
13672
-
13673
- expr->token[leftindex + 1].type = t->type + 1;
13674
- expr->token[leftindex + 1].objPtr = interp->emptyObj;
13675
-
13676
- expr->token[leftindex].type = JIM_TT_EXPR_INT;
13677
- expr->token[leftindex].objPtr = Jim_NewIntObj(interp, offset);
13678
-
13679
-
13680
- expr->token[expr->len].objPtr = interp->emptyObj;
13681
- expr->token[expr->len].type = t->type + 2;
13682
- expr->len++;
13683
-
13684
-
13685
- for (i = leftindex - 1; i > 0; i--) {
13686
- const struct Jim_ExprOperator *op = JimExprOperatorInfoByOpcode(expr->token[i].type);
13687
- if (op->lazy == LAZY_LEFT) {
13688
- if (JimWideValue(expr->token[i - 1].objPtr) + i - 1 >= leftindex) {
13689
- JimWideValue(expr->token[i - 1].objPtr) += 2;
13690
- }
13691
- }
13692
- }
13693
- return JIM_OK;
13694
-}
13695
-
13696
-static int ExprAddOperator(Jim_Interp *interp, ExprByteCode * expr, ParseToken *t)
13697
-{
13698
- struct ScriptToken *token = &expr->token[expr->len];
13699
- const struct Jim_ExprOperator *op = JimExprOperatorInfoByOpcode(t->type);
13700
-
13701
- if (op->lazy == LAZY_OP) {
13702
- if (ExprAddLazyOperator(interp, expr, t) != JIM_OK) {
13703
- Jim_SetResultFormatted(interp, "Expression has bad operands to %s", op->name);
13704
- return JIM_ERR;
13705
- }
13706
- }
13707
- else {
13708
- token->objPtr = interp->emptyObj;
13709
- token->type = t->type;
13710
- expr->len++;
13711
- }
13712
- return JIM_OK;
13713
-}
13714
-
13715
-static int ExprTernaryGetColonLeftIndex(ExprByteCode *expr, int right_index)
13716
-{
13717
- int ternary_count = 1;
13718
-
13719
- right_index--;
13720
-
13721
- while (right_index > 1) {
13722
- if (expr->token[right_index].type == JIM_EXPROP_TERNARY_LEFT) {
13723
- ternary_count--;
13724
- }
13725
- else if (expr->token[right_index].type == JIM_EXPROP_COLON_RIGHT) {
13726
- ternary_count++;
13727
- }
13728
- else if (expr->token[right_index].type == JIM_EXPROP_COLON_LEFT && ternary_count == 1) {
13729
- return right_index;
13730
- }
13731
- right_index--;
13732
- }
13733
-
13734
-
13735
- return -1;
13736
-}
13737
-
13738
-static int ExprTernaryGetMoveIndices(ExprByteCode *expr, int right_index, int *prev_right_index, int *prev_left_index)
13739
-{
13740
- int i = right_index - 1;
13741
- int ternary_count = 1;
13742
-
13743
- while (i > 1) {
13744
- if (expr->token[i].type == JIM_EXPROP_TERNARY_LEFT) {
13745
- if (--ternary_count == 0 && expr->token[i - 2].type == JIM_EXPROP_COLON_RIGHT) {
13746
- *prev_right_index = i - 2;
13747
- *prev_left_index = ExprTernaryGetColonLeftIndex(expr, *prev_right_index);
13748
- return 1;
13749
- }
13750
- }
13751
- else if (expr->token[i].type == JIM_EXPROP_COLON_RIGHT) {
13752
- if (ternary_count == 0) {
13753
- return 0;
13754
- }
13755
- ternary_count++;
13756
- }
13757
- i--;
13758
- }
13759
- return 0;
13760
-}
13761
-
13762
-static void ExprTernaryReorderExpression(Jim_Interp *interp, ExprByteCode *expr)
13763
-{
13764
- int i;
13765
-
13766
- for (i = expr->len - 1; i > 1; i--) {
13767
- int prev_right_index;
13768
- int prev_left_index;
13769
- int j;
13770
- ScriptToken tmp;
13771
-
13772
- if (expr->token[i].type != JIM_EXPROP_COLON_RIGHT) {
13773
- continue;
13774
- }
13775
-
13776
-
13777
- if (ExprTernaryGetMoveIndices(expr, i, &prev_right_index, &prev_left_index) == 0) {
13778
- continue;
13779
- }
13780
-
13781
- tmp = expr->token[prev_right_index];
13782
- for (j = prev_right_index; j < i; j++) {
13783
- expr->token[j] = expr->token[j + 1];
13784
- }
13785
- expr->token[i] = tmp;
13786
-
13787
- JimWideValue(expr->token[prev_left_index-1].objPtr) += (i - prev_right_index);
13788
-
13789
-
13790
- i++;
13791
- }
13792
-}
13793
-
13794
-static ExprByteCode *ExprCreateByteCode(Jim_Interp *interp, const ParseTokenList *tokenlist, Jim_Obj *fileNameObj)
13795
-{
13535
+struct ExprBuilder {
13536
+ int parencount;
13537
+ int level;
13538
+ ParseToken *token;
13539
+ ParseToken *first_token;
1379613540
Jim_Stack stack;
13797
- ExprByteCode *expr;
13798
- int ok = 1;
13541
+ Jim_Obj *exprObjPtr;
13542
+ Jim_Obj *fileNameObj;
13543
+ struct JimExprNode *nodes;
13544
+ struct JimExprNode *next;
13545
+};
13546
+
13547
+#ifdef DEBUG_SHOW_EXPR
13548
+static void JimShowExprNode(struct JimExprNode *node, int level)
13549
+{
1379913550
int i;
13800
- int prevtt = JIM_TT_NONE;
13801
- int have_ternary = 0;
13551
+ for (i = 0; i < level; i++) {
13552
+ printf(" ");
13553
+ }
13554
+ if (TOKEN_IS_EXPR_OP(node->type)) {
13555
+ printf("%s\n", jim_tt_name(node->type));
13556
+ if (node->left) {
13557
+ JimShowExprNode(node->left, level + 1);
13558
+ }
13559
+ if (node->right) {
13560
+ JimShowExprNode(node->right, level + 1);
13561
+ }
13562
+ if (node->ternary) {
13563
+ JimShowExprNode(node->ternary, level + 1);
13564
+ }
13565
+ }
13566
+ else {
13567
+ printf("[%s] %s\n", jim_tt_name(node->type), Jim_String(node->objPtr));
13568
+ }
13569
+}
13570
+#endif
1380213571
13803
-
13804
- int count = tokenlist->count - 1;
13572
+#define EXPR_UNTIL_CLOSE 0x0001
13573
+#define EXPR_FUNC_ARGS 0x0002
13574
+#define EXPR_TERNARY 0x0004
13575
+
13576
+static int ExprTreeBuildTree(Jim_Interp *interp, struct ExprBuilder *builder, int precedence, int flags, int exp_numterms)
13577
+{
13578
+ int rc;
13579
+ struct JimExprNode *node;
13580
+
13581
+ int exp_stacklen = builder->stack.len + exp_numterms;
13582
+
13583
+ if (builder->level++ > 200) {
13584
+ Jim_SetResultString(interp, "Expression too complex", -1);
13585
+ return JIM_ERR;
13586
+ }
13587
+
13588
+ while (builder->token->type != JIM_TT_EOL) {
13589
+ ParseToken *t = builder->token++;
13590
+ int prevtt;
13591
+
13592
+ if (t == builder->first_token) {
13593
+ prevtt = JIM_TT_NONE;
13594
+ }
13595
+ else {
13596
+ prevtt = t[-1].type;
13597
+ }
13598
+
13599
+ if (t->type == JIM_TT_SUBEXPR_START) {
13600
+ if (builder->stack.len == exp_stacklen) {
13601
+ Jim_SetResultFormatted(interp, "unexpected open parenthesis in expression: \"%#s\"", builder->exprObjPtr);
13602
+ return JIM_ERR;
13603
+ }
13604
+ builder->parencount++;
13605
+ rc = ExprTreeBuildTree(interp, builder, 0, EXPR_UNTIL_CLOSE, 1);
13606
+ if (rc != JIM_OK) {
13607
+ return rc;
13608
+ }
13609
+
13610
+ }
13611
+ else if (t->type == JIM_TT_SUBEXPR_END) {
13612
+ if (!(flags & EXPR_UNTIL_CLOSE)) {
13613
+ if (builder->stack.len == exp_stacklen && builder->level > 1) {
13614
+ builder->token--;
13615
+ builder->level--;
13616
+ return JIM_OK;
13617
+ }
13618
+ Jim_SetResultFormatted(interp, "unexpected closing parenthesis in expression: \"%#s\"", builder->exprObjPtr);
13619
+ return JIM_ERR;
13620
+ }
13621
+ builder->parencount--;
13622
+ if (builder->stack.len == exp_stacklen) {
13623
+
13624
+ break;
13625
+ }
13626
+ }
13627
+ else if (t->type == JIM_TT_SUBEXPR_COMMA) {
13628
+ if (!(flags & EXPR_FUNC_ARGS)) {
13629
+ if (builder->stack.len == exp_stacklen) {
13630
+
13631
+ builder->token--;
13632
+ builder->level--;
13633
+ return JIM_OK;
13634
+ }
13635
+ Jim_SetResultFormatted(interp, "unexpected comma in expression: \"%#s\"", builder->exprObjPtr);
13636
+ return JIM_ERR;
13637
+ }
13638
+ else {
13639
+
13640
+ if (builder->stack.len > exp_stacklen) {
13641
+ Jim_SetResultFormatted(interp, "too many arguments to math function");
13642
+ return JIM_ERR;
13643
+ }
13644
+ }
13645
+
13646
+ }
13647
+ else if (t->type == JIM_EXPROP_COLON) {
13648
+ if (!(flags & EXPR_TERNARY)) {
13649
+ if (builder->level != 1) {
13650
+
13651
+ builder->token--;
13652
+ builder->level--;
13653
+ return JIM_OK;
13654
+ }
13655
+ Jim_SetResultFormatted(interp, ": without ? in expression: \"%#s\"", builder->exprObjPtr);
13656
+ return JIM_ERR;
13657
+ }
13658
+ if (builder->stack.len == exp_stacklen) {
13659
+
13660
+ builder->token--;
13661
+ builder->level--;
13662
+ return JIM_OK;
13663
+ }
13664
+
13665
+ }
13666
+ else if (TOKEN_IS_EXPR_OP(t->type)) {
13667
+ const struct Jim_ExprOperator *op;
13668
+
13669
+
13670
+ if (TOKEN_IS_EXPR_OP(prevtt) || TOKEN_IS_EXPR_START(prevtt)) {
13671
+ if (t->type == JIM_EXPROP_SUB) {
13672
+ t->type = JIM_EXPROP_UNARYMINUS;
13673
+ }
13674
+ else if (t->type == JIM_EXPROP_ADD) {
13675
+ t->type = JIM_EXPROP_UNARYPLUS;
13676
+ }
13677
+ }
13678
+
13679
+ op = JimExprOperatorInfoByOpcode(t->type);
13680
+
13681
+ if (op->precedence < precedence || (!(op->attr & OP_RIGHT_ASSOC) && op->precedence == precedence)) {
13682
+
13683
+ builder->token--;
13684
+ break;
13685
+ }
13686
+
13687
+ if (op->attr & OP_FUNC) {
13688
+ if (builder->token->type != JIM_TT_SUBEXPR_START) {
13689
+ Jim_SetResultString(interp, "missing arguments for math function", -1);
13690
+ return JIM_ERR;
13691
+ }
13692
+ builder->token++;
13693
+ if (op->arity == 0) {
13694
+ if (builder->token->type != JIM_TT_SUBEXPR_END) {
13695
+ Jim_SetResultString(interp, "too many arguments for math function", -1);
13696
+ return JIM_ERR;
13697
+ }
13698
+ builder->token++;
13699
+ goto noargs;
13700
+ }
13701
+ builder->parencount++;
13702
+
13703
+
13704
+ rc = ExprTreeBuildTree(interp, builder, 0, EXPR_FUNC_ARGS | EXPR_UNTIL_CLOSE, op->arity);
13705
+ }
13706
+ else if (t->type == JIM_EXPROP_TERNARY) {
13707
+
13708
+ rc = ExprTreeBuildTree(interp, builder, op->precedence, EXPR_TERNARY, 2);
13709
+ }
13710
+ else {
13711
+ rc = ExprTreeBuildTree(interp, builder, op->precedence, 0, 1);
13712
+ }
13713
+
13714
+ if (rc != JIM_OK) {
13715
+ return rc;
13716
+ }
13717
+
13718
+noargs:
13719
+ node = builder->next++;
13720
+ node->type = t->type;
13721
+
13722
+ if (op->arity >= 3) {
13723
+ node->ternary = Jim_StackPop(&builder->stack);
13724
+ if (node->ternary == NULL) {
13725
+ goto missingoperand;
13726
+ }
13727
+ }
13728
+ if (op->arity >= 2) {
13729
+ node->right = Jim_StackPop(&builder->stack);
13730
+ if (node->right == NULL) {
13731
+ goto missingoperand;
13732
+ }
13733
+ }
13734
+ if (op->arity >= 1) {
13735
+ node->left = Jim_StackPop(&builder->stack);
13736
+ if (node->left == NULL) {
13737
+missingoperand:
13738
+ Jim_SetResultFormatted(interp, "missing operand to %s in expression: \"%#s\"", op->name, builder->exprObjPtr);
13739
+ builder->next--;
13740
+ return JIM_ERR;
13741
+
13742
+ }
13743
+ }
13744
+
13745
+
13746
+ Jim_StackPush(&builder->stack, node);
13747
+ }
13748
+ else {
13749
+ Jim_Obj *objPtr = NULL;
13750
+
13751
+
13752
+
13753
+
13754
+ if (!TOKEN_IS_EXPR_START(prevtt) && !TOKEN_IS_EXPR_OP(prevtt)) {
13755
+ Jim_SetResultFormatted(interp, "missing operator in expression: \"%#s\"", builder->exprObjPtr);
13756
+ return JIM_ERR;
13757
+ }
13758
+
13759
+
13760
+ if (t->type == JIM_TT_EXPR_INT || t->type == JIM_TT_EXPR_DOUBLE) {
13761
+ char *endptr;
13762
+ if (t->type == JIM_TT_EXPR_INT) {
13763
+ objPtr = Jim_NewIntObj(interp, jim_strtoull(t->token, &endptr));
13764
+ }
13765
+ else {
13766
+ objPtr = Jim_NewDoubleObj(interp, strtod(t->token, &endptr));
13767
+ }
13768
+ if (endptr != t->token + t->len) {
13769
+
13770
+ Jim_FreeNewObj(interp, objPtr);
13771
+ objPtr = NULL;
13772
+ }
13773
+ }
13774
+
13775
+ if (!objPtr) {
13776
+
13777
+ objPtr = Jim_NewStringObj(interp, t->token, t->len);
13778
+ if (t->type == JIM_TT_CMD) {
13779
+
13780
+ JimSetSourceInfo(interp, objPtr, builder->fileNameObj, t->line);
13781
+ }
13782
+ }
13783
+
13784
+
13785
+ node = builder->next++;
13786
+ node->objPtr = objPtr;
13787
+ Jim_IncrRefCount(node->objPtr);
13788
+ node->type = t->type;
13789
+ Jim_StackPush(&builder->stack, node);
13790
+ }
13791
+ }
13792
+
13793
+ if (builder->stack.len == exp_stacklen) {
13794
+ builder->level--;
13795
+ return JIM_OK;
13796
+ }
13797
+
13798
+ if ((flags & EXPR_FUNC_ARGS)) {
13799
+ Jim_SetResultFormatted(interp, "too %s arguments for math function", (builder->stack.len < exp_stacklen) ? "few" : "many");
13800
+ }
13801
+ else {
13802
+ if (builder->stack.len < exp_stacklen) {
13803
+ if (builder->level == 0) {
13804
+ Jim_SetResultFormatted(interp, "empty expression");
13805
+ }
13806
+ else {
13807
+ Jim_SetResultFormatted(interp, "syntax error in expression \"%#s\": premature end of expression", builder->exprObjPtr);
13808
+ }
13809
+ }
13810
+ else {
13811
+ Jim_SetResultFormatted(interp, "extra terms after expression");
13812
+ }
13813
+ }
13814
+
13815
+ return JIM_ERR;
13816
+}
13817
+
13818
+static struct ExprTree *ExprTreeCreateTree(Jim_Interp *interp, const ParseTokenList *tokenlist, Jim_Obj *exprObjPtr, Jim_Obj *fileNameObj)
13819
+{
13820
+ struct ExprTree *expr;
13821
+ struct ExprBuilder builder;
13822
+ int rc;
13823
+ struct JimExprNode *top = NULL;
13824
+
13825
+ builder.parencount = 0;
13826
+ builder.level = 0;
13827
+ builder.token = builder.first_token = tokenlist->list;
13828
+ builder.exprObjPtr = exprObjPtr;
13829
+ builder.fileNameObj = fileNameObj;
13830
+
13831
+ builder.nodes = malloc(sizeof(struct JimExprNode) * (tokenlist->count - 1));
13832
+ memset(builder.nodes, 0, sizeof(struct JimExprNode) * (tokenlist->count - 1));
13833
+ builder.next = builder.nodes;
13834
+ Jim_InitStack(&builder.stack);
13835
+
13836
+ rc = ExprTreeBuildTree(interp, &builder, 0, 0, 1);
13837
+
13838
+ if (rc == JIM_OK) {
13839
+ top = Jim_StackPop(&builder.stack);
13840
+
13841
+ if (builder.parencount) {
13842
+ Jim_SetResultString(interp, "missing close parenthesis", -1);
13843
+ rc = JIM_ERR;
13844
+ }
13845
+ }
13846
+
13847
+
13848
+ Jim_FreeStack(&builder.stack);
13849
+
13850
+ if (rc != JIM_OK) {
13851
+ ExprTreeFreeNodes(interp, builder.nodes, builder.next - builder.nodes);
13852
+ return NULL;
13853
+ }
1380513854
1380613855
expr = Jim_Alloc(sizeof(*expr));
1380713856
expr->inUse = 1;
13808
- expr->len = 0;
13809
-
13810
- Jim_InitStack(&stack);
13811
-
13812
- for (i = 0; i < tokenlist->count; i++) {
13813
- ParseToken *t = &tokenlist->list[i];
13814
- const struct Jim_ExprOperator *op = JimExprOperatorInfoByOpcode(t->type);
13815
-
13816
- if (op->lazy == LAZY_OP) {
13817
- count += 2;
13818
-
13819
- if (t->type == JIM_EXPROP_TERNARY) {
13820
- have_ternary = 1;
13821
- }
13822
- }
13823
- }
13824
-
13825
- expr->token = Jim_Alloc(sizeof(ScriptToken) * count);
13826
-
13827
- for (i = 0; i < tokenlist->count && ok; i++) {
13828
- ParseToken *t = &tokenlist->list[i];
13829
-
13830
-
13831
- struct ScriptToken *token = &expr->token[expr->len];
13832
-
13833
- if (t->type == JIM_TT_EOL) {
13834
- break;
13835
- }
13836
-
13837
- switch (t->type) {
13838
- case JIM_TT_STR:
13839
- case JIM_TT_ESC:
13840
- case JIM_TT_VAR:
13841
- case JIM_TT_DICTSUGAR:
13842
- case JIM_TT_EXPRSUGAR:
13843
- case JIM_TT_CMD:
13844
- token->type = t->type;
13845
-strexpr:
13846
- token->objPtr = Jim_NewStringObj(interp, t->token, t->len);
13847
- if (t->type == JIM_TT_CMD) {
13848
-
13849
- JimSetSourceInfo(interp, token->objPtr, fileNameObj, t->line);
13850
- }
13851
- expr->len++;
13852
- break;
13853
-
13854
- case JIM_TT_EXPR_INT:
13855
- case JIM_TT_EXPR_DOUBLE:
13856
- {
13857
- char *endptr;
13858
- if (t->type == JIM_TT_EXPR_INT) {
13859
- token->objPtr = Jim_NewIntObj(interp, jim_strtoull(t->token, &endptr));
13860
- }
13861
- else {
13862
- token->objPtr = Jim_NewDoubleObj(interp, strtod(t->token, &endptr));
13863
- }
13864
- if (endptr != t->token + t->len) {
13865
-
13866
- Jim_FreeNewObj(interp, token->objPtr);
13867
- token->type = JIM_TT_STR;
13868
- goto strexpr;
13869
- }
13870
- token->type = t->type;
13871
- expr->len++;
13872
- }
13873
- break;
13874
-
13875
- case JIM_TT_SUBEXPR_START:
13876
- Jim_StackPush(&stack, t);
13877
- prevtt = JIM_TT_NONE;
13878
- continue;
13879
-
13880
- case JIM_TT_SUBEXPR_COMMA:
13881
-
13882
- continue;
13883
-
13884
- case JIM_TT_SUBEXPR_END:
13885
- ok = 0;
13886
- while (Jim_StackLen(&stack)) {
13887
- ParseToken *tt = Jim_StackPop(&stack);
13888
-
13889
- if (tt->type == JIM_TT_SUBEXPR_START) {
13890
- ok = 1;
13891
- break;
13892
- }
13893
-
13894
- if (ExprAddOperator(interp, expr, tt) != JIM_OK) {
13895
- goto err;
13896
- }
13897
- }
13898
- if (!ok) {
13899
- Jim_SetResultString(interp, "Unexpected close parenthesis", -1);
13900
- goto err;
13901
- }
13902
- break;
13903
-
13904
-
13905
- default:{
13906
-
13907
- const struct Jim_ExprOperator *op;
13908
- ParseToken *tt;
13909
-
13910
-
13911
- if (prevtt == JIM_TT_NONE || prevtt >= JIM_TT_EXPR_OP) {
13912
- if (t->type == JIM_EXPROP_SUB) {
13913
- t->type = JIM_EXPROP_UNARYMINUS;
13914
- }
13915
- else if (t->type == JIM_EXPROP_ADD) {
13916
- t->type = JIM_EXPROP_UNARYPLUS;
13917
- }
13918
- }
13919
-
13920
- op = JimExprOperatorInfoByOpcode(t->type);
13921
-
13922
-
13923
- while ((tt = Jim_StackPeek(&stack)) != NULL) {
13924
- const struct Jim_ExprOperator *tt_op =
13925
- JimExprOperatorInfoByOpcode(tt->type);
13926
-
13927
-
13928
-
13929
- if (op->arity != 1 && tt_op->precedence >= op->precedence) {
13930
- if (ExprAddOperator(interp, expr, tt) != JIM_OK) {
13931
- ok = 0;
13932
- goto err;
13933
- }
13934
- Jim_StackPop(&stack);
13935
- }
13936
- else {
13937
- break;
13938
- }
13939
- }
13940
- Jim_StackPush(&stack, t);
13941
- break;
13942
- }
13943
- }
13944
- prevtt = t->type;
13945
- }
13946
-
13947
-
13948
- while (Jim_StackLen(&stack)) {
13949
- ParseToken *tt = Jim_StackPop(&stack);
13950
-
13951
- if (tt->type == JIM_TT_SUBEXPR_START) {
13952
- ok = 0;
13953
- Jim_SetResultString(interp, "Missing close parenthesis", -1);
13954
- goto err;
13955
- }
13956
- if (ExprAddOperator(interp, expr, tt) != JIM_OK) {
13957
- ok = 0;
13958
- goto err;
13959
- }
13960
- }
13961
-
13962
- if (have_ternary) {
13963
- ExprTernaryReorderExpression(interp, expr);
13964
- }
13965
-
13966
- err:
13967
-
13968
- Jim_FreeStack(&stack);
13969
-
13970
- for (i = 0; i < expr->len; i++) {
13971
- Jim_IncrRefCount(expr->token[i].objPtr);
13972
- }
13973
-
13974
- if (!ok) {
13975
- ExprFreeByteCode(interp, expr);
13976
- return NULL;
13977
- }
13857
+ expr->expr = top;
13858
+ expr->nodes = builder.nodes;
13859
+ expr->len = builder.next - builder.nodes;
13860
+
13861
+ assert(expr->len <= tokenlist->count - 1);
1397813862
1397913863
return expr;
1398013864
}
13981
-
1398213865
1398313866
static int SetExprFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr)
1398413867
{
1398513868
int exprTextLen;
1398613869
const char *exprText;
1398713870
struct JimParserCtx parser;
13988
- struct ExprByteCode *expr;
13871
+ struct ExprTree *expr;
1398913872
ParseTokenList tokenlist;
1399013873
int line;
1399113874
Jim_Obj *fileNameObj;
1399213875
int rc = JIM_ERR;
1399313876
13994
-
13877
+
1399513878
if (objPtr->typePtr == &sourceObjType) {
1399613879
fileNameObj = objPtr->internalRep.sourceValue.fileNameObj;
1399713880
line = objPtr->internalRep.sourceValue.lineNumber;
1399813881
}
1399913882
else {
@@ -14002,18 +13885,17 @@
1400213885
}
1400313886
Jim_IncrRefCount(fileNameObj);
1400413887
1400513888
exprText = Jim_GetString(objPtr, &exprTextLen);
1400613889
14007
-
13890
+
1400813891
ScriptTokenListInit(&tokenlist);
1400913892
1401013893
JimParserInit(&parser, exprText, exprTextLen, line);
1401113894
while (!parser.eof) {
1401213895
if (JimParseExpression(&parser) != JIM_OK) {
1401313896
ScriptTokenListFree(&tokenlist);
14014
- invalidexpr:
1401513897
Jim_SetResultFormatted(interp, "syntax error in expression: \"%#s\"", objPtr);
1401613898
expr = NULL;
1401713899
goto err;
1401813900
}
1401913901
@@ -14036,125 +13918,174 @@
1403613918
ScriptTokenListFree(&tokenlist);
1403713919
Jim_DecrRefCount(interp, fileNameObj);
1403813920
return JIM_ERR;
1403913921
}
1404013922
14041
-
14042
- expr = ExprCreateByteCode(interp, &tokenlist, fileNameObj);
1404313923
14044
-
13924
+ expr = ExprTreeCreateTree(interp, &tokenlist, objPtr, fileNameObj);
13925
+
13926
+
1404513927
ScriptTokenListFree(&tokenlist);
1404613928
1404713929
if (!expr) {
1404813930
goto err;
1404913931
}
1405013932
1405113933
#ifdef DEBUG_SHOW_EXPR
14052
- {
14053
- int i;
14054
-
14055
- printf("==== Expr ====\n");
14056
- for (i = 0; i < expr->len; i++) {
14057
- ScriptToken *t = &expr->token[i];
14058
-
14059
- printf("[%2d] %s '%s'\n", i, jim_tt_name(t->type), Jim_String(t->objPtr));
14060
- }
14061
- }
13934
+ printf("==== Expr ====\n");
13935
+ JimShowExprNode(expr->expr, 0);
1406213936
#endif
1406313937
14064
-
14065
- if (ExprCheckCorrectness(expr) != JIM_OK) {
14066
- ExprFreeByteCode(interp, expr);
14067
- goto invalidexpr;
14068
- }
14069
-
1407013938
rc = JIM_OK;
1407113939
1407213940
err:
14073
-
13941
+
1407413942
Jim_DecrRefCount(interp, fileNameObj);
1407513943
Jim_FreeIntRep(interp, objPtr);
1407613944
Jim_SetIntRepPtr(objPtr, expr);
1407713945
objPtr->typePtr = &exprObjType;
1407813946
return rc;
1407913947
}
1408013948
14081
-static ExprByteCode *JimGetExpression(Jim_Interp *interp, Jim_Obj *objPtr)
13949
+static struct ExprTree *JimGetExpression(Jim_Interp *interp, Jim_Obj *objPtr)
1408213950
{
1408313951
if (objPtr->typePtr != &exprObjType) {
1408413952
if (SetExprFromAny(interp, objPtr) != JIM_OK) {
1408513953
return NULL;
1408613954
}
1408713955
}
14088
- return (ExprByteCode *) Jim_GetIntRepPtr(objPtr);
13956
+ return (struct ExprTree *) Jim_GetIntRepPtr(objPtr);
1408913957
}
1409013958
1409113959
#ifdef JIM_OPTIMIZATION
14092
-static Jim_Obj *JimExprIntValOrVar(Jim_Interp *interp, const ScriptToken *token)
14093
-{
14094
- if (token->type == JIM_TT_EXPR_INT)
14095
- return token->objPtr;
14096
- else if (token->type == JIM_TT_VAR)
14097
- return Jim_GetVariable(interp, token->objPtr, JIM_NONE);
14098
- else if (token->type == JIM_TT_DICTSUGAR)
14099
- return JimExpandDictSugar(interp, token->objPtr);
13960
+static Jim_Obj *JimExprIntValOrVar(Jim_Interp *interp, struct JimExprNode *node)
13961
+{
13962
+ if (node->type == JIM_TT_EXPR_INT)
13963
+ return node->objPtr;
13964
+ else if (node->type == JIM_TT_VAR)
13965
+ return Jim_GetVariable(interp, node->objPtr, JIM_NONE);
13966
+ else if (node->type == JIM_TT_DICTSUGAR)
13967
+ return JimExpandDictSugar(interp, node->objPtr);
1410013968
else
1410113969
return NULL;
1410213970
}
1410313971
#endif
1410413972
14105
-#define JIM_EE_STATICSTACK_LEN 10
14106
-
14107
-int Jim_EvalExpression(Jim_Interp *interp, Jim_Obj *exprObjPtr, Jim_Obj **exprResultPtrPtr)
14108
-{
14109
- ExprByteCode *expr;
14110
- Jim_Obj *staticStack[JIM_EE_STATICSTACK_LEN];
14111
- int i;
14112
- int retcode = JIM_OK;
14113
- struct JimExprState e;
13973
+
13974
+static int JimExprEvalTermNode(Jim_Interp *interp, struct JimExprNode *node)
13975
+{
13976
+ if (TOKEN_IS_EXPR_OP(node->type)) {
13977
+ const struct Jim_ExprOperator *op = JimExprOperatorInfoByOpcode(node->type);
13978
+ return op->funcop(interp, node);
13979
+ }
13980
+ else {
13981
+ Jim_Obj *objPtr;
13982
+
13983
+
13984
+ switch (node->type) {
13985
+ case JIM_TT_EXPR_INT:
13986
+ case JIM_TT_EXPR_DOUBLE:
13987
+ case JIM_TT_EXPR_BOOLEAN:
13988
+ case JIM_TT_STR:
13989
+ Jim_SetResult(interp, node->objPtr);
13990
+ return JIM_OK;
13991
+
13992
+ case JIM_TT_VAR:
13993
+ objPtr = Jim_GetVariable(interp, node->objPtr, JIM_ERRMSG);
13994
+ if (objPtr) {
13995
+ Jim_SetResult(interp, objPtr);
13996
+ return JIM_OK;
13997
+ }
13998
+ return JIM_ERR;
13999
+
14000
+ case JIM_TT_DICTSUGAR:
14001
+ objPtr = JimExpandDictSugar(interp, node->objPtr);
14002
+ if (objPtr) {
14003
+ Jim_SetResult(interp, objPtr);
14004
+ return JIM_OK;
14005
+ }
14006
+ return JIM_ERR;
14007
+
14008
+ case JIM_TT_ESC:
14009
+ if (Jim_SubstObj(interp, node->objPtr, &objPtr, JIM_NONE) == JIM_OK) {
14010
+ Jim_SetResult(interp, objPtr);
14011
+ return JIM_OK;
14012
+ }
14013
+ return JIM_ERR;
14014
+
14015
+ case JIM_TT_CMD:
14016
+ return Jim_EvalObj(interp, node->objPtr);
14017
+
14018
+ default:
14019
+
14020
+ return JIM_ERR;
14021
+ }
14022
+ }
14023
+}
14024
+
14025
+static int JimExprGetTerm(Jim_Interp *interp, struct JimExprNode *node, Jim_Obj **objPtrPtr)
14026
+{
14027
+ int rc = JimExprEvalTermNode(interp, node);
14028
+ if (rc == JIM_OK) {
14029
+ *objPtrPtr = Jim_GetResult(interp);
14030
+ Jim_IncrRefCount(*objPtrPtr);
14031
+ }
14032
+ return rc;
14033
+}
14034
+
14035
+static int JimExprGetTermBoolean(Jim_Interp *interp, struct JimExprNode *node)
14036
+{
14037
+ if (JimExprEvalTermNode(interp, node) == JIM_OK) {
14038
+ return ExprBool(interp, Jim_GetResult(interp));
14039
+ }
14040
+ return -1;
14041
+}
14042
+
14043
+int Jim_EvalExpression(Jim_Interp *interp, Jim_Obj *exprObjPtr)
14044
+{
14045
+ struct ExprTree *expr;
14046
+ int retcode = JIM_OK;
1411414047
1411514048
expr = JimGetExpression(interp, exprObjPtr);
1411614049
if (!expr) {
14117
- return JIM_ERR;
14050
+ return JIM_ERR;
1411814051
}
1411914052
1412014053
#ifdef JIM_OPTIMIZATION
1412114054
{
1412214055
Jim_Obj *objPtr;
1412314056
1412414057
1412514058
switch (expr->len) {
1412614059
case 1:
14127
- objPtr = JimExprIntValOrVar(interp, &expr->token[0]);
14060
+ objPtr = JimExprIntValOrVar(interp, expr->expr);
1412814061
if (objPtr) {
14129
- Jim_IncrRefCount(objPtr);
14130
- *exprResultPtrPtr = objPtr;
14062
+ Jim_SetResult(interp, objPtr);
1413114063
return JIM_OK;
1413214064
}
1413314065
break;
1413414066
1413514067
case 2:
14136
- if (expr->token[1].type == JIM_EXPROP_NOT) {
14137
- objPtr = JimExprIntValOrVar(interp, &expr->token[0]);
14068
+ if (expr->expr->type == JIM_EXPROP_NOT) {
14069
+ objPtr = JimExprIntValOrVar(interp, expr->expr->left);
1413814070
1413914071
if (objPtr && JimIsWide(objPtr)) {
14140
- *exprResultPtrPtr = JimWideValue(objPtr) ? interp->falseObj : interp->trueObj;
14141
- Jim_IncrRefCount(*exprResultPtrPtr);
14072
+ Jim_SetResult(interp, JimWideValue(objPtr) ? interp->falseObj : interp->trueObj);
1414214073
return JIM_OK;
1414314074
}
1414414075
}
1414514076
break;
1414614077
1414714078
case 3:
14148
- objPtr = JimExprIntValOrVar(interp, &expr->token[0]);
14079
+ objPtr = JimExprIntValOrVar(interp, expr->expr->left);
1414914080
if (objPtr && JimIsWide(objPtr)) {
14150
- Jim_Obj *objPtr2 = JimExprIntValOrVar(interp, &expr->token[1]);
14081
+ Jim_Obj *objPtr2 = JimExprIntValOrVar(interp, expr->expr->right);
1415114082
if (objPtr2 && JimIsWide(objPtr2)) {
1415214083
jim_wide wideValueA = JimWideValue(objPtr);
1415314084
jim_wide wideValueB = JimWideValue(objPtr2);
1415414085
int cmpRes;
14155
- switch (expr->token[2].type) {
14086
+ switch (expr->expr->type) {
1415614087
case JIM_EXPROP_LT:
1415714088
cmpRes = wideValueA < wideValueB;
1415814089
break;
1415914090
case JIM_EXPROP_LTE:
1416014091
cmpRes = wideValueA <= wideValueB;
@@ -14172,12 +14103,11 @@
1417214103
cmpRes = wideValueA != wideValueB;
1417314104
break;
1417414105
default:
1417514106
goto noopt;
1417614107
}
14177
- *exprResultPtrPtr = cmpRes ? interp->trueObj : interp->falseObj;
14178
- Jim_IncrRefCount(*exprResultPtrPtr);
14108
+ Jim_SetResult(interp, cmpRes ? interp->trueObj : interp->falseObj);
1417914109
return JIM_OK;
1418014110
}
1418114111
}
1418214112
break;
1418314113
}
@@ -14185,145 +14115,64 @@
1418514115
noopt:
1418614116
#endif
1418714117
1418814118
expr->inUse++;
1418914119
14190
-
14191
-
14192
- if (expr->len > JIM_EE_STATICSTACK_LEN)
14193
- e.stack = Jim_Alloc(sizeof(Jim_Obj *) * expr->len);
14194
- else
14195
- e.stack = staticStack;
14196
-
14197
- e.stacklen = 0;
14198
-
14199
-
14200
- for (i = 0; i < expr->len && retcode == JIM_OK; i++) {
14201
- Jim_Obj *objPtr;
14202
-
14203
- switch (expr->token[i].type) {
14204
- case JIM_TT_EXPR_INT:
14205
- case JIM_TT_EXPR_DOUBLE:
14206
- case JIM_TT_STR:
14207
- ExprPush(&e, expr->token[i].objPtr);
14208
- break;
14209
-
14210
- case JIM_TT_VAR:
14211
- objPtr = Jim_GetVariable(interp, expr->token[i].objPtr, JIM_ERRMSG);
14212
- if (objPtr) {
14213
- ExprPush(&e, objPtr);
14214
- }
14215
- else {
14216
- retcode = JIM_ERR;
14217
- }
14218
- break;
14219
-
14220
- case JIM_TT_DICTSUGAR:
14221
- objPtr = JimExpandDictSugar(interp, expr->token[i].objPtr);
14222
- if (objPtr) {
14223
- ExprPush(&e, objPtr);
14224
- }
14225
- else {
14226
- retcode = JIM_ERR;
14227
- }
14228
- break;
14229
-
14230
- case JIM_TT_ESC:
14231
- retcode = Jim_SubstObj(interp, expr->token[i].objPtr, &objPtr, JIM_NONE);
14232
- if (retcode == JIM_OK) {
14233
- ExprPush(&e, objPtr);
14234
- }
14235
- break;
14236
-
14237
- case JIM_TT_CMD:
14238
- retcode = Jim_EvalObj(interp, expr->token[i].objPtr);
14239
- if (retcode == JIM_OK) {
14240
- ExprPush(&e, Jim_GetResult(interp));
14241
- }
14242
- break;
14243
-
14244
- default:{
14245
-
14246
- e.skip = 0;
14247
- e.opcode = expr->token[i].type;
14248
-
14249
- retcode = JimExprOperatorInfoByOpcode(e.opcode)->funcop(interp, &e);
14250
-
14251
- i += e.skip;
14252
- continue;
14253
- }
14254
- }
14255
- }
14120
+
14121
+ retcode = JimExprEvalTermNode(interp, expr->expr);
1425614122
1425714123
expr->inUse--;
1425814124
14259
- if (retcode == JIM_OK) {
14260
- *exprResultPtrPtr = ExprPop(&e);
14261
- }
14262
- else {
14263
- for (i = 0; i < e.stacklen; i++) {
14264
- Jim_DecrRefCount(interp, e.stack[i]);
14265
- }
14266
- }
14267
- if (e.stack != staticStack) {
14268
- Jim_Free(e.stack);
14269
- }
1427014125
return retcode;
1427114126
}
1427214127
1427314128
int Jim_GetBoolFromExpr(Jim_Interp *interp, Jim_Obj *exprObjPtr, int *boolPtr)
1427414129
{
14275
- int retcode;
14276
- jim_wide wideValue;
14277
- double doubleValue;
14278
- Jim_Obj *exprResultPtr;
14279
-
14280
- retcode = Jim_EvalExpression(interp, exprObjPtr, &exprResultPtr);
14281
- if (retcode != JIM_OK)
14282
- return retcode;
14283
-
14284
- if (JimGetWideNoErr(interp, exprResultPtr, &wideValue) != JIM_OK) {
14285
- if (Jim_GetDouble(interp, exprResultPtr, &doubleValue) != JIM_OK) {
14286
- Jim_DecrRefCount(interp, exprResultPtr);
14287
- return JIM_ERR;
14288
- }
14289
- else {
14290
- Jim_DecrRefCount(interp, exprResultPtr);
14291
- *boolPtr = doubleValue != 0;
14292
- return JIM_OK;
14293
- }
14294
- }
14295
- *boolPtr = wideValue != 0;
14296
-
14297
- Jim_DecrRefCount(interp, exprResultPtr);
14298
- return JIM_OK;
14130
+ int retcode = Jim_EvalExpression(interp, exprObjPtr);
14131
+
14132
+ if (retcode == JIM_OK) {
14133
+ switch (ExprBool(interp, Jim_GetResult(interp))) {
14134
+ case 0:
14135
+ *boolPtr = 0;
14136
+ break;
14137
+
14138
+ case 1:
14139
+ *boolPtr = 1;
14140
+ break;
14141
+
14142
+ case -1:
14143
+ retcode = JIM_ERR;
14144
+ break;
14145
+ }
14146
+ }
14147
+ return retcode;
1429914148
}
1430014149
1430114150
1430214151
1430314152
1430414153
typedef struct ScanFmtPartDescr
1430514154
{
14306
- char *arg;
14307
- char *prefix;
14308
- size_t width;
14309
- int pos;
14310
- char type;
14311
- char modifier;
14155
+ const char *arg;
14156
+ const char *prefix;
14157
+ size_t width;
14158
+ int pos;
14159
+ char type;
14160
+ char modifier;
1431214161
} ScanFmtPartDescr;
1431314162
1431414163
1431514164
typedef struct ScanFmtStringObj
1431614165
{
14317
- jim_wide size;
14318
- char *stringRep;
14319
- size_t count;
14320
- size_t convCount;
14321
- size_t maxPos;
14322
- const char *error;
14323
- char *scratch;
14324
- ScanFmtPartDescr descr[1];
14166
+ jim_wide size;
14167
+ char *stringRep;
14168
+ size_t count;
14169
+ size_t convCount;
14170
+ size_t maxPos;
14171
+ const char *error;
14172
+ char *scratch;
14173
+ ScanFmtPartDescr descr[1];
1432514174
} ScanFmtStringObj;
1432614175
1432714176
1432814177
static void FreeScanFmtInternalRep(Jim_Interp *interp, Jim_Obj *objPtr);
1432914178
static void DupScanFmtInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr);
@@ -14364,28 +14213,28 @@
1436414213
static int SetScanFmtFromAny(Jim_Interp *interp, Jim_Obj *objPtr)
1436514214
{
1436614215
ScanFmtStringObj *fmtObj;
1436714216
char *buffer;
1436814217
int maxCount, i, approxSize, lastPos = -1;
14369
- const char *fmt = objPtr->bytes;
14370
- int maxFmtLen = objPtr->length;
14218
+ const char *fmt = Jim_String(objPtr);
14219
+ int maxFmtLen = Jim_Length(objPtr);
1437114220
const char *fmtEnd = fmt + maxFmtLen;
1437214221
int curr;
1437314222
1437414223
Jim_FreeIntRep(interp, objPtr);
14375
-
14224
+
1437614225
for (i = 0, maxCount = 0; i < maxFmtLen; ++i)
1437714226
if (fmt[i] == '%')
1437814227
++maxCount;
14379
-
14380
- approxSize = sizeof(ScanFmtStringObj)
14381
- +(maxCount + 1) * sizeof(ScanFmtPartDescr)
14382
- +maxFmtLen * sizeof(char) + 3 + 1
14383
- + maxFmtLen * sizeof(char) + 1
14384
- + maxFmtLen * sizeof(char)
14385
- +(maxCount + 1) * sizeof(char)
14386
- +1;
14228
+
14229
+ approxSize = sizeof(ScanFmtStringObj)
14230
+ +(maxCount + 1) * sizeof(ScanFmtPartDescr)
14231
+ +maxFmtLen * sizeof(char) + 3 + 1
14232
+ + maxFmtLen * sizeof(char) + 1
14233
+ + maxFmtLen * sizeof(char)
14234
+ +(maxCount + 1) * sizeof(char)
14235
+ +1;
1438714236
fmtObj = (ScanFmtStringObj *) Jim_Alloc(approxSize);
1438814237
memset(fmtObj, 0, approxSize);
1438914238
fmtObj->size = approxSize;
1439014239
fmtObj->maxPos = 0;
1439114240
fmtObj->scratch = (char *)&fmtObj->descr[maxCount + 1];
@@ -14397,12 +14246,12 @@
1439714246
for (i = 0, curr = 0; fmt < fmtEnd; ++fmt) {
1439814247
int width = 0, skip;
1439914248
ScanFmtPartDescr *descr = &fmtObj->descr[curr];
1440014249
1440114250
fmtObj->count++;
14402
- descr->width = 0;
14403
-
14251
+ descr->width = 0;
14252
+
1440414253
if (*fmt != '%' || fmt[1] == '%') {
1440514254
descr->type = 0;
1440614255
descr->prefix = &buffer[i];
1440714256
for (; fmt < fmtEnd; ++fmt) {
1440814257
if (*fmt == '%') {
@@ -14412,65 +14261,70 @@
1441214261
}
1441314262
buffer[i++] = *fmt;
1441414263
}
1441514264
buffer[i++] = 0;
1441614265
}
14417
-
14266
+
1441814267
++fmt;
14419
-
14268
+
1442014269
if (fmt >= fmtEnd)
1442114270
goto done;
14422
- descr->pos = 0;
14271
+ descr->pos = 0;
1442314272
if (*fmt == '*') {
14424
- descr->pos = -1;
14273
+ descr->pos = -1;
1442514274
++fmt;
1442614275
}
1442714276
else
14428
- fmtObj->convCount++;
14429
-
14277
+ fmtObj->convCount++;
14278
+
1443014279
if (sscanf(fmt, "%d%n", &width, &skip) == 1) {
1443114280
fmt += skip;
14432
-
14281
+
1443314282
if (descr->pos != -1 && *fmt == '$') {
1443414283
int prev;
1443514284
1443614285
++fmt;
1443714286
descr->pos = width;
1443814287
width = 0;
14439
-
14288
+
1444014289
if ((lastPos == 0 && descr->pos > 0)
1444114290
|| (lastPos > 0 && descr->pos == 0)) {
1444214291
fmtObj->error = "cannot mix \"%\" and \"%n$\" conversion specifiers";
1444314292
return JIM_ERR;
1444414293
}
14445
-
14294
+
1444614295
for (prev = 0; prev < curr; ++prev) {
1444714296
if (fmtObj->descr[prev].pos == -1)
1444814297
continue;
1444914298
if (fmtObj->descr[prev].pos == descr->pos) {
1445014299
fmtObj->error =
1445114300
"variable is assigned by multiple \"%n$\" conversion specifiers";
1445214301
return JIM_ERR;
1445314302
}
1445414303
}
14455
-
14304
+ if (descr->pos < 0) {
14305
+ fmtObj->error =
14306
+ "\"%n$\" conversion specifier is negative";
14307
+ return JIM_ERR;
14308
+ }
14309
+
1445614310
if (sscanf(fmt, "%d%n", &width, &skip) == 1) {
1445714311
descr->width = width;
1445814312
fmt += skip;
1445914313
}
1446014314
if (descr->pos > 0 && (size_t) descr->pos > fmtObj->maxPos)
1446114315
fmtObj->maxPos = descr->pos;
1446214316
}
1446314317
else {
14464
-
14318
+
1446514319
descr->width = width;
1446614320
}
1446714321
}
14468
-
14322
+
1446914323
if (lastPos == -1)
1447014324
lastPos = descr->pos;
14471
-
14325
+
1447214326
if (*fmt == '[') {
1447314327
int swapped = 1, beg = i, end, j;
1447414328
1447514329
descr->type = '[';
1447614330
descr->arg = &buffer[i];
@@ -14485,11 +14339,11 @@
1448514339
fmtObj->error = "unmatched [ in format string";
1448614340
return JIM_ERR;
1448714341
}
1448814342
end = i;
1448914343
buffer[i++] = 0;
14490
-
14344
+
1449114345
while (swapped) {
1449214346
swapped = 0;
1449314347
for (j = beg + 1; j < end - 1; ++j) {
1449414348
if (buffer[j] == '-' && buffer[j - 1] > buffer[j + 1]) {
1449514349
char tmp = buffer[j - 1];
@@ -14500,13 +14354,18 @@
1450014354
}
1450114355
}
1450214356
}
1450314357
}
1450414358
else {
14505
-
14506
- if (strchr("hlL", *fmt) != 0)
14359
+
14360
+ if (fmt < fmtEnd && strchr("hlL", *fmt))
1450714361
descr->modifier = tolower((int)*fmt++);
14362
+
14363
+ if (fmt >= fmtEnd) {
14364
+ fmtObj->error = "missing scan conversion character";
14365
+ return JIM_ERR;
14366
+ }
1450814367
1450914368
descr->type = *fmt;
1451014369
if (strchr("efgcsndoxui", *fmt) == 0) {
1451114370
fmtObj->error = "bad scan conversion character";
1451214371
return JIM_ERR;
@@ -14543,11 +14402,11 @@
1454314402
while (*str) {
1454414403
int c;
1454514404
int n;
1454614405
1454714406
if (!sdescr && isspace(UCHAR(*str)))
14548
- break;
14407
+ break;
1454914408
1455014409
n = utf8_tounicode(str, &c);
1455114410
if (sdescr && !JimCharsetMatch(sdescr, c, JIM_CHARSET_SCAN))
1455214411
break;
1455314412
while (n--)
@@ -14566,89 +14425,89 @@
1456614425
size_t scanned = 0;
1456714426
size_t anchor = pos;
1456814427
int i;
1456914428
Jim_Obj *tmpObj = NULL;
1457014429
14571
-
14430
+
1457214431
*valObjPtr = 0;
1457314432
if (descr->prefix) {
1457414433
for (i = 0; pos < strLen && descr->prefix[i]; ++i) {
14575
-
14434
+
1457614435
if (isspace(UCHAR(descr->prefix[i])))
1457714436
while (pos < strLen && isspace(UCHAR(str[pos])))
1457814437
++pos;
1457914438
else if (descr->prefix[i] != str[pos])
14580
- break;
14439
+ break;
1458114440
else
14582
- ++pos;
14441
+ ++pos;
1458314442
}
1458414443
if (pos >= strLen) {
14585
- return -1;
14444
+ return -1;
1458614445
}
1458714446
else if (descr->prefix[i] != 0)
14588
- return 0;
14447
+ return 0;
1458914448
}
14590
-
14449
+
1459114450
if (descr->type != 'c' && descr->type != '[' && descr->type != 'n')
1459214451
while (isspace(UCHAR(str[pos])))
1459314452
++pos;
14594
-
14453
+
1459514454
scanned = pos - anchor;
1459614455
14597
-
14456
+
1459814457
if (descr->type == 'n') {
14599
-
14458
+
1460014459
*valObjPtr = Jim_NewIntObj(interp, anchor + scanned);
1460114460
}
1460214461
else if (pos >= strLen) {
14603
-
14462
+
1460414463
return -1;
1460514464
}
1460614465
else if (descr->type == 'c') {
1460714466
int c;
1460814467
scanned += utf8_tounicode(&str[pos], &c);
1460914468
*valObjPtr = Jim_NewIntObj(interp, c);
1461014469
return scanned;
1461114470
}
1461214471
else {
14613
-
14472
+
1461414473
if (descr->width > 0) {
1461514474
size_t sLen = utf8_strlen(&str[pos], strLen - pos);
1461614475
size_t tLen = descr->width > sLen ? sLen : descr->width;
1461714476
1461814477
tmpObj = Jim_NewStringObjUtf8(interp, str + pos, tLen);
1461914478
tok = tmpObj->bytes;
1462014479
}
1462114480
else {
14622
-
14481
+
1462314482
tok = &str[pos];
1462414483
}
1462514484
switch (descr->type) {
1462614485
case 'd':
1462714486
case 'o':
1462814487
case 'x':
1462914488
case 'u':
1463014489
case 'i':{
14631
- char *endp;
14490
+ char *endp;
1463214491
jim_wide w;
1463314492
1463414493
int base = descr->type == 'o' ? 8
1463514494
: descr->type == 'x' ? 16 : descr->type == 'i' ? 0 : 10;
1463614495
14637
-
14496
+
1463814497
if (base == 0) {
1463914498
w = jim_strtoull(tok, &endp);
1464014499
}
1464114500
else {
1464214501
w = strtoull(tok, &endp, base);
1464314502
}
1464414503
1464514504
if (endp != tok) {
14646
-
14505
+
1464714506
*valObjPtr = Jim_NewIntObj(interp, w);
1464814507
14649
-
14508
+
1465014509
scanned += endp - tok;
1465114510
}
1465214511
else {
1465314512
scanned = *tok ? 0 : -1;
1465414513
}
@@ -14665,13 +14524,13 @@
1466514524
case 'g':{
1466614525
char *endp;
1466714526
double value = strtod(tok, &endp);
1466814527
1466914528
if (endp != tok) {
14670
-
14529
+
1467114530
*valObjPtr = Jim_NewDoubleObj(interp, value);
14672
-
14531
+
1467314532
scanned += endp - tok;
1467414533
}
1467514534
else {
1467614535
scanned = *tok ? 0 : -1;
1467714536
}
@@ -14696,65 +14555,65 @@
1469614555
Jim_Obj **resultVec = 0;
1469714556
int resultc;
1469814557
Jim_Obj *emptyStr = 0;
1469914558
ScanFmtStringObj *fmtObj;
1470014559
14701
-
14560
+
1470214561
JimPanic((fmtObjPtr->typePtr != &scanFmtStringObjType, "Jim_ScanString() for non-scan format"));
1470314562
1470414563
fmtObj = (ScanFmtStringObj *) fmtObjPtr->internalRep.ptr;
14705
-
14564
+
1470614565
if (fmtObj->error != 0) {
1470714566
if (flags & JIM_ERRMSG)
1470814567
Jim_SetResultString(interp, fmtObj->error, -1);
1470914568
return 0;
1471014569
}
14711
-
14570
+
1471214571
emptyStr = Jim_NewEmptyStringObj(interp);
1471314572
Jim_IncrRefCount(emptyStr);
14714
-
14573
+
1471514574
resultList = Jim_NewListObj(interp, NULL, 0);
1471614575
if (fmtObj->maxPos > 0) {
1471714576
for (i = 0; i < fmtObj->maxPos; ++i)
1471814577
Jim_ListAppendElement(interp, resultList, emptyStr);
1471914578
JimListGetElements(interp, resultList, &resultc, &resultVec);
1472014579
}
14721
-
14580
+
1472214581
for (i = 0, pos = 0; i < fmtObj->count; ++i) {
1472314582
ScanFmtPartDescr *descr = &(fmtObj->descr[i]);
1472414583
Jim_Obj *value = 0;
1472514584
14726
-
14585
+
1472714586
if (descr->type == 0)
1472814587
continue;
14729
-
14588
+
1473014589
if (scanned > 0)
1473114590
scanned = ScanOneEntry(interp, str, pos, strLen, fmtObj, i, &value);
14732
-
14591
+
1473314592
if (scanned == -1 && i == 0)
1473414593
goto eof;
14735
-
14594
+
1473614595
pos += scanned;
1473714596
14738
-
14597
+
1473914598
if (value == 0)
1474014599
value = Jim_NewEmptyStringObj(interp);
14741
-
14600
+
1474214601
if (descr->pos == -1) {
1474314602
Jim_FreeNewObj(interp, value);
1474414603
}
1474514604
else if (descr->pos == 0)
14746
-
14605
+
1474714606
Jim_ListAppendElement(interp, resultList, value);
1474814607
else if (resultVec[descr->pos - 1] == emptyStr) {
14749
-
14608
+
1475014609
Jim_DecrRefCount(interp, resultVec[descr->pos - 1]);
1475114610
Jim_IncrRefCount(value);
1475214611
resultVec[descr->pos - 1] = value;
1475314612
}
1475414613
else {
14755
-
14614
+
1475614615
Jim_FreeNewObj(interp, value);
1475714616
goto err;
1475814617
}
1475914618
}
1476014619
Jim_DecrRefCount(interp, emptyStr);
@@ -14792,15 +14651,15 @@
1479214651
{
1479314652
Jim_PrngState *prng;
1479414653
unsigned char *destByte = (unsigned char *)dest;
1479514654
unsigned int si, sj, x;
1479614655
14797
-
14656
+
1479814657
if (interp->prngState == NULL)
1479914658
JimPrngInit(interp);
1480014659
prng = interp->prngState;
14801
-
14660
+
1480214661
for (x = 0; x < len; x++) {
1480314662
prng->i = (prng->i + 1) & 0xff;
1480414663
si = prng->sbox[prng->i];
1480514664
prng->j = (prng->j + si) & 0xff;
1480614665
sj = prng->sbox[prng->j];
@@ -14814,19 +14673,19 @@
1481414673
static void JimPrngSeed(Jim_Interp *interp, unsigned char *seed, int seedLen)
1481514674
{
1481614675
int i;
1481714676
Jim_PrngState *prng;
1481814677
14819
-
14678
+
1482014679
if (interp->prngState == NULL)
1482114680
JimPrngInit(interp);
1482214681
prng = interp->prngState;
1482314682
14824
-
14683
+
1482514684
for (i = 0; i < 256; i++)
1482614685
prng->sbox[i] = i;
14827
-
14686
+
1482814687
for (i = 0; i < seedLen; i++) {
1482914688
unsigned char t;
1483014689
1483114690
t = prng->sbox[i & 0xFF];
1483214691
prng->sbox[i & 0xFF] = prng->sbox[seed[i]];
@@ -14853,11 +14712,11 @@
1485314712
if (Jim_GetWide(interp, argv[2], &increment) != JIM_OK)
1485414713
return JIM_ERR;
1485514714
}
1485614715
intObjPtr = Jim_GetVariable(interp, argv[1], JIM_UNSHARED);
1485714716
if (!intObjPtr) {
14858
-
14717
+
1485914718
wideValue = 0;
1486014719
}
1486114720
else if (Jim_GetWide(interp, intObjPtr, &wideValue) != JIM_OK) {
1486214721
return JIM_ERR;
1486314722
}
@@ -14867,26 +14726,26 @@
1486714726
Jim_FreeNewObj(interp, intObjPtr);
1486814727
return JIM_ERR;
1486914728
}
1487014729
}
1487114730
else {
14872
-
14731
+
1487314732
Jim_InvalidateStringRep(intObjPtr);
1487414733
JimWideValue(intObjPtr) = wideValue + increment;
1487514734
1487614735
if (argv[1]->typePtr != &variableObjType) {
14877
-
14736
+
1487814737
Jim_SetVariable(interp, argv[1], intObjPtr);
1487914738
}
1488014739
}
1488114740
Jim_SetResult(interp, intObjPtr);
1488214741
return JIM_OK;
1488314742
}
1488414743
1488514744
14886
-#define JIM_EVAL_SARGV_LEN 8
14887
-#define JIM_EVAL_SINTV_LEN 8
14745
+#define JIM_EVAL_SARGV_LEN 8
14746
+#define JIM_EVAL_SINTV_LEN 8
1488814747
1488914748
1489014749
static int JimUnknown(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
1489114750
{
1489214751
int retcode;
@@ -14894,16 +14753,16 @@
1489414753
if (interp->unknown_called > 50) {
1489514754
return JIM_ERR;
1489614755
}
1489714756
1489814757
14899
-
14758
+
1490014759
if (Jim_GetCommand(interp, interp->unknown, JIM_NONE) == NULL)
1490114760
return JIM_ERR;
1490214761
1490314762
interp->unknown_called++;
14904
-
14763
+
1490514764
retcode = Jim_EvalObjPrefix(interp, interp->unknown, argc, argv);
1490614765
interp->unknown_called--;
1490714766
1490814767
return retcode;
1490914768
}
@@ -14910,10 +14769,11 @@
1491014769
1491114770
static int JimInvokeCommand(Jim_Interp *interp, int objc, Jim_Obj *const *objv)
1491214771
{
1491314772
int retcode;
1491414773
Jim_Cmd *cmdPtr;
14774
+ void *prevPrivData;
1491514775
1491614776
#if 0
1491714777
printf("invoke");
1491814778
int j;
1491914779
for (j = 0; j < objc; j++) {
@@ -14921,11 +14781,11 @@
1492114781
}
1492214782
printf("\n");
1492314783
#endif
1492414784
1492514785
if (interp->framePtr->tailcallCmd) {
14926
-
14786
+
1492714787
cmdPtr = interp->framePtr->tailcallCmd;
1492814788
interp->framePtr->tailcallCmd = NULL;
1492914789
}
1493014790
else {
1493114791
cmdPtr = Jim_GetCommand(interp, objv[0], JIM_ERRMSG);
@@ -14939,20 +14799,22 @@
1493914799
Jim_SetResultString(interp, "Infinite eval recursion", -1);
1494014800
retcode = JIM_ERR;
1494114801
goto out;
1494214802
}
1494314803
interp->evalDepth++;
14804
+ prevPrivData = interp->cmdPrivData;
1494414805
14945
-
14806
+
1494614807
Jim_SetEmptyResult(interp);
1494714808
if (cmdPtr->isproc) {
1494814809
retcode = JimCallProcedure(interp, cmdPtr, objc, objv);
1494914810
}
1495014811
else {
1495114812
interp->cmdPrivData = cmdPtr->u.native.privData;
1495214813
retcode = cmdPtr->u.native.cmdProc(interp, objc, objv);
1495314814
}
14815
+ interp->cmdPrivData = prevPrivData;
1495414816
interp->evalDepth--;
1495514817
1495614818
out:
1495714819
JimDecrCmdRefCount(interp, cmdPtr);
1495814820
@@ -14961,17 +14823,17 @@
1496114823
1496214824
int Jim_EvalObjVector(Jim_Interp *interp, int objc, Jim_Obj *const *objv)
1496314825
{
1496414826
int i, retcode;
1496514827
14966
-
14828
+
1496714829
for (i = 0; i < objc; i++)
1496814830
Jim_IncrRefCount(objv[i]);
1496914831
1497014832
retcode = JimInvokeCommand(interp, objc, objv);
1497114833
14972
-
14834
+
1497314835
for (i = 0; i < objc; i++)
1497414836
Jim_DecrRefCount(interp, objv[i]);
1497514837
1497614838
return retcode;
1497714839
}
@@ -14989,25 +14851,25 @@
1498914851
}
1499014852
1499114853
static void JimAddErrorToStack(Jim_Interp *interp, ScriptObj *script)
1499214854
{
1499314855
if (!interp->errorFlag) {
14994
-
14856
+
1499514857
interp->errorFlag = 1;
1499614858
Jim_IncrRefCount(script->fileNameObj);
1499714859
Jim_DecrRefCount(interp, interp->errorFileNameObj);
1499814860
interp->errorFileNameObj = script->fileNameObj;
1499914861
interp->errorLine = script->linenr;
1500014862
1500114863
JimResetStackTrace(interp);
15002
-
14864
+
1500314865
interp->addStackTrace++;
1500414866
}
1500514867
15006
-
14868
+
1500714869
if (interp->addStackTrace > 0) {
15008
-
14870
+
1500914871
1501014872
JimAppendStackTrace(interp, Jim_String(interp->errorProc), script->fileNameObj, script->linenr);
1501114873
1501214874
if (Jim_Length(script->fileNameObj)) {
1501314875
interp->addStackTrace = 0;
@@ -15042,14 +14904,14 @@
1504214904
case JIM_OK:
1504314905
case JIM_RETURN:
1504414906
objPtr = interp->result;
1504514907
break;
1504614908
case JIM_BREAK:
15047
-
14909
+
1504814910
return JIM_BREAK;
1504914911
case JIM_CONTINUE:
15050
-
14912
+
1505114913
return JIM_CONTINUE;
1505214914
default:
1505314915
return JIM_ERR;
1505414916
}
1505514917
break;
@@ -15084,23 +14946,23 @@
1508414946
case JIM_OK:
1508514947
case JIM_RETURN:
1508614948
break;
1508714949
case JIM_BREAK:
1508814950
if (flags & JIM_SUBST_FLAG) {
15089
-
14951
+
1509014952
tokens = i;
1509114953
continue;
1509214954
}
15093
-
15094
-
14955
+
14956
+
1509514957
case JIM_CONTINUE:
1509614958
if (flags & JIM_SUBST_FLAG) {
1509714959
intv[i] = NULL;
1509814960
continue;
1509914961
}
15100
-
15101
-
14962
+
14963
+
1510214964
default:
1510314965
while (i--) {
1510414966
Jim_DecrRefCount(interp, intv[i]);
1510514967
}
1510614968
if (intv != sintv) {
@@ -15111,28 +14973,29 @@
1511114973
Jim_IncrRefCount(intv[i]);
1511214974
Jim_String(intv[i]);
1511314975
totlen += intv[i]->length;
1511414976
}
1511514977
15116
-
14978
+
1511714979
if (tokens == 1 && intv[0] && intv == sintv) {
15118
- Jim_DecrRefCount(interp, intv[0]);
14980
+
14981
+ intv[0]->refCount--;
1511914982
return intv[0];
1512014983
}
1512114984
1512214985
objPtr = Jim_NewStringObjNoAlloc(interp, NULL, 0);
1512314986
1512414987
if (tokens == 4 && token[0].type == JIM_TT_ESC && token[1].type == JIM_TT_ESC
1512514988
&& token[2].type == JIM_TT_VAR) {
15126
-
14989
+
1512714990
objPtr->typePtr = &interpolatedObjType;
1512814991
objPtr->internalRep.dictSubstValue.varNameObjPtr = token[0].objPtr;
1512914992
objPtr->internalRep.dictSubstValue.indexObjPtr = intv[2];
1513014993
Jim_IncrRefCount(intv[2]);
1513114994
}
1513214995
else if (tokens && intv[0] && intv[0]->typePtr == &sourceObjType) {
15133
-
14996
+
1513414997
JimSetSourceInfo(interp, objPtr, intv[0]->internalRep.sourceValue.fileNameObj, intv[0]->internalRep.sourceValue.lineNumber);
1513514998
}
1513614999
1513715000
1513815001
s = objPtr->bytes = Jim_Alloc(totlen + 1);
@@ -15143,11 +15006,11 @@
1514315006
s += intv[i]->length;
1514415007
Jim_DecrRefCount(interp, intv[i]);
1514515008
}
1514615009
}
1514715010
objPtr->bytes[totlen] = '\0';
15148
-
15011
+
1514915012
if (intv != sintv) {
1515015013
Jim_Free(intv);
1515115014
}
1515215015
1515315016
return objPtr;
@@ -15187,11 +15050,11 @@
1518715050
1518815051
if (Jim_IsList(scriptObjPtr) && scriptObjPtr->bytes == NULL) {
1518915052
return JimEvalObjList(interp, scriptObjPtr);
1519015053
}
1519115054
15192
- Jim_IncrRefCount(scriptObjPtr);
15055
+ Jim_IncrRefCount(scriptObjPtr);
1519315056
script = JimGetScript(interp, scriptObjPtr);
1519415057
if (!JimScriptValid(interp, script)) {
1519515058
Jim_DecrRefCount(interp, scriptObjPtr);
1519615059
return JIM_ERR;
1519715060
}
@@ -15223,11 +15086,11 @@
1522315086
}
1522415087
#endif
1522515088
1522615089
script->inUse++;
1522715090
15228
-
15091
+
1522915092
prevScriptObj = interp->currentScriptObj;
1523015093
interp->currentScriptObj = scriptObjPtr;
1523115094
1523215095
interp->errorFlag = 0;
1523315096
argv = sargv;
@@ -15234,19 +15097,19 @@
1523415097
1523515098
for (i = 0; i < script->len && retcode == JIM_OK; ) {
1523615099
int argc;
1523715100
int j;
1523815101
15239
-
15102
+
1524015103
argc = token[i].objPtr->internalRep.scriptLineValue.argc;
1524115104
script->linenr = token[i].objPtr->internalRep.scriptLineValue.line;
1524215105
15243
-
15106
+
1524415107
if (argc > JIM_EVAL_SARGV_LEN)
1524515108
argv = Jim_Alloc(sizeof(Jim_Obj *) * argc);
1524615109
15247
-
15110
+
1524815111
i++;
1524915112
1525015113
for (j = 0; j < argc; j++) {
1525115114
long wordtokens = 1;
1525215115
int expand = 0;
@@ -15302,11 +15165,11 @@
1530215165
1530315166
if (!expand) {
1530415167
argv[j] = wordObjPtr;
1530515168
}
1530615169
else {
15307
-
15170
+
1530815171
int len = Jim_ListLength(interp, wordObjPtr);
1530915172
int newargc = argc + len - 1;
1531015173
int k;
1531115174
1531215175
if (len > 1) {
@@ -15315,39 +15178,39 @@
1531515178
argv = Jim_Alloc(sizeof(*argv) * newargc);
1531615179
memcpy(argv, sargv, sizeof(*argv) * j);
1531715180
}
1531815181
}
1531915182
else {
15320
-
15183
+
1532115184
argv = Jim_Realloc(argv, sizeof(*argv) * newargc);
1532215185
}
1532315186
}
1532415187
15325
-
15188
+
1532615189
for (k = 0; k < len; k++) {
1532715190
argv[j++] = wordObjPtr->internalRep.listValue.ele[k];
1532815191
Jim_IncrRefCount(wordObjPtr->internalRep.listValue.ele[k]);
1532915192
}
1533015193
1533115194
Jim_DecrRefCount(interp, wordObjPtr);
1533215195
15333
-
15196
+
1533415197
j--;
1533515198
argc += len - 1;
1533615199
}
1533715200
}
1533815201
1533915202
if (retcode == JIM_OK && argc) {
15340
-
15203
+
1534115204
retcode = JimInvokeCommand(interp, argc, argv);
15342
-
15205
+
1534315206
if (Jim_CheckSignal(interp)) {
1534415207
retcode = JIM_SIGNAL;
1534515208
}
1534615209
}
1534715210
15348
-
15211
+
1534915212
while (j-- > 0) {
1535015213
Jim_DecrRefCount(interp, argv[j]);
1535115214
}
1535215215
1535315216
if (argv != sargv) {
@@ -15354,21 +15217,21 @@
1535415217
Jim_Free(argv);
1535515218
argv = sargv;
1535615219
}
1535715220
}
1535815221
15359
-
15222
+
1536015223
if (retcode == JIM_ERR) {
1536115224
JimAddErrorToStack(interp, script);
1536215225
}
15363
-
15226
+
1536415227
else if (retcode != JIM_RETURN || interp->returnCode != JIM_ERR) {
15365
-
15228
+
1536615229
interp->addStackTrace = 0;
1536715230
}
1536815231
15369
-
15232
+
1537015233
interp->currentScriptObj = prevScriptObj;
1537115234
1537215235
Jim_FreeIntRep(interp, scriptObjPtr);
1537315236
scriptObjPtr->typePtr = &scriptObjType;
1537415237
Jim_SetIntRepPtr(scriptObjPtr, script);
@@ -15378,14 +15241,14 @@
1537815241
}
1537915242
1538015243
static int JimSetProcArg(Jim_Interp *interp, Jim_Obj *argNameObj, Jim_Obj *argValObj)
1538115244
{
1538215245
int retcode;
15383
-
15246
+
1538415247
const char *varname = Jim_String(argNameObj);
1538515248
if (*varname == '&') {
15386
-
15249
+
1538715250
Jim_Obj *objPtr;
1538815251
Jim_CallFrame *savedCallFrame = interp->framePtr;
1538915252
1539015253
interp->framePtr = interp->framePtr->parent;
1539115254
objPtr = Jim_GetVariable(interp, argValObj, JIM_ERRMSG);
@@ -15392,11 +15255,11 @@
1539215255
interp->framePtr = savedCallFrame;
1539315256
if (!objPtr) {
1539415257
return JIM_ERR;
1539515258
}
1539615259
15397
-
15260
+
1539815261
objPtr = Jim_NewStringObj(interp, varname + 1, -1);
1539915262
Jim_IncrRefCount(objPtr);
1540015263
retcode = Jim_SetVariableLink(interp, objPtr, argValObj, interp->framePtr->parent);
1540115264
Jim_DecrRefCount(interp, objPtr);
1540215265
}
@@ -15406,26 +15269,26 @@
1540615269
return retcode;
1540715270
}
1540815271
1540915272
static void JimSetProcWrongArgs(Jim_Interp *interp, Jim_Obj *procNameObj, Jim_Cmd *cmd)
1541015273
{
15411
-
15274
+
1541215275
Jim_Obj *argmsg = Jim_NewStringObj(interp, "", 0);
1541315276
int i;
1541415277
1541515278
for (i = 0; i < cmd->u.proc.argListLen; i++) {
1541615279
Jim_AppendString(interp, argmsg, " ", 1);
1541715280
1541815281
if (i == cmd->u.proc.argsPos) {
1541915282
if (cmd->u.proc.arglist[i].defaultObjPtr) {
15420
-
15283
+
1542115284
Jim_AppendString(interp, argmsg, "?", 1);
1542215285
Jim_AppendObj(interp, argmsg, cmd->u.proc.arglist[i].defaultObjPtr);
1542315286
Jim_AppendString(interp, argmsg, " ...?", -1);
1542415287
}
1542515288
else {
15426
-
15289
+
1542715290
Jim_AppendString(interp, argmsg, "?arg...?", -1);
1542815291
}
1542915292
}
1543015293
else {
1543115294
if (cmd->u.proc.arglist[i].defaultObjPtr) {
@@ -15441,20 +15304,19 @@
1544115304
Jim_AppendString(interp, argmsg, arg, -1);
1544215305
}
1544315306
}
1544415307
}
1544515308
Jim_SetResultFormatted(interp, "wrong # args: should be \"%#s%#s\"", procNameObj, argmsg);
15446
- Jim_FreeNewObj(interp, argmsg);
1544715309
}
1544815310
1544915311
#ifdef jim_ext_namespace
1545015312
int Jim_EvalNamespace(Jim_Interp *interp, Jim_Obj *scriptObj, Jim_Obj *nsObj)
1545115313
{
1545215314
Jim_CallFrame *callFramePtr;
1545315315
int retcode;
1545415316
15455
-
15317
+
1545615318
callFramePtr = JimCreateCallFrame(interp, interp->framePtr, nsObj);
1545715319
callFramePtr->argv = &interp->emptyObj;
1545815320
callFramePtr->argc = 0;
1545915321
callFramePtr->procArgsObjPtr = NULL;
1546015322
callFramePtr->procBodyObjPtr = scriptObj;
@@ -15462,21 +15324,21 @@
1546215324
callFramePtr->fileNameObj = interp->emptyObj;
1546315325
callFramePtr->line = 0;
1546415326
Jim_IncrRefCount(scriptObj);
1546515327
interp->framePtr = callFramePtr;
1546615328
15467
-
15329
+
1546815330
if (interp->framePtr->level == interp->maxCallFrameDepth) {
1546915331
Jim_SetResultString(interp, "Too many nested calls. Infinite recursion?", -1);
1547015332
retcode = JIM_ERR;
1547115333
}
1547215334
else {
15473
-
15335
+
1547415336
retcode = Jim_EvalObj(interp, scriptObj);
1547515337
}
1547615338
15477
-
15339
+
1547815340
interp->framePtr = interp->framePtr->parent;
1547915341
JimFreeCallFrame(interp, callFramePtr, JIM_FCF_REUSE);
1548015342
1548115343
return retcode;
1548215344
}
@@ -15486,62 +15348,62 @@
1548615348
{
1548715349
Jim_CallFrame *callFramePtr;
1548815350
int i, d, retcode, optargs;
1548915351
ScriptObj *script;
1549015352
15491
-
15353
+
1549215354
if (argc - 1 < cmd->u.proc.reqArity ||
1549315355
(cmd->u.proc.argsPos < 0 && argc - 1 > cmd->u.proc.reqArity + cmd->u.proc.optArity)) {
1549415356
JimSetProcWrongArgs(interp, argv[0], cmd);
1549515357
return JIM_ERR;
1549615358
}
1549715359
1549815360
if (Jim_Length(cmd->u.proc.bodyObjPtr) == 0) {
15499
-
15361
+
1550015362
return JIM_OK;
1550115363
}
1550215364
15503
-
15365
+
1550415366
if (interp->framePtr->level == interp->maxCallFrameDepth) {
1550515367
Jim_SetResultString(interp, "Too many nested calls. Infinite recursion?", -1);
1550615368
return JIM_ERR;
1550715369
}
1550815370
15509
-
15371
+
1551015372
callFramePtr = JimCreateCallFrame(interp, interp->framePtr, cmd->u.proc.nsObj);
1551115373
callFramePtr->argv = argv;
1551215374
callFramePtr->argc = argc;
1551315375
callFramePtr->procArgsObjPtr = cmd->u.proc.argListObjPtr;
1551415376
callFramePtr->procBodyObjPtr = cmd->u.proc.bodyObjPtr;
1551515377
callFramePtr->staticVars = cmd->u.proc.staticVars;
1551615378
15517
-
15379
+
1551815380
script = JimGetScript(interp, interp->currentScriptObj);
1551915381
callFramePtr->fileNameObj = script->fileNameObj;
1552015382
callFramePtr->line = script->linenr;
1552115383
1552215384
Jim_IncrRefCount(cmd->u.proc.argListObjPtr);
1552315385
Jim_IncrRefCount(cmd->u.proc.bodyObjPtr);
1552415386
interp->framePtr = callFramePtr;
1552515387
15526
-
15388
+
1552715389
optargs = (argc - 1 - cmd->u.proc.reqArity);
1552815390
15529
-
15391
+
1553015392
i = 1;
1553115393
for (d = 0; d < cmd->u.proc.argListLen; d++) {
1553215394
Jim_Obj *nameObjPtr = cmd->u.proc.arglist[d].nameObjPtr;
1553315395
if (d == cmd->u.proc.argsPos) {
15534
-
15396
+
1553515397
Jim_Obj *listObjPtr;
1553615398
int argsLen = 0;
1553715399
if (cmd->u.proc.reqArity + cmd->u.proc.optArity < argc - 1) {
1553815400
argsLen = argc - 1 - (cmd->u.proc.reqArity + cmd->u.proc.optArity);
1553915401
}
1554015402
listObjPtr = Jim_NewListObj(interp, &argv[i], argsLen);
1554115403
15542
-
15404
+
1554315405
if (cmd->u.proc.arglist[d].defaultObjPtr) {
1554415406
nameObjPtr =cmd->u.proc.arglist[d].defaultObjPtr;
1554515407
}
1554615408
retcode = Jim_SetVariable(interp, nameObjPtr, listObjPtr);
1554715409
if (retcode != JIM_OK) {
@@ -15550,33 +15412,34 @@
1555015412
1555115413
i += argsLen;
1555215414
continue;
1555315415
}
1555415416
15555
-
15417
+
1555615418
if (cmd->u.proc.arglist[d].defaultObjPtr == NULL || optargs-- > 0) {
1555715419
retcode = JimSetProcArg(interp, nameObjPtr, argv[i++]);
1555815420
}
1555915421
else {
15560
-
15422
+
1556115423
retcode = Jim_SetVariable(interp, nameObjPtr, cmd->u.proc.arglist[d].defaultObjPtr);
1556215424
}
1556315425
if (retcode != JIM_OK) {
1556415426
goto badargset;
1556515427
}
1556615428
}
1556715429
15568
-
15430
+
1556915431
retcode = Jim_EvalObj(interp, cmd->u.proc.bodyObjPtr);
1557015432
1557115433
badargset:
1557215434
15573
-
15435
+
15436
+ retcode = JimInvokeDefer(interp, retcode);
1557415437
interp->framePtr = interp->framePtr->parent;
1557515438
JimFreeCallFrame(interp, callFramePtr, JIM_FCF_REUSE);
1557615439
15577
-
15440
+
1557815441
if (interp->framePtr->tailcallObj) {
1557915442
do {
1558015443
Jim_Obj *tailcallObj = interp->framePtr->tailcallObj;
1558115444
1558215445
interp->framePtr->tailcallObj = NULL;
@@ -15588,18 +15451,18 @@
1558815451
}
1558915452
}
1559015453
Jim_DecrRefCount(interp, tailcallObj);
1559115454
} while (interp->framePtr->tailcallObj);
1559215455
15593
-
15456
+
1559415457
if (interp->framePtr->tailcallCmd) {
1559515458
JimDecrCmdRefCount(interp, interp->framePtr->tailcallCmd);
1559615459
interp->framePtr->tailcallCmd = NULL;
1559715460
}
1559815461
}
1559915462
15600
-
15463
+
1560115464
if (retcode == JIM_RETURN) {
1560215465
if (--interp->returnLevel <= 0) {
1560315466
retcode = interp->returnCode;
1560415467
interp->returnCode = JIM_OK;
1560515468
interp->returnLevel = 0;
@@ -15711,20 +15574,20 @@
1571115574
prevScriptObj = interp->currentScriptObj;
1571215575
interp->currentScriptObj = scriptObjPtr;
1571315576
1571415577
retcode = Jim_EvalObj(interp, scriptObjPtr);
1571515578
15716
-
15579
+
1571715580
if (retcode == JIM_RETURN) {
1571815581
if (--interp->returnLevel <= 0) {
1571915582
retcode = interp->returnCode;
1572015583
interp->returnCode = JIM_OK;
1572115584
interp->returnLevel = 0;
1572215585
}
1572315586
}
1572415587
if (retcode == JIM_ERR) {
15725
-
15588
+
1572615589
interp->addStackTrace++;
1572715590
}
1572815591
1572915592
interp->currentScriptObj = prevScriptObj;
1573015593
@@ -15750,11 +15613,11 @@
1575015613
}
1575115614
if (*pc->p == '$' && !(flags & JIM_SUBST_NOVAR)) {
1575215615
if (JimParseVar(pc) == JIM_OK) {
1575315616
return;
1575415617
}
15755
-
15618
+
1575615619
pc->tstart = pc->p;
1575715620
flags |= JIM_SUBST_NOVAR;
1575815621
}
1575915622
while (pc->len) {
1576015623
if (*pc->p == '$' && !(flags & JIM_SUBST_NOVAR)) {
@@ -15781,32 +15644,32 @@
1578115644
const char *scriptText = Jim_GetString(objPtr, &scriptTextLen);
1578215645
struct JimParserCtx parser;
1578315646
struct ScriptObj *script = Jim_Alloc(sizeof(*script));
1578415647
ParseTokenList tokenlist;
1578515648
15786
-
15649
+
1578715650
ScriptTokenListInit(&tokenlist);
1578815651
1578915652
JimParserInit(&parser, scriptText, scriptTextLen, 1);
1579015653
while (1) {
1579115654
JimParseSubst(&parser, flags);
1579215655
if (parser.eof) {
15793
-
15656
+
1579415657
break;
1579515658
}
1579615659
ScriptAddToken(&tokenlist, parser.tstart, parser.tend - parser.tstart + 1, parser.tt,
1579715660
parser.tline);
1579815661
}
1579915662
15800
-
15663
+
1580115664
script->inUse = 1;
1580215665
script->substFlags = flags;
1580315666
script->fileNameObj = interp->emptyObj;
1580415667
Jim_IncrRefCount(script->fileNameObj);
1580515668
SubstObjAddTokens(interp, script, &tokenlist);
1580615669
15807
-
15670
+
1580815671
ScriptTokenListFree(&tokenlist);
1580915672
1581015673
#ifdef DEBUG_SHOW_SUBST
1581115674
{
1581215675
int i;
@@ -15817,11 +15680,11 @@
1581715680
Jim_String(script->token[i].objPtr));
1581815681
}
1581915682
}
1582015683
#endif
1582115684
15822
-
15685
+
1582315686
Jim_FreeIntRep(interp, objPtr);
1582415687
Jim_SetIntRepPtr(objPtr, script);
1582515688
objPtr->typePtr = &scriptObjType;
1582615689
return JIM_OK;
1582715690
}
@@ -15835,11 +15698,11 @@
1583515698
1583615699
int Jim_SubstObj(Jim_Interp *interp, Jim_Obj *substObjPtr, Jim_Obj **resObjPtrPtr, int flags)
1583715700
{
1583815701
ScriptObj *script = Jim_GetSubst(interp, substObjPtr, flags);
1583915702
15840
- Jim_IncrRefCount(substObjPtr);
15703
+ Jim_IncrRefCount(substObjPtr);
1584115704
script->inUse++;
1584215705
1584315706
*resObjPtrPtr = JimInterpolateTokens(interp, script->token, script->len, flags);
1584415707
1584515708
script->inUse--;
@@ -15851,22 +15714,24 @@
1585115714
}
1585215715
1585315716
void Jim_WrongNumArgs(Jim_Interp *interp, int argc, Jim_Obj *const *argv, const char *msg)
1585415717
{
1585515718
Jim_Obj *objPtr;
15856
- Jim_Obj *listObjPtr = Jim_NewListObj(interp, argv, argc);
15719
+ Jim_Obj *listObjPtr;
1585715720
15858
- if (*msg) {
15721
+ JimPanic((argc == 0, "Jim_WrongNumArgs() called with argc=0"));
15722
+
15723
+ listObjPtr = Jim_NewListObj(interp, argv, argc);
15724
+
15725
+ if (msg && *msg) {
1585915726
Jim_ListAppendElement(interp, listObjPtr, Jim_NewStringObj(interp, msg, -1));
1586015727
}
1586115728
Jim_IncrRefCount(listObjPtr);
1586215729
objPtr = Jim_ListJoin(interp, listObjPtr, " ", 1);
1586315730
Jim_DecrRefCount(interp, listObjPtr);
1586415731
15865
- Jim_IncrRefCount(objPtr);
1586615732
Jim_SetResultFormatted(interp, "wrong # args: should be \"%#s\"", objPtr);
15867
- Jim_DecrRefCount(interp, objPtr);
1586815733
}
1586915734
1587015735
typedef void JimHashtableIteratorCallbackType(Jim_Interp *interp, Jim_Obj *listObjPtr,
1587115736
Jim_HashEntry *he, int type);
1587215737
@@ -15876,11 +15741,11 @@
1587615741
JimHashtableIteratorCallbackType *callback, int type)
1587715742
{
1587815743
Jim_HashEntry *he;
1587915744
Jim_Obj *listObjPtr = Jim_NewListObj(interp, NULL, 0);
1588015745
15881
-
15746
+
1588215747
if (patternObjPtr && JimTrivialMatch(Jim_String(patternObjPtr))) {
1588315748
he = Jim_FindHashEntry(ht, Jim_String(patternObjPtr));
1588415749
if (he) {
1588515750
callback(interp, listObjPtr, he, type);
1588615751
}
@@ -15907,11 +15772,11 @@
1590715772
{
1590815773
Jim_Cmd *cmdPtr = Jim_GetHashEntryVal(he);
1590915774
Jim_Obj *objPtr;
1591015775
1591115776
if (type == JIM_CMDLIST_PROCS && !cmdPtr->isproc) {
15912
-
15777
+
1591315778
return;
1591415779
}
1591515780
1591615781
objPtr = Jim_NewStringObj(interp, he->key, -1);
1591715782
Jim_IncrRefCount(objPtr);
@@ -15967,11 +15832,11 @@
1596715832
1596815833
targetCallFrame = JimGetCallFrameByInteger(interp, levelObjPtr);
1596915834
if (targetCallFrame == NULL) {
1597015835
return JIM_ERR;
1597115836
}
15972
-
15837
+
1597315838
if (targetCallFrame == interp->topFramePtr) {
1597415839
Jim_SetResultFormatted(interp, "bad level \"%#s\"", levelObjPtr);
1597515840
return JIM_ERR;
1597615841
}
1597715842
if (info_level_cmd) {
@@ -16095,12 +15960,17 @@
1609515960
doubleRes = (double)res;
1609615961
goto trydouble;
1609715962
}
1609815963
if (op == JIM_EXPROP_SUB)
1609915964
res -= wideValue;
16100
- else
15965
+ else {
15966
+ if (wideValue == 0) {
15967
+ Jim_SetResultString(interp, "Division by zero", -1);
15968
+ return JIM_ERR;
15969
+ }
1610115970
res /= wideValue;
15971
+ }
1610215972
}
1610315973
Jim_SetResultInt(interp, res);
1610415974
return JIM_OK;
1610515975
trydouble:
1610615976
for (; i < argc; i++) {
@@ -16154,11 +16024,11 @@
1615416024
if (!objPtr)
1615516025
return JIM_ERR;
1615616026
Jim_SetResult(interp, objPtr);
1615716027
return JIM_OK;
1615816028
}
16159
-
16029
+
1616016030
if (Jim_SetVariable(interp, argv[1], argv[2]) != JIM_OK)
1616116031
return JIM_ERR;
1616216032
Jim_SetResult(interp, argv[2]);
1616316033
return JIM_OK;
1616416034
}
@@ -16197,11 +16067,11 @@
1619716067
if (argc != 3) {
1619816068
Jim_WrongNumArgs(interp, 1, argv, "condition body");
1619916069
return JIM_ERR;
1620016070
}
1620116071
16202
-
16072
+
1620316073
while (1) {
1620416074
int boolean, retval;
1620516075
1620616076
if ((retval = Jim_GetBoolFromExpr(interp, argv[1], &boolean)) != JIM_OK)
1620716077
return retval;
@@ -16237,11 +16107,11 @@
1623716107
if (argc != 5) {
1623816108
Jim_WrongNumArgs(interp, 1, argv, "start test next body");
1623916109
return JIM_ERR;
1624016110
}
1624116111
16242
-
16112
+
1624316113
if ((retval = Jim_EvalObj(interp, argv[1])) != JIM_OK) {
1624416114
return retval;
1624516115
}
1624616116
1624716117
retval = Jim_GetBoolFromExpr(interp, argv[2], &boolean);
@@ -16248,78 +16118,84 @@
1624816118
1624916119
1625016120
#ifdef JIM_OPTIMIZATION
1625116121
if (retval == JIM_OK && boolean) {
1625216122
ScriptObj *incrScript;
16253
- ExprByteCode *expr;
16123
+ struct ExprTree *expr;
1625416124
jim_wide stop, currentVal;
1625516125
Jim_Obj *objPtr;
1625616126
int cmpOffset;
1625716127
16258
-
16128
+
1625916129
expr = JimGetExpression(interp, argv[2]);
1626016130
incrScript = JimGetScript(interp, argv[3]);
1626116131
16262
-
16132
+
1626316133
if (incrScript == NULL || incrScript->len != 3 || !expr || expr->len != 3) {
1626416134
goto evalstart;
1626516135
}
16266
-
16267
- if (incrScript->token[1].type != JIM_TT_ESC ||
16268
- expr->token[0].type != JIM_TT_VAR ||
16269
- (expr->token[1].type != JIM_TT_EXPR_INT && expr->token[1].type != JIM_TT_VAR)) {
16136
+
16137
+ if (incrScript->token[1].type != JIM_TT_ESC) {
1627016138
goto evalstart;
1627116139
}
1627216140
16273
- if (expr->token[2].type == JIM_EXPROP_LT) {
16141
+ if (expr->expr->type == JIM_EXPROP_LT) {
1627416142
cmpOffset = 0;
1627516143
}
16276
- else if (expr->token[2].type == JIM_EXPROP_LTE) {
16144
+ else if (expr->expr->type == JIM_EXPROP_LTE) {
1627716145
cmpOffset = 1;
1627816146
}
1627916147
else {
1628016148
goto evalstart;
1628116149
}
1628216150
16283
-
16151
+ if (expr->expr->left->type != JIM_TT_VAR) {
16152
+ goto evalstart;
16153
+ }
16154
+
16155
+ if (expr->expr->right->type != JIM_TT_VAR && expr->expr->right->type != JIM_TT_EXPR_INT) {
16156
+ goto evalstart;
16157
+ }
16158
+
16159
+
1628416160
if (!Jim_CompareStringImmediate(interp, incrScript->token[1].objPtr, "incr")) {
1628516161
goto evalstart;
1628616162
}
1628716163
16288
-
16289
- if (!Jim_StringEqObj(incrScript->token[2].objPtr, expr->token[0].objPtr)) {
16164
+
16165
+ if (!Jim_StringEqObj(incrScript->token[2].objPtr, expr->expr->left->objPtr)) {
1629016166
goto evalstart;
1629116167
}
1629216168
16293
-
16294
- if (expr->token[1].type == JIM_TT_EXPR_INT) {
16295
- if (Jim_GetWide(interp, expr->token[1].objPtr, &stop) == JIM_ERR) {
16169
+
16170
+ if (expr->expr->right->type == JIM_TT_EXPR_INT) {
16171
+ if (Jim_GetWide(interp, expr->expr->right->objPtr, &stop) == JIM_ERR) {
1629616172
goto evalstart;
1629716173
}
1629816174
}
1629916175
else {
16300
- stopVarNamePtr = expr->token[1].objPtr;
16176
+ stopVarNamePtr = expr->expr->right->objPtr;
1630116177
Jim_IncrRefCount(stopVarNamePtr);
16302
-
16178
+
1630316179
stop = 0;
1630416180
}
1630516181
16306
-
16307
- varNamePtr = expr->token[0].objPtr;
16182
+
16183
+ varNamePtr = expr->expr->left->objPtr;
1630816184
Jim_IncrRefCount(varNamePtr);
1630916185
1631016186
objPtr = Jim_GetVariable(interp, varNamePtr, JIM_NONE);
1631116187
if (objPtr == NULL || Jim_GetWide(interp, objPtr, &currentVal) != JIM_OK) {
1631216188
goto testcond;
1631316189
}
1631416190
16315
-
16191
+
1631616192
while (retval == JIM_OK) {
16317
-
16318
-
1631916193
16320
-
16194
+
16195
+
16196
+
1632116197
if (stopVarNamePtr) {
1632216198
objPtr = Jim_GetVariable(interp, stopVarNamePtr, JIM_NONE);
1632316199
if (objPtr == NULL || Jim_GetWide(interp, objPtr, &stop) != JIM_OK) {
1632416200
goto testcond;
1632516201
}
@@ -16327,18 +16203,18 @@
1632716203
1632816204
if (currentVal >= stop + cmpOffset) {
1632916205
break;
1633016206
}
1633116207
16332
-
16208
+
1633316209
retval = Jim_EvalObj(interp, argv[4]);
1633416210
if (retval == JIM_OK || retval == JIM_CONTINUE) {
1633516211
retval = JIM_OK;
1633616212
1633716213
objPtr = Jim_GetVariable(interp, varNamePtr, JIM_ERRMSG);
1633816214
16339
-
16215
+
1634016216
if (objPtr == NULL) {
1634116217
retval = JIM_ERR;
1634216218
goto out;
1634316219
}
1634416220
if (!Jim_IsShared(objPtr) && objPtr->typePtr == &intObjType) {
@@ -16358,25 +16234,25 @@
1635816234
}
1635916235
evalstart:
1636016236
#endif
1636116237
1636216238
while (boolean && (retval == JIM_OK || retval == JIM_CONTINUE)) {
16363
-
16239
+
1636416240
retval = Jim_EvalObj(interp, argv[4]);
1636516241
1636616242
if (retval == JIM_OK || retval == JIM_CONTINUE) {
16367
-
16368
- evalnext:
16243
+
16244
+JIM_IF_OPTIM(evalnext:)
1636916245
retval = Jim_EvalObj(interp, argv[3]);
1637016246
if (retval == JIM_OK || retval == JIM_CONTINUE) {
16371
-
16372
- testcond:
16247
+
16248
+JIM_IF_OPTIM(testcond:)
1637316249
retval = Jim_GetBoolFromExpr(interp, argv[2], &boolean);
1637416250
}
1637516251
}
1637616252
}
16377
- out:
16253
+JIM_IF_OPTIM(out:)
1637816254
if (stopVarNamePtr) {
1637916255
Jim_DecrRefCount(interp, stopVarNamePtr);
1638016256
}
1638116257
if (varNamePtr) {
1638216258
Jim_DecrRefCount(interp, varNamePtr);
@@ -16418,11 +16294,11 @@
1641816294
if (retval == JIM_OK || retval == JIM_CONTINUE) {
1641916295
Jim_Obj *objPtr = Jim_GetVariable(interp, argv[1], JIM_ERRMSG);
1642016296
1642116297
retval = JIM_OK;
1642216298
16423
-
16299
+
1642416300
i += incr;
1642516301
1642616302
if (objPtr && !Jim_IsShared(objPtr) && objPtr->typePtr == &intObjType) {
1642716303
if (argv[1]->typePtr != &variableObjType) {
1642816304
if (Jim_SetVariable(interp, argv[1], objPtr) != JIM_OK) {
@@ -16483,21 +16359,21 @@
1648316359
1648416360
static int JimForeachMapHelper(Jim_Interp *interp, int argc, Jim_Obj *const *argv, int doMap)
1648516361
{
1648616362
int result = JIM_OK;
1648716363
int i, numargs;
16488
- Jim_ListIter twoiters[2];
16364
+ Jim_ListIter twoiters[2];
1648916365
Jim_ListIter *iters;
1649016366
Jim_Obj *script;
1649116367
Jim_Obj *resultObj;
1649216368
1649316369
if (argc < 4 || argc % 2 != 0) {
1649416370
Jim_WrongNumArgs(interp, 1, argv, "varList list ?varList list ...? script");
1649516371
return JIM_ERR;
1649616372
}
16497
- script = argv[argc - 1];
16498
- numargs = (argc - 1 - 1);
16373
+ script = argv[argc - 1];
16374
+ numargs = (argc - 1 - 1);
1649916375
1650016376
if (numargs == 2) {
1650116377
iters = twoiters;
1650216378
}
1650316379
else {
@@ -16509,11 +16385,11 @@
1650916385
result = JIM_ERR;
1651016386
}
1651116387
}
1651216388
if (result != JIM_OK) {
1651316389
Jim_SetResultString(interp, "foreach varlist is empty", -1);
16514
- return result;
16390
+ goto empty_varlist;
1651516391
}
1651616392
1651716393
if (doMap) {
1651816394
resultObj = Jim_NewListObj(interp, NULL, 0);
1651916395
}
@@ -16521,34 +16397,34 @@
1652116397
resultObj = interp->emptyObj;
1652216398
}
1652316399
Jim_IncrRefCount(resultObj);
1652416400
1652516401
while (1) {
16526
-
16402
+
1652716403
for (i = 0; i < numargs; i += 2) {
1652816404
if (!JimListIterDone(interp, &iters[i + 1])) {
1652916405
break;
1653016406
}
1653116407
}
1653216408
if (i == numargs) {
16533
-
16409
+
1653416410
break;
1653516411
}
1653616412
16537
-
16413
+
1653816414
for (i = 0; i < numargs; i += 2) {
1653916415
Jim_Obj *varName;
1654016416
16541
-
16417
+
1654216418
JimListIterInit(&iters[i], argv[i + 1]);
1654316419
while ((varName = JimListIterNext(interp, &iters[i])) != NULL) {
1654416420
Jim_Obj *valObj = JimListIterNext(interp, &iters[i + 1]);
1654516421
if (!valObj) {
16546
-
16422
+
1654716423
valObj = interp->emptyObj;
1654816424
}
16549
-
16425
+
1655016426
Jim_IncrRefCount(valObj);
1655116427
result = Jim_SetVariable(interp, varName, valObj);
1655216428
Jim_DecrRefCount(interp, valObj);
1655316429
if (result != JIM_OK) {
1655416430
goto err;
@@ -16572,10 +16448,11 @@
1657216448
out:
1657316449
result = JIM_OK;
1657416450
Jim_SetResult(interp, resultObj);
1657516451
err:
1657616452
Jim_DecrRefCount(interp, resultObj);
16453
+ empty_varlist:
1657716454
if (numargs > 2) {
1657816455
Jim_Free(iters);
1657916456
}
1658016457
return result;
1658116458
}
@@ -16630,41 +16507,41 @@
1663016507
{
1663116508
int boolean, retval, current = 1, falsebody = 0;
1663216509
1663316510
if (argc >= 3) {
1663416511
while (1) {
16635
-
16512
+
1663616513
if (current >= argc)
1663716514
goto err;
1663816515
if ((retval = Jim_GetBoolFromExpr(interp, argv[current++], &boolean))
1663916516
!= JIM_OK)
1664016517
return retval;
16641
-
16518
+
1664216519
if (current >= argc)
1664316520
goto err;
1664416521
if (Jim_CompareStringImmediate(interp, argv[current], "then"))
1664516522
current++;
16646
-
16523
+
1664716524
if (current >= argc)
1664816525
goto err;
1664916526
if (boolean)
1665016527
return Jim_EvalObj(interp, argv[current]);
16651
-
16528
+
1665216529
if (++current >= argc) {
1665316530
Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
1665416531
return JIM_OK;
1665516532
}
1665616533
falsebody = current++;
1665716534
if (Jim_CompareStringImmediate(interp, argv[falsebody], "else")) {
16658
-
16535
+
1665916536
if (current != argc - 1)
1666016537
goto err;
1666116538
return Jim_EvalObj(interp, argv[current]);
1666216539
}
1666316540
else if (Jim_CompareStringImmediate(interp, argv[falsebody], "elseif"))
1666416541
continue;
16665
-
16542
+
1666616543
else if (falsebody != argc - 1)
1666716544
goto err;
1666816545
return Jim_EvalObj(interp, argv[falsebody]);
1666916546
}
1667016547
return JIM_OK;
@@ -16698,19 +16575,17 @@
1669816575
}
1669916576
1670016577
return eq;
1670116578
}
1670216579
16703
-enum
16704
-{ SWITCH_EXACT, SWITCH_GLOB, SWITCH_RE, SWITCH_CMD };
16705
-
1670616580
1670716581
static int Jim_SwitchCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
1670816582
{
16583
+ enum { SWITCH_EXACT, SWITCH_GLOB, SWITCH_RE, SWITCH_CMD };
1670916584
int matchOpt = SWITCH_EXACT, opt = 1, patCount, i;
16710
- Jim_Obj *command = 0, *const *caseList = 0, *strObj;
16711
- Jim_Obj *script = 0;
16585
+ Jim_Obj *command = NULL, *scriptObj = NULL, *strObj;
16586
+ Jim_Obj **caseList;
1671216587
1671316588
if (argc < 3) {
1671416589
wrongnumargs:
1671516590
Jim_WrongNumArgs(interp, 1, argv, "?options? string "
1671616591
"pattern body ... ?default body? or " "{pattern body ?pattern body ...?}");
@@ -16747,68 +16622,62 @@
1674716622
goto wrongnumargs;
1674816623
}
1674916624
strObj = argv[opt++];
1675016625
patCount = argc - opt;
1675116626
if (patCount == 1) {
16752
- Jim_Obj **vector;
16753
-
16754
- JimListGetElements(interp, argv[opt], &patCount, &vector);
16755
- caseList = vector;
16627
+ JimListGetElements(interp, argv[opt], &patCount, &caseList);
1675616628
}
1675716629
else
16758
- caseList = &argv[opt];
16630
+ caseList = (Jim_Obj **)&argv[opt];
1675916631
if (patCount == 0 || patCount % 2 != 0)
1676016632
goto wrongnumargs;
16761
- for (i = 0; script == 0 && i < patCount; i += 2) {
16633
+ for (i = 0; scriptObj == NULL && i < patCount; i += 2) {
1676216634
Jim_Obj *patObj = caseList[i];
1676316635
1676416636
if (!Jim_CompareStringImmediate(interp, patObj, "default")
1676516637
|| i < (patCount - 2)) {
1676616638
switch (matchOpt) {
1676716639
case SWITCH_EXACT:
1676816640
if (Jim_StringEqObj(strObj, patObj))
16769
- script = caseList[i + 1];
16641
+ scriptObj = caseList[i + 1];
1677016642
break;
1677116643
case SWITCH_GLOB:
1677216644
if (Jim_StringMatchObj(interp, patObj, strObj, 0))
16773
- script = caseList[i + 1];
16645
+ scriptObj = caseList[i + 1];
1677416646
break;
1677516647
case SWITCH_RE:
1677616648
command = Jim_NewStringObj(interp, "regexp", -1);
16777
-
16649
+
1677816650
case SWITCH_CMD:{
1677916651
int rc = Jim_CommandMatchObj(interp, command, patObj, strObj, 0);
1678016652
1678116653
if (argc - opt == 1) {
16782
- Jim_Obj **vector;
16783
-
16784
- JimListGetElements(interp, argv[opt], &patCount, &vector);
16785
- caseList = vector;
16654
+ JimListGetElements(interp, argv[opt], &patCount, &caseList);
1678616655
}
16787
-
16656
+
1678816657
if (rc < 0) {
1678916658
return -rc;
1679016659
}
1679116660
if (rc)
16792
- script = caseList[i + 1];
16661
+ scriptObj = caseList[i + 1];
1679316662
break;
1679416663
}
1679516664
}
1679616665
}
1679716666
else {
16798
- script = caseList[i + 1];
16667
+ scriptObj = caseList[i + 1];
1679916668
}
1680016669
}
16801
- for (; i < patCount && Jim_CompareStringImmediate(interp, script, "-"); i += 2)
16802
- script = caseList[i + 1];
16803
- if (script && Jim_CompareStringImmediate(interp, script, "-")) {
16670
+ for (; i < patCount && Jim_CompareStringImmediate(interp, scriptObj, "-"); i += 2)
16671
+ scriptObj = caseList[i + 1];
16672
+ if (scriptObj && Jim_CompareStringImmediate(interp, scriptObj, "-")) {
1680416673
Jim_SetResultFormatted(interp, "no body specified for pattern \"%#s\"", caseList[i - 2]);
1680516674
return JIM_ERR;
1680616675
}
1680716676
Jim_SetEmptyResult(interp);
16808
- if (script) {
16809
- return Jim_EvalObj(interp, script);
16677
+ if (scriptObj) {
16678
+ return Jim_EvalObj(interp, scriptObj);
1681016679
}
1681116680
return JIM_OK;
1681216681
}
1681316682
1681416683
@@ -16920,11 +16789,11 @@
1692016789
case OPT_COMMAND:
1692116790
if (i >= argc - 2) {
1692216791
goto wrongargs;
1692316792
}
1692416793
commandObj = argv[++i];
16925
-
16794
+
1692616795
case OPT_EXACT:
1692716796
case OPT_GLOB:
1692816797
case OPT_REGEXP:
1692916798
opt_match = option;
1693016799
break;
@@ -16968,17 +16837,17 @@
1696816837
goto done;
1696916838
}
1697016839
break;
1697116840
}
1697216841
16973
-
16842
+
1697416843
if (!eq && opt_bool && opt_not && !opt_all) {
1697516844
continue;
1697616845
}
1697716846
1697816847
if ((!opt_bool && eq == !opt_not) || (opt_bool && (eq || opt_all))) {
16979
-
16848
+
1698016849
Jim_Obj *resultObj;
1698116850
1698216851
if (opt_bool) {
1698316852
resultObj = Jim_NewIntObj(interp, eq ^ opt_not);
1698416853
}
@@ -17001,11 +16870,11 @@
1700116870
1700216871
if (opt_all) {
1700316872
Jim_SetResult(interp, listObjPtr);
1700416873
}
1700516874
else {
17006
-
16875
+
1700716876
if (opt_bool) {
1700816877
Jim_SetResultBool(interp, opt_not);
1700916878
}
1701016879
else if (!opt_inline) {
1701116880
Jim_SetResultInt(interp, -1);
@@ -17030,11 +16899,11 @@
1703016899
Jim_WrongNumArgs(interp, 1, argv, "varName ?value value ...?");
1703116900
return JIM_ERR;
1703216901
}
1703316902
listObjPtr = Jim_GetVariable(interp, argv[1], JIM_UNSHARED);
1703416903
if (!listObjPtr) {
17035
-
16904
+
1703616905
listObjPtr = Jim_NewListObj(interp, NULL, 0);
1703716906
new_obj = 1;
1703816907
}
1703916908
else if (Jim_IsShared(listObjPtr)) {
1704016909
listObjPtr = Jim_DuplicateObj(interp, listObjPtr);
@@ -17103,31 +16972,21 @@
1710316972
first = JimRelToAbsIndex(len, first);
1710416973
last = JimRelToAbsIndex(len, last);
1710516974
JimRelToAbsRange(len, &first, &last, &rangeLen);
1710616975
1710716976
17108
-
17109
- if (first < len) {
17110
-
17111
- }
17112
- else if (len == 0) {
17113
-
17114
- first = 0;
17115
- }
17116
- else {
17117
- Jim_SetResultString(interp, "list doesn't contain element ", -1);
17118
- Jim_AppendObj(interp, Jim_GetResult(interp), argv[2]);
17119
- return JIM_ERR;
17120
- }
17121
-
17122
-
16977
+ if (first > len) {
16978
+ first = len;
16979
+ }
16980
+
16981
+
1712316982
newListObj = Jim_NewListObj(interp, listObj->internalRep.listValue.ele, first);
1712416983
17125
-
16984
+
1712616985
ListInsertElements(newListObj, -1, argc - 4, argv + 4);
1712716986
17128
-
16987
+
1712916988
ListInsertElements(newListObj, -1, len - first - rangeLen, listObj->internalRep.listValue.ele + first + rangeLen);
1713016989
1713116990
Jim_SetResult(interp, newListObj);
1713216991
return JIM_OK;
1713316992
}
@@ -17138,11 +16997,11 @@
1713816997
if (argc < 3) {
1713916998
Jim_WrongNumArgs(interp, 1, argv, "listVar ?index...? newVal");
1714016999
return JIM_ERR;
1714117000
}
1714217001
else if (argc == 3) {
17143
-
17002
+
1714417003
if (Jim_SetVariable(interp, argv[1], argv[2]) != JIM_OK)
1714517004
return JIM_ERR;
1714617005
Jim_SetResult(interp, argv[2]);
1714717006
return JIM_OK;
1714817007
}
@@ -17158,10 +17017,11 @@
1715817017
enum
1715917018
{ OPT_ASCII, OPT_NOCASE, OPT_INCREASING, OPT_DECREASING, OPT_COMMAND, OPT_INTEGER, OPT_REAL, OPT_INDEX, OPT_UNIQUE };
1716017019
Jim_Obj *resObj;
1716117020
int i;
1716217021
int retCode;
17022
+ int shared;
1716317023
1716417024
struct lsort_info info;
1716517025
1716617026
if (argc < 2) {
1716717027
Jim_WrongNumArgs(interp, 1, argv, "?options? list");
@@ -17223,16 +17083,18 @@
1722317083
info.indexed = 1;
1722417084
i++;
1722517085
break;
1722617086
}
1722717087
}
17228
- resObj = Jim_DuplicateObj(interp, argv[argc - 1]);
17088
+ resObj = argv[argc - 1];
17089
+ if ((shared = Jim_IsShared(resObj)))
17090
+ resObj = Jim_DuplicateObj(interp, resObj);
1722917091
retCode = ListSortElements(interp, resObj, &info);
1723017092
if (retCode == JIM_OK) {
1723117093
Jim_SetResult(interp, resObj);
1723217094
}
17233
- else {
17095
+ else if (shared) {
1723417096
Jim_FreeNewObj(interp, resObj);
1723517097
}
1723617098
return retCode;
1723717099
}
1723817100
@@ -17253,11 +17115,11 @@
1725317115
}
1725417116
else {
1725517117
int new_obj = 0;
1725617118
stringObjPtr = Jim_GetVariable(interp, argv[1], JIM_UNSHARED);
1725717119
if (!stringObjPtr) {
17258
-
17120
+
1725917121
stringObjPtr = Jim_NewEmptyStringObj(interp);
1726017122
new_obj = 1;
1726117123
}
1726217124
else if (Jim_IsShared(stringObjPtr)) {
1726317125
new_obj = 1;
@@ -17274,10 +17136,11 @@
1727417136
}
1727517137
}
1727617138
Jim_SetResult(interp, stringObjPtr);
1727717139
return JIM_OK;
1727817140
}
17141
+
1727917142
1728017143
1728117144
static int Jim_DebugCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
1728217145
{
1728317146
#if !defined(JIM_DEBUG_COMMAND)
@@ -17302,11 +17165,11 @@
1730217165
else {
1730317166
rc = Jim_EvalObj(interp, Jim_ConcatObj(interp, argc - 1, argv + 1));
1730417167
}
1730517168
1730617169
if (rc == JIM_ERR) {
17307
-
17170
+
1730817171
interp->addStackTrace++;
1730917172
}
1731017173
return rc;
1731117174
}
1731217175
@@ -17316,14 +17179,14 @@
1731617179
if (argc >= 2) {
1731717180
int retcode;
1731817181
Jim_CallFrame *savedCallFrame, *targetCallFrame;
1731917182
const char *str;
1732017183
17321
-
17184
+
1732217185
savedCallFrame = interp->framePtr;
1732317186
17324
-
17187
+
1732517188
str = Jim_String(argv[1]);
1732617189
if ((str[0] >= '0' && str[0] <= '9') || str[0] == '#') {
1732717190
targetCallFrame = Jim_GetCallFrameByLevel(interp, argv[1]);
1732817191
argc--;
1732917192
argv++;
@@ -17336,11 +17199,11 @@
1733617199
}
1733717200
if (argc < 2) {
1733817201
Jim_WrongNumArgs(interp, 1, argv - 1, "?level? command ?arg ...?");
1733917202
return JIM_ERR;
1734017203
}
17341
-
17204
+
1734217205
interp->framePtr = targetCallFrame;
1734317206
if (argc == 2) {
1734417207
retcode = Jim_EvalObj(interp, argv[1]);
1734517208
}
1734617209
else {
@@ -17356,32 +17219,29 @@
1735617219
}
1735717220
1735817221
1735917222
static int Jim_ExprCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
1736017223
{
17361
- Jim_Obj *exprResultPtr;
1736217224
int retcode;
1736317225
1736417226
if (argc == 2) {
17365
- retcode = Jim_EvalExpression(interp, argv[1], &exprResultPtr);
17227
+ retcode = Jim_EvalExpression(interp, argv[1]);
1736617228
}
1736717229
else if (argc > 2) {
1736817230
Jim_Obj *objPtr;
1736917231
1737017232
objPtr = Jim_ConcatObj(interp, argc - 1, argv + 1);
1737117233
Jim_IncrRefCount(objPtr);
17372
- retcode = Jim_EvalExpression(interp, objPtr, &exprResultPtr);
17234
+ retcode = Jim_EvalExpression(interp, objPtr);
1737317235
Jim_DecrRefCount(interp, objPtr);
1737417236
}
1737517237
else {
1737617238
Jim_WrongNumArgs(interp, 1, argv, "expression ?...?");
1737717239
return JIM_ERR;
1737817240
}
1737917241
if (retcode != JIM_OK)
1738017242
return retcode;
17381
- Jim_SetResult(interp, exprResultPtr);
17382
- Jim_DecrRefCount(interp, exprResultPtr);
1738317243
return JIM_OK;
1738417244
}
1738517245
1738617246
1738717247
static int Jim_BreakCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
@@ -17438,15 +17298,15 @@
1743817298
if (i != argc - 1 && i != argc) {
1743917299
Jim_WrongNumArgs(interp, 1, argv,
1744017300
"?-code code? ?-errorinfo stacktrace? ?-level level? ?result?");
1744117301
}
1744217302
17443
-
17303
+
1744417304
if (stackTraceObj && returnCode == JIM_ERR) {
1744517305
JimSetStackTrace(interp, stackTraceObj);
1744617306
}
17447
-
17307
+
1744817308
if (errorCodeObj && returnCode == JIM_ERR) {
1744917309
Jim_SetGlobalVariableStr(interp, "errorCode", errorCodeObj);
1745017310
}
1745117311
interp->returnCode = returnCode;
1745217312
interp->returnLevel = level;
@@ -17463,31 +17323,31 @@
1746317323
if (interp->framePtr->level == 0) {
1746417324
Jim_SetResultString(interp, "tailcall can only be called from a proc or lambda", -1);
1746517325
return JIM_ERR;
1746617326
}
1746717327
else if (argc >= 2) {
17468
-
17328
+
1746917329
Jim_CallFrame *cf = interp->framePtr->parent;
1747017330
1747117331
Jim_Cmd *cmdPtr = Jim_GetCommand(interp, argv[1], JIM_ERRMSG);
1747217332
if (cmdPtr == NULL) {
1747317333
return JIM_ERR;
1747417334
}
1747517335
1747617336
JimPanic((cf->tailcallCmd != NULL, "Already have a tailcallCmd"));
1747717337
17478
-
17338
+
1747917339
JimIncrCmdRefCount(cmdPtr);
1748017340
cf->tailcallCmd = cmdPtr;
1748117341
17482
-
17342
+
1748317343
JimPanic((cf->tailcallObj != NULL, "Already have a tailcallobj"));
1748417344
1748517345
cf->tailcallObj = Jim_NewListObj(interp, argv + 1, argc - 1);
1748617346
Jim_IncrRefCount(cf->tailcallObj);
1748717347
17488
-
17348
+
1748917349
return JIM_EVAL;
1749017350
}
1749117351
return JIM_OK;
1749217352
}
1749317353
@@ -17494,11 +17354,11 @@
1749417354
static int JimAliasCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
1749517355
{
1749617356
Jim_Obj *cmdList;
1749717357
Jim_Obj *prefixListObj = Jim_CmdPrivData(interp);
1749817358
17499
-
17359
+
1750017360
cmdList = Jim_DuplicateObj(interp, prefixListObj);
1750117361
Jim_ListInsertElements(interp, cmdList, Jim_ListLength(interp, cmdList), argc - 1, argv + 1);
1750217362
1750317363
return JimEvalObjList(interp, cmdList);
1750417364
}
@@ -17552,22 +17412,22 @@
1755217412
else {
1755317413
cmd = JimCreateProcedureCmd(interp, argv[2], argv[3], argv[4], NULL);
1755417414
}
1755517415
1755617416
if (cmd) {
17557
-
17417
+
1755817418
Jim_Obj *qualifiedCmdNameObj;
1755917419
const char *cmdname = JimQualifyName(interp, Jim_String(argv[1]), &qualifiedCmdNameObj);
1756017420
1756117421
JimCreateCommand(interp, cmdname, cmd);
1756217422
17563
-
17423
+
1756417424
JimUpdateProcNamespace(interp, cmd, cmdname);
1756517425
1756617426
JimFreeQualifiedName(interp, qualifiedCmdNameObj);
1756717427
17568
-
17428
+
1756917429
Jim_SetResult(interp, argv[1]);
1757017430
return JIM_OK;
1757117431
}
1757217432
return JIM_ERR;
1757317433
}
@@ -17580,17 +17440,17 @@
1758017440
if (argc < 2) {
1758117441
Jim_WrongNumArgs(interp, 1, argv, "cmd ?args ...?");
1758217442
return JIM_ERR;
1758317443
}
1758417444
17585
-
17445
+
1758617446
interp->local++;
1758717447
retcode = Jim_EvalObjVector(interp, argc - 1, argv + 1);
1758817448
interp->local--;
1758917449
1759017450
17591
-
17451
+
1759217452
if (retcode == 0) {
1759317453
Jim_Obj *cmdNameObj = Jim_GetResult(interp);
1759417454
1759517455
if (Jim_GetCommand(interp, cmdNameObj, JIM_ERRMSG) == NULL) {
1759617456
return JIM_ERR;
@@ -17619,18 +17479,18 @@
1761917479
Jim_Cmd *cmdPtr = Jim_GetCommand(interp, argv[1], JIM_ERRMSG);
1762017480
if (cmdPtr == NULL || !cmdPtr->isproc || !cmdPtr->prevCmd) {
1762117481
Jim_SetResultFormatted(interp, "no previous command: \"%#s\"", argv[1]);
1762217482
return JIM_ERR;
1762317483
}
17624
-
17484
+
1762517485
cmdPtr->u.proc.upcall++;
1762617486
JimIncrCmdRefCount(cmdPtr);
1762717487
17628
-
17488
+
1762917489
retcode = Jim_EvalObjVector(interp, argc - 1, argv + 1);
1763017490
17631
-
17491
+
1763217492
cmdPtr->u.proc.upcall--;
1763317493
JimDecrCmdRefCount(interp, cmdPtr);
1763417494
1763517495
return retcode;
1763617496
}
@@ -17657,11 +17517,11 @@
1765717517
return JIM_ERR;
1765817518
}
1765917519
1766017520
if (len == 3) {
1766117521
#ifdef jim_ext_namespace
17662
-
17522
+
1766317523
nsObj = JimQualifyNameObj(interp, Jim_ListGetIndex(interp, argv[1], 2));
1766417524
#else
1766517525
Jim_SetResultString(interp, "namespaces not enabled", -1);
1766617526
return JIM_ERR;
1766717527
#endif
@@ -17670,11 +17530,11 @@
1767017530
bodyObjPtr = Jim_ListGetIndex(interp, argv[1], 1);
1767117531
1767217532
cmd = JimCreateProcedureCmd(interp, argListObjPtr, NULL, bodyObjPtr, nsObj);
1767317533
1767417534
if (cmd) {
17675
-
17535
+
1767617536
nargv = Jim_Alloc((argc - 2 + 1) * sizeof(*nargv));
1767717537
nargv[0] = Jim_NewStringObj(interp, "apply lambdaExpr", -1);
1767817538
Jim_IncrRefCount(nargv[0]);
1767917539
memcpy(&nargv[1], argv + 2, (argc - 2) * sizeof(*nargv));
1768017540
ret = JimCallProcedure(interp, cmd, argc - 2 + 1, nargv);
@@ -17700,11 +17560,11 @@
1770017560
static int Jim_UpvarCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
1770117561
{
1770217562
int i;
1770317563
Jim_CallFrame *targetCallFrame;
1770417564
17705
-
17565
+
1770617566
if (argc > 3 && (argc % 2 == 0)) {
1770717567
targetCallFrame = Jim_GetCallFrameByLevel(interp, argv[1]);
1770817568
argc--;
1770917569
argv++;
1771017570
}
@@ -17713,17 +17573,17 @@
1771317573
}
1771417574
if (targetCallFrame == NULL) {
1771517575
return JIM_ERR;
1771617576
}
1771717577
17718
-
17578
+
1771917579
if (argc < 3) {
1772017580
Jim_WrongNumArgs(interp, 1, argv, "?level? otherVar localVar ?otherVar localVar ...?");
1772117581
return JIM_ERR;
1772217582
}
1772317583
17724
-
17584
+
1772517585
for (i = 1; i < argc; i += 2) {
1772617586
if (Jim_SetVariableLink(interp, argv[i + 1], argv[i], targetCallFrame) != JIM_OK)
1772717587
return JIM_ERR;
1772817588
}
1772917589
return JIM_OK;
@@ -17736,15 +17596,15 @@
1773617596
1773717597
if (argc < 2) {
1773817598
Jim_WrongNumArgs(interp, 1, argv, "varName ?varName ...?");
1773917599
return JIM_ERR;
1774017600
}
17741
-
17601
+
1774217602
if (interp->framePtr->level == 0)
17743
- return JIM_OK;
17603
+ return JIM_OK;
1774417604
for (i = 1; i < argc; i++) {
17745
-
17605
+
1774617606
const char *name = Jim_String(argv[i]);
1774717607
if (name[0] != ':' || name[1] != ':') {
1774817608
if (Jim_SetVariableLink(interp, argv[i], argv[i], interp->topFramePtr) != JIM_OK)
1774917609
return JIM_ERR;
1775017610
}
@@ -17767,21 +17627,21 @@
1776717627
}
1776817628
1776917629
str = Jim_String(objPtr);
1777017630
strLen = Jim_Utf8Length(interp, objPtr);
1777117631
17772
-
17632
+
1777317633
resultObjPtr = Jim_NewStringObj(interp, "", 0);
1777417634
while (strLen) {
1777517635
for (i = 0; i < numMaps; i += 2) {
17776
- Jim_Obj *objPtr;
17636
+ Jim_Obj *eachObjPtr;
1777717637
const char *k;
1777817638
int kl;
1777917639
17780
- objPtr = Jim_ListGetIndex(interp, mapListObjPtr, i);
17781
- k = Jim_String(objPtr);
17782
- kl = Jim_Utf8Length(interp, objPtr);
17640
+ eachObjPtr = Jim_ListGetIndex(interp, mapListObjPtr, i);
17641
+ k = Jim_String(eachObjPtr);
17642
+ kl = Jim_Utf8Length(interp, eachObjPtr);
1778317643
1778417644
if (strLen >= kl && kl) {
1778517645
int rc;
1778617646
rc = JimStringCompareLen(str, k, kl, nocase);
1778717647
if (rc == 0) {
@@ -17794,11 +17654,11 @@
1779417654
strLen -= kl;
1779517655
break;
1779617656
}
1779717657
}
1779817658
}
17799
- if (i == numMaps) {
17659
+ if (i == numMaps) {
1780017660
int c;
1780117661
if (noMatchStart == NULL)
1780217662
noMatchStart = str;
1780317663
str += utf8_tounicode(str, &c);
1780417664
strLen--;
@@ -17838,11 +17698,11 @@
1783817698
Jim_WrongNumArgs(interp, 1, argv, "option ?arguments ...?");
1783917699
return JIM_ERR;
1784017700
}
1784117701
if (Jim_GetEnum(interp, argv[1], options, &option, NULL,
1784217702
JIM_ERRMSG | JIM_ENUM_ABBREV) != JIM_OK)
17843
- return JIM_ERR;
17703
+ return Jim_CheckShowCommands(interp, argv[1], options);
1784417704
1784517705
switch (option) {
1784617706
case OPT_LENGTH:
1784717707
case OPT_BYTELENGTH:
1784817708
if (argc != 3) {
@@ -17859,11 +17719,11 @@
1785917719
return JIM_OK;
1786017720
1786117721
case OPT_CAT:{
1786217722
Jim_Obj *objPtr;
1786317723
if (argc == 3) {
17864
-
17724
+
1786517725
objPtr = argv[2];
1786617726
}
1786717727
else {
1786817728
int i;
1786917729
@@ -17878,11 +17738,11 @@
1787817738
}
1787917739
1788017740
case OPT_COMPARE:
1788117741
case OPT_EQUAL:
1788217742
{
17883
-
17743
+
1788417744
long opt_length = -1;
1788517745
int n = argc - 4;
1788617746
int i = 2;
1788717747
while (n > 0) {
1788817748
int subopt;
@@ -17891,16 +17751,16 @@
1789117751
badcompareargs:
1789217752
Jim_WrongNumArgs(interp, 2, argv, "?-nocase? ?-length int? string1 string2");
1789317753
return JIM_ERR;
1789417754
}
1789517755
if (subopt == 0) {
17896
-
17756
+
1789717757
opt_case = 0;
1789817758
n--;
1789917759
}
1790017760
else {
17901
-
17761
+
1790217762
if (n < 2) {
1790317763
goto badcompareargs;
1790417764
}
1790517765
if (Jim_GetLong(interp, argv[i++], &opt_length) != JIM_OK) {
1790617766
return JIM_ERR;
@@ -17911,11 +17771,11 @@
1791117771
if (n) {
1791217772
goto badcompareargs;
1791317773
}
1791417774
argv += argc - 2;
1791517775
if (opt_length < 0 && option != OPT_COMPARE && opt_case) {
17916
-
17776
+
1791717777
Jim_SetResultBool(interp, Jim_StringEqObj(argv[0], argv[1]));
1791817778
}
1791917779
else {
1792017780
if (opt_length >= 0) {
1792117781
n = JimStringCompareLen(Jim_String(argv[0]), Jim_String(argv[1]), opt_length, !opt_case);
@@ -18025,11 +17885,10 @@
1802517885
}
1802617886
1802717887
case OPT_REVERSE:{
1802817888
char *buf, *p;
1802917889
const char *str;
18030
- int len;
1803117890
int i;
1803217891
1803317892
if (argc != 3) {
1803417893
Jim_WrongNumArgs(interp, 2, argv, "string");
1803517894
return JIM_ERR;
@@ -18069,11 +17928,11 @@
1806917928
}
1807017929
if (idx < 0 || idx >= len || str == NULL) {
1807117930
Jim_SetResultString(interp, "", 0);
1807217931
}
1807317932
else if (len == Jim_Length(argv[2])) {
18074
-
17933
+
1807517934
Jim_SetResultString(interp, str + idx, 1);
1807617935
}
1807717936
else {
1807817937
int c;
1807917938
int i = utf8_index(str, idx);
@@ -18223,11 +18082,11 @@
1822318082
{
1822418083
int exitCode = 0;
1822518084
int i;
1822618085
int sig = 0;
1822718086
18228
-
18087
+
1822918088
jim_wide ignore_mask = (1 << JIM_EXIT) | (1 << JIM_EVAL) | (1 << JIM_SIGNAL);
1823018089
static const int max_ignore_code = sizeof(ignore_mask) * 8;
1823118090
1823218091
Jim_SetGlobalVariableStr(interp, "errorCode", Jim_NewStringObj(interp, "NONE", -1));
1823318092
@@ -18234,11 +18093,11 @@
1823418093
for (i = 1; i < argc - 1; i++) {
1823518094
const char *arg = Jim_String(argv[i]);
1823618095
jim_wide option;
1823718096
int ignore;
1823818097
18239
-
18098
+
1824018099
if (strcmp(arg, "--") == 0) {
1824118100
i++;
1824218101
break;
1824318102
}
1824418103
if (*arg != '-') {
@@ -18285,28 +18144,28 @@
1828518144
sig++;
1828618145
}
1828718146
1828818147
interp->signal_level += sig;
1828918148
if (Jim_CheckSignal(interp)) {
18290
-
18149
+
1829118150
exitCode = JIM_SIGNAL;
1829218151
}
1829318152
else {
1829418153
exitCode = Jim_EvalObj(interp, argv[0]);
18295
-
18154
+
1829618155
interp->errorFlag = 0;
1829718156
}
1829818157
interp->signal_level -= sig;
1829918158
18300
-
18159
+
1830118160
if (exitCode >= 0 && exitCode < max_ignore_code && (((unsigned jim_wide)1 << exitCode) & ignore_mask)) {
18302
-
18161
+
1830318162
return exitCode;
1830418163
}
1830518164
1830618165
if (sig && exitCode == JIM_SIGNAL) {
18307
-
18166
+
1830818167
if (interp->signal_set_result) {
1830918168
interp->signal_set_result(interp, interp->sigmask);
1831018169
}
1831118170
else {
1831218171
Jim_SetResultInt(interp, interp->sigmask);
@@ -18345,125 +18204,10 @@
1834518204
}
1834618205
Jim_SetResultInt(interp, exitCode);
1834718206
return JIM_OK;
1834818207
}
1834918208
18350
-#ifdef JIM_REFERENCES
18351
-
18352
-
18353
-static int Jim_RefCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
18354
-{
18355
- if (argc != 3 && argc != 4) {
18356
- Jim_WrongNumArgs(interp, 1, argv, "string tag ?finalizer?");
18357
- return JIM_ERR;
18358
- }
18359
- if (argc == 3) {
18360
- Jim_SetResult(interp, Jim_NewReference(interp, argv[1], argv[2], NULL));
18361
- }
18362
- else {
18363
- Jim_SetResult(interp, Jim_NewReference(interp, argv[1], argv[2], argv[3]));
18364
- }
18365
- return JIM_OK;
18366
-}
18367
-
18368
-
18369
-static int Jim_GetrefCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
18370
-{
18371
- Jim_Reference *refPtr;
18372
-
18373
- if (argc != 2) {
18374
- Jim_WrongNumArgs(interp, 1, argv, "reference");
18375
- return JIM_ERR;
18376
- }
18377
- if ((refPtr = Jim_GetReference(interp, argv[1])) == NULL)
18378
- return JIM_ERR;
18379
- Jim_SetResult(interp, refPtr->objPtr);
18380
- return JIM_OK;
18381
-}
18382
-
18383
-
18384
-static int Jim_SetrefCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
18385
-{
18386
- Jim_Reference *refPtr;
18387
-
18388
- if (argc != 3) {
18389
- Jim_WrongNumArgs(interp, 1, argv, "reference newValue");
18390
- return JIM_ERR;
18391
- }
18392
- if ((refPtr = Jim_GetReference(interp, argv[1])) == NULL)
18393
- return JIM_ERR;
18394
- Jim_IncrRefCount(argv[2]);
18395
- Jim_DecrRefCount(interp, refPtr->objPtr);
18396
- refPtr->objPtr = argv[2];
18397
- Jim_SetResult(interp, argv[2]);
18398
- return JIM_OK;
18399
-}
18400
-
18401
-
18402
-static int Jim_CollectCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
18403
-{
18404
- if (argc != 1) {
18405
- Jim_WrongNumArgs(interp, 1, argv, "");
18406
- return JIM_ERR;
18407
- }
18408
- Jim_SetResultInt(interp, Jim_Collect(interp));
18409
-
18410
-
18411
- while (interp->freeList) {
18412
- Jim_Obj *nextObjPtr = interp->freeList->nextObjPtr;
18413
- Jim_Free(interp->freeList);
18414
- interp->freeList = nextObjPtr;
18415
- }
18416
-
18417
- return JIM_OK;
18418
-}
18419
-
18420
-
18421
-static int Jim_FinalizeCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
18422
-{
18423
- if (argc != 2 && argc != 3) {
18424
- Jim_WrongNumArgs(interp, 1, argv, "reference ?finalizerProc?");
18425
- return JIM_ERR;
18426
- }
18427
- if (argc == 2) {
18428
- Jim_Obj *cmdNamePtr;
18429
-
18430
- if (Jim_GetFinalizer(interp, argv[1], &cmdNamePtr) != JIM_OK)
18431
- return JIM_ERR;
18432
- if (cmdNamePtr != NULL)
18433
- Jim_SetResult(interp, cmdNamePtr);
18434
- }
18435
- else {
18436
- if (Jim_SetFinalizer(interp, argv[1], argv[2]) != JIM_OK)
18437
- return JIM_ERR;
18438
- Jim_SetResult(interp, argv[2]);
18439
- }
18440
- return JIM_OK;
18441
-}
18442
-
18443
-
18444
-static int JimInfoReferences(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
18445
-{
18446
- Jim_Obj *listObjPtr;
18447
- Jim_HashTableIterator htiter;
18448
- Jim_HashEntry *he;
18449
-
18450
- listObjPtr = Jim_NewListObj(interp, NULL, 0);
18451
-
18452
- JimInitHashTableIterator(&interp->references, &htiter);
18453
- while ((he = Jim_NextHashEntry(&htiter)) != NULL) {
18454
- char buf[JIM_REFERENCE_SPACE + 1];
18455
- Jim_Reference *refPtr = Jim_GetHashEntryVal(he);
18456
- const unsigned long *refId = he->key;
18457
-
18458
- JimFormatReference(buf, refPtr, *refId);
18459
- Jim_ListAppendElement(interp, listObjPtr, Jim_NewStringObj(interp, buf, -1));
18460
- }
18461
- Jim_SetResult(interp, listObjPtr);
18462
- return JIM_OK;
18463
-}
18464
-#endif
1846518209
1846618210
1846718211
static int Jim_RenameCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
1846818212
{
1846918213
if (argc != 3) {
@@ -18476,56 +18220,43 @@
1847618220
}
1847718221
1847818222
return Jim_RenameCommand(interp, Jim_String(argv[1]), Jim_String(argv[2]));
1847918223
}
1848018224
18481
-#define JIM_DICTMATCH_VALUES 0x0001
18482
-
18483
-typedef void JimDictMatchCallbackType(Jim_Interp *interp, Jim_Obj *listObjPtr, Jim_HashEntry *he, int type);
18484
-
18485
-static void JimDictMatchKeys(Jim_Interp *interp, Jim_Obj *listObjPtr, Jim_HashEntry *he, int type)
18486
-{
18487
- Jim_ListAppendElement(interp, listObjPtr, (Jim_Obj *)he->key);
18488
- if (type & JIM_DICTMATCH_VALUES) {
18489
- Jim_ListAppendElement(interp, listObjPtr, Jim_GetHashEntryVal(he));
18490
- }
18491
-}
18492
-
18493
-static Jim_Obj *JimDictPatternMatch(Jim_Interp *interp, Jim_HashTable *ht, Jim_Obj *patternObjPtr,
18494
- JimDictMatchCallbackType *callback, int type)
18495
-{
18496
- Jim_HashEntry *he;
18497
- Jim_Obj *listObjPtr = Jim_NewListObj(interp, NULL, 0);
18498
-
18499
-
18500
- Jim_HashTableIterator htiter;
18501
- JimInitHashTableIterator(ht, &htiter);
18502
- while ((he = Jim_NextHashEntry(&htiter)) != NULL) {
18503
- if (patternObjPtr == NULL || JimGlobMatch(Jim_String(patternObjPtr), Jim_String((Jim_Obj *)he->key), 0)) {
18504
- callback(interp, listObjPtr, he, type);
18505
- }
18506
- }
18507
-
18508
- return listObjPtr;
18509
-}
18510
-
18511
-
18512
-int Jim_DictKeys(Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj *patternObjPtr)
18513
-{
18514
- if (SetDictFromAny(interp, objPtr) != JIM_OK) {
18515
- return JIM_ERR;
18516
- }
18517
- Jim_SetResult(interp, JimDictPatternMatch(interp, objPtr->internalRep.ptr, patternObjPtr, JimDictMatchKeys, 0));
18518
- return JIM_OK;
18519
-}
18520
-
18521
-int Jim_DictValues(Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj *patternObjPtr)
18522
-{
18523
- if (SetDictFromAny(interp, objPtr) != JIM_OK) {
18524
- return JIM_ERR;
18525
- }
18526
- Jim_SetResult(interp, JimDictPatternMatch(interp, objPtr->internalRep.ptr, patternObjPtr, JimDictMatchKeys, JIM_DICTMATCH_VALUES));
18225
+#define JIM_DICTMATCH_KEYS 0x0001
18226
+#define JIM_DICTMATCH_VALUES 0x002
18227
+
18228
+int Jim_DictMatchTypes(Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj *patternObj, int match_type, int return_types)
18229
+{
18230
+ Jim_HashEntry *he;
18231
+ Jim_Obj *listObjPtr;
18232
+ Jim_HashTableIterator htiter;
18233
+
18234
+ if (SetDictFromAny(interp, objPtr) != JIM_OK) {
18235
+ return JIM_ERR;
18236
+ }
18237
+
18238
+ listObjPtr = Jim_NewListObj(interp, NULL, 0);
18239
+
18240
+ JimInitHashTableIterator(objPtr->internalRep.ptr, &htiter);
18241
+ while ((he = Jim_NextHashEntry(&htiter)) != NULL) {
18242
+ if (patternObj) {
18243
+ Jim_Obj *matchObj = (match_type == JIM_DICTMATCH_KEYS) ? (Jim_Obj *)he->key : Jim_GetHashEntryVal(he);
18244
+ if (!JimGlobMatch(Jim_String(patternObj), Jim_String(matchObj), 0)) {
18245
+
18246
+ continue;
18247
+ }
18248
+ }
18249
+ if (return_types & JIM_DICTMATCH_KEYS) {
18250
+ Jim_ListAppendElement(interp, listObjPtr, (Jim_Obj *)he->key);
18251
+ }
18252
+ if (return_types & JIM_DICTMATCH_VALUES) {
18253
+ Jim_ListAppendElement(interp, listObjPtr, Jim_GetHashEntryVal(he));
18254
+ }
18255
+ }
18256
+
18257
+ Jim_SetResult(interp, listObjPtr);
1852718258
return JIM_OK;
1852818259
}
1852918260
1853018261
int Jim_DictSize(Jim_Interp *interp, Jim_Obj *objPtr)
1853118262
{
@@ -18532,38 +18263,85 @@
1853218263
if (SetDictFromAny(interp, objPtr) != JIM_OK) {
1853318264
return -1;
1853418265
}
1853518266
return ((Jim_HashTable *)objPtr->internalRep.ptr)->used;
1853618267
}
18268
+
18269
+Jim_Obj *Jim_DictMerge(Jim_Interp *interp, int objc, Jim_Obj *const *objv)
18270
+{
18271
+ Jim_Obj *objPtr = Jim_NewDictObj(interp, NULL, 0);
18272
+ int i;
18273
+
18274
+ JimPanic((objc == 0, "Jim_DictMerge called with objc=0"));
18275
+
18276
+
18277
+
18278
+ for (i = 0; i < objc; i++) {
18279
+ Jim_HashTable *ht;
18280
+ Jim_HashTableIterator htiter;
18281
+ Jim_HashEntry *he;
18282
+
18283
+ if (SetDictFromAny(interp, objv[i]) != JIM_OK) {
18284
+ Jim_FreeNewObj(interp, objPtr);
18285
+ return NULL;
18286
+ }
18287
+ ht = objv[i]->internalRep.ptr;
18288
+ JimInitHashTableIterator(ht, &htiter);
18289
+ while ((he = Jim_NextHashEntry(&htiter)) != NULL) {
18290
+ Jim_ReplaceHashEntry(objPtr->internalRep.ptr, Jim_GetHashEntryKey(he), Jim_GetHashEntryVal(he));
18291
+ }
18292
+ }
18293
+ return objPtr;
18294
+}
1853718295
1853818296
int Jim_DictInfo(Jim_Interp *interp, Jim_Obj *objPtr)
1853918297
{
1854018298
Jim_HashTable *ht;
1854118299
unsigned int i;
18300
+ char buffer[100];
18301
+ int sum = 0;
18302
+ int nonzero_count = 0;
18303
+ Jim_Obj *output;
18304
+ int bucket_counts[11] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
1854218305
1854318306
if (SetDictFromAny(interp, objPtr) != JIM_OK) {
1854418307
return JIM_ERR;
1854518308
}
1854618309
1854718310
ht = (Jim_HashTable *)objPtr->internalRep.ptr;
1854818311
18549
-
18550
- printf("%d entries in table, %d buckets\n", ht->used, ht->size);
18312
+
18313
+ snprintf(buffer, sizeof(buffer), "%d entries in table, %d buckets\n", ht->used, ht->size);
18314
+ output = Jim_NewStringObj(interp, buffer, -1);
1855118315
1855218316
for (i = 0; i < ht->size; i++) {
1855318317
Jim_HashEntry *he = ht->table[i];
18554
-
18555
- if (he) {
18556
- printf("%d: ", i);
18557
-
18558
- while (he) {
18559
- printf(" %s", Jim_String(he->key));
18560
- he = he->next;
18561
- }
18562
- printf("\n");
18318
+ int entries = 0;
18319
+ while (he) {
18320
+ entries++;
18321
+ he = he->next;
18322
+ }
18323
+ if (entries > 9) {
18324
+ bucket_counts[10]++;
18325
+ }
18326
+ else {
18327
+ bucket_counts[entries]++;
18328
+ }
18329
+ if (entries) {
18330
+ sum += entries;
18331
+ nonzero_count++;
1856318332
}
1856418333
}
18334
+ for (i = 0; i < 10; i++) {
18335
+ snprintf(buffer, sizeof(buffer), "number of buckets with %d entries: %d\n", i, bucket_counts[i]);
18336
+ Jim_AppendString(interp, output, buffer, -1);
18337
+ }
18338
+ snprintf(buffer, sizeof(buffer), "number of buckets with 10 or more entries: %d\n", bucket_counts[10]);
18339
+ Jim_AppendString(interp, output, buffer, -1);
18340
+ snprintf(buffer, sizeof(buffer), "average search distance for entry: %.1f", nonzero_count ? (double)sum / nonzero_count : 0.0);
18341
+ Jim_AppendString(interp, output, buffer, -1);
18342
+ Jim_SetResult(interp, output);
1856518343
return JIM_OK;
1856618344
}
1856718345
1856818346
static int Jim_EvalEnsemble(Jim_Interp *interp, const char *basecmd, const char *subcmd, int argc, Jim_Obj *const *argv)
1856918347
{
@@ -18573,14 +18351,67 @@
1857318351
Jim_AppendString(interp, prefixObj, subcmd, -1);
1857418352
1857518353
return Jim_EvalObjPrefix(interp, prefixObj, argc, argv);
1857618354
}
1857718355
18356
+static int JimDictWith(Jim_Interp *interp, Jim_Obj *dictVarName, Jim_Obj *const *keyv, int keyc, Jim_Obj *scriptObj)
18357
+{
18358
+ int i;
18359
+ Jim_Obj *objPtr;
18360
+ Jim_Obj *dictObj;
18361
+ Jim_Obj **dictValues;
18362
+ int len;
18363
+ int ret = JIM_OK;
18364
+
18365
+
18366
+ dictObj = Jim_GetVariable(interp, dictVarName, JIM_ERRMSG);
18367
+ if (dictObj == NULL || Jim_DictKeysVector(interp, dictObj, keyv, keyc, &objPtr, JIM_ERRMSG) != JIM_OK) {
18368
+ return JIM_ERR;
18369
+ }
18370
+
18371
+ if (Jim_DictPairs(interp, objPtr, &dictValues, &len) == JIM_ERR) {
18372
+ return JIM_ERR;
18373
+ }
18374
+ for (i = 0; i < len; i += 2) {
18375
+ if (Jim_SetVariable(interp, dictValues[i], dictValues[i + 1]) == JIM_ERR) {
18376
+ Jim_Free(dictValues);
18377
+ return JIM_ERR;
18378
+ }
18379
+ }
18380
+
18381
+
18382
+ if (Jim_Length(scriptObj)) {
18383
+ ret = Jim_EvalObj(interp, scriptObj);
18384
+
18385
+
18386
+ if (ret == JIM_OK && Jim_GetVariable(interp, dictVarName, 0) != NULL) {
18387
+
18388
+ Jim_Obj **newkeyv = Jim_Alloc(sizeof(*newkeyv) * (keyc + 1));
18389
+ for (i = 0; i < keyc; i++) {
18390
+ newkeyv[i] = keyv[i];
18391
+ }
18392
+
18393
+ for (i = 0; i < len; i += 2) {
18394
+
18395
+ objPtr = Jim_GetVariable(interp, dictValues[i], 0);
18396
+ newkeyv[keyc] = dictValues[i];
18397
+ Jim_SetDictKeysVector(interp, dictVarName, newkeyv, keyc + 1, objPtr, 0);
18398
+ }
18399
+ Jim_Free(newkeyv);
18400
+ }
18401
+ }
18402
+
18403
+ Jim_Free(dictValues);
18404
+
18405
+ return ret;
18406
+}
18407
+
1857818408
1857918409
static int Jim_DictCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
1858018410
{
1858118411
Jim_Obj *objPtr;
18412
+ int types = JIM_DICTMATCH_KEYS;
1858218413
int option;
1858318414
static const char * const options[] = {
1858418415
"create", "get", "set", "unset", "exists", "keys", "size", "info",
1858518416
"merge", "with", "append", "lappend", "incr", "remove", "values", "for",
1858618417
"replace", "update", NULL
@@ -18596,11 +18427,11 @@
1859618427
Jim_WrongNumArgs(interp, 1, argv, "subcommand ?arguments ...?");
1859718428
return JIM_ERR;
1859818429
}
1859918430
1860018431
if (Jim_GetEnum(interp, argv[1], options, &option, "subcommand", JIM_ERRMSG) != JIM_OK) {
18601
- return JIM_ERR;
18432
+ return Jim_CheckShowCommands(interp, argv[1], options);
1860218433
}
1860318434
1860418435
switch (option) {
1860518436
case OPT_GET:
1860618437
if (argc < 3) {
@@ -18643,16 +18474,19 @@
1864318474
if (Jim_SetDictKeysVector(interp, argv[2], argv + 3, argc - 3, NULL, 0) != JIM_OK) {
1864418475
return JIM_ERR;
1864518476
}
1864618477
return JIM_OK;
1864718478
18479
+ case OPT_VALUES:
18480
+ types = JIM_DICTMATCH_VALUES;
18481
+
1864818482
case OPT_KEYS:
1864918483
if (argc != 3 && argc != 4) {
1865018484
Jim_WrongNumArgs(interp, 2, argv, "dictionary ?pattern?");
1865118485
return JIM_ERR;
1865218486
}
18653
- return Jim_DictKeys(interp, argv[2], argc == 4 ? argv[3] : NULL);
18487
+ return Jim_DictMatchTypes(interp, argv[2], argc == 4 ? argv[3] : NULL, types, types);
1865418488
1865518489
case OPT_SIZE:
1865618490
if (argc != 3) {
1865718491
Jim_WrongNumArgs(interp, 2, argv, "dictionary");
1865818492
return JIM_ERR;
@@ -18665,19 +18499,20 @@
1866518499
1866618500
case OPT_MERGE:
1866718501
if (argc == 2) {
1866818502
return JIM_OK;
1866918503
}
18670
- if (Jim_DictSize(interp, argv[2]) < 0) {
18504
+ objPtr = Jim_DictMerge(interp, argc - 2, argv + 2);
18505
+ if (objPtr == NULL) {
1867118506
return JIM_ERR;
1867218507
}
18673
-
18674
- break;
18508
+ Jim_SetResult(interp, objPtr);
18509
+ return JIM_OK;
1867518510
1867618511
case OPT_UPDATE:
1867718512
if (argc < 6 || argc % 2) {
18678
-
18513
+
1867918514
argc = 2;
1868018515
}
1868118516
break;
1868218517
1868318518
case OPT_CREATE:
@@ -18693,12 +18528,19 @@
1869318528
if (argc != 3) {
1869418529
Jim_WrongNumArgs(interp, 2, argv, "dictionary");
1869518530
return JIM_ERR;
1869618531
}
1869718532
return Jim_DictInfo(interp, argv[2]);
18533
+
18534
+ case OPT_WITH:
18535
+ if (argc < 4) {
18536
+ Jim_WrongNumArgs(interp, 2, argv, "dictVar ?key ...? script");
18537
+ return JIM_ERR;
18538
+ }
18539
+ return JimDictWith(interp, argv[2], argv + 3, argc - 4, argv[argc - 1]);
1869818540
}
18699
-
18541
+
1870018542
return Jim_EvalEnsemble(interp, "dict", options[option], argc - 2, argv + 2);
1870118543
}
1870218544
1870318545
1870418546
static int Jim_SubstCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
@@ -18764,11 +18606,11 @@
1876418606
1876518607
#ifdef jim_ext_namespace
1876618608
int nons = 0;
1876718609
1876818610
if (argc > 2 && Jim_CompareStringImmediate(interp, argv[1], "-nons")) {
18769
-
18611
+
1877018612
argc--;
1877118613
argv++;
1877218614
nons = 1;
1877318615
}
1877418616
#endif
@@ -18775,16 +18617,15 @@
1877518617
1877618618
if (argc < 2) {
1877718619
Jim_WrongNumArgs(interp, 1, argv, "subcommand ?args ...?");
1877818620
return JIM_ERR;
1877918621
}
18780
- if (Jim_GetEnum(interp, argv[1], commands, &cmd, "subcommand", JIM_ERRMSG | JIM_ENUM_ABBREV)
18781
- != JIM_OK) {
18782
- return JIM_ERR;
18622
+ if (Jim_GetEnum(interp, argv[1], commands, &cmd, "subcommand", JIM_ERRMSG | JIM_ENUM_ABBREV) != JIM_OK) {
18623
+ return Jim_CheckShowCommands(interp, argv[1], commands);
1878318624
}
1878418625
18785
-
18626
+
1878618627
switch (cmd) {
1878718628
case INFO_EXISTS:
1878818629
if (argc != 3) {
1878918630
Jim_WrongNumArgs(interp, 2, argv, "varName");
1879018631
return JIM_ERR;
@@ -18809,21 +18650,21 @@
1880918650
Jim_SetResult(interp, (Jim_Obj *)cmdPtr->u.native.privData);
1881018651
return JIM_OK;
1881118652
}
1881218653
1881318654
case INFO_CHANNELS:
18814
- mode++;
18655
+ mode++;
1881518656
#ifndef jim_ext_aio
1881618657
Jim_SetResultString(interp, "aio not enabled", -1);
1881718658
return JIM_ERR;
1881818659
#endif
18819
-
18660
+
1882018661
case INFO_PROCS:
18821
- mode++;
18822
-
18662
+ mode++;
18663
+
1882318664
case INFO_COMMANDS:
18824
-
18665
+
1882518666
if (argc != 2 && argc != 3) {
1882618667
Jim_WrongNumArgs(interp, 2, argv, "?pattern?");
1882718668
return JIM_ERR;
1882818669
}
1882918670
#ifdef jim_ext_namespace
@@ -18835,17 +18676,17 @@
1883518676
#endif
1883618677
Jim_SetResult(interp, JimCommandsList(interp, (argc == 3) ? argv[2] : NULL, mode));
1883718678
break;
1883818679
1883918680
case INFO_VARS:
18840
- mode++;
18841
-
18681
+ mode++;
18682
+
1884218683
case INFO_LOCALS:
18843
- mode++;
18844
-
18684
+ mode++;
18685
+
1884518686
case INFO_GLOBALS:
18846
-
18687
+
1884718688
if (argc != 2 && argc != 3) {
1884818689
Jim_WrongNumArgs(interp, 2, argv, "?pattern?");
1884918690
return JIM_ERR;
1885018691
}
1885118692
#ifdef jim_ext_namespace
@@ -18951,13 +18792,12 @@
1895118792
case INFO_ARGS:
1895218793
Jim_SetResult(interp, cmdPtr->u.proc.argListObjPtr);
1895318794
break;
1895418795
case INFO_STATICS:
1895518796
if (cmdPtr->u.proc.staticVars) {
18956
- int mode = JIM_VARLIST_LOCALS | JIM_VARLIST_VALUES;
1895718797
Jim_SetResult(interp, JimHashtablePatternMatch(interp, cmdPtr->u.proc.staticVars,
18958
- NULL, JimVariablesMatch, mode));
18798
+ NULL, JimVariablesMatch, JIM_VARLIST_LOCALS | JIM_VARLIST_VALUES));
1895918799
}
1896018800
break;
1896118801
}
1896218802
break;
1896318803
}
@@ -18985,15 +18825,15 @@
1898518825
}
1898618826
}
1898718827
break;
1898818828
1898918829
case INFO_HOSTNAME:
18990
-
18830
+
1899118831
return Jim_Eval(interp, "os.gethostname");
1899218832
1899318833
case INFO_NAMEOFEXECUTABLE:
18994
-
18834
+
1899518835
return Jim_Eval(interp, "{info nameofexecutable}");
1899618836
1899718837
case INFO_RETURNCODES:
1899818838
if (argc == 2) {
1899918839
int i;
@@ -19070,11 +18910,11 @@
1907018910
1907118911
if (option == OPT_VAR) {
1907218912
result = Jim_GetVariable(interp, objPtr, 0) != NULL;
1907318913
}
1907418914
else {
19075
-
18915
+
1907618916
Jim_Cmd *cmd = Jim_GetCommand(interp, objPtr, JIM_NONE);
1907718917
1907818918
if (cmd) {
1907918919
switch (option) {
1908018920
case OPT_COMMAND:
@@ -19113,11 +18953,11 @@
1911318953
if (len == 0) {
1911418954
return JIM_OK;
1911518955
}
1911618956
strLen = Jim_Utf8Length(interp, argv[1]);
1911718957
19118
-
18958
+
1911918959
if (argc == 2) {
1912018960
splitChars = " \n\t\r";
1912118961
splitLen = 4;
1912218962
}
1912318963
else {
@@ -19126,11 +18966,11 @@
1912618966
}
1912718967
1912818968
noMatchStart = str;
1912918969
resObjPtr = Jim_NewListObj(interp, NULL, 0);
1913018970
19131
-
18971
+
1913218972
if (splitLen) {
1913318973
Jim_Obj *objPtr;
1913418974
while (strLen--) {
1913518975
const char *sc = splitChars;
1913618976
int scLen = splitLen;
@@ -19155,11 +18995,11 @@
1915518995
#define NUM_COMMON (128 - 9)
1915618996
while (strLen--) {
1915718997
int n = utf8_tounicode(str, &c);
1915818998
#ifdef JIM_OPTIMIZATION
1915918999
if (c >= 9 && c < 128) {
19160
-
19000
+
1916119001
c -= 9;
1916219002
if (!commonObj) {
1916319003
commonObj = Jim_Alloc(sizeof(*commonObj) * NUM_COMMON);
1916419004
memset(commonObj, 0, sizeof(*commonObj) * NUM_COMMON);
1916519005
}
@@ -19189,11 +19029,11 @@
1918919029
1919019030
if (argc != 2 && argc != 3) {
1919119031
Jim_WrongNumArgs(interp, 1, argv, "list ?joinString?");
1919219032
return JIM_ERR;
1919319033
}
19194
-
19034
+
1919519035
if (argc == 2) {
1919619036
joinStr = " ";
1919719037
joinStrLen = 1;
1919819038
}
1919919039
else {
@@ -19468,13 +19308,13 @@
1946819308
return -1;
1946919309
else if (step < 0 && end > start)
1947019310
return -1;
1947119311
len = end - start;
1947219312
if (len < 0)
19473
- len = -len;
19313
+ len = -len;
1947419314
if (step < 0)
19475
- step = -step;
19315
+ step = -step;
1947619316
len = 1 + ((len - 1) / step);
1947719317
if (len > INT_MAX)
1947819318
len = INT_MAX;
1947919319
return (int)((len < 0) ? -1 : len);
1948019320
}
@@ -19644,57 +19484,102 @@
1964419484
argv[1] = interp->result;
1964519485
1964619486
Jim_EvalObjVector(interp, 2, argv);
1964719487
}
1964819488
19649
-static void JimSetFailedEnumResult(Jim_Interp *interp, const char *arg, const char *badtype,
19650
- const char *prefix, const char *const *tablePtr, const char *name)
19489
+static char **JimSortStringTable(const char *const *tablePtr)
1965119490
{
1965219491
int count;
1965319492
char **tablePtrSorted;
19654
- int i;
19493
+
1965519494
1965619495
for (count = 0; tablePtr[count]; count++) {
1965719496
}
1965819497
19498
+
19499
+ tablePtrSorted = Jim_Alloc(sizeof(char *) * (count + 1));
19500
+ memcpy(tablePtrSorted, tablePtr, sizeof(char *) * count);
19501
+ qsort(tablePtrSorted, count, sizeof(char *), qsortCompareStringPointers);
19502
+ tablePtrSorted[count] = NULL;
19503
+
19504
+ return tablePtrSorted;
19505
+}
19506
+
19507
+static void JimSetFailedEnumResult(Jim_Interp *interp, const char *arg, const char *badtype,
19508
+ const char *prefix, const char *const *tablePtr, const char *name)
19509
+{
19510
+ char **tablePtrSorted;
19511
+ int i;
19512
+
1965919513
if (name == NULL) {
1966019514
name = "option";
1966119515
}
1966219516
1966319517
Jim_SetResultFormatted(interp, "%s%s \"%s\": must be ", badtype, name, arg);
19664
- tablePtrSorted = Jim_Alloc(sizeof(char *) * count);
19665
- memcpy(tablePtrSorted, tablePtr, sizeof(char *) * count);
19666
- qsort(tablePtrSorted, count, sizeof(char *), qsortCompareStringPointers);
19667
- for (i = 0; i < count; i++) {
19668
- if (i + 1 == count && count > 1) {
19518
+ tablePtrSorted = JimSortStringTable(tablePtr);
19519
+ for (i = 0; tablePtrSorted[i]; i++) {
19520
+ if (tablePtrSorted[i + 1] == NULL && i > 0) {
1966919521
Jim_AppendString(interp, Jim_GetResult(interp), "or ", -1);
1967019522
}
1967119523
Jim_AppendStrings(interp, Jim_GetResult(interp), prefix, tablePtrSorted[i], NULL);
19672
- if (i + 1 != count) {
19524
+ if (tablePtrSorted[i + 1]) {
1967319525
Jim_AppendString(interp, Jim_GetResult(interp), ", ", -1);
1967419526
}
1967519527
}
1967619528
Jim_Free(tablePtrSorted);
1967719529
}
1967819530
19531
+
19532
+int Jim_CheckShowCommands(Jim_Interp *interp, Jim_Obj *objPtr, const char *const *tablePtr)
19533
+{
19534
+ if (Jim_CompareStringImmediate(interp, objPtr, "-commands")) {
19535
+ int i;
19536
+ char **tablePtrSorted = JimSortStringTable(tablePtr);
19537
+ Jim_SetResult(interp, Jim_NewListObj(interp, NULL, 0));
19538
+ for (i = 0; tablePtrSorted[i]; i++) {
19539
+ Jim_ListAppendElement(interp, Jim_GetResult(interp), Jim_NewStringObj(interp, tablePtrSorted[i], -1));
19540
+ }
19541
+ Jim_Free(tablePtrSorted);
19542
+ return JIM_OK;
19543
+ }
19544
+ return JIM_ERR;
19545
+}
19546
+
19547
+static const Jim_ObjType getEnumObjType = {
19548
+ "get-enum",
19549
+ NULL,
19550
+ NULL,
19551
+ NULL,
19552
+ JIM_TYPE_REFERENCES
19553
+};
19554
+
1967919555
int Jim_GetEnum(Jim_Interp *interp, Jim_Obj *objPtr,
1968019556
const char *const *tablePtr, int *indexPtr, const char *name, int flags)
1968119557
{
1968219558
const char *bad = "bad ";
1968319559
const char *const *entryPtr = NULL;
1968419560
int i;
1968519561
int match = -1;
1968619562
int arglen;
19687
- const char *arg = Jim_GetString(objPtr, &arglen);
19563
+ const char *arg;
19564
+
19565
+ if (objPtr->typePtr == &getEnumObjType) {
19566
+ if (objPtr->internalRep.ptrIntValue.ptr == tablePtr && objPtr->internalRep.ptrIntValue.int1 == flags) {
19567
+ *indexPtr = objPtr->internalRep.ptrIntValue.int2;
19568
+ return JIM_OK;
19569
+ }
19570
+ }
19571
+
19572
+ arg = Jim_GetString(objPtr, &arglen);
1968819573
1968919574
*indexPtr = -1;
1969019575
1969119576
for (entryPtr = tablePtr, i = 0; *entryPtr != NULL; entryPtr++, i++) {
1969219577
if (Jim_CompareStringImmediate(interp, objPtr, *entryPtr)) {
19693
-
19694
- *indexPtr = i;
19695
- return JIM_OK;
19578
+
19579
+ match = i;
19580
+ goto found;
1969619581
}
1969719582
if (flags & JIM_ENUM_ABBREV) {
1969819583
if (strncmp(arg, *entryPtr, arglen) == 0) {
1969919584
if (*arg == '-' && arglen == 1) {
1970019585
break;
@@ -19706,12 +19591,20 @@
1970619591
match = i;
1970719592
}
1970819593
}
1970919594
}
1971019595
19711
-
19596
+
1971219597
if (match >= 0) {
19598
+ found:
19599
+
19600
+ Jim_FreeIntRep(interp, objPtr);
19601
+ objPtr->typePtr = &getEnumObjType;
19602
+ objPtr->internalRep.ptrIntValue.ptr = (void *)tablePtr;
19603
+ objPtr->internalRep.ptrIntValue.int1 = flags;
19604
+ objPtr->internalRep.ptrIntValue.int2 = match;
19605
+
1971319606
*indexPtr = match;
1971419607
return JIM_OK;
1971519608
}
1971619609
1971719610
ambiguous:
@@ -19743,15 +19636,17 @@
1974319636
return objPtr->typePtr == &listObjType;
1974419637
}
1974519638
1974619639
void Jim_SetResultFormatted(Jim_Interp *interp, const char *format, ...)
1974719640
{
19748
-
19641
+
1974919642
int len = strlen(format);
1975019643
int extra = 0;
1975119644
int n = 0;
1975219645
const char *params[5];
19646
+ int nobjparam = 0;
19647
+ Jim_Obj *objparam[5];
1975319648
char *buf;
1975419649
va_list args;
1975519650
int i;
1975619651
1975719652
va_start(args, format);
@@ -19766,10 +19661,12 @@
1976619661
}
1976719662
else if (strncmp(format + i, "%#s", 3) == 0) {
1976819663
Jim_Obj *objPtr = va_arg(args, Jim_Obj *);
1976919664
1977019665
params[n] = Jim_GetString(objPtr, &l);
19666
+ objparam[nobjparam++] = objPtr;
19667
+ Jim_IncrRefCount(objPtr);
1977119668
}
1977219669
else {
1977319670
if (format[i] == '%') {
1977419671
i++;
1977519672
}
@@ -19784,10 +19681,14 @@
1978419681
len = snprintf(buf, len + 1, format, params[0], params[1], params[2], params[3], params[4]);
1978519682
1978619683
va_end(args);
1978719684
1978819685
Jim_SetResult(interp, Jim_NewStringObjNoAlloc(interp, buf, len));
19686
+
19687
+ for (i = 0; i < nobjparam; i++) {
19688
+ Jim_DecrRefCount(interp, objparam[i]);
19689
+ }
1978919690
}
1979019691
1979119692
1979219693
#ifndef jim_ext_package
1979319694
int Jim_PackageProvide(Jim_Interp *interp, const char *name, const char *ver, int flags)
@@ -19808,11 +19709,11 @@
1980819709
#include <string.h>
1980919710
1981019711
1981119712
static int subcmd_null(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
1981219713
{
19813
-
19714
+
1981419715
return JIM_OK;
1981519716
}
1981619717
1981719718
static const jim_subcmd_type dummy_subcmd = {
1981819719
"dummy", NULL, subcmd_null, 0, 0, JIM_MODFLAG_HIDDEN
@@ -19831,22 +19732,18 @@
1983119732
}
1983219733
1983319734
static void bad_subcmd(Jim_Interp *interp, const jim_subcmd_type * command_table, const char *type,
1983419735
Jim_Obj *cmd, Jim_Obj *subcmd)
1983519736
{
19836
- Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
19837
- Jim_AppendStrings(interp, Jim_GetResult(interp), Jim_String(cmd), ", ", type,
19838
- " command \"", Jim_String(subcmd), "\": should be ", NULL);
19737
+ Jim_SetResultFormatted(interp, "%#s, %s command \"%#s\": should be ", cmd, type, subcmd);
1983919738
add_commands(interp, command_table, ", ");
1984019739
}
1984119740
1984219741
static void show_cmd_usage(Jim_Interp *interp, const jim_subcmd_type * command_table, int argc,
1984319742
Jim_Obj *const *argv)
1984419743
{
19845
- Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
19846
- Jim_AppendStrings(interp, Jim_GetResult(interp), "Usage: \"", Jim_String(argv[0]),
19847
- " command ... \", where command is one of: ", NULL);
19744
+ Jim_SetResultFormatted(interp, "Usage: \"%#s command ... \", where command is one of: ", argv[0]);
1984819745
add_commands(interp, command_table, ", ");
1984919746
}
1985019747
1985119748
static void add_cmd_usage(Jim_Interp *interp, const jim_subcmd_type * ct, Jim_Obj *cmd)
1985219749
{
@@ -19863,67 +19760,78 @@
1986319760
{
1986419761
Jim_SetResultString(interp, "wrong # args: should be \"", -1);
1986519762
add_cmd_usage(interp, command_table, subcmd);
1986619763
Jim_AppendStrings(interp, Jim_GetResult(interp), "\"", NULL);
1986719764
}
19765
+
19766
+static const Jim_ObjType subcmdLookupObjType = {
19767
+ "subcmd-lookup",
19768
+ NULL,
19769
+ NULL,
19770
+ NULL,
19771
+ JIM_TYPE_REFERENCES
19772
+};
1986819773
1986919774
const jim_subcmd_type *Jim_ParseSubCmd(Jim_Interp *interp, const jim_subcmd_type * command_table,
1987019775
int argc, Jim_Obj *const *argv)
1987119776
{
1987219777
const jim_subcmd_type *ct;
1987319778
const jim_subcmd_type *partial = 0;
1987419779
int cmdlen;
1987519780
Jim_Obj *cmd;
1987619781
const char *cmdstr;
19877
- const char *cmdname;
1987819782
int help = 0;
1987919783
19880
- cmdname = Jim_String(argv[0]);
19881
-
1988219784
if (argc < 2) {
19883
- Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
19884
- Jim_AppendStrings(interp, Jim_GetResult(interp), "wrong # args: should be \"", cmdname,
19885
- " command ...\"\n", NULL);
19886
- Jim_AppendStrings(interp, Jim_GetResult(interp), "Use \"", cmdname, " -help ?command?\" for help", NULL);
19785
+ Jim_SetResultFormatted(interp, "wrong # args: should be \"%#s command ...\"\n"
19786
+ "Use \"%#s -help ?command?\" for help", argv[0], argv[0]);
1988719787
return 0;
1988819788
}
1988919789
1989019790
cmd = argv[1];
1989119791
19892
-
19792
+
19793
+ if (cmd->typePtr == &subcmdLookupObjType) {
19794
+ if (cmd->internalRep.ptrIntValue.ptr == command_table) {
19795
+ ct = command_table + cmd->internalRep.ptrIntValue.int1;
19796
+ goto found;
19797
+ }
19798
+ }
19799
+
19800
+
1989319801
if (Jim_CompareStringImmediate(interp, cmd, "-help")) {
1989419802
if (argc == 2) {
19895
-
19803
+
1989619804
show_cmd_usage(interp, command_table, argc, argv);
1989719805
return &dummy_subcmd;
1989819806
}
1989919807
help = 1;
1990019808
19901
-
19809
+
1990219810
cmd = argv[2];
1990319811
}
1990419812
19905
-
19813
+
1990619814
if (Jim_CompareStringImmediate(interp, cmd, "-commands")) {
19907
-
19815
+
1990819816
Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
1990919817
add_commands(interp, command_table, " ");
1991019818
return &dummy_subcmd;
1991119819
}
1991219820
1991319821
cmdstr = Jim_GetString(cmd, &cmdlen);
1991419822
1991519823
for (ct = command_table; ct->cmd; ct++) {
1991619824
if (Jim_CompareStringImmediate(interp, cmd, ct->cmd)) {
19917
-
19825
+
1991819826
break;
1991919827
}
1992019828
if (strncmp(cmdstr, ct->cmd, cmdlen) == 0) {
1992119829
if (partial) {
19922
-
19830
+
1992319831
if (help) {
19924
-
19832
+
1992519833
show_cmd_usage(interp, command_table, argc, argv);
1992619834
return &dummy_subcmd;
1992719835
}
1992819836
bad_subcmd(interp, command_table, "ambiguous", argv[0], argv[1 + help]);
1992919837
return 0;
@@ -19931,44 +19839,51 @@
1993119839
partial = ct;
1993219840
}
1993319841
continue;
1993419842
}
1993519843
19936
-
19844
+
1993719845
if (partial && !ct->cmd) {
1993819846
ct = partial;
1993919847
}
1994019848
1994119849
if (!ct->cmd) {
19942
-
19850
+
1994319851
if (help) {
19944
-
19852
+
1994519853
show_cmd_usage(interp, command_table, argc, argv);
1994619854
return &dummy_subcmd;
1994719855
}
1994819856
bad_subcmd(interp, command_table, "unknown", argv[0], argv[1 + help]);
1994919857
return 0;
1995019858
}
1995119859
1995219860
if (help) {
1995319861
Jim_SetResultString(interp, "Usage: ", -1);
19954
-
19862
+
1995519863
add_cmd_usage(interp, ct, argv[0]);
1995619864
return &dummy_subcmd;
1995719865
}
1995819866
19959
-
19867
+
19868
+ Jim_FreeIntRep(interp, cmd);
19869
+ cmd->typePtr = &subcmdLookupObjType;
19870
+ cmd->internalRep.ptrIntValue.ptr = (void *)command_table;
19871
+ cmd->internalRep.ptrIntValue.int1 = ct - command_table;
19872
+
19873
+found:
19874
+
1996019875
if (argc - 2 < ct->minargs || (ct->maxargs >= 0 && argc - 2 > ct->maxargs)) {
1996119876
Jim_SetResultString(interp, "wrong # args: should be \"", -1);
19962
-
19877
+
1996319878
add_cmd_usage(interp, ct, argv[0]);
1996419879
Jim_AppendStrings(interp, Jim_GetResult(interp), "\"", NULL);
1996519880
1996619881
return 0;
1996719882
}
1996819883
19969
-
19884
+
1997019885
return ct;
1997119886
}
1997219887
1997319888
int Jim_CallSubCmd(Jim_Interp *interp, const jim_subcmd_type * ct, int argc, Jim_Obj *const *argv)
1997419889
{
@@ -20019,11 +19934,11 @@
2001919934
*p++ = 0xe0 | ((uc & 0xf000) >> 12);
2002019935
*p++ = 0x80 | ((uc & 0xfc0) >> 6);
2002119936
*p = 0x80 | (uc & 0x3f);
2002219937
return 3;
2002319938
}
20024
-
19939
+
2002519940
else {
2002619941
*p++ = 0xf0 | ((uc & 0x1c0000) >> 18);
2002719942
*p++ = 0x80 | ((uc & 0x3f000) >> 12);
2002819943
*p++ = 0x80 | ((uc & 0xfc0) >> 6);
2002919944
*p = 0x80 | (uc & 0x3f);
@@ -20146,11 +20061,12 @@
2014620061
continue;
2014720062
}
2014820063
*p++ = ch;
2014920064
format += step;
2015020065
step = utf8_tounicode(format, &ch);
20151
- } while (sawFlag);
20066
+
20067
+ } while (sawFlag && (p - spec <= 5));
2015220068
2015320069
2015420070
width = 0;
2015520071
if (isdigit(ch)) {
2015620072
width = strtoul(format, &end, 10);
@@ -20210,11 +20126,11 @@
2021020126
if (ch == 'h') {
2021120127
useShort = 1;
2021220128
format += step;
2021320129
step = utf8_tounicode(format, &ch);
2021420130
} else if (ch == 'l') {
20215
-
20131
+
2021620132
format += step;
2021720133
step = utf8_tounicode(format, &ch);
2021820134
if (ch == 'l') {
2021920135
format += step;
2022020136
step = utf8_tounicode(format, &ch);
@@ -20237,11 +20153,11 @@
2023720153
goto errorMsg;
2023820154
case 's': {
2023920155
formatted_buf = Jim_GetString(objv[objIndex], &formatted_bytes);
2024020156
formatted_chars = Jim_Utf8Length(interp, objv[objIndex]);
2024120157
if (gotPrecision && (precision < formatted_chars)) {
20242
-
20158
+
2024320159
formatted_chars = precision;
2024420160
formatted_bytes = utf8_index(formatted_buf, precision);
2024520161
}
2024620162
break;
2024720163
}
@@ -20249,11 +20165,11 @@
2024920165
jim_wide code;
2025020166
2025120167
if (Jim_GetWide(interp, objv[objIndex], &code) != JIM_OK) {
2025220168
goto error;
2025320169
}
20254
-
20170
+
2025520171
formatted_bytes = utf8_getchars(spec, code);
2025620172
formatted_buf = spec;
2025720173
formatted_chars = 1;
2025820174
break;
2025920175
}
@@ -20267,11 +20183,11 @@
2026720183
goto error;
2026820184
}
2026920185
length = sizeof(w) * 8;
2027020186
2027120187
20272
-
20188
+
2027320189
if (num_buffer_size < length + 1) {
2027420190
num_buffer_size = length + 1;
2027520191
num_buffer = Jim_Realloc(num_buffer, num_buffer_size);
2027620192
}
2027720193
@@ -20295,29 +20211,29 @@
2029520211
case 'E':
2029620212
case 'f':
2029720213
case 'g':
2029820214
case 'G':
2029920215
doubleType = 1;
20300
-
20216
+
2030120217
case 'd':
2030220218
case 'u':
2030320219
case 'o':
2030420220
case 'x':
2030520221
case 'X': {
2030620222
jim_wide w;
2030720223
double d;
2030820224
int length;
2030920225
20310
-
20226
+
2031120227
if (width) {
2031220228
p += sprintf(p, "%ld", width);
2031320229
}
2031420230
if (gotPrecision) {
2031520231
p += sprintf(p, ".%ld", precision);
2031620232
}
2031720233
20318
-
20234
+
2031920235
if (doubleType) {
2032020236
if (Jim_GetDouble(interp, objv[objIndex], &d) != JIM_OK) {
2032120237
goto error;
2032220238
}
2032320239
length = MAX_FLOAT_WIDTH;
@@ -20344,19 +20260,26 @@
2034420260
}
2034520261
2034620262
*p++ = (char) ch;
2034720263
*p = '\0';
2034820264
20349
-
20265
+
20266
+ if (width > 10000 || length > 10000 || precision > 10000) {
20267
+ Jim_SetResultString(interp, "format too long", -1);
20268
+ goto error;
20269
+ }
20270
+
20271
+
20272
+
2035020273
if (width > length) {
2035120274
length = width;
2035220275
}
2035320276
if (gotPrecision) {
2035420277
length += precision;
2035520278
}
2035620279
20357
-
20280
+
2035820281
if (num_buffer_size < length + 1) {
2035920282
num_buffer_size = length + 1;
2036020283
num_buffer = Jim_Realloc(num_buffer, num_buffer_size);
2036120284
}
2036220285
@@ -20370,11 +20293,11 @@
2037020293
formatted_buf = num_buffer;
2037120294
break;
2037220295
}
2037320296
2037420297
default: {
20375
-
20298
+
2037620299
spec[0] = ch;
2037720300
spec[1] = '\0';
2037820301
Jim_SetResultFormatted(interp, "bad field specifier \"%s\"", spec);
2037920302
goto error;
2038020303
}
@@ -20422,37 +20345,37 @@
2042220345
2042320346
#define REG_MAX_PAREN 100
2042420347
2042520348
2042620349
20427
-#define END 0
20428
-#define BOL 1
20429
-#define EOL 2
20430
-#define ANY 3
20431
-#define ANYOF 4
20432
-#define ANYBUT 5
20433
-#define BRANCH 6
20434
-#define BACK 7
20435
-#define EXACTLY 8
20436
-#define NOTHING 9
20437
-#define REP 10
20438
-#define REPMIN 11
20439
-#define REPX 12
20440
-#define REPXMIN 13
20441
-#define BOLX 14
20442
-#define EOLX 15
20443
-#define WORDA 16
20444
-#define WORDZ 17
20445
-
20446
-#define OPENNC 1000
20447
-#define OPEN 1001
20448
-
20449
-
20450
-
20451
-
20452
-#define CLOSENC 2000
20453
-#define CLOSE 2001
20350
+#define END 0
20351
+#define BOL 1
20352
+#define EOL 2
20353
+#define ANY 3
20354
+#define ANYOF 4
20355
+#define ANYBUT 5
20356
+#define BRANCH 6
20357
+#define BACK 7
20358
+#define EXACTLY 8
20359
+#define NOTHING 9
20360
+#define REP 10
20361
+#define REPMIN 11
20362
+#define REPX 12
20363
+#define REPXMIN 13
20364
+#define BOLX 14
20365
+#define EOLX 15
20366
+#define WORDA 16
20367
+#define WORDZ 17
20368
+
20369
+#define OPENNC 1000
20370
+#define OPEN 1001
20371
+
20372
+
20373
+
20374
+
20375
+#define CLOSENC 2000
20376
+#define CLOSE 2001
2045420377
#define CLOSE_END (CLOSE+REG_MAX_PAREN)
2045520378
2045620379
#define REG_MAGIC 0xFADED00D
2045720380
2045820381
@@ -20465,18 +20388,18 @@
2046520388
2046620389
#define FAIL(R,M) { (R)->err = (M); return (M); }
2046720390
#define ISMULT(c) ((c) == '*' || (c) == '+' || (c) == '?' || (c) == '{')
2046820391
#define META "^$.[()|?{+*"
2046920392
20470
-#define HASWIDTH 1
20471
-#define SIMPLE 2
20472
-#define SPSTART 4
20473
-#define WORST 0
20393
+#define HASWIDTH 1
20394
+#define SIMPLE 2
20395
+#define SPSTART 4
20396
+#define WORST 0
2047420397
2047520398
#define MAX_REP_COUNT 1000000
2047620399
20477
-static int reg(regex_t *preg, int paren , int *flagp );
20400
+static int reg(regex_t *preg, int paren, int *flagp );
2047820401
static int regpiece(regex_t *preg, int *flagp );
2047920402
static int regbranch(regex_t *preg, int *flagp );
2048020403
static int regatom(regex_t *preg, int *flagp );
2048120404
static int regnode(regex_t *preg, int op );
2048220405
static int regnext(regex_t *preg, int p );
@@ -20520,15 +20443,15 @@
2052020443
memset(preg, 0, sizeof(*preg));
2052120444
2052220445
if (exp == NULL)
2052320446
FAIL(preg, REG_ERR_NULL_ARGUMENT);
2052420447
20525
-
20448
+
2052620449
preg->cflags = cflags;
2052720450
preg->regparse = exp;
2052820451
20529
-
20452
+
2053020453
preg->proglen = (strlen(exp) + 1) * 5;
2053120454
preg->program = malloc(preg->proglen * sizeof(int));
2053220455
if (preg->program == NULL)
2053320456
FAIL(preg, REG_ERR_NOMEM);
2053420457
@@ -20535,24 +20458,24 @@
2053520458
regc(preg, REG_MAGIC);
2053620459
if (reg(preg, 0, &flags) == 0) {
2053720460
return preg->err;
2053820461
}
2053920462
20540
-
20541
- if (preg->re_nsub >= REG_MAX_PAREN)
20463
+
20464
+ if (preg->re_nsub >= REG_MAX_PAREN)
2054220465
FAIL(preg,REG_ERR_TOO_BIG);
2054320466
20544
-
20545
- preg->regstart = 0;
20467
+
20468
+ preg->regstart = 0;
2054620469
preg->reganch = 0;
2054720470
preg->regmust = 0;
2054820471
preg->regmlen = 0;
20549
- scan = 1;
20550
- if (OP(preg, regnext(preg, scan)) == END) {
20472
+ scan = 1;
20473
+ if (OP(preg, regnext(preg, scan)) == END) {
2055120474
scan = OPERAND(scan);
2055220475
20553
-
20476
+
2055420477
if (OP(preg, scan) == EXACTLY) {
2055520478
preg->regstart = preg->program[OPERAND(scan)];
2055620479
}
2055720480
else if (OP(preg, scan) == BOL)
2055820481
preg->reganch++;
@@ -20579,24 +20502,24 @@
2057920502
#endif
2058020503
2058120504
return 0;
2058220505
}
2058320506
20584
-static int reg(regex_t *preg, int paren , int *flagp )
20507
+static int reg(regex_t *preg, int paren, int *flagp )
2058520508
{
2058620509
int ret;
2058720510
int br;
2058820511
int ender;
2058920512
int parno = 0;
2059020513
int flags;
2059120514
20592
- *flagp = HASWIDTH;
20515
+ *flagp = HASWIDTH;
2059320516
20594
-
20517
+
2059520518
if (paren) {
2059620519
if (preg->regparse[0] == '?' && preg->regparse[1] == ':') {
20597
-
20520
+
2059820521
preg->regparse += 2;
2059920522
parno = -1;
2060020523
}
2060120524
else {
2060220525
parno = ++preg->re_nsub;
@@ -20603,16 +20526,16 @@
2060320526
}
2060420527
ret = regnode(preg, OPEN+parno);
2060520528
} else
2060620529
ret = 0;
2060720530
20608
-
20531
+
2060920532
br = regbranch(preg, &flags);
2061020533
if (br == 0)
2061120534
return 0;
2061220535
if (ret != 0)
20613
- regtail(preg, ret, br);
20536
+ regtail(preg, ret, br);
2061420537
else
2061520538
ret = br;
2061620539
if (!(flags&HASWIDTH))
2061720540
*flagp &= ~HASWIDTH;
2061820541
*flagp |= flags&SPSTART;
@@ -20619,25 +20542,25 @@
2061920542
while (*preg->regparse == '|') {
2062020543
preg->regparse++;
2062120544
br = regbranch(preg, &flags);
2062220545
if (br == 0)
2062320546
return 0;
20624
- regtail(preg, ret, br);
20547
+ regtail(preg, ret, br);
2062520548
if (!(flags&HASWIDTH))
2062620549
*flagp &= ~HASWIDTH;
2062720550
*flagp |= flags&SPSTART;
2062820551
}
2062920552
20630
-
20553
+
2063120554
ender = regnode(preg, (paren) ? CLOSE+parno : END);
2063220555
regtail(preg, ret, ender);
2063320556
20634
-
20557
+
2063520558
for (br = ret; br != 0; br = regnext(preg, br))
2063620559
regoptail(preg, br, ender);
2063720560
20638
-
20561
+
2063920562
if (paren && *preg->regparse++ != ')') {
2064020563
preg->err = REG_ERR_UNMATCHED_PAREN;
2064120564
return 0;
2064220565
} else if (!paren && *preg->regparse != '\0') {
2064320566
if (*preg->regparse == ')') {
@@ -20657,11 +20580,11 @@
2065720580
int ret;
2065820581
int chain;
2065920582
int latest;
2066020583
int flags;
2066120584
20662
- *flagp = WORST;
20585
+ *flagp = WORST;
2066320586
2066420587
ret = regnode(preg, BRANCH);
2066520588
chain = 0;
2066620589
while (*preg->regparse != '\0' && *preg->regparse != ')' &&
2066720590
*preg->regparse != '|') {
@@ -20675,11 +20598,11 @@
2067520598
else {
2067620599
regtail(preg, chain, latest);
2067720600
}
2067820601
chain = latest;
2067920602
}
20680
- if (chain == 0)
20603
+ if (chain == 0)
2068120604
(void) regnode(preg, NOTHING);
2068220605
2068320606
return(ret);
2068420607
}
2068520608
@@ -20705,11 +20628,11 @@
2070520628
if (!(flags&HASWIDTH) && op != '?') {
2070620629
preg->err = REG_ERR_OPERAND_COULD_BE_EMPTY;
2070720630
return 0;
2070820631
}
2070920632
20710
-
20633
+
2071120634
if (op == '{') {
2071220635
char *end;
2071320636
2071420637
min = strtoul(preg->regparse + 1, &end, 10);
2071520638
if (end == preg->regparse + 1) {
@@ -20716,10 +20639,14 @@
2071620639
preg->err = REG_ERR_BAD_COUNT;
2071720640
return 0;
2071820641
}
2071920642
if (*end == '}') {
2072020643
max = min;
20644
+ }
20645
+ else if (*end == '\0') {
20646
+ preg->err = REG_ERR_UNMATCHED_BRACES;
20647
+ return 0;
2072120648
}
2072220649
else {
2072320650
preg->regparse = end;
2072420651
max = strtoul(preg->regparse + 1, &end, 10);
2072520652
if (*end != '}') {
@@ -20777,11 +20704,11 @@
2077720704
static void reg_addrange(regex_t *preg, int lower, int upper)
2077820705
{
2077920706
if (lower > upper) {
2078020707
reg_addrange(preg, upper, lower);
2078120708
}
20782
-
20709
+
2078320710
regc(preg, upper - lower + 1);
2078420711
regc(preg, lower);
2078520712
}
2078620713
2078720714
static void reg_addrange_str(regex_t *preg, const char *str)
@@ -20845,17 +20772,17 @@
2084520772
case 'r': *ch = '\r'; break;
2084620773
case 't': *ch = '\t'; break;
2084720774
case 'v': *ch = '\v'; break;
2084820775
case 'u':
2084920776
if (*s == '{') {
20850
-
20777
+
2085120778
n = parse_hex(s + 1, 6, ch);
2085220779
if (n > 0 && s[n + 1] == '}' && *ch >= 0 && *ch <= 0x1fffff) {
2085320780
s += n + 2;
2085420781
}
2085520782
else {
20856
-
20783
+
2085720784
*ch = 'u';
2085820785
}
2085920786
}
2086020787
else if ((n = parse_hex(s, 4, ch)) > 0) {
2086120788
s += n;
@@ -20886,15 +20813,15 @@
2088620813
int nocase = (preg->cflags & REG_ICASE);
2088720814
2088820815
int ch;
2088920816
int n = reg_utf8_tounicode_case(preg->regparse, &ch, nocase);
2089020817
20891
- *flagp = WORST;
20818
+ *flagp = WORST;
2089220819
2089320820
preg->regparse += n;
2089420821
switch (ch) {
20895
-
20822
+
2089620823
case '^':
2089720824
ret = regnode(preg, BOL);
2089820825
break;
2089920826
case '$':
2090020827
ret = regnode(preg, EOL);
@@ -20904,37 +20831,60 @@
2090420831
*flagp |= HASWIDTH|SIMPLE;
2090520832
break;
2090620833
case '[': {
2090720834
const char *pattern = preg->regparse;
2090820835
20909
- if (*pattern == '^') {
20836
+ if (*pattern == '^') {
2091020837
ret = regnode(preg, ANYBUT);
2091120838
pattern++;
2091220839
} else
2091320840
ret = regnode(preg, ANYOF);
2091420841
20915
-
20842
+
2091620843
if (*pattern == ']' || *pattern == '-') {
2091720844
reg_addrange(preg, *pattern, *pattern);
2091820845
pattern++;
2091920846
}
2092020847
2092120848
while (*pattern && *pattern != ']') {
20922
-
20849
+
2092320850
int start;
2092420851
int end;
2092520852
20853
+ enum {
20854
+ CC_ALPHA, CC_ALNUM, CC_SPACE, CC_BLANK, CC_UPPER, CC_LOWER,
20855
+ CC_DIGIT, CC_XDIGIT, CC_CNTRL, CC_GRAPH, CC_PRINT, CC_PUNCT,
20856
+ CC_NUM
20857
+ };
20858
+ int cc;
20859
+
2092620860
pattern += reg_utf8_tounicode_case(pattern, &start, nocase);
2092720861
if (start == '\\') {
20862
+
20863
+ switch (*pattern) {
20864
+ case 's':
20865
+ pattern++;
20866
+ cc = CC_SPACE;
20867
+ goto cc_switch;
20868
+ case 'd':
20869
+ pattern++;
20870
+ cc = CC_DIGIT;
20871
+ goto cc_switch;
20872
+ case 'w':
20873
+ pattern++;
20874
+ reg_addrange(preg, '_', '_');
20875
+ cc = CC_ALNUM;
20876
+ goto cc_switch;
20877
+ }
2092820878
pattern += reg_decode_escape(pattern, &start);
2092920879
if (start == 0) {
2093020880
preg->err = REG_ERR_NULL_CHAR;
2093120881
return 0;
2093220882
}
2093320883
}
2093420884
if (pattern[0] == '-' && pattern[1] && pattern[1] != ']') {
20935
-
20885
+
2093620886
pattern += utf8_tounicode(pattern, &end);
2093720887
pattern += reg_utf8_tounicode_case(pattern, &end, nocase);
2093820888
if (end == '\\') {
2093920889
pattern += reg_decode_escape(pattern, &end);
2094020890
if (end == 0) {
@@ -20949,30 +20899,25 @@
2094920899
if (start == '[' && pattern[0] == ':') {
2095020900
static const char *character_class[] = {
2095120901
":alpha:", ":alnum:", ":space:", ":blank:", ":upper:", ":lower:",
2095220902
":digit:", ":xdigit:", ":cntrl:", ":graph:", ":print:", ":punct:",
2095320903
};
20954
- enum {
20955
- CC_ALPHA, CC_ALNUM, CC_SPACE, CC_BLANK, CC_UPPER, CC_LOWER,
20956
- CC_DIGIT, CC_XDIGIT, CC_CNTRL, CC_GRAPH, CC_PRINT, CC_PUNCT,
20957
- CC_NUM
20958
- };
20959
- int i;
20960
-
20961
- for (i = 0; i < CC_NUM; i++) {
20962
- int n = strlen(character_class[i]);
20963
- if (strncmp(pattern, character_class[i], n) == 0) {
20964
-
20904
+
20905
+ for (cc = 0; cc < CC_NUM; cc++) {
20906
+ n = strlen(character_class[cc]);
20907
+ if (strncmp(pattern, character_class[cc], n) == 0) {
20908
+
2096520909
pattern += n + 1;
2096620910
break;
2096720911
}
2096820912
}
20969
- if (i != CC_NUM) {
20970
- switch (i) {
20913
+ if (cc != CC_NUM) {
20914
+cc_switch:
20915
+ switch (cc) {
2097120916
case CC_ALNUM:
2097220917
reg_addrange(preg, '0', '9');
20973
-
20918
+
2097420919
case CC_ALPHA:
2097520920
if ((preg->cflags & REG_ICASE) == 0) {
2097620921
reg_addrange(preg, 'a', 'z');
2097720922
}
2097820923
reg_addrange(preg, 'A', 'Z');
@@ -20990,11 +20935,11 @@
2099020935
reg_addrange(preg, 'a', 'z');
2099120936
break;
2099220937
case CC_XDIGIT:
2099320938
reg_addrange(preg, 'a', 'f');
2099420939
reg_addrange(preg, 'A', 'F');
20995
-
20940
+
2099620941
case CC_DIGIT:
2099720942
reg_addrange(preg, '0', '9');
2099820943
break;
2099920944
case CC_CNTRL:
2100020945
reg_addrange(preg, 0, 31);
@@ -21014,11 +20959,11 @@
2101420959
break;
2101520960
}
2101620961
continue;
2101720962
}
2101820963
}
21019
-
20964
+
2102020965
reg_addrange(preg, start, start);
2102120966
}
2102220967
regc(preg, '\0');
2102320968
2102420969
if (*pattern) {
@@ -21037,11 +20982,11 @@
2103720982
break;
2103820983
case '\0':
2103920984
case '|':
2104020985
case ')':
2104120986
preg->err = REG_ERR_INTERNAL;
21042
- return 0;
20987
+ return 0;
2104320988
case '?':
2104420989
case '+':
2104520990
case '*':
2104620991
case '{':
2104720992
preg->err = REG_ERR_COUNT_FOLLOWS_NOTHING;
@@ -21090,34 +21035,34 @@
2109021035
ret = regnode(preg, ch == 's' ? ANYOF : ANYBUT);
2109121036
reg_addrange_str(preg," \t\r\n\f\v");
2109221037
regc(preg, '\0');
2109321038
*flagp |= HASWIDTH|SIMPLE;
2109421039
break;
21095
-
21040
+
2109621041
default:
21097
-
21098
-
21042
+
21043
+
2109921044
preg->regparse--;
2110021045
goto de_fault;
2110121046
}
2110221047
break;
2110321048
de_fault:
2110421049
default: {
2110521050
int added = 0;
2110621051
21107
-
21052
+
2110821053
preg->regparse -= n;
2110921054
2111021055
ret = regnode(preg, EXACTLY);
2111121056
2111221057
21113
-
21058
+
2111421059
while (*preg->regparse && strchr(META, *preg->regparse) == NULL) {
2111521060
n = reg_utf8_tounicode_case(preg->regparse, &ch, (preg->cflags & REG_ICASE));
2111621061
if (ch == '\\' && preg->regparse[n]) {
2111721062
if (strchr("<>mMwWdDsSAZ", preg->regparse[n])) {
21118
-
21063
+
2111921064
break;
2112021065
}
2112121066
n += reg_decode_escape(preg->regparse + n, &ch);
2112221067
if (ch == 0) {
2112321068
preg->err = REG_ERR_NULL_CHAR;
@@ -21125,23 +21070,23 @@
2112521070
}
2112621071
}
2112721072
2112821073
2112921074
if (ISMULT(preg->regparse[n])) {
21130
-
21075
+
2113121076
if (added) {
21132
-
21077
+
2113321078
break;
2113421079
}
21135
-
21080
+
2113621081
regc(preg, ch);
2113721082
added++;
2113821083
preg->regparse += n;
2113921084
break;
2114021085
}
2114121086
21142
-
21087
+
2114321088
regc(preg, ch);
2114421089
added++;
2114521090
preg->regparse += n;
2114621091
}
2114721092
regc(preg, '\0');
@@ -21168,15 +21113,15 @@
2116821113
2116921114
static int regnode(regex_t *preg, int op)
2117021115
{
2117121116
reg_grow(preg, 2);
2117221117
21173
-
21118
+
2117421119
preg->program[preg->p++] = op;
2117521120
preg->program[preg->p++] = 0;
2117621121
21177
-
21122
+
2117821123
return preg->p - 2;
2117921124
}
2118021125
2118121126
static void regc(regex_t *preg, int b )
2118221127
{
@@ -21186,13 +21131,13 @@
2118621131
2118721132
static int reginsert(regex_t *preg, int op, int size, int opnd )
2118821133
{
2118921134
reg_grow(preg, size);
2119021135
21191
-
21136
+
2119221137
memmove(preg->program + opnd + size, preg->program + opnd, sizeof(int) * (preg->p - opnd));
21193
-
21138
+
2119421139
memset(preg->program + opnd, 0, sizeof(int) * size);
2119521140
2119621141
preg->program[opnd] = op;
2119721142
2119821143
preg->p += size;
@@ -21204,11 +21149,11 @@
2120421149
{
2120521150
int scan;
2120621151
int temp;
2120721152
int offset;
2120821153
21209
-
21154
+
2121021155
scan = p;
2121121156
for (;;) {
2121221157
temp = regnext(preg, scan);
2121321158
if (temp == 0)
2121421159
break;
@@ -21224,11 +21169,11 @@
2122421169
}
2122521170
2122621171
2122721172
static void regoptail(regex_t *preg, int p, int val )
2122821173
{
21229
-
21174
+
2123021175
if (p != 0 && OP(preg, p) == BRANCH) {
2123121176
regtail(preg, OPERAND(p), val);
2123221177
}
2123321178
}
2123421179
@@ -21240,16 +21185,16 @@
2124021185
int regexec(regex_t *preg, const char *string, size_t nmatch, regmatch_t pmatch[], int eflags)
2124121186
{
2124221187
const char *s;
2124321188
int scan;
2124421189
21245
-
21190
+
2124621191
if (preg == NULL || preg->program == NULL || string == NULL) {
2124721192
return REG_ERR_NULL_ARGUMENT;
2124821193
}
2124921194
21250
-
21195
+
2125121196
if (*preg->program != REG_MAGIC) {
2125221197
return REG_ERR_CORRUPTED;
2125321198
}
2125421199
2125521200
#ifdef DEBUG
@@ -21258,51 +21203,51 @@
2125821203
#endif
2125921204
2126021205
preg->eflags = eflags;
2126121206
preg->pmatch = pmatch;
2126221207
preg->nmatch = nmatch;
21263
- preg->start = string;
21208
+ preg->start = string;
2126421209
21265
-
21210
+
2126621211
for (scan = OPERAND(1); scan != 0; scan += regopsize(preg, scan)) {
2126721212
int op = OP(preg, scan);
2126821213
if (op == END)
2126921214
break;
2127021215
if (op == REPX || op == REPXMIN)
2127121216
preg->program[scan + 4] = 0;
2127221217
}
2127321218
21274
-
21219
+
2127521220
if (preg->regmust != 0) {
2127621221
s = string;
2127721222
while ((s = str_find(s, preg->program[preg->regmust], preg->cflags & REG_ICASE)) != NULL) {
2127821223
if (prefix_cmp(preg->program + preg->regmust, preg->regmlen, s, preg->cflags & REG_ICASE) >= 0) {
2127921224
break;
2128021225
}
2128121226
s++;
2128221227
}
21283
- if (s == NULL)
21228
+ if (s == NULL)
2128421229
return REG_NOMATCH;
2128521230
}
2128621231
21287
-
21232
+
2128821233
preg->regbol = string;
2128921234
21290
-
21235
+
2129121236
if (preg->reganch) {
2129221237
if (eflags & REG_NOTBOL) {
21293
-
21238
+
2129421239
goto nextline;
2129521240
}
2129621241
while (1) {
2129721242
if (regtry(preg, string)) {
2129821243
return REG_NOERROR;
2129921244
}
2130021245
if (*string) {
2130121246
nextline:
2130221247
if (preg->cflags & REG_NEWLINE) {
21303
-
21248
+
2130421249
string = strchr(string, '\n');
2130521250
if (string) {
2130621251
preg->regbol = ++string;
2130721252
continue;
2130821253
}
@@ -21310,22 +21255,22 @@
2131021255
}
2131121256
return REG_NOMATCH;
2131221257
}
2131321258
}
2131421259
21315
-
21260
+
2131621261
s = string;
2131721262
if (preg->regstart != '\0') {
21318
-
21263
+
2131921264
while ((s = str_find(s, preg->regstart, preg->cflags & REG_ICASE)) != NULL) {
2132021265
if (regtry(preg, s))
2132121266
return REG_NOERROR;
2132221267
s++;
2132321268
}
2132421269
}
2132521270
else
21326
-
21271
+
2132721272
while (1) {
2132821273
if (regtry(preg, s))
2132921274
return REG_NOERROR;
2133021275
if (*s == '\0') {
2133121276
break;
@@ -21334,15 +21279,15 @@
2133421279
int c;
2133521280
s += utf8_tounicode(s, &c);
2133621281
}
2133721282
}
2133821283
21339
-
21284
+
2134021285
return REG_NOMATCH;
2134121286
}
2134221287
21343
-
21288
+
2134421289
static int regtry( regex_t *preg, const char *string )
2134521290
{
2134621291
int i;
2134721292
2134821293
preg->reginput = string;
@@ -21379,11 +21324,11 @@
2137921324
}
2138021325
2138121326
static int reg_range_find(const int *range, int c)
2138221327
{
2138321328
while (*range) {
21384
-
21329
+
2138521330
if (c >= range[1] && c <= (range[0] + range[1] - 1)) {
2138621331
return 1;
2138721332
}
2138821333
range += 2;
2138921334
}
@@ -21391,11 +21336,11 @@
2139121336
}
2139221337
2139321338
static const char *str_find(const char *string, int c, int nocase)
2139421339
{
2139521340
if (nocase) {
21396
-
21341
+
2139721342
c = utf8_upper(c);
2139821343
}
2139921344
while (*string) {
2140021345
int ch;
2140121346
int n = reg_utf8_tounicode_case(string, &ch, nocase);
@@ -21435,15 +21380,15 @@
2143521380
no = regrepeat(preg, scan + 5, max);
2143621381
if (no < min) {
2143721382
return 0;
2143821383
}
2143921384
if (matchmin) {
21440
-
21385
+
2144121386
max = no;
2144221387
no = min;
2144321388
}
21444
-
21389
+
2144521390
while (1) {
2144621391
if (matchmin) {
2144721392
if (no > max) {
2144821393
break;
2144921394
}
@@ -21453,22 +21398,22 @@
2145321398
break;
2145421399
}
2145521400
}
2145621401
preg->reginput = save + utf8_index(save, no);
2145721402
reg_utf8_tounicode_case(preg->reginput, &c, (preg->cflags & REG_ICASE));
21458
-
21403
+
2145921404
if (reg_iseol(preg, nextch) || c == nextch) {
2146021405
if (regmatch(preg, next)) {
2146121406
return(1);
2146221407
}
2146321408
}
2146421409
if (matchmin) {
21465
-
21410
+
2146621411
no++;
2146721412
}
2146821413
else {
21469
-
21414
+
2147021415
no--;
2147121416
}
2147221417
}
2147321418
return(0);
2147421419
}
@@ -21478,13 +21423,13 @@
2147821423
int *scanpt = preg->program + scan;
2147921424
2148021425
int max = scanpt[2];
2148121426
int min = scanpt[3];
2148221427
21483
-
21428
+
2148421429
if (scanpt[4] < min) {
21485
-
21430
+
2148621431
scanpt[4]++;
2148721432
if (regmatch(preg, scan + 5)) {
2148821433
return 1;
2148921434
}
2149021435
scanpt[4]--;
@@ -21493,39 +21438,39 @@
2149321438
if (scanpt[4] > max) {
2149421439
return 0;
2149521440
}
2149621441
2149721442
if (matchmin) {
21498
-
21443
+
2149921444
if (regmatch(preg, regnext(preg, scan))) {
2150021445
return 1;
2150121446
}
21502
-
21447
+
2150321448
scanpt[4]++;
2150421449
if (regmatch(preg, scan + 5)) {
2150521450
return 1;
2150621451
}
2150721452
scanpt[4]--;
2150821453
return 0;
2150921454
}
21510
-
21455
+
2151121456
if (scanpt[4] < max) {
2151221457
scanpt[4]++;
2151321458
if (regmatch(preg, scan + 5)) {
2151421459
return 1;
2151521460
}
2151621461
scanpt[4]--;
2151721462
}
21518
-
21463
+
2151921464
return regmatch(preg, regnext(preg, scan));
2152021465
}
2152121466
2152221467
2152321468
static int regmatch(regex_t *preg, int prog)
2152421469
{
21525
- int scan;
21526
- int next;
21470
+ int scan;
21471
+ int next;
2152721472
const char *save;
2152821473
2152921474
scan = prog;
2153021475
2153121476
#ifdef DEBUG
@@ -21535,11 +21480,11 @@
2153521480
while (scan != 0) {
2153621481
int n;
2153721482
int c;
2153821483
#ifdef DEBUG
2153921484
if (regnarrate) {
21540
- fprintf(stderr, "%3d: %s...\n", scan, regprop(OP(preg, scan)));
21485
+ fprintf(stderr, "%3d: %s...\n", scan, regprop(OP(preg, scan)));
2154121486
}
2154221487
#endif
2154321488
next = regnext(preg, scan);
2154421489
n = reg_utf8_tounicode_case(preg->reginput, &c, (preg->cflags & REG_ICASE));
2154521490
@@ -21546,49 +21491,49 @@
2154621491
switch (OP(preg, scan)) {
2154721492
case BOLX:
2154821493
if ((preg->eflags & REG_NOTBOL)) {
2154921494
return(0);
2155021495
}
21551
-
21496
+
2155221497
case BOL:
2155321498
if (preg->reginput != preg->regbol) {
2155421499
return(0);
2155521500
}
2155621501
break;
2155721502
case EOLX:
2155821503
if (c != 0) {
21559
-
21504
+
2156021505
return 0;
2156121506
}
2156221507
break;
2156321508
case EOL:
2156421509
if (!reg_iseol(preg, c)) {
2156521510
return(0);
2156621511
}
2156721512
break;
2156821513
case WORDA:
21569
-
21514
+
2157021515
if ((!isalnum(UCHAR(c))) && c != '_')
2157121516
return(0);
21572
-
21517
+
2157321518
if (preg->reginput > preg->regbol &&
2157421519
(isalnum(UCHAR(preg->reginput[-1])) || preg->reginput[-1] == '_'))
2157521520
return(0);
2157621521
break;
2157721522
case WORDZ:
21578
-
21523
+
2157921524
if (preg->reginput > preg->regbol) {
21580
-
21525
+
2158121526
if (reg_iseol(preg, c) || !isalnum(UCHAR(c)) || c != '_') {
2158221527
c = preg->reginput[-1];
21583
-
21528
+
2158421529
if (isalnum(UCHAR(c)) || c == '_') {
2158521530
break;
2158621531
}
2158721532
}
2158821533
}
21589
-
21534
+
2159021535
return(0);
2159121536
2159221537
case ANY:
2159321538
if (reg_iseol(preg, c))
2159421539
return 0;
@@ -21624,12 +21569,12 @@
2162421569
case NOTHING:
2162521570
break;
2162621571
case BACK:
2162721572
break;
2162821573
case BRANCH:
21629
- if (OP(preg, next) != BRANCH)
21630
- next = OPERAND(scan);
21574
+ if (OP(preg, next) != BRANCH)
21575
+ next = OPERAND(scan);
2163121576
else {
2163221577
do {
2163321578
save = preg->reginput;
2163421579
if (regmatch(preg, OPERAND(scan))) {
2163521580
return(1);
@@ -21636,11 +21581,11 @@
2163621581
}
2163721582
preg->reginput = save;
2163821583
scan = regnext(preg, scan);
2163921584
} while (scan != 0 && OP(preg, scan) == BRANCH);
2164021585
return(0);
21641
-
21586
+
2164221587
}
2164321588
break;
2164421589
case REP:
2164521590
case REPMIN:
2164621591
return regmatchsimplerepeat(preg, scan, OP(preg, scan) == REPMIN);
@@ -21648,11 +21593,11 @@
2164821593
case REPX:
2164921594
case REPXMIN:
2165021595
return regmatchrepeat(preg, scan, OP(preg, scan) == REPXMIN);
2165121596
2165221597
case END:
21653
- return 1;
21598
+ return 1;
2165421599
2165521600
case OPENNC:
2165621601
case CLOSENC:
2165721602
return regmatch(preg, next);
2165821603
@@ -21695,11 +21640,11 @@
2169521640
2169621641
scan = preg->reginput;
2169721642
opnd = OPERAND(p);
2169821643
switch (OP(preg, p)) {
2169921644
case ANY:
21700
-
21645
+
2170121646
while (!reg_iseol(preg, *scan) && count < max) {
2170221647
count++;
2170321648
scan++;
2170421649
}
2170521650
break;
@@ -21731,13 +21676,13 @@
2173121676
}
2173221677
count++;
2173321678
scan += n;
2173421679
}
2173521680
break;
21736
- default:
21681
+ default:
2173721682
preg->err = REG_ERR_INTERNAL;
21738
- count = 0;
21683
+ count = 0;
2173921684
break;
2174021685
}
2174121686
preg->reginput = scan;
2174221687
2174321688
return(count);
@@ -21758,11 +21703,11 @@
2175821703
return(p+offset);
2175921704
}
2176021705
2176121706
static int regopsize(regex_t *preg, int p )
2176221707
{
21763
-
21708
+
2176421709
switch (OP(preg, p)) {
2176521710
case REP:
2176621711
case REPMIN:
2176721712
case REPX:
2176821713
case REPXMIN:
@@ -21818,10 +21763,223 @@
2181821763
2181921764
void regfree(regex_t *preg)
2182021765
{
2182121766
free(preg->program);
2182221767
}
21768
+
21769
+#endif
21770
+#include <string.h>
21771
+
21772
+void Jim_SetResultErrno(Jim_Interp *interp, const char *msg)
21773
+{
21774
+ Jim_SetResultFormatted(interp, "%s: %s", msg, strerror(Jim_Errno()));
21775
+}
21776
+
21777
+#if defined(__MINGW32__)
21778
+#include <sys/stat.h>
21779
+
21780
+int Jim_Errno(void)
21781
+{
21782
+ switch (GetLastError()) {
21783
+ case ERROR_FILE_NOT_FOUND: return ENOENT;
21784
+ case ERROR_PATH_NOT_FOUND: return ENOENT;
21785
+ case ERROR_TOO_MANY_OPEN_FILES: return EMFILE;
21786
+ case ERROR_ACCESS_DENIED: return EACCES;
21787
+ case ERROR_INVALID_HANDLE: return EBADF;
21788
+ case ERROR_BAD_ENVIRONMENT: return E2BIG;
21789
+ case ERROR_BAD_FORMAT: return ENOEXEC;
21790
+ case ERROR_INVALID_ACCESS: return EACCES;
21791
+ case ERROR_INVALID_DRIVE: return ENOENT;
21792
+ case ERROR_CURRENT_DIRECTORY: return EACCES;
21793
+ case ERROR_NOT_SAME_DEVICE: return EXDEV;
21794
+ case ERROR_NO_MORE_FILES: return ENOENT;
21795
+ case ERROR_WRITE_PROTECT: return EROFS;
21796
+ case ERROR_BAD_UNIT: return ENXIO;
21797
+ case ERROR_NOT_READY: return EBUSY;
21798
+ case ERROR_BAD_COMMAND: return EIO;
21799
+ case ERROR_CRC: return EIO;
21800
+ case ERROR_BAD_LENGTH: return EIO;
21801
+ case ERROR_SEEK: return EIO;
21802
+ case ERROR_WRITE_FAULT: return EIO;
21803
+ case ERROR_READ_FAULT: return EIO;
21804
+ case ERROR_GEN_FAILURE: return EIO;
21805
+ case ERROR_SHARING_VIOLATION: return EACCES;
21806
+ case ERROR_LOCK_VIOLATION: return EACCES;
21807
+ case ERROR_SHARING_BUFFER_EXCEEDED: return ENFILE;
21808
+ case ERROR_HANDLE_DISK_FULL: return ENOSPC;
21809
+ case ERROR_NOT_SUPPORTED: return ENODEV;
21810
+ case ERROR_REM_NOT_LIST: return EBUSY;
21811
+ case ERROR_DUP_NAME: return EEXIST;
21812
+ case ERROR_BAD_NETPATH: return ENOENT;
21813
+ case ERROR_NETWORK_BUSY: return EBUSY;
21814
+ case ERROR_DEV_NOT_EXIST: return ENODEV;
21815
+ case ERROR_TOO_MANY_CMDS: return EAGAIN;
21816
+ case ERROR_ADAP_HDW_ERR: return EIO;
21817
+ case ERROR_BAD_NET_RESP: return EIO;
21818
+ case ERROR_UNEXP_NET_ERR: return EIO;
21819
+ case ERROR_NETNAME_DELETED: return ENOENT;
21820
+ case ERROR_NETWORK_ACCESS_DENIED: return EACCES;
21821
+ case ERROR_BAD_DEV_TYPE: return ENODEV;
21822
+ case ERROR_BAD_NET_NAME: return ENOENT;
21823
+ case ERROR_TOO_MANY_NAMES: return ENFILE;
21824
+ case ERROR_TOO_MANY_SESS: return EIO;
21825
+ case ERROR_SHARING_PAUSED: return EAGAIN;
21826
+ case ERROR_REDIR_PAUSED: return EAGAIN;
21827
+ case ERROR_FILE_EXISTS: return EEXIST;
21828
+ case ERROR_CANNOT_MAKE: return ENOSPC;
21829
+ case ERROR_OUT_OF_STRUCTURES: return ENFILE;
21830
+ case ERROR_ALREADY_ASSIGNED: return EEXIST;
21831
+ case ERROR_INVALID_PASSWORD: return EPERM;
21832
+ case ERROR_NET_WRITE_FAULT: return EIO;
21833
+ case ERROR_NO_PROC_SLOTS: return EAGAIN;
21834
+ case ERROR_DISK_CHANGE: return EXDEV;
21835
+ case ERROR_BROKEN_PIPE: return EPIPE;
21836
+ case ERROR_OPEN_FAILED: return ENOENT;
21837
+ case ERROR_DISK_FULL: return ENOSPC;
21838
+ case ERROR_NO_MORE_SEARCH_HANDLES: return EMFILE;
21839
+ case ERROR_INVALID_TARGET_HANDLE: return EBADF;
21840
+ case ERROR_INVALID_NAME: return ENOENT;
21841
+ case ERROR_PROC_NOT_FOUND: return ESRCH;
21842
+ case ERROR_WAIT_NO_CHILDREN: return ECHILD;
21843
+ case ERROR_CHILD_NOT_COMPLETE: return ECHILD;
21844
+ case ERROR_DIRECT_ACCESS_HANDLE: return EBADF;
21845
+ case ERROR_SEEK_ON_DEVICE: return ESPIPE;
21846
+ case ERROR_BUSY_DRIVE: return EAGAIN;
21847
+ case ERROR_DIR_NOT_EMPTY: return EEXIST;
21848
+ case ERROR_NOT_LOCKED: return EACCES;
21849
+ case ERROR_BAD_PATHNAME: return ENOENT;
21850
+ case ERROR_LOCK_FAILED: return EACCES;
21851
+ case ERROR_ALREADY_EXISTS: return EEXIST;
21852
+ case ERROR_FILENAME_EXCED_RANGE: return ENAMETOOLONG;
21853
+ case ERROR_BAD_PIPE: return EPIPE;
21854
+ case ERROR_PIPE_BUSY: return EAGAIN;
21855
+ case ERROR_PIPE_NOT_CONNECTED: return EPIPE;
21856
+ case ERROR_DIRECTORY: return ENOTDIR;
21857
+ }
21858
+ return EINVAL;
21859
+}
21860
+
21861
+pidtype waitpid(pidtype pid, int *status, int nohang)
21862
+{
21863
+ DWORD ret = WaitForSingleObject(pid, nohang ? 0 : INFINITE);
21864
+ if (ret == WAIT_TIMEOUT || ret == WAIT_FAILED) {
21865
+
21866
+ return JIM_BAD_PID;
21867
+ }
21868
+ GetExitCodeProcess(pid, &ret);
21869
+ *status = ret;
21870
+ CloseHandle(pid);
21871
+ return pid;
21872
+}
21873
+
21874
+int Jim_MakeTempFile(Jim_Interp *interp, const char *filename_template, int unlink_file)
21875
+{
21876
+ char name[MAX_PATH];
21877
+ HANDLE handle;
21878
+
21879
+ if (!GetTempPath(MAX_PATH, name) || !GetTempFileName(name, filename_template ? filename_template : "JIM", 0, name)) {
21880
+ return -1;
21881
+ }
21882
+
21883
+ handle = CreateFile(name, GENERIC_READ | GENERIC_WRITE, 0, NULL,
21884
+ CREATE_ALWAYS, FILE_ATTRIBUTE_TEMPORARY | (unlink_file ? FILE_FLAG_DELETE_ON_CLOSE : 0),
21885
+ NULL);
21886
+
21887
+ if (handle == INVALID_HANDLE_VALUE) {
21888
+ goto error;
21889
+ }
21890
+
21891
+ Jim_SetResultString(interp, name, -1);
21892
+ return _open_osfhandle((int)handle, _O_RDWR | _O_TEXT);
21893
+
21894
+ error:
21895
+ Jim_SetResultErrno(interp, name);
21896
+ DeleteFile(name);
21897
+ return -1;
21898
+}
21899
+
21900
+int Jim_OpenForWrite(const char *filename, int append)
21901
+{
21902
+ if (strcmp(filename, "/dev/null") == 0) {
21903
+ filename = "nul:";
21904
+ }
21905
+ int fd = _open(filename, _O_WRONLY | _O_CREAT | _O_TEXT | (append ? _O_APPEND : _O_TRUNC), _S_IREAD | _S_IWRITE);
21906
+ if (fd >= 0 && append) {
21907
+
21908
+ _lseek(fd, 0L, SEEK_END);
21909
+ }
21910
+ return fd;
21911
+}
21912
+
21913
+int Jim_OpenForRead(const char *filename)
21914
+{
21915
+ if (strcmp(filename, "/dev/null") == 0) {
21916
+ filename = "nul:";
21917
+ }
21918
+ return _open(filename, _O_RDONLY | _O_TEXT, 0);
21919
+}
21920
+
21921
+#elif defined(HAVE_UNISTD_H)
21922
+
21923
+
21924
+
21925
+int Jim_MakeTempFile(Jim_Interp *interp, const char *filename_template, int unlink_file)
21926
+{
21927
+ int fd;
21928
+ mode_t mask;
21929
+ Jim_Obj *filenameObj;
21930
+
21931
+ if (filename_template == NULL) {
21932
+ const char *tmpdir = getenv("TMPDIR");
21933
+ if (tmpdir == NULL || *tmpdir == '\0' || access(tmpdir, W_OK) != 0) {
21934
+ tmpdir = "/tmp/";
21935
+ }
21936
+ filenameObj = Jim_NewStringObj(interp, tmpdir, -1);
21937
+ if (tmpdir[0] && tmpdir[strlen(tmpdir) - 1] != '/') {
21938
+ Jim_AppendString(interp, filenameObj, "/", 1);
21939
+ }
21940
+ Jim_AppendString(interp, filenameObj, "tcl.tmp.XXXXXX", -1);
21941
+ }
21942
+ else {
21943
+ filenameObj = Jim_NewStringObj(interp, filename_template, -1);
21944
+ }
21945
+
21946
+
21947
+ mask = umask(S_IXUSR | S_IRWXG | S_IRWXO);
21948
+#ifdef HAVE_MKSTEMP
21949
+ fd = mkstemp(filenameObj->bytes);
21950
+#else
21951
+ if (mktemp(filenameObj->bytes) == NULL) {
21952
+ fd = -1;
21953
+ }
21954
+ else {
21955
+ fd = open(filenameObj->bytes, O_RDWR | O_CREAT | O_TRUNC);
21956
+ }
21957
+#endif
21958
+ umask(mask);
21959
+ if (fd < 0) {
21960
+ Jim_SetResultErrno(interp, Jim_String(filenameObj));
21961
+ Jim_FreeNewObj(interp, filenameObj);
21962
+ return -1;
21963
+ }
21964
+ if (unlink_file) {
21965
+ remove(Jim_String(filenameObj));
21966
+ }
21967
+
21968
+ Jim_SetResult(interp, filenameObj);
21969
+ return fd;
21970
+}
21971
+
21972
+int Jim_OpenForWrite(const char *filename, int append)
21973
+{
21974
+ return open(filename, O_WRONLY | O_CREAT | (append ? O_APPEND : O_TRUNC), 0666);
21975
+}
21976
+
21977
+int Jim_OpenForRead(const char *filename)
21978
+{
21979
+ return open(filename, O_RDONLY, 0);
21980
+}
2182321981
2182421982
#endif
2182521983
2182621984
#if defined(_WIN32) || defined(WIN32)
2182721985
#ifndef STRICT
@@ -21879,26 +22037,26 @@
2187922037
{
2188022038
DIR *dir = 0;
2188122039
2188222040
if (name && name[0]) {
2188322041
size_t base_length = strlen(name);
21884
- const char *all =
22042
+ const char *all =
2188522043
strchr("/\\", name[base_length - 1]) ? "*" : "/*";
2188622044
2188722045
if ((dir = (DIR *) Jim_Alloc(sizeof *dir)) != 0 &&
2188822046
(dir->name = (char *)Jim_Alloc(base_length + strlen(all) + 1)) != 0) {
2188922047
strcat(strcpy(dir->name, name), all);
2189022048
2189122049
if ((dir->handle = (long)_findfirst(dir->name, &dir->info)) != -1)
2189222050
dir->result.d_name = 0;
21893
- else {
22051
+ else {
2189422052
Jim_Free(dir->name);
2189522053
Jim_Free(dir);
2189622054
dir = 0;
2189722055
}
2189822056
}
21899
- else {
22057
+ else {
2190022058
Jim_Free(dir);
2190122059
dir = 0;
2190222060
errno = ENOMEM;
2190322061
}
2190422062
}
@@ -21916,11 +22074,11 @@
2191622074
if (dir->handle != -1)
2191722075
result = _findclose(dir->handle);
2191822076
Jim_Free(dir->name);
2191922077
Jim_Free(dir);
2192022078
}
21921
- if (result == -1)
22079
+ if (result == -1)
2192222080
errno = EBADF;
2192322081
return result;
2192422082
}
2192522083
2192622084
struct dirent *readdir(DIR * dir)
@@ -21938,28 +22096,77 @@
2193822096
}
2193922097
return result;
2194022098
}
2194122099
#endif
2194222100
#endif
22101
+#include <stdio.h>
22102
+#include <signal.h>
22103
+
22104
+
22105
+
22106
+
22107
+
22108
+
22109
+#ifndef SIGPIPE
22110
+#define SIGPIPE 13
22111
+#endif
22112
+#ifndef SIGINT
22113
+#define SIGINT 2
22114
+#endif
22115
+
22116
+const char *Jim_SignalId(int sig)
22117
+{
22118
+ static char buf[10];
22119
+ switch (sig) {
22120
+ case SIGINT: return "SIGINT";
22121
+ case SIGPIPE: return "SIGPIPE";
22122
+
22123
+ }
22124
+ snprintf(buf, sizeof(buf), "%d", sig);
22125
+ return buf;
22126
+}
2194322127
#ifndef JIM_BOOTSTRAP_LIB_ONLY
2194422128
#include <errno.h>
2194522129
#include <string.h>
2194622130
2194722131
2194822132
#ifdef USE_LINENOISE
2194922133
#ifdef HAVE_UNISTD_H
2195022134
#include <unistd.h>
2195122135
#endif
22136
+#ifdef HAVE_SYS_STAT_H
22137
+ #include <sys/stat.h>
22138
+#endif
2195222139
#include "linenoise.h"
2195322140
#else
2195422141
#define MAX_LINE_LEN 512
2195522142
#endif
2195622143
21957
-char *Jim_HistoryGetline(const char *prompt)
22144
+#ifdef USE_LINENOISE
22145
+static void JimCompletionCallback(const char *prefix, linenoiseCompletions *comp, void *userdata);
22146
+static const char completion_callback_assoc_key[] = "interactive-completion";
22147
+#endif
22148
+
22149
+char *Jim_HistoryGetline(Jim_Interp *interp, const char *prompt)
2195822150
{
2195922151
#ifdef USE_LINENOISE
21960
- return linenoise(prompt);
22152
+ struct JimCompletionInfo *compinfo = Jim_GetAssocData(interp, completion_callback_assoc_key);
22153
+ char *result;
22154
+ Jim_Obj *objPtr;
22155
+ long mlmode = 0;
22156
+ if (compinfo) {
22157
+ linenoiseSetCompletionCallback(JimCompletionCallback, compinfo);
22158
+ }
22159
+ objPtr = Jim_GetVariableStr(interp, "history::multiline", JIM_NONE);
22160
+ if (objPtr && Jim_GetLong(interp, objPtr, &mlmode) == JIM_NONE) {
22161
+ linenoiseSetMultiLine(mlmode);
22162
+ }
22163
+
22164
+ result = linenoise(prompt);
22165
+
22166
+ linenoiseSetCompletionCallback(NULL, NULL);
22167
+ return result;
2196122168
#else
2196222169
int len;
2196322170
char *line = malloc(MAX_LINE_LEN);
2196422171
2196522172
fputs(prompt, stdout);
@@ -21992,26 +22199,92 @@
2199222199
}
2199322200
2199422201
void Jim_HistorySave(const char *filename)
2199522202
{
2199622203
#ifdef USE_LINENOISE
22204
+#ifdef HAVE_UMASK
22205
+ mode_t mask;
22206
+
22207
+ mask = umask(S_IXUSR | S_IRWXG | S_IRWXO);
22208
+#endif
2199722209
linenoiseHistorySave(filename);
22210
+#ifdef HAVE_UMASK
22211
+ umask(mask);
22212
+#endif
2199822213
#endif
2199922214
}
2200022215
2200122216
void Jim_HistoryShow(void)
2200222217
{
2200322218
#ifdef USE_LINENOISE
22004
-
22219
+
2200522220
int i;
2200622221
int len;
2200722222
char **history = linenoiseHistory(&len);
2200822223
for (i = 0; i < len; i++) {
2200922224
printf("%4d %s\n", i + 1, history[i]);
2201022225
}
2201122226
#endif
2201222227
}
22228
+
22229
+#ifdef USE_LINENOISE
22230
+struct JimCompletionInfo {
22231
+ Jim_Interp *interp;
22232
+ Jim_Obj *command;
22233
+};
22234
+
22235
+static void JimCompletionCallback(const char *prefix, linenoiseCompletions *comp, void *userdata)
22236
+{
22237
+ struct JimCompletionInfo *info = (struct JimCompletionInfo *)userdata;
22238
+ Jim_Obj *objv[2];
22239
+ int ret;
22240
+
22241
+ objv[0] = info->command;
22242
+ objv[1] = Jim_NewStringObj(info->interp, prefix, -1);
22243
+
22244
+ ret = Jim_EvalObjVector(info->interp, 2, objv);
22245
+
22246
+
22247
+ if (ret == JIM_OK) {
22248
+ int i;
22249
+ Jim_Obj *listObj = Jim_GetResult(info->interp);
22250
+ int len = Jim_ListLength(info->interp, listObj);
22251
+ for (i = 0; i < len; i++) {
22252
+ linenoiseAddCompletion(comp, Jim_String(Jim_ListGetIndex(info->interp, listObj, i)));
22253
+ }
22254
+ }
22255
+}
22256
+
22257
+static void JimHistoryFreeCompletion(Jim_Interp *interp, void *data)
22258
+{
22259
+ struct JimCompletionInfo *compinfo = data;
22260
+
22261
+ Jim_DecrRefCount(interp, compinfo->command);
22262
+
22263
+ Jim_Free(compinfo);
22264
+}
22265
+#endif
22266
+
22267
+void Jim_HistorySetCompletion(Jim_Interp *interp, Jim_Obj *commandObj)
22268
+{
22269
+#ifdef USE_LINENOISE
22270
+ if (commandObj) {
22271
+
22272
+ Jim_IncrRefCount(commandObj);
22273
+ }
22274
+
22275
+ Jim_DeleteAssocData(interp, completion_callback_assoc_key);
22276
+
22277
+ if (commandObj) {
22278
+ struct JimCompletionInfo *compinfo = Jim_Alloc(sizeof(*compinfo));
22279
+ compinfo->interp = interp;
22280
+ compinfo->command = commandObj;
22281
+
22282
+ Jim_SetAssocData(interp, completion_callback_assoc_key, JimHistoryFreeCompletion, compinfo);
22283
+ }
22284
+#endif
22285
+}
2201322286
2201422287
int Jim_InteractivePrompt(Jim_Interp *interp)
2201522288
{
2201622289
int retcode = JIM_OK;
2201722290
char *history_file = NULL;
@@ -22023,10 +22296,12 @@
2202322296
int history_len = strlen(home) + sizeof("/.jim_history");
2202422297
history_file = Jim_Alloc(history_len);
2202522298
snprintf(history_file, history_len, "%s/.jim_history", home);
2202622299
Jim_HistoryLoad(history_file);
2202722300
}
22301
+
22302
+ Jim_HistorySetCompletion(interp, Jim_NewStringObj(interp, "tcl::autocomplete", -1));
2202822303
#endif
2202922304
2203022305
printf("Welcome to Jim version %d.%d\n",
2203122306
JIM_VERSION / 100, JIM_VERSION % 100);
2203222307
Jim_SetVariableStrWithStr(interp, JIM_INTERACTIVE, "1");
@@ -22055,21 +22330,21 @@
2205522330
Jim_IncrRefCount(scriptObjPtr);
2205622331
while (1) {
2205722332
char state;
2205822333
char *line;
2205922334
22060
- line = Jim_HistoryGetline(prompt);
22335
+ line = Jim_HistoryGetline(interp, prompt);
2206122336
if (line == NULL) {
2206222337
if (errno == EINTR) {
2206322338
continue;
2206422339
}
2206522340
Jim_DecrRefCount(interp, scriptObjPtr);
2206622341
retcode = JIM_OK;
2206722342
goto out;
2206822343
}
2206922344
if (Jim_Length(scriptObjPtr) != 0) {
22070
-
22345
+
2207122346
Jim_AppendString(interp, scriptObjPtr, "\n", 1);
2207222347
}
2207322348
Jim_AppendString(interp, scriptObjPtr, line, -1);
2207422349
free(line);
2207522350
if (Jim_ScriptIsComplete(interp, scriptObjPtr, &state))
@@ -22077,11 +22352,11 @@
2207722352
2207822353
snprintf(prompt, sizeof(prompt), "%c> ", state);
2207922354
}
2208022355
#ifdef USE_LINENOISE
2208122356
if (strcmp(Jim_String(scriptObjPtr), "h") == 0) {
22082
-
22357
+
2208322358
Jim_HistoryShow();
2208422359
Jim_DecrRefCount(interp, scriptObjPtr);
2208522360
continue;
2208622361
}
2208722362
@@ -22104,10 +22379,11 @@
2210422379
printf("%s\n", result);
2210522380
}
2210622381
}
2210722382
out:
2210822383
Jim_Free(history_file);
22384
+
2210922385
return retcode;
2211022386
}
2211122387
2211222388
#include <stdio.h>
2211322389
#include <stdlib.h>
@@ -22120,11 +22396,11 @@
2212022396
static void JimSetArgv(Jim_Interp *interp, int argc, char *const argv[])
2212122397
{
2212222398
int n;
2212322399
Jim_Obj *listObj = Jim_NewListObj(interp, NULL, 0);
2212422400
22125
-
22401
+
2212622402
for (n = 0; n < argc; n++) {
2212722403
Jim_Obj *obj = Jim_NewStringObj(interp, argv[n], -1);
2212822404
2212922405
Jim_ListAppendElement(interp, listObj, obj);
2213022406
}
@@ -22146,71 +22422,75 @@
2214622422
printf("or : %s [options] [filename]\n", executable_name);
2214722423
printf("\n");
2214822424
printf("Without options: Interactive mode\n");
2214922425
printf("\n");
2215022426
printf("Options:\n");
22151
- printf(" --version : prints the version string\n");
22152
- printf(" --help : prints this text\n");
22153
- printf(" -e CMD : executes command CMD\n");
22154
- printf(" NOTE: all subsequent options will be passed as arguments to the command\n");
22155
- printf(" [filename] : executes the script contained in the named file\n");
22156
- printf(" NOTE: all subsequent options will be passed to the script\n\n");
22427
+ printf(" --version : prints the version string\n");
22428
+ printf(" --help : prints this text\n");
22429
+ printf(" -e CMD : executes command CMD\n");
22430
+ printf(" NOTE: all subsequent options will be passed as arguments to the command\n");
22431
+ printf(" [filename|-] : executes the script contained in the named file, or from stdin if \"-\"\n");
22432
+ printf(" NOTE: all subsequent options will be passed to the script\n\n");
2215722433
}
2215822434
2215922435
int main(int argc, char *const argv[])
2216022436
{
2216122437
int retcode;
2216222438
Jim_Interp *interp;
2216322439
char *const orig_argv0 = argv[0];
2216422440
22165
-
22441
+
2216622442
if (argc > 1 && strcmp(argv[1], "--version") == 0) {
2216722443
printf("%d.%d\n", JIM_VERSION / 100, JIM_VERSION % 100);
2216822444
return 0;
2216922445
}
2217022446
else if (argc > 1 && strcmp(argv[1], "--help") == 0) {
2217122447
usage(argv[0]);
2217222448
return 0;
2217322449
}
2217422450
22175
-
22451
+
2217622452
interp = Jim_CreateInterp();
2217722453
Jim_RegisterCoreCommands(interp);
2217822454
22179
-
22455
+
2218022456
if (Jim_InitStaticExtensions(interp) != JIM_OK) {
2218122457
JimPrintErrorMessage(interp);
2218222458
}
2218322459
2218422460
Jim_SetVariableStrWithStr(interp, "jim::argv0", orig_argv0);
2218522461
Jim_SetVariableStrWithStr(interp, JIM_INTERACTIVE, argc == 1 ? "1" : "0");
2218622462
retcode = Jim_initjimshInit(interp);
2218722463
2218822464
if (argc == 1) {
22189
-
22465
+
2219022466
if (retcode == JIM_ERR) {
2219122467
JimPrintErrorMessage(interp);
2219222468
}
2219322469
if (retcode != JIM_EXIT) {
2219422470
JimSetArgv(interp, 0, NULL);
2219522471
retcode = Jim_InteractivePrompt(interp);
2219622472
}
2219722473
}
2219822474
else {
22199
-
22475
+
2220022476
if (argc > 2 && strcmp(argv[1], "-e") == 0) {
22201
-
22477
+
2220222478
JimSetArgv(interp, argc - 3, argv + 3);
2220322479
retcode = Jim_Eval(interp, argv[2]);
2220422480
if (retcode != JIM_ERR) {
2220522481
printf("%s\n", Jim_String(Jim_GetResult(interp)));
2220622482
}
2220722483
}
2220822484
else {
2220922485
Jim_SetVariableStr(interp, "argv0", Jim_NewStringObj(interp, argv[1], -1));
2221022486
JimSetArgv(interp, argc - 2, argv + 2);
22211
- retcode = Jim_EvalFile(interp, argv[1]);
22487
+ if (strcmp(argv[1], "-") == 0) {
22488
+ retcode = Jim_Eval(interp, "eval [info source [stdin read] stdin 1]");
22489
+ } else {
22490
+ retcode = Jim_EvalFile(interp, argv[1]);
22491
+ }
2221222492
}
2221322493
if (retcode == JIM_ERR) {
2221422494
JimPrintErrorMessage(interp);
2221522495
}
2221622496
}
2221722497
--- autosetup/jimsh0.c
+++ autosetup/jimsh0.c
@@ -1,9 +1,7 @@
1 /* This is single source file, bootstrap version of Jim Tcl. See http://jim.tcl.tk/ */
2 #define _GNU_SOURCE
3 #define JIM_TCL_COMPAT
4 #define JIM_REFERENCES
5 #define JIM_ANSIC
6 #define JIM_REGEXP
7 #define HAVE_NO_AUTOCONF
8 #define _JIMAUTOCONF_H
9 #define TCL_LIBRARY "."
@@ -31,24 +29,39 @@
31 #define HAVE_MKDIR_ONE_ARG
32 #define HAVE_SYSTEM
33 #define HAVE_SYS_TIME_H
34 #define HAVE_DIRENT_H
35 #define HAVE_UNISTD_H
 
 
 
 
 
 
 
 
36 #else
37 #define TCL_PLATFORM_OS "unknown"
38 #define TCL_PLATFORM_PLATFORM "unix"
39 #define TCL_PLATFORM_PATH_SEPARATOR ":"
 
 
 
 
 
 
40 #define HAVE_VFORK
41 #define HAVE_WAITPID
42 #define HAVE_ISATTY
43 #define HAVE_MKSTEMP
44 #define HAVE_LINK
45 #define HAVE_SYS_TIME_H
46 #define HAVE_DIRENT_H
47 #define HAVE_UNISTD_H
 
48 #endif
49 #define JIM_VERSION 76
50 #ifndef JIM_WIN32COMPAT_H
51 #define JIM_WIN32COMPAT_H
52
53
54
@@ -88,11 +101,10 @@
88 #define JIM_WIDE_MIN LLONG_MIN
89 #define JIM_WIDE_MAX LLONG_MAX
90 #define JIM_WIDE_MODIFIER "I64d"
91 #define strcasecmp _stricmp
92 #define strtoull _strtoui64
93 #define snprintf _snprintf
94
95 #include <io.h>
96
97 struct timeval {
98 long tv_sec;
@@ -105,29 +117,24 @@
105 struct dirent {
106 char *d_name;
107 };
108
109 typedef struct DIR {
110 long handle;
111 struct _finddata_t info;
112 struct dirent result;
113 char *name;
114 } DIR;
115
116 DIR *opendir(const char *name);
117 int closedir(DIR *dir);
118 struct dirent *readdir(DIR *dir);
119
120 #elif defined(__MINGW32__)
121
122 #include <stdlib.h>
123 #define strtod __strtod
124
125 #endif
126
127 #endif
128
129 #ifdef __cplusplus
130 }
131 #endif
132
133 #endif
@@ -146,19 +153,21 @@
146
147 #ifndef JIM_UTF8
148 #include <ctype.h>
149
150
151 #define utf8_strlen(S, B) ((B) < 0 ? strlen(S) : (B))
 
152 #define utf8_tounicode(S, CP) (*(CP) = (unsigned char)*(S), 1)
153 #define utf8_getchars(CP, C) (*(CP) = (C), 1)
154 #define utf8_upper(C) toupper(C)
155 #define utf8_title(C) toupper(C)
156 #define utf8_lower(C) tolower(C)
157 #define utf8_index(C, I) (I)
158 #define utf8_charlen(C) 1
159 #define utf8_prev_len(S, L) 1
 
160
161 #else
162
163 #endif
164
@@ -175,13 +184,13 @@
175 extern "C" {
176 #endif
177
178 #include <time.h>
179 #include <limits.h>
180 #include <stdio.h>
181 #include <stdlib.h>
182 #include <stdarg.h>
183
184
185 #ifndef HAVE_NO_AUTOCONF
186 #endif
187
@@ -224,31 +233,31 @@
224 #define JIM_SIGNAL 5
225 #define JIM_EXIT 6
226
227 #define JIM_EVAL 7
228
229 #define JIM_MAX_CALLFRAME_DEPTH 1000
230 #define JIM_MAX_EVAL_DEPTH 2000
231
232
233 #define JIM_PRIV_FLAG_SHIFT 20
234
235 #define JIM_NONE 0
236 #define JIM_ERRMSG 1
237 #define JIM_ENUM_ABBREV 2
238 #define JIM_UNSHARED 4
239 #define JIM_MUSTEXIST 8
240
241
242 #define JIM_SUBST_NOVAR 1
243 #define JIM_SUBST_NOCMD 2
244 #define JIM_SUBST_NOESC 4
245 #define JIM_SUBST_FLAG 128
246
247
248 #define JIM_CASESENS 0
249 #define JIM_NOCASE 1
250
251
252 #define JIM_PATH_LEN 1024
253
254
@@ -339,79 +348,80 @@
339 #define Jim_GetHashTableSize(ht) ((ht)->size)
340 #define Jim_GetHashTableUsed(ht) ((ht)->used)
341
342
343 typedef struct Jim_Obj {
344 char *bytes;
345 const struct Jim_ObjType *typePtr;
346 int refCount;
347 int length;
348
349 union {
350
351 jim_wide wideValue;
352
353 int intValue;
354
355 double doubleValue;
356
357 void *ptr;
358
359 struct {
360 void *ptr1;
361 void *ptr2;
362 } twoPtrValue;
363
 
 
 
 
 
 
364 struct {
365 struct Jim_Var *varPtr;
366 unsigned long callFrameId;
367 int global;
368 } varValue;
369
370 struct {
371 struct Jim_Obj *nsObj;
372 struct Jim_Cmd *cmdPtr;
373 unsigned long procEpoch;
374 } cmdValue;
375
376 struct {
377 struct Jim_Obj **ele;
378 int len;
379 int maxLen;
380 } listValue;
381
382 struct {
383 int maxLength;
384 int charLength;
385 } strValue;
386
387 struct {
388 unsigned long id;
389 struct Jim_Reference *refPtr;
390 } refValue;
391
392 struct {
393 struct Jim_Obj *fileNameObj;
394 int lineNumber;
395 } sourceValue;
396
397 struct {
398 struct Jim_Obj *varNameObjPtr;
399 struct Jim_Obj *indexObjPtr;
400 } dictSubstValue;
401
402 struct {
403 void *compre;
404 unsigned flags;
405 } regexpValue;
406 struct {
407 int line;
408 int argc;
409 } scriptLineValue;
410 } internalRep;
411 struct Jim_Obj *prevObjPtr;
412 struct Jim_Obj *nextObjPtr;
413 } Jim_Obj;
414
415
416 #define Jim_IncrRefCount(objPtr) \
417 ++(objPtr)->refCount
@@ -442,40 +452,40 @@
442 typedef void (Jim_DupInternalRepProc)(struct Jim_Interp *interp,
443 struct Jim_Obj *srcPtr, Jim_Obj *dupPtr);
444 typedef void (Jim_UpdateStringProc)(struct Jim_Obj *objPtr);
445
446 typedef struct Jim_ObjType {
447 const char *name;
448 Jim_FreeInternalRepProc *freeIntRepProc;
449 Jim_DupInternalRepProc *dupIntRepProc;
450 Jim_UpdateStringProc *updateStringProc;
451 int flags;
452 } Jim_ObjType;
453
454
455 #define JIM_TYPE_NONE 0
456 #define JIM_TYPE_REFERENCES 1
457
458
459
460 typedef struct Jim_CallFrame {
461 unsigned long id;
462 int level;
463 struct Jim_HashTable vars;
464 struct Jim_HashTable *staticVars;
465 struct Jim_CallFrame *parent;
466 Jim_Obj *const *argv;
467 int argc;
468 Jim_Obj *procArgsObjPtr;
469 Jim_Obj *procBodyObjPtr;
470 struct Jim_CallFrame *next;
471 Jim_Obj *nsObj;
472 Jim_Obj *fileNameObj;
473 int line;
474 Jim_Stack *localCommands;
475 struct Jim_Obj *tailcallObj;
476 struct Jim_Cmd *tailcallCmd;
477 } Jim_CallFrame;
478
479 typedef struct Jim_Var {
480 Jim_Obj *objPtr;
481 struct Jim_CallFrame *linkFramePtr;
@@ -487,35 +497,35 @@
487 typedef void Jim_DelCmdProc(struct Jim_Interp *interp, void *privData);
488
489
490
491 typedef struct Jim_Cmd {
492 int inUse;
493 int isproc;
494 struct Jim_Cmd *prevCmd;
495 union {
496 struct {
497
498 Jim_CmdProc *cmdProc;
499 Jim_DelCmdProc *delProc;
500 void *privData;
501 } native;
502 struct {
503
504 Jim_Obj *argListObjPtr;
505 Jim_Obj *bodyObjPtr;
506 Jim_HashTable *staticVars;
507 int argListLen;
508 int reqArity;
509 int optArity;
510 int argsPos;
511 int upcall;
512 struct Jim_ProcArg {
513 Jim_Obj *nameObjPtr;
514 Jim_Obj *defaultObjPtr;
515 } *arglist;
516 Jim_Obj *nsObj;
517 } proc;
518 } u;
519 } Jim_Cmd;
520
521
@@ -523,64 +533,64 @@
523 unsigned char sbox[256];
524 unsigned int i, j;
525 } Jim_PrngState;
526
527 typedef struct Jim_Interp {
528 Jim_Obj *result;
529 int errorLine;
530 Jim_Obj *errorFileNameObj;
531 int addStackTrace;
532 int maxCallFrameDepth;
533 int maxEvalDepth;
534 int evalDepth;
535 int returnCode;
536 int returnLevel;
537 int exitCode;
538 long id;
539 int signal_level;
540 jim_wide sigmask;
541 int (*signal_set_result)(struct Jim_Interp *interp, jim_wide sigmask);
542 Jim_CallFrame *framePtr;
543 Jim_CallFrame *topFramePtr;
544 struct Jim_HashTable commands;
545 unsigned long procEpoch; /* Incremented every time the result
546 of procedures names lookup caching
547 may no longer be valid. */
548 unsigned long callFrameEpoch; /* Incremented every time a new
549 callframe is created. This id is used for the
550 'ID' field contained in the Jim_CallFrame
551 structure. */
552 int local;
553 Jim_Obj *liveList;
554 Jim_Obj *freeList;
555 Jim_Obj *currentScriptObj;
556 Jim_Obj *nullScriptObj;
557 Jim_Obj *emptyObj;
558 Jim_Obj *trueObj;
559 Jim_Obj *falseObj;
560 unsigned long referenceNextId;
561 struct Jim_HashTable references;
562 unsigned long lastCollectId; /* reference max Id of the last GC
563 execution. It's set to -1 while the collection
564 is running as sentinel to avoid to recursive
565 calls via the [collect] command inside
566 finalizers. */
567 time_t lastCollectTime;
568 Jim_Obj *stackTrace;
569 Jim_Obj *errorProc;
570 Jim_Obj *unknown;
571 int unknown_called;
572 int errorFlag;
573 void *cmdPrivData; /* Used to pass the private data pointer to
574 a command. It is set to what the user specified
575 via Jim_CreateCommand(). */
576
577 struct Jim_CallFrame *freeFramesList;
578 struct Jim_HashTable assocData;
579 Jim_PrngState *prngState;
580 struct Jim_HashTable packages;
581 Jim_Stack *loadHandles;
582 } Jim_Interp;
583
584 #define Jim_InterpIncrProcEpoch(i) (i)->procEpoch++
585 #define Jim_SetResultString(i,s,l) Jim_SetResult(i, Jim_NewStringObj(i,s,l))
586 #define Jim_SetResultInt(i,intval) Jim_SetResult(i, Jim_NewIntObj(i,intval))
@@ -623,11 +633,11 @@
623 JIM_EXPORT char *Jim_StrDupLen(const char *s, int l);
624
625
626 JIM_EXPORT char **Jim_GetEnviron(void);
627 JIM_EXPORT void Jim_SetEnviron(char **env);
628 JIM_EXPORT int Jim_MakeTempFile(Jim_Interp *interp, const char *template);
629
630
631 JIM_EXPORT int Jim_Eval(Jim_Interp *interp, const char *script);
632
633
@@ -816,25 +826,33 @@
816 Jim_Obj *newObjPtr, int flags);
817 JIM_EXPORT int Jim_DictPairs(Jim_Interp *interp,
818 Jim_Obj *dictPtr, Jim_Obj ***objPtrPtr, int *len);
819 JIM_EXPORT int Jim_DictAddElement(Jim_Interp *interp, Jim_Obj *objPtr,
820 Jim_Obj *keyObjPtr, Jim_Obj *valueObjPtr);
821 JIM_EXPORT int Jim_DictKeys(Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj *patternObj);
822 JIM_EXPORT int Jim_DictValues(Jim_Interp *interp, Jim_Obj *dictObjPtr, Jim_Obj *patternObjPtr);
 
 
 
823 JIM_EXPORT int Jim_DictSize(Jim_Interp *interp, Jim_Obj *objPtr);
824 JIM_EXPORT int Jim_DictInfo(Jim_Interp *interp, Jim_Obj *objPtr);
 
825
826
827 JIM_EXPORT int Jim_GetReturnCode (Jim_Interp *interp, Jim_Obj *objPtr,
828 int *intPtr);
829
830
831 JIM_EXPORT int Jim_EvalExpression (Jim_Interp *interp,
832 Jim_Obj *exprObjPtr, Jim_Obj **exprResultPtrPtr);
833 JIM_EXPORT int Jim_GetBoolFromExpr (Jim_Interp *interp,
834 Jim_Obj *exprObjPtr, int *boolPtr);
835
 
 
 
 
836
837 JIM_EXPORT int Jim_GetWide (Jim_Interp *interp, Jim_Obj *objPtr,
838 jim_wide *widePtr);
839 JIM_EXPORT int Jim_GetLong (Jim_Interp *interp, Jim_Obj *objPtr,
840 long *longPtr);
@@ -852,10 +870,12 @@
852
853 JIM_EXPORT void Jim_WrongNumArgs (Jim_Interp *interp, int argc,
854 Jim_Obj *const *argv, const char *msg);
855 JIM_EXPORT int Jim_GetEnum (Jim_Interp *interp, Jim_Obj *objPtr,
856 const char * const *tablePtr, int *indexPtr, const char *name, int flags);
 
 
857 JIM_EXPORT int Jim_ScriptIsComplete(Jim_Interp *interp,
858 Jim_Obj *scriptObj, char *stateCharPtr);
859
860 JIM_EXPORT int Jim_FindByName(const char *name, const char * const array[], size_t len);
861
@@ -878,11 +898,12 @@
878
879
880 JIM_EXPORT int Jim_InteractivePrompt (Jim_Interp *interp);
881 JIM_EXPORT void Jim_HistoryLoad(const char *filename);
882 JIM_EXPORT void Jim_HistorySave(const char *filename);
883 JIM_EXPORT char *Jim_HistoryGetline(const char *prompt);
 
884 JIM_EXPORT void Jim_HistoryAdd(const char *line);
885 JIM_EXPORT void Jim_HistoryShow(void);
886
887
888 JIM_EXPORT int Jim_InitStaticExtensions(Jim_Interp *interp);
@@ -904,11 +925,11 @@
904
905 #ifdef __cplusplus
906 }
907 #endif
908
909 #endif
910
911 #ifndef JIM_SUBCMD_H
912 #define JIM_SUBCMD_H
913
914
@@ -915,24 +936,24 @@
915 #ifdef __cplusplus
916 extern "C" {
917 #endif
918
919
920 #define JIM_MODFLAG_HIDDEN 0x0001
921 #define JIM_MODFLAG_FULLARGV 0x0002
922
923
924
925 typedef int jim_subcmd_function(Jim_Interp *interp, int argc, Jim_Obj *const *argv);
926
927 typedef struct {
928 const char *cmd;
929 const char *args;
930 jim_subcmd_function *function;
931 short minargs;
932 short maxargs;
933 unsigned short flags;
934 } jim_subcmd_type;
935
936 const jim_subcmd_type *
937 Jim_ParseSubCmd(Jim_Interp *interp, const jim_subcmd_type *command_table, int argc, Jim_Obj *const *argv);
938
@@ -960,36 +981,36 @@
960 int rm_eo;
961 } regmatch_t;
962
963
964 typedef struct regexp {
965
966 int re_nsub;
967
968
969 int cflags;
970 int err;
971 int regstart;
972 int reganch;
973 int regmust;
974 int regmlen;
975 int *program;
976
977
978 const char *regparse;
979 int p;
980 int proglen;
981
982
983 int eflags;
984 const char *start;
985 const char *reginput;
986 const char *regbol;
987
988
989 regmatch_t *pmatch;
990 int nmatch;
991 } regexp;
992
993 typedef regexp regex_t;
994
995 #define REG_EXTENDED 0
@@ -997,13 +1018,13 @@
997 #define REG_ICASE 2
998
999 #define REG_NOTBOL 16
1000
1001 enum {
1002 REG_NOERROR,
1003 REG_NOMATCH,
1004 REG_BADPAT,
1005 REG_ERR_NULL_ARGUMENT,
1006 REG_ERR_UNKNOWN,
1007 REG_ERR_TOO_BIG,
1008 REG_ERR_NOMEM,
1009 REG_ERR_TOO_MANY_PAREN,
@@ -1028,24 +1049,101 @@
1028
1029 #ifdef __cplusplus
1030 }
1031 #endif
1032
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1033 #endif
1034 int Jim_bootstrapInit(Jim_Interp *interp)
1035 {
1036 if (Jim_PackageProvide(interp, "bootstrap", "1.0", JIM_ERRMSG))
1037 return JIM_ERR;
1038
1039 return Jim_EvalSource(interp, "bootstrap.tcl", 1,
1040 "\n"
1041 "\n"
1042 "proc package {cmd pkg} {\n"
1043 " if {$cmd eq \"require\"} {\n"
1044 " foreach path $::auto_path {\n"
1045 " if {[file exists $path/$pkg.tcl]} {\n"
1046 " uplevel #0 [list source $path/$pkg.tcl]\n"
 
 
 
 
1047 " return\n"
1048 " }\n"
1049 " }\n"
1050 " }\n"
1051 "}\n"
@@ -1100,10 +1198,43 @@
1100 "\n"
1101 "if {$tcl_platform(platform) eq \"windows\"} {\n"
1102 " set jim::argv0 [string map {\\\\ /} $jim::argv0]\n"
1103 "}\n"
1104 "\n"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1105 "_jimsh_init\n"
1106 );
1107 }
1108 int Jim_globInit(Jim_Interp *interp)
1109 {
@@ -1315,10 +1446,17 @@
1315 return JIM_ERR;
1316
1317 return Jim_EvalSource(interp, "stdlib.tcl", 1,
1318 "\n"
1319 "\n"
 
 
 
 
 
 
 
1320 "\n"
1321 "proc lambda {arglist args} {\n"
1322 " tailcall proc [ref {} function lambda.finalizer] $arglist {*}$args\n"
1323 "}\n"
1324 "\n"
@@ -1375,10 +1513,17 @@
1375 " }\n"
1376 " join $lines \\n\n"
1377 "}\n"
1378 "\n"
1379 "\n"
 
 
 
 
 
 
 
1380 "\n"
1381 "proc errorInfo {msg {stacktrace \"\"}} {\n"
1382 " if {$stacktrace eq \"\"} {\n"
1383 "\n"
1384 " set stacktrace [info stacktrace]\n"
@@ -1402,31 +1547,10 @@
1402 " if {[exists ::jim::exe]} {\n"
1403 " return $::jim::exe\n"
1404 " }\n"
1405 "}\n"
1406 "\n"
1407 "\n"
1408 "proc {dict with} {&dictVar {args key} script} {\n"
1409 " set keys {}\n"
1410 " foreach {n v} [dict get $dictVar {*}$key] {\n"
1411 " upvar $n var_$n\n"
1412 " set var_$n $v\n"
1413 " lappend keys $n\n"
1414 " }\n"
1415 " catch {uplevel 1 $script} msg opts\n"
1416 " if {[info exists dictVar] && ([llength $key] == 0 || [dict exists $dictVar {*}$key])} {\n"
1417 " foreach n $keys {\n"
1418 " if {[info exists var_$n]} {\n"
1419 " dict set dictVar {*}$key $n [set var_$n]\n"
1420 " } else {\n"
1421 " dict unset dictVar {*}$key $n\n"
1422 " }\n"
1423 " }\n"
1424 " }\n"
1425 " return {*}$opts $msg\n"
1426 "}\n"
1427 "\n"
1428 "\n"
1429 "proc {dict update} {&varName args script} {\n"
1430 " set keys {}\n"
1431 " foreach {n v} $args {\n"
1432 " upvar $v var_$v\n"
@@ -1445,23 +1569,10 @@
1445 " }\n"
1446 " }\n"
1447 " return {*}$opts $msg\n"
1448 "}\n"
1449 "\n"
1450 "\n"
1451 "\n"
1452 "proc {dict merge} {dict args} {\n"
1453 " foreach d $args {\n"
1454 "\n"
1455 " dict size $d\n"
1456 " foreach {k v} $d {\n"
1457 " dict set dict $k $v\n"
1458 " }\n"
1459 " }\n"
1460 " return $dict\n"
1461 "}\n"
1462 "\n"
1463 "proc {dict replace} {dictionary {args {key value}}} {\n"
1464 " if {[llength ${key value}] % 2} {\n"
1465 " tailcall {dict replace}\n"
1466 " }\n"
1467 " tailcall dict merge $dictionary ${key value}\n"
@@ -1503,15 +1614,10 @@
1503 " dict unset dictionary $k\n"
1504 " }\n"
1505 " return $dictionary\n"
1506 "}\n"
1507 "\n"
1508 "\n"
1509 "proc {dict values} {dictionary {pattern *}} {\n"
1510 " dict keys [lreverse $dictionary] $pattern\n"
1511 "}\n"
1512 "\n"
1513 "\n"
1514 "proc {dict for} {vars dictionary script} {\n"
1515 " if {[llength $vars] != 2} {\n"
1516 " return -code error \"must have exactly two variable names\"\n"
1517 " }\n"
@@ -1591,11 +1697,10 @@
1591 " tailcall {*}$args\n"
1592 "}\n"
1593 "\n"
1594 "\n"
1595 "\n"
1596 "\n"
1597 "proc parray {arrayname {pattern *} {puts puts}} {\n"
1598 " upvar $arrayname a\n"
1599 "\n"
1600 " set max 0\n"
1601 " foreach name [array names a $pattern]] {\n"
@@ -1647,11 +1752,11 @@
1647 "}\n"
1648 "\n"
1649 "\n"
1650 "\n"
1651 "proc popen {cmd {mode r}} {\n"
1652 " lassign [socket pipe] r w\n"
1653 " try {\n"
1654 " if {[string match \"w*\" $mode]} {\n"
1655 " lappend cmd <@$r &\n"
1656 " set pids [exec {*}$cmd]\n"
1657 " $r close\n"
@@ -1663,16 +1768,31 @@
1663 " set f $r\n"
1664 " }\n"
1665 " lambda {cmd args} {f pids} {\n"
1666 " if {$cmd eq \"pid\"} {\n"
1667 " return $pids\n"
 
 
 
1668 " }\n"
1669 " if {$cmd eq \"close\"} {\n"
1670 " $f close\n"
1671 "\n"
1672 " foreach p $pids { os.wait $p }\n"
1673 " return\n"
 
 
 
 
 
 
 
 
 
 
 
 
1674 " }\n"
1675 " tailcall $f $cmd {*}$args\n"
1676 " }\n"
1677 " } on error {error opts} {\n"
1678 " $r close\n"
@@ -1692,14 +1812,10 @@
1692 " if {[catch {$channelId pid} pids]} {\n"
1693 " return \"\"\n"
1694 " }\n"
1695 " return $pids\n"
1696 "}\n"
1697 "\n"
1698 "\n"
1699 "\n"
1700 "\n"
1701 "\n"
1702 "\n"
1703 "\n"
1704 "\n"
1705 "\n"
@@ -1780,10 +1896,13 @@
1780 "}\n"
1781 );
1782 }
1783
1784
 
 
 
1785 #include <stdio.h>
1786 #include <string.h>
1787 #include <errno.h>
1788 #include <fcntl.h>
1789 #ifdef HAVE_UNISTD_H
@@ -1793,27 +1912,34 @@
1793
1794
1795 #if defined(HAVE_SYS_SOCKET_H) && defined(HAVE_SELECT) && defined(HAVE_NETINET_IN_H) && defined(HAVE_NETDB_H) && defined(HAVE_ARPA_INET_H)
1796 #include <sys/socket.h>
1797 #include <netinet/in.h>
 
1798 #include <arpa/inet.h>
1799 #include <netdb.h>
1800 #ifdef HAVE_SYS_UN_H
1801 #include <sys/un.h>
1802 #endif
 
 
 
1803 #else
1804 #define JIM_ANSIC
1805 #endif
1806
1807 #if defined(JIM_SSL)
1808 #include <openssl/ssl.h>
1809 #include <openssl/err.h>
1810 #endif
1811
 
 
1812
1813 #define AIO_CMD_LEN 32
1814 #define AIO_BUF_LEN 256
 
1815
1816 #ifndef HAVE_FTELLO
1817 #define ftello ftell
1818 #endif
1819 #ifndef HAVE_FSEEKO
@@ -1829,11 +1955,15 @@
1829 #ifndef PF_INET6
1830 #define PF_INET6 0
1831 #endif
1832 #endif
1833
1834 #define JimCheckStreamError(interp, af) af->fops->error(af)
 
 
 
 
1835
1836
1837 struct AioFile;
1838
1839 typedef struct {
@@ -1848,11 +1978,11 @@
1848 typedef struct AioFile
1849 {
1850 FILE *fp;
1851 Jim_Obj *filename;
1852 int type;
1853 int openFlags;
1854 int fd;
1855 Jim_Obj *rEvent;
1856 Jim_Obj *wEvent;
1857 Jim_Obj *eEvent;
1858 int addr_family;
@@ -1879,21 +2009,21 @@
1879 {
1880 if (!ferror(af->fp)) {
1881 return JIM_OK;
1882 }
1883 clearerr(af->fp);
1884
1885 if (feof(af->fp) || errno == EAGAIN || errno == EINTR) {
1886 return JIM_OK;
1887 }
1888 #ifdef ECONNRESET
1889 if (errno == ECONNRESET) {
1890 return JIM_OK;
1891 }
1892 #endif
1893 #ifdef ECONNABORTED
1894 if (errno != ECONNABORTED) {
1895 return JIM_OK;
1896 }
1897 #endif
1898 return JIM_ERR;
1899 }
@@ -1935,10 +2065,19 @@
1935 }
1936 else {
1937 Jim_SetResultString(interp, JimAioErrorString(af), -1);
1938 }
1939 }
 
 
 
 
 
 
 
 
 
1940
1941 static void JimAioDelProc(Jim_Interp *interp, void *privData)
1942 {
1943 AioFile *af = privData;
1944
@@ -1945,20 +2084,19 @@
1945 JIM_NOTUSED(interp);
1946
1947 Jim_DecrRefCount(interp, af->filename);
1948
1949 #ifdef jim_ext_eventloop
1950
1951 Jim_DeleteFileHandler(interp, af->fp, JIM_EVENT_READABLE | JIM_EVENT_WRITABLE | JIM_EVENT_EXCEPTION);
1952 #endif
1953
1954 #if defined(JIM_SSL)
1955 if (af->ssl != NULL) {
1956 SSL_free(af->ssl);
1957 }
1958 #endif
1959
1960 if (!(af->openFlags & AIO_KEEPOPEN)) {
1961 fclose(af->fp);
1962 }
1963
1964 Jim_Free(af);
@@ -1968,11 +2106,11 @@
1968 {
1969 AioFile *af = Jim_CmdPrivData(interp);
1970 char buf[AIO_BUF_LEN];
1971 Jim_Obj *objPtr;
1972 int nonewline = 0;
1973 jim_wide neededLen = -1;
1974
1975 if (argc && Jim_CompareStringImmediate(interp, argv[0], "-nonewline")) {
1976 nonewline = 1;
1977 argv++;
1978 argc--;
@@ -2007,11 +2145,11 @@
2007 }
2008 }
2009 if (retval != readlen)
2010 break;
2011 }
2012
2013 if (JimCheckStreamError(interp, af)) {
2014 Jim_FreeNewObj(interp, objPtr);
2015 return JIM_ERR;
2016 }
2017 if (nonewline) {
@@ -2029,11 +2167,11 @@
2029
2030 AioFile *Jim_AioFile(Jim_Interp *interp, Jim_Obj *command)
2031 {
2032 Jim_Cmd *cmdPtr = Jim_GetCommand(interp, command, JIM_ERRMSG);
2033
2034
2035 if (cmdPtr && !cmdPtr->isproc && cmdPtr->u.native.cmdProc == JimAioSubCmdProc) {
2036 return (AioFile *) cmdPtr->u.native.privData;
2037 }
2038 Jim_SetResultFormatted(interp, "Not a filehandle: \"%#s\"", command);
2039 return NULL;
@@ -2048,10 +2186,20 @@
2048 return NULL;
2049 }
2050
2051 return af->fp;
2052 }
 
 
 
 
 
 
 
 
 
 
2053
2054 static int aio_cmd_copy(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
2055 {
2056 AioFile *af = Jim_CmdPrivData(interp);
2057 jim_wide count = 0;
@@ -2110,21 +2258,21 @@
2110 }
2111 else {
2112 len = strlen(buf);
2113
2114 if (len && (buf[len - 1] == '\n')) {
2115
2116 len--;
2117 }
2118
2119 Jim_AppendString(interp, objPtr, buf, len);
2120 break;
2121 }
2122 }
2123
2124 if (JimCheckStreamError(interp, af)) {
2125
2126 Jim_FreeNewObj(interp, objPtr);
2127 return JIM_ERR;
2128 }
2129
2130 if (argc) {
@@ -2134,11 +2282,11 @@
2134 }
2135
2136 len = Jim_Length(objPtr);
2137
2138 if (len == 0 && feof(af->fp)) {
2139
2140 len = -1;
2141 }
2142 Jim_SetResultInt(interp, len);
2143 }
2144 else {
@@ -2207,11 +2355,11 @@
2207 }
2208
2209 static int aio_cmd_close(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
2210 {
2211 if (argc == 3) {
2212 #if !defined(JIM_ANSIC) && defined(HAVE_SHUTDOWN)
2213 static const char * const options[] = { "r", "w", NULL };
2214 enum { OPT_R, OPT_W, };
2215 int option;
2216 AioFile *af = Jim_CmdPrivData(interp);
2217
@@ -2297,10 +2445,11 @@
2297 }
2298 Jim_SetResultInt(interp, (fmode & O_NONBLOCK) ? 1 : 0);
2299 return JIM_OK;
2300 }
2301 #endif
 
2302
2303 #ifdef HAVE_FSYNC
2304 static int aio_cmd_sync(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
2305 {
2306 AioFile *af = Jim_CmdPrivData(interp);
@@ -2364,33 +2513,33 @@
2364
2365 static int aio_eventinfo(Jim_Interp *interp, AioFile * af, unsigned mask, Jim_Obj **scriptHandlerObj,
2366 int argc, Jim_Obj * const *argv)
2367 {
2368 if (argc == 0) {
2369
2370 if (*scriptHandlerObj) {
2371 Jim_SetResult(interp, *scriptHandlerObj);
2372 }
2373 return JIM_OK;
2374 }
2375
2376 if (*scriptHandlerObj) {
2377
2378 Jim_DeleteFileHandler(interp, af->fp, mask);
2379 }
2380
2381
2382 if (Jim_Length(argv[0]) == 0) {
2383
2384 return JIM_OK;
2385 }
2386
2387
2388 Jim_IncrRefCount(argv[0]);
2389 *scriptHandlerObj = argv[0];
2390
2391 Jim_CreateFileHandler(interp, af->fp, mask,
2392 JimAioFileEventHandler, scriptHandlerObj, JimAioFileEventFinalizer);
2393
2394 return JIM_OK;
2395 }
2396
@@ -2414,136 +2563,145 @@
2414
2415 return aio_eventinfo(interp, af, JIM_EVENT_EXCEPTION, &af->eEvent, argc, argv);
2416 }
2417 #endif
2418
 
 
2419
2420 static const jim_subcmd_type aio_command_table[] = {
2421 { "read",
2422 "?-nonewline? ?len?",
2423 aio_cmd_read,
2424 0,
2425 2,
2426
2427 },
2428 { "copyto",
2429 "handle ?size?",
2430 aio_cmd_copy,
2431 1,
2432 2,
2433
 
 
 
 
 
 
 
2434 },
2435 { "gets",
2436 "?var?",
2437 aio_cmd_gets,
2438 0,
2439 1,
2440
2441 },
2442 { "puts",
2443 "?-nonewline? str",
2444 aio_cmd_puts,
2445 1,
2446 2,
2447
2448 },
2449 { "isatty",
2450 NULL,
2451 aio_cmd_isatty,
2452 0,
2453 0,
2454
2455 },
2456 { "flush",
2457 NULL,
2458 aio_cmd_flush,
2459 0,
2460 0,
2461
2462 },
2463 { "eof",
2464 NULL,
2465 aio_cmd_eof,
2466 0,
2467 0,
2468
2469 },
2470 { "close",
2471 "?r(ead)|w(rite)?",
2472 aio_cmd_close,
2473 0,
2474 1,
2475 JIM_MODFLAG_FULLARGV,
2476
2477 },
2478 { "seek",
2479 "offset ?start|current|end",
2480 aio_cmd_seek,
2481 1,
2482 2,
2483
2484 },
2485 { "tell",
2486 NULL,
2487 aio_cmd_tell,
2488 0,
2489 0,
2490
2491 },
2492 { "filename",
2493 NULL,
2494 aio_cmd_filename,
2495 0,
2496 0,
2497
2498 },
2499 #ifdef O_NDELAY
2500 { "ndelay",
2501 "?0|1?",
2502 aio_cmd_ndelay,
2503 0,
2504 1,
2505
2506 },
2507 #endif
2508 #ifdef HAVE_FSYNC
2509 { "sync",
2510 NULL,
2511 aio_cmd_sync,
2512 0,
2513 0,
2514
2515 },
2516 #endif
2517 { "buffering",
2518 "none|line|full",
2519 aio_cmd_buffering,
2520 1,
2521 1,
2522
2523 },
2524 #ifdef jim_ext_eventloop
2525 { "readable",
2526 "?readable-script?",
2527 aio_cmd_readable,
2528 0,
2529 1,
2530
2531 },
2532 { "writable",
2533 "?writable-script?",
2534 aio_cmd_writable,
2535 0,
2536 1,
2537
2538 },
2539 { "onexception",
2540 "?exception-script?",
2541 aio_cmd_onexception,
2542 0,
2543 1,
2544
2545 },
2546 #endif
2547 { NULL }
2548 };
2549
@@ -2566,11 +2724,11 @@
2566
2567 #ifdef jim_ext_tclcompat
2568 {
2569 const char *filename = Jim_String(argv[1]);
2570
2571
2572 if (*filename == '|') {
2573 Jim_Obj *evalObj[3];
2574
2575 evalObj[0] = Jim_NewStringObj(interp, "::popen", -1);
2576 evalObj[1] = Jim_NewStringObj(interp, filename + 1, -1);
@@ -2603,42 +2761,44 @@
2603 }
2604
2605 Jim_IncrRefCount(filename);
2606
2607 if (fh == NULL) {
2608 #if !defined(JIM_ANSIC)
2609 if (fd >= 0) {
 
2610 fh = fdopen(fd, mode);
 
2611 }
2612 else
2613 #endif
2614 fh = fopen(Jim_String(filename), mode);
2615
2616 if (fh == NULL) {
2617 JimAioSetError(interp, filename);
2618 #if !defined(JIM_ANSIC)
2619 if (fd >= 0) {
2620 close(fd);
2621 }
2622 #endif
2623 Jim_DecrRefCount(interp, filename);
2624 return NULL;
2625 }
2626 }
2627
2628
2629 af = Jim_Alloc(sizeof(*af));
2630 memset(af, 0, sizeof(*af));
2631 af->fp = fh;
2632 af->fd = fileno(fh);
2633 af->filename = filename;
 
 
 
2634 #ifdef FD_CLOEXEC
2635 if ((openFlags & AIO_KEEPOPEN) == 0) {
2636 (void)fcntl(af->fd, F_SETFD, FD_CLOEXEC);
2637 }
2638 #endif
2639 af->openFlags = openFlags;
2640 af->addr_family = family;
2641 af->fops = &stdio_fops;
2642 af->ssl = NULL;
2643
2644 Jim_CreateCommand(interp, buf, JimAioSubCmdProc, af, JimAioDelProc);
@@ -2653,72 +2813,45 @@
2653 const char *hdlfmt, int family, const char *mode[2])
2654 {
2655 if (JimMakeChannel(interp, NULL, p[0], filename, hdlfmt, family, mode[0])) {
2656 Jim_Obj *objPtr = Jim_NewListObj(interp, NULL, 0);
2657 Jim_ListAppendElement(interp, objPtr, Jim_GetResult(interp));
2658
2659 if (JimMakeChannel(interp, NULL, p[1], filename, hdlfmt, family, mode[1])) {
2660 Jim_ListAppendElement(interp, objPtr, Jim_GetResult(interp));
2661 Jim_SetResult(interp, objPtr);
2662 return JIM_OK;
2663 }
2664 }
2665
2666
2667 close(p[0]);
2668 close(p[1]);
2669 JimAioSetError(interp, NULL);
2670 return JIM_ERR;
2671 }
2672 #endif
2673
2674
2675 int Jim_MakeTempFile(Jim_Interp *interp, const char *template)
2676 {
2677 #ifdef HAVE_MKSTEMP
2678 int fd;
2679 mode_t mask;
2680 Jim_Obj *filenameObj;
2681
2682 if (template == NULL) {
2683 const char *tmpdir = getenv("TMPDIR");
2684 if (tmpdir == NULL || *tmpdir == '\0' || access(tmpdir, W_OK) != 0) {
2685 tmpdir = "/tmp/";
2686 }
2687 filenameObj = Jim_NewStringObj(interp, tmpdir, -1);
2688 if (tmpdir[0] && tmpdir[strlen(tmpdir) - 1] != '/') {
2689 Jim_AppendString(interp, filenameObj, "/", 1);
2690 }
2691 Jim_AppendString(interp, filenameObj, "tcl.tmp.XXXXXX", -1);
2692 }
2693 else {
2694 filenameObj = Jim_NewStringObj(interp, template, -1);
2695 }
2696
2697 #if defined(S_IRWXG) && defined(S_IRWXO)
2698 mask = umask(S_IXUSR | S_IRWXG | S_IRWXO);
2699 #else
2700
2701 mask = umask(S_IXUSR);
2702 #endif
2703
2704
2705 fd = mkstemp(filenameObj->bytes);
2706 umask(mask);
2707 if (fd < 0) {
2708 JimAioSetError(interp, filenameObj);
2709 Jim_FreeNewObj(interp, filenameObj);
2710 return -1;
2711 }
2712
2713 Jim_SetResult(interp, filenameObj);
2714 return fd;
2715 #else
2716 Jim_SetResultString(interp, "platform has no tempfile support", -1);
2717 return -1;
2718 #endif
2719 }
2720
2721
2722 int Jim_aioInit(Jim_Interp *interp)
2723 {
2724 if (Jim_PackageProvide(interp, "aio", "1.0", JIM_ERRMSG))
@@ -2727,15 +2860,18 @@
2727 #if defined(JIM_SSL)
2728 Jim_CreateCommand(interp, "load_ssl_certs", JimAioLoadSSLCertsCommand, NULL, NULL);
2729 #endif
2730
2731 Jim_CreateCommand(interp, "open", JimAioOpenCommand, NULL, NULL);
2732 #ifndef JIM_ANSIC
2733 Jim_CreateCommand(interp, "socket", JimAioSockCommand, NULL, NULL);
2734 #endif
 
 
 
2735
2736
2737 JimMakeChannel(interp, stdin, -1, NULL, "stdin", 0, "r");
2738 JimMakeChannel(interp, stdout, -1, NULL, "stdout", 0, "w");
2739 JimMakeChannel(interp, stderr, -1, NULL, "stderr", 0, "w");
2740
2741 return JIM_OK;
@@ -2813,12 +2949,12 @@
2813 #include <regex.h>
2814 #endif
2815
2816 static void FreeRegexpInternalRep(Jim_Interp *interp, Jim_Obj *objPtr)
2817 {
2818 regfree(objPtr->internalRep.regexpValue.compre);
2819 Jim_Free(objPtr->internalRep.regexpValue.compre);
2820 }
2821
2822 static const Jim_ObjType regexpObjType = {
2823 "regexp",
2824 FreeRegexpInternalRep,
@@ -2831,20 +2967,20 @@
2831 {
2832 regex_t *compre;
2833 const char *pattern;
2834 int ret;
2835
2836
2837 if (objPtr->typePtr == &regexpObjType &&
2838 objPtr->internalRep.regexpValue.compre && objPtr->internalRep.regexpValue.flags == flags) {
2839
2840 return objPtr->internalRep.regexpValue.compre;
2841 }
2842
2843
2844
2845
 
2846 pattern = Jim_String(objPtr);
2847 compre = Jim_Alloc(sizeof(regex_t));
2848
2849 if ((ret = regcomp(compre, pattern, REG_EXTENDED | flags)) != 0) {
2850 char buf[100];
@@ -2857,12 +2993,12 @@
2857 }
2858
2859 Jim_FreeIntRep(interp, objPtr);
2860
2861 objPtr->typePtr = &regexpObjType;
2862 objPtr->internalRep.regexpValue.flags = flags;
2863 objPtr->internalRep.regexpValue.compre = compre;
2864
2865 return compre;
2866 }
2867
2868 int Jim_RegexpCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
@@ -3001,11 +3137,11 @@
3001 }
3002
3003 num_matches++;
3004
3005 if (opt_all && !opt_inline) {
3006
3007 goto try_next_match;
3008 }
3009
3010
3011 j = 0;
@@ -3041,11 +3177,11 @@
3041
3042 if (opt_inline) {
3043 Jim_ListAppendElement(interp, resultListObj, resultObj);
3044 }
3045 else {
3046
3047 result = Jim_SetVariable(interp, argv[i], resultObj);
3048
3049 if (result != JIM_OK) {
3050 Jim_FreeObj(interp, resultObj);
3051 break;
@@ -3168,11 +3304,11 @@
3168
3169 source_str = Jim_GetString(argv[i + 1], &source_len);
3170 replace_str = Jim_GetString(argv[i + 2], &replace_len);
3171 varname = argv[i + 3];
3172
3173
3174 resultObj = Jim_NewStringObj(interp, "", 0);
3175
3176 if (offset) {
3177 if (offset < 0) {
3178 offset += source_len + 1;
@@ -3183,11 +3319,11 @@
3183 else if (offset < 0) {
3184 offset = 0;
3185 }
3186 }
3187
3188
3189 Jim_AppendString(interp, resultObj, source_str, offset);
3190
3191
3192 n = source_len - offset;
3193 p = source_str + offset;
@@ -3242,23 +3378,23 @@
3242 }
3243
3244 p += pmatch[0].rm_eo;
3245 n -= pmatch[0].rm_eo;
3246
3247
3248 if (!opt_all || n == 0) {
3249 break;
3250 }
3251
3252
3253 if ((regcomp_flags & REG_NEWLINE) == 0 && pattern[0] == '^') {
3254 break;
3255 }
3256
3257
3258 if (pattern[0] == '\0' && n) {
3259
3260 Jim_AppendString(interp, resultObj, p, 1);
3261 p++;
3262 n--;
3263 }
3264
@@ -3265,11 +3401,11 @@
3265 regexec_flags |= REG_NOTBOL;
3266 } while (n);
3267
3268 Jim_AppendString(interp, resultObj, p, -1);
3269
3270
3271 if (argc - i == 4) {
3272 result = Jim_SetVariable(interp, varname, resultObj);
3273
3274 if (result == JIM_OK) {
3275 Jim_SetResultInt(interp, num_matches);
@@ -3320,16 +3456,23 @@
3320
3321 # ifndef MAXPATHLEN
3322 # define MAXPATHLEN JIM_PATH_LEN
3323 # endif
3324
3325 #if defined(__MINGW32__) || defined(_MSC_VER)
3326 #define ISWINDOWS 1
3327 #else
3328 #define ISWINDOWS 0
3329 #endif
3330
 
 
 
 
 
 
 
3331
3332 static const char *JimGetFileType(int mode)
3333 {
3334 if (S_ISREG(mode)) {
3335 return "file";
@@ -3371,11 +3514,11 @@
3371 Jim_ListAppendElement(interp, listObj, Jim_NewIntObj(interp, value));
3372 }
3373
3374 static int StoreStatData(Jim_Interp *interp, Jim_Obj *varName, const struct stat *sb)
3375 {
3376
3377 Jim_Obj *listObj = Jim_NewListObj(interp, NULL, 0);
3378
3379 AppendStatElement(interp, listObj, "dev", sb->st_dev);
3380 AppendStatElement(interp, listObj, "ino", sb->st_ino);
3381 AppendStatElement(interp, listObj, "mode", sb->st_mode);
@@ -3384,39 +3527,44 @@
3384 AppendStatElement(interp, listObj, "gid", sb->st_gid);
3385 AppendStatElement(interp, listObj, "size", sb->st_size);
3386 AppendStatElement(interp, listObj, "atime", sb->st_atime);
3387 AppendStatElement(interp, listObj, "mtime", sb->st_mtime);
3388 AppendStatElement(interp, listObj, "ctime", sb->st_ctime);
 
 
 
3389 Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, "type", -1));
3390 Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, JimGetFileType((int)sb->st_mode), -1));
3391
3392
3393 if (varName) {
3394 Jim_Obj *objPtr = Jim_GetVariable(interp, varName, JIM_NONE);
 
 
3395 if (objPtr) {
3396 if (Jim_DictSize(interp, objPtr) < 0) {
3397
 
 
 
 
 
 
3398 Jim_SetResultFormatted(interp, "can't set \"%#s(dev)\": variable isn't array", varName);
3399 Jim_FreeNewObj(interp, listObj);
3400 return JIM_ERR;
3401 }
3402
3403 if (Jim_IsShared(objPtr))
3404 objPtr = Jim_DuplicateObj(interp, objPtr);
3405
3406
3407 Jim_ListAppendList(interp, objPtr, listObj);
3408 Jim_DictSize(interp, objPtr);
3409 Jim_InvalidateStringRep(objPtr);
3410
3411 Jim_FreeNewObj(interp, listObj);
3412 listObj = objPtr;
3413 }
3414 Jim_SetVariable(interp, varName, listObj);
3415 }
3416
3417
3418 Jim_SetResult(interp, listObj);
3419
3420 return JIM_OK;
3421 }
3422
@@ -3432,11 +3580,11 @@
3432 }
3433 else if (p == path) {
3434 Jim_SetResultString(interp, "/", -1);
3435 }
3436 else if (ISWINDOWS && p[-1] == ':') {
3437
3438 Jim_SetResultString(interp, path, p - path + 1);
3439 }
3440 else {
3441 Jim_SetResultString(interp, path, p - path);
3442 }
@@ -3512,35 +3660,35 @@
3512 char *newname = Jim_Alloc(MAXPATHLEN + 1);
3513 char *last = newname;
3514
3515 *newname = 0;
3516
3517
3518 for (i = 0; i < argc; i++) {
3519 int len;
3520 const char *part = Jim_GetString(argv[i], &len);
3521
3522 if (*part == '/') {
3523
3524 last = newname;
3525 }
3526 else if (ISWINDOWS && strchr(part, ':')) {
3527
3528 last = newname;
3529 }
3530 else if (part[0] == '.') {
3531 if (part[1] == '/') {
3532 part += 2;
3533 len -= 2;
3534 }
3535 else if (part[1] == 0 && last != newname) {
3536
3537 continue;
3538 }
3539 }
3540
3541
3542 if (last != newname && last[-1] != '/') {
3543 *last++ = '/';
3544 }
3545
3546 if (len) {
@@ -3551,22 +3699,22 @@
3551 }
3552 memcpy(last, part, len);
3553 last += len;
3554 }
3555
3556
3557 if (last > newname + 1 && last[-1] == '/') {
3558
3559 if (!ISWINDOWS || !(last > newname + 2 && last[-2] == ':')) {
3560 *--last = 0;
3561 }
3562 }
3563 }
3564
3565 *last = 0;
3566
3567
3568
3569 Jim_SetResult(interp, Jim_NewStringObjNoAlloc(interp, newname, last - newname));
3570
3571 return JIM_OK;
3572 }
@@ -3591,11 +3739,11 @@
3591 static int file_cmd_executable(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
3592 {
3593 #ifdef X_OK
3594 return file_access(interp, argv[0], X_OK);
3595 #else
3596
3597 Jim_SetResultBool(interp, 1);
3598 return JIM_OK;
3599 #endif
3600 }
3601
@@ -3616,11 +3764,11 @@
3616 while (argc--) {
3617 const char *path = Jim_String(argv[0]);
3618
3619 if (unlink(path) == -1 && errno != ENOENT) {
3620 if (rmdir(path) == -1) {
3621
3622 if (!force || Jim_EvalPrefix(interp, "file delete force", 1, argv) != JIM_OK) {
3623 Jim_SetResultFormatted(interp, "couldn't delete file \"%s\": %s", path,
3624 strerror(errno));
3625 return JIM_ERR;
3626 }
@@ -3639,15 +3787,15 @@
3639
3640 static int mkdir_all(char *path)
3641 {
3642 int ok = 1;
3643
3644
3645 goto first;
3646
3647 while (ok--) {
3648
3649 {
3650 char *slash = strrchr(path, '/');
3651
3652 if (slash && slash != path) {
3653 *slash = 0;
@@ -3660,24 +3808,24 @@
3660 first:
3661 if (MKDIR_DEFAULT(path) == 0) {
3662 return 0;
3663 }
3664 if (errno == ENOENT) {
3665
3666 continue;
3667 }
3668
3669 if (errno == EEXIST) {
3670 struct stat sb;
3671
3672 if (stat(path, &sb) == 0 && S_ISDIR(sb.st_mode)) {
3673 return 0;
3674 }
3675
3676 errno = EEXIST;
3677 }
3678
3679 break;
3680 }
3681 return -1;
3682 }
3683
@@ -3698,11 +3846,11 @@
3698 return JIM_OK;
3699 }
3700
3701 static int file_cmd_tempfile(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
3702 {
3703 int fd = Jim_MakeTempFile(interp, (argc >= 1) ? Jim_String(argv[0]) : NULL);
3704
3705 if (fd < 0) {
3706 return JIM_ERR;
3707 }
3708 close(fd);
@@ -3815,42 +3963,67 @@
3815 return JIM_ERR;
3816 }
3817 Jim_SetResultInt(interp, sb.st_atime);
3818 return JIM_OK;
3819 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3820
3821 static int file_cmd_mtime(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
3822 {
3823 struct stat sb;
3824
3825 if (argc == 2) {
3826 #ifdef HAVE_UTIMES
3827 jim_wide newtime;
3828 struct timeval times[2];
3829
3830 if (Jim_GetWide(interp, argv[1], &newtime) != JIM_OK) {
3831 return JIM_ERR;
3832 }
3833
3834 times[1].tv_sec = times[0].tv_sec = newtime;
3835 times[1].tv_usec = times[0].tv_usec = 0;
3836
3837 if (utimes(Jim_String(argv[0]), times) != 0) {
3838 Jim_SetResultFormatted(interp, "can't set time on \"%#s\": %s", argv[0], strerror(errno));
3839 return JIM_ERR;
3840 }
3841 #else
3842 Jim_SetResultString(interp, "Not implemented", -1);
3843 return JIM_ERR;
3844 #endif
3845 }
3846 if (file_stat(interp, argv[0], &sb) != JIM_OK) {
3847 return JIM_ERR;
3848 }
3849 Jim_SetResultInt(interp, sb.st_mtime);
3850 return JIM_OK;
3851 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3852
3853 static int file_cmd_copy(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
3854 {
3855 return Jim_EvalPrefix(interp, "file copy", argc, argv);
3856 }
@@ -3962,192 +4135,201 @@
3962 { "atime",
3963 "name",
3964 file_cmd_atime,
3965 1,
3966 1,
3967
3968 },
3969 { "mtime",
3970 "name ?time?",
3971 file_cmd_mtime,
3972 1,
3973 2,
3974
 
 
 
 
 
 
 
 
3975 },
 
3976 { "copy",
3977 "?-force? source dest",
3978 file_cmd_copy,
3979 2,
3980 3,
3981
3982 },
3983 { "dirname",
3984 "name",
3985 file_cmd_dirname,
3986 1,
3987 1,
3988
3989 },
3990 { "rootname",
3991 "name",
3992 file_cmd_rootname,
3993 1,
3994 1,
3995
3996 },
3997 { "extension",
3998 "name",
3999 file_cmd_extension,
4000 1,
4001 1,
4002
4003 },
4004 { "tail",
4005 "name",
4006 file_cmd_tail,
4007 1,
4008 1,
4009
4010 },
4011 { "normalize",
4012 "name",
4013 file_cmd_normalize,
4014 1,
4015 1,
4016
4017 },
4018 { "join",
4019 "name ?name ...?",
4020 file_cmd_join,
4021 1,
4022 -1,
4023
4024 },
4025 { "readable",
4026 "name",
4027 file_cmd_readable,
4028 1,
4029 1,
4030
4031 },
4032 { "writable",
4033 "name",
4034 file_cmd_writable,
4035 1,
4036 1,
4037
4038 },
4039 { "executable",
4040 "name",
4041 file_cmd_executable,
4042 1,
4043 1,
4044
4045 },
4046 { "exists",
4047 "name",
4048 file_cmd_exists,
4049 1,
4050 1,
4051
4052 },
4053 { "delete",
4054 "?-force|--? name ...",
4055 file_cmd_delete,
4056 1,
4057 -1,
4058
4059 },
4060 { "mkdir",
4061 "dir ...",
4062 file_cmd_mkdir,
4063 1,
4064 -1,
4065
4066 },
4067 { "tempfile",
4068 "?template?",
4069 file_cmd_tempfile,
4070 0,
4071 1,
4072
4073 },
4074 { "rename",
4075 "?-force? source dest",
4076 file_cmd_rename,
4077 2,
4078 3,
4079
4080 },
4081 #if defined(HAVE_LINK) && defined(HAVE_SYMLINK)
4082 { "link",
4083 "?-symbolic|-hard? newname target",
4084 file_cmd_link,
4085 2,
4086 3,
4087
4088 },
4089 #endif
4090 #if defined(HAVE_READLINK)
4091 { "readlink",
4092 "name",
4093 file_cmd_readlink,
4094 1,
4095 1,
4096
4097 },
4098 #endif
4099 { "size",
4100 "name",
4101 file_cmd_size,
4102 1,
4103 1,
4104
4105 },
4106 { "stat",
4107 "name ?var?",
4108 file_cmd_stat,
4109 1,
4110 2,
4111
4112 },
4113 { "lstat",
4114 "name ?var?",
4115 file_cmd_lstat,
4116 1,
4117 2,
4118
4119 },
4120 { "type",
4121 "name",
4122 file_cmd_type,
4123 1,
4124 1,
4125
4126 },
4127 #ifdef HAVE_GETEUID
4128 { "owned",
4129 "name",
4130 file_cmd_owned,
4131 1,
4132 1,
4133
4134 },
4135 #endif
4136 { "isdirectory",
4137 "name",
4138 file_cmd_isdirectory,
4139 1,
4140 1,
4141
4142 },
4143 { "isfile",
4144 "name",
4145 file_cmd_isfile,
4146 1,
4147 1,
4148
4149 },
4150 {
4151 NULL
4152 }
4153 };
@@ -4179,11 +4361,11 @@
4179 Jim_SetResultString(interp, "Failed to get pwd", -1);
4180 Jim_Free(cwd);
4181 return JIM_ERR;
4182 }
4183 else if (ISWINDOWS) {
4184
4185 char *p = cwd;
4186 while ((p = strchr(p, '\\')) != NULL) {
4187 *p++ = '/';
4188 }
4189 }
@@ -4203,10 +4385,13 @@
4203 Jim_CreateCommand(interp, "pwd", Jim_PwdCmd, NULL, NULL);
4204 Jim_CreateCommand(interp, "cd", Jim_CdCmd, NULL, NULL);
4205 return JIM_OK;
4206 }
4207
 
 
 
4208 #include <string.h>
4209 #include <ctype.h>
4210
4211
4212 #if (!defined(HAVE_VFORK) || !defined(HAVE_WAITPID)) && !defined(__MINGW32__)
@@ -4214,20 +4399,20 @@
4214 {
4215 Jim_Obj *cmdlineObj = Jim_NewEmptyStringObj(interp);
4216 int i, j;
4217 int rc;
4218
4219
4220 for (i = 1; i < argc; i++) {
4221 int len;
4222 const char *arg = Jim_GetString(argv[i], &len);
4223
4224 if (i > 1) {
4225 Jim_AppendString(interp, cmdlineObj, " ", 1);
4226 }
4227 if (strpbrk(arg, "\\\" ") == NULL) {
4228
4229 Jim_AppendString(interp, cmdlineObj, arg, len);
4230 continue;
4231 }
4232
4233 Jim_AppendString(interp, cmdlineObj, "\"", 1);
@@ -4266,86 +4451,26 @@
4266 #else
4267
4268
4269 #include <errno.h>
4270 #include <signal.h>
4271
4272 #if defined(__MINGW32__)
4273
4274 #ifndef STRICT
4275 #define STRICT
4276 #endif
4277 #define WIN32_LEAN_AND_MEAN
4278 #include <windows.h>
4279 #include <fcntl.h>
4280
4281 typedef HANDLE fdtype;
4282 typedef HANDLE pidtype;
4283 #define JIM_BAD_FD INVALID_HANDLE_VALUE
4284 #define JIM_BAD_PID INVALID_HANDLE_VALUE
4285 #define JimCloseFd CloseHandle
4286
4287 #define WIFEXITED(STATUS) 1
4288 #define WEXITSTATUS(STATUS) (STATUS)
4289 #define WIFSIGNALED(STATUS) 0
4290 #define WTERMSIG(STATUS) 0
4291 #define WNOHANG 1
4292
4293 static fdtype JimFileno(FILE *fh);
4294 static pidtype JimWaitPid(pidtype pid, int *status, int nohang);
4295 static fdtype JimDupFd(fdtype infd);
4296 static fdtype JimOpenForRead(const char *filename);
4297 static FILE *JimFdOpenForRead(fdtype fd);
4298 static int JimPipe(fdtype pipefd[2]);
4299 static pidtype JimStartWinProcess(Jim_Interp *interp, char **argv, char *env,
4300 fdtype inputId, fdtype outputId, fdtype errorId);
4301 static int JimErrno(void);
4302 #else
4303 #include <unistd.h>
4304 #include <fcntl.h>
4305 #include <sys/wait.h>
4306 #include <sys/stat.h>
4307
4308 typedef int fdtype;
4309 typedef int pidtype;
4310 #define JimPipe pipe
4311 #define JimErrno() errno
4312 #define JIM_BAD_FD -1
4313 #define JIM_BAD_PID -1
4314 #define JimFileno fileno
4315 #define JimReadFd read
4316 #define JimCloseFd close
4317 #define JimWaitPid waitpid
4318 #define JimDupFd dup
4319 #define JimFdOpenForRead(FD) fdopen((FD), "r")
4320 #define JimOpenForRead(NAME) open((NAME), O_RDONLY, 0)
4321
4322 #ifndef HAVE_EXECVPE
4323 #define execvpe(ARG0, ARGV, ENV) execvp(ARG0, ARGV)
4324 #endif
4325 #endif
4326
4327 static const char *JimStrError(void);
4328 static char **JimSaveEnv(char **env);
4329 static void JimRestoreEnv(char **env);
4330 static int JimCreatePipeline(Jim_Interp *interp, int argc, Jim_Obj *const *argv,
4331 pidtype **pidArrayPtr, fdtype *inPipePtr, fdtype *outPipePtr, fdtype *errFilePtr);
4332 static void JimDetachPids(Jim_Interp *interp, int numPids, const pidtype *pidPtr);
4333 static int JimCleanupChildren(Jim_Interp *interp, int numPids, pidtype *pidPtr, Jim_Obj *errStrObj);
4334 static fdtype JimCreateTemp(Jim_Interp *interp, const char *contents, int len);
4335 static fdtype JimOpenForWrite(const char *filename, int append);
4336 static int JimRewindFd(fdtype fd);
4337
4338 static void Jim_SetResultErrno(Jim_Interp *interp, const char *msg)
4339 {
4340 Jim_SetResultFormatted(interp, "%s: %s", msg, JimStrError());
4341 }
4342
4343 static const char *JimStrError(void)
4344 {
4345 return strerror(JimErrno());
4346 }
4347
4348 static void Jim_RemoveTrailingNewline(Jim_Obj *objPtr)
4349 {
4350 int len;
4351 const char *s = Jim_GetString(objPtr, &len);
@@ -4354,14 +4479,14 @@
4354 objPtr->length--;
4355 objPtr->bytes[objPtr->length] = '\0';
4356 }
4357 }
4358
4359 static int JimAppendStreamToString(Jim_Interp *interp, fdtype fd, Jim_Obj *strObj)
4360 {
4361 char buf[256];
4362 FILE *fh = JimFdOpenForRead(fd);
4363 int ret = 0;
4364
4365 if (fh == NULL) {
4366 return -1;
4367 }
@@ -4390,18 +4515,18 @@
4390 char *envdata;
4391
4392 Jim_Obj *objPtr = Jim_GetGlobalVariableStr(interp, "env", JIM_NONE);
4393
4394 if (!objPtr) {
4395 return Jim_GetEnviron();
4396 }
4397
4398
4399
4400 num = Jim_ListLength(interp, objPtr);
4401 if (num % 2) {
4402
4403 num--;
4404 }
4405 size = Jim_Length(objPtr) + 2;
4406
4407 envptr = Jim_Alloc(sizeof(*envptr) * (num / 2 + 1) + size);
@@ -4433,79 +4558,76 @@
4433 if (env != original_environ) {
4434 Jim_Free(env);
4435 }
4436 }
4437
4438 #ifndef jim_ext_signal
4439
4440 const char *Jim_SignalId(int sig)
4441 {
4442 static char buf[10];
4443 snprintf(buf, sizeof(buf), "%d", sig);
4444 return buf;
4445 }
4446
4447 const char *Jim_SignalName(int sig)
4448 {
4449 return Jim_SignalId(sig);
4450 }
4451 #endif
4452
4453 static int JimCheckWaitStatus(Jim_Interp *interp, pidtype pid, int waitStatus, Jim_Obj *errStrObj)
4454 {
4455 Jim_Obj *errorCode;
4456
4457 if (WIFEXITED(waitStatus) && WEXITSTATUS(waitStatus) == 0) {
4458 return JIM_OK;
4459 }
4460 errorCode = Jim_NewListObj(interp, NULL, 0);
4461
4462 if (WIFEXITED(waitStatus)) {
4463 Jim_ListAppendElement(interp, errorCode, Jim_NewStringObj(interp, "CHILDSTATUS", -1));
4464 Jim_ListAppendElement(interp, errorCode, Jim_NewIntObj(interp, (long)pid));
4465 Jim_ListAppendElement(interp, errorCode, Jim_NewIntObj(interp, WEXITSTATUS(waitStatus)));
4466 }
4467 else {
4468 const char *type;
4469 const char *action;
 
4470
4471 if (WIFSIGNALED(waitStatus)) {
4472 type = "CHILDKILLED";
4473 action = "killed";
 
4474 }
4475 else {
4476 type = "CHILDSUSP";
4477 action = "suspended";
 
4478 }
4479
4480 Jim_ListAppendElement(interp, errorCode, Jim_NewStringObj(interp, type, -1));
4481
4482 if (errStrObj) {
4483 Jim_AppendStrings(interp, errStrObj, "child ", action, " by signal ", Jim_SignalId(WTERMSIG(waitStatus)), "\n", NULL);
4484 }
4485
4486 Jim_ListAppendElement(interp, errorCode, Jim_NewIntObj(interp, (long)pid));
4487 Jim_ListAppendElement(interp, errorCode, Jim_NewStringObj(interp, Jim_SignalId(WTERMSIG(waitStatus)), -1));
4488 Jim_ListAppendElement(interp, errorCode, Jim_NewStringObj(interp, Jim_SignalName(WTERMSIG(waitStatus)), -1));
4489 }
4490 Jim_SetGlobalVariableStr(interp, "errorCode", errorCode);
 
 
 
 
 
 
 
 
4491
4492 return JIM_ERR;
4493 }
4494
4495
4496 struct WaitInfo
4497 {
4498 pidtype pid;
4499 int status;
4500 int flags;
4501 };
 
4502
4503 struct WaitInfoTable {
4504 struct WaitInfo *info;
4505 int size;
4506 int used;
 
4507 };
4508
4509
4510 #define WI_DETACHED 2
4511
@@ -4513,32 +4635,53 @@
4513
4514 static void JimFreeWaitInfoTable(struct Jim_Interp *interp, void *privData)
4515 {
4516 struct WaitInfoTable *table = privData;
4517
4518 Jim_Free(table->info);
4519 Jim_Free(table);
 
 
4520 }
4521
4522 static struct WaitInfoTable *JimAllocWaitInfoTable(void)
4523 {
4524 struct WaitInfoTable *table = Jim_Alloc(sizeof(*table));
4525 table->info = NULL;
4526 table->size = table->used = 0;
 
4527
4528 return table;
4529 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4530
4531 static int Jim_ExecCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
4532 {
4533 fdtype outputId;
4534 fdtype errorId;
4535 pidtype *pidPtr;
4536 int numPids, result;
4537 int child_siginfo = 1;
4538 Jim_Obj *childErrObj;
4539 Jim_Obj *errStrObj;
 
4540
4541 if (argc > 1 && Jim_CompareStringImmediate(interp, argv[argc - 1], "&")) {
4542 Jim_Obj *listObj;
4543 int i;
4544
@@ -4545,17 +4688,17 @@
4545 argc--;
4546 numPids = JimCreatePipeline(interp, argc - 1, argv + 1, &pidPtr, NULL, NULL, NULL);
4547 if (numPids < 0) {
4548 return JIM_ERR;
4549 }
4550
4551 listObj = Jim_NewListObj(interp, NULL, 0);
4552 for (i = 0; i < numPids; i++) {
4553 Jim_ListAppendElement(interp, listObj, Jim_NewIntObj(interp, (long)pidPtr[i]));
4554 }
4555 Jim_SetResult(interp, listObj);
4556 JimDetachPids(interp, numPids, pidPtr);
4557 Jim_Free(pidPtr);
4558 return JIM_OK;
4559 }
4560
4561 numPids =
@@ -4567,54 +4710,98 @@
4567
4568 result = JIM_OK;
4569
4570 errStrObj = Jim_NewStringObj(interp, "", 0);
4571
4572
4573 if (outputId != JIM_BAD_FD) {
4574 if (JimAppendStreamToString(interp, outputId, errStrObj) < 0) {
4575 result = JIM_ERR;
4576 Jim_SetResultErrno(interp, "error reading from output pipe");
4577 }
4578 }
4579
4580
4581 childErrObj = Jim_NewStringObj(interp, "", 0);
4582 Jim_IncrRefCount(childErrObj);
4583
4584 if (JimCleanupChildren(interp, numPids, pidPtr, childErrObj) != JIM_OK) {
4585 result = JIM_ERR;
4586 }
4587
4588 if (errorId != JIM_BAD_FD) {
4589 int ret;
4590 JimRewindFd(errorId);
4591 ret = JimAppendStreamToString(interp, errorId, errStrObj);
4592 if (ret < 0) {
4593 Jim_SetResultErrno(interp, "error reading from error pipe");
4594 result = JIM_ERR;
4595 }
4596 else if (ret > 0) {
4597
4598 child_siginfo = 0;
4599 }
4600 }
4601
4602 if (child_siginfo) {
4603
4604 Jim_AppendObj(interp, errStrObj, childErrObj);
4605 }
4606 Jim_DecrRefCount(interp, childErrObj);
4607
4608
4609 Jim_RemoveTrailingNewline(errStrObj);
4610
4611
4612 Jim_SetResult(interp, errStrObj);
4613
4614 return result;
4615 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4616
4617 static void JimReapDetachedPids(struct WaitInfoTable *table)
4618 {
4619 struct WaitInfo *waitPtr;
4620 int count;
@@ -4627,13 +4814,13 @@
4627 waitPtr = table->info;
4628 dest = 0;
4629 for (count = table->used; count > 0; waitPtr++, count--) {
4630 if (waitPtr->flags & WI_DETACHED) {
4631 int status;
4632 pidtype pid = JimWaitPid(waitPtr->pid, &status, WNOHANG);
4633 if (pid == waitPtr->pid) {
4634
4635 table->used--;
4636 continue;
4637 }
4638 }
4639 if (waitPtr != &table->info[dest]) {
@@ -4641,66 +4828,62 @@
4641 }
4642 dest++;
4643 }
4644 }
4645
4646 static pidtype JimWaitForProcess(struct WaitInfoTable *table, pidtype pid, int *statusPtr)
4647 {
4648 int i;
4649
4650
4651 for (i = 0; i < table->used; i++) {
4652 if (pid == table->info[i].pid) {
4653
4654 JimWaitPid(pid, statusPtr, 0);
4655
4656
4657 if (i != table->used - 1) {
4658 table->info[i] = table->info[table->used - 1];
4659 }
4660 table->used--;
4661 return pid;
4662 }
4663 }
4664
4665
4666 return JIM_BAD_PID;
4667 }
4668
4669 static void JimDetachPids(Jim_Interp *interp, int numPids, const pidtype *pidPtr)
4670 {
4671 int j;
4672 struct WaitInfoTable *table = Jim_CmdPrivData(interp);
4673
4674 for (j = 0; j < numPids; j++) {
4675
4676 int i;
4677 for (i = 0; i < table->used; i++) {
4678 if (pidPtr[j] == table->info[i].pid) {
4679 table->info[i].flags |= WI_DETACHED;
4680 break;
4681 }
4682 }
4683 }
4684 }
4685
4686 static FILE *JimGetAioFilehandle(Jim_Interp *interp, const char *name)
4687 {
4688 FILE *fh;
4689 Jim_Obj *fhObj;
4690
4691 fhObj = Jim_NewStringObj(interp, name, -1);
4692 Jim_IncrRefCount(fhObj);
4693 fh = Jim_AioFilehandle(interp, fhObj);
4694 Jim_DecrRefCount(interp, fhObj);
4695
4696 return fh;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4697 }
4698
4699 static int
4700 JimCreatePipeline(Jim_Interp *interp, int argc, Jim_Obj *const *argv, pidtype **pidArrayPtr,
4701 fdtype *inPipePtr, fdtype *outPipePtr, fdtype *errFilePtr)
4702 {
4703 pidtype *pidPtr = NULL; /* Points to malloc-ed array holding all
4704 * the pids of child processes. */
4705 int numPids = 0; /* Actual number of processes that exist
4706 * at *pidPtr right now. */
@@ -4707,16 +4890,16 @@
4707 int cmdCount; /* Count of number of distinct commands
4708 * found in argc/argv. */
4709 const char *input = NULL; /* Describes input for pipeline, depending
4710 * on "inputFile". NULL means take input
4711 * from stdin/pipe. */
4712 int input_len = 0;
4713
4714 #define FILE_NAME 0
4715 #define FILE_APPEND 1
4716 #define FILE_HANDLE 2
4717 #define FILE_TEXT 3
4718
4719 int inputFile = FILE_NAME; /* 1 means input is name of input file.
4720 * 2 means input is filehandle name.
4721 * 0 means input holds actual
4722 * text to be input to command. */
@@ -4733,39 +4916,40 @@
4733 */
4734 const char *output = NULL; /* Holds name of output file to pipe to,
4735 * or NULL if output goes to stdout/pipe. */
4736 const char *error = NULL; /* Holds name of stderr file to pipe to,
4737 * or NULL if stderr goes to stderr/pipe. */
4738 fdtype inputId = JIM_BAD_FD;
4739 fdtype outputId = JIM_BAD_FD;
4740 fdtype errorId = JIM_BAD_FD;
4741 fdtype lastOutputId = JIM_BAD_FD;
4742 fdtype pipeIds[2];
4743 int firstArg, lastArg; /* Indexes of first and last arguments in
4744 * current command. */
4745 int lastBar;
4746 int i;
4747 pidtype pid;
4748 char **save_environ;
 
 
 
4749 struct WaitInfoTable *table = Jim_CmdPrivData(interp);
4750
4751
4752 char **arg_array = Jim_Alloc(sizeof(*arg_array) * (argc + 1));
4753 int arg_count = 0;
4754
4755 JimReapDetachedPids(table);
4756
4757 if (inPipePtr != NULL) {
4758 *inPipePtr = JIM_BAD_FD;
4759 }
4760 if (outPipePtr != NULL) {
4761 *outPipePtr = JIM_BAD_FD;
4762 }
4763 if (errFilePtr != NULL) {
4764 *errFilePtr = JIM_BAD_FD;
4765 }
4766 pipeIds[0] = pipeIds[1] = JIM_BAD_FD;
4767
4768 cmdCount = 1;
4769 lastBar = -1;
4770 for (i = 0; i < argc; i++) {
4771 const char *arg = Jim_String(argv[i]);
@@ -4796,11 +4980,11 @@
4796 if (*output == '>') {
4797 outputFile = FILE_APPEND;
4798 output++;
4799 }
4800 if (*output == '&') {
4801
4802 output++;
4803 dup_error = 1;
4804 }
4805 if (*output == '@') {
4806 outputFile = FILE_HANDLE;
@@ -4837,11 +5021,11 @@
4837 goto badargs;
4838 }
4839 lastBar = i;
4840 cmdCount++;
4841 }
4842
4843 arg_array[arg_count++] = (char *)arg;
4844 continue;
4845 }
4846
4847 if (i >= argc) {
@@ -4855,183 +5039,227 @@
4855 badargs:
4856 Jim_Free(arg_array);
4857 return -1;
4858 }
4859
4860
4861 save_environ = JimSaveEnv(JimBuildEnv(interp));
4862
4863 if (input != NULL) {
4864 if (inputFile == FILE_TEXT) {
4865 inputId = JimCreateTemp(interp, input, input_len);
4866 if (inputId == JIM_BAD_FD) {
 
 
 
 
 
4867 goto error;
4868 }
 
4869 }
4870 else if (inputFile == FILE_HANDLE) {
4871
4872 FILE *fh = JimGetAioFilehandle(interp, input);
4873
4874 if (fh == NULL) {
4875 goto error;
4876 }
4877 inputId = JimDupFd(JimFileno(fh));
4878 }
4879 else {
4880 inputId = JimOpenForRead(input);
4881 if (inputId == JIM_BAD_FD) {
4882 Jim_SetResultFormatted(interp, "couldn't read file \"%s\": %s", input, JimStrError());
4883 goto error;
4884 }
4885 }
4886 }
4887 else if (inPipePtr != NULL) {
4888 if (JimPipe(pipeIds) != 0) {
4889 Jim_SetResultErrno(interp, "couldn't create input pipe for command");
4890 goto error;
4891 }
4892 inputId = pipeIds[0];
4893 *inPipePtr = pipeIds[1];
4894 pipeIds[0] = pipeIds[1] = JIM_BAD_FD;
4895 }
4896
4897 if (output != NULL) {
4898 if (outputFile == FILE_HANDLE) {
4899 FILE *fh = JimGetAioFilehandle(interp, output);
4900 if (fh == NULL) {
4901 goto error;
4902 }
4903 fflush(fh);
4904 lastOutputId = JimDupFd(JimFileno(fh));
4905 }
4906 else {
4907 lastOutputId = JimOpenForWrite(output, outputFile == FILE_APPEND);
4908 if (lastOutputId == JIM_BAD_FD) {
4909 Jim_SetResultFormatted(interp, "couldn't write file \"%s\": %s", output, JimStrError());
4910 goto error;
4911 }
4912 }
4913 }
4914 else if (outPipePtr != NULL) {
4915 if (JimPipe(pipeIds) != 0) {
4916 Jim_SetResultErrno(interp, "couldn't create output pipe");
4917 goto error;
4918 }
4919 lastOutputId = pipeIds[1];
4920 *outPipePtr = pipeIds[0];
4921 pipeIds[0] = pipeIds[1] = JIM_BAD_FD;
4922 }
4923
4924 if (error != NULL) {
4925 if (errorFile == FILE_HANDLE) {
4926 if (strcmp(error, "1") == 0) {
4927
4928 if (lastOutputId != JIM_BAD_FD) {
4929 errorId = JimDupFd(lastOutputId);
4930 }
4931 else {
4932
4933 error = "stdout";
4934 }
4935 }
4936 if (errorId == JIM_BAD_FD) {
4937 FILE *fh = JimGetAioFilehandle(interp, error);
4938 if (fh == NULL) {
4939 goto error;
4940 }
4941 fflush(fh);
4942 errorId = JimDupFd(JimFileno(fh));
4943 }
4944 }
4945 else {
4946 errorId = JimOpenForWrite(error, errorFile == FILE_APPEND);
4947 if (errorId == JIM_BAD_FD) {
4948 Jim_SetResultFormatted(interp, "couldn't write file \"%s\": %s", error, JimStrError());
4949 goto error;
4950 }
4951 }
4952 }
4953 else if (errFilePtr != NULL) {
4954 errorId = JimCreateTemp(interp, NULL, 0);
4955 if (errorId == JIM_BAD_FD) {
4956 goto error;
4957 }
4958 *errFilePtr = JimDupFd(errorId);
4959 }
4960
4961
4962 pidPtr = Jim_Alloc(cmdCount * sizeof(*pidPtr));
4963 for (i = 0; i < numPids; i++) {
4964 pidPtr[i] = JIM_BAD_PID;
4965 }
4966 for (firstArg = 0; firstArg < arg_count; numPids++, firstArg = lastArg + 1) {
4967 int pipe_dup_err = 0;
4968 fdtype origErrorId = errorId;
4969
4970 for (lastArg = firstArg; lastArg < arg_count; lastArg++) {
4971 if (arg_array[lastArg][0] == '|') {
4972 if (arg_array[lastArg][1] == '&') {
4973 pipe_dup_err = 1;
4974 }
 
4975 break;
4976 }
4977 }
4978
 
 
 
 
 
 
4979 arg_array[lastArg] = NULL;
4980 if (lastArg == arg_count) {
4981 outputId = lastOutputId;
 
4982 }
4983 else {
4984 if (JimPipe(pipeIds) != 0) {
4985 Jim_SetResultErrno(interp, "couldn't create pipe");
4986 goto error;
4987 }
4988 outputId = pipeIds[1];
4989 }
4990
4991
4992 if (pipe_dup_err) {
4993 errorId = outputId;
4994 }
4995
4996
4997
4998 #ifdef __MINGW32__
4999 pid = JimStartWinProcess(interp, &arg_array[firstArg], save_environ ? save_environ[0] : NULL, inputId, outputId, errorId);
5000 if (pid == JIM_BAD_PID) {
5001 Jim_SetResultFormatted(interp, "couldn't exec \"%s\"", arg_array[firstArg]);
5002 goto error;
5003 }
5004 #else
 
 
 
5005 pid = vfork();
5006 if (pid < 0) {
5007 Jim_SetResultErrno(interp, "couldn't fork child process");
5008 goto error;
5009 }
5010 if (pid == 0) {
5011
5012
5013 if (inputId != -1) dup2(inputId, 0);
5014 if (outputId != -1) dup2(outputId, 1);
5015 if (errorId != -1) dup2(errorId, 2);
5016
5017 for (i = 3; (i <= outputId) || (i <= inputId) || (i <= errorId); i++) {
5018 close(i);
 
 
 
 
 
 
 
5019 }
5020
5021
 
 
 
 
 
 
 
 
 
 
 
 
 
5022 (void)signal(SIGPIPE, SIG_DFL);
5023
5024 execvpe(arg_array[firstArg], &arg_array[firstArg], Jim_GetEnviron());
5025
5026
5027 fprintf(stderr, "couldn't exec \"%s\"\n", arg_array[firstArg]);
 
 
 
 
 
 
 
 
 
 
5028 _exit(127);
5029 }
5030 #endif
5031
5032
5033
5034 if (table->used == table->size) {
5035 table->size += WAIT_TABLE_GROW_BY;
5036 table->info = Jim_Realloc(table->info, table->size * sizeof(*table->info));
5037 }
@@ -5040,66 +5268,66 @@
5040 table->info[table->used].flags = 0;
5041 table->used++;
5042
5043 pidPtr[numPids] = pid;
5044
5045
5046 errorId = origErrorId;
5047
5048
5049 if (inputId != JIM_BAD_FD) {
5050 JimCloseFd(inputId);
5051 }
5052 if (outputId != JIM_BAD_FD) {
5053 JimCloseFd(outputId);
5054 }
5055 inputId = pipeIds[0];
5056 pipeIds[0] = pipeIds[1] = JIM_BAD_FD;
5057 }
5058 *pidArrayPtr = pidPtr;
5059
5060
5061 cleanup:
5062 if (inputId != JIM_BAD_FD) {
5063 JimCloseFd(inputId);
5064 }
5065 if (lastOutputId != JIM_BAD_FD) {
5066 JimCloseFd(lastOutputId);
5067 }
5068 if (errorId != JIM_BAD_FD) {
5069 JimCloseFd(errorId);
5070 }
5071 Jim_Free(arg_array);
5072
5073 JimRestoreEnv(save_environ);
5074
5075 return numPids;
5076
5077
5078 error:
5079 if ((inPipePtr != NULL) && (*inPipePtr != JIM_BAD_FD)) {
5080 JimCloseFd(*inPipePtr);
5081 *inPipePtr = JIM_BAD_FD;
5082 }
5083 if ((outPipePtr != NULL) && (*outPipePtr != JIM_BAD_FD)) {
5084 JimCloseFd(*outPipePtr);
5085 *outPipePtr = JIM_BAD_FD;
5086 }
5087 if ((errFilePtr != NULL) && (*errFilePtr != JIM_BAD_FD)) {
5088 JimCloseFd(*errFilePtr);
5089 *errFilePtr = JIM_BAD_FD;
5090 }
5091 if (pipeIds[0] != JIM_BAD_FD) {
5092 JimCloseFd(pipeIds[0]);
5093 }
5094 if (pipeIds[1] != JIM_BAD_FD) {
5095 JimCloseFd(pipeIds[1]);
5096 }
5097 if (pidPtr != NULL) {
5098 for (i = 0; i < numPids; i++) {
5099 if (pidPtr[i] != JIM_BAD_PID) {
5100 JimDetachPids(interp, 1, &pidPtr[i]);
5101 }
5102 }
5103 Jim_Free(pidPtr);
5104 }
5105 numPids = -1;
@@ -5111,11 +5339,11 @@
5111 {
5112 struct WaitInfoTable *table = Jim_CmdPrivData(interp);
5113 int result = JIM_OK;
5114 int i;
5115
5116
5117 for (i = 0; i < numPids; i++) {
5118 int waitStatus = 0;
5119 if (JimWaitForProcess(table, pidPtr[i], &waitStatus) != JIM_BAD_PID) {
5120 if (JimCheckWaitStatus(interp, pidPtr[i], waitStatus, errStrObj) != JIM_OK) {
5121 result = JIM_ERR;
@@ -5127,234 +5355,30 @@
5127 return result;
5128 }
5129
5130 int Jim_execInit(Jim_Interp *interp)
5131 {
 
5132 if (Jim_PackageProvide(interp, "exec", "1.0", JIM_ERRMSG))
5133 return JIM_ERR;
5134
5135 #ifdef SIGPIPE
5136 (void)signal(SIGPIPE, SIG_IGN);
5137 #endif
5138
5139 Jim_CreateCommand(interp, "exec", Jim_ExecCmd, JimAllocWaitInfoTable(), JimFreeWaitInfoTable);
 
 
 
 
 
5140 return JIM_OK;
5141 }
5142
5143 #if defined(__MINGW32__)
5144
5145
5146 static SECURITY_ATTRIBUTES *JimStdSecAttrs(void)
5147 {
5148 static SECURITY_ATTRIBUTES secAtts;
5149
5150 secAtts.nLength = sizeof(SECURITY_ATTRIBUTES);
5151 secAtts.lpSecurityDescriptor = NULL;
5152 secAtts.bInheritHandle = TRUE;
5153 return &secAtts;
5154 }
5155
5156 static int JimErrno(void)
5157 {
5158 switch (GetLastError()) {
5159 case ERROR_FILE_NOT_FOUND: return ENOENT;
5160 case ERROR_PATH_NOT_FOUND: return ENOENT;
5161 case ERROR_TOO_MANY_OPEN_FILES: return EMFILE;
5162 case ERROR_ACCESS_DENIED: return EACCES;
5163 case ERROR_INVALID_HANDLE: return EBADF;
5164 case ERROR_BAD_ENVIRONMENT: return E2BIG;
5165 case ERROR_BAD_FORMAT: return ENOEXEC;
5166 case ERROR_INVALID_ACCESS: return EACCES;
5167 case ERROR_INVALID_DRIVE: return ENOENT;
5168 case ERROR_CURRENT_DIRECTORY: return EACCES;
5169 case ERROR_NOT_SAME_DEVICE: return EXDEV;
5170 case ERROR_NO_MORE_FILES: return ENOENT;
5171 case ERROR_WRITE_PROTECT: return EROFS;
5172 case ERROR_BAD_UNIT: return ENXIO;
5173 case ERROR_NOT_READY: return EBUSY;
5174 case ERROR_BAD_COMMAND: return EIO;
5175 case ERROR_CRC: return EIO;
5176 case ERROR_BAD_LENGTH: return EIO;
5177 case ERROR_SEEK: return EIO;
5178 case ERROR_WRITE_FAULT: return EIO;
5179 case ERROR_READ_FAULT: return EIO;
5180 case ERROR_GEN_FAILURE: return EIO;
5181 case ERROR_SHARING_VIOLATION: return EACCES;
5182 case ERROR_LOCK_VIOLATION: return EACCES;
5183 case ERROR_SHARING_BUFFER_EXCEEDED: return ENFILE;
5184 case ERROR_HANDLE_DISK_FULL: return ENOSPC;
5185 case ERROR_NOT_SUPPORTED: return ENODEV;
5186 case ERROR_REM_NOT_LIST: return EBUSY;
5187 case ERROR_DUP_NAME: return EEXIST;
5188 case ERROR_BAD_NETPATH: return ENOENT;
5189 case ERROR_NETWORK_BUSY: return EBUSY;
5190 case ERROR_DEV_NOT_EXIST: return ENODEV;
5191 case ERROR_TOO_MANY_CMDS: return EAGAIN;
5192 case ERROR_ADAP_HDW_ERR: return EIO;
5193 case ERROR_BAD_NET_RESP: return EIO;
5194 case ERROR_UNEXP_NET_ERR: return EIO;
5195 case ERROR_NETNAME_DELETED: return ENOENT;
5196 case ERROR_NETWORK_ACCESS_DENIED: return EACCES;
5197 case ERROR_BAD_DEV_TYPE: return ENODEV;
5198 case ERROR_BAD_NET_NAME: return ENOENT;
5199 case ERROR_TOO_MANY_NAMES: return ENFILE;
5200 case ERROR_TOO_MANY_SESS: return EIO;
5201 case ERROR_SHARING_PAUSED: return EAGAIN;
5202 case ERROR_REDIR_PAUSED: return EAGAIN;
5203 case ERROR_FILE_EXISTS: return EEXIST;
5204 case ERROR_CANNOT_MAKE: return ENOSPC;
5205 case ERROR_OUT_OF_STRUCTURES: return ENFILE;
5206 case ERROR_ALREADY_ASSIGNED: return EEXIST;
5207 case ERROR_INVALID_PASSWORD: return EPERM;
5208 case ERROR_NET_WRITE_FAULT: return EIO;
5209 case ERROR_NO_PROC_SLOTS: return EAGAIN;
5210 case ERROR_DISK_CHANGE: return EXDEV;
5211 case ERROR_BROKEN_PIPE: return EPIPE;
5212 case ERROR_OPEN_FAILED: return ENOENT;
5213 case ERROR_DISK_FULL: return ENOSPC;
5214 case ERROR_NO_MORE_SEARCH_HANDLES: return EMFILE;
5215 case ERROR_INVALID_TARGET_HANDLE: return EBADF;
5216 case ERROR_INVALID_NAME: return ENOENT;
5217 case ERROR_PROC_NOT_FOUND: return ESRCH;
5218 case ERROR_WAIT_NO_CHILDREN: return ECHILD;
5219 case ERROR_CHILD_NOT_COMPLETE: return ECHILD;
5220 case ERROR_DIRECT_ACCESS_HANDLE: return EBADF;
5221 case ERROR_SEEK_ON_DEVICE: return ESPIPE;
5222 case ERROR_BUSY_DRIVE: return EAGAIN;
5223 case ERROR_DIR_NOT_EMPTY: return EEXIST;
5224 case ERROR_NOT_LOCKED: return EACCES;
5225 case ERROR_BAD_PATHNAME: return ENOENT;
5226 case ERROR_LOCK_FAILED: return EACCES;
5227 case ERROR_ALREADY_EXISTS: return EEXIST;
5228 case ERROR_FILENAME_EXCED_RANGE: return ENAMETOOLONG;
5229 case ERROR_BAD_PIPE: return EPIPE;
5230 case ERROR_PIPE_BUSY: return EAGAIN;
5231 case ERROR_PIPE_NOT_CONNECTED: return EPIPE;
5232 case ERROR_DIRECTORY: return ENOTDIR;
5233 }
5234 return EINVAL;
5235 }
5236
5237 static int JimPipe(fdtype pipefd[2])
5238 {
5239 if (CreatePipe(&pipefd[0], &pipefd[1], NULL, 0)) {
5240 return 0;
5241 }
5242 return -1;
5243 }
5244
5245 static fdtype JimDupFd(fdtype infd)
5246 {
5247 fdtype dupfd;
5248 pidtype pid = GetCurrentProcess();
5249
5250 if (DuplicateHandle(pid, infd, pid, &dupfd, 0, TRUE, DUPLICATE_SAME_ACCESS)) {
5251 return dupfd;
5252 }
5253 return JIM_BAD_FD;
5254 }
5255
5256 static int JimRewindFd(fdtype fd)
5257 {
5258 return SetFilePointer(fd, 0, NULL, FILE_BEGIN) == INVALID_SET_FILE_POINTER ? -1 : 0;
5259 }
5260
5261 #if 0
5262 static int JimReadFd(fdtype fd, char *buffer, size_t len)
5263 {
5264 DWORD num;
5265
5266 if (ReadFile(fd, buffer, len, &num, NULL)) {
5267 return num;
5268 }
5269 if (GetLastError() == ERROR_HANDLE_EOF || GetLastError() == ERROR_BROKEN_PIPE) {
5270 return 0;
5271 }
5272 return -1;
5273 }
5274 #endif
5275
5276 static FILE *JimFdOpenForRead(fdtype fd)
5277 {
5278 return _fdopen(_open_osfhandle((int)fd, _O_RDONLY | _O_TEXT), "r");
5279 }
5280
5281 static fdtype JimFileno(FILE *fh)
5282 {
5283 return (fdtype)_get_osfhandle(_fileno(fh));
5284 }
5285
5286 static fdtype JimOpenForRead(const char *filename)
5287 {
5288 return CreateFile(filename, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
5289 JimStdSecAttrs(), OPEN_EXISTING, 0, NULL);
5290 }
5291
5292 static fdtype JimOpenForWrite(const char *filename, int append)
5293 {
5294 return CreateFile(filename, append ? FILE_APPEND_DATA : GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
5295 JimStdSecAttrs(), append ? OPEN_ALWAYS : CREATE_ALWAYS, 0, (HANDLE) NULL);
5296 }
5297
5298 static FILE *JimFdOpenForWrite(fdtype fd)
5299 {
5300 return _fdopen(_open_osfhandle((int)fd, _O_TEXT), "w");
5301 }
5302
5303 static pidtype JimWaitPid(pidtype pid, int *status, int nohang)
5304 {
5305 DWORD ret = WaitForSingleObject(pid, nohang ? 0 : INFINITE);
5306 if (ret == WAIT_TIMEOUT || ret == WAIT_FAILED) {
5307
5308 return JIM_BAD_PID;
5309 }
5310 GetExitCodeProcess(pid, &ret);
5311 *status = ret;
5312 CloseHandle(pid);
5313 return pid;
5314 }
5315
5316 static HANDLE JimCreateTemp(Jim_Interp *interp, const char *contents, int len)
5317 {
5318 char name[MAX_PATH];
5319 HANDLE handle;
5320
5321 if (!GetTempPath(MAX_PATH, name) || !GetTempFileName(name, "JIM", 0, name)) {
5322 return JIM_BAD_FD;
5323 }
5324
5325 handle = CreateFile(name, GENERIC_READ | GENERIC_WRITE, 0, JimStdSecAttrs(),
5326 CREATE_ALWAYS, FILE_ATTRIBUTE_TEMPORARY | FILE_FLAG_DELETE_ON_CLOSE,
5327 NULL);
5328
5329 if (handle == INVALID_HANDLE_VALUE) {
5330 goto error;
5331 }
5332
5333 if (contents != NULL) {
5334
5335 FILE *fh = JimFdOpenForWrite(JimDupFd(handle));
5336 if (fh == NULL) {
5337 goto error;
5338 }
5339
5340 if (fwrite(contents, len, 1, fh) != 1) {
5341 fclose(fh);
5342 goto error;
5343 }
5344 fseek(fh, 0, SEEK_SET);
5345 fclose(fh);
5346 }
5347 return handle;
5348
5349 error:
5350 Jim_SetResultErrno(interp, "failed to create temp file");
5351 CloseHandle(handle);
5352 DeleteFile(name);
5353 return JIM_BAD_FD;
5354 }
5355
5356 static int
5357 JimWinFindExecutable(const char *originalName, char fullPath[MAX_PATH])
5358 {
5359 int i;
5360 static char extensions[][5] = {".exe", "", ".bat"};
@@ -5381,10 +5405,15 @@
5381
5382 static void JimRestoreEnv(char **env)
5383 {
5384 JimFreeEnv(env, Jim_GetEnviron());
5385 }
 
 
 
 
 
5386
5387 static Jim_Obj *
5388 JimWinBuildCommandLine(Jim_Interp *interp, char **argv)
5389 {
5390 char *start, *special;
@@ -5455,18 +5484,19 @@
5455 }
5456 return strObj;
5457 }
5458
5459 static pidtype
5460 JimStartWinProcess(Jim_Interp *interp, char **argv, char *env, fdtype inputId, fdtype outputId, fdtype errorId)
5461 {
5462 STARTUPINFO startInfo;
5463 PROCESS_INFORMATION procInfo;
5464 HANDLE hProcess, h;
5465 char execPath[MAX_PATH];
5466 pidtype pid = JIM_BAD_PID;
5467 Jim_Obj *cmdLineObj;
 
5468
5469 if (JimWinFindExecutable(argv[0], execPath) < 0) {
5470 return JIM_BAD_PID;
5471 }
5472 argv[0] = execPath;
@@ -5480,47 +5510,51 @@
5480 startInfo.dwFlags = STARTF_USESTDHANDLES;
5481 startInfo.hStdInput = INVALID_HANDLE_VALUE;
5482 startInfo.hStdOutput= INVALID_HANDLE_VALUE;
5483 startInfo.hStdError = INVALID_HANDLE_VALUE;
5484
5485 if (inputId == JIM_BAD_FD) {
5486 if (CreatePipe(&startInfo.hStdInput, &h, JimStdSecAttrs(), 0) != FALSE) {
5487 CloseHandle(h);
5488 }
5489 } else {
5490 DuplicateHandle(hProcess, inputId, hProcess, &startInfo.hStdInput,
5491 0, TRUE, DUPLICATE_SAME_ACCESS);
5492 }
5493 if (startInfo.hStdInput == JIM_BAD_FD) {
5494 goto end;
5495 }
5496
5497 if (outputId == JIM_BAD_FD) {
5498 startInfo.hStdOutput = CreateFile("NUL:", GENERIC_WRITE, 0,
5499 JimStdSecAttrs(), OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
5500 } else {
5501 DuplicateHandle(hProcess, outputId, hProcess, &startInfo.hStdOutput,
5502 0, TRUE, DUPLICATE_SAME_ACCESS);
5503 }
5504 if (startInfo.hStdOutput == JIM_BAD_FD) {
5505 goto end;
5506 }
5507
5508 if (errorId == JIM_BAD_FD) {
5509
5510 startInfo.hStdError = CreateFile("NUL:", GENERIC_WRITE, 0,
5511 JimStdSecAttrs(), OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
5512 } else {
5513 DuplicateHandle(hProcess, errorId, hProcess, &startInfo.hStdError,
5514 0, TRUE, DUPLICATE_SAME_ACCESS);
5515 }
5516 if (startInfo.hStdError == JIM_BAD_FD) {
5517 goto end;
5518 }
5519
5520 if (!CreateProcess(NULL, (char *)Jim_String(cmdLineObj), NULL, NULL, TRUE,
5521 0, env, NULL, &startInfo, &procInfo)) {
 
 
 
 
5522 goto end;
5523 }
5524
5525
5526 WaitForInputIdle(procInfo.hProcess, 5000);
@@ -5528,49 +5562,27 @@
5528
5529 pid = procInfo.hProcess;
5530
5531 end:
5532 Jim_FreeNewObj(interp, cmdLineObj);
5533 if (startInfo.hStdInput != JIM_BAD_FD) {
5534 CloseHandle(startInfo.hStdInput);
5535 }
5536 if (startInfo.hStdOutput != JIM_BAD_FD) {
5537 CloseHandle(startInfo.hStdOutput);
5538 }
5539 if (startInfo.hStdError != JIM_BAD_FD) {
5540 CloseHandle(startInfo.hStdError);
5541 }
5542 return pid;
5543 }
 
5544 #else
5545
5546 static int JimOpenForWrite(const char *filename, int append)
5547 {
5548 return open(filename, O_WRONLY | O_CREAT | (append ? O_APPEND : O_TRUNC), 0666);
5549 }
5550
5551 static int JimRewindFd(int fd)
5552 {
5553 return lseek(fd, 0L, SEEK_SET);
5554 }
5555
5556 static int JimCreateTemp(Jim_Interp *interp, const char *contents, int len)
5557 {
5558 int fd = Jim_MakeTempFile(interp, NULL);
5559
5560 if (fd != JIM_BAD_FD) {
5561 unlink(Jim_String(Jim_GetResult(interp)));
5562 if (contents) {
5563 if (write(fd, contents, len) != len) {
5564 Jim_SetResultErrno(interp, "couldn't write temp file");
5565 close(fd);
5566 return -1;
5567 }
5568 lseek(fd, 0L, SEEK_SET);
5569 }
5570 }
5571 return fd;
5572 }
5573
5574 static char **JimSaveEnv(char **env)
5575 {
5576 char **saveenv = Jim_GetEnviron();
@@ -5585,13 +5597,21 @@
5585 }
5586 #endif
5587 #endif
5588
5589
 
 
5590 #ifndef _XOPEN_SOURCE
5591 #define _XOPEN_SOURCE 500
5592 #endif
 
 
 
 
 
 
5593
5594 #include <stdlib.h>
5595 #include <string.h>
5596 #include <stdio.h>
5597 #include <time.h>
@@ -5598,65 +5618,117 @@
5598
5599
5600 #ifdef HAVE_SYS_TIME_H
5601 #include <sys/time.h>
5602 #endif
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5603
5604 static int clock_cmd_format(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
5605 {
5606
5607 char buf[100];
5608 time_t t;
5609 long seconds;
 
 
5610
5611 const char *format = "%a %b %d %H:%M:%S %Z %Y";
5612
5613 if (argc == 2 || (argc == 3 && !Jim_CompareStringImmediate(interp, argv[1], "-format"))) {
 
5614 return -1;
5615 }
5616
5617 if (argc == 3) {
5618 format = Jim_String(argv[2]);
5619 }
5620
5621 if (Jim_GetLong(interp, argv[0], &seconds) != JIM_OK) {
5622 return JIM_ERR;
5623 }
5624 t = seconds;
 
5625
5626 if (strftime(buf, sizeof(buf), format, localtime(&t)) == 0) {
5627 Jim_SetResultString(interp, "format string too long", -1);
5628 return JIM_ERR;
5629 }
5630
5631 Jim_SetResultString(interp, buf, -1);
5632
5633 return JIM_OK;
5634 }
5635
5636 #ifdef HAVE_STRPTIME
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5637 static int clock_cmd_scan(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
5638 {
5639 char *pt;
5640 struct tm tm;
5641 time_t now = time(0);
5642
5643 if (!Jim_CompareStringImmediate(interp, argv[1], "-format")) {
 
 
 
 
 
 
 
 
 
5644 return -1;
5645 }
5646
5647
5648 localtime_r(&now, &tm);
5649
5650 pt = strptime(Jim_String(argv[0]), Jim_String(argv[2]), &tm);
5651 if (pt == 0 || *pt != 0) {
5652 Jim_SetResultString(interp, "Failed to parse time according to format", -1);
5653 return JIM_ERR;
5654 }
5655
5656
5657 Jim_SetResultInt(interp, mktime(&tm));
5658
5659 return JIM_OK;
5660 }
5661 #endif
5662
@@ -5688,54 +5760,54 @@
5688
5689 return JIM_OK;
5690 }
5691
5692 static const jim_subcmd_type clock_command_table[] = {
5693 { "seconds",
5694 NULL,
5695 clock_cmd_seconds,
5696 0,
5697 0,
5698
5699 },
5700 { "clicks",
5701 NULL,
5702 clock_cmd_micros,
5703 0,
5704 0,
5705
 
 
 
 
 
 
 
5706 },
5707 { "microseconds",
5708 NULL,
5709 clock_cmd_micros,
5710 0,
5711 0,
5712
5713 },
5714 { "milliseconds",
5715 NULL,
5716 clock_cmd_millis,
5717 0,
5718 0,
5719
5720 },
5721 { "format",
5722 "seconds ?-format format?",
5723 clock_cmd_format,
5724 1,
5725 3,
5726
5727 },
5728 #ifdef HAVE_STRPTIME
5729 { "scan",
5730 "str -format format",
5731 clock_cmd_scan,
5732 3,
5733 3,
5734
5735 },
5736 #endif
 
 
 
 
 
 
 
5737 { NULL }
5738 };
5739
5740 int Jim_clockInit(Jim_Interp *interp)
5741 {
@@ -5753,12 +5825,13 @@
5753 #include <errno.h>
5754
5755
5756 static int array_cmd_exists(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
5757 {
5758
5759 Jim_SetResultInt(interp, Jim_GetVariable(interp, argv[0], 0) != 0);
 
5760 return JIM_OK;
5761 }
5762
5763 static int array_cmd_get(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
5764 {
@@ -5769,21 +5842,20 @@
5769 return JIM_OK;
5770 }
5771
5772 patternObj = (argc == 1) ? NULL : argv[1];
5773
5774
5775 if (patternObj == NULL || Jim_CompareStringImmediate(interp, patternObj, "*")) {
5776 if (Jim_IsList(objPtr) && Jim_ListLength(interp, objPtr) % 2 == 0) {
5777
5778 Jim_SetResult(interp, objPtr);
5779 return JIM_OK;
5780 }
5781 }
5782
5783
5784 return Jim_DictValues(interp, objPtr, patternObj);
5785 }
5786
5787 static int array_cmd_names(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
5788 {
5789 Jim_Obj *objPtr = Jim_GetVariable(interp, argv[0], JIM_NONE);
@@ -5790,11 +5862,11 @@
5790
5791 if (!objPtr) {
5792 return JIM_OK;
5793 }
5794
5795 return Jim_DictKeys(interp, objPtr, argc == 1 ? NULL : argv[1]);
5796 }
5797
5798 static int array_cmd_unset(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
5799 {
5800 int i;
@@ -5802,27 +5874,29 @@
5802 Jim_Obj *resultObj;
5803 Jim_Obj *objPtr;
5804 Jim_Obj **dictValuesObj;
5805
5806 if (argc == 1 || Jim_CompareStringImmediate(interp, argv[1], "*")) {
5807
5808 Jim_UnsetVariable(interp, argv[0], JIM_NONE);
5809 return JIM_OK;
5810 }
5811
5812 objPtr = Jim_GetVariable(interp, argv[0], JIM_NONE);
5813
5814 if (objPtr == NULL) {
5815
5816 return JIM_OK;
5817 }
5818
5819 if (Jim_DictPairs(interp, objPtr, &dictValuesObj, &len) != JIM_OK) {
5820 return JIM_ERR;
 
 
5821 }
5822
5823
5824 resultObj = Jim_NewDictObj(interp, NULL, 0);
5825
5826 for (i = 0; i < len; i += 2) {
5827 if (!Jim_StringMatchObj(interp, argv[1], dictValuesObj[i], 0)) {
5828 Jim_DictAddElement(interp, resultObj, dictValuesObj[i], dictValuesObj[i + 1]);
@@ -5837,16 +5911,18 @@
5837 static int array_cmd_size(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
5838 {
5839 Jim_Obj *objPtr;
5840 int len = 0;
5841
5842
5843 objPtr = Jim_GetVariable(interp, argv[0], JIM_NONE);
5844 if (objPtr) {
5845 len = Jim_DictSize(interp, objPtr);
5846 if (len < 0) {
5847 return JIM_ERR;
 
 
5848 }
5849 }
5850
5851 Jim_SetResultInt(interp, len);
5852
@@ -5876,11 +5952,11 @@
5876 return JIM_ERR;
5877 }
5878
5879 dictObj = Jim_GetVariable(interp, argv[0], JIM_UNSHARED);
5880 if (!dictObj) {
5881
5882 return Jim_SetVariable(interp, argv[0], listObj);
5883 }
5884 else if (Jim_DictSize(interp, dictObj) < 0) {
5885 return JIM_ERR;
5886 }
@@ -5905,53 +5981,53 @@
5905 { "exists",
5906 "arrayName",
5907 array_cmd_exists,
5908 1,
5909 1,
5910
5911 },
5912 { "get",
5913 "arrayName ?pattern?",
5914 array_cmd_get,
5915 1,
5916 2,
5917
5918 },
5919 { "names",
5920 "arrayName ?pattern?",
5921 array_cmd_names,
5922 1,
5923 2,
5924
5925 },
5926 { "set",
5927 "arrayName list",
5928 array_cmd_set,
5929 2,
5930 2,
5931
5932 },
5933 { "size",
5934 "arrayName",
5935 array_cmd_size,
5936 1,
5937 1,
5938
5939 },
5940 { "stat",
5941 "arrayName",
5942 array_cmd_stat,
5943 1,
5944 1,
5945
5946 },
5947 { "unset",
5948 "arrayName ?pattern?",
5949 array_cmd_unset,
5950 1,
5951 2,
5952
5953 },
5954 { NULL
5955 }
5956 };
5957
@@ -5987,11 +6063,14 @@
5987 Jim_arrayInit(interp);
5988 Jim_stdlibInit(interp);
5989 Jim_tclcompatInit(interp);
5990 return JIM_OK;
5991 }
5992 #define JIM_OPTIMIZATION
 
 
 
5993
5994 #include <stdio.h>
5995 #include <stdlib.h>
5996
5997 #include <string.h>
@@ -6056,10 +6135,16 @@
6056 #define JimPanic(X) JimPanicDump X
6057 #else
6058 #define JimPanic(X)
6059 #endif
6060
 
 
 
 
 
 
6061
6062 static char JimEmptyStringRep[] = "";
6063
6064 static void JimFreeCallFrame(Jim_Interp *interp, Jim_CallFrame *cf, int action);
6065 static int ListSetIndex(Jim_Interp *interp, Jim_Obj *listPtr, int listindex, Jim_Obj *newObjPtr,
@@ -6112,34 +6197,34 @@
6112 if (*pattern == '^') {
6113 not++;
6114 pattern++;
6115 }
6116
6117
6118 if (*pattern == ']') {
6119 goto first;
6120 }
6121 }
6122
6123 while (*pattern && *pattern != ']') {
6124
6125 if (pattern[0] == '\\') {
6126 first:
6127 pattern += utf8_tounicode_case(pattern, &pchar, nocase);
6128 }
6129 else {
6130
6131 int start;
6132 int end;
6133
6134 pattern += utf8_tounicode_case(pattern, &start, nocase);
6135 if (pattern[0] == '-' && pattern[1]) {
6136
6137 pattern += utf8_tounicode(pattern, &pchar);
6138 pattern += utf8_tounicode_case(pattern, &end, nocase);
6139
6140
6141 if ((c >= start && c <= end) || (c >= end && c <= start)) {
6142 match = 1;
6143 }
6144 continue;
6145 }
@@ -6169,19 +6254,19 @@
6169 while (pattern[1] == '*') {
6170 pattern++;
6171 }
6172 pattern++;
6173 if (!pattern[0]) {
6174 return 1;
6175 }
6176 while (*string) {
6177
6178 if (JimGlobMatch(pattern, string, nocase))
6179 return 1;
6180 string += utf8_tounicode(string, &c);
6181 }
6182 return 0;
6183
6184 case '?':
6185 string += utf8_tounicode(string, &c);
6186 break;
6187
@@ -6190,20 +6275,20 @@
6190 pattern = JimCharsetMatch(pattern + 1, c, nocase ? JIM_NOCASE : 0);
6191 if (!pattern) {
6192 return 0;
6193 }
6194 if (!*pattern) {
6195
6196 continue;
6197 }
6198 break;
6199 }
6200 case '\\':
6201 if (pattern[1]) {
6202 pattern++;
6203 }
6204
6205 default:
6206 string += utf8_tounicode_case(string, &c, nocase);
6207 utf8_tounicode_case(pattern, &pchar, nocase);
6208 if (pchar != c) {
6209 return 0;
@@ -6249,11 +6334,11 @@
6249 maxchars--;
6250 }
6251 if (!maxchars) {
6252 return 0;
6253 }
6254
6255 if (*s1) {
6256 return 1;
6257 }
6258 if (*s2) {
6259 return -1;
@@ -6290,11 +6375,11 @@
6290 const char *p;
6291
6292 if (!l1 || !l2 || l1 > l2)
6293 return -1;
6294
6295
6296 for (p = s2 + l2 - 1; p != s2 - 1; p--) {
6297 if (*p == *s1 && memcmp(s1, p, l1) == 0) {
6298 return p - s2;
6299 }
6300 }
@@ -6349,28 +6434,28 @@
6349 }
6350 *sign = 1;
6351 }
6352
6353 if (str[i] != '0') {
6354
6355 return 0;
6356 }
6357
6358
6359 switch (str[i + 1]) {
6360 case 'x': case 'X': *base = 16; break;
6361 case 'o': case 'O': *base = 8; break;
6362 case 'b': case 'B': *base = 2; break;
6363 default: return 0;
6364 }
6365 i += 2;
6366
6367 if (str[i] != '-' && str[i] != '+' && !isspace(UCHAR(str[i]))) {
6368
6369 return i;
6370 }
6371
6372 *base = 10;
6373 return 0;
6374 }
6375
6376 static long jim_strtol(const char *str, char **endptr)
@@ -6384,11 +6469,11 @@
6384 if (endptr == NULL || *endptr != str + i) {
6385 return value * sign;
6386 }
6387 }
6388
6389
6390 return strtol(str, endptr, 10);
6391 }
6392
6393
6394 static jim_wide jim_strtoull(const char *str, char **endptr)
@@ -6403,11 +6488,11 @@
6403 if (endptr == NULL || *endptr != str + i) {
6404 return value * sign;
6405 }
6406 }
6407
6408
6409 return strtoull(str, endptr, 10);
6410 #else
6411 return (unsigned long)jim_strtol(str, endptr);
6412 #endif
6413 }
@@ -6428,26 +6513,40 @@
6428
6429 int Jim_StringToDouble(const char *str, double *doublePtr)
6430 {
6431 char *endptr;
6432
6433
6434 errno = 0;
6435
6436 *doublePtr = strtod(str, &endptr);
6437
6438 return JimCheckConversion(str, endptr);
6439 }
6440
6441 static jim_wide JimPowWide(jim_wide b, jim_wide e)
6442 {
6443 jim_wide i, res = 1;
6444
6445 if ((b == 0 && e != 0) || (e < 0))
6446 return 0;
6447 for (i = 0; i < e; i++) {
6448 res *= b;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6449 }
6450 return res;
6451 }
6452
6453 #ifdef JIM_DEBUG_PANIC
@@ -6509,11 +6608,11 @@
6509 char *Jim_StrDupLen(const char *s, int l)
6510 {
6511 char *copy = Jim_Alloc(l + 1);
6512
6513 memcpy(copy, s, l + 1);
6514 copy[l] = 0;
6515 return copy;
6516 }
6517
6518
6519
@@ -6598,52 +6697,52 @@
6598 }
6599
6600
6601 void Jim_ExpandHashTable(Jim_HashTable *ht, unsigned int size)
6602 {
6603 Jim_HashTable n;
6604 unsigned int realsize = JimHashTableNextPower(size), i;
6605
6606 if (size <= ht->used)
6607 return;
6608
6609 Jim_InitHashTable(&n, ht->type, ht->privdata);
6610 n.size = realsize;
6611 n.sizemask = realsize - 1;
6612 n.table = Jim_Alloc(realsize * sizeof(Jim_HashEntry *));
6613
6614 n.uniq = ht->uniq;
6615
6616
6617 memset(n.table, 0, realsize * sizeof(Jim_HashEntry *));
6618
6619 n.used = ht->used;
6620 for (i = 0; ht->used > 0; i++) {
6621 Jim_HashEntry *he, *nextHe;
6622
6623 if (ht->table[i] == NULL)
6624 continue;
6625
6626
6627 he = ht->table[i];
6628 while (he) {
6629 unsigned int h;
6630
6631 nextHe = he->next;
6632
6633 h = Jim_HashKey(ht, he->key) & n.sizemask;
6634 he->next = n.table[h];
6635 n.table[h] = he;
6636 ht->used--;
6637
6638 he = nextHe;
6639 }
6640 }
6641 assert(ht->used == 0);
6642 Jim_Free(ht->table);
6643
6644
6645 *ht = n;
6646 }
6647
6648
6649 int Jim_AddHashEntry(Jim_HashTable *ht, const void *key, void *val)
@@ -6652,11 +6751,11 @@
6652
6653 entry = JimInsertHashEntry(ht, key, 0);
6654 if (entry == NULL)
6655 return JIM_ERR;
6656
6657
6658 Jim_SetHashKey(ht, entry, key);
6659 Jim_SetHashVal(ht, entry, val);
6660 return JIM_OK;
6661 }
6662
@@ -6678,11 +6777,11 @@
6678 Jim_SetHashVal(ht, entry, val);
6679 }
6680 existed = 1;
6681 }
6682 else {
6683
6684 Jim_SetHashKey(ht, entry, key);
6685 Jim_SetHashVal(ht, entry, val);
6686 existed = 0;
6687 }
6688
@@ -6701,11 +6800,11 @@
6701 he = ht->table[h];
6702
6703 prevHe = NULL;
6704 while (he) {
6705 if (Jim_CompareHashKeys(ht, key, he->key)) {
6706
6707 if (prevHe)
6708 prevHe->next = he->next;
6709 else
6710 ht->table[h] = he->next;
6711 Jim_FreeEntryKey(ht, he);
@@ -6715,19 +6814,19 @@
6715 return JIM_OK;
6716 }
6717 prevHe = he;
6718 he = he->next;
6719 }
6720 return JIM_ERR;
6721 }
6722
6723
6724 int Jim_FreeHashTable(Jim_HashTable *ht)
6725 {
6726 unsigned int i;
6727
6728
6729 for (i = 0; ht->used > 0; i++) {
6730 Jim_HashEntry *he, *nextHe;
6731
6732 if ((he = ht->table[i]) == NULL)
6733 continue;
@@ -6738,15 +6837,15 @@
6738 Jim_Free(he);
6739 ht->used--;
6740 he = nextHe;
6741 }
6742 }
6743
6744 Jim_Free(ht->table);
6745
6746 JimResetHashTable(ht);
6747 return JIM_OK;
6748 }
6749
6750 Jim_HashEntry *Jim_FindHashEntry(Jim_HashTable *ht, const void *key)
6751 {
6752 Jim_HashEntry *he;
@@ -6819,24 +6918,24 @@
6819 static Jim_HashEntry *JimInsertHashEntry(Jim_HashTable *ht, const void *key, int replace)
6820 {
6821 unsigned int h;
6822 Jim_HashEntry *he;
6823
6824
6825 JimExpandHashTableIfNeeded(ht);
6826
6827
6828 h = Jim_HashKey(ht, key) & ht->sizemask;
6829
6830 he = ht->table[h];
6831 while (he) {
6832 if (Jim_CompareHashKeys(ht, key, he->key))
6833 return replace ? he : NULL;
6834 he = he->next;
6835 }
6836
6837
6838 he = Jim_Alloc(sizeof(*he));
6839 he->next = ht->table[h];
6840 ht->table[h] = he;
6841 ht->used++;
6842 he->key = NULL;
@@ -6865,16 +6964,16 @@
6865 {
6866 Jim_Free(key);
6867 }
6868
6869 static const Jim_HashTableType JimPackageHashTableType = {
6870 JimStringCopyHTHashFunction,
6871 JimStringCopyHTDup,
6872 NULL,
6873 JimStringCopyHTKeyCompare,
6874 JimStringCopyHTKeyDestructor,
6875 NULL
6876 };
6877
6878 typedef struct AssocDataValue
6879 {
6880 Jim_InterpDeleteProc *delProc;
@@ -6889,16 +6988,16 @@
6889 assocPtr->delProc((Jim_Interp *)privdata, assocPtr->data);
6890 Jim_Free(data);
6891 }
6892
6893 static const Jim_HashTableType JimAssocDataHashTableType = {
6894 JimStringCopyHTHashFunction,
6895 JimStringCopyHTDup,
6896 NULL,
6897 JimStringCopyHTKeyCompare,
6898 JimStringCopyHTKeyDestructor,
6899 JimAssocDataHashTableValueDestructor
6900 };
6901
6902 void Jim_InitStack(Jim_Stack *stack)
6903 {
6904 stack->len = 0;
@@ -6951,56 +7050,61 @@
6951 freeFunc(stack->vector[i]);
6952 }
6953
6954
6955
6956 #define JIM_TT_NONE 0
6957 #define JIM_TT_STR 1
6958 #define JIM_TT_ESC 2
6959 #define JIM_TT_VAR 3
6960 #define JIM_TT_DICTSUGAR 4
6961 #define JIM_TT_CMD 5
6962
6963 #define JIM_TT_SEP 6
6964 #define JIM_TT_EOL 7
6965 #define JIM_TT_EOF 8
6966
6967 #define JIM_TT_LINE 9
6968 #define JIM_TT_WORD 10
6969
6970
6971 #define JIM_TT_SUBEXPR_START 11
6972 #define JIM_TT_SUBEXPR_END 12
6973 #define JIM_TT_SUBEXPR_COMMA 13
6974 #define JIM_TT_EXPR_INT 14
6975 #define JIM_TT_EXPR_DOUBLE 15
 
6976
6977 #define JIM_TT_EXPRSUGAR 16
6978
6979
6980 #define JIM_TT_EXPR_OP 20
6981
6982 #define TOKEN_IS_SEP(type) (type >= JIM_TT_SEP && type <= JIM_TT_EOF)
6983
 
 
 
 
6984 struct JimParseMissing {
6985 int ch;
6986 int line;
6987 };
6988
6989 struct JimParserCtx
6990 {
6991 const char *p;
6992 int len;
6993 int linenr;
6994 const char *tstart;
6995 const char *tend;
6996 int tline;
6997 int tt;
6998 int eof;
6999 int inquote;
7000 int comment;
7001 struct JimParseMissing missing;
7002 };
7003
7004 static int JimParseScript(struct JimParserCtx *pc);
7005 static int JimParseSep(struct JimParserCtx *pc);
7006 static int JimParseEol(struct JimParserCtx *pc);
@@ -7030,11 +7134,11 @@
7030 pc->missing.line = linenr;
7031 }
7032
7033 static int JimParseScript(struct JimParserCtx *pc)
7034 {
7035 while (1) {
7036 if (!pc->len) {
7037 pc->tstart = pc->p;
7038 pc->tend = pc->p - 1;
7039 pc->tline = pc->linenr;
7040 pc->tt = JIM_TT_EOL;
@@ -7066,11 +7170,11 @@
7066 pc->comment = 0;
7067 return JimParseCmd(pc);
7068 case '$':
7069 pc->comment = 0;
7070 if (JimParseVar(pc) == JIM_ERR) {
7071
7072 pc->tstart = pc->tend = pc->p++;
7073 pc->len--;
7074 pc->tt = JIM_TT_ESC;
7075 }
7076 return JIM_OK;
@@ -7127,11 +7231,11 @@
7127
7128 static void JimParseSubBrace(struct JimParserCtx *pc)
7129 {
7130 int level = 1;
7131
7132
7133 pc->p++;
7134 pc->len--;
7135 while (pc->len) {
7136 switch (*pc->p) {
7137 case '\\':
@@ -7171,11 +7275,11 @@
7171 static int JimParseSubQuote(struct JimParserCtx *pc)
7172 {
7173 int tt = JIM_TT_STR;
7174 int line = pc->tline;
7175
7176
7177 pc->p++;
7178 pc->len--;
7179 while (pc->len) {
7180 switch (*pc->p) {
7181 case '\\':
@@ -7220,11 +7324,11 @@
7220 {
7221 int level = 1;
7222 int startofword = 1;
7223 int line = pc->tline;
7224
7225
7226 pc->p++;
7227 pc->len--;
7228 while (pc->len) {
7229 switch (*pc->p) {
7230 case '\\':
@@ -7300,17 +7404,17 @@
7300 return JIM_OK;
7301 }
7302
7303 static int JimParseVar(struct JimParserCtx *pc)
7304 {
7305
7306 pc->p++;
7307 pc->len--;
7308
7309 #ifdef EXPRSUGAR_BRACKET
7310 if (*pc->p == '[') {
7311
7312 JimParseCmd(pc);
7313 pc->tt = JIM_TT_EXPRSUGAR;
7314 return JIM_OK;
7315 }
7316 #endif
@@ -7336,11 +7440,11 @@
7336 pc->len--;
7337 }
7338 }
7339 else {
7340 while (1) {
7341
7342 if (pc->p[0] == ':' && pc->p[1] == ':') {
7343 while (*pc->p == ':') {
7344 pc->p++;
7345 pc->len--;
7346 }
@@ -7351,11 +7455,11 @@
7351 pc->len--;
7352 continue;
7353 }
7354 break;
7355 }
7356
7357 if (*pc->p == '(') {
7358 int count = 1;
7359 const char *paren = NULL;
7360
7361 pc->tt = JIM_TT_DICTSUGAR;
@@ -7378,11 +7482,11 @@
7378 if (count == 0) {
7379 pc->p++;
7380 pc->len--;
7381 }
7382 else if (paren) {
7383
7384 paren++;
7385 pc->len += (pc->p - paren);
7386 pc->p = paren;
7387 }
7388 #ifndef EXPRSUGAR_BRACKET
@@ -7403,19 +7507,19 @@
7403
7404 static int JimParseStr(struct JimParserCtx *pc)
7405 {
7406 if (pc->tt == JIM_TT_SEP || pc->tt == JIM_TT_EOL ||
7407 pc->tt == JIM_TT_NONE || pc->tt == JIM_TT_STR) {
7408
7409 if (*pc->p == '{') {
7410 return JimParseBrace(pc);
7411 }
7412 if (*pc->p == '"') {
7413 pc->inquote = 1;
7414 pc->p++;
7415 pc->len--;
7416
7417 pc->missing.line = pc->tline;
7418 }
7419 }
7420 pc->tstart = pc->p;
7421 pc->tline = pc->linenr;
@@ -7441,25 +7545,25 @@
7441 }
7442 pc->p++;
7443 pc->len--;
7444 }
7445 else if (pc->len == 1) {
7446
7447 pc->missing.ch = '\\';
7448 }
7449 break;
7450 case '(':
7451
7452 if (pc->len > 1 && pc->p[1] != '$') {
7453 break;
7454 }
7455
7456 case ')':
7457
7458 if (*pc->p == '(' || pc->tt == JIM_TT_VAR) {
7459 if (pc->p == pc->tstart) {
7460
7461 pc->p++;
7462 pc->len--;
7463 }
7464 pc->tend = pc->p - 1;
7465 pc->tt = JIM_TT_ESC;
@@ -7499,11 +7603,11 @@
7499 break;
7500 }
7501 pc->p++;
7502 pc->len--;
7503 }
7504 return JIM_OK;
7505 }
7506
7507 static int JimParseComment(struct JimParserCtx *pc)
7508 {
7509 while (*pc->p) {
@@ -7610,34 +7714,34 @@
7610 if (c == -1) {
7611 break;
7612 }
7613 val = (val << 4) | c;
7614 }
7615
7616 if (s[i] == '{') {
7617 if (k == 0 || val > 0x1fffff || s[i + k + 1] != '}') {
7618
7619 i--;
7620 k = 0;
7621 }
7622 else {
7623
7624 k++;
7625 }
7626 }
7627 if (k) {
7628
7629 if (s[i] == 'x') {
7630 *p++ = val;
7631 }
7632 else {
7633 p += utf8_fromunicode(p, val);
7634 }
7635 i += k;
7636 break;
7637 }
7638
7639 *p++ = s[i];
7640 }
7641 break;
7642 case 'v':
7643 *p++ = 0xb;
@@ -7646,11 +7750,11 @@
7646 case '\0':
7647 *p++ = '\\';
7648 i++;
7649 break;
7650 case '\n':
7651
7652 *p++ = ' ';
7653 do {
7654 i++;
7655 } while (s[i + 1] == ' ' || s[i + 1] == '\t');
7656 break;
@@ -7660,11 +7764,11 @@
7660 case '3':
7661 case '4':
7662 case '5':
7663 case '6':
7664 case '7':
7665
7666 {
7667 int val = 0;
7668 int c = odigitval(s[i + 1]);
7669
7670 val = c;
@@ -7708,27 +7812,23 @@
7708 char *token;
7709 int len;
7710
7711 start = pc->tstart;
7712 end = pc->tend;
7713 if (start > end) {
 
7714 len = 0;
7715 token = Jim_Alloc(1);
7716 token[0] = '\0';
7717 }
7718 else {
7719 len = (end - start) + 1;
7720 token = Jim_Alloc(len + 1);
7721 if (pc->tt != JIM_TT_ESC) {
7722
7723 memcpy(token, start, len);
7724 token[len] = '\0';
7725 }
7726 else {
7727
7728 len = JimEscape(token, start, len);
7729 }
7730 }
7731
7732 return Jim_NewStringObjNoAlloc(interp, token, len);
7733 }
7734
@@ -7790,11 +7890,11 @@
7790 while (pc->len) {
7791 switch (*pc->p) {
7792 case '\\':
7793 pc->tt = JIM_TT_ESC;
7794 if (--pc->len == 0) {
7795
7796 pc->tend = pc->p;
7797 return JIM_OK;
7798 }
7799 pc->p++;
7800 break;
@@ -7826,11 +7926,11 @@
7826 pc->tend = pc->p - 1;
7827 return JIM_OK;
7828 }
7829 if (*pc->p == '\\') {
7830 if (--pc->len == 0) {
7831
7832 pc->tend = pc->p;
7833 return JIM_OK;
7834 }
7835 pc->tt = JIM_TT_ESC;
7836 pc->p++;
@@ -7846,24 +7946,24 @@
7846
7847 Jim_Obj *Jim_NewObj(Jim_Interp *interp)
7848 {
7849 Jim_Obj *objPtr;
7850
7851
7852 if (interp->freeList != NULL) {
7853
7854 objPtr = interp->freeList;
7855 interp->freeList = objPtr->nextObjPtr;
7856 }
7857 else {
7858
7859 objPtr = Jim_Alloc(sizeof(*objPtr));
7860 }
7861
7862 objPtr->refCount = 0;
7863
7864
7865 objPtr->prevObjPtr = NULL;
7866 objPtr->nextObjPtr = interp->liveList;
7867 if (interp->liveList)
7868 interp->liveList->prevObjPtr = objPtr;
7869 interp->liveList = objPtr;
@@ -7871,32 +7971,32 @@
7871 return objPtr;
7872 }
7873
7874 void Jim_FreeObj(Jim_Interp *interp, Jim_Obj *objPtr)
7875 {
7876
7877 JimPanic((objPtr->refCount != 0, "!!!Object %p freed with bad refcount %d, type=%s", objPtr,
7878 objPtr->refCount, objPtr->typePtr ? objPtr->typePtr->name : "<none>"));
7879
7880
7881 Jim_FreeIntRep(interp, objPtr);
7882
7883 if (objPtr->bytes != NULL) {
7884 if (objPtr->bytes != JimEmptyStringRep)
7885 Jim_Free(objPtr->bytes);
7886 }
7887
7888 if (objPtr->prevObjPtr)
7889 objPtr->prevObjPtr->nextObjPtr = objPtr->nextObjPtr;
7890 if (objPtr->nextObjPtr)
7891 objPtr->nextObjPtr->prevObjPtr = objPtr->prevObjPtr;
7892 if (interp->liveList == objPtr)
7893 interp->liveList = objPtr->nextObjPtr;
7894 #ifdef JIM_DISABLE_OBJECT_POOL
7895 Jim_Free(objPtr);
7896 #else
7897
7898 objPtr->prevObjPtr = NULL;
7899 objPtr->nextObjPtr = interp->freeList;
7900 if (interp->freeList)
7901 interp->freeList->prevObjPtr = objPtr;
7902 interp->freeList = objPtr;
@@ -7919,45 +8019,44 @@
7919 {
7920 Jim_Obj *dupPtr;
7921
7922 dupPtr = Jim_NewObj(interp);
7923 if (objPtr->bytes == NULL) {
7924
7925 dupPtr->bytes = NULL;
7926 }
7927 else if (objPtr->length == 0) {
7928
7929 dupPtr->bytes = JimEmptyStringRep;
7930 dupPtr->length = 0;
7931 dupPtr->typePtr = NULL;
7932 return dupPtr;
7933 }
7934 else {
7935 dupPtr->bytes = Jim_Alloc(objPtr->length + 1);
7936 dupPtr->length = objPtr->length;
7937
7938 memcpy(dupPtr->bytes, objPtr->bytes, objPtr->length + 1);
7939 }
7940
7941
7942 dupPtr->typePtr = objPtr->typePtr;
7943 if (objPtr->typePtr != NULL) {
7944 if (objPtr->typePtr->dupIntRepProc == NULL) {
7945 dupPtr->internalRep = objPtr->internalRep;
7946 }
7947 else {
7948
7949 objPtr->typePtr->dupIntRepProc(interp, objPtr, dupPtr);
7950 }
7951 }
7952 return dupPtr;
7953 }
7954
7955 const char *Jim_GetString(Jim_Obj *objPtr, int *lenPtr)
7956 {
7957 if (objPtr->bytes == NULL) {
7958
7959 JimPanic((objPtr->typePtr->updateStringProc == NULL, "UpdateStringProc called against '%s' type.", objPtr->typePtr->name));
7960 objPtr->typePtr->updateStringProc(objPtr);
7961 }
7962 if (lenPtr)
7963 *lenPtr = objPtr->length;
@@ -7966,25 +8065,22 @@
7966
7967
7968 int Jim_Length(Jim_Obj *objPtr)
7969 {
7970 if (objPtr->bytes == NULL) {
7971
7972 JimPanic((objPtr->typePtr->updateStringProc == NULL, "UpdateStringProc called against '%s' type.", objPtr->typePtr->name));
7973 objPtr->typePtr->updateStringProc(objPtr);
7974 }
7975 return objPtr->length;
7976 }
7977
7978
7979 const char *Jim_String(Jim_Obj *objPtr)
7980 {
7981 if (objPtr->bytes == NULL) {
7982
7983 JimPanic((objPtr->typePtr == NULL, "UpdateStringProc called against typeless value."));
7984 JimPanic((objPtr->typePtr->updateStringProc == NULL, "UpdateStringProc called against '%s' type.", objPtr->typePtr->name));
7985 objPtr->typePtr->updateStringProc(objPtr);
7986 }
7987 return objPtr->bytes;
7988 }
7989
7990 static void JimSetStringBytes(Jim_Obj *objPtr, const char *str)
@@ -8001,23 +8097,34 @@
8001 FreeDictSubstInternalRep,
8002 DupDictSubstInternalRep,
8003 NULL,
8004 JIM_TYPE_NONE,
8005 };
 
 
 
 
 
 
 
 
 
 
 
8006
8007 static void FreeInterpolatedInternalRep(Jim_Interp *interp, Jim_Obj *objPtr)
8008 {
8009 Jim_DecrRefCount(interp, objPtr->internalRep.dictSubstValue.indexObjPtr);
8010 }
8011
8012 static const Jim_ObjType interpolatedObjType = {
8013 "interpolated",
8014 FreeInterpolatedInternalRep,
8015 NULL,
8016 NULL,
8017 JIM_TYPE_NONE,
8018 };
8019
8020 static void DupStringInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr);
8021 static int SetStringFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr);
8022
8023 static const Jim_ObjType stringObjType = {
@@ -8037,22 +8144,22 @@
8037 }
8038
8039 static int SetStringFromAny(Jim_Interp *interp, Jim_Obj *objPtr)
8040 {
8041 if (objPtr->typePtr != &stringObjType) {
8042
8043 if (objPtr->bytes == NULL) {
8044
8045 JimPanic((objPtr->typePtr->updateStringProc == NULL, "UpdateStringProc called against '%s' type.", objPtr->typePtr->name));
8046 objPtr->typePtr->updateStringProc(objPtr);
8047 }
8048
8049 Jim_FreeIntRep(interp, objPtr);
8050
8051 objPtr->typePtr = &stringObjType;
8052 objPtr->internalRep.strValue.maxLength = objPtr->length;
8053
8054 objPtr->internalRep.strValue.charLength = -1;
8055 }
8056 return JIM_OK;
8057 }
8058
@@ -8073,39 +8180,37 @@
8073
8074 Jim_Obj *Jim_NewStringObj(Jim_Interp *interp, const char *s, int len)
8075 {
8076 Jim_Obj *objPtr = Jim_NewObj(interp);
8077
8078
8079 if (len == -1)
8080 len = strlen(s);
8081
8082 if (len == 0) {
8083 objPtr->bytes = JimEmptyStringRep;
8084 }
8085 else {
8086 objPtr->bytes = Jim_Alloc(len + 1);
8087 memcpy(objPtr->bytes, s, len);
8088 objPtr->bytes[len] = '\0';
8089 }
8090 objPtr->length = len;
8091
8092
8093 objPtr->typePtr = NULL;
8094 return objPtr;
8095 }
8096
8097
8098 Jim_Obj *Jim_NewStringObjUtf8(Jim_Interp *interp, const char *s, int charlen)
8099 {
8100 #ifdef JIM_UTF8
8101
8102 int bytelen = utf8_index(s, charlen);
8103
8104 Jim_Obj *objPtr = Jim_NewStringObj(interp, s, bytelen);
8105
8106
8107 objPtr->typePtr = &stringObjType;
8108 objPtr->internalRep.strValue.maxLength = bytelen;
8109 objPtr->internalRep.strValue.charLength = charlen;
8110
8111 return objPtr;
@@ -8132,11 +8237,11 @@
8132 len = strlen(str);
8133 needlen = objPtr->length + len;
8134 if (objPtr->internalRep.strValue.maxLength < needlen ||
8135 objPtr->internalRep.strValue.maxLength == 0) {
8136 needlen *= 2;
8137
8138 if (needlen < 7) {
8139 needlen = 7;
8140 }
8141 if (objPtr->bytes == JimEmptyStringRep) {
8142 objPtr->bytes = Jim_Alloc(needlen + 1);
@@ -8148,11 +8253,11 @@
8148 }
8149 memcpy(objPtr->bytes + objPtr->length, str, len);
8150 objPtr->bytes[objPtr->length + len] = '\0';
8151
8152 if (objPtr->internalRep.strValue.charLength >= 0) {
8153
8154 objPtr->internalRep.strValue.charLength += utf8_strlen(objPtr->bytes + objPtr->length, len);
8155 }
8156 objPtr->length += len;
8157 }
8158
@@ -8210,11 +8315,11 @@
8210 int l1, l2;
8211 const char *s1 = Jim_GetString(firstObjPtr, &l1);
8212 const char *s2 = Jim_GetString(secondObjPtr, &l2);
8213
8214 if (nocase) {
8215
8216 return JimStringCompareLen(s1, s2, -1, nocase);
8217 }
8218 return JimStringCompare(s1, l1, s2, l2);
8219 }
8220
@@ -8312,11 +8417,11 @@
8312
8313 if (first == 0 && rangeLen == len) {
8314 return strObjPtr;
8315 }
8316 if (len == bytelen) {
8317
8318 return Jim_NewStringObj(interp, str + first, rangeLen);
8319 }
8320 return Jim_NewStringObjUtf8(interp, str + utf8_index(str, first), rangeLen);
8321 #else
8322 return Jim_StringByteRangeObj(interp, strObjPtr, firstObjPtr, lastObjPtr);
@@ -8341,19 +8446,19 @@
8341 return strObjPtr;
8342 }
8343
8344 str = Jim_String(strObjPtr);
8345
8346
8347 objPtr = Jim_NewStringObjUtf8(interp, str, first);
8348
8349
8350 if (newStrObj) {
8351 Jim_AppendObj(interp, objPtr, newStrObj);
8352 }
8353
8354
8355 Jim_AppendString(interp, objPtr, str + utf8_index(str, last + 1), len - last - 1);
8356
8357 return objPtr;
8358 }
8359
@@ -8371,12 +8476,10 @@
8371 {
8372 char *buf;
8373 int len;
8374 const char *str;
8375
8376 SetStringFromAny(interp, strObjPtr);
8377
8378 str = Jim_GetString(strObjPtr, &len);
8379
8380 #ifdef JIM_UTF8
8381 len *= 2;
8382 #endif
@@ -8389,14 +8492,10 @@
8389 {
8390 char *buf;
8391 const char *str;
8392 int len;
8393
8394 if (strObjPtr->typePtr != &stringObjType) {
8395 SetStringFromAny(interp, strObjPtr);
8396 }
8397
8398 str = Jim_GetString(strObjPtr, &len);
8399
8400 #ifdef JIM_UTF8
8401 len *= 2;
8402 #endif
@@ -8411,13 +8510,11 @@
8411 int len;
8412 int c;
8413 const char *str;
8414
8415 str = Jim_GetString(strObjPtr, &len);
8416 if (len == 0) {
8417 return strObjPtr;
8418 }
8419 #ifdef JIM_UTF8
8420 len *= 2;
8421 #endif
8422 buf = p = Jim_Alloc(len + 1);
8423
@@ -8452,11 +8549,11 @@
8452 while (len) {
8453 int c;
8454 int n = utf8_tounicode(str, &c);
8455
8456 if (utf8_memchr(trimchars, trimlen, c) == NULL) {
8457
8458 break;
8459 }
8460 str += n;
8461 len -= n;
8462 }
@@ -8523,41 +8620,41 @@
8523
8524 len = Jim_Length(strObjPtr);
8525 nontrim = JimFindTrimRight(strObjPtr->bytes, len, trimchars, trimcharslen);
8526
8527 if (nontrim == NULL) {
8528
8529 return Jim_NewEmptyStringObj(interp);
8530 }
8531 if (nontrim == strObjPtr->bytes + len) {
8532
8533 return strObjPtr;
8534 }
8535
8536 if (Jim_IsShared(strObjPtr)) {
8537 strObjPtr = Jim_NewStringObj(interp, strObjPtr->bytes, (nontrim - strObjPtr->bytes));
8538 }
8539 else {
8540
8541 strObjPtr->bytes[nontrim - strObjPtr->bytes] = 0;
8542 strObjPtr->length = (nontrim - strObjPtr->bytes);
8543 }
8544
8545 return strObjPtr;
8546 }
8547
8548 static Jim_Obj *JimStringTrim(Jim_Interp *interp, Jim_Obj *strObjPtr, Jim_Obj *trimcharsObjPtr)
8549 {
8550
8551 Jim_Obj *objPtr = JimStringTrimLeft(interp, strObjPtr, trimcharsObjPtr);
8552
8553
8554 strObjPtr = JimStringTrimRight(interp, objPtr, trimcharsObjPtr);
8555
8556
8557 if (objPtr != strObjPtr && objPtr->refCount == 0) {
8558
8559 Jim_FreeNewObj(interp, objPtr);
8560 }
8561
8562 return strObjPtr;
8563 }
@@ -8575,17 +8672,17 @@
8575 static int JimStringIs(Jim_Interp *interp, Jim_Obj *strObjPtr, Jim_Obj *strClass, int strict)
8576 {
8577 static const char * const strclassnames[] = {
8578 "integer", "alpha", "alnum", "ascii", "digit",
8579 "double", "lower", "upper", "space", "xdigit",
8580 "control", "print", "graph", "punct",
8581 NULL
8582 };
8583 enum {
8584 STR_IS_INTEGER, STR_IS_ALPHA, STR_IS_ALNUM, STR_IS_ASCII, STR_IS_DIGIT,
8585 STR_IS_DOUBLE, STR_IS_LOWER, STR_IS_UPPER, STR_IS_SPACE, STR_IS_XDIGIT,
8586 STR_IS_CONTROL, STR_IS_PRINT, STR_IS_GRAPH, STR_IS_PUNCT
8587 };
8588 int strclass;
8589 int len;
8590 int i;
8591 const char *str;
@@ -8613,10 +8710,17 @@
8613 {
8614 double d;
8615 Jim_SetResultBool(interp, Jim_GetDouble(interp, strObjPtr, &d) == JIM_OK && errno != ERANGE);
8616 return JIM_OK;
8617 }
 
 
 
 
 
 
 
8618
8619 case STR_IS_ALPHA: isclassfunc = isalpha; break;
8620 case STR_IS_ALNUM: isclassfunc = isalnum; break;
8621 case STR_IS_ASCII: isclassfunc = jim_isascii; break;
8622 case STR_IS_DIGIT: isclassfunc = isdigit; break;
@@ -8631,11 +8735,11 @@
8631 default:
8632 return JIM_ERR;
8633 }
8634
8635 for (i = 0; i < len; i++) {
8636 if (!isclassfunc(str[i])) {
8637 Jim_SetResultBool(interp, 0);
8638 return JIM_OK;
8639 }
8640 }
8641 Jim_SetResultBool(interp, 1);
@@ -8656,20 +8760,18 @@
8656 {
8657 if (objPtr->typePtr == &comparedStringObjType && objPtr->internalRep.ptr == str) {
8658 return 1;
8659 }
8660 else {
8661 const char *objStr = Jim_String(objPtr);
8662
8663 if (strcmp(str, objStr) != 0)
8664 return 0;
8665
8666 if (objPtr->typePtr != &comparedStringObjType) {
8667 Jim_FreeIntRep(interp, objPtr);
8668 objPtr->typePtr = &comparedStringObjType;
8669 }
8670 objPtr->internalRep.ptr = (char *)str;
8671 return 1;
8672 }
8673 }
8674
8675 static int qsortCompareStringPointers(const void *a, const void *b)
@@ -8758,20 +8860,20 @@
8758 int type;
8759 } ScriptToken;
8760
8761 typedef struct ScriptObj
8762 {
8763 ScriptToken *token;
8764 Jim_Obj *fileNameObj;
8765 int len;
8766 int substFlags;
8767 int inUse; /* Used to share a ScriptObj. Currently
8768 only used by Jim_EvalObj() as protection against
8769 shimmering of the currently evaluated object. */
8770 int firstline;
8771 int linenr;
8772 int missing;
8773 } ScriptObj;
8774
8775 static void JimSetScriptFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr);
8776 static int JimParseCheckMissing(Jim_Interp *interp, int ch);
8777 static ScriptObj *JimGetScript(Jim_Interp *interp, Jim_Obj *objPtr);
@@ -8799,23 +8901,23 @@
8799 dupPtr->typePtr = NULL;
8800 }
8801
8802 typedef struct
8803 {
8804 const char *token;
8805 int len;
8806 int type;
8807 int line;
8808 } ParseToken;
8809
8810 typedef struct
8811 {
8812
8813 ParseToken *list;
8814 int size;
8815 int count;
8816 ParseToken static_list[20];
8817 } ParseTokenList;
8818
8819 static void ScriptTokenListInit(ParseTokenList *tokenlist)
8820 {
8821 tokenlist->list = tokenlist->static_list;
@@ -8834,18 +8936,18 @@
8834 int line)
8835 {
8836 ParseToken *t;
8837
8838 if (tokenlist->count == tokenlist->size) {
8839
8840 tokenlist->size *= 2;
8841 if (tokenlist->list != tokenlist->static_list) {
8842 tokenlist->list =
8843 Jim_Realloc(tokenlist->list, tokenlist->size * sizeof(*tokenlist->list));
8844 }
8845 else {
8846
8847 tokenlist->list = Jim_Alloc(tokenlist->size * sizeof(*tokenlist->list));
8848 memcpy(tokenlist->list, tokenlist->static_list,
8849 tokenlist->count * sizeof(*tokenlist->list));
8850 }
8851 }
@@ -8854,25 +8956,32 @@
8854 t->len = len;
8855 t->type = type;
8856 t->line = line;
8857 }
8858
8859 static int JimCountWordTokens(ParseToken *t)
8860 {
8861 int expand = 1;
8862 int count = 0;
8863
8864
8865 if (t->type == JIM_TT_STR && !TOKEN_IS_SEP(t[1].type)) {
8866 if ((t->len == 1 && *t->token == '*') || (t->len == 6 && strncmp(t->token, "expand", 6) == 0)) {
8867
8868 expand = -1;
8869 t++;
8870 }
 
 
 
 
 
 
 
8871 }
8872
8873
8874 while (!TOKEN_IS_SEP(t->type)) {
8875 t++;
8876 count++;
8877 }
8878
@@ -8882,11 +8991,11 @@
8882 static Jim_Obj *JimMakeScriptObj(Jim_Interp *interp, const ParseToken *t)
8883 {
8884 Jim_Obj *objPtr;
8885
8886 if (t->type == JIM_TT_ESC && memchr(t->token, '\\', t->len) != NULL) {
8887
8888 int len = t->len;
8889 char *str = Jim_Alloc(len + 1);
8890 len = JimEscape(str, t->token, len);
8891 objPtr = Jim_NewStringObjNoAlloc(interp, str, len);
8892 }
@@ -8899,13 +9008,13 @@
8899 static void ScriptObjAddTokens(Jim_Interp *interp, struct ScriptObj *script,
8900 ParseTokenList *tokenlist)
8901 {
8902 int i;
8903 struct ScriptToken *token;
8904
8905 int lineargs = 0;
8906
8907 ScriptToken *linefirst;
8908 int count;
8909 int linenr;
8910
8911 #ifdef DEBUG_SHOW_SCRIPT_TOKENS
@@ -8914,11 +9023,11 @@
8914 printf("[%2d]@%d %s '%.*s'\n", i, tokenlist->list[i].line, jim_tt_name(tokenlist->list[i].type),
8915 tokenlist->list[i].len, tokenlist->list[i].token);
8916 }
8917 #endif
8918
8919
8920 count = tokenlist->count;
8921 for (i = 0; i < tokenlist->count; i++) {
8922 if (tokenlist->list[i].type == JIM_TT_EOL) {
8923 count++;
8924 }
@@ -8925,59 +9034,59 @@
8925 }
8926 linenr = script->firstline = tokenlist->list[0].line;
8927
8928 token = script->token = Jim_Alloc(sizeof(ScriptToken) * count);
8929
8930
8931 linefirst = token++;
8932
8933 for (i = 0; i < tokenlist->count; ) {
8934
8935 int wordtokens;
8936
8937
8938 while (tokenlist->list[i].type == JIM_TT_SEP) {
8939 i++;
8940 }
8941
8942 wordtokens = JimCountWordTokens(tokenlist->list + i);
8943
8944 if (wordtokens == 0) {
8945
8946 if (lineargs) {
8947 linefirst->type = JIM_TT_LINE;
8948 linefirst->objPtr = JimNewScriptLineObj(interp, lineargs, linenr);
8949 Jim_IncrRefCount(linefirst->objPtr);
8950
8951
8952 lineargs = 0;
8953 linefirst = token++;
8954 }
8955 i++;
8956 continue;
8957 }
8958 else if (wordtokens != 1) {
8959
8960 token->type = JIM_TT_WORD;
8961 token->objPtr = Jim_NewIntObj(interp, wordtokens);
8962 Jim_IncrRefCount(token->objPtr);
8963 token++;
8964 if (wordtokens < 0) {
8965
8966 i++;
8967 wordtokens = -wordtokens - 1;
8968 lineargs--;
8969 }
8970 }
8971
8972 if (lineargs == 0) {
8973
8974 linenr = tokenlist->list[i].line;
8975 }
8976 lineargs++;
8977
8978
8979 while (wordtokens--) {
8980 const ParseToken *t = &tokenlist->list[i++];
8981
8982 token->type = t->type;
8983 token->objPtr = JimMakeScriptObj(interp, t);
@@ -9010,11 +9119,11 @@
9010 {
9011 ScriptObj *script = JimGetScript(interp, scriptObj);
9012 if (stateCharPtr) {
9013 *stateCharPtr = script->missing;
9014 }
9015 return (script->missing == ' ');
9016 }
9017
9018 static int JimParseCheckMissing(Jim_Interp *interp, int ch)
9019 {
9020 const char *msg;
@@ -9028,10 +9137,13 @@
9028 msg = "unmatched \"[\"";
9029 break;
9030 case '{':
9031 msg = "missing close-brace";
9032 break;
 
 
 
9033 case '"':
9034 default:
9035 msg = "missing quote";
9036 break;
9037 }
@@ -9049,11 +9161,11 @@
9049 token = script->token = Jim_Alloc(sizeof(ScriptToken) * tokenlist->count);
9050
9051 for (i = 0; i < tokenlist->count; i++) {
9052 const ParseToken *t = &tokenlist->list[i];
9053
9054
9055 token->type = t->type;
9056 token->objPtr = JimMakeScriptObj(interp, t);
9057 Jim_IncrRefCount(token->objPtr);
9058 token++;
9059 }
@@ -9068,29 +9180,29 @@
9068 struct JimParserCtx parser;
9069 struct ScriptObj *script;
9070 ParseTokenList tokenlist;
9071 int line = 1;
9072
9073
9074 if (objPtr->typePtr == &sourceObjType) {
9075 line = objPtr->internalRep.sourceValue.lineNumber;
9076 }
9077
9078
9079 ScriptTokenListInit(&tokenlist);
9080
9081 JimParserInit(&parser, scriptText, scriptTextLen, line);
9082 while (!parser.eof) {
9083 JimParseScript(&parser);
9084 ScriptAddToken(&tokenlist, parser.tstart, parser.tend - parser.tstart + 1, parser.tt,
9085 parser.tline);
9086 }
9087
9088
9089 ScriptAddToken(&tokenlist, scriptText + scriptTextLen, 0, JIM_TT_EOF, 0);
9090
9091
9092 script = Jim_Alloc(sizeof(*script));
9093 memset(script, 0, sizeof(*script));
9094 script->inUse = 1;
9095 if (objPtr->typePtr == &sourceObjType) {
9096 script->fileNameObj = objPtr->internalRep.sourceValue.fileNameObj;
@@ -9102,14 +9214,14 @@
9102 script->missing = parser.missing.ch;
9103 script->linenr = parser.missing.line;
9104
9105 ScriptObjAddTokens(interp, script, &tokenlist);
9106
9107
9108 ScriptTokenListFree(&tokenlist);
9109
9110
9111 Jim_FreeIntRep(interp, objPtr);
9112 Jim_SetIntRepPtr(objPtr, script);
9113 objPtr->typePtr = &scriptObjType;
9114 }
9115
@@ -9116,11 +9228,11 @@
9116 static void JimAddErrorToStack(Jim_Interp *interp, ScriptObj *script);
9117
9118 static ScriptObj *JimGetScript(Jim_Interp *interp, Jim_Obj *objPtr)
9119 {
9120 if (objPtr == interp->emptyObj) {
9121
9122 objPtr = interp->nullScriptObj;
9123 }
9124
9125 if (objPtr->typePtr != &scriptObjType || ((struct ScriptObj *)Jim_GetIntRepPtr(objPtr))->substFlags) {
9126 JimSetScriptFromAny(interp, objPtr);
@@ -9155,67 +9267,66 @@
9155 Jim_FreeHashTable(cmdPtr->u.proc.staticVars);
9156 Jim_Free(cmdPtr->u.proc.staticVars);
9157 }
9158 }
9159 else {
9160
9161 if (cmdPtr->u.native.delProc) {
9162 cmdPtr->u.native.delProc(interp, cmdPtr->u.native.privData);
9163 }
9164 }
9165 if (cmdPtr->prevCmd) {
9166
9167 JimDecrCmdRefCount(interp, cmdPtr->prevCmd);
9168 }
9169 Jim_Free(cmdPtr);
9170 }
9171 }
9172
9173
9174 static void JimVariablesHTValDestructor(void *interp, void *val)
9175 {
9176 Jim_DecrRefCount(interp, ((Jim_Var *)val)->objPtr);
9177 Jim_Free(val);
9178 }
9179
9180 static const Jim_HashTableType JimVariablesHashTableType = {
9181 JimStringCopyHTHashFunction,
9182 JimStringCopyHTDup,
9183 NULL,
9184 JimStringCopyHTKeyCompare,
9185 JimStringCopyHTKeyDestructor,
9186 JimVariablesHTValDestructor
9187 };
9188
9189 static void JimCommandsHT_ValDestructor(void *interp, void *val)
9190 {
9191 JimDecrCmdRefCount(interp, val);
9192 }
9193
9194 static const Jim_HashTableType JimCommandsHashTableType = {
9195 JimStringCopyHTHashFunction,
9196 JimStringCopyHTDup,
9197 NULL,
9198 JimStringCopyHTKeyCompare,
9199 JimStringCopyHTKeyDestructor,
9200 JimCommandsHT_ValDestructor
9201 };
9202
9203
9204
9205 #ifdef jim_ext_namespace
9206 static Jim_Obj *JimQualifyNameObj(Jim_Interp *interp, Jim_Obj *nsObj)
9207 {
9208 const char *name = Jim_String(nsObj);
9209 if (name[0] == ':' && name[1] == ':') {
9210
9211 while (*++name == ':') {
9212 }
9213 nsObj = Jim_NewStringObj(interp, name, -1);
9214 }
9215 else if (Jim_Length(interp->framePtr->nsObj)) {
9216
9217 nsObj = Jim_DuplicateObj(interp, interp->framePtr->nsObj);
9218 Jim_AppendStrings(interp, nsObj, "::", name, NULL);
9219 }
9220 return nsObj;
9221 }
@@ -9239,16 +9350,16 @@
9239 static const char *JimQualifyName(Jim_Interp *interp, const char *name, Jim_Obj **objPtrPtr)
9240 {
9241 Jim_Obj *objPtr = interp->emptyObj;
9242
9243 if (name[0] == ':' && name[1] == ':') {
9244
9245 while (*++name == ':') {
9246 }
9247 }
9248 else if (Jim_Length(interp->framePtr->nsObj)) {
9249
9250 objPtr = Jim_DuplicateObj(interp, interp->framePtr->nsObj);
9251 Jim_AppendStrings(interp, objPtr, "::", name, NULL);
9252 name = Jim_String(objPtr);
9253 }
9254 Jim_IncrRefCount(objPtr);
@@ -9257,11 +9368,11 @@
9257 }
9258
9259 #define JimFreeQualifiedName(INTERP, OBJ) Jim_DecrRefCount((INTERP), (OBJ))
9260
9261 #else
9262
9263 #define JimQualifyName(INTERP, NAME, DUMMY) (((NAME)[0] == ':' && (NAME)[1] == ':') ? (NAME) + 2 : (NAME))
9264 #define JimFreeQualifiedName(INTERP, DUMMY) (void)(DUMMY)
9265
9266 Jim_Obj *Jim_MakeGlobalNamespaceName(Jim_Interp *interp, Jim_Obj *nameObjPtr)
9267 {
@@ -9276,17 +9387,17 @@
9276
9277 Jim_InterpIncrProcEpoch(interp);
9278 }
9279
9280 if (he && interp->local) {
9281
9282 cmd->prevCmd = Jim_GetHashEntryVal(he);
9283 Jim_SetHashVal(&interp->commands, he, cmd);
9284 }
9285 else {
9286 if (he) {
9287
9288 Jim_DeleteHashEntry(&interp->commands, name);
9289 }
9290
9291 Jim_AddHashEntry(&interp->commands, name, cmd);
9292 }
@@ -9297,11 +9408,11 @@
9297 int Jim_CreateCommand(Jim_Interp *interp, const char *cmdNameStr,
9298 Jim_CmdProc *cmdProc, void *privData, Jim_DelCmdProc *delProc)
9299 {
9300 Jim_Cmd *cmdPtr = Jim_Alloc(sizeof(*cmdPtr));
9301
9302
9303 memset(cmdPtr, 0, sizeof(*cmdPtr));
9304 cmdPtr->inUse = 1;
9305 cmdPtr->u.native.delProc = delProc;
9306 cmdPtr->u.native.cmdProc = cmdProc;
9307 cmdPtr->u.native.privData = privData;
@@ -9326,11 +9437,11 @@
9326 Jim_Obj *objPtr, *initObjPtr, *nameObjPtr;
9327 Jim_Var *varPtr;
9328 int subLen;
9329
9330 objPtr = Jim_ListGetIndex(interp, staticsListObjPtr, i);
9331
9332 subLen = Jim_ListLength(interp, objPtr);
9333 if (subLen == 1 || subLen == 2) {
9334 nameObjPtr = Jim_ListGetIndex(interp, objPtr, 0);
9335 if (subLen == 1) {
9336 initObjPtr = Jim_GetVariable(interp, nameObjPtr, JIM_NONE);
@@ -9372,19 +9483,19 @@
9372
9373 static void JimUpdateProcNamespace(Jim_Interp *interp, Jim_Cmd *cmdPtr, const char *cmdname)
9374 {
9375 #ifdef jim_ext_namespace
9376 if (cmdPtr->isproc) {
9377
9378 const char *pt = strrchr(cmdname, ':');
9379 if (pt && pt != cmdname && pt[-1] == ':') {
9380 Jim_DecrRefCount(interp, cmdPtr->u.proc.nsObj);
9381 cmdPtr->u.proc.nsObj = Jim_NewStringObj(interp, cmdname, pt - cmdname - 1);
9382 Jim_IncrRefCount(cmdPtr->u.proc.nsObj);
9383
9384 if (Jim_FindHashEntry(&interp->commands, pt + 1)) {
9385
9386 Jim_InterpIncrProcEpoch(interp);
9387 }
9388 }
9389 }
9390 #endif
@@ -9397,11 +9508,11 @@
9397 int argListLen;
9398 int i;
9399
9400 argListLen = Jim_ListLength(interp, argListObjPtr);
9401
9402
9403 cmdPtr = Jim_Alloc(sizeof(*cmdPtr) + sizeof(struct Jim_ProcArg) * argListLen);
9404 memset(cmdPtr, 0, sizeof(*cmdPtr));
9405 cmdPtr->inUse = 1;
9406 cmdPtr->isproc = 1;
9407 cmdPtr->u.proc.argListObjPtr = argListObjPtr;
@@ -9412,24 +9523,24 @@
9412 cmdPtr->u.proc.nsObj = nsObj ? nsObj : interp->emptyObj;
9413 Jim_IncrRefCount(argListObjPtr);
9414 Jim_IncrRefCount(bodyObjPtr);
9415 Jim_IncrRefCount(cmdPtr->u.proc.nsObj);
9416
9417
9418 if (staticsListObjPtr && JimCreateProcedureStatics(interp, cmdPtr, staticsListObjPtr) != JIM_OK) {
9419 goto err;
9420 }
9421
9422
9423
9424 for (i = 0; i < argListLen; i++) {
9425 Jim_Obj *argPtr;
9426 Jim_Obj *nameObjPtr;
9427 Jim_Obj *defaultObjPtr;
9428 int len;
9429
9430
9431 argPtr = Jim_ListGetIndex(interp, argListObjPtr, i);
9432 len = Jim_ListLength(interp, argPtr);
9433 if (len == 0) {
9434 Jim_SetResultString(interp, "argument with no name", -1);
9435 err:
@@ -9440,16 +9551,16 @@
9440 Jim_SetResultFormatted(interp, "too many fields in argument specifier \"%#s\"", argPtr);
9441 goto err;
9442 }
9443
9444 if (len == 2) {
9445
9446 nameObjPtr = Jim_ListGetIndex(interp, argPtr, 0);
9447 defaultObjPtr = Jim_ListGetIndex(interp, argPtr, 1);
9448 }
9449 else {
9450
9451 nameObjPtr = argPtr;
9452 defaultObjPtr = NULL;
9453 }
9454
9455
@@ -9510,29 +9621,29 @@
9510 }
9511
9512 fqold = JimQualifyName(interp, oldName, &qualifiedOldNameObj);
9513 fqnew = JimQualifyName(interp, newName, &qualifiedNewNameObj);
9514
9515
9516 he = Jim_FindHashEntry(&interp->commands, fqold);
9517 if (he == NULL) {
9518 Jim_SetResultFormatted(interp, "can't rename \"%s\": command doesn't exist", oldName);
9519 }
9520 else if (Jim_FindHashEntry(&interp->commands, fqnew)) {
9521 Jim_SetResultFormatted(interp, "can't rename to \"%s\": command already exists", newName);
9522 }
9523 else {
9524
9525 cmdPtr = Jim_GetHashEntryVal(he);
9526 JimIncrCmdRefCount(cmdPtr);
9527 JimUpdateProcNamespace(interp, cmdPtr, fqnew);
9528 Jim_AddHashEntry(&interp->commands, fqnew, cmdPtr);
9529
9530
9531 Jim_DeleteHashEntry(&interp->commands, fqold);
9532
9533
9534 Jim_InterpIncrProcEpoch(interp);
9535
9536 ret = JIM_OK;
9537 }
9538
@@ -9571,23 +9682,23 @@
9571 objPtr->internalRep.cmdValue.procEpoch != interp->procEpoch
9572 #ifdef jim_ext_namespace
9573 || !Jim_StringEqObj(objPtr->internalRep.cmdValue.nsObj, interp->framePtr->nsObj)
9574 #endif
9575 ) {
9576
9577
9578
 
9579 const char *name = Jim_String(objPtr);
9580 Jim_HashEntry *he;
9581
9582 if (name[0] == ':' && name[1] == ':') {
9583 while (*++name == ':') {
9584 }
9585 }
9586 #ifdef jim_ext_namespace
9587 else if (Jim_Length(interp->framePtr->nsObj)) {
9588
9589 Jim_Obj *nameObj = Jim_DuplicateObj(interp, interp->framePtr->nsObj);
9590 Jim_AppendStrings(interp, nameObj, "::", name, NULL);
9591 he = Jim_FindHashEntry(&interp->commands, Jim_String(nameObj));
9592 Jim_FreeNewObj(interp, nameObj);
9593 if (he) {
@@ -9594,11 +9705,11 @@
9594 goto found;
9595 }
9596 }
9597 #endif
9598
9599
9600 he = Jim_FindHashEntry(&interp->commands, name);
9601 if (he == NULL) {
9602 if (flags & JIM_ERRMSG) {
9603 Jim_SetResultFormatted(interp, "invalid command name \"%#s\"", objPtr);
9604 }
@@ -9607,11 +9718,11 @@
9607 #ifdef jim_ext_namespace
9608 found:
9609 #endif
9610 cmd = Jim_GetHashEntryVal(he);
9611
9612
9613 Jim_FreeIntRep(interp, objPtr);
9614 objPtr->typePtr = &commandObjType;
9615 objPtr->internalRep.cmdValue.procEpoch = interp->procEpoch;
9616 objPtr->internalRep.cmdValue.cmdPtr = cmd;
9617 objPtr->internalRep.cmdValue.nsObj = interp->framePtr->nsObj;
@@ -9626,11 +9737,11 @@
9626 return cmd;
9627 }
9628
9629
9630
9631 #define JIM_DICT_SUGAR 100
9632
9633 static int SetVariableFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr);
9634
9635 static const Jim_ObjType variableObjType = {
9636 "variable",
@@ -9640,11 +9751,11 @@
9640 JIM_TYPE_REFERENCES,
9641 };
9642
9643 static int JimValidName(Jim_Interp *interp, const char *type, Jim_Obj *nameObjPtr)
9644 {
9645
9646 if (nameObjPtr->typePtr != &variableObjType) {
9647 int len;
9648 const char *str = Jim_GetString(nameObjPtr, &len);
9649 if (memchr(str, '\0', len)) {
9650 Jim_SetResultFormatted(interp, "%s name contains embedded null", type);
@@ -9660,18 +9771,18 @@
9660 Jim_CallFrame *framePtr;
9661 Jim_HashEntry *he;
9662 int global;
9663 int len;
9664
9665
9666 if (objPtr->typePtr == &variableObjType) {
9667 framePtr = objPtr->internalRep.varValue.global ? interp->topFramePtr : interp->framePtr;
9668 if (objPtr->internalRep.varValue.callFrameId == framePtr->id) {
9669
9670 return JIM_OK;
9671 }
9672
9673 }
9674 else if (objPtr->typePtr == &dictSubstObjType) {
9675 return JIM_DICT_SUGAR;
9676 }
9677 else if (JimValidName(interp, "variable", objPtr) != JIM_OK) {
@@ -9679,11 +9790,11 @@
9679 }
9680
9681
9682 varName = Jim_GetString(objPtr, &len);
9683
9684
9685 if (len && varName[len - 1] == ')' && strchr(varName, '(') != NULL) {
9686 return JIM_DICT_SUGAR;
9687 }
9688
9689 if (varName[0] == ':' && varName[1] == ':') {
@@ -9695,23 +9806,23 @@
9695 else {
9696 global = 0;
9697 framePtr = interp->framePtr;
9698 }
9699
9700
9701 he = Jim_FindHashEntry(&framePtr->vars, varName);
9702 if (he == NULL) {
9703 if (!global && framePtr->staticVars) {
9704
9705 he = Jim_FindHashEntry(framePtr->staticVars, varName);
9706 }
9707 if (he == NULL) {
9708 return JIM_ERR;
9709 }
9710 }
9711
9712
9713 Jim_FreeIntRep(interp, objPtr);
9714 objPtr->typePtr = &variableObjType;
9715 objPtr->internalRep.varValue.callFrameId = framePtr->id;
9716 objPtr->internalRep.varValue.varPtr = Jim_GetHashEntryVal(he);
9717 objPtr->internalRep.varValue.global = global;
@@ -9726,11 +9837,11 @@
9726 {
9727 const char *name;
9728 Jim_CallFrame *framePtr;
9729 int global;
9730
9731
9732 Jim_Var *var = Jim_Alloc(sizeof(*var));
9733
9734 var->objPtr = valObjPtr;
9735 Jim_IncrRefCount(valObjPtr);
9736 var->linkFramePtr = NULL;
@@ -9745,14 +9856,14 @@
9745 else {
9746 framePtr = interp->framePtr;
9747 global = 0;
9748 }
9749
9750
9751 Jim_AddHashEntry(&framePtr->vars, name, var);
9752
9753
9754 Jim_FreeIntRep(interp, nameObjPtr);
9755 nameObjPtr->typePtr = &variableObjType;
9756 nameObjPtr->internalRep.varValue.callFrameId = framePtr->id;
9757 nameObjPtr->internalRep.varValue.varPtr = var;
9758 nameObjPtr->internalRep.varValue.global = global;
@@ -9782,11 +9893,11 @@
9782 if (var->linkFramePtr == NULL) {
9783 Jim_IncrRefCount(valObjPtr);
9784 Jim_DecrRefCount(interp, var->objPtr);
9785 var->objPtr = valObjPtr;
9786 }
9787 else {
9788 Jim_CallFrame *savedCallFrame;
9789
9790 savedCallFrame = interp->framePtr;
9791 interp->framePtr = var->linkFramePtr;
9792 err = Jim_SetVariable(interp, var->objPtr, valObjPtr);
@@ -9822,19 +9933,16 @@
9822 return result;
9823 }
9824
9825 int Jim_SetVariableStrWithStr(Jim_Interp *interp, const char *name, const char *val)
9826 {
9827 Jim_Obj *nameObjPtr, *valObjPtr;
9828 int result;
9829
9830 nameObjPtr = Jim_NewStringObj(interp, name, -1);
9831 valObjPtr = Jim_NewStringObj(interp, val, -1);
9832 Jim_IncrRefCount(nameObjPtr);
9833 Jim_IncrRefCount(valObjPtr);
9834 result = Jim_SetVariable(interp, nameObjPtr, valObjPtr);
9835 Jim_DecrRefCount(interp, nameObjPtr);
9836 Jim_DecrRefCount(interp, valObjPtr);
9837 return result;
9838 }
9839
9840 int Jim_SetVariableLink(Jim_Interp *interp, Jim_Obj *nameObjPtr,
@@ -9843,14 +9951,14 @@
9843 const char *varName;
9844 const char *targetName;
9845 Jim_CallFrame *framePtr;
9846 Jim_Var *varPtr;
9847
9848
9849 switch (SetVariableFromAny(interp, nameObjPtr)) {
9850 case JIM_DICT_SUGAR:
9851
9852 Jim_SetResultFormatted(interp, "bad variable name \"%#s\": upvar won't create a scalar variable that looks like an array element", nameObjPtr);
9853 return JIM_ERR;
9854
9855 case JIM_OK:
9856 varPtr = nameObjPtr->internalRep.varValue.varPtr;
@@ -9858,23 +9966,23 @@
9858 if (varPtr->linkFramePtr == NULL) {
9859 Jim_SetResultFormatted(interp, "variable \"%#s\" already exists", nameObjPtr);
9860 return JIM_ERR;
9861 }
9862
9863
9864 varPtr->linkFramePtr = NULL;
9865 break;
9866 }
9867
9868
9869
9870 varName = Jim_String(nameObjPtr);
9871
9872 if (varName[0] == ':' && varName[1] == ':') {
9873 while (*++varName == ':') {
9874 }
9875
9876 framePtr = interp->topFramePtr;
9877 }
9878 else {
9879 framePtr = interp->framePtr;
9880 }
@@ -9894,15 +10002,15 @@
9894 nameObjPtr);
9895 Jim_DecrRefCount(interp, targetNameObjPtr);
9896 return JIM_ERR;
9897 }
9898
9899
9900 if (framePtr == targetCallFrame) {
9901 Jim_Obj *objPtr = targetNameObjPtr;
9902
9903
9904 while (1) {
9905 if (strcmp(Jim_String(objPtr), varName) == 0) {
9906 Jim_SetResultString(interp, "can't upvar from variable to itself", -1);
9907 Jim_DecrRefCount(interp, targetNameObjPtr);
9908 return JIM_ERR;
@@ -9914,13 +10022,13 @@
9914 break;
9915 objPtr = varPtr->objPtr;
9916 }
9917 }
9918
9919
9920 Jim_SetVariable(interp, nameObjPtr, targetNameObjPtr);
9921
9922 nameObjPtr->internalRep.varValue.varPtr->linkFramePtr = targetCallFrame;
9923 Jim_DecrRefCount(interp, targetNameObjPtr);
9924 return JIM_OK;
9925 }
9926
@@ -9934,26 +10042,26 @@
9934 return varPtr->objPtr;
9935 }
9936 else {
9937 Jim_Obj *objPtr;
9938
9939
9940 Jim_CallFrame *savedCallFrame = interp->framePtr;
9941
9942 interp->framePtr = varPtr->linkFramePtr;
9943 objPtr = Jim_GetVariable(interp, varPtr->objPtr, flags);
9944 interp->framePtr = savedCallFrame;
9945 if (objPtr) {
9946 return objPtr;
9947 }
9948
9949 }
9950 }
9951 break;
9952
9953 case JIM_DICT_SUGAR:
9954
9955 return JimDictSugarGet(interp, nameObjPtr, flags);
9956 }
9957 if (flags & JIM_ERRMSG) {
9958 Jim_SetResultFormatted(interp, "can't read \"%#s\": no such variable", nameObjPtr);
9959 }
@@ -10003,17 +10111,17 @@
10003 int retval;
10004 Jim_CallFrame *framePtr;
10005
10006 retval = SetVariableFromAny(interp, nameObjPtr);
10007 if (retval == JIM_DICT_SUGAR) {
10008
10009 return JimDictSugarSet(interp, nameObjPtr, NULL);
10010 }
10011 else if (retval == JIM_OK) {
10012 varPtr = nameObjPtr->internalRep.varValue.varPtr;
10013
10014
10015 if (varPtr->linkFramePtr) {
10016 framePtr = interp->framePtr;
10017 interp->framePtr = varPtr->linkFramePtr;
10018 retval = Jim_UnsetVariable(interp, varPtr->objPtr, JIM_NONE);
10019 interp->framePtr = framePtr;
@@ -10028,11 +10136,11 @@
10028 framePtr = interp->framePtr;
10029 }
10030
10031 retval = Jim_DeleteHashEntry(&framePtr->vars, name);
10032 if (retval == JIM_OK) {
10033
10034 framePtr->id = interp->callFrameEpoch++;
10035 }
10036 }
10037 }
10038 if (retval != JIM_OK && (flags & JIM_ERRMSG)) {
@@ -10061,11 +10169,11 @@
10061 keyLen = (str + len) - p;
10062 if (str[len - 1] == ')') {
10063 keyLen--;
10064 }
10065
10066
10067 keyObjPtr = Jim_NewStringObj(interp, p, keyLen);
10068
10069 Jim_IncrRefCount(varObjPtr);
10070 Jim_IncrRefCount(keyObjPtr);
10071 *varPtrPtr = varObjPtr;
@@ -10080,23 +10188,23 @@
10080
10081 err = Jim_SetDictKeysVector(interp, objPtr->internalRep.dictSubstValue.varNameObjPtr,
10082 &objPtr->internalRep.dictSubstValue.indexObjPtr, 1, valObjPtr, JIM_MUSTEXIST);
10083
10084 if (err == JIM_OK) {
10085
10086 Jim_SetEmptyResult(interp);
10087 }
10088 else {
10089 if (!valObjPtr) {
10090
10091 if (Jim_GetVariable(interp, objPtr->internalRep.dictSubstValue.varNameObjPtr, JIM_NONE)) {
10092 Jim_SetResultFormatted(interp, "can't unset \"%#s\": no such element in array",
10093 objPtr);
10094 return err;
10095 }
10096 }
10097
10098 Jim_SetResultFormatted(interp, "can't %s \"%#s\": variable isn't array",
10099 (valObjPtr ? "set" : "unset"), objPtr);
10100 }
10101 return err;
10102 }
@@ -10118,11 +10226,11 @@
10118 Jim_SetResultFormatted(interp,
10119 "can't read \"%#s(%#s)\": %s array", varObjPtr, keyObjPtr,
10120 ret < 0 ? "variable isn't" : "no such element in");
10121 }
10122 else if ((flags & JIM_UNSHARED) && Jim_IsShared(dictObjPtr)) {
10123
10124 Jim_SetVariable(interp, varObjPtr, Jim_DuplicateObj(interp, dictObjPtr));
10125 }
10126
10127 return resObjPtr;
10128 }
@@ -10143,28 +10251,27 @@
10143 {
10144 Jim_DecrRefCount(interp, objPtr->internalRep.dictSubstValue.varNameObjPtr);
10145 Jim_DecrRefCount(interp, objPtr->internalRep.dictSubstValue.indexObjPtr);
10146 }
10147
10148 void DupDictSubstInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr)
10149 {
10150 JIM_NOTUSED(interp);
10151
10152 dupPtr->internalRep.dictSubstValue.varNameObjPtr =
10153 srcPtr->internalRep.dictSubstValue.varNameObjPtr;
10154 dupPtr->internalRep.dictSubstValue.indexObjPtr = srcPtr->internalRep.dictSubstValue.indexObjPtr;
10155 dupPtr->typePtr = &dictSubstObjType;
10156 }
10157
10158
10159 static void SetDictSubstFromAny(Jim_Interp *interp, Jim_Obj *objPtr)
10160 {
10161 if (objPtr->typePtr != &dictSubstObjType) {
10162 Jim_Obj *varObjPtr, *keyObjPtr;
10163
10164 if (objPtr->typePtr == &interpolatedObjType) {
10165
10166
10167 varObjPtr = objPtr->internalRep.dictSubstValue.varNameObjPtr;
10168 keyObjPtr = objPtr->internalRep.dictSubstValue.indexObjPtr;
10169
10170 Jim_IncrRefCount(varObjPtr);
@@ -10202,16 +10309,12 @@
10202 return resObjPtr;
10203 }
10204
10205 static Jim_Obj *JimExpandExprSugar(Jim_Interp *interp, Jim_Obj *objPtr)
10206 {
10207 Jim_Obj *resultObjPtr;
10208
10209 if (Jim_EvalExpression(interp, objPtr, &resultObjPtr) == JIM_OK) {
10210
10211 resultObjPtr->refCount--;
10212 return resultObjPtr;
10213 }
10214 return NULL;
10215 }
10216
10217
@@ -10249,11 +10352,11 @@
10249 return cf;
10250 }
10251
10252 static int JimDeleteLocalProcs(Jim_Interp *interp, Jim_Stack *localCommands)
10253 {
10254
10255 if (localCommands) {
10256 Jim_Obj *cmdNameObj;
10257
10258 while ((cmdNameObj = Jim_StackPop(localCommands)) != NULL) {
10259 Jim_HashEntry *he;
@@ -10268,20 +10371,20 @@
10268 Jim_Cmd *cmd = Jim_GetHashEntryVal(he);
10269 if (cmd->prevCmd) {
10270 Jim_Cmd *prevCmd = cmd->prevCmd;
10271 cmd->prevCmd = NULL;
10272
10273
10274 JimDecrCmdRefCount(interp, cmd);
10275
10276
10277 Jim_SetHashVal(ht, he, prevCmd);
10278 }
10279 else {
10280 Jim_DeleteHashEntry(ht, fqname);
10281 Jim_InterpIncrProcEpoch(interp);
10282 }
 
10283 }
10284 Jim_DecrRefCount(interp, cmdNameObj);
10285 JimFreeQualifiedName(interp, fqObjName);
10286 }
10287 Jim_FreeStack(localCommands);
@@ -10288,13 +10391,59 @@
10288 Jim_Free(localCommands);
10289 }
10290 return JIM_OK;
10291 }
10292
 
 
 
10293
10294 #define JIM_FCF_FULL 0
10295 #define JIM_FCF_REUSE 1
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
10296 static void JimFreeCallFrame(Jim_Interp *interp, Jim_CallFrame *cf, int action)
10297 {
10298 JimDeleteLocalProcs(interp, cf->localCommands);
10299
10300 if (cf->procArgsObjPtr)
@@ -10327,263 +10476,10 @@
10327 cf->next = interp->freeFramesList;
10328 interp->freeFramesList = cf;
10329 }
10330
10331
10332 #ifdef JIM_REFERENCES
10333
10334 static void JimReferencesHTValDestructor(void *interp, void *val)
10335 {
10336 Jim_Reference *refPtr = (void *)val;
10337
10338 Jim_DecrRefCount(interp, refPtr->objPtr);
10339 if (refPtr->finalizerCmdNamePtr != NULL) {
10340 Jim_DecrRefCount(interp, refPtr->finalizerCmdNamePtr);
10341 }
10342 Jim_Free(val);
10343 }
10344
10345 static unsigned int JimReferencesHTHashFunction(const void *key)
10346 {
10347
10348 const unsigned long *widePtr = key;
10349 unsigned int intValue = (unsigned int)*widePtr;
10350
10351 return Jim_IntHashFunction(intValue);
10352 }
10353
10354 static void *JimReferencesHTKeyDup(void *privdata, const void *key)
10355 {
10356 void *copy = Jim_Alloc(sizeof(unsigned long));
10357
10358 JIM_NOTUSED(privdata);
10359
10360 memcpy(copy, key, sizeof(unsigned long));
10361 return copy;
10362 }
10363
10364 static int JimReferencesHTKeyCompare(void *privdata, const void *key1, const void *key2)
10365 {
10366 JIM_NOTUSED(privdata);
10367
10368 return memcmp(key1, key2, sizeof(unsigned long)) == 0;
10369 }
10370
10371 static void JimReferencesHTKeyDestructor(void *privdata, void *key)
10372 {
10373 JIM_NOTUSED(privdata);
10374
10375 Jim_Free(key);
10376 }
10377
10378 static const Jim_HashTableType JimReferencesHashTableType = {
10379 JimReferencesHTHashFunction,
10380 JimReferencesHTKeyDup,
10381 NULL,
10382 JimReferencesHTKeyCompare,
10383 JimReferencesHTKeyDestructor,
10384 JimReferencesHTValDestructor
10385 };
10386
10387
10388
10389 #define JIM_REFERENCE_SPACE (35+JIM_REFERENCE_TAGLEN)
10390
10391 static int JimFormatReference(char *buf, Jim_Reference *refPtr, unsigned long id)
10392 {
10393 const char *fmt = "<reference.<%s>.%020lu>";
10394
10395 sprintf(buf, fmt, refPtr->tag, id);
10396 return JIM_REFERENCE_SPACE;
10397 }
10398
10399 static void UpdateStringOfReference(struct Jim_Obj *objPtr);
10400
10401 static const Jim_ObjType referenceObjType = {
10402 "reference",
10403 NULL,
10404 NULL,
10405 UpdateStringOfReference,
10406 JIM_TYPE_REFERENCES,
10407 };
10408
10409 static void UpdateStringOfReference(struct Jim_Obj *objPtr)
10410 {
10411 char buf[JIM_REFERENCE_SPACE + 1];
10412
10413 JimFormatReference(buf, objPtr->internalRep.refValue.refPtr, objPtr->internalRep.refValue.id);
10414 JimSetStringBytes(objPtr, buf);
10415 }
10416
10417 static int isrefchar(int c)
10418 {
10419 return (c == '_' || isalnum(c));
10420 }
10421
10422 static int SetReferenceFromAny(Jim_Interp *interp, Jim_Obj *objPtr)
10423 {
10424 unsigned long value;
10425 int i, len;
10426 const char *str, *start, *end;
10427 char refId[21];
10428 Jim_Reference *refPtr;
10429 Jim_HashEntry *he;
10430 char *endptr;
10431
10432
10433 str = Jim_GetString(objPtr, &len);
10434
10435 if (len < JIM_REFERENCE_SPACE)
10436 goto badformat;
10437
10438 start = str;
10439 end = str + len - 1;
10440 while (*start == ' ')
10441 start++;
10442 while (*end == ' ' && end > start)
10443 end--;
10444 if (end - start + 1 != JIM_REFERENCE_SPACE)
10445 goto badformat;
10446
10447 if (memcmp(start, "<reference.<", 12) != 0)
10448 goto badformat;
10449 if (start[12 + JIM_REFERENCE_TAGLEN] != '>' || end[0] != '>')
10450 goto badformat;
10451
10452 for (i = 0; i < JIM_REFERENCE_TAGLEN; i++) {
10453 if (!isrefchar(start[12 + i]))
10454 goto badformat;
10455 }
10456
10457 memcpy(refId, start + 14 + JIM_REFERENCE_TAGLEN, 20);
10458 refId[20] = '\0';
10459
10460 value = strtoul(refId, &endptr, 10);
10461 if (JimCheckConversion(refId, endptr) != JIM_OK)
10462 goto badformat;
10463
10464 he = Jim_FindHashEntry(&interp->references, &value);
10465 if (he == NULL) {
10466 Jim_SetResultFormatted(interp, "invalid reference id \"%#s\"", objPtr);
10467 return JIM_ERR;
10468 }
10469 refPtr = Jim_GetHashEntryVal(he);
10470
10471 Jim_FreeIntRep(interp, objPtr);
10472 objPtr->typePtr = &referenceObjType;
10473 objPtr->internalRep.refValue.id = value;
10474 objPtr->internalRep.refValue.refPtr = refPtr;
10475 return JIM_OK;
10476
10477 badformat:
10478 Jim_SetResultFormatted(interp, "expected reference but got \"%#s\"", objPtr);
10479 return JIM_ERR;
10480 }
10481
10482 Jim_Obj *Jim_NewReference(Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj *tagPtr, Jim_Obj *cmdNamePtr)
10483 {
10484 struct Jim_Reference *refPtr;
10485 unsigned long id;
10486 Jim_Obj *refObjPtr;
10487 const char *tag;
10488 int tagLen, i;
10489
10490
10491 Jim_CollectIfNeeded(interp);
10492
10493 refPtr = Jim_Alloc(sizeof(*refPtr));
10494 refPtr->objPtr = objPtr;
10495 Jim_IncrRefCount(objPtr);
10496 refPtr->finalizerCmdNamePtr = cmdNamePtr;
10497 if (cmdNamePtr)
10498 Jim_IncrRefCount(cmdNamePtr);
10499 id = interp->referenceNextId++;
10500 Jim_AddHashEntry(&interp->references, &id, refPtr);
10501 refObjPtr = Jim_NewObj(interp);
10502 refObjPtr->typePtr = &referenceObjType;
10503 refObjPtr->bytes = NULL;
10504 refObjPtr->internalRep.refValue.id = id;
10505 refObjPtr->internalRep.refValue.refPtr = refPtr;
10506 interp->referenceNextId++;
10507 tag = Jim_GetString(tagPtr, &tagLen);
10508 if (tagLen > JIM_REFERENCE_TAGLEN)
10509 tagLen = JIM_REFERENCE_TAGLEN;
10510 for (i = 0; i < JIM_REFERENCE_TAGLEN; i++) {
10511 if (i < tagLen && isrefchar(tag[i]))
10512 refPtr->tag[i] = tag[i];
10513 else
10514 refPtr->tag[i] = '_';
10515 }
10516 refPtr->tag[JIM_REFERENCE_TAGLEN] = '\0';
10517 return refObjPtr;
10518 }
10519
10520 Jim_Reference *Jim_GetReference(Jim_Interp *interp, Jim_Obj *objPtr)
10521 {
10522 if (objPtr->typePtr != &referenceObjType && SetReferenceFromAny(interp, objPtr) == JIM_ERR)
10523 return NULL;
10524 return objPtr->internalRep.refValue.refPtr;
10525 }
10526
10527 int Jim_SetFinalizer(Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj *cmdNamePtr)
10528 {
10529 Jim_Reference *refPtr;
10530
10531 if ((refPtr = Jim_GetReference(interp, objPtr)) == NULL)
10532 return JIM_ERR;
10533 Jim_IncrRefCount(cmdNamePtr);
10534 if (refPtr->finalizerCmdNamePtr)
10535 Jim_DecrRefCount(interp, refPtr->finalizerCmdNamePtr);
10536 refPtr->finalizerCmdNamePtr = cmdNamePtr;
10537 return JIM_OK;
10538 }
10539
10540 int Jim_GetFinalizer(Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj **cmdNamePtrPtr)
10541 {
10542 Jim_Reference *refPtr;
10543
10544 if ((refPtr = Jim_GetReference(interp, objPtr)) == NULL)
10545 return JIM_ERR;
10546 *cmdNamePtrPtr = refPtr->finalizerCmdNamePtr;
10547 return JIM_OK;
10548 }
10549
10550
10551
10552 static const Jim_HashTableType JimRefMarkHashTableType = {
10553 JimReferencesHTHashFunction,
10554 JimReferencesHTKeyDup,
10555 NULL,
10556 JimReferencesHTKeyCompare,
10557 JimReferencesHTKeyDestructor,
10558 NULL
10559 };
10560
10561
10562 int Jim_Collect(Jim_Interp *interp)
10563 {
10564 int collected = 0;
10565 return collected;
10566 }
10567
10568 #define JIM_COLLECT_ID_PERIOD 5000
10569 #define JIM_COLLECT_TIME_PERIOD 300
10570
10571 void Jim_CollectIfNeeded(Jim_Interp *interp)
10572 {
10573 unsigned long elapsedId;
10574 int elapsedTime;
10575
10576 elapsedId = interp->referenceNextId - interp->lastCollectId;
10577 elapsedTime = time(NULL) - interp->lastCollectTime;
10578
10579
10580 if (elapsedId > JIM_COLLECT_ID_PERIOD || elapsedTime > JIM_COLLECT_TIME_PERIOD) {
10581 Jim_Collect(interp);
10582 }
10583 }
10584 #endif
10585
10586 int Jim_IsBigEndian(void)
10587 {
10588 union {
10589 unsigned short s;
@@ -10630,11 +10526,11 @@
10630 Jim_IncrRefCount(i->nullScriptObj);
10631 Jim_IncrRefCount(i->errorProc);
10632 Jim_IncrRefCount(i->trueObj);
10633 Jim_IncrRefCount(i->falseObj);
10634
10635
10636 Jim_SetVariableStrWithStr(i, JIM_LIBPATH, TCL_LIBRARY);
10637 Jim_SetVariableStrWithStr(i, JIM_INTERACTIVE, "0");
10638
10639 Jim_SetVariableStrWithStr(i, "tcl_platform(engine)", "Jim");
10640 Jim_SetVariableStrWithStr(i, "tcl_platform(os)", TCL_PLATFORM_OS);
@@ -10652,12 +10548,14 @@
10652 {
10653 Jim_CallFrame *cf, *cfx;
10654
10655 Jim_Obj *objPtr, *nextObjPtr;
10656
10657
10658 for (cf = i->framePtr; cf; cf = cfx) {
 
 
10659 cfx = cf->parent;
10660 JimFreeCallFrame(i, cf, JIM_FCF_FULL);
10661 }
10662
10663 Jim_DecrRefCount(i, i->emptyObj);
@@ -10684,10 +10582,11 @@
10684
10685 printf("\n-------------------------------------\n");
10686 printf("Objects still in the free list:\n");
10687 while (objPtr) {
10688 const char *type = objPtr->typePtr ? objPtr->typePtr->name : "string";
 
10689
10690 if (objPtr->bytes && strlen(objPtr->bytes) > 20) {
10691 printf("%p (%d) %-10s: '%.20s...'\n",
10692 (void *)objPtr, objPtr->refCount, type, objPtr->bytes);
10693 }
@@ -10705,27 +10604,27 @@
10705 printf("-------------------------------------\n\n");
10706 JimPanic((1, "Live list non empty freeing the interpreter! Leak?"));
10707 }
10708 #endif
10709
10710
10711 objPtr = i->freeList;
10712 while (objPtr) {
10713 nextObjPtr = objPtr->nextObjPtr;
10714 Jim_Free(objPtr);
10715 objPtr = nextObjPtr;
10716 }
10717
10718
10719 for (cf = i->freeFramesList; cf; cf = cfx) {
10720 cfx = cf->next;
10721 if (cf->vars.table)
10722 Jim_FreeHashTable(&cf->vars);
10723 Jim_Free(cf);
10724 }
10725
10726
10727 Jim_Free(i);
10728 }
10729
10730 Jim_CallFrame *Jim_GetCallFrameByLevel(Jim_Interp *interp, Jim_Obj *levelObjPtr)
10731 {
@@ -10746,25 +10645,25 @@
10746 else {
10747 if (Jim_GetLong(interp, levelObjPtr, &level) != JIM_OK || level < 0) {
10748 level = -1;
10749 }
10750 else {
10751
10752 level = interp->framePtr->level - level;
10753 }
10754 }
10755 }
10756 else {
10757 str = "1";
10758 level = interp->framePtr->level - 1;
10759 }
10760
10761 if (level == 0) {
10762 return interp->topFramePtr;
10763 }
10764 if (level > 0) {
10765
10766 for (framePtr = interp->framePtr; framePtr; framePtr = framePtr->parent) {
10767 if (framePtr->level == level) {
10768 return framePtr;
10769 }
10770 }
@@ -10779,19 +10678,19 @@
10779 long level;
10780 Jim_CallFrame *framePtr;
10781
10782 if (Jim_GetLong(interp, levelObjPtr, &level) == JIM_OK) {
10783 if (level <= 0) {
10784
10785 level = interp->framePtr->level + level;
10786 }
10787
10788 if (level == 0) {
10789 return interp->topFramePtr;
10790 }
10791
10792
10793 for (framePtr = interp->framePtr; framePtr; framePtr = framePtr->parent) {
10794 if (framePtr->level == level) {
10795 return framePtr;
10796 }
10797 }
@@ -10810,11 +10709,11 @@
10810
10811 static void JimSetStackTrace(Jim_Interp *interp, Jim_Obj *stackTraceObj)
10812 {
10813 int len;
10814
10815
10816 Jim_IncrRefCount(stackTraceObj);
10817 Jim_DecrRefCount(interp, interp->stackTrace);
10818 interp->stackTrace = stackTraceObj;
10819 interp->errorFlag = 1;
10820
@@ -10831,32 +10730,32 @@
10831 {
10832 if (strcmp(procname, "unknown") == 0) {
10833 procname = "";
10834 }
10835 if (!*procname && !Jim_Length(fileNameObj)) {
10836
10837 return;
10838 }
10839
10840 if (Jim_IsShared(interp->stackTrace)) {
10841 Jim_DecrRefCount(interp, interp->stackTrace);
10842 interp->stackTrace = Jim_DuplicateObj(interp, interp->stackTrace);
10843 Jim_IncrRefCount(interp->stackTrace);
10844 }
10845
10846
10847 if (!*procname && Jim_Length(fileNameObj)) {
10848
10849 int len = Jim_ListLength(interp, interp->stackTrace);
10850
10851 if (len >= 3) {
10852 Jim_Obj *objPtr = Jim_ListGetIndex(interp, interp->stackTrace, len - 3);
10853 if (Jim_Length(objPtr)) {
10854
10855 objPtr = Jim_ListGetIndex(interp, interp->stackTrace, len - 2);
10856 if (Jim_Length(objPtr) == 0) {
10857
10858 ListSetIndex(interp, interp->stackTrace, len - 2, fileNameObj, 0);
10859 ListSetIndex(interp, interp->stackTrace, len - 1, Jim_NewIntObj(interp, linenr), 0);
10860 return;
10861 }
10862 }
@@ -10958,18 +10857,18 @@
10958 {
10959 jim_wide wideValue;
10960 const char *str;
10961
10962 if (objPtr->typePtr == &coercedDoubleObjType) {
10963
10964 objPtr->typePtr = &intObjType;
10965 return JIM_OK;
10966 }
10967
10968
10969 str = Jim_String(objPtr);
10970
10971 if (Jim_StringToWide(str, &wideValue, 0) != JIM_OK) {
10972 if (flags & JIM_ERRMSG) {
10973 Jim_SetResultFormatted(interp, "expected integer but got \"%#s\"", objPtr);
10974 }
10975 return JIM_ERR;
@@ -10976,11 +10875,11 @@
10976 }
10977 if ((wideValue == JIM_WIDE_MIN || wideValue == JIM_WIDE_MAX) && errno == ERANGE) {
10978 Jim_SetResultString(interp, "Integer value too big to be represented", -1);
10979 return JIM_ERR;
10980 }
10981
10982 Jim_FreeIntRep(interp, objPtr);
10983 objPtr->typePtr = &intObjType;
10984 objPtr->internalRep.wideValue = wideValue;
10985 return JIM_OK;
10986 }
@@ -11075,17 +10974,17 @@
11075 {
11076 char buf[JIM_DOUBLE_SPACE + 1];
11077 int i;
11078 int len = sprintf(buf, "%.12g", value);
11079
11080
11081 for (i = 0; i < len; i++) {
11082 if (buf[i] == '.' || buf[i] == 'e') {
11083 #if defined(JIM_SPRINTF_DOUBLE_NEEDS_FIX)
11084 char *e = strchr(buf, 'e');
11085 if (e && (e[1] == '-' || e[1] == '+') && e[2] == '0') {
11086
11087 e += 2;
11088 memmove(e, e + 1, len - (e - buf));
11089 }
11090 #endif
11091 break;
@@ -11104,41 +11003,40 @@
11104 {
11105 double doubleValue;
11106 jim_wide wideValue;
11107 const char *str;
11108
11109 str = Jim_String(objPtr);
11110
11111 #ifdef HAVE_LONG_LONG
11112
11113 #define MIN_INT_IN_DOUBLE -(1LL << 53)
11114 #define MAX_INT_IN_DOUBLE -(MIN_INT_IN_DOUBLE + 1)
11115
11116 if (objPtr->typePtr == &intObjType
11117 && JimWideValue(objPtr) >= MIN_INT_IN_DOUBLE
11118 && JimWideValue(objPtr) <= MAX_INT_IN_DOUBLE) {
11119
11120
11121 objPtr->typePtr = &coercedDoubleObjType;
11122 return JIM_OK;
11123 }
11124 else
11125 #endif
 
 
11126 if (Jim_StringToWide(str, &wideValue, 10) == JIM_OK) {
11127
11128 Jim_FreeIntRep(interp, objPtr);
11129 objPtr->typePtr = &coercedDoubleObjType;
11130 objPtr->internalRep.wideValue = wideValue;
11131 return JIM_OK;
11132 }
11133 else {
11134
11135 if (Jim_StringToDouble(str, &doubleValue) != JIM_OK) {
11136 Jim_SetResultFormatted(interp, "expected floating-point number but got \"%#s\"", objPtr);
11137 return JIM_ERR;
11138 }
11139
11140 Jim_FreeIntRep(interp, objPtr);
11141 }
11142 objPtr->typePtr = &doubleObjType;
11143 objPtr->internalRep.doubleValue = doubleValue;
11144 return JIM_OK;
@@ -11170,10 +11068,50 @@
11170 objPtr->typePtr = &doubleObjType;
11171 objPtr->bytes = NULL;
11172 objPtr->internalRep.doubleValue = doubleValue;
11173 return objPtr;
11174 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
11175
11176 static void ListInsertElements(Jim_Obj *listPtr, int idx, int elemc, Jim_Obj *const *elemVec);
11177 static void ListAppendElement(Jim_Obj *listPtr, Jim_Obj *objPtr);
11178 static void FreeListInternalRep(Jim_Interp *interp, Jim_Obj *objPtr);
11179 static void DupListInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr);
@@ -11221,11 +11159,11 @@
11221 #define JIM_ELESTR_QUOTE 2
11222 static unsigned char ListElementQuotingType(const char *s, int len)
11223 {
11224 int i, level, blevel, trySimple = 1;
11225
11226
11227 if (len == 0)
11228 return JIM_ELESTR_BRACE;
11229 if (s[0] == '"' || s[0] == '{') {
11230 trySimple = 0;
11231 goto testbrace;
@@ -11243,20 +11181,20 @@
11243 case '\n':
11244 case '\t':
11245 case '\f':
11246 case '\v':
11247 trySimple = 0;
11248
11249 case '{':
11250 case '}':
11251 goto testbrace;
11252 }
11253 }
11254 return JIM_ELESTR_SIMPLE;
11255
11256 testbrace:
11257
11258 if (s[len - 1] == '\\')
11259 return JIM_ELESTR_QUOTE;
11260 level = 0;
11261 blevel = 0;
11262 for (i = 0; i < len; i++) {
@@ -11372,11 +11310,11 @@
11372 int i, bufLen, realLength;
11373 const char *strRep;
11374 char *p;
11375 unsigned char *quotingType, staticQuoting[STATIC_QUOTING_LEN];
11376
11377
11378 if (objc > STATIC_QUOTING_LEN) {
11379 quotingType = Jim_Alloc(objc);
11380 }
11381 else {
11382 quotingType = staticQuoting;
@@ -11391,25 +11329,25 @@
11391 case JIM_ELESTR_SIMPLE:
11392 if (i != 0 || strRep[0] != '#') {
11393 bufLen += len;
11394 break;
11395 }
11396
11397 quotingType[i] = JIM_ELESTR_BRACE;
11398
11399 case JIM_ELESTR_BRACE:
11400 bufLen += len + 2;
11401 break;
11402 case JIM_ELESTR_QUOTE:
11403 bufLen += len * 2;
11404 break;
11405 }
11406 bufLen++;
11407 }
11408 bufLen++;
11409
11410
11411 p = objPtr->bytes = Jim_Alloc(bufLen + 1);
11412 realLength = 0;
11413 for (i = 0; i < objc; i++) {
11414 int len, qlen;
11415
@@ -11436,17 +11374,17 @@
11436 qlen = BackslashQuoteString(strRep, len, p);
11437 p += qlen;
11438 realLength += qlen;
11439 break;
11440 }
11441
11442 if (i + 1 != objc) {
11443 *p++ = ' ';
11444 realLength++;
11445 }
11446 }
11447 *p = '\0';
11448 objPtr->length = realLength;
11449
11450 if (quotingType != staticQuoting) {
11451 Jim_Free(quotingType);
11452 }
@@ -11477,21 +11415,21 @@
11477 listObjPtrPtr = JimDictPairs(objPtr, &len);
11478 for (i = 0; i < len; i++) {
11479 Jim_IncrRefCount(listObjPtrPtr[i]);
11480 }
11481
11482
11483 Jim_FreeIntRep(interp, objPtr);
11484 objPtr->typePtr = &listObjType;
11485 objPtr->internalRep.listValue.len = len;
11486 objPtr->internalRep.listValue.maxLen = len;
11487 objPtr->internalRep.listValue.ele = listObjPtrPtr;
11488
11489 return JIM_OK;
11490 }
11491
11492
11493 if (objPtr->typePtr == &sourceObjType) {
11494 fileNameObj = objPtr->internalRep.sourceValue.fileNameObj;
11495 linenr = objPtr->internalRep.sourceValue.lineNumber;
11496 }
11497 else {
@@ -11498,20 +11436,20 @@
11498 fileNameObj = interp->emptyObj;
11499 linenr = 1;
11500 }
11501 Jim_IncrRefCount(fileNameObj);
11502
11503
11504 str = Jim_GetString(objPtr, &strLen);
11505
11506 Jim_FreeIntRep(interp, objPtr);
11507 objPtr->typePtr = &listObjType;
11508 objPtr->internalRep.listValue.len = 0;
11509 objPtr->internalRep.listValue.maxLen = 0;
11510 objPtr->internalRep.listValue.ele = NULL;
11511
11512
11513 if (strLen) {
11514 JimParserInit(&parser, str, strLen, linenr);
11515 while (!parser.eof) {
11516 Jim_Obj *elementPtr;
11517
@@ -11641,11 +11579,11 @@
11641 Jim_Obj *compare_script;
11642 int rc;
11643
11644 jim_wide ret = 0;
11645
11646
11647 compare_script = Jim_DuplicateObj(sort_info->interp, sort_info->command);
11648 Jim_ListAppendElement(sort_info->interp, compare_script, *lhsObj);
11649 Jim_ListAppendElement(sort_info->interp, compare_script, *rhsObj);
11650
11651 rc = Jim_EvalObj(sort_info->interp, compare_script);
@@ -11663,23 +11601,27 @@
11663 int dst = 0;
11664 Jim_Obj **ele = listObjPtr->internalRep.listValue.ele;
11665
11666 for (src = 1; src < listObjPtr->internalRep.listValue.len; src++) {
11667 if (comp(&ele[dst], &ele[src]) == 0) {
11668
11669 Jim_DecrRefCount(sort_info->interp, ele[dst]);
11670 }
11671 else {
11672
11673 dst++;
11674 }
11675 ele[dst] = ele[src];
11676 }
11677
11678 ele[++dst] = ele[src];
11679
11680
 
 
 
 
 
 
11681 listObjPtr->internalRep.listValue.len = dst;
11682 }
11683
11684
11685 static int ListSortElements(Jim_Interp *interp, Jim_Obj *listObjPtr, struct lsort_info *info)
@@ -11693,11 +11635,11 @@
11693 int rc;
11694
11695 JimPanic((Jim_IsShared(listObjPtr), "ListSortElements called with shared object"));
11696 SetListFromAny(interp, listObjPtr);
11697
11698
11699 prev_info = sort_info;
11700 sort_info = info;
11701
11702 vector = listObjPtr->internalRep.listValue.ele;
11703 len = listObjPtr->internalRep.listValue.len;
@@ -11716,17 +11658,17 @@
11716 break;
11717 case JIM_LSORT_COMMAND:
11718 fn = ListSortCommand;
11719 break;
11720 default:
11721 fn = NULL;
11722 JimPanic((1, "ListSort called with invalid sort type"));
11723 return -1;
11724 }
11725
11726 if (info->indexed) {
11727
11728 info->subfn = fn;
11729 fn = ListSortIndexHelper;
11730 }
11731
11732 if ((rc = setjmp(info->jmpbuf)) == 0) {
@@ -11750,11 +11692,11 @@
11750 int i;
11751 Jim_Obj **point;
11752
11753 if (requiredLen > listPtr->internalRep.listValue.maxLen) {
11754 if (requiredLen < 2) {
11755
11756 requiredLen = 4;
11757 }
11758 else {
11759 requiredLen *= 2;
11760 }
@@ -11936,34 +11878,34 @@
11936 for (i = 0; i < objc; i++)
11937 ListAppendList(objPtr, objv[i]);
11938 return objPtr;
11939 }
11940 else {
11941
11942 int len = 0, objLen;
11943 char *bytes, *p;
11944
11945
11946 for (i = 0; i < objc; i++) {
11947 len += Jim_Length(objv[i]);
11948 }
11949 if (objc)
11950 len += objc - 1;
11951
11952 p = bytes = Jim_Alloc(len + 1);
11953 for (i = 0; i < objc; i++) {
11954 const char *s = Jim_GetString(objv[i], &objLen);
11955
11956
11957 while (objLen && isspace(UCHAR(*s))) {
11958 s++;
11959 objLen--;
11960 len--;
11961 }
11962
11963 while (objLen && isspace(UCHAR(s[objLen - 1]))) {
11964
11965 if (objLen > 1 && s[objLen - 2] == '\\') {
11966 break;
11967 }
11968 objLen--;
11969 len--;
@@ -11990,11 +11932,11 @@
11990 int len, rangeLen;
11991
11992 if (Jim_GetIndex(interp, firstObjPtr, &first) != JIM_OK ||
11993 Jim_GetIndex(interp, lastObjPtr, &last) != JIM_OK)
11994 return NULL;
11995 len = Jim_ListLength(interp, listObjPtr);
11996 first = JimRelToAbsIndex(len, first);
11997 last = JimRelToAbsIndex(len, last);
11998 JimRelToAbsRange(len, &first, &last, &rangeLen);
11999 if (first == 0 && last == len) {
12000 return listObjPtr;
@@ -12030,16 +11972,16 @@
12030 {
12031 Jim_DecrRefCount(interp, (Jim_Obj *)val);
12032 }
12033
12034 static const Jim_HashTableType JimDictHashTableType = {
12035 JimObjectHTHashFunction,
12036 JimObjectHTKeyValDup,
12037 JimObjectHTKeyValDup,
12038 JimObjectHTKeyCompare,
12039 JimObjectHTKeyValDestructor,
12040 JimObjectHTKeyValDestructor
12041 };
12042
12043 static const Jim_ObjType dictObjType = {
12044 "dict",
12045 FreeDictInternalRep,
@@ -12060,17 +12002,17 @@
12060 {
12061 Jim_HashTable *ht, *dupHt;
12062 Jim_HashTableIterator htiter;
12063 Jim_HashEntry *he;
12064
12065
12066 ht = srcPtr->internalRep.ptr;
12067 dupHt = Jim_Alloc(sizeof(*dupHt));
12068 Jim_InitHashTable(dupHt, &JimDictHashTableType, interp);
12069 if (ht->size != 0)
12070 Jim_ExpandHashTable(dupHt, ht->size);
12071
12072 JimInitHashTableIterator(ht, &htiter);
12073 while ((he = Jim_NextHashEntry(&htiter)) != NULL) {
12074 Jim_AddHashEntry(dupHt, he->key, he->u.val);
12075 }
12076
@@ -12086,11 +12028,11 @@
12086 Jim_Obj **objv;
12087 int i;
12088
12089 ht = dictPtr->internalRep.ptr;
12090
12091
12092 objv = Jim_Alloc((ht->used * 2) * sizeof(Jim_Obj *));
12093 JimInitHashTableIterator(ht, &htiter);
12094 i = 0;
12095 while ((he = Jim_NextHashEntry(&htiter)) != NULL) {
12096 objv[i++] = Jim_GetHashEntryKey(he);
@@ -12100,15 +12042,15 @@
12100 return objv;
12101 }
12102
12103 static void UpdateStringOfDict(struct Jim_Obj *objPtr)
12104 {
12105
12106 int len;
12107 Jim_Obj **objv = JimDictPairs(objPtr, &len);
12108
12109
12110 JimMakeListStringRep(objPtr, objv, len);
12111
12112 Jim_Free(objv);
12113 }
12114
@@ -12122,18 +12064,18 @@
12122
12123 if (Jim_IsList(objPtr) && Jim_IsShared(objPtr)) {
12124 Jim_String(objPtr);
12125 }
12126
12127
12128 listlen = Jim_ListLength(interp, objPtr);
12129 if (listlen % 2) {
12130 Jim_SetResultString(interp, "missing value to go with key", -1);
12131 return JIM_ERR;
12132 }
12133 else {
12134
12135 Jim_HashTable *ht;
12136 int i;
12137
12138 ht = Jim_Alloc(sizeof(*ht));
12139 Jim_InitHashTable(ht, &JimDictHashTableType, interp);
@@ -12158,11 +12100,11 @@
12158 static int DictAddElement(Jim_Interp *interp, Jim_Obj *objPtr,
12159 Jim_Obj *keyObjPtr, Jim_Obj *valueObjPtr)
12160 {
12161 Jim_HashTable *ht = objPtr->internalRep.ptr;
12162
12163 if (valueObjPtr == NULL) {
12164 return Jim_DeleteHashEntry(ht, keyObjPtr);
12165 }
12166 Jim_ReplaceHashEntry(ht, keyObjPtr, valueObjPtr);
12167 return JIM_OK;
12168 }
@@ -12209,12 +12151,14 @@
12209 if (flags & JIM_ERRMSG) {
12210 Jim_SetResultFormatted(interp, "key \"%#s\" not known in dictionary", keyPtr);
12211 }
12212 return JIM_ERR;
12213 }
12214 *objPtrPtr = he->u.val;
12215 return JIM_OK;
 
 
12216 }
12217
12218
12219 int Jim_DictPairs(Jim_Interp *interp, Jim_Obj *dictPtr, Jim_Obj ***objPtrPtr, int *len)
12220 {
@@ -12258,11 +12202,11 @@
12258 int shared, i;
12259
12260 varObjPtr = objPtr = Jim_GetVariable(interp, varNamePtr, flags);
12261 if (objPtr == NULL) {
12262 if (newObjPtr == NULL && (flags & JIM_MUSTEXIST)) {
12263
12264 return JIM_ERR;
12265 }
12266 varObjPtr = objPtr = Jim_NewDictObj(interp, NULL, 0);
12267 if (Jim_SetVariable(interp, varNamePtr, objPtr) != JIM_OK) {
12268 Jim_FreeNewObj(interp, varObjPtr);
@@ -12272,26 +12216,26 @@
12272 if ((shared = Jim_IsShared(objPtr)))
12273 varObjPtr = objPtr = Jim_DuplicateObj(interp, objPtr);
12274 for (i = 0; i < keyc; i++) {
12275 dictObjPtr = objPtr;
12276
12277
12278 if (SetDictFromAny(interp, dictObjPtr) != JIM_OK) {
12279 goto err;
12280 }
12281
12282 if (i == keyc - 1) {
12283
12284 if (Jim_DictAddElement(interp, objPtr, keyv[keyc - 1], newObjPtr) != JIM_OK) {
12285 if (newObjPtr || (flags & JIM_MUSTEXIST)) {
12286 goto err;
12287 }
12288 }
12289 break;
12290 }
12291
12292
12293 Jim_InvalidateStringRep(dictObjPtr);
12294 if (Jim_DictKey(interp, dictObjPtr, keyv[i], &objPtr,
12295 newObjPtr ? JIM_NONE : JIM_ERRMSG) == JIM_OK) {
12296 if (Jim_IsShared(objPtr)) {
12297 objPtr = Jim_DuplicateObj(interp, objPtr);
@@ -12304,11 +12248,11 @@
12304 }
12305 objPtr = Jim_NewDictObj(interp, NULL, 0);
12306 DictAddElement(interp, dictObjPtr, keyv[i], objPtr);
12307 }
12308 }
12309
12310 Jim_InvalidateStringRep(objPtr);
12311 Jim_InvalidateStringRep(varObjPtr);
12312 if (Jim_SetVariable(interp, varNamePtr, varObjPtr) != JIM_OK) {
12313 goto err;
12314 }
@@ -12341,11 +12285,11 @@
12341 char buf[JIM_INTEGER_SPACE + 1];
12342 if (objPtr->internalRep.intValue >= 0) {
12343 sprintf(buf, "%d", objPtr->internalRep.intValue);
12344 }
12345 else {
12346
12347 sprintf(buf, "end%d", objPtr->internalRep.intValue + 1);
12348 }
12349 JimSetStringBytes(objPtr, buf);
12350 }
12351 }
@@ -12354,14 +12298,14 @@
12354 {
12355 int idx, end = 0;
12356 const char *str;
12357 char *endptr;
12358
12359
12360 str = Jim_String(objPtr);
12361
12362
12363 if (strncmp(str, "end", 3) == 0) {
12364 end = 1;
12365 str += 3;
12366 idx = 0;
12367 }
@@ -12372,21 +12316,21 @@
12372 goto badindex;
12373 }
12374 str = endptr;
12375 }
12376
12377
12378 if (*str == '+' || *str == '-') {
12379 int sign = (*str == '+' ? 1 : -1);
12380
12381 idx += sign * jim_strtol(++str, &endptr);
12382 if (str == endptr || *endptr) {
12383 goto badindex;
12384 }
12385 str = endptr;
12386 }
12387
12388 while (isspace(UCHAR(*str))) {
12389 str++;
12390 }
12391 if (*str) {
12392 goto badindex;
@@ -12394,19 +12338,19 @@
12394 if (end) {
12395 if (idx > 0) {
12396 idx = INT_MAX;
12397 }
12398 else {
12399
12400 idx--;
12401 }
12402 }
12403 else if (idx < 0) {
12404 idx = -INT_MAX;
12405 }
12406
12407
12408 Jim_FreeIntRep(interp, objPtr);
12409 objPtr->typePtr = &indexObjType;
12410 objPtr->internalRep.intValue = idx;
12411 return JIM_OK;
12412
@@ -12416,11 +12360,11 @@
12416 return JIM_ERR;
12417 }
12418
12419 int Jim_GetIndex(Jim_Interp *interp, Jim_Obj *objPtr, int *indexPtr)
12420 {
12421
12422 if (objPtr->typePtr == &intObjType) {
12423 jim_wide val = JimWideValue(objPtr);
12424
12425 if (val < 0)
12426 *indexPtr = -INT_MAX;
@@ -12448,11 +12392,11 @@
12448 "exit",
12449 "eval",
12450 NULL
12451 };
12452
12453 #define jimReturnCodesSize (sizeof(jimReturnCodes)/sizeof(*jimReturnCodes))
12454
12455 static const Jim_ObjType returnCodeObjType = {
12456 "return-code",
12457 NULL,
12458 NULL,
@@ -12473,18 +12417,18 @@
12473 static int SetReturnCodeFromAny(Jim_Interp *interp, Jim_Obj *objPtr)
12474 {
12475 int returnCode;
12476 jim_wide wideValue;
12477
12478
12479 if (JimGetWideNoErr(interp, objPtr, &wideValue) != JIM_ERR)
12480 returnCode = (int)wideValue;
12481 else if (Jim_GetEnum(interp, objPtr, jimReturnCodes, &returnCode, NULL, JIM_NONE) != JIM_OK) {
12482 Jim_SetResultFormatted(interp, "expected return code but got \"%#s\"", objPtr);
12483 return JIM_ERR;
12484 }
12485
12486 Jim_FreeIntRep(interp, objPtr);
12487 objPtr->typePtr = &returnCodeObjType;
12488 objPtr->internalRep.intValue = returnCode;
12489 return JIM_OK;
12490 }
@@ -12498,19 +12442,19 @@
12498 }
12499
12500 static int JimParseExprOperator(struct JimParserCtx *pc);
12501 static int JimParseExprNumber(struct JimParserCtx *pc);
12502 static int JimParseExprIrrational(struct JimParserCtx *pc);
12503
12504
12505
12506
12507 enum
12508 {
12509
12510
12511 JIM_EXPROP_MUL = JIM_TT_EXPR_OP,
 
12512 JIM_EXPROP_DIV,
12513 JIM_EXPROP_MOD,
12514 JIM_EXPROP_SUB,
12515 JIM_EXPROP_ADD,
12516 JIM_EXPROP_LSHIFT,
@@ -12521,66 +12465,48 @@
12521 JIM_EXPROP_GT,
12522 JIM_EXPROP_LTE,
12523 JIM_EXPROP_GTE,
12524 JIM_EXPROP_NUMEQ,
12525 JIM_EXPROP_NUMNE,
12526 JIM_EXPROP_BITAND,
12527 JIM_EXPROP_BITXOR,
12528 JIM_EXPROP_BITOR,
12529
12530
12531 JIM_EXPROP_LOGICAND,
12532 JIM_EXPROP_LOGICAND_LEFT,
12533 JIM_EXPROP_LOGICAND_RIGHT,
12534
12535
12536 JIM_EXPROP_LOGICOR,
12537 JIM_EXPROP_LOGICOR_LEFT,
12538 JIM_EXPROP_LOGICOR_RIGHT,
12539
12540
12541
12542 JIM_EXPROP_TERNARY,
12543 JIM_EXPROP_TERNARY_LEFT,
12544 JIM_EXPROP_TERNARY_RIGHT,
12545
12546
12547 JIM_EXPROP_COLON,
12548 JIM_EXPROP_COLON_LEFT,
12549 JIM_EXPROP_COLON_RIGHT,
12550
12551 JIM_EXPROP_POW,
12552
12553
12554 JIM_EXPROP_STREQ,
12555 JIM_EXPROP_STRNE,
12556 JIM_EXPROP_STRIN,
12557 JIM_EXPROP_STRNI,
12558
12559
12560 JIM_EXPROP_NOT,
12561 JIM_EXPROP_BITNOT,
12562 JIM_EXPROP_UNARYMINUS,
12563 JIM_EXPROP_UNARYPLUS,
12564
12565
12566 JIM_EXPROP_FUNC_FIRST,
12567 JIM_EXPROP_FUNC_INT = JIM_EXPROP_FUNC_FIRST,
12568 JIM_EXPROP_FUNC_WIDE,
12569 JIM_EXPROP_FUNC_ABS,
12570 JIM_EXPROP_FUNC_DOUBLE,
12571 JIM_EXPROP_FUNC_ROUND,
12572 JIM_EXPROP_FUNC_RAND,
12573 JIM_EXPROP_FUNC_SRAND,
12574
12575
12576 JIM_EXPROP_FUNC_SIN,
12577 JIM_EXPROP_FUNC_COS,
12578 JIM_EXPROP_FUNC_TAN,
12579 JIM_EXPROP_FUNC_ASIN,
12580 JIM_EXPROP_FUNC_ACOS,
12581 JIM_EXPROP_FUNC_ATAN,
 
12582 JIM_EXPROP_FUNC_SINH,
12583 JIM_EXPROP_FUNC_COSH,
12584 JIM_EXPROP_FUNC_TANH,
12585 JIM_EXPROP_FUNC_CEIL,
12586 JIM_EXPROP_FUNC_FLOOR,
@@ -12587,52 +12513,52 @@
12587 JIM_EXPROP_FUNC_EXP,
12588 JIM_EXPROP_FUNC_LOG,
12589 JIM_EXPROP_FUNC_LOG10,
12590 JIM_EXPROP_FUNC_SQRT,
12591 JIM_EXPROP_FUNC_POW,
 
 
12592 };
12593
12594 struct JimExprState
12595 {
12596 Jim_Obj **stack;
12597 int stacklen;
12598 int opcode;
12599 int skip;
 
12600 };
12601
12602
12603 typedef struct Jim_ExprOperator
12604 {
12605 const char *name;
12606 int (*funcop) (Jim_Interp *interp, struct JimExprState * e);
12607 unsigned char precedence;
12608 unsigned char arity;
12609 unsigned char lazy;
12610 unsigned char namelen;
12611 } Jim_ExprOperator;
12612
12613 static void ExprPush(struct JimExprState *e, Jim_Obj *obj)
12614 {
12615 Jim_IncrRefCount(obj);
12616 e->stack[e->stacklen++] = obj;
12617 }
12618
12619 static Jim_Obj *ExprPop(struct JimExprState *e)
12620 {
12621 return e->stack[--e->stacklen];
12622 }
12623
12624 static int JimExprOpNumUnary(Jim_Interp *interp, struct JimExprState *e)
12625 {
12626 int intresult = 1;
12627 int rc = JIM_OK;
12628 Jim_Obj *A = ExprPop(e);
12629 double dA, dC = 0;
12630 jim_wide wA, wC = 0;
 
 
 
 
 
12631
12632 if ((A->typePtr != &doubleObjType || A->bytes) && JimGetWideNoErr(interp, A, &wA) == JIM_OK) {
12633 switch (e->opcode) {
12634 case JIM_EXPROP_FUNC_INT:
12635 case JIM_EXPROP_FUNC_WIDE:
12636 case JIM_EXPROP_FUNC_ROUND:
12637 case JIM_EXPROP_UNARYPLUS:
12638 wC = wA;
@@ -12653,11 +12579,11 @@
12653 default:
12654 abort();
12655 }
12656 }
12657 else if ((rc = Jim_GetDouble(interp, A, &dA)) == JIM_OK) {
12658 switch (e->opcode) {
12659 case JIM_EXPROP_FUNC_INT:
12660 case JIM_EXPROP_FUNC_WIDE:
12661 wC = dA;
12662 break;
12663 case JIM_EXPROP_FUNC_ROUND:
@@ -12667,11 +12593,15 @@
12667 case JIM_EXPROP_UNARYPLUS:
12668 dC = dA;
12669 intresult = 0;
12670 break;
12671 case JIM_EXPROP_FUNC_ABS:
 
 
 
12672 dC = dA >= 0 ? dA : -dA;
 
12673 intresult = 0;
12674 break;
12675 case JIM_EXPROP_UNARYMINUS:
12676 dC = -dA;
12677 intresult = 0;
@@ -12684,14 +12614,14 @@
12684 }
12685 }
12686
12687 if (rc == JIM_OK) {
12688 if (intresult) {
12689 ExprPush(e, Jim_NewIntObj(interp, wC));
12690 }
12691 else {
12692 ExprPush(e, Jim_NewDoubleObj(interp, dC));
12693 }
12694 }
12695
12696 Jim_DecrRefCount(interp, A);
12697
@@ -12704,24 +12634,29 @@
12704 JimRandomBytes(interp, &x, sizeof(x));
12705
12706 return (double)x / (unsigned long)~0;
12707 }
12708
12709 static int JimExprOpIntUnary(Jim_Interp *interp, struct JimExprState *e)
12710 {
12711 Jim_Obj *A = ExprPop(e);
12712 jim_wide wA;
 
 
12713
12714 int rc = Jim_GetWide(interp, A, &wA);
 
 
 
 
12715 if (rc == JIM_OK) {
12716 switch (e->opcode) {
12717 case JIM_EXPROP_BITNOT:
12718 ExprPush(e, Jim_NewIntObj(interp, ~wA));
12719 break;
12720 case JIM_EXPROP_FUNC_SRAND:
12721 JimPrngSeed(interp, (unsigned char *)&wA, sizeof(wA));
12722 ExprPush(e, Jim_NewDoubleObj(interp, JimRandDouble(interp)));
12723 break;
12724 default:
12725 abort();
12726 }
12727 }
@@ -12729,29 +12664,33 @@
12729 Jim_DecrRefCount(interp, A);
12730
12731 return rc;
12732 }
12733
12734 static int JimExprOpNone(Jim_Interp *interp, struct JimExprState *e)
12735 {
12736 JimPanic((e->opcode != JIM_EXPROP_FUNC_RAND, "JimExprOpNone only support rand()"));
12737
12738 ExprPush(e, Jim_NewDoubleObj(interp, JimRandDouble(interp)));
12739
12740 return JIM_OK;
12741 }
12742
12743 #ifdef JIM_MATH_FUNCTIONS
12744 static int JimExprOpDoubleUnary(Jim_Interp *interp, struct JimExprState *e)
12745 {
12746 int rc;
12747 Jim_Obj *A = ExprPop(e);
12748 double dA, dC;
 
 
 
 
 
12749
12750 rc = Jim_GetDouble(interp, A, &dA);
12751 if (rc == JIM_OK) {
12752 switch (e->opcode) {
12753 case JIM_EXPROP_FUNC_SIN:
12754 dC = sin(dA);
12755 break;
12756 case JIM_EXPROP_FUNC_COS:
12757 dC = cos(dA);
@@ -12796,33 +12735,42 @@
12796 dC = sqrt(dA);
12797 break;
12798 default:
12799 abort();
12800 }
12801 ExprPush(e, Jim_NewDoubleObj(interp, dC));
12802 }
12803
12804 Jim_DecrRefCount(interp, A);
12805
12806 return rc;
12807 }
12808 #endif
12809
12810
12811 static int JimExprOpIntBin(Jim_Interp *interp, struct JimExprState *e)
12812 {
12813 Jim_Obj *B = ExprPop(e);
12814 Jim_Obj *A = ExprPop(e);
12815 jim_wide wA, wB;
12816 int rc = JIM_ERR;
 
 
 
 
 
 
 
 
 
 
 
12817
12818 if (Jim_GetWide(interp, A, &wA) == JIM_OK && Jim_GetWide(interp, B, &wB) == JIM_OK) {
12819 jim_wide wC;
12820
12821 rc = JIM_OK;
12822
12823 switch (e->opcode) {
12824 case JIM_EXPROP_LSHIFT:
12825 wC = wA << wB;
12826 break;
12827 case JIM_EXPROP_RSHIFT:
12828 wC = wA >> wB;
@@ -12859,29 +12807,28 @@
12859 }
12860 }
12861 break;
12862 case JIM_EXPROP_ROTL:
12863 case JIM_EXPROP_ROTR:{
12864
12865 unsigned long uA = (unsigned long)wA;
12866 unsigned long uB = (unsigned long)wB;
12867 const unsigned int S = sizeof(unsigned long) * 8;
12868
12869
12870 uB %= S;
12871
12872 if (e->opcode == JIM_EXPROP_ROTR) {
12873 uB = S - uB;
12874 }
12875 wC = (unsigned long)(uA << uB) | (uA >> (S - uB));
12876 break;
12877 }
12878 default:
12879 abort();
12880 }
12881 ExprPush(e, Jim_NewIntObj(interp, wC));
12882
12883 }
12884
12885 Jim_DecrRefCount(interp, A);
12886 Jim_DecrRefCount(interp, B);
12887
@@ -12888,44 +12835,55 @@
12888 return rc;
12889 }
12890
12891
12892
12893 static int JimExprOpBin(Jim_Interp *interp, struct JimExprState *e)
12894 {
12895 int intresult = 1;
12896 int rc = JIM_OK;
12897 double dA, dB, dC = 0;
12898 jim_wide wA, wB, wC = 0;
 
12899
12900 Jim_Obj *B = ExprPop(e);
12901 Jim_Obj *A = ExprPop(e);
 
 
 
 
 
12902
12903 if ((A->typePtr != &doubleObjType || A->bytes) &&
12904 (B->typePtr != &doubleObjType || B->bytes) &&
12905 JimGetWideNoErr(interp, A, &wA) == JIM_OK && JimGetWideNoErr(interp, B, &wB) == JIM_OK) {
12906
12907
12908
12909 switch (e->opcode) {
 
12910 case JIM_EXPROP_POW:
12911 case JIM_EXPROP_FUNC_POW:
 
 
 
 
 
12912 wC = JimPowWide(wA, wB);
12913 break;
12914 case JIM_EXPROP_ADD:
12915 wC = wA + wB;
12916 break;
12917 case JIM_EXPROP_SUB:
12918 wC = wA - wB;
12919 break;
12920 case JIM_EXPROP_MUL:
12921 wC = wA * wB;
12922 break;
12923 case JIM_EXPROP_DIV:
12924 if (wB == 0) {
12925 Jim_SetResultString(interp, "Division by zero", -1);
12926 rc = JIM_ERR;
 
12927 }
12928 else {
12929 if (wB < 0) {
12930 wB = -wB;
12931 wA = -wA;
@@ -12932,55 +12890,67 @@
12932 }
12933 wC = wA / wB;
12934 if (wA % wB < 0) {
12935 wC--;
12936 }
 
12937 }
12938 break;
12939 case JIM_EXPROP_LT:
12940 wC = wA < wB;
12941 break;
12942 case JIM_EXPROP_GT:
12943 wC = wA > wB;
12944 break;
12945 case JIM_EXPROP_LTE:
12946 wC = wA <= wB;
12947 break;
12948 case JIM_EXPROP_GTE:
12949 wC = wA >= wB;
12950 break;
12951 case JIM_EXPROP_NUMEQ:
12952 wC = wA == wB;
12953 break;
12954 case JIM_EXPROP_NUMNE:
12955 wC = wA != wB;
12956 break;
12957 default:
12958 abort();
12959 }
12960 }
12961 else if (Jim_GetDouble(interp, A, &dA) == JIM_OK && Jim_GetDouble(interp, B, &dB) == JIM_OK) {
12962 intresult = 0;
12963 switch (e->opcode) {
12964 case JIM_EXPROP_POW:
12965 case JIM_EXPROP_FUNC_POW:
12966 #ifdef JIM_MATH_FUNCTIONS
12967 dC = pow(dA, dB);
12968 #else
12969 Jim_SetResultString(interp, "unsupported", -1);
12970 rc = JIM_ERR;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12971 #endif
12972 break;
12973 case JIM_EXPROP_ADD:
12974 dC = dA + dB;
12975 break;
12976 case JIM_EXPROP_SUB:
12977 dC = dA - dB;
12978 break;
12979 case JIM_EXPROP_MUL:
12980 dC = dA * dB;
12981 break;
12982 case JIM_EXPROP_DIV:
12983 if (dB == 0) {
12984 #ifdef INFINITY
12985 dC = dA < 0 ? -INFINITY : INFINITY;
12986 #else
@@ -12988,83 +12958,70 @@
12988 #endif
12989 }
12990 else {
12991 dC = dA / dB;
12992 }
12993 break;
12994 case JIM_EXPROP_LT:
12995 wC = dA < dB;
12996 intresult = 1;
12997 break;
12998 case JIM_EXPROP_GT:
12999 wC = dA > dB;
13000 intresult = 1;
13001 break;
13002 case JIM_EXPROP_LTE:
13003 wC = dA <= dB;
13004 intresult = 1;
13005 break;
13006 case JIM_EXPROP_GTE:
13007 wC = dA >= dB;
13008 intresult = 1;
13009 break;
13010 case JIM_EXPROP_NUMEQ:
13011 wC = dA == dB;
13012 intresult = 1;
13013 break;
13014 case JIM_EXPROP_NUMNE:
13015 wC = dA != dB;
13016 intresult = 1;
13017 break;
13018 default:
13019 abort();
13020 }
13021 }
13022 else {
13023
13024
13025
 
13026 int i = Jim_StringCompareObj(interp, A, B, 0);
13027
13028 switch (e->opcode) {
13029 case JIM_EXPROP_LT:
13030 wC = i < 0;
13031 break;
13032 case JIM_EXPROP_GT:
13033 wC = i > 0;
13034 break;
13035 case JIM_EXPROP_LTE:
13036 wC = i <= 0;
13037 break;
13038 case JIM_EXPROP_GTE:
13039 wC = i >= 0;
13040 break;
13041 case JIM_EXPROP_NUMEQ:
13042 wC = i == 0;
13043 break;
13044 case JIM_EXPROP_NUMNE:
13045 wC = i != 0;
13046 break;
13047 default:
13048 rc = JIM_ERR;
13049 break;
13050 }
13051 }
13052
13053 if (rc == JIM_OK) {
13054 if (intresult) {
13055 ExprPush(e, Jim_NewIntObj(interp, wC));
13056 }
13057 else {
13058 ExprPush(e, Jim_NewDoubleObj(interp, dC));
13059 }
13060 }
13061
13062 Jim_DecrRefCount(interp, A);
13063 Jim_DecrRefCount(interp, B);
13064
13065 return rc;
 
 
 
 
 
 
13066 }
13067
13068 static int JimSearchList(Jim_Interp *interp, Jim_Obj *listObjPtr, Jim_Obj *valObj)
13069 {
13070 int listlen;
@@ -13077,22 +13034,31 @@
13077 }
13078 }
13079 return 0;
13080 }
13081
13082 static int JimExprOpStrBin(Jim_Interp *interp, struct JimExprState *e)
 
 
13083 {
13084 Jim_Obj *B = ExprPop(e);
13085 Jim_Obj *A = ExprPop(e);
13086
13087 jim_wide wC;
 
13088
13089 switch (e->opcode) {
 
 
 
 
 
 
 
 
13090 case JIM_EXPROP_STREQ:
13091 case JIM_EXPROP_STRNE:
13092 wC = Jim_StringEqObj(A, B);
13093 if (e->opcode == JIM_EXPROP_STRNE) {
13094 wC = !wC;
13095 }
13096 break;
13097 case JIM_EXPROP_STRIN:
13098 wC = JimSearchList(interp, B, A);
@@ -13101,178 +13067,99 @@
13101 wC = !JimSearchList(interp, B, A);
13102 break;
13103 default:
13104 abort();
13105 }
13106 ExprPush(e, Jim_NewIntObj(interp, wC));
13107
13108 Jim_DecrRefCount(interp, A);
13109 Jim_DecrRefCount(interp, B);
13110
13111 return JIM_OK;
13112 }
13113
13114 static int ExprBool(Jim_Interp *interp, Jim_Obj *obj)
13115 {
13116 long l;
13117 double d;
 
 
 
 
 
13118
13119 if (Jim_GetLong(interp, obj, &l) == JIM_OK) {
13120 return l != 0;
13121 }
13122 if (Jim_GetDouble(interp, obj, &d) == JIM_OK) {
13123 return d != 0;
13124 }
13125 return -1;
13126 }
13127
13128 static int JimExprOpAndLeft(Jim_Interp *interp, struct JimExprState *e)
13129 {
13130 Jim_Obj *skip = ExprPop(e);
13131 Jim_Obj *A = ExprPop(e);
13132 int rc = JIM_OK;
13133
13134 switch (ExprBool(interp, A)) {
13135 case 0:
13136
13137 e->skip = JimWideValue(skip);
13138 ExprPush(e, Jim_NewIntObj(interp, 0));
13139 break;
13140
13141 case 1:
13142
13143 break;
13144
13145 case -1:
13146
13147 rc = JIM_ERR;
13148 }
13149 Jim_DecrRefCount(interp, A);
13150 Jim_DecrRefCount(interp, skip);
13151
13152 return rc;
13153 }
13154
13155 static int JimExprOpOrLeft(Jim_Interp *interp, struct JimExprState *e)
13156 {
13157 Jim_Obj *skip = ExprPop(e);
13158 Jim_Obj *A = ExprPop(e);
13159 int rc = JIM_OK;
13160
13161 switch (ExprBool(interp, A)) {
13162 case 0:
13163
13164 break;
13165
13166 case 1:
13167
13168 e->skip = JimWideValue(skip);
13169 ExprPush(e, Jim_NewIntObj(interp, 1));
13170 break;
13171
13172 case -1:
13173
13174 rc = JIM_ERR;
13175 break;
13176 }
13177 Jim_DecrRefCount(interp, A);
13178 Jim_DecrRefCount(interp, skip);
13179
13180 return rc;
13181 }
13182
13183 static int JimExprOpAndOrRight(Jim_Interp *interp, struct JimExprState *e)
13184 {
13185 Jim_Obj *A = ExprPop(e);
13186 int rc = JIM_OK;
13187
13188 switch (ExprBool(interp, A)) {
13189 case 0:
13190 ExprPush(e, Jim_NewIntObj(interp, 0));
13191 break;
13192
13193 case 1:
13194 ExprPush(e, Jim_NewIntObj(interp, 1));
13195 break;
13196
13197 case -1:
13198
13199 rc = JIM_ERR;
13200 break;
13201 }
13202 Jim_DecrRefCount(interp, A);
13203
13204 return rc;
13205 }
13206
13207 static int JimExprOpTernaryLeft(Jim_Interp *interp, struct JimExprState *e)
13208 {
13209 Jim_Obj *skip = ExprPop(e);
13210 Jim_Obj *A = ExprPop(e);
13211 int rc = JIM_OK;
13212
13213
13214 ExprPush(e, A);
13215
13216 switch (ExprBool(interp, A)) {
13217 case 0:
13218
13219 e->skip = JimWideValue(skip);
13220
13221 ExprPush(e, Jim_NewIntObj(interp, 0));
13222 break;
13223
13224 case 1:
13225
13226 break;
13227
13228 case -1:
13229
13230 rc = JIM_ERR;
13231 break;
13232 }
13233 Jim_DecrRefCount(interp, A);
13234 Jim_DecrRefCount(interp, skip);
13235
13236 return rc;
13237 }
13238
13239 static int JimExprOpColonLeft(Jim_Interp *interp, struct JimExprState *e)
13240 {
13241 Jim_Obj *skip = ExprPop(e);
13242 Jim_Obj *B = ExprPop(e);
13243 Jim_Obj *A = ExprPop(e);
13244
13245
13246 if (ExprBool(interp, A)) {
13247
13248 e->skip = JimWideValue(skip);
13249
13250 ExprPush(e, B);
13251 }
13252
13253 Jim_DecrRefCount(interp, skip);
13254 Jim_DecrRefCount(interp, A);
13255 Jim_DecrRefCount(interp, B);
13256 return JIM_OK;
13257 }
13258
13259 static int JimExprOpNull(Jim_Interp *interp, struct JimExprState *e)
13260 {
13261 return JIM_OK;
13262 }
13263
13264 enum
13265 {
13266 LAZY_NONE,
13267 LAZY_OP,
13268 LAZY_LEFT,
13269 LAZY_RIGHT
13270 };
13271
13272 #define OPRINIT(N, P, A, F) {N, F, P, A, LAZY_NONE, sizeof(N) - 1}
13273 #define OPRINIT_LAZY(N, P, A, F, L) {N, F, P, A, L, sizeof(N) - 1}
13274
13275 static const struct Jim_ExprOperator Jim_ExprOperators[] = {
13276 OPRINIT("*", 110, 2, JimExprOpBin),
13277 OPRINIT("/", 110, 2, JimExprOpBin),
13278 OPRINIT("%", 110, 2, JimExprOpIntBin),
@@ -13296,86 +13183,79 @@
13296
13297 OPRINIT("&", 50, 2, JimExprOpIntBin),
13298 OPRINIT("^", 49, 2, JimExprOpIntBin),
13299 OPRINIT("|", 48, 2, JimExprOpIntBin),
13300
13301 OPRINIT_LAZY("&&", 10, 2, NULL, LAZY_OP),
13302 OPRINIT_LAZY(NULL, 10, 2, JimExprOpAndLeft, LAZY_LEFT),
13303 OPRINIT_LAZY(NULL, 10, 2, JimExprOpAndOrRight, LAZY_RIGHT),
13304
13305 OPRINIT_LAZY("||", 9, 2, NULL, LAZY_OP),
13306 OPRINIT_LAZY(NULL, 9, 2, JimExprOpOrLeft, LAZY_LEFT),
13307 OPRINIT_LAZY(NULL, 9, 2, JimExprOpAndOrRight, LAZY_RIGHT),
13308
13309 OPRINIT_LAZY("?", 5, 2, JimExprOpNull, LAZY_OP),
13310 OPRINIT_LAZY(NULL, 5, 2, JimExprOpTernaryLeft, LAZY_LEFT),
13311 OPRINIT_LAZY(NULL, 5, 2, JimExprOpNull, LAZY_RIGHT),
13312
13313 OPRINIT_LAZY(":", 5, 2, JimExprOpNull, LAZY_OP),
13314 OPRINIT_LAZY(NULL, 5, 2, JimExprOpColonLeft, LAZY_LEFT),
13315 OPRINIT_LAZY(NULL, 5, 2, JimExprOpNull, LAZY_RIGHT),
13316
13317 OPRINIT("**", 250, 2, JimExprOpBin),
13318
13319 OPRINIT("eq", 60, 2, JimExprOpStrBin),
13320 OPRINIT("ne", 60, 2, JimExprOpStrBin),
13321
13322 OPRINIT("in", 55, 2, JimExprOpStrBin),
13323 OPRINIT("ni", 55, 2, JimExprOpStrBin),
13324
13325 OPRINIT("!", 150, 1, JimExprOpNumUnary),
13326 OPRINIT("~", 150, 1, JimExprOpIntUnary),
13327 OPRINIT(NULL, 150, 1, JimExprOpNumUnary),
13328 OPRINIT(NULL, 150, 1, JimExprOpNumUnary),
13329
13330
13331
13332 OPRINIT("int", 200, 1, JimExprOpNumUnary),
13333 OPRINIT("wide", 200, 1, JimExprOpNumUnary),
13334 OPRINIT("abs", 200, 1, JimExprOpNumUnary),
13335 OPRINIT("double", 200, 1, JimExprOpNumUnary),
13336 OPRINIT("round", 200, 1, JimExprOpNumUnary),
13337 OPRINIT("rand", 200, 0, JimExprOpNone),
13338 OPRINIT("srand", 200, 1, JimExprOpIntUnary),
13339
13340 #ifdef JIM_MATH_FUNCTIONS
13341 OPRINIT("sin", 200, 1, JimExprOpDoubleUnary),
13342 OPRINIT("cos", 200, 1, JimExprOpDoubleUnary),
13343 OPRINIT("tan", 200, 1, JimExprOpDoubleUnary),
13344 OPRINIT("asin", 200, 1, JimExprOpDoubleUnary),
13345 OPRINIT("acos", 200, 1, JimExprOpDoubleUnary),
13346 OPRINIT("atan", 200, 1, JimExprOpDoubleUnary),
13347 OPRINIT("sinh", 200, 1, JimExprOpDoubleUnary),
13348 OPRINIT("cosh", 200, 1, JimExprOpDoubleUnary),
13349 OPRINIT("tanh", 200, 1, JimExprOpDoubleUnary),
13350 OPRINIT("ceil", 200, 1, JimExprOpDoubleUnary),
13351 OPRINIT("floor", 200, 1, JimExprOpDoubleUnary),
13352 OPRINIT("exp", 200, 1, JimExprOpDoubleUnary),
13353 OPRINIT("log", 200, 1, JimExprOpDoubleUnary),
13354 OPRINIT("log10", 200, 1, JimExprOpDoubleUnary),
13355 OPRINIT("sqrt", 200, 1, JimExprOpDoubleUnary),
13356 OPRINIT("pow", 200, 2, JimExprOpBin),
 
 
 
13357 #endif
13358 };
13359 #undef OPRINIT
13360 #undef OPRINIT_LAZY
13361
13362 #define JIM_EXPR_OPERATORS_NUM \
13363 (sizeof(Jim_ExprOperators)/sizeof(struct Jim_ExprOperator))
13364
13365 static int JimParseExpression(struct JimParserCtx *pc)
13366 {
13367
13368 while (isspace(UCHAR(*pc->p)) || (*(pc->p) == '\\' && *(pc->p + 1) == '\n')) {
13369 if (*pc->p == '\n') {
13370 pc->linenr++;
13371 }
13372 pc->p++;
13373 pc->len--;
13374 }
13375
13376
13377 pc->tline = pc->linenr;
13378 pc->tstart = pc->p;
13379
13380 if (pc->len == 0) {
13381 pc->tend = pc->p;
@@ -13401,11 +13281,11 @@
13401 return JimParseCmd(pc);
13402 case '$':
13403 if (JimParseVar(pc) == JIM_ERR)
13404 return JimParseExprOperator(pc);
13405 else {
13406
13407 if (pc->tt == JIM_TT_EXPRSUGAR) {
13408 return JIM_ERR;
13409 }
13410 return JIM_OK;
13411 }
@@ -13430,10 +13310,18 @@
13430 case 'N':
13431 case 'I':
13432 case 'n':
13433 case 'i':
13434 if (JimParseExprIrrational(pc) == JIM_ERR)
 
 
 
 
 
 
 
 
13435 return JimParseExprOperator(pc);
13436 break;
13437 default:
13438 return JimParseExprOperator(pc);
13439 break;
@@ -13443,21 +13331,21 @@
13443
13444 static int JimParseExprNumber(struct JimParserCtx *pc)
13445 {
13446 char *end;
13447
13448
13449 pc->tt = JIM_TT_EXPR_INT;
13450
13451 jim_strtoull(pc->p, (char **)&pc->p);
13452
13453 if (strchr("eENnIi.", *pc->p) || pc->p == pc->tstart) {
13454 if (strtod(pc->tstart, &end)) { }
13455 if (end == pc->tstart)
13456 return JIM_ERR;
13457 if (end > pc->p) {
13458
13459 pc->tt = JIM_TT_EXPR_DOUBLE;
13460 pc->p = end;
13461 }
13462 }
13463 pc->tend = pc->p - 1;
@@ -13481,36 +13369,66 @@
13481 return JIM_OK;
13482 }
13483 }
13484 return JIM_ERR;
13485 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13486
13487 static int JimParseExprOperator(struct JimParserCtx *pc)
13488 {
13489 int i;
13490 int bestIdx = -1, bestLen = 0;
 
13491
13492
13493 for (i = 0; i < (signed)JIM_EXPR_OPERATORS_NUM; i++) {
13494 const char * const opname = Jim_ExprOperators[i].name;
13495 const int oplen = Jim_ExprOperators[i].namelen;
13496
13497 if (opname == NULL || opname[0] != pc->p[0]) {
13498 continue;
13499 }
13500
13501 if (oplen > bestLen && strncmp(opname, pc->p, oplen) == 0) {
13502 bestIdx = i + JIM_TT_EXPR_OP;
13503 bestLen = oplen;
13504 }
13505 }
13506 if (bestIdx == -1) {
13507 return JIM_ERR;
13508 }
13509
13510
13511 if (bestIdx >= JIM_EXPROP_FUNC_FIRST) {
13512 const char *p = pc->p + bestLen;
13513 int len = pc->len - bestLen;
13514
13515 while (len && isspace(UCHAR(*p))) {
13516 len--;
@@ -13522,30 +13440,27 @@
13522 }
13523 pc->tend = pc->p + bestLen - 1;
13524 pc->p += bestLen;
13525 pc->len -= bestLen;
13526
13527 pc->tt = bestIdx;
13528 return JIM_OK;
13529 }
13530
13531 static const struct Jim_ExprOperator *JimExprOperatorInfoByOpcode(int opcode)
13532 {
13533 static Jim_ExprOperator dummy_op;
13534 if (opcode < JIM_TT_EXPR_OP) {
13535 return &dummy_op;
13536 }
13537 return &Jim_ExprOperators[opcode - JIM_TT_EXPR_OP];
13538 }
13539
13540 const char *jim_tt_name(int type)
13541 {
13542 static const char * const tt_names[JIM_TT_EXPR_OP] =
13543 { "NIL", "STR", "ESC", "VAR", "ARY", "CMD", "SEP", "EOL", "EOF", "LIN", "WRD", "(((", ")))", ",,,", "INT",
13544 "DBL", "$()" };
13545 if (type < JIM_TT_EXPR_OP) {
13546 return tt_names[type];
 
 
 
 
 
 
13547 }
13548 else {
13549 const struct Jim_ExprOperator *op = JimExprOperatorInfoByOpcode(type);
13550 static char buf[20];
13551
@@ -13568,432 +13483,400 @@
13568 NULL,
13569 JIM_TYPE_REFERENCES,
13570 };
13571
13572
13573 typedef struct ExprByteCode
13574 {
13575 ScriptToken *token;
13576 int len;
13577 int inUse;
13578 } ExprByteCode;
13579
13580 static void ExprFreeByteCode(Jim_Interp *interp, ExprByteCode * expr)
 
13581 {
13582 int i;
 
 
 
 
 
 
 
13583
13584 for (i = 0; i < expr->len; i++) {
13585 Jim_DecrRefCount(interp, expr->token[i].objPtr);
13586 }
13587 Jim_Free(expr->token);
13588 Jim_Free(expr);
13589 }
13590
13591 static void FreeExprInternalRep(Jim_Interp *interp, Jim_Obj *objPtr)
13592 {
13593 ExprByteCode *expr = (void *)objPtr->internalRep.ptr;
13594
13595 if (expr) {
13596 if (--expr->inUse != 0) {
13597 return;
13598 }
13599
13600 ExprFreeByteCode(interp, expr);
13601 }
13602 }
13603
13604 static void DupExprInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr)
13605 {
13606 JIM_NOTUSED(interp);
13607 JIM_NOTUSED(srcPtr);
13608
13609
13610 dupPtr->typePtr = NULL;
13611 }
13612
13613
13614 static int ExprCheckCorrectness(ExprByteCode * expr)
13615 {
13616 int i;
13617 int stacklen = 0;
13618 int ternary = 0;
13619
13620 for (i = 0; i < expr->len; i++) {
13621 ScriptToken *t = &expr->token[i];
13622 const struct Jim_ExprOperator *op = JimExprOperatorInfoByOpcode(t->type);
13623
13624 stacklen -= op->arity;
13625 if (stacklen < 0) {
13626 break;
13627 }
13628 if (t->type == JIM_EXPROP_TERNARY || t->type == JIM_EXPROP_TERNARY_LEFT) {
13629 ternary++;
13630 }
13631 else if (t->type == JIM_EXPROP_COLON || t->type == JIM_EXPROP_COLON_LEFT) {
13632 ternary--;
13633 }
13634
13635
13636 stacklen++;
13637 }
13638 if (stacklen != 1 || ternary != 0) {
13639 return JIM_ERR;
13640 }
13641 return JIM_OK;
13642 }
13643
13644 static int ExprAddLazyOperator(Jim_Interp *interp, ExprByteCode * expr, ParseToken *t)
13645 {
13646 int i;
13647
13648 int leftindex, arity, offset;
13649
13650
13651 leftindex = expr->len - 1;
13652
13653 arity = 1;
13654 while (arity) {
13655 ScriptToken *tt = &expr->token[leftindex];
13656
13657 if (tt->type >= JIM_TT_EXPR_OP) {
13658 arity += JimExprOperatorInfoByOpcode(tt->type)->arity;
13659 }
13660 arity--;
13661 if (--leftindex < 0) {
13662 return JIM_ERR;
13663 }
13664 }
13665 leftindex++;
13666
13667
13668 memmove(&expr->token[leftindex + 2], &expr->token[leftindex],
13669 sizeof(*expr->token) * (expr->len - leftindex));
13670 expr->len += 2;
13671 offset = (expr->len - leftindex) - 1;
13672
13673 expr->token[leftindex + 1].type = t->type + 1;
13674 expr->token[leftindex + 1].objPtr = interp->emptyObj;
13675
13676 expr->token[leftindex].type = JIM_TT_EXPR_INT;
13677 expr->token[leftindex].objPtr = Jim_NewIntObj(interp, offset);
13678
13679
13680 expr->token[expr->len].objPtr = interp->emptyObj;
13681 expr->token[expr->len].type = t->type + 2;
13682 expr->len++;
13683
13684
13685 for (i = leftindex - 1; i > 0; i--) {
13686 const struct Jim_ExprOperator *op = JimExprOperatorInfoByOpcode(expr->token[i].type);
13687 if (op->lazy == LAZY_LEFT) {
13688 if (JimWideValue(expr->token[i - 1].objPtr) + i - 1 >= leftindex) {
13689 JimWideValue(expr->token[i - 1].objPtr) += 2;
13690 }
13691 }
13692 }
13693 return JIM_OK;
13694 }
13695
13696 static int ExprAddOperator(Jim_Interp *interp, ExprByteCode * expr, ParseToken *t)
13697 {
13698 struct ScriptToken *token = &expr->token[expr->len];
13699 const struct Jim_ExprOperator *op = JimExprOperatorInfoByOpcode(t->type);
13700
13701 if (op->lazy == LAZY_OP) {
13702 if (ExprAddLazyOperator(interp, expr, t) != JIM_OK) {
13703 Jim_SetResultFormatted(interp, "Expression has bad operands to %s", op->name);
13704 return JIM_ERR;
13705 }
13706 }
13707 else {
13708 token->objPtr = interp->emptyObj;
13709 token->type = t->type;
13710 expr->len++;
13711 }
13712 return JIM_OK;
13713 }
13714
13715 static int ExprTernaryGetColonLeftIndex(ExprByteCode *expr, int right_index)
13716 {
13717 int ternary_count = 1;
13718
13719 right_index--;
13720
13721 while (right_index > 1) {
13722 if (expr->token[right_index].type == JIM_EXPROP_TERNARY_LEFT) {
13723 ternary_count--;
13724 }
13725 else if (expr->token[right_index].type == JIM_EXPROP_COLON_RIGHT) {
13726 ternary_count++;
13727 }
13728 else if (expr->token[right_index].type == JIM_EXPROP_COLON_LEFT && ternary_count == 1) {
13729 return right_index;
13730 }
13731 right_index--;
13732 }
13733
13734
13735 return -1;
13736 }
13737
13738 static int ExprTernaryGetMoveIndices(ExprByteCode *expr, int right_index, int *prev_right_index, int *prev_left_index)
13739 {
13740 int i = right_index - 1;
13741 int ternary_count = 1;
13742
13743 while (i > 1) {
13744 if (expr->token[i].type == JIM_EXPROP_TERNARY_LEFT) {
13745 if (--ternary_count == 0 && expr->token[i - 2].type == JIM_EXPROP_COLON_RIGHT) {
13746 *prev_right_index = i - 2;
13747 *prev_left_index = ExprTernaryGetColonLeftIndex(expr, *prev_right_index);
13748 return 1;
13749 }
13750 }
13751 else if (expr->token[i].type == JIM_EXPROP_COLON_RIGHT) {
13752 if (ternary_count == 0) {
13753 return 0;
13754 }
13755 ternary_count++;
13756 }
13757 i--;
13758 }
13759 return 0;
13760 }
13761
13762 static void ExprTernaryReorderExpression(Jim_Interp *interp, ExprByteCode *expr)
13763 {
13764 int i;
13765
13766 for (i = expr->len - 1; i > 1; i--) {
13767 int prev_right_index;
13768 int prev_left_index;
13769 int j;
13770 ScriptToken tmp;
13771
13772 if (expr->token[i].type != JIM_EXPROP_COLON_RIGHT) {
13773 continue;
13774 }
13775
13776
13777 if (ExprTernaryGetMoveIndices(expr, i, &prev_right_index, &prev_left_index) == 0) {
13778 continue;
13779 }
13780
13781 tmp = expr->token[prev_right_index];
13782 for (j = prev_right_index; j < i; j++) {
13783 expr->token[j] = expr->token[j + 1];
13784 }
13785 expr->token[i] = tmp;
13786
13787 JimWideValue(expr->token[prev_left_index-1].objPtr) += (i - prev_right_index);
13788
13789
13790 i++;
13791 }
13792 }
13793
13794 static ExprByteCode *ExprCreateByteCode(Jim_Interp *interp, const ParseTokenList *tokenlist, Jim_Obj *fileNameObj)
13795 {
13796 Jim_Stack stack;
13797 ExprByteCode *expr;
13798 int ok = 1;
 
 
 
 
 
 
 
13799 int i;
13800 int prevtt = JIM_TT_NONE;
13801 int have_ternary = 0;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13802
13803
13804 int count = tokenlist->count - 1;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13805
13806 expr = Jim_Alloc(sizeof(*expr));
13807 expr->inUse = 1;
13808 expr->len = 0;
13809
13810 Jim_InitStack(&stack);
13811
13812 for (i = 0; i < tokenlist->count; i++) {
13813 ParseToken *t = &tokenlist->list[i];
13814 const struct Jim_ExprOperator *op = JimExprOperatorInfoByOpcode(t->type);
13815
13816 if (op->lazy == LAZY_OP) {
13817 count += 2;
13818
13819 if (t->type == JIM_EXPROP_TERNARY) {
13820 have_ternary = 1;
13821 }
13822 }
13823 }
13824
13825 expr->token = Jim_Alloc(sizeof(ScriptToken) * count);
13826
13827 for (i = 0; i < tokenlist->count && ok; i++) {
13828 ParseToken *t = &tokenlist->list[i];
13829
13830
13831 struct ScriptToken *token = &expr->token[expr->len];
13832
13833 if (t->type == JIM_TT_EOL) {
13834 break;
13835 }
13836
13837 switch (t->type) {
13838 case JIM_TT_STR:
13839 case JIM_TT_ESC:
13840 case JIM_TT_VAR:
13841 case JIM_TT_DICTSUGAR:
13842 case JIM_TT_EXPRSUGAR:
13843 case JIM_TT_CMD:
13844 token->type = t->type;
13845 strexpr:
13846 token->objPtr = Jim_NewStringObj(interp, t->token, t->len);
13847 if (t->type == JIM_TT_CMD) {
13848
13849 JimSetSourceInfo(interp, token->objPtr, fileNameObj, t->line);
13850 }
13851 expr->len++;
13852 break;
13853
13854 case JIM_TT_EXPR_INT:
13855 case JIM_TT_EXPR_DOUBLE:
13856 {
13857 char *endptr;
13858 if (t->type == JIM_TT_EXPR_INT) {
13859 token->objPtr = Jim_NewIntObj(interp, jim_strtoull(t->token, &endptr));
13860 }
13861 else {
13862 token->objPtr = Jim_NewDoubleObj(interp, strtod(t->token, &endptr));
13863 }
13864 if (endptr != t->token + t->len) {
13865
13866 Jim_FreeNewObj(interp, token->objPtr);
13867 token->type = JIM_TT_STR;
13868 goto strexpr;
13869 }
13870 token->type = t->type;
13871 expr->len++;
13872 }
13873 break;
13874
13875 case JIM_TT_SUBEXPR_START:
13876 Jim_StackPush(&stack, t);
13877 prevtt = JIM_TT_NONE;
13878 continue;
13879
13880 case JIM_TT_SUBEXPR_COMMA:
13881
13882 continue;
13883
13884 case JIM_TT_SUBEXPR_END:
13885 ok = 0;
13886 while (Jim_StackLen(&stack)) {
13887 ParseToken *tt = Jim_StackPop(&stack);
13888
13889 if (tt->type == JIM_TT_SUBEXPR_START) {
13890 ok = 1;
13891 break;
13892 }
13893
13894 if (ExprAddOperator(interp, expr, tt) != JIM_OK) {
13895 goto err;
13896 }
13897 }
13898 if (!ok) {
13899 Jim_SetResultString(interp, "Unexpected close parenthesis", -1);
13900 goto err;
13901 }
13902 break;
13903
13904
13905 default:{
13906
13907 const struct Jim_ExprOperator *op;
13908 ParseToken *tt;
13909
13910
13911 if (prevtt == JIM_TT_NONE || prevtt >= JIM_TT_EXPR_OP) {
13912 if (t->type == JIM_EXPROP_SUB) {
13913 t->type = JIM_EXPROP_UNARYMINUS;
13914 }
13915 else if (t->type == JIM_EXPROP_ADD) {
13916 t->type = JIM_EXPROP_UNARYPLUS;
13917 }
13918 }
13919
13920 op = JimExprOperatorInfoByOpcode(t->type);
13921
13922
13923 while ((tt = Jim_StackPeek(&stack)) != NULL) {
13924 const struct Jim_ExprOperator *tt_op =
13925 JimExprOperatorInfoByOpcode(tt->type);
13926
13927
13928
13929 if (op->arity != 1 && tt_op->precedence >= op->precedence) {
13930 if (ExprAddOperator(interp, expr, tt) != JIM_OK) {
13931 ok = 0;
13932 goto err;
13933 }
13934 Jim_StackPop(&stack);
13935 }
13936 else {
13937 break;
13938 }
13939 }
13940 Jim_StackPush(&stack, t);
13941 break;
13942 }
13943 }
13944 prevtt = t->type;
13945 }
13946
13947
13948 while (Jim_StackLen(&stack)) {
13949 ParseToken *tt = Jim_StackPop(&stack);
13950
13951 if (tt->type == JIM_TT_SUBEXPR_START) {
13952 ok = 0;
13953 Jim_SetResultString(interp, "Missing close parenthesis", -1);
13954 goto err;
13955 }
13956 if (ExprAddOperator(interp, expr, tt) != JIM_OK) {
13957 ok = 0;
13958 goto err;
13959 }
13960 }
13961
13962 if (have_ternary) {
13963 ExprTernaryReorderExpression(interp, expr);
13964 }
13965
13966 err:
13967
13968 Jim_FreeStack(&stack);
13969
13970 for (i = 0; i < expr->len; i++) {
13971 Jim_IncrRefCount(expr->token[i].objPtr);
13972 }
13973
13974 if (!ok) {
13975 ExprFreeByteCode(interp, expr);
13976 return NULL;
13977 }
13978
13979 return expr;
13980 }
13981
13982
13983 static int SetExprFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr)
13984 {
13985 int exprTextLen;
13986 const char *exprText;
13987 struct JimParserCtx parser;
13988 struct ExprByteCode *expr;
13989 ParseTokenList tokenlist;
13990 int line;
13991 Jim_Obj *fileNameObj;
13992 int rc = JIM_ERR;
13993
13994
13995 if (objPtr->typePtr == &sourceObjType) {
13996 fileNameObj = objPtr->internalRep.sourceValue.fileNameObj;
13997 line = objPtr->internalRep.sourceValue.lineNumber;
13998 }
13999 else {
@@ -14002,18 +13885,17 @@
14002 }
14003 Jim_IncrRefCount(fileNameObj);
14004
14005 exprText = Jim_GetString(objPtr, &exprTextLen);
14006
14007
14008 ScriptTokenListInit(&tokenlist);
14009
14010 JimParserInit(&parser, exprText, exprTextLen, line);
14011 while (!parser.eof) {
14012 if (JimParseExpression(&parser) != JIM_OK) {
14013 ScriptTokenListFree(&tokenlist);
14014 invalidexpr:
14015 Jim_SetResultFormatted(interp, "syntax error in expression: \"%#s\"", objPtr);
14016 expr = NULL;
14017 goto err;
14018 }
14019
@@ -14036,125 +13918,174 @@
14036 ScriptTokenListFree(&tokenlist);
14037 Jim_DecrRefCount(interp, fileNameObj);
14038 return JIM_ERR;
14039 }
14040
14041
14042 expr = ExprCreateByteCode(interp, &tokenlist, fileNameObj);
14043
14044
 
 
14045 ScriptTokenListFree(&tokenlist);
14046
14047 if (!expr) {
14048 goto err;
14049 }
14050
14051 #ifdef DEBUG_SHOW_EXPR
14052 {
14053 int i;
14054
14055 printf("==== Expr ====\n");
14056 for (i = 0; i < expr->len; i++) {
14057 ScriptToken *t = &expr->token[i];
14058
14059 printf("[%2d] %s '%s'\n", i, jim_tt_name(t->type), Jim_String(t->objPtr));
14060 }
14061 }
14062 #endif
14063
14064
14065 if (ExprCheckCorrectness(expr) != JIM_OK) {
14066 ExprFreeByteCode(interp, expr);
14067 goto invalidexpr;
14068 }
14069
14070 rc = JIM_OK;
14071
14072 err:
14073
14074 Jim_DecrRefCount(interp, fileNameObj);
14075 Jim_FreeIntRep(interp, objPtr);
14076 Jim_SetIntRepPtr(objPtr, expr);
14077 objPtr->typePtr = &exprObjType;
14078 return rc;
14079 }
14080
14081 static ExprByteCode *JimGetExpression(Jim_Interp *interp, Jim_Obj *objPtr)
14082 {
14083 if (objPtr->typePtr != &exprObjType) {
14084 if (SetExprFromAny(interp, objPtr) != JIM_OK) {
14085 return NULL;
14086 }
14087 }
14088 return (ExprByteCode *) Jim_GetIntRepPtr(objPtr);
14089 }
14090
14091 #ifdef JIM_OPTIMIZATION
14092 static Jim_Obj *JimExprIntValOrVar(Jim_Interp *interp, const ScriptToken *token)
14093 {
14094 if (token->type == JIM_TT_EXPR_INT)
14095 return token->objPtr;
14096 else if (token->type == JIM_TT_VAR)
14097 return Jim_GetVariable(interp, token->objPtr, JIM_NONE);
14098 else if (token->type == JIM_TT_DICTSUGAR)
14099 return JimExpandDictSugar(interp, token->objPtr);
14100 else
14101 return NULL;
14102 }
14103 #endif
14104
14105 #define JIM_EE_STATICSTACK_LEN 10
14106
14107 int Jim_EvalExpression(Jim_Interp *interp, Jim_Obj *exprObjPtr, Jim_Obj **exprResultPtrPtr)
14108 {
14109 ExprByteCode *expr;
14110 Jim_Obj *staticStack[JIM_EE_STATICSTACK_LEN];
14111 int i;
14112 int retcode = JIM_OK;
14113 struct JimExprState e;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
14114
14115 expr = JimGetExpression(interp, exprObjPtr);
14116 if (!expr) {
14117 return JIM_ERR;
14118 }
14119
14120 #ifdef JIM_OPTIMIZATION
14121 {
14122 Jim_Obj *objPtr;
14123
14124
14125 switch (expr->len) {
14126 case 1:
14127 objPtr = JimExprIntValOrVar(interp, &expr->token[0]);
14128 if (objPtr) {
14129 Jim_IncrRefCount(objPtr);
14130 *exprResultPtrPtr = objPtr;
14131 return JIM_OK;
14132 }
14133 break;
14134
14135 case 2:
14136 if (expr->token[1].type == JIM_EXPROP_NOT) {
14137 objPtr = JimExprIntValOrVar(interp, &expr->token[0]);
14138
14139 if (objPtr && JimIsWide(objPtr)) {
14140 *exprResultPtrPtr = JimWideValue(objPtr) ? interp->falseObj : interp->trueObj;
14141 Jim_IncrRefCount(*exprResultPtrPtr);
14142 return JIM_OK;
14143 }
14144 }
14145 break;
14146
14147 case 3:
14148 objPtr = JimExprIntValOrVar(interp, &expr->token[0]);
14149 if (objPtr && JimIsWide(objPtr)) {
14150 Jim_Obj *objPtr2 = JimExprIntValOrVar(interp, &expr->token[1]);
14151 if (objPtr2 && JimIsWide(objPtr2)) {
14152 jim_wide wideValueA = JimWideValue(objPtr);
14153 jim_wide wideValueB = JimWideValue(objPtr2);
14154 int cmpRes;
14155 switch (expr->token[2].type) {
14156 case JIM_EXPROP_LT:
14157 cmpRes = wideValueA < wideValueB;
14158 break;
14159 case JIM_EXPROP_LTE:
14160 cmpRes = wideValueA <= wideValueB;
@@ -14172,12 +14103,11 @@
14172 cmpRes = wideValueA != wideValueB;
14173 break;
14174 default:
14175 goto noopt;
14176 }
14177 *exprResultPtrPtr = cmpRes ? interp->trueObj : interp->falseObj;
14178 Jim_IncrRefCount(*exprResultPtrPtr);
14179 return JIM_OK;
14180 }
14181 }
14182 break;
14183 }
@@ -14185,145 +14115,64 @@
14185 noopt:
14186 #endif
14187
14188 expr->inUse++;
14189
14190
14191
14192 if (expr->len > JIM_EE_STATICSTACK_LEN)
14193 e.stack = Jim_Alloc(sizeof(Jim_Obj *) * expr->len);
14194 else
14195 e.stack = staticStack;
14196
14197 e.stacklen = 0;
14198
14199
14200 for (i = 0; i < expr->len && retcode == JIM_OK; i++) {
14201 Jim_Obj *objPtr;
14202
14203 switch (expr->token[i].type) {
14204 case JIM_TT_EXPR_INT:
14205 case JIM_TT_EXPR_DOUBLE:
14206 case JIM_TT_STR:
14207 ExprPush(&e, expr->token[i].objPtr);
14208 break;
14209
14210 case JIM_TT_VAR:
14211 objPtr = Jim_GetVariable(interp, expr->token[i].objPtr, JIM_ERRMSG);
14212 if (objPtr) {
14213 ExprPush(&e, objPtr);
14214 }
14215 else {
14216 retcode = JIM_ERR;
14217 }
14218 break;
14219
14220 case JIM_TT_DICTSUGAR:
14221 objPtr = JimExpandDictSugar(interp, expr->token[i].objPtr);
14222 if (objPtr) {
14223 ExprPush(&e, objPtr);
14224 }
14225 else {
14226 retcode = JIM_ERR;
14227 }
14228 break;
14229
14230 case JIM_TT_ESC:
14231 retcode = Jim_SubstObj(interp, expr->token[i].objPtr, &objPtr, JIM_NONE);
14232 if (retcode == JIM_OK) {
14233 ExprPush(&e, objPtr);
14234 }
14235 break;
14236
14237 case JIM_TT_CMD:
14238 retcode = Jim_EvalObj(interp, expr->token[i].objPtr);
14239 if (retcode == JIM_OK) {
14240 ExprPush(&e, Jim_GetResult(interp));
14241 }
14242 break;
14243
14244 default:{
14245
14246 e.skip = 0;
14247 e.opcode = expr->token[i].type;
14248
14249 retcode = JimExprOperatorInfoByOpcode(e.opcode)->funcop(interp, &e);
14250
14251 i += e.skip;
14252 continue;
14253 }
14254 }
14255 }
14256
14257 expr->inUse--;
14258
14259 if (retcode == JIM_OK) {
14260 *exprResultPtrPtr = ExprPop(&e);
14261 }
14262 else {
14263 for (i = 0; i < e.stacklen; i++) {
14264 Jim_DecrRefCount(interp, e.stack[i]);
14265 }
14266 }
14267 if (e.stack != staticStack) {
14268 Jim_Free(e.stack);
14269 }
14270 return retcode;
14271 }
14272
14273 int Jim_GetBoolFromExpr(Jim_Interp *interp, Jim_Obj *exprObjPtr, int *boolPtr)
14274 {
14275 int retcode;
14276 jim_wide wideValue;
14277 double doubleValue;
14278 Jim_Obj *exprResultPtr;
14279
14280 retcode = Jim_EvalExpression(interp, exprObjPtr, &exprResultPtr);
14281 if (retcode != JIM_OK)
14282 return retcode;
14283
14284 if (JimGetWideNoErr(interp, exprResultPtr, &wideValue) != JIM_OK) {
14285 if (Jim_GetDouble(interp, exprResultPtr, &doubleValue) != JIM_OK) {
14286 Jim_DecrRefCount(interp, exprResultPtr);
14287 return JIM_ERR;
14288 }
14289 else {
14290 Jim_DecrRefCount(interp, exprResultPtr);
14291 *boolPtr = doubleValue != 0;
14292 return JIM_OK;
14293 }
14294 }
14295 *boolPtr = wideValue != 0;
14296
14297 Jim_DecrRefCount(interp, exprResultPtr);
14298 return JIM_OK;
14299 }
14300
14301
14302
14303
14304 typedef struct ScanFmtPartDescr
14305 {
14306 char *arg;
14307 char *prefix;
14308 size_t width;
14309 int pos;
14310 char type;
14311 char modifier;
14312 } ScanFmtPartDescr;
14313
14314
14315 typedef struct ScanFmtStringObj
14316 {
14317 jim_wide size;
14318 char *stringRep;
14319 size_t count;
14320 size_t convCount;
14321 size_t maxPos;
14322 const char *error;
14323 char *scratch;
14324 ScanFmtPartDescr descr[1];
14325 } ScanFmtStringObj;
14326
14327
14328 static void FreeScanFmtInternalRep(Jim_Interp *interp, Jim_Obj *objPtr);
14329 static void DupScanFmtInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr);
@@ -14364,28 +14213,28 @@
14364 static int SetScanFmtFromAny(Jim_Interp *interp, Jim_Obj *objPtr)
14365 {
14366 ScanFmtStringObj *fmtObj;
14367 char *buffer;
14368 int maxCount, i, approxSize, lastPos = -1;
14369 const char *fmt = objPtr->bytes;
14370 int maxFmtLen = objPtr->length;
14371 const char *fmtEnd = fmt + maxFmtLen;
14372 int curr;
14373
14374 Jim_FreeIntRep(interp, objPtr);
14375
14376 for (i = 0, maxCount = 0; i < maxFmtLen; ++i)
14377 if (fmt[i] == '%')
14378 ++maxCount;
14379
14380 approxSize = sizeof(ScanFmtStringObj)
14381 +(maxCount + 1) * sizeof(ScanFmtPartDescr)
14382 +maxFmtLen * sizeof(char) + 3 + 1
14383 + maxFmtLen * sizeof(char) + 1
14384 + maxFmtLen * sizeof(char)
14385 +(maxCount + 1) * sizeof(char)
14386 +1;
14387 fmtObj = (ScanFmtStringObj *) Jim_Alloc(approxSize);
14388 memset(fmtObj, 0, approxSize);
14389 fmtObj->size = approxSize;
14390 fmtObj->maxPos = 0;
14391 fmtObj->scratch = (char *)&fmtObj->descr[maxCount + 1];
@@ -14397,12 +14246,12 @@
14397 for (i = 0, curr = 0; fmt < fmtEnd; ++fmt) {
14398 int width = 0, skip;
14399 ScanFmtPartDescr *descr = &fmtObj->descr[curr];
14400
14401 fmtObj->count++;
14402 descr->width = 0;
14403
14404 if (*fmt != '%' || fmt[1] == '%') {
14405 descr->type = 0;
14406 descr->prefix = &buffer[i];
14407 for (; fmt < fmtEnd; ++fmt) {
14408 if (*fmt == '%') {
@@ -14412,65 +14261,70 @@
14412 }
14413 buffer[i++] = *fmt;
14414 }
14415 buffer[i++] = 0;
14416 }
14417
14418 ++fmt;
14419
14420 if (fmt >= fmtEnd)
14421 goto done;
14422 descr->pos = 0;
14423 if (*fmt == '*') {
14424 descr->pos = -1;
14425 ++fmt;
14426 }
14427 else
14428 fmtObj->convCount++;
14429
14430 if (sscanf(fmt, "%d%n", &width, &skip) == 1) {
14431 fmt += skip;
14432
14433 if (descr->pos != -1 && *fmt == '$') {
14434 int prev;
14435
14436 ++fmt;
14437 descr->pos = width;
14438 width = 0;
14439
14440 if ((lastPos == 0 && descr->pos > 0)
14441 || (lastPos > 0 && descr->pos == 0)) {
14442 fmtObj->error = "cannot mix \"%\" and \"%n$\" conversion specifiers";
14443 return JIM_ERR;
14444 }
14445
14446 for (prev = 0; prev < curr; ++prev) {
14447 if (fmtObj->descr[prev].pos == -1)
14448 continue;
14449 if (fmtObj->descr[prev].pos == descr->pos) {
14450 fmtObj->error =
14451 "variable is assigned by multiple \"%n$\" conversion specifiers";
14452 return JIM_ERR;
14453 }
14454 }
14455
 
 
 
 
 
14456 if (sscanf(fmt, "%d%n", &width, &skip) == 1) {
14457 descr->width = width;
14458 fmt += skip;
14459 }
14460 if (descr->pos > 0 && (size_t) descr->pos > fmtObj->maxPos)
14461 fmtObj->maxPos = descr->pos;
14462 }
14463 else {
14464
14465 descr->width = width;
14466 }
14467 }
14468
14469 if (lastPos == -1)
14470 lastPos = descr->pos;
14471
14472 if (*fmt == '[') {
14473 int swapped = 1, beg = i, end, j;
14474
14475 descr->type = '[';
14476 descr->arg = &buffer[i];
@@ -14485,11 +14339,11 @@
14485 fmtObj->error = "unmatched [ in format string";
14486 return JIM_ERR;
14487 }
14488 end = i;
14489 buffer[i++] = 0;
14490
14491 while (swapped) {
14492 swapped = 0;
14493 for (j = beg + 1; j < end - 1; ++j) {
14494 if (buffer[j] == '-' && buffer[j - 1] > buffer[j + 1]) {
14495 char tmp = buffer[j - 1];
@@ -14500,13 +14354,18 @@
14500 }
14501 }
14502 }
14503 }
14504 else {
14505
14506 if (strchr("hlL", *fmt) != 0)
14507 descr->modifier = tolower((int)*fmt++);
 
 
 
 
 
14508
14509 descr->type = *fmt;
14510 if (strchr("efgcsndoxui", *fmt) == 0) {
14511 fmtObj->error = "bad scan conversion character";
14512 return JIM_ERR;
@@ -14543,11 +14402,11 @@
14543 while (*str) {
14544 int c;
14545 int n;
14546
14547 if (!sdescr && isspace(UCHAR(*str)))
14548 break;
14549
14550 n = utf8_tounicode(str, &c);
14551 if (sdescr && !JimCharsetMatch(sdescr, c, JIM_CHARSET_SCAN))
14552 break;
14553 while (n--)
@@ -14566,89 +14425,89 @@
14566 size_t scanned = 0;
14567 size_t anchor = pos;
14568 int i;
14569 Jim_Obj *tmpObj = NULL;
14570
14571
14572 *valObjPtr = 0;
14573 if (descr->prefix) {
14574 for (i = 0; pos < strLen && descr->prefix[i]; ++i) {
14575
14576 if (isspace(UCHAR(descr->prefix[i])))
14577 while (pos < strLen && isspace(UCHAR(str[pos])))
14578 ++pos;
14579 else if (descr->prefix[i] != str[pos])
14580 break;
14581 else
14582 ++pos;
14583 }
14584 if (pos >= strLen) {
14585 return -1;
14586 }
14587 else if (descr->prefix[i] != 0)
14588 return 0;
14589 }
14590
14591 if (descr->type != 'c' && descr->type != '[' && descr->type != 'n')
14592 while (isspace(UCHAR(str[pos])))
14593 ++pos;
14594
14595 scanned = pos - anchor;
14596
14597
14598 if (descr->type == 'n') {
14599
14600 *valObjPtr = Jim_NewIntObj(interp, anchor + scanned);
14601 }
14602 else if (pos >= strLen) {
14603
14604 return -1;
14605 }
14606 else if (descr->type == 'c') {
14607 int c;
14608 scanned += utf8_tounicode(&str[pos], &c);
14609 *valObjPtr = Jim_NewIntObj(interp, c);
14610 return scanned;
14611 }
14612 else {
14613
14614 if (descr->width > 0) {
14615 size_t sLen = utf8_strlen(&str[pos], strLen - pos);
14616 size_t tLen = descr->width > sLen ? sLen : descr->width;
14617
14618 tmpObj = Jim_NewStringObjUtf8(interp, str + pos, tLen);
14619 tok = tmpObj->bytes;
14620 }
14621 else {
14622
14623 tok = &str[pos];
14624 }
14625 switch (descr->type) {
14626 case 'd':
14627 case 'o':
14628 case 'x':
14629 case 'u':
14630 case 'i':{
14631 char *endp;
14632 jim_wide w;
14633
14634 int base = descr->type == 'o' ? 8
14635 : descr->type == 'x' ? 16 : descr->type == 'i' ? 0 : 10;
14636
14637
14638 if (base == 0) {
14639 w = jim_strtoull(tok, &endp);
14640 }
14641 else {
14642 w = strtoull(tok, &endp, base);
14643 }
14644
14645 if (endp != tok) {
14646
14647 *valObjPtr = Jim_NewIntObj(interp, w);
14648
14649
14650 scanned += endp - tok;
14651 }
14652 else {
14653 scanned = *tok ? 0 : -1;
14654 }
@@ -14665,13 +14524,13 @@
14665 case 'g':{
14666 char *endp;
14667 double value = strtod(tok, &endp);
14668
14669 if (endp != tok) {
14670
14671 *valObjPtr = Jim_NewDoubleObj(interp, value);
14672
14673 scanned += endp - tok;
14674 }
14675 else {
14676 scanned = *tok ? 0 : -1;
14677 }
@@ -14696,65 +14555,65 @@
14696 Jim_Obj **resultVec = 0;
14697 int resultc;
14698 Jim_Obj *emptyStr = 0;
14699 ScanFmtStringObj *fmtObj;
14700
14701
14702 JimPanic((fmtObjPtr->typePtr != &scanFmtStringObjType, "Jim_ScanString() for non-scan format"));
14703
14704 fmtObj = (ScanFmtStringObj *) fmtObjPtr->internalRep.ptr;
14705
14706 if (fmtObj->error != 0) {
14707 if (flags & JIM_ERRMSG)
14708 Jim_SetResultString(interp, fmtObj->error, -1);
14709 return 0;
14710 }
14711
14712 emptyStr = Jim_NewEmptyStringObj(interp);
14713 Jim_IncrRefCount(emptyStr);
14714
14715 resultList = Jim_NewListObj(interp, NULL, 0);
14716 if (fmtObj->maxPos > 0) {
14717 for (i = 0; i < fmtObj->maxPos; ++i)
14718 Jim_ListAppendElement(interp, resultList, emptyStr);
14719 JimListGetElements(interp, resultList, &resultc, &resultVec);
14720 }
14721
14722 for (i = 0, pos = 0; i < fmtObj->count; ++i) {
14723 ScanFmtPartDescr *descr = &(fmtObj->descr[i]);
14724 Jim_Obj *value = 0;
14725
14726
14727 if (descr->type == 0)
14728 continue;
14729
14730 if (scanned > 0)
14731 scanned = ScanOneEntry(interp, str, pos, strLen, fmtObj, i, &value);
14732
14733 if (scanned == -1 && i == 0)
14734 goto eof;
14735
14736 pos += scanned;
14737
14738
14739 if (value == 0)
14740 value = Jim_NewEmptyStringObj(interp);
14741
14742 if (descr->pos == -1) {
14743 Jim_FreeNewObj(interp, value);
14744 }
14745 else if (descr->pos == 0)
14746
14747 Jim_ListAppendElement(interp, resultList, value);
14748 else if (resultVec[descr->pos - 1] == emptyStr) {
14749
14750 Jim_DecrRefCount(interp, resultVec[descr->pos - 1]);
14751 Jim_IncrRefCount(value);
14752 resultVec[descr->pos - 1] = value;
14753 }
14754 else {
14755
14756 Jim_FreeNewObj(interp, value);
14757 goto err;
14758 }
14759 }
14760 Jim_DecrRefCount(interp, emptyStr);
@@ -14792,15 +14651,15 @@
14792 {
14793 Jim_PrngState *prng;
14794 unsigned char *destByte = (unsigned char *)dest;
14795 unsigned int si, sj, x;
14796
14797
14798 if (interp->prngState == NULL)
14799 JimPrngInit(interp);
14800 prng = interp->prngState;
14801
14802 for (x = 0; x < len; x++) {
14803 prng->i = (prng->i + 1) & 0xff;
14804 si = prng->sbox[prng->i];
14805 prng->j = (prng->j + si) & 0xff;
14806 sj = prng->sbox[prng->j];
@@ -14814,19 +14673,19 @@
14814 static void JimPrngSeed(Jim_Interp *interp, unsigned char *seed, int seedLen)
14815 {
14816 int i;
14817 Jim_PrngState *prng;
14818
14819
14820 if (interp->prngState == NULL)
14821 JimPrngInit(interp);
14822 prng = interp->prngState;
14823
14824
14825 for (i = 0; i < 256; i++)
14826 prng->sbox[i] = i;
14827
14828 for (i = 0; i < seedLen; i++) {
14829 unsigned char t;
14830
14831 t = prng->sbox[i & 0xFF];
14832 prng->sbox[i & 0xFF] = prng->sbox[seed[i]];
@@ -14853,11 +14712,11 @@
14853 if (Jim_GetWide(interp, argv[2], &increment) != JIM_OK)
14854 return JIM_ERR;
14855 }
14856 intObjPtr = Jim_GetVariable(interp, argv[1], JIM_UNSHARED);
14857 if (!intObjPtr) {
14858
14859 wideValue = 0;
14860 }
14861 else if (Jim_GetWide(interp, intObjPtr, &wideValue) != JIM_OK) {
14862 return JIM_ERR;
14863 }
@@ -14867,26 +14726,26 @@
14867 Jim_FreeNewObj(interp, intObjPtr);
14868 return JIM_ERR;
14869 }
14870 }
14871 else {
14872
14873 Jim_InvalidateStringRep(intObjPtr);
14874 JimWideValue(intObjPtr) = wideValue + increment;
14875
14876 if (argv[1]->typePtr != &variableObjType) {
14877
14878 Jim_SetVariable(interp, argv[1], intObjPtr);
14879 }
14880 }
14881 Jim_SetResult(interp, intObjPtr);
14882 return JIM_OK;
14883 }
14884
14885
14886 #define JIM_EVAL_SARGV_LEN 8
14887 #define JIM_EVAL_SINTV_LEN 8
14888
14889
14890 static int JimUnknown(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
14891 {
14892 int retcode;
@@ -14894,16 +14753,16 @@
14894 if (interp->unknown_called > 50) {
14895 return JIM_ERR;
14896 }
14897
14898
14899
14900 if (Jim_GetCommand(interp, interp->unknown, JIM_NONE) == NULL)
14901 return JIM_ERR;
14902
14903 interp->unknown_called++;
14904
14905 retcode = Jim_EvalObjPrefix(interp, interp->unknown, argc, argv);
14906 interp->unknown_called--;
14907
14908 return retcode;
14909 }
@@ -14910,10 +14769,11 @@
14910
14911 static int JimInvokeCommand(Jim_Interp *interp, int objc, Jim_Obj *const *objv)
14912 {
14913 int retcode;
14914 Jim_Cmd *cmdPtr;
 
14915
14916 #if 0
14917 printf("invoke");
14918 int j;
14919 for (j = 0; j < objc; j++) {
@@ -14921,11 +14781,11 @@
14921 }
14922 printf("\n");
14923 #endif
14924
14925 if (interp->framePtr->tailcallCmd) {
14926
14927 cmdPtr = interp->framePtr->tailcallCmd;
14928 interp->framePtr->tailcallCmd = NULL;
14929 }
14930 else {
14931 cmdPtr = Jim_GetCommand(interp, objv[0], JIM_ERRMSG);
@@ -14939,20 +14799,22 @@
14939 Jim_SetResultString(interp, "Infinite eval recursion", -1);
14940 retcode = JIM_ERR;
14941 goto out;
14942 }
14943 interp->evalDepth++;
 
14944
14945
14946 Jim_SetEmptyResult(interp);
14947 if (cmdPtr->isproc) {
14948 retcode = JimCallProcedure(interp, cmdPtr, objc, objv);
14949 }
14950 else {
14951 interp->cmdPrivData = cmdPtr->u.native.privData;
14952 retcode = cmdPtr->u.native.cmdProc(interp, objc, objv);
14953 }
 
14954 interp->evalDepth--;
14955
14956 out:
14957 JimDecrCmdRefCount(interp, cmdPtr);
14958
@@ -14961,17 +14823,17 @@
14961
14962 int Jim_EvalObjVector(Jim_Interp *interp, int objc, Jim_Obj *const *objv)
14963 {
14964 int i, retcode;
14965
14966
14967 for (i = 0; i < objc; i++)
14968 Jim_IncrRefCount(objv[i]);
14969
14970 retcode = JimInvokeCommand(interp, objc, objv);
14971
14972
14973 for (i = 0; i < objc; i++)
14974 Jim_DecrRefCount(interp, objv[i]);
14975
14976 return retcode;
14977 }
@@ -14989,25 +14851,25 @@
14989 }
14990
14991 static void JimAddErrorToStack(Jim_Interp *interp, ScriptObj *script)
14992 {
14993 if (!interp->errorFlag) {
14994
14995 interp->errorFlag = 1;
14996 Jim_IncrRefCount(script->fileNameObj);
14997 Jim_DecrRefCount(interp, interp->errorFileNameObj);
14998 interp->errorFileNameObj = script->fileNameObj;
14999 interp->errorLine = script->linenr;
15000
15001 JimResetStackTrace(interp);
15002
15003 interp->addStackTrace++;
15004 }
15005
15006
15007 if (interp->addStackTrace > 0) {
15008
15009
15010 JimAppendStackTrace(interp, Jim_String(interp->errorProc), script->fileNameObj, script->linenr);
15011
15012 if (Jim_Length(script->fileNameObj)) {
15013 interp->addStackTrace = 0;
@@ -15042,14 +14904,14 @@
15042 case JIM_OK:
15043 case JIM_RETURN:
15044 objPtr = interp->result;
15045 break;
15046 case JIM_BREAK:
15047
15048 return JIM_BREAK;
15049 case JIM_CONTINUE:
15050
15051 return JIM_CONTINUE;
15052 default:
15053 return JIM_ERR;
15054 }
15055 break;
@@ -15084,23 +14946,23 @@
15084 case JIM_OK:
15085 case JIM_RETURN:
15086 break;
15087 case JIM_BREAK:
15088 if (flags & JIM_SUBST_FLAG) {
15089
15090 tokens = i;
15091 continue;
15092 }
15093
15094
15095 case JIM_CONTINUE:
15096 if (flags & JIM_SUBST_FLAG) {
15097 intv[i] = NULL;
15098 continue;
15099 }
15100
15101
15102 default:
15103 while (i--) {
15104 Jim_DecrRefCount(interp, intv[i]);
15105 }
15106 if (intv != sintv) {
@@ -15111,28 +14973,29 @@
15111 Jim_IncrRefCount(intv[i]);
15112 Jim_String(intv[i]);
15113 totlen += intv[i]->length;
15114 }
15115
15116
15117 if (tokens == 1 && intv[0] && intv == sintv) {
15118 Jim_DecrRefCount(interp, intv[0]);
 
15119 return intv[0];
15120 }
15121
15122 objPtr = Jim_NewStringObjNoAlloc(interp, NULL, 0);
15123
15124 if (tokens == 4 && token[0].type == JIM_TT_ESC && token[1].type == JIM_TT_ESC
15125 && token[2].type == JIM_TT_VAR) {
15126
15127 objPtr->typePtr = &interpolatedObjType;
15128 objPtr->internalRep.dictSubstValue.varNameObjPtr = token[0].objPtr;
15129 objPtr->internalRep.dictSubstValue.indexObjPtr = intv[2];
15130 Jim_IncrRefCount(intv[2]);
15131 }
15132 else if (tokens && intv[0] && intv[0]->typePtr == &sourceObjType) {
15133
15134 JimSetSourceInfo(interp, objPtr, intv[0]->internalRep.sourceValue.fileNameObj, intv[0]->internalRep.sourceValue.lineNumber);
15135 }
15136
15137
15138 s = objPtr->bytes = Jim_Alloc(totlen + 1);
@@ -15143,11 +15006,11 @@
15143 s += intv[i]->length;
15144 Jim_DecrRefCount(interp, intv[i]);
15145 }
15146 }
15147 objPtr->bytes[totlen] = '\0';
15148
15149 if (intv != sintv) {
15150 Jim_Free(intv);
15151 }
15152
15153 return objPtr;
@@ -15187,11 +15050,11 @@
15187
15188 if (Jim_IsList(scriptObjPtr) && scriptObjPtr->bytes == NULL) {
15189 return JimEvalObjList(interp, scriptObjPtr);
15190 }
15191
15192 Jim_IncrRefCount(scriptObjPtr);
15193 script = JimGetScript(interp, scriptObjPtr);
15194 if (!JimScriptValid(interp, script)) {
15195 Jim_DecrRefCount(interp, scriptObjPtr);
15196 return JIM_ERR;
15197 }
@@ -15223,11 +15086,11 @@
15223 }
15224 #endif
15225
15226 script->inUse++;
15227
15228
15229 prevScriptObj = interp->currentScriptObj;
15230 interp->currentScriptObj = scriptObjPtr;
15231
15232 interp->errorFlag = 0;
15233 argv = sargv;
@@ -15234,19 +15097,19 @@
15234
15235 for (i = 0; i < script->len && retcode == JIM_OK; ) {
15236 int argc;
15237 int j;
15238
15239
15240 argc = token[i].objPtr->internalRep.scriptLineValue.argc;
15241 script->linenr = token[i].objPtr->internalRep.scriptLineValue.line;
15242
15243
15244 if (argc > JIM_EVAL_SARGV_LEN)
15245 argv = Jim_Alloc(sizeof(Jim_Obj *) * argc);
15246
15247
15248 i++;
15249
15250 for (j = 0; j < argc; j++) {
15251 long wordtokens = 1;
15252 int expand = 0;
@@ -15302,11 +15165,11 @@
15302
15303 if (!expand) {
15304 argv[j] = wordObjPtr;
15305 }
15306 else {
15307
15308 int len = Jim_ListLength(interp, wordObjPtr);
15309 int newargc = argc + len - 1;
15310 int k;
15311
15312 if (len > 1) {
@@ -15315,39 +15178,39 @@
15315 argv = Jim_Alloc(sizeof(*argv) * newargc);
15316 memcpy(argv, sargv, sizeof(*argv) * j);
15317 }
15318 }
15319 else {
15320
15321 argv = Jim_Realloc(argv, sizeof(*argv) * newargc);
15322 }
15323 }
15324
15325
15326 for (k = 0; k < len; k++) {
15327 argv[j++] = wordObjPtr->internalRep.listValue.ele[k];
15328 Jim_IncrRefCount(wordObjPtr->internalRep.listValue.ele[k]);
15329 }
15330
15331 Jim_DecrRefCount(interp, wordObjPtr);
15332
15333
15334 j--;
15335 argc += len - 1;
15336 }
15337 }
15338
15339 if (retcode == JIM_OK && argc) {
15340
15341 retcode = JimInvokeCommand(interp, argc, argv);
15342
15343 if (Jim_CheckSignal(interp)) {
15344 retcode = JIM_SIGNAL;
15345 }
15346 }
15347
15348
15349 while (j-- > 0) {
15350 Jim_DecrRefCount(interp, argv[j]);
15351 }
15352
15353 if (argv != sargv) {
@@ -15354,21 +15217,21 @@
15354 Jim_Free(argv);
15355 argv = sargv;
15356 }
15357 }
15358
15359
15360 if (retcode == JIM_ERR) {
15361 JimAddErrorToStack(interp, script);
15362 }
15363
15364 else if (retcode != JIM_RETURN || interp->returnCode != JIM_ERR) {
15365
15366 interp->addStackTrace = 0;
15367 }
15368
15369
15370 interp->currentScriptObj = prevScriptObj;
15371
15372 Jim_FreeIntRep(interp, scriptObjPtr);
15373 scriptObjPtr->typePtr = &scriptObjType;
15374 Jim_SetIntRepPtr(scriptObjPtr, script);
@@ -15378,14 +15241,14 @@
15378 }
15379
15380 static int JimSetProcArg(Jim_Interp *interp, Jim_Obj *argNameObj, Jim_Obj *argValObj)
15381 {
15382 int retcode;
15383
15384 const char *varname = Jim_String(argNameObj);
15385 if (*varname == '&') {
15386
15387 Jim_Obj *objPtr;
15388 Jim_CallFrame *savedCallFrame = interp->framePtr;
15389
15390 interp->framePtr = interp->framePtr->parent;
15391 objPtr = Jim_GetVariable(interp, argValObj, JIM_ERRMSG);
@@ -15392,11 +15255,11 @@
15392 interp->framePtr = savedCallFrame;
15393 if (!objPtr) {
15394 return JIM_ERR;
15395 }
15396
15397
15398 objPtr = Jim_NewStringObj(interp, varname + 1, -1);
15399 Jim_IncrRefCount(objPtr);
15400 retcode = Jim_SetVariableLink(interp, objPtr, argValObj, interp->framePtr->parent);
15401 Jim_DecrRefCount(interp, objPtr);
15402 }
@@ -15406,26 +15269,26 @@
15406 return retcode;
15407 }
15408
15409 static void JimSetProcWrongArgs(Jim_Interp *interp, Jim_Obj *procNameObj, Jim_Cmd *cmd)
15410 {
15411
15412 Jim_Obj *argmsg = Jim_NewStringObj(interp, "", 0);
15413 int i;
15414
15415 for (i = 0; i < cmd->u.proc.argListLen; i++) {
15416 Jim_AppendString(interp, argmsg, " ", 1);
15417
15418 if (i == cmd->u.proc.argsPos) {
15419 if (cmd->u.proc.arglist[i].defaultObjPtr) {
15420
15421 Jim_AppendString(interp, argmsg, "?", 1);
15422 Jim_AppendObj(interp, argmsg, cmd->u.proc.arglist[i].defaultObjPtr);
15423 Jim_AppendString(interp, argmsg, " ...?", -1);
15424 }
15425 else {
15426
15427 Jim_AppendString(interp, argmsg, "?arg...?", -1);
15428 }
15429 }
15430 else {
15431 if (cmd->u.proc.arglist[i].defaultObjPtr) {
@@ -15441,20 +15304,19 @@
15441 Jim_AppendString(interp, argmsg, arg, -1);
15442 }
15443 }
15444 }
15445 Jim_SetResultFormatted(interp, "wrong # args: should be \"%#s%#s\"", procNameObj, argmsg);
15446 Jim_FreeNewObj(interp, argmsg);
15447 }
15448
15449 #ifdef jim_ext_namespace
15450 int Jim_EvalNamespace(Jim_Interp *interp, Jim_Obj *scriptObj, Jim_Obj *nsObj)
15451 {
15452 Jim_CallFrame *callFramePtr;
15453 int retcode;
15454
15455
15456 callFramePtr = JimCreateCallFrame(interp, interp->framePtr, nsObj);
15457 callFramePtr->argv = &interp->emptyObj;
15458 callFramePtr->argc = 0;
15459 callFramePtr->procArgsObjPtr = NULL;
15460 callFramePtr->procBodyObjPtr = scriptObj;
@@ -15462,21 +15324,21 @@
15462 callFramePtr->fileNameObj = interp->emptyObj;
15463 callFramePtr->line = 0;
15464 Jim_IncrRefCount(scriptObj);
15465 interp->framePtr = callFramePtr;
15466
15467
15468 if (interp->framePtr->level == interp->maxCallFrameDepth) {
15469 Jim_SetResultString(interp, "Too many nested calls. Infinite recursion?", -1);
15470 retcode = JIM_ERR;
15471 }
15472 else {
15473
15474 retcode = Jim_EvalObj(interp, scriptObj);
15475 }
15476
15477
15478 interp->framePtr = interp->framePtr->parent;
15479 JimFreeCallFrame(interp, callFramePtr, JIM_FCF_REUSE);
15480
15481 return retcode;
15482 }
@@ -15486,62 +15348,62 @@
15486 {
15487 Jim_CallFrame *callFramePtr;
15488 int i, d, retcode, optargs;
15489 ScriptObj *script;
15490
15491
15492 if (argc - 1 < cmd->u.proc.reqArity ||
15493 (cmd->u.proc.argsPos < 0 && argc - 1 > cmd->u.proc.reqArity + cmd->u.proc.optArity)) {
15494 JimSetProcWrongArgs(interp, argv[0], cmd);
15495 return JIM_ERR;
15496 }
15497
15498 if (Jim_Length(cmd->u.proc.bodyObjPtr) == 0) {
15499
15500 return JIM_OK;
15501 }
15502
15503
15504 if (interp->framePtr->level == interp->maxCallFrameDepth) {
15505 Jim_SetResultString(interp, "Too many nested calls. Infinite recursion?", -1);
15506 return JIM_ERR;
15507 }
15508
15509
15510 callFramePtr = JimCreateCallFrame(interp, interp->framePtr, cmd->u.proc.nsObj);
15511 callFramePtr->argv = argv;
15512 callFramePtr->argc = argc;
15513 callFramePtr->procArgsObjPtr = cmd->u.proc.argListObjPtr;
15514 callFramePtr->procBodyObjPtr = cmd->u.proc.bodyObjPtr;
15515 callFramePtr->staticVars = cmd->u.proc.staticVars;
15516
15517
15518 script = JimGetScript(interp, interp->currentScriptObj);
15519 callFramePtr->fileNameObj = script->fileNameObj;
15520 callFramePtr->line = script->linenr;
15521
15522 Jim_IncrRefCount(cmd->u.proc.argListObjPtr);
15523 Jim_IncrRefCount(cmd->u.proc.bodyObjPtr);
15524 interp->framePtr = callFramePtr;
15525
15526
15527 optargs = (argc - 1 - cmd->u.proc.reqArity);
15528
15529
15530 i = 1;
15531 for (d = 0; d < cmd->u.proc.argListLen; d++) {
15532 Jim_Obj *nameObjPtr = cmd->u.proc.arglist[d].nameObjPtr;
15533 if (d == cmd->u.proc.argsPos) {
15534
15535 Jim_Obj *listObjPtr;
15536 int argsLen = 0;
15537 if (cmd->u.proc.reqArity + cmd->u.proc.optArity < argc - 1) {
15538 argsLen = argc - 1 - (cmd->u.proc.reqArity + cmd->u.proc.optArity);
15539 }
15540 listObjPtr = Jim_NewListObj(interp, &argv[i], argsLen);
15541
15542
15543 if (cmd->u.proc.arglist[d].defaultObjPtr) {
15544 nameObjPtr =cmd->u.proc.arglist[d].defaultObjPtr;
15545 }
15546 retcode = Jim_SetVariable(interp, nameObjPtr, listObjPtr);
15547 if (retcode != JIM_OK) {
@@ -15550,33 +15412,34 @@
15550
15551 i += argsLen;
15552 continue;
15553 }
15554
15555
15556 if (cmd->u.proc.arglist[d].defaultObjPtr == NULL || optargs-- > 0) {
15557 retcode = JimSetProcArg(interp, nameObjPtr, argv[i++]);
15558 }
15559 else {
15560
15561 retcode = Jim_SetVariable(interp, nameObjPtr, cmd->u.proc.arglist[d].defaultObjPtr);
15562 }
15563 if (retcode != JIM_OK) {
15564 goto badargset;
15565 }
15566 }
15567
15568
15569 retcode = Jim_EvalObj(interp, cmd->u.proc.bodyObjPtr);
15570
15571 badargset:
15572
15573
 
15574 interp->framePtr = interp->framePtr->parent;
15575 JimFreeCallFrame(interp, callFramePtr, JIM_FCF_REUSE);
15576
15577
15578 if (interp->framePtr->tailcallObj) {
15579 do {
15580 Jim_Obj *tailcallObj = interp->framePtr->tailcallObj;
15581
15582 interp->framePtr->tailcallObj = NULL;
@@ -15588,18 +15451,18 @@
15588 }
15589 }
15590 Jim_DecrRefCount(interp, tailcallObj);
15591 } while (interp->framePtr->tailcallObj);
15592
15593
15594 if (interp->framePtr->tailcallCmd) {
15595 JimDecrCmdRefCount(interp, interp->framePtr->tailcallCmd);
15596 interp->framePtr->tailcallCmd = NULL;
15597 }
15598 }
15599
15600
15601 if (retcode == JIM_RETURN) {
15602 if (--interp->returnLevel <= 0) {
15603 retcode = interp->returnCode;
15604 interp->returnCode = JIM_OK;
15605 interp->returnLevel = 0;
@@ -15711,20 +15574,20 @@
15711 prevScriptObj = interp->currentScriptObj;
15712 interp->currentScriptObj = scriptObjPtr;
15713
15714 retcode = Jim_EvalObj(interp, scriptObjPtr);
15715
15716
15717 if (retcode == JIM_RETURN) {
15718 if (--interp->returnLevel <= 0) {
15719 retcode = interp->returnCode;
15720 interp->returnCode = JIM_OK;
15721 interp->returnLevel = 0;
15722 }
15723 }
15724 if (retcode == JIM_ERR) {
15725
15726 interp->addStackTrace++;
15727 }
15728
15729 interp->currentScriptObj = prevScriptObj;
15730
@@ -15750,11 +15613,11 @@
15750 }
15751 if (*pc->p == '$' && !(flags & JIM_SUBST_NOVAR)) {
15752 if (JimParseVar(pc) == JIM_OK) {
15753 return;
15754 }
15755
15756 pc->tstart = pc->p;
15757 flags |= JIM_SUBST_NOVAR;
15758 }
15759 while (pc->len) {
15760 if (*pc->p == '$' && !(flags & JIM_SUBST_NOVAR)) {
@@ -15781,32 +15644,32 @@
15781 const char *scriptText = Jim_GetString(objPtr, &scriptTextLen);
15782 struct JimParserCtx parser;
15783 struct ScriptObj *script = Jim_Alloc(sizeof(*script));
15784 ParseTokenList tokenlist;
15785
15786
15787 ScriptTokenListInit(&tokenlist);
15788
15789 JimParserInit(&parser, scriptText, scriptTextLen, 1);
15790 while (1) {
15791 JimParseSubst(&parser, flags);
15792 if (parser.eof) {
15793
15794 break;
15795 }
15796 ScriptAddToken(&tokenlist, parser.tstart, parser.tend - parser.tstart + 1, parser.tt,
15797 parser.tline);
15798 }
15799
15800
15801 script->inUse = 1;
15802 script->substFlags = flags;
15803 script->fileNameObj = interp->emptyObj;
15804 Jim_IncrRefCount(script->fileNameObj);
15805 SubstObjAddTokens(interp, script, &tokenlist);
15806
15807
15808 ScriptTokenListFree(&tokenlist);
15809
15810 #ifdef DEBUG_SHOW_SUBST
15811 {
15812 int i;
@@ -15817,11 +15680,11 @@
15817 Jim_String(script->token[i].objPtr));
15818 }
15819 }
15820 #endif
15821
15822
15823 Jim_FreeIntRep(interp, objPtr);
15824 Jim_SetIntRepPtr(objPtr, script);
15825 objPtr->typePtr = &scriptObjType;
15826 return JIM_OK;
15827 }
@@ -15835,11 +15698,11 @@
15835
15836 int Jim_SubstObj(Jim_Interp *interp, Jim_Obj *substObjPtr, Jim_Obj **resObjPtrPtr, int flags)
15837 {
15838 ScriptObj *script = Jim_GetSubst(interp, substObjPtr, flags);
15839
15840 Jim_IncrRefCount(substObjPtr);
15841 script->inUse++;
15842
15843 *resObjPtrPtr = JimInterpolateTokens(interp, script->token, script->len, flags);
15844
15845 script->inUse--;
@@ -15851,22 +15714,24 @@
15851 }
15852
15853 void Jim_WrongNumArgs(Jim_Interp *interp, int argc, Jim_Obj *const *argv, const char *msg)
15854 {
15855 Jim_Obj *objPtr;
15856 Jim_Obj *listObjPtr = Jim_NewListObj(interp, argv, argc);
15857
15858 if (*msg) {
 
 
 
 
15859 Jim_ListAppendElement(interp, listObjPtr, Jim_NewStringObj(interp, msg, -1));
15860 }
15861 Jim_IncrRefCount(listObjPtr);
15862 objPtr = Jim_ListJoin(interp, listObjPtr, " ", 1);
15863 Jim_DecrRefCount(interp, listObjPtr);
15864
15865 Jim_IncrRefCount(objPtr);
15866 Jim_SetResultFormatted(interp, "wrong # args: should be \"%#s\"", objPtr);
15867 Jim_DecrRefCount(interp, objPtr);
15868 }
15869
15870 typedef void JimHashtableIteratorCallbackType(Jim_Interp *interp, Jim_Obj *listObjPtr,
15871 Jim_HashEntry *he, int type);
15872
@@ -15876,11 +15741,11 @@
15876 JimHashtableIteratorCallbackType *callback, int type)
15877 {
15878 Jim_HashEntry *he;
15879 Jim_Obj *listObjPtr = Jim_NewListObj(interp, NULL, 0);
15880
15881
15882 if (patternObjPtr && JimTrivialMatch(Jim_String(patternObjPtr))) {
15883 he = Jim_FindHashEntry(ht, Jim_String(patternObjPtr));
15884 if (he) {
15885 callback(interp, listObjPtr, he, type);
15886 }
@@ -15907,11 +15772,11 @@
15907 {
15908 Jim_Cmd *cmdPtr = Jim_GetHashEntryVal(he);
15909 Jim_Obj *objPtr;
15910
15911 if (type == JIM_CMDLIST_PROCS && !cmdPtr->isproc) {
15912
15913 return;
15914 }
15915
15916 objPtr = Jim_NewStringObj(interp, he->key, -1);
15917 Jim_IncrRefCount(objPtr);
@@ -15967,11 +15832,11 @@
15967
15968 targetCallFrame = JimGetCallFrameByInteger(interp, levelObjPtr);
15969 if (targetCallFrame == NULL) {
15970 return JIM_ERR;
15971 }
15972
15973 if (targetCallFrame == interp->topFramePtr) {
15974 Jim_SetResultFormatted(interp, "bad level \"%#s\"", levelObjPtr);
15975 return JIM_ERR;
15976 }
15977 if (info_level_cmd) {
@@ -16095,12 +15960,17 @@
16095 doubleRes = (double)res;
16096 goto trydouble;
16097 }
16098 if (op == JIM_EXPROP_SUB)
16099 res -= wideValue;
16100 else
 
 
 
 
16101 res /= wideValue;
 
16102 }
16103 Jim_SetResultInt(interp, res);
16104 return JIM_OK;
16105 trydouble:
16106 for (; i < argc; i++) {
@@ -16154,11 +16024,11 @@
16154 if (!objPtr)
16155 return JIM_ERR;
16156 Jim_SetResult(interp, objPtr);
16157 return JIM_OK;
16158 }
16159
16160 if (Jim_SetVariable(interp, argv[1], argv[2]) != JIM_OK)
16161 return JIM_ERR;
16162 Jim_SetResult(interp, argv[2]);
16163 return JIM_OK;
16164 }
@@ -16197,11 +16067,11 @@
16197 if (argc != 3) {
16198 Jim_WrongNumArgs(interp, 1, argv, "condition body");
16199 return JIM_ERR;
16200 }
16201
16202
16203 while (1) {
16204 int boolean, retval;
16205
16206 if ((retval = Jim_GetBoolFromExpr(interp, argv[1], &boolean)) != JIM_OK)
16207 return retval;
@@ -16237,11 +16107,11 @@
16237 if (argc != 5) {
16238 Jim_WrongNumArgs(interp, 1, argv, "start test next body");
16239 return JIM_ERR;
16240 }
16241
16242
16243 if ((retval = Jim_EvalObj(interp, argv[1])) != JIM_OK) {
16244 return retval;
16245 }
16246
16247 retval = Jim_GetBoolFromExpr(interp, argv[2], &boolean);
@@ -16248,78 +16118,84 @@
16248
16249
16250 #ifdef JIM_OPTIMIZATION
16251 if (retval == JIM_OK && boolean) {
16252 ScriptObj *incrScript;
16253 ExprByteCode *expr;
16254 jim_wide stop, currentVal;
16255 Jim_Obj *objPtr;
16256 int cmpOffset;
16257
16258
16259 expr = JimGetExpression(interp, argv[2]);
16260 incrScript = JimGetScript(interp, argv[3]);
16261
16262
16263 if (incrScript == NULL || incrScript->len != 3 || !expr || expr->len != 3) {
16264 goto evalstart;
16265 }
16266
16267 if (incrScript->token[1].type != JIM_TT_ESC ||
16268 expr->token[0].type != JIM_TT_VAR ||
16269 (expr->token[1].type != JIM_TT_EXPR_INT && expr->token[1].type != JIM_TT_VAR)) {
16270 goto evalstart;
16271 }
16272
16273 if (expr->token[2].type == JIM_EXPROP_LT) {
16274 cmpOffset = 0;
16275 }
16276 else if (expr->token[2].type == JIM_EXPROP_LTE) {
16277 cmpOffset = 1;
16278 }
16279 else {
16280 goto evalstart;
16281 }
16282
16283
 
 
 
 
 
 
 
 
16284 if (!Jim_CompareStringImmediate(interp, incrScript->token[1].objPtr, "incr")) {
16285 goto evalstart;
16286 }
16287
16288
16289 if (!Jim_StringEqObj(incrScript->token[2].objPtr, expr->token[0].objPtr)) {
16290 goto evalstart;
16291 }
16292
16293
16294 if (expr->token[1].type == JIM_TT_EXPR_INT) {
16295 if (Jim_GetWide(interp, expr->token[1].objPtr, &stop) == JIM_ERR) {
16296 goto evalstart;
16297 }
16298 }
16299 else {
16300 stopVarNamePtr = expr->token[1].objPtr;
16301 Jim_IncrRefCount(stopVarNamePtr);
16302
16303 stop = 0;
16304 }
16305
16306
16307 varNamePtr = expr->token[0].objPtr;
16308 Jim_IncrRefCount(varNamePtr);
16309
16310 objPtr = Jim_GetVariable(interp, varNamePtr, JIM_NONE);
16311 if (objPtr == NULL || Jim_GetWide(interp, objPtr, &currentVal) != JIM_OK) {
16312 goto testcond;
16313 }
16314
16315
16316 while (retval == JIM_OK) {
16317
16318
16319
16320
 
 
16321 if (stopVarNamePtr) {
16322 objPtr = Jim_GetVariable(interp, stopVarNamePtr, JIM_NONE);
16323 if (objPtr == NULL || Jim_GetWide(interp, objPtr, &stop) != JIM_OK) {
16324 goto testcond;
16325 }
@@ -16327,18 +16203,18 @@
16327
16328 if (currentVal >= stop + cmpOffset) {
16329 break;
16330 }
16331
16332
16333 retval = Jim_EvalObj(interp, argv[4]);
16334 if (retval == JIM_OK || retval == JIM_CONTINUE) {
16335 retval = JIM_OK;
16336
16337 objPtr = Jim_GetVariable(interp, varNamePtr, JIM_ERRMSG);
16338
16339
16340 if (objPtr == NULL) {
16341 retval = JIM_ERR;
16342 goto out;
16343 }
16344 if (!Jim_IsShared(objPtr) && objPtr->typePtr == &intObjType) {
@@ -16358,25 +16234,25 @@
16358 }
16359 evalstart:
16360 #endif
16361
16362 while (boolean && (retval == JIM_OK || retval == JIM_CONTINUE)) {
16363
16364 retval = Jim_EvalObj(interp, argv[4]);
16365
16366 if (retval == JIM_OK || retval == JIM_CONTINUE) {
16367
16368 evalnext:
16369 retval = Jim_EvalObj(interp, argv[3]);
16370 if (retval == JIM_OK || retval == JIM_CONTINUE) {
16371
16372 testcond:
16373 retval = Jim_GetBoolFromExpr(interp, argv[2], &boolean);
16374 }
16375 }
16376 }
16377 out:
16378 if (stopVarNamePtr) {
16379 Jim_DecrRefCount(interp, stopVarNamePtr);
16380 }
16381 if (varNamePtr) {
16382 Jim_DecrRefCount(interp, varNamePtr);
@@ -16418,11 +16294,11 @@
16418 if (retval == JIM_OK || retval == JIM_CONTINUE) {
16419 Jim_Obj *objPtr = Jim_GetVariable(interp, argv[1], JIM_ERRMSG);
16420
16421 retval = JIM_OK;
16422
16423
16424 i += incr;
16425
16426 if (objPtr && !Jim_IsShared(objPtr) && objPtr->typePtr == &intObjType) {
16427 if (argv[1]->typePtr != &variableObjType) {
16428 if (Jim_SetVariable(interp, argv[1], objPtr) != JIM_OK) {
@@ -16483,21 +16359,21 @@
16483
16484 static int JimForeachMapHelper(Jim_Interp *interp, int argc, Jim_Obj *const *argv, int doMap)
16485 {
16486 int result = JIM_OK;
16487 int i, numargs;
16488 Jim_ListIter twoiters[2];
16489 Jim_ListIter *iters;
16490 Jim_Obj *script;
16491 Jim_Obj *resultObj;
16492
16493 if (argc < 4 || argc % 2 != 0) {
16494 Jim_WrongNumArgs(interp, 1, argv, "varList list ?varList list ...? script");
16495 return JIM_ERR;
16496 }
16497 script = argv[argc - 1];
16498 numargs = (argc - 1 - 1);
16499
16500 if (numargs == 2) {
16501 iters = twoiters;
16502 }
16503 else {
@@ -16509,11 +16385,11 @@
16509 result = JIM_ERR;
16510 }
16511 }
16512 if (result != JIM_OK) {
16513 Jim_SetResultString(interp, "foreach varlist is empty", -1);
16514 return result;
16515 }
16516
16517 if (doMap) {
16518 resultObj = Jim_NewListObj(interp, NULL, 0);
16519 }
@@ -16521,34 +16397,34 @@
16521 resultObj = interp->emptyObj;
16522 }
16523 Jim_IncrRefCount(resultObj);
16524
16525 while (1) {
16526
16527 for (i = 0; i < numargs; i += 2) {
16528 if (!JimListIterDone(interp, &iters[i + 1])) {
16529 break;
16530 }
16531 }
16532 if (i == numargs) {
16533
16534 break;
16535 }
16536
16537
16538 for (i = 0; i < numargs; i += 2) {
16539 Jim_Obj *varName;
16540
16541
16542 JimListIterInit(&iters[i], argv[i + 1]);
16543 while ((varName = JimListIterNext(interp, &iters[i])) != NULL) {
16544 Jim_Obj *valObj = JimListIterNext(interp, &iters[i + 1]);
16545 if (!valObj) {
16546
16547 valObj = interp->emptyObj;
16548 }
16549
16550 Jim_IncrRefCount(valObj);
16551 result = Jim_SetVariable(interp, varName, valObj);
16552 Jim_DecrRefCount(interp, valObj);
16553 if (result != JIM_OK) {
16554 goto err;
@@ -16572,10 +16448,11 @@
16572 out:
16573 result = JIM_OK;
16574 Jim_SetResult(interp, resultObj);
16575 err:
16576 Jim_DecrRefCount(interp, resultObj);
 
16577 if (numargs > 2) {
16578 Jim_Free(iters);
16579 }
16580 return result;
16581 }
@@ -16630,41 +16507,41 @@
16630 {
16631 int boolean, retval, current = 1, falsebody = 0;
16632
16633 if (argc >= 3) {
16634 while (1) {
16635
16636 if (current >= argc)
16637 goto err;
16638 if ((retval = Jim_GetBoolFromExpr(interp, argv[current++], &boolean))
16639 != JIM_OK)
16640 return retval;
16641
16642 if (current >= argc)
16643 goto err;
16644 if (Jim_CompareStringImmediate(interp, argv[current], "then"))
16645 current++;
16646
16647 if (current >= argc)
16648 goto err;
16649 if (boolean)
16650 return Jim_EvalObj(interp, argv[current]);
16651
16652 if (++current >= argc) {
16653 Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
16654 return JIM_OK;
16655 }
16656 falsebody = current++;
16657 if (Jim_CompareStringImmediate(interp, argv[falsebody], "else")) {
16658
16659 if (current != argc - 1)
16660 goto err;
16661 return Jim_EvalObj(interp, argv[current]);
16662 }
16663 else if (Jim_CompareStringImmediate(interp, argv[falsebody], "elseif"))
16664 continue;
16665
16666 else if (falsebody != argc - 1)
16667 goto err;
16668 return Jim_EvalObj(interp, argv[falsebody]);
16669 }
16670 return JIM_OK;
@@ -16698,19 +16575,17 @@
16698 }
16699
16700 return eq;
16701 }
16702
16703 enum
16704 { SWITCH_EXACT, SWITCH_GLOB, SWITCH_RE, SWITCH_CMD };
16705
16706
16707 static int Jim_SwitchCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
16708 {
 
16709 int matchOpt = SWITCH_EXACT, opt = 1, patCount, i;
16710 Jim_Obj *command = 0, *const *caseList = 0, *strObj;
16711 Jim_Obj *script = 0;
16712
16713 if (argc < 3) {
16714 wrongnumargs:
16715 Jim_WrongNumArgs(interp, 1, argv, "?options? string "
16716 "pattern body ... ?default body? or " "{pattern body ?pattern body ...?}");
@@ -16747,68 +16622,62 @@
16747 goto wrongnumargs;
16748 }
16749 strObj = argv[opt++];
16750 patCount = argc - opt;
16751 if (patCount == 1) {
16752 Jim_Obj **vector;
16753
16754 JimListGetElements(interp, argv[opt], &patCount, &vector);
16755 caseList = vector;
16756 }
16757 else
16758 caseList = &argv[opt];
16759 if (patCount == 0 || patCount % 2 != 0)
16760 goto wrongnumargs;
16761 for (i = 0; script == 0 && i < patCount; i += 2) {
16762 Jim_Obj *patObj = caseList[i];
16763
16764 if (!Jim_CompareStringImmediate(interp, patObj, "default")
16765 || i < (patCount - 2)) {
16766 switch (matchOpt) {
16767 case SWITCH_EXACT:
16768 if (Jim_StringEqObj(strObj, patObj))
16769 script = caseList[i + 1];
16770 break;
16771 case SWITCH_GLOB:
16772 if (Jim_StringMatchObj(interp, patObj, strObj, 0))
16773 script = caseList[i + 1];
16774 break;
16775 case SWITCH_RE:
16776 command = Jim_NewStringObj(interp, "regexp", -1);
16777
16778 case SWITCH_CMD:{
16779 int rc = Jim_CommandMatchObj(interp, command, patObj, strObj, 0);
16780
16781 if (argc - opt == 1) {
16782 Jim_Obj **vector;
16783
16784 JimListGetElements(interp, argv[opt], &patCount, &vector);
16785 caseList = vector;
16786 }
16787
16788 if (rc < 0) {
16789 return -rc;
16790 }
16791 if (rc)
16792 script = caseList[i + 1];
16793 break;
16794 }
16795 }
16796 }
16797 else {
16798 script = caseList[i + 1];
16799 }
16800 }
16801 for (; i < patCount && Jim_CompareStringImmediate(interp, script, "-"); i += 2)
16802 script = caseList[i + 1];
16803 if (script && Jim_CompareStringImmediate(interp, script, "-")) {
16804 Jim_SetResultFormatted(interp, "no body specified for pattern \"%#s\"", caseList[i - 2]);
16805 return JIM_ERR;
16806 }
16807 Jim_SetEmptyResult(interp);
16808 if (script) {
16809 return Jim_EvalObj(interp, script);
16810 }
16811 return JIM_OK;
16812 }
16813
16814
@@ -16920,11 +16789,11 @@
16920 case OPT_COMMAND:
16921 if (i >= argc - 2) {
16922 goto wrongargs;
16923 }
16924 commandObj = argv[++i];
16925
16926 case OPT_EXACT:
16927 case OPT_GLOB:
16928 case OPT_REGEXP:
16929 opt_match = option;
16930 break;
@@ -16968,17 +16837,17 @@
16968 goto done;
16969 }
16970 break;
16971 }
16972
16973
16974 if (!eq && opt_bool && opt_not && !opt_all) {
16975 continue;
16976 }
16977
16978 if ((!opt_bool && eq == !opt_not) || (opt_bool && (eq || opt_all))) {
16979
16980 Jim_Obj *resultObj;
16981
16982 if (opt_bool) {
16983 resultObj = Jim_NewIntObj(interp, eq ^ opt_not);
16984 }
@@ -17001,11 +16870,11 @@
17001
17002 if (opt_all) {
17003 Jim_SetResult(interp, listObjPtr);
17004 }
17005 else {
17006
17007 if (opt_bool) {
17008 Jim_SetResultBool(interp, opt_not);
17009 }
17010 else if (!opt_inline) {
17011 Jim_SetResultInt(interp, -1);
@@ -17030,11 +16899,11 @@
17030 Jim_WrongNumArgs(interp, 1, argv, "varName ?value value ...?");
17031 return JIM_ERR;
17032 }
17033 listObjPtr = Jim_GetVariable(interp, argv[1], JIM_UNSHARED);
17034 if (!listObjPtr) {
17035
17036 listObjPtr = Jim_NewListObj(interp, NULL, 0);
17037 new_obj = 1;
17038 }
17039 else if (Jim_IsShared(listObjPtr)) {
17040 listObjPtr = Jim_DuplicateObj(interp, listObjPtr);
@@ -17103,31 +16972,21 @@
17103 first = JimRelToAbsIndex(len, first);
17104 last = JimRelToAbsIndex(len, last);
17105 JimRelToAbsRange(len, &first, &last, &rangeLen);
17106
17107
17108
17109 if (first < len) {
17110
17111 }
17112 else if (len == 0) {
17113
17114 first = 0;
17115 }
17116 else {
17117 Jim_SetResultString(interp, "list doesn't contain element ", -1);
17118 Jim_AppendObj(interp, Jim_GetResult(interp), argv[2]);
17119 return JIM_ERR;
17120 }
17121
17122
17123 newListObj = Jim_NewListObj(interp, listObj->internalRep.listValue.ele, first);
17124
17125
17126 ListInsertElements(newListObj, -1, argc - 4, argv + 4);
17127
17128
17129 ListInsertElements(newListObj, -1, len - first - rangeLen, listObj->internalRep.listValue.ele + first + rangeLen);
17130
17131 Jim_SetResult(interp, newListObj);
17132 return JIM_OK;
17133 }
@@ -17138,11 +16997,11 @@
17138 if (argc < 3) {
17139 Jim_WrongNumArgs(interp, 1, argv, "listVar ?index...? newVal");
17140 return JIM_ERR;
17141 }
17142 else if (argc == 3) {
17143
17144 if (Jim_SetVariable(interp, argv[1], argv[2]) != JIM_OK)
17145 return JIM_ERR;
17146 Jim_SetResult(interp, argv[2]);
17147 return JIM_OK;
17148 }
@@ -17158,10 +17017,11 @@
17158 enum
17159 { OPT_ASCII, OPT_NOCASE, OPT_INCREASING, OPT_DECREASING, OPT_COMMAND, OPT_INTEGER, OPT_REAL, OPT_INDEX, OPT_UNIQUE };
17160 Jim_Obj *resObj;
17161 int i;
17162 int retCode;
 
17163
17164 struct lsort_info info;
17165
17166 if (argc < 2) {
17167 Jim_WrongNumArgs(interp, 1, argv, "?options? list");
@@ -17223,16 +17083,18 @@
17223 info.indexed = 1;
17224 i++;
17225 break;
17226 }
17227 }
17228 resObj = Jim_DuplicateObj(interp, argv[argc - 1]);
 
 
17229 retCode = ListSortElements(interp, resObj, &info);
17230 if (retCode == JIM_OK) {
17231 Jim_SetResult(interp, resObj);
17232 }
17233 else {
17234 Jim_FreeNewObj(interp, resObj);
17235 }
17236 return retCode;
17237 }
17238
@@ -17253,11 +17115,11 @@
17253 }
17254 else {
17255 int new_obj = 0;
17256 stringObjPtr = Jim_GetVariable(interp, argv[1], JIM_UNSHARED);
17257 if (!stringObjPtr) {
17258
17259 stringObjPtr = Jim_NewEmptyStringObj(interp);
17260 new_obj = 1;
17261 }
17262 else if (Jim_IsShared(stringObjPtr)) {
17263 new_obj = 1;
@@ -17274,10 +17136,11 @@
17274 }
17275 }
17276 Jim_SetResult(interp, stringObjPtr);
17277 return JIM_OK;
17278 }
 
17279
17280
17281 static int Jim_DebugCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
17282 {
17283 #if !defined(JIM_DEBUG_COMMAND)
@@ -17302,11 +17165,11 @@
17302 else {
17303 rc = Jim_EvalObj(interp, Jim_ConcatObj(interp, argc - 1, argv + 1));
17304 }
17305
17306 if (rc == JIM_ERR) {
17307
17308 interp->addStackTrace++;
17309 }
17310 return rc;
17311 }
17312
@@ -17316,14 +17179,14 @@
17316 if (argc >= 2) {
17317 int retcode;
17318 Jim_CallFrame *savedCallFrame, *targetCallFrame;
17319 const char *str;
17320
17321
17322 savedCallFrame = interp->framePtr;
17323
17324
17325 str = Jim_String(argv[1]);
17326 if ((str[0] >= '0' && str[0] <= '9') || str[0] == '#') {
17327 targetCallFrame = Jim_GetCallFrameByLevel(interp, argv[1]);
17328 argc--;
17329 argv++;
@@ -17336,11 +17199,11 @@
17336 }
17337 if (argc < 2) {
17338 Jim_WrongNumArgs(interp, 1, argv - 1, "?level? command ?arg ...?");
17339 return JIM_ERR;
17340 }
17341
17342 interp->framePtr = targetCallFrame;
17343 if (argc == 2) {
17344 retcode = Jim_EvalObj(interp, argv[1]);
17345 }
17346 else {
@@ -17356,32 +17219,29 @@
17356 }
17357
17358
17359 static int Jim_ExprCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
17360 {
17361 Jim_Obj *exprResultPtr;
17362 int retcode;
17363
17364 if (argc == 2) {
17365 retcode = Jim_EvalExpression(interp, argv[1], &exprResultPtr);
17366 }
17367 else if (argc > 2) {
17368 Jim_Obj *objPtr;
17369
17370 objPtr = Jim_ConcatObj(interp, argc - 1, argv + 1);
17371 Jim_IncrRefCount(objPtr);
17372 retcode = Jim_EvalExpression(interp, objPtr, &exprResultPtr);
17373 Jim_DecrRefCount(interp, objPtr);
17374 }
17375 else {
17376 Jim_WrongNumArgs(interp, 1, argv, "expression ?...?");
17377 return JIM_ERR;
17378 }
17379 if (retcode != JIM_OK)
17380 return retcode;
17381 Jim_SetResult(interp, exprResultPtr);
17382 Jim_DecrRefCount(interp, exprResultPtr);
17383 return JIM_OK;
17384 }
17385
17386
17387 static int Jim_BreakCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
@@ -17438,15 +17298,15 @@
17438 if (i != argc - 1 && i != argc) {
17439 Jim_WrongNumArgs(interp, 1, argv,
17440 "?-code code? ?-errorinfo stacktrace? ?-level level? ?result?");
17441 }
17442
17443
17444 if (stackTraceObj && returnCode == JIM_ERR) {
17445 JimSetStackTrace(interp, stackTraceObj);
17446 }
17447
17448 if (errorCodeObj && returnCode == JIM_ERR) {
17449 Jim_SetGlobalVariableStr(interp, "errorCode", errorCodeObj);
17450 }
17451 interp->returnCode = returnCode;
17452 interp->returnLevel = level;
@@ -17463,31 +17323,31 @@
17463 if (interp->framePtr->level == 0) {
17464 Jim_SetResultString(interp, "tailcall can only be called from a proc or lambda", -1);
17465 return JIM_ERR;
17466 }
17467 else if (argc >= 2) {
17468
17469 Jim_CallFrame *cf = interp->framePtr->parent;
17470
17471 Jim_Cmd *cmdPtr = Jim_GetCommand(interp, argv[1], JIM_ERRMSG);
17472 if (cmdPtr == NULL) {
17473 return JIM_ERR;
17474 }
17475
17476 JimPanic((cf->tailcallCmd != NULL, "Already have a tailcallCmd"));
17477
17478
17479 JimIncrCmdRefCount(cmdPtr);
17480 cf->tailcallCmd = cmdPtr;
17481
17482
17483 JimPanic((cf->tailcallObj != NULL, "Already have a tailcallobj"));
17484
17485 cf->tailcallObj = Jim_NewListObj(interp, argv + 1, argc - 1);
17486 Jim_IncrRefCount(cf->tailcallObj);
17487
17488
17489 return JIM_EVAL;
17490 }
17491 return JIM_OK;
17492 }
17493
@@ -17494,11 +17354,11 @@
17494 static int JimAliasCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
17495 {
17496 Jim_Obj *cmdList;
17497 Jim_Obj *prefixListObj = Jim_CmdPrivData(interp);
17498
17499
17500 cmdList = Jim_DuplicateObj(interp, prefixListObj);
17501 Jim_ListInsertElements(interp, cmdList, Jim_ListLength(interp, cmdList), argc - 1, argv + 1);
17502
17503 return JimEvalObjList(interp, cmdList);
17504 }
@@ -17552,22 +17412,22 @@
17552 else {
17553 cmd = JimCreateProcedureCmd(interp, argv[2], argv[3], argv[4], NULL);
17554 }
17555
17556 if (cmd) {
17557
17558 Jim_Obj *qualifiedCmdNameObj;
17559 const char *cmdname = JimQualifyName(interp, Jim_String(argv[1]), &qualifiedCmdNameObj);
17560
17561 JimCreateCommand(interp, cmdname, cmd);
17562
17563
17564 JimUpdateProcNamespace(interp, cmd, cmdname);
17565
17566 JimFreeQualifiedName(interp, qualifiedCmdNameObj);
17567
17568
17569 Jim_SetResult(interp, argv[1]);
17570 return JIM_OK;
17571 }
17572 return JIM_ERR;
17573 }
@@ -17580,17 +17440,17 @@
17580 if (argc < 2) {
17581 Jim_WrongNumArgs(interp, 1, argv, "cmd ?args ...?");
17582 return JIM_ERR;
17583 }
17584
17585
17586 interp->local++;
17587 retcode = Jim_EvalObjVector(interp, argc - 1, argv + 1);
17588 interp->local--;
17589
17590
17591
17592 if (retcode == 0) {
17593 Jim_Obj *cmdNameObj = Jim_GetResult(interp);
17594
17595 if (Jim_GetCommand(interp, cmdNameObj, JIM_ERRMSG) == NULL) {
17596 return JIM_ERR;
@@ -17619,18 +17479,18 @@
17619 Jim_Cmd *cmdPtr = Jim_GetCommand(interp, argv[1], JIM_ERRMSG);
17620 if (cmdPtr == NULL || !cmdPtr->isproc || !cmdPtr->prevCmd) {
17621 Jim_SetResultFormatted(interp, "no previous command: \"%#s\"", argv[1]);
17622 return JIM_ERR;
17623 }
17624
17625 cmdPtr->u.proc.upcall++;
17626 JimIncrCmdRefCount(cmdPtr);
17627
17628
17629 retcode = Jim_EvalObjVector(interp, argc - 1, argv + 1);
17630
17631
17632 cmdPtr->u.proc.upcall--;
17633 JimDecrCmdRefCount(interp, cmdPtr);
17634
17635 return retcode;
17636 }
@@ -17657,11 +17517,11 @@
17657 return JIM_ERR;
17658 }
17659
17660 if (len == 3) {
17661 #ifdef jim_ext_namespace
17662
17663 nsObj = JimQualifyNameObj(interp, Jim_ListGetIndex(interp, argv[1], 2));
17664 #else
17665 Jim_SetResultString(interp, "namespaces not enabled", -1);
17666 return JIM_ERR;
17667 #endif
@@ -17670,11 +17530,11 @@
17670 bodyObjPtr = Jim_ListGetIndex(interp, argv[1], 1);
17671
17672 cmd = JimCreateProcedureCmd(interp, argListObjPtr, NULL, bodyObjPtr, nsObj);
17673
17674 if (cmd) {
17675
17676 nargv = Jim_Alloc((argc - 2 + 1) * sizeof(*nargv));
17677 nargv[0] = Jim_NewStringObj(interp, "apply lambdaExpr", -1);
17678 Jim_IncrRefCount(nargv[0]);
17679 memcpy(&nargv[1], argv + 2, (argc - 2) * sizeof(*nargv));
17680 ret = JimCallProcedure(interp, cmd, argc - 2 + 1, nargv);
@@ -17700,11 +17560,11 @@
17700 static int Jim_UpvarCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
17701 {
17702 int i;
17703 Jim_CallFrame *targetCallFrame;
17704
17705
17706 if (argc > 3 && (argc % 2 == 0)) {
17707 targetCallFrame = Jim_GetCallFrameByLevel(interp, argv[1]);
17708 argc--;
17709 argv++;
17710 }
@@ -17713,17 +17573,17 @@
17713 }
17714 if (targetCallFrame == NULL) {
17715 return JIM_ERR;
17716 }
17717
17718
17719 if (argc < 3) {
17720 Jim_WrongNumArgs(interp, 1, argv, "?level? otherVar localVar ?otherVar localVar ...?");
17721 return JIM_ERR;
17722 }
17723
17724
17725 for (i = 1; i < argc; i += 2) {
17726 if (Jim_SetVariableLink(interp, argv[i + 1], argv[i], targetCallFrame) != JIM_OK)
17727 return JIM_ERR;
17728 }
17729 return JIM_OK;
@@ -17736,15 +17596,15 @@
17736
17737 if (argc < 2) {
17738 Jim_WrongNumArgs(interp, 1, argv, "varName ?varName ...?");
17739 return JIM_ERR;
17740 }
17741
17742 if (interp->framePtr->level == 0)
17743 return JIM_OK;
17744 for (i = 1; i < argc; i++) {
17745
17746 const char *name = Jim_String(argv[i]);
17747 if (name[0] != ':' || name[1] != ':') {
17748 if (Jim_SetVariableLink(interp, argv[i], argv[i], interp->topFramePtr) != JIM_OK)
17749 return JIM_ERR;
17750 }
@@ -17767,21 +17627,21 @@
17767 }
17768
17769 str = Jim_String(objPtr);
17770 strLen = Jim_Utf8Length(interp, objPtr);
17771
17772
17773 resultObjPtr = Jim_NewStringObj(interp, "", 0);
17774 while (strLen) {
17775 for (i = 0; i < numMaps; i += 2) {
17776 Jim_Obj *objPtr;
17777 const char *k;
17778 int kl;
17779
17780 objPtr = Jim_ListGetIndex(interp, mapListObjPtr, i);
17781 k = Jim_String(objPtr);
17782 kl = Jim_Utf8Length(interp, objPtr);
17783
17784 if (strLen >= kl && kl) {
17785 int rc;
17786 rc = JimStringCompareLen(str, k, kl, nocase);
17787 if (rc == 0) {
@@ -17794,11 +17654,11 @@
17794 strLen -= kl;
17795 break;
17796 }
17797 }
17798 }
17799 if (i == numMaps) {
17800 int c;
17801 if (noMatchStart == NULL)
17802 noMatchStart = str;
17803 str += utf8_tounicode(str, &c);
17804 strLen--;
@@ -17838,11 +17698,11 @@
17838 Jim_WrongNumArgs(interp, 1, argv, "option ?arguments ...?");
17839 return JIM_ERR;
17840 }
17841 if (Jim_GetEnum(interp, argv[1], options, &option, NULL,
17842 JIM_ERRMSG | JIM_ENUM_ABBREV) != JIM_OK)
17843 return JIM_ERR;
17844
17845 switch (option) {
17846 case OPT_LENGTH:
17847 case OPT_BYTELENGTH:
17848 if (argc != 3) {
@@ -17859,11 +17719,11 @@
17859 return JIM_OK;
17860
17861 case OPT_CAT:{
17862 Jim_Obj *objPtr;
17863 if (argc == 3) {
17864
17865 objPtr = argv[2];
17866 }
17867 else {
17868 int i;
17869
@@ -17878,11 +17738,11 @@
17878 }
17879
17880 case OPT_COMPARE:
17881 case OPT_EQUAL:
17882 {
17883
17884 long opt_length = -1;
17885 int n = argc - 4;
17886 int i = 2;
17887 while (n > 0) {
17888 int subopt;
@@ -17891,16 +17751,16 @@
17891 badcompareargs:
17892 Jim_WrongNumArgs(interp, 2, argv, "?-nocase? ?-length int? string1 string2");
17893 return JIM_ERR;
17894 }
17895 if (subopt == 0) {
17896
17897 opt_case = 0;
17898 n--;
17899 }
17900 else {
17901
17902 if (n < 2) {
17903 goto badcompareargs;
17904 }
17905 if (Jim_GetLong(interp, argv[i++], &opt_length) != JIM_OK) {
17906 return JIM_ERR;
@@ -17911,11 +17771,11 @@
17911 if (n) {
17912 goto badcompareargs;
17913 }
17914 argv += argc - 2;
17915 if (opt_length < 0 && option != OPT_COMPARE && opt_case) {
17916
17917 Jim_SetResultBool(interp, Jim_StringEqObj(argv[0], argv[1]));
17918 }
17919 else {
17920 if (opt_length >= 0) {
17921 n = JimStringCompareLen(Jim_String(argv[0]), Jim_String(argv[1]), opt_length, !opt_case);
@@ -18025,11 +17885,10 @@
18025 }
18026
18027 case OPT_REVERSE:{
18028 char *buf, *p;
18029 const char *str;
18030 int len;
18031 int i;
18032
18033 if (argc != 3) {
18034 Jim_WrongNumArgs(interp, 2, argv, "string");
18035 return JIM_ERR;
@@ -18069,11 +17928,11 @@
18069 }
18070 if (idx < 0 || idx >= len || str == NULL) {
18071 Jim_SetResultString(interp, "", 0);
18072 }
18073 else if (len == Jim_Length(argv[2])) {
18074
18075 Jim_SetResultString(interp, str + idx, 1);
18076 }
18077 else {
18078 int c;
18079 int i = utf8_index(str, idx);
@@ -18223,11 +18082,11 @@
18223 {
18224 int exitCode = 0;
18225 int i;
18226 int sig = 0;
18227
18228
18229 jim_wide ignore_mask = (1 << JIM_EXIT) | (1 << JIM_EVAL) | (1 << JIM_SIGNAL);
18230 static const int max_ignore_code = sizeof(ignore_mask) * 8;
18231
18232 Jim_SetGlobalVariableStr(interp, "errorCode", Jim_NewStringObj(interp, "NONE", -1));
18233
@@ -18234,11 +18093,11 @@
18234 for (i = 1; i < argc - 1; i++) {
18235 const char *arg = Jim_String(argv[i]);
18236 jim_wide option;
18237 int ignore;
18238
18239
18240 if (strcmp(arg, "--") == 0) {
18241 i++;
18242 break;
18243 }
18244 if (*arg != '-') {
@@ -18285,28 +18144,28 @@
18285 sig++;
18286 }
18287
18288 interp->signal_level += sig;
18289 if (Jim_CheckSignal(interp)) {
18290
18291 exitCode = JIM_SIGNAL;
18292 }
18293 else {
18294 exitCode = Jim_EvalObj(interp, argv[0]);
18295
18296 interp->errorFlag = 0;
18297 }
18298 interp->signal_level -= sig;
18299
18300
18301 if (exitCode >= 0 && exitCode < max_ignore_code && (((unsigned jim_wide)1 << exitCode) & ignore_mask)) {
18302
18303 return exitCode;
18304 }
18305
18306 if (sig && exitCode == JIM_SIGNAL) {
18307
18308 if (interp->signal_set_result) {
18309 interp->signal_set_result(interp, interp->sigmask);
18310 }
18311 else {
18312 Jim_SetResultInt(interp, interp->sigmask);
@@ -18345,125 +18204,10 @@
18345 }
18346 Jim_SetResultInt(interp, exitCode);
18347 return JIM_OK;
18348 }
18349
18350 #ifdef JIM_REFERENCES
18351
18352
18353 static int Jim_RefCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
18354 {
18355 if (argc != 3 && argc != 4) {
18356 Jim_WrongNumArgs(interp, 1, argv, "string tag ?finalizer?");
18357 return JIM_ERR;
18358 }
18359 if (argc == 3) {
18360 Jim_SetResult(interp, Jim_NewReference(interp, argv[1], argv[2], NULL));
18361 }
18362 else {
18363 Jim_SetResult(interp, Jim_NewReference(interp, argv[1], argv[2], argv[3]));
18364 }
18365 return JIM_OK;
18366 }
18367
18368
18369 static int Jim_GetrefCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
18370 {
18371 Jim_Reference *refPtr;
18372
18373 if (argc != 2) {
18374 Jim_WrongNumArgs(interp, 1, argv, "reference");
18375 return JIM_ERR;
18376 }
18377 if ((refPtr = Jim_GetReference(interp, argv[1])) == NULL)
18378 return JIM_ERR;
18379 Jim_SetResult(interp, refPtr->objPtr);
18380 return JIM_OK;
18381 }
18382
18383
18384 static int Jim_SetrefCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
18385 {
18386 Jim_Reference *refPtr;
18387
18388 if (argc != 3) {
18389 Jim_WrongNumArgs(interp, 1, argv, "reference newValue");
18390 return JIM_ERR;
18391 }
18392 if ((refPtr = Jim_GetReference(interp, argv[1])) == NULL)
18393 return JIM_ERR;
18394 Jim_IncrRefCount(argv[2]);
18395 Jim_DecrRefCount(interp, refPtr->objPtr);
18396 refPtr->objPtr = argv[2];
18397 Jim_SetResult(interp, argv[2]);
18398 return JIM_OK;
18399 }
18400
18401
18402 static int Jim_CollectCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
18403 {
18404 if (argc != 1) {
18405 Jim_WrongNumArgs(interp, 1, argv, "");
18406 return JIM_ERR;
18407 }
18408 Jim_SetResultInt(interp, Jim_Collect(interp));
18409
18410
18411 while (interp->freeList) {
18412 Jim_Obj *nextObjPtr = interp->freeList->nextObjPtr;
18413 Jim_Free(interp->freeList);
18414 interp->freeList = nextObjPtr;
18415 }
18416
18417 return JIM_OK;
18418 }
18419
18420
18421 static int Jim_FinalizeCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
18422 {
18423 if (argc != 2 && argc != 3) {
18424 Jim_WrongNumArgs(interp, 1, argv, "reference ?finalizerProc?");
18425 return JIM_ERR;
18426 }
18427 if (argc == 2) {
18428 Jim_Obj *cmdNamePtr;
18429
18430 if (Jim_GetFinalizer(interp, argv[1], &cmdNamePtr) != JIM_OK)
18431 return JIM_ERR;
18432 if (cmdNamePtr != NULL)
18433 Jim_SetResult(interp, cmdNamePtr);
18434 }
18435 else {
18436 if (Jim_SetFinalizer(interp, argv[1], argv[2]) != JIM_OK)
18437 return JIM_ERR;
18438 Jim_SetResult(interp, argv[2]);
18439 }
18440 return JIM_OK;
18441 }
18442
18443
18444 static int JimInfoReferences(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
18445 {
18446 Jim_Obj *listObjPtr;
18447 Jim_HashTableIterator htiter;
18448 Jim_HashEntry *he;
18449
18450 listObjPtr = Jim_NewListObj(interp, NULL, 0);
18451
18452 JimInitHashTableIterator(&interp->references, &htiter);
18453 while ((he = Jim_NextHashEntry(&htiter)) != NULL) {
18454 char buf[JIM_REFERENCE_SPACE + 1];
18455 Jim_Reference *refPtr = Jim_GetHashEntryVal(he);
18456 const unsigned long *refId = he->key;
18457
18458 JimFormatReference(buf, refPtr, *refId);
18459 Jim_ListAppendElement(interp, listObjPtr, Jim_NewStringObj(interp, buf, -1));
18460 }
18461 Jim_SetResult(interp, listObjPtr);
18462 return JIM_OK;
18463 }
18464 #endif
18465
18466
18467 static int Jim_RenameCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
18468 {
18469 if (argc != 3) {
@@ -18476,56 +18220,43 @@
18476 }
18477
18478 return Jim_RenameCommand(interp, Jim_String(argv[1]), Jim_String(argv[2]));
18479 }
18480
18481 #define JIM_DICTMATCH_VALUES 0x0001
18482
18483 typedef void JimDictMatchCallbackType(Jim_Interp *interp, Jim_Obj *listObjPtr, Jim_HashEntry *he, int type);
18484
18485 static void JimDictMatchKeys(Jim_Interp *interp, Jim_Obj *listObjPtr, Jim_HashEntry *he, int type)
18486 {
18487 Jim_ListAppendElement(interp, listObjPtr, (Jim_Obj *)he->key);
18488 if (type & JIM_DICTMATCH_VALUES) {
18489 Jim_ListAppendElement(interp, listObjPtr, Jim_GetHashEntryVal(he));
18490 }
18491 }
18492
18493 static Jim_Obj *JimDictPatternMatch(Jim_Interp *interp, Jim_HashTable *ht, Jim_Obj *patternObjPtr,
18494 JimDictMatchCallbackType *callback, int type)
18495 {
18496 Jim_HashEntry *he;
18497 Jim_Obj *listObjPtr = Jim_NewListObj(interp, NULL, 0);
18498
18499
18500 Jim_HashTableIterator htiter;
18501 JimInitHashTableIterator(ht, &htiter);
18502 while ((he = Jim_NextHashEntry(&htiter)) != NULL) {
18503 if (patternObjPtr == NULL || JimGlobMatch(Jim_String(patternObjPtr), Jim_String((Jim_Obj *)he->key), 0)) {
18504 callback(interp, listObjPtr, he, type);
18505 }
18506 }
18507
18508 return listObjPtr;
18509 }
18510
18511
18512 int Jim_DictKeys(Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj *patternObjPtr)
18513 {
18514 if (SetDictFromAny(interp, objPtr) != JIM_OK) {
18515 return JIM_ERR;
18516 }
18517 Jim_SetResult(interp, JimDictPatternMatch(interp, objPtr->internalRep.ptr, patternObjPtr, JimDictMatchKeys, 0));
18518 return JIM_OK;
18519 }
18520
18521 int Jim_DictValues(Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj *patternObjPtr)
18522 {
18523 if (SetDictFromAny(interp, objPtr) != JIM_OK) {
18524 return JIM_ERR;
18525 }
18526 Jim_SetResult(interp, JimDictPatternMatch(interp, objPtr->internalRep.ptr, patternObjPtr, JimDictMatchKeys, JIM_DICTMATCH_VALUES));
18527 return JIM_OK;
18528 }
18529
18530 int Jim_DictSize(Jim_Interp *interp, Jim_Obj *objPtr)
18531 {
@@ -18532,38 +18263,85 @@
18532 if (SetDictFromAny(interp, objPtr) != JIM_OK) {
18533 return -1;
18534 }
18535 return ((Jim_HashTable *)objPtr->internalRep.ptr)->used;
18536 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
18537
18538 int Jim_DictInfo(Jim_Interp *interp, Jim_Obj *objPtr)
18539 {
18540 Jim_HashTable *ht;
18541 unsigned int i;
 
 
 
 
 
18542
18543 if (SetDictFromAny(interp, objPtr) != JIM_OK) {
18544 return JIM_ERR;
18545 }
18546
18547 ht = (Jim_HashTable *)objPtr->internalRep.ptr;
18548
18549
18550 printf("%d entries in table, %d buckets\n", ht->used, ht->size);
 
18551
18552 for (i = 0; i < ht->size; i++) {
18553 Jim_HashEntry *he = ht->table[i];
18554
18555 if (he) {
18556 printf("%d: ", i);
18557
18558 while (he) {
18559 printf(" %s", Jim_String(he->key));
18560 he = he->next;
18561 }
18562 printf("\n");
 
 
 
 
 
18563 }
18564 }
 
 
 
 
 
 
 
 
 
18565 return JIM_OK;
18566 }
18567
18568 static int Jim_EvalEnsemble(Jim_Interp *interp, const char *basecmd, const char *subcmd, int argc, Jim_Obj *const *argv)
18569 {
@@ -18573,14 +18351,67 @@
18573 Jim_AppendString(interp, prefixObj, subcmd, -1);
18574
18575 return Jim_EvalObjPrefix(interp, prefixObj, argc, argv);
18576 }
18577
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
18578
18579 static int Jim_DictCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
18580 {
18581 Jim_Obj *objPtr;
 
18582 int option;
18583 static const char * const options[] = {
18584 "create", "get", "set", "unset", "exists", "keys", "size", "info",
18585 "merge", "with", "append", "lappend", "incr", "remove", "values", "for",
18586 "replace", "update", NULL
@@ -18596,11 +18427,11 @@
18596 Jim_WrongNumArgs(interp, 1, argv, "subcommand ?arguments ...?");
18597 return JIM_ERR;
18598 }
18599
18600 if (Jim_GetEnum(interp, argv[1], options, &option, "subcommand", JIM_ERRMSG) != JIM_OK) {
18601 return JIM_ERR;
18602 }
18603
18604 switch (option) {
18605 case OPT_GET:
18606 if (argc < 3) {
@@ -18643,16 +18474,19 @@
18643 if (Jim_SetDictKeysVector(interp, argv[2], argv + 3, argc - 3, NULL, 0) != JIM_OK) {
18644 return JIM_ERR;
18645 }
18646 return JIM_OK;
18647
 
 
 
18648 case OPT_KEYS:
18649 if (argc != 3 && argc != 4) {
18650 Jim_WrongNumArgs(interp, 2, argv, "dictionary ?pattern?");
18651 return JIM_ERR;
18652 }
18653 return Jim_DictKeys(interp, argv[2], argc == 4 ? argv[3] : NULL);
18654
18655 case OPT_SIZE:
18656 if (argc != 3) {
18657 Jim_WrongNumArgs(interp, 2, argv, "dictionary");
18658 return JIM_ERR;
@@ -18665,19 +18499,20 @@
18665
18666 case OPT_MERGE:
18667 if (argc == 2) {
18668 return JIM_OK;
18669 }
18670 if (Jim_DictSize(interp, argv[2]) < 0) {
 
18671 return JIM_ERR;
18672 }
18673
18674 break;
18675
18676 case OPT_UPDATE:
18677 if (argc < 6 || argc % 2) {
18678
18679 argc = 2;
18680 }
18681 break;
18682
18683 case OPT_CREATE:
@@ -18693,12 +18528,19 @@
18693 if (argc != 3) {
18694 Jim_WrongNumArgs(interp, 2, argv, "dictionary");
18695 return JIM_ERR;
18696 }
18697 return Jim_DictInfo(interp, argv[2]);
 
 
 
 
 
 
 
18698 }
18699
18700 return Jim_EvalEnsemble(interp, "dict", options[option], argc - 2, argv + 2);
18701 }
18702
18703
18704 static int Jim_SubstCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
@@ -18764,11 +18606,11 @@
18764
18765 #ifdef jim_ext_namespace
18766 int nons = 0;
18767
18768 if (argc > 2 && Jim_CompareStringImmediate(interp, argv[1], "-nons")) {
18769
18770 argc--;
18771 argv++;
18772 nons = 1;
18773 }
18774 #endif
@@ -18775,16 +18617,15 @@
18775
18776 if (argc < 2) {
18777 Jim_WrongNumArgs(interp, 1, argv, "subcommand ?args ...?");
18778 return JIM_ERR;
18779 }
18780 if (Jim_GetEnum(interp, argv[1], commands, &cmd, "subcommand", JIM_ERRMSG | JIM_ENUM_ABBREV)
18781 != JIM_OK) {
18782 return JIM_ERR;
18783 }
18784
18785
18786 switch (cmd) {
18787 case INFO_EXISTS:
18788 if (argc != 3) {
18789 Jim_WrongNumArgs(interp, 2, argv, "varName");
18790 return JIM_ERR;
@@ -18809,21 +18650,21 @@
18809 Jim_SetResult(interp, (Jim_Obj *)cmdPtr->u.native.privData);
18810 return JIM_OK;
18811 }
18812
18813 case INFO_CHANNELS:
18814 mode++;
18815 #ifndef jim_ext_aio
18816 Jim_SetResultString(interp, "aio not enabled", -1);
18817 return JIM_ERR;
18818 #endif
18819
18820 case INFO_PROCS:
18821 mode++;
18822
18823 case INFO_COMMANDS:
18824
18825 if (argc != 2 && argc != 3) {
18826 Jim_WrongNumArgs(interp, 2, argv, "?pattern?");
18827 return JIM_ERR;
18828 }
18829 #ifdef jim_ext_namespace
@@ -18835,17 +18676,17 @@
18835 #endif
18836 Jim_SetResult(interp, JimCommandsList(interp, (argc == 3) ? argv[2] : NULL, mode));
18837 break;
18838
18839 case INFO_VARS:
18840 mode++;
18841
18842 case INFO_LOCALS:
18843 mode++;
18844
18845 case INFO_GLOBALS:
18846
18847 if (argc != 2 && argc != 3) {
18848 Jim_WrongNumArgs(interp, 2, argv, "?pattern?");
18849 return JIM_ERR;
18850 }
18851 #ifdef jim_ext_namespace
@@ -18951,13 +18792,12 @@
18951 case INFO_ARGS:
18952 Jim_SetResult(interp, cmdPtr->u.proc.argListObjPtr);
18953 break;
18954 case INFO_STATICS:
18955 if (cmdPtr->u.proc.staticVars) {
18956 int mode = JIM_VARLIST_LOCALS | JIM_VARLIST_VALUES;
18957 Jim_SetResult(interp, JimHashtablePatternMatch(interp, cmdPtr->u.proc.staticVars,
18958 NULL, JimVariablesMatch, mode));
18959 }
18960 break;
18961 }
18962 break;
18963 }
@@ -18985,15 +18825,15 @@
18985 }
18986 }
18987 break;
18988
18989 case INFO_HOSTNAME:
18990
18991 return Jim_Eval(interp, "os.gethostname");
18992
18993 case INFO_NAMEOFEXECUTABLE:
18994
18995 return Jim_Eval(interp, "{info nameofexecutable}");
18996
18997 case INFO_RETURNCODES:
18998 if (argc == 2) {
18999 int i;
@@ -19070,11 +18910,11 @@
19070
19071 if (option == OPT_VAR) {
19072 result = Jim_GetVariable(interp, objPtr, 0) != NULL;
19073 }
19074 else {
19075
19076 Jim_Cmd *cmd = Jim_GetCommand(interp, objPtr, JIM_NONE);
19077
19078 if (cmd) {
19079 switch (option) {
19080 case OPT_COMMAND:
@@ -19113,11 +18953,11 @@
19113 if (len == 0) {
19114 return JIM_OK;
19115 }
19116 strLen = Jim_Utf8Length(interp, argv[1]);
19117
19118
19119 if (argc == 2) {
19120 splitChars = " \n\t\r";
19121 splitLen = 4;
19122 }
19123 else {
@@ -19126,11 +18966,11 @@
19126 }
19127
19128 noMatchStart = str;
19129 resObjPtr = Jim_NewListObj(interp, NULL, 0);
19130
19131
19132 if (splitLen) {
19133 Jim_Obj *objPtr;
19134 while (strLen--) {
19135 const char *sc = splitChars;
19136 int scLen = splitLen;
@@ -19155,11 +18995,11 @@
19155 #define NUM_COMMON (128 - 9)
19156 while (strLen--) {
19157 int n = utf8_tounicode(str, &c);
19158 #ifdef JIM_OPTIMIZATION
19159 if (c >= 9 && c < 128) {
19160
19161 c -= 9;
19162 if (!commonObj) {
19163 commonObj = Jim_Alloc(sizeof(*commonObj) * NUM_COMMON);
19164 memset(commonObj, 0, sizeof(*commonObj) * NUM_COMMON);
19165 }
@@ -19189,11 +19029,11 @@
19189
19190 if (argc != 2 && argc != 3) {
19191 Jim_WrongNumArgs(interp, 1, argv, "list ?joinString?");
19192 return JIM_ERR;
19193 }
19194
19195 if (argc == 2) {
19196 joinStr = " ";
19197 joinStrLen = 1;
19198 }
19199 else {
@@ -19468,13 +19308,13 @@
19468 return -1;
19469 else if (step < 0 && end > start)
19470 return -1;
19471 len = end - start;
19472 if (len < 0)
19473 len = -len;
19474 if (step < 0)
19475 step = -step;
19476 len = 1 + ((len - 1) / step);
19477 if (len > INT_MAX)
19478 len = INT_MAX;
19479 return (int)((len < 0) ? -1 : len);
19480 }
@@ -19644,57 +19484,102 @@
19644 argv[1] = interp->result;
19645
19646 Jim_EvalObjVector(interp, 2, argv);
19647 }
19648
19649 static void JimSetFailedEnumResult(Jim_Interp *interp, const char *arg, const char *badtype,
19650 const char *prefix, const char *const *tablePtr, const char *name)
19651 {
19652 int count;
19653 char **tablePtrSorted;
19654 int i;
19655
19656 for (count = 0; tablePtr[count]; count++) {
19657 }
19658
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
19659 if (name == NULL) {
19660 name = "option";
19661 }
19662
19663 Jim_SetResultFormatted(interp, "%s%s \"%s\": must be ", badtype, name, arg);
19664 tablePtrSorted = Jim_Alloc(sizeof(char *) * count);
19665 memcpy(tablePtrSorted, tablePtr, sizeof(char *) * count);
19666 qsort(tablePtrSorted, count, sizeof(char *), qsortCompareStringPointers);
19667 for (i = 0; i < count; i++) {
19668 if (i + 1 == count && count > 1) {
19669 Jim_AppendString(interp, Jim_GetResult(interp), "or ", -1);
19670 }
19671 Jim_AppendStrings(interp, Jim_GetResult(interp), prefix, tablePtrSorted[i], NULL);
19672 if (i + 1 != count) {
19673 Jim_AppendString(interp, Jim_GetResult(interp), ", ", -1);
19674 }
19675 }
19676 Jim_Free(tablePtrSorted);
19677 }
19678
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
19679 int Jim_GetEnum(Jim_Interp *interp, Jim_Obj *objPtr,
19680 const char *const *tablePtr, int *indexPtr, const char *name, int flags)
19681 {
19682 const char *bad = "bad ";
19683 const char *const *entryPtr = NULL;
19684 int i;
19685 int match = -1;
19686 int arglen;
19687 const char *arg = Jim_GetString(objPtr, &arglen);
 
 
 
 
 
 
 
 
 
19688
19689 *indexPtr = -1;
19690
19691 for (entryPtr = tablePtr, i = 0; *entryPtr != NULL; entryPtr++, i++) {
19692 if (Jim_CompareStringImmediate(interp, objPtr, *entryPtr)) {
19693
19694 *indexPtr = i;
19695 return JIM_OK;
19696 }
19697 if (flags & JIM_ENUM_ABBREV) {
19698 if (strncmp(arg, *entryPtr, arglen) == 0) {
19699 if (*arg == '-' && arglen == 1) {
19700 break;
@@ -19706,12 +19591,20 @@
19706 match = i;
19707 }
19708 }
19709 }
19710
19711
19712 if (match >= 0) {
 
 
 
 
 
 
 
 
19713 *indexPtr = match;
19714 return JIM_OK;
19715 }
19716
19717 ambiguous:
@@ -19743,15 +19636,17 @@
19743 return objPtr->typePtr == &listObjType;
19744 }
19745
19746 void Jim_SetResultFormatted(Jim_Interp *interp, const char *format, ...)
19747 {
19748
19749 int len = strlen(format);
19750 int extra = 0;
19751 int n = 0;
19752 const char *params[5];
 
 
19753 char *buf;
19754 va_list args;
19755 int i;
19756
19757 va_start(args, format);
@@ -19766,10 +19661,12 @@
19766 }
19767 else if (strncmp(format + i, "%#s", 3) == 0) {
19768 Jim_Obj *objPtr = va_arg(args, Jim_Obj *);
19769
19770 params[n] = Jim_GetString(objPtr, &l);
 
 
19771 }
19772 else {
19773 if (format[i] == '%') {
19774 i++;
19775 }
@@ -19784,10 +19681,14 @@
19784 len = snprintf(buf, len + 1, format, params[0], params[1], params[2], params[3], params[4]);
19785
19786 va_end(args);
19787
19788 Jim_SetResult(interp, Jim_NewStringObjNoAlloc(interp, buf, len));
 
 
 
 
19789 }
19790
19791
19792 #ifndef jim_ext_package
19793 int Jim_PackageProvide(Jim_Interp *interp, const char *name, const char *ver, int flags)
@@ -19808,11 +19709,11 @@
19808 #include <string.h>
19809
19810
19811 static int subcmd_null(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
19812 {
19813
19814 return JIM_OK;
19815 }
19816
19817 static const jim_subcmd_type dummy_subcmd = {
19818 "dummy", NULL, subcmd_null, 0, 0, JIM_MODFLAG_HIDDEN
@@ -19831,22 +19732,18 @@
19831 }
19832
19833 static void bad_subcmd(Jim_Interp *interp, const jim_subcmd_type * command_table, const char *type,
19834 Jim_Obj *cmd, Jim_Obj *subcmd)
19835 {
19836 Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
19837 Jim_AppendStrings(interp, Jim_GetResult(interp), Jim_String(cmd), ", ", type,
19838 " command \"", Jim_String(subcmd), "\": should be ", NULL);
19839 add_commands(interp, command_table, ", ");
19840 }
19841
19842 static void show_cmd_usage(Jim_Interp *interp, const jim_subcmd_type * command_table, int argc,
19843 Jim_Obj *const *argv)
19844 {
19845 Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
19846 Jim_AppendStrings(interp, Jim_GetResult(interp), "Usage: \"", Jim_String(argv[0]),
19847 " command ... \", where command is one of: ", NULL);
19848 add_commands(interp, command_table, ", ");
19849 }
19850
19851 static void add_cmd_usage(Jim_Interp *interp, const jim_subcmd_type * ct, Jim_Obj *cmd)
19852 {
@@ -19863,67 +19760,78 @@
19863 {
19864 Jim_SetResultString(interp, "wrong # args: should be \"", -1);
19865 add_cmd_usage(interp, command_table, subcmd);
19866 Jim_AppendStrings(interp, Jim_GetResult(interp), "\"", NULL);
19867 }
 
 
 
 
 
 
 
 
19868
19869 const jim_subcmd_type *Jim_ParseSubCmd(Jim_Interp *interp, const jim_subcmd_type * command_table,
19870 int argc, Jim_Obj *const *argv)
19871 {
19872 const jim_subcmd_type *ct;
19873 const jim_subcmd_type *partial = 0;
19874 int cmdlen;
19875 Jim_Obj *cmd;
19876 const char *cmdstr;
19877 const char *cmdname;
19878 int help = 0;
19879
19880 cmdname = Jim_String(argv[0]);
19881
19882 if (argc < 2) {
19883 Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
19884 Jim_AppendStrings(interp, Jim_GetResult(interp), "wrong # args: should be \"", cmdname,
19885 " command ...\"\n", NULL);
19886 Jim_AppendStrings(interp, Jim_GetResult(interp), "Use \"", cmdname, " -help ?command?\" for help", NULL);
19887 return 0;
19888 }
19889
19890 cmd = argv[1];
19891
19892
 
 
 
 
 
 
 
 
19893 if (Jim_CompareStringImmediate(interp, cmd, "-help")) {
19894 if (argc == 2) {
19895
19896 show_cmd_usage(interp, command_table, argc, argv);
19897 return &dummy_subcmd;
19898 }
19899 help = 1;
19900
19901
19902 cmd = argv[2];
19903 }
19904
19905
19906 if (Jim_CompareStringImmediate(interp, cmd, "-commands")) {
19907
19908 Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
19909 add_commands(interp, command_table, " ");
19910 return &dummy_subcmd;
19911 }
19912
19913 cmdstr = Jim_GetString(cmd, &cmdlen);
19914
19915 for (ct = command_table; ct->cmd; ct++) {
19916 if (Jim_CompareStringImmediate(interp, cmd, ct->cmd)) {
19917
19918 break;
19919 }
19920 if (strncmp(cmdstr, ct->cmd, cmdlen) == 0) {
19921 if (partial) {
19922
19923 if (help) {
19924
19925 show_cmd_usage(interp, command_table, argc, argv);
19926 return &dummy_subcmd;
19927 }
19928 bad_subcmd(interp, command_table, "ambiguous", argv[0], argv[1 + help]);
19929 return 0;
@@ -19931,44 +19839,51 @@
19931 partial = ct;
19932 }
19933 continue;
19934 }
19935
19936
19937 if (partial && !ct->cmd) {
19938 ct = partial;
19939 }
19940
19941 if (!ct->cmd) {
19942
19943 if (help) {
19944
19945 show_cmd_usage(interp, command_table, argc, argv);
19946 return &dummy_subcmd;
19947 }
19948 bad_subcmd(interp, command_table, "unknown", argv[0], argv[1 + help]);
19949 return 0;
19950 }
19951
19952 if (help) {
19953 Jim_SetResultString(interp, "Usage: ", -1);
19954
19955 add_cmd_usage(interp, ct, argv[0]);
19956 return &dummy_subcmd;
19957 }
19958
19959
 
 
 
 
 
 
 
19960 if (argc - 2 < ct->minargs || (ct->maxargs >= 0 && argc - 2 > ct->maxargs)) {
19961 Jim_SetResultString(interp, "wrong # args: should be \"", -1);
19962
19963 add_cmd_usage(interp, ct, argv[0]);
19964 Jim_AppendStrings(interp, Jim_GetResult(interp), "\"", NULL);
19965
19966 return 0;
19967 }
19968
19969
19970 return ct;
19971 }
19972
19973 int Jim_CallSubCmd(Jim_Interp *interp, const jim_subcmd_type * ct, int argc, Jim_Obj *const *argv)
19974 {
@@ -20019,11 +19934,11 @@
20019 *p++ = 0xe0 | ((uc & 0xf000) >> 12);
20020 *p++ = 0x80 | ((uc & 0xfc0) >> 6);
20021 *p = 0x80 | (uc & 0x3f);
20022 return 3;
20023 }
20024
20025 else {
20026 *p++ = 0xf0 | ((uc & 0x1c0000) >> 18);
20027 *p++ = 0x80 | ((uc & 0x3f000) >> 12);
20028 *p++ = 0x80 | ((uc & 0xfc0) >> 6);
20029 *p = 0x80 | (uc & 0x3f);
@@ -20146,11 +20061,12 @@
20146 continue;
20147 }
20148 *p++ = ch;
20149 format += step;
20150 step = utf8_tounicode(format, &ch);
20151 } while (sawFlag);
 
20152
20153
20154 width = 0;
20155 if (isdigit(ch)) {
20156 width = strtoul(format, &end, 10);
@@ -20210,11 +20126,11 @@
20210 if (ch == 'h') {
20211 useShort = 1;
20212 format += step;
20213 step = utf8_tounicode(format, &ch);
20214 } else if (ch == 'l') {
20215
20216 format += step;
20217 step = utf8_tounicode(format, &ch);
20218 if (ch == 'l') {
20219 format += step;
20220 step = utf8_tounicode(format, &ch);
@@ -20237,11 +20153,11 @@
20237 goto errorMsg;
20238 case 's': {
20239 formatted_buf = Jim_GetString(objv[objIndex], &formatted_bytes);
20240 formatted_chars = Jim_Utf8Length(interp, objv[objIndex]);
20241 if (gotPrecision && (precision < formatted_chars)) {
20242
20243 formatted_chars = precision;
20244 formatted_bytes = utf8_index(formatted_buf, precision);
20245 }
20246 break;
20247 }
@@ -20249,11 +20165,11 @@
20249 jim_wide code;
20250
20251 if (Jim_GetWide(interp, objv[objIndex], &code) != JIM_OK) {
20252 goto error;
20253 }
20254
20255 formatted_bytes = utf8_getchars(spec, code);
20256 formatted_buf = spec;
20257 formatted_chars = 1;
20258 break;
20259 }
@@ -20267,11 +20183,11 @@
20267 goto error;
20268 }
20269 length = sizeof(w) * 8;
20270
20271
20272
20273 if (num_buffer_size < length + 1) {
20274 num_buffer_size = length + 1;
20275 num_buffer = Jim_Realloc(num_buffer, num_buffer_size);
20276 }
20277
@@ -20295,29 +20211,29 @@
20295 case 'E':
20296 case 'f':
20297 case 'g':
20298 case 'G':
20299 doubleType = 1;
20300
20301 case 'd':
20302 case 'u':
20303 case 'o':
20304 case 'x':
20305 case 'X': {
20306 jim_wide w;
20307 double d;
20308 int length;
20309
20310
20311 if (width) {
20312 p += sprintf(p, "%ld", width);
20313 }
20314 if (gotPrecision) {
20315 p += sprintf(p, ".%ld", precision);
20316 }
20317
20318
20319 if (doubleType) {
20320 if (Jim_GetDouble(interp, objv[objIndex], &d) != JIM_OK) {
20321 goto error;
20322 }
20323 length = MAX_FLOAT_WIDTH;
@@ -20344,19 +20260,26 @@
20344 }
20345
20346 *p++ = (char) ch;
20347 *p = '\0';
20348
20349
 
 
 
 
 
 
 
20350 if (width > length) {
20351 length = width;
20352 }
20353 if (gotPrecision) {
20354 length += precision;
20355 }
20356
20357
20358 if (num_buffer_size < length + 1) {
20359 num_buffer_size = length + 1;
20360 num_buffer = Jim_Realloc(num_buffer, num_buffer_size);
20361 }
20362
@@ -20370,11 +20293,11 @@
20370 formatted_buf = num_buffer;
20371 break;
20372 }
20373
20374 default: {
20375
20376 spec[0] = ch;
20377 spec[1] = '\0';
20378 Jim_SetResultFormatted(interp, "bad field specifier \"%s\"", spec);
20379 goto error;
20380 }
@@ -20422,37 +20345,37 @@
20422
20423 #define REG_MAX_PAREN 100
20424
20425
20426
20427 #define END 0
20428 #define BOL 1
20429 #define EOL 2
20430 #define ANY 3
20431 #define ANYOF 4
20432 #define ANYBUT 5
20433 #define BRANCH 6
20434 #define BACK 7
20435 #define EXACTLY 8
20436 #define NOTHING 9
20437 #define REP 10
20438 #define REPMIN 11
20439 #define REPX 12
20440 #define REPXMIN 13
20441 #define BOLX 14
20442 #define EOLX 15
20443 #define WORDA 16
20444 #define WORDZ 17
20445
20446 #define OPENNC 1000
20447 #define OPEN 1001
20448
20449
20450
20451
20452 #define CLOSENC 2000
20453 #define CLOSE 2001
20454 #define CLOSE_END (CLOSE+REG_MAX_PAREN)
20455
20456 #define REG_MAGIC 0xFADED00D
20457
20458
@@ -20465,18 +20388,18 @@
20465
20466 #define FAIL(R,M) { (R)->err = (M); return (M); }
20467 #define ISMULT(c) ((c) == '*' || (c) == '+' || (c) == '?' || (c) == '{')
20468 #define META "^$.[()|?{+*"
20469
20470 #define HASWIDTH 1
20471 #define SIMPLE 2
20472 #define SPSTART 4
20473 #define WORST 0
20474
20475 #define MAX_REP_COUNT 1000000
20476
20477 static int reg(regex_t *preg, int paren , int *flagp );
20478 static int regpiece(regex_t *preg, int *flagp );
20479 static int regbranch(regex_t *preg, int *flagp );
20480 static int regatom(regex_t *preg, int *flagp );
20481 static int regnode(regex_t *preg, int op );
20482 static int regnext(regex_t *preg, int p );
@@ -20520,15 +20443,15 @@
20520 memset(preg, 0, sizeof(*preg));
20521
20522 if (exp == NULL)
20523 FAIL(preg, REG_ERR_NULL_ARGUMENT);
20524
20525
20526 preg->cflags = cflags;
20527 preg->regparse = exp;
20528
20529
20530 preg->proglen = (strlen(exp) + 1) * 5;
20531 preg->program = malloc(preg->proglen * sizeof(int));
20532 if (preg->program == NULL)
20533 FAIL(preg, REG_ERR_NOMEM);
20534
@@ -20535,24 +20458,24 @@
20535 regc(preg, REG_MAGIC);
20536 if (reg(preg, 0, &flags) == 0) {
20537 return preg->err;
20538 }
20539
20540
20541 if (preg->re_nsub >= REG_MAX_PAREN)
20542 FAIL(preg,REG_ERR_TOO_BIG);
20543
20544
20545 preg->regstart = 0;
20546 preg->reganch = 0;
20547 preg->regmust = 0;
20548 preg->regmlen = 0;
20549 scan = 1;
20550 if (OP(preg, regnext(preg, scan)) == END) {
20551 scan = OPERAND(scan);
20552
20553
20554 if (OP(preg, scan) == EXACTLY) {
20555 preg->regstart = preg->program[OPERAND(scan)];
20556 }
20557 else if (OP(preg, scan) == BOL)
20558 preg->reganch++;
@@ -20579,24 +20502,24 @@
20579 #endif
20580
20581 return 0;
20582 }
20583
20584 static int reg(regex_t *preg, int paren , int *flagp )
20585 {
20586 int ret;
20587 int br;
20588 int ender;
20589 int parno = 0;
20590 int flags;
20591
20592 *flagp = HASWIDTH;
20593
20594
20595 if (paren) {
20596 if (preg->regparse[0] == '?' && preg->regparse[1] == ':') {
20597
20598 preg->regparse += 2;
20599 parno = -1;
20600 }
20601 else {
20602 parno = ++preg->re_nsub;
@@ -20603,16 +20526,16 @@
20603 }
20604 ret = regnode(preg, OPEN+parno);
20605 } else
20606 ret = 0;
20607
20608
20609 br = regbranch(preg, &flags);
20610 if (br == 0)
20611 return 0;
20612 if (ret != 0)
20613 regtail(preg, ret, br);
20614 else
20615 ret = br;
20616 if (!(flags&HASWIDTH))
20617 *flagp &= ~HASWIDTH;
20618 *flagp |= flags&SPSTART;
@@ -20619,25 +20542,25 @@
20619 while (*preg->regparse == '|') {
20620 preg->regparse++;
20621 br = regbranch(preg, &flags);
20622 if (br == 0)
20623 return 0;
20624 regtail(preg, ret, br);
20625 if (!(flags&HASWIDTH))
20626 *flagp &= ~HASWIDTH;
20627 *flagp |= flags&SPSTART;
20628 }
20629
20630
20631 ender = regnode(preg, (paren) ? CLOSE+parno : END);
20632 regtail(preg, ret, ender);
20633
20634
20635 for (br = ret; br != 0; br = regnext(preg, br))
20636 regoptail(preg, br, ender);
20637
20638
20639 if (paren && *preg->regparse++ != ')') {
20640 preg->err = REG_ERR_UNMATCHED_PAREN;
20641 return 0;
20642 } else if (!paren && *preg->regparse != '\0') {
20643 if (*preg->regparse == ')') {
@@ -20657,11 +20580,11 @@
20657 int ret;
20658 int chain;
20659 int latest;
20660 int flags;
20661
20662 *flagp = WORST;
20663
20664 ret = regnode(preg, BRANCH);
20665 chain = 0;
20666 while (*preg->regparse != '\0' && *preg->regparse != ')' &&
20667 *preg->regparse != '|') {
@@ -20675,11 +20598,11 @@
20675 else {
20676 regtail(preg, chain, latest);
20677 }
20678 chain = latest;
20679 }
20680 if (chain == 0)
20681 (void) regnode(preg, NOTHING);
20682
20683 return(ret);
20684 }
20685
@@ -20705,11 +20628,11 @@
20705 if (!(flags&HASWIDTH) && op != '?') {
20706 preg->err = REG_ERR_OPERAND_COULD_BE_EMPTY;
20707 return 0;
20708 }
20709
20710
20711 if (op == '{') {
20712 char *end;
20713
20714 min = strtoul(preg->regparse + 1, &end, 10);
20715 if (end == preg->regparse + 1) {
@@ -20716,10 +20639,14 @@
20716 preg->err = REG_ERR_BAD_COUNT;
20717 return 0;
20718 }
20719 if (*end == '}') {
20720 max = min;
 
 
 
 
20721 }
20722 else {
20723 preg->regparse = end;
20724 max = strtoul(preg->regparse + 1, &end, 10);
20725 if (*end != '}') {
@@ -20777,11 +20704,11 @@
20777 static void reg_addrange(regex_t *preg, int lower, int upper)
20778 {
20779 if (lower > upper) {
20780 reg_addrange(preg, upper, lower);
20781 }
20782
20783 regc(preg, upper - lower + 1);
20784 regc(preg, lower);
20785 }
20786
20787 static void reg_addrange_str(regex_t *preg, const char *str)
@@ -20845,17 +20772,17 @@
20845 case 'r': *ch = '\r'; break;
20846 case 't': *ch = '\t'; break;
20847 case 'v': *ch = '\v'; break;
20848 case 'u':
20849 if (*s == '{') {
20850
20851 n = parse_hex(s + 1, 6, ch);
20852 if (n > 0 && s[n + 1] == '}' && *ch >= 0 && *ch <= 0x1fffff) {
20853 s += n + 2;
20854 }
20855 else {
20856
20857 *ch = 'u';
20858 }
20859 }
20860 else if ((n = parse_hex(s, 4, ch)) > 0) {
20861 s += n;
@@ -20886,15 +20813,15 @@
20886 int nocase = (preg->cflags & REG_ICASE);
20887
20888 int ch;
20889 int n = reg_utf8_tounicode_case(preg->regparse, &ch, nocase);
20890
20891 *flagp = WORST;
20892
20893 preg->regparse += n;
20894 switch (ch) {
20895
20896 case '^':
20897 ret = regnode(preg, BOL);
20898 break;
20899 case '$':
20900 ret = regnode(preg, EOL);
@@ -20904,37 +20831,60 @@
20904 *flagp |= HASWIDTH|SIMPLE;
20905 break;
20906 case '[': {
20907 const char *pattern = preg->regparse;
20908
20909 if (*pattern == '^') {
20910 ret = regnode(preg, ANYBUT);
20911 pattern++;
20912 } else
20913 ret = regnode(preg, ANYOF);
20914
20915
20916 if (*pattern == ']' || *pattern == '-') {
20917 reg_addrange(preg, *pattern, *pattern);
20918 pattern++;
20919 }
20920
20921 while (*pattern && *pattern != ']') {
20922
20923 int start;
20924 int end;
20925
 
 
 
 
 
 
 
20926 pattern += reg_utf8_tounicode_case(pattern, &start, nocase);
20927 if (start == '\\') {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
20928 pattern += reg_decode_escape(pattern, &start);
20929 if (start == 0) {
20930 preg->err = REG_ERR_NULL_CHAR;
20931 return 0;
20932 }
20933 }
20934 if (pattern[0] == '-' && pattern[1] && pattern[1] != ']') {
20935
20936 pattern += utf8_tounicode(pattern, &end);
20937 pattern += reg_utf8_tounicode_case(pattern, &end, nocase);
20938 if (end == '\\') {
20939 pattern += reg_decode_escape(pattern, &end);
20940 if (end == 0) {
@@ -20949,30 +20899,25 @@
20949 if (start == '[' && pattern[0] == ':') {
20950 static const char *character_class[] = {
20951 ":alpha:", ":alnum:", ":space:", ":blank:", ":upper:", ":lower:",
20952 ":digit:", ":xdigit:", ":cntrl:", ":graph:", ":print:", ":punct:",
20953 };
20954 enum {
20955 CC_ALPHA, CC_ALNUM, CC_SPACE, CC_BLANK, CC_UPPER, CC_LOWER,
20956 CC_DIGIT, CC_XDIGIT, CC_CNTRL, CC_GRAPH, CC_PRINT, CC_PUNCT,
20957 CC_NUM
20958 };
20959 int i;
20960
20961 for (i = 0; i < CC_NUM; i++) {
20962 int n = strlen(character_class[i]);
20963 if (strncmp(pattern, character_class[i], n) == 0) {
20964
20965 pattern += n + 1;
20966 break;
20967 }
20968 }
20969 if (i != CC_NUM) {
20970 switch (i) {
 
20971 case CC_ALNUM:
20972 reg_addrange(preg, '0', '9');
20973
20974 case CC_ALPHA:
20975 if ((preg->cflags & REG_ICASE) == 0) {
20976 reg_addrange(preg, 'a', 'z');
20977 }
20978 reg_addrange(preg, 'A', 'Z');
@@ -20990,11 +20935,11 @@
20990 reg_addrange(preg, 'a', 'z');
20991 break;
20992 case CC_XDIGIT:
20993 reg_addrange(preg, 'a', 'f');
20994 reg_addrange(preg, 'A', 'F');
20995
20996 case CC_DIGIT:
20997 reg_addrange(preg, '0', '9');
20998 break;
20999 case CC_CNTRL:
21000 reg_addrange(preg, 0, 31);
@@ -21014,11 +20959,11 @@
21014 break;
21015 }
21016 continue;
21017 }
21018 }
21019
21020 reg_addrange(preg, start, start);
21021 }
21022 regc(preg, '\0');
21023
21024 if (*pattern) {
@@ -21037,11 +20982,11 @@
21037 break;
21038 case '\0':
21039 case '|':
21040 case ')':
21041 preg->err = REG_ERR_INTERNAL;
21042 return 0;
21043 case '?':
21044 case '+':
21045 case '*':
21046 case '{':
21047 preg->err = REG_ERR_COUNT_FOLLOWS_NOTHING;
@@ -21090,34 +21035,34 @@
21090 ret = regnode(preg, ch == 's' ? ANYOF : ANYBUT);
21091 reg_addrange_str(preg," \t\r\n\f\v");
21092 regc(preg, '\0');
21093 *flagp |= HASWIDTH|SIMPLE;
21094 break;
21095
21096 default:
21097
21098
21099 preg->regparse--;
21100 goto de_fault;
21101 }
21102 break;
21103 de_fault:
21104 default: {
21105 int added = 0;
21106
21107
21108 preg->regparse -= n;
21109
21110 ret = regnode(preg, EXACTLY);
21111
21112
21113
21114 while (*preg->regparse && strchr(META, *preg->regparse) == NULL) {
21115 n = reg_utf8_tounicode_case(preg->regparse, &ch, (preg->cflags & REG_ICASE));
21116 if (ch == '\\' && preg->regparse[n]) {
21117 if (strchr("<>mMwWdDsSAZ", preg->regparse[n])) {
21118
21119 break;
21120 }
21121 n += reg_decode_escape(preg->regparse + n, &ch);
21122 if (ch == 0) {
21123 preg->err = REG_ERR_NULL_CHAR;
@@ -21125,23 +21070,23 @@
21125 }
21126 }
21127
21128
21129 if (ISMULT(preg->regparse[n])) {
21130
21131 if (added) {
21132
21133 break;
21134 }
21135
21136 regc(preg, ch);
21137 added++;
21138 preg->regparse += n;
21139 break;
21140 }
21141
21142
21143 regc(preg, ch);
21144 added++;
21145 preg->regparse += n;
21146 }
21147 regc(preg, '\0');
@@ -21168,15 +21113,15 @@
21168
21169 static int regnode(regex_t *preg, int op)
21170 {
21171 reg_grow(preg, 2);
21172
21173
21174 preg->program[preg->p++] = op;
21175 preg->program[preg->p++] = 0;
21176
21177
21178 return preg->p - 2;
21179 }
21180
21181 static void regc(regex_t *preg, int b )
21182 {
@@ -21186,13 +21131,13 @@
21186
21187 static int reginsert(regex_t *preg, int op, int size, int opnd )
21188 {
21189 reg_grow(preg, size);
21190
21191
21192 memmove(preg->program + opnd + size, preg->program + opnd, sizeof(int) * (preg->p - opnd));
21193
21194 memset(preg->program + opnd, 0, sizeof(int) * size);
21195
21196 preg->program[opnd] = op;
21197
21198 preg->p += size;
@@ -21204,11 +21149,11 @@
21204 {
21205 int scan;
21206 int temp;
21207 int offset;
21208
21209
21210 scan = p;
21211 for (;;) {
21212 temp = regnext(preg, scan);
21213 if (temp == 0)
21214 break;
@@ -21224,11 +21169,11 @@
21224 }
21225
21226
21227 static void regoptail(regex_t *preg, int p, int val )
21228 {
21229
21230 if (p != 0 && OP(preg, p) == BRANCH) {
21231 regtail(preg, OPERAND(p), val);
21232 }
21233 }
21234
@@ -21240,16 +21185,16 @@
21240 int regexec(regex_t *preg, const char *string, size_t nmatch, regmatch_t pmatch[], int eflags)
21241 {
21242 const char *s;
21243 int scan;
21244
21245
21246 if (preg == NULL || preg->program == NULL || string == NULL) {
21247 return REG_ERR_NULL_ARGUMENT;
21248 }
21249
21250
21251 if (*preg->program != REG_MAGIC) {
21252 return REG_ERR_CORRUPTED;
21253 }
21254
21255 #ifdef DEBUG
@@ -21258,51 +21203,51 @@
21258 #endif
21259
21260 preg->eflags = eflags;
21261 preg->pmatch = pmatch;
21262 preg->nmatch = nmatch;
21263 preg->start = string;
21264
21265
21266 for (scan = OPERAND(1); scan != 0; scan += regopsize(preg, scan)) {
21267 int op = OP(preg, scan);
21268 if (op == END)
21269 break;
21270 if (op == REPX || op == REPXMIN)
21271 preg->program[scan + 4] = 0;
21272 }
21273
21274
21275 if (preg->regmust != 0) {
21276 s = string;
21277 while ((s = str_find(s, preg->program[preg->regmust], preg->cflags & REG_ICASE)) != NULL) {
21278 if (prefix_cmp(preg->program + preg->regmust, preg->regmlen, s, preg->cflags & REG_ICASE) >= 0) {
21279 break;
21280 }
21281 s++;
21282 }
21283 if (s == NULL)
21284 return REG_NOMATCH;
21285 }
21286
21287
21288 preg->regbol = string;
21289
21290
21291 if (preg->reganch) {
21292 if (eflags & REG_NOTBOL) {
21293
21294 goto nextline;
21295 }
21296 while (1) {
21297 if (regtry(preg, string)) {
21298 return REG_NOERROR;
21299 }
21300 if (*string) {
21301 nextline:
21302 if (preg->cflags & REG_NEWLINE) {
21303
21304 string = strchr(string, '\n');
21305 if (string) {
21306 preg->regbol = ++string;
21307 continue;
21308 }
@@ -21310,22 +21255,22 @@
21310 }
21311 return REG_NOMATCH;
21312 }
21313 }
21314
21315
21316 s = string;
21317 if (preg->regstart != '\0') {
21318
21319 while ((s = str_find(s, preg->regstart, preg->cflags & REG_ICASE)) != NULL) {
21320 if (regtry(preg, s))
21321 return REG_NOERROR;
21322 s++;
21323 }
21324 }
21325 else
21326
21327 while (1) {
21328 if (regtry(preg, s))
21329 return REG_NOERROR;
21330 if (*s == '\0') {
21331 break;
@@ -21334,15 +21279,15 @@
21334 int c;
21335 s += utf8_tounicode(s, &c);
21336 }
21337 }
21338
21339
21340 return REG_NOMATCH;
21341 }
21342
21343
21344 static int regtry( regex_t *preg, const char *string )
21345 {
21346 int i;
21347
21348 preg->reginput = string;
@@ -21379,11 +21324,11 @@
21379 }
21380
21381 static int reg_range_find(const int *range, int c)
21382 {
21383 while (*range) {
21384
21385 if (c >= range[1] && c <= (range[0] + range[1] - 1)) {
21386 return 1;
21387 }
21388 range += 2;
21389 }
@@ -21391,11 +21336,11 @@
21391 }
21392
21393 static const char *str_find(const char *string, int c, int nocase)
21394 {
21395 if (nocase) {
21396
21397 c = utf8_upper(c);
21398 }
21399 while (*string) {
21400 int ch;
21401 int n = reg_utf8_tounicode_case(string, &ch, nocase);
@@ -21435,15 +21380,15 @@
21435 no = regrepeat(preg, scan + 5, max);
21436 if (no < min) {
21437 return 0;
21438 }
21439 if (matchmin) {
21440
21441 max = no;
21442 no = min;
21443 }
21444
21445 while (1) {
21446 if (matchmin) {
21447 if (no > max) {
21448 break;
21449 }
@@ -21453,22 +21398,22 @@
21453 break;
21454 }
21455 }
21456 preg->reginput = save + utf8_index(save, no);
21457 reg_utf8_tounicode_case(preg->reginput, &c, (preg->cflags & REG_ICASE));
21458
21459 if (reg_iseol(preg, nextch) || c == nextch) {
21460 if (regmatch(preg, next)) {
21461 return(1);
21462 }
21463 }
21464 if (matchmin) {
21465
21466 no++;
21467 }
21468 else {
21469
21470 no--;
21471 }
21472 }
21473 return(0);
21474 }
@@ -21478,13 +21423,13 @@
21478 int *scanpt = preg->program + scan;
21479
21480 int max = scanpt[2];
21481 int min = scanpt[3];
21482
21483
21484 if (scanpt[4] < min) {
21485
21486 scanpt[4]++;
21487 if (regmatch(preg, scan + 5)) {
21488 return 1;
21489 }
21490 scanpt[4]--;
@@ -21493,39 +21438,39 @@
21493 if (scanpt[4] > max) {
21494 return 0;
21495 }
21496
21497 if (matchmin) {
21498
21499 if (regmatch(preg, regnext(preg, scan))) {
21500 return 1;
21501 }
21502
21503 scanpt[4]++;
21504 if (regmatch(preg, scan + 5)) {
21505 return 1;
21506 }
21507 scanpt[4]--;
21508 return 0;
21509 }
21510
21511 if (scanpt[4] < max) {
21512 scanpt[4]++;
21513 if (regmatch(preg, scan + 5)) {
21514 return 1;
21515 }
21516 scanpt[4]--;
21517 }
21518
21519 return regmatch(preg, regnext(preg, scan));
21520 }
21521
21522
21523 static int regmatch(regex_t *preg, int prog)
21524 {
21525 int scan;
21526 int next;
21527 const char *save;
21528
21529 scan = prog;
21530
21531 #ifdef DEBUG
@@ -21535,11 +21480,11 @@
21535 while (scan != 0) {
21536 int n;
21537 int c;
21538 #ifdef DEBUG
21539 if (regnarrate) {
21540 fprintf(stderr, "%3d: %s...\n", scan, regprop(OP(preg, scan)));
21541 }
21542 #endif
21543 next = regnext(preg, scan);
21544 n = reg_utf8_tounicode_case(preg->reginput, &c, (preg->cflags & REG_ICASE));
21545
@@ -21546,49 +21491,49 @@
21546 switch (OP(preg, scan)) {
21547 case BOLX:
21548 if ((preg->eflags & REG_NOTBOL)) {
21549 return(0);
21550 }
21551
21552 case BOL:
21553 if (preg->reginput != preg->regbol) {
21554 return(0);
21555 }
21556 break;
21557 case EOLX:
21558 if (c != 0) {
21559
21560 return 0;
21561 }
21562 break;
21563 case EOL:
21564 if (!reg_iseol(preg, c)) {
21565 return(0);
21566 }
21567 break;
21568 case WORDA:
21569
21570 if ((!isalnum(UCHAR(c))) && c != '_')
21571 return(0);
21572
21573 if (preg->reginput > preg->regbol &&
21574 (isalnum(UCHAR(preg->reginput[-1])) || preg->reginput[-1] == '_'))
21575 return(0);
21576 break;
21577 case WORDZ:
21578
21579 if (preg->reginput > preg->regbol) {
21580
21581 if (reg_iseol(preg, c) || !isalnum(UCHAR(c)) || c != '_') {
21582 c = preg->reginput[-1];
21583
21584 if (isalnum(UCHAR(c)) || c == '_') {
21585 break;
21586 }
21587 }
21588 }
21589
21590 return(0);
21591
21592 case ANY:
21593 if (reg_iseol(preg, c))
21594 return 0;
@@ -21624,12 +21569,12 @@
21624 case NOTHING:
21625 break;
21626 case BACK:
21627 break;
21628 case BRANCH:
21629 if (OP(preg, next) != BRANCH)
21630 next = OPERAND(scan);
21631 else {
21632 do {
21633 save = preg->reginput;
21634 if (regmatch(preg, OPERAND(scan))) {
21635 return(1);
@@ -21636,11 +21581,11 @@
21636 }
21637 preg->reginput = save;
21638 scan = regnext(preg, scan);
21639 } while (scan != 0 && OP(preg, scan) == BRANCH);
21640 return(0);
21641
21642 }
21643 break;
21644 case REP:
21645 case REPMIN:
21646 return regmatchsimplerepeat(preg, scan, OP(preg, scan) == REPMIN);
@@ -21648,11 +21593,11 @@
21648 case REPX:
21649 case REPXMIN:
21650 return regmatchrepeat(preg, scan, OP(preg, scan) == REPXMIN);
21651
21652 case END:
21653 return 1;
21654
21655 case OPENNC:
21656 case CLOSENC:
21657 return regmatch(preg, next);
21658
@@ -21695,11 +21640,11 @@
21695
21696 scan = preg->reginput;
21697 opnd = OPERAND(p);
21698 switch (OP(preg, p)) {
21699 case ANY:
21700
21701 while (!reg_iseol(preg, *scan) && count < max) {
21702 count++;
21703 scan++;
21704 }
21705 break;
@@ -21731,13 +21676,13 @@
21731 }
21732 count++;
21733 scan += n;
21734 }
21735 break;
21736 default:
21737 preg->err = REG_ERR_INTERNAL;
21738 count = 0;
21739 break;
21740 }
21741 preg->reginput = scan;
21742
21743 return(count);
@@ -21758,11 +21703,11 @@
21758 return(p+offset);
21759 }
21760
21761 static int regopsize(regex_t *preg, int p )
21762 {
21763
21764 switch (OP(preg, p)) {
21765 case REP:
21766 case REPMIN:
21767 case REPX:
21768 case REPXMIN:
@@ -21818,10 +21763,223 @@
21818
21819 void regfree(regex_t *preg)
21820 {
21821 free(preg->program);
21822 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
21823
21824 #endif
21825
21826 #if defined(_WIN32) || defined(WIN32)
21827 #ifndef STRICT
@@ -21879,26 +22037,26 @@
21879 {
21880 DIR *dir = 0;
21881
21882 if (name && name[0]) {
21883 size_t base_length = strlen(name);
21884 const char *all =
21885 strchr("/\\", name[base_length - 1]) ? "*" : "/*";
21886
21887 if ((dir = (DIR *) Jim_Alloc(sizeof *dir)) != 0 &&
21888 (dir->name = (char *)Jim_Alloc(base_length + strlen(all) + 1)) != 0) {
21889 strcat(strcpy(dir->name, name), all);
21890
21891 if ((dir->handle = (long)_findfirst(dir->name, &dir->info)) != -1)
21892 dir->result.d_name = 0;
21893 else {
21894 Jim_Free(dir->name);
21895 Jim_Free(dir);
21896 dir = 0;
21897 }
21898 }
21899 else {
21900 Jim_Free(dir);
21901 dir = 0;
21902 errno = ENOMEM;
21903 }
21904 }
@@ -21916,11 +22074,11 @@
21916 if (dir->handle != -1)
21917 result = _findclose(dir->handle);
21918 Jim_Free(dir->name);
21919 Jim_Free(dir);
21920 }
21921 if (result == -1)
21922 errno = EBADF;
21923 return result;
21924 }
21925
21926 struct dirent *readdir(DIR * dir)
@@ -21938,28 +22096,77 @@
21938 }
21939 return result;
21940 }
21941 #endif
21942 #endif
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
21943 #ifndef JIM_BOOTSTRAP_LIB_ONLY
21944 #include <errno.h>
21945 #include <string.h>
21946
21947
21948 #ifdef USE_LINENOISE
21949 #ifdef HAVE_UNISTD_H
21950 #include <unistd.h>
21951 #endif
 
 
 
21952 #include "linenoise.h"
21953 #else
21954 #define MAX_LINE_LEN 512
21955 #endif
21956
21957 char *Jim_HistoryGetline(const char *prompt)
 
 
 
 
 
21958 {
21959 #ifdef USE_LINENOISE
21960 return linenoise(prompt);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
21961 #else
21962 int len;
21963 char *line = malloc(MAX_LINE_LEN);
21964
21965 fputs(prompt, stdout);
@@ -21992,26 +22199,92 @@
21992 }
21993
21994 void Jim_HistorySave(const char *filename)
21995 {
21996 #ifdef USE_LINENOISE
 
 
 
 
 
21997 linenoiseHistorySave(filename);
 
 
 
21998 #endif
21999 }
22000
22001 void Jim_HistoryShow(void)
22002 {
22003 #ifdef USE_LINENOISE
22004
22005 int i;
22006 int len;
22007 char **history = linenoiseHistory(&len);
22008 for (i = 0; i < len; i++) {
22009 printf("%4d %s\n", i + 1, history[i]);
22010 }
22011 #endif
22012 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
22013
22014 int Jim_InteractivePrompt(Jim_Interp *interp)
22015 {
22016 int retcode = JIM_OK;
22017 char *history_file = NULL;
@@ -22023,10 +22296,12 @@
22023 int history_len = strlen(home) + sizeof("/.jim_history");
22024 history_file = Jim_Alloc(history_len);
22025 snprintf(history_file, history_len, "%s/.jim_history", home);
22026 Jim_HistoryLoad(history_file);
22027 }
 
 
22028 #endif
22029
22030 printf("Welcome to Jim version %d.%d\n",
22031 JIM_VERSION / 100, JIM_VERSION % 100);
22032 Jim_SetVariableStrWithStr(interp, JIM_INTERACTIVE, "1");
@@ -22055,21 +22330,21 @@
22055 Jim_IncrRefCount(scriptObjPtr);
22056 while (1) {
22057 char state;
22058 char *line;
22059
22060 line = Jim_HistoryGetline(prompt);
22061 if (line == NULL) {
22062 if (errno == EINTR) {
22063 continue;
22064 }
22065 Jim_DecrRefCount(interp, scriptObjPtr);
22066 retcode = JIM_OK;
22067 goto out;
22068 }
22069 if (Jim_Length(scriptObjPtr) != 0) {
22070
22071 Jim_AppendString(interp, scriptObjPtr, "\n", 1);
22072 }
22073 Jim_AppendString(interp, scriptObjPtr, line, -1);
22074 free(line);
22075 if (Jim_ScriptIsComplete(interp, scriptObjPtr, &state))
@@ -22077,11 +22352,11 @@
22077
22078 snprintf(prompt, sizeof(prompt), "%c> ", state);
22079 }
22080 #ifdef USE_LINENOISE
22081 if (strcmp(Jim_String(scriptObjPtr), "h") == 0) {
22082
22083 Jim_HistoryShow();
22084 Jim_DecrRefCount(interp, scriptObjPtr);
22085 continue;
22086 }
22087
@@ -22104,10 +22379,11 @@
22104 printf("%s\n", result);
22105 }
22106 }
22107 out:
22108 Jim_Free(history_file);
 
22109 return retcode;
22110 }
22111
22112 #include <stdio.h>
22113 #include <stdlib.h>
@@ -22120,11 +22396,11 @@
22120 static void JimSetArgv(Jim_Interp *interp, int argc, char *const argv[])
22121 {
22122 int n;
22123 Jim_Obj *listObj = Jim_NewListObj(interp, NULL, 0);
22124
22125
22126 for (n = 0; n < argc; n++) {
22127 Jim_Obj *obj = Jim_NewStringObj(interp, argv[n], -1);
22128
22129 Jim_ListAppendElement(interp, listObj, obj);
22130 }
@@ -22146,71 +22422,75 @@
22146 printf("or : %s [options] [filename]\n", executable_name);
22147 printf("\n");
22148 printf("Without options: Interactive mode\n");
22149 printf("\n");
22150 printf("Options:\n");
22151 printf(" --version : prints the version string\n");
22152 printf(" --help : prints this text\n");
22153 printf(" -e CMD : executes command CMD\n");
22154 printf(" NOTE: all subsequent options will be passed as arguments to the command\n");
22155 printf(" [filename] : executes the script contained in the named file\n");
22156 printf(" NOTE: all subsequent options will be passed to the script\n\n");
22157 }
22158
22159 int main(int argc, char *const argv[])
22160 {
22161 int retcode;
22162 Jim_Interp *interp;
22163 char *const orig_argv0 = argv[0];
22164
22165
22166 if (argc > 1 && strcmp(argv[1], "--version") == 0) {
22167 printf("%d.%d\n", JIM_VERSION / 100, JIM_VERSION % 100);
22168 return 0;
22169 }
22170 else if (argc > 1 && strcmp(argv[1], "--help") == 0) {
22171 usage(argv[0]);
22172 return 0;
22173 }
22174
22175
22176 interp = Jim_CreateInterp();
22177 Jim_RegisterCoreCommands(interp);
22178
22179
22180 if (Jim_InitStaticExtensions(interp) != JIM_OK) {
22181 JimPrintErrorMessage(interp);
22182 }
22183
22184 Jim_SetVariableStrWithStr(interp, "jim::argv0", orig_argv0);
22185 Jim_SetVariableStrWithStr(interp, JIM_INTERACTIVE, argc == 1 ? "1" : "0");
22186 retcode = Jim_initjimshInit(interp);
22187
22188 if (argc == 1) {
22189
22190 if (retcode == JIM_ERR) {
22191 JimPrintErrorMessage(interp);
22192 }
22193 if (retcode != JIM_EXIT) {
22194 JimSetArgv(interp, 0, NULL);
22195 retcode = Jim_InteractivePrompt(interp);
22196 }
22197 }
22198 else {
22199
22200 if (argc > 2 && strcmp(argv[1], "-e") == 0) {
22201
22202 JimSetArgv(interp, argc - 3, argv + 3);
22203 retcode = Jim_Eval(interp, argv[2]);
22204 if (retcode != JIM_ERR) {
22205 printf("%s\n", Jim_String(Jim_GetResult(interp)));
22206 }
22207 }
22208 else {
22209 Jim_SetVariableStr(interp, "argv0", Jim_NewStringObj(interp, argv[1], -1));
22210 JimSetArgv(interp, argc - 2, argv + 2);
22211 retcode = Jim_EvalFile(interp, argv[1]);
 
 
 
 
22212 }
22213 if (retcode == JIM_ERR) {
22214 JimPrintErrorMessage(interp);
22215 }
22216 }
22217
--- autosetup/jimsh0.c
+++ autosetup/jimsh0.c
@@ -1,9 +1,7 @@
1 /* This is single source file, bootstrap version of Jim Tcl. See http://jim.tcl.tk/ */
 
2 #define JIM_TCL_COMPAT
 
3 #define JIM_ANSIC
4 #define JIM_REGEXP
5 #define HAVE_NO_AUTOCONF
6 #define _JIMAUTOCONF_H
7 #define TCL_LIBRARY "."
@@ -31,24 +29,39 @@
29 #define HAVE_MKDIR_ONE_ARG
30 #define HAVE_SYSTEM
31 #define HAVE_SYS_TIME_H
32 #define HAVE_DIRENT_H
33 #define HAVE_UNISTD_H
34 #define HAVE_UMASK
35 #include <sys/stat.h>
36 #ifndef S_IRWXG
37 #define S_IRWXG 0
38 #endif
39 #ifndef S_IRWXO
40 #define S_IRWXO 0
41 #endif
42 #else
43 #define TCL_PLATFORM_OS "unknown"
44 #define TCL_PLATFORM_PLATFORM "unix"
45 #define TCL_PLATFORM_PATH_SEPARATOR ":"
46 #ifdef _MINIX
47 #define vfork fork
48 #define _POSIX_SOURCE
49 #else
50 #define _GNU_SOURCE
51 #endif
52 #define HAVE_VFORK
53 #define HAVE_WAITPID
54 #define HAVE_ISATTY
55 #define HAVE_MKSTEMP
56 #define HAVE_LINK
57 #define HAVE_SYS_TIME_H
58 #define HAVE_DIRENT_H
59 #define HAVE_UNISTD_H
60 #define HAVE_UMASK
61 #endif
62 #define JIM_VERSION 78
63 #ifndef JIM_WIN32COMPAT_H
64 #define JIM_WIN32COMPAT_H
65
66
67
@@ -88,11 +101,10 @@
101 #define JIM_WIDE_MIN LLONG_MIN
102 #define JIM_WIDE_MAX LLONG_MAX
103 #define JIM_WIDE_MODIFIER "I64d"
104 #define strcasecmp _stricmp
105 #define strtoull _strtoui64
 
106
107 #include <io.h>
108
109 struct timeval {
110 long tv_sec;
@@ -105,29 +117,24 @@
117 struct dirent {
118 char *d_name;
119 };
120
121 typedef struct DIR {
122 long handle;
123 struct _finddata_t info;
124 struct dirent result;
125 char *name;
126 } DIR;
127
128 DIR *opendir(const char *name);
129 int closedir(DIR *dir);
130 struct dirent *readdir(DIR *dir);
131
132 #endif
 
 
 
133
134 #endif
135
 
 
136 #ifdef __cplusplus
137 }
138 #endif
139
140 #endif
@@ -146,19 +153,21 @@
153
154 #ifndef JIM_UTF8
155 #include <ctype.h>
156
157
158 #define utf8_strlen(S, B) ((B) < 0 ? (int)strlen(S) : (B))
159 #define utf8_strwidth(S, B) utf8_strlen((S), (B))
160 #define utf8_tounicode(S, CP) (*(CP) = (unsigned char)*(S), 1)
161 #define utf8_getchars(CP, C) (*(CP) = (C), 1)
162 #define utf8_upper(C) toupper(C)
163 #define utf8_title(C) toupper(C)
164 #define utf8_lower(C) tolower(C)
165 #define utf8_index(C, I) (I)
166 #define utf8_charlen(C) 1
167 #define utf8_prev_len(S, L) 1
168 #define utf8_width(C) 1
169
170 #else
171
172 #endif
173
@@ -175,13 +184,13 @@
184 extern "C" {
185 #endif
186
187 #include <time.h>
188 #include <limits.h>
189 #include <stdio.h>
190 #include <stdlib.h>
191 #include <stdarg.h>
192
193
194 #ifndef HAVE_NO_AUTOCONF
195 #endif
196
@@ -224,31 +233,31 @@
233 #define JIM_SIGNAL 5
234 #define JIM_EXIT 6
235
236 #define JIM_EVAL 7
237
238 #define JIM_MAX_CALLFRAME_DEPTH 1000
239 #define JIM_MAX_EVAL_DEPTH 2000
240
241
242 #define JIM_PRIV_FLAG_SHIFT 20
243
244 #define JIM_NONE 0
245 #define JIM_ERRMSG 1
246 #define JIM_ENUM_ABBREV 2
247 #define JIM_UNSHARED 4
248 #define JIM_MUSTEXIST 8
249
250
251 #define JIM_SUBST_NOVAR 1
252 #define JIM_SUBST_NOCMD 2
253 #define JIM_SUBST_NOESC 4
254 #define JIM_SUBST_FLAG 128
255
256
257 #define JIM_CASESENS 0
258 #define JIM_NOCASE 1
259
260
261 #define JIM_PATH_LEN 1024
262
263
@@ -339,79 +348,80 @@
348 #define Jim_GetHashTableSize(ht) ((ht)->size)
349 #define Jim_GetHashTableUsed(ht) ((ht)->used)
350
351
352 typedef struct Jim_Obj {
353 char *bytes;
354 const struct Jim_ObjType *typePtr;
355 int refCount;
356 int length;
357
358 union {
359
360 jim_wide wideValue;
361
362 int intValue;
363
364 double doubleValue;
365
366 void *ptr;
367
368 struct {
369 void *ptr1;
370 void *ptr2;
371 } twoPtrValue;
372
373 struct {
374 void *ptr;
375 int int1;
376 int int2;
377 } ptrIntValue;
378
379 struct {
380 struct Jim_Var *varPtr;
381 unsigned long callFrameId;
382 int global;
383 } varValue;
384
385 struct {
386 struct Jim_Obj *nsObj;
387 struct Jim_Cmd *cmdPtr;
388 unsigned long procEpoch;
389 } cmdValue;
390
391 struct {
392 struct Jim_Obj **ele;
393 int len;
394 int maxLen;
395 } listValue;
396
397 struct {
398 int maxLength;
399 int charLength;
400 } strValue;
401
402 struct {
403 unsigned long id;
404 struct Jim_Reference *refPtr;
405 } refValue;
406
407 struct {
408 struct Jim_Obj *fileNameObj;
409 int lineNumber;
410 } sourceValue;
411
412 struct {
413 struct Jim_Obj *varNameObjPtr;
414 struct Jim_Obj *indexObjPtr;
415 } dictSubstValue;
 
 
 
 
 
416 struct {
417 int line;
418 int argc;
419 } scriptLineValue;
420 } internalRep;
421 struct Jim_Obj *prevObjPtr;
422 struct Jim_Obj *nextObjPtr;
423 } Jim_Obj;
424
425
426 #define Jim_IncrRefCount(objPtr) \
427 ++(objPtr)->refCount
@@ -442,40 +452,40 @@
452 typedef void (Jim_DupInternalRepProc)(struct Jim_Interp *interp,
453 struct Jim_Obj *srcPtr, Jim_Obj *dupPtr);
454 typedef void (Jim_UpdateStringProc)(struct Jim_Obj *objPtr);
455
456 typedef struct Jim_ObjType {
457 const char *name;
458 Jim_FreeInternalRepProc *freeIntRepProc;
459 Jim_DupInternalRepProc *dupIntRepProc;
460 Jim_UpdateStringProc *updateStringProc;
461 int flags;
462 } Jim_ObjType;
463
464
465 #define JIM_TYPE_NONE 0
466 #define JIM_TYPE_REFERENCES 1
467
468
469
470 typedef struct Jim_CallFrame {
471 unsigned long id;
472 int level;
473 struct Jim_HashTable vars;
474 struct Jim_HashTable *staticVars;
475 struct Jim_CallFrame *parent;
476 Jim_Obj *const *argv;
477 int argc;
478 Jim_Obj *procArgsObjPtr;
479 Jim_Obj *procBodyObjPtr;
480 struct Jim_CallFrame *next;
481 Jim_Obj *nsObj;
482 Jim_Obj *fileNameObj;
483 int line;
484 Jim_Stack *localCommands;
485 struct Jim_Obj *tailcallObj;
486 struct Jim_Cmd *tailcallCmd;
487 } Jim_CallFrame;
488
489 typedef struct Jim_Var {
490 Jim_Obj *objPtr;
491 struct Jim_CallFrame *linkFramePtr;
@@ -487,35 +497,35 @@
497 typedef void Jim_DelCmdProc(struct Jim_Interp *interp, void *privData);
498
499
500
501 typedef struct Jim_Cmd {
502 int inUse;
503 int isproc;
504 struct Jim_Cmd *prevCmd;
505 union {
506 struct {
507
508 Jim_CmdProc *cmdProc;
509 Jim_DelCmdProc *delProc;
510 void *privData;
511 } native;
512 struct {
513
514 Jim_Obj *argListObjPtr;
515 Jim_Obj *bodyObjPtr;
516 Jim_HashTable *staticVars;
517 int argListLen;
518 int reqArity;
519 int optArity;
520 int argsPos;
521 int upcall;
522 struct Jim_ProcArg {
523 Jim_Obj *nameObjPtr;
524 Jim_Obj *defaultObjPtr;
525 } *arglist;
526 Jim_Obj *nsObj;
527 } proc;
528 } u;
529 } Jim_Cmd;
530
531
@@ -523,64 +533,64 @@
533 unsigned char sbox[256];
534 unsigned int i, j;
535 } Jim_PrngState;
536
537 typedef struct Jim_Interp {
538 Jim_Obj *result;
539 int errorLine;
540 Jim_Obj *errorFileNameObj;
541 int addStackTrace;
542 int maxCallFrameDepth;
543 int maxEvalDepth;
544 int evalDepth;
545 int returnCode;
546 int returnLevel;
547 int exitCode;
548 long id;
549 int signal_level;
550 jim_wide sigmask;
551 int (*signal_set_result)(struct Jim_Interp *interp, jim_wide sigmask);
552 Jim_CallFrame *framePtr;
553 Jim_CallFrame *topFramePtr;
554 struct Jim_HashTable commands;
555 unsigned long procEpoch; /* Incremented every time the result
556 of procedures names lookup caching
557 may no longer be valid. */
558 unsigned long callFrameEpoch; /* Incremented every time a new
559 callframe is created. This id is used for the
560 'ID' field contained in the Jim_CallFrame
561 structure. */
562 int local;
563 Jim_Obj *liveList;
564 Jim_Obj *freeList;
565 Jim_Obj *currentScriptObj;
566 Jim_Obj *nullScriptObj;
567 Jim_Obj *emptyObj;
568 Jim_Obj *trueObj;
569 Jim_Obj *falseObj;
570 unsigned long referenceNextId;
571 struct Jim_HashTable references;
572 unsigned long lastCollectId; /* reference max Id of the last GC
573 execution. It's set to ~0 while the collection
574 is running as sentinel to avoid to recursive
575 calls via the [collect] command inside
576 finalizers. */
577 time_t lastCollectTime;
578 Jim_Obj *stackTrace;
579 Jim_Obj *errorProc;
580 Jim_Obj *unknown;
581 int unknown_called;
582 int errorFlag;
583 void *cmdPrivData; /* Used to pass the private data pointer to
584 a command. It is set to what the user specified
585 via Jim_CreateCommand(). */
586
587 struct Jim_CallFrame *freeFramesList;
588 struct Jim_HashTable assocData;
589 Jim_PrngState *prngState;
590 struct Jim_HashTable packages;
591 Jim_Stack *loadHandles;
592 } Jim_Interp;
593
594 #define Jim_InterpIncrProcEpoch(i) (i)->procEpoch++
595 #define Jim_SetResultString(i,s,l) Jim_SetResult(i, Jim_NewStringObj(i,s,l))
596 #define Jim_SetResultInt(i,intval) Jim_SetResult(i, Jim_NewIntObj(i,intval))
@@ -623,11 +633,11 @@
633 JIM_EXPORT char *Jim_StrDupLen(const char *s, int l);
634
635
636 JIM_EXPORT char **Jim_GetEnviron(void);
637 JIM_EXPORT void Jim_SetEnviron(char **env);
638 JIM_EXPORT int Jim_MakeTempFile(Jim_Interp *interp, const char *filename_template, int unlink_file);
639
640
641 JIM_EXPORT int Jim_Eval(Jim_Interp *interp, const char *script);
642
643
@@ -816,25 +826,33 @@
826 Jim_Obj *newObjPtr, int flags);
827 JIM_EXPORT int Jim_DictPairs(Jim_Interp *interp,
828 Jim_Obj *dictPtr, Jim_Obj ***objPtrPtr, int *len);
829 JIM_EXPORT int Jim_DictAddElement(Jim_Interp *interp, Jim_Obj *objPtr,
830 Jim_Obj *keyObjPtr, Jim_Obj *valueObjPtr);
831
832 #define JIM_DICTMATCH_KEYS 0x0001
833 #define JIM_DICTMATCH_VALUES 0x002
834
835 JIM_EXPORT int Jim_DictMatchTypes(Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj *patternObj, int match_type, int return_types);
836 JIM_EXPORT int Jim_DictSize(Jim_Interp *interp, Jim_Obj *objPtr);
837 JIM_EXPORT int Jim_DictInfo(Jim_Interp *interp, Jim_Obj *objPtr);
838 JIM_EXPORT Jim_Obj *Jim_DictMerge(Jim_Interp *interp, int objc, Jim_Obj *const *objv);
839
840
841 JIM_EXPORT int Jim_GetReturnCode (Jim_Interp *interp, Jim_Obj *objPtr,
842 int *intPtr);
843
844
845 JIM_EXPORT int Jim_EvalExpression (Jim_Interp *interp,
846 Jim_Obj *exprObjPtr);
847 JIM_EXPORT int Jim_GetBoolFromExpr (Jim_Interp *interp,
848 Jim_Obj *exprObjPtr, int *boolPtr);
849
850
851 JIM_EXPORT int Jim_GetBoolean(Jim_Interp *interp, Jim_Obj *objPtr,
852 int *booleanPtr);
853
854
855 JIM_EXPORT int Jim_GetWide (Jim_Interp *interp, Jim_Obj *objPtr,
856 jim_wide *widePtr);
857 JIM_EXPORT int Jim_GetLong (Jim_Interp *interp, Jim_Obj *objPtr,
858 long *longPtr);
@@ -852,10 +870,12 @@
870
871 JIM_EXPORT void Jim_WrongNumArgs (Jim_Interp *interp, int argc,
872 Jim_Obj *const *argv, const char *msg);
873 JIM_EXPORT int Jim_GetEnum (Jim_Interp *interp, Jim_Obj *objPtr,
874 const char * const *tablePtr, int *indexPtr, const char *name, int flags);
875 JIM_EXPORT int Jim_CheckShowCommands(Jim_Interp *interp, Jim_Obj *objPtr,
876 const char *const *tablePtr);
877 JIM_EXPORT int Jim_ScriptIsComplete(Jim_Interp *interp,
878 Jim_Obj *scriptObj, char *stateCharPtr);
879
880 JIM_EXPORT int Jim_FindByName(const char *name, const char * const array[], size_t len);
881
@@ -878,11 +898,12 @@
898
899
900 JIM_EXPORT int Jim_InteractivePrompt (Jim_Interp *interp);
901 JIM_EXPORT void Jim_HistoryLoad(const char *filename);
902 JIM_EXPORT void Jim_HistorySave(const char *filename);
903 JIM_EXPORT char *Jim_HistoryGetline(Jim_Interp *interp, const char *prompt);
904 JIM_EXPORT void Jim_HistorySetCompletion(Jim_Interp *interp, Jim_Obj *commandObj);
905 JIM_EXPORT void Jim_HistoryAdd(const char *line);
906 JIM_EXPORT void Jim_HistoryShow(void);
907
908
909 JIM_EXPORT int Jim_InitStaticExtensions(Jim_Interp *interp);
@@ -904,11 +925,11 @@
925
926 #ifdef __cplusplus
927 }
928 #endif
929
930 #endif
931
932 #ifndef JIM_SUBCMD_H
933 #define JIM_SUBCMD_H
934
935
@@ -915,24 +936,24 @@
936 #ifdef __cplusplus
937 extern "C" {
938 #endif
939
940
941 #define JIM_MODFLAG_HIDDEN 0x0001
942 #define JIM_MODFLAG_FULLARGV 0x0002
943
944
945
946 typedef int jim_subcmd_function(Jim_Interp *interp, int argc, Jim_Obj *const *argv);
947
948 typedef struct {
949 const char *cmd;
950 const char *args;
951 jim_subcmd_function *function;
952 short minargs;
953 short maxargs;
954 unsigned short flags;
955 } jim_subcmd_type;
956
957 const jim_subcmd_type *
958 Jim_ParseSubCmd(Jim_Interp *interp, const jim_subcmd_type *command_table, int argc, Jim_Obj *const *argv);
959
@@ -960,36 +981,36 @@
981 int rm_eo;
982 } regmatch_t;
983
984
985 typedef struct regexp {
986
987 int re_nsub;
988
989
990 int cflags;
991 int err;
992 int regstart;
993 int reganch;
994 int regmust;
995 int regmlen;
996 int *program;
997
998
999 const char *regparse;
1000 int p;
1001 int proglen;
1002
1003
1004 int eflags;
1005 const char *start;
1006 const char *reginput;
1007 const char *regbol;
1008
1009
1010 regmatch_t *pmatch;
1011 int nmatch;
1012 } regexp;
1013
1014 typedef regexp regex_t;
1015
1016 #define REG_EXTENDED 0
@@ -997,13 +1018,13 @@
1018 #define REG_ICASE 2
1019
1020 #define REG_NOTBOL 16
1021
1022 enum {
1023 REG_NOERROR,
1024 REG_NOMATCH,
1025 REG_BADPAT,
1026 REG_ERR_NULL_ARGUMENT,
1027 REG_ERR_UNKNOWN,
1028 REG_ERR_TOO_BIG,
1029 REG_ERR_NOMEM,
1030 REG_ERR_TOO_MANY_PAREN,
@@ -1028,24 +1049,101 @@
1049
1050 #ifdef __cplusplus
1051 }
1052 #endif
1053
1054 #endif
1055 #ifndef JIM_SIGNAL_H
1056 #define JIM_SIGNAL_H
1057
1058 #ifdef __cplusplus
1059 extern "C" {
1060 #endif
1061
1062 const char *Jim_SignalId(int sig);
1063
1064 #ifdef __cplusplus
1065 }
1066 #endif
1067
1068 #endif
1069 #ifndef JIMIOCOMPAT_H
1070 #define JIMIOCOMPAT_H
1071
1072
1073 #include <stdio.h>
1074 #include <errno.h>
1075
1076
1077 void Jim_SetResultErrno(Jim_Interp *interp, const char *msg);
1078
1079 int Jim_OpenForWrite(const char *filename, int append);
1080
1081 int Jim_OpenForRead(const char *filename);
1082
1083 #if defined(__MINGW32__)
1084 #ifndef STRICT
1085 #define STRICT
1086 #endif
1087 #define WIN32_LEAN_AND_MEAN
1088 #include <windows.h>
1089 #include <fcntl.h>
1090 #include <io.h>
1091 #include <process.h>
1092
1093 typedef HANDLE pidtype;
1094 #define JIM_BAD_PID INVALID_HANDLE_VALUE
1095
1096 #define JIM_NO_PID INVALID_HANDLE_VALUE
1097
1098
1099 #define WIFEXITED(STATUS) (((STATUS) & 0xff00) == 0)
1100 #define WEXITSTATUS(STATUS) ((STATUS) & 0x00ff)
1101 #define WIFSIGNALED(STATUS) (((STATUS) & 0xff00) != 0)
1102 #define WTERMSIG(STATUS) (((STATUS) >> 8) & 0xff)
1103 #define WNOHANG 1
1104
1105 int Jim_Errno(void);
1106 pidtype waitpid(pidtype pid, int *status, int nohang);
1107
1108 #define HAVE_PIPE
1109 #define pipe(P) _pipe((P), 0, O_NOINHERIT)
1110
1111 #elif defined(HAVE_UNISTD_H)
1112 #include <unistd.h>
1113 #include <fcntl.h>
1114 #include <sys/wait.h>
1115 #include <sys/stat.h>
1116
1117 typedef int pidtype;
1118 #define Jim_Errno() errno
1119 #define JIM_BAD_PID -1
1120 #define JIM_NO_PID 0
1121
1122 #ifndef HAVE_EXECVPE
1123 #define execvpe(ARG0, ARGV, ENV) execvp(ARG0, ARGV)
1124 #endif
1125 #endif
1126
1127 #endif
1128 int Jim_bootstrapInit(Jim_Interp *interp)
1129 {
1130 if (Jim_PackageProvide(interp, "bootstrap", "1.0", JIM_ERRMSG))
1131 return JIM_ERR;
1132
1133 return Jim_EvalSource(interp, "bootstrap.tcl", 1,
1134 "\n"
1135 "\n"
1136 "proc package {cmd pkg args} {\n"
1137 " if {$cmd eq \"require\"} {\n"
1138 " foreach path $::auto_path {\n"
1139 " set pkgpath $path/$pkg.tcl\n"
1140 " if {$path eq \".\"} {\n"
1141 " set pkgpath $pkg.tcl\n"
1142 " }\n"
1143 " if {[file exists $pkgpath]} {\n"
1144 " uplevel #0 [list source $pkgpath]\n"
1145 " return\n"
1146 " }\n"
1147 " }\n"
1148 " }\n"
1149 "}\n"
@@ -1100,10 +1198,43 @@
1198 "\n"
1199 "if {$tcl_platform(platform) eq \"windows\"} {\n"
1200 " set jim::argv0 [string map {\\\\ /} $jim::argv0]\n"
1201 "}\n"
1202 "\n"
1203 "\n"
1204 "set tcl::autocomplete_commands {info tcl::prefix socket namespace array clock file package string dict signal history}\n"
1205 "\n"
1206 "\n"
1207 "\n"
1208 "proc tcl::autocomplete {prefix} {\n"
1209 " if {[set space [string first \" \" $prefix]] != -1} {\n"
1210 " set cmd [string range $prefix 0 $space-1]\n"
1211 " if {$cmd in $::tcl::autocomplete_commands || [info channel $cmd] ne \"\"} {\n"
1212 " set arg [string range $prefix $space+1 end]\n"
1213 "\n"
1214 " return [lmap p [$cmd -commands] {\n"
1215 " if {![string match \"${arg}*\" $p]} continue\n"
1216 " function \"$cmd $p\"\n"
1217 " }]\n"
1218 " }\n"
1219 " }\n"
1220 "\n"
1221 " if {[string match \"source *\" $prefix]} {\n"
1222 " set path [string range $prefix 7 end]\n"
1223 " return [lmap p [glob -nocomplain \"${path}*\"] {\n"
1224 " function \"source $p\"\n"
1225 " }]\n"
1226 " }\n"
1227 "\n"
1228 " return [lmap p [lsort [info commands $prefix*]] {\n"
1229 " if {[string match \"* *\" $p]} {\n"
1230 " continue\n"
1231 " }\n"
1232 " function $p\n"
1233 " }]\n"
1234 "}\n"
1235 "\n"
1236 "_jimsh_init\n"
1237 );
1238 }
1239 int Jim_globInit(Jim_Interp *interp)
1240 {
@@ -1315,10 +1446,17 @@
1446 return JIM_ERR;
1447
1448 return Jim_EvalSource(interp, "stdlib.tcl", 1,
1449 "\n"
1450 "\n"
1451 "if {![exists -command ref]} {\n"
1452 "\n"
1453 " proc ref {args} {{count 0}} {\n"
1454 " format %08x [incr count]\n"
1455 " }\n"
1456 "}\n"
1457 "\n"
1458 "\n"
1459 "proc lambda {arglist args} {\n"
1460 " tailcall proc [ref {} function lambda.finalizer] $arglist {*}$args\n"
1461 "}\n"
1462 "\n"
@@ -1375,10 +1513,17 @@
1513 " }\n"
1514 " join $lines \\n\n"
1515 "}\n"
1516 "\n"
1517 "\n"
1518 "\n"
1519 "proc defer {script} {\n"
1520 " upvar jim::defer v\n"
1521 " lappend v $script\n"
1522 "}\n"
1523 "\n"
1524 "\n"
1525 "\n"
1526 "proc errorInfo {msg {stacktrace \"\"}} {\n"
1527 " if {$stacktrace eq \"\"} {\n"
1528 "\n"
1529 " set stacktrace [info stacktrace]\n"
@@ -1402,31 +1547,10 @@
1547 " if {[exists ::jim::exe]} {\n"
1548 " return $::jim::exe\n"
1549 " }\n"
1550 "}\n"
1551 "\n"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1552 "\n"
1553 "proc {dict update} {&varName args script} {\n"
1554 " set keys {}\n"
1555 " foreach {n v} $args {\n"
1556 " upvar $v var_$v\n"
@@ -1445,23 +1569,10 @@
1569 " }\n"
1570 " }\n"
1571 " return {*}$opts $msg\n"
1572 "}\n"
1573 "\n"
 
 
 
 
 
 
 
 
 
 
 
 
 
1574 "proc {dict replace} {dictionary {args {key value}}} {\n"
1575 " if {[llength ${key value}] % 2} {\n"
1576 " tailcall {dict replace}\n"
1577 " }\n"
1578 " tailcall dict merge $dictionary ${key value}\n"
@@ -1503,15 +1614,10 @@
1614 " dict unset dictionary $k\n"
1615 " }\n"
1616 " return $dictionary\n"
1617 "}\n"
1618 "\n"
 
 
 
 
 
1619 "\n"
1620 "proc {dict for} {vars dictionary script} {\n"
1621 " if {[llength $vars] != 2} {\n"
1622 " return -code error \"must have exactly two variable names\"\n"
1623 " }\n"
@@ -1591,11 +1697,10 @@
1697 " tailcall {*}$args\n"
1698 "}\n"
1699 "\n"
1700 "\n"
1701 "\n"
 
1702 "proc parray {arrayname {pattern *} {puts puts}} {\n"
1703 " upvar $arrayname a\n"
1704 "\n"
1705 " set max 0\n"
1706 " foreach name [array names a $pattern]] {\n"
@@ -1647,11 +1752,11 @@
1752 "}\n"
1753 "\n"
1754 "\n"
1755 "\n"
1756 "proc popen {cmd {mode r}} {\n"
1757 " lassign [pipe] r w\n"
1758 " try {\n"
1759 " if {[string match \"w*\" $mode]} {\n"
1760 " lappend cmd <@$r &\n"
1761 " set pids [exec {*}$cmd]\n"
1762 " $r close\n"
@@ -1663,16 +1768,31 @@
1768 " set f $r\n"
1769 " }\n"
1770 " lambda {cmd args} {f pids} {\n"
1771 " if {$cmd eq \"pid\"} {\n"
1772 " return $pids\n"
1773 " }\n"
1774 " if {$cmd eq \"getfd\"} {\n"
1775 " $f getfd\n"
1776 " }\n"
1777 " if {$cmd eq \"close\"} {\n"
1778 " $f close\n"
1779 "\n"
1780 " set retopts {}\n"
1781 " foreach p $pids {\n"
1782 " lassign [wait $p] status - rc\n"
1783 " if {$status eq \"CHILDSTATUS\"} {\n"
1784 " if {$rc == 0} {\n"
1785 " continue\n"
1786 " }\n"
1787 " set msg \"child process exited abnormally\"\n"
1788 " } else {\n"
1789 " set msg \"child killed: received signal\"\n"
1790 " }\n"
1791 " set retopts [list -code error -errorcode [list $status $p $rc] $msg]\n"
1792 " }\n"
1793 " return {*}$retopts\n"
1794 " }\n"
1795 " tailcall $f $cmd {*}$args\n"
1796 " }\n"
1797 " } on error {error opts} {\n"
1798 " $r close\n"
@@ -1692,14 +1812,10 @@
1812 " if {[catch {$channelId pid} pids]} {\n"
1813 " return \"\"\n"
1814 " }\n"
1815 " return $pids\n"
1816 "}\n"
 
 
 
 
1817 "\n"
1818 "\n"
1819 "\n"
1820 "\n"
1821 "\n"
@@ -1780,10 +1896,13 @@
1896 "}\n"
1897 );
1898 }
1899
1900
1901 #ifndef _GNU_SOURCE
1902 #define _GNU_SOURCE
1903 #endif
1904 #include <stdio.h>
1905 #include <string.h>
1906 #include <errno.h>
1907 #include <fcntl.h>
1908 #ifdef HAVE_UNISTD_H
@@ -1793,27 +1912,34 @@
1912
1913
1914 #if defined(HAVE_SYS_SOCKET_H) && defined(HAVE_SELECT) && defined(HAVE_NETINET_IN_H) && defined(HAVE_NETDB_H) && defined(HAVE_ARPA_INET_H)
1915 #include <sys/socket.h>
1916 #include <netinet/in.h>
1917 #include <netinet/tcp.h>
1918 #include <arpa/inet.h>
1919 #include <netdb.h>
1920 #ifdef HAVE_SYS_UN_H
1921 #include <sys/un.h>
1922 #endif
1923 #define HAVE_SOCKETS
1924 #elif defined (__MINGW32__)
1925
1926 #else
1927 #define JIM_ANSIC
1928 #endif
1929
1930 #if defined(JIM_SSL)
1931 #include <openssl/ssl.h>
1932 #include <openssl/err.h>
1933 #endif
1934
1935 #ifdef HAVE_TERMIOS_H
1936 #endif
1937
1938
1939 #define AIO_CMD_LEN 32
1940 #define AIO_BUF_LEN 256
1941
1942 #ifndef HAVE_FTELLO
1943 #define ftello ftell
1944 #endif
1945 #ifndef HAVE_FSEEKO
@@ -1829,11 +1955,15 @@
1955 #ifndef PF_INET6
1956 #define PF_INET6 0
1957 #endif
1958 #endif
1959
1960 #ifdef JIM_ANSIC
1961
1962 #undef HAVE_PIPE
1963 #undef HAVE_SOCKETPAIR
1964 #endif
1965
1966
1967 struct AioFile;
1968
1969 typedef struct {
@@ -1848,11 +1978,11 @@
1978 typedef struct AioFile
1979 {
1980 FILE *fp;
1981 Jim_Obj *filename;
1982 int type;
1983 int openFlags;
1984 int fd;
1985 Jim_Obj *rEvent;
1986 Jim_Obj *wEvent;
1987 Jim_Obj *eEvent;
1988 int addr_family;
@@ -1879,21 +2009,21 @@
2009 {
2010 if (!ferror(af->fp)) {
2011 return JIM_OK;
2012 }
2013 clearerr(af->fp);
2014
2015 if (feof(af->fp) || errno == EAGAIN || errno == EINTR) {
2016 return JIM_OK;
2017 }
2018 #ifdef ECONNRESET
2019 if (errno == ECONNRESET) {
2020 return JIM_OK;
2021 }
2022 #endif
2023 #ifdef ECONNABORTED
2024 if (errno == ECONNABORTED) {
2025 return JIM_OK;
2026 }
2027 #endif
2028 return JIM_ERR;
2029 }
@@ -1935,10 +2065,19 @@
2065 }
2066 else {
2067 Jim_SetResultString(interp, JimAioErrorString(af), -1);
2068 }
2069 }
2070
2071 static int JimCheckStreamError(Jim_Interp *interp, AioFile *af)
2072 {
2073 int ret = af->fops->error(af);
2074 if (ret) {
2075 JimAioSetError(interp, af->filename);
2076 }
2077 return ret;
2078 }
2079
2080 static void JimAioDelProc(Jim_Interp *interp, void *privData)
2081 {
2082 AioFile *af = privData;
2083
@@ -1945,20 +2084,19 @@
2084 JIM_NOTUSED(interp);
2085
2086 Jim_DecrRefCount(interp, af->filename);
2087
2088 #ifdef jim_ext_eventloop
2089
2090 Jim_DeleteFileHandler(interp, af->fd, JIM_EVENT_READABLE | JIM_EVENT_WRITABLE | JIM_EVENT_EXCEPTION);
2091 #endif
2092
2093 #if defined(JIM_SSL)
2094 if (af->ssl != NULL) {
2095 SSL_free(af->ssl);
2096 }
2097 #endif
 
2098 if (!(af->openFlags & AIO_KEEPOPEN)) {
2099 fclose(af->fp);
2100 }
2101
2102 Jim_Free(af);
@@ -1968,11 +2106,11 @@
2106 {
2107 AioFile *af = Jim_CmdPrivData(interp);
2108 char buf[AIO_BUF_LEN];
2109 Jim_Obj *objPtr;
2110 int nonewline = 0;
2111 jim_wide neededLen = -1;
2112
2113 if (argc && Jim_CompareStringImmediate(interp, argv[0], "-nonewline")) {
2114 nonewline = 1;
2115 argv++;
2116 argc--;
@@ -2007,11 +2145,11 @@
2145 }
2146 }
2147 if (retval != readlen)
2148 break;
2149 }
2150
2151 if (JimCheckStreamError(interp, af)) {
2152 Jim_FreeNewObj(interp, objPtr);
2153 return JIM_ERR;
2154 }
2155 if (nonewline) {
@@ -2029,11 +2167,11 @@
2167
2168 AioFile *Jim_AioFile(Jim_Interp *interp, Jim_Obj *command)
2169 {
2170 Jim_Cmd *cmdPtr = Jim_GetCommand(interp, command, JIM_ERRMSG);
2171
2172
2173 if (cmdPtr && !cmdPtr->isproc && cmdPtr->u.native.cmdProc == JimAioSubCmdProc) {
2174 return (AioFile *) cmdPtr->u.native.privData;
2175 }
2176 Jim_SetResultFormatted(interp, "Not a filehandle: \"%#s\"", command);
2177 return NULL;
@@ -2048,10 +2186,20 @@
2186 return NULL;
2187 }
2188
2189 return af->fp;
2190 }
2191
2192 static int aio_cmd_getfd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
2193 {
2194 AioFile *af = Jim_CmdPrivData(interp);
2195
2196 fflush(af->fp);
2197 Jim_SetResultInt(interp, fileno(af->fp));
2198
2199 return JIM_OK;
2200 }
2201
2202 static int aio_cmd_copy(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
2203 {
2204 AioFile *af = Jim_CmdPrivData(interp);
2205 jim_wide count = 0;
@@ -2110,21 +2258,21 @@
2258 }
2259 else {
2260 len = strlen(buf);
2261
2262 if (len && (buf[len - 1] == '\n')) {
2263
2264 len--;
2265 }
2266
2267 Jim_AppendString(interp, objPtr, buf, len);
2268 break;
2269 }
2270 }
2271
2272 if (JimCheckStreamError(interp, af)) {
2273
2274 Jim_FreeNewObj(interp, objPtr);
2275 return JIM_ERR;
2276 }
2277
2278 if (argc) {
@@ -2134,11 +2282,11 @@
2282 }
2283
2284 len = Jim_Length(objPtr);
2285
2286 if (len == 0 && feof(af->fp)) {
2287
2288 len = -1;
2289 }
2290 Jim_SetResultInt(interp, len);
2291 }
2292 else {
@@ -2207,11 +2355,11 @@
2355 }
2356
2357 static int aio_cmd_close(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
2358 {
2359 if (argc == 3) {
2360 #if defined(HAVE_SOCKETS) && defined(HAVE_SHUTDOWN)
2361 static const char * const options[] = { "r", "w", NULL };
2362 enum { OPT_R, OPT_W, };
2363 int option;
2364 AioFile *af = Jim_CmdPrivData(interp);
2365
@@ -2297,10 +2445,11 @@
2445 }
2446 Jim_SetResultInt(interp, (fmode & O_NONBLOCK) ? 1 : 0);
2447 return JIM_OK;
2448 }
2449 #endif
2450
2451
2452 #ifdef HAVE_FSYNC
2453 static int aio_cmd_sync(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
2454 {
2455 AioFile *af = Jim_CmdPrivData(interp);
@@ -2364,33 +2513,33 @@
2513
2514 static int aio_eventinfo(Jim_Interp *interp, AioFile * af, unsigned mask, Jim_Obj **scriptHandlerObj,
2515 int argc, Jim_Obj * const *argv)
2516 {
2517 if (argc == 0) {
2518
2519 if (*scriptHandlerObj) {
2520 Jim_SetResult(interp, *scriptHandlerObj);
2521 }
2522 return JIM_OK;
2523 }
2524
2525 if (*scriptHandlerObj) {
2526
2527 Jim_DeleteFileHandler(interp, af->fd, mask);
2528 }
2529
2530
2531 if (Jim_Length(argv[0]) == 0) {
2532
2533 return JIM_OK;
2534 }
2535
2536
2537 Jim_IncrRefCount(argv[0]);
2538 *scriptHandlerObj = argv[0];
2539
2540 Jim_CreateFileHandler(interp, af->fd, mask,
2541 JimAioFileEventHandler, scriptHandlerObj, JimAioFileEventFinalizer);
2542
2543 return JIM_OK;
2544 }
2545
@@ -2414,136 +2563,145 @@
2563
2564 return aio_eventinfo(interp, af, JIM_EVENT_EXCEPTION, &af->eEvent, argc, argv);
2565 }
2566 #endif
2567
2568
2569
2570
2571 static const jim_subcmd_type aio_command_table[] = {
2572 { "read",
2573 "?-nonewline? ?len?",
2574 aio_cmd_read,
2575 0,
2576 2,
2577
2578 },
2579 { "copyto",
2580 "handle ?size?",
2581 aio_cmd_copy,
2582 1,
2583 2,
2584
2585 },
2586 { "getfd",
2587 NULL,
2588 aio_cmd_getfd,
2589 0,
2590 0,
2591
2592 },
2593 { "gets",
2594 "?var?",
2595 aio_cmd_gets,
2596 0,
2597 1,
2598
2599 },
2600 { "puts",
2601 "?-nonewline? str",
2602 aio_cmd_puts,
2603 1,
2604 2,
2605
2606 },
2607 { "isatty",
2608 NULL,
2609 aio_cmd_isatty,
2610 0,
2611 0,
2612
2613 },
2614 { "flush",
2615 NULL,
2616 aio_cmd_flush,
2617 0,
2618 0,
2619
2620 },
2621 { "eof",
2622 NULL,
2623 aio_cmd_eof,
2624 0,
2625 0,
2626
2627 },
2628 { "close",
2629 "?r(ead)|w(rite)?",
2630 aio_cmd_close,
2631 0,
2632 1,
2633 JIM_MODFLAG_FULLARGV,
2634
2635 },
2636 { "seek",
2637 "offset ?start|current|end",
2638 aio_cmd_seek,
2639 1,
2640 2,
2641
2642 },
2643 { "tell",
2644 NULL,
2645 aio_cmd_tell,
2646 0,
2647 0,
2648
2649 },
2650 { "filename",
2651 NULL,
2652 aio_cmd_filename,
2653 0,
2654 0,
2655
2656 },
2657 #ifdef O_NDELAY
2658 { "ndelay",
2659 "?0|1?",
2660 aio_cmd_ndelay,
2661 0,
2662 1,
2663
2664 },
2665 #endif
2666 #ifdef HAVE_FSYNC
2667 { "sync",
2668 NULL,
2669 aio_cmd_sync,
2670 0,
2671 0,
2672
2673 },
2674 #endif
2675 { "buffering",
2676 "none|line|full",
2677 aio_cmd_buffering,
2678 1,
2679 1,
2680
2681 },
2682 #ifdef jim_ext_eventloop
2683 { "readable",
2684 "?readable-script?",
2685 aio_cmd_readable,
2686 0,
2687 1,
2688
2689 },
2690 { "writable",
2691 "?writable-script?",
2692 aio_cmd_writable,
2693 0,
2694 1,
2695
2696 },
2697 { "onexception",
2698 "?exception-script?",
2699 aio_cmd_onexception,
2700 0,
2701 1,
2702
2703 },
2704 #endif
2705 { NULL }
2706 };
2707
@@ -2566,11 +2724,11 @@
2724
2725 #ifdef jim_ext_tclcompat
2726 {
2727 const char *filename = Jim_String(argv[1]);
2728
2729
2730 if (*filename == '|') {
2731 Jim_Obj *evalObj[3];
2732
2733 evalObj[0] = Jim_NewStringObj(interp, "::popen", -1);
2734 evalObj[1] = Jim_NewStringObj(interp, filename + 1, -1);
@@ -2603,42 +2761,44 @@
2761 }
2762
2763 Jim_IncrRefCount(filename);
2764
2765 if (fh == NULL) {
 
2766 if (fd >= 0) {
2767 #ifndef JIM_ANSIC
2768 fh = fdopen(fd, mode);
2769 #endif
2770 }
2771 else
 
2772 fh = fopen(Jim_String(filename), mode);
2773
2774 if (fh == NULL) {
2775 JimAioSetError(interp, filename);
2776 #ifndef JIM_ANSIC
2777 if (fd >= 0) {
2778 close(fd);
2779 }
2780 #endif
2781 Jim_DecrRefCount(interp, filename);
2782 return NULL;
2783 }
2784 }
2785
2786
2787 af = Jim_Alloc(sizeof(*af));
2788 memset(af, 0, sizeof(*af));
2789 af->fp = fh;
 
2790 af->filename = filename;
2791 af->openFlags = openFlags;
2792 #ifndef JIM_ANSIC
2793 af->fd = fileno(fh);
2794 #ifdef FD_CLOEXEC
2795 if ((openFlags & AIO_KEEPOPEN) == 0) {
2796 (void)fcntl(af->fd, F_SETFD, FD_CLOEXEC);
2797 }
2798 #endif
2799 #endif
2800 af->addr_family = family;
2801 af->fops = &stdio_fops;
2802 af->ssl = NULL;
2803
2804 Jim_CreateCommand(interp, buf, JimAioSubCmdProc, af, JimAioDelProc);
@@ -2653,72 +2813,45 @@
2813 const char *hdlfmt, int family, const char *mode[2])
2814 {
2815 if (JimMakeChannel(interp, NULL, p[0], filename, hdlfmt, family, mode[0])) {
2816 Jim_Obj *objPtr = Jim_NewListObj(interp, NULL, 0);
2817 Jim_ListAppendElement(interp, objPtr, Jim_GetResult(interp));
 
2818 if (JimMakeChannel(interp, NULL, p[1], filename, hdlfmt, family, mode[1])) {
2819 Jim_ListAppendElement(interp, objPtr, Jim_GetResult(interp));
2820 Jim_SetResult(interp, objPtr);
2821 return JIM_OK;
2822 }
2823 }
2824
2825
2826 close(p[0]);
2827 close(p[1]);
2828 JimAioSetError(interp, NULL);
2829 return JIM_ERR;
2830 }
2831 #endif
2832
2833 #ifdef HAVE_PIPE
2834 static int JimAioPipeCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
2835 {
2836 int p[2];
2837 static const char *mode[2] = { "r", "w" };
2838
2839 if (argc != 1) {
2840 Jim_WrongNumArgs(interp, 1, argv, "");
2841 return JIM_ERR;
2842 }
2843
2844 if (pipe(p) != 0) {
2845 JimAioSetError(interp, NULL);
2846 return JIM_ERR;
2847 }
2848
2849 return JimMakeChannelPair(interp, p, argv[0], "aio.pipe%ld", 0, mode);
2850 }
2851 #endif
2852
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2853
2854
2855 int Jim_aioInit(Jim_Interp *interp)
2856 {
2857 if (Jim_PackageProvide(interp, "aio", "1.0", JIM_ERRMSG))
@@ -2727,15 +2860,18 @@
2860 #if defined(JIM_SSL)
2861 Jim_CreateCommand(interp, "load_ssl_certs", JimAioLoadSSLCertsCommand, NULL, NULL);
2862 #endif
2863
2864 Jim_CreateCommand(interp, "open", JimAioOpenCommand, NULL, NULL);
2865 #ifdef HAVE_SOCKETS
2866 Jim_CreateCommand(interp, "socket", JimAioSockCommand, NULL, NULL);
2867 #endif
2868 #ifdef HAVE_PIPE
2869 Jim_CreateCommand(interp, "pipe", JimAioPipeCommand, NULL, NULL);
2870 #endif
2871
2872
2873 JimMakeChannel(interp, stdin, -1, NULL, "stdin", 0, "r");
2874 JimMakeChannel(interp, stdout, -1, NULL, "stdout", 0, "w");
2875 JimMakeChannel(interp, stderr, -1, NULL, "stderr", 0, "w");
2876
2877 return JIM_OK;
@@ -2813,12 +2949,12 @@
2949 #include <regex.h>
2950 #endif
2951
2952 static void FreeRegexpInternalRep(Jim_Interp *interp, Jim_Obj *objPtr)
2953 {
2954 regfree(objPtr->internalRep.ptrIntValue.ptr);
2955 Jim_Free(objPtr->internalRep.ptrIntValue.ptr);
2956 }
2957
2958 static const Jim_ObjType regexpObjType = {
2959 "regexp",
2960 FreeRegexpInternalRep,
@@ -2831,20 +2967,20 @@
2967 {
2968 regex_t *compre;
2969 const char *pattern;
2970 int ret;
2971
2972
2973 if (objPtr->typePtr == &regexpObjType &&
2974 objPtr->internalRep.ptrIntValue.ptr && objPtr->internalRep.ptrIntValue.int1 == flags) {
2975
2976 return objPtr->internalRep.ptrIntValue.ptr;
2977 }
2978
 
2979
2980
2981
2982 pattern = Jim_String(objPtr);
2983 compre = Jim_Alloc(sizeof(regex_t));
2984
2985 if ((ret = regcomp(compre, pattern, REG_EXTENDED | flags)) != 0) {
2986 char buf[100];
@@ -2857,12 +2993,12 @@
2993 }
2994
2995 Jim_FreeIntRep(interp, objPtr);
2996
2997 objPtr->typePtr = &regexpObjType;
2998 objPtr->internalRep.ptrIntValue.int1 = flags;
2999 objPtr->internalRep.ptrIntValue.ptr = compre;
3000
3001 return compre;
3002 }
3003
3004 int Jim_RegexpCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
@@ -3001,11 +3137,11 @@
3137 }
3138
3139 num_matches++;
3140
3141 if (opt_all && !opt_inline) {
3142
3143 goto try_next_match;
3144 }
3145
3146
3147 j = 0;
@@ -3041,11 +3177,11 @@
3177
3178 if (opt_inline) {
3179 Jim_ListAppendElement(interp, resultListObj, resultObj);
3180 }
3181 else {
3182
3183 result = Jim_SetVariable(interp, argv[i], resultObj);
3184
3185 if (result != JIM_OK) {
3186 Jim_FreeObj(interp, resultObj);
3187 break;
@@ -3168,11 +3304,11 @@
3304
3305 source_str = Jim_GetString(argv[i + 1], &source_len);
3306 replace_str = Jim_GetString(argv[i + 2], &replace_len);
3307 varname = argv[i + 3];
3308
3309
3310 resultObj = Jim_NewStringObj(interp, "", 0);
3311
3312 if (offset) {
3313 if (offset < 0) {
3314 offset += source_len + 1;
@@ -3183,11 +3319,11 @@
3319 else if (offset < 0) {
3320 offset = 0;
3321 }
3322 }
3323
3324
3325 Jim_AppendString(interp, resultObj, source_str, offset);
3326
3327
3328 n = source_len - offset;
3329 p = source_str + offset;
@@ -3242,23 +3378,23 @@
3378 }
3379
3380 p += pmatch[0].rm_eo;
3381 n -= pmatch[0].rm_eo;
3382
3383
3384 if (!opt_all || n == 0) {
3385 break;
3386 }
3387
3388
3389 if ((regcomp_flags & REG_NEWLINE) == 0 && pattern[0] == '^') {
3390 break;
3391 }
3392
3393
3394 if (pattern[0] == '\0' && n) {
3395
3396 Jim_AppendString(interp, resultObj, p, 1);
3397 p++;
3398 n--;
3399 }
3400
@@ -3265,11 +3401,11 @@
3401 regexec_flags |= REG_NOTBOL;
3402 } while (n);
3403
3404 Jim_AppendString(interp, resultObj, p, -1);
3405
3406
3407 if (argc - i == 4) {
3408 result = Jim_SetVariable(interp, varname, resultObj);
3409
3410 if (result == JIM_OK) {
3411 Jim_SetResultInt(interp, num_matches);
@@ -3320,16 +3456,23 @@
3456
3457 # ifndef MAXPATHLEN
3458 # define MAXPATHLEN JIM_PATH_LEN
3459 # endif
3460
3461 #if defined(__MINGW32__) || defined(__MSYS__) || defined(_MSC_VER)
3462 #define ISWINDOWS 1
3463 #else
3464 #define ISWINDOWS 0
3465 #endif
3466
3467
3468 #if defined(HAVE_STRUCT_STAT_ST_MTIMESPEC)
3469 #define STAT_MTIME_US(STAT) ((STAT).st_mtimespec.tv_sec * 1000000ll + (STAT).st_mtimespec.tv_nsec / 1000)
3470 #elif defined(HAVE_STRUCT_STAT_ST_MTIM)
3471 #define STAT_MTIME_US(STAT) ((STAT).st_mtim.tv_sec * 1000000ll + (STAT).st_mtim.tv_nsec / 1000)
3472 #endif
3473
3474
3475 static const char *JimGetFileType(int mode)
3476 {
3477 if (S_ISREG(mode)) {
3478 return "file";
@@ -3371,11 +3514,11 @@
3514 Jim_ListAppendElement(interp, listObj, Jim_NewIntObj(interp, value));
3515 }
3516
3517 static int StoreStatData(Jim_Interp *interp, Jim_Obj *varName, const struct stat *sb)
3518 {
3519
3520 Jim_Obj *listObj = Jim_NewListObj(interp, NULL, 0);
3521
3522 AppendStatElement(interp, listObj, "dev", sb->st_dev);
3523 AppendStatElement(interp, listObj, "ino", sb->st_ino);
3524 AppendStatElement(interp, listObj, "mode", sb->st_mode);
@@ -3384,39 +3527,44 @@
3527 AppendStatElement(interp, listObj, "gid", sb->st_gid);
3528 AppendStatElement(interp, listObj, "size", sb->st_size);
3529 AppendStatElement(interp, listObj, "atime", sb->st_atime);
3530 AppendStatElement(interp, listObj, "mtime", sb->st_mtime);
3531 AppendStatElement(interp, listObj, "ctime", sb->st_ctime);
3532 #ifdef STAT_MTIME_US
3533 AppendStatElement(interp, listObj, "mtimeus", STAT_MTIME_US(*sb));
3534 #endif
3535 Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, "type", -1));
3536 Jim_ListAppendElement(interp, listObj, Jim_NewStringObj(interp, JimGetFileType((int)sb->st_mode), -1));
3537
3538
3539 if (varName) {
3540 Jim_Obj *objPtr;
3541 objPtr = Jim_GetVariable(interp, varName, JIM_NONE);
3542
3543 if (objPtr) {
3544 Jim_Obj *objv[2];
3545
3546 objv[0] = objPtr;
3547 objv[1] = listObj;
3548
3549 objPtr = Jim_DictMerge(interp, 2, objv);
3550 if (objPtr == NULL) {
3551
3552 Jim_SetResultFormatted(interp, "can't set \"%#s(dev)\": variable isn't array", varName);
3553 Jim_FreeNewObj(interp, listObj);
3554 return JIM_ERR;
3555 }
3556
 
 
 
 
 
 
3557 Jim_InvalidateStringRep(objPtr);
3558
3559 Jim_FreeNewObj(interp, listObj);
3560 listObj = objPtr;
3561 }
3562 Jim_SetVariable(interp, varName, listObj);
3563 }
3564
3565
3566 Jim_SetResult(interp, listObj);
3567
3568 return JIM_OK;
3569 }
3570
@@ -3432,11 +3580,11 @@
3580 }
3581 else if (p == path) {
3582 Jim_SetResultString(interp, "/", -1);
3583 }
3584 else if (ISWINDOWS && p[-1] == ':') {
3585
3586 Jim_SetResultString(interp, path, p - path + 1);
3587 }
3588 else {
3589 Jim_SetResultString(interp, path, p - path);
3590 }
@@ -3512,35 +3660,35 @@
3660 char *newname = Jim_Alloc(MAXPATHLEN + 1);
3661 char *last = newname;
3662
3663 *newname = 0;
3664
3665
3666 for (i = 0; i < argc; i++) {
3667 int len;
3668 const char *part = Jim_GetString(argv[i], &len);
3669
3670 if (*part == '/') {
3671
3672 last = newname;
3673 }
3674 else if (ISWINDOWS && strchr(part, ':')) {
3675
3676 last = newname;
3677 }
3678 else if (part[0] == '.') {
3679 if (part[1] == '/') {
3680 part += 2;
3681 len -= 2;
3682 }
3683 else if (part[1] == 0 && last != newname) {
3684
3685 continue;
3686 }
3687 }
3688
3689
3690 if (last != newname && last[-1] != '/') {
3691 *last++ = '/';
3692 }
3693
3694 if (len) {
@@ -3551,22 +3699,22 @@
3699 }
3700 memcpy(last, part, len);
3701 last += len;
3702 }
3703
3704
3705 if (last > newname + 1 && last[-1] == '/') {
3706
3707 if (!ISWINDOWS || !(last > newname + 2 && last[-2] == ':')) {
3708 *--last = 0;
3709 }
3710 }
3711 }
3712
3713 *last = 0;
3714
3715
3716
3717 Jim_SetResult(interp, Jim_NewStringObjNoAlloc(interp, newname, last - newname));
3718
3719 return JIM_OK;
3720 }
@@ -3591,11 +3739,11 @@
3739 static int file_cmd_executable(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
3740 {
3741 #ifdef X_OK
3742 return file_access(interp, argv[0], X_OK);
3743 #else
3744
3745 Jim_SetResultBool(interp, 1);
3746 return JIM_OK;
3747 #endif
3748 }
3749
@@ -3616,11 +3764,11 @@
3764 while (argc--) {
3765 const char *path = Jim_String(argv[0]);
3766
3767 if (unlink(path) == -1 && errno != ENOENT) {
3768 if (rmdir(path) == -1) {
3769
3770 if (!force || Jim_EvalPrefix(interp, "file delete force", 1, argv) != JIM_OK) {
3771 Jim_SetResultFormatted(interp, "couldn't delete file \"%s\": %s", path,
3772 strerror(errno));
3773 return JIM_ERR;
3774 }
@@ -3639,15 +3787,15 @@
3787
3788 static int mkdir_all(char *path)
3789 {
3790 int ok = 1;
3791
3792
3793 goto first;
3794
3795 while (ok--) {
3796
3797 {
3798 char *slash = strrchr(path, '/');
3799
3800 if (slash && slash != path) {
3801 *slash = 0;
@@ -3660,24 +3808,24 @@
3808 first:
3809 if (MKDIR_DEFAULT(path) == 0) {
3810 return 0;
3811 }
3812 if (errno == ENOENT) {
3813
3814 continue;
3815 }
3816
3817 if (errno == EEXIST) {
3818 struct stat sb;
3819
3820 if (stat(path, &sb) == 0 && S_ISDIR(sb.st_mode)) {
3821 return 0;
3822 }
3823
3824 errno = EEXIST;
3825 }
3826
3827 break;
3828 }
3829 return -1;
3830 }
3831
@@ -3698,11 +3846,11 @@
3846 return JIM_OK;
3847 }
3848
3849 static int file_cmd_tempfile(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
3850 {
3851 int fd = Jim_MakeTempFile(interp, (argc >= 1) ? Jim_String(argv[0]) : NULL, 0);
3852
3853 if (fd < 0) {
3854 return JIM_ERR;
3855 }
3856 close(fd);
@@ -3815,42 +3963,67 @@
3963 return JIM_ERR;
3964 }
3965 Jim_SetResultInt(interp, sb.st_atime);
3966 return JIM_OK;
3967 }
3968
3969 static int JimSetFileTimes(Jim_Interp *interp, const char *filename, jim_wide us)
3970 {
3971 #ifdef HAVE_UTIMES
3972 struct timeval times[2];
3973
3974 times[1].tv_sec = times[0].tv_sec = us / 1000000;
3975 times[1].tv_usec = times[0].tv_usec = us % 1000000;
3976
3977 if (utimes(filename, times) != 0) {
3978 Jim_SetResultFormatted(interp, "can't set time on \"%s\": %s", filename, strerror(errno));
3979 return JIM_ERR;
3980 }
3981 return JIM_OK;
3982 #else
3983 Jim_SetResultString(interp, "Not implemented", -1);
3984 return JIM_ERR;
3985 #endif
3986 }
3987
3988 static int file_cmd_mtime(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
3989 {
3990 struct stat sb;
3991
3992 if (argc == 2) {
3993 jim_wide secs;
3994 if (Jim_GetWide(interp, argv[1], &secs) != JIM_OK) {
3995 return JIM_ERR;
3996 }
3997 return JimSetFileTimes(interp, Jim_String(argv[0]), secs * 1000000);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3998 }
3999 if (file_stat(interp, argv[0], &sb) != JIM_OK) {
4000 return JIM_ERR;
4001 }
4002 Jim_SetResultInt(interp, sb.st_mtime);
4003 return JIM_OK;
4004 }
4005
4006 #ifdef STAT_MTIME_US
4007 static int file_cmd_mtimeus(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
4008 {
4009 struct stat sb;
4010
4011 if (argc == 2) {
4012 jim_wide us;
4013 if (Jim_GetWide(interp, argv[1], &us) != JIM_OK) {
4014 return JIM_ERR;
4015 }
4016 return JimSetFileTimes(interp, Jim_String(argv[0]), us);
4017 }
4018 if (file_stat(interp, argv[0], &sb) != JIM_OK) {
4019 return JIM_ERR;
4020 }
4021 Jim_SetResultInt(interp, STAT_MTIME_US(sb));
4022 return JIM_OK;
4023 }
4024 #endif
4025
4026 static int file_cmd_copy(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
4027 {
4028 return Jim_EvalPrefix(interp, "file copy", argc, argv);
4029 }
@@ -3962,192 +4135,201 @@
4135 { "atime",
4136 "name",
4137 file_cmd_atime,
4138 1,
4139 1,
4140
4141 },
4142 { "mtime",
4143 "name ?time?",
4144 file_cmd_mtime,
4145 1,
4146 2,
4147
4148 },
4149 #ifdef STAT_MTIME_US
4150 { "mtimeus",
4151 "name ?time?",
4152 file_cmd_mtimeus,
4153 1,
4154 2,
4155
4156 },
4157 #endif
4158 { "copy",
4159 "?-force? source dest",
4160 file_cmd_copy,
4161 2,
4162 3,
4163
4164 },
4165 { "dirname",
4166 "name",
4167 file_cmd_dirname,
4168 1,
4169 1,
4170
4171 },
4172 { "rootname",
4173 "name",
4174 file_cmd_rootname,
4175 1,
4176 1,
4177
4178 },
4179 { "extension",
4180 "name",
4181 file_cmd_extension,
4182 1,
4183 1,
4184
4185 },
4186 { "tail",
4187 "name",
4188 file_cmd_tail,
4189 1,
4190 1,
4191
4192 },
4193 { "normalize",
4194 "name",
4195 file_cmd_normalize,
4196 1,
4197 1,
4198
4199 },
4200 { "join",
4201 "name ?name ...?",
4202 file_cmd_join,
4203 1,
4204 -1,
4205
4206 },
4207 { "readable",
4208 "name",
4209 file_cmd_readable,
4210 1,
4211 1,
4212
4213 },
4214 { "writable",
4215 "name",
4216 file_cmd_writable,
4217 1,
4218 1,
4219
4220 },
4221 { "executable",
4222 "name",
4223 file_cmd_executable,
4224 1,
4225 1,
4226
4227 },
4228 { "exists",
4229 "name",
4230 file_cmd_exists,
4231 1,
4232 1,
4233
4234 },
4235 { "delete",
4236 "?-force|--? name ...",
4237 file_cmd_delete,
4238 1,
4239 -1,
4240
4241 },
4242 { "mkdir",
4243 "dir ...",
4244 file_cmd_mkdir,
4245 1,
4246 -1,
4247
4248 },
4249 { "tempfile",
4250 "?template?",
4251 file_cmd_tempfile,
4252 0,
4253 1,
4254
4255 },
4256 { "rename",
4257 "?-force? source dest",
4258 file_cmd_rename,
4259 2,
4260 3,
4261
4262 },
4263 #if defined(HAVE_LINK) && defined(HAVE_SYMLINK)
4264 { "link",
4265 "?-symbolic|-hard? newname target",
4266 file_cmd_link,
4267 2,
4268 3,
4269
4270 },
4271 #endif
4272 #if defined(HAVE_READLINK)
4273 { "readlink",
4274 "name",
4275 file_cmd_readlink,
4276 1,
4277 1,
4278
4279 },
4280 #endif
4281 { "size",
4282 "name",
4283 file_cmd_size,
4284 1,
4285 1,
4286
4287 },
4288 { "stat",
4289 "name ?var?",
4290 file_cmd_stat,
4291 1,
4292 2,
4293
4294 },
4295 { "lstat",
4296 "name ?var?",
4297 file_cmd_lstat,
4298 1,
4299 2,
4300
4301 },
4302 { "type",
4303 "name",
4304 file_cmd_type,
4305 1,
4306 1,
4307
4308 },
4309 #ifdef HAVE_GETEUID
4310 { "owned",
4311 "name",
4312 file_cmd_owned,
4313 1,
4314 1,
4315
4316 },
4317 #endif
4318 { "isdirectory",
4319 "name",
4320 file_cmd_isdirectory,
4321 1,
4322 1,
4323
4324 },
4325 { "isfile",
4326 "name",
4327 file_cmd_isfile,
4328 1,
4329 1,
4330
4331 },
4332 {
4333 NULL
4334 }
4335 };
@@ -4179,11 +4361,11 @@
4361 Jim_SetResultString(interp, "Failed to get pwd", -1);
4362 Jim_Free(cwd);
4363 return JIM_ERR;
4364 }
4365 else if (ISWINDOWS) {
4366
4367 char *p = cwd;
4368 while ((p = strchr(p, '\\')) != NULL) {
4369 *p++ = '/';
4370 }
4371 }
@@ -4203,10 +4385,13 @@
4385 Jim_CreateCommand(interp, "pwd", Jim_PwdCmd, NULL, NULL);
4386 Jim_CreateCommand(interp, "cd", Jim_CdCmd, NULL, NULL);
4387 return JIM_OK;
4388 }
4389
4390 #ifndef _GNU_SOURCE
4391 #define _GNU_SOURCE
4392 #endif
4393 #include <string.h>
4394 #include <ctype.h>
4395
4396
4397 #if (!defined(HAVE_VFORK) || !defined(HAVE_WAITPID)) && !defined(__MINGW32__)
@@ -4214,20 +4399,20 @@
4399 {
4400 Jim_Obj *cmdlineObj = Jim_NewEmptyStringObj(interp);
4401 int i, j;
4402 int rc;
4403
4404
4405 for (i = 1; i < argc; i++) {
4406 int len;
4407 const char *arg = Jim_GetString(argv[i], &len);
4408
4409 if (i > 1) {
4410 Jim_AppendString(interp, cmdlineObj, " ", 1);
4411 }
4412 if (strpbrk(arg, "\\\" ") == NULL) {
4413
4414 Jim_AppendString(interp, cmdlineObj, arg, len);
4415 continue;
4416 }
4417
4418 Jim_AppendString(interp, cmdlineObj, "\"", 1);
@@ -4266,86 +4451,26 @@
4451 #else
4452
4453
4454 #include <errno.h>
4455 #include <signal.h>
4456 #include <sys/stat.h>
4457
4458 struct WaitInfoTable;
4459
4460 static char **JimOriginalEnviron(void);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4461 static char **JimSaveEnv(char **env);
4462 static void JimRestoreEnv(char **env);
4463 static int JimCreatePipeline(Jim_Interp *interp, int argc, Jim_Obj *const *argv,
4464 pidtype **pidArrayPtr, int *inPipePtr, int *outPipePtr, int *errFilePtr);
4465 static void JimDetachPids(struct WaitInfoTable *table, int numPids, const pidtype *pidPtr);
4466 static int JimCleanupChildren(Jim_Interp *interp, int numPids, pidtype *pidPtr, Jim_Obj *errStrObj);
4467 static int Jim_WaitCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv);
4468
4469 #if defined(__MINGW32__)
4470 static pidtype JimStartWinProcess(Jim_Interp *interp, char **argv, char **env, int inputId, int outputId, int errorId);
4471 #endif
 
 
 
 
 
 
 
 
4472
4473 static void Jim_RemoveTrailingNewline(Jim_Obj *objPtr)
4474 {
4475 int len;
4476 const char *s = Jim_GetString(objPtr, &len);
@@ -4354,14 +4479,14 @@
4479 objPtr->length--;
4480 objPtr->bytes[objPtr->length] = '\0';
4481 }
4482 }
4483
4484 static int JimAppendStreamToString(Jim_Interp *interp, int fd, Jim_Obj *strObj)
4485 {
4486 char buf[256];
4487 FILE *fh = fdopen(fd, "r");
4488 int ret = 0;
4489
4490 if (fh == NULL) {
4491 return -1;
4492 }
@@ -4390,18 +4515,18 @@
4515 char *envdata;
4516
4517 Jim_Obj *objPtr = Jim_GetGlobalVariableStr(interp, "env", JIM_NONE);
4518
4519 if (!objPtr) {
4520 return JimOriginalEnviron();
4521 }
4522
4523
4524
4525 num = Jim_ListLength(interp, objPtr);
4526 if (num % 2) {
4527
4528 num--;
4529 }
4530 size = Jim_Length(objPtr) + 2;
4531
4532 envptr = Jim_Alloc(sizeof(*envptr) * (num / 2 + 1) + size);
@@ -4433,79 +4558,76 @@
4558 if (env != original_environ) {
4559 Jim_Free(env);
4560 }
4561 }
4562
4563 static Jim_Obj *JimMakeErrorCode(Jim_Interp *interp, pidtype pid, int waitStatus, Jim_Obj *errStrObj)
4564 {
4565 Jim_Obj *errorCode = Jim_NewListObj(interp, NULL, 0);
4566
4567 if (pid == JIM_BAD_PID || pid == JIM_NO_PID) {
4568 Jim_ListAppendElement(interp, errorCode, Jim_NewStringObj(interp, "NONE", -1));
4569 Jim_ListAppendElement(interp, errorCode, Jim_NewIntObj(interp, (long)pid));
4570 Jim_ListAppendElement(interp, errorCode, Jim_NewIntObj(interp, -1));
4571 }
4572 else if (WIFEXITED(waitStatus)) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4573 Jim_ListAppendElement(interp, errorCode, Jim_NewStringObj(interp, "CHILDSTATUS", -1));
4574 Jim_ListAppendElement(interp, errorCode, Jim_NewIntObj(interp, (long)pid));
4575 Jim_ListAppendElement(interp, errorCode, Jim_NewIntObj(interp, WEXITSTATUS(waitStatus)));
4576 }
4577 else {
4578 const char *type;
4579 const char *action;
4580 const char *signame;
4581
4582 if (WIFSIGNALED(waitStatus)) {
4583 type = "CHILDKILLED";
4584 action = "killed";
4585 signame = Jim_SignalId(WTERMSIG(waitStatus));
4586 }
4587 else {
4588 type = "CHILDSUSP";
4589 action = "suspended";
4590 signame = "none";
4591 }
4592
4593 Jim_ListAppendElement(interp, errorCode, Jim_NewStringObj(interp, type, -1));
4594
4595 if (errStrObj) {
4596 Jim_AppendStrings(interp, errStrObj, "child ", action, " by signal ", Jim_SignalId(WTERMSIG(waitStatus)), "\n", NULL);
4597 }
4598
4599 Jim_ListAppendElement(interp, errorCode, Jim_NewIntObj(interp, (long)pid));
4600 Jim_ListAppendElement(interp, errorCode, Jim_NewStringObj(interp, signame, -1));
 
4601 }
4602 return errorCode;
4603 }
4604
4605 static int JimCheckWaitStatus(Jim_Interp *interp, pidtype pid, int waitStatus, Jim_Obj *errStrObj)
4606 {
4607 if (WIFEXITED(waitStatus) && WEXITSTATUS(waitStatus) == 0) {
4608 return JIM_OK;
4609 }
4610 Jim_SetGlobalVariableStr(interp, "errorCode", JimMakeErrorCode(interp, pid, waitStatus, errStrObj));
4611
4612 return JIM_ERR;
4613 }
4614
4615
4616 struct WaitInfo
4617 {
4618 pidtype pid;
4619 int status;
4620 int flags;
4621 };
4622
4623
4624 struct WaitInfoTable {
4625 struct WaitInfo *info;
4626 int size;
4627 int used;
4628 int refcount;
4629 };
4630
4631
4632 #define WI_DETACHED 2
4633
@@ -4513,32 +4635,53 @@
4635
4636 static void JimFreeWaitInfoTable(struct Jim_Interp *interp, void *privData)
4637 {
4638 struct WaitInfoTable *table = privData;
4639
4640 if (--table->refcount == 0) {
4641 Jim_Free(table->info);
4642 Jim_Free(table);
4643 }
4644 }
4645
4646 static struct WaitInfoTable *JimAllocWaitInfoTable(void)
4647 {
4648 struct WaitInfoTable *table = Jim_Alloc(sizeof(*table));
4649 table->info = NULL;
4650 table->size = table->used = 0;
4651 table->refcount = 1;
4652
4653 return table;
4654 }
4655
4656 static int JimWaitRemove(struct WaitInfoTable *table, pidtype pid)
4657 {
4658 int i;
4659
4660
4661 for (i = 0; i < table->used; i++) {
4662 if (pid == table->info[i].pid) {
4663 if (i != table->used - 1) {
4664 table->info[i] = table->info[table->used - 1];
4665 }
4666 table->used--;
4667 return 0;
4668 }
4669 }
4670 return -1;
4671 }
4672
4673 static int Jim_ExecCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
4674 {
4675 int outputId;
4676 int errorId;
4677 pidtype *pidPtr;
4678 int numPids, result;
4679 int child_siginfo = 1;
4680 Jim_Obj *childErrObj;
4681 Jim_Obj *errStrObj;
4682 struct WaitInfoTable *table = Jim_CmdPrivData(interp);
4683
4684 if (argc > 1 && Jim_CompareStringImmediate(interp, argv[argc - 1], "&")) {
4685 Jim_Obj *listObj;
4686 int i;
4687
@@ -4545,17 +4688,17 @@
4688 argc--;
4689 numPids = JimCreatePipeline(interp, argc - 1, argv + 1, &pidPtr, NULL, NULL, NULL);
4690 if (numPids < 0) {
4691 return JIM_ERR;
4692 }
4693
4694 listObj = Jim_NewListObj(interp, NULL, 0);
4695 for (i = 0; i < numPids; i++) {
4696 Jim_ListAppendElement(interp, listObj, Jim_NewIntObj(interp, (long)pidPtr[i]));
4697 }
4698 Jim_SetResult(interp, listObj);
4699 JimDetachPids(table, numPids, pidPtr);
4700 Jim_Free(pidPtr);
4701 return JIM_OK;
4702 }
4703
4704 numPids =
@@ -4567,54 +4710,98 @@
4710
4711 result = JIM_OK;
4712
4713 errStrObj = Jim_NewStringObj(interp, "", 0);
4714
4715
4716 if (outputId != -1) {
4717 if (JimAppendStreamToString(interp, outputId, errStrObj) < 0) {
4718 result = JIM_ERR;
4719 Jim_SetResultErrno(interp, "error reading from output pipe");
4720 }
4721 }
4722
4723
4724 childErrObj = Jim_NewStringObj(interp, "", 0);
4725 Jim_IncrRefCount(childErrObj);
4726
4727 if (JimCleanupChildren(interp, numPids, pidPtr, childErrObj) != JIM_OK) {
4728 result = JIM_ERR;
4729 }
4730
4731 if (errorId != -1) {
4732 int ret;
4733 lseek(errorId, 0, SEEK_SET);
4734 ret = JimAppendStreamToString(interp, errorId, errStrObj);
4735 if (ret < 0) {
4736 Jim_SetResultErrno(interp, "error reading from error pipe");
4737 result = JIM_ERR;
4738 }
4739 else if (ret > 0) {
4740
4741 child_siginfo = 0;
4742 }
4743 }
4744
4745 if (child_siginfo) {
4746
4747 Jim_AppendObj(interp, errStrObj, childErrObj);
4748 }
4749 Jim_DecrRefCount(interp, childErrObj);
4750
4751
4752 Jim_RemoveTrailingNewline(errStrObj);
4753
4754
4755 Jim_SetResult(interp, errStrObj);
4756
4757 return result;
4758 }
4759
4760 static pidtype JimWaitForProcess(struct WaitInfoTable *table, pidtype pid, int *statusPtr)
4761 {
4762 if (JimWaitRemove(table, pid) == 0) {
4763
4764 waitpid(pid, statusPtr, 0);
4765 return pid;
4766 }
4767
4768
4769 return JIM_BAD_PID;
4770 }
4771
4772 static void JimDetachPids(struct WaitInfoTable *table, int numPids, const pidtype *pidPtr)
4773 {
4774 int j;
4775
4776 for (j = 0; j < numPids; j++) {
4777
4778 int i;
4779 for (i = 0; i < table->used; i++) {
4780 if (pidPtr[j] == table->info[i].pid) {
4781 table->info[i].flags |= WI_DETACHED;
4782 break;
4783 }
4784 }
4785 }
4786 }
4787
4788 static int JimGetChannelFd(Jim_Interp *interp, const char *name)
4789 {
4790 Jim_Obj *objv[2];
4791
4792 objv[0] = Jim_NewStringObj(interp, name, -1);
4793 objv[1] = Jim_NewStringObj(interp, "getfd", -1);
4794
4795 if (Jim_EvalObjVector(interp, 2, objv) == JIM_OK) {
4796 jim_wide fd;
4797 if (Jim_GetWide(interp, Jim_GetResult(interp), &fd) == JIM_OK) {
4798 return fd;
4799 }
4800 }
4801 return -1;
4802 }
4803
4804 static void JimReapDetachedPids(struct WaitInfoTable *table)
4805 {
4806 struct WaitInfo *waitPtr;
4807 int count;
@@ -4627,13 +4814,13 @@
4814 waitPtr = table->info;
4815 dest = 0;
4816 for (count = table->used; count > 0; waitPtr++, count--) {
4817 if (waitPtr->flags & WI_DETACHED) {
4818 int status;
4819 pidtype pid = waitpid(waitPtr->pid, &status, WNOHANG);
4820 if (pid == waitPtr->pid) {
4821
4822 table->used--;
4823 continue;
4824 }
4825 }
4826 if (waitPtr != &table->info[dest]) {
@@ -4641,66 +4828,62 @@
4828 }
4829 dest++;
4830 }
4831 }
4832
4833 static int Jim_WaitCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
4834 {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4835 struct WaitInfoTable *table = Jim_CmdPrivData(interp);
4836 int nohang = 0;
4837 pidtype pid;
4838 long pidarg;
4839 int status;
4840 Jim_Obj *errCodeObj;
4841
4842
4843 if (argc == 1) {
4844 JimReapDetachedPids(table);
4845 return JIM_OK;
4846 }
4847
4848 if (argc > 1 && Jim_CompareStringImmediate(interp, argv[1], "-nohang")) {
4849 nohang = 1;
4850 }
4851 if (argc != nohang + 2) {
4852 Jim_WrongNumArgs(interp, 1, argv, "?-nohang? ?pid?");
4853 return JIM_ERR;
4854 }
4855 if (Jim_GetLong(interp, argv[nohang + 1], &pidarg) != JIM_OK) {
4856 return JIM_ERR;
4857 }
4858
4859 pid = waitpid((pidtype)pidarg, &status, nohang ? WNOHANG : 0);
4860
4861 errCodeObj = JimMakeErrorCode(interp, pid, status, NULL);
4862
4863 if (pid != JIM_BAD_PID && (WIFEXITED(status) || WIFSIGNALED(status))) {
4864
4865 JimWaitRemove(table, pid);
4866 }
4867 Jim_SetResult(interp, errCodeObj);
4868 return JIM_OK;
4869 }
4870
4871 static int Jim_PidCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
4872 {
4873 if (argc != 1) {
4874 Jim_WrongNumArgs(interp, 1, argv, "");
4875 return JIM_ERR;
4876 }
4877
4878 Jim_SetResultInt(interp, (jim_wide)getpid());
4879 return JIM_OK;
4880 }
4881
4882 static int
4883 JimCreatePipeline(Jim_Interp *interp, int argc, Jim_Obj *const *argv, pidtype **pidArrayPtr,
4884 int *inPipePtr, int *outPipePtr, int *errFilePtr)
4885 {
4886 pidtype *pidPtr = NULL; /* Points to malloc-ed array holding all
4887 * the pids of child processes. */
4888 int numPids = 0; /* Actual number of processes that exist
4889 * at *pidPtr right now. */
@@ -4707,16 +4890,16 @@
4890 int cmdCount; /* Count of number of distinct commands
4891 * found in argc/argv. */
4892 const char *input = NULL; /* Describes input for pipeline, depending
4893 * on "inputFile". NULL means take input
4894 * from stdin/pipe. */
4895 int input_len = 0;
4896
4897 #define FILE_NAME 0
4898 #define FILE_APPEND 1
4899 #define FILE_HANDLE 2
4900 #define FILE_TEXT 3
4901
4902 int inputFile = FILE_NAME; /* 1 means input is name of input file.
4903 * 2 means input is filehandle name.
4904 * 0 means input holds actual
4905 * text to be input to command. */
@@ -4733,39 +4916,40 @@
4916 */
4917 const char *output = NULL; /* Holds name of output file to pipe to,
4918 * or NULL if output goes to stdout/pipe. */
4919 const char *error = NULL; /* Holds name of stderr file to pipe to,
4920 * or NULL if stderr goes to stderr/pipe. */
4921 int inputId = -1;
4922 int outputId = -1;
4923 int errorId = -1;
4924 int lastOutputId = -1;
4925 int pipeIds[2];
4926 int firstArg, lastArg; /* Indexes of first and last arguments in
4927 * current command. */
4928 int lastBar;
4929 int i;
4930 pidtype pid;
4931 char **save_environ;
4932 #ifndef __MINGW32__
4933 char **child_environ;
4934 #endif
4935 struct WaitInfoTable *table = Jim_CmdPrivData(interp);
4936
4937
4938 char **arg_array = Jim_Alloc(sizeof(*arg_array) * (argc + 1));
4939 int arg_count = 0;
4940
 
 
4941 if (inPipePtr != NULL) {
4942 *inPipePtr = -1;
4943 }
4944 if (outPipePtr != NULL) {
4945 *outPipePtr = -1;
4946 }
4947 if (errFilePtr != NULL) {
4948 *errFilePtr = -1;
4949 }
4950 pipeIds[0] = pipeIds[1] = -1;
4951
4952 cmdCount = 1;
4953 lastBar = -1;
4954 for (i = 0; i < argc; i++) {
4955 const char *arg = Jim_String(argv[i]);
@@ -4796,11 +4980,11 @@
4980 if (*output == '>') {
4981 outputFile = FILE_APPEND;
4982 output++;
4983 }
4984 if (*output == '&') {
4985
4986 output++;
4987 dup_error = 1;
4988 }
4989 if (*output == '@') {
4990 outputFile = FILE_HANDLE;
@@ -4837,11 +5021,11 @@
5021 goto badargs;
5022 }
5023 lastBar = i;
5024 cmdCount++;
5025 }
5026
5027 arg_array[arg_count++] = (char *)arg;
5028 continue;
5029 }
5030
5031 if (i >= argc) {
@@ -4855,183 +5039,227 @@
5039 badargs:
5040 Jim_Free(arg_array);
5041 return -1;
5042 }
5043
5044
5045 save_environ = JimSaveEnv(JimBuildEnv(interp));
5046
5047 if (input != NULL) {
5048 if (inputFile == FILE_TEXT) {
5049 inputId = Jim_MakeTempFile(interp, NULL, 1);
5050 if (inputId == -1) {
5051 goto error;
5052 }
5053 if (write(inputId, input, input_len) != input_len) {
5054 Jim_SetResultErrno(interp, "couldn't write temp file");
5055 close(inputId);
5056 goto error;
5057 }
5058 lseek(inputId, 0L, SEEK_SET);
5059 }
5060 else if (inputFile == FILE_HANDLE) {
5061 int fd = JimGetChannelFd(interp, input);
 
5062
5063 if (fd < 0) {
5064 goto error;
5065 }
5066 inputId = dup(fd);
5067 }
5068 else {
5069 inputId = Jim_OpenForRead(input);
5070 if (inputId == -1) {
5071 Jim_SetResultFormatted(interp, "couldn't read file \"%s\": %s", input, strerror(Jim_Errno()));
5072 goto error;
5073 }
5074 }
5075 }
5076 else if (inPipePtr != NULL) {
5077 if (pipe(pipeIds) != 0) {
5078 Jim_SetResultErrno(interp, "couldn't create input pipe for command");
5079 goto error;
5080 }
5081 inputId = pipeIds[0];
5082 *inPipePtr = pipeIds[1];
5083 pipeIds[0] = pipeIds[1] = -1;
5084 }
5085
5086 if (output != NULL) {
5087 if (outputFile == FILE_HANDLE) {
5088 int fd = JimGetChannelFd(interp, output);
5089 if (fd < 0) {
5090 goto error;
5091 }
5092 lastOutputId = dup(fd);
 
5093 }
5094 else {
5095 lastOutputId = Jim_OpenForWrite(output, outputFile == FILE_APPEND);
5096 if (lastOutputId == -1) {
5097 Jim_SetResultFormatted(interp, "couldn't write file \"%s\": %s", output, strerror(Jim_Errno()));
5098 goto error;
5099 }
5100 }
5101 }
5102 else if (outPipePtr != NULL) {
5103 if (pipe(pipeIds) != 0) {
5104 Jim_SetResultErrno(interp, "couldn't create output pipe");
5105 goto error;
5106 }
5107 lastOutputId = pipeIds[1];
5108 *outPipePtr = pipeIds[0];
5109 pipeIds[0] = pipeIds[1] = -1;
5110 }
5111
5112 if (error != NULL) {
5113 if (errorFile == FILE_HANDLE) {
5114 if (strcmp(error, "1") == 0) {
5115
5116 if (lastOutputId != -1) {
5117 errorId = dup(lastOutputId);
5118 }
5119 else {
5120
5121 error = "stdout";
5122 }
5123 }
5124 if (errorId == -1) {
5125 int fd = JimGetChannelFd(interp, error);
5126 if (fd < 0) {
5127 goto error;
5128 }
5129 errorId = dup(fd);
 
5130 }
5131 }
5132 else {
5133 errorId = Jim_OpenForWrite(error, errorFile == FILE_APPEND);
5134 if (errorId == -1) {
5135 Jim_SetResultFormatted(interp, "couldn't write file \"%s\": %s", error, strerror(Jim_Errno()));
5136 goto error;
5137 }
5138 }
5139 }
5140 else if (errFilePtr != NULL) {
5141 errorId = Jim_MakeTempFile(interp, NULL, 1);
5142 if (errorId == -1) {
5143 goto error;
5144 }
5145 *errFilePtr = dup(errorId);
5146 }
5147
5148
5149 pidPtr = Jim_Alloc(cmdCount * sizeof(*pidPtr));
5150 for (i = 0; i < numPids; i++) {
5151 pidPtr[i] = JIM_BAD_PID;
5152 }
5153 for (firstArg = 0; firstArg < arg_count; numPids++, firstArg = lastArg + 1) {
5154 int pipe_dup_err = 0;
5155 int origErrorId = errorId;
5156
5157 for (lastArg = firstArg; lastArg < arg_count; lastArg++) {
5158 if (strcmp(arg_array[lastArg], "|") == 0) {
5159 break;
5160 }
5161 if (strcmp(arg_array[lastArg], "|&") == 0) {
5162 pipe_dup_err = 1;
5163 break;
5164 }
5165 }
5166
5167 if (lastArg == firstArg) {
5168 Jim_SetResultString(interp, "missing command to exec", -1);
5169 goto error;
5170 }
5171
5172
5173 arg_array[lastArg] = NULL;
5174 if (lastArg == arg_count) {
5175 outputId = lastOutputId;
5176 lastOutputId = -1;
5177 }
5178 else {
5179 if (pipe(pipeIds) != 0) {
5180 Jim_SetResultErrno(interp, "couldn't create pipe");
5181 goto error;
5182 }
5183 outputId = pipeIds[1];
5184 }
5185
5186
5187 if (pipe_dup_err) {
5188 errorId = outputId;
5189 }
5190
5191
5192
5193 #ifdef __MINGW32__
5194 pid = JimStartWinProcess(interp, &arg_array[firstArg], save_environ, inputId, outputId, errorId);
5195 if (pid == JIM_BAD_PID) {
5196 Jim_SetResultFormatted(interp, "couldn't exec \"%s\"", arg_array[firstArg]);
5197 goto error;
5198 }
5199 #else
5200 i = strlen(arg_array[firstArg]);
5201
5202 child_environ = Jim_GetEnviron();
5203 pid = vfork();
5204 if (pid < 0) {
5205 Jim_SetResultErrno(interp, "couldn't fork child process");
5206 goto error;
5207 }
5208 if (pid == 0) {
5209
5210
5211 if (inputId != -1) {
5212 dup2(inputId, fileno(stdin));
5213 close(inputId);
5214 }
5215 if (outputId != -1) {
5216 dup2(outputId, fileno(stdout));
5217 if (outputId != errorId) {
5218 close(outputId);
5219 }
5220 }
5221 if (errorId != -1) {
5222 dup2(errorId, fileno(stderr));
5223 close(errorId);
5224 }
5225
5226 if (outPipePtr) {
5227 close(*outPipePtr);
5228 }
5229 if (errFilePtr) {
5230 close(*errFilePtr);
5231 }
5232 if (pipeIds[0] != -1) {
5233 close(pipeIds[0]);
5234 }
5235 if (lastOutputId != -1) {
5236 close(lastOutputId);
5237 }
5238
5239
5240 (void)signal(SIGPIPE, SIG_DFL);
5241
5242 execvpe(arg_array[firstArg], &arg_array[firstArg], child_environ);
5243
5244 if (write(fileno(stderr), "couldn't exec \"", 15) &&
5245 write(fileno(stderr), arg_array[firstArg], i) &&
5246 write(fileno(stderr), "\"\n", 2)) {
5247
5248 }
5249 #ifdef JIM_MAINTAINER
5250 {
5251
5252 static char *const false_argv[2] = {"false", NULL};
5253 execvp(false_argv[0],false_argv);
5254 }
5255 #endif
5256 _exit(127);
5257 }
5258 #endif
5259
5260
5261
5262 if (table->used == table->size) {
5263 table->size += WAIT_TABLE_GROW_BY;
5264 table->info = Jim_Realloc(table->info, table->size * sizeof(*table->info));
5265 }
@@ -5040,66 +5268,66 @@
5268 table->info[table->used].flags = 0;
5269 table->used++;
5270
5271 pidPtr[numPids] = pid;
5272
5273
5274 errorId = origErrorId;
5275
5276
5277 if (inputId != -1) {
5278 close(inputId);
5279 }
5280 if (outputId != -1) {
5281 close(outputId);
5282 }
5283 inputId = pipeIds[0];
5284 pipeIds[0] = pipeIds[1] = -1;
5285 }
5286 *pidArrayPtr = pidPtr;
5287
5288
5289 cleanup:
5290 if (inputId != -1) {
5291 close(inputId);
5292 }
5293 if (lastOutputId != -1) {
5294 close(lastOutputId);
5295 }
5296 if (errorId != -1) {
5297 close(errorId);
5298 }
5299 Jim_Free(arg_array);
5300
5301 JimRestoreEnv(save_environ);
5302
5303 return numPids;
5304
5305
5306 error:
5307 if ((inPipePtr != NULL) && (*inPipePtr != -1)) {
5308 close(*inPipePtr);
5309 *inPipePtr = -1;
5310 }
5311 if ((outPipePtr != NULL) && (*outPipePtr != -1)) {
5312 close(*outPipePtr);
5313 *outPipePtr = -1;
5314 }
5315 if ((errFilePtr != NULL) && (*errFilePtr != -1)) {
5316 close(*errFilePtr);
5317 *errFilePtr = -1;
5318 }
5319 if (pipeIds[0] != -1) {
5320 close(pipeIds[0]);
5321 }
5322 if (pipeIds[1] != -1) {
5323 close(pipeIds[1]);
5324 }
5325 if (pidPtr != NULL) {
5326 for (i = 0; i < numPids; i++) {
5327 if (pidPtr[i] != JIM_BAD_PID) {
5328 JimDetachPids(table, 1, &pidPtr[i]);
5329 }
5330 }
5331 Jim_Free(pidPtr);
5332 }
5333 numPids = -1;
@@ -5111,11 +5339,11 @@
5339 {
5340 struct WaitInfoTable *table = Jim_CmdPrivData(interp);
5341 int result = JIM_OK;
5342 int i;
5343
5344
5345 for (i = 0; i < numPids; i++) {
5346 int waitStatus = 0;
5347 if (JimWaitForProcess(table, pidPtr[i], &waitStatus) != JIM_BAD_PID) {
5348 if (JimCheckWaitStatus(interp, pidPtr[i], waitStatus, errStrObj) != JIM_OK) {
5349 result = JIM_ERR;
@@ -5127,234 +5355,30 @@
5355 return result;
5356 }
5357
5358 int Jim_execInit(Jim_Interp *interp)
5359 {
5360 struct WaitInfoTable *waitinfo;
5361 if (Jim_PackageProvide(interp, "exec", "1.0", JIM_ERRMSG))
5362 return JIM_ERR;
5363
5364 #ifdef SIGPIPE
5365 (void)signal(SIGPIPE, SIG_IGN);
5366 #endif
5367
5368 waitinfo = JimAllocWaitInfoTable();
5369 Jim_CreateCommand(interp, "exec", Jim_ExecCmd, waitinfo, JimFreeWaitInfoTable);
5370 waitinfo->refcount++;
5371 Jim_CreateCommand(interp, "wait", Jim_WaitCommand, waitinfo, JimFreeWaitInfoTable);
5372 Jim_CreateCommand(interp, "pid", Jim_PidCommand, 0, 0);
5373
5374 return JIM_OK;
5375 }
5376
5377 #if defined(__MINGW32__)
5378
5379
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5380 static int
5381 JimWinFindExecutable(const char *originalName, char fullPath[MAX_PATH])
5382 {
5383 int i;
5384 static char extensions[][5] = {".exe", "", ".bat"};
@@ -5381,10 +5405,15 @@
5405
5406 static void JimRestoreEnv(char **env)
5407 {
5408 JimFreeEnv(env, Jim_GetEnviron());
5409 }
5410
5411 static char **JimOriginalEnviron(void)
5412 {
5413 return NULL;
5414 }
5415
5416 static Jim_Obj *
5417 JimWinBuildCommandLine(Jim_Interp *interp, char **argv)
5418 {
5419 char *start, *special;
@@ -5455,18 +5484,19 @@
5484 }
5485 return strObj;
5486 }
5487
5488 static pidtype
5489 JimStartWinProcess(Jim_Interp *interp, char **argv, char **env, int inputId, int outputId, int errorId)
5490 {
5491 STARTUPINFO startInfo;
5492 PROCESS_INFORMATION procInfo;
5493 HANDLE hProcess;
5494 char execPath[MAX_PATH];
5495 pidtype pid = JIM_BAD_PID;
5496 Jim_Obj *cmdLineObj;
5497 char *winenv;
5498
5499 if (JimWinFindExecutable(argv[0], execPath) < 0) {
5500 return JIM_BAD_PID;
5501 }
5502 argv[0] = execPath;
@@ -5480,47 +5510,51 @@
5510 startInfo.dwFlags = STARTF_USESTDHANDLES;
5511 startInfo.hStdInput = INVALID_HANDLE_VALUE;
5512 startInfo.hStdOutput= INVALID_HANDLE_VALUE;
5513 startInfo.hStdError = INVALID_HANDLE_VALUE;
5514
5515 if (inputId == -1) {
5516 inputId = _fileno(stdin);
5517 }
5518 DuplicateHandle(hProcess, (HANDLE)_get_osfhandle(inputId), hProcess, &startInfo.hStdInput,
5519 0, TRUE, DUPLICATE_SAME_ACCESS);
5520 if (startInfo.hStdInput == INVALID_HANDLE_VALUE) {
5521 goto end;
5522 }
5523
5524 if (outputId == -1) {
5525 outputId = _fileno(stdout);
5526 }
5527 DuplicateHandle(hProcess, (HANDLE)_get_osfhandle(outputId), hProcess, &startInfo.hStdOutput,
5528 0, TRUE, DUPLICATE_SAME_ACCESS);
5529 if (startInfo.hStdOutput == INVALID_HANDLE_VALUE) {
5530 goto end;
5531 }
5532
5533
5534 if (errorId == -1) {
5535 errorId = _fileno(stderr);
5536 }
5537 DuplicateHandle(hProcess, (HANDLE)_get_osfhandle(errorId), hProcess, &startInfo.hStdError,
5538 0, TRUE, DUPLICATE_SAME_ACCESS);
5539 if (startInfo.hStdError == INVALID_HANDLE_VALUE) {
5540 goto end;
5541 }
5542
5543 if (env == NULL) {
5544
5545 winenv = NULL;
5546 }
5547 else if (env[0] == NULL) {
5548 winenv = (char *)"\0";
5549 }
5550 else {
5551 winenv = env[0];
5552 }
5553
5554 if (!CreateProcess(NULL, (char *)Jim_String(cmdLineObj), NULL, NULL, TRUE,
5555 0, winenv, NULL, &startInfo, &procInfo)) {
5556 goto end;
5557 }
5558
5559
5560 WaitForInputIdle(procInfo.hProcess, 5000);
@@ -5528,49 +5562,27 @@
5562
5563 pid = procInfo.hProcess;
5564
5565 end:
5566 Jim_FreeNewObj(interp, cmdLineObj);
5567 if (startInfo.hStdInput != INVALID_HANDLE_VALUE) {
5568 CloseHandle(startInfo.hStdInput);
5569 }
5570 if (startInfo.hStdOutput != INVALID_HANDLE_VALUE) {
5571 CloseHandle(startInfo.hStdOutput);
5572 }
5573 if (startInfo.hStdError != INVALID_HANDLE_VALUE) {
5574 CloseHandle(startInfo.hStdError);
5575 }
5576 return pid;
5577 }
5578
5579 #else
5580
5581 static char **JimOriginalEnviron(void)
5582 {
5583 return Jim_GetEnviron();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5584 }
5585
5586 static char **JimSaveEnv(char **env)
5587 {
5588 char **saveenv = Jim_GetEnviron();
@@ -5585,13 +5597,21 @@
5597 }
5598 #endif
5599 #endif
5600
5601
5602
5603 #ifdef STRPTIME_NEEDS_XOPEN_SOURCE
5604 #ifndef _XOPEN_SOURCE
5605 #define _XOPEN_SOURCE 500
5606 #endif
5607 #endif
5608
5609
5610 #ifndef _GNU_SOURCE
5611 #define _GNU_SOURCE
5612 #endif
5613
5614 #include <stdlib.h>
5615 #include <string.h>
5616 #include <stdio.h>
5617 #include <time.h>
@@ -5598,65 +5618,117 @@
5618
5619
5620 #ifdef HAVE_SYS_TIME_H
5621 #include <sys/time.h>
5622 #endif
5623
5624 struct clock_options {
5625 int gmt;
5626 const char *format;
5627 };
5628
5629 static int parse_clock_options(Jim_Interp *interp, int argc, Jim_Obj *const *argv, struct clock_options *opts)
5630 {
5631 static const char * const options[] = { "-gmt", "-format", NULL };
5632 enum { OPT_GMT, OPT_FORMAT, };
5633 int i;
5634
5635 for (i = 0; i < argc; i += 2) {
5636 int option;
5637 if (Jim_GetEnum(interp, argv[i], options, &option, NULL, JIM_ERRMSG | JIM_ENUM_ABBREV) != JIM_OK) {
5638 return JIM_ERR;
5639 }
5640 switch (option) {
5641 case OPT_GMT:
5642 if (Jim_GetBoolean(interp, argv[i + 1], &opts->gmt) != JIM_OK) {
5643 return JIM_ERR;
5644 }
5645 break;
5646 case OPT_FORMAT:
5647 opts->format = Jim_String(argv[i + 1]);
5648 break;
5649 }
5650 }
5651 return JIM_OK;
5652 }
5653
5654 static int clock_cmd_format(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
5655 {
5656
5657 char buf[100];
5658 time_t t;
5659 jim_wide seconds;
5660 struct clock_options options = { 0, "%a %b %d %H:%M:%S %Z %Y" };
5661 struct tm *tm;
5662
5663 if (Jim_GetWide(interp, argv[0], &seconds) != JIM_OK) {
5664 return JIM_ERR;
5665 }
5666 if (argc % 2 == 0) {
5667 return -1;
5668 }
5669 if (parse_clock_options(interp, argc - 1, argv + 1, &options) == JIM_ERR) {
5670 return JIM_ERR;
 
5671 }
5672
 
 
 
5673 t = seconds;
5674 tm = options.gmt ? gmtime(&t) : localtime(&t);
5675
5676 if (tm == NULL || strftime(buf, sizeof(buf), options.format, tm) == 0) {
5677 Jim_SetResultString(interp, "format string too long or invalid time", -1);
5678 return JIM_ERR;
5679 }
5680
5681 Jim_SetResultString(interp, buf, -1);
5682
5683 return JIM_OK;
5684 }
5685
5686 #ifdef HAVE_STRPTIME
5687 static time_t jim_timegm(const struct tm *tm)
5688 {
5689 int m = tm->tm_mon + 1;
5690 int y = 1900 + tm->tm_year - (m <= 2);
5691 int era = (y >= 0 ? y : y - 399) / 400;
5692 unsigned yoe = (unsigned)(y - era * 400);
5693 unsigned doy = (153 * (m + (m > 2 ? -3 : 9)) + 2) / 5 + tm->tm_mday - 1;
5694 unsigned doe = yoe * 365 + yoe / 4 - yoe / 100 + doy;
5695 long days = (era * 146097 + (int)doe - 719468);
5696 int secs = tm->tm_hour * 3600 + tm->tm_min * 60 + tm->tm_sec;
5697
5698 return days * 24 * 60 * 60 + secs;
5699 }
5700
5701 static int clock_cmd_scan(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
5702 {
5703 char *pt;
5704 struct tm tm;
5705 time_t now = time(NULL);
5706
5707 struct clock_options options = { 0, NULL };
5708
5709 if (argc % 2 == 0) {
5710 return -1;
5711 }
5712
5713 if (parse_clock_options(interp, argc - 1, argv + 1, &options) == JIM_ERR) {
5714 return JIM_ERR;
5715 }
5716 if (options.format == NULL) {
5717 return -1;
5718 }
5719
 
5720 localtime_r(&now, &tm);
5721
5722 pt = strptime(Jim_String(argv[0]), options.format, &tm);
5723 if (pt == 0 || *pt != 0) {
5724 Jim_SetResultString(interp, "Failed to parse time according to format", -1);
5725 return JIM_ERR;
5726 }
5727
5728
5729 Jim_SetResultInt(interp, options.gmt ? jim_timegm(&tm) : mktime(&tm));
5730
5731 return JIM_OK;
5732 }
5733 #endif
5734
@@ -5688,54 +5760,54 @@
5760
5761 return JIM_OK;
5762 }
5763
5764 static const jim_subcmd_type clock_command_table[] = {
 
 
 
 
 
 
 
5765 { "clicks",
5766 NULL,
5767 clock_cmd_micros,
5768 0,
5769 0,
5770
5771 },
5772 { "format",
5773 "seconds ?-format string? ?-gmt boolean?",
5774 clock_cmd_format,
5775 1,
5776 5,
5777
5778 },
5779 { "microseconds",
5780 NULL,
5781 clock_cmd_micros,
5782 0,
5783 0,
5784
5785 },
5786 { "milliseconds",
5787 NULL,
5788 clock_cmd_millis,
5789 0,
5790 0,
5791
 
 
 
 
 
 
 
5792 },
5793 #ifdef HAVE_STRPTIME
5794 { "scan",
5795 "str -format format ?-gmt boolean?",
5796 clock_cmd_scan,
5797 3,
5798 5,
5799
5800 },
5801 #endif
5802 { "seconds",
5803 NULL,
5804 clock_cmd_seconds,
5805 0,
5806 0,
5807
5808 },
5809 { NULL }
5810 };
5811
5812 int Jim_clockInit(Jim_Interp *interp)
5813 {
@@ -5753,12 +5825,13 @@
5825 #include <errno.h>
5826
5827
5828 static int array_cmd_exists(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
5829 {
5830
5831 Jim_Obj *dictObj = Jim_GetVariable(interp, argv[0], JIM_UNSHARED);
5832 Jim_SetResultInt(interp, dictObj && Jim_DictSize(interp, dictObj) != -1);
5833 return JIM_OK;
5834 }
5835
5836 static int array_cmd_get(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
5837 {
@@ -5769,21 +5842,20 @@
5842 return JIM_OK;
5843 }
5844
5845 patternObj = (argc == 1) ? NULL : argv[1];
5846
5847
5848 if (patternObj == NULL || Jim_CompareStringImmediate(interp, patternObj, "*")) {
5849 if (Jim_IsList(objPtr) && Jim_ListLength(interp, objPtr) % 2 == 0) {
5850
5851 Jim_SetResult(interp, objPtr);
5852 return JIM_OK;
5853 }
5854 }
5855
5856 return Jim_DictMatchTypes(interp, objPtr, patternObj, JIM_DICTMATCH_KEYS, JIM_DICTMATCH_KEYS | JIM_DICTMATCH_VALUES);
 
5857 }
5858
5859 static int array_cmd_names(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
5860 {
5861 Jim_Obj *objPtr = Jim_GetVariable(interp, argv[0], JIM_NONE);
@@ -5790,11 +5862,11 @@
5862
5863 if (!objPtr) {
5864 return JIM_OK;
5865 }
5866
5867 return Jim_DictMatchTypes(interp, objPtr, argc == 1 ? NULL : argv[1], JIM_DICTMATCH_KEYS, JIM_DICTMATCH_KEYS);
5868 }
5869
5870 static int array_cmd_unset(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
5871 {
5872 int i;
@@ -5802,27 +5874,29 @@
5874 Jim_Obj *resultObj;
5875 Jim_Obj *objPtr;
5876 Jim_Obj **dictValuesObj;
5877
5878 if (argc == 1 || Jim_CompareStringImmediate(interp, argv[1], "*")) {
5879
5880 Jim_UnsetVariable(interp, argv[0], JIM_NONE);
5881 return JIM_OK;
5882 }
5883
5884 objPtr = Jim_GetVariable(interp, argv[0], JIM_NONE);
5885
5886 if (objPtr == NULL) {
5887
5888 return JIM_OK;
5889 }
5890
5891 if (Jim_DictPairs(interp, objPtr, &dictValuesObj, &len) != JIM_OK) {
5892
5893 Jim_SetResultString(interp, "", -1);
5894 return JIM_OK;
5895 }
5896
5897
5898 resultObj = Jim_NewDictObj(interp, NULL, 0);
5899
5900 for (i = 0; i < len; i += 2) {
5901 if (!Jim_StringMatchObj(interp, argv[1], dictValuesObj[i], 0)) {
5902 Jim_DictAddElement(interp, resultObj, dictValuesObj[i], dictValuesObj[i + 1]);
@@ -5837,16 +5911,18 @@
5911 static int array_cmd_size(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
5912 {
5913 Jim_Obj *objPtr;
5914 int len = 0;
5915
5916
5917 objPtr = Jim_GetVariable(interp, argv[0], JIM_NONE);
5918 if (objPtr) {
5919 len = Jim_DictSize(interp, objPtr);
5920 if (len < 0) {
5921
5922 Jim_SetResultInt(interp, 0);
5923 return JIM_OK;
5924 }
5925 }
5926
5927 Jim_SetResultInt(interp, len);
5928
@@ -5876,11 +5952,11 @@
5952 return JIM_ERR;
5953 }
5954
5955 dictObj = Jim_GetVariable(interp, argv[0], JIM_UNSHARED);
5956 if (!dictObj) {
5957
5958 return Jim_SetVariable(interp, argv[0], listObj);
5959 }
5960 else if (Jim_DictSize(interp, dictObj) < 0) {
5961 return JIM_ERR;
5962 }
@@ -5905,53 +5981,53 @@
5981 { "exists",
5982 "arrayName",
5983 array_cmd_exists,
5984 1,
5985 1,
5986
5987 },
5988 { "get",
5989 "arrayName ?pattern?",
5990 array_cmd_get,
5991 1,
5992 2,
5993
5994 },
5995 { "names",
5996 "arrayName ?pattern?",
5997 array_cmd_names,
5998 1,
5999 2,
6000
6001 },
6002 { "set",
6003 "arrayName list",
6004 array_cmd_set,
6005 2,
6006 2,
6007
6008 },
6009 { "size",
6010 "arrayName",
6011 array_cmd_size,
6012 1,
6013 1,
6014
6015 },
6016 { "stat",
6017 "arrayName",
6018 array_cmd_stat,
6019 1,
6020 1,
6021
6022 },
6023 { "unset",
6024 "arrayName ?pattern?",
6025 array_cmd_unset,
6026 1,
6027 2,
6028
6029 },
6030 { NULL
6031 }
6032 };
6033
@@ -5987,11 +6063,14 @@
6063 Jim_arrayInit(interp);
6064 Jim_stdlibInit(interp);
6065 Jim_tclcompatInit(interp);
6066 return JIM_OK;
6067 }
6068 #define JIM_OPTIMIZATION
6069 #ifndef _GNU_SOURCE
6070 #define _GNU_SOURCE
6071 #endif
6072
6073 #include <stdio.h>
6074 #include <stdlib.h>
6075
6076 #include <string.h>
@@ -6056,10 +6135,16 @@
6135 #define JimPanic(X) JimPanicDump X
6136 #else
6137 #define JimPanic(X)
6138 #endif
6139
6140 #ifdef JIM_OPTIMIZATION
6141 #define JIM_IF_OPTIM(X) X
6142 #else
6143 #define JIM_IF_OPTIM(X)
6144 #endif
6145
6146
6147 static char JimEmptyStringRep[] = "";
6148
6149 static void JimFreeCallFrame(Jim_Interp *interp, Jim_CallFrame *cf, int action);
6150 static int ListSetIndex(Jim_Interp *interp, Jim_Obj *listPtr, int listindex, Jim_Obj *newObjPtr,
@@ -6112,34 +6197,34 @@
6197 if (*pattern == '^') {
6198 not++;
6199 pattern++;
6200 }
6201
6202
6203 if (*pattern == ']') {
6204 goto first;
6205 }
6206 }
6207
6208 while (*pattern && *pattern != ']') {
6209
6210 if (pattern[0] == '\\') {
6211 first:
6212 pattern += utf8_tounicode_case(pattern, &pchar, nocase);
6213 }
6214 else {
6215
6216 int start;
6217 int end;
6218
6219 pattern += utf8_tounicode_case(pattern, &start, nocase);
6220 if (pattern[0] == '-' && pattern[1]) {
6221
6222 pattern++;
6223 pattern += utf8_tounicode_case(pattern, &end, nocase);
6224
6225
6226 if ((c >= start && c <= end) || (c >= end && c <= start)) {
6227 match = 1;
6228 }
6229 continue;
6230 }
@@ -6169,19 +6254,19 @@
6254 while (pattern[1] == '*') {
6255 pattern++;
6256 }
6257 pattern++;
6258 if (!pattern[0]) {
6259 return 1;
6260 }
6261 while (*string) {
6262
6263 if (JimGlobMatch(pattern, string, nocase))
6264 return 1;
6265 string += utf8_tounicode(string, &c);
6266 }
6267 return 0;
6268
6269 case '?':
6270 string += utf8_tounicode(string, &c);
6271 break;
6272
@@ -6190,20 +6275,20 @@
6275 pattern = JimCharsetMatch(pattern + 1, c, nocase ? JIM_NOCASE : 0);
6276 if (!pattern) {
6277 return 0;
6278 }
6279 if (!*pattern) {
6280
6281 continue;
6282 }
6283 break;
6284 }
6285 case '\\':
6286 if (pattern[1]) {
6287 pattern++;
6288 }
6289
6290 default:
6291 string += utf8_tounicode_case(string, &c, nocase);
6292 utf8_tounicode_case(pattern, &pchar, nocase);
6293 if (pchar != c) {
6294 return 0;
@@ -6249,11 +6334,11 @@
6334 maxchars--;
6335 }
6336 if (!maxchars) {
6337 return 0;
6338 }
6339
6340 if (*s1) {
6341 return 1;
6342 }
6343 if (*s2) {
6344 return -1;
@@ -6290,11 +6375,11 @@
6375 const char *p;
6376
6377 if (!l1 || !l2 || l1 > l2)
6378 return -1;
6379
6380
6381 for (p = s2 + l2 - 1; p != s2 - 1; p--) {
6382 if (*p == *s1 && memcmp(s1, p, l1) == 0) {
6383 return p - s2;
6384 }
6385 }
@@ -6349,28 +6434,28 @@
6434 }
6435 *sign = 1;
6436 }
6437
6438 if (str[i] != '0') {
6439
6440 return 0;
6441 }
6442
6443
6444 switch (str[i + 1]) {
6445 case 'x': case 'X': *base = 16; break;
6446 case 'o': case 'O': *base = 8; break;
6447 case 'b': case 'B': *base = 2; break;
6448 default: return 0;
6449 }
6450 i += 2;
6451
6452 if (str[i] != '-' && str[i] != '+' && !isspace(UCHAR(str[i]))) {
6453
6454 return i;
6455 }
6456
6457 *base = 10;
6458 return 0;
6459 }
6460
6461 static long jim_strtol(const char *str, char **endptr)
@@ -6384,11 +6469,11 @@
6469 if (endptr == NULL || *endptr != str + i) {
6470 return value * sign;
6471 }
6472 }
6473
6474
6475 return strtol(str, endptr, 10);
6476 }
6477
6478
6479 static jim_wide jim_strtoull(const char *str, char **endptr)
@@ -6403,11 +6488,11 @@
6488 if (endptr == NULL || *endptr != str + i) {
6489 return value * sign;
6490 }
6491 }
6492
6493
6494 return strtoull(str, endptr, 10);
6495 #else
6496 return (unsigned long)jim_strtol(str, endptr);
6497 #endif
6498 }
@@ -6428,26 +6513,40 @@
6513
6514 int Jim_StringToDouble(const char *str, double *doublePtr)
6515 {
6516 char *endptr;
6517
6518
6519 errno = 0;
6520
6521 *doublePtr = strtod(str, &endptr);
6522
6523 return JimCheckConversion(str, endptr);
6524 }
6525
6526 static jim_wide JimPowWide(jim_wide b, jim_wide e)
6527 {
6528 jim_wide res = 1;
6529
6530
6531 if (b == 1) {
6532
6533 return 1;
6534 }
6535 if (e < 0) {
6536 if (b != -1) {
6537 return 0;
6538 }
6539 e = -e;
6540 }
6541 while (e)
6542 {
6543 if (e & 1) {
6544 res *= b;
6545 }
6546 e >>= 1;
6547 b *= b;
6548 }
6549 return res;
6550 }
6551
6552 #ifdef JIM_DEBUG_PANIC
@@ -6509,11 +6608,11 @@
6608 char *Jim_StrDupLen(const char *s, int l)
6609 {
6610 char *copy = Jim_Alloc(l + 1);
6611
6612 memcpy(copy, s, l + 1);
6613 copy[l] = 0;
6614 return copy;
6615 }
6616
6617
6618
@@ -6598,52 +6697,52 @@
6697 }
6698
6699
6700 void Jim_ExpandHashTable(Jim_HashTable *ht, unsigned int size)
6701 {
6702 Jim_HashTable n;
6703 unsigned int realsize = JimHashTableNextPower(size), i;
6704
6705 if (size <= ht->used)
6706 return;
6707
6708 Jim_InitHashTable(&n, ht->type, ht->privdata);
6709 n.size = realsize;
6710 n.sizemask = realsize - 1;
6711 n.table = Jim_Alloc(realsize * sizeof(Jim_HashEntry *));
6712
6713 n.uniq = ht->uniq;
6714
6715
6716 memset(n.table, 0, realsize * sizeof(Jim_HashEntry *));
6717
6718 n.used = ht->used;
6719 for (i = 0; ht->used > 0; i++) {
6720 Jim_HashEntry *he, *nextHe;
6721
6722 if (ht->table[i] == NULL)
6723 continue;
6724
6725
6726 he = ht->table[i];
6727 while (he) {
6728 unsigned int h;
6729
6730 nextHe = he->next;
6731
6732 h = Jim_HashKey(ht, he->key) & n.sizemask;
6733 he->next = n.table[h];
6734 n.table[h] = he;
6735 ht->used--;
6736
6737 he = nextHe;
6738 }
6739 }
6740 assert(ht->used == 0);
6741 Jim_Free(ht->table);
6742
6743
6744 *ht = n;
6745 }
6746
6747
6748 int Jim_AddHashEntry(Jim_HashTable *ht, const void *key, void *val)
@@ -6652,11 +6751,11 @@
6751
6752 entry = JimInsertHashEntry(ht, key, 0);
6753 if (entry == NULL)
6754 return JIM_ERR;
6755
6756
6757 Jim_SetHashKey(ht, entry, key);
6758 Jim_SetHashVal(ht, entry, val);
6759 return JIM_OK;
6760 }
6761
@@ -6678,11 +6777,11 @@
6777 Jim_SetHashVal(ht, entry, val);
6778 }
6779 existed = 1;
6780 }
6781 else {
6782
6783 Jim_SetHashKey(ht, entry, key);
6784 Jim_SetHashVal(ht, entry, val);
6785 existed = 0;
6786 }
6787
@@ -6701,11 +6800,11 @@
6800 he = ht->table[h];
6801
6802 prevHe = NULL;
6803 while (he) {
6804 if (Jim_CompareHashKeys(ht, key, he->key)) {
6805
6806 if (prevHe)
6807 prevHe->next = he->next;
6808 else
6809 ht->table[h] = he->next;
6810 Jim_FreeEntryKey(ht, he);
@@ -6715,19 +6814,19 @@
6814 return JIM_OK;
6815 }
6816 prevHe = he;
6817 he = he->next;
6818 }
6819 return JIM_ERR;
6820 }
6821
6822
6823 int Jim_FreeHashTable(Jim_HashTable *ht)
6824 {
6825 unsigned int i;
6826
6827
6828 for (i = 0; ht->used > 0; i++) {
6829 Jim_HashEntry *he, *nextHe;
6830
6831 if ((he = ht->table[i]) == NULL)
6832 continue;
@@ -6738,15 +6837,15 @@
6837 Jim_Free(he);
6838 ht->used--;
6839 he = nextHe;
6840 }
6841 }
6842
6843 Jim_Free(ht->table);
6844
6845 JimResetHashTable(ht);
6846 return JIM_OK;
6847 }
6848
6849 Jim_HashEntry *Jim_FindHashEntry(Jim_HashTable *ht, const void *key)
6850 {
6851 Jim_HashEntry *he;
@@ -6819,24 +6918,24 @@
6918 static Jim_HashEntry *JimInsertHashEntry(Jim_HashTable *ht, const void *key, int replace)
6919 {
6920 unsigned int h;
6921 Jim_HashEntry *he;
6922
6923
6924 JimExpandHashTableIfNeeded(ht);
6925
6926
6927 h = Jim_HashKey(ht, key) & ht->sizemask;
6928
6929 he = ht->table[h];
6930 while (he) {
6931 if (Jim_CompareHashKeys(ht, key, he->key))
6932 return replace ? he : NULL;
6933 he = he->next;
6934 }
6935
6936
6937 he = Jim_Alloc(sizeof(*he));
6938 he->next = ht->table[h];
6939 ht->table[h] = he;
6940 ht->used++;
6941 he->key = NULL;
@@ -6865,16 +6964,16 @@
6964 {
6965 Jim_Free(key);
6966 }
6967
6968 static const Jim_HashTableType JimPackageHashTableType = {
6969 JimStringCopyHTHashFunction,
6970 JimStringCopyHTDup,
6971 NULL,
6972 JimStringCopyHTKeyCompare,
6973 JimStringCopyHTKeyDestructor,
6974 NULL
6975 };
6976
6977 typedef struct AssocDataValue
6978 {
6979 Jim_InterpDeleteProc *delProc;
@@ -6889,16 +6988,16 @@
6988 assocPtr->delProc((Jim_Interp *)privdata, assocPtr->data);
6989 Jim_Free(data);
6990 }
6991
6992 static const Jim_HashTableType JimAssocDataHashTableType = {
6993 JimStringCopyHTHashFunction,
6994 JimStringCopyHTDup,
6995 NULL,
6996 JimStringCopyHTKeyCompare,
6997 JimStringCopyHTKeyDestructor,
6998 JimAssocDataHashTableValueDestructor
6999 };
7000
7001 void Jim_InitStack(Jim_Stack *stack)
7002 {
7003 stack->len = 0;
@@ -6951,56 +7050,61 @@
7050 freeFunc(stack->vector[i]);
7051 }
7052
7053
7054
7055 #define JIM_TT_NONE 0
7056 #define JIM_TT_STR 1
7057 #define JIM_TT_ESC 2
7058 #define JIM_TT_VAR 3
7059 #define JIM_TT_DICTSUGAR 4
7060 #define JIM_TT_CMD 5
7061
7062 #define JIM_TT_SEP 6
7063 #define JIM_TT_EOL 7
7064 #define JIM_TT_EOF 8
7065
7066 #define JIM_TT_LINE 9
7067 #define JIM_TT_WORD 10
7068
7069
7070 #define JIM_TT_SUBEXPR_START 11
7071 #define JIM_TT_SUBEXPR_END 12
7072 #define JIM_TT_SUBEXPR_COMMA 13
7073 #define JIM_TT_EXPR_INT 14
7074 #define JIM_TT_EXPR_DOUBLE 15
7075 #define JIM_TT_EXPR_BOOLEAN 16
7076
7077 #define JIM_TT_EXPRSUGAR 17
7078
7079
7080 #define JIM_TT_EXPR_OP 20
7081
7082 #define TOKEN_IS_SEP(type) (type >= JIM_TT_SEP && type <= JIM_TT_EOF)
7083
7084 #define TOKEN_IS_EXPR_START(type) (type == JIM_TT_NONE || type == JIM_TT_SUBEXPR_START || type == JIM_TT_SUBEXPR_COMMA)
7085
7086 #define TOKEN_IS_EXPR_OP(type) (type >= JIM_TT_EXPR_OP)
7087
7088 struct JimParseMissing {
7089 int ch;
7090 int line;
7091 };
7092
7093 struct JimParserCtx
7094 {
7095 const char *p;
7096 int len;
7097 int linenr;
7098 const char *tstart;
7099 const char *tend;
7100 int tline;
7101 int tt;
7102 int eof;
7103 int inquote;
7104 int comment;
7105 struct JimParseMissing missing;
7106 };
7107
7108 static int JimParseScript(struct JimParserCtx *pc);
7109 static int JimParseSep(struct JimParserCtx *pc);
7110 static int JimParseEol(struct JimParserCtx *pc);
@@ -7030,11 +7134,11 @@
7134 pc->missing.line = linenr;
7135 }
7136
7137 static int JimParseScript(struct JimParserCtx *pc)
7138 {
7139 while (1) {
7140 if (!pc->len) {
7141 pc->tstart = pc->p;
7142 pc->tend = pc->p - 1;
7143 pc->tline = pc->linenr;
7144 pc->tt = JIM_TT_EOL;
@@ -7066,11 +7170,11 @@
7170 pc->comment = 0;
7171 return JimParseCmd(pc);
7172 case '$':
7173 pc->comment = 0;
7174 if (JimParseVar(pc) == JIM_ERR) {
7175
7176 pc->tstart = pc->tend = pc->p++;
7177 pc->len--;
7178 pc->tt = JIM_TT_ESC;
7179 }
7180 return JIM_OK;
@@ -7127,11 +7231,11 @@
7231
7232 static void JimParseSubBrace(struct JimParserCtx *pc)
7233 {
7234 int level = 1;
7235
7236
7237 pc->p++;
7238 pc->len--;
7239 while (pc->len) {
7240 switch (*pc->p) {
7241 case '\\':
@@ -7171,11 +7275,11 @@
7275 static int JimParseSubQuote(struct JimParserCtx *pc)
7276 {
7277 int tt = JIM_TT_STR;
7278 int line = pc->tline;
7279
7280
7281 pc->p++;
7282 pc->len--;
7283 while (pc->len) {
7284 switch (*pc->p) {
7285 case '\\':
@@ -7220,11 +7324,11 @@
7324 {
7325 int level = 1;
7326 int startofword = 1;
7327 int line = pc->tline;
7328
7329
7330 pc->p++;
7331 pc->len--;
7332 while (pc->len) {
7333 switch (*pc->p) {
7334 case '\\':
@@ -7300,17 +7404,17 @@
7404 return JIM_OK;
7405 }
7406
7407 static int JimParseVar(struct JimParserCtx *pc)
7408 {
7409
7410 pc->p++;
7411 pc->len--;
7412
7413 #ifdef EXPRSUGAR_BRACKET
7414 if (*pc->p == '[') {
7415
7416 JimParseCmd(pc);
7417 pc->tt = JIM_TT_EXPRSUGAR;
7418 return JIM_OK;
7419 }
7420 #endif
@@ -7336,11 +7440,11 @@
7440 pc->len--;
7441 }
7442 }
7443 else {
7444 while (1) {
7445
7446 if (pc->p[0] == ':' && pc->p[1] == ':') {
7447 while (*pc->p == ':') {
7448 pc->p++;
7449 pc->len--;
7450 }
@@ -7351,11 +7455,11 @@
7455 pc->len--;
7456 continue;
7457 }
7458 break;
7459 }
7460
7461 if (*pc->p == '(') {
7462 int count = 1;
7463 const char *paren = NULL;
7464
7465 pc->tt = JIM_TT_DICTSUGAR;
@@ -7378,11 +7482,11 @@
7482 if (count == 0) {
7483 pc->p++;
7484 pc->len--;
7485 }
7486 else if (paren) {
7487
7488 paren++;
7489 pc->len += (pc->p - paren);
7490 pc->p = paren;
7491 }
7492 #ifndef EXPRSUGAR_BRACKET
@@ -7403,19 +7507,19 @@
7507
7508 static int JimParseStr(struct JimParserCtx *pc)
7509 {
7510 if (pc->tt == JIM_TT_SEP || pc->tt == JIM_TT_EOL ||
7511 pc->tt == JIM_TT_NONE || pc->tt == JIM_TT_STR) {
7512
7513 if (*pc->p == '{') {
7514 return JimParseBrace(pc);
7515 }
7516 if (*pc->p == '"') {
7517 pc->inquote = 1;
7518 pc->p++;
7519 pc->len--;
7520
7521 pc->missing.line = pc->tline;
7522 }
7523 }
7524 pc->tstart = pc->p;
7525 pc->tline = pc->linenr;
@@ -7441,25 +7545,25 @@
7545 }
7546 pc->p++;
7547 pc->len--;
7548 }
7549 else if (pc->len == 1) {
7550
7551 pc->missing.ch = '\\';
7552 }
7553 break;
7554 case '(':
7555
7556 if (pc->len > 1 && pc->p[1] != '$') {
7557 break;
7558 }
7559
7560 case ')':
7561
7562 if (*pc->p == '(' || pc->tt == JIM_TT_VAR) {
7563 if (pc->p == pc->tstart) {
7564
7565 pc->p++;
7566 pc->len--;
7567 }
7568 pc->tend = pc->p - 1;
7569 pc->tt = JIM_TT_ESC;
@@ -7499,11 +7603,11 @@
7603 break;
7604 }
7605 pc->p++;
7606 pc->len--;
7607 }
7608 return JIM_OK;
7609 }
7610
7611 static int JimParseComment(struct JimParserCtx *pc)
7612 {
7613 while (*pc->p) {
@@ -7610,34 +7714,34 @@
7714 if (c == -1) {
7715 break;
7716 }
7717 val = (val << 4) | c;
7718 }
7719
7720 if (s[i] == '{') {
7721 if (k == 0 || val > 0x1fffff || s[i + k + 1] != '}') {
7722
7723 i--;
7724 k = 0;
7725 }
7726 else {
7727
7728 k++;
7729 }
7730 }
7731 if (k) {
7732
7733 if (s[i] == 'x') {
7734 *p++ = val;
7735 }
7736 else {
7737 p += utf8_fromunicode(p, val);
7738 }
7739 i += k;
7740 break;
7741 }
7742
7743 *p++ = s[i];
7744 }
7745 break;
7746 case 'v':
7747 *p++ = 0xb;
@@ -7646,11 +7750,11 @@
7750 case '\0':
7751 *p++ = '\\';
7752 i++;
7753 break;
7754 case '\n':
7755
7756 *p++ = ' ';
7757 do {
7758 i++;
7759 } while (s[i + 1] == ' ' || s[i + 1] == '\t');
7760 break;
@@ -7660,11 +7764,11 @@
7764 case '3':
7765 case '4':
7766 case '5':
7767 case '6':
7768 case '7':
7769
7770 {
7771 int val = 0;
7772 int c = odigitval(s[i + 1]);
7773
7774 val = c;
@@ -7708,27 +7812,23 @@
7812 char *token;
7813 int len;
7814
7815 start = pc->tstart;
7816 end = pc->tend;
7817 len = (end - start) + 1;
7818 if (len < 0) {
7819 len = 0;
7820 }
7821 token = Jim_Alloc(len + 1);
7822 if (pc->tt != JIM_TT_ESC) {
7823
7824 memcpy(token, start, len);
7825 token[len] = '\0';
7826 }
7827 else {
7828
7829 len = JimEscape(token, start, len);
 
 
 
 
 
7830 }
7831
7832 return Jim_NewStringObjNoAlloc(interp, token, len);
7833 }
7834
@@ -7790,11 +7890,11 @@
7890 while (pc->len) {
7891 switch (*pc->p) {
7892 case '\\':
7893 pc->tt = JIM_TT_ESC;
7894 if (--pc->len == 0) {
7895
7896 pc->tend = pc->p;
7897 return JIM_OK;
7898 }
7899 pc->p++;
7900 break;
@@ -7826,11 +7926,11 @@
7926 pc->tend = pc->p - 1;
7927 return JIM_OK;
7928 }
7929 if (*pc->p == '\\') {
7930 if (--pc->len == 0) {
7931
7932 pc->tend = pc->p;
7933 return JIM_OK;
7934 }
7935 pc->tt = JIM_TT_ESC;
7936 pc->p++;
@@ -7846,24 +7946,24 @@
7946
7947 Jim_Obj *Jim_NewObj(Jim_Interp *interp)
7948 {
7949 Jim_Obj *objPtr;
7950
7951
7952 if (interp->freeList != NULL) {
7953
7954 objPtr = interp->freeList;
7955 interp->freeList = objPtr->nextObjPtr;
7956 }
7957 else {
7958
7959 objPtr = Jim_Alloc(sizeof(*objPtr));
7960 }
7961
7962 objPtr->refCount = 0;
7963
7964
7965 objPtr->prevObjPtr = NULL;
7966 objPtr->nextObjPtr = interp->liveList;
7967 if (interp->liveList)
7968 interp->liveList->prevObjPtr = objPtr;
7969 interp->liveList = objPtr;
@@ -7871,32 +7971,32 @@
7971 return objPtr;
7972 }
7973
7974 void Jim_FreeObj(Jim_Interp *interp, Jim_Obj *objPtr)
7975 {
7976
7977 JimPanic((objPtr->refCount != 0, "!!!Object %p freed with bad refcount %d, type=%s", objPtr,
7978 objPtr->refCount, objPtr->typePtr ? objPtr->typePtr->name : "<none>"));
7979
7980
7981 Jim_FreeIntRep(interp, objPtr);
7982
7983 if (objPtr->bytes != NULL) {
7984 if (objPtr->bytes != JimEmptyStringRep)
7985 Jim_Free(objPtr->bytes);
7986 }
7987
7988 if (objPtr->prevObjPtr)
7989 objPtr->prevObjPtr->nextObjPtr = objPtr->nextObjPtr;
7990 if (objPtr->nextObjPtr)
7991 objPtr->nextObjPtr->prevObjPtr = objPtr->prevObjPtr;
7992 if (interp->liveList == objPtr)
7993 interp->liveList = objPtr->nextObjPtr;
7994 #ifdef JIM_DISABLE_OBJECT_POOL
7995 Jim_Free(objPtr);
7996 #else
7997
7998 objPtr->prevObjPtr = NULL;
7999 objPtr->nextObjPtr = interp->freeList;
8000 if (interp->freeList)
8001 interp->freeList->prevObjPtr = objPtr;
8002 interp->freeList = objPtr;
@@ -7919,45 +8019,44 @@
8019 {
8020 Jim_Obj *dupPtr;
8021
8022 dupPtr = Jim_NewObj(interp);
8023 if (objPtr->bytes == NULL) {
8024
8025 dupPtr->bytes = NULL;
8026 }
8027 else if (objPtr->length == 0) {
 
8028 dupPtr->bytes = JimEmptyStringRep;
8029 dupPtr->length = 0;
8030 dupPtr->typePtr = NULL;
8031 return dupPtr;
8032 }
8033 else {
8034 dupPtr->bytes = Jim_Alloc(objPtr->length + 1);
8035 dupPtr->length = objPtr->length;
8036
8037 memcpy(dupPtr->bytes, objPtr->bytes, objPtr->length + 1);
8038 }
8039
8040
8041 dupPtr->typePtr = objPtr->typePtr;
8042 if (objPtr->typePtr != NULL) {
8043 if (objPtr->typePtr->dupIntRepProc == NULL) {
8044 dupPtr->internalRep = objPtr->internalRep;
8045 }
8046 else {
8047
8048 objPtr->typePtr->dupIntRepProc(interp, objPtr, dupPtr);
8049 }
8050 }
8051 return dupPtr;
8052 }
8053
8054 const char *Jim_GetString(Jim_Obj *objPtr, int *lenPtr)
8055 {
8056 if (objPtr->bytes == NULL) {
8057
8058 JimPanic((objPtr->typePtr->updateStringProc == NULL, "UpdateStringProc called against '%s' type.", objPtr->typePtr->name));
8059 objPtr->typePtr->updateStringProc(objPtr);
8060 }
8061 if (lenPtr)
8062 *lenPtr = objPtr->length;
@@ -7966,25 +8065,22 @@
8065
8066
8067 int Jim_Length(Jim_Obj *objPtr)
8068 {
8069 if (objPtr->bytes == NULL) {
8070
8071 Jim_GetString(objPtr, NULL);
 
8072 }
8073 return objPtr->length;
8074 }
8075
8076
8077 const char *Jim_String(Jim_Obj *objPtr)
8078 {
8079 if (objPtr->bytes == NULL) {
8080
8081 Jim_GetString(objPtr, NULL);
 
 
8082 }
8083 return objPtr->bytes;
8084 }
8085
8086 static void JimSetStringBytes(Jim_Obj *objPtr, const char *str)
@@ -8001,23 +8097,34 @@
8097 FreeDictSubstInternalRep,
8098 DupDictSubstInternalRep,
8099 NULL,
8100 JIM_TYPE_NONE,
8101 };
8102
8103 static void FreeInterpolatedInternalRep(Jim_Interp *interp, Jim_Obj *objPtr);
8104 static void DupInterpolatedInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr);
8105
8106 static const Jim_ObjType interpolatedObjType = {
8107 "interpolated",
8108 FreeInterpolatedInternalRep,
8109 DupInterpolatedInternalRep,
8110 NULL,
8111 JIM_TYPE_NONE,
8112 };
8113
8114 static void FreeInterpolatedInternalRep(Jim_Interp *interp, Jim_Obj *objPtr)
8115 {
8116 Jim_DecrRefCount(interp, objPtr->internalRep.dictSubstValue.indexObjPtr);
8117 }
8118
8119 static void DupInterpolatedInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr)
8120 {
8121
8122 dupPtr->internalRep = srcPtr->internalRep;
8123
8124 Jim_IncrRefCount(dupPtr->internalRep.dictSubstValue.indexObjPtr);
8125 }
8126
8127 static void DupStringInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr);
8128 static int SetStringFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr);
8129
8130 static const Jim_ObjType stringObjType = {
@@ -8037,22 +8144,22 @@
8144 }
8145
8146 static int SetStringFromAny(Jim_Interp *interp, Jim_Obj *objPtr)
8147 {
8148 if (objPtr->typePtr != &stringObjType) {
8149
8150 if (objPtr->bytes == NULL) {
8151
8152 JimPanic((objPtr->typePtr->updateStringProc == NULL, "UpdateStringProc called against '%s' type.", objPtr->typePtr->name));
8153 objPtr->typePtr->updateStringProc(objPtr);
8154 }
8155
8156 Jim_FreeIntRep(interp, objPtr);
8157
8158 objPtr->typePtr = &stringObjType;
8159 objPtr->internalRep.strValue.maxLength = objPtr->length;
8160
8161 objPtr->internalRep.strValue.charLength = -1;
8162 }
8163 return JIM_OK;
8164 }
8165
@@ -8073,39 +8180,37 @@
8180
8181 Jim_Obj *Jim_NewStringObj(Jim_Interp *interp, const char *s, int len)
8182 {
8183 Jim_Obj *objPtr = Jim_NewObj(interp);
8184
8185
8186 if (len == -1)
8187 len = strlen(s);
8188
8189 if (len == 0) {
8190 objPtr->bytes = JimEmptyStringRep;
8191 }
8192 else {
8193 objPtr->bytes = Jim_StrDupLen(s, len);
 
 
8194 }
8195 objPtr->length = len;
8196
8197
8198 objPtr->typePtr = NULL;
8199 return objPtr;
8200 }
8201
8202
8203 Jim_Obj *Jim_NewStringObjUtf8(Jim_Interp *interp, const char *s, int charlen)
8204 {
8205 #ifdef JIM_UTF8
8206
8207 int bytelen = utf8_index(s, charlen);
8208
8209 Jim_Obj *objPtr = Jim_NewStringObj(interp, s, bytelen);
8210
8211
8212 objPtr->typePtr = &stringObjType;
8213 objPtr->internalRep.strValue.maxLength = bytelen;
8214 objPtr->internalRep.strValue.charLength = charlen;
8215
8216 return objPtr;
@@ -8132,11 +8237,11 @@
8237 len = strlen(str);
8238 needlen = objPtr->length + len;
8239 if (objPtr->internalRep.strValue.maxLength < needlen ||
8240 objPtr->internalRep.strValue.maxLength == 0) {
8241 needlen *= 2;
8242
8243 if (needlen < 7) {
8244 needlen = 7;
8245 }
8246 if (objPtr->bytes == JimEmptyStringRep) {
8247 objPtr->bytes = Jim_Alloc(needlen + 1);
@@ -8148,11 +8253,11 @@
8253 }
8254 memcpy(objPtr->bytes + objPtr->length, str, len);
8255 objPtr->bytes[objPtr->length + len] = '\0';
8256
8257 if (objPtr->internalRep.strValue.charLength >= 0) {
8258
8259 objPtr->internalRep.strValue.charLength += utf8_strlen(objPtr->bytes + objPtr->length, len);
8260 }
8261 objPtr->length += len;
8262 }
8263
@@ -8210,11 +8315,11 @@
8315 int l1, l2;
8316 const char *s1 = Jim_GetString(firstObjPtr, &l1);
8317 const char *s2 = Jim_GetString(secondObjPtr, &l2);
8318
8319 if (nocase) {
8320
8321 return JimStringCompareLen(s1, s2, -1, nocase);
8322 }
8323 return JimStringCompare(s1, l1, s2, l2);
8324 }
8325
@@ -8312,11 +8417,11 @@
8417
8418 if (first == 0 && rangeLen == len) {
8419 return strObjPtr;
8420 }
8421 if (len == bytelen) {
8422
8423 return Jim_NewStringObj(interp, str + first, rangeLen);
8424 }
8425 return Jim_NewStringObjUtf8(interp, str + utf8_index(str, first), rangeLen);
8426 #else
8427 return Jim_StringByteRangeObj(interp, strObjPtr, firstObjPtr, lastObjPtr);
@@ -8341,19 +8446,19 @@
8446 return strObjPtr;
8447 }
8448
8449 str = Jim_String(strObjPtr);
8450
8451
8452 objPtr = Jim_NewStringObjUtf8(interp, str, first);
8453
8454
8455 if (newStrObj) {
8456 Jim_AppendObj(interp, objPtr, newStrObj);
8457 }
8458
8459
8460 Jim_AppendString(interp, objPtr, str + utf8_index(str, last + 1), len - last - 1);
8461
8462 return objPtr;
8463 }
8464
@@ -8371,12 +8476,10 @@
8476 {
8477 char *buf;
8478 int len;
8479 const char *str;
8480
 
 
8481 str = Jim_GetString(strObjPtr, &len);
8482
8483 #ifdef JIM_UTF8
8484 len *= 2;
8485 #endif
@@ -8389,14 +8492,10 @@
8492 {
8493 char *buf;
8494 const char *str;
8495 int len;
8496
 
 
 
 
8497 str = Jim_GetString(strObjPtr, &len);
8498
8499 #ifdef JIM_UTF8
8500 len *= 2;
8501 #endif
@@ -8411,13 +8510,11 @@
8510 int len;
8511 int c;
8512 const char *str;
8513
8514 str = Jim_GetString(strObjPtr, &len);
8515
 
 
8516 #ifdef JIM_UTF8
8517 len *= 2;
8518 #endif
8519 buf = p = Jim_Alloc(len + 1);
8520
@@ -8452,11 +8549,11 @@
8549 while (len) {
8550 int c;
8551 int n = utf8_tounicode(str, &c);
8552
8553 if (utf8_memchr(trimchars, trimlen, c) == NULL) {
8554
8555 break;
8556 }
8557 str += n;
8558 len -= n;
8559 }
@@ -8523,41 +8620,41 @@
8620
8621 len = Jim_Length(strObjPtr);
8622 nontrim = JimFindTrimRight(strObjPtr->bytes, len, trimchars, trimcharslen);
8623
8624 if (nontrim == NULL) {
8625
8626 return Jim_NewEmptyStringObj(interp);
8627 }
8628 if (nontrim == strObjPtr->bytes + len) {
8629
8630 return strObjPtr;
8631 }
8632
8633 if (Jim_IsShared(strObjPtr)) {
8634 strObjPtr = Jim_NewStringObj(interp, strObjPtr->bytes, (nontrim - strObjPtr->bytes));
8635 }
8636 else {
8637
8638 strObjPtr->bytes[nontrim - strObjPtr->bytes] = 0;
8639 strObjPtr->length = (nontrim - strObjPtr->bytes);
8640 }
8641
8642 return strObjPtr;
8643 }
8644
8645 static Jim_Obj *JimStringTrim(Jim_Interp *interp, Jim_Obj *strObjPtr, Jim_Obj *trimcharsObjPtr)
8646 {
8647
8648 Jim_Obj *objPtr = JimStringTrimLeft(interp, strObjPtr, trimcharsObjPtr);
8649
8650
8651 strObjPtr = JimStringTrimRight(interp, objPtr, trimcharsObjPtr);
8652
8653
8654 if (objPtr != strObjPtr && objPtr->refCount == 0) {
8655
8656 Jim_FreeNewObj(interp, objPtr);
8657 }
8658
8659 return strObjPtr;
8660 }
@@ -8575,17 +8672,17 @@
8672 static int JimStringIs(Jim_Interp *interp, Jim_Obj *strObjPtr, Jim_Obj *strClass, int strict)
8673 {
8674 static const char * const strclassnames[] = {
8675 "integer", "alpha", "alnum", "ascii", "digit",
8676 "double", "lower", "upper", "space", "xdigit",
8677 "control", "print", "graph", "punct", "boolean",
8678 NULL
8679 };
8680 enum {
8681 STR_IS_INTEGER, STR_IS_ALPHA, STR_IS_ALNUM, STR_IS_ASCII, STR_IS_DIGIT,
8682 STR_IS_DOUBLE, STR_IS_LOWER, STR_IS_UPPER, STR_IS_SPACE, STR_IS_XDIGIT,
8683 STR_IS_CONTROL, STR_IS_PRINT, STR_IS_GRAPH, STR_IS_PUNCT, STR_IS_BOOLEAN,
8684 };
8685 int strclass;
8686 int len;
8687 int i;
8688 const char *str;
@@ -8613,10 +8710,17 @@
8710 {
8711 double d;
8712 Jim_SetResultBool(interp, Jim_GetDouble(interp, strObjPtr, &d) == JIM_OK && errno != ERANGE);
8713 return JIM_OK;
8714 }
8715
8716 case STR_IS_BOOLEAN:
8717 {
8718 int b;
8719 Jim_SetResultBool(interp, Jim_GetBoolean(interp, strObjPtr, &b) == JIM_OK);
8720 return JIM_OK;
8721 }
8722
8723 case STR_IS_ALPHA: isclassfunc = isalpha; break;
8724 case STR_IS_ALNUM: isclassfunc = isalnum; break;
8725 case STR_IS_ASCII: isclassfunc = jim_isascii; break;
8726 case STR_IS_DIGIT: isclassfunc = isdigit; break;
@@ -8631,11 +8735,11 @@
8735 default:
8736 return JIM_ERR;
8737 }
8738
8739 for (i = 0; i < len; i++) {
8740 if (!isclassfunc(UCHAR(str[i]))) {
8741 Jim_SetResultBool(interp, 0);
8742 return JIM_OK;
8743 }
8744 }
8745 Jim_SetResultBool(interp, 1);
@@ -8656,20 +8760,18 @@
8760 {
8761 if (objPtr->typePtr == &comparedStringObjType && objPtr->internalRep.ptr == str) {
8762 return 1;
8763 }
8764 else {
8765 if (strcmp(str, Jim_String(objPtr)) != 0)
 
 
8766 return 0;
8767
8768 if (objPtr->typePtr != &comparedStringObjType) {
8769 Jim_FreeIntRep(interp, objPtr);
8770 objPtr->typePtr = &comparedStringObjType;
8771 }
8772 objPtr->internalRep.ptr = (char *)str;
8773 return 1;
8774 }
8775 }
8776
8777 static int qsortCompareStringPointers(const void *a, const void *b)
@@ -8758,20 +8860,20 @@
8860 int type;
8861 } ScriptToken;
8862
8863 typedef struct ScriptObj
8864 {
8865 ScriptToken *token;
8866 Jim_Obj *fileNameObj;
8867 int len;
8868 int substFlags;
8869 int inUse; /* Used to share a ScriptObj. Currently
8870 only used by Jim_EvalObj() as protection against
8871 shimmering of the currently evaluated object. */
8872 int firstline;
8873 int linenr;
8874 int missing;
8875 } ScriptObj;
8876
8877 static void JimSetScriptFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr);
8878 static int JimParseCheckMissing(Jim_Interp *interp, int ch);
8879 static ScriptObj *JimGetScript(Jim_Interp *interp, Jim_Obj *objPtr);
@@ -8799,23 +8901,23 @@
8901 dupPtr->typePtr = NULL;
8902 }
8903
8904 typedef struct
8905 {
8906 const char *token;
8907 int len;
8908 int type;
8909 int line;
8910 } ParseToken;
8911
8912 typedef struct
8913 {
8914
8915 ParseToken *list;
8916 int size;
8917 int count;
8918 ParseToken static_list[20];
8919 } ParseTokenList;
8920
8921 static void ScriptTokenListInit(ParseTokenList *tokenlist)
8922 {
8923 tokenlist->list = tokenlist->static_list;
@@ -8834,18 +8936,18 @@
8936 int line)
8937 {
8938 ParseToken *t;
8939
8940 if (tokenlist->count == tokenlist->size) {
8941
8942 tokenlist->size *= 2;
8943 if (tokenlist->list != tokenlist->static_list) {
8944 tokenlist->list =
8945 Jim_Realloc(tokenlist->list, tokenlist->size * sizeof(*tokenlist->list));
8946 }
8947 else {
8948
8949 tokenlist->list = Jim_Alloc(tokenlist->size * sizeof(*tokenlist->list));
8950 memcpy(tokenlist->list, tokenlist->static_list,
8951 tokenlist->count * sizeof(*tokenlist->list));
8952 }
8953 }
@@ -8854,25 +8956,32 @@
8956 t->len = len;
8957 t->type = type;
8958 t->line = line;
8959 }
8960
8961 static int JimCountWordTokens(struct ScriptObj *script, ParseToken *t)
8962 {
8963 int expand = 1;
8964 int count = 0;
8965
8966
8967 if (t->type == JIM_TT_STR && !TOKEN_IS_SEP(t[1].type)) {
8968 if ((t->len == 1 && *t->token == '*') || (t->len == 6 && strncmp(t->token, "expand", 6) == 0)) {
8969
8970 expand = -1;
8971 t++;
8972 }
8973 else {
8974 if (script->missing == ' ') {
8975
8976 script->missing = '}';
8977 script->linenr = t[1].line;
8978 }
8979 }
8980 }
8981
8982
8983 while (!TOKEN_IS_SEP(t->type)) {
8984 t++;
8985 count++;
8986 }
8987
@@ -8882,11 +8991,11 @@
8991 static Jim_Obj *JimMakeScriptObj(Jim_Interp *interp, const ParseToken *t)
8992 {
8993 Jim_Obj *objPtr;
8994
8995 if (t->type == JIM_TT_ESC && memchr(t->token, '\\', t->len) != NULL) {
8996
8997 int len = t->len;
8998 char *str = Jim_Alloc(len + 1);
8999 len = JimEscape(str, t->token, len);
9000 objPtr = Jim_NewStringObjNoAlloc(interp, str, len);
9001 }
@@ -8899,13 +9008,13 @@
9008 static void ScriptObjAddTokens(Jim_Interp *interp, struct ScriptObj *script,
9009 ParseTokenList *tokenlist)
9010 {
9011 int i;
9012 struct ScriptToken *token;
9013
9014 int lineargs = 0;
9015
9016 ScriptToken *linefirst;
9017 int count;
9018 int linenr;
9019
9020 #ifdef DEBUG_SHOW_SCRIPT_TOKENS
@@ -8914,11 +9023,11 @@
9023 printf("[%2d]@%d %s '%.*s'\n", i, tokenlist->list[i].line, jim_tt_name(tokenlist->list[i].type),
9024 tokenlist->list[i].len, tokenlist->list[i].token);
9025 }
9026 #endif
9027
9028
9029 count = tokenlist->count;
9030 for (i = 0; i < tokenlist->count; i++) {
9031 if (tokenlist->list[i].type == JIM_TT_EOL) {
9032 count++;
9033 }
@@ -8925,59 +9034,59 @@
9034 }
9035 linenr = script->firstline = tokenlist->list[0].line;
9036
9037 token = script->token = Jim_Alloc(sizeof(ScriptToken) * count);
9038
9039
9040 linefirst = token++;
9041
9042 for (i = 0; i < tokenlist->count; ) {
9043
9044 int wordtokens;
9045
9046
9047 while (tokenlist->list[i].type == JIM_TT_SEP) {
9048 i++;
9049 }
9050
9051 wordtokens = JimCountWordTokens(script, tokenlist->list + i);
9052
9053 if (wordtokens == 0) {
9054
9055 if (lineargs) {
9056 linefirst->type = JIM_TT_LINE;
9057 linefirst->objPtr = JimNewScriptLineObj(interp, lineargs, linenr);
9058 Jim_IncrRefCount(linefirst->objPtr);
9059
9060
9061 lineargs = 0;
9062 linefirst = token++;
9063 }
9064 i++;
9065 continue;
9066 }
9067 else if (wordtokens != 1) {
9068
9069 token->type = JIM_TT_WORD;
9070 token->objPtr = Jim_NewIntObj(interp, wordtokens);
9071 Jim_IncrRefCount(token->objPtr);
9072 token++;
9073 if (wordtokens < 0) {
9074
9075 i++;
9076 wordtokens = -wordtokens - 1;
9077 lineargs--;
9078 }
9079 }
9080
9081 if (lineargs == 0) {
9082
9083 linenr = tokenlist->list[i].line;
9084 }
9085 lineargs++;
9086
9087
9088 while (wordtokens--) {
9089 const ParseToken *t = &tokenlist->list[i++];
9090
9091 token->type = t->type;
9092 token->objPtr = JimMakeScriptObj(interp, t);
@@ -9010,11 +9119,11 @@
9119 {
9120 ScriptObj *script = JimGetScript(interp, scriptObj);
9121 if (stateCharPtr) {
9122 *stateCharPtr = script->missing;
9123 }
9124 return script->missing == ' ' || script->missing == '}';
9125 }
9126
9127 static int JimParseCheckMissing(Jim_Interp *interp, int ch)
9128 {
9129 const char *msg;
@@ -9028,10 +9137,13 @@
9137 msg = "unmatched \"[\"";
9138 break;
9139 case '{':
9140 msg = "missing close-brace";
9141 break;
9142 case '}':
9143 msg = "extra characters after close-brace";
9144 break;
9145 case '"':
9146 default:
9147 msg = "missing quote";
9148 break;
9149 }
@@ -9049,11 +9161,11 @@
9161 token = script->token = Jim_Alloc(sizeof(ScriptToken) * tokenlist->count);
9162
9163 for (i = 0; i < tokenlist->count; i++) {
9164 const ParseToken *t = &tokenlist->list[i];
9165
9166
9167 token->type = t->type;
9168 token->objPtr = JimMakeScriptObj(interp, t);
9169 Jim_IncrRefCount(token->objPtr);
9170 token++;
9171 }
@@ -9068,29 +9180,29 @@
9180 struct JimParserCtx parser;
9181 struct ScriptObj *script;
9182 ParseTokenList tokenlist;
9183 int line = 1;
9184
9185
9186 if (objPtr->typePtr == &sourceObjType) {
9187 line = objPtr->internalRep.sourceValue.lineNumber;
9188 }
9189
9190
9191 ScriptTokenListInit(&tokenlist);
9192
9193 JimParserInit(&parser, scriptText, scriptTextLen, line);
9194 while (!parser.eof) {
9195 JimParseScript(&parser);
9196 ScriptAddToken(&tokenlist, parser.tstart, parser.tend - parser.tstart + 1, parser.tt,
9197 parser.tline);
9198 }
9199
9200
9201 ScriptAddToken(&tokenlist, scriptText + scriptTextLen, 0, JIM_TT_EOF, 0);
9202
9203
9204 script = Jim_Alloc(sizeof(*script));
9205 memset(script, 0, sizeof(*script));
9206 script->inUse = 1;
9207 if (objPtr->typePtr == &sourceObjType) {
9208 script->fileNameObj = objPtr->internalRep.sourceValue.fileNameObj;
@@ -9102,14 +9214,14 @@
9214 script->missing = parser.missing.ch;
9215 script->linenr = parser.missing.line;
9216
9217 ScriptObjAddTokens(interp, script, &tokenlist);
9218
9219
9220 ScriptTokenListFree(&tokenlist);
9221
9222
9223 Jim_FreeIntRep(interp, objPtr);
9224 Jim_SetIntRepPtr(objPtr, script);
9225 objPtr->typePtr = &scriptObjType;
9226 }
9227
@@ -9116,11 +9228,11 @@
9228 static void JimAddErrorToStack(Jim_Interp *interp, ScriptObj *script);
9229
9230 static ScriptObj *JimGetScript(Jim_Interp *interp, Jim_Obj *objPtr)
9231 {
9232 if (objPtr == interp->emptyObj) {
9233
9234 objPtr = interp->nullScriptObj;
9235 }
9236
9237 if (objPtr->typePtr != &scriptObjType || ((struct ScriptObj *)Jim_GetIntRepPtr(objPtr))->substFlags) {
9238 JimSetScriptFromAny(interp, objPtr);
@@ -9155,67 +9267,66 @@
9267 Jim_FreeHashTable(cmdPtr->u.proc.staticVars);
9268 Jim_Free(cmdPtr->u.proc.staticVars);
9269 }
9270 }
9271 else {
9272
9273 if (cmdPtr->u.native.delProc) {
9274 cmdPtr->u.native.delProc(interp, cmdPtr->u.native.privData);
9275 }
9276 }
9277 if (cmdPtr->prevCmd) {
9278
9279 JimDecrCmdRefCount(interp, cmdPtr->prevCmd);
9280 }
9281 Jim_Free(cmdPtr);
9282 }
9283 }
 
9284
9285 static void JimVariablesHTValDestructor(void *interp, void *val)
9286 {
9287 Jim_DecrRefCount(interp, ((Jim_Var *)val)->objPtr);
9288 Jim_Free(val);
9289 }
9290
9291 static const Jim_HashTableType JimVariablesHashTableType = {
9292 JimStringCopyHTHashFunction,
9293 JimStringCopyHTDup,
9294 NULL,
9295 JimStringCopyHTKeyCompare,
9296 JimStringCopyHTKeyDestructor,
9297 JimVariablesHTValDestructor
9298 };
9299
9300 static void JimCommandsHT_ValDestructor(void *interp, void *val)
9301 {
9302 JimDecrCmdRefCount(interp, val);
9303 }
9304
9305 static const Jim_HashTableType JimCommandsHashTableType = {
9306 JimStringCopyHTHashFunction,
9307 JimStringCopyHTDup,
9308 NULL,
9309 JimStringCopyHTKeyCompare,
9310 JimStringCopyHTKeyDestructor,
9311 JimCommandsHT_ValDestructor
9312 };
9313
9314
9315
9316 #ifdef jim_ext_namespace
9317 static Jim_Obj *JimQualifyNameObj(Jim_Interp *interp, Jim_Obj *nsObj)
9318 {
9319 const char *name = Jim_String(nsObj);
9320 if (name[0] == ':' && name[1] == ':') {
9321
9322 while (*++name == ':') {
9323 }
9324 nsObj = Jim_NewStringObj(interp, name, -1);
9325 }
9326 else if (Jim_Length(interp->framePtr->nsObj)) {
9327
9328 nsObj = Jim_DuplicateObj(interp, interp->framePtr->nsObj);
9329 Jim_AppendStrings(interp, nsObj, "::", name, NULL);
9330 }
9331 return nsObj;
9332 }
@@ -9239,16 +9350,16 @@
9350 static const char *JimQualifyName(Jim_Interp *interp, const char *name, Jim_Obj **objPtrPtr)
9351 {
9352 Jim_Obj *objPtr = interp->emptyObj;
9353
9354 if (name[0] == ':' && name[1] == ':') {
9355
9356 while (*++name == ':') {
9357 }
9358 }
9359 else if (Jim_Length(interp->framePtr->nsObj)) {
9360
9361 objPtr = Jim_DuplicateObj(interp, interp->framePtr->nsObj);
9362 Jim_AppendStrings(interp, objPtr, "::", name, NULL);
9363 name = Jim_String(objPtr);
9364 }
9365 Jim_IncrRefCount(objPtr);
@@ -9257,11 +9368,11 @@
9368 }
9369
9370 #define JimFreeQualifiedName(INTERP, OBJ) Jim_DecrRefCount((INTERP), (OBJ))
9371
9372 #else
9373
9374 #define JimQualifyName(INTERP, NAME, DUMMY) (((NAME)[0] == ':' && (NAME)[1] == ':') ? (NAME) + 2 : (NAME))
9375 #define JimFreeQualifiedName(INTERP, DUMMY) (void)(DUMMY)
9376
9377 Jim_Obj *Jim_MakeGlobalNamespaceName(Jim_Interp *interp, Jim_Obj *nameObjPtr)
9378 {
@@ -9276,17 +9387,17 @@
9387
9388 Jim_InterpIncrProcEpoch(interp);
9389 }
9390
9391 if (he && interp->local) {
9392
9393 cmd->prevCmd = Jim_GetHashEntryVal(he);
9394 Jim_SetHashVal(&interp->commands, he, cmd);
9395 }
9396 else {
9397 if (he) {
9398
9399 Jim_DeleteHashEntry(&interp->commands, name);
9400 }
9401
9402 Jim_AddHashEntry(&interp->commands, name, cmd);
9403 }
@@ -9297,11 +9408,11 @@
9408 int Jim_CreateCommand(Jim_Interp *interp, const char *cmdNameStr,
9409 Jim_CmdProc *cmdProc, void *privData, Jim_DelCmdProc *delProc)
9410 {
9411 Jim_Cmd *cmdPtr = Jim_Alloc(sizeof(*cmdPtr));
9412
9413
9414 memset(cmdPtr, 0, sizeof(*cmdPtr));
9415 cmdPtr->inUse = 1;
9416 cmdPtr->u.native.delProc = delProc;
9417 cmdPtr->u.native.cmdProc = cmdProc;
9418 cmdPtr->u.native.privData = privData;
@@ -9326,11 +9437,11 @@
9437 Jim_Obj *objPtr, *initObjPtr, *nameObjPtr;
9438 Jim_Var *varPtr;
9439 int subLen;
9440
9441 objPtr = Jim_ListGetIndex(interp, staticsListObjPtr, i);
9442
9443 subLen = Jim_ListLength(interp, objPtr);
9444 if (subLen == 1 || subLen == 2) {
9445 nameObjPtr = Jim_ListGetIndex(interp, objPtr, 0);
9446 if (subLen == 1) {
9447 initObjPtr = Jim_GetVariable(interp, nameObjPtr, JIM_NONE);
@@ -9372,19 +9483,19 @@
9483
9484 static void JimUpdateProcNamespace(Jim_Interp *interp, Jim_Cmd *cmdPtr, const char *cmdname)
9485 {
9486 #ifdef jim_ext_namespace
9487 if (cmdPtr->isproc) {
9488
9489 const char *pt = strrchr(cmdname, ':');
9490 if (pt && pt != cmdname && pt[-1] == ':') {
9491 Jim_DecrRefCount(interp, cmdPtr->u.proc.nsObj);
9492 cmdPtr->u.proc.nsObj = Jim_NewStringObj(interp, cmdname, pt - cmdname - 1);
9493 Jim_IncrRefCount(cmdPtr->u.proc.nsObj);
9494
9495 if (Jim_FindHashEntry(&interp->commands, pt + 1)) {
9496
9497 Jim_InterpIncrProcEpoch(interp);
9498 }
9499 }
9500 }
9501 #endif
@@ -9397,11 +9508,11 @@
9508 int argListLen;
9509 int i;
9510
9511 argListLen = Jim_ListLength(interp, argListObjPtr);
9512
9513
9514 cmdPtr = Jim_Alloc(sizeof(*cmdPtr) + sizeof(struct Jim_ProcArg) * argListLen);
9515 memset(cmdPtr, 0, sizeof(*cmdPtr));
9516 cmdPtr->inUse = 1;
9517 cmdPtr->isproc = 1;
9518 cmdPtr->u.proc.argListObjPtr = argListObjPtr;
@@ -9412,24 +9523,24 @@
9523 cmdPtr->u.proc.nsObj = nsObj ? nsObj : interp->emptyObj;
9524 Jim_IncrRefCount(argListObjPtr);
9525 Jim_IncrRefCount(bodyObjPtr);
9526 Jim_IncrRefCount(cmdPtr->u.proc.nsObj);
9527
9528
9529 if (staticsListObjPtr && JimCreateProcedureStatics(interp, cmdPtr, staticsListObjPtr) != JIM_OK) {
9530 goto err;
9531 }
9532
9533
9534
9535 for (i = 0; i < argListLen; i++) {
9536 Jim_Obj *argPtr;
9537 Jim_Obj *nameObjPtr;
9538 Jim_Obj *defaultObjPtr;
9539 int len;
9540
9541
9542 argPtr = Jim_ListGetIndex(interp, argListObjPtr, i);
9543 len = Jim_ListLength(interp, argPtr);
9544 if (len == 0) {
9545 Jim_SetResultString(interp, "argument with no name", -1);
9546 err:
@@ -9440,16 +9551,16 @@
9551 Jim_SetResultFormatted(interp, "too many fields in argument specifier \"%#s\"", argPtr);
9552 goto err;
9553 }
9554
9555 if (len == 2) {
9556
9557 nameObjPtr = Jim_ListGetIndex(interp, argPtr, 0);
9558 defaultObjPtr = Jim_ListGetIndex(interp, argPtr, 1);
9559 }
9560 else {
9561
9562 nameObjPtr = argPtr;
9563 defaultObjPtr = NULL;
9564 }
9565
9566
@@ -9510,29 +9621,29 @@
9621 }
9622
9623 fqold = JimQualifyName(interp, oldName, &qualifiedOldNameObj);
9624 fqnew = JimQualifyName(interp, newName, &qualifiedNewNameObj);
9625
9626
9627 he = Jim_FindHashEntry(&interp->commands, fqold);
9628 if (he == NULL) {
9629 Jim_SetResultFormatted(interp, "can't rename \"%s\": command doesn't exist", oldName);
9630 }
9631 else if (Jim_FindHashEntry(&interp->commands, fqnew)) {
9632 Jim_SetResultFormatted(interp, "can't rename to \"%s\": command already exists", newName);
9633 }
9634 else {
9635
9636 cmdPtr = Jim_GetHashEntryVal(he);
9637 JimIncrCmdRefCount(cmdPtr);
9638 JimUpdateProcNamespace(interp, cmdPtr, fqnew);
9639 Jim_AddHashEntry(&interp->commands, fqnew, cmdPtr);
9640
9641
9642 Jim_DeleteHashEntry(&interp->commands, fqold);
9643
9644
9645 Jim_InterpIncrProcEpoch(interp);
9646
9647 ret = JIM_OK;
9648 }
9649
@@ -9571,23 +9682,23 @@
9682 objPtr->internalRep.cmdValue.procEpoch != interp->procEpoch
9683 #ifdef jim_ext_namespace
9684 || !Jim_StringEqObj(objPtr->internalRep.cmdValue.nsObj, interp->framePtr->nsObj)
9685 #endif
9686 ) {
 
9687
9688
9689
9690 const char *name = Jim_String(objPtr);
9691 Jim_HashEntry *he;
9692
9693 if (name[0] == ':' && name[1] == ':') {
9694 while (*++name == ':') {
9695 }
9696 }
9697 #ifdef jim_ext_namespace
9698 else if (Jim_Length(interp->framePtr->nsObj)) {
9699
9700 Jim_Obj *nameObj = Jim_DuplicateObj(interp, interp->framePtr->nsObj);
9701 Jim_AppendStrings(interp, nameObj, "::", name, NULL);
9702 he = Jim_FindHashEntry(&interp->commands, Jim_String(nameObj));
9703 Jim_FreeNewObj(interp, nameObj);
9704 if (he) {
@@ -9594,11 +9705,11 @@
9705 goto found;
9706 }
9707 }
9708 #endif
9709
9710
9711 he = Jim_FindHashEntry(&interp->commands, name);
9712 if (he == NULL) {
9713 if (flags & JIM_ERRMSG) {
9714 Jim_SetResultFormatted(interp, "invalid command name \"%#s\"", objPtr);
9715 }
@@ -9607,11 +9718,11 @@
9718 #ifdef jim_ext_namespace
9719 found:
9720 #endif
9721 cmd = Jim_GetHashEntryVal(he);
9722
9723
9724 Jim_FreeIntRep(interp, objPtr);
9725 objPtr->typePtr = &commandObjType;
9726 objPtr->internalRep.cmdValue.procEpoch = interp->procEpoch;
9727 objPtr->internalRep.cmdValue.cmdPtr = cmd;
9728 objPtr->internalRep.cmdValue.nsObj = interp->framePtr->nsObj;
@@ -9626,11 +9737,11 @@
9737 return cmd;
9738 }
9739
9740
9741
9742 #define JIM_DICT_SUGAR 100
9743
9744 static int SetVariableFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr);
9745
9746 static const Jim_ObjType variableObjType = {
9747 "variable",
@@ -9640,11 +9751,11 @@
9751 JIM_TYPE_REFERENCES,
9752 };
9753
9754 static int JimValidName(Jim_Interp *interp, const char *type, Jim_Obj *nameObjPtr)
9755 {
9756
9757 if (nameObjPtr->typePtr != &variableObjType) {
9758 int len;
9759 const char *str = Jim_GetString(nameObjPtr, &len);
9760 if (memchr(str, '\0', len)) {
9761 Jim_SetResultFormatted(interp, "%s name contains embedded null", type);
@@ -9660,18 +9771,18 @@
9771 Jim_CallFrame *framePtr;
9772 Jim_HashEntry *he;
9773 int global;
9774 int len;
9775
9776
9777 if (objPtr->typePtr == &variableObjType) {
9778 framePtr = objPtr->internalRep.varValue.global ? interp->topFramePtr : interp->framePtr;
9779 if (objPtr->internalRep.varValue.callFrameId == framePtr->id) {
9780
9781 return JIM_OK;
9782 }
9783
9784 }
9785 else if (objPtr->typePtr == &dictSubstObjType) {
9786 return JIM_DICT_SUGAR;
9787 }
9788 else if (JimValidName(interp, "variable", objPtr) != JIM_OK) {
@@ -9679,11 +9790,11 @@
9790 }
9791
9792
9793 varName = Jim_GetString(objPtr, &len);
9794
9795
9796 if (len && varName[len - 1] == ')' && strchr(varName, '(') != NULL) {
9797 return JIM_DICT_SUGAR;
9798 }
9799
9800 if (varName[0] == ':' && varName[1] == ':') {
@@ -9695,23 +9806,23 @@
9806 else {
9807 global = 0;
9808 framePtr = interp->framePtr;
9809 }
9810
9811
9812 he = Jim_FindHashEntry(&framePtr->vars, varName);
9813 if (he == NULL) {
9814 if (!global && framePtr->staticVars) {
9815
9816 he = Jim_FindHashEntry(framePtr->staticVars, varName);
9817 }
9818 if (he == NULL) {
9819 return JIM_ERR;
9820 }
9821 }
9822
9823
9824 Jim_FreeIntRep(interp, objPtr);
9825 objPtr->typePtr = &variableObjType;
9826 objPtr->internalRep.varValue.callFrameId = framePtr->id;
9827 objPtr->internalRep.varValue.varPtr = Jim_GetHashEntryVal(he);
9828 objPtr->internalRep.varValue.global = global;
@@ -9726,11 +9837,11 @@
9837 {
9838 const char *name;
9839 Jim_CallFrame *framePtr;
9840 int global;
9841
9842
9843 Jim_Var *var = Jim_Alloc(sizeof(*var));
9844
9845 var->objPtr = valObjPtr;
9846 Jim_IncrRefCount(valObjPtr);
9847 var->linkFramePtr = NULL;
@@ -9745,14 +9856,14 @@
9856 else {
9857 framePtr = interp->framePtr;
9858 global = 0;
9859 }
9860
9861
9862 Jim_AddHashEntry(&framePtr->vars, name, var);
9863
9864
9865 Jim_FreeIntRep(interp, nameObjPtr);
9866 nameObjPtr->typePtr = &variableObjType;
9867 nameObjPtr->internalRep.varValue.callFrameId = framePtr->id;
9868 nameObjPtr->internalRep.varValue.varPtr = var;
9869 nameObjPtr->internalRep.varValue.global = global;
@@ -9782,11 +9893,11 @@
9893 if (var->linkFramePtr == NULL) {
9894 Jim_IncrRefCount(valObjPtr);
9895 Jim_DecrRefCount(interp, var->objPtr);
9896 var->objPtr = valObjPtr;
9897 }
9898 else {
9899 Jim_CallFrame *savedCallFrame;
9900
9901 savedCallFrame = interp->framePtr;
9902 interp->framePtr = var->linkFramePtr;
9903 err = Jim_SetVariable(interp, var->objPtr, valObjPtr);
@@ -9822,19 +9933,16 @@
9933 return result;
9934 }
9935
9936 int Jim_SetVariableStrWithStr(Jim_Interp *interp, const char *name, const char *val)
9937 {
9938 Jim_Obj *valObjPtr;
9939 int result;
9940
 
9941 valObjPtr = Jim_NewStringObj(interp, val, -1);
 
9942 Jim_IncrRefCount(valObjPtr);
9943 result = Jim_SetVariableStr(interp, name, valObjPtr);
 
9944 Jim_DecrRefCount(interp, valObjPtr);
9945 return result;
9946 }
9947
9948 int Jim_SetVariableLink(Jim_Interp *interp, Jim_Obj *nameObjPtr,
@@ -9843,14 +9951,14 @@
9951 const char *varName;
9952 const char *targetName;
9953 Jim_CallFrame *framePtr;
9954 Jim_Var *varPtr;
9955
9956
9957 switch (SetVariableFromAny(interp, nameObjPtr)) {
9958 case JIM_DICT_SUGAR:
9959
9960 Jim_SetResultFormatted(interp, "bad variable name \"%#s\": upvar won't create a scalar variable that looks like an array element", nameObjPtr);
9961 return JIM_ERR;
9962
9963 case JIM_OK:
9964 varPtr = nameObjPtr->internalRep.varValue.varPtr;
@@ -9858,23 +9966,23 @@
9966 if (varPtr->linkFramePtr == NULL) {
9967 Jim_SetResultFormatted(interp, "variable \"%#s\" already exists", nameObjPtr);
9968 return JIM_ERR;
9969 }
9970
9971
9972 varPtr->linkFramePtr = NULL;
9973 break;
9974 }
9975
9976
9977
9978 varName = Jim_String(nameObjPtr);
9979
9980 if (varName[0] == ':' && varName[1] == ':') {
9981 while (*++varName == ':') {
9982 }
9983
9984 framePtr = interp->topFramePtr;
9985 }
9986 else {
9987 framePtr = interp->framePtr;
9988 }
@@ -9894,15 +10002,15 @@
10002 nameObjPtr);
10003 Jim_DecrRefCount(interp, targetNameObjPtr);
10004 return JIM_ERR;
10005 }
10006
10007
10008 if (framePtr == targetCallFrame) {
10009 Jim_Obj *objPtr = targetNameObjPtr;
10010
10011
10012 while (1) {
10013 if (strcmp(Jim_String(objPtr), varName) == 0) {
10014 Jim_SetResultString(interp, "can't upvar from variable to itself", -1);
10015 Jim_DecrRefCount(interp, targetNameObjPtr);
10016 return JIM_ERR;
@@ -9914,13 +10022,13 @@
10022 break;
10023 objPtr = varPtr->objPtr;
10024 }
10025 }
10026
10027
10028 Jim_SetVariable(interp, nameObjPtr, targetNameObjPtr);
10029
10030 nameObjPtr->internalRep.varValue.varPtr->linkFramePtr = targetCallFrame;
10031 Jim_DecrRefCount(interp, targetNameObjPtr);
10032 return JIM_OK;
10033 }
10034
@@ -9934,26 +10042,26 @@
10042 return varPtr->objPtr;
10043 }
10044 else {
10045 Jim_Obj *objPtr;
10046
10047
10048 Jim_CallFrame *savedCallFrame = interp->framePtr;
10049
10050 interp->framePtr = varPtr->linkFramePtr;
10051 objPtr = Jim_GetVariable(interp, varPtr->objPtr, flags);
10052 interp->framePtr = savedCallFrame;
10053 if (objPtr) {
10054 return objPtr;
10055 }
10056
10057 }
10058 }
10059 break;
10060
10061 case JIM_DICT_SUGAR:
10062
10063 return JimDictSugarGet(interp, nameObjPtr, flags);
10064 }
10065 if (flags & JIM_ERRMSG) {
10066 Jim_SetResultFormatted(interp, "can't read \"%#s\": no such variable", nameObjPtr);
10067 }
@@ -10003,17 +10111,17 @@
10111 int retval;
10112 Jim_CallFrame *framePtr;
10113
10114 retval = SetVariableFromAny(interp, nameObjPtr);
10115 if (retval == JIM_DICT_SUGAR) {
10116
10117 return JimDictSugarSet(interp, nameObjPtr, NULL);
10118 }
10119 else if (retval == JIM_OK) {
10120 varPtr = nameObjPtr->internalRep.varValue.varPtr;
10121
10122
10123 if (varPtr->linkFramePtr) {
10124 framePtr = interp->framePtr;
10125 interp->framePtr = varPtr->linkFramePtr;
10126 retval = Jim_UnsetVariable(interp, varPtr->objPtr, JIM_NONE);
10127 interp->framePtr = framePtr;
@@ -10028,11 +10136,11 @@
10136 framePtr = interp->framePtr;
10137 }
10138
10139 retval = Jim_DeleteHashEntry(&framePtr->vars, name);
10140 if (retval == JIM_OK) {
10141
10142 framePtr->id = interp->callFrameEpoch++;
10143 }
10144 }
10145 }
10146 if (retval != JIM_OK && (flags & JIM_ERRMSG)) {
@@ -10061,11 +10169,11 @@
10169 keyLen = (str + len) - p;
10170 if (str[len - 1] == ')') {
10171 keyLen--;
10172 }
10173
10174
10175 keyObjPtr = Jim_NewStringObj(interp, p, keyLen);
10176
10177 Jim_IncrRefCount(varObjPtr);
10178 Jim_IncrRefCount(keyObjPtr);
10179 *varPtrPtr = varObjPtr;
@@ -10080,23 +10188,23 @@
10188
10189 err = Jim_SetDictKeysVector(interp, objPtr->internalRep.dictSubstValue.varNameObjPtr,
10190 &objPtr->internalRep.dictSubstValue.indexObjPtr, 1, valObjPtr, JIM_MUSTEXIST);
10191
10192 if (err == JIM_OK) {
10193
10194 Jim_SetEmptyResult(interp);
10195 }
10196 else {
10197 if (!valObjPtr) {
10198
10199 if (Jim_GetVariable(interp, objPtr->internalRep.dictSubstValue.varNameObjPtr, JIM_NONE)) {
10200 Jim_SetResultFormatted(interp, "can't unset \"%#s\": no such element in array",
10201 objPtr);
10202 return err;
10203 }
10204 }
10205
10206 Jim_SetResultFormatted(interp, "can't %s \"%#s\": variable isn't array",
10207 (valObjPtr ? "set" : "unset"), objPtr);
10208 }
10209 return err;
10210 }
@@ -10118,11 +10226,11 @@
10226 Jim_SetResultFormatted(interp,
10227 "can't read \"%#s(%#s)\": %s array", varObjPtr, keyObjPtr,
10228 ret < 0 ? "variable isn't" : "no such element in");
10229 }
10230 else if ((flags & JIM_UNSHARED) && Jim_IsShared(dictObjPtr)) {
10231
10232 Jim_SetVariable(interp, varObjPtr, Jim_DuplicateObj(interp, dictObjPtr));
10233 }
10234
10235 return resObjPtr;
10236 }
@@ -10143,28 +10251,27 @@
10251 {
10252 Jim_DecrRefCount(interp, objPtr->internalRep.dictSubstValue.varNameObjPtr);
10253 Jim_DecrRefCount(interp, objPtr->internalRep.dictSubstValue.indexObjPtr);
10254 }
10255
10256 static void DupDictSubstInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr)
10257 {
10258
10259 dupPtr->internalRep = srcPtr->internalRep;
10260
10261 Jim_IncrRefCount(dupPtr->internalRep.dictSubstValue.varNameObjPtr);
10262 Jim_IncrRefCount(dupPtr->internalRep.dictSubstValue.indexObjPtr);
 
10263 }
10264
10265
10266 static void SetDictSubstFromAny(Jim_Interp *interp, Jim_Obj *objPtr)
10267 {
10268 if (objPtr->typePtr != &dictSubstObjType) {
10269 Jim_Obj *varObjPtr, *keyObjPtr;
10270
10271 if (objPtr->typePtr == &interpolatedObjType) {
10272
10273
10274 varObjPtr = objPtr->internalRep.dictSubstValue.varNameObjPtr;
10275 keyObjPtr = objPtr->internalRep.dictSubstValue.indexObjPtr;
10276
10277 Jim_IncrRefCount(varObjPtr);
@@ -10202,16 +10309,12 @@
10309 return resObjPtr;
10310 }
10311
10312 static Jim_Obj *JimExpandExprSugar(Jim_Interp *interp, Jim_Obj *objPtr)
10313 {
10314 if (Jim_EvalExpression(interp, objPtr) == JIM_OK) {
10315 return Jim_GetResult(interp);
 
 
 
 
10316 }
10317 return NULL;
10318 }
10319
10320
@@ -10249,11 +10352,11 @@
10352 return cf;
10353 }
10354
10355 static int JimDeleteLocalProcs(Jim_Interp *interp, Jim_Stack *localCommands)
10356 {
10357
10358 if (localCommands) {
10359 Jim_Obj *cmdNameObj;
10360
10361 while ((cmdNameObj = Jim_StackPop(localCommands)) != NULL) {
10362 Jim_HashEntry *he;
@@ -10268,20 +10371,20 @@
10371 Jim_Cmd *cmd = Jim_GetHashEntryVal(he);
10372 if (cmd->prevCmd) {
10373 Jim_Cmd *prevCmd = cmd->prevCmd;
10374 cmd->prevCmd = NULL;
10375
10376
10377 JimDecrCmdRefCount(interp, cmd);
10378
10379
10380 Jim_SetHashVal(ht, he, prevCmd);
10381 }
10382 else {
10383 Jim_DeleteHashEntry(ht, fqname);
 
10384 }
10385 Jim_InterpIncrProcEpoch(interp);
10386 }
10387 Jim_DecrRefCount(interp, cmdNameObj);
10388 JimFreeQualifiedName(interp, fqObjName);
10389 }
10390 Jim_FreeStack(localCommands);
@@ -10288,13 +10391,59 @@
10391 Jim_Free(localCommands);
10392 }
10393 return JIM_OK;
10394 }
10395
10396 static int JimInvokeDefer(Jim_Interp *interp, int retcode)
10397 {
10398 Jim_Obj *objPtr;
10399
10400
10401 if (Jim_FindHashEntry(&interp->framePtr->vars, "jim::defer") == NULL) {
10402 return retcode;
10403 }
10404
10405 objPtr = Jim_GetVariableStr(interp, "jim::defer", JIM_NONE);
10406
10407 if (objPtr) {
10408 int ret = JIM_OK;
10409 int i;
10410 int listLen = Jim_ListLength(interp, objPtr);
10411 Jim_Obj *resultObjPtr;
10412
10413 Jim_IncrRefCount(objPtr);
10414
10415 resultObjPtr = Jim_GetResult(interp);
10416 Jim_IncrRefCount(resultObjPtr);
10417 Jim_SetEmptyResult(interp);
10418
10419
10420 for (i = listLen; i > 0; i--) {
10421
10422 Jim_Obj *scriptObjPtr = Jim_ListGetIndex(interp, objPtr, i - 1);
10423 ret = Jim_EvalObj(interp, scriptObjPtr);
10424 if (ret != JIM_OK) {
10425 break;
10426 }
10427 }
10428
10429 if (ret == JIM_OK || retcode == JIM_ERR) {
10430
10431 Jim_SetResult(interp, resultObjPtr);
10432 }
10433 else {
10434 retcode = ret;
10435 }
10436
10437 Jim_DecrRefCount(interp, resultObjPtr);
10438 Jim_DecrRefCount(interp, objPtr);
10439 }
10440 return retcode;
10441 }
10442
10443 #define JIM_FCF_FULL 0
10444 #define JIM_FCF_REUSE 1
10445 static void JimFreeCallFrame(Jim_Interp *interp, Jim_CallFrame *cf, int action)
10446 {
10447 JimDeleteLocalProcs(interp, cf->localCommands);
10448
10449 if (cf->procArgsObjPtr)
@@ -10327,263 +10476,10 @@
10476 cf->next = interp->freeFramesList;
10477 interp->freeFramesList = cf;
10478 }
10479
10480
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
10481
10482 int Jim_IsBigEndian(void)
10483 {
10484 union {
10485 unsigned short s;
@@ -10630,11 +10526,11 @@
10526 Jim_IncrRefCount(i->nullScriptObj);
10527 Jim_IncrRefCount(i->errorProc);
10528 Jim_IncrRefCount(i->trueObj);
10529 Jim_IncrRefCount(i->falseObj);
10530
10531
10532 Jim_SetVariableStrWithStr(i, JIM_LIBPATH, TCL_LIBRARY);
10533 Jim_SetVariableStrWithStr(i, JIM_INTERACTIVE, "0");
10534
10535 Jim_SetVariableStrWithStr(i, "tcl_platform(engine)", "Jim");
10536 Jim_SetVariableStrWithStr(i, "tcl_platform(os)", TCL_PLATFORM_OS);
@@ -10652,12 +10548,14 @@
10548 {
10549 Jim_CallFrame *cf, *cfx;
10550
10551 Jim_Obj *objPtr, *nextObjPtr;
10552
10553
10554 for (cf = i->framePtr; cf; cf = cfx) {
10555
10556 JimInvokeDefer(i, JIM_OK);
10557 cfx = cf->parent;
10558 JimFreeCallFrame(i, cf, JIM_FCF_FULL);
10559 }
10560
10561 Jim_DecrRefCount(i, i->emptyObj);
@@ -10684,10 +10582,11 @@
10582
10583 printf("\n-------------------------------------\n");
10584 printf("Objects still in the free list:\n");
10585 while (objPtr) {
10586 const char *type = objPtr->typePtr ? objPtr->typePtr->name : "string";
10587 Jim_String(objPtr);
10588
10589 if (objPtr->bytes && strlen(objPtr->bytes) > 20) {
10590 printf("%p (%d) %-10s: '%.20s...'\n",
10591 (void *)objPtr, objPtr->refCount, type, objPtr->bytes);
10592 }
@@ -10705,27 +10604,27 @@
10604 printf("-------------------------------------\n\n");
10605 JimPanic((1, "Live list non empty freeing the interpreter! Leak?"));
10606 }
10607 #endif
10608
10609
10610 objPtr = i->freeList;
10611 while (objPtr) {
10612 nextObjPtr = objPtr->nextObjPtr;
10613 Jim_Free(objPtr);
10614 objPtr = nextObjPtr;
10615 }
10616
10617
10618 for (cf = i->freeFramesList; cf; cf = cfx) {
10619 cfx = cf->next;
10620 if (cf->vars.table)
10621 Jim_FreeHashTable(&cf->vars);
10622 Jim_Free(cf);
10623 }
10624
10625
10626 Jim_Free(i);
10627 }
10628
10629 Jim_CallFrame *Jim_GetCallFrameByLevel(Jim_Interp *interp, Jim_Obj *levelObjPtr)
10630 {
@@ -10746,25 +10645,25 @@
10645 else {
10646 if (Jim_GetLong(interp, levelObjPtr, &level) != JIM_OK || level < 0) {
10647 level = -1;
10648 }
10649 else {
10650
10651 level = interp->framePtr->level - level;
10652 }
10653 }
10654 }
10655 else {
10656 str = "1";
10657 level = interp->framePtr->level - 1;
10658 }
10659
10660 if (level == 0) {
10661 return interp->topFramePtr;
10662 }
10663 if (level > 0) {
10664
10665 for (framePtr = interp->framePtr; framePtr; framePtr = framePtr->parent) {
10666 if (framePtr->level == level) {
10667 return framePtr;
10668 }
10669 }
@@ -10779,19 +10678,19 @@
10678 long level;
10679 Jim_CallFrame *framePtr;
10680
10681 if (Jim_GetLong(interp, levelObjPtr, &level) == JIM_OK) {
10682 if (level <= 0) {
10683
10684 level = interp->framePtr->level + level;
10685 }
10686
10687 if (level == 0) {
10688 return interp->topFramePtr;
10689 }
10690
10691
10692 for (framePtr = interp->framePtr; framePtr; framePtr = framePtr->parent) {
10693 if (framePtr->level == level) {
10694 return framePtr;
10695 }
10696 }
@@ -10810,11 +10709,11 @@
10709
10710 static void JimSetStackTrace(Jim_Interp *interp, Jim_Obj *stackTraceObj)
10711 {
10712 int len;
10713
10714
10715 Jim_IncrRefCount(stackTraceObj);
10716 Jim_DecrRefCount(interp, interp->stackTrace);
10717 interp->stackTrace = stackTraceObj;
10718 interp->errorFlag = 1;
10719
@@ -10831,32 +10730,32 @@
10730 {
10731 if (strcmp(procname, "unknown") == 0) {
10732 procname = "";
10733 }
10734 if (!*procname && !Jim_Length(fileNameObj)) {
10735
10736 return;
10737 }
10738
10739 if (Jim_IsShared(interp->stackTrace)) {
10740 Jim_DecrRefCount(interp, interp->stackTrace);
10741 interp->stackTrace = Jim_DuplicateObj(interp, interp->stackTrace);
10742 Jim_IncrRefCount(interp->stackTrace);
10743 }
10744
10745
10746 if (!*procname && Jim_Length(fileNameObj)) {
10747
10748 int len = Jim_ListLength(interp, interp->stackTrace);
10749
10750 if (len >= 3) {
10751 Jim_Obj *objPtr = Jim_ListGetIndex(interp, interp->stackTrace, len - 3);
10752 if (Jim_Length(objPtr)) {
10753
10754 objPtr = Jim_ListGetIndex(interp, interp->stackTrace, len - 2);
10755 if (Jim_Length(objPtr) == 0) {
10756
10757 ListSetIndex(interp, interp->stackTrace, len - 2, fileNameObj, 0);
10758 ListSetIndex(interp, interp->stackTrace, len - 1, Jim_NewIntObj(interp, linenr), 0);
10759 return;
10760 }
10761 }
@@ -10958,18 +10857,18 @@
10857 {
10858 jim_wide wideValue;
10859 const char *str;
10860
10861 if (objPtr->typePtr == &coercedDoubleObjType) {
10862
10863 objPtr->typePtr = &intObjType;
10864 return JIM_OK;
10865 }
10866
10867
10868 str = Jim_String(objPtr);
10869
10870 if (Jim_StringToWide(str, &wideValue, 0) != JIM_OK) {
10871 if (flags & JIM_ERRMSG) {
10872 Jim_SetResultFormatted(interp, "expected integer but got \"%#s\"", objPtr);
10873 }
10874 return JIM_ERR;
@@ -10976,11 +10875,11 @@
10875 }
10876 if ((wideValue == JIM_WIDE_MIN || wideValue == JIM_WIDE_MAX) && errno == ERANGE) {
10877 Jim_SetResultString(interp, "Integer value too big to be represented", -1);
10878 return JIM_ERR;
10879 }
10880
10881 Jim_FreeIntRep(interp, objPtr);
10882 objPtr->typePtr = &intObjType;
10883 objPtr->internalRep.wideValue = wideValue;
10884 return JIM_OK;
10885 }
@@ -11075,17 +10974,17 @@
10974 {
10975 char buf[JIM_DOUBLE_SPACE + 1];
10976 int i;
10977 int len = sprintf(buf, "%.12g", value);
10978
10979
10980 for (i = 0; i < len; i++) {
10981 if (buf[i] == '.' || buf[i] == 'e') {
10982 #if defined(JIM_SPRINTF_DOUBLE_NEEDS_FIX)
10983 char *e = strchr(buf, 'e');
10984 if (e && (e[1] == '-' || e[1] == '+') && e[2] == '0') {
10985
10986 e += 2;
10987 memmove(e, e + 1, len - (e - buf));
10988 }
10989 #endif
10990 break;
@@ -11104,41 +11003,40 @@
11003 {
11004 double doubleValue;
11005 jim_wide wideValue;
11006 const char *str;
11007
 
 
11008 #ifdef HAVE_LONG_LONG
11009
11010 #define MIN_INT_IN_DOUBLE -(1LL << 53)
11011 #define MAX_INT_IN_DOUBLE -(MIN_INT_IN_DOUBLE + 1)
11012
11013 if (objPtr->typePtr == &intObjType
11014 && JimWideValue(objPtr) >= MIN_INT_IN_DOUBLE
11015 && JimWideValue(objPtr) <= MAX_INT_IN_DOUBLE) {
11016
11017
11018 objPtr->typePtr = &coercedDoubleObjType;
11019 return JIM_OK;
11020 }
 
11021 #endif
11022 str = Jim_String(objPtr);
11023
11024 if (Jim_StringToWide(str, &wideValue, 10) == JIM_OK) {
11025
11026 Jim_FreeIntRep(interp, objPtr);
11027 objPtr->typePtr = &coercedDoubleObjType;
11028 objPtr->internalRep.wideValue = wideValue;
11029 return JIM_OK;
11030 }
11031 else {
11032
11033 if (Jim_StringToDouble(str, &doubleValue) != JIM_OK) {
11034 Jim_SetResultFormatted(interp, "expected floating-point number but got \"%#s\"", objPtr);
11035 return JIM_ERR;
11036 }
11037
11038 Jim_FreeIntRep(interp, objPtr);
11039 }
11040 objPtr->typePtr = &doubleObjType;
11041 objPtr->internalRep.doubleValue = doubleValue;
11042 return JIM_OK;
@@ -11170,10 +11068,50 @@
11068 objPtr->typePtr = &doubleObjType;
11069 objPtr->bytes = NULL;
11070 objPtr->internalRep.doubleValue = doubleValue;
11071 return objPtr;
11072 }
11073
11074 static int SetBooleanFromAny(Jim_Interp *interp, Jim_Obj *objPtr, int flags);
11075
11076 int Jim_GetBoolean(Jim_Interp *interp, Jim_Obj *objPtr, int * booleanPtr)
11077 {
11078 if (objPtr->typePtr != &intObjType && SetBooleanFromAny(interp, objPtr, JIM_ERRMSG) == JIM_ERR)
11079 return JIM_ERR;
11080 *booleanPtr = (int) JimWideValue(objPtr);
11081 return JIM_OK;
11082 }
11083
11084 static int SetBooleanFromAny(Jim_Interp *interp, Jim_Obj *objPtr, int flags)
11085 {
11086 static const char * const falses[] = {
11087 "0", "false", "no", "off", NULL
11088 };
11089 static const char * const trues[] = {
11090 "1", "true", "yes", "on", NULL
11091 };
11092
11093 int boolean;
11094
11095 int index;
11096 if (Jim_GetEnum(interp, objPtr, falses, &index, NULL, 0) == JIM_OK) {
11097 boolean = 0;
11098 } else if (Jim_GetEnum(interp, objPtr, trues, &index, NULL, 0) == JIM_OK) {
11099 boolean = 1;
11100 } else {
11101 if (flags & JIM_ERRMSG) {
11102 Jim_SetResultFormatted(interp, "expected boolean but got \"%#s\"", objPtr);
11103 }
11104 return JIM_ERR;
11105 }
11106
11107
11108 Jim_FreeIntRep(interp, objPtr);
11109 objPtr->typePtr = &intObjType;
11110 objPtr->internalRep.wideValue = boolean;
11111 return JIM_OK;
11112 }
11113
11114 static void ListInsertElements(Jim_Obj *listPtr, int idx, int elemc, Jim_Obj *const *elemVec);
11115 static void ListAppendElement(Jim_Obj *listPtr, Jim_Obj *objPtr);
11116 static void FreeListInternalRep(Jim_Interp *interp, Jim_Obj *objPtr);
11117 static void DupListInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr);
@@ -11221,11 +11159,11 @@
11159 #define JIM_ELESTR_QUOTE 2
11160 static unsigned char ListElementQuotingType(const char *s, int len)
11161 {
11162 int i, level, blevel, trySimple = 1;
11163
11164
11165 if (len == 0)
11166 return JIM_ELESTR_BRACE;
11167 if (s[0] == '"' || s[0] == '{') {
11168 trySimple = 0;
11169 goto testbrace;
@@ -11243,20 +11181,20 @@
11181 case '\n':
11182 case '\t':
11183 case '\f':
11184 case '\v':
11185 trySimple = 0;
11186
11187 case '{':
11188 case '}':
11189 goto testbrace;
11190 }
11191 }
11192 return JIM_ELESTR_SIMPLE;
11193
11194 testbrace:
11195
11196 if (s[len - 1] == '\\')
11197 return JIM_ELESTR_QUOTE;
11198 level = 0;
11199 blevel = 0;
11200 for (i = 0; i < len; i++) {
@@ -11372,11 +11310,11 @@
11310 int i, bufLen, realLength;
11311 const char *strRep;
11312 char *p;
11313 unsigned char *quotingType, staticQuoting[STATIC_QUOTING_LEN];
11314
11315
11316 if (objc > STATIC_QUOTING_LEN) {
11317 quotingType = Jim_Alloc(objc);
11318 }
11319 else {
11320 quotingType = staticQuoting;
@@ -11391,25 +11329,25 @@
11329 case JIM_ELESTR_SIMPLE:
11330 if (i != 0 || strRep[0] != '#') {
11331 bufLen += len;
11332 break;
11333 }
11334
11335 quotingType[i] = JIM_ELESTR_BRACE;
11336
11337 case JIM_ELESTR_BRACE:
11338 bufLen += len + 2;
11339 break;
11340 case JIM_ELESTR_QUOTE:
11341 bufLen += len * 2;
11342 break;
11343 }
11344 bufLen++;
11345 }
11346 bufLen++;
11347
11348
11349 p = objPtr->bytes = Jim_Alloc(bufLen + 1);
11350 realLength = 0;
11351 for (i = 0; i < objc; i++) {
11352 int len, qlen;
11353
@@ -11436,17 +11374,17 @@
11374 qlen = BackslashQuoteString(strRep, len, p);
11375 p += qlen;
11376 realLength += qlen;
11377 break;
11378 }
11379
11380 if (i + 1 != objc) {
11381 *p++ = ' ';
11382 realLength++;
11383 }
11384 }
11385 *p = '\0';
11386 objPtr->length = realLength;
11387
11388 if (quotingType != staticQuoting) {
11389 Jim_Free(quotingType);
11390 }
@@ -11477,21 +11415,21 @@
11415 listObjPtrPtr = JimDictPairs(objPtr, &len);
11416 for (i = 0; i < len; i++) {
11417 Jim_IncrRefCount(listObjPtrPtr[i]);
11418 }
11419
11420
11421 Jim_FreeIntRep(interp, objPtr);
11422 objPtr->typePtr = &listObjType;
11423 objPtr->internalRep.listValue.len = len;
11424 objPtr->internalRep.listValue.maxLen = len;
11425 objPtr->internalRep.listValue.ele = listObjPtrPtr;
11426
11427 return JIM_OK;
11428 }
11429
11430
11431 if (objPtr->typePtr == &sourceObjType) {
11432 fileNameObj = objPtr->internalRep.sourceValue.fileNameObj;
11433 linenr = objPtr->internalRep.sourceValue.lineNumber;
11434 }
11435 else {
@@ -11498,20 +11436,20 @@
11436 fileNameObj = interp->emptyObj;
11437 linenr = 1;
11438 }
11439 Jim_IncrRefCount(fileNameObj);
11440
11441
11442 str = Jim_GetString(objPtr, &strLen);
11443
11444 Jim_FreeIntRep(interp, objPtr);
11445 objPtr->typePtr = &listObjType;
11446 objPtr->internalRep.listValue.len = 0;
11447 objPtr->internalRep.listValue.maxLen = 0;
11448 objPtr->internalRep.listValue.ele = NULL;
11449
11450
11451 if (strLen) {
11452 JimParserInit(&parser, str, strLen, linenr);
11453 while (!parser.eof) {
11454 Jim_Obj *elementPtr;
11455
@@ -11641,11 +11579,11 @@
11579 Jim_Obj *compare_script;
11580 int rc;
11581
11582 jim_wide ret = 0;
11583
11584
11585 compare_script = Jim_DuplicateObj(sort_info->interp, sort_info->command);
11586 Jim_ListAppendElement(sort_info->interp, compare_script, *lhsObj);
11587 Jim_ListAppendElement(sort_info->interp, compare_script, *rhsObj);
11588
11589 rc = Jim_EvalObj(sort_info->interp, compare_script);
@@ -11663,23 +11601,27 @@
11601 int dst = 0;
11602 Jim_Obj **ele = listObjPtr->internalRep.listValue.ele;
11603
11604 for (src = 1; src < listObjPtr->internalRep.listValue.len; src++) {
11605 if (comp(&ele[dst], &ele[src]) == 0) {
11606
11607 Jim_DecrRefCount(sort_info->interp, ele[dst]);
11608 }
11609 else {
11610
11611 dst++;
11612 }
11613 ele[dst] = ele[src];
11614 }
 
 
11615
11616
11617 dst++;
11618 if (dst < listObjPtr->internalRep.listValue.len) {
11619 ele[dst] = ele[src];
11620 }
11621
11622
11623 listObjPtr->internalRep.listValue.len = dst;
11624 }
11625
11626
11627 static int ListSortElements(Jim_Interp *interp, Jim_Obj *listObjPtr, struct lsort_info *info)
@@ -11693,11 +11635,11 @@
11635 int rc;
11636
11637 JimPanic((Jim_IsShared(listObjPtr), "ListSortElements called with shared object"));
11638 SetListFromAny(interp, listObjPtr);
11639
11640
11641 prev_info = sort_info;
11642 sort_info = info;
11643
11644 vector = listObjPtr->internalRep.listValue.ele;
11645 len = listObjPtr->internalRep.listValue.len;
@@ -11716,17 +11658,17 @@
11658 break;
11659 case JIM_LSORT_COMMAND:
11660 fn = ListSortCommand;
11661 break;
11662 default:
11663 fn = NULL;
11664 JimPanic((1, "ListSort called with invalid sort type"));
11665 return -1;
11666 }
11667
11668 if (info->indexed) {
11669
11670 info->subfn = fn;
11671 fn = ListSortIndexHelper;
11672 }
11673
11674 if ((rc = setjmp(info->jmpbuf)) == 0) {
@@ -11750,11 +11692,11 @@
11692 int i;
11693 Jim_Obj **point;
11694
11695 if (requiredLen > listPtr->internalRep.listValue.maxLen) {
11696 if (requiredLen < 2) {
11697
11698 requiredLen = 4;
11699 }
11700 else {
11701 requiredLen *= 2;
11702 }
@@ -11936,34 +11878,34 @@
11878 for (i = 0; i < objc; i++)
11879 ListAppendList(objPtr, objv[i]);
11880 return objPtr;
11881 }
11882 else {
11883
11884 int len = 0, objLen;
11885 char *bytes, *p;
11886
11887
11888 for (i = 0; i < objc; i++) {
11889 len += Jim_Length(objv[i]);
11890 }
11891 if (objc)
11892 len += objc - 1;
11893
11894 p = bytes = Jim_Alloc(len + 1);
11895 for (i = 0; i < objc; i++) {
11896 const char *s = Jim_GetString(objv[i], &objLen);
11897
11898
11899 while (objLen && isspace(UCHAR(*s))) {
11900 s++;
11901 objLen--;
11902 len--;
11903 }
11904
11905 while (objLen && isspace(UCHAR(s[objLen - 1]))) {
11906
11907 if (objLen > 1 && s[objLen - 2] == '\\') {
11908 break;
11909 }
11910 objLen--;
11911 len--;
@@ -11990,11 +11932,11 @@
11932 int len, rangeLen;
11933
11934 if (Jim_GetIndex(interp, firstObjPtr, &first) != JIM_OK ||
11935 Jim_GetIndex(interp, lastObjPtr, &last) != JIM_OK)
11936 return NULL;
11937 len = Jim_ListLength(interp, listObjPtr);
11938 first = JimRelToAbsIndex(len, first);
11939 last = JimRelToAbsIndex(len, last);
11940 JimRelToAbsRange(len, &first, &last, &rangeLen);
11941 if (first == 0 && last == len) {
11942 return listObjPtr;
@@ -12030,16 +11972,16 @@
11972 {
11973 Jim_DecrRefCount(interp, (Jim_Obj *)val);
11974 }
11975
11976 static const Jim_HashTableType JimDictHashTableType = {
11977 JimObjectHTHashFunction,
11978 JimObjectHTKeyValDup,
11979 JimObjectHTKeyValDup,
11980 JimObjectHTKeyCompare,
11981 JimObjectHTKeyValDestructor,
11982 JimObjectHTKeyValDestructor
11983 };
11984
11985 static const Jim_ObjType dictObjType = {
11986 "dict",
11987 FreeDictInternalRep,
@@ -12060,17 +12002,17 @@
12002 {
12003 Jim_HashTable *ht, *dupHt;
12004 Jim_HashTableIterator htiter;
12005 Jim_HashEntry *he;
12006
12007
12008 ht = srcPtr->internalRep.ptr;
12009 dupHt = Jim_Alloc(sizeof(*dupHt));
12010 Jim_InitHashTable(dupHt, &JimDictHashTableType, interp);
12011 if (ht->size != 0)
12012 Jim_ExpandHashTable(dupHt, ht->size);
12013
12014 JimInitHashTableIterator(ht, &htiter);
12015 while ((he = Jim_NextHashEntry(&htiter)) != NULL) {
12016 Jim_AddHashEntry(dupHt, he->key, he->u.val);
12017 }
12018
@@ -12086,11 +12028,11 @@
12028 Jim_Obj **objv;
12029 int i;
12030
12031 ht = dictPtr->internalRep.ptr;
12032
12033
12034 objv = Jim_Alloc((ht->used * 2) * sizeof(Jim_Obj *));
12035 JimInitHashTableIterator(ht, &htiter);
12036 i = 0;
12037 while ((he = Jim_NextHashEntry(&htiter)) != NULL) {
12038 objv[i++] = Jim_GetHashEntryKey(he);
@@ -12100,15 +12042,15 @@
12042 return objv;
12043 }
12044
12045 static void UpdateStringOfDict(struct Jim_Obj *objPtr)
12046 {
12047
12048 int len;
12049 Jim_Obj **objv = JimDictPairs(objPtr, &len);
12050
12051
12052 JimMakeListStringRep(objPtr, objv, len);
12053
12054 Jim_Free(objv);
12055 }
12056
@@ -12122,18 +12064,18 @@
12064
12065 if (Jim_IsList(objPtr) && Jim_IsShared(objPtr)) {
12066 Jim_String(objPtr);
12067 }
12068
12069
12070 listlen = Jim_ListLength(interp, objPtr);
12071 if (listlen % 2) {
12072 Jim_SetResultString(interp, "missing value to go with key", -1);
12073 return JIM_ERR;
12074 }
12075 else {
12076
12077 Jim_HashTable *ht;
12078 int i;
12079
12080 ht = Jim_Alloc(sizeof(*ht));
12081 Jim_InitHashTable(ht, &JimDictHashTableType, interp);
@@ -12158,11 +12100,11 @@
12100 static int DictAddElement(Jim_Interp *interp, Jim_Obj *objPtr,
12101 Jim_Obj *keyObjPtr, Jim_Obj *valueObjPtr)
12102 {
12103 Jim_HashTable *ht = objPtr->internalRep.ptr;
12104
12105 if (valueObjPtr == NULL) {
12106 return Jim_DeleteHashEntry(ht, keyObjPtr);
12107 }
12108 Jim_ReplaceHashEntry(ht, keyObjPtr, valueObjPtr);
12109 return JIM_OK;
12110 }
@@ -12209,12 +12151,14 @@
12151 if (flags & JIM_ERRMSG) {
12152 Jim_SetResultFormatted(interp, "key \"%#s\" not known in dictionary", keyPtr);
12153 }
12154 return JIM_ERR;
12155 }
12156 else {
12157 *objPtrPtr = Jim_GetHashEntryVal(he);
12158 return JIM_OK;
12159 }
12160 }
12161
12162
12163 int Jim_DictPairs(Jim_Interp *interp, Jim_Obj *dictPtr, Jim_Obj ***objPtrPtr, int *len)
12164 {
@@ -12258,11 +12202,11 @@
12202 int shared, i;
12203
12204 varObjPtr = objPtr = Jim_GetVariable(interp, varNamePtr, flags);
12205 if (objPtr == NULL) {
12206 if (newObjPtr == NULL && (flags & JIM_MUSTEXIST)) {
12207
12208 return JIM_ERR;
12209 }
12210 varObjPtr = objPtr = Jim_NewDictObj(interp, NULL, 0);
12211 if (Jim_SetVariable(interp, varNamePtr, objPtr) != JIM_OK) {
12212 Jim_FreeNewObj(interp, varObjPtr);
@@ -12272,26 +12216,26 @@
12216 if ((shared = Jim_IsShared(objPtr)))
12217 varObjPtr = objPtr = Jim_DuplicateObj(interp, objPtr);
12218 for (i = 0; i < keyc; i++) {
12219 dictObjPtr = objPtr;
12220
12221
12222 if (SetDictFromAny(interp, dictObjPtr) != JIM_OK) {
12223 goto err;
12224 }
12225
12226 if (i == keyc - 1) {
12227
12228 if (Jim_DictAddElement(interp, objPtr, keyv[keyc - 1], newObjPtr) != JIM_OK) {
12229 if (newObjPtr || (flags & JIM_MUSTEXIST)) {
12230 goto err;
12231 }
12232 }
12233 break;
12234 }
12235
12236
12237 Jim_InvalidateStringRep(dictObjPtr);
12238 if (Jim_DictKey(interp, dictObjPtr, keyv[i], &objPtr,
12239 newObjPtr ? JIM_NONE : JIM_ERRMSG) == JIM_OK) {
12240 if (Jim_IsShared(objPtr)) {
12241 objPtr = Jim_DuplicateObj(interp, objPtr);
@@ -12304,11 +12248,11 @@
12248 }
12249 objPtr = Jim_NewDictObj(interp, NULL, 0);
12250 DictAddElement(interp, dictObjPtr, keyv[i], objPtr);
12251 }
12252 }
12253
12254 Jim_InvalidateStringRep(objPtr);
12255 Jim_InvalidateStringRep(varObjPtr);
12256 if (Jim_SetVariable(interp, varNamePtr, varObjPtr) != JIM_OK) {
12257 goto err;
12258 }
@@ -12341,11 +12285,11 @@
12285 char buf[JIM_INTEGER_SPACE + 1];
12286 if (objPtr->internalRep.intValue >= 0) {
12287 sprintf(buf, "%d", objPtr->internalRep.intValue);
12288 }
12289 else {
12290
12291 sprintf(buf, "end%d", objPtr->internalRep.intValue + 1);
12292 }
12293 JimSetStringBytes(objPtr, buf);
12294 }
12295 }
@@ -12354,14 +12298,14 @@
12298 {
12299 int idx, end = 0;
12300 const char *str;
12301 char *endptr;
12302
12303
12304 str = Jim_String(objPtr);
12305
12306
12307 if (strncmp(str, "end", 3) == 0) {
12308 end = 1;
12309 str += 3;
12310 idx = 0;
12311 }
@@ -12372,21 +12316,21 @@
12316 goto badindex;
12317 }
12318 str = endptr;
12319 }
12320
12321
12322 if (*str == '+' || *str == '-') {
12323 int sign = (*str == '+' ? 1 : -1);
12324
12325 idx += sign * jim_strtol(++str, &endptr);
12326 if (str == endptr || *endptr) {
12327 goto badindex;
12328 }
12329 str = endptr;
12330 }
12331
12332 while (isspace(UCHAR(*str))) {
12333 str++;
12334 }
12335 if (*str) {
12336 goto badindex;
@@ -12394,19 +12338,19 @@
12338 if (end) {
12339 if (idx > 0) {
12340 idx = INT_MAX;
12341 }
12342 else {
12343
12344 idx--;
12345 }
12346 }
12347 else if (idx < 0) {
12348 idx = -INT_MAX;
12349 }
12350
12351
12352 Jim_FreeIntRep(interp, objPtr);
12353 objPtr->typePtr = &indexObjType;
12354 objPtr->internalRep.intValue = idx;
12355 return JIM_OK;
12356
@@ -12416,11 +12360,11 @@
12360 return JIM_ERR;
12361 }
12362
12363 int Jim_GetIndex(Jim_Interp *interp, Jim_Obj *objPtr, int *indexPtr)
12364 {
12365
12366 if (objPtr->typePtr == &intObjType) {
12367 jim_wide val = JimWideValue(objPtr);
12368
12369 if (val < 0)
12370 *indexPtr = -INT_MAX;
@@ -12448,11 +12392,11 @@
12392 "exit",
12393 "eval",
12394 NULL
12395 };
12396
12397 #define jimReturnCodesSize (sizeof(jimReturnCodes)/sizeof(*jimReturnCodes) - 1)
12398
12399 static const Jim_ObjType returnCodeObjType = {
12400 "return-code",
12401 NULL,
12402 NULL,
@@ -12473,18 +12417,18 @@
12417 static int SetReturnCodeFromAny(Jim_Interp *interp, Jim_Obj *objPtr)
12418 {
12419 int returnCode;
12420 jim_wide wideValue;
12421
12422
12423 if (JimGetWideNoErr(interp, objPtr, &wideValue) != JIM_ERR)
12424 returnCode = (int)wideValue;
12425 else if (Jim_GetEnum(interp, objPtr, jimReturnCodes, &returnCode, NULL, JIM_NONE) != JIM_OK) {
12426 Jim_SetResultFormatted(interp, "expected return code but got \"%#s\"", objPtr);
12427 return JIM_ERR;
12428 }
12429
12430 Jim_FreeIntRep(interp, objPtr);
12431 objPtr->typePtr = &returnCodeObjType;
12432 objPtr->internalRep.intValue = returnCode;
12433 return JIM_OK;
12434 }
@@ -12498,19 +12442,19 @@
12442 }
12443
12444 static int JimParseExprOperator(struct JimParserCtx *pc);
12445 static int JimParseExprNumber(struct JimParserCtx *pc);
12446 static int JimParseExprIrrational(struct JimParserCtx *pc);
12447 static int JimParseExprBoolean(struct JimParserCtx *pc);
 
12448
12449
12450 enum
12451 {
12452
12453
12454
12455 JIM_EXPROP_MUL = JIM_TT_EXPR_OP,
12456 JIM_EXPROP_DIV,
12457 JIM_EXPROP_MOD,
12458 JIM_EXPROP_SUB,
12459 JIM_EXPROP_ADD,
12460 JIM_EXPROP_LSHIFT,
@@ -12521,66 +12465,48 @@
12465 JIM_EXPROP_GT,
12466 JIM_EXPROP_LTE,
12467 JIM_EXPROP_GTE,
12468 JIM_EXPROP_NUMEQ,
12469 JIM_EXPROP_NUMNE,
12470 JIM_EXPROP_BITAND,
12471 JIM_EXPROP_BITXOR,
12472 JIM_EXPROP_BITOR,
12473 JIM_EXPROP_LOGICAND,
12474 JIM_EXPROP_LOGICOR,
12475 JIM_EXPROP_TERNARY,
12476 JIM_EXPROP_COLON,
12477 JIM_EXPROP_POW,
12478
12479
12480 JIM_EXPROP_STREQ,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12481 JIM_EXPROP_STRNE,
12482 JIM_EXPROP_STRIN,
12483 JIM_EXPROP_STRNI,
12484
12485
12486 JIM_EXPROP_NOT,
12487 JIM_EXPROP_BITNOT,
12488 JIM_EXPROP_UNARYMINUS,
12489 JIM_EXPROP_UNARYPLUS,
12490
12491
12492 JIM_EXPROP_FUNC_INT,
 
12493 JIM_EXPROP_FUNC_WIDE,
12494 JIM_EXPROP_FUNC_ABS,
12495 JIM_EXPROP_FUNC_DOUBLE,
12496 JIM_EXPROP_FUNC_ROUND,
12497 JIM_EXPROP_FUNC_RAND,
12498 JIM_EXPROP_FUNC_SRAND,
12499
12500
12501 JIM_EXPROP_FUNC_SIN,
12502 JIM_EXPROP_FUNC_COS,
12503 JIM_EXPROP_FUNC_TAN,
12504 JIM_EXPROP_FUNC_ASIN,
12505 JIM_EXPROP_FUNC_ACOS,
12506 JIM_EXPROP_FUNC_ATAN,
12507 JIM_EXPROP_FUNC_ATAN2,
12508 JIM_EXPROP_FUNC_SINH,
12509 JIM_EXPROP_FUNC_COSH,
12510 JIM_EXPROP_FUNC_TANH,
12511 JIM_EXPROP_FUNC_CEIL,
12512 JIM_EXPROP_FUNC_FLOOR,
@@ -12587,52 +12513,52 @@
12513 JIM_EXPROP_FUNC_EXP,
12514 JIM_EXPROP_FUNC_LOG,
12515 JIM_EXPROP_FUNC_LOG10,
12516 JIM_EXPROP_FUNC_SQRT,
12517 JIM_EXPROP_FUNC_POW,
12518 JIM_EXPROP_FUNC_HYPOT,
12519 JIM_EXPROP_FUNC_FMOD,
12520 };
12521
12522 struct JimExprNode {
12523 int type;
12524 struct Jim_Obj *objPtr;
12525
12526 struct JimExprNode *left;
12527 struct JimExprNode *right;
12528 struct JimExprNode *ternary;
12529 };
12530
12531
12532 typedef struct Jim_ExprOperator
12533 {
12534 const char *name;
12535 int (*funcop) (Jim_Interp *interp, struct JimExprNode *opnode);
12536 unsigned char precedence;
12537 unsigned char arity;
12538 unsigned char attr;
12539 unsigned char namelen;
12540 } Jim_ExprOperator;
12541
12542 static int JimExprGetTerm(Jim_Interp *interp, struct JimExprNode *node, Jim_Obj **objPtrPtr);
12543 static int JimExprGetTermBoolean(Jim_Interp *interp, struct JimExprNode *node);
12544 static int JimExprEvalTermNode(Jim_Interp *interp, struct JimExprNode *node);
12545
12546 static int JimExprOpNumUnary(Jim_Interp *interp, struct JimExprNode *node)
 
 
 
 
 
 
 
12547 {
12548 int intresult = 1;
12549 int rc;
 
12550 double dA, dC = 0;
12551 jim_wide wA, wC = 0;
12552 Jim_Obj *A;
12553
12554 if ((rc = JimExprGetTerm(interp, node->left, &A)) != JIM_OK) {
12555 return rc;
12556 }
12557
12558 if ((A->typePtr != &doubleObjType || A->bytes) && JimGetWideNoErr(interp, A, &wA) == JIM_OK) {
12559 switch (node->type) {
12560 case JIM_EXPROP_FUNC_INT:
12561 case JIM_EXPROP_FUNC_WIDE:
12562 case JIM_EXPROP_FUNC_ROUND:
12563 case JIM_EXPROP_UNARYPLUS:
12564 wC = wA;
@@ -12653,11 +12579,11 @@
12579 default:
12580 abort();
12581 }
12582 }
12583 else if ((rc = Jim_GetDouble(interp, A, &dA)) == JIM_OK) {
12584 switch (node->type) {
12585 case JIM_EXPROP_FUNC_INT:
12586 case JIM_EXPROP_FUNC_WIDE:
12587 wC = dA;
12588 break;
12589 case JIM_EXPROP_FUNC_ROUND:
@@ -12667,11 +12593,15 @@
12593 case JIM_EXPROP_UNARYPLUS:
12594 dC = dA;
12595 intresult = 0;
12596 break;
12597 case JIM_EXPROP_FUNC_ABS:
12598 #ifdef JIM_MATH_FUNCTIONS
12599 dC = fabs(dA);
12600 #else
12601 dC = dA >= 0 ? dA : -dA;
12602 #endif
12603 intresult = 0;
12604 break;
12605 case JIM_EXPROP_UNARYMINUS:
12606 dC = -dA;
12607 intresult = 0;
@@ -12684,14 +12614,14 @@
12614 }
12615 }
12616
12617 if (rc == JIM_OK) {
12618 if (intresult) {
12619 Jim_SetResultInt(interp, wC);
12620 }
12621 else {
12622 Jim_SetResult(interp, Jim_NewDoubleObj(interp, dC));
12623 }
12624 }
12625
12626 Jim_DecrRefCount(interp, A);
12627
@@ -12704,24 +12634,29 @@
12634 JimRandomBytes(interp, &x, sizeof(x));
12635
12636 return (double)x / (unsigned long)~0;
12637 }
12638
12639 static int JimExprOpIntUnary(Jim_Interp *interp, struct JimExprNode *node)
12640 {
 
12641 jim_wide wA;
12642 Jim_Obj *A;
12643 int rc;
12644
12645 if ((rc = JimExprGetTerm(interp, node->left, &A)) != JIM_OK) {
12646 return rc;
12647 }
12648
12649 rc = Jim_GetWide(interp, A, &wA);
12650 if (rc == JIM_OK) {
12651 switch (node->type) {
12652 case JIM_EXPROP_BITNOT:
12653 Jim_SetResultInt(interp, ~wA);
12654 break;
12655 case JIM_EXPROP_FUNC_SRAND:
12656 JimPrngSeed(interp, (unsigned char *)&wA, sizeof(wA));
12657 Jim_SetResult(interp, Jim_NewDoubleObj(interp, JimRandDouble(interp)));
12658 break;
12659 default:
12660 abort();
12661 }
12662 }
@@ -12729,29 +12664,33 @@
12664 Jim_DecrRefCount(interp, A);
12665
12666 return rc;
12667 }
12668
12669 static int JimExprOpNone(Jim_Interp *interp, struct JimExprNode *node)
12670 {
12671 JimPanic((node->type != JIM_EXPROP_FUNC_RAND, "JimExprOpNone only support rand()"));
12672
12673 Jim_SetResult(interp, Jim_NewDoubleObj(interp, JimRandDouble(interp)));
12674
12675 return JIM_OK;
12676 }
12677
12678 #ifdef JIM_MATH_FUNCTIONS
12679 static int JimExprOpDoubleUnary(Jim_Interp *interp, struct JimExprNode *node)
12680 {
12681 int rc;
 
12682 double dA, dC;
12683 Jim_Obj *A;
12684
12685 if ((rc = JimExprGetTerm(interp, node->left, &A)) != JIM_OK) {
12686 return rc;
12687 }
12688
12689 rc = Jim_GetDouble(interp, A, &dA);
12690 if (rc == JIM_OK) {
12691 switch (node->type) {
12692 case JIM_EXPROP_FUNC_SIN:
12693 dC = sin(dA);
12694 break;
12695 case JIM_EXPROP_FUNC_COS:
12696 dC = cos(dA);
@@ -12796,33 +12735,42 @@
12735 dC = sqrt(dA);
12736 break;
12737 default:
12738 abort();
12739 }
12740 Jim_SetResult(interp, Jim_NewDoubleObj(interp, dC));
12741 }
12742
12743 Jim_DecrRefCount(interp, A);
12744
12745 return rc;
12746 }
12747 #endif
12748
12749
12750 static int JimExprOpIntBin(Jim_Interp *interp, struct JimExprNode *node)
12751 {
 
 
12752 jim_wide wA, wB;
12753 int rc;
12754 Jim_Obj *A, *B;
12755
12756 if ((rc = JimExprGetTerm(interp, node->left, &A)) != JIM_OK) {
12757 return rc;
12758 }
12759 if ((rc = JimExprGetTerm(interp, node->right, &B)) != JIM_OK) {
12760 Jim_DecrRefCount(interp, A);
12761 return rc;
12762 }
12763
12764 rc = JIM_ERR;
12765
12766 if (Jim_GetWide(interp, A, &wA) == JIM_OK && Jim_GetWide(interp, B, &wB) == JIM_OK) {
12767 jim_wide wC;
12768
12769 rc = JIM_OK;
12770
12771 switch (node->type) {
12772 case JIM_EXPROP_LSHIFT:
12773 wC = wA << wB;
12774 break;
12775 case JIM_EXPROP_RSHIFT:
12776 wC = wA >> wB;
@@ -12859,29 +12807,28 @@
12807 }
12808 }
12809 break;
12810 case JIM_EXPROP_ROTL:
12811 case JIM_EXPROP_ROTR:{
12812
12813 unsigned long uA = (unsigned long)wA;
12814 unsigned long uB = (unsigned long)wB;
12815 const unsigned int S = sizeof(unsigned long) * 8;
12816
12817
12818 uB %= S;
12819
12820 if (node->type == JIM_EXPROP_ROTR) {
12821 uB = S - uB;
12822 }
12823 wC = (unsigned long)(uA << uB) | (uA >> (S - uB));
12824 break;
12825 }
12826 default:
12827 abort();
12828 }
12829 Jim_SetResultInt(interp, wC);
 
12830 }
12831
12832 Jim_DecrRefCount(interp, A);
12833 Jim_DecrRefCount(interp, B);
12834
@@ -12888,44 +12835,55 @@
12835 return rc;
12836 }
12837
12838
12839
12840 static int JimExprOpBin(Jim_Interp *interp, struct JimExprNode *node)
12841 {
 
12842 int rc = JIM_OK;
12843 double dA, dB, dC = 0;
12844 jim_wide wA, wB, wC = 0;
12845 Jim_Obj *A, *B;
12846
12847 if ((rc = JimExprGetTerm(interp, node->left, &A)) != JIM_OK) {
12848 return rc;
12849 }
12850 if ((rc = JimExprGetTerm(interp, node->right, &B)) != JIM_OK) {
12851 Jim_DecrRefCount(interp, A);
12852 return rc;
12853 }
12854
12855 if ((A->typePtr != &doubleObjType || A->bytes) &&
12856 (B->typePtr != &doubleObjType || B->bytes) &&
12857 JimGetWideNoErr(interp, A, &wA) == JIM_OK && JimGetWideNoErr(interp, B, &wB) == JIM_OK) {
12858
 
12859
12860
12861 switch (node->type) {
12862 case JIM_EXPROP_POW:
12863 case JIM_EXPROP_FUNC_POW:
12864 if (wA == 0 && wB < 0) {
12865 Jim_SetResultString(interp, "exponentiation of zero by negative power", -1);
12866 rc = JIM_ERR;
12867 goto done;
12868 }
12869 wC = JimPowWide(wA, wB);
12870 goto intresult;
12871 case JIM_EXPROP_ADD:
12872 wC = wA + wB;
12873 goto intresult;
12874 case JIM_EXPROP_SUB:
12875 wC = wA - wB;
12876 goto intresult;
12877 case JIM_EXPROP_MUL:
12878 wC = wA * wB;
12879 goto intresult;
12880 case JIM_EXPROP_DIV:
12881 if (wB == 0) {
12882 Jim_SetResultString(interp, "Division by zero", -1);
12883 rc = JIM_ERR;
12884 goto done;
12885 }
12886 else {
12887 if (wB < 0) {
12888 wB = -wB;
12889 wA = -wA;
@@ -12932,55 +12890,67 @@
12890 }
12891 wC = wA / wB;
12892 if (wA % wB < 0) {
12893 wC--;
12894 }
12895 goto intresult;
12896 }
 
12897 case JIM_EXPROP_LT:
12898 wC = wA < wB;
12899 goto intresult;
12900 case JIM_EXPROP_GT:
12901 wC = wA > wB;
12902 goto intresult;
12903 case JIM_EXPROP_LTE:
12904 wC = wA <= wB;
12905 goto intresult;
12906 case JIM_EXPROP_GTE:
12907 wC = wA >= wB;
12908 goto intresult;
12909 case JIM_EXPROP_NUMEQ:
12910 wC = wA == wB;
12911 goto intresult;
12912 case JIM_EXPROP_NUMNE:
12913 wC = wA != wB;
12914 goto intresult;
 
 
12915 }
12916 }
12917 if (Jim_GetDouble(interp, A, &dA) == JIM_OK && Jim_GetDouble(interp, B, &dB) == JIM_OK) {
12918 switch (node->type) {
12919 #ifndef JIM_MATH_FUNCTIONS
12920 case JIM_EXPROP_POW:
12921 case JIM_EXPROP_FUNC_POW:
12922 case JIM_EXPROP_FUNC_ATAN2:
12923 case JIM_EXPROP_FUNC_HYPOT:
12924 case JIM_EXPROP_FUNC_FMOD:
12925 Jim_SetResultString(interp, "unsupported", -1);
12926 rc = JIM_ERR;
12927 goto done;
12928 #else
12929 case JIM_EXPROP_POW:
12930 case JIM_EXPROP_FUNC_POW:
12931 dC = pow(dA, dB);
12932 goto doubleresult;
12933 case JIM_EXPROP_FUNC_ATAN2:
12934 dC = atan2(dA, dB);
12935 goto doubleresult;
12936 case JIM_EXPROP_FUNC_HYPOT:
12937 dC = hypot(dA, dB);
12938 goto doubleresult;
12939 case JIM_EXPROP_FUNC_FMOD:
12940 dC = fmod(dA, dB);
12941 goto doubleresult;
12942 #endif
 
12943 case JIM_EXPROP_ADD:
12944 dC = dA + dB;
12945 goto doubleresult;
12946 case JIM_EXPROP_SUB:
12947 dC = dA - dB;
12948 goto doubleresult;
12949 case JIM_EXPROP_MUL:
12950 dC = dA * dB;
12951 goto doubleresult;
12952 case JIM_EXPROP_DIV:
12953 if (dB == 0) {
12954 #ifdef INFINITY
12955 dC = dA < 0 ? -INFINITY : INFINITY;
12956 #else
@@ -12988,83 +12958,70 @@
12958 #endif
12959 }
12960 else {
12961 dC = dA / dB;
12962 }
12963 goto doubleresult;
12964 case JIM_EXPROP_LT:
12965 wC = dA < dB;
12966 goto intresult;
 
12967 case JIM_EXPROP_GT:
12968 wC = dA > dB;
12969 goto intresult;
 
12970 case JIM_EXPROP_LTE:
12971 wC = dA <= dB;
12972 goto intresult;
 
12973 case JIM_EXPROP_GTE:
12974 wC = dA >= dB;
12975 goto intresult;
 
12976 case JIM_EXPROP_NUMEQ:
12977 wC = dA == dB;
12978 goto intresult;
 
12979 case JIM_EXPROP_NUMNE:
12980 wC = dA != dB;
12981 goto intresult;
 
 
 
12982 }
12983 }
12984 else {
 
12985
12986
12987
12988 int i = Jim_StringCompareObj(interp, A, B, 0);
12989
12990 switch (node->type) {
12991 case JIM_EXPROP_LT:
12992 wC = i < 0;
12993 goto intresult;
12994 case JIM_EXPROP_GT:
12995 wC = i > 0;
12996 goto intresult;
12997 case JIM_EXPROP_LTE:
12998 wC = i <= 0;
12999 goto intresult;
13000 case JIM_EXPROP_GTE:
13001 wC = i >= 0;
13002 goto intresult;
13003 case JIM_EXPROP_NUMEQ:
13004 wC = i == 0;
13005 goto intresult;
13006 case JIM_EXPROP_NUMNE:
13007 wC = i != 0;
13008 goto intresult;
 
 
 
13009 }
13010 }
13011
13012 rc = JIM_ERR;
13013 done:
 
 
 
 
 
 
 
13014 Jim_DecrRefCount(interp, A);
13015 Jim_DecrRefCount(interp, B);
 
13016 return rc;
13017 intresult:
13018 Jim_SetResultInt(interp, wC);
13019 goto done;
13020 doubleresult:
13021 Jim_SetResult(interp, Jim_NewDoubleObj(interp, dC));
13022 goto done;
13023 }
13024
13025 static int JimSearchList(Jim_Interp *interp, Jim_Obj *listObjPtr, Jim_Obj *valObj)
13026 {
13027 int listlen;
@@ -13077,22 +13034,31 @@
13034 }
13035 }
13036 return 0;
13037 }
13038
13039
13040
13041 static int JimExprOpStrBin(Jim_Interp *interp, struct JimExprNode *node)
13042 {
13043 Jim_Obj *A, *B;
 
 
13044 jim_wide wC;
13045 int rc;
13046
13047 if ((rc = JimExprGetTerm(interp, node->left, &A)) != JIM_OK) {
13048 return rc;
13049 }
13050 if ((rc = JimExprGetTerm(interp, node->right, &B)) != JIM_OK) {
13051 Jim_DecrRefCount(interp, A);
13052 return rc;
13053 }
13054
13055 switch (node->type) {
13056 case JIM_EXPROP_STREQ:
13057 case JIM_EXPROP_STRNE:
13058 wC = Jim_StringEqObj(A, B);
13059 if (node->type == JIM_EXPROP_STRNE) {
13060 wC = !wC;
13061 }
13062 break;
13063 case JIM_EXPROP_STRIN:
13064 wC = JimSearchList(interp, B, A);
@@ -13101,178 +13067,99 @@
13067 wC = !JimSearchList(interp, B, A);
13068 break;
13069 default:
13070 abort();
13071 }
13072 Jim_SetResultInt(interp, wC);
13073
13074 Jim_DecrRefCount(interp, A);
13075 Jim_DecrRefCount(interp, B);
13076
13077 return rc;
13078 }
13079
13080 static int ExprBool(Jim_Interp *interp, Jim_Obj *obj)
13081 {
13082 long l;
13083 double d;
13084 int b;
13085 int ret = -1;
13086
13087
13088 Jim_IncrRefCount(obj);
13089
13090 if (Jim_GetLong(interp, obj, &l) == JIM_OK) {
13091 ret = (l != 0);
13092 }
13093 else if (Jim_GetDouble(interp, obj, &d) == JIM_OK) {
13094 ret = (d != 0);
13095 }
13096 else if (Jim_GetBoolean(interp, obj, &b) == JIM_OK) {
13097 ret = (b != 0);
13098 }
13099
13100 Jim_DecrRefCount(interp, obj);
13101 return ret;
13102 }
13103
13104 static int JimExprOpAnd(Jim_Interp *interp, struct JimExprNode *node)
13105 {
13106
13107 int result = JimExprGetTermBoolean(interp, node->left);
13108
13109 if (result == 1) {
13110
13111 result = JimExprGetTermBoolean(interp, node->right);
13112 }
13113 if (result == -1) {
13114 return JIM_ERR;
13115 }
13116 Jim_SetResultInt(interp, result);
13117 return JIM_OK;
13118 }
13119
13120 static int JimExprOpOr(Jim_Interp *interp, struct JimExprNode *node)
13121 {
13122
13123 int result = JimExprGetTermBoolean(interp, node->left);
13124
13125 if (result == 0) {
13126
13127 result = JimExprGetTermBoolean(interp, node->right);
13128 }
13129 if (result == -1) {
13130 return JIM_ERR;
13131 }
13132 Jim_SetResultInt(interp, result);
13133 return JIM_OK;
13134 }
13135
13136 static int JimExprOpTernary(Jim_Interp *interp, struct JimExprNode *node)
13137 {
13138
13139 int result = JimExprGetTermBoolean(interp, node->left);
13140
13141 if (result == 1) {
13142
13143 return JimExprEvalTermNode(interp, node->right);
13144 }
13145 else if (result == 0) {
13146
13147 return JimExprEvalTermNode(interp, node->ternary);
13148 }
13149
13150 return JIM_ERR;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13151 }
13152
13153 enum
13154 {
13155 OP_FUNC = 0x0001,
13156 OP_RIGHT_ASSOC = 0x0002,
 
 
13157 };
13158
13159 #define OPRINIT_ATTR(N, P, ARITY, F, ATTR) {N, F, P, ARITY, ATTR, sizeof(N) - 1}
13160 #define OPRINIT(N, P, ARITY, F) OPRINIT_ATTR(N, P, ARITY, F, 0)
13161
13162 static const struct Jim_ExprOperator Jim_ExprOperators[] = {
13163 OPRINIT("*", 110, 2, JimExprOpBin),
13164 OPRINIT("/", 110, 2, JimExprOpBin),
13165 OPRINIT("%", 110, 2, JimExprOpIntBin),
@@ -13296,86 +13183,79 @@
13183
13184 OPRINIT("&", 50, 2, JimExprOpIntBin),
13185 OPRINIT("^", 49, 2, JimExprOpIntBin),
13186 OPRINIT("|", 48, 2, JimExprOpIntBin),
13187
13188 OPRINIT("&&", 10, 2, JimExprOpAnd),
13189 OPRINIT("||", 9, 2, JimExprOpOr),
13190 OPRINIT_ATTR("?", 5, 3, JimExprOpTernary, OP_RIGHT_ASSOC),
13191 OPRINIT_ATTR(":", 5, 3, NULL, OP_RIGHT_ASSOC),
13192
13193
13194 OPRINIT_ATTR("**", 120, 2, JimExprOpBin, OP_RIGHT_ASSOC),
 
 
 
 
 
 
 
 
 
 
13195
13196 OPRINIT("eq", 60, 2, JimExprOpStrBin),
13197 OPRINIT("ne", 60, 2, JimExprOpStrBin),
13198
13199 OPRINIT("in", 55, 2, JimExprOpStrBin),
13200 OPRINIT("ni", 55, 2, JimExprOpStrBin),
13201
13202 OPRINIT_ATTR("!", 150, 1, JimExprOpNumUnary, OP_RIGHT_ASSOC),
13203 OPRINIT_ATTR("~", 150, 1, JimExprOpIntUnary, OP_RIGHT_ASSOC),
13204 OPRINIT_ATTR(" -", 150, 1, JimExprOpNumUnary, OP_RIGHT_ASSOC),
13205 OPRINIT_ATTR(" +", 150, 1, JimExprOpNumUnary, OP_RIGHT_ASSOC),
13206
13207
13208
13209 OPRINIT_ATTR("int", 200, 1, JimExprOpNumUnary, OP_FUNC),
13210 OPRINIT_ATTR("wide", 200, 1, JimExprOpNumUnary, OP_FUNC),
13211 OPRINIT_ATTR("abs", 200, 1, JimExprOpNumUnary, OP_FUNC),
13212 OPRINIT_ATTR("double", 200, 1, JimExprOpNumUnary, OP_FUNC),
13213 OPRINIT_ATTR("round", 200, 1, JimExprOpNumUnary, OP_FUNC),
13214 OPRINIT_ATTR("rand", 200, 0, JimExprOpNone, OP_FUNC),
13215 OPRINIT_ATTR("srand", 200, 1, JimExprOpIntUnary, OP_FUNC),
13216
13217 #ifdef JIM_MATH_FUNCTIONS
13218 OPRINIT_ATTR("sin", 200, 1, JimExprOpDoubleUnary, OP_FUNC),
13219 OPRINIT_ATTR("cos", 200, 1, JimExprOpDoubleUnary, OP_FUNC),
13220 OPRINIT_ATTR("tan", 200, 1, JimExprOpDoubleUnary, OP_FUNC),
13221 OPRINIT_ATTR("asin", 200, 1, JimExprOpDoubleUnary, OP_FUNC),
13222 OPRINIT_ATTR("acos", 200, 1, JimExprOpDoubleUnary, OP_FUNC),
13223 OPRINIT_ATTR("atan", 200, 1, JimExprOpDoubleUnary, OP_FUNC),
13224 OPRINIT_ATTR("atan2", 200, 2, JimExprOpBin, OP_FUNC),
13225 OPRINIT_ATTR("sinh", 200, 1, JimExprOpDoubleUnary, OP_FUNC),
13226 OPRINIT_ATTR("cosh", 200, 1, JimExprOpDoubleUnary, OP_FUNC),
13227 OPRINIT_ATTR("tanh", 200, 1, JimExprOpDoubleUnary, OP_FUNC),
13228 OPRINIT_ATTR("ceil", 200, 1, JimExprOpDoubleUnary, OP_FUNC),
13229 OPRINIT_ATTR("floor", 200, 1, JimExprOpDoubleUnary, OP_FUNC),
13230 OPRINIT_ATTR("exp", 200, 1, JimExprOpDoubleUnary, OP_FUNC),
13231 OPRINIT_ATTR("log", 200, 1, JimExprOpDoubleUnary, OP_FUNC),
13232 OPRINIT_ATTR("log10", 200, 1, JimExprOpDoubleUnary, OP_FUNC),
13233 OPRINIT_ATTR("sqrt", 200, 1, JimExprOpDoubleUnary, OP_FUNC),
13234 OPRINIT_ATTR("pow", 200, 2, JimExprOpBin, OP_FUNC),
13235 OPRINIT_ATTR("hypot", 200, 2, JimExprOpBin, OP_FUNC),
13236 OPRINIT_ATTR("fmod", 200, 2, JimExprOpBin, OP_FUNC),
13237 #endif
13238 };
13239 #undef OPRINIT
13240 #undef OPRINIT_ATTR
13241
13242 #define JIM_EXPR_OPERATORS_NUM \
13243 (sizeof(Jim_ExprOperators)/sizeof(struct Jim_ExprOperator))
13244
13245 static int JimParseExpression(struct JimParserCtx *pc)
13246 {
13247
13248 while (isspace(UCHAR(*pc->p)) || (*(pc->p) == '\\' && *(pc->p + 1) == '\n')) {
13249 if (*pc->p == '\n') {
13250 pc->linenr++;
13251 }
13252 pc->p++;
13253 pc->len--;
13254 }
13255
13256
13257 pc->tline = pc->linenr;
13258 pc->tstart = pc->p;
13259
13260 if (pc->len == 0) {
13261 pc->tend = pc->p;
@@ -13401,11 +13281,11 @@
13281 return JimParseCmd(pc);
13282 case '$':
13283 if (JimParseVar(pc) == JIM_ERR)
13284 return JimParseExprOperator(pc);
13285 else {
13286
13287 if (pc->tt == JIM_TT_EXPRSUGAR) {
13288 return JIM_ERR;
13289 }
13290 return JIM_OK;
13291 }
@@ -13430,10 +13310,18 @@
13310 case 'N':
13311 case 'I':
13312 case 'n':
13313 case 'i':
13314 if (JimParseExprIrrational(pc) == JIM_ERR)
13315 if (JimParseExprBoolean(pc) == JIM_ERR)
13316 return JimParseExprOperator(pc);
13317 break;
13318 case 't':
13319 case 'f':
13320 case 'o':
13321 case 'y':
13322 if (JimParseExprBoolean(pc) == JIM_ERR)
13323 return JimParseExprOperator(pc);
13324 break;
13325 default:
13326 return JimParseExprOperator(pc);
13327 break;
@@ -13443,21 +13331,21 @@
13331
13332 static int JimParseExprNumber(struct JimParserCtx *pc)
13333 {
13334 char *end;
13335
13336
13337 pc->tt = JIM_TT_EXPR_INT;
13338
13339 jim_strtoull(pc->p, (char **)&pc->p);
13340
13341 if (strchr("eENnIi.", *pc->p) || pc->p == pc->tstart) {
13342 if (strtod(pc->tstart, &end)) { }
13343 if (end == pc->tstart)
13344 return JIM_ERR;
13345 if (end > pc->p) {
13346
13347 pc->tt = JIM_TT_EXPR_DOUBLE;
13348 pc->p = end;
13349 }
13350 }
13351 pc->tend = pc->p - 1;
@@ -13481,36 +13369,66 @@
13369 return JIM_OK;
13370 }
13371 }
13372 return JIM_ERR;
13373 }
13374
13375 static int JimParseExprBoolean(struct JimParserCtx *pc)
13376 {
13377 const char *booleans[] = { "false", "no", "off", "true", "yes", "on", NULL };
13378 const int lengths[] = { 5, 2, 3, 4, 3, 2, 0 };
13379 int i;
13380
13381 for (i = 0; booleans[i]; i++) {
13382 const char *boolean = booleans[i];
13383 int length = lengths[i];
13384
13385 if (strncmp(boolean, pc->p, length) == 0) {
13386 pc->p += length;
13387 pc->len -= length;
13388 pc->tend = pc->p - 1;
13389 pc->tt = JIM_TT_EXPR_BOOLEAN;
13390 return JIM_OK;
13391 }
13392 }
13393 return JIM_ERR;
13394 }
13395
13396 static const struct Jim_ExprOperator *JimExprOperatorInfoByOpcode(int opcode)
13397 {
13398 static Jim_ExprOperator dummy_op;
13399 if (opcode < JIM_TT_EXPR_OP) {
13400 return &dummy_op;
13401 }
13402 return &Jim_ExprOperators[opcode - JIM_TT_EXPR_OP];
13403 }
13404
13405 static int JimParseExprOperator(struct JimParserCtx *pc)
13406 {
13407 int i;
13408 const struct Jim_ExprOperator *bestOp = NULL;
13409 int bestLen = 0;
13410
13411
13412 for (i = 0; i < (signed)JIM_EXPR_OPERATORS_NUM; i++) {
13413 const struct Jim_ExprOperator *op = &Jim_ExprOperators[i];
 
13414
13415 if (op->name[0] != pc->p[0]) {
13416 continue;
13417 }
13418
13419 if (op->namelen > bestLen && strncmp(op->name, pc->p, op->namelen) == 0) {
13420 bestOp = op;
13421 bestLen = op->namelen;
13422 }
13423 }
13424 if (bestOp == NULL) {
13425 return JIM_ERR;
13426 }
13427
13428
13429 if (bestOp->attr & OP_FUNC) {
13430 const char *p = pc->p + bestLen;
13431 int len = pc->len - bestLen;
13432
13433 while (len && isspace(UCHAR(*p))) {
13434 len--;
@@ -13522,30 +13440,27 @@
13440 }
13441 pc->tend = pc->p + bestLen - 1;
13442 pc->p += bestLen;
13443 pc->len -= bestLen;
13444
13445 pc->tt = (bestOp - Jim_ExprOperators) + JIM_TT_EXPR_OP;
13446 return JIM_OK;
13447 }
13448
 
 
 
 
 
 
 
 
 
13449 const char *jim_tt_name(int type)
13450 {
13451 static const char * const tt_names[JIM_TT_EXPR_OP] =
13452 { "NIL", "STR", "ESC", "VAR", "ARY", "CMD", "SEP", "EOL", "EOF", "LIN", "WRD", "(((", ")))", ",,,", "INT",
13453 "DBL", "BOO", "$()" };
13454 if (type < JIM_TT_EXPR_OP) {
13455 return tt_names[type];
13456 }
13457 else if (type == JIM_EXPROP_UNARYMINUS) {
13458 return "-VE";
13459 }
13460 else if (type == JIM_EXPROP_UNARYPLUS) {
13461 return "+VE";
13462 }
13463 else {
13464 const struct Jim_ExprOperator *op = JimExprOperatorInfoByOpcode(type);
13465 static char buf[20];
13466
@@ -13568,432 +13483,400 @@
13483 NULL,
13484 JIM_TYPE_REFERENCES,
13485 };
13486
13487
13488 struct ExprTree
13489 {
13490 struct JimExprNode *expr;
13491 struct JimExprNode *nodes;
13492 int len;
13493 int inUse;
13494 };
13495
13496 static void ExprTreeFreeNodes(Jim_Interp *interp, struct JimExprNode *nodes, int num)
13497 {
13498 int i;
13499 for (i = 0; i < num; i++) {
13500 if (nodes[i].objPtr) {
13501 Jim_DecrRefCount(interp, nodes[i].objPtr);
13502 }
13503 }
13504 Jim_Free(nodes);
13505 }
13506
13507 static void ExprTreeFree(Jim_Interp *interp, struct ExprTree *expr)
13508 {
13509 ExprTreeFreeNodes(interp, expr->nodes, expr->len);
 
13510 Jim_Free(expr);
13511 }
13512
13513 static void FreeExprInternalRep(Jim_Interp *interp, Jim_Obj *objPtr)
13514 {
13515 struct ExprTree *expr = (void *)objPtr->internalRep.ptr;
13516
13517 if (expr) {
13518 if (--expr->inUse != 0) {
13519 return;
13520 }
13521
13522 ExprTreeFree(interp, expr);
13523 }
13524 }
13525
13526 static void DupExprInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr)
13527 {
13528 JIM_NOTUSED(interp);
13529 JIM_NOTUSED(srcPtr);
13530
13531
13532 dupPtr->typePtr = NULL;
13533 }
13534
13535 struct ExprBuilder {
13536 int parencount;
13537 int level;
13538 ParseToken *token;
13539 ParseToken *first_token;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13540 Jim_Stack stack;
13541 Jim_Obj *exprObjPtr;
13542 Jim_Obj *fileNameObj;
13543 struct JimExprNode *nodes;
13544 struct JimExprNode *next;
13545 };
13546
13547 #ifdef DEBUG_SHOW_EXPR
13548 static void JimShowExprNode(struct JimExprNode *node, int level)
13549 {
13550 int i;
13551 for (i = 0; i < level; i++) {
13552 printf(" ");
13553 }
13554 if (TOKEN_IS_EXPR_OP(node->type)) {
13555 printf("%s\n", jim_tt_name(node->type));
13556 if (node->left) {
13557 JimShowExprNode(node->left, level + 1);
13558 }
13559 if (node->right) {
13560 JimShowExprNode(node->right, level + 1);
13561 }
13562 if (node->ternary) {
13563 JimShowExprNode(node->ternary, level + 1);
13564 }
13565 }
13566 else {
13567 printf("[%s] %s\n", jim_tt_name(node->type), Jim_String(node->objPtr));
13568 }
13569 }
13570 #endif
13571
13572 #define EXPR_UNTIL_CLOSE 0x0001
13573 #define EXPR_FUNC_ARGS 0x0002
13574 #define EXPR_TERNARY 0x0004
13575
13576 static int ExprTreeBuildTree(Jim_Interp *interp, struct ExprBuilder *builder, int precedence, int flags, int exp_numterms)
13577 {
13578 int rc;
13579 struct JimExprNode *node;
13580
13581 int exp_stacklen = builder->stack.len + exp_numterms;
13582
13583 if (builder->level++ > 200) {
13584 Jim_SetResultString(interp, "Expression too complex", -1);
13585 return JIM_ERR;
13586 }
13587
13588 while (builder->token->type != JIM_TT_EOL) {
13589 ParseToken *t = builder->token++;
13590 int prevtt;
13591
13592 if (t == builder->first_token) {
13593 prevtt = JIM_TT_NONE;
13594 }
13595 else {
13596 prevtt = t[-1].type;
13597 }
13598
13599 if (t->type == JIM_TT_SUBEXPR_START) {
13600 if (builder->stack.len == exp_stacklen) {
13601 Jim_SetResultFormatted(interp, "unexpected open parenthesis in expression: \"%#s\"", builder->exprObjPtr);
13602 return JIM_ERR;
13603 }
13604 builder->parencount++;
13605 rc = ExprTreeBuildTree(interp, builder, 0, EXPR_UNTIL_CLOSE, 1);
13606 if (rc != JIM_OK) {
13607 return rc;
13608 }
13609
13610 }
13611 else if (t->type == JIM_TT_SUBEXPR_END) {
13612 if (!(flags & EXPR_UNTIL_CLOSE)) {
13613 if (builder->stack.len == exp_stacklen && builder->level > 1) {
13614 builder->token--;
13615 builder->level--;
13616 return JIM_OK;
13617 }
13618 Jim_SetResultFormatted(interp, "unexpected closing parenthesis in expression: \"%#s\"", builder->exprObjPtr);
13619 return JIM_ERR;
13620 }
13621 builder->parencount--;
13622 if (builder->stack.len == exp_stacklen) {
13623
13624 break;
13625 }
13626 }
13627 else if (t->type == JIM_TT_SUBEXPR_COMMA) {
13628 if (!(flags & EXPR_FUNC_ARGS)) {
13629 if (builder->stack.len == exp_stacklen) {
13630
13631 builder->token--;
13632 builder->level--;
13633 return JIM_OK;
13634 }
13635 Jim_SetResultFormatted(interp, "unexpected comma in expression: \"%#s\"", builder->exprObjPtr);
13636 return JIM_ERR;
13637 }
13638 else {
13639
13640 if (builder->stack.len > exp_stacklen) {
13641 Jim_SetResultFormatted(interp, "too many arguments to math function");
13642 return JIM_ERR;
13643 }
13644 }
13645
13646 }
13647 else if (t->type == JIM_EXPROP_COLON) {
13648 if (!(flags & EXPR_TERNARY)) {
13649 if (builder->level != 1) {
13650
13651 builder->token--;
13652 builder->level--;
13653 return JIM_OK;
13654 }
13655 Jim_SetResultFormatted(interp, ": without ? in expression: \"%#s\"", builder->exprObjPtr);
13656 return JIM_ERR;
13657 }
13658 if (builder->stack.len == exp_stacklen) {
13659
13660 builder->token--;
13661 builder->level--;
13662 return JIM_OK;
13663 }
13664
13665 }
13666 else if (TOKEN_IS_EXPR_OP(t->type)) {
13667 const struct Jim_ExprOperator *op;
13668
13669
13670 if (TOKEN_IS_EXPR_OP(prevtt) || TOKEN_IS_EXPR_START(prevtt)) {
13671 if (t->type == JIM_EXPROP_SUB) {
13672 t->type = JIM_EXPROP_UNARYMINUS;
13673 }
13674 else if (t->type == JIM_EXPROP_ADD) {
13675 t->type = JIM_EXPROP_UNARYPLUS;
13676 }
13677 }
13678
13679 op = JimExprOperatorInfoByOpcode(t->type);
13680
13681 if (op->precedence < precedence || (!(op->attr & OP_RIGHT_ASSOC) && op->precedence == precedence)) {
13682
13683 builder->token--;
13684 break;
13685 }
13686
13687 if (op->attr & OP_FUNC) {
13688 if (builder->token->type != JIM_TT_SUBEXPR_START) {
13689 Jim_SetResultString(interp, "missing arguments for math function", -1);
13690 return JIM_ERR;
13691 }
13692 builder->token++;
13693 if (op->arity == 0) {
13694 if (builder->token->type != JIM_TT_SUBEXPR_END) {
13695 Jim_SetResultString(interp, "too many arguments for math function", -1);
13696 return JIM_ERR;
13697 }
13698 builder->token++;
13699 goto noargs;
13700 }
13701 builder->parencount++;
13702
13703
13704 rc = ExprTreeBuildTree(interp, builder, 0, EXPR_FUNC_ARGS | EXPR_UNTIL_CLOSE, op->arity);
13705 }
13706 else if (t->type == JIM_EXPROP_TERNARY) {
13707
13708 rc = ExprTreeBuildTree(interp, builder, op->precedence, EXPR_TERNARY, 2);
13709 }
13710 else {
13711 rc = ExprTreeBuildTree(interp, builder, op->precedence, 0, 1);
13712 }
13713
13714 if (rc != JIM_OK) {
13715 return rc;
13716 }
13717
13718 noargs:
13719 node = builder->next++;
13720 node->type = t->type;
13721
13722 if (op->arity >= 3) {
13723 node->ternary = Jim_StackPop(&builder->stack);
13724 if (node->ternary == NULL) {
13725 goto missingoperand;
13726 }
13727 }
13728 if (op->arity >= 2) {
13729 node->right = Jim_StackPop(&builder->stack);
13730 if (node->right == NULL) {
13731 goto missingoperand;
13732 }
13733 }
13734 if (op->arity >= 1) {
13735 node->left = Jim_StackPop(&builder->stack);
13736 if (node->left == NULL) {
13737 missingoperand:
13738 Jim_SetResultFormatted(interp, "missing operand to %s in expression: \"%#s\"", op->name, builder->exprObjPtr);
13739 builder->next--;
13740 return JIM_ERR;
13741
13742 }
13743 }
13744
13745
13746 Jim_StackPush(&builder->stack, node);
13747 }
13748 else {
13749 Jim_Obj *objPtr = NULL;
13750
13751
13752
13753
13754 if (!TOKEN_IS_EXPR_START(prevtt) && !TOKEN_IS_EXPR_OP(prevtt)) {
13755 Jim_SetResultFormatted(interp, "missing operator in expression: \"%#s\"", builder->exprObjPtr);
13756 return JIM_ERR;
13757 }
13758
13759
13760 if (t->type == JIM_TT_EXPR_INT || t->type == JIM_TT_EXPR_DOUBLE) {
13761 char *endptr;
13762 if (t->type == JIM_TT_EXPR_INT) {
13763 objPtr = Jim_NewIntObj(interp, jim_strtoull(t->token, &endptr));
13764 }
13765 else {
13766 objPtr = Jim_NewDoubleObj(interp, strtod(t->token, &endptr));
13767 }
13768 if (endptr != t->token + t->len) {
13769
13770 Jim_FreeNewObj(interp, objPtr);
13771 objPtr = NULL;
13772 }
13773 }
13774
13775 if (!objPtr) {
13776
13777 objPtr = Jim_NewStringObj(interp, t->token, t->len);
13778 if (t->type == JIM_TT_CMD) {
13779
13780 JimSetSourceInfo(interp, objPtr, builder->fileNameObj, t->line);
13781 }
13782 }
13783
13784
13785 node = builder->next++;
13786 node->objPtr = objPtr;
13787 Jim_IncrRefCount(node->objPtr);
13788 node->type = t->type;
13789 Jim_StackPush(&builder->stack, node);
13790 }
13791 }
13792
13793 if (builder->stack.len == exp_stacklen) {
13794 builder->level--;
13795 return JIM_OK;
13796 }
13797
13798 if ((flags & EXPR_FUNC_ARGS)) {
13799 Jim_SetResultFormatted(interp, "too %s arguments for math function", (builder->stack.len < exp_stacklen) ? "few" : "many");
13800 }
13801 else {
13802 if (builder->stack.len < exp_stacklen) {
13803 if (builder->level == 0) {
13804 Jim_SetResultFormatted(interp, "empty expression");
13805 }
13806 else {
13807 Jim_SetResultFormatted(interp, "syntax error in expression \"%#s\": premature end of expression", builder->exprObjPtr);
13808 }
13809 }
13810 else {
13811 Jim_SetResultFormatted(interp, "extra terms after expression");
13812 }
13813 }
13814
13815 return JIM_ERR;
13816 }
13817
13818 static struct ExprTree *ExprTreeCreateTree(Jim_Interp *interp, const ParseTokenList *tokenlist, Jim_Obj *exprObjPtr, Jim_Obj *fileNameObj)
13819 {
13820 struct ExprTree *expr;
13821 struct ExprBuilder builder;
13822 int rc;
13823 struct JimExprNode *top = NULL;
13824
13825 builder.parencount = 0;
13826 builder.level = 0;
13827 builder.token = builder.first_token = tokenlist->list;
13828 builder.exprObjPtr = exprObjPtr;
13829 builder.fileNameObj = fileNameObj;
13830
13831 builder.nodes = malloc(sizeof(struct JimExprNode) * (tokenlist->count - 1));
13832 memset(builder.nodes, 0, sizeof(struct JimExprNode) * (tokenlist->count - 1));
13833 builder.next = builder.nodes;
13834 Jim_InitStack(&builder.stack);
13835
13836 rc = ExprTreeBuildTree(interp, &builder, 0, 0, 1);
13837
13838 if (rc == JIM_OK) {
13839 top = Jim_StackPop(&builder.stack);
13840
13841 if (builder.parencount) {
13842 Jim_SetResultString(interp, "missing close parenthesis", -1);
13843 rc = JIM_ERR;
13844 }
13845 }
13846
13847
13848 Jim_FreeStack(&builder.stack);
13849
13850 if (rc != JIM_OK) {
13851 ExprTreeFreeNodes(interp, builder.nodes, builder.next - builder.nodes);
13852 return NULL;
13853 }
13854
13855 expr = Jim_Alloc(sizeof(*expr));
13856 expr->inUse = 1;
13857 expr->expr = top;
13858 expr->nodes = builder.nodes;
13859 expr->len = builder.next - builder.nodes;
13860
13861 assert(expr->len <= tokenlist->count - 1);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13862
13863 return expr;
13864 }
 
13865
13866 static int SetExprFromAny(Jim_Interp *interp, struct Jim_Obj *objPtr)
13867 {
13868 int exprTextLen;
13869 const char *exprText;
13870 struct JimParserCtx parser;
13871 struct ExprTree *expr;
13872 ParseTokenList tokenlist;
13873 int line;
13874 Jim_Obj *fileNameObj;
13875 int rc = JIM_ERR;
13876
13877
13878 if (objPtr->typePtr == &sourceObjType) {
13879 fileNameObj = objPtr->internalRep.sourceValue.fileNameObj;
13880 line = objPtr->internalRep.sourceValue.lineNumber;
13881 }
13882 else {
@@ -14002,18 +13885,17 @@
13885 }
13886 Jim_IncrRefCount(fileNameObj);
13887
13888 exprText = Jim_GetString(objPtr, &exprTextLen);
13889
13890
13891 ScriptTokenListInit(&tokenlist);
13892
13893 JimParserInit(&parser, exprText, exprTextLen, line);
13894 while (!parser.eof) {
13895 if (JimParseExpression(&parser) != JIM_OK) {
13896 ScriptTokenListFree(&tokenlist);
 
13897 Jim_SetResultFormatted(interp, "syntax error in expression: \"%#s\"", objPtr);
13898 expr = NULL;
13899 goto err;
13900 }
13901
@@ -14036,125 +13918,174 @@
13918 ScriptTokenListFree(&tokenlist);
13919 Jim_DecrRefCount(interp, fileNameObj);
13920 return JIM_ERR;
13921 }
13922
 
 
13923
13924 expr = ExprTreeCreateTree(interp, &tokenlist, objPtr, fileNameObj);
13925
13926
13927 ScriptTokenListFree(&tokenlist);
13928
13929 if (!expr) {
13930 goto err;
13931 }
13932
13933 #ifdef DEBUG_SHOW_EXPR
13934 printf("==== Expr ====\n");
13935 JimShowExprNode(expr->expr, 0);
 
 
 
 
 
 
 
 
13936 #endif
13937
 
 
 
 
 
 
13938 rc = JIM_OK;
13939
13940 err:
13941
13942 Jim_DecrRefCount(interp, fileNameObj);
13943 Jim_FreeIntRep(interp, objPtr);
13944 Jim_SetIntRepPtr(objPtr, expr);
13945 objPtr->typePtr = &exprObjType;
13946 return rc;
13947 }
13948
13949 static struct ExprTree *JimGetExpression(Jim_Interp *interp, Jim_Obj *objPtr)
13950 {
13951 if (objPtr->typePtr != &exprObjType) {
13952 if (SetExprFromAny(interp, objPtr) != JIM_OK) {
13953 return NULL;
13954 }
13955 }
13956 return (struct ExprTree *) Jim_GetIntRepPtr(objPtr);
13957 }
13958
13959 #ifdef JIM_OPTIMIZATION
13960 static Jim_Obj *JimExprIntValOrVar(Jim_Interp *interp, struct JimExprNode *node)
13961 {
13962 if (node->type == JIM_TT_EXPR_INT)
13963 return node->objPtr;
13964 else if (node->type == JIM_TT_VAR)
13965 return Jim_GetVariable(interp, node->objPtr, JIM_NONE);
13966 else if (node->type == JIM_TT_DICTSUGAR)
13967 return JimExpandDictSugar(interp, node->objPtr);
13968 else
13969 return NULL;
13970 }
13971 #endif
13972
13973
13974 static int JimExprEvalTermNode(Jim_Interp *interp, struct JimExprNode *node)
13975 {
13976 if (TOKEN_IS_EXPR_OP(node->type)) {
13977 const struct Jim_ExprOperator *op = JimExprOperatorInfoByOpcode(node->type);
13978 return op->funcop(interp, node);
13979 }
13980 else {
13981 Jim_Obj *objPtr;
13982
13983
13984 switch (node->type) {
13985 case JIM_TT_EXPR_INT:
13986 case JIM_TT_EXPR_DOUBLE:
13987 case JIM_TT_EXPR_BOOLEAN:
13988 case JIM_TT_STR:
13989 Jim_SetResult(interp, node->objPtr);
13990 return JIM_OK;
13991
13992 case JIM_TT_VAR:
13993 objPtr = Jim_GetVariable(interp, node->objPtr, JIM_ERRMSG);
13994 if (objPtr) {
13995 Jim_SetResult(interp, objPtr);
13996 return JIM_OK;
13997 }
13998 return JIM_ERR;
13999
14000 case JIM_TT_DICTSUGAR:
14001 objPtr = JimExpandDictSugar(interp, node->objPtr);
14002 if (objPtr) {
14003 Jim_SetResult(interp, objPtr);
14004 return JIM_OK;
14005 }
14006 return JIM_ERR;
14007
14008 case JIM_TT_ESC:
14009 if (Jim_SubstObj(interp, node->objPtr, &objPtr, JIM_NONE) == JIM_OK) {
14010 Jim_SetResult(interp, objPtr);
14011 return JIM_OK;
14012 }
14013 return JIM_ERR;
14014
14015 case JIM_TT_CMD:
14016 return Jim_EvalObj(interp, node->objPtr);
14017
14018 default:
14019
14020 return JIM_ERR;
14021 }
14022 }
14023 }
14024
14025 static int JimExprGetTerm(Jim_Interp *interp, struct JimExprNode *node, Jim_Obj **objPtrPtr)
14026 {
14027 int rc = JimExprEvalTermNode(interp, node);
14028 if (rc == JIM_OK) {
14029 *objPtrPtr = Jim_GetResult(interp);
14030 Jim_IncrRefCount(*objPtrPtr);
14031 }
14032 return rc;
14033 }
14034
14035 static int JimExprGetTermBoolean(Jim_Interp *interp, struct JimExprNode *node)
14036 {
14037 if (JimExprEvalTermNode(interp, node) == JIM_OK) {
14038 return ExprBool(interp, Jim_GetResult(interp));
14039 }
14040 return -1;
14041 }
14042
14043 int Jim_EvalExpression(Jim_Interp *interp, Jim_Obj *exprObjPtr)
14044 {
14045 struct ExprTree *expr;
14046 int retcode = JIM_OK;
14047
14048 expr = JimGetExpression(interp, exprObjPtr);
14049 if (!expr) {
14050 return JIM_ERR;
14051 }
14052
14053 #ifdef JIM_OPTIMIZATION
14054 {
14055 Jim_Obj *objPtr;
14056
14057
14058 switch (expr->len) {
14059 case 1:
14060 objPtr = JimExprIntValOrVar(interp, expr->expr);
14061 if (objPtr) {
14062 Jim_SetResult(interp, objPtr);
 
14063 return JIM_OK;
14064 }
14065 break;
14066
14067 case 2:
14068 if (expr->expr->type == JIM_EXPROP_NOT) {
14069 objPtr = JimExprIntValOrVar(interp, expr->expr->left);
14070
14071 if (objPtr && JimIsWide(objPtr)) {
14072 Jim_SetResult(interp, JimWideValue(objPtr) ? interp->falseObj : interp->trueObj);
 
14073 return JIM_OK;
14074 }
14075 }
14076 break;
14077
14078 case 3:
14079 objPtr = JimExprIntValOrVar(interp, expr->expr->left);
14080 if (objPtr && JimIsWide(objPtr)) {
14081 Jim_Obj *objPtr2 = JimExprIntValOrVar(interp, expr->expr->right);
14082 if (objPtr2 && JimIsWide(objPtr2)) {
14083 jim_wide wideValueA = JimWideValue(objPtr);
14084 jim_wide wideValueB = JimWideValue(objPtr2);
14085 int cmpRes;
14086 switch (expr->expr->type) {
14087 case JIM_EXPROP_LT:
14088 cmpRes = wideValueA < wideValueB;
14089 break;
14090 case JIM_EXPROP_LTE:
14091 cmpRes = wideValueA <= wideValueB;
@@ -14172,12 +14103,11 @@
14103 cmpRes = wideValueA != wideValueB;
14104 break;
14105 default:
14106 goto noopt;
14107 }
14108 Jim_SetResult(interp, cmpRes ? interp->trueObj : interp->falseObj);
 
14109 return JIM_OK;
14110 }
14111 }
14112 break;
14113 }
@@ -14185,145 +14115,64 @@
14115 noopt:
14116 #endif
14117
14118 expr->inUse++;
14119
14120
14121 retcode = JimExprEvalTermNode(interp, expr->expr);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
14122
14123 expr->inUse--;
14124
 
 
 
 
 
 
 
 
 
 
 
14125 return retcode;
14126 }
14127
14128 int Jim_GetBoolFromExpr(Jim_Interp *interp, Jim_Obj *exprObjPtr, int *boolPtr)
14129 {
14130 int retcode = Jim_EvalExpression(interp, exprObjPtr);
14131
14132 if (retcode == JIM_OK) {
14133 switch (ExprBool(interp, Jim_GetResult(interp))) {
14134 case 0:
14135 *boolPtr = 0;
14136 break;
14137
14138 case 1:
14139 *boolPtr = 1;
14140 break;
14141
14142 case -1:
14143 retcode = JIM_ERR;
14144 break;
14145 }
14146 }
14147 return retcode;
 
 
 
 
 
 
14148 }
14149
14150
14151
14152
14153 typedef struct ScanFmtPartDescr
14154 {
14155 const char *arg;
14156 const char *prefix;
14157 size_t width;
14158 int pos;
14159 char type;
14160 char modifier;
14161 } ScanFmtPartDescr;
14162
14163
14164 typedef struct ScanFmtStringObj
14165 {
14166 jim_wide size;
14167 char *stringRep;
14168 size_t count;
14169 size_t convCount;
14170 size_t maxPos;
14171 const char *error;
14172 char *scratch;
14173 ScanFmtPartDescr descr[1];
14174 } ScanFmtStringObj;
14175
14176
14177 static void FreeScanFmtInternalRep(Jim_Interp *interp, Jim_Obj *objPtr);
14178 static void DupScanFmtInternalRep(Jim_Interp *interp, Jim_Obj *srcPtr, Jim_Obj *dupPtr);
@@ -14364,28 +14213,28 @@
14213 static int SetScanFmtFromAny(Jim_Interp *interp, Jim_Obj *objPtr)
14214 {
14215 ScanFmtStringObj *fmtObj;
14216 char *buffer;
14217 int maxCount, i, approxSize, lastPos = -1;
14218 const char *fmt = Jim_String(objPtr);
14219 int maxFmtLen = Jim_Length(objPtr);
14220 const char *fmtEnd = fmt + maxFmtLen;
14221 int curr;
14222
14223 Jim_FreeIntRep(interp, objPtr);
14224
14225 for (i = 0, maxCount = 0; i < maxFmtLen; ++i)
14226 if (fmt[i] == '%')
14227 ++maxCount;
14228
14229 approxSize = sizeof(ScanFmtStringObj)
14230 +(maxCount + 1) * sizeof(ScanFmtPartDescr)
14231 +maxFmtLen * sizeof(char) + 3 + 1
14232 + maxFmtLen * sizeof(char) + 1
14233 + maxFmtLen * sizeof(char)
14234 +(maxCount + 1) * sizeof(char)
14235 +1;
14236 fmtObj = (ScanFmtStringObj *) Jim_Alloc(approxSize);
14237 memset(fmtObj, 0, approxSize);
14238 fmtObj->size = approxSize;
14239 fmtObj->maxPos = 0;
14240 fmtObj->scratch = (char *)&fmtObj->descr[maxCount + 1];
@@ -14397,12 +14246,12 @@
14246 for (i = 0, curr = 0; fmt < fmtEnd; ++fmt) {
14247 int width = 0, skip;
14248 ScanFmtPartDescr *descr = &fmtObj->descr[curr];
14249
14250 fmtObj->count++;
14251 descr->width = 0;
14252
14253 if (*fmt != '%' || fmt[1] == '%') {
14254 descr->type = 0;
14255 descr->prefix = &buffer[i];
14256 for (; fmt < fmtEnd; ++fmt) {
14257 if (*fmt == '%') {
@@ -14412,65 +14261,70 @@
14261 }
14262 buffer[i++] = *fmt;
14263 }
14264 buffer[i++] = 0;
14265 }
14266
14267 ++fmt;
14268
14269 if (fmt >= fmtEnd)
14270 goto done;
14271 descr->pos = 0;
14272 if (*fmt == '*') {
14273 descr->pos = -1;
14274 ++fmt;
14275 }
14276 else
14277 fmtObj->convCount++;
14278
14279 if (sscanf(fmt, "%d%n", &width, &skip) == 1) {
14280 fmt += skip;
14281
14282 if (descr->pos != -1 && *fmt == '$') {
14283 int prev;
14284
14285 ++fmt;
14286 descr->pos = width;
14287 width = 0;
14288
14289 if ((lastPos == 0 && descr->pos > 0)
14290 || (lastPos > 0 && descr->pos == 0)) {
14291 fmtObj->error = "cannot mix \"%\" and \"%n$\" conversion specifiers";
14292 return JIM_ERR;
14293 }
14294
14295 for (prev = 0; prev < curr; ++prev) {
14296 if (fmtObj->descr[prev].pos == -1)
14297 continue;
14298 if (fmtObj->descr[prev].pos == descr->pos) {
14299 fmtObj->error =
14300 "variable is assigned by multiple \"%n$\" conversion specifiers";
14301 return JIM_ERR;
14302 }
14303 }
14304 if (descr->pos < 0) {
14305 fmtObj->error =
14306 "\"%n$\" conversion specifier is negative";
14307 return JIM_ERR;
14308 }
14309
14310 if (sscanf(fmt, "%d%n", &width, &skip) == 1) {
14311 descr->width = width;
14312 fmt += skip;
14313 }
14314 if (descr->pos > 0 && (size_t) descr->pos > fmtObj->maxPos)
14315 fmtObj->maxPos = descr->pos;
14316 }
14317 else {
14318
14319 descr->width = width;
14320 }
14321 }
14322
14323 if (lastPos == -1)
14324 lastPos = descr->pos;
14325
14326 if (*fmt == '[') {
14327 int swapped = 1, beg = i, end, j;
14328
14329 descr->type = '[';
14330 descr->arg = &buffer[i];
@@ -14485,11 +14339,11 @@
14339 fmtObj->error = "unmatched [ in format string";
14340 return JIM_ERR;
14341 }
14342 end = i;
14343 buffer[i++] = 0;
14344
14345 while (swapped) {
14346 swapped = 0;
14347 for (j = beg + 1; j < end - 1; ++j) {
14348 if (buffer[j] == '-' && buffer[j - 1] > buffer[j + 1]) {
14349 char tmp = buffer[j - 1];
@@ -14500,13 +14354,18 @@
14354 }
14355 }
14356 }
14357 }
14358 else {
14359
14360 if (fmt < fmtEnd && strchr("hlL", *fmt))
14361 descr->modifier = tolower((int)*fmt++);
14362
14363 if (fmt >= fmtEnd) {
14364 fmtObj->error = "missing scan conversion character";
14365 return JIM_ERR;
14366 }
14367
14368 descr->type = *fmt;
14369 if (strchr("efgcsndoxui", *fmt) == 0) {
14370 fmtObj->error = "bad scan conversion character";
14371 return JIM_ERR;
@@ -14543,11 +14402,11 @@
14402 while (*str) {
14403 int c;
14404 int n;
14405
14406 if (!sdescr && isspace(UCHAR(*str)))
14407 break;
14408
14409 n = utf8_tounicode(str, &c);
14410 if (sdescr && !JimCharsetMatch(sdescr, c, JIM_CHARSET_SCAN))
14411 break;
14412 while (n--)
@@ -14566,89 +14425,89 @@
14425 size_t scanned = 0;
14426 size_t anchor = pos;
14427 int i;
14428 Jim_Obj *tmpObj = NULL;
14429
14430
14431 *valObjPtr = 0;
14432 if (descr->prefix) {
14433 for (i = 0; pos < strLen && descr->prefix[i]; ++i) {
14434
14435 if (isspace(UCHAR(descr->prefix[i])))
14436 while (pos < strLen && isspace(UCHAR(str[pos])))
14437 ++pos;
14438 else if (descr->prefix[i] != str[pos])
14439 break;
14440 else
14441 ++pos;
14442 }
14443 if (pos >= strLen) {
14444 return -1;
14445 }
14446 else if (descr->prefix[i] != 0)
14447 return 0;
14448 }
14449
14450 if (descr->type != 'c' && descr->type != '[' && descr->type != 'n')
14451 while (isspace(UCHAR(str[pos])))
14452 ++pos;
14453
14454 scanned = pos - anchor;
14455
14456
14457 if (descr->type == 'n') {
14458
14459 *valObjPtr = Jim_NewIntObj(interp, anchor + scanned);
14460 }
14461 else if (pos >= strLen) {
14462
14463 return -1;
14464 }
14465 else if (descr->type == 'c') {
14466 int c;
14467 scanned += utf8_tounicode(&str[pos], &c);
14468 *valObjPtr = Jim_NewIntObj(interp, c);
14469 return scanned;
14470 }
14471 else {
14472
14473 if (descr->width > 0) {
14474 size_t sLen = utf8_strlen(&str[pos], strLen - pos);
14475 size_t tLen = descr->width > sLen ? sLen : descr->width;
14476
14477 tmpObj = Jim_NewStringObjUtf8(interp, str + pos, tLen);
14478 tok = tmpObj->bytes;
14479 }
14480 else {
14481
14482 tok = &str[pos];
14483 }
14484 switch (descr->type) {
14485 case 'd':
14486 case 'o':
14487 case 'x':
14488 case 'u':
14489 case 'i':{
14490 char *endp;
14491 jim_wide w;
14492
14493 int base = descr->type == 'o' ? 8
14494 : descr->type == 'x' ? 16 : descr->type == 'i' ? 0 : 10;
14495
14496
14497 if (base == 0) {
14498 w = jim_strtoull(tok, &endp);
14499 }
14500 else {
14501 w = strtoull(tok, &endp, base);
14502 }
14503
14504 if (endp != tok) {
14505
14506 *valObjPtr = Jim_NewIntObj(interp, w);
14507
14508
14509 scanned += endp - tok;
14510 }
14511 else {
14512 scanned = *tok ? 0 : -1;
14513 }
@@ -14665,13 +14524,13 @@
14524 case 'g':{
14525 char *endp;
14526 double value = strtod(tok, &endp);
14527
14528 if (endp != tok) {
14529
14530 *valObjPtr = Jim_NewDoubleObj(interp, value);
14531
14532 scanned += endp - tok;
14533 }
14534 else {
14535 scanned = *tok ? 0 : -1;
14536 }
@@ -14696,65 +14555,65 @@
14555 Jim_Obj **resultVec = 0;
14556 int resultc;
14557 Jim_Obj *emptyStr = 0;
14558 ScanFmtStringObj *fmtObj;
14559
14560
14561 JimPanic((fmtObjPtr->typePtr != &scanFmtStringObjType, "Jim_ScanString() for non-scan format"));
14562
14563 fmtObj = (ScanFmtStringObj *) fmtObjPtr->internalRep.ptr;
14564
14565 if (fmtObj->error != 0) {
14566 if (flags & JIM_ERRMSG)
14567 Jim_SetResultString(interp, fmtObj->error, -1);
14568 return 0;
14569 }
14570
14571 emptyStr = Jim_NewEmptyStringObj(interp);
14572 Jim_IncrRefCount(emptyStr);
14573
14574 resultList = Jim_NewListObj(interp, NULL, 0);
14575 if (fmtObj->maxPos > 0) {
14576 for (i = 0; i < fmtObj->maxPos; ++i)
14577 Jim_ListAppendElement(interp, resultList, emptyStr);
14578 JimListGetElements(interp, resultList, &resultc, &resultVec);
14579 }
14580
14581 for (i = 0, pos = 0; i < fmtObj->count; ++i) {
14582 ScanFmtPartDescr *descr = &(fmtObj->descr[i]);
14583 Jim_Obj *value = 0;
14584
14585
14586 if (descr->type == 0)
14587 continue;
14588
14589 if (scanned > 0)
14590 scanned = ScanOneEntry(interp, str, pos, strLen, fmtObj, i, &value);
14591
14592 if (scanned == -1 && i == 0)
14593 goto eof;
14594
14595 pos += scanned;
14596
14597
14598 if (value == 0)
14599 value = Jim_NewEmptyStringObj(interp);
14600
14601 if (descr->pos == -1) {
14602 Jim_FreeNewObj(interp, value);
14603 }
14604 else if (descr->pos == 0)
14605
14606 Jim_ListAppendElement(interp, resultList, value);
14607 else if (resultVec[descr->pos - 1] == emptyStr) {
14608
14609 Jim_DecrRefCount(interp, resultVec[descr->pos - 1]);
14610 Jim_IncrRefCount(value);
14611 resultVec[descr->pos - 1] = value;
14612 }
14613 else {
14614
14615 Jim_FreeNewObj(interp, value);
14616 goto err;
14617 }
14618 }
14619 Jim_DecrRefCount(interp, emptyStr);
@@ -14792,15 +14651,15 @@
14651 {
14652 Jim_PrngState *prng;
14653 unsigned char *destByte = (unsigned char *)dest;
14654 unsigned int si, sj, x;
14655
14656
14657 if (interp->prngState == NULL)
14658 JimPrngInit(interp);
14659 prng = interp->prngState;
14660
14661 for (x = 0; x < len; x++) {
14662 prng->i = (prng->i + 1) & 0xff;
14663 si = prng->sbox[prng->i];
14664 prng->j = (prng->j + si) & 0xff;
14665 sj = prng->sbox[prng->j];
@@ -14814,19 +14673,19 @@
14673 static void JimPrngSeed(Jim_Interp *interp, unsigned char *seed, int seedLen)
14674 {
14675 int i;
14676 Jim_PrngState *prng;
14677
14678
14679 if (interp->prngState == NULL)
14680 JimPrngInit(interp);
14681 prng = interp->prngState;
14682
14683
14684 for (i = 0; i < 256; i++)
14685 prng->sbox[i] = i;
14686
14687 for (i = 0; i < seedLen; i++) {
14688 unsigned char t;
14689
14690 t = prng->sbox[i & 0xFF];
14691 prng->sbox[i & 0xFF] = prng->sbox[seed[i]];
@@ -14853,11 +14712,11 @@
14712 if (Jim_GetWide(interp, argv[2], &increment) != JIM_OK)
14713 return JIM_ERR;
14714 }
14715 intObjPtr = Jim_GetVariable(interp, argv[1], JIM_UNSHARED);
14716 if (!intObjPtr) {
14717
14718 wideValue = 0;
14719 }
14720 else if (Jim_GetWide(interp, intObjPtr, &wideValue) != JIM_OK) {
14721 return JIM_ERR;
14722 }
@@ -14867,26 +14726,26 @@
14726 Jim_FreeNewObj(interp, intObjPtr);
14727 return JIM_ERR;
14728 }
14729 }
14730 else {
14731
14732 Jim_InvalidateStringRep(intObjPtr);
14733 JimWideValue(intObjPtr) = wideValue + increment;
14734
14735 if (argv[1]->typePtr != &variableObjType) {
14736
14737 Jim_SetVariable(interp, argv[1], intObjPtr);
14738 }
14739 }
14740 Jim_SetResult(interp, intObjPtr);
14741 return JIM_OK;
14742 }
14743
14744
14745 #define JIM_EVAL_SARGV_LEN 8
14746 #define JIM_EVAL_SINTV_LEN 8
14747
14748
14749 static int JimUnknown(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
14750 {
14751 int retcode;
@@ -14894,16 +14753,16 @@
14753 if (interp->unknown_called > 50) {
14754 return JIM_ERR;
14755 }
14756
14757
14758
14759 if (Jim_GetCommand(interp, interp->unknown, JIM_NONE) == NULL)
14760 return JIM_ERR;
14761
14762 interp->unknown_called++;
14763
14764 retcode = Jim_EvalObjPrefix(interp, interp->unknown, argc, argv);
14765 interp->unknown_called--;
14766
14767 return retcode;
14768 }
@@ -14910,10 +14769,11 @@
14769
14770 static int JimInvokeCommand(Jim_Interp *interp, int objc, Jim_Obj *const *objv)
14771 {
14772 int retcode;
14773 Jim_Cmd *cmdPtr;
14774 void *prevPrivData;
14775
14776 #if 0
14777 printf("invoke");
14778 int j;
14779 for (j = 0; j < objc; j++) {
@@ -14921,11 +14781,11 @@
14781 }
14782 printf("\n");
14783 #endif
14784
14785 if (interp->framePtr->tailcallCmd) {
14786
14787 cmdPtr = interp->framePtr->tailcallCmd;
14788 interp->framePtr->tailcallCmd = NULL;
14789 }
14790 else {
14791 cmdPtr = Jim_GetCommand(interp, objv[0], JIM_ERRMSG);
@@ -14939,20 +14799,22 @@
14799 Jim_SetResultString(interp, "Infinite eval recursion", -1);
14800 retcode = JIM_ERR;
14801 goto out;
14802 }
14803 interp->evalDepth++;
14804 prevPrivData = interp->cmdPrivData;
14805
14806
14807 Jim_SetEmptyResult(interp);
14808 if (cmdPtr->isproc) {
14809 retcode = JimCallProcedure(interp, cmdPtr, objc, objv);
14810 }
14811 else {
14812 interp->cmdPrivData = cmdPtr->u.native.privData;
14813 retcode = cmdPtr->u.native.cmdProc(interp, objc, objv);
14814 }
14815 interp->cmdPrivData = prevPrivData;
14816 interp->evalDepth--;
14817
14818 out:
14819 JimDecrCmdRefCount(interp, cmdPtr);
14820
@@ -14961,17 +14823,17 @@
14823
14824 int Jim_EvalObjVector(Jim_Interp *interp, int objc, Jim_Obj *const *objv)
14825 {
14826 int i, retcode;
14827
14828
14829 for (i = 0; i < objc; i++)
14830 Jim_IncrRefCount(objv[i]);
14831
14832 retcode = JimInvokeCommand(interp, objc, objv);
14833
14834
14835 for (i = 0; i < objc; i++)
14836 Jim_DecrRefCount(interp, objv[i]);
14837
14838 return retcode;
14839 }
@@ -14989,25 +14851,25 @@
14851 }
14852
14853 static void JimAddErrorToStack(Jim_Interp *interp, ScriptObj *script)
14854 {
14855 if (!interp->errorFlag) {
14856
14857 interp->errorFlag = 1;
14858 Jim_IncrRefCount(script->fileNameObj);
14859 Jim_DecrRefCount(interp, interp->errorFileNameObj);
14860 interp->errorFileNameObj = script->fileNameObj;
14861 interp->errorLine = script->linenr;
14862
14863 JimResetStackTrace(interp);
14864
14865 interp->addStackTrace++;
14866 }
14867
14868
14869 if (interp->addStackTrace > 0) {
14870
14871
14872 JimAppendStackTrace(interp, Jim_String(interp->errorProc), script->fileNameObj, script->linenr);
14873
14874 if (Jim_Length(script->fileNameObj)) {
14875 interp->addStackTrace = 0;
@@ -15042,14 +14904,14 @@
14904 case JIM_OK:
14905 case JIM_RETURN:
14906 objPtr = interp->result;
14907 break;
14908 case JIM_BREAK:
14909
14910 return JIM_BREAK;
14911 case JIM_CONTINUE:
14912
14913 return JIM_CONTINUE;
14914 default:
14915 return JIM_ERR;
14916 }
14917 break;
@@ -15084,23 +14946,23 @@
14946 case JIM_OK:
14947 case JIM_RETURN:
14948 break;
14949 case JIM_BREAK:
14950 if (flags & JIM_SUBST_FLAG) {
14951
14952 tokens = i;
14953 continue;
14954 }
14955
14956
14957 case JIM_CONTINUE:
14958 if (flags & JIM_SUBST_FLAG) {
14959 intv[i] = NULL;
14960 continue;
14961 }
14962
14963
14964 default:
14965 while (i--) {
14966 Jim_DecrRefCount(interp, intv[i]);
14967 }
14968 if (intv != sintv) {
@@ -15111,28 +14973,29 @@
14973 Jim_IncrRefCount(intv[i]);
14974 Jim_String(intv[i]);
14975 totlen += intv[i]->length;
14976 }
14977
14978
14979 if (tokens == 1 && intv[0] && intv == sintv) {
14980
14981 intv[0]->refCount--;
14982 return intv[0];
14983 }
14984
14985 objPtr = Jim_NewStringObjNoAlloc(interp, NULL, 0);
14986
14987 if (tokens == 4 && token[0].type == JIM_TT_ESC && token[1].type == JIM_TT_ESC
14988 && token[2].type == JIM_TT_VAR) {
14989
14990 objPtr->typePtr = &interpolatedObjType;
14991 objPtr->internalRep.dictSubstValue.varNameObjPtr = token[0].objPtr;
14992 objPtr->internalRep.dictSubstValue.indexObjPtr = intv[2];
14993 Jim_IncrRefCount(intv[2]);
14994 }
14995 else if (tokens && intv[0] && intv[0]->typePtr == &sourceObjType) {
14996
14997 JimSetSourceInfo(interp, objPtr, intv[0]->internalRep.sourceValue.fileNameObj, intv[0]->internalRep.sourceValue.lineNumber);
14998 }
14999
15000
15001 s = objPtr->bytes = Jim_Alloc(totlen + 1);
@@ -15143,11 +15006,11 @@
15006 s += intv[i]->length;
15007 Jim_DecrRefCount(interp, intv[i]);
15008 }
15009 }
15010 objPtr->bytes[totlen] = '\0';
15011
15012 if (intv != sintv) {
15013 Jim_Free(intv);
15014 }
15015
15016 return objPtr;
@@ -15187,11 +15050,11 @@
15050
15051 if (Jim_IsList(scriptObjPtr) && scriptObjPtr->bytes == NULL) {
15052 return JimEvalObjList(interp, scriptObjPtr);
15053 }
15054
15055 Jim_IncrRefCount(scriptObjPtr);
15056 script = JimGetScript(interp, scriptObjPtr);
15057 if (!JimScriptValid(interp, script)) {
15058 Jim_DecrRefCount(interp, scriptObjPtr);
15059 return JIM_ERR;
15060 }
@@ -15223,11 +15086,11 @@
15086 }
15087 #endif
15088
15089 script->inUse++;
15090
15091
15092 prevScriptObj = interp->currentScriptObj;
15093 interp->currentScriptObj = scriptObjPtr;
15094
15095 interp->errorFlag = 0;
15096 argv = sargv;
@@ -15234,19 +15097,19 @@
15097
15098 for (i = 0; i < script->len && retcode == JIM_OK; ) {
15099 int argc;
15100 int j;
15101
15102
15103 argc = token[i].objPtr->internalRep.scriptLineValue.argc;
15104 script->linenr = token[i].objPtr->internalRep.scriptLineValue.line;
15105
15106
15107 if (argc > JIM_EVAL_SARGV_LEN)
15108 argv = Jim_Alloc(sizeof(Jim_Obj *) * argc);
15109
15110
15111 i++;
15112
15113 for (j = 0; j < argc; j++) {
15114 long wordtokens = 1;
15115 int expand = 0;
@@ -15302,11 +15165,11 @@
15165
15166 if (!expand) {
15167 argv[j] = wordObjPtr;
15168 }
15169 else {
15170
15171 int len = Jim_ListLength(interp, wordObjPtr);
15172 int newargc = argc + len - 1;
15173 int k;
15174
15175 if (len > 1) {
@@ -15315,39 +15178,39 @@
15178 argv = Jim_Alloc(sizeof(*argv) * newargc);
15179 memcpy(argv, sargv, sizeof(*argv) * j);
15180 }
15181 }
15182 else {
15183
15184 argv = Jim_Realloc(argv, sizeof(*argv) * newargc);
15185 }
15186 }
15187
15188
15189 for (k = 0; k < len; k++) {
15190 argv[j++] = wordObjPtr->internalRep.listValue.ele[k];
15191 Jim_IncrRefCount(wordObjPtr->internalRep.listValue.ele[k]);
15192 }
15193
15194 Jim_DecrRefCount(interp, wordObjPtr);
15195
15196
15197 j--;
15198 argc += len - 1;
15199 }
15200 }
15201
15202 if (retcode == JIM_OK && argc) {
15203
15204 retcode = JimInvokeCommand(interp, argc, argv);
15205
15206 if (Jim_CheckSignal(interp)) {
15207 retcode = JIM_SIGNAL;
15208 }
15209 }
15210
15211
15212 while (j-- > 0) {
15213 Jim_DecrRefCount(interp, argv[j]);
15214 }
15215
15216 if (argv != sargv) {
@@ -15354,21 +15217,21 @@
15217 Jim_Free(argv);
15218 argv = sargv;
15219 }
15220 }
15221
15222
15223 if (retcode == JIM_ERR) {
15224 JimAddErrorToStack(interp, script);
15225 }
15226
15227 else if (retcode != JIM_RETURN || interp->returnCode != JIM_ERR) {
15228
15229 interp->addStackTrace = 0;
15230 }
15231
15232
15233 interp->currentScriptObj = prevScriptObj;
15234
15235 Jim_FreeIntRep(interp, scriptObjPtr);
15236 scriptObjPtr->typePtr = &scriptObjType;
15237 Jim_SetIntRepPtr(scriptObjPtr, script);
@@ -15378,14 +15241,14 @@
15241 }
15242
15243 static int JimSetProcArg(Jim_Interp *interp, Jim_Obj *argNameObj, Jim_Obj *argValObj)
15244 {
15245 int retcode;
15246
15247 const char *varname = Jim_String(argNameObj);
15248 if (*varname == '&') {
15249
15250 Jim_Obj *objPtr;
15251 Jim_CallFrame *savedCallFrame = interp->framePtr;
15252
15253 interp->framePtr = interp->framePtr->parent;
15254 objPtr = Jim_GetVariable(interp, argValObj, JIM_ERRMSG);
@@ -15392,11 +15255,11 @@
15255 interp->framePtr = savedCallFrame;
15256 if (!objPtr) {
15257 return JIM_ERR;
15258 }
15259
15260
15261 objPtr = Jim_NewStringObj(interp, varname + 1, -1);
15262 Jim_IncrRefCount(objPtr);
15263 retcode = Jim_SetVariableLink(interp, objPtr, argValObj, interp->framePtr->parent);
15264 Jim_DecrRefCount(interp, objPtr);
15265 }
@@ -15406,26 +15269,26 @@
15269 return retcode;
15270 }
15271
15272 static void JimSetProcWrongArgs(Jim_Interp *interp, Jim_Obj *procNameObj, Jim_Cmd *cmd)
15273 {
15274
15275 Jim_Obj *argmsg = Jim_NewStringObj(interp, "", 0);
15276 int i;
15277
15278 for (i = 0; i < cmd->u.proc.argListLen; i++) {
15279 Jim_AppendString(interp, argmsg, " ", 1);
15280
15281 if (i == cmd->u.proc.argsPos) {
15282 if (cmd->u.proc.arglist[i].defaultObjPtr) {
15283
15284 Jim_AppendString(interp, argmsg, "?", 1);
15285 Jim_AppendObj(interp, argmsg, cmd->u.proc.arglist[i].defaultObjPtr);
15286 Jim_AppendString(interp, argmsg, " ...?", -1);
15287 }
15288 else {
15289
15290 Jim_AppendString(interp, argmsg, "?arg...?", -1);
15291 }
15292 }
15293 else {
15294 if (cmd->u.proc.arglist[i].defaultObjPtr) {
@@ -15441,20 +15304,19 @@
15304 Jim_AppendString(interp, argmsg, arg, -1);
15305 }
15306 }
15307 }
15308 Jim_SetResultFormatted(interp, "wrong # args: should be \"%#s%#s\"", procNameObj, argmsg);
 
15309 }
15310
15311 #ifdef jim_ext_namespace
15312 int Jim_EvalNamespace(Jim_Interp *interp, Jim_Obj *scriptObj, Jim_Obj *nsObj)
15313 {
15314 Jim_CallFrame *callFramePtr;
15315 int retcode;
15316
15317
15318 callFramePtr = JimCreateCallFrame(interp, interp->framePtr, nsObj);
15319 callFramePtr->argv = &interp->emptyObj;
15320 callFramePtr->argc = 0;
15321 callFramePtr->procArgsObjPtr = NULL;
15322 callFramePtr->procBodyObjPtr = scriptObj;
@@ -15462,21 +15324,21 @@
15324 callFramePtr->fileNameObj = interp->emptyObj;
15325 callFramePtr->line = 0;
15326 Jim_IncrRefCount(scriptObj);
15327 interp->framePtr = callFramePtr;
15328
15329
15330 if (interp->framePtr->level == interp->maxCallFrameDepth) {
15331 Jim_SetResultString(interp, "Too many nested calls. Infinite recursion?", -1);
15332 retcode = JIM_ERR;
15333 }
15334 else {
15335
15336 retcode = Jim_EvalObj(interp, scriptObj);
15337 }
15338
15339
15340 interp->framePtr = interp->framePtr->parent;
15341 JimFreeCallFrame(interp, callFramePtr, JIM_FCF_REUSE);
15342
15343 return retcode;
15344 }
@@ -15486,62 +15348,62 @@
15348 {
15349 Jim_CallFrame *callFramePtr;
15350 int i, d, retcode, optargs;
15351 ScriptObj *script;
15352
15353
15354 if (argc - 1 < cmd->u.proc.reqArity ||
15355 (cmd->u.proc.argsPos < 0 && argc - 1 > cmd->u.proc.reqArity + cmd->u.proc.optArity)) {
15356 JimSetProcWrongArgs(interp, argv[0], cmd);
15357 return JIM_ERR;
15358 }
15359
15360 if (Jim_Length(cmd->u.proc.bodyObjPtr) == 0) {
15361
15362 return JIM_OK;
15363 }
15364
15365
15366 if (interp->framePtr->level == interp->maxCallFrameDepth) {
15367 Jim_SetResultString(interp, "Too many nested calls. Infinite recursion?", -1);
15368 return JIM_ERR;
15369 }
15370
15371
15372 callFramePtr = JimCreateCallFrame(interp, interp->framePtr, cmd->u.proc.nsObj);
15373 callFramePtr->argv = argv;
15374 callFramePtr->argc = argc;
15375 callFramePtr->procArgsObjPtr = cmd->u.proc.argListObjPtr;
15376 callFramePtr->procBodyObjPtr = cmd->u.proc.bodyObjPtr;
15377 callFramePtr->staticVars = cmd->u.proc.staticVars;
15378
15379
15380 script = JimGetScript(interp, interp->currentScriptObj);
15381 callFramePtr->fileNameObj = script->fileNameObj;
15382 callFramePtr->line = script->linenr;
15383
15384 Jim_IncrRefCount(cmd->u.proc.argListObjPtr);
15385 Jim_IncrRefCount(cmd->u.proc.bodyObjPtr);
15386 interp->framePtr = callFramePtr;
15387
15388
15389 optargs = (argc - 1 - cmd->u.proc.reqArity);
15390
15391
15392 i = 1;
15393 for (d = 0; d < cmd->u.proc.argListLen; d++) {
15394 Jim_Obj *nameObjPtr = cmd->u.proc.arglist[d].nameObjPtr;
15395 if (d == cmd->u.proc.argsPos) {
15396
15397 Jim_Obj *listObjPtr;
15398 int argsLen = 0;
15399 if (cmd->u.proc.reqArity + cmd->u.proc.optArity < argc - 1) {
15400 argsLen = argc - 1 - (cmd->u.proc.reqArity + cmd->u.proc.optArity);
15401 }
15402 listObjPtr = Jim_NewListObj(interp, &argv[i], argsLen);
15403
15404
15405 if (cmd->u.proc.arglist[d].defaultObjPtr) {
15406 nameObjPtr =cmd->u.proc.arglist[d].defaultObjPtr;
15407 }
15408 retcode = Jim_SetVariable(interp, nameObjPtr, listObjPtr);
15409 if (retcode != JIM_OK) {
@@ -15550,33 +15412,34 @@
15412
15413 i += argsLen;
15414 continue;
15415 }
15416
15417
15418 if (cmd->u.proc.arglist[d].defaultObjPtr == NULL || optargs-- > 0) {
15419 retcode = JimSetProcArg(interp, nameObjPtr, argv[i++]);
15420 }
15421 else {
15422
15423 retcode = Jim_SetVariable(interp, nameObjPtr, cmd->u.proc.arglist[d].defaultObjPtr);
15424 }
15425 if (retcode != JIM_OK) {
15426 goto badargset;
15427 }
15428 }
15429
15430
15431 retcode = Jim_EvalObj(interp, cmd->u.proc.bodyObjPtr);
15432
15433 badargset:
15434
15435
15436 retcode = JimInvokeDefer(interp, retcode);
15437 interp->framePtr = interp->framePtr->parent;
15438 JimFreeCallFrame(interp, callFramePtr, JIM_FCF_REUSE);
15439
15440
15441 if (interp->framePtr->tailcallObj) {
15442 do {
15443 Jim_Obj *tailcallObj = interp->framePtr->tailcallObj;
15444
15445 interp->framePtr->tailcallObj = NULL;
@@ -15588,18 +15451,18 @@
15451 }
15452 }
15453 Jim_DecrRefCount(interp, tailcallObj);
15454 } while (interp->framePtr->tailcallObj);
15455
15456
15457 if (interp->framePtr->tailcallCmd) {
15458 JimDecrCmdRefCount(interp, interp->framePtr->tailcallCmd);
15459 interp->framePtr->tailcallCmd = NULL;
15460 }
15461 }
15462
15463
15464 if (retcode == JIM_RETURN) {
15465 if (--interp->returnLevel <= 0) {
15466 retcode = interp->returnCode;
15467 interp->returnCode = JIM_OK;
15468 interp->returnLevel = 0;
@@ -15711,20 +15574,20 @@
15574 prevScriptObj = interp->currentScriptObj;
15575 interp->currentScriptObj = scriptObjPtr;
15576
15577 retcode = Jim_EvalObj(interp, scriptObjPtr);
15578
15579
15580 if (retcode == JIM_RETURN) {
15581 if (--interp->returnLevel <= 0) {
15582 retcode = interp->returnCode;
15583 interp->returnCode = JIM_OK;
15584 interp->returnLevel = 0;
15585 }
15586 }
15587 if (retcode == JIM_ERR) {
15588
15589 interp->addStackTrace++;
15590 }
15591
15592 interp->currentScriptObj = prevScriptObj;
15593
@@ -15750,11 +15613,11 @@
15613 }
15614 if (*pc->p == '$' && !(flags & JIM_SUBST_NOVAR)) {
15615 if (JimParseVar(pc) == JIM_OK) {
15616 return;
15617 }
15618
15619 pc->tstart = pc->p;
15620 flags |= JIM_SUBST_NOVAR;
15621 }
15622 while (pc->len) {
15623 if (*pc->p == '$' && !(flags & JIM_SUBST_NOVAR)) {
@@ -15781,32 +15644,32 @@
15644 const char *scriptText = Jim_GetString(objPtr, &scriptTextLen);
15645 struct JimParserCtx parser;
15646 struct ScriptObj *script = Jim_Alloc(sizeof(*script));
15647 ParseTokenList tokenlist;
15648
15649
15650 ScriptTokenListInit(&tokenlist);
15651
15652 JimParserInit(&parser, scriptText, scriptTextLen, 1);
15653 while (1) {
15654 JimParseSubst(&parser, flags);
15655 if (parser.eof) {
15656
15657 break;
15658 }
15659 ScriptAddToken(&tokenlist, parser.tstart, parser.tend - parser.tstart + 1, parser.tt,
15660 parser.tline);
15661 }
15662
15663
15664 script->inUse = 1;
15665 script->substFlags = flags;
15666 script->fileNameObj = interp->emptyObj;
15667 Jim_IncrRefCount(script->fileNameObj);
15668 SubstObjAddTokens(interp, script, &tokenlist);
15669
15670
15671 ScriptTokenListFree(&tokenlist);
15672
15673 #ifdef DEBUG_SHOW_SUBST
15674 {
15675 int i;
@@ -15817,11 +15680,11 @@
15680 Jim_String(script->token[i].objPtr));
15681 }
15682 }
15683 #endif
15684
15685
15686 Jim_FreeIntRep(interp, objPtr);
15687 Jim_SetIntRepPtr(objPtr, script);
15688 objPtr->typePtr = &scriptObjType;
15689 return JIM_OK;
15690 }
@@ -15835,11 +15698,11 @@
15698
15699 int Jim_SubstObj(Jim_Interp *interp, Jim_Obj *substObjPtr, Jim_Obj **resObjPtrPtr, int flags)
15700 {
15701 ScriptObj *script = Jim_GetSubst(interp, substObjPtr, flags);
15702
15703 Jim_IncrRefCount(substObjPtr);
15704 script->inUse++;
15705
15706 *resObjPtrPtr = JimInterpolateTokens(interp, script->token, script->len, flags);
15707
15708 script->inUse--;
@@ -15851,22 +15714,24 @@
15714 }
15715
15716 void Jim_WrongNumArgs(Jim_Interp *interp, int argc, Jim_Obj *const *argv, const char *msg)
15717 {
15718 Jim_Obj *objPtr;
15719 Jim_Obj *listObjPtr;
15720
15721 JimPanic((argc == 0, "Jim_WrongNumArgs() called with argc=0"));
15722
15723 listObjPtr = Jim_NewListObj(interp, argv, argc);
15724
15725 if (msg && *msg) {
15726 Jim_ListAppendElement(interp, listObjPtr, Jim_NewStringObj(interp, msg, -1));
15727 }
15728 Jim_IncrRefCount(listObjPtr);
15729 objPtr = Jim_ListJoin(interp, listObjPtr, " ", 1);
15730 Jim_DecrRefCount(interp, listObjPtr);
15731
 
15732 Jim_SetResultFormatted(interp, "wrong # args: should be \"%#s\"", objPtr);
 
15733 }
15734
15735 typedef void JimHashtableIteratorCallbackType(Jim_Interp *interp, Jim_Obj *listObjPtr,
15736 Jim_HashEntry *he, int type);
15737
@@ -15876,11 +15741,11 @@
15741 JimHashtableIteratorCallbackType *callback, int type)
15742 {
15743 Jim_HashEntry *he;
15744 Jim_Obj *listObjPtr = Jim_NewListObj(interp, NULL, 0);
15745
15746
15747 if (patternObjPtr && JimTrivialMatch(Jim_String(patternObjPtr))) {
15748 he = Jim_FindHashEntry(ht, Jim_String(patternObjPtr));
15749 if (he) {
15750 callback(interp, listObjPtr, he, type);
15751 }
@@ -15907,11 +15772,11 @@
15772 {
15773 Jim_Cmd *cmdPtr = Jim_GetHashEntryVal(he);
15774 Jim_Obj *objPtr;
15775
15776 if (type == JIM_CMDLIST_PROCS && !cmdPtr->isproc) {
15777
15778 return;
15779 }
15780
15781 objPtr = Jim_NewStringObj(interp, he->key, -1);
15782 Jim_IncrRefCount(objPtr);
@@ -15967,11 +15832,11 @@
15832
15833 targetCallFrame = JimGetCallFrameByInteger(interp, levelObjPtr);
15834 if (targetCallFrame == NULL) {
15835 return JIM_ERR;
15836 }
15837
15838 if (targetCallFrame == interp->topFramePtr) {
15839 Jim_SetResultFormatted(interp, "bad level \"%#s\"", levelObjPtr);
15840 return JIM_ERR;
15841 }
15842 if (info_level_cmd) {
@@ -16095,12 +15960,17 @@
15960 doubleRes = (double)res;
15961 goto trydouble;
15962 }
15963 if (op == JIM_EXPROP_SUB)
15964 res -= wideValue;
15965 else {
15966 if (wideValue == 0) {
15967 Jim_SetResultString(interp, "Division by zero", -1);
15968 return JIM_ERR;
15969 }
15970 res /= wideValue;
15971 }
15972 }
15973 Jim_SetResultInt(interp, res);
15974 return JIM_OK;
15975 trydouble:
15976 for (; i < argc; i++) {
@@ -16154,11 +16024,11 @@
16024 if (!objPtr)
16025 return JIM_ERR;
16026 Jim_SetResult(interp, objPtr);
16027 return JIM_OK;
16028 }
16029
16030 if (Jim_SetVariable(interp, argv[1], argv[2]) != JIM_OK)
16031 return JIM_ERR;
16032 Jim_SetResult(interp, argv[2]);
16033 return JIM_OK;
16034 }
@@ -16197,11 +16067,11 @@
16067 if (argc != 3) {
16068 Jim_WrongNumArgs(interp, 1, argv, "condition body");
16069 return JIM_ERR;
16070 }
16071
16072
16073 while (1) {
16074 int boolean, retval;
16075
16076 if ((retval = Jim_GetBoolFromExpr(interp, argv[1], &boolean)) != JIM_OK)
16077 return retval;
@@ -16237,11 +16107,11 @@
16107 if (argc != 5) {
16108 Jim_WrongNumArgs(interp, 1, argv, "start test next body");
16109 return JIM_ERR;
16110 }
16111
16112
16113 if ((retval = Jim_EvalObj(interp, argv[1])) != JIM_OK) {
16114 return retval;
16115 }
16116
16117 retval = Jim_GetBoolFromExpr(interp, argv[2], &boolean);
@@ -16248,78 +16118,84 @@
16118
16119
16120 #ifdef JIM_OPTIMIZATION
16121 if (retval == JIM_OK && boolean) {
16122 ScriptObj *incrScript;
16123 struct ExprTree *expr;
16124 jim_wide stop, currentVal;
16125 Jim_Obj *objPtr;
16126 int cmpOffset;
16127
16128
16129 expr = JimGetExpression(interp, argv[2]);
16130 incrScript = JimGetScript(interp, argv[3]);
16131
16132
16133 if (incrScript == NULL || incrScript->len != 3 || !expr || expr->len != 3) {
16134 goto evalstart;
16135 }
16136
16137 if (incrScript->token[1].type != JIM_TT_ESC) {
 
 
16138 goto evalstart;
16139 }
16140
16141 if (expr->expr->type == JIM_EXPROP_LT) {
16142 cmpOffset = 0;
16143 }
16144 else if (expr->expr->type == JIM_EXPROP_LTE) {
16145 cmpOffset = 1;
16146 }
16147 else {
16148 goto evalstart;
16149 }
16150
16151 if (expr->expr->left->type != JIM_TT_VAR) {
16152 goto evalstart;
16153 }
16154
16155 if (expr->expr->right->type != JIM_TT_VAR && expr->expr->right->type != JIM_TT_EXPR_INT) {
16156 goto evalstart;
16157 }
16158
16159
16160 if (!Jim_CompareStringImmediate(interp, incrScript->token[1].objPtr, "incr")) {
16161 goto evalstart;
16162 }
16163
16164
16165 if (!Jim_StringEqObj(incrScript->token[2].objPtr, expr->expr->left->objPtr)) {
16166 goto evalstart;
16167 }
16168
16169
16170 if (expr->expr->right->type == JIM_TT_EXPR_INT) {
16171 if (Jim_GetWide(interp, expr->expr->right->objPtr, &stop) == JIM_ERR) {
16172 goto evalstart;
16173 }
16174 }
16175 else {
16176 stopVarNamePtr = expr->expr->right->objPtr;
16177 Jim_IncrRefCount(stopVarNamePtr);
16178
16179 stop = 0;
16180 }
16181
16182
16183 varNamePtr = expr->expr->left->objPtr;
16184 Jim_IncrRefCount(varNamePtr);
16185
16186 objPtr = Jim_GetVariable(interp, varNamePtr, JIM_NONE);
16187 if (objPtr == NULL || Jim_GetWide(interp, objPtr, &currentVal) != JIM_OK) {
16188 goto testcond;
16189 }
16190
16191
16192 while (retval == JIM_OK) {
 
 
16193
16194
16195
16196
16197 if (stopVarNamePtr) {
16198 objPtr = Jim_GetVariable(interp, stopVarNamePtr, JIM_NONE);
16199 if (objPtr == NULL || Jim_GetWide(interp, objPtr, &stop) != JIM_OK) {
16200 goto testcond;
16201 }
@@ -16327,18 +16203,18 @@
16203
16204 if (currentVal >= stop + cmpOffset) {
16205 break;
16206 }
16207
16208
16209 retval = Jim_EvalObj(interp, argv[4]);
16210 if (retval == JIM_OK || retval == JIM_CONTINUE) {
16211 retval = JIM_OK;
16212
16213 objPtr = Jim_GetVariable(interp, varNamePtr, JIM_ERRMSG);
16214
16215
16216 if (objPtr == NULL) {
16217 retval = JIM_ERR;
16218 goto out;
16219 }
16220 if (!Jim_IsShared(objPtr) && objPtr->typePtr == &intObjType) {
@@ -16358,25 +16234,25 @@
16234 }
16235 evalstart:
16236 #endif
16237
16238 while (boolean && (retval == JIM_OK || retval == JIM_CONTINUE)) {
16239
16240 retval = Jim_EvalObj(interp, argv[4]);
16241
16242 if (retval == JIM_OK || retval == JIM_CONTINUE) {
16243
16244 JIM_IF_OPTIM(evalnext:)
16245 retval = Jim_EvalObj(interp, argv[3]);
16246 if (retval == JIM_OK || retval == JIM_CONTINUE) {
16247
16248 JIM_IF_OPTIM(testcond:)
16249 retval = Jim_GetBoolFromExpr(interp, argv[2], &boolean);
16250 }
16251 }
16252 }
16253 JIM_IF_OPTIM(out:)
16254 if (stopVarNamePtr) {
16255 Jim_DecrRefCount(interp, stopVarNamePtr);
16256 }
16257 if (varNamePtr) {
16258 Jim_DecrRefCount(interp, varNamePtr);
@@ -16418,11 +16294,11 @@
16294 if (retval == JIM_OK || retval == JIM_CONTINUE) {
16295 Jim_Obj *objPtr = Jim_GetVariable(interp, argv[1], JIM_ERRMSG);
16296
16297 retval = JIM_OK;
16298
16299
16300 i += incr;
16301
16302 if (objPtr && !Jim_IsShared(objPtr) && objPtr->typePtr == &intObjType) {
16303 if (argv[1]->typePtr != &variableObjType) {
16304 if (Jim_SetVariable(interp, argv[1], objPtr) != JIM_OK) {
@@ -16483,21 +16359,21 @@
16359
16360 static int JimForeachMapHelper(Jim_Interp *interp, int argc, Jim_Obj *const *argv, int doMap)
16361 {
16362 int result = JIM_OK;
16363 int i, numargs;
16364 Jim_ListIter twoiters[2];
16365 Jim_ListIter *iters;
16366 Jim_Obj *script;
16367 Jim_Obj *resultObj;
16368
16369 if (argc < 4 || argc % 2 != 0) {
16370 Jim_WrongNumArgs(interp, 1, argv, "varList list ?varList list ...? script");
16371 return JIM_ERR;
16372 }
16373 script = argv[argc - 1];
16374 numargs = (argc - 1 - 1);
16375
16376 if (numargs == 2) {
16377 iters = twoiters;
16378 }
16379 else {
@@ -16509,11 +16385,11 @@
16385 result = JIM_ERR;
16386 }
16387 }
16388 if (result != JIM_OK) {
16389 Jim_SetResultString(interp, "foreach varlist is empty", -1);
16390 goto empty_varlist;
16391 }
16392
16393 if (doMap) {
16394 resultObj = Jim_NewListObj(interp, NULL, 0);
16395 }
@@ -16521,34 +16397,34 @@
16397 resultObj = interp->emptyObj;
16398 }
16399 Jim_IncrRefCount(resultObj);
16400
16401 while (1) {
16402
16403 for (i = 0; i < numargs; i += 2) {
16404 if (!JimListIterDone(interp, &iters[i + 1])) {
16405 break;
16406 }
16407 }
16408 if (i == numargs) {
16409
16410 break;
16411 }
16412
16413
16414 for (i = 0; i < numargs; i += 2) {
16415 Jim_Obj *varName;
16416
16417
16418 JimListIterInit(&iters[i], argv[i + 1]);
16419 while ((varName = JimListIterNext(interp, &iters[i])) != NULL) {
16420 Jim_Obj *valObj = JimListIterNext(interp, &iters[i + 1]);
16421 if (!valObj) {
16422
16423 valObj = interp->emptyObj;
16424 }
16425
16426 Jim_IncrRefCount(valObj);
16427 result = Jim_SetVariable(interp, varName, valObj);
16428 Jim_DecrRefCount(interp, valObj);
16429 if (result != JIM_OK) {
16430 goto err;
@@ -16572,10 +16448,11 @@
16448 out:
16449 result = JIM_OK;
16450 Jim_SetResult(interp, resultObj);
16451 err:
16452 Jim_DecrRefCount(interp, resultObj);
16453 empty_varlist:
16454 if (numargs > 2) {
16455 Jim_Free(iters);
16456 }
16457 return result;
16458 }
@@ -16630,41 +16507,41 @@
16507 {
16508 int boolean, retval, current = 1, falsebody = 0;
16509
16510 if (argc >= 3) {
16511 while (1) {
16512
16513 if (current >= argc)
16514 goto err;
16515 if ((retval = Jim_GetBoolFromExpr(interp, argv[current++], &boolean))
16516 != JIM_OK)
16517 return retval;
16518
16519 if (current >= argc)
16520 goto err;
16521 if (Jim_CompareStringImmediate(interp, argv[current], "then"))
16522 current++;
16523
16524 if (current >= argc)
16525 goto err;
16526 if (boolean)
16527 return Jim_EvalObj(interp, argv[current]);
16528
16529 if (++current >= argc) {
16530 Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
16531 return JIM_OK;
16532 }
16533 falsebody = current++;
16534 if (Jim_CompareStringImmediate(interp, argv[falsebody], "else")) {
16535
16536 if (current != argc - 1)
16537 goto err;
16538 return Jim_EvalObj(interp, argv[current]);
16539 }
16540 else if (Jim_CompareStringImmediate(interp, argv[falsebody], "elseif"))
16541 continue;
16542
16543 else if (falsebody != argc - 1)
16544 goto err;
16545 return Jim_EvalObj(interp, argv[falsebody]);
16546 }
16547 return JIM_OK;
@@ -16698,19 +16575,17 @@
16575 }
16576
16577 return eq;
16578 }
16579
 
 
 
16580
16581 static int Jim_SwitchCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
16582 {
16583 enum { SWITCH_EXACT, SWITCH_GLOB, SWITCH_RE, SWITCH_CMD };
16584 int matchOpt = SWITCH_EXACT, opt = 1, patCount, i;
16585 Jim_Obj *command = NULL, *scriptObj = NULL, *strObj;
16586 Jim_Obj **caseList;
16587
16588 if (argc < 3) {
16589 wrongnumargs:
16590 Jim_WrongNumArgs(interp, 1, argv, "?options? string "
16591 "pattern body ... ?default body? or " "{pattern body ?pattern body ...?}");
@@ -16747,68 +16622,62 @@
16622 goto wrongnumargs;
16623 }
16624 strObj = argv[opt++];
16625 patCount = argc - opt;
16626 if (patCount == 1) {
16627 JimListGetElements(interp, argv[opt], &patCount, &caseList);
 
 
 
16628 }
16629 else
16630 caseList = (Jim_Obj **)&argv[opt];
16631 if (patCount == 0 || patCount % 2 != 0)
16632 goto wrongnumargs;
16633 for (i = 0; scriptObj == NULL && i < patCount; i += 2) {
16634 Jim_Obj *patObj = caseList[i];
16635
16636 if (!Jim_CompareStringImmediate(interp, patObj, "default")
16637 || i < (patCount - 2)) {
16638 switch (matchOpt) {
16639 case SWITCH_EXACT:
16640 if (Jim_StringEqObj(strObj, patObj))
16641 scriptObj = caseList[i + 1];
16642 break;
16643 case SWITCH_GLOB:
16644 if (Jim_StringMatchObj(interp, patObj, strObj, 0))
16645 scriptObj = caseList[i + 1];
16646 break;
16647 case SWITCH_RE:
16648 command = Jim_NewStringObj(interp, "regexp", -1);
16649
16650 case SWITCH_CMD:{
16651 int rc = Jim_CommandMatchObj(interp, command, patObj, strObj, 0);
16652
16653 if (argc - opt == 1) {
16654 JimListGetElements(interp, argv[opt], &patCount, &caseList);
 
 
 
16655 }
16656
16657 if (rc < 0) {
16658 return -rc;
16659 }
16660 if (rc)
16661 scriptObj = caseList[i + 1];
16662 break;
16663 }
16664 }
16665 }
16666 else {
16667 scriptObj = caseList[i + 1];
16668 }
16669 }
16670 for (; i < patCount && Jim_CompareStringImmediate(interp, scriptObj, "-"); i += 2)
16671 scriptObj = caseList[i + 1];
16672 if (scriptObj && Jim_CompareStringImmediate(interp, scriptObj, "-")) {
16673 Jim_SetResultFormatted(interp, "no body specified for pattern \"%#s\"", caseList[i - 2]);
16674 return JIM_ERR;
16675 }
16676 Jim_SetEmptyResult(interp);
16677 if (scriptObj) {
16678 return Jim_EvalObj(interp, scriptObj);
16679 }
16680 return JIM_OK;
16681 }
16682
16683
@@ -16920,11 +16789,11 @@
16789 case OPT_COMMAND:
16790 if (i >= argc - 2) {
16791 goto wrongargs;
16792 }
16793 commandObj = argv[++i];
16794
16795 case OPT_EXACT:
16796 case OPT_GLOB:
16797 case OPT_REGEXP:
16798 opt_match = option;
16799 break;
@@ -16968,17 +16837,17 @@
16837 goto done;
16838 }
16839 break;
16840 }
16841
16842
16843 if (!eq && opt_bool && opt_not && !opt_all) {
16844 continue;
16845 }
16846
16847 if ((!opt_bool && eq == !opt_not) || (opt_bool && (eq || opt_all))) {
16848
16849 Jim_Obj *resultObj;
16850
16851 if (opt_bool) {
16852 resultObj = Jim_NewIntObj(interp, eq ^ opt_not);
16853 }
@@ -17001,11 +16870,11 @@
16870
16871 if (opt_all) {
16872 Jim_SetResult(interp, listObjPtr);
16873 }
16874 else {
16875
16876 if (opt_bool) {
16877 Jim_SetResultBool(interp, opt_not);
16878 }
16879 else if (!opt_inline) {
16880 Jim_SetResultInt(interp, -1);
@@ -17030,11 +16899,11 @@
16899 Jim_WrongNumArgs(interp, 1, argv, "varName ?value value ...?");
16900 return JIM_ERR;
16901 }
16902 listObjPtr = Jim_GetVariable(interp, argv[1], JIM_UNSHARED);
16903 if (!listObjPtr) {
16904
16905 listObjPtr = Jim_NewListObj(interp, NULL, 0);
16906 new_obj = 1;
16907 }
16908 else if (Jim_IsShared(listObjPtr)) {
16909 listObjPtr = Jim_DuplicateObj(interp, listObjPtr);
@@ -17103,31 +16972,21 @@
16972 first = JimRelToAbsIndex(len, first);
16973 last = JimRelToAbsIndex(len, last);
16974 JimRelToAbsRange(len, &first, &last, &rangeLen);
16975
16976
16977 if (first > len) {
16978 first = len;
16979 }
16980
16981
 
 
 
 
 
 
 
 
 
 
16982 newListObj = Jim_NewListObj(interp, listObj->internalRep.listValue.ele, first);
16983
16984
16985 ListInsertElements(newListObj, -1, argc - 4, argv + 4);
16986
16987
16988 ListInsertElements(newListObj, -1, len - first - rangeLen, listObj->internalRep.listValue.ele + first + rangeLen);
16989
16990 Jim_SetResult(interp, newListObj);
16991 return JIM_OK;
16992 }
@@ -17138,11 +16997,11 @@
16997 if (argc < 3) {
16998 Jim_WrongNumArgs(interp, 1, argv, "listVar ?index...? newVal");
16999 return JIM_ERR;
17000 }
17001 else if (argc == 3) {
17002
17003 if (Jim_SetVariable(interp, argv[1], argv[2]) != JIM_OK)
17004 return JIM_ERR;
17005 Jim_SetResult(interp, argv[2]);
17006 return JIM_OK;
17007 }
@@ -17158,10 +17017,11 @@
17017 enum
17018 { OPT_ASCII, OPT_NOCASE, OPT_INCREASING, OPT_DECREASING, OPT_COMMAND, OPT_INTEGER, OPT_REAL, OPT_INDEX, OPT_UNIQUE };
17019 Jim_Obj *resObj;
17020 int i;
17021 int retCode;
17022 int shared;
17023
17024 struct lsort_info info;
17025
17026 if (argc < 2) {
17027 Jim_WrongNumArgs(interp, 1, argv, "?options? list");
@@ -17223,16 +17083,18 @@
17083 info.indexed = 1;
17084 i++;
17085 break;
17086 }
17087 }
17088 resObj = argv[argc - 1];
17089 if ((shared = Jim_IsShared(resObj)))
17090 resObj = Jim_DuplicateObj(interp, resObj);
17091 retCode = ListSortElements(interp, resObj, &info);
17092 if (retCode == JIM_OK) {
17093 Jim_SetResult(interp, resObj);
17094 }
17095 else if (shared) {
17096 Jim_FreeNewObj(interp, resObj);
17097 }
17098 return retCode;
17099 }
17100
@@ -17253,11 +17115,11 @@
17115 }
17116 else {
17117 int new_obj = 0;
17118 stringObjPtr = Jim_GetVariable(interp, argv[1], JIM_UNSHARED);
17119 if (!stringObjPtr) {
17120
17121 stringObjPtr = Jim_NewEmptyStringObj(interp);
17122 new_obj = 1;
17123 }
17124 else if (Jim_IsShared(stringObjPtr)) {
17125 new_obj = 1;
@@ -17274,10 +17136,11 @@
17136 }
17137 }
17138 Jim_SetResult(interp, stringObjPtr);
17139 return JIM_OK;
17140 }
17141
17142
17143
17144 static int Jim_DebugCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
17145 {
17146 #if !defined(JIM_DEBUG_COMMAND)
@@ -17302,11 +17165,11 @@
17165 else {
17166 rc = Jim_EvalObj(interp, Jim_ConcatObj(interp, argc - 1, argv + 1));
17167 }
17168
17169 if (rc == JIM_ERR) {
17170
17171 interp->addStackTrace++;
17172 }
17173 return rc;
17174 }
17175
@@ -17316,14 +17179,14 @@
17179 if (argc >= 2) {
17180 int retcode;
17181 Jim_CallFrame *savedCallFrame, *targetCallFrame;
17182 const char *str;
17183
17184
17185 savedCallFrame = interp->framePtr;
17186
17187
17188 str = Jim_String(argv[1]);
17189 if ((str[0] >= '0' && str[0] <= '9') || str[0] == '#') {
17190 targetCallFrame = Jim_GetCallFrameByLevel(interp, argv[1]);
17191 argc--;
17192 argv++;
@@ -17336,11 +17199,11 @@
17199 }
17200 if (argc < 2) {
17201 Jim_WrongNumArgs(interp, 1, argv - 1, "?level? command ?arg ...?");
17202 return JIM_ERR;
17203 }
17204
17205 interp->framePtr = targetCallFrame;
17206 if (argc == 2) {
17207 retcode = Jim_EvalObj(interp, argv[1]);
17208 }
17209 else {
@@ -17356,32 +17219,29 @@
17219 }
17220
17221
17222 static int Jim_ExprCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
17223 {
 
17224 int retcode;
17225
17226 if (argc == 2) {
17227 retcode = Jim_EvalExpression(interp, argv[1]);
17228 }
17229 else if (argc > 2) {
17230 Jim_Obj *objPtr;
17231
17232 objPtr = Jim_ConcatObj(interp, argc - 1, argv + 1);
17233 Jim_IncrRefCount(objPtr);
17234 retcode = Jim_EvalExpression(interp, objPtr);
17235 Jim_DecrRefCount(interp, objPtr);
17236 }
17237 else {
17238 Jim_WrongNumArgs(interp, 1, argv, "expression ?...?");
17239 return JIM_ERR;
17240 }
17241 if (retcode != JIM_OK)
17242 return retcode;
 
 
17243 return JIM_OK;
17244 }
17245
17246
17247 static int Jim_BreakCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
@@ -17438,15 +17298,15 @@
17298 if (i != argc - 1 && i != argc) {
17299 Jim_WrongNumArgs(interp, 1, argv,
17300 "?-code code? ?-errorinfo stacktrace? ?-level level? ?result?");
17301 }
17302
17303
17304 if (stackTraceObj && returnCode == JIM_ERR) {
17305 JimSetStackTrace(interp, stackTraceObj);
17306 }
17307
17308 if (errorCodeObj && returnCode == JIM_ERR) {
17309 Jim_SetGlobalVariableStr(interp, "errorCode", errorCodeObj);
17310 }
17311 interp->returnCode = returnCode;
17312 interp->returnLevel = level;
@@ -17463,31 +17323,31 @@
17323 if (interp->framePtr->level == 0) {
17324 Jim_SetResultString(interp, "tailcall can only be called from a proc or lambda", -1);
17325 return JIM_ERR;
17326 }
17327 else if (argc >= 2) {
17328
17329 Jim_CallFrame *cf = interp->framePtr->parent;
17330
17331 Jim_Cmd *cmdPtr = Jim_GetCommand(interp, argv[1], JIM_ERRMSG);
17332 if (cmdPtr == NULL) {
17333 return JIM_ERR;
17334 }
17335
17336 JimPanic((cf->tailcallCmd != NULL, "Already have a tailcallCmd"));
17337
17338
17339 JimIncrCmdRefCount(cmdPtr);
17340 cf->tailcallCmd = cmdPtr;
17341
17342
17343 JimPanic((cf->tailcallObj != NULL, "Already have a tailcallobj"));
17344
17345 cf->tailcallObj = Jim_NewListObj(interp, argv + 1, argc - 1);
17346 Jim_IncrRefCount(cf->tailcallObj);
17347
17348
17349 return JIM_EVAL;
17350 }
17351 return JIM_OK;
17352 }
17353
@@ -17494,11 +17354,11 @@
17354 static int JimAliasCmd(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
17355 {
17356 Jim_Obj *cmdList;
17357 Jim_Obj *prefixListObj = Jim_CmdPrivData(interp);
17358
17359
17360 cmdList = Jim_DuplicateObj(interp, prefixListObj);
17361 Jim_ListInsertElements(interp, cmdList, Jim_ListLength(interp, cmdList), argc - 1, argv + 1);
17362
17363 return JimEvalObjList(interp, cmdList);
17364 }
@@ -17552,22 +17412,22 @@
17412 else {
17413 cmd = JimCreateProcedureCmd(interp, argv[2], argv[3], argv[4], NULL);
17414 }
17415
17416 if (cmd) {
17417
17418 Jim_Obj *qualifiedCmdNameObj;
17419 const char *cmdname = JimQualifyName(interp, Jim_String(argv[1]), &qualifiedCmdNameObj);
17420
17421 JimCreateCommand(interp, cmdname, cmd);
17422
17423
17424 JimUpdateProcNamespace(interp, cmd, cmdname);
17425
17426 JimFreeQualifiedName(interp, qualifiedCmdNameObj);
17427
17428
17429 Jim_SetResult(interp, argv[1]);
17430 return JIM_OK;
17431 }
17432 return JIM_ERR;
17433 }
@@ -17580,17 +17440,17 @@
17440 if (argc < 2) {
17441 Jim_WrongNumArgs(interp, 1, argv, "cmd ?args ...?");
17442 return JIM_ERR;
17443 }
17444
17445
17446 interp->local++;
17447 retcode = Jim_EvalObjVector(interp, argc - 1, argv + 1);
17448 interp->local--;
17449
17450
17451
17452 if (retcode == 0) {
17453 Jim_Obj *cmdNameObj = Jim_GetResult(interp);
17454
17455 if (Jim_GetCommand(interp, cmdNameObj, JIM_ERRMSG) == NULL) {
17456 return JIM_ERR;
@@ -17619,18 +17479,18 @@
17479 Jim_Cmd *cmdPtr = Jim_GetCommand(interp, argv[1], JIM_ERRMSG);
17480 if (cmdPtr == NULL || !cmdPtr->isproc || !cmdPtr->prevCmd) {
17481 Jim_SetResultFormatted(interp, "no previous command: \"%#s\"", argv[1]);
17482 return JIM_ERR;
17483 }
17484
17485 cmdPtr->u.proc.upcall++;
17486 JimIncrCmdRefCount(cmdPtr);
17487
17488
17489 retcode = Jim_EvalObjVector(interp, argc - 1, argv + 1);
17490
17491
17492 cmdPtr->u.proc.upcall--;
17493 JimDecrCmdRefCount(interp, cmdPtr);
17494
17495 return retcode;
17496 }
@@ -17657,11 +17517,11 @@
17517 return JIM_ERR;
17518 }
17519
17520 if (len == 3) {
17521 #ifdef jim_ext_namespace
17522
17523 nsObj = JimQualifyNameObj(interp, Jim_ListGetIndex(interp, argv[1], 2));
17524 #else
17525 Jim_SetResultString(interp, "namespaces not enabled", -1);
17526 return JIM_ERR;
17527 #endif
@@ -17670,11 +17530,11 @@
17530 bodyObjPtr = Jim_ListGetIndex(interp, argv[1], 1);
17531
17532 cmd = JimCreateProcedureCmd(interp, argListObjPtr, NULL, bodyObjPtr, nsObj);
17533
17534 if (cmd) {
17535
17536 nargv = Jim_Alloc((argc - 2 + 1) * sizeof(*nargv));
17537 nargv[0] = Jim_NewStringObj(interp, "apply lambdaExpr", -1);
17538 Jim_IncrRefCount(nargv[0]);
17539 memcpy(&nargv[1], argv + 2, (argc - 2) * sizeof(*nargv));
17540 ret = JimCallProcedure(interp, cmd, argc - 2 + 1, nargv);
@@ -17700,11 +17560,11 @@
17560 static int Jim_UpvarCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
17561 {
17562 int i;
17563 Jim_CallFrame *targetCallFrame;
17564
17565
17566 if (argc > 3 && (argc % 2 == 0)) {
17567 targetCallFrame = Jim_GetCallFrameByLevel(interp, argv[1]);
17568 argc--;
17569 argv++;
17570 }
@@ -17713,17 +17573,17 @@
17573 }
17574 if (targetCallFrame == NULL) {
17575 return JIM_ERR;
17576 }
17577
17578
17579 if (argc < 3) {
17580 Jim_WrongNumArgs(interp, 1, argv, "?level? otherVar localVar ?otherVar localVar ...?");
17581 return JIM_ERR;
17582 }
17583
17584
17585 for (i = 1; i < argc; i += 2) {
17586 if (Jim_SetVariableLink(interp, argv[i + 1], argv[i], targetCallFrame) != JIM_OK)
17587 return JIM_ERR;
17588 }
17589 return JIM_OK;
@@ -17736,15 +17596,15 @@
17596
17597 if (argc < 2) {
17598 Jim_WrongNumArgs(interp, 1, argv, "varName ?varName ...?");
17599 return JIM_ERR;
17600 }
17601
17602 if (interp->framePtr->level == 0)
17603 return JIM_OK;
17604 for (i = 1; i < argc; i++) {
17605
17606 const char *name = Jim_String(argv[i]);
17607 if (name[0] != ':' || name[1] != ':') {
17608 if (Jim_SetVariableLink(interp, argv[i], argv[i], interp->topFramePtr) != JIM_OK)
17609 return JIM_ERR;
17610 }
@@ -17767,21 +17627,21 @@
17627 }
17628
17629 str = Jim_String(objPtr);
17630 strLen = Jim_Utf8Length(interp, objPtr);
17631
17632
17633 resultObjPtr = Jim_NewStringObj(interp, "", 0);
17634 while (strLen) {
17635 for (i = 0; i < numMaps; i += 2) {
17636 Jim_Obj *eachObjPtr;
17637 const char *k;
17638 int kl;
17639
17640 eachObjPtr = Jim_ListGetIndex(interp, mapListObjPtr, i);
17641 k = Jim_String(eachObjPtr);
17642 kl = Jim_Utf8Length(interp, eachObjPtr);
17643
17644 if (strLen >= kl && kl) {
17645 int rc;
17646 rc = JimStringCompareLen(str, k, kl, nocase);
17647 if (rc == 0) {
@@ -17794,11 +17654,11 @@
17654 strLen -= kl;
17655 break;
17656 }
17657 }
17658 }
17659 if (i == numMaps) {
17660 int c;
17661 if (noMatchStart == NULL)
17662 noMatchStart = str;
17663 str += utf8_tounicode(str, &c);
17664 strLen--;
@@ -17838,11 +17698,11 @@
17698 Jim_WrongNumArgs(interp, 1, argv, "option ?arguments ...?");
17699 return JIM_ERR;
17700 }
17701 if (Jim_GetEnum(interp, argv[1], options, &option, NULL,
17702 JIM_ERRMSG | JIM_ENUM_ABBREV) != JIM_OK)
17703 return Jim_CheckShowCommands(interp, argv[1], options);
17704
17705 switch (option) {
17706 case OPT_LENGTH:
17707 case OPT_BYTELENGTH:
17708 if (argc != 3) {
@@ -17859,11 +17719,11 @@
17719 return JIM_OK;
17720
17721 case OPT_CAT:{
17722 Jim_Obj *objPtr;
17723 if (argc == 3) {
17724
17725 objPtr = argv[2];
17726 }
17727 else {
17728 int i;
17729
@@ -17878,11 +17738,11 @@
17738 }
17739
17740 case OPT_COMPARE:
17741 case OPT_EQUAL:
17742 {
17743
17744 long opt_length = -1;
17745 int n = argc - 4;
17746 int i = 2;
17747 while (n > 0) {
17748 int subopt;
@@ -17891,16 +17751,16 @@
17751 badcompareargs:
17752 Jim_WrongNumArgs(interp, 2, argv, "?-nocase? ?-length int? string1 string2");
17753 return JIM_ERR;
17754 }
17755 if (subopt == 0) {
17756
17757 opt_case = 0;
17758 n--;
17759 }
17760 else {
17761
17762 if (n < 2) {
17763 goto badcompareargs;
17764 }
17765 if (Jim_GetLong(interp, argv[i++], &opt_length) != JIM_OK) {
17766 return JIM_ERR;
@@ -17911,11 +17771,11 @@
17771 if (n) {
17772 goto badcompareargs;
17773 }
17774 argv += argc - 2;
17775 if (opt_length < 0 && option != OPT_COMPARE && opt_case) {
17776
17777 Jim_SetResultBool(interp, Jim_StringEqObj(argv[0], argv[1]));
17778 }
17779 else {
17780 if (opt_length >= 0) {
17781 n = JimStringCompareLen(Jim_String(argv[0]), Jim_String(argv[1]), opt_length, !opt_case);
@@ -18025,11 +17885,10 @@
17885 }
17886
17887 case OPT_REVERSE:{
17888 char *buf, *p;
17889 const char *str;
 
17890 int i;
17891
17892 if (argc != 3) {
17893 Jim_WrongNumArgs(interp, 2, argv, "string");
17894 return JIM_ERR;
@@ -18069,11 +17928,11 @@
17928 }
17929 if (idx < 0 || idx >= len || str == NULL) {
17930 Jim_SetResultString(interp, "", 0);
17931 }
17932 else if (len == Jim_Length(argv[2])) {
17933
17934 Jim_SetResultString(interp, str + idx, 1);
17935 }
17936 else {
17937 int c;
17938 int i = utf8_index(str, idx);
@@ -18223,11 +18082,11 @@
18082 {
18083 int exitCode = 0;
18084 int i;
18085 int sig = 0;
18086
18087
18088 jim_wide ignore_mask = (1 << JIM_EXIT) | (1 << JIM_EVAL) | (1 << JIM_SIGNAL);
18089 static const int max_ignore_code = sizeof(ignore_mask) * 8;
18090
18091 Jim_SetGlobalVariableStr(interp, "errorCode", Jim_NewStringObj(interp, "NONE", -1));
18092
@@ -18234,11 +18093,11 @@
18093 for (i = 1; i < argc - 1; i++) {
18094 const char *arg = Jim_String(argv[i]);
18095 jim_wide option;
18096 int ignore;
18097
18098
18099 if (strcmp(arg, "--") == 0) {
18100 i++;
18101 break;
18102 }
18103 if (*arg != '-') {
@@ -18285,28 +18144,28 @@
18144 sig++;
18145 }
18146
18147 interp->signal_level += sig;
18148 if (Jim_CheckSignal(interp)) {
18149
18150 exitCode = JIM_SIGNAL;
18151 }
18152 else {
18153 exitCode = Jim_EvalObj(interp, argv[0]);
18154
18155 interp->errorFlag = 0;
18156 }
18157 interp->signal_level -= sig;
18158
18159
18160 if (exitCode >= 0 && exitCode < max_ignore_code && (((unsigned jim_wide)1 << exitCode) & ignore_mask)) {
18161
18162 return exitCode;
18163 }
18164
18165 if (sig && exitCode == JIM_SIGNAL) {
18166
18167 if (interp->signal_set_result) {
18168 interp->signal_set_result(interp, interp->sigmask);
18169 }
18170 else {
18171 Jim_SetResultInt(interp, interp->sigmask);
@@ -18345,125 +18204,10 @@
18204 }
18205 Jim_SetResultInt(interp, exitCode);
18206 return JIM_OK;
18207 }
18208
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
18209
18210
18211 static int Jim_RenameCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
18212 {
18213 if (argc != 3) {
@@ -18476,56 +18220,43 @@
18220 }
18221
18222 return Jim_RenameCommand(interp, Jim_String(argv[1]), Jim_String(argv[2]));
18223 }
18224
18225 #define JIM_DICTMATCH_KEYS 0x0001
18226 #define JIM_DICTMATCH_VALUES 0x002
18227
18228 int Jim_DictMatchTypes(Jim_Interp *interp, Jim_Obj *objPtr, Jim_Obj *patternObj, int match_type, int return_types)
18229 {
18230 Jim_HashEntry *he;
18231 Jim_Obj *listObjPtr;
18232 Jim_HashTableIterator htiter;
18233
18234 if (SetDictFromAny(interp, objPtr) != JIM_OK) {
18235 return JIM_ERR;
18236 }
18237
18238 listObjPtr = Jim_NewListObj(interp, NULL, 0);
18239
18240 JimInitHashTableIterator(objPtr->internalRep.ptr, &htiter);
18241 while ((he = Jim_NextHashEntry(&htiter)) != NULL) {
18242 if (patternObj) {
18243 Jim_Obj *matchObj = (match_type == JIM_DICTMATCH_KEYS) ? (Jim_Obj *)he->key : Jim_GetHashEntryVal(he);
18244 if (!JimGlobMatch(Jim_String(patternObj), Jim_String(matchObj), 0)) {
18245
18246 continue;
18247 }
18248 }
18249 if (return_types & JIM_DICTMATCH_KEYS) {
18250 Jim_ListAppendElement(interp, listObjPtr, (Jim_Obj *)he->key);
18251 }
18252 if (return_types & JIM_DICTMATCH_VALUES) {
18253 Jim_ListAppendElement(interp, listObjPtr, Jim_GetHashEntryVal(he));
18254 }
18255 }
18256
18257 Jim_SetResult(interp, listObjPtr);
 
 
 
 
 
 
 
 
 
 
 
 
 
18258 return JIM_OK;
18259 }
18260
18261 int Jim_DictSize(Jim_Interp *interp, Jim_Obj *objPtr)
18262 {
@@ -18532,38 +18263,85 @@
18263 if (SetDictFromAny(interp, objPtr) != JIM_OK) {
18264 return -1;
18265 }
18266 return ((Jim_HashTable *)objPtr->internalRep.ptr)->used;
18267 }
18268
18269 Jim_Obj *Jim_DictMerge(Jim_Interp *interp, int objc, Jim_Obj *const *objv)
18270 {
18271 Jim_Obj *objPtr = Jim_NewDictObj(interp, NULL, 0);
18272 int i;
18273
18274 JimPanic((objc == 0, "Jim_DictMerge called with objc=0"));
18275
18276
18277
18278 for (i = 0; i < objc; i++) {
18279 Jim_HashTable *ht;
18280 Jim_HashTableIterator htiter;
18281 Jim_HashEntry *he;
18282
18283 if (SetDictFromAny(interp, objv[i]) != JIM_OK) {
18284 Jim_FreeNewObj(interp, objPtr);
18285 return NULL;
18286 }
18287 ht = objv[i]->internalRep.ptr;
18288 JimInitHashTableIterator(ht, &htiter);
18289 while ((he = Jim_NextHashEntry(&htiter)) != NULL) {
18290 Jim_ReplaceHashEntry(objPtr->internalRep.ptr, Jim_GetHashEntryKey(he), Jim_GetHashEntryVal(he));
18291 }
18292 }
18293 return objPtr;
18294 }
18295
18296 int Jim_DictInfo(Jim_Interp *interp, Jim_Obj *objPtr)
18297 {
18298 Jim_HashTable *ht;
18299 unsigned int i;
18300 char buffer[100];
18301 int sum = 0;
18302 int nonzero_count = 0;
18303 Jim_Obj *output;
18304 int bucket_counts[11] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
18305
18306 if (SetDictFromAny(interp, objPtr) != JIM_OK) {
18307 return JIM_ERR;
18308 }
18309
18310 ht = (Jim_HashTable *)objPtr->internalRep.ptr;
18311
18312
18313 snprintf(buffer, sizeof(buffer), "%d entries in table, %d buckets\n", ht->used, ht->size);
18314 output = Jim_NewStringObj(interp, buffer, -1);
18315
18316 for (i = 0; i < ht->size; i++) {
18317 Jim_HashEntry *he = ht->table[i];
18318 int entries = 0;
18319 while (he) {
18320 entries++;
18321 he = he->next;
18322 }
18323 if (entries > 9) {
18324 bucket_counts[10]++;
18325 }
18326 else {
18327 bucket_counts[entries]++;
18328 }
18329 if (entries) {
18330 sum += entries;
18331 nonzero_count++;
18332 }
18333 }
18334 for (i = 0; i < 10; i++) {
18335 snprintf(buffer, sizeof(buffer), "number of buckets with %d entries: %d\n", i, bucket_counts[i]);
18336 Jim_AppendString(interp, output, buffer, -1);
18337 }
18338 snprintf(buffer, sizeof(buffer), "number of buckets with 10 or more entries: %d\n", bucket_counts[10]);
18339 Jim_AppendString(interp, output, buffer, -1);
18340 snprintf(buffer, sizeof(buffer), "average search distance for entry: %.1f", nonzero_count ? (double)sum / nonzero_count : 0.0);
18341 Jim_AppendString(interp, output, buffer, -1);
18342 Jim_SetResult(interp, output);
18343 return JIM_OK;
18344 }
18345
18346 static int Jim_EvalEnsemble(Jim_Interp *interp, const char *basecmd, const char *subcmd, int argc, Jim_Obj *const *argv)
18347 {
@@ -18573,14 +18351,67 @@
18351 Jim_AppendString(interp, prefixObj, subcmd, -1);
18352
18353 return Jim_EvalObjPrefix(interp, prefixObj, argc, argv);
18354 }
18355
18356 static int JimDictWith(Jim_Interp *interp, Jim_Obj *dictVarName, Jim_Obj *const *keyv, int keyc, Jim_Obj *scriptObj)
18357 {
18358 int i;
18359 Jim_Obj *objPtr;
18360 Jim_Obj *dictObj;
18361 Jim_Obj **dictValues;
18362 int len;
18363 int ret = JIM_OK;
18364
18365
18366 dictObj = Jim_GetVariable(interp, dictVarName, JIM_ERRMSG);
18367 if (dictObj == NULL || Jim_DictKeysVector(interp, dictObj, keyv, keyc, &objPtr, JIM_ERRMSG) != JIM_OK) {
18368 return JIM_ERR;
18369 }
18370
18371 if (Jim_DictPairs(interp, objPtr, &dictValues, &len) == JIM_ERR) {
18372 return JIM_ERR;
18373 }
18374 for (i = 0; i < len; i += 2) {
18375 if (Jim_SetVariable(interp, dictValues[i], dictValues[i + 1]) == JIM_ERR) {
18376 Jim_Free(dictValues);
18377 return JIM_ERR;
18378 }
18379 }
18380
18381
18382 if (Jim_Length(scriptObj)) {
18383 ret = Jim_EvalObj(interp, scriptObj);
18384
18385
18386 if (ret == JIM_OK && Jim_GetVariable(interp, dictVarName, 0) != NULL) {
18387
18388 Jim_Obj **newkeyv = Jim_Alloc(sizeof(*newkeyv) * (keyc + 1));
18389 for (i = 0; i < keyc; i++) {
18390 newkeyv[i] = keyv[i];
18391 }
18392
18393 for (i = 0; i < len; i += 2) {
18394
18395 objPtr = Jim_GetVariable(interp, dictValues[i], 0);
18396 newkeyv[keyc] = dictValues[i];
18397 Jim_SetDictKeysVector(interp, dictVarName, newkeyv, keyc + 1, objPtr, 0);
18398 }
18399 Jim_Free(newkeyv);
18400 }
18401 }
18402
18403 Jim_Free(dictValues);
18404
18405 return ret;
18406 }
18407
18408
18409 static int Jim_DictCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
18410 {
18411 Jim_Obj *objPtr;
18412 int types = JIM_DICTMATCH_KEYS;
18413 int option;
18414 static const char * const options[] = {
18415 "create", "get", "set", "unset", "exists", "keys", "size", "info",
18416 "merge", "with", "append", "lappend", "incr", "remove", "values", "for",
18417 "replace", "update", NULL
@@ -18596,11 +18427,11 @@
18427 Jim_WrongNumArgs(interp, 1, argv, "subcommand ?arguments ...?");
18428 return JIM_ERR;
18429 }
18430
18431 if (Jim_GetEnum(interp, argv[1], options, &option, "subcommand", JIM_ERRMSG) != JIM_OK) {
18432 return Jim_CheckShowCommands(interp, argv[1], options);
18433 }
18434
18435 switch (option) {
18436 case OPT_GET:
18437 if (argc < 3) {
@@ -18643,16 +18474,19 @@
18474 if (Jim_SetDictKeysVector(interp, argv[2], argv + 3, argc - 3, NULL, 0) != JIM_OK) {
18475 return JIM_ERR;
18476 }
18477 return JIM_OK;
18478
18479 case OPT_VALUES:
18480 types = JIM_DICTMATCH_VALUES;
18481
18482 case OPT_KEYS:
18483 if (argc != 3 && argc != 4) {
18484 Jim_WrongNumArgs(interp, 2, argv, "dictionary ?pattern?");
18485 return JIM_ERR;
18486 }
18487 return Jim_DictMatchTypes(interp, argv[2], argc == 4 ? argv[3] : NULL, types, types);
18488
18489 case OPT_SIZE:
18490 if (argc != 3) {
18491 Jim_WrongNumArgs(interp, 2, argv, "dictionary");
18492 return JIM_ERR;
@@ -18665,19 +18499,20 @@
18499
18500 case OPT_MERGE:
18501 if (argc == 2) {
18502 return JIM_OK;
18503 }
18504 objPtr = Jim_DictMerge(interp, argc - 2, argv + 2);
18505 if (objPtr == NULL) {
18506 return JIM_ERR;
18507 }
18508 Jim_SetResult(interp, objPtr);
18509 return JIM_OK;
18510
18511 case OPT_UPDATE:
18512 if (argc < 6 || argc % 2) {
18513
18514 argc = 2;
18515 }
18516 break;
18517
18518 case OPT_CREATE:
@@ -18693,12 +18528,19 @@
18528 if (argc != 3) {
18529 Jim_WrongNumArgs(interp, 2, argv, "dictionary");
18530 return JIM_ERR;
18531 }
18532 return Jim_DictInfo(interp, argv[2]);
18533
18534 case OPT_WITH:
18535 if (argc < 4) {
18536 Jim_WrongNumArgs(interp, 2, argv, "dictVar ?key ...? script");
18537 return JIM_ERR;
18538 }
18539 return JimDictWith(interp, argv[2], argv + 3, argc - 4, argv[argc - 1]);
18540 }
18541
18542 return Jim_EvalEnsemble(interp, "dict", options[option], argc - 2, argv + 2);
18543 }
18544
18545
18546 static int Jim_SubstCoreCommand(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
@@ -18764,11 +18606,11 @@
18606
18607 #ifdef jim_ext_namespace
18608 int nons = 0;
18609
18610 if (argc > 2 && Jim_CompareStringImmediate(interp, argv[1], "-nons")) {
18611
18612 argc--;
18613 argv++;
18614 nons = 1;
18615 }
18616 #endif
@@ -18775,16 +18617,15 @@
18617
18618 if (argc < 2) {
18619 Jim_WrongNumArgs(interp, 1, argv, "subcommand ?args ...?");
18620 return JIM_ERR;
18621 }
18622 if (Jim_GetEnum(interp, argv[1], commands, &cmd, "subcommand", JIM_ERRMSG | JIM_ENUM_ABBREV) != JIM_OK) {
18623 return Jim_CheckShowCommands(interp, argv[1], commands);
 
18624 }
18625
18626
18627 switch (cmd) {
18628 case INFO_EXISTS:
18629 if (argc != 3) {
18630 Jim_WrongNumArgs(interp, 2, argv, "varName");
18631 return JIM_ERR;
@@ -18809,21 +18650,21 @@
18650 Jim_SetResult(interp, (Jim_Obj *)cmdPtr->u.native.privData);
18651 return JIM_OK;
18652 }
18653
18654 case INFO_CHANNELS:
18655 mode++;
18656 #ifndef jim_ext_aio
18657 Jim_SetResultString(interp, "aio not enabled", -1);
18658 return JIM_ERR;
18659 #endif
18660
18661 case INFO_PROCS:
18662 mode++;
18663
18664 case INFO_COMMANDS:
18665
18666 if (argc != 2 && argc != 3) {
18667 Jim_WrongNumArgs(interp, 2, argv, "?pattern?");
18668 return JIM_ERR;
18669 }
18670 #ifdef jim_ext_namespace
@@ -18835,17 +18676,17 @@
18676 #endif
18677 Jim_SetResult(interp, JimCommandsList(interp, (argc == 3) ? argv[2] : NULL, mode));
18678 break;
18679
18680 case INFO_VARS:
18681 mode++;
18682
18683 case INFO_LOCALS:
18684 mode++;
18685
18686 case INFO_GLOBALS:
18687
18688 if (argc != 2 && argc != 3) {
18689 Jim_WrongNumArgs(interp, 2, argv, "?pattern?");
18690 return JIM_ERR;
18691 }
18692 #ifdef jim_ext_namespace
@@ -18951,13 +18792,12 @@
18792 case INFO_ARGS:
18793 Jim_SetResult(interp, cmdPtr->u.proc.argListObjPtr);
18794 break;
18795 case INFO_STATICS:
18796 if (cmdPtr->u.proc.staticVars) {
 
18797 Jim_SetResult(interp, JimHashtablePatternMatch(interp, cmdPtr->u.proc.staticVars,
18798 NULL, JimVariablesMatch, JIM_VARLIST_LOCALS | JIM_VARLIST_VALUES));
18799 }
18800 break;
18801 }
18802 break;
18803 }
@@ -18985,15 +18825,15 @@
18825 }
18826 }
18827 break;
18828
18829 case INFO_HOSTNAME:
18830
18831 return Jim_Eval(interp, "os.gethostname");
18832
18833 case INFO_NAMEOFEXECUTABLE:
18834
18835 return Jim_Eval(interp, "{info nameofexecutable}");
18836
18837 case INFO_RETURNCODES:
18838 if (argc == 2) {
18839 int i;
@@ -19070,11 +18910,11 @@
18910
18911 if (option == OPT_VAR) {
18912 result = Jim_GetVariable(interp, objPtr, 0) != NULL;
18913 }
18914 else {
18915
18916 Jim_Cmd *cmd = Jim_GetCommand(interp, objPtr, JIM_NONE);
18917
18918 if (cmd) {
18919 switch (option) {
18920 case OPT_COMMAND:
@@ -19113,11 +18953,11 @@
18953 if (len == 0) {
18954 return JIM_OK;
18955 }
18956 strLen = Jim_Utf8Length(interp, argv[1]);
18957
18958
18959 if (argc == 2) {
18960 splitChars = " \n\t\r";
18961 splitLen = 4;
18962 }
18963 else {
@@ -19126,11 +18966,11 @@
18966 }
18967
18968 noMatchStart = str;
18969 resObjPtr = Jim_NewListObj(interp, NULL, 0);
18970
18971
18972 if (splitLen) {
18973 Jim_Obj *objPtr;
18974 while (strLen--) {
18975 const char *sc = splitChars;
18976 int scLen = splitLen;
@@ -19155,11 +18995,11 @@
18995 #define NUM_COMMON (128 - 9)
18996 while (strLen--) {
18997 int n = utf8_tounicode(str, &c);
18998 #ifdef JIM_OPTIMIZATION
18999 if (c >= 9 && c < 128) {
19000
19001 c -= 9;
19002 if (!commonObj) {
19003 commonObj = Jim_Alloc(sizeof(*commonObj) * NUM_COMMON);
19004 memset(commonObj, 0, sizeof(*commonObj) * NUM_COMMON);
19005 }
@@ -19189,11 +19029,11 @@
19029
19030 if (argc != 2 && argc != 3) {
19031 Jim_WrongNumArgs(interp, 1, argv, "list ?joinString?");
19032 return JIM_ERR;
19033 }
19034
19035 if (argc == 2) {
19036 joinStr = " ";
19037 joinStrLen = 1;
19038 }
19039 else {
@@ -19468,13 +19308,13 @@
19308 return -1;
19309 else if (step < 0 && end > start)
19310 return -1;
19311 len = end - start;
19312 if (len < 0)
19313 len = -len;
19314 if (step < 0)
19315 step = -step;
19316 len = 1 + ((len - 1) / step);
19317 if (len > INT_MAX)
19318 len = INT_MAX;
19319 return (int)((len < 0) ? -1 : len);
19320 }
@@ -19644,57 +19484,102 @@
19484 argv[1] = interp->result;
19485
19486 Jim_EvalObjVector(interp, 2, argv);
19487 }
19488
19489 static char **JimSortStringTable(const char *const *tablePtr)
 
19490 {
19491 int count;
19492 char **tablePtrSorted;
19493
19494
19495 for (count = 0; tablePtr[count]; count++) {
19496 }
19497
19498
19499 tablePtrSorted = Jim_Alloc(sizeof(char *) * (count + 1));
19500 memcpy(tablePtrSorted, tablePtr, sizeof(char *) * count);
19501 qsort(tablePtrSorted, count, sizeof(char *), qsortCompareStringPointers);
19502 tablePtrSorted[count] = NULL;
19503
19504 return tablePtrSorted;
19505 }
19506
19507 static void JimSetFailedEnumResult(Jim_Interp *interp, const char *arg, const char *badtype,
19508 const char *prefix, const char *const *tablePtr, const char *name)
19509 {
19510 char **tablePtrSorted;
19511 int i;
19512
19513 if (name == NULL) {
19514 name = "option";
19515 }
19516
19517 Jim_SetResultFormatted(interp, "%s%s \"%s\": must be ", badtype, name, arg);
19518 tablePtrSorted = JimSortStringTable(tablePtr);
19519 for (i = 0; tablePtrSorted[i]; i++) {
19520 if (tablePtrSorted[i + 1] == NULL && i > 0) {
 
 
19521 Jim_AppendString(interp, Jim_GetResult(interp), "or ", -1);
19522 }
19523 Jim_AppendStrings(interp, Jim_GetResult(interp), prefix, tablePtrSorted[i], NULL);
19524 if (tablePtrSorted[i + 1]) {
19525 Jim_AppendString(interp, Jim_GetResult(interp), ", ", -1);
19526 }
19527 }
19528 Jim_Free(tablePtrSorted);
19529 }
19530
19531
19532 int Jim_CheckShowCommands(Jim_Interp *interp, Jim_Obj *objPtr, const char *const *tablePtr)
19533 {
19534 if (Jim_CompareStringImmediate(interp, objPtr, "-commands")) {
19535 int i;
19536 char **tablePtrSorted = JimSortStringTable(tablePtr);
19537 Jim_SetResult(interp, Jim_NewListObj(interp, NULL, 0));
19538 for (i = 0; tablePtrSorted[i]; i++) {
19539 Jim_ListAppendElement(interp, Jim_GetResult(interp), Jim_NewStringObj(interp, tablePtrSorted[i], -1));
19540 }
19541 Jim_Free(tablePtrSorted);
19542 return JIM_OK;
19543 }
19544 return JIM_ERR;
19545 }
19546
19547 static const Jim_ObjType getEnumObjType = {
19548 "get-enum",
19549 NULL,
19550 NULL,
19551 NULL,
19552 JIM_TYPE_REFERENCES
19553 };
19554
19555 int Jim_GetEnum(Jim_Interp *interp, Jim_Obj *objPtr,
19556 const char *const *tablePtr, int *indexPtr, const char *name, int flags)
19557 {
19558 const char *bad = "bad ";
19559 const char *const *entryPtr = NULL;
19560 int i;
19561 int match = -1;
19562 int arglen;
19563 const char *arg;
19564
19565 if (objPtr->typePtr == &getEnumObjType) {
19566 if (objPtr->internalRep.ptrIntValue.ptr == tablePtr && objPtr->internalRep.ptrIntValue.int1 == flags) {
19567 *indexPtr = objPtr->internalRep.ptrIntValue.int2;
19568 return JIM_OK;
19569 }
19570 }
19571
19572 arg = Jim_GetString(objPtr, &arglen);
19573
19574 *indexPtr = -1;
19575
19576 for (entryPtr = tablePtr, i = 0; *entryPtr != NULL; entryPtr++, i++) {
19577 if (Jim_CompareStringImmediate(interp, objPtr, *entryPtr)) {
19578
19579 match = i;
19580 goto found;
19581 }
19582 if (flags & JIM_ENUM_ABBREV) {
19583 if (strncmp(arg, *entryPtr, arglen) == 0) {
19584 if (*arg == '-' && arglen == 1) {
19585 break;
@@ -19706,12 +19591,20 @@
19591 match = i;
19592 }
19593 }
19594 }
19595
19596
19597 if (match >= 0) {
19598 found:
19599
19600 Jim_FreeIntRep(interp, objPtr);
19601 objPtr->typePtr = &getEnumObjType;
19602 objPtr->internalRep.ptrIntValue.ptr = (void *)tablePtr;
19603 objPtr->internalRep.ptrIntValue.int1 = flags;
19604 objPtr->internalRep.ptrIntValue.int2 = match;
19605
19606 *indexPtr = match;
19607 return JIM_OK;
19608 }
19609
19610 ambiguous:
@@ -19743,15 +19636,17 @@
19636 return objPtr->typePtr == &listObjType;
19637 }
19638
19639 void Jim_SetResultFormatted(Jim_Interp *interp, const char *format, ...)
19640 {
19641
19642 int len = strlen(format);
19643 int extra = 0;
19644 int n = 0;
19645 const char *params[5];
19646 int nobjparam = 0;
19647 Jim_Obj *objparam[5];
19648 char *buf;
19649 va_list args;
19650 int i;
19651
19652 va_start(args, format);
@@ -19766,10 +19661,12 @@
19661 }
19662 else if (strncmp(format + i, "%#s", 3) == 0) {
19663 Jim_Obj *objPtr = va_arg(args, Jim_Obj *);
19664
19665 params[n] = Jim_GetString(objPtr, &l);
19666 objparam[nobjparam++] = objPtr;
19667 Jim_IncrRefCount(objPtr);
19668 }
19669 else {
19670 if (format[i] == '%') {
19671 i++;
19672 }
@@ -19784,10 +19681,14 @@
19681 len = snprintf(buf, len + 1, format, params[0], params[1], params[2], params[3], params[4]);
19682
19683 va_end(args);
19684
19685 Jim_SetResult(interp, Jim_NewStringObjNoAlloc(interp, buf, len));
19686
19687 for (i = 0; i < nobjparam; i++) {
19688 Jim_DecrRefCount(interp, objparam[i]);
19689 }
19690 }
19691
19692
19693 #ifndef jim_ext_package
19694 int Jim_PackageProvide(Jim_Interp *interp, const char *name, const char *ver, int flags)
@@ -19808,11 +19709,11 @@
19709 #include <string.h>
19710
19711
19712 static int subcmd_null(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
19713 {
19714
19715 return JIM_OK;
19716 }
19717
19718 static const jim_subcmd_type dummy_subcmd = {
19719 "dummy", NULL, subcmd_null, 0, 0, JIM_MODFLAG_HIDDEN
@@ -19831,22 +19732,18 @@
19732 }
19733
19734 static void bad_subcmd(Jim_Interp *interp, const jim_subcmd_type * command_table, const char *type,
19735 Jim_Obj *cmd, Jim_Obj *subcmd)
19736 {
19737 Jim_SetResultFormatted(interp, "%#s, %s command \"%#s\": should be ", cmd, type, subcmd);
 
 
19738 add_commands(interp, command_table, ", ");
19739 }
19740
19741 static void show_cmd_usage(Jim_Interp *interp, const jim_subcmd_type * command_table, int argc,
19742 Jim_Obj *const *argv)
19743 {
19744 Jim_SetResultFormatted(interp, "Usage: \"%#s command ... \", where command is one of: ", argv[0]);
 
 
19745 add_commands(interp, command_table, ", ");
19746 }
19747
19748 static void add_cmd_usage(Jim_Interp *interp, const jim_subcmd_type * ct, Jim_Obj *cmd)
19749 {
@@ -19863,67 +19760,78 @@
19760 {
19761 Jim_SetResultString(interp, "wrong # args: should be \"", -1);
19762 add_cmd_usage(interp, command_table, subcmd);
19763 Jim_AppendStrings(interp, Jim_GetResult(interp), "\"", NULL);
19764 }
19765
19766 static const Jim_ObjType subcmdLookupObjType = {
19767 "subcmd-lookup",
19768 NULL,
19769 NULL,
19770 NULL,
19771 JIM_TYPE_REFERENCES
19772 };
19773
19774 const jim_subcmd_type *Jim_ParseSubCmd(Jim_Interp *interp, const jim_subcmd_type * command_table,
19775 int argc, Jim_Obj *const *argv)
19776 {
19777 const jim_subcmd_type *ct;
19778 const jim_subcmd_type *partial = 0;
19779 int cmdlen;
19780 Jim_Obj *cmd;
19781 const char *cmdstr;
 
19782 int help = 0;
19783
 
 
19784 if (argc < 2) {
19785 Jim_SetResultFormatted(interp, "wrong # args: should be \"%#s command ...\"\n"
19786 "Use \"%#s -help ?command?\" for help", argv[0], argv[0]);
 
 
19787 return 0;
19788 }
19789
19790 cmd = argv[1];
19791
19792
19793 if (cmd->typePtr == &subcmdLookupObjType) {
19794 if (cmd->internalRep.ptrIntValue.ptr == command_table) {
19795 ct = command_table + cmd->internalRep.ptrIntValue.int1;
19796 goto found;
19797 }
19798 }
19799
19800
19801 if (Jim_CompareStringImmediate(interp, cmd, "-help")) {
19802 if (argc == 2) {
19803
19804 show_cmd_usage(interp, command_table, argc, argv);
19805 return &dummy_subcmd;
19806 }
19807 help = 1;
19808
19809
19810 cmd = argv[2];
19811 }
19812
19813
19814 if (Jim_CompareStringImmediate(interp, cmd, "-commands")) {
19815
19816 Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
19817 add_commands(interp, command_table, " ");
19818 return &dummy_subcmd;
19819 }
19820
19821 cmdstr = Jim_GetString(cmd, &cmdlen);
19822
19823 for (ct = command_table; ct->cmd; ct++) {
19824 if (Jim_CompareStringImmediate(interp, cmd, ct->cmd)) {
19825
19826 break;
19827 }
19828 if (strncmp(cmdstr, ct->cmd, cmdlen) == 0) {
19829 if (partial) {
19830
19831 if (help) {
19832
19833 show_cmd_usage(interp, command_table, argc, argv);
19834 return &dummy_subcmd;
19835 }
19836 bad_subcmd(interp, command_table, "ambiguous", argv[0], argv[1 + help]);
19837 return 0;
@@ -19931,44 +19839,51 @@
19839 partial = ct;
19840 }
19841 continue;
19842 }
19843
19844
19845 if (partial && !ct->cmd) {
19846 ct = partial;
19847 }
19848
19849 if (!ct->cmd) {
19850
19851 if (help) {
19852
19853 show_cmd_usage(interp, command_table, argc, argv);
19854 return &dummy_subcmd;
19855 }
19856 bad_subcmd(interp, command_table, "unknown", argv[0], argv[1 + help]);
19857 return 0;
19858 }
19859
19860 if (help) {
19861 Jim_SetResultString(interp, "Usage: ", -1);
19862
19863 add_cmd_usage(interp, ct, argv[0]);
19864 return &dummy_subcmd;
19865 }
19866
19867
19868 Jim_FreeIntRep(interp, cmd);
19869 cmd->typePtr = &subcmdLookupObjType;
19870 cmd->internalRep.ptrIntValue.ptr = (void *)command_table;
19871 cmd->internalRep.ptrIntValue.int1 = ct - command_table;
19872
19873 found:
19874
19875 if (argc - 2 < ct->minargs || (ct->maxargs >= 0 && argc - 2 > ct->maxargs)) {
19876 Jim_SetResultString(interp, "wrong # args: should be \"", -1);
19877
19878 add_cmd_usage(interp, ct, argv[0]);
19879 Jim_AppendStrings(interp, Jim_GetResult(interp), "\"", NULL);
19880
19881 return 0;
19882 }
19883
19884
19885 return ct;
19886 }
19887
19888 int Jim_CallSubCmd(Jim_Interp *interp, const jim_subcmd_type * ct, int argc, Jim_Obj *const *argv)
19889 {
@@ -20019,11 +19934,11 @@
19934 *p++ = 0xe0 | ((uc & 0xf000) >> 12);
19935 *p++ = 0x80 | ((uc & 0xfc0) >> 6);
19936 *p = 0x80 | (uc & 0x3f);
19937 return 3;
19938 }
19939
19940 else {
19941 *p++ = 0xf0 | ((uc & 0x1c0000) >> 18);
19942 *p++ = 0x80 | ((uc & 0x3f000) >> 12);
19943 *p++ = 0x80 | ((uc & 0xfc0) >> 6);
19944 *p = 0x80 | (uc & 0x3f);
@@ -20146,11 +20061,12 @@
20061 continue;
20062 }
20063 *p++ = ch;
20064 format += step;
20065 step = utf8_tounicode(format, &ch);
20066
20067 } while (sawFlag && (p - spec <= 5));
20068
20069
20070 width = 0;
20071 if (isdigit(ch)) {
20072 width = strtoul(format, &end, 10);
@@ -20210,11 +20126,11 @@
20126 if (ch == 'h') {
20127 useShort = 1;
20128 format += step;
20129 step = utf8_tounicode(format, &ch);
20130 } else if (ch == 'l') {
20131
20132 format += step;
20133 step = utf8_tounicode(format, &ch);
20134 if (ch == 'l') {
20135 format += step;
20136 step = utf8_tounicode(format, &ch);
@@ -20237,11 +20153,11 @@
20153 goto errorMsg;
20154 case 's': {
20155 formatted_buf = Jim_GetString(objv[objIndex], &formatted_bytes);
20156 formatted_chars = Jim_Utf8Length(interp, objv[objIndex]);
20157 if (gotPrecision && (precision < formatted_chars)) {
20158
20159 formatted_chars = precision;
20160 formatted_bytes = utf8_index(formatted_buf, precision);
20161 }
20162 break;
20163 }
@@ -20249,11 +20165,11 @@
20165 jim_wide code;
20166
20167 if (Jim_GetWide(interp, objv[objIndex], &code) != JIM_OK) {
20168 goto error;
20169 }
20170
20171 formatted_bytes = utf8_getchars(spec, code);
20172 formatted_buf = spec;
20173 formatted_chars = 1;
20174 break;
20175 }
@@ -20267,11 +20183,11 @@
20183 goto error;
20184 }
20185 length = sizeof(w) * 8;
20186
20187
20188
20189 if (num_buffer_size < length + 1) {
20190 num_buffer_size = length + 1;
20191 num_buffer = Jim_Realloc(num_buffer, num_buffer_size);
20192 }
20193
@@ -20295,29 +20211,29 @@
20211 case 'E':
20212 case 'f':
20213 case 'g':
20214 case 'G':
20215 doubleType = 1;
20216
20217 case 'd':
20218 case 'u':
20219 case 'o':
20220 case 'x':
20221 case 'X': {
20222 jim_wide w;
20223 double d;
20224 int length;
20225
20226
20227 if (width) {
20228 p += sprintf(p, "%ld", width);
20229 }
20230 if (gotPrecision) {
20231 p += sprintf(p, ".%ld", precision);
20232 }
20233
20234
20235 if (doubleType) {
20236 if (Jim_GetDouble(interp, objv[objIndex], &d) != JIM_OK) {
20237 goto error;
20238 }
20239 length = MAX_FLOAT_WIDTH;
@@ -20344,19 +20260,26 @@
20260 }
20261
20262 *p++ = (char) ch;
20263 *p = '\0';
20264
20265
20266 if (width > 10000 || length > 10000 || precision > 10000) {
20267 Jim_SetResultString(interp, "format too long", -1);
20268 goto error;
20269 }
20270
20271
20272
20273 if (width > length) {
20274 length = width;
20275 }
20276 if (gotPrecision) {
20277 length += precision;
20278 }
20279
20280
20281 if (num_buffer_size < length + 1) {
20282 num_buffer_size = length + 1;
20283 num_buffer = Jim_Realloc(num_buffer, num_buffer_size);
20284 }
20285
@@ -20370,11 +20293,11 @@
20293 formatted_buf = num_buffer;
20294 break;
20295 }
20296
20297 default: {
20298
20299 spec[0] = ch;
20300 spec[1] = '\0';
20301 Jim_SetResultFormatted(interp, "bad field specifier \"%s\"", spec);
20302 goto error;
20303 }
@@ -20422,37 +20345,37 @@
20345
20346 #define REG_MAX_PAREN 100
20347
20348
20349
20350 #define END 0
20351 #define BOL 1
20352 #define EOL 2
20353 #define ANY 3
20354 #define ANYOF 4
20355 #define ANYBUT 5
20356 #define BRANCH 6
20357 #define BACK 7
20358 #define EXACTLY 8
20359 #define NOTHING 9
20360 #define REP 10
20361 #define REPMIN 11
20362 #define REPX 12
20363 #define REPXMIN 13
20364 #define BOLX 14
20365 #define EOLX 15
20366 #define WORDA 16
20367 #define WORDZ 17
20368
20369 #define OPENNC 1000
20370 #define OPEN 1001
20371
20372
20373
20374
20375 #define CLOSENC 2000
20376 #define CLOSE 2001
20377 #define CLOSE_END (CLOSE+REG_MAX_PAREN)
20378
20379 #define REG_MAGIC 0xFADED00D
20380
20381
@@ -20465,18 +20388,18 @@
20388
20389 #define FAIL(R,M) { (R)->err = (M); return (M); }
20390 #define ISMULT(c) ((c) == '*' || (c) == '+' || (c) == '?' || (c) == '{')
20391 #define META "^$.[()|?{+*"
20392
20393 #define HASWIDTH 1
20394 #define SIMPLE 2
20395 #define SPSTART 4
20396 #define WORST 0
20397
20398 #define MAX_REP_COUNT 1000000
20399
20400 static int reg(regex_t *preg, int paren, int *flagp );
20401 static int regpiece(regex_t *preg, int *flagp );
20402 static int regbranch(regex_t *preg, int *flagp );
20403 static int regatom(regex_t *preg, int *flagp );
20404 static int regnode(regex_t *preg, int op );
20405 static int regnext(regex_t *preg, int p );
@@ -20520,15 +20443,15 @@
20443 memset(preg, 0, sizeof(*preg));
20444
20445 if (exp == NULL)
20446 FAIL(preg, REG_ERR_NULL_ARGUMENT);
20447
20448
20449 preg->cflags = cflags;
20450 preg->regparse = exp;
20451
20452
20453 preg->proglen = (strlen(exp) + 1) * 5;
20454 preg->program = malloc(preg->proglen * sizeof(int));
20455 if (preg->program == NULL)
20456 FAIL(preg, REG_ERR_NOMEM);
20457
@@ -20535,24 +20458,24 @@
20458 regc(preg, REG_MAGIC);
20459 if (reg(preg, 0, &flags) == 0) {
20460 return preg->err;
20461 }
20462
20463
20464 if (preg->re_nsub >= REG_MAX_PAREN)
20465 FAIL(preg,REG_ERR_TOO_BIG);
20466
20467
20468 preg->regstart = 0;
20469 preg->reganch = 0;
20470 preg->regmust = 0;
20471 preg->regmlen = 0;
20472 scan = 1;
20473 if (OP(preg, regnext(preg, scan)) == END) {
20474 scan = OPERAND(scan);
20475
20476
20477 if (OP(preg, scan) == EXACTLY) {
20478 preg->regstart = preg->program[OPERAND(scan)];
20479 }
20480 else if (OP(preg, scan) == BOL)
20481 preg->reganch++;
@@ -20579,24 +20502,24 @@
20502 #endif
20503
20504 return 0;
20505 }
20506
20507 static int reg(regex_t *preg, int paren, int *flagp )
20508 {
20509 int ret;
20510 int br;
20511 int ender;
20512 int parno = 0;
20513 int flags;
20514
20515 *flagp = HASWIDTH;
20516
20517
20518 if (paren) {
20519 if (preg->regparse[0] == '?' && preg->regparse[1] == ':') {
20520
20521 preg->regparse += 2;
20522 parno = -1;
20523 }
20524 else {
20525 parno = ++preg->re_nsub;
@@ -20603,16 +20526,16 @@
20526 }
20527 ret = regnode(preg, OPEN+parno);
20528 } else
20529 ret = 0;
20530
20531
20532 br = regbranch(preg, &flags);
20533 if (br == 0)
20534 return 0;
20535 if (ret != 0)
20536 regtail(preg, ret, br);
20537 else
20538 ret = br;
20539 if (!(flags&HASWIDTH))
20540 *flagp &= ~HASWIDTH;
20541 *flagp |= flags&SPSTART;
@@ -20619,25 +20542,25 @@
20542 while (*preg->regparse == '|') {
20543 preg->regparse++;
20544 br = regbranch(preg, &flags);
20545 if (br == 0)
20546 return 0;
20547 regtail(preg, ret, br);
20548 if (!(flags&HASWIDTH))
20549 *flagp &= ~HASWIDTH;
20550 *flagp |= flags&SPSTART;
20551 }
20552
20553
20554 ender = regnode(preg, (paren) ? CLOSE+parno : END);
20555 regtail(preg, ret, ender);
20556
20557
20558 for (br = ret; br != 0; br = regnext(preg, br))
20559 regoptail(preg, br, ender);
20560
20561
20562 if (paren && *preg->regparse++ != ')') {
20563 preg->err = REG_ERR_UNMATCHED_PAREN;
20564 return 0;
20565 } else if (!paren && *preg->regparse != '\0') {
20566 if (*preg->regparse == ')') {
@@ -20657,11 +20580,11 @@
20580 int ret;
20581 int chain;
20582 int latest;
20583 int flags;
20584
20585 *flagp = WORST;
20586
20587 ret = regnode(preg, BRANCH);
20588 chain = 0;
20589 while (*preg->regparse != '\0' && *preg->regparse != ')' &&
20590 *preg->regparse != '|') {
@@ -20675,11 +20598,11 @@
20598 else {
20599 regtail(preg, chain, latest);
20600 }
20601 chain = latest;
20602 }
20603 if (chain == 0)
20604 (void) regnode(preg, NOTHING);
20605
20606 return(ret);
20607 }
20608
@@ -20705,11 +20628,11 @@
20628 if (!(flags&HASWIDTH) && op != '?') {
20629 preg->err = REG_ERR_OPERAND_COULD_BE_EMPTY;
20630 return 0;
20631 }
20632
20633
20634 if (op == '{') {
20635 char *end;
20636
20637 min = strtoul(preg->regparse + 1, &end, 10);
20638 if (end == preg->regparse + 1) {
@@ -20716,10 +20639,14 @@
20639 preg->err = REG_ERR_BAD_COUNT;
20640 return 0;
20641 }
20642 if (*end == '}') {
20643 max = min;
20644 }
20645 else if (*end == '\0') {
20646 preg->err = REG_ERR_UNMATCHED_BRACES;
20647 return 0;
20648 }
20649 else {
20650 preg->regparse = end;
20651 max = strtoul(preg->regparse + 1, &end, 10);
20652 if (*end != '}') {
@@ -20777,11 +20704,11 @@
20704 static void reg_addrange(regex_t *preg, int lower, int upper)
20705 {
20706 if (lower > upper) {
20707 reg_addrange(preg, upper, lower);
20708 }
20709
20710 regc(preg, upper - lower + 1);
20711 regc(preg, lower);
20712 }
20713
20714 static void reg_addrange_str(regex_t *preg, const char *str)
@@ -20845,17 +20772,17 @@
20772 case 'r': *ch = '\r'; break;
20773 case 't': *ch = '\t'; break;
20774 case 'v': *ch = '\v'; break;
20775 case 'u':
20776 if (*s == '{') {
20777
20778 n = parse_hex(s + 1, 6, ch);
20779 if (n > 0 && s[n + 1] == '}' && *ch >= 0 && *ch <= 0x1fffff) {
20780 s += n + 2;
20781 }
20782 else {
20783
20784 *ch = 'u';
20785 }
20786 }
20787 else if ((n = parse_hex(s, 4, ch)) > 0) {
20788 s += n;
@@ -20886,15 +20813,15 @@
20813 int nocase = (preg->cflags & REG_ICASE);
20814
20815 int ch;
20816 int n = reg_utf8_tounicode_case(preg->regparse, &ch, nocase);
20817
20818 *flagp = WORST;
20819
20820 preg->regparse += n;
20821 switch (ch) {
20822
20823 case '^':
20824 ret = regnode(preg, BOL);
20825 break;
20826 case '$':
20827 ret = regnode(preg, EOL);
@@ -20904,37 +20831,60 @@
20831 *flagp |= HASWIDTH|SIMPLE;
20832 break;
20833 case '[': {
20834 const char *pattern = preg->regparse;
20835
20836 if (*pattern == '^') {
20837 ret = regnode(preg, ANYBUT);
20838 pattern++;
20839 } else
20840 ret = regnode(preg, ANYOF);
20841
20842
20843 if (*pattern == ']' || *pattern == '-') {
20844 reg_addrange(preg, *pattern, *pattern);
20845 pattern++;
20846 }
20847
20848 while (*pattern && *pattern != ']') {
20849
20850 int start;
20851 int end;
20852
20853 enum {
20854 CC_ALPHA, CC_ALNUM, CC_SPACE, CC_BLANK, CC_UPPER, CC_LOWER,
20855 CC_DIGIT, CC_XDIGIT, CC_CNTRL, CC_GRAPH, CC_PRINT, CC_PUNCT,
20856 CC_NUM
20857 };
20858 int cc;
20859
20860 pattern += reg_utf8_tounicode_case(pattern, &start, nocase);
20861 if (start == '\\') {
20862
20863 switch (*pattern) {
20864 case 's':
20865 pattern++;
20866 cc = CC_SPACE;
20867 goto cc_switch;
20868 case 'd':
20869 pattern++;
20870 cc = CC_DIGIT;
20871 goto cc_switch;
20872 case 'w':
20873 pattern++;
20874 reg_addrange(preg, '_', '_');
20875 cc = CC_ALNUM;
20876 goto cc_switch;
20877 }
20878 pattern += reg_decode_escape(pattern, &start);
20879 if (start == 0) {
20880 preg->err = REG_ERR_NULL_CHAR;
20881 return 0;
20882 }
20883 }
20884 if (pattern[0] == '-' && pattern[1] && pattern[1] != ']') {
20885
20886 pattern += utf8_tounicode(pattern, &end);
20887 pattern += reg_utf8_tounicode_case(pattern, &end, nocase);
20888 if (end == '\\') {
20889 pattern += reg_decode_escape(pattern, &end);
20890 if (end == 0) {
@@ -20949,30 +20899,25 @@
20899 if (start == '[' && pattern[0] == ':') {
20900 static const char *character_class[] = {
20901 ":alpha:", ":alnum:", ":space:", ":blank:", ":upper:", ":lower:",
20902 ":digit:", ":xdigit:", ":cntrl:", ":graph:", ":print:", ":punct:",
20903 };
20904
20905 for (cc = 0; cc < CC_NUM; cc++) {
20906 n = strlen(character_class[cc]);
20907 if (strncmp(pattern, character_class[cc], n) == 0) {
20908
 
 
 
 
 
 
20909 pattern += n + 1;
20910 break;
20911 }
20912 }
20913 if (cc != CC_NUM) {
20914 cc_switch:
20915 switch (cc) {
20916 case CC_ALNUM:
20917 reg_addrange(preg, '0', '9');
20918
20919 case CC_ALPHA:
20920 if ((preg->cflags & REG_ICASE) == 0) {
20921 reg_addrange(preg, 'a', 'z');
20922 }
20923 reg_addrange(preg, 'A', 'Z');
@@ -20990,11 +20935,11 @@
20935 reg_addrange(preg, 'a', 'z');
20936 break;
20937 case CC_XDIGIT:
20938 reg_addrange(preg, 'a', 'f');
20939 reg_addrange(preg, 'A', 'F');
20940
20941 case CC_DIGIT:
20942 reg_addrange(preg, '0', '9');
20943 break;
20944 case CC_CNTRL:
20945 reg_addrange(preg, 0, 31);
@@ -21014,11 +20959,11 @@
20959 break;
20960 }
20961 continue;
20962 }
20963 }
20964
20965 reg_addrange(preg, start, start);
20966 }
20967 regc(preg, '\0');
20968
20969 if (*pattern) {
@@ -21037,11 +20982,11 @@
20982 break;
20983 case '\0':
20984 case '|':
20985 case ')':
20986 preg->err = REG_ERR_INTERNAL;
20987 return 0;
20988 case '?':
20989 case '+':
20990 case '*':
20991 case '{':
20992 preg->err = REG_ERR_COUNT_FOLLOWS_NOTHING;
@@ -21090,34 +21035,34 @@
21035 ret = regnode(preg, ch == 's' ? ANYOF : ANYBUT);
21036 reg_addrange_str(preg," \t\r\n\f\v");
21037 regc(preg, '\0');
21038 *flagp |= HASWIDTH|SIMPLE;
21039 break;
21040
21041 default:
21042
21043
21044 preg->regparse--;
21045 goto de_fault;
21046 }
21047 break;
21048 de_fault:
21049 default: {
21050 int added = 0;
21051
21052
21053 preg->regparse -= n;
21054
21055 ret = regnode(preg, EXACTLY);
21056
21057
21058
21059 while (*preg->regparse && strchr(META, *preg->regparse) == NULL) {
21060 n = reg_utf8_tounicode_case(preg->regparse, &ch, (preg->cflags & REG_ICASE));
21061 if (ch == '\\' && preg->regparse[n]) {
21062 if (strchr("<>mMwWdDsSAZ", preg->regparse[n])) {
21063
21064 break;
21065 }
21066 n += reg_decode_escape(preg->regparse + n, &ch);
21067 if (ch == 0) {
21068 preg->err = REG_ERR_NULL_CHAR;
@@ -21125,23 +21070,23 @@
21070 }
21071 }
21072
21073
21074 if (ISMULT(preg->regparse[n])) {
21075
21076 if (added) {
21077
21078 break;
21079 }
21080
21081 regc(preg, ch);
21082 added++;
21083 preg->regparse += n;
21084 break;
21085 }
21086
21087
21088 regc(preg, ch);
21089 added++;
21090 preg->regparse += n;
21091 }
21092 regc(preg, '\0');
@@ -21168,15 +21113,15 @@
21113
21114 static int regnode(regex_t *preg, int op)
21115 {
21116 reg_grow(preg, 2);
21117
21118
21119 preg->program[preg->p++] = op;
21120 preg->program[preg->p++] = 0;
21121
21122
21123 return preg->p - 2;
21124 }
21125
21126 static void regc(regex_t *preg, int b )
21127 {
@@ -21186,13 +21131,13 @@
21131
21132 static int reginsert(regex_t *preg, int op, int size, int opnd )
21133 {
21134 reg_grow(preg, size);
21135
21136
21137 memmove(preg->program + opnd + size, preg->program + opnd, sizeof(int) * (preg->p - opnd));
21138
21139 memset(preg->program + opnd, 0, sizeof(int) * size);
21140
21141 preg->program[opnd] = op;
21142
21143 preg->p += size;
@@ -21204,11 +21149,11 @@
21149 {
21150 int scan;
21151 int temp;
21152 int offset;
21153
21154
21155 scan = p;
21156 for (;;) {
21157 temp = regnext(preg, scan);
21158 if (temp == 0)
21159 break;
@@ -21224,11 +21169,11 @@
21169 }
21170
21171
21172 static void regoptail(regex_t *preg, int p, int val )
21173 {
21174
21175 if (p != 0 && OP(preg, p) == BRANCH) {
21176 regtail(preg, OPERAND(p), val);
21177 }
21178 }
21179
@@ -21240,16 +21185,16 @@
21185 int regexec(regex_t *preg, const char *string, size_t nmatch, regmatch_t pmatch[], int eflags)
21186 {
21187 const char *s;
21188 int scan;
21189
21190
21191 if (preg == NULL || preg->program == NULL || string == NULL) {
21192 return REG_ERR_NULL_ARGUMENT;
21193 }
21194
21195
21196 if (*preg->program != REG_MAGIC) {
21197 return REG_ERR_CORRUPTED;
21198 }
21199
21200 #ifdef DEBUG
@@ -21258,51 +21203,51 @@
21203 #endif
21204
21205 preg->eflags = eflags;
21206 preg->pmatch = pmatch;
21207 preg->nmatch = nmatch;
21208 preg->start = string;
21209
21210
21211 for (scan = OPERAND(1); scan != 0; scan += regopsize(preg, scan)) {
21212 int op = OP(preg, scan);
21213 if (op == END)
21214 break;
21215 if (op == REPX || op == REPXMIN)
21216 preg->program[scan + 4] = 0;
21217 }
21218
21219
21220 if (preg->regmust != 0) {
21221 s = string;
21222 while ((s = str_find(s, preg->program[preg->regmust], preg->cflags & REG_ICASE)) != NULL) {
21223 if (prefix_cmp(preg->program + preg->regmust, preg->regmlen, s, preg->cflags & REG_ICASE) >= 0) {
21224 break;
21225 }
21226 s++;
21227 }
21228 if (s == NULL)
21229 return REG_NOMATCH;
21230 }
21231
21232
21233 preg->regbol = string;
21234
21235
21236 if (preg->reganch) {
21237 if (eflags & REG_NOTBOL) {
21238
21239 goto nextline;
21240 }
21241 while (1) {
21242 if (regtry(preg, string)) {
21243 return REG_NOERROR;
21244 }
21245 if (*string) {
21246 nextline:
21247 if (preg->cflags & REG_NEWLINE) {
21248
21249 string = strchr(string, '\n');
21250 if (string) {
21251 preg->regbol = ++string;
21252 continue;
21253 }
@@ -21310,22 +21255,22 @@
21255 }
21256 return REG_NOMATCH;
21257 }
21258 }
21259
21260
21261 s = string;
21262 if (preg->regstart != '\0') {
21263
21264 while ((s = str_find(s, preg->regstart, preg->cflags & REG_ICASE)) != NULL) {
21265 if (regtry(preg, s))
21266 return REG_NOERROR;
21267 s++;
21268 }
21269 }
21270 else
21271
21272 while (1) {
21273 if (regtry(preg, s))
21274 return REG_NOERROR;
21275 if (*s == '\0') {
21276 break;
@@ -21334,15 +21279,15 @@
21279 int c;
21280 s += utf8_tounicode(s, &c);
21281 }
21282 }
21283
21284
21285 return REG_NOMATCH;
21286 }
21287
21288
21289 static int regtry( regex_t *preg, const char *string )
21290 {
21291 int i;
21292
21293 preg->reginput = string;
@@ -21379,11 +21324,11 @@
21324 }
21325
21326 static int reg_range_find(const int *range, int c)
21327 {
21328 while (*range) {
21329
21330 if (c >= range[1] && c <= (range[0] + range[1] - 1)) {
21331 return 1;
21332 }
21333 range += 2;
21334 }
@@ -21391,11 +21336,11 @@
21336 }
21337
21338 static const char *str_find(const char *string, int c, int nocase)
21339 {
21340 if (nocase) {
21341
21342 c = utf8_upper(c);
21343 }
21344 while (*string) {
21345 int ch;
21346 int n = reg_utf8_tounicode_case(string, &ch, nocase);
@@ -21435,15 +21380,15 @@
21380 no = regrepeat(preg, scan + 5, max);
21381 if (no < min) {
21382 return 0;
21383 }
21384 if (matchmin) {
21385
21386 max = no;
21387 no = min;
21388 }
21389
21390 while (1) {
21391 if (matchmin) {
21392 if (no > max) {
21393 break;
21394 }
@@ -21453,22 +21398,22 @@
21398 break;
21399 }
21400 }
21401 preg->reginput = save + utf8_index(save, no);
21402 reg_utf8_tounicode_case(preg->reginput, &c, (preg->cflags & REG_ICASE));
21403
21404 if (reg_iseol(preg, nextch) || c == nextch) {
21405 if (regmatch(preg, next)) {
21406 return(1);
21407 }
21408 }
21409 if (matchmin) {
21410
21411 no++;
21412 }
21413 else {
21414
21415 no--;
21416 }
21417 }
21418 return(0);
21419 }
@@ -21478,13 +21423,13 @@
21423 int *scanpt = preg->program + scan;
21424
21425 int max = scanpt[2];
21426 int min = scanpt[3];
21427
21428
21429 if (scanpt[4] < min) {
21430
21431 scanpt[4]++;
21432 if (regmatch(preg, scan + 5)) {
21433 return 1;
21434 }
21435 scanpt[4]--;
@@ -21493,39 +21438,39 @@
21438 if (scanpt[4] > max) {
21439 return 0;
21440 }
21441
21442 if (matchmin) {
21443
21444 if (regmatch(preg, regnext(preg, scan))) {
21445 return 1;
21446 }
21447
21448 scanpt[4]++;
21449 if (regmatch(preg, scan + 5)) {
21450 return 1;
21451 }
21452 scanpt[4]--;
21453 return 0;
21454 }
21455
21456 if (scanpt[4] < max) {
21457 scanpt[4]++;
21458 if (regmatch(preg, scan + 5)) {
21459 return 1;
21460 }
21461 scanpt[4]--;
21462 }
21463
21464 return regmatch(preg, regnext(preg, scan));
21465 }
21466
21467
21468 static int regmatch(regex_t *preg, int prog)
21469 {
21470 int scan;
21471 int next;
21472 const char *save;
21473
21474 scan = prog;
21475
21476 #ifdef DEBUG
@@ -21535,11 +21480,11 @@
21480 while (scan != 0) {
21481 int n;
21482 int c;
21483 #ifdef DEBUG
21484 if (regnarrate) {
21485 fprintf(stderr, "%3d: %s...\n", scan, regprop(OP(preg, scan)));
21486 }
21487 #endif
21488 next = regnext(preg, scan);
21489 n = reg_utf8_tounicode_case(preg->reginput, &c, (preg->cflags & REG_ICASE));
21490
@@ -21546,49 +21491,49 @@
21491 switch (OP(preg, scan)) {
21492 case BOLX:
21493 if ((preg->eflags & REG_NOTBOL)) {
21494 return(0);
21495 }
21496
21497 case BOL:
21498 if (preg->reginput != preg->regbol) {
21499 return(0);
21500 }
21501 break;
21502 case EOLX:
21503 if (c != 0) {
21504
21505 return 0;
21506 }
21507 break;
21508 case EOL:
21509 if (!reg_iseol(preg, c)) {
21510 return(0);
21511 }
21512 break;
21513 case WORDA:
21514
21515 if ((!isalnum(UCHAR(c))) && c != '_')
21516 return(0);
21517
21518 if (preg->reginput > preg->regbol &&
21519 (isalnum(UCHAR(preg->reginput[-1])) || preg->reginput[-1] == '_'))
21520 return(0);
21521 break;
21522 case WORDZ:
21523
21524 if (preg->reginput > preg->regbol) {
21525
21526 if (reg_iseol(preg, c) || !isalnum(UCHAR(c)) || c != '_') {
21527 c = preg->reginput[-1];
21528
21529 if (isalnum(UCHAR(c)) || c == '_') {
21530 break;
21531 }
21532 }
21533 }
21534
21535 return(0);
21536
21537 case ANY:
21538 if (reg_iseol(preg, c))
21539 return 0;
@@ -21624,12 +21569,12 @@
21569 case NOTHING:
21570 break;
21571 case BACK:
21572 break;
21573 case BRANCH:
21574 if (OP(preg, next) != BRANCH)
21575 next = OPERAND(scan);
21576 else {
21577 do {
21578 save = preg->reginput;
21579 if (regmatch(preg, OPERAND(scan))) {
21580 return(1);
@@ -21636,11 +21581,11 @@
21581 }
21582 preg->reginput = save;
21583 scan = regnext(preg, scan);
21584 } while (scan != 0 && OP(preg, scan) == BRANCH);
21585 return(0);
21586
21587 }
21588 break;
21589 case REP:
21590 case REPMIN:
21591 return regmatchsimplerepeat(preg, scan, OP(preg, scan) == REPMIN);
@@ -21648,11 +21593,11 @@
21593 case REPX:
21594 case REPXMIN:
21595 return regmatchrepeat(preg, scan, OP(preg, scan) == REPXMIN);
21596
21597 case END:
21598 return 1;
21599
21600 case OPENNC:
21601 case CLOSENC:
21602 return regmatch(preg, next);
21603
@@ -21695,11 +21640,11 @@
21640
21641 scan = preg->reginput;
21642 opnd = OPERAND(p);
21643 switch (OP(preg, p)) {
21644 case ANY:
21645
21646 while (!reg_iseol(preg, *scan) && count < max) {
21647 count++;
21648 scan++;
21649 }
21650 break;
@@ -21731,13 +21676,13 @@
21676 }
21677 count++;
21678 scan += n;
21679 }
21680 break;
21681 default:
21682 preg->err = REG_ERR_INTERNAL;
21683 count = 0;
21684 break;
21685 }
21686 preg->reginput = scan;
21687
21688 return(count);
@@ -21758,11 +21703,11 @@
21703 return(p+offset);
21704 }
21705
21706 static int regopsize(regex_t *preg, int p )
21707 {
21708
21709 switch (OP(preg, p)) {
21710 case REP:
21711 case REPMIN:
21712 case REPX:
21713 case REPXMIN:
@@ -21818,10 +21763,223 @@
21763
21764 void regfree(regex_t *preg)
21765 {
21766 free(preg->program);
21767 }
21768
21769 #endif
21770 #include <string.h>
21771
21772 void Jim_SetResultErrno(Jim_Interp *interp, const char *msg)
21773 {
21774 Jim_SetResultFormatted(interp, "%s: %s", msg, strerror(Jim_Errno()));
21775 }
21776
21777 #if defined(__MINGW32__)
21778 #include <sys/stat.h>
21779
21780 int Jim_Errno(void)
21781 {
21782 switch (GetLastError()) {
21783 case ERROR_FILE_NOT_FOUND: return ENOENT;
21784 case ERROR_PATH_NOT_FOUND: return ENOENT;
21785 case ERROR_TOO_MANY_OPEN_FILES: return EMFILE;
21786 case ERROR_ACCESS_DENIED: return EACCES;
21787 case ERROR_INVALID_HANDLE: return EBADF;
21788 case ERROR_BAD_ENVIRONMENT: return E2BIG;
21789 case ERROR_BAD_FORMAT: return ENOEXEC;
21790 case ERROR_INVALID_ACCESS: return EACCES;
21791 case ERROR_INVALID_DRIVE: return ENOENT;
21792 case ERROR_CURRENT_DIRECTORY: return EACCES;
21793 case ERROR_NOT_SAME_DEVICE: return EXDEV;
21794 case ERROR_NO_MORE_FILES: return ENOENT;
21795 case ERROR_WRITE_PROTECT: return EROFS;
21796 case ERROR_BAD_UNIT: return ENXIO;
21797 case ERROR_NOT_READY: return EBUSY;
21798 case ERROR_BAD_COMMAND: return EIO;
21799 case ERROR_CRC: return EIO;
21800 case ERROR_BAD_LENGTH: return EIO;
21801 case ERROR_SEEK: return EIO;
21802 case ERROR_WRITE_FAULT: return EIO;
21803 case ERROR_READ_FAULT: return EIO;
21804 case ERROR_GEN_FAILURE: return EIO;
21805 case ERROR_SHARING_VIOLATION: return EACCES;
21806 case ERROR_LOCK_VIOLATION: return EACCES;
21807 case ERROR_SHARING_BUFFER_EXCEEDED: return ENFILE;
21808 case ERROR_HANDLE_DISK_FULL: return ENOSPC;
21809 case ERROR_NOT_SUPPORTED: return ENODEV;
21810 case ERROR_REM_NOT_LIST: return EBUSY;
21811 case ERROR_DUP_NAME: return EEXIST;
21812 case ERROR_BAD_NETPATH: return ENOENT;
21813 case ERROR_NETWORK_BUSY: return EBUSY;
21814 case ERROR_DEV_NOT_EXIST: return ENODEV;
21815 case ERROR_TOO_MANY_CMDS: return EAGAIN;
21816 case ERROR_ADAP_HDW_ERR: return EIO;
21817 case ERROR_BAD_NET_RESP: return EIO;
21818 case ERROR_UNEXP_NET_ERR: return EIO;
21819 case ERROR_NETNAME_DELETED: return ENOENT;
21820 case ERROR_NETWORK_ACCESS_DENIED: return EACCES;
21821 case ERROR_BAD_DEV_TYPE: return ENODEV;
21822 case ERROR_BAD_NET_NAME: return ENOENT;
21823 case ERROR_TOO_MANY_NAMES: return ENFILE;
21824 case ERROR_TOO_MANY_SESS: return EIO;
21825 case ERROR_SHARING_PAUSED: return EAGAIN;
21826 case ERROR_REDIR_PAUSED: return EAGAIN;
21827 case ERROR_FILE_EXISTS: return EEXIST;
21828 case ERROR_CANNOT_MAKE: return ENOSPC;
21829 case ERROR_OUT_OF_STRUCTURES: return ENFILE;
21830 case ERROR_ALREADY_ASSIGNED: return EEXIST;
21831 case ERROR_INVALID_PASSWORD: return EPERM;
21832 case ERROR_NET_WRITE_FAULT: return EIO;
21833 case ERROR_NO_PROC_SLOTS: return EAGAIN;
21834 case ERROR_DISK_CHANGE: return EXDEV;
21835 case ERROR_BROKEN_PIPE: return EPIPE;
21836 case ERROR_OPEN_FAILED: return ENOENT;
21837 case ERROR_DISK_FULL: return ENOSPC;
21838 case ERROR_NO_MORE_SEARCH_HANDLES: return EMFILE;
21839 case ERROR_INVALID_TARGET_HANDLE: return EBADF;
21840 case ERROR_INVALID_NAME: return ENOENT;
21841 case ERROR_PROC_NOT_FOUND: return ESRCH;
21842 case ERROR_WAIT_NO_CHILDREN: return ECHILD;
21843 case ERROR_CHILD_NOT_COMPLETE: return ECHILD;
21844 case ERROR_DIRECT_ACCESS_HANDLE: return EBADF;
21845 case ERROR_SEEK_ON_DEVICE: return ESPIPE;
21846 case ERROR_BUSY_DRIVE: return EAGAIN;
21847 case ERROR_DIR_NOT_EMPTY: return EEXIST;
21848 case ERROR_NOT_LOCKED: return EACCES;
21849 case ERROR_BAD_PATHNAME: return ENOENT;
21850 case ERROR_LOCK_FAILED: return EACCES;
21851 case ERROR_ALREADY_EXISTS: return EEXIST;
21852 case ERROR_FILENAME_EXCED_RANGE: return ENAMETOOLONG;
21853 case ERROR_BAD_PIPE: return EPIPE;
21854 case ERROR_PIPE_BUSY: return EAGAIN;
21855 case ERROR_PIPE_NOT_CONNECTED: return EPIPE;
21856 case ERROR_DIRECTORY: return ENOTDIR;
21857 }
21858 return EINVAL;
21859 }
21860
21861 pidtype waitpid(pidtype pid, int *status, int nohang)
21862 {
21863 DWORD ret = WaitForSingleObject(pid, nohang ? 0 : INFINITE);
21864 if (ret == WAIT_TIMEOUT || ret == WAIT_FAILED) {
21865
21866 return JIM_BAD_PID;
21867 }
21868 GetExitCodeProcess(pid, &ret);
21869 *status = ret;
21870 CloseHandle(pid);
21871 return pid;
21872 }
21873
21874 int Jim_MakeTempFile(Jim_Interp *interp, const char *filename_template, int unlink_file)
21875 {
21876 char name[MAX_PATH];
21877 HANDLE handle;
21878
21879 if (!GetTempPath(MAX_PATH, name) || !GetTempFileName(name, filename_template ? filename_template : "JIM", 0, name)) {
21880 return -1;
21881 }
21882
21883 handle = CreateFile(name, GENERIC_READ | GENERIC_WRITE, 0, NULL,
21884 CREATE_ALWAYS, FILE_ATTRIBUTE_TEMPORARY | (unlink_file ? FILE_FLAG_DELETE_ON_CLOSE : 0),
21885 NULL);
21886
21887 if (handle == INVALID_HANDLE_VALUE) {
21888 goto error;
21889 }
21890
21891 Jim_SetResultString(interp, name, -1);
21892 return _open_osfhandle((int)handle, _O_RDWR | _O_TEXT);
21893
21894 error:
21895 Jim_SetResultErrno(interp, name);
21896 DeleteFile(name);
21897 return -1;
21898 }
21899
21900 int Jim_OpenForWrite(const char *filename, int append)
21901 {
21902 if (strcmp(filename, "/dev/null") == 0) {
21903 filename = "nul:";
21904 }
21905 int fd = _open(filename, _O_WRONLY | _O_CREAT | _O_TEXT | (append ? _O_APPEND : _O_TRUNC), _S_IREAD | _S_IWRITE);
21906 if (fd >= 0 && append) {
21907
21908 _lseek(fd, 0L, SEEK_END);
21909 }
21910 return fd;
21911 }
21912
21913 int Jim_OpenForRead(const char *filename)
21914 {
21915 if (strcmp(filename, "/dev/null") == 0) {
21916 filename = "nul:";
21917 }
21918 return _open(filename, _O_RDONLY | _O_TEXT, 0);
21919 }
21920
21921 #elif defined(HAVE_UNISTD_H)
21922
21923
21924
21925 int Jim_MakeTempFile(Jim_Interp *interp, const char *filename_template, int unlink_file)
21926 {
21927 int fd;
21928 mode_t mask;
21929 Jim_Obj *filenameObj;
21930
21931 if (filename_template == NULL) {
21932 const char *tmpdir = getenv("TMPDIR");
21933 if (tmpdir == NULL || *tmpdir == '\0' || access(tmpdir, W_OK) != 0) {
21934 tmpdir = "/tmp/";
21935 }
21936 filenameObj = Jim_NewStringObj(interp, tmpdir, -1);
21937 if (tmpdir[0] && tmpdir[strlen(tmpdir) - 1] != '/') {
21938 Jim_AppendString(interp, filenameObj, "/", 1);
21939 }
21940 Jim_AppendString(interp, filenameObj, "tcl.tmp.XXXXXX", -1);
21941 }
21942 else {
21943 filenameObj = Jim_NewStringObj(interp, filename_template, -1);
21944 }
21945
21946
21947 mask = umask(S_IXUSR | S_IRWXG | S_IRWXO);
21948 #ifdef HAVE_MKSTEMP
21949 fd = mkstemp(filenameObj->bytes);
21950 #else
21951 if (mktemp(filenameObj->bytes) == NULL) {
21952 fd = -1;
21953 }
21954 else {
21955 fd = open(filenameObj->bytes, O_RDWR | O_CREAT | O_TRUNC);
21956 }
21957 #endif
21958 umask(mask);
21959 if (fd < 0) {
21960 Jim_SetResultErrno(interp, Jim_String(filenameObj));
21961 Jim_FreeNewObj(interp, filenameObj);
21962 return -1;
21963 }
21964 if (unlink_file) {
21965 remove(Jim_String(filenameObj));
21966 }
21967
21968 Jim_SetResult(interp, filenameObj);
21969 return fd;
21970 }
21971
21972 int Jim_OpenForWrite(const char *filename, int append)
21973 {
21974 return open(filename, O_WRONLY | O_CREAT | (append ? O_APPEND : O_TRUNC), 0666);
21975 }
21976
21977 int Jim_OpenForRead(const char *filename)
21978 {
21979 return open(filename, O_RDONLY, 0);
21980 }
21981
21982 #endif
21983
21984 #if defined(_WIN32) || defined(WIN32)
21985 #ifndef STRICT
@@ -21879,26 +22037,26 @@
22037 {
22038 DIR *dir = 0;
22039
22040 if (name && name[0]) {
22041 size_t base_length = strlen(name);
22042 const char *all =
22043 strchr("/\\", name[base_length - 1]) ? "*" : "/*";
22044
22045 if ((dir = (DIR *) Jim_Alloc(sizeof *dir)) != 0 &&
22046 (dir->name = (char *)Jim_Alloc(base_length + strlen(all) + 1)) != 0) {
22047 strcat(strcpy(dir->name, name), all);
22048
22049 if ((dir->handle = (long)_findfirst(dir->name, &dir->info)) != -1)
22050 dir->result.d_name = 0;
22051 else {
22052 Jim_Free(dir->name);
22053 Jim_Free(dir);
22054 dir = 0;
22055 }
22056 }
22057 else {
22058 Jim_Free(dir);
22059 dir = 0;
22060 errno = ENOMEM;
22061 }
22062 }
@@ -21916,11 +22074,11 @@
22074 if (dir->handle != -1)
22075 result = _findclose(dir->handle);
22076 Jim_Free(dir->name);
22077 Jim_Free(dir);
22078 }
22079 if (result == -1)
22080 errno = EBADF;
22081 return result;
22082 }
22083
22084 struct dirent *readdir(DIR * dir)
@@ -21938,28 +22096,77 @@
22096 }
22097 return result;
22098 }
22099 #endif
22100 #endif
22101 #include <stdio.h>
22102 #include <signal.h>
22103
22104
22105
22106
22107
22108
22109 #ifndef SIGPIPE
22110 #define SIGPIPE 13
22111 #endif
22112 #ifndef SIGINT
22113 #define SIGINT 2
22114 #endif
22115
22116 const char *Jim_SignalId(int sig)
22117 {
22118 static char buf[10];
22119 switch (sig) {
22120 case SIGINT: return "SIGINT";
22121 case SIGPIPE: return "SIGPIPE";
22122
22123 }
22124 snprintf(buf, sizeof(buf), "%d", sig);
22125 return buf;
22126 }
22127 #ifndef JIM_BOOTSTRAP_LIB_ONLY
22128 #include <errno.h>
22129 #include <string.h>
22130
22131
22132 #ifdef USE_LINENOISE
22133 #ifdef HAVE_UNISTD_H
22134 #include <unistd.h>
22135 #endif
22136 #ifdef HAVE_SYS_STAT_H
22137 #include <sys/stat.h>
22138 #endif
22139 #include "linenoise.h"
22140 #else
22141 #define MAX_LINE_LEN 512
22142 #endif
22143
22144 #ifdef USE_LINENOISE
22145 static void JimCompletionCallback(const char *prefix, linenoiseCompletions *comp, void *userdata);
22146 static const char completion_callback_assoc_key[] = "interactive-completion";
22147 #endif
22148
22149 char *Jim_HistoryGetline(Jim_Interp *interp, const char *prompt)
22150 {
22151 #ifdef USE_LINENOISE
22152 struct JimCompletionInfo *compinfo = Jim_GetAssocData(interp, completion_callback_assoc_key);
22153 char *result;
22154 Jim_Obj *objPtr;
22155 long mlmode = 0;
22156 if (compinfo) {
22157 linenoiseSetCompletionCallback(JimCompletionCallback, compinfo);
22158 }
22159 objPtr = Jim_GetVariableStr(interp, "history::multiline", JIM_NONE);
22160 if (objPtr && Jim_GetLong(interp, objPtr, &mlmode) == JIM_NONE) {
22161 linenoiseSetMultiLine(mlmode);
22162 }
22163
22164 result = linenoise(prompt);
22165
22166 linenoiseSetCompletionCallback(NULL, NULL);
22167 return result;
22168 #else
22169 int len;
22170 char *line = malloc(MAX_LINE_LEN);
22171
22172 fputs(prompt, stdout);
@@ -21992,26 +22199,92 @@
22199 }
22200
22201 void Jim_HistorySave(const char *filename)
22202 {
22203 #ifdef USE_LINENOISE
22204 #ifdef HAVE_UMASK
22205 mode_t mask;
22206
22207 mask = umask(S_IXUSR | S_IRWXG | S_IRWXO);
22208 #endif
22209 linenoiseHistorySave(filename);
22210 #ifdef HAVE_UMASK
22211 umask(mask);
22212 #endif
22213 #endif
22214 }
22215
22216 void Jim_HistoryShow(void)
22217 {
22218 #ifdef USE_LINENOISE
22219
22220 int i;
22221 int len;
22222 char **history = linenoiseHistory(&len);
22223 for (i = 0; i < len; i++) {
22224 printf("%4d %s\n", i + 1, history[i]);
22225 }
22226 #endif
22227 }
22228
22229 #ifdef USE_LINENOISE
22230 struct JimCompletionInfo {
22231 Jim_Interp *interp;
22232 Jim_Obj *command;
22233 };
22234
22235 static void JimCompletionCallback(const char *prefix, linenoiseCompletions *comp, void *userdata)
22236 {
22237 struct JimCompletionInfo *info = (struct JimCompletionInfo *)userdata;
22238 Jim_Obj *objv[2];
22239 int ret;
22240
22241 objv[0] = info->command;
22242 objv[1] = Jim_NewStringObj(info->interp, prefix, -1);
22243
22244 ret = Jim_EvalObjVector(info->interp, 2, objv);
22245
22246
22247 if (ret == JIM_OK) {
22248 int i;
22249 Jim_Obj *listObj = Jim_GetResult(info->interp);
22250 int len = Jim_ListLength(info->interp, listObj);
22251 for (i = 0; i < len; i++) {
22252 linenoiseAddCompletion(comp, Jim_String(Jim_ListGetIndex(info->interp, listObj, i)));
22253 }
22254 }
22255 }
22256
22257 static void JimHistoryFreeCompletion(Jim_Interp *interp, void *data)
22258 {
22259 struct JimCompletionInfo *compinfo = data;
22260
22261 Jim_DecrRefCount(interp, compinfo->command);
22262
22263 Jim_Free(compinfo);
22264 }
22265 #endif
22266
22267 void Jim_HistorySetCompletion(Jim_Interp *interp, Jim_Obj *commandObj)
22268 {
22269 #ifdef USE_LINENOISE
22270 if (commandObj) {
22271
22272 Jim_IncrRefCount(commandObj);
22273 }
22274
22275 Jim_DeleteAssocData(interp, completion_callback_assoc_key);
22276
22277 if (commandObj) {
22278 struct JimCompletionInfo *compinfo = Jim_Alloc(sizeof(*compinfo));
22279 compinfo->interp = interp;
22280 compinfo->command = commandObj;
22281
22282 Jim_SetAssocData(interp, completion_callback_assoc_key, JimHistoryFreeCompletion, compinfo);
22283 }
22284 #endif
22285 }
22286
22287 int Jim_InteractivePrompt(Jim_Interp *interp)
22288 {
22289 int retcode = JIM_OK;
22290 char *history_file = NULL;
@@ -22023,10 +22296,12 @@
22296 int history_len = strlen(home) + sizeof("/.jim_history");
22297 history_file = Jim_Alloc(history_len);
22298 snprintf(history_file, history_len, "%s/.jim_history", home);
22299 Jim_HistoryLoad(history_file);
22300 }
22301
22302 Jim_HistorySetCompletion(interp, Jim_NewStringObj(interp, "tcl::autocomplete", -1));
22303 #endif
22304
22305 printf("Welcome to Jim version %d.%d\n",
22306 JIM_VERSION / 100, JIM_VERSION % 100);
22307 Jim_SetVariableStrWithStr(interp, JIM_INTERACTIVE, "1");
@@ -22055,21 +22330,21 @@
22330 Jim_IncrRefCount(scriptObjPtr);
22331 while (1) {
22332 char state;
22333 char *line;
22334
22335 line = Jim_HistoryGetline(interp, prompt);
22336 if (line == NULL) {
22337 if (errno == EINTR) {
22338 continue;
22339 }
22340 Jim_DecrRefCount(interp, scriptObjPtr);
22341 retcode = JIM_OK;
22342 goto out;
22343 }
22344 if (Jim_Length(scriptObjPtr) != 0) {
22345
22346 Jim_AppendString(interp, scriptObjPtr, "\n", 1);
22347 }
22348 Jim_AppendString(interp, scriptObjPtr, line, -1);
22349 free(line);
22350 if (Jim_ScriptIsComplete(interp, scriptObjPtr, &state))
@@ -22077,11 +22352,11 @@
22352
22353 snprintf(prompt, sizeof(prompt), "%c> ", state);
22354 }
22355 #ifdef USE_LINENOISE
22356 if (strcmp(Jim_String(scriptObjPtr), "h") == 0) {
22357
22358 Jim_HistoryShow();
22359 Jim_DecrRefCount(interp, scriptObjPtr);
22360 continue;
22361 }
22362
@@ -22104,10 +22379,11 @@
22379 printf("%s\n", result);
22380 }
22381 }
22382 out:
22383 Jim_Free(history_file);
22384
22385 return retcode;
22386 }
22387
22388 #include <stdio.h>
22389 #include <stdlib.h>
@@ -22120,11 +22396,11 @@
22396 static void JimSetArgv(Jim_Interp *interp, int argc, char *const argv[])
22397 {
22398 int n;
22399 Jim_Obj *listObj = Jim_NewListObj(interp, NULL, 0);
22400
22401
22402 for (n = 0; n < argc; n++) {
22403 Jim_Obj *obj = Jim_NewStringObj(interp, argv[n], -1);
22404
22405 Jim_ListAppendElement(interp, listObj, obj);
22406 }
@@ -22146,71 +22422,75 @@
22422 printf("or : %s [options] [filename]\n", executable_name);
22423 printf("\n");
22424 printf("Without options: Interactive mode\n");
22425 printf("\n");
22426 printf("Options:\n");
22427 printf(" --version : prints the version string\n");
22428 printf(" --help : prints this text\n");
22429 printf(" -e CMD : executes command CMD\n");
22430 printf(" NOTE: all subsequent options will be passed as arguments to the command\n");
22431 printf(" [filename|-] : executes the script contained in the named file, or from stdin if \"-\"\n");
22432 printf(" NOTE: all subsequent options will be passed to the script\n\n");
22433 }
22434
22435 int main(int argc, char *const argv[])
22436 {
22437 int retcode;
22438 Jim_Interp *interp;
22439 char *const orig_argv0 = argv[0];
22440
22441
22442 if (argc > 1 && strcmp(argv[1], "--version") == 0) {
22443 printf("%d.%d\n", JIM_VERSION / 100, JIM_VERSION % 100);
22444 return 0;
22445 }
22446 else if (argc > 1 && strcmp(argv[1], "--help") == 0) {
22447 usage(argv[0]);
22448 return 0;
22449 }
22450
22451
22452 interp = Jim_CreateInterp();
22453 Jim_RegisterCoreCommands(interp);
22454
22455
22456 if (Jim_InitStaticExtensions(interp) != JIM_OK) {
22457 JimPrintErrorMessage(interp);
22458 }
22459
22460 Jim_SetVariableStrWithStr(interp, "jim::argv0", orig_argv0);
22461 Jim_SetVariableStrWithStr(interp, JIM_INTERACTIVE, argc == 1 ? "1" : "0");
22462 retcode = Jim_initjimshInit(interp);
22463
22464 if (argc == 1) {
22465
22466 if (retcode == JIM_ERR) {
22467 JimPrintErrorMessage(interp);
22468 }
22469 if (retcode != JIM_EXIT) {
22470 JimSetArgv(interp, 0, NULL);
22471 retcode = Jim_InteractivePrompt(interp);
22472 }
22473 }
22474 else {
22475
22476 if (argc > 2 && strcmp(argv[1], "-e") == 0) {
22477
22478 JimSetArgv(interp, argc - 3, argv + 3);
22479 retcode = Jim_Eval(interp, argv[2]);
22480 if (retcode != JIM_ERR) {
22481 printf("%s\n", Jim_String(Jim_GetResult(interp)));
22482 }
22483 }
22484 else {
22485 Jim_SetVariableStr(interp, "argv0", Jim_NewStringObj(interp, argv[1], -1));
22486 JimSetArgv(interp, argc - 2, argv + 2);
22487 if (strcmp(argv[1], "-") == 0) {
22488 retcode = Jim_Eval(interp, "eval [info source [stdin read] stdin 1]");
22489 } else {
22490 retcode = Jim_EvalFile(interp, argv[1]);
22491 }
22492 }
22493 if (retcode == JIM_ERR) {
22494 JimPrintErrorMessage(interp);
22495 }
22496 }
22497
--- autosetup/pkg-config.tcl
+++ autosetup/pkg-config.tcl
@@ -1,34 +1,35 @@
11
# Copyright (c) 2016 WorkWare Systems http://www.workware.net.au/
22
# All rights reserved
33
44
# @synopsis:
55
#
6
-# The 'pkg-config' module allows package information to be found via pkg-config
6
+# The 'pkg-config' module allows package information to be found via 'pkg-config'.
77
#
88
# If not cross-compiling, the package path should be determined automatically
9
-# by pkg-config.
9
+# by 'pkg-config'.
1010
# If cross-compiling, the default package path is the compiler sysroot.
11
-# If the C compiler doesn't support -print-sysroot, the path can be supplied
12
-# by the --sysroot option or by defining SYSROOT.
11
+# If the C compiler doesn't support '-print-sysroot', the path can be supplied
12
+# by the '--sysroot' option or by defining 'SYSROOT'.
1313
#
14
-# PKG_CONFIG may be set to use an alternative to pkg-config
14
+# 'PKG_CONFIG' may be set to use an alternative to 'pkg-config'.
1515
1616
use cc
1717
1818
module-options {
1919
sysroot:dir => "Override compiler sysroot for pkg-config search path"
2020
}
2121
2222
# @pkg-config-init ?required?
2323
#
24
-# Initialises the pkg-config system. Unless required is set to 0,
25
-# it is a fatal error if the pkg-config
24
+# Initialises the 'pkg-config' system. Unless '$required' is set to 0,
25
+# it is a fatal error if a usable 'pkg-config' is not found .
26
+#
2627
# This command will normally be called automatically as required,
27
-# but it may be invoked explicitly if lack of pkg-config is acceptable.
28
+# but it may be invoked explicitly if lack of 'pkg-config' is acceptable.
2829
#
29
-# Returns 1 if ok, or 0 if pkg-config not found/usable (only if required=0)
30
+# Returns 1 if ok, or 0 if 'pkg-config' not found/usable (only if '$required' is 0).
3031
#
3132
proc pkg-config-init {{required 1}} {
3233
if {[is-defined HAVE_PKG_CONFIG]} {
3334
return [get-define HAVE_PKG_CONFIG]
3435
}
@@ -46,12 +47,12 @@
4647
msg-result $version
4748
define PKG_CONFIG_VERSION $version
4849
4950
set found 1
5051
51
- if {[opt-val sysroot] ne ""} {
52
- define SYSROOT [file-normalize [opt-val sysroot]]
52
+ if {[opt-str sysroot o]} {
53
+ define SYSROOT [file-normalize $o]
5354
msg-result "Using specified sysroot [get-define SYSROOT]"
5455
} elseif {[get-define build] ne [get-define host]} {
5556
if {[catch {exec-with-stderr [get-define CC] -print-sysroot} result errinfo] == 0} {
5657
# Use the compiler sysroot, if there is one
5758
define SYSROOT $result
@@ -81,21 +82,21 @@
8182
return $found
8283
}
8384
8485
# @pkg-config module ?requirements?
8586
#
86
-# Use pkg-config to find the given module meeting the given requirements.
87
+# Use 'pkg-config' to find the given module meeting the given requirements.
8788
# e.g.
8889
#
8990
## pkg-config pango >= 1.37.0
9091
#
91
-# If found, returns 1 and sets HAVE_PKG_PANGO to 1 along with:
92
+# If found, returns 1 and sets 'HAVE_PKG_PANGO' to 1 along with:
9293
#
9394
## PKG_PANGO_VERSION to the found version
94
-## PKG_PANGO_LIBS to the required libs (--libs-only-l)
95
+## PKG_PANGO_LIBS to the required libs (--libs-only-l)
9596
## PKG_PANGO_LDFLAGS to the required linker flags (--libs-only-L)
96
-## PKG_PANGO_CFLAGS to the required compiler flags (--cflags)
97
+## PKG_PANGO_CFLAGS to the required compiler flags (--cflags)
9798
#
9899
# If not found, returns 0.
99100
#
100101
proc pkg-config {module args} {
101102
set ok [pkg-config-init]
@@ -122,13 +123,13 @@
122123
return 1
123124
}
124125
125126
# @pkg-config-get module setting
126127
#
127
-# Convenience access to the results of pkg-config
128
+# Convenience access to the results of 'pkg-config'.
128129
#
129
-# For example, [pkg-config-get pango CFLAGS] returns
130
-# the value of PKG_PANGO_CFLAGS, or "" if not defined.
130
+# For example, '[pkg-config-get pango CFLAGS]' returns
131
+# the value of 'PKG_PANGO_CFLAGS', or '""' if not defined.
131132
proc pkg-config-get {module name} {
132133
set prefix [feature-define-name $module PKG_]
133134
get-define ${prefix}_${name} ""
134135
}
135136
--- autosetup/pkg-config.tcl
+++ autosetup/pkg-config.tcl
@@ -1,34 +1,35 @@
1 # Copyright (c) 2016 WorkWare Systems http://www.workware.net.au/
2 # All rights reserved
3
4 # @synopsis:
5 #
6 # The 'pkg-config' module allows package information to be found via pkg-config
7 #
8 # If not cross-compiling, the package path should be determined automatically
9 # by pkg-config.
10 # If cross-compiling, the default package path is the compiler sysroot.
11 # If the C compiler doesn't support -print-sysroot, the path can be supplied
12 # by the --sysroot option or by defining SYSROOT.
13 #
14 # PKG_CONFIG may be set to use an alternative to pkg-config
15
16 use cc
17
18 module-options {
19 sysroot:dir => "Override compiler sysroot for pkg-config search path"
20 }
21
22 # @pkg-config-init ?required?
23 #
24 # Initialises the pkg-config system. Unless required is set to 0,
25 # it is a fatal error if the pkg-config
 
26 # This command will normally be called automatically as required,
27 # but it may be invoked explicitly if lack of pkg-config is acceptable.
28 #
29 # Returns 1 if ok, or 0 if pkg-config not found/usable (only if required=0)
30 #
31 proc pkg-config-init {{required 1}} {
32 if {[is-defined HAVE_PKG_CONFIG]} {
33 return [get-define HAVE_PKG_CONFIG]
34 }
@@ -46,12 +47,12 @@
46 msg-result $version
47 define PKG_CONFIG_VERSION $version
48
49 set found 1
50
51 if {[opt-val sysroot] ne ""} {
52 define SYSROOT [file-normalize [opt-val sysroot]]
53 msg-result "Using specified sysroot [get-define SYSROOT]"
54 } elseif {[get-define build] ne [get-define host]} {
55 if {[catch {exec-with-stderr [get-define CC] -print-sysroot} result errinfo] == 0} {
56 # Use the compiler sysroot, if there is one
57 define SYSROOT $result
@@ -81,21 +82,21 @@
81 return $found
82 }
83
84 # @pkg-config module ?requirements?
85 #
86 # Use pkg-config to find the given module meeting the given requirements.
87 # e.g.
88 #
89 ## pkg-config pango >= 1.37.0
90 #
91 # If found, returns 1 and sets HAVE_PKG_PANGO to 1 along with:
92 #
93 ## PKG_PANGO_VERSION to the found version
94 ## PKG_PANGO_LIBS to the required libs (--libs-only-l)
95 ## PKG_PANGO_LDFLAGS to the required linker flags (--libs-only-L)
96 ## PKG_PANGO_CFLAGS to the required compiler flags (--cflags)
97 #
98 # If not found, returns 0.
99 #
100 proc pkg-config {module args} {
101 set ok [pkg-config-init]
@@ -122,13 +123,13 @@
122 return 1
123 }
124
125 # @pkg-config-get module setting
126 #
127 # Convenience access to the results of pkg-config
128 #
129 # For example, [pkg-config-get pango CFLAGS] returns
130 # the value of PKG_PANGO_CFLAGS, or "" if not defined.
131 proc pkg-config-get {module name} {
132 set prefix [feature-define-name $module PKG_]
133 get-define ${prefix}_${name} ""
134 }
135
--- autosetup/pkg-config.tcl
+++ autosetup/pkg-config.tcl
@@ -1,34 +1,35 @@
1 # Copyright (c) 2016 WorkWare Systems http://www.workware.net.au/
2 # All rights reserved
3
4 # @synopsis:
5 #
6 # The 'pkg-config' module allows package information to be found via 'pkg-config'.
7 #
8 # If not cross-compiling, the package path should be determined automatically
9 # by 'pkg-config'.
10 # If cross-compiling, the default package path is the compiler sysroot.
11 # If the C compiler doesn't support '-print-sysroot', the path can be supplied
12 # by the '--sysroot' option or by defining 'SYSROOT'.
13 #
14 # 'PKG_CONFIG' may be set to use an alternative to 'pkg-config'.
15
16 use cc
17
18 module-options {
19 sysroot:dir => "Override compiler sysroot for pkg-config search path"
20 }
21
22 # @pkg-config-init ?required?
23 #
24 # Initialises the 'pkg-config' system. Unless '$required' is set to 0,
25 # it is a fatal error if a usable 'pkg-config' is not found .
26 #
27 # This command will normally be called automatically as required,
28 # but it may be invoked explicitly if lack of 'pkg-config' is acceptable.
29 #
30 # Returns 1 if ok, or 0 if 'pkg-config' not found/usable (only if '$required' is 0).
31 #
32 proc pkg-config-init {{required 1}} {
33 if {[is-defined HAVE_PKG_CONFIG]} {
34 return [get-define HAVE_PKG_CONFIG]
35 }
@@ -46,12 +47,12 @@
47 msg-result $version
48 define PKG_CONFIG_VERSION $version
49
50 set found 1
51
52 if {[opt-str sysroot o]} {
53 define SYSROOT [file-normalize $o]
54 msg-result "Using specified sysroot [get-define SYSROOT]"
55 } elseif {[get-define build] ne [get-define host]} {
56 if {[catch {exec-with-stderr [get-define CC] -print-sysroot} result errinfo] == 0} {
57 # Use the compiler sysroot, if there is one
58 define SYSROOT $result
@@ -81,21 +82,21 @@
82 return $found
83 }
84
85 # @pkg-config module ?requirements?
86 #
87 # Use 'pkg-config' to find the given module meeting the given requirements.
88 # e.g.
89 #
90 ## pkg-config pango >= 1.37.0
91 #
92 # If found, returns 1 and sets 'HAVE_PKG_PANGO' to 1 along with:
93 #
94 ## PKG_PANGO_VERSION to the found version
95 ## PKG_PANGO_LIBS to the required libs (--libs-only-l)
96 ## PKG_PANGO_LDFLAGS to the required linker flags (--libs-only-L)
97 ## PKG_PANGO_CFLAGS to the required compiler flags (--cflags)
98 #
99 # If not found, returns 0.
100 #
101 proc pkg-config {module args} {
102 set ok [pkg-config-init]
@@ -122,13 +123,13 @@
123 return 1
124 }
125
126 # @pkg-config-get module setting
127 #
128 # Convenience access to the results of 'pkg-config'.
129 #
130 # For example, '[pkg-config-get pango CFLAGS]' returns
131 # the value of 'PKG_PANGO_CFLAGS', or '""' if not defined.
132 proc pkg-config-get {module name} {
133 set prefix [feature-define-name $module PKG_]
134 get-define ${prefix}_${name} ""
135 }
136
--- autosetup/system.tcl
+++ autosetup/system.tcl
@@ -2,35 +2,40 @@
22
# All rights reserved
33
44
# @synopsis:
55
#
66
# This module supports common system interrogation and options
7
-# such as --host, --build, --prefix, and setting srcdir, builddir, and EXEEXT
7
+# such as '--host', '--build', '--prefix', and setting 'srcdir', 'builddir', and 'EXEEXT'.
88
#
9
-# It also support the 'feature' naming convention, where searching
10
-# for a feature such as sys/type.h defines HAVE_SYS_TYPES_H
9
+# It also support the "feature" naming convention, where searching
10
+# for a feature such as 'sys/type.h' defines 'HAVE_SYS_TYPES_H'.
1111
#
12
-# It defines the following variables, based on --prefix unless overridden by the user:
12
+# It defines the following variables, based on '--prefix' unless overridden by the user:
1313
#
1414
## datadir
1515
## sysconfdir
1616
## sharedstatedir
1717
## localstatedir
1818
## infodir
1919
## mandir
2020
## includedir
21
+#
22
+# If '--prefix' is not supplied, it defaults to '/usr/local' unless 'defaultprefix' is defined *before*
23
+# including the 'system' module.
2124
22
-# Do "define defaultprefix myvalue" to set the default prefix *before* the first "use"
23
-set defaultprefix [get-define defaultprefix /usr/local]
25
+if {[is-defined defaultprefix]} {
26
+ user-notice "Note: defaultprefix is deprecated. Use options-defaults to set default options"
27
+ options-defaults [list prefix [get-define defaultprefix]]
28
+}
2429
2530
module-options [subst -noc -nob {
2631
host:host-alias => {a complete or partial cpu-vendor-opsys for the system where
2732
the application will run (defaults to the same value as --build)}
2833
build:build-alias => {a complete or partial cpu-vendor-opsys for the system
2934
where the application will be built (defaults to the
3035
result of running config.guess)}
31
- prefix:dir => {the target directory for the build (defaults to '$defaultprefix')}
36
+ prefix:dir=/usr/local => {the target directory for the build (default: '@default@')}
3237
3338
# These (hidden) options are supported for autoconf/automake compatibility
3439
exec-prefix:
3540
bindir:
3641
sbindir:
@@ -41,16 +46,26 @@
4146
datadir:
4247
libdir:
4348
sysconfdir:
4449
sharedstatedir:
4550
localstatedir:
51
+ runstatedir:
4652
maintainer-mode=0
4753
dependency-tracking=0
54
+ silent-rules=0
4855
}]
4956
50
-# Returns 1 if exists, or 0 if not
57
+# @check-feature name { script }
58
+#
59
+# defines feature '$name' to the return value of '$script',
60
+# which should be 1 if found or 0 if not found.
61
+#
62
+# e.g. the following will define 'HAVE_CONST' to 0 or 1.
5163
#
64
+## check-feature const {
65
+## cctest -code {const int _x = 0;}
66
+## }
5267
proc check-feature {name code} {
5368
msg-checking "Checking for $name..."
5469
set r [uplevel 1 $code]
5570
define-feature $name $r
5671
if {$r} {
@@ -61,49 +76,54 @@
6176
return $r
6277
}
6378
6479
# @have-feature name ?default=0?
6580
#
66
-# Returns the value of the feature if defined, or $default if not.
67
-# See 'feature-define-name' for how the feature name
68
-# is translated into the define name.
81
+# Returns the value of feature '$name' if defined, or '$default' if not.
82
+#
83
+# See 'feature-define-name' for how the "feature" name
84
+# is translated into the "define" name.
6985
#
7086
proc have-feature {name {default 0}} {
7187
get-define [feature-define-name $name] $default
7288
}
7389
7490
# @define-feature name ?value=1?
7591
#
76
-# Sets the feature 'define' to the given value.
77
-# See 'feature-define-name' for how the feature name
78
-# is translated into the define name.
92
+# Sets the feature 'define' to '$value'.
93
+#
94
+# See 'feature-define-name' for how the "feature" name
95
+# is translated into the "define" name.
7996
#
8097
proc define-feature {name {value 1}} {
8198
define [feature-define-name $name] $value
8299
}
83100
84101
# @feature-checked name
85102
#
86
-# Returns 1 if the feature has been checked, whether true or not
103
+# Returns 1 if feature '$name' has been checked, whether true or not.
87104
#
88105
proc feature-checked {name} {
89106
is-defined [feature-define-name $name]
90107
}
91108
92109
# @feature-define-name name ?prefix=HAVE_?
93110
#
94
-# Converts a name to the corresponding define,
95
-# e.g. sys/stat.h becomes HAVE_SYS_STAT_H.
111
+# Converts a "feature" name to the corresponding "define",
112
+# e.g. 'sys/stat.h' becomes 'HAVE_SYS_STAT_H'.
96113
#
97
-# Converts * to P and all non-alphanumeric to underscore.
114
+# Converts '*' to 'P' and all non-alphanumeric to underscore.
98115
#
99116
proc feature-define-name {name {prefix HAVE_}} {
100117
string toupper $prefix[regsub -all {[^a-zA-Z0-9]} [regsub -all {[*]} $name p] _]
101118
}
102119
103
-# If $file doesn't exist, or it's contents are different than $buf,
104
-# the file is written and $script is executed.
120
+# @write-if-changed filename contents ?script?
121
+#
122
+# If '$filename' doesn't exist, or it's contents are different to '$contents',
123
+# the file is written and '$script' is evaluated.
124
+#
105125
# Otherwise a "file is unchanged" message is displayed.
106126
proc write-if-changed {file buf {script {}}} {
107127
set old [readfile $file ""]
108128
if {$old eq $buf && [file exists $file]} {
109129
msg-result "$file is unchanged"
@@ -110,42 +130,142 @@
110130
} else {
111131
writefile $file $buf\n
112132
uplevel 1 $script
113133
}
114134
}
135
+
136
+
137
+# @include-file infile mapping
138
+#
139
+# The core of make-template, called recursively for each @include
140
+# directive found within that template so that this proc's result
141
+# is the fully-expanded template.
142
+#
143
+# The mapping parameter is how we expand @varname@ within the template.
144
+# We do that inline within this step only for @include directives which
145
+# can have variables in the filename arg. A separate substitution pass
146
+# happens when this recursive function returns, expanding the rest of
147
+# the variables.
148
+#
149
+proc include-file {infile mapping} {
150
+ # A stack of true/false conditions, one for each nested conditional
151
+ # starting with "true"
152
+ set condstack {1}
153
+ set result {}
154
+ set linenum 0
155
+ foreach line [split [readfile $infile] \n] {
156
+ incr linenum
157
+ if {[regexp {^@(if|else|endif)(\s*)(.*)} $line -> condtype condspace condargs]} {
158
+ if {$condtype eq "if"} {
159
+ if {[string length $condspace] == 0} {
160
+ autosetup-error "$infile:$linenum: Invalid expression: $line"
161
+ }
162
+ if {[llength $condargs] == 1} {
163
+ # ABC => [get-define ABC] ni {0 ""}
164
+ # !ABC => [get-define ABC] in {0 ""}
165
+ lassign $condargs condvar
166
+ if {[regexp {^!(.*)} $condvar -> condvar]} {
167
+ set op in
168
+ } else {
169
+ set op ni
170
+ }
171
+ set condexpr "\[[list get-define $condvar]\] $op {0 {}}"
172
+ } else {
173
+ # Translate alphanumeric ABC into [get-define ABC] and leave the
174
+ # rest of the expression untouched
175
+ regsub -all {([A-Z][[:alnum:]_]*)} $condargs {[get-define \1]} condexpr
176
+ }
177
+ if {[catch [list expr $condexpr] condval]} {
178
+ dputs $condval
179
+ autosetup-error "$infile:$linenum: Invalid expression: $line"
180
+ }
181
+ dputs "@$condtype: $condexpr => $condval"
182
+ }
183
+ if {$condtype ne "if"} {
184
+ if {[llength $condstack] <= 1} {
185
+ autosetup-error "$infile:$linenum: Error: @$condtype missing @if"
186
+ } elseif {[string length $condargs] && [string index $condargs 0] ne "#"} {
187
+ autosetup-error "$infile:$linenum: Error: Extra arguments after @$condtype"
188
+ }
189
+ }
190
+ switch -exact $condtype {
191
+ if {
192
+ # push condval
193
+ lappend condstack $condval
194
+ }
195
+ else {
196
+ # Toggle the last entry
197
+ set condval [lpop condstack]
198
+ set condval [expr {!$condval}]
199
+ lappend condstack $condval
200
+ }
201
+ endif {
202
+ if {[llength $condstack] == 0} {
203
+ user-notice "$infile:$linenum: Error: @endif missing @if"
204
+ }
205
+ lpop condstack
206
+ }
207
+ }
208
+ continue
209
+ } elseif {[regexp {^@include\s+(.*)} $line -> filearg]} {
210
+ set incfile [string map $mapping $filearg]
211
+ if {[file exists $incfile]} {
212
+ lappend ::autosetup(deps) [file-normalize $incfile]
213
+ lappend result {*}[include-file $incfile $mapping]
214
+ } else {
215
+ user-error "$infile:$linenum: Include file $incfile is missing"
216
+ }
217
+ continue
218
+ } elseif {[regexp {^@define\s+(\w+)\s+(.*)} $line -> var val]} {
219
+ define $var $val
220
+ continue
221
+ }
222
+ # Only output this line if the stack contains all "true"
223
+ if {"0" in $condstack} {
224
+ continue
225
+ }
226
+ lappend result $line
227
+ }
228
+ return $result
229
+}
230
+
115231
116232
# @make-template template ?outfile?
117233
#
118
-# Reads the input file <srcdir>/$template and writes the output file $outfile.
119
-# If $outfile is blank/omitted, $template should end with ".in" which
234
+# Reads the input file '<srcdir>/$template' and writes the output file '$outfile'
235
+# (unless unchanged).
236
+# If '$outfile' is blank/omitted, '$template' should end with '.in' which
120237
# is removed to create the output file name.
121238
#
122
-# Each pattern of the form @define@ is replaced with the corresponding
123
-# define, if it exists, or left unchanged if not.
124
-#
125
-# The special value @srcdir@ is substituted with the relative
239
+# Each pattern of the form '@define@' is replaced with the corresponding
240
+# "define", if it exists, or left unchanged if not.
241
+#
242
+# The special value '@srcdir@' is substituted with the relative
126243
# path to the source directory from the directory where the output
127
-# file is created, while the special value @top_srcdir@ is substituted
244
+# file is created, while the special value '@top_srcdir@' is substituted
128245
# with the relative path to the top level source directory.
129246
#
130247
# Conditional sections may be specified as follows:
131
-## @if name == value
248
+## @if NAME eq "value"
132249
## lines
133250
## @else
134251
## lines
135252
## @endif
136253
#
137
-# Where 'name' is a defined variable name and @else is optional.
254
+# Where 'NAME' is a defined variable name and '@else' is optional.
255
+# Note that variables names *must* start with an uppercase letter.
138256
# If the expression does not match, all lines through '@endif' are ignored.
139257
#
140258
# The alternative forms may also be used:
141
-## @if name
142
-## @if name != value
259
+## @if NAME (true if the variable is defined, but not empty and not "0")
260
+## @if !NAME (opposite of the form above)
261
+## @if <general-tcl-expression>
143262
#
144
-# Where the first form is true if the variable is defined, but not empty or 0
263
+# In the general Tcl expression, any words beginning with an uppercase letter
264
+# are translated into [get-define NAME]
145265
#
146
-# Currently these expressions can't be nested.
266
+# Expressions may be nested
147267
#
148268
proc make-template {template {out {}}} {
149269
set infile [file join $::autosetup(srcdir) $template]
150270
151271
if {![file exists $infile]} {
@@ -169,61 +289,42 @@
169289
170290
# Set up srcdir and top_srcdir to be relative to the target dir
171291
define srcdir [relative-path [file join $::autosetup(srcdir) $outdir] $outdir]
172292
define top_srcdir [relative-path $::autosetup(srcdir) $outdir]
173293
174
- set mapping {}
175
- foreach {n v} [array get ::define] {
176
- lappend mapping @$n@ $v
177
- }
178
- set result {}
179
- foreach line [split [readfile $infile] \n] {
180
- if {[info exists cond]} {
181
- set l [string trimright $line]
182
- if {$l eq "@endif"} {
183
- unset cond
184
- continue
185
- }
186
- if {$l eq "@else"} {
187
- set cond [expr {!$cond}]
188
- continue
189
- }
190
- if {$cond} {
191
- lappend result $line
192
- }
193
- continue
194
- }
195
- if {[regexp {^@if\s+(\w+)(.*)} $line -> name expression]} {
196
- lassign $expression equal value
197
- set varval [get-define $name ""]
198
- if {$equal eq ""} {
199
- set cond [expr {$varval ni {"" 0}}]
200
- } else {
201
- set cond [expr {$varval eq $value}]
202
- if {$equal ne "=="} {
203
- set cond [expr {!$cond}]
204
- }
205
- }
206
- continue
207
- }
208
- lappend result $line
209
- }
210
- write-if-changed $out [string map $mapping [join $result \n]]\n {
211
- msg-result "Created [relative-path $out] from [relative-path $template]"
212
- }
294
+ # Build map from global defines to their values so they can be
295
+ # substituted into @include file names.
296
+ proc build-define-mapping {} {
297
+ set mapping {}
298
+ foreach {n v} [array get ::define] {
299
+ lappend mapping @$n@ $v
300
+ }
301
+ return $mapping
302
+ }
303
+ set mapping [build-define-mapping]
304
+
305
+ set result [include-file $infile $mapping]
306
+
307
+ # Rebuild the define mapping in case we ran across @define
308
+ # directives in the template or a file it @included, then
309
+ # apply that mapping to the expanded template.
310
+ set mapping [build-define-mapping]
311
+ write-if-changed $out [string map $mapping [join $result \n]] {
312
+ msg-result "Created [relative-path $out] from [relative-path $template]"
313
+ }
213314
}
214315
215316
# build/host tuples and cross-compilation prefix
216
-set build [opt-val build]
317
+opt-str build build ""
217318
define build_alias $build
218319
if {$build eq ""} {
219320
define build [config_guess]
220321
} else {
221322
define build [config_sub $build]
222323
}
223324
224
-set host [opt-val host]
325
+opt-str host host ""
225326
define host_alias $host
226327
if {$host eq ""} {
227328
define host [get-define build]
228329
set cross ""
229330
} else {
@@ -230,44 +331,67 @@
230331
define host [config_sub $host]
231332
set cross $host-
232333
}
233334
define cross [get-env CROSS $cross]
234335
235
-set prefix [opt-val prefix $defaultprefix]
336
+# build/host _cpu, _vendor and _os
337
+foreach type {build host} {
338
+ set v [get-define $type]
339
+ if {![regexp {^([^-]+)-([^-]+)-(.*)$} $v -> cpu vendor os]} {
340
+ user-error "Invalid canonical $type: $v"
341
+ }
342
+ define ${type}_cpu $cpu
343
+ define ${type}_vendor $vendor
344
+ define ${type}_os $os
345
+}
346
+
347
+opt-str prefix prefix /usr/local
236348
237349
# These are for compatibility with autoconf
238350
define target [get-define host]
239351
define prefix $prefix
240352
define builddir $autosetup(builddir)
241353
define srcdir $autosetup(srcdir)
242
-# Allow this to come from the environment
243
-define top_srcdir [get-env top_srcdir [get-define srcdir]]
354
+define top_srcdir $autosetup(srcdir)
355
+define abs_top_srcdir [file-normalize $autosetup(srcdir)]
356
+define abs_top_builddir [file-normalize $autosetup(builddir)]
244357
245358
# autoconf supports all of these
246
-set exec_prefix [opt-val exec-prefix $prefix]
247
-define exec_prefix $exec_prefix
359
+define exec_prefix [opt-str exec-prefix exec_prefix $prefix]
248360
foreach {name defpath} {
249361
bindir /bin
250362
sbindir /sbin
251363
libexecdir /libexec
252364
libdir /lib
253365
} {
254
- define $name [opt-val $name $exec_prefix$defpath]
366
+ define $name [opt-str $name o $exec_prefix$defpath]
255367
}
256368
foreach {name defpath} {
257369
datadir /share
258
- sysconfdir /etc
259370
sharedstatedir /com
260
- localstatedir /var
261371
infodir /share/info
262372
mandir /share/man
263373
includedir /include
264374
} {
265
- define $name [opt-val $name $prefix$defpath]
375
+ define $name [opt-str $name o $prefix$defpath]
376
+}
377
+if {$prefix ne {/usr}} {
378
+ opt-str sysconfdir sysconfdir $prefix/etc
379
+} else {
380
+ opt-str sysconfdir sysconfdir /etc
266381
}
382
+define sysconfdir $sysconfdir
383
+
384
+define localstatedir [opt-str localstatedir o /var]
385
+define runstatedir [opt-str runstatedir o /run]
267386
268387
define SHELL [get-env SHELL [find-an-executable sh bash ksh]]
388
+
389
+# These could be used to generate Makefiles following some automake conventions
390
+define AM_SILENT_RULES [opt-bool silent-rules]
391
+define AM_MAINTAINER_MODE [opt-bool maintainer-mode]
392
+define AM_DEPENDENCY_TRACKING [opt-bool dependency-tracking]
269393
270394
# Windows vs. non-Windows
271395
switch -glob -- [get-define host] {
272396
*-*-ming* - *-*-cygwin - *-*-msys {
273397
define-feature windows
274398
275399
DELETED autosetup/test-tclsh
--- autosetup/system.tcl
+++ autosetup/system.tcl
@@ -2,35 +2,40 @@
2 # All rights reserved
3
4 # @synopsis:
5 #
6 # This module supports common system interrogation and options
7 # such as --host, --build, --prefix, and setting srcdir, builddir, and EXEEXT
8 #
9 # It also support the 'feature' naming convention, where searching
10 # for a feature such as sys/type.h defines HAVE_SYS_TYPES_H
11 #
12 # It defines the following variables, based on --prefix unless overridden by the user:
13 #
14 ## datadir
15 ## sysconfdir
16 ## sharedstatedir
17 ## localstatedir
18 ## infodir
19 ## mandir
20 ## includedir
 
 
 
21
22 # Do "define defaultprefix myvalue" to set the default prefix *before* the first "use"
23 set defaultprefix [get-define defaultprefix /usr/local]
 
 
24
25 module-options [subst -noc -nob {
26 host:host-alias => {a complete or partial cpu-vendor-opsys for the system where
27 the application will run (defaults to the same value as --build)}
28 build:build-alias => {a complete or partial cpu-vendor-opsys for the system
29 where the application will be built (defaults to the
30 result of running config.guess)}
31 prefix:dir => {the target directory for the build (defaults to '$defaultprefix')}
32
33 # These (hidden) options are supported for autoconf/automake compatibility
34 exec-prefix:
35 bindir:
36 sbindir:
@@ -41,16 +46,26 @@
41 datadir:
42 libdir:
43 sysconfdir:
44 sharedstatedir:
45 localstatedir:
 
46 maintainer-mode=0
47 dependency-tracking=0
 
48 }]
49
50 # Returns 1 if exists, or 0 if not
 
 
 
 
 
51 #
 
 
 
52 proc check-feature {name code} {
53 msg-checking "Checking for $name..."
54 set r [uplevel 1 $code]
55 define-feature $name $r
56 if {$r} {
@@ -61,49 +76,54 @@
61 return $r
62 }
63
64 # @have-feature name ?default=0?
65 #
66 # Returns the value of the feature if defined, or $default if not.
67 # See 'feature-define-name' for how the feature name
68 # is translated into the define name.
 
69 #
70 proc have-feature {name {default 0}} {
71 get-define [feature-define-name $name] $default
72 }
73
74 # @define-feature name ?value=1?
75 #
76 # Sets the feature 'define' to the given value.
77 # See 'feature-define-name' for how the feature name
78 # is translated into the define name.
 
79 #
80 proc define-feature {name {value 1}} {
81 define [feature-define-name $name] $value
82 }
83
84 # @feature-checked name
85 #
86 # Returns 1 if the feature has been checked, whether true or not
87 #
88 proc feature-checked {name} {
89 is-defined [feature-define-name $name]
90 }
91
92 # @feature-define-name name ?prefix=HAVE_?
93 #
94 # Converts a name to the corresponding define,
95 # e.g. sys/stat.h becomes HAVE_SYS_STAT_H.
96 #
97 # Converts * to P and all non-alphanumeric to underscore.
98 #
99 proc feature-define-name {name {prefix HAVE_}} {
100 string toupper $prefix[regsub -all {[^a-zA-Z0-9]} [regsub -all {[*]} $name p] _]
101 }
102
103 # If $file doesn't exist, or it's contents are different than $buf,
104 # the file is written and $script is executed.
 
 
 
105 # Otherwise a "file is unchanged" message is displayed.
106 proc write-if-changed {file buf {script {}}} {
107 set old [readfile $file ""]
108 if {$old eq $buf && [file exists $file]} {
109 msg-result "$file is unchanged"
@@ -110,42 +130,142 @@
110 } else {
111 writefile $file $buf\n
112 uplevel 1 $script
113 }
114 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
115
116 # @make-template template ?outfile?
117 #
118 # Reads the input file <srcdir>/$template and writes the output file $outfile.
119 # If $outfile is blank/omitted, $template should end with ".in" which
 
120 # is removed to create the output file name.
121 #
122 # Each pattern of the form @define@ is replaced with the corresponding
123 # define, if it exists, or left unchanged if not.
124 #
125 # The special value @srcdir@ is substituted with the relative
126 # path to the source directory from the directory where the output
127 # file is created, while the special value @top_srcdir@ is substituted
128 # with the relative path to the top level source directory.
129 #
130 # Conditional sections may be specified as follows:
131 ## @if name == value
132 ## lines
133 ## @else
134 ## lines
135 ## @endif
136 #
137 # Where 'name' is a defined variable name and @else is optional.
 
138 # If the expression does not match, all lines through '@endif' are ignored.
139 #
140 # The alternative forms may also be used:
141 ## @if name
142 ## @if name != value
 
143 #
144 # Where the first form is true if the variable is defined, but not empty or 0
 
145 #
146 # Currently these expressions can't be nested.
147 #
148 proc make-template {template {out {}}} {
149 set infile [file join $::autosetup(srcdir) $template]
150
151 if {![file exists $infile]} {
@@ -169,61 +289,42 @@
169
170 # Set up srcdir and top_srcdir to be relative to the target dir
171 define srcdir [relative-path [file join $::autosetup(srcdir) $outdir] $outdir]
172 define top_srcdir [relative-path $::autosetup(srcdir) $outdir]
173
174 set mapping {}
175 foreach {n v} [array get ::define] {
176 lappend mapping @$n@ $v
177 }
178 set result {}
179 foreach line [split [readfile $infile] \n] {
180 if {[info exists cond]} {
181 set l [string trimright $line]
182 if {$l eq "@endif"} {
183 unset cond
184 continue
185 }
186 if {$l eq "@else"} {
187 set cond [expr {!$cond}]
188 continue
189 }
190 if {$cond} {
191 lappend result $line
192 }
193 continue
194 }
195 if {[regexp {^@if\s+(\w+)(.*)} $line -> name expression]} {
196 lassign $expression equal value
197 set varval [get-define $name ""]
198 if {$equal eq ""} {
199 set cond [expr {$varval ni {"" 0}}]
200 } else {
201 set cond [expr {$varval eq $value}]
202 if {$equal ne "=="} {
203 set cond [expr {!$cond}]
204 }
205 }
206 continue
207 }
208 lappend result $line
209 }
210 write-if-changed $out [string map $mapping [join $result \n]]\n {
211 msg-result "Created [relative-path $out] from [relative-path $template]"
212 }
213 }
214
215 # build/host tuples and cross-compilation prefix
216 set build [opt-val build]
217 define build_alias $build
218 if {$build eq ""} {
219 define build [config_guess]
220 } else {
221 define build [config_sub $build]
222 }
223
224 set host [opt-val host]
225 define host_alias $host
226 if {$host eq ""} {
227 define host [get-define build]
228 set cross ""
229 } else {
@@ -230,44 +331,67 @@
230 define host [config_sub $host]
231 set cross $host-
232 }
233 define cross [get-env CROSS $cross]
234
235 set prefix [opt-val prefix $defaultprefix]
 
 
 
 
 
 
 
 
 
 
 
236
237 # These are for compatibility with autoconf
238 define target [get-define host]
239 define prefix $prefix
240 define builddir $autosetup(builddir)
241 define srcdir $autosetup(srcdir)
242 # Allow this to come from the environment
243 define top_srcdir [get-env top_srcdir [get-define srcdir]]
 
244
245 # autoconf supports all of these
246 set exec_prefix [opt-val exec-prefix $prefix]
247 define exec_prefix $exec_prefix
248 foreach {name defpath} {
249 bindir /bin
250 sbindir /sbin
251 libexecdir /libexec
252 libdir /lib
253 } {
254 define $name [opt-val $name $exec_prefix$defpath]
255 }
256 foreach {name defpath} {
257 datadir /share
258 sysconfdir /etc
259 sharedstatedir /com
260 localstatedir /var
261 infodir /share/info
262 mandir /share/man
263 includedir /include
264 } {
265 define $name [opt-val $name $prefix$defpath]
 
 
 
 
 
266 }
 
 
 
 
267
268 define SHELL [get-env SHELL [find-an-executable sh bash ksh]]
 
 
 
 
 
269
270 # Windows vs. non-Windows
271 switch -glob -- [get-define host] {
272 *-*-ming* - *-*-cygwin - *-*-msys {
273 define-feature windows
274
275 ELETED autosetup/test-tclsh
--- autosetup/system.tcl
+++ autosetup/system.tcl
@@ -2,35 +2,40 @@
2 # All rights reserved
3
4 # @synopsis:
5 #
6 # This module supports common system interrogation and options
7 # such as '--host', '--build', '--prefix', and setting 'srcdir', 'builddir', and 'EXEEXT'.
8 #
9 # It also support the "feature" naming convention, where searching
10 # for a feature such as 'sys/type.h' defines 'HAVE_SYS_TYPES_H'.
11 #
12 # It defines the following variables, based on '--prefix' unless overridden by the user:
13 #
14 ## datadir
15 ## sysconfdir
16 ## sharedstatedir
17 ## localstatedir
18 ## infodir
19 ## mandir
20 ## includedir
21 #
22 # If '--prefix' is not supplied, it defaults to '/usr/local' unless 'defaultprefix' is defined *before*
23 # including the 'system' module.
24
25 if {[is-defined defaultprefix]} {
26 user-notice "Note: defaultprefix is deprecated. Use options-defaults to set default options"
27 options-defaults [list prefix [get-define defaultprefix]]
28 }
29
30 module-options [subst -noc -nob {
31 host:host-alias => {a complete or partial cpu-vendor-opsys for the system where
32 the application will run (defaults to the same value as --build)}
33 build:build-alias => {a complete or partial cpu-vendor-opsys for the system
34 where the application will be built (defaults to the
35 result of running config.guess)}
36 prefix:dir=/usr/local => {the target directory for the build (default: '@default@')}
37
38 # These (hidden) options are supported for autoconf/automake compatibility
39 exec-prefix:
40 bindir:
41 sbindir:
@@ -41,16 +46,26 @@
46 datadir:
47 libdir:
48 sysconfdir:
49 sharedstatedir:
50 localstatedir:
51 runstatedir:
52 maintainer-mode=0
53 dependency-tracking=0
54 silent-rules=0
55 }]
56
57 # @check-feature name { script }
58 #
59 # defines feature '$name' to the return value of '$script',
60 # which should be 1 if found or 0 if not found.
61 #
62 # e.g. the following will define 'HAVE_CONST' to 0 or 1.
63 #
64 ## check-feature const {
65 ## cctest -code {const int _x = 0;}
66 ## }
67 proc check-feature {name code} {
68 msg-checking "Checking for $name..."
69 set r [uplevel 1 $code]
70 define-feature $name $r
71 if {$r} {
@@ -61,49 +76,54 @@
76 return $r
77 }
78
79 # @have-feature name ?default=0?
80 #
81 # Returns the value of feature '$name' if defined, or '$default' if not.
82 #
83 # See 'feature-define-name' for how the "feature" name
84 # is translated into the "define" name.
85 #
86 proc have-feature {name {default 0}} {
87 get-define [feature-define-name $name] $default
88 }
89
90 # @define-feature name ?value=1?
91 #
92 # Sets the feature 'define' to '$value'.
93 #
94 # See 'feature-define-name' for how the "feature" name
95 # is translated into the "define" name.
96 #
97 proc define-feature {name {value 1}} {
98 define [feature-define-name $name] $value
99 }
100
101 # @feature-checked name
102 #
103 # Returns 1 if feature '$name' has been checked, whether true or not.
104 #
105 proc feature-checked {name} {
106 is-defined [feature-define-name $name]
107 }
108
109 # @feature-define-name name ?prefix=HAVE_?
110 #
111 # Converts a "feature" name to the corresponding "define",
112 # e.g. 'sys/stat.h' becomes 'HAVE_SYS_STAT_H'.
113 #
114 # Converts '*' to 'P' and all non-alphanumeric to underscore.
115 #
116 proc feature-define-name {name {prefix HAVE_}} {
117 string toupper $prefix[regsub -all {[^a-zA-Z0-9]} [regsub -all {[*]} $name p] _]
118 }
119
120 # @write-if-changed filename contents ?script?
121 #
122 # If '$filename' doesn't exist, or it's contents are different to '$contents',
123 # the file is written and '$script' is evaluated.
124 #
125 # Otherwise a "file is unchanged" message is displayed.
126 proc write-if-changed {file buf {script {}}} {
127 set old [readfile $file ""]
128 if {$old eq $buf && [file exists $file]} {
129 msg-result "$file is unchanged"
@@ -110,42 +130,142 @@
130 } else {
131 writefile $file $buf\n
132 uplevel 1 $script
133 }
134 }
135
136
137 # @include-file infile mapping
138 #
139 # The core of make-template, called recursively for each @include
140 # directive found within that template so that this proc's result
141 # is the fully-expanded template.
142 #
143 # The mapping parameter is how we expand @varname@ within the template.
144 # We do that inline within this step only for @include directives which
145 # can have variables in the filename arg. A separate substitution pass
146 # happens when this recursive function returns, expanding the rest of
147 # the variables.
148 #
149 proc include-file {infile mapping} {
150 # A stack of true/false conditions, one for each nested conditional
151 # starting with "true"
152 set condstack {1}
153 set result {}
154 set linenum 0
155 foreach line [split [readfile $infile] \n] {
156 incr linenum
157 if {[regexp {^@(if|else|endif)(\s*)(.*)} $line -> condtype condspace condargs]} {
158 if {$condtype eq "if"} {
159 if {[string length $condspace] == 0} {
160 autosetup-error "$infile:$linenum: Invalid expression: $line"
161 }
162 if {[llength $condargs] == 1} {
163 # ABC => [get-define ABC] ni {0 ""}
164 # !ABC => [get-define ABC] in {0 ""}
165 lassign $condargs condvar
166 if {[regexp {^!(.*)} $condvar -> condvar]} {
167 set op in
168 } else {
169 set op ni
170 }
171 set condexpr "\[[list get-define $condvar]\] $op {0 {}}"
172 } else {
173 # Translate alphanumeric ABC into [get-define ABC] and leave the
174 # rest of the expression untouched
175 regsub -all {([A-Z][[:alnum:]_]*)} $condargs {[get-define \1]} condexpr
176 }
177 if {[catch [list expr $condexpr] condval]} {
178 dputs $condval
179 autosetup-error "$infile:$linenum: Invalid expression: $line"
180 }
181 dputs "@$condtype: $condexpr => $condval"
182 }
183 if {$condtype ne "if"} {
184 if {[llength $condstack] <= 1} {
185 autosetup-error "$infile:$linenum: Error: @$condtype missing @if"
186 } elseif {[string length $condargs] && [string index $condargs 0] ne "#"} {
187 autosetup-error "$infile:$linenum: Error: Extra arguments after @$condtype"
188 }
189 }
190 switch -exact $condtype {
191 if {
192 # push condval
193 lappend condstack $condval
194 }
195 else {
196 # Toggle the last entry
197 set condval [lpop condstack]
198 set condval [expr {!$condval}]
199 lappend condstack $condval
200 }
201 endif {
202 if {[llength $condstack] == 0} {
203 user-notice "$infile:$linenum: Error: @endif missing @if"
204 }
205 lpop condstack
206 }
207 }
208 continue
209 } elseif {[regexp {^@include\s+(.*)} $line -> filearg]} {
210 set incfile [string map $mapping $filearg]
211 if {[file exists $incfile]} {
212 lappend ::autosetup(deps) [file-normalize $incfile]
213 lappend result {*}[include-file $incfile $mapping]
214 } else {
215 user-error "$infile:$linenum: Include file $incfile is missing"
216 }
217 continue
218 } elseif {[regexp {^@define\s+(\w+)\s+(.*)} $line -> var val]} {
219 define $var $val
220 continue
221 }
222 # Only output this line if the stack contains all "true"
223 if {"0" in $condstack} {
224 continue
225 }
226 lappend result $line
227 }
228 return $result
229 }
230
231
232 # @make-template template ?outfile?
233 #
234 # Reads the input file '<srcdir>/$template' and writes the output file '$outfile'
235 # (unless unchanged).
236 # If '$outfile' is blank/omitted, '$template' should end with '.in' which
237 # is removed to create the output file name.
238 #
239 # Each pattern of the form '@define@' is replaced with the corresponding
240 # "define", if it exists, or left unchanged if not.
241 #
242 # The special value '@srcdir@' is substituted with the relative
243 # path to the source directory from the directory where the output
244 # file is created, while the special value '@top_srcdir@' is substituted
245 # with the relative path to the top level source directory.
246 #
247 # Conditional sections may be specified as follows:
248 ## @if NAME eq "value"
249 ## lines
250 ## @else
251 ## lines
252 ## @endif
253 #
254 # Where 'NAME' is a defined variable name and '@else' is optional.
255 # Note that variables names *must* start with an uppercase letter.
256 # If the expression does not match, all lines through '@endif' are ignored.
257 #
258 # The alternative forms may also be used:
259 ## @if NAME (true if the variable is defined, but not empty and not "0")
260 ## @if !NAME (opposite of the form above)
261 ## @if <general-tcl-expression>
262 #
263 # In the general Tcl expression, any words beginning with an uppercase letter
264 # are translated into [get-define NAME]
265 #
266 # Expressions may be nested
267 #
268 proc make-template {template {out {}}} {
269 set infile [file join $::autosetup(srcdir) $template]
270
271 if {![file exists $infile]} {
@@ -169,61 +289,42 @@
289
290 # Set up srcdir and top_srcdir to be relative to the target dir
291 define srcdir [relative-path [file join $::autosetup(srcdir) $outdir] $outdir]
292 define top_srcdir [relative-path $::autosetup(srcdir) $outdir]
293
294 # Build map from global defines to their values so they can be
295 # substituted into @include file names.
296 proc build-define-mapping {} {
297 set mapping {}
298 foreach {n v} [array get ::define] {
299 lappend mapping @$n@ $v
300 }
301 return $mapping
302 }
303 set mapping [build-define-mapping]
304
305 set result [include-file $infile $mapping]
306
307 # Rebuild the define mapping in case we ran across @define
308 # directives in the template or a file it @included, then
309 # apply that mapping to the expanded template.
310 set mapping [build-define-mapping]
311 write-if-changed $out [string map $mapping [join $result \n]] {
312 msg-result "Created [relative-path $out] from [relative-path $template]"
313 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
314 }
315
316 # build/host tuples and cross-compilation prefix
317 opt-str build build ""
318 define build_alias $build
319 if {$build eq ""} {
320 define build [config_guess]
321 } else {
322 define build [config_sub $build]
323 }
324
325 opt-str host host ""
326 define host_alias $host
327 if {$host eq ""} {
328 define host [get-define build]
329 set cross ""
330 } else {
@@ -230,44 +331,67 @@
331 define host [config_sub $host]
332 set cross $host-
333 }
334 define cross [get-env CROSS $cross]
335
336 # build/host _cpu, _vendor and _os
337 foreach type {build host} {
338 set v [get-define $type]
339 if {![regexp {^([^-]+)-([^-]+)-(.*)$} $v -> cpu vendor os]} {
340 user-error "Invalid canonical $type: $v"
341 }
342 define ${type}_cpu $cpu
343 define ${type}_vendor $vendor
344 define ${type}_os $os
345 }
346
347 opt-str prefix prefix /usr/local
348
349 # These are for compatibility with autoconf
350 define target [get-define host]
351 define prefix $prefix
352 define builddir $autosetup(builddir)
353 define srcdir $autosetup(srcdir)
354 define top_srcdir $autosetup(srcdir)
355 define abs_top_srcdir [file-normalize $autosetup(srcdir)]
356 define abs_top_builddir [file-normalize $autosetup(builddir)]
357
358 # autoconf supports all of these
359 define exec_prefix [opt-str exec-prefix exec_prefix $prefix]
 
360 foreach {name defpath} {
361 bindir /bin
362 sbindir /sbin
363 libexecdir /libexec
364 libdir /lib
365 } {
366 define $name [opt-str $name o $exec_prefix$defpath]
367 }
368 foreach {name defpath} {
369 datadir /share
 
370 sharedstatedir /com
 
371 infodir /share/info
372 mandir /share/man
373 includedir /include
374 } {
375 define $name [opt-str $name o $prefix$defpath]
376 }
377 if {$prefix ne {/usr}} {
378 opt-str sysconfdir sysconfdir $prefix/etc
379 } else {
380 opt-str sysconfdir sysconfdir /etc
381 }
382 define sysconfdir $sysconfdir
383
384 define localstatedir [opt-str localstatedir o /var]
385 define runstatedir [opt-str runstatedir o /run]
386
387 define SHELL [get-env SHELL [find-an-executable sh bash ksh]]
388
389 # These could be used to generate Makefiles following some automake conventions
390 define AM_SILENT_RULES [opt-bool silent-rules]
391 define AM_MAINTAINER_MODE [opt-bool maintainer-mode]
392 define AM_DEPENDENCY_TRACKING [opt-bool dependency-tracking]
393
394 # Windows vs. non-Windows
395 switch -glob -- [get-define host] {
396 *-*-ming* - *-*-cygwin - *-*-msys {
397 define-feature windows
398
399 ELETED autosetup/test-tclsh
D autosetup/test-tclsh
-20
--- a/autosetup/test-tclsh
+++ b/autosetup/test-tclsh
@@ -1,20 +0,0 @@
1
-# A small Tcl script to verify that the chosen
2
-# interpreter works. Sometimes we might e.g. pick up
3
-# an interpreter for a different arch.
4
-# Outputs the full path to the interpreter
5
-
6
-if {[catch {info version} version] == 0} {
7
- # This is Jim Tcl
8
- if {$version >= 0.72} {
9
- # Ensure that regexp works
10
- regexp (a.*?) a
11
- puts [info nameofexecutable]
12
- exit 0
13
- }
14
-} elseif {[catch {info tclversion} version] == 0} {
15
- if {$version >= 8.5 && ![string match 8.5a* [info patchlevel]]} {
16
- puts [info nameofexecutable]
17
- exit 0
18
- }
19
-}
20
-exit 1
--- a/autosetup/test-tclsh
+++ b/autosetup/test-tclsh
@@ -1,20 +0,0 @@
1 # A small Tcl script to verify that the chosen
2 # interpreter works. Sometimes we might e.g. pick up
3 # an interpreter for a different arch.
4 # Outputs the full path to the interpreter
5
6 if {[catch {info version} version] == 0} {
7 # This is Jim Tcl
8 if {$version >= 0.72} {
9 # Ensure that regexp works
10 regexp (a.*?) a
11 puts [info nameofexecutable]
12 exit 0
13 }
14 } elseif {[catch {info tclversion} version] == 0} {
15 if {$version >= 8.5 && ![string match 8.5a* [info patchlevel]]} {
16 puts [info nameofexecutable]
17 exit 0
18 }
19 }
20 exit 1
--- a/autosetup/test-tclsh
+++ b/autosetup/test-tclsh
@@ -1,20 +0,0 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
--- autosetup/tmake.auto
+++ autosetup/tmake.auto
@@ -21,45 +21,34 @@
2121
cc-check-tools ar ranlib
2222
2323
set objdir [get-env BUILDDIR objdir]
2424
2525
make-config-header $objdir/include/autoconf.h
26
-make-tmake-settings $objdir/settings.conf {[A-Z]*}
26
+make-tmake-settings $objdir/settings.conf {[A-Z]*} *dir lib_*
2727
}
2828
2929
autosetup_check_create project.spec \
3030
{# Initial project.spec created by 'autosetup --init=tmake'
31
+
32
+tmake-require-version 0.7.3
3133
3234
# vim:set syntax=tcl:
3335
define? DESTDIR _install
3436
3537
# XXX If configure creates additional/different files than include/autoconf.h
3638
# that should be reflected here
37
-
38
-# We use [set AUTOREMAKE] here to avoid rebuilding settings.conf
39
-# if the AUTOREMAKE command changes
40
-Depends {settings.conf include/autoconf.h} auto.def -msg {note Configuring...} -do {
41
- run [set AUTOREMAKE] >$build/config.out
42
-} -onerror {puts [readfile $build/config.out]} -fatal
43
-Clean config.out
44
-DistClean --source config.log
45
-DistClean settings.conf include/autoconf.h
46
-
47
-# If not configured, configure with default options
48
-# Note that it is expected that configure will normally be run
49
-# separately. This is just a convenience for a host build
50
-define? AUTOREMAKE configure TOPBUILDDIR=$TOPBUILDDIR --conf=auto.def
51
-
52
-Load settings.conf
53
-
54
-# e.g. for up autoconf.h
39
+Autosetup include/autoconf.h
40
+
41
+# e.g. for autoconf.h
5542
IncludePaths include
5643
57
-ifconfig CONFIGURED
58
-
59
-# Hmmm, but should we turn off AutoSubDirs?
60
-#AutoSubDirs off
44
+ifconfig !CONFIGURED {
45
+ # Not configured, so don't process subdirs
46
+ AutoSubDirs off
47
+ # And don't process this file any further
48
+ ifconfig false
49
+}
6150
}
6251
6352
if {![file exists build.spec]} {
6453
puts "Note: I don't see build.spec. Try running: tmake --genie"
6554
}
6655
--- autosetup/tmake.auto
+++ autosetup/tmake.auto
@@ -21,45 +21,34 @@
21 cc-check-tools ar ranlib
22
23 set objdir [get-env BUILDDIR objdir]
24
25 make-config-header $objdir/include/autoconf.h
26 make-tmake-settings $objdir/settings.conf {[A-Z]*}
27 }
28
29 autosetup_check_create project.spec \
30 {# Initial project.spec created by 'autosetup --init=tmake'
 
 
31
32 # vim:set syntax=tcl:
33 define? DESTDIR _install
34
35 # XXX If configure creates additional/different files than include/autoconf.h
36 # that should be reflected here
37
38 # We use [set AUTOREMAKE] here to avoid rebuilding settings.conf
39 # if the AUTOREMAKE command changes
40 Depends {settings.conf include/autoconf.h} auto.def -msg {note Configuring...} -do {
41 run [set AUTOREMAKE] >$build/config.out
42 } -onerror {puts [readfile $build/config.out]} -fatal
43 Clean config.out
44 DistClean --source config.log
45 DistClean settings.conf include/autoconf.h
46
47 # If not configured, configure with default options
48 # Note that it is expected that configure will normally be run
49 # separately. This is just a convenience for a host build
50 define? AUTOREMAKE configure TOPBUILDDIR=$TOPBUILDDIR --conf=auto.def
51
52 Load settings.conf
53
54 # e.g. for up autoconf.h
55 IncludePaths include
56
57 ifconfig CONFIGURED
58
59 # Hmmm, but should we turn off AutoSubDirs?
60 #AutoSubDirs off
 
 
61 }
62
63 if {![file exists build.spec]} {
64 puts "Note: I don't see build.spec. Try running: tmake --genie"
65 }
66
--- autosetup/tmake.auto
+++ autosetup/tmake.auto
@@ -21,45 +21,34 @@
21 cc-check-tools ar ranlib
22
23 set objdir [get-env BUILDDIR objdir]
24
25 make-config-header $objdir/include/autoconf.h
26 make-tmake-settings $objdir/settings.conf {[A-Z]*} *dir lib_*
27 }
28
29 autosetup_check_create project.spec \
30 {# Initial project.spec created by 'autosetup --init=tmake'
31
32 tmake-require-version 0.7.3
33
34 # vim:set syntax=tcl:
35 define? DESTDIR _install
36
37 # XXX If configure creates additional/different files than include/autoconf.h
38 # that should be reflected here
39 Autosetup include/autoconf.h
40
41 # e.g. for autoconf.h
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
42 IncludePaths include
43
44 ifconfig !CONFIGURED {
45 # Not configured, so don't process subdirs
46 AutoSubDirs off
47 # And don't process this file any further
48 ifconfig false
49 }
50 }
51
52 if {![file exists build.spec]} {
53 puts "Note: I don't see build.spec. Try running: tmake --genie"
54 }
55
--- autosetup/tmake.tcl
+++ autosetup/tmake.tcl
@@ -15,21 +15,21 @@
1515
1616
define CONFIGURED
1717
1818
# @make-tmake-settings outfile patterns ...
1919
#
20
-# Examines all defined variables which match the given patterns (defaults to "*")
20
+# Examines all defined variables which match the given patterns (defaults to '*')
2121
# and writes a tmake-compatible .conf file defining those variables.
22
-# For example, if ABC is "3 monkeys" and ABC matches a pattern, then the file will include:
22
+# For example, if 'ABC' is '"3 monkeys"' and 'ABC' matches a pattern, then the file will include:
2323
#
2424
## define ABC {3 monkeys}
2525
#
2626
# If the file would be unchanged, it is not written.
2727
#
2828
# Typical usage is:
2929
#
30
-# make-tmake-settings [get-env BUILDDIR objdir]/settings.conf {[A-Z]*}
30
+## make-tmake-settings [get-env BUILDDIR objdir]/settings.conf {[A-Z]*}
3131
proc make-tmake-settings {file args} {
3232
file mkdir [file dirname $file]
3333
set lines {}
3434
3535
if {[llength $args] == 0} {
3636
--- autosetup/tmake.tcl
+++ autosetup/tmake.tcl
@@ -15,21 +15,21 @@
15
16 define CONFIGURED
17
18 # @make-tmake-settings outfile patterns ...
19 #
20 # Examines all defined variables which match the given patterns (defaults to "*")
21 # and writes a tmake-compatible .conf file defining those variables.
22 # For example, if ABC is "3 monkeys" and ABC matches a pattern, then the file will include:
23 #
24 ## define ABC {3 monkeys}
25 #
26 # If the file would be unchanged, it is not written.
27 #
28 # Typical usage is:
29 #
30 # make-tmake-settings [get-env BUILDDIR objdir]/settings.conf {[A-Z]*}
31 proc make-tmake-settings {file args} {
32 file mkdir [file dirname $file]
33 set lines {}
34
35 if {[llength $args] == 0} {
36
--- autosetup/tmake.tcl
+++ autosetup/tmake.tcl
@@ -15,21 +15,21 @@
15
16 define CONFIGURED
17
18 # @make-tmake-settings outfile patterns ...
19 #
20 # Examines all defined variables which match the given patterns (defaults to '*')
21 # and writes a tmake-compatible .conf file defining those variables.
22 # For example, if 'ABC' is '"3 monkeys"' and 'ABC' matches a pattern, then the file will include:
23 #
24 ## define ABC {3 monkeys}
25 #
26 # If the file would be unchanged, it is not written.
27 #
28 # Typical usage is:
29 #
30 ## make-tmake-settings [get-env BUILDDIR objdir]/settings.conf {[A-Z]*}
31 proc make-tmake-settings {file args} {
32 file mkdir [file dirname $file]
33 set lines {}
34
35 if {[llength $args] == 0} {
36
+1 -1
--- configure
+++ configure
@@ -1,3 +1,3 @@
11
#!/bin/sh
22
dir="`dirname "$0"`/autosetup"
3
-WRAPPER="$0"; export WRAPPER; exec "`$dir/find-tclsh`" "$dir/autosetup" "$@"
3
+WRAPPER="$0"; export WRAPPER; exec "`"$dir/autosetup-find-tclsh"`" "$dir/autosetup" "$@"
44
--- configure
+++ configure
@@ -1,3 +1,3 @@
1 #!/bin/sh
2 dir="`dirname "$0"`/autosetup"
3 WRAPPER="$0"; export WRAPPER; exec "`$dir/find-tclsh`" "$dir/autosetup" "$@"
4
--- configure
+++ configure
@@ -1,3 +1,3 @@
1 #!/bin/sh
2 dir="`dirname "$0"`/autosetup"
3 WRAPPER="$0"; export WRAPPER; exec "`"$dir/autosetup-find-tclsh"`" "$dir/autosetup" "$@"
4

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button