#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;
}
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;
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))
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,
+ __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;
+ 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;
+ *opaque = cb;
+
+ n = get_next_node(*tkd->cur, NULL, flags, mask);
+ if (n == NULL)
+ return -1; /* no completion */
+
+ cb->start = *tkd->cur;
+ 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 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)
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,
+};
+