Correct checking for short option matches in getopt_long_only().

This commit is contained in:
Keith Marshall 2011-05-31 20:24:51 +00:00
parent e60d84e840
commit 2ec2d00e1b
2 changed files with 79 additions and 4 deletions

View File

@ -1,3 +1,12 @@
2011-05-31 Keith Marshall <keithmarshall@users.sourceforge.net>
Correct checking for short option matches in getopt_long_only().
* mingwex/getopt.c (getopt_verify): New static inline function.
(getopt_parse) [getopt_mode_long_only]: Use it, to validate as a
possible short option match after failing to match, or ambiguously
matching as a long option.
2011-05-24 Chris Sutcliffe <ir0nh34d@users.sourceforge.net>
* include/stdlib.h (strtod): Declare as extern to resolve compilation issues.

View File

@ -310,6 +310,48 @@ struct option *opt, int index, int *retindex, const CHAR *optstring )
return opt[index].val;
}
static __inline__
int getopt_verify( const CHAR *nextchar, const CHAR *optstring )
{
/* Helper function, called by getopt_parse() when invoked
* by getopt_long_only(), to verify when an unmatched or an
* ambiguously matched long form option string is valid as
* a short form option specification.
*/
if( ! (nextchar && *nextchar && optstring && *optstring) )
/*
* There are no characters to be matched, or there are no
* valid short form option characters to which they can be
* matched, so this can never be valid.
*/
return 0;
while( *nextchar )
{
/* For each command line character in turn ...
*/
const CHAR *test;
if( (test = getopt_match( *nextchar++, optstring )) == NULL )
/*
* ... there is no short form option to match the current
* candidate, so the entire argument fails.
*/
return 0;
if( test[1] == getopt_takes_argument )
/*
* The current candidate is valid, and it matches an option
* which takes an argument, so this command line argument is
* a valid short form option specification; accept it.
*/
return 1;
}
/* If we get to here, then every character in the command line
* argument was valid as a short form option; accept it.
*/
return 1;
}
static
#define getopt_std_args int argc, CHAR *const argv[], const CHAR *optstring
int getopt_parse( int mode, getopt_std_args, ... )
@ -614,6 +656,22 @@ int getopt_parse( int mode, getopt_std_args, ... )
{
/* if this is not the first, then we have an ambiguity ...
*/
if( (mode == getopt_mode_long_only)
/*
* However, in the case of getopt_long_only(), if
* the entire ambiguously matched string represents
* a valid short option specification, then we may
* proceed to interpret it as such.
*/
&& getopt_verify( nextchar, optstring ) )
return getopt_parse( mode, argc, argv, optstring );
/* If we get to here, then the ambiguously matched
* partial long option isn't valid for short option
* evaluation; reset parser context to resume with
* the following command line argument, diagnose
* ambiguity, and bail out.
*/
optopt = 0;
nextchar = NULL;
optind = argind + 1;
@ -634,11 +692,19 @@ int getopt_parse( int mode, getopt_std_args, ... )
return getopt_resolved( mode, argc, argv, &argind,
longopts, matched, optindex, optstring );
}
if( mode < getopt_mode_long_only )
/* if here, then we had what SHOULD have been a long form option,
* but it is unmatched ...
*/
if( (mode < getopt_mode_long_only)
/*
* ... although paradoxically, `mode == getopt_mode_long_only'
* allows us to still try to match it as a short form option.
*/
|| (getopt_verify( nextchar, optstring ) == 0) )
{
/* if here, then we had what SHOULD have been a long form option,
* but it is unmatched; (perversely, `mode == getopt_mode_long_only'
* allows us to still try to match it as a short form option).
/* When it cannot be matched, reset the parsing context to
* resume from the next argument, diagnose the failed match,
* and bail out.
*/
optopt = 0;
nextchar = NULL;