OSDN Git Service

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