diff --git a/CMakeLists.txt b/CMakeLists.txt index c863afd..f8c54b8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -95,6 +95,9 @@ set(SOURCE_FILES src/qlz/QuickLZ_L3.cpp src/qlz/QuickLZ_L1.cpp + src/converters/converter.cpp + + src/query/command3.cpp src/query/command2.cpp src/query/Command.cpp src/query/escape.cpp @@ -228,6 +231,7 @@ set(TEST_LIBRARIES jsoncpp_lib ${ed25519_LIBRARIES_STATIC} ${DataPipes_LIBRARIES_SHARED} + ffi openssl::ssl::shared openssl::crypto::shared dl @@ -262,7 +266,7 @@ if(BUILD_TESTS) add_executable(PorpertyTest test/PropertyTest.cpp ${SOURCE_FILES}) target_link_libraries(PorpertyTest ${TEST_LIBRARIES}) - add_executable(BBTest test/BBTest.cpp ${SOURCE_FILES}) + add_executable(BBTest test/BBTest.cpp ${SOURCE_FILES} src/query/command_unused.h src/converters/converter.cpp src/query/command_handler.h) target_link_libraries(BBTest ${TEST_LIBRARIES}) add_executable(LinkedTest test/LinkedTest.cpp ${SOURCE_FILES}) diff --git a/src/Error.cpp b/src/Error.cpp index 0b47c63..6fc325e 100644 --- a/src/Error.cpp +++ b/src/Error.cpp @@ -34,6 +34,9 @@ const std::vector ts::avariableErrors = { {0x020F, "client_login_not_permitted" , "client is not permitted to log in" }, {0x0210, "client_not_subscribed" , "client is not subscribed to the channel" }, {0x0211, "client_unknown" , "client is not known" }, + {0x0212, "client_join_rate_limit_reached" , "client has reached his join attempt limit" }, + {0x0213, "client_is_already_member_of_group" , "client is already a member of the group" }, + {0x0213, "client_is_not_member_of_group" , "client is not a member of the group" }, {0x0300, "channel_invalid_id" , "invalid channelID" }, {0x0301, "channel_protocol_limit_reached" , "max channels protocol limit reached" }, @@ -52,6 +55,7 @@ const std::vector ts::avariableErrors = { {0x030E, "channel_is_private_channel" , "channel is private channel" }, {0x030F, "channel_invalid_security_hash" , "invalid security hash supplied by client" }, {0x0310, "channel_is_deleted" , "target channel is deleted" }, + {0x0311, "channel_name_invalid" , "channel name is invalid" }, {0x0400, "server_invalid_id" , "invalid serverID" }, {0x0401, "server_running" , "server is running" }, @@ -70,6 +74,9 @@ const std::vector ts::avariableErrors = { {0x040D, "server_already_joined" , "query client already joined to the server" }, {0x040E, "server_is_not_shutting_down" , "server isn't shutting down" }, {0x040F, "server_max_vs_reached" , "You reached the maximal virtual server limit" }, + {0x0410, "server_unbound" , "you are not bound to any server" }, + {0x0411, "server_join_rate_limit_reached" , "the server reached his join attempt limit" }, + {0x0500, "sql" , "sql error" }, {0x0501, "database_empty_result" , "sql empty result set" }, @@ -139,7 +146,8 @@ const std::vector ts::avariableErrors = { {0x1001, "web_handshake_invalid" , "Invalid handshake" }, {0x1001, "web_handshake_unsupported" , "Handshake intention unsupported" }, {0x1002, "web_handshake_identity_unsupported" , "Handshake identity unsupported" }, - {0x1002, "web_handshake_identity_proof_failed" , "Identity proof failed" }, + {0x1003, "web_handshake_identity_proof_failed" , "Identity proof failed" }, + {0x1004, "web_handshake_identity_outdated" , "data seems to be outdated" }, {0x1100, "music_invalid_id" , "invalid botID" }, {0x1101, "music_limit_reached" , "Server music bot limit is reached" }, @@ -165,6 +173,7 @@ const std::vector ts::avariableErrors = { {0x1300, "group_invalid_id" , "Invalid group id" }, {0x1301, "group_name_inuse" , "Group name is already in use" }, + {0x1302, "group_not_assigned_over_this_server" , "the group hasn't been assigned over this server" }, {0xE000, "resource_limit_reached" , "resource limit reached" }, diff --git a/src/Error.h b/src/Error.h index f7e4efa..2e6f457 100644 --- a/src/Error.h +++ b/src/Error.h @@ -30,6 +30,7 @@ namespace ts { client_invalid_id = 0x200, client_nickname_inuse = 0x201, invalid_error_code = 0x202, + client_protocol_limit_reached = 0x203, client_invalid_type = 0x204, client_already_subscribed = 0x205, @@ -44,6 +45,11 @@ namespace ts { client_cannot_verify_now = 0x20e, client_login_not_permitted = 0x20f, client_not_subscribed = 0x210, + client_unknown = 0x0211, + client_join_rate_limit_reached = 0x0212, + client_is_already_member_of_group = 0x0213, + client_is_not_member_of_group = 0x0214, + channel_invalid_id = 0x300, channel_protocol_limit_reached = 0x301, channel_already_in = 0x302, @@ -61,6 +67,8 @@ namespace ts { channel_is_private_channel = 0x30e, channel_invalid_security_hash = 0x30f, channel_is_deleted = 0x310, + channel_name_invalid = 0x311, + server_invalid_id = 0x400, server_running = 0x401, server_is_shutting_down = 0x402, @@ -77,6 +85,10 @@ namespace ts { server_version_outdated = 0x40d, server_already_joined = 0x40d, server_is_not_shutting_down = 0x40e, + server_max_vs_reached = 0x40f, + server_unbound = 0x410, + server_join_rate_limit_reached = 0x411, + sql = 0x500, database_empty_result = 0x501, database_duplicate_entry = 0x502, @@ -136,7 +148,9 @@ namespace ts { web_handshake_invalid = 0x1001, web_handshake_unsupported = 0x1001, web_handshake_identity_unsupported = 0x1002, - web_handshake_identity_proof_failed = 0x1002, + web_handshake_identity_proof_failed = 0x1003, + web_handshake_identity_outdated = 0x1004, + music_invalid_id = 0x1100, music_limit_reached = 0x1101, music_client_limit_reached = 0x1102, @@ -150,6 +164,15 @@ namespace ts { playlist_is_in_use = 0x2103, query_not_exists = 0x1200, query_already_exists = 0x1201, + + group_invalid_id = 0x1300, + group_name_inuse = 0x1301, + group_not_assigned_over_this_server = 0x1302, + + conversation_invalid_id = 0x2200, + conversation_more_data = 0x2201, + conversation_is_private = 0x2202, + custom_error = 0xffff }; }; @@ -186,10 +209,18 @@ namespace ts { static_assert(sizeof(permission::PermissionType) * 8 + sizeof(error::type) * 8 <= 62); [[nodiscard]] inline error::type error_code() const { + if(this->is_detailed()) return this->details()->error_id; + return (error::type) ((this->data >> OFFSET_ERROR) & MASK_ERROR); } + [[nodiscard]] inline bool is_permission_error() const { + return this->error_code() == error::server_insufficeient_permissions; + } + [[nodiscard]] inline permission::PermissionType permission_id() const { + if(this->is_detailed()) return (permission::PermissionType) -1; /* not supported */ + return (permission::PermissionType) ((this->data >> OFFSET_PERMISSION) & MASK_PERMISSION); } @@ -201,6 +232,8 @@ namespace ts { } inline std::unique_ptr release_details() { + if(!this->is_detailed()) return nullptr; + auto result = this->details(); this->data = 0; return std::unique_ptr{result}; diff --git a/src/converters/converter.cpp b/src/converters/converter.cpp new file mode 100644 index 0000000..7ffb256 --- /dev/null +++ b/src/converters/converter.cpp @@ -0,0 +1,40 @@ +#include "converter.h" +#include +#include + +using namespace std; +using namespace ts; + +#define CONVERTER_ST(type, m_decode, m_encode) \ +CONVERTER_METHOD_DECODE(type, impl::converter_ ##type ##_decode) { \ + m_decode; \ +} \ + \ +CONVERTER_METHOD_ENCODE(type, impl::converter_ ##type ##_encode) { \ + m_encode \ +} + +#define CONVERTER_PRIMITIVE_ST(type, m_decode) CONVERTER_ST(type, \ + return m_decode;, \ + return std::to_string(std::any_cast(value)); \ +) + +CONVERTER_PRIMITIVE_ST(int8_t, std::stol(std::string{str}) & 0xFF); +CONVERTER_PRIMITIVE_ST(uint8_t, std::stoul(std::string{str}) & 0xFF); + +CONVERTER_PRIMITIVE_ST(int16_t, std::stol(std::string{str}) & 0xFFFF); +CONVERTER_PRIMITIVE_ST(uint16_t, std::stoul(std::string{str}) & 0xFFFF); + +CONVERTER_PRIMITIVE_ST(int32_t, std::stol(std::string{str}) & 0xFFFFFFFF); +CONVERTER_PRIMITIVE_ST(uint32_t, std::stoul(std::string{str}) & 0xFFFFFFFF); + +CONVERTER_PRIMITIVE_ST(int64_t, std::stoll(std::string{str})); +CONVERTER_PRIMITIVE_ST(uint64_t, std::stoull(std::string{str})) + +CONVERTER_PRIMITIVE_ST(bool, str == "1" || str == "true"); +CONVERTER_PRIMITIVE_ST(float, std::stof(std::string{str})); +CONVERTER_PRIMITIVE_ST(double, std::stod(std::string{str})); +CONVERTER_PRIMITIVE_ST(long_double, std::stold(std::string{str})); + +CONVERTER_ST(std__string, return std::string{str};, return std::any_cast(value);); +CONVERTER_ST(const_char__ , return str.data();, return std::string(std::any_cast(value));); \ No newline at end of file diff --git a/src/converters/converter.h b/src/converters/converter.h index 434c860..aba21b7 100644 --- a/src/converters/converter.h +++ b/src/converters/converter.h @@ -1,6 +1,8 @@ #pragma once #include +#include +#include namespace ts { typedef long double long_double; @@ -20,10 +22,10 @@ namespace ts { static constexpr bool supported = true; \ \ static constexpr std::string(*to_string)(const std::any&) = encode; \ - static constexpr type(*from_string)(const std::string&) = decode; \ + static constexpr type(*from_string)(const std::string_view&) = decode; \ }; - #define CONVERTER_METHOD_DECODE(type, name) type name(const std::string& str) + #define CONVERTER_METHOD_DECODE(type, name) type name(const std::string_view& str) #define CONVERTER_METHOD_ENCODE(type, name) std::string name(const std::any& value) /* helper for primitive types */ diff --git a/src/query/Command.cpp b/src/query/Command.cpp index 2308414..ee58cb7 100644 --- a/src/query/Command.cpp +++ b/src/query/Command.cpp @@ -1,11 +1,12 @@ #include "Command.h" +#include "command_exception.h" + #include #include #include #include #include "log/LogUtils.h" #include "escape.h" -#include "command2.h" using namespace std; diff --git a/src/query/command2.cpp b/src/query/command2.cpp index 9364216..8dd041e 100644 --- a/src/query/command2.cpp +++ b/src/query/command2.cpp @@ -1,4 +1,3 @@ -#include "command2.h" #include "escape.h" #include #include @@ -6,178 +5,7 @@ using namespace std; using namespace ts; -#define CONVERTER_ST(type, m_decode, m_encode) \ -CONVERTER_METHOD_DECODE(type, impl::converter_ ##type ##_decode) { \ - m_decode; \ -} \ - \ -CONVERTER_METHOD_ENCODE(type, impl::converter_ ##type ##_encode) { \ - m_encode \ -} - -#define CONVERTER_PRIMITIVE_ST(type, m_decode) CONVERTER_ST(type, \ - return m_decode;, \ - return std::to_string(std::any_cast(value)); \ -) - -CONVERTER_PRIMITIVE_ST(int8_t, std::stol(str) & 0xFF); -CONVERTER_PRIMITIVE_ST(uint8_t, std::stoul(str) & 0xFF); - -CONVERTER_PRIMITIVE_ST(int16_t, std::stol(str) & 0xFFFF); -CONVERTER_PRIMITIVE_ST(uint16_t, std::stoul(str) & 0xFFFF); - -CONVERTER_PRIMITIVE_ST(int32_t, std::stol(str) & 0xFFFFFFFF); -CONVERTER_PRIMITIVE_ST(uint32_t, std::stoul(str) & 0xFFFFFFFF); - -CONVERTER_PRIMITIVE_ST(int64_t, std::stoll(str)); -CONVERTER_PRIMITIVE_ST(uint64_t, std::stoull(str)) - -CONVERTER_PRIMITIVE_ST(bool, str == "1" || str == "true"); -CONVERTER_PRIMITIVE_ST(float, std::stof(str)); -CONVERTER_PRIMITIVE_ST(double, std::stod(str)); -CONVERTER_PRIMITIVE_ST(long_double, std::stold(str)); - -CONVERTER_ST(std__string, return str;, return std::any_cast(value);); -CONVERTER_ST(const_char__ , return str.c_str();, return std::string(std::any_cast(value));); - -command::command(const std::string& command, bool editable) { - this->handle = make_shared(); - this->handle->editable = editable; - this->handle->command = command; -} - -const std::string& command::identifier() const { - return this->handle->command; -} - -void command::set_identifier(const std::string &command) { - this->handle->command = command; -} - -command_bulk command::bulk(size_t index) { - if(this->handle->bulks.size() <= index) { - if(!this->handle->editable) - throw command_bulk_exceed_index_exception(); - - while(this->handle->bulks.size() <= index) { - auto bulk = make_shared(); - bulk->handle = this->handle.get(); - this->handle->bulks.push_back(std::move(bulk)); - } - } - - return {index, this->handle->bulks[index]}; -} - -const command_bulk command::bulk(size_t index) const { - if(this->handle->bulks.size() <= index) - throw command_bulk_exceed_index_exception(); - - return {index, this->handle->bulks[index]}; -} - -size_t command::bulk_count() const { - return this->handle->bulks.size(); -} - - -command_entry command::value(const std::string &key) { - return this->bulk(0)[key]; -} - -const command_entry command::value(const std::string &key) const { - return this->bulk(0)[key]; -} - -bool command::has_value(const std::string &key) const { - if(this->bulk_count() == 0) return false; - - return this->bulk(0).has(key); -} - -bool command::has_trigger(const std::string &key) const { - for(const auto& trigger : this->handle->triggers) - if(trigger == key) - return true; - return false; -} - -void command::set_trigger(const std::string &key, bool value) { - auto& triggers = this->handle->triggers; - auto it = find(triggers.begin(), triggers.end(), key); - if(it == triggers.end() && value) { - triggers.push_back(key); - } else if(it != triggers.end() && !value) { - triggers.erase(it); - } -} - -command command::parse(const std::string_view &data, bool expect_type, bool drop_non_utf8) { - command result; - - size_t current_index = std::string::npos, end_index; - if(expect_type) { - current_index = data.find(' ', 0); - if(current_index == std::string::npos){ - result.set_identifier(std::string(data)); - return result; - } else { - result.set_identifier(std::string(data.substr(0, current_index))); - } - } - - size_t bulk_index = 0; - while(++current_index > 0 || (current_index == 0 && !expect_type)) { - expect_type = true; - - end_index = data.find_first_of(" |", current_index); - - if(end_index != current_index) { /* else we've found another space or a pipe */ - if(data[current_index] == '-') { - string trigger(data.substr(current_index + 1, end_index - current_index - 1)); - result.set_trigger(trigger); - } else { - auto index_assign = data.find_first_of('=', current_index); - string key, value; - if(index_assign == string::npos || index_assign > end_index) { - key = data.substr(current_index, end_index - current_index); - } else { - key = data.substr(current_index, index_assign - current_index); - try { - value = query::unescape(string(data.substr(index_assign + 1, end_index - index_assign - 1)), true); - } catch(const std::invalid_argument& ex) { - (void) ex; - - /* invalid character at index X */ - if(!drop_non_utf8) - throw; - - goto skip_assign; - } - } - - { - const static auto key_validator = [](char c){ return !((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_' || c == '-'); }; - auto invalid_index = find_if(key.begin(), key.end(), key_validator); - if(invalid_index != key.end()) - throw command_malformed_exception(current_index + distance(key.begin(), invalid_index)); - - if(!key.empty() && !result[bulk_index].has(key)) - result[bulk_index][key] = value; - } - - skip_assign:; - } - } - - if(end_index < data.length() && data[end_index] == '|') - bulk_index++; - current_index = end_index; - } - - return result; -} - +/* std::string command::build(ts::command::format::value type) { if(type == format::QUERY || type == format::BRACE_ESCAPED_QUERY) { std::stringstream ss; @@ -223,34 +51,4 @@ std::string command::build(ts::command::format::value type) { } return ""; } - -bool command_bulk::has(const std::string &key) const { - auto& values = this->handle->values; - auto index = values.find(key); - return index != values.end(); -} - -command_entry command_bulk::value(const std::string &key) { - auto& values = this->handle->values; - auto index = values.find(key); - if(index == values.end()) { - if(!this->handle->handle->editable) - throw command_value_missing_exception(this->bulk_index, key); - - auto result = make_shared(); - values[key] = result; - return command_entry(result); - } - return command_entry(index->second); -} - -const command_entry command_bulk::value(const std::string &key) const { - auto& values = this->handle->values; - auto index = values.find(key); - if(index == values.end()) - throw command_value_missing_exception(this->bulk_index, key); - - return command_entry(index->second); -} - -command_entry command_entry::empty{}; \ No newline at end of file + */ diff --git a/src/query/command2.h b/src/query/command2.h deleted file mode 100644 index 22f96ca..0000000 --- a/src/query/command2.h +++ /dev/null @@ -1,641 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "Error.h" - -#include "command_exception.h" -#include "converters/converter.h" - -#ifdef WIN32 - #define __attribute__used -#else - #define __attribute__used __attribute__((used)) -#endif - -namespace ts { - /* data impl stuff */ - namespace impl { - struct command_data; - - struct command_value { - bool casted = false; /* true if value isn't a std::string */ - std::any value; - std::string(*to_string)(const std::any&); - }; - - struct command_bulk { - command_data* handle; - std::map> values; - }; - - struct command_data { - std::string command; - bool editable; - std::deque> bulks; - std::deque triggers; - }; - } - - /* Container stuff */ - class command_bulk; - class command_entry; - class command { - public: - struct format { - enum value { - QUERY, - BRACE_ESCAPED_QUERY, - JSON - }; - }; - static command parse(const std::string_view& /* command data */, bool /* expect type */ = true, bool /* drop non UTF-8 characters */ = false); - explicit command(const std::string& /* command */ = "", bool /* editable */ = true); - - [[nodiscard]] const std::string& identifier() const; - void set_identifier(const std::string& /* command */); - - command_bulk bulk(size_t /* bulk index */); - [[nodiscard]] const command_bulk bulk(size_t /* bulk index */) const; - [[nodiscard]] size_t bulk_count() const; - inline command_bulk operator[](size_t /* index */); - inline const command_bulk operator[](size_t /* index */) const; - - command_entry value(const std::string& /* key */); - [[nodiscard]] const command_entry value(const std::string& /* key */) const; - [[nodiscard]] bool has_value(const std::string& /* key */) const; - command_entry operator[](const std::string& /* key */); - const command_entry operator[](const std::string& /* key */) const; - - [[nodiscard]] bool has_trigger(const std::string& /* key */) const; - void set_trigger(const std::string& /* key */, bool /* value */ = true); - - std::string build(format::value /* format */ = format::QUERY); - /* TODO add a json object build method */ - private: - std::shared_ptr handle; - }; - - class command_bulk { - friend class command; - public: - [[nodiscard]] bool has(const std::string& /* key */) const; - command_entry value(const std::string& /* key */); - [[nodiscard]] command_entry const value(const std::string& /* key */) const; - - - inline command_entry operator[](const std::string& /* key */); - inline const command_entry operator[](const std::string& /* key */) const; - private: - command_bulk(size_t index, std::shared_ptr handle) : bulk_index(index), handle(std::move(handle)) {} - - size_t bulk_index; - std::shared_ptr handle; - }; - - class command_entry { - public: - static command_entry empty; - - command_entry() : handle(std::make_shared()) {} - command_entry(const command_entry& ref) : handle(ref.handle) {} - command_entry(command_entry&& ref) : handle(std::move(ref.handle)) {} - - command_entry&operator=(const command_entry& other) { - this->handle = other.handle; - return *this; - } - - inline bool is_empty() const { return !this->handle->value.has_value(); } - - command_entry& reset() { - this->handle->value.reset(); - return *this; - } - - [[nodiscard]] const std::string string() const { - if(this->is_empty()) return ""; - - if(!this->handle->casted || this->handle->value.type() == typeid(std::string)) //No cast needed - return std::any_cast(this->handle->value); - - if(!this->handle->to_string) throw command_cannot_uncast_exception(); - return this->handle->to_string(this->handle->value); - } - - [[nodiscard]] inline const std::string value() const { return (std::string) this->string(); } - - [[nodiscard]] inline operator std::string() const { - return this->string(); - } - - template ::value, int> = 0> - T as() { - static_assert(converter::supported, "Target type isn't supported!"); - static_assert(!converter::supported || converter::from_string, "Target type dosn't support parsing"); - - if(this->is_empty()) return T(); - - if(this->handle->casted) { - if(this->handle->value.type() == typeid(T)) - return std::any_cast(this->handle->value); - else - throw command_casted_exception(); - } else { - const auto& ref = std::any_cast(this->handle->value); - this->handle->value = converter::from_string(ref); - this->handle->to_string = converter::to_string; - this->handle->casted = true; - } - - return std::any_cast(this->handle->value); - } - - template ::value, int> = 0> - T as() { - return this->string(); - } - - template - inline operator T() { - return this->as(); - } - - command_entry& melt() { - if(this->handle->casted) { - this->handle->value = this->handle->to_string(this->handle->value); - this->handle->casted = false; - this->handle->to_string = nullptr; - } - return *this; - } - - template ::value && !std::is_same::value && !std::is_same::value, int>::type = 0> - void set(const T& value) { - static_assert(converter::supported, "Target type isn't supported!"); - static_assert(!converter::supported || converter::to_string, "Target type dosn't support encode"); - - this->handle->casted = true; - this->handle->value = std::move(value); - this->handle->to_string = converter::to_string; - } - - template ::value, int>::type = 0> - void set(const T& value) { - this->handle->value = value; - this->handle->casted = false; - this->handle->to_string = nullptr; - } - - template - void set(const char (&string)[N]) { - this->set(std::string(string, N - 1)); - } - - template - command_entry&operator=(const T& value) { - this->set(value); - return *this; - } - - explicit command_entry(std::shared_ptr handle) : handle(std::move(handle)) {} - - private: - std::shared_ptr handle; - }; - - namespace descriptor { - namespace tliterals { - template - using tstring = std::integer_sequence; - -#ifndef WIN32 - template - constexpr tstring operator""_tstr() { return { }; } -#endif - template - struct tliteral; - - template - struct tliteral> { - static constexpr char string[sizeof...(elements) + 1] = { elements..., '\0' }; - }; - } - - namespace impl { - namespace templates { - template - struct _or_ { - constexpr static bool value = false; - }; - - template - struct _or_ { - constexpr static bool value = T || _or_::value; - }; - - template - struct index; - - template - struct tuple_index; - - template - struct index : std::integral_constant - { }; - - template - struct index : std::integral_constant::value> - { }; - - template - struct tuple_index> : std::integral_constant::value> - { }; - - template - struct remove_cr { - typedef T type; - }; - - template - struct remove_cr { - typedef T type; - }; - } - - struct base; - - template - struct field; - - struct field_data; - struct field_base; - struct optional_extend; - struct bulk_extend; - - template - struct command_parser { - constexpr static bool supported = false; - }; - - inline void parse_field(const std::shared_ptr& description, field_base* field, command& cmd); - - struct option_data { - bool bulked; - bool optional; - }; - - template - struct options { - using object_data_t = option_data; - static constexpr auto is_bulked = bulked_t; - static constexpr auto is_optional = optional_t; - - protected: - inline static object_data_t options_object() { - return { - is_bulked, - is_optional - }; - } - }; - using default_options = options; - - struct base { - virtual ~base() = default; - }; - - struct base_data { - int type; /* 1 = field | 2 = switch | 3 = command handle */ - option_data options; - }; - - struct field_base : public base { - virtual std::vector& ref_values() = 0; - virtual const std::vector& ref_values() const = 0; - }; - - struct field_data : public base_data { - const char* key; - const std::type_info& field_type; - - void* from_string; - void* to_string; - }; - - template - struct field : public field_base, public options, public extends... { - friend struct command_parser>; - static_assert(converter::supported, "Target type isn't supported!"); - static_assert(!converter::supported || converter::from_string, "Target type dosn't support parsing"); - static_assert(impl::templates::_or_::value...>::value == false, "Extensions could not have data members"); - - protected: - using object_t = field_data; - using value_type = value_type_t; - static constexpr auto key = key_t::string; - static constexpr auto from_string = converter::from_string; - - public: - template ::value...>::value, int> = 0 */> - using as_optional = field, optional_extend, extends...>; - - template ::value...>::value, int> = 0 */> - using as_bulked = field, bulk_extend, extends...>; - - using optional = as_optional; - using bulked = as_bulked; - - inline static std::shared_ptr describe() { - return std::make_shared( - object_t { - 1, - options::options_object(), - key, - typeid(value_type_t), - (void*) converter::from_string, - (void*) converter::to_string - } - ); - } - - inline value_type_t value() const { - command_entry& value = this->get_command_entry(); - return value.as(); - } - - inline command_entry& get_command_entry() const { - if(this->values.empty()) - throw command_value_missing_exception{0, key}; - - const auto& front = this->values.front(); - return *(command_entry*) &front; - } - - template - inline T as() const { - command_entry& value = this->get_command_entry(); - return value.as(); - } - - template - inline operator T() const { - return this->as(); - } - - std::vector& ref_values() final { return this->values; } - const std::vector& ref_values() const final { return this->values; } - protected: - std::vector values; - }; - - struct optional_extend { - public: - inline bool has_value() const { - auto base = dynamic_cast((struct base*) this); - assert(base); - - const auto& values = base->ref_values(); - return !values.empty() && !values[0].is_empty(); - } - - template - inline T get_or(T&& value = T{}) const { - auto base = dynamic_cast((struct base*) this); - assert(base); - - auto& values = base->ref_values(); - if(values.empty() || values[0].is_empty()) - return value; - - return values.front().as(); - } - }; - - struct bulk_extend { - public: - inline bool has_index(size_t index) const { - return !this->at(index).is_empty(); - } - - inline size_t length() const { - auto base = dynamic_cast((struct base*) this); - assert(base); - - return base->ref_values().size(); - } - - inline command_entry at(size_t index) const { - auto base = dynamic_cast((struct base*) this); - assert(base); - - auto& values = base->ref_values(); - if(index > values.size()) - throw command_bulk_exceed_index_exception(); - - return values[index]; - } - - inline command_entry operator[](size_t index) const { - return this->at(index); - } - }; - - struct trigger_base : public base { - virtual bool& ref_flag() = 0; - }; - - struct trigger_data : public base_data { - const char* key; - }; - - template - struct trigger : public trigger_base, public options { - protected: - static constexpr auto key = key_t::string; - public: - using object_t = trigger_data; - - inline static std::shared_ptr describe() { - return std::make_shared( - object_t { - 2, - options::options_object(), - key - } - ); - } - - inline bool is_set() const { return this->flag_set; } - operator bool() const { return this->flag_set; } - - bool& ref_flag() override { - return this->flag_set; - } - - private: - bool flag_set = false; - }; - - template - struct command_parser> { - constexpr static bool supported = true; - - typedef field field_t; - using descriptor_t = std::shared_ptr; - - inline static descriptor_t describe() { - return field_t::describe(); - } - - inline static field_t apply(descriptor_t& descriptor, command& cmd) { - assert(descriptor->type == 1); - - field_t result{}; - - //if(!description->options.optional && !cmd.has_value(description->key)) - // throw command_value_missing_exception(); - auto& values = result.ref_values(); - values.clear(); - - if(descriptor->options.bulked) { - values.resize(cmd.bulk_count()); - for(size_t bulk_index = 0; bulk_index < cmd.bulk_count(); bulk_index++) { - if(!cmd[bulk_index].has(descriptor->key)) { - if(!descriptor->options.optional) - throw command_value_missing_exception(bulk_index, descriptor->key); - else - values[bulk_index] = command_entry::empty; - } else { - values[bulk_index] = cmd[bulk_index][descriptor->key]; - } - } - } else { - if(!cmd.has_value(descriptor->key)) { - if(!descriptor->options.optional) - throw command_value_missing_exception(0, descriptor->key); - else - values.push_back(command_entry::empty); - } else - values.push_back(cmd[descriptor->key]); - } - - return result; - } - }; - - template - struct command_parser> { - constexpr static bool supported = true; - - typedef trigger trigger_t; - using descriptor_t = std::shared_ptr; - - inline static descriptor_t describe() { - return trigger_t::describe(); - } - - inline static trigger_t apply(descriptor_t& descriptor, command& cmd) { - assert(descriptor->type == 2); - - trigger_t result{}; - result.ref_flag() = cmd.has_trigger(descriptor->key); - return result; - } - }; - - struct command_data : public base_data { }; - - template <> - struct command_parser { - constexpr static bool supported = true; - - using descriptor_t = std::shared_ptr; - - inline static descriptor_t describe() { return std::make_shared(command_data{{3, {false, false}}}); } - - inline static command& apply(descriptor_t& descriptor, command& cmd) { - assert(descriptor->type == 3); - return cmd; - } - }; - - template - struct command_parser { - constexpr static bool supported = false; - - using descriptor_t = std::shared_ptr; - - inline static descriptor_t describe() { - return nullptr; - } - - inline static command& apply(descriptor_t& descriptor, command& cmd) { - return cmd; - } - }; - } - - template - using field = impl::field; - - template - using trigger = impl::trigger; - - template - inline std::array, sizeof...(args_t)> describe_function(void(*)(args_t...)) { - static_assert(!impl::templates::_or_::type>::supported...>::value, "Not any function argument type is supported"); - return {impl::command_parser::type>::describe()...}; - } - - struct invocable_function { - void operator()(command& command) { this->invoke(command); } - - virtual void invoke(command& command) = 0; - }; - - template - struct typed_invocable_function : public invocable_function { - using args_tuple_t = std::tuple; - template - using command_parser_t = impl::command_parser::type>; - using descriptors_t = std::tuple::descriptor_t...>; - - descriptors_t descriptors; - void(*function)(args_t...); - - void invoke(command& command) override { - this->function(command_parser_t::apply(std::get::value>(descriptors), command)...); - } - }; - - template > - std::shared_ptr parse_function(void(*function)(args_t...)) { - auto result = std::make_shared(); - result->function = function; - result->descriptors = {impl::command_parser::type>::describe()...}; - return result; - } - - template - void invoke_function(void(*function)(args_t...), command& command) { - auto descriptor = parse_function(function); - (*descriptor)(command); - } - - /* converts a literal into a template literal */ - #define _tlit(literal) ::ts::descriptor::tliterals::tliteral - #define tl(lit) _tlit(lit) - } - - //using desc = descriptor::base; -} - -#include "command_internal.h" \ No newline at end of file diff --git a/src/query/command3.cpp b/src/query/command3.cpp new file mode 100644 index 0000000..624d034 --- /dev/null +++ b/src/query/command3.cpp @@ -0,0 +1,38 @@ +// +// Created by wolverindev on 25.01.20. +// + +#include "command3.h" + +using namespace ts; + +command_bulk command_parser::empty_bulk{std::string::npos, ""}; + +bool command_parser::parse(bool command) { + this->data = this->_command; + this->index = std::string::npos; + + size_t index{0}, findex; + if(command) { + index = this->_command.find(' ', index); + if(index == std::string::npos) { + this->command_type = this->_command; + return true; + } else { + this->command_type = this->data.substr(0, index); + } + + index++; + } + + this->_bulks.reserve(4); + while(index < this->_command.size()) { + findex = this->_command.find('|', index); + if(findex == std::string::npos) + findex = this->_command.size(); + + auto& bulk = this->_bulks.emplace_back(this->_bulks.size() - 1, this->data.substr(index, findex - index)); + index = findex + 1; + } + return true; +} \ No newline at end of file diff --git a/src/query/command3.h b/src/query/command3.h new file mode 100644 index 0000000..cd77fb5 --- /dev/null +++ b/src/query/command3.h @@ -0,0 +1,124 @@ +#pragma once + +#include +#include +#include + +#include "escape.h" +#include "converters/converter.h" +#include "command_exception.h" + +namespace ts { + namespace impl { + class command_string_parser { + public: + [[nodiscard]] inline bool is_empty() const noexcept { return this->data.empty(); } + + [[nodiscard]] inline std::string_view value_raw(const std::string_view& key) const { + bool tmp; + auto result = this->value_raw(key, tmp); + if(!tmp) throw command_value_missing_exception{index, std::string{key}}; + return result; + } + + [[nodiscard]] inline std::string_view value_raw(const std::string_view& key, bool& has_been_found) const noexcept { + has_been_found = false; + + size_t index{0}, findex, max{this->data.size()}, key_size{key.size()}; + do { + findex = this->data.find(key, index); + if(findex > max) return std::string_view{}; + + /* not starting with a space so not a match */ + if(findex != 0 && this->data[findex - 1] != ' ') { + index = findex + key_size; + continue; + } + + findex += key_size; + if(findex < max) { + if(findex < max && this->data[findex] != '=') { + index = findex + key_size; + continue; + } + + has_been_found = true; + return this->data.substr(findex + 1, this->data.find(' ', findex + 1) - findex - 1); + } else { + has_been_found = true; + return std::string_view{}; + } + } while(true); + } + + [[nodiscard]] inline std::string value(const std::string_view& key) const { + const auto value = this->value_raw(key); + if(value.empty()) return std::string{}; + + return query::unescape(std::string{value}, false); + } + + template + [[nodiscard]] inline T value_as(const std::string_view& key) const { + static_assert(converter::supported, "Target type isn't supported!"); + static_assert(!converter::supported || converter::from_string, "Target type dosn't support parsing"); + + return converter::from_string(this->value(key)); + } + + protected: + command_string_parser(size_t index, std::string_view data) : index{index}, data{std::move(data)} {} + + size_t index{}; + std::string_view data{}; + }; + } + + struct command_bulk : public impl::command_string_parser { + command_bulk(size_t index, std::string_view data) : command_string_parser{index, std::move(data)} {} + }; + + class command_parser : public impl::command_string_parser { + public: + enum struct parse_status { + succeeded, + failed + }; + + explicit command_parser(std::string command) : _command{std::move(command)}, impl::command_string_parser{std::string::npos, this->_command} { } + + bool parse(bool /* contains identifier */); + + [[nodiscard]] inline const std::string_view& identifier() const noexcept { return this->command_type; } + [[nodiscard]] inline size_t bulk_count() const noexcept { return this->_bulks.size(); } + [[nodiscard]] inline const command_bulk& bulk(size_t index) const noexcept { + if(this->_bulks.size() <= index) return empty_bulk; + return this->_bulks[index]; + } + + const command_bulk& operator[](size_t index) const { return this->bulk(index); } + + [[nodiscard]] inline bool has_switch(const std::string_view& key) const noexcept { + size_t index{0}; + do { + index = this->_command_view.find(key, index); + index -= 1; + if(index > key.size()) return false; + if(this->_command_view[index] == '-') return index == 0 || this->_command_view[index - 1] == ' '; + index += 2; + } while(true); + } + + [[nodiscard]] const std::vector& bulks() const { return this->_bulks; } + private: + static command_bulk empty_bulk; + + const std::string _command{}; + const std::string_view _command_view{}; + + std::string_view command_type{}; + + std::vector _bulks{}; + std::vector flags{}; + }; +} \ No newline at end of file diff --git a/src/query/command_constants.h b/src/query/command_constants.h index af5e307..1952773 100644 --- a/src/query/command_constants.h +++ b/src/query/command_constants.h @@ -1,23 +1,23 @@ #pragma once #include "Definitions.h" -#include "command2.h" +#include "command_handler.h" namespace ts { namespace cconstants { - typedef descriptor::field return_code; + typedef command_handler::field return_code; - typedef descriptor::field server_id; + typedef command_handler::field server_id; - typedef descriptor::field client_id; - typedef descriptor::field client_database_id; + typedef command_handler::field client_id; + typedef command_handler::field client_database_id; - typedef descriptor::field channel_id; - typedef descriptor::field channel_parent_id; + typedef command_handler::field channel_id; + typedef command_handler::field channel_parent_id; - typedef descriptor::field channel_group_id; - typedef descriptor::field server_group_id; + typedef command_handler::field channel_group_id; + typedef command_handler::field server_group_id; //FIXME /* typedef descriptor::field permission_id; diff --git a/src/query/command_handler.h b/src/query/command_handler.h new file mode 100644 index 0000000..ca5e26c --- /dev/null +++ b/src/query/command_handler.h @@ -0,0 +1,391 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Error.h" + +#include "command_exception.h" +#include "converters/converter.h" +#include "command3.h" + +#ifdef WIN32 +#define __attribute__used +#else +#define __attribute__used __attribute__((used)) +#endif + +namespace ts { + namespace command_handler { + namespace tliterals { + template + using tstring = std::integer_sequence; + +#ifndef WIN32 + template + constexpr tstring operator""_tstr() { return { }; } +#endif + template + struct tliteral; + + template + struct tliteral> { + static constexpr char string[sizeof...(elements) + 1] = { elements..., '\0' }; + }; + } + + /* general description of a function */ + struct parameter_description { + int type; /* 1 = field | 2 = switch | 3 = command handle */ + }; + + struct parameter_description_field : public parameter_description { + const char* key; + bool optional; + const std::type_info& field_type; + }; + + struct parameter_description_switch : public parameter_description { + const char* key; + }; + + struct parameter_description_command : public parameter_description { }; + + + struct invocable_function { + void operator()(command_parser& command) { this->invoke(command); } + virtual void invoke(command_parser& command) = 0; + }; + + namespace impl { + namespace templates { + template + struct _or_ { + constexpr static bool value = false; + }; + + template + struct _or_ { + constexpr static bool value = T || _or_::value; + }; + + template + struct index; + + template + struct tuple_index; + + template + struct index : std::integral_constant + { }; + + template + struct index : std::integral_constant::value> + { }; + + template + struct tuple_index> : std::integral_constant::value> + { }; + + template + struct remove_cr { + typedef T type; + }; + + template + struct remove_cr { + typedef T type; + }; + } + + template + struct command_invoker { + constexpr static bool supported = false; + }; + + struct function_parameter { + virtual ~function_parameter() = default; + + virtual void parse(const command_parser& /* parser */) = 0; + }; + + template + class value_container; + + /* single value implementation */ + template + class single_value_base { + public: + [[nodiscard]] inline const value_t& value() const { + if(!this->_value.has_value()) throw command_value_missing_exception{0, "unknown"}; /* this should never happen! */ + assert(this->_value.has_value()); + + return this->_value.value(); + } + + inline operator value_t() const { + return this->value(); + } + + protected: + static constexpr bool bulked_value = false; + std::optional _value{}; + }; + + template + class value_container : public single_value_base { + protected: + void _parse(const command_parser& parser) { + this->_value = std::make_optional(parser.value_as(key_t::string)); /* will cause a not found exception if missing */ + } + }; + + template + class value_container : public single_value_base { + public: + [[nodiscard]] inline bool has_value() const { return this->_value.has_value(); } + + [[nodiscard]] inline const value_t& value_or(value_t&& fallback) const { + if(this->_value.has_value()) + return this->value(); + return fallback; + } + + protected: + void _parse(const command_parser& parser) { + bool found{}; + (void) parser.value_raw(key_t::string, found); + if(found) + this->_value = parser.value_as(key_t::string); + } + }; + + /* optional bulk implementation */ + template + class value_container { + public: + [[nodiscard]] inline bool has_value(size_t index) const { return this->_values[index].has_value(); } + + [[nodiscard]] inline const value_t& value(size_t index) const { + if(!this->_values[index].has_value()) throw command_value_missing_exception{0, "unknown"}; /* this should never happen! */ + assert(this->_values[index].has_value()); + + return this->_values[index].value(); + } + + + [[nodiscard]] inline const value_t& value_or(size_t index, value_t&& fallback) const { + if(this->has_value(index)) + return this->value(index); + return fallback; + } + protected: + static constexpr bool bulked_value = true; + + void _parse(const command_parser& parser) { + this->_values.reserve(parser.bulk_count()); + for(const auto& bulk : parser.bulks()) { + auto& value = this->_values.emplace_back(); + + bool found{}; + (void) bulk.value_raw(key_t::string, found); + if(found) + value = bulk.value_as(key_t::string); + } + } + + private: + std::vector> _values{}; + }; + + /* non optional bulk implementation */ + template + class value_container { + public: + [[nodiscard]] inline const value_t& value(size_t index) const { + return this->_values[index]; + } + + protected: + static constexpr bool bulked_value = true; + + void _parse(const command_parser& parser) { + this->_values.reserve(parser.bulk_count()); + for(const auto& bulk : parser.bulks()) + this->_values.push_back(bulk.value_as(key_t::string)); /* will cause a not found exception if missing */ + } + + private: + std::vector _values{}; + }; + + template > + struct field : public function_parameter, public bulk_extend { + friend struct command_invoker>; + static_assert(converter::supported, "Target type isn't supported!"); + static_assert(!converter::supported || converter::from_string, "Target type dosn't support parsing"); + + public: + template + using as_optional = field, value_container>; + + template + using as_bulked = field>; + + using optional = as_optional; + using bulked = as_bulked; + + inline static const parameter_description* describe() { + static std::unique_ptr description; + if(!description) { + description = std::make_unique(parameter_description_field{ + 1, + key_t::string, + is_optional_t::value, + typeid(value_type_t) + }); + } + return &*description; + } + + + [[nodiscard]] inline constexpr bool is_optional() { return is_optional_t::value; } + [[nodiscard]] inline constexpr bool is_bulked() { return bulk_extend::bulked_value; } + + + ~field() override = default; + void parse(const command_parser& parser) override { this->_parse(parser); } + }; + + template + struct trigger : public function_parameter { + public: + inline static const parameter_description* describe() { + static std::unique_ptr description; + if(!description) { + description = std::make_unique(parameter_description_switch{ + 2, + key_t::string + }); + } + return &*description; + } + + inline bool is_set() const { return this->flag_set; } + operator bool() const { return this->flag_set; } + + + void parse(const command_parser& parser) override { this->flag_set = parser.has_switch(key_t::string); } + private: + bool flag_set = false; + }; + + template + struct command_invoker> { + constexpr static bool supported = true; + + typedef field field_t; + + inline static const parameter_description* describe() { + return field_t::describe(); + } + + inline static field_t apply(command_parser& cmd) { + field_t result{}; + result.parse(cmd); + return result; + } + }; + + template + struct command_invoker> { + constexpr static bool supported = true; + + inline static const parameter_description* describe() { + return trigger::describe(); + } + + inline static trigger apply(command_parser& cmd) { + trigger result{}; + result.parse(cmd); + return result; + } + }; + + template <> + struct command_invoker { + constexpr static bool supported = true; + + inline static const parameter_description* describe() { + static std::unique_ptr description; + if(!description) + description = std::make_unique(parameter_description_command{3}); + return &*description; + } + + inline static command_parser& apply(command_parser& cmd) { + return cmd; + } + }; + + template + struct command_invoker { + constexpr static bool supported = false; + + using descriptor_t = std::shared_ptr; + + inline static descriptor_t describe() { + return nullptr; + } + + inline static command_parser& apply(descriptor_t& descriptor, command_parser& cmd) { + return cmd; + } + }; + + template + struct typed_invocable_function : public invocable_function { + template + using command_invoker_t = command_invoker::type>; + + void(*function)(args_t...); + void invoke(command_parser& command) override { + this->function(command_invoker_t::apply(command)...); + } + }; + } + + template + using field = impl::field; + + template + using trigger = impl::trigger; + + template + inline std::array describe_function(void(*)(args_t...)) { + static_assert(!impl::templates::_or_<(!impl::command_invoker::type>::supported)...>::value, "Not any function argument type is supported"); + return {impl::command_invoker::type>::describe()...}; + } + + template > + std::shared_ptr parse_function(void(*function)(args_t...)) { + auto result = std::make_shared(); + result->function = function; + return result; + } + + /* converts a literal into a template literal */ +#define _tlit(literal) ::ts::command_handler::tliterals::tliteral +#define tl(lit) _tlit(lit) + } + + //using desc = descriptor::base; +} + +#include "command_internal.h" \ No newline at end of file diff --git a/src/query/command_internal.h b/src/query/command_internal.h index f2cc973..4c5a87d 100644 --- a/src/query/command_internal.h +++ b/src/query/command_internal.h @@ -2,31 +2,9 @@ namespace ts { /* some inlineable implementations */ - inline command_bulk command::operator[](size_t index) { - return this->bulk(index); - } - inline command_entry command::operator[](const std::string &key) { - return this->value(key); - } - - inline command_entry command_bulk::operator[](const std::string &key) { - return this->value(key); - } - - inline const command_bulk command::operator[](size_t index) const { - return this->bulk(index); - } - - inline const command_entry command::operator[](const std::string &key) const { - return this->value(key); - } - - inline const command_entry command_bulk::operator[](const std::string &key) const { - return this->value(key); - } } #ifndef WIN32 - using ts::descriptor::tliterals::operator""_tstr; + using ts::command_handler::tliterals::operator""_tstr; #endif \ No newline at end of file diff --git a/src/query/command_unused.h b/src/query/command_unused.h new file mode 100644 index 0000000..7ce83a3 --- /dev/null +++ b/src/query/command_unused.h @@ -0,0 +1,8 @@ +// +// Created by wolverindev on 25.01.20. +// + +#ifndef TEASPEAK_PARENT_COMMAND_UNUSED_H +#define TEASPEAK_PARENT_COMMAND_UNUSED_H + +#endif //TEASPEAK_PARENT_COMMAND_UNUSED_H diff --git a/src/query/escape.h b/src/query/escape.h index 343b2a0..acc96b7 100644 --- a/src/query/escape.h +++ b/src/query/escape.h @@ -2,9 +2,7 @@ #include -namespace ts { - namespace query { - extern std::string escape(std::string); - extern std::string unescape(std::string, bool /* throw error */); - } +namespace ts::query { + extern std::string escape(std::string); + extern std::string unescape(std::string, bool /* throw error */); } \ No newline at end of file diff --git a/test/CommandTest.cpp b/test/CommandTest.cpp index d97c93b..1e2defc 100644 --- a/test/CommandTest.cpp +++ b/test/CommandTest.cpp @@ -1,4 +1,4 @@ -#include +#include #include #include #include @@ -9,6 +9,7 @@ #include #include "PermissionManager.h" +#include "src/query/command_handler.h" #include "src/query/command_constants.h" using namespace std; @@ -16,34 +17,13 @@ using namespace ts; using namespace license::teamspeak; template -using field = ts::descriptor::field; +using field = ts::command_handler::field; template -using trigger = ts::descriptor::trigger; - -template -class FixedString { - public: - constexpr FixedString(char const* s) { - for (unsigned i = 0; i < N; ++i) - buf[i] = s[i]; - } - - constexpr operator const char*() const { return buf; } - [[nodiscard]] constexpr const char* c_str() const { return buf; } - private: - char buf[N + 1]{}; -}; -template FixedString(char const (&)[N]) -> FixedString; - -template -void test() { - std::cout << "Parameter: " << T.c_str() << "\n"; -} - +using trigger = ts::command_handler::trigger; void handleCommand( - ts::command& _cmd, + ts::command_parser& parser, const cconstants::return_code::optional& return_code, const field& key_a, const field::optional& key_b, @@ -53,20 +33,15 @@ void handleCommand( if(key_a.value() < 10) { __asm__("nop"); } - __asm__("nop"); - auto b = key_c.as(); - __asm__("nop"); - string key_c_str = key_c; - __asm__("nop"); auto c = key_b.has_value(); __asm__("nop"); - (void) key_c[1].value(); + (void) key_c.value(1); __asm__("nop"); - (void) return_code.get_or("XXX"); - //cout << << endl; - //cout << "Return code: " << return_code.get_or("XXX") << endl; + (void) return_code.value_or("XXX"); + cout << key_b.has_value() << endl; + cout << "Return code: " << return_code.value_or("XXX") << endl; __asm__("nop"); } @@ -93,38 +68,16 @@ void eval_test(command_result x) { } } -struct A { - virtual ~A() { puts("~A\n"); } -}; - -struct B : public A { - virtual ~B() { puts("~B\n"); } -}; - int main() { - make_command_result(error::accounting_slot_limit_reached, ""); - /* -0x559e5259a479 : lea 0xa0(%rsp),%rbx -0x559e5259a481 : lea 0x30(%rsp),%r14 -0x559e5259a486 : callq 0x559e525579d0 -0x559e5259a48b : lea 0x17e6a6(%rip),%rdi # 0x559e52718b38 -0x559e5259a492 : mov %rax,%rbp -0x559e5259a495 : callq 0x559e52558b10 -0x559e5259a49a : mov $0x1,%esi -0x559e5259a49f : mov %rbp,%rdi -0x559e5259a4a2 : callq 0x559e525573d0 - */ - { - A* var = new B{}; - delete var; - } - test<"abs">(); + ts::command_handler::impl::field::as_bulked a; + std::cout << "Optional: " << a.is_optional() << "\n"; + //test<"abs">(); //for(const auto& error : avariableErrors) // cout << error.name << " = " << hex << "0x" << error.errorId << "," << endl; - eval_test(test()); - eval_test(test2()); - eval_test(test3()); + //eval_test(test()); + //eval_test(test2()); + //eval_test(test3()); /* ios_base::sync_with_stdio(false); // Avoids synchronization with C stdio on gcc // (either localize both or disable sync) @@ -160,9 +113,12 @@ int main() { //register_function(handleCommand); + /* cout << sizeof(command_result) << endl; ts::command cmd("notify"); + */ + /* cout << ts::command::parse("test a=b ").build(ts::command::format::BRACE_ESCAPED_QUERY) << endl; cout << ts::command::parse("test a=").build(ts::command::format::BRACE_ESCAPED_QUERY) << endl; cout << ts::command::parse("test a").build(ts::command::format::BRACE_ESCAPED_QUERY) << endl; @@ -170,7 +126,17 @@ int main() { cout << ts::command::parse("a=c | a=c -x", false).build(ts::command::format::BRACE_ESCAPED_QUERY) << endl; cout << ts::command::parse("a a=c|a=c").build(ts::command::format::BRACE_ESCAPED_QUERY) << endl; cout << ts::command::parse("a a=c a=c2 -z | -? a=c").build(ts::command::format::BRACE_ESCAPED_QUERY) << endl; + */ + std::cout << "Command v3:\n"; + { + auto command = ts::command_parser{"a a=c a=c2 -z | -? a=2 key_c=c"}; + if(!command.parse(true)) return 1; + + std::cout << command.bulk_count() << "\n"; + std::cout << command.bulk(1).value("a") << "\n"; + std::cout << command.has_switch("?") << "\n"; + }; /* * cmd[0]["key_a"] = 2; @@ -182,18 +148,14 @@ int main() { cmd.set_trigger("test2"); cout << "Key_A => " << cmd[0]["key_a"].string() << endl; */ - cmd["key_a"] = "0"; - cmd["key_b"] = "key_b_value"; - cmd["return_code"] = "ASD"; - cmd[0]["key_c"] = "key_c_value_0"; - cmd[1]["key_c"] = "key_c_value_1"; - cmd.set_trigger("test"); - auto result = ts::descriptor::describe_function(handleCommand); + auto result = ts::command_handler::describe_function(handleCommand); + auto cmd_handler = ts::command_handler::parse_function(handleCommand); + + auto cmd = ts::command_parser{"a key_a=77 a=c a=c2 -z | -? key_c=3333 c=22 a=c return_code=234"}; + if(!cmd.parse(true)) return 1; - auto cmd_handler = ts::descriptor::parse_function(handleCommand); cmd_handler->invoke(cmd); - cout << cmd.build() << endl; //auto v = ts::descriptor::entry::bulked::val; return 0;