The only standard thing is setting optind = 1
.
The SUSv4 standard makes no mention of optreset
and declares optind = 0
"unspecified":
If the application sets optind
to zero before calling getopt()
, the behavior is unspecified.
Otherwise, the standard it vague, and does not say anything at all about calling getopt()
multiple times, neither allowing it nor declaring it undefined.
Also, there are no defines which say if optind = 0
or optreset
are supported (fwiw the former is supported on OpenBSD, but not on FreeBSD, and the latter on Linux/musl, but not on Linux/glibc), so there can't be any reliable way to detect it via #ifdef
s.
Weren't for bugs in fancy getopt/_long
implementations (see below), just setting optind = 1
to restart getopt()
should work fine as long as
a) you don't use any GNU extensions:
A program that scans multiple argument vectors, or rescans the same
vector more than once, and wants to make use of GNU extensions such as
+
and -
at the start of optstring, or changes the value of
POSIXLY_CORRECT
between scans, must reinitialize getopt()
by resetting
optind
to 0
,
b) you don't restart the getopt()
in the middle, before it has returned -1
. Eg. from FreeBSD's getopt
:
#define BADCH (int)'?'
#define BADARG (int)':'
#define EMSG ""
...
int
getopt(int nargc, char * const nargv[], const char *ostr)
{
static char *place = EMSG; /* option letter processing */
...
if (optreset || *place == 0) { /* update scanning pointer */
optreset = 0;
...
place = EMSG;
return (-1);
...
place = EMSG;
return (-1);
...
place = EMSG;
if (strchr(ostr, '-') == NULL)
return (-1);
...
return (BADCH);
...
return (BADARG);
...
return (BADCH);
...
return (optopt); /* return option letter */
}
Bugs
The glibc implementation of getopt
will cling to stale state even after returning -1
. This may result in stupid bugs and crashes if the old strings are freed.
The OpenBSD implementation will do likewise, but only when a bogus -
option is used, as in getopt("q", ["prog", "-q-", NULL])
. Notice that OpenBSD's getopt_long
implementation may have made its way as the default getopt()
into other systems like Solaris and Android.