parseargs.h

/* Notice of Copyright, License and Warranty
**
** This software is Copyright 1998, 1999, 2000 Jeffrey S. Dutky
** This software is licensed for use under the terms of the GNU General
** Public License (also called the GPL), a copy of which must be included
** with any distribution of this software. You may also find a copy of the
** GPL at the Free Software Foundation's web site at http://www.fsf.org/
** or http://www.gnu.org.
**
** This software is provided "as is" and without any express or implied
** warranties, including, without limitation, the implied waranties of
** merchantability and fitness for a particular purpose.
*/

/*
** This is a replacement for getopts() that has more features and will
** parse all your arguments in one command (no need to call the routine
** repeatedly). You can specify option flags, option flags that take an
** argument, optional positional parameters, optional positional param-
** eters with an optional flag, and required parameters. The routine
** will figure out what the maximum and minimum number of arguments to
** your program should be, and return an error if there too few or too
** many. It will also create a string containing the option flags that
** were passed to your program, and fill in any values into a variable
** list of strings.
**
** The format string is very similar to the one used by getopts(), only
** more so. You can pass a normal getopts() format string to parseargs
** and get a reasonable result, since the format for simple option flags
** is the same (option flag character followed by a colon). In order to
** specify a positional parameter that does not have an optional flag,
** you insert a pound sign or hash mark (#). If you want to specify a
** positional parameter that can have an optional flag you insert the
** flag character followedby an equals sign (=). If you want to specify
** a required positional parameter you insert a plus sign (+). Note that
** required postional parameters cannot have optional flags associated
** with them. You can specify that a program will accept a possibly
** infinite number of arguments by ending the format string with a
** question mark (?). The routine will not, however, check any more
** arguments than it has formats for. If you specify an infinite number
** of arguments you will need to examine the remaining arugments
** after the routine has finished. Since the routine returns the number
** of arguments it has examined, however, this a relatively easy.
**
** Values to option flags (and flags for positional parameters) can be
** separated by white space or can be contained in the same argument
** string (meaning "foo -b bar" and "foo -bbar" are both recognized).
**
** Now for an example of a command with complex arguments structure,
** the format string used to specify that structure, and how to call
** parseargs:
**
** The command can take four flags, two of which have arguments. It has
** one required positional parameter and two optional parameters, one of
** which can have a flag associated with it.
**
** foo [-ab] [-c <argc>] [-d <argd>] <param1> [[-e] <param2>] [<param3>]
**
** The format string looks like this: "abc:d:+e=#"
**
** Clearly the minimum number of arguments is 1, and the maximum is 10.
**
** The code in foo, that parses the arguments, looks like this:
**
** main(int args, char *arg[]){
**   char ac[255],ad[255],rp[255],pe[255],xx[255];
**   char options[255];
**   int err;
**
**   err=parseargs(args,arg,"abc:d:+e=#",options,ac,ad,rp,pe,xx);
**   if(err>0){
**     fprintf(stderr,"%s\n",parseerror(err));
**     return -1;
**   }
**   ...
**   return 0;
** }
**
** Whatever arguments were specified when the program is called are
** placed in the strings ac, ad, p1, p2, and p3, for use by the rest
** of the program. A list of the option flags is placed in the string
** options. The return value is either the number of arguments parsed,
** on success, or a negative value specifying what error occured and
** the last argument parsed before the error.
**
** Clearly there are some limitations to this tool: first, you can't
** have an option flag whose character is colon, hash, equals or plus.
** Second, I don't enforce the requirement that all flags must occur
** before all flagless parameters, though it won't cause any errors.
** Third, commands with a possibly infinite number of operands are
** not supported. Fourth, required parameters should occur before any
** optional positional parameters, or assignment behaviour will be
** somewhat odd.
**
** As an example, if the above example were called as "foo hello there"
** the result would be: options="", rp="hello", pe="there". If, however
** the format string were "abc:d:e=#+" (which would mean that the
** parseargs call would have to look like this:
**
**   err=parseargs(args,arg,"abc:d:e=#+",ac,ad,pe,xx,rp);
**
** the result would be: options="", pe="hello", xx="there". This is not
** what you might hope. (The fix for this problem, which involves
** trying to fill required parameters before other positonal parameters,
** is likely to be fairly involved. I don't feel like makeing this kind of
** effort at the moment, since it would likely compromose readability
** and reliability)
**
** If the program encounters an argument of "--" it will stop trying
** to match flags, assuming that all further arguments are just
** parameter values, even if they begin with a dash. Similary, a lone
** dash will be treated as a parameter, even if it occurs while the
** routine is still trying to match flags.
*/

/*
** parseargs() parses the command line arguments based on the
** format string provided by the caller and places parsed values
** into elements of a variable list of strings. A list of option flags is
** returned in the opt parameter.
*/

/*
** parserror() returns a string describing an error code returned by
** parseargs.
*/

/*
** parseusage() returns a string describing the correct usage of a
** command, whose name is provided in the prog parameter, as
** indicated by the provided format string. The description is
** wrapped to the specified width. Descriptive names of any
** parameters or option values are provided by the caller as a
** variable list of strings.
*/

/*
** badusage() returns true (1) if the provided return value from
** parseargs idicates a usage error. For any other type of error, a
** false value (0) is returned.
*/

int parseargs(int args, char *arg[], char *fmt, char *opt, ...);
const char *parseerror(int error);
const char *parseusage(char *prog, int width, char *fmt, ...);
int badusage(int retval);