| /*% cyntax -DTEST % && cc -DTEST -go # % |
| */ |
| #include "rc.h" |
| #include "getflags.h" |
| #include "fns.h" |
| char *flagset[] = {"<flag>"}; |
| char **flag[NFLAG]; |
| char cmdline[NCMDLINE+1]; |
| char *cmdname; |
| static char *flagarg=""; |
| static void reverse(char**, char**); |
| static int scanflag(int, char*); |
| static void errn(char*, int); |
| static void errs(char*); |
| static void errc(int); |
| static int reason; |
| #define RESET 1 |
| #define FEWARGS 2 |
| #define FLAGSYN 3 |
| #define BADFLAG 4 |
| static int badflag; |
| |
| int |
| getflags(int argc, char *argv[], char *flags, int stop) |
| { |
| char *s, *t; |
| int i, j, c, count; |
| flagarg = flags; |
| if(cmdname==0) |
| cmdname = argv[0]; |
| s = cmdline; |
| for(i = 0;i!=argc;i++){ |
| for(t = argv[i];*t;t++) |
| if(s!=&cmdline[NCMDLINE]) |
| *s++=*t; |
| if(i!=argc-1 && s!=&cmdline[NCMDLINE]) |
| *s++=' '; |
| } |
| *s='\0'; |
| i = 1; |
| while(i!=argc){ |
| if(argv[i][0]!='-' || argv[i][1]=='\0'){ |
| if(stop) |
| return argc; |
| i++; |
| continue; |
| } |
| s = argv[i]+1; |
| while(*s){ |
| c=*s++; |
| count = scanflag(c, flags); |
| if(count==-1) |
| return -1; |
| if(flag[c]){ reason = RESET; badflag = c; return -1; } |
| if(count==0){ |
| flag[c] = flagset; |
| if(*s=='\0'){ |
| for(j = i+1;j<=argc;j++) |
| argv[j-1] = argv[j]; |
| --argc; |
| } |
| } |
| else{ |
| if(*s=='\0'){ |
| for(j = i+1;j<=argc;j++) |
| argv[j-1] = argv[j]; |
| --argc; |
| s = argv[i]; |
| } |
| if(argc-i<count){ |
| reason = FEWARGS; |
| badflag = c; |
| return -1; |
| } |
| reverse(argv+i, argv+argc); |
| reverse(argv+i, argv+argc-count); |
| reverse(argv+argc-count+1, argv+argc); |
| argc-=count; |
| flag[c] = argv+argc+1; |
| flag[c][0] = s; |
| s=""; |
| } |
| } |
| } |
| return argc; |
| } |
| |
| static void |
| reverse(char **p, char **q) |
| { |
| char *t; |
| for(;p<q;p++,--q){ t=*p; *p=*q; *q = t; } |
| } |
| |
| static int |
| scanflag(int c, char *f) |
| { |
| int fc, count; |
| if(0<=c && c<NFLAG) |
| while(*f){ |
| if(*f==' '){ |
| f++; |
| continue; |
| } |
| fc=*f++; |
| if(*f==':'){ |
| f++; |
| if(*f<'0' || '9'<*f){ reason = FLAGSYN; return -1; } |
| count = 0; |
| while('0'<=*f && *f<='9') count = count*10+*f++-'0'; |
| } |
| else |
| count = 0; |
| if(*f=='['){ |
| do{ |
| f++; |
| if(*f=='\0'){ reason = FLAGSYN; return -1; } |
| }while(*f!=']'); |
| f++; |
| } |
| if(c==fc) |
| return count; |
| } |
| reason = BADFLAG; |
| badflag = c; |
| return -1; |
| } |
| |
| void |
| usage(char *tail) |
| { |
| char *s, *t, c; |
| int count, nflag = 0; |
| switch(reason){ |
| case RESET: |
| errs("Flag -"); |
| errc(badflag); |
| errs(": set twice\n"); |
| break; |
| case FEWARGS: |
| errs("Flag -"); |
| errc(badflag); |
| errs(": too few arguments\n"); |
| break; |
| case FLAGSYN: |
| errs("Bad argument to getflags!\n"); |
| break; |
| case BADFLAG: |
| errs("Illegal flag -"); |
| errc(badflag); |
| errc('\n'); |
| break; |
| } |
| errs("Usage: "); |
| errs(cmdname); |
| for(s = flagarg;*s;){ |
| c=*s; |
| if(*s++==' ') |
| continue; |
| if(*s==':'){ |
| s++; |
| count = 0; |
| while('0'<=*s && *s<='9') count = count*10+*s++-'0'; |
| } |
| else count = 0; |
| if(count==0){ |
| if(nflag==0) |
| errs(" [-"); |
| nflag++; |
| errc(c); |
| } |
| if(*s=='['){ |
| s++; |
| while(*s!=']' && *s!='\0') s++; |
| if(*s==']') |
| s++; |
| } |
| } |
| if(nflag) |
| errs("]"); |
| for(s = flagarg;*s;){ |
| c=*s; |
| if(*s++==' ') |
| continue; |
| if(*s==':'){ |
| s++; |
| count = 0; |
| while('0'<=*s && *s<='9') count = count*10+*s++-'0'; |
| } |
| else count = 0; |
| if(count!=0){ |
| errs(" [-"); |
| errc(c); |
| if(*s=='['){ |
| s++; |
| t = s; |
| while(*s!=']' && *s!='\0') s++; |
| errs(" "); |
| errn(t, s-t); |
| if(*s==']') |
| s++; |
| } |
| else |
| while(count--) errs(" arg"); |
| errs("]"); |
| } |
| else if(*s=='['){ |
| s++; |
| while(*s!=']' && *s!='\0') s++; |
| if(*s==']') |
| s++; |
| } |
| } |
| if(tail){ |
| errs(" "); |
| errs(tail); |
| } |
| errs("\n"); |
| Exit("bad flags"); |
| } |
| |
| static void |
| errn(char *s, int count) |
| { |
| while(count){ errc(*s++); --count; } |
| } |
| |
| static void |
| errs(char *s) |
| { |
| while(*s) errc(*s++); |
| } |
| #define NBUF 80 |
| static char buf[NBUF], *bufp = buf; |
| |
| static void |
| errc(int c) |
| { |
| *bufp++=c; |
| if(bufp==&buf[NBUF] || c=='\n'){ |
| Write(2, buf, bufp-buf); |
| bufp = buf; |
| } |
| } |