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