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
17namespace 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

source code of boost/libs/program_options/src/variables_map.cpp