funcgetflags.c 4.5 KB

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