Sun, 21 May 2000 17:33:48 +0200
trunk: changeset 15
- Optparser generates --help from option descriptions in the
OptParserOpt structure
- Changed the options --license, --authors and --proginfo to single
--about
include/libtu/optparser.h | file | annotate | diff | comparison | revisions | |
include/libtu/util.h | file | annotate | diff | comparison | revisions | |
optparser.c | file | annotate | diff | comparison | revisions | |
tester.c | file | annotate | diff | comparison | revisions | |
tester3.c | file | annotate | diff | comparison | revisions | |
util.c | file | annotate | diff | comparison | revisions |
--- a/include/libtu/optparser.h Sat May 20 17:43:36 2000 +0200 +++ b/include/libtu/optparser.h Sun May 21 17:33:48 2000 +0200 @@ -11,8 +11,11 @@ #include "types.h" -#define OPT_ID(X) ((X)|0x10000) -#define OPT_ID_RESERVED(X) ((X)|0x20000) +#define OPT_ID_NOSHORT_FLAG 0x10000 +#define OPT_ID_RESERVED_FLAG 0x20000 + +#define OPT_ID(X) ((X)|OPT_ID_NOSHORT_FLAG) +#define OPT_ID_RESERVED(X) ((X)|OPT_ID_RESERVED_FLAG) /* OPTP_CHAIN is the normal behavior, i.e. single-letter options can be * "chained" together: 'lr -lR'. Use for normal command line programs. @@ -27,6 +30,7 @@ enum{ OPTP_CHAIN=0, + OPTP_DEFAULT=0, OPTP_MIDLONG=1, OPTP_IMMEDIATE=2, OPTP_NO_DASH=3 @@ -38,13 +42,22 @@ }; -typedef struct{ +typedef struct _OptParserOpt{ int optid; const char *longopt; int flags; + const char *argname; + const char *descr; } OptParserOpt; +typedef struct _OptParserCommonInfo{ + const char *version; + const char *usage_tmpl; + const char *about; +} OptParserCommonInfo; + + enum{ OPT_ID_END=0, OPT_ID_ARGUMENT=1, @@ -58,7 +71,9 @@ extern void optparser_init(int argc, char *const argv[], int mode, - const OptParserOpt *opts); + const OptParserOpt *opts, + const OptParserCommonInfo *cinfo); + extern int optparser_get_opt(); extern const char* optparser_get_arg(); extern void optparser_print_error();
--- a/include/libtu/util.h Sat May 20 17:43:36 2000 +0200 +++ b/include/libtu/util.h Sun May 21 17:33:48 2000 +0200 @@ -13,26 +13,13 @@ #include <stdlib.h> #include "types.h" - +#include "optparser.h" -typedef struct{ - const char *name; - const char *version; - const char *authors; - const char *license; - const char *usage; -} ProgInfo; - - -extern void libtu_init_argv0(const char *argv0, const ProgInfo *info); -extern void libtu_init(int *argc, char *argv[], const ProgInfo *info); +extern void libtu_init(const char *argv0); +extern void libtu_init_copt(int argc, char *const argv[], + const OptParserCommonInfo *cinfo); + extern const char *prog_execname(); -extern const ProgInfo *prog_info(); -extern const char *prog_name(); -extern const char *prog_version(); -extern const char *prog_authors(); -extern const char *prog_license(); -extern const char *prog_usage(); #endif /* LIBTU_UTIL_H */
--- 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++<maxw) + putc(' ', f); + + /* descr */ + + p=p2=opt->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++; + } +} +
--- a/tester.c Sat May 20 17:43:36 2000 +0200 +++ b/tester.c Sun May 21 17:33:48 2000 +0200 @@ -9,13 +9,15 @@ #include <libtu/misc.h> #include <libtu/tokenizer.h> - +#include <libtu/util.h> -int main(void) +int main(int argc, char *argv[]) { Tokenizer*tokz; Token tok=TOK_INIT; + libtu_init(argv[0]); + if(!(tokz=tokz_open_file(stdin))) return EXIT_FAILURE;
--- a/tester3.c Sat May 20 17:43:36 2000 +0200 +++ b/tester3.c Sun May 21 17:33:48 2000 +0200 @@ -13,31 +13,19 @@ static const char usage[]= - "$u [options]\n" + "Usage: $p [options]\n" "\n" "Where options are:\n" - "\n" - " -o, -f, -v, -z, -x\n" - "$c \n" - "\n"; + "$o\n"; -static ProgInfo proginfo={ - "Tester III", - "0.1", - "foo", - "bar", - usage -}; - - static OptParserOpt opts[]={ - {'o', "opt", OPT_ARG}, - {'f', "file", OPT_ARG}, - {'v', "view", 0}, - {'z', "zip", 0}, - {'x', "extract", 0}, - {0, NULL, 0} + {'o', "opt", OPT_ARG, "OPTION", "foo bar baz quk asdf jklö äölk dfgh quik aaaa bbbb cccc dddd eeee ffff"}, + {'f', "file", OPT_ARG, "FILE", "asdfsadlfölökjasdflökjasdflkjöasdflkjöas dlöfjkasdfölkjasdfölkjasdfasdflöjasdfkasödjlfkasdlföjasdölfjkölkasjdfasdfölkjasd asdöljfasöldf asdölfköasdlf asfdlök asdföljkadsfölasdfölasdölkfjasdölfasödlflöskflasdföaölsdf"}, + {'v', "view", 0, NULL, NULL}, + {'z', "zip", 0, NULL, NULL}, + {'x', "extract", 0, NULL, NULL}, + {0, NULL, 0, NULL, NULL} }; @@ -45,9 +33,9 @@ { int opt; - libtu_init(&argc, argv, &proginfo); + libtu_init(argv[0]); - optparser_init(argc, argv, OPTP_NO_DASH, opts); + optparser_init(argc, argv, OPTP_NO_DASH, opts, NULL); while((opt=optparser_get_opt())){ switch(opt){
--- a/util.c Sat May 20 17:43:36 2000 +0200 +++ b/util.c Sun May 21 17:33:48 2000 +0200 @@ -18,16 +18,12 @@ #include <libtu/misc.h> -static const ProgInfo *proginfo=NULL; static const char *progname=NULL; -static void common_opts(int *argc, char *argv[]); - -void libtu_init_argv0(const char *argv0, const ProgInfo *info) +void libtu_init(const char *argv0) { progname=argv0; - proginfo=info; #ifdef CONFIG_LOCALE textdomain(simple_basename(argv0)); @@ -35,11 +31,22 @@ } -void libtu_init(int *argc, char *argv[], const ProgInfo *info) +void libtu_init_copt(int argc, char *const argv[], + const OptParserCommonInfo *cinfo) { - libtu_init_argv0(argv[0], info); + int opt; + + libtu_init(argv[0]); + + optparser_init(argc, argv, OPTP_DEFAULT, NULL, cinfo); - common_opts(argc, argv); + while((opt=optparser_get_opt())){ + switch(opt){ + default: + optparser_print_error(); + exit(EXIT_FAILURE); + } + } } @@ -48,178 +55,3 @@ return progname; } - -const ProgInfo *prog_info() -{ - return proginfo; -} - - -const char *prog_name() -{ - return proginfo ? proginfo->name : NULL; -} - - -const char *prog_version() -{ - return proginfo ? proginfo->version : NULL; -} - - -const char *prog_authors() -{ - return proginfo ? proginfo->authors : NULL; -} - - -const char *prog_license() -{ - return proginfo ? proginfo->license : NULL; -} - - -const char *prog_usage() -{ - return proginfo ? proginfo->usage : NULL; -} - - -/* */ - - -static char *usages[][2]={ - {"--help", "Show this help\n"}, - {"--version", "Show program version\n"}, - {"--authors", "Show program authors\n"}, - {"--license", "Show program license\n"}, - {"--proginfo", "Show program info\n"}, - {NULL,} -}; - - -static void common_usage(size_t start, size_t len) -{ - size_t l; - int i; - - for(i=0; usages[i][0]!=NULL; i++){ - - for(l=0; l<start; l++){ - putc(' ', stdout); - }; - - l=strlen(usages[i][0]); - writef(stdout, usages[i][0], l); - - do{ - putc(' ', stdout); - }while(++l<len-start); - - writef(stdout, usages[i][1], strlen(usages[i][1])); - } -} - - -static void show_usage(const char *p) -{ - const char *tmp; - size_t len; - size_t start; - - do{ - tmp=strchr(p, '\n'); - - if(tmp==NULL){ - len=strlen(p); - if(len==0) - break; - }else{ - len=tmp-p; - } - - start=strspn(p, " "); - - if(p[start]=='$' && p[start+1]=='u'){ - tmp=prog_execname(); - if(start!=0) - writef(stdout, p, start); - printf(TR("Usage: %s"), tmp); - writef(stdout, p+start+2, len-start-2); - putc('\n', stdout); - }else if(p[start]=='$' && p[start+1]=='c'){ - common_usage(start, len); - }else{ - writef(stdout, p, len); - putc('\n', stdout); - } - - p+=len+1; - }while(*(p-1)!='\0'); - -} - - -static void common_opts(int *argcp, char *argv[]) -{ - int argc=*argcp; - const char *p, *p2; - - argc--; - argv++; - - for(; argc>0; argc--, argv++){ - if(strcmp(*argv, "--help")==0){ - p=prog_usage(); - if(p==NULL){ - printf(TR("Usage: %s [options]\n" - "Where options are:\n\n"), prog_execname()); - common_usage(5, 20); - printf("\n"); - }else{ - show_usage(p); - } - }else if(strcmp(*argv, "--version")==0){ - p=prog_version(); - if(p==NULL) - printf(TR("No version available\n")); - else - printf("%s\n", p); - }else if(strcmp(*argv, "--authors")==0){ - p=prog_authors(); - if(p==NULL) - printf(TR("No author(s) info available\n")); - else - printf("%s\n", p); - }else if(strcmp(*argv, "--license")==0){ - p=prog_license(); - if(p==NULL) - printf(TR("No license available\n")); - else - printf("%s", TR(p)); - }else if(strcmp(*argv, "--proginfo")==0){ - p2=prog_version(); - p=prog_name(); - - if(p==NULL){ - p=prog_execname(); - - if(p==NULL){ - printf(TR("No name available\n")); - break; - } - } - - if(p2) - printf("%s v%s\n", p, p2); - else - printf("%s\n", p); - }else if(strcmp(*argv, "--")){ - break; - }else{ - continue; - } - - exit(EXIT_SUCCESS); - } -}