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