Git fork

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 <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>

authored by

Patrick Steinhardt and committed by
Junio C Hamano
bc288c59 09705696

+60 -13
+37 -11
parse-options.c
··· 197 198 if (value < lower_bound) 199 return error(_("value %s for %s not in range [%"PRIdMAX",%"PRIdMAX"]"), 200 - arg, optname(opt, flags), lower_bound, upper_bound); 201 202 switch (opt->precision) { 203 case 1: ··· 218 } 219 } 220 case OPTION_UNSIGNED: 221 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)) 230 return -1; 231 - if (!git_parse_ulong(arg, opt->value)) 232 return error(_("%s expects a non-negative integer value" 233 " with an optional k/m/g suffix"), 234 optname(opt, flags)); 235 - return 0; 236 237 default: 238 BUG("opt->type %d should not happen", opt->type);
··· 197 198 if (value < lower_bound) 199 return error(_("value %s for %s not in range [%"PRIdMAX",%"PRIdMAX"]"), 200 + arg, optname(opt, flags), (intmax_t)lower_bound, (intmax_t)upper_bound); 201 202 switch (opt->precision) { 203 case 1: ··· 218 } 219 } 220 case OPTION_UNSIGNED: 221 + { 222 + uintmax_t upper_bound = UINTMAX_MAX >> (bitsizeof(uintmax_t) - CHAR_BIT * opt->precision); 223 + uintmax_t value; 224 + 225 if (unset) { 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)) { 230 return -1; 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 + 239 return error(_("%s expects a non-negative integer value" 240 " with an optional k/m/g suffix"), 241 optname(opt, flags)); 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 + } 262 263 default: 264 BUG("opt->type %d should not happen", opt->type);
+1
parse-options.h
··· 281 .short_name = (s), \ 282 .long_name = (l), \ 283 .value = (v), \ 284 .argh = N_("n"), \ 285 .help = (h), \ 286 .flags = PARSE_OPT_NONEG, \
··· 281 .short_name = (s), \ 282 .long_name = (l), \ 283 .value = (v), \ 284 + .precision = sizeof(*v), \ 285 .argh = N_("n"), \ 286 .help = (h), \ 287 .flags = PARSE_OPT_NONEG, \
+1 -1
parse.c
··· 51 return 0; 52 } 53 54 - static int git_parse_unsigned(const char *value, uintmax_t *ret, uintmax_t max) 55 { 56 if (value && *value) { 57 char *end;
··· 51 return 0; 52 } 53 54 + int git_parse_unsigned(const char *value, uintmax_t *ret, uintmax_t max) 55 { 56 if (value && *value) { 57 char *end;
+1
parse.h
··· 2 #define PARSE_H 3 4 int git_parse_signed(const char *value, intmax_t *ret, intmax_t max); 5 int git_parse_ssize_t(const char *, ssize_t *); 6 int git_parse_ulong(const char *, unsigned long *); 7 int git_parse_int(const char *value, int *ret);
··· 2 #define PARSE_H 3 4 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); 6 int git_parse_ssize_t(const char *, ssize_t *); 7 int git_parse_ulong(const char *, unsigned long *); 8 int git_parse_int(const char *value, int *ret);
+3
t/helper/test-parse-options.c
··· 120 }; 121 struct string_list expect = STRING_LIST_INIT_NODUP; 122 struct string_list list = STRING_LIST_INIT_NODUP; 123 int16_t i16 = 0; 124 125 struct option options[] = { ··· 143 OPT_INTEGER(0, "i16", &i16, "get a 16 bit integer"), 144 OPT_INTEGER('j', NULL, &integer, "get a integer, too"), 145 OPT_UNSIGNED('u', "unsigned", &unsigned_integer, "get an unsigned integer"), 146 OPT_SET_INT(0, "set23", &integer, "set integer to 23", 23), 147 OPT_CMDMODE(0, "mode1", &integer, "set integer to 1 (cmdmode option)", 1), 148 OPT_CMDMODE(0, "mode2", &integer, "set integer to 2 (cmdmode option)", 2), ··· 214 show(&expect, &ret, "integer: %d", integer); 215 show(&expect, &ret, "i16: %"PRIdMAX, (intmax_t) i16); 216 show(&expect, &ret, "unsigned: %lu", unsigned_integer); 217 show(&expect, &ret, "timestamp: %"PRItime, timestamp); 218 show(&expect, &ret, "string: %s", string ? string : "(not set)"); 219 show(&expect, &ret, "abbrev: %d", abbrev);
··· 120 }; 121 struct string_list expect = STRING_LIST_INIT_NODUP; 122 struct string_list list = STRING_LIST_INIT_NODUP; 123 + uint16_t u16 = 0; 124 int16_t i16 = 0; 125 126 struct option options[] = { ··· 144 OPT_INTEGER(0, "i16", &i16, "get a 16 bit integer"), 145 OPT_INTEGER('j', NULL, &integer, "get a integer, too"), 146 OPT_UNSIGNED('u', "unsigned", &unsigned_integer, "get an unsigned integer"), 147 + OPT_UNSIGNED(0, "u16", &u16, "get a 16 bit unsigned integer"), 148 OPT_SET_INT(0, "set23", &integer, "set integer to 23", 23), 149 OPT_CMDMODE(0, "mode1", &integer, "set integer to 1 (cmdmode option)", 1), 150 OPT_CMDMODE(0, "mode2", &integer, "set integer to 2 (cmdmode option)", 2), ··· 216 show(&expect, &ret, "integer: %d", integer); 217 show(&expect, &ret, "i16: %"PRIdMAX, (intmax_t) i16); 218 show(&expect, &ret, "unsigned: %lu", unsigned_integer); 219 + show(&expect, &ret, "u16: %"PRIuMAX, (uintmax_t) u16); 220 show(&expect, &ret, "timestamp: %"PRItime, timestamp); 221 show(&expect, &ret, "string: %s", string ? string : "(not set)"); 222 show(&expect, &ret, "abbrev: %d", abbrev);
+17 -1
t/t0040-parse-options.sh
··· 25 --[no-]i16 <n> get a 16 bit integer 26 -j <n> get a integer, too 27 -u, --unsigned <n> get an unsigned integer 28 --[no-]set23 set integer to 23 29 --mode1 set integer to 1 (cmdmode option) 30 --mode2 set integer to 2 (cmdmode option) ··· 141 integer: 1729 142 i16: 0 143 unsigned: 16384 144 timestamp: 0 145 string: 123 146 abbrev: 7 ··· 162 integer: 1729 163 i16: 9000 164 unsigned: 16384 165 timestamp: 0 166 string: 321 167 abbrev: 10 ··· 173 174 test_expect_success 'long options' ' 175 test-tool parse-options --boolean --integer 1729 --i16 9000 --unsigned 16k \ 176 - --boolean --string2=321 --verbose --verbose --no-dry-run \ 177 --abbrev=10 --file fi.le --obsolete \ 178 >output 2>output.err && 179 test_must_be_empty output.err && ··· 186 integer: 0 187 i16: 0 188 unsigned: 0 189 timestamp: 0 190 string: (not set) 191 abbrev: 100 ··· 261 integer: 13 262 i16: 0 263 unsigned: 0 264 timestamp: 0 265 string: 123 266 abbrev: 7 ··· 285 integer: 2 286 i16: 0 287 unsigned: 0 288 timestamp: 0 289 string: (not set) 290 abbrev: 7 ··· 353 integer: 4 354 i16: 0 355 unsigned: 0 356 timestamp: 0 357 string: (not set) 358 abbrev: 7 ··· 379 integer: 23 380 i16: 0 381 unsigned: 0 382 timestamp: 0 383 string: (not set) 384 abbrev: 7 ··· 459 integer: 0 460 i16: 0 461 unsigned: 0 462 timestamp: 0 463 string: (not set) 464 abbrev: 7 ··· 804 test_grep "i16: -32768" out && 805 test_must_fail test-tool parse-options --i16 -32769 2>err && 806 test_grep "value -32769 for option .i16. not in range \[-32768,32767\]" err 807 ' 808 809 test_done
··· 25 --[no-]i16 <n> get a 16 bit integer 26 -j <n> get a integer, too 27 -u, --unsigned <n> get an unsigned integer 28 + --u16 <n> get a 16 bit unsigned integer 29 --[no-]set23 set integer to 23 30 --mode1 set integer to 1 (cmdmode option) 31 --mode2 set integer to 2 (cmdmode option) ··· 142 integer: 1729 143 i16: 0 144 unsigned: 16384 145 + u16: 0 146 timestamp: 0 147 string: 123 148 abbrev: 7 ··· 164 integer: 1729 165 i16: 9000 166 unsigned: 16384 167 + u16: 32768 168 timestamp: 0 169 string: 321 170 abbrev: 10 ··· 176 177 test_expect_success 'long options' ' 178 test-tool parse-options --boolean --integer 1729 --i16 9000 --unsigned 16k \ 179 + --u16 32k --boolean --string2=321 --verbose --verbose --no-dry-run \ 180 --abbrev=10 --file fi.le --obsolete \ 181 >output 2>output.err && 182 test_must_be_empty output.err && ··· 189 integer: 0 190 i16: 0 191 unsigned: 0 192 + u16: 0 193 timestamp: 0 194 string: (not set) 195 abbrev: 100 ··· 265 integer: 13 266 i16: 0 267 unsigned: 0 268 + u16: 0 269 timestamp: 0 270 string: 123 271 abbrev: 7 ··· 290 integer: 2 291 i16: 0 292 unsigned: 0 293 + u16: 0 294 timestamp: 0 295 string: (not set) 296 abbrev: 7 ··· 359 integer: 4 360 i16: 0 361 unsigned: 0 362 + u16: 0 363 timestamp: 0 364 string: (not set) 365 abbrev: 7 ··· 386 integer: 23 387 i16: 0 388 unsigned: 0 389 + u16: 0 390 timestamp: 0 391 string: (not set) 392 abbrev: 7 ··· 467 integer: 0 468 i16: 0 469 unsigned: 0 470 + u16: 0 471 timestamp: 0 472 string: (not set) 473 abbrev: 7 ··· 813 test_grep "i16: -32768" out && 814 test_must_fail test-tool parse-options --i16 -32769 2>err && 815 test_grep "value -32769 for option .i16. not in range \[-32768,32767\]" err 816 + ' 817 + 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 825 test_done