Easyargs -Let proceedure switches set themselves

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