2 #@package: TclX-ArrayProcedures for_array_keys
4 proc for_array_keys {varName arrayName codeFragment} {
5 upvar $varName enumVar $arrayName enumArray
7 if ![info exists enumArray] {
8 error "\"$arrayName\" isn't an array"
11 set searchId [array startsearch enumArray]
12 while {[array anymore enumArray $searchId]} {
13 set enumVar [array nextelement enumArray $searchId]
16 array donesearch enumArray $searchId
19 #@package: TclX-assign_fields assign_fields
21 proc assign_fields {list args} {
22 foreach varName $args {
23 set value [lvarpop list]
24 uplevel "set $varName [list $value]"
28 #@package: TclX-developer_utils saveprocs edprocs
30 proc saveprocs {fileName args} {
31 set fp [open $fileName w]
32 puts $fp "# tcl procs saved on [fmtclock [getclock]]\n"
33 puts $fp [eval "showprocs $args"]
40 set tmpFilename /tmp/tcldev.[id process]
42 set fp [open $tmpFilename w]
43 puts $fp "\n# TEMP EDIT BUFFER -- YOUR CHANGES ARE FOR THIS SESSION ONLY\n"
44 puts $fp [eval "showprocs $args"]
47 if [info exists env(EDITOR)] {
48 set editor $env(EDITOR)
53 set startMtime [file mtime $tmpFilename]
54 system "$editor $tmpFilename"
56 if {[file mtime $tmpFilename] != $startMtime} {
58 echo "Procedures were reloaded."
60 echo "No changes were made."
66 #@package: TclX-forfile for_file
68 proc for_file {var filename code} {
70 set fp [open $filename r]
71 while {[gets $fp line] >= 0} {
78 #@package: TclX-forrecur for_recursive_glob
80 proc for_recursive_glob {var globlist code {depth 1}} {
81 upvar $depth $var myVar
82 foreach globpat $globlist {
83 foreach file [glob -nocomplain $globpat] {
84 if [file isdirectory $file] {
85 for_recursive_glob $var $file/* $code [expr {$depth + 1}]
93 #@package: TclX-globrecur recursive_glob
95 proc recursive_glob {globlist} {
97 foreach pattern $globlist {
98 foreach file [glob -nocomplain $pattern] {
100 if [file isdirectory $file] {
101 set result [concat $result [recursive_glob $file/*]]
108 #@package: TclX-help help helpcd helppwd apropos
111 proc help:flattenPath {pathName} {
113 foreach element [split $pathName /] {
114 if {"$element" == "."} {
117 if {"$element" == ".."} {
118 if {[llength [join $newPath /]] == 0} {
119 error "Help: name goes above subject directory root"}
120 lvarpop newPath [expr [llength $newPath]-1]
123 lappend newPath $element
125 set newPath [join $newPath /]
128 if {("$newPath" == "") && [string match "/*" $pathName]} {
135 proc help:EvalPath {pathName} {
138 if {![string match "/*" $pathName]} {
139 if {"$pathName" == ""} {
140 return $TCLENV(help:curDir)}
141 if {"$TCLENV(help:curDir)" == "/"} {
142 set pathName "/$pathName"
144 set pathName "$TCLENV(help:curDir)/$pathName"
147 set pathName [help:flattenPath $pathName]
148 if {[string match "*/" $pathName] && ($pathName != "/")} {
149 set pathName [csubstr $pathName 0 [expr [length $pathName]-1]]}
155 proc help:Display {line} {
157 if {$TCLENV(help:lineCnt) >= 23} {
158 set TCLENV(help:lineCnt) 0
159 puts stdout ":" nonewline
162 if {![lempty $response]} {
166 incr TCLENV(help:lineCnt)
170 proc help:DisplayFile {filepath} {
172 set inFH [open $filepath r]
173 while {[gets $inFH fileBuf] >= 0} {
174 if {![help:Display $fileBuf]} {
182 proc help:ListDir {dirPath} {
185 if {[catch {set dirFiles [glob $dirPath/*]}] != 0} {
186 error "No files in subject directory: $dirPath"}
187 foreach fileName $dirFiles {
188 if [file isdirectory $fileName] {
189 lappend dirList "[file tail $fileName]/"
191 lappend fileList [file tail $fileName]
194 return [list [lsort $dirList] [lsort $fileList]]
198 proc help:DisplayColumns {nameList} {
201 foreach name $nameList {
205 if {[incr count] < 4} {
206 set padLen [expr 17-[clength $name]]
209 append outLine [replicate " " $padLen]
211 if {![help:Display $outLine]} {
218 help:Display $outLine}
224 proc help {{subject {}}} {
227 set TCLENV(help:lineCnt) 0
230 if {($subject == "help") || ($subject == "?")} {
231 help:DisplayFile "$TCLENV(help:root)/help"
235 set request [help:EvalPath $subject]
236 set requestPath "$TCLENV(help:root)$request"
238 if {![file exists $requestPath]} {
239 error "Help:\"$request\" does not exist"}
241 if [file isdirectory $requestPath] {
242 set dirList [help:ListDir $requestPath]
243 set subList [lindex $dirList 0]
244 set fileList [lindex $dirList 1]
245 if {[llength $subList] != 0} {
246 help:Display "\nSubjects available in $request:"
247 help:DisplayColumns $subList
249 if {[llength $fileList] != 0} {
250 help:Display "\nHelp files available in $request:"
251 help:DisplayColumns $fileList
254 help:DisplayFile $requestPath
261 proc helpcd {{dir /}} {
264 set request [help:EvalPath $dir]
265 set requestPath "$TCLENV(help:root)$request"
267 if {![file exists $requestPath]} {
268 error "Helpcd: \"$request\" does not exist"}
270 if {![file isdirectory $requestPath]} {
271 error "Helpcd: \"$request\" is not a directory"}
273 set TCLENV(help:curDir) $request
280 echo "Current help subject directory: $TCLENV(help:curDir)"
284 proc apropos {name} {
287 set TCLENV(help:lineCnt) 0
289 set aproposCT [scancontext create]
290 scanmatch -nocase $aproposCT $name {
291 set path [lindex $matchInfo(line) 0]
292 set desc [lrange $matchInfo(line) 1 end]
293 if {![help:Display [format "%s - %s" $path $desc]]} {
296 foreach brief [glob -nocomplain $TCLENV(help:root)/*.brf] {
297 set briefFH [open $brief]
298 scanfile $aproposCT $briefFH
301 scancontext delete $aproposCT
304 global TCLENV TCLPATH
306 set TCLENV(help:root) [searchpath $TCLPATH help]
307 set TCLENV(help:curDir) "/"
308 set TCLENV(help:outBuf) {}
310 #@package: TclX-packages packages autoprocs
312 proc packages {{option {}}} {
315 foreach key [array names TCLENV] {
316 if {[string match "PKG:*" $key]} {
317 lappend packList [string range $key 4 end]
320 if [lempty $option] {
323 if {$option != "-location"} {
324 error "Unknow option \"$option\", expected \"-location\""
327 foreach pack $packList {
328 set fileId [lindex $TCLENV(PKG:$pack) 0]
330 lappend locList [list $pack [concat $TCLENV($fileId) \
331 [lrange $TCLENV(PKG:$pack) 1 2]]]
340 foreach key [array names TCLENV] {
341 if {[string match "PROC:*" $key]} {
342 lappend procList [string range $key 5 end]
348 #@package: TclX-directory_stack pushd popd dirs
350 global TCLENV(dirPushList)
352 set TCLENV(dirPushList) ""
357 if {[llength $args] > 1} {
358 error "bad # args: pushd [dir_to_cd_to]"
360 set TCLENV(dirPushList) [linsert $TCLENV(dirPushList) 0 [pwd]]
362 if {[llength $args] != 0} {
370 if [llength $TCLENV(dirPushList)] {
371 cd [lvarpop TCLENV(dirPushList)]
374 error "directory stack empty"
380 echo [pwd] $TCLENV(dirPushList)
383 #@package: TclX-set_functions union intersect intersect3 lrmdups
385 proc union {lista listb} {
386 set full_list [lsort [concat $lista $listb]]
387 set check_element [lindex $full_list 0]
388 set outlist $check_element
389 foreach element [lrange $full_list 1 end] {
390 if {$check_element == $element} continue
391 lappend outlist $element
392 set check_element $element
397 proc lrmdups {list} {
398 set list [lsort $list]
399 set result [lvarpop list]
401 foreach element $list {
402 if {$last != $element} {
403 lappend result $element
411 proc intersect3 {list1 list2} {
416 set list1 [lrmdups $list1]
417 set list2 [lrmdups $list2]
421 if ![lempty $list2] {
422 set list2Result [concat $list2Result $list2]
427 set list1Result [concat $list1Result $list1]
430 set compareResult [string compare [lindex $list1 0] [lindex $list2 0]]
432 if {$compareResult < 0} {
433 lappend list1Result [lvarpop list1]
436 if {$compareResult > 0} {
437 lappend list2Result [lvarpop list2]
440 lappend intersectList [lvarpop list1]
443 return [list $list1Result $intersectList $list2Result]
446 proc intersect {list1 list2} {
449 set list1 [lsort $list1]
450 set list2 [lsort $list2]
453 if {[lempty $list1] || [lempty $list2]} break
455 set compareResult [string compare [lindex $list1 0] [lindex $list2 0]]
457 if {$compareResult < 0} {
462 if {$compareResult > 0} {
467 lappend intersectList [lvarpop list1]
470 return $intersectList
475 #@package: TclX-show_procedures showproc showprocs
477 proc showproc {procname} {
478 if [lempty [info procs $procname]] {demand_load $procname}
479 set arglist [info args $procname]
481 while {[llength $arglist] > 0} {
482 set varg [lvarpop arglist 0]
483 if [info default $procname $varg defarg] {
484 lappend nargs [list $varg $defarg]
489 format "proc %s \{%s\} \{%s\}\n" $procname $nargs [info body $procname]
492 proc showprocs {args} {
493 if [lempty $args] { set args [info procs] }
497 foreach j $i { append out [showproc $j] "\n"}
503 #@package: TclX-stringfile_functions read_file write_file
505 proc read_file {fileName {numBytes {}}} {
506 set fp [open $fileName]
507 if {$numBytes != ""} {
508 set result [read $fp $numBytes]
510 set result [read $fp]
516 proc write_file {fileName args} {
517 set fp [open $fileName w]
518 foreach string $args {
525 #@package: TclX-Compatibility execvp
527 proc execvp {progname args} {
528 execl $progname $args
531 #@package: TclX-convertlib convert_lib
533 proc convert_lib {tclIndex packageLib {ignore {}}} {
534 if {[file tail $tclIndex] != "tclIndex"} {
535 error "Tail file name numt be `tclIndex': $tclIndex"}
536 set srcDir [file dirname $tclIndex]
538 if {[file extension $packageLib] != ".tlib"} {
539 append packageLib ".tlib"}
542 set tclIndexFH [open $tclIndex r]
543 while {[gets $tclIndexFH line] >= 0} {
544 if {([cindex $line 0] == "#") || ([llength $line] != 2)} {
546 if {[lsearch $ignore [lindex $line 1]] >= 0} {
548 lappend entryTable([lindex $line 1]) [lindex $line 0]
552 set libFH [open $packageLib w]
553 foreach srcFile [array names entryTable] {
554 set srcFH [open $srcDir/$srcFile r]
555 puts $libFH "#@package: $srcFile $entryTable($srcFile)\n"
556 copyfile $srcFH $libFH
560 buildpackageindex $packageLib
563 #@package: TclX-profrep profrep
565 proc profrep:summarize {profDataVar stackDepth sumProfDataVar} {
566 upvar $profDataVar profData $sumProfDataVar sumProfData
568 if {(![info exists profData]) || ([catch {array size profData}] != 0)} {
569 error "`profDataVar' must be the name of an array returned by the `profile off' command"
572 foreach procStack [array names profData] {
573 if {[llength $procStack] < $stackDepth} {
574 set sigProcStack $procStack
576 set sigProcStack [lrange $procStack 0 [expr {$stackDepth - 1}]]
578 set maxNameLen [max $maxNameLen [clength $sigProcStack]]
579 if [info exists sumProfData($sigProcStack)] {
580 set cur $sumProfData($sigProcStack)
581 set add $profData($procStack)
582 set new [expr [lindex $cur 0]+[lindex $add 0]]
583 lappend new [expr [lindex $cur 1]+[lindex $add 1]]
584 lappend new [expr [lindex $cur 2]+[lindex $add 2]]
585 set $sumProfData($sigProcStack) $new
587 set sumProfData($sigProcStack) $profData($procStack)
593 proc profrep:sort {sumProfDataVar sortKey} {
594 upvar $sumProfDataVar sumProfData
597 {calls} {set keyIndex 0}
598 {real} {set keyIndex 1}
599 {cpu} {set keyIndex 2}
601 error "Expected a sort of: `calls', `cpu' or ` real'"}
605 foreach procStack [array names sumProfData] {
606 set key [format "%016d" [lindex $sumProfData($procStack) $keyIndex]]
607 lappend keyProcList [list $key $procStack]
609 set keyProcList [lsort $keyProcList]
612 for {set idx [expr [llength $keyProcList]-1]} {$idx >= 0} {incr idx -1} {
613 lappend sortedProcList [lindex [lindex $keyProcList $idx] 1]
615 return $sortedProcList
619 proc profrep:print {sumProfDataVar sortedProcList maxNameLen outFile
621 upvar $sumProfDataVar sumProfData
623 if {$outFile == ""} {
626 set outFH [open $outFile w]
630 set stackTitle "Procedure Call Stack"
631 set maxNameLen [max $maxNameLen [clength $stackTitle]]
632 set hdr [format "%-${maxNameLen}s %10s %10s %10s" $stackTitle \
633 "Calls" "Real Time" "CPU Time"]
634 if {$userTitle != ""} {
635 puts $outFH [replicate - [clength $hdr]]
636 puts $outFH $userTitle
638 puts $outFH [replicate - [clength $hdr]]
640 puts $outFH [replicate - [clength $hdr]]
643 foreach procStack $sortedProcList {
644 set data $sumProfData($procStack)
645 puts $outFH [format "%-${maxNameLen}s %10d %10d %10d" $procStack \
646 [lindex $data 0] [lindex $data 1] [lindex $data 2]]
648 if {$outFile != ""} {
654 proc profrep {profDataVar sortKey stackDepth {outFile {}} {userTitle {}}} {
655 upvar $profDataVar profData
657 set maxNameLen [profrep:summarize profData $stackDepth sumProfData]
658 set sortedProcList [profrep:sort sumProfData $sortKey]
659 profrep:print sumProfData $sortedProcList $maxNameLen $outFile $userTitle