aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/Makefile.am3
-rw-r--r--lib/libeclat.h16
-rw-r--r--lib/xmltree.c188
-rw-r--r--src/eclat.c73
-rw-r--r--tests/.gitignore1
-rw-r--r--tests/Makefile.am8
-rw-r--r--tests/testsuite.at4
-rw-r--r--tests/txml.c88
-rw-r--r--tests/xml01.at63
9 files changed, 438 insertions, 6 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=\
28 reqsign.c\ 28 reqsign.c\
29 sha1.c\ 29 sha1.c\
30 sha1.h\ 30 sha1.h\
31 urlencode.c 31 urlencode.c\
32 xmltree.c
32 33
33AM_LDFLAGS = $(CURL_LIBS) 34AM_LDFLAGS = $(CURL_LIBS)
34INCLUDES = -I$(top_srcdir)/grecs/src/ $(CURL_CFLAGS) 35INCLUDES = -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 @@
15 along with Eclat. If not, see <http://www.gnu.org/licenses/>. */ 15 along with Eclat. If not, see <http://www.gnu.org/licenses/>. */
16 16
17#include <stddef.h> 17#include <stddef.h>
18#include <expat.h>
19#include "grecs.h"
18 20
19void hmac_sha1(const void *text, size_t textlen, 21void hmac_sha1(const void *text, size_t textlen,
20 const void *key, size_t keylen, 22 const void *key, size_t keylen,
@@ -56,4 +58,16 @@ int eclat_query_signature(struct ec2_query *req, char *secret);
56char *eclat_query_to_url(struct ec2_query *req, char **post_params); 58char *eclat_query_to_url(struct ec2_query *req, char **post_params);
57 59
58void eclat_query_encode(struct ec2_query *q); 60void eclat_query_encode(struct ec2_query *q);
59 61
62typedef struct eclat_partial_tree *eclat_partial_tree_t;
63
64eclat_partial_tree_t eclat_partial_tree_create(void);
65void eclat_partial_tree_destroy(eclat_partial_tree_t);
66struct grecs_node *eclat_partial_tree_finish(eclat_partial_tree_t);
67void eclat_partial_tree_data_handler(void *data, const XML_Char *s, int len);
68void eclat_partial_tree_start_handler(void *data, const XML_Char *name,
69 const XML_Char **atts);
70void eclat_partial_tree_end_handler(void *data, const XML_Char *name);
71
72
73
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 @@
1/* This file is part of Eclat
2 Copyright (C) 2012 Sergey Poznyakoff
3
4 Eclat is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 3, or (at your option)
7 any later version.
8
9 Eclat is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with Eclat. If not, see <http://www.gnu.org/licenses/>. */
16
17#include <config.h>
18#include "libeclat.h"
19
20#define NODEREF_TEXT 0x01 /* Text is being constructed */
21
22struct eclat_partial_tree {
23 int flags;
24 struct grecs_txtacc *acc;
25 struct grecs_symtab *texttab;
26 struct grecs_list *stack; /* Node stack */
27};
28
29static void
30pt_free_node(void *ptr)
31{
32 struct grecs_node *node = ptr;
33 grecs_node_free(node);
34}
35
36struct eclat_partial_tree *
37eclat_partial_tree_create()
38{
39 struct eclat_partial_tree *pt = grecs_zalloc(sizeof(*pt));
40 pt->acc = grecs_txtacc_create();
41 pt->stack = grecs_list_create();
42 pt->stack->free_entry = pt_free_node;
43 return pt;
44}
45
46void
47eclat_partial_tree_destroy(struct eclat_partial_tree *pt)
48{
49 grecs_txtacc_free(pt->acc);
50 if (pt->texttab)
51 grecs_symtab_free(pt->texttab);
52 grecs_list_free(pt->stack);
53 free(pt);
54}
55
56struct grecs_node *
57eclat_partial_tree_finish(struct eclat_partial_tree *pt)
58{
59 struct grecs_node *root = grecs_node_create(grecs_node_root, NULL);
60 root->v.texttab = pt->texttab;
61 pt->texttab = NULL;
62 grecs_node_bind(root, grecs_list_pop(pt->stack), 1);
63 eclat_partial_tree_destroy(pt);
64 return root;
65}
66
67
68static char *
69install_text(struct eclat_partial_tree *nref, const char *str)
70{
71 struct grecs_syment key;
72 struct grecs_syment *ent;
73 int install = 1;
74
75 if (!nref->texttab) {
76 nref->texttab = grecs_symtab_create_default(
77 sizeof(struct grecs_syment));
78 if (!nref->texttab)
79 grecs_alloc_die();
80 }
81
82 key.name = (char*) str;
83 ent = grecs_symtab_lookup_or_install(nref->texttab, &key, &install);
84 if (!ent)
85 grecs_alloc_die();
86 return ent->name;
87}
88
89static struct grecs_node *
90gettos(struct eclat_partial_tree *nref)
91{
92 if (nref->stack->head)
93 return nref->stack->head->data;
94 return NULL;
95}
96
97void
98eclat_partial_tree_data_handler(void *data, const XML_Char *s, int len)
99{
100 struct eclat_partial_tree *noderef = data;
101
102 grecs_txtacc_grow(noderef->acc, s, len);
103 noderef->flags |= NODEREF_TEXT;
104}
105
106/* Start handler: create a node and push it on stack */
107void
108eclat_partial_tree_start_handler(void *data, const XML_Char *name,
109 const XML_Char **atts)
110{
111 struct eclat_partial_tree *noderef = data;
112 struct grecs_node *node;
113
114 if (noderef->flags & NODEREF_TEXT) {
115 grecs_txtacc_free_string(noderef->acc,
116 grecs_txtacc_finish(noderef->acc, 0));
117 noderef->flags &= ~NODEREF_TEXT;
118 }
119
120 node = grecs_node_create((enum grecs_node_type)-1, NULL);
121 node->ident = grecs_strdup(name);
122 grecs_list_push(noderef->stack, node);
123 noderef->flags &= ~NODEREF_TEXT;
124}
125
126void
127eclat_partial_tree_end_handler(void *data, const XML_Char *name)
128{
129 struct eclat_partial_tree *noderef = data;
130 struct grecs_node *node = grecs_list_pop(noderef->stack);
131 struct grecs_node *tos = gettos(noderef);
132
133 if (noderef->flags & NODEREF_TEXT) {
134 char *s, *p;
135 grecs_value_t *ptr;
136
137 grecs_txtacc_grow_char(noderef->acc, 0);
138 s = grecs_txtacc_finish(noderef->acc, 1);
139
140 for (p = s; *p && isspace(*p); p++)
141 ;
142 if (!*p) {
143 free(s);
144 if (node->type == -1)
145 node->type = grecs_node_block;
146 } else {
147 switch (node->type) {
148 default:
149 node->type = grecs_node_stmt;
150 ptr = grecs_malloc(sizeof(*ptr));
151 ptr->type = GRECS_TYPE_STRING;
152 ptr->v.string = s;
153 node->v.value = ptr;
154 break;
155
156 case grecs_node_root:
157 abort(); /* should not happen */
158
159 case grecs_node_stmt:
160 case grecs_node_block:
161 /* FIXME: error message */
162 /* ignoring additional textual data */
163 free(s);
164 }
165 }
166 noderef->flags &= ~NODEREF_TEXT;
167 }
168
169 if (!tos)
170 grecs_list_push(noderef->stack, node);
171 else {
172 switch (tos->type) {
173 default:
174 tos->type = grecs_node_block;
175 break;
176 case grecs_node_root:
177 abort(); /* should not happen */
178 case grecs_node_stmt:
179 /* FIXME: error message */
180 /* ignoring additional textual data */
181 grecs_value_free(tos->v.value);
182 tos->type = grecs_node_block;
183 break;
184 }
185
186 grecs_node_bind(tos, node, 1);
187 }
188}
diff --git a/src/eclat.c b/src/eclat.c
index c5994fe..3703376 100644
--- a/src/eclat.c
+++ b/src/eclat.c
@@ -169,7 +169,52 @@ eclat_trace_fun(CURL *handle, curl_infotype type,
169 dump(text, stderr, (unsigned char *)data, size); 169 dump(text, stderr, (unsigned char *)data, size);
170 return 0; 170 return 0;
171} 171}
172
173static void
174dump_text(FILE *stream, int line, int column, const char *text, size_t len)
175{
176 fprintf(stream, "%02d:%02d: ", line, column);
177 while (len--) {
178 char c = *text++;
179 if (c == '\r')
180 continue;
181 fputc(c, stream);
182 ++column;
183 if (c == '\n') {
184 ++line;
185 column = 0;
186 fprintf(stream, "%02d:%02d: ", line, column);
187 }
188 }
189 fputc('\n', stream);
190}
172 191
192static size_t
193write_callback(void *ptr, size_t size, size_t nmemb, void *data)
194{
195 size_t realsize = size * nmemb;
196 XML_Parser parser = data;
197 enum XML_Status status;
198 int line = XML_GetCurrentLineNumber(parser);
199 int column = XML_GetCurrentColumnNumber(parser);
200
201 /* FIXME: Debugging level. */
202 if (debug_level[ECLAT_DEBCAT_MAIN] > 10) {
203 dump_text(stderr, line, column, ptr, realsize);
204 }
205 status = XML_Parse(parser, ptr, realsize, 0);
206 if (status == XML_STATUS_ERROR) {
207 enum XML_Error error = XML_GetErrorCode(parser);
208
209 line = XML_GetCurrentLineNumber(parser);
210 column = XML_GetCurrentColumnNumber(parser);
211
212 /* FIXME: better diagnostics. */
213 die(EX_SOFTWARE, "XML parse error at %d:%d: %s",
214 line, column, XML_ErrorString(error));
215 }
216 return realsize;
217}
173 218
174 219
175#include "cmdline.h" 220#include "cmdline.h"
@@ -187,6 +232,9 @@ main(int argc, char **argv)
187 int index, rc; 232 int index, rc;
188 struct grecs_node *tree; 233 struct grecs_node *tree;
189 CURL *curl; 234 CURL *curl;
235 XML_Parser parser;
236 eclat_partial_tree_t part;
237 struct grecs_node *xmltree;
190 238
191 set_program_name(argv[0]); 239 set_program_name(argv[0]);
192 config_init(); 240 config_init();
@@ -250,8 +298,33 @@ main(int argc, char **argv)
250 curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, 298 curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION,
251 eclat_trace_fun); 299 eclat_trace_fun);
252 } 300 }
301
302
303 /* Create XML parser */
304 parser = XML_ParserCreate("UTF-8");
305 if (!parser)
306 die(EX_SOFTWARE, "cannot create XML parser");
307
308 XML_SetElementHandler(parser,
309 eclat_partial_tree_start_handler,
310 eclat_partial_tree_end_handler);
311 XML_SetCharacterDataHandler(parser,
312 eclat_partial_tree_data_handler);
313 part = eclat_partial_tree_create();
314 XML_SetUserData(parser, part);
315
316 curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback);
317 curl_easy_setopt(curl, CURLOPT_WRITEDATA, parser);
253 318
254 rc = handler_tab[eclat_command](curl, argc, argv); 319 rc = handler_tab[eclat_command](curl, argc, argv);
255 curl_easy_cleanup(curl); 320 curl_easy_cleanup(curl);
321 XML_Parse(parser, "", 0, 1);
322
323 xmltree = eclat_partial_tree_finish(part);
324
325 grecs_print_node(xmltree, GRECS_NODE_FLAG_DEFAULT, stdout);
326 fputc('\n', stdout);
327
328
256 exit(rc); 329 exit(rc);
257} 330}
diff --git a/tests/.gitignore b/tests/.gitignore
index 9a2f830..99d3c9c 100644
--- a/tests/.gitignore
+++ b/tests/.gitignore
@@ -6,3 +6,4 @@ testsuite.dir
6testsuite.log 6testsuite.log
7thmac 7thmac
8turlenc 8turlenc
9txml
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 6d95607..82cae7e 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -44,7 +44,8 @@ TESTSUITE_AT = \
44 hmac02.at\ 44 hmac02.at\
45 hmac03.at\ 45 hmac03.at\
46 testsuite.at\ 46 testsuite.at\
47 urlenc01.at 47 urlenc01.at\
48 xml01.at
48 49
49TESTSUITE = $(srcdir)/testsuite 50TESTSUITE = $(srcdir)/testsuite
50M4=m4 51M4=m4
@@ -69,10 +70,11 @@ check-local: atconfig atlocal $(TESTSUITE)
69 70
70noinst_PROGRAMS = \ 71noinst_PROGRAMS = \
71 thmac\ 72 thmac\
72 turlenc 73 turlenc\
74 txml
73 75
74LDADD = ../lib/libeclat.a ../grecs/src/libgrecs.a 76LDADD = ../lib/libeclat.a ../grecs/src/libgrecs.a
75INCLUDES = -I$(top_srcdir)/lib 77INCLUDES = -I$(top_srcdir)/grecs/src/ -I$(top_srcdir)/lib
76 78
77 79
78 80
diff --git a/tests/testsuite.at b/tests/testsuite.at
index c368490..f40b8a7 100644
--- a/tests/testsuite.at
+++ b/tests/testsuite.at
@@ -24,7 +24,9 @@ m4_include(hmac01.at)
24m4_include(hmac02.at) 24m4_include(hmac02.at)
25m4_include(hmac03.at) 25m4_include(hmac03.at)
26 26
27AT_BANNER([URL encode]) 27AT_BANNER([URL Encode])
28m4_include([urlenc01.at]) 28m4_include([urlenc01.at])
29 29
30AT_BANNER([XML Processing])
31m4_include([xml01.at])
30# End of testsuite.at 32# End of testsuite.at
diff --git a/tests/txml.c b/tests/txml.c
new file mode 100644
index 0000000..e00abc2
--- /dev/null
+++ b/tests/txml.c
@@ -0,0 +1,88 @@
1/* This file is part of Eclat.
2 Copyright (C) 2012 Sergey Poznyakoff.
3
4 Eclat is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 3, or (at your option)
7 any later version.
8
9 Eclat is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with Eclat. If not, see <http://www.gnu.org/licenses/>. */
16
17#include <config.h>
18#include <stdlib.h>
19#include <stdio.h>
20#include <string.h>
21#include "libeclat.h"
22
23int
24main(int argc, char **argv)
25{
26 XML_Parser parser;
27 eclat_partial_tree_t part;
28 FILE *fp;
29 char buffer[128];
30 size_t size;
31 const char *filename;
32 struct grecs_node *tree;
33
34 if (argc > 2) {
35 fprintf(stderr, "usage: %s [string]\n", argv[0]);
36 return 1;
37 }
38
39 if (argc == 1 || strcmp(argv[1], "-") == 0) {
40 fp = stdin;
41 filename = "<stdin>";
42 } else {
43 filename = argv[1];
44 fp = fopen(filename, "r");
45 if (!fp) {
46 perror(filename);
47 return 1;
48 }
49 }
50
51 parser = XML_ParserCreate("UTF-8");
52 if (!parser) {
53 fprintf(stderr, "cannot create XML parser\n");
54 return 1;
55 }
56
57 XML_SetElementHandler(parser,
58 eclat_partial_tree_start_handler,
59 eclat_partial_tree_end_handler);
60 XML_SetCharacterDataHandler(parser,
61 eclat_partial_tree_data_handler);
62 part = eclat_partial_tree_create();
63 XML_SetUserData(parser, part);
64
65 while ((size = fread(buffer, 1, sizeof(buffer), fp)) > 0) {
66 enum XML_Status status;
67
68 status = XML_Parse(parser, buffer, size, 0);
69 if (status == XML_STATUS_ERROR) {
70 enum XML_Error error = XML_GetErrorCode(parser);
71 int line = XML_GetCurrentLineNumber(parser);
72 int column = XML_GetCurrentColumnNumber(parser);
73
74 fprintf(stderr, "%s:%d:%d: %s\n",
75 filename, line, column, XML_ErrorString(error));
76 return 1;
77 }
78 }
79 XML_Parse(parser, "", 0, 1);
80
81 tree = eclat_partial_tree_finish(part);
82
83 grecs_print_node(tree, GRECS_NODE_FLAG_DEFAULT, stdout);
84 fputc('\n', stdout);
85 grecs_tree_free(tree);
86
87 return 0;
88}
diff --git a/tests/xml01.at b/tests/xml01.at
new file mode 100644
index 0000000..01d7df4
--- /dev/null
+++ b/tests/xml01.at
@@ -0,0 +1,63 @@
1# This file is part of Eclat -*- Autotest -*-
2# Copyright (C) 2012 Sergey Poznyakoff
3#
4# Eclat is free software; you can redistribute it and/or modify
5# it under the terms of the GNU General Public License as published by
6# the Free Software Foundation; either version 3, or (at your option)
7# any later version.
8#
9# Eclat is distributed in the hope that it will be useful,
10# but WITHOUT ANY WARRANTY; without even the implied warranty of
11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12# GNU General Public License for more details.
13#
14# You should have received a copy of the GNU General Public License
15# along with Eclat. If not, see <http://www.gnu.org/licenses/>.
16
17AT_SETUP([xml01])
18AT_KEYWORDS([xml xml01])
19
20AT_DATA([input],[<?xml version="1.0" encoding="UTF-8"?>
21<DescribeTagsResponse xmlns="http://ec2.amazonaws.com/doc/2012-08-15/">
22 <requestId>beefdead-57rt-ffea-e4ac-deadbeefbeef</requestId>
23 <tagSet>
24 <item>
25 <resourceId>i-00000000</resourceId>
26 <resourceType>instance</resourceType>
27 <key>foo</key>
28 <value>bar</value>
29 </item>
30 <item>
31 <resourceId>i-11111111</resourceId>
32 <resourceType>instance</resourceType>
33 <key>baz</key>
34 <value>quux</value>
35 </item>
36 <item>
37 <resourceId>i-22222222</resourceId>
38 <resourceType>instance</resourceType>
39 <key>Name</key>
40 <value>test</value>
41 </item>
42 </tagSet>
43</DescribeTagsResponse>
44])
45
46AT_CHECK([txml input],
47[0],
48[.DescribeTagsResponse.requestId: "beefdead-57rt-ffea-e4ac-deadbeefbeef"
49.DescribeTagsResponse.tagSet.item.resourceId: "i-00000000"
50.DescribeTagsResponse.tagSet.item.resourceType: "instance"
51.DescribeTagsResponse.tagSet.item.key: "foo"
52.DescribeTagsResponse.tagSet.item.value: "bar"
53.DescribeTagsResponse.tagSet.item.resourceId: "i-11111111"
54.DescribeTagsResponse.tagSet.item.resourceType: "instance"
55.DescribeTagsResponse.tagSet.item.key: "baz"
56.DescribeTagsResponse.tagSet.item.value: "quux"
57.DescribeTagsResponse.tagSet.item.resourceId: "i-22222222"
58.DescribeTagsResponse.tagSet.item.resourceType: "instance"
59.DescribeTagsResponse.tagSet.item.key: "Name"
60.DescribeTagsResponse.tagSet.item.value: "test"
61])
62
63AT_CLEANUP

Return to:

Send suggestions and report system problems to the System administrator.