Boost logo

Boost-Commit :

From: ghost_at_[hidden]
Date: 2007-08-08 14:40:50


Author: vladimir_prus
Date: 2007-08-08 14:40:48 EDT (Wed, 08 Aug 2007)
New Revision: 38514
URL: http://svn.boost.org/trac/boost/changeset/38514

Log:
Support for 'implicit' options.
Patch from Bryan Green.
Fixes #1131.

Text files modified:
   trunk/boost/program_options/detail/value_semantic.hpp | 16 ++++++++++++++--
   trunk/boost/program_options/value_semantic.hpp | 36 +++++++++++++++++++++++++++++++++++-
   trunk/libs/program_options/example/options_description.cpp | 13 +++++++++++++
   trunk/libs/program_options/src/cmdline.cpp | 8 ++++++++
   trunk/libs/program_options/test/variable_map_test.cpp | 19 +++++++++++++++++++
   5 files changed, 89 insertions(+), 3 deletions(-)

Modified: trunk/boost/program_options/detail/value_semantic.hpp
==============================================================================
--- trunk/boost/program_options/detail/value_semantic.hpp (original)
+++ trunk/boost/program_options/detail/value_semantic.hpp 2007-08-08 14:40:48 EDT (Wed, 08 Aug 2007)
@@ -16,7 +16,13 @@
     std::string
     typed_value<T, charT>::name() const
     {
- if (!m_default_value.empty() && !m_default_value_as_text.empty()) {
+ if (!m_implicit_value.empty() && !m_implicit_value_as_text.empty()) {
+ std::string msg = "[=arg(=" + m_implicit_value_as_text + ")]";
+ if (!m_default_value.empty() && !m_default_value_as_text.empty())
+ msg += " (=" + m_default_value_as_text + ")";
+ return msg;
+ }
+ else if (!m_default_value.empty() && !m_default_value_as_text.empty()) {
             return arg + " (=" + m_default_value_as_text + ")";
         } else {
             return arg;
@@ -155,7 +161,13 @@
     xparse(boost::any& value_store,
            const std::vector<std::basic_string<charT> >& new_tokens) const
     {
- validate(value_store, new_tokens, (T*)0, 0);
+ // If no tokens were given, and the option accepts an implicit
+ // value, then assign the implicit value as the stored value;
+ // otherwise, validate the user-provided token(s).
+ if (new_tokens.empty() && !m_implicit_value.empty())
+ value_store = m_implicit_value;
+ else
+ validate(value_store, new_tokens, (T*)0, 0);
     }
 
     template<class T>

Modified: trunk/boost/program_options/value_semantic.hpp
==============================================================================
--- trunk/boost/program_options/value_semantic.hpp (original)
+++ trunk/boost/program_options/value_semantic.hpp 2007-08-08 14:40:48 EDT (Wed, 08 Aug 2007)
@@ -204,6 +204,38 @@
             return this;
         }
 
+ /** Specifies an implicit value, which will be used
+ if the option is given, but without an adjacent value.
+ Using this implies that an explicit value is optional, but if
+ given, must be strictly adjacent to the option, i.e.: '-ovalue'
+ or '--option=value'. Giving '-o' or '--option' will cause the
+ implicit value to be applied.
+ */
+ typed_value* implicit_value(const T &v)
+ {
+ m_implicit_value = boost::any(v);
+ m_implicit_value_as_text =
+ boost::lexical_cast<std::string>(v);
+ return this;
+ }
+
+ /** Specifies an implicit value, which will be used
+ if the option is given, but without an adjacent value.
+ Using this implies that an explicit value is optional, but if
+ given, must be strictly adjacent to the option, i.e.: '-ovalue'
+ or '--option=value'. Giving '-o' or '--option' will cause the
+ implicit value to be applied.
+ Unlike the above overload, the type 'T' need not provide
+ operator<< for ostream, but textual representation of default
+ value must be provided by the user.
+ */
+ typed_value* implicit_value(const T &v, const std::string& textual)
+ {
+ m_implicit_value = boost::any(v);
+ m_implicit_value_as_text = textual;
+ return this;
+ }
+
         /** Specifies a function to be called when the final value
             is determined. */
         typed_value* notifier(function1<void, const T&> f)
@@ -243,7 +275,7 @@
 
         unsigned min_tokens() const
         {
- if (m_zero_tokens) {
+ if (m_zero_tokens || !m_implicit_value.empty()) {
                 return 0;
             } else {
                 return 1;
@@ -301,6 +333,8 @@
         // as boost::optional to avoid unnecessary instantiations.
         boost::any m_default_value;
         std::string m_default_value_as_text;
+ boost::any m_implicit_value;
+ std::string m_implicit_value_as_text;
         bool m_composing, m_implicit, m_multitoken, m_zero_tokens;
         boost::function1<void, const T&> m_notifier;
     };

Modified: trunk/libs/program_options/example/options_description.cpp
==============================================================================
--- trunk/libs/program_options/example/options_description.cpp (original)
+++ trunk/libs/program_options/example/options_description.cpp 2007-08-08 14:40:48 EDT (Wed, 08 Aug 2007)
@@ -26,11 +26,17 @@
 {
     try {
         int opt;
+ int portnum;
         po::options_description desc("Allowed options");
         desc.add_options()
             ("help", "produce help message")
             ("optimization", po::value<int>(&opt)->default_value(10),
                   "optimization level")
+ ("verbose,v", po::value<int>()->implicit_value(1),
+ "enable verbosity (optionally specify level)")
+ ("listen,l", po::value<int>(&portnum)->implicit_value(1001)
+ ->default_value(0,"no"),
+ "listen on a port.")
             ("include-path,I", po::value< vector<string> >(),
                   "include path")
             ("input-file", po::value< vector<string> >(), "input file")
@@ -62,7 +68,14 @@
                  << vm["input-file"].as< vector<string> >() << "\n";
         }
 
+ if (vm.count("verbose")) {
+ cout << "Verbosity enabled. Level is " << vm["verbose"].as<int>()
+ << "\n";
+ }
+
         cout << "Optimization level is " << opt << "\n";
+
+ cout << "Listen port is " << portnum << "\n";
     }
     catch(exception& e)
     {

Modified: trunk/libs/program_options/src/cmdline.cpp
==============================================================================
--- trunk/libs/program_options/src/cmdline.cpp (original)
+++ trunk/libs/program_options/src/cmdline.cpp 2007-08-08 14:40:48 EDT (Wed, 08 Aug 2007)
@@ -329,6 +329,14 @@
             
             max_tokens -= opt.value.size();
 
+ // A value is optional if min_tokens == 0, but max_tokens > 0.
+ // If a value is optional, it must appear in opt.value (because
+ // it was 'adjacent'. Otherwise, remove the expectation of a
+ // non-adjacent value. (For now, we just check max_tokens == 1,
+ // as there is no current support for max_tokens>1)
+ if (min_tokens == 0 && max_tokens == 1 && opt.value.empty())
+ --max_tokens;
+
             // Everything's OK, move the values to the result.
             for(;!other_tokens.empty() && max_tokens--; ) {
                 opt.value.push_back(other_tokens[0]);

Modified: trunk/libs/program_options/test/variable_map_test.cpp
==============================================================================
--- trunk/libs/program_options/test/variable_map_test.cpp (original)
+++ trunk/libs/program_options/test/variable_map_test.cpp 2007-08-08 14:40:48 EDT (Wed, 08 Aug 2007)
@@ -102,6 +102,25 @@
     BOOST_CHECK(vm3["vee"].as<string>() == "42");
     BOOST_CHECK(vm3["voo"].as<string>() == "1");
     BOOST_CHECK(vm3["iii"].as<int>() == 123);
+
+ options_description desc3;
+ desc3.add_options()
+ ("imp", po::value<int>()->implicit_value(100))
+ ("iim", po::value<int>()->implicit_value(200)->default_value(201))
+ ("mmp,m", po::value<int>()->implicit_value(123)->default_value(124))
+ ;
+ char* cmdline6_[] = { "--imp=1", "-m" };
+ vector<string> cmdline6 = sv(cmdline6_,
+ sizeof(cmdline6_)/sizeof(cmdline6_[0]));
+ parsed_options a6 = command_line_parser(cmdline6).options(desc3).run();
+
+ variables_map vm4;
+ store(a6, vm4);
+ notify(vm4);
+ BOOST_REQUIRE(vm4.size() == 3);
+ BOOST_CHECK(vm4["imp"].as<int>() == 1);
+ BOOST_CHECK(vm4["iim"].as<int>() == 201);
+ BOOST_CHECK(vm4["mmp"].as<int>() == 123);
 }
 
 int stored_value;


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