Boost logo

Boost-Commit :

Subject: [Boost-commit] svn:boost r52154 - in branches/release/libs/program_options: src test
From: ghost_at_[hidden]
Date: 2009-04-03 09:42:30


Author: vladimir_prus
Date: 2009-04-03 09:42:29 EDT (Fri, 03 Apr 2009)
New Revision: 52154
URL: http://svn.boost.org/trac/boost/changeset/52154

Log:
When processing value multitoken options, don't eat futher options.
Fixes #469.

Text files modified:
   branches/release/libs/program_options/src/cmdline.cpp | 69 ++++++++++++++++++++++++++++++++++-----
   branches/release/libs/program_options/test/parsers_test.cpp | 19 +++++++++-
   branches/release/libs/program_options/test/variable_map_test.cpp | 7 ++-
   3 files changed, 82 insertions(+), 13 deletions(-)

Modified: branches/release/libs/program_options/src/cmdline.cpp
==============================================================================
--- branches/release/libs/program_options/src/cmdline.cpp (original)
+++ branches/release/libs/program_options/src/cmdline.cpp 2009-04-03 09:42:29 EDT (Fri, 03 Apr 2009)
@@ -254,6 +254,54 @@
             }
         }
 
+ /* If an key option is followed by a positional option,
+ can can consume more tokens (e.g. it's multitoke option),
+ give those tokens to it. */
+ vector<option> result2;
+ for (unsigned i = 0; i < result.size(); ++i)
+ {
+ result2.push_back(result[i]);
+ option& opt = result2.back();
+
+ if (opt.string_key.empty())
+ continue;
+
+ const option_description* xd =
+ m_desc->find_nothrow(opt.string_key,
+ (m_style & allow_guessing));
+ if (!xd)
+ continue;
+
+ int min_tokens = xd->semantic()->min_tokens();
+ int max_tokens = xd->semantic()->max_tokens();
+ if (min_tokens < max_tokens && opt.value.size() < max_tokens)
+ {
+ // This option may grab some more tokens.
+ // We only allow to grab tokens that are not already
+ // recognized as key options.
+
+ int can_take_more = max_tokens - opt.value.size();
+ int j = i+1;
+ for (; can_take_more && j < result.size(); --can_take_more, ++j)
+ {
+ option& opt2 = result[j];
+ if (!opt2.string_key.empty())
+ break;
+
+ assert(opt2.value.size() == 1);
+
+ opt.value.push_back(opt2.value[0]);
+
+ assert(opt2.original_tokens.size() == 1);
+
+ opt.original_tokens.push_back(opt2.original_tokens[0]);
+ }
+ i = j-1;
+ }
+ }
+ result.swap(result2);
+
+
         // Assign position keys to positional options.
         int position_key = 0;
         for(unsigned i = 0; i < result.size(); ++i) {
@@ -327,18 +375,21 @@
                     invalid_command_line_syntax::extra_parameter);
             }
             
- max_tokens -= opt.value.size();
+ // If an option wants, at minimum, N tokens, we grab them
+ // there and don't care if they look syntactically like an
+ // option.
 
- // 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;
+ if (opt.value.size() <= min_tokens)
+ {
+ min_tokens -= opt.value.size();
+ }
+ else
+ {
+ min_tokens = 0;
+ }
 
             // Everything's OK, move the values to the result.
- for(;!other_tokens.empty() && max_tokens--; ) {
+ for(;!other_tokens.empty() && min_tokens--; ) {
                 opt.value.push_back(other_tokens[0]);
                 opt.original_tokens.push_back(other_tokens[0]);
                 other_tokens.erase(other_tokens.begin());

Modified: branches/release/libs/program_options/test/parsers_test.cpp
==============================================================================
--- branches/release/libs/program_options/test/parsers_test.cpp (original)
+++ branches/release/libs/program_options/test/parsers_test.cpp 2009-04-03 09:42:29 EDT (Fri, 03 Apr 2009)
@@ -146,8 +146,23 @@
     variables_map vm;
     po::store(po::parse_command_line(3, cmdline4, desc2), vm);
 
-
-
+ char* cmdline5[] = {"", "-p7", "-o", "1", "2", "3", "-x8"};
+ options_description desc3;
+ desc3.add_options()
+ (",p", po::value<string>())
+ (",o", po::value<string>()->multitoken())
+ (",x", po::value<string>())
+ ;
+ vector<option> a5 =
+ parse_command_line(7, cmdline5, desc3, 0, additional_parser).options;
+ BOOST_CHECK_EQUAL(a5.size(), 3u);
+ check_value(a5[0], "-p", "7");
+ BOOST_REQUIRE(a5[1].value.size() == 3);
+ BOOST_CHECK_EQUAL(a5[1].string_key, "-o");
+ BOOST_CHECK_EQUAL(a5[1].value[0], "1");
+ BOOST_CHECK_EQUAL(a5[1].value[1], "2");
+ BOOST_CHECK_EQUAL(a5[1].value[2], "3");
+ check_value(a5[2], "-x", "8");
 }
 
 void test_config_file()

Modified: branches/release/libs/program_options/test/variable_map_test.cpp
==============================================================================
--- branches/release/libs/program_options/test/variable_map_test.cpp (original)
+++ branches/release/libs/program_options/test/variable_map_test.cpp 2009-04-03 09:42:29 EDT (Fri, 03 Apr 2009)
@@ -96,8 +96,11 @@
     ("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))
+ ("foo", po::value<int>())
     ;
- char* cmdline6_[] = { "--imp=1", "-m" };
+ /* The -m option is implicit. It does not have value in inside the token,
+ and we should not grab the next token. */
+ char* cmdline6_[] = { "--imp=1", "-m", "--foo=1" };
     vector<string> cmdline6 = sv(cmdline6_,
                                  sizeof(cmdline6_)/sizeof(cmdline6_[0]));
     parsed_options a6 = command_line_parser(cmdline6).options(desc3).run();
@@ -105,7 +108,7 @@
     variables_map vm4;
     store(a6, vm4);
     notify(vm4);
- BOOST_REQUIRE(vm4.size() == 3);
+ BOOST_REQUIRE(vm4.size() == 4);
     BOOST_CHECK(vm4["imp"].as<int>() == 1);
     BOOST_CHECK(vm4["iim"].as<int>() == 201);
     BOOST_CHECK(vm4["mmp"].as<int>() == 123);


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