Check out the latest version of Routino: svn co http://routino.org/svn/trunk routino
Contents of /trunk/src/xmlparse.l
Parent Directory
|
Revision Log
Revision 388 -
(show annotations)
(download)
Mon May 10 18:17:04 2010 UTC (14 years, 10 months ago) by amb
File size: 23600 byte(s)
Mon May 10 18:17:04 2010 UTC (14 years, 10 months ago) by amb
File size: 23600 byte(s)
The line number is now a long integer.
1 | %{ |
2 | /*************************************** |
3 | $Header: /home/amb/CVS/routino/src/xmlparse.l,v 1.13 2010-05-10 18:17:04 amb Exp $ |
4 | |
5 | A simple generic XML parser where the structure comes from the function parameters. |
6 | Not intended to be fully conforming to XML staandard or a validating parser but |
7 | sufficient to parse OSM XML and simple program configuration files. |
8 | |
9 | Part of the Routino routing software. |
10 | ******************/ /****************** |
11 | This file Copyright 2010 Andrew M. Bishop |
12 | |
13 | This program is free software: you can redistribute it and/or modify |
14 | it under the terms of the GNU Affero General Public License as published by |
15 | the Free Software Foundation, either version 3 of the License, or |
16 | (at your option) any later version. |
17 | |
18 | This program is distributed in the hope that it will be useful, |
19 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
20 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
21 | GNU Affero General Public License for more details. |
22 | |
23 | You should have received a copy of the GNU Affero General Public License |
24 | along with this program. If not, see <http://www.gnu.org/licenses/>. |
25 | ***************************************/ |
26 | |
27 | |
28 | #include <stdio.h> |
29 | #include <stdlib.h> |
30 | #include <ctype.h> |
31 | #include <string.h> |
32 | |
33 | #include "xmlparse.h" |
34 | |
35 | |
36 | /* Parser outputs */ |
37 | |
38 | #define LEX_EOF 0 |
39 | |
40 | #define LEX_TAG_BEGIN 1 |
41 | #define LEX_XML_DECL_BEGIN 2 |
42 | #define LEX_TAG_POP 3 |
43 | #define LEX_TAG_PUSH 4 |
44 | #define LEX_XML_DECL_FINISH 6 |
45 | #define LEX_TAG_FINISH 7 |
46 | #define LEX_ATTR_KEY 8 |
47 | #define LEX_ATTR_VAL 9 |
48 | |
49 | #define LEX_ERROR 100 |
50 | |
51 | #define LEX_ERROR_TAG_START 101 |
52 | #define LEX_ERROR_XML_DECL_START 102 |
53 | #define LEX_ERROR_TAG 103 |
54 | #define LEX_ERROR_XML_DECL 104 |
55 | #define LEX_ERROR_ATTR 105 |
56 | #define LEX_ERROR_END_TAG 106 |
57 | #define LEX_ERROR_COMMENT 107 |
58 | #define LEX_ERROR_CLOSE 108 |
59 | #define LEX_ERROR_ATTR_VAL 109 |
60 | #define LEX_ERROR_ENTITY_REF 110 |
61 | #define LEX_ERROR_CHAR_REF 111 |
62 | |
63 | #define LEX_ERROR_UNEXP_TAG 201 |
64 | #define LEX_ERROR_UNBALANCED 202 |
65 | #define LEX_ERROR_NO_START 203 |
66 | #define LEX_ERROR_UNEXP_ATT 204 |
67 | #define LEX_ERROR_UNEXP_EOF 205 |
68 | #define LEX_ERROR_XML_NOT_FIRST 206 |
69 | |
70 | #define LEX_ERROR_CALLBACK 255 |
71 | |
72 | |
73 | /* Lexer definitions */ |
74 | |
75 | #define YY_SKIP_YYWRAP 1 /* Remove error with prototype of ..._yywrap */ |
76 | #ifndef yywrap |
77 | /*+ Needed in lex but does nothing. +*/ |
78 | #define yywrap() 1 |
79 | #endif |
80 | |
81 | /*+ Reset the current string. +*/ |
82 | #define reset_string \ |
83 | if(string) *string=0; \ |
84 | stringused=0; |
85 | |
86 | /*+ append information to the current string. +*/ |
87 | #define append_string(xx) \ |
88 | newlen=strlen(xx); \ |
89 | if((stringused+newlen)>=stringlen) \ |
90 | string=(char*)realloc((void*)string,stringlen=(stringused+newlen+16)); \ |
91 | strcpy(string+stringused,xx); \ |
92 | stringused+=newlen; |
93 | |
94 | #define YY_NO_INPUT |
95 | |
96 | |
97 | /* Lexer functions and variables */ |
98 | |
99 | extern int yylex(void); |
100 | |
101 | static char *yylval=NULL; |
102 | |
103 | static int xmlparse_options; |
104 | |
105 | %} |
106 | |
107 | %option 8bit |
108 | %option pointer |
109 | %option batch |
110 | %option yylineno |
111 | |
112 | %option nodefault |
113 | %option perf-report |
114 | %option fast |
115 | %option nounput |
116 | |
117 | |
118 | /* Grammar based on http://www.w3.org/TR/2004/REC-xml-20040204/ but for ASCII not Unicode. */ |
119 | |
120 | S [ \t\r\n] |
121 | |
122 | letter [a-zA-Z] |
123 | digit [0-9] |
124 | xdigit [a-fA-F0-9] |
125 | |
126 | namechar ({letter}|{digit}|[-._:]) |
127 | name ({letter}|[_:]){namechar}* |
128 | |
129 | entityref &{name}; |
130 | charref &#({digit}+|x{xdigit}+); |
131 | |
132 | |
133 | %x COMMENT |
134 | %x CDATA |
135 | %x DOCTYPE |
136 | %x XML_DECL_START XML_DECL |
137 | %x TAG_START TAG |
138 | %x ATTR_KEY ATTR_VAL |
139 | %x END_TAG1 END_TAG2 |
140 | %x DQUOTED SQUOTED |
141 | |
142 | %% |
143 | /* Must use static variables since the parser returns often. */ |
144 | static char *string=NULL; |
145 | static int stringlen=0,stringused=0; |
146 | static int after_attr=0; |
147 | int newlen; |
148 | int doctype_depth=0; |
149 | |
150 | /* Handle top level entities */ |
151 | |
152 | "<!--" { BEGIN(COMMENT); } |
153 | "<![CDATA[" { BEGIN(CDATA); } |
154 | "<!DOCTYPE" { BEGIN(DOCTYPE); doctype_depth=0; } |
155 | "</" { BEGIN(END_TAG1); } |
156 | "<?" { BEGIN(XML_DECL_START); } |
157 | "<" { BEGIN(TAG_START); } |
158 | ">" { return(LEX_ERROR_CLOSE); } |
159 | [^<>]+ { } |
160 | |
161 | /* Comments */ |
162 | |
163 | <COMMENT>"--->" { return(LEX_ERROR_COMMENT); } |
164 | <COMMENT>"-->" { BEGIN(INITIAL); } |
165 | <COMMENT>"--"[^->]+ { } |
166 | <COMMENT>[^-]+ { } |
167 | <COMMENT>"-" { } |
168 | |
169 | /* CDATA */ |
170 | |
171 | <CDATA>"]]>" { BEGIN(INITIAL); } |
172 | <CDATA>"]" { } |
173 | <CDATA>[^]]+ { } |
174 | |
175 | /* CDATA */ |
176 | |
177 | <DOCTYPE>"<" { doctype_depth++; } |
178 | <DOCTYPE>">" { if(doctype_depth==0) BEGIN(INITIAL); else doctype_depth--; } |
179 | <DOCTYPE>[^<>]+ { } |
180 | |
181 | /* XML Declaration start */ |
182 | |
183 | <XML_DECL_START>{name} { BEGIN(XML_DECL); yylval=yytext; return(LEX_XML_DECL_BEGIN); } |
184 | <XML_DECL_START>.|\n { return(LEX_ERROR_XML_DECL_START); } |
185 | |
186 | /* Tag middle */ |
187 | |
188 | <XML_DECL>"?>" { BEGIN(INITIAL); return(LEX_XML_DECL_FINISH); } |
189 | <XML_DECL>{S}+ { } |
190 | <XML_DECL>{name} { after_attr=XML_DECL; BEGIN(ATTR_KEY); yylval=yytext; return(LEX_ATTR_KEY); } |
191 | <XML_DECL>.|\n { return(LEX_ERROR_XML_DECL); } |
192 | |
193 | /* Any tag start */ |
194 | |
195 | <TAG_START>{name} { BEGIN(TAG); yylval=yytext; return(LEX_TAG_BEGIN); } |
196 | <TAG_START>.|\n { return(LEX_ERROR_TAG_START); } |
197 | |
198 | /* End-tag start */ |
199 | |
200 | <END_TAG1>{name} { BEGIN(END_TAG2); yylval=yytext; return(LEX_TAG_POP); } |
201 | <END_TAG1>.|\n { return(LEX_ERROR_END_TAG); } |
202 | |
203 | <END_TAG2>">" { BEGIN(INITIAL); } |
204 | <END_TAG2>.|\n { return(LEX_ERROR_END_TAG); } |
205 | |
206 | /* Any tag middle */ |
207 | |
208 | <TAG>"/>" { BEGIN(INITIAL); return(LEX_TAG_FINISH); } |
209 | <TAG>">" { BEGIN(INITIAL); return(LEX_TAG_PUSH); } |
210 | <TAG>{S}+ { } |
211 | <TAG>{name} { after_attr=TAG; BEGIN(ATTR_KEY); yylval=yytext; return(LEX_ATTR_KEY); } |
212 | <TAG>.|\n { return(LEX_ERROR_TAG); } |
213 | |
214 | /* Attributes */ |
215 | |
216 | <ATTR_KEY>= { BEGIN(ATTR_VAL); } |
217 | <ATTR_KEY>.|\n { return(LEX_ERROR_ATTR); } |
218 | |
219 | <ATTR_VAL>\" { BEGIN(DQUOTED); reset_string; } |
220 | <ATTR_VAL>\' { BEGIN(SQUOTED); reset_string; } |
221 | <ATTR_VAL>.|\n { return(LEX_ERROR_ATTR); } |
222 | |
223 | /* Quoted strings */ |
224 | |
225 | <DQUOTED>\" { BEGIN(after_attr); yylval=string; return(LEX_ATTR_VAL); } |
226 | <DQUOTED>{entityref} { if(xmlparse_options&XMLPARSE_RETURN_ATTR_ENCODED) {append_string(yytext);} |
227 | else { const char *str=ParseXML_Decode_Entity_Ref(yytext); if(str) {append_string(str);} else {yylval=yytext; return(LEX_ERROR_ENTITY_REF);} } } |
228 | <DQUOTED>{charref} { if(xmlparse_options&XMLPARSE_RETURN_ATTR_ENCODED) {append_string(yytext);} |
229 | else { const char *str=ParseXML_Decode_Char_Ref(yytext); if(str) {append_string(str);} else {yylval=yytext; return(LEX_ERROR_CHAR_REF);} } } |
230 | <DQUOTED>[<>&] { yylval=yytext; return(LEX_ERROR_ATTR_VAL); } |
231 | <DQUOTED>[^<>&\"]+ { append_string(yytext); } |
232 | |
233 | <SQUOTED>\' { BEGIN(after_attr); yylval=string; return(LEX_ATTR_VAL); } |
234 | <SQUOTED>{entityref} { if(xmlparse_options&XMLPARSE_RETURN_ATTR_ENCODED) {append_string(yytext);} |
235 | else { const char *str=ParseXML_Decode_Entity_Ref(yytext); if(str) {append_string(str);} else {yylval=yytext; return(LEX_ERROR_ENTITY_REF);} } } |
236 | <SQUOTED>{charref} { if(xmlparse_options&XMLPARSE_RETURN_ATTR_ENCODED) {append_string(yytext);} |
237 | else { const char *str=ParseXML_Decode_Char_Ref(yytext); if(str) {append_string(str);} else {yylval=yytext; return(LEX_ERROR_CHAR_REF);} } } |
238 | <SQUOTED>[<>&] { yylval=yytext; return(LEX_ERROR_ATTR_VAL); } |
239 | <SQUOTED>[^<>&\']+ { append_string(yytext); } |
240 | |
241 | /* End of file */ |
242 | |
243 | <<EOF>> { free(string); string=NULL; stringlen=stringused=0; BEGIN(INITIAL); return(LEX_EOF); } |
244 | |
245 | %% |
246 | |
247 | |
248 | /*++++++++++++++++++++++++++++++++++++++ |
249 | A function to call the callback function with the parameters needed. |
250 | |
251 | int call_callback Returns 1 if the callback returned with an error. |
252 | |
253 | const char *name The name of the tag. |
254 | |
255 | int (*callback)() The callback function. |
256 | |
257 | int type The type of tag (start and/or end). |
258 | |
259 | int nattributes The number of attributes collected. |
260 | |
261 | char *attributes[XMLPARSE_MAX_ATTRS] The list of attributes. |
262 | ++++++++++++++++++++++++++++++++++++++*/ |
263 | |
264 | static inline int call_callback(const char *name,int (*callback)(),int type,int nattributes,char *attributes[XMLPARSE_MAX_ATTRS]) |
265 | { |
266 | switch(nattributes) |
267 | { |
268 | case 0: return (*callback)(name,type); |
269 | case 1: return (*callback)(name,type,attributes[0]); |
270 | case 2: return (*callback)(name,type,attributes[0],attributes[1]); |
271 | case 3: return (*callback)(name,type,attributes[0],attributes[1],attributes[2]); |
272 | case 4: return (*callback)(name,type,attributes[0],attributes[1],attributes[2],attributes[3]); |
273 | case 5: return (*callback)(name,type,attributes[0],attributes[1],attributes[2],attributes[3],attributes[4]); |
274 | case 6: return (*callback)(name,type,attributes[0],attributes[1],attributes[2],attributes[3],attributes[4],attributes[5]); |
275 | case 7: return (*callback)(name,type,attributes[0],attributes[1],attributes[2],attributes[3],attributes[4],attributes[5],attributes[6]); |
276 | case 8: return (*callback)(name,type,attributes[0],attributes[1],attributes[2],attributes[3],attributes[4],attributes[5],attributes[6],attributes[7]); |
277 | case 9: return (*callback)(name,type,attributes[0],attributes[1],attributes[2],attributes[3],attributes[4],attributes[5],attributes[6],attributes[7],attributes[8]); |
278 | case 10: return (*callback)(name,type,attributes[0],attributes[1],attributes[2],attributes[3],attributes[4],attributes[5],attributes[6],attributes[7],attributes[8],attributes[9]); |
279 | case 11: return (*callback)(name,type,attributes[0],attributes[1],attributes[2],attributes[3],attributes[4],attributes[5],attributes[6],attributes[7],attributes[8],attributes[9],attributes[10]); |
280 | case 12: return (*callback)(name,type,attributes[0],attributes[1],attributes[2],attributes[3],attributes[4],attributes[5],attributes[6],attributes[7],attributes[8],attributes[9],attributes[10],attributes[11]); |
281 | case 13: return (*callback)(name,type,attributes[0],attributes[1],attributes[2],attributes[3],attributes[4],attributes[5],attributes[6],attributes[7],attributes[8],attributes[9],attributes[10],attributes[11],attributes[12]); |
282 | case 14: return (*callback)(name,type,attributes[0],attributes[1],attributes[2],attributes[3],attributes[4],attributes[5],attributes[6],attributes[7],attributes[8],attributes[9],attributes[10],attributes[11],attributes[12],attributes[13]); |
283 | case 15: return (*callback)(name,type,attributes[0],attributes[1],attributes[2],attributes[3],attributes[4],attributes[5],attributes[6],attributes[7],attributes[8],attributes[9],attributes[10],attributes[11],attributes[12],attributes[13],attributes[14]); |
284 | case 16: return (*callback)(name,type,attributes[0],attributes[1],attributes[2],attributes[3],attributes[4],attributes[5],attributes[6],attributes[7],attributes[8],attributes[9],attributes[10],attributes[11],attributes[12],attributes[13],attributes[14],attributes[15]); |
285 | |
286 | default: |
287 | fprintf(stderr,"XML Parser: Error on line %d: too many attributes for tag '%s' source code needs changing.\n",yylineno,name); |
288 | exit(1); |
289 | } |
290 | } |
291 | |
292 | |
293 | /*++++++++++++++++++++++++++++++++++++++ |
294 | Parse the XML and call the functions for each tag as seen. |
295 | |
296 | int ParseXML Returns 0 if OK or something else in case of an error. |
297 | |
298 | FILE *file The file to parse. |
299 | |
300 | xmltag **tags The array of pointers to tags for the top level. |
301 | |
302 | int options A list of XML Parser options OR-ed together. |
303 | ++++++++++++++++++++++++++++++++++++++*/ |
304 | |
305 | int ParseXML(FILE *file,xmltag **tags,int options) |
306 | { |
307 | int yychar,i; |
308 | |
309 | char *attributes[XMLPARSE_MAX_ATTRS]={NULL}; |
310 | int attribute=0; |
311 | |
312 | int stackdepth=0,stackused=0; |
313 | xmltag ***tags_stack=NULL; |
314 | xmltag **tag_stack=NULL; |
315 | xmltag *tag=NULL; |
316 | |
317 | /* The actual parser. */ |
318 | |
319 | xmlparse_options=options; |
320 | |
321 | yyin=file; |
322 | |
323 | yyrestart(yyin); |
324 | |
325 | BEGIN(INITIAL); |
326 | |
327 | do |
328 | { |
329 | yychar=yylex(); |
330 | |
331 | switch(yychar) |
332 | { |
333 | /* The start of a tag for an XML declaration */ |
334 | |
335 | case LEX_XML_DECL_BEGIN: |
336 | |
337 | if(tag_stack) |
338 | { |
339 | fprintf(stderr,"XML Parser: Error on line %d: XML declaration not before all other tags.\n",yylineno); |
340 | yychar=LEX_ERROR_XML_NOT_FIRST; |
341 | break; |
342 | } |
343 | |
344 | /* The start of a tag for an element */ |
345 | |
346 | case LEX_TAG_BEGIN: |
347 | |
348 | tag=NULL; |
349 | |
350 | for(i=0;tags[i];i++) |
351 | if(!strcasecmp(yylval,tags[i]->name)) |
352 | { |
353 | tag=tags[i]; |
354 | |
355 | for(i=0;i<tag->nattributes;i++) |
356 | if(attributes[i]) |
357 | { |
358 | free(attributes[i]); |
359 | attributes[i]=NULL; |
360 | } |
361 | |
362 | break; |
363 | } |
364 | |
365 | if(tag==NULL) |
366 | { |
367 | fprintf(stderr,"XML Parser: Error on line %d: unexpected tag '%s'.\n",yylineno,yylval); |
368 | yychar=LEX_ERROR_UNEXP_TAG; |
369 | } |
370 | |
371 | break; |
372 | |
373 | /* The end of the start-tag for an element */ |
374 | |
375 | case LEX_TAG_PUSH: |
376 | |
377 | if(stackused==stackdepth) |
378 | { |
379 | tag_stack =(xmltag**) realloc((void*)tag_stack ,(stackdepth+=8)*sizeof(xmltag*)); |
380 | tags_stack=(xmltag***)realloc((void*)tags_stack,(stackdepth+=8)*sizeof(xmltag**)); |
381 | } |
382 | |
383 | tag_stack [stackused]=tag; |
384 | tags_stack[stackused]=tags; |
385 | stackused++; |
386 | |
387 | if(tag->callback) |
388 | if(call_callback(tag->name,tag->callback,XMLPARSE_TAG_START,tag->nattributes,attributes)) |
389 | yychar=LEX_ERROR_CALLBACK; |
390 | |
391 | tags=tag->subtags; |
392 | |
393 | break; |
394 | |
395 | /* The end of the empty-element-tag for an XML declaration */ |
396 | |
397 | case LEX_XML_DECL_FINISH: |
398 | |
399 | /* The end of the empty-element-tag for an element */ |
400 | |
401 | case LEX_TAG_FINISH: |
402 | |
403 | if(tag->callback) |
404 | if(call_callback(tag->name,tag->callback,XMLPARSE_TAG_START|XMLPARSE_TAG_END,tag->nattributes,attributes)) |
405 | yychar=LEX_ERROR_CALLBACK; |
406 | |
407 | if(stackused>0) |
408 | tag=tag_stack[stackused-1]; |
409 | else |
410 | tag=NULL; |
411 | |
412 | break; |
413 | |
414 | /* The end of the end-tag for an element */ |
415 | |
416 | case LEX_TAG_POP: |
417 | |
418 | stackused--; |
419 | tags=tags_stack[stackused]; |
420 | tag =tag_stack [stackused]; |
421 | |
422 | if(strcmp(tag->name,yylval)) |
423 | { |
424 | fprintf(stderr,"XML Parser: Error on line %d: end tag '</%s>' doesn't match start tag '<%s ...>'.\n",yylineno,yylval,tag->name); |
425 | yychar=LEX_ERROR_UNBALANCED; |
426 | } |
427 | |
428 | if(stackused<0) |
429 | { |
430 | fprintf(stderr,"XML Parser: Error on line %d: end tag '</%s>' seen but there was no start tag '<%s ...>'.\n",yylineno,yylval,yylval); |
431 | yychar=LEX_ERROR_NO_START; |
432 | } |
433 | |
434 | for(i=0;i<tag->nattributes;i++) |
435 | if(attributes[i]) |
436 | { |
437 | free(attributes[i]); |
438 | attributes[i]=NULL; |
439 | } |
440 | |
441 | if(tag->callback) |
442 | if(call_callback(tag->name,tag->callback,XMLPARSE_TAG_END,tag->nattributes,attributes)) |
443 | yychar=LEX_ERROR_CALLBACK; |
444 | |
445 | if(stackused>0) |
446 | tag=tag_stack[stackused-1]; |
447 | else |
448 | tag=NULL; |
449 | |
450 | break; |
451 | |
452 | /* An attribute key */ |
453 | |
454 | case LEX_ATTR_KEY: |
455 | |
456 | attribute=-1; |
457 | |
458 | for(i=0;i<tag->nattributes;i++) |
459 | if(!strcasecmp(yylval,tag->attributes[i])) |
460 | { |
461 | attribute=i; |
462 | |
463 | break; |
464 | } |
465 | |
466 | if(attribute==-1) |
467 | { |
468 | if((options&XMLPARSE_UNKNOWN_ATTRIBUTES)==XMLPARSE_UNKNOWN_ATTR_ERROR || |
469 | ((options&XMLPARSE_UNKNOWN_ATTRIBUTES)==XMLPARSE_UNKNOWN_ATTR_ERRNONAME && !strchr(yylval,':'))) |
470 | { |
471 | fprintf(stderr,"XML Parser: Error on line %d: unexpected attribute '%s' for tag '%s'.\n",yylineno,yylval,tag->name); |
472 | yychar=LEX_ERROR_UNEXP_ATT; |
473 | } |
474 | else if((options&XMLPARSE_UNKNOWN_ATTRIBUTES)==XMLPARSE_UNKNOWN_ATTR_WARN) |
475 | fprintf(stderr,"XML Parser: Warning on line %d: unexpected attribute '%s' for tag '%s'.\n",yylineno,yylval,tag->name); |
476 | } |
477 | |
478 | break; |
479 | |
480 | /* An attribute value */ |
481 | |
482 | case LEX_ATTR_VAL: |
483 | |
484 | if(tag->callback && attribute!=-1 && yylval) |
485 | attributes[attribute]=strcpy(malloc(strlen(yylval)+1),yylval); |
486 | |
487 | break; |
488 | |
489 | /* End of file */ |
490 | |
491 | case LEX_EOF: |
492 | |
493 | if(tag) |
494 | { |
495 | fprintf(stderr,"XML Parser: Error on line %d: end of file seen without end tag '</%s>'.\n",yylineno,tag->name); |
496 | yychar=LEX_ERROR_UNEXP_EOF; |
497 | } |
498 | |
499 | break; |
500 | |
501 | case LEX_ERROR_TAG_START: |
502 | fprintf(stderr,"XML Parser: Error on line %d: character '<' seen not at start of tag.\n",yylineno); |
503 | break; |
504 | |
505 | case LEX_ERROR_XML_DECL_START: |
506 | fprintf(stderr,"XML Parser: Error on line %d: characters '<?' seen not at start of XML declaration.\n",yylineno); |
507 | break; |
508 | |
509 | case LEX_ERROR_TAG: |
510 | fprintf(stderr,"XML Parser: Error on line %d: invalid character seen inside tag '<%s...>'.\n",yylineno,tag->name); |
511 | break; |
512 | |
513 | case LEX_ERROR_XML_DECL: |
514 | fprintf(stderr,"XML Parser: Error on line %d: invalid character seen inside XML declaration '<?%s...>'.\n",yylineno,tag->name); |
515 | break; |
516 | |
517 | case LEX_ERROR_ATTR: |
518 | fprintf(stderr,"XML Parser: Error on line %d: invalid attribute definition seen in tag.\n",yylineno); |
519 | break; |
520 | |
521 | case LEX_ERROR_END_TAG: |
522 | fprintf(stderr,"XML Parser: Error on line %d: invalid character seen in end-tag.\n",yylineno); |
523 | break; |
524 | |
525 | case LEX_ERROR_COMMENT: |
526 | fprintf(stderr,"XML Parser: Error on line %d: invalid comment seen.\n",yylineno); |
527 | break; |
528 | |
529 | case LEX_ERROR_CLOSE: |
530 | fprintf(stderr,"XML Parser: Error on line %d: character '>' seen not at end of tag.\n",yylineno); |
531 | break; |
532 | |
533 | case LEX_ERROR_ATTR_VAL: |
534 | fprintf(stderr,"XML Parser: Error on line %d: invalid character '%s' seen in attribute value.\n",yylineno,yylval); |
535 | break; |
536 | |
537 | case LEX_ERROR_ENTITY_REF: |
538 | fprintf(stderr,"XML Parser: Error on line %d: invalid entity reference '%s' seen in attribute value.\n",yylineno,yylval); |
539 | break; |
540 | |
541 | case LEX_ERROR_CHAR_REF: |
542 | fprintf(stderr,"XML Parser: Error on line %d: invalid character reference '%s' seen in attribute value.\n",yylineno,yylval); |
543 | break; |
544 | } |
545 | } |
546 | while(yychar>LEX_EOF && yychar<LEX_ERROR); |
547 | |
548 | /* Delete the tagdata */ |
549 | |
550 | for(i=0;i<XMLPARSE_MAX_ATTRS;i++) |
551 | if(attributes[i]) |
552 | free(attributes[i]); |
553 | |
554 | if(stackdepth) |
555 | free(tags_stack); |
556 | |
557 | return(yychar); |
558 | } |
559 | |
560 | |
561 | /*++++++++++++++++++++++++++++++++++++++ |
562 | Return the current parser line number. |
563 | |
564 | unsigned long ParseXML_LineNumber Returns the line number. |
565 | ++++++++++++++++++++++++++++++++++++++*/ |
566 | |
567 | unsigned long ParseXML_LineNumber(void) |
568 | { |
569 | return(yylineno); |
570 | } |
571 | |
572 | |
573 | /*++++++++++++++++++++++++++++++++++++++ |
574 | Convert an XML entity reference into an ASCII string. |
575 | |
576 | char *ParseXML_Decode_Entity_Ref Returns a pointer to the replacement decoded string. |
577 | |
578 | const char *string The entity reference string. |
579 | ++++++++++++++++++++++++++++++++++++++*/ |
580 | |
581 | char *ParseXML_Decode_Entity_Ref(const char *string) |
582 | { |
583 | if(!strcmp(string,"&")) return("&"); |
584 | if(!strcmp(string,"<")) return("<"); |
585 | if(!strcmp(string,">")) return(">"); |
586 | if(!strcmp(string,"'")) return("'"); |
587 | if(!strcmp(string,""")) return("\""); |
588 | return(NULL); |
589 | } |
590 | |
591 | |
592 | /*++++++++++++++++++++++++++++++++++++++ |
593 | Convert an XML character reference into an ASCII string. |
594 | |
595 | char *ParseXML_Decode_Char_Ref Returns a pointer to the replacement decoded string. |
596 | |
597 | const char *string The character reference string. |
598 | ++++++++++++++++++++++++++++++++++++++*/ |
599 | |
600 | char *ParseXML_Decode_Char_Ref(const char *string) |
601 | { |
602 | static char result[2]=" "; |
603 | long int val; |
604 | |
605 | if(string[2]=='x') val=strtol(string+3,NULL,16); |
606 | else val=strtol(string+2,NULL,10); |
607 | |
608 | if(val<0 || val>255) |
609 | return(NULL); |
610 | |
611 | result[0]=val&0xff; |
612 | |
613 | return(result); |
614 | } |
615 | |
616 | |
617 | /*++++++++++++++++++++++++++++++++++++++ |
618 | Convert a string into something that is safe to output in an XML file. |
619 | |
620 | char *ParseXML_Encode_Safe_XML Returns a pointer to the replacement encoded string (or the original if no change needed). |
621 | |
622 | const char *string The string to convert. |
623 | ++++++++++++++++++++++++++++++++++++++*/ |
624 | |
625 | char *ParseXML_Encode_Safe_XML(const char *string) |
626 | { |
627 | static const char hexstring[17]="0123456789ABCDEF"; |
628 | int i=0,j=0,len; |
629 | char *result; |
630 | |
631 | for(i=0;string[i];i++) |
632 | if(string[i]=='<' || string[i]=='>' || string[i]=='&' || string[i]=='\'' || string[i]=='"' || string[i]<32 || string[i]>126) |
633 | break; |
634 | |
635 | if(!string[i]) |
636 | return((char*)string); |
637 | |
638 | len=i+256-6; |
639 | |
640 | result=(char*)malloc(len+7); |
641 | strncpy(result,string,i); |
642 | |
643 | do |
644 | { |
645 | for(;j<len && string[i];i++) |
646 | if(string[i]=='<') |
647 | { |
648 | result[j++]='&'; |
649 | result[j++]='l'; |
650 | result[j++]='t'; |
651 | result[j++]=';'; |
652 | } |
653 | else if(string[i]=='>') |
654 | { |
655 | result[j++]='&'; |
656 | result[j++]='g'; |
657 | result[j++]='t'; |
658 | result[j++]=';'; |
659 | } |
660 | else if(string[i]=='&') |
661 | { |
662 | result[j++]='&'; |
663 | result[j++]='a'; |
664 | result[j++]='m'; |
665 | result[j++]='p'; |
666 | result[j++]=';'; |
667 | } |
668 | else if(string[i]=='\'') |
669 | { |
670 | result[j++]='&'; |
671 | result[j++]='a'; |
672 | result[j++]='p'; |
673 | result[j++]='o'; |
674 | result[j++]='s'; |
675 | result[j++]=';'; |
676 | } |
677 | else if(string[i]=='"') |
678 | { |
679 | result[j++]='&'; |
680 | result[j++]='q'; |
681 | result[j++]='u'; |
682 | result[j++]='o'; |
683 | result[j++]='t'; |
684 | result[j++]=';'; |
685 | } |
686 | else if(string[i]<32 || string[i]>126) |
687 | { |
688 | result[j++]='&'; |
689 | result[j++]='#'; |
690 | result[j++]='x'; |
691 | result[j++]=hexstring[(string[i]&0xf0)>>4]; |
692 | result[j++]=hexstring[ string[i]&0x0f ]; |
693 | result[j++]=';'; |
694 | } |
695 | else |
696 | result[j++]=string[i]; |
697 | |
698 | if(string[i]) /* Not finished */ |
699 | { |
700 | len+=256; |
701 | result=(char*)realloc((void*)result,len+7); |
702 | } |
703 | } |
704 | while(string[i]); |
705 | |
706 | result[j]=0; |
707 | |
708 | return(result); |
709 | } |
710 | |
711 | |
712 | /*++++++++++++++++++++++++++++++++++++++ |
713 | Convert a string to a integer (checking that it really is a integer). |
714 | |
715 | int ParseXML_GetInteger Returns 1 if a integer could be found or 0 otherwise. |
716 | |
717 | const char *string The string to be parsed. |
718 | |
719 | int *number Returns the number. |
720 | ++++++++++++++++++++++++++++++++++++++*/ |
721 | |
722 | int ParseXML_GetInteger(const char *string,int *number) |
723 | { |
724 | const char *p=string; |
725 | |
726 | if(*p=='-' || *p=='+') |
727 | p++; |
728 | |
729 | while(isdigit(*p)) |
730 | p++; |
731 | |
732 | if(*p) |
733 | return(0); |
734 | |
735 | *number=atoi(string); |
736 | |
737 | return(1); |
738 | } |
739 | |
740 | |
741 | /*++++++++++++++++++++++++++++++++++++++ |
742 | Convert a string to a floating point number (checking that it really is a number). |
743 | |
744 | int ParseXML_GetFloating Returns 1 if a number could be found or 0 otherwise. |
745 | |
746 | const char *string The string to be parsed. |
747 | |
748 | int *number Returns the number. |
749 | ++++++++++++++++++++++++++++++++++++++*/ |
750 | |
751 | int ParseXML_GetFloating(const char *string,double *number) |
752 | { |
753 | const char *p=string; |
754 | |
755 | if(*p=='-' || *p=='+') |
756 | p++; |
757 | |
758 | while(isdigit(*p) || *p=='.') |
759 | p++; |
760 | |
761 | if(*p) |
762 | return(0); |
763 | |
764 | *number=atof(string); |
765 | |
766 | return(1); |
767 | } |
Properties
Name | Value |
---|---|
cvs:description | A simple generic XML parser. |