Mercurial > repos > rliterman > csp2
comparison CSP2/CSP2_env/env-d9b9114564458d9d-741b3de822f2aaca6c6caa4325c4afce/lib/tcl8.6/init.tcl @ 69:33d812a61356
planemo upload commit 2e9511a184a1ca667c7be0c6321a36dc4e3d116d
author | jpayne |
---|---|
date | Tue, 18 Mar 2025 17:55:14 -0400 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
67:0e9998148a16 | 69:33d812a61356 |
---|---|
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.13 | |
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 } |