]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
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" | |
b32b8144 FG |
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 | } | |
7c673cae FG |
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 | ||
b32b8144 | 177 | std::string get_option_name() const |
7c673cae FG |
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 | extra_parameter, | |
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): | |
92f5a8d4 TL |
378 | error_with_option_name(get_template(kind), option_name, original_token, option_style), |
379 | m_kind(kind) | |
7c673cae FG |
380 | { |
381 | } | |
382 | ||
383 | ~validation_error() throw() {} | |
384 | ||
92f5a8d4 TL |
385 | kind_t kind() const { return m_kind; } |
386 | ||
7c673cae FG |
387 | protected: |
388 | /** Used to convert kind_t to a related error text */ | |
389 | std::string get_template(kind_t kind); | |
390 | kind_t m_kind; | |
391 | }; | |
392 | ||
393 | /** Class thrown if there is an invalid option value given */ | |
394 | class BOOST_PROGRAM_OPTIONS_DECL invalid_option_value | |
395 | : public validation_error | |
396 | { | |
397 | public: | |
398 | invalid_option_value(const std::string& value); | |
399 | #ifndef BOOST_NO_STD_WSTRING | |
400 | invalid_option_value(const std::wstring& value); | |
401 | #endif | |
402 | }; | |
403 | ||
404 | /** Class thrown if there is an invalid bool value given */ | |
405 | class BOOST_PROGRAM_OPTIONS_DECL invalid_bool_value | |
406 | : public validation_error | |
407 | { | |
408 | public: | |
409 | invalid_bool_value(const std::string& value); | |
410 | }; | |
411 | ||
412 | ||
413 | ||
414 | ||
415 | ||
416 | ||
417 | ||
418 | }} | |
419 | ||
420 | #if defined(BOOST_MSVC) | |
421 | # pragma warning (pop) | |
422 | #endif | |
423 | ||
424 | #endif |