| 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 |
| 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 |