sl@0
|
1 |
# auto.tcl --
|
sl@0
|
2 |
#
|
sl@0
|
3 |
# utility procs formerly in init.tcl dealing with auto execution
|
sl@0
|
4 |
# of commands and can be auto loaded themselves.
|
sl@0
|
5 |
#
|
sl@0
|
6 |
# RCS: @(#) $Id: auto.tcl,v 1.12.2.10 2005/07/23 03:31:41 dgp Exp $
|
sl@0
|
7 |
#
|
sl@0
|
8 |
# Copyright (c) 1991-1993 The Regents of the University of California.
|
sl@0
|
9 |
# Copyright (c) 1994-1998 Sun Microsystems, Inc.
|
sl@0
|
10 |
#
|
sl@0
|
11 |
# See the file "license.terms" for information on usage and redistribution
|
sl@0
|
12 |
# of this file, and for a DISCLAIMER OF ALL WARRANTIES.
|
sl@0
|
13 |
#
|
sl@0
|
14 |
|
sl@0
|
15 |
# auto_reset --
|
sl@0
|
16 |
#
|
sl@0
|
17 |
# Destroy all cached information for auto-loading and auto-execution,
|
sl@0
|
18 |
# so that the information gets recomputed the next time it's needed.
|
sl@0
|
19 |
# Also delete any procedures that are listed in the auto-load index
|
sl@0
|
20 |
# except those defined in this file.
|
sl@0
|
21 |
#
|
sl@0
|
22 |
# Arguments:
|
sl@0
|
23 |
# None.
|
sl@0
|
24 |
|
sl@0
|
25 |
proc auto_reset {} {
|
sl@0
|
26 |
global auto_execs auto_index auto_oldpath
|
sl@0
|
27 |
foreach p [info procs] {
|
sl@0
|
28 |
if {[info exists auto_index($p)] && ![string match auto_* $p]
|
sl@0
|
29 |
&& ([lsearch -exact {unknown pkg_mkIndex tclPkgSetup
|
sl@0
|
30 |
tcl_findLibrary pkg_compareExtension
|
sl@0
|
31 |
tclPkgUnknown tcl::MacOSXPkgUnknown
|
sl@0
|
32 |
tcl::MacPkgUnknown} $p] < 0)} {
|
sl@0
|
33 |
rename $p {}
|
sl@0
|
34 |
}
|
sl@0
|
35 |
}
|
sl@0
|
36 |
unset -nocomplain auto_execs auto_index auto_oldpath
|
sl@0
|
37 |
}
|
sl@0
|
38 |
|
sl@0
|
39 |
# tcl_findLibrary --
|
sl@0
|
40 |
#
|
sl@0
|
41 |
# This is a utility for extensions that searches for a library directory
|
sl@0
|
42 |
# using a canonical searching algorithm. A side effect is to source
|
sl@0
|
43 |
# the initialization script and set a global library variable.
|
sl@0
|
44 |
#
|
sl@0
|
45 |
# Arguments:
|
sl@0
|
46 |
# basename Prefix of the directory name, (e.g., "tk")
|
sl@0
|
47 |
# version Version number of the package, (e.g., "8.0")
|
sl@0
|
48 |
# patch Patchlevel of the package, (e.g., "8.0.3")
|
sl@0
|
49 |
# initScript Initialization script to source (e.g., tk.tcl)
|
sl@0
|
50 |
# enVarName environment variable to honor (e.g., TK_LIBRARY)
|
sl@0
|
51 |
# varName Global variable to set when done (e.g., tk_library)
|
sl@0
|
52 |
|
sl@0
|
53 |
proc tcl_findLibrary {basename version patch initScript enVarName varName} {
|
sl@0
|
54 |
upvar #0 $varName the_library
|
sl@0
|
55 |
global env errorInfo
|
sl@0
|
56 |
|
sl@0
|
57 |
set dirs {}
|
sl@0
|
58 |
set errors {}
|
sl@0
|
59 |
|
sl@0
|
60 |
# The C application may have hardwired a path, which we honor
|
sl@0
|
61 |
|
sl@0
|
62 |
if {[info exists the_library] && $the_library ne ""} {
|
sl@0
|
63 |
lappend dirs $the_library
|
sl@0
|
64 |
} else {
|
sl@0
|
65 |
|
sl@0
|
66 |
# Do the canonical search
|
sl@0
|
67 |
|
sl@0
|
68 |
# 1. From an environment variable, if it exists.
|
sl@0
|
69 |
# Placing this first gives the end-user ultimate control
|
sl@0
|
70 |
# to work-around any bugs, or to customize.
|
sl@0
|
71 |
|
sl@0
|
72 |
if {[info exists env($enVarName)]} {
|
sl@0
|
73 |
lappend dirs $env($enVarName)
|
sl@0
|
74 |
}
|
sl@0
|
75 |
|
sl@0
|
76 |
# 2. In the package script directory registered within
|
sl@0
|
77 |
# the configuration of the package itself.
|
sl@0
|
78 |
#
|
sl@0
|
79 |
# Only do this for Tcl 8.5+, when Tcl_RegsiterConfig() is available.
|
sl@0
|
80 |
#if {[catch {
|
sl@0
|
81 |
# ::${basename}::pkgconfig get scriptdir,runtime
|
sl@0
|
82 |
#} value] == 0} {
|
sl@0
|
83 |
# lappend dirs $value
|
sl@0
|
84 |
#}
|
sl@0
|
85 |
|
sl@0
|
86 |
# 3. Relative to auto_path directories. This checks relative to the
|
sl@0
|
87 |
# Tcl library as well as allowing loading of libraries added to the
|
sl@0
|
88 |
# auto_path that is not relative to the core library or binary paths.
|
sl@0
|
89 |
foreach d $::auto_path {
|
sl@0
|
90 |
lappend dirs [file join $d $basename$version]
|
sl@0
|
91 |
if {$::tcl_platform(platform) eq "unix"
|
sl@0
|
92 |
&& $::tcl_platform(os) eq "Darwin"} {
|
sl@0
|
93 |
# 4. On MacOSX, check the Resources/Scripts subdir too
|
sl@0
|
94 |
lappend dirs [file join $d $basename$version Resources Scripts]
|
sl@0
|
95 |
}
|
sl@0
|
96 |
}
|
sl@0
|
97 |
|
sl@0
|
98 |
# 3. Various locations relative to the executable
|
sl@0
|
99 |
# ../lib/foo1.0 (From bin directory in install hierarchy)
|
sl@0
|
100 |
# ../../lib/foo1.0 (From bin/arch directory in install hierarchy)
|
sl@0
|
101 |
# ../library (From unix directory in build hierarchy)
|
sl@0
|
102 |
set parentDir [file dirname [file dirname [info nameofexecutable]]]
|
sl@0
|
103 |
set grandParentDir [file dirname $parentDir]
|
sl@0
|
104 |
lappend dirs [file join $parentDir lib $basename$version]
|
sl@0
|
105 |
lappend dirs [file join $grandParentDir lib $basename$version]
|
sl@0
|
106 |
lappend dirs [file join $parentDir library]
|
sl@0
|
107 |
|
sl@0
|
108 |
# Remaining locations are out of date (when relevant, they ought
|
sl@0
|
109 |
# to be covered by the $::auto_path seach above).
|
sl@0
|
110 |
#
|
sl@0
|
111 |
# ../../library (From unix/arch directory in build hierarchy)
|
sl@0
|
112 |
# ../../foo1.0.1/library
|
sl@0
|
113 |
# (From unix directory in parallel build hierarchy)
|
sl@0
|
114 |
# ../../../foo1.0.1/library
|
sl@0
|
115 |
# (From unix/arch directory in parallel build hierarchy)
|
sl@0
|
116 |
#
|
sl@0
|
117 |
# For the sake of extra compatibility safety, we keep adding these
|
sl@0
|
118 |
# paths during the 8.4.* release series.
|
sl@0
|
119 |
if {1} {
|
sl@0
|
120 |
lappend dirs [file join $grandParentDir library]
|
sl@0
|
121 |
lappend dirs [file join $grandParentDir $basename$patch library]
|
sl@0
|
122 |
lappend dirs [file join [file dirname $grandParentDir] \
|
sl@0
|
123 |
$basename$patch library]
|
sl@0
|
124 |
}
|
sl@0
|
125 |
}
|
sl@0
|
126 |
# uniquify $dirs in order
|
sl@0
|
127 |
array set seen {}
|
sl@0
|
128 |
foreach i $dirs {
|
sl@0
|
129 |
# For Tcl 8.4.9, we've disabled the use of [file normalize] here.
|
sl@0
|
130 |
# This means that two different path names that are the same path
|
sl@0
|
131 |
# in normalized form, will both remain on the search path. There
|
sl@0
|
132 |
# should be no harm in that, just a bit more file system access
|
sl@0
|
133 |
# than is strictly necessary.
|
sl@0
|
134 |
#
|
sl@0
|
135 |
# [file normalize] has been disabled because of reports it has
|
sl@0
|
136 |
# caused difficulties with the freewrap utility. To keep
|
sl@0
|
137 |
# compatibility with freewrap's needs, we'll keep this disabled
|
sl@0
|
138 |
# throughout the 8.4.x (x >= 9) releases. See Bug 1072136.
|
sl@0
|
139 |
if {1 || [interp issafe]} {
|
sl@0
|
140 |
set norm $i
|
sl@0
|
141 |
} else {
|
sl@0
|
142 |
set norm [file normalize $i]
|
sl@0
|
143 |
}
|
sl@0
|
144 |
if {[info exists seen($norm)]} { continue }
|
sl@0
|
145 |
set seen($norm) ""
|
sl@0
|
146 |
lappend uniqdirs $i
|
sl@0
|
147 |
}
|
sl@0
|
148 |
set dirs $uniqdirs
|
sl@0
|
149 |
foreach i $dirs {
|
sl@0
|
150 |
set the_library $i
|
sl@0
|
151 |
set file [file join $i $initScript]
|
sl@0
|
152 |
|
sl@0
|
153 |
# source everything when in a safe interpreter because
|
sl@0
|
154 |
# we have a source command, but no file exists command
|
sl@0
|
155 |
|
sl@0
|
156 |
if {[interp issafe] || [file exists $file]} {
|
sl@0
|
157 |
if {![catch {uplevel #0 [list source $file]} msg]} {
|
sl@0
|
158 |
return
|
sl@0
|
159 |
} else {
|
sl@0
|
160 |
append errors "$file: $msg\n$errorInfo\n"
|
sl@0
|
161 |
}
|
sl@0
|
162 |
}
|
sl@0
|
163 |
}
|
sl@0
|
164 |
unset -nocomplain the_library
|
sl@0
|
165 |
set msg "Can't find a usable $initScript in the following directories: \n"
|
sl@0
|
166 |
append msg " $dirs\n\n"
|
sl@0
|
167 |
append msg "$errors\n\n"
|
sl@0
|
168 |
append msg "This probably means that $basename wasn't installed properly.\n"
|
sl@0
|
169 |
error $msg
|
sl@0
|
170 |
}
|
sl@0
|
171 |
|
sl@0
|
172 |
|
sl@0
|
173 |
# ----------------------------------------------------------------------
|
sl@0
|
174 |
# auto_mkindex
|
sl@0
|
175 |
# ----------------------------------------------------------------------
|
sl@0
|
176 |
# The following procedures are used to generate the tclIndex file
|
sl@0
|
177 |
# from Tcl source files. They use a special safe interpreter to
|
sl@0
|
178 |
# parse Tcl source files, writing out index entries as "proc"
|
sl@0
|
179 |
# commands are encountered. This implementation won't work in a
|
sl@0
|
180 |
# safe interpreter, since a safe interpreter can't create the
|
sl@0
|
181 |
# special parser and mess with its commands.
|
sl@0
|
182 |
|
sl@0
|
183 |
if {[interp issafe]} {
|
sl@0
|
184 |
return ;# Stop sourcing the file here
|
sl@0
|
185 |
}
|
sl@0
|
186 |
|
sl@0
|
187 |
# auto_mkindex --
|
sl@0
|
188 |
# Regenerate a tclIndex file from Tcl source files. Takes as argument
|
sl@0
|
189 |
# the name of the directory in which the tclIndex file is to be placed,
|
sl@0
|
190 |
# followed by any number of glob patterns to use in that directory to
|
sl@0
|
191 |
# locate all of the relevant files.
|
sl@0
|
192 |
#
|
sl@0
|
193 |
# Arguments:
|
sl@0
|
194 |
# dir - Name of the directory in which to create an index.
|
sl@0
|
195 |
# args - Any number of additional arguments giving the
|
sl@0
|
196 |
# names of files within dir. If no additional
|
sl@0
|
197 |
# are given auto_mkindex will look for *.tcl.
|
sl@0
|
198 |
|
sl@0
|
199 |
proc auto_mkindex {dir args} {
|
sl@0
|
200 |
global errorCode errorInfo
|
sl@0
|
201 |
|
sl@0
|
202 |
if {[interp issafe]} {
|
sl@0
|
203 |
error "can't generate index within safe interpreter"
|
sl@0
|
204 |
}
|
sl@0
|
205 |
|
sl@0
|
206 |
set oldDir [pwd]
|
sl@0
|
207 |
cd $dir
|
sl@0
|
208 |
set dir [pwd]
|
sl@0
|
209 |
|
sl@0
|
210 |
append index "# Tcl autoload index file, version 2.0\n"
|
sl@0
|
211 |
append index "# This file is generated by the \"auto_mkindex\" command\n"
|
sl@0
|
212 |
append index "# and sourced to set up indexing information for one or\n"
|
sl@0
|
213 |
append index "# more commands. Typically each line is a command that\n"
|
sl@0
|
214 |
append index "# sets an element in the auto_index array, where the\n"
|
sl@0
|
215 |
append index "# element name is the name of a command and the value is\n"
|
sl@0
|
216 |
append index "# a script that loads the command.\n\n"
|
sl@0
|
217 |
if {[llength $args] == 0} {
|
sl@0
|
218 |
set args *.tcl
|
sl@0
|
219 |
}
|
sl@0
|
220 |
|
sl@0
|
221 |
auto_mkindex_parser::init
|
sl@0
|
222 |
foreach file [eval [linsert $args 0 glob --]] {
|
sl@0
|
223 |
if {[catch {auto_mkindex_parser::mkindex $file} msg] == 0} {
|
sl@0
|
224 |
append index $msg
|
sl@0
|
225 |
} else {
|
sl@0
|
226 |
set code $errorCode
|
sl@0
|
227 |
set info $errorInfo
|
sl@0
|
228 |
cd $oldDir
|
sl@0
|
229 |
error $msg $info $code
|
sl@0
|
230 |
}
|
sl@0
|
231 |
}
|
sl@0
|
232 |
auto_mkindex_parser::cleanup
|
sl@0
|
233 |
|
sl@0
|
234 |
set fid [open "tclIndex" w]
|
sl@0
|
235 |
puts -nonewline $fid $index
|
sl@0
|
236 |
close $fid
|
sl@0
|
237 |
cd $oldDir
|
sl@0
|
238 |
}
|
sl@0
|
239 |
|
sl@0
|
240 |
# Original version of auto_mkindex that just searches the source
|
sl@0
|
241 |
# code for "proc" at the beginning of the line.
|
sl@0
|
242 |
|
sl@0
|
243 |
proc auto_mkindex_old {dir args} {
|
sl@0
|
244 |
global errorCode errorInfo
|
sl@0
|
245 |
set oldDir [pwd]
|
sl@0
|
246 |
cd $dir
|
sl@0
|
247 |
set dir [pwd]
|
sl@0
|
248 |
append index "# Tcl autoload index file, version 2.0\n"
|
sl@0
|
249 |
append index "# This file is generated by the \"auto_mkindex\" command\n"
|
sl@0
|
250 |
append index "# and sourced to set up indexing information for one or\n"
|
sl@0
|
251 |
append index "# more commands. Typically each line is a command that\n"
|
sl@0
|
252 |
append index "# sets an element in the auto_index array, where the\n"
|
sl@0
|
253 |
append index "# element name is the name of a command and the value is\n"
|
sl@0
|
254 |
append index "# a script that loads the command.\n\n"
|
sl@0
|
255 |
if {[llength $args] == 0} {
|
sl@0
|
256 |
set args *.tcl
|
sl@0
|
257 |
}
|
sl@0
|
258 |
foreach file [eval [linsert $args 0 glob --]] {
|
sl@0
|
259 |
set f ""
|
sl@0
|
260 |
set error [catch {
|
sl@0
|
261 |
set f [open $file]
|
sl@0
|
262 |
while {[gets $f line] >= 0} {
|
sl@0
|
263 |
if {[regexp {^proc[ ]+([^ ]*)} $line match procName]} {
|
sl@0
|
264 |
set procName [lindex [auto_qualify $procName "::"] 0]
|
sl@0
|
265 |
append index "set [list auto_index($procName)]"
|
sl@0
|
266 |
append index " \[list source \[file join \$dir [list $file]\]\]\n"
|
sl@0
|
267 |
}
|
sl@0
|
268 |
}
|
sl@0
|
269 |
close $f
|
sl@0
|
270 |
} msg]
|
sl@0
|
271 |
if {$error} {
|
sl@0
|
272 |
set code $errorCode
|
sl@0
|
273 |
set info $errorInfo
|
sl@0
|
274 |
catch {close $f}
|
sl@0
|
275 |
cd $oldDir
|
sl@0
|
276 |
error $msg $info $code
|
sl@0
|
277 |
}
|
sl@0
|
278 |
}
|
sl@0
|
279 |
set f ""
|
sl@0
|
280 |
set error [catch {
|
sl@0
|
281 |
set f [open tclIndex w]
|
sl@0
|
282 |
puts -nonewline $f $index
|
sl@0
|
283 |
close $f
|
sl@0
|
284 |
cd $oldDir
|
sl@0
|
285 |
} msg]
|
sl@0
|
286 |
if {$error} {
|
sl@0
|
287 |
set code $errorCode
|
sl@0
|
288 |
set info $errorInfo
|
sl@0
|
289 |
catch {close $f}
|
sl@0
|
290 |
cd $oldDir
|
sl@0
|
291 |
error $msg $info $code
|
sl@0
|
292 |
}
|
sl@0
|
293 |
}
|
sl@0
|
294 |
|
sl@0
|
295 |
# Create a safe interpreter that can be used to parse Tcl source files
|
sl@0
|
296 |
# generate a tclIndex file for autoloading. This interp contains
|
sl@0
|
297 |
# commands for things that need index entries. Each time a command
|
sl@0
|
298 |
# is executed, it writes an entry out to the index file.
|
sl@0
|
299 |
|
sl@0
|
300 |
namespace eval auto_mkindex_parser {
|
sl@0
|
301 |
variable parser "" ;# parser used to build index
|
sl@0
|
302 |
variable index "" ;# maintains index as it is built
|
sl@0
|
303 |
variable scriptFile "" ;# name of file being processed
|
sl@0
|
304 |
variable contextStack "" ;# stack of namespace scopes
|
sl@0
|
305 |
variable imports "" ;# keeps track of all imported cmds
|
sl@0
|
306 |
variable initCommands "" ;# list of commands that create aliases
|
sl@0
|
307 |
|
sl@0
|
308 |
proc init {} {
|
sl@0
|
309 |
variable parser
|
sl@0
|
310 |
variable initCommands
|
sl@0
|
311 |
|
sl@0
|
312 |
if {![interp issafe]} {
|
sl@0
|
313 |
set parser [interp create -safe]
|
sl@0
|
314 |
$parser hide info
|
sl@0
|
315 |
$parser hide rename
|
sl@0
|
316 |
$parser hide proc
|
sl@0
|
317 |
$parser hide namespace
|
sl@0
|
318 |
$parser hide eval
|
sl@0
|
319 |
$parser hide puts
|
sl@0
|
320 |
$parser invokehidden namespace delete ::
|
sl@0
|
321 |
$parser invokehidden proc unknown {args} {}
|
sl@0
|
322 |
|
sl@0
|
323 |
# We'll need access to the "namespace" command within the
|
sl@0
|
324 |
# interp. Put it back, but move it out of the way.
|
sl@0
|
325 |
|
sl@0
|
326 |
$parser expose namespace
|
sl@0
|
327 |
$parser invokehidden rename namespace _%@namespace
|
sl@0
|
328 |
$parser expose eval
|
sl@0
|
329 |
$parser invokehidden rename eval _%@eval
|
sl@0
|
330 |
|
sl@0
|
331 |
# Install all the registered psuedo-command implementations
|
sl@0
|
332 |
|
sl@0
|
333 |
foreach cmd $initCommands {
|
sl@0
|
334 |
eval $cmd
|
sl@0
|
335 |
}
|
sl@0
|
336 |
}
|
sl@0
|
337 |
}
|
sl@0
|
338 |
proc cleanup {} {
|
sl@0
|
339 |
variable parser
|
sl@0
|
340 |
interp delete $parser
|
sl@0
|
341 |
unset parser
|
sl@0
|
342 |
}
|
sl@0
|
343 |
}
|
sl@0
|
344 |
|
sl@0
|
345 |
# auto_mkindex_parser::mkindex --
|
sl@0
|
346 |
#
|
sl@0
|
347 |
# Used by the "auto_mkindex" command to create a "tclIndex" file for
|
sl@0
|
348 |
# the given Tcl source file. Executes the commands in the file, and
|
sl@0
|
349 |
# handles things like the "proc" command by adding an entry for the
|
sl@0
|
350 |
# index file. Returns a string that represents the index file.
|
sl@0
|
351 |
#
|
sl@0
|
352 |
# Arguments:
|
sl@0
|
353 |
# file Name of Tcl source file to be indexed.
|
sl@0
|
354 |
|
sl@0
|
355 |
proc auto_mkindex_parser::mkindex {file} {
|
sl@0
|
356 |
variable parser
|
sl@0
|
357 |
variable index
|
sl@0
|
358 |
variable scriptFile
|
sl@0
|
359 |
variable contextStack
|
sl@0
|
360 |
variable imports
|
sl@0
|
361 |
|
sl@0
|
362 |
set scriptFile $file
|
sl@0
|
363 |
|
sl@0
|
364 |
set fid [open $file]
|
sl@0
|
365 |
set contents [read $fid]
|
sl@0
|
366 |
close $fid
|
sl@0
|
367 |
|
sl@0
|
368 |
# There is one problem with sourcing files into the safe
|
sl@0
|
369 |
# interpreter: references like "$x" will fail since code is not
|
sl@0
|
370 |
# really being executed and variables do not really exist.
|
sl@0
|
371 |
# To avoid this, we replace all $ with \0 (literally, the null char)
|
sl@0
|
372 |
# later, when getting proc names we will have to reverse this replacement,
|
sl@0
|
373 |
# in case there were any $ in the proc name. This will cause a problem
|
sl@0
|
374 |
# if somebody actually tries to have a \0 in their proc name. Too bad
|
sl@0
|
375 |
# for them.
|
sl@0
|
376 |
set contents [string map "$ \u0000" $contents]
|
sl@0
|
377 |
|
sl@0
|
378 |
set index ""
|
sl@0
|
379 |
set contextStack ""
|
sl@0
|
380 |
set imports ""
|
sl@0
|
381 |
|
sl@0
|
382 |
$parser eval $contents
|
sl@0
|
383 |
|
sl@0
|
384 |
foreach name $imports {
|
sl@0
|
385 |
catch {$parser eval [list _%@namespace forget $name]}
|
sl@0
|
386 |
}
|
sl@0
|
387 |
return $index
|
sl@0
|
388 |
}
|
sl@0
|
389 |
|
sl@0
|
390 |
# auto_mkindex_parser::hook command
|
sl@0
|
391 |
#
|
sl@0
|
392 |
# Registers a Tcl command to evaluate when initializing the
|
sl@0
|
393 |
# slave interpreter used by the mkindex parser.
|
sl@0
|
394 |
# The command is evaluated in the master interpreter, and can
|
sl@0
|
395 |
# use the variable auto_mkindex_parser::parser to get to the slave
|
sl@0
|
396 |
|
sl@0
|
397 |
proc auto_mkindex_parser::hook {cmd} {
|
sl@0
|
398 |
variable initCommands
|
sl@0
|
399 |
|
sl@0
|
400 |
lappend initCommands $cmd
|
sl@0
|
401 |
}
|
sl@0
|
402 |
|
sl@0
|
403 |
# auto_mkindex_parser::slavehook command
|
sl@0
|
404 |
#
|
sl@0
|
405 |
# Registers a Tcl command to evaluate when initializing the
|
sl@0
|
406 |
# slave interpreter used by the mkindex parser.
|
sl@0
|
407 |
# The command is evaluated in the slave interpreter.
|
sl@0
|
408 |
|
sl@0
|
409 |
proc auto_mkindex_parser::slavehook {cmd} {
|
sl@0
|
410 |
variable initCommands
|
sl@0
|
411 |
|
sl@0
|
412 |
# The $parser variable is defined to be the name of the
|
sl@0
|
413 |
# slave interpreter when this command is used later.
|
sl@0
|
414 |
|
sl@0
|
415 |
lappend initCommands "\$parser eval [list $cmd]"
|
sl@0
|
416 |
}
|
sl@0
|
417 |
|
sl@0
|
418 |
# auto_mkindex_parser::command --
|
sl@0
|
419 |
#
|
sl@0
|
420 |
# Registers a new command with the "auto_mkindex_parser" interpreter
|
sl@0
|
421 |
# that parses Tcl files. These commands are fake versions of things
|
sl@0
|
422 |
# like the "proc" command. When you execute them, they simply write
|
sl@0
|
423 |
# out an entry to a "tclIndex" file for auto-loading.
|
sl@0
|
424 |
#
|
sl@0
|
425 |
# This procedure allows extensions to register their own commands
|
sl@0
|
426 |
# with the auto_mkindex facility. For example, a package like
|
sl@0
|
427 |
# [incr Tcl] might register a "class" command so that class definitions
|
sl@0
|
428 |
# could be added to a "tclIndex" file for auto-loading.
|
sl@0
|
429 |
#
|
sl@0
|
430 |
# Arguments:
|
sl@0
|
431 |
# name Name of command recognized in Tcl files.
|
sl@0
|
432 |
# arglist Argument list for command.
|
sl@0
|
433 |
# body Implementation of command to handle indexing.
|
sl@0
|
434 |
|
sl@0
|
435 |
proc auto_mkindex_parser::command {name arglist body} {
|
sl@0
|
436 |
hook [list auto_mkindex_parser::commandInit $name $arglist $body]
|
sl@0
|
437 |
}
|
sl@0
|
438 |
|
sl@0
|
439 |
# auto_mkindex_parser::commandInit --
|
sl@0
|
440 |
#
|
sl@0
|
441 |
# This does the actual work set up by auto_mkindex_parser::command
|
sl@0
|
442 |
# This is called when the interpreter used by the parser is created.
|
sl@0
|
443 |
#
|
sl@0
|
444 |
# Arguments:
|
sl@0
|
445 |
# name Name of command recognized in Tcl files.
|
sl@0
|
446 |
# arglist Argument list for command.
|
sl@0
|
447 |
# body Implementation of command to handle indexing.
|
sl@0
|
448 |
|
sl@0
|
449 |
proc auto_mkindex_parser::commandInit {name arglist body} {
|
sl@0
|
450 |
variable parser
|
sl@0
|
451 |
|
sl@0
|
452 |
set ns [namespace qualifiers $name]
|
sl@0
|
453 |
set tail [namespace tail $name]
|
sl@0
|
454 |
if {$ns eq ""} {
|
sl@0
|
455 |
set fakeName [namespace current]::_%@fake_$tail
|
sl@0
|
456 |
} else {
|
sl@0
|
457 |
set fakeName [namespace current]::[string map {:: _} _%@fake_$name]
|
sl@0
|
458 |
}
|
sl@0
|
459 |
proc $fakeName $arglist $body
|
sl@0
|
460 |
|
sl@0
|
461 |
# YUK! Tcl won't let us alias fully qualified command names,
|
sl@0
|
462 |
# so we can't handle names like "::itcl::class". Instead,
|
sl@0
|
463 |
# we have to build procs with the fully qualified names, and
|
sl@0
|
464 |
# have the procs point to the aliases.
|
sl@0
|
465 |
|
sl@0
|
466 |
if {[string match *::* $name]} {
|
sl@0
|
467 |
set exportCmd [list _%@namespace export [namespace tail $name]]
|
sl@0
|
468 |
$parser eval [list _%@namespace eval $ns $exportCmd]
|
sl@0
|
469 |
|
sl@0
|
470 |
# The following proc definition does not work if you
|
sl@0
|
471 |
# want to tolerate space or something else diabolical
|
sl@0
|
472 |
# in the procedure name, (i.e., space in $alias)
|
sl@0
|
473 |
# The following does not work:
|
sl@0
|
474 |
# "_%@eval {$alias} \$args"
|
sl@0
|
475 |
# because $alias gets concat'ed to $args.
|
sl@0
|
476 |
# The following does not work because $cmd is somehow undefined
|
sl@0
|
477 |
# "set cmd {$alias} \; _%@eval {\$cmd} \$args"
|
sl@0
|
478 |
# A gold star to someone that can make test
|
sl@0
|
479 |
# autoMkindex-3.3 work properly
|
sl@0
|
480 |
|
sl@0
|
481 |
set alias [namespace tail $fakeName]
|
sl@0
|
482 |
$parser invokehidden proc $name {args} "_%@eval {$alias} \$args"
|
sl@0
|
483 |
$parser alias $alias $fakeName
|
sl@0
|
484 |
} else {
|
sl@0
|
485 |
$parser alias $name $fakeName
|
sl@0
|
486 |
}
|
sl@0
|
487 |
return
|
sl@0
|
488 |
}
|
sl@0
|
489 |
|
sl@0
|
490 |
# auto_mkindex_parser::fullname --
|
sl@0
|
491 |
# Used by commands like "proc" within the auto_mkindex parser.
|
sl@0
|
492 |
# Returns the qualified namespace name for the "name" argument.
|
sl@0
|
493 |
# If the "name" does not start with "::", elements are added from
|
sl@0
|
494 |
# the current namespace stack to produce a qualified name. Then,
|
sl@0
|
495 |
# the name is examined to see whether or not it should really be
|
sl@0
|
496 |
# qualified. If the name has more than the leading "::", it is
|
sl@0
|
497 |
# returned as a fully qualified name. Otherwise, it is returned
|
sl@0
|
498 |
# as a simple name. That way, the Tcl autoloader will recognize
|
sl@0
|
499 |
# it properly.
|
sl@0
|
500 |
#
|
sl@0
|
501 |
# Arguments:
|
sl@0
|
502 |
# name - Name that is being added to index.
|
sl@0
|
503 |
|
sl@0
|
504 |
proc auto_mkindex_parser::fullname {name} {
|
sl@0
|
505 |
variable contextStack
|
sl@0
|
506 |
|
sl@0
|
507 |
if {![string match ::* $name]} {
|
sl@0
|
508 |
foreach ns $contextStack {
|
sl@0
|
509 |
set name "${ns}::$name"
|
sl@0
|
510 |
if {[string match ::* $name]} {
|
sl@0
|
511 |
break
|
sl@0
|
512 |
}
|
sl@0
|
513 |
}
|
sl@0
|
514 |
}
|
sl@0
|
515 |
|
sl@0
|
516 |
if {[namespace qualifiers $name] eq ""} {
|
sl@0
|
517 |
set name [namespace tail $name]
|
sl@0
|
518 |
} elseif {![string match ::* $name]} {
|
sl@0
|
519 |
set name "::$name"
|
sl@0
|
520 |
}
|
sl@0
|
521 |
|
sl@0
|
522 |
# Earlier, mkindex replaced all $'s with \0. Now, we have to reverse
|
sl@0
|
523 |
# that replacement.
|
sl@0
|
524 |
return [string map "\u0000 $" $name]
|
sl@0
|
525 |
}
|
sl@0
|
526 |
|
sl@0
|
527 |
# Register all of the procedures for the auto_mkindex parser that
|
sl@0
|
528 |
# will build the "tclIndex" file.
|
sl@0
|
529 |
|
sl@0
|
530 |
# AUTO MKINDEX: proc name arglist body
|
sl@0
|
531 |
# Adds an entry to the auto index list for the given procedure name.
|
sl@0
|
532 |
|
sl@0
|
533 |
auto_mkindex_parser::command proc {name args} {
|
sl@0
|
534 |
variable index
|
sl@0
|
535 |
variable scriptFile
|
sl@0
|
536 |
# Do some fancy reformatting on the "source" call to handle platform
|
sl@0
|
537 |
# differences with respect to pathnames. Use format just so that the
|
sl@0
|
538 |
# command is a little easier to read (otherwise it'd be full of
|
sl@0
|
539 |
# backslashed dollar signs, etc.
|
sl@0
|
540 |
append index [list set auto_index([fullname $name])] \
|
sl@0
|
541 |
[format { [list source [file join $dir %s]]} \
|
sl@0
|
542 |
[file split $scriptFile]] "\n"
|
sl@0
|
543 |
}
|
sl@0
|
544 |
|
sl@0
|
545 |
# Conditionally add support for Tcl byte code files. There are some
|
sl@0
|
546 |
# tricky details here. First, we need to get the tbcload library
|
sl@0
|
547 |
# initialized in the current interpreter. We cannot load tbcload into the
|
sl@0
|
548 |
# slave until we have done so because it needs access to the tcl_patchLevel
|
sl@0
|
549 |
# variable. Second, because the package index file may defer loading the
|
sl@0
|
550 |
# library until we invoke a command, we need to explicitly invoke auto_load
|
sl@0
|
551 |
# to force it to be loaded. This should be a noop if the package has
|
sl@0
|
552 |
# already been loaded
|
sl@0
|
553 |
|
sl@0
|
554 |
auto_mkindex_parser::hook {
|
sl@0
|
555 |
if {![catch {package require tbcload}]} {
|
sl@0
|
556 |
if {[namespace which -command tbcload::bcproc] eq ""} {
|
sl@0
|
557 |
auto_load tbcload::bcproc
|
sl@0
|
558 |
}
|
sl@0
|
559 |
load {} tbcload $auto_mkindex_parser::parser
|
sl@0
|
560 |
|
sl@0
|
561 |
# AUTO MKINDEX: tbcload::bcproc name arglist body
|
sl@0
|
562 |
# Adds an entry to the auto index list for the given pre-compiled
|
sl@0
|
563 |
# procedure name.
|
sl@0
|
564 |
|
sl@0
|
565 |
auto_mkindex_parser::commandInit tbcload::bcproc {name args} {
|
sl@0
|
566 |
variable index
|
sl@0
|
567 |
variable scriptFile
|
sl@0
|
568 |
# Do some nice reformatting of the "source" call, to get around
|
sl@0
|
569 |
# path differences on different platforms. We use the format
|
sl@0
|
570 |
# command just so that the code is a little easier to read.
|
sl@0
|
571 |
append index [list set auto_index([fullname $name])] \
|
sl@0
|
572 |
[format { [list source [file join $dir %s]]} \
|
sl@0
|
573 |
[file split $scriptFile]] "\n"
|
sl@0
|
574 |
}
|
sl@0
|
575 |
}
|
sl@0
|
576 |
}
|
sl@0
|
577 |
|
sl@0
|
578 |
# AUTO MKINDEX: namespace eval name command ?arg arg...?
|
sl@0
|
579 |
# Adds the namespace name onto the context stack and evaluates the
|
sl@0
|
580 |
# associated body of commands.
|
sl@0
|
581 |
#
|
sl@0
|
582 |
# AUTO MKINDEX: namespace import ?-force? pattern ?pattern...?
|
sl@0
|
583 |
# Performs the "import" action in the parser interpreter. This is
|
sl@0
|
584 |
# important for any commands contained in a namespace that affect
|
sl@0
|
585 |
# the index. For example, a script may say "itcl::class ...",
|
sl@0
|
586 |
# or it may import "itcl::*" and then say "class ...". This
|
sl@0
|
587 |
# procedure does the import operation, but keeps track of imported
|
sl@0
|
588 |
# patterns so we can remove the imports later.
|
sl@0
|
589 |
|
sl@0
|
590 |
auto_mkindex_parser::command namespace {op args} {
|
sl@0
|
591 |
switch -- $op {
|
sl@0
|
592 |
eval {
|
sl@0
|
593 |
variable parser
|
sl@0
|
594 |
variable contextStack
|
sl@0
|
595 |
|
sl@0
|
596 |
set name [lindex $args 0]
|
sl@0
|
597 |
set args [lrange $args 1 end]
|
sl@0
|
598 |
|
sl@0
|
599 |
set contextStack [linsert $contextStack 0 $name]
|
sl@0
|
600 |
$parser eval [list _%@namespace eval $name] $args
|
sl@0
|
601 |
set contextStack [lrange $contextStack 1 end]
|
sl@0
|
602 |
}
|
sl@0
|
603 |
import {
|
sl@0
|
604 |
variable parser
|
sl@0
|
605 |
variable imports
|
sl@0
|
606 |
foreach pattern $args {
|
sl@0
|
607 |
if {$pattern ne "-force"} {
|
sl@0
|
608 |
lappend imports $pattern
|
sl@0
|
609 |
}
|
sl@0
|
610 |
}
|
sl@0
|
611 |
catch {$parser eval "_%@namespace import $args"}
|
sl@0
|
612 |
}
|
sl@0
|
613 |
}
|
sl@0
|
614 |
}
|
sl@0
|
615 |
|
sl@0
|
616 |
return
|