cmdline: big rework and clean of cmdline library
[libcmdline.git] / src / genconf / parse_confnode.c
index b25166f..21ccaac 100644 (file)
@@ -29,6 +29,7 @@
 #include <inttypes.h>
 #include <ctype.h>
 #include <string.h>
+#include <stdlib.h>
 #include <netinet/in.h>
 #include <sys/queue.h>
 
 #include "conf_htable.h"
 #include "parse_confnode.h"
 
-struct cmdline_token_ops token_conf_node_ops = {
-       .parse = parse_conf_node,
-       .complete_get_nb = complete_get_nb_conf_node,
-       .complete_get_elt = complete_get_elt_conf_node,
-       .get_help = get_help_conf_node,
-};
-
 /* return 0 if string matches pattern (string must not contain '*')*/
-static int strcmp_joker(const char *s, const char *pattern)
+static int
+strcmp_joker(const char *s, const char *pattern)
 {
        if (s == pattern)
                return 0;
@@ -95,46 +90,6 @@ find_in_children(struct confnode_list *l, struct confnode *n,
 }
 
 static int
-count_children(struct confnode *n, int flags, int mask)
-{
-       struct confnode *c;
-       int i = 0;
-
-       TAILQ_FOREACH(c, &n->children, next) {
-               /* if it's a "if" node, parse children */
-               if (c->flags & CONFNODE_F_INVISIBLE)
-                       i += count_children(c, flags, mask);
-               else if ((c->flags & mask) == flags)
-                       i ++;
-       }
-       return i;
-}
-
-static struct confnode *
-get_from_idx(struct confnode *n, unsigned int *cur, unsigned int idx,
-            int flags, int mask)
-{
-       struct confnode *c, *tmp;
-
-       TAILQ_FOREACH(c, &n->children, next) {
-               /* if it's a "if" node, parse children */
-               if (c->flags & CONFNODE_F_INVISIBLE) {
-                       tmp = get_from_idx(c, cur, idx, flags, mask);
-                       if (tmp)
-                               return tmp;
-               }
-               else {
-                       if ((c->flags & mask) != flags)
-                               continue;
-                       if (*cur == idx)
-                               return c;
-                       *cur = *cur + 1;
-               }
-       }
-       return NULL;
-}
-
-int
 parse_conf_node(cmdline_parse_token_hdr_t *tk, const char *buf, void *res,
                unsigned ressize)
 {
@@ -181,25 +136,97 @@ parse_conf_node(cmdline_parse_token_hdr_t *tk, const char *buf, void *res,
        return token_len;
 }
 
-int complete_get_nb_conf_node(cmdline_parse_token_hdr_t *tk)
+struct confnode_complete_callback {
+       struct confnode *start;
+       struct confnode *cur;
+};
+
+
+static struct confnode *get_next_node(struct confnode *start,
+                                     struct confnode *cur, unsigned flags,
+                                     unsigned mask)
+{
+       struct confnode *prev;
+       struct confnode *parent = start;
+
+       while (1) {
+               prev = cur;
+
+               /* no more node to browse */
+               if (cur == start)
+                       return NULL;
+
+               /* first iteration */
+               if (cur == NULL)
+                       cur = TAILQ_FIRST(&parent->children);
+               else
+                       cur = TAILQ_NEXT(cur, next);
+
+               /* no next, return to upper level */
+               if (cur == NULL) {
+                       if (prev == NULL)
+                               return NULL; /* no node */
+                       cur = prev->parent;
+                       continue;
+               }
+
+               /* skip invisible nodes, and browse their contents */
+               if (cur->flags & CONFNODE_F_INVISIBLE) {
+                       parent = cur;
+                       cur = NULL;
+                       continue;
+               }
+
+               /* check that flags match what we want */
+               if ((cur->flags & mask) != flags)
+                       continue;
+
+               /* standard node, return it */
+               return cur;
+       }
+}
+
+static int
+complete_conf_node_start(cmdline_parse_token_hdr_t *tk, void **opaque)
 {
        struct token_conf_node *tk2 = (struct token_conf_node *)tk;
        struct token_conf_node_data *tkd = &tk2->conf_node_data;
+       struct confnode_complete_callback *cb;
+       struct confnode *n;
+       unsigned flags = tkd->flags;
+       unsigned mask = tkd->mask;
 
-       return count_children(*tkd->cur, tkd->flags, tkd->mask);
+       cb = malloc(sizeof(*cb));
+       if (cb == NULL)
+               return -1;
+
+       n = get_next_node(*tkd->cur, NULL, flags, mask);
+       if (n == NULL)
+               return -1; /* no completion */
+
+       cb->start = *tkd->cur;
+       cb->cur = n;
+       *opaque = cb;
+       return 0;
 }
 
-int complete_get_elt_conf_node(cmdline_parse_token_hdr_t *tk, int idx,
-                              char *dstbuf, unsigned int size)
+static int
+complete_conf_node_iterate(cmdline_parse_token_hdr_t *tk, void **opaque,
+                         char *dstbuf, unsigned int size)
 {
        struct token_conf_node *tk2 = (struct token_conf_node *)tk;
        struct token_conf_node_data *tkd = &tk2->conf_node_data;
+       struct confnode_complete_callback *cb;
        struct confnode *n;
-       unsigned int i = 0, len;
+       unsigned len;
+       unsigned flags = tkd->flags;
+       unsigned mask = tkd->mask;
 
-       n = get_from_idx(*tkd->cur, &i, idx, tkd->flags, tkd->mask);
+       cb = *opaque;
+       n = cb->cur;
        if (n == NULL)
                return -1;
+       cb->cur = get_next_node(cb->start, n, flags, mask);
 
        len = strlen(n->name) + 1;
        if (len > size)
@@ -209,9 +236,23 @@ int complete_get_elt_conf_node(cmdline_parse_token_hdr_t *tk, int idx,
        return 0;
 }
 
+static void
+complete_conf_node_end(cmdline_parse_token_hdr_t *tk, void **opaque)
+{
+       free(*opaque);
+}
 
-int get_help_conf_node(cmdline_parse_token_hdr_t *tk, char *dstbuf, unsigned int size)
+int help_conf_node(cmdline_parse_token_hdr_t *tk, char *dstbuf, unsigned int size)
 {
        snprintf(dstbuf, size, "conf-node");
        return 0;
 }
+
+struct cmdline_token_ops token_conf_node_ops = {
+       .parse = parse_conf_node,
+       .complete_start = complete_conf_node_start,
+       .complete_iterate = complete_conf_node_iterate,
+       .complete_end = complete_conf_node_end,
+       .help = help_conf_node,
+};
+