On Sun, Mar 15, 2020 at 09:30:22AM +0100, Martijn van Duren wrote: > > --- 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) > > > From my research you're close, but not quite. > This particular case is for handling the actual "-" string.
Nope. That's already handled above: start: if (optreset || !*place) { /* update scanning pointer */ ... if (*(place = nargv[optind]) != '-' || (place[1] == '\0' && strchr(options, '-') == NULL)) { Notice that OpenBSD's getopt(3) explicitly allows to use "-" as an option character, and there may be a /separate/ bug related to that, but my patch doesn't change or affect it in any way. But in the case I'm WRONG, could you prove your point with a test? OpenBSD's getopt_long.c is self-contained. Copy it into some other directory, apply my patch, and try with the simple getopt-test.c test-case program at the end of this message: cp /PATH/TO/OPENBSD-SRC/lib/libc/stdlib/getopt_long.c getopt_long.c patch -s < MY_PREVIOUS_MESSAGE getopt_long.c cc -O2 -W -Wall getopt-test.c getopt_long.c -o getopt-test cc -O2 -W -Wall getopt-test.c -o getopt-test-unpatched # as expected: OPTS=pq: ./getopt-test -p - x y z {./getopt-test} <p> | {-} {x} {y} {z} OPTS=pq: ./getopt-test -pq - x y z {./getopt-test} <p> <q>={-} | {x} {y} {z} OPTS=pq: ./getopt-test -pq - - x y z {./getopt-test} <p> <q>={-} | {-} {x} {y} {z} # bugs in the unpatched version, demonstrated: OPTS=q ./getopt-test-unpatched -q- arg {./getopt-test-unpatched} <q> | {-q-} {arg} OPTS=-p ./getopt-test-unpatched -p-- -- arg getopt-test-unpatched: unknown option -- - {./getopt-test-unpatched} <p> #U- | {-p--} {--} {arg} OPTS=p-: ./getopt-test-unpatched -p-- -- arg getopt-test-unpatched: unknown option -- - {./getopt-test-unpatched} <p> #U- <->={--} | {arg} =================================================================== getopt-test.c =================================================================== #include <unistd.h> #include <stdlib.h> #include <string.h> #include <stdio.h> static int showargs(int ac, char **av, char *os){ char *s; int c, i; if(ac < 1) return 1; printf("{%s}", av[0]); while((c = getopt(ac, av, os)) != -1) switch(c){ case '?': printf(" #U%c", optopt); break; case ':': printf(" #A%c", optopt); break; case '\1': printf(" <\\1>={%s}", optarg); break; default: if((s = strrchr(os, c)) && s[1] == ':') printf(" <%c>={%s}", c, optarg); else printf(" <%c>", c); } printf(" |"); for(i = optind; i < ac; i++) printf(" {%s}", av[i]); printf("\n"); return 0; } int main(int ac, char **av){ char *os; if(!(os = getenv("OPTS"))) os = ""; return showargs(ac, av, os); }