mirror of
https://github.com/boostorg/program_options.git
synced 2026-01-19 04:22:15 +00:00
Merge from trunk.
[SVN r77829]
This commit is contained in:
@@ -12,6 +12,8 @@ SOURCES =
|
||||
lib boost_program_options
|
||||
: $(SOURCES).cpp
|
||||
: <link>shared:<define>BOOST_PROGRAM_OPTIONS_DYN_LINK=1 # tell source we're building dll's
|
||||
# See https://svn.boost.org/trac/boost/ticket/5049
|
||||
<target-os>hpux,<toolset>gcc:<define>_INCLUDE_STDC__SOURCE_199901
|
||||
:
|
||||
: <link>shared:<define>BOOST_PROGRAM_OPTIONS_DYN_LINK=1
|
||||
;
|
||||
|
||||
@@ -181,7 +181,7 @@ options_description desc;
|
||||
desc.add_options()
|
||||
("help", "produce help message")
|
||||
("compression", value<string>(), "compression level")
|
||||
("verbose", value<string>()->zero_tokens(), "verbosity level")
|
||||
("verbose", value<string>()->implicit_value("0"), "verbosity level")
|
||||
("email", value<string>()->multitoken(), "email to send to")
|
||||
;
|
||||
</programlisting>
|
||||
|
||||
@@ -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<int>(), "set compression level")
|
||||
("compression", po::value<double>(), "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 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (vm.count("compression")) {
|
||||
cout << "Compression level was set to "
|
||||
<< vm["compression"].as<int>() << ".\n";
|
||||
<< vm["compression"].as<double>() << ".\n";
|
||||
} else {
|
||||
cout << "Compression level was not set.\n";
|
||||
}
|
||||
|
||||
@@ -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>(cout, " "));
|
||||
copy(v.begin(), v.end(), ostream_iterator<T>(os, " "));
|
||||
return os;
|
||||
}
|
||||
|
||||
|
||||
@@ -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>(cout, " "));
|
||||
copy(v.begin(), v.end(), ostream_iterator<T>(os, " "));
|
||||
return os;
|
||||
}
|
||||
|
||||
|
||||
@@ -81,6 +81,18 @@ 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);
|
||||
|
||||
@@ -100,7 +100,11 @@ namespace boost { namespace program_options {
|
||||
basic_parsed_options<charT>
|
||||
basic_command_line_parser<charT>::run()
|
||||
{
|
||||
parsed_options result(m_desc);
|
||||
// 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());
|
||||
result.options = detail::cmdline::run();
|
||||
|
||||
// Presense of parsed_options -> wparsed_options conversion
|
||||
|
||||
@@ -12,6 +12,8 @@
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
|
||||
#if defined(BOOST_MSVC)
|
||||
# pragma warning (push)
|
||||
@@ -21,170 +23,17 @@
|
||||
|
||||
namespace boost { namespace program_options {
|
||||
|
||||
inline std::string strip_prefixes(const std::string& text)
|
||||
{
|
||||
return text.substr(text.find_last_of("-/") + 1);
|
||||
}
|
||||
|
||||
/** 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.
|
||||
@@ -192,16 +41,10 @@ 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")
|
||||
: error("too many positional arguments have been specified on the command line")
|
||||
{}
|
||||
};
|
||||
|
||||
/** 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:
|
||||
@@ -214,26 +57,355 @@ 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 file ").append(filename))
|
||||
: error(std::string("can not read options configuration file '").append(filename).append("'"))
|
||||
{}
|
||||
};
|
||||
|
||||
/** 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();
|
||||
|
||||
/** 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& option_name){}
|
||||
|
||||
~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
|
||||
};
|
||||
|
||||
private:
|
||||
std::string m_option_name; // The name of the option which
|
||||
// caused the exception.
|
||||
};
|
||||
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);
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}}
|
||||
|
||||
#if defined(BOOST_MSVC)
|
||||
|
||||
@@ -102,6 +102,16 @@ 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
|
||||
|
||||
@@ -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)
|
||||
: description(xdescription) {}
|
||||
explicit basic_parsed_options(const options_description* xdescription, int options_prefix = 0)
|
||||
: description(xdescription), m_options_prefix(options_prefix) {}
|
||||
/** Options found in the source. */
|
||||
std::vector< basic_option<charT> > options;
|
||||
/** Options description that was used for parsing.
|
||||
@@ -46,6 +46,17 @@ 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:
|
||||
@@ -64,6 +75,17 @@ 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;
|
||||
@@ -260,6 +282,10 @@ namespace boost { namespace program_options {
|
||||
|
||||
}}
|
||||
|
||||
#if defined(BOOST_MSVC)
|
||||
# pragma warning (pop)
|
||||
#endif
|
||||
|
||||
#undef DECL
|
||||
|
||||
#include "boost/program_options/detail/parsers.hpp"
|
||||
|
||||
@@ -261,13 +261,21 @@ namespace boost { namespace program_options {
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Specifies that the value can span multiple tokens. */
|
||||
/** Specifies that the value can span multiple tokens.
|
||||
*/
|
||||
typed_value* multitoken()
|
||||
{
|
||||
m_multitoken = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Specifies that no tokens may be provided as the value of
|
||||
this option, which means that only presense of the option
|
||||
is significant. For such option to be useful, either the
|
||||
'validate' function should be specialized, or the
|
||||
'implicit_value' method should be also used. In most
|
||||
cases, you can use the 'bool_switch' function instead of
|
||||
using this method. */
|
||||
typed_value* zero_tokens()
|
||||
{
|
||||
m_zero_tokens = true;
|
||||
|
||||
@@ -153,6 +153,9 @@ namespace boost { namespace program_options {
|
||||
// Resolve conflict between inherited operators.
|
||||
const variable_value& operator[](const std::string& name) const
|
||||
{ return abstract_variables_map::operator[](name); }
|
||||
|
||||
// Override to clear some extra fields.
|
||||
void clear();
|
||||
|
||||
void notify();
|
||||
|
||||
@@ -171,8 +174,10 @@ namespace boost { namespace program_options {
|
||||
bool utf8);
|
||||
|
||||
/** Names of required options, filled by parser which has
|
||||
access to options_description. */
|
||||
std::set<std::string> m_required;
|
||||
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;
|
||||
};
|
||||
|
||||
|
||||
@@ -208,4 +213,8 @@ namespace boost { namespace program_options {
|
||||
|
||||
}}
|
||||
|
||||
#if defined(BOOST_MSVC)
|
||||
# pragma warning (pop)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
326
src/cmdline.cpp
326
src/cmdline.cpp
@@ -34,64 +34,43 @@ 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::error_message(kind_t kind)
|
||||
invalid_syntax::get_template(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 long_not_allowed:
|
||||
msg = "long options are not allowed";
|
||||
break;
|
||||
case long_adjacent_not_allowed:
|
||||
msg = "parameters adjacent to long options not allowed";
|
||||
break;
|
||||
case short_adjacent_not_allowed:
|
||||
msg = "parameters adjust to short options are not allowed";
|
||||
break;
|
||||
case empty_adjacent_parameter:
|
||||
msg = "adjacent parameter is empty";
|
||||
msg = "the argument for option '%canonical_option%' should follow immediately after the equal sign";
|
||||
break;
|
||||
case missing_parameter:
|
||||
msg = "required parameter is missing";
|
||||
break;
|
||||
case extra_parameter:
|
||||
msg = "extra parameter";
|
||||
msg = "the required argument for option '%canonical_option%' is missing";
|
||||
break;
|
||||
case unrecognized_line:
|
||||
msg = "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";
|
||||
break;
|
||||
case long_adjacent_not_allowed:
|
||||
msg = "the unabbreviated option '%canonical_option%' does not take any arguments";
|
||||
break;
|
||||
case short_adjacent_not_allowed:
|
||||
msg = "the abbreviated option '%canonical_option%' does not take any arguments";
|
||||
break;
|
||||
case extra_parameter:
|
||||
msg = "option '%canonical_option%' does not take any arguments";
|
||||
break;
|
||||
default:
|
||||
msg = "unknown error";
|
||||
msg = "unknown command line syntax error for '%s'";
|
||||
}
|
||||
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)
|
||||
{}
|
||||
|
||||
}}
|
||||
|
||||
@@ -156,15 +135,26 @@ namespace boost { namespace program_options { namespace detail {
|
||||
const char* error = 0;
|
||||
if (allow_some_long &&
|
||||
!(style & long_allow_adjacent) && !(style & long_allow_next))
|
||||
error = "style disallows parameters for long options";
|
||||
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.";
|
||||
|
||||
if (!error && (style & allow_short) &&
|
||||
!(style & short_allow_adjacent) && !(style & short_allow_next))
|
||||
error = "style disallows parameters for short options";
|
||||
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.";
|
||||
|
||||
if (!error && (style & allow_short) &&
|
||||
!(style & allow_dash_for_short) && !(style & allow_slash_for_short))
|
||||
error = "style disallows all characters for short options";
|
||||
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.";
|
||||
|
||||
if (error)
|
||||
boost::throw_exception(invalid_command_line_style(error));
|
||||
@@ -192,6 +182,23 @@ 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()
|
||||
@@ -277,7 +284,7 @@ namespace boost { namespace program_options { namespace detail {
|
||||
}
|
||||
|
||||
/* If an key option is followed by a positional option,
|
||||
can can consume more tokens (e.g. it's multitoke option),
|
||||
can can consume more tokens (e.g. it's multitoken option),
|
||||
give those tokens to it. */
|
||||
vector<option> result2;
|
||||
for (unsigned i = 0; i < result.size(); ++i)
|
||||
@@ -288,11 +295,21 @@ namespace boost { namespace program_options { namespace detail {
|
||||
if (opt.string_key.empty())
|
||||
continue;
|
||||
|
||||
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));
|
||||
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;
|
||||
}
|
||||
|
||||
if (!xd)
|
||||
continue;
|
||||
|
||||
@@ -383,92 +400,112 @@ namespace boost { namespace program_options { namespace detail {
|
||||
if (opt.string_key.empty())
|
||||
return;
|
||||
|
||||
// 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));
|
||||
//
|
||||
// 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];
|
||||
|
||||
if (!xd)
|
||||
try
|
||||
{
|
||||
if (m_allow_unregistered) {
|
||||
opt.unregistered = true;
|
||||
return;
|
||||
} else {
|
||||
boost::throw_exception(unknown_option(opt.string_key));
|
||||
}
|
||||
}
|
||||
const option_description& d = *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));
|
||||
|
||||
// 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 (!xd)
|
||||
{
|
||||
boost::throw_exception(invalid_command_line_syntax(opt.string_key,
|
||||
invalid_command_line_syntax::extra_parameter));
|
||||
if (m_allow_unregistered) {
|
||||
opt.unregistered = true;
|
||||
return;
|
||||
} else {
|
||||
boost::throw_exception(unknown_option());
|
||||
}
|
||||
}
|
||||
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();
|
||||
|
||||
// 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)
|
||||
unsigned present_tokens = opt.value.size() + other_tokens.size();
|
||||
|
||||
if (present_tokens >= min_tokens)
|
||||
{
|
||||
min_tokens -= opt.value.size();
|
||||
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 -= 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());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
min_tokens = 0;
|
||||
}
|
||||
boost::throw_exception(
|
||||
invalid_command_line_syntax(invalid_command_line_syntax::missing_parameter));
|
||||
|
||||
// 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
|
||||
}
|
||||
// use only original token for unknown_option / ambiguous_option since by definition
|
||||
// they are unrecognised / unparsable
|
||||
catch(error_with_option_name& e)
|
||||
{
|
||||
boost::throw_exception(invalid_command_line_syntax(opt.string_key,
|
||||
invalid_command_line_syntax::missing_parameter));
|
||||
|
||||
// add context and rethrow
|
||||
e.add_context(opt.string_key, original_token_for_exceptions, get_canonical_option_prefix());
|
||||
throw;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
vector<option>
|
||||
@@ -486,8 +523,11 @@ 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(name,
|
||||
invalid_command_line_syntax::empty_adjacent_parameter) );
|
||||
boost::throw_exception( invalid_command_line_syntax(
|
||||
invalid_command_line_syntax::empty_adjacent_parameter,
|
||||
name,
|
||||
name,
|
||||
get_canonical_option_prefix()) );
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -523,9 +563,20 @@ namespace boost { namespace program_options { namespace detail {
|
||||
// of token is considered to be value, not further grouped
|
||||
// option.
|
||||
for(;;) {
|
||||
const option_description* d
|
||||
= m_desc->find_nothrow(name, false, false,
|
||||
is_style_active(short_case_insensitive));
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
// FIXME: check for 'allow_sticky'.
|
||||
if (d && (m_style & allow_sticky) &&
|
||||
@@ -589,15 +640,24 @@ namespace boost { namespace program_options { namespace detail {
|
||||
((tok[0] == '-' && tok[1] != '-') ||
|
||||
((m_style & allow_slash_for_short) && tok[0] == '/')))
|
||||
{
|
||||
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)))
|
||||
try
|
||||
{
|
||||
args[0].insert(0, "-");
|
||||
if (args[0][1] == '/')
|
||||
args[0][1] = '-';
|
||||
return parse_long_option(args);
|
||||
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;
|
||||
}
|
||||
}
|
||||
return vector<option>();
|
||||
|
||||
@@ -57,7 +57,9 @@ namespace boost { namespace program_options { namespace detail {
|
||||
bad_prefixes = true;
|
||||
}
|
||||
if (bad_prefixes)
|
||||
boost::throw_exception(error("bad prefixes"));
|
||||
boost::throw_exception(error("options '" + string(name) + "' and '" +
|
||||
*i + "*' will both match the same "
|
||||
"arguments from the configuration file"));
|
||||
allowed_prefixes.insert(s);
|
||||
}
|
||||
}
|
||||
@@ -117,7 +119,7 @@ namespace boost { namespace program_options { namespace detail {
|
||||
break;
|
||||
|
||||
} else {
|
||||
boost::throw_exception(invalid_syntax(s, invalid_syntax::unrecognized_line));
|
||||
boost::throw_exception(invalid_config_file_syntax(s, invalid_syntax::unrecognized_line));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -137,6 +137,31 @@ 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
|
||||
{
|
||||
@@ -174,10 +199,13 @@ namespace boost { namespace program_options {
|
||||
option_description::format_name() const
|
||||
{
|
||||
if (!m_short_name.empty())
|
||||
return string(m_short_name).append(" [ --").
|
||||
append(m_long_name).append(" ]");
|
||||
else
|
||||
return string("--").append(m_long_name);
|
||||
{
|
||||
return m_long_name.empty()
|
||||
? m_short_name
|
||||
: string(m_short_name).append(" [ --").
|
||||
append(m_long_name).append(" ]");
|
||||
}
|
||||
return string("--").append(m_long_name);
|
||||
}
|
||||
|
||||
std::string
|
||||
@@ -289,7 +317,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(name));
|
||||
boost::throw_exception(unknown_option());
|
||||
return *d;
|
||||
}
|
||||
|
||||
@@ -337,8 +365,7 @@ namespace boost { namespace program_options {
|
||||
}
|
||||
}
|
||||
if (full_matches.size() > 1)
|
||||
boost::throw_exception(
|
||||
ambiguous_option(name, full_matches));
|
||||
boost::throw_exception(ambiguous_option(full_matches));
|
||||
|
||||
// If we have a full match, and an approximate match,
|
||||
// ignore approximate match instead of reporting error.
|
||||
@@ -346,8 +373,7 @@ 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(name, approximate_matches));
|
||||
boost::throw_exception(ambiguous_option(approximate_matches));
|
||||
|
||||
return found.get();
|
||||
}
|
||||
@@ -396,7 +422,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"));
|
||||
"Only one tab per paragraph is allowed in the options description"));
|
||||
}
|
||||
|
||||
// erase tab from string
|
||||
|
||||
@@ -45,7 +45,10 @@
|
||||
// See: http://article.gmane.org/gmane.comp.lib.boost.devel/103843
|
||||
// See: http://lists.gnu.org/archive/html/bug-guile/2004-01/msg00013.html
|
||||
#if defined(__APPLE__) && defined(__DYNAMIC__)
|
||||
#include <crt_externs.h>
|
||||
// The proper include for this is crt_externs.h, however it's not
|
||||
// available on iOS. The right replacement is not known. See
|
||||
// https://svn.boost.org/trac/boost/ticket/5053
|
||||
extern "C" { extern char ***_NSGetEnviron(void); }
|
||||
#define environ (*_NSGetEnviron())
|
||||
#else
|
||||
#if defined(__MWERKS__)
|
||||
@@ -85,7 +88,8 @@ namespace boost { namespace program_options {
|
||||
basic_parsed_options<wchar_t>
|
||||
::basic_parsed_options(const parsed_options& po)
|
||||
: description(po.description),
|
||||
utf8_encoded_options(po)
|
||||
utf8_encoded_options(po),
|
||||
m_options_prefix(po.m_options_prefix)
|
||||
{
|
||||
for (unsigned i = 0; i < po.options.size(); ++i)
|
||||
options.push_back(woption_from_option(po.options[i]));
|
||||
@@ -107,7 +111,7 @@ namespace boost { namespace program_options {
|
||||
|
||||
if (d.long_name().empty())
|
||||
boost::throw_exception(
|
||||
error("long name required for config file"));
|
||||
error("abbreviated option names are not permitted in options configuration files"));
|
||||
|
||||
allowed_options.insert(d.long_name());
|
||||
}
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
#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>
|
||||
|
||||
@@ -14,6 +16,22 @@ 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,
|
||||
@@ -139,7 +157,7 @@ namespace boost { namespace program_options {
|
||||
else if (s == "off" || s == "no" || s == "0" || s == "false")
|
||||
v = any(false);
|
||||
else
|
||||
boost::throw_exception(validation_error(validation_error::invalid_bool_value, s));
|
||||
boost::throw_exception(invalid_bool_value(s));
|
||||
}
|
||||
|
||||
// This is blatant copy-paste. However, templating this will cause a problem,
|
||||
@@ -161,7 +179,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(validation_error(validation_error::invalid_bool_value));
|
||||
boost::throw_exception(invalid_bool_value(convert_value(s)));
|
||||
}
|
||||
#endif
|
||||
BOOST_PROGRAM_OPTIONS_DECL
|
||||
@@ -194,120 +212,212 @@ namespace boost { namespace program_options {
|
||||
|
||||
invalid_option_value::
|
||||
invalid_option_value(const std::string& bad_value)
|
||||
: validation_error(validation_error::invalid_option_value, bad_value)
|
||||
{}
|
||||
: validation_error(validation_error::invalid_option_value)
|
||||
{
|
||||
set_substitute("value", bad_value);
|
||||
}
|
||||
|
||||
#ifndef BOOST_NO_STD_WSTRING
|
||||
namespace
|
||||
invalid_option_value::
|
||||
invalid_option_value(const std::wstring& bad_value)
|
||||
: validation_error(validation_error::invalid_option_value)
|
||||
{
|
||||
std::string convert_value(const std::wstring& s)
|
||||
set_substitute("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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
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_)
|
||||
{
|
||||
// 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;
|
||||
}
|
||||
|
||||
|
||||
const char* error_with_option_name::what() const throw()
|
||||
{
|
||||
// will substitute tokens each time what is run()
|
||||
substitute_placeholders(m_error_template);
|
||||
|
||||
return m_message.c_str();
|
||||
}
|
||||
|
||||
void error_with_option_name::replace_token(const string& from, const string& to) const
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
try {
|
||||
return to_local_8_bit(s);
|
||||
}
|
||||
catch(const std::exception&) {
|
||||
return "<unrepresentable unicode string>";
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
invalid_option_value::
|
||||
invalid_option_value(const std::wstring& bad_value)
|
||||
: validation_error(validation_error::invalid_option_value, convert_value(bad_value))
|
||||
{}
|
||||
#endif
|
||||
const std::string&
|
||||
unknown_option::get_option_name() const throw()
|
||||
{
|
||||
return m_option_name;
|
||||
string error_with_option_name::get_canonical_option_prefix() const
|
||||
{
|
||||
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]");
|
||||
}
|
||||
|
||||
const std::string&
|
||||
ambiguous_option::get_option_name() const throw()
|
||||
{
|
||||
return m_option_name;
|
||||
}
|
||||
|
||||
const std::vector<std::string>&
|
||||
ambiguous_option::alternatives() const throw()
|
||||
|
||||
string error_with_option_name::get_canonical_option_name() const
|
||||
{
|
||||
return m_alternatives;
|
||||
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;
|
||||
}
|
||||
|
||||
void
|
||||
multiple_values::set_option_name(const std::string& option_name)
|
||||
|
||||
void error_with_option_name::substitute_placeholders(const string& error_template) const
|
||||
{
|
||||
m_option_name = option_name;
|
||||
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);
|
||||
}
|
||||
|
||||
const std::string&
|
||||
multiple_values::get_option_name() const throw()
|
||||
|
||||
void ambiguous_option::substitute_placeholders(const string& original_error_template) const
|
||||
{
|
||||
return m_option_name;
|
||||
}
|
||||
|
||||
void
|
||||
multiple_occurrences::set_option_name(const std::string& option_name)
|
||||
{
|
||||
m_option_name = option_name;
|
||||
// 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);
|
||||
}
|
||||
|
||||
const std::string&
|
||||
multiple_occurrences::get_option_name() const throw()
|
||||
{
|
||||
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("'"));
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
|
||||
|
||||
string
|
||||
validation_error::get_template(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";
|
||||
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 = "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";
|
||||
break;
|
||||
case at_least_one_value_required:
|
||||
msg = "option '%canonical_option%' requires at least one argument";
|
||||
break;
|
||||
// currently unused
|
||||
case invalid_option:
|
||||
msg = "invalid option";
|
||||
msg = "option '%canonical_option%' is not valid";
|
||||
break;
|
||||
default:
|
||||
msg = "unknown error";
|
||||
@@ -315,21 +425,4 @@ 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;
|
||||
}
|
||||
|
||||
}}
|
||||
|
||||
@@ -38,65 +38,68 @@ namespace boost { namespace program_options {
|
||||
// Declared once, to please Intel in VC++ mode;
|
||||
unsigned i;
|
||||
|
||||
// First, convert/store all given options
|
||||
for (i = 0; i < options.options.size(); ++i) {
|
||||
// Declared here so can be used to provide context for exceptions
|
||||
string option_name;
|
||||
string original_token;
|
||||
|
||||
const string& name = options.options[i].string_key;
|
||||
// Skip positional options without name
|
||||
if (name.empty())
|
||||
continue;
|
||||
try
|
||||
{
|
||||
|
||||
// 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;
|
||||
// First, convert/store all given options
|
||||
for (i = 0; i < options.options.size(); ++i) {
|
||||
|
||||
// If option has final value, skip this assignment
|
||||
if (xm.m_final.count(name))
|
||||
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;
|
||||
|
||||
const option_description& d = desc.find(name, false,
|
||||
false, false);
|
||||
// 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;
|
||||
|
||||
variable_value& v = m[name];
|
||||
if (v.defaulted()) {
|
||||
// Explicit assignment here erases defaulted value
|
||||
v = variable_value();
|
||||
}
|
||||
|
||||
try {
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
#ifndef BOOST_NO_EXCEPTIONS
|
||||
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);
|
||||
catch(error_with_option_name& e)
|
||||
{
|
||||
// add context and rethrow
|
||||
e.add_context(option_name, original_token, options.m_options_prefix);
|
||||
throw;
|
||||
}
|
||||
#endif
|
||||
xm.m_final.insert(new_final.begin(), new_final.end());
|
||||
|
||||
|
||||
@@ -127,7 +130,14 @@ namespace boost { namespace program_options {
|
||||
|
||||
// add empty value if this is an required option
|
||||
if (d.semantic()->is_required()) {
|
||||
xm.m_required.insert(key);
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -182,6 +192,13 @@ namespace boost { namespace program_options {
|
||||
: abstract_variables_map(next)
|
||||
{}
|
||||
|
||||
void variables_map::clear()
|
||||
{
|
||||
std::map<std::string, variable_value>::clear();
|
||||
m_final.clear();
|
||||
m_required.clear();
|
||||
}
|
||||
|
||||
const variable_value&
|
||||
variables_map::get(const std::string& name) const
|
||||
{
|
||||
@@ -197,15 +214,16 @@ namespace boost { namespace program_options {
|
||||
variables_map::notify()
|
||||
{
|
||||
// This checks if all required options occur
|
||||
for (set<string>::const_iterator r = m_required.begin();
|
||||
for (map<string, string>::const_iterator r = m_required.begin();
|
||||
r != m_required.end();
|
||||
++r)
|
||||
{
|
||||
const string& opt = *r;
|
||||
const string& opt = r->first;
|
||||
const string& display_opt = r->second;
|
||||
map<string, variable_value>::const_iterator iter = find(opt);
|
||||
if (iter == end() || iter->second.empty())
|
||||
{
|
||||
boost::throw_exception(required_option(opt));
|
||||
boost::throw_exception(required_option(display_opt));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -378,6 +378,15 @@ void test_guessing()
|
||||
{0, 0, 0}
|
||||
};
|
||||
test_cmdline("opt123 opt56 foo,f=", style, test_cases1);
|
||||
|
||||
test_case test_cases2[] = {
|
||||
{"--fname file --fname2 file2", s_success, "fname: file fname2: file2"},
|
||||
{"--fnam file --fnam file2", s_ambiguous_option, ""},
|
||||
{"--fnam file --fname2 file2", s_ambiguous_option, ""},
|
||||
{"--fname2 file2 --fnam file", s_ambiguous_option, ""},
|
||||
{0, 0, 0}
|
||||
};
|
||||
test_cmdline("fname fname2", style, test_cases2);
|
||||
}
|
||||
|
||||
void test_arguments()
|
||||
|
||||
@@ -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()), "unknown option -f");
|
||||
BOOST_CHECK_EQUAL(string(e.what()), "unrecognised 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()), "in option 'cfgfile': multiple values not allowed");
|
||||
BOOST_CHECK_EQUAL(e.get_option_name(), "--cfgfile");
|
||||
BOOST_CHECK_EQUAL(string(e.what()), "option '--cfgfile' only takes a single argument");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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()), "multiple occurrences");
|
||||
BOOST_CHECK_EQUAL(e.get_option_name(), "--cfgfile");
|
||||
BOOST_CHECK_EQUAL(string(e.what()), "option '--cfgfile' cannot be specified more than once");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
4053
test/exception_txt_test.cpp
Normal file
4053
test/exception_txt_test.cpp
Normal file
File diff suppressed because it is too large
Load Diff
@@ -21,7 +21,7 @@ void do_it()
|
||||
f.write("(\"opt%d\", value<int>())\n")
|
||||
f.write(";\n}\n")
|
||||
f.close()
|
||||
os.system(compiler_command + " -c -save-temps -I /home/ghost/Work/boost-rc program_options_test.cpp")
|
||||
os.system(compiler_command + " -c -save-temps -I /home/ghost/Work/Boost/boost-svn program_options_test.cpp")
|
||||
|
||||
nm = os.popen("nm -S program_options_test.o")
|
||||
for l in nm:
|
||||
@@ -45,7 +45,7 @@ def run_tests(range, compiler_command):
|
||||
print "Avarage: ", (last_size-first_size)/(range[-1]-range[0])
|
||||
|
||||
if __name__ == '__main__':
|
||||
for compiler in [ "g++-3.3 -Os", "g++-3.3 -O3", "g++-3.4 -Os", "g++-3.4 -O3"]:
|
||||
for compiler in [ "g++ -Os", "g++ -O3"]:
|
||||
print "****", compiler, "****"
|
||||
run_tests(range(1, 20), compiler)
|
||||
|
||||
|
||||
@@ -34,6 +34,7 @@ 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);
|
||||
|
||||
Reference in New Issue
Block a user