diff options
author | Remko Tronçon <git@el-tramo.be> | 2012-12-23 13:16:26 (GMT) |
---|---|---|
committer | Remko Tronçon <git@el-tramo.be> | 2012-12-23 14:43:26 (GMT) |
commit | 491ddd570a752cf9bda85933bed0c6942e39b1f9 (patch) | |
tree | 10c25c1be8cc08d0497df1dccd56a10fbb30beee /3rdParty/Boost/src/libs/program_options | |
parent | da7d7a0ca71b80281aa9ff2526290b61ccb0cc60 (diff) | |
download | swift-491ddd570a752cf9bda85933bed0c6942e39b1f9.zip swift-491ddd570a752cf9bda85933bed0c6942e39b1f9.tar.bz2 |
Update Boost to 1.52.0.
Change-Id: I1e56bea2600bf2ed9c5b3aba8c4f9d2a0f350e77
Diffstat (limited to '3rdParty/Boost/src/libs/program_options')
9 files changed, 510 insertions, 305 deletions
diff --git a/3rdParty/Boost/src/libs/program_options/src/cmdline.cpp b/3rdParty/Boost/src/libs/program_options/src/cmdline.cpp index be31385..cd9a5fe 100644 --- a/3rdParty/Boost/src/libs/program_options/src/cmdline.cpp +++ b/3rdParty/Boost/src/libs/program_options/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 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 = "long options are not allowed"; + msg = "the unabbreviated option '%canonical_option%' is not valid"; break; case long_adjacent_not_allowed: - msg = "parameters adjacent to long options not allowed"; + msg = "the unabbreviated option '%canonical_option%' does not take any arguments"; 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"; - break; - case missing_parameter: - msg = "required parameter is missing"; + msg = "the abbreviated option '%canonical_option%' does not take any arguments"; break; case extra_parameter: - msg = "extra parameter"; - break; - case unrecognized_line: - msg = "unrecognized line"; + 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() @@ -242,7 +249,7 @@ namespace boost { namespace program_options { namespace detail { bool ok = false; for(unsigned i = 0; i < style_parsers.size(); ++i) { - unsigned current_size = args.size(); + unsigned current_size = static_cast<unsigned>(args.size()); vector<option> next = style_parsers[i](args); // Check that option names @@ -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; @@ -304,7 +321,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 - opt.value.size(); + int can_take_more = max_tokens - static_cast<int>(opt.value.size()); unsigned j = i+1; for (; can_take_more && j < result.size(); --can_take_more, ++j) { @@ -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); + if (!xd) + { + if (m_allow_unregistered) { + opt.unregistered = true; + return; + } else { + boost::throw_exception(unknown_option()); + } + } + const option_description& d = *xd; - // 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. + // Canonize the name + opt.string_key = d.key(opt.string_key); - // We don't check if those tokens look like option, or not! + // 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. - 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) - { - boost::throw_exception(invalid_command_line_syntax(opt.string_key, - invalid_command_line_syntax::extra_parameter)); - } - - // If an option wants, at minimum, N tokens, we grab them there, - // 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; - } + // We don't check if those tokens look like option, or not! - // Everything's OK, move the values to the result. - for(;!other_tokens.empty() && min_tokens--; ) + 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) { - // 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) + 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) { - followed_option = style_parsers[i](next_token); + min_tokens -= static_cast<unsigned>(opt.value.size()); } - if (!followed_option.empty()) + else { - 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)); + 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()); } - 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)); + else + { + boost::throw_exception( + invalid_command_line_syntax(invalid_command_line_syntax::missing_parameter)); + } + } + // 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; } + } 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 + { + 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) { - args[0].insert(0, "-"); - if (args[0][1] == '/') - args[0][1] = '-'; - return parse_long_option(args); + // add context and rethrow + e.add_context(tok, tok, get_canonical_option_prefix()); + throw; } } return vector<option>(); diff --git a/3rdParty/Boost/src/libs/program_options/src/config_file.cpp b/3rdParty/Boost/src/libs/program_options/src/config_file.cpp index a12844c..f2a57b4 100644 --- a/3rdParty/Boost/src/libs/program_options/src/config_file.cpp +++ b/3rdParty/Boost/src/libs/program_options/src/config_file.cpp @@ -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)); } } } diff --git a/3rdParty/Boost/src/libs/program_options/src/options_description.cpp b/3rdParty/Boost/src/libs/program_options/src/options_description.cpp index 0d8dfd4..343bd30 100644 --- a/3rdParty/Boost/src/libs/program_options/src/options_description.cpp +++ b/3rdParty/Boost/src/libs/program_options/src/options_description.cpp @@ -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 @@ -443,7 +469,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 = distance(line_begin, par_end); + unsigned remaining = static_cast<unsigned>(std::distance(line_begin, par_end)); string::const_iterator line_end = line_begin + ((remaining < line_length) ? remaining : line_length); @@ -463,7 +489,7 @@ namespace boost { namespace program_options { { // is last_space within the second half ot the // current line - if (static_cast<unsigned>(distance(last_space, line_end)) < + if (static_cast<unsigned>(std::distance(last_space, line_end)) < (line_length / 2)) { line_end = last_space; @@ -476,8 +502,8 @@ namespace boost { namespace program_options { if (first_line) { - indent += par_indent; - line_length -= par_indent; // there's less to work with now + indent += static_cast<unsigned>(par_indent); + line_length -= static_cast<unsigned>(par_indent); // there's less to work with now first_line = false; } @@ -566,7 +592,7 @@ namespace boost { namespace program_options { os.put(' '); } } else { - for(unsigned pad = first_column_width - ss.str().size(); pad > 0; --pad) + for(unsigned pad = first_column_width - static_cast<unsigned>(ss.str().size()); pad > 0; --pad) { os.put(' '); } diff --git a/3rdParty/Boost/src/libs/program_options/src/parsers.cpp b/3rdParty/Boost/src/libs/program_options/src/parsers.cpp index bc3b858..2361a48 100644 --- a/3rdParty/Boost/src/libs/program_options/src/parsers.cpp +++ b/3rdParty/Boost/src/libs/program_options/src/parsers.cpp @@ -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()); } diff --git a/3rdParty/Boost/src/libs/program_options/src/positional_options.cpp b/3rdParty/Boost/src/libs/program_options/src/positional_options.cpp index 55995d7..72dc0d6 100644 --- a/3rdParty/Boost/src/libs/program_options/src/positional_options.cpp +++ b/3rdParty/Boost/src/libs/program_options/src/positional_options.cpp @@ -34,7 +34,7 @@ namespace boost { namespace program_options { positional_options_description::max_total_count() const { return m_trailing.empty() ? - m_names.size() : (std::numeric_limits<unsigned>::max)(); + static_cast<unsigned>(m_names.size()) : (std::numeric_limits<unsigned>::max)(); } const std::string& diff --git a/3rdParty/Boost/src/libs/program_options/src/program_options_utf8_codecvt_facet.cpp b/3rdParty/Boost/src/libs/program_options/src/program_options_utf8_codecvt_facet.cpp index c0fd7c0..2e4c532 100644 --- a/3rdParty/Boost/src/libs/program_options/src/program_options_utf8_codecvt_facet.cpp +++ b/3rdParty/Boost/src/libs/program_options/src/program_options_utf8_codecvt_facet.cpp @@ -12,7 +12,7 @@ #define BOOST_UTF8_END_NAMESPACE }}} #define BOOST_UTF8_DECL BOOST_PROGRAM_OPTIONS_DECL -#include "../../detail/utf8_codecvt_facet.cpp" +#include <boost/detail/utf8_codecvt_facet.ipp> #undef BOOST_UTF8_BEGIN_NAMESPACE diff --git a/3rdParty/Boost/src/libs/program_options/src/value_semantic.cpp b/3rdParty/Boost/src/libs/program_options/src/value_semantic.cpp index f5770f1..5314029 100644 --- a/3rdParty/Boost/src/libs/program_options/src/value_semantic.cpp +++ b/3rdParty/Boost/src/libs/program_options/src/value_semantic.cpp @@ -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) - {} - -#ifndef BOOST_NO_STD_WSTRING - namespace + : validation_error(validation_error::invalid_option_value) { - std::string convert_value(const std::wstring& s) - { - try { - return to_local_8_bit(s); - } - catch(const std::exception&) { - return "<unrepresentable unicode string>"; - } - } + set_substitute("value", bad_value); } +#ifndef BOOST_NO_STD_WSTRING 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; + : validation_error(validation_error::invalid_option_value) + { + set_substitute("value", convert_value(bad_value)); } +#endif - const std::string& - ambiguous_option::get_option_name() const throw() - { - return m_option_name; - } - - const std::vector<std::string>& - ambiguous_option::alternatives() const throw() + + + invalid_bool_value:: + invalid_bool_value(const std::string& bad_value) + : validation_error(validation_error::invalid_bool_value) { - return m_alternatives; + set_substitute("value", bad_value); } - void - multiple_values::set_option_name(const std::string& 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_) { - m_option_name = option_name; + // 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 std::string& - multiple_values::get_option_name() const throw() + + const char* error_with_option_name::what() const throw() { - return m_option_name; + // will substitute tokens each time what is run() + substitute_placeholders(m_error_template); + + return m_message.c_str(); } - - void - multiple_occurrences::set_option_name(const std::string& option_name) + + void error_with_option_name::replace_token(const string& from, const string& to) const { - m_option_name = option_name; + 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); + } } - const std::string& - multiple_occurrences::get_option_name() const throw() + string error_with_option_name::get_canonical_option_prefix() const { - return m_option_name; + 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]"); } - - 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)) + + + string error_with_option_name::get_canonical_option_name() const { - if (!option_value.empty()) - { - m_message.append(std::string("'") + option_value + std::string("'")); - } + 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 - validation_error::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& - validation_error::get_option_name() const throw() + + void ambiguous_option::substitute_placeholders(const string& original_error_template) const { - return m_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); } - 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; - } - }} diff --git a/3rdParty/Boost/src/libs/program_options/src/variables_map.cpp b/3rdParty/Boost/src/libs/program_options/src/variables_map.cpp index 29b1de9..caf354e 100644 --- a/3rdParty/Boost/src/libs/program_options/src/variables_map.cpp +++ b/3rdParty/Boost/src/libs/program_options/src/variables_map.cpp @@ -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; - - // Ignore unregistered option. The 'unregistered' - // field can be true only if user has explicitly asked - // to allow unregistered options. We can't store them - // to variables map (lacking any information about paring), - // so just ignore them. - if (options.options[i].unregistered) - continue; - - // If option has final value, skip this assignment - if (xm.m_final.count(name)) - continue; - - const option_description& d = desc.find(name, false, - false, false); + try + { - variable_value& v = m[name]; - if (v.defaulted()) { - // Explicit assignment here erases defaulted value - v = variable_value(); - } - - try { + // First, convert/store all given options + for (i = 0; i < options.options.size(); ++i) { + + 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; + + // Ignore unregistered option. The 'unregistered' + // field can be true only if user has explicitly asked + // to allow unregistered options. We can't store them + // to variables map (lacking any information about paring), + // so just ignore them. + if (options.options[i].unregistered) + continue; + + // If option has final value, skip this assignment + if (xm.m_final.count(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)); } } diff --git a/3rdParty/Boost/src/libs/program_options/src/winmain.cpp b/3rdParty/Boost/src/libs/program_options/src/winmain.cpp index 8a7c43f..6220043 100644 --- a/3rdParty/Boost/src/libs/program_options/src/winmain.cpp +++ b/3rdParty/Boost/src/libs/program_options/src/winmain.cpp @@ -7,6 +7,8 @@ #include <boost/program_options/parsers.hpp> #include <cctype> +using std::size_t; + #ifdef _WIN32 namespace boost { namespace program_options { @@ -89,7 +91,7 @@ namespace boost { namespace program_options { { std::vector<std::wstring> result; std::vector<std::string> aux = split_winmain(to_internal(cmdline)); - for (unsigned i = 0, e = aux.size(); i < e; ++i) + for (size_t i = 0, e = aux.size(); i < e; ++i) result.push_back(from_utf8(aux[i])); return result; } |