• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
store(const parsed_options & options,variables_map & xm,bool utf8)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
store(const wparsed_options & options,variables_map & m)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
notify(variables_map & vm)151     void notify(variables_map& vm)
152     {
153         vm.notify();
154     }
155 
abstract_variables_map()156     abstract_variables_map::abstract_variables_map()
157     : m_next(0)
158     {}
159 
160     abstract_variables_map::
abstract_variables_map(const abstract_variables_map * next)161     abstract_variables_map(const abstract_variables_map* next)
162     : m_next(next)
163     {}
164 
165     const variable_value&
operator [](const std::string & name) const166     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
next(abstract_variables_map * next)182     abstract_variables_map::next(abstract_variables_map* next)
183     {
184         m_next = next;
185     }
186 
variables_map()187     variables_map::variables_map()
188     {}
189 
variables_map(const abstract_variables_map * next)190     variables_map::variables_map(const abstract_variables_map* next)
191     : abstract_variables_map(next)
192     {}
193 
clear()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&
get(const std::string & name) const202     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
notify()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