Skip to content

Commit bc288c5

Browse files
pks-tgitster
authored andcommitted
parse-options: introduce precision handling for OPTION_UNSIGNED
This commit is the equivalent to the preceding commit, but instead of introducing precision handling for `OPTION_INTEGER` we introduce it for `OPTION_UNSIGNED`. Signed-off-by: Patrick Steinhardt <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 0970569 commit bc288c5

File tree

6 files changed

+60
-13
lines changed

6 files changed

+60
-13
lines changed

parse-options.c

Lines changed: 37 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,7 @@ static enum parse_opt_result do_get_value(struct parse_opt_ctx_t *p,
197197

198198
if (value < lower_bound)
199199
return error(_("value %s for %s not in range [%"PRIdMAX",%"PRIdMAX"]"),
200-
arg, optname(opt, flags), lower_bound, upper_bound);
200+
arg, optname(opt, flags), (intmax_t)lower_bound, (intmax_t)upper_bound);
201201

202202
switch (opt->precision) {
203203
case 1:
@@ -218,21 +218,47 @@ static enum parse_opt_result do_get_value(struct parse_opt_ctx_t *p,
218218
}
219219
}
220220
case OPTION_UNSIGNED:
221+
{
222+
uintmax_t upper_bound = UINTMAX_MAX >> (bitsizeof(uintmax_t) - CHAR_BIT * opt->precision);
223+
uintmax_t value;
224+
221225
if (unset) {
222-
*(unsigned long *)opt->value = 0;
223-
return 0;
224-
}
225-
if (opt->flags & PARSE_OPT_OPTARG && !p->opt) {
226-
*(unsigned long *)opt->value = opt->defval;
227-
return 0;
228-
}
229-
if (get_arg(p, opt, flags, &arg))
226+
value = 0;
227+
} else if (opt->flags & PARSE_OPT_OPTARG && !p->opt) {
228+
value = opt->defval;
229+
} else if (get_arg(p, opt, flags, &arg)) {
230230
return -1;
231-
if (!git_parse_ulong(arg, opt->value))
231+
} else if (!*arg) {
232+
return error(_("%s expects a numerical value"),
233+
optname(opt, flags));
234+
} else if (!git_parse_unsigned(arg, &value, upper_bound)) {
235+
if (errno == ERANGE)
236+
return error(_("value %s for %s not in range [%"PRIdMAX",%"PRIdMAX"]"),
237+
arg, optname(opt, flags), (uintmax_t) 0, upper_bound);
238+
232239
return error(_("%s expects a non-negative integer value"
233240
" with an optional k/m/g suffix"),
234241
optname(opt, flags));
235-
return 0;
242+
}
243+
244+
switch (opt->precision) {
245+
case 1:
246+
*(uint8_t *)opt->value = value;
247+
return 0;
248+
case 2:
249+
*(uint16_t *)opt->value = value;
250+
return 0;
251+
case 4:
252+
*(uint32_t *)opt->value = value;
253+
return 0;
254+
case 8:
255+
*(uint64_t *)opt->value = value;
256+
return 0;
257+
default:
258+
BUG("invalid precision for option %s",
259+
optname(opt, flags));
260+
}
261+
}
236262

237263
default:
238264
BUG("opt->type %d should not happen", opt->type);

parse-options.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,7 @@ struct option {
281281
.short_name = (s), \
282282
.long_name = (l), \
283283
.value = (v), \
284+
.precision = sizeof(*v), \
284285
.argh = N_("n"), \
285286
.help = (h), \
286287
.flags = PARSE_OPT_NONEG, \

parse.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ int git_parse_signed(const char *value, intmax_t *ret, intmax_t max)
5151
return 0;
5252
}
5353

54-
static int git_parse_unsigned(const char *value, uintmax_t *ret, uintmax_t max)
54+
int git_parse_unsigned(const char *value, uintmax_t *ret, uintmax_t max)
5555
{
5656
if (value && *value) {
5757
char *end;

parse.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
#define PARSE_H
33

44
int git_parse_signed(const char *value, intmax_t *ret, intmax_t max);
5+
int git_parse_unsigned(const char *value, uintmax_t *ret, uintmax_t max);
56
int git_parse_ssize_t(const char *, ssize_t *);
67
int git_parse_ulong(const char *, unsigned long *);
78
int git_parse_int(const char *value, int *ret);

t/helper/test-parse-options.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@ int cmd__parse_options(int argc, const char **argv)
120120
};
121121
struct string_list expect = STRING_LIST_INIT_NODUP;
122122
struct string_list list = STRING_LIST_INIT_NODUP;
123+
uint16_t u16 = 0;
123124
int16_t i16 = 0;
124125

125126
struct option options[] = {
@@ -143,6 +144,7 @@ int cmd__parse_options(int argc, const char **argv)
143144
OPT_INTEGER(0, "i16", &i16, "get a 16 bit integer"),
144145
OPT_INTEGER('j', NULL, &integer, "get a integer, too"),
145146
OPT_UNSIGNED('u', "unsigned", &unsigned_integer, "get an unsigned integer"),
147+
OPT_UNSIGNED(0, "u16", &u16, "get a 16 bit unsigned integer"),
146148
OPT_SET_INT(0, "set23", &integer, "set integer to 23", 23),
147149
OPT_CMDMODE(0, "mode1", &integer, "set integer to 1 (cmdmode option)", 1),
148150
OPT_CMDMODE(0, "mode2", &integer, "set integer to 2 (cmdmode option)", 2),
@@ -214,6 +216,7 @@ int cmd__parse_options(int argc, const char **argv)
214216
show(&expect, &ret, "integer: %d", integer);
215217
show(&expect, &ret, "i16: %"PRIdMAX, (intmax_t) i16);
216218
show(&expect, &ret, "unsigned: %lu", unsigned_integer);
219+
show(&expect, &ret, "u16: %"PRIuMAX, (uintmax_t) u16);
217220
show(&expect, &ret, "timestamp: %"PRItime, timestamp);
218221
show(&expect, &ret, "string: %s", string ? string : "(not set)");
219222
show(&expect, &ret, "abbrev: %d", abbrev);

t/t0040-parse-options.sh

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ usage: test-tool parse-options <options>
2525
--[no-]i16 <n> get a 16 bit integer
2626
-j <n> get a integer, too
2727
-u, --unsigned <n> get an unsigned integer
28+
--u16 <n> get a 16 bit unsigned integer
2829
--[no-]set23 set integer to 23
2930
--mode1 set integer to 1 (cmdmode option)
3031
--mode2 set integer to 2 (cmdmode option)
@@ -141,6 +142,7 @@ boolean: 2
141142
integer: 1729
142143
i16: 0
143144
unsigned: 16384
145+
u16: 0
144146
timestamp: 0
145147
string: 123
146148
abbrev: 7
@@ -162,6 +164,7 @@ boolean: 2
162164
integer: 1729
163165
i16: 9000
164166
unsigned: 16384
167+
u16: 32768
165168
timestamp: 0
166169
string: 321
167170
abbrev: 10
@@ -173,7 +176,7 @@ EOF
173176

174177
test_expect_success 'long options' '
175178
test-tool parse-options --boolean --integer 1729 --i16 9000 --unsigned 16k \
176-
--boolean --string2=321 --verbose --verbose --no-dry-run \
179+
--u16 32k --boolean --string2=321 --verbose --verbose --no-dry-run \
177180
--abbrev=10 --file fi.le --obsolete \
178181
>output 2>output.err &&
179182
test_must_be_empty output.err &&
@@ -186,6 +189,7 @@ test_expect_success 'abbreviate to something longer than SHA1 length' '
186189
integer: 0
187190
i16: 0
188191
unsigned: 0
192+
u16: 0
189193
timestamp: 0
190194
string: (not set)
191195
abbrev: 100
@@ -261,6 +265,7 @@ boolean: 1
261265
integer: 13
262266
i16: 0
263267
unsigned: 0
268+
u16: 0
264269
timestamp: 0
265270
string: 123
266271
abbrev: 7
@@ -285,6 +290,7 @@ boolean: 0
285290
integer: 2
286291
i16: 0
287292
unsigned: 0
293+
u16: 0
288294
timestamp: 0
289295
string: (not set)
290296
abbrev: 7
@@ -353,6 +359,7 @@ boolean: 5
353359
integer: 4
354360
i16: 0
355361
unsigned: 0
362+
u16: 0
356363
timestamp: 0
357364
string: (not set)
358365
abbrev: 7
@@ -379,6 +386,7 @@ boolean: 1
379386
integer: 23
380387
i16: 0
381388
unsigned: 0
389+
u16: 0
382390
timestamp: 0
383391
string: (not set)
384392
abbrev: 7
@@ -459,6 +467,7 @@ boolean: 0
459467
integer: 0
460468
i16: 0
461469
unsigned: 0
470+
u16: 0
462471
timestamp: 0
463472
string: (not set)
464473
abbrev: 7
@@ -806,4 +815,11 @@ test_expect_success 'i16 limits range' '
806815
test_grep "value -32769 for option .i16. not in range \[-32768,32767\]" err
807816
'
808817

818+
test_expect_success 'u16 limits range' '
819+
test-tool parse-options --u16 65535 >out &&
820+
test_grep "u16: 65535" out &&
821+
test_must_fail test-tool parse-options --u16 65536 2>err &&
822+
test_grep "value 65536 for option .u16. not in range \[0,65535\]" err
823+
'
824+
809825
test_done

0 commit comments

Comments
 (0)