summaryrefslogtreecommitdiffstats
blob: f31defbd3694de31a8b800a326522ba0489a9f59 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
// Copyright Vladimir Prus 2002-2004.
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt
// or copy at http://www.boost.org/LICENSE_1_0.txt)


#ifndef BOOST_ERRORS_VP_2003_01_02
#define BOOST_ERRORS_VP_2003_01_02

#include <boost/program_options/config.hpp>

#include <string>
#include <stdexcept>
#include <vector>
#include <map>


#if defined(BOOST_MSVC)
#   pragma warning (push)
#   pragma warning (disable:4275) // non dll-interface class 'std::logic_error' used as base for dll-interface class 'boost::program_options::error'
#   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'
#endif

namespace boost { namespace program_options {

    inline std::string strip_prefixes(const std::string& text)
    {
        // "--foo-bar" -> "foo-bar"
        return text.substr(text.find_first_not_of("-/"));
    }

    /** Base class for all errors in the library. */
    class BOOST_PROGRAM_OPTIONS_DECL error : public std::logic_error {
    public:
        error(const std::string& xwhat) : std::logic_error(xwhat) {}
    };


    /** Class thrown when there are too many positional options. 
        This is a programming error.
    */
    class BOOST_PROGRAM_OPTIONS_DECL too_many_positional_options_error : public error {
    public:
        too_many_positional_options_error() 
         : error("too many positional options have been specified on the command line") 
        {}
    };

    /** Class thrown when there are programming error related to style */
    class BOOST_PROGRAM_OPTIONS_DECL invalid_command_line_style : public error {
    public:
        invalid_command_line_style(const std::string& msg)
        : error(msg)
        {}
    };

    /** Class thrown if config file can not be read */
    class BOOST_PROGRAM_OPTIONS_DECL reading_file : public error {
    public:
        reading_file(const char* filename)
         : error(std::string("can not read options configuration file '").append(filename).append("'"))
        {}
    };


    /** Base class for most exceptions in the library.
     *  
     *  Substitutes the values for the parameter name
     *      placeholders in the template to create the human
     *      readable error message
     *  
     *  Placeholders are surrounded by % signs: %example%
     *      Poor man's version of boost::format
     *  
     *  If a parameter name is absent, perform default substitutions
     *      instead so ugly placeholders are never left in-place.
     *  
     *  Options are displayed in "canonical" form
     *      This is the most unambiguous form of the
     *      *parsed* option name and would correspond to
     *      option_description::format_name()
     *      i.e. what is shown by print_usage()
     *  
     *  The "canonical" form depends on whether the option is
     *      specified in short or long form, using dashes or slashes
     *      or without a prefix (from a configuration file)
     *  
     *   */
    class BOOST_PROGRAM_OPTIONS_DECL error_with_option_name : public error {

    protected:
        /** can be
         *      0 = no prefix (config file options)
         *      allow_long
         *      allow_dash_for_short
         *      allow_slash_for_short
         *      allow_long_disguise */
        int m_option_style;


        /** substitutions
         *  from placeholders to values */
        std::map<std::string, std::string> m_substitutions;
        typedef std::pair<std::string, std::string> string_pair;
        std::map<std::string, string_pair > m_substitution_defaults;

    public:
        /** template with placeholders */
        std::string m_error_template;

        error_with_option_name(const std::string& template_,
                               const std::string& option_name = "",
                               const std::string& original_token = "",
                               int option_style = 0);

        /** gcc says that throw specification on dtor is loosened 
         *  without this line                                     
         *  */ 
        ~error_with_option_name() throw() {}


        //void dump() const
        //{
        //  std::cerr << "m_substitution_defaults:\n";
        //  for (std::map<std::string, string_pair>::const_iterator iter = m_substitution_defaults.begin();
        //        iter != m_substitution_defaults.end(); ++iter)
        //      std::cerr << "\t" << iter->first << ":" << iter->second.first << "=" << iter->second.second << "\n";
        //  std::cerr << "m_substitutions:\n";
        //  for (std::map<std::string, std::string>::const_iterator iter = m_substitutions.begin();
        //        iter != m_substitutions.end(); ++iter)
        //      std::cerr << "\t" << iter->first << "=" << iter->second << "\n";
        //  std::cerr << "m_error_template:\n";
        //  std::cerr << "\t" << m_error_template << "\n";
        //  std::cerr << "canonical_option_prefix:[" << get_canonical_option_prefix() << "]\n";
        //  std::cerr << "canonical_option_name:[" << get_canonical_option_name() <<"]\n";
        //  std::cerr << "what:[" << what() << "]\n";
        //}

        /** Substitute
         *      parameter_name->value to create the error message from
         *      the error template */
        void set_substitute(const std::string& parameter_name,  const std::string& value)
        {           m_substitutions[parameter_name] = value;    }

        /** If the parameter is missing, then make the
         *      from->to substitution instead */
        void set_substitute_default(const std::string& parameter_name, 
                                    const std::string& from,  
                                    const std::string& to)
        {           
            m_substitution_defaults[parameter_name] = std::make_pair(from, to); 
        }


        /** Add context to an exception */
        void add_context(const std::string& option_name,
                         const std::string& original_token,
                         int option_style)
        {
            set_option_name(option_name);
            set_original_token(original_token);
            set_prefix(option_style);
        }

        void set_prefix(int option_style)
        {           m_option_style = option_style;}

        /** Overridden in error_with_no_option_name */
        virtual void set_option_name(const std::string& option_name)
        {           set_substitute("option", option_name);}

        std::string get_option_name() const throw()
        {           return get_canonical_option_name();         }

        void set_original_token(const std::string& original_token)
        {           set_substitute("original_token", original_token);}


        /** Creates the error_message on the fly
         *      Currently a thin wrapper for substitute_placeholders() */
        virtual const char* what() const throw();

    protected:
        /** Used to hold the error text returned by what() */
        mutable std::string m_message;  // For on-demand formatting in 'what'

        /** Makes all substitutions using the template */
        virtual void substitute_placeholders(const std::string& error_template) const;

        // helper function for substitute_placeholders
        void replace_token(const std::string& from, const std::string& to) const;

        /** Construct option name in accordance with the appropriate
         *  prefix style: i.e. long dash or short slash etc */
        std::string get_canonical_option_name() const;
        std::string get_canonical_option_prefix() const;
    };


    /** Class thrown when there are several option values, but
        user called a method which cannot return them all. */
    class BOOST_PROGRAM_OPTIONS_DECL multiple_values : public error_with_option_name {
    public:
        multiple_values() 
         : error_with_option_name("option '%canonical_option%' only takes a single argument"){}

        ~multiple_values() throw() {}
    };

    /** Class thrown when there are several occurrences of an
        option, but user called a method which cannot return 
        them all. */
    class BOOST_PROGRAM_OPTIONS_DECL multiple_occurrences : public error_with_option_name {
    public:
        multiple_occurrences() 
         : error_with_option_name("option '%canonical_option%' cannot be specified more than once"){}

        ~multiple_occurrences() throw() {}

    };

    /** Class thrown when a required/mandatory option is missing */
    class BOOST_PROGRAM_OPTIONS_DECL required_option : public error_with_option_name {
    public:
       // option name is constructed by the option_descriptor and never on the fly
       required_option(const std::string& option_name)
       : error_with_option_name("the option '%canonical_option%' is required but missing", "", option_name)
       {
       }

       ~required_option() throw() {}
    };

    /** Base class of unparsable options,
     *  when the desired option cannot be identified.
     *  
     *  
     *  It makes no sense to have an option name, when we can't match an option to the
     *      parameter
     *  
     *  Having this a part of the error_with_option_name hierachy makes error handling
     *      a lot easier, even if the name indicates some sort of conceptual dissonance!
     *  
     *   */
    class BOOST_PROGRAM_OPTIONS_DECL error_with_no_option_name : public error_with_option_name {
    public:
        error_with_no_option_name(const std::string& template_,
                              const std::string& original_token = "")
        : error_with_option_name(template_, "", original_token)
        {
        }

        /** Does NOT set option name, because no option name makes sense */
        virtual void set_option_name(const std::string&) {}

        ~error_with_no_option_name() throw() {}
    };


    /** Class thrown when option name is not recognized. */
    class BOOST_PROGRAM_OPTIONS_DECL unknown_option : public error_with_no_option_name {
    public:
        unknown_option(const std::string& original_token = "")
        : error_with_no_option_name("unrecognised option '%canonical_option%'", original_token)
        {
        }

        ~unknown_option() throw() {}
    };



    /** Class thrown when there's ambiguity amoung several possible options. */
    class BOOST_PROGRAM_OPTIONS_DECL ambiguous_option : public error_with_no_option_name {
    public:
        ambiguous_option(const std::vector<std::string>& xalternatives)
        : error_with_no_option_name("option '%canonical_option%' is ambiguous"),
            m_alternatives(xalternatives)
        {}

        ~ambiguous_option() throw() {}

        const std::vector<std::string>& alternatives() const throw() {return m_alternatives;}

    protected:
        /** Makes all substitutions using the template */
        virtual void substitute_placeholders(const std::string& error_template) const;
    private:
        // TODO: copy ctor might throw
        std::vector<std::string> m_alternatives;
    };


    /** Class thrown when there's syntax error either for command
     *  line or config file options. See derived children for
     *  concrete classes. */
    class BOOST_PROGRAM_OPTIONS_DECL invalid_syntax : public error_with_option_name {
    public:
        enum kind_t {
            long_not_allowed = 30,
            long_adjacent_not_allowed,
            short_adjacent_not_allowed,
            empty_adjacent_parameter,
            missing_parameter,
            extra_parameter,
            unrecognized_line
        };

        invalid_syntax(kind_t kind, 
                       const std::string& option_name = "",
                       const std::string& original_token = "",
                       int option_style              = 0):
            error_with_option_name(get_template(kind), option_name, original_token, option_style),
            m_kind(kind)
        {
        }

        ~invalid_syntax() throw() {}

        kind_t kind() const {return m_kind;}

        /** Convenience functions for backwards compatibility */
        virtual std::string tokens() const {return get_option_name();   }
    protected:
        /** Used to convert kind_t to a related error text */
        std::string get_template(kind_t kind);
        kind_t m_kind;
    };

    class BOOST_PROGRAM_OPTIONS_DECL invalid_config_file_syntax : public invalid_syntax {
    public:
        invalid_config_file_syntax(const std::string& invalid_line, kind_t kind):
            invalid_syntax(kind)
        {
            m_substitutions["invalid_line"] = invalid_line;
        }

        ~invalid_config_file_syntax() throw() {}

        /** Convenience functions for backwards compatibility */
        virtual std::string tokens() const {return m_substitutions.find("invalid_line")->second;    }
    };


    /** Class thrown when there are syntax errors in given command line */
    class BOOST_PROGRAM_OPTIONS_DECL invalid_command_line_syntax : public invalid_syntax {
    public:
        invalid_command_line_syntax(kind_t kind,
                       const std::string& option_name = "",
                       const std::string& original_token = "",
                       int option_style              = 0):
            invalid_syntax(kind, option_name, original_token, option_style) {}
        ~invalid_command_line_syntax() throw() {}
    };


    /** Class thrown when value of option is incorrect. */
    class BOOST_PROGRAM_OPTIONS_DECL validation_error : public error_with_option_name {
    public:
        enum kind_t {
            multiple_values_not_allowed = 30,
            at_least_one_value_required, 
            invalid_bool_value,
            invalid_option_value,
            invalid_option
        };
        
    public:
        validation_error(kind_t kind, 
                   const std::string& option_name = "",
                   const std::string& original_token = "",
                   int option_style              = 0):
        error_with_option_name(get_template(kind), option_name, original_token, option_style)
        {
        }

        ~validation_error() throw() {}

    protected:
        /** Used to convert kind_t to a related error text */
        std::string get_template(kind_t kind);
        kind_t m_kind;
    };

    /** Class thrown if there is an invalid option value given */
    class BOOST_PROGRAM_OPTIONS_DECL invalid_option_value 
        : public validation_error
    {
    public:
        invalid_option_value(const std::string& value);
#ifndef BOOST_NO_STD_WSTRING
        invalid_option_value(const std::wstring& value);
#endif
    };

    /** Class thrown if there is an invalid bool value given */
    class BOOST_PROGRAM_OPTIONS_DECL invalid_bool_value 
        : public validation_error
    {
    public:
        invalid_bool_value(const std::string& value);
    };





    

}}

#if defined(BOOST_MSVC)
#   pragma warning (pop)
#endif

#endif