Skip to content

Commit 91d9cab

Browse files
committed
When processing value multitoken options, don't eat futher options.
Fixes #469. [SVN r52154]
1 parent 22e8d11 commit 91d9cab

File tree

3 files changed

+82
-13
lines changed

3 files changed

+82
-13
lines changed

src/cmdline.cpp

Lines changed: 60 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,54 @@ namespace boost { namespace program_options { namespace detail {
254254
}
255255
}
256256

257+
/* If an key option is followed by a positional option,
258+
can can consume more tokens (e.g. it's multitoke option),
259+
give those tokens to it. */
260+
vector<option> result2;
261+
for (unsigned i = 0; i < result.size(); ++i)
262+
{
263+
result2.push_back(result[i]);
264+
option& opt = result2.back();
265+
266+
if (opt.string_key.empty())
267+
continue;
268+
269+
const option_description* xd =
270+
m_desc->find_nothrow(opt.string_key,
271+
(m_style & allow_guessing));
272+
if (!xd)
273+
continue;
274+
275+
int min_tokens = xd->semantic()->min_tokens();
276+
int max_tokens = xd->semantic()->max_tokens();
277+
if (min_tokens < max_tokens && opt.value.size() < max_tokens)
278+
{
279+
// This option may grab some more tokens.
280+
// We only allow to grab tokens that are not already
281+
// recognized as key options.
282+
283+
int can_take_more = max_tokens - opt.value.size();
284+
int j = i+1;
285+
for (; can_take_more && j < result.size(); --can_take_more, ++j)
286+
{
287+
option& opt2 = result[j];
288+
if (!opt2.string_key.empty())
289+
break;
290+
291+
assert(opt2.value.size() == 1);
292+
293+
opt.value.push_back(opt2.value[0]);
294+
295+
assert(opt2.original_tokens.size() == 1);
296+
297+
opt.original_tokens.push_back(opt2.original_tokens[0]);
298+
}
299+
i = j-1;
300+
}
301+
}
302+
result.swap(result2);
303+
304+
257305
// Assign position keys to positional options.
258306
int position_key = 0;
259307
for(unsigned i = 0; i < result.size(); ++i) {
@@ -327,18 +375,21 @@ namespace boost { namespace program_options { namespace detail {
327375
invalid_command_line_syntax::extra_parameter);
328376
}
329377

330-
max_tokens -= opt.value.size();
378+
// If an option wants, at minimum, N tokens, we grab them
379+
// there and don't care if they look syntactically like an
380+
// option.
331381

332-
// A value is optional if min_tokens == 0, but max_tokens > 0.
333-
// If a value is optional, it must appear in opt.value (because
334-
// it was 'adjacent'. Otherwise, remove the expectation of a
335-
// non-adjacent value. (For now, we just check max_tokens == 1,
336-
// as there is no current support for max_tokens>1)
337-
if (min_tokens == 0 && max_tokens == 1 && opt.value.empty())
338-
--max_tokens;
382+
if (opt.value.size() <= min_tokens)
383+
{
384+
min_tokens -= opt.value.size();
385+
}
386+
else
387+
{
388+
min_tokens = 0;
389+
}
339390

340391
// Everything's OK, move the values to the result.
341-
for(;!other_tokens.empty() && max_tokens--; ) {
392+
for(;!other_tokens.empty() && min_tokens--; ) {
342393
opt.value.push_back(other_tokens[0]);
343394
opt.original_tokens.push_back(other_tokens[0]);
344395
other_tokens.erase(other_tokens.begin());

test/parsers_test.cpp

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -146,8 +146,23 @@ void test_command_line()
146146
variables_map vm;
147147
po::store(po::parse_command_line(3, cmdline4, desc2), vm);
148148

149-
150-
149+
char* cmdline5[] = {"", "-p7", "-o", "1", "2", "3", "-x8"};
150+
options_description desc3;
151+
desc3.add_options()
152+
(",p", po::value<string>())
153+
(",o", po::value<string>()->multitoken())
154+
(",x", po::value<string>())
155+
;
156+
vector<option> a5 =
157+
parse_command_line(7, cmdline5, desc3, 0, additional_parser).options;
158+
BOOST_CHECK_EQUAL(a5.size(), 3u);
159+
check_value(a5[0], "-p", "7");
160+
BOOST_REQUIRE(a5[1].value.size() == 3);
161+
BOOST_CHECK_EQUAL(a5[1].string_key, "-o");
162+
BOOST_CHECK_EQUAL(a5[1].value[0], "1");
163+
BOOST_CHECK_EQUAL(a5[1].value[1], "2");
164+
BOOST_CHECK_EQUAL(a5[1].value[2], "3");
165+
check_value(a5[2], "-x", "8");
151166
}
152167

153168
void test_config_file()

test/variable_map_test.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -96,16 +96,19 @@ void test_variable_map()
9696
("imp", po::value<int>()->implicit_value(100))
9797
("iim", po::value<int>()->implicit_value(200)->default_value(201))
9898
("mmp,m", po::value<int>()->implicit_value(123)->default_value(124))
99+
("foo", po::value<int>())
99100
;
100-
char* cmdline6_[] = { "--imp=1", "-m" };
101+
/* The -m option is implicit. It does not have value in inside the token,
102+
and we should not grab the next token. */
103+
char* cmdline6_[] = { "--imp=1", "-m", "--foo=1" };
101104
vector<string> cmdline6 = sv(cmdline6_,
102105
sizeof(cmdline6_)/sizeof(cmdline6_[0]));
103106
parsed_options a6 = command_line_parser(cmdline6).options(desc3).run();
104107

105108
variables_map vm4;
106109
store(a6, vm4);
107110
notify(vm4);
108-
BOOST_REQUIRE(vm4.size() == 3);
111+
BOOST_REQUIRE(vm4.size() == 4);
109112
BOOST_CHECK(vm4["imp"].as<int>() == 1);
110113
BOOST_CHECK(vm4["iim"].as<int>() == 201);
111114
BOOST_CHECK(vm4["mmp"].as<int>() == 123);

0 commit comments

Comments
 (0)