COIN-OR::LEMON - Graph Library

source: lemon-1.2/lemon/arg_parser.h @ 875:07ec2b52e53d

Last change on this file since 875:07ec2b52e53d was 842:c2ff0a365245, checked in by Alpar Juttner <alpar@…>, 14 years ago

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

File size: 13.2 KB
RevLine 
[209]1/* -*- mode: C++; indent-tabs-mode: nil; -*-
[85]2 *
[209]3 * This file is a part of LEMON, a generic C++ optimization library.
[85]4 *
[440]5 * Copyright (C) 2003-2009
[85]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
[261]19#ifndef LEMON_ARG_PARSER_H
20#define LEMON_ARG_PARSER_H
[85]21
22#include <vector>
23#include <map>
24#include <list>
25#include <string>
26#include <iostream>
27#include <sstream>
28#include <algorithm>
[108]29#include <lemon/assert.h>
[85]30
31///\ingroup misc
32///\file
[88]33///\brief A tool to parse command line arguments.
[85]34
35namespace lemon {
36
[842]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
[85]75  ///Command line arguments parser
76
77  ///\ingroup misc
[88]78  ///Command line arguments parser.
[85]79  ///
[88]80  ///For a complete example see the \ref arg_parser_demo.cc demo file.
[85]81  class ArgParser {
[209]82
[85]83    static void _showHelp(void *p);
84  protected:
[209]85
[85]86    int _argc;
[311]87    const char * const *_argv;
[209]88
[85]89    enum OptType { UNKNOWN=0, BOOL=1, STRING=2, DOUBLE=3, INTEGER=4, FUNC=5 };
[209]90
[85]91    class ParData {
92    public:
93      union {
[209]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
[85]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),
[209]113                  has_syn(false), syn(false), self_delete(false) {}
[85]114    };
115
116    typedef std::map<std::string,ParData> Opts;
117    Opts _opts;
118
[209]119    class GroupData
[85]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    };
[209]128
[85]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    };
[209]139
[85]140    std::vector<OtherArg> _others_help;
141    std::vector<std::string> _file_args;
142    std::string _command_name;
[87]143
[842]144   
[87]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,
[209]154                    const std::string &help,
155                    void (*func)(void *),void *data);
156
[842]157    bool _exit_on_problems;
158   
159    void _terminate(ArgParserException::Reason reason) const;
160
[85]161  public:
162
[204]163    ///Constructor
[311]164    ArgParser(int argc, const char * const *argv);
[85]165
166    ~ArgParser();
167
[204]168    ///\name Options
169    ///
170
171    ///@{
172
[85]173    ///Add a new integer type option
174
[204]175    ///Add a new integer type option.
[85]176    ///\param name The name of the option. The leading '-' must be omitted.
177    ///\param help A help string.
[95]178    ///\param value A default value for the option.
[85]179    ///\param obl Indicate if the option is mandatory.
180    ArgParser &intOption(const std::string &name,
[209]181                    const std::string &help,
182                    int value=0, bool obl=false);
[85]183
[86]184    ///Add a new floating point type option
[85]185
[204]186    ///Add a new floating point type option.
[85]187    ///\param name The name of the option. The leading '-' must be omitted.
188    ///\param help A help string.
[95]189    ///\param value A default value for the option.
[85]190    ///\param obl Indicate if the option is mandatory.
191    ArgParser &doubleOption(const std::string &name,
[209]192                      const std::string &help,
193                      double value=0, bool obl=false);
[85]194
195    ///Add a new bool type option
196
[204]197    ///Add a new bool type option.
[85]198    ///\param name The name of the option. The leading '-' must be omitted.
199    ///\param help A help string.
[95]200    ///\param value A default value for the option.
[85]201    ///\param obl Indicate if the option is mandatory.
[95]202    ///\note A mandatory bool obtion is of very little use.
[85]203    ArgParser &boolOption(const std::string &name,
[209]204                      const std::string &help,
205                      bool value=false, bool obl=false);
[85]206
207    ///Add a new string type option
208
[204]209    ///Add a new string type option.
[85]210    ///\param name The name of the option. The leading '-' must be omitted.
211    ///\param help A help string.
[95]212    ///\param value A default value for the option.
[85]213    ///\param obl Indicate if the option is mandatory.
214    ArgParser &stringOption(const std::string &name,
[209]215                      const std::string &help,
216                      std::string value="", bool obl=false);
[85]217
[204]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,
[209]224                     const std::string &help="");
225
[204]226    ///@}
227
228    ///\name Options with External Storage
[85]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
[204]236    ///Add a new integer type option with a storage reference.
[85]237    ///\param name The name of the option. The leading '-' must be omitted.
238    ///\param help A help string.
[90]239    ///\param obl Indicate if the option is mandatory.
[85]240    ///\retval ref The value of the argument will be written to this variable.
241    ArgParser &refOption(const std::string &name,
[209]242                    const std::string &help,
243                    int &ref, bool obl=false);
[85]244
245    ///Add a new floating type option with a storage reference
246
[204]247    ///Add a new floating type option with a storage reference.
[85]248    ///\param name The name of the option. The leading '-' must be omitted.
249    ///\param help A help string.
[90]250    ///\param obl Indicate if the option is mandatory.
[85]251    ///\retval ref The value of the argument will be written to this variable.
252    ArgParser &refOption(const std::string &name,
[209]253                      const std::string &help,
254                      double &ref, bool obl=false);
[85]255
256    ///Add a new bool type option with a storage reference
257
[204]258    ///Add a new bool type option with a storage reference.
[85]259    ///\param name The name of the option. The leading '-' must be omitted.
260    ///\param help A help string.
[90]261    ///\param obl Indicate if the option is mandatory.
[85]262    ///\retval ref The value of the argument will be written to this variable.
[95]263    ///\note A mandatory bool obtion is of very little use.
[85]264    ArgParser &refOption(const std::string &name,
[209]265                      const std::string &help,
266                      bool &ref, bool obl=false);
[85]267
268    ///Add a new string type option with a storage reference
269
[204]270    ///Add a new string type option with a storage reference.
[85]271    ///\param name The name of the option. The leading '-' must be omitted.
272    ///\param help A help string.
[95]273    ///\param obl Indicate if the option is mandatory.
[85]274    ///\retval ref The value of the argument will be written to this variable.
275    ArgParser &refOption(const std::string &name,
[209]276                      const std::string &help,
277                      std::string &ref, bool obl=false);
278
[85]279    ///@}
280
281    ///\name Option Groups and Synonyms
282    ///
[209]283
[85]284    ///@{
285
[204]286    ///Bundle some options into a group
[85]287
288    /// You can group some option by calling this function repeatedly for each
[88]289    /// option to be grouped with the same groupname.
290    ///\param group The group name.
291    ///\param opt The option name.
[85]292    ArgParser &optionGroup(const std::string &group,
[209]293                           const std::string &opt);
[85]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
[204]298    ///given at the same time.
[85]299    ArgParser &onlyOneGroup(const std::string &group);
[209]300
[85]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);
[209]306
[85]307    ///Create synonym to an option
308
[88]309    ///With this function you can create a synonym \c syn of the
[85]310    ///option \c opt.
311    ArgParser &synonym(const std::string &syn,
[209]312                           const std::string &opt);
313
[85]314    ///@}
315
[214]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;
[85]321
[214]322    void unknownOpt(std::string arg) const;
[85]323
[214]324    void requiresValue(std::string arg, OptType t) const;
325    void checkMandatories() const;
326
327    void shortHelp() const;
328    void showHelp() const;
329  public:
[209]330
[85]331    ///Start the parsing process
332    ArgParser &parse();
333
334    /// Synonym for parse()
[209]335    ArgParser &run()
[85]336    {
337      return parse();
338    }
[209]339
[204]340    ///Give back the command name (the 0th argument)
[214]341    const std::string &commandName() const { return _command_name; }
[204]342
[85]343    ///Check if an opion has been given to the command.
[214]344    bool given(std::string op) const
[85]345    {
[214]346      Opts::const_iterator i = _opts.find(op);
[85]347      return i!=_opts.end()?i->second.set:false;
348    }
349
350
351    ///Magic type for operator[]
[209]352
[85]353    ///This is the type of the return value of ArgParser::operator[]().
[88]354    ///It automatically converts to \c int, \c double, \c bool or
[290]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).
[209]358    class RefType
[85]359    {
[214]360      const ArgParser &_parser;
[85]361      std::string _name;
362    public:
363      ///\e
[214]364      RefType(const ArgParser &p,const std::string &n) :_parser(p),_name(n) {}
[85]365      ///\e
[209]366      operator bool()
[85]367      {
[214]368        Opts::const_iterator i = _parser._opts.find(_name);
[209]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);
[85]374      }
375      ///\e
376      operator std::string()
377      {
[214]378        Opts::const_iterator i = _parser._opts.find(_name);
[209]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);
[85]384      }
385      ///\e
[209]386      operator double()
[85]387      {
[214]388        Opts::const_iterator i = _parser._opts.find(_name);
[209]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);
[85]396      }
397      ///\e
[209]398      operator int()
[85]399      {
[214]400        Opts::const_iterator i = _parser._opts.find(_name);
[209]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);
[85]406      }
407
408    };
409
410    ///Give back the value of an option
[209]411
[88]412    ///Give back the value of an option.
[85]413    ///\sa RefType
[214]414    RefType operator[](const std::string &n) const
[85]415    {
416      return RefType(*this, n);
[209]417    }
[204]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.
[214]423    const std::vector<std::string> &files() const { return _file_args; }
[209]424
[842]425    ///Throw instead of exit in case of problems
426    void throwOnProblems()
427    {
428      _exit_on_problems=false;
429    }
[85]430  };
431}
432
[261]433#endif // LEMON_ARG_PARSER_H
Note: See TracBrowser for help on using the repository browser.