]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
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 | |
17 | 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 | |
35 | 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> | |
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> | |
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> | |
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>:: | |
158 | 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>* | |
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>* | |
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>* | |
189 | wvalue() | |
190 | { | |
191 | return wvalue<T>(0); | |
192 | } | |
193 | ||
194 | template<class T> | |
195 | typed_value<T, wchar_t>* | |
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 | }} |