logo

utils

~/.local/bin tools and git-hooks git clone https://hacktivis.me/git/utils.git
commit: 950e3a9c99ff0d965077b3013783a3612d7d7b38
parent b989ec55d65529f5dfa16db56374e337f0b30a7e
Author: Haelwenn (lanodan) Monnier <contact@hacktivis.me>
Date:   Sun,  8 May 2022 19:38:35 +0200

bin/humanize: drop humanize_number, roll own algorithm

Diffstat:

Mbin/humanize.16++----
Mbin/humanize.c60+++++++++++++++++++++++++++++++++++-------------------------
Mtest-bin/humanize36++++++++++++++++++------------------
3 files changed, 55 insertions(+), 47 deletions(-)

diff --git a/bin/humanize.1 b/bin/humanize.1 @@ -1,7 +1,7 @@ .\" Collection of Unix tools, comparable to coreutils .\" Copyright 2017-2022 Haelwenn (lanodan) Monnier <contact+utils@hacktivis.me> .\" SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only -.Dd 2021-05-13 +.Dd 2022-05-08 .Dt HUMANIZE 1 .Os .Sh NAME @@ -14,7 +14,7 @@ .Sh DESCRIPTION Takes each .Ar number -and format it in a human readable form. +and format it in a human readable form, one per line. It supports the following options: .Bl -tag -width Ds .It Fl b @@ -24,7 +24,5 @@ Divide by 1000, this is the default but made explicit in case of changes without .El .Sh EXIT STATUS .Ex -std -.Sh SEE ALSO -.Xr humanize_number 3 .Sh AUTHORS .An Haelwenn (lanodan) Monnier Aq Mt contact@hacktivis.me diff --git a/bin/humanize.c b/bin/humanize.c @@ -6,15 +6,36 @@ // strtonum #define _OPENBSD_SOURCE // On non-BSDs use libbsd -#include <err.h> // errx -#include <errno.h> // EINVAL, ERANGE -#include <limits.h> // LLONG_MIN, LLONG_MAX -#include <stdio.h> // fprintf -#include <stdlib.h> // humanize_number, strtonum -#include <string.h> // strerror -#include <unistd.h> // opt*, getopt +#include <err.h> // errx +#include <errno.h> // EINVAL, ERANGE +#include <limits.h> // LLONG_MIN, LLONG_MAX +#include <stdbool.h> // bool +#include <stdio.h> // fprintf +#include <stdlib.h> // strtonum +#include <string.h> // strerror +#include <unistd.h> // opt*, getopt void +dtosi(double num, char *buf, size_t bufsize, bool iec) +{ + char *si_prefixes[9] = {"", "k", "M", "G", "T", "P", "E", "Z", "Y"}; + char *iec_prefixes[9] = {"B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB"}; + + int div = iec ? 1024 : 1000; + char **prefixes = iec ? iec_prefixes : si_prefixes; + + unsigned quotient = 0; + + while(num > div && quotient < 9) + { + num /= div; + quotient += 1; + } + + snprintf(buf, bufsize, "%g %s", num, prefixes[quotient]); +} + +static void usage() { fprintf(stderr, "Usage: humanize [-bd] number\n"); @@ -23,23 +44,19 @@ usage() int main(int argc, char *argv[]) { - int c; - int flags = HN_NOSPACE | HN_DECIMAL; // default to -d - int divisor = HN_DIVISOR_1000; - size_t buflen = 6; + bool iec = false; + int c = -1; while((c = getopt(argc, argv, ":bd")) != -1) { switch(c) { case 'b': - divisor = ~HN_DIVISOR_1000; - buflen = 7; // 4 digits, 3 letters for suffix, NUL byte + iec = true; break; case 'd': - divisor = HN_DIVISOR_1000; - buflen = 6; // 4 digits, 2 letters for suffix, NUL byte + iec = false; break; case ':': fprintf(stderr, "Error: Missing operand for option: '-%c'\n", optopt); @@ -64,7 +81,7 @@ main(int argc, char *argv[]) for(int argi = 0; argi < argc; argi++) { const char *errstr = NULL; - char buffer[7] = "-"; + char buf[32] = ""; // 1024^(6+1) goes higher than long long; don't ask for the moon long long n = strtonum(argv[argi], LLONG_MIN, LLONG_MAX, &errstr); @@ -73,17 +90,10 @@ main(int argc, char *argv[]) errx(1, "strtonum: %s is %s", argv[argi], errstr); } - int err = humanize_number(buffer, buflen, n, "", HN_AUTOSCALE, flags | divisor); - if(err < 0) - { - fprintf(stderr, "humanize_number: %s is %s\n", argv[argi], strerror(errno)); - return 1; - } + dtosi(n, buf, 32, iec); - printf("%s ", buffer); + printf("%s\n", buf); } - printf("\n"); - return 0; } diff --git a/test-bin/humanize b/test-bin/humanize @@ -3,53 +3,53 @@ atf_test_case one one_body() { atf_check -o "inline:1 \n" ../bin/humanize 1 atf_check -o "inline:1 \n" ../bin/humanize -d 1 - atf_check -o "inline:1B \n" ../bin/humanize -b 1 + atf_check -o "inline:1 B\n" ../bin/humanize -b 1 } atf_test_case two two_body() { atf_check -o "inline:12 \n" ../bin/humanize 12 atf_check -o "inline:12 \n" ../bin/humanize -d 12 - atf_check -o "inline:12B \n" ../bin/humanize -b 12 + atf_check -o "inline:12 B\n" ../bin/humanize -b 12 } atf_test_case three three_body() { atf_check -o "inline:123 \n" ../bin/humanize 123 atf_check -o "inline:123 \n" ../bin/humanize -d 123 - atf_check -o "inline:123B \n" ../bin/humanize -b 123 + atf_check -o "inline:123 B\n" ../bin/humanize -b 123 } # 1 234 atf_test_case four four_body() { - atf_check -o "inline:1234 \n" ../bin/humanize 1234 - atf_check -o "inline:1234 \n" ../bin/humanize -d 1234 - atf_check -o "inline:1234B \n" ../bin/humanize -b 1234 + atf_check -o "inline:1.234 k\n" ../bin/humanize 1234 + atf_check -o "inline:1.234 k\n" ../bin/humanize -d 1234 + atf_check -o "inline:1.20508 KiB\n" ../bin/humanize -b 1234 } # 12 345 atf_test_case five five_body() { - atf_check -o "inline:12k \n" ../bin/humanize 12345 - atf_check -o "inline:12k \n" ../bin/humanize -d 12345 - atf_check -o "inline:12Ki \n" ../bin/humanize -b 12345 + atf_check -o "inline:12.345 k\n" ../bin/humanize 12345 + atf_check -o "inline:12.345 k\n" ../bin/humanize -d 12345 + atf_check -o "inline:12.0557 KiB\n" ../bin/humanize -b 12345 } # 123 456 atf_test_case six six_body() { - atf_check -o "inline:123k \n" ../bin/humanize 123456 - atf_check -o "inline:123k \n" ../bin/humanize -d 123456 - atf_check -o "inline:121Ki \n" ../bin/humanize -b 123456 + atf_check -o "inline:123.456 k\n" ../bin/humanize 123456 + atf_check -o "inline:123.456 k\n" ../bin/humanize -d 123456 + atf_check -o "inline:120.562 KiB\n" ../bin/humanize -b 123456 } # 1234 4567 atf_test_case seven seven_body() { - atf_check -o "inline:1235k \n" ../bin/humanize 1234567 - atf_check -o "inline:1235k \n" ../bin/humanize -d 1234567 - atf_check -o "inline:1206Ki \n" ../bin/humanize -b 1234567 + atf_check -o "inline:1.23457 M\n" ../bin/humanize 1234567 + atf_check -o "inline:1.23457 M\n" ../bin/humanize -d 1234567 + atf_check -o "inline:1.17737 MiB\n" ../bin/humanize -b 1234567 } atf_test_case noarg @@ -65,11 +65,11 @@ badflag_body() { atf_test_case limits limits_body() { - atf_check -o 'inline:9223P \n' ../bin/humanize 9223372036854775807 + atf_check -o 'inline:9.22337 E\n' ../bin/humanize 9223372036854775807 atf_check -s exit:1 -e 'inline:humanize: strtonum: 9223372036854775808 is too large\n' ../bin/humanize 9223372036854775808 - # The fuck is this result - atf_check -o 'inline:-9223 \n' ../bin/humanize -- -9223372036854775808 + # Not as great as it should but at least not a lie + atf_check -o 'inline:-9.22337e+18 \n' ../bin/humanize -- -9223372036854775808 atf_check -s exit:1 -e 'inline:humanize: strtonum: -9223372036854775809 is too small\n' ../bin/humanize -- -9223372036854775809 }