EC_LOG(EC_LOG_DEBUG, "create node type=%s id=%s\n",
type->name, id);
if (id == NULL) {
- errno = -EINVAL;
+ errno = EINVAL;
goto fail;
}
if (node == NULL)
goto fail;
- TAILQ_INIT(&node->children);
node->type = type;
node->refcnt = 1;
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);
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;
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);
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)
*/
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
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
*
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);
}
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, ...)
/* 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;
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)
#include <string.h>
#include <assert.h>
#include <stdarg.h>
+#include <errno.h>
#include <ecoli_malloc.h>
#include <ecoli_log.h>
#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);
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 */
#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
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;
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, ...)
{
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, ...)
/* 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)
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;
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) {
}
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, ...)
{
{
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)
*/
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
*/
* 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,
struct ec_vec *vec;
if (elt_size == 0) {
- errno = -EINVAL;
+ errno = EINVAL;
return NULL;
}