# -*- mode: TCL; fill-column: 75; tab-width: 8; coding: iso-latin-1-unix -*- # # $Id: WinFile.tcl,v 1.4.2.1 2001/11/03 07:26:10 idiscovery Exp $ # # WinFile.tcl -- # # MS Window file access portibility routines. # # Copyright (c) 1993-1999 Ioi Kim Lam. # Copyright (c) 2000-2001 Tix Project Group. # # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. # proc tixInitFileCmpt:Win {} { global tixPriv tcl_platform if {$tcl_platform(osVersion) >= 4.0} { set tixPriv(isWin95) 1 } else { set tixPriv(isWin95) 0 } if {$tixPriv(isWin95)} { set tixPriv(WinPrefix) xx\\xx } else { set tixPriv(WinPrefix) xx } #---------------------------------------------------------------------- # # MS Windows # #---------------------------------------------------------------------- # splits a Windows directory into its hierarchical components # proc tixFSSplit {vpath} { global tixPriv set path "" if $tixPriv(isWin95) { if {![string compare $vpath xx]} { lappend path [list xx "Desktop" "C:\\Windows\\Desktop" ] return $path } if {![string compare $vpath xx\\xx]} { lappend path [list xx "Desktop" "C:\\Windows\\Desktop" ] lappend path [list xx\\xx "My Computer" "C:\\"] return $path } set prefix "xx\\xx" if {![regsub -- {^xx\\xx\\} $vpath "" dir]} { if {[regsub -- {^xx\\} $vpath "" dir]} { lappend path [list xx "Desktop" "C:\\Windows\\Desktop" ] set v "xx" set p "C:\\Windows\\Desktop" foreach d [split $dir \\] { append v \\$d append p \\$d lappend path [list $v $d $p] } return $path } } regsub -- {:$} $dir :/ dir lappend path [list xx "Desktop" "C:\\Windows\\Desktop" ] lappend path [list xx\\xx "My Computer" "C:\\"] } else { if {![string compare $vpath xx]} { lappend path [list xx "My Computer" "C:\\"] return $path } lappend path [list xx "My Computer" "C:\\"] set prefix xx regsub -- {^xx\\} $vpath "" dir regsub -- {:$} $dir :/ dir } if {![string compare $dir ""]} { return $path } if {[string compare [file pathtype $dir] "absolute"]} { error "$dir must be an absolute path" } set dirs [file split $dir] set p "" foreach d $dirs { set p [file join $p $d] regsub -all / $p \\ p set vpath $prefix\\$p regsub -- {[\\]$} $vpath "" vpath regsub -- {:/$} $d ":" d lappend path [list $vpath $d $p] } return $path } # returns true if $dir is an valid path (not equal to "") # proc tixFSValid {dir} { return [expr ![string compare $dir ""]] } # tixFSIntName # # Returns the "virtual path" of a filename # proc tixFSIntName {dir} { global tixPriv if {![string compare $dir ""]} { if $tixPriv(isWin95) { return "xx\\xx" } else { return xx } } if {[string compare [file pathtype $dir] "absolute"]} { error "$dir must be an absolute path" } if $tixPriv(isWin95) { set vpath "xx\\xx\\$dir" } else { set vpath "xx\\$dir" } regsub -- {:/$} $vpath ":" vpath regsub -- {[\\]$} $vpath "" vpath return $vpath } proc tixFSIntJoin {dir sub} { set vpath $dir\\$sub regsub -all {\\\\} $vpath \\ vpath regsub -- {:/$} $vpath : vpath regsub -- {[\\]$} $vpath "" vpath return $vpath } proc tixFSJoin {dir sub} { set p [file join $dir $sub] regsub -all / $p \\ p return $p } proc tixFSResolveName {p} { regsub -all / $p \\ p if {[regexp -- {:([^\\]|$)} $p]} { regsub : $p :\\ p } return $p } # dir: Make a listing of this directory # showSubDir: Want to list the subdirectories? # showFile: Want to list the non-directory files in this directory? # showPrevDir: Want to list ".." as well? # showHidden: Want to list the hidden files? (%% is ignored) # # return value: a list of files and/or subdirectories # proc tixFSListDir {vpath showSubDir showFile showPrevDir showHidden {pattern ""}} { global tixPriv set appPWD [pwd] set list "" if $tixPriv(isWin95) { if {![string compare $vpath xx]} { set dir C:\\Windows\\Desktop if {$showSubDir} { lappend list xx: } } elseif {![string compare $vpath xx\\xx]} { if {$showSubDir} { return [tixFSGetDrives] } else { return "" } } else { if {![regsub -- {^xx\\xx\\} $vpath "" dir]} { regsub -- {^xx\\} $vpath C:\\Windows\\Desktop\\ dir } regsub -- {:$} $dir :\\ dir } } else { if {![string compare $vpath xx]} { if {$showSubDir} { return [tixFSGetDrives] } else { return "" } } regsub -- {^xx\\} $vpath "" dir regsub -- {:$} $dir :\\ dir } if {[catch {cd $dir} err]} { # The user has entered an invalid directory # %% todo: prompt error, go back to last succeed directory cd $appPWD return "" } if {$pattern == ""} { set pattern "*" } if {[catch {set names [lsort [eval glob -nocomplain $pattern]]} err]} { # Cannot read directory # %% todo: show directory permission denied cd $appPWD return "" } catch { # We are catch'ing, just in case the "file" command returns unexpected # errors # foreach fname $names { if {![string compare . $fname]} { continue } if {![string compare ".." $fname]} { continue } if {[file isdirectory $fname]} { if $showSubDir { lappend list [file tail $fname] } } else { if $showFile { lappend list [file tail $fname] } } } } cd $appPWD if {$showSubDir && $showPrevDir && $dir != "/"} { return [tixFSMakeList $vpath $dir [lsort [concat .. $list]]] } else { return [tixFSMakeList $vpath $dir $list] } } proc tixFSMakeList {vpath dir list} { global tixPriv if $tixPriv(isWin95) { set prefix xx\\xx } else { set prefix xx } set l "" foreach file $list { if {![string compare $file xx:]} { lappend l [list xx\\xx "My Computer" "C:\\"] } else { set path [tixFSJoin $dir $file] lappend l [list $vpath\\$file $file $path] } } return $l } proc tixFSSep {} { return "\\" } proc tixFSGetDrives {} { global tixPriv if {[info exists tixPriv(drives)]} { return $tixPriv(drives) } else { set drives [list A: B:] foreach d {c d e f g h i j k l m n o p q r s t u v w x y z} { if {[file exists $d:\\]} { lappend drives [string toupper $d:] } } set tixPriv(drives) "" foreach d $drives { lappend tixPriv(drives) [list $tixPriv(WinPrefix)\\$d $d $d\\] } } return $tixPriv(drives) } #---------------------------------------------------------------------- # # OBSOLETE # #---------------------------------------------------------------------- # Directory separator # proc tixDirSep {} { return "\\" } # returns the "root directory" of this operating system # # out: intName proc tixRootDir {} { return "/" } # is an absoulte path only if it starts with a baclskash # or starts with ":" # # in: nativeName # proc tixIsAbsPath {nativeName} { set c [string index $nativeName 0] if {$c == "\\"} { return 1 } if {[string compare [string toupper $c] A] < 0} { return 0 } if {[string compare [string toupper $c] Z] > 0} { return 0 } if {[string index $nativeName 1] != ":"} { return 0 } return 1 } # returns : # proc tixWinGetFileDrive {nativeName} { set c [string index $nativeName 0] if {$c == "\\"} { return [string toupper [string range [pwd] 0 1]] } if {[string compare [string toupper $c] A] < 0} { return [string toupper [string range [pwd] 0 1]] } if {[string compare [string toupper $c] Z] > 0} { return [string toupper [string range [pwd] 0 1]] } if {[string index $nativeName 1] != ":"} { return [string toupper [string range [pwd] 0 1]] } return [string toupper [string range $nativeName 0 1]] } # returns the absolute pathname of the file # (not including the drive letter or the first backslash) # # [tixWinGetFileDrive]\\[tixWinGetFilePath] gives the complete # drive and pathname # proc tixWinGetFilePath {nativeName} { set c [string index $nativeName 0] if {$c == "\\"} { return "" } if {[string compare [string toupper $c] A] < 0} { return [tixWinGetPathFromDrive $nativeName] } if {[string compare [string toupper $c] Z] > 0} { return [tixWinGetPathFromDrive $nativeName] } if {[string index $nativeName 1] != ":"} { return [tixWinGetPathFromDrive $nativeName] } if {[string index $nativeName 2] != "\\"} { regexp -- {[A-z]:} $nativeName drive regsub -- {[A-z]:} $nativeName "" path return [tixWinGetPathFromDrive $path $drive] } regsub -- {[A-z]:[\\]} $nativeName "" path return $path } proc tixWinCurrentDrive {} { return [string range [pwd] 0 1] } proc tixWinGetPathFromDrive {path {drive ""}} { if {$drive == ""} { set drive [tixWinCurrentDrive] } # # %% currently TCL (7.5b3) does not tell what the current path # on a particular drive is return $path } # # # nativeName: native filename used in this OS, comes from the user or # application programmer # defParent: (intName) if the filename is not an absolute path, # treat it as a subfolder of $defParent # (must be an intName, must be absolute) proc tixFileIntName {nativeName {defParent ""}} { if {![tixIsAbsPath $nativeName]} { if {$defParent != ""} { if {[string index $defParent 0] != "/"} { error "Tix toolkit error: \"$defParent\" is not an absolute internal file name" } set path [tixSubFolder $defParent $nativeName] } else { set path $nativeName } } else { set path /[tixWinGetFileDrive $nativeName]\\[tixWinGetFilePath $nativeName] } set intName "" foreach name [tixFileSplit $path] { set intName [tixSubFolder $intName $name] } return $intName } # in: internal name # out: native name proc tixNativeName {intName {mustBeAbs 1}} { if {[string index $intName 0] != "/"} { if {$mustBeAbs} { error "Tix internal error: \"$intName\" is not an intName" } else { return $intName } } if {$intName == "/"} { return C:\\ } regsub -- {/[\\]} $intName "" nativeName if {[string length $nativeName] == 2} { return $nativeName\\ } else { return $nativeName } } # how a filename should be displayed # # e.g. /\C: becomes C:\\ # /\ becomes "My Computer" # /\C:\\Windows is Windows proc tixFileDisplayName {intName} { if {[string index $intName 0] != "/"} { error "Tix internal error: \"$intName\" is not an intName" } if {$intName == "/"} { return "My Computer" } regsub -- {/[\\]} $intName "" nativeName if {[string length $nativeName] == 2} { return [string toupper $nativeName\\] } else { return [file tail $nativeName] } } # in: internal name # out: a list of paths proc tixFileSplit {intName} { set l "" foreach n [split $intName /\\] { if {$n == ""} { continue } if {$n == "."} { continue } lappend l $n } while {1} { set idx [lsearch $l ".."] if {$idx == -1} { break; } set l [lreplace $l [expr $idx -1] $idx] } if {[string index $intName 0] == "/"} { return [concat "/" $l] } else { return $l } } # parent, sub: intName # proc tixSubFolder {parent sub} { if {$parent == ""} { return $sub } return $parent\\$sub } proc tixWinGetDrives {} { global tixPriv if {[info exists tixPriv(drives)]} { return $tixPriv(drives) } else { set tixPriv(drives) {A: B:} foreach d {c e d f g h i j k l m n o p q r s t u v w x y z} { if {[file exists $d:]} { lappend tixPriv(drives) [string toupper $d:] } } } return $tixPriv(drives) } # dir: Make a listing of this directory # showSubDir: Want to list the subdirectories? # showFile: Want to list the non-directory files in this directory? # showPrevDir: Want to list ".." as well? # showHidden: Want to list the hidden files? (%% is ignored) # # return value: a list of files and/or subdirectories # proc tixListDir {dir showSubDir showFile showPrevDir showHidden {pattern ""}} { set appPWD [pwd] if {$dir == "/"} { if {$showSubDir} { return [tixWinGetDrives] } else { return "" } } if {[catch {cd [tixNativeName $dir]} err]} { # The user has entered an invalid directory # %% todo: prompt error, go back to last succeed directory cd $appPWD return "" } if {$pattern == ""} { set pattern "*" } if {[catch {set names [lsort [eval glob -nocomplain $pattern]]} err]} { # Cannot read directory # %% todo: show directory permission denied cd $appPWD return "" } set list "" catch { # We are catch'ing, just in case the "file" command returns unexpected # errors # foreach fname $names { if {![string compare . $fname]} { continue } if {![string compare ".." $fname]} { continue } if {[file isdirectory $fname]} { if $showSubDir { lappend list [file tail $fname] } } else { if $showFile { lappend list [file tail $fname] } } } } cd $appPWD if {$showSubDir && $showPrevDir && $dir != "/"} { return [lsort [concat .. $list]] } else { return $list } } proc tixVerifyFile {file} { return [tixFileIntName $file] } proc tixFilePattern {args} { if {[lsearch $args allFiles] != -1} { return * } return * } } # tixWinFileEmu -- # # Emulates a MS Windows file system environemnt inside Unix # proc tixWinFileEmu {} { cd /mnt/c rename pwd __pwd rename cd __cd proc EmuConvert {path} { if {[regsub ^/mnt/c/ $path c:/ path]} { return $path } if {[regsub ^/mnt/d/ $path d:/ path]} { return $path } if {[regsub ^/mnt/c\$ $path c:/ path]} { return $path } if {[regsub ^/mnt/d\$ $path d:/ path]} { return $path } return c:/windows } proc pwd {} { return [EmuConvert [__pwd]] } proc glob {args} { } } .