getopt

Sarantos Kapidakis sarantos at notecnirp.Princeton.EDU
Fri Jun 16 15:36:47 AEST 1989


Here is my version of getopt, which have much more flexibility
than the standard one, and can parse the arguments more than one
times.  Examples and documentation can be produced by different
preprocessor options:

#if defined(DOC)
The Getopt routine helps with finding the options from the command line.
It takes 7 arguments:
argc, argv: The argument counter and vector, as in the main program.
	The argv[0] is used as the program name, in case of error.
pargc, pargv: Pointers to (so as their values can be updated) the argument
	index and position in the current argument.
	In the usual usage, in the first call to this routine, *pargc will
	be 1, indicating that the next argument to be processed is the
	first argument (after the program name), and **pargv=`\0`,
	indicating we finished processing the previous argument.
	In any case, if **pargv != '\0', the next letter **pargv
	is considered as the next option, while otherwise, a '-'
	is expected to be found as the first character of the next
	argument is processed.
	Normally, the client never has to change *pargv, and *pargc.
par: If the option found has arguments, the first of these is stored in *par.
	If more arguments, say n were asked, argument i (1<i<=n) is accessed
	as agrv[(*pargc)-n-1+i].  This is easily understand from the fact that
	argv[*pargc] is always the next argument to be processed, so the last
	argument found was argv[(*pargc)-1], and so on.
	The first argument has a special treatment, because it may start from
	the middle of the real argument, while the others start always in the
	beginning.
	This variable is not changed if the option found has no arguments.
ostr1: The string containing the option letters, and possibly some of
	the control characters ':', '?' and '*'.
	The option-letters, followed by a '*' means that this
	option may have an argument adjacent to it. If no such
	argument exists, the routine consider the empty string
	as its argument (and never the next argument in the list).
	The option-letters, followed by a number of ':' or '?' means that
  	this option needs so many arguments. The first argument may
	be adjacent to the option letter, or a separate argument if
	if the option was the last character in that argument.
	*ppar is assigned the address of the first argument, or NULL
	if there are no arguments at all.
	The rest of the required arguments (if any), are the next
	arguments in the argv list, upto argv[(*pargc)-1].
	An error occurs if not enough arguments were found, when the
	':' was used (but not when the '*' was used).

	In any case, *pargc is always increased one for each expected
	argument, so that its difference from argc expresses the number
	of arguments still availiable (or missing for negative value).

	After returning from any of these cases(an option found followed
	by a ':', '?' or '*'), **pargv is always '\0', since the last
	argument was consumed entirelly.
ostr2: The string containing some additional option letters, in the same
	format as ostr1, and which are just going to be ignored and passed by,
	by the procedure. In most cases this string is the empty string.

	The routine returns the option found, or '?' for error
	and EOF for no option found.  Then the arguments to the
	program are from argv[*pargc] up to argv[argc-1].

example:
	we can call the following program as follows,
	or in many other combinations:
#endif
#if !(defined(DOC) || defined(DEFS) || defined(SHELL) ||\
			defined(PROGRAM) || defined(DATA))
/*FUNCTIONS*/
/* got this off net.sources, and improve it */
#include <stdio.h>

Getopt(argc, argv, /*INOUT*/ pargc, /*INOUT*/ pargv, /*OUT*/ ppar, ostr1, ostr2)
int	argc; /* argument counter */
char	**argv; /* argument vector */
int	*pargc; /* the &possition to be read next on the argument vector */
char	**pargv; /* the &possition to be read next on the current argument */
char	**ppar; /* any returned &value (string) for the option found */
char	*ostr1, *ostr2; /* the string of options */
{
	extern	char	*index();
	char	sop[2];
	char	*dummy;			/* dummy parameter - ignored options */
	register char	**pstr;		/* the real first parameter address */
	register char	*optr;		/* option letter list index */
	register int	ochar;		/* character checked for validity */
			/* update scanning pointer */
	for(;;){
	if (**pargv == '\0' && (*pargc >= argc || (*pargv=argv[*pargc]) == NULL
	|| **pargv != '-' || *++*pargv=='\0' || **pargv == '-' && (++*pargc))) {
			*pargv = "";
			return(EOF);
		}
	if ((ochar = *(*pargv)++) == ':' || ochar == '*' ||  ochar == '?' ||
		(ostr1==NULL || (pstr= ppar, optr=index(ostr1,ochar))==NULL) &&
		(ostr2==NULL || (pstr= &dummy, optr=index(ostr2,ochar))==NULL)) {
		if (**pargv=='\0') ++*pargc ;
		sop[0]=ochar; sop[1]='\0';
		wrong("illegal option: '%s'", sop);
		return('?');
	}
	if (*++optr != ':' && *optr != '?') {	/* don't need next argument */
		if (*optr=='*' && *(*pstr = *pargv)!='\0') *pargv="";
		if (**pargv=='\0') ++*pargc ;
	}
	else {				/* need argument */
		++*pargc;
		if (*(*pstr = *pargv) != '\0') *pargv = "";
		else	*pstr = (*pargc < argc)? argv[(*pargc)++]:
				(--optr, (char *) NULL);
		while(*++optr == ':' || *optr == '?')
			if (++*pargc > argc && *optr == ':') {
				sop[0]=ochar; sop[1]='\0';
				wrong("argument missing from option '%s'", sop);
				return('?');
			}
					
	}
	if (pstr==ppar) return(ochar);	/* dump back option letter */
	}
}
/*FUNCTIONS*/
#endif
#if defined(DOC) || defined(SHELL)
	a.out	-vvargument -a argumenttoa -P -x 1 2 3 file1 file2
	a.out	-aargumenttoa -PargumenttoP -v varg -x 1 2 3 file1 file2
	a.out	-a argumenttoa -x1 2 3 file1 file2
	a.out	-P file1 file2
#endif
#if defined(DOC) || defined(TEST) || defined(PROGRAM)
#if !defined(DOC)
#include <stdio.h>
#endif

char	*progname;
char	*opa="default aa", *opc=NULL, *opP=NULL;
char	*opx1=NULL, *opx2=NULL, *opx3=NULL;
char	*opy1=NULL, *opy2=NULL, *opy3=NULL;
int	opA=0;

main(argc,argv)
int	argc ;
char	**argv ;
{
	int	optc=1;
	char	*optr="", *par;
	int	c, i;
	progname=argv[0];
	while ((c=Getopt(argc, argv, &optc, &optr, &par,
		"Aa?P*c:x:::y:??", "v:"))!=EOF)
		switch (c) {
		/* 'v' will never be returned. It is just ignored */
		case'a':opa=par ;break;
			/* may have 1 argument */

		case'c':opc=par ;break;
		case'A':opA= !opA; break;
			/* needs no argument */
		case'P':opP=par;break;
			/* may have an argument (if -Parg) or may not (if -P) */
		case'x':opx1=par; opx2=argv[optc-2]; opx3=argv[optc-1]; break;
			/* needs 3 arguments */
		case'y':opy1=par;
			if (optc-argc < 2) opy2=argv[optc-2];
			if (optc-argc < 1) opy3=argv[optc-1]; break;
			/* needs 1 argument and may have up to 3 arguments */
		default:exit(2);
		}
	for(i=0 ; i<argc ; i++) printf("%s%c", argv[i], (i==argc-1)?'\n':' ');
	printf("%c: %s\n", 'A', opA? "true": "false");
	if (opP != NULL)printf("%c: %s\n", 'P', opP);
	if (opc != NULL)printf("%c: %s\n", 'c', opc);
	if (opa != NULL)printf("%c: %s\n", 'a', opa);
	if (opx1 != NULL)printf("%c: %s %s %s\n", 'x', opx1, opx2, opx3);
	if (opy1 != NULL)printf("%c: %s", 'y', opy1);
	if (opy2 != NULL)printf(" %s", opy2);
	if (opy3 != NULL)printf(" %s", opy3);
	if (opy1 != NULL)printf("\n");
	printf("optc=%d, argc=%d\n file arguments:", optc, argc);
	while(optc < argc) printf("%s ", argv[optc++]);
	printf("\noptc=%d, argc=%d\n", optc, argc);
	exit(0);
}

#include "error.c"
#endif



More information about the Comp.lang.c mailing list