From anand@desktop.com  Mon Nov 27 17:52:00 2000
Return-Path: <anand@desktop.com>
Received: from wooster.jumpdata.com (flimsy.lean.to [166.90.128.243])
	by hub.freebsd.org (Postfix) with ESMTP id 6A07937B4CF
	for <FreeBSD-gnats-submit@freebsd.org>; Mon, 27 Nov 2000 17:52:00 -0800 (PST)
Received: (from anand@localhost)
	by wooster.jumpdata.com (8.11.1/8.11.1) id eAS1qHo59965;
	Mon, 27 Nov 2000 17:52:17 -0800 (PST)
	(envelope-from anand)
Message-Id: <200011280152.eAS1qHo59965@wooster.jumpdata.com>
Date: Mon, 27 Nov 2000 17:52:17 -0800 (PST)
From: anand@blandings.com
Sender: anand@desktop.com
Reply-To: anand@blandings.com
To: FreeBSD-gnats-submit@freebsd.org
Subject: getopt(3) works non-intuitively?
X-Send-Pr-Version: 3.2

>Number:         23148
>Category:       kern
>Synopsis:       getopt(3) works non-intuitively?
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    freebsd-bugs
>State:          closed
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Mon Nov 27 18:00:05 PST 2000
>Closed-Date:    Sat Jun 09 18:53:29 GMT 2007
>Last-Modified:  Sat Jun 09 18:53:29 GMT 2007
>Originator:     Anand Ranganathan
>Release:        FreeBSD 4.2-RELEASE i386
>Organization:
>Environment:

	FreeBSD 4.2-RELEASE i386

>Description:

	The getopt(3) man page says:
The interpretation of op-
tions in the argument list may be cancelled by the option `--' (double
dash) which causes getopt() to signal the end of argument processing and
return -1.

        And fair enough, the getopt function seems to conform to this
description. However, this includes the option '--' not occuring by itself
(e.g., if the program were passed the argument --foo in the GNU style by
mistake), or if -- were inferred by an option of the form -abcd-

Both of these occurences are treated by the getopt function to be the
option --, whereas it seems intuitively to be an occurence of the option
'-' and not an occurence of --.


>How-To-Repeat:

Consider the following program:

#include <unistd.h>

int
main(int argc, char *argv[])
{
        char ch;
        while ((ch = getopt(argc, argv, "abc")) != -1) {
                switch (ch) {
                case 'a':
                        printf("-a\n");
                        break;
                case 'b':
                        printf("-b\n");
                        break;
                case 'c':
                        printf("-c\n");
                        break;
                default:
                        printf("huh\n");
                        break;
                }
        }
        return 0;
}

If you were to compile and run this program:
229 wooster:/usr/tmp> ./a.out -f
a.out: illegal option -- f
huh
230 wooster:/usr/tmp> ./a.out -af
-a
a.out: illegal option -- f
huh
231 wooster:/usr/tmp> ./a.out -a-f
-a
232 wooster:/usr/tmp> ./a.out --foo
233 wooster:/usr/tmp> 

This gets weirder still when you use a standard program called ls with
gnu-style arguments. e.g.,

239 wooster:tmp/foo> touch bar baz
240 wooster:tmp/foo> ls
bar     baz
241 wooster:tmp/foo> ls --color
bar     baz
242 wooster:tmp/foo> ls --foobarbaz
bar     baz
243 wooster:tmp/foo> 

Essentially, getopt considers --color to be an occurence of --, but
swallows the --color option.

With the fix that I'm supplying below, the same program given above works
like so:

245 wooster:/usr/tmp> ./a.out -f
a.out: illegal option -- f
huh
246 wooster:/usr/tmp> ./a.out -af
-a
a.out: illegal option -- f
huh
247 wooster:/usr/tmp> ./a.out -a-f
-a
a.out: illegal option -- -
huh
a.out: illegal option -- f
huh
248 wooster:/usr/tmp> ./a.out --foo
a.out: illegal option -- -
huh
a.out: illegal option -- f
huh
a.out: illegal option -- o
huh
a.out: illegal option -- o
huh
249 wooster:/usr/tmp> ./a.out -- foo
250 wooster:/usr/tmp> 

To me this seems more intuitive.

>Fix:

This patch to /usr/src/lib/libc/stdlib/getopt.c changes the way getopt
works to the description that I supplied:

--- getopt.c.orig	Mon Nov 27 15:27:57 2000
+++ getopt.c	Mon Nov 27 16:29:31 2000
@@ -73,7 +73,7 @@
 			place = EMSG;
 			return (-1);
 		}
-		if (place[1] && *++place == '-') {	/* found "--" */
+		if (place[1] && *++place == '-' && !place[1]) {	/* found "--" */
 			++optind;
 			place = EMSG;
 			return (-1);
@@ -81,12 +81,6 @@
 	}					/* option letter okay? */
 	if ((optopt = (int)*place++) == (int)':' ||
 	    !(oli = strchr(ostr, optopt))) {
-		/*
-		 * if the user didn't specify '-' as an option,
-		 * assume it means -1.
-		 */
-		if (optopt == (int)'-')
-			return (-1);
 		if (!*place)
 			++optind;
 		if (opterr && *ostr != ':' && optopt != BADCH)



>Release-Note:
>Audit-Trail:
State-Changed-From-To: open->patched 
State-Changed-By: iedowse 
State-Changed-When: Sun Apr 17 22:29:40 GMT 2005 
State-Changed-Why:  

This has been fixed in 5.x and -CURRENT, but hasn't been merged to 
RELENG_4. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=23148 
State-Changed-From-To: patched->closed 
State-Changed-By: gavin 
State-Changed-When: Sat Jun 9 18:51:52 UTC 2007 
State-Changed-Why:  
Fixed in all supported FreeBSD releases 

http://www.freebsd.org/cgi/query-pr.cgi?pr=23148 
>Unformatted:
 Anand Ranganathan
