lemon/arg_parser.h
author Balazs Dezso <deba@inf.elte.hu>
Thu, 24 Jun 2010 09:27:53 +0200
changeset 982 bb70ad62c95f
parent 311 c887e703b566
child 915 c2ff0a365245
permissions -rw-r--r--
Fix critical bug in preflow (#372)

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