---- '''Version history''' * 2009/06/14: globx2 minimally returns the name of the requested folder itself (before, only subfolders where returned, if some exist) -- Att: incompatibility! * 2006/07/26: exposed glob's possibility of specifying '''more than one search mask''' to avoid double calls to globx. Backward compatible. ---- package provide Globx 0.05 proc globx {startDir {search *} {cb ""}} { set dirStack [list [file normalize $startDir]] set files {} set fc 0 while {[llength $dirStack]} { set newStack {} foreach dir $dirStack { # temporary var's only because eventually using CallBack set c [list glob -noc -typ f -dir $dir --]; eval lappend c $search; set fn [eval $c] set c [list glob -noc -typ {f hidden} -dir $dir --]; eval lappend c $search; set fh [eval $c] if {[string equal $cb ""]} { eval lappend files $fn $fh } else { foreach f [concat $fn $fh] { incr fc uplevel [list $cb $f] } } set dn [glob -noc -typ d -dir $dir *] set dh [glob -noc -typ {d hidden} -dir $dir *] # eval lappend newStack $dn $dh; # v0.01 # Wikipatch Start v0.02 --- foreach newDir [concat $dn $dh] { set theDir [file tail $newDir] if {[string equal $theDir "." ] || \ [string equal $theDir ".."]} { # Don't push this, otherwise entering an endless # loop (on UNIX, at least) } else { lappend newStack $newDir } } # Wikipatch Ende --- } set dirStack $newStack update; # keep Background alive } if {[string equal $cb ""]} { return [lsort $files] } else { return $fc } } # Die Anwendung von Wildcards hier wäre zwar möglich, aber erst auf UNTERSTER # EBENE sinnvoll bzw. wäre ganz am Ende eine Filterung des Gesamtpfads mittels # string match besser. proc globx2 {startDir {cb ""}} { set dirStack [list [file normalize $startDir]] set dirs $dirStack; # bis v0.04: {} (ACHTUNG: potentielle Inkompatibilität!) set dc 0 while {[llength $dirStack]} { set newStack {} foreach dir $dirStack { set dn [glob -noc -typ d -dir $dir -- *] set dh [glob -noc -typ {d hidden} -dir $dir -- *] if {[string equal $cb ""]} { eval lappend dirs $dn $dh } else { foreach d [concat $dn $dh] { incr dc uplevel [list $cb $d] } } foreach newDir [concat $dn $dh] { set theDir [file tail $newDir] if {[string equal $theDir "." ] || \ [string equal $theDir ".."]} { # Don't push this, otherwise entering an endless # loop (on UNIX, at least) } else { lappend newStack $newDir } } } set dirStack $newStack update } if {[string equal $cb ""]} { return [lsort $dirs] } else { return $dc } } #******************************************************************************* '''Examples:''' '''''Without a callback, directly returning the filenames as a list:''''' puts [globx c:/winnt] puts [globx c:/winnt *.dll] '''''Returning the filenames unsorted name-by-name via callback:''''' proc callback file { puts $file } puts [globx c:/winnt * callback]; # will return the number of files read This is to save memory! '''''Specifying search masks (v0.04)''''' puts [globx c:/winnt {*.dll *.sys *.exe}] ---- [ECS]: I had to include some lines to test for "." and ".." otherwise the routine loops. MH: On my platform (W2k, Tcl 8.4.6), the original routine does ''not'' loop; the glob command never returns '..' and '.'. Which platform did you test the code on? ECS: Debian Linux: Linux babylon 2.4.26-ow2 #1 Fri Jul 9 15:19:06 BRT 2004 i686 GNU/Linux TCL is 8.4.7 (samething happens with 8.4.6). In any case it is better to be safe than sorry :-)