Subject: RFC: getopt_long(3) change
To: None <tech-userlevel@NetBSD.org>
From: Brian Ginsbach <ginsbach@NetBSD.org>
List: tech-userlevel
Date: 06/21/2007 20:50:11
I'd like to make the following change to getopt_long(3).  The
current NetBSD version of getopt_long(3) does not match the behavior
of GNU getopt_long(3) when dealing with potentially abmiguous
arguments.  I first noticed this while trying to create a package
for trueprint.  It is also why I wrote the regression test for
getopt_long(3).

Anyone see any problems with making this change?  Does it require
cranking the library version?


Index: lib/libc/stdlib/getopt_long.c
===================================================================
RCS file: /cvsroot/src/lib/libc/stdlib/getopt_long.c,v
retrieving revision 1.20
diff -u -r1.20 getopt_long.c
--- lib/libc/stdlib/getopt_long.c	4 Oct 2006 17:29:42 -0000	1.20
+++ lib/libc/stdlib/getopt_long.c	17 Jan 2007 20:17:59 -0000
@@ -371,10 +371,11 @@
 	if (retval == -2) {
 		char *current_argv, *has_equal;
 		size_t current_argv_len;
-		int i, match;
+		int i, ambiguous, match;
 
 		current_argv = __UNCONST(place);
 		match = -1;
+		ambiguous = 0;
 
 		optind++;
 		place = EMSG;
@@ -409,18 +410,25 @@
 			    (unsigned)current_argv_len) {
 				/* exact match */
 				match = i;
+				ambiguous = 0;
 				break;
 			}
+#define lopts	long_options
 			if (match == -1)		/* partial match */
 				match = i;
-			else {
-				/* ambiguous abbreviation */
-				if (PRINT_ERROR)
-					warnx(ambig, (int)current_argv_len,
-					     current_argv);
-				optopt = 0;
-				return BADCH;
-			}
+			else if (!(lopts[i].has_arg == lopts[match].has_arg &&
+				   lopts[i].flag == lopts[match].flag &&
+				   lopts[i].val == lopts[match].val))
+				ambiguous = 1;
+#undef lopts
+		}
+		if (ambiguous) {
+			/* ambiguous abbreviation */
+			if (PRINT_ERROR)
+				warnx(ambig, (int)current_argv_len,
+				     current_argv);
+			optopt = 0;
+			return BADCH;
 		}
 		if (match != -1) {			/* option found */
 		        if (long_options[match].has_arg == no_argument
Index: regress/lib/libc/stdlib/getopt_long/opttest
===================================================================
RCS file: /cvsroot/src/regress/lib/libc/stdlib/getopt_long/opttest,v
retrieving revision 1.1
diff -u -r1.1 opttest
--- regress/lib/libc/stdlib/getopt_long/opttest	18 Jan 2007 16:29:21 -0000	1.1
+++ regress/lib/libc/stdlib/getopt_long/opttest	19 Jun 2007 20:46:13 -0000
@@ -19,9 +19,9 @@
 # This is promblematic
 args:	foo --col
 # GNU libc 2.1.3 this fails with ambiguous
-result:	!?|0
+#result:	!?|0
 # GNU libc 2.2 >= this works
-#result:	color|0
+result:	color|0
 #
 args:	foo --colour
 result:	-colour|0
@@ -30,6 +30,6 @@
 args:	foo -a -b -cfoobar --required foobar --optional=bazbug --none random \
 		--col --color --colour
 # GNU libc 2.1.3 this fails with ambiguous
-result:	a,b,c=foobar,-required=foobar,-optional=bazbug,-none,!?,-color,-colour|1
+#result:	a,b,c=foobar,-required=foobar,-optional=bazbug,-none,!?,-color,-colour|1
 # GNU libc 2.2 >= this works
-#result:	a,b,c=foobar,-required=foobar,-optional=bazbug,-none,-color,-color,-colour|1
+result:	a,b,c=foobar,-required=foobar,-optional=bazbug,-none,-color,-color,-colour|1