parse-options: add precision handling for PARSE_OPT_CMDMODE

Build on 09705696f7 (parse-options: introduce precision handling for
`OPTION_INTEGER`, 2025-04-17) to support value variables of different
sizes for PARSE_OPT_CMDMODE options.  Do that by requiring their
"precision" to be set and casting their "value" pointer accordingly.

Call the function that does the raw casting do_get_int_value() to
reserve the name get_int_value() for a more friendly wrapper we're
going to introduce in one of the next patches.

Signed-off-by: René Scharfe <l.s.r@web.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
maint
René Scharfe 2025-07-09 11:45:14 +02:00 committed by Junio C Hamano
parent 369e6d94b2
commit 0d3e045b34
4 changed files with 48 additions and 8 deletions

View File

@ -2406,6 +2406,7 @@ int cmd_am(int argc,
.type = OPTION_CALLBACK,
.long_name = "show-current-patch",
.value = &resume_mode,
.precision = sizeof(resume_mode),
.argh = "(diff|raw)",
.help = N_("show the patch being applied"),
.flags = PARSE_OPT_CMDMODE | PARSE_OPT_OPTARG | PARSE_OPT_NONEG | PARSE_OPT_LITERAL_ARGHELP,

View File

@ -68,6 +68,26 @@ static char *fix_filename(const char *prefix, const char *file)
return prefix_filename_except_for_dash(prefix, file);
}

static int do_get_int_value(const void *value, size_t precision, intmax_t *ret)
{
switch (precision) {
case sizeof(int8_t):
*ret = *(int8_t *)value;
return 0;
case sizeof(int16_t):
*ret = *(int16_t *)value;
return 0;
case sizeof(int32_t):
*ret = *(int32_t *)value;
return 0;
case sizeof(int64_t):
*ret = *(int64_t *)value;
return 0;
default:
return -1;
}
}

static enum parse_opt_result do_get_value(struct parse_opt_ctx_t *p,
const struct option *opt,
enum opt_parsed flags,
@ -266,7 +286,9 @@ static enum parse_opt_result do_get_value(struct parse_opt_ctx_t *p,
}

struct parse_opt_cmdmode_list {
int value, *value_ptr;
intmax_t value;
void *value_ptr;
size_t precision;
const struct option *opt;
const char *arg;
enum opt_parsed flags;
@ -280,7 +302,7 @@ static void build_cmdmode_list(struct parse_opt_ctx_t *ctx,

for (; opts->type != OPTION_END; opts++) {
struct parse_opt_cmdmode_list *elem = ctx->cmdmode_list;
int *value_ptr = opts->value;
void *value_ptr = opts->value;

if (!(opts->flags & PARSE_OPT_CMDMODE) || !value_ptr)
continue;
@ -292,10 +314,13 @@ static void build_cmdmode_list(struct parse_opt_ctx_t *ctx,

CALLOC_ARRAY(elem, 1);
elem->value_ptr = value_ptr;
elem->value = *value_ptr;
elem->precision = opts->precision;
if (do_get_int_value(value_ptr, opts->precision, &elem->value))
optbug(opts, "has invalid precision");
elem->next = ctx->cmdmode_list;
ctx->cmdmode_list = elem;
}
BUG_if_bug("invalid 'struct option'");
}

static char *optnamearg(const struct option *opt, const char *arg,
@ -317,7 +342,13 @@ static enum parse_opt_result get_value(struct parse_opt_ctx_t *p,
char *opt_name, *other_opt_name;

for (; elem; elem = elem->next) {
if (*elem->value_ptr == elem->value)
intmax_t new_value;

if (do_get_int_value(elem->value_ptr, elem->precision,
&new_value))
BUG("impossible: invalid precision");

if (new_value == elem->value)
continue;

if (elem->opt &&
@ -327,7 +358,7 @@ static enum parse_opt_result get_value(struct parse_opt_ctx_t *p,
elem->opt = opt;
elem->arg = arg;
elem->flags = flags;
elem->value = *elem->value_ptr;
elem->value = new_value;
}

if (result || !elem)

View File

@ -269,6 +269,7 @@ struct option {
.short_name = (s), \
.long_name = (l), \
.value = (v), \
.precision = sizeof(*v), \
.help = (h), \
.flags = PARSE_OPT_CMDMODE|PARSE_OPT_NOARG|PARSE_OPT_NONEG | (f), \
.defval = (i), \

View File

@ -148,9 +148,16 @@ int cmd__parse_options(int argc, const char **argv)
OPT_SET_INT(0, "set23", &integer, "set integer to 23", 23),
OPT_CMDMODE(0, "mode1", &integer, "set integer to 1 (cmdmode option)", 1),
OPT_CMDMODE(0, "mode2", &integer, "set integer to 2 (cmdmode option)", 2),
OPT_CALLBACK_F(0, "mode34", &integer, "(3|4)",
"set integer to 3 or 4 (cmdmode option)",
PARSE_OPT_CMDMODE, mode34_callback),
{
.type = OPTION_CALLBACK,
.long_name = "mode34",
.value = &integer,
.precision = sizeof(integer),
.argh = "(3|4)",
.help = "set integer to 3 or 4 (cmdmode option)",
.flags = PARSE_OPT_CMDMODE,
.callback = mode34_callback,
},
OPT_CALLBACK('L', "length", &integer, "str",
"get length of <str>", length_callback),
OPT_FILENAME('F', "file", &file, "set file to <file>"),