diff options
author | Joel Kronqvist <joelkronqvist@proton.me> | 2024-04-13 21:48:07 +0300 |
---|---|---|
committer | Joel Kronqvist <joelkronqvist@proton.me> | 2024-04-13 21:51:01 +0300 |
commit | ba5dd828bde07493ef5f2f8abf6921e0a040133d (patch) | |
tree | 3032f7429482f27afb015f9ab4605df0a4f3d460 | |
parent | f8f07ca39bd617ddaeb2149f138b12aa7a6532bf (diff) | |
download | stdu-ba5dd828bde07493ef5f2f8abf6921e0a040133d.tar.gz stdu-ba5dd828bde07493ef5f2f8abf6921e0a040133d.zip |
Combined one-letter options support (eg. "-mhp 3")
-rw-r--r-- | config-parser.c | 164 | ||||
-rw-r--r-- | stdu.c | 4 |
2 files changed, 120 insertions, 48 deletions
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); } @@ -19,7 +19,7 @@ int main (int argc, char* argv[]) { char* err_msg = (char*) res.result; fprintf( stderr, - "Error parsing command line: %s\n", + "Error parsing command line: %s.\nTry `stdu --help` for more info.\n", err_msg ); return 1; @@ -34,7 +34,7 @@ Print amount of data piped to stdin.\n\ --help | -?: print this help message\n\ --human-readable | -h: output in a human readable format\n\ --multiline | -m: output with line breaks\n\ ---precision n | -p n | -pn: output with n significant digits\n " +--precision n | -p n | -pn: output with n significant digits\n" ); return 0; } |