glob $dir/* glob [file join $dir *]which both fail if $dir contains glob sensitive characters. The new syntax would be:
glob -dir $dir *which besides fixing the above problem has the added benefit of working on old MacOS, since '/' is not assumed to be the directory separator.If you want to write code using the new glob flags/options, such as glob -dir $dir -type d *, obviously your new code will no longer work with older versions of Tcl (e.g. 8.0-8.2). If you would like a compatibility layer which can be loaded into Tcl 8.0-8.2 (probably even older versions of Tcl too), overriding the old glob to emulate the new one in Tcl 8.3, here it is:New: this now adds support for '-tails' which was introduced in Tcl 8.4a3.
# Tcl 8.3 or newer have a more complex glob already.
if {[info tclversion] < 8.3} {
# we've copied this here from stringsLists.tcl to avoid some
# bad auto-loading problems if there are early startup errors.
;proc getOpts {{take_value ""} {set "set"}} {
upvar args a
upvar opts o
while {[string match \-* [set arg [lindex $a 0]]]} {
set a [lreplace $a 0 0]
if {$arg == "--"} {
return
} else {
if {[set idx [lsearch -regexp $take_value \
"^-?[string range $arg 1 end]( .*)?$"]] == -1} {
set o($arg) 1
} else {
if {[llength [set the_arg \
[lindex $take_value $idx]]] == 1} {
$set o($arg) [lindex $a 0]
set a [lreplace $a 0 0]
} else {
set numargs [expr {[lindex $the_arg 1] -1}]
$set o($arg) [lrange $a 0 $numargs]
set a [lreplace $a 0 $numargs]
}
}
}
}
}
rename glob __glob
;proc glob {args} {
getOpts {-t -types -type -dir -directory -path}
# place platform specific file separator in variable 'separator's
regexp {Z(.)Z} [file join Z Z] "" separator
if {[info exists opts(-join)]} {
unset opts(-join)
set args [list [eval file join $args]]
}
set add ""
foreach t {t type} {
if {[info exists opts(-$t)]} {
eval lappend opts(-types) $opts(-$t)
unset opts(-$t)
}
}
if {[info exists opts(-directory)]} {
set opts(-dir) $opts(-directory)
unset opts(-directory)
}
if {[info exists opts(-types)]} {
if {[set item [lsearch -exact $opts(-types) "d"]] != -1} {
set opts(-types) [lreplace $opts(-types) $item $item]
set add $separator
set isdirectory 1
}
}
if {[set nocomplain [info exists opts(-nocomplain)]]} {
unset opts(-nocomplain)
}
if {[info exists opts(-path)]} {
if {[info exists opts(-dir)]} {
error {"-directory" cannot be used with "-path"}
}
regsub -all {[][*?\{\}\\]} $opts(-path) {\\&} prefix
unset opts(-path)
} elseif {[info exists opts(-dir)]} {
regsub -all {[][*?\{\}\\]} $opts(-dir) {\\&} prefix
append prefix ${separator}
unset opts(-dir)
} else {
set prefix ""
}
if {[info exists opts(-tails)]} {
set tails [file dirname "${prefix}xx"]
unset opts(-tails)
if {![string length $prefix]} {
error {"-tails" must be used with either "-directory" or "-path"}
}
}
set res {}
foreach arg $args {
eval lappend res [__glob -nocomplain -- \
"${prefix}${arg}${add}"]
}
if {[info exists opts(-types)]} {
# we ignore arguments to -types which haven't yet been
# handled, since they are assumed to be platform
# specific
unset opts(-types)
}
if {[set llen [llength [array names opts]]]} {
set ok "-nocomplain, -join, -dir <dir>,\
-path <path>, -types <list of types>"
if {$llen > 1} {
error "bad switches \"[array names opts]\":\
must be $ok or --"
} else {
error "bad switch \"[array names opts]\":\
must be $ok or --"
}
} elseif {[llength $res]} {
if {[info exists isdirectory]} {
foreach r $res {
lappend newres [string trimright $r $separator]
}
set res $newres
}
if {[info exists tails]} {
set res [list]
set len [expr {[string length $tails]}]
foreach r $newres {
lappend res [string range $r $len end]
}
}
return $res
} elseif {$nocomplain} {
return ""
} else {
switch -- [llength $args] {
0 {
error "wrong # args: should be \"glob ?switches?\
name ?name ...?\""
}
1 {
error "no files matched glob pattern \"$args\""
}
default {
error "no files matched glob patterns \"$args\""
}
}
}
}
} else {
# Version 8.3.x have all the glob flags apart from -tails which
# should be introduced in 8.4a3. Therefore we overload glob
# here for 8.3.x-8.4a2 specifically to support -tails (which is
# quite easy).
if {([info tclversion] < 8.4) || [regexp {8\.4a[12]} [info patchlevel]]} {
# Need to add '-tails' to glob
rename glob __glob
;proc glob {args} {
set i 0
while {1} {
set str [lindex $args $i]
if {[string index $str 0] != "-"} {
break
}
switch -glob -- $str {
"--" { break }
"-n*" - "-j*" {
}
"-ty*" {
incr i
}
"-d*" {
incr i
set dir [lindex $args $i]
}
"-p*" {
incr i
set dir [file dirname [lindex $args $i]]
}
"-ta*" {
set tails $i
}
"-t" {
error {ambiguous option "-t": must be -directory, -join, -nocomplain, -path, -tails, -types, or --}
}
}
incr i
}
if {[info exists tails]} {
if {![info exists dir]} {
error {"-tails" must be used with either "-directory" or "-path"}
}
set args [lreplace $args $tails $tails]
set res [uplevel 1 [list __glob] $args]
set realres {}
set len [expr {1+ [string length $dir]}]
foreach r $res {
lappend realres [string range $r $len end]
}
return $realres
} else {
uplevel 1 [list __glob] $args
}
}
}
}I'm confused. Can you show some old code that breaks?By the way, I assume you meant to say "if you want your OLD glob code to work ..."Vince: hopefully the clarification above solves your confusion. The Tcl 8.3 changes to glob are 100% backwards compatible. The goal of this page is to provide forwards compatibility for people who write 'modern' code but still want those stuck at Tcl 8.0-8.2 to be able to use it. It handles most common uses of Tcl 8.3's glob.This approach deserves its own page IMO: Forward compatibility --jcw

