human

output numbers in human-readable formats
git clone git://z3bra.org/human
Log | Files | Refs | README | LICENSE

commit 8c6c2473ecf5c168e145c8fb784caee76bb97e18
parent 53e70a441dfd24c48ba912bcaaa23f725b200cdc
Author: z3bra <willyatmailoodotorg>
Date:   Mon Apr 11 00:52:24 2016

Handle multiple arguments and read from stdin

pranomostro's patch to bring multiple argument handling on the CLI, as
well as reading numbers to convert from stdin (one per line).

This patch also replace getopts with arg.h.

Diffstat:
 arg.h   | 48 ++++++++++++++++++++++++++++++++++++++++++++++++
 human.1 |  7 ++++---
 human.c | 61 +++++++++++++++++++++++++++++++++++++++++++------------------
 3 files changed, 95 insertions(+), 21 deletions(-)

diff --git a/arg.h b/arg.h @@ -0,0 +1,48 @@ +/* + * Copy me if you can. + * by 20h + */ + +#ifndef ARG_H__ +#define ARG_H__ + +extern char *argv0; + +/* use main(int argc, char *argv[]) */ +#define ARGBEGIN for (argv0 = *argv, argv++, argc--;\ + argv[0] && argv[0][0] == '-'\ + && argv[0][1];\ + argc--, argv++) {\ + char argc_;\ + char **argv_;\ + int brk_;\ + if (argv[0][1] == '-' && argv[0][2] == '\0') {\ + argv++;\ + argc--;\ + break;\ + }\ + for (brk_ = 0, argv[0]++, argv_ = argv;\ + argv[0][0] && !brk_;\ + argv[0]++) {\ + if (argv_ != argv)\ + break;\ + argc_ = argv[0][0];\ + switch (argc_) +#define ARGEND }\ + } + +#define ARGC() argc_ + +#define EARGF(x) ((argv[0][1] == '\0' && argv[1] == NULL)?\ + ((x), abort(), (char *)0) :\ + (brk_ = 1, (argv[0][1] != '\0')?\ + (&argv[0][1]) :\ + (argc--, argv++, argv[0]))) + +#define ARGF() ((argv[0][1] == '\0' && argv[1] == NULL)?\ + (char *)0 :\ + (brk_ = 1, (argv[0][1] != '\0')?\ + (&argv[0][1]) :\ + (argc--, argv++, argv[0]))) + +#endif diff --git a/human.1 b/human.1 @@ -3,11 +3,12 @@ human \- output a number in human-readable format .SH SYNOPSIS .B human -.RI [ \-hbkmgt ] <number> +.RI [ \-hbkmgt ]\ [ numbers ] .SH DESCRIPTION .PP .B human -takes the number given as an argument, and output it in a human readable format. +takes numbers as arguments on the CLI, or from stdin, and output it in a human +readable format. .TP .B \-h Displays a help text @@ -45,4 +46,4 @@ The special variable SCALE will allow you to choose how many numbers you want af .SH REPORTING BUGS If you encounter any bugs, feel free to report them at \fIwilly@mailoo.org\fR .SH AUTHORS / CONTRIBUTORS -Willy Goiffon is the main author. +Willy Goiffon, Pranomostro diff --git a/human.c b/human.c @@ -18,9 +18,9 @@ #include <err.h> #include <stdio.h> #include <stdlib.h> -#include <getopt.h> #include <limits.h> #include <string.h> +#include "arg.h" #define TERA 1099511627776 #define GIGA 1073741824 @@ -102,33 +102,25 @@ double humanize (double number, char factor) return number /= power(1024, pow); } -int main (int argc, char **argv) +/* + * finally print a number in human-readable format, + * + */ +int human(char* s, char fac) { - char ch, pow = 0, fac = 0; + int pow = 0; double number = 0; - /* only switches are use to force factorization */ - while ((ch = getopt(argc, argv, "hbkmgt")) != -1) { - switch (ch) { - case 'h': usage(argv[0]); exit(0); break; - case 't': fac = 'T'; break; - case 'g': fac = 'G'; break; - case 'm': fac = 'M'; break; - case 'k': fac = 'K'; break; - case 'b': fac = 'B'; break; - } - } - - switch (argv[argc - 1][strnlen(argv[argc - 1],32) - 1]) { + switch (s[strnlen(s, LINE_MAX) - 1]) { case 'T': pow++; case 'G': pow++; case 'M': pow++; case 'K': pow++; - case 'B': argv[argc - 1][strnlen(argv[argc - 1],32) - 1] = 0; + case 'B': s[strnlen(s, 32) - 1] = 0; } /* get the number and convert it to bytes. If there is none, strtold will return 0 */ - number = strtold(argv[argc - 1], NULL); + number = strtold(s, NULL); number *= power(1024, pow); if (number <= 0) { @@ -140,6 +132,39 @@ int main (int argc, char **argv) /* 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); + return 0; +} + +int main (int argc, char **argv) +{ + char fac = 0; + char *argv0, *in; + + /* only switches are use to force factorization */ + ARGBEGIN { + case 'h': usage(argv0); exit(0); break; + case 't': fac = 'T'; break; + case 'g': fac = 'G'; break; + case 'm': fac = 'M'; break; + case 'k': fac = 'K'; break; + case 'b': fac = 'B'; break; + default: break; + } ARGEND; + + if (argc > 0) { + /* consume numbers from arguments, if any */ + while (argc --> 0) { + human(*argv++, fac); + } + } else { + /* read numbers from stdin if no args, one per line */ + in = malloc(LINE_MAX); + while (fgets(in, LINE_MAX, stdin) != NULL) { + /* overwrite the '\n' */ + in[strnlen(in, LINE_MAX) - 1] = 0; + human(in, fac); + } + } return 0; }