From 1e5abd545622cbbd1cc566e53435900d5a091ddd Mon Sep 17 00:00:00 2001 From: Daniel Wagner Date: Thu, 2 Feb 2023 15:58:33 +0100 Subject: [PATCH] util: Update suffix_binary_parse API Use the same API type for suffix_binary_parse as we have for suffix_si_parse. While at it also introduce a unit test for it. Reviewed-by: Tokunori Ikegami Signed-off-by: Daniel Wagner --- unit/meson.build | 9 +++++ unit/test-suffix-binary-parse.c | 68 +++++++++++++++++++++++++++++++++ util/argconfig.c | 3 +- util/suffix.c | 50 +++++++++++++++--------- util/suffix.h | 2 +- 5 files changed, 111 insertions(+), 21 deletions(-) create mode 100644 unit/test-suffix-binary-parse.c diff --git a/unit/meson.build b/unit/meson.build index d4ff925c..296f7637 100644 --- a/unit/meson.build +++ b/unit/meson.build @@ -18,6 +18,15 @@ test_suffix_si_parse = executable( test('suffix_si_parse', test_suffix_si_parse) +test_suffix_binary_parse = executable( + 'test-suffix-binary-parse', + ['test-suffix-binary-parse.c', '../util/suffix.c'], + include_directories: [incdir, '..'], + dependencies: [libnvme_dep], +) + +test('suffix_binary_parse', test_suffix_binary_parse) + test_uint128_si = executable( 'test-uint128-si', ['test-uint128-si.c', '../util/types.c', '../util/suffix.c'], diff --git a/unit/test-suffix-binary-parse.c b/unit/test-suffix-binary-parse.c new file mode 100644 index 00000000..41b05620 --- /dev/null +++ b/unit/test-suffix-binary-parse.c @@ -0,0 +1,68 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + +#include +#include +#include +#include + +#include "../util/suffix.h" +#include "../util/types.h" + +#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) + +static int test_rc; + +static void check_num(const char *val, __u64 exp, __u64 num) +{ + if (exp == num) + return; + + printf("ERROR: printing {%s}, got '%llu', expected '%llu'\n", + val, (unsigned long long)num, (unsigned long long)exp); + + test_rc = 1; +} + +struct tonum_test { + const char *val; + const uint64_t exp; + int ret; +}; + +static struct tonum_test tonum_tests[] = { + { "1Ki", 1024, 0}, + { "34Gi", 36507222016, 0 }, + { "1234", 0, -EINVAL }, + { "34.9Ki", 0, -EINVAL}, + { "32Gii", 0, -EINVAL }, +}; + +void tonum_test(struct tonum_test *test) +{ + char *endptr; + uint64_t num; + int ret; + + ret = suffix_binary_parse(test->val, &endptr, &num); + if (ret != test->ret) { + printf("ERROR: converting {%s} failed\n", test->val); + test_rc = 1; + return; + } + if (ret) + return; + + check_num(test->val, test->exp, num); +} + +int main(void) +{ + unsigned int i; + + test_rc = 0; + + for (i = 0; i < ARRAY_SIZE(tonum_tests); i++) + tonum_test(&tonum_tests[i]); + + return test_rc ? EXIT_FAILURE : EXIT_SUCCESS; +} diff --git a/util/argconfig.c b/util/argconfig.c index 231a704a..87437228 100644 --- a/util/argconfig.c +++ b/util/argconfig.c @@ -293,8 +293,7 @@ int argconfig_parse(int argc, char *argv[], const char *program_desc, goto out; } } else if (s->config_type == CFG_LONG_SUFFIX) { - *((uint64_t *)value_addr) = suffix_binary_parse(optarg); - if (errno) { + if (suffix_binary_parse(optarg, &endptr, (uint64_t*)&value_addr)) { fprintf(stderr, "Expected long suffixed integer argument for '%s' but got '%s'!\n", long_opts[option_index].name, optarg); diff --git a/util/suffix.c b/util/suffix.c index 94bd279c..1d753867 100644 --- a/util/suffix.c +++ b/util/suffix.c @@ -167,14 +167,15 @@ static struct binary_suffix { {30, "Gi"}, {20, "Mi"}, {10, "Ki"}, - {0, ""} }; const char *suffix_binary_get(long long *value) { - struct binary_suffix *s; + int i; + + for (i = 0; i < ARRAY_SIZE(binary_suffixes); i++) { + struct binary_suffix *s = &binary_suffixes[i]; - for (s = binary_suffixes; s->shift != 0; s++) { if (llabs(*value) >= (1LL << s->shift)) { *value = (*value + (1LL << (s->shift - 1))) / (1LL << s->shift); @@ -187,9 +188,11 @@ const char *suffix_binary_get(long long *value) const char *suffix_dbinary_get(double *value) { - struct binary_suffix *s; + int i; + + for (i = 0; i < ARRAY_SIZE(binary_suffixes); i++) { + struct binary_suffix *s = &binary_suffixes[i]; - for (s = binary_suffixes; s->shift != 0; s++) { if (fabs(*value) >= (1LL << s->shift)) { *value = *value / (1LL << s->shift); return s->suffix; @@ -199,24 +202,35 @@ const char *suffix_dbinary_get(double *value) return ""; } -uint64_t suffix_binary_parse(const char *value) +int suffix_binary_parse(const char *str, char **endptr, uint64_t *val) { - char *suffix; - errno = 0; - uint64_t ret = strtoull(value, &suffix, 0); - if (errno) + uint64_t ret; + int i; + + ret = strtoull(str, endptr, 0); + if (str == *endptr || + ((ret == ULLONG_MAX) && errno == ERANGE)) + return -EINVAL; + + if (str == *endptr) { + *val = ret; return 0; + } + + for (i = 0; i < ARRAY_SIZE(binary_suffixes); i++) { + struct binary_suffix *s = &binary_suffixes[i]; - struct binary_suffix *s; - for (s = binary_suffixes; s->shift != 0; s++) { - if (tolower(suffix[0]) == tolower(s->suffix[0])) { + if (tolower((*endptr)[0]) == tolower(s->suffix[0]) && + (s->suffix[0] != '\0' && + (((*endptr)[0] != '\0' && + (*endptr)[1] != '\0' && + (*endptr)[2] == '\0') && + (tolower((*endptr)[1]) == tolower(s->suffix[1]))))) { ret <<= s->shift; - return ret; + *val = ret; + return 0; } } - if (suffix[0] != '\0') - errno = EINVAL; - - return ret; + return -EINVAL; } diff --git a/util/suffix.h b/util/suffix.h index 8fab823b..5ea58f48 100644 --- a/util/suffix.h +++ b/util/suffix.h @@ -40,6 +40,6 @@ int suffix_si_parse(const char *str, char **endptr, uint64_t *val); const char *suffix_si_get_ld(long double *value); const char *suffix_binary_get(long long *value); const char *suffix_dbinary_get(double *value); -uint64_t suffix_binary_parse(const char *value); +int suffix_binary_parse(const char *str, char **endptr, uint64_t *val); #endif -- 2.50.1