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) 194542f276SCyrill Gorcunov return pr_error("switch `%c' %s", opt->short_name, reason); 2098ee79f4SPrasad Joshi if (flags & OPT_UNSET) 214542f276SCyrill Gorcunov return pr_error("option `no-%s' %s", opt->long_name, reason); 224542f276SCyrill 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 42*dec94ae9SCyrill Gorcunov #define numvalue(c) \ 43*dec94ae9SCyrill Gorcunov ((c) >= 'a' ? (c) - 'a' + 10 : \ 44*dec94ae9SCyrill Gorcunov (c) >= 'A' ? (c) - 'A' + 10 : (c) - '0') 45*dec94ae9SCyrill Gorcunov 46*dec94ae9SCyrill Gorcunov static u64 readhex(const char *str, bool *error) 47*dec94ae9SCyrill Gorcunov { 48*dec94ae9SCyrill Gorcunov char *pos = strchr(str, 'x') + 1; 49*dec94ae9SCyrill Gorcunov u64 res = 0; 50*dec94ae9SCyrill Gorcunov 51*dec94ae9SCyrill Gorcunov while (*pos) { 52*dec94ae9SCyrill Gorcunov unsigned int v = numvalue(*pos); 53*dec94ae9SCyrill Gorcunov if (v > 16) { 54*dec94ae9SCyrill Gorcunov *error = true; 55*dec94ae9SCyrill Gorcunov return 0; 56*dec94ae9SCyrill Gorcunov } 57*dec94ae9SCyrill Gorcunov 58*dec94ae9SCyrill Gorcunov res = (res * 16) + v; 59*dec94ae9SCyrill Gorcunov pos++; 60*dec94ae9SCyrill Gorcunov } 61*dec94ae9SCyrill Gorcunov 62*dec94ae9SCyrill Gorcunov *error = false; 63*dec94ae9SCyrill Gorcunov return res; 64*dec94ae9SCyrill Gorcunov } 65*dec94ae9SCyrill Gorcunov 66*dec94ae9SCyrill Gorcunov static int readnum(const struct option *opt, int flags, 67*dec94ae9SCyrill Gorcunov const char *str, char **end) 68*dec94ae9SCyrill Gorcunov { 69*dec94ae9SCyrill Gorcunov if (strchr(str, 'x')) { 70*dec94ae9SCyrill Gorcunov bool error; 71*dec94ae9SCyrill Gorcunov u64 value; 72*dec94ae9SCyrill Gorcunov 73*dec94ae9SCyrill Gorcunov value = readhex(str, &error); 74*dec94ae9SCyrill Gorcunov if (error) 75*dec94ae9SCyrill Gorcunov goto enotnum; 76*dec94ae9SCyrill Gorcunov 77*dec94ae9SCyrill Gorcunov switch (opt->type) { 78*dec94ae9SCyrill Gorcunov case OPTION_INTEGER: 79*dec94ae9SCyrill Gorcunov *(int *)opt->value = value; 80*dec94ae9SCyrill Gorcunov break; 81*dec94ae9SCyrill Gorcunov case OPTION_UINTEGER: 82*dec94ae9SCyrill Gorcunov *(unsigned int *)opt->value = value; 83*dec94ae9SCyrill Gorcunov break; 84*dec94ae9SCyrill Gorcunov case OPTION_LONG: 85*dec94ae9SCyrill Gorcunov *(long *)opt->value = value; 86*dec94ae9SCyrill Gorcunov break; 87*dec94ae9SCyrill Gorcunov case OPTION_U64: 88*dec94ae9SCyrill Gorcunov *(u64 *)opt->value = value; 89*dec94ae9SCyrill Gorcunov break; 90*dec94ae9SCyrill Gorcunov default: 91*dec94ae9SCyrill Gorcunov goto invcall; 92*dec94ae9SCyrill Gorcunov } 93*dec94ae9SCyrill Gorcunov } else { 94*dec94ae9SCyrill Gorcunov switch (opt->type) { 95*dec94ae9SCyrill Gorcunov case OPTION_INTEGER: 96*dec94ae9SCyrill Gorcunov *(int *)opt->value = strtol(str, end, 10); 97*dec94ae9SCyrill Gorcunov break; 98*dec94ae9SCyrill Gorcunov case OPTION_UINTEGER: 99*dec94ae9SCyrill Gorcunov *(unsigned int *)opt->value = strtol(str, end, 10); 100*dec94ae9SCyrill Gorcunov break; 101*dec94ae9SCyrill Gorcunov case OPTION_LONG: 102*dec94ae9SCyrill Gorcunov *(long *)opt->value = strtol(str, end, 10); 103*dec94ae9SCyrill Gorcunov break; 104*dec94ae9SCyrill Gorcunov case OPTION_U64: 105*dec94ae9SCyrill Gorcunov *(u64 *)opt->value = strtoull(str, end, 10); 106*dec94ae9SCyrill Gorcunov break; 107*dec94ae9SCyrill Gorcunov default: 108*dec94ae9SCyrill Gorcunov goto invcall; 109*dec94ae9SCyrill Gorcunov } 110*dec94ae9SCyrill Gorcunov } 111*dec94ae9SCyrill Gorcunov 112*dec94ae9SCyrill Gorcunov return 0; 113*dec94ae9SCyrill Gorcunov 114*dec94ae9SCyrill Gorcunov enotnum: 115*dec94ae9SCyrill Gorcunov return opterror(opt, "expects a numerical value", flags); 116*dec94ae9SCyrill Gorcunov invcall: 117*dec94ae9SCyrill Gorcunov return opterror(opt, "invalid numeric conversion", flags); 118*dec94ae9SCyrill Gorcunov } 119*dec94ae9SCyrill Gorcunov 12098ee79f4SPrasad Joshi static int get_value(struct parse_opt_ctx_t *p, 12198ee79f4SPrasad Joshi const struct option *opt, int flags) 12298ee79f4SPrasad Joshi { 12398ee79f4SPrasad Joshi const char *s, *arg = NULL; 12498ee79f4SPrasad Joshi const int unset = flags & OPT_UNSET; 12598ee79f4SPrasad Joshi 12698ee79f4SPrasad Joshi if (unset && p->opt) 12798ee79f4SPrasad Joshi return opterror(opt, "takes no value", flags); 12898ee79f4SPrasad Joshi if (unset && (opt->flags & PARSE_OPT_NONEG)) 12998ee79f4SPrasad Joshi return opterror(opt, "isn't available", flags); 13098ee79f4SPrasad Joshi 13198ee79f4SPrasad Joshi if (!(flags & OPT_SHORT) && p->opt) { 13298ee79f4SPrasad Joshi switch (opt->type) { 13398ee79f4SPrasad Joshi case OPTION_CALLBACK: 13498ee79f4SPrasad Joshi if (!(opt->flags & PARSE_OPT_NOARG)) 13598ee79f4SPrasad Joshi break; 13698ee79f4SPrasad Joshi /* FALLTHROUGH */ 13798ee79f4SPrasad Joshi case OPTION_BOOLEAN: 13898ee79f4SPrasad Joshi case OPTION_INCR: 13998ee79f4SPrasad Joshi case OPTION_BIT: 14098ee79f4SPrasad Joshi case OPTION_SET_UINT: 14198ee79f4SPrasad Joshi case OPTION_SET_PTR: 14298ee79f4SPrasad Joshi return opterror(opt, "takes no value", flags); 14398ee79f4SPrasad Joshi case OPTION_END: 14498ee79f4SPrasad Joshi case OPTION_ARGUMENT: 14598ee79f4SPrasad Joshi case OPTION_GROUP: 14698ee79f4SPrasad Joshi case OPTION_STRING: 14798ee79f4SPrasad Joshi case OPTION_INTEGER: 14898ee79f4SPrasad Joshi case OPTION_UINTEGER: 14998ee79f4SPrasad Joshi case OPTION_LONG: 15098ee79f4SPrasad Joshi case OPTION_U64: 15198ee79f4SPrasad Joshi default: 15298ee79f4SPrasad Joshi break; 15398ee79f4SPrasad Joshi } 15498ee79f4SPrasad Joshi } 15598ee79f4SPrasad Joshi 15698ee79f4SPrasad Joshi switch (opt->type) { 15798ee79f4SPrasad Joshi case OPTION_BIT: 15898ee79f4SPrasad Joshi if (unset) 15998ee79f4SPrasad Joshi *(int *)opt->value &= ~opt->defval; 16098ee79f4SPrasad Joshi else 16198ee79f4SPrasad Joshi *(int *)opt->value |= opt->defval; 16298ee79f4SPrasad Joshi return 0; 16398ee79f4SPrasad Joshi 16498ee79f4SPrasad Joshi case OPTION_BOOLEAN: 16598ee79f4SPrasad Joshi *(bool *)opt->value = unset ? false : true; 16698ee79f4SPrasad Joshi return 0; 16798ee79f4SPrasad Joshi 16898ee79f4SPrasad Joshi case OPTION_INCR: 16998ee79f4SPrasad Joshi *(int *)opt->value = unset ? 0 : *(int *)opt->value + 1; 17098ee79f4SPrasad Joshi return 0; 17198ee79f4SPrasad Joshi 17298ee79f4SPrasad Joshi case OPTION_SET_UINT: 17398ee79f4SPrasad Joshi *(unsigned int *)opt->value = unset ? 0 : opt->defval; 17498ee79f4SPrasad Joshi return 0; 17598ee79f4SPrasad Joshi 17698ee79f4SPrasad Joshi case OPTION_SET_PTR: 17798ee79f4SPrasad Joshi *(void **)opt->value = unset ? NULL : (void *)opt->defval; 17898ee79f4SPrasad Joshi return 0; 17998ee79f4SPrasad Joshi 18098ee79f4SPrasad Joshi case OPTION_STRING: 18198ee79f4SPrasad Joshi if (unset) 18298ee79f4SPrasad Joshi *(const char **)opt->value = NULL; 18398ee79f4SPrasad Joshi else if (opt->flags & PARSE_OPT_OPTARG && !p->opt) 18498ee79f4SPrasad Joshi *(const char **)opt->value = (const char *)opt->defval; 18598ee79f4SPrasad Joshi else 18698ee79f4SPrasad Joshi return get_arg(p, opt, flags, 18798ee79f4SPrasad Joshi (const char **)opt->value); 18898ee79f4SPrasad Joshi return 0; 18998ee79f4SPrasad Joshi 19098ee79f4SPrasad Joshi case OPTION_CALLBACK: 19198ee79f4SPrasad Joshi if (unset) 19298ee79f4SPrasad Joshi return (*opt->callback)(opt, NULL, 1) ? (-1) : 0; 19398ee79f4SPrasad Joshi if (opt->flags & PARSE_OPT_NOARG) 19498ee79f4SPrasad Joshi return (*opt->callback)(opt, NULL, 0) ? (-1) : 0; 19598ee79f4SPrasad Joshi if (opt->flags & PARSE_OPT_OPTARG && !p->opt) 19698ee79f4SPrasad Joshi return (*opt->callback)(opt, NULL, 0) ? (-1) : 0; 19798ee79f4SPrasad Joshi if (get_arg(p, opt, flags, &arg)) 19898ee79f4SPrasad Joshi return -1; 19998ee79f4SPrasad Joshi return (*opt->callback)(opt, arg, 0) ? (-1) : 0; 20098ee79f4SPrasad Joshi 20198ee79f4SPrasad Joshi case OPTION_INTEGER: 20298ee79f4SPrasad Joshi if (unset) { 20398ee79f4SPrasad Joshi *(int *)opt->value = 0; 20498ee79f4SPrasad Joshi return 0; 20598ee79f4SPrasad Joshi } 20698ee79f4SPrasad Joshi if (opt->flags & PARSE_OPT_OPTARG && !p->opt) { 20798ee79f4SPrasad Joshi *(int *)opt->value = opt->defval; 20898ee79f4SPrasad Joshi return 0; 20998ee79f4SPrasad Joshi } 21098ee79f4SPrasad Joshi if (get_arg(p, opt, flags, &arg)) 21198ee79f4SPrasad Joshi return -1; 212*dec94ae9SCyrill Gorcunov return readnum(opt, flags, arg, (char **)&s); 21398ee79f4SPrasad Joshi 21498ee79f4SPrasad Joshi case OPTION_UINTEGER: 21598ee79f4SPrasad Joshi if (unset) { 21698ee79f4SPrasad Joshi *(unsigned int *)opt->value = 0; 21798ee79f4SPrasad Joshi return 0; 21898ee79f4SPrasad Joshi } 21998ee79f4SPrasad Joshi if (opt->flags & PARSE_OPT_OPTARG && !p->opt) { 22098ee79f4SPrasad Joshi *(unsigned int *)opt->value = opt->defval; 22198ee79f4SPrasad Joshi return 0; 22298ee79f4SPrasad Joshi } 22398ee79f4SPrasad Joshi if (get_arg(p, opt, flags, &arg)) 22498ee79f4SPrasad Joshi return -1; 225*dec94ae9SCyrill Gorcunov return readnum(opt, flags, arg, (char **)&s); 22698ee79f4SPrasad Joshi 22798ee79f4SPrasad Joshi case OPTION_LONG: 22898ee79f4SPrasad Joshi if (unset) { 22998ee79f4SPrasad Joshi *(long *)opt->value = 0; 23098ee79f4SPrasad Joshi return 0; 23198ee79f4SPrasad Joshi } 23298ee79f4SPrasad Joshi if (opt->flags & PARSE_OPT_OPTARG && !p->opt) { 23398ee79f4SPrasad Joshi *(long *)opt->value = opt->defval; 23498ee79f4SPrasad Joshi return 0; 23598ee79f4SPrasad Joshi } 23698ee79f4SPrasad Joshi if (get_arg(p, opt, flags, &arg)) 23798ee79f4SPrasad Joshi return -1; 238*dec94ae9SCyrill Gorcunov return readnum(opt, flags, arg, (char **)&s); 23998ee79f4SPrasad Joshi 24098ee79f4SPrasad Joshi case OPTION_U64: 24198ee79f4SPrasad Joshi if (unset) { 24298ee79f4SPrasad Joshi *(u64 *)opt->value = 0; 24398ee79f4SPrasad Joshi return 0; 24498ee79f4SPrasad Joshi } 24598ee79f4SPrasad Joshi if (opt->flags & PARSE_OPT_OPTARG && !p->opt) { 24698ee79f4SPrasad Joshi *(u64 *)opt->value = opt->defval; 24798ee79f4SPrasad Joshi return 0; 24898ee79f4SPrasad Joshi } 24998ee79f4SPrasad Joshi if (get_arg(p, opt, flags, &arg)) 25098ee79f4SPrasad Joshi return -1; 251*dec94ae9SCyrill Gorcunov return readnum(opt, flags, arg, (char **)&s); 25298ee79f4SPrasad Joshi 25398ee79f4SPrasad Joshi case OPTION_END: 25498ee79f4SPrasad Joshi case OPTION_ARGUMENT: 25598ee79f4SPrasad Joshi case OPTION_GROUP: 25698ee79f4SPrasad Joshi default: 25798ee79f4SPrasad Joshi die("should not happen, someone must be hit on the forehead"); 25898ee79f4SPrasad Joshi } 25998ee79f4SPrasad Joshi } 26098ee79f4SPrasad Joshi 26198ee79f4SPrasad Joshi #define USAGE_OPTS_WIDTH 24 26298ee79f4SPrasad Joshi #define USAGE_GAP 2 26398ee79f4SPrasad Joshi 26498ee79f4SPrasad Joshi static int usage_with_options_internal(const char * const *usagestr, 26598ee79f4SPrasad Joshi const struct option *opts, int full) 26698ee79f4SPrasad Joshi { 26798ee79f4SPrasad Joshi if (!usagestr) 26898ee79f4SPrasad Joshi return PARSE_OPT_HELP; 26998ee79f4SPrasad Joshi 27098ee79f4SPrasad Joshi fprintf(stderr, "\n usage: %s\n", *usagestr++); 27198ee79f4SPrasad Joshi while (*usagestr && **usagestr) 27298ee79f4SPrasad Joshi fprintf(stderr, " or: %s\n", *usagestr++); 27398ee79f4SPrasad Joshi while (*usagestr) { 27498ee79f4SPrasad Joshi fprintf(stderr, "%s%s\n", 27598ee79f4SPrasad Joshi **usagestr ? " " : "", 27698ee79f4SPrasad Joshi *usagestr); 27798ee79f4SPrasad Joshi usagestr++; 27898ee79f4SPrasad Joshi } 27998ee79f4SPrasad Joshi 28098ee79f4SPrasad Joshi if (opts->type != OPTION_GROUP) 28198ee79f4SPrasad Joshi fputc('\n', stderr); 28298ee79f4SPrasad Joshi 28398ee79f4SPrasad Joshi for (; opts->type != OPTION_END; opts++) { 28498ee79f4SPrasad Joshi size_t pos; 28598ee79f4SPrasad Joshi int pad; 28698ee79f4SPrasad Joshi 28798ee79f4SPrasad Joshi if (opts->type == OPTION_GROUP) { 28898ee79f4SPrasad Joshi fputc('\n', stderr); 28998ee79f4SPrasad Joshi if (*opts->help) 29098ee79f4SPrasad Joshi fprintf(stderr, "%s\n", opts->help); 29198ee79f4SPrasad Joshi continue; 29298ee79f4SPrasad Joshi } 29398ee79f4SPrasad Joshi if (!full && (opts->flags & PARSE_OPT_HIDDEN)) 29498ee79f4SPrasad Joshi continue; 29598ee79f4SPrasad Joshi 29698ee79f4SPrasad Joshi pos = fprintf(stderr, " "); 29798ee79f4SPrasad Joshi if (opts->short_name) 29898ee79f4SPrasad Joshi pos += fprintf(stderr, "-%c", opts->short_name); 29998ee79f4SPrasad Joshi else 30098ee79f4SPrasad Joshi pos += fprintf(stderr, " "); 30198ee79f4SPrasad Joshi 30298ee79f4SPrasad Joshi if (opts->long_name && opts->short_name) 30398ee79f4SPrasad Joshi pos += fprintf(stderr, ", "); 30498ee79f4SPrasad Joshi if (opts->long_name) 30598ee79f4SPrasad Joshi pos += fprintf(stderr, "--%s", opts->long_name); 30698ee79f4SPrasad Joshi 30798ee79f4SPrasad Joshi switch (opts->type) { 30898ee79f4SPrasad Joshi case OPTION_ARGUMENT: 30998ee79f4SPrasad Joshi break; 31098ee79f4SPrasad Joshi case OPTION_LONG: 31198ee79f4SPrasad Joshi case OPTION_U64: 31298ee79f4SPrasad Joshi case OPTION_INTEGER: 31398ee79f4SPrasad Joshi case OPTION_UINTEGER: 31498ee79f4SPrasad Joshi if (opts->flags & PARSE_OPT_OPTARG) 31598ee79f4SPrasad Joshi if (opts->long_name) 31698ee79f4SPrasad Joshi pos += fprintf(stderr, "[=<n>]"); 31798ee79f4SPrasad Joshi else 31898ee79f4SPrasad Joshi pos += fprintf(stderr, "[<n>]"); 31998ee79f4SPrasad Joshi else 32098ee79f4SPrasad Joshi pos += fprintf(stderr, " <n>"); 32198ee79f4SPrasad Joshi break; 32298ee79f4SPrasad Joshi case OPTION_CALLBACK: 32398ee79f4SPrasad Joshi if (opts->flags & PARSE_OPT_NOARG) 32498ee79f4SPrasad Joshi break; 32598ee79f4SPrasad Joshi /* FALLTHROUGH */ 32698ee79f4SPrasad Joshi case OPTION_STRING: 32798ee79f4SPrasad Joshi if (opts->argh) { 32898ee79f4SPrasad Joshi if (opts->flags & PARSE_OPT_OPTARG) 32998ee79f4SPrasad Joshi if (opts->long_name) 33098ee79f4SPrasad Joshi pos += fprintf(stderr, "[=<%s>]", opts->argh); 33198ee79f4SPrasad Joshi else 33298ee79f4SPrasad Joshi pos += fprintf(stderr, "[<%s>]", opts->argh); 33398ee79f4SPrasad Joshi else 33498ee79f4SPrasad Joshi pos += fprintf(stderr, " <%s>", opts->argh); 33598ee79f4SPrasad Joshi } else { 33698ee79f4SPrasad Joshi if (opts->flags & PARSE_OPT_OPTARG) 33798ee79f4SPrasad Joshi if (opts->long_name) 33898ee79f4SPrasad Joshi pos += fprintf(stderr, "[=...]"); 33998ee79f4SPrasad Joshi else 34098ee79f4SPrasad Joshi pos += fprintf(stderr, "[...]"); 34198ee79f4SPrasad Joshi else 34298ee79f4SPrasad Joshi pos += fprintf(stderr, " ..."); 34398ee79f4SPrasad Joshi } 34498ee79f4SPrasad Joshi break; 34598ee79f4SPrasad Joshi default: /* OPTION_{BIT,BOOLEAN,SET_UINT,SET_PTR} */ 34698ee79f4SPrasad Joshi case OPTION_END: 34798ee79f4SPrasad Joshi case OPTION_GROUP: 34898ee79f4SPrasad Joshi case OPTION_BIT: 34998ee79f4SPrasad Joshi case OPTION_BOOLEAN: 35098ee79f4SPrasad Joshi case OPTION_INCR: 35198ee79f4SPrasad Joshi case OPTION_SET_UINT: 35298ee79f4SPrasad Joshi case OPTION_SET_PTR: 35398ee79f4SPrasad Joshi break; 35498ee79f4SPrasad Joshi } 35598ee79f4SPrasad Joshi if (pos <= USAGE_OPTS_WIDTH) 35698ee79f4SPrasad Joshi pad = USAGE_OPTS_WIDTH - pos; 35798ee79f4SPrasad Joshi else { 35898ee79f4SPrasad Joshi fputc('\n', stderr); 35998ee79f4SPrasad Joshi pad = USAGE_OPTS_WIDTH; 36098ee79f4SPrasad Joshi } 36198ee79f4SPrasad Joshi fprintf(stderr, "%*s%s\n", pad + USAGE_GAP, "", opts->help); 36298ee79f4SPrasad Joshi } 36398ee79f4SPrasad Joshi fputc('\n', stderr); 36498ee79f4SPrasad Joshi 36598ee79f4SPrasad Joshi return PARSE_OPT_HELP; 36698ee79f4SPrasad Joshi } 36798ee79f4SPrasad Joshi 36898ee79f4SPrasad Joshi void usage_with_options(const char * const *usagestr, 36998ee79f4SPrasad Joshi const struct option *opts) 37098ee79f4SPrasad Joshi { 37198ee79f4SPrasad Joshi usage_with_options_internal(usagestr, opts, 0); 37298ee79f4SPrasad Joshi exit(129); 37398ee79f4SPrasad Joshi } 37498ee79f4SPrasad Joshi 37598ee79f4SPrasad Joshi static void check_typos(const char *arg, const struct option *options) 37698ee79f4SPrasad Joshi { 37798ee79f4SPrasad Joshi if (strlen(arg) < 3) 37898ee79f4SPrasad Joshi return; 37998ee79f4SPrasad Joshi 38098ee79f4SPrasad Joshi if (!prefixcmp(arg, "no-")) { 3814542f276SCyrill Gorcunov pr_error ("did you mean `--%s` (with two dashes ?)", arg); 38298ee79f4SPrasad Joshi exit(129); 38398ee79f4SPrasad Joshi } 38498ee79f4SPrasad Joshi 38598ee79f4SPrasad Joshi for (; options->type != OPTION_END; options++) { 38698ee79f4SPrasad Joshi if (!options->long_name) 38798ee79f4SPrasad Joshi continue; 38898ee79f4SPrasad Joshi if (!prefixcmp(options->long_name, arg)) { 3894542f276SCyrill Gorcunov pr_error ("did you mean `--%s` (with two dashes ?)", arg); 39098ee79f4SPrasad Joshi exit(129); 39198ee79f4SPrasad Joshi } 39298ee79f4SPrasad Joshi } 39398ee79f4SPrasad Joshi } 39498ee79f4SPrasad Joshi 39598ee79f4SPrasad Joshi static int parse_options_usage(const char * const *usagestr, 39698ee79f4SPrasad Joshi const struct option *opts) 39798ee79f4SPrasad Joshi { 39898ee79f4SPrasad Joshi return usage_with_options_internal(usagestr, opts, 0); 39998ee79f4SPrasad Joshi } 40098ee79f4SPrasad Joshi 40198ee79f4SPrasad Joshi static int parse_short_opt(struct parse_opt_ctx_t *p, 40298ee79f4SPrasad Joshi const struct option *options) 40398ee79f4SPrasad Joshi { 40498ee79f4SPrasad Joshi for (; options->type != OPTION_END; options++) { 40598ee79f4SPrasad Joshi if (options->short_name == *p->opt) { 40698ee79f4SPrasad Joshi p->opt = p->opt[1] ? p->opt + 1 : NULL; 40798ee79f4SPrasad Joshi return get_value(p, options, OPT_SHORT); 40898ee79f4SPrasad Joshi } 40998ee79f4SPrasad Joshi } 41098ee79f4SPrasad Joshi return -2; 41198ee79f4SPrasad Joshi } 41298ee79f4SPrasad Joshi 41398ee79f4SPrasad Joshi static int parse_long_opt(struct parse_opt_ctx_t *p, const char *arg, 41498ee79f4SPrasad Joshi const struct option *options) 41598ee79f4SPrasad Joshi { 41698ee79f4SPrasad Joshi const char *arg_end = strchr(arg, '='); 41798ee79f4SPrasad Joshi const struct option *abbrev_option = NULL, *ambiguous_option = NULL; 41898ee79f4SPrasad Joshi int abbrev_flags = 0, ambiguous_flags = 0; 41998ee79f4SPrasad Joshi 42098ee79f4SPrasad Joshi if (!arg_end) 42198ee79f4SPrasad Joshi arg_end = arg + strlen(arg); 42298ee79f4SPrasad Joshi 42398ee79f4SPrasad Joshi for (; options->type != OPTION_END; options++) { 42498ee79f4SPrasad Joshi const char *rest; 42598ee79f4SPrasad Joshi int flags = 0; 42698ee79f4SPrasad Joshi 42798ee79f4SPrasad Joshi if (!options->long_name) 42898ee79f4SPrasad Joshi continue; 42998ee79f4SPrasad Joshi 43098ee79f4SPrasad Joshi rest = skip_prefix(arg, options->long_name); 43198ee79f4SPrasad Joshi if (options->type == OPTION_ARGUMENT) { 43298ee79f4SPrasad Joshi if (!rest) 43398ee79f4SPrasad Joshi continue; 43498ee79f4SPrasad Joshi if (*rest == '=') 43598ee79f4SPrasad Joshi return opterror(options, "takes no value", 43698ee79f4SPrasad Joshi flags); 43798ee79f4SPrasad Joshi if (*rest) 43898ee79f4SPrasad Joshi continue; 43998ee79f4SPrasad Joshi p->out[p->cpidx++] = arg - 2; 44098ee79f4SPrasad Joshi return 0; 44198ee79f4SPrasad Joshi } 44298ee79f4SPrasad Joshi if (!rest) { 44398ee79f4SPrasad Joshi /* abbreviated? */ 44498ee79f4SPrasad Joshi if (!strncmp(options->long_name, arg, arg_end - arg)) { 44598ee79f4SPrasad Joshi is_abbreviated: 44698ee79f4SPrasad Joshi if (abbrev_option) { 44798ee79f4SPrasad Joshi /* 44898ee79f4SPrasad Joshi * If this is abbreviated, it is 44998ee79f4SPrasad Joshi * ambiguous. So when there is no 45098ee79f4SPrasad Joshi * exact match later, we need to 45198ee79f4SPrasad Joshi * error out. 45298ee79f4SPrasad Joshi */ 45398ee79f4SPrasad Joshi ambiguous_option = abbrev_option; 45498ee79f4SPrasad Joshi ambiguous_flags = abbrev_flags; 45598ee79f4SPrasad Joshi } 45698ee79f4SPrasad Joshi if (!(flags & OPT_UNSET) && *arg_end) 45798ee79f4SPrasad Joshi p->opt = arg_end + 1; 45898ee79f4SPrasad Joshi abbrev_option = options; 45998ee79f4SPrasad Joshi abbrev_flags = flags; 46098ee79f4SPrasad Joshi continue; 46198ee79f4SPrasad Joshi } 46298ee79f4SPrasad Joshi /* negated and abbreviated very much? */ 46398ee79f4SPrasad Joshi if (!prefixcmp("no-", arg)) { 46498ee79f4SPrasad Joshi flags |= OPT_UNSET; 46598ee79f4SPrasad Joshi goto is_abbreviated; 46698ee79f4SPrasad Joshi } 46798ee79f4SPrasad Joshi /* negated? */ 46898ee79f4SPrasad Joshi if (strncmp(arg, "no-", 3)) 46998ee79f4SPrasad Joshi continue; 47098ee79f4SPrasad Joshi flags |= OPT_UNSET; 47198ee79f4SPrasad Joshi rest = skip_prefix(arg + 3, options->long_name); 47298ee79f4SPrasad Joshi /* abbreviated and negated? */ 47398ee79f4SPrasad Joshi if (!rest && !prefixcmp(options->long_name, arg + 3)) 47498ee79f4SPrasad Joshi goto is_abbreviated; 47598ee79f4SPrasad Joshi if (!rest) 47698ee79f4SPrasad Joshi continue; 47798ee79f4SPrasad Joshi } 47898ee79f4SPrasad Joshi if (*rest) { 47998ee79f4SPrasad Joshi if (*rest != '=') 48098ee79f4SPrasad Joshi continue; 48198ee79f4SPrasad Joshi p->opt = rest + 1; 48298ee79f4SPrasad Joshi } 48398ee79f4SPrasad Joshi return get_value(p, options, flags); 48498ee79f4SPrasad Joshi } 48598ee79f4SPrasad Joshi 48698ee79f4SPrasad Joshi if (ambiguous_option) 4874542f276SCyrill Gorcunov return pr_error("Ambiguous option: %s " 48898ee79f4SPrasad Joshi "(could be --%s%s or --%s%s)", 48998ee79f4SPrasad Joshi arg, 49098ee79f4SPrasad Joshi (ambiguous_flags & OPT_UNSET) ? "no-" : "", 49198ee79f4SPrasad Joshi ambiguous_option->long_name, 49298ee79f4SPrasad Joshi (abbrev_flags & OPT_UNSET) ? "no-" : "", 49398ee79f4SPrasad Joshi abbrev_option->long_name); 49498ee79f4SPrasad Joshi if (abbrev_option) 49598ee79f4SPrasad Joshi return get_value(p, abbrev_option, abbrev_flags); 49698ee79f4SPrasad Joshi return -2; 49798ee79f4SPrasad Joshi } 49898ee79f4SPrasad Joshi 49998ee79f4SPrasad Joshi 50098ee79f4SPrasad Joshi static void parse_options_start(struct parse_opt_ctx_t *ctx, int argc, 50198ee79f4SPrasad Joshi const char **argv, int flags) 50298ee79f4SPrasad Joshi { 50398ee79f4SPrasad Joshi memset(ctx, 0, sizeof(*ctx)); 50498ee79f4SPrasad Joshi ctx->argc = argc; 50598ee79f4SPrasad Joshi ctx->argv = argv; 50698ee79f4SPrasad Joshi ctx->out = argv; 50798ee79f4SPrasad Joshi ctx->cpidx = ((flags & PARSE_OPT_KEEP_ARGV0) != 0); 50898ee79f4SPrasad Joshi ctx->flags = flags; 50998ee79f4SPrasad Joshi if ((flags & PARSE_OPT_KEEP_UNKNOWN) && 51098ee79f4SPrasad Joshi (flags & PARSE_OPT_STOP_AT_NON_OPTION)) 51198ee79f4SPrasad Joshi die("STOP_AT_NON_OPTION and KEEP_UNKNOWN don't go together"); 51298ee79f4SPrasad Joshi } 51398ee79f4SPrasad Joshi 51498ee79f4SPrasad Joshi static int parse_options_end(struct parse_opt_ctx_t *ctx) 51598ee79f4SPrasad Joshi { 51698ee79f4SPrasad Joshi memmove(ctx->out + ctx->cpidx, ctx->argv, ctx->argc * sizeof(*ctx->out)); 51798ee79f4SPrasad Joshi ctx->out[ctx->cpidx + ctx->argc] = NULL; 51898ee79f4SPrasad Joshi return ctx->cpidx + ctx->argc; 51998ee79f4SPrasad Joshi } 52098ee79f4SPrasad Joshi 52198ee79f4SPrasad Joshi 52298ee79f4SPrasad Joshi static int parse_options_step(struct parse_opt_ctx_t *ctx, 52398ee79f4SPrasad Joshi const struct option *options, const char * const usagestr[]) 52498ee79f4SPrasad Joshi { 52598ee79f4SPrasad Joshi int internal_help = !(ctx->flags & PARSE_OPT_NO_INTERNAL_HELP); 52698ee79f4SPrasad Joshi 52798ee79f4SPrasad Joshi /* we must reset ->opt, unknown short option leave it dangling */ 52898ee79f4SPrasad Joshi ctx->opt = NULL; 52998ee79f4SPrasad Joshi 53098ee79f4SPrasad Joshi for (; ctx->argc; ctx->argc--, ctx->argv++) { 53198ee79f4SPrasad Joshi const char *arg = ctx->argv[0]; 53298ee79f4SPrasad Joshi 53398ee79f4SPrasad Joshi if (*arg != '-' || !arg[1]) { 53498ee79f4SPrasad Joshi if (ctx->flags & PARSE_OPT_STOP_AT_NON_OPTION) 53598ee79f4SPrasad Joshi break; 53698ee79f4SPrasad Joshi ctx->out[ctx->cpidx++] = ctx->argv[0]; 53798ee79f4SPrasad Joshi continue; 53898ee79f4SPrasad Joshi } 53998ee79f4SPrasad Joshi 54098ee79f4SPrasad Joshi if (arg[1] != '-') { 54198ee79f4SPrasad Joshi ctx->opt = arg + 1; 54298ee79f4SPrasad Joshi if (internal_help && *ctx->opt == 'h') 54398ee79f4SPrasad Joshi return parse_options_usage(usagestr, options); 54498ee79f4SPrasad Joshi switch (parse_short_opt(ctx, options)) { 54598ee79f4SPrasad Joshi case -1: 54698ee79f4SPrasad Joshi return parse_options_usage(usagestr, options); 54798ee79f4SPrasad Joshi case -2: 54898ee79f4SPrasad Joshi goto unknown; 54998ee79f4SPrasad Joshi default: 55098ee79f4SPrasad Joshi break; 55198ee79f4SPrasad Joshi } 55298ee79f4SPrasad Joshi if (ctx->opt) 55398ee79f4SPrasad Joshi check_typos(arg + 1, options); 55498ee79f4SPrasad Joshi while (ctx->opt) { 55598ee79f4SPrasad Joshi if (internal_help && *ctx->opt == 'h') 55698ee79f4SPrasad Joshi return parse_options_usage(usagestr, 55798ee79f4SPrasad Joshi options); 55898ee79f4SPrasad Joshi switch (parse_short_opt(ctx, options)) { 55998ee79f4SPrasad Joshi case -1: 56098ee79f4SPrasad Joshi return parse_options_usage(usagestr, 56198ee79f4SPrasad Joshi options); 56298ee79f4SPrasad Joshi case -2: 56398ee79f4SPrasad Joshi /* fake a short option thing to hide 56498ee79f4SPrasad Joshi * the fact that we may have 56598ee79f4SPrasad Joshi * started to parse aggregated stuff 56698ee79f4SPrasad Joshi * 56798ee79f4SPrasad Joshi * This is leaky, too bad. 56898ee79f4SPrasad Joshi */ 56998ee79f4SPrasad Joshi ctx->argv[0] = strdup(ctx->opt - 1); 57098ee79f4SPrasad Joshi *(char *)ctx->argv[0] = '-'; 57198ee79f4SPrasad Joshi goto unknown; 57298ee79f4SPrasad Joshi default: 57398ee79f4SPrasad Joshi break; 57498ee79f4SPrasad Joshi } 57598ee79f4SPrasad Joshi } 57698ee79f4SPrasad Joshi continue; 57798ee79f4SPrasad Joshi } 57898ee79f4SPrasad Joshi 57998ee79f4SPrasad Joshi if (!arg[2]) { /* "--" */ 58098ee79f4SPrasad Joshi if (!(ctx->flags & PARSE_OPT_KEEP_DASHDASH)) { 58198ee79f4SPrasad Joshi ctx->argc--; 58298ee79f4SPrasad Joshi ctx->argv++; 58398ee79f4SPrasad Joshi } 58498ee79f4SPrasad Joshi break; 58598ee79f4SPrasad Joshi } 58698ee79f4SPrasad Joshi 58798ee79f4SPrasad Joshi if (internal_help && !strcmp(arg + 2, "help-all")) 58898ee79f4SPrasad Joshi return usage_with_options_internal(usagestr, options, 58998ee79f4SPrasad Joshi 1); 59098ee79f4SPrasad Joshi if (internal_help && !strcmp(arg + 2, "help")) 59198ee79f4SPrasad Joshi return parse_options_usage(usagestr, options); 59298ee79f4SPrasad Joshi switch (parse_long_opt(ctx, arg + 2, options)) { 59398ee79f4SPrasad Joshi case -1: 59498ee79f4SPrasad Joshi return parse_options_usage(usagestr, options); 59598ee79f4SPrasad Joshi case -2: 59698ee79f4SPrasad Joshi goto unknown; 59798ee79f4SPrasad Joshi default: 59898ee79f4SPrasad Joshi break; 59998ee79f4SPrasad Joshi } 60098ee79f4SPrasad Joshi continue; 60198ee79f4SPrasad Joshi unknown: 60298ee79f4SPrasad Joshi if (!(ctx->flags & PARSE_OPT_KEEP_UNKNOWN)) 60398ee79f4SPrasad Joshi return PARSE_OPT_UNKNOWN; 60498ee79f4SPrasad Joshi ctx->out[ctx->cpidx++] = ctx->argv[0]; 60598ee79f4SPrasad Joshi ctx->opt = NULL; 60698ee79f4SPrasad Joshi } 60798ee79f4SPrasad Joshi return PARSE_OPT_DONE; 60898ee79f4SPrasad Joshi } 60998ee79f4SPrasad Joshi 61098ee79f4SPrasad Joshi int parse_options(int argc, const char **argv, const struct option *options, 61198ee79f4SPrasad Joshi const char * const usagestr[], int flags) 61298ee79f4SPrasad Joshi { 61398ee79f4SPrasad Joshi struct parse_opt_ctx_t ctx; 61498ee79f4SPrasad Joshi 61598ee79f4SPrasad Joshi parse_options_start(&ctx, argc, argv, flags); 61698ee79f4SPrasad Joshi switch (parse_options_step(&ctx, options, usagestr)) { 61798ee79f4SPrasad Joshi case PARSE_OPT_HELP: 61898ee79f4SPrasad Joshi exit(129); 61998ee79f4SPrasad Joshi case PARSE_OPT_DONE: 62098ee79f4SPrasad Joshi break; 62198ee79f4SPrasad Joshi default: /* PARSE_OPT_UNKNOWN */ 62298ee79f4SPrasad Joshi if (ctx.argv[0][1] == '-') { 6234542f276SCyrill Gorcunov pr_error("unknown option `%s'", ctx.argv[0] + 2); 62498ee79f4SPrasad Joshi } else { 6254542f276SCyrill Gorcunov pr_error("unknown switch `%c'", *ctx.opt); 62698ee79f4SPrasad Joshi } 62798ee79f4SPrasad Joshi usage_with_options(usagestr, options); 62898ee79f4SPrasad Joshi } 62998ee79f4SPrasad Joshi 63098ee79f4SPrasad Joshi return parse_options_end(&ctx); 63198ee79f4SPrasad Joshi } 632