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