namespace eval ::pkg {
}
proc pkg_compareExtension { fileName {ext {}} } {
global tcl_platform
if {![string length $ext]} {set ext [info sharedlibextension]}
if {[string equal $tcl_platform(platform) "windows"]} {
return [string equal -nocase [file extension $fileName] $ext]
} else {
set root $fileName
while {1} {
set currExt [file extension $root]
if {[string equal $currExt $ext]} {
return 1
}
if { ![string is integer -strict [string range $currExt 1 end]] } {
return 0
}
set root [file rootname $root]
}
}
}
proc pkg_mkIndex {args} {
global errorCode errorInfo
set usage {"pkg_mkIndex ?-direct? ?-lazy? ?-load pattern? ?-verbose? ?--? dir ?pattern ...?"};
set argCount [llength $args]
if {$argCount < 1} {
return -code error "wrong # args: should be\n$usage"
}
set more ""
set direct 1
set doVerbose 0
set loadPat ""
for {set idx 0} {$idx < $argCount} {incr idx} {
set flag [lindex $args $idx]
switch -glob -- $flag {
-- {
incr idx
break
}
-verbose {
set doVerbose 1
}
-lazy {
set direct 0
append more " -lazy"
}
-direct {
append more " -direct"
}
-load {
incr idx
set loadPat [lindex $args $idx]
append more " -load $loadPat"
}
-* {
return -code error "unknown flag $flag: should be\n$usage"
}
default {
break
}
}
}
set dir [lindex $args $idx]
set patternList [lrange $args [expr {$idx + 1}] end]
if {[llength $patternList] == 0} {
set patternList [list "*.tcl" "*[info sharedlibextension]"]
}
set oldDir [pwd]
cd $dir
if {[catch {eval glob $patternList} fileList]} {
global errorCode errorInfo
cd $oldDir
return -code error -errorcode $errorCode -errorinfo $errorInfo $fileList
}
foreach file $fileList {
if {[string equal $file "pkgIndex.tcl"]} {
continue
}
cd $oldDir
set c [interp create]
if {[string length $loadPat]} {
if {$doVerbose} {
tclLog "currently loaded packages: '[info loaded]'"
tclLog "trying to load all packages matching $loadPat"
}
if {![llength [info loaded]]} {
tclLog "warning: no packages are currently loaded, nothing"
tclLog "can possibly match '$loadPat'"
}
}
foreach pkg [info loaded] {
if {! [string match $loadPat [lindex $pkg 1]]} {
continue
}
if {$doVerbose} {
tclLog "package [lindex $pkg 1] matches '$loadPat'"
}
if {[catch {
load [lindex $pkg 0] [lindex $pkg 1] $c
} err]} {
if {$doVerbose} {
tclLog "warning: load [lindex $pkg 0] [lindex $pkg 1]\nfailed with: $err"
}
} elseif {$doVerbose} {
tclLog "loaded [lindex $pkg 0] [lindex $pkg 1]"
}
if {[string equal [lindex $pkg 1] "Tk"]} {
$c eval [list wm withdraw .]
}
}
cd $dir
$c eval {
rename package __package_orig
proc package {what args} {
switch -- $what {
require { return ; default { eval __package_orig {$what} $args }
}
}
proc tclPkgUnknown args {}
package unknown tclPkgUnknown
proc unknown {args} {}
proc auto_import {args} {}
namespace eval ::tcl {
variable file ; variable direct ; variable x ; variable debug ; variable type ; variable namespaces ; variable packages ; variable origCmds ; variable newCmds ; variable newPkgs {} ; }
}
$c eval [list set ::tcl::file $file]
$c eval [list set ::tcl::direct $direct]
foreach p {pkg_compareExtension} {
$c eval [list proc $p [info args $p] [info body $p]]
}
if {[catch {
$c eval {
set ::tcl::debug "loading or sourcing"
proc ::tcl::GetAllNamespaces {{root ::}} {
set list $root
foreach ns [namespace children $root] {
eval lappend list [::tcl::GetAllNamespaces $ns]
}
return $list
}
foreach ::tcl::x [::tcl::GetAllNamespaces] {
set ::tcl::namespaces($::tcl::x) 1
}
foreach ::tcl::x [package names] {
set ::tcl::packages($::tcl::x) 1
}
set ::tcl::origCmds [info commands]
if {[pkg_compareExtension $::tcl::file [info sharedlibextension]]} {
set ::tcl::debug loading
load [file join . $::tcl::file]
set ::tcl::type load
} else {
set ::tcl::debug sourcing
source $::tcl::file
set ::tcl::type source
}
if { !$::tcl::direct } {
foreach ::tcl::x [::tcl::GetAllNamespaces] {
if {! [info exists ::tcl::namespaces($::tcl::x)]} {
namespace import -force ${::tcl::x}::*
}
foreach ::tcl::x [info commands] {
set ::tcl::newCmds($::tcl::x) 1
}
foreach ::tcl::x $::tcl::origCmds {
catch {unset ::tcl::newCmds($::tcl::x)}
}
foreach ::tcl::x [array names ::tcl::newCmds] {
set ::tcl::abs [namespace origin $::tcl::x]
set ::tcl::abs \
[lindex [auto_qualify $::tcl::abs ::] 0]
if {[string compare $::tcl::x $::tcl::abs]} {
set ::tcl::newCmds($::tcl::abs) 1
unset ::tcl::newCmds($::tcl::x)
}
}
}
}
foreach ::tcl::x [package names] {
if {[string compare [package provide $::tcl::x] ""] \
&& ![info exists ::tcl::packages($::tcl::x)]} {
lappend ::tcl::newPkgs \
[list $::tcl::x [package provide $::tcl::x]]
}
}
}
} msg] == 1} {
set what [$c eval set ::tcl::debug]
if {$doVerbose} {
tclLog "warning: error while $what $file: $msg"
}
} else {
set what [$c eval set ::tcl::debug]
if {$doVerbose} {
tclLog "successful $what of $file"
}
set type [$c eval set ::tcl::type]
set cmds [lsort [$c eval array names ::tcl::newCmds]]
set pkgs [$c eval set ::tcl::newPkgs]
if {$doVerbose} {
tclLog "commands provided were $cmds"
tclLog "packages provided were $pkgs"
}
if {[llength $pkgs] > 1} {
tclLog "warning: \"$file\" provides more than one package ($pkgs)"
}
foreach pkg $pkgs {
lappend files($pkg) [list $file $type $cmds]
}
if {$doVerbose} {
tclLog "processed $file"
}
}
interp delete $c
}
append index "# Tcl package index file, version 1.1\n"
append index "# This file is generated by the \"pkg_mkIndex$more\" command\n"
append index "# and sourced either when an application starts up or\n"
append index "# by a \"package unknown\" script. It invokes the\n"
append index "# \"package ifneeded\" command to set up package-related\n"
append index "# information so that packages will be loaded automatically\n"
append index "# in response to \"package require\" commands. When this\n"
append index "# script is sourced, the variable \$dir must contain the\n"
append index "# full path name of this file's directory.\n"
foreach pkg [lsort [array names files]] {
set cmd {}
foreach {name version} $pkg {
break
}
lappend cmd ::pkg::create -name $name -version $version
foreach spec $files($pkg) {
foreach {file type procs} $spec {
if { $direct } {
set procs {}
}
lappend cmd "-$type" [list $file $procs]
}
}
append index "\n[eval $cmd]"
}
set f [open pkgIndex.tcl w]
puts $f $index
close $f
cd $oldDir
}
proc tclPkgSetup {dir pkg version files} {
global auto_index
package provide $pkg $version
foreach fileInfo $files {
set f [lindex $fileInfo 0]
set type [lindex $fileInfo 1]
foreach cmd [lindex $fileInfo 2] {
if {[string equal $type "load"]} {
set auto_index($cmd) [list load [file join $dir $f] $pkg]
} else {
set auto_index($cmd) [list source [file join $dir $f]]
}
}
}
}
proc tclMacPkgSearch {dir} {
foreach x [glob -directory $dir -nocomplain *.shlb] {
if {[file isfile $x]} {
set res [resource open $x]
foreach y [resource list TEXT $res] {
if {[string equal $y "pkgIndex"]} {source -rsrc pkgIndex}
}
catch {resource close $res}
}
}
}
proc tclPkgUnknown {name version {exact {}}} {
global auto_path tcl_platform env
if {![info exists auto_path]} {
return
}
set old_path [set use_path $auto_path]
while {[llength $use_path]} {
set dir [lindex $use_path end]
catch {
foreach file [glob -directory $dir -join -nocomplain \
* pkgIndex.tcl] {
set dir [file dirname $file]
if {[file readable $file] && ![info exists procdDirs($dir)]} {
if {[catch {source $file} msg]} {
tclLog "error reading package index file $file: $msg"
} else {
set procdDirs($dir) 1
}
}
}
}
if {[string equal $::tcl_platform(platform) "unix"] && \
[string equal $::tcl_platform(os) "Darwin"]} {
set dir [lindex $use_path end]
catch {
foreach file [glob -directory $dir -join -nocomplain \
* Resources Scripts pkgIndex.tcl] {
set dir [file dirname $file]
if {[file readable $file] && ![info exists procdDirs($dir)]} {
if {[catch {source $file} msg]} {
tclLog "error reading package index file $file: $msg"
} else {
set procdDirs($dir) 1
}
}
}
}
}
set dir [lindex $use_path end]
set file [file join $dir pkgIndex.tcl]
if {([interp issafe] || [file readable $file]) && \
![info exists procdDirs($dir)]} {
if {[catch {source $file} msg] && ![interp issafe]} {
tclLog "error reading package index file $file: $msg"
} else {
set procdDirs($dir) 1
}
}
if {(![interp issafe]) && \
[string equal $tcl_platform(platform) "macintosh"]} {
set dir [lindex $use_path end]
if {![info exists procdDirs($dir)]} {
tclMacPkgSearch $dir
set procdDirs($dir) 1
}
foreach x [glob -directory $dir -nocomplain *] {
if {[file isdirectory $x] && ![info exists procdDirs($x)]} {
set dir $x
tclMacPkgSearch $dir
set procdDirs($dir) 1
}
}
}
set use_path [lrange $use_path 0 end-1]
if {[string compare $old_path $auto_path]} {
foreach dir $auto_path {
lappend use_path $dir
}
set old_path $auto_path
}
}
}
proc ::pkg::create {args} {
append err(usage) "[lindex [info level 0] 0] "
append err(usage) "-name packageName -version packageVersion"
append err(usage) "?-load {filename ?{procs}?}? ... "
append err(usage) "?-source {filename ?{procs}?}? ..."
set err(wrongNumArgs) "wrong # args: should be \"$err(usage)\""
set err(valueMissing) "value for \"%s\" missing: should be \"$err(usage)\""
set err(unknownOpt) "unknown option \"%s\": should be \"$err(usage)\""
set err(noLoadOrSource) "at least one of -load and -source must be given"
set len [llength $args]
if { $len < 6 } {
error $err(wrongNumArgs)
}
set opts(-name) {}
set opts(-version) {}
set opts(-source) {}
set opts(-load) {}
for {set i 0} {$i < $len} {incr i} {
set flag [lindex $args $i]
incr i
switch -glob -- $flag {
"-name" -
"-version" {
if { $i >= $len } {
error [format $err(valueMissing) $flag]
}
set opts($flag) [lindex $args $i]
}
"-source" -
"-load" {
if { $i >= $len } {
error [format $err(valueMissing) $flag]
}
lappend opts($flag) [lindex $args $i]
}
default {
error [format $err(unknownOpt) [lindex $args $i]]
}
}
}
if { [llength $opts(-name)] == 0 } {
error [format $err(valueMissing) "-name"]
}
if { [llength $opts(-version)] == 0 } {
error [format $err(valueMissing) "-version"]
}
if { [llength $opts(-source)] == 0 && [llength $opts(-load)] == 0 } {
error $err(noLoadOrSource)
}
set cmdline "package ifneeded $opts(-name) $opts(-version) "
set cmdList {}
set lazyFileList {}
foreach key {load source} {
foreach filespec $opts(-$key) {
foreach {filename proclist} {{} {}} {
break
}
foreach {filename proclist} $filespec {
break
}
if { [llength $proclist] == 0 } {
set cmd "\[list $key \[file join \$dir [list $filename]\]\]"
lappend cmdList $cmd
} else {
lappend lazyFileList [list $filename $key $proclist]
}
}
}
if { [llength $lazyFileList] > 0 } {
lappend cmdList "\[list tclPkgSetup \$dir $opts(-name)\
$opts(-version) [list $lazyFileList]\]"
}
append cmdline [join $cmdList "\\n"]
return $cmdline
}