aboutsummaryrefslogtreecommitdiff
path: root/src/xz/util.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/xz/util.c')
-rw-r--r--src/xz/util.c72
1 files changed, 72 insertions, 0 deletions
diff --git a/src/xz/util.c b/src/xz/util.c
index c0ac5384..a962421f 100644
--- a/src/xz/util.c
+++ b/src/xz/util.c
@@ -11,6 +11,7 @@
///////////////////////////////////////////////////////////////////////////////
#include "private.h"
+#include <stdarg.h>
extern void *
@@ -144,6 +145,55 @@ uint64_to_str(uint64_t value, uint32_t slot)
extern const char *
+uint64_to_nicestr(uint64_t value, enum nicestr_unit unit_min,
+ enum nicestr_unit unit_max, bool always_also_bytes,
+ uint32_t slot)
+{
+ assert(unit_min <= unit_max);
+ assert(unit_max <= NICESTR_TIB);
+
+ enum nicestr_unit unit = NICESTR_B;
+ const char *str;
+
+ if ((unit_min == NICESTR_B && value < 10000)
+ || unit_max == NICESTR_B) {
+ // The value is shown as bytes.
+ str = uint64_to_str(value, slot);
+ } else {
+ // Scale the value to a nicer unit. Unless unit_min and
+ // unit_max limit us, we will show at most five significant
+ // digits with one decimal place.
+ double d = (double)(value);
+ do {
+ d /= 1024.0;
+ ++unit;
+ } while (unit < unit_min || (d > 9999.9 && unit < unit_max));
+
+ str = double_to_str(d);
+ }
+
+ static const char suffix[5][4] = { "B", "KiB", "MiB", "GiB", "TiB" };
+
+ // Minimum buffer size:
+ // 11 "1,234.5 MiB"
+ // 2 " ("
+ // 26 2^64 with thousand separators
+ // 3 " B)"
+ // 1 '\0'
+ // 43 Total
+ static char buf[4][44];
+ char *pos = buf[slot];
+ size_t left = sizeof(buf[slot]);
+ my_snprintf(&pos, &left, "%s %s", str, suffix[unit]);
+
+ if (always_also_bytes && value >= 10000)
+ snprintf(pos, left, " (%s B)", uint64_to_str(value, slot));
+
+ return buf[slot];
+}
+
+
+extern const char *
double_to_str(double value)
{
// 64 bytes is surely enough, since it won't fit in some other
@@ -166,6 +216,28 @@ double_to_str(double value)
}
+extern void
+my_snprintf(char **pos, size_t *left, const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ const int len = vsnprintf(*pos, *left, fmt, ap);
+ va_end(ap);
+
+ // If an error occurred, we want the caller to think that the whole
+ // buffer was used. This way no more data will be written to the
+ // buffer. We don't need better error handling here.
+ if (len < 0 || (size_t)(len) >= *left) {
+ *left = 0;
+ } else {
+ *pos += len;
+ *left -= len;
+ }
+
+ return;
+}
+
+
/*
/// \brief Simple quoting to get rid of ASCII control characters
///