* implemented member parser (to store parameters in suitable configuration objects)master
@@ -1,6 +1,5 @@ | |||
#pragma once | |||
#include "cppargs/option.h" | |||
#include "cppargs/parser.h" | |||
#include "cppargs/option.inl" | |||
#include <cppargs/misc.h> | |||
#include <cppargs/options.h> | |||
#include <cppargs/parser.h> |
@@ -0,0 +1,9 @@ | |||
#pragma once | |||
#include <cppargs/group/group.h> | |||
#include <cppargs/group/simple_group.h> | |||
#include <cppargs/group/member_group.h> | |||
#include <cppargs/group/group.inl> | |||
#include <cppargs/group/simple_group.inl> | |||
#include <cppargs/group/member_group.inl> |
@@ -0,0 +1,68 @@ | |||
#pragma once | |||
#include <memory> | |||
#include <vector> | |||
#include <cppargs/options/option.h> | |||
namespace cppargs | |||
{ | |||
/** | |||
* @brief Struct to collect group meta data. | |||
*/ | |||
struct group_meta | |||
{ | |||
const std::string name { "" }; //!< Name of the group. | |||
const std::string description { "" }; //!< Description of the group. | |||
}; | |||
/** | |||
* @brief Struct to manage options and subgroups. | |||
*/ | |||
struct group | |||
{ | |||
public: | |||
using option_type = option; | |||
using option_ptr_type = std::unique_ptr<option_type>; | |||
using option_vector_type = std::vector<option_ptr_type>; | |||
using group_type = group; | |||
using group_ptr_type = std::unique_ptr<group_type>; | |||
using group_vector_type = std::vector<group_ptr_type>; | |||
public: | |||
friend struct parser; | |||
const group_meta meta; | |||
protected: | |||
option_vector_type _options; | |||
group_vector_type _groups; | |||
private: | |||
inline group(const group&) = delete; | |||
public: | |||
/** | |||
* @brief Constructor. | |||
* | |||
* @param[in] p_meta Meta data of the group. | |||
* @param[in] p_args Sub groups and options. | |||
*/ | |||
template<typename... T_args> | |||
inline group( | |||
const group_meta& p_meta, | |||
T_args&&... p_args); | |||
/** | |||
* @brief Move constructor. | |||
*/ | |||
inline group(group&&) = default; | |||
/** | |||
* @brief Destructor. | |||
*/ | |||
virtual ~group() = default; | |||
}; | |||
} |
@@ -0,0 +1,58 @@ | |||
#pragma once | |||
#include <cpputils/mp.h> | |||
#include "group.h" | |||
namespace cppargs | |||
{ | |||
template<typename T_arg, typename T_enable = void> | |||
struct group_init; | |||
template<typename T_arg> | |||
struct group_init< | |||
std::unique_ptr<T_arg>, | |||
utl::mp::enable_if<utl::mp::is_base_of<option, T_arg>>> | |||
{ | |||
using option_ptr_type = std::unique_ptr<option>; | |||
using option_vector_type = std::vector<option_ptr_type>; | |||
using group_ptr_type = std::unique_ptr<group>; | |||
using group_vector_type = std::vector<group_ptr_type>; | |||
option_vector_type& options; | |||
group_vector_type& groups; | |||
template<typename X> | |||
void operator()(X&& x) | |||
{ options.emplace_back(std::forward<X>(x)); } | |||
}; | |||
template<typename T_arg> | |||
struct group_init< | |||
std::unique_ptr<T_arg>, | |||
utl::mp::enable_if<utl::mp::is_base_of<group, T_arg>>> | |||
{ | |||
using option_ptr_type = std::unique_ptr<option>; | |||
using option_vector_type = std::vector<option_ptr_type>; | |||
using group_ptr_type = std::unique_ptr<group>; | |||
using group_vector_type = std::vector<group_ptr_type>; | |||
option_vector_type& options; | |||
group_vector_type& groups; | |||
template<typename X> | |||
void operator()(X&& x) | |||
{ groups.emplace_back(std::forward<X>(x)); } | |||
}; | |||
template<typename... T_args> | |||
group::group( | |||
const group_meta& p_meta, | |||
T_args&&... p_args) | |||
: meta(p_meta) | |||
{ | |||
(void) (int[]) { 0, (group_init<T_args> { _options, _groups } (std::forward<T_args>(p_args)), 0)... }; | |||
} | |||
} |
@@ -0,0 +1,102 @@ | |||
#pragma once | |||
#include <cppargs/group/group.h> | |||
#include <cppargs/options/member/member_option.h> | |||
namespace cppargs | |||
{ | |||
/** | |||
* @brief Member group that is owned by other groups. | |||
*/ | |||
template<typename T_instance> | |||
struct member_owned_group | |||
{ | |||
public: | |||
using instance_type = T_instance; | |||
using owner_type = instance_owner<instance_type>; | |||
template<typename, typename, typename> | |||
friend struct member_group; | |||
protected: | |||
owner_type* _owner { nullptr }; | |||
public: | |||
/** | |||
* @brief Destructor. | |||
*/ | |||
virtual ~member_owned_group() = default; | |||
}; | |||
/** | |||
* @brief Member group that is owner of of other groups and options. | |||
*/ | |||
template<typename T_instance> | |||
struct member_owner_group | |||
: public instance_owner<T_instance> | |||
{ | |||
public: | |||
using instance_type = T_instance; | |||
/** | |||
* @brief Get the instance of current parsed object. | |||
*/ | |||
virtual instance_type* instance() const override | |||
{ return nullptr; } | |||
/** | |||
* @brief Destructor. | |||
*/ | |||
virtual ~member_owner_group() = default; | |||
}; | |||
/** | |||
* @brief Member group that stores subgroups and options. | |||
*/ | |||
template< | |||
typename T_owner_instance, | |||
typename T_my_instance, | |||
typename T_resolve_instance_pred> | |||
struct member_group | |||
: public group | |||
, public member_owned_group<T_owner_instance> | |||
, public member_owner_group<T_my_instance> | |||
{ | |||
public: | |||
using owner_instance_type = T_owner_instance; | |||
using my_instance_type = T_my_instance; | |||
using resolve_instance_pred_type = T_resolve_instance_pred; | |||
using my_owned_group_type = member_owned_group<owner_instance_type>; | |||
using sub_owned_group_type = member_owned_group<my_instance_type>; | |||
using owner_group_type = member_owner_group<my_instance_type>; | |||
using member_option_type = member_option<my_instance_type>; | |||
private: | |||
resolve_instance_pred_type _predicate; | |||
public: | |||
/** | |||
* @brief Constructor. | |||
* | |||
* @param[in] p_meta Meta data of the group. | |||
* @param[in] p_args Sub groups and options. | |||
*/ | |||
template<typename... T_args> | |||
inline member_group( | |||
const group_meta& p_meta, | |||
resolve_instance_pred_type&& p_pred, | |||
T_args&&... p_args); | |||
/** | |||
* @brief Destructor. | |||
*/ | |||
virtual ~member_group() = default; | |||
/** | |||
* @brief Get the instance of current parsed object. | |||
*/ | |||
virtual my_instance_type* instance() const override; | |||
}; | |||
} |
@@ -0,0 +1,53 @@ | |||
#pragma once | |||
#include <cppargs/group/member_group.h> | |||
namespace cppargs | |||
{ | |||
template< | |||
typename T_owner_instance, | |||
typename T_my_instance, | |||
typename T_resolve_instance_pred> | |||
template< | |||
typename... T_args> | |||
member_group<T_owner_instance, T_my_instance, T_resolve_instance_pred> | |||
::member_group( | |||
const group_meta& p_meta, | |||
resolve_instance_pred_type&& p_pred, | |||
T_args&&... p_args) | |||
: group (p_meta, std::forward<T_args>(p_args)...) | |||
, _predicate(p_pred) | |||
{ | |||
for (auto& o : _options) | |||
{ | |||
auto* x = dynamic_cast<member_option_type*>(o.get()); | |||
if (!x) | |||
throw std::runtime_error("option of member group is not a suitable member option"); | |||
x->_owner = this; | |||
} | |||
for (auto& g : _groups) | |||
{ | |||
auto* x = dynamic_cast<sub_owned_group_type*>(g.get()); | |||
if (!x) | |||
throw std::runtime_error("group of member group is not a suitable member group"); | |||
x->_owner = this; | |||
} | |||
} | |||
template< | |||
typename T_owner_instance, | |||
typename T_my_instance, | |||
typename T_resolve_instance_pred> | |||
T_my_instance* member_group<T_owner_instance, T_my_instance, T_resolve_instance_pred> | |||
::instance() const | |||
{ | |||
T_owner_instance * owner_inst = nullptr; | |||
if (this->_owner) | |||
owner_inst = this->_owner->instance(); | |||
auto* ret = _predicate(owner_inst); | |||
return ret; | |||
} | |||
} |
@@ -0,0 +1,28 @@ | |||
#pragma once | |||
#include <cppargs/group/group.h> | |||
namespace cppargs | |||
{ | |||
struct simple_group | |||
: public group | |||
{ | |||
private: | |||
template<typename T_arg> | |||
using simple_verify_and_forward = verify_and_forward<simple_group, simple_option, T_arg>; | |||
public: | |||
/** | |||
* @brief Constructor. | |||
* | |||
* @param[in] p_meta Meta data of the group. | |||
* @param[in] p_args Sub groups and options. | |||
*/ | |||
template<typename... T_args> | |||
inline simple_group( | |||
const group_meta& p_meta, | |||
T_args&&... p_args); | |||
}; | |||
} |
@@ -0,0 +1,15 @@ | |||
#pragma once | |||
#include <cppargs/group/simple_group.h> | |||
namespace cppargs | |||
{ | |||
template<typename... T_args> | |||
simple_group::simple_group( | |||
const group_meta& p_meta, | |||
T_args&&... p_args) | |||
: group(p_meta, simple_verify_and_forward<T_args> { } (std::forward<T_args>(p_args))...) | |||
{ } | |||
} |
@@ -0,0 +1,7 @@ | |||
#pragma once | |||
#include <cppargs/misc/context.h> | |||
#include <cppargs/misc/option_parser.h> | |||
#include <cppargs/misc/context.inl> | |||
#include <cppargs/misc/option_parser.inl> |
@@ -0,0 +1,34 @@ | |||
#pragma once | |||
#include <string> | |||
#include <cstring> | |||
namespace cppargs | |||
{ | |||
enum class next_result | |||
{ | |||
finished = 0, //!< context does not have any further arguments | |||
option_short = 1, //!< moving to next argument was successfull (argument starts with - or --) | |||
option_long = 2, //!< moving to next argument was successfull (argument starts with - or --) | |||
argument = 3, //!< moving to next argument was successfull (argument does not starts with - or --) | |||
}; | |||
struct context | |||
{ | |||
int argc; | |||
char const * const * argv; | |||
char const * exe; | |||
char const * arg { nullptr }; | |||
char const * value { nullptr }; | |||
int index { 0 }; | |||
/** | |||
* @brief Move to the next argument | |||
* | |||
* @param[out] key key of the next argument | |||
*/ | |||
inline next_result next(std::string* key = nullptr); | |||
}; | |||
} |
@@ -0,0 +1,56 @@ | |||
#pragma once | |||
#include "context.h" | |||
namespace cppargs | |||
{ | |||
next_result context::next(std::string* key) | |||
{ | |||
if (key) | |||
key->clear(); | |||
if (index + 1 >= argc) | |||
return next_result::finished; | |||
++index; | |||
arg = argv[index]; | |||
value = nullptr; | |||
/* check argument */ | |||
int i = 0; | |||
value = nullptr; | |||
while (arg[i] == '-') | |||
++i; | |||
/* parse value */ | |||
if (i == 1) | |||
{ | |||
if (key) | |||
*key = std::string("-") + arg[1]; | |||
if (arg[2] != '\0') | |||
value = &arg[2]; | |||
return next_result::option_short; | |||
} | |||
else if (i == 2) | |||
{ | |||
auto tmp = strchr(arg, '='); | |||
if (tmp) | |||
{ | |||
value = tmp + 1; | |||
if (key) | |||
*key = std::string(arg, static_cast<size_t>(tmp - arg)); | |||
} | |||
else if (key) | |||
{ | |||
*key = arg; | |||
} | |||
return next_result::option_long; | |||
} | |||
else | |||
{ | |||
return next_result::argument; | |||
} | |||
} | |||
} |
@@ -0,0 +1,44 @@ | |||
#pragma once | |||
#include <cpputils/mp.h> | |||
namespace cppargs | |||
{ | |||
template<typename T_group, typename T_option, typename T_arg> | |||
struct verify_and_forward | |||
{ | |||
template<typename T, typename T_enable = void> | |||
struct check | |||
{ | |||
template<typename X> | |||
constexpr X&& operator()(X&& x) const | |||
{ static_assert(sizeof(X) == -1, "invalid group or option type"); } | |||
}; | |||
template<typename T> | |||
struct check< | |||
T, | |||
utl::mp::enable_if<utl::mp::is_base_of<T_group, T>>> | |||
{ | |||
template<typename X> | |||
constexpr X&& operator()(X&& x) const | |||
{ return std::forward<X>(x); } | |||
}; | |||
template<typename T> | |||
struct check< | |||
std::unique_ptr<T>, | |||
utl::mp::enable_if<utl::mp::is_base_of<T_option, T>>> | |||
{ | |||
template<typename X> | |||
constexpr X&& operator()(X&& x) const | |||
{ return std::forward<X>(x); } | |||
}; | |||
template<typename X> | |||
constexpr decltype(auto) operator()(X&& x) const | |||
{ return check<T_arg> { } (std::forward<X>(x)); } | |||
}; | |||
} |
@@ -0,0 +1,17 @@ | |||
#pragma once | |||
#include <cppargs/misc/context.h> | |||
namespace cppargs | |||
{ | |||
template<typename T_value> | |||
struct option_parser | |||
{ | |||
cppargs::context& context; | |||
T_value& value; | |||
inline void operator()() const; | |||
}; | |||
} |
@@ -0,0 +1,167 @@ | |||
#pragma once | |||
#include <list> | |||
#include <vector> | |||
#include <cpputils/misc/string.h> | |||
#include <cppargs/misc/option_parser.h> | |||
namespace cppargs | |||
{ | |||
template<typename T_derived, typename T_value> | |||
struct option_parser_list_impl; | |||
template<typename T_value> | |||
void option_parser<T_value>::operator()() const | |||
{ | |||
auto arg = context.arg; | |||
auto str = context.value; | |||
if (!str) | |||
{ | |||
auto ret = context.next(); | |||
if (ret != next_result::argument) | |||
throw std::runtime_error(std::string("expected one argument (option=") + arg + ")"); | |||
str = context.arg; | |||
} | |||
if (!utl::try_from_string(str, value)) | |||
throw std::runtime_error(std::string("unable to parse option argument (option=") + arg + "; value=" + str + ")"); | |||
} | |||
template<> | |||
struct option_parser<bool> | |||
{ | |||
cppargs::context& context; | |||
bool& value; | |||
inline void operator()() const | |||
{ | |||
value = true; | |||
auto arg = context.arg; | |||
auto str = context.value; | |||
if (!str) | |||
{ | |||
auto next_context = context; | |||
auto ret = next_context.next(); | |||
if (ret == next_result::argument) | |||
{ | |||
context = next_context; | |||
str = context.arg; | |||
} | |||
} | |||
if (str && !utl::try_from_string(str, value)) | |||
throw std::runtime_error(std::string("unable to parse option argument (option=") + arg + "; value=" + str + ")"); | |||
} | |||
}; | |||
template<typename T_value> | |||
struct option_parser<std::vector<T_value>> | |||
: public option_parser_list_impl< | |||
option_parser<std::vector<T_value>>, T_value> | |||
{ | |||
using value_type = T_value; | |||
using vector_type = std::vector<value_type>; | |||
using this_type = option_parser<vector_type>; | |||
using base_type = option_parser_list_impl<this_type, value_type>; | |||
cppargs::context& context; | |||
vector_type& value; | |||
inline option_parser( | |||
cppargs::context& p_context, | |||
vector_type& p_value) | |||
: base_type (*this) | |||
, context (p_context) | |||
, value (p_value) | |||
{ } | |||
template<typename X> | |||
inline void emplace(X&& x) | |||
{ value.emplace_back(std::forward<X>(x)); } | |||
}; | |||
template<typename T_value> | |||
struct option_parser<std::list<T_value>> | |||
: public option_parser_list_impl< | |||
option_parser<std::list<T_value>>, T_value> | |||
{ | |||
using value_type = T_value; | |||
using list_type = std::list<value_type>; | |||
using this_type = option_parser<list_type>; | |||
using base_type = option_parser_list_impl<this_type, value_type>; | |||
cppargs::context& context; | |||
list_type& value; | |||
inline option_parser( | |||
cppargs::context& p_context, | |||
list_type& p_value) | |||
: base_type (*this) | |||
, context (p_context) | |||
, value (p_value) | |||
{ } | |||
template<typename X> | |||
inline void emplace(X&& x) | |||
{ value.emplace_back(std::forward<X>(x)); } | |||
}; | |||
template<typename T_derived, typename T_value> | |||
struct option_parser_list_impl | |||
{ | |||
using derived_type = T_derived; | |||
using value_type = T_value; | |||
derived_type& derived; | |||
inline option_parser_list_impl( | |||
derived_type& p_derived) | |||
: derived(p_derived) | |||
{ } | |||
inline void operator()() const | |||
{ | |||
auto arg = derived.context.arg; | |||
auto index = derived.context.index; | |||
if (derived.context.value) | |||
{ | |||
const char * s = derived.context.value; | |||
const char * e = s - 1; | |||
do | |||
{ | |||
++e; | |||
if ( s != e | |||
&& ( *e == ',' | |||
|| *e == '\0')) | |||
{ | |||
value_type tmp; | |||
std::string str(s, static_cast<size_t>(e - s)); | |||
s = e + 1; | |||
if (!utl::try_from_string(str, tmp)) | |||
throw std::runtime_error(std::string("unable to parse option argument (option=") + arg + "; value=" + s + ")"); | |||
derived.emplace(std::move(tmp)); | |||
} | |||
} | |||
while(*e != '\0'); | |||
} | |||
else | |||
{ | |||
auto new_context = derived.context; | |||
while (new_context.next() == next_result::argument) | |||
{ | |||
value_type tmp; | |||
if (!utl::try_from_string(new_context.arg, tmp)) | |||
throw std::runtime_error(std::string("unable to parse option argument (option=") + arg + "; value=" + new_context.arg + ")"); | |||
derived.emplace(std::move(tmp)); | |||
derived.context = new_context; | |||
} | |||
if (derived.context.index == index) | |||
throw std::runtime_error(std::string("expected at least one argument (option=") + arg + ")"); | |||
} | |||
} | |||
}; | |||
} |
@@ -1,161 +0,0 @@ | |||
#pragma once | |||
#include <string> | |||
namespace cppargs | |||
{ | |||
enum class next_result | |||
{ | |||
finished = 0, //!< context does not have any further arguments | |||
option_short = 1, //!< moving to next argument was successfull (argument starts with - or --) | |||
option_long = 2, //!< moving to next argument was successfull (argument starts with - or --) | |||
argument = 3, //!< moving to next argument was successfull (argument does not starts with - or --) | |||
}; | |||
struct context | |||
{ | |||
int const argc; | |||
char const * const * const argv; | |||
char const * const exe; | |||
char const * arg { nullptr }; | |||
char const * value { nullptr }; | |||
int index { 0 }; | |||
inline next_result next(std::string* key = nullptr) | |||
{ | |||
if (key) | |||
key->clear(); | |||
if (index + 1 >= argc) | |||
return next_result::finished; | |||
++index; | |||
arg = argv[index]; | |||
value = nullptr; | |||
/* check argument */ | |||
int i = 0; | |||
value = nullptr; | |||
while (arg[i] == '-') | |||
++i; | |||
/* parse value */ | |||
if (i == 1) | |||
{ | |||
if (key) | |||
*key = std::string("-") + arg[1]; | |||
if (arg[2] != '\0') | |||
value = &arg[2]; | |||
return next_result::option_short; | |||
} | |||
else if (i == 2) | |||
{ | |||
auto tmp = strchr(arg, '='); | |||
if (tmp) | |||
{ | |||
value = tmp + 1; | |||
if (key) | |||
*key = std::string(arg, static_cast<size_t>(tmp - arg - 1)); | |||
} | |||
else if (key) | |||
{ | |||
*key = arg; | |||
} | |||
return next_result::option_long; | |||
} | |||
else | |||
{ | |||
return next_result::argument; | |||
} | |||
} | |||
}; | |||
struct option | |||
{ | |||
public: | |||
const std::string long_name; | |||
const char short_name; | |||
public: | |||
inline option( | |||
const std::string& p_long_name, | |||
const char p_short_name); | |||
virtual ~option() = default; | |||
virtual void parse(context& c) = 0; | |||
}; | |||
template<typename T_predicate> | |||
struct predicate_option | |||
: public option | |||
{ | |||
public: | |||
using predicate_type = T_predicate; | |||
private: | |||
predicate_type _predicate; | |||
public: | |||
template<typename... T_args> | |||
inline predicate_option( | |||
const std::string& p_long_name, | |||
const char p_short_name, | |||
T_args&&... args); | |||
virtual void parse(context& c) override; | |||
}; | |||
template<typename T_value> | |||
struct reference_option | |||
: public option | |||
{ | |||
public: | |||
using value_type = T_value; | |||
private: | |||
value_type& _value; | |||
public: | |||
inline reference_option( | |||
const std::string& p_long_name, | |||
const char p_short_name, | |||
value_type& p_value) | |||
: option(p_long_name, p_short_name) | |||
, _value(p_value) | |||
{ } | |||
virtual void parse(context& c) override | |||
{ | |||
auto old = c; | |||
auto value = c.value; | |||
if (!value) | |||
{ | |||
auto ret = c.next(); | |||
if (ret != next_result::argument) | |||
throw std::runtime_error(std::string("option ") + old.arg + " expected one argument"); | |||
value = c.arg; | |||
} | |||
std::cout << value << std::endl; | |||
} | |||
}; | |||
template<typename T_predicate> | |||
constexpr decltype(auto) make_predicate_option(const std::string& long_name, char short_name, T_predicate&& predicate) | |||
{ | |||
using predicate_type = T_predicate; | |||
using predicate_option_type = predicate_option<predicate_type>; | |||
return std::make_unique<predicate_option_type>(long_name, short_name, std::forward<predicate_type>(predicate)); | |||
} | |||
template<typename T_value> | |||
constexpr decltype(auto) make_reference_option(const std::string& long_name, char short_name, T_value& value) | |||
{ | |||
using value_type = T_value; | |||
using reference_option_type = reference_option<value_type>; | |||
return std::make_unique<reference_option_type>(long_name, short_name, value); | |||
} | |||
} |
@@ -1,33 +0,0 @@ | |||
#pragma once | |||
#include "option.h" | |||
namespace cppargs | |||
{ | |||
/* option */ | |||
option::option( | |||
const std::string& p_long_name, | |||
const char p_short_name) | |||
: long_name (p_long_name) | |||
, short_name(p_short_name) | |||
{ } | |||
/* predicate_option */ | |||
template<typename T_predicate> | |||
template<typename... T_args> | |||
predicate_option<T_predicate>::predicate_option( | |||
const std::string& p_long_name, | |||
const char p_short_name, | |||
T_args&&... args) | |||
: option(p_long_name, p_short_name) | |||
, _predicate(std::forward<T_args>(args)...) | |||
{ } | |||
template<typename T_predicate> | |||
void predicate_option<T_predicate>::parse(context& c) | |||
{ _predicate(c); } | |||
} |
@@ -0,0 +1,6 @@ | |||
#pragma once | |||
#include <cppargs/options/option.h> | |||
#include <cppargs/options/simple.h> | |||
#include <cppargs/options/option.inl> |
@@ -0,0 +1,7 @@ | |||
#pragma once | |||
#include <cppargs/options/member/member_option.h> | |||
#include <cppargs/options/member/member_predicate_option.h> | |||
#include <cppargs/options/member/member_option.inl> | |||
#include <cppargs/options/member/member_predicate_option.inl> |
@@ -0,0 +1,40 @@ | |||
#pragma once | |||
#include <cppargs/options/option.h> | |||
namespace cppargs | |||
{ | |||
template<typename T_instance> | |||
struct instance_owner | |||
{ | |||
virtual T_instance* instance() const = 0; | |||
}; | |||
template<typename T_instance> | |||
struct member_option | |||
: public option | |||
{ | |||
public: | |||
using base_type = option; | |||
using instance_type = T_instance; | |||
using owner_type = instance_owner<instance_type>; | |||
private: | |||
template<typename X, typename Y, typename Z> | |||
friend struct member_group; | |||
owner_type* _owner; | |||
public: | |||
using option::option; | |||
protected: | |||
/** | |||
* @brief Get the current instance of the object to parse. | |||
* | |||
* @return Current instance of the object to parse. | |||
*/ | |||
inline instance_type& instance() const; | |||
}; | |||
} |
@@ -0,0 +1,19 @@ | |||
#pragma once | |||
#include <cppargs/options/member/member_option.h> | |||
namespace cppargs | |||
{ | |||
template<typename T_instance> | |||
T_instance& member_option<T_instance>::instance() const | |||
{ | |||
if (!_owner) | |||
throw std::runtime_error("option has no owner assigned"); | |||
auto* ret = _owner->instance(); | |||
if (!ret) | |||
throw std::runtime_error("option has no instance assigned"); | |||
return *ret; | |||
} | |||
} |
@@ -0,0 +1,41 @@ | |||
#pragma once | |||
#include <cppargs/options/member/member_option.h> | |||
namespace cppargs | |||
{ | |||
template<typename T_instance, typename T_value, typename T_predicate> | |||
struct member_predicate_option | |||
: public member_option<T_instance> | |||
{ | |||
public: | |||
using instance_type = T_instance; | |||
using value_type = T_value; | |||
using predicate_type = T_predicate; | |||
using base_type = member_option<instance_type>; | |||
private: | |||
predicate_type _predicate; | |||
public: | |||
/** | |||
* @brief Constructor. | |||
* | |||
* @param[in] p_meta Meta data of the option. | |||
* @param[in] args Arguments to pass to the predicate constructor. | |||
*/ | |||
template<typename... T_args> | |||
inline member_predicate_option( | |||
const option_meta& p_meta, | |||
T_args&&... args); | |||
/** | |||
* @brief Parse the option using the current context. | |||
* | |||
* @param[in|out] c Context to use for parsing. | |||
*/ | |||
virtual void parse(context& c) const override; | |||
}; | |||
} |
@@ -0,0 +1,21 @@ | |||
#pragma once | |||
#include <cppargs/options/member/member_predicate_option.h> | |||
namespace cppargs | |||
{ | |||
template<typename T_instance, typename T_value, typename T_predicate> | |||
template<typename... T_args> | |||
member_predicate_option<T_instance, T_value, T_predicate>::member_predicate_option( | |||
const option_meta& p_meta, | |||
T_args&&... args) | |||
: base_type (p_meta) | |||
, _predicate(std::forward<T_args>(args)...) | |||
{ } | |||
template<typename T_instance, typename T_value, typename T_predicate> | |||
void member_predicate_option<T_instance, T_value, T_predicate>::parse(context& c) const | |||
{ _predicate(this->instance(), c); } | |||
} |
@@ -0,0 +1,52 @@ | |||
#pragma once | |||
#include <string> | |||
#include <cppargs/misc/context.h> | |||
namespace cppargs | |||
{ | |||
/** | |||
* @brief Class to store all meta data for a option. | |||
*/ | |||
struct option_meta | |||
{ | |||
const std::string long_name { "" }; //!< long name of the option (without the prepending --) | |||
const char short_name { '\0' }; //!< short option of the option (without the prependding -) | |||
const std::string description { "" }; //!< description for this option | |||
const std::string default_value { "" }; //!< default value for this option | |||
const bool optional { true }; //!< TRUE if this option is optional, FALSE otherwise | |||
}; | |||
/** | |||
* @brief Option to parse from command line arguments | |||
*/ | |||
struct option | |||
{ | |||
public: | |||
const option_meta meta; //!< meta data of the option | |||
protected: | |||
/** | |||
* @brief Constructor. | |||
* | |||
* @param[in] p_long_name Long name of the option. | |||
* @param[in] p_short_name Short name of the option. | |||
*/ | |||
inline option(const option_meta& meta); | |||
public: | |||
/** | |||
* @brief Destructor. | |||
*/ | |||
virtual ~option() = default; | |||
/** | |||
* @brief Parse the option using the current context. | |||
* | |||
* @param[in|out] c Context to use for parsing. | |||
*/ | |||
virtual void parse(context& c) const = 0; | |||
}; | |||
} |
@@ -0,0 +1,12 @@ | |||
#pragma once | |||
#include "option.h" | |||
namespace cppargs | |||
{ | |||
option::option(const option_meta& p_meta) | |||
: meta(p_meta) | |||
{ } | |||
} |
@@ -0,0 +1,6 @@ | |||
#pragma once | |||
#include <cppargs/options/simple/simple_option.h> | |||
#include <cppargs/options/simple/simple_predicate_option.h> | |||
#include <cppargs/options/simple/simple_predicate_option.inl> |
@@ -0,0 +1,14 @@ | |||
#pragma once | |||
#include <cppargs/options/option.h> | |||
namespace cppargs | |||
{ | |||
struct simple_option | |||
: public option | |||
{ | |||
using option::option; | |||
}; | |||
} |
@@ -0,0 +1,42 @@ | |||
#pragma once | |||
#include <string> | |||
#include <cppargs/options/simple/simple_option.h> | |||
namespace cppargs | |||
{ | |||
/** | |||
* @brief Specialized option using a predicate to parse the argument. | |||
*/ | |||
template<typename T_predicate> | |||
struct simple_predicate_option | |||
: public simple_option | |||
{ | |||
public: | |||
using predicate_type = T_predicate; | |||
private: | |||
predicate_type _predicate; | |||
public: | |||
/** | |||
* @brief Constructor. | |||
* | |||
* @param[in] p_meta Meta data of the option. | |||
* @param[in] args Arguments to pass to the predicate constructor. | |||
*/ | |||
template<typename... T_args> | |||
inline simple_predicate_option( | |||
const option_meta& p_meta, | |||
T_args&&... args); | |||
/** | |||
* @brief Parse the current argument. | |||
* | |||
* @param[in|out] c Context of the current argument. | |||
*/ | |||
virtual void parse(context& c) const override; | |||
}; | |||
} |
@@ -0,0 +1,21 @@ | |||
#pragma once | |||
#include "simple_predicate_option.h" | |||
namespace cppargs | |||
{ | |||
template<typename T_predicate> | |||
template<typename... T_args> | |||
simple_predicate_option<T_predicate>::simple_predicate_option( | |||
const option_meta& p_meta, | |||
T_args&&... args) | |||
: simple_option(p_meta) | |||
, _predicate(std::forward<T_args>(args)...) | |||
{ } | |||
template<typename T_predicate> | |||
void simple_predicate_option<T_predicate>::parse(context& c) const | |||
{ _predicate(c); } | |||
} |
@@ -1,96 +1,9 @@ | |||
#pragma once | |||
#include <map> | |||
#include <vector> | |||
#include <memory> | |||
#include <cstring> | |||
#include <cppargs/parser/parser.h> | |||
#include <cppargs/parser/simple_parser.h> | |||
#include <cppargs/parser/member_parser.h> | |||
#include "option.h" | |||
namespace cppargs | |||
{ | |||
struct parser | |||
{ | |||
private: | |||
using option_ptr_type = std::unique_ptr<option>; | |||
using option_vector_type = std::vector<option_ptr_type>; | |||
using option_map_type = std::map<std::string, option*>; | |||
private: | |||
option_ptr_type _default; | |||
option_vector_type _options; | |||
option_map_type _map; | |||
inline void update_map() | |||
{ | |||
_map.clear(); | |||
for (auto& o : _options) | |||
{ | |||
if (!o) | |||
throw std::runtime_error("expectd option to not be null!"); | |||
if (o->short_name) | |||
_map.emplace(std::string("-") + o->short_name, o.get()); | |||
if (!o->long_name.empty()) | |||
_map.emplace(std::string("--") + o->long_name, o.get()); | |||
} | |||
} | |||
inline void handle_invalid_arg(context& c) const | |||
{ | |||
if (_default) | |||
{ | |||
_default->parse(c); | |||
} | |||
else | |||
{ | |||
throw std::runtime_error(std::string("invalid or unknown argument: ") + c.arg); | |||
} | |||
} | |||
public: | |||
template<typename... T_option> | |||
inline parser(option_ptr_type&& default_option, T_option&&... option) | |||
: _default(std::move(default_option)) | |||
{ | |||
(void) (int[]) { 0, (_options.emplace_back(std::forward<T_option>(option)), 0)... }; | |||
update_map(); | |||
} | |||
void parse(int argc, char const * argv[]) const | |||
{ | |||
if (argc <= 0) { | |||
return; | |||
} | |||
context c | |||
{ | |||
argc, | |||
argv, | |||
argv[0], | |||
}; | |||
next_result ret; | |||
std::string key; | |||
while ((ret = c.next(&key)) != next_result::finished) | |||
{ | |||
/* move to next option */ | |||
if ( ret != next_result::option_short | |||
&& ret != next_result::option_long) | |||
handle_invalid_arg(c); | |||
/* find option */ | |||
auto it = _map.find(key); | |||
if (it == _map.end()) | |||
{ | |||
handle_invalid_arg(c); | |||
} | |||
else | |||
{ | |||
it->second->parse(c); | |||
} | |||
} | |||
} | |||
}; | |||
} | |||
#include <cppargs/parser/parser.inl> | |||
#include <cppargs/parser/simple_parser.inl> | |||
#include <cppargs/parser/member_parser.inl> |
@@ -0,0 +1,100 @@ | |||
#pragma once | |||
#include <cppargs/parser/parser.h> | |||
#include <cppargs/group/member_group.h> | |||
namespace cppargs | |||
{ | |||
struct member_parser_base | |||
: public parser | |||
{ | |||
public: | |||
using parser::parser; | |||
public: | |||
/** | |||
* @brief Create new member option. | |||
* | |||
* @param[in] meta Meta data of the new option. | |||
* @param[in] member Member to write parsed argument to. | |||
* | |||
* @return Created option. | |||
*/ | |||
template<typename T_instance, typename T_object, typename T_value> | |||
static constexpr decltype(auto) make_member_option(const option_meta& meta, T_value T_object::*member); | |||
/** | |||
* @brief Create new group. | |||
* | |||
* @param[in] meta Meta data of the new option. | |||
* @param[in] member Member of current instance to use for this group. | |||
* @param[in] args Subgroups and options. | |||
* | |||
* @return Created group. | |||
*/ | |||
template<typename T_instance, typename T_object, typename T_value, typename... T_args> | |||
static constexpr decltype(auto) make_member_group(const group_meta& meta, T_value T_object::*member, T_args&&... args); | |||
}; | |||
/** | |||
* @brief Class to parse options using a object to store values in. | |||
*/ | |||
template<typename T_instance> | |||
struct member_parser | |||
: public member_parser_base | |||
{ | |||
public: | |||
using base_type = member_parser_base; | |||
using instance_type = T_instance; | |||
using this_type = member_parser<instance_type>; | |||
using option_ptr_type = typename base_type::option_ptr_type; | |||
private: | |||
struct base_group_pred | |||
{ | |||
this_type& owner; | |||
instance_type* operator()(void*) const | |||
{ return owner._instance; } | |||
}; | |||
using base_group_type = member_group<void, instance_type, base_group_pred>; | |||
template<typename... T_args> | |||
constexpr decltype(auto) make_base_group(T_args&&... args) | |||
{ | |||
using owner_instance_type = void; | |||
using group_instance_type = T_instance; | |||
using predicate_type = base_group_pred; | |||
using group_type = member_group<owner_instance_type, group_instance_type, predicate_type>; | |||
return group_type({ }, predicate_type { *this }, std::forward<T_args>(args)...); | |||
} | |||
private: | |||
base_group_type _group; | |||
mutable instance_type* _instance { nullptr }; | |||
public: | |||
/** | |||
* @brief Constructor. | |||
* | |||
* @param[in] p_default Default option to use for unknown arguents (optional / can be null). | |||
* @param[in] p_args Options and subgroups. | |||
*/ | |||
template<typename... T_args> | |||
member_parser( | |||
option_ptr_type&& p_default, | |||
T_args&&... args); | |||
/** | |||
* @brief Parse the command line arguments using the passed options. | |||
* | |||
* @param[in] instance Instance to store parsed values in. | |||
* @param[in] argc Number of arguments in argv. | |||
* @param[in] argv Array of all arguments. | |||
*/ | |||
inline void parse(instance_type& instance, int argc, char const * argv[]) const; | |||
}; | |||
} |
@@ -0,0 +1,66 @@ | |||
#pragma once | |||
#include <cppargs/parser/parser.h> | |||
#include <cppargs/options/member.h> | |||
#include <cppargs/misc/option_parser.h> | |||
#include <cppargs/group/member_group.inl> | |||
namespace cppargs | |||
{ | |||
template<typename T_instance, typename T_object, typename T_value> | |||
constexpr decltype(auto) member_parser_base::make_member_option(const option_meta& meta, T_value T_object::*member) | |||
{ | |||
static_assert(std::is_base_of<T_object, T_instance>::value, "Member pointer must be in the instance type."); | |||
using instance_type = T_instance; | |||
using value_type = T_value; | |||
auto predicate = [member](instance_type& instance, context& c) | |||
{ | |||
using executor_type = option_parser<value_type>; | |||
executor_type { c, instance.*member } ( ); | |||
}; | |||
using predicate_type = decltype(predicate); | |||
using member_predicate_option_type = member_predicate_option<instance_type, value_type, predicate_type>; | |||
return std::make_unique<member_predicate_option_type>(meta, std::move(predicate)); | |||
} | |||
template<typename T_instance, typename T_object, typename T_value, typename... T_args> | |||
constexpr decltype(auto) member_parser_base::make_member_group(const group_meta& meta, T_value T_object::*member, T_args&&... args) | |||
{ | |||
using owner_instance_type = T_instance; | |||
using my_instance_type = T_value; | |||
auto predicate = [member](owner_instance_type* instance) | |||
{ | |||
if (!instance) | |||
throw std::runtime_error("unable to resolve instance for sub group: no instance assigned"); | |||
return &(instance->*member); | |||
}; | |||
using predicate_type = decltype(predicate); | |||
using group_type = member_group<owner_instance_type, my_instance_type, predicate_type>; | |||
return std::make_unique<group_type>(meta, std::move(predicate), std::forward<T_args>(args)...); | |||
} | |||
template<typename T_instance> | |||
template<typename... T_args> | |||
member_parser<T_instance>::member_parser( | |||
option_ptr_type&& p_default, | |||
T_args&&... args) | |||
: base_type (std::move(p_default), _group) | |||
, _group (make_base_group(std::forward<T_args>(args)...)) | |||
{ update_map(); } | |||
template<typename T_instance> | |||
void member_parser<T_instance>::parse(instance_type& instance, int argc, char const * argv[]) const | |||
{ | |||
auto lambda = [this]() { _instance = nullptr; }; | |||
auto cleanup = std::make_unique<decltype(lambda)>(std::move(lambda)); | |||
_instance = &instance; | |||
base_type::parse(argc, argv); | |||
} | |||
} |
@@ -0,0 +1,70 @@ | |||
#pragma once | |||
#include <map> | |||
#include <vector> | |||
#include <memory> | |||
#include <cstring> | |||
#include <cppargs/group/group.h> | |||
namespace cppargs | |||
{ | |||
/** | |||
* @brief Class to parse command line arguments. | |||
*/ | |||
struct parser | |||
{ | |||
public: | |||
using option_type = option; | |||
using option_ptr_type = std::unique_ptr<option_type>; | |||
using option_map_type = std::map<std::string, option_type*>; | |||
private: | |||
group& _group; | |||
option_ptr_type _default; //!< Default option to parse unknown arguments. | |||
option_map_type _map; //!< Map of option name to option. | |||
protected: | |||
/** | |||
* @brief Add the passed group to the options map | |||
*/ | |||
inline void add_to_map(const group& g); | |||
/** | |||
* @brief Update the option map. | |||
*/ | |||
inline void update_map(); | |||
/** | |||
* @brief Handle invalid argument (use default option or throw exception). | |||
*/ | |||
inline void handle_invalid_arg(context& c) const; | |||
/** | |||
* @brief Parse the command line arguments using the passed options. | |||
* | |||
* @param[in] argc Number of arguments in argv. | |||
* @param[in] argv Array of all arguments. | |||
*/ | |||
inline void parse(int argc, char const * argv[]) const; | |||
public: | |||
/** | |||
* @brief Constructor. | |||
* | |||
* @param[in] p_default Default option to use for unknown arguents (optional / can be null). | |||
* @param[in] p_group Group with options and subgroups. | |||
*/ | |||
inline parser( | |||
option_ptr_type&& p_default, | |||
group& p_group); | |||
/** | |||
* @brief Print the help of all options | |||
* | |||
* @param[in] os Stream to write help to. | |||
*/ | |||
void print_help(std::ostream& os) const; | |||
}; | |||
} |
@@ -0,0 +1,95 @@ | |||
#pragma once | |||
#include <cppargs/parser/parser.h> | |||
#include <cppargs/group/group.inl> | |||
namespace cppargs | |||
{ | |||
parser::parser( | |||
option_ptr_type&& p_default, | |||
group& p_group) | |||
: _default (std::move(p_default)) | |||
, _group (p_group) | |||
{ } | |||
void parser::add_to_map(const group& g) | |||
{ | |||
for (auto& o : g._options) | |||
{ | |||
if (!o) | |||
throw std::runtime_error("expectd option to not be null!"); | |||
if (o->meta.short_name) | |||
{ | |||
if (!_map.emplace(std::string("-") + o->meta.short_name, o.get()).second) | |||
throw std::runtime_error(std::string("duplicate option key: ") + o->meta.short_name); | |||
} | |||
if (!o->meta.long_name.empty()) | |||
{ | |||
if (!_map.emplace(std::string("--") + o->meta.long_name, o.get()).second) | |||
throw std::runtime_error(std::string("duplicate option key: ") + o->meta.long_name); | |||
} | |||
} | |||
for (auto& i : g._groups) | |||
{ | |||
if (!i) | |||
throw std::runtime_error("expectd group to not be null!"); | |||
add_to_map(*i); | |||
} | |||
} | |||
void parser::update_map() | |||
{ | |||
_map.clear(); | |||
add_to_map(_group); | |||
} | |||
void parser::handle_invalid_arg(context& c) const | |||
{ | |||
if (_default) | |||
{ | |||
_default->parse(c); | |||
} | |||
else | |||
{ | |||
throw std::runtime_error(std::string("invalid or unknown argument: ") + c.arg); | |||
} | |||
} | |||
void parser::parse(int argc, char const * argv[]) const | |||
{ | |||
if (argc <= 0) { | |||
return; | |||
} | |||
context c | |||
{ | |||
argc, | |||
argv, | |||
argv[0], | |||
}; | |||
next_result ret; | |||
std::string key; | |||
while ((ret = c.next(&key)) != next_result::finished) | |||
{ | |||
/* move to next option */ | |||
if ( ret != next_result::option_short | |||
&& ret != next_result::option_long) | |||
handle_invalid_arg(c); | |||
/* find option */ | |||
auto it = _map.find(key); | |||
if (it == _map.end()) | |||
{ | |||
handle_invalid_arg(c); | |||
} | |||
else | |||
{ | |||
it->second->parse(c); | |||
} | |||
} | |||
} | |||
} |
@@ -0,0 +1,78 @@ | |||
#pragma once | |||
#include <cppargs/misc/misc.h> | |||
#include <cppargs/parser/parser.h> | |||
#include <cppargs/group/simple_group.h> | |||
namespace cppargs | |||
{ | |||
/** | |||
* @brief Class to parse options using simple types or callbacks. | |||
*/ | |||
struct simple_parser | |||
: public parser | |||
{ | |||
public: | |||
using base_type = parser; | |||
using option_ptr_type = typename base_type::option_ptr_type; | |||
private: | |||
simple_group _group; | |||
public: | |||
/** | |||
* @brief Constructor. | |||
* | |||
* @param[in] p_default Default option to use for unknown arguents (optional / can be null). | |||
* @param[in] p_args Options and subgroups. | |||
*/ | |||
template<typename... T_args> | |||
simple_parser( | |||
option_ptr_type&& p_default, | |||
T_args&&... args); | |||
/** | |||
* @brief Parse the command line arguments using the passed options. | |||
* | |||
* @param[in] argc Number of arguments in argv. | |||
* @param[in] argv Array of all arguments. | |||
*/ | |||
inline void parse(int argc, char const * argv[]) const; | |||
public: | |||
/** | |||
* @brief Create new option group. | |||
* | |||
* @param[in] meta Meta data of the new group. | |||
* @param[in] args Subgroups and options. | |||
* | |||
* @return Created group. | |||
*/ | |||
template<typename... T_args> | |||
static constexpr decltype(auto) make_group(const group_meta& meta, T_args&&... args); | |||
/** | |||
* @brief Create new predicate option. | |||
* | |||
* @param[in] meta Meta data of the new option. | |||
* @param[in] predicate Predicate to execute for this option. | |||
* | |||
* @return Created option. | |||
*/ | |||
template<typename T_predicate> | |||
static constexpr decltype(auto) make_predicate_option(const option_meta& meta, T_predicate&& predicate); | |||
/** | |||
* @brief Create new reference option. | |||
* | |||
* @param[in] meta Meta data of the new option. | |||
* @param[in] value Value to set for this option. | |||
* | |||
* @return Created option. | |||
*/ | |||
template<typename T_value> | |||
static constexpr decltype(auto) make_reference_option(const option_meta& meta, T_value& value); | |||
}; | |||
} |
@@ -0,0 +1,51 @@ | |||
#pragma once | |||
#include <cpputils/mp.h> | |||
#include <cppargs/parser/parser.h> | |||
#include <cppargs/group/simple_group.inl> | |||
namespace cppargs | |||
{ | |||
template<typename... T_args> | |||
simple_parser::simple_parser( | |||
option_ptr_type&& p_default, | |||
T_args&&... args) | |||
: base_type (std::move(p_default), _group) | |||
, _group ({ }, std::forward<T_args>(args)...) | |||
{ update_map(); } | |||
void simple_parser::parse(int argc, char const * argv[]) const | |||
{ parser::parse(argc, argv); } | |||
template<typename... T_args> | |||
constexpr decltype(auto) simple_parser::make_group(const group_meta& meta, T_args&&... args) | |||
{ | |||
return std::make_unique<simple_group>(meta, std::forward<T_args>(args)...); | |||
} | |||
template<typename T_predicate> | |||
constexpr decltype(auto) simple_parser::make_predicate_option(const option_meta& meta, T_predicate&& predicate) | |||
{ | |||
using predicate_type = T_predicate; | |||
using simple_predicate_option_type = simple_predicate_option<predicate_type>; | |||
return std::make_unique<simple_predicate_option_type>(meta, std::forward<predicate_type>(predicate)); | |||
} | |||
template<typename T_value> | |||
constexpr decltype(auto) simple_parser::make_reference_option(const option_meta& meta, T_value& value) | |||
{ | |||
using value_type = T_value; | |||
auto predicate = [&value](context& c) | |||
{ | |||
using executor_type = option_parser<value_type>; | |||
executor_type { c, value } ( ); | |||
}; | |||
using predicate_type = decltype(predicate); | |||
using simple_predicate_option_type = simple_predicate_option<predicate_type>; | |||
return std::make_unique<simple_predicate_option_type>(meta, std::move(predicate)); | |||
} | |||
} |
@@ -8,11 +8,15 @@ Set ( CMAKE_CXX_STANDARD 17 ) | |||
# Project: cppargs ################################################################################ | |||
Find_Package ( cpputils REQUIRED ) | |||
Project ( cppargs VERSION 1.0.0.0 LANGUAGES CXX ) | |||
Set ( CPPARGS_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../include ) | |||
Add_Library ( cppargs INTERFACE ) | |||
Target_Include_Directories ( cppargs | |||
INTERFACE ${CPPARGS_INCLUDE_DIR} ) | |||
Target_Link_Libraries ( cppargs | |||
INTERFACE cpputils ) | |||
If ( HAS_PEDANTIC ) | |||
Pedantic_Apply_Flags ( ALL ) | |||
@@ -1,22 +0,0 @@ | |||
#include <gtest/gtest.h> | |||
#include <cppargs.h> | |||
TEST(cppargs, simple) | |||
{ | |||
int x; | |||
cppargs::parser p( | |||
nullptr, | |||
cppargs::make_reference_option("index", 'i', x), | |||
cppargs::make_predicate_option("test", 't', [](auto& c){ | |||
std::cout << c.arg << std::endl; | |||
}) | |||
); | |||
std::vector<const char*> args({ | |||
"/fuu/bar/exe", | |||
"-i", "6", | |||
"--test" | |||
}); | |||
p.parse(static_cast<int>(args.size()), args.data()); | |||
} |
@@ -0,0 +1,81 @@ | |||
#include <list> | |||
#include <vector> | |||
#include <gtest/gtest.h> | |||
#include <cppargs.h> | |||
struct simple | |||
{ | |||
int i; | |||
std::string s; | |||
double d; | |||
}; | |||
TEST(member_parser, simple_object) | |||
{ | |||
using parser = ::cppargs::member_parser<simple>; | |||
simple s; | |||
parser p( | |||
nullptr, | |||
parser::make_member_option<simple>({ "int", 'i' }, &simple::i), | |||
parser::make_member_option<simple>({ "string", 's' }, &simple::s), | |||
parser::make_member_option<simple>({ "double", 'd' }, &simple::d) | |||
); | |||
std::vector<const char*> args({ | |||
"/fuu/bar/exe", | |||
"-i", "123", | |||
"--string", "fuubar", | |||
"-d123.123" | |||
}); | |||
p.parse(s, static_cast<int>(args.size()), args.data()); | |||
EXPECT_EQ(s.i, 123); | |||
EXPECT_EQ(s.s, "fuubar"); | |||
EXPECT_EQ(s.d, 123.123); | |||
} | |||
struct grouped | |||
: public simple | |||
{ | |||
struct group1 | |||
{ | |||
std::list<std::string> list; | |||
std::vector<int> vec; | |||
}; | |||
group1 g1; | |||
}; | |||
TEST(member_parser, grouped_object) | |||
{ | |||
using parser = ::cppargs::member_parser<grouped>; | |||
grouped g; | |||
parser p( | |||
nullptr, | |||
parser::make_member_option<grouped>({ "int", 'i' }, &grouped::i), | |||
parser::make_member_option<grouped>({ "string", 's' }, &grouped::s), | |||
parser::make_member_option<grouped>({ "double", 'd' }, &grouped::d), | |||
parser::make_member_group<grouped> ({ }, &grouped::g1, | |||
parser::make_member_option<grouped::group1>({ "list", 'l' }, &grouped::group1::list), | |||
parser::make_member_option<grouped::group1>({ "vector", 'v' }, &grouped::group1::vec)) | |||
); | |||
std::vector<const char*> args({ | |||
"/fuu/bar/exe", | |||
"-i", "123", | |||
"--string", "fuubar", | |||
"-d123.123", | |||
"--list=fuu,bar,baz", | |||
"--vector", "123", "456", "789" | |||
}); | |||
p.parse(g, static_cast<int>(args.size()), args.data()); | |||
EXPECT_EQ(g.i, 123); | |||
EXPECT_EQ(g.s, "fuubar"); | |||
EXPECT_EQ(g.d, 123.123); | |||
EXPECT_EQ(g.g1.list, std::list<std::string>({ "fuu", "bar", "baz" })); | |||
EXPECT_EQ(g.g1.vec, std::vector<int>({ 123, 456, 789 })); | |||
} |
@@ -0,0 +1,103 @@ | |||
#include <vector> | |||
#include <gtest/gtest.h> | |||
#include <cppargs.h> | |||
using parser = ::cppargs::simple_parser; | |||
TEST(simple_parser, short_name_seperate_arg) | |||
{ | |||
std::string s; | |||
parser p( | |||
nullptr, | |||
parser::make_reference_option({ "string", 's' }, s) | |||
); | |||
std::vector<const char*> args({ | |||
"/fuu/bar/exe", "-s", "fuu" | |||
}); | |||
p.parse(static_cast<int>(args.size()), args.data()); | |||
EXPECT_EQ(s, "fuu"); | |||
} | |||
TEST(simple_parser, long_name_seperate_arg) | |||
{ | |||
int i; | |||
parser p( | |||
nullptr, | |||
parser::make_reference_option({ "int", 'i' }, i) | |||
); | |||
std::vector<const char*> args({ | |||
"/fuu/bar/exe", "--int", "123" | |||
}); | |||
p.parse(static_cast<int>(args.size()), args.data()); | |||
EXPECT_EQ(i, 123); | |||
} | |||
TEST(simple_parser, short_name_same_arg) | |||
{ | |||
double d; | |||
parser p( | |||
nullptr, | |||
parser::make_reference_option({ "double", 'd' }, d) | |||
); | |||
std::vector<const char*> args({ | |||
"/fuu/bar/exe", "-d0.2" | |||
}); | |||
p.parse(static_cast<int>(args.size()), args.data()); | |||
EXPECT_EQ(d, 0.2); | |||
} | |||
TEST(simple_parser, long_name_same_arg) | |||
{ | |||
std::string s; | |||
parser p( | |||
nullptr, | |||
parser::make_reference_option({ "string", 's' }, s) | |||
); | |||
std::vector<const char*> args({ | |||
"/fuu/bar/exe", "--string=fuubar" | |||
}); | |||
p.parse(static_cast<int>(args.size()), args.data()); | |||
EXPECT_EQ(s, "fuubar"); | |||
} | |||
TEST(simple_parser, vector_extra_arg) | |||
{ | |||
std::vector<int> vec; | |||
parser p( | |||
parser::make_predicate_option({ }, [](auto){ }), | |||
parser::make_reference_option({ "vec", 'v' }, vec) | |||
); | |||
std::vector<const char*> args({ | |||
"/fuu/bar/exe", "--vec", "1", "2", "3", "4", "5", "-i" | |||
}); | |||
p.parse(static_cast<int>(args.size()), args.data()); | |||
EXPECT_EQ(vec, std::vector<int>({ 1, 2, 3, 4, 5 })); | |||
} | |||
TEST(simple_parser, vector_same_arg) | |||
{ | |||
std::vector<int> vec; | |||
parser p( | |||
parser::make_predicate_option({ }, [](auto){ }), | |||
parser::make_reference_option({ "vec", 'v' }, vec) | |||
); | |||
std::vector<const char*> args({ | |||
"/fuu/bar/exe", "--vec=1,2,3,4,5", "-i" | |||
}); | |||
p.parse(static_cast<int>(args.size()), args.data()); | |||
EXPECT_EQ(vec, std::vector<int>({ 1, 2, 3, 4, 5 })); | |||
} |