home *** CD-ROM | disk | FTP | other *** search
/ PCNET 2006 September - Disc 1 / PCNET_CD_2006_09.iso / linux / puppy-barebones-2.01r2.iso / pup_201.sfs / usr / lib / tcl8.5 / init.tcl < prev    next >
Encoding:
Text File  |  2006-06-17  |  25.1 KB  |  849 lines

  1. # init.tcl --
  2. #
  3. # Default system startup file for Tcl-based applications.  Defines
  4. # "unknown" procedure and auto-load facilities.
  5. #
  6. # RCS: @(#) $Id: init.tcl,v 1.85 2006/02/08 21:41:28 dgp Exp $
  7. #
  8. # Copyright (c) 1991-1993 The Regents of the University of California.
  9. # Copyright (c) 1994-1996 Sun Microsystems, Inc.
  10. # Copyright (c) 1998-1999 Scriptics Corporation.
  11. # Copyright (c) 2004 by Kevin B. Kenny.  All rights reserved.
  12. #
  13. # See the file "license.terms" for information on usage and redistribution
  14. # of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  15. #
  16.  
  17. if {[info commands package] == ""} {
  18.     error "version mismatch: library\nscripts expect Tcl version 7.5b1 or later but the loaded version is\nonly [info patchlevel]"
  19. }
  20. package require -exact Tcl 8.5
  21.  
  22. # Compute the auto path to use in this interpreter.
  23. # The values on the path come from several locations:
  24. #
  25. # The environment variable TCLLIBPATH
  26. #
  27. # tcl_library, which is the directory containing this init.tcl script.
  28. # [tclInit] (Tcl_Init()) searches around for the directory containing this
  29. # init.tcl and defines tcl_library to that location before sourcing it.
  30. #
  31. # The parent directory of tcl_library. Adding the parent
  32. # means that packages in peer directories will be found automatically.
  33. #
  34. # Also add the directory ../lib relative to the directory where the
  35. # executable is located.  This is meant to find binary packages for the
  36. # same architecture as the current executable.
  37. #
  38. # tcl_pkgPath, which is set by the platform-specific initialization routines
  39. #    On UNIX it is compiled in
  40. #       On Windows, it is not used
  41.  
  42. if {![info exists auto_path]} {
  43.     if {[info exists env(TCLLIBPATH)]} {
  44.     set auto_path $env(TCLLIBPATH)
  45.     } else {
  46.     set auto_path ""
  47.     }
  48. }
  49. namespace eval tcl {
  50.     variable Dir
  51.     foreach Dir [list $::tcl_library [file dirname $::tcl_library]] {
  52.     if {$Dir ni $::auto_path} {
  53.         lappend ::auto_path $Dir
  54.     }
  55.     }
  56.     set Dir [file join [file dirname [file dirname \
  57.         [info nameofexecutable]]] lib]
  58.     if {$Dir ni $::auto_path} {
  59.     lappend ::auto_path $Dir
  60.     }
  61.     catch {
  62.     foreach Dir $::tcl_pkgPath {
  63.         if {$Dir ni $::auto_path} {
  64.         lappend ::auto_path $Dir
  65.         }
  66.     }
  67.     }
  68.  
  69.     if {![interp issafe]} {
  70.         variable Path [encoding dirs]
  71.         set Dir [file join $::tcl_library encoding]
  72.         if {$Dir ni $Path} {
  73.         lappend Path $Dir
  74.         encoding dirs $Path
  75.         }
  76.     }
  77.  
  78.     # Set up the 'chan' ensemble (TIP #208).
  79.     namespace eval chan {
  80.         # TIP #219. Added methods: create, postevent.
  81.         namespace ensemble create -command ::chan -map {
  82.             blocked     ::fblocked
  83.             close       ::close
  84.             configure   ::fconfigure
  85.             copy        ::fcopy
  86.             create      ::tcl::chan::rCreate
  87.             eof         ::eof
  88.             event       ::fileevent
  89.             flush       ::flush
  90.             gets        ::gets
  91.             names       {::file channels}
  92.             postevent   ::tcl::chan::rPostevent
  93.             puts        ::puts
  94.             read        ::read
  95.             seek        ::seek
  96.             tell        ::tell
  97.             truncate    ::tcl::chan::Truncate
  98.         }
  99.     }
  100.  
  101.     # TIP #255 min and max functions
  102.     namespace eval mathfunc {
  103.     proc min {args} {
  104.         if {[llength $args] == 0} {
  105.         return -code error \
  106.             "too few arguments to math function \"min\""
  107.         }
  108.         set val Inf
  109.         foreach arg $args {
  110.         # This will handle forcing the numeric value without
  111.         # ruining the internal type of a numeric object
  112.         if {[catch {expr {double($arg)}} err]} {
  113.             return -code error $err
  114.         }
  115.         if {$arg < $val} { set val $arg }
  116.         }
  117.         return $val
  118.     }
  119.     proc max {args} {
  120.         if {[llength $args] == 0} {
  121.         return -code error \
  122.             "too few arguments to math function \"max\""
  123.         }
  124.         set val -Inf
  125.         foreach arg $args {
  126.         # This will handle forcing the numeric value without
  127.         # ruining the internal type of a numeric object
  128.         if {[catch {expr {double($arg)}} err]} {
  129.             return -code error $err
  130.         }
  131.         if {$arg > $val} { set val $arg }
  132.         }
  133.         return $val
  134.     }
  135.     }
  136. }
  137.  
  138. # Windows specific end of initialization
  139.  
  140. if {(![interp issafe]) && ($tcl_platform(platform) eq "windows")} {
  141.     namespace eval tcl {
  142.     proc EnvTraceProc {lo n1 n2 op} {
  143.         set x $::env($n2)
  144.         set ::env($lo) $x
  145.         set ::env([string toupper $lo]) $x
  146.     }
  147.     proc InitWinEnv {} {
  148.         global env tcl_platform
  149.         foreach p [array names env] {
  150.         set u [string toupper $p]
  151.         if {$u ne $p} {
  152.             switch -- $u {
  153.             COMSPEC -
  154.             PATH {
  155.                 if {![info exists env($u)]} {
  156.                 set env($u) $env($p)
  157.                 }
  158.                 trace add variable env($p) write \
  159.                     [namespace code [list EnvTraceProc $p]]
  160.                 trace add variable env($u) write \
  161.                     [namespace code [list EnvTraceProc $p]]
  162.             }
  163.             }
  164.         }
  165.         }
  166.         if {![info exists env(COMSPEC)]} {
  167.         if {$tcl_platform(os) eq "Windows NT"} {
  168.             set env(COMSPEC) cmd.exe
  169.         } else {
  170.             set env(COMSPEC) command.com
  171.         }
  172.         }
  173.     }
  174.     InitWinEnv
  175.     }
  176. }
  177.  
  178. # Setup the unknown package handler
  179.  
  180.  
  181. if {[interp issafe]} {
  182.     package unknown ::tclPkgUnknown
  183. } else {
  184.     # Set up search for Tcl Modules (TIP #189).
  185.     # and setup platform specific unknown package handlers
  186.     if {$::tcl_platform(os) eq "Darwin"
  187.         && $::tcl_platform(platform) eq "unix"} {
  188.     package unknown {::tcl::tm::UnknownHandler \
  189.         {::tcl::MacOSXPkgUnknown ::tclPkgUnknown}}
  190.     } else {
  191.     package unknown {::tcl::tm::UnknownHandler ::tclPkgUnknown}
  192.     }
  193.  
  194.     # Set up the 'clock' ensemble
  195.  
  196.     namespace eval ::tcl::clock [list variable TclLibDir $::tcl_library]
  197.  
  198.     proc clock args {
  199.     namespace eval ::tcl::clock [list namespace ensemble create -command \
  200.         [uplevel 1 [list namespace origin [lindex [info level 0] 0]]] \
  201.         -subcommands {
  202.             add clicks format microseconds milliseconds scan seconds
  203.         }]
  204.     
  205.     # Auto-loading stubs for 'clock.tcl'
  206.     
  207.     foreach cmd {add format scan} {
  208.         proc ::tcl::clock::$cmd args {
  209.         variable TclLibDir
  210.         source -encoding utf-8 [file join $TclLibDir clock.tcl]
  211.         return [uplevel 1 [info level 0]]
  212.         }
  213.     }
  214.  
  215.     return [uplevel 1 [info level 0]]
  216.     }
  217. }
  218.  
  219. # Conditionalize for presence of exec.
  220.  
  221. if {[namespace which -command exec] eq ""} {
  222.  
  223.     # Some machines do not have exec. Also, on all
  224.     # platforms, safe interpreters do not have exec.
  225.  
  226.     set auto_noexec 1
  227. }
  228.  
  229. # Define a log command (which can be overwitten to log errors
  230. # differently, specially when stderr is not available)
  231.  
  232. if {[namespace which -command tclLog] eq ""} {
  233.     proc tclLog {string} {
  234.     catch {puts stderr $string}
  235.     }
  236. }
  237.  
  238. # unknown --
  239. # This procedure is called when a Tcl command is invoked that doesn't
  240. # exist in the interpreter.  It takes the following steps to make the
  241. # command available:
  242. #
  243. #    1. See if the command has the form "namespace inscope ns cmd" and
  244. #       if so, concatenate its arguments onto the end and evaluate it.
  245. #    2. See if the autoload facility can locate the command in a
  246. #       Tcl script file.  If so, load it and execute it.
  247. #    3. If the command was invoked interactively at top-level:
  248. #        (a) see if the command exists as an executable UNIX program.
  249. #        If so, "exec" the command.
  250. #        (b) see if the command requests csh-like history substitution
  251. #        in one of the common forms !!, !<number>, or ^old^new.  If
  252. #        so, emulate csh's history substitution.
  253. #        (c) see if the command is a unique abbreviation for another
  254. #        command.  If so, invoke the command.
  255. #
  256. # Arguments:
  257. # args -    A list whose elements are the words of the original
  258. #        command, including the command name.
  259.  
  260. proc unknown args {
  261.     variable ::tcl::UnknownPending
  262.     global auto_noexec auto_noload env tcl_interactive
  263.  
  264.     # If the command word has the form "namespace inscope ns cmd"
  265.     # then concatenate its arguments onto the end and evaluate it.
  266.  
  267.     set cmd [lindex $args 0]
  268.     if {[regexp "^:*namespace\[ \t\n\]+inscope" $cmd] && [llength $cmd] == 4} {
  269.     #return -code error "You need an {expand}"
  270.         set arglist [lrange $args 1 end]
  271.     set ret [catch {uplevel 1 ::$cmd $arglist} result opts]
  272.     dict unset opts -errorinfo
  273.     dict incr opts -level
  274.     return -options $opts $result
  275.     }
  276.  
  277.     catch {set savedErrorInfo $::errorInfo}
  278.     catch {set savedErrorCode $::errorCode}
  279.     set name $cmd
  280.     if {![info exists auto_noload]} {
  281.     #
  282.     # Make sure we're not trying to load the same proc twice.
  283.     #
  284.     if {[info exists UnknownPending($name)]} {
  285.         return -code error "self-referential recursion\
  286.             in \"unknown\" for command \"$name\"";
  287.     }
  288.     set UnknownPending($name) pending;
  289.     set ret [catch {
  290.         auto_load $name [uplevel 1 {::namespace current}]
  291.     } msg opts]
  292.     unset UnknownPending($name);
  293.     if {$ret != 0} {
  294.         dict append opts -errorinfo "\n    (autoloading \"$name\")"
  295.         return -options $opts $msg
  296.     }
  297.     if {![array size UnknownPending]} {
  298.         unset UnknownPending
  299.     }
  300.     if {$msg} {
  301.         catch {set ::errorCode $savedErrorCode}
  302.         catch {set ::errorInfo $savedErrorInfo}
  303.         set code [catch {uplevel 1 $args} msg opts]
  304.         if {$code ==  1} {
  305.         #
  306.         # Compute stack trace contribution from the [uplevel].
  307.         # Note the dependence on how Tcl_AddErrorInfo, etc. 
  308.         # construct the stack trace.
  309.         #
  310.         set errorInfo [dict get $opts -errorinfo]
  311.         set errorCode [dict get $opts -errorcode]
  312.         set cinfo $args
  313.         if {[string bytelength $cinfo] > 150} {
  314.             set cinfo [string range $cinfo 0 150]
  315.             while {[string bytelength $cinfo] > 150} {
  316.             set cinfo [string range $cinfo 0 end-1]
  317.             }
  318.             append cinfo ...
  319.         }
  320.         append cinfo "\"\n    (\"uplevel\" body line 1)"
  321.         append cinfo "\n    invoked from within"
  322.         append cinfo "\n\"uplevel 1 \$args\""
  323.         #
  324.         # Try each possible form of the stack trace
  325.         # and trim the extra contribution from the matching case
  326.         #
  327.         set expect "$msg\n    while executing\n\"$cinfo"
  328.         if {$errorInfo eq $expect} {
  329.             #
  330.             # The stack has only the eval from the expanded command
  331.             # Do not generate any stack trace here.
  332.             #
  333.             dict unset opts -errorinfo
  334.             dict incr opts -level
  335.             return -options $opts $msg
  336.         }
  337.         #
  338.         # Stack trace is nested, trim off just the contribution
  339.         # from the extra "eval" of $args due to the "catch" above.
  340.         #
  341.         set expect "\n    invoked from within\n\"$cinfo"
  342.         set exlen [string length $expect]
  343.         set eilen [string length $errorInfo]
  344.         set i [expr {$eilen - $exlen - 1}]
  345.         set einfo [string range $errorInfo 0 $i]
  346.         #
  347.         # For now verify that $errorInfo consists of what we are about
  348.         # to return plus what we expected to trim off.
  349.         #
  350.         if {$errorInfo ne "$einfo$expect"} {
  351.             error "Tcl bug: unexpected stack trace in \"unknown\"" {} \
  352.             [list CORE UNKNOWN BADTRACE $einfo $expect $errorInfo]
  353.         }
  354.         return -code error -errorcode $errorCode \
  355.             -errorinfo $einfo $msg
  356.         } else {
  357.         dict incr opts -level
  358.         return -options $opts $msg
  359.         }
  360.     }
  361.     }
  362.  
  363.     if {([info level] == 1) && ([info script] eq "") \
  364.         && [info exists tcl_interactive] && $tcl_interactive} {
  365.     if {![info exists auto_noexec]} {
  366.         set new [auto_execok $name]
  367.         if {$new ne ""} {
  368.         set redir ""
  369.         if {[namespace which -command console] eq ""} {
  370.             set redir ">&@stdout <@stdin"
  371.         }
  372.         uplevel 1 [list ::catch \
  373.             [concat exec $redir $new [lrange $args 1 end]] \
  374.             ::tcl::UnknownResult ::tcl::UnknownOptions]
  375.         dict incr ::tcl::UnknownOptions -level
  376.         return -options $::tcl::UnknownOptions $::tcl::UnknownResult
  377.         }
  378.     }
  379.     if {$name eq "!!"} {
  380.         set newcmd [history event]
  381.     } elseif {[regexp {^!(.+)$} $name -> event]} {
  382.         set newcmd [history event $event]
  383.     } elseif {[regexp {^\^([^^]*)\^([^^]*)\^?$} $name -> old new]} {
  384.         set newcmd [history event -1]
  385.         catch {regsub -all -- $old $newcmd $new newcmd}
  386.     }
  387.     if {[info exists newcmd]} {
  388.         tclLog $newcmd
  389.         history change $newcmd 0
  390.         uplevel 1 [list ::catch $newcmd \
  391.             ::tcl::UnknownResult ::tcl::UnknownOptions]
  392.         dict incr ::tcl::UnknownOptions -level
  393.         return -options $::tcl::UnknownOptions $::tcl::UnknownResult
  394.     }
  395.  
  396.     set ret [catch {set candidates [info commands $name*]} msg]
  397.     if {$name eq "::"} {
  398.         set name ""
  399.     }
  400.     if {$ret != 0} {
  401.         dict append opts -errorinfo \
  402.             "\n    (expanding command prefix \"$name\" in unknown)"
  403.         return -options $opts $msg
  404.     }
  405.     # Handle empty $name separately due to strangeness in [string first]
  406.     if {$name eq ""} {
  407.         if {[llength $candidates] != 1} {
  408.         return -code error "empty command name \"\""
  409.         }
  410.         # It's not really possible to reach here.
  411.         return [uplevel 1 [lreplace $args 0 0 [lindex $candidates 0]]]
  412.     }
  413.     # Filter out bogus matches when $name contained
  414.     # a glob-special char [Bug 946952]
  415.     set cmds [list]
  416.     foreach x $candidates {
  417.         if {[string first $name $x] == 0} {
  418.         lappend cmds $x
  419.         }
  420.     }
  421.     if {[llength $cmds] == 1} {
  422.         uplevel 1 [list ::catch [lreplace $args 0 0 [lindex $cmds 0]] \
  423.             ::tcl::UnknownResult ::tcl::UnknownOptions]
  424.         dict incr ::tcl::UnknownOptions -level
  425.         return -options $::tcl::UnknownOptions $::tcl::UnknownResult
  426.     }
  427.     if {[llength $cmds]} {
  428.         return -code error "ambiguous command name \"$name\": [lsort $cmds]"
  429.     }
  430.     }
  431.     return -code error "invalid command name \"$name\""
  432. }
  433.  
  434. # auto_load --
  435. # Checks a collection of library directories to see if a procedure
  436. # is defined in one of them.  If so, it sources the appropriate
  437. # library file to create the procedure.  Returns 1 if it successfully
  438. # loaded the procedure, 0 otherwise.
  439. #
  440. # Arguments: 
  441. # cmd -            Name of the command to find and load.
  442. # namespace (optional)  The namespace where the command is being used - must be
  443. #                       a canonical namespace as returned [namespace current]
  444. #                       for instance. If not given, namespace current is used.
  445.  
  446. proc auto_load {cmd {namespace {}}} {
  447.     global auto_index auto_path
  448.  
  449.     if {$namespace eq ""} {
  450.     set namespace [uplevel 1 [list ::namespace current]]
  451.     }
  452.     set nameList [auto_qualify $cmd $namespace]
  453.     # workaround non canonical auto_index entries that might be around
  454.     # from older auto_mkindex versions
  455.     lappend nameList $cmd
  456.     foreach name $nameList {
  457.     if {[info exists auto_index($name)]} {
  458.         namespace eval :: $auto_index($name)
  459.         # There's a couple of ways to look for a command of a given
  460.         # name.  One is to use
  461.         #    info commands $name
  462.         # Unfortunately, if the name has glob-magic chars in it like *
  463.         # or [], it may not match.  For our purposes here, a better
  464.         # route is to use 
  465.         #    namespace which -command $name
  466.         if {[namespace which -command $name] ne ""} {
  467.         return 1
  468.         }
  469.     }
  470.     }
  471.     if {![info exists auto_path]} {
  472.     return 0
  473.     }
  474.  
  475.     if {![auto_load_index]} {
  476.     return 0
  477.     }
  478.     foreach name $nameList {
  479.     if {[info exists auto_index($name)]} {
  480.         namespace eval :: $auto_index($name)
  481.         if {[namespace which -command $name] ne ""} {
  482.         return 1
  483.         }
  484.     }
  485.     }
  486.     return 0
  487. }
  488.  
  489. # auto_load_index --
  490. # Loads the contents of tclIndex files on the auto_path directory
  491. # list.  This is usually invoked within auto_load to load the index
  492. # of available commands.  Returns 1 if the index is loaded, and 0 if
  493. # the index is already loaded and up to date.
  494. #
  495. # Arguments: 
  496. # None.
  497.  
  498. proc auto_load_index {} {
  499.     variable ::tcl::auto_oldpath
  500.     global auto_index auto_path
  501.  
  502.     if {[info exists auto_oldpath] && ($auto_oldpath eq $auto_path)} {
  503.     return 0
  504.     }
  505.     set auto_oldpath $auto_path
  506.  
  507.     # Check if we are a safe interpreter. In that case, we support only
  508.     # newer format tclIndex files.
  509.  
  510.     set issafe [interp issafe]
  511.     for {set i [expr {[llength $auto_path] - 1}]} {$i >= 0} {incr i -1} {
  512.     set dir [lindex $auto_path $i]
  513.     set f ""
  514.     if {$issafe} {
  515.         catch {source [file join $dir tclIndex]}
  516.     } elseif {[catch {set f [open [file join $dir tclIndex]]}]} {
  517.         continue
  518.     } else {
  519.         set error [catch {
  520.         set id [gets $f]
  521.         if {$id eq "# Tcl autoload index file, version 2.0"} {
  522.             eval [read $f]
  523.         } elseif {$id eq "# Tcl autoload index file: each line identifies a Tcl"]} {
  524.             while {[gets $f line] >= 0} {
  525.             if {([string index $line 0] eq "#") \
  526.                 || ([llength $line] != 2)} {
  527.                 continue
  528.             }
  529.             set name [lindex $line 0]
  530.             set auto_index($name) \
  531.                 "source [file join $dir [lindex $line 1]]"
  532.             }
  533.         } else {
  534.             error "[file join $dir tclIndex] isn't a proper Tcl index file"
  535.         }
  536.         } msg opts]
  537.         if {$f ne ""} {
  538.         close $f
  539.         }
  540.         if {$error} {
  541.         return -options $opts $msg
  542.         }
  543.     }
  544.     }
  545.     return 1
  546. }
  547.  
  548. # auto_qualify --
  549. #
  550. # Compute a fully qualified names list for use in the auto_index array.
  551. # For historical reasons, commands in the global namespace do not have leading
  552. # :: in the index key. The list has two elements when the command name is
  553. # relative (no leading ::) and the namespace is not the global one. Otherwise
  554. # only one name is returned (and searched in the auto_index).
  555. #
  556. # Arguments -
  557. # cmd        The command name. Can be any name accepted for command
  558. #               invocations (Like "foo::::bar").
  559. # namespace    The namespace where the command is being used - must be
  560. #               a canonical namespace as returned by [namespace current]
  561. #               for instance.
  562.  
  563. proc auto_qualify {cmd namespace} {
  564.  
  565.     # count separators and clean them up
  566.     # (making sure that foo:::::bar will be treated as foo::bar)
  567.     set n [regsub -all {::+} $cmd :: cmd]
  568.  
  569.     # Ignore namespace if the name starts with ::
  570.     # Handle special case of only leading ::
  571.  
  572.     # Before each return case we give an example of which category it is
  573.     # with the following form :
  574.     # ( inputCmd, inputNameSpace) -> output
  575.  
  576.     if {[string match ::* $cmd]} {
  577.     if {$n > 1} {
  578.         # ( ::foo::bar , * ) -> ::foo::bar
  579.         return [list $cmd]
  580.     } else {
  581.         # ( ::global , * ) -> global
  582.         return [list [string range $cmd 2 end]]
  583.     }
  584.     }
  585.     
  586.     # Potentially returning 2 elements to try  :
  587.     # (if the current namespace is not the global one)
  588.  
  589.     if {$n == 0} {
  590.     if {$namespace eq "::"} {
  591.         # ( nocolons , :: ) -> nocolons
  592.         return [list $cmd]
  593.     } else {
  594.         # ( nocolons , ::sub ) -> ::sub::nocolons nocolons
  595.         return [list ${namespace}::$cmd $cmd]
  596.     }
  597.     } elseif {$namespace eq "::"} {
  598.     #  ( foo::bar , :: ) -> ::foo::bar
  599.     return [list ::$cmd]
  600.     } else {
  601.     # ( foo::bar , ::sub ) -> ::sub::foo::bar ::foo::bar
  602.     return [list ${namespace}::$cmd ::$cmd]
  603.     }
  604. }
  605.  
  606. # auto_import --
  607. #
  608. # Invoked during "namespace import" to make see if the imported commands
  609. # reside in an autoloaded library.  If so, the commands are loaded so
  610. # that they will be available for the import links.  If not, then this
  611. # procedure does nothing.
  612. #
  613. # Arguments -
  614. # pattern    The pattern of commands being imported (like "foo::*")
  615. #               a canonical namespace as returned by [namespace current]
  616.  
  617. proc auto_import {pattern} {
  618.     global auto_index
  619.  
  620.     # If no namespace is specified, this will be an error case
  621.  
  622.     if {![string match *::* $pattern]} {
  623.     return
  624.     }
  625.  
  626.     set ns [uplevel 1 [list ::namespace current]]
  627.     set patternList [auto_qualify $pattern $ns]
  628.  
  629.     auto_load_index
  630.  
  631.     foreach pattern $patternList {
  632.         foreach name [array names auto_index $pattern] {
  633.             if {([namespace which -command $name] eq "")
  634.             && ([namespace qualifiers $pattern] eq [namespace qualifiers $name])} {
  635.                 namespace eval :: $auto_index($name)
  636.             }
  637.         }
  638.     }
  639. }
  640.  
  641. # auto_execok --
  642. #
  643. # Returns string that indicates name of program to execute if 
  644. # name corresponds to a shell builtin or an executable in the
  645. # Windows search path, or "" otherwise.  Builds an associative 
  646. # array auto_execs that caches information about previous checks, 
  647. # for speed.
  648. #
  649. # Arguments: 
  650. # name -            Name of a command.
  651.  
  652. if {$tcl_platform(platform) eq "windows"} {
  653. # Windows version.
  654. #
  655. # Note that info executable doesn't work under Windows, so we have to
  656. # look for files with .exe, .com, or .bat extensions.  Also, the path
  657. # may be in the Path or PATH environment variables, and path
  658. # components are separated with semicolons, not colons as under Unix.
  659. #
  660. proc auto_execok name {
  661.     global auto_execs env tcl_platform
  662.  
  663.     if {[info exists auto_execs($name)]} {
  664.     return $auto_execs($name)
  665.     }
  666.     set auto_execs($name) ""
  667.  
  668.     set shellBuiltins [list cls copy date del erase dir echo mkdir \
  669.         md rename ren rmdir rd time type ver vol]
  670.     if {$tcl_platform(os) eq "Windows NT"} {
  671.     # NT includes the 'start' built-in
  672.     lappend shellBuiltins "start"
  673.     }
  674.     if {[info exists env(PATHEXT)]} {
  675.     # Add an initial ; to have the {} extension check first.
  676.     set execExtensions [split ";$env(PATHEXT)" ";"]
  677.     } else {
  678.     set execExtensions [list {} .com .exe .bat]
  679.     }
  680.  
  681.     if {$name in $shellBuiltins} {
  682.     # When this is command.com for some reason on Win2K, Tcl won't
  683.     # exec it unless the case is right, which this corrects.  COMSPEC
  684.     # may not point to a real file, so do the check.
  685.     set cmd $env(COMSPEC)
  686.     if {[file exists $cmd]} {
  687.         set cmd [file attributes $cmd -shortname]
  688.     }
  689.     return [set auto_execs($name) [list $cmd /c $name]]
  690.     }
  691.  
  692.     if {[llength [file split $name]] != 1} {
  693.     foreach ext $execExtensions {
  694.         set file ${name}${ext}
  695.         if {[file exists $file] && ![file isdirectory $file]} {
  696.         return [set auto_execs($name) [list $file]]
  697.         }
  698.     }
  699.     return ""
  700.     }
  701.  
  702.     set path "[file dirname [info nameof]];.;"
  703.     if {[info exists env(WINDIR)]} {
  704.     set windir $env(WINDIR) 
  705.     }
  706.     if {[info exists windir]} {
  707.     if {$tcl_platform(os) eq "Windows NT"} {
  708.         append path "$windir/system32;"
  709.     }
  710.     append path "$windir/system;$windir;"
  711.     }
  712.  
  713.     foreach var {PATH Path path} {
  714.     if {[info exists env($var)]} {
  715.         append path ";$env($var)"
  716.     }
  717.     }
  718.  
  719.     foreach dir [split $path {;}] {
  720.     # Skip already checked directories
  721.     if {[info exists checked($dir)] || ($dir eq {})} { continue }
  722.     set checked($dir) {}
  723.     foreach ext $execExtensions {
  724.         set file [file join $dir ${name}${ext}]
  725.         if {[file exists $file] && ![file isdirectory $file]} {
  726.         return [set auto_execs($name) [list $file]]
  727.         }
  728.     }
  729.     }
  730.     return ""
  731. }
  732.  
  733. } else {
  734. # Unix version.
  735. #
  736. proc auto_execok name {
  737.     global auto_execs env
  738.  
  739.     if {[info exists auto_execs($name)]} {
  740.     return $auto_execs($name)
  741.     }
  742.     set auto_execs($name) ""
  743.     if {[llength [file split $name]] != 1} {
  744.     if {[file executable $name] && ![file isdirectory $name]} {
  745.         set auto_execs($name) [list $name]
  746.     }
  747.     return $auto_execs($name)
  748.     }
  749.     foreach dir [split $env(PATH) :] {
  750.     if {$dir eq ""} {
  751.         set dir .
  752.     }
  753.     set file [file join $dir $name]
  754.     if {[file executable $file] && ![file isdirectory $file]} {
  755.         set auto_execs($name) [list $file]
  756.         return $auto_execs($name)
  757.     }
  758.     }
  759.     return ""
  760. }
  761.  
  762. }
  763.  
  764. # ::tcl::CopyDirectory --
  765. #
  766. # This procedure is called by Tcl's core when attempts to call the
  767. # filesystem's copydirectory function fail.  The semantics of the call
  768. # are that 'dest' does not yet exist, i.e. dest should become the exact
  769. # image of src.  If dest does exist, we throw an error.  
  770. # Note that making changes to this procedure can change the results
  771. # of running Tcl's tests.
  772. #
  773. # Arguments: 
  774. # action -              "renaming" or "copying" 
  775. # src -            source directory
  776. # dest -        destination directory
  777. proc tcl::CopyDirectory {action src dest} {
  778.     set nsrc [file normalize $src]
  779.     set ndest [file normalize $dest]
  780.  
  781.     if {$action eq "renaming"} {
  782.     # Can't rename volumes.  We could give a more precise
  783.     # error message here, but that would break the test suite.
  784.     if {$nsrc in [file volumes]} {
  785.         return -code error "error $action \"$src\" to\
  786.           \"$dest\": trying to rename a volume or move a directory\
  787.           into itself"
  788.     }
  789.     }
  790.     if {[file exists $dest]} {
  791.     if {$nsrc eq $ndest} {
  792.         return -code error "error $action \"$src\" to\
  793.           \"$dest\": trying to rename a volume or move a directory\
  794.           into itself"
  795.     }
  796.     if {$action eq "copying"} {
  797.         # We used to throw an error here, but, looking more closely
  798.         # at the core copy code in tclFCmd.c, if the destination
  799.         # exists, then we should only call this function if -force
  800.         # is true, which means we just want to over-write.  So,
  801.         # the following code is now commented out.
  802.         # 
  803.         # return -code error "error $action \"$src\" to\
  804.         # \"$dest\": file already exists"
  805.     } else {
  806.         # Depending on the platform, and on the current
  807.         # working directory, the directories '.', '..'
  808.         # can be returned in various combinations.  Anyway,
  809.         # if any other file is returned, we must signal an error.
  810.         set existing [glob -nocomplain -directory $dest * .*]
  811.         lappend existing {expand}[glob -nocomplain -directory $dest \
  812.             -type hidden * .*]
  813.         foreach s $existing {
  814.         if {([file tail $s] ne ".") && ([file tail $s] ne "..")} {
  815.             return -code error "error $action \"$src\" to\
  816.               \"$dest\": file already exists"
  817.         }
  818.         }
  819.     }
  820.     } else {
  821.     if {[string first $nsrc $ndest] != -1} {
  822.         set srclen [expr {[llength [file split $nsrc]] -1}]
  823.         set ndest [lindex [file split $ndest] $srclen]
  824.         if {$ndest eq [file tail $nsrc]} {
  825.         return -code error "error $action \"$src\" to\
  826.           \"$dest\": trying to rename a volume or move a directory\
  827.           into itself"
  828.         }
  829.     }
  830.     file mkdir $dest
  831.     }
  832.     # Have to be careful to capture both visible and hidden files.
  833.     # We will also be more generous to the file system and not
  834.     # assume the hidden and non-hidden lists are non-overlapping.
  835.     # 
  836.     # On Unix 'hidden' files begin with '.'.  On other platforms
  837.     # or filesystems hidden files may have other interpretations.
  838.     set filelist [concat [glob -nocomplain -directory $src *] \
  839.       [glob -nocomplain -directory $src -types hidden *]]
  840.  
  841.     foreach s [lsort -unique $filelist] {
  842.     if {([file tail $s] ne ".") && ([file tail $s] ne "..")} {
  843.         file copy -force $s [file join $dest [file tail $s]]
  844.     }
  845.     }
  846.     return
  847. }
  848.