"command options" suggests several distinct topics:
Certain considerations are common to all these, and are convenient to treat here in a unified way.
Question: In C, for Tcl, using the newer objc, objv API, how do I parse options? I would have thought people would need to do this all the time, but I can't find anything. Needs to handle args, options, required optional etc. Speed is high on the priority list...
If you can use the Tk library, try Tk_SetOptions and its assorted support functions. It would be nice if something like this were in the Tcl library, for those times when one doesn't have Tk around. A pure-Tcl solution might be to do the option handling in Tcl, passing a fixed number of arguments to the C code, but that might not meet your speed requirements.
SPB I've modified the Tk_ParseArgv() routine in tkArg.hc to handle this case. Also, to make it even more useful, I added a Tcl_ParseArgsObjv for parsing a bunch of arguments passed to a C-implemented Tcl command. For example, you can do something like:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <tcl.h> #include <tclArgv.h> int mycoolcommand(ClientData clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]) { int mytoggle=0; int myint=-2; Tcl_ArgvInfo argTable[] = { {"-toggle",TCL_ARGV_CONSTANT,(void*)1,&mytoggle,"turn toggle on"}, {"-theint",TCL_ARGV_INT,NULL,&myint,"set myint"}, {(char*)NULL,TCL_ARGV_END,NULL,NULL,(char*)NULL} }; Tcl_Obj **private_objv=(Tcl_Obj**)calloc(objc+1,sizeof(Tcl_Obj*)); int i; for (i=0;i<objc;i++) private_objv[i]=objv[i]; if (Tcl_ParseArgsObjv(interp,&objc,private_objv,argTable,0)!=TCL_OK) return TCL_ERROR; /* after this call, private_objv only holds unprocessed arguments, and objc reflects this. */ ... do stuff... return TCL_OK; }
If you feel this may be of use, you can grab the tar file from http://www.sambromley.com/tclArgv/
Sam.
}
[Many people write their own "... -arg1 val1 -arg2 val2 ..." processing, because it's so easy to use Tcl associative arrays (see "Arrays / Hash Maps") simply as the "optional arguments" section in Tcl Gems does ...]
Here is the start of some code to show at least one method of doing command line parsing. Hopefully people will contribute other samples as appropriate.
# If this script was executed, and not just "source"'d, handle argv if { [string compare [info script] $argv0] == 0} { while {[llength $argv] > 0 } { set flag [lindex $argv 0] switch -- $flag { "-bool" { set bool 1 set argv [lrange $argv 1 end] } "-option" { set value [lindex $argv 1] set argv [lrange $argv 2 end] } default { break } } } } foreach file $argv { puts "[format "file: %s" $file]" }
PT writes: I like to use code similar to the above example for option processing. However, we want to avoid 'shimmering' the args list into a string and back into a list. Plus I find it repatative to keep writing the same two lines for setting the option value. Here is my current example:
# ------------------------------------------------------------------------- # Description: # Pop the nth element off a list. Used in options processing. # proc dns::Pop {varname {nth 0}} { upvar $varname args set r [lindex $args $nth] set args [lreplace $args $nth $nth] return $r } # --------------------------------------------------------------------- # Now the option processing loop. Eats the arguments once handled and stops at '--' # setup the defaults. array set opts {-a 1 -b 0} while {[string match -* [lindex $args 0]]} { switch -glob -- [lindex $args 0] { -A* -a* { set opts(-a) [Pop args 1] } -b* { set opts(-b) [Pop args 1] } -- { Pop args ; break } default { set opts [join [lsort [array names state -*]] ", "] return -code error "bad option [lindex $args 0]: \ must be one of $opts" } } Pop args } puts "Options now [array get opts] and the remaining args: $args"
I use procargs to do this job JBR
A quick and dirty way uses one-liners like this:
if [regexp " -x" $::argv] {# do the X thing} ;# RS
If your values come in pairs (like -option value), I usually use the following code for parsing them:
foreach {option value} $argument_list { switch -glob -- $option { -opt* {set opt $value} -otheropt* {set otheropt $value} default {error "Unknown option $option!"} } }
A classical and elegant solution to this task is from the Welch book:
proc foo {args} { # first assign default values... array set options {-bar 1 -grill 2 -verbose 0 ...} # ...then possibly override them with user choices array set options $args .... }
It does not check for undefined switches, though. (RS)
SB, 2003-05-21: For many of my tcl utilities I have only vanilla tclsh but still need to parse command line options. As I mostly use the tools myself I don't need too much fancy error detection. For a small application, I need a couple of switches, one with an argument and then the file to process. Nothing fancy, but it is written in a matter of seconds, and it is fairly easy to extend with more switches.
set arglen [llength $argv] set index 0 while {$index < $arglen} { set arg [lindex $argv $index] switch -exact -- $arg { {-s} {set args($arg) [lindex $argv [incr index]]} {-l} {set args($arg) .} default {set filename [lindex $argv $index]} } incr index } if {[info exists args(-l)]} { puts "-l switch set" ... code what happens for -l } if {[info exists args(-s)]} { puts "-s switch set with arg $args(-s)" ... code what happens for -s and its arg }
A related topic: "Syntax parsing in Tcl".
Tcl syntax help - Arts and crafts of Tcl-Tk programming