/* getargs - command line argument processor for C programs (C) Copyright 1985, Allen I. Holub. All rights reserved. This program may be copied for personal, non-profit use only history... May 1985 published in Dr. Dobb's Journal #103. 19 May 85 Transcribed by James R. Van Zandt */ #include #include typedef int (*PFI)(); static char *setarg(argp,linep) ARG *argp; char *linep; { /* set an argument. argp points at the argument table entry corresponding to *linep. Returns linep, updated to point past the argument being set */ ++linep; switch(argp->type) {case INTEGER: *argp->variable=stoi(&linep); break; case BOOLEAN: *argp->variable=1; break; case CHARACTER: *argp->variable=*linep++; break; case STRING: *(char **)argp->variable=linep; linep=""; break; case PROC: (*(PFI)(argp->variable))(linep); linep=""; break; default: fprintf(stderr,"INTERNAL ERROR: BAD ARGUMENT TYPE\n"); break; } return (linep); } static ARG *findarg(c,tabp,tabsize) int c,tabsize; ARG *tabp; { /* return pointer to argument table entry corresponding to c (or 0 if c isn't in table). */ for( ; --tabsize>=0; tabp++) {if(tabp->arg==c) return tabp;} return 0; } static pr_usage(tabp,tabsize) ARG *tabp; int tabsize; { /* print the argtab in the form: - (value is <*variable>) */ for(; --tabsize>=0; tabp++) {switch(tabp->type) {case INTEGER: fprintf(stderr,"-%c %-40s (value is ", tabp->arg, tabp->errmsg); fprintf(stderr,"%-5d)\n",*(tabp->variable)); break; case BOOLEAN: fprintf(stderr,"-%c %-40s (value is ", tabp->arg, tabp->errmsg); fprintf(stderr,"%-5s)\n",*(tabp->variable) ?"TRUE":"FALSE"); break; case CHARACTER: fprintf(stderr,"-%c %-40s (value is ", tabp->arg,tabp->errmsg); fprintf(stderr,"%-5c)\n",*(tabp->variable)); break; case STRING: fprintf(stderr,"-%c %-40s (value is ", tabp->arg, tabp->errmsg); fprintf(stderr,"\"%s\")\n", *(char **)tabp->variable); break; case PROC: fprintf(stderr,"-%c %-40s\n", tabp->arg,tabp->errmsg); break; } } } #define ERRMSG "Illegal argument \'%c\'. Legal arguments are:\n\n" int getargs(argc,argv,tabp,tabsize) int argc,tabsize; char **argv; ARG *tabp; { /* Process command line arguments, stripping all command line switches out of argv. Return a new argc. If an error is found exit(1) is called (getargs won't return) and a usage message is printed showing all arguments in the table. */ register int nargc; register char **nargv, *p; register ARG *argp; nargc=1; for (nargv=++argv; --argc>0; argv++) {if(**argv!='-') {*nargv++=*argv; nargc++;} else {p=(*argv)+1; while(*p) {if(argp=findarg(*p,tabp, tabsize)) {p=setarg(argp,p);} else {fprintf(stderr,ERRMSG,*p); pr_usage(tabp,tabsize); exit(1); } } } } return nargc; } #define islower(c) ('a'<=(c)&&(c)<='z') #define toupper(c) (islower(c)?(c)-('a'-'A'):(c)) int stoi(instr) register char **instr; { /* Convert string to integer. If string starts with 0x it is interpreted as a hex number, else if it starts with a 0 it is octal, else it is decimal. Conversion stops on encountering the first character which is not a digit in the indicated radix. *instr is updated to point past the end of the number. */ register int num=0; register char *str; int sign=1; str=*instr; while(*str==' ' || *str=='\t' || *str=='\n') {str++;} if(*str=='-') {sign=-1; str++;} if(*str=='0') {++str; if(*str=='x' || *str=='X') {str++; while( ('0'<=*str && *str<='9') || ('a'<=*str && *str<='f') || ('A'<=*str && *str<='F') ) {num=num*16+ (('0'<=*str && *str<='9') ? *str-'0' : toupper(*str)-'A'+10); str++; } } else {while('0'<=*str && *str<='7') {num = num*8+ *str++ - '0';}} } else {while('0'<=*str && *str<='9') {num=num*10+ *str++-'0';}} *instr=str; return (num*sign); }