aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoel Kronqvist <joelkronqvist@proton.me>2024-03-23 17:56:49 +0200
committerJoel Kronqvist <joelkronqvist@proton.me>2024-03-23 18:00:51 +0200
commite26279107edf7012e6b9cd558aaa09a8f0ca4764 (patch)
tree2bcd2eb3c6c2ade2e85c9f52ca1fc41d3c720811
downloadstdu-e26279107edf7012e6b9cd558aaa09a8f0ca4764.tar.gz
stdu-e26279107edf7012e6b9cd558aaa09a8f0ca4764.zip
Initial commit
-rw-r--r--.gitignore4
-rw-r--r--Makefile16
-rw-r--r--intmath.c447
-rw-r--r--intmath.h33
-rw-r--r--minitest.h31
-rw-r--r--stdu.c237
-rw-r--r--tests.c18
7 files changed, 786 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..26e8cf8
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,4 @@
+stdu
+stdu.o
+intmath.o
+test
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..685f42a
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,16 @@
+
+stdu : stdu.o intmath.o intmath.h
+ cc -o stdu stdu.o intmath.o
+
+stdu.o : stdu.c
+ cc -c stdu.c
+
+intmath.o : intmath.c minitest.h intmath.h
+ cc -c intmath.c
+
+test : tests.c minitest.h intmath.c
+ cc -o test tests.c
+ ./test
+
+clean :
+ rm stdu stdu.o intmath.o test
diff --git a/intmath.c b/intmath.c
new file mode 100644
index 0000000..cba66a9
--- /dev/null
+++ b/intmath.c
@@ -0,0 +1,447 @@
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "minitest.h"
+#include "intmath.h"
+
+int int_pown(unsigned int base, unsigned int exp) {
+ int res = 1;
+ while (exp > 0) {
+ res *= base;
+ exp--;
+ }
+ return res;
+}
+
+int int_pow10(unsigned int exp) {
+ return int_pown(10, exp);
+}
+
+int int_floor(int x, int precision) {
+ int sign = (x < 0) * -2 + 1;
+ x *= sign;
+
+ int iterations = 0;
+ while (x > int_pow10(precision)) {
+ x /= 10;
+ iterations++;
+ }
+
+ return (x + (sign == -1))
+ * int_pow10(iterations)
+ * sign;
+}
+
+int int_ceil(int x, int precision) {
+ return -int_floor(-x, precision);
+}
+
+int int_min(int a, int b) {
+ return (a < b) * a + (b <= a) * b;
+}
+
+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);
+ mt_assert_eq(int_pown(9, 0), 1);
+ return 0;
+}
+
+char* test_pow10() {
+ mt_assert_eq(int_pow10(3), 1000);
+ mt_assert_eq(int_pow10(0), 1);
+ return 0;
+}
+
+char* test_floor() {
+ mt_assert_eq(int_floor(34128, 2), 34000);
+ mt_assert_eq(int_floor(-34128, 3), -34200);
+ mt_assert_eq(int_floor(-9999, 3), -10000);
+ mt_assert_eq(int_floor(9999, 3), 9990);
+ mt_assert_eq(int_floor(0, 1), 0);
+ return 0;
+}
+
+char* test_ceil() {
+ mt_assert_eq(int_ceil(44212, 3), 44300);
+ mt_assert_eq(int_ceil(-44212, 3), -44200);
+ mt_assert_eq(int_ceil(-9999, 3), -9990);
+ mt_assert_eq(int_ceil(9999, 3), 10000);
+ mt_assert_eq(int_ceil(0, 1), 0);
+ return 0;
+}
+
+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);
+ 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);
+ return 0;
+}
+
+void intmath_tests() {
+ mt_run_test(test_pown);
+ mt_run_test(test_pow10);
+ mt_run_test(test_floor);
+ 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
new file mode 100644
index 0000000..b71334c
--- /dev/null
+++ b/intmath.h
@@ -0,0 +1,33 @@
+
+#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_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
new file mode 100644
index 0000000..c566e48
--- /dev/null
+++ b/minitest.h
@@ -0,0 +1,31 @@
+
+/// Minimal testing library tweaked with
+/// reference from `minunit.h` from
+/// Jera Design LLC:
+/// https://jera.com/techinfo/jtns/jtn002
+
+#include <stdio.h>
+#define mt_assert(test, message) do { if (!(test)) return message; } while (0)
+#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(); \
+ if (message) { \
+ fprintf(stderr, "[FAIL] " #test ": %s\n", message); \
+ tests_failed++; \
+ } else { \
+ fprintf(stderr, "[PASS] " #test "\n"); \
+ } \
+ tests_run++; \
+} while (0)
+#define mt_test_report() do { \
+ if (tests_failed == 0) \
+ fprintf(stderr, "[REPORT] All %d tests passed.\n", tests_run); \
+ else \
+ fprintf(stderr, "[REPORT] Failure. %d/%d tests failed.\n", tests_failed, tests_run); \
+} while (0)
+extern int tests_run;
+extern int tests_failed;
diff --git a/stdu.c b/stdu.c
new file mode 100644
index 0000000..43038a8
--- /dev/null
+++ b/stdu.c
@@ -0,0 +1,237 @@
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <stdbool.h>
+
+#include "intmath.h"
+
+int tests_run = 0;
+int tests_failed = 0;
+
+struct Config {
+ int precision;
+ bool human_readable;
+};
+typedef struct Config Config;
+struct Result {
+ bool success;
+ void* result;
+};
+typedef struct Result Result;
+
+Result parse_config(int argc, char* argv[]) {
+ Result res;
+ res.success = false;
+ Config tmp;
+ tmp.precision = 0;
+ tmp.human_readable = false;
+
+ size_t i = 1;
+ char* argument;
+ char* precision = NULL;
+ while (i < argc) {
+ argument = argv[i];
+ int comp1 = strcmp(argument, "--precision") == 0;
+ if (
+ comp1 || strncmp(argument, "-p", 2) == 0
+ ) {
+ if (precision != NULL) {
+ char* error_msg = malloc(44);
+ snprintf(
+ error_msg,
+ 44,
+ "precision can't be specified multiple times"
+ );
+ res.result = error_msg;
+ return res;
+ }
+ i++;
+ if (strlen(argument) != 2 && !comp1) {
+ precision = argument + 2;
+ continue;
+ }
+ if (i == argc) {
+ char* error_msg = malloc(57);
+ snprintf(
+ error_msg,
+ 57,
+ "`%s` should be followed by an integer argument",
+ argument
+ );
+ res.result = error_msg;
+ return res;
+ }
+ precision = argv[i];
+ } else if (
+ strcmp(argument, "--human-readable") == 0
+ || strcmp(argument, "-h") == 0
+ ) {
+ if (tmp.human_readable != false) {
+ char* error_msg = malloc(52);
+ snprintf(
+ error_msg,
+ 52,
+ "human readability can't be specified multiple times"
+ );
+ res.result = error_msg;
+ return res;
+ }
+ tmp.human_readable = true;
+ } else {
+ size_t msg_size = 21 + strlen(argument);
+ char* error_msg = malloc(msg_size);
+ snprintf(
+ error_msg,
+ msg_size,
+ "unknown argument: `%s`",
+ argument
+ );
+ res.result = error_msg;
+ return res;
+ }
+
+ i++;
+ }
+
+ if (precision != NULL) {
+ char* endptr;
+ errno = 0;
+ tmp.precision = (int) strtol(precision, &endptr, 10);
+ if (errno != 0) {
+ char* error_msg = malloc(64);
+ char* errno_str = strerror(errno);
+ snprintf(
+ error_msg,
+ 64,
+ "invalid precision: %s",
+ errno_str
+ );
+ free(errno_str);
+ res.result = error_msg;
+ return res;
+ }
+ if (*endptr != '\0') {
+ char* error_msg = malloc(53);
+ snprintf(
+ error_msg,
+ 53,
+ "the precision may not contain non-numeric characters",
+ precision
+ );
+ res.result = error_msg;
+ return res;
+ }
+ if (tmp.precision <= 0) {
+ char* error_msg = malloc(50);
+ snprintf(
+ error_msg,
+ 50,
+ "the precision can't be less than or equal to zero"
+ );
+ res.result = error_msg;
+ return res;
+ }
+ }
+
+ Config* conf = malloc(sizeof(int) + sizeof(bool));
+ conf->precision = tmp.precision;
+ conf->human_readable = tmp.human_readable;
+
+ res.success = true;
+ res.result = conf;
+ return res;
+}
+
+int main (int argc, char* argv[]) {
+ Result res = parse_config(argc, argv);
+ if (res.success == false) {
+ char* err_msg = (char*) res.result;
+ fprintf(
+ stderr,
+ "Error parsing command line: %s\n",
+ err_msg
+ );
+ return 1;
+ }
+
+ Config* conf = (Config*) res.result;
+ int precision = conf->precision;
+ bool human_readable = conf->human_readable;
+ printf("precision: %d\n", precision);
+ if (human_readable) printf("human readable\n");
+
+ unsigned int base = 10;
+ if (human_readable && precision == 0) {
+ precision = 1;
+ base = 1024;
+ }
+
+ int blocksize = 1;
+ size_t bufsize = 1;
+ unsigned int bytes_read = 0;
+ size_t new_read_bytes = 0;
+ if (precision != 0) {
+ blocksize = exp_notated_to_int(int_ceiled_exponent_notation_base(
+ bytes_read + 1,
+ precision,
+ base))
+ - bytes_read;
+ bufsize = 1024;
+ }
+ size_t max_bufsize = 1048576;
+ char* buf = malloc(bufsize);
+ char* tmpbuf;
+
+ while (1) {
+ /* output */
+ printf("\r%u", bytes_read);
+ if (fflush(stdin) == EOF) {
+ printf("\n");
+ perror("error during fflush");
+ return 1;
+ }
+
+ /* reading */
+ new_read_bytes = fread(
+ buf,
+ 1,
+ int_min(blocksize, bufsize)/* + (blocksize == 0)*/,
+ stdin
+ );
+ if (new_read_bytes == 0) {
+ int err = ferror(stdin);
+ if (err != 0) {
+ printf("\n");
+ fprintf(stderr, "error reading stdin");
+ return err;
+ }
+ break;
+ }
+ bytes_read += new_read_bytes;
+
+ /* resizing buffer and blocksize to read as much as possible
+ * at once
+ */
+ if (precision == 0) continue;
+ blocksize = exp_notated_to_int(int_ceiled_exponent_notation_base(
+ bytes_read + 1,
+ precision,
+ base))
+ - bytes_read;
+ if (blocksize > bufsize) {
+ tmpbuf = malloc(bufsize * 2);
+ if (tmpbuf == NULL) {
+ free(tmpbuf);
+ } else {
+ free(buf);
+ buf = tmpbuf;
+ bufsize *= 2;
+ }
+ }
+ }
+ printf("\n");
+
+ return 0;
+}
diff --git a/tests.c b/tests.c
new file mode 100644
index 0000000..138a994
--- /dev/null
+++ b/tests.c
@@ -0,0 +1,18 @@
+
+#include "minitest.h"
+#include "intmath.c"
+
+int tests_run = 0;
+int tests_failed = 0;
+
+int main() {
+ printf("[INFO] Running tests...\n\n");
+
+ printf("[INFO] Running intmath-tests...\n");
+ intmath_tests();
+ printf("\n");
+
+ mt_test_report();
+
+ return tests_failed != 0;
+}