The cmdargs Tcl extension

Introduction

Cmdargs is a Tcl extension that provides a command-line interface to any user-created proc.

Tcl make heavy use of command-line options. Most Tcl commands use this style of input. For example,

set res [glob -nocomplain -directory ../dir -types {f l} *]

Tcl users are familiar with command-line option conventions. This style of input is useful when a proc has several optional inputs or multiple parameters. Unfortunately, "out of the box", user-created commands have limited support for optional parameters and none for arbitrary-order,named parameters.

Say we've written a proc:

proc setdata {name {addr {}} {city {}} {age {}} {email {}}} {
    # do something with inputs...
}

Instead of entering

setdata Sam "" "" "" sam@email.net

it would be better if this were possible:

setdata -name Sam -email sam@email.net

This extension cmdargs makes this kind of command-line easy to accomplish. For practical numbers of command-line options cmdargs is also reasonably performant. It does have some overhead, so it's not recommended for procedures being used in tight loops. However, for many or most purposes it's slight performance cost won't be noticeable.

Installation

Binary installation cmdargs is straightforward. Download the archive in zip or tgz format. Use zip or tar to decompress into any convenient location.

The archive structure is as follows:

CmdArgs-ext bin config config.exe pkgNdx pkgNdx.exe doc generic tcl8 unix cmdargs1.0 cmdargs10.so pkgIndex.tcl config.def win-msys (as in unix) tcl9 unix (as above) win-msys (as above) tools win

The extension is a shared library found in the cmdargs1.0 directory in each of the 4 directories: Tcl8/unix, Tcl8/win-msys, Tcl9/unix and Tcl9/win-msys. It's only necessary to copy the suitable cmdargs1.0 directory to the package directory used by your installed Tcl. (Usually that's /usr/lib, /usr/local/lib, or TclNNN/lib directory.)

Then put package require cmdargs at the top of the Tcl file.

The use of the other directories is described below, see "Compiling".

Usage

Syntax

cmdargs::chkArgs* <input (list)> <defaults (list[s])>

<input> : {-optionA ?valueA? ...}  # <value> isn't required for boolean options
<defaults> : <type> <defaults> <type2> <defaults2> ...
<type> : ?-?(dbool|dnum|dstr|denum) 
<defaults-list> : {optionA defaultA ...}

Syntax details

The "cmdargs::" namespace provides 4 commands, chkArgs, chkArgsCi, chkArgsv, and chkArgsvCi. chkArgsCi is the case-insentive variant of chkArgs. The 'v' variants provide a variable, _CA_allvar in the caller. This variable has a list of all varnames created by chkArgs*. The syntax:

cmdargs::chkArgs?vCi? <cmdline (list)> ?-dbool {...}? ?-dnum {...}? ?-dstr {...}? ?-denum {...}?

cmdline is the input to the proc, typically using args. proc input is in -option value format, except for boolean options which don't require input values.

proc test {args} {
    cmdargs::chkArgs $args -dbool ....
    ...
}

Remainder of chkArgs invocation consists of paired parameters, one of <?-?dbool dnum dstr denum> followed by a list of <option value> pairs. For example, CmdArgs::chkArgs $args dbool {flagc 0 flagd 1} dnum {nlines 80 npages 23} ...

The d... identifiers denote the type of the values in the associated list.

ID Value type List example
dbool boolean (0|1) flagd 0 flagm 1
dnum numeric (int|float) elem 9.0 year 2011
dstr string (Tcl string) name "First Last" addr ""
denum enumerated list food {fresh frozen canned}

IOW using cmdargs provides a basic level of type-checking and validation of proc inputs. This not only reduces errors, it also can save programmers some work validating proc input values.

Note that in the lists the option names (even-numbered elements) will be names of variables created by cmdargs. Values (odd-numbered elements) are the defaults assigned to the named variables. Command-line options/values override these defaults.

Cmdline input

<cmdname> -option value -option1 value1 -booloption -option2 ...

Each -option sets a variable option with value. Some conditions apply:

Typed lists

?-?dbool {flagx 0 flagy 1} ## sets flagx 0, flagy 1
cmdline: -flagx -option ... ## flagx is now 1

?-?dnum {qty 12 area 234.5 ...} 
cmdline: -qty 23 
         -qty abc -> error (non-numeric value)
         -qtty 23 -> error (no such option)

?-?dstr {item1 "green" ...} ## item1 green
cmdline: -item1 reddish    ## item1 reddish
         -item1 -opt ...   ## error (missing value)

?-?denum {food {veggie fruit legume}} ## food veggie
first elem in list (veggie) is default value of var food
value list elems can be of any type
cmdline: -food legume -> sets food to "legume"
         -food lamb -> error ("lamb" not member of enum)

Note that the leading dash is optional for type designators.

At runtime, enter "-opts?" or "-options?" to prompt cmdargs to print a list of variables and default values:

source cmdargs-test.tcl cmdln -opts? ----dstr---- kitchen: modern stuff floors: linoleum walls: off-white auto: Honda ----dnum---- frac: 0.5 area: 2000 rooms: 12 doors: 4 ---denum---- critter: cat dog racoon deer ants birds food: vegetable fruit meat legume grain ---dbool---- flagd: 0 flagc: 1

Benchmarks

Some benchmark results are supplied in the file "benchmarks.txt". Notable is that the binary extension is ~ 5-6 times as fast vs. the pure Tcl implementation. (CmdArgs.tcl was originally used in jWebTools.) Also, the chkArgs variant is fastest, chkArgsvCi slowest. The difference is ~25%. See benchmark.txt for more detailed info.

Compiling

While the supplied precompiled shared libraries should work on unix and Windows systems, there's always a chance of problems.

The archive contains the full source code and a build system. The supplied Makefiles will probably need to be regenerated to suit individual operating systems and environments.

The included build system is simple but can be elaborated to adapt to situations as necessary. The bin directory contains two executables, config and pkgNdx (or config.exe, pkgNdx.exe). These two files can be copied to a directory on the PATH. These may also be run from the bin directory as well. On unix-like systems check that bin/config,pkgNdx have exec bits "on". If not use chmod a+x config pkgNdx to fix it.

The primary configuration file is config.def found in each Tcl8/9/unix/win directory. (The tools directory also has config.def in its unix and win subdirectories. The provided bin/ files will probably not need to be regenerated.)

In config.def change the "tcldir" default path near the top of the file. Change the installto list to reflect your system's Tcl package directories.

set Defaults {
    tcldir /usr/local/opt/tcl87b1s <- (replace with location on YOUR system...)
    installto {directories to cp <cmdargs1.0> to}
    <other settings...>
}

Now run

../../bin/config

the Makefile will be regenerated. Then run make install and it should be good to go.

Regenerating config and pkgNdx

Info available soon...