9base

revived minimalist port of Plan 9 userland to Unix
git clone git://git.suckless.org/9base
Log | Files | Refs | README | LICENSE

getflags.c (3962B)


      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 }