diff options
author | Rob Landley <rob@landley.net> | 2015-09-03 20:36:44 -0500 |
---|---|---|
committer | Rob Landley <rob@landley.net> | 2015-09-03 20:36:44 -0500 |
commit | d06ea3708d12e3e87fa26441715ac47f6dc63032 (patch) | |
tree | 18a517dd614a27ec99b36f51822a90d3a1155736 /lib/lib.c | |
parent | 5640847b0328c5319f353eed985781e166547ef7 (diff) | |
download | toybox-d06ea3708d12e3e87fa26441715ac47f6dc63032.tar.gz |
Make human_readable() handle base 1024 units without floating point.
Rounds correctly via brute force, displayed digits are decimal even when
working with powers of 2, shows at most 3 significant (decimal) digits.
(So no "1023M" nonsense, that's 1.0G.)
Diffstat (limited to 'lib/lib.c')
-rw-r--r-- | lib/lib.c | 42 |
1 files changed, 26 insertions, 16 deletions
@@ -866,27 +866,37 @@ void names_to_pid(char **names, int (*callback)(pid_t pid, char *name)) closedir(dp); } -// display first few digits of number with power of two units, except we're -// actually just counting decimal digits and showing mil/bil/trillions. +// display first few digits of number with power of two units int human_readable(char *buf, unsigned long long num, int style) { - int end, len; - - len = sprintf(buf, "%lld", num)-1; - end = (len%3)+1; - len /= 3; + unsigned long long snap = 0; + int len, unit, divisor = (style&HR_SI) ? 1024 : 1000; + + // Divide rounding up until we have 3 or fewer digits. Since the part we + // print is decimal, the test is 999 even when we divide by 1024. + // We can't run out of units because 2<<64 is 18 exabytes. + // test 5675 is 5.5k not 5.6k. + for (unit = 0; num > 999; unit++) num = ((snap = num)+(divisor/2))/divisor; + len = sprintf(buf, "%llu", num); + if (unit && len == 1) { + // Redo rounding for 1.2M case, this works with HR_SI and not. + num = snap/divisor; + snap -= num*divisor; + snap = ((snap*100)+50)/divisor; + snap /= 10; + len = sprintf(buf, "%llu.%llu", num, snap); + } + if (style & HR_SPACE) buf[len++] = ' '; + if (unit) { + unit = " kMGTPE"[unit]; - if (len && end == 1) { - buf[2] = buf[1]; - buf[1] = '.'; - end = 3; + if (!(style&HR_SI)) unit = toupper(unit); + buf[len++] = unit; } - if (style & HR_SPACE) buf[end++] = ' '; - if (len) buf[end++] = " KMGTPE"[len]; - if (style & HR_B) buf[end++] = 'B'; - buf[end++] = 0; + if (style & HR_B) buf[len++] = 'B'; + buf[len] = 0; - return end; + return len; } // The qsort man page says you can use alphasort, the posix committee |