X-Git-Url: http://git.droids-corp.org/?a=blobdiff_plain;f=lib%2Fecoli_parsed.c;h=c2e7c8e2baa76dc53cfab69d55b14cc092118121;hb=cb46a57b224f228fb0b14170b49f84b07e0fb78e;hp=e8f3cb9b9ea93b860f1a1eaac95f1359e57fd074;hpb=ff1f48e335ca77cc97e49ea86b292233731ecb78;p=protos%2Flibecoli.git diff --git a/lib/ecoli_parsed.c b/lib/ecoli_parsed.c index e8f3cb9..c2e7c8e 100644 --- a/lib/ecoli_parsed.c +++ b/lib/ecoli_parsed.c @@ -1,28 +1,5 @@ -/* - * Copyright (c) 2016, Olivier MATZ - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * * Neither the name of the University of California, Berkeley nor the - * names of its contributors may be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +/* SPDX-License-Identifier: BSD-3-Clause + * Copyright 2016, Olivier MATZ */ #include @@ -32,6 +9,7 @@ #include #include +#include #include #include #include @@ -39,79 +17,85 @@ #include #include -int ec_node_parse_child(struct ec_node *node, struct ec_parsed *state, - const struct ec_strvec *strvec) +TAILQ_HEAD(ec_parsed_list, ec_parsed); + +struct ec_parsed { + TAILQ_ENTRY(ec_parsed) next; + struct ec_parsed_list children; + struct ec_parsed *parent; + const struct ec_node *node; + struct ec_strvec *strvec; + struct ec_keyval *attrs; +}; + +static int __ec_node_parse_child(const struct ec_node *node, + struct ec_parsed *state, + bool is_root, const struct ec_strvec *strvec) { struct ec_strvec *match_strvec; - struct ec_parsed *child; + struct ec_parsed *child = NULL; 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; + if (!is_root) { + child = ec_parsed(node); + 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; + ec_parsed_link_child(state, child); + } else { + child = state; } + ret = node->type->parse(node, child, strvec); + if (ret < 0 || ret == EC_PARSED_NOMATCH) + goto free; match_strvec = ec_strvec_ndup(strvec, 0, ret); - if (match_strvec == NULL) - return -ENOMEM; + if (match_strvec == NULL) { + ret = -ENOMEM; + goto free; + } child->strvec = match_strvec; return ret; + +free: + if (!is_root) { + ec_parsed_unlink_child(state, child); + ec_parsed_free(child); + } + return ret; } -struct ec_parsed *ec_node_parse_strvec(struct ec_node *node, +int ec_node_parse_child(const struct ec_node *node, struct ec_parsed *state, + const struct ec_strvec *strvec) +{ + assert(state != NULL); + return __ec_node_parse_child(node, state, false, strvec); +} + +struct ec_parsed *ec_node_parse_strvec(const struct ec_node *node, const struct ec_strvec *strvec) { - struct ec_parsed *parsed = ec_parsed(); - struct ec_parsed *child_parsed; + struct ec_parsed *parsed = ec_parsed(node); 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); + ret = __ec_node_parse_child(node, parsed, true, strvec); + if (ret < 0) { ec_parsed_free(parsed); - parsed = child_parsed; + return NULL; } return parsed; } -struct ec_parsed *ec_node_parse(struct ec_node *node, const char *str) +struct ec_parsed *ec_node_parse(const struct ec_node *node, const char *str) { struct ec_strvec *strvec = NULL; struct ec_parsed *parsed = NULL; @@ -137,7 +121,7 @@ struct ec_parsed *ec_node_parse(struct ec_node *node, const char *str) return NULL; } -struct ec_parsed *ec_parsed(void) +struct ec_parsed *ec_parsed(const struct ec_node *node) { struct ec_parsed *parsed = NULL; @@ -147,6 +131,7 @@ struct ec_parsed *ec_parsed(void) TAILQ_INIT(&parsed->children); + parsed->node = node; parsed->attrs = ec_keyval(); if (parsed->attrs == NULL) goto fail; @@ -161,6 +146,64 @@ struct ec_parsed *ec_parsed(void) return NULL; } +static struct ec_parsed * +__ec_parsed_dup(const struct ec_parsed *root, const struct ec_parsed *ref, + struct ec_parsed **new_ref) +{ + struct ec_parsed *dup = NULL; + struct ec_parsed *child, *dup_child; + struct ec_keyval *attrs = NULL; + + if (root == NULL) + return NULL; + + dup = ec_parsed(root->node); + if (dup == NULL) + return NULL; + + if (root == ref) + *new_ref = dup; + + attrs = ec_keyval_dup(root->attrs); + if (attrs == NULL) + goto fail; + ec_keyval_free(dup->attrs); + dup->attrs = attrs; + + if (root->strvec != NULL) { + dup->strvec = ec_strvec_dup(root->strvec); + if (dup->strvec == NULL) + goto fail; + } + + TAILQ_FOREACH(child, &root->children, next) { + dup_child = __ec_parsed_dup(child, ref, new_ref); + if (dup_child == NULL) + goto fail; + ec_parsed_link_child(dup, dup_child); + } + + return dup; + +fail: + ec_parsed_free(dup); + return NULL; +} + +struct ec_parsed *ec_parsed_dup(const struct ec_parsed *parsed) +{ + const struct ec_parsed *root; + struct ec_parsed *dup_root, *dup = NULL; + + root = ec_parsed_get_root(parsed); + dup_root = __ec_parsed_dup(root, parsed, &dup); + if (dup_root == NULL) + return NULL; + assert(dup != NULL); + + return dup; +} + void ec_parsed_free_children(struct ec_parsed *parsed) { struct ec_parsed *child; @@ -171,6 +214,7 @@ void ec_parsed_free_children(struct ec_parsed *parsed) while (!TAILQ_EMPTY(&parsed->children)) { child = TAILQ_FIRST(&parsed->children); TAILQ_REMOVE(&parsed->children, child, next); + child->parent = NULL; ec_parsed_free(child); } } @@ -180,6 +224,9 @@ void ec_parsed_free(struct ec_parsed *parsed) if (parsed == NULL) return; + ec_assert_print(parsed->parent == NULL, + "parent not NULL in ec_parsed_free()"); + ec_parsed_free_children(parsed); ec_strvec_free(parsed->strvec); ec_keyval_free(parsed->attrs); @@ -191,40 +238,37 @@ 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, *typename = "none"; + /* node can be null when parsing is incomplete */ if (parsed->node != NULL) { - if (parsed->node->id != NULL) - id = parsed->node->id; + id = parsed->node->id; typename = parsed->node->type->name; } - /* XXX enhance */ - for (i = 0; i < indent; i++) { - if (i % 2) - fprintf(out, " "); - else - fprintf(out, "|"); - } - - fprintf(out, "node_type=%s id=%s vec=", typename, id); + fprintf(out, "%*s" "type=%s id=%s vec=", + (int)indent * 4, "", typename, id); vec = ec_parsed_strvec(parsed); ec_strvec_dump(out, vec); TAILQ_FOREACH(child, &parsed->children, next) - __ec_parsed_dump(out, child, indent + 2); + __ec_parsed_dump(out, child, indent + 1); } void ec_parsed_dump(FILE *out, const struct ec_parsed *parsed) { - fprintf(out, "------------------- parsed dump:\n"); //XXX + fprintf(out, "------------------- parsed dump:\n"); if (parsed == NULL) { fprintf(out, "parsed is NULL, error in parse\n"); return; } - if (!ec_parsed_matches(parsed)) { + + /* only exist if it does not match (strvec == NULL) and if it + * does not have children: an incomplete parse, like those + * generated by complete() don't match but have children that + * may match. */ + if (!ec_parsed_matches(parsed) && TAILQ_EMPTY(&parsed->children)) { fprintf(out, "no match\n"); return; } @@ -232,14 +276,14 @@ void ec_parsed_dump(FILE *out, const struct ec_parsed *parsed) __ec_parsed_dump(out, parsed, 0); } -void ec_parsed_add_child(struct ec_parsed *parsed, +void ec_parsed_link_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, // XXX rename del in unlink? +void ec_parsed_unlink_child(struct ec_parsed *parsed, struct ec_parsed *child) { TAILQ_REMOVE(&parsed->children, child, next); @@ -247,21 +291,42 @@ void ec_parsed_del_child(struct ec_parsed *parsed, // XXX rename del in unlink? } struct ec_parsed * -ec_parsed_get_last_child(struct ec_parsed *parsed) +ec_parsed_get_first_child(const struct ec_parsed *parsed) +{ + return TAILQ_FIRST(&parsed->children); +} + +struct ec_parsed * +ec_parsed_get_last_child(const 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 *ec_parsed_get_next(const struct ec_parsed *parsed) +{ + return TAILQ_NEXT(parsed, next); +} + +bool ec_parsed_has_child(const struct ec_parsed *parsed) +{ + return !TAILQ_EMPTY(&parsed->children); +} + +const struct ec_node *ec_parsed_get_node(const struct ec_parsed *parsed) +{ + return parsed->node; +} + +void ec_parsed_del_last_child(struct ec_parsed *parsed) { struct ec_parsed *child; child = ec_parsed_get_last_child(parsed); - ec_parsed_del_child(parsed, child); + ec_parsed_unlink_child(parsed, child); ec_parsed_free(child); } -struct ec_parsed *ec_parsed_get_root(struct ec_parsed *parsed) +struct ec_parsed *__ec_parsed_get_root(struct ec_parsed *parsed) { if (parsed == NULL) return NULL; @@ -272,7 +337,7 @@ struct ec_parsed *ec_parsed_get_root(struct ec_parsed *parsed) return parsed; } -struct ec_parsed *ec_parsed_get_parent(struct ec_parsed *parsed) +struct ec_parsed *ec_parsed_get_parent(const struct ec_parsed *parsed) { if (parsed == NULL) return NULL; @@ -280,6 +345,24 @@ struct ec_parsed *ec_parsed_get_parent(struct ec_parsed *parsed) return parsed->parent; } +struct ec_parsed *ec_parsed_iter_next(struct ec_parsed *parsed) +{ + struct ec_parsed *child, *parent, *next; + + child = TAILQ_FIRST(&parsed->children); + if (child != NULL) + return child; + parent = parsed->parent; + while (parent != NULL) { + next = TAILQ_NEXT(parsed, next); + if (next != NULL) + return next; + parsed = parent; + parent = parsed->parent; + } + return NULL; +} + struct ec_parsed *ec_parsed_find_first(struct ec_parsed *parsed, const char *id) { @@ -302,6 +385,15 @@ struct ec_parsed *ec_parsed_find_first(struct ec_parsed *parsed, return NULL; } +struct ec_keyval * +ec_parsed_get_attrs(struct ec_parsed *parsed) +{ + if (parsed == NULL) + return NULL; + + return parsed->attrs; +} + const struct ec_strvec *ec_parsed_strvec(const struct ec_parsed *parsed) { if (parsed == NULL || parsed->strvec == NULL) @@ -324,7 +416,7 @@ size_t ec_parsed_matches(const struct ec_parsed *parsed) if (parsed == NULL) return 0; - if (parsed->node == NULL && TAILQ_EMPTY(&parsed->children)) // XXX both needed? + if (parsed->strvec == NULL) return 0; return 1;