diff options
-rw-r--r-- | winsup/mingw/ChangeLog | 9 | ||||
-rw-r--r-- | winsup/mingw/mingwex/getopt.c | 74 |
2 files changed, 79 insertions, 4 deletions
diff --git a/winsup/mingw/ChangeLog b/winsup/mingw/ChangeLog index 083981c6f..d0c6c6730 100644 --- a/winsup/mingw/ChangeLog +++ b/winsup/mingw/ChangeLog @@ -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. diff --git a/winsup/mingw/mingwex/getopt.c b/winsup/mingw/mingwex/getopt.c index 4f081d18d..b26e97c43 100644 --- a/winsup/mingw/mingwex/getopt.c +++ b/winsup/mingw/mingwex/getopt.c @@ -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; |