diff options
-rw-r--r-- | lib/lib.c | 29 | ||||
-rw-r--r-- | lib/lib.h | 10 | ||||
-rw-r--r-- | toys/example/demo_number.c | 11 | ||||
-rw-r--r-- | toys/posix/ps.c | 20 |
4 files changed, 45 insertions, 25 deletions
@@ -1148,18 +1148,33 @@ match: } // display first "dgt" many digits of number plus unit (kilo-exabytes) -int human_readable_long(char *buf, unsigned long long num, int dgt, int style) +int human_readable_long(char *buf, unsigned long long num, int dgt, int unit, + int style) { unsigned long long snap = 0; - int len, unit, divisor = (style&HR_1000) ? 1000 : 1024; + int len, commas = 0, off, ii, divisor = (style&HR_1000) ? 1000 : 1024; // 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 1<<64 is 18 exabytes. - for (unit = 0; snprintf(0, 0, "%llu", num)>dgt; unit++) + // The largest unit we can detect is 1<<64 = 18 Exabytes, but we added + // Zettabyte and Yottabyte in case "unit" starts above zero. + for (;;unit++) { + len = snprintf(0, 0, "%llu", num); + if (style&HR_COMMAS) commas = (len>4)*((len-1)/3); + if (len<=(dgt-commas)) break; num = ((snap = num)+(divisor/2))/divisor; + } + if (CFG_TOYBOX_DEBUG && unit>8) return sprintf(buf, "%.*s", dgt, "TILT"); + len = sprintf(buf, "%llu", num); - if (unit && len == 1) { + if (commas) { + for (ii = 0; ii<commas; ii++) { + off = len-3*(ii+1); + memmove(buf+off+commas-ii, buf+off, 3); + buf[off+commas-ii-1] = ','; + } + len += commas; + } else if (unit && len == 1) { // Redo rounding for 1.2M case, this works with and without HR_1000. num = snap/divisor; snap -= num*divisor; @@ -1169,7 +1184,7 @@ int human_readable_long(char *buf, unsigned long long num, int dgt, int style) } if (style & HR_SPACE) buf[len++] = ' '; if (unit) { - unit = " kMGTPE"[unit]; + unit = " kMGTPEZY"[unit]; if (!(style&HR_1000)) unit = toupper(unit); buf[len++] = unit; @@ -1182,7 +1197,7 @@ int human_readable_long(char *buf, unsigned long long num, int dgt, int style) // Give 3 digit estimate + units ala 999M or 1.7T int human_readable(char *buf, unsigned long long num, int style) { - return human_readable_long(buf, num, 3, style); + return human_readable_long(buf, num, 3, 0, style); } // The qsort man page says you can use alphasort, the posix committee @@ -275,10 +275,12 @@ unsigned tar_cksum(void *data); int is_tar_header(void *pkt); char *elf_arch_name(int type); -#define HR_SPACE 1 // Space between number and units -#define HR_B 2 // Use "B" for single byte units -#define HR_1000 4 // Use decimal instead of binary units -int human_readable_long(char *buf, unsigned long long num, int dgt, int style); +#define HR_SPACE 1 // Space between number and units +#define HR_B 2 // Use "B" for single byte units +#define HR_1000 4 // Use decimal instead of binary units +#define HR_COMMAS 8 // Commas every 1000 +int human_readable_long(char *buf, unsigned long long num, int dgt, int unit, + int style); int human_readable(char *buf, unsigned long long num, int style); // env.c diff --git a/toys/example/demo_number.c b/toys/example/demo_number.c index 010320cf..42b62b51 100644 --- a/toys/example/demo_number.c +++ b/toys/example/demo_number.c @@ -2,14 +2,17 @@ * * Copyright 2015 Rob Landley <rob@landley.net> -USE_DEMO_NUMBER(NEWTOY(demo_number, "D#=3<3hdbs", TOYFLAG_BIN)) +USE_DEMO_NUMBER(NEWTOY(demo_number, "D#=3<3M#<0hcdbs", TOYFLAG_BIN)) config DEMO_NUMBER bool "demo_number" default n help - usage: demo_number [-hsbi] NUMBER... + usage: demo_number [-hsbi] [-D LEN] NUMBER... + -D output field is LEN chars + -M input units (index into bkmgtpe) + -c Comma comma down do be do down down -b Use "B" for single byte units (HR_B) -d Decimal units -h Human readable @@ -20,7 +23,7 @@ config DEMO_NUMBER #include "toys.h" GLOBALS( - long D; + long M, D; ) void demo_number_main(void) @@ -31,7 +34,7 @@ void demo_number_main(void) long long ll = atolx(*arg); if (toys.optflags) { - human_readable_long(toybuf, ll, TT.D, toys.optflags); + human_readable_long(toybuf, ll, TT.D, TT.M, toys.optflags); xputs(toybuf); } else printf("%lld\n", ll); } diff --git a/toys/posix/ps.c b/toys/posix/ps.c index cd8c73ea..8707ae5a 100644 --- a/toys/posix/ps.c +++ b/toys/posix/ps.c @@ -600,7 +600,7 @@ static char *string_field(struct procpid *tb, struct ofields *field) } if (which <= PS_SHR) ll *= sysconf(_SC_PAGESIZE); if (TT.forcek) sprintf(out, "%lldk", ll/1024); - else human_readable_long(s, ll, i-1, 0); + else human_readable_long(s, ll, i-1, 0, 0); // Posix doesn't specify what flags should say. Man page says // 1 for PF_FORKNOEXEC and 4 for PF_SUPERPRIV from linux/sched.h @@ -1568,7 +1568,7 @@ static void top_common( char hr[4][32]; long long ll, up = 0; long run[6]; - int j; + int j, k; // Count running, sleeping, stopped, zombie processes. // The kernel has more states (and different sets in different @@ -1590,19 +1590,19 @@ static void top_common( j = i%3; pos = strafter(toybuf+256, (char *[]){"MemTotal:","\nMemFree:", "\nBuffers:","\nSwapTotal:","\nSwapFree:","\nCached:"}[i]); - human_readable_long(hr[j+!!j], 1024*(run[i] = pos?atol(pos):0), - 8, 0); - if (j==1) human_readable_long(hr[1], 1024*(run[i-1]-run[i]), 8,0); + run[i] = pos ? atol(pos) : 0; + k = (*run>=10000000); + human_readable_long(hr[j+!!j], run[i]>>(10*k), 8, k+1, HR_COMMAS); + if (j==1) human_readable_long(hr[1], (run[i-1]-run[i])>>(10*k), + 8, k+1, HR_COMMAS); else if (j==2) { - sprintf(toybuf, (i<3) - ? " Mem: %9s total, %9s used, %9s free, %9s buffers" - : " Swap: %9s total, %9s used, %9s free, %9s cached", - hr[0], hr[1], hr[2], hr[3]); + sprintf(toybuf, " %s: %9s total, %9s used, %9s free, %9s %s", + (i<3) ? " Mem" : "Swap", hr[0], hr[1], hr[2], hr[3], + (i<3) ? "buffers" : "cached"); lines = header_line(lines, 0); } } } - pos = toybuf; i = sysconf(_SC_NPROCESSORS_CONF); pos += sprintf(pos, "%d%%cpu", i*100); |