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 | |