xref: /plan9/sys/src/cmd/rc/getflags.c (revision d3907fe5a68251e8b016f54f72acf8767ba044bb)
13e12c5d1SDavid du Colombier /*% cyntax -DTEST % && cc -DTEST -go # %
23e12c5d1SDavid du Colombier  */
33e12c5d1SDavid du Colombier #include "rc.h"
43e12c5d1SDavid du Colombier #include "getflags.h"
53e12c5d1SDavid du Colombier #include "fns.h"
63e12c5d1SDavid du Colombier char *flagset[] = {"<flag>"};
73e12c5d1SDavid du Colombier char **flag[NFLAG];
83e12c5d1SDavid du Colombier char cmdline[NCMDLINE+1];
93e12c5d1SDavid du Colombier char *cmdname;
103e12c5d1SDavid du Colombier static char *flagarg="";
117dd7cddfSDavid du Colombier static void reverse(char**, char**);
12*d3907fe5SDavid du Colombier static int scanflag(int, char*);
137dd7cddfSDavid du Colombier static void errn(char*, int);
147dd7cddfSDavid du Colombier static void errs(char*);
157dd7cddfSDavid du Colombier static void errc(int);
163e12c5d1SDavid du Colombier static int reason;
173e12c5d1SDavid du Colombier #define	RESET	1
183e12c5d1SDavid du Colombier #define	FEWARGS	2
193e12c5d1SDavid du Colombier #define	FLAGSYN	3
203e12c5d1SDavid du Colombier #define	BADFLAG	4
213e12c5d1SDavid du Colombier static int badflag;
22dc5a79c1SDavid du Colombier 
23dc5a79c1SDavid du Colombier int
24dc5a79c1SDavid du Colombier getflags(int argc, char *argv[], char *flags, int stop)
253e12c5d1SDavid du Colombier {
263e12c5d1SDavid du Colombier 	char *s, *t;
273e12c5d1SDavid du Colombier 	int i, j, c, count;
283e12c5d1SDavid du Colombier 	flagarg = flags;
29dc5a79c1SDavid du Colombier 	if(cmdname==0)
30dc5a79c1SDavid du Colombier 		cmdname = argv[0];
313e12c5d1SDavid du Colombier 	s = cmdline;
323e12c5d1SDavid du Colombier 	for(i = 0;i!=argc;i++){
333e12c5d1SDavid du Colombier 		for(t = argv[i];*t;t++)
343e12c5d1SDavid du Colombier 			if(s!=&cmdline[NCMDLINE])
353e12c5d1SDavid du Colombier 				*s++=*t;
363e12c5d1SDavid du Colombier 		if(i!=argc-1 && s!=&cmdline[NCMDLINE])
373e12c5d1SDavid du Colombier 			*s++=' ';
383e12c5d1SDavid du Colombier 	}
393e12c5d1SDavid du Colombier 	*s='\0';
403e12c5d1SDavid du Colombier 	i = 1;
413e12c5d1SDavid du Colombier 	while(i!=argc){
423e12c5d1SDavid du Colombier 		if(argv[i][0]!='-' || argv[i][1]=='\0'){
43dc5a79c1SDavid du Colombier 			if(stop)
44dc5a79c1SDavid du Colombier 				return argc;
453e12c5d1SDavid du Colombier 			i++;
463e12c5d1SDavid du Colombier 			continue;
473e12c5d1SDavid du Colombier 		}
483e12c5d1SDavid du Colombier 		s = argv[i]+1;
493e12c5d1SDavid du Colombier 		while(*s){
503e12c5d1SDavid du Colombier 			c=*s++;
513e12c5d1SDavid du Colombier 			count = scanflag(c, flags);
52dc5a79c1SDavid du Colombier 			if(count==-1)
53dc5a79c1SDavid du Colombier 				return -1;
543e12c5d1SDavid du Colombier 			if(flag[c]){ reason = RESET; badflag = c; return -1; }
553e12c5d1SDavid du Colombier 			if(count==0){
563e12c5d1SDavid du Colombier 				flag[c] = flagset;
573e12c5d1SDavid du Colombier 				if(*s=='\0'){
583e12c5d1SDavid du Colombier 					for(j = i+1;j<=argc;j++)
593e12c5d1SDavid du Colombier 						argv[j-1] = argv[j];
603e12c5d1SDavid du Colombier 					--argc;
613e12c5d1SDavid du Colombier 				}
623e12c5d1SDavid du Colombier 			}
633e12c5d1SDavid du Colombier 			else{
643e12c5d1SDavid du Colombier 				if(*s=='\0'){
653e12c5d1SDavid du Colombier 					for(j = i+1;j<=argc;j++)
663e12c5d1SDavid du Colombier 						argv[j-1] = argv[j];
673e12c5d1SDavid du Colombier 					--argc;
683e12c5d1SDavid du Colombier 					s = argv[i];
693e12c5d1SDavid du Colombier 				}
703e12c5d1SDavid du Colombier 				if(argc-i<count){
713e12c5d1SDavid du Colombier 					reason = FEWARGS;
723e12c5d1SDavid du Colombier 					badflag = c;
733e12c5d1SDavid du Colombier 					return -1;
743e12c5d1SDavid du Colombier 				}
753e12c5d1SDavid du Colombier 				reverse(argv+i, argv+argc);
763e12c5d1SDavid du Colombier 				reverse(argv+i, argv+argc-count);
773e12c5d1SDavid du Colombier 				reverse(argv+argc-count+1, argv+argc);
783e12c5d1SDavid du Colombier 				argc-=count;
793e12c5d1SDavid du Colombier 				flag[c] = argv+argc+1;
803e12c5d1SDavid du Colombier 				flag[c][0] = s;
813e12c5d1SDavid du Colombier 				s="";
823e12c5d1SDavid du Colombier 			}
833e12c5d1SDavid du Colombier 		}
843e12c5d1SDavid du Colombier 	}
853e12c5d1SDavid du Colombier 	return argc;
863e12c5d1SDavid du Colombier }
87dc5a79c1SDavid du Colombier 
88dc5a79c1SDavid du Colombier static void
89dc5a79c1SDavid du Colombier reverse(char **p, char **q)
903e12c5d1SDavid du Colombier {
913e12c5d1SDavid du Colombier 	char *t;
923e12c5d1SDavid du Colombier 	for(;p<q;p++,--q){ t=*p; *p=*q; *q = t; }
933e12c5d1SDavid du Colombier }
94dc5a79c1SDavid du Colombier 
95*d3907fe5SDavid du Colombier static int
96dc5a79c1SDavid du Colombier scanflag(int c, char *f)
973e12c5d1SDavid du Colombier {
983e12c5d1SDavid du Colombier 	int fc, count;
99dc5a79c1SDavid du Colombier 	if(0<=c && c<NFLAG)
100dc5a79c1SDavid du Colombier 		while(*f){
1013e12c5d1SDavid du Colombier 			if(*f==' '){
1023e12c5d1SDavid du Colombier 				f++;
1033e12c5d1SDavid du Colombier 				continue;
1043e12c5d1SDavid du Colombier 			}
1053e12c5d1SDavid du Colombier 			fc=*f++;
1063e12c5d1SDavid du Colombier 			if(*f==':'){
1073e12c5d1SDavid du Colombier 				f++;
1083e12c5d1SDavid du Colombier 				if(*f<'0' || '9'<*f){ reason = FLAGSYN; return -1; }
1093e12c5d1SDavid du Colombier 				count = 0;
1103e12c5d1SDavid du Colombier 				while('0'<=*f && *f<='9') count = count*10+*f++-'0';
1113e12c5d1SDavid du Colombier 			}
1123e12c5d1SDavid du Colombier 			else
1133e12c5d1SDavid du Colombier 				count = 0;
1143e12c5d1SDavid du Colombier 			if(*f=='['){
1153e12c5d1SDavid du Colombier 				do{
1163e12c5d1SDavid du Colombier 					f++;
1173e12c5d1SDavid du Colombier 					if(*f=='\0'){ reason = FLAGSYN; return -1; }
1183e12c5d1SDavid du Colombier 				}while(*f!=']');
1193e12c5d1SDavid du Colombier 				f++;
1203e12c5d1SDavid du Colombier 			}
121dc5a79c1SDavid du Colombier 			if(c==fc)
122dc5a79c1SDavid du Colombier 				return count;
1233e12c5d1SDavid du Colombier 		}
1243e12c5d1SDavid du Colombier 	reason = BADFLAG;
1253e12c5d1SDavid du Colombier 	badflag = c;
1263e12c5d1SDavid du Colombier 	return -1;
1273e12c5d1SDavid du Colombier }
128dc5a79c1SDavid du Colombier 
129dc5a79c1SDavid du Colombier void
130dc5a79c1SDavid du Colombier usage(char *tail)
1313e12c5d1SDavid du Colombier {
1323e12c5d1SDavid du Colombier 	char *s, *t, c;
1333e12c5d1SDavid du Colombier 	int count, nflag = 0;
1343e12c5d1SDavid du Colombier 	switch(reason){
1353e12c5d1SDavid du Colombier 	case RESET:
1363e12c5d1SDavid du Colombier 		errs("Flag -");
1373e12c5d1SDavid du Colombier 		errc(badflag);
1383e12c5d1SDavid du Colombier 		errs(": set twice\n");
1393e12c5d1SDavid du Colombier 		break;
1403e12c5d1SDavid du Colombier 	case FEWARGS:
1413e12c5d1SDavid du Colombier 		errs("Flag -");
1423e12c5d1SDavid du Colombier 		errc(badflag);
1433e12c5d1SDavid du Colombier 		errs(": too few arguments\n");
1443e12c5d1SDavid du Colombier 		break;
1453e12c5d1SDavid du Colombier 	case FLAGSYN:
1463e12c5d1SDavid du Colombier 		errs("Bad argument to getflags!\n");
1473e12c5d1SDavid du Colombier 		break;
1483e12c5d1SDavid du Colombier 	case BADFLAG:
1493e12c5d1SDavid du Colombier 		errs("Illegal flag -");
1503e12c5d1SDavid du Colombier 		errc(badflag);
1513e12c5d1SDavid du Colombier 		errc('\n');
1523e12c5d1SDavid du Colombier 		break;
1533e12c5d1SDavid du Colombier 	}
1543e12c5d1SDavid du Colombier 	errs("Usage: ");
1553e12c5d1SDavid du Colombier 	errs(cmdname);
1563e12c5d1SDavid du Colombier 	for(s = flagarg;*s;){
1573e12c5d1SDavid du Colombier 		c=*s;
158dc5a79c1SDavid du Colombier 		if(*s++==' ')
159dc5a79c1SDavid du Colombier 			continue;
1603e12c5d1SDavid du Colombier 		if(*s==':'){
1613e12c5d1SDavid du Colombier 			s++;
1623e12c5d1SDavid du Colombier 			count = 0;
1633e12c5d1SDavid du Colombier 			while('0'<=*s && *s<='9') count = count*10+*s++-'0';
1643e12c5d1SDavid du Colombier 		}
1653e12c5d1SDavid du Colombier 		else count = 0;
1663e12c5d1SDavid du Colombier 		if(count==0){
167dc5a79c1SDavid du Colombier 			if(nflag==0)
168dc5a79c1SDavid du Colombier 				errs(" [-");
1693e12c5d1SDavid du Colombier 			nflag++;
1703e12c5d1SDavid du Colombier 			errc(c);
1713e12c5d1SDavid du Colombier 		}
1723e12c5d1SDavid du Colombier 		if(*s=='['){
1733e12c5d1SDavid du Colombier 			s++;
1743e12c5d1SDavid du Colombier 			while(*s!=']' && *s!='\0') s++;
175dc5a79c1SDavid du Colombier 			if(*s==']')
176dc5a79c1SDavid du Colombier 				s++;
1773e12c5d1SDavid du Colombier 		}
1783e12c5d1SDavid du Colombier 	}
179dc5a79c1SDavid du Colombier 	if(nflag)
180dc5a79c1SDavid du Colombier 		errs("]");
1813e12c5d1SDavid du Colombier 	for(s = flagarg;*s;){
1823e12c5d1SDavid du Colombier 		c=*s;
183dc5a79c1SDavid du Colombier 		if(*s++==' ')
184dc5a79c1SDavid du Colombier 			continue;
1853e12c5d1SDavid du Colombier 		if(*s==':'){
1863e12c5d1SDavid du Colombier 			s++;
1873e12c5d1SDavid du Colombier 			count = 0;
1883e12c5d1SDavid du Colombier 			while('0'<=*s && *s<='9') count = count*10+*s++-'0';
1893e12c5d1SDavid du Colombier 		}
1903e12c5d1SDavid du Colombier 		else count = 0;
1913e12c5d1SDavid du Colombier 		if(count!=0){
1923e12c5d1SDavid du Colombier 			errs(" [-");
1933e12c5d1SDavid du Colombier 			errc(c);
1943e12c5d1SDavid du Colombier 			if(*s=='['){
1953e12c5d1SDavid du Colombier 				s++;
1963e12c5d1SDavid du Colombier 				t = s;
1973e12c5d1SDavid du Colombier 				while(*s!=']' && *s!='\0') s++;
1983e12c5d1SDavid du Colombier 				errs(" ");
1993e12c5d1SDavid du Colombier 				errn(t, s-t);
200dc5a79c1SDavid du Colombier 				if(*s==']')
201dc5a79c1SDavid du Colombier 					s++;
2023e12c5d1SDavid du Colombier 			}
2033e12c5d1SDavid du Colombier 			else
2043e12c5d1SDavid du Colombier 				while(count--) errs(" arg");
2053e12c5d1SDavid du Colombier 			errs("]");
2063e12c5d1SDavid du Colombier 		}
2073e12c5d1SDavid du Colombier 		else if(*s=='['){
2083e12c5d1SDavid du Colombier 			s++;
2093e12c5d1SDavid du Colombier 			while(*s!=']' && *s!='\0') s++;
210dc5a79c1SDavid du Colombier 			if(*s==']')
211dc5a79c1SDavid du Colombier 				s++;
2123e12c5d1SDavid du Colombier 		}
2133e12c5d1SDavid du Colombier 	}
2143e12c5d1SDavid du Colombier 	if(tail){
2153e12c5d1SDavid du Colombier 		errs(" ");
2163e12c5d1SDavid du Colombier 		errs(tail);
2173e12c5d1SDavid du Colombier 	}
2183e12c5d1SDavid du Colombier 	errs("\n");
2193e12c5d1SDavid du Colombier 	Exit("bad flags");
2203e12c5d1SDavid du Colombier }
221dc5a79c1SDavid du Colombier 
222dc5a79c1SDavid du Colombier static void
223dc5a79c1SDavid du Colombier errn(char *s, int count)
2243e12c5d1SDavid du Colombier {
2253e12c5d1SDavid du Colombier 	while(count){ errc(*s++); --count; }
2263e12c5d1SDavid du Colombier }
227dc5a79c1SDavid du Colombier 
228dc5a79c1SDavid du Colombier static void
229dc5a79c1SDavid du Colombier errs(char *s)
2303e12c5d1SDavid du Colombier {
2313e12c5d1SDavid du Colombier 	while(*s) errc(*s++);
2323e12c5d1SDavid du Colombier }
2333e12c5d1SDavid du Colombier #define	NBUF	80
2343e12c5d1SDavid du Colombier static char buf[NBUF], *bufp = buf;
235dc5a79c1SDavid du Colombier 
236dc5a79c1SDavid du Colombier static void
237dc5a79c1SDavid du Colombier errc(int c)
238dc5a79c1SDavid du Colombier {
2393e12c5d1SDavid du Colombier 	*bufp++=c;
2403e12c5d1SDavid du Colombier 	if(bufp==&buf[NBUF] || c=='\n'){
2413e12c5d1SDavid du Colombier 		Write(2, buf, bufp-buf);
2423e12c5d1SDavid du Colombier 		bufp = buf;
2433e12c5d1SDavid du Colombier 	}
2443e12c5d1SDavid du Colombier }
245