1.1 --- a/.hgignore Tue Jan 22 10:59:14 2008 +0000
1.2 +++ b/.hgignore Tue Jan 22 15:55:49 2008 +0000
1.3 @@ -31,4 +31,5 @@
1.4 ^autom4te.cache/.*
1.5 ^build-aux/.*
1.6 ^objs.*/.*
1.7 -^test/[a-z_]*$
1.8 \ No newline at end of file
1.9 +^test/[a-z_]*$
1.10 +^demo/.*_demo$
2.1 --- a/demo/Makefile.am Tue Jan 22 10:59:14 2008 +0000
2.2 +++ b/demo/Makefile.am Tue Jan 22 15:55:49 2008 +0000
2.3 @@ -3,6 +3,10 @@
2.4
2.5 if WANT_DEMO
2.6
2.7 -noinst_PROGRAMS +=
2.8 +noinst_PROGRAMS += \
2.9 + demo/arg_parser_demo
2.10
2.11 endif WANT_DEMO
2.12 +
2.13 +demo_arg_parser_demo_SOURCES = demo/arg_parser_demo.cc
2.14 +
3.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
3.2 +++ b/demo/arg_parser_demo.cc Tue Jan 22 15:55:49 2008 +0000
3.3 @@ -0,0 +1,79 @@
3.4 +/* -*- C++ -*-
3.5 + *
3.6 + * This file is a part of LEMON, a generic C++ optimization library
3.7 + *
3.8 + * Copyright (C) 2003-2008
3.9 + * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
3.10 + * (Egervary Research Group on Combinatorial Optimization, EGRES).
3.11 + *
3.12 + * Permission to use, modify and distribute this software is granted
3.13 + * provided that this copyright notice appears in all copies. For
3.14 + * precise terms see the accompanying LICENSE file.
3.15 + *
3.16 + * This software is provided "AS IS" with no warranty of any kind,
3.17 + * express or implied, and with no claim as to its suitability for any
3.18 + * purpose.
3.19 + *
3.20 + */
3.21 +
3.22 +///\ingroup demos
3.23 +///\file
3.24 +///\brief Argument parser demo
3.25 +///
3.26 +/// This example shows how can the argument parser used.
3.27 +///
3.28 +/// \include arg_parser.cc
3.29 +
3.30 +#include <lemon/arg_parser.h>
3.31 +
3.32 +using namespace lemon;
3.33 +int main(int argc, const char **argv)
3.34 +{
3.35 + ArgParser ap(argc,argv);
3.36 + int i;
3.37 + std::string s;
3.38 + double d;
3.39 + bool b,sil;
3.40 + bool g1,g2,g3;
3.41 + ap.refOption("n", "an integer input", i, true)
3.42 + .refOption("val", "a double input", d)
3.43 + .synonym("vals","val")
3.44 + .refOption("name", "a string input", s)
3.45 + .refOption("f", "a switch", b)
3.46 + .refOption("nohelp", "", sil)
3.47 + .refOption("gra","Choise A",g1)
3.48 + .refOption("grb","Choise B",g2)
3.49 + .refOption("grc","Choise C",g3)
3.50 + .optionGroup("gr","gra")
3.51 + .optionGroup("gr","grb")
3.52 + .optionGroup("gr","grc")
3.53 + .mandatoryGroup("gr")
3.54 + .onlyOneGroup("gr")
3.55 + .other("infile","The input file")
3.56 + .other("...");
3.57 +
3.58 + ap.parse();
3.59 +
3.60 + std::cout << "Parameters of '" << ap.commandName() << "':\n";
3.61 +
3.62 + if(ap.given("n")) std::cout << " Value of -n: " << i << std::endl;
3.63 + if(ap.given("val")) std::cout << " Value of -val: " << d << std::endl;
3.64 + if(ap.given("name")) std::cout << " Value of -name: " << s << std::endl;
3.65 + if(ap.given("f")) std::cout << " -f is given\n";
3.66 + if(ap.given("nohelp")) std::cout << " Value of -nohelp: " << sil << std::endl;
3.67 +
3.68 + switch(ap.files().size()) {
3.69 + case 0:
3.70 + std::cout << " No file argument was given.\n";
3.71 + break;
3.72 + case 1:
3.73 + std::cout << " 1 file argument was given. It is:\n";
3.74 + break;
3.75 + default:
3.76 + std::cout << " "
3.77 + << ap.files().size() << " file arguments were given. They are:\n";
3.78 + }
3.79 + for(unsigned int i=0;i<ap.files().size();++i)
3.80 + std::cout << " '" << ap.files()[i] << "'\n";
3.81 +
3.82 +}
4.1 --- a/lemon/Makefile.am Tue Jan 22 10:59:14 2008 +0000
4.2 +++ b/lemon/Makefile.am Tue Jan 22 15:55:49 2008 +0000
4.3 @@ -7,6 +7,7 @@
4.4 lib_LTLIBRARIES += lemon/libemon.la
4.5
4.6 lemon_libemon_la_SOURCES = \
4.7 + lemon/arg_parser.cc \
4.8 lemon/base.cc \
4.9 lemon/random.cc
4.10
4.11 @@ -15,6 +16,7 @@
4.12 lemon_libemon_la_LDFLAGS = $(GLPK_LIBS) $(CPLEX_LIBS) $(SOPLEX_LIBS)
4.13
4.14 lemon_HEADERS += \
4.15 + lemon/arg_parser.h \
4.16 lemon/dim2.h \
4.17 lemon/maps.h \
4.18 lemon/random.h \
5.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
5.2 +++ b/lemon/arg_parser.cc Tue Jan 22 15:55:49 2008 +0000
5.3 @@ -0,0 +1,469 @@
5.4 +/* -*- C++ -*-
5.5 + *
5.6 + * This file is a part of LEMON, a generic C++ optimization library
5.7 + *
5.8 + * Copyright (C) 2003-2008
5.9 + * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
5.10 + * (Egervary Research Group on Combinatorial Optimization, EGRES).
5.11 + *
5.12 + * Permission to use, modify and distribute this software is granted
5.13 + * provided that this copyright notice appears in all copies. For
5.14 + * precise terms see the accompanying LICENSE file.
5.15 + *
5.16 + * This software is provided "AS IS" with no warranty of any kind,
5.17 + * express or implied, and with no claim as to its suitability for any
5.18 + * purpose.
5.19 + *
5.20 + */
5.21 +
5.22 +#include <lemon/arg_parser.h>
5.23 +
5.24 +namespace lemon {
5.25 +
5.26 + void ArgParser::_showHelp(void *p)
5.27 + {
5.28 + (static_cast<ArgParser*>(p))->showHelp();
5.29 + exit(1);
5.30 + }
5.31 +
5.32 + ArgParser::ArgParser(int argc, const char **argv) :_argc(argc), _argv(argv),
5.33 + _command_name(argv[0]) {
5.34 + funcOption("-help","Print a short help message",_showHelp,this);
5.35 + synonym("help","-help");
5.36 + synonym("h","-help");
5.37 +
5.38 + }
5.39 +
5.40 + ArgParser::~ArgParser()
5.41 + {
5.42 + for(Opts::iterator i=_opts.begin();i!=_opts.end();++i)
5.43 + if(i->second.self_delete)
5.44 + switch(i->second.type) {
5.45 + case BOOL:
5.46 + delete i->second.bool_p;
5.47 + break;
5.48 + case STRING:
5.49 + delete i->second.string_p;
5.50 + break;
5.51 + case DOUBLE:
5.52 + delete i->second.double_p;
5.53 + break;
5.54 + case INTEGER:
5.55 + delete i->second.int_p;
5.56 + break;
5.57 + case UNKNOWN:
5.58 + break;
5.59 + case FUNC:
5.60 + break;
5.61 + }
5.62 + }
5.63 +
5.64 +
5.65 + ArgParser &ArgParser::intOption(const std::string &name,
5.66 + const std::string &help,
5.67 + int value, bool obl)
5.68 + {
5.69 + ParData p;
5.70 + p.int_p=new int(value);
5.71 + p.self_delete=true;
5.72 + p.help=help;
5.73 + p.type=INTEGER;
5.74 + p.mandatory=obl;
5.75 + p.self_delete=true;
5.76 + _opts[name]=p;
5.77 + return *this;
5.78 + }
5.79 +
5.80 + ArgParser &ArgParser::doubleOption(const std::string &name,
5.81 + const std::string &help,
5.82 + double value, bool obl)
5.83 + {
5.84 + ParData p;
5.85 + p.double_p=new double(value);
5.86 + p.self_delete=true;
5.87 + p.help=help;
5.88 + p.type=DOUBLE;
5.89 + p.mandatory=obl;
5.90 + _opts[name]=p;
5.91 + return *this;
5.92 + }
5.93 +
5.94 + ArgParser &ArgParser::boolOption(const std::string &name,
5.95 + const std::string &help,
5.96 + bool value, bool obl)
5.97 + {
5.98 + ParData p;
5.99 + p.bool_p=new bool(value);
5.100 + p.self_delete=true;
5.101 + p.help=help;
5.102 + p.type=BOOL;
5.103 + p.mandatory=obl;
5.104 + _opts[name]=p;
5.105 +
5.106 + value = false;
5.107 +
5.108 + return *this;
5.109 + }
5.110 +
5.111 + ArgParser &ArgParser::stringOption(const std::string &name,
5.112 + const std::string &help,
5.113 + std::string value, bool obl)
5.114 + {
5.115 + ParData p;
5.116 + p.string_p=new std::string(value);
5.117 + p.self_delete=true;
5.118 + p.help=help;
5.119 + p.type=STRING;
5.120 + p.mandatory=obl;
5.121 + _opts[name]=p;
5.122 + return *this;
5.123 + }
5.124 +
5.125 + ArgParser &ArgParser::refOption(const std::string &name,
5.126 + const std::string &help,
5.127 + int &ref, bool obl)
5.128 + {
5.129 + ParData p;
5.130 + p.int_p=&ref;
5.131 + p.self_delete=false;
5.132 + p.help=help;
5.133 + p.type=INTEGER;
5.134 + p.mandatory=obl;
5.135 + _opts[name]=p;
5.136 + return *this;
5.137 + }
5.138 +
5.139 + ArgParser &ArgParser::refOption(const std::string &name,
5.140 + const std::string &help,
5.141 + double &ref, bool obl)
5.142 + {
5.143 + ParData p;
5.144 + p.double_p=&ref;
5.145 + p.self_delete=false;
5.146 + p.help=help;
5.147 + p.type=DOUBLE;
5.148 + p.mandatory=obl;
5.149 + _opts[name]=p;
5.150 + return *this;
5.151 + }
5.152 +
5.153 + ArgParser &ArgParser::refOption(const std::string &name,
5.154 + const std::string &help,
5.155 + bool &ref, bool obl)
5.156 + {
5.157 + ParData p;
5.158 + p.bool_p=&ref;
5.159 + p.self_delete=false;
5.160 + p.help=help;
5.161 + p.type=BOOL;
5.162 + p.mandatory=obl;
5.163 + _opts[name]=p;
5.164 +
5.165 + ref = false;
5.166 +
5.167 + return *this;
5.168 + }
5.169 +
5.170 + ArgParser &ArgParser::refOption(const std::string &name,
5.171 + const std::string &help,
5.172 + std::string &ref, bool obl)
5.173 + {
5.174 + ParData p;
5.175 + p.string_p=&ref;
5.176 + p.self_delete=false;
5.177 + p.help=help;
5.178 + p.type=STRING;
5.179 + p.mandatory=obl;
5.180 + _opts[name]=p;
5.181 + return *this;
5.182 + }
5.183 +
5.184 + ArgParser &ArgParser::funcOption(const std::string &name,
5.185 + const std::string &help,
5.186 + void (*func)(void *),void *data)
5.187 + {
5.188 + ParData p;
5.189 + p.func_p.p=func;
5.190 + p.func_p.data=data;
5.191 + p.self_delete=false;
5.192 + p.help=help;
5.193 + p.type=FUNC;
5.194 + p.mandatory=false;
5.195 + _opts[name]=p;
5.196 + return *this;
5.197 + }
5.198 +
5.199 + ArgParser &ArgParser::optionGroup(const std::string &group,
5.200 + const std::string &opt)
5.201 + {
5.202 + Opts::iterator i = _opts.find(opt);
5.203 + LEMON_ASSERT(i!=_opts.end(), "Unknown option: '"+opt+"'");
5.204 + LEMON_ASSERT(!(i->second.ingroup),
5.205 + "Option already in option group: '"+opt+"'");
5.206 + GroupData &g=_groups[group];
5.207 + g.opts.push_back(opt);
5.208 + i->second.ingroup=true;
5.209 + return *this;
5.210 + }
5.211 +
5.212 + ArgParser &ArgParser::onlyOneGroup(const std::string &group)
5.213 + {
5.214 + GroupData &g=_groups[group];
5.215 + g.only_one=true;
5.216 + return *this;
5.217 + }
5.218 +
5.219 + ArgParser &ArgParser::synonym(const std::string &syn,
5.220 + const std::string &opt)
5.221 + {
5.222 + Opts::iterator o = _opts.find(opt);
5.223 + Opts::iterator s = _opts.find(syn);
5.224 + LEMON_ASSERT(o!=_opts.end(), "Unknown option: '"+opt+"'");
5.225 + LEMON_ASSERT(s==_opts.end(), "Option already used: '"+syn+"'");
5.226 + ParData p;
5.227 + p.help=opt;
5.228 + p.mandatory=false;
5.229 + p.syn=true;
5.230 + _opts[syn]=p;
5.231 + o->second.has_syn=true;
5.232 + return *this;
5.233 + }
5.234 +
5.235 + ArgParser &ArgParser::mandatoryGroup(const std::string &group)
5.236 + {
5.237 + GroupData &g=_groups[group];
5.238 + g.mandatory=true;
5.239 + return *this;
5.240 + }
5.241 +
5.242 + ArgParser &ArgParser::other(const std::string &name,
5.243 + const std::string &help)
5.244 + {
5.245 + _others_help.push_back(OtherArg(name,help));
5.246 + return *this;
5.247 + }
5.248 +
5.249 + void ArgParser::show(std::ostream &os,Opts::iterator i)
5.250 + {
5.251 + os << "-" << i->first;
5.252 + if(i->second.has_syn)
5.253 + for(Opts::iterator j=_opts.begin();j!=_opts.end();++j)
5.254 + if(j->second.syn&&j->second.help==i->first)
5.255 + os << "|-" << j->first;
5.256 + switch(i->second.type) {
5.257 + case STRING:
5.258 + os << " str";
5.259 + break;
5.260 + case INTEGER:
5.261 + os << " int";
5.262 + break;
5.263 + case DOUBLE:
5.264 + os << " num";
5.265 + break;
5.266 + default:
5.267 + break;
5.268 + }
5.269 + }
5.270 +
5.271 + void ArgParser::show(std::ostream &os,Groups::iterator i)
5.272 + {
5.273 + GroupData::Opts::iterator o=i->second.opts.begin();
5.274 + while(o!=i->second.opts.end()) {
5.275 + show(os,_opts.find(*o));
5.276 + ++o;
5.277 + if(o!=i->second.opts.end()) os<<'|';
5.278 + }
5.279 + }
5.280 +
5.281 + void ArgParser::showHelp(Opts::iterator i)
5.282 + {
5.283 + if(i->second.help.size()==0||i->second.syn) return;
5.284 + std::cerr << " ";
5.285 + show(std::cerr,i);
5.286 + std::cerr << std::endl;
5.287 + std::cerr << " " << i->second.help << std::endl;
5.288 + }
5.289 + void ArgParser::showHelp(std::vector<ArgParser::OtherArg>::iterator i)
5.290 + {
5.291 + if(i->help.size()==0) return;
5.292 + std::cerr << " " << i->name << std::endl
5.293 + << " " << i->help << std::endl;
5.294 + }
5.295 +
5.296 + void ArgParser::shortHelp()
5.297 + {
5.298 + const unsigned int LINE_LEN=77;
5.299 + const std::string indent(" ");
5.300 + std::cerr << "Usage:\n " << _command_name;
5.301 + int pos=_command_name.size()+2;
5.302 + for(Groups::iterator g=_groups.begin();g!=_groups.end();++g) {
5.303 + std::ostringstream cstr;
5.304 + cstr << ' ';
5.305 + if(!g->second.mandatory) cstr << '[';
5.306 + show(cstr,g);
5.307 + if(!g->second.mandatory) cstr << ']';
5.308 + if(pos+cstr.str().size()>LINE_LEN) {
5.309 + std::cerr << std::endl << indent;
5.310 + pos=indent.size();
5.311 + }
5.312 + std::cerr << cstr.str();
5.313 + pos+=cstr.str().size();
5.314 + }
5.315 + for(Opts::iterator i=_opts.begin();i!=_opts.end();++i)
5.316 + if(!i->second.ingroup&&!i->second.syn) {
5.317 + std::ostringstream cstr;
5.318 + cstr << ' ';
5.319 + if(!i->second.mandatory) cstr << '[';
5.320 + show(cstr,i);
5.321 + if(!i->second.mandatory) cstr << ']';
5.322 + if(pos+cstr.str().size()>LINE_LEN) {
5.323 + std::cerr << std::endl << indent;
5.324 + pos=indent.size();
5.325 + }
5.326 + std::cerr << cstr.str();
5.327 + pos+=cstr.str().size();
5.328 + }
5.329 + for(std::vector<OtherArg>::iterator i=_others_help.begin();
5.330 + i!=_others_help.end();++i)
5.331 + {
5.332 + std::ostringstream cstr;
5.333 + cstr << ' ' << i->name;
5.334 +
5.335 + if(pos+cstr.str().size()>LINE_LEN) {
5.336 + std::cerr << std::endl << indent;
5.337 + pos=indent.size();
5.338 + }
5.339 + std::cerr << cstr.str();
5.340 + pos+=cstr.str().size();
5.341 + }
5.342 + std::cerr << std::endl;
5.343 + }
5.344 +
5.345 + void ArgParser::showHelp()
5.346 + {
5.347 + shortHelp();
5.348 + std::cerr << "Where:\n";
5.349 + for(std::vector<OtherArg>::iterator i=_others_help.begin();
5.350 + i!=_others_help.end();++i) showHelp(i);
5.351 + for(Opts::iterator i=_opts.begin();i!=_opts.end();++i) showHelp(i);
5.352 + exit(1);
5.353 + }
5.354 +
5.355 +
5.356 + void ArgParser::unknownOpt(std::string arg)
5.357 + {
5.358 + std::cerr << "\nUnknown option: " << arg << "\n";
5.359 + std::cerr << "\nType '" << _command_name <<
5.360 + " --help' to obtain a short summary on the usage.\n\n";
5.361 + exit(1);
5.362 + }
5.363 +
5.364 + void ArgParser::requiresValue(std::string arg, OptType t)
5.365 + {
5.366 + std::cerr << "Argument '" << arg << "' requires a";
5.367 + switch(t) {
5.368 + case STRING:
5.369 + std::cerr << " string";
5.370 + break;
5.371 + case INTEGER:
5.372 + std::cerr << "n integer";
5.373 + break;
5.374 + case DOUBLE:
5.375 + std::cerr << " floating point";
5.376 + break;
5.377 + default:
5.378 + break;
5.379 + }
5.380 + std::cerr << " value\n\n";
5.381 + showHelp();
5.382 + }
5.383 +
5.384 +
5.385 + void ArgParser::checkMandatories()
5.386 + {
5.387 + bool ok=true;
5.388 + for(Opts::iterator i=_opts.begin();i!=_opts.end();++i)
5.389 + if(i->second.mandatory&&!i->second.set)
5.390 + {
5.391 + if(ok)
5.392 + std::cerr << _command_name
5.393 + << ": The following mandatory arguments are missing.\n";
5.394 + ok=false;
5.395 + showHelp(i);
5.396 + }
5.397 + for(Groups::iterator i=_groups.begin();i!=_groups.end();++i)
5.398 + if(i->second.mandatory||i->second.only_one)
5.399 + {
5.400 + int set=0;
5.401 + for(GroupData::Opts::iterator o=i->second.opts.begin();
5.402 + o!=i->second.opts.end();++o)
5.403 + if(_opts.find(*o)->second.set) ++set;
5.404 + if(i->second.mandatory&&!set) {
5.405 + std::cerr << _command_name
5.406 + << ": At least one of the following arguments is mandatory.\n";
5.407 + ok=false;
5.408 + for(GroupData::Opts::iterator o=i->second.opts.begin();
5.409 + o!=i->second.opts.end();++o)
5.410 + showHelp(_opts.find(*o));
5.411 + }
5.412 + if(i->second.only_one&&set>1) {
5.413 + std::cerr << _command_name
5.414 + << ": At most one of the following arguments can be given.\n";
5.415 + ok=false;
5.416 + for(GroupData::Opts::iterator o=i->second.opts.begin();
5.417 + o!=i->second.opts.end();++o)
5.418 + showHelp(_opts.find(*o));
5.419 + }
5.420 + }
5.421 + if(!ok) {
5.422 + std::cerr << "\nType '" << _command_name <<
5.423 + " --help' to obtain a short summary on the usage.\n\n";
5.424 + exit(1);
5.425 + }
5.426 + }
5.427 +
5.428 + ArgParser &ArgParser::parse()
5.429 + {
5.430 + for(int ar=1; ar<_argc; ++ar) {
5.431 + std::string arg(_argv[ar]);
5.432 + if (arg[0] != '-' || arg.size() == 1) {
5.433 + _file_args.push_back(arg);
5.434 + }
5.435 + else {
5.436 + Opts::iterator i = _opts.find(arg.substr(1));
5.437 + if(i==_opts.end()) unknownOpt(arg);
5.438 + else {
5.439 + if(i->second.syn) i=_opts.find(i->second.help);
5.440 + ParData &p(i->second);
5.441 + if (p.type==BOOL) *p.bool_p=true;
5.442 + else if (p.type==FUNC) p.func_p.p(p.func_p.data);
5.443 + else if(++ar==_argc) requiresValue(arg, p.type);
5.444 + else {
5.445 + std::string val(_argv[ar]);
5.446 + std::istringstream vals(val);
5.447 + switch(p.type) {
5.448 + case STRING:
5.449 + *p.string_p=val;
5.450 + break;
5.451 + case INTEGER:
5.452 + vals >> *p.int_p;
5.453 + break;
5.454 + case DOUBLE:
5.455 + vals >> *p.double_p;
5.456 + break;
5.457 + default:
5.458 + break;
5.459 + }
5.460 + if(p.type!=STRING&&(!vals||!vals.eof()))
5.461 + requiresValue(arg, p.type);
5.462 + }
5.463 + p.set = true;
5.464 + }
5.465 + }
5.466 + }
5.467 + checkMandatories();
5.468 +
5.469 + return *this;
5.470 + }
5.471 +
5.472 +}
6.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
6.2 +++ b/lemon/arg_parser.h Tue Jan 22 15:55:49 2008 +0000
6.3 @@ -0,0 +1,368 @@
6.4 +/* -*- C++ -*-
6.5 + *
6.6 + * This file is a part of LEMON, a generic C++ optimization library
6.7 + *
6.8 + * Copyright (C) 2003-2008
6.9 + * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
6.10 + * (Egervary Research Group on Combinatorial Optimization, EGRES).
6.11 + *
6.12 + * Permission to use, modify and distribute this software is granted
6.13 + * provided that this copyright notice appears in all copies. For
6.14 + * precise terms see the accompanying LICENSE file.
6.15 + *
6.16 + * This software is provided "AS IS" with no warranty of any kind,
6.17 + * express or implied, and with no claim as to its suitability for any
6.18 + * purpose.
6.19 + *
6.20 + */
6.21 +
6.22 +#ifndef LEMON_ARG_PARSER
6.23 +#define LEMON_ARG_PARSER
6.24 +
6.25 +#include <vector>
6.26 +#include <map>
6.27 +#include <list>
6.28 +#include <string>
6.29 +#include <iostream>
6.30 +#include <sstream>
6.31 +#include <algorithm>
6.32 +#include <lemon/error.h>
6.33 +
6.34 +///\ingroup misc
6.35 +///\file
6.36 +///\brief A tools to parse command line arguments.
6.37 +///
6.38 +///\author Alpar Juttner
6.39 +
6.40 +namespace lemon {
6.41 +
6.42 + ///Command line arguments parser
6.43 +
6.44 + ///\ingroup misc
6.45 + ///Command line arguments parser
6.46 + ///
6.47 + class ArgParser {
6.48 +
6.49 + static void _showHelp(void *p);
6.50 + protected:
6.51 +
6.52 + int _argc;
6.53 + const char **_argv;
6.54 +
6.55 + enum OptType { UNKNOWN=0, BOOL=1, STRING=2, DOUBLE=3, INTEGER=4, FUNC=5 };
6.56 +
6.57 + class ParData {
6.58 + public:
6.59 + union {
6.60 + bool *bool_p;
6.61 + int *int_p;
6.62 + double *double_p;
6.63 + std::string *string_p;
6.64 + struct {
6.65 + void (*p)(void *);
6.66 + void *data;
6.67 + } func_p;
6.68 +
6.69 + };
6.70 + std::string help;
6.71 + bool mandatory;
6.72 + OptType type;
6.73 + bool set;
6.74 + bool ingroup;
6.75 + bool has_syn;
6.76 + bool syn;
6.77 + bool self_delete;
6.78 + ParData() : mandatory(false), type(UNKNOWN), set(false), ingroup(false),
6.79 + has_syn(false), syn(false), self_delete(false) {}
6.80 + };
6.81 +
6.82 + typedef std::map<std::string,ParData> Opts;
6.83 + Opts _opts;
6.84 +
6.85 + class GroupData
6.86 + {
6.87 + public:
6.88 + typedef std::list<std::string> Opts;
6.89 + Opts opts;
6.90 + bool only_one;
6.91 + bool mandatory;
6.92 + GroupData() :only_one(false), mandatory(false) {}
6.93 + };
6.94 +
6.95 + typedef std::map<std::string,GroupData> Groups;
6.96 + Groups _groups;
6.97 +
6.98 + struct OtherArg
6.99 + {
6.100 + std::string name;
6.101 + std::string help;
6.102 + OtherArg(std::string n, std::string h) :name(n), help(h) {}
6.103 +
6.104 + };
6.105 +
6.106 + std::vector<OtherArg> _others_help;
6.107 + std::vector<std::string> _file_args;
6.108 + std::string _command_name;
6.109 +
6.110 + public:
6.111 +
6.112 + ///\e
6.113 + ArgParser(int argc, const char **argv);
6.114 +
6.115 + ~ArgParser();
6.116 +
6.117 + ///Add a new integer type option
6.118 +
6.119 + ///\param name The name of the option. The leading '-' must be omitted.
6.120 + ///\param help A help string.
6.121 + ///\retval value The value of the argument will be written to this variable.
6.122 + ///\param obl Indicate if the option is mandatory.
6.123 + ArgParser &intOption(const std::string &name,
6.124 + const std::string &help,
6.125 + int value=0, bool obl=false);
6.126 +
6.127 + ///Add a new floating type option
6.128 +
6.129 + ///\param name The name of the option. The leading '-' must be omitted.
6.130 + ///\param help A help string.
6.131 + ///\retval value The value of the argument will be written to this variable.
6.132 + ///\param obl Indicate if the option is mandatory.
6.133 + ArgParser &doubleOption(const std::string &name,
6.134 + const std::string &help,
6.135 + double value=0, bool obl=false);
6.136 +
6.137 + ///Add a new bool type option
6.138 +
6.139 + ///\param name The name of the option. The leading '-' must be omitted.
6.140 + ///\param help A help string.
6.141 + ///\retval value The value of the argument will be written to this variable.
6.142 + ///\param obl Indicate if the option is mandatory.
6.143 + ////\note A mandatory bool obtion is of very little use.)
6.144 + ArgParser &boolOption(const std::string &name,
6.145 + const std::string &help,
6.146 + bool value=false, bool obl=false);
6.147 +
6.148 + ///Add a new string type option
6.149 +
6.150 + ///\param name The name of the option. The leading '-' must be omitted.
6.151 + ///\param help A help string.
6.152 + ///\retval value The value of the argument will be written to this variable.
6.153 + ///\param obl Indicate if the option is mandatory.
6.154 + ArgParser &stringOption(const std::string &name,
6.155 + const std::string &help,
6.156 + std::string value="", bool obl=false);
6.157 +
6.158 + ///Bind a function to an option.
6.159 +
6.160 + ///\param name The name of the option. The leading '-' must be omitted.
6.161 + ///\param help A help string.
6.162 + ///\retval func The function to be called when the option is given. It
6.163 + /// must be of type "void f(void *)"
6.164 + ///\param data Data to be passed to \c func
6.165 + ArgParser &funcOption(const std::string &name,
6.166 + const std::string &help,
6.167 + void (*func)(void *),void *data);
6.168 +
6.169 + ///\name Options with an external strorage.
6.170 + ///Using this functions, the value of the option will be directly written
6.171 + ///into a variable once the option appears in the command line.
6.172 +
6.173 + ///@{
6.174 +
6.175 + ///Add a new integer type option with a storage reference
6.176 +
6.177 + ///\param name The name of the option. The leading '-' must be omitted.
6.178 + ///\param help A help string.
6.179 + ///\retval ref The value of the argument will be written to this variable.
6.180 + ///\param obl Indicate if the option is mandatory.
6.181 + ArgParser &refOption(const std::string &name,
6.182 + const std::string &help,
6.183 + int &ref, bool obl=false);
6.184 +
6.185 + ///Add a new floating type option with a storage reference
6.186 +
6.187 + ///\param name The name of the option. The leading '-' must be omitted.
6.188 + ///\param help A help string.
6.189 + ///\retval ref The value of the argument will be written to this variable.
6.190 + ///\param obl Indicate if the option is mandatory.
6.191 + ArgParser &refOption(const std::string &name,
6.192 + const std::string &help,
6.193 + double &ref, bool obl=false);
6.194 +
6.195 + ///Add a new bool type option with a storage reference
6.196 +
6.197 + ///\param name The name of the option. The leading '-' must be omitted.
6.198 + ///\param help A help string.
6.199 + ///\retval ref The value of the argument will be written to this variable.
6.200 + ///\param obl Indicate if the option is mandatory.
6.201 + ////\note A mandatory bool obtion is of very little use.)
6.202 + ArgParser &refOption(const std::string &name,
6.203 + const std::string &help,
6.204 + bool &ref, bool obl=false);
6.205 +
6.206 + ///Add a new string type option with a storage reference
6.207 +
6.208 + ///\param name The name of the option. The leading '-' must be omitted.
6.209 + ///\param help A help string.
6.210 + ///\retval ref The value of the argument will be written to this variable.
6.211 + ///\param obl Indicate if the option is mandatory.
6.212 + ArgParser &refOption(const std::string &name,
6.213 + const std::string &help,
6.214 + std::string &ref, bool obl=false);
6.215 +
6.216 + ///@}
6.217 +
6.218 + ///\name Option Groups and Synonyms
6.219 + ///
6.220 +
6.221 + ///@{
6.222 +
6.223 + ///Boundle some options into a group
6.224 +
6.225 + /// You can group some option by calling this function repeatedly for each
6.226 + /// option to be grupped with the same groupname.
6.227 + ///\param group The group name
6.228 + ///\param opt The option name
6.229 + ArgParser &optionGroup(const std::string &group,
6.230 + const std::string &opt);
6.231 +
6.232 + ///Make the members of a group exclusive
6.233 +
6.234 + ///If you call this function for a group, than at most one of them can be
6.235 + ///given at the same time
6.236 + ArgParser &onlyOneGroup(const std::string &group);
6.237 +
6.238 + ///Make a group mandatory
6.239 +
6.240 + ///Using this function, at least one of the members of \c group
6.241 + ///must be given.
6.242 + ArgParser &mandatoryGroup(const std::string &group);
6.243 +
6.244 + ///Create synonym to an option
6.245 +
6.246 + ///With this function you can create a sysnonym called \c sys of the
6.247 + ///option \c opt.
6.248 + ArgParser &synonym(const std::string &syn,
6.249 + const std::string &opt);
6.250 +
6.251 + ///@}
6.252 +
6.253 + ///Give help string for non-parsed arguments.
6.254 +
6.255 + ///With this function you can give help string for non-parsed arguments.
6.256 + ///the parameter \c name will be printed in the short usage line, while
6.257 + ///\c help gives a more detailed description.
6.258 + ArgParser &other(const std::string &name,
6.259 + const std::string &help="");
6.260 +
6.261 + ///Non option type arguments.
6.262 +
6.263 + ///Gives back a reference to a vector consisting of the program arguments
6.264 + ///not starting with a '-' character.
6.265 + std::vector<std::string> &files() { return _file_args; }
6.266 +
6.267 + ///Give back the command name (the 0th argument)
6.268 + const std::string &commandName() { return _command_name; }
6.269 +
6.270 + void show(std::ostream &os,Opts::iterator i);
6.271 + void show(std::ostream &os,Groups::iterator i);
6.272 + void showHelp(Opts::iterator i);
6.273 + void showHelp(std::vector<OtherArg>::iterator i);
6.274 + void shortHelp();
6.275 + void showHelp();
6.276 +
6.277 + void unknownOpt(std::string arg);
6.278 +
6.279 + void requiresValue(std::string arg, OptType t);
6.280 + void checkMandatories();
6.281 +
6.282 + ///Start the parsing process
6.283 + ArgParser &parse();
6.284 +
6.285 + /// Synonym for parse()
6.286 + ArgParser &run()
6.287 + {
6.288 + return parse();
6.289 + }
6.290 +
6.291 + ///Check if an opion has been given to the command.
6.292 + bool given(std::string op)
6.293 + {
6.294 + Opts::iterator i = _opts.find(op);
6.295 + return i!=_opts.end()?i->second.set:false;
6.296 + }
6.297 +
6.298 +
6.299 + ///Magic type for operator[]
6.300 +
6.301 + ///This is the type of the return value of ArgParser::operator[]().
6.302 + ///It automatically converts to int, double, bool or std::string, if it
6.303 + ///match the type of the option, otherwise it throws an exception.
6.304 + ///(i.e. it performs runtime type checking).
6.305 + class RefType
6.306 + {
6.307 + ArgParser &_parser;
6.308 + std::string _name;
6.309 + public:
6.310 + ///\e
6.311 + RefType(ArgParser &p,const std::string &n) :_parser(p),_name(n) {}
6.312 + ///\e
6.313 + operator bool()
6.314 + {
6.315 + Opts::iterator i = _parser._opts.find(_name);
6.316 + LEMON_ASSERT(i==_parser._opts.end(),
6.317 + std::string()+"Unkown option: '"+_name+"'");
6.318 + LEMON_ASSERT(i->second.type!=ArgParser::BOOL,
6.319 + std::string()+"'"+_name+"' is a bool option");
6.320 + return *(i->second.bool_p);
6.321 + }
6.322 + ///\e
6.323 + operator std::string()
6.324 + {
6.325 + Opts::iterator i = _parser._opts.find(_name);
6.326 + LEMON_ASSERT(i==_parser._opts.end(),
6.327 + std::string()+"Unkown option: '"+_name+"'");
6.328 + LEMON_ASSERT(i->second.type!=ArgParser::STRING,
6.329 + std::string()+"'"+_name+"' is a string option");
6.330 + return *(i->second.string_p);
6.331 + }
6.332 + ///\e
6.333 + operator double()
6.334 + {
6.335 + Opts::iterator i = _parser._opts.find(_name);
6.336 + LEMON_ASSERT(i==_parser._opts.end(),
6.337 + std::string()+"Unkown option: '"+_name+"'");
6.338 + LEMON_ASSERT(i->second.type!=ArgParser::DOUBLE &&
6.339 + i->second.type!=ArgParser::INTEGER,
6.340 + std::string()+"'"+_name+"' is a floating point option");
6.341 + return i->second.type==ArgParser::DOUBLE ?
6.342 + *(i->second.double_p) : *(i->second.int_p);
6.343 + }
6.344 + ///\e
6.345 + operator int()
6.346 + {
6.347 + Opts::iterator i = _parser._opts.find(_name);
6.348 + LEMON_ASSERT(i==_parser._opts.end(),
6.349 + std::string()+"Unkown option: '"+_name+"'");
6.350 + LEMON_ASSERT(i->second.type!=ArgParser::INTEGER,
6.351 + std::string()+"'"+_name+"' is an integer option");
6.352 + return *(i->second.int_p);
6.353 + }
6.354 +
6.355 + };
6.356 +
6.357 + ///Give back the value of an option
6.358 +
6.359 + ///Give back the value of an option
6.360 + ///\sa RefType
6.361 + RefType operator[](const std::string &n)
6.362 + {
6.363 + return RefType(*this, n);
6.364 + }
6.365 +
6.366 + };
6.367 +}
6.368 +
6.369 +
6.370 +
6.371 +#endif // LEMON_MAIN_PARAMS