parse-options: add one-shot mode
authorNguyễn Thái Ngọc Duy <pclouds@gmail.com>
Sun, 27 Jan 2019 00:35:23 +0000 (07:35 +0700)
committerJunio C Hamano <gitster@pobox.com>
Mon, 28 Jan 2019 00:28:17 +0000 (16:28 -0800)
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>
parse-options.c
parse-options.h
index 9f84bacce64e72d117be2bdbe91db6d4c190e257..740ae5438f93d65d660cfec51edc56c8df145e2b 100644 (file)
@@ -416,15 +416,24 @@ void parse_options_start(struct parse_opt_ctx_t *ctx,
                         const struct option *options, int flags)
 {
        memset(ctx, 0, sizeof(*ctx));
-       ctx->argc = ctx->total = argc - 1;
-       ctx->argv = argv + 1;
-       ctx->out  = argv;
+       ctx->argc = argc;
+       ctx->argv = argv;
+       if (!(flags & PARSE_OPT_ONE_SHOT)) {
+               ctx->argc--;
+               ctx->argv++;
+       }
+       ctx->total = ctx->argc;
+       ctx->out   = argv;
        ctx->prefix = prefix;
        ctx->cpidx = ((flags & PARSE_OPT_KEEP_ARGV0) != 0);
        ctx->flags = flags;
        if ((flags & PARSE_OPT_KEEP_UNKNOWN) &&
-           (flags & PARSE_OPT_STOP_AT_NON_OPTION))
+           (flags & PARSE_OPT_STOP_AT_NON_OPTION) &&
+           !(flags & PARSE_OPT_ONE_SHOT))
                BUG("STOP_AT_NON_OPTION and KEEP_UNKNOWN don't go together");
+       if ((flags & PARSE_OPT_ONE_SHOT) &&
+           (flags & PARSE_OPT_KEEP_ARGV0))
+               BUG("Can't keep argv0 if you don't have it");
        parse_options_check(options);
 }
 
@@ -536,6 +545,10 @@ int parse_options_step(struct parse_opt_ctx_t *ctx,
        for (; ctx->argc; ctx->argc--, ctx->argv++) {
                const char *arg = ctx->argv[0];
 
+               if (ctx->flags & PARSE_OPT_ONE_SHOT &&
+                   ctx->argc != ctx->total)
+                       break;
+
                if (*arg != '-' || !arg[1]) {
                        if (parse_nodash_opt(ctx, arg, options) == 0)
                                continue;
@@ -610,6 +623,8 @@ int parse_options_step(struct parse_opt_ctx_t *ctx,
                }
                continue;
 unknown:
+               if (ctx->flags & PARSE_OPT_ONE_SHOT)
+                       break;
                if (!(ctx->flags & PARSE_OPT_KEEP_UNKNOWN))
                        return PARSE_OPT_UNKNOWN;
                ctx->out[ctx->cpidx++] = ctx->argv[0];
@@ -623,6 +638,9 @@ int parse_options_step(struct parse_opt_ctx_t *ctx,
 
 int parse_options_end(struct parse_opt_ctx_t *ctx)
 {
+       if (ctx->flags & PARSE_OPT_ONE_SHOT)
+               return ctx->total - ctx->argc;
+
        MOVE_ARRAY(ctx->out + ctx->cpidx, ctx->argv, ctx->argc);
        ctx->out[ctx->cpidx + ctx->argc] = NULL;
        return ctx->cpidx + ctx->argc;
index f5e7ec7d235d3948214d932fd061760040c6945d..d663b839734771e159090095d09e43258ecf0829 100644 (file)
@@ -27,7 +27,8 @@ enum parse_opt_flags {
        PARSE_OPT_STOP_AT_NON_OPTION = 2,
        PARSE_OPT_KEEP_ARGV0 = 4,
        PARSE_OPT_KEEP_UNKNOWN = 8,
-       PARSE_OPT_NO_INTERNAL_HELP = 16
+       PARSE_OPT_NO_INTERNAL_HELP = 16,
+       PARSE_OPT_ONE_SHOT = 32
 };
 
 enum parse_opt_option_flags {
@@ -169,10 +170,18 @@ struct option {
          N_("no-op (backward compatibility)"),         \
          PARSE_OPT_HIDDEN | PARSE_OPT_NOARG, parse_opt_noop_cb }
 
-/* parse_options() will filter out the processed options and leave the
- * non-option arguments in argv[]. usagestr strings should be marked
- * for translation with N_().
+/*
+ * parse_options() will filter out the processed options and leave the
+ * non-option arguments in argv[]. argv0 is assumed program name and
+ * skipped.
+ *
+ * usagestr strings should be marked for translation with N_().
+ *
  * Returns the number of arguments left in argv[].
+ *
+ * In one-shot mode, argv0 is not a program name, argv[] is left
+ * untouched and parse_options() returns the number of options
+ * processed.
  */
 int parse_options(int argc, const char **argv, const char *prefix,
                  const struct option *options,