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