| #include "git-compat-util.h" |
| #include "gettext.h" |
| #include "parse.h" |
| |
| static uintmax_t get_unit_factor(const char *end) |
| { |
| if (!*end) |
| return 1; |
| else if (!strcasecmp(end, "k")) |
| return 1024; |
| else if (!strcasecmp(end, "m")) |
| return 1024 * 1024; |
| else if (!strcasecmp(end, "g")) |
| return 1024 * 1024 * 1024; |
| return 0; |
| } |
| |
| int git_parse_signed(const char *value, intmax_t *ret, intmax_t max) |
| { |
| if (value && *value) { |
| char *end; |
| intmax_t val; |
| intmax_t factor; |
| |
| if (max < 0) |
| BUG("max must be a positive integer"); |
| |
| errno = 0; |
| val = strtoimax(value, &end, 0); |
| if (errno == ERANGE) |
| return 0; |
| if (end == value) { |
| errno = EINVAL; |
| return 0; |
| } |
| factor = get_unit_factor(end); |
| if (!factor) { |
| errno = EINVAL; |
| return 0; |
| } |
| if ((val < 0 && -max / factor > val) || |
| (val > 0 && max / factor < val)) { |
| errno = ERANGE; |
| return 0; |
| } |
| val *= factor; |
| *ret = val; |
| return 1; |
| } |
| errno = EINVAL; |
| return 0; |
| } |
| |
| static int git_parse_unsigned(const char *value, uintmax_t *ret, uintmax_t max) |
| { |
| if (value && *value) { |
| char *end; |
| uintmax_t val; |
| uintmax_t factor; |
| |
| /* negative values would be accepted by strtoumax */ |
| if (strchr(value, '-')) { |
| errno = EINVAL; |
| return 0; |
| } |
| errno = 0; |
| val = strtoumax(value, &end, 0); |
| if (errno == ERANGE) |
| return 0; |
| if (end == value) { |
| errno = EINVAL; |
| return 0; |
| } |
| factor = get_unit_factor(end); |
| if (!factor) { |
| errno = EINVAL; |
| return 0; |
| } |
| if (unsigned_mult_overflows(factor, val) || |
| factor * val > max) { |
| errno = ERANGE; |
| return 0; |
| } |
| val *= factor; |
| *ret = val; |
| return 1; |
| } |
| errno = EINVAL; |
| return 0; |
| } |
| |
| int git_parse_int(const char *value, int *ret) |
| { |
| intmax_t tmp; |
| if (!git_parse_signed(value, &tmp, maximum_signed_value_of_type(int))) |
| return 0; |
| *ret = tmp; |
| return 1; |
| } |
| |
| int git_parse_int64(const char *value, int64_t *ret) |
| { |
| intmax_t tmp; |
| if (!git_parse_signed(value, &tmp, maximum_signed_value_of_type(int64_t))) |
| return 0; |
| *ret = tmp; |
| return 1; |
| } |
| |
| int git_parse_ulong(const char *value, unsigned long *ret) |
| { |
| uintmax_t tmp; |
| if (!git_parse_unsigned(value, &tmp, maximum_unsigned_value_of_type(long))) |
| return 0; |
| *ret = tmp; |
| return 1; |
| } |
| |
| int git_parse_ssize_t(const char *value, ssize_t *ret) |
| { |
| intmax_t tmp; |
| if (!git_parse_signed(value, &tmp, maximum_signed_value_of_type(ssize_t))) |
| return 0; |
| *ret = tmp; |
| return 1; |
| } |
| |
| int git_parse_maybe_bool_text(const char *value) |
| { |
| if (!value) |
| return 1; |
| if (!*value) |
| return 0; |
| if (!strcasecmp(value, "true") |
| || !strcasecmp(value, "yes") |
| || !strcasecmp(value, "on")) |
| return 1; |
| if (!strcasecmp(value, "false") |
| || !strcasecmp(value, "no") |
| || !strcasecmp(value, "off")) |
| return 0; |
| return -1; |
| } |
| |
| int git_parse_maybe_bool(const char *value) |
| { |
| int v = git_parse_maybe_bool_text(value); |
| if (0 <= v) |
| return v; |
| if (git_parse_int(value, &v)) |
| return !!v; |
| return -1; |
| } |
| |
| /* |
| * Parse environment variable 'k' as a boolean (in various |
| * possible spellings); if missing, use the default value 'def'. |
| */ |
| int git_env_bool(const char *k, int def) |
| { |
| const char *v = getenv(k); |
| int val; |
| if (!v) |
| return def; |
| val = git_parse_maybe_bool(v); |
| if (val < 0) |
| die(_("bad boolean environment value '%s' for '%s'"), |
| v, k); |
| return val; |
| } |
| |
| /* |
| * Parse environment variable 'k' as ulong with possibly a unit |
| * suffix; if missing, use the default value 'val'. |
| */ |
| unsigned long git_env_ulong(const char *k, unsigned long val) |
| { |
| const char *v = getenv(k); |
| if (v && !git_parse_ulong(v, &val)) |
| die(_("failed to parse %s"), k); |
| return val; |
| } |