human

convert bytes to human readable formats
git clone git://git.2f30.org/human.git
Log | Files | Refs | README | LICENSE

commit 7efd0ff2e01c72c2997535545ba5b62931b0e110
parent 1f789f4b2321bf0ca20096a24dbe1442b24fad7c
Author: z3bra <willyatmailoodotorg>
Date:   Fri, 29 Apr 2016 22:26:44 +0200

Add PETA/EXA factorization and fix output (thanks pranomostro!)

Original email:
> 1.Remove trailing spaces and fix the indentation a little bit.
> 2.Do not exit when an error occurs (factor(1) and sed(1) don't do this either)
> 3.Don't print trailing nullbytes when a number is converted to decimal
>     before:
>     $ human 6 | od -bc
>     0000000 066 000 012
>             6  \0  \n
>     0000003
>
>     now:
>     $ human 6 | od -bc
>     0000000 066 012
>             6  \n
>     0000002
> 4.Fix a string access at 32 (now LINE_MAX)
> 5.Add support for conversions up to EiB (Etabyte). I know this can be a bit
>   controversial.

Diffstat:
human.1 | 4++--
human.c | 45++++++++++++++++++++++++++++++---------------
2 files changed, 32 insertions(+), 17 deletions(-)

diff --git a/human.1 b/human.1 @@ -3,7 +3,7 @@ human \- output a number in human-readable format .SH SYNOPSIS .B human -.RI [ \-hbkmgt ]\ [ numbers ] +.RI [ \-hbkmgtpe ]\ [ numbers ] .SH DESCRIPTION .PP .B human @@ -14,7 +14,7 @@ readable format. Displays a help text .TP .B \-b, -k, -m, -g, -t -Force output in, respectively, Bytes, KiB, MiB, GiB or TiB. +Force output in, respectively, Bytes, KiB, MiB, GiB, TiB, PiB or EiB. .SH ENVIRONMENT .B SCALE The special variable SCALE will allow you to choose how many numbers you want after the decimal point. diff --git a/human.c b/human.c @@ -15,13 +15,14 @@ * */ -#include <err.h> #include <stdio.h> #include <stdlib.h> #include <limits.h> #include <string.h> #include "arg.h" +#define EXA 1152921504606846976 +#define PETA 1125899906842624 #define TERA 1099511627776 #define GIGA 1073741824 #define MEGA 1048576 @@ -30,9 +31,9 @@ #define DEFAULT_SCALE 0 /* - * Help, I need somebody - * Help, not just anybody - * Help, you know I need someone + * Help, I need somebody + * Help, not just anybody + * Help, you know I need someone * Help! * */ @@ -41,10 +42,10 @@ void usage (char *progname) printf("usage: %s [-hbkmgt] <number>\n", progname); } -/* +/* * calculate a power of number * disclaimers: return no more than a "long" so use wisely... - * + * */ long power (long number, int pow) { @@ -68,12 +69,14 @@ int getscale() /* * calculate the best factorization for a number, depending on its value. - * actual max factorisation is 1024^3 (TiB) + * actual max factorisation is 1024^5 (EiB) * */ char factorize (double number) { - return number >= TERA ? 'T' : + return number >= EXA ? 'E' : + number >= PETA ? 'P' : + number >= TERA ? 'T' : number >= GIGA ? 'G' : number >= MEGA ? 'M' : number >= KILO ? 'K' : @@ -91,12 +94,14 @@ double humanize (double number, char factor) /* cascading switch. note the lack of "break" statements */ switch (factor) { + case 'E' : pow++; + case 'P' : pow++; case 'T' : pow++; case 'G' : pow++; case 'M' : pow++; case 'K' : pow++; break; default : return number; - } + } /* return the number divided by the correct factorization level */ return number /= power(1024, pow); @@ -112,26 +117,34 @@ int human(char* s, char fac) double number = 0; switch (s[strnlen(s, LINE_MAX) - 1]) { + case 'E': pow++; + case 'P': pow++; case 'T': pow++; case 'G': pow++; case 'M': pow++; case 'K': pow++; - case 'B': s[strnlen(s, 32) - 1] = 0; + case 'B': s[strnlen(s, LINE_MAX) - 1] = 0; } /* get the number and convert it to bytes. If there is none, strtold will return 0 */ number = strtold(s, NULL); number *= power(1024, pow); - if (number <= 0) { - errx(EXIT_FAILURE, "I ain't gonna do that. Deal with it."); + if (number < 0) { + fprintf(stderr, "I ain't gonna do that. Deal with it."); + return -1; } /* use explicit factorization. otherwise, guess the best one */ fac = fac > 0 ? fac : factorize(number); /* actually print the result, isn't that what we're here for after all ? */ - printf("%.*f%c\n", getscale(), humanize(number, fac), fac == 'B' ? 0 : fac); + if (fac == 'B' || fac == '\0') { + printf("%.*f\n", getscale(), humanize(number, fac)); + } + else { + printf("%.*f%c\n", getscale(), humanize(number, fac), fac); + } return 0; } @@ -143,6 +156,8 @@ int main (int argc, char **argv) /* only switches are use to force factorization */ ARGBEGIN { case 'h': usage(argv0); exit(0); break; + case 'e': fac = 'E'; break; + case 'p': fac = 'P'; break; case 't': fac = 'T'; break; case 'g': fac = 'G'; break; case 'm': fac = 'M'; break; @@ -155,9 +170,9 @@ int main (int argc, char **argv) /* consume numbers from arguments, if any */ while (argc --> 0) { human(*argv++, fac); - } + } } else { - /* read numbers from stdin if no args, one per line */ + /* read numbers from stdin if no args, one per line */ while (fgets(in, LINE_MAX, stdin) != NULL) { /* overwrite the '\n' */ in[strnlen(in, LINE_MAX) - 1] = 0;