1 | // Copyright Vladimir Prus 2002-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 | #ifndef BOOST_PROGRAM_OPTIONS_SOURCE |
7 | # define BOOST_PROGRAM_OPTIONS_SOURCE |
8 | #endif |
9 | #include <boost/program_options/config.hpp> |
10 | #include <boost/program_options/parsers.hpp> |
11 | #include <boost/program_options/options_description.hpp> |
12 | #include <boost/program_options/value_semantic.hpp> |
13 | #include <boost/program_options/variables_map.hpp> |
14 | |
15 | #include <cassert> |
16 | |
17 | namespace boost { namespace program_options { |
18 | |
19 | using namespace std; |
20 | |
21 | // First, performs semantic actions for 'oa'. |
22 | // Then, stores in 'm' all options that are defined in 'desc'. |
23 | BOOST_PROGRAM_OPTIONS_DECL |
24 | void store(const parsed_options& options, variables_map& xm, |
25 | bool utf8) |
26 | { |
27 | // TODO: what if we have different definition |
28 | // for the same option name during different calls |
29 | // 'store'. |
30 | assert(options.description); |
31 | const options_description& desc = *options.description; |
32 | |
33 | // We need to access map's operator[], not the overriden version |
34 | // variables_map. Ehmm.. messy. |
35 | std::map<std::string, variable_value>& m = xm; |
36 | |
37 | std::set<std::string> new_final; |
38 | |
39 | // Declared once, to please Intel in VC++ mode; |
40 | unsigned i; |
41 | |
42 | // Declared here so can be used to provide context for exceptions |
43 | string option_name; |
44 | string original_token; |
45 | |
46 | #ifndef BOOST_NO_EXCEPTIONS |
47 | try |
48 | #endif |
49 | { |
50 | |
51 | // First, convert/store all given options |
52 | for (i = 0; i < options.options.size(); ++i) { |
53 | |
54 | option_name = options.options[i].string_key; |
55 | // Skip positional options without name |
56 | if (option_name.empty()) |
57 | continue; |
58 | |
59 | // Ignore unregistered option. The 'unregistered' |
60 | // field can be true only if user has explicitly asked |
61 | // to allow unregistered options. We can't store them |
62 | // to variables map (lacking any information about paring), |
63 | // so just ignore them. |
64 | if (options.options[i].unregistered) |
65 | continue; |
66 | |
67 | // If option has final value, skip this assignment |
68 | if (xm.m_final.count(x: option_name)) |
69 | continue; |
70 | |
71 | original_token = options.options[i].original_tokens.size() ? |
72 | options.options[i].original_tokens[0] : "" ; |
73 | const option_description& d = desc.find(name: option_name, approx: false, |
74 | long_ignore_case: false, short_ignore_case: false); |
75 | |
76 | variable_value& v = m[option_name]; |
77 | if (v.defaulted()) { |
78 | // Explicit assignment here erases defaulted value |
79 | v = variable_value(); |
80 | } |
81 | |
82 | d.semantic()->parse(value_store&: v.value(), new_tokens: options.options[i].value, utf8); |
83 | |
84 | v.m_value_semantic = d.semantic(); |
85 | |
86 | // The option is not composing, and the value is explicitly |
87 | // provided. Ignore values of this option for subsequent |
88 | // calls to 'store'. We store this to a temporary set, |
89 | // so that several assignment inside *this* 'store' call |
90 | // are allowed. |
91 | if (!d.semantic()->is_composing()) |
92 | new_final.insert(x: option_name); |
93 | } |
94 | } |
95 | #ifndef BOOST_NO_EXCEPTIONS |
96 | catch(error_with_option_name& e) |
97 | { |
98 | // add context and rethrow |
99 | e.add_context(option_name, original_token, option_style: options.m_options_prefix); |
100 | throw; |
101 | } |
102 | #endif |
103 | xm.m_final.insert(first: new_final.begin(), last: new_final.end()); |
104 | |
105 | |
106 | |
107 | // Second, apply default values and store required options. |
108 | const vector<shared_ptr<option_description> >& all = desc.options(); |
109 | for(i = 0; i < all.size(); ++i) |
110 | { |
111 | const option_description& d = *all[i]; |
112 | string key = d.key(option: "" ); |
113 | // FIXME: this logic relies on knowledge of option_description |
114 | // internals. |
115 | // The 'key' is empty if options description contains '*'. |
116 | // In that |
117 | // case, default value makes no sense at all. |
118 | if (key.empty()) |
119 | { |
120 | continue; |
121 | } |
122 | if (m.count(x: key) == 0) { |
123 | |
124 | boost::any def; |
125 | if (d.semantic()->apply_default(value_store&: def)) { |
126 | m[key] = variable_value(def, true); |
127 | m[key].m_value_semantic = d.semantic(); |
128 | } |
129 | } |
130 | |
131 | // add empty value if this is an required option |
132 | if (d.semantic()->is_required()) { |
133 | |
134 | // For option names specified in multiple ways, e.g. on the command line, |
135 | // config file etc, the following precedence rules apply: |
136 | // "--" > ("-" or "/") > "" |
137 | // Precedence is set conveniently by a single call to length() |
138 | string canonical_name = d.canonical_display_name(canonical_option_style: options.m_options_prefix); |
139 | if (canonical_name.length() > xm.m_required[key].length()) |
140 | xm.m_required[key] = canonical_name; |
141 | } |
142 | } |
143 | } |
144 | |
145 | BOOST_PROGRAM_OPTIONS_DECL |
146 | void store(const wparsed_options& options, variables_map& m) |
147 | { |
148 | store(options: options.utf8_encoded_options, xm&: m, utf8: true); |
149 | } |
150 | |
151 | BOOST_PROGRAM_OPTIONS_DECL |
152 | void notify(variables_map& vm) |
153 | { |
154 | vm.notify(); |
155 | } |
156 | |
157 | abstract_variables_map::abstract_variables_map() |
158 | : m_next(0) |
159 | {} |
160 | |
161 | abstract_variables_map:: |
162 | abstract_variables_map(const abstract_variables_map* next) |
163 | : m_next(next) |
164 | {} |
165 | |
166 | const variable_value& |
167 | abstract_variables_map::operator[](const std::string& name) const |
168 | { |
169 | const variable_value& v = get(name); |
170 | if (v.empty() && m_next) |
171 | return (*m_next)[name]; |
172 | else if (v.defaulted() && m_next) { |
173 | const variable_value& v2 = (*m_next)[name]; |
174 | if (!v2.empty() && !v2.defaulted()) |
175 | return v2; |
176 | else return v; |
177 | } else { |
178 | return v; |
179 | } |
180 | } |
181 | |
182 | void |
183 | abstract_variables_map::next(abstract_variables_map* next) |
184 | { |
185 | m_next = next; |
186 | } |
187 | |
188 | variables_map::variables_map() |
189 | {} |
190 | |
191 | variables_map::variables_map(const abstract_variables_map* next) |
192 | : abstract_variables_map(next) |
193 | {} |
194 | |
195 | void variables_map::clear() |
196 | { |
197 | std::map<std::string, variable_value>::clear(); |
198 | m_final.clear(); |
199 | m_required.clear(); |
200 | } |
201 | |
202 | const variable_value& |
203 | variables_map::get(const std::string& name) const |
204 | { |
205 | static variable_value empty; |
206 | const_iterator i = this->find(x: name); |
207 | if (i == this->end()) |
208 | return empty; |
209 | else |
210 | return i->second; |
211 | } |
212 | |
213 | void |
214 | variables_map::notify() |
215 | { |
216 | // This checks if all required options occur |
217 | for (map<string, string>::const_iterator r = m_required.begin(); |
218 | r != m_required.end(); |
219 | ++r) |
220 | { |
221 | const string& opt = r->first; |
222 | const string& display_opt = r->second; |
223 | map<string, variable_value>::const_iterator iter = find(x: opt); |
224 | if (iter == end() || iter->second.empty()) |
225 | { |
226 | boost::throw_exception(e: required_option(display_opt)); |
227 | |
228 | } |
229 | } |
230 | |
231 | // Lastly, run notify actions. |
232 | for (map<string, variable_value>::iterator k = begin(); |
233 | k != end(); |
234 | ++k) |
235 | { |
236 | /* Users might wish to use variables_map to store their own values |
237 | that are not parsed, and therefore will not have value_semantics |
238 | defined. Do not crash on such values. In multi-module programs, |
239 | one module might add custom values, and the 'notify' function |
240 | will be called after that, so we check that value_sematics is |
241 | not NULL. See: |
242 | https://svn.boost.org/trac/boost/ticket/2782 |
243 | */ |
244 | if (k->second.m_value_semantic) |
245 | k->second.m_value_semantic->notify(value_store: k->second.value()); |
246 | } |
247 | } |
248 | |
249 | }} |
250 | |