genconf: basic support of completion for nodes starting with "//"
authorOlivier Matz <zer0@droids-corp.org>
Sun, 8 May 2011 16:00:54 +0000 (18:00 +0200)
committerOlivier Matz <zer0@droids-corp.org>
Sun, 8 May 2011 16:00:54 +0000 (18:00 +0200)
Signed-off-by: Olivier Matz <zer0@droids-corp.org>
src/genconf/parse_confnode.c

index 382bfde..562e688 100644 (file)
@@ -118,6 +118,8 @@ parse_conf_node(cmdline_parse_token_hdr_t *tk, const char *buf, void *res,
                                         tkd->mask, 1);
                else {
                        n = conf_htable_lookup(token + 2);
+                       if (n == NULL)
+                               return -1;
                        if ((n->flags & tkd->mask) != tkd->flags)
                                return -1;
                        TAILQ_INSERT_TAIL(&l, n, user_next);
@@ -139,15 +141,17 @@ parse_conf_node(cmdline_parse_token_hdr_t *tk, const char *buf, void *res,
 struct confnode_complete_callback {
        struct confnode *start;
        struct confnode *cur;
+       int xpath;
 };
 
 
 static struct confnode *get_next_node(struct confnode *start,
                                      struct confnode *cur, unsigned flags,
-                                     unsigned mask)
+                                     unsigned mask, int xpath)
 {
        struct confnode *prev;
        struct confnode *parent = start;
+       int descend = 1;
 
        while (1) {
                prev = cur;
@@ -159,14 +163,22 @@ static struct confnode *get_next_node(struct confnode *start,
                /* first iteration */
                if (cur == NULL)
                        cur = TAILQ_FIRST(&parent->children);
+               /* directory in xpath mode */
+               else if (xpath && descend &&
+                        (cur->flags & CONFNODE_F_IS_DIR) &&
+                        (cur->flags & CONFNODE_F_INVISIBLE) == 0)
+                       cur = TAILQ_FIRST(&cur->children);
+               /* other cases */
                else
                        cur = TAILQ_NEXT(cur, next);
+               descend = 1;
 
                /* no next, return to upper level */
                if (cur == NULL) {
                        if (prev == NULL)
                                return NULL; /* no node */
                        cur = prev->parent;
+                       descend = 0;
                        continue;
                }
 
@@ -177,6 +189,10 @@ static struct confnode *get_next_node(struct confnode *start,
                        continue;
                }
 
+               /* skip other nodes with no name */
+               if (cur->flags & CONFNODE_F_NO_NAME)
+                       continue;
+
                /* check that flags match what we want */
                if ((cur->flags & mask) != flags)
                        continue;
@@ -194,7 +210,7 @@ complete_conf_node_start(cmdline_parse_token_hdr_t *tk,
        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;
+       struct confnode *n, *start;
        unsigned flags = tkd->flags;
        unsigned mask = tkd->mask;
 
@@ -204,11 +220,23 @@ complete_conf_node_start(cmdline_parse_token_hdr_t *tk,
                return -1;
        *opaque = cb;
 
-       n = get_next_node(*tkd->cur, NULL, flags, mask);
-       if (n == NULL)
-               return -1; /* no completion */
+       if (strlen(tokstr) >= 2 && tokstr[0] == '/' && tokstr[1] == '/') {
+               start = *tkd->root;
+               cb->xpath = 1;
+       }
+       else {
+               start = *tkd->cur;
+               cb->xpath = 0;
+       }
+
+       n = get_next_node(start, NULL, flags, mask, cb->xpath);
+       if (n == NULL) {
+               /* no completion.
+                * cb is freed in complete_conf_node_end()*/
+               return -1;
+       }
 
-       cb->start = *tkd->cur;
+       cb->start = start;
        cb->cur = n;
        return 0;
 }
@@ -221,21 +249,22 @@ complete_conf_node_iterate(cmdline_parse_token_hdr_t *tk, void **opaque,
        struct token_conf_node_data *tkd = &tk2->conf_node_data;
        struct confnode_complete_callback *cb;
        struct confnode *n;
-       unsigned len;
        unsigned flags = tkd->flags;
        unsigned mask = tkd->mask;
+       int len;
 
        cb = *opaque;
        n = cb->cur;
        if (n == NULL)
                return -1;
-       cb->cur = get_next_node(cb->start, n, flags, mask);
+       cb->cur = get_next_node(cb->start, n, flags, mask, cb->xpath);
 
-       len = strlen(n->name) + 1;
-       if (len > size)
+       len = snprintf(dstbuf, size, "%s%s",
+                      cb->xpath ? "//" : "",
+                      n->name);
+       if (len < 0 || len >= size)
                return -1;
 
-       strcpy(dstbuf, n->name);
        return 0;
 }