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)
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>
16 namespace boost
{ namespace program_options
{
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
,
26 // TODO: what if we have different definition
27 // for the same option name during different calls
29 assert(options
.description
);
30 const options_description
& desc
= *options
.description
;
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
;
36 std::set
<std::string
> new_final
;
38 // Declared once, to please Intel in VC++ mode;
41 // Declared here so can be used to provide context for exceptions
43 string original_token
;
48 // First, convert/store all given options
49 for (i
= 0; i
< options
.options
.size(); ++i
) {
51 option_name
= options
.options
[i
].string_key
;
52 original_token
= options
.options
[i
].original_tokens
.size() ?
53 options
.options
[i
].original_tokens
[0] :
55 // Skip positional options without name
56 if (option_name
.empty())
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
)
67 // If option has final value, skip this assignment
68 if (xm
.m_final
.count(option_name
))
71 string original_token
= options
.options
[i
].original_tokens
.size() ?
72 options
.options
[i
].original_tokens
[0] : "";
73 const option_description
& d
= desc
.find(option_name
, false,
76 variable_value
& v
= m
[option_name
];
78 // Explicit assignment here erases defaulted value
82 d
.semantic()->parse(v
.value(), options
.options
[i
].value
, utf8
);
84 v
.m_value_semantic
= d
.semantic();
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
91 if (!d
.semantic()->is_composing())
92 new_final
.insert(option_name
);
95 #ifndef BOOST_NO_EXCEPTIONS
96 catch(error_with_option_name
& e
)
98 // add context and rethrow
99 e
.add_context(option_name
, original_token
, options
.m_options_prefix
);
103 xm
.m_final
.insert(new_final
.begin(), new_final
.end());
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
)
111 const option_description
& d
= *all
[i
];
112 string key
= d
.key("");
113 // FIXME: this logic relies on knowledge of option_description
115 // The 'key' is empty if options description contains '*'.
117 // case, default value makes no sense at all.
122 if (m
.count(key
) == 0) {
125 if (d
.semantic()->apply_default(def
)) {
126 m
[key
] = variable_value(def
, true);
127 m
[key
].m_value_semantic
= d
.semantic();
131 // add empty value if this is an required option
132 if (d
.semantic()->is_required()) {
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(options
.m_options_prefix
);
139 if (canonical_name
.length() > xm
.m_required
[key
].length())
140 xm
.m_required
[key
] = canonical_name
;
145 BOOST_PROGRAM_OPTIONS_DECL
146 void store(const wparsed_options
& options
, variables_map
& m
)
148 store(options
.utf8_encoded_options
, m
, true);
151 BOOST_PROGRAM_OPTIONS_DECL
152 void notify(variables_map
& vm
)
157 abstract_variables_map::abstract_variables_map()
161 abstract_variables_map::
162 abstract_variables_map(const abstract_variables_map
* next
)
166 const variable_value
&
167 abstract_variables_map::operator[](const std::string
& name
) const
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())
183 abstract_variables_map::next(abstract_variables_map
* next
)
188 variables_map::variables_map()
191 variables_map::variables_map(const abstract_variables_map
* next
)
192 : abstract_variables_map(next
)
195 void variables_map::clear()
197 std::map
<std::string
, variable_value
>::clear();
202 const variable_value
&
203 variables_map::get(const std::string
& name
) const
205 static variable_value empty
;
206 const_iterator i
= this->find(name
);
207 if (i
== this->end())
214 variables_map::notify()
216 // This checks if all required options occur
217 for (map
<string
, string
>::const_iterator r
= m_required
.begin();
218 r
!= m_required
.end();
221 const string
& opt
= r
->first
;
222 const string
& display_opt
= r
->second
;
223 map
<string
, variable_value
>::const_iterator iter
= find(opt
);
224 if (iter
== end() || iter
->second
.empty())
226 boost::throw_exception(required_option(display_opt
));
231 // Lastly, run notify actions.
232 for (map
<string
, variable_value
>::iterator k
= begin();
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
242 https://svn.boost.org/trac/boost/ticket/2782
244 if (k
->second
.m_value_semantic
)
245 k
->second
.m_value_semantic
->notify(k
->second
.value());