summaryrefslogtreecommitdiffstats
blob: caf354eb61897729bd6e2bd1b4cef59d362d372f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
// Copyright Vladimir Prus 2002-2004.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt
// or copy at http://www.boost.org/LICENSE_1_0.txt)


#define BOOST_PROGRAM_OPTIONS_SOURCE
#include <boost/program_options/config.hpp>
#include <boost/program_options/parsers.hpp>
#include <boost/program_options/options_description.hpp>
#include <boost/program_options/value_semantic.hpp>
#include <boost/program_options/variables_map.hpp>

#include <cassert>

namespace boost { namespace program_options {

    using namespace std;

    // First, performs semantic actions for 'oa'. 
    // Then, stores in 'm' all options that are defined in 'desc'. 
    BOOST_PROGRAM_OPTIONS_DECL 
    void store(const parsed_options& options, variables_map& xm,
               bool utf8)
    {       
        // TODO: what if we have different definition
        // for the same option name during different calls
        // 'store'.
        assert(options.description);
        const options_description& desc = *options.description;

        // We need to access map's operator[], not the overriden version
        // variables_map. Ehmm.. messy.
        std::map<std::string, variable_value>& m = xm;

        std::set<std::string> new_final;

        // Declared once, to please Intel in VC++ mode;
        unsigned i;

        // Declared here so can be used to provide context for exceptions
        string option_name;
        string original_token;

        try
        {

            // First, convert/store all given options
            for (i = 0; i < options.options.size(); ++i) {

                option_name = options.options[i].string_key;
                original_token = options.options[i].original_tokens.size() ? 
                                options.options[i].original_tokens[0] :
                                option_name;
                // Skip positional options without name
                if (option_name.empty())
                    continue;

                // Ignore unregistered option. The 'unregistered'
                // field can be true only if user has explicitly asked
                // to allow unregistered options. We can't store them
                // to variables map (lacking any information about paring), 
                // so just ignore them.
                if (options.options[i].unregistered)
                    continue;

                // If option has final value, skip this assignment
                if (xm.m_final.count(option_name))
                    continue;

                string original_token = options.options[i].original_tokens.size() ? 
                                        options.options[i].original_tokens[0]     : "";
                const option_description& d = desc.find(option_name, false, 
                                                        false, false);

                variable_value& v = m[option_name];            
                if (v.defaulted()) {
                    // Explicit assignment here erases defaulted value
                    v = variable_value();
                }
                
                d.semantic()->parse(v.value(), options.options[i].value, utf8);

                v.m_value_semantic = d.semantic();
                
                // The option is not composing, and the value is explicitly
                // provided. Ignore values of this option for subsequent
                // calls to 'store'. We store this to a temporary set,
                // so that several assignment inside *this* 'store' call
                // are allowed.
                if (!d.semantic()->is_composing())
                    new_final.insert(option_name);
            }
        } 
#ifndef BOOST_NO_EXCEPTIONS
        catch(error_with_option_name& e)
        {
            // add context and rethrow
            e.add_context(option_name, original_token, options.m_options_prefix);
            throw;
        }
#endif
        xm.m_final.insert(new_final.begin(), new_final.end());

        
        
        // Second, apply default values and store required options.
        const vector<shared_ptr<option_description> >& all = desc.options();
        for(i = 0; i < all.size(); ++i)
        {
            const option_description& d = *all[i];
            string key = d.key("");
            // FIXME: this logic relies on knowledge of option_description
            // internals.
            // The 'key' is empty if options description contains '*'. 
            // In that 
            // case, default value makes no sense at all.
            if (key.empty())
            {
                continue;
            }
            if (m.count(key) == 0) {
            
                boost::any def;
                if (d.semantic()->apply_default(def)) {
                    m[key] = variable_value(def, true);
                    m[key].m_value_semantic = d.semantic();
                }
            }  

            // add empty value if this is an required option
            if (d.semantic()->is_required()) {

                // For option names specified in multiple ways, e.g. on the command line,
                // config file etc, the following precedence rules apply:
                //  "--"  >  ("-" or "/")  >  ""
                //  Precedence is set conveniently by a single call to length()
                string canonical_name = d.canonical_display_name(options.m_options_prefix);
                if (canonical_name.length() > xm.m_required[key].length())
                    xm.m_required[key] = canonical_name;
            }
        }
    }

    BOOST_PROGRAM_OPTIONS_DECL 
    void store(const wparsed_options& options, variables_map& m)
    {
        store(options.utf8_encoded_options, m, true);
    }

    BOOST_PROGRAM_OPTIONS_DECL 
    void notify(variables_map& vm)
    {        
        vm.notify();               
    }

    abstract_variables_map::abstract_variables_map()
    : m_next(0)
    {}

    abstract_variables_map::
    abstract_variables_map(const abstract_variables_map* next)
    : m_next(next)
    {}

    const variable_value& 
    abstract_variables_map::operator[](const std::string& name) const
    {
        const variable_value& v = get(name);
        if (v.empty() && m_next)
            return (*m_next)[name];
        else if (v.defaulted() && m_next) {
            const variable_value& v2 = (*m_next)[name];
            if (!v2.empty() && !v2.defaulted())
                return v2;
            else return v;
        } else {
            return v;
        }
    }

    void 
    abstract_variables_map::next(abstract_variables_map* next)
    {
        m_next = next;
    }

    variables_map::variables_map()
    {}

    variables_map::variables_map(const abstract_variables_map* next)
    : abstract_variables_map(next)
    {}

    void variables_map::clear()
    {
        std::map<std::string, variable_value>::clear();
        m_final.clear();
        m_required.clear();
    }

    const variable_value&
    variables_map::get(const std::string& name) const
    {
        static variable_value empty;
        const_iterator i = this->find(name);
        if (i == this->end())
            return empty;
        else
            return i->second;
    }
    
    void
    variables_map::notify()
    {
        // This checks if all required options occur
        for (map<string, string>::const_iterator r = m_required.begin();
             r != m_required.end();
             ++r)
        {
            const string& opt = r->first;
            const string& display_opt = r->second;
            map<string, variable_value>::const_iterator iter = find(opt);
            if (iter == end() || iter->second.empty()) 
            {
                boost::throw_exception(required_option(display_opt));
            
            }
        }

        // Lastly, run notify actions.
        for (map<string, variable_value>::iterator k = begin(); 
             k != end(); 
             ++k) 
        {
            /* Users might wish to use variables_map to store their own values
               that are not parsed, and therefore will not have value_semantics
               defined. Do no crash on such values. In multi-module programs,
               one module might add custom values, and the 'notify' function
               will be called after that, so we check that value_sematics is 
               not NULL. See:
                   https://svn.boost.org/trac/boost/ticket/2782
            */
            if (k->second.m_value_semantic)
                k->second.m_value_semantic->notify(k->second.value());
        }               
    }
    
}}