X-Git-Url: http://git.droids-corp.org/?a=blobdiff_plain;f=src%2Fgenconf%2Fparse_confnode.c;h=562e68879947d1e563e745e3581c112a048172d7;hb=09addaa3b831267407b6f4a51dfaa4597d5da0a6;hp=5c8202bdf99e694df64e31211e3fe0d6faf8050f;hpb=5dbaf53aa2c6187d464108e360621ebfff6e0bc4;p=libcmdline.git diff --git a/src/genconf/parse_confnode.c b/src/genconf/parse_confnode.c index 5c8202b..562e688 100644 --- a/src/genconf/parse_confnode.c +++ b/src/genconf/parse_confnode.c @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -41,15 +42,9 @@ #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,47 +90,8 @@ 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) +parse_conf_node(cmdline_parse_token_hdr_t *tk, const char *buf, void *res, + unsigned ressize) { struct token_conf_node *tk2 = (struct token_conf_node *)tk; struct token_conf_node_data *tkd = &tk2->conf_node_data; @@ -144,6 +100,9 @@ parse_conf_node(cmdline_parse_token_hdr_t *tk, const char *buf, void *res) unsigned int token_len = 0; char token[CMDLINE_MAX_TOKEN_SIZE]; + if (res && ressize < sizeof(struct confnode *)) + return -1; + /* if token is too big... */ token_len = snprintf(token, sizeof(token), "%s", buf); if (token_len >= sizeof(token)) @@ -159,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); @@ -174,40 +135,157 @@ parse_conf_node(cmdline_parse_token_hdr_t *tk, const char *buf, void *res) if (res) *(struct confnode **)res = TAILQ_FIRST(&l); - return token_len; + return 0; +} + +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, int xpath) +{ + struct confnode *prev; + struct confnode *parent = start; + int descend = 1; + + while (1) { + prev = cur; + + /* no more node to browse */ + if (cur == start) + return NULL; + + /* 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; + } + + /* skip invisible nodes, and browse their contents */ + if (cur->flags & CONFNODE_F_INVISIBLE) { + parent = cur; + cur = NULL; + 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; + + /* standard node, return it */ + return cur; + } } -int complete_get_nb_conf_node(cmdline_parse_token_hdr_t *tk) +static int +complete_conf_node_start(cmdline_parse_token_hdr_t *tk, + __attribute__((unused)) const char *tokstr, + 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, *start; + unsigned flags = tkd->flags; + unsigned mask = tkd->mask; + + *opaque = NULL; + cb = malloc(sizeof(*cb)); + if (cb == NULL) + return -1; + *opaque = cb; - return count_children(*tkd->cur, tkd->flags, tkd->mask); + 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 = start; + cb->cur = n; + 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 flags = tkd->flags; + unsigned mask = tkd->mask; + int len; - 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, 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; } +static void +complete_conf_node_end(cmdline_parse_token_hdr_t *tk, void **opaque) +{ + if (*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, +}; +