|
@@ -339,10 +339,10 @@ int parse_options_step(struct parse_opt_ctx_t *ctx,
|
|
|
if (arg[1] != '-') {
|
|
|
ctx->opt = arg + 1;
|
|
|
if (internal_help && *ctx->opt == 'h')
|
|
|
- return parse_options_usage(usagestr, options);
|
|
|
+ return usage_with_options_internal(usagestr, options, 0);
|
|
|
switch (parse_short_opt(ctx, options)) {
|
|
|
case -1:
|
|
|
- return parse_options_usage(usagestr, options);
|
|
|
+ return parse_options_usage(usagestr, options, arg + 1, 1);
|
|
|
case -2:
|
|
|
goto unknown;
|
|
|
default:
|
|
@@ -352,10 +352,11 @@ int parse_options_step(struct parse_opt_ctx_t *ctx,
|
|
|
check_typos(arg + 1, options);
|
|
|
while (ctx->opt) {
|
|
|
if (internal_help && *ctx->opt == 'h')
|
|
|
- return parse_options_usage(usagestr, options);
|
|
|
+ return usage_with_options_internal(usagestr, options, 0);
|
|
|
+ arg = ctx->opt;
|
|
|
switch (parse_short_opt(ctx, options)) {
|
|
|
case -1:
|
|
|
- return parse_options_usage(usagestr, options);
|
|
|
+ return parse_options_usage(usagestr, options, arg, 1);
|
|
|
case -2:
|
|
|
/* fake a short option thing to hide the fact that we may have
|
|
|
* started to parse aggregated stuff
|
|
@@ -383,12 +384,12 @@ int parse_options_step(struct parse_opt_ctx_t *ctx,
|
|
|
if (internal_help && !strcmp(arg + 2, "help-all"))
|
|
|
return usage_with_options_internal(usagestr, options, 1);
|
|
|
if (internal_help && !strcmp(arg + 2, "help"))
|
|
|
- return parse_options_usage(usagestr, options);
|
|
|
+ return usage_with_options_internal(usagestr, options, 0);
|
|
|
if (!strcmp(arg + 2, "list-opts"))
|
|
|
return PARSE_OPT_LIST;
|
|
|
switch (parse_long_opt(ctx, arg + 2, options)) {
|
|
|
case -1:
|
|
|
- return parse_options_usage(usagestr, options);
|
|
|
+ return parse_options_usage(usagestr, options, arg + 2, 0);
|
|
|
case -2:
|
|
|
goto unknown;
|
|
|
default:
|
|
@@ -445,6 +446,89 @@ int parse_options(int argc, const char **argv, const struct option *options,
|
|
|
#define USAGE_OPTS_WIDTH 24
|
|
|
#define USAGE_GAP 2
|
|
|
|
|
|
+static void print_option_help(const struct option *opts, int full)
|
|
|
+{
|
|
|
+ size_t pos;
|
|
|
+ int pad;
|
|
|
+
|
|
|
+ if (opts->type == OPTION_GROUP) {
|
|
|
+ fputc('\n', stderr);
|
|
|
+ if (*opts->help)
|
|
|
+ fprintf(stderr, "%s\n", opts->help);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ if (!full && (opts->flags & PARSE_OPT_HIDDEN))
|
|
|
+ return;
|
|
|
+
|
|
|
+ pos = fprintf(stderr, " ");
|
|
|
+ if (opts->short_name)
|
|
|
+ pos += fprintf(stderr, "-%c", opts->short_name);
|
|
|
+ else
|
|
|
+ pos += fprintf(stderr, " ");
|
|
|
+
|
|
|
+ if (opts->long_name && opts->short_name)
|
|
|
+ pos += fprintf(stderr, ", ");
|
|
|
+ if (opts->long_name)
|
|
|
+ pos += fprintf(stderr, "--%s", opts->long_name);
|
|
|
+
|
|
|
+ switch (opts->type) {
|
|
|
+ case OPTION_ARGUMENT:
|
|
|
+ break;
|
|
|
+ case OPTION_LONG:
|
|
|
+ case OPTION_U64:
|
|
|
+ case OPTION_INTEGER:
|
|
|
+ case OPTION_UINTEGER:
|
|
|
+ if (opts->flags & PARSE_OPT_OPTARG)
|
|
|
+ if (opts->long_name)
|
|
|
+ pos += fprintf(stderr, "[=<n>]");
|
|
|
+ else
|
|
|
+ pos += fprintf(stderr, "[<n>]");
|
|
|
+ else
|
|
|
+ pos += fprintf(stderr, " <n>");
|
|
|
+ break;
|
|
|
+ case OPTION_CALLBACK:
|
|
|
+ if (opts->flags & PARSE_OPT_NOARG)
|
|
|
+ break;
|
|
|
+ /* FALLTHROUGH */
|
|
|
+ case OPTION_STRING:
|
|
|
+ if (opts->argh) {
|
|
|
+ if (opts->flags & PARSE_OPT_OPTARG)
|
|
|
+ if (opts->long_name)
|
|
|
+ pos += fprintf(stderr, "[=<%s>]", opts->argh);
|
|
|
+ else
|
|
|
+ pos += fprintf(stderr, "[<%s>]", opts->argh);
|
|
|
+ else
|
|
|
+ pos += fprintf(stderr, " <%s>", opts->argh);
|
|
|
+ } else {
|
|
|
+ if (opts->flags & PARSE_OPT_OPTARG)
|
|
|
+ if (opts->long_name)
|
|
|
+ pos += fprintf(stderr, "[=...]");
|
|
|
+ else
|
|
|
+ pos += fprintf(stderr, "[...]");
|
|
|
+ else
|
|
|
+ pos += fprintf(stderr, " ...");
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ default: /* OPTION_{BIT,BOOLEAN,SET_UINT,SET_PTR} */
|
|
|
+ case OPTION_END:
|
|
|
+ case OPTION_GROUP:
|
|
|
+ case OPTION_BIT:
|
|
|
+ case OPTION_BOOLEAN:
|
|
|
+ case OPTION_INCR:
|
|
|
+ case OPTION_SET_UINT:
|
|
|
+ case OPTION_SET_PTR:
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (pos <= USAGE_OPTS_WIDTH)
|
|
|
+ pad = USAGE_OPTS_WIDTH - pos;
|
|
|
+ else {
|
|
|
+ fputc('\n', stderr);
|
|
|
+ pad = USAGE_OPTS_WIDTH;
|
|
|
+ }
|
|
|
+ fprintf(stderr, "%*s%s\n", pad + USAGE_GAP, "", opts->help);
|
|
|
+}
|
|
|
+
|
|
|
int usage_with_options_internal(const char * const *usagestr,
|
|
|
const struct option *opts, int full)
|
|
|
{
|
|
@@ -464,87 +548,9 @@ int usage_with_options_internal(const char * const *usagestr,
|
|
|
if (opts->type != OPTION_GROUP)
|
|
|
fputc('\n', stderr);
|
|
|
|
|
|
- for (; opts->type != OPTION_END; opts++) {
|
|
|
- size_t pos;
|
|
|
- int pad;
|
|
|
-
|
|
|
- if (opts->type == OPTION_GROUP) {
|
|
|
- fputc('\n', stderr);
|
|
|
- if (*opts->help)
|
|
|
- fprintf(stderr, "%s\n", opts->help);
|
|
|
- continue;
|
|
|
- }
|
|
|
- if (!full && (opts->flags & PARSE_OPT_HIDDEN))
|
|
|
- continue;
|
|
|
-
|
|
|
- pos = fprintf(stderr, " ");
|
|
|
- if (opts->short_name)
|
|
|
- pos += fprintf(stderr, "-%c", opts->short_name);
|
|
|
- else
|
|
|
- pos += fprintf(stderr, " ");
|
|
|
-
|
|
|
- if (opts->long_name && opts->short_name)
|
|
|
- pos += fprintf(stderr, ", ");
|
|
|
- if (opts->long_name)
|
|
|
- pos += fprintf(stderr, "--%s", opts->long_name);
|
|
|
+ for ( ; opts->type != OPTION_END; opts++)
|
|
|
+ print_option_help(opts, full);
|
|
|
|
|
|
- switch (opts->type) {
|
|
|
- case OPTION_ARGUMENT:
|
|
|
- break;
|
|
|
- case OPTION_LONG:
|
|
|
- case OPTION_U64:
|
|
|
- case OPTION_INTEGER:
|
|
|
- case OPTION_UINTEGER:
|
|
|
- if (opts->flags & PARSE_OPT_OPTARG)
|
|
|
- if (opts->long_name)
|
|
|
- pos += fprintf(stderr, "[=<n>]");
|
|
|
- else
|
|
|
- pos += fprintf(stderr, "[<n>]");
|
|
|
- else
|
|
|
- pos += fprintf(stderr, " <n>");
|
|
|
- break;
|
|
|
- case OPTION_CALLBACK:
|
|
|
- if (opts->flags & PARSE_OPT_NOARG)
|
|
|
- break;
|
|
|
- /* FALLTHROUGH */
|
|
|
- case OPTION_STRING:
|
|
|
- if (opts->argh) {
|
|
|
- if (opts->flags & PARSE_OPT_OPTARG)
|
|
|
- if (opts->long_name)
|
|
|
- pos += fprintf(stderr, "[=<%s>]", opts->argh);
|
|
|
- else
|
|
|
- pos += fprintf(stderr, "[<%s>]", opts->argh);
|
|
|
- else
|
|
|
- pos += fprintf(stderr, " <%s>", opts->argh);
|
|
|
- } else {
|
|
|
- if (opts->flags & PARSE_OPT_OPTARG)
|
|
|
- if (opts->long_name)
|
|
|
- pos += fprintf(stderr, "[=...]");
|
|
|
- else
|
|
|
- pos += fprintf(stderr, "[...]");
|
|
|
- else
|
|
|
- pos += fprintf(stderr, " ...");
|
|
|
- }
|
|
|
- break;
|
|
|
- default: /* OPTION_{BIT,BOOLEAN,SET_UINT,SET_PTR} */
|
|
|
- case OPTION_END:
|
|
|
- case OPTION_GROUP:
|
|
|
- case OPTION_BIT:
|
|
|
- case OPTION_BOOLEAN:
|
|
|
- case OPTION_INCR:
|
|
|
- case OPTION_SET_UINT:
|
|
|
- case OPTION_SET_PTR:
|
|
|
- break;
|
|
|
- }
|
|
|
-
|
|
|
- if (pos <= USAGE_OPTS_WIDTH)
|
|
|
- pad = USAGE_OPTS_WIDTH - pos;
|
|
|
- else {
|
|
|
- fputc('\n', stderr);
|
|
|
- pad = USAGE_OPTS_WIDTH;
|
|
|
- }
|
|
|
- fprintf(stderr, "%*s%s\n", pad + USAGE_GAP, "", opts->help);
|
|
|
- }
|
|
|
fputc('\n', stderr);
|
|
|
|
|
|
return PARSE_OPT_HELP;
|
|
@@ -559,9 +565,44 @@ void usage_with_options(const char * const *usagestr,
|
|
|
}
|
|
|
|
|
|
int parse_options_usage(const char * const *usagestr,
|
|
|
- const struct option *opts)
|
|
|
+ const struct option *opts,
|
|
|
+ const char *optstr, bool short_opt)
|
|
|
{
|
|
|
- return usage_with_options_internal(usagestr, opts, 0);
|
|
|
+ if (!usagestr)
|
|
|
+ return PARSE_OPT_HELP;
|
|
|
+
|
|
|
+ fprintf(stderr, "\n usage: %s\n", *usagestr++);
|
|
|
+ while (*usagestr && **usagestr)
|
|
|
+ fprintf(stderr, " or: %s\n", *usagestr++);
|
|
|
+ while (*usagestr) {
|
|
|
+ fprintf(stderr, "%s%s\n",
|
|
|
+ **usagestr ? " " : "",
|
|
|
+ *usagestr);
|
|
|
+ usagestr++;
|
|
|
+ }
|
|
|
+ fputc('\n', stderr);
|
|
|
+
|
|
|
+ for ( ; opts->type != OPTION_END; opts++) {
|
|
|
+ if (short_opt) {
|
|
|
+ if (opts->short_name == *optstr)
|
|
|
+ break;
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (opts->long_name == NULL)
|
|
|
+ continue;
|
|
|
+
|
|
|
+ if (!prefixcmp(optstr, opts->long_name))
|
|
|
+ break;
|
|
|
+ if (!prefixcmp(optstr, "no-") &&
|
|
|
+ !prefixcmp(optstr + 3, opts->long_name))
|
|
|
+ break;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (opts->type != OPTION_END)
|
|
|
+ print_option_help(opts, 0);
|
|
|
+
|
|
|
+ return PARSE_OPT_HELP;
|
|
|
}
|
|
|
|
|
|
|