COIN-OR::LEMON - Graph Library

source: lemon-main/lemon/arg_parser.h

Last change on this file was 1123:18c89646185e, checked in by Alpar Juttner <alpar@…>, 5 years ago

Suppress MSVC warning C4267 (#519)

C4267: conversion from 'size_t' to 'type', possible loss of data

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