Fix MinGW-Bug [2144266]: getopt() sets `optind' incorrectly.

This commit is contained in:
Keith Marshall 2008-10-03 22:56:18 +00:00
parent 13ff1518ee
commit e77c4e6672
2 changed files with 55 additions and 26 deletions

View File

@ -1,3 +1,14 @@
2008-10-03 Keith Marshall <keithmarshall@users.sourceforge.net>
Fix MinGW-Bug [2144266]: getopt() sets `optind' incorrectly.
(Reported by Christian Franke)
* mingwex/getopt.c (optind): Make global variable value conform to
behaviour specified by POSIX; do not use it for internal state in...
(getopt_parse): ...this static function; use...
(optbase): ...this new static local variable instead.
(getopt_resolved): Update `optind' as required.
2008-10-03 Keith Marshall <keithmarshall@users.sourceforge.net> 2008-10-03 Keith Marshall <keithmarshall@users.sourceforge.net>
Improve package identification in configure script. Improve package identification in configure script.

View File

@ -254,6 +254,12 @@ struct option *opt, int index, int *retindex, const CHAR *optstring )
if( retindex != NULL ) if( retindex != NULL )
*retindex = index; *retindex = index;
/* On return, `optind' should normally refer to the argument, if any,
* which follows the current one; it is convenient to set this, before
* checking for the presence of any `optarg'.
*/
optind = *argind + 1;
if( optarg && (opt[index].has_arg == no_argument) ) if( optarg && (opt[index].has_arg == no_argument) )
/* /*
* it is an error for the user to specify an option specific argument * it is an error for the user to specify an option specific argument
@ -267,12 +273,12 @@ struct option *opt, int index, int *retindex, const CHAR *optstring )
/* similarly, it is an error if no argument is specified /* similarly, it is an error if no argument is specified
* with an option which requires one ... * with an option which requires one ...
*/ */
if( (*argind + 1) < argc ) if( optind < argc )
/* /*
* ... except that the requirement may be satisfied from * ... except that the requirement may be satisfied from
* the following comand line argument, if any ... * the following command line argument, if any ...
*/ */
optarg = argv[++*argind]; optarg = argv[*argind = optind++];
else else
/* so fail this case, only if no such argument exists! /* so fail this case, only if no such argument exists!
@ -303,19 +309,23 @@ int getopt_parse( int mode, getopt_std_args, ... )
/* Common core implementation for ALL `getopt' functions. /* Common core implementation for ALL `getopt' functions.
*/ */
static int argind = 0; static int argind = 0;
static int optbase = 0;
static const CHAR *nextchar = NULL; static const CHAR *nextchar = NULL;
static int optmark = 0; static int optmark = 0;
if( (argind == 0) || (optind == 0) ) if( optind < optbase )
{ {
/* POSIX wants `optind' to have an initial value of one, but we want /* POSIX does not prescribe any definitive mechanism for restarting
* it to be initialised to zero, when we are called for the first time, * a `getopt' scan, but some applications may require such capability.
* (as indicated by `argind' having a value of zero). We also want to * We will support it, by allowing the caller to adjust the value of
* allow the caller to reset the `getopt' parser, causing it to scan * `optind' downwards, (nominally setting it to zero). Since POSIX
* the arguments again, (or to scan a new set of arguments); this * wants `optind' to have an initial value of one, but we want all
* may be achieved by the caller resetting `optind' to zero. * of our internal placeholders to be initialised to zero, when we
* are called for the first time, we will handle such a reset by
* adjusting all of the internal placeholders to one less than the
* adjusted `optind' value, (but never to less than zero).
*/ */
optmark = optind = argind = 0; optmark = optbase = argind = (optind > 0) ? optind - 1 : 0;
nextchar = NULL; nextchar = NULL;
} }
@ -363,10 +373,12 @@ int getopt_parse( int mode, getopt_std_args, ... )
return getopt_missing_arg( optstring ); return getopt_missing_arg( optstring );
} }
} }
optind = argind + 1;
nextchar = NULL; nextchar = NULL;
} }
else else
optarg = NULL; optarg = NULL;
optind = (nextchar && *nextchar) ? argind : argind + 1;
return optopt; return optopt;
} }
/* if we didn't find a valid match for the specified option character, /* if we didn't find a valid match for the specified option character,
@ -378,11 +390,13 @@ int getopt_parse( int mode, getopt_std_args, ... )
nextchar = NULL; nextchar = NULL;
optopt = 0; optopt = 0;
} }
else complain( "invalid option -- %c", optopt ); else
complain( "invalid option -- %c", optopt );
optind = (nextchar && *nextchar) ? argind : argind + 1;
return getopt_unknown; return getopt_unknown;
} }
if( optmark > optind ) if( optmark > optbase )
{ {
/* This can happen, in GNU parsing mode ONLY, when we have /* This can happen, in GNU parsing mode ONLY, when we have
* skipped over non-option arguments, and found a subsequent * skipped over non-option arguments, and found a subsequent
@ -416,25 +430,25 @@ int getopt_parse( int mode, getopt_std_args, ... )
* overwriting these saved arguments, while making space * overwriting these saved arguments, while making space
* to replace them in their permuted location. * to replace them in their permuted location.
*/ */
for( --optmark; optmark >= optind; --optmark ) for( --optmark; optmark >= optbase; --optmark )
arglist[optmark + optspan] = arglist[optmark]; arglist[optmark + optspan] = arglist[optmark];
/* restore the temporarily saved option arguments to /* restore the temporarily saved option arguments to
* their permuted location. * their permuted location.
*/ */
for( index = 0; index < optspan; ++index ) for( index = 0; index < optspan; ++index )
arglist[optind + index] = this_arg[index]; arglist[optbase + index] = this_arg[index];
/* adjust `optind', to account for the relocated option. /* adjust `optbase', to account for the relocated option.
*/ */
optind += optspan; optbase += optspan;
} }
else else
/* no permutation occurred ... /* no permutation occurred ...
* simply adjust `optind' for all options parsed so far. * simply adjust `optbase' for all options parsed so far.
*/ */
optind = argind + 1; optbase = argind + 1;
/* enter main parsing loop ... /* enter main parsing loop ...
*/ */
@ -468,7 +482,7 @@ int getopt_parse( int mode, getopt_std_args, ... )
{ {
/* this is an explicit `--' end of options marker, so wrap up now! /* this is an explicit `--' end of options marker, so wrap up now!
*/ */
if( optmark > optind ) if( optmark > optbase )
{ {
/* permuting the argument list as necessary ... /* permuting the argument list as necessary ...
* (note use of `this_arg' and `arglist', as above). * (note use of `this_arg' and `arglist', as above).
@ -479,16 +493,16 @@ int getopt_parse( int mode, getopt_std_args, ... )
/* move all preceding non-option arguments to the right ... /* move all preceding non-option arguments to the right ...
*/ */
do arglist[optmark] = arglist[optmark - 1]; do arglist[optmark] = arglist[optmark - 1];
while( optmark-- > optind ); while( optmark-- > optbase );
/* reinstate the `--' marker, in its permuted location. /* reinstate the `--' marker, in its permuted location.
*/ */
arglist[optind] = this_arg; arglist[optbase] = this_arg;
} }
/* ... before finally bumping `optind' past the `--' marker, /* ... before finally bumping `optbase' past the `--' marker,
* and returning the `all done' completion indicator. * and returning the `all done' completion indicator.
*/ */
++optind; optind = ++optbase;
return getopt_all_done; return getopt_all_done;
} }
} }
@ -549,9 +563,10 @@ int getopt_parse( int mode, getopt_std_args, ... )
{ {
/* if this is not the first, then we have an ambiguity ... /* if this is not the first, then we have an ambiguity ...
*/ */
complain( "option `%s' is ambiguous", argv[argind] );
nextchar = NULL;
optopt = 0; optopt = 0;
nextchar = NULL;
optind = argind + 1;
complain( "option `%s' is ambiguous", argv[argind] );
return getopt_unknown; return getopt_unknown;
} }
/* otherwise just note that we've found a possible match ... /* otherwise just note that we've found a possible match ...
@ -576,6 +591,7 @@ int getopt_parse( int mode, getopt_std_args, ... )
*/ */
optopt = 0; optopt = 0;
nextchar = NULL; nextchar = NULL;
optind = argind + 1;
complain( "unrecognised option `%s'", argv[argind] ); complain( "unrecognised option `%s'", argv[argind] );
return getopt_unknown; return getopt_unknown;
} }
@ -601,6 +617,7 @@ int getopt_parse( int mode, getopt_std_args, ... )
* option, with return value defined as `getopt_ordered'. * option, with return value defined as `getopt_ordered'.
*/ */
nextchar = NULL; nextchar = NULL;
optind = argind + 1;
optarg = argv[argind]; optarg = argv[argind];
return getopt_ordered; return getopt_ordered;
} }
@ -615,6 +632,7 @@ int getopt_parse( int mode, getopt_std_args, ... )
} }
/* fall through when all arguments have been evaluated, /* fall through when all arguments have been evaluated,
*/ */
optind = optbase;
return getopt_all_done; return getopt_all_done;
} }