[Toybox] [PATCH] Add support for 1024 as well as 1000 to human_readable.

enh enh at google.com
Sat Aug 15 15:20:34 PDT 2015


Add support for 1024 as well as 1000 to human_readable.

This fixes the issue found with du, and paves the way for ls -lh (in a
separate patch). In manual testing this produces similar results to
coreutils, but better in some cases, presumably due to bad rounding in
coreutils. (toybox's 5675-byte main.c, for example, should be rounded
to 5.5Ki, not the 5.6 that coreutils reports.)

I've preserved support for SI multiples of 1000, but haven't bothered
to work out whether dd actually wants that. "It's in pending for a
reason", after all.

diff --git a/lib/lib.c b/lib/lib.c
index c16cffe..2f80be3 100644
--- a/lib/lib.c
+++ b/lib/lib.c
@@ -866,23 +866,22 @@ 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.
 int human_readable(char *buf, unsigned long long num, int style)
 {
-  int end, len;
+  double amount = num;
+  const char *unit = (style&HR_SI) ? " kMGTPE" : " KMGTPE";
+  int divisor = (style&HR_SI) ? 1000 : 1024;
+  int end;

-  len = sprintf(buf, "%lld", num)-1;
-  end = (len%3)+1;
-  len /= 3;
-
-  if (len && end == 1) {
-    buf[2] = buf[1];
-    buf[1] = '.';
-    end = 3;
+  while (amount > divisor && *unit) {
+    amount /= divisor;
+    ++unit;
   }
+  if (amount < 10) end = sprintf(buf, "%.1lf", amount);
+  else end = sprintf(buf, "%.0lf", amount);
+
   if (style & HR_SPACE) buf[end++] = ' ';
-  if (len) buf[end++] = " KMGTPE"[len];
+  if (*unit && *unit != ' ') buf[end++] = *unit;
   if (style & HR_B) buf[end++] = 'B';
   buf[end++] = 0;

diff --git a/lib/lib.h b/lib/lib.h
index 17a4a97..5805295 100644
--- a/lib/lib.h
+++ b/lib/lib.h
@@ -177,8 +177,9 @@ void replace_tempfile(int fdin, int fdout, char **tempname);
 void crc_init(unsigned int *crc_table, int little_endian);
 void base64_init(char *p);
 int yesno(char *prompt, int def);
-#define HR_SPACE 1
-#define HR_B 2
+#define HR_SPACE 1  // "20 K"; default "20K".
+#define HR_B 2      // "4B"; default "4".
+#define HR_SI 4     // /1000; default /1024.
 int human_readable(char *buf, unsigned long long num, int style);
 int qstrcmp(const void *a, const void *b);
 int xpoll(struct pollfd *fds, int nfds, int timeout);


More information about the Toybox mailing list