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