diff options
Diffstat (limited to 'lib/command_match.c')
| -rw-r--r-- | lib/command_match.c | 262 |
1 files changed, 147 insertions, 115 deletions
diff --git a/lib/command_match.c b/lib/command_match.c index f7e2789253..dbf9984ca8 100644 --- a/lib/command_match.c +++ b/lib/command_match.c @@ -3,132 +3,61 @@ #include "vector.h" #include "command_match.h" -static enum match_type -match_token (struct graph_node *node, char *token, enum filter_type filter) -{ - switch (node->type) { - case WORD_GN: - return cmd_word_match (node, filter, token); - case IPV4_GN: - return cmd_ipv4_match (token); - case IPV4_PREFIX_GN: - return cmd_ipv4_prefix_match (token); - case IPV6_GN: - return cmd_ipv6_match (token); - case IPV6_PREFIX_GN: - return cmd_ipv6_prefix_match (token); - case RANGE_GN: - return cmd_range_match (node, token); - case NUMBER_GN: - return node->value == atoi(token); - case VARIABLE_GN: - default: - return no_match; - } -} - -/* Breaking up string into each command piece. I assume given - character is separated by a space character. Return value is a - vector which includes char ** data element. */ -static vector -cmd_make_strvec (const char *string) -{ - const char *cp, *start; - char *token; - int strlen; - vector strvec; +/* prototypes */ +static int +add_nexthops(struct list *, struct graph_node *); - if (string == NULL) - return NULL; +static enum match_type +cmd_ipv4_match (const char *); - cp = string; +static enum match_type +cmd_ipv4_prefix_match (const char *); - /* Skip white spaces. */ - while (isspace ((int) *cp) && *cp != '\0') - cp++; +static enum match_type +cmd_ipv6_match (const char *); - /* Return if there is only white spaces */ - if (*cp == '\0') - return NULL; +static enum match_type +cmd_ipv6_prefix_match (const char *); - if (*cp == '!' || *cp == '#') - return NULL; +static enum match_type +cmd_range_match (struct graph_node *, const char *str); - /* Prepare return vector. */ - strvec = vector_init (VECTOR_MIN_SIZE); +static enum match_type +cmd_word_match (struct graph_node *, enum filter_type, const char *); - /* Copy each command piece and set into vector. */ - while (1) - { - start = cp; - while (!(isspace ((int) *cp) || *cp == '\r' || *cp == '\n') && - *cp != '\0') - cp++; - strlen = cp - start; - token = XMALLOC (MTYPE_STRVEC, strlen + 1); - memcpy (token, start, strlen); - *(token + strlen) = '\0'; - vector_set (strvec, token); +static vector +cmd_make_strvec (const char *); - while ((isspace ((int) *cp) || *cp == '\n' || *cp == '\r') && - *cp != '\0') - cp++; +static enum match_type +match_token (struct graph_node *, char *, enum filter_type); - if (*cp == '\0') - return strvec; - } -} +static vector +cmd_make_strvec (const char *); -/** - * Adds all children that are reachable by one parser hop - * to the given list. NUL_GN, SELECTOR_GN, and OPTION_GN - * nodes are treated as though their children are attached - * to their parent. - * - * @param[out] l the list to add the children to - * @param[in] node the node to get the children of - * @return the number of children added to the list - */ -static int -add_nexthops(struct list *l, struct graph_node *node) -{ - int added = 0; - struct graph_node *child; - for (unsigned int i = 0; i < vector_active(node->children); i++) - { - child = vector_slot(node->children, i); - if (child->type == OPTION_GN || child->type == SELECTOR_GN || child->type == NUL_GN) - added += add_nexthops(l, child); - else { - listnode_add(l, child); - added++; - } - } - return added; -} +/* matching functions */ /** * Compiles matches or next-hops for a given line of user input. * * Given a string of input and a start node for a matching DFA, runs the input - * against the DFA until the input is exhausted, there are no possible - * transitions, or both. - * If there are no further state transitions available, one of two scenarios is possible: - * - The end of input has been reached. This indicates a valid command. - * - The end of input has not yet been reached. The input does not match any command. - * If there are further transitions available, one of two scenarios is possible: - * - The current input is a valid prefix to a longer command - * - The current input matches a command - * - The current input matches a command, and is also a valid prefix to a longer command + * against the DFA until the input is exhausted or a mismatch is encountered. * - * Any other states indicate a programming error. + * This function returns all valid next hops away from the current node. + * - If the input is a valid prefix to a longer command(s), the set of next + * hops determines what tokens are valid to follow the prefix. In other words, + * the returned list is a list of possible completions. + * - If the input matched a full command, exactly one of the next hops will be + * a node of type END_GN and its function pointer will be set. + * - If the input did not match any valid token sequence, the returned list + * will be empty (there are no transitions away from a nonexistent state). * * @param[in] start the start node of the DFA to match against * @param[in] filter the filtering method * @param[in] input the input string - * @return an array with two lists. The first list is + * @return pointer to linked list with all possible next hops from the last + * matched token. If this is empty, the input did not match any command. */ -struct list** +struct list * match_command (struct graph_node *start, enum filter_type filter, const char *input) { // break command @@ -176,19 +105,122 @@ match_command (struct graph_node *start, enum filter_type filter, const char *in * matched = set of all nodes reachable with current input * next = set of all nodes reachable from all nodes in `matched` */ + list_free (current); + list_free (matched); + + return next; +} + +/** + * Adds all children that are reachable by one parser hop + * to the given list. NUL_GN, SELECTOR_GN, and OPTION_GN + * nodes are treated as though their children are attached + * to their parent. + * + * @param[out] l the list to add the children to + * @param[in] node the node to get the children of + * @return the number of children added to the list + */ +static int +add_nexthops(struct list *l, struct graph_node *node) +{ + int added = 0; + struct graph_node *child; + for (unsigned int i = 0; i < vector_active(node->children); i++) + { + child = vector_slot(node->children, i); + if (child->type == OPTION_GN || child->type == SELECTOR_GN || child->type == NUL_GN) + added += add_nexthops(l, child); + else { + listnode_add(l, child); + added++; + } + } + return added; +} - struct list **result = malloc( 2 * sizeof(struct list *) ); - result[0] = matched; - result[1] = next; - return result; +/* matching utility functions */ + +static enum match_type +match_token (struct graph_node *node, char *token, enum filter_type filter) +{ + switch (node->type) { + case WORD_GN: + return cmd_word_match (node, filter, token); + case IPV4_GN: + return cmd_ipv4_match (token); + case IPV4_PREFIX_GN: + return cmd_ipv4_prefix_match (token); + case IPV6_GN: + return cmd_ipv6_match (token); + case IPV6_PREFIX_GN: + return cmd_ipv6_prefix_match (token); + case RANGE_GN: + return cmd_range_match (node, token); + case NUMBER_GN: + return node->value == atoi(token); + case NUL_GN: + return exact_match; + case VARIABLE_GN: + default: + return no_match; + } } +static vector +cmd_make_strvec (const char *string) +{ + const char *cp, *start; + char *token; + int strlen; + vector strvec; + + if (string == NULL) + return NULL; + + cp = string; + + /* Skip white spaces. */ + while (isspace ((int) *cp) && *cp != '\0') + cp++; + + /* Return if there is only white spaces */ + if (*cp == '\0') + return NULL; + + if (*cp == '!' || *cp == '#') + return NULL; + + /* Prepare return vector. */ + strvec = vector_init (VECTOR_MIN_SIZE); + + /* Copy each command piece and set into vector. */ + while (1) + { + start = cp; + while (!(isspace ((int) *cp) || *cp == '\r' || *cp == '\n') && + *cp != '\0') + cp++; + strlen = cp - start; + token = XMALLOC (MTYPE_STRVEC, strlen + 1); + memcpy (token, start, strlen); + *(token + strlen) = '\0'; + vector_set (strvec, token); + + while ((isspace ((int) *cp) || *cp == '\n' || *cp == '\r') && + *cp != '\0') + cp++; + + if (*cp == '\0') + return strvec; + } +} #define IPV4_ADDR_STR "0123456789." #define IPV4_PREFIX_STR "0123456789./" -enum match_type +static enum match_type cmd_ipv4_match (const char *str) { struct sockaddr_in sin_dummy; @@ -205,7 +237,7 @@ cmd_ipv4_match (const char *str) return exact_match; } -enum match_type +static enum match_type cmd_ipv4_prefix_match (const char *str) { struct sockaddr_in sin_dummy; @@ -246,7 +278,7 @@ cmd_ipv4_prefix_match (const char *str) #define IPV6_PREFIX_STR "0123456789abcdefABCDEF:./" #ifdef HAVE_IPV6 -enum match_type +static enum match_type cmd_ipv6_match (const char *str) { struct sockaddr_in6 sin6_dummy; @@ -266,7 +298,7 @@ cmd_ipv6_match (const char *str) return no_match; } -enum match_type +static enum match_type cmd_ipv6_prefix_match (const char *str) { struct sockaddr_in6 sin6_dummy; @@ -304,7 +336,7 @@ cmd_ipv6_prefix_match (const char *str) } #endif -enum match_type +static enum match_type cmd_range_match (struct graph_node *rangenode, const char *str) { char *endptr = NULL; @@ -324,7 +356,7 @@ cmd_range_match (struct graph_node *rangenode, const char *str) return exact_match; } -enum match_type +static enum match_type cmd_word_match(struct graph_node *wordnode, enum filter_type filter, const char *word) |
