COIN-OR::LEMON - Graph Library

source: lemon/lemon/arg_parser.h @ 959:38213abd2911

Last change on this file since 959:38213abd2911 was 959:38213abd2911, checked in by Peter Kovacs <kpeter@…>, 10 years ago

Small doc fixes and improvements (#359)

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