figenc

[RADIOACTIVE] rsa and symmetric key encryption scripts and executables
git clone git://git.figbert.com/figenc.git
Log | Files | Refs | README

init.tcl (24432B)


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