optparser.c

changeset 12
5fd153b29d40
parent 9
55e7f2ff6021
child 19
3e498ec7abcd
equal deleted inserted replaced
11:3ea4e7930c5b 12:5fd153b29d40
17 #define O_ARGS(o) (o->flags&OPT_OPT_ARG) 17 #define O_ARGS(o) (o->flags&OPT_OPT_ARG)
18 #define O_ARG(o) (o->flasg&OPT_ARG) 18 #define O_ARG(o) (o->flasg&OPT_ARG)
19 #define O_OPT_ARG(o) (O_ARGS(o)==OPT_OPT_ARG) 19 #define O_OPT_ARG(o) (O_ARGS(o)==OPT_OPT_ARG)
20 #define O_ID(o) (o->optid) 20 #define O_ID(o) (o->optid)
21 21
22 #define OPT_ID_HELP OPT_ID_RESERVED('h')
23 #define OPT_ID_VERSION OPT_ID_RESERVED('V')
24 #define OPT_ID_ABOUT OPT_ID_RESERVED('a'|OPT_ID_NOSHORT_FLAG)
25
26
27 static OptParserOpt common_opts[]={
28 {OPT_ID_HELP, "help", 0, NULL, DUMMY_TR("Show this help")},
29 {OPT_ID_VERSION, "version", 0, NULL, DUMMY_TR("Show program version")},
30 {OPT_ID_ABOUT, "about", 0, NULL, DUMMY_TR("Show about text")},
31 {0, NULL, 0, NULL, NULL}
32 };
33
34
35 static OptParserCommonInfo dummy_cinfo[]={
36 NULL, /* version */
37 "Usage: $p\n", /* usage_tmpl */
38 NULL /* about */
39 };
40
22 41
23 static const OptParserOpt *o_opts=NULL; 42 static const OptParserOpt *o_opts=NULL;
24 static char *const *o_current=NULL; 43 static char *const *o_current=NULL;
25 static int o_left=0; 44 static int o_left=0;
26 static const char* o_chain_ptr=NULL; 45 static const char* o_chain_ptr=NULL;
27 static int o_args_left=0; 46 static int o_args_left=0;
28 static const char*o_tmp=NULL; 47 static const char*o_tmp=NULL;
29 static int o_error=0; 48 static int o_error=0;
30 static int o_mode=OPTP_CHAIN; 49 static int o_mode=OPTP_CHAIN;
50 static const OptParserCommonInfo *o_cinfo=NULL;
51
52
53 /* */
54
55
56 static void print_help(const OptParserOpt *opts, bool midlong,
57 const OptParserCommonInfo *cinfo);
31 58
32 59
33 /* */ 60 /* */
34 61
35 62
36 void optparser_init(int argc, char *const argv[], int mode, 63 void optparser_init(int argc, char *const argv[], int mode,
37 const OptParserOpt *opts) 64 const OptParserOpt *opts, const OptParserCommonInfo *cinfo)
38 { 65 {
39 o_mode=mode; 66 o_mode=mode;
40 o_opts=opts; 67 o_opts=(opts==NULL ? common_opts : opts);
41 o_current=argv+1; 68 o_current=argv+1;
42 o_left=argc-1; 69 o_left=argc-1;
43 o_chain_ptr=NULL; 70 o_chain_ptr=NULL;
44 o_args_left=0; 71 o_args_left=0;
45 o_tmp=NULL; 72 o_tmp=NULL;
73 o_cinfo=(cinfo==NULL ? dummy_cinfo : cinfo);
46 } 74 }
47 75
48 76
49 /* */ 77 /* */
50 78
51 79
52 static const OptParserOpt *find_chain_opt(char p, const OptParserOpt *o) 80 static const OptParserOpt *find_chain_opt(char p, const OptParserOpt *o)
53 { 81 {
54 for(;O_ID(o);o++){ 82 for(;O_ID(o);o++){
55 if(O_ID(o)==p) 83 if((O_ID(o)&~OPT_ID_RESERVED_FLAG)==p)
56 return o; 84 return o;
57 } 85 }
58 return NULL; 86 return NULL;
59 } 87 }
60 88
78 enum{ 106 enum{
79 SHORT, MIDLONG, LONG 107 SHORT, MIDLONG, LONG
80 }; 108 };
81 109
82 110
83 int optparser_get_opt() 111 static int optparser_do_get_opt()
84 { 112 {
85 #define RET(X) return o_tmp=p, o_error=X 113 #define RET(X) return o_tmp=p, o_error=X
86 const char *p, *p2=NULL; 114 const char *p, *p2=NULL;
87 bool dash=TRUE; 115 bool dash=TRUE;
88 int type=SHORT; 116 int type=SHORT;
141 } 169 }
142 170
143 o=o_opts; 171 o=o_opts;
144 172
145 again: 173 again:
146 for(;O_ID(o);o++){ 174 for(; O_ID(o); o++){
147 if(type==LONG){ 175 if(type==LONG){
148 /* Do long option (--foo=bar) */ 176 /* Do long option (--foo=bar) */
149 if(o->longopt==NULL) 177 if(o->longopt==NULL)
150 continue; 178 continue;
151 l=strlen(o->longopt); 179 l=strlen(o->longopt);
171 continue; 199 continue;
172 200
173 if(strcmp(p2, o->longopt)!=0) 201 if(strcmp(p2, o->longopt)!=0)
174 continue; 202 continue;
175 }else{ /* type==SHORT */ 203 }else{ /* type==SHORT */
176 if(*p2!=O_ID(o)) 204 if(*p2!=(O_ID(o)&~OPT_ID_RESERVED_FLAG))
177 continue; 205 continue;
178 206
179 if(*(p2+1)!='\0'){ 207 if(*(p2+1)!='\0'){
180 if(o_mode==OPTP_CHAIN || o_mode==OPTP_NO_DASH){ 208 if(o_mode==OPTP_CHAIN || o_mode==OPTP_NO_DASH){
181 /*valid_chain(p2+1, o_opts)*/ 209 /*valid_chain(p2+1, o_opts)*/
210 } 238 }
211 239
212 o_args_left=1; 240 o_args_left=1;
213 return O_ID(o); 241 return O_ID(o);
214 } 242 }
243
244 if(o!=&(common_opts[3])){
245 o=common_opts;
246 goto again;
247 }
215 248
216 if(dash) 249 if(dash)
217 RET(E_OPT_INVALID_OPTION); 250 RET(E_OPT_INVALID_OPTION);
218 251
219 RET(OPT_ID_ARGUMENT); 252 RET(OPT_ID_ARGUMENT);
220 #undef RET 253 #undef RET
254 }
255
256
257 int optparser_get_opt()
258 {
259 int oid=optparser_do_get_opt();
260
261 if(oid<=0 || (oid&OPT_ID_RESERVED_FLAG)==0)
262 return oid;
263
264 switch(oid){
265 case OPT_ID_ABOUT:
266 if(o_cinfo->about!=NULL)
267 printf("%s", o_cinfo->about);
268 break;
269
270 case OPT_ID_VERSION:
271 if(o_cinfo->version!=NULL)
272 printf("%s\n", o_cinfo->version);
273 break;
274
275 case OPT_ID_HELP:
276 print_help(o_opts, o_mode==OPTP_MIDLONG, o_cinfo);
277 break;
278 }
279
280 exit(EXIT_SUCCESS);
221 } 281 }
222 282
223 283
224 /* */ 284 /* */
225 285
300 } 360 }
301 361
302 o_tmp=NULL; 362 o_tmp=NULL;
303 o_error=0; 363 o_error=0;
304 } 364 }
365
366
367 /* */
368
369
370 static uint opt_w(const OptParserOpt *opt, bool midlong)
371 {
372 uint w=0;
373
374 if((opt->optid&OPT_ID_NOSHORT_FLAG)==0){
375 w+=2; /* "-o" */
376 if(opt->longopt!=NULL)
377 w+=2; /* ", " */
378 }
379
380 if(opt->longopt!=NULL)
381 w+=strlen(opt->longopt)+(midlong ? 1 : 2);
382
383 if(O_ARGS(opt)){
384 if(opt->argname==NULL)
385 w+=4;
386 else
387 w+=1+strlen(opt->argname); /* "=ARG" or " ARG" */
388
389 if(O_OPT_ARG(opt))
390 w+=2; /* [ARG] */
391 }
392
393 return w;
394 }
395
396
397 #define TERM_W 80
398 #define OFF1 2
399 #define OFF2 2
400 #define SPACER1 " "
401 #define SPACER2 " "
402
403 static void print_opt(const OptParserOpt *opt, bool midlong,
404 uint maxw, uint tw)
405 {
406 FILE *f=stdout;
407 const char *p, *p2, *p3;
408 uint w=0;
409
410 fprintf(f, SPACER1);
411
412 /* short opt */
413
414 if((O_ID(opt)&OPT_ID_NOSHORT_FLAG)==0){
415 fprintf(f, "-%c", O_ID(opt)&~OPT_ID_RESERVED_FLAG);
416 w+=2;
417
418 if(opt->longopt!=NULL){
419 fprintf(f, ", ");
420 w+=2;
421 }
422 }
423
424 /* long opt */
425
426 if(opt->longopt!=NULL){
427 if(midlong){
428 w++;
429 fprintf(f, "-%s", opt->longopt);
430 }else{
431 w+=2;
432 fprintf(f, "--%s", opt->longopt);
433 }
434 w+=strlen(opt->longopt);
435 }
436
437 /* arg */
438
439 if(O_ARGS(opt)){
440 w++;
441 if(opt->longopt!=NULL && !midlong)
442 putc('=', f);
443 else
444 putc(' ', f);
445
446 if(O_OPT_ARG(opt)){
447 w+=2;
448 putc('[', f);
449 }
450
451 if(opt->argname!=NULL){
452 fprintf(f, "%s", opt->argname);
453 w+=strlen(opt->argname);
454 }else{
455 w+=3;
456 fprintf(f, "ARG");
457 }
458
459 if(O_OPT_ARG(opt))
460 putc(']', f);
461 }
462
463 while(w++<maxw)
464 putc(' ', f);
465
466 /* descr */
467
468 p=p2=opt->descr;
469
470 if(p==NULL){
471 putc('\n', f);
472 return;
473 }
474
475 fprintf(f, SPACER2);
476
477 maxw+=OFF1+OFF2;
478 tw-=maxw;
479
480 while(strlen(p)>tw){
481 p3=p2=p+tw-2;
482
483 while(*p2!=' ' && p2!=p)
484 p2--;
485
486 while(*p3!=' ' && *p3!='\0')
487 p3++;
488
489 if((uint)(p3-p2)>tw){
490 /* long word - just wrap */
491 p2=p+tw-2;
492 }
493
494 writef(f, p, p2-p);
495 if(*p2==' ')
496 putc('\n', f);
497 else
498 fprintf(f, "\\\n");
499
500 p=p2+1;
501
502 w=maxw;
503 while(w--)
504 putc(' ', f);
505 }
506
507 fprintf(f, "%s\n", p);
508 }
509
510
511 static void print_opts(const OptParserOpt *opts, bool midlong,
512 const OptParserCommonInfo *cinfo)
513 {
514 uint w, maxw=0;
515 const OptParserOpt *o;
516
517 o=opts;
518 again:
519 for(; O_ID(o); o++){
520 w=opt_w(o, midlong);
521 if(w>maxw)
522 maxw=w;
523 }
524
525 if(o!=&(common_opts[3])){
526 o=common_opts;
527 goto again;
528 }
529
530 o=opts;
531 again2:
532 for(; O_ID(o); o++)
533 print_opt(o, midlong, maxw, TERM_W);
534
535 if(o!=&(common_opts[3])){
536 printf("\n");
537 o=common_opts;
538 goto again2;
539 }
540 }
541
542
543 static void print_help(const OptParserOpt *opts, bool midlong,
544 const OptParserCommonInfo *cinfo)
545 {
546 const char *tmp, *p=cinfo->usage_tmpl;
547 size_t len;
548 size_t start;
549
550 while(1){
551 tmp=strchr(p, '$');
552
553 if(tmp==NULL){
554 writef(stdout, p, strlen(p));
555 return;
556 }
557
558 if(tmp!=p)
559 writef(stdout, p, tmp-p);
560
561 p=tmp+1;
562
563 if(*p=='p'){
564 tmp=prog_execname();
565 writef(stdout, tmp, strlen(tmp));
566 }else if(*p=='o'){
567 print_opts(opts, midlong, cinfo);
568 }
569 p++;
570 }
571 }
572

mercurial