$include_dir="/home/hyper-archives/boost-commit/include"; include("$include_dir/msg-header.inc") ?>
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);