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.