From f975594e55bdc05ee436bc7bdcd6e09aec5357b1 Mon Sep 17 00:00:00 2001 From: Joel Kronqvist Date: Sun, 7 Apr 2024 10:53:40 +0300 Subject: Finished implementation for formatting for human readability --- .gitignore | 2 +- Makefile | 24 ++- config-parser.c | 26 +-- formatting.c | 593 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ formatting.h | 30 +++ formatting.o | Bin 0 -> 27848 bytes intmath.c | 353 +-------------------------------- intmath.h | 29 +-- minitest.h | 1 - stdu.c | 49 ++++- tests.c | 10 +- 11 files changed, 702 insertions(+), 415 deletions(-) create mode 100644 formatting.c create mode 100644 formatting.h create mode 100644 formatting.o 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 +#include +#include + +#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 Binary files /dev/null and b/formatting.o 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 #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; -- cgit v1.2.3