# Init.tcl - (c) Martin S. Weber, 2003-2004 # License: BSD / Tcl. Have fun. # test: # --<<snip>>-- # package require -exact Init 0.1 # namespace import Init::* # # onInit -type procedure -proc { puts stderr "Init 1" } # onInit -type procedure -proc { puts stderr "Init 2" } # onInit -type cleanup -cleanup { puts stderr "Cleanup 1" } # onInit -type cleanup -cleanup { puts stderr "cleanup 2" } # onInit -type procedure -proc { puts stderr "Init 3" } # # onInit -type file -filePrefix "bla_" -fileSuffix ".tcl" \ # -fileDirs {/home/phaeton/programming/test-src} \ # -fileList {_cvs_ _help_ _init_ _proc_decl_} # # doInit # # array set pref {} # # traverse pref # # parray pref # # puts "Hit key to continue" # gets stdin # # onInit -type file -filePrefix "bla_" -fileSuffix ".tcl" \ # -fileDirs {/home/phaeton/programming/test-src} \ # -fileList {_cvs_ _hep_ _ini_ _pro_decl_} # # reInit # array set pref2 {} # traverse pref2 # puts "hit key to view pref" # gets stdin # parray pref # puts "hit key to view pref2" # gets stdin # parray pref2 # --<<snap>>-- # # Whether init automatically initializes or not, should # be version number dependant. You require 0.1, no auto # init, you require 0.2 (which will be default since it # has a higher version number) and autoinit takes place. # # I.e. the following code's in my pkgindex..: # package ifneeded Init 0.2 \ # " set ::dofastinit 1; source \[file join $dir Init Init.tcl\]" # package ifneeded Init 0.1 \ # " set ::dofastinit 0; source \[file join $dir Init Init.tcl\]" # ## -- SOC -- Start of Code (searchmark:) ## -- namespace mumbodjumbo namespace eval Init { namespace export traverse reInit doInit doFinalize onInit reset ## let's start it variable iState variable doneInit 0 variable iFFound array set iFFound {} array set iState {} ## traverse (array) ## traverses init state to array named in array proc traverse { arrN } { variable iState upvar $arrN target foreach name [array names iState] { set target($name) $iState($name) } } ## --- Interface to set Init actions -- ## onInit ( args ) ## # onInit -type file -filePrefix prefix -fileSuffix suffix \ # -fileDirs dirlist -fileList filestosearch # -> search for filestosearch under the directories dirlist # with prefix prepended if [string index $fname 0] == _ and # with suffix appended if [string index $fname end] == _. # # onInit -type proc -proc block # -> execute the block when starting # # onInit -type cleanup -cleanup block # -> execute the block when restarting # # (-type really should be implicit :) proc onInit { args } { variable doneInit variable ::initInfo set fileSuffix [list] set filePrefix [list] set fileList [list] set dirList [list] set block [list] set type "" if {$doneInit} { puts stderr "Warning: onInit: initialized already, do reInit to see the effect!" } set numargs [llength $args] if {!$numargs} { puts stderr "onInit called without arguments!" return } ## if called with -copy, just return the current initInfo ## if called with -pop, pop off the last element of the list. if {($numargs == 1) } { if {[lindex $args 0] == "-copy"} { puts stderr "traversing initInfo." return $initInfo } elseif { [lindex $args 0] == "-pop"} { set tmp [lindex $initInfo end] set initInfo [lreplace $initInfo end end] puts stderr "Popping of initInfo: <$tmp>" return $tmp } } for {set i 0} {$i < $numargs} {incr i} { set j [expr $i +1] set step 0 switch -glob -- [set cur_arg [lindex $args $i]] { "-*" { switch -glob -- [set cur_arg [string range $cur_arg 1 end]] { "type" { set data [string tolower [lindex $args $j]] if {!(($data == "cleanup")||($data=="procedure")||($data=="file"))} { puts stderr "onInit: -$cur_arg <$data>: Cannot recognize \"$data\"!" } set type $data incr step } "file*" { switch -- $cur_arg { "fileSuffix" { set fileSuffix [lindex $args $j]; incr step } "filePrefix" { set filePrefix [lindex $args $j]; incr step } "fileList" { set fileList [lindex $args $j]; incr step } "fileDirs" { set dirList [lindex $args $j]; incr step } default { puts stderr "onInit: Do not recognize file sub opt \"-$cur_arg\"" } } } "proc" { set block [lindex $args $j] ; incr step } "cleanup" { set block [lindex $args $j] ; incr step } default { puts stderr "Unknown option -$cur_arg!" } } } default { puts stderr "Unknown argument $cur_arg" } } incr i $step } if {$type == ""} { puts stderr "onInit: lacking type specification!" return } if {$type == "file"} { lappend initInfo [list $type [list $filePrefix $fileList $fileSuffix $dirList]] } else { lappend initInfo [list $type $block] } } ## reInit just does reinitialization proc reInit { } { variable doneInit variable iState variable iFFound doFinalize set doneInit 0 array set iState {} array set iFFound {} doInit } ## reset clears the current state. proc reset { } { variable ::initInfo variable doneInit variable iState variable iFFound set doneInit 0 array set iState {} array set iFFound {} unset initInfo } ## doFinalize reads the global variable initInfo ## which can be set by the caller, and searches ## for entries named Cleanup, and evaluates them. ## This is a special form of the Procedure spec, ## which causes the correlated calls to be performed ## at reinitialization time, where you may want to ## perform cleanups and such. proc doFinalize { } { variable ::initInfo if {![info exists initInfo]} { puts stderr "doFinalize([info level [info level]]): No initInfo found!" return } foreach entry $initInfo { if {[lindex $entry 0] == "cleanup"} { if [catch {uplevel #0 [lindex $entry 1]} errInf] { puts stderr "doFinalize([info level [info level]]): Error in code block!" puts stderr "codeblock was: <<[lindex $entry 1]>>" puts stderr "thrown error: $errInf" } } } return } ## doInit reads the global variable initInfo ## which can be set by the caller. Currently ## initInfo consists of a simple list: ## < <Init-type> <Init-type-info> >, ## there can be multiple init-type, init-type-info ## tuples, all will be attempted to handled. ## current handling works for: ## Init-type Init-type-info ## ---------------------------------------------------------- ## file < <prefix> <name(s)> <suffix> <dir(s)> > ## >> Sets in the local state array entries with the filenames ## >> of the files, like banzai/bla.x comes as bla.x into the ## >> array. files following [_]pattern[_] ([] meaning optional) ## >> will be renamed, where the leading underscore gets replaced ## >> with prefix, and the trailing one with suffix. ## procedure < <procedure <arg> [<arg> ..]> > ## >> Calls the listed procedure ## cleanup < valid tcl cmd > ## >> Evaluates each block on global level to perform cleanups ## >> in the underlying program. ## proc doInit { } { variable ::initInfo variable ::env variable doneInit variable iState variable iFFound if {$doneInit} { puts stderr "Warning, reInit ?!" } if {![info exists initInfo]} { puts stderr " Cannot find initInfo !!! " } else { foreach entry $initInfo { switch -- [lindex $entry 0] { "cleanup" { continue } "procedure" { if [catch {uplevel #0 [lindex $entry 1]} errInf] { puts stderr "doInit([info level [info level]]): Error in code block!" puts stderr "codeblock was: <<[lindex $entry 1]>>" puts stderr "thrown error: $errInf" } } "file" { #puts stderr " -- search for files -- " set l [lindex $entry 1] set prefix [lindex $l 0] set suffix [lindex $l 2] set names [lindex $l 1] set dirs [lindex $l 3] #puts stderr " Prefix: $prefix, Suffix: $suffix." #puts stderr " Files: $names " #puts stderr " Dirs: $dirs" foreach fil $names { if {[string index $fil 0] == "_"} { set fil [string replace $fil 0 0 $prefix] } if {[string index $fil end] == "_"} { set fil [string replace $fil end end $suffix] } set iFFound([lindex [file split $fil] end]) 0 foreach dir $dirs { set fpath [file join $dir $fil] if {[file exists $fpath] && [file readable $fpath]} { set fil [lindex [file split $fil] end] set iState($fil) $fpath set iFFound($fil) 1 break } } } if {[lsearch [array get iFFound] 0] != -1} { if {[info exists env(INIT_DEBUG)] && $env(INIT_DEBUG) == 1} { puts stderr " WARNING! Could not find all files. Continue ? \[yn\] " puts stderr " --------------- File status -----------------------" foreach name [array names iFFound] { puts stderr [format "%-40s:........%d" $name $iFFound($name)] } puts -nonewline stderr " Choice ? \[yn\] :" set ans [gets stdin] if {$ans == "y"} { puts stderr " You're driving at own risk, continuing... " } else { puts stderr " Exitting (user choice) " exit 1 } } else { puts stderr " Bang ! Some files not found (set INIT_DEBUG to 1 in your environment " puts stderr " for more information on what files were not found.) Exitting now. " exit 1 } } } default { puts stderr "Unknown entry $entry!!" } } } set doneInit 1 } } ## <<--- closing the namespace mumbodjumbo } ## --->> ## Do the actual init. if {$::dofastinit} { Init::doInit package provide Init 0.2 } else { package provide Init 0.1 }
Category Package