Skip to content

Commit 7f63290

Browse files
committed
Modernising the safe base for 9.1
1 parent 42b42ca commit 7f63290

File tree

1 file changed

+83
-103
lines changed

1 file changed

+83
-103
lines changed

library/safe.tcl

Lines changed: 83 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,9 @@ namespace eval ::safe {
3232
# Helper function to resolve the dual way of specifying staticsok (either
3333
# by -noStatics or -statics 0)
3434
proc ::safe::InterpStatics {} {
35-
foreach v {Args statics noStatics} {
36-
upvar $v $v
37-
}
38-
set flag [::tcl::OptProcArgGiven -noStatics]
39-
if {$flag && (!$noStatics == !$statics)
40-
&& ([::tcl::OptProcArgGiven -statics])} {
35+
upvar 1 Args Args statics statics noStatics noStatics
36+
set flag [expr {"-noStatics" in $Args}]
37+
if {$flag && (!$noStatics == !$statics) && ("-statics" in $Args)} {
4138
return -code error\
4239
"conflicting values given for -statics and -noStatics"
4340
}
@@ -51,14 +48,11 @@ proc ::safe::InterpStatics {} {
5148
# Helper function to resolve the dual way of specifying nested loading
5249
# (either by -nestedLoadOk or -nested 1)
5350
proc ::safe::InterpNested {} {
54-
foreach v {Args nested nestedLoadOk} {
55-
upvar $v $v
56-
}
57-
set flag [::tcl::OptProcArgGiven -nestedLoadOk]
51+
upvar 1 Args Args nested nested nestedLoadOk nestedLoadOk
52+
set flag [expr {"-nestedLoadOk" in $Args}]
5853
# note that the test here is the opposite of the "InterpStatics" one
5954
# (it is not -noNested... because of the wanted default value)
60-
if {$flag && (!$nestedLoadOk != !$nested)
61-
&& ([::tcl::OptProcArgGiven -nested])} {
55+
if {$flag && (!$nestedLoadOk != !$nested) && ("-nested" in $Args)} {
6256
return -code error\
6357
"conflicting values given for -nested and -nestedLoadOk"
6458
}
@@ -85,7 +79,7 @@ proc ::safe::interpCreate {args} {
8579
set Args [::tcl::OptKeyParse ::safe::interpCreate $args]
8680
RejectExcessColons $child
8781

88-
set withAutoPath [::tcl::OptProcArgGiven -autoPath]
82+
set withAutoPath [expr {"-autoPath" in $Args}]
8983
InterpCreate $child $accessPath \
9084
[InterpStatics] [InterpNested] $deleteHook $autoPath $withAutoPath
9185
}
@@ -101,7 +95,7 @@ proc ::safe::interpInit {args} {
10195
}
10296
RejectExcessColons $child
10397

104-
set withAutoPath [::tcl::OptProcArgGiven -autoPath]
98+
set withAutoPath [expr {"-autoPath" in $Args}]
10599
InterpInit $child $accessPath \
106100
[InterpStatics] [InterpNested] $deleteHook $autoPath $withAutoPath
107101
}
@@ -218,39 +212,33 @@ proc ::safe::interpConfigure {args} {
218212

219213
# Get the current (and not the default) values of whatever has
220214
# not been given:
221-
if {![::tcl::OptProcArgGiven -accessPath]} {
215+
if {"-accessPath" ni $Args} {
222216
set doreset 0
223217
set accessPath $state(access_path)
224218
} else {
225219
set doreset 1
226220
}
227-
if {(!$AutoPathSync) && (![::tcl::OptProcArgGiven -autoPath])} {
221+
if {(!$AutoPathSync) && ("-autoPath" ni $Args)} {
228222
set autoPath $state(auto_path)
229223
} elseif {$AutoPathSync} {
230224
set autoPath {}
231225
} else {
232226
}
233-
if {
234-
![::tcl::OptProcArgGiven -statics]
235-
&& ![::tcl::OptProcArgGiven -noStatics]
236-
} then {
227+
if {("-statics" ni $Args) && ("-noStatics" ni $Args)} {
237228
set statics $state(staticsok)
238229
} else {
239230
set statics [InterpStatics]
240231
}
241-
if {
242-
[::tcl::OptProcArgGiven -nested] ||
243-
[::tcl::OptProcArgGiven -nestedLoadOk]
244-
} then {
232+
if {("-nested" in $Args) || ("-nestedLoadOk" in $Args)} {
245233
set nested [InterpNested]
246234
} else {
247235
set nested $state(nestedok)
248236
}
249-
if {![::tcl::OptProcArgGiven -deleteHook]} {
237+
if {"-deleteHook" ni $Args} {
250238
set deleteHook $state(cleanupHook)
251239
}
252240
# Now reconfigure
253-
set withAutoPath [::tcl::OptProcArgGiven -autoPath]
241+
set withAutoPath [expr {"-autoPath" in $Args}]
254242
InterpSetConfig $child $accessPath $statics $nested $deleteHook $autoPath $withAutoPath
255243

256244
# auto_reset the child (to completely sync the new access_path) tests safe-9.8 safe-9.9
@@ -361,14 +349,13 @@ proc ::safe::InterpSetConfig {child access_path staticsok nestedok deletehook au
361349
set where [lsearch -exact $access_path [info library]]
362350
if {$where < 0} {
363351
# not found, add it.
364-
set access_path [linsert $access_path 0 [info library]]
352+
ledit access_path 0 -1 [info library]
365353
Log $child "tcl_library was not in auto_path,\
366354
added it to child's access_path" NOTICE
367-
} elseif {$where != 0} {
355+
} elseif {$where > 0} {
368356
# not first, move it first
369-
set access_path [linsert \
370-
[lreplace $access_path $where $where] \
371-
0 [info library]]
357+
ledit access_path $where $where; # Remove
358+
ledit access_path 0 -1 [info library]; # Insert at beginning
372359
Log $child "tcl_libray was not in first in auto_path,\
373360
moved it to front of child's access_path" NOTICE
374361
}
@@ -410,10 +397,10 @@ proc ::safe::InterpSetConfig {child access_path staticsok nestedok deletehook au
410397
set i 0
411398
foreach dir $access_path {
412399
set token [PathToken $i]
413-
lappend child_access_path $token
414-
lappend map_access_path $token $dir
415-
lappend remap_access_path $dir $token
416-
lappend norm_access_path [file normalize $dir]
400+
lappend child_access_path $token
401+
dict set map_access_path $token $dir
402+
dict set remap_access_path $dir $token
403+
lappend norm_access_path [file normalize $dir]
417404
incr i
418405
}
419406

@@ -451,11 +438,11 @@ proc ::safe::InterpSetConfig {child access_path staticsok nestedok deletehook au
451438
}
452439

453440
set token [PathToken $i]
454-
lappend access_path $dir
455-
lappend child_access_path $token
456-
lappend map_access_path $token $dir
457-
lappend remap_access_path $dir $token
458-
lappend norm_access_path [file normalize $dir]
441+
lappend access_path $dir
442+
lappend child_access_path $token
443+
dict set map_access_path $token $dir
444+
dict set remap_access_path $dir $token
445+
lappend norm_access_path [file normalize $dir]
459446
if {$firstpass} {
460447
# $dir is in [::tcl::tm::list] and belongs in the child_tm_path.
461448
# Later passes handle subdirectories, which belong in the
@@ -503,15 +490,9 @@ proc ::safe::InterpSetConfig {child access_path staticsok nestedok deletehook au
503490
proc ::safe::DetokPath {child tokenPath} {
504491
namespace upvar ::safe [VarName $child] state
505492

506-
set childPath {}
507-
foreach token $tokenPath {
508-
if {[dict exists $state(access_path,map) $token]} {
509-
lappend childPath [dict get $state(access_path,map) $token]
510-
} else {
511-
lappend childPath $token
512-
}
513-
}
514-
return $childPath
493+
return [lmap token $tokenPath {
494+
dict getdef $state(access_path,map) $token $token
495+
}]
515496
}
516497

517498
#
@@ -550,11 +531,11 @@ proc ::safe::interpAddToAccessPath {child path} {
550531
# new one, add it:
551532
set token [PathToken [llength $state(access_path)]]
552533

553-
lappend state(access_path) $path
554-
lappend state(access_path,child) $token
555-
lappend state(access_path,map) $token $path
556-
lappend state(access_path,remap) $path $token
557-
lappend state(access_path,norm) [file normalize $path]
534+
lappend state(access_path) $path
535+
lappend state(access_path,child) $token
536+
dict set state(access_path,map) $token $path
537+
dict set state(access_path,remap) $path $token
538+
lappend state(access_path,norm) [file normalize $path]
558539

559540
SyncAccessPath $child
560541
return $token
@@ -622,16 +603,16 @@ proc ::safe::InterpInit {
622603
# Source init.tcl and tm.tcl into the child, to get auto_load and
623604
# other procedures defined:
624605

625-
if {[catch {::interp eval $child {
606+
try {::interp eval $child {
626607
source [file join $tcl_library init.tcl]
627-
}} msg opt]} {
608+
}} on error {msg opt} {
628609
Log $child "can't source init.tcl ($msg)"
629610
return -options $opt "can't source init.tcl into child $child ($msg)"
630611
}
631612

632-
if {[catch {::interp eval $child {
613+
try {::interp eval $child {
633614
source [file join $tcl_library tm.tcl]
634-
}} msg opt]} {
615+
}} on error {msg opt} {
635616
Log $child "can't source tm.tcl ($msg)"
636617
return -options $opt "can't source tm.tcl into child $child ($msg)"
637618
}
@@ -905,7 +886,7 @@ proc ::safe::AliasGlob {child args} {
905886
return -code error "permission denied"
906887
}
907888
if {$got(--)} {
908-
set cmd [linsert $cmd end-1 -directory $dir]
889+
ledit cmd end -1 -directory $dir
909890
} else {
910891
lappend cmd -directory $dir
911892
}
@@ -920,7 +901,7 @@ proc ::safe::AliasGlob {child args} {
920901

921902
# Apply the -join semantics ourselves (hence -join not copied to $cmd)
922903
if {$got(-join)} {
923-
set args [lreplace $args $at end [join [lrange $args $at end] "/"]]
904+
ledit args $at end [join [lrange $args $at end] "/"]
924905
}
925906

926907
# Process the pattern arguments. If we've done a join there is only one
@@ -1042,17 +1023,17 @@ proc ::safe::AliasSource {child args} {
10421023
set file [lindex $args $at]
10431024

10441025
# get the real path from the virtual one.
1045-
if {[catch {
1026+
try {
10461027
set realfile [TranslatePath $child $file]
1047-
} msg]} {
1028+
} on error msg {
10481029
Log $child $msg
10491030
return -code error "permission denied"
10501031
}
10511032

10521033
# check that the path is in the access path of that child
1053-
if {[catch {
1034+
try {
10541035
FileInAccessPath $child $realfile
1055-
} msg]} {
1036+
} on error msg {
10561037
Log $child $msg
10571038
return -code error "permission denied"
10581039
}
@@ -1061,9 +1042,9 @@ proc ::safe::AliasSource {child args} {
10611042
# this -errorcode so that caller in tclPkgUnknown does not write a message
10621043
# to tclLog. Has no effect on other callers of ::source, which are in
10631044
# "package ifneeded" scripts.
1064-
if {[catch {
1045+
try {
10651046
CheckFileName $child $realfile
1066-
} msg]} {
1047+
} on error msg {
10671048
Log $child "$realfile:$msg"
10681049
return -code error -errorcode {POSIX EACCES} $msg
10691050
}
@@ -1108,14 +1089,13 @@ proc ::safe::AliasLoad {child file args} {
11081089
return -code error $msg
11091090
}
11101091

1111-
# prefix (can be empty if file is not).
1112-
set prefix [lindex $args 0]
1113-
11141092
namespace upvar ::safe [VarName $child] state
11151093

1094+
# prefix (can be empty if file is not).
1095+
lassign $args prefix target
1096+
11161097
# Determine where to load. load use a relative interp path and {}
11171098
# means self, so we can directly and safely use passed arg.
1118-
set target [lindex $args 1]
11191099
if {$target ne ""} {
11201100
# we will try to load into a sub sub interp; check that we want to
11211101
# authorize that.
@@ -1164,7 +1144,7 @@ proc ::safe::AliasLoad {child file args} {
11641144
} on error msg {
11651145
# Some libraries return no error message.
11661146
set msg0 "load of library for prefix $prefix failed"
1167-
if {$msg eq {}} {
1147+
if {$msg eq ""} {
11681148
set msg $msg0
11691149
} else {
11701150
set msg "$msg0: $msg"
@@ -1228,16 +1208,12 @@ proc ::safe::BadSubcommand {child command subcommand args} {
12281208
# AliasEncodingSystem is the target of the "encoding system" alias in safe
12291209
# interpreters.
12301210
proc ::safe::AliasEncodingSystem {child args} {
1231-
try {
1232-
# Must not pass extra arguments; safe interpreters may not set the
1233-
# system encoding but they may read it.
1234-
if {[llength $args]} {
1235-
return -code error -errorcode {TCL WRONGARGS} \
1236-
"wrong # args: should be \"encoding system\""
1237-
}
1238-
} on error {msg options} {
1211+
# Must not pass extra arguments; safe interpreters may not set the
1212+
# system encoding but they may read it.
1213+
if {[llength $args]} {
1214+
set msg "wrong # args: should be \"encoding system\""
12391215
Log $child $msg
1240-
return -options $options $msg
1216+
return -code error -errorcode {TCL WRONGARGS} $msg
12411217
}
12421218
tailcall ::interp invokehidden $child tcl:encoding:system
12431219
}
@@ -1282,14 +1258,14 @@ proc ::safe::AliasExeName {child} {
12821258

12831259
proc ::safe::RejectExcessColons {child} {
12841260
set stripped [regsub -all -- {:::*} $child ::]
1285-
if {[string range $stripped end-1 end] eq {::}} {
1261+
if {[string match *:: $stripped]} {
12861262
return -code error {interpreter name must not end in "::"}
12871263
}
12881264
if {$stripped ne $child} {
12891265
set msg {interpreter name has excess colons in namespace separators}
12901266
return -code error $msg
12911267
}
1292-
if {[string range $stripped 0 1] eq {::}} {
1268+
if {[string match ::* $stripped]} {
12931269
return -code error {interpreter name must not begin "::"}
12941270
}
12951271
return
@@ -1374,31 +1350,35 @@ proc ::safe::Setup {} {
13741350
proc ::safe::setSyncMode {args} {
13751351
variable AutoPathSync
13761352

1377-
if {[llength $args] == 0} {
1378-
} elseif {[llength $args] == 1} {
1379-
set newValue [lindex $args 0]
1380-
if {![string is boolean -strict $newValue]} {
1381-
return -code error "new value must be a valid boolean"
1353+
switch -integer -- [llength $args] {
1354+
0 {
1355+
return $AutoPathSync
13821356
}
1383-
set args [expr {$newValue && $newValue}]
1384-
if {([info vars ::safe::S*] ne {}) && ($args != $AutoPathSync)} {
1385-
return -code error \
1386-
"cannot set new value while Safe Base child interpreters exist"
1357+
1 {
1358+
lassign $args newValue
1359+
if {![string is boolean -strict $newValue]} {
1360+
return -code error "new value must be a valid boolean"
1361+
}
1362+
set newValue [expr {!!$newValue}]
1363+
if {([info vars ::safe::S*] ne {}) && ($newValue != $AutoPathSync)} {
1364+
return -code error \
1365+
"cannot set new value while Safe Base child interpreters exist"
1366+
}
1367+
if {$newValue != $AutoPathSync} {
1368+
set AutoPathSync $newValue
1369+
::tcl::OptKeyDelete ::safe::interpCreate
1370+
::tcl::OptKeyDelete ::safe::interpIC
1371+
set TmpLog [setLogCmd]
1372+
Setup
1373+
setLogCmd $TmpLog
1374+
}
1375+
return $AutoPathSync
13871376
}
1388-
if {($args != $AutoPathSync)} {
1389-
set AutoPathSync {*}$args
1390-
::tcl::OptKeyDelete ::safe::interpCreate
1391-
::tcl::OptKeyDelete ::safe::interpIC
1392-
set TmpLog [setLogCmd]
1393-
Setup
1394-
setLogCmd $TmpLog
1377+
default {
1378+
set msg {wrong # args: should be "safe::setSyncMode ?newValue?"}
1379+
return -code error $msg
13951380
}
1396-
} else {
1397-
set msg {wrong # args: should be "safe::setSyncMode ?newValue?"}
1398-
return -code error $msg
13991381
}
1400-
1401-
return $AutoPathSync
14021382
}
14031383

14041384
namespace eval ::safe {

0 commit comments

Comments
 (0)