auto.tcl
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:20k
- # auto.tcl --
- #
- # utility procs formerly in init.tcl dealing with auto execution
- # of commands and can be auto loaded themselves.
- #
- # RCS: @(#) $Id: auto.tcl,v 1.12.2.10 2005/07/23 03:31:41 dgp Exp $
- #
- # Copyright (c) 1991-1993 The Regents of the University of California.
- # Copyright (c) 1994-1998 Sun Microsystems, Inc.
- #
- # See the file "license.terms" for information on usage and redistribution
- # of this file, and for a DISCLAIMER OF ALL WARRANTIES.
- #
- # auto_reset --
- #
- # Destroy all cached information for auto-loading and auto-execution,
- # so that the information gets recomputed the next time it's needed.
- # Also delete any procedures that are listed in the auto-load index
- # except those defined in this file.
- #
- # Arguments:
- # None.
- proc auto_reset {} {
- global auto_execs auto_index auto_oldpath
- foreach p [info procs] {
- if {[info exists auto_index($p)] && ![string match auto_* $p]
- && ([lsearch -exact {unknown pkg_mkIndex tclPkgSetup
- tcl_findLibrary pkg_compareExtension
- tclPkgUnknown tcl::MacOSXPkgUnknown
- tcl::MacPkgUnknown} $p] < 0)} {
- rename $p {}
- }
- }
- unset -nocomplain auto_execs auto_index auto_oldpath
- }
- # tcl_findLibrary --
- #
- # This is a utility for extensions that searches for a library directory
- # using a canonical searching algorithm. A side effect is to source
- # the initialization script and set a global library variable.
- #
- # Arguments:
- # basename Prefix of the directory name, (e.g., "tk")
- # version Version number of the package, (e.g., "8.0")
- # patch Patchlevel of the package, (e.g., "8.0.3")
- # initScript Initialization script to source (e.g., tk.tcl)
- # enVarName environment variable to honor (e.g., TK_LIBRARY)
- # varName Global variable to set when done (e.g., tk_library)
- proc tcl_findLibrary {basename version patch initScript enVarName varName} {
- upvar #0 $varName the_library
- global env errorInfo
- set dirs {}
- set errors {}
- # The C application may have hardwired a path, which we honor
- if {[info exists the_library] && $the_library ne ""} {
- lappend dirs $the_library
- } else {
- # Do the canonical search
- # 1. From an environment variable, if it exists.
- # Placing this first gives the end-user ultimate control
- # to work-around any bugs, or to customize.
- if {[info exists env($enVarName)]} {
- lappend dirs $env($enVarName)
- }
- # 2. In the package script directory registered within
- # the configuration of the package itself.
- #
- # Only do this for Tcl 8.5+, when Tcl_RegsiterConfig() is available.
- #if {[catch {
- # ::${basename}::pkgconfig get scriptdir,runtime
- #} value] == 0} {
- # lappend dirs $value
- #}
- # 3. Relative to auto_path directories. This checks relative to the
- # Tcl library as well as allowing loading of libraries added to the
- # auto_path that is not relative to the core library or binary paths.
- foreach d $::auto_path {
- lappend dirs [file join $d $basename$version]
- if {$::tcl_platform(platform) eq "unix"
- && $::tcl_platform(os) eq "Darwin"} {
- # 4. On MacOSX, check the Resources/Scripts subdir too
- lappend dirs [file join $d $basename$version Resources Scripts]
- }
- }
- # 3. Various locations relative to the executable
- # ../lib/foo1.0 (From bin directory in install hierarchy)
- # ../../lib/foo1.0 (From bin/arch directory in install hierarchy)
- # ../library (From unix directory in build hierarchy)
- set parentDir [file dirname [file dirname [info nameofexecutable]]]
- set grandParentDir [file dirname $parentDir]
- lappend dirs [file join $parentDir lib $basename$version]
- lappend dirs [file join $grandParentDir lib $basename$version]
- lappend dirs [file join $parentDir library]
- # Remaining locations are out of date (when relevant, they ought
- # to be covered by the $::auto_path seach above).
- #
- # ../../library (From unix/arch directory in build hierarchy)
- # ../../foo1.0.1/library
- # (From unix directory in parallel build hierarchy)
- # ../../../foo1.0.1/library
- # (From unix/arch directory in parallel build hierarchy)
- #
- # For the sake of extra compatibility safety, we keep adding these
- # paths during the 8.4.* release series.
- if {1} {
- lappend dirs [file join $grandParentDir library]
- lappend dirs [file join $grandParentDir $basename$patch library]
- lappend dirs [file join [file dirname $grandParentDir]
- $basename$patch library]
- }
- }
- # uniquify $dirs in order
- array set seen {}
- foreach i $dirs {
- # For Tcl 8.4.9, we've disabled the use of [file normalize] here.
- # This means that two different path names that are the same path
- # in normalized form, will both remain on the search path. There
- # should be no harm in that, just a bit more file system access
- # than is strictly necessary.
- #
- # [file normalize] has been disabled because of reports it has
- # caused difficulties with the freewrap utility. To keep
- # compatibility with freewrap's needs, we'll keep this disabled
- # throughout the 8.4.x (x >= 9) releases. See Bug 1072136.
- if {1 || [interp issafe]} {
- set norm $i
- } else {
- set norm [file normalize $i]
- }
- if {[info exists seen($norm)]} { continue }
- set seen($norm) ""
- lappend uniqdirs $i
- }
- set dirs $uniqdirs
- foreach i $dirs {
- set the_library $i
- set file [file join $i $initScript]
- # source everything when in a safe interpreter because
- # we have a source command, but no file exists command
- if {[interp issafe] || [file exists $file]} {
- if {![catch {uplevel #0 [list source $file]} msg]} {
- return
- } else {
- append errors "$file: $msgn$errorInfon"
- }
- }
- }
- unset -nocomplain the_library
- set msg "Can't find a usable $initScript in the following directories: n"
- append msg " $dirsnn"
- append msg "$errorsnn"
- append msg "This probably means that $basename wasn't installed properly.n"
- error $msg
- }
- # ----------------------------------------------------------------------
- # auto_mkindex
- # ----------------------------------------------------------------------
- # The following procedures are used to generate the tclIndex file
- # from Tcl source files. They use a special safe interpreter to
- # parse Tcl source files, writing out index entries as "proc"
- # commands are encountered. This implementation won't work in a
- # safe interpreter, since a safe interpreter can't create the
- # special parser and mess with its commands.
- if {[interp issafe]} {
- return ;# Stop sourcing the file here
- }
- # auto_mkindex --
- # Regenerate a tclIndex file from Tcl source files. Takes as argument
- # the name of the directory in which the tclIndex file is to be placed,
- # followed by any number of glob patterns to use in that directory to
- # locate all of the relevant files.
- #
- # Arguments:
- # dir - Name of the directory in which to create an index.
- # args - Any number of additional arguments giving the
- # names of files within dir. If no additional
- # are given auto_mkindex will look for *.tcl.
- proc auto_mkindex {dir args} {
- global errorCode errorInfo
- if {[interp issafe]} {
- error "can't generate index within safe interpreter"
- }
- set oldDir [pwd]
- cd $dir
- set dir [pwd]
- append index "# Tcl autoload index file, version 2.0n"
- append index "# This file is generated by the "auto_mkindex" commandn"
- append index "# and sourced to set up indexing information for one orn"
- append index "# more commands. Typically each line is a command thatn"
- append index "# sets an element in the auto_index array, where then"
- append index "# element name is the name of a command and the value isn"
- append index "# a script that loads the command.nn"
- if {[llength $args] == 0} {
- set args *.tcl
- }
- auto_mkindex_parser::init
- foreach file [eval [linsert $args 0 glob --]] {
- if {[catch {auto_mkindex_parser::mkindex $file} msg] == 0} {
- append index $msg
- } else {
- set code $errorCode
- set info $errorInfo
- cd $oldDir
- error $msg $info $code
- }
- }
- auto_mkindex_parser::cleanup
- set fid [open "tclIndex" w]
- puts -nonewline $fid $index
- close $fid
- cd $oldDir
- }
- # Original version of auto_mkindex that just searches the source
- # code for "proc" at the beginning of the line.
- proc auto_mkindex_old {dir args} {
- global errorCode errorInfo
- set oldDir [pwd]
- cd $dir
- set dir [pwd]
- append index "# Tcl autoload index file, version 2.0n"
- append index "# This file is generated by the "auto_mkindex" commandn"
- append index "# and sourced to set up indexing information for one orn"
- append index "# more commands. Typically each line is a command thatn"
- append index "# sets an element in the auto_index array, where then"
- append index "# element name is the name of a command and the value isn"
- append index "# a script that loads the command.nn"
- if {[llength $args] == 0} {
- set args *.tcl
- }
- foreach file [eval [linsert $args 0 glob --]] {
- set f ""
- set error [catch {
- set f [open $file]
- while {[gets $f line] >= 0} {
- if {[regexp {^proc[ ]+([^ ]*)} $line match procName]} {
- set procName [lindex [auto_qualify $procName "::"] 0]
- append index "set [list auto_index($procName)]"
- append index " [list source [file join $dir [list $file]]]n"
- }
- }
- close $f
- } msg]
- if {$error} {
- set code $errorCode
- set info $errorInfo
- catch {close $f}
- cd $oldDir
- error $msg $info $code
- }
- }
- set f ""
- set error [catch {
- set f [open tclIndex w]
- puts -nonewline $f $index
- close $f
- cd $oldDir
- } msg]
- if {$error} {
- set code $errorCode
- set info $errorInfo
- catch {close $f}
- cd $oldDir
- error $msg $info $code
- }
- }
- # Create a safe interpreter that can be used to parse Tcl source files
- # generate a tclIndex file for autoloading. This interp contains
- # commands for things that need index entries. Each time a command
- # is executed, it writes an entry out to the index file.
- namespace eval auto_mkindex_parser {
- variable parser "" ;# parser used to build index
- variable index "" ;# maintains index as it is built
- variable scriptFile "" ;# name of file being processed
- variable contextStack "" ;# stack of namespace scopes
- variable imports "" ;# keeps track of all imported cmds
- variable initCommands "" ;# list of commands that create aliases
- proc init {} {
- variable parser
- variable initCommands
- if {![interp issafe]} {
- set parser [interp create -safe]
- $parser hide info
- $parser hide rename
- $parser hide proc
- $parser hide namespace
- $parser hide eval
- $parser hide puts
- $parser invokehidden namespace delete ::
- $parser invokehidden proc unknown {args} {}
- # We'll need access to the "namespace" command within the
- # interp. Put it back, but move it out of the way.
- $parser expose namespace
- $parser invokehidden rename namespace _%@namespace
- $parser expose eval
- $parser invokehidden rename eval _%@eval
- # Install all the registered psuedo-command implementations
- foreach cmd $initCommands {
- eval $cmd
- }
- }
- }
- proc cleanup {} {
- variable parser
- interp delete $parser
- unset parser
- }
- }
- # auto_mkindex_parser::mkindex --
- #
- # Used by the "auto_mkindex" command to create a "tclIndex" file for
- # the given Tcl source file. Executes the commands in the file, and
- # handles things like the "proc" command by adding an entry for the
- # index file. Returns a string that represents the index file.
- #
- # Arguments:
- # file Name of Tcl source file to be indexed.
- proc auto_mkindex_parser::mkindex {file} {
- variable parser
- variable index
- variable scriptFile
- variable contextStack
- variable imports
- set scriptFile $file
- set fid [open $file]
- set contents [read $fid]
- close $fid
- # There is one problem with sourcing files into the safe
- # interpreter: references like "$x" will fail since code is not
- # really being executed and variables do not really exist.
- # To avoid this, we replace all $ with