Commit 776522ee authored by Dominik Charousset's avatar Dominik Charousset

support for command line parsing (on_opt, on_vopt, rd_arg)

parent ea2eafef
...@@ -271,3 +271,4 @@ examples/group_server.cpp ...@@ -271,3 +271,4 @@ examples/group_server.cpp
examples/group_chat.cpp examples/group_chat.cpp
cppa/opt.hpp cppa/opt.hpp
src/opt.cpp src/opt.cpp
cppa/detail/opt_impls.hpp
/******************************************************************************\
* ___ __ *
* /\_ \ __/\ \ *
* \//\ \ /\_\ \ \____ ___ _____ _____ __ *
* \ \ \ \/\ \ \ '__`\ /'___\/\ '__`\/\ '__`\ /'__`\ *
* \_\ \_\ \ \ \ \L\ \/\ \__/\ \ \L\ \ \ \L\ \/\ \L\.\_ *
* /\____\\ \_\ \_,__/\ \____\\ \ ,__/\ \ ,__/\ \__/.\_\ *
* \/____/ \/_/\/___/ \/____/ \ \ \/ \ \ \/ \/__/\/_/ *
* \ \_\ \ \_\ *
* \/_/ \/_/ *
* *
* Copyright (C) 2011, 2012 *
* Dominik Charousset <dominik.charousset@haw-hamburg.de> *
* *
* This file is part of libcppa. *
* libcppa is free software: you can redistribute it and/or modify it under *
* the terms of the GNU Lesser General Public License as published by the *
* Free Software Foundation, either version 3 of the License *
* or (at your option) any later version. *
* *
* libcppa is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
* See the GNU Lesser General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public License *
* along with libcppa. If not, see <http://www.gnu.org/licenses/>. *
\******************************************************************************/
#ifndef CPPA_OPT_IMPLS_HPP
#define CPPA_OPT_IMPLS_HPP
#include <sstream>
#include "cppa/on.hpp"
#include "cppa/option.hpp"
// this header contains implementation details for opt.hpp
namespace cppa { namespace detail {
template<typename T>
struct conv_arg_impl {
typedef option<T> result_type;
static inline result_type _(const std::string& arg) {
std::istringstream iss(arg);
T result;
if (iss >> result && iss.eof()) {
return result;
}
return {};
}
};
template<>
struct conv_arg_impl<std::string> {
typedef option<std::string> result_type;
static inline result_type _(const std::string& arg) { return arg; }
};
template<bool> class opt_rvalue_builder;
template<typename T>
struct rd_arg_storage : ref_counted {
T& storage;
bool set;
std::string arg_name;
rd_arg_storage(T& r) : storage(r), set(false) { }
};
template<typename T>
class rd_arg_functor {
template<bool> friend class opt_rvalue_builder;
typedef rd_arg_storage<T> storage_type;
public:
rd_arg_functor(const rd_arg_functor&) = default;
rd_arg_functor(T& storage) : m_storage(new storage_type(storage)) { }
bool operator()(const std::string& arg) const {
if (m_storage->set) {
std::cerr << "*** error: " << m_storage->arg_name
<< " previously set to " << m_storage->storage
<< std::endl;
}
else {
auto opt = conv_arg_impl<T>::_(arg);
if (opt) {
m_storage->storage = *opt;
m_storage->set = true;
return true;
}
else {
std::cerr << "*** error: cannot convert \"" << arg << "\" to "
<< detail::demangle(typeid(T).name())
<< " [option: \"" << m_storage->arg_name << "\"]"
<< std::endl;
}
}
return false;
}
private:
intrusive_ptr<storage_type> m_storage;
};
template<typename T>
struct is_rd_arg : std::false_type { };
template<typename T>
struct is_rd_arg<rd_arg_functor<T> > : std::true_type { };
template<bool HasShortOpt = true>
class opt_rvalue_builder {
public:
typedef decltype(on<std::string, std::string>()
.when(cppa::placeholders::_x1.in(std::vector<std::string>())))
left_type;
typedef decltype(on(std::function<option<std::string>(const std::string&)>()))
right_type;
template<typename Left, typename Right>
opt_rvalue_builder(char sopt, std::string lopt, Left&& lhs, Right&& rhs)
: m_short(sopt), m_long(std::move(lopt))
, m_left(std::forward<Left>(lhs)), m_right(std::forward<Right>(rhs)) { }
template<typename Expr>
auto operator>>(Expr expr)
-> decltype((*(static_cast<left_type*>(nullptr)) >> expr).or_else(
*(static_cast<right_type*>(nullptr)) >> expr)) const {
return (m_left >> expr).or_else(m_right >> expr);
}
private:
template<typename T>
inline void inject_arg_name(rd_arg_functor<T>& expr) {
expr.m_storage->arg_name = m_long;
}
template<typename T>
inline void inject_arg_name(const T&) { }
char m_short;
std::string m_long;
left_type m_left;
right_type m_right;
};
template<>
class opt_rvalue_builder<false> {
public:
typedef decltype(on(std::function<option<std::string>(const std::string&)>()))
sub_type;
template<typename SubType>
opt_rvalue_builder(char sopt, std::string lopt, SubType&& sub)
: m_short(sopt), m_long(std::move(lopt))
, m_sub(std::forward<SubType>(sub)) { }
template<typename Expr>
auto operator>>(Expr expr)
-> decltype(*static_cast<sub_type*>(nullptr) >> expr) const {
return m_sub >> expr;
}
private:
template<typename T>
inline void inject_arg_name(rd_arg_functor<T>& expr) {
expr.m_storage->arg_name = m_long;
}
template<typename T>
inline void inject_arg_name(const T&) { }
char m_short;
std::string m_long;
sub_type m_sub;
};
} } // namespace cppa::detail
#endif // CPPA_OPT_IMPLS_HPP
...@@ -31,17 +31,51 @@ ...@@ -31,17 +31,51 @@
#ifndef CPPA_OPT_HPP #ifndef CPPA_OPT_HPP
#define CPPA_OPT_HPP #define CPPA_OPT_HPP
#include <map>
#include <string>
#include <iostream>
#include <functional>
#include "cppa/on.hpp" #include "cppa/on.hpp"
#include "cppa/option.hpp" #include "cppa/option.hpp"
#include "cppa/detail/demangle.hpp" #include "cppa/detail/demangle.hpp"
#include "cppa/detail/opt_impls.hpp"
namespace cppa { namespace cppa {
namespace detail { template<typename T>
typename detail::conv_arg_impl<T>::result_type conv_arg(const std::string& arg) {
return detail::conv_arg_impl<T>::_(arg);
}
template<typename T>
detail::rd_arg_functor<T> rd_arg(T& storage) {
return {storage};
}
typedef std::map<std::string, std::map<std::pair<char, std::string>, std::string> >
options_description;
detail::opt_rvalue_builder<true> on_opt(char short_opt,
std::string long_opt,
options_description* desc = nullptr,
std::string help_text = "",
std::string help_group = "general options");
decltype(on<std::string>()
.when(cppa::placeholders::_x1.in(std::vector<std::string>())))
on_vopt(char short_opt,
std::string long_opt,
options_description* desc = nullptr,
std::string help_text = "",
std::string help_group = "general options");
std::function<void()> print_desc(options_description* desc,
std::ostream& out = std::cout);
} // namespace detail std::function<void()> print_desc_and_exit(options_description* desc,
std::ostream& out = std::cout,
int exit_reason = 0);
} // namespace cppa } // namespace cppa
......
...@@ -28,5 +28,89 @@ ...@@ -28,5 +28,89 @@
\******************************************************************************/ \******************************************************************************/
#include <iomanip>
#include <algorithm>
#include "cppa/opt.hpp" #include "cppa/opt.hpp"
using namespace std;
using cppa::placeholders::_x1;
namespace cppa {
detail::opt_rvalue_builder<true> on_opt(char short_opt,
string long_opt,
options_description* desc,
string help_text,
string help_group) {
if (desc) {
(*desc)[help_group].insert(make_pair(make_pair(short_opt, long_opt), help_text));
}
const char short_flag_arr[] = {'-', short_opt, '\0' };
const char* lhs_str = short_flag_arr;
string prefix = "--";
prefix += long_opt;
prefix += "=";
function<option<string> (const string&)> kvp = [prefix](const string& input) -> option<string> {
if (equal(begin(prefix), end(prefix), begin(input))) {
return input.substr(prefix.size());
}
else if (equal(begin(prefix) + 1, end(prefix), begin(input))) {
return input.substr(prefix.size() - 1);
}
return {};
};
vector<string> opts;
opts.push_back(lhs_str);
opts.push_back("--" + long_opt);
opts.push_back("-" + long_opt);
return {short_opt, long_opt, on<string, string>().when(_x1.in(opts)), on(kvp)};
}
decltype(on<string>().when(_x1.in(vector<string>())))
on_vopt(char short_opt,
string long_opt,
options_description* desc,
string help_text,
string help_group) {
if (desc) {
(*desc)[help_group].insert(make_pair(make_pair(short_opt, long_opt), help_text));
}
const char short_flag_arr[] = {'-', short_opt, '\0' };
vector<string> opt_strs = { short_flag_arr };
opt_strs.push_back("-" + long_opt);
opt_strs.push_back("--" + move(long_opt));
return on<string>().when(_x1.in(move(opt_strs)));
}
function<void()> print_desc(options_description* desc, ostream& out) {
return [&out, desc] {
if (!desc) return;
for (auto& opt_group : *desc) {
out << opt_group.first << ":\n";
for (auto& opt : opt_group.second) {
out << " ";
out << std::setw(40) << left;
ostringstream tmp;
auto& names = opt.first;
if (names.first != '\0') {
tmp << "-" << names.first << " <arg> | ";
}
tmp << "--" << names.second << " <arg>";
out << tmp.str() << opt.second << "\n";
}
out << "\n";
}
};
}
function<void()> print_desc_and_exit(options_description* desc,
ostream& out,
int exit_reason) {
auto fun = print_desc(desc, out);
return [=] {
fun();
exit(exit_reason);
};
}
} // namespace cppa
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment