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