COIN-OR::LEMON - Graph Library

source: lemon-1.2/lemon/arg_parser.h @ 864:d3ea191c3412

Last change on this file since 864:d3ea191c3412 was 842:c2ff0a365245, checked in by Alpar Juttner <alpar@…>, 10 years ago

ArgParser? can throw exception instead of exit(1) (#332)

File size: 13.2 KB
Line 
1/* -*- mode: C++; indent-tabs-mode: nil; -*-
2 *
3 * This file is a part of LEMON, a generic C++ optimization library.
4 *
5 * Copyright (C) 2003-2009
6 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
7 * (Egervary Research Group on Combinatorial Optimization, EGRES).
8 *
9 * Permission to use, modify and distribute this software is granted
10 * provided that this copyright notice appears in all copies. For
11 * precise terms see the accompanying LICENSE file.
12 *
13 * This software is provided "AS IS" with no warranty of any kind,
14 * express or implied, and with no claim as to its suitability for any
15 * purpose.
16 *
17 */
18
19#ifndef LEMON_ARG_PARSER_H
20#define LEMON_ARG_PARSER_H
21
22#include <vector>
23#include <map>
24#include <list>
25#include <string>
26#include <iostream>
27#include <sstream>
28#include <algorithm>
29#include <lemon/assert.h>
30
31///\ingroup misc
32///\file
33///\brief A tool to parse command line arguments.
34
35namespace lemon {
36
37  ///Exception used by ArgParser
38  class ArgParserException : public Exception {
39  public:
40    enum Reason {
41      HELP,         /// <tt>--help</tt> option was given
42      UNKNOWN_OPT,  /// Unknown option was given
43      INVALID_OPT   /// Invalid combination of options
44    };
45   
46  private:
47    Reason _reason;
48   
49  public:
50    ///Constructor
51    ArgParserException(Reason r) throw() : _reason(r) {}
52    ///Virtual destructor
53    virtual ~ArgParserException() throw() {}
54    ///A short description of the exception
55    virtual const char* what() const throw() {
56      switch(_reason)
57        {
58        case HELP:
59          return "lemon::ArgParseException: ask for help";
60          break;
61        case UNKNOWN_OPT:
62          return "lemon::ArgParseException: unknown option";
63          break;
64        case INVALID_OPT:
65          return "lemon::ArgParseException: invalid combination of options";
66          break;
67        }
68      return "";
69    }
70    ///Return the reason for the failure
71    Reason reason() const {return _reason; }
72  };
73
74
75  ///Command line arguments parser
76
77  ///\ingroup misc
78  ///Command line arguments parser.
79  ///
80  ///For a complete example see the \ref arg_parser_demo.cc demo file.
81  class ArgParser {
82
83    static void _showHelp(void *p);
84  protected:
85
86    int _argc;
87    const char * const *_argv;
88
89    enum OptType { UNKNOWN=0, BOOL=1, STRING=2, DOUBLE=3, INTEGER=4, FUNC=5 };
90
91    class ParData {
92    public:
93      union {
94        bool *bool_p;
95        int *int_p;
96        double *double_p;
97        std::string *string_p;
98        struct {
99          void (*p)(void *);
100          void *data;
101        } func_p;
102
103      };
104      std::string help;
105      bool mandatory;
106      OptType type;
107      bool set;
108      bool ingroup;
109      bool has_syn;
110      bool syn;
111      bool self_delete;
112      ParData() : mandatory(false), type(UNKNOWN), set(false), ingroup(false),
113                  has_syn(false), syn(false), self_delete(false) {}
114    };
115
116    typedef std::map<std::string,ParData> Opts;
117    Opts _opts;
118
119    class GroupData
120    {
121    public:
122      typedef std::list<std::string> Opts;
123      Opts opts;
124      bool only_one;
125      bool mandatory;
126      GroupData() :only_one(false), mandatory(false) {}
127    };
128
129    typedef std::map<std::string,GroupData> Groups;
130    Groups _groups;
131
132    struct OtherArg
133    {
134      std::string name;
135      std::string help;
136      OtherArg(std::string n, std::string h) :name(n), help(h) {}
137
138    };
139
140    std::vector<OtherArg> _others_help;
141    std::vector<std::string> _file_args;
142    std::string _command_name;
143
144   
145  private:
146    //Bind a function to an option.
147
148    //\param name The name of the option. The leading '-' must be omitted.
149    //\param help A help string.
150    //\retval func The function to be called when the option is given. It
151    //  must be of type "void f(void *)"
152    //\param data Data to be passed to \c func
153    ArgParser &funcOption(const std::string &name,
154                    const std::string &help,
155                    void (*func)(void *),void *data);
156
157    bool _exit_on_problems;
158   
159    void _terminate(ArgParserException::Reason reason) const;
160
161  public:
162
163    ///Constructor
164    ArgParser(int argc, const char * const *argv);
165
166    ~ArgParser();
167
168    ///\name Options
169    ///
170
171    ///@{
172
173    ///Add a new integer type option
174
175    ///Add a new integer type option.
176    ///\param name The name of the option. The leading '-' must be omitted.
177    ///\param help A help string.
178    ///\param value A default value for the option.
179    ///\param obl Indicate if the option is mandatory.
180    ArgParser &intOption(const std::string &name,
181                    const std::string &help,
182                    int value=0, bool obl=false);
183
184    ///Add a new floating point type option
185
186    ///Add a new floating point type option.
187    ///\param name The name of the option. The leading '-' must be omitted.
188    ///\param help A help string.
189    ///\param value A default value for the option.
190    ///\param obl Indicate if the option is mandatory.
191    ArgParser &doubleOption(const std::string &name,
192                      const std::string &help,
193                      double value=0, bool obl=false);
194
195    ///Add a new bool type option
196
197    ///Add a new bool type option.
198    ///\param name The name of the option. The leading '-' must be omitted.
199    ///\param help A help string.
200    ///\param value A default value for the option.
201    ///\param obl Indicate if the option is mandatory.
202    ///\note A mandatory bool obtion is of very little use.
203    ArgParser &boolOption(const std::string &name,
204                      const std::string &help,
205                      bool value=false, bool obl=false);
206
207    ///Add a new string type option
208
209    ///Add a new string type option.
210    ///\param name The name of the option. The leading '-' must be omitted.
211    ///\param help A help string.
212    ///\param value A default value for the option.
213    ///\param obl Indicate if the option is mandatory.
214    ArgParser &stringOption(const std::string &name,
215                      const std::string &help,
216                      std::string value="", bool obl=false);
217
218    ///Give help string for non-parsed arguments.
219
220    ///With this function you can give help string for non-parsed arguments.
221    ///The parameter \c name will be printed in the short usage line, while
222    ///\c help gives a more detailed description.
223    ArgParser &other(const std::string &name,
224                     const std::string &help="");
225
226    ///@}
227
228    ///\name Options with External Storage
229    ///Using this functions, the value of the option will be directly written
230    ///into a variable once the option appears in the command line.
231
232    ///@{
233
234    ///Add a new integer type option with a storage reference
235
236    ///Add a new integer type option with a storage reference.
237    ///\param name The name of the option. The leading '-' must be omitted.
238    ///\param help A help string.
239    ///\param obl Indicate if the option is mandatory.
240    ///\retval ref The value of the argument will be written to this variable.
241    ArgParser &refOption(const std::string &name,
242                    const std::string &help,
243                    int &ref, bool obl=false);
244
245    ///Add a new floating type option with a storage reference
246
247    ///Add a new floating type option with a storage reference.
248    ///\param name The name of the option. The leading '-' must be omitted.
249    ///\param help A help string.
250    ///\param obl Indicate if the option is mandatory.
251    ///\retval ref The value of the argument will be written to this variable.
252    ArgParser &refOption(const std::string &name,
253                      const std::string &help,
254                      double &ref, bool obl=false);
255
256    ///Add a new bool type option with a storage reference
257
258    ///Add a new bool type option with a storage reference.
259    ///\param name The name of the option. The leading '-' must be omitted.
260    ///\param help A help string.
261    ///\param obl Indicate if the option is mandatory.
262    ///\retval ref The value of the argument will be written to this variable.
263    ///\note A mandatory bool obtion is of very little use.
264    ArgParser &refOption(const std::string &name,
265                      const std::string &help,
266                      bool &ref, bool obl=false);
267
268    ///Add a new string type option with a storage reference
269
270    ///Add a new string type option with a storage reference.
271    ///\param name The name of the option. The leading '-' must be omitted.
272    ///\param help A help string.
273    ///\param obl Indicate if the option is mandatory.
274    ///\retval ref The value of the argument will be written to this variable.
275    ArgParser &refOption(const std::string &name,
276                      const std::string &help,
277                      std::string &ref, bool obl=false);
278
279    ///@}
280
281    ///\name Option Groups and Synonyms
282    ///
283
284    ///@{
285
286    ///Bundle some options into a group
287
288    /// You can group some option by calling this function repeatedly for each
289    /// option to be grouped with the same groupname.
290    ///\param group The group name.
291    ///\param opt The option name.
292    ArgParser &optionGroup(const std::string &group,
293                           const std::string &opt);
294
295    ///Make the members of a group exclusive
296
297    ///If you call this function for a group, than at most one of them can be
298    ///given at the same time.
299    ArgParser &onlyOneGroup(const std::string &group);
300
301    ///Make a group mandatory
302
303    ///Using this function, at least one of the members of \c group
304    ///must be given.
305    ArgParser &mandatoryGroup(const std::string &group);
306
307    ///Create synonym to an option
308
309    ///With this function you can create a synonym \c syn of the
310    ///option \c opt.
311    ArgParser &synonym(const std::string &syn,
312                           const std::string &opt);
313
314    ///@}
315
316  private:
317    void show(std::ostream &os,Opts::const_iterator i) const;
318    void show(std::ostream &os,Groups::const_iterator i) const;
319    void showHelp(Opts::const_iterator i) const;
320    void showHelp(std::vector<OtherArg>::const_iterator i) const;
321
322    void unknownOpt(std::string arg) const;
323
324    void requiresValue(std::string arg, OptType t) const;
325    void checkMandatories() const;
326
327    void shortHelp() const;
328    void showHelp() const;
329  public:
330
331    ///Start the parsing process
332    ArgParser &parse();
333
334    /// Synonym for parse()
335    ArgParser &run()
336    {
337      return parse();
338    }
339
340    ///Give back the command name (the 0th argument)
341    const std::string &commandName() const { return _command_name; }
342
343    ///Check if an opion has been given to the command.
344    bool given(std::string op) const
345    {
346      Opts::const_iterator i = _opts.find(op);
347      return i!=_opts.end()?i->second.set:false;
348    }
349
350
351    ///Magic type for operator[]
352
353    ///This is the type of the return value of ArgParser::operator[]().
354    ///It automatically converts to \c int, \c double, \c bool or
355    ///\c std::string if the type of the option matches, which is checked
356    ///with an \ref LEMON_ASSERT "assertion" (i.e. it performs runtime
357    ///type checking).
358    class RefType
359    {
360      const ArgParser &_parser;
361      std::string _name;
362    public:
363      ///\e
364      RefType(const ArgParser &p,const std::string &n) :_parser(p),_name(n) {}
365      ///\e
366      operator bool()
367      {
368        Opts::const_iterator i = _parser._opts.find(_name);
369        LEMON_ASSERT(i!=_parser._opts.end(),
370                     std::string()+"Unkown option: '"+_name+"'");
371        LEMON_ASSERT(i->second.type==ArgParser::BOOL,
372                     std::string()+"'"+_name+"' is a bool option");
373        return *(i->second.bool_p);
374      }
375      ///\e
376      operator std::string()
377      {
378        Opts::const_iterator i = _parser._opts.find(_name);
379        LEMON_ASSERT(i!=_parser._opts.end(),
380                     std::string()+"Unkown option: '"+_name+"'");
381        LEMON_ASSERT(i->second.type==ArgParser::STRING,
382                     std::string()+"'"+_name+"' is a string option");
383        return *(i->second.string_p);
384      }
385      ///\e
386      operator double()
387      {
388        Opts::const_iterator i = _parser._opts.find(_name);
389        LEMON_ASSERT(i!=_parser._opts.end(),
390                     std::string()+"Unkown option: '"+_name+"'");
391        LEMON_ASSERT(i->second.type==ArgParser::DOUBLE ||
392                     i->second.type==ArgParser::INTEGER,
393                     std::string()+"'"+_name+"' is a floating point option");
394        return i->second.type==ArgParser::DOUBLE ?
395          *(i->second.double_p) : *(i->second.int_p);
396      }
397      ///\e
398      operator int()
399      {
400        Opts::const_iterator i = _parser._opts.find(_name);
401        LEMON_ASSERT(i!=_parser._opts.end(),
402                     std::string()+"Unkown option: '"+_name+"'");
403        LEMON_ASSERT(i->second.type==ArgParser::INTEGER,
404                     std::string()+"'"+_name+"' is an integer option");
405        return *(i->second.int_p);
406      }
407
408    };
409
410    ///Give back the value of an option
411
412    ///Give back the value of an option.
413    ///\sa RefType
414    RefType operator[](const std::string &n) const
415    {
416      return RefType(*this, n);
417    }
418
419    ///Give back the non-option type arguments.
420
421    ///Give back a reference to a vector consisting of the program arguments
422    ///not starting with a '-' character.
423    const std::vector<std::string> &files() const { return _file_args; }
424
425    ///Throw instead of exit in case of problems
426    void throwOnProblems()
427    {
428      _exit_on_problems=false;
429    }
430  };
431}
432
433#endif // LEMON_ARG_PARSER_H
Note: See TracBrowser for help on using the repository browser.