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