xref: /plan9/sys/src/cmd/rc/getflags.c (revision 219b2ee8daee37f4aad58d63f21287faa8e4ffdc)
1 /*% cyntax -DTEST % && cc -DTEST -go # %
2  */
3 #include "rc.h"
4 #include "getflags.h"
5 #include "fns.h"
6 char *flagset[]={"<flag>"};
7 char **flag[NFLAG];
8 char cmdline[NCMDLINE+1];
9 char *cmdname;
10 static char *flagarg="";
11 static reverse(char**, char**);
12 static scanflag(int, char*);
13 static errn(char*, int);
14 static errs(char*);
15 static errc(int);
16 static int reason;
17 #define	RESET	1
18 #define	FEWARGS	2
19 #define	FLAGSYN	3
20 #define	BADFLAG	4
21 static int badflag;
22 int getflags(int argc, char *argv[], char *flags, int stop)
23 {
24 	char *s, *t;
25 	int i, j, c, count;
26 	flagarg=flags;
27 	if(cmdname==0) cmdname=argv[0];
28 	s=cmdline;
29 	for(i=0;i!=argc;i++){
30 		for(t=argv[i];*t;t++)
31 			if(s!=&cmdline[NCMDLINE])
32 				*s++=*t;
33 		if(i!=argc-1 && s!=&cmdline[NCMDLINE])
34 			*s++=' ';
35 	}
36 	*s='\0';
37 	i=1;
38 	while(i!=argc){
39 		if(argv[i][0]!='-' || argv[i][1]=='\0'){
40 			if(stop) return argc;
41 			i++;
42 			continue;
43 		}
44 		s=argv[i]+1;
45 		while(*s){
46 			c=*s++;
47 			count=scanflag(c, flags);
48 			if(count==-1) return -1;
49 			if(flag[c]){ reason=RESET; badflag=c; return -1; }
50 			if(count==0){
51 				flag[c]=flagset;
52 				if(*s=='\0'){
53 					for(j=i+1;j<=argc;j++)
54 						argv[j-1]=argv[j];
55 					--argc;
56 				}
57 			}
58 			else{
59 				if(*s=='\0'){
60 					for(j=i+1;j<=argc;j++)
61 						argv[j-1]=argv[j];
62 					--argc;
63 					s=argv[i];
64 				}
65 				if(argc-i<count){
66 					reason=FEWARGS;
67 					badflag=c;
68 					return -1;
69 				}
70 				reverse(argv+i, argv+argc);
71 				reverse(argv+i, argv+argc-count);
72 				reverse(argv+argc-count+1, argv+argc);
73 				argc-=count;
74 				flag[c]=argv+argc+1;
75 				flag[c][0]=s;
76 				s="";
77 			}
78 		}
79 	}
80 	return argc;
81 }
82 static reverse(char **p, char **q)
83 {
84 	char *t;
85 	for(;p<q;p++,--q){ t=*p; *p=*q; *q=t; }
86 }
87 static scanflag(int c, char *f)
88 {
89 	int fc, count;
90 	if(0<=c && c<NFLAG) while(*f){
91 		if(*f==' '){
92 			f++;
93 			continue;
94 		}
95 		fc=*f++;
96 		if(*f==':'){
97 			f++;
98 			if(*f<'0' || '9'<*f){ reason=FLAGSYN; return -1; }
99 			count=0;
100 			while('0'<=*f && *f<='9') count=count*10+*f++-'0';
101 		}
102 		else
103 			count=0;
104 		if(*f=='['){
105 			do{
106 				f++;
107 				if(*f=='\0'){ reason=FLAGSYN; return -1; }
108 			}while(*f!=']');
109 			f++;
110 		}
111 		if(c==fc) return count;
112 	}
113 	reason=BADFLAG;
114 	badflag=c;
115 	return -1;
116 }
117 void usage(char *tail)
118 {
119 	char *s, *t, c;
120 	int count, nflag=0;
121 	switch(reason){
122 	case RESET:
123 		errs("Flag -");
124 		errc(badflag);
125 		errs(": set twice\n");
126 		break;
127 	case FEWARGS:
128 		errs("Flag -");
129 		errc(badflag);
130 		errs(": too few arguments\n");
131 		break;
132 	case FLAGSYN:
133 		errs("Bad argument to getflags!\n");
134 		break;
135 	case BADFLAG:
136 		errs("Illegal flag -");
137 		errc(badflag);
138 		errc('\n');
139 		break;
140 	}
141 	errs("Usage: ");
142 	errs(cmdname);
143 	for(s=flagarg;*s;){
144 		c=*s;
145 		if(*s++==' ') continue;
146 		if(*s==':'){
147 			s++;
148 			count=0;
149 			while('0'<=*s && *s<='9') count=count*10+*s++-'0';
150 		}
151 		else count=0;
152 		if(count==0){
153 			if(nflag==0) errs(" [-");
154 			nflag++;
155 			errc(c);
156 		}
157 		if(*s=='['){
158 			s++;
159 			while(*s!=']' && *s!='\0') s++;
160 			if(*s==']') s++;
161 		}
162 	}
163 	if(nflag) errs("]");
164 	for(s=flagarg;*s;){
165 		c=*s;
166 		if(*s++==' ') continue;
167 		if(*s==':'){
168 			s++;
169 			count=0;
170 			while('0'<=*s && *s<='9') count=count*10+*s++-'0';
171 		}
172 		else count=0;
173 		if(count!=0){
174 			errs(" [-");
175 			errc(c);
176 			if(*s=='['){
177 				s++;
178 				t=s;
179 				while(*s!=']' && *s!='\0') s++;
180 				errs(" ");
181 				errn(t, s-t);
182 				if(*s==']') s++;
183 			}
184 			else
185 				while(count--) errs(" arg");
186 			errs("]");
187 		}
188 		else if(*s=='['){
189 			s++;
190 			while(*s!=']' && *s!='\0') s++;
191 			if(*s==']') s++;
192 		}
193 	}
194 	if(tail){
195 		errs(" ");
196 		errs(tail);
197 	}
198 	errs("\n");
199 	Exit("bad flags");
200 }
201 static errn(char *s, int count)
202 {
203 	while(count){ errc(*s++); --count; }
204 }
205 static errs(char *s)
206 {
207 	while(*s) errc(*s++);
208 }
209 #define	NBUF	80
210 static char buf[NBUF], *bufp=buf;
211 static errc(int c){
212 	*bufp++=c;
213 	if(bufp==&buf[NBUF] || c=='\n'){
214 		Write(2, buf, bufp-buf);
215 		bufp=buf;
216 	}
217 }
218