list children in a table, not in a list
authorOlivier Matz <zer0@droids-corp.org>
Thu, 8 Mar 2018 18:50:04 +0000 (19:50 +0100)
committerOlivier Matz <zer0@droids-corp.org>
Thu, 8 Mar 2018 19:02:49 +0000 (20:02 +0100)
so that we can add a child in a list them without modifying it

13 files changed:
lib/ecoli_node.c
lib/ecoli_node.h
lib/ecoli_node_cmd.c
lib/ecoli_node_once.c
lib/ecoli_node_option.c
lib/ecoli_node_option.h
lib/ecoli_node_or.c
lib/ecoli_node_seq.c
lib/ecoli_node_str.c
lib/ecoli_node_subset.c
lib/ecoli_node_weakref.c
lib/ecoli_parsed.h
lib/ecoli_vec.c

index 17a18a8..ff52440 100644 (file)
@@ -83,7 +83,7 @@ struct ec_node *__ec_node(const struct ec_node_type *type, const char *id)
        EC_LOG(EC_LOG_DEBUG, "create node type=%s id=%s\n",
                type->name, id);
        if (id == NULL) {
-               errno = -EINVAL;
+               errno = EINVAL;
                goto fail;
        }
 
@@ -91,7 +91,6 @@ struct ec_node *__ec_node(const struct ec_node_type *type, const char *id)
        if (node == NULL)
                goto fail;
 
-       TAILQ_INIT(&node->children);
        node->type = type;
        node->refcnt = 1;
 
@@ -150,6 +149,7 @@ void ec_node_free(struct ec_node *node)
 
        if (node->type != NULL && node->type->free_priv != NULL)
                node->type->free_priv(node);
+       ec_free(node->children);
        ec_free(node->id);
        ec_free(node->desc);
        ec_free(node->attrs);
@@ -170,15 +170,79 @@ struct ec_node *ec_node_clone(struct ec_node *node)
        return node;
 }
 
+size_t ec_node_get_children_count(const struct ec_node *node)
+{
+       return node->n_children;
+}
+
+struct ec_node *
+ec_node_get_child(const struct ec_node *node, size_t i)
+{
+       if (i >= ec_node_get_children_count(node))
+               return NULL;
+       return node->children[i];
+}
+
+int ec_node_add_child(struct ec_node *node, struct ec_node *child)
+{
+       struct ec_node **children = NULL;
+       size_t n;
+
+       if (node == NULL || child == NULL) {
+               errno = EINVAL;
+               goto fail;
+       }
+
+       n = node->n_children;
+       children = ec_realloc(node->children,
+                       (n + 1) * sizeof(child));
+       if (children == NULL)
+               goto fail;
+
+       children[n] = child;
+       node->children = children;
+       node->n_children = n + 1;
+
+       return 0;
+
+fail:
+       ec_free(children);
+       return -1;
+}
+
+int ec_node_del_child(struct ec_node *node, struct ec_node *child)
+{
+       size_t i, n;
+
+       if (node == NULL || child == NULL)
+               goto fail;
+
+       n = node->n_children;
+       for (i = 0; i < n; i++) {
+               if (node->children[i] != child)
+                       continue;
+               memcpy(&node->children[i], &node->children[i+1],
+                       (n - i - 1) * sizeof(child));
+               return 0;
+       }
+
+fail:
+       errno = EINVAL;
+       return -1;
+}
+
 struct ec_node *ec_node_find(struct ec_node *node, const char *id)
 {
        struct ec_node *child, *ret;
        const char *node_id = ec_node_id(node);
+       size_t i, n;
 
        if (id != NULL && node_id != NULL && !strcmp(node_id, id))
                return node;
 
-       TAILQ_FOREACH(child, &node->children, next) {
+       n = node->n_children;
+       for (i = 0; i < n; i++) {
+               child = node->children[i];
                ret = ec_node_find(child, id);
                if (ret != NULL)
                        return ret;
@@ -205,7 +269,7 @@ static void __ec_node_dump(FILE *out,
        const char *id, *typename, *desc;
        struct ec_node *child;
        size_t maxlen;
-       size_t i;
+       size_t i, n;
 
        maxlen = ec_node_get_max_parse_len(node);
        id = ec_node_id(node);
@@ -226,8 +290,11 @@ static void __ec_node_dump(FILE *out,
                fprintf(out, "maxlen=no\n");
        else
                fprintf(out, "maxlen=%zu\n", maxlen);
-       TAILQ_FOREACH(child, &node->children, next)
+       n = node->n_children;
+       for (i = 0; i < n; i++) {
+               child = node->children[i];
                __ec_node_dump(out, child, indent + 2);
+       }
 }
 
 void ec_node_dump(FILE *out, const struct ec_node *node)
index ac88033..6520d23 100644 (file)
@@ -146,17 +146,14 @@ struct ec_node_type *ec_node_type_lookup(const char *name);
  */
 void ec_node_type_dump(FILE *out);
 
-TAILQ_HEAD(ec_node_list, ec_node);
-
 struct ec_node {
        const struct ec_node_type *type;
        char *id;
        char *desc;
        struct ec_keyval *attrs;
        unsigned int refcnt;
-
-       TAILQ_ENTRY(ec_node) next;
-       struct ec_node_list children;
+       struct ec_node **children;   /* array of children */
+       size_t n_children;           /* number of children in the array */
 };
 
 /* create a new node when the type is known, typically called from the node
@@ -169,6 +166,12 @@ struct ec_node *ec_node(const char *typename, const char *id);
 struct ec_node *ec_node_clone(struct ec_node *node);
 void ec_node_free(struct ec_node *node);
 
+size_t ec_node_get_children_count(const struct ec_node *node);
+struct ec_node *
+ec_node_get_child(const struct ec_node *node, size_t i);
+int ec_node_add_child(struct ec_node *node, struct ec_node *child);
+int ec_node_del_child(struct ec_node *node, struct ec_node *child);
+
 /**
  * Get the max len of strvec that can be parsed by this node
  *
index 5d47a7b..f479c3f 100644 (file)
@@ -412,12 +412,15 @@ int ec_node_cmd_add_child(struct ec_node *gen_node, struct ec_node *child)
        struct ec_node **table;
        int ret;
 
-       // XXX check node type
-
        assert(node != NULL);
 
-       if (child == NULL)
-               return -EINVAL;
+       if (child == NULL) {
+               errno = EINVAL;
+               goto fail;
+       }
+
+       if (ec_node_check_type(gen_node, &ec_node_cmd_type) < 0)
+               goto fail;
 
        if (node->cmd == NULL) {
                ret = ec_node_cmd_build(node);
@@ -426,18 +429,22 @@ int ec_node_cmd_add_child(struct ec_node *gen_node, struct ec_node *child)
        }
 
        table = ec_realloc(node->table, (node->len + 1) * sizeof(*node->table));
-       if (table == NULL) {
-               ec_node_free(child);
-               return -ENOMEM;
-       }
+       if (table == NULL)
+               goto fail;
 
        node->table = table;
+
+       if (ec_node_add_child(gen_node, child) < 0)
+               goto fail;
+
        table[node->len] = child;
        node->len++;
 
-       TAILQ_INSERT_TAIL(&gen_node->children, child, next); // XXX really needed?
-
        return 0;
+
+fail:
+       ec_node_free(child);
+       return -1;
 }
 
 struct ec_node *__ec_node_cmd(const char *id, const char *cmd, ...)
index 940ab4b..3e716e0 100644 (file)
@@ -100,7 +100,7 @@ ec_node_once_complete(const struct ec_node *gen_node,
        /* count the number of occurences of the node: if already parsed,
         * do not match
         */
-       count = count_node(ec_parsed_get_root(parsed), node->child); //XXX
+       count = count_node(ec_parsed_get_root(parsed), node->child);
        if (count > 0)
                return 0;
 
@@ -131,20 +131,25 @@ EC_NODE_TYPE_REGISTER(ec_node_once_type);
 int ec_node_once_set(struct ec_node *gen_node, struct ec_node *child)
 {
        struct ec_node_once *node = (struct ec_node_once *)gen_node;
-       int ret;
 
-       if (gen_node == NULL || child == NULL)
-               return -EINVAL;
+       if (gen_node == NULL || child == NULL) {
+               errno = EINVAL;
+               goto fail;
+       }
 
-       ret = ec_node_check_type(gen_node, &ec_node_once_type);
-       if (ret < 0)
-               return ret;
+       if (ec_node_check_type(gen_node, &ec_node_once_type) < 0)
+               goto fail;
 
-       node->child = child;
+       if (ec_node_add_child(gen_node, child) < 0)
+               goto fail;
 
-       TAILQ_INSERT_TAIL(&gen_node->children, child, next); // XXX really needed?
+       node->child = child;
 
        return 0;
+
+fail:
+       ec_node_free(child);
+       return -1;
 }
 
 struct ec_node *ec_node_once(const char *id, struct ec_node *child)
index bc912ef..f97ae7e 100644 (file)
@@ -30,6 +30,7 @@
 #include <string.h>
 #include <assert.h>
 #include <stdarg.h>
+#include <errno.h>
 
 #include <ecoli_malloc.h>
 #include <ecoli_log.h>
@@ -37,9 +38,9 @@
 #include <ecoli_node.h>
 #include <ecoli_parsed.h>
 #include <ecoli_completed.h>
-#include <ecoli_node_option.h>
 #include <ecoli_node_str.h>
 #include <ecoli_test.h>
+#include <ecoli_node_option.h>
 
 EC_LOG_TYPE_REGISTER(node_option);
 
@@ -93,26 +94,49 @@ static struct ec_node_type ec_node_option_type = {
 
 EC_NODE_TYPE_REGISTER(ec_node_option_type);
 
+int ec_node_option_set(struct ec_node *gen_node, struct ec_node *child)
+{
+       struct ec_node_option *node = (struct ec_node_option *)gen_node;
+
+       if (gen_node == NULL || child == NULL) {
+               errno = EINVAL;
+               goto fail;
+       }
+
+       if (ec_node_check_type(gen_node, &ec_node_option_type) < 0)
+               goto fail;
+
+       if (ec_node_add_child(gen_node, child) < 0)
+               goto fail;
+
+       node->child = child;
+
+       return 0;
+
+fail:
+       ec_node_free(child);
+       return -1;
+}
+
 struct ec_node *ec_node_option(const char *id, struct ec_node *child)
 {
        struct ec_node *gen_node = NULL;
-       struct ec_node_option *node = NULL;
 
        if (child == NULL)
-               return NULL;
+               goto fail;
 
        gen_node = __ec_node(&ec_node_option_type, id);
-       if (gen_node == NULL) {
-               ec_node_free(child);
-               return NULL;
-       }
-       node = (struct ec_node_option *)gen_node;
+       if (gen_node == NULL)
+               goto fail;
 
-       node->child = child;
+       ec_node_option_set(gen_node, child);
+       child = NULL;
 
-       TAILQ_INSERT_TAIL(&gen_node->children, child, next);
+       return gen_node;
 
-       return &node->gen;
+fail:
+       ec_node_free(child);
+       return NULL;
 }
 
 /* LCOV_EXCL_START */
index 3b6e3a2..41d4f38 100644 (file)
@@ -31,5 +31,6 @@
 #include <ecoli_node.h>
 
 struct ec_node *ec_node_option(const char *id, struct ec_node *node);
+int ec_node_option_set(struct ec_node *gen_node, struct ec_node *child);
 
 #endif
index c0d43e2..03aa5fe 100644 (file)
@@ -112,6 +112,17 @@ static void ec_node_or_free_priv(struct ec_node *gen_node)
        ec_free(node->table);
 }
 
+static struct ec_node_type ec_node_or_type = {
+       .name = "or",
+       .parse = ec_node_or_parse,
+       .complete = ec_node_or_complete,
+       .get_max_parse_len = ec_node_or_get_max_parse_len,
+       .size = sizeof(struct ec_node_or),
+       .free_priv = ec_node_or_free_priv,
+};
+
+EC_NODE_TYPE_REGISTER(ec_node_or_type);
+
 int ec_node_or_add(struct ec_node *gen_node, struct ec_node *child)
 {
        struct ec_node_or *node = (struct ec_node_or *)gen_node;
@@ -119,32 +130,34 @@ int ec_node_or_add(struct ec_node *gen_node, struct ec_node *child)
 
        assert(node != NULL);
 
-       if (child == NULL)
-               return -EINVAL;
+       assert(node != NULL);
+
+       if (child == NULL) {
+               errno = EINVAL;
+               goto fail;
+       }
+
+       if (ec_node_check_type(gen_node, &ec_node_or_type) < 0)
+               goto fail;
 
        table = ec_realloc(node->table, (node->len + 1) * sizeof(*node->table));
        if (table == NULL)
-               return -1;
+               goto fail;
 
        node->table = table;
+
+       if (ec_node_add_child(gen_node, child) < 0)
+               goto fail;
+
        table[node->len] = child;
        node->len++;
 
-       TAILQ_INSERT_TAIL(&gen_node->children, child, next);
-
        return 0;
-}
-
-static struct ec_node_type ec_node_or_type = {
-       .name = "or",
-       .parse = ec_node_or_parse,
-       .complete = ec_node_or_complete,
-       .get_max_parse_len = ec_node_or_get_max_parse_len,
-       .size = sizeof(struct ec_node_or),
-       .free_priv = ec_node_or_free_priv,
-};
 
-EC_NODE_TYPE_REGISTER(ec_node_or_type);
+fail:
+       ec_node_free(child);
+       return -1;
+}
 
 struct ec_node *__ec_node_or(const char *id, ...)
 {
index f825d54..68aa287 100644 (file)
@@ -221,26 +221,33 @@ int ec_node_seq_add(struct ec_node *gen_node, struct ec_node *child)
        struct ec_node_seq *node = (struct ec_node_seq *)gen_node;
        struct ec_node **table;
 
-       // XXX check node type
-
        assert(node != NULL);
 
-       if (child == NULL)
-               return -EINVAL;
+       if (child == NULL) {
+               errno = EINVAL;
+               goto fail;
+       }
+
+       if (ec_node_check_type(gen_node, &ec_node_seq_type) < 0)
+               goto fail;
 
        table = ec_realloc(node->table, (node->len + 1) * sizeof(*node->table));
-       if (table == NULL) {
-               ec_node_free(child);
-               return -1;
-       }
+       if (table == NULL)
+               goto fail;
 
        node->table = table;
+
+       if (ec_node_add_child(gen_node, child) < 0)
+               goto fail;
+
        table[node->len] = child;
        node->len++;
 
-       TAILQ_INSERT_TAIL(&gen_node->children, child, next); // XXX really needed?
-
        return 0;
+
+fail:
+       ec_node_free(child);
+       return -1;
 }
 
 struct ec_node *__ec_node_seq(const char *id, ...)
index 3cbc31b..af4f607 100644 (file)
@@ -87,7 +87,7 @@ ec_node_str_complete(const struct ec_node *gen_node,
 
        /* no completion */
        if (str[n] != '\0')
-               return 0; // XXX add a no_match instead?
+               return EC_PARSED_NOMATCH;
 
        if (ec_completed_add_item(completed, gen_node, NULL, EC_COMP_FULL,
                                        str, node->string) < 0)
@@ -139,9 +139,7 @@ int ec_node_str_set_str(struct ec_node *gen_node, const char *str)
 
        if (str == NULL)
                return -EINVAL;
-       if (node->string != NULL)
-               return -EEXIST; // XXX allow to replace
-
+       ec_free(node->string);
        node->string = ec_strdup(str);
        if (node->string == NULL)
                return -ENOMEM;
index 9dc6020..f0d2384 100644 (file)
@@ -268,15 +268,30 @@ static void ec_node_subset_free_priv(struct ec_node *gen_node)
        ec_free(node->table);
 }
 
+static struct ec_node_type ec_node_subset_type = {
+       .name = "subset",
+       .parse = ec_node_subset_parse,
+       .complete = ec_node_subset_complete,
+       .size = sizeof(struct ec_node_subset),
+       .free_priv = ec_node_subset_free_priv,
+};
+
+EC_NODE_TYPE_REGISTER(ec_node_subset_type);
+
 int ec_node_subset_add(struct ec_node *gen_node, struct ec_node *child)
 {
        struct ec_node_subset *node = (struct ec_node_subset *)gen_node;
        struct ec_node **table;
 
-       assert(node != NULL);
+       assert(node != NULL); // XXX specific assert for it, like in libyang
+
+       if (child == NULL) {
+               errno = EINVAL;
+               goto fail;
+       }
 
-       if (child == NULL)
-               return -EINVAL;
+       if (ec_node_check_type(gen_node, &ec_node_subset_type) < 0)
+               goto fail;
 
        table = ec_realloc(node->table, (node->len + 1) * sizeof(*node->table));
        if (table == NULL) {
@@ -285,23 +300,19 @@ int ec_node_subset_add(struct ec_node *gen_node, struct ec_node *child)
        }
 
        node->table = table;
+
+       if (ec_node_add_child(gen_node, child) < 0)
+               goto fail;
+
        table[node->len] = child;
        node->len++;
 
-       TAILQ_INSERT_TAIL(&gen_node->children, child, next);
-
        return 0;
-}
 
-static struct ec_node_type ec_node_subset_type = {
-       .name = "subset",
-       .parse = ec_node_subset_parse,
-       .complete = ec_node_subset_complete,
-       .size = sizeof(struct ec_node_subset),
-       .free_priv = ec_node_subset_free_priv,
-};
-
-EC_NODE_TYPE_REGISTER(ec_node_subset_type);
+fail:
+       ec_node_free(child);
+       return -1;
+}
 
 struct ec_node *__ec_node_subset(const char *id, ...)
 {
index 2a8f1f9..f87866f 100644 (file)
@@ -83,19 +83,23 @@ int ec_node_weakref_set(struct ec_node *gen_node, struct ec_node *child)
 {
        struct ec_node_weakref *node = (struct ec_node_weakref *)gen_node;
 
-       // XXX check node type
-
        assert(node != NULL);
 
-       if (child == NULL)
-               return -EINVAL;
+       if (child == NULL) {
+               errno = EINVAL;
+               goto fail;
+       }
 
-       node->child = child;
+       if (ec_node_check_type(gen_node, &ec_node_weakref_type) < 0)
+               goto fail;
 
-       // XXX else it breaks the dump()
-       //TAILQ_INSERT_TAIL(&gen_node->children, child, next); // XXX really needed?
+       node->child = child;
 
        return 0;
+
+fail:
+       ec_node_free(child);
+       return -1;
 }
 
 struct ec_node *ec_node_weakref(const char *id, struct ec_node *child)
index 340c23e..404392d 100644 (file)
@@ -80,10 +80,6 @@ struct ec_parsed *ec_parsed_dup(struct ec_parsed *parsed);
  */
 const struct ec_strvec *ec_parsed_strvec(const struct ec_parsed *parsed);
 
-/* XXX we could use a cache to store possible completions or match: the
- * cache would be per-node, and would be reset for each call to parse()
- * or complete() ? ... not sure, since parse result can depend on state
- */
 /* a NULL return value is an error, with errno set
   ENOTSUP: no ->parse() operation
 */
@@ -122,7 +118,6 @@ struct ec_parsed *ec_node_parse_strvec(const struct ec_node *node,
  * EC_PARSED_NOMATCH (positive) if it does not match
  * any other negative value (-errno) for other errors
  * the number of matched strings in strvec
- * XXX state is not freed on error ?
  */
 int ec_node_parse_child(const struct ec_node *node,
                        struct ec_parsed *state,
index b3249b5..aea0684 100644 (file)
@@ -61,7 +61,7 @@ ec_vec(size_t elt_size, size_t size, ec_vec_elt_copy_t copy,
        struct ec_vec *vec;
 
        if (elt_size == 0) {
-               errno = -EINVAL;
+               errno = EINVAL;
                return NULL;
        }