id,summary,reporter,owner,description,type,status,milestone,component,version,severity,resolution,keywords,cc 4512,[program_options]: wrong option_description returned by options_descriptions::find_nothrow,Soren Soe ,Vladimir Prus,"In 1.43 my code started failing when an option_description has two options where option1 is ""all"" and option2 is ""all-chroots"". I am using command_line_style::allow_guessing and at some point the command_line_parser calls options_description::find_nothrow(""all"",true,...) in options_description.cpp It turns out find_nothrow has changed since the earlier version (1.38) which I am currently using. The old version immediately returned on a full_match: {{{ ... // If we have a full patch, and an approximate match, // ignore approximate match instead of reporting error. // Say, if we have options ""all"" and ""all-chroots"", then // ""--all"" on the command line should select the first one, // without ambiguity. // // For now, we don't check the situation when there are // two full matches. if (r == option_description::full_match) { return m_options[i].get(); } ... }}} But in 1.43, the loop that iterates {{{m_options}}} sets a variable {{{found}}} to which ever match is found last, be that a full_match or an approximate_match: {{{ ... if (r == option_description::full_match) { full_matches.push_back(m_options[i]->key(name)); } else { // FIXME: the use of 'key' here might not // be the best approach. approximate_matches.push_back(m_options[i]->key(name)); } found = m_options[i]; ... }}} Ultimately, the variable {{{found}}} is returned and in my case with the partial match even though there really was a full match. I propose the following implementation of find_nothrow(...). The error checking is unchanged from 1.43 version, but a full_match, if any, will be returned as expected. {{{ const option_description* options_description::find_nothrow(const std::string& name, bool approx, bool long_ignore_case, bool short_ignore_case) const { int found = -1; vector approximate_matches; vector full_matches; // We use linear search because matching specified option // name with the declaraed option name need to take care about // case sensitivity and trailing '*' and so we can't use simple map. for(unsigned i = 0; i < m_options.size(); ++i) { option_description::match_result r = m_options[i]->match(name, approx, long_ignore_case, short_ignore_case); if (r == option_description::no_match) continue; if (r == option_description::full_match) { full_matches.push_back(m_options[i]->key(name)); // Use this full match regardless of other matches found. found = i; } else { // FIXME: the use of 'key' here might not // be the best approach. approximate_matches.push_back(m_options[i]->key(name)); // If this is the first match found the use it. If // a later full match is found that will be used instead. if (found == -1) found = i; } } if (full_matches.size() > 1) boost::throw_exception( ambiguous_option(name, full_matches)); if (full_matches.empty() && approximate_matches.size() > 1) boost::throw_exception( ambiguous_option(name, approximate_matches)); return found>=0 ? m_options[found].get() : 0; } }}} I have attached my modified version of options_description.cpp",Bugs,closed,Boost 1.44.0,program_options,Boost 1.44.0,Problem,fixed,,