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