@@ -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)
@@ -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();
}
@@ -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.
*/
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 <berrange@redhat.com> --- include/qemu/cutils.h | 12 +++++++ tests/test-cutils.c | 96 +++++++++++++++++++++++++++++++++++++++++++++++++++ util/cutils.c | 78 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 186 insertions(+)