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