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