diff --git a/src/core/CommandMap.cc b/src/core/CommandMap.cc index 12a3549..8637521 100644 --- a/src/core/CommandMap.cc +++ b/src/core/CommandMap.cc @@ -32,53 +32,89 @@ void CommandMap::add(const char * s, uint32_t id, node->next_map = next_map; } -std::shared_ptr CommandMap::get_command(uint32_t * command_characters, - uint32_t length) const +uint8_t CommandMap::lookup_command(const uint32_t * command_characters, + size_t length, Command & command) const +{ + const Node * node = &m_root_node; + for (size_t unit_index = 0u; unit_index < 2u; unit_index++) + { + size_t consumed_length = 0u; + Command::Unit & unit = (unit_index == 0u) ? command.main : command.motion; + uint8_t unit_status = extract_command_unit(command_characters, + length, unit, node, &node, &consumed_length); + switch (unit_status) + { + case UNIT_INVALID: + return COMMAND_INVALID; + case UNIT_NEED_MORE_CHARACTERS: + return COMMAND_NEED_MORE_CHARACTERS; + case UNIT_COMPLETE: + return COMMAND_COMPLETE; + case UNIT_COMPLETE_NEED_ANOTHER: + command_characters += consumed_length; + length -= consumed_length; + break; + default: + return COMMAND_INVALID; + } + } + return COMMAND_INVALID; +} + +uint8_t CommandMap::extract_command_unit(const uint32_t * command_characters, + size_t length, Command::Unit & unit, const Node * start_node, + const Node ** next_node, size_t * consumed_length) const { if (length < 1u) - return nullptr; - const Node * node = &m_root_node; - bool in_motion = false; - Command command; + return UNIT_NEED_MORE_CHARACTERS; + bool gathering_count = true; + unit.count = 0u; + const Node * node = start_node; for (size_t i = 0u; i < length; i++) { + *consumed_length = i + 1u; uint32_t c = command_characters[i]; - auto it = node->next_chars.find(c); - if (it != node->next_chars.end()) + if (gathering_count && ('0' <= c) && (c <= '9')) { - node = &*it->second; - if (node->flags & Node::FLAG_TERMINATOR) - { - if (in_motion) - command.motion.id = node->id; - else - command.main.id = node->id; - if (node->flags & Node::FLAG_FOLLOWING_CHAR) - { - if (i < (length - 1u)) - { - if (in_motion) - command.motion.following_char = command_characters[i + 1u]; - else - command.main.following_char = command_characters[i + 1u]; - return std::make_shared(command); - } - } - else if (node->next_map) - { - in_motion = true; - node = &node->next_map->m_root_node; - } - else - { - return std::make_shared(command); - } - } + unit.count *= 10u; + unit.count += (c - '0'); } else { - return nullptr; + gathering_count = false; + auto it = node->next_chars.find(c); + if (it != node->next_chars.end()) + { + node = &*it->second; + if (node->flags & Node::FLAG_TERMINATOR) + { + unit.id = node->id; + if (node->flags & Node::FLAG_FOLLOWING_CHAR) + { + if (i < (length - 1u)) + { + *consumed_length = i + 2u; + unit.following_char = command_characters[i + 1u]; + return UNIT_COMPLETE; + } + return UNIT_NEED_MORE_CHARACTERS; + } + else if (node->next_map) + { + *next_node = &node->next_map->m_root_node; + return UNIT_COMPLETE_NEED_ANOTHER; + } + else + { + return UNIT_COMPLETE; + } + } + } + else + { + return UNIT_INVALID; + } } } - return nullptr; + return UNIT_NEED_MORE_CHARACTERS; } diff --git a/src/core/CommandMap.h b/src/core/CommandMap.h index f97da33..cb36449 100644 --- a/src/core/CommandMap.h +++ b/src/core/CommandMap.h @@ -9,10 +9,17 @@ class CommandMap { public: + enum : uint8_t + { + COMMAND_INVALID, + COMMAND_NEED_MORE_CHARACTERS, + COMMAND_COMPLETE, + }; + void add(const char * s, uint32_t id, std::shared_ptr next_map, bool following_char); - std::shared_ptr get_command(uint32_t * command_characters, - uint32_t length) const; + uint8_t lookup_command(const uint32_t * command_characters, size_t length, + Command & command) const; protected: struct Node @@ -36,6 +43,18 @@ protected: }; Node m_root_node; + + enum : uint8_t + { + UNIT_INVALID, + UNIT_NEED_MORE_CHARACTERS, + UNIT_COMPLETE, + UNIT_COMPLETE_NEED_ANOTHER, + }; + + uint8_t extract_command_unit(const uint32_t * command_characters, + size_t length, Command::Unit & unit, const Node * start_node, + const Node ** next_node, size_t * consumed_length) const; }; #endif