[Boost-bugs] [Boost C++ Libraries] #4512: [program_options]: wrong option_description returned by options_descriptions::find_nothrow

Subject: [Boost-bugs] [Boost C++ Libraries] #4512: [program_options]: wrong option_description returned by options_descriptions::find_nothrow
From: Boost C++ Libraries (noreply_at_[hidden])
Date: 2010-08-05 22:17:56


#4512: [program_options]: wrong option_description returned by
options_descriptions::find_nothrow
----------------------------------------------+-----------------------------
 Reporter: Soren Soe <soren.soe@…> | Owner: vladimir_prus
     Type: Bugs | Status: new
Milestone: Boost 1.44.0 | Component: program_options
  Version: Boost 1.44.0 | Severity: Problem
 Keywords: |
----------------------------------------------+-----------------------------
 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

-- 
Ticket URL: <https://svn.boost.org/trac/boost/ticket/4512>
Boost C++ Libraries <http://www.boost.org/>
Boost provides free peer-reviewed portable C++ source libraries.

This archive was generated by hypermail 2.1.7 : 2017-02-16 18:50:04 UTC