Compare commits

..

107 Commits

Author SHA1 Message Date
Beman Dawes
f9bb3e5db9 Branch at revision 46530
[SVN r46531]
2008-06-19 18:57:10 +00:00
Marshall Clow
4dcce9efce Replaced all occurrences of non-ASCII copyright symbol with '(c)' for people using non-ASCII code pages
[SVN r43992]
2008-04-02 01:42:32 +00:00
Vladimir Prus
316e2fabe4 Tolerate argc being zero.
Patch from C. K. Jester-Young.


[SVN r43207]
2008-02-10 13:13:41 +00:00
Beman Dawes
152fbd8384 // Add or correct comment identifying Boost library this header is associated with.
[SVN r41173]
2007-11-17 20:13:16 +00:00
Vladimir Prus
80361c6b8f Fix winmain test
[SVN r40487]
2007-10-26 19:37:56 +00:00
Vladimir Prus
a3d19d354a Make sure every library can be installed by using
bjam stage|install

in libs/<library>/build.


[SVN r40475]
2007-10-26 09:04:25 +00:00
Vladimir Prus
86aeaf478d Don't use boost.test for testing.
[SVN r40463]
2007-10-25 17:08:27 +00:00
Hartmut Kaiser
7ba4ac9c14 ProgramOptions: Silenced VC++ warnings.
[SVN r39720]
2007-10-05 23:27:43 +00:00
Hartmut Kaiser
d343dda27e Trying to work around a SUN 5.8 compiler error.
[SVN r39686]
2007-10-04 17:49:20 +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
John Maddock
84cc0d2972 Large patch from Ulrich Eckhardt to fix support for EVC++ 4.
[SVN r30670]
2005-08-25 16:27:28 +00:00
Dave Abrahams
d43c947002 Fix broken link
[SVN r30559]
2005-08-12 19:49:30 +00:00
Douglas Gregor
e6e1ef29db Fixup uses of max
[SVN r30059]
2005-07-13 16:32:41 +00:00
Markus Schöpflin
78c3d90280 Fixed previous checkin.
[SVN r29621]
2005-06-16 13:23:17 +00:00
Markus Schöpflin
2f17c3b9b9 Added workaround for Tru64/CXX, getline() is not defined in <string> when
compiling in strict ansi mode. This is a bug in the string header file.


[SVN r29617]
2005-06-16 12:49:32 +00:00
Vladimir Prus
a78a1f0d76 Unroll 'make parse_command_line' const-correct patch, because it causes too
much troubles. Basically, consider;

    char* cmdline3_[1] = {};

    template<class charT>
    void func(const charT* const argv[]) {}

    int main()
    {
        func(cmdline3_);
        char** p = cmdline3_;
        func(p);
    }

EDG compilers can't deduce template argument in the first call. See
http://thread.gmane.org/gmane.comp.lib.boost.devel/125396 for details.
Some other compilers (borland, vc 7.0) see to be have this issue too.


[SVN r29615]
2005-06-16 10:44:23 +00:00
Vladimir Prus
5af27a78e7 Use boost::throw_exception instead just throw_exception. Otherwise, borland
"forgets" to generate code for the function call.


[SVN r29614]
2005-06-16 10:29:49 +00:00
Vladimir Prus
de511c601a Make install target explicit. Otherwise top-level Jamfile will try to
install both results of 'boost_program_options' and of the install target,
resulting in duplicate target error.


[SVN r29604]
2005-06-16 07:51:56 +00:00
Vladimir Prus
f88e0a9572 Attempt to fix VC7 parse error.
[SVN r29400]
2005-06-03 10:38:24 +00:00
Vladimir Prus
1fec99d686 Fix library target naming.
Patch from Jurgen Hunold.


[SVN r29246]
2005-05-27 15:15:05 +00:00
John Maddock
da4baad235 Added qualifier to cmdline type to fix Borland failures.
[SVN r28987]
2005-05-17 11:44:44 +00:00
Rene Rivera
0c1332a0d3 Some compilers don't support, or make it hard to use, source relative includes. So avoid them.
[SVN r28920]
2005-05-15 06:32:18 +00:00
Markus Schöpflin
4fab784453 Fixed failure for 64 bit platforms.
[SVN r28860]
2005-05-13 11:48:09 +00:00
Vladimir Prus
274cd2e682 Fix ambiguity between 'std::detail' and 'program_options::detail' on cw.
[SVN r28692]
2005-05-06 08:13:32 +00:00
Vladimir Prus
b5bc8b4fcb Add test for unregisted options.
[SVN r28691]
2005-05-06 08:12:27 +00:00
Vladimir Prus
6b57600a81 Finally make 'allow_unregistered' method of cmdline work.
[SVN r28689]
2005-05-06 07:48:45 +00:00
Vladimir Prus
9a149beb76 Fix 'unknown option' error for two successive calls to 'store'.
The bug triggered if
- we store two parsed_option object into variables_map
- the options descriptions associated with those parsed_option objects
  are different
- an option present in first parser_option object is not declared in
  second options_description.

The problem was that on the second 'store' call we went over all
stored options, trying to get their description from the *second*
options description object.

Thanks to Hartmut Kaiser for the bug report.


[SVN r28685]
2005-05-06 06:40:39 +00:00
Hartmut Kaiser
dc9097c3d0 Make the True64 compiler happy.
[SVN r28663]
2005-05-05 16:50:41 +00:00
Vladimir Prus
d4748e8153 Fix a regression -- the if the 'style' argument to parse_command_line
function was zero, it was interpreted as no style is suppored. Previously,
it was interpreted as default_styles. Also, remove 'style' argument from
'cmdline' constructors.


[SVN r28500]
2005-04-27 07:02:39 +00:00
Vladimir Prus
efc9712f70 Check for invalid options in vector<option> returned by extra style
parser or additional parser.


[SVN r28468]
2005-04-25 09:06:44 +00:00
Vladimir Prus
239deeb456 Fix positional options.
[SVN r28467]
2005-04-25 06:39:34 +00:00
Rene Rivera
2476e5b265 Fix use of *DYN_LIB=1 defines.
Add dist-lib target to put results in a convenient place.


[SVN r28461]
2005-04-24 17:17:09 +00:00
Rene Rivera
f5bba0a918 Add missing define to make the code export symbols when creating a DLL.
[SVN r28440]
2005-04-23 16:37:48 +00:00
Vladimir Prus
94d186836e Derive basic_command_line_parser from cmdline.
Eliminate 'common_command_line_parser'.


[SVN r28419]
2005-04-22 15:32:23 +00:00
Vladimir Prus
6565cbc334 Revive 'additional parser'.
[SVN r28415]
2005-04-22 14:05:17 +00:00
Vladimir Prus
c984d59de1 Refactor the command line parser so that it uses options_description,
as opposed to having his own data structures. Clean up option description
classes a bit, removing unneeded methods. Remove support for 'implicit'
options.


[SVN r28413]
2005-04-22 13:35:45 +00:00
Vladimir Prus
07778adab7 Use direct cast from any to reference, recently introduced in CVS.
[SVN r28411]
2005-04-22 12:56:15 +00:00
Vladimir Prus
d78ebf5f0e Don't force static linking on NT.
[SVN r28334]
2005-04-20 11:25:16 +00:00
Hartmut Kaiser
7b23670e4d Improved readability in certain cases.
[SVN r27896]
2005-03-31 06:55:01 +00:00
Vladimir Prus
cb9bd037d9 Fix 64-bit portability problem.
Patch from Jonathan Wakely. Original explanation follows:

   The attached patch fixes a 64 bit portability problem where
   std::string::size_type is assigned to unsigned, which is shorter
   than size_t on x86-64 and so will be truncated. This means the
   following comparison to std::string::npos is always false.


[SVN r27772]
2005-03-23 11:11:55 +00:00
Vladimir Prus
c2442fcad6 Remove a couple of unused option_description members.
[SVN r27494]
2005-02-24 12:57:07 +00:00
Vladimir Prus
e5a143e2c5 Update BOOST_CHECK_EQUAL_COLLECTIONS usage to the current version of
Boost.Test.


[SVN r27417]
2005-02-18 11:11:11 +00:00
Vladimir Prus
58d35a27b9 Change "throw" to "throw_exception".
[SVN r27398]
2005-02-16 09:03:19 +00:00
Vladimir Prus
69d2f8fb21 Use "const char * const []" for parameters which take command line.
[SVN r27397]
2005-02-16 08:09:36 +00:00
Vladimir Prus
cedd6570fd Patches for IRIX MIPSPro. See
https://sourceforge.net/tracker/?func=detail&atid=307586&aid=1115576&group_id=7586


[SVN r27269]
2005-02-09 09:06:45 +00:00
Vladimir Prus
065b0a4a9d Correct example usage of positional_options_description::add.
[SVN r27218]
2005-02-07 14:27:20 +00:00
Stefan Slapeta
fc423bf6bc Replaced BOOST_TEST*
[SVN r27052]
2005-02-03 12:45:59 +00:00
Vladimir Prus
a9c3f21021 Remove a couple of potentially confusing sentences.
[SVN r26839]
2005-01-24 16:03:26 +00:00
Vladimir Prus
f27dce4ed4 Initial docs for text formatting rules.
[SVN r26785]
2005-01-21 16:11:26 +00:00
Vladimir Prus
c3e02a2b0a Merge the utf8 workaround in program_options and serialization and
put the result to boost/detail and libs/detail.


[SVN r26758]
2005-01-20 08:49:13 +00:00
Vladimir Prus
934e96dcef Workaround for borland
[SVN r26757]
2005-01-20 07:29:17 +00:00
Vladimir Prus
c184748325 Typo fixes
[SVN r26694]
2005-01-14 07:10:19 +00:00
Vladimir Prus
87558bfe7c Added wordwrapping and improved intentation for options_description
output.

Patch from Bertolt Mildner.


[SVN r26679]
2005-01-12 12:05:47 +00:00
Vladimir Prus
eca947a1ab Add a new option to response_file.cpp to illustrate that options in
response files are overriden by options on the command line.


[SVN r26678]
2005-01-12 10:56:29 +00:00
Vladimir Prus
87b4fff3e2 Fix missing includes.
Patch from Graham Bennett.


[SVN r26677]
2005-01-12 10:50:32 +00:00
Vladimir Prus
11946c4461 Some doc updates
[SVN r26676]
2005-01-12 10:00:25 +00:00
58 changed files with 4303 additions and 1761 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

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

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

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

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

@@ -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&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>
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&lt;int&gt;()->default(10), "compression level")
("compression", value&lt;int&gt;()->default_value(10), "compression level")
("email", value&lt; vector&lt;string&gt; &gt;()
->composing()->notify(&amp;your_function), "email")
->composing()->notifier(&amp;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 &#x2014;, 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

View File

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

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

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

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

View File

@@ -1,2 +1,3 @@
-I bar
-I biz
-I biz
--magic 10

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

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>

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

View File

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

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,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&

View File

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

View File

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

View File

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

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

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

View File

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

View File

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

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

View File

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

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 "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");

View File

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

View File

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

View File

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