Skip to content

Commit c898bbc

Browse files
rscharfegitster
authored andcommitted
parse-options: add precision handling for OPTION_SET_INT
Similar to 0970569 (parse-options: introduce precision handling for `OPTION_INTEGER`, 2025-04-17) support value variables of different sizes for OPTION_SET_INT. Do that by requiring their "precision" to be set, casting their "value" pointer accordingly and checking whether the value fits. Factor out the casting code from the part of do_get_value() that handles OPTION_INTEGER to avoid code duplication. We're going to use it in the next patches as well. Signed-off-by: René Scharfe <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 0d3e045 commit c898bbc

File tree

4 files changed

+45
-20
lines changed

4 files changed

+45
-20
lines changed

builtin/update-index.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -981,6 +981,7 @@ int cmd_update_index(int argc,
981981
.type = OPTION_SET_INT,
982982
.long_name = "assume-unchanged",
983983
.value = &mark_valid_only,
984+
.precision = sizeof(mark_valid_only),
984985
.help = N_("mark files as \"not changing\""),
985986
.flags = PARSE_OPT_NOARG | PARSE_OPT_NONEG,
986987
.defval = MARK_FLAG,
@@ -989,6 +990,7 @@ int cmd_update_index(int argc,
989990
.type = OPTION_SET_INT,
990991
.long_name = "no-assume-unchanged",
991992
.value = &mark_valid_only,
993+
.precision = sizeof(mark_valid_only),
992994
.help = N_("clear assumed-unchanged bit"),
993995
.flags = PARSE_OPT_NOARG | PARSE_OPT_NONEG,
994996
.defval = UNMARK_FLAG,
@@ -997,6 +999,7 @@ int cmd_update_index(int argc,
997999
.type = OPTION_SET_INT,
9981000
.long_name = "skip-worktree",
9991001
.value = &mark_skip_worktree_only,
1002+
.precision = sizeof(mark_skip_worktree_only),
10001003
.help = N_("mark files as \"index-only\""),
10011004
.flags = PARSE_OPT_NOARG | PARSE_OPT_NONEG,
10021005
.defval = MARK_FLAG,
@@ -1005,6 +1008,7 @@ int cmd_update_index(int argc,
10051008
.type = OPTION_SET_INT,
10061009
.long_name = "no-skip-worktree",
10071010
.value = &mark_skip_worktree_only,
1011+
.precision = sizeof(mark_skip_worktree_only),
10081012
.help = N_("clear skip-worktree bit"),
10091013
.flags = PARSE_OPT_NOARG | PARSE_OPT_NONEG,
10101014
.defval = UNMARK_FLAG,
@@ -1079,6 +1083,7 @@ int cmd_update_index(int argc,
10791083
.type = OPTION_SET_INT,
10801084
.long_name = "fsmonitor-valid",
10811085
.value = &mark_fsmonitor_only,
1086+
.precision = sizeof(mark_fsmonitor_only),
10821087
.help = N_("mark files as fsmonitor valid"),
10831088
.flags = PARSE_OPT_NOARG | PARSE_OPT_NONEG,
10841089
.defval = MARK_FLAG,
@@ -1087,6 +1092,7 @@ int cmd_update_index(int argc,
10871092
.type = OPTION_SET_INT,
10881093
.long_name = "no-fsmonitor-valid",
10891094
.value = &mark_fsmonitor_only,
1095+
.precision = sizeof(mark_fsmonitor_only),
10901096
.help = N_("clear fsmonitor valid bit"),
10911097
.flags = PARSE_OPT_NOARG | PARSE_OPT_NONEG,
10921098
.defval = UNMARK_FLAG,

parse-options.c

Lines changed: 36 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,36 @@ static int do_get_int_value(const void *value, size_t precision, intmax_t *ret)
8888
}
8989
}
9090

91+
static enum parse_opt_result set_int_value(const struct option *opt,
92+
enum opt_parsed flags,
93+
intmax_t value)
94+
{
95+
switch (opt->precision) {
96+
case sizeof(int8_t):
97+
*(int8_t *)opt->value = value;
98+
return 0;
99+
case sizeof(int16_t):
100+
*(int16_t *)opt->value = value;
101+
return 0;
102+
case sizeof(int32_t):
103+
*(int32_t *)opt->value = value;
104+
return 0;
105+
case sizeof(int64_t):
106+
*(int64_t *)opt->value = value;
107+
return 0;
108+
default:
109+
BUG("invalid precision for option %s", optname(opt, flags));
110+
}
111+
}
112+
113+
static int signed_int_fits(intmax_t value, size_t precision)
114+
{
115+
size_t bits = precision * CHAR_BIT;
116+
intmax_t upper_bound = INTMAX_MAX >> (bitsizeof(intmax_t) - bits);
117+
intmax_t lower_bound = -upper_bound - 1;
118+
return lower_bound <= value && value <= upper_bound;
119+
}
120+
91121
static enum parse_opt_result do_get_value(struct parse_opt_ctx_t *p,
92122
const struct option *opt,
93123
enum opt_parsed flags,
@@ -136,8 +166,7 @@ static enum parse_opt_result do_get_value(struct parse_opt_ctx_t *p,
136166
return 0;
137167

138168
case OPTION_SET_INT:
139-
*(int *)opt->value = unset ? 0 : opt->defval;
140-
return 0;
169+
return set_int_value(opt, flags, unset ? 0 : opt->defval);
141170

142171
case OPTION_STRING:
143172
if (unset)
@@ -219,23 +248,7 @@ static enum parse_opt_result do_get_value(struct parse_opt_ctx_t *p,
219248
return error(_("value %s for %s not in range [%"PRIdMAX",%"PRIdMAX"]"),
220249
arg, optname(opt, flags), (intmax_t)lower_bound, (intmax_t)upper_bound);
221250

222-
switch (opt->precision) {
223-
case 1:
224-
*(int8_t *)opt->value = value;
225-
return 0;
226-
case 2:
227-
*(int16_t *)opt->value = value;
228-
return 0;
229-
case 4:
230-
*(int32_t *)opt->value = value;
231-
return 0;
232-
case 8:
233-
*(int64_t *)opt->value = value;
234-
return 0;
235-
default:
236-
BUG("invalid precision for option %s",
237-
optname(opt, flags));
238-
}
251+
return set_int_value(opt, flags, value);
239252
}
240253
case OPTION_UNSIGNED:
241254
{
@@ -617,10 +630,13 @@ static void parse_options_check(const struct option *opts)
617630
opts->long_name && !(opts->flags & PARSE_OPT_NONEG))
618631
optbug(opts, "OPTION_SET_INT 0 should not be negatable");
619632
switch (opts->type) {
633+
case OPTION_SET_INT:
634+
if (!signed_int_fits(opts->defval, opts->precision))
635+
optbug(opts, "has invalid defval");
636+
/* fallthru */
620637
case OPTION_COUNTUP:
621638
case OPTION_BIT:
622639
case OPTION_NEGBIT:
623-
case OPTION_SET_INT:
624640
case OPTION_NUMBER:
625641
case OPTION_BITOP:
626642
if ((opts->flags & PARSE_OPT_OPTARG) ||

parse-options.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,6 +190,7 @@ struct option {
190190
.short_name = (s), \
191191
.long_name = (l), \
192192
.value = (v), \
193+
.precision = sizeof(*v), \
193194
.help = (h), \
194195
.flags = PARSE_OPT_NOARG | (f), \
195196
.defval = (i), \
@@ -260,6 +261,7 @@ struct option {
260261
.short_name = (s), \
261262
.long_name = (l), \
262263
.value = (v), \
264+
.precision = sizeof(*v), \
263265
.help = (h), \
264266
.flags = PARSE_OPT_NOARG | PARSE_OPT_HIDDEN, \
265267
.defval = 1, \

t/helper/test-parse-options.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@ int cmd__parse_options(int argc, const char **argv)
131131
.short_name = 'B',
132132
.long_name = "no-fear",
133133
.value = &boolean,
134+
.precision = sizeof(boolean),
134135
.help = "be brave",
135136
.flags = PARSE_OPT_NOARG | PARSE_OPT_NONEG,
136137
.defval = 1,

0 commit comments

Comments
 (0)