diff options
Diffstat (limited to 'src/xz/util.c')
-rw-r--r-- | src/xz/util.c | 72 |
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 /// |