diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2012-09-20 15:52:18 +0300 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2012-09-20 15:52:18 +0300 |
commit | 7f3dd0599ac3fb3a69c512b0ecfd043c67ca94ee (patch) | |
tree | 422bda7fdce2709ea0b4c67c42e6f9a7cecc4918 /lib | |
parent | 205d53a8e930d3fd126075ab083d316cc344ebaf (diff) | |
download | eclat-7f3dd0599ac3fb3a69c512b0ecfd043c67ca94ee.tar.gz eclat-7f3dd0599ac3fb3a69c512b0ecfd043c67ca94ee.tar.bz2 |
Parse returned XML into a grecs tree structure.
* lib/xmltree.c: New file.
* lib/Makefile.am: Add new file.
* lib/libeclat.h: Include expat.h and grecs.h
(eclat_partial_tree_t): New typedef.
(eclat_partial_tree_create,eclat_partial_tree_destroy)
(eclat_partial_tree_finish,eclat_partial_tree_data_handler)
(eclat_partial_tree_start_handler)
(eclat_partial_tree_end_handler): New protos.
* src/eclat.c (main): Initialize XML parser with eclat_partial_tree
handlers and bind it to the CURL output handler.
* tests/.gitignore: Add txml
* tests/Makefile.am (TESTSUITE_AT): Add xml01.at
Build txml
* tests/testsuite.at: Include xml01.at
* tests/txml.c: New file.
* tests/xml01.at: New file.
Diffstat (limited to 'lib')
-rw-r--r-- | lib/Makefile.am | 3 | ||||
-rw-r--r-- | lib/libeclat.h | 16 | ||||
-rw-r--r-- | lib/xmltree.c | 188 |
3 files changed, 205 insertions, 2 deletions
diff --git a/lib/Makefile.am b/lib/Makefile.am index 7843433..2c1d3a8 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -28,7 +28,8 @@ libeclat_a_SOURCES=\ reqsign.c\ sha1.c\ sha1.h\ - urlencode.c + urlencode.c\ + xmltree.c AM_LDFLAGS = $(CURL_LIBS) INCLUDES = -I$(top_srcdir)/grecs/src/ $(CURL_CFLAGS) diff --git a/lib/libeclat.h b/lib/libeclat.h index 59ff0f6..670c51b 100644 --- a/lib/libeclat.h +++ b/lib/libeclat.h @@ -15,6 +15,8 @@ along with Eclat. If not, see <http://www.gnu.org/licenses/>. */ #include <stddef.h> +#include <expat.h> +#include "grecs.h" void hmac_sha1(const void *text, size_t textlen, const void *key, size_t keylen, @@ -56,4 +58,16 @@ int eclat_query_signature(struct ec2_query *req, char *secret); char *eclat_query_to_url(struct ec2_query *req, char **post_params); void eclat_query_encode(struct ec2_query *q); - + +typedef struct eclat_partial_tree *eclat_partial_tree_t; + +eclat_partial_tree_t eclat_partial_tree_create(void); +void eclat_partial_tree_destroy(eclat_partial_tree_t); +struct grecs_node *eclat_partial_tree_finish(eclat_partial_tree_t); +void eclat_partial_tree_data_handler(void *data, const XML_Char *s, int len); +void eclat_partial_tree_start_handler(void *data, const XML_Char *name, + const XML_Char **atts); +void eclat_partial_tree_end_handler(void *data, const XML_Char *name); + + + diff --git a/lib/xmltree.c b/lib/xmltree.c new file mode 100644 index 0000000..e5d4772 --- /dev/null +++ b/lib/xmltree.c @@ -0,0 +1,188 @@ +/* This file is part of Eclat + Copyright (C) 2012 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 <http://www.gnu.org/licenses/>. */ + +#include <config.h> +#include "libeclat.h" + +#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 char * +install_text(struct eclat_partial_tree *nref, const char *str) +{ + struct grecs_syment key; + struct grecs_syment *ent; + int install = 1; + + if (!nref->texttab) { + nref->texttab = grecs_symtab_create_default( + sizeof(struct grecs_syment)); + if (!nref->texttab) + grecs_alloc_die(); + } + + key.name = (char*) str; + ent = grecs_symtab_lookup_or_install(nref->texttab, &key, &install); + if (!ent) + grecs_alloc_die(); + return ent->name; +} + +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; + } + + 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); + } +} |