fix config dump
[protos/libecoli.git] / lib / ecoli_parse.c
index 7f36226..6396fc1 100644 (file)
 #include <ecoli_strvec.h>
 #include <ecoli_keyval.h>
 #include <ecoli_log.h>
+#include <ecoli_test.h>
 #include <ecoli_node.h>
+#include <ecoli_node_sh_lex.h>
+#include <ecoli_node_str.h>
+#include <ecoli_node_seq.h>
 #include <ecoli_parse.h>
 
+EC_LOG_TYPE_REGISTER(parse);
+
 TAILQ_HEAD(ec_parse_list, ec_parse);
 
 struct ec_parse {
@@ -36,38 +42,46 @@ static int __ec_node_parse_child(const struct ec_node *node,
        struct ec_parse *child = NULL;
        int ret;
 
-       if (node->type->parse == NULL)
-               return -ENOTSUP;
+       if (ec_node_type(node)->parse == NULL) {
+               errno = ENOTSUP;
+               return -1;
+       }
 
        if (!is_root) {
                child = ec_parse(node);
                if (child == NULL)
-                       return -ENOMEM;
+                       return -1;
 
                ec_parse_link_child(state, child);
        } else {
                child = state;
        }
-       ret = node->type->parse(node, child, strvec);
-       if (ret < 0 || ret == EC_PARSE_NOMATCH)
-               goto free;
+       ret = ec_node_type(node)->parse(node, child, strvec);
+       if (ret < 0)
+               goto fail;
 
-       match_strvec = ec_strvec_ndup(strvec, 0, ret);
-       if (match_strvec == NULL) {
-               ret = -ENOMEM;
-               goto free;
+       if (ret == EC_PARSE_NOMATCH) {
+               if (!is_root) {
+                       ec_parse_unlink_child(state, child);
+                       ec_parse_free(child);
+               }
+               return ret;
        }
 
+       match_strvec = ec_strvec_ndup(strvec, 0, ret);
+       if (match_strvec == NULL)
+               goto fail;
+
        child->strvec = match_strvec;
 
        return ret;
 
-free:
+fail:
        if (!is_root) {
                ec_parse_unlink_child(state, child);
                ec_parse_free(child);
        }
-       return ret;
+       return -1;
 }
 
 int ec_node_parse_child(const struct ec_node *node, struct ec_parse *state,
@@ -238,12 +252,12 @@ static void __ec_parse_dump(FILE *out,
 {
        struct ec_parse *child;
        const struct ec_strvec *vec;
-       const char *id, *typename = "none";
+       const char *id = "none", *typename = "none";
 
        /* node can be null when parsing is incomplete */
        if (parse->node != NULL) {
                id = parse->node->id;
-               typename = parse->node->type->name;
+               typename = ec_node_type(parse->node)->name;
        }
 
        fprintf(out, "%*s" "type=%s id=%s vec=",
@@ -366,20 +380,16 @@ struct ec_parse *ec_parse_iter_next(struct ec_parse *parse)
 struct ec_parse *ec_parse_find_first(struct ec_parse *parse,
        const char *id)
 {
-       struct ec_parse *child, *ret;
+       struct ec_parse *iter;
 
        if (parse == NULL)
                return NULL;
 
-       if (parse->node != NULL &&
-                       parse->node->id != NULL &&
-                       !strcmp(parse->node->id, id))
-               return parse;
-
-       TAILQ_FOREACH(child, &parse->children, next) {
-               ret = ec_parse_find_first(child, id);
-               if (ret != NULL)
-                       return ret;
+       for (iter = parse; iter != NULL; iter = ec_parse_iter_next(iter)) {
+               if (iter->node != NULL &&
+                               iter->node->id != NULL &&
+                               !strcmp(iter->node->id, id))
+                       return iter;
        }
 
        return NULL;
@@ -421,3 +431,110 @@ size_t ec_parse_matches(const struct ec_parse *parse)
 
        return 1;
 }
+
+/* LCOV_EXCL_START */
+static int ec_parse_testcase(void)
+{
+       struct ec_node *node = NULL;
+       struct ec_parse *p = NULL, *p2 = NULL;
+       const struct ec_parse *pc;
+       FILE *f = NULL;
+       char *buf = NULL;
+       size_t buflen = 0;
+       int testres = 0;
+       int ret;
+
+       node = ec_node_sh_lex(EC_NO_ID,
+                       EC_NODE_SEQ(EC_NO_ID,
+                               ec_node_str("id_x", "x"),
+                               ec_node_str("id_y", "y")));
+       if (node == NULL)
+               goto fail;
+
+       p = ec_node_parse(node, "xcdscds");
+       testres |= EC_TEST_CHECK(
+               p != NULL && !ec_parse_matches(p),
+               "parse should not match\n");
+
+       f = open_memstream(&buf, &buflen);
+       if (f == NULL)
+               goto fail;
+       ec_parse_dump(f, p);
+       fclose(f);
+       f = NULL;
+
+       testres |= EC_TEST_CHECK(
+               strstr(buf, "no match"), "bad dump\n");
+       free(buf);
+       buf = NULL;
+       ec_parse_free(p);
+
+       p = ec_node_parse(node, "x y");
+       testres |= EC_TEST_CHECK(
+               p != NULL && ec_parse_matches(p),
+               "parse should match\n");
+       testres |= EC_TEST_CHECK(
+               ec_parse_len(p) == 1, "bad parse len\n");
+
+       ret = ec_keyval_set(ec_parse_get_attrs(p), "key", "val", NULL);
+       testres |= EC_TEST_CHECK(ret == 0,
+               "cannot set parse attribute\n");
+
+       p2 = ec_parse_dup(p);
+       testres |= EC_TEST_CHECK(
+               p2 != NULL && ec_parse_matches(p2),
+               "parse should match\n");
+       ec_parse_free(p2);
+       p2 = NULL;
+
+       pc = ec_parse_find_first(p, "id_x");
+       testres |= EC_TEST_CHECK(pc != NULL, "cannot find id_x");
+       testres |= EC_TEST_CHECK(pc != NULL &&
+               ec_parse_get_parent(pc) != NULL &&
+               ec_parse_get_parent(ec_parse_get_parent(pc)) == p,
+               "invalid parent\n");
+
+       pc = ec_parse_find_first(p, "id_y");
+       testres |= EC_TEST_CHECK(pc != NULL, "cannot find id_y");
+       pc = ec_parse_find_first(p, "id_dezdezdez");
+       testres |= EC_TEST_CHECK(pc == NULL, "should not find bad id");
+
+
+       f = open_memstream(&buf, &buflen);
+       if (f == NULL)
+               goto fail;
+       ec_parse_dump(f, p);
+       fclose(f);
+       f = NULL;
+
+       testres |= EC_TEST_CHECK(
+               strstr(buf, "type=sh_lex id=no-id") &&
+               strstr(buf, "type=seq id=no-id") &&
+               strstr(buf, "type=str id=id_x") &&
+               strstr(buf, "type=str id=id_x"),
+               "bad dump\n");
+       free(buf);
+       buf = NULL;
+
+       ec_parse_free(p);
+       ec_node_free(node);
+       return testres;
+
+fail:
+       ec_parse_free(p2);
+       ec_parse_free(p);
+       ec_node_free(node);
+       if (f != NULL)
+               fclose(f);
+       free(buf);
+
+       return -1;
+}
+/* LCOV_EXCL_STOP */
+
+static struct ec_test ec_parse_test = {
+       .name = "parse",
+       .test = ec_parse_testcase,
+};
+
+EC_TEST_REGISTER(ec_parse_test);