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 |