lemon/arg_parser.h
author Alpar Juttner <alpar@cs.elte.hu>
Sun, 13 Jul 2008 19:51:02 +0100
changeset 209 765619b7cbb2
parent 204 77d56a21c3ab
child 214 60eecd3fe37a
permissions -rw-r--r--
Apply unify-sources.sh to the source tree
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@85
     5
 * Copyright (C) 2003-2008
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@85
    19
#ifndef LEMON_ARG_PARSER
alpar@85
    20
#define LEMON_ARG_PARSER
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;
alpar@85
    49
    const char **_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
alpar@85
   122
    ArgParser(int argc, const char **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@85
   274
    void show(std::ostream &os,Opts::iterator i);
alpar@85
   275
    void show(std::ostream &os,Groups::iterator i);
alpar@85
   276
    void showHelp(Opts::iterator i);
alpar@85
   277
    void showHelp(std::vector<OtherArg>::iterator i);
alpar@85
   278
    void shortHelp();
alpar@85
   279
    void showHelp();
alpar@85
   280
alpar@85
   281
    void unknownOpt(std::string arg);
alpar@85
   282
alpar@85
   283
    void requiresValue(std::string arg, OptType t);
alpar@85
   284
    void checkMandatories();
alpar@209
   285
alpar@85
   286
    ///Start the parsing process
alpar@85
   287
    ArgParser &parse();
alpar@85
   288
alpar@85
   289
    /// Synonym for parse()
alpar@209
   290
    ArgParser &run()
alpar@85
   291
    {
alpar@85
   292
      return parse();
alpar@85
   293
    }
alpar@209
   294
kpeter@204
   295
    ///Give back the command name (the 0th argument)
kpeter@204
   296
    const std::string &commandName() { return _command_name; }
kpeter@204
   297
alpar@85
   298
    ///Check if an opion has been given to the command.
alpar@209
   299
    bool given(std::string op)
alpar@85
   300
    {
alpar@85
   301
      Opts::iterator i = _opts.find(op);
alpar@85
   302
      return i!=_opts.end()?i->second.set:false;
alpar@85
   303
    }
alpar@85
   304
alpar@85
   305
alpar@85
   306
    ///Magic type for operator[]
alpar@209
   307
alpar@85
   308
    ///This is the type of the return value of ArgParser::operator[]().
kpeter@88
   309
    ///It automatically converts to \c int, \c double, \c bool or
kpeter@88
   310
    ///\c std::string if the type of the option matches, otherwise it
kpeter@88
   311
    ///throws an exception (i.e. it performs runtime type checking).
alpar@209
   312
    class RefType
alpar@85
   313
    {
alpar@85
   314
      ArgParser &_parser;
alpar@85
   315
      std::string _name;
alpar@85
   316
    public:
alpar@85
   317
      ///\e
alpar@85
   318
      RefType(ArgParser &p,const std::string &n) :_parser(p),_name(n) {}
alpar@85
   319
      ///\e
alpar@209
   320
      operator bool()
alpar@85
   321
      {
alpar@209
   322
        Opts::iterator i = _parser._opts.find(_name);
alpar@209
   323
        LEMON_ASSERT(i!=_parser._opts.end(),
alpar@209
   324
                     std::string()+"Unkown option: '"+_name+"'");
alpar@209
   325
        LEMON_ASSERT(i->second.type==ArgParser::BOOL,
alpar@209
   326
                     std::string()+"'"+_name+"' is a bool option");
alpar@209
   327
        return *(i->second.bool_p);
alpar@85
   328
      }
alpar@85
   329
      ///\e
alpar@85
   330
      operator std::string()
alpar@85
   331
      {
alpar@209
   332
        Opts::iterator i = _parser._opts.find(_name);
alpar@209
   333
        LEMON_ASSERT(i!=_parser._opts.end(),
alpar@209
   334
                     std::string()+"Unkown option: '"+_name+"'");
alpar@209
   335
        LEMON_ASSERT(i->second.type==ArgParser::STRING,
alpar@209
   336
                     std::string()+"'"+_name+"' is a string option");
alpar@209
   337
        return *(i->second.string_p);
alpar@85
   338
      }
alpar@85
   339
      ///\e
alpar@209
   340
      operator double()
alpar@85
   341
      {
alpar@209
   342
        Opts::iterator i = _parser._opts.find(_name);
alpar@209
   343
        LEMON_ASSERT(i!=_parser._opts.end(),
alpar@209
   344
                     std::string()+"Unkown option: '"+_name+"'");
alpar@209
   345
        LEMON_ASSERT(i->second.type==ArgParser::DOUBLE ||
alpar@209
   346
                     i->second.type==ArgParser::INTEGER,
alpar@209
   347
                     std::string()+"'"+_name+"' is a floating point option");
alpar@209
   348
        return i->second.type==ArgParser::DOUBLE ?
alpar@209
   349
          *(i->second.double_p) : *(i->second.int_p);
alpar@85
   350
      }
alpar@85
   351
      ///\e
alpar@209
   352
      operator int()
alpar@85
   353
      {
alpar@209
   354
        Opts::iterator i = _parser._opts.find(_name);
alpar@209
   355
        LEMON_ASSERT(i!=_parser._opts.end(),
alpar@209
   356
                     std::string()+"Unkown option: '"+_name+"'");
alpar@209
   357
        LEMON_ASSERT(i->second.type==ArgParser::INTEGER,
alpar@209
   358
                     std::string()+"'"+_name+"' is an integer option");
alpar@209
   359
        return *(i->second.int_p);
alpar@85
   360
      }
alpar@85
   361
alpar@85
   362
    };
alpar@85
   363
alpar@85
   364
    ///Give back the value of an option
alpar@209
   365
kpeter@88
   366
    ///Give back the value of an option.
alpar@85
   367
    ///\sa RefType
alpar@85
   368
    RefType operator[](const std::string &n)
alpar@85
   369
    {
alpar@85
   370
      return RefType(*this, n);
alpar@209
   371
    }
kpeter@204
   372
kpeter@204
   373
    ///Give back the non-option type arguments.
kpeter@204
   374
kpeter@204
   375
    ///Give back a reference to a vector consisting of the program arguments
kpeter@204
   376
    ///not starting with a '-' character.
kpeter@204
   377
    std::vector<std::string> &files() { return _file_args; }
alpar@209
   378
alpar@85
   379
  };
alpar@85
   380
}
alpar@85
   381
kpeter@204
   382
#endif // LEMON_ARG_PARSER