]> git.ipfire.org Git - thirdparty/git.git/commitdiff
parseopt: extract subcommand handling from parse_options_step()
authorJiamu Sun <39@barroit.sh>
Thu, 23 Apr 2026 01:37:51 +0000 (10:37 +0900)
committerJunio C Hamano <gitster@pobox.com>
Thu, 23 Apr 2026 02:02:14 +0000 (11:02 +0900)
Move the subcommand branch out of parse_options_step() into a new
handle_subcommand() helper. Also, make parse_subcommand() return a
simple success/failure status.

This removes the switch over impossible parse_opt_result values and
makes the non-option path easier to follow and maintain.

Signed-off-by: Jiamu Sun <39@barroit.sh>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
parse-options.c

index c9cafc21b90355a2dfee41b90649b43604a41a37..02a4f00919f6d600bddc2e1aa224029411bc0c51 100644 (file)
@@ -605,17 +605,44 @@ static enum parse_opt_result parse_nodash_opt(struct parse_opt_ctx_t *p,
        return PARSE_OPT_ERROR;
 }
 
-static enum parse_opt_result parse_subcommand(const char *arg,
-                                             const struct option *options)
+static int parse_subcommand(const char *arg, const struct option *options)
 {
-       for (; options->type != OPTION_END; options++)
-               if (options->type == OPTION_SUBCOMMAND &&
-                   !strcmp(options->long_name, arg)) {
-                       *(parse_opt_subcommand_fn **)options->value = options->subcommand_fn;
-                       return PARSE_OPT_SUBCOMMAND;
-               }
+       for (; options->type != OPTION_END; options++) {
+               parse_opt_subcommand_fn **opt_val;
 
-       return PARSE_OPT_UNKNOWN;
+               if (options->type != OPTION_SUBCOMMAND ||
+                   strcmp(options->long_name, arg))
+                       continue;
+
+               opt_val = options->value;
+               *opt_val = options->subcommand_fn;
+               return 0;
+       }
+
+       return -1;
+}
+
+static enum parse_opt_result handle_subcommand(struct parse_opt_ctx_t *ctx,
+                                              const char *arg,
+                                              const struct option *options,
+                                              const char * const usagestr[])
+{
+       int err = parse_subcommand(arg, options);
+
+       if (!err)
+               return PARSE_OPT_SUBCOMMAND;
+
+       /*
+        * arg is neither a short or long option nor a subcommand.  Since this
+        * command has a default operation mode, we have to treat this arg and
+        * all remaining args as args meant to that default operation mode.
+        * So we are done parsing.
+        */
+       if (ctx->flags & PARSE_OPT_SUBCOMMAND_OPTIONAL)
+               return PARSE_OPT_DONE;
+
+       error(_("unknown subcommand: `%s'"), arg);
+       usage_with_options(usagestr, options);
 }
 
 static void check_typos(const char *arg, const struct option *options)
@@ -990,38 +1017,16 @@ enum parse_opt_result parse_options_step(struct parse_opt_ctx_t *ctx,
                if (*arg != '-' || !arg[1]) {
                        if (parse_nodash_opt(ctx, arg, options) == 0)
                                continue;
-                       if (!ctx->has_subcommands) {
-                               if (ctx->flags & PARSE_OPT_STOP_AT_NON_OPTION)
-                                       return PARSE_OPT_NON_OPTION;
-                               ctx->out[ctx->cpidx++] = ctx->argv[0];
-                               continue;
-                       }
-                       switch (parse_subcommand(arg, options)) {
-                       case PARSE_OPT_SUBCOMMAND:
-                               return PARSE_OPT_SUBCOMMAND;
-                       case PARSE_OPT_UNKNOWN:
-                               if (ctx->flags & PARSE_OPT_SUBCOMMAND_OPTIONAL)
-                                       /*
-                                        * arg is neither a short or long
-                                        * option nor a subcommand.  Since
-                                        * this command has a default
-                                        * operation mode, we have to treat
-                                        * this arg and all remaining args
-                                        * as args meant to that default
-                                        * operation mode.
-                                        * So we are done parsing.
-                                        */
-                                       return PARSE_OPT_DONE;
-                               error(_("unknown subcommand: `%s'"), arg);
-                               usage_with_options(usagestr, options);
-                       case PARSE_OPT_COMPLETE:
-                       case PARSE_OPT_HELP:
-                       case PARSE_OPT_ERROR:
-                       case PARSE_OPT_DONE:
-                       case PARSE_OPT_NON_OPTION:
-                               /* Impossible. */
-                               BUG("parse_subcommand() cannot return these");
-                       }
+
+                       if (ctx->has_subcommands)
+                               return handle_subcommand(ctx, arg, options,
+                                                        usagestr);
+
+                       if (ctx->flags & PARSE_OPT_STOP_AT_NON_OPTION)
+                               return PARSE_OPT_NON_OPTION;
+
+                       ctx->out[ctx->cpidx++] = ctx->argv[0];
+                       continue;
                }
 
                /* lone -h asks for help */