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:

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


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!