| 1 | // Copyright Vladimir Prus 2004. |
| 2 | // Distributed under the Boost Software License, Version 1.0. |
| 3 | // (See accompanying file LICENSE_1_0.txt |
| 4 | // or copy at http://www.boost.org/LICENSE_1_0.txt) |
| 5 | |
| 6 | // This file defines template functions that are declared in |
| 7 | // ../value_semantic.hpp. |
| 8 | |
| 9 | #include <boost/throw_exception.hpp> |
| 10 | |
| 11 | // forward declaration |
| 12 | namespace boost { template<class T> class optional; } |
| 13 | |
| 14 | namespace boost { namespace program_options { |
| 15 | |
| 16 | extern BOOST_PROGRAM_OPTIONS_DECL std::string arg; |
| 17 | |
| 18 | template<class T, class charT> |
| 19 | std::string |
| 20 | typed_value<T, charT>::name() const |
| 21 | { |
| 22 | std::string const& var = (m_value_name.empty() ? arg : m_value_name); |
| 23 | if (!m_implicit_value.empty() && !m_implicit_value_as_text.empty()) { |
| 24 | std::string msg = "[=" + var + "(=" + m_implicit_value_as_text + ")]" ; |
| 25 | if (!m_default_value.empty() && !m_default_value_as_text.empty()) |
| 26 | msg += " (=" + m_default_value_as_text + ")" ; |
| 27 | return msg; |
| 28 | } |
| 29 | else if (!m_default_value.empty() && !m_default_value_as_text.empty()) { |
| 30 | return var + " (=" + m_default_value_as_text + ")" ; |
| 31 | } else { |
| 32 | return var; |
| 33 | } |
| 34 | } |
| 35 | |
| 36 | template<class T, class charT> |
| 37 | void |
| 38 | typed_value<T, charT>::notify(const boost::any& value_store) const |
| 39 | { |
| 40 | const T* value = boost::any_cast<T>(&value_store); |
| 41 | if (m_store_to) { |
| 42 | *m_store_to = *value; |
| 43 | } |
| 44 | if (m_notifier) { |
| 45 | m_notifier(*value); |
| 46 | } |
| 47 | } |
| 48 | |
| 49 | namespace validators { |
| 50 | /* If v.size() > 1, throw validation_error. |
| 51 | If v.size() == 1, return v.front() |
| 52 | Otherwise, returns a reference to a statically allocated |
| 53 | empty string if 'allow_empty' and throws validation_error |
| 54 | otherwise. */ |
| 55 | template<class charT> |
| 56 | const std::basic_string<charT>& get_single_string( |
| 57 | const std::vector<std::basic_string<charT> >& v, |
| 58 | bool allow_empty = false) |
| 59 | { |
| 60 | static std::basic_string<charT> empty; |
| 61 | if (v.size() > 1) |
| 62 | boost::throw_exception(validation_error(validation_error::multiple_values_not_allowed)); |
| 63 | else if (v.size() == 1) |
| 64 | return v.front(); |
| 65 | else if (!allow_empty) |
| 66 | boost::throw_exception(validation_error(validation_error::at_least_one_value_required)); |
| 67 | return empty; |
| 68 | } |
| 69 | |
| 70 | /* Throws multiple_occurrences if 'value' is not empty. */ |
| 71 | BOOST_PROGRAM_OPTIONS_DECL void |
| 72 | check_first_occurrence(const boost::any& value); |
| 73 | } |
| 74 | |
| 75 | using namespace validators; |
| 76 | |
| 77 | /** Validates 's' and updates 'v'. |
| 78 | @pre 'v' is either empty or in the state assigned by the previous |
| 79 | invocation of 'validate'. |
| 80 | The target type is specified via a parameter which has the type of |
| 81 | pointer to the desired type. This is workaround for compilers without |
| 82 | partial template ordering, just like the last 'long/int' parameter. |
| 83 | */ |
| 84 | template<class T, class charT> |
| 85 | void validate(boost::any& v, |
| 86 | const std::vector< std::basic_string<charT> >& xs, |
| 87 | T*, long) |
| 88 | { |
| 89 | validators::check_first_occurrence(v); |
| 90 | std::basic_string<charT> s(validators::get_single_string(xs)); |
| 91 | try { |
| 92 | v = any(lexical_cast<T>(s)); |
| 93 | } |
| 94 | catch(const bad_lexical_cast&) { |
| 95 | boost::throw_exception(invalid_option_value(s)); |
| 96 | } |
| 97 | } |
| 98 | |
| 99 | BOOST_PROGRAM_OPTIONS_DECL void validate(boost::any& v, |
| 100 | const std::vector<std::string>& xs, |
| 101 | bool*, |
| 102 | int); |
| 103 | |
| 104 | #if !defined(BOOST_NO_STD_WSTRING) |
| 105 | BOOST_PROGRAM_OPTIONS_DECL void validate(boost::any& v, |
| 106 | const std::vector<std::wstring>& xs, |
| 107 | bool*, |
| 108 | int); |
| 109 | #endif |
| 110 | // For some reason, this declaration, which is require by the standard, |
| 111 | // cause msvc 7.1 to not generate code to specialization defined in |
| 112 | // value_semantic.cpp |
| 113 | #if ! ( BOOST_WORKAROUND(BOOST_MSVC, == 1310) ) |
| 114 | BOOST_PROGRAM_OPTIONS_DECL void validate(boost::any& v, |
| 115 | const std::vector<std::string>& xs, |
| 116 | std::string*, |
| 117 | int); |
| 118 | |
| 119 | #if !defined(BOOST_NO_STD_WSTRING) |
| 120 | BOOST_PROGRAM_OPTIONS_DECL void validate(boost::any& v, |
| 121 | const std::vector<std::wstring>& xs, |
| 122 | std::string*, |
| 123 | int); |
| 124 | #endif |
| 125 | #endif |
| 126 | |
| 127 | /** Validates sequences. Allows multiple values per option occurrence |
| 128 | and multiple occurrences. */ |
| 129 | template<class T, class charT> |
| 130 | void validate(boost::any& v, |
| 131 | const std::vector<std::basic_string<charT> >& s, |
| 132 | std::vector<T>*, |
| 133 | int) |
| 134 | { |
| 135 | if (v.empty()) { |
| 136 | v = boost::any(std::vector<T>()); |
| 137 | } |
| 138 | std::vector<T>* tv = boost::any_cast< std::vector<T> >(&v); |
| 139 | assert(NULL != tv); |
| 140 | for (unsigned i = 0; i < s.size(); ++i) |
| 141 | { |
| 142 | try { |
| 143 | /* We call validate so that if user provided |
| 144 | a validator for class T, we use it even |
| 145 | when parsing vector<T>. */ |
| 146 | boost::any a; |
| 147 | std::vector<std::basic_string<charT> > cv; |
| 148 | cv.push_back(s[i]); |
| 149 | validate(a, cv, (T*)0, 0); |
| 150 | tv->push_back(boost::any_cast<T>(a)); |
| 151 | } |
| 152 | catch(const bad_lexical_cast& /*e*/) { |
| 153 | boost::throw_exception(invalid_option_value(s[i])); |
| 154 | } |
| 155 | } |
| 156 | } |
| 157 | |
| 158 | /** Validates optional arguments. */ |
| 159 | template<class T, class charT> |
| 160 | void validate(boost::any& v, |
| 161 | const std::vector<std::basic_string<charT> >& s, |
| 162 | boost::optional<T>*, |
| 163 | int) |
| 164 | { |
| 165 | validators::check_first_occurrence(v); |
| 166 | validators::get_single_string(s); |
| 167 | boost::any a; |
| 168 | validate(a, s, (T*)0, 0); |
| 169 | v = boost::any(boost::optional<T>(boost::any_cast<T>(a))); |
| 170 | } |
| 171 | |
| 172 | template<class T, class charT> |
| 173 | void |
| 174 | typed_value<T, charT>:: |
| 175 | xparse(boost::any& value_store, |
| 176 | const std::vector<std::basic_string<charT> >& new_tokens) const |
| 177 | { |
| 178 | // If no tokens were given, and the option accepts an implicit |
| 179 | // value, then assign the implicit value as the stored value; |
| 180 | // otherwise, validate the user-provided token(s). |
| 181 | if (new_tokens.empty() && !m_implicit_value.empty()) |
| 182 | value_store = m_implicit_value; |
| 183 | else |
| 184 | validate(value_store, new_tokens, (T*)0, 0); |
| 185 | } |
| 186 | |
| 187 | template<class T> |
| 188 | typed_value<T>* |
| 189 | value() |
| 190 | { |
| 191 | // Explicit qualification is vc6 workaround. |
| 192 | return boost::program_options::value<T>(0); |
| 193 | } |
| 194 | |
| 195 | template<class T> |
| 196 | typed_value<T>* |
| 197 | value(T* v) |
| 198 | { |
| 199 | typed_value<T>* r = new typed_value<T>(v); |
| 200 | |
| 201 | return r; |
| 202 | } |
| 203 | |
| 204 | template<class T> |
| 205 | typed_value<T, wchar_t>* |
| 206 | wvalue() |
| 207 | { |
| 208 | return wvalue<T>(0); |
| 209 | } |
| 210 | |
| 211 | template<class T> |
| 212 | typed_value<T, wchar_t>* |
| 213 | wvalue(T* v) |
| 214 | { |
| 215 | typed_value<T, wchar_t>* r = new typed_value<T, wchar_t>(v); |
| 216 | |
| 217 | return r; |
| 218 | } |
| 219 | |
| 220 | |
| 221 | |
| 222 | }} |
| 223 | |