Bug 23148

Summary: getopt(3) works non-intuitively?
Product: Base System Reporter: anand <anand>
Component: kernAssignee: freebsd-bugs (Nobody) <bugs>
Status: Closed FIXED    
Severity: Affects Only Me    
Priority: Normal    
Version: 4.2-RELEASE   
Hardware: Any   
OS: Any   
Attachments:
Description Flags
file.diff none

Description anand 2000-11-28 02:00:05 UTC
	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 --.

Fix: This patch to /usr/src/lib/libc/stdlib/getopt.c changes the way getopt
works to the description that I supplied:
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.
Comment 1 iedowse freebsd_committer freebsd_triage 2005-04-17 23:29:40 UTC
State Changed
From-To: open->patched


This has been fixed in 5.x and -CURRENT, but hasn't been merged to 
RELENG_4.
Comment 2 Gavin Atkinson freebsd_committer freebsd_triage 2007-06-09 19:51:52 UTC
State Changed
From-To: patched->closed

Fixed in all supported FreeBSD releases