diff options
-rw-r--r-- | src/argparse.c | 293 |
1 files changed, 188 insertions, 105 deletions
diff --git a/src/argparse.c b/src/argparse.c index 765c96c..c29e2ea 100644 --- a/src/argparse.c +++ b/src/argparse.c @@ -57,7 +57,8 @@ static struct /* Hidden argparse flag used to mark the object as initialized. */ #define ARGPARSE_FLAG__INITIALIZED (1<< ((8*SIZEOF_INT)-1)) -/* Special short options which are auto-inserterd. */ +/* Special short options which are auto-inserterd. Must fit into an + * unsigned short. */ #define ARGPARSE_SHORTOPT_HELP 32768 #define ARGPARSE_SHORTOPT_VERSION 32769 #define ARGPARSE_SHORTOPT_WARRANTY 32770 @@ -80,6 +81,18 @@ enum argparser_states }; +/* An internal object used to store the user provided option table and + * some meta information. */ +typedef struct +{ + unsigned short short_opt; + unsigned short ordinal; /* (for --help) */ + unsigned int flags; + const char *long_opt; /* Points into the user provided table. */ + const char *description; /* Points into the user provided table. */ +} opttable_t; + + /* Internal object of the public gpgrt_argparse_t object. */ struct _gpgrt_argparse_internal_s { @@ -97,7 +110,8 @@ struct _gpgrt_argparse_internal_s void *iio_list; estream_t conffp; char *confname; - gpgrt_opt_t **opts; /* Malloced array of pointer to user provided opts. */ + opttable_t *opts; /* Malloced option table. */ + unsigned int nopts; /* Number of items in OPTS. */ }; @@ -127,7 +141,7 @@ static int (*custom_outfnc) (int, const char *); static const char *(*fixed_string_mapper)(const char*); static int set_opt_arg (gpgrt_argparse_t *arg, unsigned int flags, char *s); -static void show_help (gpgrt_opt_t **opts, unsigned int flags); +static void show_help (opttable_t *opts, unsigned int nopts,unsigned int flags); static void show_version (void); static int writestrings (int is_error, const char *string, ...) GPGRT_ATTR_SENTINEL(0); @@ -273,6 +287,7 @@ initialize (gpgrt_argparse_t *arg, gpgrt_opt_t *opts, estream_t fp) else if (arg->internal->opts) xfree (arg->internal->opts); arg->internal->opts = NULL; + arg->internal->nopts = 0; /* Initialize this instance. */ arg->internal->idx = 0; @@ -317,16 +332,6 @@ initialize (gpgrt_argparse_t *arg, gpgrt_opt_t *opts, estream_t fp) * this array. */ if (!arg->internal->opts) { - static gpgrt_opt_t help_opt - = ARGPARSE_s_n (ARGPARSE_SHORTOPT_HELP, "help", "@"); - static gpgrt_opt_t version_opt - = ARGPARSE_s_n (ARGPARSE_SHORTOPT_VERSION, "version", "@"); - static gpgrt_opt_t warranty_opt - = ARGPARSE_s_n (ARGPARSE_SHORTOPT_WARRANTY, "warranty", "@"); - static gpgrt_opt_t dump_options_opt - = ARGPARSE_s_n(ARGPARSE_SHORTOPT_DUMP_OPTIONS, "dump-options", "@"); - static gpgrt_opt_t end_marker - = ARGPARSE_end (); int seen_help = 0; int seen_version = 0; int seen_warranty = 0; @@ -337,13 +342,13 @@ initialize (gpgrt_argparse_t *arg, gpgrt_opt_t *opts, estream_t fp) { if (opts[i].long_opt) { - if (!strcmp(opts[i].long_opt, help_opt.long_opt)) + if (!strcmp(opts[i].long_opt, "help")) seen_help = 1; - else if (!strcmp(opts[i].long_opt, version_opt.long_opt)) + else if (!strcmp(opts[i].long_opt, "version")) seen_version = 1; - else if (!strcmp(opts[i].long_opt, warranty_opt.long_opt)) + else if (!strcmp(opts[i].long_opt, "warranty")) seen_warranty = 1; - else if (!strcmp(opts[i].long_opt, dump_options_opt.long_opt)) + else if (!strcmp(opts[i].long_opt, "dump-options")) seen_dump_options = 1; } } @@ -353,16 +358,58 @@ initialize (gpgrt_argparse_t *arg, gpgrt_opt_t *opts, estream_t fp) if (!arg->internal->opts) return _gpg_err_code_from_syserror (); for(i=0; opts[i].short_opt; i++) - arg->internal->opts[i] = opts + i; + { + arg->internal->opts[i].short_opt = opts[i].short_opt; + arg->internal->opts[i].flags = opts[i].flags; + arg->internal->opts[i].long_opt = opts[i].long_opt; + arg->internal->opts[i].description = opts[i].description; + arg->internal->opts[i].ordinal = i; + } + if (!seen_help) - arg->internal->opts[i++] = &help_opt; + { + arg->internal->opts[i].short_opt = ARGPARSE_SHORTOPT_HELP; + arg->internal->opts[i].flags = ARGPARSE_TYPE_NONE; + arg->internal->opts[i].long_opt = "help"; + arg->internal->opts[i].description = "@"; + arg->internal->opts[i].ordinal = i; + i++; + } if (!seen_version) - arg->internal->opts[i++] = &version_opt; + { + arg->internal->opts[i].short_opt = ARGPARSE_SHORTOPT_VERSION; + arg->internal->opts[i].flags = ARGPARSE_TYPE_NONE; + arg->internal->opts[i].long_opt = "version"; + arg->internal->opts[i].description = "@"; + arg->internal->opts[i].ordinal = i; + i++; + } + if (!seen_warranty) - arg->internal->opts[i++] = &warranty_opt; + { + arg->internal->opts[i].short_opt = ARGPARSE_SHORTOPT_WARRANTY; + arg->internal->opts[i].flags = ARGPARSE_TYPE_NONE; + arg->internal->opts[i].long_opt = "warranty"; + arg->internal->opts[i].description = "@"; + arg->internal->opts[i].ordinal = i; + i++; + } + if (!seen_dump_options) - arg->internal->opts[i++] = &dump_options_opt; - arg->internal->opts[i] = &end_marker; + { + arg->internal->opts[i].short_opt = ARGPARSE_SHORTOPT_DUMP_OPTIONS; + arg->internal->opts[i].flags = ARGPARSE_TYPE_NONE; + arg->internal->opts[i].long_opt = "dump-options"; + arg->internal->opts[i].description = "@"; + arg->internal->opts[i].ordinal = i; + i++; + } + + arg->internal->opts[i].short_opt = 0; + + /* Note that we do not count the end marker but keep it in the + * table anyway as an extra item. */ + arg->internal->nopts = i; } if (arg->err) @@ -613,7 +660,8 @@ _gpgrt_argparse (estream_t fp, gpgrt_argparse_t *arg, gpgrt_opt_t *opts_orig) Ametacmd, /* Process the metacmd. */ Askipandleave /* Skip the rest of the line and then leave. */ } state; - gpgrt_opt_t **opts; + opttable_t *opts; + unsigned int nopts; int i, c; int idx = 0; char keyword[100]; @@ -636,6 +684,7 @@ _gpgrt_argparse (estream_t fp, gpgrt_argparse_t *arg, gpgrt_opt_t *opts_orig) return (arg->r_opt = ARGPARSE_OUT_OF_CORE); opts = arg->internal->opts; + nopts = arg->internal->nopts; /* If the LINENO is zero we assume that we are at the start of a * file and we skip over a possible Byte Order Mark. */ @@ -662,21 +711,21 @@ _gpgrt_argparse (estream_t fp, gpgrt_argparse_t *arg, gpgrt_opt_t *opts_orig) if (state == Akeyword_eol || state == Akeyword_spc) { /* Check the keyword. */ - for (i=0; opts[i]->short_opt; i++ ) + for (i=0; i < nopts; i++ ) { - if (opts[i]->long_opt && !strcmp (opts[i]->long_opt, keyword)) + if (opts[i].long_opt && !strcmp (opts[i].long_opt, keyword)) break; } idx = i; - arg->r_opt = opts[idx]->short_opt; - if ((opts[idx]->flags & ARGPARSE_OPT_IGNORE)) + arg->r_opt = opts[idx].short_opt; + if ((opts[idx].flags & ARGPARSE_OPT_IGNORE)) { /* Option is configured to be ignored. Start from * scratch (new line) or process like a comment. */ state = state == Akeyword_eol? Ainit : Acomment; i = 0; } - else if (!opts[idx]->short_opt ) + else if (!(i < nopts)) { /* The option is not known - check for internal keywords. */ if (state == Akeyword_spc && !strcmp (keyword, "alias")) @@ -710,7 +759,7 @@ _gpgrt_argparse (estream_t fp, gpgrt_argparse_t *arg, gpgrt_opt_t *opts_orig) } else { - arg->r_opt = ((opts[idx]->flags & ARGPARSE_OPT_COMMAND) + arg->r_opt = ((opts[idx].flags & ARGPARSE_OPT_COMMAND) ? ARGPARSE_INVALID_COMMAND : ARGPARSE_INVALID_OPTION); if (state == Akeyword_spc) @@ -727,9 +776,9 @@ _gpgrt_argparse (estream_t fp, gpgrt_argparse_t *arg, gpgrt_opt_t *opts_orig) else { /* Known option and at end of line - return option. */ - if (!(opts[idx]->flags & ARGPARSE_TYPE_MASK)) + if (!(opts[idx].flags & ARGPARSE_TYPE_MASK)) arg->r_type = 0; /* Does not take an arg. */ - else if ((opts[idx]->flags & ARGPARSE_OPT_OPTIONAL) ) + else if ((opts[idx].flags & ARGPARSE_OPT_OPTIONAL) ) arg->r_type = 0; /* Arg is optional. */ else arg->r_opt = ARGPARSE_MISSING_ARG; @@ -788,9 +837,9 @@ _gpgrt_argparse (estream_t fp, gpgrt_argparse_t *arg, gpgrt_opt_t *opts_orig) /* No argument found at the end of the line. */ if (in_alias) arg->r_opt = ARGPARSE_MISSING_ARG; - else if (!(opts[idx]->flags & ARGPARSE_TYPE_MASK)) + else if (!(opts[idx].flags & ARGPARSE_TYPE_MASK)) arg->r_type = 0; /* Does not take an arg. */ - else if ((opts[idx]->flags & ARGPARSE_OPT_OPTIONAL)) + else if ((opts[idx].flags & ARGPARSE_OPT_OPTIONAL)) arg->r_type = 0; /* No optional argument. */ else arg->r_opt = ARGPARSE_MISSING_ARG; @@ -826,7 +875,7 @@ _gpgrt_argparse (estream_t fp, gpgrt_argparse_t *arg, gpgrt_opt_t *opts_orig) } } } - else if (!(opts[idx]->flags & ARGPARSE_TYPE_MASK)) + else if (!(opts[idx].flags & ARGPARSE_TYPE_MASK)) arg->r_opt = ARGPARSE_UNEXPECTED_ARG; else { @@ -853,7 +902,7 @@ _gpgrt_argparse (estream_t fp, gpgrt_argparse_t *arg, gpgrt_opt_t *opts_orig) if (*p && p[strlen(p)-1] == '\"' ) p[strlen(p)-1] = 0; } - if (!set_opt_arg (arg, opts[idx]->flags, p)) + if (!set_opt_arg (arg, opts[idx].flags, p)) xfree (buffer); else gpgrt_annotate_leaked_object (buffer); @@ -983,11 +1032,11 @@ _gpgrt_argparse (estream_t fp, gpgrt_argparse_t *arg, gpgrt_opt_t *opts_orig) /* Return true if the list of options OPTS has any option marked with * ARGPARSE_OPT_CONFFILE. */ static int -any_opt_conffile (gpgrt_opt_t *opts) +any_opt_conffile (opttable_t *opts, unsigned int nopts) { int i; - for (i=0; opts[i].short_opt; i++ ) + for (i=0; i < nopts; i++ ) if ((opts[i].flags & ARGPARSE_OPT_CONFFILE)) return 1; return 0; @@ -1132,7 +1181,7 @@ _gpgrt_argparser (gpgrt_argparse_t *arg, gpgrt_opt_t *opts, { case STATE_init: if (arg->argc && arg->argv && *arg->argc - && any_opt_conffile (opts)) + && any_opt_conffile (arg->internal->opts, arg->internal->nopts)) { /* The list of option allow for conf files * (e.g. gpg's "--option FILE" and "--no-options") @@ -1403,26 +1452,26 @@ _gpgrt_argparser (gpgrt_argparse_t *arg, gpgrt_opt_t *opts, } -/* Given the list of options OPTS and a keyword, return the index of - * the long option macthing KEYWORD. On error -1 is retruned for not +/* Given the list of options in ARG and a keyword, return the index of + * the long option matching KEYWORD. On error -1 is returned for not * found or -2 for ambigious keyword. */ static int -find_long_option (gpgrt_argparse_t *arg, gpgrt_opt_t **opts, - const char *keyword) +find_long_option (gpgrt_argparse_t *arg, const char *keyword) { int i; size_t n; - - (void)arg; /* Not yet required. */ + opttable_t *opts = arg->internal->opts; + unsigned int nopts = arg->internal->nopts; /* Would be better if we can do a binary search, but it is not * possible to reorder our option table because we would mess up our * help strings. What we can do is: Build an option lookup table - * when this function is first invoked. */ + * when this function is first invoked. The latter has already been + * done. */ if (!*keyword) return -1; - for (i=0; opts[i]->short_opt; i++ ) - if (opts[i]->long_opt && !strcmp (opts[i]->long_opt, keyword)) + for (i=0; i < nopts; i++ ) + if (opts[i].long_opt && !strcmp (opts[i].long_opt, keyword)) return i; #if 0 { @@ -1442,17 +1491,17 @@ find_long_option (gpgrt_argparse_t *arg, gpgrt_opt_t **opts, /* Not found. See whether it is an abbreviation. Aliases may not * be abbreviated, though. */ n = strlen (keyword); - for (i=0; opts[i]->short_opt; i++) + for (i=0; i < nopts; i++) { - if (opts[i]->long_opt && !strncmp (opts[i]->long_opt, keyword, n)) + if (opts[i].long_opt && !strncmp (opts[i].long_opt, keyword, n)) { int j; - for (j=i+1; opts[j]->short_opt; j++) + for (j=i+1; j < nopts; j++) { - if (opts[j]->long_opt - && !strncmp (opts[j]->long_opt, keyword, n) - && !(opts[j]->short_opt == opts[i]->short_opt - && opts[j]->flags == opts[i]->flags ) ) + if (opts[j].long_opt + && !strncmp (opts[j].long_opt, keyword, n) + && !(opts[j].short_opt == opts[i].short_opt + && opts[j].flags == opts[i].flags ) ) return -2; /* Abbreviation is ambiguous. */ } return i; @@ -1467,7 +1516,8 @@ static int arg_parse (gpgrt_argparse_t *arg, gpgrt_opt_t *opts_orig, int no_init) { int idx; - gpgrt_opt_t **opts; + opttable_t *opts; + unsigned int nopts; int argc; char **argv; char *s, *s2; @@ -1479,6 +1529,7 @@ arg_parse (gpgrt_argparse_t *arg, gpgrt_opt_t *opts_orig, int no_init) return (arg->r_opt = ARGPARSE_OUT_OF_CORE); opts = arg->internal->opts; + nopts = arg->internal->nopts; argc = *arg->argc; argv = *arg->argv; idx = arg->internal->idx; @@ -1508,7 +1559,7 @@ arg_parse (gpgrt_argparse_t *arg, gpgrt_opt_t *opts_orig, int no_init) arg->r.ret_str = s; argc--; argv++; idx++; /* set to next one */ } - else if( arg->internal->stopped ) + else if (arg->internal->stopped) { arg->r_opt = 0; goto leave; /* Ready. */ @@ -1531,13 +1582,13 @@ arg_parse (gpgrt_argparse_t *arg, gpgrt_opt_t *opts_orig, int no_init) argpos = strchr( s+2, '=' ); if ( argpos ) *argpos = 0; - i = find_long_option ( arg, opts, s+2 ); + i = find_long_option (arg, s+2); if ( argpos ) *argpos = '='; - if (i > 0 && opts[i]->short_opt == ARGPARSE_SHORTOPT_HELP) - show_help (opts, arg->flags); - else if (i > 0 && opts[i]->short_opt == ARGPARSE_SHORTOPT_VERSION) + if (i > 0 && opts[i].short_opt == ARGPARSE_SHORTOPT_HELP) + show_help (opts, nopts, arg->flags); + else if (i > 0 && opts[i].short_opt == ARGPARSE_SHORTOPT_VERSION) { if (!(arg->flags & ARGPARSE_FLAG_NOVERSION)) { @@ -1545,17 +1596,17 @@ arg_parse (gpgrt_argparse_t *arg, gpgrt_opt_t *opts_orig, int no_init) my_exit (arg, 0); } } - else if (i > 0 && opts[i]->short_opt == ARGPARSE_SHORTOPT_WARRANTY) + else if (i > 0 && opts[i].short_opt == ARGPARSE_SHORTOPT_WARRANTY) { writestrings (0, _gpgrt_strusage (16), "\n", NULL); my_exit (arg, 0); } - else if (i > 0 && opts[i]->short_opt == ARGPARSE_SHORTOPT_DUMP_OPTIONS) + else if (i > 0 && opts[i].short_opt == ARGPARSE_SHORTOPT_DUMP_OPTIONS) { - for (i=0; opts[i]->short_opt; i++ ) + for (i=0; i < nopts; i++ ) { - if (opts[i]->long_opt && !(opts[i]->flags & ARGPARSE_OPT_IGNORE)) - writestrings (0, "--", opts[i]->long_opt, "\n", NULL); + if (opts[i].long_opt && !(opts[i].flags & ARGPARSE_OPT_IGNORE)) + writestrings (0, "--", opts[i].long_opt, "\n", NULL); } my_exit (arg, 0); } @@ -1568,10 +1619,10 @@ arg_parse (gpgrt_argparse_t *arg, gpgrt_opt_t *opts_orig, int no_init) arg->r.ret_str = s+2; } else - arg->r_opt = opts[i]->short_opt; + arg->r_opt = opts[i].short_opt; if ( i < 0 ) ; - else if ( (opts[i]->flags & ARGPARSE_TYPE_MASK) ) + else if ( (opts[i].flags & ARGPARSE_TYPE_MASK) ) { if ( argpos ) { @@ -1581,7 +1632,7 @@ arg_parse (gpgrt_argparse_t *arg, gpgrt_opt_t *opts_orig, int no_init) } else s2 = argv[1]; - if ( !s2 && (opts[i]->flags & ARGPARSE_OPT_OPTIONAL) ) + if ( !s2 && (opts[i].flags & ARGPARSE_OPT_OPTIONAL) ) { arg->r_type = ARGPARSE_TYPE_NONE; /* Argument is optional. */ } @@ -1590,7 +1641,7 @@ arg_parse (gpgrt_argparse_t *arg, gpgrt_opt_t *opts_orig, int no_init) arg->r_opt = ARGPARSE_MISSING_ARG; } else if ( !argpos && *s2 == '-' - && (opts[i]->flags & ARGPARSE_OPT_OPTIONAL) ) + && (opts[i].flags & ARGPARSE_OPT_OPTIONAL) ) { /* The argument is optional and the next seems to be an option. We do not check this possible option but @@ -1599,7 +1650,7 @@ arg_parse (gpgrt_argparse_t *arg, gpgrt_opt_t *opts_orig, int no_init) } else { - set_opt_arg (arg, opts[i]->flags, s2); + set_opt_arg (arg, opts[i].flags, s2); if ( !argpos ) { argc--; argv++; idx++; /* Skip one. */ @@ -1613,7 +1664,7 @@ arg_parse (gpgrt_argparse_t *arg, gpgrt_opt_t *opts_orig, int no_init) arg->r_type = ARGPARSE_UNEXPECTED_ARG; else { - arg->internal->opt_flags = opts[i]->flags; + arg->internal->opt_flags = opts[i].flags; arg->r_type = 0; } } @@ -1630,8 +1681,8 @@ arg_parse (gpgrt_argparse_t *arg, gpgrt_opt_t *opts_orig, int no_init) arg->internal->inarg++; if ( (arg->flags & ARGPARSE_FLAG_ONEDASH) ) { - for (i=0; opts[i]->short_opt; i++ ) - if ( opts[i]->long_opt && !strcmp (opts[i]->long_opt, s+1)) + for (i=0; opts[i].short_opt; i++ ) + if ( opts[i].long_opt && !strcmp (opts[i].long_opt, s+1)) { dash_kludge = 1; break; @@ -1642,53 +1693,53 @@ arg_parse (gpgrt_argparse_t *arg, gpgrt_opt_t *opts_orig, int no_init) if (!dash_kludge ) { - for (i=0; opts[i]->short_opt; i++ ) - if ( opts[i]->short_opt == *s ) + for (i=0; i < nopts; i++ ) + if ( opts[i].short_opt == *s ) break; } - if ( !opts[i]->short_opt && ( *s == 'h' || *s == '?' ) ) - show_help (opts, arg->flags); + if ( !opts[i].short_opt && ( *s == 'h' || *s == '?' ) ) + show_help (opts, nopts, arg->flags); - arg->r_opt = opts[i]->short_opt; - if (!opts[i]->short_opt ) + arg->r_opt = opts[i].short_opt; + if (!opts[i].short_opt ) { - arg->r_opt = (opts[i]->flags & ARGPARSE_OPT_COMMAND)? + arg->r_opt = (opts[i].flags & ARGPARSE_OPT_COMMAND)? ARGPARSE_INVALID_COMMAND:ARGPARSE_INVALID_OPTION; arg->internal->inarg++; /* Point to the next arg. */ arg->r.ret_str = s; } - else if ( (opts[i]->flags & ARGPARSE_TYPE_MASK) ) + else if ( (opts[i].flags & ARGPARSE_TYPE_MASK) ) { if ( s[1] && !dash_kludge ) { s2 = s+1; - set_opt_arg (arg, opts[i]->flags, s2); + set_opt_arg (arg, opts[i].flags, s2); } else { s2 = argv[1]; - if ( !s2 && (opts[i]->flags & ARGPARSE_OPT_OPTIONAL) ) + if ( !s2 && (opts[i].flags & ARGPARSE_OPT_OPTIONAL) ) { arg->r_type = ARGPARSE_TYPE_NONE; - arg->internal->opt_flags = opts[i]->flags; + arg->internal->opt_flags = opts[i].flags; } else if ( !s2 ) { arg->r_opt = ARGPARSE_MISSING_ARG; } else if ( *s2 == '-' && s2[1] - && (opts[i]->flags & ARGPARSE_OPT_OPTIONAL) ) + && (opts[i].flags & ARGPARSE_OPT_OPTIONAL) ) { /* The argument is optional and the next seems to be an option. We do not check this possible option but assume no argument. */ arg->r_type = ARGPARSE_TYPE_NONE; - arg->internal->opt_flags = opts[i]->flags; + arg->internal->opt_flags = opts[i].flags; } else { - set_opt_arg (arg, opts[i]->flags, s2); + set_opt_arg (arg, opts[i].flags, s2); argc--; argv++; idx++; /* Skip one. */ } } @@ -1698,7 +1749,7 @@ arg_parse (gpgrt_argparse_t *arg, gpgrt_opt_t *opts_orig, int no_init) { /* Does not take an argument. */ arg->r_type = ARGPARSE_TYPE_NONE; - arg->internal->opt_flags = opts[i]->flags; + arg->internal->opt_flags = opts[i].flags; arg->internal->inarg++; /* Point to the next arg. */ } if ( !s[1] || dash_kludge ) @@ -1789,7 +1840,7 @@ set_opt_arg (gpgrt_argparse_t *arg, unsigned flags, char *s) /* Return the length of the option O. This needs to consider the * description as weel as the option name. */ static size_t -long_opt_strlen (gpgrt_opt_t *o) +long_opt_strlen (opttable_t *o) { size_t n = strlen (o->long_opt); @@ -1812,6 +1863,18 @@ long_opt_strlen (gpgrt_opt_t *o) } + +/* Qsort compare for show_help. */ +static int +cmp_ordtbl (const void *a_v, const void *b_v) +{ + const unsigned short *a = a_v; + const unsigned short *b = b_v; + + return *a - *b; +} + + /**************** * Print formatted help. The description string has some special * meanings: @@ -1824,10 +1887,11 @@ long_opt_strlen (gpgrt_opt_t *o) * bar and the next one as arguments of the long option. */ static void -show_help (gpgrt_opt_t **opts, unsigned int flags) +show_help (opttable_t *opts, unsigned int nopts, unsigned int flags) { const char *s; char tmp[2]; + unsigned int *ordtbl = NULL; show_version (); writestrings (0, "\n", NULL); @@ -1841,27 +1905,43 @@ show_help (gpgrt_opt_t **opts, unsigned int flags) } s = _gpgrt_strusage(41); writestrings (0, s, "\n", NULL); - if ( opts[0]->description ) + if ( nopts ) { /* Auto format the option description. */ int i,j, indent; + ordtbl = xtrycalloc (nopts, sizeof *ordtbl); + if (!ordtbl) + { + writestrings (1, "\nOoops: Out of memory whilst printing the help.\n", + NULL); + goto leave; + } + /* Get max. length of long options. */ - for (i=indent=0; opts[i]->short_opt; i++ ) + for (i=indent=0; i < nopts; i++ ) { - if ( opts[i]->long_opt ) - if ( !opts[i]->description || *opts[i]->description != '@' ) - if ( (j=long_opt_strlen(opts[i])) > indent && j < 35 ) + if ( opts[i].long_opt ) + if ( !opts[i].description || *opts[i].description != '@' ) + if ( (j=long_opt_strlen(opts+i)) > indent && j < 35 ) indent = j; + ordtbl[i] = opts[i].ordinal; } + qsort (ordtbl, nopts, sizeof *ordtbl, cmp_ordtbl); + + /* The first option needs to have a description; if not do not + * print the help at all. */ + if (!opts[ordtbl[0]].description) + goto leave; + /* Example: " -v, --verbose Viele Sachen ausgeben" */ indent += 10; - if ( *opts[0]->description != '@' ) + if ( *opts[ordtbl[0]].description != '@' ) writestrings (0, "Options:", "\n", NULL); - for (i=0; opts[i]->short_opt; i++ ) + for (i=0; i < nopts; i++ ) { - s = map_fixed_string (_( opts[i]->description )); + s = map_fixed_string (_( opts[ordtbl[i]].description )); if ( s && *s== '@' && !s[1] ) /* Hide this line. */ continue; if ( s && *s == '@' ) /* Unindented comment only line. */ @@ -1885,12 +1965,12 @@ show_help (gpgrt_opt_t **opts, unsigned int flags) } j = 3; - if ( opts[i]->short_opt < 256 ) + if ( opts[ordtbl[i]].short_opt < 256 ) { - tmp[0] = opts[i]->short_opt; + tmp[0] = opts[ordtbl[i]].short_opt; tmp[1] = 0; writestrings (0, " -", tmp, NULL ); - if ( !opts[i]->long_opt ) + if ( !opts[ordtbl[i]].long_opt ) { if (s && *s == '|' ) { @@ -1908,11 +1988,11 @@ show_help (gpgrt_opt_t **opts, unsigned int flags) } else writestrings (0, " ", NULL); - if ( opts[i]->long_opt ) + if ( opts[ordtbl[i]].long_opt ) { - tmp[0] = opts[i]->short_opt < 256?',':' '; + tmp[0] = opts[ordtbl[i]].short_opt < 256?',':' '; tmp[1] = 0; - j += writestrings (0, tmp, " --", opts[i]->long_opt, NULL); + j += writestrings (0, tmp, " --", opts[ordtbl[i]].long_opt, NULL); if (s && *s == '|' ) { if ( *++s != '=' ) @@ -1972,7 +2052,10 @@ show_help (gpgrt_opt_t **opts, unsigned int flags) writestrings (0, "\n", NULL); writestrings (0, s, NULL); } + + leave: flushstrings (0); + xfree (ordtbl); exit (0); } |