summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKim Gräsman <kim.grasman@gmail.com>2023-06-24 16:06:44 +0200
committerKim Gräsman <kim.grasman@gmail.com>2023-06-24 16:27:45 +0200
commit36b9ae390740126554aeb3192f7399c873c90889 (patch)
treefd57574dba2b42b89903a5925e2c445ea834600d
parent1d113962b23e814e1bc69b32644d94643eed9002 (diff)
Roll getopt_port to latest version
The new implementation corresponds to https://github.com/kimgr/getopt_port/commit/6ad8cc105b55ad9f83136129fd0c6c2a209da43e. This fixes the ambiguity issue raised in PR #1260.
-rw-r--r--iwyu_getopt.cc21
-rw-r--r--iwyu_getopt.h15
2 files changed, 25 insertions, 11 deletions
diff --git a/iwyu_getopt.cc b/iwyu_getopt.cc
index 77323d1..67c756b 100644
--- a/iwyu_getopt.cc
+++ b/iwyu_getopt.cc
@@ -17,10 +17,6 @@
#include <stddef.h>
#include <string.h>
-const int no_argument = 0;
-const int required_argument = 1;
-const int optional_argument = 2;
-
char* optarg;
int optopt;
/* The variable optind [...] shall be initialized to 1 by the system. */
@@ -98,7 +94,7 @@ int getopt(int argc, char* const argv[], const char* optstring) {
if (optdecl[2] != ':') {
/* If the option was the last character in the string pointed to by
an element of argv, then optarg shall contain the next element
- of argv, and optind shall be incremented by 2. If the resulting
+ of argv, and optind shall be incremented by 2. If the resulting
value of optind is greater than argc, this indicates a missing
option-argument, and getopt() shall return an error indication.
@@ -144,11 +140,12 @@ no_more_optchars:
[1] http://www.kernel.org/doc/man-pages/online/pages/man3/getopt.3.html
*/
int getopt_long(int argc, char* const argv[], const char* optstring,
- const struct option* longopts, int* longindex) {
+ const struct option* longopts, int* longindex) {
const struct option* o = longopts;
const struct option* match = NULL;
int num_matches = 0;
size_t argument_name_length = 0;
+ size_t option_length = 0;
const char* current_argument = NULL;
int retval = -1;
@@ -165,6 +162,16 @@ int getopt_long(int argc, char* const argv[], const char* optstring,
current_argument = argv[optind] + 2;
argument_name_length = strcspn(current_argument, "=");
for (; o->name; ++o) {
+ /* Check for exact match first. */
+ option_length = strlen(o->name);
+ if (option_length == argument_name_length &&
+ strncmp(o->name, current_argument, option_length) == 0) {
+ match = o;
+ num_matches = 1;
+ break;
+ }
+
+ /* If not exact, count the number of abbreviated matches. */
if (strncmp(o->name, current_argument, argument_name_length) == 0) {
match = o;
++num_matches;
@@ -192,7 +199,7 @@ int getopt_long(int argc, char* const argv[], const char* optstring,
++optarg;
if (match->has_arg == required_argument) {
- /* Only scan the next argv for required arguments. Behavior is not
+ /* Only scan the next argv for required arguments. Behavior is not
specified, but has been observed with Ubuntu and Mac OSX. */
if (optarg == NULL && ++optind < argc) {
optarg = argv[optind];
diff --git a/iwyu_getopt.h b/iwyu_getopt.h
index 1a0c697..41ea82b 100644
--- a/iwyu_getopt.h
+++ b/iwyu_getopt.h
@@ -12,10 +12,13 @@
#if defined(_MSC_VER)
-// Hand-rolled implementation of getopt/getopt_long for Visual C++.
-extern const int no_argument;
-extern const int required_argument;
-extern const int optional_argument;
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
+#define no_argument 1
+#define required_argument 2
+#define optional_argument 3
extern char* optarg;
extern int optind, opterr, optopt;
@@ -32,6 +35,10 @@ int getopt(int argc, char* const argv[], const char* optstring);
int getopt_long(int argc, char* const argv[],
const char* optstring, const struct option* longopts, int* longindex);
+#if defined(__cplusplus)
+}
+#endif
+
#else // #if defined(_MSC_VER)
#include <getopt.h> // IWYU pragma: export