Chris@16: // Copyright Vladimir Prus 2004. Chris@16: // Distributed under the Boost Software License, Version 1.0. Chris@16: // (See accompanying file LICENSE_1_0.txt Chris@16: // or copy at http://www.boost.org/LICENSE_1_0.txt) Chris@16: Chris@16: // This file defines template functions that are declared in Chris@16: // ../value_semantic.hpp. Chris@16: Chris@16: #include Chris@16: Chris@16: namespace boost { namespace program_options { Chris@16: Chris@16: extern BOOST_PROGRAM_OPTIONS_DECL std::string arg; Chris@16: Chris@16: template Chris@16: std::string Chris@16: typed_value::name() const Chris@16: { Chris@16: std::string const& var = (m_value_name.empty() ? arg : m_value_name); Chris@16: if (!m_implicit_value.empty() && !m_implicit_value_as_text.empty()) { Chris@16: std::string msg = "[=" + var + "(=" + m_implicit_value_as_text + ")]"; Chris@16: if (!m_default_value.empty() && !m_default_value_as_text.empty()) Chris@16: msg += " (=" + m_default_value_as_text + ")"; Chris@16: return msg; Chris@16: } Chris@16: else if (!m_default_value.empty() && !m_default_value_as_text.empty()) { Chris@16: return var + " (=" + m_default_value_as_text + ")"; Chris@16: } else { Chris@16: return var; Chris@16: } Chris@16: } Chris@16: Chris@16: template Chris@16: void Chris@16: typed_value::notify(const boost::any& value_store) const Chris@16: { Chris@16: const T* value = boost::any_cast(&value_store); Chris@16: if (m_store_to) { Chris@16: *m_store_to = *value; Chris@16: } Chris@16: if (m_notifier) { Chris@16: m_notifier(*value); Chris@16: } Chris@16: } Chris@16: Chris@16: namespace validators { Chris@16: /* If v.size() > 1, throw validation_error. Chris@16: If v.size() == 1, return v.front() Chris@16: Otherwise, returns a reference to a statically allocated Chris@16: empty string if 'allow_empty' and throws validation_error Chris@16: otherwise. */ Chris@16: template Chris@16: const std::basic_string& get_single_string( Chris@16: const std::vector >& v, Chris@16: bool allow_empty = false) Chris@16: { Chris@16: static std::basic_string empty; Chris@16: if (v.size() > 1) Chris@16: boost::throw_exception(validation_error(validation_error::multiple_values_not_allowed)); Chris@16: else if (v.size() == 1) Chris@16: return v.front(); Chris@16: else if (!allow_empty) Chris@16: boost::throw_exception(validation_error(validation_error::at_least_one_value_required)); Chris@16: return empty; Chris@16: } Chris@16: Chris@16: /* Throws multiple_occurrences if 'value' is not empty. */ Chris@16: BOOST_PROGRAM_OPTIONS_DECL void Chris@16: check_first_occurrence(const boost::any& value); Chris@16: } Chris@16: Chris@16: using namespace validators; Chris@16: Chris@16: /** Validates 's' and updates 'v'. Chris@16: @pre 'v' is either empty or in the state assigned by the previous Chris@16: invocation of 'validate'. Chris@16: The target type is specified via a parameter which has the type of Chris@16: pointer to the desired type. This is workaround for compilers without Chris@16: partial template ordering, just like the last 'long/int' parameter. Chris@16: */ Chris@16: template Chris@16: void validate(boost::any& v, Chris@16: const std::vector< std::basic_string >& xs, Chris@16: T*, long) Chris@16: { Chris@16: validators::check_first_occurrence(v); Chris@16: std::basic_string s(validators::get_single_string(xs)); Chris@16: try { Chris@16: v = any(lexical_cast(s)); Chris@16: } Chris@16: catch(const bad_lexical_cast&) { Chris@16: boost::throw_exception(invalid_option_value(s)); Chris@16: } Chris@16: } Chris@16: Chris@16: BOOST_PROGRAM_OPTIONS_DECL void validate(boost::any& v, Chris@16: const std::vector& xs, Chris@16: bool*, Chris@16: int); Chris@16: Chris@16: #if !defined(BOOST_NO_STD_WSTRING) Chris@16: BOOST_PROGRAM_OPTIONS_DECL void validate(boost::any& v, Chris@16: const std::vector& xs, Chris@16: bool*, Chris@16: int); Chris@16: #endif Chris@16: // For some reason, this declaration, which is require by the standard, Chris@101: // cause msvc 7.1 to not generate code to specialization defined in Chris@16: // value_semantic.cpp Chris@101: #if ! ( BOOST_WORKAROUND(BOOST_MSVC, == 1310) ) Chris@16: BOOST_PROGRAM_OPTIONS_DECL void validate(boost::any& v, Chris@16: const std::vector& xs, Chris@16: std::string*, Chris@16: int); Chris@16: Chris@16: #if !defined(BOOST_NO_STD_WSTRING) Chris@16: BOOST_PROGRAM_OPTIONS_DECL void validate(boost::any& v, Chris@16: const std::vector& xs, Chris@16: std::string*, Chris@16: int); Chris@16: #endif Chris@16: #endif Chris@16: Chris@16: /** Validates sequences. Allows multiple values per option occurrence Chris@16: and multiple occurrences. */ Chris@16: template Chris@16: void validate(boost::any& v, Chris@16: const std::vector >& s, Chris@16: std::vector*, Chris@16: int) Chris@16: { Chris@16: if (v.empty()) { Chris@16: v = boost::any(std::vector()); Chris@16: } Chris@16: std::vector* tv = boost::any_cast< std::vector >(&v); Chris@16: assert(NULL != tv); Chris@16: for (unsigned i = 0; i < s.size(); ++i) Chris@16: { Chris@16: try { Chris@16: /* We call validate so that if user provided Chris@16: a validator for class T, we use it even Chris@16: when parsing vector. */ Chris@16: boost::any a; Chris@16: std::vector > cv; Chris@16: cv.push_back(s[i]); Chris@16: validate(a, cv, (T*)0, 0); Chris@16: tv->push_back(boost::any_cast(a)); Chris@16: } Chris@16: catch(const bad_lexical_cast& /*e*/) { Chris@16: boost::throw_exception(invalid_option_value(s[i])); Chris@16: } Chris@16: } Chris@16: } Chris@16: Chris@16: template Chris@16: void Chris@16: typed_value:: Chris@16: xparse(boost::any& value_store, Chris@16: const std::vector >& new_tokens) const Chris@16: { Chris@16: // If no tokens were given, and the option accepts an implicit Chris@16: // value, then assign the implicit value as the stored value; Chris@16: // otherwise, validate the user-provided token(s). Chris@16: if (new_tokens.empty() && !m_implicit_value.empty()) Chris@16: value_store = m_implicit_value; Chris@16: else Chris@16: validate(value_store, new_tokens, (T*)0, 0); Chris@16: } Chris@16: Chris@16: template Chris@16: typed_value* Chris@16: value() Chris@16: { Chris@16: // Explicit qualification is vc6 workaround. Chris@16: return boost::program_options::value(0); Chris@16: } Chris@16: Chris@16: template Chris@16: typed_value* Chris@16: value(T* v) Chris@16: { Chris@16: typed_value* r = new typed_value(v); Chris@16: Chris@16: return r; Chris@16: } Chris@16: Chris@16: template Chris@16: typed_value* Chris@16: wvalue() Chris@16: { Chris@16: return wvalue(0); Chris@16: } Chris@16: Chris@16: template Chris@16: typed_value* Chris@16: wvalue(T* v) Chris@16: { Chris@16: typed_value* r = new typed_value(v); Chris@16: Chris@16: return r; Chris@16: } Chris@16: Chris@16: Chris@16: Chris@16: }}