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