parseopt: extract subcommand handling from parse_options_step()

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>
This commit is contained in:
Jiamu Sun
2026-03-10 20:41:00 +09:00
committed by Junio C Hamano
parent d181b9354c
commit 38ed9faa1d

View 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,17 @@ 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 */