diff options
author | jan.nijtmans <nijtmans@users.sourceforge.net> | 2020-10-24 14:50:11 (GMT) |
---|---|---|
committer | jan.nijtmans <nijtmans@users.sourceforge.net> | 2020-10-24 14:50:11 (GMT) |
commit | 63855497af431a6ee84d67b62ade8694485d76c9 (patch) | |
tree | 8239e1a67cec1bb976b23a1d96024097fc93b8a1 /library | |
parent | fe94c1d6c4fa1c0d810d2eb6b845e7d0faf8812c (diff) | |
parent | 48d0827130389368a247f26b480bd819a1c753e5 (diff) | |
download | tcl-63855497af431a6ee84d67b62ade8694485d76c9.zip tcl-63855497af431a6ee84d67b62ade8694485d76c9.tar.gz tcl-63855497af431a6ee84d67b62ade8694485d76c9.tar.bz2 |
Merge 8.7
Diffstat (limited to 'library')
-rw-r--r-- | library/auto.tcl | 4 | ||||
-rw-r--r-- | library/clock.tcl | 6 | ||||
-rw-r--r-- | library/http/http.tcl | 96 | ||||
-rw-r--r-- | library/http/pkgIndex.tcl | 2 | ||||
-rw-r--r-- | library/init.tcl | 7 | ||||
-rw-r--r-- | library/install.tcl | 5 | ||||
-rw-r--r-- | library/manifest.txt | 4 | ||||
-rw-r--r-- | library/opt/optparse.tcl | 6 | ||||
-rw-r--r-- | library/opt/pkgIndex.tcl | 2 | ||||
-rw-r--r-- | library/package.tcl | 13 | ||||
-rw-r--r-- | library/safe.tcl | 591 | ||||
-rw-r--r-- | library/tcltest/tcltest.tcl | 29 | ||||
-rw-r--r-- | library/tm.tcl | 13 | ||||
-rw-r--r-- | library/tzdata/Africa/Algiers | 2 | ||||
-rw-r--r-- | library/tzdata/Africa/Casablanca | 20 | ||||
-rw-r--r-- | library/tzdata/Africa/El_Aaiun | 20 | ||||
-rw-r--r-- | library/tzdata/America/Dawson | 3 | ||||
-rw-r--r-- | library/tzdata/America/Whitehorse | 3 | ||||
-rw-r--r-- | library/tzdata/Antarctica/Casey | 5 | ||||
-rw-r--r-- | library/tzdata/Antarctica/Macquarie | 181 | ||||
-rw-r--r-- | library/tzdata/Europe/Budapest | 45 | ||||
-rw-r--r-- | library/tzdata/Europe/Monaco | 4 | ||||
-rw-r--r-- | library/tzdata/Europe/Paris | 4 | ||||
-rw-r--r-- | library/tzdata/Pacific/Fiji | 2 |
24 files changed, 744 insertions, 323 deletions
diff --git a/library/auto.tcl b/library/auto.tcl index 2deae05..32da97c 100644 --- a/library/auto.tcl +++ b/library/auto.tcl @@ -265,6 +265,7 @@ proc auto_mkindex {dir args} { auto_mkindex_parser::cleanup set fid [open "tclIndex" w] + fconfigure $fid -translation lf puts -nonewline $fid $index close $fid cd $oldDir @@ -291,6 +292,7 @@ proc auto_mkindex_old {dir args} { set f "" set error [catch { set f [open $file] + fconfigure $f -eofchar \032 while {[gets $f line] >= 0} { if {[regexp {^proc[ ]+([^ ]*)} $line match procName]} { set procName [lindex [auto_qualify $procName "::"] 0] @@ -309,6 +311,7 @@ proc auto_mkindex_old {dir args} { set f "" set error [catch { set f [open tclIndex w] + fconfigure $f -translation lf puts -nonewline $f $index close $f cd $oldDir @@ -401,6 +404,7 @@ proc auto_mkindex_parser::mkindex {file} { set scriptFile $file set fid [open $file] + fconfigure $fid -eofchar \032 set contents [read $fid] close $fid diff --git a/library/clock.tcl b/library/clock.tcl index 49dfdbe..54919f2 100644 --- a/library/clock.tcl +++ b/library/clock.tcl @@ -3304,7 +3304,7 @@ proc ::tcl::clock::LoadTimeZoneFile { fileName } { return } - # Since an unsafe interp uses the [clock] command in the master, this code + # Since an unsafe interp uses the [clock] command in the parent, this code # is security sensitive. Make sure that the path name cannot escape the # given directory. @@ -3314,7 +3314,7 @@ proc ::tcl::clock::LoadTimeZoneFile { fileName } { "time zone \":$fileName\" not valid" } try { - source -encoding utf-8 [file join $DataDir $fileName] + source [file join $DataDir $fileName] } on error {} { return -code error \ -errorcode [list CLOCK badTimeZone :$fileName] \ @@ -3344,7 +3344,7 @@ proc ::tcl::clock::LoadTimeZoneFile { fileName } { proc ::tcl::clock::LoadZoneinfoFile { fileName } { variable ZoneinfoPaths - # Since an unsafe interp uses the [clock] command in the master, this code + # Since an unsafe interp uses the [clock] command in the parent, this code # is security sensitive. Make sure that the path name cannot escape the # given directory. diff --git a/library/http/http.tcl b/library/http/http.tcl index 2cef614..df8fe2d 100644 --- a/library/http/http.tcl +++ b/library/http/http.tcl @@ -11,7 +11,7 @@ package require Tcl 8.6- # Keep this in sync with pkgIndex.tcl and with the install directories in # Makefiles -package provide http 2.9.3 +package provide http 2.10.0a1 namespace eval http { # Allow resourcing to not clobber existing data @@ -544,7 +544,7 @@ proc http::CloseSocket {s {token {}}} { } else { set map [array get socketMapping] set ndx [lsearch -exact $map $s] - if {$ndx != -1} { + if {$ndx >= 0} { incr ndx -1 set connId [lindex $map $ndx] } @@ -746,6 +746,7 @@ proc http::geturl {url args} { -strict boolean -timeout integer -validate boolean + -headers dict } set state(charset) $defaultCharset set options { @@ -759,9 +760,8 @@ proc http::geturl {url args} { foreach {flag value} $args { if {[regexp -- $pat $flag]} { # Validate numbers - if { - [info exists type($flag)] && - ![string is $type($flag) -strict $value] + if {($flag eq "-headers") ? [catch {dict size $value}] : + ([info exists type($flag)] && ![string is $type($flag) -strict $value]) } { unset $token return -code error \ @@ -983,6 +983,18 @@ proc http::geturl {url args} { set state(-pipeline) $http(-pipeline) } + # We cannot handle chunked encodings with -handler, so force HTTP/1.0 + # until we can manage this. + if {[info exists state(-handler)]} { + set state(-protocol) 1.0 + } + + # RFC 7320 A.1 - HTTP/1.0 Keep-Alive is problematic. We do not support it. + if {$state(-protocol) eq "1.0"} { + set state(connection) close + set state(-keepalive) 0 + } + # See if we are supposed to use a previously opened channel. # - In principle, ANY call to http::geturl could use a previously opened # channel if it is available - the "Connection: keep-alive" header is a @@ -1355,11 +1367,6 @@ proc http::Connected {token proto phost srvurl} { if {[info exists state(-method)] && ($state(-method) ne "")} { set how $state(-method) } - # We cannot handle chunked encodings with -handler, so force HTTP/1.0 - # until we can manage this. - if {[info exists state(-handler)]} { - set state(-protocol) 1.0 - } set accept_types_seen 0 Log ^B$tk begin sending request - token $token @@ -1382,7 +1389,7 @@ proc http::Connected {token proto phost srvurl} { puts $sock "Host: $host:$port" } puts $sock "User-Agent: $http(-useragent)" - if {($state(-protocol) >= 1.0) && $state(-keepalive)} { + if {($state(-protocol) > 1.0) && $state(-keepalive)} { # Send this header, because a 1.1 server is not compelled to treat # this as the default. puts $sock "Connection: keep-alive" @@ -1390,9 +1397,17 @@ proc http::Connected {token proto phost srvurl} { if {($state(-protocol) > 1.0) && !$state(-keepalive)} { puts $sock "Connection: close" ;# RFC2616 sec 8.1.2.1 } - if {[info exists phost] && ($phost ne "") && $state(-keepalive)} { - puts $sock "Proxy-Connection: Keep-Alive" - } + if {($state(-protocol) < 1.1)} { + # RFC7230 A.1 + # Some server implementations of HTTP/1.0 have a faulty + # implementation of RFC 2068 Keep-Alive. + # Don't leave this to chance. + # For HTTP/1.0 we have already "set state(connection) close" + # and "state(-keepalive) 0". + puts $sock "Connection: close" + } + # RFC7230 A.1 - "clients are encouraged not to send the + # Proxy-Connection header field in any requests" set accept_encoding_seen 0 set content_type_seen 0 dict for {key value} $state(-headers) { @@ -1668,9 +1683,51 @@ proc http::ReceiveResponse {token} { Log ^D$tk begin receiving response - token $token coroutine ${token}EventCoroutine http::Event $sock $token - fileevent $sock readable ${token}EventCoroutine + if {[info exists state(-handler)] || [info exists state(-progress)]} { + fileevent $sock readable [list http::EventGateway $sock $token] + } else { + fileevent $sock readable ${token}EventCoroutine + } + return } + +# http::EventGateway +# +# Bug [c2dc1da315]. +# - Recursive launch of the coroutine can occur if a -handler or -progress +# callback is used, and the callback command enters the event loop. +# - To prevent this, the fileevent "binding" is disabled while the +# coroutine is in flight. +# - If a recursive call occurs despite these precautions, it is not +# trapped and discarded here, because it is better to report it as a +# bug. +# - Although this solution is believed to be sufficiently general, it is +# used only if -handler or -progress is specified. In other cases, +# the coroutine is called directly. + +proc http::EventGateway {sock token} { + variable $token + upvar 0 $token state + fileevent $sock readable {} + catch {${token}EventCoroutine} res opts + if {[info commands ${token}EventCoroutine] ne {}} { + # The coroutine can be deleted by completion (a non-yield return), by + # http::Finish (when there is a premature end to the transaction), by + # http::reset or http::cleanup, or if the caller set option -channel + # but not option -handler: in the last case reading from the socket is + # now managed by commands ::http::Copy*, http::ReceiveChunked, and + # http::make-transformation-chunked. + # + # Catch in case the coroutine has closed the socket. + catch {fileevent $sock readable [list http::EventGateway $sock $token]} + } + + # If there was an error, re-throw it. + return -options $opts $res +} + + # http::NextPipelinedWrite # # - Connecting a socket to a token for writing is done by this command and by @@ -2734,20 +2791,21 @@ proc http::Event {sock token} { # scan any list for "close". if {$tmpHeader in {close keep-alive}} { # The common cases, continue. - } elseif {[string first , $tmpHeader] == -1} { + } elseif {[string first , $tmpHeader] < 0} { # Not a comma-separated list, not "close", # therefore "keep-alive". set tmpHeader keep-alive } else { - set tmpHeader keep-alive + set tmpResult keep-alive set tmpCsl [split $tmpHeader ,] # Optional whitespace either side of separator. foreach el $tmpCsl { if {[string trim $el] eq {close}} { - set tmpHeader close + set tmpResult close break } } + set tmpHeader $tmpResult } set state(connection) $tmpHeader } @@ -3186,7 +3244,7 @@ proc http::BlockingGets {sock} { while 1 { set count [gets $sock line] set eof [eof $sock] - if {$count > -1 || $eof} { + if {$count >= 0 || $eof} { return $line } else { yield diff --git a/library/http/pkgIndex.tcl b/library/http/pkgIndex.tcl index 43cd86b..f312aac 100644 --- a/library/http/pkgIndex.tcl +++ b/library/http/pkgIndex.tcl @@ -1,2 +1,2 @@ if {![package vsatisfies [package provide Tcl] 8.6-]} {return} -package ifneeded http 2.9.3 [list tclPkgSetup $dir http 2.9.3 {{http.tcl source {::http::config ::http::formatQuery ::http::geturl ::http::reset ::http::wait ::http::register ::http::unregister ::http::mapReply}}}] +package ifneeded http 2.10.0a1 [list tclPkgSetup $dir http 2.10.0a1 {{http.tcl source {::http::config ::http::formatQuery ::http::geturl ::http::reset ::http::wait ::http::register ::http::unregister ::http::mapReply}}}] diff --git a/library/init.tcl b/library/init.tcl index e62d05d..09dd6a4 100644 --- a/library/init.tcl +++ b/library/init.tcl @@ -112,7 +112,7 @@ if {[interp issafe]} { foreach cmd {add format scan} { proc ::tcl::clock::$cmd args { variable TclLibDir - source -encoding utf-8 [file join $TclLibDir clock.tcl] + source [file join $TclLibDir clock.tcl] return [uplevel 1 [info level 0]] } } @@ -245,7 +245,7 @@ proc unknown args { set errInfo [string range $errInfo 0 $last-1] set tail "\"$cinfo\"" set last [string last $tail $errInfo] - if {$last + [string length $tail] != [string length $errInfo]} { + if {$last < 0 || $last + [string length $tail] != [string length $errInfo]} { return -code error -errorcode $errCode \ -errorinfo $errInfo $msg } @@ -442,6 +442,7 @@ proc auto_load_index {} { continue } else { set error [catch { + fconfigure $f -eofchar \032 set id [gets $f] if {$id eq "# Tcl autoload index file, version 2.0"} { eval [read $f] @@ -742,7 +743,7 @@ proc tcl::CopyDirectory {action src dest} { } } } else { - if {[string first $nsrc $ndest] != -1} { + if {[string first $nsrc $ndest] >= 0} { set srclen [expr {[llength [file split $nsrc]] - 1}] set ndest [lindex [file split $ndest] $srclen] if {$ndest eq [file tail $nsrc]} { diff --git a/library/install.tcl b/library/install.tcl index e62226e..26e5e68 100644 --- a/library/install.tcl +++ b/library/install.tcl @@ -35,6 +35,7 @@ proc ::practcl::_pkgindex_directory {path} { # Read the file, and override assumptions as needed ### set fin [open $file r] + fconfigure $fin -eofchar \032 set dat [read $fin] close $fin # Look for a teapot style Package statement @@ -58,6 +59,7 @@ proc ::practcl::_pkgindex_directory {path} { foreach file [glob -nocomplain $path/*.tcl] { if { [file tail $file] == "version_info.tcl" } continue set fin [open $file r] + fconfigure $fin -eofchar \032 set dat [read $fin] close $fin if {![regexp "package provide" $dat]} continue @@ -77,6 +79,7 @@ proc ::practcl::_pkgindex_directory {path} { return $buffer } set fin [open $pkgidxfile r] + fconfigure $fin -eofchar \032 set dat [read $fin] close $fin set trace 0 @@ -104,7 +107,7 @@ proc ::practcl::_pkgindex_directory {path} { } if {![regexp "package.*ifneeded" $thisline]} { # This package index contains arbitrary code - # source instead of trying to add it to the master + # source instead of trying to add it to the main # package index if {$trace} { puts "[file dirname $pkgidxfile] Arbitrary code $thisline" } return {source [file join $dir pkgIndex.tcl]} diff --git a/library/manifest.txt b/library/manifest.txt index 3a7ba54..51da565 100644 --- a/library/manifest.txt +++ b/library/manifest.txt @@ -5,9 +5,9 @@ apply {{dir} { set ::test [info script] set isafe [interp issafe] foreach {safe package version file} { - 0 http 2.9.3 {http http.tcl} + 0 http 2.10.0a1 {http http.tcl} 1 msgcat 1.7.1 {msgcat msgcat.tcl} - 1 opt 0.4.7 {opt optparse.tcl} + 1 opt 0.4.8 {opt optparse.tcl} 0 cookiejar 0.2.0 {cookiejar cookiejar.tcl} 0 tcl::idna 1.0.1 {cookiejar idna.tcl} 0 platform 1.0.14 {platform platform.tcl} diff --git a/library/opt/optparse.tcl b/library/opt/optparse.tcl index c8946fd..1639379 100644 --- a/library/opt/optparse.tcl +++ b/library/opt/optparse.tcl @@ -11,7 +11,7 @@ package require Tcl 8.5- # When this version number changes, update the pkgIndex.tcl file # and the install directory in the Makefiles. -package provide opt 0.4.7 +package provide opt 0.4.8 namespace eval ::tcl { @@ -44,8 +44,8 @@ namespace eval ::tcl { {-intflag 7} {-weirdflag "help string"} {-noStatics "Not ok to load static packages"} - {-nestedloading1 true "OK to load into nested slaves"} - {-nestedloading2 -boolean true "OK to load into nested slaves"} + {-nestedloading1 true "OK to load into nested children"} + {-nestedloading2 -boolean true "OK to load into nested children"} {-libsOK -choice {Tk SybTcl} "List of packages that can be loaded"} {-precision -int 12 "Number of digits of precision"} diff --git a/library/opt/pkgIndex.tcl b/library/opt/pkgIndex.tcl index daf9aa9..23e118c 100644 --- a/library/opt/pkgIndex.tcl +++ b/library/opt/pkgIndex.tcl @@ -9,4 +9,4 @@ # full path name of this file's directory. if {![package vsatisfies [package provide Tcl] 8.5-]} {return} -package ifneeded opt 0.4.7 [list source [file join $dir optparse.tcl]] +package ifneeded opt 0.4.8 [list source [file join $dir optparse.tcl]] diff --git a/library/package.tcl b/library/package.tcl index 6c87ec1..64fac7b 100644 --- a/library/package.tcl +++ b/library/package.tcl @@ -237,7 +237,7 @@ proc pkg_mkIndex {args} { $c eval [list set ::tcl::file $file] $c eval [list set ::tcl::direct $direct] - # Download needed procedures into the slave because we've just deleted + # Download needed procedures into the child because we've just deleted # the unknown procedure. This doesn't handle procedures with default # arguments. @@ -409,6 +409,7 @@ proc pkg_mkIndex {args} { } set f [open [file join $dir pkgIndex.tcl] w] + fconfigure $f -translation lf puts $f $index close $f } @@ -479,9 +480,12 @@ proc tclPkgUnknown {name args} { } set tclSeenPath($dir) 1 - # we can't use glob in safe interps, so enclose the following in a - # catch statement, where we get the pkgIndex files out of the - # subdirectories + # Get the pkgIndex.tcl files in subdirectories of auto_path directories. + # - Safe Base interpreters have a restricted "glob" command that + # works in this case. + # - The "catch" was essential when there was no safe glob and every + # call in a safe interp failed; it is retained only for corner + # cases in which the eventual call to glob returns an error. catch { foreach file [glob -directory $dir -join -nocomplain \ * pkgIndex.tcl] { @@ -593,6 +597,7 @@ proc tcl::MacOSXPkgUnknown {original name args} { set tclSeenPath($dir) 1 # get the pkgIndex files out of the subdirectories + # Safe interpreters do not use tcl::MacOSXPkgUnknown - see init.tcl. foreach file [glob -directory $dir -join -nocomplain \ * Resources Scripts pkgIndex.tcl] { set dir [file dirname $file] diff --git a/library/safe.tcl b/library/safe.tcl index 470cfa3..4c0f3b1 100644 --- a/library/safe.tcl +++ b/library/safe.tcl @@ -2,8 +2,8 @@ # # This file provide a safe loading/sourcing mechanism for safe interpreters. # It implements a virtual path mecanism to hide the real pathnames from the -# slave. It runs in a master interpreter and sets up data structure and -# aliases that will be invoked when used from a slave interpreter. +# child. It runs in a parent interpreter and sets up data structure and +# aliases that will be invoked when used from a child interpreter. # # See the safe.n man page for details. # @@ -20,7 +20,7 @@ # # Needed utilities package -package require opt 0.4.7 +package require opt 0.4.8 # Create the safe namespace namespace eval ::safe { @@ -79,25 +79,27 @@ proc ::safe::InterpNested {} { # Interface/entry point function and front end for "Create" proc ::safe::interpCreate {args} { set Args [::tcl::OptKeyParse ::safe::interpCreate $args] - InterpCreate $slave $accessPath \ + RejectExcessColons $child + InterpCreate $child $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" + if {![::interp exists $child]} { + return -code error "\"$child\" is not an interpreter" } - InterpInit $slave $accessPath \ + RejectExcessColons $child + InterpInit $child $accessPath \ [InterpStatics] [InterpNested] $deleteHook } -# Check that the given slave is "one of us" -proc ::safe::CheckInterp {slave} { - namespace upvar ::safe S$slave state - if {![info exists state] || ![::interp exists $slave]} { +# Check that the given child is "one of us" +proc ::safe::CheckInterp {child} { + namespace upvar ::safe [VarName $child] state + if {![info exists state] || ![::interp exists $child]} { return -code error \ - "\"$slave\" is not an interpreter managed by ::safe::" + "\"$child\" is not an interpreter managed by ::safe::" } } @@ -119,11 +121,11 @@ proc ::safe::interpConfigure {args} { 1 { # If we have exactly 1 argument the semantic is to return all # the current configuration. We still call OptKeyParse though - # we know that "slave" is our given argument because it also + # we know that "child" is our given argument because it also # checks for the "-help" option. set Args [::tcl::OptKeyParse ::safe::interpIC $args] - CheckInterp $slave - namespace upvar ::safe S$slave state + CheckInterp $child + namespace upvar ::safe [VarName $child] state return [join [list \ [list -accessPath $state(access_path)] \ @@ -134,7 +136,7 @@ proc ::safe::interpConfigure {args} { 2 { # If we have exactly 2 arguments the semantic is a "configure # get" - lassign $args slave arg + lassign $args child arg # get the flag sub program (we 'know' about Opt's internal # representation of data) @@ -145,8 +147,8 @@ proc ::safe::interpConfigure {args} { } elseif {$hits == 0} { return -code error [::tcl::OptFlagUsage $desc $arg] } - CheckInterp $slave - namespace upvar ::safe S$slave state + CheckInterp $child + namespace upvar ::safe [VarName $child] state set item [::tcl::OptCurDesc $desc] set name [::tcl::OptName $item] @@ -186,16 +188,16 @@ proc ::safe::interpConfigure {args} { # Otherwise we want to parse the arguments like init and # create did set Args [::tcl::OptKeyParse ::safe::interpIC $args] - CheckInterp $slave - namespace upvar ::safe S$slave state + CheckInterp $child + namespace upvar ::safe [VarName $child] state # Get the current (and not the default) values of whatever has # not been given: if {![::tcl::OptProcArgGiven -accessPath]} { - set doreset 1 + set doreset 0 set accessPath $state(access_path) } else { - set doreset 0 + set doreset 1 } if { ![::tcl::OptProcArgGiven -statics] @@ -217,15 +219,34 @@ proc ::safe::interpConfigure {args} { set deleteHook $state(cleanupHook) } # we can now reconfigure : - InterpSetConfig $slave $accessPath $statics $nested $deleteHook - # auto_reset the slave (to completly synch the new access_path) + InterpSetConfig $child $accessPath $statics $nested $deleteHook + # auto_reset the child (to completly synch the new access_path) if {$doreset} { - if {[catch {::interp eval $slave {auto_reset}} msg]} { - Log $slave "auto_reset failed: $msg" + if {[catch {::interp eval $child {auto_reset}} msg]} { + Log $child "auto_reset failed: $msg" } else { - Log $slave "successful auto_reset" NOTICE + Log $child "successful auto_reset" NOTICE + } + + # Sync the paths used to search for Tcl modules. + ::interp eval $child {tcl::tm::path remove {*}[tcl::tm::list]} + if {[llength $state(tm_path_child)] > 0} { + ::interp eval $child [list \ + ::tcl::tm::add {*}[lreverse $state(tm_path_child)]] + } + + # Remove stale "package ifneeded" data for non-loaded packages. + # - Not for loaded packages, because "package forget" erases + # data from "package provide" as well as "package ifneeded". + # - This is OK because the script cannot reload any version of + # the package unless it first does "package forget". + foreach pkg [::interp eval $child {package names}] { + if {[::interp eval $child [list package provide $pkg]] eq ""} { + ::interp eval $child [list package forget $pkg] + } } } + return } } } @@ -239,17 +260,17 @@ proc ::safe::interpConfigure {args} { # # safe::InterpCreate : doing the real job # -# This procedure creates a safe slave and initializes it with the safe +# This procedure creates a safe interpreter and initializes it with the safe # base aliases. -# NB: slave name must be simple alphanumeric string, no spaces, no (), no +# NB: child name must be simple alphanumeric string, no spaces, no (), no # {},... {because the state array is stored as part of the name} # -# Returns the slave name. +# Returns the child name. # # Optional Arguments : -# + slave name : if empty, generated name will be used +# + child name : if empty, generated name will be used # + access_path: path list controlling where load/source can occur, -# if empty: the master auto_path will be used. +# if empty: the parent auto_path will be used. # + staticsok : flag, if 0 :no static package can be loaded (load {} Xxx) # if 1 :static packages are ok. # + nestedok: flag, if 0 :no loading to sub-sub interps (load xx xx sub) @@ -257,35 +278,37 @@ proc ::safe::interpConfigure {args} { # use the full name and no indent so auto_mkIndex can find us proc ::safe::InterpCreate { - slave + child access_path staticsok nestedok deletehook } { - # Create the slave. - if {$slave ne ""} { - ::interp create -safe $slave + # Create the child. + # If evaluated in ::safe, the interpreter command for foo is ::foo; + # but for foo::bar is safe::foo::bar. So evaluate in :: instead. + if {$child ne ""} { + namespace eval :: [list ::interp create -safe $child] } else { - # empty argument: generate slave name - set slave [::interp create -safe] + # empty argument: generate child name + set child [::interp create -safe] } - Log $slave "Created" NOTICE + Log $child "Created" NOTICE - # Initialize it. (returns slave name) - InterpInit $slave $access_path $staticsok $nestedok $deletehook + # Initialize it. (returns child name) + InterpInit $child $access_path $staticsok $nestedok $deletehook } # # InterpSetConfig (was setAccessPath) : -# Sets up slave virtual auto_path and corresponding structure within -# the master. Also sets the tcl_library in the slave to be the first +# Sets up child virtual auto_path and corresponding structure within +# the parent. Also sets the tcl_library in the child to be the first # directory in the path. -# NB: If you change the path after the slave has been initialized you -# probably need to call "auto_reset" in the slave in order that it gets +# NB: If you change the path after the child has been initialized you +# probably need to call "auto_reset" in the child in order that it gets # the right auto_index() array values. -proc ::safe::InterpSetConfig {slave access_path staticsok nestedok deletehook} { +proc ::safe::InterpSetConfig {child access_path staticsok nestedok deletehook} { global auto_path # determine and store the access path if empty @@ -295,48 +318,48 @@ proc ::safe::InterpSetConfig {slave access_path staticsok nestedok deletehook} { # Make sure that tcl_library is in auto_path and at the first # position (needed by setAccessPath) set where [lsearch -exact $access_path [info library]] - if {$where == -1} { + if {$where < 0} { # not found, add it. set access_path [linsert $access_path 0 [info library]] - Log $slave "tcl_library was not in auto_path,\ - added it to slave's access_path" NOTICE + Log $child "tcl_library was not in auto_path,\ + added it to child's access_path" NOTICE } elseif {$where != 0} { # not first, move it first set access_path [linsert \ [lreplace $access_path $where $where] \ 0 [info library]] - Log $slave "tcl_libray was not in first in auto_path,\ - moved it to front of slave's access_path" NOTICE + Log $child "tcl_libray was not in first in auto_path,\ + moved it to front of child's access_path" NOTICE } # Add 1st level sub dirs (will searched by auto loading from tcl - # code in the slave using glob and thus fail, so we add them here + # code in the child using glob and thus fail, so we add them here # so by default it works the same). set access_path [AddSubDirs $access_path] } - Log $slave "Setting accessPath=($access_path) staticsok=$staticsok\ + Log $child "Setting accessPath=($access_path) staticsok=$staticsok\ nestedok=$nestedok deletehook=($deletehook)" NOTICE - namespace upvar ::safe S$slave state + namespace upvar ::safe [VarName $child] state # clear old autopath if it existed # build new one # Extend the access list with the paths used to look for Tcl Modules. # We save the virtual form separately as well, as syncing it with the - # slave has to be defered until the necessary commands are present for + # child has to be defered until the necessary commands are present for # setup. set norm_access_path {} - set slave_access_path {} + set child_access_path {} set map_access_path {} set remap_access_path {} - set slave_tm_path {} + set child_tm_path {} set i 0 foreach dir $access_path { set token [PathToken $i] - lappend slave_access_path $token + lappend child_access_path $token lappend map_access_path $token $dir lappend remap_access_path $dir $token lappend norm_access_path [file normalize $dir] @@ -344,6 +367,7 @@ proc ::safe::InterpSetConfig {slave access_path staticsok nestedok deletehook} { } set morepaths [::tcl::tm::list] + set firstpass 1 while {[llength $morepaths]} { set addpaths $morepaths set morepaths {} @@ -352,16 +376,27 @@ proc ::safe::InterpSetConfig {slave access_path staticsok nestedok deletehook} { # Prevent the addition of dirs on the tm list to the # result if they are already known. if {[dict exists $remap_access_path $dir]} { + if {$firstpass} { + # $dir is in [::tcl::tm::list] and belongs in the child_tm_path. + # Later passes handle subdirectories, which belong in the + # access path but not in the module path. + lappend child_tm_path [dict get $remap_access_path $dir] + } continue } set token [PathToken $i] lappend access_path $dir - lappend slave_access_path $token + lappend child_access_path $token lappend map_access_path $token $dir lappend remap_access_path $dir $token lappend norm_access_path [file normalize $dir] - lappend slave_tm_path $token + if {$firstpass} { + # $dir is in [::tcl::tm::list] and belongs in the child_tm_path. + # Later passes handle subdirectories, which belong in the + # access path but not in the module path. + lappend child_tm_path $token + } incr i # [Bug 2854929] @@ -372,19 +407,21 @@ proc ::safe::InterpSetConfig {slave access_path staticsok nestedok deletehook} { # subdirectories. 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(access_path,child) $child_access_path + set state(tm_path_child) $child_tm_path set state(staticsok) $staticsok set state(nestedok) $nestedok set state(cleanupHook) $deletehook - SyncAccessPath $slave + SyncAccessPath $child + return } # @@ -392,11 +429,12 @@ proc ::safe::InterpSetConfig {slave access_path staticsok nestedok deletehook} { # FindInAccessPath: # Search for a real directory and returns its virtual Id (including the # "$") -proc ::safe::interpFindInAccessPath {slave path} { - namespace upvar ::safe S$slave state +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 $access_path" + return -code error "$path not found in access path" } return [dict get $state(access_path,remap) $path] @@ -406,10 +444,11 @@ proc ::safe::interpFindInAccessPath {slave path} { # addToAccessPath: # add (if needed) a real directory to access path and return its # virtual token (including the "$"). -proc ::safe::interpAddToAccessPath {slave path} { +proc ::safe::interpAddToAccessPath {child path} { # first check if the directory is already in there # (inlined interpFindInAccessPath). - namespace upvar ::safe S$slave state + CheckInterp $child + namespace upvar ::safe [VarName $child] state if {[dict exists $state(access_path,remap) $path]} { return [dict get $state(access_path,remap) $path] @@ -419,12 +458,12 @@ proc ::safe::interpAddToAccessPath {slave path} { set token [PathToken [llength $state(access_path)]] lappend state(access_path) $path - lappend state(access_path,slave) $token + lappend state(access_path,child) $token lappend state(access_path,map) $token $path lappend state(access_path,remap) $path $token lappend state(access_path,norm) [file normalize $path] - SyncAccessPath $slave + SyncAccessPath $child return $token } @@ -432,25 +471,25 @@ proc ::safe::interpAddToAccessPath {slave path} { # interpreter. It is useful when you want to install the safe base aliases # into a preexisting safe interpreter. proc ::safe::InterpInit { - slave + child access_path staticsok nestedok deletehook } { # Configure will generate an access_path when access_path is empty. - InterpSetConfig $slave $access_path $staticsok $nestedok $deletehook + InterpSetConfig $child $access_path $staticsok $nestedok $deletehook # NB we need to add [namespace current], aliases are always absolute # paths. - # These aliases let the slave load files to define new commands - # This alias lets the slave use the encoding names, convertfrom, + # These aliases let the child load files to define new commands + # This alias lets the child use the encoding names, convertfrom, # convertto, and system, but not "encoding system <name>" to set the # system encoding. # Handling Tcl Modules, we need a restricted form of Glob. # This alias interposes on the 'exit' command and cleanly terminates - # the slave. + # the child. foreach {command alias} { source AliasSource @@ -458,60 +497,60 @@ proc ::safe::InterpInit { exit interpDelete glob AliasGlob } { - ::interp alias $slave $command {} [namespace current]::$alias $slave + ::interp alias $child $command {} [namespace current]::$alias $child } # UGLY POINT! These commands are safe (they're ensembles with unsafe # subcommands), but is assumed to not be by existing policies so it is # hidden by default. Hack it... foreach command {encoding file} { - ::interp alias $slave $command {} interp invokehidden $slave $command + ::interp alias $child $command {} interp invokehidden $child $command } - # This alias lets the slave have access to a subset of the 'file' + # This alias lets the child have access to a subset of the 'file' # command functionality. foreach subcommand {dirname extension rootname tail} { - ::interp alias $slave ::tcl::file::$subcommand {} \ - ::safe::AliasFileSubcommand $slave $subcommand + ::interp alias $child ::tcl::file::$subcommand {} \ + ::safe::AliasFileSubcommand $child $subcommand } # Subcommand of 'encoding' that has special handling; [encoding system] is # OK provided it has no other arguments passed to it. - ::interp alias $slave ::tcl::encoding::system {} \ - ::safe::AliasEncodingSystem $slave + ::interp alias $child ::tcl::encoding::system {} \ + ::safe::AliasEncodingSystem $child # Subcommands of info - ::interp alias $slave ::tcl::info::nameofexecutable {} \ - ::safe::AliasExeName $slave + ::interp alias $child ::tcl::info::nameofexecutable {} \ + ::safe::AliasExeName $child - # The allowed slave variables already have been set by Tcl_MakeSafe(3) + # The allowed child variables already have been set by Tcl_MakeSafe(3) - # Source init.tcl and tm.tcl into the slave, to get auto_load and + # Source init.tcl and tm.tcl into the child, to get auto_load and # other procedures defined: - if {[catch {::interp eval $slave { + if {[catch {::interp eval $child { source [file join $tcl_library init.tcl] }} msg opt]} { - Log $slave "can't source init.tcl ($msg)" - return -options $opt "can't source init.tcl into slave $slave ($msg)" + Log $child "can't source init.tcl ($msg)" + return -options $opt "can't source init.tcl into child $child ($msg)" } - if {[catch {::interp eval $slave { + if {[catch {::interp eval $child { source [file join $tcl_library tm.tcl] }} msg opt]} { - Log $slave "can't source tm.tcl ($msg)" - return -options $opt "can't source tm.tcl into slave $slave ($msg)" + Log $child "can't source tm.tcl ($msg)" + return -options $opt "can't source tm.tcl into child $child ($msg)" } # Sync the paths used to search for Tcl modules. This can be done only # now, after tm.tcl was loaded. - namespace upvar ::safe S$slave state - if {[llength $state(tm_path_slave)] > 0} { - ::interp eval $slave [list \ - ::tcl::tm::add {*}[lreverse $state(tm_path_slave)]] + namespace upvar ::safe [VarName $child] state + if {[llength $state(tm_path_child)] > 0} { + ::interp eval $child [list \ + ::tcl::tm::add {*}[lreverse $state(tm_path_child)]] } - return $slave + return $child } # Add (only if needed, avoid duplicates) 1 level of sub directories to an @@ -537,15 +576,30 @@ proc ::safe::AddSubDirs {pathList} { return $res } -# This procedure deletes a safe slave managed by Safe Tcl and cleans up -# associated state: - -proc ::safe::interpDelete {slave} { - Log $slave "About to delete" NOTICE - - namespace upvar ::safe S$slave state +# This procedure deletes a safe interpreter managed by Safe Tcl and cleans up +# associated state. +# - The command will also delete non-Safe-Base interpreters. +# - This is regrettable, but to avoid breaking existing code this should be +# amended at the next major revision by uncommenting "CheckInterp". + +proc ::safe::interpDelete {child} { + Log $child "About to delete" NOTICE + + # CheckInterp $child + namespace upvar ::safe [VarName $child] state + + # When an interpreter is deleted with [interp delete], any sub-interpreters + # are deleted automatically, but this leaves behind their data in the Safe + # Base. To clean up properly, we call safe::interpDelete recursively on each + # Safe Base sub-interpreter, so each one is deleted cleanly and not by + # the automatic mechanism built into [interp delete]. + foreach sub [interp children $child] { + if {[info exists ::safe::[VarName [list $child $sub]]]} { + ::safe::interpDelete [list $child $sub] + } + } - # If the slave has a cleanup hook registered, call it. Check the + # If the child has a cleanup hook registered, call it. Check the # existance because we might be called to delete an interp which has # not been registered with us at all @@ -556,14 +610,14 @@ proc ::safe::interpDelete {slave} { # we'll loop unset state(cleanupHook) try { - {*}$hook $slave + {*}$hook $child } on error err { - Log $slave "Delete hook error ($err)" + Log $child "Delete hook error ($err)" } } } - # Discard the global array of state associated with the slave, and + # Discard the global array of state associated with the child, and # delete the interpreter. if {[info exists state]} { @@ -572,9 +626,9 @@ proc ::safe::interpDelete {slave} { # if we have been called twice, the interp might have been deleted # already - if {[::interp exists $slave]} { - ::interp delete $slave - Log $slave "Deleted" NOTICE + if {[::interp exists $child]} { + ::interp delete $child + Log $child "Deleted" NOTICE } return @@ -600,9 +654,9 @@ proc ::safe::setLogCmd {args} { } else { # Activate logging, define proper command. - proc ::safe::Log {slave msg {type ERROR}} { + proc ::safe::Log {child msg {type ERROR}} { variable Log - {*}$Log "$type for slave $slave : $msg" + {*}$Log "$type for child $child : $msg" return } } @@ -611,24 +665,24 @@ proc ::safe::setLogCmd {args} { # ------------------- END OF PUBLIC METHODS ------------ # -# Sets the slave auto_path to the master recorded value. Also sets +# Sets the child auto_path to the parent recorded value. Also sets # tcl_library to the first token of the virtual path. # -proc ::safe::SyncAccessPath {slave} { - namespace upvar ::safe S$slave state +proc ::safe::SyncAccessPath {child} { + namespace upvar ::safe [VarName $child] state - set slave_access_path $state(access_path,slave) - ::interp eval $slave [list set auto_path $slave_access_path] + set child_access_path $state(access_path,child) + ::interp eval $child [list set auto_path $child_access_path] - Log $slave "auto_path in $slave has been set to $slave_access_path"\ + Log $child "auto_path in $child has been set to $child_access_path"\ NOTICE # This code assumes that info library is the first element in the # list of auto_path's. See -> InterpSetConfig for the code which # ensures this condition. - ::interp eval $slave [list \ - set tcl_library [lindex $slave_access_path 0]] + ::interp eval $child [list \ + set tcl_library [lindex $child_access_path 0]] } # Returns the virtual token for directory number N. @@ -641,8 +695,8 @@ proc ::safe::PathToken {n} { # # translate virtual path into real path # -proc ::safe::TranslatePath {slave path} { - namespace upvar ::safe S$slave state +proc ::safe::TranslatePath {child path} { + namespace upvar ::safe [VarName $child] state # somehow strip the namespaces 'functionality' out (the danger is that # we would strip valid macintosh "../" queries... : @@ -657,7 +711,7 @@ proc ::safe::TranslatePath {slave path} { # file name control (limit access to files/resources that should be a # valid tcl source file) -proc ::safe::CheckFileName {slave file} { +proc ::safe::CheckFileName {child file} { # This used to limit what can be sourced to ".tcl" and forbid files # with more than 1 dot and longer than 14 chars, but I changed that # for 8.4 as a safe interp has enough internal protection already to @@ -678,17 +732,17 @@ proc ::safe::CheckFileName {slave file} { # interpreters that are *almost* safe. In particular, it just acts to # prevent discovery of what home directories exist. -proc ::safe::AliasFileSubcommand {slave subcommand name} { +proc ::safe::AliasFileSubcommand {child subcommand name} { if {[string match ~* $name]} { set name ./$name } - tailcall ::interp invokehidden $slave tcl:file:$subcommand $name + tailcall ::interp invokehidden $child tcl:file:$subcommand $name } # AliasGlob is the target of the "glob" alias in safe interpreters. -proc ::safe::AliasGlob {slave args} { - Log $slave "GLOB ! $args" NOTICE +proc ::safe::AliasGlob {child args} { + Log $child "GLOB ! $args" NOTICE set cmd {} set at 0 array set got { @@ -710,11 +764,15 @@ proc ::safe::AliasGlob {slave args} { while {$at < [llength $args]} { switch -glob -- [set opt [lindex $args $at]] { - -nocomplain - -- - -join - -tails { + -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 @@ -728,15 +786,8 @@ proc ::safe::AliasGlob {slave args} { set virtualdir [lindex $args [incr at]] incr at } - pkgIndex.tcl { - # Oops, this is globbing a subdirectory in regular package - # search. That is not wanted. Abort, handler does catch - # already (because glob was not defined before). See - # package.tcl, lines 484ff in tclPkgUnknown. - return -code error "unknown command glob" - } -* { - Log $slave "Safe base rejecting glob option '$opt'" + Log $child "Safe base rejecting glob option '$opt'" return -code error "Safe base rejecting glob option '$opt'" } default { @@ -747,73 +798,116 @@ proc ::safe::AliasGlob {slave args} { } # Get the real path from the virtual one and check that the path is in the - # access path of that slave. Done after basic argument processing so that + # access path of that child. Done after basic argument processing so that # we know if -nocomplain is set. if {$got(-directory)} { try { - set dir [TranslatePath $slave $virtualdir] - DirInAccessPath $slave $dir + set dir [TranslatePath $child $virtualdir] + DirInAccessPath $child $dir } on error msg { - Log $slave $msg + Log $child $msg if {$got(-nocomplain)} return return -code error "permission denied" } - lappend cmd -directory $dir + if {$got(--)} { + set cmd [linsert $cmd end-1 -directory $dir] + } else { + lappend cmd -directory $dir + } + } else { + # The code after this "if ... else" block would conspire to return with + # no results in this case, if it were allowed to proceed. Instead, + # return now and reduce the number of cases to be considered later. + Log $child {option -directory must be supplied} + if {$got(-nocomplain)} return + return -code error "permission denied" } - # Apply the -join semantics ourselves + # Apply the -join semantics ourselves. if {$got(-join)} { set args [lreplace $args $at end [join [lrange $args $at end] "/"]] } - # Process remaining pattern arguments + # Process the pattern arguments. If we've done a join there is only one + # pattern argument. + set firstPattern [llength $cmd] foreach opt [lrange $args $at end] { if {![regexp $dirPartRE $opt -> thedir thefile]} { set thedir . - } elseif {[string match ~* $thedir]} { - set thedir ./$thedir + # The *.tm search comes here. } - if {$thedir eq "*" && - ($thefile eq "pkgIndex.tcl" || $thefile eq "*.tm")} { + # "Special" treatment for (joined) argument {*/pkgIndex.tcl}. + # Do the expansion of "*" here, and filter out any directories that are + # not in the access path. The outcome is to lappend to cmd a path of + # the form $virtualdir/subdir/pkgIndex.tcl for each subdirectory subdir, + # after removing any subdir that are not in the access path. + if {($thedir eq "*") && ($thefile eq "pkgIndex.tcl")} { set mapped 0 - foreach d [glob -directory [TranslatePath $slave $virtualdir] \ + foreach d [glob -directory [TranslatePath $child $virtualdir] \ -types d -tails *] { catch { - DirInAccessPath $slave \ - [TranslatePath $slave [file join $virtualdir $d]] + DirInAccessPath $child \ + [TranslatePath $child [file join $virtualdir $d]] lappend cmd [file join $d $thefile] set mapped 1 } } if {$mapped} continue + # Don't [continue] if */pkgIndex.tcl has no matches in the access + # path. The pattern will now receive the same treatment as a + # "non-special" pattern (and will fail because it includes a "*" in + # the directory name). } + # Any directory pattern that is not an exact (i.e. non-glob) match to a + # directory in the access path will be rejected here. + # - Rejections include any directory pattern that has glob matching + # patterns "*", "?", backslashes, braces or square brackets, (UNLESS + # it corresponds to a genuine directory name AND that directory is in + # the access path). + # - The only "special matching characters" that remain in patterns for + # processing by glob are in the filename tail. + # - [file join $anything ~${foo}] is ~${foo}, which is not an exact + # match to any directory in the access path. Hence directory patterns + # that begin with "~" are rejected here. Tests safe-16.[5-8] check + # that "file join" remains as required and does not expand ~${foo}. + # - Bug [3529949] relates to unwanted expansion of ~${foo} and this is + # how the present code avoids the bug. All tests safe-16.* relate. try { - DirInAccessPath $slave [TranslatePath $slave \ + DirInAccessPath $child [TranslatePath $child \ [file join $virtualdir $thedir]] } on error msg { - Log $slave $msg + Log $child $msg if {$got(-nocomplain)} continue return -code error "permission denied" } lappend cmd $opt } - Log $slave "GLOB = $cmd" NOTICE + Log $child "GLOB = $cmd" NOTICE if {$got(-nocomplain) && [llength $cmd] eq $firstPattern} { return } try { - set entries [::interp invokehidden $slave glob {*}$cmd] + # >>>>>>>>>> HERE'S THE CALL TO SAFE INTERP GLOB <<<<<<<<<< + # - Pattern arguments added to cmd have NOT been translated from tokens. + # Only the virtualdir is translated (to dir). + # - In the pkgIndex.tcl case, there is no "*" in the pattern arguments, + # which are a list of names each with tail pkgIndex.tcl. The purpose + # of the call to glob is to remove the names for which the file does + # not exist. + set entries [::interp invokehidden $child glob {*}$cmd] } on error msg { - Log $slave $msg + # This is the only place that a call with -nocomplain and no invalid + # "dash-options" can return an error. + Log $child $msg return -code error "script error" } - Log $slave "GLOB < $entries" NOTICE + Log $child "GLOB < $entries" NOTICE - # Translate path back to what the slave should see. + # Translate path back to what the child should see. set res {} set l [string length $dir] foreach p $entries { @@ -823,13 +917,13 @@ proc ::safe::AliasGlob {slave args} { lappend res $p } - Log $slave "GLOB > $res" NOTICE + Log $child "GLOB > $res" NOTICE return $res } # AliasSource is the target of the "source" alias in safe interpreters. -proc ::safe::AliasSource {slave args} { +proc ::safe::AliasSource {child args} { set argc [llength $args] # Extended for handling of Tcl Modules to allow not only "source # filename", but "source -encoding E filename" as well. @@ -838,68 +932,68 @@ proc ::safe::AliasSource {slave args} { set encoding [lindex $args 1] set at 2 if {$encoding eq "identity"} { - Log $slave "attempt to use the identity encoding" + Log $child "attempt to use the identity encoding" return -code error "permission denied" } } else { set at 0 - set encoding {} + set encoding utf-8 } if {$argc != 1} { set msg "wrong # args: should be \"source ?-encoding E? fileName\"" - Log $slave "$msg ($args)" + Log $child "$msg ($args)" return -code error $msg } set file [lindex $args $at] # get the real path from the virtual one. if {[catch { - set realfile [TranslatePath $slave $file] + set realfile [TranslatePath $child $file] } msg]} { - Log $slave $msg + Log $child $msg return -code error "permission denied" } - # check that the path is in the access path of that slave + # check that the path is in the access path of that child if {[catch { - FileInAccessPath $slave $realfile + FileInAccessPath $child $realfile } msg]} { - Log $slave $msg + Log $child $msg return -code error "permission denied" } - # do the checks on the filename : + # Check that the filename exists and is readable. If it is not, deliver + # this -errorcode so that caller in tclPkgUnknown does not write a message + # to tclLog. Has no effect on other callers of ::source, which are in + # "package ifneeded" scripts. if {[catch { - CheckFileName $slave $realfile + CheckFileName $child $realfile } msg]} { - Log $slave "$realfile:$msg" - return -code error $msg + Log $child "$realfile:$msg" + return -code error -errorcode {POSIX EACCES} $msg } # Passed all the tests, lets source it. Note that we do this all manually - # because we want to control [info script] in the slave so information + # because we want to control [info script] in the child so information # doesn't leak so much. [Bug 2913625] - set old [::interp eval $slave {info script}] + 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 - } + fconfigure $f -encoding $encoding -eofchar \032 set contents [read $f] close $f - ::interp eval $slave [list info script $file] + ::interp eval $child [list info script $file] } msg opt] if {$code == 0} { - set code [catch {::interp eval $slave $contents} msg opt] + set code [catch {::interp eval $child $contents} msg opt] set replacementMsg $msg } - catch {interp eval $slave [list info script $old]} + catch {interp eval $child [list info script $old]} # Note that all non-errors are fine result codes from [source], so we must # take a little care to do it properly. [Bug 2923613] if {$code == 1} { - Log $slave $msg + Log $child $msg return -code error $replacementMsg } return -code $code -options $opt $msg @@ -907,18 +1001,18 @@ proc ::safe::AliasSource {slave args} { # AliasLoad is the target of the "load" alias in safe interpreters. -proc ::safe::AliasLoad {slave file args} { +proc ::safe::AliasLoad {child file args} { set argc [llength $args] if {$argc > 2} { set msg "load error: too many arguments" - Log $slave "$msg ($argc) {$file $args}" + Log $child "$msg ($argc) {$file $args}" return -code error $msg } # package name (can be empty if file is not). set package [lindex $args 0] - namespace upvar ::safe S$slave state + namespace upvar ::safe [VarName $child] state # Determine where to load. load use a relative interp path and {} # means self, so we can directly and safely use passed arg. @@ -927,7 +1021,7 @@ proc ::safe::AliasLoad {slave file args} { # we will try to load into a sub sub interp; check that we want to # authorize that. if {!$state(nestedok)} { - Log $slave "loading to a sub interp (nestedok)\ + Log $child "loading to a sub interp (nestedok)\ disabled (trying to load $package to $target)" return -code error "permission denied (nested load)" } @@ -938,11 +1032,11 @@ proc ::safe::AliasLoad {slave file args} { # static package loading if {$package eq ""} { set msg "load error: empty filename and no package name" - Log $slave $msg + Log $child $msg return -code error $msg } if {!$state(staticsok)} { - Log $slave "static packages loading disabled\ + Log $child "static packages loading disabled\ (trying to load $package to $target)" return -code error "permission denied (static package)" } @@ -951,36 +1045,43 @@ proc ::safe::AliasLoad {slave file args} { # get the real path from the virtual one. try { - set file [TranslatePath $slave $file] + set file [TranslatePath $child $file] } on error msg { - Log $slave $msg + Log $child $msg return -code error "permission denied" } # check the translated path try { - FileInAccessPath $slave $file + FileInAccessPath $child $file } on error msg { - Log $slave $msg + Log $child $msg return -code error "permission denied (path)" } } try { - return [::interp invokehidden $slave load $file $package $target] + return [::interp invokehidden $child load $file $package $target] } on error msg { - Log $slave $msg + # Some packages return no error message. + 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 } } # FileInAccessPath raises an error if the file is not found in the list of -# directories contained in the (master side recorded) slave's access path. +# directories contained in the (parent side recorded) child's access path. # the security here relies on "file dirname" answering the proper # result... needs checking ? -proc ::safe::FileInAccessPath {slave file} { - namespace upvar ::safe S$slave state +proc ::safe::FileInAccessPath {child file} { + namespace upvar ::safe [VarName $child] state set access_path $state(access_path) if {[file isdirectory $file]} { @@ -992,14 +1093,14 @@ proc ::safe::FileInAccessPath {slave file} { # potential pathname anomalies. set norm_parent [file normalize $parent] - namespace upvar ::safe S$slave state + 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 {slave dir} { - namespace upvar ::safe S$slave state +proc ::safe::DirInAccessPath {child dir} { + namespace upvar ::safe [VarName $child] state set access_path $state(access_path) if {[file isfile $dir]} { @@ -1010,7 +1111,7 @@ proc ::safe::DirInAccessPath {slave dir} { # potential pathname anomalies. set norm_dir [file normalize $dir] - namespace upvar ::safe S$slave state + namespace upvar ::safe [VarName $child] state if {$norm_dir ni $state(access_path,norm)} { return -code error "\"$dir\": not in access_path" } @@ -1019,35 +1120,87 @@ proc ::safe::DirInAccessPath {slave dir} { # This procedure is used to report an attempt to use an unsafe member of an # ensemble command. -proc ::safe::BadSubcommand {slave command subcommand args} { +proc ::safe::BadSubcommand {child command subcommand args} { set msg "not allowed to invoke subcommand $subcommand of $command" - Log $slave $msg + Log $child $msg return -code error -errorcode {TCL SAFE SUBCOMMAND} $msg } # AliasEncodingSystem is the target of the "encoding system" alias in safe # interpreters. -proc ::safe::AliasEncodingSystem {slave args} { +proc ::safe::AliasEncodingSystem {child args} { try { - # Must not pass extra arguments; safe slaves may not set the system - # encoding but they may read it. + # Must not pass extra arguments; safe interpreters may not set the + # system encoding but they may read it. if {[llength $args]} { return -code error -errorcode {TCL WRONGARGS} \ "wrong # args: should be \"encoding system\"" } } on error {msg options} { - Log $slave $msg + Log $child $msg return -options $options $msg } - tailcall ::interp invokehidden $slave tcl:encoding:system + tailcall ::interp invokehidden $child tcl:encoding:system } # Various minor hiding of platform features. [Bug 2913625] -proc ::safe::AliasExeName {slave} { +proc ::safe::AliasExeName {child} { return "" } +# ------------------------------------------------------------------------------ +# Using Interpreter Names with Namespace Qualifiers +# ------------------------------------------------------------------------------ +# (1) We wish to preserve compatibility with existing code, in which Safe Base +# interpreter names have no namespace qualifiers. +# (2) safe::interpCreate and the rest of the Safe Base previously could not +# accept namespace qualifiers in an interpreter name. +# (3) The interp command will accept namespace qualifiers in an interpreter +# name, but accepts distinct interpreters that will have the same command +# name (e.g. foo, ::foo, and :::foo) (bug 66c2e8c974). +# (4) To satisfy these constraints, Safe Base interpreter names will be fully +# qualified namespace names with no excess colons and with the leading "::" +# omitted. +# (5) Trailing "::" implies a namespace tail {}, which interp reads as {{}}. +# Reject such names. +# (6) We could: +# (a) EITHER reject usable but non-compliant names (e.g. excess colons) in +# interpCreate, interpInit; +# (b) OR accept such names and then translate to a compliant name in every +# command. +# The problem with (b) is that the user will expect to use the name with the +# interp command and will find that it is not recognised. +# E.g "interpCreate ::foo" creates interpreter "foo", and the user's name +# "::foo" works with all the Safe Base commands, but "interp eval ::foo" +# fails. +# So we choose (a). +# (7) The command +# namespace upvar ::safe S$child state +# becomes +# namespace upvar ::safe [VarName $child] state +# ------------------------------------------------------------------------------ + +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$child + return S[string map {:: @N @ @A} $child] +} + proc ::safe::Setup {} { #### # @@ -1057,7 +1210,7 @@ proc ::safe::Setup {} { # Share the descriptions set temp [::tcl::OptKeyRegister { - {-accessPath -list {} "access path for the slave"} + {-accessPath -list {} "access path for the child"} {-noStatics "prevent loading of statically linked pkgs"} {-statics true "loading of statically linked pkgs"} {-nestedLoadOk "allow nested loading"} @@ -1065,18 +1218,18 @@ proc ::safe::Setup {} { {-deleteHook -script {} "delete hook"} }] - # create case (slave is optional) + # create case (child is optional) ::tcl::OptKeyRegister { - {?slave? -name {} "name of the slave (optional)"} + {?child? -name {} "name of the child (optional)"} } ::safe::interpCreate # adding the flags sub programs to the command program (relying on Opt's # internal implementation details) lappend ::tcl::OptDesc(::safe::interpCreate) $::tcl::OptDesc($temp) - # init and configure (slave is needed) + # init and configure (child is needed) ::tcl::OptKeyRegister { - {slave -name {} "name of the slave"} + {child -name {} "name of the child"} } ::safe::interpIC # adding the flags sub programs to the command program (relying on Opt's @@ -1106,20 +1259,20 @@ namespace eval ::safe { # Log command, set via 'setLogCmd'. Logging is disabled when empty. variable Log {} - # The package maintains a state array per slave interp under its + # The package maintains a state array per child interp under its # control. The name of this array is S<interp-name>. This array is # brought into scope where needed, using 'namespace upvar'. The S - # prefix is used to avoid that a slave interp called "Log" smashes + # prefix is used to avoid that a child interp called "Log" smashes # the "Log" variable. # # The array's elements are: # - # access_path : List of paths accessible to the slave. + # access_path : List of paths accessible to the child. # access_path,norm : Ditto, in normalized form. - # access_path,slave : Ditto, as the path tokens as seen by the slave. + # access_path,child : Ditto, as the path tokens as seen by the child. # access_path,map : dict ( token -> path ) # access_path,remap : dict ( path -> token ) - # tm_path_slave : List of TM root directories, as tokens seen by the slave. + # tm_path_child : List of TM root directories, as tokens seen by the child. # staticsok : Value of option -statics # nestedok : Value of option -nested # cleanupHook : Value of option -deleteHook diff --git a/library/tcltest/tcltest.tcl b/library/tcltest/tcltest.tcl index c894ff1..4df25e4 100644 --- a/library/tcltest/tcltest.tcl +++ b/library/tcltest/tcltest.tcl @@ -640,7 +640,7 @@ namespace eval tcltest { proc IsVerbose {level} { variable Option - return [expr {[lsearch -exact $Option(-verbose) $level] != -1}] + return [expr {[lsearch -exact $Option(-verbose) $level] >= 0}] } # Default verbosity is to show bodies of failed tests @@ -2798,7 +2798,6 @@ proc tcltest::runAllTests { {shell ""} } { variable numTests variable failFiles variable DefaultValue - set failFilesAccum {} FillFilesExisted if {[llength [info level 0]] == 1} { @@ -2854,8 +2853,18 @@ proc tcltest::runAllTests { {shell ""} } { flush [outputChannel] if {[singleProcess]} { - incr numTestFiles - uplevel 1 [list ::source $file] + if {[catch { + incr numTestFiles + uplevel 1 [list ::source $file] + } msg]} { + puts [outputChannel] "Test file error: $msg" + # append the name of the test to a list to be reported + # later + lappend testFileFailures $file + } + if {$numTests(Failed) > 0} { + set failFilesSet 1 + } } else { # Pass along our configuration to the child processes. # EXCEPT for the -outfile, because the parent process @@ -2888,7 +2897,7 @@ proc tcltest::runAllTests { {shell ""} } { } if {$Failed > 0} { lappend failFiles $testFile - lappend failFilesAccum $testFile + set failFilesSet 1 } } elseif {[regexp [join { {^Number of tests skipped } @@ -2935,7 +2944,7 @@ proc tcltest::runAllTests { {shell ""} } { puts [outputChannel] "" puts [outputChannel] [string repeat ~ 44] } - return [expr {[info exists testFileFailures] || [llength $failFilesAccum]}] + return [expr {[info exists testFileFailures] || [info exists failFilesSet]}] } ##################################################################### @@ -3107,7 +3116,7 @@ proc tcltest::removeFile {name {directory ""}} { set fullName [file join $directory $name] DebugPuts 3 "[lindex [info level 0] 0]: removing $fullName" set idx [lsearch -exact $filesMade $fullName] - if {$idx == -1} { + if {$idx < 0} { DebugDo 1 { Warn "removeFile removing \"$fullName\":\n not created by makeFile" } @@ -3184,7 +3193,7 @@ proc tcltest::removeDirectory {name {directory ""}} { DebugPuts 3 "[lindex [info level 0] 0]: deleting $fullName" set idx [lsearch -exact $filesMade $fullName] set filesMade [lreplace $filesMade $idx $idx] - if {$idx == -1} { + if {$idx < 0} { DebugDo 1 { Warn "removeDirectory removing \"$fullName\":\n not created\ by makeDirectory" @@ -3233,8 +3242,8 @@ proc tcltest::viewFile {name {directory ""}} { # procedures that are supposed to accept strings with embedded NULL # bytes. # 2. Confirm that a string result has a certain pattern of bytes, for -# instance to confirm that "\xe0\0" in a Tcl script is stored -# internally in UTF-8 as the sequence of bytes "\xc3\xa0\xc0\x80". +# instance to confirm that "\xE0\0" in a Tcl script is stored +# internally in UTF-8 as the sequence of bytes "\xC3\xA0\xC0\x80". # # Generally, it's a bad idea to examine the bytes in a Tcl string or to # construct improperly formed strings in this manner, because it involves diff --git a/library/tm.tcl b/library/tm.tcl index 0ed3f1a..3c0ec22 100644 --- a/library/tm.tcl +++ b/library/tm.tcl @@ -212,11 +212,12 @@ proc ::tcl::tm::UnknownHandler {original name args} { } set strip [llength [file split $path]] - # We can't use glob in safe interps, so enclose the following in a - # catch statement, where we get the module files out of the - # subdirectories. In other words, Tcl Modules are not-functional - # in such an interpreter. This is the same as for the command - # "tclPkgUnknown", i.e. the search for regular packages. + # Get the module files out of the subdirectories. + # - Safe Base interpreters have a restricted "glob" command that + # works in this case. + # - The "catch" was essential when there was no safe glob and every + # call in a safe interp failed; it is retained only for corner + # cases in which the eventual call to glob returns an error. catch { # We always look for _all_ possible modules in the current @@ -266,7 +267,7 @@ proc ::tcl::tm::UnknownHandler {original name args} { # of the package file is the last element in the list. package ifneeded $pkgname $pkgversion \ - "[::list package provide $pkgname $pkgversion];[::list source -encoding utf-8 $file]" + "[::list package provide $pkgname $pkgversion];[::list source $file]" # We abort in this unknown handler only if we got a # satisfying candidate for the requested package. diff --git a/library/tzdata/Africa/Algiers b/library/tzdata/Africa/Algiers index fe4de22..b26d31c 100644 --- a/library/tzdata/Africa/Algiers +++ b/library/tzdata/Africa/Algiers @@ -2,7 +2,7 @@ set TZData(:Africa/Algiers) { {-9223372036854775808 732 0 LMT} - {-2486679072 561 0 PMT} + {-2486592732 561 0 PMT} {-1855958961 0 0 WET} {-1689814800 3600 1 WEST} {-1680397200 0 0 WET} diff --git a/library/tzdata/Africa/Casablanca b/library/tzdata/Africa/Casablanca index 05ae49f..cb60740 100644 --- a/library/tzdata/Africa/Casablanca +++ b/library/tzdata/Africa/Casablanca @@ -66,7 +66,7 @@ set TZData(:Africa/Casablanca) { {1648346400 0 1 +01} {1651975200 3600 0 +01} {1679191200 0 1 +01} - {1682215200 3600 0 +01} + {1682820000 3600 0 +01} {1710036000 0 1 +01} {1713060000 3600 0 +01} {1740276000 0 1 +01} @@ -82,7 +82,7 @@ set TZData(:Africa/Casablanca) { {1893290400 0 1 +01} {1896919200 3600 0 +01} {1924135200 0 1 +01} - {1927159200 3600 0 +01} + {1927764000 3600 0 +01} {1954980000 0 1 +01} {1958004000 3600 0 +01} {1985220000 0 1 +01} @@ -98,7 +98,7 @@ set TZData(:Africa/Casablanca) { {2138234400 0 1 +01} {2141863200 3600 0 +01} {2169079200 0 1 +01} - {2172103200 3600 0 +01} + {2172708000 3600 0 +01} {2199924000 0 1 +01} {2202948000 3600 0 +01} {2230164000 0 1 +01} @@ -114,7 +114,7 @@ set TZData(:Africa/Casablanca) { {2383178400 0 1 +01} {2386807200 3600 0 +01} {2414023200 0 1 +01} - {2417047200 3600 0 +01} + {2417652000 3600 0 +01} {2444868000 0 1 +01} {2447892000 3600 0 +01} {2475108000 0 1 +01} @@ -130,7 +130,7 @@ set TZData(:Africa/Casablanca) { {2628122400 0 1 +01} {2631751200 3600 0 +01} {2658967200 0 1 +01} - {2661991200 3600 0 +01} + {2662596000 3600 0 +01} {2689812000 0 1 +01} {2692836000 3600 0 +01} {2720052000 0 1 +01} @@ -146,7 +146,7 @@ set TZData(:Africa/Casablanca) { {2873066400 0 1 +01} {2876695200 3600 0 +01} {2903911200 0 1 +01} - {2906935200 3600 0 +01} + {2907540000 3600 0 +01} {2934756000 0 1 +01} {2937780000 3600 0 +01} {2964996000 0 1 +01} @@ -162,7 +162,7 @@ set TZData(:Africa/Casablanca) { {3118010400 0 1 +01} {3121639200 3600 0 +01} {3148855200 0 1 +01} - {3151879200 3600 0 +01} + {3152484000 3600 0 +01} {3179700000 0 1 +01} {3182724000 3600 0 +01} {3209940000 0 1 +01} @@ -178,7 +178,7 @@ set TZData(:Africa/Casablanca) { {3362954400 0 1 +01} {3366583200 3600 0 +01} {3393799200 0 1 +01} - {3396823200 3600 0 +01} + {3397428000 3600 0 +01} {3424644000 0 1 +01} {3427668000 3600 0 +01} {3454884000 0 1 +01} @@ -188,13 +188,13 @@ set TZData(:Africa/Casablanca) { {3515968800 0 1 +01} {3519597600 3600 0 +01} {3546813600 0 1 +01} - {3549837600 3600 0 +01} + {3550442400 3600 0 +01} {3577658400 0 1 +01} {3580682400 3600 0 +01} {3607898400 0 1 +01} {3611527200 3600 0 +01} {3638743200 0 1 +01} - {3641767200 3600 0 +01} + {3642372000 3600 0 +01} {3669588000 0 1 +01} {3672612000 3600 0 +01} {3699828000 0 1 +01} diff --git a/library/tzdata/Africa/El_Aaiun b/library/tzdata/Africa/El_Aaiun index 8dbbdea..fd3e88f 100644 --- a/library/tzdata/Africa/El_Aaiun +++ b/library/tzdata/Africa/El_Aaiun @@ -55,7 +55,7 @@ set TZData(:Africa/El_Aaiun) { {1648346400 0 1 +01} {1651975200 3600 0 +01} {1679191200 0 1 +01} - {1682215200 3600 0 +01} + {1682820000 3600 0 +01} {1710036000 0 1 +01} {1713060000 3600 0 +01} {1740276000 0 1 +01} @@ -71,7 +71,7 @@ set TZData(:Africa/El_Aaiun) { {1893290400 0 1 +01} {1896919200 3600 0 +01} {1924135200 0 1 +01} - {1927159200 3600 0 +01} + {1927764000 3600 0 +01} {1954980000 0 1 +01} {1958004000 3600 0 +01} {1985220000 0 1 +01} @@ -87,7 +87,7 @@ set TZData(:Africa/El_Aaiun) { {2138234400 0 1 +01} {2141863200 3600 0 +01} {2169079200 0 1 +01} - {2172103200 3600 0 +01} + {2172708000 3600 0 +01} {2199924000 0 1 +01} {2202948000 3600 0 +01} {2230164000 0 1 +01} @@ -103,7 +103,7 @@ set TZData(:Africa/El_Aaiun) { {2383178400 0 1 +01} {2386807200 3600 0 +01} {2414023200 0 1 +01} - {2417047200 3600 0 +01} + {2417652000 3600 0 +01} {2444868000 0 1 +01} {2447892000 3600 0 +01} {2475108000 0 1 +01} @@ -119,7 +119,7 @@ set TZData(:Africa/El_Aaiun) { {2628122400 0 1 +01} {2631751200 3600 0 +01} {2658967200 0 1 +01} - {2661991200 3600 0 +01} + {2662596000 3600 0 +01} {2689812000 0 1 +01} {2692836000 3600 0 +01} {2720052000 0 1 +01} @@ -135,7 +135,7 @@ set TZData(:Africa/El_Aaiun) { {2873066400 0 1 +01} {2876695200 3600 0 +01} {2903911200 0 1 +01} - {2906935200 3600 0 +01} + {2907540000 3600 0 +01} {2934756000 0 1 +01} {2937780000 3600 0 +01} {2964996000 0 1 +01} @@ -151,7 +151,7 @@ set TZData(:Africa/El_Aaiun) { {3118010400 0 1 +01} {3121639200 3600 0 +01} {3148855200 0 1 +01} - {3151879200 3600 0 +01} + {3152484000 3600 0 +01} {3179700000 0 1 +01} {3182724000 3600 0 +01} {3209940000 0 1 +01} @@ -167,7 +167,7 @@ set TZData(:Africa/El_Aaiun) { {3362954400 0 1 +01} {3366583200 3600 0 +01} {3393799200 0 1 +01} - {3396823200 3600 0 +01} + {3397428000 3600 0 +01} {3424644000 0 1 +01} {3427668000 3600 0 +01} {3454884000 0 1 +01} @@ -177,13 +177,13 @@ set TZData(:Africa/El_Aaiun) { {3515968800 0 1 +01} {3519597600 3600 0 +01} {3546813600 0 1 +01} - {3549837600 3600 0 +01} + {3550442400 3600 0 +01} {3577658400 0 1 +01} {3580682400 3600 0 +01} {3607898400 0 1 +01} {3611527200 3600 0 +01} {3638743200 0 1 +01} - {3641767200 3600 0 +01} + {3642372000 3600 0 +01} {3669588000 0 1 +01} {3672612000 3600 0 +01} {3699828000 0 1 +01} diff --git a/library/tzdata/America/Dawson b/library/tzdata/America/Dawson index 1c827ff..c8e3f26 100644 --- a/library/tzdata/America/Dawson +++ b/library/tzdata/America/Dawson @@ -93,5 +93,6 @@ set TZData(:America/Dawson) { {1541322000 -28800 0 PST} {1552212000 -25200 1 PDT} {1572771600 -28800 0 PST} - {1583661600 -25200 0 MST} + {1583661600 -25200 1 PDT} + {1604217600 -25200 0 MST} } diff --git a/library/tzdata/America/Whitehorse b/library/tzdata/America/Whitehorse index da0c0f0..498a203 100644 --- a/library/tzdata/America/Whitehorse +++ b/library/tzdata/America/Whitehorse @@ -93,5 +93,6 @@ set TZData(:America/Whitehorse) { {1541322000 -28800 0 PST} {1552212000 -25200 1 PDT} {1572771600 -28800 0 PST} - {1583661600 -25200 0 MST} + {1583661600 -25200 1 PDT} + {1604217600 -25200 0 MST} } diff --git a/library/tzdata/Antarctica/Casey b/library/tzdata/Antarctica/Casey index aa37480..56935e3 100644 --- a/library/tzdata/Antarctica/Casey +++ b/library/tzdata/Antarctica/Casey @@ -9,4 +9,9 @@ set TZData(:Antarctica/Casey) { {1329843600 28800 0 +08} {1477065600 39600 0 +11} {1520701200 28800 0 +08} + {1538856000 39600 0 +11} + {1552752000 28800 0 +08} + {1570129200 39600 0 +11} + {1583596800 28800 0 +08} + {1601740860 39600 0 +11} } diff --git a/library/tzdata/Antarctica/Macquarie b/library/tzdata/Antarctica/Macquarie index 60bf7a6..e8ed043 100644 --- a/library/tzdata/Antarctica/Macquarie +++ b/library/tzdata/Antarctica/Macquarie @@ -93,5 +93,184 @@ set TZData(:Antarctica/Macquarie) { {1223136000 39600 1 AEDT} {1238860800 36000 0 AEST} {1254585600 39600 1 AEDT} - {1270310400 39600 0 +11} + {1262264400 39600 1 AEDT} + {1293800400 39600 0 AEST} + {1301760000 36000 0 AEST} + {1317484800 39600 1 AEDT} + {1333209600 36000 0 AEST} + {1349539200 39600 1 AEDT} + {1365264000 36000 0 AEST} + {1380988800 39600 1 AEDT} + {1396713600 36000 0 AEST} + {1412438400 39600 1 AEDT} + {1428163200 36000 0 AEST} + {1443888000 39600 1 AEDT} + {1459612800 36000 0 AEST} + {1475337600 39600 1 AEDT} + {1491062400 36000 0 AEST} + {1506787200 39600 1 AEDT} + {1522512000 36000 0 AEST} + {1538841600 39600 1 AEDT} + {1554566400 36000 0 AEST} + {1570291200 39600 1 AEDT} + {1586016000 36000 0 AEST} + {1601740800 39600 1 AEDT} + {1617465600 36000 0 AEST} + {1633190400 39600 1 AEDT} + {1648915200 36000 0 AEST} + {1664640000 39600 1 AEDT} + {1680364800 36000 0 AEST} + {1696089600 39600 1 AEDT} + {1712419200 36000 0 AEST} + {1728144000 39600 1 AEDT} + {1743868800 36000 0 AEST} + {1759593600 39600 1 AEDT} + {1775318400 36000 0 AEST} + {1791043200 39600 1 AEDT} + {1806768000 36000 0 AEST} + {1822492800 39600 1 AEDT} + {1838217600 36000 0 AEST} + {1853942400 39600 1 AEDT} + {1869667200 36000 0 AEST} + {1885996800 39600 1 AEDT} + {1901721600 36000 0 AEST} + {1917446400 39600 1 AEDT} + {1933171200 36000 0 AEST} + {1948896000 39600 1 AEDT} + {1964620800 36000 0 AEST} + {1980345600 39600 1 AEDT} + {1996070400 36000 0 AEST} + {2011795200 39600 1 AEDT} + {2027520000 36000 0 AEST} + {2043244800 39600 1 AEDT} + {2058969600 36000 0 AEST} + {2075299200 39600 1 AEDT} + {2091024000 36000 0 AEST} + {2106748800 39600 1 AEDT} + {2122473600 36000 0 AEST} + {2138198400 39600 1 AEDT} + {2153923200 36000 0 AEST} + {2169648000 39600 1 AEDT} + {2185372800 36000 0 AEST} + {2201097600 39600 1 AEDT} + {2216822400 36000 0 AEST} + {2233152000 39600 1 AEDT} + {2248876800 36000 0 AEST} + {2264601600 39600 1 AEDT} + {2280326400 36000 0 AEST} + {2296051200 39600 1 AEDT} + {2311776000 36000 0 AEST} + {2327500800 39600 1 AEDT} + {2343225600 36000 0 AEST} + {2358950400 39600 1 AEDT} + {2374675200 36000 0 AEST} + {2390400000 39600 1 AEDT} + {2406124800 36000 0 AEST} + {2422454400 39600 1 AEDT} + {2438179200 36000 0 AEST} + {2453904000 39600 1 AEDT} + {2469628800 36000 0 AEST} + {2485353600 39600 1 AEDT} + {2501078400 36000 0 AEST} + {2516803200 39600 1 AEDT} + {2532528000 36000 0 AEST} + {2548252800 39600 1 AEDT} + {2563977600 36000 0 AEST} + {2579702400 39600 1 AEDT} + {2596032000 36000 0 AEST} + {2611756800 39600 1 AEDT} + {2627481600 36000 0 AEST} + {2643206400 39600 1 AEDT} + {2658931200 36000 0 AEST} + {2674656000 39600 1 AEDT} + {2690380800 36000 0 AEST} + {2706105600 39600 1 AEDT} + {2721830400 36000 0 AEST} + {2737555200 39600 1 AEDT} + {2753280000 36000 0 AEST} + {2769609600 39600 1 AEDT} + {2785334400 36000 0 AEST} + {2801059200 39600 1 AEDT} + {2816784000 36000 0 AEST} + {2832508800 39600 1 AEDT} + {2848233600 36000 0 AEST} + {2863958400 39600 1 AEDT} + {2879683200 36000 0 AEST} + {2895408000 39600 1 AEDT} + {2911132800 36000 0 AEST} + {2926857600 39600 1 AEDT} + {2942582400 36000 0 AEST} + {2958912000 39600 1 AEDT} + {2974636800 36000 0 AEST} + {2990361600 39600 1 AEDT} + {3006086400 36000 0 AEST} + {3021811200 39600 1 AEDT} + {3037536000 36000 0 AEST} + {3053260800 39600 1 AEDT} + {3068985600 36000 0 AEST} + {3084710400 39600 1 AEDT} + {3100435200 36000 0 AEST} + {3116764800 39600 1 AEDT} + {3132489600 36000 0 AEST} + {3148214400 39600 1 AEDT} + {3163939200 36000 0 AEST} + {3179664000 39600 1 AEDT} + {3195388800 36000 0 AEST} + {3211113600 39600 1 AEDT} + {3226838400 36000 0 AEST} + {3242563200 39600 1 AEDT} + {3258288000 36000 0 AEST} + {3274012800 39600 1 AEDT} + {3289737600 36000 0 AEST} + {3306067200 39600 1 AEDT} + {3321792000 36000 0 AEST} + {3337516800 39600 1 AEDT} + {3353241600 36000 0 AEST} + {3368966400 39600 1 AEDT} + {3384691200 36000 0 AEST} + {3400416000 39600 1 AEDT} + {3416140800 36000 0 AEST} + {3431865600 39600 1 AEDT} + {3447590400 36000 0 AEST} + {3463315200 39600 1 AEDT} + {3479644800 36000 0 AEST} + {3495369600 39600 1 AEDT} + {3511094400 36000 0 AEST} + {3526819200 39600 1 AEDT} + {3542544000 36000 0 AEST} + {3558268800 39600 1 AEDT} + {3573993600 36000 0 AEST} + {3589718400 39600 1 AEDT} + {3605443200 36000 0 AEST} + {3621168000 39600 1 AEDT} + {3636892800 36000 0 AEST} + {3653222400 39600 1 AEDT} + {3668947200 36000 0 AEST} + {3684672000 39600 1 AEDT} + {3700396800 36000 0 AEST} + {3716121600 39600 1 AEDT} + {3731846400 36000 0 AEST} + {3747571200 39600 1 AEDT} + {3763296000 36000 0 AEST} + {3779020800 39600 1 AEDT} + {3794745600 36000 0 AEST} + {3810470400 39600 1 AEDT} + {3826195200 36000 0 AEST} + {3842524800 39600 1 AEDT} + {3858249600 36000 0 AEST} + {3873974400 39600 1 AEDT} + {3889699200 36000 0 AEST} + {3905424000 39600 1 AEDT} + {3921148800 36000 0 AEST} + {3936873600 39600 1 AEDT} + {3952598400 36000 0 AEST} + {3968323200 39600 1 AEDT} + {3984048000 36000 0 AEST} + {4000377600 39600 1 AEDT} + {4016102400 36000 0 AEST} + {4031827200 39600 1 AEDT} + {4047552000 36000 0 AEST} + {4063276800 39600 1 AEDT} + {4079001600 36000 0 AEST} + {4094726400 39600 1 AEDT} } diff --git a/library/tzdata/Europe/Budapest b/library/tzdata/Europe/Budapest index e660ad1..4b92c5f 100644 --- a/library/tzdata/Europe/Budapest +++ b/library/tzdata/Europe/Budapest @@ -2,17 +2,19 @@ set TZData(:Europe/Budapest) { {-9223372036854775808 4580 0 LMT} - {-2500938980 3600 0 CET} + {-2498260580 3600 0 CET} {-1693706400 7200 1 CEST} {-1680483600 3600 0 CET} {-1663455600 7200 1 CEST} {-1650150000 3600 0 CET} {-1640998800 3600 0 CET} - {-1633212000 7200 1 CEST} + {-1632006000 7200 1 CEST} {-1618700400 3600 0 CET} - {-1600466400 7200 1 CEST} - {-1581202800 3600 0 CET} - {-906771600 3600 0 CET} + {-1600470000 7200 1 CEST} + {-1587250800 3600 0 CET} + {-1569711600 7200 1 CEST} + {-1555196400 3600 0 CET} + {-906775200 3600 0 CET} {-857257200 3600 0 CET} {-844556400 7200 1 CEST} {-828226800 3600 0 CET} @@ -20,33 +22,32 @@ set TZData(:Europe/Budapest) { {-796777200 3600 0 CET} {-788922000 3600 0 CET} {-778471200 7200 1 CEST} - {-762660000 3600 0 CET} + {-762656400 3600 0 CET} {-749689200 7200 1 CEST} - {-733359600 3600 0 CET} + {-733276800 3600 0 CET} {-717634800 7200 1 CEST} {-701910000 3600 0 CET} {-686185200 7200 1 CEST} {-670460400 3600 0 CET} {-654130800 7200 1 CEST} {-639010800 3600 0 CET} - {-621990000 7200 1 CEST} - {-605660400 3600 0 CET} {-492656400 7200 1 CEST} {-481168800 3600 0 CET} - {-461120400 7200 1 CEST} - {-449632800 3600 0 CET} - {-428547600 7200 1 CEST} - {-418269600 3600 0 CET} - {-397094400 7200 1 CEST} + {-461199600 7200 1 CEST} + {-449708400 3600 0 CET} + {-428540400 7200 1 CEST} + {-418258800 3600 0 CET} + {-397090800 7200 1 CEST} {-386809200 3600 0 CET} - {323827200 7200 1 CEST} - {338950800 3600 0 CET} - {354675600 7200 1 CEST} - {370400400 3600 0 CET} - {386125200 7200 1 CEST} - {401850000 3600 0 CET} - {417574800 7200 1 CEST} - {433299600 3600 0 CET} + {323823600 7200 1 CEST} + {338943600 3600 0 CET} + {354668400 7200 1 CEST} + {370393200 3600 0 CET} + {386118000 7200 1 CEST} + {401842800 3600 0 CET} + {417567600 7200 1 CEST} + {433292400 3600 0 CET} + {441759600 3600 0 CET} {449024400 7200 1 CEST} {465354000 3600 0 CET} {481078800 7200 1 CEST} diff --git a/library/tzdata/Europe/Monaco b/library/tzdata/Europe/Monaco index f887b0b..7428b2f 100644 --- a/library/tzdata/Europe/Monaco +++ b/library/tzdata/Europe/Monaco @@ -2,8 +2,8 @@ set TZData(:Europe/Monaco) { {-9223372036854775808 1772 0 LMT} - {-2486680172 561 0 PMT} - {-1855958961 0 0 WET} + {-2448318572 561 0 PMT} + {-1854403761 0 0 WET} {-1689814800 3600 1 WEST} {-1680397200 0 0 WET} {-1665363600 3600 1 WEST} diff --git a/library/tzdata/Europe/Paris b/library/tzdata/Europe/Paris index 4b22a09..7208e55 100644 --- a/library/tzdata/Europe/Paris +++ b/library/tzdata/Europe/Paris @@ -2,8 +2,8 @@ set TZData(:Europe/Paris) { {-9223372036854775808 561 0 LMT} - {-2486678901 561 0 PMT} - {-1855958901 0 0 WET} + {-2486592561 561 0 PMT} + {-1855958961 0 0 WET} {-1689814800 3600 1 WEST} {-1680397200 0 0 WET} {-1665363600 3600 1 WEST} diff --git a/library/tzdata/Pacific/Fiji b/library/tzdata/Pacific/Fiji index e316b93..a062913 100644 --- a/library/tzdata/Pacific/Fiji +++ b/library/tzdata/Pacific/Fiji @@ -29,7 +29,7 @@ set TZData(:Pacific/Fiji) { {1547301600 43200 0 +12} {1573308000 46800 1 +12} {1578751200 43200 0 +12} - {1604757600 46800 1 +12} + {1608386400 46800 1 +12} {1610805600 43200 0 +12} {1636812000 46800 1 +12} {1642255200 43200 0 +12} |