|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T a
Length: 15849 (0x3de9) Types: TextFile Names: »argh.c«
└─⟦2d1937cfd⟧ Bits:30007241 EUUGD22: P.P 5.0 └─⟦dc59850a2⟧ »EurOpenD22/pp5.0/pp-5.tar.Z« └─⟦e5a54fb17⟧ └─⟦this⟧ »pp-5.0/Tools/mu/argh.c«
/* argh.c argument handling routines */ # ifndef lint static char Rcsid[] = "@(#)$Header: /cs/research/pp/hubris/pp-beta/Tools/mu/RCS/argh.c,v 5.0 90/09/20 16:29:00 pp Exp Locker: pp $"; # endif /* * $Header: /cs/research/pp/hubris/pp-beta/Tools/mu/RCS/argh.c,v 5.0 90/09/20 16:29:00 pp Exp Locker: pp $ * * $Log: argh.c,v $ * Revision 5.0 90/09/20 16:29:00 pp * rcsforce : 5.0 public release * */ #include "argh.h" #include "util.h" extern struct argdef arg[]; /* defined in main program */ static struct argfull *argfull; /* to point to full array */ static struct arginst *ai; /* to point to linked lists */ static asource; /* holds scan_args counter */ struct sort { struct argfull *tag; char *string; } argsort[MAXFLAGS]; /* to hold sort sequence */ static char *aerrlist[] = { /* usage : printf(aerrlist[i],a,b,c,d); char *a,*b,*c,*d */ "unknown error\n", /* 0 */ "flag %s not known\n", /* 1 */ "flag %s ambiguous match\n", /* 2 */ "invalid type for flag %s - fix source\n", /* 3 */ "limit of %s argument instances - aborted\n", /* 4 */ "flag %s value should be adjacent to '='\n", /* 5 */ "flag %s (type adjacent) not followed by value\n", /* 6 */ "flag %s - adjacent arguments not allowed without '='\n", /* 7 */ "flag %s (type next) must use next argument\n", /* 8 */ "flag %s (type next) has no next argument\n", /* 9 */ "flag %s (type 0 valued ) should not have value\n", /*10 */ "flag %s (type %s valued) has no value%s\n", /*11 */ "flag %s (type %s valued) has only %s value%s\n", /*12 */ "flag %s (type 1 or more) must have at least one value\n", /*13 */ "duplicate flag %s in table - fix source\n", /*14 */ "ambiguous flags %s and %s - fix source\n" /*15 */ }; /* ----------------------------------------------------------------- */ int prep_args(arg) /* scan flags list, count, set length, sort and calculate match length */ struct argdef arg[]; { struct argdef *a; struct argfull *af; int i,j,cur,prev; for(i=0,a=arg; a->flag[0]; i++,a++); /* count arg[] */ flagcount=i; /* flagcount is structure member for 'others' */ argfull = (struct argfull *) calloc( (flagcount+1), sizeof(struct argfull) ); asource=1; /* initialise scan_counter */ /* printf("flagcount %d\n",flagcount); */ for(i=0,a=arg,af=argfull; i<=flagcount; i++,a++,af++) { af->flag = a->flag; af->function = a->function; af->type = a->type; af->match = a->match; af->length = 0; af->count = 0; af->first = NULL; af->last = NULL; if ( index(VALIDTYPES,af->type) == NULL ) { arg_error(3,af->flag); cleanquit(); } argsort[i].tag = af; /* pointer to structure */ argsort[i].string = af->flag; /* pointer to flag chars. */ af->length=strlen(af->flag); /* printf("length %d match %d type %c %s\n",af->length, af->match, af->type, af->flag); */ } quick_string(argsort,flagcount+1); /* sort array argsort in flag order */ argsort[flagcount+1].tag = argsort[0].tag; /* both ends point to "" */ /* for(j=0;j<=flagcount; j++) { printf("argsort j=%d string=%s\n",j,argsort[j].string); } */ for(j=0,prev=0; j<=flagcount; j++,prev=cur) { af = argsort[j].tag; cur=mincmp(af->flag,(argsort[j+1].tag)->flag); if(!cur) { arg_error(14,af->flag); return(-1); } if (j && cur > af->length) { arg_error(15,af->flag,(argsort[j+1].tag)->flag); return(-1); } /* printf("sort %d %s type %c cur %d prev %d\n",j,af,af->type,cur,prev); */ if(af->match <= 0) { if(af->match < 0) af->match=af->length; else { af->match = (cur < prev) ? (prev) : (cur); } } } return(0); } /* ----------------------------------------------------------------- */ int scan_args(argc,argv) /* returns incremented scan_counter */ int argc; char **argv; { struct argdef *a=arg; /* passed in */ struct argfull *af=argfull; /* generated internally */ char **argvtemp=argv; char *cp,*v,*index(); char nullbyte='\0'; int i,c,ca,offset,n; if (!flagcount) { if ( (i=prep_args(arg)) ) cleanquit(); } /* The argument list is scanned, checking each argument against entries in structure 'argfull'. Linked lists are generated for all arguments of the same type, in command line sequence. Any parameters which do not match one of the ->type's are accumulated in a list of 'others'. sample flag -samplearg complete match (adj) ok ( unless !ADJARGS ) -sample arg complete match (next) ok ^ offset -sample=arg complete match with = (adj) ok -sample= arg complete match with = (next) - error - "value should be adjacent to '='" ^ offset -samarg incomplete match (adj) - error - "flag not known/ambiguous match" -sam arg incomplete match (next) ok -sam=arg incomplete match with =arg ok -sam= arg incomplete match with = (next) arg - error - "value should be adjacent to '='" ^ offset */ for(argcpi=1; argcpi < argc; argcpi++) { /* loop until arguments exhausted */ cp = *++argvtemp; if (**argvtemp == FLAGCHAR) { /* now test against each allowed type in turn */ for(i=0,af=argfull; i < flagcount; i++,af++) { if (!mystrncmp(af->flag, &cp[1], af->match)) { /* found a match */ if(( v = index(cp,EQUCHAR) ) != NULL) { if(*++v == '\0') { arg_error(5,af->flag); break; } } else { v = &nullbyte; if(af->length == af->match) { v=cp + af->match + 1; /* value starts at end of match (could point at '\0') */ } else { if ( (ONECHARARGS) && (af->match == 1)) { /* allow one char */ v = cp + 2 ; } else { /* have matched on af->match chars - try on ca chars */ ca=strlen(cp)-1; /* length of current argument less '-' */ if (mystrncmp(af->flag, &cp[1], ca)) { /* doesn't match */ /* now - try on af->length chars */ if (mystrncmp(af->flag, &cp[1], af->length)) { /* doesn't match */ arg_error(2,af->flag); break; } else { /* does match af->length chars */ v=cp + af->length + 1; } } else { /* does match ca chars */ v=cp + ca + 1; } } } if ((*v != '\0') && !ADJARGS) { arg_error(7,af->flag); break; } } /* endif == EQUCHAR */ offset=(v-cp); c = count_to_flag(argc,argvtemp,v); /* printf ("flag %s c-flag%s\n",af->flag,digit_word(c)); */ switch(af->type) { case 'a': if (*v == '\0') arg_error(6,af->flag); else take_next(1,af,&argvtemp,v,offset); break; case 'n': if (*v != '\0') { arg_error(8,af->flag); break; } if (c < 1 ) { arg_error(9,af->flag); break; } else take_next(1,af,&argvtemp,v,offset); break; case 'm': if (c < 1 ) arg_error(13,af->flag); else take_next(c,af,&argvtemp,v,offset); break; case 'z': take_next(c,af,&argvtemp,v,offset); break; case '0': if (c && ZEROCHECK) arg_error(10,af->flag); else take_next(1,af,&argvtemp,*argvtemp,0); /* from add_link */ break; default : /* digit flag type 1-9 */ n = af->type - '0'; if( c < n ) { if ( !c ) arg_error(11,af->flag,digit_word(n),(n == 1 ? "" : "s" ) ); else { arg_error(12,af->flag,digit_word(n),digit_word(c),(c == 1 ? "" : "s" )); } } else take_next(n,af,&argvtemp,v,offset); break; } /* end switch */ break; } else { /* no match */ if (i == flagcount-1 ) { /* have tried all flags */ arg_error(1,cp); /* take_next(1,&arg[flagcount],&argvtemp,*argvtemp,0); */ take_next(1,af+flagcount,&argvtemp,*argvtemp,0); /* make it an 'other' */ } } /* end if */ } /* end for */ } /* end if == FLAGCHAR */ else { /* this is an 'other' */ /* add argi to list pointed to by *next */ take_next(1,af+flagcount,&argvtemp,*argvtemp,0); /* from add_link */ } } /* endfor */ return(asource++); /* return value THEN increment */ } /* ----------------------------------------------------------------- */ void add_link(af,v,offset,argn,argof) /* extend linked list for flagnumber ONLY called from take_next() */ struct argfull *af; char *v; int offset,argn,argof; { static int argi_count=0; /* to count number of entries */ ai = (struct arginst *) malloc(sizeof(struct arginst)); /* printf("add_link: %s %x %d %d\n",af->flag,ai,argcpi,offset); */ if(!af->first) { af->first=ai; } else { (af->last)->next=ai; } ai->argcp=v; /* actual string of argument value */ ai->argci=argcpi; ai->argoi=offset; ai->argn=argn; ai->argof=argof; ai->argsrc=asource; /* indicates source of value */ ai->argused=0; ai->next=NULL; af->count++; af->last=ai; argi_count++; if ( argi_count > MAXARGS ) { arg_error(4,digit_word(MAXARGS)); cleanquit(); } return; } /* ----------------------------------------------------------------- */ void take_next(i,af,p,v,offset) /* take next i arguments ( assumes i > 0 ) offset used if first argument is adjacent */ int i,offset; struct argfull *af; char ***p,*v; { int argn=1; /* argn of argof=i */ int argof=i; if (*v != '\0') { add_link(af,v,offset,argn,argof); i--; argn++; } while(i) { (*p)++; argcpi++; add_link(af,**p,0,argn,argof); i--; argn++; } return; } /* ----------------------------------------------------------------- */ void arg_error(i,a,b,c,d) /* general error message output */ int i; char *a,*b,*c,*d; { printf("argh! : "); printf(aerrlist[i],a,b,c,d); return; } /* ----------------------------------------------------------------- */ int count_to_flag(argc,argvtemp,v) /* count arguments up to next flag */ int argc; char **argvtemp,*v; { int i; i=argcpi; argvtemp++; /* NOTE: this relies on left-right evaluation with && */ while ((i < (argc-1)) && (**argvtemp != FLAGCHAR)) { /* printf("loop i %d **argvtemp %c\n",i,**argvtemp); */ i++; argvtemp++; }; return(i-argcpi + ( *v == '\0' ? 0 : 1 )); } /* ----------------------------------------------------------------- */ void show_args(argc,argv,fp,af) /* display (sorted) list of flags, arguments found */ int argc; char **argv; FILE *fp; struct argfull *af; /* points to command which invoked display */ { int i; fprintf(fp,"\n%s : ",ARGHVER); fprintf(fp,"%d flags %d command line arguments",flagcount,argc); for(i=0; i <= flagcount; i++) { af = argsort[i].tag; fprintf(fp,(*af->flag == '\0') ? "\nothers ":"\nflag "); fprintf(fp,"%-15s\011type %c\011match %d\011count %d : ",af->flag,af->type,af->match,af->count); ai=af->first; while (ai) { /* fprintf(fp," %s",&argv[ai->argci][ai->argoi]); */ fprintf(fp," %s",ai->argcp); ai=ai->next; } } fprintf(fp,"\n"); return; } /* ----------------------------------------------------------------- */ void call_args(argc,argv,fp) /* call any routines corresponding to arguments found in flag declaration order */ FILE *fp; int argc; char **argv; { struct argfull *af; int i; for(i=0,af=argfull; i <= flagcount; i++,af++) { if((af->count) && (af->function != NULL)) { (*af->function)(argc,argv,fp,af); } } return; } /* ----------------------------------------------------------------- */ void list_args(fp,f) /* list arguments for flag f to file fp */ FILE *fp; char *f; { char *p; fprintf(fp,"%s_args : ",f); while( p = next_arg(f) ) { fprintf(fp,"<%s>",p); } fprintf(fp,"\n"); return; } /* ----------------------------------------------------------------- */ char *next_arg(f) /* get next arg for flag f - no ambiguity in specification of f allowed - any level */ char *f; { int n,of; /* place holders */ int s = 0; /* source not significant */ return(nextc_arg(f,s,&n,&of)); } /* ----------------------------------------------------------------- */ char *nextc_arg(f,s,n,of) /* get next arg for flag f with counts - no ambiguity in specification of f allowed */ char *f; int s,*n,*of; /* source, which, of how many */ { static char lastf[MAXFLAGLEN]="?"; /* to compare with last call */ static int source; /* ditto */ struct argfull *af=argfull; int i; if ((mystrcmp(f,lastf)) || (source != s)) { /* new value */ /* printf("new value <%s>{%d}, old value <%s>{%d}\n",f,s,lastf,source); */ strcpy(lastf,f); /* store for future reference */ source = s; /* ditto */ if (*f == '\0') { /* null string for 'others' */ ai=(af+flagcount)->first; } else { for(i=0,af=argfull; i <= flagcount; i++,af++) { if(mystrcmp(f,af->flag)) continue; /* printf("flag found"); */ ai=af->first; break; } } } else { ai=ai->next; } if(source) { /* searching for source */ while ( ai && (ai->argsrc != source)) ai=ai->next; } if(ai) { if(source) ai->argsrc = 0; /* clear out source indicator */ *n = ai->argn; *of = ai->argof; return(ai->argcp); } else { *n = 0; *of = 0; return(NULL); } } /* ----------------------------------------------------------------- */ char *digit_word(x) /* DANGER - do not expect to work for two calls both >10 or negative in same printf() */ int x; { int sign; static char buf[10]; static char *words[]= { "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine" }; if (x < 0) { sign = TRUE; x = -x; } else sign = FALSE; if (x < 10) if (!sign) return(words[x]); else sprintf( buf, "%s%s", (sign? "minus ":""), words[x] ); else sprintf( buf, "%s%d", (sign? "minus ":""), x ); return( buf ); } /* ----------------------------------------------------------------- */ void quick_string(a,count) /* quick sort string array a[i]->tag is tag pointer a[i]->string is pointer to character string - to be sorted */ struct sort a[]; int count; { qs_string(a,0,count-1,count); } void qs_string(a,left,right,count) /* recursive sort */ struct sort a[]; int left,right,count; { register int i,j; register char *x,*y; /* pointers to characters being sorted */ i=left; j=right; x=a[(left+right)/2].string; do { while(mystrcmp(a[i].string,x)<0 && i<right) i++; while(mystrcmp(a[j].string,x)>0 && j>left) j--; if( i <= j ) { y = a[i].string; a[count+1].tag = a[i].tag; /* swap tag pointers */ a[i].string = a[j].string; a[i].tag = a[j].tag; a[j].string = y; a[j].tag = a[count+1].tag; i++; j--; } } while ( i <= j ); if( left < j ) qs_string(a,left,j,count); if( i < right ) qs_string(a,i,right,count); } /* ----------------------------------------------------------------- */ int mincmp(a,b) /* minimum length reqd. to distinguish a, b - this relies on the behaviour of strncmp, when one or other string is exhausted first */ char *a,*b; { int i; if (!mystrcmp(a,b)) return(0); /* cannot distinguish */ if( a == NULL || b == NULL ) /* strictly NULLCP */ return(1); if( &a == '\0' || &b == '\0' ) return(1); for(i=1;;i++) { /* printf("a %s b %s i %d\n",a,b,i); */ if(mystrncmp(a,b,i)) /* different at i */ break; } return(i); } /* ----------------------------------------------------------------- */ mystrcmp(a,b) /* to avoid null dereference */ char *a,*b; { if ((a == NULL) && (b == NULL)) return(0); if ((a == NULL)) return(-1); if ((b == NULL)) return(1); return(strcmp(a,b)); } /* ----------------------------------------------------------------- */ mystrncmp(a,b,i) /* to avoid null dereference */ char *a,*b; int i; { if ((a == NULL) && (b == NULL)) return(0); if ((a == NULL)) return(-1); if ((b == NULL)) return(1); return(strncmp(a,b,i)); } /* ----------------------------------------------------------------- */