To wrap this up and get if off my plate, here is the updated patch, and a testcase program together with what should be (imvho) the correct output.
Please do NOT assume that I'm insisting or that I have any personal interest to have this included, considered, etc. The testcase is a stripped down version of a much messier thing which was also handling getopt_long() and getopt_long_only(). The output of the testcase in is in the form: << "q" ["prog", "-pq", "a1", "a2"] gopts: unknown option -- p >> {prog} #Up <q> | {a1} {a2} ie '<< input', '>> expected output' with the expected error messages in between. ===== patch to lib/libc/stdlib/getopt_long.c ====== --- getopt-long.c~ 2020-03-12 02:23:29.028903616 +0200 +++ getopt-long.c 2020-03-15 23:46:07.988119523 +0200 @@ -418,15 +418,7 @@ } 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); if (!*place) ++optind; if (PRINT_ERROR) ====== gopts.c ===================================== #include <unistd.h> #include <stdlib.h> #include <string.h> #include <stdio.h> static void showargs(int ac, char **av, char *os){ int c, i; if(ac > 0) printf("{%s} ", av[0]); for(optarg = 0; (c = getopt(ac, av, os)) != -1; optarg = 0) switch(c){ case '?': printf("#U%c ", optopt); break; case ':': printf("#A%c ", optopt); break; default: printf(c >= ' ' && c <= '~' ? "<%c>" : c < 8 ? "<\\%d>" : "<\\x%02x", c); if(optarg) printf("={%s}", optarg); printf(" "); } printf("|"); for(i = optind; i < ac; i++) printf(" {%s}", av[i]); printf("\n"); } static void test(int oi, char *os, char **av, char *buf, int blen){ int ac, l; char *s; printf("<< %s\n>> ", buf); for(ac = 0, s = buf; av[ac]; ac++, s += l + 1){ l = strlen(av[ac]); memcpy(s, av[ac], l + 1); av[ac] = s; } optind = oi; showargs(ac, av, os); printf("\n"); memset(buf, ':', blen); /* clobber it */ } #define TEST(oi, os, ...) do{\ char *av[] = { __VA_ARGS__, NULL };\ static char buf[] = #os " [" #__VA_ARGS__ "]";\ test(oi, os, av, buf, sizeof buf);\ }while(0) int main(int ac, char **av){ char *t; int oi = (t = getenv("OI")) ? *t - '0' : 1; if(ac > 1){ optind = oi; showargs(ac - 2, av + 2, av[1]); return 0; } dup2(1, 2); setvbuf(stdout, NULL, _IOLBF, 0); setvbuf(stderr, NULL, _IOLBF, 0); TEST(oi, "q", "prog", "-q-"); TEST(oi, "-q", "prog", "-q--", "--", "arg"); TEST(oi, "p-:", "prog", "-p--", "--", "arg"); TEST(oi, "q-", "---", "--", "arg"); TEST(oi, "q-", "---", "arg"); TEST(oi, "p:", "prog", "-p"); TEST(oi, "p", "prog", "-p", "arg"); TEST(oi, "q", "prog", "-q", "arg"); TEST(oi, "-q", "prog", "-q", "a1", "a2"); } ====== gopts.output ================================ << "q" ["prog", "-q-"] gogs-o: unknown option -- - >> {prog} <q> #U- | << "-q" ["prog", "-q--", "--", "arg"] gogs-o: unknown option -- - gogs-o: unknown option -- - >> {prog} <q> #U- #U- | {arg} << "p-:" ["prog", "-p--", "--", "arg"] >> {prog} <p> <->={-} | {arg} << "q-" ["---", "--", "arg"] >> {---} | {arg} << "q-" ["---", "arg"] >> {---} | {arg} << "p:" ["prog", "-p"] gogs-o: option requires an argument -- p >> {prog} #Up | << "p" ["prog", "-p", "arg"] >> {prog} <p> | {arg} << "q" ["prog", "-q", "arg"] >> {prog} <q> | {arg} << "-q" ["prog", "-q", "a1", "a2"] >> {prog} <q> <\1>={a1} <\1>={a2} |