parse-options: add one-shot mode

This is to help reimplement diff_opt_parse() using parse_options(). The behavior of parse_options() is changed to be the same as the other: - no argv0 in argv[], everything can be processed - argv[] must not be updated, it's the caller's job to do that - return the number of arguments processed - leave all unknown options / non-options alone (this one can already be achieved with PARSE_OPT_KEEP_UNKNOWN and PARSE_OPT_STOP_AT_NON_OPTION) This mode is NOT supposed to stay here for long. It's to help converting diff/rev option parsing. Once that work is over and we can just use parse_options() throughout the code base, this will be deleted. Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Nguyễn Thái Ngọc Duy committed Jan 27, 2019 at 07:35 UTC 202fbb33156287feeabc39c46db0e9857cb97152
2 files changed +35 -8
parse-options.c
+22 -4
@@ -416,15 +416,24 @@ void parse_options_start(struct parse_opt_ctx_t *ctx,
416 const struct option *options, int flags)
417 {
418 memset(ctx, 0, sizeof(*ctx));
419 - ctx->argc = ctx->total = argc - 1;
420 - ctx->argv = argv + 1;
421 - ctx->out = argv;
419 + ctx->argc = argc;
420 + ctx->argv = argv;
421 + if (!(flags & PARSE_OPT_ONE_SHOT)) {
422 + ctx->argc--;
423 + ctx->argv++;
424 + }
425 + ctx->total = ctx->argc;
426 + ctx->out = argv;
427 ctx->prefix = prefix;
428 ctx->cpidx = ((flags & PARSE_OPT_KEEP_ARGV0) != 0);
429 ctx->flags = flags;
430 if ((flags & PARSE_OPT_KEEP_UNKNOWN) &&
426 - (flags & PARSE_OPT_STOP_AT_NON_OPTION))
431 + (flags & PARSE_OPT_STOP_AT_NON_OPTION) &&
432 + !(flags & PARSE_OPT_ONE_SHOT))
433 BUG("STOP_AT_NON_OPTION and KEEP_UNKNOWN don't go together");
434 + if ((flags & PARSE_OPT_ONE_SHOT) &&
435 + (flags & PARSE_OPT_KEEP_ARGV0))
436 + BUG("Can't keep argv0 if you don't have it");
437 parse_options_check(options);
438 }
439
@@ -536,6 +545,10 @@ int parse_options_step(struct parse_opt_ctx_t *ctx,
545 for (; ctx->argc; ctx->argc--, ctx->argv++) {
546 const char *arg = ctx->argv[0];
547
548 + if (ctx->flags & PARSE_OPT_ONE_SHOT &&
549 + ctx->argc != ctx->total)
550 + break;
551 +
552 if (*arg != '-' || !arg[1]) {
553 if (parse_nodash_opt(ctx, arg, options) == 0)
554 continue;
@@ -610,6 +623,8 @@ int parse_options_step(struct parse_opt_ctx_t *ctx,
623 }
624 continue;
625 unknown:
626 + if (ctx->flags & PARSE_OPT_ONE_SHOT)
627 + break;
628 if (!(ctx->flags & PARSE_OPT_KEEP_UNKNOWN))
629 return PARSE_OPT_UNKNOWN;
630 ctx->out[ctx->cpidx++] = ctx->argv[0];
@@ -623,6 +638,9 @@ unknown:
638
639 int parse_options_end(struct parse_opt_ctx_t *ctx)
640 {
641 + if (ctx->flags & PARSE_OPT_ONE_SHOT)
642 + return ctx->total - ctx->argc;
643 +
644 MOVE_ARRAY(ctx->out + ctx->cpidx, ctx->argv, ctx->argc);
645 ctx->out[ctx->cpidx + ctx->argc] = NULL;
646 return ctx->cpidx + ctx->argc;
parse-options.h
+13 -4
@@ -27,7 +27,8 @@ enum parse_opt_flags {
27 PARSE_OPT_STOP_AT_NON_OPTION = 2,
28 PARSE_OPT_KEEP_ARGV0 = 4,
29 PARSE_OPT_KEEP_UNKNOWN = 8,
30 - PARSE_OPT_NO_INTERNAL_HELP = 16
30 + PARSE_OPT_NO_INTERNAL_HELP = 16,
31 + PARSE_OPT_ONE_SHOT = 32
32 };
33
34 enum parse_opt_option_flags {
@@ -169,10 +170,18 @@ struct option {
170 N_("no-op (backward compatibility)"), \
171 PARSE_OPT_HIDDEN | PARSE_OPT_NOARG, parse_opt_noop_cb }
172
172 -/* parse_options() will filter out the processed options and leave the
173 - * non-option arguments in argv[]. usagestr strings should be marked
174 - * for translation with N_().
173 +/*
174 + * parse_options() will filter out the processed options and leave the
175 + * non-option arguments in argv[]. argv0 is assumed program name and
176 + * skipped.
177 + *
178 + * usagestr strings should be marked for translation with N_().
179 + *
180 * Returns the number of arguments left in argv[].
181 + *
182 + * In one-shot mode, argv0 is not a program name, argv[] is left
183 + * untouched and parse_options() returns the number of options
184 + * processed.
185 */
186 int parse_options(int argc, const char **argv, const char *prefix,
187 const struct option *options,