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 + ")";
dsa_decrypt_key(const unsigned char * in,unsigned long inlen,unsigned char * out,unsigned long * outlen,dsa_key * key)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