diff -r 3ea4e7930c5b -r 5fd153b29d40 optparser.c --- a/optparser.c Sat May 20 17:43:36 2000 +0200 +++ b/optparser.c Sun May 21 17:33:48 2000 +0200 @@ -19,6 +19,25 @@ #define O_OPT_ARG(o) (O_ARGS(o)==OPT_OPT_ARG) #define O_ID(o) (o->optid) +#define OPT_ID_HELP OPT_ID_RESERVED('h') +#define OPT_ID_VERSION OPT_ID_RESERVED('V') +#define OPT_ID_ABOUT OPT_ID_RESERVED('a'|OPT_ID_NOSHORT_FLAG) + + +static OptParserOpt common_opts[]={ + {OPT_ID_HELP, "help", 0, NULL, DUMMY_TR("Show this help")}, + {OPT_ID_VERSION, "version", 0, NULL, DUMMY_TR("Show program version")}, + {OPT_ID_ABOUT, "about", 0, NULL, DUMMY_TR("Show about text")}, + {0, NULL, 0, NULL, NULL} +}; + + +static OptParserCommonInfo dummy_cinfo[]={ + NULL, /* version */ + "Usage: $p\n", /* usage_tmpl */ + NULL /* about */ +}; + static const OptParserOpt *o_opts=NULL; static char *const *o_current=NULL; @@ -28,21 +47,30 @@ static const char*o_tmp=NULL; static int o_error=0; static int o_mode=OPTP_CHAIN; +static const OptParserCommonInfo *o_cinfo=NULL; + + +/* */ + + +static void print_help(const OptParserOpt *opts, bool midlong, + const OptParserCommonInfo *cinfo); /* */ void optparser_init(int argc, char *const argv[], int mode, - const OptParserOpt *opts) + const OptParserOpt *opts, const OptParserCommonInfo *cinfo) { o_mode=mode; - o_opts=opts; + o_opts=(opts==NULL ? common_opts : opts); o_current=argv+1; o_left=argc-1; o_chain_ptr=NULL; o_args_left=0; o_tmp=NULL; + o_cinfo=(cinfo==NULL ? dummy_cinfo : cinfo); } @@ -52,7 +80,7 @@ static const OptParserOpt *find_chain_opt(char p, const OptParserOpt *o) { for(;O_ID(o);o++){ - if(O_ID(o)==p) + if((O_ID(o)&~OPT_ID_RESERVED_FLAG)==p) return o; } return NULL; @@ -80,7 +108,7 @@ }; -int optparser_get_opt() +static int optparser_do_get_opt() { #define RET(X) return o_tmp=p, o_error=X const char *p, *p2=NULL; @@ -143,7 +171,7 @@ o=o_opts; again: - for(;O_ID(o);o++){ + for(; O_ID(o); o++){ if(type==LONG){ /* Do long option (--foo=bar) */ if(o->longopt==NULL) @@ -173,7 +201,7 @@ if(strcmp(p2, o->longopt)!=0) continue; }else{ /* type==SHORT */ - if(*p2!=O_ID(o)) + if(*p2!=(O_ID(o)&~OPT_ID_RESERVED_FLAG)) continue; if(*(p2+1)!='\0'){ @@ -212,6 +240,11 @@ o_args_left=1; return O_ID(o); } + + if(o!=&(common_opts[3])){ + o=common_opts; + goto again; + } if(dash) RET(E_OPT_INVALID_OPTION); @@ -221,6 +254,33 @@ } +int optparser_get_opt() +{ + int oid=optparser_do_get_opt(); + + if(oid<=0 || (oid&OPT_ID_RESERVED_FLAG)==0) + return oid; + + switch(oid){ + case OPT_ID_ABOUT: + if(o_cinfo->about!=NULL) + printf("%s", o_cinfo->about); + break; + + case OPT_ID_VERSION: + if(o_cinfo->version!=NULL) + printf("%s\n", o_cinfo->version); + break; + + case OPT_ID_HELP: + print_help(o_opts, o_mode==OPTP_MIDLONG, o_cinfo); + break; + } + + exit(EXIT_SUCCESS); +} + + /* */ @@ -302,3 +362,211 @@ o_tmp=NULL; o_error=0; } + + +/* */ + + +static uint opt_w(const OptParserOpt *opt, bool midlong) +{ + uint w=0; + + if((opt->optid&OPT_ID_NOSHORT_FLAG)==0){ + w+=2; /* "-o" */ + if(opt->longopt!=NULL) + w+=2; /* ", " */ + } + + if(opt->longopt!=NULL) + w+=strlen(opt->longopt)+(midlong ? 1 : 2); + + if(O_ARGS(opt)){ + if(opt->argname==NULL) + w+=4; + else + w+=1+strlen(opt->argname); /* "=ARG" or " ARG" */ + + if(O_OPT_ARG(opt)) + w+=2; /* [ARG] */ + } + + return w; +} + + +#define TERM_W 80 +#define OFF1 2 +#define OFF2 2 +#define SPACER1 " " +#define SPACER2 " " + +static void print_opt(const OptParserOpt *opt, bool midlong, + uint maxw, uint tw) +{ + FILE *f=stdout; + const char *p, *p2, *p3; + uint w=0; + + fprintf(f, SPACER1); + + /* short opt */ + + if((O_ID(opt)&OPT_ID_NOSHORT_FLAG)==0){ + fprintf(f, "-%c", O_ID(opt)&~OPT_ID_RESERVED_FLAG); + w+=2; + + if(opt->longopt!=NULL){ + fprintf(f, ", "); + w+=2; + } + } + + /* long opt */ + + if(opt->longopt!=NULL){ + if(midlong){ + w++; + fprintf(f, "-%s", opt->longopt); + }else{ + w+=2; + fprintf(f, "--%s", opt->longopt); + } + w+=strlen(opt->longopt); + } + + /* arg */ + + if(O_ARGS(opt)){ + w++; + if(opt->longopt!=NULL && !midlong) + putc('=', f); + else + putc(' ', f); + + if(O_OPT_ARG(opt)){ + w+=2; + putc('[', f); + } + + if(opt->argname!=NULL){ + fprintf(f, "%s", opt->argname); + w+=strlen(opt->argname); + }else{ + w+=3; + fprintf(f, "ARG"); + } + + if(O_OPT_ARG(opt)) + putc(']', f); + } + + while(w++descr; + + if(p==NULL){ + putc('\n', f); + return; + } + + fprintf(f, SPACER2); + + maxw+=OFF1+OFF2; + tw-=maxw; + + while(strlen(p)>tw){ + p3=p2=p+tw-2; + + while(*p2!=' ' && p2!=p) + p2--; + + while(*p3!=' ' && *p3!='\0') + p3++; + + if((uint)(p3-p2)>tw){ + /* long word - just wrap */ + p2=p+tw-2; + } + + writef(f, p, p2-p); + if(*p2==' ') + putc('\n', f); + else + fprintf(f, "\\\n"); + + p=p2+1; + + w=maxw; + while(w--) + putc(' ', f); + } + + fprintf(f, "%s\n", p); +} + + +static void print_opts(const OptParserOpt *opts, bool midlong, + const OptParserCommonInfo *cinfo) +{ + uint w, maxw=0; + const OptParserOpt *o; + + o=opts; +again: + for(; O_ID(o); o++){ + w=opt_w(o, midlong); + if(w>maxw) + maxw=w; + } + + if(o!=&(common_opts[3])){ + o=common_opts; + goto again; + } + + o=opts; +again2: + for(; O_ID(o); o++) + print_opt(o, midlong, maxw, TERM_W); + + if(o!=&(common_opts[3])){ + printf("\n"); + o=common_opts; + goto again2; + } +} + + +static void print_help(const OptParserOpt *opts, bool midlong, + const OptParserCommonInfo *cinfo) +{ + const char *tmp, *p=cinfo->usage_tmpl; + size_t len; + size_t start; + + while(1){ + tmp=strchr(p, '$'); + + if(tmp==NULL){ + writef(stdout, p, strlen(p)); + return; + } + + if(tmp!=p) + writef(stdout, p, tmp-p); + + p=tmp+1; + + if(*p=='p'){ + tmp=prog_execname(); + writef(stdout, tmp, strlen(tmp)); + }else if(*p=='o'){ + print_opts(opts, midlong, cinfo); + } + p++; + } +} +