1 // SPDX-License-Identifier: GPL-2.0 2 #include <linux/compiler.h> 3 #include <linux/string.h> 4 #include <linux/types.h> 5 #include <stdio.h> 6 #include <stdlib.h> 7 #include <stdint.h> 8 #include <string.h> 9 #include <ctype.h> 10 #include "subcmd-util.h" 11 #include "parse-options.h" 12 #include "subcmd-config.h" 13 #include "pager.h" 14 15 #define OPT_SHORT 1 16 #define OPT_UNSET 2 17 18 char *error_buf; 19 20 static int opterror(const struct option *opt, const char *reason, int flags) 21 { 22 if (flags & OPT_SHORT) 23 fprintf(stderr, " Error: switch `%c' %s", opt->short_name, reason); 24 else if (flags & OPT_UNSET) 25 fprintf(stderr, " Error: option `no-%s' %s", opt->long_name, reason); 26 else 27 fprintf(stderr, " Error: option `%s' %s", opt->long_name, reason); 28 29 return -1; 30 } 31 32 static const char *skip_prefix(const char *str, const char *prefix) 33 { 34 size_t len = strlen(prefix); 35 return strncmp(str, prefix, len) ? NULL : str + len; 36 } 37 38 static void optwarning(const struct option *opt, const char *reason, int flags) 39 { 40 if (flags & OPT_SHORT) 41 fprintf(stderr, " Warning: switch `%c' %s", opt->short_name, reason); 42 else if (flags & OPT_UNSET) 43 fprintf(stderr, " Warning: option `no-%s' %s", opt->long_name, reason); 44 else 45 fprintf(stderr, " Warning: option `%s' %s", opt->long_name, reason); 46 } 47 48 static int get_arg(struct parse_opt_ctx_t *p, const struct option *opt, 49 int flags, const char **arg) 50 { 51 const char *res; 52 53 if (p->opt) { 54 res = p->opt; 55 p->opt = NULL; 56 } else if ((opt->flags & PARSE_OPT_LASTARG_DEFAULT) && (p->argc == 1 || 57 **(p->argv + 1) == '-')) { 58 res = (const char *)opt->defval; 59 } else if (p->argc > 1) { 60 p->argc--; 61 res = *++p->argv; 62 } else 63 return opterror(opt, "requires a value", flags); 64 if (arg) 65 *arg = res; 66 return 0; 67 } 68 69 static int get_value(struct parse_opt_ctx_t *p, 70 const struct option *opt, int flags) 71 { 72 const char *s, *arg = NULL; 73 const int unset = flags & OPT_UNSET; 74 int err; 75 76 if (unset && p->opt) 77 return opterror(opt, "takes no value", flags); 78 if (unset && (opt->flags & PARSE_OPT_NONEG)) 79 return opterror(opt, "isn't available", flags); 80 if (opt->flags & PARSE_OPT_DISABLED) 81 return opterror(opt, "is not usable", flags); 82 83 if (opt->flags & PARSE_OPT_EXCLUSIVE) { 84 if (p->excl_opt && p->excl_opt != opt) { 85 char msg[128]; 86 87 if (((flags & OPT_SHORT) && p->excl_opt->short_name) || 88 p->excl_opt->long_name == NULL) { 89 snprintf(msg, sizeof(msg), "cannot be used with switch `%c'", 90 p->excl_opt->short_name); 91 } else { 92 snprintf(msg, sizeof(msg), "cannot be used with %s", 93 p->excl_opt->long_name); 94 } 95 opterror(opt, msg, flags); 96 return -3; 97 } 98 p->excl_opt = opt; 99 } 100 if (!(flags & OPT_SHORT) && p->opt) { 101 switch (opt->type) { 102 case OPTION_CALLBACK: 103 if (!(opt->flags & PARSE_OPT_NOARG)) 104 break; 105 /* FALLTHROUGH */ 106 case OPTION_BOOLEAN: 107 case OPTION_INCR: 108 case OPTION_BIT: 109 case OPTION_SET_UINT: 110 case OPTION_SET_PTR: 111 return opterror(opt, "takes no value", flags); 112 case OPTION_END: 113 case OPTION_ARGUMENT: 114 case OPTION_GROUP: 115 case OPTION_STRING: 116 case OPTION_INTEGER: 117 case OPTION_UINTEGER: 118 case OPTION_LONG: 119 case OPTION_ULONG: 120 case OPTION_U64: 121 default: 122 break; 123 } 124 } 125 126 if (opt->flags & PARSE_OPT_NOBUILD) { 127 char reason[128]; 128 bool noarg = false; 129 130 err = snprintf(reason, sizeof(reason), 131 opt->flags & PARSE_OPT_CANSKIP ? 132 "is being ignored because %s " : 133 "is not available because %s", 134 opt->build_opt); 135 reason[sizeof(reason) - 1] = '\0'; 136 137 if (err < 0) 138 strncpy(reason, opt->flags & PARSE_OPT_CANSKIP ? 139 "is being ignored" : 140 "is not available", 141 sizeof(reason)); 142 143 if (!(opt->flags & PARSE_OPT_CANSKIP)) 144 return opterror(opt, reason, flags); 145 146 err = 0; 147 if (unset) 148 noarg = true; 149 if (opt->flags & PARSE_OPT_NOARG) 150 noarg = true; 151 if (opt->flags & PARSE_OPT_OPTARG && !p->opt) 152 noarg = true; 153 154 switch (opt->type) { 155 case OPTION_BOOLEAN: 156 case OPTION_INCR: 157 case OPTION_BIT: 158 case OPTION_SET_UINT: 159 case OPTION_SET_PTR: 160 case OPTION_END: 161 case OPTION_ARGUMENT: 162 case OPTION_GROUP: 163 noarg = true; 164 break; 165 case OPTION_CALLBACK: 166 case OPTION_STRING: 167 case OPTION_INTEGER: 168 case OPTION_UINTEGER: 169 case OPTION_LONG: 170 case OPTION_ULONG: 171 case OPTION_U64: 172 default: 173 break; 174 } 175 176 if (!noarg) 177 err = get_arg(p, opt, flags, NULL); 178 if (err) 179 return err; 180 181 optwarning(opt, reason, flags); 182 return 0; 183 } 184 185 switch (opt->type) { 186 case OPTION_BIT: 187 if (unset) 188 *(int *)opt->value &= ~opt->defval; 189 else 190 *(int *)opt->value |= opt->defval; 191 return 0; 192 193 case OPTION_BOOLEAN: 194 *(bool *)opt->value = unset ? false : true; 195 if (opt->set) 196 *(bool *)opt->set = true; 197 return 0; 198 199 case OPTION_INCR: 200 *(int *)opt->value = unset ? 0 : *(int *)opt->value + 1; 201 return 0; 202 203 case OPTION_SET_UINT: 204 *(unsigned int *)opt->value = unset ? 0 : opt->defval; 205 return 0; 206 207 case OPTION_SET_PTR: 208 *(void **)opt->value = unset ? NULL : (void *)opt->defval; 209 return 0; 210 211 case OPTION_STRING: 212 err = 0; 213 if (unset) 214 *(const char **)opt->value = NULL; 215 else if (opt->flags & PARSE_OPT_OPTARG && !p->opt) 216 *(const char **)opt->value = (const char *)opt->defval; 217 else 218 err = get_arg(p, opt, flags, (const char **)opt->value); 219 220 if (opt->set) 221 *(bool *)opt->set = true; 222 223 /* PARSE_OPT_NOEMPTY: Allow NULL but disallow empty string. */ 224 if (opt->flags & PARSE_OPT_NOEMPTY) { 225 const char *val = *(const char **)opt->value; 226 227 if (!val) 228 return err; 229 230 /* Similar to unset if we are given an empty string. */ 231 if (val[0] == '\0') { 232 *(const char **)opt->value = NULL; 233 return 0; 234 } 235 } 236 237 return err; 238 239 case OPTION_CALLBACK: 240 if (opt->set) 241 *(bool *)opt->set = true; 242 243 if (unset) 244 return (*opt->callback)(opt, NULL, 1) ? (-1) : 0; 245 if (opt->flags & PARSE_OPT_NOARG) 246 return (*opt->callback)(opt, NULL, 0) ? (-1) : 0; 247 if (opt->flags & PARSE_OPT_OPTARG && !p->opt) 248 return (*opt->callback)(opt, NULL, 0) ? (-1) : 0; 249 if (get_arg(p, opt, flags, &arg)) 250 return -1; 251 return (*opt->callback)(opt, arg, 0) ? (-1) : 0; 252 253 case OPTION_INTEGER: 254 if (unset) { 255 *(int *)opt->value = 0; 256 return 0; 257 } 258 if (opt->flags & PARSE_OPT_OPTARG && !p->opt) { 259 *(int *)opt->value = opt->defval; 260 return 0; 261 } 262 if (get_arg(p, opt, flags, &arg)) 263 return -1; 264 *(int *)opt->value = strtol(arg, (char **)&s, 10); 265 if (*s) 266 return opterror(opt, "expects a numerical value", flags); 267 return 0; 268 269 case OPTION_UINTEGER: 270 if (unset) { 271 *(unsigned int *)opt->value = 0; 272 return 0; 273 } 274 if (opt->flags & PARSE_OPT_OPTARG && !p->opt) { 275 *(unsigned int *)opt->value = opt->defval; 276 return 0; 277 } 278 if (get_arg(p, opt, flags, &arg)) 279 return -1; 280 if (arg[0] == '-') 281 return opterror(opt, "expects an unsigned numerical value", flags); 282 *(unsigned int *)opt->value = strtol(arg, (char **)&s, 10); 283 if (*s) 284 return opterror(opt, "expects a numerical value", flags); 285 return 0; 286 287 case OPTION_LONG: 288 if (unset) { 289 *(long *)opt->value = 0; 290 return 0; 291 } 292 if (opt->flags & PARSE_OPT_OPTARG && !p->opt) { 293 *(long *)opt->value = opt->defval; 294 return 0; 295 } 296 if (get_arg(p, opt, flags, &arg)) 297 return -1; 298 *(long *)opt->value = strtol(arg, (char **)&s, 10); 299 if (*s) 300 return opterror(opt, "expects a numerical value", flags); 301 return 0; 302 303 case OPTION_ULONG: 304 if (unset) { 305 *(unsigned long *)opt->value = 0; 306 return 0; 307 } 308 if (opt->flags & PARSE_OPT_OPTARG && !p->opt) { 309 *(unsigned long *)opt->value = opt->defval; 310 return 0; 311 } 312 if (get_arg(p, opt, flags, &arg)) 313 return -1; 314 *(unsigned long *)opt->value = strtoul(arg, (char **)&s, 10); 315 if (*s) 316 return opterror(opt, "expects a numerical value", flags); 317 return 0; 318 319 case OPTION_U64: 320 if (unset) { 321 *(u64 *)opt->value = 0; 322 return 0; 323 } 324 if (opt->flags & PARSE_OPT_OPTARG && !p->opt) { 325 *(u64 *)opt->value = opt->defval; 326 return 0; 327 } 328 if (get_arg(p, opt, flags, &arg)) 329 return -1; 330 if (arg[0] == '-') 331 return opterror(opt, "expects an unsigned numerical value", flags); 332 *(u64 *)opt->value = strtoull(arg, (char **)&s, 10); 333 if (*s) 334 return opterror(opt, "expects a numerical value", flags); 335 return 0; 336 337 case OPTION_END: 338 case OPTION_ARGUMENT: 339 case OPTION_GROUP: 340 default: 341 die("should not happen, someone must be hit on the forehead"); 342 } 343 } 344 345 static int parse_short_opt(struct parse_opt_ctx_t *p, const struct option *options) 346 { 347 retry: 348 for (; options->type != OPTION_END; options++) { 349 if (options->short_name == *p->opt) { 350 p->opt = p->opt[1] ? p->opt + 1 : NULL; 351 return get_value(p, options, OPT_SHORT); 352 } 353 } 354 355 if (options->parent) { 356 options = options->parent; 357 goto retry; 358 } 359 360 return -2; 361 } 362 363 static int parse_long_opt(struct parse_opt_ctx_t *p, const char *arg, 364 const struct option *options) 365 { 366 const char *arg_end = strchr(arg, '='); 367 const struct option *abbrev_option = NULL, *ambiguous_option = NULL; 368 int abbrev_flags = 0, ambiguous_flags = 0; 369 370 if (!arg_end) 371 arg_end = arg + strlen(arg); 372 373 retry: 374 for (; options->type != OPTION_END; options++) { 375 const char *rest; 376 int flags = 0; 377 378 if (!options->long_name) 379 continue; 380 381 rest = skip_prefix(arg, options->long_name); 382 if (options->type == OPTION_ARGUMENT) { 383 if (!rest) 384 continue; 385 if (*rest == '=') 386 return opterror(options, "takes no value", flags); 387 if (*rest) 388 continue; 389 p->out[p->cpidx++] = arg - 2; 390 return 0; 391 } 392 if (!rest) { 393 if (strstarts(options->long_name, "no-")) { 394 /* 395 * The long name itself starts with "no-", so 396 * accept the option without "no-" so that users 397 * do not have to enter "no-no-" to get the 398 * negation. 399 */ 400 rest = skip_prefix(arg, options->long_name + 3); 401 if (rest) { 402 flags |= OPT_UNSET; 403 goto match; 404 } 405 /* Abbreviated case */ 406 if (strstarts(options->long_name + 3, arg)) { 407 flags |= OPT_UNSET; 408 goto is_abbreviated; 409 } 410 } 411 /* abbreviated? */ 412 if (!strncmp(options->long_name, arg, arg_end - arg)) { 413 is_abbreviated: 414 if (abbrev_option) { 415 /* 416 * If this is abbreviated, it is 417 * ambiguous. So when there is no 418 * exact match later, we need to 419 * error out. 420 */ 421 ambiguous_option = abbrev_option; 422 ambiguous_flags = abbrev_flags; 423 } 424 if (!(flags & OPT_UNSET) && *arg_end) 425 p->opt = arg_end + 1; 426 abbrev_option = options; 427 abbrev_flags = flags; 428 continue; 429 } 430 /* negated and abbreviated very much? */ 431 if (strstarts("no-", arg)) { 432 flags |= OPT_UNSET; 433 goto is_abbreviated; 434 } 435 /* negated? */ 436 if (strncmp(arg, "no-", 3)) 437 continue; 438 flags |= OPT_UNSET; 439 rest = skip_prefix(arg + 3, options->long_name); 440 /* abbreviated and negated? */ 441 if (!rest && strstarts(options->long_name, arg + 3)) 442 goto is_abbreviated; 443 if (!rest) 444 continue; 445 } 446 match: 447 if (*rest) { 448 if (*rest != '=') 449 continue; 450 p->opt = rest + 1; 451 } 452 return get_value(p, options, flags); 453 } 454 455 if (ambiguous_option) { 456 fprintf(stderr, 457 " Error: Ambiguous option: %s (could be --%s%s or --%s%s)\n", 458 arg, 459 (ambiguous_flags & OPT_UNSET) ? "no-" : "", 460 ambiguous_option->long_name, 461 (abbrev_flags & OPT_UNSET) ? "no-" : "", 462 abbrev_option->long_name); 463 return -1; 464 } 465 if (abbrev_option) 466 return get_value(p, abbrev_option, abbrev_flags); 467 468 if (options->parent) { 469 options = options->parent; 470 goto retry; 471 } 472 473 return -2; 474 } 475 476 static void check_typos(const char *arg, const struct option *options) 477 { 478 if (strlen(arg) < 3) 479 return; 480 481 if (strstarts(arg, "no-")) { 482 fprintf(stderr, " Error: did you mean `--%s` (with two dashes ?)\n", arg); 483 exit(129); 484 } 485 486 for (; options->type != OPTION_END; options++) { 487 if (!options->long_name) 488 continue; 489 if (strstarts(options->long_name, arg)) { 490 fprintf(stderr, " Error: did you mean `--%s` (with two dashes ?)\n", arg); 491 exit(129); 492 } 493 } 494 } 495 496 static void parse_options_start(struct parse_opt_ctx_t *ctx, 497 int argc, const char **argv, int flags) 498 { 499 memset(ctx, 0, sizeof(*ctx)); 500 ctx->argc = argc - 1; 501 ctx->argv = argv + 1; 502 ctx->out = argv; 503 ctx->cpidx = ((flags & PARSE_OPT_KEEP_ARGV0) != 0); 504 ctx->flags = flags; 505 if ((flags & PARSE_OPT_KEEP_UNKNOWN) && 506 (flags & PARSE_OPT_STOP_AT_NON_OPTION)) 507 die("STOP_AT_NON_OPTION and KEEP_UNKNOWN don't go together"); 508 } 509 510 static int usage_with_options_internal(const char * const *, 511 const struct option *, int, 512 struct parse_opt_ctx_t *); 513 514 static int parse_options_step(struct parse_opt_ctx_t *ctx, 515 const struct option *options, 516 const char * const usagestr[]) 517 { 518 int internal_help = !(ctx->flags & PARSE_OPT_NO_INTERNAL_HELP); 519 int excl_short_opt = 1; 520 const char *arg; 521 522 /* we must reset ->opt, unknown short option leave it dangling */ 523 ctx->opt = NULL; 524 525 for (; ctx->argc; ctx->argc--, ctx->argv++) { 526 arg = ctx->argv[0]; 527 if (*arg != '-' || !arg[1]) { 528 if (ctx->flags & PARSE_OPT_STOP_AT_NON_OPTION) 529 break; 530 ctx->out[ctx->cpidx++] = ctx->argv[0]; 531 continue; 532 } 533 534 if (arg[1] != '-') { 535 ctx->opt = ++arg; 536 if (internal_help && *ctx->opt == 'h') { 537 return usage_with_options_internal(usagestr, options, 0, ctx); 538 } 539 switch (parse_short_opt(ctx, options)) { 540 case -1: 541 return parse_options_usage(usagestr, options, arg, 1); 542 case -2: 543 goto unknown; 544 case -3: 545 goto exclusive; 546 default: 547 break; 548 } 549 if (ctx->opt) 550 check_typos(arg, options); 551 while (ctx->opt) { 552 if (internal_help && *ctx->opt == 'h') 553 return usage_with_options_internal(usagestr, options, 0, ctx); 554 arg = ctx->opt; 555 switch (parse_short_opt(ctx, options)) { 556 case -1: 557 return parse_options_usage(usagestr, options, arg, 1); 558 case -2: 559 /* fake a short option thing to hide the fact that we may have 560 * started to parse aggregated stuff 561 * 562 * This is leaky, too bad. 563 */ 564 ctx->argv[0] = strdup(ctx->opt - 1); 565 *(char *)ctx->argv[0] = '-'; 566 goto unknown; 567 case -3: 568 goto exclusive; 569 default: 570 break; 571 } 572 } 573 continue; 574 } 575 576 if (!arg[2]) { /* "--" */ 577 if (!(ctx->flags & PARSE_OPT_KEEP_DASHDASH)) { 578 ctx->argc--; 579 ctx->argv++; 580 } 581 break; 582 } 583 584 arg += 2; 585 if (internal_help && !strcmp(arg, "help-all")) 586 return usage_with_options_internal(usagestr, options, 1, ctx); 587 if (internal_help && !strcmp(arg, "help")) 588 return usage_with_options_internal(usagestr, options, 0, ctx); 589 if (!strcmp(arg, "list-opts")) 590 return PARSE_OPT_LIST_OPTS; 591 if (!strcmp(arg, "list-cmds")) 592 return PARSE_OPT_LIST_SUBCMDS; 593 switch (parse_long_opt(ctx, arg, options)) { 594 case -1: 595 return parse_options_usage(usagestr, options, arg, 0); 596 case -2: 597 goto unknown; 598 case -3: 599 excl_short_opt = 0; 600 goto exclusive; 601 default: 602 break; 603 } 604 continue; 605 unknown: 606 if (!(ctx->flags & PARSE_OPT_KEEP_UNKNOWN)) 607 return PARSE_OPT_UNKNOWN; 608 ctx->out[ctx->cpidx++] = ctx->argv[0]; 609 ctx->opt = NULL; 610 } 611 return PARSE_OPT_DONE; 612 613 exclusive: 614 parse_options_usage(usagestr, options, arg, excl_short_opt); 615 if ((excl_short_opt && ctx->excl_opt->short_name) || 616 ctx->excl_opt->long_name == NULL) { 617 char opt = ctx->excl_opt->short_name; 618 parse_options_usage(NULL, options, &opt, 1); 619 } else { 620 parse_options_usage(NULL, options, ctx->excl_opt->long_name, 0); 621 } 622 return PARSE_OPT_HELP; 623 } 624 625 static int parse_options_end(struct parse_opt_ctx_t *ctx) 626 { 627 memmove(ctx->out + ctx->cpidx, ctx->argv, ctx->argc * sizeof(*ctx->out)); 628 ctx->out[ctx->cpidx + ctx->argc] = NULL; 629 return ctx->cpidx + ctx->argc; 630 } 631 632 int parse_options_subcommand(int argc, const char **argv, const struct option *options, 633 const char *const subcommands[], const char *usagestr[], int flags) 634 { 635 struct parse_opt_ctx_t ctx; 636 char *buf = NULL; 637 638 /* build usage string if it's not provided */ 639 if (subcommands && !usagestr[0]) { 640 astrcatf(&buf, "%s %s [<options>] {", subcmd_config.exec_name, argv[0]); 641 642 for (int i = 0; subcommands[i]; i++) { 643 if (i) 644 astrcat(&buf, "|"); 645 astrcat(&buf, subcommands[i]); 646 } 647 astrcat(&buf, "}"); 648 649 usagestr[0] = buf; 650 } 651 652 parse_options_start(&ctx, argc, argv, flags); 653 switch (parse_options_step(&ctx, options, usagestr)) { 654 case PARSE_OPT_HELP: 655 exit(129); 656 case PARSE_OPT_DONE: 657 break; 658 case PARSE_OPT_LIST_OPTS: 659 while (options->type != OPTION_END) { 660 if (options->long_name) 661 printf("--%s ", options->long_name); 662 options++; 663 } 664 putchar('\n'); 665 exit(130); 666 case PARSE_OPT_LIST_SUBCMDS: 667 if (subcommands) { 668 for (int i = 0; subcommands[i]; i++) 669 printf("%s ", subcommands[i]); 670 } 671 putchar('\n'); 672 exit(130); 673 default: /* PARSE_OPT_UNKNOWN */ 674 if (ctx.argv[0][1] == '-') 675 astrcatf(&error_buf, "unknown option `%s'", 676 ctx.argv[0] + 2); 677 else 678 astrcatf(&error_buf, "unknown switch `%c'", *ctx.opt); 679 usage_with_options(usagestr, options); 680 } 681 if (buf) { 682 usagestr[0] = NULL; 683 free(buf); 684 } 685 return parse_options_end(&ctx); 686 } 687 688 int parse_options(int argc, const char **argv, const struct option *options, 689 const char * const usagestr[], int flags) 690 { 691 return parse_options_subcommand(argc, argv, options, NULL, 692 (const char **) usagestr, flags); 693 } 694 695 #define USAGE_OPTS_WIDTH 24 696 #define USAGE_GAP 2 697 698 static void print_option_help(const struct option *opts, int full) 699 { 700 size_t pos; 701 int pad; 702 703 if (opts->type == OPTION_GROUP) { 704 fputc('\n', stderr); 705 if (*opts->help) 706 fprintf(stderr, "%s\n", opts->help); 707 return; 708 } 709 if (!full && (opts->flags & PARSE_OPT_HIDDEN)) 710 return; 711 if (opts->flags & PARSE_OPT_DISABLED) 712 return; 713 714 pos = fprintf(stderr, " "); 715 if (opts->short_name) 716 pos += fprintf(stderr, "-%c", opts->short_name); 717 else 718 pos += fprintf(stderr, " "); 719 720 if (opts->long_name && opts->short_name) 721 pos += fprintf(stderr, ", "); 722 if (opts->long_name) 723 pos += fprintf(stderr, "--%s", opts->long_name); 724 725 switch (opts->type) { 726 case OPTION_ARGUMENT: 727 break; 728 case OPTION_LONG: 729 case OPTION_ULONG: 730 case OPTION_U64: 731 case OPTION_INTEGER: 732 case OPTION_UINTEGER: 733 if (opts->flags & PARSE_OPT_OPTARG) 734 if (opts->long_name) 735 pos += fprintf(stderr, "[=<n>]"); 736 else 737 pos += fprintf(stderr, "[<n>]"); 738 else 739 pos += fprintf(stderr, " <n>"); 740 break; 741 case OPTION_CALLBACK: 742 if (opts->flags & PARSE_OPT_NOARG) 743 break; 744 /* FALLTHROUGH */ 745 case OPTION_STRING: 746 if (opts->argh) { 747 if (opts->flags & PARSE_OPT_OPTARG) 748 if (opts->long_name) 749 pos += fprintf(stderr, "[=<%s>]", opts->argh); 750 else 751 pos += fprintf(stderr, "[<%s>]", opts->argh); 752 else 753 pos += fprintf(stderr, " <%s>", opts->argh); 754 } else { 755 if (opts->flags & PARSE_OPT_OPTARG) 756 if (opts->long_name) 757 pos += fprintf(stderr, "[=...]"); 758 else 759 pos += fprintf(stderr, "[...]"); 760 else 761 pos += fprintf(stderr, " ..."); 762 } 763 break; 764 default: /* OPTION_{BIT,BOOLEAN,SET_UINT,SET_PTR} */ 765 case OPTION_END: 766 case OPTION_GROUP: 767 case OPTION_BIT: 768 case OPTION_BOOLEAN: 769 case OPTION_INCR: 770 case OPTION_SET_UINT: 771 case OPTION_SET_PTR: 772 break; 773 } 774 775 if (pos <= USAGE_OPTS_WIDTH) 776 pad = USAGE_OPTS_WIDTH - pos; 777 else { 778 fputc('\n', stderr); 779 pad = USAGE_OPTS_WIDTH; 780 } 781 fprintf(stderr, "%*s%s\n", pad + USAGE_GAP, "", opts->help); 782 if (opts->flags & PARSE_OPT_NOBUILD) 783 fprintf(stderr, "%*s(not built-in because %s)\n", 784 USAGE_OPTS_WIDTH + USAGE_GAP, "", 785 opts->build_opt); 786 } 787 788 static int option__cmp(const void *va, const void *vb) 789 { 790 const struct option *a = va, *b = vb; 791 int sa = tolower(a->short_name), sb = tolower(b->short_name), ret; 792 793 if (sa == 0) 794 sa = 'z' + 1; 795 if (sb == 0) 796 sb = 'z' + 1; 797 798 ret = sa - sb; 799 800 if (ret == 0) { 801 const char *la = a->long_name ?: "", 802 *lb = b->long_name ?: ""; 803 ret = strcmp(la, lb); 804 } 805 806 return ret; 807 } 808 809 static struct option *options__order(const struct option *opts) 810 { 811 int nr_opts = 0, nr_group = 0, nr_parent = 0, len; 812 const struct option *o, *p = opts; 813 struct option *opt, *ordered = NULL, *group; 814 815 /* flatten the options that have parents */ 816 for (p = opts; p != NULL; p = o->parent) { 817 for (o = p; o->type != OPTION_END; o++) 818 ++nr_opts; 819 820 /* 821 * the length is given by the number of options plus a null 822 * terminator for the last loop iteration. 823 */ 824 len = sizeof(*o) * (nr_opts + !o->parent); 825 group = realloc(ordered, len); 826 if (!group) 827 goto out; 828 ordered = group; 829 memcpy(&ordered[nr_parent], p, sizeof(*o) * (nr_opts - nr_parent)); 830 831 nr_parent = nr_opts; 832 } 833 /* copy the last OPTION_END */ 834 memcpy(&ordered[nr_opts], o, sizeof(*o)); 835 836 /* sort each option group individually */ 837 for (opt = group = ordered; opt->type != OPTION_END; opt++) { 838 if (opt->type == OPTION_GROUP) { 839 qsort(group, nr_group, sizeof(*opt), option__cmp); 840 group = opt + 1; 841 nr_group = 0; 842 continue; 843 } 844 nr_group++; 845 } 846 qsort(group, nr_group, sizeof(*opt), option__cmp); 847 848 out: 849 return ordered; 850 } 851 852 static bool option__in_argv(const struct option *opt, const struct parse_opt_ctx_t *ctx) 853 { 854 int i; 855 856 for (i = 1; i < ctx->argc; ++i) { 857 const char *arg = ctx->argv[i]; 858 859 if (arg[0] != '-') { 860 if (arg[1] == '\0') { 861 if (arg[0] == opt->short_name) 862 return true; 863 continue; 864 } 865 866 if (opt->long_name && strcmp(opt->long_name, arg) == 0) 867 return true; 868 869 if (opt->help && strcasestr(opt->help, arg) != NULL) 870 return true; 871 872 continue; 873 } 874 875 if (arg[1] == opt->short_name || 876 (arg[1] == '-' && opt->long_name && strcmp(opt->long_name, arg + 2) == 0)) 877 return true; 878 } 879 880 return false; 881 } 882 883 static int usage_with_options_internal(const char * const *usagestr, 884 const struct option *opts, int full, 885 struct parse_opt_ctx_t *ctx) 886 { 887 struct option *ordered; 888 889 if (!usagestr) 890 return PARSE_OPT_HELP; 891 892 setup_pager(); 893 894 if (error_buf) { 895 fprintf(stderr, " Error: %s\n", error_buf); 896 zfree(&error_buf); 897 } 898 899 fprintf(stderr, "\n Usage: %s\n", *usagestr++); 900 while (*usagestr && **usagestr) 901 fprintf(stderr, " or: %s\n", *usagestr++); 902 while (*usagestr) { 903 fprintf(stderr, "%s%s\n", 904 **usagestr ? " " : "", 905 *usagestr); 906 usagestr++; 907 } 908 909 if (opts->type != OPTION_GROUP) 910 fputc('\n', stderr); 911 912 ordered = options__order(opts); 913 if (ordered) 914 opts = ordered; 915 916 for ( ; opts->type != OPTION_END; opts++) { 917 if (ctx && ctx->argc > 1 && !option__in_argv(opts, ctx)) 918 continue; 919 print_option_help(opts, full); 920 } 921 922 fputc('\n', stderr); 923 924 free(ordered); 925 926 return PARSE_OPT_HELP; 927 } 928 929 void usage_with_options(const char * const *usagestr, 930 const struct option *opts) 931 { 932 usage_with_options_internal(usagestr, opts, 0, NULL); 933 exit(129); 934 } 935 936 void usage_with_options_msg(const char * const *usagestr, 937 const struct option *opts, const char *fmt, ...) 938 { 939 va_list ap; 940 char *tmp = error_buf; 941 942 va_start(ap, fmt); 943 if (vasprintf(&error_buf, fmt, ap) == -1) 944 die("vasprintf failed"); 945 va_end(ap); 946 947 free(tmp); 948 949 usage_with_options_internal(usagestr, opts, 0, NULL); 950 exit(129); 951 } 952 953 int parse_options_usage(const char * const *usagestr, 954 const struct option *opts, 955 const char *optstr, bool short_opt) 956 { 957 if (!usagestr) 958 goto opt; 959 960 fprintf(stderr, "\n Usage: %s\n", *usagestr++); 961 while (*usagestr && **usagestr) 962 fprintf(stderr, " or: %s\n", *usagestr++); 963 while (*usagestr) { 964 fprintf(stderr, "%s%s\n", 965 **usagestr ? " " : "", 966 *usagestr); 967 usagestr++; 968 } 969 fputc('\n', stderr); 970 971 opt: 972 for ( ; opts->type != OPTION_END; opts++) { 973 if (short_opt) { 974 if (opts->short_name == *optstr) { 975 print_option_help(opts, 0); 976 break; 977 } 978 continue; 979 } 980 981 if (opts->long_name == NULL) 982 continue; 983 984 if (strstarts(opts->long_name, optstr)) 985 print_option_help(opts, 0); 986 if (strstarts("no-", optstr) && 987 strstarts(opts->long_name, optstr + 3)) 988 print_option_help(opts, 0); 989 } 990 991 return PARSE_OPT_HELP; 992 } 993 994 995 int parse_opt_verbosity_cb(const struct option *opt, 996 const char *arg __maybe_unused, 997 int unset) 998 { 999 int *target = opt->value; 1000 1001 if (unset) 1002 /* --no-quiet, --no-verbose */ 1003 *target = 0; 1004 else if (opt->short_name == 'v') { 1005 if (*target >= 0) 1006 (*target)++; 1007 else 1008 *target = 1; 1009 } else { 1010 if (*target <= 0) 1011 (*target)--; 1012 else 1013 *target = -1; 1014 } 1015 return 0; 1016 } 1017 1018 static struct option * 1019 find_option(struct option *opts, int shortopt, const char *longopt) 1020 { 1021 for (; opts->type != OPTION_END; opts++) { 1022 if ((shortopt && opts->short_name == shortopt) || 1023 (opts->long_name && longopt && 1024 !strcmp(opts->long_name, longopt))) 1025 return opts; 1026 } 1027 return NULL; 1028 } 1029 1030 void set_option_flag(struct option *opts, int shortopt, const char *longopt, 1031 int flag) 1032 { 1033 struct option *opt = find_option(opts, shortopt, longopt); 1034 1035 if (opt) 1036 opt->flags |= flag; 1037 return; 1038 } 1039 1040 void set_option_nobuild(struct option *opts, int shortopt, 1041 const char *longopt, 1042 const char *build_opt, 1043 bool can_skip) 1044 { 1045 struct option *opt = find_option(opts, shortopt, longopt); 1046 1047 if (!opt) 1048 return; 1049 1050 opt->flags |= PARSE_OPT_NOBUILD; 1051 opt->flags |= can_skip ? PARSE_OPT_CANSKIP : 0; 1052 opt->build_opt = build_opt; 1053 } 1054
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.