Check out the latest version of Routino: svn co http://routino.org/svn/trunk routino
Annotation of /trunk/src/xmlparse.l
Parent Directory
|
Revision Log
Revision 351 -
(hide annotations)
(download)
Tue Apr 6 18:48:07 2010 UTC (15 years ago) by amb
File size: 17358 byte(s)
Tue Apr 6 18:48:07 2010 UTC (15 years ago) by amb
File size: 17358 byte(s)
Change error message for bad character in a quoted string. Make sure attribute values are cleared before calling tag function (for end-tags).
1 | amb | 334 | %{ |
2 | /*************************************** | ||
3 | amb | 351 | $Header: /home/amb/CVS/routino/src/xmlparse.l,v 1.5 2010-04-06 18:48:07 amb Exp $ |
4 | amb | 334 | |
5 | A simple generic XML parser where the structure comes from the function parameters. | ||
6 | amb | 348 | 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 | amb | 334 | |
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 | /* Parser outputs */ | ||
33 | |||
34 | amb | 348 | #define LEX_EOF 0 |
35 | amb | 334 | |
36 | amb | 348 | #define LEX_TAG_BEGIN 1 |
37 | #define LEX_XML_DECL_BEGIN 2 | ||
38 | #define LEX_TAG_POP 3 | ||
39 | #define LEX_TAG_PUSH 4 | ||
40 | #define LEX_XML_DECL_FINISH 6 | ||
41 | #define LEX_TAG_FINISH 7 | ||
42 | #define LEX_ATTR_KEY 8 | ||
43 | #define LEX_ATTR_VAL 9 | ||
44 | amb | 334 | |
45 | amb | 348 | #define LEX_ERROR 100 |
46 | |||
47 | #define LEX_ERROR_TAG_START 101 | ||
48 | #define LEX_ERROR_XML_DECL_START 102 | ||
49 | #define LEX_ERROR_TAG 103 | ||
50 | #define LEX_ERROR_XML_DECL 104 | ||
51 | #define LEX_ERROR_ATTR 105 | ||
52 | #define LEX_ERROR_END_TAG 106 | ||
53 | #define LEX_ERROR_COMMENT 107 | ||
54 | #define LEX_ERROR_CLOSE 108 | ||
55 | amb | 351 | #define LEX_ERROR_ATTR_VAL 109 |
56 | amb | 348 | |
57 | #define LEX_ERROR_UNEXP_TAG 201 | ||
58 | #define LEX_ERROR_UNBALANCED 202 | ||
59 | #define LEX_ERROR_NO_START 203 | ||
60 | #define LEX_ERROR_UNEXP_ATT 204 | ||
61 | #define LEX_ERROR_UNEXP_EOF 205 | ||
62 | #define LEX_ERROR_XML_NOT_FIRST 206 | ||
63 | |||
64 | |||
65 | amb | 334 | /* Lexer definitions */ |
66 | |||
67 | #define YY_SKIP_YYWRAP 1 /* Remove error with prototype of ..._yywrap */ | ||
68 | #ifndef yywrap | ||
69 | /*+ Needed in lex but does nothing. +*/ | ||
70 | #define yywrap() 1 | ||
71 | #endif | ||
72 | |||
73 | /*+ Reset the current string. +*/ | ||
74 | #define reset_string \ | ||
75 | if(string) *string=0; \ | ||
76 | stringused=0; | ||
77 | |||
78 | /*+ append information to the current string. +*/ | ||
79 | #define append_string(xx) \ | ||
80 | newlen=strlen(xx); \ | ||
81 | if((stringused+newlen)>=stringlen) \ | ||
82 | string=(char*)realloc((void*)string,stringlen=(stringused+newlen+16)); \ | ||
83 | strcpy(string+stringused,xx); \ | ||
84 | stringused+=newlen; | ||
85 | |||
86 | #define YY_NO_INPUT | ||
87 | |||
88 | |||
89 | /* Lexer functions and variables */ | ||
90 | |||
91 | extern int yylex(void); | ||
92 | |||
93 | static char *yylval=NULL; | ||
94 | |||
95 | %} | ||
96 | |||
97 | amb | 344 | %option 8bit |
98 | amb | 348 | %option pointer |
99 | amb | 344 | %option batch |
100 | %option yylineno | ||
101 | amb | 348 | |
102 | amb | 344 | %option nodefault |
103 | %option perf-report | ||
104 | %option fast | ||
105 | amb | 348 | %option nounput |
106 | amb | 344 | |
107 | amb | 334 | |
108 | amb | 348 | /* Grammar based on http://www.w3.org/TR/2004/REC-xml-20040204/ but for ASCII not Unicode. */ |
109 | amb | 334 | |
110 | amb | 348 | S [ \t\r\n] |
111 | amb | 334 | |
112 | amb | 348 | letter [a-zA-Z] |
113 | digit [0-9] | ||
114 | xdigit [a-fA-F0-9] | ||
115 | |||
116 | namechar ({letter}|{digit}|[-._:]) | ||
117 | name ({letter}|[_:]){namechar}* | ||
118 | |||
119 | entityref &{name}; | ||
120 | charref &#({digit}+|x{xdigit}+); | ||
121 | |||
122 | |||
123 | amb | 334 | %x COMMENT |
124 | amb | 348 | %x CDATA |
125 | %x DOCTYPE | ||
126 | %x XML_DECL_START XML_DECL | ||
127 | %x TAG_START TAG | ||
128 | %x ATTR_KEY ATTR_VAL | ||
129 | %x END_TAG1 END_TAG2 | ||
130 | amb | 334 | %x DQUOTED SQUOTED |
131 | |||
132 | %% | ||
133 | /* Must use static variables since the parser returns often. */ | ||
134 | static char *string=NULL; | ||
135 | static int stringlen=0,stringused=0; | ||
136 | amb | 348 | static int after_attr=0; |
137 | amb | 334 | int newlen; |
138 | amb | 348 | int doctype_depth=0; |
139 | amb | 334 | |
140 | amb | 348 | /* Handle top level entities */ |
141 | amb | 334 | |
142 | "<!--" { BEGIN(COMMENT); } | ||
143 | amb | 348 | "<![CDATA[" { BEGIN(CDATA); } |
144 | "<!DOCTYPE" { BEGIN(DOCTYPE); doctype_depth=0; } | ||
145 | "</" { BEGIN(END_TAG1); } | ||
146 | "<?" { BEGIN(XML_DECL_START); } | ||
147 | amb | 334 | "<" { BEGIN(TAG_START); } |
148 | amb | 348 | ">" { return(LEX_ERROR_CLOSE); } |
149 | [^<>]+ { } | ||
150 | amb | 334 | |
151 | amb | 348 | /* Comments */ |
152 | amb | 334 | |
153 | amb | 348 | <COMMENT>"--->" { return(LEX_ERROR_COMMENT); } |
154 | <COMMENT>"-->" { BEGIN(INITIAL); } | ||
155 | <COMMENT>"--"[^->]+ { } | ||
156 | <COMMENT>[^-]+ { } | ||
157 | amb | 334 | <COMMENT>"-" { } |
158 | |||
159 | amb | 348 | /* CDATA */ |
160 | amb | 334 | |
161 | amb | 348 | <CDATA>"]]>" { BEGIN(INITIAL); } |
162 | <CDATA>"]" { } | ||
163 | <CDATA>[^]]+ { } | ||
164 | amb | 334 | |
165 | amb | 348 | /* CDATA */ |
166 | amb | 334 | |
167 | amb | 348 | <DOCTYPE>"<" { doctype_depth++; } |
168 | <DOCTYPE>">" { if(doctype_depth==0) BEGIN(INITIAL); else doctype_depth--; } | ||
169 | <DOCTYPE>[^<>]+ { } | ||
170 | amb | 334 | |
171 | amb | 348 | /* XML Declaration start */ |
172 | |||
173 | <XML_DECL_START>{name} { BEGIN(XML_DECL); yylval=yytext; return(LEX_XML_DECL_BEGIN); } | ||
174 | <XML_DECL_START>.|\n { return(LEX_ERROR_XML_DECL_START); } | ||
175 | |||
176 | /* Tag middle */ | ||
177 | |||
178 | <XML_DECL>"?>" { BEGIN(INITIAL); return(LEX_XML_DECL_FINISH); } | ||
179 | <XML_DECL>{S}+ { } | ||
180 | <XML_DECL>{name} { after_attr=XML_DECL; BEGIN(ATTR_KEY); yylval=yytext; return(LEX_ATTR_KEY); } | ||
181 | <XML_DECL>.|\n { return(LEX_ERROR_XML_DECL); } | ||
182 | |||
183 | /* Any tag start */ | ||
184 | |||
185 | <TAG_START>{name} { BEGIN(TAG); yylval=yytext; return(LEX_TAG_BEGIN); } | ||
186 | <TAG_START>.|\n { return(LEX_ERROR_TAG_START); } | ||
187 | |||
188 | /* End-tag start */ | ||
189 | |||
190 | <END_TAG1>{name} { BEGIN(END_TAG2); yylval=yytext; return(LEX_TAG_POP); } | ||
191 | <END_TAG1>.|\n { return(LEX_ERROR_END_TAG); } | ||
192 | |||
193 | <END_TAG2>">" { BEGIN(INITIAL); } | ||
194 | <END_TAG2>.|\n { return(LEX_ERROR_END_TAG); } | ||
195 | |||
196 | /* Any tag middle */ | ||
197 | |||
198 | amb | 334 | <TAG>"/>" { BEGIN(INITIAL); return(LEX_TAG_FINISH); } |
199 | <TAG>">" { BEGIN(INITIAL); return(LEX_TAG_PUSH); } | ||
200 | amb | 348 | <TAG>{S}+ { } |
201 | <TAG>{name} { after_attr=TAG; BEGIN(ATTR_KEY); yylval=yytext; return(LEX_ATTR_KEY); } | ||
202 | <TAG>.|\n { return(LEX_ERROR_TAG); } | ||
203 | amb | 334 | |
204 | amb | 348 | /* Attributes */ |
205 | amb | 334 | |
206 | amb | 348 | <ATTR_KEY>= { BEGIN(ATTR_VAL); } |
207 | <ATTR_KEY>.|\n { return(LEX_ERROR_ATTR); } | ||
208 | amb | 334 | |
209 | amb | 348 | <ATTR_VAL>\" { BEGIN(DQUOTED); reset_string; } |
210 | <ATTR_VAL>\' { BEGIN(SQUOTED); reset_string; } | ||
211 | <ATTR_VAL>.|\n { return(LEX_ERROR_ATTR); } | ||
212 | |||
213 | amb | 334 | /* Quoted strings */ |
214 | |||
215 | amb | 348 | <DQUOTED>\" { BEGIN(after_attr); yylval=string; return(LEX_ATTR_VAL); } |
216 | <DQUOTED>{entityref} { append_string(yytext); } | ||
217 | <DQUOTED>{charref} { append_string(yytext); } | ||
218 | amb | 351 | <DQUOTED>[<>&] { return(LEX_ERROR_ATTR_VAL); } |
219 | amb | 348 | <DQUOTED>[^<>&\"]+ { append_string(yytext); } |
220 | amb | 334 | |
221 | amb | 348 | <SQUOTED>\' { BEGIN(after_attr); yylval=string; return(LEX_ATTR_VAL); } |
222 | <SQUOTED>{entityref} { append_string(yytext); } | ||
223 | <SQUOTED>{charref} { append_string(yytext); } | ||
224 | amb | 351 | <SQUOTED>[<>&] { return(LEX_ERROR_ATTR_VAL); } |
225 | amb | 348 | <SQUOTED>[^<>&\']+ { append_string(yytext); } |
226 | amb | 334 | |
227 | /* End of file */ | ||
228 | |||
229 | amb | 348 | <<EOF>> { free(string); string=NULL; BEGIN(INITIAL); return(LEX_EOF); } |
230 | amb | 334 | |
231 | %% | ||
232 | |||
233 | #include "xmlparse.h" | ||
234 | |||
235 | amb | 348 | |
236 | /*++++++++++++++++++++++++++++++++++++++ | ||
237 | A function to call the callback function with the parameters needed. | ||
238 | |||
239 | char *name The name of the tag. | ||
240 | |||
241 | void (*callback)() The callback function. | ||
242 | |||
243 | int type The type of tag (start and/or end). | ||
244 | |||
245 | int nattributes The number of attributes collected. | ||
246 | |||
247 | char *attributes[XMLPARSE_MAX_ATTRS] The list of attributes. | ||
248 | ++++++++++++++++++++++++++++++++++++++*/ | ||
249 | |||
250 | amb | 344 | static inline void call_callback(char *name,void (*callback)(),int type,int nattributes,char *attributes[XMLPARSE_MAX_ATTRS]) |
251 | { | ||
252 | switch(nattributes) | ||
253 | { | ||
254 | case 0: (*callback)(type); break; | ||
255 | case 1: (*callback)(type,attributes[0]); break; | ||
256 | case 2: (*callback)(type,attributes[0],attributes[1]); break; | ||
257 | case 3: (*callback)(type,attributes[0],attributes[1],attributes[2]); break; | ||
258 | case 4: (*callback)(type,attributes[0],attributes[1],attributes[2],attributes[3]); break; | ||
259 | case 5: (*callback)(type,attributes[0],attributes[1],attributes[2],attributes[3],attributes[4]); break; | ||
260 | case 6: (*callback)(type,attributes[0],attributes[1],attributes[2],attributes[3],attributes[4],attributes[5]); break; | ||
261 | case 7: (*callback)(type,attributes[0],attributes[1],attributes[2],attributes[3],attributes[4],attributes[5],attributes[6]); break; | ||
262 | case 8: (*callback)(type,attributes[0],attributes[1],attributes[2],attributes[3],attributes[4],attributes[5],attributes[6],attributes[7]); break; | ||
263 | case 9: (*callback)(type,attributes[0],attributes[1],attributes[2],attributes[3],attributes[4],attributes[5],attributes[6],attributes[7],attributes[8]); break; | ||
264 | 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; | ||
265 | 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; | ||
266 | 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; | ||
267 | 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; | ||
268 | 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; | ||
269 | 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; | ||
270 | 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; | ||
271 | amb | 334 | |
272 | amb | 344 | default: |
273 | amb | 348 | fprintf(stderr,"XML Parser: Error on line %d: too many attributes for tag '%s'.\n",yylineno,name); |
274 | amb | 344 | exit(1); |
275 | } | ||
276 | } | ||
277 | |||
278 | |||
279 | amb | 334 | /*++++++++++++++++++++++++++++++++++++++ |
280 | Parse the XML and call the functions for each tag as seen. | ||
281 | |||
282 | amb | 348 | int ParseXML Returns 0 if OK or something else in case of an error. |
283 | |||
284 | amb | 334 | FILE *file The file to parse. |
285 | |||
286 | xmltag **tags The array of pointers to tags for the top level. | ||
287 | amb | 337 | |
288 | 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. | ||
289 | amb | 334 | ++++++++++++++++++++++++++++++++++++++*/ |
290 | |||
291 | amb | 348 | int ParseXML(FILE *file,xmltag **tags,int ignore_unknown_attributes) |
292 | amb | 334 | { |
293 | int yychar,i; | ||
294 | |||
295 | int nattributes=0; | ||
296 | amb | 351 | char *attributes[XMLPARSE_MAX_ATTRS]={NULL}; |
297 | amb | 334 | int attribute=0; |
298 | |||
299 | int stackdepth=0,stackused=0; | ||
300 | amb | 344 | xmltag ***tags_stack=NULL; |
301 | xmltag **tag_stack=NULL; | ||
302 | amb | 334 | xmltag *tag=NULL; |
303 | |||
304 | static int first=1; | ||
305 | |||
306 | /* Parser (re)-initialisation */ | ||
307 | |||
308 | yyin=file; | ||
309 | |||
310 | if(!first) | ||
311 | yyrestart(NULL); | ||
312 | |||
313 | first=0; | ||
314 | |||
315 | /* The actual parser. */ | ||
316 | |||
317 | amb | 348 | do |
318 | { | ||
319 | yychar=yylex(); | ||
320 | |||
321 | amb | 334 | switch(yychar) |
322 | { | ||
323 | amb | 348 | /* The start of a tag for an XML declaration */ |
324 | |||
325 | case LEX_XML_DECL_BEGIN: | ||
326 | |||
327 | if(tag_stack) | ||
328 | { | ||
329 | fprintf(stderr,"XML Parser: Error on line %d: XML declaration not before all other tags.\n",yylineno); | ||
330 | yychar=LEX_ERROR_XML_NOT_FIRST; | ||
331 | break; | ||
332 | } | ||
333 | |||
334 | amb | 334 | /* The start of a tag for an element */ |
335 | |||
336 | case LEX_TAG_BEGIN: | ||
337 | |||
338 | tag=NULL; | ||
339 | |||
340 | for(i=0;tags[i];i++) | ||
341 | if(!strcasecmp(yylval,tags[i]->name)) | ||
342 | { | ||
343 | tag=tags[i]; | ||
344 | |||
345 | amb | 351 | for(i=0;i<XMLPARSE_MAX_ATTRS;i++) |
346 | if(attributes[i]) | ||
347 | { | ||
348 | free(attributes[i]); | ||
349 | attributes[i]=NULL; | ||
350 | } | ||
351 | amb | 334 | |
352 | for(i=0;i<XMLPARSE_MAX_ATTRS;i++) | ||
353 | if(!tag->attributes[i]) | ||
354 | break; | ||
355 | |||
356 | nattributes=i; | ||
357 | |||
358 | break; | ||
359 | } | ||
360 | |||
361 | if(tag==NULL) | ||
362 | { | ||
363 | amb | 348 | fprintf(stderr,"XML Parser: Error on line %d: unexpected tag '%s'.\n",yylineno,yylval); |
364 | yychar=LEX_ERROR_UNEXP_TAG; | ||
365 | amb | 334 | } |
366 | amb | 348 | |
367 | amb | 334 | break; |
368 | |||
369 | /* The end of the start-tag for an element */ | ||
370 | |||
371 | case LEX_TAG_PUSH: | ||
372 | |||
373 | if(stackused==stackdepth) | ||
374 | amb | 344 | { |
375 | tag_stack =(xmltag**) realloc((void*)tag_stack ,(stackdepth+=8)*sizeof(xmltag*)); | ||
376 | tags_stack=(xmltag***)realloc((void*)tags_stack,(stackdepth+=8)*sizeof(xmltag**)); | ||
377 | } | ||
378 | amb | 334 | |
379 | amb | 344 | tag_stack [stackused]=tag; |
380 | tags_stack[stackused]=tags; | ||
381 | stackused++; | ||
382 | |||
383 | if(tag->callback) | ||
384 | call_callback(tag->name,tag->callback,XMLPARSE_TAG_START,nattributes,attributes); | ||
385 | |||
386 | amb | 334 | tags=tag->subtags; |
387 | |||
388 | amb | 344 | break; |
389 | |||
390 | amb | 348 | /* The end of the empty-element-tag for an XML declaration */ |
391 | |||
392 | case LEX_XML_DECL_FINISH: | ||
393 | |||
394 | amb | 334 | /* The end of the empty-element-tag for an element */ |
395 | |||
396 | case LEX_TAG_FINISH: | ||
397 | |||
398 | if(tag->callback) | ||
399 | amb | 344 | call_callback(tag->name,tag->callback,XMLPARSE_TAG_START|XMLPARSE_TAG_END,nattributes,attributes); |
400 | amb | 334 | |
401 | amb | 344 | if(stackused>0) |
402 | tag=tag_stack[stackused-1]; | ||
403 | else | ||
404 | tag=NULL; | ||
405 | amb | 334 | |
406 | break; | ||
407 | |||
408 | /* The end of the end-tag for an element */ | ||
409 | |||
410 | case LEX_TAG_POP: | ||
411 | |||
412 | amb | 344 | stackused--; |
413 | tags=tags_stack[stackused]; | ||
414 | tag =tag_stack [stackused]; | ||
415 | amb | 334 | |
416 | amb | 348 | if(strcmp(tag->name,yylval)) |
417 | { | ||
418 | fprintf(stderr,"XML Parser: Error on line %d: end tag '</%s>' doesn't match start tag '<%s ...>'.\n",yylineno,yylval,tag->name); | ||
419 | yychar=LEX_ERROR_UNBALANCED; | ||
420 | } | ||
421 | |||
422 | if(stackused<0) | ||
423 | { | ||
424 | fprintf(stderr,"XML Parser: Error on line %d: end tag '</%s>' seen but there was no start tag '<%s ...>'.\n",yylineno,yylval,yylval); | ||
425 | yychar=LEX_ERROR_NO_START; | ||
426 | } | ||
427 | |||
428 | amb | 351 | for(i=0;i<XMLPARSE_MAX_ATTRS;i++) |
429 | if(attributes[i]) | ||
430 | { | ||
431 | free(attributes[i]); | ||
432 | attributes[i]=NULL; | ||
433 | } | ||
434 | |||
435 | amb | 344 | if(tag->callback) |
436 | call_callback(tag->name,tag->callback,XMLPARSE_TAG_END,nattributes,attributes); | ||
437 | |||
438 | amb | 348 | if(stackused>0) |
439 | tag=tag_stack[stackused-1]; | ||
440 | else | ||
441 | tag=NULL; | ||
442 | amb | 344 | |
443 | amb | 334 | break; |
444 | |||
445 | /* An attribute key */ | ||
446 | |||
447 | case LEX_ATTR_KEY: | ||
448 | |||
449 | attribute=-1; | ||
450 | |||
451 | for(i=0;i<nattributes;i++) | ||
452 | if(!strcasecmp(yylval,tag->attributes[i])) | ||
453 | { | ||
454 | attribute=i; | ||
455 | |||
456 | break; | ||
457 | } | ||
458 | |||
459 | if(attribute==-1) | ||
460 | { | ||
461 | amb | 337 | if(ignore_unknown_attributes==0) |
462 | { | ||
463 | amb | 348 | 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 | amb | 337 | } |
466 | else if(ignore_unknown_attributes==1) | ||
467 | amb | 348 | fprintf(stderr,"XML Parser: Warning on line %d: unexpected attribute '%s' for tag '%s'.\n",yylineno,yylval,tag->name); |
468 | amb | 334 | } |
469 | amb | 348 | |
470 | amb | 334 | break; |
471 | |||
472 | /* An attribute value */ | ||
473 | |||
474 | case LEX_ATTR_VAL: | ||
475 | |||
476 | amb | 337 | if(yylval && attribute!=-1) |
477 | amb | 334 | attributes[attribute]=strcpy(malloc(strlen(yylval)+1),yylval); |
478 | amb | 348 | |
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 | amb | 351 | |
525 | case LEX_ERROR_ATTR_VAL: | ||
526 | fprintf(stderr,"XML Parser: Error on line %d: invalid character seen in attribute value.\n",yylineno); | ||
527 | break; | ||
528 | amb | 334 | } |
529 | amb | 348 | } |
530 | while(yychar>LEX_EOF && yychar<LEX_ERROR); | ||
531 | amb | 334 | |
532 | /* Delete the tagdata */ | ||
533 | |||
534 | for(i=0;i<nattributes;i++) | ||
535 | if(attributes[i]) | ||
536 | free(attributes[i]); | ||
537 | |||
538 | if(stackdepth) | ||
539 | amb | 344 | free(tags_stack); |
540 | amb | 348 | |
541 | return(yychar); | ||
542 | amb | 334 | } |
543 | amb | 348 | |
544 | |||
545 | /*++++++++++++++++++++++++++++++++++++++ | ||
546 | Return the current parser line number. | ||
547 | |||
548 | int ParseXML_LineNumber Returns the line number. | ||
549 | ++++++++++++++++++++++++++++++++++++++*/ | ||
550 | |||
551 | int ParseXML_LineNumber(void) | ||
552 | { | ||
553 | return(yylineno); | ||
554 | } |
Properties
Name | Value |
---|---|
cvs:description | A simple generic XML parser. |