Introduce qemu_sztostr which takes an int and turns it into a sized string. Variants are added for both signed and unsigned integers.
Signed-off-by: Daniel P. Berrange <berra...@redhat.com> --- include/qemu/cutils.h | 12 +++++++ tests/test-cutils.c | 96 +++++++++++++++++++++++++++++++++++++++++++++++++++ util/cutils.c | 78 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 186 insertions(+) diff --git a/include/qemu/cutils.h b/include/qemu/cutils.h index 3e4ea23..31f6bff 100644 --- a/include/qemu/cutils.h +++ b/include/qemu/cutils.h @@ -158,6 +158,18 @@ int64_t qemu_strtosz_suffix(const char *nptr, char **end, const char default_suffix); int64_t qemu_strtosz_suffix_unit(const char *nptr, char **end, const char default_suffix, int64_t unit); + +char *qemu_sztostr(int64_t val); +char *qemu_sztostr_full(int64_t val, + const char default_suffix, + bool long_suffix, + const char *separator); +char *qemu_szutostr(uint64_t val); +char *qemu_szutostr_full(uint64_t val, + const char default_suffix, + bool long_suffix, + const char *separator); + #define K_BYTE (1ULL << 10) #define M_BYTE (1ULL << 20) #define G_BYTE (1ULL << 30) diff --git a/tests/test-cutils.c b/tests/test-cutils.c index 20b0f59..b067c68 100644 --- a/tests/test-cutils.c +++ b/tests/test-cutils.c @@ -1437,8 +1437,94 @@ static void test_qemu_strtosz_suffix_unit(void) g_assert_cmpint(res, ==, 12345000); } + +static struct SzToStrData { + const char *path; + int64_t val; + const char *expected; + const char default_suffix; + bool long_suffix; + const char *separator; +} test_qemu_sztostr_data[] = { + { "/cutils/sztostr/simple", -42, "-42B", '\0', true, NULL }, + { "/cutils/sztostr/simple-suffix", -1729, "-1.69KiB", '\0', true, NULL }, + { "/cutils/sztostr/default-suffix", 1729, "1.69", + QEMU_STRTOSZ_DEFSUFFIX_KB, true, NULL }, + { "/cutils/sztostr/short-suffix", 1729, "1.69 K", '\0', false, " " }, + { "/cutils/sztostr/simple-sepator", -1729, "-1.69", + QEMU_STRTOSZ_DEFSUFFIX_KB, true, " " }, + { "/cutils/sztostr/simple-suffix-sepator", -1729, "-1.69 KiB", + '\0', true, " " }, + { "/cutils/sztostr/ulong-max", ULLONG_MAX, "-1B", '\0', true, NULL }, + { "/cutils/sztostr/long-max", LONG_MAX, "8EiB", '\0', true, NULL }, + { "/cutils/sztostr/long-min", -LONG_MAX - 1, "-8EiB", '\0', true, NULL }, +}; + +static void test_qemu_sztostr(const void *opaque) +{ + const struct SzToStrData *data = opaque; + char *actual; + + if (data->separator || data->default_suffix) { + actual = qemu_sztostr_full(data->val, + data->default_suffix, + data->long_suffix, + data->separator); + } else { + actual = qemu_sztostr(data->val); + } + + g_assert_cmpstr(actual, ==, data->expected); + + g_free(actual); +} + + +static struct SzUToStrData { + const char *path; + uint64_t val; + const char *expected; + const char default_suffix; + bool long_suffix; + const char *separator; +} test_qemu_szutostr_data[] = { + { "/cutils/szutostr/simple", 42, "42B", '\0', true, NULL }, + { "/cutils/szutostr/simple-suffix", 1729, "1.69KiB", '\0', true, NULL }, + { "/cutils/szutostr/default-suffix", 1729, "1.69", + QEMU_STRTOSZ_DEFSUFFIX_KB, true, NULL }, + { "/cutils/szutostr/short-suffix", 1729, "1.69 K", '\0', false, " " }, + { "/cutils/szutostr/simple-sepator", 1729, "1.69", + QEMU_STRTOSZ_DEFSUFFIX_KB, true, " " }, + { "/cutils/szutostr/simple-suffix-sepator", 1729, "1.69 KiB", + '\0', true, " " }, + { "/cutils/szutostr/ulong-max", ULLONG_MAX, "16EiB", '\0', true, NULL }, + { "/cutils/szutostr/long-max", LONG_MAX, "8EiB", '\0', true, NULL }, +}; + +static void test_qemu_szutostr(const void *opaque) +{ + const struct SzUToStrData *data = opaque; + char *actual; + + if (data->separator || data->default_suffix) { + actual = qemu_szutostr_full(data->val, + data->default_suffix, + data->long_suffix, + data->separator); + } else { + actual = qemu_szutostr(data->val); + } + + g_assert_cmpstr(actual, ==, data->expected); + + g_free(actual); +} + + int main(int argc, char **argv) { + gsize i; + g_test_init(&argc, &argv, NULL); g_test_add_func("/cutils/parse_uint/null", test_parse_uint_null); @@ -1598,5 +1684,15 @@ int main(int argc, char **argv) g_test_add_func("/cutils/strtosz/suffix-unit", test_qemu_strtosz_suffix_unit); + for (i = 0; i < G_N_ELEMENTS(test_qemu_sztostr_data); i++) { + g_test_add_data_func(test_qemu_sztostr_data[i].path, + &(test_qemu_sztostr_data[i]), + test_qemu_sztostr); + } + for (i = 0; i < G_N_ELEMENTS(test_qemu_szutostr_data); i++) { + g_test_add_data_func(test_qemu_szutostr_data[i].path, + &(test_qemu_szutostr_data[i]), + test_qemu_szutostr); + } return g_test_run(); } diff --git a/util/cutils.c b/util/cutils.c index 7505fda..bdc3fc1 100644 --- a/util/cutils.c +++ b/util/cutils.c @@ -503,6 +503,84 @@ int64_t qemu_strtosz(const char *nptr, char **end) return qemu_strtosz_suffix(nptr, end, QEMU_STRTOSZ_DEFSUFFIX_MB); } + +static char *qemu_sztostr_impl(uint64_t val, + const char default_suffix, + bool long_suffix, + const char *separator, + bool allowSigned) +{ + static const char *suffixes[] = { + "B", "K", "M", "G", "T", "P", "E" }; + const char *extra_suffix = ""; + uint64_t div; + int i; + const char *sign = ""; + const char *suffix = ""; + + /* The exponent (returned in i) minus one gives us + * floor(log2(val * 1024 / 1000). The correction makes us + * switch to the higher power when the integer part is >= 1000. + */ + if (allowSigned && ((int64_t)val < 0)) { + val = ((int64_t)val) * -1; + sign = "-"; + } + + frexp(val / (1000.0 / 1024.0), &i); + i = (i - 1) / 10; + assert(i < ARRAY_SIZE(suffixes)); + div = 1ULL << (i * 10); + + if (suffixes[i][0] != default_suffix) { + suffix = suffixes[i]; + if (i > 0 && long_suffix) { + extra_suffix = "iB"; + } + } else { + separator = NULL; + } + + return g_strdup_printf("%s%0.3g%s%s%s", + sign, + (double)val / div, + separator ? separator : "", + suffix, extra_suffix); +} + + +char *qemu_sztostr(int64_t val) +{ + return qemu_sztostr_impl((uint64_t)val, '\0', true, "", true); +} + + +char *qemu_sztostr_full(int64_t val, + const char default_suffix, + bool long_suffix, + const char *separator) +{ + return qemu_sztostr_impl((uint64_t)val, default_suffix, + long_suffix, separator, true); +} + + +char *qemu_szutostr(uint64_t val) +{ + return qemu_sztostr_impl(val, '\0', true, "", false); +} + + +char *qemu_szutostr_full(uint64_t val, + const char default_suffix, + bool long_suffix, + const char *separator) +{ + return qemu_sztostr_impl(val, default_suffix, + long_suffix, separator, false); +} + + /** * Helper function for qemu_strto*l() functions. */ -- 2.7.4