Parse `-` and `--` as non-option arguments
authorPhilippe Proulx <eeppeliteloop@gmail.com>
Tue, 1 Jun 2021 15:42:56 +0000 (11:42 -0400)
committerPhilippe Proulx <eeppeliteloop@gmail.com>
Fri, 4 Jun 2021 17:59:12 +0000 (13:59 -0400)
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 <eeppeliteloop@gmail.com>
Change-Id: I3b3f1670863992a17a7edfabdc48c921f71cd4b6

argpar/argpar.c
argpar/argpar.h
tests/test_argpar.c

index f324d7fb130355a42ef07583cfcd520f09f2e324..58cbc2b9d917203be676d58e7259bb8518cf0529 100644 (file)
@@ -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;
 
        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;
 
        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;
 
        /* 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, '=');
 
        /* 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;
 
        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 */
                /* 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);
 
                        create_non_opt_item(orig_arg, iter->i,
                                iter->non_opt_index);
 
index 453f53385eec786140b425eae1f9d157b2cbeda1..be715131d5628c3018393a7d436b92ae2744e4e7 100644 (file)
  *
  * * Non-option arguments (anything else).
  *
  *
  * * 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
  * 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;
 
        /* 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 */
        const char * const long_name;
 
        /* True if this option has an argument */
index 4882d45c1c0bade6ca1ef0b0ac7ee9ac755f55b0..c78b6e8a6babb71c7b362ba62eb45932e84644fb 100644 (file)
@@ -624,6 +624,32 @@ void succeed_tests(void)
                        "-f --yeah= -f",
                        descrs, 3);
        }
                        "-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);
        }
 
                        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 },
        {
                const struct argpar_opt_descr descrs[] = {
                        { 0, 'c', "chevre", false },
@@ -885,7 +880,7 @@ void fail_tests(void)
 
 int main(void)
 {
 
 int main(void)
 {
-       plan_tests(419);
+       plan_tests(423);
        succeed_tests();
        fail_tests();
        return exit_status();
        succeed_tests();
        fail_tests();
        return exit_status();
This page took 0.025809 seconds and 4 git commands to generate.