auto.tcl 22 KB

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