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