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 368 -
(show annotations)
(download)
Thu Apr 22 17:53:42 2010 UTC (14 years, 11 months ago) by amb
File size: 23009 byte(s)
Thu Apr 22 17:53:42 2010 UTC (14 years, 11 months ago) by amb
File size: 23009 byte(s)
Restart properly so that a different file can be read.
1 | %{ |
2 | /*************************************** |
3 | $Header: /home/amb/CVS/routino/src/xmlparse.l,v 1.9 2010-04-22 17:53:42 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 | %} |
104 | |
105 | %option 8bit |
106 | %option pointer |
107 | %option batch |
108 | %option yylineno |
109 | |
110 | %option nodefault |
111 | %option perf-report |
112 | %option fast |
113 | %option nounput |
114 | |
115 | |
116 | /* Grammar based on http://www.w3.org/TR/2004/REC-xml-20040204/ but for ASCII not Unicode. */ |
117 | |
118 | S [ \t\r\n] |
119 | |
120 | letter [a-zA-Z] |
121 | digit [0-9] |
122 | xdigit [a-fA-F0-9] |
123 | |
124 | namechar ({letter}|{digit}|[-._:]) |
125 | name ({letter}|[_:]){namechar}* |
126 | |
127 | entityref &{name}; |
128 | charref &#({digit}+|x{xdigit}+); |
129 | |
130 | |
131 | %x COMMENT |
132 | %x CDATA |
133 | %x DOCTYPE |
134 | %x XML_DECL_START XML_DECL |
135 | %x TAG_START TAG |
136 | %x ATTR_KEY ATTR_VAL |
137 | %x END_TAG1 END_TAG2 |
138 | %x DQUOTED SQUOTED |
139 | |
140 | %% |
141 | /* Must use static variables since the parser returns often. */ |
142 | static char *string=NULL; |
143 | static int stringlen=0,stringused=0; |
144 | static int after_attr=0; |
145 | int newlen; |
146 | int doctype_depth=0; |
147 | |
148 | /* Handle top level entities */ |
149 | |
150 | "<!--" { BEGIN(COMMENT); } |
151 | "<![CDATA[" { BEGIN(CDATA); } |
152 | "<!DOCTYPE" { BEGIN(DOCTYPE); doctype_depth=0; } |
153 | "</" { BEGIN(END_TAG1); } |
154 | "<?" { BEGIN(XML_DECL_START); } |
155 | "<" { BEGIN(TAG_START); } |
156 | ">" { return(LEX_ERROR_CLOSE); } |
157 | [^<>]+ { } |
158 | |
159 | /* Comments */ |
160 | |
161 | <COMMENT>"--->" { return(LEX_ERROR_COMMENT); } |
162 | <COMMENT>"-->" { BEGIN(INITIAL); } |
163 | <COMMENT>"--"[^->]+ { } |
164 | <COMMENT>[^-]+ { } |
165 | <COMMENT>"-" { } |
166 | |
167 | /* CDATA */ |
168 | |
169 | <CDATA>"]]>" { BEGIN(INITIAL); } |
170 | <CDATA>"]" { } |
171 | <CDATA>[^]]+ { } |
172 | |
173 | /* CDATA */ |
174 | |
175 | <DOCTYPE>"<" { doctype_depth++; } |
176 | <DOCTYPE>">" { if(doctype_depth==0) BEGIN(INITIAL); else doctype_depth--; } |
177 | <DOCTYPE>[^<>]+ { } |
178 | |
179 | /* XML Declaration start */ |
180 | |
181 | <XML_DECL_START>{name} { BEGIN(XML_DECL); yylval=yytext; return(LEX_XML_DECL_BEGIN); } |
182 | <XML_DECL_START>.|\n { return(LEX_ERROR_XML_DECL_START); } |
183 | |
184 | /* Tag middle */ |
185 | |
186 | <XML_DECL>"?>" { BEGIN(INITIAL); return(LEX_XML_DECL_FINISH); } |
187 | <XML_DECL>{S}+ { } |
188 | <XML_DECL>{name} { after_attr=XML_DECL; BEGIN(ATTR_KEY); yylval=yytext; return(LEX_ATTR_KEY); } |
189 | <XML_DECL>.|\n { return(LEX_ERROR_XML_DECL); } |
190 | |
191 | /* Any tag start */ |
192 | |
193 | <TAG_START>{name} { BEGIN(TAG); yylval=yytext; return(LEX_TAG_BEGIN); } |
194 | <TAG_START>.|\n { return(LEX_ERROR_TAG_START); } |
195 | |
196 | /* End-tag start */ |
197 | |
198 | <END_TAG1>{name} { BEGIN(END_TAG2); yylval=yytext; return(LEX_TAG_POP); } |
199 | <END_TAG1>.|\n { return(LEX_ERROR_END_TAG); } |
200 | |
201 | <END_TAG2>">" { BEGIN(INITIAL); } |
202 | <END_TAG2>.|\n { return(LEX_ERROR_END_TAG); } |
203 | |
204 | /* Any tag middle */ |
205 | |
206 | <TAG>"/>" { BEGIN(INITIAL); return(LEX_TAG_FINISH); } |
207 | <TAG>">" { BEGIN(INITIAL); return(LEX_TAG_PUSH); } |
208 | <TAG>{S}+ { } |
209 | <TAG>{name} { after_attr=TAG; BEGIN(ATTR_KEY); yylval=yytext; return(LEX_ATTR_KEY); } |
210 | <TAG>.|\n { return(LEX_ERROR_TAG); } |
211 | |
212 | /* Attributes */ |
213 | |
214 | <ATTR_KEY>= { BEGIN(ATTR_VAL); } |
215 | <ATTR_KEY>.|\n { return(LEX_ERROR_ATTR); } |
216 | |
217 | <ATTR_VAL>\" { BEGIN(DQUOTED); reset_string; } |
218 | <ATTR_VAL>\' { BEGIN(SQUOTED); reset_string; } |
219 | <ATTR_VAL>.|\n { return(LEX_ERROR_ATTR); } |
220 | |
221 | /* Quoted strings */ |
222 | |
223 | <DQUOTED>\" { BEGIN(after_attr); yylval=string; return(LEX_ATTR_VAL); } |
224 | <DQUOTED>{entityref} { const char *str=ParseXML_Decode_Entity_Ref(yytext); if(str) {append_string(str);} else {yylval=yytext; return(LEX_ERROR_ENTITY_REF);} } |
225 | <DQUOTED>{charref} { const char *str=ParseXML_Decode_Char_Ref(yytext); if(str) {append_string(str);} else {yylval=yytext; return(LEX_ERROR_CHAR_REF);} } |
226 | <DQUOTED>[<>&] { yylval=yytext; return(LEX_ERROR_ATTR_VAL); } |
227 | <DQUOTED>[^<>&\"]+ { append_string(yytext); } |
228 | |
229 | <SQUOTED>\' { BEGIN(after_attr); yylval=string; return(LEX_ATTR_VAL); } |
230 | <SQUOTED>{entityref} { const char *str=ParseXML_Decode_Entity_Ref(yytext); if(str) {append_string(str);} else {yylval=yytext; return(LEX_ERROR_ENTITY_REF);} } |
231 | <SQUOTED>{charref} { const char *str=ParseXML_Decode_Char_Ref(yytext); if(str) {append_string(str);} else {yylval=yytext; return(LEX_ERROR_CHAR_REF);} } |
232 | <SQUOTED>[<>&] { yylval=yytext; return(LEX_ERROR_ATTR_VAL); } |
233 | <SQUOTED>[^<>&\']+ { append_string(yytext); } |
234 | |
235 | /* End of file */ |
236 | |
237 | <<EOF>> { free(string); string=NULL; stringlen=stringused=0; BEGIN(INITIAL); return(LEX_EOF); } |
238 | |
239 | %% |
240 | |
241 | |
242 | /*++++++++++++++++++++++++++++++++++++++ |
243 | A function to call the callback function with the parameters needed. |
244 | |
245 | int call_callback Returns 1 if the callback returned with an error. |
246 | |
247 | const char *name The name of the tag. |
248 | |
249 | int (*callback)() The callback function. |
250 | |
251 | int type The type of tag (start and/or end). |
252 | |
253 | int nattributes The number of attributes collected. |
254 | |
255 | char *attributes[XMLPARSE_MAX_ATTRS] The list of attributes. |
256 | ++++++++++++++++++++++++++++++++++++++*/ |
257 | |
258 | static inline int call_callback(const char *name,int (*callback)(),int type,int nattributes,char *attributes[XMLPARSE_MAX_ATTRS]) |
259 | { |
260 | switch(nattributes) |
261 | { |
262 | case 0: return (*callback)(type); |
263 | case 1: return (*callback)(type,attributes[0]); |
264 | case 2: return (*callback)(type,attributes[0],attributes[1]); |
265 | case 3: return (*callback)(type,attributes[0],attributes[1],attributes[2]); |
266 | case 4: return (*callback)(type,attributes[0],attributes[1],attributes[2],attributes[3]); |
267 | case 5: return (*callback)(type,attributes[0],attributes[1],attributes[2],attributes[3],attributes[4]); |
268 | case 6: return (*callback)(type,attributes[0],attributes[1],attributes[2],attributes[3],attributes[4],attributes[5]); |
269 | case 7: return (*callback)(type,attributes[0],attributes[1],attributes[2],attributes[3],attributes[4],attributes[5],attributes[6]); |
270 | case 8: return (*callback)(type,attributes[0],attributes[1],attributes[2],attributes[3],attributes[4],attributes[5],attributes[6],attributes[7]); |
271 | case 9: return (*callback)(type,attributes[0],attributes[1],attributes[2],attributes[3],attributes[4],attributes[5],attributes[6],attributes[7],attributes[8]); |
272 | case 10: return (*callback)(type,attributes[0],attributes[1],attributes[2],attributes[3],attributes[4],attributes[5],attributes[6],attributes[7],attributes[8],attributes[9]); |
273 | case 11: return (*callback)(type,attributes[0],attributes[1],attributes[2],attributes[3],attributes[4],attributes[5],attributes[6],attributes[7],attributes[8],attributes[9],attributes[10]); |
274 | case 12: return (*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]); |
275 | case 13: return (*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]); |
276 | case 14: return (*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]); |
277 | case 15: return (*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]); |
278 | case 16: return (*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]); |
279 | |
280 | default: |
281 | fprintf(stderr,"XML Parser: Error on line %d: too many attributes for tag '%s' source code needs changing.\n",yylineno,name); |
282 | exit(1); |
283 | } |
284 | } |
285 | |
286 | |
287 | /*++++++++++++++++++++++++++++++++++++++ |
288 | Parse the XML and call the functions for each tag as seen. |
289 | |
290 | int ParseXML Returns 0 if OK or something else in case of an error. |
291 | |
292 | FILE *file The file to parse. |
293 | |
294 | xmltag **tags The array of pointers to tags for the top level. |
295 | |
296 | int options A list of XML Parser options OR-ed together. |
297 | ++++++++++++++++++++++++++++++++++++++*/ |
298 | |
299 | int ParseXML(FILE *file,xmltag **tags,int options) |
300 | { |
301 | int yychar,i; |
302 | |
303 | char *attributes[XMLPARSE_MAX_ATTRS]={NULL}; |
304 | int attribute=0; |
305 | |
306 | int stackdepth=0,stackused=0; |
307 | xmltag ***tags_stack=NULL; |
308 | xmltag **tag_stack=NULL; |
309 | xmltag *tag=NULL; |
310 | |
311 | /* The actual parser. */ |
312 | |
313 | yyin=file; |
314 | |
315 | yyrestart(yyin); |
316 | |
317 | BEGIN(INITIAL); |
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 | if(call_callback(tag->name,tag->callback,XMLPARSE_TAG_START,tag->nattributes,attributes)) |
381 | yychar=LEX_ERROR_CALLBACK; |
382 | |
383 | tags=tag->subtags; |
384 | |
385 | break; |
386 | |
387 | /* The end of the empty-element-tag for an XML declaration */ |
388 | |
389 | case LEX_XML_DECL_FINISH: |
390 | |
391 | /* The end of the empty-element-tag for an element */ |
392 | |
393 | case LEX_TAG_FINISH: |
394 | |
395 | if(tag->callback) |
396 | if(call_callback(tag->name,tag->callback,XMLPARSE_TAG_START|XMLPARSE_TAG_END,tag->nattributes,attributes)) |
397 | yychar=LEX_ERROR_CALLBACK; |
398 | |
399 | if(stackused>0) |
400 | tag=tag_stack[stackused-1]; |
401 | else |
402 | tag=NULL; |
403 | |
404 | break; |
405 | |
406 | /* The end of the end-tag for an element */ |
407 | |
408 | case LEX_TAG_POP: |
409 | |
410 | stackused--; |
411 | tags=tags_stack[stackused]; |
412 | tag =tag_stack [stackused]; |
413 | |
414 | if(strcmp(tag->name,yylval)) |
415 | { |
416 | fprintf(stderr,"XML Parser: Error on line %d: end tag '</%s>' doesn't match start tag '<%s ...>'.\n",yylineno,yylval,tag->name); |
417 | yychar=LEX_ERROR_UNBALANCED; |
418 | } |
419 | |
420 | if(stackused<0) |
421 | { |
422 | fprintf(stderr,"XML Parser: Error on line %d: end tag '</%s>' seen but there was no start tag '<%s ...>'.\n",yylineno,yylval,yylval); |
423 | yychar=LEX_ERROR_NO_START; |
424 | } |
425 | |
426 | for(i=0;i<tag->nattributes;i++) |
427 | if(attributes[i]) |
428 | { |
429 | free(attributes[i]); |
430 | attributes[i]=NULL; |
431 | } |
432 | |
433 | if(tag->callback) |
434 | if(call_callback(tag->name,tag->callback,XMLPARSE_TAG_END,tag->nattributes,attributes)) |
435 | yychar=LEX_ERROR_CALLBACK; |
436 | |
437 | if(stackused>0) |
438 | tag=tag_stack[stackused-1]; |
439 | else |
440 | tag=NULL; |
441 | |
442 | break; |
443 | |
444 | /* An attribute key */ |
445 | |
446 | case LEX_ATTR_KEY: |
447 | |
448 | attribute=-1; |
449 | |
450 | for(i=0;i<tag->nattributes;i++) |
451 | if(!strcasecmp(yylval,tag->attributes[i])) |
452 | { |
453 | attribute=i; |
454 | |
455 | break; |
456 | } |
457 | |
458 | if(attribute==-1) |
459 | { |
460 | if((options&XMLPARSE_UNKNOWN_ATTRIBUTES)==XMLPARSE_UNKNOWN_ATTR_ERROR || |
461 | ((options&XMLPARSE_UNKNOWN_ATTRIBUTES)==XMLPARSE_UNKNOWN_ATTR_ERRNONAME && !strchr(yylval,':'))) |
462 | { |
463 | fprintf(stderr,"XML Parser: Error on line %d: unexpected attribute '%s' for tag '%s'.\n",yylineno,yylval,tag->name); |
464 | yychar=LEX_ERROR_UNEXP_ATT; |
465 | } |
466 | else if((options&XMLPARSE_UNKNOWN_ATTRIBUTES)==XMLPARSE_UNKNOWN_ATTR_WARN) |
467 | fprintf(stderr,"XML Parser: Warning on line %d: unexpected attribute '%s' for tag '%s'.\n",yylineno,yylval,tag->name); |
468 | } |
469 | |
470 | break; |
471 | |
472 | /* An attribute value */ |
473 | |
474 | case LEX_ATTR_VAL: |
475 | |
476 | if(tag->callback && attribute!=-1 && yylval) |
477 | attributes[attribute]=strcpy(malloc(strlen(yylval)+1),yylval); |
478 | |
479 | break; |
480 | |
481 | /* End of file */ |
482 | |
483 | case LEX_EOF: |
484 | |
485 | if(tag) |
486 | { |
487 | fprintf(stderr,"XML Parser: Error on line %d: end of file seen without end tag '</%s>'.\n",yylineno,tag->name); |
488 | yychar=LEX_ERROR_UNEXP_EOF; |
489 | } |
490 | |
491 | break; |
492 | |
493 | case LEX_ERROR_TAG_START: |
494 | fprintf(stderr,"XML Parser: Error on line %d: character '<' seen not at start of tag.\n",yylineno); |
495 | break; |
496 | |
497 | case LEX_ERROR_XML_DECL_START: |
498 | fprintf(stderr,"XML Parser: Error on line %d: characters '<?' seen not at start of XML declaration.\n",yylineno); |
499 | break; |
500 | |
501 | case LEX_ERROR_TAG: |
502 | fprintf(stderr,"XML Parser: Error on line %d: invalid character seen inside tag '<%s...>'.\n",yylineno,tag->name); |
503 | break; |
504 | |
505 | case LEX_ERROR_XML_DECL: |
506 | fprintf(stderr,"XML Parser: Error on line %d: invalid character seen inside XML declaration '<?%s...>'.\n",yylineno,tag->name); |
507 | break; |
508 | |
509 | case LEX_ERROR_ATTR: |
510 | fprintf(stderr,"XML Parser: Error on line %d: invalid attribute definition seen in tag.\n",yylineno); |
511 | break; |
512 | |
513 | case LEX_ERROR_END_TAG: |
514 | fprintf(stderr,"XML Parser: Error on line %d: invalid character seen in end-tag.\n",yylineno); |
515 | break; |
516 | |
517 | case LEX_ERROR_COMMENT: |
518 | fprintf(stderr,"XML Parser: Error on line %d: invalid comment seen.\n",yylineno); |
519 | break; |
520 | |
521 | case LEX_ERROR_CLOSE: |
522 | fprintf(stderr,"XML Parser: Error on line %d: character '>' seen not at end of tag.\n",yylineno); |
523 | break; |
524 | |
525 | case LEX_ERROR_ATTR_VAL: |
526 | fprintf(stderr,"XML Parser: Error on line %d: invalid character '%s' seen in attribute value.\n",yylineno,yylval); |
527 | break; |
528 | |
529 | case LEX_ERROR_ENTITY_REF: |
530 | fprintf(stderr,"XML Parser: Error on line %d: invalid entity reference '%s' seen in attribute value.\n",yylineno,yylval); |
531 | break; |
532 | |
533 | case LEX_ERROR_CHAR_REF: |
534 | fprintf(stderr,"XML Parser: Error on line %d: invalid character reference '%s' seen in attribute value.\n",yylineno,yylval); |
535 | break; |
536 | } |
537 | } |
538 | while(yychar>LEX_EOF && yychar<LEX_ERROR); |
539 | |
540 | /* Delete the tagdata */ |
541 | |
542 | for(i=0;i<XMLPARSE_MAX_ATTRS;i++) |
543 | if(attributes[i]) |
544 | free(attributes[i]); |
545 | |
546 | if(stackdepth) |
547 | free(tags_stack); |
548 | |
549 | return(yychar); |
550 | } |
551 | |
552 | |
553 | /*++++++++++++++++++++++++++++++++++++++ |
554 | Return the current parser line number. |
555 | |
556 | int ParseXML_LineNumber Returns the line number. |
557 | ++++++++++++++++++++++++++++++++++++++*/ |
558 | |
559 | int ParseXML_LineNumber(void) |
560 | { |
561 | return(yylineno); |
562 | } |
563 | |
564 | |
565 | /*++++++++++++++++++++++++++++++++++++++ |
566 | Convert an XML entity reference into an ASCII string. |
567 | |
568 | const char *ParseXML_Decode_Entity_Ref Returns a pointer to the replacement decoded string. |
569 | |
570 | const char *string The entity reference string. |
571 | ++++++++++++++++++++++++++++++++++++++*/ |
572 | |
573 | const char *ParseXML_Decode_Entity_Ref(const char *string) |
574 | { |
575 | if(!strcmp(string,"&")) return("&"); |
576 | if(!strcmp(string,"<")) return("<"); |
577 | if(!strcmp(string,">")) return(">"); |
578 | if(!strcmp(string,"'")) return("'"); |
579 | if(!strcmp(string,""")) return("\""); |
580 | return(NULL); |
581 | } |
582 | |
583 | |
584 | /*++++++++++++++++++++++++++++++++++++++ |
585 | Convert an XML character reference into an ASCII string. |
586 | |
587 | const char *ParseXML_Decode_Char_Ref Returns a pointer to the replacement decoded string. |
588 | |
589 | const char *string The character reference string. |
590 | ++++++++++++++++++++++++++++++++++++++*/ |
591 | |
592 | const char *ParseXML_Decode_Char_Ref(const char *string) |
593 | { |
594 | static char result[2]=" "; |
595 | long int val; |
596 | |
597 | if(string[2]=='x') val=strtol(string+3,NULL,16); |
598 | else val=strtol(string+2,NULL,10); |
599 | |
600 | if(val<0 || val>255) |
601 | return(NULL); |
602 | |
603 | result[0]=val&0xff; |
604 | |
605 | return(result); |
606 | } |
607 | |
608 | |
609 | /*++++++++++++++++++++++++++++++++++++++ |
610 | Convert a string into something that is safe to output in an XML file. |
611 | |
612 | const char *ParseXML_Encode_Safe_XML Returns a pointer to the replacement encoded string (or the original if no change needed). |
613 | |
614 | const char *string The string to convert. |
615 | ++++++++++++++++++++++++++++++++++++++*/ |
616 | |
617 | const char *ParseXML_Encode_Safe_XML(const char *string) |
618 | { |
619 | static const char hexstring[17]="0123456789ABCDEF"; |
620 | int i=0,j=0,len; |
621 | char *result; |
622 | |
623 | for(i=0;string[i];i++) |
624 | if(string[i]=='<' || string[i]=='>' || string[i]=='&' || string[i]=='\'' || string[i]=='"' || string[i]<32 || string[i]>126) |
625 | break; |
626 | |
627 | if(!string[i]) |
628 | return(string); |
629 | |
630 | len=i+256-6; |
631 | |
632 | result=(char*)malloc(len+7); |
633 | strncpy(result,string,i); |
634 | |
635 | do |
636 | { |
637 | for(;j<len && string[i];i++) |
638 | if(string[i]=='<') |
639 | { |
640 | result[j++]='&'; |
641 | result[j++]='l'; |
642 | result[j++]='t'; |
643 | result[j++]=';'; |
644 | } |
645 | else if(string[i]=='>') |
646 | { |
647 | result[j++]='&'; |
648 | result[j++]='g'; |
649 | result[j++]='t'; |
650 | result[j++]=';'; |
651 | } |
652 | else if(string[i]=='&') |
653 | { |
654 | result[j++]='&'; |
655 | result[j++]='a'; |
656 | result[j++]='m'; |
657 | result[j++]='p'; |
658 | result[j++]=';'; |
659 | } |
660 | else if(string[i]=='\'') |
661 | { |
662 | result[j++]='&'; |
663 | result[j++]='a'; |
664 | result[j++]='p'; |
665 | result[j++]='o'; |
666 | result[j++]='s'; |
667 | result[j++]=';'; |
668 | } |
669 | else if(string[i]=='"') |
670 | { |
671 | result[j++]='&'; |
672 | result[j++]='q'; |
673 | result[j++]='u'; |
674 | result[j++]='o'; |
675 | result[j++]='t'; |
676 | result[j++]=';'; |
677 | } |
678 | else if(string[i]<32 || string[i]>126) |
679 | { |
680 | result[j++]='&'; |
681 | result[j++]='#'; |
682 | result[j++]='x'; |
683 | result[j++]=hexstring[(string[i]&0xf0)>>4]; |
684 | result[j++]=hexstring[ string[i]&0x0f ]; |
685 | result[j++]=';'; |
686 | } |
687 | else |
688 | result[j++]=string[i]; |
689 | |
690 | if(string[i]) /* Not finished */ |
691 | { |
692 | len+=256; |
693 | result=(char*)realloc((void*)result,len+7); |
694 | } |
695 | } |
696 | while(string[i]); |
697 | |
698 | result[j]=0; |
699 | |
700 | return(result); |
701 | } |
702 | |
703 | |
704 | /*++++++++++++++++++++++++++++++++++++++ |
705 | Convert a string to a integer (checking that it really is a integer). |
706 | |
707 | int ParseXML_GetInteger Returns 1 if a integer could be found or 0 otherwise. |
708 | |
709 | const char *string The string to be parsed. |
710 | |
711 | int *number Returns the number. |
712 | ++++++++++++++++++++++++++++++++++++++*/ |
713 | |
714 | int ParseXML_GetInteger(const char *string,int *number) |
715 | { |
716 | const char *p=string; |
717 | |
718 | if(*p=='-' || *p=='+') |
719 | p++; |
720 | |
721 | while(isdigit(*p)) |
722 | p++; |
723 | |
724 | if(*p) |
725 | return(0); |
726 | |
727 | *number=atoi(string); |
728 | |
729 | return(1); |
730 | } |
731 | |
732 | |
733 | /*++++++++++++++++++++++++++++++++++++++ |
734 | Convert a string to a floating point number (checking that it really is a number). |
735 | |
736 | int ParseXML_GetFloating Returns 1 if a number could be found or 0 otherwise. |
737 | |
738 | const char *string The string to be parsed. |
739 | |
740 | int *number Returns the number. |
741 | ++++++++++++++++++++++++++++++++++++++*/ |
742 | |
743 | int ParseXML_GetFloating(const char *string,double *number) |
744 | { |
745 | const char *p=string; |
746 | |
747 | if(*p=='-' || *p=='+') |
748 | p++; |
749 | |
750 | while(isdigit(*p) || *p=='.') |
751 | p++; |
752 | |
753 | if(*p) |
754 | return(0); |
755 | |
756 | *number=atof(string); |
757 | |
758 | return(1); |
759 | } |
Properties
Name | Value |
---|---|
cvs:description | A simple generic XML parser. |