Version 65 of command options

Updated 2016-02-15 03:58:01 by pooryorick

command options are ever-present in Tcl scripts. This page presents various approaches to processing them.

See Also

category Argument Processing
Syntax parsing in Tcl
Tcl syntax
Argument Parsing, a discussion

Description

suggests several distinct topics:

  • tclsh and wish arguments
  • command-line options (as seen through $::argv) of Tcl-coded applications
  • idioms for parsing variable (args) arguments seen by pure-Tcl procs.

Certain considerations are common to all these, and are convenient to treat here in a unified way.

Option Parsing for Tcl Commands

ad_proc
argument processing for Tcl (Lehenbauer)
Tk-like argument processing for Tcl procs.
argument parsing with defaults (Wagner)
Only available by contacting the author directly. see theObjects for a C version, which is available for download
argument processing (Zimmer)
aqtools
includes an ... [?] package for argument parsing
argp
simple and flexible arg parsing for Tcl
clig
written in Tcl, generates interpreters for both standalone programs and Tcl commands
cmdline in tcllib
probably the most standard and widely-used of these packages
cmdr , by AK
a framework for command-line parsing and dispatch. Presented at the Twentieth Annual Tcl/Tk Conference (2013)
Evaluate Parameters 2.4
for C, Perl, and Tcl
Extral's args_parse, cmd_parse, and so on
getopt, by RS
light-weight, of course
GetOpt-ish by FF
getopt-like tool
groom: a simple getopt: calling Tcl procs with options , Doug Simpson, 2001-09-04
init, by Larry Smith
parses a command's arguments and also initialises local variables.
Matthias Hoffmann - Tcl-Code-Snippets - misc routines - command line parsing
another simple command line parsing routine in a few lines of tcl, with integrated help support
mkextensions, by Michael Kraus
includes mkGeneric::options, a simple but efficient option-processing routine.
Named arguments, by RS
Octopus package for parsing command line options for procedures/scripts
opt
deprecated
optparse, by Laurent Demailly
deprecated
optional arguments, in Tcl Gems
illustrates the use of arrays to do simple argument parsing
Options and Arguments, by aspect
option parsing using ensemble, by Lars H
uses the namespace ensemble mechanism to to handle options
ParseArgs, circa 1996
Utility library for parsing command line arguments in various languages (including Tcl) and on various hardware platforms
procargs, by JBR
Procedure for Extracting Options and Switches , by J Adrian Zimmer, 1988
Simple way to parse command options, by Fabricio Rocha
provides optionscheck, which verifies the formatting of a traditional options list like -option1 value1 -option2 value2 .... Intended for being used in megawidgets and customized commands, the procedure finds unknown options, values without preceding options, options without a value assigned to them. It returns a dict containing all those cases above along with the valid option/value pairs, and can generate errors in such cases or work silently.
SNTL, by Sam Shen
contains code for command line argument processing as well as many other items.
TclGetOpts
mildly buggy
Tcl_ParseArgsObjv
parsing of C implemented Tcl commands using the object interface. (See example below.)
tepam, or Tcl's Enhanced Procedure Argument Manager
a component of tcllib
Option Parsing for Tcl Commands - tgetopt
TWAPI
provides parseargs for flexible argument parsing. This is implemented in C and is therefore fast enough to be used for argument parsing in any proc. Some of the Tcl based parsers are slow enough that they impose a significant performance penalty if used for general proc arg processing as opposed to just dealing with command line options where performance of course does not matter.
The Simple Development Library
includes both SimpleProc , a package for command arguments handling including typed arguments, with optional run-time checking, and options SimpleOption , a very powerful command options parser with too many features to list here
yaap - Yet Another Argument Parsing utility
a template-based argument parsing utility inspired by XtGetApplicationResources()
ycl::checkargs
Like tepam, but weaves documentation and code together in a Literate Programming style, providing a versatile argument specification system as well as argument validation and inter-argument validation. Both positional and key-value arguments can be fully specified and processed. Additional features include a docstring-like characteristic, default argument values, configurable collector variable for unrecognized values, inline argument transformers, specifcation of mandatory vs optional arguments, configurable end-of-arguments indicator, ability to specify whether multiple occurrences of an argument are collected into a list or simply replace earlier values, as well as minimum and maximimum limits on the number of occurrences of each argument. It's also possible to reuse all or part of the argument specifications of other procs, mixing and matching as required. It's urrently somewhat slow, but its performance should improve over time.

System Command Line

Evaluate Parameters 2.4
for C, Perl, and Tcl

A "Standard" Template

The following example can be used as a template for processing arguments in the way that is fairly standard for built-in commands:

# If this script was executed, and not just "source"'d, handle argv
if {[info exists argv0] && [
    file dirname [file normalize [info script]/...]] eq [
    file dirname [file normalize $argv0/...]]} {

    while {[llength $argv]} { 
        puts [list ooo $argv]
        set argv [lassign $argv[set argv {}] flag]

        switch -glob $flag {
            -bool {
                set bool 1
            }
            -option {
                set argv [lassign $argv[set argv {}] value]
            }
            -- break
            -* {
                return -code error [list {unknown option} $flag]
            }
            default {
                set argv [list $flag {*}$argv]
                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 repetitive 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"

PYK 2016-02-04: As far as I can tell, neither the original code, nor the modified version I'm providing with this edit, cause $argv to shimmer, so I plan to delete the portion of the statement above, by PT, to that effect.


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
}

The Key/Value Approach

See named parameters

Discussion

 

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.


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!"}
    }
}

troym72 2009-12-22: Passing arguments from the UNIX command line in the form of a keyed list, can be a little tricky. Here's an example procedure that I created to help illustrate how Tcl handles arguments from the command line in keyed list form.

#!/usr/bin/tcl

#  Script Name: argstest.tcl
# Date Created: 12/22/2009
#       Author: Troy Morton
#      Purpose: Test command line arguments

package require tclx

proc parseargs args {
    echo $args                   ;# args as passed from the “parseargs $argv procedure call”
    set args [lindex $args 0]    ;# pull my args keyed list from the argv single element list
    keylget args KEY1 value      ;# now do my keylget from the args which is now a properly formatted keyed list.
    echo $value                  ;# echo value of the key “KEY1”.
}

echo $argv                   ;# args from command line arrive as keyed list
parseargs $argv              ;# argv is passed to pareargs as a list

When run from the UNIX command line the above script looks like this:

/>argstest.tcl "KEY ValueKey1" "KEY2 ValueKey2"     ;# typed on command line
{KEY1 ValueKey1} {KEY2 ValueKey2}                   ;# argv as received by the tcl script
{{KEY1 ValueKey1} {KEY2 ValueKey2}}                 ;# argv as received by proc parseargs
ValueKey1                                           ;# value of the key KEY1

PYK 2015-10-20: That approach bundles a key and a value into a single argument, which can lead to quoting issues between the system shell and the Tcl interpreter. Better to treat $argv as a sequence of key-value pairs:

proc main {$argv0 $argv} {
    dict update $argv KEY KEY KEY2 KEY2 {}
    ...
}
main $argv0 $argv