From dd757a651292048da829dd6fa085c1f107569bcc Mon Sep 17 00:00:00 2001 From: Philippe Proulx Date: Tue, 1 Jun 2021 11:42:56 -0400 Subject: [PATCH 1/1] Parse `-` and `--` as non-option arguments The `-` and `--` arguments are common in many Unix command-line tools. `--` often means "end of options" while `-` often means "read from standard input". Depending on the application, they can have different meanings. This patch makes argpar_iter_next() specifically parse `-` and `--` arguments as non-options. Signed-off-by: Philippe Proulx Change-Id: I3b3f1670863992a17a7edfabdc48c921f71cd4b6 --- argpar/argpar.c | 17 ++++--------- argpar/argpar.h | 7 ++---- tests/test_argpar.c | 61 +++++++++++++++++++++------------------------ 3 files changed, 35 insertions(+), 50 deletions(-) diff --git a/argpar/argpar.c b/argpar/argpar.c index f324d7f..58cbc2b 100644 --- a/argpar/argpar.c +++ b/argpar/argpar.c @@ -418,11 +418,7 @@ enum parse_orig_arg_opt_ret parse_short_opts(const char * const short_opts, const struct argpar_opt_descr *descr; struct argpar_item_opt *opt_item; - if (strlen(short_opts) == 0) { - try_append_string_printf(error, "Invalid argument"); - ret = PARSE_ORIG_ARG_OPT_RET_ERROR_INVALID_ARG; - goto error; - } + ARGPAR_ASSERT(strlen(short_opts) != 0); if (!iter->short_opt_ch) { iter->short_opt_ch = short_opts; @@ -517,11 +513,7 @@ enum parse_orig_arg_opt_ret parse_long_opt(const char * const long_opt_arg, /* Option name */ const char *long_opt_name = long_opt_arg; - if (strlen(long_opt_arg) == 0) { - try_append_string_printf(error, "Invalid argument"); - ret = PARSE_ORIG_ARG_OPT_RET_ERROR_INVALID_ARG; - goto error; - } + ARGPAR_ASSERT(strlen(long_opt_arg) != 0); /* Find the first `=` in original argument */ eq_pos = strchr(long_opt_arg, '='); @@ -703,9 +695,10 @@ enum argpar_iter_next_status argpar_iter_next( next_orig_arg = iter->i < (iter->argc - 1) ? iter->argv[iter->i + 1] : NULL; - if (orig_arg[0] != '-') { + if (strcmp(orig_arg, "-") == 0 || strcmp(orig_arg, "--") == 0 || + orig_arg[0] != '-') { /* Non-option argument */ - struct argpar_item_non_opt * const non_opt_item = + const struct argpar_item_non_opt * const non_opt_item = create_non_opt_item(orig_arg, iter->i, iter->non_opt_index); diff --git a/argpar/argpar.h b/argpar/argpar.h index 453f533..be71513 100644 --- a/argpar/argpar.h +++ b/argpar/argpar.h @@ -67,10 +67,7 @@ * * * Non-option arguments (anything else). * - * The argpar parsers don't accept `-` or `--` as arguments. The latter - * means "end of options" for many command-line tools, but this library - * is all about keeping the order of the arguments, so it doesn't mean - * much to put them at the end. This has the side effect that a + * The argpar parsers parse `-` and `--` as non-option arguments. A * non-option argument cannot have the form of an option, for example if * you need to pass the exact relative path `--component`. In that case, * you would need to pass `./--component`. There's no generic way to @@ -128,7 +125,7 @@ struct argpar_opt_descr { /* Short option character, or `\0` */ const char short_name; - /* Long option name (without `--`), or `NULL` */ + /* Long option name (without the `--` prefix), or `NULL` */ const char * const long_name; /* True if this option has an argument */ diff --git a/tests/test_argpar.c b/tests/test_argpar.c index 4882d45..c78b6e8 100644 --- a/tests/test_argpar.c +++ b/tests/test_argpar.c @@ -624,6 +624,32 @@ void succeed_tests(void) "-f --yeah= -f", descrs, 3); } + + /* `-` non-option argument */ + { + const struct argpar_opt_descr descrs[] = { + { 0, 'f', NULL, false }, + ARGPAR_OPT_DESCR_SENTINEL + }; + + test_succeed( + "-f - -f", + "-f -<1,0> -f", + descrs, 3); + } + + /* `--` non-option argument */ + { + const struct argpar_opt_descr descrs[] = { + { 0, 'f', NULL, false }, + ARGPAR_OPT_DESCR_SENTINEL + }; + + test_succeed( + "-f -- -f", + "-f --<1,0> -f", + descrs, 3); + } } /* @@ -837,38 +863,7 @@ void fail_tests(void) descrs); } - /* Invalid `-` */ - { - const struct argpar_opt_descr descrs[] = { - { 0, 'a', NULL, false }, - { 0, 'b', NULL, false }, - { 0, 'c', NULL, true }, - ARGPAR_OPT_DESCR_SENTINEL - }; - - test_fail( - "-ab - -c", - "While parsing argument #2 (`-`): Invalid argument", - ARGPAR_ITER_NEXT_STATUS_ERROR_INVALID_ARG, - descrs); - } - - /* Invalid `--` */ - { - const struct argpar_opt_descr descrs[] = { - { 0, 'a', NULL, false }, - { 0, 'b', NULL, false }, - { 0, 'c', NULL, true }, - ARGPAR_OPT_DESCR_SENTINEL - }; - - test_fail( - "-ab -- -c", - "While parsing argument #2 (`--`): Invalid argument", - ARGPAR_ITER_NEXT_STATUS_ERROR_INVALID_ARG, - descrs); - } - + /* Unexpected long option argument */ { const struct argpar_opt_descr descrs[] = { { 0, 'c', "chevre", false }, @@ -885,7 +880,7 @@ void fail_tests(void) int main(void) { - plan_tests(419); + plan_tests(423); succeed_tests(); fail_tests(); return exit_status(); -- 2.34.1