mirror of
https://github.com/boostorg/program_options.git
synced 2026-01-20 16:52:14 +00:00
Compare commits
107 Commits
svn-branch
...
svn-branch
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f9bb3e5db9 | ||
|
|
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 | ||
|
|
8f0bc7ad72 | ||
|
|
48ee128928 | ||
|
|
596f8aa46f | ||
|
|
cbe799d914 | ||
|
|
5e4b39d672 | ||
|
|
d8c809b0a3 | ||
|
|
881c3b4e3a | ||
|
|
e17d52165f | ||
|
|
6e7b140c98 | ||
|
|
4cde608b3e | ||
|
|
7bc84f1b39 | ||
|
|
3400019810 | ||
|
|
e1d38380f4 | ||
|
|
f2e43384fb | ||
|
|
78f209eb0b | ||
|
|
e7e1550269 | ||
|
|
a00a6c9d19 | ||
|
|
84cc0d2972 | ||
|
|
d43c947002 | ||
|
|
e6e1ef29db | ||
|
|
78c3d90280 | ||
|
|
2f17c3b9b9 | ||
|
|
a78a1f0d76 | ||
|
|
5af27a78e7 | ||
|
|
de511c601a | ||
|
|
f88e0a9572 | ||
|
|
1fec99d686 | ||
|
|
da4baad235 | ||
|
|
0c1332a0d3 | ||
|
|
4fab784453 | ||
|
|
274cd2e682 | ||
|
|
b5bc8b4fcb | ||
|
|
6b57600a81 | ||
|
|
9a149beb76 | ||
|
|
dc9097c3d0 | ||
|
|
d4748e8153 | ||
|
|
efc9712f70 | ||
|
|
239deeb456 | ||
|
|
2476e5b265 | ||
|
|
f5bba0a918 | ||
|
|
94d186836e | ||
|
|
6565cbc334 | ||
|
|
c984d59de1 | ||
|
|
07778adab7 | ||
|
|
d78ebf5f0e | ||
|
|
7b23670e4d | ||
|
|
cb9bd037d9 | ||
|
|
c2442fcad6 | ||
|
|
e5a143e2c5 | ||
|
|
58d35a27b9 | ||
|
|
69d2f8fb21 | ||
|
|
cedd6570fd | ||
|
|
065b0a4a9d | ||
|
|
fc423bf6bc | ||
|
|
a9c3f21021 | ||
|
|
f27dce4ed4 | ||
|
|
c3e02a2b0a | ||
|
|
934e96dcef | ||
|
|
c184748325 | ||
|
|
87558bfe7c | ||
|
|
eca947a1ab | ||
|
|
87b4fff3e2 | ||
|
|
11946c4461 |
@@ -1,49 +0,0 @@
|
||||
|
||||
subproject libs/program_options/build ;
|
||||
|
||||
SOURCES = cmdline config_file options_description parsers variables_map
|
||||
value_semantic positional_options utf8_codecvt_facet convert
|
||||
winmain
|
||||
;
|
||||
|
||||
lib boost_program_options
|
||||
: ../src/$(SOURCES).cpp
|
||||
: # build requirements
|
||||
[ common-names ] # magic for install and auto-link features
|
||||
<include>$(BOOST_ROOT) <sysinclude>$(BOOST_ROOT)
|
||||
std::locale-support
|
||||
: debug release # build variants
|
||||
;
|
||||
|
||||
dll boost_program_options
|
||||
: ../src/$(SOURCES).cpp
|
||||
: # build requirements
|
||||
[ common-names ] # magic for install and auto-link features
|
||||
<define>BOOST_ALL_DYN_LINK=1 # tell source we're building dll's
|
||||
<runtime-link>dynamic # build only for dynamic runtimes
|
||||
<include>$(BOOST_ROOT) <sysinclude>$(BOOST_ROOT)
|
||||
# The following really turns on static runtime linking
|
||||
# which leads to runtime crashes when using DLL, so
|
||||
# seem DLL is not usable on Metrowerks 8
|
||||
# std::facet-support std::locale-support
|
||||
: debug release # build variants
|
||||
;
|
||||
|
||||
install program_options lib
|
||||
: <lib>boost_program_options <dll>boost_program_options
|
||||
;
|
||||
|
||||
stage stage/lib : <lib>boost_program_options <dll>boost_program_options
|
||||
:
|
||||
# copy to a path rooted at BOOST_ROOT:
|
||||
<locate>$(BOOST_ROOT)
|
||||
# make sure the names of the libraries are correctly named:
|
||||
[ common-names ]
|
||||
# add this target to the "stage" and "all" psuedo-targets:
|
||||
<target>stage
|
||||
<target>all
|
||||
:
|
||||
debug release
|
||||
;
|
||||
|
||||
# end
|
||||
@@ -1,20 +1,20 @@
|
||||
|
||||
project boost/program_options
|
||||
: source-location ../src
|
||||
:
|
||||
source-location ../src
|
||||
;
|
||||
|
||||
SOURCES = cmdline config_file options_description parsers variables_map
|
||||
value_semantic positional_options utf8_codecvt_facet
|
||||
convert winmain
|
||||
;
|
||||
|
||||
import os ;
|
||||
if [ os.name ] = NT
|
||||
{
|
||||
linkage = <link>static ;
|
||||
}
|
||||
|
||||
lib program_options
|
||||
: $(SOURCES).cpp
|
||||
: $(linkage)
|
||||
SOURCES =
|
||||
cmdline config_file options_description parsers variables_map
|
||||
value_semantic positional_options utf8_codecvt_facet
|
||||
convert winmain
|
||||
;
|
||||
|
||||
lib boost_program_options
|
||||
:
|
||||
$(SOURCES).cpp
|
||||
:
|
||||
<link>shared:<define>BOOST_PROGRAM_OPTIONS_DYN_LINK=1 # tell source we're building dll's
|
||||
;
|
||||
|
||||
boost-install boost_program_options ;
|
||||
@@ -2,7 +2,10 @@
|
||||
import toolset ;
|
||||
toolset.using doxygen ;
|
||||
|
||||
boostbook program_option : program_options.xml ;
|
||||
boostbook program_option
|
||||
: program_options.xml
|
||||
: <implicit-dependency>autodoc
|
||||
;
|
||||
|
||||
doxygen autodoc
|
||||
: [ glob ../../../boost/program_options/*.hpp ] ;
|
||||
@@ -52,8 +52,7 @@
|
||||
<listitem>
|
||||
<para>ascii input passed to a Unicode value, and Unicode input
|
||||
passed to an ascii value will be converted using a codecvt
|
||||
facet (which may be specified by the user(which can be
|
||||
specified by the user)
|
||||
facet (which may be specified by the user).
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
@@ -83,7 +82,7 @@
|
||||
</para>
|
||||
|
||||
<para>The Unicode support outlined above is not complete. For example, we
|
||||
don't plan allow Unicode in option names. Unicode support is hard and
|
||||
don't support Unicode option names. Unicode support is hard and
|
||||
requires a Boost-wide solution. Even comparing two arbitrary Unicode
|
||||
strings is non-trivial. Finally, using Unicode in option names is
|
||||
related to internationalization, which has it's own
|
||||
|
||||
@@ -138,7 +138,7 @@ if (vm.count("response-file")) {
|
||||
compilers, it is possible to obtain
|
||||
the split command line, but it's not clear if all compilers support the
|
||||
same mechanism on all versions of the operating system. The
|
||||
<code>split_command_line</code> function is a portable mechanism provided
|
||||
<code>split_winmain</code> function is a portable mechanism provided
|
||||
by the library.</para>
|
||||
|
||||
<para>Here's an example of use:
|
||||
@@ -184,7 +184,7 @@ store(command_line_parser(args).options(desc).run(), vm);
|
||||
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")
|
||||
;
|
||||
@@ -284,7 +284,7 @@ void validate(boost::any& v,
|
||||
using namespace boost::program_options;
|
||||
|
||||
// Make sure no previous assignment to 'a' was made.
|
||||
validators::check_first_occurence(v);
|
||||
validators::check_first_occurrence(v);
|
||||
// Extract the first string from 'values'. If there is more than
|
||||
// one string, it's an error, and exception will be thrown.
|
||||
const string& s = validators::get_single_string(values);
|
||||
@@ -398,13 +398,49 @@ $ export LC_CTYPE=ru_RU.KOI8-R
|
||||
|
||||
</section>
|
||||
|
||||
<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
|
||||
<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
|
||||
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>
|
||||
method of that class:
|
||||
<programlisting>
|
||||
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
|
||||
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
|
||||
<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:
|
||||
<programlisting>
|
||||
vector<string> to_pass_further = collect_unrecognized(parsed.options, include_positional);
|
||||
</programlisting>
|
||||
|
||||
</para>
|
||||
|
||||
</section>
|
||||
|
||||
</section>
|
||||
|
||||
<!--
|
||||
Local Variables:
|
||||
mode: xml
|
||||
sgml-indent-data: t
|
||||
sgml-parent-document: ("program_options.xml" "section")
|
||||
mode: nxml
|
||||
sgml-indent-data: t
|
||||
sgml-parent-document: ("userman.xml" "chapter")
|
||||
sgml-set-face: t
|
||||
End:
|
||||
-->
|
||||
|
||||
@@ -1,9 +1,14 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="refresh" content="0; URL=../../../doc/html/program_option.html">
|
||||
<meta http-equiv="refresh" content="0; URL=../../../doc/html/program_options.html">
|
||||
</head>
|
||||
<body>
|
||||
Automatic redirection failed, please go to
|
||||
<a href="../../../doc/html/program_options.html">../../../doc/html/program_options.html</a>
|
||||
<a href="../../../doc/html/program_options.html">../../../doc/html/program_options.html</a>
|
||||
<hr>
|
||||
<p>© Copyright Beman Dawes, 2001</p>
|
||||
<p>Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
file <a href="../../../LICENSE_1_0.txt">LICENSE_1_0.txt</a> or copy
|
||||
at <a href="http://www.boost.org/LICENSE_1_0.txt">www.boost.org/LICENSE_1_0.txt</a>)</p>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
270
doc/overview.xml
270
doc/overview.xml
@@ -152,37 +152,142 @@ desc.add_options()
|
||||
<para>The syntactic information is provided by the
|
||||
<classname>boost::program_options::options_description</classname> class
|
||||
and some methods of the
|
||||
<classname>boost::program_options::value_semantic</classname> class.
|
||||
The simplest usage is illustrated below:
|
||||
<programlisting>
|
||||
<classname>boost::program_options::value_semantic</classname> class
|
||||
and includes:
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
name of the option, used to identify the option inside the
|
||||
program,
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
description of the option, which can be presented to the user,
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
the allowed number of source tokens that comprise options's
|
||||
value, which is used during parsing.
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
|
||||
<para>Consider the following example:
|
||||
<programlisting>
|
||||
options_description desc;
|
||||
desc.add_options()
|
||||
("help", "produce help message")
|
||||
;
|
||||
</programlisting>
|
||||
This declares one option named "help" and associates a description with
|
||||
it. The user is not allowed to specify any value.
|
||||
</para>
|
||||
|
||||
<para>To make an option accept a value, you'd need the
|
||||
<code>value</code> function mentioned above:
|
||||
<programlisting>
|
||||
options_description desc;
|
||||
desc.add_options()
|
||||
("compression", value<string>(), "compression level")
|
||||
("verbose", value<string>()->implicit(), "verbosity level")
|
||||
("verbose", value<string>()->zero_tokens(), "verbosity level")
|
||||
("email", value<string>()->multitoken(), "email to send to")
|
||||
;
|
||||
</programlisting>
|
||||
With these declarations, the user must specify a value for
|
||||
the first option, using a single token. For the second option, the user
|
||||
may either provide a single token for the value, or no token at
|
||||
all. For the last option, the value can span several tokens. For
|
||||
example, the following command line is OK:
|
||||
<screen>
|
||||
test --compression 10 --verbose --email beadle@mars beadle2@mars
|
||||
</screen>
|
||||
</programlisting>
|
||||
For the first parameter, we specify only the name and the
|
||||
description. No value can be specified in the parsed source.
|
||||
For the first option, the user must specify a value, using a single
|
||||
token. For the third option, the user may either provide a single token
|
||||
for the value, or no token at all. For the last option, the value can
|
||||
span several tokens. For example, the following command line is OK:
|
||||
<screen>
|
||||
test --help --compression 10 --verbose --email beadle@mars beadle2@mars
|
||||
</screen>
|
||||
</para>
|
||||
|
||||
<section>
|
||||
<title>Description formatting</title>
|
||||
|
||||
<para>
|
||||
Sometimes the description can get rather long, for example, when
|
||||
several option's values need separate documentation. Below we
|
||||
describe some simple formatting mechanisms you can use.
|
||||
</para>
|
||||
|
||||
<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
|
||||
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:
|
||||
<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:
|
||||
<screen>
|
||||
--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
|
||||
|
||||
</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:
|
||||
<programlisting>
|
||||
options.add_options()
|
||||
("well_formated", "As you can see this is a very well formatted
|
||||
option description.\n"
|
||||
"You can do this for example:\n\n"
|
||||
"Values:\n"
|
||||
" Value1: \tdoes this and that, bla bla bla bla
|
||||
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");
|
||||
</programlisting>
|
||||
will produce:
|
||||
<screen>
|
||||
--well_formated As you can see this is a
|
||||
very well formatted
|
||||
option description.
|
||||
You can do this for
|
||||
example:
|
||||
|
||||
Values:
|
||||
Value1: does this and
|
||||
that, bla bla
|
||||
bla bla bla bla
|
||||
bla bla bla bla
|
||||
bla bla bla bla
|
||||
bla
|
||||
Value2: does something
|
||||
else, bla bla
|
||||
bla bla bla bla
|
||||
bla bla bla bla
|
||||
bla bla bla bla
|
||||
bla
|
||||
|
||||
This paragraph has a
|
||||
first line indent only,
|
||||
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
|
||||
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
|
||||
possible position of the first line.
|
||||
</para>
|
||||
|
||||
</section>
|
||||
|
||||
</section>
|
||||
|
||||
<section>
|
||||
@@ -194,9 +299,9 @@ desc.add_options()
|
||||
<programlisting>
|
||||
options_description desc;
|
||||
desc.add_options()
|
||||
("compression", value<int>()->default(10), "compression level")
|
||||
("compression", value<int>()->default_value(10), "compression level")
|
||||
("email", value< vector<string> >()
|
||||
->composing()->notify(&your_function), "email")
|
||||
->composing()->notifier(&your_function), "email")
|
||||
;
|
||||
</programlisting>
|
||||
These declarations specify that default value of the first option is 10,
|
||||
@@ -234,7 +339,7 @@ desc.add_options()
|
||||
parser to assign the names. The class specifies how many positional options
|
||||
are allowed, and for each allowed option, specifies the name. For example:
|
||||
<programlisting>
|
||||
positional_options_description pd; pd.add("input-file", 1, 1);
|
||||
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>
|
||||
@@ -243,11 +348,18 @@ positional_options_description pd; pd.add("input-file", 1, 1);
|
||||
given the same name.
|
||||
<programlisting>
|
||||
positional_options_description pd;
|
||||
pd.add("output-file", 2, 2).add_optional("input-file", 0, -1);
|
||||
pd.add("output-file", 2).add("input-file", -1);
|
||||
</programlisting>
|
||||
In the above example, the first two positional options will be associated
|
||||
with name "output-file", and any others with the name "input-file".
|
||||
</para>
|
||||
|
||||
<warning>
|
||||
<para>The &positional_options_desc; class only specifies translation from
|
||||
position to name, and the option name should still be registered with
|
||||
an instance of the &options_description; class.</para>
|
||||
</warning>
|
||||
|
||||
|
||||
</section>
|
||||
|
||||
@@ -362,6 +474,97 @@ notify(vm);
|
||||
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Specific parsers</title>
|
||||
|
||||
<section>
|
||||
<title>Configuration file parser</title>
|
||||
|
||||
<para>The &parse_config_file; function implements parsing
|
||||
of simple INI-like configuration files. Configuration file
|
||||
syntax is line based:
|
||||
</para>
|
||||
<itemizedlist>
|
||||
<listitem><para>A line in the form:</para>
|
||||
<screen>
|
||||
<replaceable>name</replaceable>=<replaceable>value</replaceable>
|
||||
</screen>
|
||||
<para>gives a value to an option.</para>
|
||||
</listitem>
|
||||
<listitem><para>A line in the form:</para>
|
||||
<screen>
|
||||
[<replaceable>section name</replaceable>]
|
||||
</screen>
|
||||
<para>introduces a new section in the configuration file.</para>
|
||||
</listitem>
|
||||
<listitem><para>The <literal>#</literal> character introduces a
|
||||
comment that spans until the end of the line.</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
<para>The option names are relative to the section names, so
|
||||
the following configuration file part:</para>
|
||||
<screen>
|
||||
[gui.accessibility]
|
||||
visual_bell=yes
|
||||
</screen>
|
||||
<para>is equivalent to</para>
|
||||
<screen>
|
||||
gui.accessibility.visual_bell=yes
|
||||
</screen>
|
||||
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Environment variables parser</title>
|
||||
|
||||
<para><firstterm>Environment variables</firstterm> are string variables
|
||||
which are available to all programs via the <code>getenv</code> function
|
||||
of C runtime library. The operating system allows to set initial values
|
||||
for a given user, and the values can be further changed on the command
|
||||
line. For example, on Windows one can use the
|
||||
<filename>autoexec.bat</filename> file or (on recent versions) the
|
||||
<filename>Control Panel/System/Advanced/Environment Variables</filename>
|
||||
dialog, and on Unix —, the <filename>/etc/profile</filename>,
|
||||
<filename>~/.profile</filename> and <filename>~/.bash_profile</filename>
|
||||
files. Because environment variables can be set for the entire system,
|
||||
they are particularly suitable for options which apply to all programs.
|
||||
</para>
|
||||
|
||||
<para>The environment variables can be parsed with the
|
||||
&parse_environment; function. The function have several overloaded
|
||||
versions. The first parameter is always an &options_description;
|
||||
instance, and the second specifies what variables must be processed, and
|
||||
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
|
||||
variables. Also, while option names are most likely in lower case,
|
||||
environment variables conventionally use upper case. So, for an option
|
||||
name <literal>proxy</literal> the environment variable might be called
|
||||
<envar>BOOST_PROXY</envar>. During parsing, we need to perform reverse
|
||||
conversion of the names. This is accomplished by passing the choosen
|
||||
prefix as the second parameter of the &parse_environment; function.
|
||||
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>.
|
||||
</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
|
||||
<code>std::string</code>. That function will be called for each
|
||||
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>
|
||||
|
||||
@@ -402,8 +605,15 @@ notify(vm);
|
||||
|
||||
<row>
|
||||
<entry>&parse_command_line;</entry>
|
||||
<entry>parses command line</entry>
|
||||
<entry>parses command line (simpified interface)</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry>&basic_command_line_parser;</entry>
|
||||
<entry>parses command line (extended interface)</entry>
|
||||
</row>
|
||||
|
||||
|
||||
<row>
|
||||
<entry>&parse_config_file;</entry>
|
||||
<entry>parses config file</entry>
|
||||
@@ -434,7 +644,7 @@ notify(vm);
|
||||
|
||||
<!--
|
||||
Local Variables:
|
||||
mode: xml
|
||||
mode: nxml
|
||||
sgml-indent-data: t
|
||||
sgml-parent-document: ("program_options.xml" "section")
|
||||
sgml-set-face: t
|
||||
|
||||
@@ -151,7 +151,7 @@
|
||||
- test additional parser
|
||||
- Show default values in help output
|
||||
- Adaptive field width
|
||||
- Mandatory options
|
||||
- Mandatory options (2 votes (second Jonathan Graehl))
|
||||
- (new) return vector from parsers by auto_ptr, not by value?
|
||||
- (new) rename value_semantic into value_description
|
||||
- (new) output for positional_options_description
|
||||
|
||||
@@ -37,3 +37,10 @@
|
||||
<!ENTITY command_line_parser
|
||||
"<classname alt='boost::program_options::command_line_parser'>command_line_parser</classname>">
|
||||
|
||||
<!ENTITY basic_command_line_parser
|
||||
"<classname alt='boost::program_options::basic_command_line_parser'>basic_command_line_parser</classname>">
|
||||
|
||||
|
||||
<!ENTITY basic_option
|
||||
"<classname alt='boost::program_options::basic_option'>basic_option</classname>">
|
||||
|
||||
|
||||
@@ -83,5 +83,5 @@
|
||||
<xi:include href="design.xml"/>
|
||||
<xi:include href="acknowledgements.xml"/>
|
||||
|
||||
<xi:include href="autodoc.boostbook"/>
|
||||
<xi:include href="autodoc.xml"/>
|
||||
</library>
|
||||
|
||||
35
doc/todo.txt
35
doc/todo.txt
@@ -1,4 +1,20 @@
|
||||
|
||||
Say that variables_map is actually derived from std::map.
|
||||
|
||||
Make parse_config_file("foo.cfg", desc) work.
|
||||
|
||||
Document handling of positional options which depends on precedding options.
|
||||
I.e scanning the parsed options and creating new variables_map when we see
|
||||
a positional option. (Email from Tony).
|
||||
|
||||
> My instinctive reaction is to provide both via an options argument to
|
||||
> split_command_line (a name that would now be more appropriate). But I
|
||||
> haven't devoted much time to thinking this through, so I may be wrong. :-)
|
||||
>
|
||||
> In any event, the tokenization isn't much fun. I'd expect the library to
|
||||
> provide a convenient mechanism for parsing a response file.
|
||||
|
||||
|
||||
> Similarly, is there some easy to use hook for customizing the "arg" to
|
||||
> indicate the type of the data (similar to how the textual representation
|
||||
> of the default argument can be changed, e.g.
|
||||
@@ -201,3 +217,22 @@ More visibility for bool_switch.
|
||||
> as what can be achieved with the po::command_line_style::style_t enum. I
|
||||
> think most users will need this information sooner or later. A few
|
||||
> examples would be fine... But then again time is such a precious thing
|
||||
|
||||
> Does the library supports sections in config files
|
||||
|
||||
> What about the combination of (if some user-settable switch is thrown,
|
||||
> but not by default):
|
||||
>
|
||||
> * allowing unknown options -- these are considered positional parameters
|
||||
> * rearranging the argument list such that all positional parameters
|
||||
> are moved to the end
|
||||
>
|
||||
> This way:
|
||||
>
|
||||
> program --unknown 42 --known-flag --known-arg value
|
||||
>
|
||||
> is handled as if it were (in standard UNIX command-line-ese):
|
||||
>
|
||||
> program --known-flag --known-arg value -- --unknown 42
|
||||
|
||||
|
||||
|
||||
@@ -96,7 +96,7 @@ Compression level was set to 10.
|
||||
<para>An option value, surely, can have other types than <code>int</code>, and
|
||||
can have other interesting properties, which we'll discuss right now. The
|
||||
complete version of the code snipped below can be found in
|
||||
"example/options_description.cpp".</para>
|
||||
<filename>example/options_description.cpp</filename>.</para>
|
||||
|
||||
<para>Imagine we're writing a compiler. It should take the optimization
|
||||
level, a number of include paths, and a number of input files, and perform some
|
||||
@@ -115,21 +115,29 @@ desc.add_options()
|
||||
</programlisting>
|
||||
</para>
|
||||
|
||||
<para>The "--help" option should be familiar from the previous example.
|
||||
It's a good idea to have this option in all cases.</para>
|
||||
<para>The <literal>"help"</literal> option should be familiar from
|
||||
the previous example. It's a good idea to have this option in all cases.
|
||||
</para>
|
||||
|
||||
<para>The "optimization" option shows two new features. First, we specify
|
||||
<para>The <literal>"optimization"</literal> option shows two new features. First, we specify
|
||||
the address of the variable(<code>&opt</code>). After storing values, that
|
||||
variable will have the value of the option. Second, we specify a default
|
||||
value of 10, which will be used if no value is specified by the user.
|
||||
</para>
|
||||
|
||||
<para>The "include-path" option is an example of the only case where
|
||||
the interface of the <code>options_description</code> class serves only one
|
||||
<para>The <literal>"include-path"</literal> option is an example of the
|
||||
only case where the interface of the <code>options_description</code>
|
||||
class serves only one
|
||||
source -- the command line. Users typically like to use short option names
|
||||
for common options, and the "include-path,I" name specifies that short
|
||||
option name is "I". So, both "--include-path" and "-I" can be used.
|
||||
</para>
|
||||
|
||||
<para>Note also that the type of the <literal>"include-path"</literal>
|
||||
option is <type>std::vector</type>. The library provides special
|
||||
support for vectors -- it will be possible to specify the option several
|
||||
times, and all specified values will be collected in one vector.
|
||||
</para>
|
||||
|
||||
<para>The "input-file" option specifies the list of files to
|
||||
process. That's okay for a start, but, of course, writing something like:
|
||||
@@ -337,7 +345,7 @@ Optimization level is 4
|
||||
|
||||
<!--
|
||||
Local Variables:
|
||||
mode: xml
|
||||
mode: nxml
|
||||
sgml-indent-data: t
|
||||
sgml-parent-document: ("program_options.xml" "section")
|
||||
sgml-set-face: t
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
|
||||
subproject libs/program_options/example ;
|
||||
|
||||
rule program-options-example ( name extra-sources * )
|
||||
{
|
||||
exe $(name) : $(name).cpp <lib>../build/boost_program_options $(extra-sources)
|
||||
: <include>$(BOOST_ROOT) ;
|
||||
}
|
||||
|
||||
program-options-example first ;
|
||||
program-options-example options_description ;
|
||||
program-options-example multiple_sources ;
|
||||
program-options-example custom_syntax ;
|
||||
program-options-example response_file ;
|
||||
program-options-example option_groups ;
|
||||
program-options-example real ;
|
||||
program-options-example regex <lib>../../regex/build/boost_regex ;
|
||||
|
||||
|
||||
#program-options-example prefix ;
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
|
||||
project
|
||||
: requirements <library>../build//program_options
|
||||
: requirements <library>../build//boost_program_options
|
||||
<hardcode-dll-paths>true
|
||||
;
|
||||
|
||||
@@ -9,7 +9,5 @@ exe options_description : options_description.cpp ;
|
||||
exe multiple_sources : multiple_sources.cpp ;
|
||||
exe custom_syntax : custom_syntax.cpp ;
|
||||
|
||||
exe a : a.cpp ;
|
||||
|
||||
#exe real : real.cpp ;
|
||||
#exe regex : regex.cpp /boost/regex//boost_regex ;
|
||||
exe real : real.cpp ;
|
||||
exe regex : regex.cpp /boost/regex//boost_regex ;
|
||||
|
||||
@@ -26,11 +26,17 @@ int main(int ac, char* av[])
|
||||
{
|
||||
try {
|
||||
int opt;
|
||||
int portnum;
|
||||
po::options_description desc("Allowed options");
|
||||
desc.add_options()
|
||||
("help", "produce help message")
|
||||
("optimization", po::value<int>(&opt)->default_value(10),
|
||||
"optimization level")
|
||||
("verbose,v", po::value<int>()->implicit_value(1),
|
||||
"enable verbosity (optionally specify level)")
|
||||
("listen,l", po::value<int>(&portnum)->implicit_value(1001)
|
||||
->default_value(0,"no"),
|
||||
"listen on a port.")
|
||||
("include-path,I", po::value< vector<string> >(),
|
||||
"include path")
|
||||
("input-file", po::value< vector<string> >(), "input file")
|
||||
@@ -62,7 +68,14 @@ int main(int ac, char* av[])
|
||||
<< vm["input-file"].as< vector<string> >() << "\n";
|
||||
}
|
||||
|
||||
if (vm.count("verbose")) {
|
||||
cout << "Verbosity enabled. Level is " << vm["verbose"].as<int>()
|
||||
<< "\n";
|
||||
}
|
||||
|
||||
cout << "Optimization level is " << opt << "\n";
|
||||
|
||||
cout << "Listen port is " << portnum << "\n";
|
||||
}
|
||||
catch(exception& e)
|
||||
{
|
||||
|
||||
@@ -46,6 +46,7 @@ int main(int ac, char* av[])
|
||||
("help", "produce a help message")
|
||||
("include-path,I", value< vector<string> >()->composing(),
|
||||
"include path")
|
||||
("magic", value<int>(), "magic value")
|
||||
("response-file", value<string>(),
|
||||
"can be specified with '@name', too")
|
||||
;
|
||||
@@ -82,6 +83,9 @@ int main(int ac, char* av[])
|
||||
copy(s.begin(), s.end(), ostream_iterator<string>(cout, " "));
|
||||
cout << "\n";
|
||||
}
|
||||
if (vm.count("magic")) {
|
||||
cout << "Magic value: " << vm["magic"].as<int>() << "\n";
|
||||
}
|
||||
}
|
||||
catch(exception& e) {
|
||||
cout << e.what() << "\n";
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
-I bar
|
||||
-I biz
|
||||
-I biz
|
||||
--magic 10
|
||||
25
include/boost/program_options.hpp
Normal file
25
include/boost/program_options.hpp
Normal file
@@ -0,0 +1,25 @@
|
||||
// Copyright Vladimir Prus 2002.
|
||||
// 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)
|
||||
|
||||
// See www.boost.org/libs/program_options for documentation.
|
||||
|
||||
#ifndef PROGRAM_OPTIONS_VP_2003_05_19
|
||||
#define PROGRAM_OPTIONS_VP_2003_05_19
|
||||
|
||||
#if _MSC_VER >= 1020
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/program_options/options_description.hpp>
|
||||
#include <boost/program_options/positional_options.hpp>
|
||||
#include <boost/program_options/parsers.hpp>
|
||||
#include <boost/program_options/variables_map.hpp>
|
||||
#include <boost/program_options/cmdline.hpp>
|
||||
#include <boost/program_options/errors.hpp>
|
||||
#include <boost/program_options/option.hpp>
|
||||
#include <boost/program_options/value_semantic.hpp>
|
||||
#include <boost/program_options/version.hpp>
|
||||
|
||||
#endif
|
||||
85
include/boost/program_options/cmdline.hpp
Normal file
85
include/boost/program_options/cmdline.hpp
Normal file
@@ -0,0 +1,85 @@
|
||||
// Copyright Vladimir Prus 2004.
|
||||
// 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)
|
||||
|
||||
#ifndef BOOST_CMDLINE_HPP_VP_2004_03_13
|
||||
#define BOOST_CMDLINE_HPP_VP_2004_03_13
|
||||
|
||||
namespace boost { namespace program_options { namespace command_line_style {
|
||||
/** Various possible styles of options.
|
||||
|
||||
There are "long" options, which start with "--" and "short",
|
||||
which start with either "-" or "/". Both kinds can be allowed or
|
||||
disallowed, see allow_long and allow_short. The allowed character
|
||||
for short options is also configurable.
|
||||
|
||||
Option's value can be specified in the same token as name
|
||||
("--foo=bar"), or in the next token.
|
||||
|
||||
It's possible to introduce long options by the same character as
|
||||
short options, see allow_long_disguise.
|
||||
|
||||
Finally, guessing (specifying only prefix of option) and case
|
||||
insensitive processing are supported.
|
||||
*/
|
||||
enum style_t {
|
||||
/// Allow "--long_name" style
|
||||
allow_long = 1,
|
||||
/// Alow "-<single character" style
|
||||
allow_short = allow_long << 1,
|
||||
/// Allow "-" in short options
|
||||
allow_dash_for_short = allow_short << 1,
|
||||
/// Allow "/" in short options
|
||||
allow_slash_for_short = allow_dash_for_short << 1,
|
||||
/** Allow option parameter in the same token
|
||||
for long option, like in
|
||||
@verbatim
|
||||
--foo=10
|
||||
@endverbatim
|
||||
*/
|
||||
long_allow_adjacent = allow_slash_for_short << 1,
|
||||
/** Allow option parameter in the next token for
|
||||
long options. */
|
||||
long_allow_next = long_allow_adjacent << 1,
|
||||
/** Allow option parameter in the same token for
|
||||
short options. */
|
||||
short_allow_adjacent = long_allow_next << 1,
|
||||
/** Allow option parameter in the next token for
|
||||
short options. */
|
||||
short_allow_next = short_allow_adjacent << 1,
|
||||
/** Allow to merge several short options together,
|
||||
so that "-s -k" become "-sk". All of the options
|
||||
but last should accept no parameter. For example, if
|
||||
"-s" accept a parameter, then "k" will be taken as
|
||||
parameter, not another short option.
|
||||
Dos-style short options cannot be sticky.
|
||||
*/
|
||||
allow_sticky = short_allow_next << 1,
|
||||
/** Allow abbreviated spellings for long options,
|
||||
if they unambiguously identify long option.
|
||||
No long option name should be prefix of other
|
||||
long option name if guessing is in effect.
|
||||
*/
|
||||
allow_guessing = allow_sticky << 1,
|
||||
/** Ignore the difference in case for options.
|
||||
@todo Should this apply to long options only?
|
||||
*/
|
||||
case_insensitive = allow_guessing << 1,
|
||||
/** Allow long options with single option starting character,
|
||||
e.g <tt>-foo=10</tt>
|
||||
*/
|
||||
allow_long_disguise = case_insensitive << 1,
|
||||
/** The more-or-less traditional unix style. */
|
||||
unix_style = (allow_short | short_allow_adjacent | short_allow_next
|
||||
| allow_long | long_allow_adjacent | long_allow_next
|
||||
| allow_sticky | allow_guessing
|
||||
| allow_dash_for_short),
|
||||
/** The default style. */
|
||||
default_style = unix_style
|
||||
};
|
||||
}}}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
55
include/boost/program_options/config.hpp
Normal file
55
include/boost/program_options/config.hpp
Normal file
@@ -0,0 +1,55 @@
|
||||
// Copyright (c) 2004 Hartmut Kaiser
|
||||
//
|
||||
// Use, modification and distribution is subject to 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)
|
||||
|
||||
#ifndef BOOST_PROGRAM_OPTIONS_CONFIG_HK_2004_01_11
|
||||
#define BOOST_PROGRAM_OPTIONS_CONFIG_HK_2004_01_11
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/version.hpp>
|
||||
|
||||
// Support for autolinking.
|
||||
#if BOOST_VERSION >= 103100 // works beginning from Boost V1.31.0
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// enable automatic library variant selection
|
||||
#if !defined(BOOST_PROGRAM_OPTIONS_SOURCE) && !defined(BOOST_ALL_NO_LIB) && \
|
||||
!defined(BOOST_PROGRAM_OPTIONS_NO_LIB)
|
||||
|
||||
// Set the name of our library, this will get undef'ed by auto_link.hpp
|
||||
// once it's done with it:
|
||||
#define BOOST_LIB_NAME boost_program_options
|
||||
// tell the auto-link code to select a dll when required:
|
||||
#if defined(BOOST_ALL_DYN_LINK) || defined(BOOST_PROGRAM_OPTIONS_DYN_LINK)
|
||||
# define BOOST_DYN_LINK
|
||||
#endif
|
||||
|
||||
// And include the header that does the work:
|
||||
#include <boost/config/auto_link.hpp>
|
||||
|
||||
#endif // auto-linking disabled
|
||||
|
||||
#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)
|
||||
#else
|
||||
# define BOOST_PROGRAM_OPTIONS_DECL __declspec(dllimport)
|
||||
#endif // BOOST_PROGRAM_OPTIONS_SOURCE
|
||||
#endif // DYN_LINK
|
||||
#endif // BOOST_HAS_DECLSPEC
|
||||
|
||||
#ifndef BOOST_PROGRAM_OPTIONS_DECL
|
||||
#define BOOST_PROGRAM_OPTIONS_DECL
|
||||
#endif
|
||||
|
||||
|
||||
#endif // PROGRAM_OPTIONS_CONFIG_HK_2004_01_11
|
||||
|
||||
136
include/boost/program_options/detail/cmdline.hpp
Normal file
136
include/boost/program_options/detail/cmdline.hpp
Normal file
@@ -0,0 +1,136 @@
|
||||
// Copyright Vladimir Prus 2002-2004.
|
||||
// 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)
|
||||
|
||||
|
||||
#ifndef BOOST_CMDLINE_VP_2003_05_19
|
||||
#define BOOST_CMDLINE_VP_2003_05_19
|
||||
|
||||
#include <boost/program_options/config.hpp>
|
||||
#include <boost/program_options/errors.hpp>
|
||||
#include <boost/program_options/cmdline.hpp>
|
||||
#include <boost/program_options/option.hpp>
|
||||
#include <boost/program_options/options_description.hpp>
|
||||
#include <boost/program_options/positional_options.hpp>
|
||||
|
||||
|
||||
#include <boost/detail/workaround.hpp>
|
||||
|
||||
#include <boost/function.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace boost { namespace program_options { namespace detail {
|
||||
|
||||
/** Command line parser class. Main requirements were:
|
||||
- Powerful enough to support all common uses.
|
||||
- Simple and easy to learn/use.
|
||||
- Minimal code size and external dependencies.
|
||||
- Extensible for custom syntaxes.
|
||||
|
||||
First all options are registered. After that, elements of command line
|
||||
are extracted using operator++.
|
||||
|
||||
For each element, user can find
|
||||
- if it's an option or an argument
|
||||
- name of the option
|
||||
- index of the option
|
||||
- option value(s), if any
|
||||
|
||||
Sometimes the registered option name is not equal to the encountered
|
||||
one, for example, because name abbreviation is supported. Therefore
|
||||
two option names can be obtained:
|
||||
- the registered one
|
||||
- the one found at the command line
|
||||
|
||||
There are lot of style options, which can be used to tune the command
|
||||
line parsing. In addition, it's possible to install additional parser
|
||||
which will process custom option styles.
|
||||
|
||||
@todo mininal match length for guessing?
|
||||
*/
|
||||
class BOOST_PROGRAM_OPTIONS_DECL cmdline {
|
||||
public:
|
||||
|
||||
typedef ::boost::program_options::command_line_style::style_t style_t;
|
||||
|
||||
typedef function1<std::pair<std::string, std::string>,
|
||||
const std::string&>
|
||||
additional_parser;
|
||||
|
||||
typedef function1<std::vector<option>, std::vector<std::string>&>
|
||||
style_parser;
|
||||
|
||||
/** Constructs a command line parser for (argc, argv) pair. Uses
|
||||
style options passed in 'style', which should be binary or'ed values
|
||||
of style_t enum. It can also be zero, in which case a "default"
|
||||
style will be used. If 'allow_unregistered' is true, then allows
|
||||
unregistered options. They will be assigned index 1 and are
|
||||
assumed to have optional parameter.
|
||||
*/
|
||||
cmdline(const std::vector<std::string>& args);
|
||||
|
||||
/** @overload */
|
||||
cmdline(int argc, const char*const * argv);
|
||||
|
||||
void style(int style);
|
||||
void allow_unregistered();
|
||||
|
||||
void set_options_description(const options_description& desc);
|
||||
void set_positional_options(
|
||||
const positional_options_description& m_positional);
|
||||
|
||||
std::vector<option> run();
|
||||
|
||||
std::vector<option> parse_long_option(std::vector<std::string>& args);
|
||||
std::vector<option> parse_short_option(std::vector<std::string>& args);
|
||||
std::vector<option> parse_dos_option(std::vector<std::string>& args);
|
||||
std::vector<option> parse_disguised_long_option(
|
||||
std::vector<std::string>& args);
|
||||
std::vector<option> parse_terminator(
|
||||
std::vector<std::string>& args);
|
||||
std::vector<option> handle_additional_parser(
|
||||
std::vector<std::string>& args);
|
||||
|
||||
|
||||
/** Set additional parser. This will be called for each token
|
||||
of command line. If first string in pair is not empty,
|
||||
then the token is considered matched by this parser,
|
||||
and the first string will be considered an option name
|
||||
(which can be long or short), while the second will be
|
||||
option's parameter (if not empty).
|
||||
Note that additional parser can match only one token.
|
||||
*/
|
||||
void set_additional_parser(additional_parser p);
|
||||
|
||||
void extra_style_parser(style_parser s);
|
||||
|
||||
void check_style(int style) const;
|
||||
|
||||
|
||||
void init(const std::vector<std::string>& args);
|
||||
|
||||
void
|
||||
finish_option(option& opt,
|
||||
std::vector<std::string>& other_tokens);
|
||||
|
||||
// Copies of input.
|
||||
std::vector<std::string> args;
|
||||
style_t m_style;
|
||||
bool m_allow_unregistered;
|
||||
|
||||
const options_description* m_desc;
|
||||
const positional_options_description* m_positional;
|
||||
|
||||
additional_parser m_additional_parser;
|
||||
style_parser m_style_parser;
|
||||
};
|
||||
|
||||
void test_cmdline_detail();
|
||||
|
||||
}}}
|
||||
|
||||
#endif
|
||||
|
||||
182
include/boost/program_options/detail/config_file.hpp
Normal file
182
include/boost/program_options/detail/config_file.hpp
Normal file
@@ -0,0 +1,182 @@
|
||||
// Copyright Vladimir Prus 2002-2004.
|
||||
// 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)
|
||||
|
||||
|
||||
#ifndef BOOST_CONFIG_FILE_VP_2003_01_02
|
||||
#define BOOST_CONFIG_FILE_VP_2003_01_02
|
||||
|
||||
#include <iosfwd>
|
||||
#include <string>
|
||||
#include <set>
|
||||
|
||||
#include <boost/noncopyable.hpp>
|
||||
#include <boost/program_options/config.hpp>
|
||||
#include <boost/program_options/option.hpp>
|
||||
#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
|
||||
#endif
|
||||
|
||||
#include <boost/static_assert.hpp>
|
||||
#include <boost/type_traits/is_same.hpp>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
|
||||
|
||||
namespace boost { namespace program_options { namespace detail {
|
||||
|
||||
/** Standalone parser for config files in ini-line format.
|
||||
The parser is a model of single-pass lvalue iterator, and
|
||||
default constructor creates past-the-end-iterator. The typical usage is:
|
||||
config_file_iterator i(is, ... set of options ...), e;
|
||||
for(; i !=e; ++i) {
|
||||
*i;
|
||||
}
|
||||
|
||||
Syntax conventions:
|
||||
|
||||
- config file can not contain positional options
|
||||
- '#' is comment character: it is ignored together with
|
||||
the rest of the line.
|
||||
- variable assignments are in the form
|
||||
name '=' value.
|
||||
spaces around '=' are trimmed.
|
||||
- Section names are given in brackets.
|
||||
|
||||
The actual option name is constructed by combining current section
|
||||
name and specified option name, with dot between. If section_name
|
||||
already contains dot at the end, new dot is not inserted. For example:
|
||||
@verbatim
|
||||
[gui.accessibility]
|
||||
visual_bell=yes
|
||||
@endverbatim
|
||||
will result in option "gui.accessibility.visual_bell" with value
|
||||
"yes" been returned.
|
||||
|
||||
TODO: maybe, we should just accept a pointer to options_description
|
||||
class.
|
||||
*/
|
||||
class common_config_file_iterator
|
||||
: public eof_iterator<common_config_file_iterator, option>
|
||||
{
|
||||
public:
|
||||
common_config_file_iterator() { found_eof(); }
|
||||
common_config_file_iterator(
|
||||
const std::set<std::string>& allowed_options,
|
||||
bool allow_unregistered = false);
|
||||
|
||||
virtual ~common_config_file_iterator() {}
|
||||
|
||||
public: // Method required by eof_iterator
|
||||
|
||||
void get();
|
||||
|
||||
protected: // Stubs for derived classes
|
||||
|
||||
// Obtains next line from the config file
|
||||
// Note: really, this design is a bit ugly
|
||||
// The most clean thing would be to pass 'line_iterator' to
|
||||
// constructor of this class, but to avoid templating this class
|
||||
// we'd need polymorphic iterator, which does not exist yet.
|
||||
virtual bool getline(std::string&) { return false; }
|
||||
|
||||
private:
|
||||
/** Adds another allowed option. If the 'name' ends with
|
||||
'*', then all options with the same prefix are
|
||||
allowed. For example, if 'name' is 'foo*', then 'foo1' and
|
||||
'foo_bar' are allowed. */
|
||||
void add_option(const char* name);
|
||||
|
||||
// Returns true if 's' is a registered option name.
|
||||
bool allowed_option(const std::string& s) const;
|
||||
|
||||
// That's probably too much data for iterator, since
|
||||
// it will be copied, but let's not bother for now.
|
||||
std::set<std::string> allowed_options;
|
||||
// Invariant: no element is prefix of other element.
|
||||
std::set<std::string> allowed_prefixes;
|
||||
std::string m_prefix;
|
||||
bool m_allow_unregistered;
|
||||
};
|
||||
|
||||
template<class charT>
|
||||
class basic_config_file_iterator : public common_config_file_iterator {
|
||||
public:
|
||||
basic_config_file_iterator()
|
||||
{
|
||||
found_eof();
|
||||
}
|
||||
|
||||
/** Creates a config file parser for the specified stream.
|
||||
*/
|
||||
basic_config_file_iterator(std::basic_istream<charT>& is,
|
||||
const std::set<std::string>& allowed_options,
|
||||
bool allow_unregistered = false);
|
||||
|
||||
private: // base overrides
|
||||
|
||||
bool getline(std::string&);
|
||||
|
||||
private: // internal data
|
||||
shared_ptr<std::basic_istream<charT> > is;
|
||||
};
|
||||
|
||||
typedef basic_config_file_iterator<char> config_file_iterator;
|
||||
typedef basic_config_file_iterator<wchar_t> wconfig_file_iterator;
|
||||
|
||||
|
||||
struct null_deleter
|
||||
{
|
||||
void operator()(void const *) const {}
|
||||
};
|
||||
|
||||
|
||||
template<class charT>
|
||||
basic_config_file_iterator<charT>::
|
||||
basic_config_file_iterator(std::basic_istream<charT>& is,
|
||||
const std::set<std::string>& allowed_options,
|
||||
bool allow_unregistered)
|
||||
: common_config_file_iterator(allowed_options, allow_unregistered)
|
||||
{
|
||||
this->is.reset(&is, null_deleter());
|
||||
get();
|
||||
}
|
||||
|
||||
// Specializing this function for wchar_t causes problems on
|
||||
// borland and vc7, as well as on metrowerks. On the first two
|
||||
// I don't know a workaround, so make use of 'to_internal' to
|
||||
// avoid specialization.
|
||||
template<class charT>
|
||||
bool
|
||||
basic_config_file_iterator<charT>::getline(std::string& s)
|
||||
{
|
||||
std::basic_string<charT> in;
|
||||
if (std::getline(*is, in)) {
|
||||
s = to_internal(in);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Specialization is needed to workaround getline bug on Comeau.
|
||||
#if BOOST_WORKAROUND(__COMO_VERSION__, BOOST_TESTED_AT(4303)) || \
|
||||
(defined(__sgi) && BOOST_WORKAROUND(_COMPILER_VERSION, BOOST_TESTED_AT(741)))
|
||||
template<>
|
||||
bool
|
||||
basic_config_file_iterator<wchar_t>::getline(std::string& s);
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
}}}
|
||||
|
||||
#endif
|
||||
107
include/boost/program_options/detail/convert.hpp
Normal file
107
include/boost/program_options/detail/convert.hpp
Normal file
@@ -0,0 +1,107 @@
|
||||
// Copyright Vladimir Prus 2004.
|
||||
// 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)
|
||||
|
||||
#ifndef BOOST_CONVERT_HPP_VP_2004_04_28
|
||||
#define BOOST_CONVERT_HPP_VP_2004_04_28
|
||||
|
||||
#include <boost/program_options/config.hpp>
|
||||
|
||||
#if !defined(BOOST_NO_STD_WSTRING)
|
||||
|
||||
#include <boost/detail/workaround.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <locale>
|
||||
// for mbstate_t
|
||||
#include <cwchar>
|
||||
#include <stdexcept>
|
||||
|
||||
#if defined(BOOST_NO_STDC_NAMESPACE)
|
||||
#include <wchar.h>
|
||||
namespace std
|
||||
{
|
||||
using ::mbstate_t;
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
|
||||
/** Converts from local 8 bit encoding into wchar_t string using
|
||||
the specified locale facet. */
|
||||
BOOST_PROGRAM_OPTIONS_DECL std::wstring
|
||||
from_8_bit(const std::string& s,
|
||||
const std::codecvt<wchar_t, char, std::mbstate_t>& cvt);
|
||||
|
||||
/** Converts from wchar_t string into local 8 bit encoding into using
|
||||
the specified locale facet. */
|
||||
BOOST_PROGRAM_OPTIONS_DECL std::string
|
||||
to_8_bit(const std::wstring& s,
|
||||
const std::codecvt<wchar_t, char, std::mbstate_t>& cvt);
|
||||
|
||||
|
||||
/** Converts 's', which is assumed to be in UTF8 encoding, into wide
|
||||
string. */
|
||||
BOOST_PROGRAM_OPTIONS_DECL std::wstring
|
||||
from_utf8(const std::string& s);
|
||||
|
||||
/** Converts wide string 's' into string in UTF8 encoding. */
|
||||
BOOST_PROGRAM_OPTIONS_DECL std::string
|
||||
to_utf8(const std::wstring& s);
|
||||
|
||||
/** Converts wide string 's' into local 8 bit encoding determined by
|
||||
the current locale. */
|
||||
BOOST_PROGRAM_OPTIONS_DECL std::string
|
||||
to_local_8_bit(const std::wstring& s);
|
||||
|
||||
/** Converts 's', which is assumed to be in local 8 bit encoding, into wide
|
||||
string. */
|
||||
BOOST_PROGRAM_OPTIONS_DECL std::wstring
|
||||
from_local_8_bit(const std::string& s);
|
||||
|
||||
namespace program_options
|
||||
{
|
||||
/** Convert the input string into internal encoding used by
|
||||
program_options. Presence of this function allows to avoid
|
||||
specializing all methods which access input on wchar_t.
|
||||
*/
|
||||
BOOST_PROGRAM_OPTIONS_DECL std::string to_internal(const std::string&);
|
||||
/** @overload */
|
||||
BOOST_PROGRAM_OPTIONS_DECL std::string to_internal(const std::wstring&);
|
||||
|
||||
template<class T>
|
||||
std::vector<std::string> to_internal(const std::vector<T>& s)
|
||||
{
|
||||
std::vector<std::string> result;
|
||||
for (unsigned i = 0; i < s.size(); ++i)
|
||||
result.push_back(to_internal(s[i]));
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
#else
|
||||
#include <vector>
|
||||
#include <string>
|
||||
namespace boost{
|
||||
namespace program_options{
|
||||
BOOST_PROGRAM_OPTIONS_DECL std::string to_internal(const std::string&);
|
||||
|
||||
template<class T>
|
||||
std::vector<std::string> to_internal(const std::vector<T>& s)
|
||||
{
|
||||
std::vector<std::string> result;
|
||||
for (unsigned i = 0; i < s.size(); ++i)
|
||||
result.push_back(to_internal(s[i]));
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
144
include/boost/program_options/detail/parsers.hpp
Normal file
144
include/boost/program_options/detail/parsers.hpp
Normal file
@@ -0,0 +1,144 @@
|
||||
// Copyright Vladimir Prus 2004.
|
||||
// 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)
|
||||
|
||||
#ifndef BOOST_PARSERS_HPP_VP_2004_05_06
|
||||
#define BOOST_PARSERS_HPP_VP_2004_05_06
|
||||
|
||||
#include <boost/program_options/detail/convert.hpp>
|
||||
|
||||
namespace boost { namespace program_options {
|
||||
|
||||
namespace detail {
|
||||
template<class charT, class Iterator>
|
||||
std::vector<std::basic_string<charT> >
|
||||
make_vector(Iterator i, Iterator e)
|
||||
{
|
||||
std::vector<std::basic_string<charT> > result;
|
||||
// Some compilers don't have templated constructor for
|
||||
// vector, so we can't create vector from (argv+1, argv+argc) range
|
||||
for(; i != e; ++i)
|
||||
result.push_back(*i);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
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))
|
||||
{}
|
||||
|
||||
|
||||
template<class charT>
|
||||
basic_command_line_parser<charT>::
|
||||
basic_command_line_parser(int argc, charT* 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)))
|
||||
{}
|
||||
|
||||
|
||||
template<class charT>
|
||||
basic_command_line_parser<charT>&
|
||||
basic_command_line_parser<charT>::options(const options_description& desc)
|
||||
{
|
||||
detail::cmdline::set_options_description(desc);
|
||||
m_desc = &desc;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<class charT>
|
||||
basic_command_line_parser<charT>&
|
||||
basic_command_line_parser<charT>::positional(
|
||||
const positional_options_description& desc)
|
||||
{
|
||||
detail::cmdline::set_positional_options(desc);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<class charT>
|
||||
basic_command_line_parser<charT>&
|
||||
basic_command_line_parser<charT>::style(int style)
|
||||
{
|
||||
detail::cmdline::style(style);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<class charT>
|
||||
basic_command_line_parser<charT>&
|
||||
basic_command_line_parser<charT>::extra_parser(ext_parser ext)
|
||||
{
|
||||
detail::cmdline::set_additional_parser(ext);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<class charT>
|
||||
basic_command_line_parser<charT>&
|
||||
basic_command_line_parser<charT>::allow_unregistered()
|
||||
{
|
||||
detail::cmdline::allow_unregistered();
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<class charT>
|
||||
basic_command_line_parser<charT>&
|
||||
basic_command_line_parser<charT>::extra_style_parser(style_parser s)
|
||||
{
|
||||
detail::cmdline::extra_style_parser(s);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
|
||||
template<class charT>
|
||||
basic_parsed_options<charT>
|
||||
basic_command_line_parser<charT>::run()
|
||||
{
|
||||
parsed_options result(m_desc);
|
||||
result.options = detail::cmdline::run();
|
||||
|
||||
// Presense of parsed_options -> wparsed_options conversion
|
||||
// does the trick.
|
||||
return basic_parsed_options<charT>(result);
|
||||
}
|
||||
|
||||
|
||||
template<class charT>
|
||||
basic_parsed_options<charT>
|
||||
parse_command_line(int argc, charT* argv[],
|
||||
const options_description& desc,
|
||||
int style,
|
||||
function1<std::pair<std::string, std::string>,
|
||||
const std::string&> ext)
|
||||
{
|
||||
return basic_command_line_parser<charT>(argc, argv).options(desc).
|
||||
style(style).extra_parser(ext).run();
|
||||
}
|
||||
|
||||
template<class charT>
|
||||
std::vector< std::basic_string<charT> >
|
||||
collect_unrecognized(const std::vector< basic_option<charT> >& options,
|
||||
enum collect_unrecognized_mode mode)
|
||||
{
|
||||
std::vector< std::basic_string<charT> > result;
|
||||
for(unsigned i = 0; i < options.size(); ++i)
|
||||
{
|
||||
if (options[i].unregistered ||
|
||||
(mode == include_positional && options[i].position_key != -1))
|
||||
{
|
||||
copy(options[i].original_tokens.begin(),
|
||||
options[i].original_tokens.end(),
|
||||
back_inserter(result));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
25
include/boost/program_options/detail/utf8_codecvt_facet.hpp
Normal file
25
include/boost/program_options/detail/utf8_codecvt_facet.hpp
Normal file
@@ -0,0 +1,25 @@
|
||||
// Copyright (c) 2001 Ronald Garcia, Indiana University (garcia@osl.iu.edu)
|
||||
// Andrew Lumsdaine, Indiana University (lums@osl.iu.edu). Permission to copy,
|
||||
// use, modify, sell and distribute this software is granted provided this
|
||||
// copyright notice appears in all copies. This software is provided "as is"
|
||||
// without express or implied warranty, and with no claim as to its suitability
|
||||
// for any purpose.
|
||||
|
||||
#ifndef BOOST_PROGRAM_OPTIONS_UTF8_CODECVT_FACET_HPP
|
||||
#define BOOST_PROGRAM_OPTIONS_UTF8_CODECVT_FACET_HPP
|
||||
|
||||
#include <boost/program_options/config.hpp>
|
||||
|
||||
#define BOOST_UTF8_BEGIN_NAMESPACE \
|
||||
namespace boost { namespace program_options { namespace detail {
|
||||
|
||||
#define BOOST_UTF8_END_NAMESPACE }}}
|
||||
#define BOOST_UTF8_DECL BOOST_PROGRAM_OPTIONS_DECL
|
||||
|
||||
#include <boost/detail/utf8_codecvt_facet.hpp>
|
||||
|
||||
#undef BOOST_UTF8_BEGIN_NAMESPACE
|
||||
#undef BOOST_UTF8_END_NAMESPACE
|
||||
#undef BOOST_UTF8_DECL
|
||||
|
||||
#endif
|
||||
208
include/boost/program_options/detail/value_semantic.hpp
Normal file
208
include/boost/program_options/detail/value_semantic.hpp
Normal file
@@ -0,0 +1,208 @@
|
||||
// Copyright Vladimir Prus 2004.
|
||||
// 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)
|
||||
|
||||
// This file defines template functions that are declared in
|
||||
// ../value_semantic.hpp.
|
||||
|
||||
#include <boost/throw_exception.hpp>
|
||||
|
||||
namespace boost { namespace program_options {
|
||||
|
||||
extern BOOST_PROGRAM_OPTIONS_DECL std::string arg;
|
||||
|
||||
template<class T, class charT>
|
||||
std::string
|
||||
typed_value<T, charT>::name() const
|
||||
{
|
||||
if (!m_implicit_value.empty() && !m_implicit_value_as_text.empty()) {
|
||||
std::string msg = "[=arg(=" + m_implicit_value_as_text + ")]";
|
||||
if (!m_default_value.empty() && !m_default_value_as_text.empty())
|
||||
msg += " (=" + m_default_value_as_text + ")";
|
||||
return msg;
|
||||
}
|
||||
else if (!m_default_value.empty() && !m_default_value_as_text.empty()) {
|
||||
return arg + " (=" + m_default_value_as_text + ")";
|
||||
} else {
|
||||
return arg;
|
||||
}
|
||||
}
|
||||
|
||||
template<class T, class charT>
|
||||
void
|
||||
typed_value<T, charT>::notify(const boost::any& value_store) const
|
||||
{
|
||||
const T* value = boost::any_cast<const T>(&value_store);
|
||||
if (m_store_to) {
|
||||
*m_store_to = *value;
|
||||
}
|
||||
if (m_notifier) {
|
||||
m_notifier(*value);
|
||||
}
|
||||
}
|
||||
|
||||
namespace validators {
|
||||
/* If v.size() > 1, throw validation_error.
|
||||
If v.size() == 1, return v.front()
|
||||
Otherwise, returns a reference to a statically allocated
|
||||
empty string if 'allow_empty' and throws validation_error
|
||||
otherwise. */
|
||||
template<class charT>
|
||||
const std::basic_string<charT>& get_single_string(
|
||||
const std::vector<std::basic_string<charT> >& v,
|
||||
bool allow_empty = false)
|
||||
{
|
||||
static std::basic_string<charT> empty;
|
||||
if (v.size() > 1)
|
||||
throw validation_error("multiple values not allowed");
|
||||
if (v.size() == 1)
|
||||
return v.front();
|
||||
else if (allow_empty)
|
||||
return empty;
|
||||
else
|
||||
throw validation_error("at least one value required");
|
||||
}
|
||||
|
||||
/* Throws multiple_occurrences if 'value' is not empty. */
|
||||
BOOST_PROGRAM_OPTIONS_DECL void
|
||||
check_first_occurrence(const boost::any& value);
|
||||
}
|
||||
|
||||
using namespace validators;
|
||||
|
||||
/** Validates 's' and updates 'v'.
|
||||
@pre 'v' is either empty or in the state assigned by the previous
|
||||
invocation of 'validate'.
|
||||
The target type is specified via a parameter which has the type of
|
||||
pointer to the desired type. This is workaround for compilers without
|
||||
partial template ordering, just like the last 'long/int' parameter.
|
||||
*/
|
||||
template<class T, class charT>
|
||||
void validate(boost::any& v,
|
||||
const std::vector< std::basic_string<charT> >& xs,
|
||||
T*, long)
|
||||
{
|
||||
validators::check_first_occurrence(v);
|
||||
std::basic_string<charT> s(validators::get_single_string(xs));
|
||||
try {
|
||||
v = any(lexical_cast<T>(s));
|
||||
}
|
||||
catch(const bad_lexical_cast&) {
|
||||
boost::throw_exception(invalid_option_value(s));
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_PROGRAM_OPTIONS_DECL void validate(boost::any& v,
|
||||
const std::vector<std::string>& xs,
|
||||
bool*,
|
||||
int);
|
||||
|
||||
#if !defined(BOOST_NO_STD_WSTRING)
|
||||
BOOST_PROGRAM_OPTIONS_DECL void validate(boost::any& v,
|
||||
const std::vector<std::wstring>& xs,
|
||||
bool*,
|
||||
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
|
||||
// value_semantic.cpp
|
||||
#if ! ( ( BOOST_WORKAROUND(__GNUC__, <= 3) &&\
|
||||
BOOST_WORKAROUND(__GNUC_MINOR__, < 3) ) || \
|
||||
( BOOST_WORKAROUND(BOOST_MSVC, == 1310) ) \
|
||||
)
|
||||
BOOST_PROGRAM_OPTIONS_DECL void validate(boost::any& v,
|
||||
const std::vector<std::string>& xs,
|
||||
std::string*,
|
||||
int);
|
||||
|
||||
#if !defined(BOOST_NO_STD_WSTRING)
|
||||
BOOST_PROGRAM_OPTIONS_DECL void validate(boost::any& v,
|
||||
const std::vector<std::wstring>& xs,
|
||||
std::string*,
|
||||
int);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/** Validates sequences. Allows multiple values per option occurrence
|
||||
and multiple occurrences. */
|
||||
template<class T, class charT>
|
||||
void validate(boost::any& v,
|
||||
const std::vector<std::basic_string<charT> >& s,
|
||||
std::vector<T>*,
|
||||
int)
|
||||
{
|
||||
if (v.empty()) {
|
||||
v = boost::any(std::vector<T>());
|
||||
}
|
||||
std::vector<T>* tv = boost::any_cast< std::vector<T> >(&v);
|
||||
assert(NULL != tv);
|
||||
for (unsigned i = 0; i < s.size(); ++i)
|
||||
{
|
||||
try {
|
||||
/* We call validate so that if user provided
|
||||
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);
|
||||
tv->push_back(boost::any_cast<T>(a));
|
||||
}
|
||||
catch(const bad_lexical_cast& /*e*/) {
|
||||
boost::throw_exception(invalid_option_value(s[i]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<class T, class charT>
|
||||
void
|
||||
typed_value<T, charT>::
|
||||
xparse(boost::any& value_store,
|
||||
const std::vector<std::basic_string<charT> >& new_tokens) const
|
||||
{
|
||||
// If no tokens were given, and the option accepts an implicit
|
||||
// value, then assign the implicit value as the stored value;
|
||||
// otherwise, validate the user-provided token(s).
|
||||
if (new_tokens.empty() && !m_implicit_value.empty())
|
||||
value_store = m_implicit_value;
|
||||
else
|
||||
validate(value_store, new_tokens, (T*)0, 0);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
typed_value<T>*
|
||||
value()
|
||||
{
|
||||
// Explicit qualification is vc6 workaround.
|
||||
return boost::program_options::value<T>(0);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
typed_value<T>*
|
||||
value(T* v)
|
||||
{
|
||||
typed_value<T>* r = new typed_value<T>(v);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
typed_value<T, wchar_t>*
|
||||
wvalue()
|
||||
{
|
||||
return wvalue<T>(0);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
typed_value<T, wchar_t>*
|
||||
wvalue(T* v)
|
||||
{
|
||||
typed_value<T, wchar_t>* r = new typed_value<T, wchar_t>(v);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}}
|
||||
51
include/boost/program_options/environment_iterator.hpp
Normal file
51
include/boost/program_options/environment_iterator.hpp
Normal file
@@ -0,0 +1,51 @@
|
||||
// Copyright Vladimir Prus 2004.
|
||||
// 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)
|
||||
|
||||
#ifndef BOOST_ENVIRONMENT_ITERATOR_VP_2004_05_14
|
||||
#define BOOST_ENVIRONMENT_ITERATOR_VP_2004_05_14
|
||||
|
||||
#include "eof_iterator.hpp"
|
||||
|
||||
#include <utility>
|
||||
#include <string>
|
||||
#include <cassert>
|
||||
|
||||
namespace boost {
|
||||
|
||||
class environment_iterator
|
||||
: public eof_iterator<environment_iterator,
|
||||
std::pair<std::string, std::string> >
|
||||
{
|
||||
public:
|
||||
environment_iterator(char** environment)
|
||||
: m_environment(environment)
|
||||
{
|
||||
get();
|
||||
}
|
||||
|
||||
environment_iterator()
|
||||
{
|
||||
found_eof();
|
||||
}
|
||||
|
||||
void get()
|
||||
{
|
||||
if (*m_environment == 0)
|
||||
found_eof();
|
||||
else {
|
||||
std::string s(*m_environment);
|
||||
std::string::size_type n = s.find('=');
|
||||
assert(n != s.npos);
|
||||
value().first = s.substr(0, n);
|
||||
value().second = s.substr(n+1);
|
||||
}
|
||||
++m_environment;
|
||||
}
|
||||
|
||||
private:
|
||||
char** m_environment;
|
||||
};
|
||||
}
|
||||
#endif
|
||||
97
include/boost/program_options/eof_iterator.hpp
Normal file
97
include/boost/program_options/eof_iterator.hpp
Normal file
@@ -0,0 +1,97 @@
|
||||
// Copyright Vladimir Prus 2004.
|
||||
// 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)
|
||||
|
||||
#ifndef BOOST_EOF_ITERATOR_VP_2004_03_12
|
||||
#define BOOST_EOF_ITERATOR_VP_2004_03_12
|
||||
|
||||
#include <boost/iterator/iterator_facade.hpp>
|
||||
|
||||
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
|
||||
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
|
||||
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
|
||||
only if both have their 'eof' bits set. The 'get' method either obtains
|
||||
the new value or sets the 'eof' bit.
|
||||
|
||||
Specifically, derived class should define:
|
||||
|
||||
1. A default constructor, which creates iterator with 'eof' bit set. The
|
||||
constructor body should call 'found_eof' method defined here.
|
||||
2. Some other constructor. It should initialize some 'data pointer' used
|
||||
in iterator operation and then call 'get'.
|
||||
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'
|
||||
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.
|
||||
*/
|
||||
template<class Derived, class ValueType>
|
||||
class eof_iterator : public iterator_facade<Derived, const ValueType,
|
||||
forward_traversal_tag>
|
||||
{
|
||||
public:
|
||||
eof_iterator()
|
||||
: m_at_eof(false)
|
||||
{}
|
||||
|
||||
protected: // interface for derived
|
||||
|
||||
/** Returns the reference which should be used by derived
|
||||
class to store the next value. */
|
||||
ValueType& value()
|
||||
{
|
||||
return m_value;
|
||||
}
|
||||
|
||||
/** Should be called by derived class to indicate that it can't
|
||||
produce next element. */
|
||||
void found_eof()
|
||||
{
|
||||
m_at_eof = true;
|
||||
}
|
||||
|
||||
|
||||
private: // iterator core operations
|
||||
friend class iterator_core_access;
|
||||
|
||||
void increment()
|
||||
{
|
||||
static_cast<Derived&>(*this).get();
|
||||
}
|
||||
|
||||
bool equal(const eof_iterator& other) const
|
||||
{
|
||||
if (m_at_eof && other.m_at_eof)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
const ValueType& dereference() const
|
||||
{
|
||||
return m_value;
|
||||
}
|
||||
|
||||
bool m_at_eof;
|
||||
ValueType m_value;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
146
include/boost/program_options/errors.hpp
Normal file
146
include/boost/program_options/errors.hpp
Normal file
@@ -0,0 +1,146 @@
|
||||
// Copyright Vladimir Prus 2002-2004.
|
||||
// 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)
|
||||
|
||||
|
||||
#ifndef BOOST_ERRORS_VP_2003_01_02
|
||||
#define BOOST_ERRORS_VP_2003_01_02
|
||||
|
||||
#include <boost/program_options/config.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
#include <vector>
|
||||
|
||||
|
||||
|
||||
namespace boost { namespace program_options {
|
||||
|
||||
/** 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) {}
|
||||
};
|
||||
|
||||
class BOOST_PROGRAM_OPTIONS_DECL invalid_syntax : public error {
|
||||
public:
|
||||
invalid_syntax(const std::string& tokens, const std::string& msg)
|
||||
: error(std::string(msg).append(" in '").append(tokens).append("'")),
|
||||
tokens(tokens), msg(msg)
|
||||
{}
|
||||
|
||||
// gcc says that throw specification on dtor is loosened
|
||||
// without this line
|
||||
~invalid_syntax() throw() {}
|
||||
|
||||
// TODO: copy ctor might throw
|
||||
std::string tokens, msg;
|
||||
};
|
||||
|
||||
/** 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))
|
||||
{}
|
||||
};
|
||||
|
||||
/** 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)),
|
||||
alternatives(alternatives)
|
||||
{}
|
||||
|
||||
~ambiguous_option() throw() {}
|
||||
|
||||
// TODO: copy ctor might throw
|
||||
std::vector<std::string> alternatives;
|
||||
};
|
||||
|
||||
/** 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(const std::string& what) : error(what) {}
|
||||
};
|
||||
|
||||
/** 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(const std::string& what) : error(what) {}
|
||||
};
|
||||
|
||||
/** Class thrown when value of option is incorrect. */
|
||||
class BOOST_PROGRAM_OPTIONS_DECL validation_error : public error {
|
||||
public:
|
||||
validation_error(const std::string& what) : error(what) {}
|
||||
~validation_error() throw() {}
|
||||
void set_option_name(const std::string& option);
|
||||
|
||||
const char* what() const throw();
|
||||
private:
|
||||
mutable std::string m_message; // For on-demand formatting in 'what'
|
||||
std::string m_option_name; // The name of the option which
|
||||
// caused the exception.
|
||||
};
|
||||
|
||||
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. */
|
||||
class BOOST_PROGRAM_OPTIONS_DECL too_many_positional_options_error : public error {
|
||||
public:
|
||||
too_many_positional_options_error(const std::string& what)
|
||||
: error(what) {}
|
||||
};
|
||||
|
||||
/** Class thrown when there are too few positional options. */
|
||||
class BOOST_PROGRAM_OPTIONS_DECL too_few_positional_options_error : public error {
|
||||
public:
|
||||
too_few_positional_options_error(const std::string& what)
|
||||
: error(what) {}
|
||||
};
|
||||
|
||||
class BOOST_PROGRAM_OPTIONS_DECL invalid_command_line_syntax : public invalid_syntax {
|
||||
public:
|
||||
enum kind_t {
|
||||
long_not_allowed = 30,
|
||||
long_adjacent_not_allowed,
|
||||
short_adjacent_not_allowed,
|
||||
empty_adjacent_parameter,
|
||||
missing_parameter,
|
||||
extra_parameter
|
||||
};
|
||||
|
||||
invalid_command_line_syntax(const std::string& tokens, kind_t kind);
|
||||
kind_t kind() const;
|
||||
protected:
|
||||
static std::string error_message(kind_t kind);
|
||||
private:
|
||||
kind_t m_kind;
|
||||
};
|
||||
|
||||
class BOOST_PROGRAM_OPTIONS_DECL invalid_command_line_style : public error {
|
||||
public:
|
||||
invalid_command_line_style(const std::string& msg)
|
||||
: error(msg)
|
||||
{}
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
|
||||
#endif
|
||||
60
include/boost/program_options/option.hpp
Normal file
60
include/boost/program_options/option.hpp
Normal file
@@ -0,0 +1,60 @@
|
||||
// Copyright Vladimir Prus 2004.
|
||||
// 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)
|
||||
|
||||
#ifndef BOOST_OPTION_HPP_VP_2004_02_25
|
||||
#define BOOST_OPTION_HPP_VP_2004_02_25
|
||||
|
||||
#include <boost/program_options/config.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
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
|
||||
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.
|
||||
*/
|
||||
template<class charT>
|
||||
class basic_option {
|
||||
public:
|
||||
basic_option() : position_key(-1), unregistered(false) {}
|
||||
basic_option(const std::string& string_key,
|
||||
const std::vector< std::string> &value)
|
||||
: string_key(string_key), value(value), unregistered(false)
|
||||
{}
|
||||
|
||||
/** String key of this option. Intentionally independent of the template
|
||||
parameter. */
|
||||
std::string string_key;
|
||||
/** Position key of this option. All options without an explicit name are
|
||||
sequentially numbered starting from 0. If an option has explicit name,
|
||||
'position_key' is equal to -1. It is possible that both
|
||||
position_key and string_key is specified, in case name is implicitly
|
||||
added.
|
||||
*/
|
||||
int position_key;
|
||||
/** Option's value */
|
||||
std::vector< std::basic_string<charT> > value;
|
||||
/** The original unchanged tokens this option was
|
||||
created from. */
|
||||
std::vector< std::basic_string<charT> > original_tokens;
|
||||
/** True if option was not recognized. In that case,
|
||||
'string_key' and 'value' are results of purely
|
||||
syntactic parsing of source. The original tokens can be
|
||||
recovered from the "original_tokens" member.
|
||||
*/
|
||||
bool unregistered;
|
||||
|
||||
};
|
||||
typedef basic_option<char> option;
|
||||
typedef basic_option<wchar_t> woption;
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
241
include/boost/program_options/options_description.hpp
Normal file
241
include/boost/program_options/options_description.hpp
Normal file
@@ -0,0 +1,241 @@
|
||||
// Copyright Vladimir Prus 2002-2004.
|
||||
// Copyright Bertolt Mildner 2004.
|
||||
// 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)
|
||||
|
||||
|
||||
#ifndef BOOST_OPTION_DESCRIPTION_VP_2003_05_19
|
||||
#define BOOST_OPTION_DESCRIPTION_VP_2003_05_19
|
||||
|
||||
#include <boost/program_options/config.hpp>
|
||||
#include <boost/program_options/errors.hpp>
|
||||
#include <boost/program_options/value_semantic.hpp>
|
||||
|
||||
#include <boost/function.hpp>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <boost/detail/workaround.hpp>
|
||||
#include <boost/any.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <set>
|
||||
#include <map>
|
||||
#include <stdexcept>
|
||||
|
||||
#include <iosfwd>
|
||||
|
||||
/** Boost namespace */
|
||||
namespace boost {
|
||||
/** Namespace for the library. */
|
||||
namespace program_options {
|
||||
|
||||
/** Describes one possible command line/config file option. There are two
|
||||
kinds of properties of an option. First describe it syntactically and
|
||||
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.
|
||||
@sa options_description
|
||||
*/
|
||||
class BOOST_PROGRAM_OPTIONS_DECL option_description {
|
||||
public:
|
||||
|
||||
option_description();
|
||||
|
||||
/** Initializes the object with the passed data.
|
||||
|
||||
Note: it would be nice to make the second parameter auto_ptr,
|
||||
to explicitly pass ownership. Unfortunately, it's often needed to
|
||||
create objects of types derived from 'value_semantic':
|
||||
options_description d;
|
||||
d.add_options()("a", parameter<int>("n")->default_value(1));
|
||||
Here, the static type returned by 'parameter' should be derived
|
||||
from value_semantic.
|
||||
|
||||
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
|
||||
|
||||
So, we have to use plain old pointers. Besides, users are not
|
||||
expected to use the constructor directly.
|
||||
|
||||
|
||||
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.
|
||||
*/
|
||||
option_description(const char* name,
|
||||
const value_semantic* s);
|
||||
|
||||
/** Initializes the class with the passed data.
|
||||
*/
|
||||
option_description(const char* name,
|
||||
const value_semantic* s,
|
||||
const char* description);
|
||||
|
||||
virtual ~option_description();
|
||||
|
||||
enum match_result { no_match, full_match, approximate_match };
|
||||
|
||||
/** Given 'option', specified in the input source,
|
||||
return 'true' is 'option' specifies *this.
|
||||
*/
|
||||
match_result match(const std::string& option, bool approx) const;
|
||||
|
||||
/** Return 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.
|
||||
If option name contains '*', returns 'option'.
|
||||
If long name was specified, it's the long name, otherwise
|
||||
it's a short name with prepended '-'.
|
||||
*/
|
||||
const std::string& key(const std::string& option) const;
|
||||
|
||||
const std::string& long_name() const;
|
||||
|
||||
/// Explanation of this option
|
||||
const std::string& description() const;
|
||||
|
||||
/// Semantic of option's value
|
||||
shared_ptr<const value_semantic> semantic() const;
|
||||
|
||||
/// Returns the option name, formatted suitably for usage message.
|
||||
std::string format_name() const;
|
||||
|
||||
/** Return the parameter name and properties, formatted suitably for
|
||||
usage message. */
|
||||
std::string format_parameter() const;
|
||||
|
||||
private:
|
||||
|
||||
option_description& set_name(const char* name);
|
||||
|
||||
std::string m_short_name, m_long_name, m_description;
|
||||
// shared_ptr is needed to simplify memory management in
|
||||
// copy ctor and destructor.
|
||||
shared_ptr<const value_semantic> m_value_semantic;
|
||||
};
|
||||
|
||||
class options_description;
|
||||
|
||||
/** Class which provides convenient creation syntax to option_description.
|
||||
*/
|
||||
class BOOST_PROGRAM_OPTIONS_DECL options_description_easy_init {
|
||||
public:
|
||||
options_description_easy_init(options_description* owner);
|
||||
|
||||
options_description_easy_init&
|
||||
operator()(const char* name,
|
||||
const char* description);
|
||||
|
||||
options_description_easy_init&
|
||||
operator()(const char* name,
|
||||
const value_semantic* s);
|
||||
|
||||
options_description_easy_init&
|
||||
operator()(const char* name,
|
||||
const value_semantic* s,
|
||||
const char* description);
|
||||
|
||||
private:
|
||||
options_description* owner;
|
||||
};
|
||||
|
||||
|
||||
/** A set of option descriptions. This provides convenient interface for
|
||||
adding new option (the add_options) method, and facilities to search
|
||||
for options by name.
|
||||
|
||||
See @ref a_adding_options "here" for option adding interface discussion.
|
||||
@sa option_description
|
||||
*/
|
||||
class BOOST_PROGRAM_OPTIONS_DECL options_description {
|
||||
public:
|
||||
static const unsigned m_default_line_length;
|
||||
|
||||
/** Creates the instance. */
|
||||
options_description(unsigned line_length = m_default_line_length);
|
||||
/** Creates the instance. The 'caption' parameter gives the name of
|
||||
this 'options_description' instance. Primarily useful for output.
|
||||
*/
|
||||
options_description(const std::string& caption,
|
||||
unsigned line_length = m_default_line_length);
|
||||
/** Adds new variable description. Throws duplicate_variable_error if
|
||||
either short or long name matches that of already present one.
|
||||
*/
|
||||
void add(shared_ptr<option_description> desc);
|
||||
/** Adds a group of option description. This has the same
|
||||
effect as adding all option_descriptions in 'desc'
|
||||
individually, except that output operator will show
|
||||
a separate group.
|
||||
Returns *this.
|
||||
*/
|
||||
options_description& add(const options_description& desc);
|
||||
|
||||
public:
|
||||
/** Returns an object of implementation-defined type suitable for adding
|
||||
options to options_description. The returned object will
|
||||
have overloaded operator() with parameter type matching
|
||||
'option_description' constructors. Calling the operator will create
|
||||
new option_description instance and add it.
|
||||
*/
|
||||
options_description_easy_init add_options();
|
||||
|
||||
const option_description& find(const std::string& name, bool approx)
|
||||
const;
|
||||
|
||||
const option_description* find_nothrow(const std::string& name,
|
||||
bool approx) const;
|
||||
|
||||
|
||||
const std::vector< shared_ptr<option_description> >& options() const;
|
||||
|
||||
/** Produces a human readable output of 'desc', listing options,
|
||||
their descriptions and allowed parameters. Other options_description
|
||||
instances previously passed to add will be output separately. */
|
||||
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
|
||||
option_description element. */
|
||||
void print(std::ostream& os) const;
|
||||
|
||||
private:
|
||||
typedef std::map<std::string, int>::const_iterator name2index_iterator;
|
||||
typedef std::pair<name2index_iterator, name2index_iterator>
|
||||
approximation_range;
|
||||
|
||||
//approximation_range find_approximation(const std::string& prefix) const;
|
||||
|
||||
std::string m_caption;
|
||||
const unsigned m_line_length;
|
||||
// Data organization is chosen because:
|
||||
// - there could be two names for one option
|
||||
// - option_add_proxy needs to know the last added option
|
||||
std::vector< shared_ptr<option_description> > m_options;
|
||||
|
||||
// Whether the option comes from one of declared groups.
|
||||
#if BOOST_WORKAROUND(BOOST_DINKUMWARE_STDLIB, BOOST_TESTED_AT(313))
|
||||
// vector<bool> is buggy there, see
|
||||
// http://support.microsoft.com/default.aspx?scid=kb;en-us;837698
|
||||
std::vector<char> belong_to_group;
|
||||
#else
|
||||
std::vector<bool> belong_to_group;
|
||||
#endif
|
||||
|
||||
std::vector< shared_ptr<options_description> > groups;
|
||||
|
||||
};
|
||||
|
||||
/** 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) {}
|
||||
};
|
||||
}}
|
||||
|
||||
#endif
|
||||
229
include/boost/program_options/parsers.hpp
Normal file
229
include/boost/program_options/parsers.hpp
Normal file
@@ -0,0 +1,229 @@
|
||||
// Copyright Vladimir Prus 2002-2004.
|
||||
// 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)
|
||||
|
||||
|
||||
#ifndef BOOST_PARSERS_VP_2003_05_19
|
||||
#define BOOST_PARSERS_VP_2003_05_19
|
||||
|
||||
#include <boost/program_options/config.hpp>
|
||||
#include <boost/program_options/option.hpp>
|
||||
#include <boost/program_options/detail/cmdline.hpp>
|
||||
|
||||
#include <boost/function/function1.hpp>
|
||||
|
||||
#include <iosfwd>
|
||||
#include <vector>
|
||||
#include <utility>
|
||||
|
||||
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
|
||||
component to value storage component. This class does not makes
|
||||
much sense itself.
|
||||
*/
|
||||
template<class charT>
|
||||
class basic_parsed_options {
|
||||
public:
|
||||
explicit basic_parsed_options(const options_description* description)
|
||||
: description(description) {}
|
||||
/** 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
|
||||
option_description passed to them, and issues of lifetime are
|
||||
up to the caller. Can be NULL.
|
||||
*/
|
||||
const options_description* description;
|
||||
};
|
||||
|
||||
/** Specialization of basic_parsed_options which:
|
||||
- provides convenient conversion from basic_parsed_options<char>
|
||||
- stores the passed char-based options for later use.
|
||||
*/
|
||||
template<>
|
||||
class BOOST_PROGRAM_OPTIONS_DECL basic_parsed_options<wchar_t> {
|
||||
public:
|
||||
/** Constructs wrapped options from options in UTF8 encoding. */
|
||||
explicit basic_parsed_options(const basic_parsed_options<char>& po);
|
||||
|
||||
std::vector< basic_option<wchar_t> > options;
|
||||
const options_description* description;
|
||||
|
||||
/** Stores UTF8 encoded options that were passed to constructor,
|
||||
to avoid reverse conversion in some cases. */
|
||||
basic_parsed_options<char> utf8_encoded_options;
|
||||
};
|
||||
|
||||
typedef basic_parsed_options<char> parsed_options;
|
||||
typedef basic_parsed_options<wchar_t> wparsed_options;
|
||||
|
||||
/** Augments basic_parsed_options<wchar_t> with conversion from
|
||||
'parsed_options' */
|
||||
|
||||
|
||||
typedef function1<std::pair<std::string, std::string>, const std::string&> ext_parser;
|
||||
|
||||
/** Command line parser.
|
||||
|
||||
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
|
||||
parameters will be hard to use and creating overloads with a smaller
|
||||
nuber of parameters will be confusing.
|
||||
|
||||
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,
|
||||
for charT == char and charT == wchar_t cases.
|
||||
*/
|
||||
template<class charT>
|
||||
class basic_command_line_parser : private detail::cmdline {
|
||||
public:
|
||||
/** Creates a command line parser for the specified arguments
|
||||
list. The 'args' parameter should not include program name.
|
||||
*/
|
||||
basic_command_line_parser(const std::vector<
|
||||
std::basic_string<charT> >& args);
|
||||
/** 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[]);
|
||||
|
||||
/** Sets options descriptions to use. */
|
||||
basic_command_line_parser& options(const options_description& desc);
|
||||
/** Sets positional options description to use. */
|
||||
basic_command_line_parser& positional(
|
||||
const positional_options_description& desc);
|
||||
|
||||
/** Sets the command line style. */
|
||||
basic_command_line_parser& style(int);
|
||||
/** Sets the extra parsers. */
|
||||
basic_command_line_parser& extra_parser(ext_parser);
|
||||
|
||||
/** Parses the options and returns the result of parsing.
|
||||
Throws on error.
|
||||
*/
|
||||
basic_parsed_options<charT> run();
|
||||
|
||||
/** Specifies that unregistered options are allowed and should
|
||||
be passed though. For each command like token that looks
|
||||
like an option but does not contain a recognized name, an
|
||||
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.
|
||||
*/
|
||||
basic_command_line_parser& allow_unregistered();
|
||||
|
||||
using detail::cmdline::style_parser;
|
||||
|
||||
basic_command_line_parser& extra_style_parser(style_parser s);
|
||||
|
||||
private:
|
||||
const options_description* m_desc;
|
||||
};
|
||||
|
||||
typedef basic_command_line_parser<char> command_line_parser;
|
||||
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.
|
||||
*/
|
||||
template<class charT>
|
||||
basic_parsed_options<charT>
|
||||
parse_command_line(int argc, charT* argv[],
|
||||
const options_description&,
|
||||
int style = 0,
|
||||
function1<std::pair<std::string, std::string>,
|
||||
const std::string&> ext
|
||||
= ext_parser());
|
||||
|
||||
/** Parse a config file.
|
||||
*/
|
||||
template<class charT>
|
||||
#if ! BOOST_WORKAROUND(__ICL, BOOST_TESTED_AT(700))
|
||||
BOOST_PROGRAM_OPTIONS_DECL
|
||||
#endif
|
||||
basic_parsed_options<charT>
|
||||
parse_config_file(std::basic_istream<charT>&, const options_description&,
|
||||
bool allow_unregistered = false);
|
||||
|
||||
/** Controls if the 'collect_unregistered' function should
|
||||
include positional options, or not. */
|
||||
enum collect_unrecognized_mode
|
||||
{ include_positional, exclude_positional };
|
||||
|
||||
/** Collects the original tokens for all named options with
|
||||
'unregistered' flag set. If 'mode' is 'include_positional'
|
||||
also collects all positional options.
|
||||
Returns the vector of origianl tokens for all collected
|
||||
options.
|
||||
*/
|
||||
template<class charT>
|
||||
std::vector< std::basic_string<charT> >
|
||||
collect_unrecognized(const std::vector< basic_option<charT> >& options,
|
||||
enum collect_unrecognized_mode mode);
|
||||
|
||||
/** 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.
|
||||
|
||||
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&,
|
||||
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
|
||||
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
|
||||
functions when second argument is of 'char*' type. There's implicit
|
||||
conversion to both function1 and string.
|
||||
*/
|
||||
BOOST_PROGRAM_OPTIONS_DECL parsed_options
|
||||
parse_environment(const options_description&, const char* prefix);
|
||||
|
||||
#ifdef _WIN32
|
||||
/** Parses the char* string which is passed to WinMain function on
|
||||
windows. This function is provided for convenience, and because it's
|
||||
not clear how to portably access split command line string from
|
||||
runtime library and if it always exists.
|
||||
This function is available only on Windows.
|
||||
*/
|
||||
BOOST_PROGRAM_OPTIONS_DECL std::vector<std::string>
|
||||
split_winmain(const std::string& cmdline);
|
||||
|
||||
#ifndef BOOST_NO_STD_WSTRING
|
||||
/** @overload */
|
||||
BOOST_PROGRAM_OPTIONS_DECL std::vector<std::wstring>
|
||||
split_winmain(const std::wstring& cmdline);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
}}
|
||||
|
||||
#undef DECL
|
||||
|
||||
#include "boost/program_options/detail/parsers.hpp"
|
||||
|
||||
#endif
|
||||
65
include/boost/program_options/positional_options.hpp
Normal file
65
include/boost/program_options/positional_options.hpp
Normal file
@@ -0,0 +1,65 @@
|
||||
// Copyright Vladimir Prus 2004.
|
||||
// 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)
|
||||
|
||||
#ifndef BOOST_PROGRAM_OPTIONS_POSITIONAL_OPTIONS_VP_2004_03_02
|
||||
#define BOOST_PROGRAM_OPTIONS_POSITIONAL_OPTIONS_VP_2004_03_02
|
||||
|
||||
#include <boost/program_options/config.hpp>
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
namespace boost { namespace program_options {
|
||||
|
||||
/** Describes positional options.
|
||||
|
||||
The class allows to guess option names for positional options, which
|
||||
are specified on the command line and are identified by the position.
|
||||
The class uses the information provided by the user to associate a name
|
||||
with every positional option, or tell that no name is known.
|
||||
|
||||
The primary assumption is that only the relative order of the
|
||||
positional options themselves matters, and that any interleaving
|
||||
ordinary options don't affect interpretation of positional options.
|
||||
|
||||
The user initializes the class by specifying that first N positional
|
||||
options should be given the name X1, following M options should be given
|
||||
the name X2 and so on.
|
||||
*/
|
||||
class BOOST_PROGRAM_OPTIONS_DECL positional_options_description {
|
||||
public:
|
||||
positional_options_description();
|
||||
|
||||
/** Species that up to 'max_count' next positional options
|
||||
should be given the 'name'. The value of '-1' means 'unlimited'.
|
||||
No calls to 'add' can be made after call with 'max_value' equal to
|
||||
'-1'.
|
||||
*/
|
||||
positional_options_description&
|
||||
add(const char* name, int max_count);
|
||||
|
||||
/** Returns the maximum number of positional options that can
|
||||
be present. Can return numeric_limits<unsigned>::max() to
|
||||
indicate unlimited number. */
|
||||
unsigned max_total_count() const;
|
||||
|
||||
/** Returns the name that should be associated with positional
|
||||
options at 'position'.
|
||||
Precondition: position < max_total_count()
|
||||
*/
|
||||
const std::string& name_for_position(unsigned position) const;
|
||||
|
||||
private:
|
||||
// List of names corresponding to the positions. If the number of
|
||||
// positions is unlimited, then the last name is stored in
|
||||
// m_trailing;
|
||||
std::vector<std::string> m_names;
|
||||
std::string m_trailing;
|
||||
};
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
|
||||
390
include/boost/program_options/value_semantic.hpp
Normal file
390
include/boost/program_options/value_semantic.hpp
Normal file
@@ -0,0 +1,390 @@
|
||||
// Copyright Vladimir Prus 2004.
|
||||
// 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)
|
||||
|
||||
#ifndef BOOST_VALUE_SEMANTIC_HPP_VP_2004_02_24
|
||||
#define BOOST_VALUE_SEMANTIC_HPP_VP_2004_02_24
|
||||
|
||||
#include <boost/program_options/config.hpp>
|
||||
#include <boost/program_options/errors.hpp>
|
||||
|
||||
#include <boost/any.hpp>
|
||||
#include <boost/function/function1.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <typeinfo>
|
||||
|
||||
namespace boost { namespace program_options {
|
||||
|
||||
/** Class which specifies how the option's value is to be parsed
|
||||
and converted into C++ types.
|
||||
*/
|
||||
class BOOST_PROGRAM_OPTIONS_DECL value_semantic {
|
||||
public:
|
||||
/** Returns the name of the option. The name is only meaningful
|
||||
for automatic help message.
|
||||
*/
|
||||
virtual std::string name() const = 0;
|
||||
|
||||
/** The minimum number of tokens for this option that
|
||||
should be present on the command line. */
|
||||
virtual unsigned min_tokens() const = 0;
|
||||
|
||||
/** The maximum number of tokens for this option that
|
||||
should be present on the command line. */
|
||||
virtual unsigned max_tokens() 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.
|
||||
*/
|
||||
virtual bool is_composing() 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
|
||||
option is specified more than once.
|
||||
*/
|
||||
virtual void parse(boost::any& value_store,
|
||||
const std::vector<std::string>& new_tokens,
|
||||
bool utf8) const
|
||||
= 0;
|
||||
|
||||
/** Called to assign default value to 'value_store'. Returns
|
||||
true if default value is assigned, and false if no default
|
||||
value exists. */
|
||||
virtual bool apply_default(boost::any& value_store) const = 0;
|
||||
|
||||
/** Called when final value of an option is determined.
|
||||
*/
|
||||
virtual void notify(const boost::any& value_store) const = 0;
|
||||
|
||||
virtual ~value_semantic() {}
|
||||
};
|
||||
|
||||
/** Helper class which perform necessary character conversions in the
|
||||
'parse' method and forwards the data further.
|
||||
*/
|
||||
template<class charT>
|
||||
class value_semantic_codecvt_helper {
|
||||
// Nothing here. Specializations to follow.
|
||||
};
|
||||
|
||||
/** Helper conversion class for values that accept ascii
|
||||
strings as input.
|
||||
Overrides the 'parse' method and defines new 'xparse'
|
||||
method taking std::string. Depending on whether input
|
||||
to parse is ascii or UTF8, will pass it to xparse unmodified,
|
||||
or with UTF8->ascii conversion.
|
||||
*/
|
||||
template<>
|
||||
class BOOST_PROGRAM_OPTIONS_DECL
|
||||
value_semantic_codecvt_helper<char> : public value_semantic {
|
||||
private: // base overrides
|
||||
void parse(boost::any& value_store,
|
||||
const std::vector<std::string>& new_tokens,
|
||||
bool utf8) const;
|
||||
protected: // interface for derived classes.
|
||||
virtual void xparse(boost::any& value_store,
|
||||
const std::vector<std::string>& new_tokens)
|
||||
const = 0;
|
||||
};
|
||||
|
||||
/** Helper conversion class for values that accept ascii
|
||||
strings as input.
|
||||
Overrides the 'parse' method and defines new 'xparse'
|
||||
method taking std::wstring. Depending on whether input
|
||||
to parse is ascii or UTF8, will recode input to Unicode, or
|
||||
pass it unmodified.
|
||||
*/
|
||||
template<>
|
||||
class BOOST_PROGRAM_OPTIONS_DECL
|
||||
value_semantic_codecvt_helper<wchar_t> : public value_semantic {
|
||||
private: // base overrides
|
||||
void parse(boost::any& value_store,
|
||||
const std::vector<std::string>& new_tokens,
|
||||
bool utf8) const;
|
||||
protected: // interface for derived classes.
|
||||
#if !defined(BOOST_NO_STD_WSTRING)
|
||||
virtual void xparse(boost::any& value_store,
|
||||
const std::vector<std::wstring>& new_tokens)
|
||||
const = 0;
|
||||
#endif
|
||||
};
|
||||
|
||||
/** Class which specifies a simple handling of a value: the value will
|
||||
have string type and only one token is allowed. */
|
||||
class BOOST_PROGRAM_OPTIONS_DECL
|
||||
untyped_value : public value_semantic_codecvt_helper<char> {
|
||||
public:
|
||||
untyped_value(bool zero_tokens = false)
|
||||
: m_zero_tokens(zero_tokens)
|
||||
{}
|
||||
|
||||
std::string name() const;
|
||||
|
||||
unsigned min_tokens() const;
|
||||
unsigned max_tokens() const;
|
||||
|
||||
bool is_composing() const { return false; }
|
||||
|
||||
/** If 'value_store' is already initialized, or new_tokens
|
||||
has more than one elements, throws. Otherwise, assigns
|
||||
the first string from 'new_tokens' to 'value_store', without
|
||||
any modifications.
|
||||
*/
|
||||
void xparse(boost::any& value_store,
|
||||
const std::vector<std::string>& new_tokens) const;
|
||||
|
||||
/** Does nothing. */
|
||||
bool apply_default(boost::any&) const { return false; }
|
||||
|
||||
/** Does nothing. */
|
||||
void notify(const boost::any&) const {}
|
||||
private:
|
||||
bool m_zero_tokens;
|
||||
};
|
||||
|
||||
/** 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
|
||||
type can be dynamic_cast-ed to typed_value_base. If conversion
|
||||
succeeds, the 'type' method can be called.
|
||||
*/
|
||||
class typed_value_base
|
||||
{
|
||||
public:
|
||||
// Returns the type of the value described by this
|
||||
// object.
|
||||
virtual const std::type_info& value_type() const = 0;
|
||||
// Not really needed, since deletion from this
|
||||
// class is silly, but just in case.
|
||||
virtual ~typed_value_base() {}
|
||||
};
|
||||
|
||||
|
||||
/** 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
|
||||
{
|
||||
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)
|
||||
{}
|
||||
|
||||
/** Specifies default value, which will be used
|
||||
if none is explicitly specified. The type 'T' should
|
||||
provide operator<< for ostream.
|
||||
*/
|
||||
typed_value* default_value(const T& v)
|
||||
{
|
||||
m_default_value = boost::any(v);
|
||||
m_default_value_as_text = boost::lexical_cast<std::string>(v);
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Specifies default value, which will be used
|
||||
if none is explicitly specified. Unlike the above overload,
|
||||
the type 'T' need not provide operator<< for ostream,
|
||||
but textual representation of default value must be provided
|
||||
by the user.
|
||||
*/
|
||||
typed_value* default_value(const T& v, const std::string& textual)
|
||||
{
|
||||
m_default_value = boost::any(v);
|
||||
m_default_value_as_text = textual;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Specifies an implicit value, which will be used
|
||||
if the option is given, but without an adjacent value.
|
||||
Using this implies that an explicit value is optional, but if
|
||||
given, must be strictly adjacent to the option, i.e.: '-ovalue'
|
||||
or '--option=value'. Giving '-o' or '--option' will cause the
|
||||
implicit value to be applied.
|
||||
*/
|
||||
typed_value* implicit_value(const T &v)
|
||||
{
|
||||
m_implicit_value = boost::any(v);
|
||||
m_implicit_value_as_text =
|
||||
boost::lexical_cast<std::string>(v);
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Specifies an implicit value, which will be used
|
||||
if the option is given, but without an adjacent value.
|
||||
Using this implies that an explicit value is optional, but if
|
||||
given, must be strictly adjacent to the option, i.e.: '-ovalue'
|
||||
or '--option=value'. Giving '-o' or '--option' will cause the
|
||||
implicit value to be applied.
|
||||
Unlike the above overload, the type 'T' need not provide
|
||||
operator<< for ostream, but textual representation of default
|
||||
value must be provided by the user.
|
||||
*/
|
||||
typed_value* implicit_value(const T &v, const std::string& textual)
|
||||
{
|
||||
m_implicit_value = boost::any(v);
|
||||
m_implicit_value_as_text = textual;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Specifies a function to be called when the final value
|
||||
is determined. */
|
||||
typed_value* notifier(function1<void, const T&> f)
|
||||
{
|
||||
m_notifier = f;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Specifies that the value is composing. See the 'is_composing'
|
||||
method for explanation.
|
||||
*/
|
||||
typed_value* composing()
|
||||
{
|
||||
m_composing = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Specifies that the value can span multiple tokens. */
|
||||
typed_value* multitoken()
|
||||
{
|
||||
m_multitoken = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
typed_value* zero_tokens()
|
||||
{
|
||||
m_zero_tokens = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public: // value semantic overrides
|
||||
|
||||
std::string name() const;
|
||||
|
||||
bool is_composing() const { return m_composing; }
|
||||
|
||||
unsigned min_tokens() const
|
||||
{
|
||||
if (m_zero_tokens || !m_implicit_value.empty()) {
|
||||
return 0;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned max_tokens() const {
|
||||
if (m_multitoken) {
|
||||
return 32000;
|
||||
} else if (m_zero_tokens) {
|
||||
return 0;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** Creates an instance of the 'validator' class and calls
|
||||
its operator() to perform the actual conversion. */
|
||||
void xparse(boost::any& value_store,
|
||||
const std::vector< std::basic_string<charT> >& new_tokens)
|
||||
const;
|
||||
|
||||
/** If default value was specified via previous call to
|
||||
'default_value', stores that value into 'value_store'.
|
||||
Returns true if default value was stored.
|
||||
*/
|
||||
virtual bool apply_default(boost::any& value_store) const
|
||||
{
|
||||
if (m_default_value.empty()) {
|
||||
return false;
|
||||
} else {
|
||||
value_store = m_default_value;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/** If an address of variable to store value was specified
|
||||
when creating *this, stores the value there. Otherwise,
|
||||
does nothing. */
|
||||
void notify(const boost::any& value_store) const;
|
||||
|
||||
public: // typed_value_base overrides
|
||||
|
||||
const std::type_info& value_type() const
|
||||
{
|
||||
return typeid(T);
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
T* m_store_to;
|
||||
|
||||
// Default value is stored as boost::any and not
|
||||
// as boost::optional to avoid unnecessary instantiations.
|
||||
boost::any m_default_value;
|
||||
std::string m_default_value_as_text;
|
||||
boost::any m_implicit_value;
|
||||
std::string m_implicit_value_as_text;
|
||||
bool m_composing, m_implicit, m_multitoken, m_zero_tokens;
|
||||
boost::function1<void, const T&> m_notifier;
|
||||
};
|
||||
|
||||
|
||||
/** Creates a typed_value<T> instance. This function is the primary
|
||||
method to create value_semantic instance for a specific type, which
|
||||
can later be passed to 'option_description' constructor.
|
||||
The second overload is used when it's additionally desired to store the
|
||||
value of option into program variable.
|
||||
*/
|
||||
template<class T>
|
||||
typed_value<T>*
|
||||
value();
|
||||
|
||||
/** @overload
|
||||
*/
|
||||
template<class T>
|
||||
typed_value<T>*
|
||||
value(T* v);
|
||||
|
||||
/** Creates a typed_value<T> instance. This function is the primary
|
||||
method to create value_semantic instance for a specific type, which
|
||||
can later be passed to 'option_description' constructor.
|
||||
*/
|
||||
template<class T>
|
||||
typed_value<T, wchar_t>*
|
||||
wvalue();
|
||||
|
||||
/** @overload
|
||||
*/
|
||||
template<class T>
|
||||
typed_value<T, wchar_t>*
|
||||
wvalue(T* v);
|
||||
|
||||
/** Works the same way as the 'value<bool>' function, but the created
|
||||
value_semantic won't accept any explicit value. So, if the option
|
||||
is present on the command line, the value will be 'true'.
|
||||
*/
|
||||
BOOST_PROGRAM_OPTIONS_DECL typed_value<bool>*
|
||||
bool_switch();
|
||||
|
||||
/** @overload
|
||||
*/
|
||||
BOOST_PROGRAM_OPTIONS_DECL typed_value<bool>*
|
||||
bool_switch(bool* v);
|
||||
|
||||
}}
|
||||
|
||||
#include "boost/program_options/detail/value_semantic.hpp"
|
||||
|
||||
#endif
|
||||
|
||||
199
include/boost/program_options/variables_map.hpp
Normal file
199
include/boost/program_options/variables_map.hpp
Normal file
@@ -0,0 +1,199 @@
|
||||
// Copyright Vladimir Prus 2002-2004.
|
||||
// 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)
|
||||
|
||||
|
||||
#ifndef BOOST_VARIABLES_MAP_VP_2003_05_19
|
||||
#define BOOST_VARIABLES_MAP_VP_2003_05_19
|
||||
|
||||
#include <boost/program_options/config.hpp>
|
||||
|
||||
#include <boost/any.hpp>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <set>
|
||||
|
||||
namespace boost { namespace program_options {
|
||||
|
||||
template<class charT>
|
||||
class basic_parsed_options;
|
||||
|
||||
class value_semantic;
|
||||
class variables_map;
|
||||
|
||||
// forward declaration
|
||||
|
||||
/** 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.
|
||||
*/
|
||||
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'.
|
||||
If 'm' already has a non-defaulted value of an option, that 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,
|
||||
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
|
||||
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)
|
||||
{}
|
||||
|
||||
/** If stored value if of type T, returns that value. Otherwise,
|
||||
throws boost::bad_any_cast exception. */
|
||||
template<class T>
|
||||
const T& as() const {
|
||||
return boost::any_cast<const T&>(v);
|
||||
}
|
||||
/** @overload */
|
||||
template<class T>
|
||||
T& as() {
|
||||
return boost::any_cast<T&>(v);
|
||||
}
|
||||
|
||||
/// Returns true if no value is stored.
|
||||
bool empty() const;
|
||||
/** Returns true if the value was not explicitly
|
||||
given, but has default value. */
|
||||
bool defaulted() const;
|
||||
/** Returns the contained value. */
|
||||
const boost::any& value() const;
|
||||
|
||||
/** Returns the contained value. */
|
||||
boost::any& value();
|
||||
private:
|
||||
boost::any v;
|
||||
bool m_defaulted;
|
||||
// Internal reference to value semantic. We need to run
|
||||
// notifications when *final* values of options are known, and
|
||||
// they are known only after all sources are stored. By that
|
||||
// time options_description for the first source might not
|
||||
// be easily accessible, so we need to store semantic here.
|
||||
shared_ptr<const value_semantic> m_value_semantic;
|
||||
|
||||
friend BOOST_PROGRAM_OPTIONS_DECL
|
||||
void store(const basic_parsed_options<char>& options,
|
||||
variables_map& m, bool);
|
||||
friend BOOST_PROGRAM_OPTIONS_DECL void notify(variables_map& m);
|
||||
};
|
||||
|
||||
/** Implements string->string mapping with convenient value casting
|
||||
facilities. */
|
||||
class BOOST_PROGRAM_OPTIONS_DECL abstract_variables_map {
|
||||
public:
|
||||
abstract_variables_map();
|
||||
abstract_variables_map(const abstract_variables_map* next);
|
||||
|
||||
virtual ~abstract_variables_map() {}
|
||||
|
||||
/** Obtains the value of variable 'name', from *this and
|
||||
possibly from the chain of variable maps.
|
||||
|
||||
- if there's no value in *this.
|
||||
- if there's next variable map, returns value from it
|
||||
- otherwise, returns empty value
|
||||
|
||||
- if there's defaulted value
|
||||
- if there's next varaible map, which has a non-defauled
|
||||
value, return that
|
||||
- otherwise, return value from *this
|
||||
|
||||
- if there's a non-defauled value, returns it.
|
||||
*/
|
||||
const variable_value& operator[](const std::string& name) const;
|
||||
|
||||
/** Sets next variable map, which will be used to find
|
||||
variables not found in *this. */
|
||||
void next(abstract_variables_map* next);
|
||||
|
||||
private:
|
||||
/** Returns value of variable 'name' stored in *this, or
|
||||
empty value otherwise. */
|
||||
virtual const variable_value& get(const std::string& name) const = 0;
|
||||
|
||||
const abstract_variables_map* m_next;
|
||||
};
|
||||
|
||||
/** 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.
|
||||
*/
|
||||
class BOOST_PROGRAM_OPTIONS_DECL variables_map : public abstract_variables_map,
|
||||
public std::map<std::string, variable_value>
|
||||
{
|
||||
public:
|
||||
variables_map();
|
||||
variables_map(const abstract_variables_map* next);
|
||||
|
||||
// Resolve conflict between inherited operators.
|
||||
const variable_value& operator[](const std::string& name) const
|
||||
{ return abstract_variables_map::operator[](name); }
|
||||
|
||||
private:
|
||||
/** Implementation of abstract_variables_map::get
|
||||
which does 'find' in *this. */
|
||||
const variable_value& get(const std::string& name) const;
|
||||
|
||||
/** 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,
|
||||
variables_map& xm,
|
||||
bool utf8);
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Templates/inlines
|
||||
*/
|
||||
|
||||
inline bool
|
||||
variable_value::empty() const
|
||||
{
|
||||
return v.empty();
|
||||
}
|
||||
|
||||
inline bool
|
||||
variable_value::defaulted() const
|
||||
{
|
||||
return m_defaulted;
|
||||
}
|
||||
|
||||
inline
|
||||
const boost::any&
|
||||
variable_value::value() const
|
||||
{
|
||||
return v;
|
||||
}
|
||||
|
||||
inline
|
||||
boost::any&
|
||||
variable_value::value()
|
||||
{
|
||||
return v;
|
||||
}
|
||||
|
||||
}}
|
||||
|
||||
#endif
|
||||
19
include/boost/program_options/version.hpp
Normal file
19
include/boost/program_options/version.hpp
Normal file
@@ -0,0 +1,19 @@
|
||||
// Copyright Vladimir Prus 2004.
|
||||
// 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)
|
||||
|
||||
#ifndef BOOST_PROGRAM_OPTIONS_VERSION_HPP_VP_2004_04_05
|
||||
#define BOOST_PROGRAM_OPTIONS_VERSION_HPP_VP_2004_04_05
|
||||
|
||||
/** The version of the source interface.
|
||||
The value will be incremented whenever a change is made which might
|
||||
cause compilation errors for existing code.
|
||||
*/
|
||||
#ifdef BOOST_PROGRAM_OPTIONS_VERSION
|
||||
#error BOOST_PROGRAM_OPTIONS_VERSION already defined
|
||||
#endif
|
||||
#define BOOST_PROGRAM_OPTIONS_VERSION 2
|
||||
|
||||
|
||||
#endif
|
||||
@@ -4,6 +4,11 @@
|
||||
</head>
|
||||
<body>
|
||||
Automatic redirection failed, please go to
|
||||
<a href="../../doc/html/program_options.html">../../doc/html/program_options.html</a>
|
||||
<a href="../../doc/html/program_options.html">../../doc/html/program_options.html</a>
|
||||
<hr>
|
||||
<p>© Copyright Beman Dawes, 2001</p>
|
||||
<p>Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
file <a href="../../LICENSE_1_0.txt">LICENSE_1_0.txt</a> or copy
|
||||
at <a href="http://www.boost.org/LICENSE_1_0.txt">www.boost.org/LICENSE_1_0.txt</a>)</p>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
1032
src/cmdline.cpp
1032
src/cmdline.cpp
File diff suppressed because it is too large
Load Diff
@@ -10,6 +10,7 @@
|
||||
#include <boost/program_options/detail/config_file.hpp>
|
||||
#include <boost/program_options/errors.hpp>
|
||||
#include <boost/program_options/detail/convert.hpp>
|
||||
#include <boost/throw_exception.hpp>
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
@@ -20,8 +21,10 @@ namespace boost { namespace program_options { namespace detail {
|
||||
using namespace std;
|
||||
|
||||
common_config_file_iterator::common_config_file_iterator(
|
||||
const std::set<std::string>& allowed_options)
|
||||
: allowed_options(allowed_options)
|
||||
const std::set<std::string>& allowed_options,
|
||||
bool allow_unregistered)
|
||||
: allowed_options(allowed_options),
|
||||
m_allow_unregistered(allow_unregistered)
|
||||
{
|
||||
for(std::set<std::string>::const_iterator i = allowed_options.begin();
|
||||
i != allowed_options.end();
|
||||
@@ -54,7 +57,7 @@ namespace boost { namespace program_options { namespace detail {
|
||||
bad_prefixes = true;
|
||||
}
|
||||
if (bad_prefixes)
|
||||
throw error("bad prefixes");
|
||||
boost::throw_exception(error("bad prefixes"));
|
||||
allowed_prefixes.insert(s);
|
||||
}
|
||||
}
|
||||
@@ -99,20 +102,22 @@ namespace boost { namespace program_options { namespace detail {
|
||||
string name = m_prefix + trim_ws(s.substr(0, n));
|
||||
string value = trim_ws(s.substr(n+1));
|
||||
|
||||
if (!allowed_option(name))
|
||||
throw unknown_option(name);
|
||||
bool registered = allowed_option(name);
|
||||
if (!registered && !m_allow_unregistered)
|
||||
boost::throw_exception(unknown_option(name));
|
||||
|
||||
if (value.empty())
|
||||
throw invalid_syntax(s, "no value given");
|
||||
boost::throw_exception(invalid_syntax(s, "no value given"));
|
||||
|
||||
found = true;
|
||||
this->value().string_key = name;
|
||||
this->value().value.clear();
|
||||
this->value().value.push_back(value);
|
||||
this->value().unregistered = !registered;
|
||||
break;
|
||||
|
||||
} else {
|
||||
throw invalid_syntax(s, "unrecognized line");
|
||||
boost::throw_exception(invalid_syntax(s, "unrecognized line"));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -136,9 +141,8 @@ namespace boost { namespace program_options { namespace detail {
|
||||
return false;
|
||||
}
|
||||
|
||||
// On Metrowerks, the function is defined inline.
|
||||
|
||||
#if BOOST_WORKAROUND(__COMO_VERSION__, BOOST_TESTED_AT(4303))
|
||||
#if BOOST_WORKAROUND(__COMO_VERSION__, BOOST_TESTED_AT(4303)) || \
|
||||
(defined(__sgi) && BOOST_WORKAROUND(_COMPILER_VERSION, BOOST_TESTED_AT(741)))
|
||||
template<>
|
||||
bool
|
||||
basic_config_file_iterator<wchar_t>::getline(std::string& s)
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include <boost/program_options/config.hpp>
|
||||
#include <boost/program_options/detail/convert.hpp>
|
||||
#include <boost/program_options/detail/utf8_codecvt_facet.hpp>
|
||||
#include <boost/throw_exception.hpp>
|
||||
|
||||
#include <boost/bind.hpp>
|
||||
|
||||
@@ -62,14 +63,16 @@ namespace boost { namespace detail {
|
||||
fun(state, from, from_end, from, buffer, to_end, to_next);
|
||||
|
||||
if (r == std::codecvt_base::error)
|
||||
throw std::logic_error("character conversion failed");
|
||||
boost::throw_exception(
|
||||
std::logic_error("character conversion failed"));
|
||||
// 'partial' is not an error, it just means not all source
|
||||
// characters were converted. However, we need to check that at
|
||||
// least one new target character was produced. If not, it means
|
||||
// the source data is incomplete, and since we don't have extra
|
||||
// data to add to source, it's error.
|
||||
if (to_next == buffer)
|
||||
throw std::logic_error("character conversion failed");
|
||||
boost::throw_exception(
|
||||
std::logic_error("character conversion failed"));
|
||||
|
||||
// Add converted characters
|
||||
result.append(buffer, to_next);
|
||||
@@ -106,7 +109,7 @@ namespace boost {
|
||||
|
||||
|
||||
namespace {
|
||||
boost::program_options::detail::utf8_codecvt_facet<wchar_t, char>
|
||||
boost::program_options::detail::utf8_codecvt_facet
|
||||
utf8_facet;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
// Copyright Vladimir Prus 2002-2004.
|
||||
// Copyright Bertolt Mildner 2004.
|
||||
// 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)
|
||||
@@ -11,15 +12,18 @@
|
||||
// should move that to a separate headers.
|
||||
#include <boost/program_options/parsers.hpp>
|
||||
|
||||
#include <boost/lexical_cast.hpp>
|
||||
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <boost/tokenizer.hpp>
|
||||
#include <boost/detail/workaround.hpp>
|
||||
#include <boost/throw_exception.hpp>
|
||||
|
||||
#include <cassert>
|
||||
#include <climits>
|
||||
#include <cstring>
|
||||
#include <cstdarg>
|
||||
#include <sstream>
|
||||
#include <iterator>
|
||||
using namespace std;
|
||||
|
||||
namespace boost { namespace program_options {
|
||||
@@ -33,7 +37,7 @@ namespace boost { namespace program_options {
|
||||
const value_semantic* s)
|
||||
: m_value_semantic(s)
|
||||
{
|
||||
this->name(name);
|
||||
this->set_name(name);
|
||||
}
|
||||
|
||||
|
||||
@@ -43,32 +47,64 @@ namespace boost { namespace program_options {
|
||||
const char* description)
|
||||
: m_description(description), m_value_semantic(s)
|
||||
{
|
||||
this->name(name);
|
||||
this->set_name(name);
|
||||
}
|
||||
|
||||
option_description::~option_description()
|
||||
{
|
||||
}
|
||||
|
||||
option_description&
|
||||
option_description::name(const char* _name)
|
||||
option_description::match_result
|
||||
option_description::match(const std::string& option, bool approx) const
|
||||
{
|
||||
std::string name(_name);
|
||||
string::size_type n = name.find(',');
|
||||
if (n != string::npos) {
|
||||
assert(n == name.size()-2);
|
||||
m_long_name = name.substr(0, n);
|
||||
m_short_name = name.substr(n+1,1);
|
||||
} else {
|
||||
m_long_name = name;
|
||||
match_result result = no_match;
|
||||
if (!m_long_name.empty()) {
|
||||
|
||||
if (*m_long_name.rbegin() == '*')
|
||||
{
|
||||
// The name ends with '*'. Any specified name with the given
|
||||
// prefix is OK.
|
||||
if (option.find(m_long_name.substr(0, m_long_name.length()-1))
|
||||
== 0)
|
||||
result = approximate_match;
|
||||
}
|
||||
|
||||
if (approx)
|
||||
{
|
||||
if (m_long_name.find(option) == 0)
|
||||
if (m_long_name == option)
|
||||
result = full_match;
|
||||
else
|
||||
result = approximate_match;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_long_name == option)
|
||||
result = full_match;
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
|
||||
if (m_short_name == option)
|
||||
result = full_match;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
const std::string&
|
||||
option_description::short_name() const
|
||||
{
|
||||
return m_short_name;
|
||||
const std::string&
|
||||
option_description::key(const std::string& option) const
|
||||
{
|
||||
if (!m_long_name.empty())
|
||||
if (m_long_name.find('*') != string::npos)
|
||||
// The '*' character means we're long_name
|
||||
// matches only part of the input. So, returning
|
||||
// long name will remove some of the information,
|
||||
// and we have to return the option as specified
|
||||
// in the source.
|
||||
return option;
|
||||
else
|
||||
return m_long_name;
|
||||
else
|
||||
return m_short_name;
|
||||
}
|
||||
|
||||
const std::string&
|
||||
@@ -77,6 +113,21 @@ namespace boost { namespace program_options {
|
||||
return m_long_name;
|
||||
}
|
||||
|
||||
option_description&
|
||||
option_description::set_name(const char* _name)
|
||||
{
|
||||
std::string name(_name);
|
||||
string::size_type n = name.find(',');
|
||||
if (n != string::npos) {
|
||||
assert(n == name.size()-2);
|
||||
m_long_name = name.substr(0, n);
|
||||
m_short_name = '-' + name.substr(n+1,1);
|
||||
} else {
|
||||
m_long_name = name;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
const std::string&
|
||||
option_description::description() const
|
||||
{
|
||||
@@ -92,17 +143,17 @@ namespace boost { namespace program_options {
|
||||
std::string
|
||||
option_description::format_name() const
|
||||
{
|
||||
if (!short_name().empty())
|
||||
return string("-").append(short_name()).append(" [ --").
|
||||
append(long_name()).append(" ]");
|
||||
if (!m_short_name.empty())
|
||||
return string(m_short_name).append(" [ --").
|
||||
append(m_long_name).append(" ]");
|
||||
else
|
||||
return string("--").append(long_name());
|
||||
return string("--").append(m_long_name);
|
||||
}
|
||||
|
||||
std::string
|
||||
option_description::format_parameter() const
|
||||
{
|
||||
if (!m_value_semantic->is_zero_tokens())
|
||||
if (m_value_semantic->max_tokens() != 0)
|
||||
return m_value_semantic->name();
|
||||
else
|
||||
return "";
|
||||
@@ -150,30 +201,21 @@ namespace boost { namespace program_options {
|
||||
return *this;
|
||||
}
|
||||
|
||||
options_description::options_description()
|
||||
const unsigned options_description::m_default_line_length = 80;
|
||||
|
||||
options_description::options_description(unsigned line_length)
|
||||
: m_line_length(line_length)
|
||||
{}
|
||||
|
||||
options_description::options_description(const string& caption)
|
||||
: m_caption(caption)
|
||||
options_description::options_description(const string& caption,
|
||||
unsigned line_length)
|
||||
: m_caption(caption), m_line_length(line_length)
|
||||
{}
|
||||
|
||||
void
|
||||
options_description::add(shared_ptr<option_description> desc)
|
||||
{
|
||||
const string& s = desc->short_name();
|
||||
const string& l = desc->long_name();
|
||||
assert(!s.empty() || !l.empty());
|
||||
if (!s.empty())
|
||||
if (name2index.count("-" + s) != 0)
|
||||
throw duplicate_option_error("Short name '" + s + "' is already present");
|
||||
else
|
||||
name2index["-" + s] = options.size();
|
||||
if (!l.empty())
|
||||
if (name2index.count(s) != 0)
|
||||
throw duplicate_option_error("Long name '" + s + "' is already present");
|
||||
else
|
||||
name2index[l] = options.size();
|
||||
options.push_back(desc);
|
||||
m_options.push_back(desc);
|
||||
belong_to_group.push_back(false);
|
||||
}
|
||||
|
||||
@@ -183,8 +225,8 @@ namespace boost { namespace program_options {
|
||||
shared_ptr<options_description> d(new options_description(desc));
|
||||
groups.push_back(d);
|
||||
|
||||
for (size_t i = 0; i < desc.options.size(); ++i) {
|
||||
add(desc.options[i]);
|
||||
for (size_t i = 0; i < desc.m_options.size(); ++i) {
|
||||
add(desc.m_options[i]);
|
||||
belong_to_group.back() = true;
|
||||
}
|
||||
|
||||
@@ -197,75 +239,63 @@ namespace boost { namespace program_options {
|
||||
return options_description_easy_init(this);
|
||||
}
|
||||
|
||||
unsigned
|
||||
options_description::count(const std::string& name) const
|
||||
{
|
||||
return name2index.count(name);
|
||||
}
|
||||
|
||||
unsigned
|
||||
options_description::count_approx(const std::string& prefix) const
|
||||
{
|
||||
approximation_range er = find_approximation(prefix);
|
||||
return distance(er.first, er.second);
|
||||
}
|
||||
|
||||
const option_description&
|
||||
options_description::find(const std::string& name) const
|
||||
options_description::find(const std::string& name, bool approx) const
|
||||
{
|
||||
assert(this->count(name) != 0);
|
||||
return *options[name2index.find(name)->second];
|
||||
const option_description* d = find_nothrow(name, approx);
|
||||
if (!d)
|
||||
boost::throw_exception(unknown_option(name));
|
||||
return *d;
|
||||
}
|
||||
|
||||
const option_description&
|
||||
options_description::find_approx(const std::string& prefix) const
|
||||
const std::vector< shared_ptr<option_description> >&
|
||||
options_description::options() const
|
||||
{
|
||||
approximation_range er = find_approximation(prefix);
|
||||
assert(distance(er.first, er.second) == 1);
|
||||
return *options[er.first->second];
|
||||
return m_options;
|
||||
}
|
||||
|
||||
std::set<std::string>
|
||||
options_description::keys() const
|
||||
const option_description*
|
||||
options_description::find_nothrow(const std::string& name,
|
||||
bool approx) const
|
||||
{
|
||||
set<string> result;
|
||||
for (map<string, int>::const_iterator i = name2index.begin();
|
||||
i != name2index.end();
|
||||
++i)
|
||||
result.insert(i->first);
|
||||
return result;
|
||||
}
|
||||
shared_ptr<option_description> found;
|
||||
vector<string> approximate_matches;
|
||||
// We use linear search because matching specified option
|
||||
// name with the declared option name need to take care about
|
||||
// case sensitivity and trailing '*' and so we can't use simple map.
|
||||
for(unsigned i = 0; i < m_options.size(); ++i)
|
||||
{
|
||||
option_description::match_result r =
|
||||
m_options[i]->match(name, approx);
|
||||
|
||||
std::set<std::string>
|
||||
options_description::primary_keys() const
|
||||
{
|
||||
set<string> result;
|
||||
for (size_t i = 0; i < options.size(); ++i)
|
||||
if (options[i]->long_name().empty())
|
||||
result.insert("-" + options[i]->short_name());
|
||||
else
|
||||
result.insert(options[i]->long_name());
|
||||
return result;
|
||||
}
|
||||
if (r == option_description::no_match)
|
||||
continue;
|
||||
|
||||
std::set<std::string>
|
||||
options_description::approximations(const std::string& prefix) const
|
||||
{
|
||||
approximation_range er = find_approximation(prefix);
|
||||
set<string> result;
|
||||
for (name2index_iterator i = er.first; i != er.second; ++i)
|
||||
result.insert(i->first);
|
||||
return result;
|
||||
}
|
||||
// If we have a full patch, and an approximate match,
|
||||
// ignore approximate match instead of reporting error.
|
||||
// Say, if we have options "all" and "all-chroots", then
|
||||
// "--all" on the command line should select the first one,
|
||||
// without ambiguity.
|
||||
//
|
||||
// For now, we don't check the situation when there are
|
||||
// two full matches.
|
||||
|
||||
options_description::approximation_range
|
||||
options_description::find_approximation(const std::string& prefix) const
|
||||
{
|
||||
name2index_iterator b = name2index.lower_bound(prefix);
|
||||
name2index_iterator e = name2index.upper_bound(prefix + char(CHAR_MAX));
|
||||
return make_pair(b, e);
|
||||
}
|
||||
if (r == option_description::full_match)
|
||||
{
|
||||
return m_options[i].get();
|
||||
}
|
||||
|
||||
found = m_options[i];
|
||||
// FIXME: the use of 'key' here might not
|
||||
// be the best approach.
|
||||
approximate_matches.push_back(m_options[i]->key(name));
|
||||
}
|
||||
if (approximate_matches.size() > 1)
|
||||
boost::throw_exception(
|
||||
ambiguous_option(name, approximate_matches));
|
||||
|
||||
return found.get();
|
||||
}
|
||||
|
||||
BOOST_PROGRAM_OPTIONS_DECL
|
||||
std::ostream& operator<<(std::ostream& os, const options_description& desc)
|
||||
@@ -275,21 +305,212 @@ namespace boost { namespace program_options {
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
/* Given a string 'par', that contains no newline characters
|
||||
outputs it to 'os' with wordwrapping, that is, as several
|
||||
line.
|
||||
|
||||
Each output line starts with 'indent' space characters,
|
||||
following by characters from 'par'. The total length of
|
||||
line is no longer than 'line_length'.
|
||||
|
||||
*/
|
||||
void format_paragraph(std::ostream& os,
|
||||
std::string par,
|
||||
unsigned indent,
|
||||
unsigned line_length)
|
||||
{
|
||||
// Through reminder of this function, 'line_length' will
|
||||
// be the length available for characters, not including
|
||||
// indent.
|
||||
assert(indent < line_length);
|
||||
line_length -= indent;
|
||||
|
||||
// index of tab (if present) is used as additional indent relative
|
||||
// to first_column_width if paragrapth is spanned over multiple
|
||||
// lines if tab is not on first line it is ignored
|
||||
string::size_type par_indent = par.find('\t');
|
||||
|
||||
if (par_indent == string::npos)
|
||||
{
|
||||
par_indent = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// only one tab per paragraph allowed
|
||||
if (count(par.begin(), par.end(), '\t') > 1)
|
||||
{
|
||||
boost::throw_exception(program_options::error(
|
||||
"Only one tab per paragraph is allowed"));
|
||||
}
|
||||
|
||||
// erase tab from string
|
||||
par.erase(par_indent, 1);
|
||||
|
||||
// this assert may fail due to user error or
|
||||
// environment conditions!
|
||||
assert(par_indent < line_length);
|
||||
|
||||
// ignore tab if not on first line
|
||||
if (par_indent >= line_length)
|
||||
{
|
||||
par_indent = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (par.size() < line_length)
|
||||
{
|
||||
os << par;
|
||||
}
|
||||
else
|
||||
{
|
||||
string::const_iterator line_begin = par.begin();
|
||||
const string::const_iterator par_end = par.end();
|
||||
|
||||
bool first_line = true; // of current paragraph!
|
||||
|
||||
while (line_begin < par_end) // paragraph lines
|
||||
{
|
||||
if (!first_line)
|
||||
{
|
||||
// If line starts with space, but second character
|
||||
// is not space, remove the leading space.
|
||||
// We don't remove double spaces because those
|
||||
// might be intentianal.
|
||||
if ((*line_begin == ' ') &&
|
||||
((line_begin + 1 < par_end) &&
|
||||
(*(line_begin + 1) != ' ')))
|
||||
{
|
||||
line_begin += 1; // line_begin != line_end
|
||||
}
|
||||
}
|
||||
|
||||
// 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);
|
||||
string::const_iterator line_end = line_begin +
|
||||
((remaining < line_length) ? remaining : line_length);
|
||||
|
||||
// prevent chopped words
|
||||
// Is line_end between two non-space characters?
|
||||
if ((*(line_end - 1) != ' ') &&
|
||||
((line_end < par_end) && (*line_end != ' ')))
|
||||
{
|
||||
// find last ' ' in the second half of the current paragraph line
|
||||
string::const_iterator last_space =
|
||||
find(reverse_iterator<string::const_iterator>(line_end),
|
||||
reverse_iterator<string::const_iterator>(line_begin),
|
||||
' ')
|
||||
.base();
|
||||
|
||||
if (last_space != line_begin)
|
||||
{
|
||||
// is last_space within the second half ot the
|
||||
// current line
|
||||
if ((unsigned)distance(last_space, line_end) <
|
||||
(line_length - indent) / 2)
|
||||
{
|
||||
line_end = last_space;
|
||||
}
|
||||
}
|
||||
} // prevent chopped words
|
||||
|
||||
// write line to stream
|
||||
copy(line_begin, line_end, ostream_iterator<char>(os));
|
||||
|
||||
if (first_line)
|
||||
{
|
||||
indent += par_indent;
|
||||
first_line = false;
|
||||
}
|
||||
|
||||
// more lines to follow?
|
||||
if (line_end != par_end)
|
||||
{
|
||||
os << '\n';
|
||||
|
||||
for(unsigned pad = indent; pad > 0; --pad)
|
||||
{
|
||||
os.put(' ');
|
||||
}
|
||||
}
|
||||
|
||||
// next line starts after of this line
|
||||
line_begin = line_end;
|
||||
} // paragraph lines
|
||||
}
|
||||
}
|
||||
|
||||
void format_description(std::ostream& os,
|
||||
const std::string& desc,
|
||||
unsigned first_column_width,
|
||||
unsigned line_length)
|
||||
{
|
||||
// we need to use one char less per line to work correctly if actual
|
||||
// console has longer lines
|
||||
assert(line_length > 1);
|
||||
if (line_length > 1)
|
||||
{
|
||||
--line_length;
|
||||
}
|
||||
|
||||
// line_length must be larger than first_column_width
|
||||
// this assert may fail due to user error or environment conditions!
|
||||
assert(line_length > first_column_width);
|
||||
|
||||
// Note: can't use 'tokenizer' as name of typedef -- borland
|
||||
// will consider uses of 'tokenizer' below as uses of
|
||||
// boost::tokenizer, not typedef.
|
||||
typedef boost::tokenizer<boost::char_separator<char> > tok;
|
||||
|
||||
tok paragraphs(
|
||||
desc,
|
||||
char_separator<char>("\n", "", boost::keep_empty_tokens));
|
||||
|
||||
tok::const_iterator par_iter = paragraphs.begin();
|
||||
const tok::const_iterator par_end = paragraphs.end();
|
||||
|
||||
while (par_iter != par_end) // paragraphs
|
||||
{
|
||||
format_paragraph(os, *par_iter, first_column_width,
|
||||
line_length);
|
||||
|
||||
++par_iter;
|
||||
|
||||
// prepair next line if any
|
||||
if (par_iter != par_end)
|
||||
{
|
||||
os << '\n';
|
||||
|
||||
for(unsigned pad = first_column_width; pad > 0; --pad)
|
||||
{
|
||||
os.put(' ');
|
||||
}
|
||||
}
|
||||
} // paragraphs
|
||||
}
|
||||
|
||||
void format_one(std::ostream& os, const option_description& opt,
|
||||
unsigned first_column_width)
|
||||
unsigned first_column_width, unsigned line_length)
|
||||
{
|
||||
stringstream ss;
|
||||
ss << " " << opt.format_name() << ' ' << opt.format_parameter();
|
||||
|
||||
// Don't use ss.rdbuf() since g++ 2.96 is buggy on it.
|
||||
os << ss.str();
|
||||
|
||||
if (!opt.description().empty()) {
|
||||
|
||||
for(int pad = first_column_width - ss.str().size(); pad > 0; --pad) {
|
||||
|
||||
if (!opt.description().empty())
|
||||
{
|
||||
for(unsigned pad = first_column_width - ss.str().size();
|
||||
pad > 0;
|
||||
--pad)
|
||||
{
|
||||
os.put(' ');
|
||||
}
|
||||
os << " : " << opt.description();
|
||||
|
||||
format_description(os, opt.description(),
|
||||
first_column_width, line_length);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -301,25 +522,28 @@ namespace boost { namespace program_options {
|
||||
os << m_caption << ":\n";
|
||||
|
||||
/* Find the maximum width of the option column */
|
||||
unsigned width(24);
|
||||
unsigned width(23);
|
||||
unsigned i; // vc6 has broken for loop scoping
|
||||
for (i = 0; i < options.size(); ++i)
|
||||
for (i = 0; i < m_options.size(); ++i)
|
||||
{
|
||||
const option_description& opt = *options[i];
|
||||
const option_description& opt = *m_options[i];
|
||||
stringstream ss;
|
||||
ss << " " << opt.format_name() << ' ' << opt.format_parameter();
|
||||
width = max(width, static_cast<unsigned>(ss.str().size()));
|
||||
width = (max)(width, static_cast<unsigned>(ss.str().size()));
|
||||
}
|
||||
|
||||
|
||||
/* add an additional space to improve readability */
|
||||
++width;
|
||||
|
||||
/* The options formatting style is stolen from Subversion. */
|
||||
for (i = 0; i < options.size(); ++i)
|
||||
for (i = 0; i < m_options.size(); ++i)
|
||||
{
|
||||
if (belong_to_group[i])
|
||||
continue;
|
||||
|
||||
const option_description& opt = *options[i];
|
||||
const option_description& opt = *m_options[i];
|
||||
|
||||
format_one(os, opt, width);
|
||||
format_one(os, opt, width, m_line_length);
|
||||
|
||||
os << "\n";
|
||||
}
|
||||
|
||||
118
src/parsers.cpp
118
src/parsers.cpp
@@ -17,7 +17,9 @@
|
||||
#include <boost/program_options/detail/convert.hpp>
|
||||
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/throw_exception.hpp>
|
||||
|
||||
#include <cctype>
|
||||
|
||||
#if !defined(__GNUC__) || __GNUC__ < 3
|
||||
#include <iostream>
|
||||
@@ -83,118 +85,30 @@ namespace boost { namespace program_options {
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace detail
|
||||
{
|
||||
void
|
||||
parse_command_line(cmdline& cmd, parsed_options& result);
|
||||
}
|
||||
|
||||
common_command_line_parser::
|
||||
common_command_line_parser(const std::vector<std::string>& args)
|
||||
: m_style(0), m_desc(0), m_positional(0), m_args(args)
|
||||
{}
|
||||
|
||||
parsed_options
|
||||
common_command_line_parser::run() const
|
||||
{
|
||||
parsed_options result(m_desc);
|
||||
detail::cmdline cmd(m_args, m_style);
|
||||
cmd.set_additional_parser(m_ext);
|
||||
|
||||
if (m_desc) {
|
||||
set<string> keys = m_desc->primary_keys();
|
||||
for (set<string>::iterator i = keys.begin(); i != keys.end(); ++i) {
|
||||
const option_description& d = m_desc->find(*i);
|
||||
char s = d.short_name().empty() ? '\0' : d.short_name()[0];
|
||||
|
||||
shared_ptr<const value_semantic> vs = d.semantic();
|
||||
char flags;
|
||||
if (vs->is_zero_tokens())
|
||||
flags = '|';
|
||||
else
|
||||
if (vs->is_implicit())
|
||||
if (vs->is_multitoken())
|
||||
flags = '*';
|
||||
else
|
||||
flags = '?';
|
||||
else if (vs->is_multitoken())
|
||||
flags = '+';
|
||||
else flags = ':';
|
||||
|
||||
cmd.add_option(d.long_name(), s, flags, 1);
|
||||
}
|
||||
}
|
||||
|
||||
detail::parse_command_line(cmd, result);
|
||||
|
||||
if (m_positional)
|
||||
{
|
||||
unsigned position = 0;
|
||||
for (unsigned i = 0; i < result.options.size(); ++i) {
|
||||
option& opt = result.options[i];
|
||||
if (opt.position_key != -1) {
|
||||
if (position >= m_positional->max_total_count())
|
||||
{
|
||||
throw too_many_positional_options_error(
|
||||
"too many positional options");
|
||||
}
|
||||
opt.string_key = m_positional->name_for_position(position);
|
||||
++position;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
namespace detail {
|
||||
void
|
||||
parse_command_line(cmdline& cmd, parsed_options& result)
|
||||
{
|
||||
int position(0);
|
||||
|
||||
while(++cmd) {
|
||||
|
||||
option n;
|
||||
|
||||
if (cmd.at_option()) {
|
||||
if (*cmd.option_name().rbegin() != '*') {
|
||||
n.string_key = cmd.option_name();
|
||||
}
|
||||
else {
|
||||
n.string_key = cmd.raw_option_name();
|
||||
}
|
||||
n.value = cmd.option_values();
|
||||
} else {
|
||||
n.position_key = position++;
|
||||
n.value.clear();
|
||||
n.value.push_back(cmd.argument());
|
||||
}
|
||||
result.options.push_back(n);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<class charT>
|
||||
basic_parsed_options<charT>
|
||||
parse_config_file(std::basic_istream<charT>& is,
|
||||
const options_description& desc)
|
||||
const options_description& desc,
|
||||
bool allow_unregistered)
|
||||
{
|
||||
set<string> allowed_options;
|
||||
set<string> pm = desc.primary_keys();
|
||||
for (set<string>::iterator i = pm.begin(); i != pm.end(); ++i) {
|
||||
const option_description& d = desc.find(*i);
|
||||
|
||||
const vector<shared_ptr<option_description> >& options = desc.options();
|
||||
for (unsigned i = 0; i < options.size(); ++i)
|
||||
{
|
||||
const option_description& d = *options[i];
|
||||
|
||||
if (d.long_name().empty())
|
||||
throw error("long name required for config file");
|
||||
boost::throw_exception(
|
||||
error("long name required for config file"));
|
||||
|
||||
allowed_options.insert(d.long_name());
|
||||
}
|
||||
|
||||
// Parser return char strings
|
||||
parsed_options result(&desc);
|
||||
copy(detail::basic_config_file_iterator<charT>(is, allowed_options),
|
||||
copy(detail::basic_config_file_iterator<charT>(
|
||||
is, allowed_options, allow_unregistered),
|
||||
detail::basic_config_file_iterator<charT>(),
|
||||
back_inserter(result.options));
|
||||
// Convert char strings into desired type.
|
||||
@@ -204,13 +118,15 @@ namespace boost { namespace program_options {
|
||||
template
|
||||
BOOST_PROGRAM_OPTIONS_DECL basic_parsed_options<char>
|
||||
parse_config_file(std::basic_istream<char>& is,
|
||||
const options_description& desc);
|
||||
const options_description& desc,
|
||||
bool allow_unregistered);
|
||||
|
||||
#ifndef BOOST_NO_STD_WSTRING
|
||||
template
|
||||
BOOST_PROGRAM_OPTIONS_DECL basic_parsed_options<wchar_t>
|
||||
parse_config_file(std::basic_istream<wchar_t>& is,
|
||||
const options_description& desc);
|
||||
const options_description& desc,
|
||||
bool allow_unregistered);
|
||||
#endif
|
||||
|
||||
// This versio, which accepts any options without validation, is disabled,
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace boost { namespace program_options {
|
||||
positional_options_description::positional_options_description()
|
||||
{}
|
||||
|
||||
void
|
||||
positional_options_description&
|
||||
positional_options_description::add(const char* name, int max_count)
|
||||
{
|
||||
assert(max_count != -1 || m_trailing.empty());
|
||||
@@ -27,14 +27,14 @@ namespace boost { namespace program_options {
|
||||
else {
|
||||
m_names.resize(m_names.size() + max_count, name);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
unsigned
|
||||
positional_options_description::max_total_count() const
|
||||
{
|
||||
return m_trailing.empty() ?
|
||||
m_names.size() : std::numeric_limits<unsigned>::max();
|
||||
m_names.size() : (std::numeric_limits<unsigned>::max)();
|
||||
}
|
||||
|
||||
const std::string&
|
||||
|
||||
@@ -1,364 +1,21 @@
|
||||
/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
|
||||
// utf8_codecvt_facet.cpp
|
||||
// Copyright Vladimir Prus 2004.
|
||||
// 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)
|
||||
|
||||
// Copyright © 2001 Ronald Garcia, Indiana University (garcia@osl.iu.edu)
|
||||
// Andrew Lumsdaine, Indiana University (lums@osl.iu.edu).
|
||||
// Use, modification and distribution is subject to 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 <cstdlib> // for multi-byte converson routines
|
||||
|
||||
#include <cassert>
|
||||
#define BOOST_PROGRAM_OPTIONS_SOURCE
|
||||
#include <boost/program_options/detail/utf8_codecvt_facet.hpp>
|
||||
#include <boost/program_options/config.hpp>
|
||||
|
||||
#include <boost/limits.hpp>
|
||||
#include <boost/config.hpp>
|
||||
#define BOOST_UTF8_BEGIN_NAMESPACE \
|
||||
namespace boost { namespace program_options { namespace detail {
|
||||
|
||||
// If we don't have wstring, then Unicode support
|
||||
// is not available anyway, so we don't need to even
|
||||
// compiler this file. This also fixes the problem
|
||||
// with mingw, which can compile this file, but will
|
||||
// generate link error when building DLL.
|
||||
#ifndef BOOST_NO_STD_WSTRING
|
||||
#define BOOST_UTF8_END_NAMESPACE }}}
|
||||
#define BOOST_UTF8_DECL BOOST_PROGRAM_OPTIONS_DECL
|
||||
|
||||
namespace boost { namespace program_options { namespace detail {
|
||||
/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
|
||||
// implementation for wchar_t
|
||||
#include "../../detail/utf8_codecvt_facet.cpp"
|
||||
|
||||
// Translate incoming UTF-8 into UCS-4
|
||||
std::codecvt_base::result utf8_codecvt_facet_wchar_t::do_in(
|
||||
mbstate_t& state,
|
||||
const char * from,
|
||||
const char * from_end,
|
||||
const char * & from_next,
|
||||
wchar_t * to,
|
||||
wchar_t * to_end,
|
||||
wchar_t * & to_next
|
||||
) const {
|
||||
// Basic algorithm: The first octet determines how many
|
||||
// octets total make up the UCS-4 character. The remaining
|
||||
// "continuing octets" all begin with "10". To convert, subtract
|
||||
// the amount that specifies the number of octets from the first
|
||||
// octet. Subtract 0x80 (1000 0000) from each continuing octet,
|
||||
// then mash the whole lot together. Note that each continuing
|
||||
// octet only uses 6 bits as unique values, so only shift by
|
||||
// multiples of 6 to combine.
|
||||
while (from != from_end && to != to_end) {
|
||||
|
||||
// Error checking on the first octet
|
||||
if (invalid_leading_octet(*from)){
|
||||
from_next = from;
|
||||
to_next = to;
|
||||
return std::codecvt_base::error;
|
||||
}
|
||||
#undef BOOST_UTF8_BEGIN_NAMESPACE
|
||||
#undef BOOST_UTF8_END_NAMESPACE
|
||||
#undef BOOST_UTF8_DECL
|
||||
|
||||
// The first octet is adjusted by a value dependent upon
|
||||
// the number of "continuing octets" encoding the character
|
||||
const int cont_octet_count = get_cont_octet_count(*from);
|
||||
const wchar_t octet1_modifier_table[] = {
|
||||
0x00, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc
|
||||
};
|
||||
|
||||
// The unsigned char conversion is necessary in case char is
|
||||
// signed (I learned this the hard way)
|
||||
wchar_t ucs_result =
|
||||
(unsigned char)(*from++) - octet1_modifier_table[cont_octet_count];
|
||||
|
||||
// Invariants :
|
||||
// 1) At the start of the loop, 'i' continuing characters have been
|
||||
// processed
|
||||
// 2) *from points to the next continuing character to be processed.
|
||||
int i = 0;
|
||||
while(i != cont_octet_count && from != from_end) {
|
||||
|
||||
// Error checking on continuing characters
|
||||
if (invalid_continuing_octet(*from)) {
|
||||
from_next = from;
|
||||
to_next = to;
|
||||
return std::codecvt_base::error;
|
||||
}
|
||||
|
||||
ucs_result *= (1 << 6);
|
||||
|
||||
// each continuing character has an extra (10xxxxxx)b attached to
|
||||
// it that must be removed.
|
||||
ucs_result += (unsigned char)(*from++) - 0x80;
|
||||
++i;
|
||||
}
|
||||
|
||||
// If the buffer ends with an incomplete unicode character...
|
||||
if (from == from_end && i != cont_octet_count) {
|
||||
// rewind "from" to before the current character translation
|
||||
from_next = from - (i+1);
|
||||
to_next = to;
|
||||
return std::codecvt_base::partial;
|
||||
}
|
||||
*to++ = ucs_result;
|
||||
}
|
||||
from_next = from;
|
||||
to_next = to;
|
||||
|
||||
// Were we done converting or did we run out of destination space?
|
||||
if(from == from_end) return std::codecvt_base::ok;
|
||||
else return std::codecvt_base::partial;
|
||||
}
|
||||
|
||||
std::codecvt_base::result utf8_codecvt_facet_wchar_t::do_out(
|
||||
mbstate_t& state,
|
||||
const wchar_t * from,
|
||||
const wchar_t * from_end,
|
||||
const wchar_t * & from_next,
|
||||
char * to,
|
||||
char * to_end,
|
||||
char * & to_next
|
||||
) const
|
||||
{
|
||||
// RG - consider merging this table with the other one
|
||||
const wchar_t octet1_modifier_table[] = {
|
||||
0x00, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc
|
||||
};
|
||||
|
||||
wchar_t max_wchar = std::numeric_limits<wchar_t>::max();
|
||||
while (from != from_end && to != to_end) {
|
||||
|
||||
// Check for invalid UCS-4 character
|
||||
if (*from > max_wchar) {
|
||||
from_next = from;
|
||||
to_next = to;
|
||||
return std::codecvt_base::error;
|
||||
}
|
||||
|
||||
int cont_octet_count = get_cont_octet_out_count(*from);
|
||||
|
||||
// RG - comment this formula better
|
||||
int shift_exponent = (cont_octet_count) * 6;
|
||||
|
||||
// Process the first character
|
||||
*to++ = octet1_modifier_table[cont_octet_count] +
|
||||
(unsigned char)(*from / (1 << shift_exponent));
|
||||
|
||||
// Process the continuation characters
|
||||
// Invariants: At the start of the loop:
|
||||
// 1) 'i' continuing octets have been generated
|
||||
// 2) '*to' points to the next location to place an octet
|
||||
// 3) shift_exponent is 6 more than needed for the next octet
|
||||
int i = 0;
|
||||
while (i != cont_octet_count && to != to_end) {
|
||||
shift_exponent -= 6;
|
||||
*to++ = 0x80 + ((*from / (1 << shift_exponent)) % (1 << 6));
|
||||
++i;
|
||||
}
|
||||
// If we filled up the out buffer before encoding the character
|
||||
if(to == to_end && i != cont_octet_count) {
|
||||
from_next = from;
|
||||
to_next = to - (i+1);
|
||||
return std::codecvt_base::partial;
|
||||
}
|
||||
*from++;
|
||||
}
|
||||
from_next = from;
|
||||
to_next = to;
|
||||
// Were we done or did we run out of destination space
|
||||
if(from == from_end) return std::codecvt_base::ok;
|
||||
else return std::codecvt_base::partial;
|
||||
}
|
||||
|
||||
// How many char objects can I process to get <= max_limit
|
||||
// wchar_t objects?
|
||||
int utf8_codecvt_facet_wchar_t::do_length(
|
||||
mbstate_t &,
|
||||
const char * from,
|
||||
const char * from_end,
|
||||
std::size_t max_limit
|
||||
#if BOOST_WORKAROUND(__IBMCPP__, BOOST_TESTED_AT(600))
|
||||
) const throw()
|
||||
#else
|
||||
) const
|
||||
#endif
|
||||
{
|
||||
// RG - this code is confusing! I need a better way to express it.
|
||||
// and test cases.
|
||||
|
||||
// Invariants:
|
||||
// 1) last_octet_count has the size of the last measured character
|
||||
// 2) char_count holds the number of characters shown to fit
|
||||
// within the bounds so far (no greater than max_limit)
|
||||
// 3) from_next points to the octet 'last_octet_count' before the
|
||||
// last measured character.
|
||||
int last_octet_count=0;
|
||||
std::size_t char_count = 0;
|
||||
const char* from_next = from;
|
||||
// Use "<" because the buffer may represent incomplete characters
|
||||
while (from_next+last_octet_count <= from_end && char_count <= max_limit) {
|
||||
from_next += last_octet_count;
|
||||
last_octet_count = (get_octet_count(*from_next));
|
||||
++char_count;
|
||||
}
|
||||
return from_next-from_end;
|
||||
}
|
||||
|
||||
unsigned int utf8_codecvt_facet_wchar_t::get_octet_count(
|
||||
unsigned char lead_octet
|
||||
){
|
||||
// if the 0-bit (MSB) is 0, then 1 character
|
||||
if (lead_octet <= 0x7f) return 1;
|
||||
|
||||
// Otherwise the count number of consecutive 1 bits starting at MSB
|
||||
// assert(0xc0 <= lead_octet && lead_octet <= 0xfd);
|
||||
|
||||
if (0xc0 <= lead_octet && lead_octet <= 0xdf) return 2;
|
||||
else if (0xe0 <= lead_octet && lead_octet <= 0xef) return 3;
|
||||
else if (0xf0 <= lead_octet && lead_octet <= 0xf7) return 4;
|
||||
else if (0xf8 <= lead_octet && lead_octet <= 0xfb) return 5;
|
||||
else return 6;
|
||||
}
|
||||
}}}
|
||||
|
||||
namespace {
|
||||
template<std::size_t s>
|
||||
int get_cont_octet_out_count_impl(wchar_t word){
|
||||
if (word < 0x80) {
|
||||
return 0;
|
||||
}
|
||||
if (word < 0x800) {
|
||||
return 1;
|
||||
}
|
||||
return 2;
|
||||
}
|
||||
|
||||
template<>
|
||||
int get_cont_octet_out_count_impl<4>(wchar_t word){
|
||||
if (word < 0x80) {
|
||||
return 0;
|
||||
}
|
||||
if (word < 0x800) {
|
||||
return 1;
|
||||
}
|
||||
if (word < 0x10000) {
|
||||
return 2;
|
||||
}
|
||||
if (word < 0x200000) {
|
||||
return 3;
|
||||
}
|
||||
if (word < 0x4000000) {
|
||||
return 4;
|
||||
}
|
||||
return 5;
|
||||
}
|
||||
|
||||
} // namespace anonymous
|
||||
|
||||
namespace boost { namespace program_options { namespace detail {
|
||||
// How many "continuing octets" will be needed for this word
|
||||
// == total octets - 1.
|
||||
int utf8_codecvt_facet_wchar_t::get_cont_octet_out_count(
|
||||
wchar_t word
|
||||
) const {
|
||||
return get_cont_octet_out_count_impl<sizeof(wchar_t)>(word);
|
||||
}
|
||||
}}}
|
||||
|
||||
#if 0 // not used?
|
||||
/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
|
||||
// implementation for char
|
||||
|
||||
std::codecvt_base::result utf8_codecvt_facet_char::do_in(
|
||||
mbstate_t & state,
|
||||
const char * from,
|
||||
const char * from_end,
|
||||
const char * & from_next,
|
||||
char * to,
|
||||
char * to_end,
|
||||
char * & to_next
|
||||
) const
|
||||
{
|
||||
while(from_next < from_end){
|
||||
wchar_t w;
|
||||
wchar_t *wnext = & w;
|
||||
utf8_codecvt_facet_wchar_t::result ucs4_result;
|
||||
ucs4_result = base_class::do_in(
|
||||
state,
|
||||
from, from_end, from_next,
|
||||
wnext, wnext + 1, wnext
|
||||
);
|
||||
if(codecvt_base::ok != ucs4_result)
|
||||
return ucs4_result;
|
||||
// if the conversion succeeds.
|
||||
int length = std::wctomb(to_next, w);
|
||||
// assert(-1 != length);
|
||||
to_next += length;
|
||||
}
|
||||
return codecvt_base::ok;
|
||||
}
|
||||
|
||||
std::codecvt_base::result utf8_codecvt_facet_char::do_out(
|
||||
std::mbstate_t & state,
|
||||
const char * from,
|
||||
const char * from_end,
|
||||
const char * & from_next,
|
||||
char * to,
|
||||
char * to_end,
|
||||
char * & to_next
|
||||
) const
|
||||
{
|
||||
while(from_next < from_end){
|
||||
wchar_t w;
|
||||
int result = std::mbtowc(&w, from_next, MB_LENGTH_MAX);
|
||||
// assert(-1 != result);
|
||||
from_next += result;
|
||||
utf8_codecvt_facet_wchar_t::result ucs4_result;
|
||||
|
||||
const wchar_t *wptr = & w;
|
||||
ucs4_result = base_class::do_out(
|
||||
state,
|
||||
wptr, wptr+1, wptr,
|
||||
to_next, to_end, to_next
|
||||
);
|
||||
if(codecvt_base::ok != ucs4_result)
|
||||
return ucs4_result;
|
||||
}
|
||||
return codecvt_base::ok;
|
||||
}
|
||||
|
||||
// How many bytes objects can I process to get <= max_limit
|
||||
// char objects?
|
||||
int utf8_codecvt_facet_char::do_length(
|
||||
const mbstate_t & initial_state,
|
||||
const char * from_next,
|
||||
const char * from_end,
|
||||
std::size_t max_limit
|
||||
) const
|
||||
{
|
||||
int total_length = 0;
|
||||
const char *from = from_next;
|
||||
mbstate_t state = initial_state;
|
||||
while(from_next < from_end){
|
||||
wchar_t w;
|
||||
wchar_t *wnext = & w;
|
||||
utf8_codecvt_facet_wchar_t::result ucs4_result;
|
||||
ucs4_result = base_class::do_in(
|
||||
state,
|
||||
from_next, from_end, from_next,
|
||||
wnext, wnext + 1, wnext
|
||||
);
|
||||
|
||||
if(codecvt_base::ok != ucs4_result)
|
||||
break;
|
||||
|
||||
char carray[MB_LENGTH_MAX];
|
||||
std::size_t count = wctomb(carray, w);
|
||||
if(count > max_limit)
|
||||
break;
|
||||
|
||||
max_limit -= count;
|
||||
total_length = from_next - from;
|
||||
}
|
||||
return total_length;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -8,6 +8,8 @@
|
||||
#include <boost/program_options/value_semantic.hpp>
|
||||
#include <boost/program_options/detail/convert.hpp>
|
||||
|
||||
#include <cctype>
|
||||
|
||||
namespace boost { namespace program_options {
|
||||
|
||||
using namespace std;
|
||||
@@ -28,7 +30,8 @@ namespace boost { namespace program_options {
|
||||
}
|
||||
xparse(value_store, local_tokens);
|
||||
#else
|
||||
throw std::runtime_error("UTF-8 conversion not supported.");
|
||||
boost::throw_exception(
|
||||
std::runtime_error("UTF-8 conversion not supported."));
|
||||
#endif
|
||||
} else {
|
||||
// Already in local encoding, pass unmodified
|
||||
@@ -68,15 +71,35 @@ namespace boost { namespace program_options {
|
||||
{
|
||||
return arg;
|
||||
}
|
||||
|
||||
unsigned
|
||||
untyped_value::min_tokens() const
|
||||
{
|
||||
if (m_zero_tokens)
|
||||
return 0;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
|
||||
unsigned
|
||||
untyped_value::max_tokens() const
|
||||
{
|
||||
if (m_zero_tokens)
|
||||
return 0;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
untyped_value::xparse(boost::any& value_store,
|
||||
const std::vector<std::string>& new_tokens) const
|
||||
{
|
||||
if (!value_store.empty())
|
||||
throw multiple_occurrences("multiple_occurrences");
|
||||
boost::throw_exception(
|
||||
multiple_occurrences("multiple_occurrences"));
|
||||
if (new_tokens.size() > 1)
|
||||
throw multiple_values("multiple_values");
|
||||
boost::throw_exception(multiple_values("multiple_values"));
|
||||
value_store = new_tokens.empty() ? std::string("") : new_tokens.front();
|
||||
}
|
||||
|
||||
@@ -99,8 +122,8 @@ namespace boost { namespace program_options {
|
||||
/* Validates bool value.
|
||||
Any of "1", "true", "yes", "on" will be converted to "1".<br>
|
||||
Any of "0", "false", "no", "off" will be converted to "0".<br>
|
||||
Case is ignored. Regardless of name passed, parameter will always
|
||||
be optional.
|
||||
Case is ignored. The 'xs' vector can either be empty, in which
|
||||
case the value is 'true', or can contain explicit value.
|
||||
*/
|
||||
BOOST_PROGRAM_OPTIONS_DECL void validate(any& v, const vector<string>& xs,
|
||||
bool*, int)
|
||||
@@ -116,7 +139,8 @@ namespace boost { namespace program_options {
|
||||
else if (s == "off" || s == "no" || s == "0" || s == "false")
|
||||
v = any(false);
|
||||
else
|
||||
throw validation_error("'" + s + "' doesn't look like a bool value.");
|
||||
boost::throw_exception(validation_error(
|
||||
"'" + s + "' doesn't look like a bool value."));
|
||||
}
|
||||
|
||||
// This is blatant copy-paste. However, templating this will cause a problem,
|
||||
@@ -138,7 +162,7 @@ namespace boost { namespace program_options {
|
||||
else if (s == L"off" || s == L"no" || s == L"0" || s == L"false")
|
||||
v = any(false);
|
||||
else
|
||||
throw validation_error("invalid bool value");
|
||||
boost::throw_exception(validation_error("invalid bool value"));
|
||||
}
|
||||
#endif
|
||||
BOOST_PROGRAM_OPTIONS_DECL
|
||||
@@ -146,9 +170,12 @@ namespace boost { namespace program_options {
|
||||
{
|
||||
check_first_occurrence(v);
|
||||
string s(get_single_string(xs));
|
||||
if (*s.begin() == '\'' && *s.rbegin() == '\'' ||
|
||||
*s.begin() == '"' && *s.rbegin() == '"')
|
||||
if (!s.empty() && (
|
||||
(*s.begin() == '\'' && *s.rbegin() == '\'' ||
|
||||
*s.begin() == '"' && *s.rbegin() == '"')))
|
||||
{
|
||||
v = any(s.substr(1, s.size()-2));
|
||||
}
|
||||
else
|
||||
v = any(s);
|
||||
}
|
||||
@@ -173,7 +200,8 @@ namespace boost { namespace program_options {
|
||||
void check_first_occurrence(const boost::any& value)
|
||||
{
|
||||
if (!value.empty())
|
||||
throw multiple_occurrences("multiple_occurrences");
|
||||
boost::throw_exception(
|
||||
multiple_occurrences("multiple_occurrences"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -23,6 +23,9 @@ namespace boost { namespace program_options {
|
||||
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'.
|
||||
assert(options.description);
|
||||
const options_description& desc = *options.description;
|
||||
|
||||
@@ -30,47 +33,44 @@ namespace boost { namespace program_options {
|
||||
// variables_map. Ehmm.. messy.
|
||||
std::map<std::string, variable_value>& m = xm;
|
||||
|
||||
// The set of existing values that should not be changed.
|
||||
std::set<std::string> final;
|
||||
for (map<string, variable_value>::iterator k = m.begin();
|
||||
k != m.end();
|
||||
++k)
|
||||
{
|
||||
if (!k->second.defaulted()) {
|
||||
// TODO: what if we have different definition
|
||||
// for the same option name during different calls
|
||||
// 'store'.
|
||||
bool composing = desc.count(k->first)
|
||||
&& desc.find(k->first).semantic()->is_composing();
|
||||
std::set<std::string> new_final;
|
||||
|
||||
if (!composing)
|
||||
final.insert(k->first);
|
||||
}
|
||||
}
|
||||
// Declared once, to please Intel in VC++ mode;
|
||||
unsigned i;
|
||||
|
||||
// First, convert/store all given options
|
||||
for (size_t i = 0; i < options.options.size(); ++i) {
|
||||
for (i = 0; i < options.options.size(); ++i) {
|
||||
|
||||
const string& name = options.options[i].string_key;
|
||||
// Skip positional options without name
|
||||
if (name.empty())
|
||||
continue;
|
||||
|
||||
// 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 (final.count(name))
|
||||
if (xm.m_final.count(name))
|
||||
continue;
|
||||
|
||||
// Ignore options which are not described
|
||||
if (desc.count(name) == 0)
|
||||
continue;
|
||||
//TODO: consider this.
|
||||
//if (desc.count(name) == 0)
|
||||
// continue;
|
||||
|
||||
const option_description& d = desc.find(name);
|
||||
const option_description& d = desc.find(name, false);
|
||||
|
||||
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);
|
||||
}
|
||||
@@ -80,20 +80,43 @@ namespace boost { namespace program_options {
|
||||
throw;
|
||||
}
|
||||
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);
|
||||
}
|
||||
xm.m_final.insert(new_final.begin(), new_final.end());
|
||||
|
||||
|
||||
|
||||
// Second, apply default values.
|
||||
set<string> keys = desc.primary_keys();
|
||||
for (set<string>::const_iterator j = keys.begin(); j != keys.end(); ++j)
|
||||
if (m.count(*j) == 0) {
|
||||
const option_description& d = desc.find(*j);
|
||||
|
||||
const vector<shared_ptr<option_description> >& all = desc.options();
|
||||
for(i = 0; i < all.size(); ++i)
|
||||
{
|
||||
const option_description& d = *all[i];
|
||||
string key = d.key("");
|
||||
// FIXME: this logic relies on knowledge of option_description
|
||||
// internals.
|
||||
// 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[*j] = variable_value(def, true);
|
||||
m[*j].m_value_semantic = d.semantic();
|
||||
m[key] = variable_value(def, true);
|
||||
m[key].m_value_semantic = d.semantic();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_PROGRAM_OPTIONS_DECL
|
||||
|
||||
@@ -12,10 +12,12 @@ namespace boost { namespace program_options {
|
||||
|
||||
using namespace std;
|
||||
|
||||
// The rules for windows command line are pretty funny, see
|
||||
// Take a command line string and splits in into tokens, according
|
||||
// to the rules windows command line processor uses.
|
||||
//
|
||||
// The rules are pretty funny, see
|
||||
// http://article.gmane.org/gmane.comp.lib.boost.user/3005
|
||||
// http://msdn.microsoft.com/library/en-us/vccelng/htm/progs_12.asp
|
||||
|
||||
BOOST_PROGRAM_OPTIONS_DECL
|
||||
std::vector<std::string> split_winmain(const std::string& input)
|
||||
{
|
||||
@@ -23,7 +25,7 @@ namespace boost { namespace program_options {
|
||||
|
||||
string::const_iterator i = input.begin(), e = input.end();
|
||||
for(;i != e; ++i)
|
||||
if (!isspace(*i))
|
||||
if (!isspace((unsigned char)*i))
|
||||
break;
|
||||
|
||||
if (i != e) {
|
||||
@@ -55,11 +57,11 @@ namespace boost { namespace program_options {
|
||||
current.append(backslash_count, '\\');
|
||||
backslash_count = 0;
|
||||
}
|
||||
if (isspace(*i) && !inside_quoted) {
|
||||
if (isspace((unsigned char)*i) && !inside_quoted) {
|
||||
// Space outside quoted section terminate the current argument
|
||||
result.push_back(current);
|
||||
current.resize(0);
|
||||
for(;i != e && isspace(*i); ++i)
|
||||
for(;i != e && isspace((unsigned char)*i); ++i)
|
||||
;
|
||||
--i;
|
||||
} else {
|
||||
@@ -86,7 +88,7 @@ namespace boost { namespace program_options {
|
||||
{
|
||||
vector<wstring> result;
|
||||
vector<string> aux = split_winmain(to_internal(cmdline));
|
||||
for (unsigned i = 0, e = result.size(); i < e; ++i)
|
||||
for (unsigned i = 0, e = aux.size(); i < e; ++i)
|
||||
result.push_back(from_utf8(aux[i]));
|
||||
return result;
|
||||
}
|
||||
|
||||
47
test/Jamfile
47
test/Jamfile
@@ -1,47 +0,0 @@
|
||||
|
||||
subproject libs/program_options/test ;
|
||||
|
||||
import testing ;
|
||||
|
||||
rule program-options-test ( name )
|
||||
{
|
||||
return [
|
||||
run $(name).cpp <lib>../build/boost_program_options
|
||||
<lib>../../test/build/boost_test_exec_monitor : :
|
||||
: <include>$(BOOST_ROOT)
|
||||
std::locale-support ]
|
||||
;
|
||||
}
|
||||
|
||||
rule program-options-dll-test ( name )
|
||||
{
|
||||
return [
|
||||
run $(name).cpp <dll>../build/boost_program_options
|
||||
<lib>../../test/build/boost_test_exec_monitor : :
|
||||
: <include>$(BOOST_ROOT)
|
||||
<define>BOOST_ALL_DYN_LINK=1
|
||||
<runtime-link>dynamic
|
||||
: $(name)_dll ]
|
||||
;
|
||||
}
|
||||
|
||||
|
||||
test-suite program_options :
|
||||
[ program-options-test options_description_test ]
|
||||
[ program-options-test parsers_test ]
|
||||
[ program-options-test variable_map_test ]
|
||||
[ program-options-test cmdline_test ]
|
||||
[ program-options-test positional_options_test ]
|
||||
[ program-options-test unicode_test ]
|
||||
[ program-options-test winmain ]
|
||||
[ program-options-dll-test options_description_test ]
|
||||
[ program-options-dll-test parsers_test ]
|
||||
[ program-options-dll-test variable_map_test ]
|
||||
[ program-options-dll-test cmdline_test ]
|
||||
[ program-options-dll-test positional_options_test ]
|
||||
[ program-options-dll-test unicode_test ]
|
||||
[ program-options-dll-test winmain ]
|
||||
|
||||
|
||||
;
|
||||
|
||||
@@ -1,24 +1,33 @@
|
||||
|
||||
project
|
||||
: requirements
|
||||
<library>../build//program_options
|
||||
<library>/boost/test//boost_test_exec_monitor
|
||||
<hardcode-dll-paths>true
|
||||
<library>../build//boost_program_options
|
||||
<link>static
|
||||
<variant>debug
|
||||
|
||||
# <define>_GLIBCXX_CONCEPT_CHECKS
|
||||
# <define>_GLIBCXX_DEBUG
|
||||
;
|
||||
|
||||
rule po-test ( source )
|
||||
{
|
||||
return
|
||||
[ run $(source) ]
|
||||
[ run $(source) : : : <link>shared <define>BOOST_PROGRAM_OPTIONS_DYN_LINK=1
|
||||
: $(source:B)_dll ]
|
||||
;
|
||||
}
|
||||
|
||||
test-suite program_options :
|
||||
|
||||
[ run options_description_test.cpp ]
|
||||
[ run parsers_test.cpp ]
|
||||
[ run variable_map_test.cpp ]
|
||||
[ run cmdline_test.cpp ]
|
||||
[ run positional_options_test.cpp ]
|
||||
[ run unicode_test.cpp ]
|
||||
[ run winmain.cpp ]
|
||||
[ po-test options_description_test.cpp ]
|
||||
[ po-test parsers_test.cpp ]
|
||||
[ po-test variable_map_test.cpp ]
|
||||
[ po-test cmdline_test.cpp ]
|
||||
[ po-test positional_options_test.cpp ]
|
||||
[ po-test unicode_test.cpp ]
|
||||
[ po-test winmain.cpp ]
|
||||
;
|
||||
|
||||
exe test_convert : test_convert.cpp ../build//program_options ;
|
||||
exe test_convert : test_convert.cpp ;
|
||||
|
||||
|
||||
@@ -3,21 +3,20 @@
|
||||
// (See accompanying file LICENSE_1_0.txt
|
||||
// or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
||||
#include <boost/program_options/cmdline.hpp>
|
||||
#include <boost/program_options/options_description.hpp>
|
||||
#include <boost/program_options/detail/cmdline.hpp>
|
||||
using namespace boost::program_options;
|
||||
using boost::program_options::detail::cmdline;
|
||||
|
||||
|
||||
#include <boost/test/test_tools.hpp>
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
#include <cassert>
|
||||
using namespace std;
|
||||
|
||||
#include "minitest.hpp"
|
||||
|
||||
/* To facilitate testing, declare a number of error codes. Otherwise,
|
||||
we'd have to specify the type of exception that should be thrown.
|
||||
*/
|
||||
@@ -50,19 +49,19 @@ int translate_syntax_error_kind(invalid_command_line_syntax::kind_t k)
|
||||
return std::distance(b, i) + 3;
|
||||
}
|
||||
|
||||
|
||||
struct test_case {
|
||||
const char* input;
|
||||
int expected_status;
|
||||
const char* expected_result;
|
||||
};
|
||||
|
||||
|
||||
/* Parses the syntax description in 'syntax' and initialized
|
||||
'cmd' accordingly'
|
||||
The "boost::program_options" in parameter type is needed because CW9
|
||||
has std::detail and it causes an ambiguity.
|
||||
*/
|
||||
void apply_syntax(cmdline& cmd,
|
||||
void apply_syntax(options_description& desc,
|
||||
const char* syntax)
|
||||
{
|
||||
|
||||
@@ -70,32 +69,29 @@ void apply_syntax(cmdline& cmd,
|
||||
stringstream ss;
|
||||
ss << syntax;
|
||||
while(ss >> s) {
|
||||
string long_name;
|
||||
char short_name = '\0';
|
||||
char properties = '|';
|
||||
value_semantic* v = 0;
|
||||
|
||||
if (*(s.end()-1) == '=') {
|
||||
properties = ':';
|
||||
v = value<string>();
|
||||
s.resize(s.size()-1);
|
||||
} else if (*(s.end()-1) == '?') {
|
||||
properties = '?';
|
||||
//v = value<string>()->implicit();
|
||||
v = value<string>();
|
||||
s.resize(s.size()-1);
|
||||
} else if (*(s.end()-1) == '*') {
|
||||
properties = '*';
|
||||
v = value<vector<string> >()->multitoken();
|
||||
s.resize(s.size()-1);
|
||||
} else if (*(s.end()-1) == '+') {
|
||||
properties = '+';
|
||||
v = value<vector<string> >()->multitoken();
|
||||
s.resize(s.size()-1);
|
||||
}
|
||||
string::size_type n = s.find(',');
|
||||
if (n == string::npos) {
|
||||
long_name = s;
|
||||
if (v) {
|
||||
desc.add_options()
|
||||
(s.c_str(), v, "");
|
||||
} else {
|
||||
assert(n == s.size()-2);
|
||||
long_name = s.substr(0, s.size()-2);
|
||||
short_name = *s.rbegin();
|
||||
desc.add_options()
|
||||
(s.c_str(), "");
|
||||
}
|
||||
cmd.add_option(long_name, short_name, properties, 1);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -114,30 +110,36 @@ void test_cmdline(const char* syntax,
|
||||
xinput.push_back(s);
|
||||
}
|
||||
}
|
||||
cmdline cmd(xinput, style);
|
||||
options_description desc;
|
||||
apply_syntax(desc, syntax);
|
||||
|
||||
cmdline cmd(xinput);
|
||||
cmd.style(style);
|
||||
cmd.set_options_description(desc);
|
||||
|
||||
apply_syntax(cmd, syntax);
|
||||
|
||||
string result;
|
||||
int status = 0;
|
||||
|
||||
try {
|
||||
while(++cmd) {
|
||||
if (cmd.at_argument()) {
|
||||
vector<option> options = cmd.run();
|
||||
|
||||
for(unsigned i = 0; i < options.size(); ++i)
|
||||
{
|
||||
option opt = options[i];
|
||||
|
||||
if (opt.position_key != -1) {
|
||||
if (!result.empty())
|
||||
result += " ";
|
||||
result += cmd.argument();
|
||||
result += opt.value[0];
|
||||
} else {
|
||||
if (!result.empty())
|
||||
result += " ";
|
||||
if (*cmd.option_name().rbegin() != '*')
|
||||
result += cmd.option_name() + ":";
|
||||
else
|
||||
result += cmd.raw_option_name() + ":";
|
||||
for (size_t i = 0; i < cmd.option_values().size(); ++i) {
|
||||
if (i != 0)
|
||||
result += opt.string_key + ":";
|
||||
for (size_t j = 0; j < opt.value.size(); ++j) {
|
||||
if (j != 0)
|
||||
result += "-";
|
||||
result += cmd.option_values()[i];
|
||||
result += opt.value[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -177,34 +179,28 @@ void test_long_options()
|
||||
{"--foo=13", s_extra_parameter, ""},
|
||||
|
||||
// Test option with required parameter
|
||||
|
||||
{"--bar=", s_empty_adjacent_parameter, ""},
|
||||
{"--bar", s_missing_parameter, ""},
|
||||
{"--bar=123", s_success, "bar:123"},
|
||||
|
||||
// Test option with optional parameter
|
||||
{"--baz", s_success, "baz:"},
|
||||
{"--baz=7", s_success, "baz:7"},
|
||||
{"--bar=123", s_success, "bar:123"},
|
||||
{0}
|
||||
};
|
||||
test_cmdline("foo bar= baz?", style, test_cases1);
|
||||
test_cmdline("foo bar=", style, test_cases1);
|
||||
|
||||
|
||||
style = cmdline::style_t(
|
||||
allow_long | long_allow_next);
|
||||
|
||||
test_case test_cases2[] = {
|
||||
{"--foo", s_success, "foo:"},
|
||||
{"--bar=10", s_long_adjacent_not_allowed, ""},
|
||||
{"--bar 10", s_success, "bar:10"},
|
||||
{"--bar", s_missing_parameter, ""},
|
||||
{"--bar --foo", s_missing_parameter, ""},
|
||||
{"--baz", s_success, "baz:"},
|
||||
{"--baz 10", s_success, "baz:10"},
|
||||
{"--baz --foo", s_success, "baz: foo:"},
|
||||
// Since --bar accepts a parameter, --foo is
|
||||
// considered a value, even though it looks like
|
||||
// an option.
|
||||
{"--bar --foo", s_success, "bar:--foo"},
|
||||
{0}
|
||||
};
|
||||
test_cmdline("foo bar= baz?", style, test_cases2);
|
||||
|
||||
test_cmdline("foo bar=", style, test_cases2);
|
||||
style = cmdline::style_t(
|
||||
allow_long | long_allow_adjacent
|
||||
| long_allow_next);
|
||||
@@ -212,17 +208,16 @@ void test_long_options()
|
||||
test_case test_cases3[] = {
|
||||
{"--bar=10", s_success, "bar:10"},
|
||||
{"--bar 11", s_success, "bar:11"},
|
||||
{"--baz=12", s_success, "baz:12"},
|
||||
{"--baz 13", s_success, "baz:13"},
|
||||
{"--baz --foo", s_success, "baz: foo:"},
|
||||
{0}
|
||||
};
|
||||
test_cmdline("foo bar= baz?", style, test_cases3);
|
||||
test_cmdline("foo bar=", style, test_cases3);
|
||||
|
||||
style = cmdline::style_t(
|
||||
allow_long | long_allow_adjacent
|
||||
| long_allow_next | case_insensitive);
|
||||
|
||||
// FIXME: restore
|
||||
#if 0
|
||||
// Test case insensitive style.
|
||||
// Note that option names are normalized to lower case.
|
||||
test_case test_cases4[] = {
|
||||
@@ -234,6 +229,7 @@ void test_long_options()
|
||||
{0}
|
||||
};
|
||||
test_cmdline("foo bar= baz? Giz", style, test_cases4);
|
||||
#endif
|
||||
}
|
||||
|
||||
void test_short_options()
|
||||
@@ -248,14 +244,14 @@ void test_short_options()
|
||||
test_case test_cases1[] = {
|
||||
{"-d d /bar", s_success, "-d: d /bar"},
|
||||
// This is treated as error when long options are disabled
|
||||
{"--foo", s_long_not_allowed, ""},
|
||||
{"--foo", s_success, "--foo"},
|
||||
{"-d13", s_extra_parameter, ""},
|
||||
{"-f14", s_success, "-f:14"},
|
||||
{"-g -f1", s_success, "-g: -f:1"},
|
||||
{"-f", s_missing_parameter, ""},
|
||||
{0}
|
||||
};
|
||||
test_cmdline(",d ,f= ,g?", style, test_cases1);
|
||||
test_cmdline(",d ,f= ,g", style, test_cases1);
|
||||
|
||||
style = cmdline::style_t(
|
||||
allow_short | allow_dash_for_short
|
||||
@@ -265,18 +261,11 @@ void test_short_options()
|
||||
{"-f 13", s_success, "-f:13"},
|
||||
{"-f -13", s_success, "-f:-13"},
|
||||
{"-f", s_missing_parameter, ""},
|
||||
{"-f --foo", s_missing_parameter, ""},
|
||||
{"-f /foo", s_success, "-f:/foo"},
|
||||
{"-f -d", s_success, "-f:-d"},
|
||||
{"-g 13", s_success, "-g:13"},
|
||||
{"-g", s_success, "-g:"},
|
||||
{"-g --foo", s_long_not_allowed, "-g:"},
|
||||
{"-g /foo", s_success, "-g:/foo"},
|
||||
{"-g -d", s_success, "-g: -d:"},
|
||||
{"-f12", s_short_adjacent_not_allowed, ""},
|
||||
{0}
|
||||
};
|
||||
test_cmdline(",d ,f= ,g?", style, test_cases2);
|
||||
test_cmdline(",d ,f=", style, test_cases2);
|
||||
|
||||
style = cmdline::style_t(
|
||||
allow_short | short_allow_next
|
||||
@@ -286,12 +275,9 @@ void test_short_options()
|
||||
{"-f10", s_success, "-f:10"},
|
||||
{"-f 10", s_success, "-f:10"},
|
||||
{"-f -d", s_success, "-f:-d"},
|
||||
{"-g10", s_success, "-g:10"},
|
||||
{"-g 10", s_success, "-g:10"},
|
||||
{"-g -d", s_success, "-g: -d:"},
|
||||
{0}
|
||||
};
|
||||
test_cmdline(",d ,f= ,g?", style, test_cases3);
|
||||
test_cmdline(",d ,f=", style, test_cases3);
|
||||
|
||||
style = cmdline::style_t(
|
||||
allow_short | short_allow_next
|
||||
@@ -300,14 +286,14 @@ void test_short_options()
|
||||
|
||||
test_case test_cases4[] = {
|
||||
{"-de", s_success, "-d: -e:"},
|
||||
{"-dg", s_success, "-d: -g:"},
|
||||
{"-dg10", s_success, "-d: -g:10"},
|
||||
{"-d12", s_extra_parameter, ""},
|
||||
{"-gd", s_success, "-g:d"},
|
||||
{"-df10", s_success, "-d: -f:10"},
|
||||
// FIXME: review
|
||||
//{"-d12", s_extra_parameter, ""},
|
||||
{"-f12", s_success, "-f:12"},
|
||||
{"-fe", s_success, "-f:e"},
|
||||
{0}
|
||||
};
|
||||
test_cmdline(",d ,f= ,g? ,e", style, test_cases4);
|
||||
test_cmdline(",d ,f= ,e", style, test_cases4);
|
||||
|
||||
}
|
||||
|
||||
@@ -323,15 +309,13 @@ void test_dos_options()
|
||||
|
||||
test_case test_cases1[] = {
|
||||
{"/d d -bar", s_success, "-d: d -bar"},
|
||||
// This is treated as disallowed long option
|
||||
{"--foo", s_long_not_allowed, ""},
|
||||
{"--foo", s_success, "--foo"},
|
||||
{"/d13", s_extra_parameter, ""},
|
||||
{"/f14", s_success, "-f:14"},
|
||||
{"/g /f1", s_success, "-g: -f:1"},
|
||||
{"/f", s_missing_parameter, ""},
|
||||
{0}
|
||||
};
|
||||
test_cmdline(",d ,f= ,g?", style, test_cases1);
|
||||
test_cmdline(",d ,f=", style, test_cases1);
|
||||
|
||||
style = cmdline::style_t(
|
||||
allow_short
|
||||
@@ -340,14 +324,14 @@ void test_dos_options()
|
||||
|
||||
test_case test_cases2[] = {
|
||||
{"/de", s_extra_parameter, ""},
|
||||
{"/gd", s_success, "-g:d"},
|
||||
{"/fe", s_success, "-f:e"},
|
||||
{0}
|
||||
};
|
||||
test_cmdline(",d ,f= ,g? ,e", style, test_cases2);
|
||||
test_cmdline(",d ,f= ,e", style, test_cases2);
|
||||
|
||||
}
|
||||
|
||||
|
||||
void test_disguised_long()
|
||||
{
|
||||
using namespace command_line_style;
|
||||
@@ -447,43 +431,176 @@ void test_prefix()
|
||||
test_cmdline("foo*=", style, test_cases1);
|
||||
}
|
||||
|
||||
void test_multiple()
|
||||
|
||||
pair<string, string> at_option_parser(string const&s)
|
||||
{
|
||||
using namespace command_line_style;
|
||||
cmdline::style_t style;
|
||||
|
||||
style = cmdline::style_t(
|
||||
unix_style | long_allow_next);
|
||||
|
||||
test_case test_cases1[] = {
|
||||
{"--value 1 2 3 4 --help", s_success, "value:1-2-3-4 help:"},
|
||||
{"--value 1 2 3 4 --", s_success, "value:1-2-3-4"},
|
||||
{0}
|
||||
};
|
||||
|
||||
test_cmdline("value+ help", style, test_cases1);
|
||||
if ('@' == s[0])
|
||||
return std::make_pair(string("response-file"), s.substr(1));
|
||||
else
|
||||
return pair<string, string>();
|
||||
}
|
||||
|
||||
void test_style_errors()
|
||||
pair<string, string> at_option_parser_broken(string const&s)
|
||||
{
|
||||
using namespace command_line_style;
|
||||
char* argv[] = {"program"};
|
||||
|
||||
BOOST_CHECK_THROW(cmdline cmd(1, (const char*const *)argv, allow_long),
|
||||
invalid_command_line_style);
|
||||
|
||||
BOOST_CHECK_THROW(cmdline cmd(1, (const char*const *)argv, allow_short),
|
||||
invalid_command_line_style);
|
||||
|
||||
BOOST_CHECK_THROW(cmdline cmd(1, (const char*const *)argv, allow_short |
|
||||
short_allow_next),
|
||||
invalid_command_line_style);
|
||||
if ('@' == s[0])
|
||||
return std::make_pair(string("some garbage"), s.substr(1));
|
||||
else
|
||||
return pair<string, string>();
|
||||
}
|
||||
|
||||
int test_main(int ac, char* av[])
|
||||
{
|
||||
// ### detail::test_cmdline_detail();
|
||||
|
||||
|
||||
void test_additional_parser()
|
||||
{
|
||||
options_description desc;
|
||||
desc.add_options()
|
||||
("response-file", value<string>(), "response file")
|
||||
("foo", value<int>(), "foo")
|
||||
;
|
||||
|
||||
vector<string> input;
|
||||
input.push_back("@config");
|
||||
input.push_back("--foo=1");
|
||||
|
||||
cmdline cmd(input);
|
||||
cmd.set_options_description(desc);
|
||||
cmd.set_additional_parser(at_option_parser);
|
||||
|
||||
vector<option> result = cmd.run();
|
||||
|
||||
BOOST_REQUIRE(result.size() == 2);
|
||||
BOOST_CHECK_EQUAL(result[0].string_key, "response-file");
|
||||
BOOST_CHECK_EQUAL(result[0].value[0], "config");
|
||||
BOOST_CHECK_EQUAL(result[1].string_key, "foo");
|
||||
BOOST_CHECK_EQUAL(result[1].value[0], "1");
|
||||
|
||||
// Test that invalid options returned by additional style
|
||||
// parser are detected.
|
||||
cmdline cmd2(input);
|
||||
cmd2.set_options_description(desc);
|
||||
cmd2.set_additional_parser(at_option_parser_broken);
|
||||
|
||||
BOOST_CHECK_THROW(cmd2.run(), unknown_option);
|
||||
|
||||
}
|
||||
|
||||
vector<option> at_option_parser2(vector<string>& args)
|
||||
{
|
||||
vector<option> result;
|
||||
if ('@' == args[0][0]) {
|
||||
// Simulate reading the response file.
|
||||
result.push_back(option("foo", vector<string>(1, "1")));
|
||||
result.push_back(option("bar", vector<string>(1, "1")));
|
||||
args.erase(args.begin());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
void test_style_parser()
|
||||
{
|
||||
options_description desc;
|
||||
desc.add_options()
|
||||
("foo", value<int>(), "foo")
|
||||
("bar", value<int>(), "bar")
|
||||
;
|
||||
|
||||
vector<string> input;
|
||||
input.push_back("@config");
|
||||
|
||||
cmdline cmd(input);
|
||||
cmd.set_options_description(desc);
|
||||
cmd.extra_style_parser(at_option_parser2);
|
||||
|
||||
vector<option> result = cmd.run();
|
||||
|
||||
BOOST_REQUIRE(result.size() == 2);
|
||||
BOOST_CHECK_EQUAL(result[0].string_key, "foo");
|
||||
BOOST_CHECK_EQUAL(result[0].value[0], "1");
|
||||
BOOST_CHECK_EQUAL(result[1].string_key, "bar");
|
||||
BOOST_CHECK_EQUAL(result[1].value[0], "1");
|
||||
}
|
||||
|
||||
void test_unregistered()
|
||||
{
|
||||
// Check unregisted option when no options are registed at all.
|
||||
options_description desc;
|
||||
|
||||
vector<string> input;
|
||||
input.push_back("--foo=1");
|
||||
input.push_back("--bar");
|
||||
input.push_back("1");
|
||||
input.push_back("-b");
|
||||
input.push_back("-biz");
|
||||
|
||||
cmdline cmd(input);
|
||||
cmd.set_options_description(desc);
|
||||
cmd.allow_unregistered();
|
||||
|
||||
vector<option> result = cmd.run();
|
||||
BOOST_REQUIRE(result.size() == 5);
|
||||
// --foo=1
|
||||
BOOST_CHECK_EQUAL(result[0].string_key, "foo");
|
||||
BOOST_CHECK_EQUAL(result[0].unregistered, true);
|
||||
BOOST_CHECK_EQUAL(result[0].value[0], "1");
|
||||
// --bar
|
||||
BOOST_CHECK_EQUAL(result[1].string_key, "bar");
|
||||
BOOST_CHECK_EQUAL(result[1].unregistered, true);
|
||||
BOOST_CHECK(result[1].value.empty());
|
||||
// '1' is considered a positional option, not a value to
|
||||
// --bar
|
||||
BOOST_CHECK(result[2].string_key.empty());
|
||||
BOOST_CHECK(result[2].position_key == 0);
|
||||
BOOST_CHECK_EQUAL(result[2].unregistered, false);
|
||||
BOOST_CHECK_EQUAL(result[2].value[0], "1");
|
||||
// -b
|
||||
BOOST_CHECK_EQUAL(result[3].string_key, "-b");
|
||||
BOOST_CHECK_EQUAL(result[3].unregistered, true);
|
||||
BOOST_CHECK(result[3].value.empty());
|
||||
// -biz
|
||||
BOOST_CHECK_EQUAL(result[4].string_key, "-b");
|
||||
BOOST_CHECK_EQUAL(result[4].unregistered, true);
|
||||
BOOST_CHECK_EQUAL(result[4].value[0], "iz");
|
||||
|
||||
// Check sticky short options together with unregisted options.
|
||||
|
||||
desc.add_options()
|
||||
("help,h", "")
|
||||
("magic,m", value<string>(), "")
|
||||
;
|
||||
|
||||
input.clear();
|
||||
input.push_back("-hc");
|
||||
input.push_back("-mc");
|
||||
|
||||
|
||||
cmdline cmd2(input);
|
||||
cmd2.set_options_description(desc);
|
||||
cmd2.allow_unregistered();
|
||||
|
||||
result = cmd2.run();
|
||||
|
||||
BOOST_REQUIRE(result.size() == 3);
|
||||
BOOST_CHECK_EQUAL(result[0].string_key, "help");
|
||||
BOOST_CHECK_EQUAL(result[0].unregistered, false);
|
||||
BOOST_CHECK(result[0].value.empty());
|
||||
BOOST_CHECK_EQUAL(result[1].string_key, "-c");
|
||||
BOOST_CHECK_EQUAL(result[1].unregistered, true);
|
||||
BOOST_CHECK(result[1].value.empty());
|
||||
BOOST_CHECK_EQUAL(result[2].string_key, "magic");
|
||||
BOOST_CHECK_EQUAL(result[2].unregistered, false);
|
||||
BOOST_CHECK_EQUAL(result[2].value[0], "c");
|
||||
|
||||
// CONSIDER:
|
||||
// There's a corner case:
|
||||
// -foo
|
||||
// when 'allow_long_disguise' is set. Should this be considered
|
||||
// disguised long option 'foo' or short option '-f' with value 'oo'?
|
||||
// It's not clear yet, so I'm leaving the decision till later.
|
||||
}
|
||||
|
||||
int main(int ac, char* av[])
|
||||
{
|
||||
test_long_options();
|
||||
test_short_options();
|
||||
test_dos_options();
|
||||
@@ -491,31 +608,9 @@ int test_main(int ac, char* av[])
|
||||
test_guessing();
|
||||
test_arguments();
|
||||
test_prefix();
|
||||
test_multiple();
|
||||
test_style_errors();
|
||||
|
||||
cmdline cmd((int)ac, (const char*const *)av,
|
||||
int(command_line_style::unix_style));
|
||||
cmd.add_option("version", 'v');
|
||||
cmd.add_option("help", 'h');
|
||||
cmd.add_option("verbose", 'V');
|
||||
cmd.add_option("magic", 'm');
|
||||
cmd.add_option("output", 'o', ':');
|
||||
|
||||
try {
|
||||
while(++cmd) {
|
||||
|
||||
if (cmd.at_argument()) {
|
||||
cout << "Argument : " << cmd.argument() << "\n";
|
||||
} else {
|
||||
cout << "Option : " << cmd.option_name()
|
||||
<< "(" << cmd.option_value() << ")\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
catch(exception& e) {
|
||||
cout << e.what() << "\n";
|
||||
}
|
||||
test_additional_parser();
|
||||
test_style_parser();
|
||||
test_unregistered();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
25
test/minitest.hpp
Normal file
25
test/minitest.hpp
Normal file
@@ -0,0 +1,25 @@
|
||||
#ifndef BOOST_PROGRAM_OPTIONS_MINITEST
|
||||
#define BOOST_PROGRAM_OPTIONS_MINITEST
|
||||
|
||||
#include <assert.h>
|
||||
#include <iostream>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define BOOST_REQUIRE(b) assert(b)
|
||||
#define BOOST_CHECK(b) assert(b)
|
||||
#define BOOST_CHECK_EQUAL(a, b) assert(a == b)
|
||||
#define BOOST_ERROR(description) std::cerr << description; std::cerr << "\n"; abort();
|
||||
#define BOOST_CHECK_THROW(expression, exception) \
|
||||
try \
|
||||
{ \
|
||||
expression; \
|
||||
BOOST_ERROR("expected exception not thrown");\
|
||||
throw 10; \
|
||||
} \
|
||||
catch(exception &) \
|
||||
{ \
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
@@ -10,89 +10,76 @@ using namespace boost::program_options;
|
||||
#include <boost/function.hpp>
|
||||
using namespace boost;
|
||||
|
||||
#define BOOST_INCLUDE_MAIN // for testing, include rather than link
|
||||
#include <boost/test/test_tools.hpp>
|
||||
|
||||
#include <utility>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
using namespace std;
|
||||
|
||||
/* This is very wierd test case -- it tests trivial things. After writing it,
|
||||
I think that XP folks must be somehow wrong.
|
||||
*/
|
||||
void test_option_description_construction()
|
||||
{
|
||||
option_description d1("a", new untyped_value(), "desc1");
|
||||
BOOST_TEST(d1.long_name() == "a");
|
||||
BOOST_TEST(d1.description() == "desc1");
|
||||
BOOST_TEST(d1.semantic()->name() == "arg");
|
||||
#include "minitest.hpp"
|
||||
|
||||
// It is not possible to compare boost::function
|
||||
#if 0
|
||||
function<string, string> f1;
|
||||
BOOST_TEST(&option_description("x", "y", "z").
|
||||
validator(f1).validator() ==
|
||||
&f1);
|
||||
function<void, string> f2;
|
||||
BOOST_TEST(&option_description("x", "y", "z").
|
||||
notify(f2).notify() ==
|
||||
&f2);
|
||||
#endif
|
||||
|
||||
option_description d4("foo,f", new untyped_value(), "desc1");
|
||||
BOOST_CHECK(d4.long_name() == "foo");
|
||||
BOOST_CHECK(d4.short_name() == "f");
|
||||
}
|
||||
|
||||
void test_options_description()
|
||||
void test_type()
|
||||
{
|
||||
options_description desc;
|
||||
|
||||
shared_ptr<option_description> d1(
|
||||
new option_description("first,f", new untyped_value(), ""));
|
||||
desc.add(d1);
|
||||
BOOST_TEST(desc.count("first") == 1);
|
||||
BOOST_TEST(desc.count("-f") == 1);
|
||||
BOOST_TEST(desc.keys().size() == 2);
|
||||
BOOST_TEST(desc.keys().count("first") == 1);
|
||||
BOOST_TEST(desc.keys().count("-f") == 1);
|
||||
|
||||
desc.add_options()
|
||||
("second,s", new untyped_value())
|
||||
("third,t", new untyped_value())
|
||||
("foo", value<int>(), "")
|
||||
("bar", value<std::string>(), "")
|
||||
;
|
||||
BOOST_TEST(desc.count("second") == 1);
|
||||
BOOST_TEST(desc.count("-s") == 1);
|
||||
|
||||
const typed_value_base* b = dynamic_cast<const typed_value_base*>
|
||||
(desc.find("foo", false).semantic().get());
|
||||
BOOST_CHECK(b);
|
||||
BOOST_CHECK(b->value_type() == typeid(int));
|
||||
|
||||
desc.add_options()
|
||||
(",x", new untyped_value)
|
||||
;
|
||||
BOOST_TEST(desc.primary_keys().size() == 4);
|
||||
BOOST_TEST(desc.primary_keys().count("first") == 1);
|
||||
BOOST_TEST(desc.primary_keys().count("second") == 1);
|
||||
BOOST_TEST(desc.primary_keys().count("third") == 1);
|
||||
BOOST_TEST(desc.primary_keys().count("-x") == 1);
|
||||
const typed_value_base* b2 = dynamic_cast<const typed_value_base*>
|
||||
(desc.find("bar", false).semantic().get());
|
||||
BOOST_CHECK(b2);
|
||||
BOOST_CHECK(b2->value_type() == typeid(std::string));
|
||||
}
|
||||
|
||||
void test_approximation()
|
||||
{
|
||||
options_description desc;
|
||||
desc.add_options()
|
||||
("foo", new untyped_value())
|
||||
("fee", new untyped_value())
|
||||
("baz", new untyped_value());
|
||||
("foo", new untyped_value())
|
||||
("fee", new untyped_value())
|
||||
("baz", new untyped_value())
|
||||
("all-chroots", new untyped_value())
|
||||
("all-sessions", new untyped_value())
|
||||
("all", new untyped_value())
|
||||
;
|
||||
|
||||
BOOST_TEST(desc.count_approx("f") == 2);
|
||||
BOOST_TEST(desc.count_approx("foo") == 1);
|
||||
set<string> a = desc.approximations("f");
|
||||
BOOST_TEST(a.size() == 2);
|
||||
BOOST_TEST(*a.begin() == "fee");
|
||||
BOOST_TEST(*(++a.begin()) == "foo");
|
||||
BOOST_CHECK_EQUAL(desc.find("fo", true).long_name(), "foo");
|
||||
|
||||
BOOST_CHECK_EQUAL(desc.find("all", true).long_name(), "all");
|
||||
BOOST_CHECK_EQUAL(desc.find("all-ch", true).long_name(), "all-chroots");
|
||||
|
||||
|
||||
// BOOST_CHECK(desc.count_approx("foo") == 1);
|
||||
// set<string> a = desc.approximations("f");
|
||||
// BOOST_CHECK(a.size() == 2);
|
||||
// BOOST_CHECK(*a.begin() == "fee");
|
||||
// BOOST_CHECK(*(++a.begin()) == "foo");
|
||||
}
|
||||
|
||||
int test_main(int, char* [])
|
||||
void test_formatting()
|
||||
{
|
||||
test_option_description_construction();
|
||||
test_options_description();
|
||||
// Long option descriptions used to crash on MSVC-8.0.
|
||||
options_description desc;
|
||||
desc.add_options()(
|
||||
"test", new untyped_value(),
|
||||
"foo foo foo foo foo foo foo foo foo foo foo foo foo foo"
|
||||
"foo foo foo foo foo foo foo foo foo foo foo foo foo foo"
|
||||
"foo foo foo foo foo foo foo foo foo foo foo foo foo foo"
|
||||
"foo foo foo foo foo foo foo foo foo foo foo foo foo foo");
|
||||
|
||||
stringstream ss;
|
||||
ss << desc;
|
||||
}
|
||||
|
||||
int main(int, char* [])
|
||||
{
|
||||
test_type();
|
||||
test_approximation();
|
||||
test_formatting();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
#include <boost/program_options/parsers.hpp>
|
||||
#include <boost/program_options/options_description.hpp>
|
||||
#include <boost/program_options/variables_map.hpp>
|
||||
using namespace boost::program_options;
|
||||
// We'll use po::value everywhere to workaround vc6 bug.
|
||||
namespace po = boost::program_options;
|
||||
@@ -13,13 +14,17 @@ namespace po = boost::program_options;
|
||||
#include <boost/function.hpp>
|
||||
using namespace boost;
|
||||
|
||||
#define BOOST_INCLUDE_MAIN // for testing, include rather than link
|
||||
#include <boost/test/test_tools.hpp>
|
||||
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
using namespace std;
|
||||
|
||||
#if defined(__sun)
|
||||
#include <stdlib.h> // for putenv on solaris
|
||||
#else
|
||||
#include <cstdlib> // for putenv
|
||||
#endif
|
||||
|
||||
#include "minitest.hpp"
|
||||
|
||||
#define TEST_CHECK_THROW(expression, exception, description) \
|
||||
try \
|
||||
@@ -60,6 +65,11 @@ vector<string> sv(char* array[], unsigned size)
|
||||
return r;
|
||||
}
|
||||
|
||||
pair<string, string> additional_parser(const std::string&)
|
||||
{
|
||||
return pair<string, string>();
|
||||
}
|
||||
|
||||
void test_command_line()
|
||||
{
|
||||
// The following commented out blocks used to test parsing
|
||||
@@ -74,14 +84,14 @@ void test_command_line()
|
||||
parse_command_line(cmdline1,
|
||||
cmdline1 + sizeof(cmdline1)/sizeof(cmdline1[0]));
|
||||
|
||||
BOOST_CRITICAL_TEST(a1.options().size() == 4);
|
||||
BOOST_TEST(a1.options()[0] == msp("a", ""));
|
||||
BOOST_TEST(a1.options()[1] == msp("b", "12"));
|
||||
BOOST_TEST(a1.options()[2] == msp("-f", ""));
|
||||
BOOST_TEST(a1.options()[3] == msp("-g", "4"));
|
||||
BOOST_CRITICAL_TEST(a1.arguments().size() == 2);
|
||||
BOOST_TEST(a1.arguments()[0] == "-");
|
||||
BOOST_TEST(a1.arguments()[1] == "file");
|
||||
BOOST_REQUIRE(a1.options().size() == 4);
|
||||
BOOST_CHECK(a1.options()[0] == msp("a", ""));
|
||||
BOOST_CHECK(a1.options()[1] == msp("b", "12"));
|
||||
BOOST_CHECK(a1.options()[2] == msp("-f", ""));
|
||||
BOOST_CHECK(a1.options()[3] == msp("-g", "4"));
|
||||
BOOST_REQUIRE(a1.arguments().size() == 2);
|
||||
BOOST_CHECK(a1.arguments()[0] == "-");
|
||||
BOOST_CHECK(a1.arguments()[1] == "file");
|
||||
|
||||
char* cmdline2[] = { "--a", "--", "file" };
|
||||
|
||||
@@ -89,42 +99,55 @@ void test_command_line()
|
||||
parse_command_line(cmdline2,
|
||||
cmdline2 + sizeof(cmdline2)/sizeof(cmdline2[0]));
|
||||
|
||||
BOOST_CRITICAL_TEST(a2.options().size() == 1);
|
||||
BOOST_TEST(a2.options()[0] == msp("a", ""));
|
||||
BOOST_TEST(a2.arguments().size() == 1);
|
||||
BOOST_TEST(a2.arguments()[0] == "file");
|
||||
BOOST_REQUIRE(a2.options().size() == 1);
|
||||
BOOST_CHECK(a2.options()[0] == msp("a", ""));
|
||||
BOOST_CHECK(a2.arguments().size() == 1);
|
||||
BOOST_CHECK(a2.arguments()[0] == "file");
|
||||
#endif
|
||||
|
||||
options_description desc;
|
||||
desc.add_options()
|
||||
("foo,f", new untyped_value(), "")
|
||||
// Explicit qualification is a workaround for vc6
|
||||
("bar,b", po::value<std::string>()->implicit(), "")
|
||||
("bar,b", po::value<std::string>(), "")
|
||||
("baz", new untyped_value())
|
||||
("plug*", new untyped_value())
|
||||
;
|
||||
char* cmdline3_[] = { "--foo=12", "-f4", "--bar=11", "--bar", "-b4", "-b",
|
||||
"--plug3=10"};
|
||||
char* cmdline3_[] = { "--foo=12", "-f4", "--bar=11", "-b4",
|
||||
"--plug3=10"};
|
||||
vector<string> cmdline3 = sv(cmdline3_,
|
||||
sizeof(cmdline3_)/sizeof(cmdline3_[0]));
|
||||
vector<option> a3 =
|
||||
command_line_parser(cmdline3).options(desc).run().options;
|
||||
|
||||
BOOST_CRITICAL_TEST(a3.size() == 7);
|
||||
BOOST_CHECK_EQUAL(a3.size(), 5u);
|
||||
|
||||
check_value(a3[0], "foo", "12");
|
||||
check_value(a3[1], "foo", "4");
|
||||
check_value(a3[2], "bar", "11");
|
||||
check_value(a3[3], "bar", "4");
|
||||
check_value(a3[4], "plug3", "10");
|
||||
|
||||
BOOST_TEST(a3[3].string_key == "bar");
|
||||
BOOST_CRITICAL_TEST(a3[3].value.size() == 0);
|
||||
// Regression test: check that '0' as style is interpreted as
|
||||
// 'default_style'
|
||||
vector<option> a4 =
|
||||
parse_command_line(5, cmdline3_, desc, 0, additional_parser).options;
|
||||
|
||||
BOOST_CHECK_EQUAL(a4.size(), 4u);
|
||||
check_value(a4[0], "foo", "4");
|
||||
check_value(a4[1], "bar", "11");
|
||||
|
||||
// Check that we don't crash on empty values of type 'string'
|
||||
char* cmdline4[] = {"", "--open", ""};
|
||||
options_description desc2;
|
||||
desc2.add_options()
|
||||
("open", po::value<string>())
|
||||
;
|
||||
variables_map vm;
|
||||
po::store(po::parse_command_line(3, cmdline4, desc2), vm);
|
||||
|
||||
check_value(a3[4], "bar", "4");
|
||||
|
||||
BOOST_TEST(a3[5].string_key == "bar");
|
||||
BOOST_CRITICAL_TEST(a3[5].value.size() == 0);
|
||||
|
||||
check_value(a3[6], "plug3", "10");
|
||||
}
|
||||
|
||||
void test_config_file()
|
||||
@@ -151,7 +174,7 @@ void test_config_file()
|
||||
|
||||
stringstream ss(content1);
|
||||
vector<option> a1 = parse_config_file(ss, desc).options;
|
||||
BOOST_CRITICAL_TEST(a1.size() == 5);
|
||||
BOOST_REQUIRE(a1.size() == 5);
|
||||
check_value(a1[0], "gv1", "0");
|
||||
check_value(a1[1], "plug3", "7");
|
||||
check_value(a1[2], "b", "true");
|
||||
@@ -184,11 +207,63 @@ void test_environment()
|
||||
// which already has a value.
|
||||
}
|
||||
|
||||
int test_main(int, char* [])
|
||||
void test_unregistered()
|
||||
{
|
||||
options_description desc;
|
||||
|
||||
char* cmdline1_[] = { "--foo=12", "--bar", "1"};
|
||||
vector<string> cmdline1 = sv(cmdline1_,
|
||||
sizeof(cmdline1_)/sizeof(cmdline1_[0]));
|
||||
vector<option> a1 =
|
||||
command_line_parser(cmdline1).options(desc).allow_unregistered().run()
|
||||
.options;
|
||||
|
||||
BOOST_REQUIRE(a1.size() == 3);
|
||||
BOOST_CHECK(a1[0].string_key == "foo");
|
||||
BOOST_CHECK(a1[0].unregistered == true);
|
||||
BOOST_REQUIRE(a1[0].value.size() == 1);
|
||||
BOOST_CHECK(a1[0].value[0] == "12");
|
||||
BOOST_CHECK(a1[1].string_key == "bar");
|
||||
BOOST_CHECK(a1[1].unregistered == true);
|
||||
BOOST_CHECK(a1[2].string_key == "");
|
||||
BOOST_CHECK(a1[2].unregistered == false);
|
||||
|
||||
|
||||
vector<string> a2 = collect_unrecognized(a1, include_positional);
|
||||
BOOST_CHECK(a2[0] == "--foo=12");
|
||||
BOOST_CHECK(a2[1] == "--bar");
|
||||
BOOST_CHECK(a2[2] == "1");
|
||||
|
||||
// Test that storing unregisted options has no effect
|
||||
variables_map vm;
|
||||
|
||||
store(command_line_parser(cmdline1).options(desc).
|
||||
allow_unregistered().run(),
|
||||
vm);
|
||||
|
||||
BOOST_CHECK_EQUAL(vm.size(), 0u);
|
||||
|
||||
|
||||
const char content1[] =
|
||||
"gv1 = 0\n"
|
||||
"[m1]\n"
|
||||
"v1 = 1\n"
|
||||
;
|
||||
|
||||
stringstream ss(content1);
|
||||
vector<option> a3 = parse_config_file(ss, desc, true).options;
|
||||
BOOST_REQUIRE(a3.size() == 2);
|
||||
cout << "XXX" << a3[0].value.front() << "\n";
|
||||
check_value(a3[0], "gv1", "0");
|
||||
check_value(a3[1], "m1.v1", "1");
|
||||
}
|
||||
|
||||
int main(int, char* [])
|
||||
{
|
||||
test_command_line();
|
||||
test_config_file();
|
||||
test_environment();
|
||||
test_unregistered();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -12,7 +12,8 @@ namespace po = boost::program_options;
|
||||
|
||||
|
||||
#include <boost/limits.hpp>
|
||||
#include <boost/test/test_tools.hpp>
|
||||
|
||||
#include "minitest.hpp"
|
||||
|
||||
#include <vector>
|
||||
using namespace std;
|
||||
@@ -34,7 +35,7 @@ void test_positional_options()
|
||||
|
||||
p.add("third", -1);
|
||||
|
||||
BOOST_CHECK_EQUAL(p.max_total_count(), std::numeric_limits<unsigned>::max());
|
||||
BOOST_CHECK_EQUAL(p.max_total_count(), (std::numeric_limits<unsigned>::max)());
|
||||
BOOST_CHECK_EQUAL(p.name_for_position(0), "first");
|
||||
BOOST_CHECK_EQUAL(p.name_for_position(1), "second");
|
||||
BOOST_CHECK_EQUAL(p.name_for_position(2), "second");
|
||||
@@ -49,28 +50,31 @@ void test_parsing()
|
||||
("first", po::value<int>())
|
||||
("second", po::value<int>())
|
||||
("input-file", po::value< vector<string> >())
|
||||
("some-other", po::value<string>())
|
||||
;
|
||||
|
||||
positional_options_description p;
|
||||
p.add("input-file", 2);
|
||||
p.add("input-file", 2).add("some-other", 1);
|
||||
|
||||
vector<string> args;
|
||||
args.push_back("--first=10");
|
||||
args.push_back("file1");
|
||||
args.push_back("--second=10");
|
||||
args.push_back("file2");
|
||||
args.push_back("file3");
|
||||
|
||||
// Check that positional options are handled.
|
||||
parsed_options parsed =
|
||||
command_line_parser(args).options(desc).positional(p).run();
|
||||
|
||||
BOOST_REQUIRE(parsed.options.size() == 4);
|
||||
BOOST_REQUIRE(parsed.options.size() == 5);
|
||||
BOOST_CHECK_EQUAL(parsed.options[1].string_key, "input-file");
|
||||
BOOST_CHECK_EQUAL(parsed.options[1].value[0], "file1");
|
||||
BOOST_CHECK_EQUAL(parsed.options[3].string_key, "input-file");
|
||||
BOOST_CHECK_EQUAL(parsed.options[3].value[0], "file2");
|
||||
BOOST_CHECK_EQUAL(parsed.options[4].value[0], "file3");
|
||||
|
||||
args.push_back("file3");
|
||||
args.push_back("file4");
|
||||
|
||||
// Check that excessive number of positional options is detected.
|
||||
BOOST_CHECK_THROW(command_line_parser(args).options(desc).positional(p)
|
||||
@@ -78,7 +82,7 @@ void test_parsing()
|
||||
too_many_positional_options_error);
|
||||
}
|
||||
|
||||
int test_main(int, char* [])
|
||||
int main(int, char* [])
|
||||
{
|
||||
test_positional_options();
|
||||
test_parsing();
|
||||
|
||||
@@ -3,11 +3,11 @@
|
||||
// (See accompanying file LICENSE_1_0.txt
|
||||
// or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <cassert>
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <iostream>
|
||||
#include <cassert>
|
||||
#include <boost/progress.hpp>
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/ref.hpp>
|
||||
@@ -15,6 +15,8 @@
|
||||
#include <boost/program_options/detail/convert.hpp>
|
||||
#include <boost/program_options/detail/utf8_codecvt_facet.hpp>
|
||||
|
||||
#include "minitest.hpp"
|
||||
|
||||
using namespace std;
|
||||
|
||||
string file_content(const string& filename)
|
||||
@@ -75,7 +77,7 @@ std::wstring from_8_bit_2(const std::string& s,
|
||||
void test_convert(const std::string& input,
|
||||
const std::string& expected_output)
|
||||
{
|
||||
boost::program_options::detail::utf8_codecvt_facet<wchar_t, char> facet;
|
||||
boost::program_options::detail::utf8_codecvt_facet facet;
|
||||
|
||||
std::wstring output;
|
||||
{
|
||||
@@ -94,7 +96,7 @@ void test_convert(const std::string& input,
|
||||
facet);
|
||||
}
|
||||
|
||||
assert(output.size()*2 == expected_output.size());
|
||||
BOOST_CHECK(output.size()*2 == expected_output.size());
|
||||
|
||||
for(unsigned i = 0; i < output.size(); ++i) {
|
||||
|
||||
@@ -103,23 +105,23 @@ void test_convert(const std::string& input,
|
||||
low &= 0xFF;
|
||||
unsigned low2 = expected_output[2*i];
|
||||
low2 &= 0xFF;
|
||||
assert(low == low2);
|
||||
BOOST_CHECK(low == low2);
|
||||
}
|
||||
{
|
||||
unsigned high = output[i];
|
||||
high >>= 8;
|
||||
high &= 0xFF;
|
||||
unsigned high2 = expected_output[2*i+1];
|
||||
assert(high == high2);
|
||||
BOOST_CHECK(high == high2);
|
||||
}
|
||||
}
|
||||
|
||||
string ref = boost::to_8_bit(output, facet);
|
||||
|
||||
assert(ref == input);
|
||||
BOOST_CHECK(ref == input);
|
||||
}
|
||||
|
||||
int test_main(int ac, char* av[])
|
||||
int main(int ac, char* av[])
|
||||
{
|
||||
std::string input = file_content("utf8.txt");
|
||||
std::string expected = file_content("ucs2.txt");
|
||||
|
||||
@@ -15,12 +15,11 @@ namespace po = boost::program_options;
|
||||
#include <boost/function.hpp>
|
||||
using namespace boost;
|
||||
|
||||
#define BOOST_INCLUDE_MAIN // for testing, include rather than link
|
||||
#include <boost/test/test_tools.hpp>
|
||||
|
||||
#include <sstream>
|
||||
using namespace std;
|
||||
|
||||
#include "minitest.hpp"
|
||||
|
||||
// Test that unicode input is forwarded to unicode option without
|
||||
// problems.
|
||||
void test_unicode_to_unicode()
|
||||
@@ -46,7 +45,7 @@ void test_unicode_to_unicode()
|
||||
void test_unicode_to_native()
|
||||
{
|
||||
std::codecvt<wchar_t, char, mbstate_t>* facet =
|
||||
new boost::program_options::detail::utf8_codecvt_facet<wchar_t, char>;
|
||||
new boost::program_options::detail::utf8_codecvt_facet;
|
||||
locale::global(locale(locale(), facet));
|
||||
|
||||
options_description desc;
|
||||
@@ -61,13 +60,13 @@ void test_unicode_to_native()
|
||||
variables_map vm;
|
||||
store(wcommand_line_parser(args).options(desc).run(), vm);
|
||||
|
||||
BOOST_TEST(vm["foo"].as<string>() == "\xD1\x8F");
|
||||
BOOST_CHECK(vm["foo"].as<string>() == "\xD1\x8F");
|
||||
}
|
||||
|
||||
void test_native_to_unicode()
|
||||
{
|
||||
std::codecvt<wchar_t, char, mbstate_t>* facet =
|
||||
new boost::program_options::detail::utf8_codecvt_facet<wchar_t, char>;
|
||||
new boost::program_options::detail::utf8_codecvt_facet;
|
||||
locale::global(locale(locale(), facet));
|
||||
|
||||
options_description desc;
|
||||
@@ -82,7 +81,7 @@ void test_native_to_unicode()
|
||||
variables_map vm;
|
||||
store(command_line_parser(args).options(desc).run(), vm);
|
||||
|
||||
BOOST_TEST(vm["foo"].as<wstring>() == L"\x044F");
|
||||
BOOST_CHECK(vm["foo"].as<wstring>() == L"\x044F");
|
||||
}
|
||||
|
||||
|
||||
@@ -107,19 +106,19 @@ void test_command_line()
|
||||
desc.add_options()
|
||||
("foo,f", new untyped_value(), "")
|
||||
// Explicit qualification is a workaround for vc6
|
||||
("bar,b", po::value<std::string>()->implicit(), "")
|
||||
("bar,b", po::value<std::string>(), "")
|
||||
("baz", new untyped_value())
|
||||
("plug*", new untyped_value())
|
||||
;
|
||||
|
||||
wchar_t* cmdline4_[] = { L"--foo=1\u0FF52", L"-f4", L"--bar=11", L"--bar",
|
||||
L"-b4", L"-b", L"--plug3=10"};
|
||||
wchar_t* cmdline4_[] = { L"--foo=1\u0FF52", L"-f4", L"--bar=11",
|
||||
L"-b4", L"--plug3=10"};
|
||||
vector<wstring> cmdline4 = sv(cmdline4_,
|
||||
sizeof(cmdline4_)/sizeof(cmdline4_[0]));
|
||||
vector<woption> a4 =
|
||||
wcommand_line_parser(cmdline4).options(desc).run().options;
|
||||
|
||||
BOOST_CRITICAL_TEST(a4.size() == 7);
|
||||
BOOST_REQUIRE(a4.size() == 5);
|
||||
|
||||
check_value(a4[0], "foo", L"1\u0FF52");
|
||||
check_value(a4[1], "foo", L"4");
|
||||
@@ -132,7 +131,7 @@ void test_command_line()
|
||||
void test_config_file()
|
||||
{
|
||||
std::codecvt<wchar_t, char, mbstate_t>* facet =
|
||||
new boost::program_options::detail::utf8_codecvt_facet<wchar_t, char>;
|
||||
new boost::program_options::detail::utf8_codecvt_facet;
|
||||
locale::global(locale(locale(), facet));
|
||||
|
||||
options_description desc;
|
||||
@@ -146,10 +145,10 @@ void test_config_file()
|
||||
variables_map vm;
|
||||
store(parse_config_file(stream, desc), vm);
|
||||
|
||||
BOOST_TEST(vm["foo"].as<string>() == "\xD1\x8F");
|
||||
BOOST_CHECK(vm["foo"].as<string>() == "\xD1\x8F");
|
||||
}
|
||||
|
||||
int test_main(int, char* [])
|
||||
int main(int, char* [])
|
||||
{
|
||||
test_unicode_to_unicode();
|
||||
test_unicode_to_native();
|
||||
|
||||
@@ -15,22 +15,10 @@ namespace po = boost::program_options;
|
||||
#include <boost/function.hpp>
|
||||
using namespace boost;
|
||||
|
||||
#define BOOST_INCLUDE_MAIN // for testing, include rather than link
|
||||
#include <boost/test/test_tools.hpp>
|
||||
|
||||
#include <sstream>
|
||||
using namespace std;
|
||||
|
||||
#define TEST_CHECK_THROW(expression, exception, description) \
|
||||
try \
|
||||
{ \
|
||||
expression; \
|
||||
BOOST_ERROR(description);\
|
||||
throw 10; \
|
||||
} \
|
||||
catch(exception &) \
|
||||
{ \
|
||||
}
|
||||
#include "minitest.hpp"
|
||||
|
||||
vector<string> sv(char* array[], unsigned size)
|
||||
{
|
||||
@@ -45,8 +33,8 @@ void test_variable_map()
|
||||
options_description desc;
|
||||
desc.add_options()
|
||||
("foo,f", new untyped_value)
|
||||
("bar,b", po::value<string>()->implicit())
|
||||
("biz,z", po::value<string>()->implicit())
|
||||
("bar,b", po::value<string>())
|
||||
("biz,z", po::value<string>())
|
||||
("baz", new untyped_value())
|
||||
("output,o", new untyped_value(), "")
|
||||
;
|
||||
@@ -57,12 +45,12 @@ void test_variable_map()
|
||||
variables_map vm;
|
||||
store(a3, vm);
|
||||
notify(vm);
|
||||
BOOST_CRITICAL_TEST(vm.size() == 4);
|
||||
BOOST_TEST(vm["foo"].as<string>() == "'12'");
|
||||
BOOST_TEST(vm["bar"].as<string>() == "11");
|
||||
BOOST_TEST(vm.count("biz") == 1);
|
||||
BOOST_TEST(vm["biz"].as<string>() == "3");
|
||||
BOOST_TEST(vm["output"].as<string>() == "foo");
|
||||
BOOST_REQUIRE(vm.size() == 4);
|
||||
BOOST_CHECK(vm["foo"].as<string>() == "'12'");
|
||||
BOOST_CHECK(vm["bar"].as<string>() == "11");
|
||||
BOOST_CHECK(vm.count("biz") == 1);
|
||||
BOOST_CHECK(vm["biz"].as<string>() == "3");
|
||||
BOOST_CHECK(vm["output"].as<string>() == "foo");
|
||||
|
||||
int i;
|
||||
desc.add_options()
|
||||
@@ -78,11 +66,11 @@ void test_variable_map()
|
||||
variables_map vm2;
|
||||
store(a4, vm2);
|
||||
notify(vm2);
|
||||
BOOST_CRITICAL_TEST(vm2.size() == 3);
|
||||
BOOST_TEST(vm2["zee"].as<bool>() == true);
|
||||
BOOST_TEST(vm2["zak"].as<int>() == 13);
|
||||
BOOST_TEST(vm2["opt"].as<bool>() == false);
|
||||
BOOST_TEST(i == 13);
|
||||
BOOST_REQUIRE(vm2.size() == 3);
|
||||
BOOST_CHECK(vm2["zee"].as<bool>() == true);
|
||||
BOOST_CHECK(vm2["zak"].as<int>() == 13);
|
||||
BOOST_CHECK(vm2["opt"].as<bool>() == false);
|
||||
BOOST_CHECK(i == 13);
|
||||
|
||||
options_description desc2;
|
||||
desc2.add_options()
|
||||
@@ -98,10 +86,29 @@ void test_variable_map()
|
||||
variables_map vm3;
|
||||
store(a5, vm3);
|
||||
notify(vm3);
|
||||
BOOST_CRITICAL_TEST(vm3.size() == 3);
|
||||
BOOST_TEST(vm3["vee"].as<string>() == "42");
|
||||
BOOST_TEST(vm3["voo"].as<string>() == "1");
|
||||
BOOST_TEST(vm3["iii"].as<int>() == 123);
|
||||
BOOST_REQUIRE(vm3.size() == 3);
|
||||
BOOST_CHECK(vm3["vee"].as<string>() == "42");
|
||||
BOOST_CHECK(vm3["voo"].as<string>() == "1");
|
||||
BOOST_CHECK(vm3["iii"].as<int>() == 123);
|
||||
|
||||
options_description desc3;
|
||||
desc3.add_options()
|
||||
("imp", po::value<int>()->implicit_value(100))
|
||||
("iim", po::value<int>()->implicit_value(200)->default_value(201))
|
||||
("mmp,m", po::value<int>()->implicit_value(123)->default_value(124))
|
||||
;
|
||||
char* cmdline6_[] = { "--imp=1", "-m" };
|
||||
vector<string> cmdline6 = sv(cmdline6_,
|
||||
sizeof(cmdline6_)/sizeof(cmdline6_[0]));
|
||||
parsed_options a6 = command_line_parser(cmdline6).options(desc3).run();
|
||||
|
||||
variables_map vm4;
|
||||
store(a6, vm4);
|
||||
notify(vm4);
|
||||
BOOST_REQUIRE(vm4.size() == 3);
|
||||
BOOST_CHECK(vm4["imp"].as<int>() == 1);
|
||||
BOOST_CHECK(vm4["iim"].as<int>() == 201);
|
||||
BOOST_CHECK(vm4["mmp"].as<int>() == 123);
|
||||
}
|
||||
|
||||
int stored_value;
|
||||
@@ -227,13 +234,54 @@ void test_priority()
|
||||
BOOST_CHECK_EQUAL(vm["include"].as< vector<int> >()[1], 7);
|
||||
}
|
||||
|
||||
void test_multiple_assignments_with_different_option_description()
|
||||
{
|
||||
// Test that if we store option twice into the same variable_map,
|
||||
// and some of the options stored the first time are not present
|
||||
// in the options descrription provided the second time, we don't crash.
|
||||
|
||||
options_description desc1("");
|
||||
desc1.add_options()
|
||||
("help,h", "")
|
||||
("includes", po::value< vector<string> >()->composing(), "");
|
||||
;
|
||||
|
||||
options_description desc2("");
|
||||
desc2.add_options()
|
||||
("output,o", "");
|
||||
|
||||
vector<string> input1;
|
||||
input1.push_back("--help");
|
||||
input1.push_back("--includes=a");
|
||||
parsed_options p1 = command_line_parser(input1).options(desc1).run();
|
||||
|
||||
vector<string> input2;
|
||||
input1.push_back("--output");
|
||||
parsed_options p2 = command_line_parser(input2).options(desc2).run();
|
||||
|
||||
vector<string> input3;
|
||||
input3.push_back("--includes=b");
|
||||
parsed_options p3 = command_line_parser(input3).options(desc1).run();
|
||||
|
||||
|
||||
int test_main(int, char* [])
|
||||
variables_map vm;
|
||||
store(p1, vm);
|
||||
store(p2, vm);
|
||||
store(p3, vm);
|
||||
|
||||
BOOST_REQUIRE(vm.count("help") == 1);
|
||||
BOOST_REQUIRE(vm.count("includes") == 1);
|
||||
BOOST_CHECK_EQUAL(vm["includes"].as< vector<string> >()[0], "a");
|
||||
BOOST_CHECK_EQUAL(vm["includes"].as< vector<string> >()[1], "b");
|
||||
|
||||
}
|
||||
|
||||
int main(int, char* [])
|
||||
{
|
||||
test_variable_map();
|
||||
test_semantic_values();
|
||||
test_priority();
|
||||
test_multiple_assignments_with_different_option_description();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -3,30 +3,46 @@
|
||||
// (See accompanying file LICENSE_1_0.txt
|
||||
// or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#ifdef _WIN32
|
||||
#if defined(_WIN32)
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <cctype>
|
||||
#include <iostream>
|
||||
#include <stdlib.h>
|
||||
|
||||
using namespace std;
|
||||
|
||||
#include <boost/program_options/parsers.hpp>
|
||||
using namespace boost::program_options;
|
||||
|
||||
#include <boost/test/test_tools.hpp>
|
||||
void check_equal(const std::vector<string>& actual, char **expected, int n)
|
||||
{
|
||||
if (actual.size() != n)
|
||||
{
|
||||
std::cerr << "Size mismatch between expected and actual data\n";
|
||||
abort();
|
||||
}
|
||||
for (int i = 0; i < n; ++i)
|
||||
{
|
||||
if (actual[i] != expected[i])
|
||||
{
|
||||
std::cerr << "Unexpected content\n";
|
||||
abort();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#include <boost/preprocessor/cat.hpp>
|
||||
|
||||
void test_winmain()
|
||||
{
|
||||
using namespace std;
|
||||
|
||||
#define C ,
|
||||
#define TEST(input, expected) \
|
||||
char* BOOST_PP_CAT(e, __LINE__)[] = expected;\
|
||||
vector<string> BOOST_PP_CAT(v, __LINE__) = split_winmain(input);\
|
||||
BOOST_REQUIRE(BOOST_PP_CAT(v, __LINE__).size() == \
|
||||
sizeof(BOOST_PP_CAT(e, __LINE__))/sizeof(char*));\
|
||||
BOOST_CHECK_EQUAL_COLLECTIONS(BOOST_PP_CAT(v, __LINE__).begin(),\
|
||||
BOOST_PP_CAT(v, __LINE__).end(),\
|
||||
BOOST_PP_CAT(e, __LINE__));
|
||||
check_equal(BOOST_PP_CAT(v, __LINE__), BOOST_PP_CAT(e, __LINE__),\
|
||||
sizeof(BOOST_PP_CAT(e, __LINE__))/sizeof(char*));
|
||||
|
||||
// The following expectations were obtained in Win2000 shell:
|
||||
TEST("1 ", {"1"});
|
||||
@@ -45,13 +61,13 @@ void test_winmain()
|
||||
TEST("1\\\\1 ", {"1\\\\1"});
|
||||
}
|
||||
|
||||
int test_main(int, char*[])
|
||||
int main(int, char*[])
|
||||
{
|
||||
test_winmain();
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
int test_main(int, char*[])
|
||||
int main(int, char*[])
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user