#ifndef OPTIONS_HPP
#define OPTIONS_HPP
#include <string>
#include <sstream>
#include <ostream>
#include <vector>
#include <stdexcept>
namespace example {
struct bad_option : public std::runtime_error {
bad_option(const std::string& s) : std::runtime_error(s) {}
};
class options {
public:
options(int argc, char const * const * argv) : argc_(argc), argv_(argv), prog_(argv[0]), help_() {
size_t slash = prog_.find_last_of("/\\");
if (slash != std::string::npos)
prog_ = prog_.substr(slash+1); // Extract prog name from path
add_flag(help_, 'h', "help", "Print the help message");
}
~options() {
for (opts::iterator i = opts_.begin(); i != opts_.end(); ++i)
delete *i;
}
template<class T>
void add_value(T& value, char short_name, const std::string& long_name, const std::string& description, const std::string var) {
opts_.push_back(new option_value<T>(value, short_name, long_name, description, var));
}
void add_flag(bool& flag, char short_name, const std::string& long_name, const std::string& description) {
opts_.push_back(new option_flag(flag, short_name, long_name, description));
}
int parse() {
int arg = 1;
for (; arg < argc_ && argv_[arg][0] == '-'; ++arg) {
opts::iterator i = opts_.begin();
while (i != opts_.end() && !(*i)->parse(argc_, argv_, arg))
++i;
if (i == opts_.end())
throw bad_option(std::string("unknown option ") + argv_[arg]);
}
if (help_) throw bad_option("");
return arg;
}
friend std::ostream& operator<<(std::ostream& os, const options& op) {
os << std::endl << "usage: " << op.prog_ << " [options]" << std::endl;
os << std::endl << "options:" << std::endl;
for (opts::const_iterator i = op.opts_.begin(); i < op.opts_.end(); ++i)
os << **i << std::endl;
return os;
}
private:
class option {
public:
option(char s, const std::string& l, const std::string& d, const std::string v) :
short_(std::string("-") + s), long_("--" + l), desc_(d), var_(v) {}
virtual ~option() {}
virtual bool parse(int argc, char const * const * argv, int &i) = 0;
virtual void print_default(std::ostream&) const {}
friend std::ostream& operator<<(std::ostream& os, const option& op) {
os << " " << op.short_;
if (!op.var_.empty()) os << " " << op.var_;
os << ", " << op.long_;
if (!op.var_.empty()) os << "=" << op.var_;
os << std::endl << " " << op.desc_;
op.print_default(os);
return os;
}
protected:
std::string short_, long_, desc_, var_;
};
template <class T>
class option_value : public option {
public:
option_value(T& value, char s, const std::string& l, const std::string& d, const std::string& v) :
option(s, l, d, v), value_(value) {}
bool parse(int argc, char const * const * argv, int &i) {
std::string arg(argv[i]);
if (arg == short_ || arg == long_) {
if (i < argc-1) {
set_value(arg, argv[++i]);
return true;
} else {
throw bad_option("missing value for " + arg);
}
}
if (arg.compare(0, long_.size(), long_) == 0 && arg[long_.size()] == '=' ) {
set_value(long_, arg.substr(long_.size()+1));
return true;
}
return false;
}
virtual void print_default(std::ostream& os) const { os << " (default " << value_ << ")"; }
void set_value(const std::string& opt, const std::string& s) {
std::istringstream is(s);
is >> value_;
if (is.fail() || is.bad())
throw bad_option("bad value for " + opt + ": " + s);
}
private:
T& value_;
};
class option_flag: public option {
public:
option_flag(bool& flag, const char s, const std::string& l, const std::string& d) :
option(s, l, d, ""), flag_(flag)
{ flag_ = false; }
bool parse(int , char const * const * argv, int &i) {
if (argv[i] == short_ || argv[i] == long_) {
flag_ = true;
return true;
} else {
return false;
}
}
private:
bool &flag_;
};
typedef std::vector<option*> opts;
int argc_;
char const * const * argv_;
std::string prog_;
opts opts_;
bool help_;
};
}
#endif // OPTIONS_HPP
Apache Qpid, Messaging built on AMQP; Copyright © 2015 The Apache Software Foundation; Licensed under the Apache License, Version 2.0; Apache Qpid, Qpid, Qpid Proton, Proton, Apache, the Apache feather logo, and the Apache Qpid project logo are trademarks of The Apache Software Foundation; All other marks mentioned may be trademarks or registered trademarks of their respective owners