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
16namespace 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
45#ifndef BOOST_NO_EXCEPTIONS
46 try
47#endif
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;
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
70 original_token = options.options[i].original_tokens.size() ?
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}}
249