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 | #ifndef BOOST_ERRORS_VP_2003_01_02 |
8 | #define BOOST_ERRORS_VP_2003_01_02 |
9 | |
10 | #include <boost/program_options/config.hpp> |
11 | |
12 | #include <string> |
13 | #include <stdexcept> |
14 | #include <vector> |
15 | #include <map> |
16 | |
17 | |
18 | #if defined(BOOST_MSVC) |
19 | # pragma warning (push) |
20 | # pragma warning (disable:4275) // non dll-interface class 'std::logic_error' used as base for dll-interface class 'boost::program_options::error' |
21 | # pragma warning (disable:4251) // class 'std::vector<_Ty>' needs to have dll-interface to be used by clients of class 'boost::program_options::ambiguous_option' |
22 | #endif |
23 | |
24 | namespace boost { namespace program_options { |
25 | |
26 | inline std::string strip_prefixes(const std::string& text) |
27 | { |
28 | // "--foo-bar" -> "foo-bar" |
29 | std::string::size_type i = text.find_first_not_of("-/" ); |
30 | if (i == std::string::npos) { |
31 | return text; |
32 | } else { |
33 | return text.substr(i); |
34 | } |
35 | } |
36 | |
37 | /** Base class for all errors in the library. */ |
38 | class BOOST_PROGRAM_OPTIONS_DECL error : public std::logic_error { |
39 | public: |
40 | error(const std::string& xwhat) : std::logic_error(xwhat) {} |
41 | }; |
42 | |
43 | |
44 | /** Class thrown when there are too many positional options. |
45 | This is a programming error. |
46 | */ |
47 | class BOOST_PROGRAM_OPTIONS_DECL too_many_positional_options_error : public error { |
48 | public: |
49 | too_many_positional_options_error() |
50 | : error("too many positional options have been specified on the command line" ) |
51 | {} |
52 | }; |
53 | |
54 | /** Class thrown when there are programming error related to style */ |
55 | class BOOST_PROGRAM_OPTIONS_DECL invalid_command_line_style : public error { |
56 | public: |
57 | invalid_command_line_style(const std::string& msg) |
58 | : error(msg) |
59 | {} |
60 | }; |
61 | |
62 | /** Class thrown if config file can not be read */ |
63 | class BOOST_PROGRAM_OPTIONS_DECL reading_file : public error { |
64 | public: |
65 | reading_file(const char* filename) |
66 | : error(std::string("can not read options configuration file '" ).append(filename).append("'" )) |
67 | {} |
68 | }; |
69 | |
70 | |
71 | /** Base class for most exceptions in the library. |
72 | * |
73 | * Substitutes the values for the parameter name |
74 | * placeholders in the template to create the human |
75 | * readable error message |
76 | * |
77 | * Placeholders are surrounded by % signs: %example% |
78 | * Poor man's version of boost::format |
79 | * |
80 | * If a parameter name is absent, perform default substitutions |
81 | * instead so ugly placeholders are never left in-place. |
82 | * |
83 | * Options are displayed in "canonical" form |
84 | * This is the most unambiguous form of the |
85 | * *parsed* option name and would correspond to |
86 | * option_description::format_name() |
87 | * i.e. what is shown by print_usage() |
88 | * |
89 | * The "canonical" form depends on whether the option is |
90 | * specified in short or long form, using dashes or slashes |
91 | * or without a prefix (from a configuration file) |
92 | * |
93 | * */ |
94 | class BOOST_PROGRAM_OPTIONS_DECL error_with_option_name : public error { |
95 | |
96 | protected: |
97 | /** can be |
98 | * 0 = no prefix (config file options) |
99 | * allow_long |
100 | * allow_dash_for_short |
101 | * allow_slash_for_short |
102 | * allow_long_disguise */ |
103 | int m_option_style; |
104 | |
105 | |
106 | /** substitutions |
107 | * from placeholders to values */ |
108 | std::map<std::string, std::string> m_substitutions; |
109 | typedef std::pair<std::string, std::string> string_pair; |
110 | std::map<std::string, string_pair > m_substitution_defaults; |
111 | |
112 | public: |
113 | /** template with placeholders */ |
114 | std::string m_error_template; |
115 | |
116 | error_with_option_name(const std::string& template_, |
117 | const std::string& option_name = "" , |
118 | const std::string& original_token = "" , |
119 | int option_style = 0); |
120 | |
121 | /** gcc says that throw specification on dtor is loosened |
122 | * without this line |
123 | * */ |
124 | ~error_with_option_name() throw() {} |
125 | |
126 | |
127 | //void dump() const |
128 | //{ |
129 | // std::cerr << "m_substitution_defaults:\n"; |
130 | // for (std::map<std::string, string_pair>::const_iterator iter = m_substitution_defaults.begin(); |
131 | // iter != m_substitution_defaults.end(); ++iter) |
132 | // std::cerr << "\t" << iter->first << ":" << iter->second.first << "=" << iter->second.second << "\n"; |
133 | // std::cerr << "m_substitutions:\n"; |
134 | // for (std::map<std::string, std::string>::const_iterator iter = m_substitutions.begin(); |
135 | // iter != m_substitutions.end(); ++iter) |
136 | // std::cerr << "\t" << iter->first << "=" << iter->second << "\n"; |
137 | // std::cerr << "m_error_template:\n"; |
138 | // std::cerr << "\t" << m_error_template << "\n"; |
139 | // std::cerr << "canonical_option_prefix:[" << get_canonical_option_prefix() << "]\n"; |
140 | // std::cerr << "canonical_option_name:[" << get_canonical_option_name() <<"]\n"; |
141 | // std::cerr << "what:[" << what() << "]\n"; |
142 | //} |
143 | |
144 | /** Substitute |
145 | * parameter_name->value to create the error message from |
146 | * the error template */ |
147 | void set_substitute(const std::string& parameter_name, const std::string& value) |
148 | { m_substitutions[parameter_name] = value; } |
149 | |
150 | /** If the parameter is missing, then make the |
151 | * from->to substitution instead */ |
152 | void set_substitute_default(const std::string& parameter_name, |
153 | const std::string& from, |
154 | const std::string& to) |
155 | { |
156 | m_substitution_defaults[parameter_name] = std::make_pair(from, to); |
157 | } |
158 | |
159 | |
160 | /** Add context to an exception */ |
161 | void add_context(const std::string& option_name, |
162 | const std::string& original_token, |
163 | int option_style) |
164 | { |
165 | set_option_name(option_name); |
166 | set_original_token(original_token); |
167 | set_prefix(option_style); |
168 | } |
169 | |
170 | void set_prefix(int option_style) |
171 | { m_option_style = option_style;} |
172 | |
173 | /** Overridden in error_with_no_option_name */ |
174 | virtual void set_option_name(const std::string& option_name) |
175 | { set_substitute("option" , option_name);} |
176 | |
177 | std::string get_option_name() const |
178 | { return get_canonical_option_name(); } |
179 | |
180 | void set_original_token(const std::string& original_token) |
181 | { set_substitute("original_token" , original_token);} |
182 | |
183 | |
184 | /** Creates the error_message on the fly |
185 | * Currently a thin wrapper for substitute_placeholders() */ |
186 | virtual const char* what() const throw(); |
187 | |
188 | protected: |
189 | /** Used to hold the error text returned by what() */ |
190 | mutable std::string m_message; // For on-demand formatting in 'what' |
191 | |
192 | /** Makes all substitutions using the template */ |
193 | virtual void substitute_placeholders(const std::string& error_template) const; |
194 | |
195 | // helper function for substitute_placeholders |
196 | void replace_token(const std::string& from, const std::string& to) const; |
197 | |
198 | /** Construct option name in accordance with the appropriate |
199 | * prefix style: i.e. long dash or short slash etc */ |
200 | std::string get_canonical_option_name() const; |
201 | std::string get_canonical_option_prefix() const; |
202 | }; |
203 | |
204 | |
205 | /** Class thrown when there are several option values, but |
206 | user called a method which cannot return them all. */ |
207 | class BOOST_PROGRAM_OPTIONS_DECL multiple_values : public error_with_option_name { |
208 | public: |
209 | multiple_values() |
210 | : error_with_option_name("option '%canonical_option%' only takes a single argument" ){} |
211 | |
212 | ~multiple_values() throw() {} |
213 | }; |
214 | |
215 | /** Class thrown when there are several occurrences of an |
216 | option, but user called a method which cannot return |
217 | them all. */ |
218 | class BOOST_PROGRAM_OPTIONS_DECL multiple_occurrences : public error_with_option_name { |
219 | public: |
220 | multiple_occurrences() |
221 | : error_with_option_name("option '%canonical_option%' cannot be specified more than once" ){} |
222 | |
223 | ~multiple_occurrences() throw() {} |
224 | |
225 | }; |
226 | |
227 | /** Class thrown when a required/mandatory option is missing */ |
228 | class BOOST_PROGRAM_OPTIONS_DECL required_option : public error_with_option_name { |
229 | public: |
230 | // option name is constructed by the option_descriptor and never on the fly |
231 | required_option(const std::string& option_name) |
232 | : error_with_option_name("the option '%canonical_option%' is required but missing" , "" , option_name) |
233 | { |
234 | } |
235 | |
236 | ~required_option() throw() {} |
237 | }; |
238 | |
239 | /** Base class of unparsable options, |
240 | * when the desired option cannot be identified. |
241 | * |
242 | * |
243 | * It makes no sense to have an option name, when we can't match an option to the |
244 | * parameter |
245 | * |
246 | * Having this a part of the error_with_option_name hierachy makes error handling |
247 | * a lot easier, even if the name indicates some sort of conceptual dissonance! |
248 | * |
249 | * */ |
250 | class BOOST_PROGRAM_OPTIONS_DECL error_with_no_option_name : public error_with_option_name { |
251 | public: |
252 | error_with_no_option_name(const std::string& template_, |
253 | const std::string& original_token = "" ) |
254 | : error_with_option_name(template_, "" , original_token) |
255 | { |
256 | } |
257 | |
258 | /** Does NOT set option name, because no option name makes sense */ |
259 | virtual void set_option_name(const std::string&) {} |
260 | |
261 | ~error_with_no_option_name() throw() {} |
262 | }; |
263 | |
264 | |
265 | /** Class thrown when option name is not recognized. */ |
266 | class BOOST_PROGRAM_OPTIONS_DECL unknown_option : public error_with_no_option_name { |
267 | public: |
268 | unknown_option(const std::string& original_token = "" ) |
269 | : error_with_no_option_name("unrecognised option '%canonical_option%'" , original_token) |
270 | { |
271 | } |
272 | |
273 | ~unknown_option() throw() {} |
274 | }; |
275 | |
276 | |
277 | |
278 | /** Class thrown when there's ambiguity amoung several possible options. */ |
279 | class BOOST_PROGRAM_OPTIONS_DECL ambiguous_option : public error_with_no_option_name { |
280 | public: |
281 | ambiguous_option(const std::vector<std::string>& xalternatives) |
282 | : error_with_no_option_name("option '%canonical_option%' is ambiguous" ), |
283 | m_alternatives(xalternatives) |
284 | {} |
285 | |
286 | ~ambiguous_option() throw() {} |
287 | |
288 | const std::vector<std::string>& alternatives() const throw() {return m_alternatives;} |
289 | |
290 | protected: |
291 | /** Makes all substitutions using the template */ |
292 | virtual void substitute_placeholders(const std::string& error_template) const; |
293 | private: |
294 | // TODO: copy ctor might throw |
295 | std::vector<std::string> m_alternatives; |
296 | }; |
297 | |
298 | |
299 | /** Class thrown when there's syntax error either for command |
300 | * line or config file options. See derived children for |
301 | * concrete classes. */ |
302 | class BOOST_PROGRAM_OPTIONS_DECL invalid_syntax : public error_with_option_name { |
303 | public: |
304 | enum kind_t { |
305 | long_not_allowed = 30, |
306 | long_adjacent_not_allowed, |
307 | short_adjacent_not_allowed, |
308 | empty_adjacent_parameter, |
309 | missing_parameter, |
310 | , |
311 | unrecognized_line |
312 | }; |
313 | |
314 | invalid_syntax(kind_t kind, |
315 | const std::string& option_name = "" , |
316 | const std::string& original_token = "" , |
317 | int option_style = 0): |
318 | error_with_option_name(get_template(kind), option_name, original_token, option_style), |
319 | m_kind(kind) |
320 | { |
321 | } |
322 | |
323 | ~invalid_syntax() throw() {} |
324 | |
325 | kind_t kind() const {return m_kind;} |
326 | |
327 | /** Convenience functions for backwards compatibility */ |
328 | virtual std::string tokens() const {return get_option_name(); } |
329 | protected: |
330 | /** Used to convert kind_t to a related error text */ |
331 | std::string get_template(kind_t kind); |
332 | kind_t m_kind; |
333 | }; |
334 | |
335 | class BOOST_PROGRAM_OPTIONS_DECL invalid_config_file_syntax : public invalid_syntax { |
336 | public: |
337 | invalid_config_file_syntax(const std::string& invalid_line, kind_t kind): |
338 | invalid_syntax(kind) |
339 | { |
340 | m_substitutions["invalid_line" ] = invalid_line; |
341 | } |
342 | |
343 | ~invalid_config_file_syntax() throw() {} |
344 | |
345 | /** Convenience functions for backwards compatibility */ |
346 | virtual std::string tokens() const {return m_substitutions.find("invalid_line" )->second; } |
347 | }; |
348 | |
349 | |
350 | /** Class thrown when there are syntax errors in given command line */ |
351 | class BOOST_PROGRAM_OPTIONS_DECL invalid_command_line_syntax : public invalid_syntax { |
352 | public: |
353 | invalid_command_line_syntax(kind_t kind, |
354 | const std::string& option_name = "" , |
355 | const std::string& original_token = "" , |
356 | int option_style = 0): |
357 | invalid_syntax(kind, option_name, original_token, option_style) {} |
358 | ~invalid_command_line_syntax() throw() {} |
359 | }; |
360 | |
361 | |
362 | /** Class thrown when value of option is incorrect. */ |
363 | class BOOST_PROGRAM_OPTIONS_DECL validation_error : public error_with_option_name { |
364 | public: |
365 | enum kind_t { |
366 | multiple_values_not_allowed = 30, |
367 | at_least_one_value_required, |
368 | invalid_bool_value, |
369 | invalid_option_value, |
370 | invalid_option |
371 | }; |
372 | |
373 | public: |
374 | validation_error(kind_t kind, |
375 | const std::string& option_name = "" , |
376 | const std::string& original_token = "" , |
377 | int option_style = 0): |
378 | error_with_option_name(get_template(kind), option_name, original_token, option_style) |
379 | { |
380 | } |
381 | |
382 | ~validation_error() throw() {} |
383 | |
384 | protected: |
385 | /** Used to convert kind_t to a related error text */ |
386 | std::string get_template(kind_t kind); |
387 | kind_t m_kind; |
388 | }; |
389 | |
390 | /** Class thrown if there is an invalid option value given */ |
391 | class BOOST_PROGRAM_OPTIONS_DECL invalid_option_value |
392 | : public validation_error |
393 | { |
394 | public: |
395 | invalid_option_value(const std::string& value); |
396 | #ifndef BOOST_NO_STD_WSTRING |
397 | invalid_option_value(const std::wstring& value); |
398 | #endif |
399 | }; |
400 | |
401 | /** Class thrown if there is an invalid bool value given */ |
402 | class BOOST_PROGRAM_OPTIONS_DECL invalid_bool_value |
403 | : public validation_error |
404 | { |
405 | public: |
406 | invalid_bool_value(const std::string& value); |
407 | }; |
408 | |
409 | |
410 | |
411 | |
412 | |
413 | |
414 | |
415 | }} |
416 | |
417 | #if defined(BOOST_MSVC) |
418 | # pragma warning (pop) |
419 | #endif |
420 | |
421 | #endif |
422 | |