1 /* $Id: axp.c 20800 2012-01-19 05:13:45Z m-oki $ */
2
3 /*
4 * Copyright (c) 2012, Internet Initiative Japan, Inc.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
21 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
24 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
26 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
27 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30 /*
31 * Arms Xml Processor API routines.
32 * requires: expat
33 */
34
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38
39 #include <sys/queue.h>
40
41 #include <axp_extern.h>
42 #include <libarms/malloc.h>
43 #include <xml/axp_internal.h>
44
45 AXP *
axp_create(struct axp_schema * as,const char * encoding,void * userdata,AXP_BUILDCALLBACK func)46 axp_create(struct axp_schema *as, const char *encoding,
47 void *userdata, AXP_BUILDCALLBACK func)
48 {
49 AXP *obj;
50 struct axp_schema_entry *ent;
51 int i;
52 char *buf;
53
54 /* allocate all data structures first for easy error handling */
55 obj = MALLOC(sizeof(AXP));
56 buf = MALLOC(AXP_BUFSIZE);
57 ent = MALLOC(sizeof(*ent));
58 if (obj == NULL || buf == NULL || ent == NULL)
59 goto free_and_return;
60
61 obj->parser = XML_ParserCreate(encoding);
62 if (obj->parser == NULL) {
63 goto free_and_return;
64 }
65 XML_SetUserData(obj->parser, obj);
66
67 /* XXX? copy? */
68 obj->schema = as;
69
70 obj->userdata = userdata;
71 obj->state = AXP_PARSE_START;
72 obj->tagstate = AXP_PARSE_TAG;
73 obj->buf = buf;
74 obj->len = 0;
75 axp_register_handler(obj);
76
77 ent->schema = obj->schema;
78 for (i = 0; i < AXP_MAX_HASH_ARRAY; i++) {
79 LIST_INIT(&obj->valhash[i]);
80 }
81 LIST_INIT(&obj->sc_stack);
82 LIST_INSERT_HEAD(&obj->sc_stack, ent, next);
83
84 return obj;
85
86 free_and_return:
87 if (obj != NULL)
88 FREE(obj);
89 if (buf != NULL)
90 FREE(buf);
91 if (ent != NULL)
92 FREE(ent);
93 return NULL;
94 }
95
96 int
axp_parse(AXP * obj,const char * buf,size_t len)97 axp_parse(AXP *obj, const char *buf, size_t len)
98 {
99 int error;
100
101 if (obj->state == AXP_PARSE_END)
102 return -1;
103
104 obj->state = AXP_PARSE_CONTENT;
105 error = XML_Parse(obj->parser, buf, (int)len, 0);
106 if (error == XML_STATUS_ERROR) {
107 #ifdef XML_DEBUG
108 char errbuf[40 + 1];
109 int offset, errlen;
110
111 fprintf(stderr, "Parse error at line %ld:\n%s\n",
112 XML_GetCurrentLineNumber(obj->parser),
113 XML_ErrorString(XML_GetErrorCode(obj->parser)));
114 offset = XML_GetCurrentByteCount(obj->parser);
115 if (offset == 0) {
116 fprintf(stderr, "No column info.\n");
117 }
118 else {
119 errlen = len - offset;
120 if (errlen > 40)
121 errlen = 40;
122 memcpy(errbuf, buf + offset, errlen);
123 errbuf[errlen] = '\0';
124 fprintf(stderr, "Error Position: %s\n", errbuf);
125 }
126 #endif
127 obj->state = AXP_PARSE_ERROR;
128 return -1;
129 }
130 return 0;
131 }
132
133 int
axp_endparse(AXP * obj)134 axp_endparse(AXP *obj)
135 {
136 int error;
137
138 error = XML_Parse(obj->parser, 0, 0, 1); /* Done */
139 if (error == XML_STATUS_ERROR) {
140 #if XML_DEBUG
141 fprintf(stderr, "Parse error at line %ld:\n%s\n",
142 XML_GetCurrentLineNumber(obj->parser),
143 XML_ErrorString(XML_GetErrorCode(obj->parser)));
144 #endif
145 obj->state = AXP_PARSE_ERROR;
146 return -1;
147 }
148 obj->state = AXP_PARSE_END;
149 return 0;
150 }
151
152 int
axp_destroy(AXP * obj)153 axp_destroy(AXP *obj)
154 {
155 int i;
156
157 if (obj != 0) {
158 struct axp_schema_entry *ent;
159
160 /* free expat parser */
161 XML_ParserFree(obj->parser);
162 /* free var and attr */
163 for (i = 0; i < AXP_MAX_HASH_ARRAY; i++) {
164 struct axp_val_storage *p;
165
166 while ((p = LIST_FIRST(&obj->valhash[i])) != 0) {
167 struct axp_attr_entry *attr;
168
169 while ((attr = LIST_FIRST(&p->attr)) != 0) {
170 LIST_REMOVE(attr, next);
171 FREE(attr->prop);
172 FREE(attr->value);
173 FREE(attr);
174 }
175 LIST_REMOVE(p, next);
176 if (p->type == AXP_TYPE_TEXT &&
177 p->value != NULL)
178 FREE(p->value);
179 FREE(p);
180 }
181 }
182 /* free stack */
183 while ((ent = LIST_FIRST(&obj->sc_stack)) != 0) {
184 LIST_REMOVE(ent, next);
185 FREE(ent);
186 }
187 /* free buffer */
188 FREE(obj->buf);
189 /* free obj */
190 FREE(obj);
191 }
192 return 0;
193 }
194
195 int
axp_get_tagstate(AXP * obj)196 axp_get_tagstate(AXP *obj)
197 {
198 return obj->tagstate;
199 }
200
201 int
axp_set_userdata(AXP * obj,void * userdata)202 axp_set_userdata(AXP *obj, void *userdata)
203 {
204 obj->userdata = userdata;
205 return 0;
206 }
207
208 void *
axp_get_userdata(AXP * obj)209 axp_get_userdata(AXP *obj)
210 {
211 return obj->userdata;
212 }
213
214 static void *
axp_find_var(AXP * obj,int tag)215 axp_find_var(AXP *obj, int tag)
216 {
217 struct axp_val_storage *p;
218 int hash;
219
220 hash = tag % AXP_MAX_HASH_ARRAY;
221 LIST_FOREACH(p, &obj->valhash[hash], next) {
222 if (p->tag == tag)
223 return p;
224 }
225 return 0;
226 }
227
228 /* XXX int or string */
229 int
axp_refer(AXP * obj,int tagtype,void * valp)230 axp_refer(AXP *obj, int tagtype, void *valp)
231 {
232 struct axp_val_storage *p;
233 p = axp_find_var(obj, tagtype);
234 if (p) {
235 *(void **)valp = p->value;
236 return 0;
237 } else {
238 return -1;
239 }
240 }
241
242 /*
243 * note: tagtype validation is disabled now.
244 */
245 int
axp_set(AXP * obj,int tagtype,void * valp)246 axp_set(AXP *obj, int tagtype, void *valp)
247 {
248 return axp_set_value(obj, tagtype, valp, AXP_TYPE_TEXT);
249 }
250
251 void
axp_reset(AXP * obj,int tagtype)252 axp_reset(AXP *obj, int tagtype)
253 {
254 struct axp_val_storage *p;
255
256 p = axp_find_var(obj, tagtype);
257 if (p) {
258 struct axp_attr_entry *attr;
259
260 /* reuse p, clear all attribute */
261 while ((attr = LIST_FIRST(&p->attr)) != 0) {
262 LIST_REMOVE(attr, next);
263 FREE(attr->prop);
264 FREE(attr->value);
265 FREE(attr);
266 }
267 }
268 }
269
270 int
axp_set_value(AXP * obj,int tagtype,void * valp,int type)271 axp_set_value(AXP *obj, int tagtype, void *valp, int type)
272 {
273 struct axp_val_storage *p;
274
275 p = axp_find_var(obj, tagtype);
276 if (p) {
277 if (p->type == AXP_TYPE_TEXT) {
278 if (p->value)
279 FREE(p->value);
280 if (valp)
281 p->value = STRDUP(valp);
282 else
283 p->value = valp;
284 } else {
285 p->value = valp;
286 }
287 } else {
288 int hash;
289
290 hash = tagtype % AXP_MAX_HASH_ARRAY;
291 p = MALLOC(sizeof(struct axp_val_storage));
292 p->tag = tagtype;
293 p->type = type;
294 if (p->type == AXP_TYPE_TEXT && valp != NULL) {
295 p->value = STRDUP(valp);
296 } else {
297 p->value = valp;
298 }
299 LIST_INIT(&p->attr);
300 LIST_INSERT_HEAD(&obj->valhash[hash], p, next);
301 }
302 return 0;
303 }
304
305 int
axp_set_attr(AXP * obj,int tagtype,const char * prop,const char * value)306 axp_set_attr(AXP *obj, int tagtype, const char *prop, const char *value)
307 {
308 struct axp_val_storage *p;
309 struct axp_attr_entry *attr;
310
311 p = axp_find_var(obj, tagtype);
312 if (!p) {
313 /* subset case, or empty */
314 axp_set(obj, tagtype, 0);
315 /* again */
316 p = axp_find_var(obj, tagtype);
317 }
318 LIST_FOREACH(attr, &p->attr, next) {
319 if (!strcmp(attr->prop, prop)) {
320 /* found, overwrite value */
321 FREE(attr->value);
322 attr->value = STRDUP(value);
323 return 0;
324 }
325 }
326 /* not found, add new entry */
327 attr = MALLOC(sizeof(*attr));
328 attr->prop = STRDUP(prop);
329 attr->value = STRDUP(value);
330 LIST_INSERT_HEAD(&p->attr, attr, next);
331 return 0;
332 }
333
334 const char *
axp_find_attr(AXP * obj,int tagtype,char * prop)335 axp_find_attr(AXP *obj, int tagtype, char *prop)
336 {
337 struct axp_val_storage *p;
338 struct axp_attr_entry *attr;
339
340 p = axp_find_var(obj, tagtype);
341 if (!p) {
342 /* tag don't have any attribute */
343 return 0;
344 }
345 LIST_FOREACH(attr, &p->attr, next) {
346 if (!strcmp(attr->prop, prop)) {
347 return attr->value;
348 }
349 }
350 /* attribute not found */
351 return 0;
352 }
353