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 | // First, convert/store all given options |
---|
42 | for (i = 0; i < options.options.size(); ++i) { |
---|
43 | |
---|
44 | const string& name = options.options[i].string_key; |
---|
45 | // Skip positional options without name |
---|
46 | if (name.empty()) |
---|
47 | continue; |
---|
48 | |
---|
49 | // Ignore unregistered option. The 'unregistered' |
---|
50 | // field can be true only if user has explicitly asked |
---|
51 | // to allow unregistered options. We can't store them |
---|
52 | // to variables map (lacking any information about paring), |
---|
53 | // so just ignore them. |
---|
54 | if (options.options[i].unregistered) |
---|
55 | continue; |
---|
56 | |
---|
57 | // If option has final value, skip this assignment |
---|
58 | if (xm.m_final.count(name)) |
---|
59 | continue; |
---|
60 | |
---|
61 | // Ignore options which are not described |
---|
62 | //TODO: consider this. |
---|
63 | //if (desc.count(name) == 0) |
---|
64 | // continue; |
---|
65 | |
---|
66 | const option_description& d = desc.find(name, false); |
---|
67 | |
---|
68 | variable_value& v = m[name]; |
---|
69 | if (v.defaulted()) { |
---|
70 | // Explicit assignment here erases defaulted value |
---|
71 | v = variable_value(); |
---|
72 | } |
---|
73 | |
---|
74 | try { |
---|
75 | d.semantic()->parse(v.value(), options.options[i].value, utf8); |
---|
76 | } |
---|
77 | catch(validation_error& e) |
---|
78 | { |
---|
79 | e.set_option_name(name); |
---|
80 | throw; |
---|
81 | } |
---|
82 | v.m_value_semantic = d.semantic(); |
---|
83 | |
---|
84 | // The option is not composing, and the value is explicitly |
---|
85 | // provided. Ignore values of this option for subsequent |
---|
86 | // calls to 'store'. We store this to a temporary set, |
---|
87 | // so that several assignment inside *this* 'store' call |
---|
88 | // are allowed. |
---|
89 | if (!d.semantic()->is_composing()) |
---|
90 | new_final.insert(name); |
---|
91 | } |
---|
92 | xm.m_final.insert(new_final.begin(), new_final.end()); |
---|
93 | |
---|
94 | |
---|
95 | |
---|
96 | // Second, apply default values. |
---|
97 | const vector<shared_ptr<option_description> >& all = desc.options(); |
---|
98 | for(i = 0; i < all.size(); ++i) |
---|
99 | { |
---|
100 | const option_description& d = *all[i]; |
---|
101 | string key = d.key(""); |
---|
102 | // FIXME: this logic relies on knowledge of option_description |
---|
103 | // internals. |
---|
104 | // The 'key' is empty if options description contains '*'. |
---|
105 | // In that |
---|
106 | // case, default value makes no sense at all. |
---|
107 | if (key.empty()) |
---|
108 | { |
---|
109 | continue; |
---|
110 | } |
---|
111 | if (m.count(key) == 0) { |
---|
112 | |
---|
113 | boost::any def; |
---|
114 | if (d.semantic()->apply_default(def)) { |
---|
115 | m[key] = variable_value(def, true); |
---|
116 | m[key].m_value_semantic = d.semantic(); |
---|
117 | } |
---|
118 | } |
---|
119 | } |
---|
120 | } |
---|
121 | |
---|
122 | BOOST_PROGRAM_OPTIONS_DECL |
---|
123 | void store(const wparsed_options& options, variables_map& m) |
---|
124 | { |
---|
125 | store(options.utf8_encoded_options, m, true); |
---|
126 | } |
---|
127 | |
---|
128 | BOOST_PROGRAM_OPTIONS_DECL |
---|
129 | void notify(variables_map& vm) |
---|
130 | { |
---|
131 | // Lastly, run notify actions. |
---|
132 | for (map<string, variable_value>::iterator k = vm.begin(); |
---|
133 | k != vm.end(); |
---|
134 | ++k) |
---|
135 | { |
---|
136 | k->second.m_value_semantic->notify(k->second.value()); |
---|
137 | } |
---|
138 | } |
---|
139 | |
---|
140 | abstract_variables_map::abstract_variables_map() |
---|
141 | : m_next(0) |
---|
142 | {} |
---|
143 | |
---|
144 | abstract_variables_map:: |
---|
145 | abstract_variables_map(const abstract_variables_map* next) |
---|
146 | : m_next(next) |
---|
147 | {} |
---|
148 | |
---|
149 | const variable_value& |
---|
150 | abstract_variables_map::operator[](const std::string& name) const |
---|
151 | { |
---|
152 | const variable_value& v = get(name); |
---|
153 | if (v.empty() && m_next) |
---|
154 | return (*m_next)[name]; |
---|
155 | else if (v.defaulted() && m_next) { |
---|
156 | const variable_value& v2 = (*m_next)[name]; |
---|
157 | if (!v2.empty() && !v2.defaulted()) |
---|
158 | return v2; |
---|
159 | else return v; |
---|
160 | } else { |
---|
161 | return v; |
---|
162 | } |
---|
163 | } |
---|
164 | |
---|
165 | void |
---|
166 | abstract_variables_map::next(abstract_variables_map* next) |
---|
167 | { |
---|
168 | m_next = next; |
---|
169 | } |
---|
170 | |
---|
171 | variables_map::variables_map() |
---|
172 | {} |
---|
173 | |
---|
174 | variables_map::variables_map(const abstract_variables_map* next) |
---|
175 | : abstract_variables_map(next) |
---|
176 | {} |
---|
177 | |
---|
178 | const variable_value& |
---|
179 | variables_map::get(const std::string& name) const |
---|
180 | { |
---|
181 | static variable_value empty; |
---|
182 | const_iterator i = this->find(name); |
---|
183 | if (i == this->end()) |
---|
184 | return empty; |
---|
185 | else |
---|
186 | return i->second; |
---|
187 | } |
---|
188 | }} |
---|