This adds the PARSE_OPT_NO_ERROR_ON_UNKNOWN flag which prevents parse_options() from erroring out when it finds an unknown option, and leaves the original command and unknown options in argv. This option is useful if the option parsing needs to be done in multiple stages for example if the remaining options will be passed to additional git commands. Signed-off-by: Shawn Bohrer <shawn.bohrer@xxxxxxxxx> --- parse-options.c | 25 ++++++++++++++++++++----- parse-options.h | 5 +++-- 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/parse-options.c b/parse-options.c index 8071711..2635e18 100644 --- a/parse-options.c +++ b/parse-options.c @@ -131,7 +131,8 @@ static int get_value(struct optparse_t *p, } } -static int parse_short_opt(struct optparse_t *p, const struct option *options) +static int parse_short_opt(struct optparse_t *p, const struct option *options, + int flags) { for (; options->type != OPTION_END; options++) { if (options->short_name == *p->opt) { @@ -139,11 +140,16 @@ static int parse_short_opt(struct optparse_t *p, const struct option *options) return get_value(p, options, OPT_SHORT); } } + + if (flags & PARSE_OPT_NO_ERROR_ON_UNKNOWN) { + p->out[p->cpidx++] = p->argv[0]; + return 0; + } return error("unknown switch `%c'", *p->opt); } static int parse_long_opt(struct optparse_t *p, const char *arg, - const struct option *options) + const struct option *options, int flags) { const char *arg_end = strchr(arg, '='); const struct option *abbrev_option = NULL, *ambiguous_option = NULL; @@ -224,6 +230,11 @@ is_abbreviated: abbrev_option->long_name); if (abbrev_option) return get_value(p, abbrev_option, abbrev_flags); + + if (flags & PARSE_OPT_NO_ERROR_ON_UNKNOWN) { + p->out[p->cpidx++] = p->argv[0]; + return 0; + } return error("unknown option `%s'", arg); } @@ -254,6 +265,8 @@ int parse_options(int argc, const char **argv, const struct option *options, const char * const usagestr[], int flags) { struct optparse_t args = { argv + 1, argv, argc - 1, 0, NULL }; + if (flags & PARSE_OPT_NO_ERROR_ON_UNKNOWN) + args.out = argv + 1; for (; args.argc; args.argc--, args.argv++) { const char *arg = args.argv[0]; @@ -269,14 +282,14 @@ int parse_options(int argc, const char **argv, const struct option *options, args.opt = arg + 1; if (*args.opt == 'h') usage_with_options(usagestr, options); - if (parse_short_opt(&args, options) < 0) + if (parse_short_opt(&args, options, flags) < 0) usage_with_options(usagestr, options); if (args.opt) check_typos(arg + 1, options); while (args.opt) { if (*args.opt == 'h') usage_with_options(usagestr, options); - if (parse_short_opt(&args, options) < 0) + if (parse_short_opt(&args, options, flags) < 0) usage_with_options(usagestr, options); } continue; @@ -294,11 +307,13 @@ int parse_options(int argc, const char **argv, const struct option *options, usage_with_options_internal(usagestr, options, 1); if (!strcmp(arg + 2, "help")) usage_with_options(usagestr, options); - if (parse_long_opt(&args, arg + 2, options)) + if (parse_long_opt(&args, arg + 2, options, flags)) usage_with_options(usagestr, options); } memmove(args.out + args.cpidx, args.argv, args.argc * sizeof(*args.out)); + if (flags & PARSE_OPT_NO_ERROR_ON_UNKNOWN) + ++args.cpidx; args.out[args.cpidx + args.argc] = NULL; return args.cpidx + args.argc; } diff --git a/parse-options.h b/parse-options.h index 4ee443d..416ccdd 100644 --- a/parse-options.h +++ b/parse-options.h @@ -18,8 +18,9 @@ enum parse_opt_type { }; enum parse_opt_flags { - PARSE_OPT_KEEP_DASHDASH = 1, - PARSE_OPT_STOP_AT_NON_OPTION = 2, + PARSE_OPT_KEEP_DASHDASH = 1, + PARSE_OPT_STOP_AT_NON_OPTION = 2, + PARSE_OPT_NO_ERROR_ON_UNKNOWN = 4 }; enum parse_opt_option_flags { -- 1.5.4.3 -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html