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