aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore2
-rw-r--r--Makefile24
-rw-r--r--config-parser.c26
-rw-r--r--formatting.c593
-rw-r--r--formatting.h30
-rw-r--r--formatting.obin0 -> 27848 bytes
-rw-r--r--intmath.c353
-rw-r--r--intmath.h29
-rw-r--r--minitest.h1
-rw-r--r--stdu.c49
-rw-r--r--tests.c10
11 files changed, 702 insertions, 415 deletions
diff --git a/.gitignore b/.gitignore
index 09bf9a3..cba0639 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,4 +2,4 @@ stdu
stdu.o
intmath.o
config-parser.o
-test
+tests
diff --git a/Makefile b/Makefile
index 3c3b8ae..e5bfd68 100644
--- a/Makefile
+++ b/Makefile
@@ -1,19 +1,25 @@
-stdu : stdu.o intmath.o intmath.h config-parser.h config-parser.o
- cc -o stdu stdu.o intmath.o config-parser.o
+stdu : stdu.o intmath.o intmath.h config-parser.h config-parser.o formatting.o \
+ formatting.h
+ cc -g -o stdu stdu.o intmath.o config-parser.o formatting.o
stdu.o : stdu.c
- cc -c stdu.c
+ cc -g -c stdu.c
+
+formatting.o : formatting.h formatting.c intmath.h intmath.c minitest.h
+ cc -g -c formatting.c
intmath.o : intmath.c minitest.h intmath.h
- cc -c intmath.c
+ cc -g -c intmath.c
config-parser.o : config-parser.c config-parser.h minitest.h
- cc -c config-parser.c
+ cc -g -c config-parser.c
+
+tests : tests.c minitest.h intmath.c config-parser.c formatting.c
+ cc -g -o tests tests.c
-test : tests.c minitest.h intmath.c config-parser.c
- cc -o test tests.c
- ./test
+test : tests
+ ./tests
clean :
- rm stdu stdu.o intmath.o test config-parser.o
+ rm stdu stdu.o intmath.o tests config-parser.o formatting.o
diff --git a/config-parser.c b/config-parser.c
index cd97dc7..5e403f8 100644
--- a/config-parser.c
+++ b/config-parser.c
@@ -9,6 +9,8 @@
#include "minitest.h"
#include "config-parser.h"
+/* Returns a `Result` containing a dynamically allocated `Config` or a `char*`
+ * error message depending on the `success` field of the `Result`. */
Result parse_config(int argc, char* argv[]) {
Result res;
res.success = false;
@@ -140,6 +142,7 @@ char* test_default_config() {
mt_assert_eq(res.success, true);
mt_assert_eq(conf->precision, 0);
mt_assert_eq(conf->human_readable, false);
+ free(conf);
return 0;
}
@@ -147,7 +150,6 @@ char* test_precision_parsing() {
int argc;
Result res;
Config* conf;
- char* error_msg;
argc = 3;
char* argv[] = { "stdu", "--precision", "3" };
@@ -165,7 +167,7 @@ char* test_precision_parsing() {
res.success == false,
"not specifying precision after `-p` didn't error"
);
- free(error_msg);
+ free(res.result);
argc = 4;
char* argv3[] = { "stdu", "--precision", "1", "-p3" };
@@ -187,10 +189,7 @@ char* test_human_readability_parsing() {
char* error_msg;
argc = 2;
- char* argv[] = {
- "stdu",
- "--human-readable"
- };
+ char* argv[] = { "stdu", "--human-readable" };
res = parse_config(argc, argv);
conf = (Config*) res.result;
mt_assert_eq(res.success, true);
@@ -199,21 +198,10 @@ char* test_human_readability_parsing() {
free(conf);
argc = 3;
- char* argv3[] = {
- "stdu",
- "-h",
- "-h"
- };
- res = parse_config(argc, argv3);
+ char* argv2[] = { "stdu", "-h", "-h" };
+ res = parse_config(argc, argv2);
error_msg = (char*) res.result;
mt_assert_eq(res.success, false);
- mt_assert(
- strcmp(
- error_msg,
- "human readability can't be specified multiple times"
- ),
- "should error on double argument of human readability"
- );
free(error_msg);
return 0;
diff --git a/formatting.c b/formatting.c
new file mode 100644
index 0000000..c806f4d
--- /dev/null
+++ b/formatting.c
@@ -0,0 +1,593 @@
+
+#include <math.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "intmath.h"
+#include "formatting.h"
+#include "minitest.h"
+
+size_t int_charcount(int x) {
+ size_t n = x < 0;
+ x *= -(x < 0) * 2 + 1;
+ while (x >= 10) {
+ x /= 10;
+ n += 1;
+ }
+ return n + 1;
+}
+
+/* Returns `int x` floored to `unsigned int precision` as an `exp_notated`
+ * value with given `unsigned int base`.
+ *
+ * `unsigned int base` affects the precision.
+ */
+exp_notated int_floored_exponent_notation_base
+(
+ int x,
+ unsigned int precision,
+ unsigned int base
+) {
+ int original = x;
+ int sign = (x < 0) * -2 + 1;
+ x *= sign;
+
+ int i = 0;
+ while (x >= int_pown(base, precision)) {
+ x /= base;
+ i++;
+ }
+ x += (sign == -1) && (original != -x * int_pown(base, i));
+ if (x >= int_pown(base, precision)) {
+ x /= base;
+ i++;
+ }
+ x *= sign;
+
+ exp_notated res = {
+ .mantissa = x,
+ .exponent = i,
+ .base = base
+ };
+ return res;
+}
+
+exp_notated int_floored_exponent_notation(int x, unsigned int precision) {
+ return int_floored_exponent_notation_base(x, precision, 10);
+}
+
+exp_notated int_ceiled_exponent_notation_base(
+ int x,
+ unsigned int precision,
+ unsigned int base
+) {
+ exp_notated res = int_floored_exponent_notation_base(-x, precision, base);
+ res.mantissa = -res.mantissa;
+ return res;
+}
+
+exp_notated int_ceiled_exponent_notation(int x, unsigned int precision) {
+ return int_ceiled_exponent_notation_base(x, precision, 10);
+}
+
+int exp_notated_to_int(exp_notated x) {
+ return x.mantissa * int_pown(x.base, x.exponent);
+}
+
+/* Returns the appropriate binary prefix for `exp_notated x`. `x` must have
+ * `1024` as its base and its exponent should not be greater than `10` Failing
+ * to meet these conditions results in the function returning `NULL`.
+ */
+const char* binary_prefix(exp_notated x) {
+ if (x.base != 1024) return NULL;
+
+ switch (x.exponent) {
+ case 0:
+ return "";
+ case 1:
+ return "Ki";
+ case 2:
+ return "Mi";
+ case 3:
+ return "Gi";
+ case 4:
+ return "Ti";
+ case 5:
+ return "Pi";
+ case 6:
+ return "Ei";
+ case 7:
+ return "Zi";
+ case 8:
+ return "Yi";
+ case 9:
+ return "Ri";
+ case 10:
+ return "Qi";
+ }
+
+ return NULL;
+}
+
+/* Modifies the string pointed to by `char** res` to a string describing the
+ * argument `int x` floored to the appropriate multiple of 1024 followed with a
+ * binary prefix (Ki, Mi, Gi...).
+ *
+ * `size_t* res_bufsize` should point to a value describing the size of the
+ * string buffer pointed to by `char** res`. Returns a negative value upon
+ * failure in memory allocation or `snprintf`, otherwise returns the length of
+ * `char* res`.
+ */
+int int_floored_with_binary_prefix(char** res, size_t* res_bufsize, int x) {
+ exp_notated x_exp = int_floored_exponent_notation_base(x, 1, 1024);
+ if (x_exp.exponent > 10) { /* quebi-=1024^10 greatest defined prefix */
+ x_exp.mantissa *= int_pown(1024, x_exp.exponent - 10);
+ x_exp.exponent = 10;
+ }
+
+ const char* prefix = binary_prefix(x_exp);
+
+ size_t bufsize =
+ 5 + /* len("-1024") */
+ /* length of possible zeroes */
+ int_max(0, (x_exp.exponent - 10) * 3) +
+ 4; /* len(" Gi\0") */
+ if (bufsize > *res_bufsize) {
+ free(*res);
+ *res = malloc(bufsize);
+ *res_bufsize = bufsize;
+ }
+ if (*res == NULL) return -1;
+ return snprintf(*res, *res_bufsize, "%d %s", x_exp.mantissa, prefix);
+}
+
+/* Returns the unit prefix resembling the exponent `int x`. If there is no
+ * prefix resembling `x`, NULL is returned, though the special case `x = 0`
+ * returns an empty string.
+ */
+const char* unit_prefix(int exponent) {
+ switch (exponent) {
+ case -30:
+ return "q";
+ case -27:
+ return "r";
+ case -24:
+ return "y";
+ case -21:
+ return "z";
+ case -18:
+ return "a";
+ case -15:
+ return "f";
+ case -12:
+ return "p";
+ case -9:
+ return "n";
+ case -6:
+ return "μ";
+ case -3:
+ return "m";
+ case -2:
+ return "c";
+ case -1:
+ return "d";
+ case 0:
+ return "";
+ case 1:
+ return "da";
+ case 2:
+ return "h";
+ case 3:
+ return "k";
+ case 6:
+ return "M";
+ case 9:
+ return "G";
+ case 12:
+ return "T";
+ case 15:
+ return "P";
+ case 18:
+ return "E";
+ case 21:
+ return "Z";
+ case 24:
+ return "Y";
+ case 27:
+ return "R";
+ case 30:
+ return "Q";
+ }
+
+ return NULL;
+}
+
+/* Modifies the string pointed to by `char** res` to a string describing the
+ * argument `int x` floored to the appropriate precision followed with a unit
+ * prefix (k, M, G...).
+ *
+ * `size_t* res_bufsize` should point to a value describing the size of the
+ * string buffer pointed to by `char** res`. Returns a negative value upon
+ * failure and the length of `char* res` on success. Failure can be caused by
+ * problems in memory allocation or failure in `snprintf`.
+ */
+int int_floored_with_prefix(
+ char** res,
+ size_t* res_bufsize,
+ int x,
+ unsigned int precision
+) {
+ exp_notated x_exp
+ = int_floored_exponent_notation_base(x, precision, 10);
+ double mantissa = (double) x_exp.mantissa * int_pow10(x_exp.exponent % 3);
+ unsigned int exponent = x_exp.exponent - x_exp.exponent % 3;
+
+ while (fabs(mantissa) >= 1000) {
+ mantissa /= 1000;
+ exponent += 3;
+ }
+
+ const char* prefix = unit_prefix(exponent);
+ size_t prefix_len = strlen(prefix);
+
+ size_t bufsize =
+ int_max(precision, 3) /* mantissa */
+ + 4 /* minus, space, decimal dot and NULL byte */
+ + prefix_len;
+ if (bufsize > *res_bufsize) {
+ free(*res);
+ *res_bufsize = bufsize;
+ *res = malloc(*res_bufsize);
+ }
+ if (*res == NULL) return -1;
+
+ return snprintf(
+ *res,
+ *res_bufsize,
+ "%.*f %s",
+ int_max(precision - int_charcount((int) fabs(mantissa)), 0),
+ mantissa,
+ prefix
+ );
+}
+
+char* test_floored_exponent_notation() {
+ const size_t bufsize = 128;
+ char* msg = malloc(bufsize);
+
+ exp_notated res = int_floored_exponent_notation(9489345, 3);
+ snprintf(msg, bufsize,
+ "int_floored_exponent_notation(9489345, 3): expected 948*10^4, got %d*%d^%d",
+ res.mantissa, res.base, res.exponent
+ );
+ mt_assert(
+ res.mantissa == 948 &&
+ res.base == 10 &&
+ res.exponent == 4
+ , msg);
+
+ res = int_floored_exponent_notation(-88, 1);
+ snprintf(msg, bufsize,
+ "int_floored_exponent_notation(-88, 1): expected -9*10^1, got %d*%d^%d",
+ res.mantissa, res.base, res.exponent
+ );
+ mt_assert(
+ res.mantissa == -9 &&
+ res.base == 10 &&
+ res.exponent == 1
+ , msg);
+
+ res = int_floored_exponent_notation(-99, 1);
+ snprintf(msg, bufsize,
+ "int_floored_exponent_notation(-99, 1): expected -1*10^2, got %d*%d^%d",
+ res.mantissa, res.base, res.exponent
+ );
+ mt_assert(
+ res.mantissa == -1 &&
+ res.base == 10 &&
+ res.exponent == 2
+ , msg);
+
+ res = int_floored_exponent_notation_base(3145733, 1, 1024);
+ snprintf(msg, bufsize,
+ "int_floored_exponent_notation_base(3145733, 1, 1024): expected 3*1024^2, got %d*%d^%d",
+ res.mantissa, res.base, res.exponent
+ );
+ mt_assert(
+ res.mantissa == 3 &&
+ res.base == 1024 &&
+ res.exponent == 2
+ , msg);
+
+ res = int_floored_exponent_notation_base(-1022, 1, 1024);
+ snprintf(msg, bufsize,
+ "int_floored_exponent_notation(-1022, 1, 1024): expected -1022*1024^0, got %d*%d^%d",
+ res.mantissa, res.base, res.exponent
+ );
+ mt_assert(
+ res.mantissa == -1022 &&
+ res.base == 1024 &&
+ res.exponent == 0
+ , msg);
+
+ res = int_floored_exponent_notation_base(-1023, 1, 1024);
+ snprintf(msg, bufsize,
+ "int_floored_exponent_notation(-1023, 1, 1024): expected -1023*1024^0, got %d*%d^%d",
+ res.mantissa, res.base, res.exponent
+ );
+ mt_assert(
+ res.mantissa == -1023 &&
+ res.base == 1024 &&
+ res.exponent == 0
+ , msg);
+
+ res = int_floored_exponent_notation_base(-1024, 1, 1024);
+ snprintf(msg, bufsize,
+ "int_floored_exponent_notation(-1024, 1, 1024): expected -1*1024^1, got %d*%d^%d",
+ res.mantissa, res.base, res.exponent
+ );
+ mt_assert(
+ res.mantissa == -1 &&
+ res.base == 1024 &&
+ res.exponent == 1
+ , msg);
+
+ free(msg);
+ return 0;
+}
+
+char* test_ceiled_exponent_notation() {
+ const size_t bufsize = 128;
+ char* msg = malloc(bufsize);
+
+ exp_notated res = int_ceiled_exponent_notation(9489345, 3);
+ snprintf(msg, bufsize,
+ "int_ceiled_exponent_notation(9489345, 3): expected 949*10^4, got %d*%d^%d",
+ res.mantissa, res.base, res.exponent
+ );
+ mt_assert(
+ res.mantissa == 949 &&
+ res.base == 10 &&
+ res.exponent == 4
+ , msg);
+
+ res = int_ceiled_exponent_notation(-99, 1);
+ snprintf(msg, bufsize,
+ "int_ceiled_exponent_notation(-99, 1): expected -9*10^1, got %d*%d^%d",
+ res.mantissa, res.base, res.exponent
+ );
+ mt_assert(
+ res.mantissa == -9 &&
+ res.base == 10 &&
+ res.exponent == 1
+ , msg);
+
+ res = int_ceiled_exponent_notation(-100, 1);
+ snprintf(msg, bufsize,
+ "int_ceiled_exponent_notation(-100, 1): expected -1*10^2, got %d*%d^%d",
+ res.mantissa, res.base, res.exponent
+ );
+ mt_assert(
+ res.mantissa == -1 &&
+ res.base == 10 &&
+ res.exponent == 2
+ , msg);
+
+ res = int_ceiled_exponent_notation_base(3145733, 1, 1024);
+ snprintf(msg, bufsize,
+ "int_ceiled_exponent_notation_base(3145733, 1, 1024): expected 4*1024^2, got %d*%d^%d",
+ res.mantissa, res.base, res.exponent
+ );
+ mt_assert(
+ res.mantissa == 4 &&
+ res.base == 1024 &&
+ res.exponent == 2
+ , msg);
+
+ res = int_ceiled_exponent_notation_base(-1023, 1, 1024);
+ snprintf(msg, bufsize,
+ "int_ceiled_exponent_notation(-1023, 1, 1024): expected -1023*1024^0, got %d*%d^%d",
+ res.mantissa, res.base, res.exponent
+ );
+ mt_assert(
+ res.mantissa == -1023 &&
+ res.base == 1024 &&
+ res.exponent == 0
+ , msg);
+
+ res = int_ceiled_exponent_notation_base(-1024, 1, 1024);
+ snprintf(msg, bufsize,
+ "int_ceiled_exponent_notation(-1024, 1, 1024): expected -1*1024^1, got %d*%d^%d",
+ res.mantissa, res.base, res.exponent
+ );
+ mt_assert(
+ res.mantissa == -1 &&
+ res.base == 1024 &&
+ res.exponent == 1
+ , msg);
+
+ free(msg);
+ return 0;
+}
+
+char* test_exponent_notated_to_int() {
+ exp_notated x = {
+ .mantissa = 3,
+ .exponent = 2,
+ .base = 10
+ };
+ mt_assert_eq(300, exp_notated_to_int(x));
+ return 0;
+}
+
+char* test_floored_with_binary_prefix() {
+ const size_t bufsize = 64;
+ char* msg = malloc(bufsize);
+ size_t res_bufsize = 2;
+ char* res = malloc(res_bufsize);
+
+ int_floored_with_binary_prefix(
+ &res,
+ &res_bufsize,
+ 1026
+ );
+ snprintf(msg, bufsize, "1026 yielded `%s` instead of `1 Ki`", res);
+ mt_assert(strcmp(
+ res,
+ "1 Ki"
+ ) == 0, msg);
+
+ int_floored_with_binary_prefix(
+ &res,
+ &res_bufsize,
+ -1023
+ );
+ snprintf(msg, bufsize, "-1023 yielded `%s` instead of `-1023`", res);
+ mt_assert(strcmp(
+ res,
+ "-1023 "
+ ) == 0, msg);
+
+ int_floored_with_binary_prefix(
+ &res,
+ &res_bufsize,
+ -1026
+ );
+ snprintf(msg, bufsize, "-1026 yielded `%s` instead of `-2 Ki`", res);
+ mt_assert(strcmp(
+ res,
+ "-2 Ki"
+ ) == 0, msg);
+
+ int_floored_with_binary_prefix(
+ &res,
+ &res_bufsize,
+ 1049088
+ );
+ snprintf(msg, bufsize, "1049088 yielded `%s` instead of `1 Mi`", res);
+ mt_assert(strcmp(
+ res,
+ "1 Mi"
+ ) == 0, msg);
+
+ int_floored_with_binary_prefix(
+ &res,
+ &res_bufsize,
+ 5243392
+ );
+ snprintf(msg, bufsize, "5243392 yielded `%s` instead of `5 Mi`", res);
+ mt_assert(strcmp(
+ res,
+ "5 Mi"
+ ) == 0, msg);
+
+ free(res);
+ free(msg);
+ return 0;
+}
+
+
+char* test_floored_with_prefix() {
+ const size_t bufsize = 64;
+ char* msg = malloc(bufsize);
+ size_t res_bufsize = 2;
+ char* res = malloc(res_bufsize);
+
+ int_floored_with_prefix(
+ &res,
+ &res_bufsize,
+ 1001,
+ 3
+ );
+ snprintf(msg, bufsize, "1001 yielded `%s` instead of `1.00 k`", res);
+ mt_assert(strcmp(
+ res,
+ "1.00 k"
+ ) == 0, msg);
+
+ int_floored_with_prefix(
+ &res,
+ &res_bufsize,
+ 300,
+ 1
+ );
+ snprintf(msg, bufsize, "300 (-p1) yielded `%s` instead of `300 `", res);
+ mt_assert(strcmp(
+ res,
+ "300 "
+ ) == 0, msg);
+
+ int_floored_with_prefix(
+ &res,
+ &res_bufsize,
+ -999,
+ 3
+ );
+ snprintf(msg, bufsize, "-999 yielded `%s` instead of `-999 `", res);
+ mt_assert(strcmp(
+ res,
+ "-999 "
+ ) == 0, msg);
+
+ int_floored_with_prefix(
+ &res,
+ &res_bufsize,
+ -1026,
+ 3
+ );
+ snprintf(msg, bufsize, "-1021 yielded `%s` instead of `-1.03 k`", res);
+ mt_assert(strcmp(
+ res,
+ "-1.03 k"
+ ) == 0, msg);
+
+ int_floored_with_prefix(
+ &res,
+ &res_bufsize,
+ 1000000,
+ 2
+ );
+ snprintf(msg, bufsize, "1 000 000 yielded `%s` instead of `1.0 M`", res);
+ mt_assert(strcmp(
+ res,
+ "1.0 M"
+ ) == 0, msg);
+
+ int_floored_with_prefix(
+ &res,
+ &res_bufsize,
+ 5243392,
+ 4
+ );
+ snprintf(msg, bufsize, "5243692 yielded `%s` instead of `5.243 M`", res);
+ mt_assert(strcmp(
+ res,
+ "5.243 M"
+ ) == 0, msg);
+
+ free(res);
+ free(msg);
+ return 0;
+}
+
+char* test_int_charcount() {
+ mt_assert_eq(int_charcount(5), 1);
+ mt_assert_eq(int_charcount(24), 2);
+ mt_assert_eq(int_charcount(10), 2);
+ mt_assert_eq(int_charcount(0), 1);
+ mt_assert_eq(int_charcount(1), 1);
+ mt_assert_eq(int_charcount(-1), 2);
+ mt_assert_eq(int_charcount(99), 2);
+ mt_assert_eq(int_charcount(100), 3);
+ return 0;
+}
+
+
+void formatting_tests() {
+ mt_run_test(test_int_charcount);
+ mt_run_test(test_floored_exponent_notation);
+ mt_run_test(test_ceiled_exponent_notation);
+ mt_run_test(test_exponent_notated_to_int);
+ mt_run_test(test_floored_with_binary_prefix);
+ mt_run_test(test_floored_with_prefix);
+}
diff --git a/formatting.h b/formatting.h
new file mode 100644
index 0000000..b9ef53b
--- /dev/null
+++ b/formatting.h
@@ -0,0 +1,30 @@
+
+#ifndef FORMATTING_IS_IMPORTED
+#define FORMATTING_IS_IMPORTED
+
+struct exp_val {
+ int mantissa;
+ int exponent;
+ int base;
+};
+typedef struct exp_val exp_notated;
+
+exp_notated int_floored_exponent_notation_base(
+ int x,
+ unsigned int precision,
+ unsigned int base
+);
+exp_notated int_ceiled_exponent_notation_base(
+ int x,
+ unsigned int precision,
+ unsigned int base
+);
+exp_notated int_floored_exponent_notation(int x, unsigned int precision);
+exp_notated int_ceiled_exponent_notation(int x, unsigned int precision);
+int exp_notated_to_int(exp_notated x);
+const char* binary_prefix(exp_notated x);
+const char* prefix(exp_notated x);
+int int_floored_with_binary_prefix(char** res, size_t* res_bufsize, int x);
+int int_floored_with_prefix(char** res, size_t* res_bufsize, int x, unsigned int precision);
+
+#endif
diff --git a/formatting.o b/formatting.o
new file mode 100644
index 0000000..709e87b
--- /dev/null
+++ b/formatting.o
Binary files differ
diff --git a/intmath.c b/intmath.c
index cba66a9..5d70860 100644
--- a/intmath.c
+++ b/intmath.c
@@ -45,132 +45,6 @@ int int_max(int a, int b) {
return (a > b) * a + (b >= a) * b;
}
-/* Returns `int x` floored to `unsigned int precision` as an `exp_notated`
- * value with given `unsigned int base`.
- *
- * `unsigned int base` affects the precision.
- */
-exp_notated int_floored_exponent_notation_base
-(
- int x,
- unsigned int precision,
- unsigned int base
-) {
- int original = x;
- int sign = (x < 0) * -2 + 1;
- x *= sign;
-
- int i = 0;
- while (x >= int_pown(base, precision)) {
- x /= base;
- i++;
- }
- x += (sign == -1) && (original != -x * int_pown(base, i));
- if (x >= int_pown(base, precision)) {
- x /= base;
- i++;
- }
- x *= sign;
-
- exp_notated res = {
- .mantissa = x,
- .exponent = i,
- .base = base
- };
- return res;
-}
-
-exp_notated int_floored_exponent_notation(int x, unsigned int precision) {
- return int_floored_exponent_notation_base(x, precision, 10);
-}
-
-exp_notated int_ceiled_exponent_notation_base(
- int x,
- unsigned int precision,
- unsigned int base
-) {
- exp_notated res = int_floored_exponent_notation_base(-x, precision, base);
- res.mantissa = -res.mantissa;
- return res;
-}
-
-exp_notated int_ceiled_exponent_notation(int x, unsigned int precision) {
- return int_ceiled_exponent_notation_base(x, precision, 10);
-}
-
-int exp_notated_to_int(exp_notated x) {
- return x.mantissa * int_pown(x.base, x.exponent);
-}
-
-/* Returns the appropriate binary prefix for `exp_notated x`. `x` must have
- * `1024` as its base, it should not be greater than `1023*1024^10` and it
- * should be floored/ceiled (ie. the mantissa should not be further away from
- * zero than `1023`). Failing to meet these conditions results in the function
- * returning `NULL`.
- */
-const char* binary_prefix(exp_notated x) {
- if (
- (x.base != 1024) ||
- (x.exponent > 10) ||
- (x.mantissa > 1023) ||
- (x.mantissa < -1023)
- ) {
- return NULL;
- }
-
- switch (x.exponent) {
- case 0:
- return "";
- case 1:
- return "Ki";
- case 2:
- return "Mi";
- case 3:
- return "Gi";
- case 4:
- return "Ti";
- case 5:
- return "Pi";
- case 6:
- return "Ei";
- case 7:
- return "Zi";
- case 8:
- return "Yi";
- case 9:
- return "Ri";
- default:
- return "Qi";
- }
-}
-
-/* Returns the a string describing the argument `int x` floored to the
- * appropriate multiple of 1024 followed with a binary prefix (Ki, Mi, Gi...).
- * The string is dynamically allocated and should be free'd.
- *
- * Returns NULL on malloc error.
- */
-char* int_floored_with_binary_prefix(int x) {
- exp_notated x_exp = int_floored_exponent_notation_base(x, 1, 1024);
- if (x_exp.exponent > 10) /* quebi-=1024^10 greatest defined prefix */
- x_exp.mantissa *= int_pow10(x_exp.exponent - 10);
-
- const char* prefix = binary_prefix(x_exp);
-
- size_t bufsize =
- 5 + /* len("-1024") */
- int_max(0, x_exp.exponent - 10) + /* length of possible zeros */
- 4; /* len(" Gi\0") */
- char* res = malloc(bufsize);
- if (res == NULL) return NULL;
- sprintf(res, "%d", x_exp.mantissa);
- if (strcmp(prefix, "") != 0)
- strcat(res, " ");
- strcat(res, prefix);
-
- return res;
-}
-
char* test_pown() {
mt_assert_eq(int_pown(2, 5), 32);
mt_assert_eq(int_pown(3, 3), 27);
@@ -205,231 +79,14 @@ char* test_ceil() {
char* test_min() {
mt_assert_eq(int_min(2, 6), 2);
mt_assert_eq(int_min(4, 1), 1);
- mt_assert_eq(int_min(10, 10), 1);
+ mt_assert_eq(int_min(10, 10), 10);
return 0;
}
char* test_max() {
mt_assert_eq(int_max(3, 7), 7);
- mt_assert_eq(int_min(4, 1), 4);
- mt_assert_eq(int_min(10, 10), 10);
- return 0;
-}
-
-char* test_floored_exponent_notation() {
- const size_t bufsize = 128;
- char* msg = malloc(bufsize);
-
- exp_notated res = int_floored_exponent_notation(9489345, 3);
- snprintf(msg, bufsize,
- "int_floored_exponent_notation(9489345, 3): expected 948*10^4, got %d*%d^%d",
- res.mantissa, res.base, res.exponent
- );
- mt_assert(
- res.mantissa == 948 &&
- res.base == 10 &&
- res.exponent == 4
- , msg);
-
- res = int_floored_exponent_notation(-88, 1);
- snprintf(msg, bufsize,
- "int_floored_exponent_notation(-88, 1): expected -9*10^1, got %d*%d^%d",
- res.mantissa, res.base, res.exponent
- );
- mt_assert(
- res.mantissa == -9 &&
- res.base == 10 &&
- res.exponent == 1
- , msg);
-
- res = int_floored_exponent_notation(-99, 1);
- snprintf(msg, bufsize,
- "int_floored_exponent_notation(-99, 1): expected -1*10^2, got %d*%d^%d",
- res.mantissa, res.base, res.exponent
- );
- mt_assert(
- res.mantissa == -1 &&
- res.base == 10 &&
- res.exponent == 2
- , msg);
-
- res = int_floored_exponent_notation_base(3145733, 1, 1024);
- snprintf(msg, bufsize,
- "int_floored_exponent_notation_base(3145733, 1, 1024): expected 3*1024^2, got %d*%d^%d",
- res.mantissa, res.base, res.exponent
- );
- mt_assert(
- res.mantissa == 3 &&
- res.base == 1024 &&
- res.exponent == 2
- , msg);
-
- res = int_floored_exponent_notation_base(-1022, 1, 1024);
- snprintf(msg, bufsize,
- "int_floored_exponent_notation(-1022, 1, 1024): expected -1022*1024^0, got %d*%d^%d",
- res.mantissa, res.base, res.exponent
- );
- mt_assert(
- res.mantissa == -1022 &&
- res.base == 1024 &&
- res.exponent == 0
- , msg);
-
- res = int_floored_exponent_notation_base(-1023, 1, 1024);
- snprintf(msg, bufsize,
- "int_floored_exponent_notation(-1023, 1, 1024): expected -1023*1024^0, got %d*%d^%d",
- res.mantissa, res.base, res.exponent
- );
- mt_assert(
- res.mantissa == -1023 &&
- res.base == 1024 &&
- res.exponent == 0
- , msg);
-
- res = int_floored_exponent_notation_base(-1024, 1, 1024);
- snprintf(msg, bufsize,
- "int_floored_exponent_notation(-1024, 1, 1024): expected -1*1024^1, got %d*%d^%d",
- res.mantissa, res.base, res.exponent
- );
- mt_assert(
- res.mantissa == -1 &&
- res.base == 1024 &&
- res.exponent == 1
- , msg);
-
- free(msg);
- return 0;
-}
-
-char* test_ceiled_exponent_notation() {
- const size_t bufsize = 128;
- char* msg = malloc(bufsize);
-
- exp_notated res = int_ceiled_exponent_notation(9489345, 3);
- snprintf(msg, bufsize,
- "int_ceiled_exponent_notation(9489345, 3): expected 949*10^4, got %d*%d^%d",
- res.mantissa, res.base, res.exponent
- );
- mt_assert(
- res.mantissa == 949 &&
- res.base == 10 &&
- res.exponent == 4
- , msg);
-
- res = int_ceiled_exponent_notation(-99, 1);
- snprintf(msg, bufsize,
- "int_ceiled_exponent_notation(-99, 1): expected -9*10^1, got %d*%d^%d",
- res.mantissa, res.base, res.exponent
- );
- mt_assert(
- res.mantissa == -9 &&
- res.base == 10 &&
- res.exponent == 1
- , msg);
-
- res = int_ceiled_exponent_notation(-100, 1);
- snprintf(msg, bufsize,
- "int_ceiled_exponent_notation(-100, 1): expected -1*10^2, got %d*%d^%d",
- res.mantissa, res.base, res.exponent
- );
- mt_assert(
- res.mantissa == -1 &&
- res.base == 10 &&
- res.exponent == 2
- , msg);
-
- res = int_ceiled_exponent_notation_base(3145733, 1, 1024);
- snprintf(msg, bufsize,
- "int_ceiled_exponent_notation_base(3145733, 1, 1024): expected 4*1024^2, got %d*%d^%d",
- res.mantissa, res.base, res.exponent
- );
- mt_assert(
- res.mantissa == 4 &&
- res.base == 1024 &&
- res.exponent == 2
- , msg);
-
- res = int_ceiled_exponent_notation_base(-1023, 1, 1024);
- snprintf(msg, bufsize,
- "int_ceiled_exponent_notation(-1023, 1, 1024): expected -1023*1024^0, got %d*%d^%d",
- res.mantissa, res.base, res.exponent
- );
- mt_assert(
- res.mantissa == -1023 &&
- res.base == 1024 &&
- res.exponent == 0
- , msg);
-
- res = int_ceiled_exponent_notation_base(-1024, 1, 1024);
- snprintf(msg, bufsize,
- "int_ceiled_exponent_notation(-1024, 1, 1024): expected -1*1024^1, got %d*%d^%d",
- res.mantissa, res.base, res.exponent
- );
- mt_assert(
- res.mantissa == -1 &&
- res.base == 1024 &&
- res.exponent == 1
- , msg);
-
- free(msg);
- return 0;
-}
-
-char* test_exponent_notated_to_int() {
- exp_notated x = {
- .mantissa = 3,
- .exponent = 2,
- .base = 10
- };
- mt_assert_eq(300, exp_notated_to_int(x));
- return 0;
-}
-
-char* test_floored_with_binary_prefix() {
- const size_t bufsize = 64;
- char* msg = malloc(bufsize);
-
- char* res = int_floored_with_binary_prefix(1026);
- snprintf(msg, bufsize, "1026 yielded `%s` instead of `1 Ki`", res);
- mt_assert(strcmp(
- res,
- "1 Ki"
- ) == 0, msg);
- free(res);
-
- res = int_floored_with_binary_prefix(-1023);
- snprintf(msg, bufsize, "-1023 yielded `%s` instead of `-1023`", res);
- mt_assert(strcmp(
- res,
- "-1023"
- ) == 0, msg);
- free(res);
-
- res = int_floored_with_binary_prefix(-1026);
- snprintf(msg, bufsize, "-1026 yielded `%s` instead of `-2 Ki`", res);
- mt_assert(strcmp(
- res,
- "-2 Ki"
- ) == 0, msg);
- free(res);
-
- res = int_floored_with_binary_prefix(1049088);
- snprintf(msg, bufsize, "1049088 yielded `%s` instead of `1 Mi`", res);
- mt_assert(strcmp(
- res,
- "1 Mi"
- ) == 0, msg);
- free(res);
-
- res = int_floored_with_binary_prefix(5243392);
- snprintf(msg, bufsize, "5243392 yielded `%s` instead of `5 Mi`", res);
- mt_assert(strcmp(
- res,
- "5 Mi"
- ) == 0, msg);
- free(res);
-
- free(msg);
+ mt_assert_eq(int_max(4, 1), 4);
+ mt_assert_eq(int_max(10, 10), 10);
return 0;
}
@@ -440,8 +97,4 @@ void intmath_tests() {
mt_run_test(test_ceil);
mt_run_test(test_min);
mt_run_test(test_max);
- mt_run_test(test_floored_exponent_notation);
- mt_run_test(test_ceiled_exponent_notation);
- mt_run_test(test_exponent_notated_to_int);
- mt_run_test(test_floored_with_binary_prefix);
}
diff --git a/intmath.h b/intmath.h
index b71334c..810c221 100644
--- a/intmath.h
+++ b/intmath.h
@@ -1,33 +1,6 @@
-
-#ifndef INTMATH_IS_IMPORTED
-#define INTMATH_IS_IMPORTED
-
-struct exp_val {
- int mantissa;
- int exponent;
- int base;
-};
-typedef struct exp_val exp_notated;
-
+int int_pown(unsigned int base, unsigned int exp);
int int_pow10(unsigned int exp);
int int_floor(int x, int precision);
int int_ceil(int x, int precision);
int int_max(int a, int b);
int int_min(int a, int b);
-exp_notated int_floored_exponent_notation_base(
- int x,
- unsigned int precision,
- unsigned int base
-);
-exp_notated int_ceiled_exponent_notation_base(
- int x,
- unsigned int precision,
- unsigned int base
-);
-exp_notated int_floored_exponent_notation(int x, unsigned int precision);
-exp_notated int_ceiled_exponent_notation(int x, unsigned int precision);
-int exp_notated_to_int(exp_notated x);
-const char* binary_prefix(exp_notated x);
-char* int_floored_with_binary_prefix(int x);
-
-#endif
diff --git a/minitest.h b/minitest.h
index c566e48..cc2d5c5 100644
--- a/minitest.h
+++ b/minitest.h
@@ -9,7 +9,6 @@
#define mt_assert_eq(left, right) do { \
if (left != right) \
return "`" #left "` didn't match `" #right "`"; \
- return 0; \
} while (0)
#define mt_run_test(test) do { \
char *message = test(); \
diff --git a/stdu.c b/stdu.c
index f7f5511..f2273f7 100644
--- a/stdu.c
+++ b/stdu.c
@@ -6,6 +6,7 @@
#include <stdbool.h>
#include "intmath.h"
+#include "formatting.h"
#include "config-parser.h"
int tests_run = 0;
@@ -24,7 +25,6 @@ int main (int argc, char* argv[]) {
}
Config* conf = (Config*) res.result;
- if (conf->human_readable) printf("human readable\n");
unsigned int base = 10;
if (conf->human_readable && conf->precision == 0) {
@@ -48,10 +48,52 @@ int main (int argc, char* argv[]) {
char* buf = malloc(bufsize);
char* tmpbuf;
+ size_t stdout_buffer_size = 16;
+ char* stdout_buffer = malloc(stdout_buffer_size);
+ int previous_line_strlen = 0;
+
while (1) {
/* output */
- printf("\r%u", bytes_read);
- if (fflush(stdin) == EOF) {
+ if (conf->human_readable && base == 10) {
+ int res = int_floored_with_prefix(
+ &stdout_buffer,
+ &stdout_buffer_size,
+ bytes_read,
+ conf->precision
+ );
+ if (res < 0) {
+ printf("\r%u \
+ (error when getting prefix)",
+ bytes_read);
+ continue;
+ }
+ printf(
+ "\r%*sB",
+ previous_line_strlen,
+ stdout_buffer
+ );
+ previous_line_strlen
+ = int_max(res, previous_line_strlen);
+ } else if (conf->human_readable && base == 1024) {
+ int success = int_floored_with_binary_prefix(
+ &stdout_buffer,
+ &stdout_buffer_size,
+ bytes_read
+ );
+ if (success < 0) {
+ printf("\r%u \
+ (error when getting prefix)",
+ bytes_read);
+ }
+ printf(
+ "\r%*sB",
+ 4 + (bytes_read > 1024),
+ stdout_buffer
+ );
+ } else {
+ printf("\r%u", bytes_read);
+ }
+ if (fflush(stdout) == EOF) {
printf("\n");
perror("error during fflush");
return 1;
@@ -96,6 +138,7 @@ int main (int argc, char* argv[]) {
}
}
printf("\n");
+ free(stdout_buffer);
return 0;
}
diff --git a/tests.c b/tests.c
index f4a047d..24db2fc 100644
--- a/tests.c
+++ b/tests.c
@@ -2,17 +2,15 @@
#include "minitest.h"
#include "config-parser.c"
#include "intmath.c"
+#include "formatting.c"
int tests_run = 0;
int tests_failed = 0;
-void intmath_tests();
-void main_tests();
-
int main() {
printf("[INFO] Running tests...\n\n");
- printf("[INFO] Running main-tests...\n");
+ printf("[INFO] Running parsing-tests...\n");
parsing_tests();
printf("\n");
@@ -20,6 +18,10 @@ int main() {
intmath_tests();
printf("\n");
+ printf("[INFO] Running formatting-tests...\n");
+ formatting_tests();
+ printf("\n");
+
mt_test_report();
return tests_failed != 0;