home *** CD-ROM | disk | FTP | other *** search
/ H4CK3R 5 / hacker05 / 05_HACK_05.ISO / programacao / freewrap / TCLLIBsampleApp.exe / sample / tcllib / tcllib1.0 / fileutil / fileutil.tcl next >
Encoding:
Text File  |  2001-08-17  |  5.9 KB  |  204 lines

  1. # fileutil.tcl --
  2. #
  3. #    Tcl implementations of standard UNIX utilities.
  4. #
  5. # Copyright (c) 1998-2000 by Ajuba Solutions.
  6. #
  7. # See the file "license.terms" for information on usage and redistribution
  8. # of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  9. # RCS: @(#) $Id: fileutil.tcl,v 1.7 2001/08/02 16:38:06 andreas_kupries Exp $
  10.  
  11. package require Tcl 8
  12. package provide fileutil 1.1
  13.  
  14. namespace eval ::fileutil {
  15.     namespace export *
  16. }
  17.  
  18. # ::fileutil::grep --
  19. #
  20. #    Implementation of grep.  Adapted from the Tcler's Wiki.
  21. #
  22. # Arguments:
  23. #    pattern        pattern to search for.
  24. #    files        list of files to search; if NULL, uses stdin.
  25. #
  26. # Results:
  27. #    results        list of matches
  28.  
  29. proc ::fileutil::grep {pattern {files {}}} {
  30.     set result [list]
  31.     if {[llength $files] == 0} {
  32.     # read from stdin
  33.     set lnum 0
  34.     while {[gets stdin line] >= 0} {
  35.         incr lnum
  36.         if {[regexp -- $pattern $line]} {
  37.         lappend result "${lnum}:${line}"
  38.         }
  39.     }
  40.     } else {
  41.     foreach filename $files {
  42.         set file [open $filename r]
  43.         set lnum 0
  44.         while {[gets $file line] >= 0} {
  45.         incr lnum
  46.         if {[regexp -- $pattern $line]} {
  47.             lappend result "${filename}:${lnum}:${line}"
  48.         }
  49.         }
  50.         close $file
  51.     }
  52.     }
  53.     return $result
  54. }
  55.  
  56. # ::fileutil::find ==
  57. #
  58. # Two different implementations of this command, one for unix with its
  59. # softlinks, the other for the Win* platform. The trouble with
  60. # softlink is that they can generate circles in the directory and/or
  61. # file structure, leading a simple recursion into infinity. So we
  62. # record device/inode information for each file and directory we touch
  63. # to be able to skip it should we happen to visit it again.
  64.  
  65. # Note about the general implementation: The tcl interpreter sets a
  66. # tcl stack limit of 1000 levels to prevent infinite recursions from
  67. # running out of bounds. As this command is implemented recursively it
  68. # will fail for very deeply nested directory structures.
  69.  
  70. if {[string compare unix $tcl_platform(platform)]} {
  71.     # Not a unix platform => Original implementation
  72.     # Note: This may still fail for directories mounted via SAMBA,
  73.     # i.e. coming from a unix server.
  74.  
  75.     # ::fileutil::find --
  76.     #
  77.     #    Implementation of find.  Adapted from the Tcler's Wiki.
  78.     #
  79.     # Arguments:
  80.     #    basedir        directory to start searching from; default is .
  81.     #    filtercmd    command to use to evaluate interest in each file.
  82.     #            If NULL, all files are interesting.
  83.     #
  84.     # Results:
  85.     #    files        a list of interesting files.
  86.  
  87.     proc ::fileutil::find {{basedir .} {filtercmd {}}} {
  88.     set oldwd [pwd]
  89.     cd $basedir
  90.     set cwd [pwd]
  91.     set filenames [glob -nocomplain * .*]
  92.     set files {}
  93.     set filt [string length $filtercmd]
  94.     # If we don't remove . and .. from the file list, we'll get stuck in
  95.     # an infinite loop in an infinite loop in an infinite loop in an inf...
  96.     foreach special [list "." ".."] {
  97.         set index [lsearch -exact $filenames $special]
  98.         set filenames [lreplace $filenames $index $index]
  99.     }
  100.     foreach filename $filenames {
  101.         # Use uplevel to eval the command, not eval, so that variable 
  102.         # substitutions occur in the right context.
  103.         if {!$filt || [uplevel $filtercmd [list $filename]]} {
  104.         lappend files [file join $cwd $filename]
  105.         }
  106.         if {[file isdirectory $filename]} {
  107.         set files [concat $files [find $filename $filtercmd]]
  108.         }
  109.     }
  110.     cd $oldwd
  111.     return $files
  112.     }
  113. } else {
  114.     # Unix, record dev/inode to detect and break circles
  115.  
  116.     # ::fileutil::find --
  117.     #
  118.     #    Implementation of find.  Adapted from the Tcler's Wiki.
  119.     #
  120.     # Arguments:
  121.     #    basedir        directory to start searching from; default is .
  122.     #    filtercmd    command to use to evaluate interest in each file.
  123.     #            If NULL, all files are interesting.
  124.     #
  125.     # Results:
  126.     #    files        a list of interesting files.
  127.  
  128.     proc ::fileutil::find {{basedir .} {filtercmd {}} {nodeVar {}}} {
  129.     if {$nodeVar == {}} {
  130.         # Main call, setup the device/inode structure
  131.         array set inodes {}
  132.     } else {
  133.         # Recursive call, import the device/inode record from the caller.
  134.         upvar $nodeVar inodes
  135.     }
  136.  
  137.     set oldwd [pwd]
  138.     cd $basedir
  139.     set cwd [pwd]
  140.     set filenames [glob -nocomplain * .*]
  141.     set files {}
  142.     set filt [string length $filtercmd]
  143.     # If we don't remove . and .. from the file list, we'll get stuck in
  144.     # an infinite loop in an infinite loop in an infinite loop in an inf...
  145.     foreach special [list "." ".."] {
  146.         set index [lsearch -exact $filenames $special]
  147.         set filenames [lreplace $filenames $index $index]
  148.     }
  149.     foreach filename $filenames {
  150.         # Stat each file/directory get exact information about its identity
  151.         # (device, inode). Non-'stat'able files are either junk (link to
  152.         # non-existing target) or not readable, i.e. inaccessible. In both
  153.         # cases it makes sense to ignore them.
  154.  
  155.         if {[catch {file stat [file join $cwd $filename] stat}]} {
  156.         continue
  157.         }
  158.  
  159.         # No skip over previously recorded files/directories and
  160.         # record the new files/directories.
  161.  
  162.         set key "$stat(dev),$stat(ino)"
  163.         if {[info exists inodes($key)]} {
  164.         continue
  165.         }
  166.         set inodes($key) 1
  167.  
  168.         # Use uplevel to eval the command, not eval, so that variable 
  169.         # substitutions occur in the right context.
  170.         if {!$filt || [uplevel $filtercmd [list $filename]]} {
  171.         lappend files [file join $cwd $filename]
  172.         }
  173.         if {[file isdirectory $filename]} {
  174.         set files [concat $files [find $filename $filtercmd inodes]]
  175.         }
  176.     }
  177.     cd $oldwd
  178.     return $files
  179.     }
  180. }
  181.  
  182. # ::fileutil::cat --
  183. #
  184. #    Tcl implementation of the UNIX "cat" command.  Returns the contents
  185. #    of the specified file.
  186. #
  187. # Arguments:
  188. #    filename    name of the file to read.
  189. #
  190. # Results:
  191. #    data        data read from the file.
  192.  
  193. proc ::fileutil::cat {filename} {
  194.     # Don't bother catching errors, just let them propagate up
  195.     set fd [open $filename r]
  196.     # Use the [file size] command to get the size, which preallocates memory,
  197.     # rather than trying to grow it as the read progresses.
  198.     set data [read $fd [file size $filename]]
  199.     close $fd
  200.     return $data
  201. }
  202.  
  203.