lemon/arg_parser.h
author Alpar Juttner <alpar@cs.elte.hu>
Thu, 24 Jan 2008 17:25:31 +0000
changeset 87 81e138275860
parent 86 eba5222bb6f5
child 88 18444049848b
permissions -rw-r--r--
Hide and privatize member function funcOption()
     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     
   108   private:
   109     //Bind a function to an option.
   110 
   111     //\param name The name of the option. The leading '-' must be omitted.
   112     //\param help A help string.
   113     //\retval func The function to be called when the option is given. It
   114     //  must be of type "void f(void *)"
   115     //\param data Data to be passed to \c func
   116     ArgParser &funcOption(const std::string &name,
   117 		    const std::string &help,
   118 		    void (*func)(void *),void *data);
   119     
   120   public:
   121 
   122     ///\e
   123     ArgParser(int argc, const char **argv);
   124 
   125     ~ArgParser();
   126 
   127     ///Add a new integer type option
   128 
   129     ///\param name The name of the option. The leading '-' must be omitted.
   130     ///\param help A help string.
   131     ///\retval value The value of the argument will be written to this variable.
   132     ///\param obl Indicate if the option is mandatory.
   133     ArgParser &intOption(const std::string &name,
   134 		    const std::string &help,
   135 		    int value=0, bool obl=false);
   136 
   137     ///Add a new floating point type option
   138 
   139     ///\param name The name of the option. The leading '-' must be omitted.
   140     ///\param help A help string.
   141     ///\retval value The value of the argument will be written to this variable.
   142     ///\param obl Indicate if the option is mandatory.
   143     ArgParser &doubleOption(const std::string &name,
   144 		      const std::string &help,
   145 		      double value=0, bool obl=false);
   146 
   147     ///Add a new bool type option
   148 
   149     ///\param name The name of the option. The leading '-' must be omitted.
   150     ///\param help A help string.
   151     ///\retval value The value of the argument will be written to this variable.
   152     ///\param obl Indicate if the option is mandatory.
   153     ////\note A mandatory bool obtion is of very little use.)
   154     ArgParser &boolOption(const std::string &name,
   155 		      const std::string &help,
   156 		      bool value=false, bool obl=false);
   157 
   158     ///Add a new string type option
   159 
   160     ///\param name The name of the option. The leading '-' must be omitted.
   161     ///\param help A help string.
   162     ///\retval value The value of the argument will be written to this variable.
   163     ///\param obl Indicate if the option is mandatory.
   164     ArgParser &stringOption(const std::string &name,
   165 		      const std::string &help,
   166 		      std::string value="", bool obl=false);
   167 
   168     ///\name Options with an external strorage.
   169     ///Using this functions, the value of the option will be directly written
   170     ///into a variable once the option appears in the command line.
   171 
   172     ///@{
   173 
   174     ///Add a new integer type option with a storage reference
   175 
   176     ///\param name The name of the option. The leading '-' must be omitted.
   177     ///\param help A help string.
   178     ///\retval ref The value of the argument will be written to this variable.
   179     ///\param obl Indicate if the option is mandatory.
   180     ArgParser &refOption(const std::string &name,
   181 		    const std::string &help,
   182 		    int &ref, bool obl=false);
   183 
   184     ///Add a new floating type option with a storage reference
   185 
   186     ///\param name The name of the option. The leading '-' must be omitted.
   187     ///\param help A help string.
   188     ///\retval ref The value of the argument will be written to this variable.
   189     ///\param obl Indicate if the option is mandatory.
   190     ArgParser &refOption(const std::string &name,
   191 		      const std::string &help,
   192 		      double &ref, bool obl=false);
   193 
   194     ///Add a new bool type option with a storage reference
   195 
   196     ///\param name The name of the option. The leading '-' must be omitted.
   197     ///\param help A help string.
   198     ///\retval ref The value of the argument will be written to this variable.
   199     ///\param obl Indicate if the option is mandatory.
   200     ////\note A mandatory bool obtion is of very little use.)
   201     ArgParser &refOption(const std::string &name,
   202 		      const std::string &help,
   203 		      bool &ref, bool obl=false);
   204 
   205     ///Add a new string type option with a storage reference
   206 
   207     ///\param name The name of the option. The leading '-' must be omitted.
   208     ///\param help A help string.
   209     ///\retval ref The value of the argument will be written to this variable.
   210     ///\param obl Indicate if the option is mandatory.
   211     ArgParser &refOption(const std::string &name,
   212 		      const std::string &help,
   213 		      std::string &ref, bool obl=false);
   214     
   215     ///@}
   216 
   217     ///\name Option Groups and Synonyms
   218     ///
   219     
   220     ///@{
   221 
   222     ///Boundle some options into a group
   223 
   224     /// You can group some option by calling this function repeatedly for each
   225     /// option to be grupped with the same groupname.
   226     ///\param group The group name
   227     ///\param opt The option name
   228     ArgParser &optionGroup(const std::string &group,
   229 			   const std::string &opt);
   230 
   231     ///Make the members of a group exclusive
   232 
   233     ///If you call this function for a group, than at most one of them can be
   234     ///given at the same time
   235     ArgParser &onlyOneGroup(const std::string &group);
   236   
   237     ///Make a group mandatory
   238 
   239     ///Using this function, at least one of the members of \c group
   240     ///must be given.
   241     ArgParser &mandatoryGroup(const std::string &group);
   242     
   243     ///Create synonym to an option
   244 
   245     ///With this function you can create a sysnonym called \c sys of the
   246     ///option \c opt.
   247     ArgParser &synonym(const std::string &syn,
   248 			   const std::string &opt);
   249     
   250     ///@}
   251 
   252     ///Give help string for non-parsed arguments.
   253 
   254     ///With this function you can give help string for non-parsed arguments.
   255     ///the parameter \c name will be printed in the short usage line, while
   256     ///\c help gives a more detailed description.
   257     ArgParser &other(const std::string &name,
   258 		     const std::string &help="");
   259     
   260     ///Non option type arguments.
   261 
   262     ///Gives back a reference to a vector consisting of the program arguments
   263     ///not starting with a '-' character.
   264     std::vector<std::string> &files() { return _file_args; }
   265 
   266     ///Give back the command name (the 0th argument)
   267     const std::string &commandName() { return _command_name; }
   268 
   269     void show(std::ostream &os,Opts::iterator i);
   270     void show(std::ostream &os,Groups::iterator i);
   271     void showHelp(Opts::iterator i);
   272     void showHelp(std::vector<OtherArg>::iterator i);
   273     void shortHelp();
   274     void showHelp();
   275 
   276     void unknownOpt(std::string arg);
   277 
   278     void requiresValue(std::string arg, OptType t);
   279     void checkMandatories();
   280     
   281     ///Start the parsing process
   282     ArgParser &parse();
   283 
   284     /// Synonym for parse()
   285     ArgParser &run() 
   286     {
   287       return parse();
   288     }
   289     
   290     ///Check if an opion has been given to the command.
   291     bool given(std::string op) 
   292     {
   293       Opts::iterator i = _opts.find(op);
   294       return i!=_opts.end()?i->second.set:false;
   295     }
   296 
   297 
   298     ///Magic type for operator[]
   299     
   300     ///This is the type of the return value of ArgParser::operator[]().
   301     ///It automatically converts to int, double, bool or std::string if
   302     ///the type of the option matches, otherwise it throws an exception.
   303     ///(i.e. it performs runtime type checking).
   304     class RefType 
   305     {
   306       ArgParser &_parser;
   307       std::string _name;
   308     public:
   309       ///\e
   310       RefType(ArgParser &p,const std::string &n) :_parser(p),_name(n) {}
   311       ///\e
   312       operator bool() 
   313       {
   314 	Opts::iterator i = _parser._opts.find(_name);
   315 	LEMON_ASSERT(i==_parser._opts.end(),
   316 		     std::string()+"Unkown option: '"+_name+"'");
   317 	LEMON_ASSERT(i->second.type!=ArgParser::BOOL,
   318 		     std::string()+"'"+_name+"' is a bool option");
   319 	return *(i->second.bool_p);
   320       }
   321       ///\e
   322       operator std::string()
   323       {
   324 	Opts::iterator i = _parser._opts.find(_name);
   325 	LEMON_ASSERT(i==_parser._opts.end(),
   326 		     std::string()+"Unkown option: '"+_name+"'");
   327 	LEMON_ASSERT(i->second.type!=ArgParser::STRING,
   328 		     std::string()+"'"+_name+"' is a string option");
   329 	return *(i->second.string_p);
   330       }
   331       ///\e
   332       operator double() 
   333       {
   334 	Opts::iterator i = _parser._opts.find(_name);
   335 	LEMON_ASSERT(i==_parser._opts.end(),
   336 		     std::string()+"Unkown option: '"+_name+"'");
   337 	LEMON_ASSERT(i->second.type!=ArgParser::DOUBLE &&
   338 		     i->second.type!=ArgParser::INTEGER,
   339 		     std::string()+"'"+_name+"' is a floating point option");
   340 	return i->second.type==ArgParser::DOUBLE ?
   341 	  *(i->second.double_p) : *(i->second.int_p);
   342       }
   343       ///\e
   344       operator int() 
   345       {
   346 	Opts::iterator i = _parser._opts.find(_name);
   347 	LEMON_ASSERT(i==_parser._opts.end(),
   348 		     std::string()+"Unkown option: '"+_name+"'");
   349 	LEMON_ASSERT(i->second.type!=ArgParser::INTEGER,
   350 		     std::string()+"'"+_name+"' is an integer option");
   351 	return *(i->second.int_p);
   352       }
   353 
   354     };
   355 
   356     ///Give back the value of an option
   357     
   358     ///Give back the value of an option
   359     ///\sa RefType
   360     RefType operator[](const std::string &n)
   361     {
   362       return RefType(*this, n);
   363     }    
   364  
   365   };
   366 }
   367 
   368     
   369 
   370 #endif // LEMON_MAIN_PARAMS