$ cat > opts.c <<'EOT' && cc -Wall -W opts.c -o opts #include <stdio.h> #include <unistd.h> int main(int ac, char **av){ int c, i; while((c = getopt(ac, av, "q")) != -1) if(c != '?' && c != ':') printf("OPT %c\n", c); for(i = optind; i < ac; i++) printf("%s\n", av[i]); } EOT
$ ./opts -q- arg OPT q -q- arg On any other platform (except those where OpenBSD's getopt_long.c made its way) this will complain about an unknown option "-", and leave "optind" pointing to the next argument, not to "-q-": linux$ ./opts -q- arg OPT q ./opts: illegal option -- - arg [or "unrecognized option: -", "invalid option -- '-'", etc] ------------------------------------------------------------------------ The code in getopt_long.c says: /* * If the user specified "-" and '-' isn't listed in * options, return -1 (non-option) as per POSIX. * Otherwise, it is an unknown option character (or ':'). */ if (optchar == (int)'-' && *place == '\0') return (-1); If that is supposed to catch a "--" option end marker, it doesn't seem to, because it's already caught by the code above it: if (optreset || !*place) { /* update scanning pointer */ ... /* * If we have "-" do nothing, if "--" we are done. */ if (place[1] != '\0' && *++place == '-' && place[1] == '\0') { optind++; place = EMSG; ... return (-1); } If not, could you point me where the POSIX standard requires the OpenBSD's behavior? ------------------------------------------------------------------------ In case this is not a completely bogus report, maybe the patch below could do -- not tested very much. The extra "oli == options" condition is to handle the GNU getopt's "optstring starting with '-' => \1=optarg" extension, also implemented by OpenBSD's getopt_long.c. If this is correct, these are sub-bugs in the current code, that this patch is also fixing: getopt("-p", ["prog", "-p--", "--", "arg"]) => fails to skip the "--" getopt("p-:", ["prog", "-p--", "--", "arg"]) => complains about unknown option "-", but still sets the "-" option to "--" (not to "-"!) --- lib/libc/stdlib/getopt_long.c~ +++ lib/libc/stdlib/getopt_long.c @@ -418,15 +418,8 @@ } if ((optchar = (int)*place++) == (int)':' || - (optchar == (int)'-' && *place != '\0') || - (oli = strchr(options, optchar)) == NULL) { - /* - * If the user specified "-" and '-' isn't listed in - * options, return -1 (non-option) as per POSIX. - * Otherwise, it is an unknown option character (or ':'). - */ - if (optchar == (int)'-' && *place == '\0') - return (-1); + ((oli = strchr(options, optchar)) == NULL || + (optchar == (int)'-' && oli == options))) { if (!*place) ++optind; if (PRINT_ERROR)