summaryrefslogtreecommitdiff
path: root/lib/command_match.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/command_match.c')
-rw-r--r--lib/command_match.c262
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)