/* This file is part of Eclat Copyright (C) 2012-2014 Sergey Poznyakoff Eclat is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3, or (at your option) any later version. Eclat is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Eclat. If not, see . */ #include #include "libeclat.h" #include #define NODEREF_TEXT 0x01 /* Text is being constructed */ struct eclat_partial_tree { int flags; struct grecs_txtacc *acc; struct grecs_symtab *texttab; struct grecs_list *stack; /* Node stack */ }; static void pt_free_node(void *ptr) { struct grecs_node *node = ptr; grecs_node_free(node); } struct eclat_partial_tree * eclat_partial_tree_create() { struct eclat_partial_tree *pt = grecs_zalloc(sizeof(*pt)); pt->acc = grecs_txtacc_create(); pt->stack = grecs_list_create(); pt->stack->free_entry = pt_free_node; return pt; } void eclat_partial_tree_destroy(struct eclat_partial_tree *pt) { grecs_txtacc_free(pt->acc); if (pt->texttab) grecs_symtab_free(pt->texttab); grecs_list_free(pt->stack); free(pt); } struct grecs_node * eclat_partial_tree_finish(struct eclat_partial_tree *pt) { struct grecs_node *root = grecs_node_create(grecs_node_root, NULL); root->v.texttab = pt->texttab; pt->texttab = NULL; grecs_node_bind(root, grecs_list_pop(pt->stack), 1); eclat_partial_tree_destroy(pt); return root; } static struct grecs_node * gettos(struct eclat_partial_tree *nref) { if (nref->stack->head) return nref->stack->head->data; return NULL; } void eclat_partial_tree_data_handler(void *data, const XML_Char *s, int len) { struct eclat_partial_tree *noderef = data; grecs_txtacc_grow(noderef->acc, s, len); noderef->flags |= NODEREF_TEXT; } /* Start handler: create a node and push it on stack */ void eclat_partial_tree_start_handler(void *data, const XML_Char *name, const XML_Char **atts) { struct eclat_partial_tree *noderef = data; struct grecs_node *node; if (noderef->flags & NODEREF_TEXT) { grecs_txtacc_free_string(noderef->acc, grecs_txtacc_finish(noderef->acc, 0)); noderef->flags &= ~NODEREF_TEXT; } node = grecs_node_create((enum grecs_node_type)-1, NULL); node->ident = grecs_strdup(name); grecs_list_push(noderef->stack, node); noderef->flags &= ~NODEREF_TEXT; } void eclat_partial_tree_end_handler(void *data, const XML_Char *name) { struct eclat_partial_tree *noderef = data; struct grecs_node *node = grecs_list_pop(noderef->stack); struct grecs_node *tos = gettos(noderef); if (noderef->flags & NODEREF_TEXT) { char *s, *p; grecs_value_t *ptr; grecs_txtacc_grow_char(noderef->acc, 0); s = grecs_txtacc_finish(noderef->acc, 1); for (p = s; *p && isspace(*p); p++) ; if (!*p) { free(s); if (node->type == -1) node->type = grecs_node_block; } else { switch (node->type) { default: node->type = grecs_node_stmt; ptr = grecs_malloc(sizeof(*ptr)); ptr->type = GRECS_TYPE_STRING; ptr->v.string = s; node->v.value = ptr; break; case grecs_node_root: abort(); /* should not happen */ case grecs_node_stmt: case grecs_node_block: /* FIXME: error message */ /* ignoring additional textual data */ free(s); } } noderef->flags &= ~NODEREF_TEXT; } else if (node->type == (enum grecs_node_type)-1) node->type = grecs_node_block; if (!tos) grecs_list_push(noderef->stack, node); else { switch (tos->type) { default: tos->type = grecs_node_block; break; case grecs_node_root: abort(); /* should not happen */ case grecs_node_stmt: /* FIXME: error message */ /* ignoring additional textual data */ grecs_value_free(tos->v.value); tos->type = grecs_node_block; break; } grecs_node_bind(tos, node, 1); } }