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