~ubuntu-branches/debian/sid/boost1.49/sid

« back to all changes in this revision

Viewing changes to libs/program_options/src/variables_map.cpp

  • Committer: Package Import Robot
  • Author(s): Steve M. Robbins
  • Date: 2012-02-26 00:31:44 UTC
  • Revision ID: package-import@ubuntu.com-20120226003144-eaytp12cbf6ubpms
Tags: upstream-1.49.0
ImportĀ upstreamĀ versionĀ 1.49.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
            const option_description& d = desc.find(name, false, 
 
62
                                                      false, false);
 
63
 
 
64
            variable_value& v = m[name];            
 
65
            if (v.defaulted()) {
 
66
                // Explicit assignment here erases defaulted value
 
67
                v = variable_value();
 
68
            }
 
69
            
 
70
            try {
 
71
                d.semantic()->parse(v.value(), options.options[i].value, utf8);
 
72
            }
 
73
#ifndef BOOST_NO_EXCEPTIONS
 
74
            catch(validation_error& e)
 
75
            {
 
76
                e.set_option_name(name);
 
77
                throw;
 
78
            }
 
79
            catch(multiple_occurrences& e)
 
80
            {
 
81
                e.set_option_name(name);
 
82
                throw;
 
83
            }
 
84
            catch(multiple_values& e) 
 
85
            {
 
86
                e.set_option_name(name);
 
87
                throw;
 
88
            }
 
89
#endif
 
90
            v.m_value_semantic = d.semantic();
 
91
            
 
92
            // The option is not composing, and the value is explicitly
 
93
            // provided. Ignore values of this option for subsequent
 
94
            // calls to 'store'. We store this to a temporary set,
 
95
            // so that several assignment inside *this* 'store' call
 
96
            // are allowed.
 
97
            if (!d.semantic()->is_composing())
 
98
                new_final.insert(name);
 
99
        }
 
100
        xm.m_final.insert(new_final.begin(), new_final.end());
 
101
 
 
102
        
 
103
        
 
104
        // Second, apply default values and store required options.
 
105
        const vector<shared_ptr<option_description> >& all = desc.options();
 
106
        for(i = 0; i < all.size(); ++i)
 
107
        {
 
108
            const option_description& d = *all[i];
 
109
            string key = d.key("");
 
110
            // FIXME: this logic relies on knowledge of option_description
 
111
            // internals.
 
112
            // The 'key' is empty if options description contains '*'. 
 
113
            // In that 
 
114
            // case, default value makes no sense at all.
 
115
            if (key.empty())
 
116
            {
 
117
                continue;
 
118
            }
 
119
            if (m.count(key) == 0) {
 
120
            
 
121
                boost::any def;
 
122
                if (d.semantic()->apply_default(def)) {
 
123
                    m[key] = variable_value(def, true);
 
124
                    m[key].m_value_semantic = d.semantic();
 
125
                }
 
126
            }  
 
127
 
 
128
            // add empty value if this is an required option
 
129
            if (d.semantic()->is_required()) {
 
130
               xm.m_required.insert(key);
 
131
            }
 
132
        }
 
133
    }
 
134
 
 
135
    BOOST_PROGRAM_OPTIONS_DECL 
 
136
    void store(const wparsed_options& options, variables_map& m)
 
137
    {
 
138
        store(options.utf8_encoded_options, m, true);
 
139
    }
 
140
 
 
141
    BOOST_PROGRAM_OPTIONS_DECL 
 
142
    void notify(variables_map& vm)
 
143
    {        
 
144
        vm.notify();               
 
145
    }
 
146
 
 
147
    abstract_variables_map::abstract_variables_map()
 
148
    : m_next(0)
 
149
    {}
 
150
 
 
151
    abstract_variables_map::
 
152
    abstract_variables_map(const abstract_variables_map* next)
 
153
    : m_next(next)
 
154
    {}
 
155
 
 
156
    const variable_value& 
 
157
    abstract_variables_map::operator[](const std::string& name) const
 
158
    {
 
159
        const variable_value& v = get(name);
 
160
        if (v.empty() && m_next)
 
161
            return (*m_next)[name];
 
162
        else if (v.defaulted() && m_next) {
 
163
            const variable_value& v2 = (*m_next)[name];
 
164
            if (!v2.empty() && !v2.defaulted())
 
165
                return v2;
 
166
            else return v;
 
167
        } else {
 
168
            return v;
 
169
        }
 
170
    }
 
171
 
 
172
    void 
 
173
    abstract_variables_map::next(abstract_variables_map* next)
 
174
    {
 
175
        m_next = next;
 
176
    }
 
177
 
 
178
    variables_map::variables_map()
 
179
    {}
 
180
 
 
181
    variables_map::variables_map(const abstract_variables_map* next)
 
182
    : abstract_variables_map(next)
 
183
    {}
 
184
 
 
185
    const variable_value&
 
186
    variables_map::get(const std::string& name) const
 
187
    {
 
188
        static variable_value empty;
 
189
        const_iterator i = this->find(name);
 
190
        if (i == this->end())
 
191
            return empty;
 
192
        else
 
193
            return i->second;
 
194
    }
 
195
    
 
196
    void
 
197
    variables_map::notify()
 
198
    {
 
199
        // This checks if all required options occur
 
200
        for (set<string>::const_iterator r = m_required.begin();
 
201
             r != m_required.end();
 
202
             ++r)
 
203
        {
 
204
            const string& opt = *r;
 
205
            map<string, variable_value>::const_iterator iter = find(opt);
 
206
            if (iter == end() || iter->second.empty()) 
 
207
            {
 
208
                boost::throw_exception(required_option(opt));
 
209
            
 
210
            }
 
211
        }
 
212
 
 
213
        // Lastly, run notify actions.
 
214
        for (map<string, variable_value>::iterator k = begin(); 
 
215
             k != end(); 
 
216
             ++k) 
 
217
        {
 
218
            /* Users might wish to use variables_map to store their own values
 
219
               that are not parsed, and therefore will not have value_semantics
 
220
               defined. Do no crash on such values. In multi-module programs,
 
221
               one module might add custom values, and the 'notify' function
 
222
               will be called after that, so we check that value_sematics is 
 
223
               not NULL. See:
 
224
                   https://svn.boost.org/trac/boost/ticket/2782
 
225
            */
 
226
            if (k->second.m_value_semantic)
 
227
                k->second.m_value_semantic->notify(k->second.value());
 
228
        }               
 
229
    }
 
230
    
 
231
}}