[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: glibc getopt bugs
From: |
Eric Blake |
Subject: |
Re: glibc getopt bugs |
Date: |
Wed, 2 Dec 2009 22:53:01 +0000 (UTC) |
User-agent: |
Loom/3.14 (http://gmane.org/) |
Eric Blake <ebb9 <at> byu.net> writes:
>
> The carnage continues.
>
> http://sources.redhat.com/bugzilla/show_bug.cgi?id=11043
Here's a real-life example of glibc's getopt getting in the way of sane
behavior. Anyone opposed to me change gnulib to blindly replacing the broken
glibc getopt?
$ env -ua -:
env: invalid option -- :
Try `env --help' for more information.
$ env -:
env: invalid option -- :
Try `env --help' for more information.
$ env -+
env: invalid option -- +
Try `env --help' for more information.
$ env -ua -+
Try `env --help' for more information.
Ouch. If -+ is not the first option, the error message is omitted.
By the way, here's the tests I've been working on to expose all of these glibc
bugs; still a work in progress (I'd have to tweak m4/getopt.m4 and lib/getopt.c
in order to remove some of the commented out portions in the test
improvements). It also exposes some more corner case bugs in BSD; for example,
in glibc, getopt_long_only intentionally handles ambiguous options differently
than getopt_long, due to a usage pattern demanded by ld; but various BSD
implementations have not picked up on that subtle difference.
>From aabb0345c0e9f7e76ea74bd519046118ec8ff18c Mon Sep 17 00:00:00 2001
From: Eric Blake <address@hidden>
Date: Tue, 1 Dec 2009 17:21:34 -0700
Subject: [PATCH 1/2] test-getopt: enhance test
* tests/test-getopt.c (OPTIND_MIN): Move...
* tests/test-getopt.h (OPTIND_MIN): ...here.
* tests/test-getopt_long.h (test_getopt_long): Add more coverage.
Require that optind=0 works, since modern BSD supports it in
addition to optreset.
(test_getopt_long_only): New test.
* doc/glibc-functions/getopt_long.texi (getopt_long): Document
glibc shortcomings with 'W;'.
* doc/glibc-functions/getopt_long_only.texi (getopt_long_only):
Likewise.
---
ChangeLog | 14 +
doc/glibc-functions/getopt_long.texi | 4 +
doc/glibc-functions/getopt_long_only.texi | 4 +
tests/test-getopt.c | 13 +-
tests/test-getopt.h | 11 +
tests/test-getopt_long.h | 1119 ++++++++++++++++++++++++++++-
6 files changed, 1129 insertions(+), 36 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index 6eec830..a1d3f50 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,17 @@
+2009-12-02 Eric Blake <address@hidden>
+
+ test-getopt: enhance test
+ * tests/test-getopt.c (OPTIND_MIN): Move...
+ * tests/test-getopt.h (OPTIND_MIN): ...here.
+ * tests/test-getopt_long.h (test_getopt_long): Add more coverage.
+ Require that optind=0 works, since modern BSD supports it in
+ addition to optreset.
+ (test_getopt_long_only): New test.
+ * doc/glibc-functions/getopt_long.texi (getopt_long): Document
+ glibc shortcomings with 'W;'.
+ * doc/glibc-functions/getopt_long_only.texi (getopt_long_only):
+ Likewise.
+
2009-12-01 Jim Meyering <address@hidden>
fts: fts_open: do not let an empty string cause immediate failure
diff --git a/doc/glibc-functions/getopt_long.texi b/doc/glibc-
functions/getopt_long.texi
index c9843ea..275722b 100644
--- a/doc/glibc-functions/getopt_long.texi
+++ b/doc/glibc-functions/getopt_long.texi
@@ -31,4 +31,8 @@ getopt_long
@code{optind} to 0. Other implementations provide @code{optreset},
causing a reset by setting it non-zero, although it does not
necessarily re-read @env{POSIXLY_CORRECT}.
address@hidden
+The glibc extension of using an option string containing @samp{W;} to
+allow @code{-W foo} to behave synonymously with @code{--foo} is not
+very reliable.
@end itemize
diff --git a/doc/glibc-functions/getopt_long_only.texi b/doc/glibc-
functions/getopt_long_only.texi
index ed6cd7b..5ade129 100644
--- a/doc/glibc-functions/getopt_long_only.texi
+++ b/doc/glibc-functions/getopt_long_only.texi
@@ -32,4 +32,8 @@ getopt_long_only
@code{optind} to 0. Other implementations provide @code{optreset},
causing a reset by setting it non-zero, although it does not
necessarily re-read @env{POSIXLY_CORRECT}.
address@hidden
+The glibc extension of using an option string containing @samp{W;} to
+allow @code{-W foo} to behave synonymously with @code{--foo} is not
+very reliable.
@end itemize
diff --git a/tests/test-getopt.c b/tests/test-getopt.c
index cc87f32..5ef6974 100644
--- a/tests/test-getopt.c
+++ b/tests/test-getopt.c
@@ -39,14 +39,6 @@
} \
while (0)
-/* The glibc/gnulib implementation of getopt supports setting optind = 0,
- but other implementations don't. */
-#if defined __GETOPT_PREFIX || (__GLIBC__ >= 2)
-# define OPTIND_MIN 0
-#else
-# define OPTIND_MIN 1
-#endif
-
#include "test-getopt.h"
#if GNULIB_GETOPT_GNU
# include "test-getopt_long.h"
@@ -55,6 +47,10 @@
int
main (void)
{
+ /* These default values are required by POSIX. */
+ ASSERT (optind == 1);
+ ASSERT (opterr != 0);
+
setenv ("POSIXLY_CORRECT", "1", 1);
test_getopt ();
@@ -67,6 +63,7 @@ main (void)
#if GNULIB_GETOPT_GNU
test_getopt_long ();
+ test_getopt_long_only ();
#endif
return 0;
diff --git a/tests/test-getopt.h b/tests/test-getopt.h
index be47b53..3a3ee63 100644
--- a/tests/test-getopt.h
+++ b/tests/test-getopt.h
@@ -18,6 +18,17 @@
#include <stdbool.h>
+/* The glibc/gnulib implementation of getopt supports setting optind =
+ 0, but not all other implementations do. This matters for getopt.
+ But for getopt_long, we require GNU compatibility. */
+#if defined __GETOPT_PREFIX || (__GLIBC__ >= 2)
+# define OPTIND_MIN 0
+#elif HAVE_DECL_OPTRESET
+# define OPTIND_MIN (optreset = 1)
+#else
+# define OPTIND_MIN 1
+#endif
+
static void
getopt_loop (int argc, const char **argv,
const char *options,
diff --git a/tests/test-getopt_long.h b/tests/test-getopt_long.h
index 63cc5c7..7f629bc 100644
--- a/tests/test-getopt_long.h
+++ b/tests/test-getopt_long.h
@@ -18,13 +18,15 @@
static int a_seen;
static int b_seen;
+static int q_seen;
static const struct option long_options_required[] =
{
{ "alpha", no_argument, NULL, 'a' },
{ "beta", no_argument, &b_seen, 1 },
{ "prune", required_argument, NULL, 'p' },
- { "quetsche", required_argument, NULL, 'q' },
+ { "quetsche", required_argument, &q_seen, 1 },
+ { "xtremely", no_argument, NULL, 1003 },
{ "xtra", no_argument, NULL, 1001 },
{ "xtreme", no_argument, NULL, 1002 },
{ "xtremely", no_argument, NULL, 1003 },
@@ -36,7 +38,7 @@ static const struct option long_options_optional[] =
{ "alpha", no_argument, NULL, 'a' },
{ "beta", no_argument, &b_seen, 1 },
{ "prune", optional_argument, NULL, 'p' },
- { "quetsche", optional_argument, NULL, 'q' },
+ { "quetsche", optional_argument, &q_seen, 1 },
{ NULL, 0, NULL, 0 }
};
@@ -47,10 +49,11 @@ getopt_long_loop (int argc, const char **argv,
int *non_options_count, const char **non_options,
int *unrecognized)
{
- int option_index;
+ int option_index = -1;
int c;
opterr = 0;
+ q_seen = 0;
while ((c = getopt_long (argc, (char **) argv, options, long_options,
&option_index))
!= -1)
@@ -59,6 +62,8 @@ getopt_long_loop (int argc, const char **argv,
{
case 0:
/* An option with a non-NULL flag pointer was processed. */
+ if (q_seen)
+ *q_value = optarg;
break;
case 'a':
a_seen++;
@@ -77,6 +82,12 @@ getopt_long_loop (int argc, const char **argv,
ASSERT (options[0] == '-');
non_options[(*non_options_count)++] = optarg;
break;
+ case ':':
+ /* Must only happen with option ':' at the beginning. */
+ ASSERT (options[0] == ':'
+ || ((options[0] == '-' || options[0] == '+')
+ && options[1] == ':'));
+ /* fall through */
case '?':
*unrecognized = optopt;
break;
@@ -235,8 +246,76 @@ test_getopt_long (void)
ASSERT (c == 1003);
}
- /* Test processing of boolean options. */
- for (start = OPTIND_MIN; start <= 1; start++)
+ /* Check that -W handles unknown options. */
+ {
+ int argc = 0;
+ const char *argv[10];
+ int option_index;
+ int c;
+
+ argv[argc++] = "program";
+ argv[argc++] = "-W";
+ argv[argc] = NULL;
+ optind = 1;
+ opterr = 0;
+ c = do_getopt_long (argc, argv, "W;", long_options_required,
&option_index);
+ ASSERT (c == '?');
+ ASSERT (optopt == 'W');
+ }
+ {
+ int argc = 0;
+ const char *argv[10];
+ int option_index;
+ int c;
+
+ argv[argc++] = "program";
+ argv[argc++] = "-Wunknown";
+ argv[argc] = NULL;
+ optind = 1;
+ opterr = 0;
+ c = do_getopt_long (argc, argv, "W;", long_options_required,
&option_index);
+ /* glibc and BSD behave differently here, but for now, we allow
+ both behaviors since W support is not frequently used. */
+ if (c == '?')
+ {
+ ASSERT (optopt == 0);
+ ASSERT (optarg == NULL);
+ }
+ else
+ {
+ ASSERT (c == 'W');
+ ASSERT (strcmp (optarg, "unknown") == 0);
+ }
+ }
+ {
+ int argc = 0;
+ const char *argv[10];
+ int option_index;
+ int c;
+
+ argv[argc++] = "program";
+ argv[argc++] = "-W";
+ argv[argc++] = "unknown";
+ argv[argc] = NULL;
+ optind = 1;
+ opterr = 0;
+ c = do_getopt_long (argc, argv, "W;", long_options_required,
&option_index);
+ /* glibc and BSD behave differently here, but for now, we allow
+ both behaviors since W support is not frequently used. */
+ if (c == '?')
+ {
+ ASSERT (optopt == 0);
+ ASSERT (optarg == NULL);
+ }
+ else
+ {
+ ASSERT (c == 'W');
+ ASSERT (strcmp (optarg, "unknown") == 0);
+ }
+ }
+
+ /* Test processing of boolean short options. */
+ for (start = 0; start <= 1; start++)
{
const char *p_value = NULL;
const char *q_value = NULL;
@@ -265,7 +344,7 @@ test_getopt_long (void)
ASSERT (unrecognized == 0);
ASSERT (optind == 2);
}
- for (start = OPTIND_MIN; start <= 1; start++)
+ for (start = 0; start <= 1; start++)
{
const char *p_value = NULL;
const char *q_value = NULL;
@@ -295,7 +374,7 @@ test_getopt_long (void)
ASSERT (unrecognized == 0);
ASSERT (optind == 3);
}
- for (start = OPTIND_MIN; start <= 1; start++)
+ for (start = 0; start <= 1; start++)
{
const char *p_value = NULL;
const char *q_value = NULL;
@@ -324,7 +403,7 @@ test_getopt_long (void)
ASSERT (unrecognized == 0);
ASSERT (optind == 2);
}
- for (start = OPTIND_MIN; start <= 1; start++)
+ for (start = 0; start <= 1; start++)
{
const char *p_value = NULL;
const char *q_value = NULL;
@@ -355,8 +434,196 @@ test_getopt_long (void)
ASSERT (optind == 3);
}
- /* Test processing of options with arguments. */
- for (start = OPTIND_MIN; start <= 1; start++)
+ /* Test processing of boolean long options. */
+ for (start = 0; start <= 1; start++)
+ {
+ const char *p_value = NULL;
+ const char *q_value = NULL;
+ int non_options_count = 0;
+ const char *non_options[10];
+ int unrecognized = 0;
+ int argc = 0;
+ const char *argv[10];
+ a_seen = 0;
+ b_seen = 0;
+
+ argv[argc++] = "program";
+ argv[argc++] = "--alpha";
+ argv[argc++] = "foo";
+ argv[argc++] = "bar";
+ argv[argc] = NULL;
+ optind = start;
+ getopt_long_loop (argc, argv, "ab", long_options_required,
+ &p_value, &q_value,
+ &non_options_count, non_options, &unrecognized);
+ ASSERT (a_seen == 1);
+ ASSERT (b_seen == 0);
+ ASSERT (p_value == NULL);
+ ASSERT (q_value == NULL);
+ ASSERT (non_options_count == 0);
+ ASSERT (unrecognized == 0);
+ ASSERT (optind == 2);
+ }
+ for (start = 0; start <= 1; start++)
+ {
+ const char *p_value = NULL;
+ const char *q_value = NULL;
+ int non_options_count = 0;
+ const char *non_options[10];
+ int unrecognized = 0;
+ int argc = 0;
+ const char *argv[10];
+ a_seen = 0;
+ b_seen = 0;
+
+ argv[argc++] = "program";
+ argv[argc++] = "--beta";
+ argv[argc++] = "--alpha";
+ argv[argc++] = "foo";
+ argv[argc++] = "bar";
+ argv[argc] = NULL;
+ optind = start;
+ getopt_long_loop (argc, argv, "ab", long_options_required,
+ &p_value, &q_value,
+ &non_options_count, non_options, &unrecognized);
+ ASSERT (a_seen == 1);
+ ASSERT (b_seen == 1);
+ ASSERT (p_value == NULL);
+ ASSERT (q_value == NULL);
+ ASSERT (non_options_count == 0);
+ ASSERT (unrecognized == 0);
+ ASSERT (optind == 3);
+ }
+ for (start = 0; start <= 1; start++)
+ {
+ const char *p_value = NULL;
+ const char *q_value = NULL;
+ int non_options_count = 0;
+ const char *non_options[10];
+ int unrecognized = 0;
+ int argc = 0;
+ const char *argv[10];
+ a_seen = 0;
+ b_seen = 0;
+
+ argv[argc++] = "program";
+ argv[argc++] = "--alpha";
+ argv[argc++] = "--beta";
+ argv[argc++] = "--alpha";
+ argv[argc++] = "--beta";
+ argv[argc++] = "foo";
+ argv[argc++] = "bar";
+ argv[argc] = NULL;
+ optind = start;
+ getopt_long_loop (argc, argv, "ab", long_options_required,
+ &p_value, &q_value,
+ &non_options_count, non_options, &unrecognized);
+ ASSERT (a_seen == 2);
+ ASSERT (b_seen == 1);
+ ASSERT (p_value == NULL);
+ ASSERT (q_value == NULL);
+ ASSERT (non_options_count == 0);
+ ASSERT (unrecognized == 0);
+ ASSERT (optind == 5);
+ }
+
+ /* Test processing of boolean long options via -W. */
+ for (start = 0; start <= 1; start++)
+ {
+ const char *p_value = NULL;
+ const char *q_value = NULL;
+ int non_options_count = 0;
+ const char *non_options[10];
+ int unrecognized = 0;
+ int argc = 0;
+ const char *argv[10];
+ a_seen = 0;
+ b_seen = 0;
+
+ argv[argc++] = "program";
+ argv[argc++] = "-Walpha";
+ argv[argc++] = "foo";
+ argv[argc++] = "bar";
+ argv[argc] = NULL;
+ optind = start;
+ getopt_long_loop (argc, argv, "abW;", long_options_required,
+ &p_value, &q_value,
+ &non_options_count, non_options, &unrecognized);
+ ASSERT (a_seen == 1);
+ ASSERT (b_seen == 0);
+ ASSERT (p_value == NULL);
+ ASSERT (q_value == NULL);
+ ASSERT (non_options_count == 0);
+ ASSERT (unrecognized == 0);
+ ASSERT (optind == 2);
+ }
+ for (start = 0; start <= 1; start++)
+ {
+ const char *p_value = NULL;
+ const char *q_value = NULL;
+ int non_options_count = 0;
+ const char *non_options[10];
+ int unrecognized = 0;
+ int argc = 0;
+ const char *argv[10];
+ a_seen = 0;
+ b_seen = 0;
+
+ argv[argc++] = "program";
+ argv[argc++] = "-W";
+ argv[argc++] = "beta";
+ argv[argc++] = "-W";
+ argv[argc++] = "alpha";
+ argv[argc++] = "foo";
+ argv[argc++] = "bar";
+ argv[argc] = NULL;
+ optind = start;
+ getopt_long_loop (argc, argv, "aW;b", long_options_required,
+ &p_value, &q_value,
+ &non_options_count, non_options, &unrecognized);
+ ASSERT (a_seen == 1);
+ ASSERT (b_seen == 1);
+ ASSERT (p_value == NULL);
+ ASSERT (q_value == NULL);
+ ASSERT (non_options_count == 0);
+ ASSERT (unrecognized == 0);
+ ASSERT (optind == 5);
+ }
+ for (start = 0; start <= 1; start++)
+ {
+ const char *p_value = NULL;
+ const char *q_value = NULL;
+ int non_options_count = 0;
+ const char *non_options[10];
+ int unrecognized = 0;
+ int argc = 0;
+ const char *argv[10];
+ a_seen = 0;
+ b_seen = 0;
+
+ argv[argc++] = "program";
+ argv[argc++] = "-Walpha";
+ argv[argc++] = "-Wbeta";
+ argv[argc++] = "-Walpha";
+ argv[argc++] = "-Wbeta";
+ argv[argc++] = "foo";
+ argv[argc++] = "bar";
+ argv[argc] = NULL;
+ optind = start;
+ getopt_long_loop (argc, argv, "W;ab", long_options_required,
+ &p_value, &q_value,
+ &non_options_count, non_options, &unrecognized);
+ ASSERT (a_seen == 2);
+ ASSERT (b_seen == 1);
+ ASSERT (p_value == NULL);
+ ASSERT (q_value == NULL);
+ ASSERT (non_options_count == 0);
+ ASSERT (unrecognized == 0);
+ ASSERT (optind == 5);
+ }
+
+ /* Test processing of short options with arguments. */
+ for (start = 0; start <= 1; start++)
{
const char *p_value = NULL;
const char *q_value = NULL;
@@ -384,7 +651,7 @@ test_getopt_long (void)
ASSERT (unrecognized == 0);
ASSERT (optind == 2);
}
- for (start = OPTIND_MIN; start <= 1; start++)
+ for (start = 0; start <= 1; start++)
{
const char *p_value = NULL;
const char *q_value = NULL;
@@ -413,7 +680,7 @@ test_getopt_long (void)
ASSERT (unrecognized == 0);
ASSERT (optind == 3);
}
- for (start = OPTIND_MIN; start <= 1; start++)
+ for (start = 0; start <= 1; start++)
{
const char *p_value = NULL;
const char *q_value = NULL;
@@ -445,8 +712,190 @@ test_getopt_long (void)
ASSERT (optind == 5);
}
- /* Test processing of options with optional arguments. */
- for (start = OPTIND_MIN; start <= 1; start++)
+ /* Test processing of long options with arguments. */
+ for (start = 0; start <= 1; start++)
+ {
+ const char *p_value = NULL;
+ const char *q_value = NULL;
+ int non_options_count = 0;
+ const char *non_options[10];
+ int unrecognized = 0;
+ int argc = 0;
+ const char *argv[10];
+ a_seen = 0;
+ b_seen = 0;
+
+ argv[argc++] = "program";
+ argv[argc++] = "--p=foo";
+ argv[argc++] = "bar";
+ argv[argc] = NULL;
+ optind = start;
+ getopt_long_loop (argc, argv, "p:q:", long_options_required,
+ &p_value, &q_value,
+ &non_options_count, non_options, &unrecognized);
+ ASSERT (a_seen == 0);
+ ASSERT (b_seen == 0);
+ ASSERT (p_value != NULL && strcmp (p_value, "foo") == 0);
+ ASSERT (q_value == NULL);
+ ASSERT (non_options_count == 0);
+ ASSERT (unrecognized == 0);
+ ASSERT (optind == 2);
+ }
+ for (start = 0; start <= 1; start++)
+ {
+ const char *p_value = NULL;
+ const char *q_value = NULL;
+ int non_options_count = 0;
+ const char *non_options[10];
+ int unrecognized = 0;
+ int argc = 0;
+ const char *argv[10];
+ a_seen = 0;
+ b_seen = 0;
+
+ argv[argc++] = "program";
+ argv[argc++] = "--p";
+ argv[argc++] = "foo";
+ argv[argc++] = "bar";
+ argv[argc] = NULL;
+ optind = start;
+ getopt_long_loop (argc, argv, "p:q:", long_options_required,
+ &p_value, &q_value,
+ &non_options_count, non_options, &unrecognized);
+ ASSERT (a_seen == 0);
+ ASSERT (b_seen == 0);
+ ASSERT (p_value != NULL && strcmp (p_value, "foo") == 0);
+ ASSERT (q_value == NULL);
+ ASSERT (non_options_count == 0);
+ ASSERT (unrecognized == 0);
+ ASSERT (optind == 3);
+ }
+ for (start = 0; start <= 1; start++)
+ {
+ const char *p_value = NULL;
+ const char *q_value = NULL;
+ int non_options_count = 0;
+ const char *non_options[10];
+ int unrecognized = 0;
+ int argc = 0;
+ const char *argv[10];
+ a_seen = 0;
+ b_seen = 0;
+
+ argv[argc++] = "program";
+ argv[argc++] = "-ab";
+ argv[argc++] = "--q";
+ argv[argc++] = "baz";
+ argv[argc++] = "--p=foo";
+ argv[argc++] = "bar";
+ argv[argc] = NULL;
+ optind = start;
+ getopt_long_loop (argc, argv, "abp:q:", long_options_required,
+ &p_value, &q_value,
+ &non_options_count, non_options, &unrecognized);
+ ASSERT (a_seen == 1);
+ ASSERT (b_seen == 1);
+ ASSERT (p_value != NULL && strcmp (p_value, "foo") == 0);
+ ASSERT (q_value != NULL && strcmp (q_value, "baz") == 0);
+ ASSERT (non_options_count == 0);
+ ASSERT (unrecognized == 0);
+ ASSERT (optind == 5);
+ }
+
+ /* Test processing of long options with arguments via -W. */
+ for (start = 0; start <= 1; start++)
+ {
+ const char *p_value = NULL;
+ const char *q_value = NULL;
+ int non_options_count = 0;
+ const char *non_options[10];
+ int unrecognized = 0;
+ int argc = 0;
+ const char *argv[10];
+ a_seen = 0;
+ b_seen = 0;
+
+ argv[argc++] = "program";
+ argv[argc++] = "-Wp=foo";
+ argv[argc++] = "bar";
+ argv[argc] = NULL;
+ optind = start;
+ getopt_long_loop (argc, argv, "p:q:W;", long_options_required,
+ &p_value, &q_value,
+ &non_options_count, non_options, &unrecognized);
+ ASSERT (a_seen == 0);
+ ASSERT (b_seen == 0);
+ ASSERT (p_value != NULL && strcmp (p_value, "foo") == 0);
+ ASSERT (q_value == NULL);
+ ASSERT (non_options_count == 0);
+ ASSERT (unrecognized == 0);
+ ASSERT (optind == 2);
+ }
+ for (start = 0; start <= 1; start++)
+ {
+ const char *p_value = NULL;
+ const char *q_value = NULL;
+ int non_options_count = 0;
+ const char *non_options[10];
+ int unrecognized = 0;
+ int argc = 0;
+ const char *argv[10];
+ a_seen = 0;
+ b_seen = 0;
+
+ argv[argc++] = "program";
+ argv[argc++] = "-W";
+ argv[argc++] = "p";
+ argv[argc++] = "foo";
+ argv[argc++] = "bar";
+ argv[argc] = NULL;
+ optind = start;
+ getopt_long_loop (argc, argv, "p:W;q:", long_options_required,
+ &p_value, &q_value,
+ &non_options_count, non_options, &unrecognized);
+ ASSERT (a_seen == 0);
+ ASSERT (b_seen == 0);
+ ASSERT (p_value != NULL && strcmp (p_value, "foo") == 0);
+ ASSERT (q_value == NULL);
+ ASSERT (non_options_count == 0);
+ ASSERT (unrecognized == 0);
+ ASSERT (optind == 4);
+ }
+ for (start = 0; start <= 1; start++)
+ {
+ const char *p_value = NULL;
+ const char *q_value = NULL;
+ int non_options_count = 0;
+ const char *non_options[10];
+ int unrecognized = 0;
+ int argc = 0;
+ const char *argv[10];
+ a_seen = 0;
+ b_seen = 0;
+
+ argv[argc++] = "program";
+ argv[argc++] = "-ab";
+ argv[argc++] = "-Wq";
+ argv[argc++] = "baz";
+ argv[argc++] = "-W";
+ argv[argc++] = "p=foo";
+ argv[argc++] = "bar";
+ argv[argc] = NULL;
+ optind = start;
+ getopt_long_loop (argc, argv, "W;abp:q:", long_options_required,
+ &p_value, &q_value,
+ &non_options_count, non_options, &unrecognized);
+ ASSERT (a_seen == 1);
+ ASSERT (b_seen == 1);
+ ASSERT (p_value != NULL && strcmp (p_value, "foo") == 0);
+ ASSERT (q_value != NULL && strcmp (q_value, "baz") == 0);
+ ASSERT (non_options_count == 0);
+ ASSERT (unrecognized == 0);
+ ASSERT (optind == 6);
+ }
+
+ /* Test processing of short options with optional arguments. */
+ for (start = 0; start <= 1; start++)
{
const char *p_value = NULL;
const char *q_value = NULL;
@@ -474,7 +923,7 @@ test_getopt_long (void)
ASSERT (unrecognized == 0);
ASSERT (optind == 2);
}
- for (start = OPTIND_MIN; start <= 1; start++)
+ for (start = 0; start <= 1; start++)
{
const char *p_value = NULL;
const char *q_value = NULL;
@@ -503,7 +952,7 @@ test_getopt_long (void)
ASSERT (unrecognized == 0);
ASSERT (optind == 2);
}
- for (start = OPTIND_MIN; start <= 1; start++)
+ for (start = 0; start <= 1; start++)
{
const char *p_value = NULL;
const char *q_value = NULL;
@@ -533,8 +982,274 @@ test_getopt_long (void)
ASSERT (optind == 3);
}
+ /* Test processing of long options with optional arguments. */
+ for (start = 0; start <= 1; start++)
+ {
+ const char *p_value = NULL;
+ const char *q_value = NULL;
+ int non_options_count = 0;
+ const char *non_options[10];
+ int unrecognized = 0;
+ int argc = 0;
+ const char *argv[10];
+ a_seen = 0;
+ b_seen = 0;
+
+ argv[argc++] = "program";
+ argv[argc++] = "--p=foo";
+ argv[argc++] = "bar";
+ argv[argc] = NULL;
+ optind = start;
+ getopt_long_loop (argc, argv, "p::q::", long_options_optional,
+ &p_value, &q_value,
+ &non_options_count, non_options, &unrecognized);
+ ASSERT (a_seen == 0);
+ ASSERT (b_seen == 0);
+ ASSERT (p_value != NULL && strcmp (p_value, "foo") == 0);
+ ASSERT (q_value == NULL);
+ ASSERT (non_options_count == 0);
+ ASSERT (unrecognized == 0);
+ ASSERT (optind == 2);
+ }
+ for (start = 0; start <= 1; start++)
+ {
+ const char *p_value = NULL;
+ const char *q_value = NULL;
+ int non_options_count = 0;
+ const char *non_options[10];
+ int unrecognized = 0;
+ int argc = 0;
+ const char *argv[10];
+ a_seen = 0;
+ b_seen = 0;
+
+ argv[argc++] = "program";
+ argv[argc++] = "--p";
+ argv[argc++] = "foo";
+ argv[argc++] = "bar";
+ argv[argc] = NULL;
+ optind = start;
+ getopt_long_loop (argc, argv, "p::q::", long_options_optional,
+ &p_value, &q_value,
+ &non_options_count, non_options, &unrecognized);
+ ASSERT (a_seen == 0);
+ ASSERT (b_seen == 0);
+ ASSERT (p_value == NULL);
+ ASSERT (q_value == NULL);
+ ASSERT (non_options_count == 0);
+ ASSERT (unrecognized == 0);
+ ASSERT (optind == 2);
+ }
+ for (start = 0; start <= 1; start++)
+ {
+ const char *p_value = NULL;
+ const char *q_value = NULL;
+ int non_options_count = 0;
+ const char *non_options[10];
+ int unrecognized = 0;
+ int argc = 0;
+ const char *argv[10];
+ a_seen = 0;
+ b_seen = 0;
+
+ argv[argc++] = "program";
+ argv[argc++] = "--p=";
+ argv[argc++] = "foo";
+ argv[argc++] = "bar";
+ argv[argc] = NULL;
+ optind = start;
+ getopt_long_loop (argc, argv, "p::q::", long_options_optional,
+ &p_value, &q_value,
+ &non_options_count, non_options, &unrecognized);
+ ASSERT (a_seen == 0);
+ ASSERT (b_seen == 0);
+ ASSERT (p_value != NULL && *p_value == '\0');
+ ASSERT (q_value == NULL);
+ ASSERT (non_options_count == 0);
+ ASSERT (unrecognized == 0);
+ ASSERT (optind == 2);
+ }
+ for (start = 0; start <= 1; start++)
+ {
+ const char *p_value = NULL;
+ const char *q_value = NULL;
+ int non_options_count = 0;
+ const char *non_options[10];
+ int unrecognized = 0;
+ int argc = 0;
+ const char *argv[10];
+ a_seen = 0;
+ b_seen = 0;
+
+ argv[argc++] = "program";
+ argv[argc++] = "--p";
+ argv[argc++] = "-a";
+ argv[argc++] = "bar";
+ argv[argc] = NULL;
+ optind = start;
+ getopt_long_loop (argc, argv, "abp::q::", long_options_optional,
+ &p_value, &q_value,
+ &non_options_count, non_options, &unrecognized);
+ ASSERT (a_seen == 1);
+ ASSERT (b_seen == 0);
+ ASSERT (p_value == NULL);
+ ASSERT (q_value == NULL);
+ ASSERT (non_options_count == 0);
+ ASSERT (unrecognized == 0);
+ ASSERT (optind == 3);
+ }
+
+ /* Test processing of long options with optional arguments via -W. */
+ for (start = 0; start <= 1; start++)
+ {
+ const char *p_value = NULL;
+ const char *q_value = NULL;
+ int non_options_count = 0;
+ const char *non_options[10];
+ int unrecognized = 0;
+ int argc = 0;
+ const char *argv[10];
+ a_seen = 0;
+ b_seen = 0;
+
+ argv[argc++] = "program";
+ argv[argc++] = "-Wp=foo";
+ argv[argc++] = "bar";
+ argv[argc] = NULL;
+ optind = start;
+ getopt_long_loop (argc, argv, "p::q::W;", long_options_optional,
+ &p_value, &q_value,
+ &non_options_count, non_options, &unrecognized);
+ ASSERT (a_seen == 0);
+ ASSERT (b_seen == 0);
+ ASSERT (p_value != NULL && strcmp (p_value, "foo") == 0);
+ ASSERT (q_value == NULL);
+ ASSERT (non_options_count == 0);
+ ASSERT (unrecognized == 0);
+ ASSERT (optind == 2);
+ }
+ for (start = 0; start <= 1; start++)
+ {
+ const char *p_value = NULL;
+ const char *q_value = NULL;
+ int non_options_count = 0;
+ const char *non_options[10];
+ int unrecognized = 0;
+ int argc = 0;
+ const char *argv[10];
+ a_seen = 0;
+ b_seen = 0;
+
+ argv[argc++] = "program";
+ argv[argc++] = "-Wp";
+ argv[argc++] = "foo";
+ argv[argc++] = "bar";
+ argv[argc] = NULL;
+ optind = start;
+ getopt_long_loop (argc, argv, "p::q::W;", long_options_optional,
+ &p_value, &q_value,
+ &non_options_count, non_options, &unrecognized);
+ ASSERT (a_seen == 0);
+ ASSERT (b_seen == 0);
+ /* glibc bug http://sources.redhat.com/bugzilla/show_bug.cgi?id=11041 */
+ /* ASSERT (p_value == NULL); */
+ ASSERT (q_value == NULL);
+ ASSERT (non_options_count == 0);
+ ASSERT (unrecognized == 0);
+ ASSERT (optind == 2);
+ }
+ for (start = 0; start <= 1; start++)
+ {
+ const char *p_value = NULL;
+ const char *q_value = NULL;
+ int non_options_count = 0;
+ const char *non_options[10];
+ int unrecognized = 0;
+ int argc = 0;
+ const char *argv[10];
+ a_seen = 0;
+ b_seen = 0;
+
+ argv[argc++] = "program";
+ argv[argc++] = "-Wp=";
+ argv[argc++] = "foo";
+ argv[argc++] = "bar";
+ argv[argc] = NULL;
+ optind = start;
+ getopt_long_loop (argc, argv, "W;p::q::", long_options_optional,
+ &p_value, &q_value,
+ &non_options_count, non_options, &unrecognized);
+ ASSERT (a_seen == 0);
+ ASSERT (b_seen == 0);
+ ASSERT (p_value != NULL && *p_value == '\0');
+ ASSERT (q_value == NULL);
+ ASSERT (non_options_count == 0);
+ ASSERT (unrecognized == 0);
+ ASSERT (optind == 2);
+ }
+ for (start = 0; start <= 1; start++)
+ {
+ const char *p_value = NULL;
+ const char *q_value = NULL;
+ int non_options_count = 0;
+ const char *non_options[10];
+ int unrecognized = 0;
+ int argc = 0;
+ const char *argv[10];
+ a_seen = 0;
+ b_seen = 0;
+
+ argv[argc++] = "program";
+ argv[argc++] = "-W";
+ argv[argc++] = "p=";
+ argv[argc++] = "foo";
+ argv[argc++] = "bar";
+ argv[argc] = NULL;
+ optind = start;
+ getopt_long_loop (argc, argv, "W;p::q::", long_options_optional,
+ &p_value, &q_value,
+ &non_options_count, non_options, &unrecognized);
+ ASSERT (a_seen == 0);
+ ASSERT (b_seen == 0);
+ ASSERT (p_value != NULL && *p_value == '\0');
+ ASSERT (q_value == NULL);
+ ASSERT (non_options_count == 0);
+ ASSERT (unrecognized == 0);
+ ASSERT (optind == 3);
+ }
+ for (start = 0; start <= 1; start++)
+ {
+ const char *p_value = NULL;
+ const char *q_value = NULL;
+ int non_options_count = 0;
+ const char *non_options[10];
+ int unrecognized = 0;
+ int argc = 0;
+ const char *argv[10];
+ a_seen = 0;
+ b_seen = 0;
+
+ argv[argc++] = "program";
+ argv[argc++] = "-W";
+ argv[argc++] = "p";
+ argv[argc++] = "-a";
+ argv[argc++] = "bar";
+ argv[argc] = NULL;
+ optind = start;
+ getopt_long_loop (argc, argv, "W;abp::q::", long_options_optional,
+ &p_value, &q_value,
+ &non_options_count, non_options, &unrecognized);
+ ASSERT (a_seen == 1);
+ ASSERT (b_seen == 0);
+ /* ASSERT (p_value == NULL); */
+ ASSERT (q_value == NULL);
+ ASSERT (non_options_count == 0);
+ ASSERT (unrecognized == 0);
+ ASSERT (optind == 4);
+ }
+
/* Check that invalid options are recognized. */
- for (start = OPTIND_MIN; start <= 1; start++)
+ for (start = 0; start <= 1; start++)
{
const char *p_value = NULL;
const char *q_value = NULL;
@@ -565,9 +1280,104 @@ test_getopt_long (void)
ASSERT (unrecognized == 'x');
ASSERT (optind == 5);
}
+ for (start = 0; start <= 1; start++)
+ {
+ const char *p_value = NULL;
+ const char *q_value = NULL;
+ int non_options_count = 0;
+ const char *non_options[10];
+ int unrecognized = 0;
+ int argc = 0;
+ const char *argv[10];
+ a_seen = 0;
+ b_seen = 0;
+
+ argv[argc++] = "program";
+ argv[argc++] = "-p";
+ argv[argc++] = "foo";
+ argv[argc++] = "-:";
+ argv[argc++] = "-a";
+ argv[argc++] = "bar";
+ argv[argc] = NULL;
+ optind = start;
+ getopt_long_loop (argc, argv, "abp:q:", long_options_required,
+ &p_value, &q_value,
+ &non_options_count, non_options, &unrecognized);
+ ASSERT (a_seen == 1);
+ ASSERT (b_seen == 0);
+ ASSERT (p_value != NULL && strcmp (p_value, "foo") == 0);
+ ASSERT (q_value == NULL);
+ ASSERT (non_options_count == 0);
+ ASSERT (unrecognized == ':');
+ ASSERT (optind == 5);
+ }
+
+ /* Check that unexpected arguments are recognized. */
+ for (start = 0; start <= 1; start++)
+ {
+ const char *p_value = NULL;
+ const char *q_value = NULL;
+ int non_options_count = 0;
+ const char *non_options[10];
+ int unrecognized = 0;
+ int argc = 0;
+ const char *argv[10];
+ a_seen = 0;
+ b_seen = 0;
+
+ argv[argc++] = "program";
+ argv[argc++] = "-p";
+ argv[argc++] = "foo";
+ argv[argc++] = "--a=";
+ argv[argc++] = "bar";
+ argv[argc] = NULL;
+ optind = start;
+ getopt_long_loop (argc, argv, "abp:q:", long_options_required,
+ &p_value, &q_value,
+ &non_options_count, non_options, &unrecognized);
+ ASSERT (a_seen == 0);
+ ASSERT (b_seen == 0);
+ ASSERT (p_value != NULL && strcmp (p_value, "foo") == 0);
+ ASSERT (q_value == NULL);
+ ASSERT (non_options_count == 0);
+ ASSERT (unrecognized == 'a');
+ ASSERT (optind == 4);
+ }
+ for (start = 0; start <= 1; start++)
+ {
+ const char *p_value = NULL;
+ const char *q_value = NULL;
+ int non_options_count = 0;
+ const char *non_options[10];
+ int unrecognized = 0;
+ int argc = 0;
+ const char *argv[10];
+ a_seen = 0;
+ b_seen = 0;
+
+ argv[argc++] = "program";
+ argv[argc++] = "-p";
+ argv[argc++] = "foo";
+ argv[argc++] = "--b=";
+ argv[argc++] = "bar";
+ argv[argc] = NULL;
+ optind = start;
+ getopt_long_loop (argc, argv, "abp:q:", long_options_required,
+ &p_value, &q_value,
+ &non_options_count, non_options, &unrecognized);
+ ASSERT (a_seen == 0);
+ ASSERT (b_seen == 0);
+ ASSERT (p_value != NULL && strcmp (p_value, "foo") == 0);
+ ASSERT (q_value == NULL);
+ ASSERT (non_options_count == 0);
+ /* When flag is non-zero, glibc sets optopt anyway, but BSD
+ leaves optopt unchanged. */
+ ASSERT (unrecognized == 1 || unrecognized == 0);
+ ASSERT (optind == 4);
+ }
/* Check that by default, non-options arguments are moved to the end. */
- for (start = OPTIND_MIN; start <= 1; start++)
+ for (start = 0; start <= 1; start++)
{
const char *p_value = NULL;
const char *q_value = NULL;
@@ -609,7 +1419,7 @@ test_getopt_long (void)
}
/* Check that '--' ends the argument processing. */
- for (start = OPTIND_MIN; start <= 1; start++)
+ for (start = 0; start <= 1; start++)
{
const char *p_value = NULL;
const char *q_value = NULL;
@@ -661,7 +1471,7 @@ test_getopt_long (void)
}
/* Check that the '-' flag causes non-options to be returned in order. */
- for (start = OPTIND_MIN; start <= 1; start++)
+ for (start = 0; start <= 1; start++)
{
const char *p_value = NULL;
const char *q_value = NULL;
@@ -706,7 +1516,7 @@ test_getopt_long (void)
}
/* Check that '--' ends the argument processing. */
- for (start = OPTIND_MIN; start <= 1; start++)
+ for (start = 0; start <= 1; start++)
{
const char *p_value = NULL;
const char *q_value = NULL;
@@ -778,7 +1588,7 @@ test_getopt_long (void)
}
/* Check that the '-' flag has to come first. */
- for (start = OPTIND_MIN; start <= 1; start++)
+ for (start = 0; start <= 1; start++)
{
const char *p_value = NULL;
const char *q_value = NULL;
@@ -821,7 +1631,7 @@ test_getopt_long (void)
/* Check that the '+' flag causes the first non-option to terminate the
loop. */
- for (start = OPTIND_MIN; start <= 1; start++)
+ for (start = 0; start <= 1; start++)
{
const char *p_value = NULL;
const char *q_value = NULL;
@@ -861,7 +1671,7 @@ test_getopt_long (void)
ASSERT (unrecognized == 0);
ASSERT (optind == 1);
}
- for (start = OPTIND_MIN; start <= 1; start++)
+ for (start = 0; start <= 1; start++)
{
const char *p_value = NULL;
const char *q_value = NULL;
@@ -890,7 +1700,7 @@ test_getopt_long (void)
}
/* Check that '--' ends the argument processing. */
- for (start = OPTIND_MIN; start <= 1; start++)
+ for (start = 0; start <= 1; start++)
{
const char *p_value = NULL;
const char *q_value = NULL;
@@ -942,7 +1752,7 @@ test_getopt_long (void)
}
/* Check that the '+' flag has to come first. */
- for (start = OPTIND_MIN; start <= 1; start++)
+ for (start = 0; start <= 1; start++)
{
const char *p_value = NULL;
const char *q_value = NULL;
@@ -993,8 +1803,50 @@ test_getopt_long_posix (void)
{
int start;
+ /* Check that POSIXLY_CORRECT stops parsing the same as leading '+'. */
+ for (start = 0; start <= 1; start++)
+ {
+ const char *p_value = NULL;
+ const char *q_value = NULL;
+ int non_options_count = 0;
+ const char *non_options[10];
+ int unrecognized = 0;
+ int argc = 0;
+ const char *argv[10];
+ a_seen = 0;
+ b_seen = 0;
+
+ argv[argc++] = "program";
+ argv[argc++] = "donald";
+ argv[argc++] = "-p";
+ argv[argc++] = "billy";
+ argv[argc++] = "duck";
+ argv[argc++] = "-a";
+ argv[argc++] = "bar";
+ argv[argc] = NULL;
+ optind = start;
+ getopt_long_loop (argc, argv, "abp:q:", long_options_required,
+ &p_value, &q_value,
+ &non_options_count, non_options, &unrecognized);
+ ASSERT (strcmp (argv[0], "program") == 0);
+ ASSERT (strcmp (argv[1], "donald") == 0);
+ ASSERT (strcmp (argv[2], "-p") == 0);
+ ASSERT (strcmp (argv[3], "billy") == 0);
+ ASSERT (strcmp (argv[4], "duck") == 0);
+ ASSERT (strcmp (argv[5], "-a") == 0);
+ ASSERT (strcmp (argv[6], "bar") == 0);
+ ASSERT (argv[7] == NULL);
+ ASSERT (a_seen == 0);
+ ASSERT (b_seen == 0);
+ ASSERT (p_value == NULL);
+ ASSERT (q_value == NULL);
+ ASSERT (non_options_count == 0);
+ ASSERT (unrecognized == 0);
+ ASSERT (optind == 1);
+ }
+
/* Check that POSIXLY_CORRECT doesn't change optional arguments. */
- for (start = OPTIND_MIN; start <= 1; start++)
+ for (start = 0; start <= 1; start++)
{
const char *p_value = NULL;
const char *q_value = NULL;
@@ -1024,7 +1876,7 @@ test_getopt_long_posix (void)
}
/* Check that leading - still sees options after non-options. */
- for (start = OPTIND_MIN; start <= 1; start++)
+ for (start = 0; start <= 1; start++)
{
const char *p_value = NULL;
const char *q_value = NULL;
@@ -1055,3 +1907,214 @@ test_getopt_long_posix (void)
ASSERT (optind == 4);
}
}
+
+/* Reduce casting, so we can use string literals elsewhere.
+ getopt_long_only takes an array of char*, but luckily does not
+ modify those elements, so we can pass const char*. */
+static int
+do_getopt_long_only (int argc, const char **argv, const char *shortopts,
+ const struct option *longopts, int *longind)
+{
+ return getopt_long_only (argc, (char **) argv, shortopts, longopts, longind);
+}
+
+static void
+test_getopt_long_only (void)
+{
+ /* Test disambiguation of options. */
+ {
+ int argc = 0;
+ const char *argv[10];
+ int option_index;
+ int c;
+
+ argv[argc++] = "program";
+ argv[argc++] = "-x";
+ argv[argc] = NULL;
+ optind = 1;
+ opterr = 0;
+ c = do_getopt_long_only (argc, argv, "ab", long_options_required,
+ &option_index);
+ ASSERT (c == '?');
+ ASSERT (optopt == 0);
+ }
+ {
+ int argc = 0;
+ const char *argv[10];
+ int option_index;
+ int c;
+
+ argv[argc++] = "program";
+ argv[argc++] = "-x";
+ argv[argc] = NULL;
+ optind = 1;
+ opterr = 0;
+ c = do_getopt_long_only (argc, argv, "abx", long_options_required,
+ &option_index);
+ ASSERT (c == 'x');
+ ASSERT (optopt == 0);
+ }
+ {
+ int argc = 0;
+ const char *argv[10];
+ int option_index;
+ int c;
+
+ argv[argc++] = "program";
+ argv[argc++] = "--x";
+ argv[argc] = NULL;
+ optind = 1;
+ opterr = 0;
+ c = do_getopt_long_only (argc, argv, "abx", long_options_required,
+ &option_index);
+ ASSERT (c == '?');
+ ASSERT (optopt == 0);
+ }
+ {
+ int argc = 0;
+ const char *argv[10];
+ int option_index;
+ int c;
+
+ argv[argc++] = "program";
+ argv[argc++] = "-b";
+ argv[argc] = NULL;
+ optind = 1;
+ opterr = 0;
+ b_seen = 0;
+ c = do_getopt_long_only (argc, argv, "abx", long_options_required,
+ &option_index);
+ ASSERT (c == 'b');
+ ASSERT (b_seen == 0);
+ }
+ {
+ int argc = 0;
+ const char *argv[10];
+ int option_index;
+ int c;
+
+ argv[argc++] = "program";
+ argv[argc++] = "--b";
+ argv[argc] = NULL;
+ optind = 1;
+ opterr = 0;
+ b_seen = 0;
+ c = do_getopt_long_only (argc, argv, "abx", long_options_required,
+ &option_index);
+ ASSERT (c == 0);
+ ASSERT (b_seen == 1);
+ }
+ {
+ int argc = 0;
+ const char *argv[10];
+ int option_index;
+ int c;
+
+ argv[argc++] = "program";
+ argv[argc++] = "-xt";
+ argv[argc] = NULL;
+ optind = 1;
+ opterr = 0;
+ c = do_getopt_long_only (argc, argv, "ab", long_options_required,
+ &option_index);
+ ASSERT (c == '?');
+ ASSERT (optopt == 0);
+ }
+ {
+ int argc = 0;
+ const char *argv[10];
+ int option_index;
+ int c;
+
+ argv[argc++] = "program";
+ argv[argc++] = "-xt";
+ argv[argc] = NULL;
+ optind = 1;
+ opterr = 0;
+ c = do_getopt_long_only (argc, argv, "abx", long_options_required,
+ &option_index);
+ ASSERT (c == '?');
+ ASSERT (optopt == 0);
+ }
+ {
+ int argc = 0;
+ const char *argv[10];
+ int option_index;
+ int c;
+
+ argv[argc++] = "program";
+ argv[argc++] = "-xtra";
+ argv[argc] = NULL;
+ optind = 1;
+ opterr = 0;
+ c = do_getopt_long_only (argc, argv, "ab", long_options_required,
+ &option_index);
+ ASSERT (c == 1001);
+ }
+ {
+ int argc = 0;
+ const char *argv[10];
+ int option_index;
+ int c;
+
+ argv[argc++] = "program";
+ argv[argc++] = "-xtreme";
+ argv[argc] = NULL;
+ optind = 1;
+ opterr = 0;
+ c = do_getopt_long_only (argc, argv, "abx:", long_options_required,
+ &option_index);
+ ASSERT (c == 1002);
+ }
+ {
+ int argc = 0;
+ const char *argv[10];
+ int option_index;
+ int c;
+
+ argv[argc++] = "program";
+ argv[argc++] = "-xtremel";
+ argv[argc] = NULL;
+ optind = 1;
+ opterr = 0;
+ c = do_getopt_long_only (argc, argv, "ab", long_options_required,
+ &option_index);
+ /* glibc bug http://sources.redhat.com/bugzilla/show_bug.cgi?id=11041 */
+ /* ASSERT (c == 1003); */
+ ASSERT (optind == 2);
+ }
+ {
+ int argc = 0;
+ const char *argv[10];
+ int option_index;
+ int c;
+
+ argv[argc++] = "program";
+ argv[argc++] = "-xtremel";
+ argv[argc] = NULL;
+ optind = 1;
+ opterr = 0;
+ c = do_getopt_long_only (argc, argv, "abx::", long_options_required,
+ &option_index);
+ /* glibc bug http://sources.redhat.com/bugzilla/show_bug.cgi?id=11041 */
+ /* ASSERT (c == 1003); */
+ ASSERT (optind == 2);
+ ASSERT (optarg == NULL);
+ }
+ {
+ int argc = 0;
+ const char *argv[10];
+ int option_index;
+ int c;
+
+ argv[argc++] = "program";
+ argv[argc++] = "-xtras";
+ argv[argc] = NULL;
+ optind = 1;
+ opterr = 0;
+ c = do_getopt_long_only (argc, argv, "abx::", long_options_required,
+ &option_index);
+ ASSERT (c == 'x');
+ ASSERT (strcmp (optarg, "tras") == 0);
+ }
+}
--
1.6.4.2
>From e7dc3f8ed92d330a367f7e5d02ed84d700ad23cb Mon Sep 17 00:00:00 2001
From: Eric Blake <address@hidden>
Date: Wed, 2 Dec 2009 15:48:08 -0700
Subject: [PATCH 2/2] test-getopt: test stderr behavior
Portions of this commit are commented out because they tickle
glibc bugs. For a real-life example of the bug:
$ env -ua -:
env: invalid option -- :
Try `env --help' for more information.
$ env -:
env: invalid option -- :
Try `env --help' for more information.
$ env -+
env: invalid option -- +
Try `env --help' for more information.
$ env -ua -+
Try `env --help' for more information.
Notice that when -+ is not given as the first argument, the
error message is mistakenly suppressed.
* modules/getopt-posix-tests (Depends-on): Add dup2.
* tests/test-getopt.c (ASSERT): Avoid stderr.
(main): Move stderr to a temporary file.
* tests/test-getopt.h (getopt_loop): No longer manipulate opterr.
Instead, add parameter to inform caller if output occurred.
(test_getopt): Adjust all tests to expect silence, and add new
tests of leading ":".
Signed-off-by: Eric Blake <address@hidden>
---
ChangeLog | 9 +
modules/getopt-posix-tests | 1 +
tests/test-getopt.c | 28 +++-
tests/test-getopt.h | 387 +++++++++++++++++++++++++++++++++++++++++---
4 files changed, 400 insertions(+), 25 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index a1d3f50..c2a2242 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,14 @@
2009-12-02 Eric Blake <address@hidden>
+ test-getopt: test stderr behavior
+ * modules/getopt-posix-tests (Depends-on): Add dup2.
+ * tests/test-getopt.c (ASSERT): Avoid stderr.
+ (main): Move stderr to a temporary file.
+ * tests/test-getopt.h (getopt_loop): No longer manipulate opterr.
+ Instead, add parameter to inform caller if output occurred.
+ (test_getopt): Adjust all tests to expect silence, and add new
+ tests of leading ":".
+
test-getopt: enhance test
* tests/test-getopt.c (OPTIND_MIN): Move...
* tests/test-getopt.h (OPTIND_MIN): ...here.
diff --git a/modules/getopt-posix-tests b/modules/getopt-posix-tests
index be828cf..b2e3727 100644
--- a/modules/getopt-posix-tests
+++ b/modules/getopt-posix-tests
@@ -4,6 +4,7 @@ tests/test-getopt.h
tests/test-getopt_long.h
Depends-on:
+dup2
setenv
stdbool
unistd
diff --git a/tests/test-getopt.c b/tests/test-getopt.c
index 5ef6974..cac54f5 100644
--- a/tests/test-getopt.c
+++ b/tests/test-getopt.c
@@ -27,18 +27,31 @@
#include <stdlib.h>
#include <string.h>
+/* This test intentionally remaps stderr. So, we arrange to have fd 10
+ (outside the range of interesting fd's during the test) set up to
+ duplicate the original stderr. */
+
+#define BACKUP_STDERR_FILENO 10
+static FILE *myerr;
+
#define ASSERT(expr) \
do \
{ \
if (!(expr)) \
{ \
- fprintf (stderr, "%s:%d: assertion failed\n", __FILE__, __LINE__); \
- fflush (stderr); \
+ fprintf (myerr, "%s:%d: assertion failed\n", __FILE__, __LINE__); \
+ fflush (myerr); \
abort (); \
} \
} \
while (0)
+/* None of the output to stderr by this test is large, so disable the
+ ftell link warning if we are not using the gnulib ftell module. */
+#if !GNULIB_FTELL
+# undef ftell
+#endif
+
#include "test-getopt.h"
#if GNULIB_GETOPT_GNU
# include "test-getopt_long.h"
@@ -47,6 +60,14 @@
int
main (void)
{
+ /* This test validates that stderr is used correctly, so move the
+ original into fd 10. */
+ if (dup2 (STDERR_FILENO, BACKUP_STDERR_FILENO) != BACKUP_STDERR_FILENO
+ || (myerr = fdopen (BACKUP_STDERR_FILENO, "w")) == NULL)
+ return 2;
+
+ ASSERT (freopen ("test-getopt.tmp", "w", stderr) == stderr);
+
/* These default values are required by POSIX. */
ASSERT (optind == 1);
ASSERT (opterr != 0);
@@ -66,5 +87,8 @@ main (void)
test_getopt_long_only ();
#endif
+ ASSERT (fclose (stderr) == 0);
+ ASSERT (remove ("test-getopt.tmp") == 0);
+
return 0;
}
diff --git a/tests/test-getopt.h b/tests/test-getopt.h
index 3a3ee63..245a6f8 100644
--- a/tests/test-getopt.h
+++ b/tests/test-getopt.h
@@ -35,11 +35,11 @@ getopt_loop (int argc, const char **argv,
int *a_seen, int *b_seen,
const char **p_value, const char **q_value,
int *non_options_count, const char **non_options,
- int *unrecognized)
+ int *unrecognized, bool *message_issued)
{
int c;
+ int pos = ftell (stderr);
- opterr = 0;
while ((c = getopt (argc, (char **) argv, options)) != -1)
{
switch (c)
@@ -61,6 +61,12 @@ getopt_loop (int argc, const char **argv,
ASSERT (options[0] == '-');
non_options[(*non_options_count)++] = optarg;
break;
+ case ':':
+ /* Must only happen with option ':' at the beginning. */
+ ASSERT (options[0] == ':'
+ || ((options[0] == '-' || options[0] == '+')
+ && options[1] == ':'));
+ /* fall through */
case '?':
*unrecognized = optopt;
break;
@@ -69,6 +75,8 @@ getopt_loop (int argc, const char **argv,
break;
}
}
+
+ *message_issued = pos < ftell (stderr);
}
static void
@@ -94,6 +102,7 @@ test_getopt (void)
int non_options_count = 0;
const char *non_options[10];
int unrecognized = 0;
+ bool output;
int argc = 0;
const char *argv[10];
@@ -103,9 +112,10 @@ test_getopt (void)
argv[argc++] = "bar";
argv[argc] = NULL;
optind = start;
+ opterr = 1;
getopt_loop (argc, argv, "ab",
&a_seen, &b_seen, &p_value, &q_value,
- &non_options_count, non_options, &unrecognized);
+ &non_options_count, non_options, &unrecognized, &output);
ASSERT (a_seen == 1);
ASSERT (b_seen == 0);
ASSERT (p_value == NULL);
@@ -113,6 +123,7 @@ test_getopt (void)
ASSERT (non_options_count == 0);
ASSERT (unrecognized == 0);
ASSERT (optind == 2);
+ ASSERT (!output);
}
for (start = OPTIND_MIN; start <= 1; start++)
{
@@ -123,6 +134,7 @@ test_getopt (void)
int non_options_count = 0;
const char *non_options[10];
int unrecognized = 0;
+ bool output;
int argc = 0;
const char *argv[10];
@@ -133,9 +145,10 @@ test_getopt (void)
argv[argc++] = "bar";
argv[argc] = NULL;
optind = start;
+ opterr = 1;
getopt_loop (argc, argv, "ab",
&a_seen, &b_seen, &p_value, &q_value,
- &non_options_count, non_options, &unrecognized);
+ &non_options_count, non_options, &unrecognized, &output);
ASSERT (a_seen == 1);
ASSERT (b_seen == 1);
ASSERT (p_value == NULL);
@@ -143,6 +156,7 @@ test_getopt (void)
ASSERT (non_options_count == 0);
ASSERT (unrecognized == 0);
ASSERT (optind == 3);
+ ASSERT (!output);
}
for (start = OPTIND_MIN; start <= 1; start++)
{
@@ -153,6 +167,7 @@ test_getopt (void)
int non_options_count = 0;
const char *non_options[10];
int unrecognized = 0;
+ bool output;
int argc = 0;
const char *argv[10];
@@ -162,9 +177,10 @@ test_getopt (void)
argv[argc++] = "bar";
argv[argc] = NULL;
optind = start;
+ opterr = 1;
getopt_loop (argc, argv, "ab",
&a_seen, &b_seen, &p_value, &q_value,
- &non_options_count, non_options, &unrecognized);
+ &non_options_count, non_options, &unrecognized, &output);
ASSERT (a_seen == 1);
ASSERT (b_seen == 1);
ASSERT (p_value == NULL);
@@ -172,6 +188,7 @@ test_getopt (void)
ASSERT (non_options_count == 0);
ASSERT (unrecognized == 0);
ASSERT (optind == 2);
+ ASSERT (!output);
}
for (start = OPTIND_MIN; start <= 1; start++)
{
@@ -182,6 +199,7 @@ test_getopt (void)
int non_options_count = 0;
const char *non_options[10];
int unrecognized = 0;
+ bool output;
int argc = 0;
const char *argv[10];
@@ -192,9 +210,10 @@ test_getopt (void)
argv[argc++] = "bar";
argv[argc] = NULL;
optind = start;
+ opterr = 1;
getopt_loop (argc, argv, "ab",
&a_seen, &b_seen, &p_value, &q_value,
- &non_options_count, non_options, &unrecognized);
+ &non_options_count, non_options, &unrecognized, &output);
ASSERT (a_seen == 2);
ASSERT (b_seen == 1);
ASSERT (p_value == NULL);
@@ -202,6 +221,7 @@ test_getopt (void)
ASSERT (non_options_count == 0);
ASSERT (unrecognized == 0);
ASSERT (optind == 3);
+ ASSERT (!output);
}
/* Test processing of options with arguments. */
@@ -214,6 +234,7 @@ test_getopt (void)
int non_options_count = 0;
const char *non_options[10];
int unrecognized = 0;
+ bool output;
int argc = 0;
const char *argv[10];
@@ -222,9 +243,10 @@ test_getopt (void)
argv[argc++] = "bar";
argv[argc] = NULL;
optind = start;
+ opterr = 1;
getopt_loop (argc, argv, "p:q:",
&a_seen, &b_seen, &p_value, &q_value,
- &non_options_count, non_options, &unrecognized);
+ &non_options_count, non_options, &unrecognized, &output);
ASSERT (a_seen == 0);
ASSERT (b_seen == 0);
ASSERT (p_value != NULL && strcmp (p_value, "foo") == 0);
@@ -232,6 +254,7 @@ test_getopt (void)
ASSERT (non_options_count == 0);
ASSERT (unrecognized == 0);
ASSERT (optind == 2);
+ ASSERT (!output);
}
for (start = OPTIND_MIN; start <= 1; start++)
{
@@ -242,6 +265,7 @@ test_getopt (void)
int non_options_count = 0;
const char *non_options[10];
int unrecognized = 0;
+ bool output;
int argc = 0;
const char *argv[10];
@@ -251,9 +275,10 @@ test_getopt (void)
argv[argc++] = "bar";
argv[argc] = NULL;
optind = start;
+ opterr = 1;
getopt_loop (argc, argv, "p:q:",
&a_seen, &b_seen, &p_value, &q_value,
- &non_options_count, non_options, &unrecognized);
+ &non_options_count, non_options, &unrecognized, &output);
ASSERT (a_seen == 0);
ASSERT (b_seen == 0);
ASSERT (p_value != NULL && strcmp (p_value, "foo") == 0);
@@ -261,6 +286,7 @@ test_getopt (void)
ASSERT (non_options_count == 0);
ASSERT (unrecognized == 0);
ASSERT (optind == 3);
+ ASSERT (!output);
}
for (start = OPTIND_MIN; start <= 1; start++)
{
@@ -271,6 +297,7 @@ test_getopt (void)
int non_options_count = 0;
const char *non_options[10];
int unrecognized = 0;
+ bool output;
int argc = 0;
const char *argv[10];
@@ -282,9 +309,10 @@ test_getopt (void)
argv[argc++] = "bar";
argv[argc] = NULL;
optind = start;
+ opterr = 1;
getopt_loop (argc, argv, "abp:q:",
&a_seen, &b_seen, &p_value, &q_value,
- &non_options_count, non_options, &unrecognized);
+ &non_options_count, non_options, &unrecognized, &output);
ASSERT (a_seen == 1);
ASSERT (b_seen == 1);
ASSERT (p_value != NULL && strcmp (p_value, "foo") == 0);
@@ -292,6 +320,7 @@ test_getopt (void)
ASSERT (non_options_count == 0);
ASSERT (unrecognized == 0);
ASSERT (optind == 5);
+ ASSERT (!output);
}
#if GNULIB_GETOPT_GNU
@@ -305,6 +334,7 @@ test_getopt (void)
int non_options_count = 0;
const char *non_options[10];
int unrecognized = 0;
+ bool output;
int argc = 0;
const char *argv[10];
@@ -313,9 +343,10 @@ test_getopt (void)
argv[argc++] = "bar";
argv[argc] = NULL;
optind = start;
+ opterr = 1;
getopt_loop (argc, argv, "p::q::",
&a_seen, &b_seen, &p_value, &q_value,
- &non_options_count, non_options, &unrecognized);
+ &non_options_count, non_options, &unrecognized, &output);
ASSERT (a_seen == 0);
ASSERT (b_seen == 0);
ASSERT (p_value != NULL && strcmp (p_value, "foo") == 0);
@@ -323,6 +354,7 @@ test_getopt (void)
ASSERT (non_options_count == 0);
ASSERT (unrecognized == 0);
ASSERT (optind == 2);
+ ASSERT (!output);
}
for (start = OPTIND_MIN; start <= 1; start++)
{
@@ -333,6 +365,7 @@ test_getopt (void)
int non_options_count = 0;
const char *non_options[10];
int unrecognized = 0;
+ bool output;
int argc = 0;
const char *argv[10];
@@ -342,9 +375,10 @@ test_getopt (void)
argv[argc++] = "bar";
argv[argc] = NULL;
optind = start;
+ opterr = 1;
getopt_loop (argc, argv, "p::q::",
&a_seen, &b_seen, &p_value, &q_value,
- &non_options_count, non_options, &unrecognized);
+ &non_options_count, non_options, &unrecognized, &output);
ASSERT (a_seen == 0);
ASSERT (b_seen == 0);
ASSERT (p_value == NULL);
@@ -352,6 +386,7 @@ test_getopt (void)
ASSERT (non_options_count == 0);
ASSERT (unrecognized == 0);
ASSERT (optind == 2);
+ ASSERT (!output);
}
for (start = OPTIND_MIN; start <= 1; start++)
{
@@ -362,6 +397,7 @@ test_getopt (void)
int non_options_count = 0;
const char *non_options[10];
int unrecognized = 0;
+ bool output;
int argc = 0;
const char *argv[10];
@@ -371,9 +407,10 @@ test_getopt (void)
argv[argc++] = "bar";
argv[argc] = NULL;
optind = start;
+ opterr = 1;
getopt_loop (argc, argv, "abp::q::",
&a_seen, &b_seen, &p_value, &q_value,
- &non_options_count, non_options, &unrecognized);
+ &non_options_count, non_options, &unrecognized, &output);
ASSERT (a_seen == 1);
ASSERT (b_seen == 0);
ASSERT (p_value == NULL);
@@ -381,10 +418,46 @@ test_getopt (void)
ASSERT (non_options_count == 0);
ASSERT (unrecognized == 0);
ASSERT (optind == 3);
+ ASSERT (!output);
}
#endif
- /* Check that invalid options are recognized. */
+ /* Check that invalid options are recognized; and that both opterr
+ and leading ':' can silence output. */
+ for (start = OPTIND_MIN; start <= 1; start++)
+ {
+ int a_seen = 0;
+ int b_seen = 0;
+ const char *p_value = NULL;
+ const char *q_value = NULL;
+ int non_options_count = 0;
+ const char *non_options[10];
+ int unrecognized = 0;
+ bool output;
+ int argc = 0;
+ const char *argv[10];
+
+ argv[argc++] = "program";
+ argv[argc++] = "-p";
+ argv[argc++] = "foo";
+ argv[argc++] = "-x";
+ argv[argc++] = "-a";
+ argv[argc++] = "bar";
+ argv[argc] = NULL;
+ optind = start;
+ opterr = 42;
+ getopt_loop (argc, argv, "abp:q:",
+ &a_seen, &b_seen, &p_value, &q_value,
+ &non_options_count, non_options, &unrecognized, &output);
+ ASSERT (a_seen == 1);
+ ASSERT (b_seen == 0);
+ ASSERT (p_value != NULL && strcmp (p_value, "foo") == 0);
+ ASSERT (q_value == NULL);
+ ASSERT (non_options_count == 0);
+ ASSERT (unrecognized == 'x');
+ ASSERT (optind == 5);
+ ASSERT (output);
+ }
for (start = OPTIND_MIN; start <= 1; start++)
{
int a_seen = 0;
@@ -394,6 +467,7 @@ test_getopt (void)
int non_options_count = 0;
const char *non_options[10];
int unrecognized = 0;
+ bool output;
int argc = 0;
const char *argv[10];
@@ -405,9 +479,44 @@ test_getopt (void)
argv[argc++] = "bar";
argv[argc] = NULL;
optind = start;
+ opterr = 0;
getopt_loop (argc, argv, "abp:q:",
&a_seen, &b_seen, &p_value, &q_value,
- &non_options_count, non_options, &unrecognized);
+ &non_options_count, non_options, &unrecognized, &output);
+ ASSERT (a_seen == 1);
+ ASSERT (b_seen == 0);
+ ASSERT (p_value != NULL && strcmp (p_value, "foo") == 0);
+ ASSERT (q_value == NULL);
+ ASSERT (non_options_count == 0);
+ ASSERT (unrecognized == 'x');
+ ASSERT (optind == 5);
+ ASSERT (!output);
+ }
+ for (start = OPTIND_MIN; start <= 1; start++)
+ {
+ int a_seen = 0;
+ int b_seen = 0;
+ const char *p_value = NULL;
+ const char *q_value = NULL;
+ int non_options_count = 0;
+ const char *non_options[10];
+ int unrecognized = 0;
+ bool output;
+ int argc = 0;
+ const char *argv[10];
+
+ argv[argc++] = "program";
+ argv[argc++] = "-p";
+ argv[argc++] = "foo";
+ argv[argc++] = "-x";
+ argv[argc++] = "-a";
+ argv[argc++] = "bar";
+ argv[argc] = NULL;
+ optind = start;
+ opterr = 1;
+ getopt_loop (argc, argv, ":abp:q:",
+ &a_seen, &b_seen, &p_value, &q_value,
+ &non_options_count, non_options, &unrecognized, &output);
ASSERT (a_seen == 1);
ASSERT (b_seen == 0);
ASSERT (p_value != NULL && strcmp (p_value, "foo") == 0);
@@ -415,6 +524,201 @@ test_getopt (void)
ASSERT (non_options_count == 0);
ASSERT (unrecognized == 'x');
ASSERT (optind == 5);
+ ASSERT (!output);
+ }
+ for (start = OPTIND_MIN; start <= 1; start++)
+ {
+ int a_seen = 0;
+ int b_seen = 0;
+ const char *p_value = NULL;
+ const char *q_value = NULL;
+ int non_options_count = 0;
+ const char *non_options[10];
+ int unrecognized = 0;
+ bool output;
+ int argc = 0;
+ const char *argv[10];
+
+ argv[argc++] = "program";
+ argv[argc++] = "-p";
+ argv[argc++] = "foo";
+ argv[argc++] = "-:";
+ argv[argc++] = "-a";
+ argv[argc++] = "bar";
+ argv[argc] = NULL;
+ optind = start;
+ opterr = 42;
+ getopt_loop (argc, argv, "abp:q:",
+ &a_seen, &b_seen, &p_value, &q_value,
+ &non_options_count, non_options, &unrecognized, &output);
+ ASSERT (a_seen == 1);
+ ASSERT (b_seen == 0);
+ ASSERT (p_value != NULL && strcmp (p_value, "foo") == 0);
+ ASSERT (q_value == NULL);
+ ASSERT (non_options_count == 0);
+ ASSERT (unrecognized == ':');
+ ASSERT (optind == 5);
+ ASSERT (output);
+ }
+ for (start = OPTIND_MIN; start <= 1; start++)
+ {
+ int a_seen = 0;
+ int b_seen = 0;
+ const char *p_value = NULL;
+ const char *q_value = NULL;
+ int non_options_count = 0;
+ const char *non_options[10];
+ int unrecognized = 0;
+ bool output;
+ int argc = 0;
+ const char *argv[10];
+
+ argv[argc++] = "program";
+ argv[argc++] = "-p";
+ argv[argc++] = "foo";
+ argv[argc++] = "-:";
+ argv[argc++] = "-a";
+ argv[argc++] = "bar";
+ argv[argc] = NULL;
+ optind = start;
+ opterr = 0;
+ getopt_loop (argc, argv, "abp:q:",
+ &a_seen, &b_seen, &p_value, &q_value,
+ &non_options_count, non_options, &unrecognized, &output);
+ ASSERT (a_seen == 1);
+ ASSERT (b_seen == 0);
+ ASSERT (p_value != NULL && strcmp (p_value, "foo") == 0);
+ ASSERT (q_value == NULL);
+ ASSERT (non_options_count == 0);
+ ASSERT (unrecognized == ':');
+ ASSERT (optind == 5);
+ ASSERT (!output);
+ }
+ for (start = OPTIND_MIN; start <= 1; start++)
+ {
+ int a_seen = 0;
+ int b_seen = 0;
+ const char *p_value = NULL;
+ const char *q_value = NULL;
+ int non_options_count = 0;
+ const char *non_options[10];
+ int unrecognized = 0;
+ bool output;
+ int argc = 0;
+ const char *argv[10];
+
+ argv[argc++] = "program";
+ argv[argc++] = "-p";
+ argv[argc++] = "foo";
+ argv[argc++] = "-:";
+ argv[argc++] = "-a";
+ argv[argc++] = "bar";
+ argv[argc] = NULL;
+ optind = start;
+ opterr = 1;
+ getopt_loop (argc, argv, ":abp:q:",
+ &a_seen, &b_seen, &p_value, &q_value,
+ &non_options_count, non_options, &unrecognized, &output);
+ ASSERT (a_seen == 1);
+ ASSERT (b_seen == 0);
+ ASSERT (p_value != NULL && strcmp (p_value, "foo") == 0);
+ ASSERT (q_value == NULL);
+ ASSERT (non_options_count == 0);
+ ASSERT (unrecognized == ':');
+ ASSERT (optind == 5);
+ ASSERT (!output);
+ }
+
+ /* Check for missing argument behavior. */
+ for (start = OPTIND_MIN; start <= 1; start++)
+ {
+ int a_seen = 0;
+ int b_seen = 0;
+ const char *p_value = NULL;
+ const char *q_value = NULL;
+ int non_options_count = 0;
+ const char *non_options[10];
+ int unrecognized = 0;
+ bool output;
+ int argc = 0;
+ const char *argv[10];
+
+ argv[argc++] = "program";
+ argv[argc++] = "-ap";
+ argv[argc] = NULL;
+ optind = start;
+ opterr = 1;
+ getopt_loop (argc, argv, "abp:q:",
+ &a_seen, &b_seen, &p_value, &q_value,
+ &non_options_count, non_options, &unrecognized, &output);
+ ASSERT (a_seen == 1);
+ ASSERT (b_seen == 0);
+ ASSERT (p_value == NULL);
+ ASSERT (q_value == NULL);
+ ASSERT (non_options_count == 0);
+ ASSERT (unrecognized == 'p');
+ ASSERT (optind == 2);
+ ASSERT (output);
+ }
+ for (start = OPTIND_MIN; start <= 1; start++)
+ {
+ int a_seen = 0;
+ int b_seen = 0;
+ const char *p_value = NULL;
+ const char *q_value = NULL;
+ int non_options_count = 0;
+ const char *non_options[10];
+ int unrecognized = 0;
+ bool output;
+ int argc = 0;
+ const char *argv[10];
+
+ argv[argc++] = "program";
+ argv[argc++] = "-ap";
+ argv[argc] = NULL;
+ optind = start;
+ opterr = 0;
+ getopt_loop (argc, argv, "abp:q:",
+ &a_seen, &b_seen, &p_value, &q_value,
+ &non_options_count, non_options, &unrecognized, &output);
+ ASSERT (a_seen == 1);
+ ASSERT (b_seen == 0);
+ ASSERT (p_value == NULL);
+ ASSERT (q_value == NULL);
+ ASSERT (non_options_count == 0);
+ ASSERT (unrecognized == 'p');
+ ASSERT (optind == 2);
+ ASSERT (!output);
+ }
+ for (start = OPTIND_MIN; start <= 1; start++)
+ {
+ int a_seen = 0;
+ int b_seen = 0;
+ const char *p_value = NULL;
+ const char *q_value = NULL;
+ int non_options_count = 0;
+ const char *non_options[10];
+ int unrecognized = 0;
+ bool output;
+ int argc = 0;
+ const char *argv[10];
+
+ argv[argc++] = "program";
+ argv[argc++] = "-ap";
+ argv[argc] = NULL;
+ optind = start;
+ opterr = 1;
+ getopt_loop (argc, argv, ":abp:q:",
+ &a_seen, &b_seen, &p_value, &q_value,
+ &non_options_count, non_options, &unrecognized, &output);
+ ASSERT (a_seen == 1);
+ ASSERT (b_seen == 0);
+ ASSERT (p_value == NULL);
+ ASSERT (q_value == NULL);
+ ASSERT (non_options_count == 0);
+ ASSERT (unrecognized == 'p');
+ ASSERT (optind == 2);
+ ASSERT (!output);
}
/* Check that by default, non-options arguments are moved to the end. */
@@ -427,6 +731,7 @@ test_getopt (void)
int non_options_count = 0;
const char *non_options[10];
int unrecognized = 0;
+ bool output;
int argc = 0;
const char *argv[10];
@@ -439,9 +744,10 @@ test_getopt (void)
argv[argc++] = "bar";
argv[argc] = NULL;
optind = start;
+ opterr = 1;
getopt_loop (argc, argv, "abp:q:",
&a_seen, &b_seen, &p_value, &q_value,
- &non_options_count, non_options, &unrecognized);
+ &non_options_count, non_options, &unrecognized, &output);
if (posixly)
{
ASSERT (strcmp (argv[0], "program") == 0);
@@ -459,6 +765,7 @@ test_getopt (void)
ASSERT (non_options_count == 0);
ASSERT (unrecognized == 0);
ASSERT (optind == 1);
+ ASSERT (!output);
}
else
{
@@ -477,6 +784,7 @@ test_getopt (void)
ASSERT (non_options_count == 0);
ASSERT (unrecognized == 0);
ASSERT (optind == 4);
+ ASSERT (!output);
}
}
@@ -490,6 +798,7 @@ test_getopt (void)
int non_options_count = 0;
const char *non_options[10];
int unrecognized = 0;
+ bool output;
int argc = 0;
const char *argv[20];
@@ -507,9 +816,10 @@ test_getopt (void)
argv[argc++] = "bar";
argv[argc] = NULL;
optind = start;
+ opterr = 1;
getopt_loop (argc, argv, "abp:q:",
&a_seen, &b_seen, &p_value, &q_value,
- &non_options_count, non_options, &unrecognized);
+ &non_options_count, non_options, &unrecognized, &output);
if (posixly)
{
ASSERT (strcmp (argv[0], "program") == 0);
@@ -532,6 +842,7 @@ test_getopt (void)
ASSERT (non_options_count == 0);
ASSERT (unrecognized == 0);
ASSERT (optind == 1);
+ ASSERT (!output);
}
else
{
@@ -555,6 +866,7 @@ test_getopt (void)
ASSERT (non_options_count == 0);
ASSERT (unrecognized == 0);
ASSERT (optind == 5);
+ ASSERT (!output);
}
}
@@ -569,6 +881,7 @@ test_getopt (void)
int non_options_count = 0;
const char *non_options[10];
int unrecognized = 0;
+ bool output;
int argc = 0;
const char *argv[10];
@@ -581,9 +894,10 @@ test_getopt (void)
argv[argc++] = "bar";
argv[argc] = NULL;
optind = start;
+ opterr = 1;
getopt_loop (argc, argv, "-abp:q:",
&a_seen, &b_seen, &p_value, &q_value,
- &non_options_count, non_options, &unrecognized);
+ &non_options_count, non_options, &unrecognized, &output);
ASSERT (strcmp (argv[0], "program") == 0);
ASSERT (strcmp (argv[1], "donald") == 0);
ASSERT (strcmp (argv[2], "-p") == 0);
@@ -602,6 +916,7 @@ test_getopt (void)
ASSERT (strcmp (non_options[2], "bar") == 0);
ASSERT (unrecognized == 0);
ASSERT (optind == 7);
+ ASSERT (!output);
}
/* Check that '--' ends the argument processing. */
@@ -614,6 +929,7 @@ test_getopt (void)
int non_options_count = 0;
const char *non_options[10];
int unrecognized = 0;
+ bool output;
int argc = 0;
const char *argv[20];
@@ -631,9 +947,10 @@ test_getopt (void)
argv[argc++] = "bar";
argv[argc] = NULL;
optind = start;
+ opterr = 1;
getopt_loop (argc, argv, "-abp:q:",
&a_seen, &b_seen, &p_value, &q_value,
- &non_options_count, non_options, &unrecognized);
+ &non_options_count, non_options, &unrecognized, &output);
ASSERT (strcmp (argv[0], "program") == 0);
ASSERT (strcmp (argv[1], "donald") == 0);
ASSERT (strcmp (argv[2], "-p") == 0);
@@ -651,6 +968,7 @@ test_getopt (void)
ASSERT (b_seen == 0);
ASSERT (p_value != NULL && strcmp (p_value, "billy") == 0);
ASSERT (q_value == NULL);
+ ASSERT (!output);
if (non_options_count == 2)
{
/* glibc behaviour. */
@@ -687,6 +1005,7 @@ test_getopt (void)
int non_options_count = 0;
const char *non_options[10];
int unrecognized = 0;
+ bool output;
int argc = 0;
const char *argv[10];
@@ -699,9 +1018,10 @@ test_getopt (void)
argv[argc++] = "bar";
argv[argc] = NULL;
optind = start;
+ opterr = 1;
getopt_loop (argc, argv, "abp:q:-",
&a_seen, &b_seen, &p_value, &q_value,
- &non_options_count, non_options, &unrecognized);
+ &non_options_count, non_options, &unrecognized, &output);
if (posixly)
{
ASSERT (strcmp (argv[0], "program") == 0);
@@ -719,6 +1039,7 @@ test_getopt (void)
ASSERT (non_options_count == 0);
ASSERT (unrecognized == 0);
ASSERT (optind == 1);
+ ASSERT (!output);
}
else
{
@@ -737,6 +1058,7 @@ test_getopt (void)
ASSERT (non_options_count == 0);
ASSERT (unrecognized == 0);
ASSERT (optind == 4);
+ ASSERT (!output);
}
}
@@ -751,6 +1073,7 @@ test_getopt (void)
int non_options_count = 0;
const char *non_options[10];
int unrecognized = 0;
+ bool output;
int argc = 0;
const char *argv[10];
@@ -763,9 +1086,10 @@ test_getopt (void)
argv[argc++] = "bar";
argv[argc] = NULL;
optind = start;
+ opterr = 1;
getopt_loop (argc, argv, "+abp:q:",
&a_seen, &b_seen, &p_value, &q_value,
- &non_options_count, non_options, &unrecognized);
+ &non_options_count, non_options, &unrecognized, &output);
ASSERT (strcmp (argv[0], "program") == 0);
ASSERT (strcmp (argv[1], "donald") == 0);
ASSERT (strcmp (argv[2], "-p") == 0);
@@ -781,6 +1105,7 @@ test_getopt (void)
ASSERT (non_options_count == 0);
ASSERT (unrecognized == 0);
ASSERT (optind == 1);
+ ASSERT (!output);
}
for (start = OPTIND_MIN; start <= 1; start++)
{
@@ -791,6 +1116,7 @@ test_getopt (void)
int non_options_count = 0;
const char *non_options[10];
int unrecognized = 0;
+ bool output;
int argc = 0;
const char *argv[10];
@@ -798,9 +1124,13 @@ test_getopt (void)
argv[argc++] = "-+";
argv[argc] = NULL;
optind = start;
+ /* Suppress output, since glibc is inconsistent on whether this
+ prints a message:
+ http://sources.redhat.com/bugzilla/show_bug.cgi?id=11039 */
+ opterr = 0;
getopt_loop (argc, argv, "+abp:q:",
&a_seen, &b_seen, &p_value, &q_value,
- &non_options_count, non_options, &unrecognized);
+ &non_options_count, non_options, &unrecognized, &output);
ASSERT (a_seen == 0);
ASSERT (b_seen == 0);
ASSERT (p_value == NULL);
@@ -808,6 +1138,7 @@ test_getopt (void)
ASSERT (non_options_count == 0);
ASSERT (unrecognized == '+');
ASSERT (optind == 2);
+ ASSERT (!output);
}
/* Check that '--' ends the argument processing. */
@@ -820,6 +1151,7 @@ test_getopt (void)
int non_options_count = 0;
const char *non_options[10];
int unrecognized = 0;
+ bool output;
int argc = 0;
const char *argv[20];
@@ -837,9 +1169,10 @@ test_getopt (void)
argv[argc++] = "bar";
argv[argc] = NULL;
optind = start;
+ opterr = 1;
getopt_loop (argc, argv, "+abp:q:",
&a_seen, &b_seen, &p_value, &q_value,
- &non_options_count, non_options, &unrecognized);
+ &non_options_count, non_options, &unrecognized, &output);
ASSERT (strcmp (argv[0], "program") == 0);
ASSERT (strcmp (argv[1], "donald") == 0);
ASSERT (strcmp (argv[2], "-p") == 0);
@@ -860,6 +1193,7 @@ test_getopt (void)
ASSERT (non_options_count == 0);
ASSERT (unrecognized == 0);
ASSERT (optind = 1);
+ ASSERT (!output);
}
/* Check that the '+' flag has to come first. */
@@ -872,6 +1206,7 @@ test_getopt (void)
int non_options_count = 0;
const char *non_options[10];
int unrecognized = 0;
+ bool output;
int argc = 0;
const char *argv[10];
@@ -884,9 +1219,10 @@ test_getopt (void)
argv[argc++] = "bar";
argv[argc] = NULL;
optind = start;
+ opterr = 1;
getopt_loop (argc, argv, "abp:q:+",
&a_seen, &b_seen, &p_value, &q_value,
- &non_options_count, non_options, &unrecognized);
+ &non_options_count, non_options, &unrecognized, &output);
if (posixly)
{
ASSERT (strcmp (argv[0], "program") == 0);
@@ -904,6 +1240,7 @@ test_getopt (void)
ASSERT (non_options_count == 0);
ASSERT (unrecognized == 0);
ASSERT (optind == 1);
+ ASSERT (!output);
}
else
{
@@ -922,6 +1259,10 @@ test_getopt (void)
ASSERT (non_options_count == 0);
ASSERT (unrecognized == 0);
ASSERT (optind == 4);
+ ASSERT (!output);
}
}
+
+ /* No tests of "-:..." or "+:...", due to glibc bug:
+ http://sources.redhat.com/bugzilla/show_bug.cgi?id=11039 */
}
--
1.6.4.2