[comp.lang.c] command line parser

mjc@rm1.UUCP (Mark J. Christophel) (02/06/90)

In article <2048@lamont.ldgo.columbia.edu>, boaz@lamont.ldgo.columbia.edu (richard boaz) writes:
> does anyone happen to have a nice clean command line parser in C?  i'm currently
> using one i came up with, however, i'm wondering if there might be a better
> solution.  this parser must be:
> 
> 	1)  straightford, i.e. easy to understand as well as easy to add to,
> 
> 	2)  command line arguments may be optional or required,
> 
> 	3)  program must recognize when an incorrect invocation of the program
> 	    has been made.
> 
> what i'm thinking of is an example like:
> 
> 	cluster -S /duke/data/events/ -l /duke/data/events/LOGS -m 2.5
> 
> where directories, numbers, whatever appear after the '-' argument, or not.

Try using getopt().

main (argc, argv)
int	argc;
char 	*argv[];
{
	int c;
	extern char *optarg;

	/* Third argument to getopt() is option string.  The ':'
	 * tells getopt() that the preceding option has an argument.
	 * So, 'S', 'l', and 'm' have arguments following them on the
	 * command line.  'a', and 'b' would not.
	 */
	while ((c = getopt(argc, argv, "S:l:m:ab")) != EOF)
	    switch (c)
	    {
		case 'S':
		    Sdir = optarg;	/* like your strcpy() */
					/* no need to in/decrement
					 * argc, argv.  getopt() does this.
					 */
		     .			/* rest of processing */
		     .
		     .
		    break;
		
		case 'l':
		    ldir = optarg;
		     .
		     .
		     .
		    break;

		case 'm':
		    mflag = atof(optarg);
		     .
		     .
		     .
		    break;

		case 'a':
		    aflag = TRUE;
		     .
		     .
		     .
		    break;

		case 'b':
		    bflag = TRUE;
		     .
		     .
		     .
		    break;

		case '?':
		default:
		    /* Invalid option, error message displayed by
		     * getopt() I believe.
		     */
		    break;
	    }
	/* rest of processing */
}

> 
> i would apreciate any responses via the newsgroup or email to me.  
> thanks in advance.

--

Mark J. Christophel		!rm1!mjc	       (305) 846-6873
Racal-Milgo, P.O. Box 407044, MS E112, Ft. Lauderdale, FL  33340-7044
-- 
Mark J. Christophel		   novavax!rm1!mjc		  (305) 846-6873
[M. Christophel, Racal-Milgo, MS E112, Box 407044, Ft Lauderdale, FL 33340-7044]

peter@ficc.uu.net (Peter da Silva) (02/06/90)

In article <232@rm1.UUCP> mjc@rm1.UUCP (Mark J. Christophel) writes:
> In article <2048@lamont.ldgo.columbia.edu>, boaz@lamont.ldgo.columbia.edu (richard boaz) writes:
> > does anyone happen to have a nice clean command line parser in C?

> > 	cluster -S /duke/data/events/ -l /duke/data/events/LOGS -m 2.5

> Try using getopt().

No, try using parseargs() by Eric Allman. I've made some enhancements to it,
and recently posted diffs to alt.sources. The original will be coming out in
comp.sources.unix if Rich $alz ever wakes up, or you can ftp it from:

ucbarpa.berkeley.edu [128.32.130.11] pub/c_advisor/parseargs.shar

I'm thinking I should maybe post my complete code to alt.sources.

#include <parseargs.h>

char *Log = DEFAULTLOG;
char *Sdir = DEFAULTDIR;
float mflag = 0.0;
int aflag = 0, bflag = 0;

ARGDESC	Args[] =
{
	'S',	ARGOPT,		argStr,		__ &Sdir,	"Directory",
	'l',	ARGOPT,		argStr,		__ &Sdir,	"Logfile",
	'm',	ARGOPT,		argFloat,	__ &mflag,	"MFlag",
	'a',	ARGOPT,		argBool,	__ &aflag,	"AFlag",
	'b',	ARGOPT,		argBool,	__ &bflag,	"BFlag",
	ENDOFARGS
};

main(argc, argv)
	int argc;
	char **argv;
{
	int newargc;

	newargc = parseargs(argv, Args, "File");

	/* Now argv just contains actual file name arguments. */
}

Isn't that much simpler than getopt? And, it will automatically generate
the following usage message:

Usage: program [-S <Directory>] [-l <Logfile>] [-m <MFlag>] [-a] [-b] \
	[<File>]...

The exact same code, on the Amiga (with the Amiga version of parseargs I'm
working on) will implement Amiga syntax:

Usage: program [DIRECTORY <Directory>] [LOGFILE <Logfile>] [MFLAG <Mflag>] +
	[AFLAG] [BFLAG] [<File>]...

Similarly, VMS users would be able to use, with a slightly modified library:

Usage: program [/Directory=<Directory>] [/Logfile=<Logfile>] [/MFlag=<MFlag>] -
	[/AFlag] [/BFlag] [<File>]...

And in all of the above you get argument type checking, meaningful error
messages, and so on.

I'm much impressed with Eric's concept, and with minimal tweaking this becomes
the biggest advance in command line parsing since argv[argc] was -1.
-- 
 _--_|\  Peter da Silva. +1 713 274 5180. <peter@ficc.uu.net>.
/      \
\_.--._/ Xenix Support -- it's not just a job, it's an adventure!
      v  "Have you hugged your wolf today?" `-_-'