198ee79f4SPrasad Joshi #include <stdio.h> 298ee79f4SPrasad Joshi #include <string.h> 398ee79f4SPrasad Joshi #include <unistd.h> 498ee79f4SPrasad Joshi 598ee79f4SPrasad Joshi #include <stdbool.h> 698ee79f4SPrasad Joshi 798ee79f4SPrasad Joshi /* user defined includes */ 898ee79f4SPrasad Joshi #include <linux/types.h> 998ee79f4SPrasad Joshi #include <kvm/util.h> 1098ee79f4SPrasad Joshi #include <kvm/parse-options.h> 1198ee79f4SPrasad Joshi #include <kvm/strbuf.h> 1298ee79f4SPrasad Joshi 1398ee79f4SPrasad Joshi #define OPT_SHORT 1 1498ee79f4SPrasad Joshi #define OPT_UNSET 2 1598ee79f4SPrasad Joshi 1698ee79f4SPrasad Joshi static int opterror(const struct option *opt, const char *reason, int flags) 1798ee79f4SPrasad Joshi { 1898ee79f4SPrasad Joshi if (flags & OPT_SHORT) 19*4542f276SCyrill Gorcunov return pr_error("switch `%c' %s", opt->short_name, reason); 2098ee79f4SPrasad Joshi if (flags & OPT_UNSET) 21*4542f276SCyrill Gorcunov return pr_error("option `no-%s' %s", opt->long_name, reason); 22*4542f276SCyrill Gorcunov return pr_error("option `%s' %s", opt->long_name, reason); 2398ee79f4SPrasad Joshi } 2498ee79f4SPrasad Joshi 2598ee79f4SPrasad Joshi static int get_arg(struct parse_opt_ctx_t *p, const struct option *opt, 2698ee79f4SPrasad Joshi int flags, const char **arg) 2798ee79f4SPrasad Joshi { 2898ee79f4SPrasad Joshi if (p->opt) { 2998ee79f4SPrasad Joshi *arg = p->opt; 3098ee79f4SPrasad Joshi p->opt = NULL; 3198ee79f4SPrasad Joshi } else if ((opt->flags & PARSE_OPT_LASTARG_DEFAULT) && (p->argc == 1 || 3298ee79f4SPrasad Joshi **(p->argv + 1) == '-')) { 3398ee79f4SPrasad Joshi *arg = (const char *)opt->defval; 3498ee79f4SPrasad Joshi } else if (p->argc > 1) { 3598ee79f4SPrasad Joshi p->argc--; 3698ee79f4SPrasad Joshi *arg = *++p->argv; 3798ee79f4SPrasad Joshi } else 3898ee79f4SPrasad Joshi return opterror(opt, "requires a value", flags); 3998ee79f4SPrasad Joshi return 0; 4098ee79f4SPrasad Joshi } 4198ee79f4SPrasad Joshi 4298ee79f4SPrasad Joshi static int get_value(struct parse_opt_ctx_t *p, 4398ee79f4SPrasad Joshi const struct option *opt, int flags) 4498ee79f4SPrasad Joshi { 4598ee79f4SPrasad Joshi const char *s, *arg = NULL; 4698ee79f4SPrasad Joshi const int unset = flags & OPT_UNSET; 4798ee79f4SPrasad Joshi 4898ee79f4SPrasad Joshi if (unset && p->opt) 4998ee79f4SPrasad Joshi return opterror(opt, "takes no value", flags); 5098ee79f4SPrasad Joshi if (unset && (opt->flags & PARSE_OPT_NONEG)) 5198ee79f4SPrasad Joshi return opterror(opt, "isn't available", flags); 5298ee79f4SPrasad Joshi 5398ee79f4SPrasad Joshi if (!(flags & OPT_SHORT) && p->opt) { 5498ee79f4SPrasad Joshi switch (opt->type) { 5598ee79f4SPrasad Joshi case OPTION_CALLBACK: 5698ee79f4SPrasad Joshi if (!(opt->flags & PARSE_OPT_NOARG)) 5798ee79f4SPrasad Joshi break; 5898ee79f4SPrasad Joshi /* FALLTHROUGH */ 5998ee79f4SPrasad Joshi case OPTION_BOOLEAN: 6098ee79f4SPrasad Joshi case OPTION_INCR: 6198ee79f4SPrasad Joshi case OPTION_BIT: 6298ee79f4SPrasad Joshi case OPTION_SET_UINT: 6398ee79f4SPrasad Joshi case OPTION_SET_PTR: 6498ee79f4SPrasad Joshi return opterror(opt, "takes no value", flags); 6598ee79f4SPrasad Joshi case OPTION_END: 6698ee79f4SPrasad Joshi case OPTION_ARGUMENT: 6798ee79f4SPrasad Joshi case OPTION_GROUP: 6898ee79f4SPrasad Joshi case OPTION_STRING: 6998ee79f4SPrasad Joshi case OPTION_INTEGER: 7098ee79f4SPrasad Joshi case OPTION_UINTEGER: 7198ee79f4SPrasad Joshi case OPTION_LONG: 7298ee79f4SPrasad Joshi case OPTION_U64: 7398ee79f4SPrasad Joshi default: 7498ee79f4SPrasad Joshi break; 7598ee79f4SPrasad Joshi } 7698ee79f4SPrasad Joshi } 7798ee79f4SPrasad Joshi 7898ee79f4SPrasad Joshi switch (opt->type) { 7998ee79f4SPrasad Joshi case OPTION_BIT: 8098ee79f4SPrasad Joshi if (unset) 8198ee79f4SPrasad Joshi *(int *)opt->value &= ~opt->defval; 8298ee79f4SPrasad Joshi else 8398ee79f4SPrasad Joshi *(int *)opt->value |= opt->defval; 8498ee79f4SPrasad Joshi return 0; 8598ee79f4SPrasad Joshi 8698ee79f4SPrasad Joshi case OPTION_BOOLEAN: 8798ee79f4SPrasad Joshi *(bool *)opt->value = unset ? false : true; 8898ee79f4SPrasad Joshi return 0; 8998ee79f4SPrasad Joshi 9098ee79f4SPrasad Joshi case OPTION_INCR: 9198ee79f4SPrasad Joshi *(int *)opt->value = unset ? 0 : *(int *)opt->value + 1; 9298ee79f4SPrasad Joshi return 0; 9398ee79f4SPrasad Joshi 9498ee79f4SPrasad Joshi case OPTION_SET_UINT: 9598ee79f4SPrasad Joshi *(unsigned int *)opt->value = unset ? 0 : opt->defval; 9698ee79f4SPrasad Joshi return 0; 9798ee79f4SPrasad Joshi 9898ee79f4SPrasad Joshi case OPTION_SET_PTR: 9998ee79f4SPrasad Joshi *(void **)opt->value = unset ? NULL : (void *)opt->defval; 10098ee79f4SPrasad Joshi return 0; 10198ee79f4SPrasad Joshi 10298ee79f4SPrasad Joshi case OPTION_STRING: 10398ee79f4SPrasad Joshi if (unset) 10498ee79f4SPrasad Joshi *(const char **)opt->value = NULL; 10598ee79f4SPrasad Joshi else if (opt->flags & PARSE_OPT_OPTARG && !p->opt) 10698ee79f4SPrasad Joshi *(const char **)opt->value = (const char *)opt->defval; 10798ee79f4SPrasad Joshi else 10898ee79f4SPrasad Joshi return get_arg(p, opt, flags, 10998ee79f4SPrasad Joshi (const char **)opt->value); 11098ee79f4SPrasad Joshi return 0; 11198ee79f4SPrasad Joshi 11298ee79f4SPrasad Joshi case OPTION_CALLBACK: 11398ee79f4SPrasad Joshi if (unset) 11498ee79f4SPrasad Joshi return (*opt->callback)(opt, NULL, 1) ? (-1) : 0; 11598ee79f4SPrasad Joshi if (opt->flags & PARSE_OPT_NOARG) 11698ee79f4SPrasad Joshi return (*opt->callback)(opt, NULL, 0) ? (-1) : 0; 11798ee79f4SPrasad Joshi if (opt->flags & PARSE_OPT_OPTARG && !p->opt) 11898ee79f4SPrasad Joshi return (*opt->callback)(opt, NULL, 0) ? (-1) : 0; 11998ee79f4SPrasad Joshi if (get_arg(p, opt, flags, &arg)) 12098ee79f4SPrasad Joshi return -1; 12198ee79f4SPrasad Joshi return (*opt->callback)(opt, arg, 0) ? (-1) : 0; 12298ee79f4SPrasad Joshi 12398ee79f4SPrasad Joshi case OPTION_INTEGER: 12498ee79f4SPrasad Joshi if (unset) { 12598ee79f4SPrasad Joshi *(int *)opt->value = 0; 12698ee79f4SPrasad Joshi return 0; 12798ee79f4SPrasad Joshi } 12898ee79f4SPrasad Joshi if (opt->flags & PARSE_OPT_OPTARG && !p->opt) { 12998ee79f4SPrasad Joshi *(int *)opt->value = opt->defval; 13098ee79f4SPrasad Joshi return 0; 13198ee79f4SPrasad Joshi } 13298ee79f4SPrasad Joshi if (get_arg(p, opt, flags, &arg)) 13398ee79f4SPrasad Joshi return -1; 13498ee79f4SPrasad Joshi *(int *)opt->value = strtol(arg, (char **)&s, 10); 13598ee79f4SPrasad Joshi if (*s) 13698ee79f4SPrasad Joshi return opterror(opt, "expects a numerical value", 13798ee79f4SPrasad Joshi flags); 13898ee79f4SPrasad Joshi return 0; 13998ee79f4SPrasad Joshi 14098ee79f4SPrasad Joshi case OPTION_UINTEGER: 14198ee79f4SPrasad Joshi if (unset) { 14298ee79f4SPrasad Joshi *(unsigned int *)opt->value = 0; 14398ee79f4SPrasad Joshi return 0; 14498ee79f4SPrasad Joshi } 14598ee79f4SPrasad Joshi if (opt->flags & PARSE_OPT_OPTARG && !p->opt) { 14698ee79f4SPrasad Joshi *(unsigned int *)opt->value = opt->defval; 14798ee79f4SPrasad Joshi return 0; 14898ee79f4SPrasad Joshi } 14998ee79f4SPrasad Joshi if (get_arg(p, opt, flags, &arg)) 15098ee79f4SPrasad Joshi return -1; 15198ee79f4SPrasad Joshi *(unsigned int *)opt->value = strtol(arg, (char **)&s, 10); 15298ee79f4SPrasad Joshi if (*s) 15398ee79f4SPrasad Joshi return opterror(opt, 15498ee79f4SPrasad Joshi "expects a numerical value", flags); 15598ee79f4SPrasad Joshi return 0; 15698ee79f4SPrasad Joshi 15798ee79f4SPrasad Joshi case OPTION_LONG: 15898ee79f4SPrasad Joshi if (unset) { 15998ee79f4SPrasad Joshi *(long *)opt->value = 0; 16098ee79f4SPrasad Joshi return 0; 16198ee79f4SPrasad Joshi } 16298ee79f4SPrasad Joshi if (opt->flags & PARSE_OPT_OPTARG && !p->opt) { 16398ee79f4SPrasad Joshi *(long *)opt->value = opt->defval; 16498ee79f4SPrasad Joshi return 0; 16598ee79f4SPrasad Joshi } 16698ee79f4SPrasad Joshi if (get_arg(p, opt, flags, &arg)) 16798ee79f4SPrasad Joshi return -1; 16898ee79f4SPrasad Joshi *(long *)opt->value = strtol(arg, (char **)&s, 10); 16998ee79f4SPrasad Joshi if (*s) 17098ee79f4SPrasad Joshi return opterror(opt, 17198ee79f4SPrasad Joshi "expects a numerical value", flags); 17298ee79f4SPrasad Joshi return 0; 17398ee79f4SPrasad Joshi 17498ee79f4SPrasad Joshi case OPTION_U64: 17598ee79f4SPrasad Joshi if (unset) { 17698ee79f4SPrasad Joshi *(u64 *)opt->value = 0; 17798ee79f4SPrasad Joshi return 0; 17898ee79f4SPrasad Joshi } 17998ee79f4SPrasad Joshi if (opt->flags & PARSE_OPT_OPTARG && !p->opt) { 18098ee79f4SPrasad Joshi *(u64 *)opt->value = opt->defval; 18198ee79f4SPrasad Joshi return 0; 18298ee79f4SPrasad Joshi } 18398ee79f4SPrasad Joshi if (get_arg(p, opt, flags, &arg)) 18498ee79f4SPrasad Joshi return -1; 18598ee79f4SPrasad Joshi *(u64 *)opt->value = strtoull(arg, (char **)&s, 10); 18698ee79f4SPrasad Joshi if (*s) 18798ee79f4SPrasad Joshi return opterror(opt, 18898ee79f4SPrasad Joshi "expects a numerical value", flags); 18998ee79f4SPrasad Joshi return 0; 19098ee79f4SPrasad Joshi 19198ee79f4SPrasad Joshi case OPTION_END: 19298ee79f4SPrasad Joshi case OPTION_ARGUMENT: 19398ee79f4SPrasad Joshi case OPTION_GROUP: 19498ee79f4SPrasad Joshi default: 19598ee79f4SPrasad Joshi die("should not happen, someone must be hit on the forehead"); 19698ee79f4SPrasad Joshi } 19798ee79f4SPrasad Joshi } 19898ee79f4SPrasad Joshi 19998ee79f4SPrasad Joshi #define USAGE_OPTS_WIDTH 24 20098ee79f4SPrasad Joshi #define USAGE_GAP 2 20198ee79f4SPrasad Joshi 20298ee79f4SPrasad Joshi static int usage_with_options_internal(const char * const *usagestr, 20398ee79f4SPrasad Joshi const struct option *opts, int full) 20498ee79f4SPrasad Joshi { 20598ee79f4SPrasad Joshi if (!usagestr) 20698ee79f4SPrasad Joshi return PARSE_OPT_HELP; 20798ee79f4SPrasad Joshi 20898ee79f4SPrasad Joshi fprintf(stderr, "\n usage: %s\n", *usagestr++); 20998ee79f4SPrasad Joshi while (*usagestr && **usagestr) 21098ee79f4SPrasad Joshi fprintf(stderr, " or: %s\n", *usagestr++); 21198ee79f4SPrasad Joshi while (*usagestr) { 21298ee79f4SPrasad Joshi fprintf(stderr, "%s%s\n", 21398ee79f4SPrasad Joshi **usagestr ? " " : "", 21498ee79f4SPrasad Joshi *usagestr); 21598ee79f4SPrasad Joshi usagestr++; 21698ee79f4SPrasad Joshi } 21798ee79f4SPrasad Joshi 21898ee79f4SPrasad Joshi if (opts->type != OPTION_GROUP) 21998ee79f4SPrasad Joshi fputc('\n', stderr); 22098ee79f4SPrasad Joshi 22198ee79f4SPrasad Joshi for (; opts->type != OPTION_END; opts++) { 22298ee79f4SPrasad Joshi size_t pos; 22398ee79f4SPrasad Joshi int pad; 22498ee79f4SPrasad Joshi 22598ee79f4SPrasad Joshi if (opts->type == OPTION_GROUP) { 22698ee79f4SPrasad Joshi fputc('\n', stderr); 22798ee79f4SPrasad Joshi if (*opts->help) 22898ee79f4SPrasad Joshi fprintf(stderr, "%s\n", opts->help); 22998ee79f4SPrasad Joshi continue; 23098ee79f4SPrasad Joshi } 23198ee79f4SPrasad Joshi if (!full && (opts->flags & PARSE_OPT_HIDDEN)) 23298ee79f4SPrasad Joshi continue; 23398ee79f4SPrasad Joshi 23498ee79f4SPrasad Joshi pos = fprintf(stderr, " "); 23598ee79f4SPrasad Joshi if (opts->short_name) 23698ee79f4SPrasad Joshi pos += fprintf(stderr, "-%c", opts->short_name); 23798ee79f4SPrasad Joshi else 23898ee79f4SPrasad Joshi pos += fprintf(stderr, " "); 23998ee79f4SPrasad Joshi 24098ee79f4SPrasad Joshi if (opts->long_name && opts->short_name) 24198ee79f4SPrasad Joshi pos += fprintf(stderr, ", "); 24298ee79f4SPrasad Joshi if (opts->long_name) 24398ee79f4SPrasad Joshi pos += fprintf(stderr, "--%s", opts->long_name); 24498ee79f4SPrasad Joshi 24598ee79f4SPrasad Joshi switch (opts->type) { 24698ee79f4SPrasad Joshi case OPTION_ARGUMENT: 24798ee79f4SPrasad Joshi break; 24898ee79f4SPrasad Joshi case OPTION_LONG: 24998ee79f4SPrasad Joshi case OPTION_U64: 25098ee79f4SPrasad Joshi case OPTION_INTEGER: 25198ee79f4SPrasad Joshi case OPTION_UINTEGER: 25298ee79f4SPrasad Joshi if (opts->flags & PARSE_OPT_OPTARG) 25398ee79f4SPrasad Joshi if (opts->long_name) 25498ee79f4SPrasad Joshi pos += fprintf(stderr, "[=<n>]"); 25598ee79f4SPrasad Joshi else 25698ee79f4SPrasad Joshi pos += fprintf(stderr, "[<n>]"); 25798ee79f4SPrasad Joshi else 25898ee79f4SPrasad Joshi pos += fprintf(stderr, " <n>"); 25998ee79f4SPrasad Joshi break; 26098ee79f4SPrasad Joshi case OPTION_CALLBACK: 26198ee79f4SPrasad Joshi if (opts->flags & PARSE_OPT_NOARG) 26298ee79f4SPrasad Joshi break; 26398ee79f4SPrasad Joshi /* FALLTHROUGH */ 26498ee79f4SPrasad Joshi case OPTION_STRING: 26598ee79f4SPrasad Joshi if (opts->argh) { 26698ee79f4SPrasad Joshi if (opts->flags & PARSE_OPT_OPTARG) 26798ee79f4SPrasad Joshi if (opts->long_name) 26898ee79f4SPrasad Joshi pos += fprintf(stderr, "[=<%s>]", opts->argh); 26998ee79f4SPrasad Joshi else 27098ee79f4SPrasad Joshi pos += fprintf(stderr, "[<%s>]", opts->argh); 27198ee79f4SPrasad Joshi else 27298ee79f4SPrasad Joshi pos += fprintf(stderr, " <%s>", opts->argh); 27398ee79f4SPrasad Joshi } else { 27498ee79f4SPrasad Joshi if (opts->flags & PARSE_OPT_OPTARG) 27598ee79f4SPrasad Joshi if (opts->long_name) 27698ee79f4SPrasad Joshi pos += fprintf(stderr, "[=...]"); 27798ee79f4SPrasad Joshi else 27898ee79f4SPrasad Joshi pos += fprintf(stderr, "[...]"); 27998ee79f4SPrasad Joshi else 28098ee79f4SPrasad Joshi pos += fprintf(stderr, " ..."); 28198ee79f4SPrasad Joshi } 28298ee79f4SPrasad Joshi break; 28398ee79f4SPrasad Joshi default: /* OPTION_{BIT,BOOLEAN,SET_UINT,SET_PTR} */ 28498ee79f4SPrasad Joshi case OPTION_END: 28598ee79f4SPrasad Joshi case OPTION_GROUP: 28698ee79f4SPrasad Joshi case OPTION_BIT: 28798ee79f4SPrasad Joshi case OPTION_BOOLEAN: 28898ee79f4SPrasad Joshi case OPTION_INCR: 28998ee79f4SPrasad Joshi case OPTION_SET_UINT: 29098ee79f4SPrasad Joshi case OPTION_SET_PTR: 29198ee79f4SPrasad Joshi break; 29298ee79f4SPrasad Joshi } 29398ee79f4SPrasad Joshi if (pos <= USAGE_OPTS_WIDTH) 29498ee79f4SPrasad Joshi pad = USAGE_OPTS_WIDTH - pos; 29598ee79f4SPrasad Joshi else { 29698ee79f4SPrasad Joshi fputc('\n', stderr); 29798ee79f4SPrasad Joshi pad = USAGE_OPTS_WIDTH; 29898ee79f4SPrasad Joshi } 29998ee79f4SPrasad Joshi fprintf(stderr, "%*s%s\n", pad + USAGE_GAP, "", opts->help); 30098ee79f4SPrasad Joshi } 30198ee79f4SPrasad Joshi fputc('\n', stderr); 30298ee79f4SPrasad Joshi 30398ee79f4SPrasad Joshi return PARSE_OPT_HELP; 30498ee79f4SPrasad Joshi } 30598ee79f4SPrasad Joshi 30698ee79f4SPrasad Joshi void usage_with_options(const char * const *usagestr, 30798ee79f4SPrasad Joshi const struct option *opts) 30898ee79f4SPrasad Joshi { 30998ee79f4SPrasad Joshi usage_with_options_internal(usagestr, opts, 0); 31098ee79f4SPrasad Joshi exit(129); 31198ee79f4SPrasad Joshi } 31298ee79f4SPrasad Joshi 31398ee79f4SPrasad Joshi static void check_typos(const char *arg, const struct option *options) 31498ee79f4SPrasad Joshi { 31598ee79f4SPrasad Joshi if (strlen(arg) < 3) 31698ee79f4SPrasad Joshi return; 31798ee79f4SPrasad Joshi 31898ee79f4SPrasad Joshi if (!prefixcmp(arg, "no-")) { 319*4542f276SCyrill Gorcunov pr_error ("did you mean `--%s` (with two dashes ?)", arg); 32098ee79f4SPrasad Joshi exit(129); 32198ee79f4SPrasad Joshi } 32298ee79f4SPrasad Joshi 32398ee79f4SPrasad Joshi for (; options->type != OPTION_END; options++) { 32498ee79f4SPrasad Joshi if (!options->long_name) 32598ee79f4SPrasad Joshi continue; 32698ee79f4SPrasad Joshi if (!prefixcmp(options->long_name, arg)) { 327*4542f276SCyrill Gorcunov pr_error ("did you mean `--%s` (with two dashes ?)", arg); 32898ee79f4SPrasad Joshi exit(129); 32998ee79f4SPrasad Joshi } 33098ee79f4SPrasad Joshi } 33198ee79f4SPrasad Joshi } 33298ee79f4SPrasad Joshi 33398ee79f4SPrasad Joshi static int parse_options_usage(const char * const *usagestr, 33498ee79f4SPrasad Joshi const struct option *opts) 33598ee79f4SPrasad Joshi { 33698ee79f4SPrasad Joshi return usage_with_options_internal(usagestr, opts, 0); 33798ee79f4SPrasad Joshi } 33898ee79f4SPrasad Joshi 33998ee79f4SPrasad Joshi static int parse_short_opt(struct parse_opt_ctx_t *p, 34098ee79f4SPrasad Joshi const struct option *options) 34198ee79f4SPrasad Joshi { 34298ee79f4SPrasad Joshi for (; options->type != OPTION_END; options++) { 34398ee79f4SPrasad Joshi if (options->short_name == *p->opt) { 34498ee79f4SPrasad Joshi p->opt = p->opt[1] ? p->opt + 1 : NULL; 34598ee79f4SPrasad Joshi return get_value(p, options, OPT_SHORT); 34698ee79f4SPrasad Joshi } 34798ee79f4SPrasad Joshi } 34898ee79f4SPrasad Joshi return -2; 34998ee79f4SPrasad Joshi } 35098ee79f4SPrasad Joshi 35198ee79f4SPrasad Joshi static int parse_long_opt(struct parse_opt_ctx_t *p, const char *arg, 35298ee79f4SPrasad Joshi const struct option *options) 35398ee79f4SPrasad Joshi { 35498ee79f4SPrasad Joshi const char *arg_end = strchr(arg, '='); 35598ee79f4SPrasad Joshi const struct option *abbrev_option = NULL, *ambiguous_option = NULL; 35698ee79f4SPrasad Joshi int abbrev_flags = 0, ambiguous_flags = 0; 35798ee79f4SPrasad Joshi 35898ee79f4SPrasad Joshi if (!arg_end) 35998ee79f4SPrasad Joshi arg_end = arg + strlen(arg); 36098ee79f4SPrasad Joshi 36198ee79f4SPrasad Joshi for (; options->type != OPTION_END; options++) { 36298ee79f4SPrasad Joshi const char *rest; 36398ee79f4SPrasad Joshi int flags = 0; 36498ee79f4SPrasad Joshi 36598ee79f4SPrasad Joshi if (!options->long_name) 36698ee79f4SPrasad Joshi continue; 36798ee79f4SPrasad Joshi 36898ee79f4SPrasad Joshi rest = skip_prefix(arg, options->long_name); 36998ee79f4SPrasad Joshi if (options->type == OPTION_ARGUMENT) { 37098ee79f4SPrasad Joshi if (!rest) 37198ee79f4SPrasad Joshi continue; 37298ee79f4SPrasad Joshi if (*rest == '=') 37398ee79f4SPrasad Joshi return opterror(options, "takes no value", 37498ee79f4SPrasad Joshi flags); 37598ee79f4SPrasad Joshi if (*rest) 37698ee79f4SPrasad Joshi continue; 37798ee79f4SPrasad Joshi p->out[p->cpidx++] = arg - 2; 37898ee79f4SPrasad Joshi return 0; 37998ee79f4SPrasad Joshi } 38098ee79f4SPrasad Joshi if (!rest) { 38198ee79f4SPrasad Joshi /* abbreviated? */ 38298ee79f4SPrasad Joshi if (!strncmp(options->long_name, arg, arg_end - arg)) { 38398ee79f4SPrasad Joshi is_abbreviated: 38498ee79f4SPrasad Joshi if (abbrev_option) { 38598ee79f4SPrasad Joshi /* 38698ee79f4SPrasad Joshi * If this is abbreviated, it is 38798ee79f4SPrasad Joshi * ambiguous. So when there is no 38898ee79f4SPrasad Joshi * exact match later, we need to 38998ee79f4SPrasad Joshi * error out. 39098ee79f4SPrasad Joshi */ 39198ee79f4SPrasad Joshi ambiguous_option = abbrev_option; 39298ee79f4SPrasad Joshi ambiguous_flags = abbrev_flags; 39398ee79f4SPrasad Joshi } 39498ee79f4SPrasad Joshi if (!(flags & OPT_UNSET) && *arg_end) 39598ee79f4SPrasad Joshi p->opt = arg_end + 1; 39698ee79f4SPrasad Joshi abbrev_option = options; 39798ee79f4SPrasad Joshi abbrev_flags = flags; 39898ee79f4SPrasad Joshi continue; 39998ee79f4SPrasad Joshi } 40098ee79f4SPrasad Joshi /* negated and abbreviated very much? */ 40198ee79f4SPrasad Joshi if (!prefixcmp("no-", arg)) { 40298ee79f4SPrasad Joshi flags |= OPT_UNSET; 40398ee79f4SPrasad Joshi goto is_abbreviated; 40498ee79f4SPrasad Joshi } 40598ee79f4SPrasad Joshi /* negated? */ 40698ee79f4SPrasad Joshi if (strncmp(arg, "no-", 3)) 40798ee79f4SPrasad Joshi continue; 40898ee79f4SPrasad Joshi flags |= OPT_UNSET; 40998ee79f4SPrasad Joshi rest = skip_prefix(arg + 3, options->long_name); 41098ee79f4SPrasad Joshi /* abbreviated and negated? */ 41198ee79f4SPrasad Joshi if (!rest && !prefixcmp(options->long_name, arg + 3)) 41298ee79f4SPrasad Joshi goto is_abbreviated; 41398ee79f4SPrasad Joshi if (!rest) 41498ee79f4SPrasad Joshi continue; 41598ee79f4SPrasad Joshi } 41698ee79f4SPrasad Joshi if (*rest) { 41798ee79f4SPrasad Joshi if (*rest != '=') 41898ee79f4SPrasad Joshi continue; 41998ee79f4SPrasad Joshi p->opt = rest + 1; 42098ee79f4SPrasad Joshi } 42198ee79f4SPrasad Joshi return get_value(p, options, flags); 42298ee79f4SPrasad Joshi } 42398ee79f4SPrasad Joshi 42498ee79f4SPrasad Joshi if (ambiguous_option) 425*4542f276SCyrill Gorcunov return pr_error("Ambiguous option: %s " 42698ee79f4SPrasad Joshi "(could be --%s%s or --%s%s)", 42798ee79f4SPrasad Joshi arg, 42898ee79f4SPrasad Joshi (ambiguous_flags & OPT_UNSET) ? "no-" : "", 42998ee79f4SPrasad Joshi ambiguous_option->long_name, 43098ee79f4SPrasad Joshi (abbrev_flags & OPT_UNSET) ? "no-" : "", 43198ee79f4SPrasad Joshi abbrev_option->long_name); 43298ee79f4SPrasad Joshi if (abbrev_option) 43398ee79f4SPrasad Joshi return get_value(p, abbrev_option, abbrev_flags); 43498ee79f4SPrasad Joshi return -2; 43598ee79f4SPrasad Joshi } 43698ee79f4SPrasad Joshi 43798ee79f4SPrasad Joshi 43898ee79f4SPrasad Joshi static void parse_options_start(struct parse_opt_ctx_t *ctx, int argc, 43998ee79f4SPrasad Joshi const char **argv, int flags) 44098ee79f4SPrasad Joshi { 44198ee79f4SPrasad Joshi memset(ctx, 0, sizeof(*ctx)); 44298ee79f4SPrasad Joshi ctx->argc = argc; 44398ee79f4SPrasad Joshi ctx->argv = argv; 44498ee79f4SPrasad Joshi ctx->out = argv; 44598ee79f4SPrasad Joshi ctx->cpidx = ((flags & PARSE_OPT_KEEP_ARGV0) != 0); 44698ee79f4SPrasad Joshi ctx->flags = flags; 44798ee79f4SPrasad Joshi if ((flags & PARSE_OPT_KEEP_UNKNOWN) && 44898ee79f4SPrasad Joshi (flags & PARSE_OPT_STOP_AT_NON_OPTION)) 44998ee79f4SPrasad Joshi die("STOP_AT_NON_OPTION and KEEP_UNKNOWN don't go together"); 45098ee79f4SPrasad Joshi } 45198ee79f4SPrasad Joshi 45298ee79f4SPrasad Joshi static int parse_options_end(struct parse_opt_ctx_t *ctx) 45398ee79f4SPrasad Joshi { 45498ee79f4SPrasad Joshi memmove(ctx->out + ctx->cpidx, ctx->argv, ctx->argc * sizeof(*ctx->out)); 45598ee79f4SPrasad Joshi ctx->out[ctx->cpidx + ctx->argc] = NULL; 45698ee79f4SPrasad Joshi return ctx->cpidx + ctx->argc; 45798ee79f4SPrasad Joshi } 45898ee79f4SPrasad Joshi 45998ee79f4SPrasad Joshi 46098ee79f4SPrasad Joshi static int parse_options_step(struct parse_opt_ctx_t *ctx, 46198ee79f4SPrasad Joshi const struct option *options, const char * const usagestr[]) 46298ee79f4SPrasad Joshi { 46398ee79f4SPrasad Joshi int internal_help = !(ctx->flags & PARSE_OPT_NO_INTERNAL_HELP); 46498ee79f4SPrasad Joshi 46598ee79f4SPrasad Joshi /* we must reset ->opt, unknown short option leave it dangling */ 46698ee79f4SPrasad Joshi ctx->opt = NULL; 46798ee79f4SPrasad Joshi 46898ee79f4SPrasad Joshi for (; ctx->argc; ctx->argc--, ctx->argv++) { 46998ee79f4SPrasad Joshi const char *arg = ctx->argv[0]; 47098ee79f4SPrasad Joshi 47198ee79f4SPrasad Joshi if (*arg != '-' || !arg[1]) { 47298ee79f4SPrasad Joshi if (ctx->flags & PARSE_OPT_STOP_AT_NON_OPTION) 47398ee79f4SPrasad Joshi break; 47498ee79f4SPrasad Joshi ctx->out[ctx->cpidx++] = ctx->argv[0]; 47598ee79f4SPrasad Joshi continue; 47698ee79f4SPrasad Joshi } 47798ee79f4SPrasad Joshi 47898ee79f4SPrasad Joshi if (arg[1] != '-') { 47998ee79f4SPrasad Joshi ctx->opt = arg + 1; 48098ee79f4SPrasad Joshi if (internal_help && *ctx->opt == 'h') 48198ee79f4SPrasad Joshi return parse_options_usage(usagestr, options); 48298ee79f4SPrasad Joshi switch (parse_short_opt(ctx, options)) { 48398ee79f4SPrasad Joshi case -1: 48498ee79f4SPrasad Joshi return parse_options_usage(usagestr, options); 48598ee79f4SPrasad Joshi case -2: 48698ee79f4SPrasad Joshi goto unknown; 48798ee79f4SPrasad Joshi default: 48898ee79f4SPrasad Joshi break; 48998ee79f4SPrasad Joshi } 49098ee79f4SPrasad Joshi if (ctx->opt) 49198ee79f4SPrasad Joshi check_typos(arg + 1, options); 49298ee79f4SPrasad Joshi while (ctx->opt) { 49398ee79f4SPrasad Joshi if (internal_help && *ctx->opt == 'h') 49498ee79f4SPrasad Joshi return parse_options_usage(usagestr, 49598ee79f4SPrasad Joshi options); 49698ee79f4SPrasad Joshi switch (parse_short_opt(ctx, options)) { 49798ee79f4SPrasad Joshi case -1: 49898ee79f4SPrasad Joshi return parse_options_usage(usagestr, 49998ee79f4SPrasad Joshi options); 50098ee79f4SPrasad Joshi case -2: 50198ee79f4SPrasad Joshi /* fake a short option thing to hide 50298ee79f4SPrasad Joshi * the fact that we may have 50398ee79f4SPrasad Joshi * started to parse aggregated stuff 50498ee79f4SPrasad Joshi * 50598ee79f4SPrasad Joshi * This is leaky, too bad. 50698ee79f4SPrasad Joshi */ 50798ee79f4SPrasad Joshi ctx->argv[0] = strdup(ctx->opt - 1); 50898ee79f4SPrasad Joshi *(char *)ctx->argv[0] = '-'; 50998ee79f4SPrasad Joshi goto unknown; 51098ee79f4SPrasad Joshi default: 51198ee79f4SPrasad Joshi break; 51298ee79f4SPrasad Joshi } 51398ee79f4SPrasad Joshi } 51498ee79f4SPrasad Joshi continue; 51598ee79f4SPrasad Joshi } 51698ee79f4SPrasad Joshi 51798ee79f4SPrasad Joshi if (!arg[2]) { /* "--" */ 51898ee79f4SPrasad Joshi if (!(ctx->flags & PARSE_OPT_KEEP_DASHDASH)) { 51998ee79f4SPrasad Joshi ctx->argc--; 52098ee79f4SPrasad Joshi ctx->argv++; 52198ee79f4SPrasad Joshi } 52298ee79f4SPrasad Joshi break; 52398ee79f4SPrasad Joshi } 52498ee79f4SPrasad Joshi 52598ee79f4SPrasad Joshi if (internal_help && !strcmp(arg + 2, "help-all")) 52698ee79f4SPrasad Joshi return usage_with_options_internal(usagestr, options, 52798ee79f4SPrasad Joshi 1); 52898ee79f4SPrasad Joshi if (internal_help && !strcmp(arg + 2, "help")) 52998ee79f4SPrasad Joshi return parse_options_usage(usagestr, options); 53098ee79f4SPrasad Joshi switch (parse_long_opt(ctx, arg + 2, options)) { 53198ee79f4SPrasad Joshi case -1: 53298ee79f4SPrasad Joshi return parse_options_usage(usagestr, options); 53398ee79f4SPrasad Joshi case -2: 53498ee79f4SPrasad Joshi goto unknown; 53598ee79f4SPrasad Joshi default: 53698ee79f4SPrasad Joshi break; 53798ee79f4SPrasad Joshi } 53898ee79f4SPrasad Joshi continue; 53998ee79f4SPrasad Joshi unknown: 54098ee79f4SPrasad Joshi if (!(ctx->flags & PARSE_OPT_KEEP_UNKNOWN)) 54198ee79f4SPrasad Joshi return PARSE_OPT_UNKNOWN; 54298ee79f4SPrasad Joshi ctx->out[ctx->cpidx++] = ctx->argv[0]; 54398ee79f4SPrasad Joshi ctx->opt = NULL; 54498ee79f4SPrasad Joshi } 54598ee79f4SPrasad Joshi return PARSE_OPT_DONE; 54698ee79f4SPrasad Joshi } 54798ee79f4SPrasad Joshi 54898ee79f4SPrasad Joshi int parse_options(int argc, const char **argv, const struct option *options, 54998ee79f4SPrasad Joshi const char * const usagestr[], int flags) 55098ee79f4SPrasad Joshi { 55198ee79f4SPrasad Joshi struct parse_opt_ctx_t ctx; 55298ee79f4SPrasad Joshi 55398ee79f4SPrasad Joshi parse_options_start(&ctx, argc, argv, flags); 55498ee79f4SPrasad Joshi switch (parse_options_step(&ctx, options, usagestr)) { 55598ee79f4SPrasad Joshi case PARSE_OPT_HELP: 55698ee79f4SPrasad Joshi exit(129); 55798ee79f4SPrasad Joshi case PARSE_OPT_DONE: 55898ee79f4SPrasad Joshi break; 55998ee79f4SPrasad Joshi default: /* PARSE_OPT_UNKNOWN */ 56098ee79f4SPrasad Joshi if (ctx.argv[0][1] == '-') { 561*4542f276SCyrill Gorcunov pr_error("unknown option `%s'", ctx.argv[0] + 2); 56298ee79f4SPrasad Joshi } else { 563*4542f276SCyrill Gorcunov pr_error("unknown switch `%c'", *ctx.opt); 56498ee79f4SPrasad Joshi } 56598ee79f4SPrasad Joshi usage_with_options(usagestr, options); 56698ee79f4SPrasad Joshi } 56798ee79f4SPrasad Joshi 56898ee79f4SPrasad Joshi return parse_options_end(&ctx); 56998ee79f4SPrasad Joshi } 570