Boost logo

Boost-Commit :

Subject: [Boost-commit] svn:boost r58273 - in trunk: boost/program_options libs/program_options/src libs/program_options/test
From: s.ochsenknecht_at_[hidden]
Date: 2009-12-10 15:25:54


Author: s_ochsenknecht
Date: 2009-12-10 15:25:53 EST (Thu, 10 Dec 2009)
New Revision: 58273
URL: http://svn.boost.org/trac/boost/changeset/58273

Log:
reactive case_insensitive style for cmdline
Text files modified:
   trunk/boost/program_options/cmdline.hpp | 13 ++++--
   trunk/boost/program_options/option.hpp | 18 +++++++--
   trunk/boost/program_options/options_description.hpp | 13 ++++--
   trunk/libs/program_options/src/cmdline.cpp | 43 ++++++++++++++++++---
   trunk/libs/program_options/src/options_description.cpp | 76 ++++++++++++++++++++++++++++-----------
   trunk/libs/program_options/src/variables_map.cpp | 8 +---
   trunk/libs/program_options/test/cmdline_test.cpp | 3 -
   7 files changed, 125 insertions(+), 49 deletions(-)

Modified: trunk/boost/program_options/cmdline.hpp
==============================================================================
--- trunk/boost/program_options/cmdline.hpp (original)
+++ trunk/boost/program_options/cmdline.hpp 2009-12-10 15:25:53 EST (Thu, 10 Dec 2009)
@@ -62,14 +62,19 @@
             long option name if guessing is in effect.
         */
         allow_guessing = allow_sticky << 1,
- /** Ignore the difference in case for options.
- @todo Should this apply to long options only?
+ /** Ignore the difference in case for long options.
         */
- case_insensitive = allow_guessing << 1,
+ long_case_insensitive = allow_guessing << 1,
+ /** Ignore the difference in case for short options.
+ */
+ short_case_insensitive = long_case_insensitive << 1,
+ /** Ignore the difference in case for all options.
+ */
+ case_insensitive = (long_case_insensitive | short_case_insensitive),
         /** Allow long options with single option starting character,
             e.g <tt>-foo=10</tt>
         */
- allow_long_disguise = case_insensitive << 1,
+ allow_long_disguise = short_case_insensitive << 1,
         /** The more-or-less traditional unix style. */
         unix_style = (allow_short | short_allow_adjacent | short_allow_next
                       | allow_long | long_allow_adjacent | long_allow_next

Modified: trunk/boost/program_options/option.hpp
==============================================================================
--- trunk/boost/program_options/option.hpp (original)
+++ trunk/boost/program_options/option.hpp 2009-12-10 15:25:53 EST (Thu, 10 Dec 2009)
@@ -23,10 +23,17 @@
     template<class charT>
     class basic_option {
     public:
- basic_option() : position_key(-1), unregistered(false) {}
+ basic_option()
+ : position_key(-1)
+ , unregistered(false)
+ , case_insensitive(false)
+ {}
         basic_option(const std::string& string_key,
- const std::vector< std::string> &value)
- : string_key(string_key), value(value), unregistered(false)
+ const std::vector< std::string> &value)
+ : string_key(string_key)
+ , value(value)
+ , unregistered(false)
+ , case_insensitive(false)
         {}
 
         /** String key of this option. Intentionally independent of the template
@@ -50,7 +57,10 @@
             recovered from the "original_tokens" member.
         */
         bool unregistered;
-
+ /** True if string_key has to be handled
+ case insensitive.
+ */
+ bool case_insensitive;
     };
     typedef basic_option<char> option;
     typedef basic_option<wchar_t> woption;

Modified: trunk/boost/program_options/options_description.hpp
==============================================================================
--- trunk/boost/program_options/options_description.hpp (original)
+++ trunk/boost/program_options/options_description.hpp 2009-12-10 15:25:53 EST (Thu, 10 Dec 2009)
@@ -83,7 +83,8 @@
         /** Given 'option', specified in the input source,
             return 'true' is 'option' specifies *this.
         */
- match_result match(const std::string& option, bool approx) const;
+ match_result match(const std::string& option, bool approx,
+ bool long_ignore_case, bool short_ignore_case) const;
 
         /** Return the key that should identify the option, in
             particular in the variables_map class.
@@ -191,11 +192,15 @@
         */
         options_description_easy_init add_options();
 
- const option_description& find(const std::string& name, bool approx)
- const;
+ const option_description& find(const std::string& name,
+ bool approx,
+ bool long_ignore_case = false,
+ bool short_ignore_case = false) const;
 
         const option_description* find_nothrow(const std::string& name,
- bool approx) const;
+ bool approx,
+ bool long_ignore_case = false,
+ bool short_ignore_case = false) const;
 
 
         const std::vector< shared_ptr<option_description> >& options() const;

Modified: trunk/libs/program_options/src/cmdline.cpp
==============================================================================
--- trunk/libs/program_options/src/cmdline.cpp (original)
+++ trunk/libs/program_options/src/cmdline.cpp 2009-12-10 15:25:53 EST (Thu, 10 Dec 2009)
@@ -172,6 +172,12 @@
         // Need to check that if guessing and long disguise are enabled
         // -f will mean the same as -foo
     }
+
+ bool
+ cmdline::is_style_active(style_t style) const
+ {
+ return ((m_style & style) ? true : false);
+ }
 
     void
     cmdline::set_options_description(const options_description& desc)
@@ -284,7 +290,9 @@
 
             const option_description* xd =
                 m_desc->find_nothrow(opt.string_key,
- (m_style & allow_guessing));
+ is_style_active(allow_guessing),
+ is_style_active(long_case_insensitive),
+ is_style_active(short_case_insensitive));
             if (!xd)
                 continue;
 
@@ -348,6 +356,21 @@
                 }
             }
         }
+
+ // set case sensitive flag
+ for (unsigned i = 0; i < result.size(); ++i) {
+ if (result[i].string_key.size() > 2 ||
+ (result[i].string_key.size() > 1 && result[i].string_key[0] != '-'))
+ {
+ // it is a long option
+ result[i].case_insensitive = is_style_active(long_case_insensitive);
+ }
+ else
+ {
+ // it is a short option
+ result[i].case_insensitive = is_style_active(short_case_insensitive);
+ }
+ }
 
         return result;
     }
@@ -361,9 +384,10 @@
             return;
 
         // First check that the option is valid, and get its description.
- // TODO: case-sensitivity.
         const option_description* xd = m_desc->find_nothrow(opt.string_key,
- (m_style & allow_guessing) ? true : false);
+ is_style_active(allow_guessing),
+ is_style_active(long_case_insensitive),
+ is_style_active(short_case_insensitive));
 
         if (!xd)
         {
@@ -427,7 +451,9 @@
                 if (!followed_option.empty())
                 {
                     const option_description* od = m_desc->find_nothrow(other_tokens[0],
- (m_style & allow_guessing) ? true : false);
+ is_style_active(allow_guessing),
+ is_style_active(long_case_insensitive),
+ is_style_active(short_case_insensitive));
                     if (od)
                         boost::throw_exception(invalid_command_line_syntax(opt.string_key,
                                                     invalid_command_line_syntax::missing_parameter));
@@ -461,7 +487,7 @@
                 adjacent = tok.substr(p+1);
                 if (adjacent.empty())
                     boost::throw_exception( invalid_command_line_syntax(name,
- invalid_command_line_syntax::empty_adjacent_parameter));
+ invalid_command_line_syntax::empty_adjacent_parameter) );
             }
             else
             {
@@ -498,7 +524,8 @@
             // option.
             for(;;) {
                 const option_description* d
- = m_desc->find_nothrow(name, false);
+ = m_desc->find_nothrow(name, false, false,
+ is_style_active(short_case_insensitive));
 
                 // FIXME: check for 'allow_sticky'.
                 if (d && (m_style & allow_sticky) &&
@@ -563,7 +590,9 @@
              ((m_style & allow_slash_for_short) && tok[0] == '/')))
         {
             if (m_desc->find_nothrow(tok.substr(1, tok.find('=')-1),
- (m_style & allow_guessing) ? true : false))
+ is_style_active(allow_guessing),
+ is_style_active(long_case_insensitive),
+ is_style_active(short_case_insensitive)))
             {
                 args[0].insert(0, "-");
                 if (args[0][1] == '/')

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-10 15:25:53 EST (Thu, 10 Dec 2009)
@@ -28,6 +28,22 @@
 
 namespace boost { namespace program_options {
 
+ namespace {
+
+ template< class charT >
+ std::basic_string< charT > tolower_(const std::basic_string< charT >& str)
+ {
+ std::basic_string< charT > result;
+ for (typename std::basic_string< charT >::size_type i = 0; i < str.size(); ++i)
+ {
+ result.append(1, static_cast< charT >(std::tolower(str[i])));
+ }
+ return result;
+ }
+
+ } // unnamed namespace
+
+
     option_description::option_description()
     {
     }
@@ -55,39 +71,51 @@
     }
 
     option_description::match_result
- option_description::match(const std::string& option, bool approx) const
+ option_description::match(const std::string& option,
+ bool approx,
+ bool long_ignore_case,
+ bool short_ignore_case) const
     {
- match_result result = no_match;
- if (!m_long_name.empty()) {
+ match_result result = no_match;
+
+ std::string local_long_name((long_ignore_case ? tolower_(m_long_name) : m_long_name));
+
+ if (!local_long_name.empty()) {
+
+ std::string local_option = (long_ignore_case ? tolower_(option) : option);
 
- if (*m_long_name.rbegin() == '*')
+ if (*local_long_name.rbegin() == '*')
             {
                 // The name ends with '*'. Any specified name with the given
                 // prefix is OK.
- if (option.find(m_long_name.substr(0, m_long_name.length()-1))
+ if (local_option.find(local_long_name.substr(0, local_long_name.length()-1))
                     == 0)
                     result = approximate_match;
             }
 
- if (approx)
+ if (local_long_name == local_option)
+ {
+ result = full_match;
+ }
+ else if (approx)
             {
- if (m_long_name.find(option) == 0)
+ if (local_long_name.find(local_option) == 0)
                 {
- if (m_long_name == option)
- result = full_match;
- else
- result = approximate_match;
+ result = approximate_match;
                 }
             }
- else
+ }
+
+ if (result != full_match)
+ {
+ std::string local_option(short_ignore_case ? tolower_(option) : option);
+ std::string local_short_name(short_ignore_case ? tolower_(m_short_name) : m_short_name);
+
+ if (local_short_name == local_option)
             {
- if (m_long_name == option)
- result = full_match;
+ result = full_match;
             }
         }
-
- if (m_short_name == option)
- result = full_match;
 
         return result;
     }
@@ -253,9 +281,13 @@
     }
 
     const option_description&
- options_description::find(const std::string& name, bool approx) const
+ options_description::find(const std::string& name,
+ bool approx,
+ bool long_ignore_case,
+ bool short_ignore_case) const
     {
- const option_description* d = find_nothrow(name, approx);
+ const option_description* d = find_nothrow(name, approx,
+ long_ignore_case, short_ignore_case);
         if (!d)
             boost::throw_exception(unknown_option(name));
         return *d;
@@ -269,7 +301,9 @@
 
     const option_description*
     options_description::find_nothrow(const std::string& name,
- bool approx) const
+ bool approx,
+ bool long_ignore_case,
+ bool short_ignore_case) const
     {
         shared_ptr<option_description> found;
         vector<string> approximate_matches;
@@ -281,7 +315,7 @@
         for(unsigned i = 0; i < m_options.size(); ++i)
         {
             option_description::match_result r =
- m_options[i]->match(name, approx);
+ m_options[i]->match(name, approx, long_ignore_case, short_ignore_case);
 
             if (r == option_description::no_match)
                 continue;

Modified: trunk/libs/program_options/src/variables_map.cpp
==============================================================================
--- trunk/libs/program_options/src/variables_map.cpp (original)
+++ trunk/libs/program_options/src/variables_map.cpp 2009-12-10 15:25:53 EST (Thu, 10 Dec 2009)
@@ -58,12 +58,8 @@
             if (xm.m_final.count(name))
                 continue;
 
- // Ignore options which are not described
- //TODO: consider this.
- //if (desc.count(name) == 0)
- // continue;
-
- const option_description& d = desc.find(name, false);
+ const option_description& d = desc.find(name, false,
+ false, false);
 
             variable_value& v = m[name];
             if (v.defaulted()) {

Modified: trunk/libs/program_options/test/cmdline_test.cpp
==============================================================================
--- trunk/libs/program_options/test/cmdline_test.cpp (original)
+++ trunk/libs/program_options/test/cmdline_test.cpp 2009-12-10 15:25:53 EST (Thu, 10 Dec 2009)
@@ -218,8 +218,6 @@
         allow_long | long_allow_adjacent
         | long_allow_next | case_insensitive);
 
-// FIXME: restore
-#if 0
     // Test case insensitive style.
     // Note that option names are normalized to lower case.
     test_case test_cases4[] = {
@@ -231,7 +229,6 @@
         {0, 0, 0}
     };
     test_cmdline("foo bar= baz? Giz", style, test_cases4);
-#endif
 }
 
 void test_short_options()


Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk