0001
0002 #include <linux/compiler.h>
0003 #include <linux/string.h>
0004 #include <linux/types.h>
0005 #include <stdio.h>
0006 #include <stdlib.h>
0007 #include <stdint.h>
0008 #include <string.h>
0009 #include <ctype.h>
0010 #include "subcmd-util.h"
0011 #include "parse-options.h"
0012 #include "subcmd-config.h"
0013 #include "pager.h"
0014
0015 #define OPT_SHORT 1
0016 #define OPT_UNSET 2
0017
0018 char *error_buf;
0019
0020 static int opterror(const struct option *opt, const char *reason, int flags)
0021 {
0022 if (flags & OPT_SHORT)
0023 fprintf(stderr, " Error: switch `%c' %s", opt->short_name, reason);
0024 else if (flags & OPT_UNSET)
0025 fprintf(stderr, " Error: option `no-%s' %s", opt->long_name, reason);
0026 else
0027 fprintf(stderr, " Error: option `%s' %s", opt->long_name, reason);
0028
0029 return -1;
0030 }
0031
0032 static const char *skip_prefix(const char *str, const char *prefix)
0033 {
0034 size_t len = strlen(prefix);
0035 return strncmp(str, prefix, len) ? NULL : str + len;
0036 }
0037
0038 static void optwarning(const struct option *opt, const char *reason, int flags)
0039 {
0040 if (flags & OPT_SHORT)
0041 fprintf(stderr, " Warning: switch `%c' %s", opt->short_name, reason);
0042 else if (flags & OPT_UNSET)
0043 fprintf(stderr, " Warning: option `no-%s' %s", opt->long_name, reason);
0044 else
0045 fprintf(stderr, " Warning: option `%s' %s", opt->long_name, reason);
0046 }
0047
0048 static int get_arg(struct parse_opt_ctx_t *p, const struct option *opt,
0049 int flags, const char **arg)
0050 {
0051 const char *res;
0052
0053 if (p->opt) {
0054 res = p->opt;
0055 p->opt = NULL;
0056 } else if ((opt->flags & PARSE_OPT_LASTARG_DEFAULT) && (p->argc == 1 ||
0057 **(p->argv + 1) == '-')) {
0058 res = (const char *)opt->defval;
0059 } else if (p->argc > 1) {
0060 p->argc--;
0061 res = *++p->argv;
0062 } else
0063 return opterror(opt, "requires a value", flags);
0064 if (arg)
0065 *arg = res;
0066 return 0;
0067 }
0068
0069 static int get_value(struct parse_opt_ctx_t *p,
0070 const struct option *opt, int flags)
0071 {
0072 const char *s, *arg = NULL;
0073 const int unset = flags & OPT_UNSET;
0074 int err;
0075
0076 if (unset && p->opt)
0077 return opterror(opt, "takes no value", flags);
0078 if (unset && (opt->flags & PARSE_OPT_NONEG))
0079 return opterror(opt, "isn't available", flags);
0080 if (opt->flags & PARSE_OPT_DISABLED)
0081 return opterror(opt, "is not usable", flags);
0082
0083 if (opt->flags & PARSE_OPT_EXCLUSIVE) {
0084 if (p->excl_opt && p->excl_opt != opt) {
0085 char msg[128];
0086
0087 if (((flags & OPT_SHORT) && p->excl_opt->short_name) ||
0088 p->excl_opt->long_name == NULL) {
0089 snprintf(msg, sizeof(msg), "cannot be used with switch `%c'",
0090 p->excl_opt->short_name);
0091 } else {
0092 snprintf(msg, sizeof(msg), "cannot be used with %s",
0093 p->excl_opt->long_name);
0094 }
0095 opterror(opt, msg, flags);
0096 return -3;
0097 }
0098 p->excl_opt = opt;
0099 }
0100 if (!(flags & OPT_SHORT) && p->opt) {
0101 switch (opt->type) {
0102 case OPTION_CALLBACK:
0103 if (!(opt->flags & PARSE_OPT_NOARG))
0104 break;
0105
0106 case OPTION_BOOLEAN:
0107 case OPTION_INCR:
0108 case OPTION_BIT:
0109 case OPTION_SET_UINT:
0110 case OPTION_SET_PTR:
0111 return opterror(opt, "takes no value", flags);
0112 case OPTION_END:
0113 case OPTION_ARGUMENT:
0114 case OPTION_GROUP:
0115 case OPTION_STRING:
0116 case OPTION_INTEGER:
0117 case OPTION_UINTEGER:
0118 case OPTION_LONG:
0119 case OPTION_ULONG:
0120 case OPTION_U64:
0121 default:
0122 break;
0123 }
0124 }
0125
0126 if (opt->flags & PARSE_OPT_NOBUILD) {
0127 char reason[128];
0128 bool noarg = false;
0129
0130 err = snprintf(reason, sizeof(reason),
0131 opt->flags & PARSE_OPT_CANSKIP ?
0132 "is being ignored because %s " :
0133 "is not available because %s",
0134 opt->build_opt);
0135 reason[sizeof(reason) - 1] = '\0';
0136
0137 if (err < 0)
0138 strncpy(reason, opt->flags & PARSE_OPT_CANSKIP ?
0139 "is being ignored" :
0140 "is not available",
0141 sizeof(reason));
0142
0143 if (!(opt->flags & PARSE_OPT_CANSKIP))
0144 return opterror(opt, reason, flags);
0145
0146 err = 0;
0147 if (unset)
0148 noarg = true;
0149 if (opt->flags & PARSE_OPT_NOARG)
0150 noarg = true;
0151 if (opt->flags & PARSE_OPT_OPTARG && !p->opt)
0152 noarg = true;
0153
0154 switch (opt->type) {
0155 case OPTION_BOOLEAN:
0156 case OPTION_INCR:
0157 case OPTION_BIT:
0158 case OPTION_SET_UINT:
0159 case OPTION_SET_PTR:
0160 case OPTION_END:
0161 case OPTION_ARGUMENT:
0162 case OPTION_GROUP:
0163 noarg = true;
0164 break;
0165 case OPTION_CALLBACK:
0166 case OPTION_STRING:
0167 case OPTION_INTEGER:
0168 case OPTION_UINTEGER:
0169 case OPTION_LONG:
0170 case OPTION_ULONG:
0171 case OPTION_U64:
0172 default:
0173 break;
0174 }
0175
0176 if (!noarg)
0177 err = get_arg(p, opt, flags, NULL);
0178 if (err)
0179 return err;
0180
0181 optwarning(opt, reason, flags);
0182 return 0;
0183 }
0184
0185 switch (opt->type) {
0186 case OPTION_BIT:
0187 if (unset)
0188 *(int *)opt->value &= ~opt->defval;
0189 else
0190 *(int *)opt->value |= opt->defval;
0191 return 0;
0192
0193 case OPTION_BOOLEAN:
0194 *(bool *)opt->value = unset ? false : true;
0195 if (opt->set)
0196 *(bool *)opt->set = true;
0197 return 0;
0198
0199 case OPTION_INCR:
0200 *(int *)opt->value = unset ? 0 : *(int *)opt->value + 1;
0201 return 0;
0202
0203 case OPTION_SET_UINT:
0204 *(unsigned int *)opt->value = unset ? 0 : opt->defval;
0205 return 0;
0206
0207 case OPTION_SET_PTR:
0208 *(void **)opt->value = unset ? NULL : (void *)opt->defval;
0209 return 0;
0210
0211 case OPTION_STRING:
0212 err = 0;
0213 if (unset)
0214 *(const char **)opt->value = NULL;
0215 else if (opt->flags & PARSE_OPT_OPTARG && !p->opt)
0216 *(const char **)opt->value = (const char *)opt->defval;
0217 else
0218 err = get_arg(p, opt, flags, (const char **)opt->value);
0219
0220 if (opt->set)
0221 *(bool *)opt->set = true;
0222
0223
0224 if (opt->flags & PARSE_OPT_NOEMPTY) {
0225 const char *val = *(const char **)opt->value;
0226
0227 if (!val)
0228 return err;
0229
0230
0231 if (val[0] == '\0') {
0232 *(const char **)opt->value = NULL;
0233 return 0;
0234 }
0235 }
0236
0237 return err;
0238
0239 case OPTION_CALLBACK:
0240 if (opt->set)
0241 *(bool *)opt->set = true;
0242
0243 if (unset)
0244 return (*opt->callback)(opt, NULL, 1) ? (-1) : 0;
0245 if (opt->flags & PARSE_OPT_NOARG)
0246 return (*opt->callback)(opt, NULL, 0) ? (-1) : 0;
0247 if (opt->flags & PARSE_OPT_OPTARG && !p->opt)
0248 return (*opt->callback)(opt, NULL, 0) ? (-1) : 0;
0249 if (get_arg(p, opt, flags, &arg))
0250 return -1;
0251 return (*opt->callback)(opt, arg, 0) ? (-1) : 0;
0252
0253 case OPTION_INTEGER:
0254 if (unset) {
0255 *(int *)opt->value = 0;
0256 return 0;
0257 }
0258 if (opt->flags & PARSE_OPT_OPTARG && !p->opt) {
0259 *(int *)opt->value = opt->defval;
0260 return 0;
0261 }
0262 if (get_arg(p, opt, flags, &arg))
0263 return -1;
0264 *(int *)opt->value = strtol(arg, (char **)&s, 10);
0265 if (*s)
0266 return opterror(opt, "expects a numerical value", flags);
0267 return 0;
0268
0269 case OPTION_UINTEGER:
0270 if (unset) {
0271 *(unsigned int *)opt->value = 0;
0272 return 0;
0273 }
0274 if (opt->flags & PARSE_OPT_OPTARG && !p->opt) {
0275 *(unsigned int *)opt->value = opt->defval;
0276 return 0;
0277 }
0278 if (get_arg(p, opt, flags, &arg))
0279 return -1;
0280 if (arg[0] == '-')
0281 return opterror(opt, "expects an unsigned numerical value", flags);
0282 *(unsigned int *)opt->value = strtol(arg, (char **)&s, 10);
0283 if (*s)
0284 return opterror(opt, "expects a numerical value", flags);
0285 return 0;
0286
0287 case OPTION_LONG:
0288 if (unset) {
0289 *(long *)opt->value = 0;
0290 return 0;
0291 }
0292 if (opt->flags & PARSE_OPT_OPTARG && !p->opt) {
0293 *(long *)opt->value = opt->defval;
0294 return 0;
0295 }
0296 if (get_arg(p, opt, flags, &arg))
0297 return -1;
0298 *(long *)opt->value = strtol(arg, (char **)&s, 10);
0299 if (*s)
0300 return opterror(opt, "expects a numerical value", flags);
0301 return 0;
0302
0303 case OPTION_ULONG:
0304 if (unset) {
0305 *(unsigned long *)opt->value = 0;
0306 return 0;
0307 }
0308 if (opt->flags & PARSE_OPT_OPTARG && !p->opt) {
0309 *(unsigned long *)opt->value = opt->defval;
0310 return 0;
0311 }
0312 if (get_arg(p, opt, flags, &arg))
0313 return -1;
0314 *(unsigned long *)opt->value = strtoul(arg, (char **)&s, 10);
0315 if (*s)
0316 return opterror(opt, "expects a numerical value", flags);
0317 return 0;
0318
0319 case OPTION_U64:
0320 if (unset) {
0321 *(u64 *)opt->value = 0;
0322 return 0;
0323 }
0324 if (opt->flags & PARSE_OPT_OPTARG && !p->opt) {
0325 *(u64 *)opt->value = opt->defval;
0326 return 0;
0327 }
0328 if (get_arg(p, opt, flags, &arg))
0329 return -1;
0330 if (arg[0] == '-')
0331 return opterror(opt, "expects an unsigned numerical value", flags);
0332 *(u64 *)opt->value = strtoull(arg, (char **)&s, 10);
0333 if (*s)
0334 return opterror(opt, "expects a numerical value", flags);
0335 return 0;
0336
0337 case OPTION_END:
0338 case OPTION_ARGUMENT:
0339 case OPTION_GROUP:
0340 default:
0341 die("should not happen, someone must be hit on the forehead");
0342 }
0343 }
0344
0345 static int parse_short_opt(struct parse_opt_ctx_t *p, const struct option *options)
0346 {
0347 retry:
0348 for (; options->type != OPTION_END; options++) {
0349 if (options->short_name == *p->opt) {
0350 p->opt = p->opt[1] ? p->opt + 1 : NULL;
0351 return get_value(p, options, OPT_SHORT);
0352 }
0353 }
0354
0355 if (options->parent) {
0356 options = options->parent;
0357 goto retry;
0358 }
0359
0360 return -2;
0361 }
0362
0363 static int parse_long_opt(struct parse_opt_ctx_t *p, const char *arg,
0364 const struct option *options)
0365 {
0366 const char *arg_end = strchr(arg, '=');
0367 const struct option *abbrev_option = NULL, *ambiguous_option = NULL;
0368 int abbrev_flags = 0, ambiguous_flags = 0;
0369
0370 if (!arg_end)
0371 arg_end = arg + strlen(arg);
0372
0373 retry:
0374 for (; options->type != OPTION_END; options++) {
0375 const char *rest;
0376 int flags = 0;
0377
0378 if (!options->long_name)
0379 continue;
0380
0381 rest = skip_prefix(arg, options->long_name);
0382 if (options->type == OPTION_ARGUMENT) {
0383 if (!rest)
0384 continue;
0385 if (*rest == '=')
0386 return opterror(options, "takes no value", flags);
0387 if (*rest)
0388 continue;
0389 p->out[p->cpidx++] = arg - 2;
0390 return 0;
0391 }
0392 if (!rest) {
0393 if (strstarts(options->long_name, "no-")) {
0394
0395
0396
0397
0398
0399
0400 rest = skip_prefix(arg, options->long_name + 3);
0401 if (rest) {
0402 flags |= OPT_UNSET;
0403 goto match;
0404 }
0405
0406 if (strstarts(options->long_name + 3, arg)) {
0407 flags |= OPT_UNSET;
0408 goto is_abbreviated;
0409 }
0410 }
0411
0412 if (!strncmp(options->long_name, arg, arg_end - arg)) {
0413 is_abbreviated:
0414 if (abbrev_option) {
0415
0416
0417
0418
0419
0420
0421 ambiguous_option = abbrev_option;
0422 ambiguous_flags = abbrev_flags;
0423 }
0424 if (!(flags & OPT_UNSET) && *arg_end)
0425 p->opt = arg_end + 1;
0426 abbrev_option = options;
0427 abbrev_flags = flags;
0428 continue;
0429 }
0430
0431 if (strstarts("no-", arg)) {
0432 flags |= OPT_UNSET;
0433 goto is_abbreviated;
0434 }
0435
0436 if (strncmp(arg, "no-", 3))
0437 continue;
0438 flags |= OPT_UNSET;
0439 rest = skip_prefix(arg + 3, options->long_name);
0440
0441 if (!rest && strstarts(options->long_name, arg + 3))
0442 goto is_abbreviated;
0443 if (!rest)
0444 continue;
0445 }
0446 match:
0447 if (*rest) {
0448 if (*rest != '=')
0449 continue;
0450 p->opt = rest + 1;
0451 }
0452 return get_value(p, options, flags);
0453 }
0454
0455 if (ambiguous_option) {
0456 fprintf(stderr,
0457 " Error: Ambiguous option: %s (could be --%s%s or --%s%s)\n",
0458 arg,
0459 (ambiguous_flags & OPT_UNSET) ? "no-" : "",
0460 ambiguous_option->long_name,
0461 (abbrev_flags & OPT_UNSET) ? "no-" : "",
0462 abbrev_option->long_name);
0463 return -1;
0464 }
0465 if (abbrev_option)
0466 return get_value(p, abbrev_option, abbrev_flags);
0467
0468 if (options->parent) {
0469 options = options->parent;
0470 goto retry;
0471 }
0472
0473 return -2;
0474 }
0475
0476 static void check_typos(const char *arg, const struct option *options)
0477 {
0478 if (strlen(arg) < 3)
0479 return;
0480
0481 if (strstarts(arg, "no-")) {
0482 fprintf(stderr, " Error: did you mean `--%s` (with two dashes ?)\n", arg);
0483 exit(129);
0484 }
0485
0486 for (; options->type != OPTION_END; options++) {
0487 if (!options->long_name)
0488 continue;
0489 if (strstarts(options->long_name, arg)) {
0490 fprintf(stderr, " Error: did you mean `--%s` (with two dashes ?)\n", arg);
0491 exit(129);
0492 }
0493 }
0494 }
0495
0496 static void parse_options_start(struct parse_opt_ctx_t *ctx,
0497 int argc, const char **argv, int flags)
0498 {
0499 memset(ctx, 0, sizeof(*ctx));
0500 ctx->argc = argc - 1;
0501 ctx->argv = argv + 1;
0502 ctx->out = argv;
0503 ctx->cpidx = ((flags & PARSE_OPT_KEEP_ARGV0) != 0);
0504 ctx->flags = flags;
0505 if ((flags & PARSE_OPT_KEEP_UNKNOWN) &&
0506 (flags & PARSE_OPT_STOP_AT_NON_OPTION))
0507 die("STOP_AT_NON_OPTION and KEEP_UNKNOWN don't go together");
0508 }
0509
0510 static int usage_with_options_internal(const char * const *,
0511 const struct option *, int,
0512 struct parse_opt_ctx_t *);
0513
0514 static int parse_options_step(struct parse_opt_ctx_t *ctx,
0515 const struct option *options,
0516 const char * const usagestr[])
0517 {
0518 int internal_help = !(ctx->flags & PARSE_OPT_NO_INTERNAL_HELP);
0519 int excl_short_opt = 1;
0520 const char *arg;
0521
0522
0523 ctx->opt = NULL;
0524
0525 for (; ctx->argc; ctx->argc--, ctx->argv++) {
0526 arg = ctx->argv[0];
0527 if (*arg != '-' || !arg[1]) {
0528 if (ctx->flags & PARSE_OPT_STOP_AT_NON_OPTION)
0529 break;
0530 ctx->out[ctx->cpidx++] = ctx->argv[0];
0531 continue;
0532 }
0533
0534 if (arg[1] != '-') {
0535 ctx->opt = ++arg;
0536 if (internal_help && *ctx->opt == 'h') {
0537 return usage_with_options_internal(usagestr, options, 0, ctx);
0538 }
0539 switch (parse_short_opt(ctx, options)) {
0540 case -1:
0541 return parse_options_usage(usagestr, options, arg, 1);
0542 case -2:
0543 goto unknown;
0544 case -3:
0545 goto exclusive;
0546 default:
0547 break;
0548 }
0549 if (ctx->opt)
0550 check_typos(arg, options);
0551 while (ctx->opt) {
0552 if (internal_help && *ctx->opt == 'h')
0553 return usage_with_options_internal(usagestr, options, 0, ctx);
0554 arg = ctx->opt;
0555 switch (parse_short_opt(ctx, options)) {
0556 case -1:
0557 return parse_options_usage(usagestr, options, arg, 1);
0558 case -2:
0559
0560
0561
0562
0563
0564 ctx->argv[0] = strdup(ctx->opt - 1);
0565 *(char *)ctx->argv[0] = '-';
0566 goto unknown;
0567 case -3:
0568 goto exclusive;
0569 default:
0570 break;
0571 }
0572 }
0573 continue;
0574 }
0575
0576 if (!arg[2]) {
0577 if (!(ctx->flags & PARSE_OPT_KEEP_DASHDASH)) {
0578 ctx->argc--;
0579 ctx->argv++;
0580 }
0581 break;
0582 }
0583
0584 arg += 2;
0585 if (internal_help && !strcmp(arg, "help-all"))
0586 return usage_with_options_internal(usagestr, options, 1, ctx);
0587 if (internal_help && !strcmp(arg, "help"))
0588 return usage_with_options_internal(usagestr, options, 0, ctx);
0589 if (!strcmp(arg, "list-opts"))
0590 return PARSE_OPT_LIST_OPTS;
0591 if (!strcmp(arg, "list-cmds"))
0592 return PARSE_OPT_LIST_SUBCMDS;
0593 switch (parse_long_opt(ctx, arg, options)) {
0594 case -1:
0595 return parse_options_usage(usagestr, options, arg, 0);
0596 case -2:
0597 goto unknown;
0598 case -3:
0599 excl_short_opt = 0;
0600 goto exclusive;
0601 default:
0602 break;
0603 }
0604 continue;
0605 unknown:
0606 if (!(ctx->flags & PARSE_OPT_KEEP_UNKNOWN))
0607 return PARSE_OPT_UNKNOWN;
0608 ctx->out[ctx->cpidx++] = ctx->argv[0];
0609 ctx->opt = NULL;
0610 }
0611 return PARSE_OPT_DONE;
0612
0613 exclusive:
0614 parse_options_usage(usagestr, options, arg, excl_short_opt);
0615 if ((excl_short_opt && ctx->excl_opt->short_name) ||
0616 ctx->excl_opt->long_name == NULL) {
0617 char opt = ctx->excl_opt->short_name;
0618 parse_options_usage(NULL, options, &opt, 1);
0619 } else {
0620 parse_options_usage(NULL, options, ctx->excl_opt->long_name, 0);
0621 }
0622 return PARSE_OPT_HELP;
0623 }
0624
0625 static int parse_options_end(struct parse_opt_ctx_t *ctx)
0626 {
0627 memmove(ctx->out + ctx->cpidx, ctx->argv, ctx->argc * sizeof(*ctx->out));
0628 ctx->out[ctx->cpidx + ctx->argc] = NULL;
0629 return ctx->cpidx + ctx->argc;
0630 }
0631
0632 int parse_options_subcommand(int argc, const char **argv, const struct option *options,
0633 const char *const subcommands[], const char *usagestr[], int flags)
0634 {
0635 struct parse_opt_ctx_t ctx;
0636
0637
0638 if (subcommands && !usagestr[0]) {
0639 char *buf = NULL;
0640
0641 astrcatf(&buf, "%s %s [<options>] {", subcmd_config.exec_name, argv[0]);
0642
0643 for (int i = 0; subcommands[i]; i++) {
0644 if (i)
0645 astrcat(&buf, "|");
0646 astrcat(&buf, subcommands[i]);
0647 }
0648 astrcat(&buf, "}");
0649
0650 usagestr[0] = buf;
0651 }
0652
0653 parse_options_start(&ctx, argc, argv, flags);
0654 switch (parse_options_step(&ctx, options, usagestr)) {
0655 case PARSE_OPT_HELP:
0656 exit(129);
0657 case PARSE_OPT_DONE:
0658 break;
0659 case PARSE_OPT_LIST_OPTS:
0660 while (options->type != OPTION_END) {
0661 if (options->long_name)
0662 printf("--%s ", options->long_name);
0663 options++;
0664 }
0665 putchar('\n');
0666 exit(130);
0667 case PARSE_OPT_LIST_SUBCMDS:
0668 if (subcommands) {
0669 for (int i = 0; subcommands[i]; i++)
0670 printf("%s ", subcommands[i]);
0671 }
0672 putchar('\n');
0673 exit(130);
0674 default:
0675 if (ctx.argv[0][1] == '-')
0676 astrcatf(&error_buf, "unknown option `%s'",
0677 ctx.argv[0] + 2);
0678 else
0679 astrcatf(&error_buf, "unknown switch `%c'", *ctx.opt);
0680 usage_with_options(usagestr, options);
0681 }
0682
0683 return parse_options_end(&ctx);
0684 }
0685
0686 int parse_options(int argc, const char **argv, const struct option *options,
0687 const char * const usagestr[], int flags)
0688 {
0689 return parse_options_subcommand(argc, argv, options, NULL,
0690 (const char **) usagestr, flags);
0691 }
0692
0693 #define USAGE_OPTS_WIDTH 24
0694 #define USAGE_GAP 2
0695
0696 static void print_option_help(const struct option *opts, int full)
0697 {
0698 size_t pos;
0699 int pad;
0700
0701 if (opts->type == OPTION_GROUP) {
0702 fputc('\n', stderr);
0703 if (*opts->help)
0704 fprintf(stderr, "%s\n", opts->help);
0705 return;
0706 }
0707 if (!full && (opts->flags & PARSE_OPT_HIDDEN))
0708 return;
0709 if (opts->flags & PARSE_OPT_DISABLED)
0710 return;
0711
0712 pos = fprintf(stderr, " ");
0713 if (opts->short_name)
0714 pos += fprintf(stderr, "-%c", opts->short_name);
0715 else
0716 pos += fprintf(stderr, " ");
0717
0718 if (opts->long_name && opts->short_name)
0719 pos += fprintf(stderr, ", ");
0720 if (opts->long_name)
0721 pos += fprintf(stderr, "--%s", opts->long_name);
0722
0723 switch (opts->type) {
0724 case OPTION_ARGUMENT:
0725 break;
0726 case OPTION_LONG:
0727 case OPTION_ULONG:
0728 case OPTION_U64:
0729 case OPTION_INTEGER:
0730 case OPTION_UINTEGER:
0731 if (opts->flags & PARSE_OPT_OPTARG)
0732 if (opts->long_name)
0733 pos += fprintf(stderr, "[=<n>]");
0734 else
0735 pos += fprintf(stderr, "[<n>]");
0736 else
0737 pos += fprintf(stderr, " <n>");
0738 break;
0739 case OPTION_CALLBACK:
0740 if (opts->flags & PARSE_OPT_NOARG)
0741 break;
0742
0743 case OPTION_STRING:
0744 if (opts->argh) {
0745 if (opts->flags & PARSE_OPT_OPTARG)
0746 if (opts->long_name)
0747 pos += fprintf(stderr, "[=<%s>]", opts->argh);
0748 else
0749 pos += fprintf(stderr, "[<%s>]", opts->argh);
0750 else
0751 pos += fprintf(stderr, " <%s>", opts->argh);
0752 } else {
0753 if (opts->flags & PARSE_OPT_OPTARG)
0754 if (opts->long_name)
0755 pos += fprintf(stderr, "[=...]");
0756 else
0757 pos += fprintf(stderr, "[...]");
0758 else
0759 pos += fprintf(stderr, " ...");
0760 }
0761 break;
0762 default:
0763 case OPTION_END:
0764 case OPTION_GROUP:
0765 case OPTION_BIT:
0766 case OPTION_BOOLEAN:
0767 case OPTION_INCR:
0768 case OPTION_SET_UINT:
0769 case OPTION_SET_PTR:
0770 break;
0771 }
0772
0773 if (pos <= USAGE_OPTS_WIDTH)
0774 pad = USAGE_OPTS_WIDTH - pos;
0775 else {
0776 fputc('\n', stderr);
0777 pad = USAGE_OPTS_WIDTH;
0778 }
0779 fprintf(stderr, "%*s%s\n", pad + USAGE_GAP, "", opts->help);
0780 if (opts->flags & PARSE_OPT_NOBUILD)
0781 fprintf(stderr, "%*s(not built-in because %s)\n",
0782 USAGE_OPTS_WIDTH + USAGE_GAP, "",
0783 opts->build_opt);
0784 }
0785
0786 static int option__cmp(const void *va, const void *vb)
0787 {
0788 const struct option *a = va, *b = vb;
0789 int sa = tolower(a->short_name), sb = tolower(b->short_name), ret;
0790
0791 if (sa == 0)
0792 sa = 'z' + 1;
0793 if (sb == 0)
0794 sb = 'z' + 1;
0795
0796 ret = sa - sb;
0797
0798 if (ret == 0) {
0799 const char *la = a->long_name ?: "",
0800 *lb = b->long_name ?: "";
0801 ret = strcmp(la, lb);
0802 }
0803
0804 return ret;
0805 }
0806
0807 static struct option *options__order(const struct option *opts)
0808 {
0809 int nr_opts = 0, nr_group = 0, len;
0810 const struct option *o = opts;
0811 struct option *opt, *ordered, *group;
0812
0813 for (o = opts; o->type != OPTION_END; o++)
0814 ++nr_opts;
0815
0816 len = sizeof(*o) * (nr_opts + 1);
0817 ordered = malloc(len);
0818 if (!ordered)
0819 goto out;
0820 memcpy(ordered, opts, len);
0821
0822
0823 for (opt = group = ordered; opt->type != OPTION_END; opt++) {
0824 if (opt->type == OPTION_GROUP) {
0825 qsort(group, nr_group, sizeof(*opt), option__cmp);
0826 group = opt + 1;
0827 nr_group = 0;
0828 continue;
0829 }
0830 nr_group++;
0831 }
0832 qsort(group, nr_group, sizeof(*opt), option__cmp);
0833
0834 out:
0835 return ordered;
0836 }
0837
0838 static bool option__in_argv(const struct option *opt, const struct parse_opt_ctx_t *ctx)
0839 {
0840 int i;
0841
0842 for (i = 1; i < ctx->argc; ++i) {
0843 const char *arg = ctx->argv[i];
0844
0845 if (arg[0] != '-') {
0846 if (arg[1] == '\0') {
0847 if (arg[0] == opt->short_name)
0848 return true;
0849 continue;
0850 }
0851
0852 if (opt->long_name && strcmp(opt->long_name, arg) == 0)
0853 return true;
0854
0855 if (opt->help && strcasestr(opt->help, arg) != NULL)
0856 return true;
0857
0858 continue;
0859 }
0860
0861 if (arg[1] == opt->short_name ||
0862 (arg[1] == '-' && opt->long_name && strcmp(opt->long_name, arg + 2) == 0))
0863 return true;
0864 }
0865
0866 return false;
0867 }
0868
0869 static int usage_with_options_internal(const char * const *usagestr,
0870 const struct option *opts, int full,
0871 struct parse_opt_ctx_t *ctx)
0872 {
0873 struct option *ordered;
0874
0875 if (!usagestr)
0876 return PARSE_OPT_HELP;
0877
0878 setup_pager();
0879
0880 if (error_buf) {
0881 fprintf(stderr, " Error: %s\n", error_buf);
0882 zfree(&error_buf);
0883 }
0884
0885 fprintf(stderr, "\n Usage: %s\n", *usagestr++);
0886 while (*usagestr && **usagestr)
0887 fprintf(stderr, " or: %s\n", *usagestr++);
0888 while (*usagestr) {
0889 fprintf(stderr, "%s%s\n",
0890 **usagestr ? " " : "",
0891 *usagestr);
0892 usagestr++;
0893 }
0894
0895 if (opts->type != OPTION_GROUP)
0896 fputc('\n', stderr);
0897
0898 ordered = options__order(opts);
0899 if (ordered)
0900 opts = ordered;
0901
0902 for ( ; opts->type != OPTION_END; opts++) {
0903 if (ctx && ctx->argc > 1 && !option__in_argv(opts, ctx))
0904 continue;
0905 print_option_help(opts, full);
0906 }
0907
0908 fputc('\n', stderr);
0909
0910 free(ordered);
0911
0912 return PARSE_OPT_HELP;
0913 }
0914
0915 void usage_with_options(const char * const *usagestr,
0916 const struct option *opts)
0917 {
0918 usage_with_options_internal(usagestr, opts, 0, NULL);
0919 exit(129);
0920 }
0921
0922 void usage_with_options_msg(const char * const *usagestr,
0923 const struct option *opts, const char *fmt, ...)
0924 {
0925 va_list ap;
0926 char *tmp = error_buf;
0927
0928 va_start(ap, fmt);
0929 if (vasprintf(&error_buf, fmt, ap) == -1)
0930 die("vasprintf failed");
0931 va_end(ap);
0932
0933 free(tmp);
0934
0935 usage_with_options_internal(usagestr, opts, 0, NULL);
0936 exit(129);
0937 }
0938
0939 int parse_options_usage(const char * const *usagestr,
0940 const struct option *opts,
0941 const char *optstr, bool short_opt)
0942 {
0943 if (!usagestr)
0944 goto opt;
0945
0946 fprintf(stderr, "\n Usage: %s\n", *usagestr++);
0947 while (*usagestr && **usagestr)
0948 fprintf(stderr, " or: %s\n", *usagestr++);
0949 while (*usagestr) {
0950 fprintf(stderr, "%s%s\n",
0951 **usagestr ? " " : "",
0952 *usagestr);
0953 usagestr++;
0954 }
0955 fputc('\n', stderr);
0956
0957 opt:
0958 for ( ; opts->type != OPTION_END; opts++) {
0959 if (short_opt) {
0960 if (opts->short_name == *optstr) {
0961 print_option_help(opts, 0);
0962 break;
0963 }
0964 continue;
0965 }
0966
0967 if (opts->long_name == NULL)
0968 continue;
0969
0970 if (strstarts(opts->long_name, optstr))
0971 print_option_help(opts, 0);
0972 if (strstarts("no-", optstr) &&
0973 strstarts(opts->long_name, optstr + 3))
0974 print_option_help(opts, 0);
0975 }
0976
0977 return PARSE_OPT_HELP;
0978 }
0979
0980
0981 int parse_opt_verbosity_cb(const struct option *opt,
0982 const char *arg __maybe_unused,
0983 int unset)
0984 {
0985 int *target = opt->value;
0986
0987 if (unset)
0988
0989 *target = 0;
0990 else if (opt->short_name == 'v') {
0991 if (*target >= 0)
0992 (*target)++;
0993 else
0994 *target = 1;
0995 } else {
0996 if (*target <= 0)
0997 (*target)--;
0998 else
0999 *target = -1;
1000 }
1001 return 0;
1002 }
1003
1004 static struct option *
1005 find_option(struct option *opts, int shortopt, const char *longopt)
1006 {
1007 for (; opts->type != OPTION_END; opts++) {
1008 if ((shortopt && opts->short_name == shortopt) ||
1009 (opts->long_name && longopt &&
1010 !strcmp(opts->long_name, longopt)))
1011 return opts;
1012 }
1013 return NULL;
1014 }
1015
1016 void set_option_flag(struct option *opts, int shortopt, const char *longopt,
1017 int flag)
1018 {
1019 struct option *opt = find_option(opts, shortopt, longopt);
1020
1021 if (opt)
1022 opt->flags |= flag;
1023 return;
1024 }
1025
1026 void set_option_nobuild(struct option *opts, int shortopt,
1027 const char *longopt,
1028 const char *build_opt,
1029 bool can_skip)
1030 {
1031 struct option *opt = find_option(opts, shortopt, longopt);
1032
1033 if (!opt)
1034 return;
1035
1036 opt->flags |= PARSE_OPT_NOBUILD;
1037 opt->flags |= can_skip ? PARSE_OPT_CANSKIP : 0;
1038 opt->build_opt = build_opt;
1039 }