[alt.sources] parse.c: parse command-line arguments

hermit@ucscf.UCSC.EDU (William R. Ward) (01/05/91)

The following utility, to be linked into c programs which use
command-line arguments.

example program that uses this utility:

#include "parse.h"

int	main( argc, argv )
int	argc;
char	**argv;
{
	char		c;
	struct arg	*args;

	args = parse_args( argc, argv );
	for ( c='a' ; c!='z'; c++ )
		if ( args[ chindex( c )].ch )
			if ( args[ chindex( c )].str )
				printf( "Argument for %c is %s.\n", c,
				  args[ chindex( c )].str );
			else
				printf( "Flag %c set.\n", c );
}

Note that parse_args() returns a pointer to a series of struct
args.  (an array, but the returned value is a pointer, which is
almost the same thing.)  The index of the array is from 0 to
MAXARGS-1 (52), with 0 being any arguments specified without a -x
option (ie, if you gave the command "foo bar" the "bar" would be
in args[0]).  1-26 is for lower case characters ("foo -m bar" goes
in args[13]) and 27-52 are for uppercase characters.  The macros
chindex() and indexch() in parse.h perform the conversion between
character <-> index.

If the flag exists, args[n].ch contains the character corresponding
to 'n' and args[n].str contains any argument(s) associated with
it.  Also, note that if more than one argument is given for any
flag (or without any flags) they are concatenated with one space
between arguments.  This means that any flagless arg must precede
any flags or it will *not* end up in args[0].  I decided this was
better than only allowing one argument.  If you want to fix it, go
ahead, but please send me a patch so I can have both versions--both
are useful.  (Examples: The command "foo -n14 bar" puts "14 bar"
in args[12]; "foo -n hello -xn world" places "hello world" in
args[12].str and NULL in args[24].str.)

checksums using BSD4.3 'sum' program:

36727     2 parse.c
18452     1 parse.h

to unbundle, "sh" this file -- DO NOT use csh
SHAR archive format.  Archive created Fri Jan 4 12:45:26 PST 1991

-- cut here --
#!/bin/sh
echo x - parse.c
sed 's/^X//' > parse.c <<'+FUNKY+STUFF+'
X/*
X *	parse.c		William R. Ward <hermit@ucscb.UCSC.EDU>
X *
X *	Given parameters (argc,argv) representing command-line
X *	arguments, function parse_args() returns an array of argument
X *	values.  The array is of type struct arg, which is described in
X *	the file parse.h.
X *
X *	The routine defines a argument as follows: all uppercase or
X *	lowercase letters in a word starting with '-' up to the first
X *	non-letter in the word, with any words not beginning with '-'
X *	or parts of a word after and including the last argument letter
X *	given as that argument's parameter.
X *
X *	For example, given the following strings in (argc, argv),
X *	parse_args recognizes the following as arguments:
X *
X *		input:		argument(s):	parameter:
X *		-r		r		(none)
X *		-abc		a		(none)
X *				b		(none)
X *				c		(none)
X *		-xy74		x		(none)
X *				y		74
X *		-z45h		z		45h
X *		-f filename	f		filename
X */
X
X#include "parse.h"
X#include <stdio.h>
X#include <strings.h>
X
Xstruct arg	*parse_args( argc, argv )
Xint	argc;
Xchar	*argv[];
X{
X	int	i, set_ch();
X	static struct arg	args[ MAXARGS ];
X	char	*p, last = 0;
X	void	set_str();
X
X	for( i=1; i<argc; i++ )
X		if ( *argv[i] == '-' && *(argv[i]+1) ) {
X			for( p=argv[i]+1; chindex(*p); p++ )
X				if ( set_ch( args, *p ))
X					last = *p;
X			if ( *p )
X				if ( p==argv[i]+1 )
X					set_str( args, p-1, last );
X				else
X					set_str( args, p, last );
X		} else
X			set_str( args, argv[i], last );
X	return args;
X}
X
Xint	set_ch( args, x )
Xstruct arg	args[];
Xchar	x;
X{
X	int	index;
X
X	index = chindex(x);
X	if ( index ) {
X		args[ index ].ch = 1;
X		return 1;
X	} else
X		return 0;
X}
X
Xvoid	set_str( args, x, last )
Xstruct arg	args[];
Xchar	*x,
X	last;
X{
X	char	*t;
X	int	index;
X
X	index = chindex( last );
X	if ( args[ index ].str == NULL ) {
X		t = ( char * )calloc( strlen( x ), sizeof( char ));
X		strcpy( t, x );
X	} else {
X		t = ( char * )calloc( strlen( args[ index ].str ) +
X		    strlen( x ) + 1, sizeof( char ));
X		strcpy( t, args[ index ].str );
X		strcat( t, " " );
X		strcat( t, x );
X	}
X	free( args[ index ].str );
X	args[ index ].str = t;
X}
+FUNKY+STUFF+
echo '-rw-------  1 hermit       2037 Feb  9  1990 parse.c    (as sent)'
chmod u=rw,g=,o= parse.c
ls -l parse.c
echo x - parse.h
sed 's/^X//' > parse.h <<'+FUNKY+STUFF+'
X#include <ctype.h>
X
X#define MAXARGS	53
X	/* 26 lowercase + 26 uppercase + zero for non-letter */
X#define chindex(x) ( isalpha(x) ? ( islower(x) ? (x)-'a'+1 : (x)-'A'+27 ) : 0 )
X	/* macro, given a char x, returns the index into args[] */
X#define indexch(x) ( (x) ? ( (x)<=26 ? (x)+'a'-1 : (x)+'A'-27 ) : 0 )
X	/* macro, given an index into args[] 0 <= x <= MAXARGS, returns char */
X
Xstruct arg {
X	char	ch;	/* true/false: is there an arg for this letter? */
X	char	*str;	/* holds pointer to string containing parameter
X			    or NULL if no parameter */
X};
+FUNKY+STUFF+
echo '-rw-------  1 hermit        551 Feb  9  1990 parse.h    (as sent)'
chmod u=rw,g=,o= parse.h
ls -l parse.h
exit 0
-- cut here --
-- 
------------------------------------------------------------------------
William R. Ward      | UC Santa Cruz, CIS    | [backbone]!ucbvax!
(408) 426-7267       | hermit@ucscf.UCSC.EDU |        ucscc!ucscf!hermit
UCSC-Cowell-787      +--------------------------------------------------
Santa Cruz, CA 95064 | Disclaimer: Nobody reads this anyway.
------------------------------------------------------------------------