Introduction to argtable 1.1.
Stewart Heitmann
January 1999
Legal notice
The
argtable library and accompanying documentation is copyright © 1998,
1999 Stewart Heitmann (Stewart.Heitmann@tip.csiro.au)
Argtable is free software;
you can redistribute it and/or modify it under the terms of the GNU Library
General Public License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This
software is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE.
See the GNU Library
General Public License for more details.
You
should have received a copy of the GNU Library General Public License along
with this library; if not, write to the Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
Overview
Argtable is a freely available programmer's library for parsing the command
line arguments of any C/C++ program.
The programmer specifies the desired
format of the command line arguments in one or more statically defined
arrays known as argument tables. Each row of an argument table specifies
the data type of an expected argument, its default value (if any), and
nominates a user-defined program variable as storage for the incoming argument
value. Processing the command line is done by calling an argtable library
function which attempts to resolve the program's command line arguments
with the entries of a given argument table. If successful, the command
line arguments are thus known to be valid and their values are ready and
available for use in their nominated program variables. Otherwise, erroneous
argument usages are automatically trapped and reported back to the main
program for appropriate action.
Argtable also provides auxiliary functions that allow the programmer
to generate plain text descriptions of the individual arguments and their
overall usage syntax directly from an argument table. These greatly assist
the implementation of on-line help facilities, and ensure that help messages
are always up to date with the code.
Perhaps best of all, the argtable library has only seven functions
and thus is very easy to learn.
Styles of command line arguments.
Argtable supports
two styles of command line arguments, tagged and untagged.
Tagged arguments are identified by a prefix tag, as in -o file or
title:mystuff, and may appear anywhere on the command line. The
format of the tags is completely general; they appear exactly as defined
in the argument table, without being restricted to any particular formatting
style or identifying character traits. The programmer may implement any
style of argument tag desired, including such common styles as -title
mystuff, title:mystuff, --title mystuff, or title=mystuff.
Untagged arguments on the other hand have no prefix; they are identified
purely by their ordering on the command line. The two styles of arguments
may be freely mixed, whereupon the tagged arguments are always processed
first, leaving any remaining (untagged) arguments to be scanned strictly
from left to right.
Argument values may be of type integer, double, string,
or boolean. Doubles may be given in either floating point or scientific
notation, and strings may be either quoted or unquoted. Booleans will accept
any of the keywords on, off, yes, no, true,
or false and yield an integer value of 0 (negative) or 1 (affirmative)
accordingly. A special argument type called literal is also provided;
it yields an integer value according to the presence or absence of a given
string literal on the command line. It is useful for specifying unparameterised
command line switches such as -verbose and -help.
Optional arguments and default values.
Arguments
may be assigned default values that take effect when no matching
command line argument could be found. When you specify a default value
for an argument you are, in effect, declaring that argument as being optional.
Arguments without defaults are, by definition, regarded as mandatory arguments.
Supported platforms
Since
argtable conforms to ansi C requirements it should, in theory, compile
on any system with a standard ansi C compiler. To date, argtable has been
successfully compiled on:
MIPSpro
C/C++ on IRIX 6.2, 6.3 and IRIX64 6.2
DEC
C/C++ on Digital Unix V4.0 (OSF/1)
GNU
gcc/g++ 2.7.2 on SunOS 5.5.1 and Linux 2.0.30.
Installation
Having
untarred the argtable distribution file (argtable-1.1.tar), cd to
the argtable/ directory and execute the configure
script. This script will determine which type of system you are running
and create the Makefile.config file from the appropriate configuration
file in the config/ directory.
Type
make clean to remove any old object files and executables
from the argtable directory tree.
Type
make all to build the executables and libraries. There shouldn't
be any compiler warning or errors.
Type
make runtest to run the system tests (optional). You ought
to see some messages like this:
RUNNING TESTS test10 test10cc test11 test11cc
test10 OK
test10cc OK
test11 OK
test11cc OK
ALL TESTS PASSED
If
you get the "all tests passed" message then you can be confident argtable
is working properly.
Edit
the INSTALL_DIR variable in the top level Makefile to be
the path where you would like to install the argtable libraries and documentation.
Nominally it is defined as INSTALL_DIR=/usr. The install process
will put files in the directories:
${INSTALL_DIR}/include
${INSTALL_DIR}/lib
${INSTALL_DIR}/man/man3/
${INSTALL_DIR}/doc/argtable
If these directories do not already exist you may have to create them
manually, depending upon your system.
As
root, type make install to install argtable into ${INSTALL_DIR}.
You may later use make uninstall to remove these files.
Argument tables in detail.
An argument table
is declared as an array of arg_rec structs, with each array element
pertaining to a single command line argument. The arg_rec struct
is defined in argtable.h as:
typedef enum {arg_int=0,arg_dbl,arg_str,arg_bool,arg_lit} arg_type;
typedef struct
{
char *tagstr; /* argument tag string */
char *argname; /* argument name string */
arg_type argtype; /* argument data type */
void *valueptr; /* pointer to user storage location */
char *defaultstr; /* default argument value, as a string */
char *argdescrip; /* argument description string */
} arg_rec;
An
argument table might, for example, be defined as follows:
int main(int argc, char **argv)
{
char str[50];
double grad;
int c;
arg_rec argtable[] =
{
{"-tit ", "<title>", arg_str, str, "noname","\t\t title"},
{"grad:", "gradient",arg_dbl, &grad, NULL, "\t line gradient"},
{NULL, "y-int", arg_int, &c, "0", "\t\t y-intercept"}
};
const size_t narg = sizeof(argtable)/sizeof(arg_rec);
...
The tag string:
The first field of arg_rec is the argument's tag string. It defines
the prefix literal that identifies a tagged argument. The tag string is
optional, but when present it must contain at least one non-whitespace
character. Alternatively it can be given as NULL thus declaring the argument
as untagged.
The
name string:
The second field of arg_rec is the argument's name string. It is not
actually used to process the command line arguments, rather it defines
the name of the argument as it appears in the description strings generated
by the arg_syntax() and arg_glossary() library functions.
Those functions automatically substitute any NULL names with the argument's
data type enclosed in angled brackets, as in "<int>" or "<string>".
The
data type:
The third field is an enumerated type that defines the data type of
the command line argument. Possible values are arg_int, arg_dbl,
arg_str, arg_bool, and arg_lit. They represent integer,
double, string, boolean, and literal arguments
respectively.
The
data pointer:
The fourth field is a pointer-to-void that gives the address of the
user-defined program variable that is to be used to store the argument's
value. A NULL pointer here causes the value to be discarded once is has
been scanned.
Take care that the data type of of the target memory location matches
that specified in the previous column. Arguments of type arg_int,
arg_bool, and arg_lit must each point to an integer
variable. Those of type arg_dbl must point to a double and
those of arg_str must point to a char array.
The
default value:
The fifth field is a string which contains an optional default value
for the argument. It is defined as a string and automatically cast to the
appropriate data type at run time. A NULL value indicates no default.
The
description string:
The sixth and final field allows the programmer to enter a brief description
of the argument. It is these descriptions that are output by the arg_glossary()
function. A NULL value causes that entry to be omitted from the glossary
output.
The argtable library functions
Of
all the argtable library functions, the three basic functions arg_scanargv(),
arg_syntax() and arg_glossary() are usually all that is required
to implement a simple command line grammar. The remaining library functions
afford greater control over the argument parsing for more complex grammars,
or just make for convenience.
int
arg_scanargv(int argc, char** argv, arg_rec *argtable, int n, char* CmdLine,
char* ErrMsg, char* ErrMark);
Scans
the command line arguments in argv[] according to the n argument
entries given in *argtable. Returns 1 upon success, else 0.
A copy of the command line is always written into *CmdLine and any
error reporting information is written into *ErrMsg and *ErrMark.
const
char* arg_syntax(const arg_rec* argtable, int n);
Generates
a single line string describing the usage syntax of the n element
argument table at *argtable.
const
char* arg_glossary(const arg_rec* argtable, int n, const char* prefix);
Generates
a multi-line glossary string from an argument table, one line per argument
table entry. Each line is prefixed with the string in *prefix. Argument
table records with NULL description fields are omitted from the glossary.
void
arg_catargs(int argc, char **argv, char *str);
Concatenates
the command line arguments in argv[] into a one line string of space
separated arguments and stores the result in *str. This is useful
for preparing an argument string for the arg_scanstr() function.
void
arg_dump(FILE* fp, const arg_rec* argtable, int n);
Prints
the contents of the argument table at *argtable to the stream fp.
This is useful for debugging.
arg_rec
arg_record(char *tagstr, char *argname, arg_type argtype, void *valueptr,
char *defaultstr, char *argdescrip);
Returns
an arg_rec struct pre-filled with the given values. Provides a convenient
method for constructing argument table records dynamically.
int
arg_scanstr(char* str, arg_rec *argtable, int n, char* ErrMsg, char* ErrMark);
Much
like arg_scanargv() but scans the arguments from a string instead
of argv[].
For
more comprehensive descriptions of these functions see the unix man pages
arg_catargs.3
arg_glossary.3
arg_record.3
arg_scanargv.3
arg_scanstr.3
arg_syntax.3
arg_typestr.3
An example program
Usage: example [-tit<title>] grad:gradient [y-int]
-tit<title> title
grad:gradient line gradient
y-int y-intercept
This
simple program implements the above argument usage which it also displays
on stdout when invoked without any arguments. When given a valid set of
arguments, the program displays the resulting argument values stored as
they are stored in the local program variables. Otherwise, it echoes the
erroneous command line together with an appropriate error message to stdout
after which it terminates with error code 1.
#include "argtable.h"
int main(int argc, char **argv)
{
static char str[50];
static double grad;
static int c;
arg_rec argtable[] =
{
{"-tit ","<title>", arg_str, str, "noname", "\t\t title"},
{"grad:","gradient",arg_dbl, &grad, NULL, "\t line gradient"},
{NULL, "y-int", arg_int, &c, "0", "\t\t y-intercept"}
};
const size_t narg = sizeof(argtable)/sizeof(arg_rec);
/*-- process the command line args --*/
if (argc==1)
{
/*-- display program usage and exit. --*/
printf("Usage: %s %s\n", argv[0], arg_syntax(argtable,narg));
printf("%s\n",arg_glossary(argtable,narg," "));
return 0;
}
else
{
/*-- scan command line arguments from argv[] --*/
char cmdline[200], errmsg[200], errmark[200];
if (!arg_scanargv(argc,argv,argtable,narg,
cmdline,errmsg,errmark))
{
/*-- arg error occurred, print error message and exit --*/
printf("ERROR: %s\n", cmdline);
printf(" %s %s\n", errmark, errmsg);
return 1;
}
}
/*-- get here only if command line args ok --*/
printf("title: \"%s\"\n",str);
printf("gradient: %f\n",grad);
printf("y-intercept: %d\n",c);
return 0;
}
The
code for this program is available, along with other examples, in the examples/
subdirectory of the argtable installation directory. To compile it, you
must link the source code with libargtable.a which is found in the
lib/ subdirectory of the installation directory.
$
cc example.c -largtable -o example
Below
is the output of this example program when given various command line arguments,
both good and bad.
$ example
Usage: example [-tit <title>] grad:gradient [y-int]
-tit <title> title
grad:gradient line gradient
y-int y-intercept
$ example grad:10
title: "noname"
gradient: 10.000000
y-intercept: 0
$ example 7 grad:1.234
title: "noname"
gradient: 1.234000
y-intercept: 7
$ example -tit "hello world" grad:3.33 11
title: "hello world"
gradient: 3.330000
y-intercept: 11
$ example grad:oops
ERROR: example grad:oops
^ invalid grad:gradient argument
$ example grad:13 nope
ERROR: example grad:13 nope
^^^^ unexpected argument
$ example grad:13 99 uh oh
ERROR: example grad:13 99 uh oh
^^ unexpected argument
History & Release Notes
Argtable-1.0
released November 13, 1998.
Argtable-1.1 released
January 20, 1999.
This version fixes some cross-platform compilation errors, and saw the
introduction of the multi-platform configuration. It also saw the addition
of the arg_record() function and a change to the arg_scanargv()
function so that it no longer requires argv[0] to be the first entry of
the argument table. To maintain backwards compatibility, programs written
for version 1.0 should now define the macro
#define ARGTABLE_COMPATIBILITY_10
prior to including the argtable.h header file.
From the author
Argtable
is actively maintained by me, its author, Stewart Heitmann. It is a tool
I have felt has been long overdue in the C/C++ world, and having written
it I hope that you will find it as useful as I do. If you have any comments
or suggestions for improvements please email me at Stewart.Heitmann@tip.csiro.au,
I'd love to hear from you. Happy parsing!