Compare commits

...

53 Commits

Author SHA1 Message Date
Ronald Garcia
2b9118089f Created a branch from trunk
[SVN r38959]
2007-08-26 05:34:35 +00:00
Vladimir Prus
8329c28a1a Apply patch to fix gcc warning.
Fixes #1209.


[SVN r38871]
2007-08-23 19:51:47 +00:00
Vladimir Prus
73cf706164 Remove V1 Jamfiles
[SVN r38516]
2007-08-08 19:02:26 +00:00
Vladimir Prus
e51a3ae742 Support for 'implicit' options.
Patch from Bryan Green.
Fixes #1131.


[SVN r38514]
2007-08-08 18:40:48 +00:00
Vladimir Prus
a0a661e4ec Fix examples Jamfile
[SVN r38507]
2007-08-08 17:15:09 +00:00
Vladimir Prus
c25408f6d2 Document config file support in more detail. Fixes #808. Fixes #1125.
[SVN r38495]
2007-08-07 13:55:41 +00:00
Vladimir Prus
63fca63679 Fix dependency
[SVN r38494]
2007-08-07 13:54:47 +00:00
Vladimir Prus
8c39e5aa8d When parsing vector<T>, use validator for
type T.
Fixes #1118.


[SVN r38459]
2007-08-05 18:38:07 +00:00
Vladimir Prus
d0aa5abee5 Implement support for unregistered options in config files. Closes #687.
[SVN r38191]
2007-07-11 19:39:06 +00:00
Vladimir Prus
90dc6b94d0 Clarify comment
[SVN r38190]
2007-07-11 19:37:51 +00:00
Vladimir Prus
2320c07267 Add todo
[SVN r38189]
2007-07-11 19:37:18 +00:00
Vladimir Prus
cd647f785a Fix #898. Two approximate matches followed by an exact match
no longer cause an ambiguity to be reported.


[SVN r38187]
2007-07-11 19:07:44 +00:00
Vladimir Prus
4223d3231d Fix typo
[SVN r38186]
2007-07-11 18:22:57 +00:00
Vladimir Prus
d1d5636365 Compilation fix for sun. Fixes #739.
[SVN r38109]
2007-06-28 07:09:38 +00:00
Vladimir Prus
c00c4a57db Define static const member in .cpp. Fixes #646.
[SVN r38108]
2007-06-28 07:05:50 +00:00
Vladimir Prus
8ad16ee97c Fix typo. Closes #749
[SVN r38107]
2007-06-28 06:54:11 +00:00
Vladimir Prus
0c3e43f2ce Fix typo. Closes #748
[SVN r38106]
2007-06-28 06:51:48 +00:00
Hartmut Kaiser
e42f028278 Fixed VC8 warnings about inconsistent dll export declarations.
[SVN r38099]
2007-06-26 19:13:33 +00:00
Eric Niebler
a29728e679 fix xincludes of doxygen-generated reference sections
[SVN r37571]
2007-05-03 01:18:48 +00:00
Vladimir Prus
232894cb3d Add missing include, to try to fix compilation on sun
[SVN r37005]
2007-02-19 19:27:54 +00:00
Daniel James
d39f2b5979 Merge fixed links from RC_1_34_0.
[SVN r36660]
2007-01-07 23:50:56 +00:00
Vladimir Prus
8c68a478c9 Fix dynamic linking
[SVN r35991]
2006-11-10 20:29:40 +00:00
Vladimir Prus
5d1345c5a9 Allow building of shared versions of some Boost.Test libraries.
Adjust tests to use always use static linking to Boost.Test, since
linking to the shared version requires test changes.

Patch from Juergen Hunold.


[SVN r35989]
2006-11-10 19:09:56 +00:00
Beman Dawes
a560d767fb Add copyright, license
[SVN r35905]
2006-11-07 19:11:57 +00:00
John Maddock
8c1982de82 Fix for Borland compilers.
[SVN r35652]
2006-10-18 12:33:54 +00:00
Vladimir Prus
928d7806f7 Make intel happy
[SVN r35034]
2006-09-07 08:06:16 +00:00
Hartmut Kaiser
b99ae04040 Fixed a dllimport/dllexport problem.
[SVN r34049]
2006-05-20 22:14:41 +00:00
Vladimir Prus
dc334deea7 Fix typo
[SVN r33990]
2006-05-18 06:06:18 +00:00
Vladimir Prus
de66d37405 Make positional_options_description::add return reference to *this.
[SVN r33989]
2006-05-18 05:59:56 +00:00
Vladimir Prus
a4375600a2 Make validation_error::what public, as it's public in std::exception.
[SVN r33969]
2006-05-15 14:05:47 +00:00
Vladimir Prus
bec34dd1b9 Note that variables_map is inherited from std::map, since BoostBook
"hides" that information.


[SVN r33786]
2006-04-24 09:50:30 +00:00
Vladimir Prus
7b73b2e84c Fix typos.
Thanks to Olaf van der Spek for the report!


[SVN r33784]
2006-04-24 09:41:22 +00:00
Vladimir Prus
2625de2dd0 If additional parser returns empty string as value, assume there's no value.
[SVN r33782]
2006-04-24 09:14:57 +00:00
Vladimir Prus
ac6de20f85 Clarify special handling of vectors.
[SVN r33780]
2006-04-24 08:51:38 +00:00
Vladimir Prus
3765e8e8e9 Fix accesses to first element of an empty string.
Thanks to Olaf van der Spek for the report.


[SVN r33778]
2006-04-24 08:25:12 +00:00
Vladimir Prus
026c527d8d Workaround "interator incremented past the end" assertion in MSVC-8.0.
[SVN r33776]
2006-04-24 08:00:13 +00:00
Dave Abrahams
8f0bc7ad72 Stop using assert() in tests
[SVN r33181]
2006-02-28 22:56:33 +00:00
Vladimir Prus
48ee128928 Set BOOST_ALL_NO_LIB for _dll tests
[SVN r32884]
2006-02-13 09:04:49 +00:00
Vladimir Prus
596f8aa46f Remove remaining occurences of "implicit" method from the docs.
[SVN r32265]
2006-01-09 09:53:20 +00:00
Vladimir Prus
cbe799d914 Ignore unregisted options in 'store'.
[SVN r32264]
2006-01-09 09:44:44 +00:00
Vladimir Prus
5e4b39d672 Fix SF bug 1395874. When both "all" and "all-chroots" options were registered
and "--all" was specified on command line and approximation was on,
ambiguity was reported. Now, "all" is recognized.


[SVN r32263]
2006-01-09 09:06:24 +00:00
Vladimir Prus
d8c809b0a3 Fix wide version of split_winmain.
Patch from Tilman Sohr.


[SVN r32262]
2006-01-09 08:42:26 +00:00
Vladimir Prus
881c3b4e3a Fix typo.
[SVN r32174]
2005-12-28 07:28:45 +00:00
Vladimir Prus
e17d52165f Minor editorial changes.
[SVN r32135]
2005-12-22 09:39:11 +00:00
Vladimir Prus
6e7b140c98 Fix asserts in format_paragraph on VC 8.0 -- the reverse iterator was
incorrectly used. Generally clean up the code.


[SVN r32133]
2005-12-22 09:29:14 +00:00
Vladimir Prus
4cde608b3e Fix type in reference to 'check_first_occurrence'.
[SVN r31993]
2005-12-12 06:20:47 +00:00
Hartmut Kaiser
7bc84f1b39 Fixed a Windows build problem.
[SVN r31793]
2005-11-27 23:58:05 +00:00
Vladimir Prus
3400019810 Cast argument to isspace to 'unsigned char'. Otherwise, if base char
type is signed, and a specific value is 8-bit and so negative,
we get implicit char->int conversion that does sign-extending. However,
the 'isspace' function requires that the value be either representable in
'unsigned char', or be EOF.


[SVN r31765]
2005-11-24 09:25:38 +00:00
Vladimir Prus
e1d38380f4 Allow to query the type of options:
- add new class typed_value_base, with "value_type" method
- derived typed_value from typed_value_base

Idea from Giuseppe Vacanti.


[SVN r31752]
2005-11-23 09:14:02 +00:00
Vladimir Prus
f2e43384fb Note that positional options must be still registered.
[SVN r31740]
2005-11-22 12:43:23 +00:00
Vladimir Prus
78f209eb0b Add test for unregisted options on the command_line_parser level.
[SVN r31614]
2005-11-10 08:15:44 +00:00
Vladimir Prus
e7e1550269 Add 'extra_style_parser' method to basic_command_line_parser. Previously
this functionality was not available to use user due to private
derivation from detail::cmdline.


[SVN r31491]
2005-10-27 09:42:13 +00:00
Vladimir Prus
a00a6c9d19 Really make unregistered options to work.
- Add forwarding method allow_unregistered to the basic_command_line parser
  class.
- Add new 'collect_unrecognized' function
- Add new field 'original_tokens' to the basic_option class


[SVN r31490]
2005-10-27 09:20:16 +00:00
40 changed files with 706 additions and 305 deletions

View File

@@ -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

View File

@@ -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 ] ;

View File

@@ -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

View File

@@ -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&lt;string&gt; 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:
-->

View File

@@ -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>
&nbsp;<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>

View File

@@ -181,7 +181,7 @@ options_description desc;
desc.add_options()
("help", "produce help message")
("compression", value&lt;string&gt;(), "compression level")
("verbose", value&lt;string&gt;()->implicit(), "verbosity level")
("verbose", value&lt;string&gt;()->zero_tokens(), "verbosity level")
("email", value&lt;string&gt;()->multitoken(), "email to send to")
;
</programlisting>
@@ -348,11 +348,18 @@ positional_options_description pd; pd.add("input-file", 1);
given the same name.
<programlisting>
positional_options_description pd;
pd.add("output-file", 2).add_optional("input-file", -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>
@@ -471,7 +478,45 @@ notify(vm);
<title>Specific parsers</title>
<section>
<title>Environment variables</title>
<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
@@ -481,7 +526,7 @@ notify(vm);
<filename>autoexec.bat</filename> file or (on recent versions) the
<filename>Control Panel/System/Advanced/Environment Variables</filename>
dialog, and on Unix &#x2014;, the <filename>/etc/profile</filename>,
<filename>~/profile</filename> and <filename>~/bash_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>
@@ -560,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>

View File

@@ -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>">

View File

@@ -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>

View File

@@ -1,4 +1,8 @@
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).

View File

@@ -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>&amp;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

View File

@@ -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 ;

View File

@@ -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 ;

View File

@@ -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)
{

View File

@@ -12,13 +12,13 @@ namespace boost { namespace program_options { namespace command_line_style {
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 option is also configurable.
for short options is also configurable.
Option's value can be specified in the same token as value
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 option by the same character as
long option, see allow_long_disguise.
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.
@@ -39,7 +39,7 @@ namespace boost { namespace program_options { namespace command_line_style {
@endverbatim
*/
long_allow_adjacent = allow_slash_for_short << 1,
/** Allow option parameter in the same token for
/** 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
@@ -59,7 +59,7 @@ namespace boost { namespace program_options { namespace command_line_style {
/** Allow abbreviated spellings for long options,
if they unambiguously identify long option.
No long option name should be prefix of other
long option name is guessing is in effect.
long option name if guessing is in effect.
*/
allow_guessing = allow_sticky << 1,
/** Ignore the difference in case for options.

View File

@@ -70,7 +70,8 @@ namespace boost { namespace program_options { namespace detail {
public:
common_config_file_iterator() { found_eof(); }
common_config_file_iterator(
const std::set<std::string>& allowed_options);
const std::set<std::string>& allowed_options,
bool allow_unregistered = false);
virtual ~common_config_file_iterator() {}
@@ -103,6 +104,7 @@ namespace boost { namespace program_options { namespace detail {
// 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>
@@ -116,7 +118,8 @@ namespace boost { namespace program_options { namespace detail {
/** 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);
const std::set<std::string>& allowed_options,
bool allow_unregistered = false);
private: // base overrides
@@ -139,8 +142,9 @@ namespace boost { namespace program_options { namespace detail {
template<class charT>
basic_config_file_iterator<charT>::
basic_config_file_iterator(std::basic_istream<charT>& is,
const std::set<std::string>& allowed_options)
: common_config_file_iterator(allowed_options)
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();

View File

@@ -76,6 +76,24 @@ namespace boost { namespace program_options {
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()
@@ -101,6 +119,26 @@ namespace boost { namespace program_options {
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

View File

@@ -16,7 +16,13 @@ namespace boost { namespace program_options {
std::string
typed_value<T, charT>::name() const
{
if (!m_default_value.empty() && !m_default_value_as_text.empty()) {
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;
@@ -134,7 +140,14 @@ namespace boost { namespace program_options {
for (unsigned i = 0; i < s.size(); ++i)
{
try {
tv->push_back(boost::lexical_cast<T>(s[i]));
/* 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]));
@@ -148,7 +161,13 @@ namespace boost { namespace program_options {
xparse(boost::any& value_store,
const std::vector<std::basic_string<charT> >& new_tokens) const
{
validate(value_store, new_tokens, (T*)0, 0);
// 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>

View File

@@ -82,11 +82,12 @@ namespace boost { namespace program_options {
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.
const char* what() const throw();
};
class BOOST_PROGRAM_OPTIONS_DECL invalid_option_value

View File

@@ -41,10 +41,16 @@ namespace boost { namespace program_options {
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. */
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;

View File

@@ -78,10 +78,12 @@ namespace program_options {
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.
*/
bool match(const std::string& option, bool approx) const;
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.
@@ -153,7 +155,7 @@ namespace program_options {
*/
class BOOST_PROGRAM_OPTIONS_DECL options_description {
public:
static const unsigned m_default_line_length = 80;
static const unsigned m_default_line_length;
/** Creates the instance. */
options_description(unsigned line_length = m_default_line_length);

View File

@@ -73,13 +73,16 @@ namespace boost { namespace program_options {
/** Command line parser.
The class allows one to specify all the information needed for parsing
and to parser the parse the command line. It is primarily needed to
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 {
@@ -90,7 +93,7 @@ namespace boost { namespace program_options {
basic_command_line_parser(const std::vector<
std::basic_string<charT> >& args);
/** Creates a command line parser for the specified arguments
list. The parameter should be the same as passes to 'main'.
list. The parameters should be the same as passed to 'main'.
*/
basic_command_line_parser(int argc, charT* argv[]);
@@ -104,8 +107,26 @@ namespace boost { namespace program_options {
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;
};
@@ -132,7 +153,24 @@ namespace boost { namespace program_options {
BOOST_PROGRAM_OPTIONS_DECL
#endif
basic_parsed_options<charT>
parse_config_file(std::basic_istream<charT>&, const options_description&);
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.
@@ -180,6 +218,7 @@ namespace boost { namespace program_options {
split_winmain(const std::wstring& cmdline);
#endif
#endif
}}

View File

@@ -37,7 +37,8 @@ namespace boost { namespace program_options {
No calls to 'add' can be made after call with 'max_value' equal to
'-1'.
*/
void add(const char* name, int max_count);
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

View File

@@ -14,9 +14,9 @@
#include <boost/lexical_cast.hpp>
#include <string>
#include <vector>
#include <typeinfo>
namespace boost { namespace program_options {
@@ -74,6 +74,13 @@ namespace boost { namespace program_options {
// 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 {
@@ -87,6 +94,13 @@ namespace boost { namespace program_options {
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 {
@@ -101,6 +115,7 @@ namespace boost { namespace program_options {
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
@@ -134,9 +149,29 @@ namespace boost { namespace program_options {
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> {
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. */
@@ -169,6 +204,38 @@ namespace boost { namespace program_options {
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)
@@ -208,7 +275,7 @@ namespace boost { namespace program_options {
unsigned min_tokens() const
{
if (m_zero_tokens) {
if (m_zero_tokens || !m_implicit_value.empty()) {
return 0;
} else {
return 1;
@@ -227,7 +294,7 @@ namespace boost { namespace program_options {
/** Creates an instance of the 'validator' class and calls
its operator() to perform athe ctual conversion. */
its operator() to perform the actual conversion. */
void xparse(boost::any& value_store,
const std::vector< std::basic_string<charT> >& new_tokens)
const;
@@ -250,6 +317,13 @@ namespace boost { namespace program_options {
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:
@@ -259,6 +333,8 @@ namespace boost { namespace program_options {
// 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;
};

View File

@@ -24,6 +24,29 @@ namespace boost { namespace program_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.
*/
@@ -36,10 +59,15 @@ namespace boost { namespace program_options {
/** If stored value if of type T, returns that value. Otherwise,
throws boost::bad_any_cast exception. */
template<class T> const T& as() const;
/** @overload */
template<class T> T& as();
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;
@@ -61,10 +89,10 @@ namespace boost { namespace program_options {
// be easily accessible, so we need to store semantic here.
shared_ptr<const value_semantic> m_value_semantic;
friend void BOOST_PROGRAM_OPTIONS_DECL
store(const basic_parsed_options<char>& options,
friend BOOST_PROGRAM_OPTIONS_DECL
void store(const basic_parsed_options<char>& options,
variables_map& m, bool);
friend void BOOST_PROGRAM_OPTIONS_DECL notify(variables_map& m);
friend BOOST_PROGRAM_OPTIONS_DECL void notify(variables_map& m);
};
/** Implements string->string mapping with convenient value casting
@@ -104,7 +132,11 @@ namespace boost { namespace program_options {
const abstract_variables_map* m_next;
};
/** Concrete variables map which store variables in real map. */
/** Concrete variables map which store variables in real map.
This class is derived from std::map<std::string, variable_value>,
so you can use all map operators to examine its content.
*/
class BOOST_PROGRAM_OPTIONS_DECL variables_map : public abstract_variables_map,
public std::map<std::string, variable_value>
{
@@ -125,30 +157,12 @@ namespace boost { namespace program_options {
be changed by subsequence assignments. */
std::set<std::string> m_final;
friend void store(const basic_parsed_options<char>& options,
friend BOOST_PROGRAM_OPTIONS_DECL
void store(const basic_parsed_options<char>& options,
variables_map& xm,
bool utf8);
};
/** 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);
/*
* Templates/inlines
@@ -180,18 +194,6 @@ namespace boost { namespace program_options {
return v;
}
template<class T>
const T&
variable_value::as() const {
return boost::any_cast<const T&>(v);
}
template<class T>
T&
variable_value::as() {
return boost::any_cast<T&>(v);
}
}}
#endif

View File

@@ -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>
&nbsp;<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>

View File

@@ -248,6 +248,7 @@ namespace boost { namespace program_options { namespace detail {
if (!ok) {
option opt;
opt.value.push_back(args[0]);
opt.original_tokens.push_back(args[0]);
result.push_back(opt);
args.erase(args.begin());
}
@@ -328,9 +329,18 @@ namespace boost { namespace program_options { namespace detail {
max_tokens -= opt.value.size();
// A value is optional if min_tokens == 0, but max_tokens > 0.
// If a value is optional, it must appear in opt.value (because
// it was 'adjacent'. Otherwise, remove the expectation of a
// non-adjacent value. (For now, we just check max_tokens == 1,
// as there is no current support for max_tokens>1)
if (min_tokens == 0 && max_tokens == 1 && opt.value.empty())
--max_tokens;
// Everything's OK, move the values to the result.
for(;!other_tokens.empty() && max_tokens--; ) {
opt.value.push_back(other_tokens[0]);
opt.original_tokens.push_back(other_tokens[0]);
other_tokens.erase(other_tokens.begin());
}
}
@@ -368,6 +378,7 @@ namespace boost { namespace program_options { namespace detail {
opt.string_key = name;
if (!adjacent.empty())
opt.value.push_back(adjacent);
opt.original_tokens.push_back(tok);
result.push_back(opt);
args.erase(args.begin());
}
@@ -416,6 +427,7 @@ namespace boost { namespace program_options { namespace detail {
option opt;
opt.string_key = name;
opt.original_tokens.push_back(tok);
if (!adjacent.empty())
opt.value.push_back(adjacent);
result.push_back(opt);
@@ -442,6 +454,7 @@ namespace boost { namespace program_options { namespace detail {
opt.string_key = name;
if (!adjacent.empty())
opt.value.push_back(adjacent);
opt.original_tokens.push_back(tok);
result.push_back(opt);
args.erase(args.begin());
}
@@ -493,7 +506,8 @@ namespace boost { namespace program_options { namespace detail {
if (!r.first.empty()) {
option next;
next.string_key = r.first;
next.value.push_back(r.second);
if (!r.second.empty())
next.value.push_back(r.second);
result.push_back(next);
args.erase(args.begin());
}

View File

@@ -21,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();
@@ -100,7 +102,8 @@ 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))
bool registered = allowed_option(name);
if (!registered && !m_allow_unregistered)
boost::throw_exception(unknown_option(name));
if (value.empty())
@@ -110,6 +113,7 @@ namespace boost { namespace program_options { namespace detail {
this->value().string_key = name;
this->value().value.clear();
this->value().value.push_back(value);
this->value().unregistered = !registered;
break;
} else {

View File

@@ -23,6 +23,7 @@
#include <cstring>
#include <cstdarg>
#include <sstream>
#include <iterator>
using namespace std;
namespace boost { namespace program_options {
@@ -53,10 +54,10 @@ namespace boost { namespace program_options {
{
}
bool
option_description::match_result
option_description::match(const std::string& option, bool approx) const
{
bool result = false;
match_result result = no_match;
if (!m_long_name.empty()) {
if (*m_long_name.rbegin() == '*')
@@ -65,23 +66,26 @@ namespace boost { namespace program_options {
// prefix is OK.
if (option.find(m_long_name.substr(0, m_long_name.length()-1))
== 0)
result = true;
result = approximate_match;
}
if (approx)
{
if (m_long_name.find(option) == 0)
result = true;
if (m_long_name == option)
result = full_match;
else
result = approximate_match;
}
else
{
if (m_long_name == option)
result = true;
result = full_match;
}
}
if (m_short_name == option)
result = true;
result = full_match;
return result;
}
@@ -197,6 +201,8 @@ namespace boost { namespace program_options {
return *this;
}
const unsigned options_description::m_default_line_length = 80;
options_description::options_description(unsigned line_length)
: m_line_length(line_length)
{}
@@ -248,38 +254,47 @@ namespace boost { namespace program_options {
return m_options;
}
const option_description*
const option_description*
options_description::find_nothrow(const std::string& name,
bool approx) const
{
int found = -1;
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)
{
if (m_options[i]->match(name, approx))
option_description::match_result r =
m_options[i]->match(name, approx);
if (r == option_description::no_match)
continue;
// 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.
if (r == option_description::full_match)
{
if (found != -1)
{
vector<string> alts;
// FIXME: the use of 'key' here might not
// be the best approach.
alts.push_back(m_options[found]->key(name));
alts.push_back(m_options[i]->key(name));
boost::throw_exception(ambiguous_option(name, alts));
}
else
{
found = i;
}
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 (found != -1) {
return m_options[found].get();
} else {
return 0;
}
if (approximate_matches.size() > 1)
boost::throw_exception(
ambiguous_option(name, approximate_matches));
return found.get();
}
BOOST_PROGRAM_OPTIONS_DECL
@@ -291,11 +306,26 @@ 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 first_column_width,
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
@@ -319,16 +349,16 @@ namespace boost { namespace program_options {
// this assert may fail due to user error or
// environment conditions!
assert(par_indent < (line_length - first_column_width));
assert(par_indent < line_length);
// ignore tab if not on first line
if (par_indent >= (line_length - first_column_width))
if (par_indent >= line_length)
{
par_indent = 0;
}
}
if (par.size() < (line_length - first_column_width))
if (par.size() < line_length)
{
os << par;
}
@@ -337,17 +367,16 @@ namespace boost { namespace program_options {
string::const_iterator line_begin = par.begin();
const string::const_iterator par_end = par.end();
bool first_line = true; // of current paragraph!
unsigned indent = first_column_width;
bool first_line = true; // of current paragraph!
while (line_begin < par_end) // paragraph lines
{
if (!first_line)
{
// trimm leading single spaces
// if (firstchar == ' ') &&
// ((exists(firstchar + 1) && (firstchar + 1 != ' '))
// 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) != ' ')))
@@ -356,31 +385,26 @@ namespace boost { namespace program_options {
}
}
string::const_iterator line_end;
if (line_begin + (line_length - indent) > par_end)
{
line_end = par_end;
}
else
{
line_end = line_begin + (line_length - indent);
}
// 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
// if (lastchar != ' ') &&
// ((exists(lastchar + 1) && (lastchar + 1 != ' '))
// 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 - 1),
reverse_iterator<string::const_iterator>(line_begin - 1),
find(reverse_iterator<string::const_iterator>(line_end),
reverse_iterator<string::const_iterator>(line_begin),
' ')
.base();
if (last_space != line_begin - 1)
if (last_space != line_begin)
{
// is last_space within the second half ot the
// current line
@@ -397,7 +421,7 @@ namespace boost { namespace program_options {
if (first_line)
{
indent = first_column_width + par_indent;
indent += par_indent;
first_line = false;
}
@@ -436,7 +460,7 @@ namespace boost { namespace program_options {
assert(line_length > first_column_width);
// Note: can't use 'tokenizer' as name of typedef -- borland
// will consider subsequence uses of 'tokenizer' as uses of
// will consider uses of 'tokenizer' below as uses of
// boost::tokenizer, not typedef.
typedef boost::tokenizer<boost::char_separator<char> > tok;

View File

@@ -88,7 +88,8 @@ namespace boost { namespace program_options {
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;
@@ -106,7 +107,8 @@ namespace boost { namespace program_options {
// 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.
@@ -116,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,

View File

@@ -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,7 +27,7 @@ namespace boost { namespace program_options {
else {
m_names.resize(m_names.size() + max_count, name);
}
return *this;
}
unsigned

View File

@@ -122,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)
@@ -170,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);
}

View File

@@ -35,14 +35,25 @@ namespace boost { namespace program_options {
std::set<std::string> new_final;
// 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 (xm.m_final.count(name))
continue;
@@ -84,7 +95,7 @@ namespace boost { namespace program_options {
// Second, apply default values.
const vector<shared_ptr<option_description> >& all = desc.options();
for(unsigned i = 0; i < all.size(); ++i)
for(i = 0; i < all.size(); ++i)
{
const option_description& d = *all[i];
string key = d.key("");

View File

@@ -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;
}

View File

@@ -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 ]
;

View File

@@ -2,7 +2,7 @@
project
: requirements
<library>../build//boost_program_options
<library>/boost/test//boost_test_exec_monitor
<library>/boost/test//boost_test_exec_monitor/<link>static
<link>static
# <define>_GLIBCXX_CONCEPT_CHECKS
@@ -13,7 +13,8 @@ rule po-test ( source )
{
return
[ run $(source) ]
[ run $(source) : : : <link>shared : $(source:B)_dll ]
[ run $(source) : : : <link>shared <define>BOOST_PROGRAM_OPTIONS_DYN_LINK=1
: $(source:B)_dll ]
;
}

View File

@@ -14,17 +14,47 @@ using namespace boost;
#include <boost/test/test_tools.hpp>
#include <utility>
#include <string>
#include <sstream>
using namespace std;
void test_type()
{
options_description desc;
desc.add_options()
("foo", value<int>(), "")
("bar", value<std::string>(), "")
;
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));
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_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);
@@ -32,8 +62,25 @@ void test_approximation()
// BOOST_CHECK(*(++a.begin()) == "foo");
}
void test_formatting()
{
// 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 test_main(int, char* [])
{
test_type();
test_approximation();
test_formatting();
return 0;
}

View File

@@ -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;
@@ -17,9 +18,14 @@ using namespace boost;
#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
#define TEST_CHECK_THROW(expression, exception, description) \
try \
@@ -132,6 +138,16 @@ void test_command_line()
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);
}
@@ -192,11 +208,63 @@ void test_environment()
// which already has a value.
}
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 test_main(int, char* [])
{
test_command_line();
test_config_file();
test_environment();
test_unregistered();
return 0;
}

View File

@@ -49,28 +49,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)

View File

@@ -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 <boost/test/test_tools.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,20 +105,20 @@ 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[])

View File

@@ -102,6 +102,25 @@ void test_variable_map()
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;