Compare commits

..

1 Commits

Author SHA1 Message Date
Daniel James
ab21d804f3 Branch for working on the documentation tools documentation.
[SVN r68640]
2011-02-04 21:18:24 +00:00
28 changed files with 529 additions and 1661 deletions

View File

@@ -20,7 +20,7 @@ int main(int ac, char* av[])
po::options_description desc("Allowed options");
desc.add_options()
("help", "produce help message")
("compression", po::value<double>(), "set compression level")
("compression", po::value<int>(), "set compression level")
;
po::variables_map vm;
@@ -29,12 +29,12 @@ int main(int ac, char* av[])
if (vm.count("help")) {
cout << desc << "\n";
return 0;
return 1;
}
if (vm.count("compression")) {
cout << "Compression level was set to "
<< vm["compression"].as<double>() << ".\n";
<< vm["compression"].as<int>() << ".\n";
} else {
cout << "Compression level was not set.\n";
}

View File

@@ -18,7 +18,7 @@ using namespace std;
template<class T>
ostream& operator<<(ostream& os, const vector<T>& v)
{
copy(v.begin(), v.end(), ostream_iterator<T>(os, " "));
copy(v.begin(), v.end(), ostream_iterator<T>(cout, " "));
return os;
}

View File

@@ -18,7 +18,7 @@ using namespace std;
template<class T>
ostream& operator<<(ostream& os, const vector<T>& v)
{
copy(v.begin(), v.end(), ostream_iterator<T>(os, " "));
copy(v.begin(), v.end(), ostream_iterator<T>(cout, " "));
return os;
}

View File

@@ -8,7 +8,7 @@
#ifndef PROGRAM_OPTIONS_VP_2003_05_19
#define PROGRAM_OPTIONS_VP_2003_05_19
#if defined(_MSC_VER)
#if defined(_MSC_VER) && _MSC_VER >= 1020
#pragma once
#endif

View File

@@ -34,14 +34,17 @@
#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 BOOST_SYMBOL_EXPORT
# define BOOST_PROGRAM_OPTIONS_DECL __declspec(dllexport)
#else
# define BOOST_PROGRAM_OPTIONS_DECL BOOST_SYMBOL_IMPORT
# 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

View File

@@ -81,18 +81,6 @@ namespace boost { namespace program_options { namespace detail {
cmdline(int argc, const char*const * argv);
void style(int style);
/** returns the canonical option prefix associated with the command_line_style
* In order of precedence:
* allow_long : allow_long
* allow_long_disguise : allow_long_disguise
* allow_dash_for_short : allow_short | allow_dash_for_short
* allow_slash_for_short: allow_short | allow_slash_for_short
*
* This is mainly used for the diagnostic messages in exceptions
*/
int get_canonical_option_prefix();
void allow_unregistered();
void set_options_description(const options_description& desc);

View File

@@ -17,7 +17,9 @@
#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

View File

@@ -100,11 +100,7 @@ namespace boost { namespace program_options {
basic_parsed_options<charT>
basic_command_line_parser<charT>::run()
{
// save the canonical prefixes which were used by this cmdline parser
// eventually inside the parsed results
// This will be handy to format recognisable options
// for diagnostic messages if everything blows up much later on
parsed_options result(m_desc, detail::cmdline::get_canonical_option_prefix());
parsed_options result(m_desc);
result.options = detail::cmdline::run();
// Presense of parsed_options -> wparsed_options conversion

View File

@@ -16,17 +16,16 @@ namespace boost { namespace program_options {
std::string
typed_value<T, charT>::name() const
{
std::string const& var = (m_value_name.empty() ? arg : m_value_name);
if (!m_implicit_value.empty() && !m_implicit_value_as_text.empty()) {
std::string msg = "[=" + var + "(=" + m_implicit_value_as_text + ")]";
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 var + " (=" + m_default_value_as_text + ")";
return arg + " (=" + m_default_value_as_text + ")";
} else {
return var;
return arg;
}
}
@@ -105,9 +104,12 @@ namespace boost { namespace program_options {
int);
#endif
// For some reason, this declaration, which is require by the standard,
// cause msvc 7.1 to not generate code to specialization defined in
// cause gcc 3.2 to not generate code to specialization defined in
// value_semantic.cpp
#if ! ( BOOST_WORKAROUND(BOOST_MSVC, == 1310) )
#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*,

View File

@@ -12,8 +12,6 @@
#include <string>
#include <stdexcept>
#include <vector>
#include <map>
#if defined(BOOST_MSVC)
# pragma warning (push)
@@ -23,18 +21,170 @@
namespace boost { namespace program_options {
inline std::string strip_prefixes(const std::string& text)
{
// "--foo-bar" -> "foo-bar"
return text.substr(text.find_first_not_of("-/"));
}
/** Base class for all errors in the library. */
class BOOST_PROGRAM_OPTIONS_DECL error : public std::logic_error {
public:
error(const std::string& xwhat) : std::logic_error(xwhat) {}
};
class BOOST_PROGRAM_OPTIONS_DECL invalid_syntax : public error {
public:
enum kind_t {
long_not_allowed = 30,
long_adjacent_not_allowed,
short_adjacent_not_allowed,
empty_adjacent_parameter,
missing_parameter,
extra_parameter,
unrecognized_line
};
invalid_syntax(const std::string& tokens, kind_t kind);
// gcc says that throw specification on dtor is loosened
// without this line
~invalid_syntax() throw() {}
kind_t kind() const;
const std::string& tokens() const;
protected:
/** Used to convert kind_t to a related error text */
static std::string error_message(kind_t kind);
private:
// TODO: copy ctor might throw
std::string m_tokens;
kind_t m_kind;
};
/** Class thrown when option name is not recognized. */
class BOOST_PROGRAM_OPTIONS_DECL unknown_option : public error {
public:
unknown_option(const std::string& name)
: error(std::string("unknown option ").append(name)),
m_option_name(name)
{}
// gcc says that throw specification on dtor is loosened
// without this line
~unknown_option() throw() {}
const std::string& get_option_name() const throw();
private:
std::string m_option_name;
};
/** Class thrown when there's ambiguity amoung several possible options. */
class BOOST_PROGRAM_OPTIONS_DECL ambiguous_option : public error {
public:
ambiguous_option(const std::string& name,
const std::vector<std::string>& xalternatives)
: error(std::string("ambiguous option ").append(name))
, m_alternatives(xalternatives)
, m_option_name(name)
{}
~ambiguous_option() throw() {}
const std::string& get_option_name() const throw();
const std::vector<std::string>& alternatives() const throw();
private:
// TODO: copy ctor might throw
std::vector<std::string> m_alternatives;
std::string m_option_name;
};
/** Class thrown when there are several option values, but
user called a method which cannot return them all. */
class BOOST_PROGRAM_OPTIONS_DECL multiple_values : public error {
public:
multiple_values()
: error("multiple values")
, m_option_name() {}
~multiple_values() throw() {}
void set_option_name(const std::string& option);
const std::string& get_option_name() const throw();
private:
std::string m_option_name; // The name of the option which
// caused the exception.
};
/** Class thrown when there are several occurrences of an
option, but user called a method which cannot return
them all. */
class BOOST_PROGRAM_OPTIONS_DECL multiple_occurrences : public error {
public:
multiple_occurrences()
: error("multiple occurrences")
, m_option_name() {}
~multiple_occurrences() throw() {}
void set_option_name(const std::string& option);
const std::string& get_option_name() const throw();
private:
std::string m_option_name; // The name of the option which
// caused the exception.
};
/** Class thrown when value of option is incorrect. */
class BOOST_PROGRAM_OPTIONS_DECL validation_error : public error {
public:
enum kind_t {
multiple_values_not_allowed = 30,
at_least_one_value_required,
invalid_bool_value,
invalid_option_value,
invalid_option
};
validation_error(kind_t kind,
const std::string& option_value = "",
const std::string& option_name = "");
~validation_error() throw() {}
void set_option_name(const std::string& option);
const std::string& get_option_name() const throw();
const char* what() const throw();
protected:
/** Used to convert kind_t to a related error text */
static std::string error_message(kind_t kind);
private:
kind_t m_kind;
std::string m_option_name; // The name of the option which
// caused the exception.
std::string m_option_value; // Optional: value of the option m_options_name
mutable std::string m_message; // For on-demand formatting in 'what'
};
/** Class thrown if there is an invalid option value givenn */
class BOOST_PROGRAM_OPTIONS_DECL invalid_option_value
: public validation_error
{
public:
invalid_option_value(const std::string& value);
#ifndef BOOST_NO_STD_WSTRING
invalid_option_value(const std::wstring& value);
#endif
};
/** Class thrown when there are too many positional options.
This is a programming error.
@@ -42,10 +192,16 @@ namespace boost { namespace program_options {
class BOOST_PROGRAM_OPTIONS_DECL too_many_positional_options_error : public error {
public:
too_many_positional_options_error()
: error("too many positional options have been specified on the command line")
: 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:
invalid_command_line_syntax(const std::string& tokens, kind_t kind);
};
/** Class thrown when there are programming error related to style */
class BOOST_PROGRAM_OPTIONS_DECL invalid_command_line_style : public error {
public:
@@ -58,355 +214,26 @@ namespace boost { namespace program_options {
class BOOST_PROGRAM_OPTIONS_DECL reading_file : public error {
public:
reading_file(const char* filename)
: error(std::string("can not read options configuration file '").append(filename).append("'"))
: error(std::string("can not read file ").append(filename))
{}
};
/** Base class for most exceptions in the library.
*
* Substitutes the values for the parameter name
* placeholders in the template to create the human
* readable error message
*
* Placeholders are surrounded by % signs: %example%
* Poor man's version of boost::format
*
* If a parameter name is absent, perform default substitutions
* instead so ugly placeholders are never left in-place.
*
* Options are displayed in "canonical" form
* This is the most unambiguous form of the
* *parsed* option name and would correspond to
* option_description::format_name()
* i.e. what is shown by print_usage()
*
* The "canonical" form depends on whether the option is
* specified in short or long form, using dashes or slashes
* or without a prefix (from a configuration file)
*
* */
class BOOST_PROGRAM_OPTIONS_DECL error_with_option_name : public error {
protected:
/** can be
* 0 = no prefix (config file options)
* allow_long
* allow_dash_for_short
* allow_slash_for_short
* allow_long_disguise */
int m_option_style;
/** substitutions
* from placeholders to values */
std::map<std::string, std::string> m_substitutions;
typedef std::pair<std::string, std::string> string_pair;
std::map<std::string, string_pair > m_substitution_defaults;
public:
/** template with placeholders */
std::string m_error_template;
error_with_option_name(const std::string& template_,
const std::string& option_name = "",
const std::string& original_token = "",
int option_style = 0);
/** gcc says that throw specification on dtor is loosened
* without this line
* */
~error_with_option_name() throw() {}
//void dump() const
//{
// std::cerr << "m_substitution_defaults:\n";
// for (std::map<std::string, string_pair>::const_iterator iter = m_substitution_defaults.begin();
// iter != m_substitution_defaults.end(); ++iter)
// std::cerr << "\t" << iter->first << ":" << iter->second.first << "=" << iter->second.second << "\n";
// std::cerr << "m_substitutions:\n";
// for (std::map<std::string, std::string>::const_iterator iter = m_substitutions.begin();
// iter != m_substitutions.end(); ++iter)
// std::cerr << "\t" << iter->first << "=" << iter->second << "\n";
// std::cerr << "m_error_template:\n";
// std::cerr << "\t" << m_error_template << "\n";
// std::cerr << "canonical_option_prefix:[" << get_canonical_option_prefix() << "]\n";
// std::cerr << "canonical_option_name:[" << get_canonical_option_name() <<"]\n";
// std::cerr << "what:[" << what() << "]\n";
//}
/** Substitute
* parameter_name->value to create the error message from
* the error template */
void set_substitute(const std::string& parameter_name, const std::string& value)
{ m_substitutions[parameter_name] = value; }
/** If the parameter is missing, then make the
* from->to substitution instead */
void set_substitute_default(const std::string& parameter_name,
const std::string& from,
const std::string& to)
{
m_substitution_defaults[parameter_name] = std::make_pair(from, to);
}
/** Add context to an exception */
void add_context(const std::string& option_name,
const std::string& original_token,
int option_style)
{
set_option_name(option_name);
set_original_token(original_token);
set_prefix(option_style);
}
void set_prefix(int option_style)
{ m_option_style = option_style;}
/** Overridden in error_with_no_option_name */
virtual void set_option_name(const std::string& option_name)
{ set_substitute("option", option_name);}
std::string get_option_name() const throw()
{ return get_canonical_option_name(); }
void set_original_token(const std::string& original_token)
{ set_substitute("original_token", original_token);}
/** Creates the error_message on the fly
* Currently a thin wrapper for substitute_placeholders() */
virtual const char* what() const throw();
protected:
/** Used to hold the error text returned by what() */
mutable std::string m_message; // For on-demand formatting in 'what'
/** Makes all substitutions using the template */
virtual void substitute_placeholders(const std::string& error_template) const;
// helper function for substitute_placeholders
void replace_token(const std::string& from, const std::string& to) const;
/** Construct option name in accordance with the appropriate
* prefix style: i.e. long dash or short slash etc */
std::string get_canonical_option_name() const;
std::string get_canonical_option_prefix() const;
};
/** Class thrown when there are several option values, but
user called a method which cannot return them all. */
class BOOST_PROGRAM_OPTIONS_DECL multiple_values : public error_with_option_name {
public:
multiple_values()
: error_with_option_name("option '%canonical_option%' only takes a single argument"){}
~multiple_values() throw() {}
};
/** Class thrown when there are several occurrences of an
option, but user called a method which cannot return
them all. */
class BOOST_PROGRAM_OPTIONS_DECL multiple_occurrences : public error_with_option_name {
public:
multiple_occurrences()
: error_with_option_name("option '%canonical_option%' cannot be specified more than once"){}
~multiple_occurrences() throw() {}
};
/** Class thrown when a required/mandatory option is missing */
class BOOST_PROGRAM_OPTIONS_DECL required_option : public error_with_option_name {
public:
// option name is constructed by the option_descriptor and never on the fly
required_option(const std::string& option_name)
: error_with_option_name("the option '%canonical_option%' is required but missing", "", option_name)
{
}
~required_option() throw() {}
};
/** Base class of unparsable options,
* when the desired option cannot be identified.
*
*
* It makes no sense to have an option name, when we can't match an option to the
* parameter
*
* Having this a part of the error_with_option_name hierachy makes error handling
* a lot easier, even if the name indicates some sort of conceptual dissonance!
*
* */
class BOOST_PROGRAM_OPTIONS_DECL error_with_no_option_name : public error_with_option_name {
public:
error_with_no_option_name(const std::string& template_,
const std::string& original_token = "")
: error_with_option_name(template_, "", original_token)
{
}
/** Does NOT set option name, because no option name makes sense */
virtual void set_option_name(const std::string&) {}
~error_with_no_option_name() throw() {}
};
/** Class thrown when option name is not recognized. */
class BOOST_PROGRAM_OPTIONS_DECL unknown_option : public error_with_no_option_name {
public:
unknown_option(const std::string& original_token = "")
: error_with_no_option_name("unrecognised option '%canonical_option%'", original_token)
{
}
~unknown_option() throw() {}
};
/** Class thrown when there's ambiguity amoung several possible options. */
class BOOST_PROGRAM_OPTIONS_DECL ambiguous_option : public error_with_no_option_name {
public:
ambiguous_option(const std::vector<std::string>& xalternatives)
: error_with_no_option_name("option '%canonical_option%' is ambiguous"),
m_alternatives(xalternatives)
{}
~ambiguous_option() throw() {}
const std::vector<std::string>& alternatives() const throw() {return m_alternatives;}
protected:
/** Makes all substitutions using the template */
virtual void substitute_placeholders(const std::string& error_template) const;
private:
// TODO: copy ctor might throw
std::vector<std::string> m_alternatives;
};
/** Class thrown when there's syntax error either for command
* line or config file options. See derived children for
* concrete classes. */
class BOOST_PROGRAM_OPTIONS_DECL invalid_syntax : public error_with_option_name {
public:
enum kind_t {
long_not_allowed = 30,
long_adjacent_not_allowed,
short_adjacent_not_allowed,
empty_adjacent_parameter,
missing_parameter,
extra_parameter,
unrecognized_line
};
invalid_syntax(kind_t kind,
const std::string& option_name = "",
const std::string& original_token = "",
int option_style = 0):
error_with_option_name(get_template(kind), option_name, original_token, option_style),
m_kind(kind)
{
}
~invalid_syntax() throw() {}
kind_t kind() const {return m_kind;}
/** Convenience functions for backwards compatibility */
virtual std::string tokens() const {return get_option_name(); }
protected:
/** Used to convert kind_t to a related error text */
std::string get_template(kind_t kind);
kind_t m_kind;
};
class BOOST_PROGRAM_OPTIONS_DECL invalid_config_file_syntax : public invalid_syntax {
public:
invalid_config_file_syntax(const std::string& invalid_line, kind_t kind):
invalid_syntax(kind)
{
m_substitutions["invalid_line"] = invalid_line;
}
~invalid_config_file_syntax() throw() {}
/** Convenience functions for backwards compatibility */
virtual std::string tokens() const {return m_substitutions.find("invalid_line")->second; }
};
/** Class thrown when there are syntax errors in given command line */
class BOOST_PROGRAM_OPTIONS_DECL invalid_command_line_syntax : public invalid_syntax {
public:
invalid_command_line_syntax(kind_t kind,
const std::string& option_name = "",
const std::string& original_token = "",
int option_style = 0):
invalid_syntax(kind, option_name, original_token, option_style) {}
~invalid_command_line_syntax() throw() {}
};
/** Class thrown when value of option is incorrect. */
class BOOST_PROGRAM_OPTIONS_DECL validation_error : public error_with_option_name {
public:
enum kind_t {
multiple_values_not_allowed = 30,
at_least_one_value_required,
invalid_bool_value,
invalid_option_value,
invalid_option
};
public:
validation_error(kind_t kind,
const std::string& option_name = "",
const std::string& original_token = "",
int option_style = 0):
error_with_option_name(get_template(kind), option_name, original_token, option_style)
{
}
~validation_error() throw() {}
protected:
/** Used to convert kind_t to a related error text */
std::string get_template(kind_t kind);
kind_t m_kind;
};
/** Class thrown if there is an invalid option value given */
class BOOST_PROGRAM_OPTIONS_DECL invalid_option_value
: public validation_error
{
public:
invalid_option_value(const std::string& value);
#ifndef BOOST_NO_STD_WSTRING
invalid_option_value(const std::wstring& value);
#endif
};
/** Class thrown if there is an invalid bool value given */
class BOOST_PROGRAM_OPTIONS_DECL invalid_bool_value
: public validation_error
{
public:
invalid_bool_value(const std::string& value);
};
/** 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.
};
}}
#if defined(BOOST_MSVC)

View File

@@ -61,8 +61,8 @@ namespace program_options {
Alas, derived->base conversion for auto_ptr does not really work,
see
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2000/n1232.pdf
http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#84
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.
@@ -102,16 +102,6 @@ namespace program_options {
*/
const std::string& key(const std::string& option) const;
/** Returns the canonical name for the option description to enable the user to
recognised a matching option.
1) For short options ('-', '/'), returns the short name prefixed.
2) For long options ('--' / '-') returns the long name prefixed
3) All other cases, returns the long name (if present) or the short name,
unprefixed.
*/
std::string canonical_display_name(int canonical_option_style = 0) const;
const std::string& long_name() const;
/// Explanation of this option
@@ -199,10 +189,6 @@ namespace program_options {
*/
options_description& add(const options_description& desc);
/** Find the maximum width of the option column, including options
in groups. */
unsigned get_option_column_width() const;
public:
/** Returns an object of implementation-defined type suitable for adding
options to options_description. The returned object will
@@ -233,7 +219,7 @@ namespace program_options {
/** Outputs 'desc' to the specified stream, calling 'f' to output each
option_description element. */
void print(std::ostream& os, unsigned width = 0) const;
void print(std::ostream& os) const;
private:
typedef std::map<std::string, int>::const_iterator name2index_iterator;

View File

@@ -36,8 +36,8 @@ namespace boost { namespace program_options {
template<class charT>
class basic_parsed_options {
public:
explicit basic_parsed_options(const options_description* xdescription, int options_prefix = 0)
: description(xdescription), m_options_prefix(options_prefix) {}
explicit basic_parsed_options(const options_description* xdescription)
: description(xdescription) {}
/** Options found in the source. */
std::vector< basic_option<charT> > options;
/** Options description that was used for parsing.
@@ -46,17 +46,6 @@ namespace boost { namespace program_options {
up to the caller. Can be NULL.
*/
const options_description* description;
/** Mainly used for the diagnostic messages in exceptions.
* The canonical option prefix for the parser which generated these results,
* depending on the settings for basic_command_line_parser::style() or
* cmdline::style(). In order of precedence of command_line_style enums:
* allow_long
* allow_long_disguise
* allow_dash_for_short
* allow_slash_for_short
*/
int m_options_prefix;
};
/** Specialization of basic_parsed_options which:
@@ -75,17 +64,6 @@ namespace boost { namespace program_options {
/** Stores UTF8 encoded options that were passed to constructor,
to avoid reverse conversion in some cases. */
basic_parsed_options<char> utf8_encoded_options;
/** Mainly used for the diagnostic messages in exceptions.
* The canonical option prefix for the parser which generated these results,
* depending on the settings for basic_command_line_parser::style() or
* cmdline::style(). In order of precedence of command_line_style enums:
* allow_long
* allow_long_disguise
* allow_dash_for_short
* allow_slash_for_short
*/
int m_options_prefix;
};
typedef basic_parsed_options<char> parsed_options;
@@ -282,10 +260,6 @@ namespace boost { namespace program_options {
}}
#if defined(BOOST_MSVC)
# pragma warning (pop)
#endif
#undef DECL
#include "boost/program_options/detail/parsers.hpp"

View File

@@ -227,13 +227,6 @@ namespace boost { namespace program_options {
return this;
}
/** Specifies the name used to to the value in help message. */
typed_value* value_name(const std::string& name)
{
m_value_name = name;
return this;
}
/** Specifies an implicit value, which will be used
if the option is given, but without an adjacent value.
Using this implies that an explicit value is optional, but if
@@ -361,7 +354,6 @@ namespace boost { namespace program_options {
// Default value is stored as boost::any and not
// as boost::optional to avoid unnecessary instantiations.
std::string m_value_name;
boost::any m_default_value;
std::string m_default_value_as_text;
boost::any m_implicit_value;

View File

@@ -98,7 +98,7 @@ namespace boost { namespace program_options {
void store(const basic_parsed_options<char>& options,
variables_map& m, bool);
friend class BOOST_PROGRAM_OPTIONS_DECL variables_map;
friend BOOST_PROGRAM_OPTIONS_DECL class variables_map;
};
/** Implements string->string mapping with convenient value casting
@@ -174,10 +174,8 @@ namespace boost { namespace program_options {
bool utf8);
/** Names of required options, filled by parser which has
access to options_description.
The map values are the "canonical" names for each corresponding option.
This is useful in creating diagnostic messages when the option is absent. */
std::map<std::string, std::string> m_required;
access to options_description. */
std::set<std::string> m_required;
};
@@ -213,8 +211,4 @@ namespace boost { namespace program_options {
}}
#if defined(BOOST_MSVC)
# pragma warning (pop)
#endif
#endif

View File

@@ -34,43 +34,64 @@ namespace boost { namespace program_options {
using namespace std;
using namespace boost::program_options::command_line_style;
invalid_syntax::
invalid_syntax(const string& tokens, kind_t kind)
: error(error_message(kind).append(" in '").append(tokens).append("'"))
, m_tokens(tokens)
, m_kind(kind)
{}
string
invalid_syntax::get_template(kind_t kind)
invalid_syntax::error_message(kind_t kind)
{
// Initially, store the message in 'const char*' variable,
// to avoid conversion to string in all cases.
const char* msg;
switch(kind)
{
case empty_adjacent_parameter:
msg = "the argument for option '%canonical_option%' should follow immediately after the equal sign";
break;
case missing_parameter:
msg = "the required argument for option '%canonical_option%' is missing";
break;
case unrecognized_line:
msg = "the options configuration file contains an invalid line '%invalid_line%'";
break;
// none of the following are currently used:
case long_not_allowed:
msg = "the unabbreviated option '%canonical_option%' is not valid";
msg = "long options are not allowed";
break;
case long_adjacent_not_allowed:
msg = "the unabbreviated option '%canonical_option%' does not take any arguments";
msg = "parameters adjacent to long options not allowed";
break;
case short_adjacent_not_allowed:
msg = "the abbreviated option '%canonical_option%' does not take any arguments";
msg = "parameters adjust to short options are not allowed";
break;
case empty_adjacent_parameter:
msg = "adjacent parameter is empty";
break;
case missing_parameter:
msg = "required parameter is missing";
break;
case extra_parameter:
msg = "option '%canonical_option%' does not take any arguments";
msg = "extra parameter";
break;
case unrecognized_line:
msg = "unrecognized line";
break;
default:
msg = "unknown command line syntax error for '%s'";
msg = "unknown error";
}
return msg;
}
invalid_syntax::kind_t
invalid_syntax::kind() const
{
return m_kind;
}
const string&
invalid_syntax::tokens() const
{
return m_tokens;
}
invalid_command_line_syntax::
invalid_command_line_syntax(const string& tokens, kind_t kind)
: invalid_syntax(tokens, kind)
{}
}}
@@ -135,26 +156,15 @@ namespace boost { namespace program_options { namespace detail {
const char* error = 0;
if (allow_some_long &&
!(style & long_allow_adjacent) && !(style & long_allow_next))
error = "boost::program_options misconfiguration: "
"choose one or other of 'command_line_style::long_allow_next' "
"(whitespace separated arguments) or "
"'command_line_style::long_allow_adjacent' ('=' separated arguments) for "
"long options.";
error = "style disallows parameters for long options";
if (!error && (style & allow_short) &&
!(style & short_allow_adjacent) && !(style & short_allow_next))
error = "boost::program_options misconfiguration: "
"choose one or other of 'command_line_style::short_allow_next' "
"(whitespace separated arguments) or "
"'command_line_style::short_allow_adjacent' ('=' separated arguments) for "
"short options.";
error = "style disallows parameters for short options";
if (!error && (style & allow_short) &&
!(style & allow_dash_for_short) && !(style & allow_slash_for_short))
error = "boost::program_options misconfiguration: "
"choose one or other of 'command_line_style::allow_slash_for_short' "
"(slashes) or 'command_line_style::allow_dash_for_short' (dashes) for "
"short options.";
error = "style disallows all characters for short options";
if (error)
boost::throw_exception(invalid_command_line_style(error));
@@ -182,23 +192,6 @@ namespace boost { namespace program_options { namespace detail {
m_positional = &positional;
}
int
cmdline::get_canonical_option_prefix()
{
if (m_style & allow_long)
return allow_long;
if (m_style & allow_long_disguise)
return allow_long_disguise;
if ((m_style & allow_short) && (m_style & allow_dash_for_short))
return allow_dash_for_short;
if ((m_style & allow_short) && (m_style & allow_slash_for_short))
return allow_slash_for_short;
return 0;
}
vector<option>
cmdline::run()
@@ -249,7 +242,7 @@ namespace boost { namespace program_options { namespace detail {
bool ok = false;
for(unsigned i = 0; i < style_parsers.size(); ++i)
{
unsigned current_size = static_cast<unsigned>(args.size());
unsigned current_size = args.size();
vector<option> next = style_parsers[i](args);
// Check that option names
@@ -295,21 +288,11 @@ namespace boost { namespace program_options { namespace detail {
if (opt.string_key.empty())
continue;
const option_description* xd;
try
{
xd = m_desc->find_nothrow(opt.string_key,
is_style_active(allow_guessing),
is_style_active(long_case_insensitive),
is_style_active(short_case_insensitive));
}
catch(error_with_option_name& e)
{
// add context and rethrow
e.add_context(opt.string_key, opt.original_tokens[0], get_canonical_option_prefix());
throw;
}
const option_description* xd =
m_desc->find_nothrow(opt.string_key,
is_style_active(allow_guessing),
is_style_active(long_case_insensitive),
is_style_active(short_case_insensitive));
if (!xd)
continue;
@@ -321,7 +304,7 @@ namespace boost { namespace program_options { namespace detail {
// We only allow to grab tokens that are not already
// recognized as key options.
int can_take_more = max_tokens - static_cast<int>(opt.value.size());
int can_take_more = max_tokens - opt.value.size();
unsigned j = i+1;
for (; can_take_more && j < result.size(); --can_take_more, ++j)
{
@@ -400,112 +383,92 @@ namespace boost { namespace program_options { namespace detail {
if (opt.string_key.empty())
return;
//
// Be defensive:
// will have no original token if option created by handle_additional_parser()
std::string original_token_for_exceptions = opt.string_key;
if (opt.original_tokens.size())
original_token_for_exceptions = opt.original_tokens[0];
// First check that the option is valid, and get its description.
const option_description* xd = m_desc->find_nothrow(opt.string_key,
is_style_active(allow_guessing),
is_style_active(long_case_insensitive),
is_style_active(short_case_insensitive));
try
if (!xd)
{
// First check that the option is valid, and get its description.
const option_description* xd = m_desc->find_nothrow(opt.string_key,
is_style_active(allow_guessing),
is_style_active(long_case_insensitive),
is_style_active(short_case_insensitive));
if (m_allow_unregistered) {
opt.unregistered = true;
return;
} else {
boost::throw_exception(unknown_option(opt.string_key));
}
}
const option_description& d = *xd;
if (!xd)
// Canonize the name
opt.string_key = d.key(opt.string_key);
// We check that the min/max number of tokens for the option
// agrees with the number of tokens we have. The 'adjacent_value'
// (the value in --foo=1) counts as a separate token, and if present
// must be consumed. The following tokens on the command line may be
// left unconsumed.
// We don't check if those tokens look like option, or not!
unsigned min_tokens = d.semantic()->min_tokens();
unsigned max_tokens = d.semantic()->max_tokens();
unsigned present_tokens = opt.value.size() + other_tokens.size();
if (present_tokens >= min_tokens)
{
if (!opt.value.empty() && max_tokens == 0)
{
if (m_allow_unregistered) {
opt.unregistered = true;
return;
} else {
boost::throw_exception(unknown_option());
}
boost::throw_exception(invalid_command_line_syntax(opt.string_key,
invalid_command_line_syntax::extra_parameter));
}
const option_description& d = *xd;
// Canonize the name
opt.string_key = d.key(opt.string_key);
// We check that the min/max number of tokens for the option
// agrees with the number of tokens we have. The 'adjacent_value'
// (the value in --foo=1) counts as a separate token, and if present
// must be consumed. The following tokens on the command line may be
// left unconsumed.
// We don't check if those tokens look like option, or not!
unsigned min_tokens = d.semantic()->min_tokens();
unsigned max_tokens = d.semantic()->max_tokens();
unsigned present_tokens = static_cast<unsigned>(opt.value.size() + other_tokens.size());
if (present_tokens >= 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)
{
if (!opt.value.empty() && max_tokens == 0)
{
boost::throw_exception(
invalid_command_line_syntax(invalid_command_line_syntax::extra_parameter));
}
// If an option wants, at minimum, N tokens, we grab them there,
// when adding these tokens as values to current option we check
// if they look like options
if (opt.value.size() <= min_tokens)
{
min_tokens -= static_cast<unsigned>(opt.value.size());
}
else
{
min_tokens = 0;
}
// Everything's OK, move the values to the result.
for(;!other_tokens.empty() && min_tokens--; )
{
// check if extra parameter looks like a known option
// we use style parsers to check if it is syntactically an option,
// additionally we check if an option_description exists
vector<option> followed_option;
vector<string> next_token(1, other_tokens[0]);
for (unsigned i = 0; followed_option.empty() && i < style_parsers.size(); ++i)
{
followed_option = style_parsers[i](next_token);
}
if (!followed_option.empty())
{
original_token_for_exceptions = other_tokens[0];
const option_description* od = m_desc->find_nothrow(other_tokens[0],
is_style_active(allow_guessing),
is_style_active(long_case_insensitive),
is_style_active(short_case_insensitive));
if (od)
boost::throw_exception(
invalid_command_line_syntax(invalid_command_line_syntax::missing_parameter));
}
opt.value.push_back(other_tokens[0]);
opt.original_tokens.push_back(other_tokens[0]);
other_tokens.erase(other_tokens.begin());
}
min_tokens -= opt.value.size();
}
else
{
boost::throw_exception(
invalid_command_line_syntax(invalid_command_line_syntax::missing_parameter));
min_tokens = 0;
}
}
// use only original token for unknown_option / ambiguous_option since by definition
// they are unrecognised / unparsable
catch(error_with_option_name& e)
{
// add context and rethrow
e.add_context(opt.string_key, original_token_for_exceptions, get_canonical_option_prefix());
throw;
}
// Everything's OK, move the values to the result.
for(;!other_tokens.empty() && min_tokens--; )
{
// check if extra parameter looks like a known option
// we use style parsers to check if it is syntactically an option,
// additionally we check if an option_description exists
vector<option> followed_option;
vector<string> next_token(1, other_tokens[0]);
for (unsigned i = 0; followed_option.empty() && i < style_parsers.size(); ++i)
{
followed_option = style_parsers[i](next_token);
}
if (!followed_option.empty())
{
const option_description* od = m_desc->find_nothrow(other_tokens[0],
is_style_active(allow_guessing),
is_style_active(long_case_insensitive),
is_style_active(short_case_insensitive));
if (od)
boost::throw_exception(invalid_command_line_syntax(opt.string_key,
invalid_command_line_syntax::missing_parameter));
}
opt.value.push_back(other_tokens[0]);
opt.original_tokens.push_back(other_tokens[0]);
other_tokens.erase(other_tokens.begin());
}
}
else
{
boost::throw_exception(invalid_command_line_syntax(opt.string_key,
invalid_command_line_syntax::missing_parameter));
}
}
vector<option>
@@ -523,11 +486,8 @@ namespace boost { namespace program_options { namespace detail {
name = tok.substr(2, p-2);
adjacent = tok.substr(p+1);
if (adjacent.empty())
boost::throw_exception( invalid_command_line_syntax(
invalid_command_line_syntax::empty_adjacent_parameter,
name,
name,
get_canonical_option_prefix()) );
boost::throw_exception( invalid_command_line_syntax(name,
invalid_command_line_syntax::empty_adjacent_parameter) );
}
else
{
@@ -563,20 +523,9 @@ namespace boost { namespace program_options { namespace detail {
// of token is considered to be value, not further grouped
// option.
for(;;) {
const option_description* d;
try
{
d = m_desc->find_nothrow(name, false, false,
is_style_active(short_case_insensitive));
}
catch(error_with_option_name& e)
{
// add context and rethrow
e.add_context(name, name, get_canonical_option_prefix());
throw;
}
const option_description* d
= m_desc->find_nothrow(name, false, false,
is_style_active(short_case_insensitive));
// FIXME: check for 'allow_sticky'.
if (d && (m_style & allow_sticky) &&
@@ -640,24 +589,15 @@ namespace boost { namespace program_options { namespace detail {
((tok[0] == '-' && tok[1] != '-') ||
((m_style & allow_slash_for_short) && tok[0] == '/')))
{
try
if (m_desc->find_nothrow(tok.substr(1, tok.find('=')-1),
is_style_active(allow_guessing),
is_style_active(long_case_insensitive),
is_style_active(short_case_insensitive)))
{
if (m_desc->find_nothrow(tok.substr(1, tok.find('=')-1),
is_style_active(allow_guessing),
is_style_active(long_case_insensitive),
is_style_active(short_case_insensitive)))
{
args[0].insert(0, "-");
if (args[0][1] == '/')
args[0][1] = '-';
return parse_long_option(args);
}
}
catch(error_with_option_name& e)
{
// add context and rethrow
e.add_context(tok, tok, get_canonical_option_prefix());
throw;
args[0].insert(0, "-");
if (args[0][1] == '/')
args[0][1] = '-';
return parse_long_option(args);
}
}
return vector<option>();

View File

@@ -57,9 +57,7 @@ namespace boost { namespace program_options { namespace detail {
bad_prefixes = true;
}
if (bad_prefixes)
boost::throw_exception(error("options '" + string(name) + "' and '" +
*i + "*' will both match the same "
"arguments from the configuration file"));
boost::throw_exception(error("bad prefixes"));
allowed_prefixes.insert(s);
}
}
@@ -119,7 +117,7 @@ namespace boost { namespace program_options { namespace detail {
break;
} else {
boost::throw_exception(invalid_config_file_syntax(s, invalid_syntax::unrecognized_line));
boost::throw_exception(invalid_syntax(s, invalid_syntax::unrecognized_line));
}
}
}

View File

@@ -137,31 +137,6 @@ namespace boost { namespace program_options {
return m_short_name;
}
std::string
option_description::canonical_display_name(int prefix_style) const
{
if (!m_long_name.empty())
{
if (prefix_style == command_line_style::allow_long)
return "--" + m_long_name;
if (prefix_style == command_line_style::allow_long_disguise)
return "-" + m_long_name;
}
// sanity check: m_short_name[0] should be '-' or '/'
if (m_short_name.length() == 2)
{
if (prefix_style == command_line_style::allow_slash_for_short)
return string("/") + m_short_name[1];
if (prefix_style == command_line_style::allow_dash_for_short)
return string("-") + m_short_name[1];
}
if (!m_long_name.empty())
return m_long_name;
else
return m_short_name;
}
const std::string&
option_description::long_name() const
{
@@ -317,7 +292,7 @@ namespace boost { namespace program_options {
const option_description* d = find_nothrow(name, approx,
long_ignore_case, short_ignore_case);
if (!d)
boost::throw_exception(unknown_option());
boost::throw_exception(unknown_option(name));
return *d;
}
@@ -365,7 +340,8 @@ namespace boost { namespace program_options {
}
}
if (full_matches.size() > 1)
boost::throw_exception(ambiguous_option(full_matches));
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.
@@ -373,7 +349,8 @@ namespace boost { namespace program_options {
// "--all" on the command line should select the first one,
// without ambiguity.
if (full_matches.empty() && approximate_matches.size() > 1)
boost::throw_exception(ambiguous_option(approximate_matches));
boost::throw_exception(
ambiguous_option(name, approximate_matches));
return found.get();
}
@@ -422,7 +399,7 @@ namespace boost { namespace program_options {
if (count(par.begin(), par.end(), '\t') > 1)
{
boost::throw_exception(program_options::error(
"Only one tab per paragraph is allowed in the options description"));
"Only one tab per paragraph is allowed"));
}
// erase tab from string
@@ -469,7 +446,7 @@ namespace boost { namespace program_options {
// Take care to never increment the iterator past
// the end, since MSVC 8.0 (brokenly), assumes that
// doing that, even if no access happens, is a bug.
unsigned remaining = static_cast<unsigned>(std::distance(line_begin, par_end));
unsigned remaining = distance(line_begin, par_end);
string::const_iterator line_end = line_begin +
((remaining < line_length) ? remaining : line_length);
@@ -489,7 +466,7 @@ namespace boost { namespace program_options {
{
// is last_space within the second half ot the
// current line
if (static_cast<unsigned>(std::distance(last_space, line_end)) <
if (static_cast<unsigned>(distance(last_space, line_end)) <
(line_length / 2))
{
line_end = last_space;
@@ -502,8 +479,8 @@ namespace boost { namespace program_options {
if (first_line)
{
indent += static_cast<unsigned>(par_indent);
line_length -= static_cast<unsigned>(par_indent); // there's less to work with now
indent += par_indent;
line_length -= par_indent; // there's less to work with now
first_line = false;
}
@@ -592,7 +569,7 @@ namespace boost { namespace program_options {
os.put(' ');
}
} else {
for(unsigned pad = first_column_width - static_cast<unsigned>(ss.str().size()); pad > 0; --pad)
for(unsigned pad = first_column_width - ss.str().size(); pad > 0; --pad)
{
os.put(' ');
}
@@ -604,9 +581,12 @@ namespace boost { namespace program_options {
}
}
unsigned
options_description::get_option_column_width() const
void
options_description::print(std::ostream& os) const
{
if (!m_caption.empty())
os << m_caption << ":\n";
/* Find the maximum width of the option column */
unsigned width(23);
unsigned i; // vc6 has broken for loop scoping
@@ -617,11 +597,6 @@ namespace boost { namespace program_options {
ss << " " << opt.format_name() << ' ' << opt.format_parameter();
width = (max)(width, static_cast<unsigned>(ss.str().size()));
}
/* Get width of groups as well*/
for (unsigned j = 0; j < groups.size(); ++j)
width = max(width, groups[j]->get_option_column_width());
/* this is the column were description should start, if first
column is longer, we go to a new line */
const unsigned start_of_description_column = m_line_length - m_min_description_length;
@@ -630,20 +605,9 @@ namespace boost { namespace program_options {
/* add an additional space to improve readability */
++width;
return width;
}
void
options_description::print(std::ostream& os, unsigned width) const
{
if (!m_caption.empty())
os << m_caption << ":\n";
if (!width)
width = get_option_column_width();
/* The options formatting style is stolen from Subversion. */
for (unsigned i = 0; i < m_options.size(); ++i)
for (i = 0; i < m_options.size(); ++i)
{
if (belong_to_group[i])
continue;
@@ -656,8 +620,7 @@ namespace boost { namespace program_options {
}
for (unsigned j = 0; j < groups.size(); ++j) {
os << "\n";
groups[j]->print(os, width);
os << "\n" << *groups[j];
}
}

View File

@@ -88,8 +88,7 @@ namespace boost { namespace program_options {
basic_parsed_options<wchar_t>
::basic_parsed_options(const parsed_options& po)
: description(po.description),
utf8_encoded_options(po),
m_options_prefix(po.m_options_prefix)
utf8_encoded_options(po)
{
for (unsigned i = 0; i < po.options.size(); ++i)
options.push_back(woption_from_option(po.options[i]));
@@ -111,7 +110,7 @@ namespace boost { namespace program_options {
if (d.long_name().empty())
boost::throw_exception(
error("abbreviated option names are not permitted in options configuration files"));
error("long name required for config file"));
allowed_options.insert(d.long_name());
}

View File

@@ -34,7 +34,7 @@ namespace boost { namespace program_options {
positional_options_description::max_total_count() const
{
return m_trailing.empty() ?
static_cast<unsigned>(m_names.size()) : (std::numeric_limits<unsigned>::max)();
m_names.size() : (std::numeric_limits<unsigned>::max)();
}
const std::string&

View File

@@ -12,7 +12,7 @@
#define BOOST_UTF8_END_NAMESPACE }}}
#define BOOST_UTF8_DECL BOOST_PROGRAM_OPTIONS_DECL
#include <boost/detail/utf8_codecvt_facet.ipp>
#include "../../detail/utf8_codecvt_facet.cpp"
#undef BOOST_UTF8_BEGIN_NAMESPACE

View File

@@ -7,8 +7,6 @@
#include <boost/program_options/config.hpp>
#include <boost/program_options/value_semantic.hpp>
#include <boost/program_options/detail/convert.hpp>
#include <boost/program_options/detail/cmdline.hpp>
#include <set>
#include <cctype>
@@ -16,22 +14,6 @@ namespace boost { namespace program_options {
using namespace std;
#ifndef BOOST_NO_STD_WSTRING
namespace
{
std::string convert_value(const std::wstring& s)
{
try {
return to_local_8_bit(s);
}
catch(const std::exception&) {
return "<unrepresentable unicode string>";
}
}
}
#endif
void
value_semantic_codecvt_helper<char>::
parse(boost::any& value_store,
@@ -157,7 +139,7 @@ namespace boost { namespace program_options {
else if (s == "off" || s == "no" || s == "0" || s == "false")
v = any(false);
else
boost::throw_exception(invalid_bool_value(s));
boost::throw_exception(validation_error(validation_error::invalid_bool_value, s));
}
// This is blatant copy-paste. However, templating this will cause a problem,
@@ -179,7 +161,7 @@ namespace boost { namespace program_options {
else if (s == L"off" || s == L"no" || s == L"0" || s == L"false")
v = any(false);
else
boost::throw_exception(invalid_bool_value(convert_value(s)));
boost::throw_exception(validation_error(validation_error::invalid_bool_value));
}
#endif
BOOST_PROGRAM_OPTIONS_DECL
@@ -212,212 +194,120 @@ namespace boost { namespace program_options {
invalid_option_value::
invalid_option_value(const std::string& bad_value)
: validation_error(validation_error::invalid_option_value)
{
set_substitute("value", bad_value);
}
: validation_error(validation_error::invalid_option_value, bad_value)
{}
#ifndef BOOST_NO_STD_WSTRING
namespace
{
std::string convert_value(const std::wstring& s)
{
try {
return to_local_8_bit(s);
}
catch(const std::exception&) {
return "<unrepresentable unicode string>";
}
}
}
invalid_option_value::
invalid_option_value(const std::wstring& bad_value)
: validation_error(validation_error::invalid_option_value)
{
set_substitute("value", convert_value(bad_value));
}
: validation_error(validation_error::invalid_option_value, convert_value(bad_value))
{}
#endif
invalid_bool_value::
invalid_bool_value(const std::string& bad_value)
: validation_error(validation_error::invalid_bool_value)
{
set_substitute("value", bad_value);
const std::string&
unknown_option::get_option_name() const throw()
{
return m_option_name;
}
error_with_option_name::error_with_option_name( const std::string& template_,
const std::string& option_name,
const std::string& original_token,
int option_style) :
error(template_),
m_option_style(option_style),
m_error_template(template_)
const std::string&
ambiguous_option::get_option_name() const throw()
{
return m_option_name;
}
const std::vector<std::string>&
ambiguous_option::alternatives() const throw()
{
// parameter | placeholder | value
// --------- | ----------- | -----
set_substitute_default("canonical_option", "option '%canonical_option%'", "option");
set_substitute_default("value", "argument ('%value%')", "argument");
set_substitute_default("prefix", "%prefix%", "");
m_substitutions["option"] = option_name;
m_substitutions["original_token"] = original_token;
return m_alternatives;
}
const char* error_with_option_name::what() const throw()
void
multiple_values::set_option_name(const std::string& option_name)
{
// will substitute tokens each time what is run()
substitute_placeholders(m_error_template);
return m_message.c_str();
m_option_name = option_name;
}
void error_with_option_name::replace_token(const string& from, const string& to) const
const std::string&
multiple_values::get_option_name() const throw()
{
while (1)
{
std::size_t pos = m_message.find(from.c_str(), 0, from.length());
// not found: all replaced
if (pos == std::string::npos)
return;
m_message.replace(pos, from.length(), to);
}
return m_option_name;
}
void
multiple_occurrences::set_option_name(const std::string& option_name)
{
m_option_name = option_name;
}
string error_with_option_name::get_canonical_option_prefix() const
const std::string&
multiple_occurrences::get_option_name() const throw()
{
switch (m_option_style)
{
case command_line_style::allow_dash_for_short:
return "-";
case command_line_style::allow_slash_for_short:
return "/";
case command_line_style::allow_long_disguise:
return "-";
case command_line_style::allow_long:
return "--";
case 0:
return "";
}
throw std::logic_error("error_with_option_name::m_option_style can only be "
"one of [0, allow_dash_for_short, allow_slash_for_short, "
"allow_long_disguise or allow_long]");
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("'"));
}
}
string error_with_option_name::get_canonical_option_name() const
void
validation_error::set_option_name(const std::string& option_name)
{
if (!m_substitutions.find("option")->second.length())
return m_substitutions.find("original_token")->second;
string original_token = strip_prefixes(m_substitutions.find("original_token")->second);
string option_name = strip_prefixes(m_substitutions.find("option")->second);
// For long options, use option name
if (m_option_style == command_line_style::allow_long ||
m_option_style == command_line_style::allow_long_disguise)
return get_canonical_option_prefix() + option_name;
// For short options use first letter of original_token
if (m_option_style && original_token.length())
return get_canonical_option_prefix() + original_token[0];
// no prefix
return option_name;
m_option_name = option_name;
}
void error_with_option_name::substitute_placeholders(const string& error_template) const
const std::string&
validation_error::get_option_name() const throw()
{
m_message = error_template;
std::map<std::string, std::string> substitutions(m_substitutions);
substitutions["canonical_option"] = get_canonical_option_name();
substitutions["prefix"] = get_canonical_option_prefix();
//
// replace placeholder with defaults if values are missing
//
for (map<string, string_pair>::const_iterator iter = m_substitution_defaults.begin();
iter != m_substitution_defaults.end(); ++iter)
{
// missing parameter: use default
if (substitutions.count(iter->first) == 0 ||
substitutions[iter->first].length() == 0)
replace_token(iter->second.first, iter->second.second);
}
//
// replace placeholder with values
// placeholder are denoted by surrounding '%'
//
for (map<string, string>::iterator iter = substitutions.begin();
iter != substitutions.end(); ++iter)
replace_token('%' + iter->first + '%', iter->second);
return m_option_name;
}
void ambiguous_option::substitute_placeholders(const string& original_error_template) const
{
// For short forms, all alternatives must be identical, by
// definition, to the specified option, so we don't need to
// display alternatives
if (m_option_style == command_line_style::allow_dash_for_short ||
m_option_style == command_line_style::allow_slash_for_short)
{
error_with_option_name::substitute_placeholders(original_error_template);
return;
}
string error_template = original_error_template;
// remove duplicates using std::set
std::set<std::string> alternatives_set (m_alternatives.begin(), m_alternatives.end());
std::vector<std::string> alternatives_vec (alternatives_set.begin(), alternatives_set.end());
error_template += " and matches ";
// Being very cautious: should be > 1 alternative!
if (alternatives_vec.size() > 1)
{
for (unsigned i = 0; i < alternatives_vec.size() - 1; ++i)
error_template += "'%prefix%" + alternatives_vec[i] + "', ";
error_template += "and ";
}
// there is a programming error if multiple options have the same name...
if (m_alternatives.size() > 1 && alternatives_vec.size() == 1)
error_template += "different versions of ";
error_template += "'%prefix%" + alternatives_vec.back() + "'";
// use inherited logic
error_with_option_name::substitute_placeholders(error_template);
}
string
validation_error::get_template(kind_t kind)
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 invalid_bool_value:
msg = "the argument ('%value%') for option '%canonical_option%' is invalid. Valid choices are 'on|off', 'yes|no', '1|0' and 'true|false'";
break;
case invalid_option_value:
msg = "the argument ('%value%') for option '%canonical_option%' is invalid";
break;
case multiple_values_not_allowed:
msg = "option '%canonical_option%' only takes a single argument";
msg = "multiple values not allowed";
break;
case at_least_one_value_required:
msg = "option '%canonical_option%' requires at least one argument";
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;
// currently unused
case invalid_option:
msg = "option '%canonical_option%' is not valid";
msg = "invalid option";
break;
default:
msg = "unknown error";
@@ -425,4 +315,21 @@ namespace boost { namespace program_options {
return msg;
}
const char*
validation_error::what() const throw()
{
if (!m_option_name.empty())
{
m_message = "in option '" + m_option_name + "': "
+ error_message(m_kind);
}
return m_message.c_str();
}
const std::string&
required_option::get_option_name() const throw()
{
return m_option_name;
}
}}

View File

@@ -38,68 +38,65 @@ namespace boost { namespace program_options {
// Declared once, to please Intel in VC++ mode;
unsigned i;
// Declared here so can be used to provide context for exceptions
string option_name;
string original_token;
// First, convert/store all given options
for (i = 0; i < options.options.size(); ++i) {
try
{
const string& name = options.options[i].string_key;
// Skip positional options without name
if (name.empty())
continue;
// First, convert/store all given options
for (i = 0; i < options.options.size(); ++i) {
// 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;
option_name = options.options[i].string_key;
original_token = options.options[i].original_tokens.size() ?
options.options[i].original_tokens[0] :
option_name;
// Skip positional options without name
if (option_name.empty())
continue;
// If option has final value, skip this assignment
if (xm.m_final.count(name))
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;
const option_description& d = desc.find(name, false,
false, false);
// If option has final value, skip this assignment
if (xm.m_final.count(option_name))
continue;
string original_token = options.options[i].original_tokens.size() ?
options.options[i].original_tokens[0] : "";
const option_description& d = desc.find(option_name, false,
false, false);
variable_value& v = m[option_name];
if (v.defaulted()) {
// Explicit assignment here erases defaulted value
v = variable_value();
}
d.semantic()->parse(v.value(), options.options[i].value, utf8);
v.m_value_semantic = d.semantic();
// The option is not composing, and the value is explicitly
// provided. Ignore values of this option for subsequent
// calls to 'store'. We store this to a temporary set,
// so that several assignment inside *this* 'store' call
// are allowed.
if (!d.semantic()->is_composing())
new_final.insert(option_name);
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);
}
}
#ifndef BOOST_NO_EXCEPTIONS
catch(error_with_option_name& e)
{
// add context and rethrow
e.add_context(option_name, original_token, options.m_options_prefix);
throw;
}
catch(validation_error& e)
{
e.set_option_name(name);
throw;
}
catch(multiple_occurrences& e)
{
e.set_option_name(name);
throw;
}
catch(multiple_values& e)
{
e.set_option_name(name);
throw;
}
#endif
v.m_value_semantic = d.semantic();
// The option is not composing, and the value is explicitly
// provided. Ignore values of this option for subsequent
// calls to 'store'. We store this to a temporary set,
// so that several assignment inside *this* 'store' call
// are allowed.
if (!d.semantic()->is_composing())
new_final.insert(name);
}
xm.m_final.insert(new_final.begin(), new_final.end());
@@ -130,14 +127,7 @@ namespace boost { namespace program_options {
// add empty value if this is an required option
if (d.semantic()->is_required()) {
// For option names specified in multiple ways, e.g. on the command line,
// config file etc, the following precedence rules apply:
// "--" > ("-" or "/") > ""
// Precedence is set conveniently by a single call to length()
string canonical_name = d.canonical_display_name(options.m_options_prefix);
if (canonical_name.length() > xm.m_required[key].length())
xm.m_required[key] = canonical_name;
xm.m_required.insert(key);
}
}
}
@@ -214,16 +204,15 @@ namespace boost { namespace program_options {
variables_map::notify()
{
// This checks if all required options occur
for (map<string, string>::const_iterator r = m_required.begin();
for (set<string>::const_iterator r = m_required.begin();
r != m_required.end();
++r)
{
const string& opt = r->first;
const string& display_opt = r->second;
const string& opt = *r;
map<string, variable_value>::const_iterator iter = find(opt);
if (iter == end() || iter->second.empty())
{
boost::throw_exception(required_option(display_opt));
boost::throw_exception(required_option(opt));
}
}

View File

@@ -7,8 +7,6 @@
#include <boost/program_options/parsers.hpp>
#include <cctype>
using std::size_t;
#ifdef _WIN32
namespace boost { namespace program_options {
@@ -91,7 +89,7 @@ namespace boost { namespace program_options {
{
std::vector<std::wstring> result;
std::vector<std::string> aux = split_winmain(to_internal(cmdline));
for (size_t i = 0, e = aux.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

@@ -32,7 +32,6 @@ test-suite program_options :
[ po-test split_test.cpp ]
[ po-test unrecognized_test.cpp ]
[ po-test required_test.cpp : required_test.cfg ]
[ po-test exception_txt_test.cpp ]
;
exe test_convert : test_convert.cpp ;

View File

@@ -63,7 +63,7 @@ void test_unknown_option()
catch (unknown_option& e)
{
BOOST_CHECK_EQUAL(e.get_option_name(), "-f");
BOOST_CHECK_EQUAL(string(e.what()), "unrecognised option '-f'");
BOOST_CHECK_EQUAL(string(e.what()), "unknown option -f");
}
}
@@ -94,8 +94,8 @@ void test_multiple_values()
// because: untyped_value always has one value and this is filtered before reach specific
// validation and parsing
//
BOOST_CHECK_EQUAL(e.get_option_name(), "--cfgfile");
BOOST_CHECK_EQUAL(string(e.what()), "option '--cfgfile' only takes a single argument");
BOOST_CHECK_EQUAL(e.get_option_name(), "cfgfile");
BOOST_CHECK_EQUAL(string(e.what()), "in option 'cfgfile': multiple values not allowed");
}
}
@@ -118,8 +118,8 @@ void test_multiple_occurrences()
}
catch (multiple_occurrences& e)
{
BOOST_CHECK_EQUAL(e.get_option_name(), "--cfgfile");
BOOST_CHECK_EQUAL(string(e.what()), "option '--cfgfile' cannot be specified more than once");
BOOST_CHECK_EQUAL(e.get_option_name(), "cfgfile");
BOOST_CHECK_EQUAL(string(e.what()), "multiple occurrences");
}
}
@@ -145,7 +145,7 @@ void test_missing_value()
catch (invalid_command_line_syntax& e)
{
BOOST_CHECK_EQUAL(e.kind(), invalid_syntax::missing_parameter);
BOOST_CHECK_EQUAL(e.tokens(), "--cfgfile");
BOOST_CHECK_EQUAL(e.tokens(), "cfgfile");
}
}

View File

@@ -1,672 +0,0 @@
// Copyright Leo Goodstadt 2012
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt
// or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <boost/program_options/parsers.hpp>
#include <boost/program_options/options_description.hpp>
#include <boost/program_options/variables_map.hpp>
#include <boost/program_options/cmdline.hpp>
using namespace boost::program_options;
#include <iostream>
#include <sstream>
#include <vector>
#include <cassert>
using namespace std;
#include "minitest.hpp"
//
// like BOOST_CHECK_EQUAL but with more descriptive error message
//
#define CHECK_EQUAL(description, a, b) if (a != b) {std::cerr << "\n\nError:\n<<" << \
description << ">>\n Expected text=\"" << b << "\"\n Actual text =\"" << a << "\"\n\n"; assert(a == b);}
// Uncomment for Debugging, removes asserts so we can see more failures!
//#define BOOST_ERROR(description) std::cerr << description; std::cerr << "\n";
//8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888
//
// Uncomment to print out the complete set of diagnostic messages for the different test cases
/*
#define CHECK_EQUAL(description, a, b) if (a != b) {std::cerr << "\n\nError: " << \
description << "\n Expecting\n" << b << "\n Found\n" << a << "\n\n"; } \
else {std::cout << description<< "\t" << b << "\n";}
*/
//8888888888888888888888888888888888888888888888888888888888888888888888888888888888888888
//
// test exception for each specified command line style, e.g. short dash or config file
//
template<typename EXCEPTION>
void test_each_exception_message(const string& test_description, const vector<const char*>& argv, options_description& desc, int style, string exception_msg, istream& is = cin)
{
if (exception_msg.length() == 0)
return;
variables_map vm;
unsigned argc = argv.size();
try {
if (style == -1)
store(parse_config_file(is, desc), vm);
else
store(parse_command_line(argv.size(), argv.data(), desc, style), vm);
notify(vm);
}
catch (EXCEPTION& e)
{
//cerr << "Correct:\n\t" << e.what() << "\n";
CHECK_EQUAL(test_description, e.what(), exception_msg);
return;
}
catch (std::exception& e)
{
// concatenate argv without boost::algorithm::join
string argv_txt;
for (unsigned ii = 0; ii < argc - 1; ++ii)
argv_txt += argv[ii] + string(" ");
if (argc)
argv_txt += argv[argc - 1];
BOOST_ERROR("\n<<" + test_description +
string(">>\n Unexpected exception type!\n Actual text =\"") + e.what() +
"\"\n argv =\"" + argv_txt +
"\"\n Expected text=\"" + exception_msg + "\"\n");
return;
}
BOOST_ERROR(test_description + ": No exception thrown. ");
}
//
// test exception messages for all command line styles (unix/long/short/slash/config file)
//
// try each command line style in turn
const int unix_style = command_line_style::unix_style;
const int short_dash = command_line_style::allow_dash_for_short | command_line_style::allow_short | command_line_style::short_allow_adjacent | command_line_style::allow_sticky;
const int short_slash = command_line_style::allow_slash_for_short | command_line_style::allow_short | command_line_style::short_allow_adjacent;
const int long_dash = command_line_style::allow_long | command_line_style::long_allow_adjacent | command_line_style::allow_guessing;
template<typename EXCEPTION>
void test_exception_message(const vector<vector<const char*> >& argv,
options_description& desc,
const string& error_description,
const char* expected_message_template[5])
{
string expected_message;
// unix
expected_message = expected_message_template[0];
test_each_exception_message<EXCEPTION>(error_description + " -- unix",
argv[0], desc, unix_style, expected_message);
// long dash only
expected_message = expected_message_template[1];
test_each_exception_message<EXCEPTION>(error_description + " -- long_dash",
argv[1], desc, long_dash, expected_message);
// short dash only
expected_message = expected_message_template[2];
test_each_exception_message<EXCEPTION>(error_description + " -- short_dash",
argv[2], desc, short_dash, expected_message);
// short slash only
expected_message = expected_message_template[3];
test_each_exception_message<EXCEPTION>(error_description + " -- short_slash",
argv[3], desc, short_slash, expected_message);
// config file only
expected_message = expected_message_template[4];
if (expected_message.length())
{
istringstream istrm(argv[4][0]);
test_each_exception_message<EXCEPTION>(error_description + " -- config_file",
argv[4], desc, -1, expected_message, istrm);
}
}
#define VEC_STR_PUSH_BACK(vec, c_array) \
vec.push_back(vector<const char*>(c_array, c_array + sizeof(c_array) / sizeof(char*)));
//________________________________________________________________________________________
//
// invalid_option_value
//
//________________________________________________________________________________________
void test_invalid_option_value_exception_msg()
{
options_description desc;
desc.add_options()
("int-option,d", value< int >(), "An option taking an integer")
;
vector<vector<const char*> > argv;
const char* argv0[] = { "program", "-d", "A_STRING"} ; VEC_STR_PUSH_BACK(argv, argv0);
const char* argv1[] = { "program", "--int", "A_STRING"}; VEC_STR_PUSH_BACK(argv, argv1);
const char* argv2[] = { "program", "-d", "A_STRING"} ; VEC_STR_PUSH_BACK(argv, argv2);
const char* argv3[] = { "program", "/d", "A_STRING"} ; VEC_STR_PUSH_BACK(argv, argv3);
const char* argv4[] = { "int-option=A_STRING"} ; VEC_STR_PUSH_BACK(argv, argv4);
const char* expected_msg[5] = {
"the argument ('A_STRING') for option '--int-option' is invalid",
"the argument ('A_STRING') for option '--int-option' is invalid",
"the argument ('A_STRING') for option '-d' is invalid",
"the argument ('A_STRING') for option '/d' is invalid",
"the argument ('A_STRING') for option 'int-option' is invalid",
};
test_exception_message<invalid_option_value>(argv, desc, "invalid_option_value",
expected_msg);
}
//________________________________________________________________________________________
//
// missing_value
//
//________________________________________________________________________________________
void test_missing_value_exception_msg()
{
options_description desc;
desc.add_options()
("cfgfile,e", value<string>(), "the config file")
("output,o", value<string>(), "the output file")
;
vector<vector<const char*> > argv;
const char* argv0[] = { "program", "-e", "-e", "output.txt"} ; VEC_STR_PUSH_BACK(argv, argv0);
const char* argv1[] = { "program", "--cfgfile"} ; VEC_STR_PUSH_BACK(argv, argv1);
const char* argv2[] = { "program", "-e", "-e", "output.txt"} ; VEC_STR_PUSH_BACK(argv, argv2);
const char* argv3[] = { "program", "/e", "/e", "output.txt"} ; VEC_STR_PUSH_BACK(argv, argv3);
const char* argv4[] = { ""} ; VEC_STR_PUSH_BACK(argv, argv4);
const char* expected_msg[5] = {
"the required argument for option '--cfgfile' is missing",
"the required argument for option '--cfgfile' is missing",
"the required argument for option '-e' is missing",
"", // Ignore probable bug in cmdline::finish_option
//"the required argument for option '/e' is missing",
"",
};
test_exception_message<invalid_command_line_syntax>(argv, desc,
"invalid_syntax::missing_parameter",
expected_msg);
}
//________________________________________________________________________________________
//
// ambiguous_option
//
//________________________________________________________________________________________
void test_ambiguous_option_exception_msg()
{
options_description desc;
desc.add_options()
("cfgfile1,c", value<string>(), "the config file")
("cfgfile2,o", value<string>(), "the config file")
("good,g", "good option")
("output,c", value<string>(), "the output file")
("output", value<string>(), "the output file")
;
vector<vector<const char*> > argv;
const char* argv0[] = {"program", "-ggc", "file", "-o", "anotherfile"} ; VEC_STR_PUSH_BACK(argv, argv0);
const char* argv1[] = {"program", "--cfgfile", "file", "--cfgfile", "anotherfile"} ; VEC_STR_PUSH_BACK(argv, argv1);
const char* argv2[] = {"program", "-ggc", "file", "-o", "anotherfile"} ; VEC_STR_PUSH_BACK(argv, argv2);
const char* argv3[] = {"program", "/c", "file", "/o", "anotherfile"} ; VEC_STR_PUSH_BACK(argv, argv3);
const char* argv4[] = { "output=output.txt\n"} ; VEC_STR_PUSH_BACK(argv, argv4);
const char* expected_msg[5] = {
"option '-c' is ambiguous and matches '--cfgfile1', and '--output'",
"option '--cfgfile' is ambiguous and matches '--cfgfile1', and '--cfgfile2'",
"option '-c' is ambiguous",
"option '/c' is ambiguous",
"option 'output' is ambiguous and matches different versions of 'output'",
};
test_exception_message<ambiguous_option>(argv, desc, "ambiguous_option",
expected_msg);
}
//________________________________________________________________________________________
//
// multiple_occurrences
//
//________________________________________________________________________________________
void test_multiple_occurrences_exception_msg()
{
options_description desc;
desc.add_options()
("cfgfile,c", value<string>(), "the configfile")
;
vector<vector<const char*> > argv;
const char* argv0[] = {"program", "-c", "file", "-c", "anotherfile"} ; VEC_STR_PUSH_BACK(argv, argv0);
const char* argv1[] = {"program", "--cfgfi", "file", "--cfgfi", "anotherfile"} ; VEC_STR_PUSH_BACK(argv, argv1);
const char* argv2[] = {"program", "-c", "file", "-c", "anotherfile"} ; VEC_STR_PUSH_BACK(argv, argv2);
const char* argv3[] = {"program", "/c", "file", "/c", "anotherfile"} ; VEC_STR_PUSH_BACK(argv, argv3);
const char* argv4[] = { "cfgfile=output.txt\ncfgfile=output.txt\n"} ; VEC_STR_PUSH_BACK(argv, argv4);
const char* expected_msg[5] = {
"option '--cfgfile' cannot be specified more than once",
"option '--cfgfile' cannot be specified more than once",
"option '-c' cannot be specified more than once",
"option '/c' cannot be specified more than once",
"option 'cfgfile' cannot be specified more than once",
};
test_exception_message<multiple_occurrences>(argv, desc, "multiple_occurrences",
expected_msg);
}
//________________________________________________________________________________________
//
// unknown_option
//
//________________________________________________________________________________________
void test_unknown_option_exception_msg()
{
options_description desc;
desc.add_options()
("good,g", "good option")
;
vector<vector<const char*> > argv;
const char* argv0[] = {"program", "-ggc", "file"} ; VEC_STR_PUSH_BACK(argv, argv0);
const char* argv1[] = {"program", "--cfgfile", "file"} ; VEC_STR_PUSH_BACK(argv, argv1);
const char* argv2[] = {"program", "-ggc", "file"} ; VEC_STR_PUSH_BACK(argv, argv2);
const char* argv3[] = {"program", "/c", "file"} ; VEC_STR_PUSH_BACK(argv, argv3);
const char* argv4[] = { "cfgfile=output.txt\n"} ; VEC_STR_PUSH_BACK(argv, argv4);
const char* expected_msg[5] = {
"unrecognised option '-ggc'",
"unrecognised option '--cfgfile'",
"unrecognised option '-ggc'",
"unrecognised option '/c'",
"unrecognised option 'cfgfile'",
};
test_exception_message<unknown_option>(argv, desc, "unknown_option", expected_msg);
}
//________________________________________________________________________________________
//
// validation_error::invalid_bool_value
//
//________________________________________________________________________________________
void test_invalid_bool_value_exception_msg()
{
options_description desc;
desc.add_options()
("bool_option,b", value< bool>(), "bool_option")
;
vector<vector<const char*> > argv;
const char* argv0[] = {"program", "-b", "file"} ; VEC_STR_PUSH_BACK(argv, argv0);
const char* argv1[] = {"program", "--bool_optio", "file"} ; VEC_STR_PUSH_BACK(argv, argv1);
const char* argv2[] = {"program", "-b", "file"} ; VEC_STR_PUSH_BACK(argv, argv2);
const char* argv3[] = {"program", "/b", "file"} ; VEC_STR_PUSH_BACK(argv, argv3);
const char* argv4[] = { "bool_option=output.txt\n"} ; VEC_STR_PUSH_BACK(argv, argv4);
const char* expected_msg[5] = {
"the argument ('file') for option '--bool_option' is invalid. Valid choices are 'on|off', 'yes|no', '1|0' and 'true|false'",
"the argument ('file') for option '--bool_option' is invalid. Valid choices are 'on|off', 'yes|no', '1|0' and 'true|false'",
"the argument ('file') for option '-b' is invalid. Valid choices are 'on|off', 'yes|no', '1|0' and 'true|false'",
"the argument ('file') for option '/b' is invalid. Valid choices are 'on|off', 'yes|no', '1|0' and 'true|false'",
"the argument ('output.txt') for option 'bool_option' is invalid. Valid choices are 'on|off', 'yes|no', '1|0' and 'true|false'",
};
test_exception_message<validation_error>(argv,
desc,
"validation_error::invalid_bool_value",
expected_msg);
}
//________________________________________________________________________________________
//
// validation_error::multiple_values_not_allowed
//
//________________________________________________________________________________________
//
// Strange exception: sole purpose seems to be catching multitoken() associated with a scalar
// validation_error::multiple_values_not_allowed seems thus to be a programmer error
//
//
void test_multiple_values_not_allowed_exception_msg()
{
options_description desc;
desc.add_options()
("cfgfile,c", value<string>()->multitoken(), "the config file")
("good,g", "good option")
("output,o", value<string>(), "the output file")
;
vector<vector<const char*> > argv;
const char* argv0[] = { "program", "-c", "file", "c", "-o", "fritz", "hugo" } ; VEC_STR_PUSH_BACK(argv, argv0);
const char* argv1[] = { "program", "--cfgfil", "file", "c", "--outpu", "fritz", "hugo" } ; VEC_STR_PUSH_BACK(argv, argv1);
const char* argv2[] = { "program", "-c", "file", "c", "-o", "fritz", "hugo"} ; VEC_STR_PUSH_BACK(argv, argv2);
const char* argv3[] = { "program", "/c", "file", "c", "/o", "fritz", "hugo"} ; VEC_STR_PUSH_BACK(argv, argv3);
const char* argv4[] = { "" } ; VEC_STR_PUSH_BACK(argv, argv4);
const char* expected_msg[5] = {
"option '--cfgfile' only takes a single argument",
"option '--cfgfile' only takes a single argument",
"option '-c' only takes a single argument",
"option '/c' only takes a single argument",
"",
};
test_exception_message<validation_error>(argv,
desc,
"validation_error::multiple_values_not_allowed",
expected_msg);
}
//________________________________________________________________________________________
//
// validation_error::at_least_one_value_required
//
//________________________________________________________________________________________
//
// Strange exception: sole purpose seems to be catching zero_tokens() associated with a scalar
// validation_error::multiple_values_not_allowed seems thus to be a programmer error
//
//
void test_at_least_one_value_required_exception_msg()
{
options_description desc;
desc.add_options()
("cfgfile,c", value<int>()->zero_tokens(), "the config file")
("other,o", value<string>(), "other")
;
vector<vector<const char*> > argv;
const char* argv0[] = { "program", "-c" } ; VEC_STR_PUSH_BACK(argv, argv0);
const char* argv1[] = { "program", "--cfg", "--o", "name" } ; VEC_STR_PUSH_BACK(argv, argv1);
const char* argv2[] = { "program", "-c" , "-o" , "name" } ; VEC_STR_PUSH_BACK(argv, argv2);
const char* argv3[] = { "program", "/c" } ; VEC_STR_PUSH_BACK(argv, argv3);
const char* argv4[] = { "" } ; VEC_STR_PUSH_BACK(argv, argv4);
const char* expected_msg[5] = {
"option '--cfgfile' requires at least one argument",
"option '--cfgfile' requires at least one argument",
"option '-c' requires at least one argument",
"option '/c' requires at least one argument",
"",
};
test_exception_message<validation_error>(argv,
desc,
"validation_error::at_least_one_value_required",
expected_msg);
}
//________________________________________________________________________________________
//
// required_option
//
//________________________________________________________________________________________
void test_required_option_exception_msg()
{
options_description desc;
desc.add_options()
("cfgfile,c", value<string>()->required(), "the config file")
("good,g", "good option")
("output,o", value<string>()->required(), "the output file")
;
vector<vector<const char*> > argv;
const char* argv0[] = { "program", "-g" } ; VEC_STR_PUSH_BACK(argv, argv0);
const char* argv1[] = { "program", "--g" } ; VEC_STR_PUSH_BACK(argv, argv1);
const char* argv2[] = { "program", "-g"} ; VEC_STR_PUSH_BACK(argv, argv2);
const char* argv3[] = { "program", "/g"} ; VEC_STR_PUSH_BACK(argv, argv3);
const char* argv4[] = { "" } ; VEC_STR_PUSH_BACK(argv, argv4);
const char* expected_msg[5] = {
"the option '--cfgfile' is required but missing",
"the option '--cfgfile' is required but missing",
"the option '-c' is required but missing",
"the option '/c' is required but missing",
"the option 'cfgfile' is required but missing",
};
test_exception_message<required_option>(argv,
desc,
"required_option",
expected_msg);
}
/**
* Check if this is the expected exception with the right message is being thrown inside
* func
*/
template <typename EXCEPTION, typename FUNC>
void test_exception(const string& test_name, const string& exception_txt, FUNC func)
{
try {
options_description desc;
variables_map vm;
func(desc, vm);
}
catch (EXCEPTION& e)
{
CHECK_EQUAL(test_name, e.what(), exception_txt);
return;
}
catch (std::exception& e)
{
BOOST_ERROR(string(test_name + ":\nUnexpected exception. ") + e.what() +
"\nExpected text:\n" + exception_txt + "\n\n");
return;
}
BOOST_ERROR(test_name + ": No exception thrown. ");
}
//________________________________________________________________________________________
//
// check_reading_file
//
//________________________________________________________________________________________
void check_reading_file(options_description& desc, variables_map& vm)
{
desc.add_options()
("output,o", value<string>(), "the output file");
const char* file_name = "no_such_file";
store(parse_config_file<char>(file_name, desc, true), vm);
}
//________________________________________________________________________________________
//
// config_file_wildcard
//
//________________________________________________________________________________________
void config_file_wildcard(options_description& desc, variables_map& vm)
{
desc.add_options()
("outpu*", value<string>(), "the output file1")
("outp*", value<string>(), "the output file2")
;
istringstream is("output1=whichone\noutput2=whichone\n");
store(parse_config_file(is, desc), vm);
}
//________________________________________________________________________________________
//
// invalid_syntax::unrecognized_line
//
//________________________________________________________________________________________
void unrecognized_line(options_description& desc, variables_map& vm)
{
istringstream is("funny wierd line\n");
store(parse_config_file(is, desc), vm);
}
//________________________________________________________________________________________
//
// abbreviated_options_in_config_file
//
//________________________________________________________________________________________
void abbreviated_options_in_config_file(options_description& desc, variables_map& vm)
{
desc.add_options()(",o", value<string>(), "the output file");
istringstream is("o=output.txt\n");
store(parse_config_file(is, desc), vm);
}
//________________________________________________________________________________________
//
// too_many_positional_options
//
//________________________________________________________________________________________
void too_many_positional_options(options_description& desc, variables_map& vm)
{
const char* argv[] = {"program", "1", "2", "3"};
positional_options_description positional_args;
positional_args.add("two_positional_arguments", 2);
store(command_line_parser(4, argv).options(desc).positional(positional_args).run(), vm);
}
//________________________________________________________________________________________
//
// invalid_command_line_style
//
//________________________________________________________________________________________
void test_invalid_command_line_style_exception_msg()
{
string test_name = "invalid_command_line_style";
using namespace command_line_style;
options_description desc;
desc.add_options()("output,o", value<string>(), "the output file");
vector<int> invalid_styles;
invalid_styles.push_back(allow_short | short_allow_adjacent);
invalid_styles.push_back(allow_short | allow_dash_for_short);
invalid_styles.push_back(allow_long);
vector<string> invalid_diagnostics;
invalid_diagnostics.push_back("boost::program_options misconfiguration: choose one "
"or other of 'command_line_style::allow_slash_for_short' "
"(slashes) or 'command_line_style::allow_dash_for_short' "
"(dashes) for short options.");
invalid_diagnostics.push_back("boost::program_options misconfiguration: choose one "
"or other of 'command_line_style::short_allow_next' "
"(whitespace separated arguments) or "
"'command_line_style::short_allow_adjacent' ('=' "
"separated arguments) for short options.");
invalid_diagnostics.push_back("boost::program_options misconfiguration: choose one "
"or other of 'command_line_style::long_allow_next' "
"(whitespace separated arguments) or "
"'command_line_style::long_allow_adjacent' ('=' "
"separated arguments) for long options.");
const char* argv[] = {"program"};
variables_map vm;
for (unsigned ii = 0; ii < 3; ++ii)
{
bool exception_thrown = false;
try
{
store(parse_command_line(1, argv, desc, invalid_styles[ii]), vm);
}
catch (invalid_command_line_style& e)
{
string error_msg("arguments are not allowed for unabbreviated option names");
CHECK_EQUAL(test_name, e.what(), invalid_diagnostics[ii]);
exception_thrown = true;
}
catch (std::exception& e)
{
BOOST_ERROR(string(test_name + ":\nUnexpected exception. ") + e.what() +
"\nExpected text:\n" + invalid_diagnostics[ii] + "\n");
exception_thrown = true;
}
if (!exception_thrown)
{
BOOST_ERROR(test_name << ": No exception thrown. ");
}
}
}
int main(int /*ac*/, char** /*av*/)
{
test_ambiguous_option_exception_msg();
test_unknown_option_exception_msg();
test_multiple_occurrences_exception_msg();
test_missing_value_exception_msg();
test_invalid_option_value_exception_msg();
test_invalid_bool_value_exception_msg();
test_multiple_values_not_allowed_exception_msg();
test_required_option_exception_msg();
test_at_least_one_value_required_exception_msg();
string test_name;
string expected_message;
// check_reading_file
test_name = "check_reading_file";
expected_message = "can not read options configuration file 'no_such_file'";
test_exception<reading_file>(test_name, expected_message, check_reading_file);
// config_file_wildcard
test_name = "config_file_wildcard";
expected_message = "options 'outpu*' and 'outp*' will both match the same arguments from the configuration file";
test_exception<error>(test_name, expected_message, config_file_wildcard);
// unrecognized_line
test_name = "unrecognized_line";
expected_message = "the options configuration file contains an invalid line 'funny wierd line'";
test_exception<invalid_syntax>(test_name, expected_message, unrecognized_line);
// abbreviated_options_in_config_file
test_name = "abbreviated_options_in_config_file";
expected_message = "abbreviated option names are not permitted in options configuration files";
test_exception<error>(test_name, expected_message, abbreviated_options_in_config_file);
test_name = "too_many_positional_options";
expected_message = "too many positional options have been specified on the command line";
test_exception<too_many_positional_options_error>(
test_name, expected_message, too_many_positional_options);
test_invalid_command_line_style_exception_msg();
return 0;
}

View File

@@ -228,21 +228,6 @@ void test_default_values()
);
}
void test_value_name()
{
options_description desc("Supported options");
desc.add_options()
("include", value<string>()->value_name("directory"), "Search for headers in 'directory'.")
;
stringstream ss;
ss << desc;
BOOST_CHECK_EQUAL(ss.str(),
"Supported options:\n"
" --include directory Search for headers in 'directory'.\n"
);
}
int main(int, char* [])
{
@@ -253,7 +238,6 @@ int main(int, char* [])
test_long_default_value();
test_word_wrapping();
test_default_values();
test_value_name();
return 0;
}

View File

@@ -34,7 +34,6 @@ void required_throw_test()
notify(vm);
}
catch (required_option& e) {
BOOST_CHECK_EQUAL(e.what(), string("the option '--cfgfile' is required but missing"));
throwed = true;
}
BOOST_CHECK(throwed);