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:
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
 }