I've spent some time this evening hacking on a set of tools to ease my pain when I need a command with subcommands that parses its arguments in a manner that is compatible with [proc]. I've got something that sort of works here, good enough for the serial command that I was implementing anyway: ------------------------------------------------------------------------ # subcommands.tcl # Copyright April 13, 2005 - Pierre Coueffin proc subcommand {cmd arglname commands} { set code [list switch -exact -- $cmd] set switches {} foreach {c a b} $commands { set b "nameArgs [list $a] \$[set arglname]\n$b" lappend switches $c $b } lappend code $switches uplevel 1 $code } proc nameArgs {prototype argl} { set mandatory {} set optional {} set args [lindex $prototype end] if {! [string match $args args]} { set args {} upvar args v set v {} } else { set prototype [lrange $prototype 0 end-1] } foreach proto $prototype { switch [llength $proto] { 0 { error "You can't have an argument with no name." } 1 { if {[llength $optional] > 0} { error "You can't have a mandatory argument after an optional one." } lappend mandatory $proto } 2 { foreach part $proto { lappend optional $part } } default { error "too many fields in argument specifier \"$proto\"" } } } if {[llength $argl] < [llength $mandatory]} { set errmsg "wrong # args: should be \"$mandatory" foreach {opt default} $optional { append errmsg " ?$opt?" } append errmsg " $args\"" error $errmsg } foreach name $mandatory arg [lrange $argl 0 [llength $mandatory]] { upvar $name v set v $arg } set argl [lrange $argl [llength $mandatory] end] if {[llength $argl] > [expr [llength $optional] / 2]} { if {$args == {}} { set errmsg "wrong # args: should be \"$mandatory" foreach {opt default} $optional { append errmsg " ?$opt?" } append errmsg "\"" error $errmsg } upvar args v set len [expr [llength $optional] / 2] set v [lrange $argl $len end] set argl [lrange $argl 0 $len] } set i 0 foreach {opt default} $optional arg $argl { upvar $opt v if {[llength $argl] <= $i} { set v $default } else { set v $arg } incr i } return } ------------------------------------------------------------- [LV] What would be an example of this in action? ------------------------------------------------------------ [Pierre Coueffin] subcommand is used in [The serial iterator] (It's the only example, since I just wrote it...) namedArgs is useful for breaking up argument lists. I intend to replace a bunch of places where I do: foreach {a b c} $args break with: namedArgs {a b {c defaultValueForC} {d defaultValueForD} args} $args the idea was to be more compatible with the way [proc] handles arguments. That's why it has so many attempts at sanity checks and verbose error messages... It's not perfect yet, but I want to get some feedback in case anyone else spots the glaring design flaws that I'm sure are lurking in it. ---- * See [Matthias Hoffmann - Tcl-Code-Snippets - misc routines - command line parsing] ---- [Category Dev. Tools] [Category Command] [Category Argument Processing]