OpenCores
URL https://opencores.org/ocsvn/or1k_old/or1k_old/trunk

Subversion Repositories or1k_old

[/] [or1k_old/] [trunk/] [insight/] [tcl/] [library/] [init.tcl] - Blame information for rev 1782

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 578 markom
# init.tcl --
2
#
3
# Default system startup file for Tcl-based applications.  Defines
4
# "unknown" procedure and auto-load facilities.
5
#
6
# RCS: @(#) $Id: init.tcl,v 1.1.1.1 2002-01-16 10:25:30 markom Exp $
7
#
8
# Copyright (c) 1991-1993 The Regents of the University of California.
9
# Copyright (c) 1994-1996 Sun Microsystems, Inc.
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
if {[info commands package] == ""} {
16
    error "version mismatch: library\nscripts expect Tcl version 7.5b1 or later but the loaded version is\nonly [info patchlevel]"
17
}
18
package require -exact Tcl 8.0
19
 
20
# Compute the auto path to use in this interpreter.
21
# The values on the path come from several locations:
22
#
23
# The environment variable TCLLIBPATH
24
#
25
# tcl_library, which is the directory containing this init.tcl script.
26
# tclInitScript.h searches around for the directory containing this
27
# init.tcl and defines tcl_library to that location before sourcing it.
28
#
29
# The parent directory of tcl_library. Adding the parent
30
# means that packages in peer directories will be found automatically.
31
#
32
# tcl_pkgPath, which is set by the platform-specific initialization routines
33
#       On UNIX it is compiled in
34
#       On Windows it comes from the registry
35
#       On Macintosh it is "Tool Command Language" in the Extensions folder
36
 
37
if {![info exists auto_path]} {
38
    if {[info exist env(TCLLIBPATH)]} {
39
        set auto_path $env(TCLLIBPATH)
40
    } else {
41
        set auto_path ""
42
    }
43
}
44
foreach __dir [list [info library] [file dirname [info library]]] {
45
    if {[lsearch -exact $auto_path $__dir] < 0} {
46
        lappend auto_path $__dir
47
    }
48
}
49
if {[info exist tcl_pkgPath]} {
50
    foreach __dir $tcl_pkgPath {
51
        if {[lsearch -exact $auto_path $__dir] < 0} {
52
            lappend auto_path $__dir
53
        }
54
    }
55
}
56
unset __dir
57
 
58
# Windows specific initialization to handle case isses with envars
59
 
60
if {(![interp issafe]) && ($tcl_platform(platform) == "windows")} {
61
    namespace eval tcl {
62
        proc envTraceProc {lo n1 n2 op} {
63
            set x $::env($n2)
64
            set ::env($lo) $x
65
            set ::env([string toupper $lo]) $x
66
        }
67
    }
68
    foreach p [array names env] {
69
        set u [string toupper $p]
70
        if {$u != $p} {
71
            switch -- $u {
72
                COMSPEC -
73
                PATH {
74
                    if {![info exists env($u)]} {
75
                        set env($u) $env($p)
76
                    }
77
                    trace variable env($p) w [list tcl::envTraceProc $p]
78
                    trace variable env($u) w [list tcl::envTraceProc $p]
79
                }
80
            }
81
        }
82
    }
83
    if {[info exists p]} {
84
        unset p
85
    }
86
    if {[info exists u]} {
87
        unset u
88
    }
89
    if {![info exists env(COMSPEC)]} {
90
        if {$tcl_platform(os) == {Windows NT}} {
91
            set env(COMSPEC) cmd.exe
92
        } else {
93
            set env(COMSPEC) command.com
94
        }
95
    }
96
}
97
 
98
# Setup the unknown package handler
99
 
100
package unknown tclPkgUnknown
101
 
102
# Conditionalize for presence of exec.
103
 
104
if {[info commands exec] == ""} {
105
 
106
    # Some machines, such as the Macintosh, do not have exec. Also, on all
107
    # platforms, safe interpreters do not have exec.
108
 
109
    set auto_noexec 1
110
}
111
set errorCode ""
112
set errorInfo ""
113
 
114
# Define a log command (which can be overwitten to log errors
115
# differently, specially when stderr is not available)
116
 
117
if {[info commands tclLog] == ""} {
118
    proc tclLog {string} {
119
        catch {puts stderr $string}
120
    }
121
}
122
 
123
# unknown --
124
# This procedure is called when a Tcl command is invoked that doesn't
125
# exist in the interpreter.  It takes the following steps to make the
126
# command available:
127
#
128
#       1. See if the command has the form "namespace inscope ns cmd" and
129
#          if so, concatenate its arguments onto the end and evaluate it.
130
#       2. See if the autoload facility can locate the command in a
131
#          Tcl script file.  If so, load it and execute it.
132
#       3. If the command was invoked interactively at top-level:
133
#           (a) see if the command exists as an executable UNIX program.
134
#               If so, "exec" the command.
135
#           (b) see if the command requests csh-like history substitution
136
#               in one of the common forms !!, !<number>, or ^old^new.  If
137
#               so, emulate csh's history substitution.
138
#           (c) see if the command is a unique abbreviation for another
139
#               command.  If so, invoke the command.
140
#
141
# Arguments:
142
# args -        A list whose elements are the words of the original
143
#               command, including the command name.
144
 
145
proc unknown args {
146
    global auto_noexec auto_noload env unknown_pending tcl_interactive
147
    global errorCode errorInfo
148
 
149
    # If the command word has the form "namespace inscope ns cmd"
150
    # then concatenate its arguments onto the end and evaluate it.
151
 
152
    set cmd [lindex $args 0]
153
    if {[regexp "^namespace\[ \t\n\]+inscope" $cmd] && [llength $cmd] == 4} {
154
        set arglist [lrange $args 1 end]
155
        set ret [catch {uplevel $cmd $arglist} result]
156
        if {$ret == 0} {
157
            return $result
158
        } else {
159
            return -code $ret -errorcode $errorCode $result
160
        }
161
    }
162
 
163
    # Save the values of errorCode and errorInfo variables, since they
164
    # may get modified if caught errors occur below.  The variables will
165
    # be restored just before re-executing the missing command.
166
 
167
    set savedErrorCode $errorCode
168
    set savedErrorInfo $errorInfo
169
    set name [lindex $args 0]
170
    if {![info exists auto_noload]} {
171
        #
172
        # Make sure we're not trying to load the same proc twice.
173
        #
174
        if {[info exists unknown_pending($name)]} {
175
            return -code error "self-referential recursion in \"unknown\" for command \"$name\"";
176
        }
177
        set unknown_pending($name) pending;
178
        set ret [catch {auto_load $name [uplevel 1 {namespace current}]} msg]
179
        unset unknown_pending($name);
180
        if {$ret != 0} {
181
            return -code $ret -errorcode $errorCode \
182
                "error while autoloading \"$name\": $msg"
183
        }
184
        if {![array size unknown_pending]} {
185
            unset unknown_pending
186
        }
187
        if {$msg} {
188
            set errorCode $savedErrorCode
189
            set errorInfo $savedErrorInfo
190
            set code [catch {uplevel 1 $args} msg]
191
            if {$code ==  1} {
192
                #
193
                # Strip the last five lines off the error stack (they're
194
                # from the "uplevel" command).
195
                #
196
 
197
                set new [split $errorInfo \n]
198
                set new [join [lrange $new 0 [expr {[llength $new] - 6}]] \n]
199
                return -code error -errorcode $errorCode \
200
                        -errorinfo $new $msg
201
            } else {
202
                return -code $code $msg
203
            }
204
        }
205
    }
206
 
207
    if {([info level] == 1) && ([info script] == "") \
208
            && [info exists tcl_interactive] && $tcl_interactive} {
209
        if {![info exists auto_noexec]} {
210
            set new [auto_execok $name]
211
            if {$new != ""} {
212
                set errorCode $savedErrorCode
213
                set errorInfo $savedErrorInfo
214
                set redir ""
215
                if {[info commands console] == ""} {
216
                    set redir ">&@stdout <@stdin"
217
                }
218
                return [uplevel exec $redir $new [lrange $args 1 end]]
219
            }
220
        }
221
        set errorCode $savedErrorCode
222
        set errorInfo $savedErrorInfo
223
        if {$name == "!!"} {
224
            set newcmd [history event]
225
        } elseif {[regexp {^!(.+)$} $name dummy event]} {
226
            set newcmd [history event $event]
227
        } elseif {[regexp {^\^([^^]*)\^([^^]*)\^?$} $name dummy old new]} {
228
            set newcmd [history event -1]
229
            catch {regsub -all -- $old $newcmd $new newcmd}
230
        }
231
        if {[info exists newcmd]} {
232
            tclLog $newcmd
233
            history change $newcmd 0
234
            return [uplevel $newcmd]
235
        }
236
 
237
        set ret [catch {set cmds [info commands $name*]} msg]
238
        if {[string compare $name "::"] == 0} {
239
            set name ""
240
        }
241
        if {$ret != 0} {
242
            return -code $ret -errorcode $errorCode \
243
                "error in unknown while checking if \"$name\" is a unique command abbreviation: $msg"
244
        }
245
        if {[llength $cmds] == 1} {
246
            return [uplevel [lreplace $args 0 0 $cmds]]
247
        }
248
        if {[llength $cmds] != 0} {
249
            if {$name == ""} {
250
                return -code error "empty command name \"\""
251
            } else {
252
                return -code error \
253
                        "ambiguous command name \"$name\": [lsort $cmds]"
254
            }
255
        }
256
    }
257
    return -code error "invalid command name \"$name\""
258
}
259
 
260
# auto_load --
261
# Checks a collection of library directories to see if a procedure
262
# is defined in one of them.  If so, it sources the appropriate
263
# library file to create the procedure.  Returns 1 if it successfully
264
# loaded the procedure, 0 otherwise.
265
#
266
# Arguments: 
267
# cmd -                 Name of the command to find and load.
268
# namespace (optional)  The namespace where the command is being used - must be
269
#                       a canonical namespace as returned [namespace current]
270
#                       for instance. If not given, namespace current is used.
271
 
272
proc auto_load {cmd {namespace {}}} {
273
    global auto_index auto_oldpath auto_path
274
 
275
    if {[string length $namespace] == 0} {
276
        set namespace [uplevel {namespace current}]
277
    }
278
    set nameList [auto_qualify $cmd $namespace]
279
    # workaround non canonical auto_index entries that might be around
280
    # from older auto_mkindex versions
281
    lappend nameList $cmd
282
    foreach name $nameList {
283
        if {[info exists auto_index($name)]} {
284
            uplevel #0 $auto_index($name)
285
            return [expr {[info commands $name] != ""}]
286
        }
287
    }
288
    if {![info exists auto_path]} {
289
        return 0
290
    }
291
 
292
    if {![auto_load_index]} {
293
        return 0
294
    }
295
 
296
    foreach name $nameList {
297
        if {[info exists auto_index($name)]} {
298
            uplevel #0 $auto_index($name)
299
            if {[info commands $name] != ""} {
300
                return 1
301
            }
302
        }
303
    }
304
    return 0
305
}
306
 
307
# auto_load_index --
308
# Loads the contents of tclIndex files on the auto_path directory
309
# list.  This is usually invoked within auto_load to load the index
310
# of available commands.  Returns 1 if the index is loaded, and 0 if
311
# the index is already loaded and up to date.
312
#
313
# Arguments: 
314
# None.
315
 
316
proc auto_load_index {} {
317
    global auto_index auto_oldpath auto_path errorInfo errorCode
318
 
319
    if {[info exists auto_oldpath]} {
320
        if {$auto_oldpath == $auto_path} {
321
            return 0
322
        }
323
    }
324
    set auto_oldpath $auto_path
325
 
326
    # Check if we are a safe interpreter. In that case, we support only
327
    # newer format tclIndex files.
328
 
329
    set issafe [interp issafe]
330
    for {set i [expr {[llength $auto_path] - 1}]} {$i >= 0} {incr i -1} {
331
        set dir [lindex $auto_path $i]
332
        set f ""
333
        if {$issafe} {
334
            catch {source [file join $dir tclIndex]}
335
        } elseif {[catch {set f [open [file join $dir tclIndex]]}]} {
336
            continue
337
        } else {
338
            set error [catch {
339
                set id [gets $f]
340
                if {$id == "# Tcl autoload index file, version 2.0"} {
341
                    eval [read $f]
342
                } elseif {$id == \
343
                    "# Tcl autoload index file: each line identifies a Tcl"} {
344
                    while {[gets $f line] >= 0} {
345
                        if {([string index $line 0] == "#")
346
                                || ([llength $line] != 2)} {
347
                            continue
348
                        }
349
                        set name [lindex $line 0]
350
                        set auto_index($name) \
351
                            "source [file join $dir [lindex $line 1]]"
352
                    }
353
                } else {
354
                    error \
355
                      "[file join $dir tclIndex] isn't a proper Tcl index file"
356
                }
357
            } msg]
358
            if {$f != ""} {
359
                close $f
360
            }
361
            if {$error} {
362
                error $msg $errorInfo $errorCode
363
            }
364
        }
365
    }
366
    return 1
367
}
368
 
369
# auto_qualify --
370
# compute a fully qualified names list for use in the auto_index array.
371
# For historical reasons, commands in the global namespace do not have leading
372
# :: in the index key. The list has two elements when the command name is
373
# relative (no leading ::) and the namespace is not the global one. Otherwise
374
# only one name is returned (and searched in the auto_index).
375
#
376
# Arguments -
377
# cmd           The command name. Can be any name accepted for command
378
#               invocations (Like "foo::::bar").
379
# namespace     The namespace where the command is being used - must be
380
#               a canonical namespace as returned by [namespace current]
381
#               for instance.
382
 
383
proc auto_qualify {cmd namespace} {
384
 
385
    # count separators and clean them up
386
    # (making sure that foo:::::bar will be treated as foo::bar)
387
    set n [regsub -all {::+} $cmd :: cmd]
388
 
389
    # Ignore namespace if the name starts with ::
390
    # Handle special case of only leading ::
391
 
392
    # Before each return case we give an example of which category it is
393
    # with the following form :
394
    # ( inputCmd, inputNameSpace) -> output
395
 
396
    if {[regexp {^::(.*)$} $cmd x tail]} {
397
        if {$n > 1} {
398
            # ( ::foo::bar , * ) -> ::foo::bar
399
            return [list $cmd]
400
        } else {
401
            # ( ::global , * ) -> global
402
            return [list $tail]
403
        }
404
    }
405
 
406
    # Potentially returning 2 elements to try  :
407
    # (if the current namespace is not the global one)
408
 
409
    if {$n == 0} {
410
        if {[string compare $namespace ::] == 0} {
411
            # ( nocolons , :: ) -> nocolons
412
            return [list $cmd]
413
        } else {
414
            # ( nocolons , ::sub ) -> ::sub::nocolons nocolons
415
            return [list ${namespace}::$cmd $cmd]
416
        }
417
    } else {
418
        if {[string compare $namespace ::] == 0} {
419
            #  ( foo::bar , :: ) -> ::foo::bar
420
            return [list ::$cmd]
421
        } else {
422
            # ( foo::bar , ::sub ) -> ::sub::foo::bar ::foo::bar
423
            return [list ${namespace}::$cmd ::$cmd]
424
        }
425
    }
426
}
427
 
428
# auto_import --
429
# invoked during "namespace import" to make see if the imported commands
430
# reside in an autoloaded library.  If so, the commands are loaded so
431
# that they will be available for the import links.  If not, then this
432
# procedure does nothing.
433
#
434
# Arguments -
435
# pattern       The pattern of commands being imported (like "foo::*")
436
#               a canonical namespace as returned by [namespace current]
437
 
438
proc auto_import {pattern} {
439
    global auto_index
440
 
441
    set ns [uplevel namespace current]
442
    set patternList [auto_qualify $pattern $ns]
443
 
444
    auto_load_index
445
 
446
    foreach pattern $patternList {
447
        foreach name [array names auto_index] {
448
            if {[string match $pattern $name] && "" == [info commands $name]} {
449
                uplevel #0 $auto_index($name)
450
            }
451
        }
452
    }
453
}
454
 
455
if {[string compare $tcl_platform(platform) windows] == 0} {
456
 
457
# auto_execok --
458
#
459
# Returns string that indicates name of program to execute if 
460
# name corresponds to a shell builtin or an executable in the
461
# Windows search path, or "" otherwise.  Builds an associative 
462
# array auto_execs that caches information about previous checks, 
463
# for speed.
464
#
465
# Arguments: 
466
# name -                        Name of a command.
467
 
468
# Windows version.
469
#
470
# Note that info executable doesn't work under Windows, so we have to
471
# look for files with .exe, .com, or .bat extensions.  Also, the path
472
# may be in the Path or PATH environment variables, and path
473
# components are separated with semicolons, not colons as under Unix.
474
#
475
proc auto_execok name {
476
    global auto_execs env tcl_platform
477
 
478
    if {[info exists auto_execs($name)]} {
479
        return $auto_execs($name)
480
    }
481
    set auto_execs($name) ""
482
 
483
    if {[lsearch -exact {cls copy date del erase dir echo mkdir md rename
484
            ren rmdir rd time type ver vol} $name] != -1} {
485
        return [set auto_execs($name) [list $env(COMSPEC) /c $name]]
486
    }
487
 
488
    if {[llength [file split $name]] != 1} {
489
        foreach ext {{} .com .exe .bat} {
490
            set file ${name}${ext}
491
            if {[file exists $file] && ![file isdirectory $file]} {
492
                return [set auto_execs($name) [list $file]]
493
            }
494
        }
495
        return ""
496
    }
497
 
498
    set path "[file dirname [info nameof]];.;"
499
    if {[info exists env(WINDIR)]} {
500
        set windir $env(WINDIR)
501
    }
502
    if {[info exists windir]} {
503
        if {$tcl_platform(os) == "Windows NT"} {
504
            append path "$windir/system32;"
505
        }
506
        append path "$windir/system;$windir;"
507
    }
508
 
509
    if {[info exists env(PATH)]} {
510
        # CYGNUS LOCAL: in the Cygwin environment, we convert to a
511
        # Windows path first.
512
        if {[llength [info commands ide_cygwin_path]]} {
513
            append path [ide_cygwin_path posix_to_win32_path_list $env(PATH)]
514
        } else {
515
            append path $env(PATH)
516
        }
517
    }
518
 
519
    foreach dir [split $path {;}] {
520
        if {$dir == ""} {
521
            set dir .
522
        }
523
        foreach ext {{} .com .exe .bat} {
524
            set file [file join $dir ${name}${ext}]
525
            if {[file exists $file] && ![file isdirectory $file]} {
526
                return [set auto_execs($name) [list $file]]
527
            }
528
        }
529
    }
530
    return ""
531
}
532
 
533
} else {
534
 
535
# auto_execok --
536
#
537
# Returns string that indicates name of program to execute if 
538
# name corresponds to an executable in the path. Builds an associative 
539
# array auto_execs that caches information about previous checks, 
540
# for speed.
541
#
542
# Arguments: 
543
# name -                        Name of a command.
544
 
545
# Unix version.
546
#
547
proc auto_execok name {
548
    global auto_execs env
549
 
550
    if {[info exists auto_execs($name)]} {
551
        return $auto_execs($name)
552
    }
553
    set auto_execs($name) ""
554
    if {[llength [file split $name]] != 1} {
555
        if {[file executable $name] && ![file isdirectory $name]} {
556
            set auto_execs($name) [list $name]
557
        }
558
        return $auto_execs($name)
559
    }
560
    foreach dir [split $env(PATH) :] {
561
        if {$dir == ""} {
562
            set dir .
563
        }
564
        set file [file join $dir $name]
565
        if {[file executable $file] && ![file isdirectory $file]} {
566
            set auto_execs($name) [list $file]
567
            return $auto_execs($name)
568
        }
569
    }
570
    return ""
571
}
572
 
573
}
574
# auto_reset --
575
# Destroy all cached information for auto-loading and auto-execution,
576
# so that the information gets recomputed the next time it's needed.
577
# Also delete any procedures that are listed in the auto-load index
578
# except those defined in this file.
579
#
580
# Arguments: 
581
# None.
582
 
583
proc auto_reset {} {
584
    global auto_execs auto_index auto_oldpath
585
    foreach p [info procs] {
586
        if {[info exists auto_index($p)] && ![string match auto_* $p]
587
                && ([lsearch -exact {unknown pkg_mkIndex tclPkgSetup
588
                        tcl_findLibrary pkg_compareExtension
589
                        tclMacPkgSearch tclPkgUnknown} $p] < 0)} {
590
            rename $p {}
591
        }
592
    }
593
    catch {unset auto_execs}
594
    catch {unset auto_index}
595
    catch {unset auto_oldpath}
596
}
597
 
598
# tcl_findLibrary
599
#       This is a utility for extensions that searches for a library directory
600
#       using a canonical searching algorithm. A side effect is to source
601
#       the initialization script and set a global library variable.
602
# Arguments:
603
#       basename        Prefix of the directory name, (e.g., "tk")
604
#       version         Version number of the package, (e.g., "8.0")
605
#       patch           Patchlevel of the package, (e.g., "8.0.3")
606
#       initScript      Initialization script to source (e.g., tk.tcl)
607
#       enVarName       environment variable to honor (e.g., TK_LIBRARY)
608
#       varName         Global variable to set when done (e.g., tk_library)
609
#       CYGNUS LOCAL:   We have funny things like gdb having different library
610
#                       names before & after install (and neither of them is gdb
611
#                       or gdb$version... 
612
#       srcLibName      The name of the library directory in the build tree (assumed to be 
613
#                       under the basename directory.
614
#       instLibName     The name of the installed library directory
615
#       pkgName         The package name (for cases like Itcl where you have
616
#                       several subpackages under one package...
617
#       debug_startup   Run the startup proc through debugger_eval?
618
 
619
proc tcl_findLibrary {basename version patch initScript
620
                      enVarName varName {srcLibName {}} {instLibName {}}
621
                      {pkgName {}} {debug_startup 0}} {
622
    upvar #0 $varName the_library
623
    global env errorInfo
624
 
625
    set dirs {}
626
    set errors {}
627
 
628
    # The C application may have hardwired a path, which we honor
629
 
630
    if {[info exist the_library]} {
631
        lappend dirs $the_library
632
    } else {
633
 
634
        # Do the canonical search
635
 
636
        # 1. From an environment variable, if it exists
637
 
638
        if {[info exists env($enVarName)]} {
639
            lappend dirs $env($enVarName)
640
        }
641
 
642
        # 2. Relative to the Tcl library
643
        # CYGNUS LOCAL: look in several places relative to the tcl library.
644
 
645
        if {$srcLibName == ""} {
646
          set srcLibName library
647
        }
648
        if {$instLibName == ""} {
649
          set instLibName $basename$version
650
        }
651
 
652
        set parentDir [file dirname [info library]]
653
        set grandParentDir [file dirname $parentDir]
654
        # These two are install locations without & with exec_prefix.
655
        lappend dirs [file join $parentDir $instLibName]
656
        lappend dirs [file join $grandParentDir $instLibName]
657
        # The rest are in the build tree:
658
        # this is for most things:
659
        lappend dirs [file join $grandParentDir $basename $srcLibName]
660
        # this is if we ever put version numbers on Tcl & Tk:
661
        lappend dirs [file join $grandParentDir $basename$version $srcLibName]
662
        # This handles itcl:
663
        if {$pkgName != ""} {
664
          lappend dirs [file join $grandParentDir $pkgName $basename $srcLibName]
665
          lappend dirs [file join $grandParentDir $pkgName $basename$version $srcLibName]
666
        }
667
 
668
        # 3. Various locations relative to the executable
669
        #CYGNUS LOCAL - I took all this out.  For Cygnus, it seems more
670
        # reasonable to look relative to tcl_library.  This might be anywhere
671
        # since the source & build trees are often widely separated, 
672
        # but once you've found tcl_library, you've found the source tree,
673
        # and everything else is easy...
674
    }
675
 
676
    foreach i $dirs {
677
        set the_library $i
678
        set file [file join $i $initScript]
679
 
680
        # source everything when in a safe interpreter because
681
        # we have a source command, but no file exists command
682
 
683
        if {[interp issafe] || [file exists $file]} {
684
            if {$debug_startup} {
685
 
686
              if {![catch {uplevel \#0 debugger_eval [list [list source $file]]} msg]} {
687
                    return
688
                } else {
689
                    append errors "$file: $msg\n$errorInfo\n"
690
                }
691
            } else {
692
                if {![catch {uplevel \#0 [list source $file]} msg]} {
693
                    return
694
                } else {
695
                    append errors "$file: $msg\n$errorInfo\n"
696
                }
697
            }
698
        }
699
    }
700
    set msg "Can't find a usable $initScript in the following directories: \n"
701
    append msg "    $dirs\n\n"
702
    append msg "$errors\n\n"
703
    append msg "This probably means that $basename wasn't installed properly.\n"
704
    error $msg
705
}
706
 
707
 
708
# OPTIONAL SUPPORT PROCEDURES
709
# In Tcl 8.1 all the code below here has been moved to other files to
710
# reduce the size of init.tcl
711
 
712
# ----------------------------------------------------------------------
713
# auto_mkindex
714
# ----------------------------------------------------------------------
715
# The following procedures are used to generate the tclIndex file
716
# from Tcl source files.  They use a special safe interpreter to
717
# parse Tcl source files, writing out index entries as "proc"
718
# commands are encountered.  This implementation won't work in a
719
# safe interpreter, since a safe interpreter can't create the
720
# special parser and mess with its commands.  If this is a safe
721
# interpreter, we simply clip these procs out.
722
 
723
if {! [interp issafe]} {
724
 
725
    # auto_mkindex --
726
    # Regenerate a tclIndex file from Tcl source files.  Takes as argument
727
    # the name of the directory in which the tclIndex file is to be placed,
728
    # followed by any number of glob patterns to use in that directory to
729
    # locate all of the relevant files.
730
    #
731
    # Arguments: 
732
    # dir -             Name of the directory in which to create an index.
733
    # args -    Any number of additional arguments giving the
734
    #           names of files within dir.  If no additional
735
    #           are given auto_mkindex will look for *.tcl.
736
 
737
    proc auto_mkindex {dir args} {
738
        global errorCode errorInfo
739
 
740
        set oldDir [pwd]
741
        cd $dir
742
        set dir [pwd]
743
 
744
        append index "# Tcl autoload index file, version 2.0\n"
745
        append index "# This file is generated by the \"auto_mkindex\" command\n"
746
        append index "# and sourced to set up indexing information for one or\n"
747
        append index "# more commands.  Typically each line is a command that\n"
748
        append index "# sets an element in the auto_index array, where the\n"
749
        append index "# element name is the name of a command and the value is\n"
750
        append index "# a script that loads the command.\n\n"
751
        if {$args == ""} {
752
            set args *.tcl
753
        }
754
        foreach file [eval glob $args] {
755
            auto_mkindex_parser::init
756
            if {[catch {auto_mkindex_parser::mkindex $file} msg] == 0} {
757
                append index $msg
758
            } else {
759
                set code $errorCode
760
                set info $errorInfo
761
                cd $oldDir
762
                error $msg $info $code
763
            }
764
            auto_mkindex_parser::cleanup
765
        }
766
 
767
        set fid [open "tclIndex" w]
768
        puts $fid $index nonewline
769
        close $fid
770
        cd $oldDir
771
    }
772
 
773
    # Original version of auto_mkindex that just searches the source
774
    # code for "proc" at the beginning of the line.
775
 
776
    proc auto_mkindex_old {dir args} {
777
        global errorCode errorInfo
778
        set oldDir [pwd]
779
        cd $dir
780
        set dir [pwd]
781
        append index "# Tcl autoload index file, version 2.0\n"
782
        append index "# This file is generated by the \"auto_mkindex\" command\n"
783
        append index "# and sourced to set up indexing information for one or\n"
784
        append index "# more commands.  Typically each line is a command that\n"
785
        append index "# sets an element in the auto_index array, where the\n"
786
        append index "# element name is the name of a command and the value is\n"
787
        append index "# a script that loads the command.\n\n"
788
        if {$args == ""} {
789
            set args *.tcl
790
        }
791
        foreach file [eval glob $args] {
792
            set f ""
793
            set error [catch {
794
                set f [open $file]
795
                while {[gets $f line] >= 0} {
796
                    if {[regexp {^proc[         ]+([^   ]*)} $line match procName]} {
797
                        set procName [lindex [auto_qualify $procName "::"] 0]
798
                        append index "set [list auto_index($procName)]"
799
                        append index " \[list source \[file join \$dir [list $file]\]\]\n"
800
                    }
801
                }
802
                close $f
803
            } msg]
804
            if {$error} {
805
                set code $errorCode
806
                set info $errorInfo
807
                catch {close $f}
808
                cd $oldDir
809
                error $msg $info $code
810
            }
811
        }
812
        set f ""
813
        set error [catch {
814
            set f [open tclIndex w]
815
            puts $f $index nonewline
816
            close $f
817
            cd $oldDir
818
        } msg]
819
        if {$error} {
820
            set code $errorCode
821
            set info $errorInfo
822
            catch {close $f}
823
            cd $oldDir
824
            error $msg $info $code
825
        }
826
    }
827
 
828
    # Create a safe interpreter that can be used to parse Tcl source files
829
    # generate a tclIndex file for autoloading.  This interp contains
830
    # commands for things that need index entries.  Each time a command
831
    # is executed, it writes an entry out to the index file.
832
 
833
    namespace eval auto_mkindex_parser {
834
        variable parser ""          ;# parser used to build index
835
        variable index ""           ;# maintains index as it is built
836
        variable scriptFile ""      ;# name of file being processed
837
        variable contextStack ""    ;# stack of namespace scopes
838
        variable imports ""         ;# keeps track of all imported cmds
839
        variable initCommands ""    ;# list of commands that create aliases
840
        proc init {} {
841
            variable parser
842
            variable initCommands
843
            if {![interp issafe]} {
844
                set parser [interp create -safe]
845
                $parser hide info
846
                $parser hide rename
847
                $parser hide proc
848
                $parser hide namespace
849
                $parser hide eval
850
                $parser hide puts
851
                $parser invokehidden namespace delete ::
852
                $parser invokehidden proc unknown {args} {}
853
 
854
                #
855
                # We'll need access to the "namespace" command within the
856
                # interp.  Put it back, but move it out of the way.
857
                #
858
                $parser expose namespace
859
                $parser invokehidden rename namespace _%@namespace
860
                $parser expose eval
861
                $parser invokehidden rename eval _%@eval
862
 
863
                # Install all the registered psuedo-command implementations
864
 
865
                foreach cmd $initCommands {
866
                    eval $cmd
867
                }
868
            }
869
        }
870
        proc cleanup {} {
871
            variable parser
872
            interp delete $parser
873
            unset parser
874
        }
875
    }
876
 
877
    # auto_mkindex_parser::mkindex --
878
    # Used by the "auto_mkindex" command to create a "tclIndex" file for
879
    # the given Tcl source file.  Executes the commands in the file, and
880
    # handles things like the "proc" command by adding an entry for the
881
    # index file.  Returns a string that represents the index file.
882
    #
883
    # Arguments: 
884
    # file -            Name of Tcl source file to be indexed.
885
 
886
    proc auto_mkindex_parser::mkindex {file} {
887
        variable parser
888
        variable index
889
        variable scriptFile
890
        variable contextStack
891
        variable imports
892
 
893
        set scriptFile $file
894
 
895
        set fid [open $file]
896
        set contents [read $fid]
897
        close $fid
898
 
899
        # There is one problem with sourcing files into the safe
900
        # interpreter:  references like "$x" will fail since code is not
901
        # really being executed and variables do not really exist.
902
        # Be careful to escape all naked "$" before evaluating.
903
 
904
        regsub -all {([^\$])\$([^\$])} $contents {\1\\$\2} contents
905
 
906
        set index ""
907
        set contextStack ""
908
        set imports ""
909
 
910
        $parser eval $contents
911
 
912
        foreach name $imports {
913
            catch {$parser eval [list _%@namespace forget $name]}
914
        }
915
        return $index
916
    }
917
 
918
    # auto_mkindex_parser::hook command
919
    # Registers a Tcl command to evaluate when initializing the
920
    # slave interpreter used by the mkindex parser.
921
    # The command is evaluated in the master interpreter, and can
922
    # use the variable auto_mkindex_parser::parser to get to the slave
923
 
924
    proc auto_mkindex_parser::hook {cmd} {
925
        variable initCommands
926
 
927
        lappend initCommands $cmd
928
    }
929
 
930
    # auto_mkindex_parser::slavehook command
931
    # Registers a Tcl command to evaluate when initializing the
932
    # slave interpreter used by the mkindex parser.
933
    # The command is evaluated in the slave interpreter.
934
 
935
    proc auto_mkindex_parser::slavehook {cmd} {
936
        variable initCommands
937
 
938
        lappend initCommands "\$parser eval [list $cmd]"
939
    }
940
 
941
    # auto_mkindex_parser::command --
942
    # Registers a new command with the "auto_mkindex_parser" interpreter
943
    # that parses Tcl files.  These commands are fake versions of things
944
    # like the "proc" command.  When you execute them, they simply write
945
    # out an entry to a "tclIndex" file for auto-loading.
946
    #
947
    # This procedure allows extensions to register their own commands
948
    # with the auto_mkindex facility.  For example, a package like
949
    # [incr Tcl] might register a "class" command so that class definitions
950
    # could be added to a "tclIndex" file for auto-loading.
951
    #
952
    # Arguments:
953
    # name -            Name of command recognized in Tcl files.
954
    # arglist -         Argument list for command.
955
    # body -            Implementation of command to handle indexing.
956
 
957
    proc auto_mkindex_parser::command {name arglist body} {
958
        hook [list auto_mkindex_parser::commandInit $name $arglist $body]
959
    }
960
 
961
    # auto_mkindex_parser::commandInit --
962
    # This does the actual work set up by auto_mkindex_parser::command
963
    # This is called when the interpreter used by the parser is created.
964
 
965
    proc auto_mkindex_parser::commandInit {name arglist body} {
966
        variable parser
967
 
968
        set ns [namespace qualifiers $name]
969
        set tail [namespace tail $name]
970
        if {$ns == ""} {
971
            set fakeName "[namespace current]::_%@fake_$tail"
972
        } else {
973
            set fakeName "_%@fake_$name"
974
            regsub -all {::} $fakeName "_" fakeName
975
            set fakeName "[namespace current]::$fakeName"
976
        }
977
        proc $fakeName $arglist $body
978
 
979
        #
980
        # YUK!  Tcl won't let us alias fully qualified command names,
981
        # so we can't handle names like "::itcl::class".  Instead,
982
        # we have to build procs with the fully qualified names, and
983
        # have the procs point to the aliases.
984
        #
985
        if {[regexp {::} $name]} {
986
            set exportCmd [list _%@namespace export [namespace tail $name]]
987
            $parser eval [list _%@namespace eval $ns $exportCmd]
988
            set alias [namespace tail $fakeName]
989
            $parser invokehidden proc $name {args} "_%@eval $alias \$args"
990
            $parser alias $alias $fakeName
991
        } else {
992
            $parser alias $name $fakeName
993
        }
994
        return
995
    }
996
 
997
    # auto_mkindex_parser::fullname --
998
    # Used by commands like "proc" within the auto_mkindex parser.
999
    # Returns the qualified namespace name for the "name" argument.
1000
    # If the "name" does not start with "::", elements are added from
1001
    # the current namespace stack to produce a qualified name.  Then,
1002
    # the name is examined to see whether or not it should really be
1003
    # qualified.  If the name has more than the leading "::", it is
1004
    # returned as a fully qualified name.  Otherwise, it is returned
1005
    # as a simple name.  That way, the Tcl autoloader will recognize
1006
    # it properly.
1007
    #
1008
    # Arguments:
1009
    # name -            Name that is being added to index.
1010
 
1011
    proc auto_mkindex_parser::fullname {name} {
1012
        variable contextStack
1013
 
1014
        if {![string match ::* $name]} {
1015
            foreach ns $contextStack {
1016
                set name "${ns}::$name"
1017
                if {[string match ::* $name]} {
1018
                    break
1019
                }
1020
            }
1021
        }
1022
 
1023
        if {[namespace qualifiers $name] == ""} {
1024
            return [namespace tail $name]
1025
        } elseif {![string match ::* $name]} {
1026
            return "::$name"
1027
        }
1028
        return $name
1029
    }
1030
 
1031
    # Register all of the procedures for the auto_mkindex parser that
1032
    # will build the "tclIndex" file.
1033
 
1034
    # AUTO MKINDEX:  proc name arglist body
1035
    # Adds an entry to the auto index list for the given procedure name.
1036
 
1037
    auto_mkindex_parser::command proc {name args} {
1038
        variable index
1039
        variable scriptFile
1040
        append index "set [list auto_index([fullname $name])]"
1041
        append index " \[list source \[file join \$dir [list $scriptFile]\]\]\n"
1042
    }
1043
 
1044
    # AUTO MKINDEX:  namespace eval name command ?arg arg...?
1045
    # Adds the namespace name onto the context stack and evaluates the
1046
    # associated body of commands.
1047
    #
1048
    # AUTO MKINDEX:  namespace import ?-force? pattern ?pattern...?
1049
    # Performs the "import" action in the parser interpreter.  This is
1050
    # important for any commands contained in a namespace that affect
1051
    # the index.  For example, a script may say "itcl::class ...",
1052
    # or it may import "itcl::*" and then say "class ...".  This
1053
    # procedure does the import operation, but keeps track of imported
1054
    # patterns so we can remove the imports later.
1055
 
1056
    auto_mkindex_parser::command namespace {op args} {
1057
        switch -- $op {
1058
            eval {
1059
                variable parser
1060
                variable contextStack
1061
 
1062
                set name [lindex $args 0]
1063
                set args [lrange $args 1 end]
1064
 
1065
                set contextStack [linsert $contextStack 0 $name]
1066
                if {[llength $args] == 1} {
1067
                    $parser eval [lindex $args 0]
1068
                } else {
1069
                    eval $parser eval $args
1070
                }
1071
                set contextStack [lrange $contextStack 1 end]
1072
            }
1073
            import {
1074
                variable parser
1075
                variable imports
1076
                foreach pattern $args {
1077
                    if {$pattern != "-force"} {
1078
                        lappend imports $pattern
1079
                    }
1080
                }
1081
                catch {$parser eval "_%@namespace import $args"}
1082
            }
1083
        }
1084
    }
1085
 
1086
# Close of the if ![interp issafe] block
1087
}
1088
 
1089
# pkg_compareExtension --
1090
#
1091
#  Used internally by pkg_mkIndex to compare the extension of a file to
1092
#  a given extension. On Windows, it uses a case-insensitive comparison.
1093
#
1094
# Arguments:
1095
#  fileName     name of a file whose extension is compared
1096
#  ext          (optional) The extension to compare against; you must
1097
#               provide the starting dot.
1098
#               Defaults to [info sharedlibextension]
1099
#
1100
# Results:
1101
#  Returns 1 if the extension matches, 0 otherwise
1102
 
1103
proc pkg_compareExtension { fileName {ext {}} } {
1104
    global tcl_platform
1105
    if {[string length $ext] == 0} {
1106
        set ext [info sharedlibextension]
1107
    }
1108
    if {[string compare $tcl_platform(platform) "windows"] == 0} {
1109
        return [expr {[string compare \
1110
                [string tolower [file extension $fileName]] \
1111
                [string tolower $ext]] == 0}]
1112
    } else {
1113
        return [expr {[string compare [file extension $fileName] $ext] == 0}]
1114
    }
1115
}
1116
 
1117
# pkg_mkIndex --
1118
# This procedure creates a package index in a given directory.  The
1119
# package index consists of a "pkgIndex.tcl" file whose contents are
1120
# a Tcl script that sets up package information with "package require"
1121
# commands.  The commands describe all of the packages defined by the
1122
# files given as arguments.
1123
#
1124
# Arguments:
1125
# -direct               (optional) If this flag is present, the generated
1126
#                       code in pkgMkIndex.tcl will cause the package to be
1127
#                       loaded when "package require" is executed, rather
1128
#                       than lazily when the first reference to an exported
1129
#                       procedure in the package is made.
1130
# -verbose              (optional) Verbose output; the name of each file that
1131
#                       was successfully rocessed is printed out. Additionally,
1132
#                       if processing of a file failed a message is printed.
1133
# -load pat             (optional) Preload any packages whose names match
1134
#                       the pattern.  Used to handle DLLs that depend on
1135
#                       other packages during their Init procedure.
1136
# dir -                 Name of the directory in which to create the index.
1137
# args -                Any number of additional arguments, each giving
1138
#                       a glob pattern that matches the names of one or
1139
#                       more shared libraries or Tcl script files in
1140
#                       dir.
1141
 
1142
proc pkg_mkIndex {args} {
1143
    global errorCode errorInfo
1144
    set usage {"pkg_mkIndex ?-direct? ?-verbose? ?-load pattern? ?--? dir ?pattern ...?"};
1145
 
1146
    set argCount [llength $args]
1147
    if {$argCount < 1} {
1148
        return -code error "wrong # args: should be\n$usage"
1149
    }
1150
 
1151
    set more ""
1152
    set direct 0
1153
    set doVerbose 0
1154
    set loadPat ""
1155
    for {set idx 0} {$idx < $argCount} {incr idx} {
1156
        set flag [lindex $args $idx]
1157
        switch -glob -- $flag {
1158
            -- {
1159
                # done with the flags
1160
                incr idx
1161
                break
1162
            }
1163
            -verbose {
1164
                set doVerbose 1
1165
            }
1166
            -direct {
1167
                set direct 1
1168
                append more " -direct"
1169
            }
1170
            -load {
1171
                incr idx
1172
                set loadPat [lindex $args $idx]
1173
                append more " -load $loadPat"
1174
            }
1175
            -* {
1176
                return -code error "unknown flag $flag: should be\n$usage"
1177
            }
1178
            default {
1179
                # done with the flags
1180
                break
1181
            }
1182
        }
1183
    }
1184
 
1185
    set dir [lindex $args $idx]
1186
    set patternList [lrange $args [expr {$idx + 1}] end]
1187
    if {[llength $patternList] == 0} {
1188
        set patternList [list "*.tcl" "*[info sharedlibextension]"]
1189
    }
1190
 
1191
    append index "# Tcl package index file, version 1.1\n"
1192
    append index "# This file is generated by the \"pkg_mkIndex$more\" command\n"
1193
    append index "# and sourced either when an application starts up or\n"
1194
    append index "# by a \"package unknown\" script.  It invokes the\n"
1195
    append index "# \"package ifneeded\" command to set up package-related\n"
1196
    append index "# information so that packages will be loaded automatically\n"
1197
    append index "# in response to \"package require\" commands.  When this\n"
1198
    append index "# script is sourced, the variable \$dir must contain the\n"
1199
    append index "# full path name of this file's directory.\n"
1200
    set oldDir [pwd]
1201
    cd $dir
1202
 
1203
    if {[catch {eval glob $patternList} fileList]} {
1204
        global errorCode errorInfo
1205
        cd $oldDir
1206
        return -code error -errorcode $errorCode -errorinfo $errorInfo $fileList
1207
    }
1208
    foreach file $fileList {
1209
        # For each file, figure out what commands and packages it provides.
1210
        # To do this, create a child interpreter, load the file into the
1211
        # interpreter, and get a list of the new commands and packages
1212
        # that are defined.
1213
 
1214
        if {[string compare $file "pkgIndex.tcl"] == 0} {
1215
            continue
1216
        }
1217
 
1218
        # Changed back to the original directory before initializing the
1219
        # slave in case TCL_LIBRARY is a relative path (e.g. in the test
1220
        # suite). 
1221
 
1222
        cd $oldDir
1223
        set c [interp create]
1224
 
1225
        # Load into the child any packages currently loaded in the parent
1226
        # interpreter that match the -load pattern.
1227
 
1228
        foreach pkg [info loaded] {
1229
            if {! [string match $loadPat [lindex $pkg 1]]} {
1230
                continue
1231
            }
1232
            if {[lindex $pkg 1] == "Tk"} {
1233
                $c eval {set argv {-geometry +0+0}}
1234
            }
1235
            if {[catch {
1236
                load [lindex $pkg 0] [lindex $pkg 1] $c
1237
            } err]} {
1238
                if {$doVerbose} {
1239
                    tclLog "warning: load [lindex $pkg 0] [lindex $pkg 1]\nfailed with: $err"
1240
                }
1241
            } else {
1242
                if {$doVerbose} {
1243
                    tclLog "loaded [lindex $pkg 0] [lindex $pkg 1]"
1244
                }
1245
            }
1246
        }
1247
        cd $dir
1248
 
1249
        $c eval {
1250
            # Stub out the package command so packages can
1251
            # require other packages.
1252
 
1253
            rename package __package_orig
1254
            proc package {what args} {
1255
                switch -- $what {
1256
                    require { return ; # ignore transitive requires }
1257
                    default { eval __package_orig {$what} $args }
1258
                }
1259
            }
1260
            proc tclPkgUnknown args {}
1261
            package unknown tclPkgUnknown
1262
 
1263
            # Stub out the unknown command so package can call
1264
            # into each other during their initialilzation.
1265
 
1266
            proc unknown {args} {}
1267
 
1268
            # Stub out the auto_import mechanism
1269
 
1270
            proc auto_import {args} {}
1271
 
1272
            # reserve the ::tcl namespace for support procs
1273
            # and temporary variables.  This might make it awkward
1274
            # to generate a pkgIndex.tcl file for the ::tcl namespace.
1275
 
1276
            namespace eval ::tcl {
1277
                variable file           ;# Current file being processed
1278
                variable direct         ;# -direct flag value
1279
                variable x              ;# Loop variable
1280
                variable debug          ;# For debugging
1281
                variable type           ;# "load" or "source", for -direct
1282
                variable namespaces     ;# Existing namespaces (e.g., ::tcl)
1283
                variable packages       ;# Existing packages (e.g., Tcl)
1284
                variable origCmds       ;# Existing commands
1285
                variable newCmds        ;# Newly created commands
1286
                variable newPkgs {}     ;# Newly created packages
1287
            }
1288
        }
1289
 
1290
        $c eval [list set ::tcl::file $file]
1291
        $c eval [list set ::tcl::direct $direct]
1292
        if {[catch {
1293
            $c eval {
1294
                set ::tcl::debug "loading or sourcing"
1295
 
1296
                # we need to track command defined by each package even in
1297
                # the -direct case, because they are needed internally by
1298
                # the "partial pkgIndex.tcl" step above.
1299
 
1300
                proc ::tcl::GetAllNamespaces {{root ::}} {
1301
                    set list $root
1302
                    foreach ns [namespace children $root] {
1303
                        eval lappend list [::tcl::GetAllNamespaces $ns]
1304
                    }
1305
                    return $list
1306
                }
1307
 
1308
                # initialize the list of existing namespaces, packages, commands
1309
 
1310
                foreach ::tcl::x [::tcl::GetAllNamespaces] {
1311
                    set ::tcl::namespaces($::tcl::x) 1
1312
                }
1313
                foreach ::tcl::x [package names] {
1314
                    set ::tcl::packages($::tcl::x) 1
1315
                }
1316
                set ::tcl::origCmds [info commands]
1317
 
1318
                # Try to load the file if it has the shared library
1319
                # extension, otherwise source it.  It's important not to
1320
                # try to load files that aren't shared libraries, because
1321
                # on some systems (like SunOS) the loader will abort the
1322
                # whole application when it gets an error.
1323
 
1324
                if {[pkg_compareExtension $::tcl::file [info sharedlibextension]]} {
1325
                    # The "file join ." command below is necessary.
1326
                    # Without it, if the file name has no \'s and we're
1327
                    # on UNIX, the load command will invoke the
1328
                    # LD_LIBRARY_PATH search mechanism, which could cause
1329
                    # the wrong file to be used.
1330
 
1331
                    set ::tcl::debug loading
1332
                    load [file join . $::tcl::file]
1333
                    set ::tcl::type load
1334
                } else {
1335
                    set ::tcl::debug sourcing
1336
                    source $::tcl::file
1337
                    set ::tcl::type source
1338
                }
1339
 
1340
                # See what new namespaces appeared, and import commands
1341
                # from them.  Only exported commands go into the index.
1342
 
1343
                foreach ::tcl::x [::tcl::GetAllNamespaces] {
1344
                    if {! [info exists ::tcl::namespaces($::tcl::x)]} {
1345
                        namespace import ${::tcl::x}::*
1346
                    }
1347
                }
1348
 
1349
                # Figure out what commands appeared
1350
 
1351
                foreach ::tcl::x [info commands] {
1352
                    set ::tcl::newCmds($::tcl::x) 1
1353
                }
1354
                foreach ::tcl::x $::tcl::origCmds {
1355
                    catch {unset ::tcl::newCmds($::tcl::x)}
1356
                }
1357
                foreach ::tcl::x [array names ::tcl::newCmds] {
1358
                    # reverse engineer which namespace a command comes from
1359
 
1360
                    set ::tcl::abs [namespace origin $::tcl::x]
1361
 
1362
                    # special case so that global names have no leading
1363
                    # ::, this is required by the unknown command
1364
 
1365
                    set ::tcl::abs [auto_qualify $::tcl::abs ::]
1366
 
1367
                    if {[string compare $::tcl::x $::tcl::abs] != 0} {
1368
                        # Name changed during qualification
1369
 
1370
                        set ::tcl::newCmds($::tcl::abs) 1
1371
                        unset ::tcl::newCmds($::tcl::x)
1372
                    }
1373
                }
1374
 
1375
                # Look through the packages that appeared, and if there is
1376
                # a version provided, then record it
1377
 
1378
                foreach ::tcl::x [package names] {
1379
                    if {([string compare [package provide $::tcl::x] ""] != 0) \
1380
                            && ![info exists ::tcl::packages($::tcl::x)]} {
1381
                        lappend ::tcl::newPkgs \
1382
                            [list $::tcl::x [package provide $::tcl::x]]
1383
                    }
1384
                }
1385
            }
1386
        } msg] == 1} {
1387
            set what [$c eval set ::tcl::debug]
1388
            if {$doVerbose} {
1389
                tclLog "warning: error while $what $file: $msg"
1390
            }
1391
        } else {
1392
            set type [$c eval set ::tcl::type]
1393
            set cmds [lsort [$c eval array names ::tcl::newCmds]]
1394
            set pkgs [$c eval set ::tcl::newPkgs]
1395
            if {[llength $pkgs] > 1} {
1396
                tclLog "warning: \"$file\" provides more than one package ($pkgs)"
1397
            }
1398
            foreach pkg $pkgs {
1399
                # cmds is empty/not used in the direct case
1400
                lappend files($pkg) [list $file $type $cmds]
1401
            }
1402
 
1403
            if {$doVerbose} {
1404
                tclLog "processed $file"
1405
            }
1406
        }
1407
        interp delete $c
1408
    }
1409
 
1410
    foreach pkg [lsort [array names files]] {
1411
        append index "\npackage ifneeded $pkg "
1412
        if {$direct} {
1413
            set cmdList {}
1414
            foreach elem $files($pkg) {
1415
                set file [lindex $elem 0]
1416
                set type [lindex $elem 1]
1417
                lappend cmdList "\[list $type \[file join \$dir\
1418
                        [list $file]\]\]"
1419
            }
1420
            append index [join $cmdList "\\n"]
1421
        } else {
1422
            append index "\[list tclPkgSetup \$dir [lrange $pkg 0 0]\
1423
                    [lrange $pkg 1 1] [list $files($pkg)]\]"
1424
        }
1425
    }
1426
    set f [open pkgIndex.tcl w]
1427
    puts $f $index
1428
    close $f
1429
    cd $oldDir
1430
}
1431
 
1432
# tclPkgSetup --
1433
# This is a utility procedure use by pkgIndex.tcl files.  It is invoked
1434
# as part of a "package ifneeded" script.  It calls "package provide"
1435
# to indicate that a package is available, then sets entries in the
1436
# auto_index array so that the package's files will be auto-loaded when
1437
# the commands are used.
1438
#
1439
# Arguments:
1440
# dir -                 Directory containing all the files for this package.
1441
# pkg -                 Name of the package (no version number).
1442
# version -             Version number for the package, such as 2.1.3.
1443
# files -               List of files that constitute the package.  Each
1444
#                       element is a sub-list with three elements.  The first
1445
#                       is the name of a file relative to $dir, the second is
1446
#                       "load" or "source", indicating whether the file is a
1447
#                       loadable binary or a script to source, and the third
1448
#                       is a list of commands defined by this file.
1449
 
1450
proc tclPkgSetup {dir pkg version files} {
1451
    global auto_index
1452
 
1453
    package provide $pkg $version
1454
    foreach fileInfo $files {
1455
        set f [lindex $fileInfo 0]
1456
        set type [lindex $fileInfo 1]
1457
        foreach cmd [lindex $fileInfo 2] {
1458
            if {$type == "load"} {
1459
                set auto_index($cmd) [list load [file join $dir $f] $pkg]
1460
            } else {
1461
                set auto_index($cmd) [list source [file join $dir $f]]
1462
            }
1463
        }
1464
    }
1465
}
1466
 
1467
# tclMacPkgSearch --
1468
# The procedure is used on the Macintosh to search a given directory for files
1469
# with a TEXT resource named "pkgIndex".  If it exists it is sourced in to the
1470
# interpreter to setup the package database.
1471
 
1472
proc tclMacPkgSearch {dir} {
1473
    foreach x [glob -nocomplain [file join $dir *.shlb]] {
1474
        if {[file isfile $x]} {
1475
            set res [resource open $x]
1476
            foreach y [resource list TEXT $res] {
1477
                if {$y == "pkgIndex"} {source -rsrc pkgIndex}
1478
            }
1479
            catch {resource close $res}
1480
        }
1481
    }
1482
}
1483
 
1484
# tclPkgUnknown --
1485
# This procedure provides the default for the "package unknown" function.
1486
# It is invoked when a package that's needed can't be found.  It scans
1487
# the auto_path directories and their immediate children looking for
1488
# pkgIndex.tcl files and sources any such files that are found to setup
1489
# the package database.  (On the Macintosh we also search for pkgIndex
1490
# TEXT resources in all files.)
1491
#
1492
# Arguments:
1493
# name -                Name of desired package.  Not used.
1494
# version -             Version of desired package.  Not used.
1495
# exact -               Either "-exact" or omitted.  Not used.
1496
 
1497
proc tclPkgUnknown {name version {exact {}}} {
1498
    global auto_path tcl_platform env
1499
 
1500
    if {![info exists auto_path]} {
1501
        return
1502
    }
1503
    for {set i [expr {[llength $auto_path] - 1}]} {$i >= 0} {incr i -1} {
1504
        # we can't use glob in safe interps, so enclose the following
1505
        # in a catch statement
1506
        catch {
1507
            foreach file [glob -nocomplain [file join [lindex $auto_path $i] \
1508
                    * pkgIndex.tcl]] {
1509
                set dir [file dirname $file]
1510
                if {[catch {source $file} msg]} {
1511
                    tclLog "error reading package index file $file: $msg"
1512
                }
1513
            }
1514
        }
1515
        set dir [lindex $auto_path $i]
1516
        set file [file join $dir pkgIndex.tcl]
1517
        # safe interps usually don't have "file readable", nor stderr channel
1518
        if {[interp issafe] || [file readable $file]} {
1519
            if {[catch {source $file} msg] && ![interp issafe]}  {
1520
                tclLog "error reading package index file $file: $msg"
1521
            }
1522
        }
1523
        # On the Macintosh we also look in the resource fork 
1524
        # of shared libraries
1525
        # We can't use tclMacPkgSearch in safe interps because it uses glob
1526
        if {(![interp issafe]) && ($tcl_platform(platform) == "macintosh")} {
1527
            set dir [lindex $auto_path $i]
1528
            tclMacPkgSearch $dir
1529
            foreach x [glob -nocomplain [file join $dir *]] {
1530
                if {[file isdirectory $x]} {
1531
                    set dir $x
1532
                    tclMacPkgSearch $dir
1533
                }
1534
            }
1535
        }
1536
    }
1537
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.