mirror of
https://github.com/boostorg/program_options.git
synced 2026-01-20 04:42:24 +00:00
Compare commits
190 Commits
boost-1.42
...
boost-1.59
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fae2d4c57b | ||
|
|
c0cee7f6da | ||
|
|
0756d35f8b | ||
|
|
bd1d0bd861 | ||
|
|
6feeeb3b92 | ||
|
|
0efb385e99 | ||
|
|
2c4d25a04b | ||
|
|
bae408095f | ||
|
|
c724b800a8 | ||
|
|
0f9793e369 | ||
|
|
0c01e9aadc | ||
|
|
88dea3c6fd | ||
|
|
145e5728d7 | ||
|
|
1d3294a058 | ||
|
|
7542447620 | ||
|
|
794de34bf9 | ||
|
|
095cb36f8a | ||
|
|
a9ea9bb453 | ||
|
|
3cec23f2ba | ||
|
|
fcc4e6ef1a | ||
|
|
1a17f20532 | ||
|
|
6e846597d5 | ||
|
|
f081a93643 | ||
|
|
37804b54d4 | ||
|
|
f50b02750a | ||
|
|
3ce1c74a0f | ||
|
|
2acfab15a3 | ||
|
|
4ae33ce15e | ||
|
|
fda6414443 | ||
|
|
9d7c987526 | ||
|
|
0a7005d7c6 | ||
|
|
fb4f36f3ee | ||
|
|
6bf4607eac | ||
|
|
81844db902 | ||
|
|
d3f32ca813 | ||
|
|
da03a78b66 | ||
|
|
5059a8f393 | ||
|
|
b430a83dfb | ||
|
|
96b365ce17 | ||
|
|
2ceb54f9a2 | ||
|
|
e8e538036d | ||
|
|
f11104084b | ||
|
|
a9993a8f01 | ||
|
|
d27da53324 | ||
|
|
94fc1c677d | ||
|
|
3360ad0ea2 | ||
|
|
f271e1ffce | ||
|
|
5a470bcc41 | ||
|
|
2eda0313c7 | ||
|
|
63e8f1c954 | ||
|
|
a70de616b0 | ||
|
|
43e53664f2 | ||
|
|
5cbfa80841 | ||
|
|
cddd2c593f | ||
|
|
fd7b310993 | ||
|
|
ae0ecf6581 | ||
|
|
76a62c1809 | ||
|
|
c054a3b034 | ||
|
|
540e300c38 | ||
|
|
9d7afca35c | ||
|
|
cf09cfde1f | ||
|
|
7051655c76 | ||
|
|
825562ed1e | ||
|
|
38e7ea8516 | ||
|
|
5b7fbb5fe7 | ||
|
|
28cafd9bd9 | ||
|
|
ec3192a6c8 | ||
|
|
84415c1e7b | ||
|
|
abd32c88fc | ||
|
|
c537274c44 | ||
|
|
4b17731e11 | ||
|
|
56d2c97ece | ||
|
|
e3f331a23b | ||
|
|
b000bf9a1d | ||
|
|
0c04bde7e0 | ||
|
|
7d7dad09d3 | ||
|
|
f0fdc822d4 | ||
|
|
cd1b58aac2 | ||
|
|
310a638dc8 | ||
|
|
277065182e | ||
|
|
572a93ac5b | ||
|
|
e79708eee7 | ||
|
|
444146bd25 | ||
|
|
cbacc90d8f | ||
|
|
0a2145c008 | ||
|
|
9691bb1b62 | ||
|
|
b9e8acef7b | ||
|
|
53ba9ab34f | ||
|
|
af37add8c6 | ||
|
|
85b2b1c890 | ||
|
|
524460caba | ||
|
|
388c0d1e35 | ||
|
|
a5e45eda5f | ||
|
|
970e377710 | ||
|
|
fbb8f045ee | ||
|
|
645adb48cb | ||
|
|
80b3a04b1f | ||
|
|
f4e7fb0348 | ||
|
|
f00e305f40 | ||
|
|
69bb59d15f | ||
|
|
d9c57f58d9 | ||
|
|
9a04daa2b2 | ||
|
|
5f01f7bf3f | ||
|
|
6e0f1db1fc | ||
|
|
35bf26f432 | ||
|
|
00dadb4203 | ||
|
|
263534a213 | ||
|
|
60966caa35 | ||
|
|
6b194eed21 | ||
|
|
5fbdd0fafd | ||
|
|
3c9e01cad1 | ||
|
|
b3e9b5180e | ||
|
|
370834c5c2 | ||
|
|
78693e8799 | ||
|
|
ccbbcab336 | ||
|
|
249094d496 | ||
|
|
98b0f14f5a | ||
|
|
8add1551dc | ||
|
|
63c0bf7bfc | ||
|
|
aaa914e9a4 | ||
|
|
e1010ad09e | ||
|
|
73957ca639 | ||
|
|
c6b373ff48 | ||
|
|
5a5ad8df61 | ||
|
|
9c934c39fe | ||
|
|
122fe22e07 | ||
|
|
8f40132e63 | ||
|
|
3f6577a53b | ||
|
|
6dbc2ac80a | ||
|
|
b5ce55ad8c | ||
|
|
79b43138d6 | ||
|
|
354717d9c9 | ||
|
|
badade7842 | ||
|
|
55a1a045a3 | ||
|
|
6aaee3bbef | ||
|
|
ba75831f1b | ||
|
|
620a9a5021 | ||
|
|
3c3b8d8818 | ||
|
|
98331c3542 | ||
|
|
e4ccf81e82 | ||
|
|
600a8aa105 | ||
|
|
454c878389 | ||
|
|
49bc2d6226 | ||
|
|
ee3079c247 | ||
|
|
68fa36b0f6 | ||
|
|
ea2b309994 | ||
|
|
23019ff2ef | ||
|
|
4dcce9efce | ||
|
|
316e2fabe4 | ||
|
|
152fbd8384 | ||
|
|
80361c6b8f | ||
|
|
a3d19d354a | ||
|
|
86aeaf478d | ||
|
|
7ba4ac9c14 | ||
|
|
d343dda27e | ||
|
|
8329c28a1a | ||
|
|
73cf706164 | ||
|
|
e51a3ae742 | ||
|
|
a0a661e4ec | ||
|
|
c25408f6d2 | ||
|
|
63fca63679 | ||
|
|
8c39e5aa8d | ||
|
|
d0aa5abee5 | ||
|
|
90dc6b94d0 | ||
|
|
2320c07267 | ||
|
|
cd647f785a | ||
|
|
4223d3231d | ||
|
|
d1d5636365 | ||
|
|
c00c4a57db | ||
|
|
8ad16ee97c | ||
|
|
0c3e43f2ce | ||
|
|
e42f028278 | ||
|
|
a29728e679 | ||
|
|
232894cb3d | ||
|
|
d39f2b5979 | ||
|
|
8c68a478c9 | ||
|
|
5d1345c5a9 | ||
|
|
a560d767fb | ||
|
|
8c1982de82 | ||
|
|
928d7806f7 | ||
|
|
b99ae04040 | ||
|
|
dc334deea7 | ||
|
|
de66d37405 | ||
|
|
a4375600a2 | ||
|
|
bec34dd1b9 | ||
|
|
7b73b2e84c | ||
|
|
2625de2dd0 | ||
|
|
ac6de20f85 | ||
|
|
3765e8e8e9 | ||
|
|
026c527d8d |
@@ -12,6 +12,8 @@ SOURCES =
|
||||
lib boost_program_options
|
||||
: $(SOURCES).cpp
|
||||
: <link>shared:<define>BOOST_PROGRAM_OPTIONS_DYN_LINK=1 # tell source we're building dll's
|
||||
# See https://svn.boost.org/trac/boost/ticket/5049
|
||||
<target-os>hpux,<toolset>gcc:<define>_INCLUDE_STDC__SOURCE_199901
|
||||
:
|
||||
: <link>shared:<define>BOOST_PROGRAM_OPTIONS_DYN_LINK=1
|
||||
;
|
||||
|
||||
@@ -5,6 +5,7 @@ toolset.using doxygen ;
|
||||
boostbook program_option
|
||||
: program_options.xml
|
||||
: <implicit-dependency>autodoc
|
||||
<xsl:param>boost.root=../../../..
|
||||
<format>pdf:<xsl:param>boost.url.prefix=http://www.boost.org/doc/libs/release/doc/html
|
||||
;
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
not mean strict 7-bit ASCII encoding, but rather "char" strings in local
|
||||
8-bit encoding.
|
||||
</para>
|
||||
|
||||
|
||||
<para>
|
||||
Generally, "Unicode support" can mean
|
||||
many things, but for the program_options library it means that:
|
||||
@@ -54,7 +54,7 @@
|
||||
passed to an ascii value will be converted using a codecvt
|
||||
facet (which may be specified by the user).
|
||||
</para>
|
||||
</listitem>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
</listitem>
|
||||
@@ -68,8 +68,8 @@
|
||||
Second, imagine a reusable library which has some options and exposes
|
||||
options description in its interface. If <emphasis>all</emphasis>
|
||||
options are either ascii or Unicode, and the library does not use any
|
||||
Unicode strings, then the author will likely to use ascii options, which
|
||||
would make the library unusable inside Unicode
|
||||
Unicode strings, then the author is likely to use ascii options, making
|
||||
the library unusable inside Unicode
|
||||
applications. Essentially, it would be necessary to provide two versions
|
||||
of the library -- ascii and Unicode.
|
||||
</para>
|
||||
@@ -94,7 +94,7 @@
|
||||
<para>The primary question in implementing the Unicode support is whether
|
||||
to use templates and <code>std::basic_string</code> or to use some
|
||||
internal encoding and convert between internal and external encodings on
|
||||
the interface boundaries.
|
||||
the interface boundaries.
|
||||
</para>
|
||||
|
||||
<para>The choice, mostly, is between code size and execution
|
||||
@@ -171,14 +171,14 @@
|
||||
number of new instantiations.
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
|
||||
</itemizedlist>
|
||||
There's no clear leader, but the last point seems important, so UTF-8
|
||||
will be used.
|
||||
will be used.
|
||||
</para>
|
||||
|
||||
<para>Choosing the UTF-8 encoding allows the use of existing parsers,
|
||||
because 7-bit ascii characters retain their values in UTF-8,
|
||||
<para>Choosing the UTF-8 encoding allows the use of existing parsers,
|
||||
because 7-bit ascii characters retain their values in UTF-8,
|
||||
so searching for 7-bit strings is simple. However, there are
|
||||
two subtle issues:
|
||||
<itemizedlist>
|
||||
@@ -197,16 +197,16 @@
|
||||
almost universal encoding and since composing characters following '=' (and
|
||||
other characters with special meaning to the library) are not likely to appear.
|
||||
</para>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
<!--
|
||||
Local Variables:
|
||||
mode: xml
|
||||
sgml-indent-data: t
|
||||
sgml-indent-data: t
|
||||
sgml-parent-document: ("program_options.xml" "section")
|
||||
sgml-set-face: t
|
||||
End:
|
||||
|
||||
@@ -21,7 +21,7 @@ options groups/hidden options
|
||||
-->
|
||||
<section>
|
||||
<title>Non-conventional Syntax</title>
|
||||
|
||||
|
||||
<para>Sometimes, standard command line syntaxes are not enough. For
|
||||
example, the gcc compiler has "-frtti" and -fno-rtti" options, and this
|
||||
syntax is not directly supported.
|
||||
@@ -57,14 +57,14 @@ store(command_line_parser(ac, av).options(desc).extra_parser(reg_foo)
|
||||
.run(), vm);
|
||||
</programlisting>
|
||||
The complete example can be found in the "example/custom_syntax.cpp"
|
||||
file.
|
||||
file.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Response Files</title>
|
||||
|
||||
<indexterm><primary>response files</primary></indexterm>
|
||||
<indexterm><primary>response files</primary></indexterm>
|
||||
|
||||
<para>Some operating system have very low limits of the command line
|
||||
length. The common way to work around those limitations is using
|
||||
@@ -79,7 +79,7 @@ store(command_line_parser(ac, av).options(desc).extra_parser(reg_foo)
|
||||
<para>
|
||||
First, you need to define an option for the response file:
|
||||
<programlisting>
|
||||
("response-file", value<string>(),
|
||||
("response-file", value<string>(),
|
||||
"can be specified with '@name', too")
|
||||
</programlisting>
|
||||
</para>
|
||||
@@ -107,7 +107,7 @@ if (vm.count("response-file")) {
|
||||
// Load the file and tokenize it
|
||||
ifstream ifs(vm["response-file"].as<string>().c_str());
|
||||
if (!ifs) {
|
||||
cout << "Could no open the response file\n";
|
||||
cout << "Could not open the response file\n";
|
||||
return 1;
|
||||
}
|
||||
// Read the whole file into a string
|
||||
@@ -115,18 +115,19 @@ if (vm.count("response-file")) {
|
||||
ss << ifs.rdbuf();
|
||||
// Split the file content
|
||||
char_separator<char> sep(" \n\r");
|
||||
tokenizer<char_separator<char> > tok(ss.str(), sep);
|
||||
std::string ResponsefileContents( ss.str() );
|
||||
tokenizer<char_separator<char> > tok(ResponsefileContents, sep);
|
||||
vector<string> args;
|
||||
copy(tok.begin(), tok.end(), back_inserter(args));
|
||||
// Parse the file and store the options
|
||||
store(command_line_parser(args).options(desc).run(), vm);
|
||||
store(command_line_parser(args).options(desc).run(), vm);
|
||||
}
|
||||
]]>
|
||||
</programlisting>
|
||||
The complete example can be found in the "example/response_file.cpp"
|
||||
file.
|
||||
file.
|
||||
</para>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
<section>
|
||||
@@ -145,8 +146,8 @@ if (vm.count("response-file")) {
|
||||
<programlisting>
|
||||
vector<string> args = split_winmain(lpCmdLine);
|
||||
store(command_line_parser(args).options(desc).run(), vm);
|
||||
</programlisting>
|
||||
The function is an overload for <code>wchar_t</code> strings, so can
|
||||
</programlisting>
|
||||
The <code>split_winmain</code> function is overloaded for <code>wchar_t</code> strings, so can
|
||||
also be used in Unicode applications.
|
||||
</para>
|
||||
|
||||
@@ -222,7 +223,7 @@ visible.add(general).add(gui);
|
||||
variables_map vm;
|
||||
store(parse_command_line(ac, av, all), vm);
|
||||
|
||||
if (vm.count("help"))
|
||||
if (vm.count("help"))
|
||||
{
|
||||
cout << visible;
|
||||
return 0;
|
||||
@@ -234,7 +235,7 @@ if (vm.count("help-module")) {
|
||||
} else if (s == "backend") {
|
||||
cout << backend;
|
||||
} else {
|
||||
cout << "Unknown module '"
|
||||
cout << "Unknown module '"
|
||||
<< s << "' in the --help-module option\n";
|
||||
return 1;
|
||||
}
|
||||
@@ -242,8 +243,8 @@ if (vm.count("help-module")) {
|
||||
}
|
||||
if (vm.count("num-threads")) {
|
||||
cout << "The 'num-threads' options was set to "
|
||||
<< vm["num-threads"].as<int>() << "\n";
|
||||
}
|
||||
<< vm["num-threads"].as<int>() << "\n";
|
||||
}
|
||||
]]></programlisting>
|
||||
When parsing the command line, all options are allowed. The "--help"
|
||||
message, however, does not include the "Backend options" group -- the
|
||||
@@ -252,7 +253,7 @@ if (vm.count("num-threads")) {
|
||||
option. The complete example can be found in the
|
||||
"example/option_groups.cpp" file.
|
||||
</para>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
<section>
|
||||
@@ -275,7 +276,7 @@ public:
|
||||
};
|
||||
]]></programlisting> and then overload the <code>validate</code> function:
|
||||
<programlisting><![CDATA[
|
||||
void validate(boost::any& v,
|
||||
void validate(boost::any& v,
|
||||
const std::vector<std::string>& values,
|
||||
magic_number* target_type, int)
|
||||
{
|
||||
@@ -289,16 +290,16 @@ void validate(boost::any& v,
|
||||
// one string, it's an error, and exception will be thrown.
|
||||
const string& s = validators::get_single_string(values);
|
||||
|
||||
// Do regex match and convert the interesting part to
|
||||
// Do regex match and convert the interesting part to
|
||||
// int.
|
||||
smatch match;
|
||||
if (regex_match(s, match, r)) {
|
||||
v = any(magic_number(lexical_cast<int>(match[1])));
|
||||
} else {
|
||||
throw validation_error("invalid value");
|
||||
}
|
||||
throw validation_error(validation_error::invalid_option_value);
|
||||
}
|
||||
}
|
||||
]]>
|
||||
]]>
|
||||
</programlisting>The function takes four parameters. The first is the storage
|
||||
for the value, and in this case is either empty or contains an instance of
|
||||
the <code>magic_number</code> class. The second is the list of strings
|
||||
@@ -371,7 +372,7 @@ void validate(boost::any& v,
|
||||
locale::global(locale(""));
|
||||
</programlisting>
|
||||
which would set up the conversion facet according to the user's selected
|
||||
locale.
|
||||
locale.
|
||||
</para>
|
||||
|
||||
<para>It's wise to check the status of the C++ locale support on your
|
||||
@@ -381,7 +382,7 @@ locale::global(locale(""));
|
||||
<para>Go the the "test" directory and build the "test_convert" binary.</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>Set some non-ascii locale in the environmemt. On Linux, one can
|
||||
<para>Set some non-ascii locale in the environment. On Linux, one can
|
||||
run, for example: <screen>
|
||||
$ export LC_CTYPE=ru_RU.KOI8-R
|
||||
</screen>
|
||||
@@ -401,37 +402,37 @@ $ export LC_CTYPE=ru_RU.KOI8-R
|
||||
<section>
|
||||
<title>Allowing Unknown Options</title>
|
||||
|
||||
<para>Usually, the library throws an exception on unknown option names. This
|
||||
behaviour can be changed. For example, only some part of your application uses
|
||||
<para>Usually, the library throws an exception on unknown option names. This
|
||||
behaviour can be changed. For example, only some part of your application uses
|
||||
<libraryname>Program_options</libraryname>, and you wish to pass unrecognized options to another part of
|
||||
the program, or even to another application.</para>
|
||||
|
||||
<para>To allow unregistered options on the command line, you need to use
|
||||
<para>To allow unregistered options on the command line, you need to use
|
||||
the &basic_command_line_parser; class for parsing (not &parse_command_line;)
|
||||
and call the <methodname alt="boost::program_options::basic_command_line_parser::allow_unregistered">allow_unregistered</methodname>
|
||||
and call the <methodname alt="boost::program_options::basic_command_line_parser::allow_unregistered">allow_unregistered</methodname>
|
||||
method of that class:
|
||||
<programlisting>
|
||||
parsed_options parsed =
|
||||
command_line_parser(argc, argv).options(desc).allow_unregistered().run();
|
||||
parsed_options parsed =
|
||||
command_line_parser(argc, argv).options(desc).allow_unregistered().run();
|
||||
</programlisting>
|
||||
|
||||
For each token that looks like an option, but does not have a known name,
|
||||
an instance of &basic_option; will be added to the result.
|
||||
The <code>string_key</code> and <code>value</code> fields of the instance will contain results
|
||||
|
||||
For each token that looks like an option, but does not have a known name,
|
||||
an instance of &basic_option; will be added to the result.
|
||||
The <code>string_key</code> and <code>value</code> fields of the instance will contain results
|
||||
of syntactic parsing of the token, the <code>unregistered</code> field will be set to <code>true</code>,
|
||||
and the <code>original_tokens</code> field will contain the token as it appeared on the command line.
|
||||
</para>
|
||||
|
||||
<para>If you want to pass the unrecognized options further, the
|
||||
<para>If you want to pass the unrecognized options further, the
|
||||
<functionname alt="boost::program_options::collect_unrecognized">collect_unrecognized</functionname> function can be used.
|
||||
The function will collect original tokens for all unrecognized values, and optionally, all found positional options.
|
||||
Say, if your code handles a few options, but does not handles positional options at all, you can use the function like this:
|
||||
Say, if your code handles a few options, but does not handle positional options at all, you can use the function like this:
|
||||
<programlisting>
|
||||
vector<string> to_pass_further = collect_unrecognized(parsed.options, include_positional);
|
||||
</programlisting>
|
||||
|
||||
</para>
|
||||
|
||||
|
||||
</para>
|
||||
|
||||
</section>
|
||||
|
||||
</section>
|
||||
|
||||
112
doc/overview.xml
112
doc/overview.xml
@@ -22,7 +22,7 @@
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>The parsers component, which uses this information to find option names
|
||||
and values in the input sources and return them.
|
||||
and values in the input sources and return them.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
@@ -72,10 +72,10 @@
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>The storage component is focused on storing options values. It
|
||||
<para>The storage component is focused on storing options values. It
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
|
||||
|
||||
</itemizedlist>
|
||||
|
||||
@@ -105,7 +105,7 @@ desc.add_options()
|
||||
("help", "produce help")
|
||||
("optimization", value<int>()->default_value(10), "optimization level")
|
||||
;
|
||||
</programlisting>
|
||||
</programlisting>
|
||||
</para>
|
||||
|
||||
<para>The call to the <code>value</code> function creates an instance of
|
||||
@@ -116,14 +116,14 @@ desc.add_options()
|
||||
essentially emulates named parameters of the constructor.) Calls to
|
||||
<code>operator()</code> on the object returned by <code>add_options</code>
|
||||
forward arguments to the constructor of the <code>option_description</code>
|
||||
class and add the new instance.
|
||||
class and add the new instance.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Note that in addition to the
|
||||
<code>value</code>, library provides the <code>bool_switch</code>
|
||||
function, and user can write his own function which will return
|
||||
other subclasses of <code>value_semantic</code> with
|
||||
other subclasses of <code>value_semantic</code> with
|
||||
different behaviour. For the remainder of this section, we'll talk only
|
||||
about the <code>value</code> function.
|
||||
</para>
|
||||
@@ -135,7 +135,7 @@ desc.add_options()
|
||||
where value is just a vector of strings
|
||||
(<code>std::vector<std::string></code>). The semantic layer
|
||||
is responsible for converting the value of the option into more usable C++
|
||||
types.
|
||||
types.
|
||||
</para>
|
||||
|
||||
<para>This separation is an important part of library design. The parsers
|
||||
@@ -153,7 +153,7 @@ desc.add_options()
|
||||
<classname>boost::program_options::options_description</classname> class
|
||||
and some methods of the
|
||||
<classname>boost::program_options::value_semantic</classname> class
|
||||
and includes:
|
||||
and includes:
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
@@ -181,7 +181,7 @@ options_description desc;
|
||||
desc.add_options()
|
||||
("help", "produce help message")
|
||||
("compression", value<string>(), "compression level")
|
||||
("verbose", value<string>()->zero_tokens(), "verbosity level")
|
||||
("verbose", value<string>()->implicit_value("0"), "verbosity level")
|
||||
("email", value<string>()->multitoken(), "email to send to")
|
||||
;
|
||||
</programlisting>
|
||||
@@ -193,7 +193,7 @@ desc.add_options()
|
||||
span several tokens. For example, the following command line is OK:
|
||||
<screen>
|
||||
test --help --compression 10 --verbose --email beadle@mars beadle2@mars
|
||||
</screen>
|
||||
</screen>
|
||||
</para>
|
||||
|
||||
<section>
|
||||
@@ -208,18 +208,18 @@ desc.add_options()
|
||||
<para>The description string has one or more paragraphs, separated by
|
||||
the newline character ('\n'). When an option is output, the library
|
||||
will compute the indentation for options's description. Each of the
|
||||
paragraph is output as a separate line with that intentation. If
|
||||
paragraph is output as a separate line with that intentation. If
|
||||
a paragraph does not fit on one line it is spanned over multiple
|
||||
lines (which will have the same indentation).
|
||||
</para>
|
||||
|
||||
<para>You may specify additional indent for the first specified by
|
||||
inserting spaces at the beginning of a paragraph. For example:
|
||||
inserting spaces at the beginning of a paragraph. For example:
|
||||
<programlisting>
|
||||
options.add_options()
|
||||
("help", " A long help msg a long help msg a long help msg a long help
|
||||
msg a long help msg a long help msg a long help msg a long help msg ")
|
||||
;
|
||||
;
|
||||
</programlisting>
|
||||
will specify a four-space indent for the first line. The output will
|
||||
look like:
|
||||
@@ -230,14 +230,14 @@ msg a long help msg a long help msg a long help msg a long help msg ")
|
||||
help msg a long help msg
|
||||
a long help msg a long
|
||||
help msg
|
||||
|
||||
|
||||
</screen>
|
||||
</para>
|
||||
|
||||
<para>For the case where line is wrapped, you can want an additional
|
||||
indent for wrapped text. This can be done by
|
||||
inserting a tabulator character ('\t') at the desired position. For
|
||||
example:
|
||||
example:
|
||||
<programlisting>
|
||||
options.add_options()
|
||||
("well_formated", "As you can see this is a very well formatted
|
||||
@@ -249,7 +249,7 @@ bla bla bla bla bla bla bla bla bla bla bla\n"
|
||||
" Value2: \tdoes something else, bla bla bla bla
|
||||
bla bla bla bla bla bla bla bla bla bla bla\n\n"
|
||||
" This paragraph has a first line indent only,
|
||||
bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla");
|
||||
bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla");
|
||||
</programlisting>
|
||||
will produce:
|
||||
<screen>
|
||||
@@ -280,20 +280,20 @@ bla bla bla bla bla bla bla bla bla bla bla bla bla bla bla");
|
||||
bla bla bla
|
||||
</screen>
|
||||
The tab character is removed before output. Only one tabulator per
|
||||
paragraph is allowed, otherwisee an exception of type
|
||||
paragraph is allowed, otherwise an exception of type
|
||||
program_options::error is thrown. Finally, the tabulator is ignored if
|
||||
it's is not on the first line of the paragraph or is on the last
|
||||
it is not on the first line of the paragraph or is on the last
|
||||
possible position of the first line.
|
||||
</para>
|
||||
|
||||
</section>
|
||||
|
||||
</section>
|
||||
|
||||
|
||||
<section>
|
||||
<title>Semantic Information</title>
|
||||
|
||||
<para>The semantic information is completely provided by the
|
||||
|
||||
<para>The semantic information is completely provided by the
|
||||
<classname>boost::program_options::value_semantic</classname> class. For
|
||||
example:
|
||||
<programlisting>
|
||||
@@ -303,18 +303,18 @@ desc.add_options()
|
||||
("email", value< vector<string> >()
|
||||
->composing()->notifier(&your_function), "email")
|
||||
;
|
||||
</programlisting>
|
||||
</programlisting>
|
||||
These declarations specify that default value of the first option is 10,
|
||||
that the second option can appear several times and all instances should
|
||||
be merged, and that after parsing is done, the library will call
|
||||
function <code>&your_function</code>, passing the value of the
|
||||
"email" option as argument.
|
||||
"email" option as argument.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
|
||||
<section>
|
||||
<title>Positional Options</title>
|
||||
|
||||
|
||||
<para>Our definition of option as (name, value) pairs is simple and
|
||||
useful, but in one special case of the command line, there's a
|
||||
problem. A command line can include a <firstterm>positional option</firstterm>,
|
||||
@@ -324,7 +324,7 @@ desc.add_options()
|
||||
</screen>
|
||||
Here, the "/etc/passwd" element does not have any option name.
|
||||
</para>
|
||||
|
||||
|
||||
<para>One solution is to ask the user to extract positional options
|
||||
himself and process them as he likes. However, there's a nicer approach
|
||||
-- provide a method to automatically assign the names for positional
|
||||
@@ -334,7 +334,7 @@ desc.add_options()
|
||||
archiver --compression=9 --input-file=/etc/passwd
|
||||
</screen>
|
||||
</para>
|
||||
|
||||
|
||||
<para>The &positional_options_desc; class allows the command line
|
||||
parser to assign the names. The class specifies how many positional options
|
||||
are allowed, and for each allowed option, specifies the name. For example:
|
||||
@@ -343,7 +343,7 @@ positional_options_description pd; pd.add("input-file", 1);
|
||||
</programlisting> specifies that for exactly one, first, positional
|
||||
option the name will be "input-file".
|
||||
</para>
|
||||
|
||||
|
||||
<para>It's possible to specify that a number, or even all positional options, be
|
||||
given the same name.
|
||||
<programlisting>
|
||||
@@ -360,11 +360,11 @@ pd.add("output-file", 2).add("input-file", -1);
|
||||
an instance of the &options_description; class.</para>
|
||||
</warning>
|
||||
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
|
||||
<!-- Note that the classes are not modified during parsing -->
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
<section>
|
||||
@@ -390,7 +390,7 @@ pd.add("output-file", 2).add("input-file", -1);
|
||||
The results of parsing are returned as an instance of the &parsed_options;
|
||||
class. Typically, that object is passed directly to the storage
|
||||
component. However, it also can be used directly, or undergo some additional
|
||||
processing.
|
||||
processing.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
@@ -422,8 +422,8 @@ pd.add("output-file", 2).add("input-file", -1);
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
|
||||
</para>
|
||||
|
||||
</section>
|
||||
|
||||
|
||||
@@ -512,7 +512,7 @@ visual_bell=yes
|
||||
<screen>
|
||||
gui.accessibility.visual_bell=yes
|
||||
</screen>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
<section>
|
||||
@@ -538,7 +538,7 @@ gui.accessibility.visual_bell=yes
|
||||
what option names must correspond to it. To describe the second
|
||||
parameter we need to consider naming conventions for environment
|
||||
variables.</para>
|
||||
|
||||
|
||||
<para>If you have an option that should be specified via environment
|
||||
variable, you need make up the variable's name. To avoid name clashes,
|
||||
we suggest that you use a sufficiently unique prefix for environment
|
||||
@@ -551,9 +551,9 @@ gui.accessibility.visual_bell=yes
|
||||
Say, if you pass <literal>BOOST_</literal> as the prefix, and there are
|
||||
two variables, <envar>CVSROOT</envar> and <envar>BOOST_PROXY</envar>, the
|
||||
first variable will be ignored, and the second one will be converted to
|
||||
option <literal>proxy</literal>.
|
||||
option <literal>proxy</literal>.
|
||||
</para>
|
||||
|
||||
|
||||
<para>The above logic is sufficient in many cases, but it is also
|
||||
possible to pass, as the second parameter of the &parse_environment;
|
||||
function, any function taking a <code>std::string</code> and returning
|
||||
@@ -561,35 +561,35 @@ gui.accessibility.visual_bell=yes
|
||||
environment variable and should return either the name of the option, or
|
||||
empty string if the variable should be ignored.
|
||||
</para>
|
||||
|
||||
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Annotated List of Symbols</title>
|
||||
|
||||
|
||||
<para>The following table describes all the important symbols in the
|
||||
library, for quick access.</para>
|
||||
|
||||
|
||||
<informaltable pgwide="1">
|
||||
|
||||
|
||||
<tgroup cols="2">
|
||||
<colspec colname='c1'/>
|
||||
<colspec colname='c2'/>
|
||||
<thead>
|
||||
|
||||
<row>
|
||||
|
||||
<row>
|
||||
<entry>Symbol</entry>
|
||||
<entry>Description</entry>
|
||||
</row>
|
||||
</thead>
|
||||
|
||||
|
||||
<tbody>
|
||||
|
||||
<row>
|
||||
|
||||
<row>
|
||||
<entry namest='c1' nameend='c2'>Options description component</entry>
|
||||
</row>
|
||||
|
||||
|
||||
<row>
|
||||
<entry>&options_description;</entry>
|
||||
<entry>describes a number of options</entry>
|
||||
@@ -599,10 +599,10 @@ gui.accessibility.visual_bell=yes
|
||||
<entry>defines the option's value</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<row>
|
||||
<entry namest='c1' nameend='c2'>Parsers component</entry>
|
||||
</row>
|
||||
|
||||
|
||||
<row>
|
||||
<entry>&parse_command_line;</entry>
|
||||
<entry>parses command line (simpified interface)</entry>
|
||||
@@ -624,7 +624,7 @@ gui.accessibility.visual_bell=yes
|
||||
<entry>parses environment</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<row>
|
||||
<entry namest='c1' nameend='c2'>Storage component</entry>
|
||||
</row>
|
||||
|
||||
@@ -632,20 +632,20 @@ gui.accessibility.visual_bell=yes
|
||||
<entry>&variables_map;</entry>
|
||||
<entry>storage for option values</entry>
|
||||
</row>
|
||||
|
||||
|
||||
</tbody>
|
||||
</tgroup>
|
||||
|
||||
|
||||
</informaltable>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
<!--
|
||||
Local Variables:
|
||||
mode: nxml
|
||||
sgml-indent-data: t
|
||||
sgml-indent-data: t
|
||||
sgml-parent-document: ("program_options.xml" "section")
|
||||
sgml-set-face: t
|
||||
End:
|
||||
|
||||
@@ -4,12 +4,12 @@ implement generic composition classes. The former was choosen,
|
||||
mostly because of simplicity.
|
||||
|
||||
There were two implementation approaches for multiple option
|
||||
occurences in options_and_arguments. First is store them
|
||||
occurrences in options_and_arguments. First is store them
|
||||
separately. The advantage is that it's easy to obtain all
|
||||
occurences before certain position on command line. The
|
||||
occurrences before certain position on command line. The
|
||||
disadvantage is that we cannot return a reference to
|
||||
vector<vector<string> > in get_all_values. It was considered
|
||||
that if support for position-dependent options is to be
|
||||
added, then we're be mostly interested in occurences of
|
||||
added, then we're be mostly interested in occurrences of
|
||||
a single option that were before some point. That's possible
|
||||
with vector<vector<string> > storage.
|
||||
with vector<vector<string> > storage.
|
||||
|
||||
@@ -81,7 +81,7 @@
|
||||
|
||||
@section help_handling Handling of --help
|
||||
|
||||
It was suggested by Gennadiy Rozental that occurence of <tt>--help</tt>
|
||||
It was suggested by Gennadiy Rozental that occurrence of <tt>--help</tt>
|
||||
on command line results in throwing an exception. Actually, the
|
||||
"special" option must have been configurable. This was not
|
||||
implemented, because applications might reasonable want to process
|
||||
|
||||
@@ -77,13 +77,13 @@ if (vm.count("compression")) {
|
||||
<para>It's now a good time to try compiling the code yourself, but if
|
||||
you're not yet ready, here's an example session:
|
||||
<screen>
|
||||
$<userinput>bin/gcc/debug/first</userinput>
|
||||
$ <userinput>bin/gcc/debug/first</userinput>
|
||||
Compression level was not set.
|
||||
$<userinput>bin/gcc/debug/first --help</userinput>
|
||||
$ <userinput>bin/gcc/debug/first --help</userinput>
|
||||
Allowed options:
|
||||
--help : produce help message
|
||||
--compression arg : set compression level
|
||||
$<userinput>bin/gcc/debug/first --compression 10</userinput>
|
||||
$ <userinput>bin/gcc/debug/first --compression 10</userinput>
|
||||
Compression level was set to 10.
|
||||
</screen>
|
||||
</para>
|
||||
@@ -199,16 +199,16 @@ cout << "Optimization level is " << opt << "\n&
|
||||
|
||||
<para>Here's an example session:
|
||||
<screen>
|
||||
$<userinput>bin/gcc/debug/options_description --help</userinput>
|
||||
$ <userinput>bin/gcc/debug/options_description --help</userinput>
|
||||
Usage: options_description [options]
|
||||
Allowed options:
|
||||
--help : produce help message
|
||||
--optimization arg : optimization level
|
||||
-I [ --include-path ] arg : include path
|
||||
--input-file arg : input file
|
||||
$bin/gcc/debug/options_description
|
||||
$ <userinput>bin/gcc/debug/options_description</userinput>
|
||||
Optimization level is 10
|
||||
$<userinput>bin/gcc/debug/options_description --optimization 4 -I foo a.cpp</userinput>
|
||||
$ <userinput>bin/gcc/debug/options_description --optimization 4 -I foo a.cpp</userinput>
|
||||
Include paths are: foo
|
||||
Input files are: a.cpp
|
||||
Optimization level is 4
|
||||
@@ -308,10 +308,10 @@ visible.add(generic).add(config);
|
||||
|
||||
<para>Here's an example session:
|
||||
<screen>
|
||||
$<userinput>bin/gcc/debug/multiple_sources</userinput>
|
||||
$ <userinput>bin/gcc/debug/multiple_sources</userinput>
|
||||
Include paths are: /opt
|
||||
Optimization level is 1
|
||||
$<userinput>bin/gcc/debug/multiple_sources --help</userinput>
|
||||
$ <userinput>bin/gcc/debug/multiple_sources --help</userinput>
|
||||
Allows options:
|
||||
|
||||
Generic options:
|
||||
@@ -322,7 +322,7 @@ Configuration:
|
||||
--optimization n : optimization level
|
||||
-I [ --include-path ] path : include path
|
||||
|
||||
$<userinput>bin/gcc/debug/multiple_sources --optimization=4 -I foo a.cpp b.cpp</userinput>
|
||||
$ <userinput>bin/gcc/debug/multiple_sources --optimization=4 -I foo a.cpp b.cpp</userinput>
|
||||
Include paths are: foo /opt
|
||||
Input files are: a.cpp b.cpp
|
||||
Optimization level is 4
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
project
|
||||
: requirements <library>../build//boost_program_options
|
||||
<hardcode-dll-paths>true
|
||||
<link>static
|
||||
;
|
||||
|
||||
exe first : first.cpp ;
|
||||
|
||||
@@ -20,7 +20,7 @@ int main(int ac, char* av[])
|
||||
po::options_description desc("Allowed options");
|
||||
desc.add_options()
|
||||
("help", "produce help message")
|
||||
("compression", po::value<int>(), "set compression level")
|
||||
("compression", po::value<double>(), "set compression level")
|
||||
;
|
||||
|
||||
po::variables_map vm;
|
||||
@@ -29,12 +29,12 @@ int main(int ac, char* av[])
|
||||
|
||||
if (vm.count("help")) {
|
||||
cout << desc << "\n";
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (vm.count("compression")) {
|
||||
cout << "Compression level was set to "
|
||||
<< vm["compression"].as<int>() << ".\n";
|
||||
<< vm["compression"].as<double>() << ".\n";
|
||||
} else {
|
||||
cout << "Compression level was not set.\n";
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ using namespace std;
|
||||
template<class T>
|
||||
ostream& operator<<(ostream& os, const vector<T>& v)
|
||||
{
|
||||
copy(v.begin(), v.end(), ostream_iterator<T>(cout, " "));
|
||||
copy(v.begin(), v.end(), ostream_iterator<T>(os, " "));
|
||||
return os;
|
||||
}
|
||||
|
||||
@@ -79,7 +79,7 @@ int main(int ac, char* av[])
|
||||
ifstream ifs(config_file.c_str());
|
||||
if (!ifs)
|
||||
{
|
||||
cout << "can not open config file: " << config_file << "\n";
|
||||
cout << "can not open config file: " << config_file << "\n";
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
|
||||
@@ -29,9 +29,9 @@ using namespace boost::program_options;
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <exception>
|
||||
using namespace std;
|
||||
|
||||
|
||||
int main(int ac, char* av[])
|
||||
{
|
||||
try {
|
||||
@@ -39,7 +39,7 @@ int main(int ac, char* av[])
|
||||
options_description general("General options");
|
||||
general.add_options()
|
||||
("help", "produce a help message")
|
||||
("help-module", value<string>()->implicit(),
|
||||
("help-module", value<string>(),
|
||||
"produce a help for a given module")
|
||||
("version", "output the version number")
|
||||
;
|
||||
@@ -91,7 +91,7 @@ int main(int ac, char* av[])
|
||||
<< vm["num-threads"].as<int>() << "\n";
|
||||
}
|
||||
}
|
||||
catch(exception& e) {
|
||||
catch(std::exception& e) {
|
||||
cout << e.what() << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ using namespace std;
|
||||
template<class T>
|
||||
ostream& operator<<(ostream& os, const vector<T>& v)
|
||||
{
|
||||
copy(v.begin(), v.end(), ostream_iterator<T>(cout, " "));
|
||||
copy(v.begin(), v.end(), ostream_iterator<T>(os, " "));
|
||||
return os;
|
||||
}
|
||||
|
||||
@@ -30,26 +30,26 @@ int main(int ac, char* av[])
|
||||
po::options_description desc("Allowed options");
|
||||
desc.add_options()
|
||||
("help", "produce help message")
|
||||
("optimization", po::value<int>(&opt)->default_value(10),
|
||||
("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,I", po::value< vector<string> >(),
|
||||
"include path")
|
||||
("input-file", po::value< vector<string> >(), "input file")
|
||||
;
|
||||
|
||||
po::positional_options_description p;
|
||||
p.add("input-file", -1);
|
||||
|
||||
|
||||
po::variables_map vm;
|
||||
po::store(po::command_line_parser(ac, av).
|
||||
options(desc).positional(p).run(), vm);
|
||||
po::notify(vm);
|
||||
|
||||
|
||||
if (vm.count("help")) {
|
||||
cout << "Usage: options_description [options]\n";
|
||||
cout << desc;
|
||||
@@ -58,13 +58,13 @@ int main(int ac, char* av[])
|
||||
|
||||
if (vm.count("include-path"))
|
||||
{
|
||||
cout << "Include paths are: "
|
||||
cout << "Include paths are: "
|
||||
<< vm["include-path"].as< vector<string> >() << "\n";
|
||||
}
|
||||
|
||||
if (vm.count("input-file"))
|
||||
{
|
||||
cout << "Input files are: "
|
||||
cout << "Input files are: "
|
||||
<< vm["input-file"].as< vector<string> >() << "\n";
|
||||
}
|
||||
|
||||
@@ -73,14 +73,14 @@ int main(int ac, char* av[])
|
||||
<< "\n";
|
||||
}
|
||||
|
||||
cout << "Optimization level is " << opt << "\n";
|
||||
cout << "Optimization level is " << opt << "\n";
|
||||
|
||||
cout << "Listen port is " << portnum << "\n";
|
||||
cout << "Listen port is " << portnum << "\n";
|
||||
}
|
||||
catch(std::exception& e)
|
||||
{
|
||||
cout << e.what() << "\n";
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
#ifndef PROGRAM_OPTIONS_VP_2003_05_19
|
||||
#define PROGRAM_OPTIONS_VP_2003_05_19
|
||||
|
||||
#if _MSC_VER >= 1020
|
||||
#if defined(_MSC_VER)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
|
||||
@@ -34,17 +34,14 @@
|
||||
#endif // BOOST_VERSION
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Windows DLL suport
|
||||
#ifdef BOOST_HAS_DECLSPEC
|
||||
#if defined(BOOST_ALL_DYN_LINK) || defined(BOOST_PROGRAM_OPTIONS_DYN_LINK)
|
||||
// export if this is our own source, otherwise import:
|
||||
#ifdef BOOST_PROGRAM_OPTIONS_SOURCE
|
||||
# define BOOST_PROGRAM_OPTIONS_DECL __declspec(dllexport)
|
||||
# define BOOST_PROGRAM_OPTIONS_DECL BOOST_SYMBOL_EXPORT
|
||||
#else
|
||||
# define BOOST_PROGRAM_OPTIONS_DECL __declspec(dllimport)
|
||||
# define BOOST_PROGRAM_OPTIONS_DECL BOOST_SYMBOL_IMPORT
|
||||
#endif // BOOST_PROGRAM_OPTIONS_SOURCE
|
||||
#endif // DYN_LINK
|
||||
#endif // BOOST_HAS_DECLSPEC
|
||||
|
||||
#ifndef BOOST_PROGRAM_OPTIONS_DECL
|
||||
#define BOOST_PROGRAM_OPTIONS_DECL
|
||||
|
||||
@@ -22,6 +22,11 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#if defined(BOOST_MSVC)
|
||||
# pragma warning (push)
|
||||
# pragma warning (disable:4251) // class 'std::vector<_Ty>' needs to have dll-interface to be used by clients of class 'boost::program_options::positional_options_description'
|
||||
#endif
|
||||
|
||||
namespace boost { namespace program_options { namespace detail {
|
||||
|
||||
/** Command line parser class. Main requirements were:
|
||||
@@ -76,6 +81,18 @@ namespace boost { namespace program_options { namespace detail {
|
||||
cmdline(int argc, const char*const * argv);
|
||||
|
||||
void style(int style);
|
||||
|
||||
/** returns the canonical option prefix associated with the command_line_style
|
||||
* In order of precedence:
|
||||
* allow_long : allow_long
|
||||
* allow_long_disguise : allow_long_disguise
|
||||
* allow_dash_for_short : allow_short | allow_dash_for_short
|
||||
* allow_slash_for_short: allow_short | allow_slash_for_short
|
||||
*
|
||||
* This is mainly used for the diagnostic messages in exceptions
|
||||
*/
|
||||
int get_canonical_option_prefix();
|
||||
|
||||
void allow_unregistered();
|
||||
|
||||
void set_options_description(const options_description& desc);
|
||||
@@ -134,5 +151,9 @@ namespace boost { namespace program_options { namespace detail {
|
||||
|
||||
}}}
|
||||
|
||||
#if defined(BOOST_MSVC)
|
||||
# pragma warning (pop)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -17,9 +17,7 @@
|
||||
#include <boost/program_options/eof_iterator.hpp>
|
||||
|
||||
#include <boost/detail/workaround.hpp>
|
||||
#if BOOST_WORKAROUND(__MWERKS__, BOOST_TESTED_AT(0x3202))
|
||||
#include <boost/program_options/detail/convert.hpp>
|
||||
#endif
|
||||
|
||||
#if BOOST_WORKAROUND(__DECCXX_VER, BOOST_TESTED_AT(60590042))
|
||||
#include <istream> // std::getline
|
||||
@@ -29,6 +27,11 @@
|
||||
#include <boost/type_traits/is_same.hpp>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
#ifdef BOOST_MSVC
|
||||
# pragma warning(push)
|
||||
# pragma warning(disable: 4251) // class XYZ needs to have dll-interface to be used by clients of class XYZ
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
namespace boost { namespace program_options { namespace detail {
|
||||
@@ -64,7 +67,7 @@ namespace boost { namespace program_options { namespace detail {
|
||||
TODO: maybe, we should just accept a pointer to options_description
|
||||
class.
|
||||
*/
|
||||
class common_config_file_iterator
|
||||
class BOOST_PROGRAM_OPTIONS_DECL common_config_file_iterator
|
||||
: public eof_iterator<common_config_file_iterator, option>
|
||||
{
|
||||
public:
|
||||
@@ -79,6 +82,11 @@ namespace boost { namespace program_options { namespace detail {
|
||||
|
||||
void get();
|
||||
|
||||
#if BOOST_WORKAROUND(_MSC_VER, <= 1900)
|
||||
void decrement() {}
|
||||
void advance(difference_type) {}
|
||||
#endif
|
||||
|
||||
protected: // Stubs for derived classes
|
||||
|
||||
// Obtains next line from the config file
|
||||
@@ -179,4 +187,8 @@ namespace boost { namespace program_options { namespace detail {
|
||||
|
||||
}}}
|
||||
|
||||
#ifdef BOOST_MSVC
|
||||
# pragma warning(pop)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -29,18 +29,19 @@ namespace boost { namespace program_options {
|
||||
template<class charT>
|
||||
basic_command_line_parser<charT>::
|
||||
basic_command_line_parser(const std::vector<
|
||||
std::basic_string<charT> >& args)
|
||||
: detail::cmdline(to_internal(args))
|
||||
std::basic_string<charT> >& xargs)
|
||||
: detail::cmdline(to_internal(xargs))
|
||||
{}
|
||||
|
||||
|
||||
template<class charT>
|
||||
basic_command_line_parser<charT>::
|
||||
basic_command_line_parser(int argc, charT* argv[])
|
||||
basic_command_line_parser(int argc, const charT* const argv[])
|
||||
: detail::cmdline(
|
||||
// Explicit template arguments are required by gcc 3.3.1
|
||||
// (at least mingw version), and do no harm on other compilers.
|
||||
to_internal(detail::make_vector<charT, charT**>(argv+1, argv+argc+!argc)))
|
||||
to_internal(detail::make_vector<charT, const charT* const*>(argv+1, argv+argc+!argc))),
|
||||
m_desc()
|
||||
{}
|
||||
|
||||
|
||||
@@ -64,9 +65,9 @@ namespace boost { namespace program_options {
|
||||
|
||||
template<class charT>
|
||||
basic_command_line_parser<charT>&
|
||||
basic_command_line_parser<charT>::style(int style)
|
||||
basic_command_line_parser<charT>::style(int xstyle)
|
||||
{
|
||||
detail::cmdline::style(style);
|
||||
detail::cmdline::style(xstyle);
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -100,7 +101,11 @@ namespace boost { namespace program_options {
|
||||
basic_parsed_options<charT>
|
||||
basic_command_line_parser<charT>::run()
|
||||
{
|
||||
parsed_options result(m_desc);
|
||||
// save the canonical prefixes which were used by this cmdline parser
|
||||
// eventually inside the parsed results
|
||||
// This will be handy to format recognisable options
|
||||
// for diagnostic messages if everything blows up much later on
|
||||
parsed_options result(m_desc, detail::cmdline::get_canonical_option_prefix());
|
||||
result.options = detail::cmdline::run();
|
||||
|
||||
// Presense of parsed_options -> wparsed_options conversion
|
||||
@@ -111,7 +116,7 @@ namespace boost { namespace program_options {
|
||||
|
||||
template<class charT>
|
||||
basic_parsed_options<charT>
|
||||
parse_command_line(int argc, charT* argv[],
|
||||
parse_command_line(int argc, const charT* const argv[],
|
||||
const options_description& desc,
|
||||
int style,
|
||||
function1<std::pair<std::string, std::string>,
|
||||
|
||||
@@ -16,16 +16,17 @@ namespace boost { namespace program_options {
|
||||
std::string
|
||||
typed_value<T, charT>::name() const
|
||||
{
|
||||
std::string const& var = (m_value_name.empty() ? arg : m_value_name);
|
||||
if (!m_implicit_value.empty() && !m_implicit_value_as_text.empty()) {
|
||||
std::string msg = "[=arg(=" + m_implicit_value_as_text + ")]";
|
||||
std::string msg = "[=" + var + "(=" + 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 + ")";
|
||||
return var + " (=" + m_default_value_as_text + ")";
|
||||
} else {
|
||||
return arg;
|
||||
return var;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,12 +105,9 @@ namespace boost { namespace program_options {
|
||||
int);
|
||||
#endif
|
||||
// For some reason, this declaration, which is require by the standard,
|
||||
// cause gcc 3.2 to not generate code to specialization defined in
|
||||
// cause msvc 7.1 to not generate code to specialization defined in
|
||||
// value_semantic.cpp
|
||||
#if ! ( ( BOOST_WORKAROUND(__GNUC__, <= 3) &&\
|
||||
BOOST_WORKAROUND(__GNUC_MINOR__, < 3) ) || \
|
||||
( BOOST_WORKAROUND(BOOST_MSVC, == 1310) ) \
|
||||
)
|
||||
#if ! ( BOOST_WORKAROUND(BOOST_MSVC, == 1310) )
|
||||
BOOST_PROGRAM_OPTIONS_DECL void validate(boost::any& v,
|
||||
const std::vector<std::string>& xs,
|
||||
std::string*,
|
||||
@@ -143,9 +141,9 @@ namespace boost { namespace program_options {
|
||||
a validator for class T, we use it even
|
||||
when parsing vector<T>. */
|
||||
boost::any a;
|
||||
std::vector<std::basic_string<charT> > v;
|
||||
v.push_back(s[i]);
|
||||
validate(a, v, (T*)0, 0);
|
||||
std::vector<std::basic_string<charT> > cv;
|
||||
cv.push_back(s[i]);
|
||||
validate(a, cv, (T*)0, 0);
|
||||
tv->push_back(boost::any_cast<T>(a));
|
||||
}
|
||||
catch(const bad_lexical_cast& /*e*/) {
|
||||
|
||||
@@ -40,8 +40,9 @@ namespace boost {
|
||||
assert(n != s.npos);
|
||||
value().first = s.substr(0, n);
|
||||
value().second = s.substr(n+1);
|
||||
}
|
||||
++m_environment;
|
||||
|
||||
++m_environment;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
@@ -10,17 +10,17 @@
|
||||
|
||||
namespace boost {
|
||||
|
||||
/** The 'eof_iterator' class is useful for constructing forward iterators
|
||||
in cases where iterator extract data from some source and it's easy
|
||||
to detect 'eof' -- i.e. the situation where there's no data. One
|
||||
/** The 'eof_iterator' class is useful for constructing forward iterators
|
||||
in cases where iterator extract data from some source and it's easy
|
||||
to detect 'eof' \-- i.e. the situation where there's no data. One
|
||||
apparent example is reading lines from a file.
|
||||
|
||||
|
||||
Implementing such iterators using 'iterator_facade' directly would
|
||||
require to create class with three core operation, a couple of
|
||||
constructors. When using 'eof_iterator', the derived class should define
|
||||
require to create class with three core operation, a couple of
|
||||
constructors. When using 'eof_iterator', the derived class should define
|
||||
only one method to get new value, plus a couple of constructors.
|
||||
|
||||
The basic idea is that iterator has 'eof' bit. Two iterators are equal
|
||||
The basic idea is that iterator has 'eof' bit. Two iterators are equal
|
||||
only if both have their 'eof' bits set. The 'get' method either obtains
|
||||
the new value or sets the 'eof' bit.
|
||||
|
||||
@@ -33,13 +33,13 @@ namespace boost {
|
||||
3. The 'get' method. It should operate this way:
|
||||
- look at some 'data pointer' to see if new element is available;
|
||||
if not, it should call 'found_eof'.
|
||||
- extract new element and store it at location returned by the 'value'
|
||||
- extract new element and store it at location returned by the 'value'
|
||||
method.
|
||||
- advance the data pointer.
|
||||
|
||||
Essentially, the 'get' method has the functionality of both 'increment'
|
||||
and 'dereference'. It's very good for the cases where data extraction
|
||||
implicitly moves data pointer, like for stream operation.
|
||||
Essentially, the 'get' method has the functionality of both 'increment'
|
||||
and 'dereference'. It's very good for the cases where data extraction
|
||||
implicitly moves data pointer, like for stream operation.
|
||||
*/
|
||||
template<class Derived, class ValueType>
|
||||
class eof_iterator : public iterator_facade<Derived, const ValueType,
|
||||
@@ -65,16 +65,16 @@ namespace boost {
|
||||
{
|
||||
m_at_eof = true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
private: // iterator core operations
|
||||
friend class iterator_core_access;
|
||||
|
||||
void increment()
|
||||
|
||||
void increment()
|
||||
{
|
||||
static_cast<Derived&>(*this).get();
|
||||
}
|
||||
|
||||
|
||||
bool equal(const eof_iterator& other) const
|
||||
{
|
||||
if (m_at_eof && other.m_at_eof)
|
||||
@@ -82,14 +82,14 @@ namespace boost {
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
const ValueType& dereference() const
|
||||
{
|
||||
return m_value;
|
||||
}
|
||||
|
||||
bool m_at_eof;
|
||||
ValueType m_value;
|
||||
ValueType m_value;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -12,175 +12,29 @@
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
|
||||
#if defined(BOOST_MSVC)
|
||||
# pragma warning (push)
|
||||
# pragma warning (disable:4275) // non dll-interface class 'std::logic_error' used as base for dll-interface class 'boost::program_options::error'
|
||||
# pragma warning (disable:4251) // class 'std::vector<_Ty>' needs to have dll-interface to be used by clients of class 'boost::program_options::ambiguous_option'
|
||||
#endif
|
||||
|
||||
namespace boost { namespace program_options {
|
||||
|
||||
inline std::string strip_prefixes(const std::string& text)
|
||||
{
|
||||
// "--foo-bar" -> "foo-bar"
|
||||
return text.substr(text.find_first_not_of("-/"));
|
||||
}
|
||||
|
||||
/** Base class for all errors in the library. */
|
||||
class BOOST_PROGRAM_OPTIONS_DECL error : public std::logic_error {
|
||||
public:
|
||||
error(const std::string& what) : std::logic_error(what) {}
|
||||
error(const std::string& xwhat) : std::logic_error(xwhat) {}
|
||||
};
|
||||
|
||||
class BOOST_PROGRAM_OPTIONS_DECL invalid_syntax : public error {
|
||||
public:
|
||||
enum kind_t {
|
||||
long_not_allowed = 30,
|
||||
long_adjacent_not_allowed,
|
||||
short_adjacent_not_allowed,
|
||||
empty_adjacent_parameter,
|
||||
missing_parameter,
|
||||
extra_parameter,
|
||||
unrecognized_line
|
||||
};
|
||||
|
||||
invalid_syntax(const std::string& tokens, kind_t kind);
|
||||
|
||||
// gcc says that throw specification on dtor is loosened
|
||||
// without this line
|
||||
~invalid_syntax() throw() {}
|
||||
|
||||
kind_t kind() const;
|
||||
|
||||
const std::string& tokens() const;
|
||||
|
||||
protected:
|
||||
/** Used to convert kind_t to a related error text */
|
||||
static std::string error_message(kind_t kind);
|
||||
|
||||
private:
|
||||
// TODO: copy ctor might throw
|
||||
std::string m_tokens;
|
||||
|
||||
kind_t m_kind;
|
||||
};
|
||||
|
||||
/** Class thrown when option name is not recognized. */
|
||||
class BOOST_PROGRAM_OPTIONS_DECL unknown_option : public error {
|
||||
public:
|
||||
unknown_option(const std::string& name)
|
||||
: error(std::string("unknown option ").append(name)),
|
||||
m_option_name(name)
|
||||
{}
|
||||
|
||||
// gcc says that throw specification on dtor is loosened
|
||||
// without this line
|
||||
~unknown_option() throw() {}
|
||||
|
||||
const std::string& get_option_name() const throw();
|
||||
|
||||
private:
|
||||
std::string m_option_name;
|
||||
};
|
||||
|
||||
/** Class thrown when there's ambiguity amoung several possible options. */
|
||||
class BOOST_PROGRAM_OPTIONS_DECL ambiguous_option : public error {
|
||||
public:
|
||||
ambiguous_option(const std::string& name,
|
||||
const std::vector<std::string>& alternatives)
|
||||
: error(std::string("ambiguous option ").append(name))
|
||||
, m_alternatives(alternatives)
|
||||
, m_option_name(name)
|
||||
{}
|
||||
|
||||
~ambiguous_option() throw() {}
|
||||
|
||||
const std::string& get_option_name() const throw();
|
||||
|
||||
const std::vector<std::string>& alternatives() const throw();
|
||||
|
||||
private:
|
||||
// TODO: copy ctor might throw
|
||||
std::vector<std::string> m_alternatives;
|
||||
std::string m_option_name;
|
||||
};
|
||||
|
||||
/** Class thrown when there are several option values, but
|
||||
user called a method which cannot return them all. */
|
||||
class BOOST_PROGRAM_OPTIONS_DECL multiple_values : public error {
|
||||
public:
|
||||
multiple_values()
|
||||
: error("multiple values")
|
||||
, m_option_name() {}
|
||||
|
||||
~multiple_values() throw() {}
|
||||
|
||||
void set_option_name(const std::string& option);
|
||||
|
||||
const std::string& get_option_name() const throw();
|
||||
|
||||
private:
|
||||
std::string m_option_name; // The name of the option which
|
||||
// caused the exception.
|
||||
};
|
||||
|
||||
/** Class thrown when there are several occurrences of an
|
||||
option, but user called a method which cannot return
|
||||
them all. */
|
||||
class BOOST_PROGRAM_OPTIONS_DECL multiple_occurrences : public error {
|
||||
public:
|
||||
multiple_occurrences()
|
||||
: error("multiple occurrences")
|
||||
, m_option_name() {}
|
||||
|
||||
~multiple_occurrences() throw() {}
|
||||
|
||||
void set_option_name(const std::string& option);
|
||||
|
||||
const std::string& get_option_name() const throw();
|
||||
|
||||
private:
|
||||
std::string m_option_name; // The name of the option which
|
||||
// caused the exception.
|
||||
};
|
||||
|
||||
/** Class thrown when value of option is incorrect. */
|
||||
class BOOST_PROGRAM_OPTIONS_DECL validation_error : public error {
|
||||
public:
|
||||
enum kind_t {
|
||||
multiple_values_not_allowed = 30,
|
||||
at_least_one_value_required,
|
||||
invalid_bool_value,
|
||||
invalid_option_value,
|
||||
invalid_option
|
||||
};
|
||||
|
||||
validation_error(kind_t kind,
|
||||
const std::string& option_value = "",
|
||||
const std::string& option_name = "");
|
||||
|
||||
~validation_error() throw() {}
|
||||
|
||||
void set_option_name(const std::string& option);
|
||||
|
||||
const std::string& get_option_name() const throw();
|
||||
|
||||
const char* what() const throw();
|
||||
|
||||
protected:
|
||||
/** Used to convert kind_t to a related error text */
|
||||
static std::string error_message(kind_t kind);
|
||||
|
||||
private:
|
||||
kind_t m_kind;
|
||||
std::string m_option_name; // The name of the option which
|
||||
// caused the exception.
|
||||
std::string m_option_value; // Optional: value of the option m_options_name
|
||||
mutable std::string m_message; // For on-demand formatting in 'what'
|
||||
|
||||
};
|
||||
|
||||
/** Class thrown if there is an invalid option value givenn */
|
||||
class BOOST_PROGRAM_OPTIONS_DECL invalid_option_value
|
||||
: public validation_error
|
||||
{
|
||||
public:
|
||||
invalid_option_value(const std::string& value);
|
||||
#ifndef BOOST_NO_STD_WSTRING
|
||||
invalid_option_value(const std::wstring& value);
|
||||
#endif
|
||||
};
|
||||
|
||||
/** Class thrown when there are too many positional options.
|
||||
This is a programming error.
|
||||
@@ -188,16 +42,10 @@ namespace boost { namespace program_options {
|
||||
class BOOST_PROGRAM_OPTIONS_DECL too_many_positional_options_error : public error {
|
||||
public:
|
||||
too_many_positional_options_error()
|
||||
: error("too many positional options")
|
||||
: error("too many positional options have been specified on the command line")
|
||||
{}
|
||||
};
|
||||
|
||||
/** Class thrown when there are syntax errors in given command line */
|
||||
class BOOST_PROGRAM_OPTIONS_DECL invalid_command_line_syntax : public invalid_syntax {
|
||||
public:
|
||||
invalid_command_line_syntax(const std::string& tokens, kind_t kind);
|
||||
};
|
||||
|
||||
/** Class thrown when there are programming error related to style */
|
||||
class BOOST_PROGRAM_OPTIONS_DECL invalid_command_line_style : public error {
|
||||
public:
|
||||
@@ -210,27 +58,359 @@ namespace boost { namespace program_options {
|
||||
class BOOST_PROGRAM_OPTIONS_DECL reading_file : public error {
|
||||
public:
|
||||
reading_file(const char* filename)
|
||||
: error(std::string("can not read file ").append(filename))
|
||||
: error(std::string("can not read options configuration file '").append(filename).append("'"))
|
||||
{}
|
||||
};
|
||||
|
||||
/** Class thrown when a required/mandatory option is missing */
|
||||
class BOOST_PROGRAM_OPTIONS_DECL required_option : public error {
|
||||
public:
|
||||
required_option(const std::string& name)
|
||||
: error(std::string("missing required option ").append(name))
|
||||
, m_option_name(name)
|
||||
{}
|
||||
|
||||
~required_option() throw() {}
|
||||
|
||||
const std::string& get_option_name() const throw();
|
||||
|
||||
/** Base class for most exceptions in the library.
|
||||
*
|
||||
* Substitutes the values for the parameter name
|
||||
* placeholders in the template to create the human
|
||||
* readable error message
|
||||
*
|
||||
* Placeholders are surrounded by % signs: %example%
|
||||
* Poor man's version of boost::format
|
||||
*
|
||||
* If a parameter name is absent, perform default substitutions
|
||||
* instead so ugly placeholders are never left in-place.
|
||||
*
|
||||
* Options are displayed in "canonical" form
|
||||
* This is the most unambiguous form of the
|
||||
* *parsed* option name and would correspond to
|
||||
* option_description::format_name()
|
||||
* i.e. what is shown by print_usage()
|
||||
*
|
||||
* The "canonical" form depends on whether the option is
|
||||
* specified in short or long form, using dashes or slashes
|
||||
* or without a prefix (from a configuration file)
|
||||
*
|
||||
* */
|
||||
class BOOST_PROGRAM_OPTIONS_DECL error_with_option_name : public error {
|
||||
|
||||
protected:
|
||||
/** can be
|
||||
* 0 = no prefix (config file options)
|
||||
* allow_long
|
||||
* allow_dash_for_short
|
||||
* allow_slash_for_short
|
||||
* allow_long_disguise */
|
||||
int m_option_style;
|
||||
|
||||
|
||||
/** substitutions
|
||||
* from placeholders to values */
|
||||
std::map<std::string, std::string> m_substitutions;
|
||||
typedef std::pair<std::string, std::string> string_pair;
|
||||
std::map<std::string, string_pair > m_substitution_defaults;
|
||||
|
||||
public:
|
||||
/** template with placeholders */
|
||||
std::string m_error_template;
|
||||
|
||||
error_with_option_name(const std::string& template_,
|
||||
const std::string& option_name = "",
|
||||
const std::string& original_token = "",
|
||||
int option_style = 0);
|
||||
|
||||
/** gcc says that throw specification on dtor is loosened
|
||||
* without this line
|
||||
* */
|
||||
~error_with_option_name() throw() {}
|
||||
|
||||
|
||||
//void dump() const
|
||||
//{
|
||||
// std::cerr << "m_substitution_defaults:\n";
|
||||
// for (std::map<std::string, string_pair>::const_iterator iter = m_substitution_defaults.begin();
|
||||
// iter != m_substitution_defaults.end(); ++iter)
|
||||
// std::cerr << "\t" << iter->first << ":" << iter->second.first << "=" << iter->second.second << "\n";
|
||||
// std::cerr << "m_substitutions:\n";
|
||||
// for (std::map<std::string, std::string>::const_iterator iter = m_substitutions.begin();
|
||||
// iter != m_substitutions.end(); ++iter)
|
||||
// std::cerr << "\t" << iter->first << "=" << iter->second << "\n";
|
||||
// std::cerr << "m_error_template:\n";
|
||||
// std::cerr << "\t" << m_error_template << "\n";
|
||||
// std::cerr << "canonical_option_prefix:[" << get_canonical_option_prefix() << "]\n";
|
||||
// std::cerr << "canonical_option_name:[" << get_canonical_option_name() <<"]\n";
|
||||
// std::cerr << "what:[" << what() << "]\n";
|
||||
//}
|
||||
|
||||
/** Substitute
|
||||
* parameter_name->value to create the error message from
|
||||
* the error template */
|
||||
void set_substitute(const std::string& parameter_name, const std::string& value)
|
||||
{ m_substitutions[parameter_name] = value; }
|
||||
|
||||
/** If the parameter is missing, then make the
|
||||
* from->to substitution instead */
|
||||
void set_substitute_default(const std::string& parameter_name,
|
||||
const std::string& from,
|
||||
const std::string& to)
|
||||
{
|
||||
m_substitution_defaults[parameter_name] = std::make_pair(from, to);
|
||||
}
|
||||
|
||||
|
||||
/** Add context to an exception */
|
||||
void add_context(const std::string& option_name,
|
||||
const std::string& original_token,
|
||||
int option_style)
|
||||
{
|
||||
set_option_name(option_name);
|
||||
set_original_token(original_token);
|
||||
set_prefix(option_style);
|
||||
}
|
||||
|
||||
void set_prefix(int option_style)
|
||||
{ m_option_style = option_style;}
|
||||
|
||||
/** Overridden in error_with_no_option_name */
|
||||
virtual void set_option_name(const std::string& option_name)
|
||||
{ set_substitute("option", option_name);}
|
||||
|
||||
std::string get_option_name() const throw()
|
||||
{ return get_canonical_option_name(); }
|
||||
|
||||
void set_original_token(const std::string& original_token)
|
||||
{ set_substitute("original_token", original_token);}
|
||||
|
||||
|
||||
/** Creates the error_message on the fly
|
||||
* Currently a thin wrapper for substitute_placeholders() */
|
||||
virtual const char* what() const throw();
|
||||
|
||||
protected:
|
||||
/** Used to hold the error text returned by what() */
|
||||
mutable std::string m_message; // For on-demand formatting in 'what'
|
||||
|
||||
/** Makes all substitutions using the template */
|
||||
virtual void substitute_placeholders(const std::string& error_template) const;
|
||||
|
||||
// helper function for substitute_placeholders
|
||||
void replace_token(const std::string& from, const std::string& to) const;
|
||||
|
||||
/** Construct option name in accordance with the appropriate
|
||||
* prefix style: i.e. long dash or short slash etc */
|
||||
std::string get_canonical_option_name() const;
|
||||
std::string get_canonical_option_prefix() const;
|
||||
};
|
||||
|
||||
|
||||
/** Class thrown when there are several option values, but
|
||||
user called a method which cannot return them all. */
|
||||
class BOOST_PROGRAM_OPTIONS_DECL multiple_values : public error_with_option_name {
|
||||
public:
|
||||
multiple_values()
|
||||
: error_with_option_name("option '%canonical_option%' only takes a single argument"){}
|
||||
|
||||
~multiple_values() throw() {}
|
||||
};
|
||||
|
||||
/** Class thrown when there are several occurrences of an
|
||||
option, but user called a method which cannot return
|
||||
them all. */
|
||||
class BOOST_PROGRAM_OPTIONS_DECL multiple_occurrences : public error_with_option_name {
|
||||
public:
|
||||
multiple_occurrences()
|
||||
: error_with_option_name("option '%canonical_option%' cannot be specified more than once"){}
|
||||
|
||||
~multiple_occurrences() throw() {}
|
||||
|
||||
};
|
||||
|
||||
/** Class thrown when a required/mandatory option is missing */
|
||||
class BOOST_PROGRAM_OPTIONS_DECL required_option : public error_with_option_name {
|
||||
public:
|
||||
// option name is constructed by the option_descriptor and never on the fly
|
||||
required_option(const std::string& option_name)
|
||||
: error_with_option_name("the option '%canonical_option%' is required but missing", "", option_name)
|
||||
{
|
||||
}
|
||||
|
||||
~required_option() throw() {}
|
||||
};
|
||||
|
||||
/** Base class of unparsable options,
|
||||
* when the desired option cannot be identified.
|
||||
*
|
||||
*
|
||||
* It makes no sense to have an option name, when we can't match an option to the
|
||||
* parameter
|
||||
*
|
||||
* Having this a part of the error_with_option_name hierachy makes error handling
|
||||
* a lot easier, even if the name indicates some sort of conceptual dissonance!
|
||||
*
|
||||
* */
|
||||
class BOOST_PROGRAM_OPTIONS_DECL error_with_no_option_name : public error_with_option_name {
|
||||
public:
|
||||
error_with_no_option_name(const std::string& template_,
|
||||
const std::string& original_token = "")
|
||||
: error_with_option_name(template_, "", original_token)
|
||||
{
|
||||
}
|
||||
|
||||
/** Does NOT set option name, because no option name makes sense */
|
||||
virtual void set_option_name(const std::string&) {}
|
||||
|
||||
~error_with_no_option_name() throw() {}
|
||||
};
|
||||
|
||||
|
||||
/** Class thrown when option name is not recognized. */
|
||||
class BOOST_PROGRAM_OPTIONS_DECL unknown_option : public error_with_no_option_name {
|
||||
public:
|
||||
unknown_option(const std::string& original_token = "")
|
||||
: error_with_no_option_name("unrecognised option '%canonical_option%'", original_token)
|
||||
{
|
||||
}
|
||||
|
||||
~unknown_option() throw() {}
|
||||
};
|
||||
|
||||
|
||||
|
||||
/** Class thrown when there's ambiguity amoung several possible options. */
|
||||
class BOOST_PROGRAM_OPTIONS_DECL ambiguous_option : public error_with_no_option_name {
|
||||
public:
|
||||
ambiguous_option(const std::vector<std::string>& xalternatives)
|
||||
: error_with_no_option_name("option '%canonical_option%' is ambiguous"),
|
||||
m_alternatives(xalternatives)
|
||||
{}
|
||||
|
||||
~ambiguous_option() throw() {}
|
||||
|
||||
const std::vector<std::string>& alternatives() const throw() {return m_alternatives;}
|
||||
|
||||
protected:
|
||||
/** Makes all substitutions using the template */
|
||||
virtual void substitute_placeholders(const std::string& error_template) const;
|
||||
private:
|
||||
// TODO: copy ctor might throw
|
||||
std::vector<std::string> m_alternatives;
|
||||
};
|
||||
|
||||
|
||||
/** Class thrown when there's syntax error either for command
|
||||
* line or config file options. See derived children for
|
||||
* concrete classes. */
|
||||
class BOOST_PROGRAM_OPTIONS_DECL invalid_syntax : public error_with_option_name {
|
||||
public:
|
||||
enum kind_t {
|
||||
long_not_allowed = 30,
|
||||
long_adjacent_not_allowed,
|
||||
short_adjacent_not_allowed,
|
||||
empty_adjacent_parameter,
|
||||
missing_parameter,
|
||||
extra_parameter,
|
||||
unrecognized_line
|
||||
};
|
||||
|
||||
invalid_syntax(kind_t kind,
|
||||
const std::string& option_name = "",
|
||||
const std::string& original_token = "",
|
||||
int option_style = 0):
|
||||
error_with_option_name(get_template(kind), option_name, original_token, option_style),
|
||||
m_kind(kind)
|
||||
{
|
||||
}
|
||||
|
||||
~invalid_syntax() throw() {}
|
||||
|
||||
kind_t kind() const {return m_kind;}
|
||||
|
||||
/** Convenience functions for backwards compatibility */
|
||||
virtual std::string tokens() const {return get_option_name(); }
|
||||
protected:
|
||||
/** Used to convert kind_t to a related error text */
|
||||
std::string get_template(kind_t kind);
|
||||
kind_t m_kind;
|
||||
};
|
||||
|
||||
class BOOST_PROGRAM_OPTIONS_DECL invalid_config_file_syntax : public invalid_syntax {
|
||||
public:
|
||||
invalid_config_file_syntax(const std::string& invalid_line, kind_t kind):
|
||||
invalid_syntax(kind)
|
||||
{
|
||||
m_substitutions["invalid_line"] = invalid_line;
|
||||
}
|
||||
|
||||
~invalid_config_file_syntax() throw() {}
|
||||
|
||||
/** Convenience functions for backwards compatibility */
|
||||
virtual std::string tokens() const {return m_substitutions.find("invalid_line")->second; }
|
||||
};
|
||||
|
||||
|
||||
/** Class thrown when there are syntax errors in given command line */
|
||||
class BOOST_PROGRAM_OPTIONS_DECL invalid_command_line_syntax : public invalid_syntax {
|
||||
public:
|
||||
invalid_command_line_syntax(kind_t kind,
|
||||
const std::string& option_name = "",
|
||||
const std::string& original_token = "",
|
||||
int option_style = 0):
|
||||
invalid_syntax(kind, option_name, original_token, option_style) {}
|
||||
~invalid_command_line_syntax() throw() {}
|
||||
};
|
||||
|
||||
|
||||
/** Class thrown when value of option is incorrect. */
|
||||
class BOOST_PROGRAM_OPTIONS_DECL validation_error : public error_with_option_name {
|
||||
public:
|
||||
enum kind_t {
|
||||
multiple_values_not_allowed = 30,
|
||||
at_least_one_value_required,
|
||||
invalid_bool_value,
|
||||
invalid_option_value,
|
||||
invalid_option
|
||||
};
|
||||
|
||||
private:
|
||||
std::string m_option_name; // The name of the option which
|
||||
// caused the exception.
|
||||
};
|
||||
public:
|
||||
validation_error(kind_t kind,
|
||||
const std::string& option_name = "",
|
||||
const std::string& original_token = "",
|
||||
int option_style = 0):
|
||||
error_with_option_name(get_template(kind), option_name, original_token, option_style)
|
||||
{
|
||||
}
|
||||
|
||||
~validation_error() throw() {}
|
||||
|
||||
protected:
|
||||
/** Used to convert kind_t to a related error text */
|
||||
std::string get_template(kind_t kind);
|
||||
kind_t m_kind;
|
||||
};
|
||||
|
||||
/** Class thrown if there is an invalid option value given */
|
||||
class BOOST_PROGRAM_OPTIONS_DECL invalid_option_value
|
||||
: public validation_error
|
||||
{
|
||||
public:
|
||||
invalid_option_value(const std::string& value);
|
||||
#ifndef BOOST_NO_STD_WSTRING
|
||||
invalid_option_value(const std::wstring& value);
|
||||
#endif
|
||||
};
|
||||
|
||||
/** Class thrown if there is an invalid bool value given */
|
||||
class BOOST_PROGRAM_OPTIONS_DECL invalid_bool_value
|
||||
: public validation_error
|
||||
{
|
||||
public:
|
||||
invalid_bool_value(const std::string& value);
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}}
|
||||
|
||||
#if defined(BOOST_MSVC)
|
||||
# pragma warning (pop)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -15,7 +15,7 @@ namespace boost { namespace program_options {
|
||||
|
||||
/** Option found in input source.
|
||||
Contains a key and a value. The key, in turn, can be a string (name of
|
||||
an option), or an integer (position in input source) -- in case no name
|
||||
an option), or an integer (position in input source) \-- in case no name
|
||||
is specified. The latter is only possible for command line.
|
||||
The template parameter specifies the type of char used for storing the
|
||||
option's value.
|
||||
@@ -28,10 +28,10 @@ namespace boost { namespace program_options {
|
||||
, unregistered(false)
|
||||
, case_insensitive(false)
|
||||
{}
|
||||
basic_option(const std::string& string_key,
|
||||
const std::vector< std::string> &value)
|
||||
: string_key(string_key)
|
||||
, value(value)
|
||||
basic_option(const std::string& xstring_key,
|
||||
const std::vector< std::string> &xvalue)
|
||||
: string_key(xstring_key)
|
||||
, value(xvalue)
|
||||
, unregistered(false)
|
||||
, case_insensitive(false)
|
||||
{}
|
||||
|
||||
@@ -25,6 +25,12 @@
|
||||
|
||||
#include <iosfwd>
|
||||
|
||||
#if defined(BOOST_MSVC)
|
||||
# pragma warning (push)
|
||||
# pragma warning (disable:4251) // class 'boost::shared_ptr<T>' needs to have dll-interface to be used by clients of class 'boost::program_options::option_description'
|
||||
#endif
|
||||
|
||||
|
||||
/** Boost namespace */
|
||||
namespace boost {
|
||||
/** Namespace for the library. */
|
||||
@@ -35,7 +41,7 @@ namespace program_options {
|
||||
are used only to validate input. Second affect interpretation of the
|
||||
option, for example default value for it or function that should be
|
||||
called when the value is finally known. Routines which perform parsing
|
||||
never use second kind of properties -- they are side effect free.
|
||||
never use second kind of properties \-- they are side effect free.
|
||||
@sa options_description
|
||||
*/
|
||||
class BOOST_PROGRAM_OPTIONS_DECL option_description {
|
||||
@@ -55,8 +61,8 @@ namespace program_options {
|
||||
|
||||
Alas, derived->base conversion for auto_ptr does not really work,
|
||||
see
|
||||
http://anubis.dkuug.dk/jtc1/sc22/wg21/docs/papers/2000/n1232.pdf
|
||||
http://std.dkuug.dk/jtc1/sc22/wg21/docs/cwg_defects.html#84
|
||||
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2000/n1232.pdf
|
||||
http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#84
|
||||
|
||||
So, we have to use plain old pointers. Besides, users are not
|
||||
expected to use the constructor directly.
|
||||
@@ -65,7 +71,7 @@ namespace program_options {
|
||||
The 'name' parameter is interpreted by the following rules:
|
||||
- if there's no "," character in 'name', it specifies long name
|
||||
- otherwise, the part before "," specifies long name and the part
|
||||
after -- long name.
|
||||
after \-- short name.
|
||||
*/
|
||||
option_description(const char* name,
|
||||
const value_semantic* s);
|
||||
@@ -81,12 +87,12 @@ namespace program_options {
|
||||
enum match_result { no_match, full_match, approximate_match };
|
||||
|
||||
/** Given 'option', specified in the input source,
|
||||
return 'true' is 'option' specifies *this.
|
||||
returns 'true' if 'option' specifies *this.
|
||||
*/
|
||||
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
|
||||
/** Returns the key that should identify the option, in
|
||||
particular in the variables_map class.
|
||||
The 'option' parameter is the option spelling from the
|
||||
input source.
|
||||
@@ -96,6 +102,16 @@ namespace program_options {
|
||||
*/
|
||||
const std::string& key(const std::string& option) const;
|
||||
|
||||
|
||||
/** Returns the canonical name for the option description to enable the user to
|
||||
recognised a matching option.
|
||||
1) For short options ('-', '/'), returns the short name prefixed.
|
||||
2) For long options ('--' / '-') returns the long name prefixed
|
||||
3) All other cases, returns the long name (if present) or the short name,
|
||||
unprefixed.
|
||||
*/
|
||||
std::string canonical_display_name(int canonical_option_style = 0) const;
|
||||
|
||||
const std::string& long_name() const;
|
||||
|
||||
/// Explanation of this option
|
||||
@@ -107,7 +123,7 @@ namespace program_options {
|
||||
/// Returns the option name, formatted suitably for usage message.
|
||||
std::string format_name() const;
|
||||
|
||||
/** Return the parameter name and properties, formatted suitably for
|
||||
/** Returns the parameter name and properties, formatted suitably for
|
||||
usage message. */
|
||||
std::string format_parameter() const;
|
||||
|
||||
@@ -183,6 +199,10 @@ namespace program_options {
|
||||
*/
|
||||
options_description& add(const options_description& desc);
|
||||
|
||||
/** Find the maximum width of the option column, including options
|
||||
in groups. */
|
||||
unsigned get_option_column_width() const;
|
||||
|
||||
public:
|
||||
/** Returns an object of implementation-defined type suitable for adding
|
||||
options to options_description. The returned object will
|
||||
@@ -211,11 +231,16 @@ namespace program_options {
|
||||
friend BOOST_PROGRAM_OPTIONS_DECL std::ostream& operator<<(std::ostream& os,
|
||||
const options_description& desc);
|
||||
|
||||
/** Output 'desc' to the specified stream, calling 'f' to output each
|
||||
/** Outputs 'desc' to the specified stream, calling 'f' to output each
|
||||
option_description element. */
|
||||
void print(std::ostream& os) const;
|
||||
void print(std::ostream& os, unsigned width = 0) const;
|
||||
|
||||
private:
|
||||
#if BOOST_WORKAROUND(BOOST_MSVC, BOOST_TESTED_AT(1800))
|
||||
// prevent warning C4512: assignment operator could not be generated
|
||||
options_description& operator=(const options_description&);
|
||||
#endif
|
||||
|
||||
typedef std::map<std::string, int>::const_iterator name2index_iterator;
|
||||
typedef std::pair<name2index_iterator, name2index_iterator>
|
||||
approximation_range;
|
||||
@@ -247,8 +272,12 @@ namespace program_options {
|
||||
/** Class thrown when duplicate option description is found. */
|
||||
class BOOST_PROGRAM_OPTIONS_DECL duplicate_option_error : public error {
|
||||
public:
|
||||
duplicate_option_error(const std::string& what) : error(what) {}
|
||||
duplicate_option_error(const std::string& xwhat) : error(xwhat) {}
|
||||
};
|
||||
}}
|
||||
|
||||
#if defined(BOOST_MSVC)
|
||||
# pragma warning (pop)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -17,30 +17,46 @@
|
||||
#include <vector>
|
||||
#include <utility>
|
||||
|
||||
#if defined(BOOST_MSVC)
|
||||
# pragma warning (push)
|
||||
# pragma warning (disable:4251) // class 'std::vector<_Ty>' needs to have dll-interface to be used by clients of class 'boost::program_options::basic_parsed_options<wchar_t>'
|
||||
#endif
|
||||
|
||||
namespace boost { namespace program_options {
|
||||
|
||||
class options_description;
|
||||
class positional_options_description;
|
||||
|
||||
|
||||
/** Results of parsing an input source.
|
||||
The primary use of this class is passing information from parsers
|
||||
/** Results of parsing an input source.
|
||||
The primary use of this class is passing information from parsers
|
||||
component to value storage component. This class does not makes
|
||||
much sense itself.
|
||||
much sense itself.
|
||||
*/
|
||||
template<class charT>
|
||||
class basic_parsed_options {
|
||||
public:
|
||||
explicit basic_parsed_options(const options_description* description)
|
||||
: description(description) {}
|
||||
explicit basic_parsed_options(const options_description* xdescription, int options_prefix = 0)
|
||||
: description(xdescription), m_options_prefix(options_prefix) {}
|
||||
/** Options found in the source. */
|
||||
std::vector< basic_option<charT> > options;
|
||||
/** Options description that was used for parsing.
|
||||
Parsers should return pointer to the instance of
|
||||
/** Options description that was used for parsing.
|
||||
Parsers should return pointer to the instance of
|
||||
option_description passed to them, and issues of lifetime are
|
||||
up to the caller. Can be NULL.
|
||||
*/
|
||||
const options_description* description;
|
||||
|
||||
/** Mainly used for the diagnostic messages in exceptions.
|
||||
* The canonical option prefix for the parser which generated these results,
|
||||
* depending on the settings for basic_command_line_parser::style() or
|
||||
* cmdline::style(). In order of precedence of command_line_style enums:
|
||||
* allow_long
|
||||
* allow_long_disguise
|
||||
* allow_dash_for_short
|
||||
* allow_slash_for_short
|
||||
*/
|
||||
int m_options_prefix;
|
||||
};
|
||||
|
||||
/** Specialization of basic_parsed_options which:
|
||||
@@ -58,7 +74,18 @@ namespace boost { namespace program_options {
|
||||
|
||||
/** Stores UTF8 encoded options that were passed to constructor,
|
||||
to avoid reverse conversion in some cases. */
|
||||
basic_parsed_options<char> utf8_encoded_options;
|
||||
basic_parsed_options<char> utf8_encoded_options;
|
||||
|
||||
/** Mainly used for the diagnostic messages in exceptions.
|
||||
* The canonical option prefix for the parser which generated these results,
|
||||
* depending on the settings for basic_command_line_parser::style() or
|
||||
* cmdline::style(). In order of precedence of command_line_style enums:
|
||||
* allow_long
|
||||
* allow_long_disguise
|
||||
* allow_dash_for_short
|
||||
* allow_slash_for_short
|
||||
*/
|
||||
int m_options_prefix;
|
||||
};
|
||||
|
||||
typedef basic_parsed_options<char> parsed_options;
|
||||
@@ -74,14 +101,14 @@ namespace boost { namespace program_options {
|
||||
|
||||
The class allows one to specify all the information needed for parsing
|
||||
and to parse the command line. It is primarily needed to
|
||||
emulate named function parameters -- a regular function with 5
|
||||
emulate named function parameters \-- a regular function with 5
|
||||
parameters will be hard to use and creating overloads with a smaller
|
||||
nuber of parameters will be confusing.
|
||||
number of parameters will be confusing.
|
||||
|
||||
For the most common case, the function parse_command_line is a better
|
||||
alternative.
|
||||
For the most common case, the function parse_command_line is a better
|
||||
alternative.
|
||||
|
||||
There are two typedefs -- command_line_parser and wcommand_line_parser,
|
||||
There are two typedefs \-- command_line_parser and wcommand_line_parser,
|
||||
for charT == char and charT == wchar_t cases.
|
||||
*/
|
||||
template<class charT>
|
||||
@@ -95,7 +122,7 @@ namespace boost { namespace program_options {
|
||||
/** Creates a command line parser for the specified arguments
|
||||
list. The parameters should be the same as passed to 'main'.
|
||||
*/
|
||||
basic_command_line_parser(int argc, charT* argv[]);
|
||||
basic_command_line_parser(int argc, const charT* const argv[]);
|
||||
|
||||
/** Sets options descriptions to use. */
|
||||
basic_command_line_parser& options(const options_description& desc);
|
||||
@@ -119,10 +146,10 @@ namespace boost { namespace program_options {
|
||||
instance of basic_option<charT> will be added to result,
|
||||
with 'unrecognized' field set to 'true'. It's possible to
|
||||
collect all unrecognized options with the 'collect_unrecognized'
|
||||
funciton.
|
||||
funciton.
|
||||
*/
|
||||
basic_command_line_parser& allow_unregistered();
|
||||
|
||||
|
||||
using detail::cmdline::style_parser;
|
||||
|
||||
basic_command_line_parser& extra_style_parser(style_parser s);
|
||||
@@ -135,19 +162,19 @@ namespace boost { namespace program_options {
|
||||
typedef basic_command_line_parser<wchar_t> wcommand_line_parser;
|
||||
|
||||
/** Creates instance of 'command_line_parser', passes parameters to it,
|
||||
and returns the result of calling the 'run' method.
|
||||
and returns the result of calling the 'run' method.
|
||||
*/
|
||||
template<class charT>
|
||||
basic_parsed_options<charT>
|
||||
parse_command_line(int argc, charT* argv[],
|
||||
parse_command_line(int argc, const charT* const argv[],
|
||||
const options_description&,
|
||||
int style = 0,
|
||||
function1<std::pair<std::string, std::string>,
|
||||
function1<std::pair<std::string, std::string>,
|
||||
const std::string&> ext
|
||||
= ext_parser());
|
||||
|
||||
/** Parse a config file.
|
||||
|
||||
/** Parse a config file.
|
||||
|
||||
Read from given stream.
|
||||
*/
|
||||
template<class charT>
|
||||
@@ -158,10 +185,10 @@ namespace boost { namespace program_options {
|
||||
parse_config_file(std::basic_istream<charT>&, const options_description&,
|
||||
bool allow_unregistered = false);
|
||||
|
||||
/** Parse a config file.
|
||||
|
||||
/** Parse a config file.
|
||||
|
||||
Read from file with the given name. The character type is
|
||||
passed to the file stream.
|
||||
passed to the file stream.
|
||||
*/
|
||||
template<class charT>
|
||||
#if ! BOOST_WORKAROUND(__ICL, BOOST_TESTED_AT(700))
|
||||
@@ -173,7 +200,7 @@ namespace boost { namespace program_options {
|
||||
|
||||
/** Controls if the 'collect_unregistered' function should
|
||||
include positional options, or not. */
|
||||
enum collect_unrecognized_mode
|
||||
enum collect_unrecognized_mode
|
||||
{ include_positional, exclude_positional };
|
||||
|
||||
/** Collects the original tokens for all named options with
|
||||
@@ -183,34 +210,34 @@ namespace boost { namespace program_options {
|
||||
options.
|
||||
*/
|
||||
template<class charT>
|
||||
std::vector< std::basic_string<charT> >
|
||||
std::vector< std::basic_string<charT> >
|
||||
collect_unrecognized(const std::vector< basic_option<charT> >& options,
|
||||
enum collect_unrecognized_mode mode);
|
||||
|
||||
/** Parse environment.
|
||||
/** Parse environment.
|
||||
|
||||
For each environment variable, the 'name_mapper' function is called to
|
||||
obtain the option name. If it returns empty string, the variable is
|
||||
ignored.
|
||||
obtain the option name. If it returns empty string, the variable is
|
||||
ignored.
|
||||
|
||||
This is done since naming of environment variables is typically
|
||||
different from the naming of command line options.
|
||||
This is done since naming of environment variables is typically
|
||||
different from the naming of command line options.
|
||||
*/
|
||||
BOOST_PROGRAM_OPTIONS_DECL parsed_options
|
||||
parse_environment(const options_description&,
|
||||
parse_environment(const options_description&,
|
||||
const function1<std::string, std::string>& name_mapper);
|
||||
|
||||
/** Parse environment.
|
||||
|
||||
Takes all environment variables which start with 'prefix'. The option
|
||||
name is obtained from variable name by removing the prefix and
|
||||
name is obtained from variable name by removing the prefix and
|
||||
converting the remaining string into lower case.
|
||||
*/
|
||||
BOOST_PROGRAM_OPTIONS_DECL parsed_options
|
||||
parse_environment(const options_description&, const std::string& prefix);
|
||||
|
||||
/** @overload
|
||||
This function exists to resolve ambiguity between the two above
|
||||
This function exists to resolve ambiguity between the two above
|
||||
functions when second argument is of 'char*' type. There's implicit
|
||||
conversion to both function1 and string.
|
||||
*/
|
||||
@@ -225,13 +252,13 @@ namespace boost { namespace program_options {
|
||||
and escape characters '\'
|
||||
*/
|
||||
BOOST_PROGRAM_OPTIONS_DECL std::vector<std::string>
|
||||
split_unix(const std::string& cmdline, const std::string& seperator = " \t",
|
||||
split_unix(const std::string& cmdline, const std::string& seperator = " \t",
|
||||
const std::string& quote = "'\"", const std::string& escape = "\\");
|
||||
|
||||
|
||||
#ifndef BOOST_NO_STD_WSTRING
|
||||
/** @overload */
|
||||
BOOST_PROGRAM_OPTIONS_DECL std::vector<std::wstring>
|
||||
split_unix(const std::wstring& cmdline, const std::wstring& seperator = L" \t",
|
||||
split_unix(const std::wstring& cmdline, const std::wstring& seperator = L" \t",
|
||||
const std::wstring& quote = L"'\"", const std::wstring& escape = L"\\");
|
||||
#endif
|
||||
|
||||
@@ -251,10 +278,14 @@ namespace boost { namespace program_options {
|
||||
split_winmain(const std::wstring& cmdline);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
}}
|
||||
|
||||
#if defined(BOOST_MSVC)
|
||||
# pragma warning (pop)
|
||||
#endif
|
||||
|
||||
#undef DECL
|
||||
|
||||
#include "boost/program_options/detail/parsers.hpp"
|
||||
|
||||
@@ -11,6 +11,11 @@
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#if defined(BOOST_MSVC)
|
||||
# pragma warning (push)
|
||||
# pragma warning (disable:4251) // class 'std::vector<_Ty>' needs to have dll-interface to be used by clients of class 'boost::program_options::positional_options_description'
|
||||
#endif
|
||||
|
||||
namespace boost { namespace program_options {
|
||||
|
||||
/** Describes positional options.
|
||||
@@ -61,5 +66,9 @@ namespace boost { namespace program_options {
|
||||
|
||||
}}
|
||||
|
||||
#if defined(BOOST_MSVC)
|
||||
# pragma warning (pop)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -13,10 +13,10 @@
|
||||
#include <boost/function/function1.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <typeinfo>
|
||||
#include <limits>
|
||||
|
||||
namespace boost { namespace program_options {
|
||||
|
||||
@@ -38,6 +38,11 @@ namespace boost { namespace program_options {
|
||||
should be present on the command line. */
|
||||
virtual unsigned max_tokens() const = 0;
|
||||
|
||||
/** Returns true if the option should only take adjacent token,
|
||||
not one from further command-line arguments.
|
||||
*/
|
||||
virtual bool adjacent_tokens_only() const = 0;
|
||||
|
||||
/** Returns true if values from different sources should be composed.
|
||||
Otherwise, value from the first source is used and values from
|
||||
other sources are discarded.
|
||||
@@ -48,7 +53,7 @@ namespace boost { namespace program_options {
|
||||
|
||||
*/
|
||||
virtual bool is_required() const = 0;
|
||||
|
||||
|
||||
/** Parses a group of tokens that specify a value of option.
|
||||
Stores the result in 'value_store', using whatever representation
|
||||
is desired. May be be called several times if value of the same
|
||||
@@ -134,6 +139,7 @@ namespace boost { namespace program_options {
|
||||
|
||||
unsigned min_tokens() const;
|
||||
unsigned max_tokens() const;
|
||||
bool adjacent_tokens_only() const { return false; }
|
||||
|
||||
bool is_composing() const { return false; }
|
||||
|
||||
@@ -156,6 +162,7 @@ namespace boost { namespace program_options {
|
||||
bool m_zero_tokens;
|
||||
};
|
||||
|
||||
#ifndef BOOST_NO_RTTI
|
||||
/** Base class for all option that have a fixed type, and are
|
||||
willing to announce this type to the outside world.
|
||||
Any 'value_semantics' for which you want to find out the
|
||||
@@ -172,20 +179,23 @@ namespace boost { namespace program_options {
|
||||
// class is silly, but just in case.
|
||||
virtual ~typed_value_base() {}
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
/** Class which handles value of a specific type. */
|
||||
template<class T, class charT = char>
|
||||
class typed_value : public value_semantic_codecvt_helper<charT>,
|
||||
public typed_value_base
|
||||
class typed_value : public value_semantic_codecvt_helper<charT>
|
||||
#ifndef BOOST_NO_RTTI
|
||||
, public typed_value_base
|
||||
#endif
|
||||
{
|
||||
public:
|
||||
/** Ctor. The 'store_to' parameter tells where to store
|
||||
the value when it's known. The parameter can be NULL. */
|
||||
typed_value(T* store_to)
|
||||
: m_store_to(store_to), m_composing(false),
|
||||
m_multitoken(false), m_zero_tokens(false),
|
||||
m_required(false)
|
||||
m_implicit(false), m_multitoken(false),
|
||||
m_zero_tokens(false), m_required(false)
|
||||
{}
|
||||
|
||||
/** Specifies default value, which will be used
|
||||
@@ -227,6 +237,13 @@ namespace boost { namespace program_options {
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Specifies the name used to to the value in help message. */
|
||||
typed_value* value_name(const std::string& name)
|
||||
{
|
||||
m_value_name = name;
|
||||
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
|
||||
@@ -261,13 +278,21 @@ namespace boost { namespace program_options {
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Specifies that the value can span multiple tokens. */
|
||||
/** Specifies that the value can span multiple tokens.
|
||||
*/
|
||||
typed_value* multitoken()
|
||||
{
|
||||
m_multitoken = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Specifies that no tokens may be provided as the value of
|
||||
this option, which means that only presense of the option
|
||||
is significant. For such option to be useful, either the
|
||||
'validate' function should be specialized, or the
|
||||
'implicit_value' method should be also used. In most
|
||||
cases, you can use the 'bool_switch' function instead of
|
||||
using this method. */
|
||||
typed_value* zero_tokens()
|
||||
{
|
||||
m_zero_tokens = true;
|
||||
@@ -298,7 +323,7 @@ namespace boost { namespace program_options {
|
||||
|
||||
unsigned max_tokens() const {
|
||||
if (m_multitoken) {
|
||||
return 32000;
|
||||
return std::numeric_limits<unsigned>::max BOOST_PREVENT_MACRO_SUBSTITUTION();
|
||||
} else if (m_zero_tokens) {
|
||||
return 0;
|
||||
} else {
|
||||
@@ -306,6 +331,8 @@ namespace boost { namespace program_options {
|
||||
}
|
||||
}
|
||||
|
||||
bool adjacent_tokens_only() const { return !m_implicit_value.empty(); }
|
||||
|
||||
bool is_required() const { return m_required; }
|
||||
|
||||
/** Creates an instance of the 'validator' class and calls
|
||||
@@ -335,10 +362,12 @@ namespace boost { namespace program_options {
|
||||
|
||||
public: // typed_value_base overrides
|
||||
|
||||
#ifndef BOOST_NO_RTTI
|
||||
const std::type_info& value_type() const
|
||||
{
|
||||
return typeid(T);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
private:
|
||||
@@ -346,6 +375,7 @@ namespace boost { namespace program_options {
|
||||
|
||||
// Default value is stored as boost::any and not
|
||||
// as boost::optional to avoid unnecessary instantiations.
|
||||
std::string m_value_name;
|
||||
boost::any m_default_value;
|
||||
std::string m_default_value_as_text;
|
||||
boost::any m_implicit_value;
|
||||
|
||||
@@ -16,6 +16,11 @@
|
||||
#include <map>
|
||||
#include <set>
|
||||
|
||||
#if defined(BOOST_MSVC)
|
||||
# pragma warning (push)
|
||||
# pragma warning (disable:4251) // 'boost::program_options::variable_value::v' : class 'boost::any' needs to have dll-interface to be used by clients of class 'boost::program_options::variable_value
|
||||
#endif
|
||||
|
||||
namespace boost { namespace program_options {
|
||||
|
||||
template<class charT>
|
||||
@@ -26,35 +31,35 @@ namespace boost { namespace program_options {
|
||||
|
||||
// forward declaration
|
||||
|
||||
/** Stores in 'm' all options that are defined in 'options'.
|
||||
/** Stores in 'm' all options that are defined in 'options'.
|
||||
If 'm' already has a non-defaulted value of an option, that value
|
||||
is not changed, even if 'options' specify some value.
|
||||
is not changed, even if 'options' specify some value.
|
||||
*/
|
||||
BOOST_PROGRAM_OPTIONS_DECL
|
||||
BOOST_PROGRAM_OPTIONS_DECL
|
||||
void store(const basic_parsed_options<char>& options, variables_map& m,
|
||||
bool utf8 = false);
|
||||
|
||||
/** Stores in 'm' all options that are defined in 'options'.
|
||||
/** Stores in 'm' all options that are defined in 'options'.
|
||||
If 'm' already has a non-defaulted value of an option, that value
|
||||
is not changed, even if 'options' specify some value.
|
||||
is not changed, even if 'options' specify some value.
|
||||
This is wide character variant.
|
||||
*/
|
||||
BOOST_PROGRAM_OPTIONS_DECL
|
||||
void store(const basic_parsed_options<wchar_t>& options,
|
||||
BOOST_PROGRAM_OPTIONS_DECL
|
||||
void store(const basic_parsed_options<wchar_t>& options,
|
||||
variables_map& m);
|
||||
|
||||
|
||||
/** Runs all 'notify' function for options in 'm'. */
|
||||
BOOST_PROGRAM_OPTIONS_DECL void notify(variables_map& m);
|
||||
|
||||
/** Class holding value of option. Contains details about how the
|
||||
/** Class holding value of option. Contains details about how the
|
||||
value is set and allows to conveniently obtain the value.
|
||||
*/
|
||||
class BOOST_PROGRAM_OPTIONS_DECL variable_value {
|
||||
public:
|
||||
variable_value() : m_defaulted(false) {}
|
||||
variable_value(const boost::any& v, bool defaulted)
|
||||
: v(v), m_defaulted(defaulted)
|
||||
variable_value(const boost::any& xv, bool xdefaulted)
|
||||
: v(xv), m_defaulted(xdefaulted)
|
||||
{}
|
||||
|
||||
/** If stored value if of type T, returns that value. Otherwise,
|
||||
@@ -90,10 +95,10 @@ namespace boost { namespace program_options {
|
||||
shared_ptr<const value_semantic> m_value_semantic;
|
||||
|
||||
friend BOOST_PROGRAM_OPTIONS_DECL
|
||||
void store(const basic_parsed_options<char>& options,
|
||||
void store(const basic_parsed_options<char>& options,
|
||||
variables_map& m, bool);
|
||||
|
||||
friend BOOST_PROGRAM_OPTIONS_DECL class variables_map;
|
||||
friend class BOOST_PROGRAM_OPTIONS_DECL variables_map;
|
||||
};
|
||||
|
||||
/** Implements string->string mapping with convenient value casting
|
||||
@@ -113,11 +118,11 @@ namespace boost { namespace program_options {
|
||||
- otherwise, returns empty value
|
||||
|
||||
- if there's defaulted value
|
||||
- if there's next varaible map, which has a non-defauled
|
||||
- if there's next variable map, which has a non-defaulted
|
||||
value, return that
|
||||
- otherwise, return value from *this
|
||||
|
||||
- if there's a non-defauled value, returns it.
|
||||
- if there's a non-defaulted value, returns it.
|
||||
*/
|
||||
const variable_value& operator[](const std::string& name) const;
|
||||
|
||||
@@ -133,8 +138,8 @@ namespace boost { namespace program_options {
|
||||
const abstract_variables_map* m_next;
|
||||
};
|
||||
|
||||
/** Concrete variables map which store variables in real map.
|
||||
|
||||
/** Concrete variables map which store variables in real map.
|
||||
|
||||
This class is derived from std::map<std::string, variable_value>,
|
||||
so you can use all map operators to examine its content.
|
||||
*/
|
||||
@@ -148,7 +153,10 @@ namespace boost { namespace program_options {
|
||||
// Resolve conflict between inherited operators.
|
||||
const variable_value& operator[](const std::string& name) const
|
||||
{ return abstract_variables_map::operator[](name); }
|
||||
|
||||
|
||||
// Override to clear some extra fields.
|
||||
void clear();
|
||||
|
||||
void notify();
|
||||
|
||||
private:
|
||||
@@ -156,18 +164,20 @@ namespace boost { namespace program_options {
|
||||
which does 'find' in *this. */
|
||||
const variable_value& get(const std::string& name) const;
|
||||
|
||||
/** Names of option with 'final' values -- which should not
|
||||
/** Names of option with 'final' values \-- which should not
|
||||
be changed by subsequence assignments. */
|
||||
std::set<std::string> m_final;
|
||||
|
||||
friend BOOST_PROGRAM_OPTIONS_DECL
|
||||
void store(const basic_parsed_options<char>& options,
|
||||
void store(const basic_parsed_options<char>& options,
|
||||
variables_map& xm,
|
||||
bool utf8);
|
||||
|
||||
|
||||
/** Names of required options, filled by parser which has
|
||||
access to options_description. */
|
||||
std::set<std::string> m_required;
|
||||
access to options_description.
|
||||
The map values are the "canonical" names for each corresponding option.
|
||||
This is useful in creating diagnostic messages when the option is absent. */
|
||||
std::map<std::string, std::string> m_required;
|
||||
};
|
||||
|
||||
|
||||
@@ -203,4 +213,8 @@ namespace boost { namespace program_options {
|
||||
|
||||
}}
|
||||
|
||||
#if defined(BOOST_MSVC)
|
||||
# pragma warning (pop)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
15
meta/libraries.json
Normal file
15
meta/libraries.json
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"key": "program_options",
|
||||
"name": "Program Options",
|
||||
"authors": [
|
||||
"Vladimir Prus"
|
||||
],
|
||||
"description": "The program_options library allows program developers to obtain program options, that is (name, value) pairs from the user, via conventional methods such as command line and config file.",
|
||||
"category": [
|
||||
"IO",
|
||||
"Miscellaneous"
|
||||
],
|
||||
"maintainers": [
|
||||
"Vladimir Prus <vladimir.prus -at- gmail.com>"
|
||||
]
|
||||
}
|
||||
333
src/cmdline.cpp
333
src/cmdline.cpp
@@ -34,64 +34,43 @@ namespace boost { namespace program_options {
|
||||
using namespace std;
|
||||
using namespace boost::program_options::command_line_style;
|
||||
|
||||
invalid_syntax::
|
||||
invalid_syntax(const string& tokens, kind_t kind)
|
||||
: error(error_message(kind).append(" in '").append(tokens).append("'"))
|
||||
, m_tokens(tokens)
|
||||
, m_kind(kind)
|
||||
{}
|
||||
|
||||
string
|
||||
invalid_syntax::error_message(kind_t kind)
|
||||
invalid_syntax::get_template(kind_t kind)
|
||||
{
|
||||
// Initially, store the message in 'const char*' variable,
|
||||
// to avoid conversion to string in all cases.
|
||||
const char* msg;
|
||||
switch(kind)
|
||||
{
|
||||
case long_not_allowed:
|
||||
msg = "long options are not allowed";
|
||||
break;
|
||||
case long_adjacent_not_allowed:
|
||||
msg = "parameters adjacent to long options not allowed";
|
||||
break;
|
||||
case short_adjacent_not_allowed:
|
||||
msg = "parameters adjust to short options are not allowed";
|
||||
break;
|
||||
case empty_adjacent_parameter:
|
||||
msg = "adjacent parameter is empty";
|
||||
msg = "the argument for option '%canonical_option%' should follow immediately after the equal sign";
|
||||
break;
|
||||
case missing_parameter:
|
||||
msg = "required parameter is missing";
|
||||
break;
|
||||
case extra_parameter:
|
||||
msg = "extra parameter";
|
||||
msg = "the required argument for option '%canonical_option%' is missing";
|
||||
break;
|
||||
case unrecognized_line:
|
||||
msg = "unrecognized line";
|
||||
msg = "the options configuration file contains an invalid line '%invalid_line%'";
|
||||
break;
|
||||
// none of the following are currently used:
|
||||
case long_not_allowed:
|
||||
msg = "the unabbreviated option '%canonical_option%' is not valid";
|
||||
break;
|
||||
case long_adjacent_not_allowed:
|
||||
msg = "the unabbreviated option '%canonical_option%' does not take any arguments";
|
||||
break;
|
||||
case short_adjacent_not_allowed:
|
||||
msg = "the abbreviated option '%canonical_option%' does not take any arguments";
|
||||
break;
|
||||
case extra_parameter:
|
||||
msg = "option '%canonical_option%' does not take any arguments";
|
||||
break;
|
||||
default:
|
||||
msg = "unknown error";
|
||||
msg = "unknown command line syntax error for '%s'";
|
||||
}
|
||||
return msg;
|
||||
}
|
||||
|
||||
invalid_syntax::kind_t
|
||||
invalid_syntax::kind() const
|
||||
{
|
||||
return m_kind;
|
||||
}
|
||||
|
||||
const string&
|
||||
invalid_syntax::tokens() const
|
||||
{
|
||||
return m_tokens;
|
||||
}
|
||||
|
||||
invalid_command_line_syntax::
|
||||
invalid_command_line_syntax(const string& tokens, kind_t kind)
|
||||
: invalid_syntax(tokens, kind)
|
||||
{}
|
||||
|
||||
}}
|
||||
|
||||
@@ -156,15 +135,26 @@ namespace boost { namespace program_options { namespace detail {
|
||||
const char* error = 0;
|
||||
if (allow_some_long &&
|
||||
!(style & long_allow_adjacent) && !(style & long_allow_next))
|
||||
error = "style disallows parameters for long options";
|
||||
error = "boost::program_options misconfiguration: "
|
||||
"choose one or other of 'command_line_style::long_allow_next' "
|
||||
"(whitespace separated arguments) or "
|
||||
"'command_line_style::long_allow_adjacent' ('=' separated arguments) for "
|
||||
"long options.";
|
||||
|
||||
if (!error && (style & allow_short) &&
|
||||
!(style & short_allow_adjacent) && !(style & short_allow_next))
|
||||
error = "style disallows parameters for short options";
|
||||
error = "boost::program_options misconfiguration: "
|
||||
"choose one or other of 'command_line_style::short_allow_next' "
|
||||
"(whitespace separated arguments) or "
|
||||
"'command_line_style::short_allow_adjacent' ('=' separated arguments) for "
|
||||
"short options.";
|
||||
|
||||
if (!error && (style & allow_short) &&
|
||||
!(style & allow_dash_for_short) && !(style & allow_slash_for_short))
|
||||
error = "style disallows all characters for short options";
|
||||
error = "boost::program_options misconfiguration: "
|
||||
"choose one or other of 'command_line_style::allow_slash_for_short' "
|
||||
"(slashes) or 'command_line_style::allow_dash_for_short' (dashes) for "
|
||||
"short options.";
|
||||
|
||||
if (error)
|
||||
boost::throw_exception(invalid_command_line_style(error));
|
||||
@@ -192,6 +182,23 @@ namespace boost { namespace program_options { namespace detail {
|
||||
m_positional = &positional;
|
||||
}
|
||||
|
||||
int
|
||||
cmdline::get_canonical_option_prefix()
|
||||
{
|
||||
if (m_style & allow_long)
|
||||
return allow_long;
|
||||
|
||||
if (m_style & allow_long_disguise)
|
||||
return allow_long_disguise;
|
||||
|
||||
if ((m_style & allow_short) && (m_style & allow_dash_for_short))
|
||||
return allow_dash_for_short;
|
||||
|
||||
if ((m_style & allow_short) && (m_style & allow_slash_for_short))
|
||||
return allow_slash_for_short;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
vector<option>
|
||||
cmdline::run()
|
||||
@@ -242,7 +249,7 @@ namespace boost { namespace program_options { namespace detail {
|
||||
bool ok = false;
|
||||
for(unsigned i = 0; i < style_parsers.size(); ++i)
|
||||
{
|
||||
unsigned current_size = args.size();
|
||||
unsigned current_size = static_cast<unsigned>(args.size());
|
||||
vector<option> next = style_parsers[i](args);
|
||||
|
||||
// Check that option names
|
||||
@@ -277,7 +284,7 @@ namespace boost { namespace program_options { namespace detail {
|
||||
}
|
||||
|
||||
/* If an key option is followed by a positional option,
|
||||
can can consume more tokens (e.g. it's multitoke option),
|
||||
can can consume more tokens (e.g. it's multitoken option),
|
||||
give those tokens to it. */
|
||||
vector<option> result2;
|
||||
for (unsigned i = 0; i < result.size(); ++i)
|
||||
@@ -288,14 +295,27 @@ namespace boost { namespace program_options { namespace detail {
|
||||
if (opt.string_key.empty())
|
||||
continue;
|
||||
|
||||
const option_description* xd =
|
||||
m_desc->find_nothrow(opt.string_key,
|
||||
is_style_active(allow_guessing),
|
||||
is_style_active(long_case_insensitive),
|
||||
is_style_active(short_case_insensitive));
|
||||
const option_description* xd;
|
||||
try
|
||||
{
|
||||
xd = m_desc->find_nothrow(opt.string_key,
|
||||
is_style_active(allow_guessing),
|
||||
is_style_active(long_case_insensitive),
|
||||
is_style_active(short_case_insensitive));
|
||||
}
|
||||
catch(error_with_option_name& e)
|
||||
{
|
||||
// add context and rethrow
|
||||
e.add_context(opt.string_key, opt.original_tokens[0], get_canonical_option_prefix());
|
||||
throw;
|
||||
}
|
||||
|
||||
if (!xd)
|
||||
continue;
|
||||
|
||||
if (xd->semantic()->adjacent_tokens_only())
|
||||
continue;
|
||||
|
||||
unsigned min_tokens = xd->semantic()->min_tokens();
|
||||
unsigned max_tokens = xd->semantic()->max_tokens();
|
||||
if (min_tokens < max_tokens && opt.value.size() < max_tokens)
|
||||
@@ -304,7 +324,7 @@ namespace boost { namespace program_options { namespace detail {
|
||||
// We only allow to grab tokens that are not already
|
||||
// recognized as key options.
|
||||
|
||||
int can_take_more = max_tokens - opt.value.size();
|
||||
int can_take_more = max_tokens - static_cast<int>(opt.value.size());
|
||||
unsigned j = i+1;
|
||||
for (; can_take_more && j < result.size(); --can_take_more, ++j)
|
||||
{
|
||||
@@ -383,92 +403,112 @@ namespace boost { namespace program_options { namespace detail {
|
||||
if (opt.string_key.empty())
|
||||
return;
|
||||
|
||||
// First check that the option is valid, and get its description.
|
||||
const option_description* xd = m_desc->find_nothrow(opt.string_key,
|
||||
is_style_active(allow_guessing),
|
||||
is_style_active(long_case_insensitive),
|
||||
is_style_active(short_case_insensitive));
|
||||
//
|
||||
// Be defensive:
|
||||
// will have no original token if option created by handle_additional_parser()
|
||||
std::string original_token_for_exceptions = opt.string_key;
|
||||
if (opt.original_tokens.size())
|
||||
original_token_for_exceptions = opt.original_tokens[0];
|
||||
|
||||
if (!xd)
|
||||
try
|
||||
{
|
||||
if (m_allow_unregistered) {
|
||||
opt.unregistered = true;
|
||||
return;
|
||||
} else {
|
||||
boost::throw_exception(unknown_option(opt.string_key));
|
||||
}
|
||||
}
|
||||
const option_description& d = *xd;
|
||||
// First check that the option is valid, and get its description.
|
||||
const option_description* xd = m_desc->find_nothrow(opt.string_key,
|
||||
is_style_active(allow_guessing),
|
||||
is_style_active(long_case_insensitive),
|
||||
is_style_active(short_case_insensitive));
|
||||
|
||||
// Canonize the name
|
||||
opt.string_key = d.key(opt.string_key);
|
||||
|
||||
// We check that the min/max number of tokens for the option
|
||||
// agrees with the number of tokens we have. The 'adjacent_value'
|
||||
// (the value in --foo=1) counts as a separate token, and if present
|
||||
// must be consumed. The following tokens on the command line may be
|
||||
// left unconsumed.
|
||||
|
||||
// We don't check if those tokens look like option, or not!
|
||||
|
||||
unsigned min_tokens = d.semantic()->min_tokens();
|
||||
unsigned max_tokens = d.semantic()->max_tokens();
|
||||
|
||||
unsigned present_tokens = opt.value.size() + other_tokens.size();
|
||||
|
||||
if (present_tokens >= min_tokens)
|
||||
{
|
||||
if (!opt.value.empty() && max_tokens == 0)
|
||||
if (!xd)
|
||||
{
|
||||
boost::throw_exception(invalid_command_line_syntax(opt.string_key,
|
||||
invalid_command_line_syntax::extra_parameter));
|
||||
if (m_allow_unregistered) {
|
||||
opt.unregistered = true;
|
||||
return;
|
||||
} else {
|
||||
boost::throw_exception(unknown_option());
|
||||
}
|
||||
}
|
||||
const option_description& d = *xd;
|
||||
|
||||
// Canonize the name
|
||||
opt.string_key = d.key(opt.string_key);
|
||||
|
||||
// We check that the min/max number of tokens for the option
|
||||
// agrees with the number of tokens we have. The 'adjacent_value'
|
||||
// (the value in --foo=1) counts as a separate token, and if present
|
||||
// must be consumed. The following tokens on the command line may be
|
||||
// left unconsumed.
|
||||
|
||||
// We don't check if those tokens look like option, or not!
|
||||
|
||||
unsigned min_tokens = d.semantic()->min_tokens();
|
||||
unsigned max_tokens = d.semantic()->max_tokens();
|
||||
|
||||
// If an option wants, at minimum, N tokens, we grab them there,
|
||||
// when adding these tokens as values to current option we check
|
||||
// if they look like options
|
||||
if (opt.value.size() <= min_tokens)
|
||||
unsigned present_tokens = static_cast<unsigned>(opt.value.size() + other_tokens.size());
|
||||
|
||||
if (present_tokens >= min_tokens)
|
||||
{
|
||||
min_tokens -= opt.value.size();
|
||||
if (!opt.value.empty() && max_tokens == 0)
|
||||
{
|
||||
boost::throw_exception(
|
||||
invalid_command_line_syntax(invalid_command_line_syntax::extra_parameter));
|
||||
}
|
||||
|
||||
// If an option wants, at minimum, N tokens, we grab them there,
|
||||
// when adding these tokens as values to current option we check
|
||||
// if they look like options
|
||||
if (opt.value.size() <= min_tokens)
|
||||
{
|
||||
min_tokens -= static_cast<unsigned>(opt.value.size());
|
||||
}
|
||||
else
|
||||
{
|
||||
min_tokens = 0;
|
||||
}
|
||||
|
||||
// Everything's OK, move the values to the result.
|
||||
for(;!other_tokens.empty() && min_tokens--; )
|
||||
{
|
||||
// check if extra parameter looks like a known option
|
||||
// we use style parsers to check if it is syntactically an option,
|
||||
// additionally we check if an option_description exists
|
||||
vector<option> followed_option;
|
||||
vector<string> next_token(1, other_tokens[0]);
|
||||
for (unsigned i = 0; followed_option.empty() && i < style_parsers.size(); ++i)
|
||||
{
|
||||
followed_option = style_parsers[i](next_token);
|
||||
}
|
||||
if (!followed_option.empty())
|
||||
{
|
||||
original_token_for_exceptions = other_tokens[0];
|
||||
const option_description* od = m_desc->find_nothrow(other_tokens[0],
|
||||
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(invalid_command_line_syntax::missing_parameter));
|
||||
}
|
||||
opt.value.push_back(other_tokens[0]);
|
||||
opt.original_tokens.push_back(other_tokens[0]);
|
||||
other_tokens.erase(other_tokens.begin());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
min_tokens = 0;
|
||||
}
|
||||
boost::throw_exception(
|
||||
invalid_command_line_syntax(invalid_command_line_syntax::missing_parameter));
|
||||
|
||||
// Everything's OK, move the values to the result.
|
||||
for(;!other_tokens.empty() && min_tokens--; )
|
||||
{
|
||||
// check if extra parameter looks like a known option
|
||||
// we use style parsers to check if it is syntactically an option,
|
||||
// additionally we check if an option_description exists
|
||||
vector<option> followed_option;
|
||||
vector<string> next_token(1, other_tokens[0]);
|
||||
for (unsigned i = 0; followed_option.empty() && i < style_parsers.size(); ++i)
|
||||
{
|
||||
followed_option = style_parsers[i](next_token);
|
||||
}
|
||||
if (!followed_option.empty())
|
||||
{
|
||||
const option_description* od = m_desc->find_nothrow(other_tokens[0],
|
||||
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));
|
||||
}
|
||||
opt.value.push_back(other_tokens[0]);
|
||||
opt.original_tokens.push_back(other_tokens[0]);
|
||||
other_tokens.erase(other_tokens.begin());
|
||||
}
|
||||
}
|
||||
else
|
||||
}
|
||||
// use only original token for unknown_option / ambiguous_option since by definition
|
||||
// they are unrecognised / unparsable
|
||||
catch(error_with_option_name& e)
|
||||
{
|
||||
boost::throw_exception(invalid_command_line_syntax(opt.string_key,
|
||||
invalid_command_line_syntax::missing_parameter));
|
||||
|
||||
// add context and rethrow
|
||||
e.add_context(opt.string_key, original_token_for_exceptions, get_canonical_option_prefix());
|
||||
throw;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
vector<option>
|
||||
@@ -486,8 +526,11 @@ namespace boost { namespace program_options { namespace detail {
|
||||
name = tok.substr(2, p-2);
|
||||
adjacent = tok.substr(p+1);
|
||||
if (adjacent.empty())
|
||||
boost::throw_exception( invalid_command_line_syntax(name,
|
||||
invalid_command_line_syntax::empty_adjacent_parameter) );
|
||||
boost::throw_exception( invalid_command_line_syntax(
|
||||
invalid_command_line_syntax::empty_adjacent_parameter,
|
||||
name,
|
||||
name,
|
||||
get_canonical_option_prefix()) );
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -523,9 +566,20 @@ namespace boost { namespace program_options { namespace detail {
|
||||
// of token is considered to be value, not further grouped
|
||||
// option.
|
||||
for(;;) {
|
||||
const option_description* d
|
||||
= m_desc->find_nothrow(name, false, false,
|
||||
is_style_active(short_case_insensitive));
|
||||
const option_description* d;
|
||||
try
|
||||
{
|
||||
|
||||
d = m_desc->find_nothrow(name, false, false,
|
||||
is_style_active(short_case_insensitive));
|
||||
}
|
||||
catch(error_with_option_name& e)
|
||||
{
|
||||
// add context and rethrow
|
||||
e.add_context(name, name, get_canonical_option_prefix());
|
||||
throw;
|
||||
}
|
||||
|
||||
|
||||
// FIXME: check for 'allow_sticky'.
|
||||
if (d && (m_style & allow_sticky) &&
|
||||
@@ -589,15 +643,24 @@ namespace boost { namespace program_options { namespace detail {
|
||||
((tok[0] == '-' && tok[1] != '-') ||
|
||||
((m_style & allow_slash_for_short) && tok[0] == '/')))
|
||||
{
|
||||
if (m_desc->find_nothrow(tok.substr(1, tok.find('=')-1),
|
||||
is_style_active(allow_guessing),
|
||||
is_style_active(long_case_insensitive),
|
||||
is_style_active(short_case_insensitive)))
|
||||
try
|
||||
{
|
||||
args[0].insert(0, "-");
|
||||
if (args[0][1] == '/')
|
||||
args[0][1] = '-';
|
||||
return parse_long_option(args);
|
||||
if (m_desc->find_nothrow(tok.substr(1, tok.find('=')-1),
|
||||
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] == '/')
|
||||
args[0][1] = '-';
|
||||
return parse_long_option(args);
|
||||
}
|
||||
}
|
||||
catch(error_with_option_name& e)
|
||||
{
|
||||
// add context and rethrow
|
||||
e.add_context(tok, tok, get_canonical_option_prefix());
|
||||
throw;
|
||||
}
|
||||
}
|
||||
return vector<option>();
|
||||
|
||||
@@ -57,7 +57,9 @@ namespace boost { namespace program_options { namespace detail {
|
||||
bad_prefixes = true;
|
||||
}
|
||||
if (bad_prefixes)
|
||||
boost::throw_exception(error("bad prefixes"));
|
||||
boost::throw_exception(error("options '" + string(name) + "' and '" +
|
||||
*i + "*' will both match the same "
|
||||
"arguments from the configuration file"));
|
||||
allowed_prefixes.insert(s);
|
||||
}
|
||||
}
|
||||
@@ -117,7 +119,7 @@ namespace boost { namespace program_options { namespace detail {
|
||||
break;
|
||||
|
||||
} else {
|
||||
boost::throw_exception(invalid_syntax(s, invalid_syntax::unrecognized_line));
|
||||
boost::throw_exception(invalid_config_file_syntax(s, invalid_syntax::unrecognized_line));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
#define BOOST_PROGRAM_OPTIONS_SOURCE
|
||||
#include <boost/program_options/config.hpp>
|
||||
#include <boost/program_options/options_description.hpp>
|
||||
// FIXME: this is only to get multiple_occurences class
|
||||
// FIXME: this is only to get multiple_occurrences class
|
||||
// should move that to a separate headers.
|
||||
#include <boost/program_options/parsers.hpp>
|
||||
|
||||
@@ -137,6 +137,31 @@ namespace boost { namespace program_options {
|
||||
return m_short_name;
|
||||
}
|
||||
|
||||
std::string
|
||||
option_description::canonical_display_name(int prefix_style) const
|
||||
{
|
||||
if (!m_long_name.empty())
|
||||
{
|
||||
if (prefix_style == command_line_style::allow_long)
|
||||
return "--" + m_long_name;
|
||||
if (prefix_style == command_line_style::allow_long_disguise)
|
||||
return "-" + m_long_name;
|
||||
}
|
||||
// sanity check: m_short_name[0] should be '-' or '/'
|
||||
if (m_short_name.length() == 2)
|
||||
{
|
||||
if (prefix_style == command_line_style::allow_slash_for_short)
|
||||
return string("/") + m_short_name[1];
|
||||
if (prefix_style == command_line_style::allow_dash_for_short)
|
||||
return string("-") + m_short_name[1];
|
||||
}
|
||||
if (!m_long_name.empty())
|
||||
return m_long_name;
|
||||
else
|
||||
return m_short_name;
|
||||
}
|
||||
|
||||
|
||||
const std::string&
|
||||
option_description::long_name() const
|
||||
{
|
||||
@@ -174,10 +199,13 @@ namespace boost { namespace program_options {
|
||||
option_description::format_name() const
|
||||
{
|
||||
if (!m_short_name.empty())
|
||||
return string(m_short_name).append(" [ --").
|
||||
append(m_long_name).append(" ]");
|
||||
else
|
||||
return string("--").append(m_long_name);
|
||||
{
|
||||
return m_long_name.empty()
|
||||
? m_short_name
|
||||
: string(m_short_name).append(" [ --").
|
||||
append(m_long_name).append(" ]");
|
||||
}
|
||||
return string("--").append(m_long_name);
|
||||
}
|
||||
|
||||
std::string
|
||||
@@ -289,7 +317,7 @@ namespace boost { namespace program_options {
|
||||
const option_description* d = find_nothrow(name, approx,
|
||||
long_ignore_case, short_ignore_case);
|
||||
if (!d)
|
||||
boost::throw_exception(unknown_option(name));
|
||||
boost::throw_exception(unknown_option());
|
||||
return *d;
|
||||
}
|
||||
|
||||
@@ -306,6 +334,7 @@ namespace boost { namespace program_options {
|
||||
bool short_ignore_case) const
|
||||
{
|
||||
shared_ptr<option_description> found;
|
||||
bool had_full_match = false;
|
||||
vector<string> approximate_matches;
|
||||
vector<string> full_matches;
|
||||
|
||||
@@ -323,19 +352,20 @@ namespace boost { namespace program_options {
|
||||
if (r == option_description::full_match)
|
||||
{
|
||||
full_matches.push_back(m_options[i]->key(name));
|
||||
found = m_options[i];
|
||||
had_full_match = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// FIXME: the use of 'key' here might not
|
||||
// be the best approach.
|
||||
approximate_matches.push_back(m_options[i]->key(name));
|
||||
if (!had_full_match)
|
||||
found = m_options[i];
|
||||
}
|
||||
|
||||
found = m_options[i];
|
||||
}
|
||||
if (full_matches.size() > 1)
|
||||
boost::throw_exception(
|
||||
ambiguous_option(name, full_matches));
|
||||
boost::throw_exception(ambiguous_option(full_matches));
|
||||
|
||||
// If we have a full match, and an approximate match,
|
||||
// ignore approximate match instead of reporting error.
|
||||
@@ -343,8 +373,7 @@ namespace boost { namespace program_options {
|
||||
// "--all" on the command line should select the first one,
|
||||
// without ambiguity.
|
||||
if (full_matches.empty() && approximate_matches.size() > 1)
|
||||
boost::throw_exception(
|
||||
ambiguous_option(name, approximate_matches));
|
||||
boost::throw_exception(ambiguous_option(approximate_matches));
|
||||
|
||||
return found.get();
|
||||
}
|
||||
@@ -393,7 +422,7 @@ namespace boost { namespace program_options {
|
||||
if (count(par.begin(), par.end(), '\t') > 1)
|
||||
{
|
||||
boost::throw_exception(program_options::error(
|
||||
"Only one tab per paragraph is allowed"));
|
||||
"Only one tab per paragraph is allowed in the options description"));
|
||||
}
|
||||
|
||||
// erase tab from string
|
||||
@@ -440,7 +469,7 @@ namespace boost { namespace program_options {
|
||||
// Take care to never increment the iterator past
|
||||
// the end, since MSVC 8.0 (brokenly), assumes that
|
||||
// doing that, even if no access happens, is a bug.
|
||||
unsigned remaining = distance(line_begin, par_end);
|
||||
unsigned remaining = static_cast<unsigned>(std::distance(line_begin, par_end));
|
||||
string::const_iterator line_end = line_begin +
|
||||
((remaining < line_length) ? remaining : line_length);
|
||||
|
||||
@@ -460,7 +489,7 @@ namespace boost { namespace program_options {
|
||||
{
|
||||
// is last_space within the second half ot the
|
||||
// current line
|
||||
if (static_cast<unsigned>(distance(last_space, line_end)) <
|
||||
if (static_cast<unsigned>(std::distance(last_space, line_end)) <
|
||||
(line_length / 2))
|
||||
{
|
||||
line_end = last_space;
|
||||
@@ -473,8 +502,8 @@ namespace boost { namespace program_options {
|
||||
|
||||
if (first_line)
|
||||
{
|
||||
indent += par_indent;
|
||||
line_length -= par_indent; // there's less to work with now
|
||||
indent += static_cast<unsigned>(par_indent);
|
||||
line_length -= static_cast<unsigned>(par_indent); // there's less to work with now
|
||||
first_line = false;
|
||||
}
|
||||
|
||||
@@ -563,7 +592,7 @@ namespace boost { namespace program_options {
|
||||
os.put(' ');
|
||||
}
|
||||
} else {
|
||||
for(unsigned pad = first_column_width - ss.str().size(); pad > 0; --pad)
|
||||
for(unsigned pad = first_column_width - static_cast<unsigned>(ss.str().size()); pad > 0; --pad)
|
||||
{
|
||||
os.put(' ');
|
||||
}
|
||||
@@ -575,12 +604,9 @@ namespace boost { namespace program_options {
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
options_description::print(std::ostream& os) const
|
||||
unsigned
|
||||
options_description::get_option_column_width() const
|
||||
{
|
||||
if (!m_caption.empty())
|
||||
os << m_caption << ":\n";
|
||||
|
||||
/* Find the maximum width of the option column */
|
||||
unsigned width(23);
|
||||
unsigned i; // vc6 has broken for loop scoping
|
||||
@@ -591,6 +617,11 @@ namespace boost { namespace program_options {
|
||||
ss << " " << opt.format_name() << ' ' << opt.format_parameter();
|
||||
width = (max)(width, static_cast<unsigned>(ss.str().size()));
|
||||
}
|
||||
|
||||
/* Get width of groups as well*/
|
||||
for (unsigned j = 0; j < groups.size(); ++j)
|
||||
width = max(width, groups[j]->get_option_column_width());
|
||||
|
||||
/* this is the column were description should start, if first
|
||||
column is longer, we go to a new line */
|
||||
const unsigned start_of_description_column = m_line_length - m_min_description_length;
|
||||
@@ -599,9 +630,20 @@ namespace boost { namespace program_options {
|
||||
|
||||
/* add an additional space to improve readability */
|
||||
++width;
|
||||
|
||||
return width;
|
||||
}
|
||||
|
||||
void
|
||||
options_description::print(std::ostream& os, unsigned width) const
|
||||
{
|
||||
if (!m_caption.empty())
|
||||
os << m_caption << ":\n";
|
||||
|
||||
if (!width)
|
||||
width = get_option_column_width();
|
||||
|
||||
/* The options formatting style is stolen from Subversion. */
|
||||
for (i = 0; i < m_options.size(); ++i)
|
||||
for (unsigned i = 0; i < m_options.size(); ++i)
|
||||
{
|
||||
if (belong_to_group[i])
|
||||
continue;
|
||||
@@ -614,7 +656,8 @@ namespace boost { namespace program_options {
|
||||
}
|
||||
|
||||
for (unsigned j = 0; j < groups.size(); ++j) {
|
||||
os << "\n" << *groups[j];
|
||||
os << "\n";
|
||||
groups[j]->print(os, width);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -45,7 +45,10 @@
|
||||
// See: http://article.gmane.org/gmane.comp.lib.boost.devel/103843
|
||||
// See: http://lists.gnu.org/archive/html/bug-guile/2004-01/msg00013.html
|
||||
#if defined(__APPLE__) && defined(__DYNAMIC__)
|
||||
#include <crt_externs.h>
|
||||
// The proper include for this is crt_externs.h, however it's not
|
||||
// available on iOS. The right replacement is not known. See
|
||||
// https://svn.boost.org/trac/boost/ticket/5053
|
||||
extern "C" { extern char ***_NSGetEnviron(void); }
|
||||
#define environ (*_NSGetEnviron())
|
||||
#else
|
||||
#if defined(__MWERKS__)
|
||||
@@ -85,7 +88,8 @@ namespace boost { namespace program_options {
|
||||
basic_parsed_options<wchar_t>
|
||||
::basic_parsed_options(const parsed_options& po)
|
||||
: description(po.description),
|
||||
utf8_encoded_options(po)
|
||||
utf8_encoded_options(po),
|
||||
m_options_prefix(po.m_options_prefix)
|
||||
{
|
||||
for (unsigned i = 0; i < po.options.size(); ++i)
|
||||
options.push_back(woption_from_option(po.options[i]));
|
||||
@@ -107,7 +111,7 @@ namespace boost { namespace program_options {
|
||||
|
||||
if (d.long_name().empty())
|
||||
boost::throw_exception(
|
||||
error("long name required for config file"));
|
||||
error("abbreviated option names are not permitted in options configuration files"));
|
||||
|
||||
allowed_options.insert(d.long_name());
|
||||
}
|
||||
@@ -216,7 +220,7 @@ namespace boost { namespace program_options {
|
||||
{
|
||||
// Intel-Win-7.1 does not understand
|
||||
// push_back on string.
|
||||
result += tolower(s[n]);
|
||||
result += static_cast<char>(tolower(s[n]));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
|
||||
@@ -34,7 +34,7 @@ namespace boost { namespace program_options {
|
||||
positional_options_description::max_total_count() const
|
||||
{
|
||||
return m_trailing.empty() ?
|
||||
m_names.size() : (std::numeric_limits<unsigned>::max)();
|
||||
static_cast<unsigned>(m_names.size()) : (std::numeric_limits<unsigned>::max)();
|
||||
}
|
||||
|
||||
const std::string&
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
#define BOOST_UTF8_END_NAMESPACE }}}
|
||||
#define BOOST_UTF8_DECL BOOST_PROGRAM_OPTIONS_DECL
|
||||
|
||||
#include "../../detail/utf8_codecvt_facet.cpp"
|
||||
#include <boost/detail/utf8_codecvt_facet.ipp>
|
||||
|
||||
|
||||
#undef BOOST_UTF8_BEGIN_NAMESPACE
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
#include <boost/program_options/config.hpp>
|
||||
#include <boost/program_options/value_semantic.hpp>
|
||||
#include <boost/program_options/detail/convert.hpp>
|
||||
#include <boost/program_options/detail/cmdline.hpp>
|
||||
#include <set>
|
||||
|
||||
#include <cctype>
|
||||
|
||||
@@ -14,6 +16,22 @@ namespace boost { namespace program_options {
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
||||
#ifndef BOOST_NO_STD_WSTRING
|
||||
namespace
|
||||
{
|
||||
std::string convert_value(const std::wstring& s)
|
||||
{
|
||||
try {
|
||||
return to_local_8_bit(s);
|
||||
}
|
||||
catch(const std::exception&) {
|
||||
return "<unrepresentable unicode string>";
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
value_semantic_codecvt_helper<char>::
|
||||
parse(boost::any& value_store,
|
||||
@@ -139,7 +157,7 @@ namespace boost { namespace program_options {
|
||||
else if (s == "off" || s == "no" || s == "0" || s == "false")
|
||||
v = any(false);
|
||||
else
|
||||
boost::throw_exception(validation_error(validation_error::invalid_bool_value, s));
|
||||
boost::throw_exception(invalid_bool_value(s));
|
||||
}
|
||||
|
||||
// This is blatant copy-paste. However, templating this will cause a problem,
|
||||
@@ -161,7 +179,7 @@ namespace boost { namespace program_options {
|
||||
else if (s == L"off" || s == L"no" || s == L"0" || s == L"false")
|
||||
v = any(false);
|
||||
else
|
||||
boost::throw_exception(validation_error(validation_error::invalid_bool_value));
|
||||
boost::throw_exception(invalid_bool_value(convert_value(s)));
|
||||
}
|
||||
#endif
|
||||
BOOST_PROGRAM_OPTIONS_DECL
|
||||
@@ -194,120 +212,212 @@ namespace boost { namespace program_options {
|
||||
|
||||
invalid_option_value::
|
||||
invalid_option_value(const std::string& bad_value)
|
||||
: validation_error(validation_error::invalid_option_value, bad_value)
|
||||
{}
|
||||
: validation_error(validation_error::invalid_option_value)
|
||||
{
|
||||
set_substitute("value", bad_value);
|
||||
}
|
||||
|
||||
#ifndef BOOST_NO_STD_WSTRING
|
||||
namespace
|
||||
invalid_option_value::
|
||||
invalid_option_value(const std::wstring& bad_value)
|
||||
: validation_error(validation_error::invalid_option_value)
|
||||
{
|
||||
std::string convert_value(const std::wstring& s)
|
||||
set_substitute("value", convert_value(bad_value));
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
invalid_bool_value::
|
||||
invalid_bool_value(const std::string& bad_value)
|
||||
: validation_error(validation_error::invalid_bool_value)
|
||||
{
|
||||
set_substitute("value", bad_value);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
error_with_option_name::error_with_option_name( const std::string& template_,
|
||||
const std::string& option_name,
|
||||
const std::string& original_token,
|
||||
int option_style) :
|
||||
error(template_),
|
||||
m_option_style(option_style),
|
||||
m_error_template(template_)
|
||||
{
|
||||
// parameter | placeholder | value
|
||||
// --------- | ----------- | -----
|
||||
set_substitute_default("canonical_option", "option '%canonical_option%'", "option");
|
||||
set_substitute_default("value", "argument ('%value%')", "argument");
|
||||
set_substitute_default("prefix", "%prefix%", "");
|
||||
m_substitutions["option"] = option_name;
|
||||
m_substitutions["original_token"] = original_token;
|
||||
}
|
||||
|
||||
|
||||
const char* error_with_option_name::what() const throw()
|
||||
{
|
||||
// will substitute tokens each time what is run()
|
||||
substitute_placeholders(m_error_template);
|
||||
|
||||
return m_message.c_str();
|
||||
}
|
||||
|
||||
void error_with_option_name::replace_token(const string& from, const string& to) const
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
try {
|
||||
return to_local_8_bit(s);
|
||||
}
|
||||
catch(const std::exception&) {
|
||||
return "<unrepresentable unicode string>";
|
||||
}
|
||||
std::size_t pos = m_message.find(from.c_str(), 0, from.length());
|
||||
// not found: all replaced
|
||||
if (pos == std::string::npos)
|
||||
return;
|
||||
m_message.replace(pos, from.length(), to);
|
||||
}
|
||||
}
|
||||
|
||||
invalid_option_value::
|
||||
invalid_option_value(const std::wstring& bad_value)
|
||||
: validation_error(validation_error::invalid_option_value, convert_value(bad_value))
|
||||
{}
|
||||
#endif
|
||||
const std::string&
|
||||
unknown_option::get_option_name() const throw()
|
||||
{
|
||||
return m_option_name;
|
||||
string error_with_option_name::get_canonical_option_prefix() const
|
||||
{
|
||||
switch (m_option_style)
|
||||
{
|
||||
case command_line_style::allow_dash_for_short:
|
||||
return "-";
|
||||
case command_line_style::allow_slash_for_short:
|
||||
return "/";
|
||||
case command_line_style::allow_long_disguise:
|
||||
return "-";
|
||||
case command_line_style::allow_long:
|
||||
return "--";
|
||||
case 0:
|
||||
return "";
|
||||
}
|
||||
throw std::logic_error("error_with_option_name::m_option_style can only be "
|
||||
"one of [0, allow_dash_for_short, allow_slash_for_short, "
|
||||
"allow_long_disguise or allow_long]");
|
||||
}
|
||||
|
||||
const std::string&
|
||||
ambiguous_option::get_option_name() const throw()
|
||||
{
|
||||
return m_option_name;
|
||||
}
|
||||
|
||||
const std::vector<std::string>&
|
||||
ambiguous_option::alternatives() const throw()
|
||||
|
||||
string error_with_option_name::get_canonical_option_name() const
|
||||
{
|
||||
return m_alternatives;
|
||||
if (!m_substitutions.find("option")->second.length())
|
||||
return m_substitutions.find("original_token")->second;
|
||||
|
||||
string original_token = strip_prefixes(m_substitutions.find("original_token")->second);
|
||||
string option_name = strip_prefixes(m_substitutions.find("option")->second);
|
||||
|
||||
// For long options, use option name
|
||||
if (m_option_style == command_line_style::allow_long ||
|
||||
m_option_style == command_line_style::allow_long_disguise)
|
||||
return get_canonical_option_prefix() + option_name;
|
||||
|
||||
// For short options use first letter of original_token
|
||||
if (m_option_style && original_token.length())
|
||||
return get_canonical_option_prefix() + original_token[0];
|
||||
|
||||
// no prefix
|
||||
return option_name;
|
||||
}
|
||||
|
||||
void
|
||||
multiple_values::set_option_name(const std::string& option_name)
|
||||
|
||||
void error_with_option_name::substitute_placeholders(const string& error_template) const
|
||||
{
|
||||
m_option_name = option_name;
|
||||
m_message = error_template;
|
||||
std::map<std::string, std::string> substitutions(m_substitutions);
|
||||
substitutions["canonical_option"] = get_canonical_option_name();
|
||||
substitutions["prefix"] = get_canonical_option_prefix();
|
||||
|
||||
|
||||
//
|
||||
// replace placeholder with defaults if values are missing
|
||||
//
|
||||
for (map<string, string_pair>::const_iterator iter = m_substitution_defaults.begin();
|
||||
iter != m_substitution_defaults.end(); ++iter)
|
||||
{
|
||||
// missing parameter: use default
|
||||
if (substitutions.count(iter->first) == 0 ||
|
||||
substitutions[iter->first].length() == 0)
|
||||
replace_token(iter->second.first, iter->second.second);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// replace placeholder with values
|
||||
// placeholder are denoted by surrounding '%'
|
||||
//
|
||||
for (map<string, string>::iterator iter = substitutions.begin();
|
||||
iter != substitutions.end(); ++iter)
|
||||
replace_token('%' + iter->first + '%', iter->second);
|
||||
}
|
||||
|
||||
const std::string&
|
||||
multiple_values::get_option_name() const throw()
|
||||
|
||||
void ambiguous_option::substitute_placeholders(const string& original_error_template) const
|
||||
{
|
||||
return m_option_name;
|
||||
}
|
||||
|
||||
void
|
||||
multiple_occurrences::set_option_name(const std::string& option_name)
|
||||
{
|
||||
m_option_name = option_name;
|
||||
// For short forms, all alternatives must be identical, by
|
||||
// definition, to the specified option, so we don't need to
|
||||
// display alternatives
|
||||
if (m_option_style == command_line_style::allow_dash_for_short ||
|
||||
m_option_style == command_line_style::allow_slash_for_short)
|
||||
{
|
||||
error_with_option_name::substitute_placeholders(original_error_template);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
string error_template = original_error_template;
|
||||
// remove duplicates using std::set
|
||||
std::set<std::string> alternatives_set (m_alternatives.begin(), m_alternatives.end());
|
||||
std::vector<std::string> alternatives_vec (alternatives_set.begin(), alternatives_set.end());
|
||||
|
||||
error_template += " and matches ";
|
||||
// Being very cautious: should be > 1 alternative!
|
||||
if (alternatives_vec.size() > 1)
|
||||
{
|
||||
for (unsigned i = 0; i < alternatives_vec.size() - 1; ++i)
|
||||
error_template += "'%prefix%" + alternatives_vec[i] + "', ";
|
||||
error_template += "and ";
|
||||
}
|
||||
|
||||
// there is a programming error if multiple options have the same name...
|
||||
if (m_alternatives.size() > 1 && alternatives_vec.size() == 1)
|
||||
error_template += "different versions of ";
|
||||
|
||||
error_template += "'%prefix%" + alternatives_vec.back() + "'";
|
||||
|
||||
|
||||
// use inherited logic
|
||||
error_with_option_name::substitute_placeholders(error_template);
|
||||
}
|
||||
|
||||
const std::string&
|
||||
multiple_occurrences::get_option_name() const throw()
|
||||
{
|
||||
return m_option_name;
|
||||
}
|
||||
|
||||
validation_error::
|
||||
validation_error(kind_t kind,
|
||||
const std::string& option_value,
|
||||
const std::string& option_name)
|
||||
: error("")
|
||||
, m_kind(kind)
|
||||
, m_option_name(option_name)
|
||||
, m_option_value(option_value)
|
||||
, m_message(error_message(kind))
|
||||
{
|
||||
if (!option_value.empty())
|
||||
{
|
||||
m_message.append(std::string("'") + option_value + std::string("'"));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
validation_error::set_option_name(const std::string& option_name)
|
||||
{
|
||||
m_option_name = option_name;
|
||||
}
|
||||
|
||||
const std::string&
|
||||
validation_error::get_option_name() const throw()
|
||||
{
|
||||
return m_option_name;
|
||||
}
|
||||
|
||||
std::string
|
||||
validation_error::error_message(kind_t kind)
|
||||
|
||||
|
||||
string
|
||||
validation_error::get_template(kind_t kind)
|
||||
{
|
||||
// Initially, store the message in 'const char*' variable,
|
||||
// to avoid conversion to std::string in all cases.
|
||||
const char* msg;
|
||||
switch(kind)
|
||||
{
|
||||
case multiple_values_not_allowed:
|
||||
msg = "multiple values not allowed";
|
||||
break;
|
||||
case at_least_one_value_required:
|
||||
msg = "at least one value required";
|
||||
break;
|
||||
case invalid_bool_value:
|
||||
msg = "invalid bool value";
|
||||
msg = "the argument ('%value%') for option '%canonical_option%' is invalid. Valid choices are 'on|off', 'yes|no', '1|0' and 'true|false'";
|
||||
break;
|
||||
case invalid_option_value:
|
||||
msg = "invalid option value";
|
||||
msg = "the argument ('%value%') for option '%canonical_option%' is invalid";
|
||||
break;
|
||||
case multiple_values_not_allowed:
|
||||
msg = "option '%canonical_option%' only takes a single argument";
|
||||
break;
|
||||
case at_least_one_value_required:
|
||||
msg = "option '%canonical_option%' requires at least one argument";
|
||||
break;
|
||||
// currently unused
|
||||
case invalid_option:
|
||||
msg = "invalid option";
|
||||
msg = "option '%canonical_option%' is not valid";
|
||||
break;
|
||||
default:
|
||||
msg = "unknown error";
|
||||
@@ -315,21 +425,4 @@ namespace boost { namespace program_options {
|
||||
return msg;
|
||||
}
|
||||
|
||||
const char*
|
||||
validation_error::what() const throw()
|
||||
{
|
||||
if (!m_option_name.empty())
|
||||
{
|
||||
m_message = "in option '" + m_option_name + "': "
|
||||
+ error_message(m_kind);
|
||||
}
|
||||
return m_message.c_str();
|
||||
}
|
||||
|
||||
const std::string&
|
||||
required_option::get_option_name() const throw()
|
||||
{
|
||||
return m_option_name;
|
||||
}
|
||||
|
||||
}}
|
||||
|
||||
@@ -17,12 +17,12 @@ namespace boost { namespace program_options {
|
||||
|
||||
using namespace std;
|
||||
|
||||
// First, performs semantic actions for 'oa'.
|
||||
// Then, stores in 'm' all options that are defined in 'desc'.
|
||||
BOOST_PROGRAM_OPTIONS_DECL
|
||||
// First, performs semantic actions for 'oa'.
|
||||
// Then, stores in 'm' all options that are defined in 'desc'.
|
||||
BOOST_PROGRAM_OPTIONS_DECL
|
||||
void store(const parsed_options& options, variables_map& xm,
|
||||
bool utf8)
|
||||
{
|
||||
{
|
||||
// TODO: what if we have different definition
|
||||
// for the same option name during different calls
|
||||
// 'store'.
|
||||
@@ -38,69 +38,72 @@ namespace boost { namespace program_options {
|
||||
// Declared once, to please Intel in VC++ mode;
|
||||
unsigned i;
|
||||
|
||||
// First, convert/store all given options
|
||||
for (i = 0; i < options.options.size(); ++i) {
|
||||
// Declared here so can be used to provide context for exceptions
|
||||
string option_name;
|
||||
string original_token;
|
||||
|
||||
const string& name = options.options[i].string_key;
|
||||
// Skip positional options without name
|
||||
if (name.empty())
|
||||
continue;
|
||||
try
|
||||
{
|
||||
|
||||
// Ignore unregistered option. The 'unregistered'
|
||||
// field can be true only if user has explicitly asked
|
||||
// to allow unregistered options. We can't store them
|
||||
// to variables map (lacking any information about paring),
|
||||
// so just ignore them.
|
||||
if (options.options[i].unregistered)
|
||||
continue;
|
||||
// First, convert/store all given options
|
||||
for (i = 0; i < options.options.size(); ++i) {
|
||||
|
||||
// If option has final value, skip this assignment
|
||||
if (xm.m_final.count(name))
|
||||
continue;
|
||||
option_name = options.options[i].string_key;
|
||||
original_token = options.options[i].original_tokens.size() ?
|
||||
options.options[i].original_tokens[0] :
|
||||
option_name;
|
||||
// Skip positional options without name
|
||||
if (option_name.empty())
|
||||
continue;
|
||||
|
||||
const option_description& d = desc.find(name, false,
|
||||
false, false);
|
||||
// Ignore unregistered option. The 'unregistered'
|
||||
// field can be true only if user has explicitly asked
|
||||
// to allow unregistered options. We can't store them
|
||||
// to variables map (lacking any information about paring),
|
||||
// so just ignore them.
|
||||
if (options.options[i].unregistered)
|
||||
continue;
|
||||
|
||||
// If option has final value, skip this assignment
|
||||
if (xm.m_final.count(option_name))
|
||||
continue;
|
||||
|
||||
string original_token = options.options[i].original_tokens.size() ?
|
||||
options.options[i].original_tokens[0] : "";
|
||||
const option_description& d = desc.find(option_name, false,
|
||||
false, false);
|
||||
|
||||
variable_value& v = m[option_name];
|
||||
if (v.defaulted()) {
|
||||
// Explicit assignment here erases defaulted value
|
||||
v = variable_value();
|
||||
}
|
||||
|
||||
variable_value& v = m[name];
|
||||
if (v.defaulted()) {
|
||||
// Explicit assignment here erases defaulted value
|
||||
v = variable_value();
|
||||
}
|
||||
|
||||
try {
|
||||
d.semantic()->parse(v.value(), options.options[i].value, utf8);
|
||||
|
||||
v.m_value_semantic = d.semantic();
|
||||
|
||||
// The option is not composing, and the value is explicitly
|
||||
// provided. Ignore values of this option for subsequent
|
||||
// calls to 'store'. We store this to a temporary set,
|
||||
// so that several assignment inside *this* 'store' call
|
||||
// are allowed.
|
||||
if (!d.semantic()->is_composing())
|
||||
new_final.insert(option_name);
|
||||
}
|
||||
#ifndef BOOST_NO_EXCEPTIONS
|
||||
catch(validation_error& e)
|
||||
{
|
||||
e.set_option_name(name);
|
||||
throw;
|
||||
}
|
||||
catch(multiple_occurrences& e)
|
||||
{
|
||||
e.set_option_name(name);
|
||||
throw;
|
||||
}
|
||||
catch(multiple_values& e)
|
||||
{
|
||||
e.set_option_name(name);
|
||||
throw;
|
||||
}
|
||||
#endif
|
||||
v.m_value_semantic = d.semantic();
|
||||
|
||||
// The option is not composing, and the value is explicitly
|
||||
// provided. Ignore values of this option for subsequent
|
||||
// calls to 'store'. We store this to a temporary set,
|
||||
// so that several assignment inside *this* 'store' call
|
||||
// are allowed.
|
||||
if (!d.semantic()->is_composing())
|
||||
new_final.insert(name);
|
||||
}
|
||||
#ifndef BOOST_NO_EXCEPTIONS
|
||||
catch(error_with_option_name& e)
|
||||
{
|
||||
// add context and rethrow
|
||||
e.add_context(option_name, original_token, options.m_options_prefix);
|
||||
throw;
|
||||
}
|
||||
#endif
|
||||
xm.m_final.insert(new_final.begin(), new_final.end());
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Second, apply default values and store required options.
|
||||
const vector<shared_ptr<option_description> >& all = desc.options();
|
||||
for(i = 0; i < all.size(); ++i)
|
||||
@@ -109,39 +112,46 @@ namespace boost { namespace program_options {
|
||||
string key = d.key("");
|
||||
// FIXME: this logic relies on knowledge of option_description
|
||||
// internals.
|
||||
// The 'key' is empty if options description contains '*'.
|
||||
// In that
|
||||
// The 'key' is empty if options description contains '*'.
|
||||
// In that
|
||||
// case, default value makes no sense at all.
|
||||
if (key.empty())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (m.count(key) == 0) {
|
||||
|
||||
|
||||
boost::any def;
|
||||
if (d.semantic()->apply_default(def)) {
|
||||
m[key] = variable_value(def, true);
|
||||
m[key].m_value_semantic = d.semantic();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// add empty value if this is an required option
|
||||
if (d.semantic()->is_required()) {
|
||||
xm.m_required.insert(key);
|
||||
|
||||
// For option names specified in multiple ways, e.g. on the command line,
|
||||
// config file etc, the following precedence rules apply:
|
||||
// "--" > ("-" or "/") > ""
|
||||
// Precedence is set conveniently by a single call to length()
|
||||
string canonical_name = d.canonical_display_name(options.m_options_prefix);
|
||||
if (canonical_name.length() > xm.m_required[key].length())
|
||||
xm.m_required[key] = canonical_name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_PROGRAM_OPTIONS_DECL
|
||||
BOOST_PROGRAM_OPTIONS_DECL
|
||||
void store(const wparsed_options& options, variables_map& m)
|
||||
{
|
||||
store(options.utf8_encoded_options, m, true);
|
||||
}
|
||||
|
||||
BOOST_PROGRAM_OPTIONS_DECL
|
||||
BOOST_PROGRAM_OPTIONS_DECL
|
||||
void notify(variables_map& vm)
|
||||
{
|
||||
vm.notify();
|
||||
{
|
||||
vm.notify();
|
||||
}
|
||||
|
||||
abstract_variables_map::abstract_variables_map()
|
||||
@@ -153,7 +163,7 @@ namespace boost { namespace program_options {
|
||||
: m_next(next)
|
||||
{}
|
||||
|
||||
const variable_value&
|
||||
const variable_value&
|
||||
abstract_variables_map::operator[](const std::string& name) const
|
||||
{
|
||||
const variable_value& v = get(name);
|
||||
@@ -169,7 +179,7 @@ namespace boost { namespace program_options {
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
void
|
||||
abstract_variables_map::next(abstract_variables_map* next)
|
||||
{
|
||||
m_next = next;
|
||||
@@ -182,6 +192,13 @@ namespace boost { namespace program_options {
|
||||
: abstract_variables_map(next)
|
||||
{}
|
||||
|
||||
void variables_map::clear()
|
||||
{
|
||||
std::map<std::string, variable_value>::clear();
|
||||
m_final.clear();
|
||||
m_required.clear();
|
||||
}
|
||||
|
||||
const variable_value&
|
||||
variables_map::get(const std::string& name) const
|
||||
{
|
||||
@@ -192,40 +209,41 @@ namespace boost { namespace program_options {
|
||||
else
|
||||
return i->second;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
variables_map::notify()
|
||||
{
|
||||
// This checks if all required options occur
|
||||
for (set<string>::const_iterator r = m_required.begin();
|
||||
for (map<string, string>::const_iterator r = m_required.begin();
|
||||
r != m_required.end();
|
||||
++r)
|
||||
{
|
||||
const string& opt = *r;
|
||||
const string& opt = r->first;
|
||||
const string& display_opt = r->second;
|
||||
map<string, variable_value>::const_iterator iter = find(opt);
|
||||
if (iter == end() || iter->second.empty())
|
||||
if (iter == end() || iter->second.empty())
|
||||
{
|
||||
boost::throw_exception(required_option(opt));
|
||||
|
||||
boost::throw_exception(required_option(display_opt));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// Lastly, run notify actions.
|
||||
for (map<string, variable_value>::iterator k = begin();
|
||||
k != end();
|
||||
++k)
|
||||
for (map<string, variable_value>::iterator k = begin();
|
||||
k != end();
|
||||
++k)
|
||||
{
|
||||
/* Users might wish to use variables_map to store their own values
|
||||
that are not parsed, and therefore will not have value_semantics
|
||||
defined. Do no crash on such values. In multi-module programs,
|
||||
defined. Do not crash on such values. In multi-module programs,
|
||||
one module might add custom values, and the 'notify' function
|
||||
will be called after that, so we check that value_sematics is
|
||||
will be called after that, so we check that value_sematics is
|
||||
not NULL. See:
|
||||
https://svn.boost.org/trac/boost/ticket/2782
|
||||
*/
|
||||
if (k->second.m_value_semantic)
|
||||
k->second.m_value_semantic->notify(k->second.value());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}}
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
#include <boost/program_options/parsers.hpp>
|
||||
#include <cctype>
|
||||
|
||||
using std::size_t;
|
||||
|
||||
#ifdef _WIN32
|
||||
namespace boost { namespace program_options {
|
||||
|
||||
@@ -30,6 +32,7 @@ namespace boost { namespace program_options {
|
||||
|
||||
std::string current;
|
||||
bool inside_quoted = false;
|
||||
bool empty_quote = false;
|
||||
int backslash_count = 0;
|
||||
|
||||
for(; i != e; ++i) {
|
||||
@@ -38,6 +41,7 @@ namespace boost { namespace program_options {
|
||||
// n/2 backslashes and is a quoted block delimiter
|
||||
if (backslash_count % 2 == 0) {
|
||||
current.append(backslash_count / 2, '\\');
|
||||
empty_quote = inside_quoted && current.empty();
|
||||
inside_quoted = !inside_quoted;
|
||||
// '"' preceded by odd number (n) of backslashes generates
|
||||
// (n-1)/2 backslashes and is literal quote.
|
||||
@@ -59,6 +63,7 @@ namespace boost { namespace program_options {
|
||||
// Space outside quoted section terminate the current argument
|
||||
result.push_back(current);
|
||||
current.resize(0);
|
||||
empty_quote = false;
|
||||
for(;i != e && isspace((unsigned char)*i); ++i)
|
||||
;
|
||||
--i;
|
||||
@@ -74,7 +79,7 @@ namespace boost { namespace program_options {
|
||||
|
||||
// If we have non-empty 'current' or we're still in quoted
|
||||
// section (even if 'current' is empty), add the last token.
|
||||
if (!current.empty() || inside_quoted)
|
||||
if (!current.empty() || inside_quoted || empty_quote)
|
||||
result.push_back(current);
|
||||
}
|
||||
return result;
|
||||
@@ -86,7 +91,7 @@ namespace boost { namespace program_options {
|
||||
{
|
||||
std::vector<std::wstring> result;
|
||||
std::vector<std::string> aux = split_winmain(to_internal(cmdline));
|
||||
for (unsigned i = 0, e = aux.size(); i < e; ++i)
|
||||
for (size_t i = 0, e = aux.size(); i < e; ++i)
|
||||
result.push_back(from_utf8(aux[i]));
|
||||
return result;
|
||||
}
|
||||
@@ -94,3 +99,4 @@ namespace boost { namespace program_options {
|
||||
|
||||
}}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -32,6 +32,8 @@ test-suite program_options :
|
||||
[ po-test split_test.cpp ]
|
||||
[ po-test unrecognized_test.cpp ]
|
||||
[ po-test required_test.cpp : required_test.cfg ]
|
||||
[ po-test exception_txt_test.cpp ]
|
||||
[ run options_description_test.cpp : : : <rtti>off <define>BOOST_NO_RTTI <define>BOOST_NO_TYPEID : options_description_no_rtti_test ]
|
||||
;
|
||||
|
||||
exe test_convert : test_convert.cpp ;
|
||||
|
||||
@@ -63,7 +63,8 @@ struct test_case {
|
||||
The "boost::program_options" in parameter type is needed because CW9
|
||||
has std::detail and it causes an ambiguity.
|
||||
*/
|
||||
void apply_syntax(options_description& desc,
|
||||
void apply_syntax(options_description& desc,
|
||||
positional_options_description & m_positional,
|
||||
const char* syntax)
|
||||
{
|
||||
|
||||
@@ -77,8 +78,8 @@ void apply_syntax(options_description& desc,
|
||||
v = value<string>();
|
||||
s.resize(s.size()-1);
|
||||
} else if (*(s.end()-1) == '?') {
|
||||
//v = value<string>()->implicit();
|
||||
v = value<string>();
|
||||
v = value<string>()->implicit_value("bar");
|
||||
m_positional.add("positional", -1);
|
||||
s.resize(s.size()-1);
|
||||
} else if (*(s.end()-1) == '*') {
|
||||
v = value<vector<string> >()->multitoken();
|
||||
@@ -113,12 +114,14 @@ void test_cmdline(const char* syntax,
|
||||
}
|
||||
}
|
||||
options_description desc;
|
||||
apply_syntax(desc, syntax);
|
||||
positional_options_description m_positional;
|
||||
apply_syntax(desc, m_positional, syntax);
|
||||
|
||||
cmdline cmd(xinput);
|
||||
cmd.style(style);
|
||||
cmd.set_options_description(desc);
|
||||
|
||||
if(m_positional.max_total_count())
|
||||
cmd.set_positional_options(m_positional);
|
||||
|
||||
string result;
|
||||
int status = 0;
|
||||
@@ -126,11 +129,13 @@ void test_cmdline(const char* syntax,
|
||||
try {
|
||||
vector<option> options = cmd.run();
|
||||
|
||||
for(unsigned i = 0; i < options.size(); ++i)
|
||||
for(unsigned j = 0; j < options.size(); ++j)
|
||||
{
|
||||
option opt = options[i];
|
||||
option opt = options[j];
|
||||
|
||||
if (opt.position_key != -1) {
|
||||
if (opt.position_key != -1
|
||||
&& (m_positional.max_total_count() == 0 || (size_t)opt.position_key >= m_positional.max_total_count()
|
||||
|| m_positional.name_for_position(opt.position_key) != "positional")) {
|
||||
if (!result.empty())
|
||||
result += " ";
|
||||
result += opt.value[0];
|
||||
@@ -138,18 +143,18 @@ void test_cmdline(const char* syntax,
|
||||
if (!result.empty())
|
||||
result += " ";
|
||||
result += opt.string_key + ":";
|
||||
for (size_t j = 0; j < opt.value.size(); ++j) {
|
||||
if (j != 0)
|
||||
for (size_t k = 0; k < opt.value.size(); ++k) {
|
||||
if (k != 0)
|
||||
result += "-";
|
||||
result += opt.value[j];
|
||||
result += opt.value[k];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch(unknown_option& e) {
|
||||
catch(unknown_option&) {
|
||||
status = s_unknown_option;
|
||||
}
|
||||
catch(ambiguous_option& e) {
|
||||
catch(ambiguous_option&) {
|
||||
status = s_ambiguous_option;
|
||||
}
|
||||
catch(invalid_command_line_syntax& e) {
|
||||
@@ -228,7 +233,7 @@ void test_long_options()
|
||||
{"--giz", s_success, "Giz:"},
|
||||
{0, 0, 0}
|
||||
};
|
||||
test_cmdline("foo bar= baz? Giz", style, test_cases4);
|
||||
test_cmdline("foo bar= Giz", style, test_cases4);
|
||||
}
|
||||
|
||||
void test_short_options()
|
||||
@@ -348,7 +353,7 @@ void test_disguised_long()
|
||||
{"-bee=x -by", s_success, "bee:x bee:y"},
|
||||
{0, 0, 0}
|
||||
};
|
||||
test_cmdline("foo,f goo,g= bee,b?", style, test_cases1);
|
||||
test_cmdline("foo,f goo,g= bee,b=", style, test_cases1);
|
||||
|
||||
style = cmdline::style_t(style | allow_slash_for_short);
|
||||
test_case test_cases2[] = {
|
||||
@@ -356,7 +361,7 @@ void test_disguised_long()
|
||||
{"/goo=x", s_success, "goo:x"},
|
||||
{0, 0, 0}
|
||||
};
|
||||
test_cmdline("foo,f goo,g= bee,b?", style, test_cases2);
|
||||
test_cmdline("foo,f goo,g=", style, test_cases2);
|
||||
}
|
||||
|
||||
void test_guessing()
|
||||
@@ -378,6 +383,15 @@ void test_guessing()
|
||||
{0, 0, 0}
|
||||
};
|
||||
test_cmdline("opt123 opt56 foo,f=", style, test_cases1);
|
||||
|
||||
test_case test_cases2[] = {
|
||||
{"--fname file --fname2 file2", s_success, "fname: file fname2: file2"},
|
||||
{"--fnam file --fnam file2", s_ambiguous_option, ""},
|
||||
{"--fnam file --fname2 file2", s_ambiguous_option, ""},
|
||||
{"--fname2 file2 --fnam file", s_ambiguous_option, ""},
|
||||
{0, 0, 0}
|
||||
};
|
||||
test_cmdline("fname fname2", style, test_cases2);
|
||||
}
|
||||
|
||||
void test_arguments()
|
||||
@@ -598,6 +612,35 @@ void test_unregistered()
|
||||
// It's not clear yet, so I'm leaving the decision till later.
|
||||
}
|
||||
|
||||
void test_implicit_value()
|
||||
{
|
||||
using namespace command_line_style;
|
||||
cmdline::style_t style;
|
||||
|
||||
style = cmdline::style_t(
|
||||
allow_long | long_allow_adjacent
|
||||
);
|
||||
|
||||
test_case test_cases1[] = {
|
||||
{"--foo bar", s_success, "foo: positional:bar"},
|
||||
{"--foo=bar foobar", s_success, "foo:bar positional:foobar"},
|
||||
{0, 0, 0}
|
||||
};
|
||||
|
||||
test_cmdline("positional= foo?", style, test_cases1);
|
||||
|
||||
style = cmdline::style_t(
|
||||
allow_short | allow_dash_for_short
|
||||
| short_allow_adjacent);
|
||||
|
||||
test_case test_cases2[] = {
|
||||
{"-f bar", s_success, "-f: positional:bar"},
|
||||
{"-fbar foobar", s_success, "-f:bar positional:foobar"},
|
||||
{0, 0, 0}
|
||||
};
|
||||
test_cmdline("positional= ,f?", style, test_cases2);
|
||||
}
|
||||
|
||||
int main(int /*ac*/, char** /*av*/)
|
||||
{
|
||||
test_long_options();
|
||||
@@ -610,6 +653,7 @@ int main(int /*ac*/, char** /*av*/)
|
||||
test_additional_parser();
|
||||
test_style_parser();
|
||||
test_unregistered();
|
||||
test_implicit_value();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -63,7 +63,7 @@ void test_unknown_option()
|
||||
catch (unknown_option& e)
|
||||
{
|
||||
BOOST_CHECK_EQUAL(e.get_option_name(), "-f");
|
||||
BOOST_CHECK_EQUAL(string(e.what()), "unknown option -f");
|
||||
BOOST_CHECK_EQUAL(string(e.what()), "unrecognised option '-f'");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,8 +94,8 @@ void test_multiple_values()
|
||||
// because: untyped_value always has one value and this is filtered before reach specific
|
||||
// validation and parsing
|
||||
//
|
||||
BOOST_CHECK_EQUAL(e.get_option_name(), "cfgfile");
|
||||
BOOST_CHECK_EQUAL(string(e.what()), "in option 'cfgfile': multiple values not allowed");
|
||||
BOOST_CHECK_EQUAL(e.get_option_name(), "--cfgfile");
|
||||
BOOST_CHECK_EQUAL(string(e.what()), "option '--cfgfile' only takes a single argument");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -118,8 +118,8 @@ void test_multiple_occurrences()
|
||||
}
|
||||
catch (multiple_occurrences& e)
|
||||
{
|
||||
BOOST_CHECK_EQUAL(e.get_option_name(), "cfgfile");
|
||||
BOOST_CHECK_EQUAL(string(e.what()), "multiple occurrences");
|
||||
BOOST_CHECK_EQUAL(e.get_option_name(), "--cfgfile");
|
||||
BOOST_CHECK_EQUAL(string(e.what()), "option '--cfgfile' cannot be specified more than once");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -145,7 +145,7 @@ void test_missing_value()
|
||||
catch (invalid_command_line_syntax& e)
|
||||
{
|
||||
BOOST_CHECK_EQUAL(e.kind(), invalid_syntax::missing_parameter);
|
||||
BOOST_CHECK_EQUAL(e.tokens(), "cfgfile");
|
||||
BOOST_CHECK_EQUAL(e.tokens(), "--cfgfile");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
672
test/exception_txt_test.cpp
Normal file
672
test/exception_txt_test.cpp
Normal file
@@ -0,0 +1,672 @@
|
||||
// Copyright Leo Goodstadt 2012
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See accompanying file LICENSE_1_0.txt
|
||||
// or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
#include <boost/program_options/parsers.hpp>
|
||||
#include <boost/program_options/options_description.hpp>
|
||||
#include <boost/program_options/variables_map.hpp>
|
||||
#include <boost/program_options/cmdline.hpp>
|
||||
using namespace boost::program_options;
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
#include <cassert>
|
||||
using namespace std;
|
||||
|
||||
#include "minitest.hpp"
|
||||
|
||||
|
||||
|
||||
//
|
||||
// like BOOST_CHECK_EQUAL but with more descriptive error message
|
||||
//
|
||||
#define CHECK_EQUAL(description, a, b) if (a != b) {std::cerr << "\n\nError:\n<<" << \
|
||||
description << ">>\n Expected text=\"" << b << "\"\n Actual text =\"" << a << "\"\n\n"; assert(a == b);}
|
||||
|
||||
|
||||
// Uncomment for Debugging, removes asserts so we can see more failures!
|
||||
//#define BOOST_ERROR(description) std::cerr << description; std::cerr << "\n";
|
||||
|
||||
|
||||
//8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888
|
||||
//
|
||||
// Uncomment to print out the complete set of diagnostic messages for the different test cases
|
||||
/*
|
||||
#define CHECK_EQUAL(description, a, b) if (a != b) {std::cerr << "\n\nError: " << \
|
||||
description << "\n Expecting\n" << b << "\n Found\n" << a << "\n\n"; } \
|
||||
else {std::cout << description<< "\t" << b << "\n";}
|
||||
*/
|
||||
|
||||
//8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888
|
||||
|
||||
|
||||
//
|
||||
// test exception for each specified command line style, e.g. short dash or config file
|
||||
//
|
||||
template<typename EXCEPTION>
|
||||
void test_each_exception_message(const string& test_description, const vector<const char*>& argv, options_description& desc, int style, string exception_msg, istream& is = cin)
|
||||
{
|
||||
if (exception_msg.length() == 0)
|
||||
return;
|
||||
variables_map vm;
|
||||
unsigned argc = argv.size();
|
||||
|
||||
|
||||
try {
|
||||
if (style == -1)
|
||||
store(parse_config_file(is, desc), vm);
|
||||
else
|
||||
store(parse_command_line(argv.size(), &argv[0], desc, style), vm);
|
||||
notify(vm);
|
||||
}
|
||||
catch (EXCEPTION& e)
|
||||
{
|
||||
//cerr << "Correct:\n\t" << e.what() << "\n";
|
||||
CHECK_EQUAL(test_description, e.what(), exception_msg);
|
||||
return;
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
// concatenate argv without boost::algorithm::join
|
||||
string argv_txt;
|
||||
for (unsigned ii = 0; ii < argc - 1; ++ii)
|
||||
argv_txt += argv[ii] + string(" ");
|
||||
if (argc)
|
||||
argv_txt += argv[argc - 1];
|
||||
|
||||
BOOST_ERROR("\n<<" + test_description +
|
||||
string(">>\n Unexpected exception type!\n Actual text =\"") + e.what() +
|
||||
"\"\n argv =\"" + argv_txt +
|
||||
"\"\n Expected text=\"" + exception_msg + "\"\n");
|
||||
return;
|
||||
}
|
||||
BOOST_ERROR(test_description + ": No exception thrown. ");
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//
|
||||
// test exception messages for all command line styles (unix/long/short/slash/config file)
|
||||
//
|
||||
// try each command line style in turn
|
||||
const int unix_style = command_line_style::unix_style;
|
||||
const int short_dash = command_line_style::allow_dash_for_short | command_line_style::allow_short | command_line_style::short_allow_adjacent | command_line_style::allow_sticky;
|
||||
const int short_slash = command_line_style::allow_slash_for_short | command_line_style::allow_short | command_line_style::short_allow_adjacent;
|
||||
const int long_dash = command_line_style::allow_long | command_line_style::long_allow_adjacent | command_line_style::allow_guessing;
|
||||
|
||||
|
||||
|
||||
template<typename EXCEPTION>
|
||||
void test_exception_message(const vector<vector<const char*> >& argv,
|
||||
options_description& desc,
|
||||
const string& error_description,
|
||||
const char* expected_message_template[5])
|
||||
{
|
||||
string expected_message;
|
||||
|
||||
// unix
|
||||
expected_message = expected_message_template[0];
|
||||
test_each_exception_message<EXCEPTION>(error_description + " -- unix",
|
||||
argv[0], desc, unix_style, expected_message);
|
||||
|
||||
// long dash only
|
||||
expected_message = expected_message_template[1];
|
||||
test_each_exception_message<EXCEPTION>(error_description + " -- long_dash",
|
||||
argv[1], desc, long_dash, expected_message);
|
||||
|
||||
|
||||
// short dash only
|
||||
expected_message = expected_message_template[2];
|
||||
test_each_exception_message<EXCEPTION>(error_description + " -- short_dash",
|
||||
argv[2], desc, short_dash, expected_message);
|
||||
|
||||
// short slash only
|
||||
expected_message = expected_message_template[3];
|
||||
test_each_exception_message<EXCEPTION>(error_description + " -- short_slash",
|
||||
argv[3], desc, short_slash, expected_message);
|
||||
|
||||
// config file only
|
||||
expected_message = expected_message_template[4];
|
||||
if (expected_message.length())
|
||||
{
|
||||
istringstream istrm(argv[4][0]);
|
||||
test_each_exception_message<EXCEPTION>(error_description + " -- config_file",
|
||||
argv[4], desc, -1, expected_message, istrm);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#define VEC_STR_PUSH_BACK(vec, c_array) \
|
||||
vec.push_back(vector<const char*>(c_array, c_array + sizeof(c_array) / sizeof(char*)));
|
||||
|
||||
//________________________________________________________________________________________
|
||||
//
|
||||
// invalid_option_value
|
||||
//
|
||||
//________________________________________________________________________________________
|
||||
void test_invalid_option_value_exception_msg()
|
||||
{
|
||||
options_description desc;
|
||||
desc.add_options()
|
||||
("int-option,d", value< int >(), "An option taking an integer")
|
||||
;
|
||||
|
||||
vector<vector<const char*> > argv;
|
||||
const char* argv0[] = { "program", "-d", "A_STRING"} ; VEC_STR_PUSH_BACK(argv, argv0);
|
||||
const char* argv1[] = { "program", "--int", "A_STRING"}; VEC_STR_PUSH_BACK(argv, argv1);
|
||||
const char* argv2[] = { "program", "-d", "A_STRING"} ; VEC_STR_PUSH_BACK(argv, argv2);
|
||||
const char* argv3[] = { "program", "/d", "A_STRING"} ; VEC_STR_PUSH_BACK(argv, argv3);
|
||||
const char* argv4[] = { "int-option=A_STRING"} ; VEC_STR_PUSH_BACK(argv, argv4);
|
||||
|
||||
const char* expected_msg[5] = {
|
||||
"the argument ('A_STRING') for option '--int-option' is invalid",
|
||||
"the argument ('A_STRING') for option '--int-option' is invalid",
|
||||
"the argument ('A_STRING') for option '-d' is invalid",
|
||||
"the argument ('A_STRING') for option '/d' is invalid",
|
||||
"the argument ('A_STRING') for option 'int-option' is invalid",
|
||||
};
|
||||
|
||||
|
||||
test_exception_message<invalid_option_value>(argv, desc, "invalid_option_value",
|
||||
expected_msg);
|
||||
|
||||
|
||||
}
|
||||
|
||||
//________________________________________________________________________________________
|
||||
//
|
||||
// missing_value
|
||||
//
|
||||
//________________________________________________________________________________________
|
||||
void test_missing_value_exception_msg()
|
||||
{
|
||||
options_description desc;
|
||||
desc.add_options()
|
||||
("cfgfile,e", value<string>(), "the config file")
|
||||
("output,o", value<string>(), "the output file")
|
||||
;
|
||||
vector<vector<const char*> > argv;
|
||||
const char* argv0[] = { "program", "-e", "-e", "output.txt"} ; VEC_STR_PUSH_BACK(argv, argv0);
|
||||
const char* argv1[] = { "program", "--cfgfile"} ; VEC_STR_PUSH_BACK(argv, argv1);
|
||||
const char* argv2[] = { "program", "-e", "-e", "output.txt"} ; VEC_STR_PUSH_BACK(argv, argv2);
|
||||
const char* argv3[] = { "program", "/e", "/e", "output.txt"} ; VEC_STR_PUSH_BACK(argv, argv3);
|
||||
const char* argv4[] = { ""} ; VEC_STR_PUSH_BACK(argv, argv4);
|
||||
|
||||
const char* expected_msg[5] = {
|
||||
"the required argument for option '--cfgfile' is missing",
|
||||
"the required argument for option '--cfgfile' is missing",
|
||||
"the required argument for option '-e' is missing",
|
||||
"", // Ignore probable bug in cmdline::finish_option
|
||||
//"the required argument for option '/e' is missing",
|
||||
"",
|
||||
};
|
||||
test_exception_message<invalid_command_line_syntax>(argv, desc,
|
||||
"invalid_syntax::missing_parameter",
|
||||
expected_msg);
|
||||
}
|
||||
|
||||
//________________________________________________________________________________________
|
||||
//
|
||||
// ambiguous_option
|
||||
//
|
||||
//________________________________________________________________________________________
|
||||
void test_ambiguous_option_exception_msg()
|
||||
{
|
||||
options_description desc;
|
||||
desc.add_options()
|
||||
("cfgfile1,c", value<string>(), "the config file")
|
||||
("cfgfile2,o", value<string>(), "the config file")
|
||||
("good,g", "good option")
|
||||
("output,c", value<string>(), "the output file")
|
||||
("output", value<string>(), "the output file")
|
||||
;
|
||||
|
||||
vector<vector<const char*> > argv;
|
||||
const char* argv0[] = {"program", "-ggc", "file", "-o", "anotherfile"} ; VEC_STR_PUSH_BACK(argv, argv0);
|
||||
const char* argv1[] = {"program", "--cfgfile", "file", "--cfgfile", "anotherfile"} ; VEC_STR_PUSH_BACK(argv, argv1);
|
||||
const char* argv2[] = {"program", "-ggc", "file", "-o", "anotherfile"} ; VEC_STR_PUSH_BACK(argv, argv2);
|
||||
const char* argv3[] = {"program", "/c", "file", "/o", "anotherfile"} ; VEC_STR_PUSH_BACK(argv, argv3);
|
||||
const char* argv4[] = { "output=output.txt\n"} ; VEC_STR_PUSH_BACK(argv, argv4);
|
||||
const char* expected_msg[5] = {
|
||||
"option '-c' is ambiguous and matches '--cfgfile1', and '--output'",
|
||||
"option '--cfgfile' is ambiguous and matches '--cfgfile1', and '--cfgfile2'",
|
||||
"option '-c' is ambiguous",
|
||||
"option '/c' is ambiguous",
|
||||
"option 'output' is ambiguous and matches different versions of 'output'",
|
||||
};
|
||||
test_exception_message<ambiguous_option>(argv, desc, "ambiguous_option",
|
||||
expected_msg);
|
||||
}
|
||||
|
||||
//________________________________________________________________________________________
|
||||
//
|
||||
// multiple_occurrences
|
||||
//
|
||||
//________________________________________________________________________________________
|
||||
void test_multiple_occurrences_exception_msg()
|
||||
{
|
||||
options_description desc;
|
||||
desc.add_options()
|
||||
("cfgfile,c", value<string>(), "the configfile")
|
||||
;
|
||||
|
||||
vector<vector<const char*> > argv;
|
||||
const char* argv0[] = {"program", "-c", "file", "-c", "anotherfile"} ; VEC_STR_PUSH_BACK(argv, argv0);
|
||||
const char* argv1[] = {"program", "--cfgfi", "file", "--cfgfi", "anotherfile"} ; VEC_STR_PUSH_BACK(argv, argv1);
|
||||
const char* argv2[] = {"program", "-c", "file", "-c", "anotherfile"} ; VEC_STR_PUSH_BACK(argv, argv2);
|
||||
const char* argv3[] = {"program", "/c", "file", "/c", "anotherfile"} ; VEC_STR_PUSH_BACK(argv, argv3);
|
||||
const char* argv4[] = { "cfgfile=output.txt\ncfgfile=output.txt\n"} ; VEC_STR_PUSH_BACK(argv, argv4);
|
||||
const char* expected_msg[5] = {
|
||||
"option '--cfgfile' cannot be specified more than once",
|
||||
"option '--cfgfile' cannot be specified more than once",
|
||||
"option '-c' cannot be specified more than once",
|
||||
"option '/c' cannot be specified more than once",
|
||||
"option 'cfgfile' cannot be specified more than once",
|
||||
};
|
||||
test_exception_message<multiple_occurrences>(argv, desc, "multiple_occurrences",
|
||||
expected_msg);
|
||||
}
|
||||
|
||||
//________________________________________________________________________________________
|
||||
//
|
||||
// unknown_option
|
||||
//
|
||||
//________________________________________________________________________________________
|
||||
void test_unknown_option_exception_msg()
|
||||
{
|
||||
options_description desc;
|
||||
desc.add_options()
|
||||
("good,g", "good option")
|
||||
;
|
||||
|
||||
vector<vector<const char*> > argv;
|
||||
const char* argv0[] = {"program", "-ggc", "file"} ; VEC_STR_PUSH_BACK(argv, argv0);
|
||||
const char* argv1[] = {"program", "--cfgfile", "file"} ; VEC_STR_PUSH_BACK(argv, argv1);
|
||||
const char* argv2[] = {"program", "-ggc", "file"} ; VEC_STR_PUSH_BACK(argv, argv2);
|
||||
const char* argv3[] = {"program", "/c", "file"} ; VEC_STR_PUSH_BACK(argv, argv3);
|
||||
const char* argv4[] = { "cfgfile=output.txt\n"} ; VEC_STR_PUSH_BACK(argv, argv4);
|
||||
const char* expected_msg[5] = {
|
||||
"unrecognised option '-ggc'",
|
||||
"unrecognised option '--cfgfile'",
|
||||
"unrecognised option '-ggc'",
|
||||
"unrecognised option '/c'",
|
||||
"unrecognised option 'cfgfile'",
|
||||
};
|
||||
test_exception_message<unknown_option>(argv, desc, "unknown_option", expected_msg);
|
||||
}
|
||||
|
||||
//________________________________________________________________________________________
|
||||
//
|
||||
// validation_error::invalid_bool_value
|
||||
//
|
||||
//________________________________________________________________________________________
|
||||
void test_invalid_bool_value_exception_msg()
|
||||
{
|
||||
options_description desc;
|
||||
desc.add_options()
|
||||
("bool_option,b", value< bool>(), "bool_option")
|
||||
;
|
||||
|
||||
|
||||
vector<vector<const char*> > argv;
|
||||
const char* argv0[] = {"program", "-b", "file"} ; VEC_STR_PUSH_BACK(argv, argv0);
|
||||
const char* argv1[] = {"program", "--bool_optio", "file"} ; VEC_STR_PUSH_BACK(argv, argv1);
|
||||
const char* argv2[] = {"program", "-b", "file"} ; VEC_STR_PUSH_BACK(argv, argv2);
|
||||
const char* argv3[] = {"program", "/b", "file"} ; VEC_STR_PUSH_BACK(argv, argv3);
|
||||
const char* argv4[] = { "bool_option=output.txt\n"} ; VEC_STR_PUSH_BACK(argv, argv4);
|
||||
const char* expected_msg[5] = {
|
||||
"the argument ('file') for option '--bool_option' is invalid. Valid choices are 'on|off', 'yes|no', '1|0' and 'true|false'",
|
||||
"the argument ('file') for option '--bool_option' is invalid. Valid choices are 'on|off', 'yes|no', '1|0' and 'true|false'",
|
||||
"the argument ('file') for option '-b' is invalid. Valid choices are 'on|off', 'yes|no', '1|0' and 'true|false'",
|
||||
"the argument ('file') for option '/b' is invalid. Valid choices are 'on|off', 'yes|no', '1|0' and 'true|false'",
|
||||
"the argument ('output.txt') for option 'bool_option' is invalid. Valid choices are 'on|off', 'yes|no', '1|0' and 'true|false'",
|
||||
};
|
||||
test_exception_message<validation_error>(argv,
|
||||
desc,
|
||||
"validation_error::invalid_bool_value",
|
||||
expected_msg);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//________________________________________________________________________________________
|
||||
//
|
||||
// validation_error::multiple_values_not_allowed
|
||||
//
|
||||
//________________________________________________________________________________________
|
||||
//
|
||||
// Strange exception: sole purpose seems to be catching multitoken() associated with a scalar
|
||||
// validation_error::multiple_values_not_allowed seems thus to be a programmer error
|
||||
//
|
||||
//
|
||||
void test_multiple_values_not_allowed_exception_msg()
|
||||
{
|
||||
options_description desc;
|
||||
desc.add_options()
|
||||
("cfgfile,c", value<string>()->multitoken(), "the config file")
|
||||
("good,g", "good option")
|
||||
("output,o", value<string>(), "the output file")
|
||||
;
|
||||
|
||||
vector<vector<const char*> > argv;
|
||||
const char* argv0[] = { "program", "-c", "file", "c", "-o", "fritz", "hugo" } ; VEC_STR_PUSH_BACK(argv, argv0);
|
||||
const char* argv1[] = { "program", "--cfgfil", "file", "c", "--outpu", "fritz", "hugo" } ; VEC_STR_PUSH_BACK(argv, argv1);
|
||||
const char* argv2[] = { "program", "-c", "file", "c", "-o", "fritz", "hugo"} ; VEC_STR_PUSH_BACK(argv, argv2);
|
||||
const char* argv3[] = { "program", "/c", "file", "c", "/o", "fritz", "hugo"} ; VEC_STR_PUSH_BACK(argv, argv3);
|
||||
const char* argv4[] = { "" } ; VEC_STR_PUSH_BACK(argv, argv4);
|
||||
const char* expected_msg[5] = {
|
||||
"option '--cfgfile' only takes a single argument",
|
||||
"option '--cfgfile' only takes a single argument",
|
||||
"option '-c' only takes a single argument",
|
||||
"option '/c' only takes a single argument",
|
||||
"",
|
||||
};
|
||||
test_exception_message<validation_error>(argv,
|
||||
desc,
|
||||
"validation_error::multiple_values_not_allowed",
|
||||
expected_msg);
|
||||
}
|
||||
|
||||
//________________________________________________________________________________________
|
||||
//
|
||||
// validation_error::at_least_one_value_required
|
||||
//
|
||||
//________________________________________________________________________________________
|
||||
//
|
||||
// Strange exception: sole purpose seems to be catching zero_tokens() associated with a scalar
|
||||
// validation_error::multiple_values_not_allowed seems thus to be a programmer error
|
||||
//
|
||||
//
|
||||
void test_at_least_one_value_required_exception_msg()
|
||||
{
|
||||
|
||||
|
||||
options_description desc;
|
||||
desc.add_options()
|
||||
("cfgfile,c", value<int>()->zero_tokens(), "the config file")
|
||||
("other,o", value<string>(), "other")
|
||||
;
|
||||
|
||||
vector<vector<const char*> > argv;
|
||||
const char* argv0[] = { "program", "-c" } ; VEC_STR_PUSH_BACK(argv, argv0);
|
||||
const char* argv1[] = { "program", "--cfg", "--o", "name" } ; VEC_STR_PUSH_BACK(argv, argv1);
|
||||
const char* argv2[] = { "program", "-c" , "-o" , "name" } ; VEC_STR_PUSH_BACK(argv, argv2);
|
||||
const char* argv3[] = { "program", "/c" } ; VEC_STR_PUSH_BACK(argv, argv3);
|
||||
const char* argv4[] = { "" } ; VEC_STR_PUSH_BACK(argv, argv4);
|
||||
const char* expected_msg[5] = {
|
||||
"option '--cfgfile' requires at least one argument",
|
||||
"option '--cfgfile' requires at least one argument",
|
||||
"option '-c' requires at least one argument",
|
||||
"option '/c' requires at least one argument",
|
||||
"",
|
||||
};
|
||||
test_exception_message<validation_error>(argv,
|
||||
desc,
|
||||
"validation_error::at_least_one_value_required",
|
||||
expected_msg);
|
||||
}
|
||||
|
||||
|
||||
//________________________________________________________________________________________
|
||||
//
|
||||
// required_option
|
||||
//
|
||||
//________________________________________________________________________________________
|
||||
void test_required_option_exception_msg()
|
||||
{
|
||||
options_description desc;
|
||||
desc.add_options()
|
||||
("cfgfile,c", value<string>()->required(), "the config file")
|
||||
("good,g", "good option")
|
||||
("output,o", value<string>()->required(), "the output file")
|
||||
;
|
||||
|
||||
vector<vector<const char*> > argv;
|
||||
const char* argv0[] = { "program", "-g" } ; VEC_STR_PUSH_BACK(argv, argv0);
|
||||
const char* argv1[] = { "program", "--g" } ; VEC_STR_PUSH_BACK(argv, argv1);
|
||||
const char* argv2[] = { "program", "-g"} ; VEC_STR_PUSH_BACK(argv, argv2);
|
||||
const char* argv3[] = { "program", "/g"} ; VEC_STR_PUSH_BACK(argv, argv3);
|
||||
const char* argv4[] = { "" } ; VEC_STR_PUSH_BACK(argv, argv4);
|
||||
const char* expected_msg[5] = {
|
||||
"the option '--cfgfile' is required but missing",
|
||||
"the option '--cfgfile' is required but missing",
|
||||
"the option '-c' is required but missing",
|
||||
"the option '/c' is required but missing",
|
||||
"the option 'cfgfile' is required but missing",
|
||||
};
|
||||
test_exception_message<required_option>(argv,
|
||||
desc,
|
||||
"required_option",
|
||||
expected_msg);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Check if this is the expected exception with the right message is being thrown inside
|
||||
* func
|
||||
*/
|
||||
template <typename EXCEPTION, typename FUNC>
|
||||
void test_exception(const string& test_name, const string& exception_txt, FUNC func)
|
||||
{
|
||||
|
||||
try {
|
||||
options_description desc;
|
||||
variables_map vm;
|
||||
func(desc, vm);
|
||||
}
|
||||
catch (EXCEPTION& e)
|
||||
{
|
||||
CHECK_EQUAL(test_name, e.what(), exception_txt);
|
||||
return;
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
BOOST_ERROR(string(test_name + ":\nUnexpected exception. ") + e.what() +
|
||||
"\nExpected text:\n" + exception_txt + "\n\n");
|
||||
return;
|
||||
}
|
||||
BOOST_ERROR(test_name + ": No exception thrown. ");
|
||||
}
|
||||
|
||||
|
||||
|
||||
//________________________________________________________________________________________
|
||||
//
|
||||
// check_reading_file
|
||||
//
|
||||
//________________________________________________________________________________________
|
||||
void check_reading_file(options_description& desc, variables_map& vm)
|
||||
{
|
||||
desc.add_options()
|
||||
("output,o", value<string>(), "the output file");
|
||||
|
||||
const char* file_name = "no_such_file";
|
||||
store(parse_config_file<char>(file_name, desc, true), vm);
|
||||
|
||||
}
|
||||
|
||||
|
||||
//________________________________________________________________________________________
|
||||
//
|
||||
// config_file_wildcard
|
||||
//
|
||||
//________________________________________________________________________________________
|
||||
void config_file_wildcard(options_description& desc, variables_map& vm)
|
||||
{
|
||||
desc.add_options()
|
||||
("outpu*", value<string>(), "the output file1")
|
||||
("outp*", value<string>(), "the output file2")
|
||||
;
|
||||
istringstream is("output1=whichone\noutput2=whichone\n");
|
||||
store(parse_config_file(is, desc), vm);
|
||||
}
|
||||
|
||||
//________________________________________________________________________________________
|
||||
//
|
||||
// invalid_syntax::unrecognized_line
|
||||
//
|
||||
//________________________________________________________________________________________
|
||||
void unrecognized_line(options_description& desc, variables_map& vm)
|
||||
{
|
||||
istringstream is("funny wierd line\n");
|
||||
store(parse_config_file(is, desc), vm);
|
||||
}
|
||||
|
||||
//________________________________________________________________________________________
|
||||
//
|
||||
// abbreviated_options_in_config_file
|
||||
//
|
||||
//________________________________________________________________________________________
|
||||
void abbreviated_options_in_config_file(options_description& desc, variables_map& vm)
|
||||
{
|
||||
desc.add_options()(",o", value<string>(), "the output file");
|
||||
istringstream is("o=output.txt\n");
|
||||
store(parse_config_file(is, desc), vm);
|
||||
}
|
||||
|
||||
|
||||
//________________________________________________________________________________________
|
||||
//
|
||||
// too_many_positional_options
|
||||
//
|
||||
//________________________________________________________________________________________
|
||||
void too_many_positional_options(options_description& desc, variables_map& vm)
|
||||
{
|
||||
const char* argv[] = {"program", "1", "2", "3"};
|
||||
positional_options_description positional_args;
|
||||
positional_args.add("two_positional_arguments", 2);
|
||||
store(command_line_parser(4, argv).options(desc).positional(positional_args).run(), vm);
|
||||
}
|
||||
|
||||
|
||||
//________________________________________________________________________________________
|
||||
//
|
||||
// invalid_command_line_style
|
||||
//
|
||||
//________________________________________________________________________________________
|
||||
|
||||
void test_invalid_command_line_style_exception_msg()
|
||||
{
|
||||
string test_name = "invalid_command_line_style";
|
||||
using namespace command_line_style;
|
||||
options_description desc;
|
||||
desc.add_options()("output,o", value<string>(), "the output file");
|
||||
|
||||
vector<int> invalid_styles;
|
||||
invalid_styles.push_back(allow_short | short_allow_adjacent);
|
||||
invalid_styles.push_back(allow_short | allow_dash_for_short);
|
||||
invalid_styles.push_back(allow_long);
|
||||
vector<string> invalid_diagnostics;
|
||||
invalid_diagnostics.push_back("boost::program_options misconfiguration: choose one "
|
||||
"or other of 'command_line_style::allow_slash_for_short' "
|
||||
"(slashes) or 'command_line_style::allow_dash_for_short' "
|
||||
"(dashes) for short options.");
|
||||
invalid_diagnostics.push_back("boost::program_options misconfiguration: choose one "
|
||||
"or other of 'command_line_style::short_allow_next' "
|
||||
"(whitespace separated arguments) or "
|
||||
"'command_line_style::short_allow_adjacent' ('=' "
|
||||
"separated arguments) for short options.");
|
||||
invalid_diagnostics.push_back("boost::program_options misconfiguration: choose one "
|
||||
"or other of 'command_line_style::long_allow_next' "
|
||||
"(whitespace separated arguments) or "
|
||||
"'command_line_style::long_allow_adjacent' ('=' "
|
||||
"separated arguments) for long options.");
|
||||
|
||||
|
||||
const char* argv[] = {"program"};
|
||||
variables_map vm;
|
||||
for (unsigned ii = 0; ii < 3; ++ii)
|
||||
{
|
||||
bool exception_thrown = false;
|
||||
try
|
||||
{
|
||||
store(parse_command_line(1, argv, desc, invalid_styles[ii]), vm);
|
||||
}
|
||||
catch (invalid_command_line_style& e)
|
||||
{
|
||||
string error_msg("arguments are not allowed for unabbreviated option names");
|
||||
CHECK_EQUAL(test_name, e.what(), invalid_diagnostics[ii]);
|
||||
exception_thrown = true;
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
BOOST_ERROR(string(test_name + ":\nUnexpected exception. ") + e.what() +
|
||||
"\nExpected text:\n" + invalid_diagnostics[ii] + "\n");
|
||||
exception_thrown = true;
|
||||
}
|
||||
if (!exception_thrown)
|
||||
{
|
||||
BOOST_ERROR(test_name << ": No exception thrown. ");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
int main(int /*ac*/, char** /*av*/)
|
||||
{
|
||||
test_ambiguous_option_exception_msg();
|
||||
test_unknown_option_exception_msg();
|
||||
test_multiple_occurrences_exception_msg();
|
||||
test_missing_value_exception_msg();
|
||||
test_invalid_option_value_exception_msg();
|
||||
test_invalid_bool_value_exception_msg();
|
||||
test_multiple_values_not_allowed_exception_msg();
|
||||
test_required_option_exception_msg();
|
||||
test_at_least_one_value_required_exception_msg();
|
||||
|
||||
string test_name;
|
||||
string expected_message;
|
||||
|
||||
|
||||
// check_reading_file
|
||||
test_name = "check_reading_file";
|
||||
expected_message = "can not read options configuration file 'no_such_file'";
|
||||
test_exception<reading_file>(test_name, expected_message, check_reading_file);
|
||||
|
||||
// config_file_wildcard
|
||||
test_name = "config_file_wildcard";
|
||||
expected_message = "options 'outpu*' and 'outp*' will both match the same arguments from the configuration file";
|
||||
test_exception<error>(test_name, expected_message, config_file_wildcard);
|
||||
|
||||
// unrecognized_line
|
||||
test_name = "unrecognized_line";
|
||||
expected_message = "the options configuration file contains an invalid line 'funny wierd line'";
|
||||
test_exception<invalid_syntax>(test_name, expected_message, unrecognized_line);
|
||||
|
||||
|
||||
// abbreviated_options_in_config_file
|
||||
test_name = "abbreviated_options_in_config_file";
|
||||
expected_message = "abbreviated option names are not permitted in options configuration files";
|
||||
test_exception<error>(test_name, expected_message, abbreviated_options_in_config_file);
|
||||
|
||||
test_name = "too_many_positional_options";
|
||||
expected_message = "too many positional options have been specified on the command line";
|
||||
test_exception<too_many_positional_options_error>(
|
||||
test_name, expected_message, too_many_positional_options);
|
||||
|
||||
test_invalid_command_line_style_exception_msg();
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ void test_type()
|
||||
("bar", value<string>(), "")
|
||||
;
|
||||
|
||||
#ifndef BOOST_NO_RTTI
|
||||
const typed_value_base* b = dynamic_cast<const typed_value_base*>
|
||||
(desc.find("foo", false).semantic().get());
|
||||
BOOST_CHECK(b);
|
||||
@@ -34,6 +35,7 @@ void test_type()
|
||||
(desc.find("bar", false).semantic().get());
|
||||
BOOST_CHECK(b2);
|
||||
BOOST_CHECK(b2->value_type() == typeid(string));
|
||||
#endif
|
||||
}
|
||||
|
||||
void test_approximation()
|
||||
@@ -53,6 +55,17 @@ void test_approximation()
|
||||
BOOST_CHECK_EQUAL(desc.find("all", true).long_name(), "all");
|
||||
BOOST_CHECK_EQUAL(desc.find("all-ch", true).long_name(), "all-chroots");
|
||||
|
||||
options_description desc2;
|
||||
desc2.add_options()
|
||||
("help", "display this message")
|
||||
("config", value<string>(), "config file name")
|
||||
("config-value", value<string>(), "single config value")
|
||||
;
|
||||
|
||||
BOOST_CHECK_EQUAL(desc2.find("config", true).long_name(), "config");
|
||||
BOOST_CHECK_EQUAL(desc2.find("config-value", true).long_name(),
|
||||
"config-value");
|
||||
|
||||
|
||||
// BOOST_CHECK(desc.count_approx("foo") == 1);
|
||||
// set<string> a = desc.approximations("f");
|
||||
@@ -217,6 +230,21 @@ void test_default_values()
|
||||
);
|
||||
}
|
||||
|
||||
void test_value_name()
|
||||
{
|
||||
options_description desc("Supported options");
|
||||
desc.add_options()
|
||||
("include", value<string>()->value_name("directory"), "Search for headers in 'directory'.")
|
||||
;
|
||||
|
||||
stringstream ss;
|
||||
ss << desc;
|
||||
BOOST_CHECK_EQUAL(ss.str(),
|
||||
"Supported options:\n"
|
||||
" --include directory Search for headers in 'directory'.\n"
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
int main(int, char* [])
|
||||
{
|
||||
@@ -227,6 +255,7 @@ int main(int, char* [])
|
||||
test_long_default_value();
|
||||
test_word_wrapping();
|
||||
test_default_values();
|
||||
test_value_name();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -131,7 +131,7 @@ void test_command_line()
|
||||
// Regression test: check that '0' as style is interpreted as
|
||||
// 'default_style'
|
||||
vector<option> a4 =
|
||||
parse_command_line(sizeof(cmdline3_)/sizeof(const char*), const_cast<char**>(cmdline3_),
|
||||
parse_command_line(sizeof(cmdline3_)/sizeof(const char*), cmdline3_,
|
||||
desc, 0, additional_parser).options;
|
||||
|
||||
BOOST_CHECK_EQUAL(a4.size(), 4u);
|
||||
|
||||
@@ -21,7 +21,7 @@ void do_it()
|
||||
f.write("(\"opt%d\", value<int>())\n")
|
||||
f.write(";\n}\n")
|
||||
f.close()
|
||||
os.system(compiler_command + " -c -save-temps -I /home/ghost/Work/boost-rc program_options_test.cpp")
|
||||
os.system(compiler_command + " -c -save-temps -I /home/ghost/Work/Boost/boost-svn program_options_test.cpp")
|
||||
|
||||
nm = os.popen("nm -S program_options_test.o")
|
||||
for l in nm:
|
||||
@@ -45,7 +45,7 @@ def run_tests(range, compiler_command):
|
||||
print "Avarage: ", (last_size-first_size)/(range[-1]-range[0])
|
||||
|
||||
if __name__ == '__main__':
|
||||
for compiler in [ "g++-3.3 -Os", "g++-3.3 -O3", "g++-3.4 -Os", "g++-3.4 -O3"]:
|
||||
for compiler in [ "g++ -Os", "g++ -O3"]:
|
||||
print "****", compiler, "****"
|
||||
run_tests(range(1, 20), compiler)
|
||||
|
||||
|
||||
@@ -34,6 +34,7 @@ void required_throw_test()
|
||||
notify(vm);
|
||||
}
|
||||
catch (required_option& e) {
|
||||
BOOST_CHECK_EQUAL(e.what(), string("the option '--cfgfile' is required but missing"));
|
||||
throwed = true;
|
||||
}
|
||||
BOOST_CHECK(throwed);
|
||||
|
||||
Reference in New Issue
Block a user