Blob


1 #include <u.h>
2 #include <libc.h>
3 #include <ctype.h>
4 #include "getflags.h"
6 char **flag[NFLAG];
7 char cmdline[NCMDLINE+1];
8 char *cmdname;
9 char *flagset[];
10 char *flagset[]={"<flag>"};
11 static char *flagarg="";
12 static void reverse(char **, char **);
13 static int scanflag(int, char *);
14 static int reason;
15 #define RESET 1
16 #define ARGCCOUNT 2
17 #define FLAGSYN 3
18 #define BADFLAG 4
19 static int badflag;
20 char *getflagsargv[NGETFLAGSARGV+2]; /* original argv stored here for people who need it */
22 int
23 getflags(int argc, char *argv[], char *flags)
24 {
25 char *s, *t;
26 int i, j, c, count;
27 flagarg=flags;
28 if(cmdname==0){
29 cmdname=argv[0];
30 for(i=0;i!=argc && i!=NGETFLAGSARGV;i++) getflagsargv[i]=argv[i];
31 if(argc>NGETFLAGSARGV) getflagsargv[i++]="...";
32 getflagsargv[i]=0;
33 }
34 s=cmdline;
35 for(i=0;i!=argc;i++){
36 for(t=argv[i];*t;)
37 if(s!=&cmdline[NCMDLINE])
38 *s++=*t++;
39 else
40 break;
41 if(i!=argc-1 && s!=&cmdline[NCMDLINE])
42 *s++=' ';
43 }
44 *s='\0';
45 i=1;
46 while(i!=argc && argv[i][0]=='-'){
47 s=argv[i]+1;
48 if(*s=='\0'){ /* if argument is "-", stop scanning and delete it */
49 for(j=i+1;j<=argc;j++)
50 argv[j-1]=argv[j];
51 return argc-1;
52 }
53 while(*s){
54 c=*s++;
55 count=scanflag(c, flags);
56 if(count==-1) return -1;
57 if(flag[c]){ reason=RESET; badflag=c; return -1; }
58 if(count==0){
59 flag[c]=flagset;
60 if(*s=='\0'){
61 for(j=i+1;j<=argc;j++)
62 argv[j-1]=argv[j];
63 --argc;
64 }
65 }
66 else{
67 if(*s=='\0'){
68 for(j=i+1;j<=argc;j++)
69 argv[j-1]=argv[j];
70 --argc;
71 s=argv[i];
72 }
73 if(argc-i<count){
74 reason=ARGCCOUNT;
75 badflag=c;
76 return -1;
77 }
78 reverse(argv+i, argv+argc);
79 reverse(argv+i, argv+argc-count);
80 reverse(argv+argc-count+1, argv+argc);
81 argc-=count;
82 flag[c]=argv+argc+1;
83 flag[c][0]=s;
84 s="";
85 }
86 }
87 }
88 return argc;
89 }
91 void
92 static reverse(char **p, char **q)
93 {
94 register char *t;
95 for(;p<q;p++,--q){ t=*p; *p=*q; *q=t; }
96 }
98 static int
99 scanflag(int c, char *f)
101 int fc, count;
102 if(0<=c && c<NFLAG) while(*f){
103 if(*f==' '){
104 f++;
105 continue;
107 fc=*f++;
108 if(*f==':'){
109 f++;
110 if(!isdigit((uchar)*f)){ reason=FLAGSYN; return -1; }
111 count=strtol(f, &f, 10);
113 else
114 count=0;
115 if(*f=='['){
116 int depth=1;
117 do{
118 f++;
119 if(*f=='\0'){ reason=FLAGSYN; return -1; }
120 if(*f=='[') depth++;
121 if(*f==']') depth--;
122 }while(depth>0);
123 f++;
125 if(c==fc) return count;
127 reason=BADFLAG;
128 badflag=c;
129 return -1;
132 static void errn(char *, int), errs(char *), errc(int);
134 void
135 usage(char *tail)
137 char *s, *t, c;
138 int count, nflag=0;
139 switch(reason){
140 case RESET:
141 errs("Flag -");
142 errc(badflag);
143 errs(": set twice\n");
144 break;
145 case ARGCCOUNT:
146 errs("Flag -");
147 errc(badflag);
148 errs(": too few arguments\n");
149 break;
150 case FLAGSYN:
151 errs("Bad argument to getflags!\n");
152 break;
153 case BADFLAG:
154 errs("Illegal flag -");
155 errc(badflag);
156 errc('\n');
157 break;
159 errs("Usage: ");
160 errs(cmdname);
161 for(s=flagarg;*s;){
162 c=*s;
163 if(*s++==' ') continue;
164 if(*s==':'){
165 s++;
166 count=strtol(s, &s, 10);
168 else count=0;
169 if(count==0){
170 if(nflag==0) errs(" [-");
171 nflag++;
172 errc(c);
174 if(*s=='['){
175 int depth=1;
176 s++;
177 for(;*s!='\0' && depth>0; s++)
178 if (*s==']') depth--;
179 else if (*s=='[') depth++;
182 if(nflag) errs("]");
183 for(s=flagarg;*s;){
184 c=*s;
185 if(*s++==' ') continue;
186 if(*s==':'){
187 s++;
188 count=strtol(s, &s, 10);
190 else count=0;
191 if(count!=0){
192 errs(" [-");
193 errc(c);
194 if(*s=='['){
195 int depth=1;
196 s++;
197 t=s;
198 for(;*s!='\0' && depth>0; s++)
199 if (*s==']') depth--;
200 else if (*s=='[') depth++;
201 errs(" ");
202 errn(t, s-t);
204 else
205 while(count--) errs(" arg");
206 errs("]");
208 else if(*s=='['){
209 int depth=1;
210 s++;
211 for(;*s!='\0' && depth>0; s++)
212 if (*s==']') depth--;
213 else if (*s=='[') depth++;
216 if(tail){
217 errs(" ");
218 errs(tail);
220 errs("\n");
221 exits("usage");
224 static void
225 errn(char *s, int count)
227 while(count){ errc(*s++); --count; }
230 static void
231 errs(char *s)
233 while(*s) errc(*s++);
236 #define NBUF 80
237 static char buf[NBUF], *bufp=buf;
239 static void
240 errc(int c){
241 *bufp++=c;
242 if(bufp==&buf[NBUF] || c=='\n'){
243 write(2, buf, bufp-buf);
244 bufp=buf;
248 #ifdef TEST
249 #include <stdio.h>
250 main(int argc, char *argv[])
252 int c, i, n;
253 if(argc<3){
254 fprint(2, "Usage: %s flags cmd ...\n", argv[0]);
255 exits("usage");
257 n=getflags(argc-2, argv+2, argv[1]);
258 if(n<0) usage("...");
259 putchar('\n');
260 for(c=0;c!=128;c++) if(flag[c]){
261 print("\t-.%c. ", c);
262 n=scanflag(c, argv[1]);
263 for(i=0;i!=n;i++) print(" <%s>", flag[c][i]);
264 putchar('\n');
267 #endif