Where does getopt_long store an unrecognized option? Where does getopt_long store an unrecognized option? c c

Where does getopt_long store an unrecognized option?


You're quite right that the man page glosses right over these details, but enough hints can be gleaned from the source code, e.g., glibc's implementation in glibc-x.y.z/posix/getopt.c's _getopt_internal_r. (Perhaps that's the only interesting implementation of this GNU extension function?)

That code sets optopt to 0 when it encounters an erroneous long option, which I guess is useful to distinguish this case from an erroneous short option, when optopt will surely be non-NUL.

The error messages produced when opterr != 0 mostly print out the erroneous long option as argv[optind], and later code (always or -- conservatively -- at least mostly) later increments optind before returning.

Hence consider this program:

#include <getopt.h>#include <stdio.h>int main(int argc, char **argv) {  struct option longopts[] = {    { "foo", no_argument, NULL, 'F' },    { NULL, 0, NULL, 0 }  };  int c;  do {    int curind = optind;    c = getopt_long(argc, argv, "f", longopts, NULL);    switch (c) {    case 'f':  printf("-f\n");  break;    case 'F':  printf("--foo\n");  break;    case '?':      if (optopt)  printf("bad short opt '%c'\n", optopt);      else  printf("bad long opt \"%s\"\n", argv[curind]);      break;    case -1:      break;    default:      printf("returned %d\n", c);      break;    }  } while (c != -1);  return 0;}

$ ./longopt -f -x --bar --foo
-f
./longopt: invalid option -- 'x'
bad short opt 'x'
./longopt: unrecognized option '--bar'
bad long opt "--bar"
--foo

Thus in these cases, by caching the pre-getopt_long value of optind, we're easily able to print out the same bad options as the opterr messages.

This may not be quite right in all cases, as the glibc implementation's use of its own __nextchar rather than argv[optind] (in the "unrecognized option" case) deserves study, but it should be enough to get you started.

If you think carefully about the relationship between optind and the repeated invocations of getopt_long, I think printing out argv[cached_optind] is going to be pretty safe. optopt exists because for short options you need to know just which character within the word is the problem, but for long options the problem is the whole current word (modulo stripping off option arguments of the form =param). And the current word is the one that getopt_long is looking at with the (incoming) optind value.

In the absence of a guarantee written in the documentation, I would be somewhat less sanguine about taking advantage of the optopt = 0 behaviour though.


The closest I can find is that if you get a BADCH return the argv item that caused it is in argv[optind-1]. Seems like there should be a better way to find the problem argument.