$include_dir="/home/hyper-archives/boost-commit/include"; include("$include_dir/msg-header.inc") ?>
Subject: [Boost-commit] svn:boost r58152 - in trunk: boost/program_options libs/program_options/src libs/program_options/test
From: s.ochsenknecht_at_[hidden]
Date: 2009-12-05 03:08:46
Author: s_ochsenknecht
Date: 2009-12-05 03:08:45 EST (Sat, 05 Dec 2009)
New Revision: 58152
URL: http://svn.boost.org/trac/boost/changeset/58152
Log:
better detection of ambiguous options, see Ticket #3423
Text files modified: 
   trunk/boost/program_options/errors.hpp                 |     6 +++-                                    
   trunk/libs/program_options/src/options_description.cpp |    35 ++++++++++++++++++-------------         
   trunk/libs/program_options/src/value_semantic.cpp      |     6 +++++                                   
   trunk/libs/program_options/test/exception_test.cpp     |    44 +++++++++++++++++++++++---------------- 
   4 files changed, 56 insertions(+), 35 deletions(-)
Modified: trunk/boost/program_options/errors.hpp
==============================================================================
--- trunk/boost/program_options/errors.hpp	(original)
+++ trunk/boost/program_options/errors.hpp	2009-12-05 03:08:45 EST (Sat, 05 Dec 2009)
@@ -78,17 +78,19 @@
         ambiguous_option(const std::string& name, 
                          const std::vector<std::string>& alternatives)
         : error(std::string("ambiguous option ").append(name))
-        , alternatives(alternatives)
+        , m_alternatives(alternatives)
         , m_option_name(name)
         {}
 
         ~ambiguous_option() throw() {}
         
         const std::string& get_option_name() const throw();
+        
+        const std::vector<std::string>& alternatives() const throw();
 
     private:
         // TODO: copy ctor might throw
-        std::vector<std::string> alternatives;
+        std::vector<std::string> m_alternatives;
         std::string m_option_name;
     };
 
Modified: trunk/libs/program_options/src/options_description.cpp
==============================================================================
--- trunk/libs/program_options/src/options_description.cpp	(original)
+++ trunk/libs/program_options/src/options_description.cpp	2009-12-05 03:08:45 EST (Sat, 05 Dec 2009)
@@ -273,6 +273,8 @@
     {
         shared_ptr<option_description> found;
         vector<string> approximate_matches;
+        vector<string> full_matches;
+        
         // We use linear search because matching specified option
         // name with the declared option name need to take care about
         // case sensitivity and trailing '*' and so we can't use simple map.
@@ -284,26 +286,29 @@
             if (r == option_description::no_match)
                 continue;
 
-            // 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();
+            {                
+                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];
-            // FIXME: the use of 'key' here might not
-            // be the best approach.
-            approximate_matches.push_back(m_options[i]->key(name));
         }
-        if (approximate_matches.size() > 1)
+        if (full_matches.size() > 1) 
+            boost::throw_exception(
+                ambiguous_option(name, full_matches));
+        
+        // If we have a full match, 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.
+        if (full_matches.empty() && approximate_matches.size() > 1)
             boost::throw_exception(
                 ambiguous_option(name, approximate_matches));
 
Modified: trunk/libs/program_options/src/value_semantic.cpp
==============================================================================
--- trunk/libs/program_options/src/value_semantic.cpp	(original)
+++ trunk/libs/program_options/src/value_semantic.cpp	2009-12-05 03:08:45 EST (Sat, 05 Dec 2009)
@@ -227,6 +227,12 @@
     { 
         return m_option_name; 
     }
+ 
+    const std::vector<std::string>& 
+    ambiguous_option::alternatives() const throw()
+    {
+        return m_alternatives;
+    }
 
     void 
     multiple_values::set_option_name(const std::string& option_name)
Modified: trunk/libs/program_options/test/exception_test.cpp
==============================================================================
--- trunk/libs/program_options/test/exception_test.cpp	(original)
+++ trunk/libs/program_options/test/exception_test.cpp	2009-12-05 03:08:45 EST (Sat, 05 Dec 2009)
@@ -19,6 +19,30 @@
 #include "minitest.hpp"
 
 
+void test_ambiguous() 
+{
+    options_description desc; 
+    desc.add_options()
+        ("cfgfile,c", value<string>()->multitoken(), "the config file") 
+        ("output,c", value<string>(), "the output file") 
+        ("output,o", value<string>(), "the output file")
+    ;
+
+    const char* cmdline[] = {"program", "-c", "file", "-o", "anotherfile"};
+
+    variables_map vm;
+    try {
+       store(parse_command_line(sizeof(cmdline)/sizeof(const char*), 
+                                    const_cast<char**>(cmdline), desc), vm);
+    }
+    catch (ambiguous_option& e)
+    {
+        BOOST_CHECK_EQUAL(e.alternatives().size(), 2);
+        BOOST_CHECK_EQUAL(e.get_option_name(), "-c");      
+        BOOST_CHECK_EQUAL(e.alternatives()[0], "cfgfile");
+        BOOST_CHECK_EQUAL(e.alternatives()[1], "output");
+    }
+}
 
 void test_unknown_option() 
 {
@@ -101,27 +125,11 @@
 
 int main(int /*ac*/, char** /*av*/)
 {
+   test_ambiguous();
    test_unknown_option();
    test_multiple_values();
    test_multiple_occurrences();
 
-   bool helpflag = false;
-
-   options_description desc;
-   desc.add_options()
-        ("cfgfile,c", value<string>(), "the configfile")
-        ("help,h", value<bool>(&helpflag)->implicit_value(true), "help")
-      ;
-
-   const char* cmdline[] = {"program", "--cfgfile", "hugo", "-h", "yes"  };
-   
-   variables_map vm;
-      store(parse_command_line(sizeof(cmdline)/sizeof(const char*), 
-                                    const_cast<char**>(cmdline), desc), vm);
-      notify(vm);
-
-   cout << " help: " << (helpflag ? "true" : "false") << endl;
-
-
    return 0;
 }
+