1 #include <stdio.h> 2 #include <string.h> 3 #include <unistd.h> 4 5 #include <stdbool.h> 6 7 /* user defined includes */ 8 #include <linux/types.h> 9 #include <kvm/util.h> 10 #include <kvm/parse-options.h> 11 #include <kvm/strbuf.h> 12 13 #define OPT_SHORT 1 14 #define OPT_UNSET 2 15 16 static int opterror(const struct option *opt, const char *reason, int flags) 17 { 18 if (flags & OPT_SHORT) 19 return pr_error("switch `%c' %s", opt->short_name, reason); 20 if (flags & OPT_UNSET) 21 return pr_error("option `no-%s' %s", opt->long_name, reason); 22 return pr_error("option `%s' %s", opt->long_name, reason); 23 } 24 25 static int get_arg(struct parse_opt_ctx_t *p, const struct option *opt, 26 int flags, const char **arg) 27 { 28 if (p->opt) { 29 *arg = p->opt; 30 p->opt = NULL; 31 } else if ((opt->flags & PARSE_OPT_LASTARG_DEFAULT) && (p->argc == 1 || 32 **(p->argv + 1) == '-')) { 33 *arg = (const char *)opt->defval; 34 } else if (p->argc > 1) { 35 p->argc--; 36 *arg = *++p->argv; 37 } else 38 return opterror(opt, "requires a value", flags); 39 return 0; 40 } 41 42 static int get_value(struct parse_opt_ctx_t *p, 43 const struct option *opt, int flags) 44 { 45 const char *s, *arg = NULL; 46 const int unset = flags & OPT_UNSET; 47 48 if (unset && p->opt) 49 return opterror(opt, "takes no value", flags); 50 if (unset && (opt->flags & PARSE_OPT_NONEG)) 51 return opterror(opt, "isn't available", flags); 52 53 if (!(flags & OPT_SHORT) && p->opt) { 54 switch (opt->type) { 55 case OPTION_CALLBACK: 56 if (!(opt->flags & PARSE_OPT_NOARG)) 57 break; 58 /* FALLTHROUGH */ 59 case OPTION_BOOLEAN: 60 case OPTION_INCR: 61 case OPTION_BIT: 62 case OPTION_SET_UINT: 63 case OPTION_SET_PTR: 64 return opterror(opt, "takes no value", flags); 65 case OPTION_END: 66 case OPTION_ARGUMENT: 67 case OPTION_GROUP: 68 case OPTION_STRING: 69 case OPTION_INTEGER: 70 case OPTION_UINTEGER: 71 case OPTION_LONG: 72 case OPTION_U64: 73 default: 74 break; 75 } 76 } 77 78 switch (opt->type) { 79 case OPTION_BIT: 80 if (unset) 81 *(int *)opt->value &= ~opt->defval; 82 else 83 *(int *)opt->value |= opt->defval; 84 return 0; 85 86 case OPTION_BOOLEAN: 87 *(bool *)opt->value = unset ? false : true; 88 return 0; 89 90 case OPTION_INCR: 91 *(int *)opt->value = unset ? 0 : *(int *)opt->value + 1; 92 return 0; 93 94 case OPTION_SET_UINT: 95 *(unsigned int *)opt->value = unset ? 0 : opt->defval; 96 return 0; 97 98 case OPTION_SET_PTR: 99 *(void **)opt->value = unset ? NULL : (void *)opt->defval; 100 return 0; 101 102 case OPTION_STRING: 103 if (unset) 104 *(const char **)opt->value = NULL; 105 else if (opt->flags & PARSE_OPT_OPTARG && !p->opt) 106 *(const char **)opt->value = (const char *)opt->defval; 107 else 108 return get_arg(p, opt, flags, 109 (const char **)opt->value); 110 return 0; 111 112 case OPTION_CALLBACK: 113 if (unset) 114 return (*opt->callback)(opt, NULL, 1) ? (-1) : 0; 115 if (opt->flags & PARSE_OPT_NOARG) 116 return (*opt->callback)(opt, NULL, 0) ? (-1) : 0; 117 if (opt->flags & PARSE_OPT_OPTARG && !p->opt) 118 return (*opt->callback)(opt, NULL, 0) ? (-1) : 0; 119 if (get_arg(p, opt, flags, &arg)) 120 return -1; 121 return (*opt->callback)(opt, arg, 0) ? (-1) : 0; 122 123 case OPTION_INTEGER: 124 if (unset) { 125 *(int *)opt->value = 0; 126 return 0; 127 } 128 if (opt->flags & PARSE_OPT_OPTARG && !p->opt) { 129 *(int *)opt->value = opt->defval; 130 return 0; 131 } 132 if (get_arg(p, opt, flags, &arg)) 133 return -1; 134 *(int *)opt->value = strtol(arg, (char **)&s, 10); 135 if (*s) 136 return opterror(opt, "expects a numerical value", 137 flags); 138 return 0; 139 140 case OPTION_UINTEGER: 141 if (unset) { 142 *(unsigned int *)opt->value = 0; 143 return 0; 144 } 145 if (opt->flags & PARSE_OPT_OPTARG && !p->opt) { 146 *(unsigned int *)opt->value = opt->defval; 147 return 0; 148 } 149 if (get_arg(p, opt, flags, &arg)) 150 return -1; 151 *(unsigned int *)opt->value = strtol(arg, (char **)&s, 10); 152 if (*s) 153 return opterror(opt, 154 "expects a numerical value", flags); 155 return 0; 156 157 case OPTION_LONG: 158 if (unset) { 159 *(long *)opt->value = 0; 160 return 0; 161 } 162 if (opt->flags & PARSE_OPT_OPTARG && !p->opt) { 163 *(long *)opt->value = opt->defval; 164 return 0; 165 } 166 if (get_arg(p, opt, flags, &arg)) 167 return -1; 168 *(long *)opt->value = strtol(arg, (char **)&s, 10); 169 if (*s) 170 return opterror(opt, 171 "expects a numerical value", flags); 172 return 0; 173 174 case OPTION_U64: 175 if (unset) { 176 *(u64 *)opt->value = 0; 177 return 0; 178 } 179 if (opt->flags & PARSE_OPT_OPTARG && !p->opt) { 180 *(u64 *)opt->value = opt->defval; 181 return 0; 182 } 183 if (get_arg(p, opt, flags, &arg)) 184 return -1; 185 *(u64 *)opt->value = strtoull(arg, (char **)&s, 10); 186 if (*s) 187 return opterror(opt, 188 "expects a numerical value", flags); 189 return 0; 190 191 case OPTION_END: 192 case OPTION_ARGUMENT: 193 case OPTION_GROUP: 194 default: 195 die("should not happen, someone must be hit on the forehead"); 196 } 197 } 198 199 #define USAGE_OPTS_WIDTH 24 200 #define USAGE_GAP 2 201 202 static int usage_with_options_internal(const char * const *usagestr, 203 const struct option *opts, int full) 204 { 205 if (!usagestr) 206 return PARSE_OPT_HELP; 207 208 fprintf(stderr, "\n usage: %s\n", *usagestr++); 209 while (*usagestr && **usagestr) 210 fprintf(stderr, " or: %s\n", *usagestr++); 211 while (*usagestr) { 212 fprintf(stderr, "%s%s\n", 213 **usagestr ? " " : "", 214 *usagestr); 215 usagestr++; 216 } 217 218 if (opts->type != OPTION_GROUP) 219 fputc('\n', stderr); 220 221 for (; opts->type != OPTION_END; opts++) { 222 size_t pos; 223 int pad; 224 225 if (opts->type == OPTION_GROUP) { 226 fputc('\n', stderr); 227 if (*opts->help) 228 fprintf(stderr, "%s\n", opts->help); 229 continue; 230 } 231 if (!full && (opts->flags & PARSE_OPT_HIDDEN)) 232 continue; 233 234 pos = fprintf(stderr, " "); 235 if (opts->short_name) 236 pos += fprintf(stderr, "-%c", opts->short_name); 237 else 238 pos += fprintf(stderr, " "); 239 240 if (opts->long_name && opts->short_name) 241 pos += fprintf(stderr, ", "); 242 if (opts->long_name) 243 pos += fprintf(stderr, "--%s", opts->long_name); 244 245 switch (opts->type) { 246 case OPTION_ARGUMENT: 247 break; 248 case OPTION_LONG: 249 case OPTION_U64: 250 case OPTION_INTEGER: 251 case OPTION_UINTEGER: 252 if (opts->flags & PARSE_OPT_OPTARG) 253 if (opts->long_name) 254 pos += fprintf(stderr, "[=<n>]"); 255 else 256 pos += fprintf(stderr, "[<n>]"); 257 else 258 pos += fprintf(stderr, " <n>"); 259 break; 260 case OPTION_CALLBACK: 261 if (opts->flags & PARSE_OPT_NOARG) 262 break; 263 /* FALLTHROUGH */ 264 case OPTION_STRING: 265 if (opts->argh) { 266 if (opts->flags & PARSE_OPT_OPTARG) 267 if (opts->long_name) 268 pos += fprintf(stderr, "[=<%s>]", opts->argh); 269 else 270 pos += fprintf(stderr, "[<%s>]", opts->argh); 271 else 272 pos += fprintf(stderr, " <%s>", opts->argh); 273 } else { 274 if (opts->flags & PARSE_OPT_OPTARG) 275 if (opts->long_name) 276 pos += fprintf(stderr, "[=...]"); 277 else 278 pos += fprintf(stderr, "[...]"); 279 else 280 pos += fprintf(stderr, " ..."); 281 } 282 break; 283 default: /* OPTION_{BIT,BOOLEAN,SET_UINT,SET_PTR} */ 284 case OPTION_END: 285 case OPTION_GROUP: 286 case OPTION_BIT: 287 case OPTION_BOOLEAN: 288 case OPTION_INCR: 289 case OPTION_SET_UINT: 290 case OPTION_SET_PTR: 291 break; 292 } 293 if (pos <= USAGE_OPTS_WIDTH) 294 pad = USAGE_OPTS_WIDTH - pos; 295 else { 296 fputc('\n', stderr); 297 pad = USAGE_OPTS_WIDTH; 298 } 299 fprintf(stderr, "%*s%s\n", pad + USAGE_GAP, "", opts->help); 300 } 301 fputc('\n', stderr); 302 303 return PARSE_OPT_HELP; 304 } 305 306 void usage_with_options(const char * const *usagestr, 307 const struct option *opts) 308 { 309 usage_with_options_internal(usagestr, opts, 0); 310 exit(129); 311 } 312 313 static void check_typos(const char *arg, const struct option *options) 314 { 315 if (strlen(arg) < 3) 316 return; 317 318 if (!prefixcmp(arg, "no-")) { 319 pr_error ("did you mean `--%s` (with two dashes ?)", arg); 320 exit(129); 321 } 322 323 for (; options->type != OPTION_END; options++) { 324 if (!options->long_name) 325 continue; 326 if (!prefixcmp(options->long_name, arg)) { 327 pr_error ("did you mean `--%s` (with two dashes ?)", arg); 328 exit(129); 329 } 330 } 331 } 332 333 static int parse_options_usage(const char * const *usagestr, 334 const struct option *opts) 335 { 336 return usage_with_options_internal(usagestr, opts, 0); 337 } 338 339 static int parse_short_opt(struct parse_opt_ctx_t *p, 340 const struct option *options) 341 { 342 for (; options->type != OPTION_END; options++) { 343 if (options->short_name == *p->opt) { 344 p->opt = p->opt[1] ? p->opt + 1 : NULL; 345 return get_value(p, options, OPT_SHORT); 346 } 347 } 348 return -2; 349 } 350 351 static int parse_long_opt(struct parse_opt_ctx_t *p, const char *arg, 352 const struct option *options) 353 { 354 const char *arg_end = strchr(arg, '='); 355 const struct option *abbrev_option = NULL, *ambiguous_option = NULL; 356 int abbrev_flags = 0, ambiguous_flags = 0; 357 358 if (!arg_end) 359 arg_end = arg + strlen(arg); 360 361 for (; options->type != OPTION_END; options++) { 362 const char *rest; 363 int flags = 0; 364 365 if (!options->long_name) 366 continue; 367 368 rest = skip_prefix(arg, options->long_name); 369 if (options->type == OPTION_ARGUMENT) { 370 if (!rest) 371 continue; 372 if (*rest == '=') 373 return opterror(options, "takes no value", 374 flags); 375 if (*rest) 376 continue; 377 p->out[p->cpidx++] = arg - 2; 378 return 0; 379 } 380 if (!rest) { 381 /* abbreviated? */ 382 if (!strncmp(options->long_name, arg, arg_end - arg)) { 383 is_abbreviated: 384 if (abbrev_option) { 385 /* 386 * If this is abbreviated, it is 387 * ambiguous. So when there is no 388 * exact match later, we need to 389 * error out. 390 */ 391 ambiguous_option = abbrev_option; 392 ambiguous_flags = abbrev_flags; 393 } 394 if (!(flags & OPT_UNSET) && *arg_end) 395 p->opt = arg_end + 1; 396 abbrev_option = options; 397 abbrev_flags = flags; 398 continue; 399 } 400 /* negated and abbreviated very much? */ 401 if (!prefixcmp("no-", arg)) { 402 flags |= OPT_UNSET; 403 goto is_abbreviated; 404 } 405 /* negated? */ 406 if (strncmp(arg, "no-", 3)) 407 continue; 408 flags |= OPT_UNSET; 409 rest = skip_prefix(arg + 3, options->long_name); 410 /* abbreviated and negated? */ 411 if (!rest && !prefixcmp(options->long_name, arg + 3)) 412 goto is_abbreviated; 413 if (!rest) 414 continue; 415 } 416 if (*rest) { 417 if (*rest != '=') 418 continue; 419 p->opt = rest + 1; 420 } 421 return get_value(p, options, flags); 422 } 423 424 if (ambiguous_option) 425 return pr_error("Ambiguous option: %s " 426 "(could be --%s%s or --%s%s)", 427 arg, 428 (ambiguous_flags & OPT_UNSET) ? "no-" : "", 429 ambiguous_option->long_name, 430 (abbrev_flags & OPT_UNSET) ? "no-" : "", 431 abbrev_option->long_name); 432 if (abbrev_option) 433 return get_value(p, abbrev_option, abbrev_flags); 434 return -2; 435 } 436 437 438 static void parse_options_start(struct parse_opt_ctx_t *ctx, int argc, 439 const char **argv, int flags) 440 { 441 memset(ctx, 0, sizeof(*ctx)); 442 ctx->argc = argc; 443 ctx->argv = argv; 444 ctx->out = argv; 445 ctx->cpidx = ((flags & PARSE_OPT_KEEP_ARGV0) != 0); 446 ctx->flags = flags; 447 if ((flags & PARSE_OPT_KEEP_UNKNOWN) && 448 (flags & PARSE_OPT_STOP_AT_NON_OPTION)) 449 die("STOP_AT_NON_OPTION and KEEP_UNKNOWN don't go together"); 450 } 451 452 static int parse_options_end(struct parse_opt_ctx_t *ctx) 453 { 454 memmove(ctx->out + ctx->cpidx, ctx->argv, ctx->argc * sizeof(*ctx->out)); 455 ctx->out[ctx->cpidx + ctx->argc] = NULL; 456 return ctx->cpidx + ctx->argc; 457 } 458 459 460 static int parse_options_step(struct parse_opt_ctx_t *ctx, 461 const struct option *options, const char * const usagestr[]) 462 { 463 int internal_help = !(ctx->flags & PARSE_OPT_NO_INTERNAL_HELP); 464 465 /* we must reset ->opt, unknown short option leave it dangling */ 466 ctx->opt = NULL; 467 468 for (; ctx->argc; ctx->argc--, ctx->argv++) { 469 const char *arg = ctx->argv[0]; 470 471 if (*arg != '-' || !arg[1]) { 472 if (ctx->flags & PARSE_OPT_STOP_AT_NON_OPTION) 473 break; 474 ctx->out[ctx->cpidx++] = ctx->argv[0]; 475 continue; 476 } 477 478 if (arg[1] != '-') { 479 ctx->opt = arg + 1; 480 if (internal_help && *ctx->opt == 'h') 481 return parse_options_usage(usagestr, options); 482 switch (parse_short_opt(ctx, options)) { 483 case -1: 484 return parse_options_usage(usagestr, options); 485 case -2: 486 goto unknown; 487 default: 488 break; 489 } 490 if (ctx->opt) 491 check_typos(arg + 1, options); 492 while (ctx->opt) { 493 if (internal_help && *ctx->opt == 'h') 494 return parse_options_usage(usagestr, 495 options); 496 switch (parse_short_opt(ctx, options)) { 497 case -1: 498 return parse_options_usage(usagestr, 499 options); 500 case -2: 501 /* fake a short option thing to hide 502 * the fact that we may have 503 * started to parse aggregated stuff 504 * 505 * This is leaky, too bad. 506 */ 507 ctx->argv[0] = strdup(ctx->opt - 1); 508 *(char *)ctx->argv[0] = '-'; 509 goto unknown; 510 default: 511 break; 512 } 513 } 514 continue; 515 } 516 517 if (!arg[2]) { /* "--" */ 518 if (!(ctx->flags & PARSE_OPT_KEEP_DASHDASH)) { 519 ctx->argc--; 520 ctx->argv++; 521 } 522 break; 523 } 524 525 if (internal_help && !strcmp(arg + 2, "help-all")) 526 return usage_with_options_internal(usagestr, options, 527 1); 528 if (internal_help && !strcmp(arg + 2, "help")) 529 return parse_options_usage(usagestr, options); 530 switch (parse_long_opt(ctx, arg + 2, options)) { 531 case -1: 532 return parse_options_usage(usagestr, options); 533 case -2: 534 goto unknown; 535 default: 536 break; 537 } 538 continue; 539 unknown: 540 if (!(ctx->flags & PARSE_OPT_KEEP_UNKNOWN)) 541 return PARSE_OPT_UNKNOWN; 542 ctx->out[ctx->cpidx++] = ctx->argv[0]; 543 ctx->opt = NULL; 544 } 545 return PARSE_OPT_DONE; 546 } 547 548 int parse_options(int argc, const char **argv, const struct option *options, 549 const char * const usagestr[], int flags) 550 { 551 struct parse_opt_ctx_t ctx; 552 553 parse_options_start(&ctx, argc, argv, flags); 554 switch (parse_options_step(&ctx, options, usagestr)) { 555 case PARSE_OPT_HELP: 556 exit(129); 557 case PARSE_OPT_DONE: 558 break; 559 default: /* PARSE_OPT_UNKNOWN */ 560 if (ctx.argv[0][1] == '-') { 561 pr_error("unknown option `%s'", ctx.argv[0] + 2); 562 } else { 563 pr_error("unknown switch `%c'", *ctx.opt); 564 } 565 usage_with_options(usagestr, options); 566 } 567 568 return parse_options_end(&ctx); 569 } 570