1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/lemon/arg_parser.h Mon Mar 17 11:03:35 2008 +0000
1.3 @@ -0,0 +1,369 @@
1.4 +/* -*- C++ -*-
1.5 + *
1.6 + * This file is a part of LEMON, a generic C++ optimization library
1.7 + *
1.8 + * Copyright (C) 2003-2008
1.9 + * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
1.10 + * (Egervary Research Group on Combinatorial Optimization, EGRES).
1.11 + *
1.12 + * Permission to use, modify and distribute this software is granted
1.13 + * provided that this copyright notice appears in all copies. For
1.14 + * precise terms see the accompanying LICENSE file.
1.15 + *
1.16 + * This software is provided "AS IS" with no warranty of any kind,
1.17 + * express or implied, and with no claim as to its suitability for any
1.18 + * purpose.
1.19 + *
1.20 + */
1.21 +
1.22 +#ifndef LEMON_ARG_PARSER
1.23 +#define LEMON_ARG_PARSER
1.24 +
1.25 +#include <vector>
1.26 +#include <map>
1.27 +#include <list>
1.28 +#include <string>
1.29 +#include <iostream>
1.30 +#include <sstream>
1.31 +#include <algorithm>
1.32 +#include <lemon/error.h>
1.33 +
1.34 +///\ingroup misc
1.35 +///\file
1.36 +///\brief A tool to parse command line arguments.
1.37 +
1.38 +namespace lemon {
1.39 +
1.40 + ///Command line arguments parser
1.41 +
1.42 + ///\ingroup misc
1.43 + ///Command line arguments parser.
1.44 + ///
1.45 + ///For a complete example see the \ref arg_parser_demo.cc demo file.
1.46 + class ArgParser {
1.47 +
1.48 + static void _showHelp(void *p);
1.49 + protected:
1.50 +
1.51 + int _argc;
1.52 + const char **_argv;
1.53 +
1.54 + enum OptType { UNKNOWN=0, BOOL=1, STRING=2, DOUBLE=3, INTEGER=4, FUNC=5 };
1.55 +
1.56 + class ParData {
1.57 + public:
1.58 + union {
1.59 + bool *bool_p;
1.60 + int *int_p;
1.61 + double *double_p;
1.62 + std::string *string_p;
1.63 + struct {
1.64 + void (*p)(void *);
1.65 + void *data;
1.66 + } func_p;
1.67 +
1.68 + };
1.69 + std::string help;
1.70 + bool mandatory;
1.71 + OptType type;
1.72 + bool set;
1.73 + bool ingroup;
1.74 + bool has_syn;
1.75 + bool syn;
1.76 + bool self_delete;
1.77 + ParData() : mandatory(false), type(UNKNOWN), set(false), ingroup(false),
1.78 + has_syn(false), syn(false), self_delete(false) {}
1.79 + };
1.80 +
1.81 + typedef std::map<std::string,ParData> Opts;
1.82 + Opts _opts;
1.83 +
1.84 + class GroupData
1.85 + {
1.86 + public:
1.87 + typedef std::list<std::string> Opts;
1.88 + Opts opts;
1.89 + bool only_one;
1.90 + bool mandatory;
1.91 + GroupData() :only_one(false), mandatory(false) {}
1.92 + };
1.93 +
1.94 + typedef std::map<std::string,GroupData> Groups;
1.95 + Groups _groups;
1.96 +
1.97 + struct OtherArg
1.98 + {
1.99 + std::string name;
1.100 + std::string help;
1.101 + OtherArg(std::string n, std::string h) :name(n), help(h) {}
1.102 +
1.103 + };
1.104 +
1.105 + std::vector<OtherArg> _others_help;
1.106 + std::vector<std::string> _file_args;
1.107 + std::string _command_name;
1.108 +
1.109 +
1.110 + private:
1.111 + //Bind a function to an option.
1.112 +
1.113 + //\param name The name of the option. The leading '-' must be omitted.
1.114 + //\param help A help string.
1.115 + //\retval func The function to be called when the option is given. It
1.116 + // must be of type "void f(void *)"
1.117 + //\param data Data to be passed to \c func
1.118 + ArgParser &funcOption(const std::string &name,
1.119 + const std::string &help,
1.120 + void (*func)(void *),void *data);
1.121 +
1.122 + public:
1.123 +
1.124 + ///\e
1.125 + ArgParser(int argc, const char **argv);
1.126 +
1.127 + ~ArgParser();
1.128 +
1.129 + ///Add a new integer type option
1.130 +
1.131 + ///\param name The name of the option. The leading '-' must be omitted.
1.132 + ///\param help A help string.
1.133 + ///\retval value The value of the argument will be written to this variable.
1.134 + ///\param obl Indicate if the option is mandatory.
1.135 + ArgParser &intOption(const std::string &name,
1.136 + const std::string &help,
1.137 + int value=0, bool obl=false);
1.138 +
1.139 + ///Add a new floating point type option
1.140 +
1.141 + ///\param name The name of the option. The leading '-' must be omitted.
1.142 + ///\param help A help string.
1.143 + ///\retval value The value of the argument will be written to this variable.
1.144 + ///\param obl Indicate if the option is mandatory.
1.145 + ArgParser &doubleOption(const std::string &name,
1.146 + const std::string &help,
1.147 + double value=0, bool obl=false);
1.148 +
1.149 + ///Add a new bool type option
1.150 +
1.151 + ///\param name The name of the option. The leading '-' must be omitted.
1.152 + ///\param help A help string.
1.153 + ///\retval value The value of the argument will be written to this variable.
1.154 + ///\param obl Indicate if the option is mandatory.
1.155 + ////\note A mandatory bool obtion is of very little use.)
1.156 + ArgParser &boolOption(const std::string &name,
1.157 + const std::string &help,
1.158 + bool value=false, bool obl=false);
1.159 +
1.160 + ///Add a new string type option
1.161 +
1.162 + ///\param name The name of the option. The leading '-' must be omitted.
1.163 + ///\param help A help string.
1.164 + ///\retval value The value of the argument will be written to this variable.
1.165 + ///\param obl Indicate if the option is mandatory.
1.166 + ArgParser &stringOption(const std::string &name,
1.167 + const std::string &help,
1.168 + std::string value="", bool obl=false);
1.169 +
1.170 + ///\name Options with external storage
1.171 + ///Using this functions, the value of the option will be directly written
1.172 + ///into a variable once the option appears in the command line.
1.173 +
1.174 + ///@{
1.175 +
1.176 + ///Add a new integer type option with a storage reference
1.177 +
1.178 + ///\param name The name of the option. The leading '-' must be omitted.
1.179 + ///\param help A help string.
1.180 + ///\retval ref The value of the argument will be written to this variable.
1.181 + ///\param obl Indicate if the option is mandatory.
1.182 + ArgParser &refOption(const std::string &name,
1.183 + const std::string &help,
1.184 + int &ref, bool obl=false);
1.185 +
1.186 + ///Add a new floating type option with a storage reference
1.187 +
1.188 + ///\param name The name of the option. The leading '-' must be omitted.
1.189 + ///\param help A help string.
1.190 + ///\retval ref The value of the argument will be written to this variable.
1.191 + ///\param obl Indicate if the option is mandatory.
1.192 + ArgParser &refOption(const std::string &name,
1.193 + const std::string &help,
1.194 + double &ref, bool obl=false);
1.195 +
1.196 + ///Add a new bool type option with a storage reference
1.197 +
1.198 + ///\param name The name of the option. The leading '-' must be omitted.
1.199 + ///\param help A help string.
1.200 + ///\retval ref The value of the argument will be written to this variable.
1.201 + ///\param obl Indicate if the option is mandatory.
1.202 + ////\note A mandatory bool obtion is of very little use.)
1.203 + ArgParser &refOption(const std::string &name,
1.204 + const std::string &help,
1.205 + bool &ref, bool obl=false);
1.206 +
1.207 + ///Add a new string type option with a storage reference
1.208 +
1.209 + ///\param name The name of the option. The leading '-' must be omitted.
1.210 + ///\param help A help string.
1.211 + ///\retval ref The value of the argument will be written to this variable.
1.212 + ///\param obl Indicate if the option is mandatory.
1.213 + ArgParser &refOption(const std::string &name,
1.214 + const std::string &help,
1.215 + std::string &ref, bool obl=false);
1.216 +
1.217 + ///@}
1.218 +
1.219 + ///\name Option Groups and Synonyms
1.220 + ///
1.221 +
1.222 + ///@{
1.223 +
1.224 + ///Boundle some options into a group
1.225 +
1.226 + /// You can group some option by calling this function repeatedly for each
1.227 + /// option to be grouped with the same groupname.
1.228 + ///\param group The group name.
1.229 + ///\param opt The option name.
1.230 + ArgParser &optionGroup(const std::string &group,
1.231 + const std::string &opt);
1.232 +
1.233 + ///Make the members of a group exclusive
1.234 +
1.235 + ///If you call this function for a group, than at most one of them can be
1.236 + ///given at the same time
1.237 + ArgParser &onlyOneGroup(const std::string &group);
1.238 +
1.239 + ///Make a group mandatory
1.240 +
1.241 + ///Using this function, at least one of the members of \c group
1.242 + ///must be given.
1.243 + ArgParser &mandatoryGroup(const std::string &group);
1.244 +
1.245 + ///Create synonym to an option
1.246 +
1.247 + ///With this function you can create a synonym \c syn of the
1.248 + ///option \c opt.
1.249 + ArgParser &synonym(const std::string &syn,
1.250 + const std::string &opt);
1.251 +
1.252 + ///@}
1.253 +
1.254 + ///Give help string for non-parsed arguments.
1.255 +
1.256 + ///With this function you can give help string for non-parsed arguments.
1.257 + ///The parameter \c name will be printed in the short usage line, while
1.258 + ///\c help gives a more detailed description.
1.259 + ArgParser &other(const std::string &name,
1.260 + const std::string &help="");
1.261 +
1.262 + ///Give back the non-option type arguments.
1.263 +
1.264 + ///Give back a reference to a vector consisting of the program arguments
1.265 + ///not starting with a '-' character.
1.266 + std::vector<std::string> &files() { return _file_args; }
1.267 +
1.268 + ///Give back the command name (the 0th argument)
1.269 + const std::string &commandName() { return _command_name; }
1.270 +
1.271 + void show(std::ostream &os,Opts::iterator i);
1.272 + void show(std::ostream &os,Groups::iterator i);
1.273 + void showHelp(Opts::iterator i);
1.274 + void showHelp(std::vector<OtherArg>::iterator i);
1.275 + void shortHelp();
1.276 + void showHelp();
1.277 +
1.278 + void unknownOpt(std::string arg);
1.279 +
1.280 + void requiresValue(std::string arg, OptType t);
1.281 + void checkMandatories();
1.282 +
1.283 + ///Start the parsing process
1.284 + ArgParser &parse();
1.285 +
1.286 + /// Synonym for parse()
1.287 + ArgParser &run()
1.288 + {
1.289 + return parse();
1.290 + }
1.291 +
1.292 + ///Check if an opion has been given to the command.
1.293 + bool given(std::string op)
1.294 + {
1.295 + Opts::iterator i = _opts.find(op);
1.296 + return i!=_opts.end()?i->second.set:false;
1.297 + }
1.298 +
1.299 +
1.300 + ///Magic type for operator[]
1.301 +
1.302 + ///This is the type of the return value of ArgParser::operator[]().
1.303 + ///It automatically converts to \c int, \c double, \c bool or
1.304 + ///\c std::string if the type of the option matches, otherwise it
1.305 + ///throws an exception (i.e. it performs runtime type checking).
1.306 + class RefType
1.307 + {
1.308 + ArgParser &_parser;
1.309 + std::string _name;
1.310 + public:
1.311 + ///\e
1.312 + RefType(ArgParser &p,const std::string &n) :_parser(p),_name(n) {}
1.313 + ///\e
1.314 + operator bool()
1.315 + {
1.316 + Opts::iterator i = _parser._opts.find(_name);
1.317 + LEMON_ASSERT(i==_parser._opts.end(),
1.318 + std::string()+"Unkown option: '"+_name+"'");
1.319 + LEMON_ASSERT(i->second.type!=ArgParser::BOOL,
1.320 + std::string()+"'"+_name+"' is a bool option");
1.321 + return *(i->second.bool_p);
1.322 + }
1.323 + ///\e
1.324 + operator std::string()
1.325 + {
1.326 + Opts::iterator i = _parser._opts.find(_name);
1.327 + LEMON_ASSERT(i==_parser._opts.end(),
1.328 + std::string()+"Unkown option: '"+_name+"'");
1.329 + LEMON_ASSERT(i->second.type!=ArgParser::STRING,
1.330 + std::string()+"'"+_name+"' is a string option");
1.331 + return *(i->second.string_p);
1.332 + }
1.333 + ///\e
1.334 + operator double()
1.335 + {
1.336 + Opts::iterator i = _parser._opts.find(_name);
1.337 + LEMON_ASSERT(i==_parser._opts.end(),
1.338 + std::string()+"Unkown option: '"+_name+"'");
1.339 + LEMON_ASSERT(i->second.type!=ArgParser::DOUBLE &&
1.340 + i->second.type!=ArgParser::INTEGER,
1.341 + std::string()+"'"+_name+"' is a floating point option");
1.342 + return i->second.type==ArgParser::DOUBLE ?
1.343 + *(i->second.double_p) : *(i->second.int_p);
1.344 + }
1.345 + ///\e
1.346 + operator int()
1.347 + {
1.348 + Opts::iterator i = _parser._opts.find(_name);
1.349 + LEMON_ASSERT(i==_parser._opts.end(),
1.350 + std::string()+"Unkown option: '"+_name+"'");
1.351 + LEMON_ASSERT(i->second.type!=ArgParser::INTEGER,
1.352 + std::string()+"'"+_name+"' is an integer option");
1.353 + return *(i->second.int_p);
1.354 + }
1.355 +
1.356 + };
1.357 +
1.358 + ///Give back the value of an option
1.359 +
1.360 + ///Give back the value of an option.
1.361 + ///\sa RefType
1.362 + RefType operator[](const std::string &n)
1.363 + {
1.364 + return RefType(*this, n);
1.365 + }
1.366 +
1.367 + };
1.368 +}
1.369 +
1.370 +
1.371 +
1.372 +#endif // LEMON_MAIN_PARAMS