save
[protos/libecoli.git] / lib / ecoli_parsed.c
index 93d5325..e8f3cb9 100644 (file)
@@ -27,6 +27,7 @@
 
 #include <stdio.h>
 #include <stdlib.h>
+#include <stdint.h>
 #include <string.h>
 #include <assert.h>
 #include <errno.h>
 #include <ecoli_node.h>
 #include <ecoli_parsed.h>
 
+int ec_node_parse_child(struct ec_node *node, struct ec_parsed *state,
+                       const struct ec_strvec *strvec)
+{
+       struct ec_strvec *match_strvec;
+       struct ec_parsed *child;
+       int ret;
+
+       assert(state != NULL);
+
+       /* build the node if required */
+       if (node->type->build != NULL) {
+               if ((node->flags & EC_NODE_F_BUILT) == 0) {
+                       ret = node->type->build(node);
+                       if (ret < 0)
+                               return ret;
+               }
+       }
+       node->flags |= EC_NODE_F_BUILT;
+
+       if (node->type->parse == NULL)
+               return -ENOTSUP;
+
+       child = ec_parsed();
+       if (child == NULL)
+               return -ENOMEM;
+
+       child->node = node;
+       ec_parsed_add_child(state, child);
+       ret = node->type->parse(node, child, strvec);
+       if (ret == EC_PARSED_NOMATCH) {
+               ec_parsed_del_child(state, child);
+               assert(TAILQ_EMPTY(&child->children));
+               ec_parsed_free(child);
+               return ret;
+       } else if (ret < 0) {
+               return ret;
+       }
+
+       match_strvec = ec_strvec_ndup(strvec, 0, ret);
+       if (match_strvec == NULL)
+               return -ENOMEM;
+
+       child->strvec = match_strvec;
+
+       return ret;
+}
+
+struct ec_parsed *ec_node_parse_strvec(struct ec_node *node,
+                               const struct ec_strvec *strvec)
+{
+       struct ec_parsed *parsed = ec_parsed();
+       struct ec_parsed *child_parsed;
+       int ret;
+
+       if (parsed == NULL)
+               return NULL;
+
+       ret = ec_node_parse_child(node, parsed, strvec);
+       if (ret < 0 && ret != EC_PARSED_NOMATCH) {
+               ec_parsed_free(parsed);
+               parsed = NULL;
+       } else if (ret != EC_PARSED_NOMATCH) {
+               /* remove dummy root node */
+               child_parsed = ec_parsed_get_last_child(parsed);
+               ec_parsed_del_child(parsed, child_parsed);
+               ec_parsed_free(parsed);
+               parsed = child_parsed;
+       }
+
+       return parsed;
+}
+
 struct ec_parsed *ec_node_parse(struct ec_node *node, const char *str)
 {
        struct ec_strvec *strvec = NULL;
-       struct ec_parsed *parsed;
+       struct ec_parsed *parsed = NULL;
 
        errno = ENOMEM;
        strvec = ec_strvec();
@@ -60,38 +133,10 @@ struct ec_parsed *ec_node_parse(struct ec_node *node, const char *str)
 
  fail:
        ec_strvec_free(strvec);
+       ec_parsed_free(parsed);
        return NULL;
 }
 
-struct ec_parsed *ec_node_parse_strvec(struct ec_node *node,
-       const struct ec_strvec *strvec)
-{
-       struct ec_parsed *parsed;
-       int ret;
-
-       /* build the node if required */
-       if (node->type->build != NULL) {
-               if ((node->flags & EC_NODE_F_BUILT) == 0) {
-                       ret = node->type->build(node);
-                       if (ret < 0) {
-                               errno = -ret;
-                               return NULL;
-                       }
-               }
-       }
-       node->flags |= EC_NODE_F_BUILT;
-
-       if (node->type->parse == NULL) {
-               errno = ENOTSUP;
-               return NULL;
-       }
-
-       parsed = node->type->parse(node, strvec);
-
-       return parsed;
-}
-
-
 struct ec_parsed *ec_parsed(void)
 {
        struct ec_parsed *parsed = NULL;
@@ -102,17 +147,18 @@ struct ec_parsed *ec_parsed(void)
 
        TAILQ_INIT(&parsed->children);
 
+       parsed->attrs = ec_keyval();
+       if (parsed->attrs == NULL)
+               goto fail;
+
        return parsed;
 
  fail:
-       return NULL;
-}
+       if (parsed != NULL)
+               ec_keyval_free(parsed->attrs);
+       ec_free(parsed);
 
-void ec_parsed_set_match(struct ec_parsed *parsed,
-       const struct ec_node *node, struct ec_strvec *strvec)
-{
-       parsed->node = node;
-       parsed->strvec = strvec;
+       return NULL;
 }
 
 void ec_parsed_free_children(struct ec_parsed *parsed)
@@ -136,6 +182,7 @@ void ec_parsed_free(struct ec_parsed *parsed)
 
        ec_parsed_free_children(parsed);
        ec_strvec_free(parsed->strvec);
+       ec_keyval_free(parsed->attrs);
        ec_free(parsed);
 }
 
@@ -145,7 +192,7 @@ static void __ec_parsed_dump(FILE *out,
        struct ec_parsed *child;
        const struct ec_strvec *vec;
        size_t i;
-       const char *id = "None", *typename = "None";
+       const char *id = "none", *typename = "none";
 
        if (parsed->node != NULL) {
                if (parsed->node->id != NULL)
@@ -161,13 +208,9 @@ static void __ec_parsed_dump(FILE *out,
                        fprintf(out, "|");
        }
 
-       fprintf(out, "node_type=%s id=%s vec=[", typename, id);
+       fprintf(out, "node_type=%s id=%s vec=", typename, id);
        vec = ec_parsed_strvec(parsed);
-       for (i = 0; i < ec_strvec_len(vec); i++)
-               fprintf(out, "%s<%s>",
-                       i == 0 ? "" : ",",
-                       ec_strvec_val(vec, i));
-       fprintf(out, "]\n");
+       ec_strvec_dump(out, vec);
 
        TAILQ_FOREACH(child, &parsed->children, next)
                __ec_parsed_dump(out, child, indent + 2);
@@ -193,12 +236,48 @@ void ec_parsed_add_child(struct ec_parsed *parsed,
        struct ec_parsed *child)
 {
        TAILQ_INSERT_TAIL(&parsed->children, child, next);
+       child->parent = parsed;
 }
 
-void ec_parsed_del_child(struct ec_parsed *parsed,
+void ec_parsed_del_child(struct ec_parsed *parsed, // XXX rename del in unlink?
        struct ec_parsed *child)
 {
        TAILQ_REMOVE(&parsed->children, child, next);
+       child->parent = NULL;
+}
+
+struct ec_parsed *
+ec_parsed_get_last_child(struct ec_parsed *parsed)
+{
+       return TAILQ_LAST(&parsed->children, ec_parsed_list);
+}
+
+void ec_parsed_del_last_child(struct ec_parsed *parsed) // rename in free
+{
+       struct ec_parsed *child;
+
+       child = ec_parsed_get_last_child(parsed);
+       ec_parsed_del_child(parsed, child);
+       ec_parsed_free(child);
+}
+
+struct ec_parsed *ec_parsed_get_root(struct ec_parsed *parsed)
+{
+       if (parsed == NULL)
+               return NULL;
+
+       while (parsed->parent != NULL)
+               parsed = parsed->parent;
+
+       return parsed;
+}
+
+struct ec_parsed *ec_parsed_get_parent(struct ec_parsed *parsed)
+{
+       if (parsed == NULL)
+               return NULL;
+
+       return parsed->parent;
 }
 
 struct ec_parsed *ec_parsed_find_first(struct ec_parsed *parsed,
@@ -231,7 +310,7 @@ const struct ec_strvec *ec_parsed_strvec(const struct ec_parsed *parsed)
        return parsed->strvec;
 }
 
-/* number of parsed strings in the vector */
+/* number of strings in the parsed vector */
 size_t ec_parsed_len(const struct ec_parsed *parsed)
 {
        if (parsed == NULL || parsed->strvec == NULL)
@@ -245,7 +324,7 @@ size_t ec_parsed_matches(const struct ec_parsed *parsed)
        if (parsed == NULL)
                return 0;
 
-       if (parsed->node == NULL && TAILQ_EMPTY(&parsed->children))
+       if (parsed->node == NULL && TAILQ_EMPTY(&parsed->children)) // XXX both needed?
                return 0;
 
        return 1;