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'],
--- /dev/null
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#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;
+}
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);
{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);
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;
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;
}
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