From ba5dd828bde07493ef5f2f8abf6921e0a040133d Mon Sep 17 00:00:00 2001 From: Joel Kronqvist Date: Sat, 13 Apr 2024 21:48:07 +0300 Subject: Combined one-letter options support (eg. "-mhp 3") --- config-parser.c | 164 ++++++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 118 insertions(+), 46 deletions(-) (limited to 'config-parser.c') diff --git a/config-parser.c b/config-parser.c index 3cebc73..0ef0a47 100644 --- a/config-parser.c +++ b/config-parser.c @@ -22,27 +22,13 @@ Result parse_config(int argc, char* argv[]) { size_t i = 1; char* argument; char* precision = NULL; + bool next_is_precision = false; while (i < argc) { argument = argv[i]; - int comp1 = strcmp(argument, "--precision") == 0; - if ( - strcmp(argument, "--help") == 0 - || strcmp(argument, "-?") == 0 - ) { - tmp.help = true; - } else if ( - strcmp(argument, "--human-readable") == 0 - || strcmp(argument, "-h") == 0 - ) { - tmp.human_readable = true; - } else if ( - strcmp(argument, "--multiline") == 0 - || strcmp(argument, "-m") == 0 - ) { - tmp.multiline = true; - } else if ( - comp1 || strncmp(argument, "-p", 2) == 0 - ) { + size_t arglen = strlen(argument); + + if (next_is_precision) { + i += 1; if (precision != NULL) { char* error_msg = malloc(44); snprintf( @@ -53,11 +39,6 @@ Result parse_config(int argc, char* argv[]) { 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( @@ -69,21 +50,98 @@ Result parse_config(int argc, char* argv[]) { res.result = error_msg; return res; } - precision = argv[i]; - } 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; + precision = argv[i++]; + next_is_precision = false; + continue; + } + + size_t tacktacklen = 2; + if (strncmp(argument, "--", tacktacklen) == 0) { + argument += tacktacklen; + if (strcmp(argument, "help") == 0) { + tmp.help = true; + } else if (strcmp(argument, "human-readable") == 0) { + tmp.human_readable = true; + } else if (strcmp(argument, "multiline") == 0) { + tmp.multiline = true; + } else if (strcmp(argument, "precision") == 0) { + next_is_precision = true; + continue; + } else { + argument -= tacktacklen; + size_t msg_size = 18 + strlen(argument); + char* error_msg = malloc(msg_size); + snprintf( + error_msg, + msg_size, + "unknown option `%s`", + argument + ); + res.result = error_msg; + return res; + } + i++; + continue; + } + + if (strncmp(argument, "-p", 2) == 0 && arglen != 2) { + 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; + } + precision = argument + 2; + i++; + continue; } - i++; + size_t opt_i = 0; + while (++opt_i < arglen) { + char opt = *(argument + opt_i); + switch (opt) { + case 'h': + tmp.human_readable = true; + break; + case 'm': + tmp.multiline = true; + break; + case 'p': + next_is_precision = true; + if (opt_i != arglen - 1) { + size_t msg_size = 75; + char* error_msg + = malloc(msg_size); + snprintf( + error_msg, + msg_size, + "`-p` should be the last option when combined with other one-letter options" + ); + res.result = error_msg; + return res; + } + break; + case '?': + tmp.help = true; + break; + default: + size_t msg_size = 20; + char* error_msg = malloc(msg_size); + snprintf( + error_msg, + msg_size, + "unknown option `-%c`", + opt + ); + res.result = error_msg; + return res; + } + } + i += !next_is_precision; } if (precision != NULL) { @@ -143,8 +201,10 @@ char* test_default_config() { 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); + mt_assert_eq(conf->help, false); + mt_assert_eq(conf->multiline, false); + mt_assert_eq(conf->precision, 0); free(conf); return 0; } @@ -196,17 +256,28 @@ char* test_human_readability_parsing() { 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* argv2[] = { "stdu", "-h", "-h" }; - res = parse_config(argc, argv2); - error_msg = (char*) res.result; - mt_assert_eq(res.success, false); - free(error_msg); - + return 0; +} + +char* test_multioption_parsing() { + Result res; + Config* conf; + char* error_msg; + + int argc = 3; + char* argv[] = { "stdu", "-mh?p", "3"}; + res = parse_config(argc, argv); + conf = (Config*) res.result; + mt_assert_eq(res.success, true); + mt_assert_eq(conf->help, true); + mt_assert_eq(conf->human_readable, true); + mt_assert_eq(conf->multiline, true); + mt_assert_eq(conf->precision, 3); + free(conf); + return 0; } @@ -214,4 +285,5 @@ void parsing_tests() { mt_run_test(test_default_config); mt_run_test(test_precision_parsing); mt_run_test(test_human_readability_parsing); + mt_run_test(test_multioption_parsing); } -- cgit v1.2.3