WJG (25nd May, 2005) I expect that something like this code snippet is already somewhere on the Wiki but I thought it worth a posting as this method allows for cleaner, simpler code.
Larry Smith This is precisely what init does, but init also provides a way to initialize switches, and will disallow setting things that the proc isn't able to understand (this is both a security thing as well as error detection). init can also parse your argv as well, if called in the global scope.
If a proceedure has a whole range of switches then why waste time parsing the args list with a load of switch options or if.. else.. constructions? Just assume that the switch names themselves have some meaningful description within the scope of the calling proc, strip out the leading "-" and use the remnamt of the string as a variable name.
As the proc documentation should always contain some explanation of the usage of the proceedure, its arguments and switches should be no cause for confusion.
# ------------------------------------------------------- # proc: # easyargs -just a piece of demo code # # args: # a # b # # switches: # -up # -down # -in # -out # # ------------------------------------------------------- proc easyargs {a b args} { # read in args, set values according to switch names foreach {opt val} $args { set tmp [string trim $opt -] set $tmp $val } #just to prove that the values are set... foreach item {up down in out} { puts "$item [set $item]" } } easyargs red green -up 0 -down 1 -in 0 -out 1
WJG (16/12/11) I thought that I'd revisit this task but allow for the setting of defaults and some error checking. The above is fine, but I don't want to have such a bulky solution. Much better to have a single proc to call to handle the necessaries.
#--------------- # parse options string and set values within scope of calling procedure #--------------- # Arguments # options array containing procedure option names and default values # args list of options and values passed to calling procedure # Returns # 0 if successful or -1 if there is an error. # # Notes # The function creates variables within the scope of the calling function # by stripping away the leading "-" and using a variable name derived from # shifting the option string to lowercase. # # If an undefined option is specified, the error will be reported to stderr # and the script will terminate. # # Following the creation of the variables, the options array will be unset. # proc parseOptions {options args} { upvar $options opts set names [array names opts] # set default values for the options foreach item $names { set aa [string tolower [string trimleft $item -]] uplevel 1 set $aa $opts($item) } # change option values to those specified in args foreach {a b} [lindex $args 0] { if { [string first $a $names] >= 0 } { set aa [string tolower [string trimleft $a -]] uplevel 1 set $aa [list $b] } else { set err "ERROR! Invalid option $a, should be one of [array names opts]." exit -1 } } # clear the options array uplevel 1 unset opts } proc testProc1 {val args} { # set options and default values array set opts {-opt1 A -opt2 B -opt3 C -opt4 ZZZZZ} puts [parray opts] parseOptions opts $args foreach i [info vars] { puts "$i = [set $i]" } if { [catch {puts [parray opts] }] } { puts "Array opts no longer exists" } } proc testProc2 {val args} { # set options and default values array set opts {-Day A -Day B -Month C -Year D } parseOptions opts $args foreach i [info vars] { puts "$i = [set $i]" } puts "Happy Yuletide: $day $month $year" } testProc1 25-DEC -opt1 "HAPPY NEW YEAR" -opt2 "Merry Christmas" -opt3 "MERRY YULETIDE" testProc2 25-DEC -Day 25th -Month December -Year 2011
See also Named arguments