12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289 |
- package require opt 0.4.8
- namespace eval ::safe {
- namespace export interpCreate interpInit interpConfigure interpDelete \
- interpAddToAccessPath interpFindInAccessPath setLogCmd
- }
- proc ::safe::InterpStatics {} {
- foreach v {Args statics noStatics} {
- upvar $v $v
- }
- set flag [::tcl::OptProcArgGiven -noStatics]
- if {$flag && (!$noStatics == !$statics)
- && ([::tcl::OptProcArgGiven -statics])} {
- return -code error\
- "conflicting values given for -statics and -noStatics"
- }
- if {$flag} {
- return [expr {!$noStatics}]
- } else {
- return $statics
- }
- }
- proc ::safe::InterpNested {} {
- foreach v {Args nested nestedLoadOk} {
- upvar $v $v
- }
- set flag [::tcl::OptProcArgGiven -nestedLoadOk]
- if {$flag && (!$nestedLoadOk != !$nested)
- && ([::tcl::OptProcArgGiven -nested])} {
- return -code error\
- "conflicting values given for -nested and -nestedLoadOk"
- }
- if {$flag} {
- return $nestedLoadOk
- } else {
- return $nested
- }
- }
- proc ::safe::interpCreate {args} {
- set Args [::tcl::OptKeyParse ::safe::interpCreate $args]
- RejectExcessColons $slave
- InterpCreate $slave $accessPath \
- [InterpStatics] [InterpNested] $deleteHook
- }
- proc ::safe::interpInit {args} {
- set Args [::tcl::OptKeyParse ::safe::interpIC $args]
- if {![::interp exists $slave]} {
- return -code error "\"$slave\" is not an interpreter"
- }
- RejectExcessColons $slave
- InterpInit $slave $accessPath \
- [InterpStatics] [InterpNested] $deleteHook
- }
- proc ::safe::CheckInterp {child} {
- namespace upvar ::safe [VarName $child] state
- if {![info exists state] || ![::interp exists $child]} {
- return -code error \
- "\"$child\" is not an interpreter managed by ::safe::"
- }
- }
- proc ::safe::interpConfigure {args} {
- switch [llength $args] {
- 1 {
- set Args [::tcl::OptKeyParse ::safe::interpIC $args]
- CheckInterp $slave
- namespace upvar ::safe [VarName $slave] state
- return [join [list \
- [list -accessPath $state(access_path)] \
- [list -statics $state(staticsok)] \
- [list -nested $state(nestedok)] \
- [list -deleteHook $state(cleanupHook)]]]
- }
- 2 {
- lassign $args slave arg
- set desc [lindex [::tcl::OptKeyGetDesc ::safe::interpIC] 2]
- set hits [::tcl::OptHits desc $arg]
- if {$hits > 1} {
- return -code error [::tcl::OptAmbigous $desc $arg]
- } elseif {$hits == 0} {
- return -code error [::tcl::OptFlagUsage $desc $arg]
- }
- CheckInterp $slave
- namespace upvar ::safe [VarName $slave] state
- set item [::tcl::OptCurDesc $desc]
- set name [::tcl::OptName $item]
- switch -exact -- $name {
- -accessPath {
- return [list -accessPath $state(access_path)]
- }
- -statics {
- return [list -statics $state(staticsok)]
- }
- -nested {
- return [list -nested $state(nestedok)]
- }
- -deleteHook {
- return [list -deleteHook $state(cleanupHook)]
- }
- -noStatics {
- return -code error\
- "ambigous query (get or set -noStatics ?)\
- use -statics instead"
- }
- -nestedLoadOk {
- return -code error\
- "ambigous query (get or set -nestedLoadOk ?)\
- use -nested instead"
- }
- default {
- return -code error "unknown flag $name (bug)"
- }
- }
- }
- default {
- set Args [::tcl::OptKeyParse ::safe::interpIC $args]
- CheckInterp $slave
- namespace upvar ::safe [VarName $slave] state
- if {![::tcl::OptProcArgGiven -accessPath]} {
- set doreset 0
- set accessPath $state(access_path)
- } else {
- set doreset 1
- }
- if {
- ![::tcl::OptProcArgGiven -statics]
- && ![::tcl::OptProcArgGiven -noStatics]
- } then {
- set statics $state(staticsok)
- } else {
- set statics [InterpStatics]
- }
- if {
- [::tcl::OptProcArgGiven -nested] ||
- [::tcl::OptProcArgGiven -nestedLoadOk]
- } then {
- set nested [InterpNested]
- } else {
- set nested $state(nestedok)
- }
- if {![::tcl::OptProcArgGiven -deleteHook]} {
- set deleteHook $state(cleanupHook)
- }
- InterpSetConfig $slave $accessPath $statics $nested $deleteHook
- if {$doreset} {
- if {[catch {::interp eval $slave {auto_reset}} msg]} {
- Log $slave "auto_reset failed: $msg"
- } else {
- Log $slave "successful auto_reset" NOTICE
- }
- ::interp eval $slave {tcl::tm::path remove {*}[tcl::tm::list]}
- if {[llength $state(tm_path_slave)] > 0} {
- ::interp eval $slave [list \
- ::tcl::tm::add {*}[lreverse $state(tm_path_slave)]]
- }
- foreach pkg [::interp eval $slave {package names}] {
- if {[::interp eval $slave [list package provide $pkg]] eq ""} {
- ::interp eval $slave [list package forget $pkg]
- }
- }
- }
- return
- }
- }
- }
- proc ::safe::InterpCreate {
- child
- access_path
- staticsok
- nestedok
- deletehook
- } {
- if {$child ne ""} {
- namespace eval :: [list ::interp create -safe $child]
- } else {
- set child [::interp create -safe]
- }
- Log $child "Created" NOTICE
- InterpInit $child $access_path $staticsok $nestedok $deletehook
- }
- proc ::safe::InterpSetConfig {child access_path staticsok nestedok deletehook} {
- global auto_path
- if {$access_path eq ""} {
- set access_path $auto_path
- set where [lsearch -exact $access_path [info library]]
- if {$where < 0} {
- set access_path [linsert $access_path 0 [info library]]
- Log $child "tcl_library was not in auto_path,\
- added it to slave's access_path" NOTICE
- } elseif {$where != 0} {
- set access_path [linsert \
- [lreplace $access_path $where $where] \
- 0 [info library]]
- Log $child "tcl_libray was not in first in auto_path,\
- moved it to front of slave's access_path" NOTICE
- }
- set access_path [AddSubDirs $access_path]
- }
- Log $child "Setting accessPath=($access_path) staticsok=$staticsok\
- nestedok=$nestedok deletehook=($deletehook)" NOTICE
- namespace upvar ::safe [VarName $child] state
- set norm_access_path {}
- set slave_access_path {}
- set map_access_path {}
- set remap_access_path {}
- set slave_tm_path {}
- set i 0
- foreach dir $access_path {
- set token [PathToken $i]
- lappend slave_access_path $token
- lappend map_access_path $token $dir
- lappend remap_access_path $dir $token
- lappend norm_access_path [file normalize $dir]
- incr i
- }
- set morepaths [::tcl::tm::list]
- set firstpass 1
- while {[llength $morepaths]} {
- set addpaths $morepaths
- set morepaths {}
- foreach dir $addpaths {
- if {[dict exists $remap_access_path $dir]} {
- if {$firstpass} {
- lappend slave_tm_path [dict get $remap_access_path $dir]
- }
- continue
- }
- set token [PathToken $i]
- lappend access_path $dir
- lappend slave_access_path $token
- lappend map_access_path $token $dir
- lappend remap_access_path $dir $token
- lappend norm_access_path [file normalize $dir]
- if {$firstpass} {
- lappend slave_tm_path $token
- }
- incr i
- lappend morepaths {*}[glob -nocomplain -directory $dir -type d *]
- }
- set firstpass 0
- }
- set state(access_path) $access_path
- set state(access_path,map) $map_access_path
- set state(access_path,remap) $remap_access_path
- set state(access_path,norm) $norm_access_path
- set state(access_path,slave) $slave_access_path
- set state(tm_path_slave) $slave_tm_path
- set state(staticsok) $staticsok
- set state(nestedok) $nestedok
- set state(cleanupHook) $deletehook
- SyncAccessPath $child
- return
- }
- proc ::safe::interpFindInAccessPath {child path} {
- CheckInterp $child
- namespace upvar ::safe [VarName $child] state
- if {![dict exists $state(access_path,remap) $path]} {
- return -code error "$path not found in access path"
- }
- return [dict get $state(access_path,remap) $path]
- }
- proc ::safe::interpAddToAccessPath {child path} {
- CheckInterp $child
- namespace upvar ::safe [VarName $child] state
- if {[dict exists $state(access_path,remap) $path]} {
- return [dict get $state(access_path,remap) $path]
- }
- set token [PathToken [llength $state(access_path)]]
- lappend state(access_path) $path
- lappend state(access_path,slave) $token
- lappend state(access_path,map) $token $path
- lappend state(access_path,remap) $path $token
- lappend state(access_path,norm) [file normalize $path]
- SyncAccessPath $child
- return $token
- }
- proc ::safe::InterpInit {
- child
- access_path
- staticsok
- nestedok
- deletehook
- } {
- InterpSetConfig $child $access_path $staticsok $nestedok $deletehook
- foreach {command alias} {
- source AliasSource
- load AliasLoad
- encoding AliasEncoding
- exit interpDelete
- glob AliasGlob
- } {
- ::interp alias $child $command {} [namespace current]::$alias $child
- }
- ::interp expose $child file
- foreach subcommand {dirname extension rootname tail} {
- ::interp alias $child ::tcl::file::$subcommand {} \
- ::safe::AliasFileSubcommand $child $subcommand
- }
- foreach subcommand {
- atime attributes copy delete executable exists isdirectory isfile
- link lstat mtime mkdir nativename normalize owned readable readlink
- rename size stat tempfile type volumes writable
- } {
- ::interp alias $child ::tcl::file::$subcommand {} \
- ::safe::BadSubcommand $child file $subcommand
- }
- foreach {subcommand alias} {
- nameofexecutable AliasExeName
- } {
- ::interp alias $child ::tcl::info::$subcommand \
- {} [namespace current]::$alias $child
- }
- if {[catch {::interp eval $child {
- source [file join $tcl_library init.tcl]
- }} msg opt]} {
- Log $child "can't source init.tcl ($msg)"
- return -options $opt "can't source init.tcl into slave $child ($msg)"
- }
- if {[catch {::interp eval $child {
- source [file join $tcl_library tm.tcl]
- }} msg opt]} {
- Log $child "can't source tm.tcl ($msg)"
- return -options $opt "can't source tm.tcl into slave $child ($msg)"
- }
- namespace upvar ::safe [VarName $child] state
- if {[llength $state(tm_path_slave)] > 0} {
- ::interp eval $child [list \
- ::tcl::tm::add {*}[lreverse $state(tm_path_slave)]]
- }
- return $child
- }
- proc ::safe::AddSubDirs {pathList} {
- set res {}
- foreach dir $pathList {
- if {[file isdirectory $dir]} {
- if {$dir ni $res} {
- lappend res $dir
- }
- foreach sub [glob -directory $dir -nocomplain *] {
- if {[file isdirectory $sub] && ($sub ni $res)} {
- lappend res $sub
- }
- }
- }
- }
- return $res
- }
- proc ::safe::interpDelete {child} {
- Log $child "About to delete" NOTICE
- namespace upvar ::safe [VarName $child] state
- foreach sub [interp children $child] {
- if {[info exists ::safe::[VarName [list $child $sub]]]} {
- ::safe::interpDelete [list $child $sub]
- }
- }
- if {[info exists state(cleanupHook)]} {
- set hook $state(cleanupHook)
- if {[llength $hook]} {
- unset state(cleanupHook)
- try {
- {*}$hook $child
- } on error err {
- Log $child "Delete hook error ($err)"
- }
- }
- }
- if {[info exists state]} {
- unset state
- }
- if {[::interp exists $child]} {
- ::interp delete $child
- Log $child "Deleted" NOTICE
- }
- return
- }
- proc ::safe::setLogCmd {args} {
- variable Log
- set la [llength $args]
- if {$la == 0} {
- return $Log
- } elseif {$la == 1} {
- set Log [lindex $args 0]
- } else {
- set Log $args
- }
- if {$Log eq ""} {
- proc ::safe::Log {args} {}
- } else {
- proc ::safe::Log {child msg {type ERROR}} {
- variable Log
- {*}$Log "$type for slave $child : $msg"
- return
- }
- }
- }
- proc ::safe::SyncAccessPath {child} {
- namespace upvar ::safe [VarName $child] state
- set slave_access_path $state(access_path,slave)
- ::interp eval $child [list set auto_path $slave_access_path]
- Log $child "auto_path in $child has been set to $slave_access_path"\
- NOTICE
- ::interp eval $child [list \
- set tcl_library [lindex $slave_access_path 0]]
- }
- proc ::safe::PathToken {n} {
- return "\$p(:$n:)"
- }
- proc ::safe::TranslatePath {child path} {
- namespace upvar ::safe [VarName $child] state
- if {[string match "*::*" $path] || [string match "*..*" $path]} {
- return -code error "invalid characters in path $path"
- }
- return [string map $state(access_path,map) $path]
- }
- proc ::safe::CheckFileName {child file} {
- if {![file exists $file]} {
- return -code error "no such file or directory"
- }
- if {![file readable $file]} {
- return -code error "not readable"
- }
- }
- proc ::safe::AliasFileSubcommand {child subcommand name} {
- if {[string match ~* $name]} {
- set name ./$name
- }
- tailcall ::interp invokehidden $child tcl:file:$subcommand $name
- }
- proc ::safe::AliasGlob {child args} {
- Log $child "GLOB ! $args" NOTICE
- set cmd {}
- set at 0
- array set got {
- -directory 0
- -nocomplain 0
- -join 0
- -tails 0
- -- 0
- }
- if {$::tcl_platform(platform) eq "windows"} {
- set dirPartRE {^(.*)[\\/]([^\\/]*)$}
- } else {
- set dirPartRE {^(.*)/([^/]*)$}
- }
- set dir {}
- set virtualdir {}
- while {$at < [llength $args]} {
- switch -glob -- [set opt [lindex $args $at]] {
- -nocomplain - -- - -tails {
- lappend cmd $opt
- set got($opt) 1
- incr at
- }
- -join {
- set got($opt) 1
- incr at
- }
- -types - -type {
- lappend cmd -types [lindex $args [incr at]]
- incr at
- }
- -directory {
- if {$got($opt)} {
- return -code error \
- {"-directory" cannot be used with "-path"}
- }
- set got($opt) 1
- set virtualdir [lindex $args [incr at]]
- incr at
- }
- -* {
- Log $child "Safe base rejecting glob option '$opt'"
- return -code error "Safe base rejecting glob option '$opt'"
- }
- default {
- break
- }
- }
- if {$got(--)} break
- }
- if {$got(-directory)} {
- try {
- set dir [TranslatePath $child $virtualdir]
- DirInAccessPath $child $dir
- } on error msg {
- Log $child $msg
- if {$got(-nocomplain)} return
- return -code error "permission denied"
- }
- if {$got(--)} {
- set cmd [linsert $cmd end-1 -directory $dir]
- } else {
- lappend cmd -directory $dir
- }
- } else {
- Log $child {option -directory must be supplied}
- if {$got(-nocomplain)} return
- return -code error "permission denied"
- }
- if {$got(-join)} {
- set args [lreplace $args $at end [join [lrange $args $at end] "/"]]
- }
- set firstPattern [llength $cmd]
- foreach opt [lrange $args $at end] {
- if {![regexp $dirPartRE $opt -> thedir thefile]} {
- set thedir .
- }
- if {($thedir eq "*") && ($thefile eq "pkgIndex.tcl")} {
- set mapped 0
- foreach d [glob -directory [TranslatePath $child $virtualdir] \
- -types d -tails *] {
- catch {
- DirInAccessPath $child \
- [TranslatePath $child [file join $virtualdir $d]]
- lappend cmd [file join $d $thefile]
- set mapped 1
- }
- }
- if {$mapped} continue
- }
- try {
- DirInAccessPath $child [TranslatePath $child \
- [file join $virtualdir $thedir]]
- } on error msg {
- Log $child $msg
- if {$got(-nocomplain)} continue
- return -code error "permission denied"
- }
- lappend cmd $opt
- }
- Log $child "GLOB = $cmd" NOTICE
- if {$got(-nocomplain) && [llength $cmd] eq $firstPattern} {
- return
- }
- try {
- set entries [::interp invokehidden $child glob {*}$cmd]
- } on error msg {
- Log $child $msg
- return -code error "script error"
- }
- Log $child "GLOB < $entries" NOTICE
- set res {}
- set l [string length $dir]
- foreach p $entries {
- if {[string equal -length $l $dir $p]} {
- set p [string replace $p 0 [expr {$l-1}] $virtualdir]
- }
- lappend res $p
- }
- Log $child "GLOB > $res" NOTICE
- return $res
- }
- proc ::safe::AliasSource {child args} {
- set argc [llength $args]
- if {[lindex $args 0] eq "-encoding"} {
- incr argc -2
- set encoding [lindex $args 1]
- set at 2
- if {$encoding eq "identity"} {
- Log $child "attempt to use the identity encoding"
- return -code error "permission denied"
- }
- } else {
- set at 0
- set encoding {}
- }
- if {$argc != 1} {
- set msg "wrong # args: should be \"source ?-encoding E? fileName\""
- Log $child "$msg ($args)"
- return -code error $msg
- }
- set file [lindex $args $at]
- if {[catch {
- set realfile [TranslatePath $child $file]
- } msg]} {
- Log $child $msg
- return -code error "permission denied"
- }
- if {[catch {
- FileInAccessPath $child $realfile
- } msg]} {
- Log $child $msg
- return -code error "permission denied"
- }
- if {[catch {
- CheckFileName $child $realfile
- } msg]} {
- Log $child "$realfile:$msg"
- return -code error -errorcode {POSIX EACCES} $msg
- }
- set old [::interp eval $child {info script}]
- set replacementMsg "script error"
- set code [catch {
- set f [open $realfile]
- fconfigure $f -eofchar "\032 {}"
- if {$encoding ne ""} {
- fconfigure $f -encoding $encoding
- }
- set contents [read $f]
- close $f
- ::interp eval $child [list info script $file]
- } msg opt]
- if {$code == 0} {
- set code [catch {::interp eval $child $contents} msg opt]
- set replacementMsg $msg
- }
- catch {interp eval $child [list info script $old]}
- if {$code == 1} {
- Log $child $msg
- return -code error $replacementMsg
- }
- return -code $code -options $opt $msg
- }
- proc ::safe::AliasLoad {child file args} {
- set argc [llength $args]
- if {$argc > 2} {
- set msg "load error: too many arguments"
- Log $child "$msg ($argc) {$file $args}"
- return -code error $msg
- }
- set package [lindex $args 0]
- namespace upvar ::safe [VarName $child] state
- set target [lindex $args 1]
- if {$target ne ""} {
- if {!$state(nestedok)} {
- Log $child "loading to a sub interp (nestedok)\
- disabled (trying to load $package to $target)"
- return -code error "permission denied (nested load)"
- }
- }
- if {$file eq ""} {
- if {$package eq ""} {
- set msg "load error: empty filename and no package name"
- Log $child $msg
- return -code error $msg
- }
- if {!$state(staticsok)} {
- Log $child "static packages loading disabled\
- (trying to load $package to $target)"
- return -code error "permission denied (static package)"
- }
- } else {
- try {
- set file [TranslatePath $child $file]
- } on error msg {
- Log $child $msg
- return -code error "permission denied"
- }
- try {
- FileInAccessPath $child $file
- } on error msg {
- Log $child $msg
- return -code error "permission denied (path)"
- }
- }
- try {
- return [::interp invokehidden $child load $file $package $target]
- } on error msg {
- set msg0 "load of binary library for package $package failed"
- if {$msg eq {}} {
- set msg $msg0
- } else {
- set msg "$msg0: $msg"
- }
- Log $child $msg
- return -code error $msg
- }
- }
- proc ::safe::FileInAccessPath {child file} {
- namespace upvar ::safe [VarName $child] state
- set access_path $state(access_path)
- if {[file isdirectory $file]} {
- return -code error "\"$file\": is a directory"
- }
- set parent [file dirname $file]
- set norm_parent [file normalize $parent]
- namespace upvar ::safe [VarName $child] state
- if {$norm_parent ni $state(access_path,norm)} {
- return -code error "\"$file\": not in access_path"
- }
- }
- proc ::safe::DirInAccessPath {child dir} {
- namespace upvar ::safe [VarName $child] state
- set access_path $state(access_path)
- if {[file isfile $dir]} {
- return -code error "\"$dir\": is a file"
- }
- set norm_dir [file normalize $dir]
- namespace upvar ::safe [VarName $child] state
- if {$norm_dir ni $state(access_path,norm)} {
- return -code error "\"$dir\": not in access_path"
- }
- }
- proc ::safe::BadSubcommand {child command subcommand args} {
- set msg "not allowed to invoke subcommand $subcommand of $command"
- Log $child $msg
- return -code error -errorcode {TCL SAFE SUBCOMMAND} $msg
- }
- proc ::safe::AliasEncoding {child option args} {
- set subcommands {convertfrom convertto names system}
- try {
- set option [tcl::prefix match -error [list -level 1 -errorcode \
- [list TCL LOOKUP INDEX option $option]] $subcommands $option]
- if {$option eq "system" && [llength $args]} {
- return -code error -errorcode {TCL WRONGARGS} \
- "wrong # args: should be \"encoding system\""
- }
- } on error {msg options} {
- Log $child $msg
- return -options $options $msg
- }
- tailcall ::interp invokehidden $child encoding $option {*}$args
- }
- proc ::safe::AliasExeName {child} {
- return ""
- }
- proc ::safe::RejectExcessColons {child} {
- set stripped [regsub -all -- {:::*} $child ::]
- if {[string range $stripped end-1 end] eq {::}} {
- return -code error {interpreter name must not end in "::"}
- }
- if {$stripped ne $child} {
- set msg {interpreter name has excess colons in namespace separators}
- return -code error $msg
- }
- if {[string range $stripped 0 1] eq {::}} {
- return -code error {interpreter name must not begin "::"}
- }
- return
- }
- proc ::safe::VarName {child} {
- return S[string map {:: @N @ @A} $child]
- }
- proc ::safe::Setup {} {
- set temp [::tcl::OptKeyRegister {
- {-accessPath -list {} "access path for the slave"}
- {-noStatics "prevent loading of statically linked pkgs"}
- {-statics true "loading of statically linked pkgs"}
- {-nestedLoadOk "allow nested loading"}
- {-nested false "nested loading"}
- {-deleteHook -script {} "delete hook"}
- }]
- ::tcl::OptKeyRegister {
- {?slave? -name {} "name of the slave (optional)"}
- } ::safe::interpCreate
- lappend ::tcl::OptDesc(::safe::interpCreate) $::tcl::OptDesc($temp)
- ::tcl::OptKeyRegister {
- {slave -name {} "name of the slave"}
- } ::safe::interpIC
- lappend ::tcl::OptDesc(::safe::interpIC) $::tcl::OptDesc($temp)
- ::tcl::OptKeyDelete $temp
- setLogCmd {}
- return
- }
- namespace eval ::safe {
- variable Log {}
- }
- ::safe::Setup
|