| Summary: | getopt(3) works non-intuitively? | ||||||
|---|---|---|---|---|---|---|---|
| Product: | Base System | Reporter: | anand <anand> | ||||
| Component: | kern | Assignee: | freebsd-bugs (Nobody) <bugs> | ||||
| Status: | Closed FIXED | ||||||
| Severity: | Affects Only Me | ||||||
| Priority: | Normal | ||||||
| Version: | 4.2-RELEASE | ||||||
| Hardware: | Any | ||||||
| OS: | Any | ||||||
| Attachments: |
|
||||||
State Changed From-To: open->patched This has been fixed in 5.x and -CURRENT, but hasn't been merged to RELENG_4. State Changed From-To: patched->closed Fixed in all supported FreeBSD releases |
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.