Opened 12 years ago
Closed 12 years ago
#4512 closed Bugs (fixed)
[program_options]: wrong option_description returned by options_descriptions::find_nothrow
Reported by: | Owned by: | Vladimir Prus | |
---|---|---|---|
Milestone: | Boost 1.44.0 | Component: | program_options |
Version: | Boost 1.44.0 | Severity: | Problem |
Keywords: | Cc: |
Description
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<string> approximate_matches; vector<string> 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
Attachments (1)
Change History (4)
by , 12 years ago
Attachment: | options_description.cpp added |
---|
comment:1 by , 12 years ago
comment:3 by , 12 years ago
Resolution: | → fixed |
---|---|
Status: | new → closed |
Could you please try trunk or just published 1.44 beta? This issue should be fixed there.