* implemented member parser (to store parameters in suitable configuration objects)master
| @@ -1,6 +1,5 @@ | |||||
| #pragma once | #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 | #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 ################################################################################ | # Project: cppargs ################################################################################ | ||||
| Find_Package ( cpputils REQUIRED ) | |||||
| Project ( cppargs VERSION 1.0.0.0 LANGUAGES CXX ) | Project ( cppargs VERSION 1.0.0.0 LANGUAGES CXX ) | ||||
| Set ( CPPARGS_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../include ) | Set ( CPPARGS_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../include ) | ||||
| Add_Library ( cppargs INTERFACE ) | Add_Library ( cppargs INTERFACE ) | ||||
| Target_Include_Directories ( cppargs | Target_Include_Directories ( cppargs | ||||
| INTERFACE ${CPPARGS_INCLUDE_DIR} ) | INTERFACE ${CPPARGS_INCLUDE_DIR} ) | ||||
| Target_Link_Libraries ( cppargs | |||||
| INTERFACE cpputils ) | |||||
| If ( HAS_PEDANTIC ) | If ( HAS_PEDANTIC ) | ||||
| Pedantic_Apply_Flags ( ALL ) | 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 })); | |||||
| } | |||||