aboutsummaryrefslogtreecommitdiff
path: root/config-parser.c
diff options
context:
space:
mode:
Diffstat (limited to 'config-parser.c')
-rw-r--r--config-parser.c226
1 files changed, 226 insertions, 0 deletions
diff --git a/config-parser.c b/config-parser.c
new file mode 100644
index 0000000..cd97dc7
--- /dev/null
+++ b/config-parser.c
@@ -0,0 +1,226 @@
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <stdbool.h>
+
+#include "minitest.h"
+#include "config-parser.h"
+
+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;
+}
+
+char* test_default_config() {
+ int argc = 1;
+ char* argv[] = { "stdu" };
+ Result res = parse_config(argc, argv);
+ Config* conf = (Config*) res.result;
+ mt_assert_eq(res.success, true);
+ mt_assert_eq(conf->precision, 0);
+ mt_assert_eq(conf->human_readable, false);
+ return 0;
+}
+
+char* test_precision_parsing() {
+ int argc;
+ Result res;
+ Config* conf;
+ char* error_msg;
+
+ argc = 3;
+ char* argv[] = { "stdu", "--precision", "3" };
+ res = parse_config(argc, argv);
+ conf = (Config*) res.result;
+ mt_assert_eq(res.success, true);
+ mt_assert_eq(conf->precision, 3);
+ mt_assert_eq(conf->human_readable, false);
+ free(conf);
+
+ argc = 2;
+ char* argv2[] = { "stdu", "-p" };
+ res = parse_config(argc, argv2);
+ mt_assert(
+ res.success == false,
+ "not specifying precision after `-p` didn't error"
+ );
+ free(error_msg);
+
+ argc = 4;
+ char* argv3[] = { "stdu", "--precision", "1", "-p3" };
+ res = parse_config(argc, argv3);
+ mt_assert(
+ res.success == false,
+ "specifying precision multiple times didn't error"
+ );
+ free(res.result);
+
+ return 0;
+
+}
+
+char* test_human_readability_parsing() {
+ int argc;
+ Result res;
+ Config* conf;
+ char* error_msg;
+
+ argc = 2;
+ char* argv[] = {
+ "stdu",
+ "--human-readable"
+ };
+ res = parse_config(argc, argv);
+ conf = (Config*) res.result;
+ mt_assert_eq(res.success, true);
+ mt_assert_eq(conf->precision, 0);
+ mt_assert_eq(conf->human_readable, true);
+ free(conf);
+
+ argc = 3;
+ char* argv3[] = {
+ "stdu",
+ "-h",
+ "-h"
+ };
+ res = parse_config(argc, argv3);
+ 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;
+}
+
+void parsing_tests() {
+ mt_run_test(test_default_config);
+ mt_run_test(test_precision_parsing);
+ mt_run_test(test_human_readability_parsing);
+}