|
Boost-Commit : |
Subject: [Boost-commit] svn:boost r58818 - in branches/release: boost/program_options boost/program_options/detail libs/program_options libs/program_options/build libs/program_options/example libs/program_options/src libs/program_options/test
From: ghost_at_[hidden]
Date: 2010-01-08 16:01:00
Author: vladimir_prus
Date: 2010-01-08 16:00:57 EST (Fri, 08 Jan 2010)
New Revision: 58818
URL: http://svn.boost.org/trac/boost/changeset/58818
Log:
Merge from trunk.
Added:
branches/release/libs/program_options/src/split.cpp
- copied, changed from r57972, /trunk/libs/program_options/src/split.cpp
branches/release/libs/program_options/test/config_test.cfg
- copied unchanged from r58269, /trunk/libs/program_options/test/config_test.cfg
branches/release/libs/program_options/test/exception_test.cpp
- copied, changed from r57747, /trunk/libs/program_options/test/exception_test.cpp
branches/release/libs/program_options/test/required_test.cfg
- copied unchanged from r58269, /trunk/libs/program_options/test/required_test.cfg
branches/release/libs/program_options/test/required_test.cpp
- copied, changed from r58269, /trunk/libs/program_options/test/required_test.cpp
branches/release/libs/program_options/test/split_test.cpp
- copied, changed from r57972, /trunk/libs/program_options/test/split_test.cpp
branches/release/libs/program_options/test/unrecognized_test.cpp
- copied unchanged from r58245, /trunk/libs/program_options/test/unrecognized_test.cpp
Properties modified:
branches/release/boost/program_options/ (props changed)
branches/release/libs/program_options/ (props changed)
Text files modified:
branches/release/boost/program_options/cmdline.hpp | 15 ++-
branches/release/boost/program_options/detail/cmdline.hpp | 6
branches/release/boost/program_options/detail/value_semantic.hpp | 6
branches/release/boost/program_options/errors.hpp | 166 ++++++++++++++++++++++++++++++---------
branches/release/boost/program_options/option.hpp | 18 +++
branches/release/boost/program_options/options_description.hpp | 25 ++++-
branches/release/boost/program_options/parsers.hpp | 33 +++++++
branches/release/boost/program_options/value_semantic.hpp | 19 ++++
branches/release/boost/program_options/variables_map.hpp | 9 +
branches/release/libs/program_options/build/Jamfile.v2 | 13 +-
branches/release/libs/program_options/example/multiple_sources.cpp | 20 +++
branches/release/libs/program_options/example/regex.cpp | 4
branches/release/libs/program_options/example/response_file.cpp | 5
branches/release/libs/program_options/src/cmdline.cpp | 158 ++++++++++++++++++++++++++-----------
branches/release/libs/program_options/src/config_file.cpp | 10 +-
branches/release/libs/program_options/src/convert.cpp | 2
branches/release/libs/program_options/src/options_description.cpp | 163 +++++++++++++++++++++++++++-----------
branches/release/libs/program_options/src/parsers.cpp | 35 +++++++
branches/release/libs/program_options/src/split.cpp | 65 +++++++--------
branches/release/libs/program_options/src/value_semantic.cpp | 152 ++++++++++++++++++++++++++---------
branches/release/libs/program_options/src/variables_map.cpp | 80 +++++++++++++-----
branches/release/libs/program_options/src/winmain.cpp | 8 -
branches/release/libs/program_options/test/Jamfile.v2 | 17 ++-
branches/release/libs/program_options/test/cmdline_test.cpp | 43 +++++-----
branches/release/libs/program_options/test/exception_test.cpp | 75 +++++++++++++----
branches/release/libs/program_options/test/options_description_test.cpp | 153 ++++++++++++++++++++++++++++++++++++
branches/release/libs/program_options/test/parsers_test.cpp | 58 ++++++++-----
branches/release/libs/program_options/test/required_test.cpp | 12 +-
branches/release/libs/program_options/test/split_test.cpp | 95 +++++++++++++++++++++-
branches/release/libs/program_options/test/test_convert.cpp | 5
branches/release/libs/program_options/test/unicode_test.cpp | 5
branches/release/libs/program_options/test/variable_map_test.cpp | 26 +++---
32 files changed, 1116 insertions(+), 385 deletions(-)
Modified: branches/release/boost/program_options/cmdline.hpp
==============================================================================
--- branches/release/boost/program_options/cmdline.hpp (original)
+++ branches/release/boost/program_options/cmdline.hpp 2010-01-08 16:00:57 EST (Fri, 08 Jan 2010)
@@ -26,7 +26,7 @@
enum style_t {
/// Allow "--long_name" style
allow_long = 1,
- /// Alow "-<single character" style
+ /// Allow "-<single character" style
allow_short = allow_long << 1,
/// Allow "-" in short options
allow_dash_for_short = allow_short << 1,
@@ -62,14 +62,19 @@
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?
+ /** Ignore the difference in case for long options.
*/
- case_insensitive = allow_guessing << 1,
+ long_case_insensitive = allow_guessing << 1,
+ /** Ignore the difference in case for short options.
+ */
+ short_case_insensitive = long_case_insensitive << 1,
+ /** Ignore the difference in case for all options.
+ */
+ case_insensitive = (long_case_insensitive | short_case_insensitive),
/** Allow long options with single option starting character,
e.g <tt>-foo=10</tt>
*/
- allow_long_disguise = case_insensitive << 1,
+ allow_long_disguise = short_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
Modified: branches/release/boost/program_options/detail/cmdline.hpp
==============================================================================
--- branches/release/boost/program_options/detail/cmdline.hpp (original)
+++ branches/release/boost/program_options/detail/cmdline.hpp 2010-01-08 16:00:57 EST (Fri, 08 Jan 2010)
@@ -108,13 +108,15 @@
void extra_style_parser(style_parser s);
void check_style(int style) const;
-
+
+ bool is_style_active(style_t style) const;
void init(const std::vector<std::string>& args);
void
finish_option(option& opt,
- std::vector<std::string>& other_tokens);
+ std::vector<std::string>& other_tokens,
+ const std::vector<style_parser>& style_parsers);
// Copies of input.
std::vector<std::string> args;
Modified: branches/release/boost/program_options/detail/value_semantic.hpp
==============================================================================
--- branches/release/boost/program_options/detail/value_semantic.hpp (original)
+++ branches/release/boost/program_options/detail/value_semantic.hpp 2010-01-08 16:00:57 EST (Fri, 08 Jan 2010)
@@ -33,7 +33,7 @@
void
typed_value<T, charT>::notify(const boost::any& value_store) const
{
- const T* value = boost::any_cast<const T>(&value_store);
+ const T* value = boost::any_cast<T>(&value_store);
if (m_store_to) {
*m_store_to = *value;
}
@@ -55,11 +55,11 @@
{
static std::basic_string<charT> empty;
if (v.size() > 1)
- boost::throw_exception(validation_error("multiple values not allowed"));
+ boost::throw_exception(validation_error(validation_error::multiple_values_not_allowed));
else if (v.size() == 1)
return v.front();
else if (!allow_empty)
- boost::throw_exception(validation_error("at least one value required"));
+ boost::throw_exception(validation_error(validation_error::at_least_one_value_required));
return empty;
}
Modified: branches/release/boost/program_options/errors.hpp
==============================================================================
--- branches/release/boost/program_options/errors.hpp (original)
+++ branches/release/boost/program_options/errors.hpp 2010-01-08 16:00:57 EST (Fri, 08 Jan 2010)
@@ -25,25 +25,53 @@
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)
- {}
+ enum kind_t {
+ long_not_allowed = 30,
+ long_adjacent_not_allowed,
+ short_adjacent_not_allowed,
+ empty_adjacent_parameter,
+ missing_parameter,
+ extra_parameter,
+ unrecognized_line
+ };
+
+ invalid_syntax(const std::string& tokens, kind_t kind);
// gcc says that throw specification on dtor is loosened
// without this line
~invalid_syntax() throw() {}
+
+ kind_t kind() const;
+
+ const std::string& tokens() const;
+
+ protected:
+ /** Used to convert kind_t to a related error text */
+ static std::string error_message(kind_t kind);
+ private:
// TODO: copy ctor might throw
- std::string tokens, msg;
+ std::string m_tokens;
+
+ kind_t m_kind;
};
/** Class thrown when option name is not recognized. */
class BOOST_PROGRAM_OPTIONS_DECL unknown_option : public error {
public:
unknown_option(const std::string& name)
- : error(std::string("unknown option ").append(name))
+ : error(std::string("unknown option ").append(name)),
+ m_option_name(name)
{}
+
+ // gcc says that throw specification on dtor is loosened
+ // without this line
+ ~unknown_option() throw() {}
+
+ const std::string& get_option_name() const throw();
+
+ private:
+ std::string m_option_name;
};
/** Class thrown when there's ambiguity amoung several possible options. */
@@ -51,21 +79,40 @@
public:
ambiguous_option(const std::string& name,
const std::vector<std::string>& alternatives)
- : error(std::string("ambiguous option ").append(name)),
- alternatives(alternatives)
+ : error(std::string("ambiguous option ").append(name))
+ , m_alternatives(alternatives)
+ , m_option_name(name)
{}
~ambiguous_option() throw() {}
+
+ const std::string& get_option_name() const throw();
+
+ const std::vector<std::string>& alternatives() const throw();
+ private:
// TODO: copy ctor might throw
- std::vector<std::string> alternatives;
+ std::vector<std::string> m_alternatives;
+ std::string m_option_name;
};
/** Class thrown when there are several option values, but
user called a method which cannot return them all. */
class BOOST_PROGRAM_OPTIONS_DECL multiple_values : public error {
public:
- multiple_values(const std::string& what) : error(what) {}
+ multiple_values()
+ : error("multiple values")
+ , m_option_name() {}
+
+ ~multiple_values() throw() {}
+
+ void set_option_name(const std::string& option);
+
+ const std::string& get_option_name() const throw();
+
+ private:
+ std::string m_option_name; // The name of the option which
+ // caused the exception.
};
/** Class thrown when there are several occurrences of an
@@ -73,23 +120,58 @@
them all. */
class BOOST_PROGRAM_OPTIONS_DECL multiple_occurrences : public error {
public:
- multiple_occurrences(const std::string& what) : error(what) {}
+ multiple_occurrences()
+ : error("multiple occurrences")
+ , m_option_name() {}
+
+ ~multiple_occurrences() throw() {}
+
+ void set_option_name(const std::string& option);
+
+ const std::string& get_option_name() const throw();
+
+ private:
+ std::string m_option_name; // The name of the option which
+ // caused the exception.
};
/** Class thrown when value of option is incorrect. */
class BOOST_PROGRAM_OPTIONS_DECL validation_error : public error {
public:
- validation_error(const std::string& what) : error(what) {}
+ enum kind_t {
+ multiple_values_not_allowed = 30,
+ at_least_one_value_required,
+ invalid_bool_value,
+ invalid_option_value,
+ invalid_option
+ };
+
+ validation_error(kind_t kind,
+ const std::string& option_value = "",
+ const std::string& option_name = "");
+
~validation_error() throw() {}
- void set_option_name(const std::string& option);
+ void set_option_name(const std::string& option);
+
+ const std::string& get_option_name() const throw();
+
const char* what() const throw();
+
+ protected:
+ /** Used to convert kind_t to a related error text */
+ static std::string error_message(kind_t kind);
+
private:
- mutable std::string m_message; // For on-demand formatting in 'what'
+ kind_t m_kind;
std::string m_option_name; // The name of the option which
// caused the exception.
+ std::string m_option_value; // Optional: value of the option m_options_name
+ mutable std::string m_message; // For on-demand formatting in 'what'
+
};
+ /** Class thrown if there is an invalid option value givenn */
class BOOST_PROGRAM_OPTIONS_DECL invalid_option_value
: public validation_error
{
@@ -100,39 +182,23 @@
#endif
};
- /** Class thrown when there are too many positional options. */
+ /** Class thrown when there are too many positional options.
+ This is a programming error.
+ */
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) {}
+ too_many_positional_options_error()
+ : error("too many positional options")
+ {}
};
+ /** Class thrown when there are syntax errors in given command line */
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 thrown when there are programming error related to style */
class BOOST_PROGRAM_OPTIONS_DECL invalid_command_line_style : public error {
public:
invalid_command_line_style(const std::string& msg)
@@ -140,6 +206,30 @@
{}
};
+ /** Class thrown if config file can not be read */
+ class BOOST_PROGRAM_OPTIONS_DECL reading_file : public error {
+ public:
+ reading_file(const char* filename)
+ : error(std::string("can not read file ").append(filename))
+ {}
+ };
+
+ /** Class thrown when a required/mandatory option is missing */
+ class BOOST_PROGRAM_OPTIONS_DECL required_option : public error {
+ public:
+ required_option(const std::string& name)
+ : error(std::string("missing required option ").append(name))
+ , m_option_name(name)
+ {}
+
+ ~required_option() throw() {}
+
+ const std::string& get_option_name() const throw();
+
+ private:
+ std::string m_option_name; // The name of the option which
+ // caused the exception.
+ };
}}
Modified: branches/release/boost/program_options/option.hpp
==============================================================================
--- branches/release/boost/program_options/option.hpp (original)
+++ branches/release/boost/program_options/option.hpp 2010-01-08 16:00:57 EST (Fri, 08 Jan 2010)
@@ -23,10 +23,17 @@
template<class charT>
class basic_option {
public:
- basic_option() : position_key(-1), unregistered(false) {}
+ basic_option()
+ : position_key(-1)
+ , unregistered(false)
+ , case_insensitive(false)
+ {}
basic_option(const std::string& string_key,
- const std::vector< std::string> &value)
- : string_key(string_key), value(value), unregistered(false)
+ const std::vector< std::string> &value)
+ : string_key(string_key)
+ , value(value)
+ , unregistered(false)
+ , case_insensitive(false)
{}
/** String key of this option. Intentionally independent of the template
@@ -50,7 +57,10 @@
recovered from the "original_tokens" member.
*/
bool unregistered;
-
+ /** True if string_key has to be handled
+ case insensitive.
+ */
+ bool case_insensitive;
};
typedef basic_option<char> option;
typedef basic_option<wchar_t> woption;
Modified: branches/release/boost/program_options/options_description.hpp
==============================================================================
--- branches/release/boost/program_options/options_description.hpp (original)
+++ branches/release/boost/program_options/options_description.hpp 2010-01-08 16:00:57 EST (Fri, 08 Jan 2010)
@@ -83,7 +83,8 @@
/** Given 'option', specified in the input source,
return 'true' is 'option' specifies *this.
*/
- match_result match(const std::string& option, bool approx) const;
+ match_result match(const std::string& option, bool approx,
+ bool long_ignore_case, bool short_ignore_case) const;
/** Return the key that should identify the option, in
particular in the variables_map class.
@@ -158,12 +159,18 @@
static const unsigned m_default_line_length;
/** Creates the instance. */
- options_description(unsigned line_length = m_default_line_length);
+ options_description(unsigned line_length = m_default_line_length,
+ unsigned min_description_length = m_default_line_length / 2);
/** Creates the instance. The 'caption' parameter gives the name of
this 'options_description' instance. Primarily useful for output.
+ The 'description_length' specifies the number of columns that
+ should be reserved for the description text; if the option text
+ encroaches into this, then the description will start on the next
+ line.
*/
options_description(const std::string& caption,
- unsigned line_length = m_default_line_length);
+ unsigned line_length = m_default_line_length,
+ unsigned min_description_length = m_default_line_length / 2);
/** Adds new variable description. Throws duplicate_variable_error if
either short or long name matches that of already present one.
*/
@@ -185,11 +192,15 @@
*/
options_description_easy_init add_options();
- const option_description& find(const std::string& name, bool approx)
- const;
+ const option_description& find(const std::string& name,
+ bool approx,
+ bool long_ignore_case = false,
+ bool short_ignore_case = false) const;
const option_description* find_nothrow(const std::string& name,
- bool approx) const;
+ bool approx,
+ bool long_ignore_case = false,
+ bool short_ignore_case = false) const;
const std::vector< shared_ptr<option_description> >& options() const;
@@ -213,6 +224,8 @@
std::string m_caption;
const unsigned m_line_length;
+ const unsigned m_min_description_length;
+
// Data organization is chosen because:
// - there could be two names for one option
// - option_add_proxy needs to know the last added option
Modified: branches/release/boost/program_options/parsers.hpp
==============================================================================
--- branches/release/boost/program_options/parsers.hpp (original)
+++ branches/release/boost/program_options/parsers.hpp 2010-01-08 16:00:57 EST (Fri, 08 Jan 2010)
@@ -147,6 +147,8 @@
= ext_parser());
/** Parse a config file.
+
+ Read from given stream.
*/
template<class charT>
#if ! BOOST_WORKAROUND(__ICL, BOOST_TESTED_AT(700))
@@ -156,6 +158,19 @@
parse_config_file(std::basic_istream<charT>&, const options_description&,
bool allow_unregistered = false);
+ /** Parse a config file.
+
+ Read from file with the given name. The character type is
+ passed to the file stream.
+ */
+ template<class charT>
+#if ! BOOST_WORKAROUND(__ICL, BOOST_TESTED_AT(700))
+ BOOST_PROGRAM_OPTIONS_DECL
+#endif
+ basic_parsed_options<charT>
+ parse_config_file(const char* filename, const options_description&,
+ bool allow_unregistered = false);
+
/** Controls if the 'collect_unregistered' function should
include positional options, or not. */
enum collect_unrecognized_mode
@@ -202,6 +217,24 @@
BOOST_PROGRAM_OPTIONS_DECL parsed_options
parse_environment(const options_description&, const char* prefix);
+ /** Splits a given string to a collection of single strings which
+ can be passed to command_line_parser. The second parameter is
+ used to specify a collection of possible seperator chars used
+ for splitting. The seperator is defaulted to space " ".
+ Splitting is done in a unix style way, with respect to quotes '"'
+ and escape characters '\'
+ */
+ BOOST_PROGRAM_OPTIONS_DECL std::vector<std::string>
+ split_unix(const std::string& cmdline, const std::string& seperator = " \t",
+ const std::string& quote = "'\"", const std::string& escape = "\\");
+
+#ifndef BOOST_NO_STD_WSTRING
+ /** @overload */
+ BOOST_PROGRAM_OPTIONS_DECL std::vector<std::wstring>
+ split_unix(const std::wstring& cmdline, const std::wstring& seperator = L" \t",
+ const std::wstring& quote = L"'\"", const std::wstring& escape = L"\\");
+#endif
+
#ifdef _WIN32
/** Parses the char* string which is passed to WinMain function on
windows. This function is provided for convenience, and because it's
Modified: branches/release/boost/program_options/value_semantic.hpp
==============================================================================
--- branches/release/boost/program_options/value_semantic.hpp (original)
+++ branches/release/boost/program_options/value_semantic.hpp 2010-01-08 16:00:57 EST (Fri, 08 Jan 2010)
@@ -43,6 +43,11 @@
other sources are discarded.
*/
virtual bool is_composing() const = 0;
+
+ /** Returns true if value must be given. Non-optional value
+
+ */
+ virtual bool is_required() const = 0;
/** Parses a group of tokens that specify a value of option.
Stores the result in 'value_store', using whatever representation
@@ -131,6 +136,8 @@
unsigned max_tokens() const;
bool is_composing() const { return false; }
+
+ bool is_required() const { return false; }
/** If 'value_store' is already initialized, or new_tokens
has more than one elements, throws. Otherwise, assigns
@@ -177,7 +184,8 @@
the value when it's known. The parameter can be NULL. */
typed_value(T* store_to)
: m_store_to(store_to), m_composing(false),
- m_multitoken(false), m_zero_tokens(false)
+ m_multitoken(false), m_zero_tokens(false),
+ m_required(false)
{}
/** Specifies default value, which will be used
@@ -266,6 +274,12 @@
return this;
}
+ /** Specifies that the value must occur. */
+ typed_value* required()
+ {
+ m_required = true;
+ return this;
+ }
public: // value semantic overrides
@@ -292,6 +306,7 @@
}
}
+ bool is_required() const { return m_required; }
/** Creates an instance of the 'validator' class and calls
its operator() to perform the actual conversion. */
@@ -335,7 +350,7 @@
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;
+ bool m_composing, m_implicit, m_multitoken, m_zero_tokens, m_required;
boost::function1<void, const T&> m_notifier;
};
Modified: branches/release/boost/program_options/variables_map.hpp
==============================================================================
--- branches/release/boost/program_options/variables_map.hpp (original)
+++ branches/release/boost/program_options/variables_map.hpp 2010-01-08 16:00:57 EST (Fri, 08 Jan 2010)
@@ -92,7 +92,8 @@
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);
+
+ friend BOOST_PROGRAM_OPTIONS_DECL class variables_map;
};
/** Implements string->string mapping with convenient value casting
@@ -147,6 +148,8 @@
// Resolve conflict between inherited operators.
const variable_value& operator[](const std::string& name) const
{ return abstract_variables_map::operator[](name); }
+
+ void notify();
private:
/** Implementation of abstract_variables_map::get
@@ -161,6 +164,10 @@
void store(const basic_parsed_options<char>& options,
variables_map& xm,
bool utf8);
+
+ /** Names of required options, filled by parser which has
+ access to options_description. */
+ std::set<std::string> m_required;
};
Modified: branches/release/libs/program_options/build/Jamfile.v2
==============================================================================
--- branches/release/libs/program_options/build/Jamfile.v2 (original)
+++ branches/release/libs/program_options/build/Jamfile.v2 2010-01-08 16:00:57 EST (Fri, 08 Jan 2010)
@@ -1,20 +1,19 @@
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
+ convert winmain split
;
lib boost_program_options
+ : $(SOURCES).cpp
+ : <link>shared:<define>BOOST_PROGRAM_OPTIONS_DYN_LINK=1 # tell source we're building dll's
:
- $(SOURCES).cpp
- :
- <link>shared:<define>BOOST_PROGRAM_OPTIONS_DYN_LINK=1 # tell source we're building dll's
+ : <link>shared:<define>BOOST_PROGRAM_OPTIONS_DYN_LINK=1
;
-boost-install boost_program_options ;
\ No newline at end of file
+boost-install boost_program_options ;
Modified: branches/release/libs/program_options/example/multiple_sources.cpp
==============================================================================
--- branches/release/libs/program_options/example/multiple_sources.cpp (original)
+++ branches/release/libs/program_options/example/multiple_sources.cpp 2010-01-08 16:00:57 EST (Fri, 08 Jan 2010)
@@ -27,13 +27,16 @@
{
try {
int opt;
+ string config_file;
// Declare a group of options that will be
// allowed only on command line
po::options_description generic("Generic options");
generic.add_options()
("version,v", "print version string")
- ("help", "produce help message")
+ ("help", "produce help message")
+ ("config,c", po::value<string>(&config_file)->default_value("multiple_sources.cfg"),
+ "name of a file of a configuration.")
;
// Declare a group of options that will be
@@ -71,10 +74,19 @@
po::variables_map vm;
store(po::command_line_parser(ac, av).
options(cmdline_options).positional(p).run(), vm);
-
- ifstream ifs("multiple_sources.cfg");
- store(parse_config_file(ifs, config_file_options), vm);
notify(vm);
+
+ ifstream ifs(config_file.c_str());
+ if (!ifs)
+ {
+ cout << "can not open config file: " << config_file << "\n";
+ return 0;
+ }
+ else
+ {
+ store(parse_config_file(ifs, config_file_options), vm);
+ notify(vm);
+ }
if (vm.count("help")) {
cout << visible << "\n";
Modified: branches/release/libs/program_options/example/regex.cpp
==============================================================================
--- branches/release/libs/program_options/example/regex.cpp (original)
+++ branches/release/libs/program_options/example/regex.cpp 2010-01-08 16:00:57 EST (Fri, 08 Jan 2010)
@@ -43,7 +43,7 @@
*/
void validate(boost::any& v,
const std::vector<std::string>& values,
- magic_number* target_type, int)
+ magic_number*, int)
{
static regex r("\\d\\d\\d-(\\d\\d\\d)");
@@ -61,7 +61,7 @@
if (regex_match(s, match, r)) {
v = any(magic_number(lexical_cast<int>(match[1])));
} else {
- throw validation_error("invalid value");
+ throw validation_error(validation_error::invalid_option_value);
}
}
Modified: branches/release/libs/program_options/example/response_file.cpp
==============================================================================
--- branches/release/libs/program_options/example/response_file.cpp (original)
+++ branches/release/libs/program_options/example/response_file.cpp 2010-01-08 16:00:57 EST (Fri, 08 Jan 2010)
@@ -70,7 +70,8 @@
ss << ifs.rdbuf();
// Split the file content
char_separator<char> sep(" \n\r");
- tokenizer<char_separator<char> > tok(ss.str(), sep);
+ string sstr = ss.str();
+ tokenizer<char_separator<char> > tok(sstr, sep);
vector<string> args;
copy(tok.begin(), tok.end(), back_inserter(args));
// Parse the file and store the options
@@ -87,7 +88,7 @@
cout << "Magic value: " << vm["magic"].as<int>() << "\n";
}
}
- catch(exception& e) {
+ catch (std::exception& e) {
cout << e.what() << "\n";
}
}
Modified: branches/release/libs/program_options/src/cmdline.cpp
==============================================================================
--- branches/release/libs/program_options/src/cmdline.cpp (original)
+++ branches/release/libs/program_options/src/cmdline.cpp 2010-01-08 16:00:57 EST (Fri, 08 Jan 2010)
@@ -34,16 +34,18 @@
using namespace std;
using namespace boost::program_options::command_line_style;
- invalid_command_line_syntax::
- invalid_command_line_syntax(const std::string& tokens, kind_t kind)
- : invalid_syntax(tokens, error_message(kind)), m_kind(kind)
+ invalid_syntax::
+ invalid_syntax(const string& tokens, kind_t kind)
+ : error(error_message(kind).append(" in '").append(tokens).append("'"))
+ , m_tokens(tokens)
+ , m_kind(kind)
{}
-
- std::string
- invalid_command_line_syntax::error_message(kind_t kind)
+
+ string
+ invalid_syntax::error_message(kind_t kind)
{
// Initially, store the message in 'const char*' variable,
- // to avoid conversion to std::string in all cases.
+ // to avoid conversion to string in all cases.
const char* msg;
switch(kind)
{
@@ -65,18 +67,31 @@
case extra_parameter:
msg = "extra parameter";
break;
+ case unrecognized_line:
+ msg = "unrecognized line";
+ break;
default:
msg = "unknown error";
}
return msg;
}
- invalid_command_line_syntax::kind_t
- invalid_command_line_syntax::kind() const
+ invalid_syntax::kind_t
+ invalid_syntax::kind() const
{
return m_kind;
}
+
+ const string&
+ invalid_syntax::tokens() const
+ {
+ return m_tokens;
+ }
+ invalid_command_line_syntax::
+ invalid_command_line_syntax(const string& tokens, kind_t kind)
+ : invalid_syntax(tokens, kind)
+ {}
}}
@@ -90,7 +105,7 @@
#endif
- cmdline::cmdline(const std::vector<std::string>& args)
+ cmdline::cmdline(const vector<string>& args)
{
init(args);
}
@@ -107,7 +122,7 @@
}
void
- cmdline::init(const std::vector<std::string>& args)
+ cmdline::init(const vector<string>& args)
{
this->args = args;
m_style = command_line_style::default_style;
@@ -157,6 +172,12 @@
// Need to check that if guessing and long disguise are enabled
// -f will mean the same as -foo
}
+
+ bool
+ cmdline::is_style_active(style_t style) const
+ {
+ return ((m_style & style) ? true : false);
+ }
void
cmdline::set_options_description(const options_description& desc)
@@ -230,12 +251,12 @@
{
vector<string> e;
for(unsigned k = 0; k < next.size()-1; ++k) {
- finish_option(next[k], e);
+ finish_option(next[k], e, style_parsers);
}
// For the last option, pass the unparsed tokens
// so that they can be added to next.back()'s values
// if appropriate.
- finish_option(next.back(), args);
+ finish_option(next.back(), args, style_parsers);
for (unsigned j = 0; j < next.size(); ++j)
result.push_back(next[j]);
}
@@ -269,7 +290,9 @@
const option_description* xd =
m_desc->find_nothrow(opt.string_key,
- (m_style & allow_guessing));
+ is_style_active(allow_guessing),
+ is_style_active(long_case_insensitive),
+ is_style_active(short_case_insensitive));
if (!xd)
continue;
@@ -326,29 +349,45 @@
if (opt.position_key != -1) {
if (position >= m_positional->max_total_count())
{
- boost::throw_exception(too_many_positional_options_error(
- "too many positional options"));
+ boost::throw_exception(too_many_positional_options_error());
}
opt.string_key = m_positional->name_for_position(position);
++position;
}
}
}
+
+ // set case sensitive flag
+ for (unsigned i = 0; i < result.size(); ++i) {
+ if (result[i].string_key.size() > 2 ||
+ (result[i].string_key.size() > 1 && result[i].string_key[0] != '-'))
+ {
+ // it is a long option
+ result[i].case_insensitive = is_style_active(long_case_insensitive);
+ }
+ else
+ {
+ // it is a short option
+ result[i].case_insensitive = is_style_active(short_case_insensitive);
+ }
+ }
return result;
}
void
cmdline::finish_option(option& opt,
- vector<string>& other_tokens)
- {
+ vector<string>& other_tokens,
+ const vector<style_parser>& style_parsers)
+ {
if (opt.string_key.empty())
return;
// First check that the option is valid, and get its description.
- // TODO: case-sensitivity.
const option_description* xd = m_desc->find_nothrow(opt.string_key,
- (m_style & allow_guessing) ? true : false);
+ is_style_active(allow_guessing),
+ is_style_active(long_case_insensitive),
+ is_style_active(short_case_insensitive));
if (!xd)
{
@@ -379,16 +418,16 @@
if (present_tokens >= min_tokens)
{
- if (!opt.value.empty() && max_tokens == 0) {
+ if (!opt.value.empty() && max_tokens == 0)
+ {
boost::throw_exception(invalid_command_line_syntax(opt.string_key,
invalid_command_line_syntax::extra_parameter));
}
- // If an option wants, at minimum, N tokens, we grab them
- // there and don't care if they look syntactically like an
- // option.
-
- if (opt.value.size() <= min_tokens)
+ // If an option wants, at minimum, N tokens, we grab them there,
+ // when adding these tokens as values to current option we check
+ // if they look like options
+ if (opt.value.size() <= min_tokens)
{
min_tokens -= opt.value.size();
}
@@ -398,7 +437,27 @@
}
// Everything's OK, move the values to the result.
- for(;!other_tokens.empty() && min_tokens--; ) {
+ for(;!other_tokens.empty() && min_tokens--; )
+ {
+ // check if extra parameter looks like a known option
+ // we use style parsers to check if it is syntactically an option,
+ // additionally we check if an option_description exists
+ vector<option> followed_option;
+ vector<string> next_token(1, other_tokens[0]);
+ for (unsigned i = 0; followed_option.empty() && i < style_parsers.size(); ++i)
+ {
+ followed_option = style_parsers[i](next_token);
+ }
+ if (!followed_option.empty())
+ {
+ const option_description* od = m_desc->find_nothrow(other_tokens[0],
+ is_style_active(allow_guessing),
+ is_style_active(long_case_insensitive),
+ is_style_active(short_case_insensitive));
+ if (od)
+ boost::throw_exception(invalid_command_line_syntax(opt.string_key,
+ invalid_command_line_syntax::missing_parameter));
+ }
opt.value.push_back(other_tokens[0]);
opt.original_tokens.push_back(other_tokens[0]);
other_tokens.erase(other_tokens.begin());
@@ -412,11 +471,11 @@
}
}
- std::vector<option>
- cmdline::parse_long_option(std::vector<string>& args)
+ vector<option>
+ cmdline::parse_long_option(vector<string>& args)
{
vector<option> result;
- const std::string& tok = args[0];
+ const string& tok = args[0];
if (tok.size() >= 3 && tok[0] == '-' && tok[1] == '-')
{
string name, adjacent;
@@ -428,7 +487,7 @@
adjacent = tok.substr(p+1);
if (adjacent.empty())
boost::throw_exception( invalid_command_line_syntax(name,
- invalid_command_line_syntax::empty_adjacent_parameter));
+ invalid_command_line_syntax::empty_adjacent_parameter) );
}
else
{
@@ -446,10 +505,10 @@
}
- std::vector<option>
- cmdline::parse_short_option(std::vector<string>& args)
+ vector<option>
+ cmdline::parse_short_option(vector<string>& args)
{
- const std::string& tok = args[0];
+ const string& tok = args[0];
if (tok.size() >= 2 && tok[0] == '-' && tok[1] != '-')
{
vector<option> result;
@@ -465,7 +524,8 @@
// option.
for(;;) {
const option_description* d
- = m_desc->find_nothrow(name, false);
+ = m_desc->find_nothrow(name, false, false,
+ is_style_active(short_case_insensitive));
// FIXME: check for 'allow_sticky'.
if (d && (m_style & allow_sticky) &&
@@ -497,14 +557,14 @@
}
return result;
}
- return std::vector<option>();
+ return vector<option>();
}
- std::vector<option>
- cmdline::parse_dos_option(std::vector<string>& args)
+ vector<option>
+ cmdline::parse_dos_option(vector<string>& args)
{
vector<option> result;
- const std::string& tok = args[0];
+ const string& tok = args[0];
if (tok.size() >= 2 && tok[0] == '/')
{
string name = "-" + tok.substr(1,1);
@@ -521,16 +581,18 @@
return result;
}
- std::vector<option>
- cmdline::parse_disguised_long_option(std::vector<string>& args)
+ vector<option>
+ cmdline::parse_disguised_long_option(vector<string>& args)
{
- const std::string& tok = args[0];
+ const string& tok = args[0];
if (tok.size() >= 2 &&
((tok[0] == '-' && tok[1] != '-') ||
((m_style & allow_slash_for_short) && tok[0] == '/')))
{
if (m_desc->find_nothrow(tok.substr(1, tok.find('=')-1),
- (m_style & allow_guessing) ? true : false))
+ is_style_active(allow_guessing),
+ is_style_active(long_case_insensitive),
+ is_style_active(short_case_insensitive)))
{
args[0].insert(0, "-");
if (args[0][1] == '/')
@@ -541,11 +603,11 @@
return vector<option>();
}
- std::vector<option>
- cmdline::parse_terminator(std::vector<std::string>& args)
+ vector<option>
+ cmdline::parse_terminator(vector<string>& args)
{
vector<option> result;
- const std::string& tok = args[0];
+ const string& tok = args[0];
if (tok == "--")
{
for(unsigned i = 1; i < args.size(); ++i)
@@ -561,8 +623,8 @@
return result;
}
- std::vector<option>
- cmdline::handle_additional_parser(std::vector<std::string>& args)
+ vector<option>
+ cmdline::handle_additional_parser(vector<string>& args)
{
vector<option> result;
pair<string, string> r = m_additional_parser(args[0]);
Modified: branches/release/libs/program_options/src/config_file.cpp
==============================================================================
--- branches/release/libs/program_options/src/config_file.cpp (original)
+++ branches/release/libs/program_options/src/config_file.cpp 2010-01-08 16:00:57 EST (Fri, 08 Jan 2010)
@@ -105,19 +105,19 @@
bool registered = allowed_option(name);
if (!registered && !m_allow_unregistered)
boost::throw_exception(unknown_option(name));
-
- if (value.empty())
- 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;
+ this->value().original_tokens.clear();
+ this->value().original_tokens.push_back(name);
+ this->value().original_tokens.push_back(value);
break;
} else {
- boost::throw_exception(invalid_syntax(s, "unrecognized line"));
+ boost::throw_exception(invalid_syntax(s, invalid_syntax::unrecognized_line));
}
}
}
Modified: branches/release/libs/program_options/src/convert.cpp
==============================================================================
--- branches/release/libs/program_options/src/convert.cpp (original)
+++ branches/release/libs/program_options/src/convert.cpp 2010-01-08 16:00:57 EST (Fri, 08 Jan 2010)
@@ -43,7 +43,7 @@
{
std::basic_string<ToChar> result;
- std::mbstate_t state = {0};
+ std::mbstate_t state = std::mbstate_t();
const FromChar* from = s.data();
const FromChar* from_end = s.data() + s.size();
Modified: branches/release/libs/program_options/src/options_description.cpp
==============================================================================
--- branches/release/libs/program_options/src/options_description.cpp (original)
+++ branches/release/libs/program_options/src/options_description.cpp 2010-01-08 16:00:57 EST (Fri, 08 Jan 2010)
@@ -8,7 +8,7 @@
#define BOOST_PROGRAM_OPTIONS_SOURCE
#include <boost/program_options/config.hpp>
#include <boost/program_options/options_description.hpp>
-// FIXME: this is only to get multiple_occureces class
+// FIXME: this is only to get multiple_occurences class
// should move that to a separate headers.
#include <boost/program_options/parsers.hpp>
@@ -28,6 +28,22 @@
namespace boost { namespace program_options {
+ namespace {
+
+ template< class charT >
+ std::basic_string< charT > tolower_(const std::basic_string< charT >& str)
+ {
+ std::basic_string< charT > result;
+ for (typename std::basic_string< charT >::size_type i = 0; i < str.size(); ++i)
+ {
+ result.append(1, static_cast< charT >(std::tolower(str[i])));
+ }
+ return result;
+ }
+
+ } // unnamed namespace
+
+
option_description::option_description()
{
}
@@ -55,37 +71,51 @@
}
option_description::match_result
- option_description::match(const std::string& option, bool approx) const
+ option_description::match(const std::string& option,
+ bool approx,
+ bool long_ignore_case,
+ bool short_ignore_case) const
{
- match_result result = no_match;
- if (!m_long_name.empty()) {
+ match_result result = no_match;
+
+ std::string local_long_name((long_ignore_case ? tolower_(m_long_name) : m_long_name));
+
+ if (!local_long_name.empty()) {
+
+ std::string local_option = (long_ignore_case ? tolower_(option) : option);
- if (*m_long_name.rbegin() == '*')
+ if (*local_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))
+ if (local_option.find(local_long_name.substr(0, local_long_name.length()-1))
== 0)
result = approximate_match;
}
- if (approx)
+ if (local_long_name == local_option)
{
- if (m_long_name.find(option) == 0)
- if (m_long_name == option)
- result = full_match;
- else
- result = approximate_match;
+ result = full_match;
}
- else
+ else if (approx)
{
- if (m_long_name == option)
- result = full_match;
+ if (local_long_name.find(local_option) == 0)
+ {
+ result = approximate_match;
+ }
}
}
- if (m_short_name == option)
- result = full_match;
+ if (result != full_match)
+ {
+ std::string local_option(short_ignore_case ? tolower_(option) : option);
+ std::string local_short_name(short_ignore_case ? tolower_(m_short_name) : m_short_name);
+
+ if (local_short_name == local_option)
+ {
+ result = full_match;
+ }
+ }
return result;
}
@@ -203,15 +233,26 @@
const unsigned options_description::m_default_line_length = 80;
- options_description::options_description(unsigned line_length)
+ options_description::options_description(unsigned line_length,
+ unsigned min_description_length)
: m_line_length(line_length)
- {}
-
- options_description::options_description(const string& caption,
- unsigned line_length)
- : m_caption(caption), m_line_length(line_length)
- {}
+ , m_min_description_length(min_description_length)
+ {
+ // we require a space between the option and description parts, so add 1.
+ assert(m_min_description_length < m_line_length - 1);
+ }
+ options_description::options_description(const std::string& caption,
+ unsigned line_length,
+ unsigned min_description_length)
+ : m_caption(caption)
+ , m_line_length(line_length)
+ , m_min_description_length(min_description_length)
+ {
+ // we require a space between the option and description parts, so add 1.
+ assert(m_min_description_length < m_line_length - 1);
+ }
+
void
options_description::add(shared_ptr<option_description> desc)
{
@@ -240,9 +281,13 @@
}
const option_description&
- options_description::find(const std::string& name, bool approx) const
+ options_description::find(const std::string& name,
+ bool approx,
+ bool long_ignore_case,
+ bool short_ignore_case) const
{
- const option_description* d = find_nothrow(name, approx);
+ const option_description* d = find_nothrow(name, approx,
+ long_ignore_case, short_ignore_case);
if (!d)
boost::throw_exception(unknown_option(name));
return *d;
@@ -256,41 +301,48 @@
const option_description*
options_description::find_nothrow(const std::string& name,
- bool approx) const
+ bool approx,
+ bool long_ignore_case,
+ bool short_ignore_case) const
{
shared_ptr<option_description> found;
vector<string> approximate_matches;
+ vector<string> full_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);
+ m_options[i]->match(name, approx, long_ignore_case, short_ignore_case);
if (r == option_description::no_match)
continue;
- // If we have a full patch, and an approximate match,
- // ignore approximate match instead of reporting error.
- // Say, if we have options "all" and "all-chroots", then
- // "--all" on the command line should select the first one,
- // without ambiguity.
- //
- // For now, we don't check the situation when there are
- // two full matches.
-
if (r == option_description::full_match)
- {
- return m_options[i].get();
+ {
+ full_matches.push_back(m_options[i]->key(name));
+ }
+ else
+ {
+ // FIXME: the use of 'key' here might not
+ // be the best approach.
+ approximate_matches.push_back(m_options[i]->key(name));
}
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)
+ if (full_matches.size() > 1)
+ boost::throw_exception(
+ ambiguous_option(name, full_matches));
+
+ // If we have a full match, 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.
+ if (full_matches.empty() && approximate_matches.size() > 1)
boost::throw_exception(
ambiguous_option(name, approximate_matches));
@@ -408,8 +460,8 @@
{
// is last_space within the second half ot the
// current line
- if ((unsigned)distance(last_space, line_end) <
- (line_length - indent) / 2)
+ if (static_cast<unsigned>(distance(last_space, line_end)) <
+ (line_length / 2))
{
line_end = last_space;
}
@@ -422,6 +474,7 @@
if (first_line)
{
indent += par_indent;
+ line_length -= par_indent; // there's less to work with now
first_line = false;
}
@@ -502,11 +555,18 @@
if (!opt.description().empty())
{
- for(unsigned pad = first_column_width - ss.str().size();
- pad > 0;
- --pad)
+ if (ss.str().size() >= first_column_width)
{
- os.put(' ');
+ os.put('\n'); // first column is too long, lets put description in new line
+ for (unsigned pad = first_column_width; pad > 0; --pad)
+ {
+ os.put(' ');
+ }
+ } else {
+ for(unsigned pad = first_column_width - ss.str().size(); pad > 0; --pad)
+ {
+ os.put(' ');
+ }
}
format_description(os, opt.description(),
@@ -531,6 +591,11 @@
ss << " " << opt.format_name() << ' ' << opt.format_parameter();
width = (max)(width, static_cast<unsigned>(ss.str().size()));
}
+ /* this is the column were description should start, if first
+ column is longer, we go to a new line */
+ const unsigned start_of_description_column = m_line_length - m_min_description_length;
+
+ width = (min)(width, start_of_description_column-1);
/* add an additional space to improve readability */
++width;
Modified: branches/release/libs/program_options/src/parsers.cpp
==============================================================================
--- branches/release/libs/program_options/src/parsers.cpp (original)
+++ branches/release/libs/program_options/src/parsers.cpp 2010-01-08 16:00:57 EST (Fri, 08 Jan 2010)
@@ -20,6 +20,7 @@
#include <boost/throw_exception.hpp>
#include <cctype>
+#include <fstream>
#if !defined(__GNUC__) || __GNUC__ < 3
#include <iostream>
@@ -134,6 +135,36 @@
const options_description& desc,
bool allow_unregistered);
#endif
+
+ template<class charT>
+ basic_parsed_options<charT>
+ parse_config_file(const char* filename,
+ const options_description& desc,
+ bool allow_unregistered)
+ {
+ // Parser return char strings
+ std::basic_ifstream< charT > strm(filename);
+ if (!strm)
+ {
+ boost::throw_exception(reading_file(filename));
+ }
+ return parse_config_file(strm, desc, allow_unregistered);
+ }
+
+ template
+ BOOST_PROGRAM_OPTIONS_DECL basic_parsed_options<char>
+ parse_config_file(const char* filename,
+ 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(const char* filename,
+ const options_description& desc,
+ bool allow_unregistered);
+#endif
+
// This versio, which accepts any options without validation, is disabled,
// in the hope that nobody will need it and we cant drop it altogether.
@@ -170,7 +201,7 @@
return result;
}
- namespace {
+ namespace detail {
class prefix_name_mapper {
public:
prefix_name_mapper(const std::string& prefix)
@@ -199,7 +230,7 @@
parse_environment(const options_description& desc,
const std::string& prefix)
{
- return parse_environment(desc, prefix_name_mapper(prefix));
+ return parse_environment(desc, detail::prefix_name_mapper(prefix));
}
BOOST_PROGRAM_OPTIONS_DECL parsed_options
Copied: branches/release/libs/program_options/src/split.cpp (from r57972, /trunk/libs/program_options/src/split.cpp)
==============================================================================
--- /trunk/libs/program_options/src/split.cpp (original)
+++ branches/release/libs/program_options/src/split.cpp 2010-01-08 16:00:57 EST (Fri, 08 Jan 2010)
@@ -4,62 +4,59 @@
// or copy at http://www.boost.org/LICENSE_1_0.txt)
#define BOOST_PROGRAM_OPTIONS_SOURCE
+
#include <boost/program_options/parsers.hpp>
+#include <boost/tokenizer.hpp>
+
#include <string>
#include <vector>
namespace boost { namespace program_options { namespace detail {
-
- template<class charT>
+ template< class charT >
std::vector<std::basic_string<charT> >
- split(const std::basic_string<charT>& cmdline, const std::basic_string<charT>& sep)
- {
- std::vector<std::basic_string<charT> > result;
- if (!cmdline.empty())
- {
- std::basic_string<charT> sub(cmdline), val;
- std::size_t pos;
-
- while (sub.size() > 0)
- {
- if ((pos = sub.find_first_of(sep)) != sub.npos)
- {
- val = sub.substr(0,pos);
- sub = sub.substr(pos+1);
- }
- else
- {
- val = sub;
- sub.erase();
- }
- if (!val.empty())
- {
- result.push_back(val);
- }
- }
+ split_unix(
+ const std::basic_string<charT>& cmdline,
+ const std::basic_string<charT>& seperator,
+ const std::basic_string<charT>& quote,
+ const std::basic_string<charT>& escape)
+ {
+ typedef boost::tokenizer< boost::escaped_list_separator<charT>,
+ typename std::basic_string<charT>::const_iterator,
+ std::basic_string<charT> > tokenizerT;
+
+ tokenizerT tok(cmdline.begin(), cmdline.end(),
+ boost::escaped_list_separator< charT >(escape, seperator, quote));
+
+ std::vector< std::basic_string<charT> > result;
+ for (typename tokenizerT::iterator cur_token(tok.begin()), end_token(tok.end()); cur_token != end_token; ++cur_token) {
+ if (!cur_token->empty())
+ result.push_back(*cur_token);
}
- return result;
+ return result;
}
-}}}
+}}} // namespace
namespace boost { namespace program_options {
// Take a command line string and splits in into tokens, according
// to the given collection of seperators chars.
BOOST_PROGRAM_OPTIONS_DECL std::vector<std::string>
- split(const std::string& cmdline, const std::string& sep)
+ split_unix(const std::string& cmdline, const std::string& seperator,
+ const std::string& quote, const std::string& escape)
{
- return detail::split(cmdline, sep);
+ return detail::split_unix< char >(cmdline, seperator, quote, escape);
}
#ifndef BOOST_NO_STD_WSTRING
BOOST_PROGRAM_OPTIONS_DECL std::vector<std::wstring>
- split(const std::wstring& cmdline, const std::wstring& sep)
+ split_unix(const std::wstring& cmdline, const std::wstring& seperator,
+ const std::wstring& quote, const std::wstring& escape)
{
- return detail::split(cmdline, sep);
+ return detail::split_unix< wchar_t >(cmdline, seperator, quote, escape);
}
#endif
-}}
+}} // namespace
+
Modified: branches/release/libs/program_options/src/value_semantic.cpp
==============================================================================
--- branches/release/libs/program_options/src/value_semantic.cpp (original)
+++ branches/release/libs/program_options/src/value_semantic.cpp 2010-01-08 16:00:57 EST (Fri, 08 Jan 2010)
@@ -97,9 +97,9 @@
{
if (!value_store.empty())
boost::throw_exception(
- multiple_occurrences("multiple_occurrences"));
+ multiple_occurrences());
if (new_tokens.size() > 1)
- boost::throw_exception(multiple_values("multiple_values"));
+ boost::throw_exception(multiple_values());
value_store = new_tokens.empty() ? std::string("") : new_tokens.front();
}
@@ -139,8 +139,7 @@
else if (s == "off" || s == "no" || s == "0" || s == "false")
v = any(false);
else
- boost::throw_exception(validation_error(
- "'" + s + "' doesn't look like a bool value."));
+ boost::throw_exception(validation_error(validation_error::invalid_bool_value, s));
}
// This is blatant copy-paste. However, templating this will cause a problem,
@@ -162,22 +161,14 @@
else if (s == L"off" || s == L"no" || s == L"0" || s == L"false")
v = any(false);
else
- boost::throw_exception(validation_error("invalid bool value"));
+ boost::throw_exception(validation_error(validation_error::invalid_bool_value));
}
#endif
BOOST_PROGRAM_OPTIONS_DECL
void validate(any& v, const vector<string>& xs, std::string*, int)
{
check_first_occurrence(v);
- string s(get_single_string(xs));
- if (!s.empty() && (
- (*s.begin() == '\'' && *s.rbegin() == '\'' ||
- *s.begin() == '"' && *s.rbegin() == '"')))
- {
- v = any(s.substr(1, s.size()-2));
- }
- else
- v = any(s);
+ v = any(get_single_string(xs));
}
#if !defined(BOOST_NO_STD_WSTRING)
@@ -185,12 +176,7 @@
void validate(any& v, const vector<wstring>& xs, std::string*, int)
{
check_first_occurrence(v);
- wstring s(get_single_string(xs));
- if (*s.begin() == L'\'' && *s.rbegin() == L'\'' ||
- *s.begin() == L'"' && *s.rbegin() == L'"')
- v = any(s.substr(1, s.size()-2));
- else
- v = any(s);
+ v = any(get_single_string(xs));
}
#endif
@@ -201,19 +187,17 @@
{
if (!value.empty())
boost::throw_exception(
- multiple_occurrences("multiple_occurrences"));
+ multiple_occurrences());
}
}
invalid_option_value::
invalid_option_value(const std::string& bad_value)
- : validation_error(string("invalid option value '")
- .append(bad_value).append("'"))
+ : validation_error(validation_error::invalid_option_value, bad_value)
{}
#ifndef BOOST_NO_STD_WSTRING
-
namespace
{
std::string convert_value(const std::wstring& s)
@@ -229,35 +213,123 @@
invalid_option_value::
invalid_option_value(const std::wstring& bad_value)
- : validation_error(string("invalid option value '")
- .append(convert_value(bad_value))
- .append("'"))
+ : validation_error(validation_error::invalid_option_value, convert_value(bad_value))
{}
-#endif
+#endif
+ const std::string&
+ unknown_option::get_option_name() const throw()
+ {
+ return m_option_name;
+ }
+ const std::string&
+ ambiguous_option::get_option_name() const throw()
+ {
+ return m_option_name;
+ }
+
+ const std::vector<std::string>&
+ ambiguous_option::alternatives() const throw()
+ {
+ return m_alternatives;
+ }
+ void
+ multiple_values::set_option_name(const std::string& option_name)
+ {
+ m_option_name = option_name;
+ }
- void validation_error::set_option_name(const std::string& option_name)
+ const std::string&
+ multiple_values::get_option_name() const throw()
+ {
+ return m_option_name;
+ }
+
+ void
+ multiple_occurrences::set_option_name(const std::string& option_name)
{
m_option_name = option_name;
}
- const char* validation_error::what() const throw()
+ const std::string&
+ multiple_occurrences::get_option_name() const throw()
{
- if (!m_option_name.empty())
- {
- m_message = "in option '" + m_option_name + "': "
- + logic_error::what();
- return m_message.c_str();
+ return m_option_name;
+ }
+
+ validation_error::
+ validation_error(kind_t kind,
+ const std::string& option_value,
+ const std::string& option_name)
+ : error("")
+ , m_kind(kind)
+ , m_option_name(option_name)
+ , m_option_value(option_value)
+ , m_message(error_message(kind))
+ {
+ if (!option_value.empty())
+ {
+ m_message.append(std::string("'") + option_value + std::string("'"));
+ }
+ }
- }
- else
- {
- return logic_error::what();
- }
+ void
+ validation_error::set_option_name(const std::string& option_name)
+ {
+ m_option_name = option_name;
}
+ const std::string&
+ validation_error::get_option_name() const throw()
+ {
+ return m_option_name;
+ }
+ std::string
+ validation_error::error_message(kind_t kind)
+ {
+ // Initially, store the message in 'const char*' variable,
+ // to avoid conversion to std::string in all cases.
+ const char* msg;
+ switch(kind)
+ {
+ case multiple_values_not_allowed:
+ msg = "multiple values not allowed";
+ break;
+ case at_least_one_value_required:
+ msg = "at least one value required";
+ break;
+ case invalid_bool_value:
+ msg = "invalid bool value";
+ break;
+ case invalid_option_value:
+ msg = "invalid option value";
+ break;
+ case invalid_option:
+ msg = "invalid option";
+ break;
+ default:
+ msg = "unknown error";
+ }
+ return msg;
+ }
+ const char*
+ validation_error::what() const throw()
+ {
+ if (!m_option_name.empty())
+ {
+ m_message = "in option '" + m_option_name + "': "
+ + error_message(m_kind);
+ }
+ return m_message.c_str();
+ }
+
+ const std::string&
+ required_option::get_option_name() const throw()
+ {
+ return m_option_name;
+ }
}}
Modified: branches/release/libs/program_options/src/variables_map.cpp
==============================================================================
--- branches/release/libs/program_options/src/variables_map.cpp (original)
+++ branches/release/libs/program_options/src/variables_map.cpp 2010-01-08 16:00:57 EST (Fri, 08 Jan 2010)
@@ -58,12 +58,8 @@
if (xm.m_final.count(name))
continue;
- // Ignore options which are not described
- //TODO: consider this.
- //if (desc.count(name) == 0)
- // continue;
-
- const option_description& d = desc.find(name, false);
+ const option_description& d = desc.find(name, false,
+ false, false);
variable_value& v = m[name];
if (v.defaulted()) {
@@ -80,6 +76,16 @@
e.set_option_name(name);
throw;
}
+ catch(multiple_occurrences& e)
+ {
+ e.set_option_name(name);
+ throw;
+ }
+ catch(multiple_values& e)
+ {
+ e.set_option_name(name);
+ throw;
+ }
#endif
v.m_value_semantic = d.semantic();
@@ -95,7 +101,7 @@
- // Second, apply default values.
+ // Second, apply default values and store required options.
const vector<shared_ptr<option_description> >& all = desc.options();
for(i = 0; i < all.size(); ++i)
{
@@ -117,7 +123,12 @@
m[key] = variable_value(def, true);
m[key].m_value_semantic = d.semantic();
}
- }
+ }
+
+ // add empty value if this is an required option
+ if (d.semantic()->is_required()) {
+ xm.m_required.insert(key);
+ }
}
}
@@ -130,22 +141,7 @@
BOOST_PROGRAM_OPTIONS_DECL
void notify(variables_map& vm)
{
- // Lastly, run notify actions.
- for (map<string, variable_value>::iterator k = vm.begin();
- k != vm.end();
- ++k)
- {
- /* Users might wish to use variables_map to store their own values
- that are not parsed, and therefore will not have value_semantics
- defined. Do no crash on such values. In multi-module programs,
- one module might add custom values, and the 'notify' function
- will be called after that, so we check that value_sematics is
- not NULL. See:
- https://svn.boost.org/trac/boost/ticket/2782
- */
- if (k->second.m_value_semantic)
- k->second.m_value_semantic->notify(k->second.value());
- }
+ vm.notify();
}
abstract_variables_map::abstract_variables_map()
@@ -196,4 +192,40 @@
else
return i->second;
}
+
+ void
+ variables_map::notify()
+ {
+ // This checks if all required options occur
+ for (set<string>::const_iterator r = m_required.begin();
+ r != m_required.end();
+ ++r)
+ {
+ const string& opt = *r;
+ map<string, variable_value>::const_iterator iter = find(opt);
+ if (iter == end() || iter->second.empty())
+ {
+ boost::throw_exception(required_option(opt));
+
+ }
+ }
+
+ // Lastly, run notify actions.
+ for (map<string, variable_value>::iterator k = begin();
+ k != end();
+ ++k)
+ {
+ /* Users might wish to use variables_map to store their own values
+ that are not parsed, and therefore will not have value_semantics
+ defined. Do no crash on such values. In multi-module programs,
+ one module might add custom values, and the 'notify' function
+ will be called after that, so we check that value_sematics is
+ not NULL. See:
+ https://svn.boost.org/trac/boost/ticket/2782
+ */
+ if (k->second.m_value_semantic)
+ k->second.m_value_semantic->notify(k->second.value());
+ }
+ }
+
}}
Modified: branches/release/libs/program_options/src/winmain.cpp
==============================================================================
--- branches/release/libs/program_options/src/winmain.cpp (original)
+++ branches/release/libs/program_options/src/winmain.cpp 2010-01-08 16:00:57 EST (Fri, 08 Jan 2010)
@@ -10,8 +10,6 @@
#ifdef _WIN32
namespace boost { namespace program_options {
- using namespace std;
-
// Take a command line string and splits in into tokens, according
// to the rules windows command line processor uses.
//
@@ -23,7 +21,7 @@
{
std::vector<std::string> result;
- string::const_iterator i = input.begin(), e = input.end();
+ std::string::const_iterator i = input.begin(), e = input.end();
for(;i != e; ++i)
if (!isspace((unsigned char)*i))
break;
@@ -86,8 +84,8 @@
BOOST_PROGRAM_OPTIONS_DECL std::vector<std::wstring>
split_winmain(const std::wstring& cmdline)
{
- vector<wstring> result;
- vector<string> aux = split_winmain(to_internal(cmdline));
+ std::vector<std::wstring> result;
+ std::vector<std::string> aux = split_winmain(to_internal(cmdline));
for (unsigned i = 0, e = aux.size(); i < e; ++i)
result.push_back(from_utf8(aux[i]));
return result;
Modified: branches/release/libs/program_options/test/Jamfile.v2
==============================================================================
--- branches/release/libs/program_options/test/Jamfile.v2 (original)
+++ branches/release/libs/program_options/test/Jamfile.v2 2010-01-08 16:00:57 EST (Fri, 08 Jan 2010)
@@ -9,24 +9,29 @@
# <define>_GLIBCXX_DEBUG
;
-rule po-test ( source )
+rule po-test ( source : input-file ? )
{
return
- [ run $(source) ]
- [ run $(source) : : : <link>shared <define>BOOST_PROGRAM_OPTIONS_DYN_LINK=1
- : $(source:B)_dll ]
- ;
+ [ run $(source) : : $(input-file) ]
+ [ run $(source) : : $(input-file)
+ : <link>shared <define>BOOST_PROGRAM_OPTIONS_DYN_LINK=1
+ : $(source:B)_dll ]
+ ;
}
test-suite program_options :
[ po-test options_description_test.cpp ]
- [ po-test parsers_test.cpp ]
+ [ po-test parsers_test.cpp : config_test.cfg ]
[ 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 ]
+ [ po-test exception_test.cpp ]
+ [ po-test split_test.cpp ]
+ [ po-test unrecognized_test.cpp ]
+ [ po-test required_test.cpp : required_test.cfg ]
;
exe test_convert : test_convert.cpp ;
Modified: branches/release/libs/program_options/test/cmdline_test.cpp
==============================================================================
--- branches/release/libs/program_options/test/cmdline_test.cpp (original)
+++ branches/release/libs/program_options/test/cmdline_test.cpp 2010-01-08 16:00:57 EST (Fri, 08 Jan 2010)
@@ -30,6 +30,7 @@
const int s_empty_adjacent_parameter = 6;
const int s_missing_parameter = 7;
const int s_extra_parameter = 8;
+const int s_unrecognized_line = 9;
int translate_syntax_error_kind(invalid_command_line_syntax::kind_t k)
{
@@ -40,6 +41,7 @@
invalid_command_line_syntax::empty_adjacent_parameter,
invalid_command_line_syntax::missing_parameter,
invalid_command_line_syntax::extra_parameter,
+ invalid_command_line_syntax::unrecognized_line
};
invalid_command_line_syntax::kind_t *b, *e, *i;
b = table;
@@ -183,7 +185,7 @@
{"--bar", s_missing_parameter, ""},
{"--bar=123", s_success, "bar:123"},
- {0}
+ {0, 0, 0}
};
test_cmdline("foo bar=", style, test_cases1);
@@ -198,7 +200,7 @@
// considered a value, even though it looks like
// an option.
{"--bar --foo", s_success, "bar:--foo"},
- {0}
+ {0, 0, 0}
};
test_cmdline("foo bar=", style, test_cases2);
style = cmdline::style_t(
@@ -208,7 +210,7 @@
test_case test_cases3[] = {
{"--bar=10", s_success, "bar:10"},
{"--bar 11", s_success, "bar:11"},
- {0}
+ {0, 0, 0}
};
test_cmdline("foo bar=", style, test_cases3);
@@ -216,8 +218,6 @@
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[] = {
@@ -226,10 +226,9 @@
{"--bar=Ab", s_success, "bar:Ab"},
{"--Bar=ab", s_success, "bar:ab"},
{"--giz", s_success, "Giz:"},
- {0}
+ {0, 0, 0}
};
test_cmdline("foo bar= baz? Giz", style, test_cases4);
-#endif
}
void test_short_options()
@@ -249,7 +248,7 @@
{"-f14", s_success, "-f:14"},
{"-g -f1", s_success, "-g: -f:1"},
{"-f", s_missing_parameter, ""},
- {0}
+ {0, 0, 0}
};
test_cmdline(",d ,f= ,g", style, test_cases1);
@@ -262,8 +261,8 @@
{"-f -13", s_success, "-f:-13"},
{"-f", s_missing_parameter, ""},
{"-f /foo", s_success, "-f:/foo"},
- {"-f -d", s_success, "-f:-d"},
- {0}
+ {"-f -d", s_missing_parameter, ""},
+ {0, 0, 0}
};
test_cmdline(",d ,f=", style, test_cases2);
@@ -274,8 +273,8 @@
test_case test_cases3[] = {
{"-f10", s_success, "-f:10"},
{"-f 10", s_success, "-f:10"},
- {"-f -d", s_success, "-f:-d"},
- {0}
+ {"-f -d", s_missing_parameter, ""},
+ {0, 0, 0}
};
test_cmdline(",d ,f=", style, test_cases3);
@@ -291,7 +290,7 @@
//{"-d12", s_extra_parameter, ""},
{"-f12", s_success, "-f:12"},
{"-fe", s_success, "-f:e"},
- {0}
+ {0, 0, 0}
};
test_cmdline(",d ,f= ,e", style, test_cases4);
@@ -313,7 +312,7 @@
{"/d13", s_extra_parameter, ""},
{"/f14", s_success, "-f:14"},
{"/f", s_missing_parameter, ""},
- {0}
+ {0, 0, 0}
};
test_cmdline(",d ,f=", style, test_cases1);
@@ -325,7 +324,7 @@
test_case test_cases2[] = {
{"/de", s_extra_parameter, ""},
{"/fe", s_success, "-f:e"},
- {0}
+ {0, 0, 0}
};
test_cmdline(",d ,f= ,e", style, test_cases2);
@@ -347,7 +346,7 @@
{"-foo -f", s_success, "foo: foo:"},
{"-goo=x -gy", s_success, "goo:x goo:y"},
{"-bee=x -by", s_success, "bee:x bee:y"},
- {0}
+ {0, 0, 0}
};
test_cmdline("foo,f goo,g= bee,b?", style, test_cases1);
@@ -355,7 +354,7 @@
test_case test_cases2[] = {
{"/foo -f", s_success, "foo: foo:"},
{"/goo=x", s_success, "goo:x"},
- {0}
+ {0, 0, 0}
};
test_cmdline("foo,f goo,g= bee,b?", style, test_cases2);
}
@@ -376,7 +375,7 @@
{"--opt", s_ambiguous_option, ""},
{"--f=1", s_success, "foo:1"},
{"-far", s_success, "foo:ar"},
- {0}
+ {0, 0, 0}
};
test_cmdline("opt123 opt56 foo,f=", style, test_cases1);
}
@@ -394,7 +393,7 @@
test_case test_cases1[] = {
{"-f file -gx file2", s_success, "-f: file -g:x file2"},
{"-f - -gx - -- -e", s_success, "-f: - -g:x - -e"},
- {0}
+ {0, 0, 0}
};
test_cmdline(",f ,g= ,e", style, test_cases1);
@@ -407,7 +406,7 @@
test_case test_cases2[] = {
{"-f - -gx - -- -e", s_success, "-f: - -g:x - -e"},
- {0}
+ {0, 0, 0}
};
test_cmdline(",f ,g= ,e", style, test_cases2);
}
@@ -425,7 +424,7 @@
test_case test_cases1[] = {
{"--foo.bar=12", s_success, "foo.bar:12"},
- {0}
+ {0, 0, 0}
};
test_cmdline("foo*=", style, test_cases1);
@@ -599,7 +598,7 @@
// It's not clear yet, so I'm leaving the decision till later.
}
-int main(int ac, char* av[])
+int main(int /*ac*/, char** /*av*/)
{
test_long_options();
test_short_options();
Copied: branches/release/libs/program_options/test/exception_test.cpp (from r57747, /trunk/libs/program_options/test/exception_test.cpp)
==============================================================================
--- /trunk/libs/program_options/test/exception_test.cpp (original)
+++ branches/release/libs/program_options/test/exception_test.cpp 2010-01-08 16:00:57 EST (Fri, 08 Jan 2010)
@@ -19,6 +19,32 @@
#include "minitest.hpp"
+void test_ambiguous()
+{
+ options_description desc;
+ desc.add_options()
+ ("cfgfile,c", value<string>()->multitoken(), "the config file")
+ ("output,c", value<string>(), "the output file")
+ ("output,o", value<string>(), "the output file")
+ ;
+
+ const char* cmdline[] = {"program", "-c", "file", "-o", "anotherfile"};
+
+ variables_map vm;
+ try {
+ store(parse_command_line(sizeof(cmdline)/sizeof(const char*),
+ const_cast<char**>(cmdline), desc), vm);
+ }
+ catch (ambiguous_option& e)
+ {
+ BOOST_CHECK_EQUAL(e.alternatives().size(), 2);
+ BOOST_CHECK_EQUAL(e.get_option_name(), "-c");
+ BOOST_CHECK_EQUAL(e.alternatives()[0], "cfgfile");
+ BOOST_CHECK_EQUAL(e.alternatives()[1], "output");
+ }
+}
+
+
void test_unknown_option()
{
@@ -74,6 +100,7 @@
}
+
void test_multiple_occurrences()
{
options_description desc;
@@ -92,36 +119,46 @@
catch (multiple_occurrences& e)
{
BOOST_CHECK_EQUAL(e.get_option_name(), "cfgfile");
- BOOST_CHECK_EQUAL(string(e.what()), "multiple_occurrences");
+ BOOST_CHECK_EQUAL(string(e.what()), "multiple occurrences");
}
}
+void test_missing_value()
+{
+ options_description desc;
+ desc.add_options()
+ ("cfgfile,c", value<string>()->multitoken(), "the config file")
+ ("output,o", value<string>(), "the output file")
+ ;
+ // missing value for option '-c'
+ const char* cmdline[] = { "program", "-c", "-c", "output.txt"};
+
+ variables_map vm;
+
+ try {
+ store(parse_command_line(sizeof(cmdline)/sizeof(const char*),
+ const_cast<char**>(cmdline), desc), vm);
+ notify(vm);
+ }
+ catch (invalid_command_line_syntax& e)
+ {
+ BOOST_CHECK_EQUAL(e.kind(), invalid_syntax::missing_parameter);
+ BOOST_CHECK_EQUAL(e.tokens(), "cfgfile");
+ }
+}
+
+
int main(int /*ac*/, char** /*av*/)
{
+ test_ambiguous();
test_unknown_option();
test_multiple_values();
test_multiple_occurrences();
-
- bool helpflag = false;
-
- options_description desc;
- desc.add_options()
- ("cfgfile,c", value<string>(), "the configfile")
- ("help,h", value<bool>(&helpflag)->implicit_value(true), "help")
- ;
-
- const char* cmdline[] = {"program", "--cfgfile", "hugo", "-h", "yes" };
-
- variables_map vm;
- store(parse_command_line(sizeof(cmdline)/sizeof(const char*),
- const_cast<char**>(cmdline), desc), vm);
- notify(vm);
-
- cout << " help: " << (helpflag ? "true" : "false") << endl;
-
+ test_missing_value();
return 0;
}
+
Modified: branches/release/libs/program_options/test/options_description_test.cpp
==============================================================================
--- branches/release/libs/program_options/test/options_description_test.cpp (original)
+++ branches/release/libs/program_options/test/options_description_test.cpp 2010-01-08 16:00:57 EST (Fri, 08 Jan 2010)
@@ -22,7 +22,7 @@
options_description desc;
desc.add_options()
("foo", value<int>(), "")
- ("bar", value<std::string>(), "")
+ ("bar", value<string>(), "")
;
const typed_value_base* b = dynamic_cast<const typed_value_base*>
@@ -33,7 +33,7 @@
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));
+ BOOST_CHECK(b2->value_type() == typeid(string));
}
void test_approximation()
@@ -70,16 +70,163 @@
"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");
+ "foo foo foo foo foo foo foo foo foo foo foo foo foo foo")
+ ("list", new untyped_value(),
+ "a list:\n \t"
+ "item1, item2, item3, item4, item5, item6, item7, item8, item9, "
+ "item10, item11, item12, item13, item14, item15, item16, item17, item18")
+ ("well_formated", new untyped_value(),
+ "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")
+ ;
stringstream ss;
ss << desc;
+ BOOST_CHECK_EQUAL(ss.str(),
+" --test arg foo foo foo foo foo foo foo foo foo foo foo foo foo \n"
+" foofoo foo foo foo foo foo foo foo foo foo foo foo foo \n"
+" foofoo foo foo foo foo foo foo foo foo foo foo foo foo \n"
+" foofoo foo foo foo foo foo foo foo foo foo foo foo foo \n"
+" foo\n"
+" --list arg a list:\n"
+" item1, item2, item3, item4, item5, item6, item7, \n"
+" item8, item9, item10, item11, item12, item13, \n"
+" item14, item15, item16, item17, item18\n"
+" --well_formated arg As you can see this is a very well formatted option \n"
+" description.\n"
+" You can do this for example:\n"
+" \n"
+" Values:\n"
+" Value1: does this and that, bla bla bla bla bla bla \n"
+" bla bla bla bla bla bla bla bla bla\n"
+" Value2: does something else, bla bla bla bla bla bla \n"
+" bla bla bla bla bla bla bla bla bla\n"
+" \n"
+" This paragraph has a first line indent only, bla \n"
+" bla bla bla bla bla bla bla bla bla bla bla bla bla bla\n"
+ );
}
+void test_formatting_description_length()
+{
+ {
+ options_description desc("",
+ options_description::m_default_line_length,
+ options_description::m_default_line_length / 2U);
+ desc.add_options()
+ ("an-option-that-sets-the-max", new untyped_value(), // > 40 available for desc
+ "this description sits on the same line, but wrapping should still work correctly")
+ ("a-long-option-that-would-leave-very-little-space-for-description", new untyped_value(),
+ "the description of the long opt, but placed on the next line\n"
+ " \talso ensure that the tabulation works correctly when a"
+ " description size has been set");
+
+ stringstream ss;
+ ss << desc;
+ BOOST_CHECK_EQUAL(ss.str(),
+ " --an-option-that-sets-the-max arg this description sits on the same line,\n"
+ " but wrapping should still work \n"
+ " correctly\n"
+ " --a-long-option-that-would-leave-very-little-space-for-description arg\n"
+ " the description of the long opt, but \n"
+ " placed on the next line\n"
+ " also ensure that the tabulation \n"
+ " works correctly when a description \n"
+ " size has been set\n");
+ }
+ {
+ // the default behaviour reserves 23 (+1 space) characters for the
+ // option column; this shows that the min_description_length does not
+ // breach that.
+ options_description desc("",
+ options_description::m_default_line_length,
+ options_description::m_default_line_length - 10U); // leaves < 23 (default option space)
+ desc.add_options()
+ ("an-option-that-encroaches-description", new untyped_value(),
+ "this description should always be placed on the next line, and wrapping should continue as normal");
+
+ stringstream ss;
+ ss << desc;
+ BOOST_CHECK_EQUAL(ss.str(),
+ " --an-option-that-encroaches-description arg\n"
+ //123456789_123456789_
+ " this description should always be placed on the next line, and \n"
+ " wrapping should continue as normal\n");
+ }
+}
+
+void test_long_default_value()
+{
+ options_description desc;
+ desc.add_options()
+ ("cfgfile,c",
+ value<string>()->default_value("/usr/local/etc/myprogramXXXXXXXXX/configuration.conf"),
+ "the configfile")
+ ;
+
+ stringstream ss;
+ ss << desc;
+ BOOST_CHECK_EQUAL(ss.str(),
+" -c [ --cfgfile ] arg (=/usr/local/etc/myprogramXXXXXXXXX/configuration.conf)\n"
+" the configfile\n"
+ );
+}
+
+void test_word_wrapping()
+{
+ options_description desc("Supported options");
+ desc.add_options()
+ ("help", "this is a sufficiently long text to require word-wrapping")
+ ("prefix", value<string>()->default_value("/h/proj/tmp/dispatch"), "root path of the dispatch installation")
+ ("opt1", "this_is_a_sufficiently_long_text_to_require_word-wrapping_but_cannot_be_wrapped")
+ ("opt2", "this_is_a_sufficiently long_text_to_require_word-wrapping")
+ ("opt3", "this_is_a sufficiently_long_text_to_require_word-wrapping_but_will_not_be_wrapped")
+ ;
+ stringstream ss;
+ ss << desc;
+ BOOST_CHECK_EQUAL(ss.str(),
+"Supported options:\n"
+" --help this is a sufficiently long text to \n"
+" require word-wrapping\n"
+" --prefix arg (=/h/proj/tmp/dispatch) root path of the dispatch installation\n"
+" --opt1 this_is_a_sufficiently_long_text_to_requ\n"
+" ire_word-wrapping_but_cannot_be_wrapped\n"
+" --opt2 this_is_a_sufficiently \n"
+" long_text_to_require_word-wrapping\n"
+" --opt3 this_is_a sufficiently_long_text_to_requ\n"
+" ire_word-wrapping_but_will_not_be_wrappe\n"
+" d\n"
+ );
+}
+
+void test_default_values()
+{
+ options_description desc("Supported options");
+ desc.add_options()
+ ("maxlength", value<double>()->default_value(.1, "0.1"), "Maximum edge length to keep.")
+ ;
+ stringstream ss;
+ ss << desc;
+ BOOST_CHECK_EQUAL(ss.str(),
+"Supported options:\n"
+" --maxlength arg (=0.1) Maximum edge length to keep.\n"
+ );
+}
+
+
int main(int, char* [])
{
test_type();
test_approximation();
test_formatting();
+ test_formatting_description_length();
+ test_long_default_value();
+ test_word_wrapping();
+ test_default_values();
return 0;
}
+
Modified: branches/release/libs/program_options/test/parsers_test.cpp
==============================================================================
--- branches/release/libs/program_options/test/parsers_test.cpp (original)
+++ branches/release/libs/program_options/test/parsers_test.cpp 2010-01-08 16:00:57 EST (Fri, 08 Jan 2010)
@@ -57,7 +57,7 @@
BOOST_CHECK(option.value.front() == value);
}
-vector<string> sv(char* array[], unsigned size)
+vector<string> sv(const char* array[], unsigned size)
{
vector<string> r;
for (unsigned i = 0; i < size; ++i)
@@ -113,10 +113,10 @@
("baz", new untyped_value())
("plug*", new untyped_value())
;
- char* cmdline3_[] = { "--foo=12", "-f4", "--bar=11", "-b4",
+ const char* cmdline3_[] = { "--foo=12", "-f4", "--bar=11", "-b4",
"--plug3=10"};
vector<string> cmdline3 = sv(cmdline3_,
- sizeof(cmdline3_)/sizeof(cmdline3_[0]));
+ sizeof(cmdline3_)/sizeof(const char*));
vector<option> a3 =
command_line_parser(cmdline3).options(desc).run().options;
@@ -131,22 +131,23 @@
// 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;
+ parse_command_line(sizeof(cmdline3_)/sizeof(const char*), const_cast<char**>(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", ""};
+ const 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);
+ po::store(po::parse_command_line(sizeof(cmdline4)/sizeof(const char*), const_cast<char**>(cmdline4), desc2), vm);
- char* cmdline5[] = {"", "-p7", "-o", "1", "2", "3", "-x8"};
+ const char* cmdline5[] = {"", "-p7", "-o", "1", "2", "3", "-x8"};
options_description desc3;
desc3.add_options()
(",p", po::value<string>())
@@ -154,7 +155,8 @@
(",x", po::value<string>())
;
vector<option> a5 =
- parse_command_line(7, cmdline5, desc3, 0, additional_parser).options;
+ parse_command_line(sizeof(cmdline5)/sizeof(const char*), const_cast<char**>(cmdline5),
+ desc3, 0, additional_parser).options;
BOOST_CHECK_EQUAL(a5.size(), 3u);
check_value(a5[0], "-p", "7");
BOOST_REQUIRE(a5[1].value.size() == 3);
@@ -180,9 +182,9 @@
po::positional_options_description p;
p.add( "file", 1 );
- char* cmdline6[] = {"", "-m", "token1", "token2", "--", "some_file"};
+ const char* cmdline6[] = {"", "-m", "token1", "token2", "--", "some_file"};
vector<option> a6 =
- command_line_parser(6, cmdline6).options(desc4).positional(p)
+ command_line_parser(sizeof(cmdline6)/sizeof(const char*), const_cast<char**>(cmdline6)).options(desc4).positional(p)
.run().options;
BOOST_CHECK_EQUAL(a6.size(), 2u);
BOOST_REQUIRE(a6[0].value.size() == 2);
@@ -194,12 +196,13 @@
BOOST_CHECK_EQUAL(a6[1].value[0], "some_file");
}
-void test_config_file()
+void test_config_file(const char* config_file)
{
options_description desc;
desc.add_options()
("gv1", new untyped_value)
("gv2", new untyped_value)
+ ("empty_value", new untyped_value)
("plug*", new untyped_value)
("m1.v1", new untyped_value)
("m1.v2", new untyped_value)
@@ -208,6 +211,7 @@
const char content1[] =
" gv1 = 0#asd\n"
+ "empty_value = \n"
"plug3 = 7\n"
"b = true\n"
"[m1]\n"
@@ -218,13 +222,23 @@
stringstream ss(content1);
vector<option> a1 = parse_config_file(ss, desc).options;
- BOOST_REQUIRE(a1.size() == 5);
+ BOOST_REQUIRE(a1.size() == 6);
check_value(a1[0], "gv1", "0");
- check_value(a1[1], "plug3", "7");
- check_value(a1[2], "b", "true");
- check_value(a1[3], "m1.v1", "1");
- check_value(a1[4], "m1.v2", "2");
-
+ check_value(a1[1], "empty_value", "");
+ check_value(a1[2], "plug3", "7");
+ check_value(a1[3], "b", "true");
+ check_value(a1[4], "m1.v1", "1");
+ check_value(a1[5], "m1.v2", "2");
+
+ // same test, but now options come from file
+ vector<option> a2 = parse_config_file<char>(config_file, desc).options;
+ BOOST_REQUIRE(a2.size() == 6);
+ check_value(a2[0], "gv1", "0");
+ check_value(a2[1], "empty_value", "");
+ check_value(a2[2], "plug3", "7");
+ check_value(a2[3], "b", "true");
+ check_value(a2[4], "m1.v1", "1");
+ check_value(a2[5], "m1.v2", "2");
}
void test_environment()
@@ -238,7 +252,7 @@
#if defined(_WIN32) && ! defined(__BORLANDC__)
_putenv("PO_TEST_FOO=1");
#else
- putenv("PO_TEST_FOO=1");
+ putenv(const_cast<char*>("PO_TEST_FOO=1"));
#endif
parsed_options p = parse_environment(desc, "PO_TEST_");
@@ -255,9 +269,9 @@
{
options_description desc;
- char* cmdline1_[] = { "--foo=12", "--bar", "1"};
+ const char* cmdline1_[] = { "--foo=12", "--bar", "1"};
vector<string> cmdline1 = sv(cmdline1_,
- sizeof(cmdline1_)/sizeof(cmdline1_[0]));
+ sizeof(cmdline1_)/sizeof(const char*));
vector<option> a1 =
command_line_parser(cmdline1).options(desc).allow_unregistered().run()
.options;
@@ -302,10 +316,10 @@
check_value(a3[1], "m1.v1", "1");
}
-int main(int, char* [])
+int main(int, char* av[])
{
test_command_line();
- test_config_file();
+ test_config_file(av[1]);
test_environment();
test_unregistered();
return 0;
Copied: branches/release/libs/program_options/test/required_test.cpp (from r58269, /trunk/libs/program_options/test/required_test.cpp)
==============================================================================
--- /trunk/libs/program_options/test/required_test.cpp (original)
+++ branches/release/libs/program_options/test/required_test.cpp 2010-01-08 16:00:57 EST (Fri, 08 Jan 2010)
@@ -16,7 +16,7 @@
void required_throw_test()
{
- options_description opts;
+ options_description opts;
opts.add_options()
("cfgfile,c", value<string>()->required(), "the configfile")
("fritz,f", value<string>()->required(), "the output file")
@@ -57,9 +57,9 @@
-void simple_required_test()
+void simple_required_test(const char* config_file)
{
- options_description opts;
+ options_description opts;
opts.add_options()
("cfgfile,c", value<string>()->required(), "the configfile")
("fritz,f", value<string>()->required(), "the output file")
@@ -75,7 +75,7 @@
try {
// options coming from different sources
store(command_line_parser(tokens).options(opts).run(), vm);
- store(parse_config_file<char>("required_test.cfg", opts), vm);
+ store(parse_config_file<char>(config_file, opts), vm);
notify(vm);
}
catch (required_option& e) {
@@ -87,10 +87,10 @@
-int main(int /*argc*/, char** /*argv*/)
+int main(int /*argc*/, char* av[])
{
required_throw_test();
- simple_required_test();
+ simple_required_test(av[1]);
return 0;
}
Copied: branches/release/libs/program_options/test/split_test.cpp (from r57972, /trunk/libs/program_options/test/split_test.cpp)
==============================================================================
--- /trunk/libs/program_options/test/split_test.cpp (original)
+++ branches/release/libs/program_options/test/split_test.cpp 2010-01-08 16:00:57 EST (Fri, 08 Jan 2010)
@@ -26,11 +26,12 @@
void split_whitespace(const options_description& description)
{
- const char* cmdline = "prg --input input.txt \t --optimization 4 \t\n --opt option";
+ const char* cmdline = "prg --input input.txt \r --optimization 4 \t --opt \n option";
- vector< string > tokens = split(cmdline, " \t\n");
+ vector< string > tokens = split_unix(cmdline, " \t\n\r");
BOOST_REQUIRE(tokens.size() == 7);
+
check_value(tokens[0], "prg");
check_value(tokens[1], "--input");
check_value(tokens[2], "input.txt");
@@ -49,8 +50,8 @@
const char* cmdline = "prg --input=input.txt --optimization=4 --opt=option";
- vector< string > tokens = split(cmdline, "= ");
-
+ vector< string > tokens = split_unix(cmdline, "= ");
+
BOOST_REQUIRE(tokens.size() == 7);
check_value(tokens[0], "prg");
check_value(tokens[1], "--input");
@@ -70,7 +71,7 @@
const char* cmdline = "prg;--input input.txt;--optimization 4;--opt option";
- vector< string > tokens = split(cmdline, "; ");
+ vector< string > tokens = split_unix(cmdline, "; ");
BOOST_REQUIRE(tokens.size() == 7);
check_value(tokens[0], "prg");
@@ -86,6 +87,86 @@
notify(vm);
}
+void split_quotes(const options_description& description)
+{
+ const char* cmdline = "prg --input \"input.txt input.txt\" --optimization 4 --opt \"option1 option2\"";
+
+ vector< string > tokens = split_unix(cmdline, " ");
+
+ BOOST_REQUIRE(tokens.size() == 7);
+ check_value(tokens[0], "prg");
+ check_value(tokens[1], "--input");
+ check_value(tokens[2], "input.txt input.txt");
+ check_value(tokens[3], "--optimization");
+ check_value(tokens[4], "4");
+ check_value(tokens[5], "--opt");
+ check_value(tokens[6], "option1 option2");
+
+ variables_map vm;
+ store(command_line_parser(tokens).options(description).run(), vm);
+ notify(vm);
+}
+
+void split_escape(const options_description& description)
+{
+ const char* cmdline = "prg --input \\\"input.txt\\\" --optimization 4 --opt \\\"option1\\ option2\\\"";
+
+ vector< string > tokens = split_unix(cmdline, " ");
+
+ BOOST_REQUIRE(tokens.size() == 7);
+ check_value(tokens[0], "prg");
+ check_value(tokens[1], "--input");
+ check_value(tokens[2], "\"input.txt\"");
+ check_value(tokens[3], "--optimization");
+ check_value(tokens[4], "4");
+ check_value(tokens[5], "--opt");
+ check_value(tokens[6], "\"option1 option2\"");
+
+ variables_map vm;
+ store(command_line_parser(tokens).options(description).run(), vm);
+ notify(vm);
+}
+
+
+void split_single_quote(const options_description& description)
+{
+ const char* cmdline = "prg --input 'input.txt input.txt' --optimization 4 --opt 'option1 option2'";
+
+ vector< string > tokens = split_unix(cmdline, " ", "'");
+
+ BOOST_REQUIRE(tokens.size() == 7);
+ check_value(tokens[0], "prg");
+ check_value(tokens[1], "--input");
+ check_value(tokens[2], "input.txt input.txt");
+ check_value(tokens[3], "--optimization");
+ check_value(tokens[4], "4");
+ check_value(tokens[5], "--opt");
+ check_value(tokens[6], "option1 option2");
+
+ variables_map vm;
+ store(command_line_parser(tokens).options(description).run(), vm);
+ notify(vm);
+}
+
+void split_defaults(const options_description& description)
+{
+ const char* cmdline = "prg --input \t \'input file.txt\' \t --optimization 4 --opt \\\"option1\\ option2\\\"";
+
+ vector< string > tokens = split_unix(cmdline);
+
+ BOOST_REQUIRE(tokens.size() == 7);
+ check_value(tokens[0], "prg");
+ check_value(tokens[1], "--input");
+ check_value(tokens[2], "input file.txt");
+ check_value(tokens[3], "--optimization");
+ check_value(tokens[4], "4");
+ check_value(tokens[5], "--opt");
+ check_value(tokens[6], "\"option1 option2\"");
+
+ variables_map vm;
+ store(command_line_parser(tokens).options(description).run(), vm);
+ notify(vm);
+}
int main(int /*ac*/, char** /*av*/)
{
@@ -99,6 +180,10 @@
split_whitespace(desc);
split_equalsign(desc);
split_semi(desc);
+ split_quotes(desc);
+ split_escape(desc);
+ split_single_quote(desc);
+ split_defaults(desc);
return 0;
}
Modified: branches/release/libs/program_options/test/test_convert.cpp
==============================================================================
--- branches/release/libs/program_options/test/test_convert.cpp (original)
+++ branches/release/libs/program_options/test/test_convert.cpp 2010-01-08 16:00:57 EST (Fri, 08 Jan 2010)
@@ -3,6 +3,7 @@
// (See accompanying file LICENSE_1_0.txt
// or copy at http://www.boost.org/LICENSE_1_0.txt)
+#include <cstring>
#include <cassert>
#include <string>
#include <fstream>
@@ -38,8 +39,8 @@
std::wstring result;
- std::mbstate_t state = {0};
-
+ std::mbstate_t state = std::mbstate_t();
+
const char* from = s.data();
const char* from_end = s.data() + s.size();
// The interace of cvt is not really iterator-like, and it's
Modified: branches/release/libs/program_options/test/unicode_test.cpp
==============================================================================
--- branches/release/libs/program_options/test/unicode_test.cpp (original)
+++ branches/release/libs/program_options/test/unicode_test.cpp 2010-01-08 16:00:57 EST (Fri, 08 Jan 2010)
@@ -88,8 +88,7 @@
BOOST_CHECK(vm["foo"].as<wstring>() == L"\x044F");
}
-
-vector<wstring> sv(wchar_t* array[], unsigned size)
+vector<wstring> sv(const wchar_t* array[], unsigned size)
{
vector<wstring> r;
for (unsigned i = 0; i < size; ++i)
@@ -115,7 +114,7 @@
("plug*", new untyped_value())
;
- wchar_t* cmdline4_[] = { L"--foo=1\u0FF52", L"-f4", L"--bar=11",
+ const 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]));
Modified: branches/release/libs/program_options/test/variable_map_test.cpp
==============================================================================
--- branches/release/libs/program_options/test/variable_map_test.cpp (original)
+++ branches/release/libs/program_options/test/variable_map_test.cpp 2010-01-08 16:00:57 EST (Fri, 08 Jan 2010)
@@ -20,7 +20,7 @@
#include "minitest.hpp"
-vector<string> sv(char* array[], unsigned size)
+vector<string> sv(const char* array[], unsigned size)
{
vector<string> r;
for (unsigned i = 0; i < size; ++i)
@@ -38,9 +38,9 @@
("baz", new untyped_value())
("output,o", new untyped_value(), "")
;
- char* cmdline3_[] = { "--foo='12'", "--bar=11", "-z3", "-ofoo" };
+ const char* cmdline3_[] = { "--foo='12'", "--bar=11", "-z3", "-ofoo" };
vector<string> cmdline3 = sv(cmdline3_,
- sizeof(cmdline3_)/sizeof(cmdline3_[0]));
+ sizeof(cmdline3_)/sizeof(const char*));
parsed_options a3 = command_line_parser(cmdline3).options(desc).run();
variables_map vm;
store(a3, vm);
@@ -58,9 +58,9 @@
("zak", po::value<int>(&i), "")
("opt", bool_switch(), "");
- char* cmdline4_[] = { "--zee", "--zak=13" };
+ const char* cmdline4_[] = { "--zee", "--zak=13" };
vector<string> cmdline4 = sv(cmdline4_,
- sizeof(cmdline4_)/sizeof(cmdline4_[0]));
+ sizeof(cmdline4_)/sizeof(const char*));
parsed_options a4 = command_line_parser(cmdline4).options(desc).run();
variables_map vm2;
@@ -78,9 +78,9 @@
("voo", po::value<string>())
("iii", po::value<int>()->default_value(123))
;
- char* cmdline5_[] = { "--voo=1" };
+ const char* cmdline5_[] = { "--voo=1" };
vector<string> cmdline5 = sv(cmdline5_,
- sizeof(cmdline5_)/sizeof(cmdline5_[0]));
+ sizeof(cmdline5_)/sizeof(const char*));
parsed_options a5 = command_line_parser(cmdline5).options(desc2).run();
variables_map vm3;
@@ -100,9 +100,9 @@
;
/* The -m option is implicit. It does not have value in inside the token,
and we should not grab the next token. */
- char* cmdline6_[] = { "--imp=1", "-m", "--foo=1" };
+ const char* cmdline6_[] = { "--imp=1", "-m", "--foo=1" };
vector<string> cmdline6 = sv(cmdline6_,
- sizeof(cmdline6_)/sizeof(cmdline6_[0]));
+ sizeof(cmdline6_)/sizeof(const char*));
parsed_options a6 = command_line_parser(cmdline6).options(desc3).run();
variables_map vm4;
@@ -194,15 +194,15 @@
("include", po::value< vector<int> >()->composing())
;
- char* cmdline1_[] = { "--first=1", "--aux=10", "--first=3", "--include=1" };
+ const char* cmdline1_[] = { "--first=1", "--aux=10", "--first=3", "--include=1" };
vector<string> cmdline1 = sv(cmdline1_,
- sizeof(cmdline1_)/sizeof(cmdline1_[0]));
+ sizeof(cmdline1_)/sizeof(const char*));
parsed_options p1 = command_line_parser(cmdline1).options(desc).run();
- char* cmdline2_[] = { "--first=12", "--second=7", "--include=7" };
+ const char* cmdline2_[] = { "--first=12", "--second=7", "--include=7" };
vector<string> cmdline2 = sv(cmdline2_,
- sizeof(cmdline2_)/sizeof(cmdline2_[0]));
+ sizeof(cmdline2_)/sizeof(const char*));
parsed_options p2 = command_line_parser(cmdline2).options(desc).run();
Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk