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