2017-05-13 20:24:26 +00:00
|
|
|
/** @addtogroup Utilities
|
|
|
|
* @{
|
|
|
|
*/
|
|
|
|
|
|
|
|
/** @file argúparse.hh
|
|
|
|
*
|
|
|
|
* @brief Portable argument parsing.
|
|
|
|
*
|
|
|
|
* Provides a powerful argument parser that can handle a wide variety of
|
|
|
|
* cases, including POSIX and GNU argument ordering, different argument
|
|
|
|
* formats, optional values and type conversions.
|
|
|
|
*
|
|
|
|
* @copyright See COPYING.md in the project tree for further information.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef OSTD_ARGPARSE_HH
|
|
|
|
#define OSTD_ARGPARSE_HH
|
|
|
|
|
|
|
|
#include <vector>
|
|
|
|
#include <memory>
|
|
|
|
#include <stdexcept>
|
|
|
|
#include <utility>
|
|
|
|
|
|
|
|
#include "ostd/algorithm.hh"
|
|
|
|
#include "ostd/format.hh"
|
|
|
|
#include "ostd/string.hh"
|
2017-05-14 14:24:19 +00:00
|
|
|
#include "ostd/io.hh"
|
2017-05-13 20:24:26 +00:00
|
|
|
|
|
|
|
namespace ostd {
|
|
|
|
|
|
|
|
/** @addtogroup Utilities
|
|
|
|
* @{
|
|
|
|
*/
|
|
|
|
|
|
|
|
struct arg_error: std::runtime_error {
|
|
|
|
using std::runtime_error::runtime_error;
|
|
|
|
};
|
|
|
|
|
|
|
|
enum class arg_type {
|
|
|
|
OPTIONAL = 0,
|
|
|
|
POSITIONAL,
|
|
|
|
CATEGORY
|
|
|
|
};
|
|
|
|
|
|
|
|
enum class arg_value {
|
|
|
|
NONE = 0,
|
|
|
|
REQUIRED,
|
2017-05-14 14:24:19 +00:00
|
|
|
OPTIONAL,
|
|
|
|
ALL,
|
|
|
|
REST
|
2017-05-13 20:24:26 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
struct arg_parser;
|
|
|
|
|
2017-05-15 16:49:59 +00:00
|
|
|
struct arg_description {
|
2017-05-13 20:24:26 +00:00
|
|
|
friend struct arg_parser;
|
|
|
|
|
2017-05-15 16:49:59 +00:00
|
|
|
virtual ~arg_description() {}
|
2017-05-13 20:24:26 +00:00
|
|
|
|
|
|
|
virtual arg_type type() const = 0;
|
|
|
|
|
|
|
|
virtual bool is_arg(string_range name) const = 0;
|
|
|
|
|
2017-05-15 16:49:59 +00:00
|
|
|
protected:
|
|
|
|
arg_description() {}
|
|
|
|
};
|
|
|
|
|
|
|
|
struct arg_argument: arg_description {
|
|
|
|
friend struct arg_parser;
|
|
|
|
|
2017-05-15 17:55:26 +00:00
|
|
|
arg_argument &help(string_range str) {
|
|
|
|
p_helpstr = std::string{str};
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
2017-05-13 20:24:26 +00:00
|
|
|
protected:
|
2017-05-14 14:24:19 +00:00
|
|
|
arg_argument(arg_value req = arg_value::NONE, int nargs = 1):
|
2017-05-15 16:49:59 +00:00
|
|
|
arg_description(), p_valreq(req), p_nargs(nargs)
|
|
|
|
{}
|
|
|
|
arg_argument(int nargs):
|
|
|
|
arg_description(),
|
|
|
|
p_valreq((nargs > 0)
|
|
|
|
? arg_value::REQUIRED
|
|
|
|
: ((nargs < 0) ? arg_value::ALL : arg_value::NONE)
|
|
|
|
), p_nargs(nargs)
|
2017-05-14 14:24:19 +00:00
|
|
|
{}
|
|
|
|
|
2017-05-15 17:55:26 +00:00
|
|
|
std::string p_helpstr;
|
2017-05-14 14:24:19 +00:00
|
|
|
arg_value p_valreq;
|
|
|
|
int p_nargs;
|
2017-05-13 20:24:26 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
struct arg_optional: arg_argument {
|
|
|
|
friend struct arg_parser;
|
|
|
|
|
|
|
|
arg_type type() const {
|
|
|
|
return arg_type::OPTIONAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool is_arg(string_range name) const {
|
|
|
|
if (starts_with(name, "--")) {
|
|
|
|
return name.slice(2) == ostd::citer(p_lname);
|
|
|
|
}
|
|
|
|
if (name[0] == '-') {
|
|
|
|
return name[1] == p_sname;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
arg_value needs_value() const {
|
|
|
|
return p_valreq;
|
|
|
|
}
|
|
|
|
|
2017-05-15 22:22:46 +00:00
|
|
|
bool used() const {
|
|
|
|
return p_used;
|
2017-05-15 22:06:16 +00:00
|
|
|
}
|
|
|
|
|
2017-05-15 17:18:25 +00:00
|
|
|
template<typename F>
|
|
|
|
arg_optional &action(F func) {
|
2017-05-15 22:06:16 +00:00
|
|
|
p_action = [this, func = std::move(func)](
|
|
|
|
iterator_range<string_range const *> vals
|
|
|
|
) mutable {
|
2017-05-15 22:22:46 +00:00
|
|
|
func(vals);
|
|
|
|
p_used = true;
|
2017-05-15 22:06:16 +00:00
|
|
|
};
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
2017-05-15 17:55:26 +00:00
|
|
|
arg_optional &help(string_range str) {
|
|
|
|
arg_argument::help(str);
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
2017-05-13 20:24:26 +00:00
|
|
|
protected:
|
2017-05-14 14:24:19 +00:00
|
|
|
arg_optional() = delete;
|
|
|
|
arg_optional(
|
|
|
|
char short_name, string_range long_name,
|
|
|
|
arg_value req, int nargs = 1
|
|
|
|
):
|
|
|
|
arg_argument(req, nargs), p_lname(long_name), p_sname(short_name)
|
2017-05-13 20:24:26 +00:00
|
|
|
{}
|
2017-05-15 16:49:59 +00:00
|
|
|
arg_optional(char short_name, string_range long_name, int nargs):
|
|
|
|
arg_argument(nargs), p_lname(long_name), p_sname(short_name)
|
|
|
|
{}
|
2017-05-13 20:24:26 +00:00
|
|
|
|
2017-05-15 17:55:26 +00:00
|
|
|
void set_values(iterator_range<string_range const *> vals) {
|
|
|
|
if (p_action) {
|
2017-05-15 22:06:16 +00:00
|
|
|
p_action(vals);
|
2017-05-15 17:55:26 +00:00
|
|
|
} else {
|
2017-05-15 22:22:46 +00:00
|
|
|
p_used = true;
|
2017-05-15 17:55:26 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-05-13 20:24:26 +00:00
|
|
|
private:
|
2017-05-15 22:06:16 +00:00
|
|
|
std::function<void(iterator_range<string_range const *>)> p_action;
|
2017-05-13 20:24:26 +00:00
|
|
|
std::string p_lname;
|
|
|
|
char p_sname;
|
2017-05-15 22:22:46 +00:00
|
|
|
bool p_used = false;
|
2017-05-13 20:24:26 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
struct arg_positional: arg_argument {
|
|
|
|
friend struct arg_parser;
|
|
|
|
|
|
|
|
arg_type type() const {
|
|
|
|
return arg_type::POSITIONAL;
|
|
|
|
}
|
|
|
|
|
2017-05-15 17:18:25 +00:00
|
|
|
bool is_arg(string_range name) const {
|
|
|
|
return (name == ostd::citer(p_name));
|
2017-05-13 20:24:26 +00:00
|
|
|
}
|
2017-05-14 14:24:19 +00:00
|
|
|
|
|
|
|
protected:
|
|
|
|
arg_positional() = delete;
|
|
|
|
arg_positional(
|
|
|
|
string_range name, arg_value req = arg_value::REQUIRED, int nargs = 1
|
|
|
|
):
|
|
|
|
arg_argument(req, nargs),
|
|
|
|
p_name(name)
|
|
|
|
{}
|
2017-05-15 16:49:59 +00:00
|
|
|
arg_positional(string_range name, int nargs):
|
|
|
|
arg_argument(nargs),
|
|
|
|
p_name(name)
|
|
|
|
{}
|
2017-05-14 14:24:19 +00:00
|
|
|
|
|
|
|
private:
|
|
|
|
std::string p_name;
|
2017-05-13 20:24:26 +00:00
|
|
|
};
|
|
|
|
|
2017-05-15 16:49:59 +00:00
|
|
|
struct arg_category: arg_description {
|
2017-05-13 20:24:26 +00:00
|
|
|
friend struct arg_parser;
|
|
|
|
|
|
|
|
arg_type type() const {
|
|
|
|
return arg_type::CATEGORY;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool is_arg(string_range) const {
|
|
|
|
return false;
|
|
|
|
}
|
2017-05-14 14:24:19 +00:00
|
|
|
|
|
|
|
protected:
|
|
|
|
arg_category() = delete;
|
|
|
|
arg_category(
|
|
|
|
string_range name
|
|
|
|
):
|
|
|
|
p_name(name)
|
|
|
|
{}
|
|
|
|
|
|
|
|
private:
|
|
|
|
std::string p_name;
|
2017-05-13 20:24:26 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
struct arg_parser {
|
2017-05-14 14:24:19 +00:00
|
|
|
arg_parser(string_range progname = string_range{}):
|
|
|
|
p_progname(progname)
|
|
|
|
{}
|
|
|
|
|
|
|
|
void parse(int argc, char **argv) {
|
|
|
|
if (p_progname.empty()) {
|
|
|
|
p_progname = argv[0];
|
|
|
|
}
|
|
|
|
parse(iter(&argv[1], &argv[argc]));
|
|
|
|
}
|
2017-05-13 20:24:26 +00:00
|
|
|
|
|
|
|
template<typename InputRange>
|
|
|
|
void parse(InputRange args) {
|
|
|
|
bool allow_optional = true;
|
|
|
|
|
|
|
|
while (!args.empty()) {
|
|
|
|
string_range s{args.front()};
|
|
|
|
if (s == "--") {
|
|
|
|
args.pop_front();
|
|
|
|
allow_optional = false;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (!allow_optional) {
|
|
|
|
parse_pos(s);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (starts_with(s, "--")) {
|
|
|
|
parse_long(s, args);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if ((s.size() > 1) && (s[0] == '-') && (s != "-")) {
|
|
|
|
parse_short(s, args);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
parse_pos(s);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename ...A>
|
|
|
|
arg_optional &add_optional(A &&...args) {
|
2017-05-15 16:49:59 +00:00
|
|
|
arg_description *p = new arg_optional{std::forward<A>(args)...};
|
2017-05-13 20:24:26 +00:00
|
|
|
return static_cast<arg_optional &>(*p_opts.emplace_back(p));
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename ...A>
|
|
|
|
arg_positional &add_positional(A &&...args) {
|
2017-05-15 16:49:59 +00:00
|
|
|
arg_description *p = new arg_positional{std::forward<A>(args)...};
|
2017-05-13 20:24:26 +00:00
|
|
|
return static_cast<arg_positional &>(*p_opts.emplace_back(p));
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename ...A>
|
|
|
|
arg_category &add_category(A &&...args) {
|
2017-05-15 16:49:59 +00:00
|
|
|
arg_description *p = new arg_category{std::forward<A>(args)...};
|
2017-05-13 20:24:26 +00:00
|
|
|
return static_cast<arg_category &>(*p_opts.emplace_back(p));
|
|
|
|
}
|
|
|
|
|
2017-05-15 19:10:41 +00:00
|
|
|
template<typename OutputRange>
|
|
|
|
arg_optional &add_help(OutputRange out, string_range msg) {
|
|
|
|
auto &opt = add_optional('h', "help", arg_value::NONE);
|
|
|
|
opt.help(msg);
|
|
|
|
opt.action([this, out = std::move(out)](auto) mutable {
|
|
|
|
this->print_help(out);
|
|
|
|
return true;
|
|
|
|
});
|
|
|
|
return opt;
|
|
|
|
}
|
|
|
|
|
|
|
|
arg_optional &add_help(string_range msg) {
|
|
|
|
return add_help(cout.iter(), msg);
|
|
|
|
}
|
|
|
|
|
2017-05-14 14:24:19 +00:00
|
|
|
template<typename OutputRange>
|
|
|
|
OutputRange &&print_help(OutputRange &&range) {
|
|
|
|
print_usage_impl(range);
|
|
|
|
print_help_impl(range);
|
|
|
|
return std::forward<OutputRange>(range);
|
|
|
|
}
|
|
|
|
|
|
|
|
void print_help() {
|
|
|
|
print_help(cout.iter());
|
|
|
|
}
|
|
|
|
|
2017-05-15 17:18:25 +00:00
|
|
|
arg_argument &get(string_range name) {
|
|
|
|
return find_arg<arg_argument>(name);
|
|
|
|
}
|
|
|
|
|
2017-05-15 19:10:41 +00:00
|
|
|
bool used(string_range name) {
|
|
|
|
auto &arg = find_arg<arg_optional>(name);
|
2017-05-15 22:22:46 +00:00
|
|
|
return arg.p_used;
|
2017-05-15 19:10:41 +00:00
|
|
|
}
|
|
|
|
|
2017-05-13 20:24:26 +00:00
|
|
|
private:
|
2017-05-14 14:24:19 +00:00
|
|
|
template<typename OR>
|
|
|
|
void print_usage_impl(OR &out) {
|
|
|
|
string_range progname = p_progname;
|
|
|
|
if (progname.empty()) {
|
|
|
|
progname = "program";
|
|
|
|
}
|
|
|
|
format(out, "usage: %s [opts] [args]\n", progname);
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename OR>
|
|
|
|
void print_help_impl(OR &out) {
|
2017-05-15 17:55:26 +00:00
|
|
|
std::size_t opt_namel = 0, pos_namel = 0;
|
2017-05-14 14:24:19 +00:00
|
|
|
for (auto &p: p_opts) {
|
|
|
|
switch (p->type()) {
|
2017-05-15 17:55:26 +00:00
|
|
|
case arg_type::OPTIONAL: {
|
|
|
|
auto &opt = static_cast<arg_optional &>(*p);
|
|
|
|
std::size_t nl = 0;
|
|
|
|
if (opt.p_sname) {
|
|
|
|
nl += 2;
|
|
|
|
}
|
|
|
|
if (!opt.p_lname.empty()) {
|
|
|
|
if (opt.p_sname) {
|
|
|
|
nl += 2;
|
|
|
|
}
|
|
|
|
nl += opt.p_lname.size() + 2;
|
|
|
|
}
|
|
|
|
opt_namel = std::max(opt_namel, nl);
|
2017-05-14 14:24:19 +00:00
|
|
|
break;
|
2017-05-15 17:55:26 +00:00
|
|
|
}
|
2017-05-14 14:24:19 +00:00
|
|
|
case arg_type::POSITIONAL:
|
2017-05-15 17:55:26 +00:00
|
|
|
pos_namel = std::max(
|
|
|
|
pos_namel,
|
|
|
|
static_cast<arg_positional &>(*p).p_name.size()
|
|
|
|
);
|
2017-05-14 14:24:19 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-05-15 17:55:26 +00:00
|
|
|
std::size_t maxpad = std::max(opt_namel, pos_namel);
|
|
|
|
|
|
|
|
if (pos_namel) {
|
2017-05-14 14:24:19 +00:00
|
|
|
format(out, "\npositional arguments:\n");
|
|
|
|
for (auto &p: p_opts) {
|
|
|
|
if (p->type() != arg_type::POSITIONAL) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
auto &parg = static_cast<arg_positional &>(*p.get());
|
2017-05-15 17:55:26 +00:00
|
|
|
format(out, " %s", parg.p_name);
|
|
|
|
if (parg.p_helpstr.empty()) {
|
|
|
|
out.put('\n');
|
|
|
|
} else {
|
|
|
|
std::size_t nd = maxpad - parg.p_name.size() + 2;
|
|
|
|
for (std::size_t i = 0; i < nd; ++i) {
|
|
|
|
out.put(' ');
|
|
|
|
}
|
|
|
|
format(out, "%s\n", parg.p_helpstr);
|
|
|
|
}
|
2017-05-14 14:24:19 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-05-15 17:55:26 +00:00
|
|
|
if (opt_namel) {
|
2017-05-14 14:24:19 +00:00
|
|
|
format(out, "\noptional arguments:\n");
|
|
|
|
for (auto &p: p_opts) {
|
|
|
|
if (p->type() != arg_type::OPTIONAL) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
auto &parg = static_cast<arg_optional &>(*p.get());
|
|
|
|
format(out, " ");
|
2017-05-15 17:55:26 +00:00
|
|
|
std::size_t nd = 0;
|
2017-05-14 14:24:19 +00:00
|
|
|
if (parg.p_sname) {
|
2017-05-15 17:55:26 +00:00
|
|
|
nd += 2;
|
2017-05-14 14:24:19 +00:00
|
|
|
format(out, "-%c", parg.p_sname);
|
|
|
|
if (!parg.p_lname.empty()) {
|
2017-05-15 17:55:26 +00:00
|
|
|
nd += 2;
|
2017-05-14 14:24:19 +00:00
|
|
|
format(out, ", ");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!parg.p_lname.empty()) {
|
2017-05-15 17:55:26 +00:00
|
|
|
nd += parg.p_lname.size() + 2;
|
2017-05-14 14:24:19 +00:00
|
|
|
format(out, "--%s", parg.p_lname);
|
|
|
|
}
|
2017-05-15 17:55:26 +00:00
|
|
|
if (parg.p_helpstr.empty()) {
|
|
|
|
out.put('\n');
|
|
|
|
} else {
|
|
|
|
nd = maxpad - nd + 2;
|
|
|
|
for (std::size_t i = 0; i < nd; ++i) {
|
|
|
|
out.put(' ');
|
|
|
|
}
|
|
|
|
format(out, "%s\n", parg.p_helpstr);
|
|
|
|
}
|
2017-05-14 14:24:19 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-05-13 20:24:26 +00:00
|
|
|
template<typename R>
|
|
|
|
void parse_long(string_range arg, R &args) {
|
|
|
|
string_range val = find(arg, '=');
|
|
|
|
bool has_val = !val.empty(), arg_val = false;
|
|
|
|
if (has_val) {
|
|
|
|
arg = arg.slice(0, arg.size() - val.size());
|
|
|
|
val.pop_front();
|
|
|
|
}
|
|
|
|
|
2017-05-15 17:18:25 +00:00
|
|
|
auto &desc = find_arg<arg_optional>(arg);
|
2017-05-13 20:24:26 +00:00
|
|
|
|
|
|
|
args.pop_front();
|
|
|
|
auto needs = desc.needs_value();
|
|
|
|
if (needs == arg_value::NONE) {
|
|
|
|
if (has_val) {
|
|
|
|
throw arg_error{format(
|
2017-05-14 14:24:19 +00:00
|
|
|
appender<std::string>(), "argument '--%s' takes no value",
|
2017-05-13 20:24:26 +00:00
|
|
|
desc.p_lname
|
|
|
|
).get()};
|
|
|
|
}
|
2017-05-15 19:10:41 +00:00
|
|
|
desc.set_values(nullptr);
|
2017-05-13 20:24:26 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (!has_val) {
|
|
|
|
if (args.empty()) {
|
|
|
|
if (needs == arg_value::REQUIRED) {
|
|
|
|
throw arg_error{format(
|
2017-05-14 14:24:19 +00:00
|
|
|
appender<std::string>(), "argument '--%s' needs a value",
|
2017-05-13 20:24:26 +00:00
|
|
|
desc.p_lname
|
|
|
|
).get()};
|
|
|
|
}
|
2017-05-15 19:10:41 +00:00
|
|
|
desc.set_values(nullptr);
|
2017-05-13 20:24:26 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
string_range tval = args.front();
|
|
|
|
if ((needs != arg_value::OPTIONAL) || !find_arg_ptr(tval)) {
|
|
|
|
val = tval;
|
|
|
|
has_val = arg_val = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (has_val) {
|
2017-05-15 17:55:26 +00:00
|
|
|
desc.set_values(iter({ val }));
|
2017-05-13 20:24:26 +00:00
|
|
|
if (arg_val) {
|
|
|
|
args.pop_front();
|
|
|
|
}
|
2017-05-15 19:10:41 +00:00
|
|
|
} else {
|
|
|
|
desc.set_values(nullptr);
|
2017-05-13 20:24:26 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename R>
|
|
|
|
void parse_short(string_range arg, R &args) {
|
|
|
|
string_range val;
|
|
|
|
bool has_val = (arg.size() > 2), arg_val = false;
|
|
|
|
if (has_val) {
|
|
|
|
val = arg.slice(2);
|
|
|
|
arg = arg.slice(0, 2);
|
|
|
|
}
|
|
|
|
|
2017-05-15 17:18:25 +00:00
|
|
|
auto &desc = find_arg<arg_optional>(arg);
|
2017-05-13 20:24:26 +00:00
|
|
|
|
|
|
|
args.pop_front();
|
|
|
|
auto needs = desc.needs_value();
|
|
|
|
if (needs == arg_value::NONE) {
|
|
|
|
if (has_val) {
|
|
|
|
throw arg_error{format(
|
|
|
|
appender<std::string>(), "argument '-%c' takes no value",
|
|
|
|
desc.p_sname
|
|
|
|
).get()};
|
|
|
|
}
|
2017-05-15 19:10:41 +00:00
|
|
|
desc.set_values(nullptr);
|
2017-05-13 20:24:26 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (!has_val) {
|
|
|
|
if (args.empty()) {
|
|
|
|
if (needs == arg_value::REQUIRED) {
|
|
|
|
throw arg_error{format(
|
|
|
|
appender<std::string>(), "argument '-%c' needs a value",
|
|
|
|
desc.p_sname
|
|
|
|
).get()};
|
|
|
|
}
|
2017-05-15 19:10:41 +00:00
|
|
|
desc.set_values(nullptr);
|
2017-05-13 20:24:26 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
string_range tval = args.front();
|
|
|
|
if ((needs != arg_value::OPTIONAL) || !find_arg_ptr(tval)) {
|
|
|
|
val = tval;
|
|
|
|
has_val = arg_val = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (has_val) {
|
2017-05-15 17:55:26 +00:00
|
|
|
desc.set_values(iter({ val }));
|
2017-05-13 20:24:26 +00:00
|
|
|
if (arg_val) {
|
|
|
|
args.pop_front();
|
|
|
|
}
|
2017-05-15 19:10:41 +00:00
|
|
|
} else {
|
|
|
|
desc.set_values(nullptr);
|
2017-05-13 20:24:26 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void parse_pos(string_range) {
|
|
|
|
}
|
|
|
|
|
2017-05-15 16:49:59 +00:00
|
|
|
arg_description *find_arg_ptr(string_range name) {
|
2017-05-13 20:24:26 +00:00
|
|
|
for (auto &p: p_opts) {
|
|
|
|
if (p->is_arg(name)) {
|
|
|
|
return &*p;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2017-05-15 17:18:25 +00:00
|
|
|
template<typename AT>
|
|
|
|
AT &find_arg(string_range name) {
|
|
|
|
auto p = static_cast<AT *>(find_arg_ptr(name));
|
2017-05-13 20:24:26 +00:00
|
|
|
if (p) {
|
|
|
|
return *p;
|
|
|
|
}
|
|
|
|
throw arg_error{format(
|
|
|
|
appender<std::string>(), "unknown argument '%s'", name
|
|
|
|
).get()};
|
|
|
|
}
|
|
|
|
|
2017-05-15 16:49:59 +00:00
|
|
|
std::vector<std::unique_ptr<arg_description>> p_opts;
|
2017-05-14 14:24:19 +00:00
|
|
|
std::string p_progname;
|
2017-05-13 20:24:26 +00:00
|
|
|
};
|
|
|
|
|
2017-05-15 19:10:41 +00:00
|
|
|
template<typename OutputRange>
|
|
|
|
auto arg_print_help(OutputRange o, arg_parser &p) {
|
2017-05-15 22:06:16 +00:00
|
|
|
return [o = std::move(o), &p](iterator_range<string_range const *>)
|
|
|
|
mutable
|
|
|
|
{
|
|
|
|
p.print_help(o);
|
2017-05-15 19:10:41 +00:00
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
auto arg_print_help(arg_parser &p) {
|
|
|
|
return arg_print_help(cout.iter(), p);
|
|
|
|
}
|
|
|
|
|
2017-05-15 22:22:46 +00:00
|
|
|
template<typename T, typename U>
|
|
|
|
auto arg_store_const(T &&val, U &ref) {
|
|
|
|
return [val, &ref](iterator_range<string_range const *>) mutable {
|
|
|
|
ref = std::move(val);
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2017-05-15 19:10:41 +00:00
|
|
|
template<typename T>
|
2017-05-15 22:22:46 +00:00
|
|
|
auto arg_store_str(T &ref) {
|
|
|
|
return [&ref](iterator_range<string_range const *> r) mutable {
|
|
|
|
ref = T{r[0]};
|
2017-05-15 19:10:41 +00:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2017-05-15 22:22:46 +00:00
|
|
|
auto arg_store_true(bool &ref) {
|
|
|
|
return arg_store_const(true, ref);
|
2017-05-15 19:10:41 +00:00
|
|
|
}
|
|
|
|
|
2017-05-15 22:22:46 +00:00
|
|
|
auto arg_store_false(bool &ref) {
|
|
|
|
return arg_store_const(false, ref);
|
2017-05-15 19:10:41 +00:00
|
|
|
}
|
|
|
|
|
2017-05-13 20:24:26 +00:00
|
|
|
/** @} */
|
|
|
|
|
|
|
|
} /* namespace ostd */
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/** @} */
|