Routino SVN Repository Browser

Check out the latest version of Routino: svn co http://routino.org/svn/trunk routino

ViewVC logotype

Annotation of /trunk/src/xmlparse.l

Parent Directory Parent Directory | Revision Log Revision Log


Revision 791 - (hide annotations) (download)
Sat Jun 18 18:36:40 2011 UTC (13 years, 9 months ago) by amb
File size: 27649 byte(s)
Don't use the flex yylineno but keep track with an unsigned long long line
counter instead (if there are more than 2^31 nodes then there are more than 2^31
lines as well).

1 amb 334 %{
2     /***************************************
3     A simple generic XML parser where the structure comes from the function parameters.
4 amb 348 Not intended to be fully conforming to XML staandard or a validating parser but
5     sufficient to parse OSM XML and simple program configuration files.
6 amb 334
7     Part of the Routino routing software.
8     ******************/ /******************
9 amb 773 This file Copyright 2010-2011 Andrew M. Bishop
10 amb 334
11     This program is free software: you can redistribute it and/or modify
12     it under the terms of the GNU Affero General Public License as published by
13     the Free Software Foundation, either version 3 of the License, or
14     (at your option) any later version.
15    
16     This program is distributed in the hope that it will be useful,
17     but WITHOUT ANY WARRANTY; without even the implied warranty of
18     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19     GNU Affero General Public License for more details.
20    
21     You should have received a copy of the GNU Affero General Public License
22     along with this program. If not, see <http://www.gnu.org/licenses/>.
23     ***************************************/
24    
25    
26     #include <stdio.h>
27     #include <stdlib.h>
28 amb 363 #include <ctype.h>
29 amb 334 #include <string.h>
30 amb 787 #include <strings.h>
31 amb 334
32 amb 356 #include "xmlparse.h"
33    
34    
35 amb 334 /* Parser outputs */
36    
37 amb 348 #define LEX_EOF 0
38 amb 334
39 amb 348 #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 amb 334
48 amb 348 #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 amb 351 #define LEX_ERROR_ATTR_VAL 109
59 amb 356 #define LEX_ERROR_ENTITY_REF 110
60     #define LEX_ERROR_CHAR_REF 111
61 amb 348
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 amb 363 #define LEX_ERROR_CALLBACK 255
70 amb 348
71 amb 363
72 amb 334 /* Lexer definitions */
73    
74     /*+ Reset the current string. +*/
75     #define reset_string \
76 amb 389 if(!string) string=(char*)malloc(16); \
77     *string=0; \
78 amb 334 stringused=0;
79    
80     /*+ append information to the current string. +*/
81     #define append_string(xx) \
82     newlen=strlen(xx); \
83     if((stringused+newlen)>=stringlen) \
84     string=(char*)realloc((void*)string,stringlen=(stringused+newlen+16)); \
85     strcpy(string+stringused,xx); \
86     stringused+=newlen;
87    
88    
89     /* Lexer functions and variables */
90    
91     extern int yylex(void);
92    
93     static char *yylval=NULL;
94    
95 amb 374 static int xmlparse_options;
96    
97 amb 791 static unsigned long long lineno;
98    
99 amb 334 %}
100    
101 amb 344 %option 8bit
102 amb 348 %option pointer
103 amb 344 %option batch
104 amb 787 %option never-interactive
105    
106 amb 344 %option nodefault
107     %option perf-report
108     %option fast
109 amb 787 %option noread
110    
111 amb 348 %option nounput
112 amb 787 %option noinput
113     %option noyywrap
114 amb 344
115 amb 334
116 amb 487 /* Grammar based on http://www.w3.org/TR/2004/REC-xml-20040204/ but for ASCII tags not Unicode. */
117 amb 334
118 amb 791 S [ \t]
119 amb 334
120 amb 487 U1 [\x09\x0A\x0D\x20-\x7F]
121 amb 483 U2 [\xC2-\xDF][\x80-\xBF]
122 amb 487 U3a \xE0[\xA0-\xBF][\x80-\xBF]
123     U3b [\xE1-\xEC][\x80-\xBF][\x80-\xBF]
124     U3c \xED[\x80-\x9F][\x80-\xBF]
125     U3d [\xEE-\xEF][\x80-\xBF][\x80-\xBF]
126     U3 {U3a}|{U3b}|{U3c}|{U3d}
127     U4a \xF0[\x90-\xBF][\x80-\xBF][\x80-\xBF]
128     U4b [\xF1-\xF3][\x80-\xBF][\x80-\xBF][\x80-\xBF]
129     U4c \xF4[\x80-\x8F][\x80-\xBF][\x80-\xBF]
130     U4 {U4a}|{U4b}|{U4c}
131 amb 483
132     U ({U1}|{U2}|{U3}|{U4})
133 amb 487 UquotedS ([\x09\x0A\x0D\x20-\x25\x28-\x3B\x3D\x3F-\x7F]|{U2}|{U3}|{U4})
134     UquotedD ([\x09\x0A\x0D\x20-\x21\x23-\x25\x27-\x3B\x3D\x3F-\x7F]|{U2}|{U3}|{U4})
135 amb 483
136     N (\n|\r\n)
137    
138 amb 348 letter [a-zA-Z]
139     digit [0-9]
140     xdigit [a-fA-F0-9]
141    
142     namechar ({letter}|{digit}|[-._:])
143     name ({letter}|[_:]){namechar}*
144    
145     entityref &{name};
146     charref &#({digit}+|x{xdigit}+);
147    
148    
149 amb 334 %x COMMENT
150 amb 348 %x CDATA
151     %x DOCTYPE
152     %x XML_DECL_START XML_DECL
153     %x TAG_START TAG
154     %x ATTR_KEY ATTR_VAL
155     %x END_TAG1 END_TAG2
156 amb 334 %x DQUOTED SQUOTED
157    
158     %%
159     /* Must use static variables since the parser returns often. */
160     static char *string=NULL;
161     static int stringlen=0,stringused=0;
162 amb 348 static int after_attr=0;
163 amb 334 int newlen;
164 amb 348 int doctype_depth=0;
165 amb 334
166 amb 348 /* Handle top level entities */
167 amb 334
168     "<!--" { BEGIN(COMMENT); }
169 amb 348 "<![CDATA[" { BEGIN(CDATA); }
170     "<!DOCTYPE" { BEGIN(DOCTYPE); doctype_depth=0; }
171     "</" { BEGIN(END_TAG1); }
172     "<?" { BEGIN(XML_DECL_START); }
173 amb 334 "<" { BEGIN(TAG_START); }
174 amb 348 ">" { return(LEX_ERROR_CLOSE); }
175 amb 791 {N} { lineno++; }
176     [^<>] { }
177 amb 334
178 amb 348 /* Comments */
179 amb 334
180 amb 348 <COMMENT>"--->" { return(LEX_ERROR_COMMENT); }
181     <COMMENT>"-->" { BEGIN(INITIAL); }
182 amb 791 <COMMENT>"--"[^->] { }
183     <COMMENT>{N} { lineno++; }
184     <COMMENT>[^-] { }
185 amb 334 <COMMENT>"-" { }
186    
187 amb 348 /* CDATA */
188 amb 334
189 amb 348 <CDATA>"]]>" { BEGIN(INITIAL); }
190     <CDATA>"]" { }
191 amb 791 <CDATA>{N} { lineno++; }
192     <CDATA>[^]] { }
193 amb 334
194 amb 348 /* CDATA */
195 amb 334
196 amb 348 <DOCTYPE>"<" { doctype_depth++; }
197     <DOCTYPE>">" { if(doctype_depth==0) BEGIN(INITIAL); else doctype_depth--; }
198 amb 791 <DOCTYPE>{N} { lineno++; }
199     <DOCTYPE>[^<>] { }
200 amb 334
201 amb 348 /* XML Declaration start */
202    
203 amb 483 <XML_DECL_START>xml { BEGIN(XML_DECL); yylval=yytext; return(LEX_XML_DECL_BEGIN); }
204 amb 791 <XML_DECL_START>{N} { /* lineno++; */ return(LEX_ERROR_XML_DECL_START); }
205     <XML_DECL_START>. { return(LEX_ERROR_XML_DECL_START); }
206 amb 348
207     /* Tag middle */
208    
209     <XML_DECL>"?>" { BEGIN(INITIAL); return(LEX_XML_DECL_FINISH); }
210     <XML_DECL>{S}+ { }
211 amb 791 <XML_DECL>{N} { lineno++; }
212 amb 348 <XML_DECL>{name} { after_attr=XML_DECL; BEGIN(ATTR_KEY); yylval=yytext; return(LEX_ATTR_KEY); }
213 amb 791 <XML_DECL>. { return(LEX_ERROR_XML_DECL); }
214 amb 348
215     /* Any tag start */
216    
217     <TAG_START>{name} { BEGIN(TAG); yylval=yytext; return(LEX_TAG_BEGIN); }
218 amb 791 <TAG_START>{N} { /* lineno++; */ return(LEX_ERROR_TAG_START); }
219     <TAG_START>. { return(LEX_ERROR_TAG_START); }
220 amb 348
221     /* End-tag start */
222    
223     <END_TAG1>{name} { BEGIN(END_TAG2); yylval=yytext; return(LEX_TAG_POP); }
224 amb 791 <END_TAG1>{N} { /* lineno++; */ return(LEX_ERROR_END_TAG); }
225     <END_TAG1>. { return(LEX_ERROR_END_TAG); }
226 amb 348
227     <END_TAG2>">" { BEGIN(INITIAL); }
228 amb 791 <END_TAG2>{N} { /* lineno++; */ return(LEX_ERROR_END_TAG); }
229     <END_TAG2>. { return(LEX_ERROR_END_TAG); }
230 amb 348
231     /* Any tag middle */
232    
233 amb 334 <TAG>"/>" { BEGIN(INITIAL); return(LEX_TAG_FINISH); }
234     <TAG>">" { BEGIN(INITIAL); return(LEX_TAG_PUSH); }
235 amb 348 <TAG>{S}+ { }
236 amb 791 <TAG>{N} { lineno++; }
237 amb 348 <TAG>{name} { after_attr=TAG; BEGIN(ATTR_KEY); yylval=yytext; return(LEX_ATTR_KEY); }
238 amb 791 <TAG>. { return(LEX_ERROR_TAG); }
239 amb 334
240 amb 348 /* Attributes */
241 amb 334
242 amb 348 <ATTR_KEY>= { BEGIN(ATTR_VAL); }
243 amb 791 <ATTR_KEY>{N} { /* lineno++; */ return(LEX_ERROR_ATTR); }
244     <ATTR_KEY>. { return(LEX_ERROR_ATTR); }
245 amb 334
246 amb 348 <ATTR_VAL>\" { BEGIN(DQUOTED); reset_string; }
247     <ATTR_VAL>\' { BEGIN(SQUOTED); reset_string; }
248 amb 791 <ATTR_VAL>{N} { /* lineno++; */ return(LEX_ERROR_ATTR); }
249     <ATTR_VAL>. { return(LEX_ERROR_ATTR); }
250 amb 348
251 amb 334 /* Quoted strings */
252    
253 amb 348 <DQUOTED>\" { BEGIN(after_attr); yylval=string; return(LEX_ATTR_VAL); }
254 amb 374 <DQUOTED>{entityref} { if(xmlparse_options&XMLPARSE_RETURN_ATTR_ENCODED) {append_string(yytext);}
255     else { const char *str=ParseXML_Decode_Entity_Ref(yytext); if(str) {append_string(str);} else {yylval=yytext; return(LEX_ERROR_ENTITY_REF);} } }
256     <DQUOTED>{charref} { if(xmlparse_options&XMLPARSE_RETURN_ATTR_ENCODED) {append_string(yytext);}
257     else { const char *str=ParseXML_Decode_Char_Ref(yytext); if(str) {append_string(str);} else {yylval=yytext; return(LEX_ERROR_CHAR_REF);} } }
258 amb 487 <DQUOTED>[<>&\"] { yylval=yytext; return(LEX_ERROR_ATTR_VAL); }
259     <DQUOTED>{UquotedD}+ { append_string(yytext); }
260     <DQUOTED>. { yylval=yytext; return(LEX_ERROR_ATTR_VAL); }
261 amb 334
262 amb 348 <SQUOTED>\' { BEGIN(after_attr); yylval=string; return(LEX_ATTR_VAL); }
263 amb 374 <SQUOTED>{entityref} { if(xmlparse_options&XMLPARSE_RETURN_ATTR_ENCODED) {append_string(yytext);}
264     else { const char *str=ParseXML_Decode_Entity_Ref(yytext); if(str) {append_string(str);} else {yylval=yytext; return(LEX_ERROR_ENTITY_REF);} } }
265     <SQUOTED>{charref} { if(xmlparse_options&XMLPARSE_RETURN_ATTR_ENCODED) {append_string(yytext);}
266     else { const char *str=ParseXML_Decode_Char_Ref(yytext); if(str) {append_string(str);} else {yylval=yytext; return(LEX_ERROR_CHAR_REF);} } }
267 amb 356 <SQUOTED>[<>&] { yylval=yytext; return(LEX_ERROR_ATTR_VAL); }
268 amb 487 <SQUOTED>{UquotedS}+ { append_string(yytext); }
269     <SQUOTED>. { yylval=yytext; return(LEX_ERROR_ATTR_VAL); }
270 amb 334
271     /* End of file */
272    
273 amb 368 <<EOF>> { free(string); string=NULL; stringlen=stringused=0; BEGIN(INITIAL); return(LEX_EOF); }
274 amb 334
275     %%
276    
277    
278 amb 348 /*++++++++++++++++++++++++++++++++++++++
279     A function to call the callback function with the parameters needed.
280    
281 amb 363 int call_callback Returns 1 if the callback returned with an error.
282    
283 amb 356 const char *name The name of the tag.
284 amb 348
285 amb 363 int (*callback)() The callback function.
286 amb 348
287     int type The type of tag (start and/or end).
288    
289     int nattributes The number of attributes collected.
290    
291     char *attributes[XMLPARSE_MAX_ATTRS] The list of attributes.
292     ++++++++++++++++++++++++++++++++++++++*/
293    
294 amb 363 static inline int call_callback(const char *name,int (*callback)(),int type,int nattributes,char *attributes[XMLPARSE_MAX_ATTRS])
295 amb 344 {
296     switch(nattributes)
297     {
298 amb 373 case 0: return (*callback)(name,type);
299     case 1: return (*callback)(name,type,attributes[0]);
300     case 2: return (*callback)(name,type,attributes[0],attributes[1]);
301     case 3: return (*callback)(name,type,attributes[0],attributes[1],attributes[2]);
302     case 4: return (*callback)(name,type,attributes[0],attributes[1],attributes[2],attributes[3]);
303     case 5: return (*callback)(name,type,attributes[0],attributes[1],attributes[2],attributes[3],attributes[4]);
304     case 6: return (*callback)(name,type,attributes[0],attributes[1],attributes[2],attributes[3],attributes[4],attributes[5]);
305     case 7: return (*callback)(name,type,attributes[0],attributes[1],attributes[2],attributes[3],attributes[4],attributes[5],attributes[6]);
306     case 8: return (*callback)(name,type,attributes[0],attributes[1],attributes[2],attributes[3],attributes[4],attributes[5],attributes[6],attributes[7]);
307     case 9: return (*callback)(name,type,attributes[0],attributes[1],attributes[2],attributes[3],attributes[4],attributes[5],attributes[6],attributes[7],attributes[8]);
308     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]);
309     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]);
310     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]);
311     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]);
312     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]);
313     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]);
314     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]);
315 amb 334
316 amb 344 default:
317 amb 791 fprintf(stderr,"XML Parser: Error on line %llu: too many attributes for tag '%s' source code needs changing.\n",lineno,name);
318 amb 344 exit(1);
319     }
320     }
321    
322    
323 amb 334 /*++++++++++++++++++++++++++++++++++++++
324     Parse the XML and call the functions for each tag as seen.
325    
326 amb 348 int ParseXML Returns 0 if OK or something else in case of an error.
327    
328 amb 334 FILE *file The file to parse.
329    
330     xmltag **tags The array of pointers to tags for the top level.
331 amb 337
332 amb 366 int options A list of XML Parser options OR-ed together.
333 amb 334 ++++++++++++++++++++++++++++++++++++++*/
334    
335 amb 366 int ParseXML(FILE *file,xmltag **tags,int options)
336 amb 334 {
337     int yychar,i;
338    
339 amb 351 char *attributes[XMLPARSE_MAX_ATTRS]={NULL};
340 amb 334 int attribute=0;
341    
342     int stackdepth=0,stackused=0;
343 amb 344 xmltag ***tags_stack=NULL;
344     xmltag **tag_stack=NULL;
345 amb 334 xmltag *tag=NULL;
346    
347 amb 368 /* The actual parser. */
348 amb 334
349 amb 374 xmlparse_options=options;
350    
351 amb 334 yyin=file;
352    
353 amb 368 yyrestart(yyin);
354 amb 334
355 amb 791 lineno=1;
356 amb 396
357 amb 368 BEGIN(INITIAL);
358 amb 334
359 amb 348 do
360     {
361     yychar=yylex();
362    
363 amb 334 switch(yychar)
364     {
365 amb 348 /* The start of a tag for an XML declaration */
366    
367     case LEX_XML_DECL_BEGIN:
368    
369     if(tag_stack)
370     {
371 amb 791 fprintf(stderr,"XML Parser: Error on line %llu: XML declaration not before all other tags.\n",lineno);
372 amb 348 yychar=LEX_ERROR_XML_NOT_FIRST;
373     break;
374     }
375    
376 amb 334 /* The start of a tag for an element */
377    
378     case LEX_TAG_BEGIN:
379    
380     tag=NULL;
381    
382     for(i=0;tags[i];i++)
383     if(!strcasecmp(yylval,tags[i]->name))
384     {
385     tag=tags[i];
386    
387 amb 356 for(i=0;i<tag->nattributes;i++)
388 amb 351 if(attributes[i])
389     {
390     free(attributes[i]);
391     attributes[i]=NULL;
392     }
393 amb 334
394     break;
395     }
396    
397     if(tag==NULL)
398     {
399 amb 791 fprintf(stderr,"XML Parser: Error on line %llu: unexpected tag '%s'.\n",lineno,yylval);
400 amb 348 yychar=LEX_ERROR_UNEXP_TAG;
401 amb 334 }
402 amb 348
403 amb 334 break;
404    
405     /* The end of the start-tag for an element */
406    
407     case LEX_TAG_PUSH:
408    
409     if(stackused==stackdepth)
410 amb 344 {
411     tag_stack =(xmltag**) realloc((void*)tag_stack ,(stackdepth+=8)*sizeof(xmltag*));
412     tags_stack=(xmltag***)realloc((void*)tags_stack,(stackdepth+=8)*sizeof(xmltag**));
413     }
414 amb 334
415 amb 344 tag_stack [stackused]=tag;
416     tags_stack[stackused]=tags;
417     stackused++;
418    
419     if(tag->callback)
420 amb 363 if(call_callback(tag->name,tag->callback,XMLPARSE_TAG_START,tag->nattributes,attributes))
421     yychar=LEX_ERROR_CALLBACK;
422 amb 344
423 amb 334 tags=tag->subtags;
424    
425 amb 344 break;
426    
427 amb 348 /* The end of the empty-element-tag for an XML declaration */
428    
429     case LEX_XML_DECL_FINISH:
430    
431 amb 334 /* The end of the empty-element-tag for an element */
432    
433     case LEX_TAG_FINISH:
434    
435     if(tag->callback)
436 amb 363 if(call_callback(tag->name,tag->callback,XMLPARSE_TAG_START|XMLPARSE_TAG_END,tag->nattributes,attributes))
437     yychar=LEX_ERROR_CALLBACK;
438 amb 334
439 amb 344 if(stackused>0)
440     tag=tag_stack[stackused-1];
441     else
442     tag=NULL;
443 amb 334
444     break;
445    
446     /* The end of the end-tag for an element */
447    
448     case LEX_TAG_POP:
449    
450 amb 344 stackused--;
451     tags=tags_stack[stackused];
452     tag =tag_stack [stackused];
453 amb 334
454 amb 348 if(strcmp(tag->name,yylval))
455     {
456 amb 791 fprintf(stderr,"XML Parser: Error on line %llu: end tag '</%s>' doesn't match start tag '<%s ...>'.\n",lineno,yylval,tag->name);
457 amb 348 yychar=LEX_ERROR_UNBALANCED;
458     }
459    
460     if(stackused<0)
461     {
462 amb 791 fprintf(stderr,"XML Parser: Error on line %llu: end tag '</%s>' seen but there was no start tag '<%s ...>'.\n",lineno,yylval,yylval);
463 amb 348 yychar=LEX_ERROR_NO_START;
464     }
465    
466 amb 356 for(i=0;i<tag->nattributes;i++)
467 amb 351 if(attributes[i])
468     {
469     free(attributes[i]);
470     attributes[i]=NULL;
471     }
472    
473 amb 344 if(tag->callback)
474 amb 363 if(call_callback(tag->name,tag->callback,XMLPARSE_TAG_END,tag->nattributes,attributes))
475     yychar=LEX_ERROR_CALLBACK;
476 amb 344
477 amb 348 if(stackused>0)
478     tag=tag_stack[stackused-1];
479     else
480     tag=NULL;
481 amb 344
482 amb 334 break;
483    
484     /* An attribute key */
485    
486     case LEX_ATTR_KEY:
487    
488     attribute=-1;
489    
490 amb 356 for(i=0;i<tag->nattributes;i++)
491 amb 334 if(!strcasecmp(yylval,tag->attributes[i]))
492     {
493     attribute=i;
494    
495     break;
496     }
497    
498     if(attribute==-1)
499     {
500 amb 366 if((options&XMLPARSE_UNKNOWN_ATTRIBUTES)==XMLPARSE_UNKNOWN_ATTR_ERROR ||
501     ((options&XMLPARSE_UNKNOWN_ATTRIBUTES)==XMLPARSE_UNKNOWN_ATTR_ERRNONAME && !strchr(yylval,':')))
502 amb 337 {
503 amb 791 fprintf(stderr,"XML Parser: Error on line %llu: unexpected attribute '%s' for tag '%s'.\n",lineno,yylval,tag->name);
504 amb 348 yychar=LEX_ERROR_UNEXP_ATT;
505 amb 337 }
506 amb 366 else if((options&XMLPARSE_UNKNOWN_ATTRIBUTES)==XMLPARSE_UNKNOWN_ATTR_WARN)
507 amb 791 fprintf(stderr,"XML Parser: Warning on line %llu: unexpected attribute '%s' for tag '%s'.\n",lineno,yylval,tag->name);
508 amb 334 }
509 amb 348
510 amb 334 break;
511    
512     /* An attribute value */
513    
514     case LEX_ATTR_VAL:
515    
516 amb 363 if(tag->callback && attribute!=-1 && yylval)
517 amb 334 attributes[attribute]=strcpy(malloc(strlen(yylval)+1),yylval);
518 amb 348
519     break;
520    
521     /* End of file */
522    
523     case LEX_EOF:
524    
525     if(tag)
526     {
527 amb 791 fprintf(stderr,"XML Parser: Error on line %llu: end of file seen without end tag '</%s>'.\n",lineno,tag->name);
528 amb 348 yychar=LEX_ERROR_UNEXP_EOF;
529     }
530    
531     break;
532    
533     case LEX_ERROR_TAG_START:
534 amb 791 fprintf(stderr,"XML Parser: Error on line %llu: character '<' seen not at start of tag.\n",lineno);
535 amb 348 break;
536    
537     case LEX_ERROR_XML_DECL_START:
538 amb 791 fprintf(stderr,"XML Parser: Error on line %llu: characters '<?' seen not at start of XML declaration.\n",lineno);
539 amb 348 break;
540    
541     case LEX_ERROR_TAG:
542 amb 791 fprintf(stderr,"XML Parser: Error on line %llu: invalid character seen inside tag '<%s...>'.\n",lineno,tag->name);
543 amb 348 break;
544    
545     case LEX_ERROR_XML_DECL:
546 amb 791 fprintf(stderr,"XML Parser: Error on line %llu: invalid character seen inside XML declaration '<?%s...>'.\n",lineno,tag->name);
547 amb 348 break;
548    
549     case LEX_ERROR_ATTR:
550 amb 791 fprintf(stderr,"XML Parser: Error on line %llu: invalid attribute definition seen in tag.\n",lineno);
551 amb 348 break;
552    
553     case LEX_ERROR_END_TAG:
554 amb 791 fprintf(stderr,"XML Parser: Error on line %llu: invalid character seen in end-tag.\n",lineno);
555 amb 348 break;
556    
557     case LEX_ERROR_COMMENT:
558 amb 791 fprintf(stderr,"XML Parser: Error on line %llu: invalid comment seen.\n",lineno);
559 amb 348 break;
560    
561     case LEX_ERROR_CLOSE:
562 amb 791 fprintf(stderr,"XML Parser: Error on line %llu: character '>' seen not at end of tag.\n",lineno);
563 amb 348 break;
564 amb 351
565     case LEX_ERROR_ATTR_VAL:
566 amb 791 fprintf(stderr,"XML Parser: Error on line %llu: invalid character '%s' seen in attribute value.\n",lineno,yylval);
567 amb 351 break;
568 amb 356
569     case LEX_ERROR_ENTITY_REF:
570 amb 791 fprintf(stderr,"XML Parser: Error on line %llu: invalid entity reference '%s' seen in attribute value.\n",lineno,yylval);
571 amb 356 break;
572    
573     case LEX_ERROR_CHAR_REF:
574 amb 791 fprintf(stderr,"XML Parser: Error on line %llu: invalid character reference '%s' seen in attribute value.\n",lineno,yylval);
575 amb 356 break;
576 amb 334 }
577 amb 348 }
578     while(yychar>LEX_EOF && yychar<LEX_ERROR);
579 amb 334
580     /* Delete the tagdata */
581    
582 amb 356 for(i=0;i<XMLPARSE_MAX_ATTRS;i++)
583 amb 334 if(attributes[i])
584     free(attributes[i]);
585    
586     if(stackdepth)
587 amb 401 {
588     free(tag_stack);
589 amb 344 free(tags_stack);
590 amb 401 }
591 amb 348
592     return(yychar);
593 amb 334 }
594 amb 348
595    
596     /*++++++++++++++++++++++++++++++++++++++
597     Return the current parser line number.
598    
599 amb 791 unsigned long long ParseXML_LineNumber Returns the line number.
600 amb 348 ++++++++++++++++++++++++++++++++++++++*/
601    
602 amb 791 unsigned long long ParseXML_LineNumber(void)
603 amb 348 {
604 amb 791 return(lineno);
605 amb 348 }
606 amb 356
607    
608     /*++++++++++++++++++++++++++++++++++++++
609     Convert an XML entity reference into an ASCII string.
610    
611 amb 377 char *ParseXML_Decode_Entity_Ref Returns a pointer to the replacement decoded string.
612 amb 356
613     const char *string The entity reference string.
614     ++++++++++++++++++++++++++++++++++++++*/
615    
616 amb 377 char *ParseXML_Decode_Entity_Ref(const char *string)
617 amb 356 {
618     if(!strcmp(string,"&amp;")) return("&");
619     if(!strcmp(string,"&lt;")) return("<");
620     if(!strcmp(string,"&gt;")) return(">");
621     if(!strcmp(string,"&apos;")) return("'");
622     if(!strcmp(string,"&quot;")) return("\"");
623     return(NULL);
624     }
625    
626    
627     /*++++++++++++++++++++++++++++++++++++++
628     Convert an XML character reference into an ASCII string.
629    
630 amb 377 char *ParseXML_Decode_Char_Ref Returns a pointer to the replacement decoded string.
631 amb 356
632     const char *string The character reference string.
633     ++++++++++++++++++++++++++++++++++++++*/
634    
635 amb 377 char *ParseXML_Decode_Char_Ref(const char *string)
636 amb 356 {
637 amb 662 static char result[5]="";
638     long int unicode;
639 amb 356
640 amb 662 if(string[2]=='x') unicode=strtol(string+3,NULL,16);
641     else unicode=strtol(string+2,NULL,10);
642 amb 356
643 amb 662 if(unicode<0x80)
644     {
645     /* 0000 0000-0000 007F => 0xxxxxxx */
646     result[0]=unicode;
647     result[1]=0;
648     }
649     else if(unicode<0x07FF)
650     {
651     /* 0000 0080-0000 07FF => 110xxxxx 10xxxxxx */
652     result[0]=0xC0+((unicode&0x07C0)>>6);
653     result[1]=0x80+ (unicode&0x003F);
654     result[2]=0;
655     }
656     else if(unicode<0xFFFF)
657     {
658     /* 0000 0800-0000 FFFF => 1110xxxx 10xxxxxx 10xxxxxx */
659     result[0]=0xE0+((unicode&0xF000)>>12);
660     result[1]=0x80+((unicode&0x0FC0)>>6);
661     result[2]=0x80+ (unicode&0x003F);
662     result[3]=0;
663     }
664     else if(unicode<0x1FFFFF)
665     {
666     /* 0001 0000-001F FFFF => 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */
667     result[0]=0xF0+((unicode&0x1C0000)>>18);
668     result[1]=0x80+((unicode&0x03F000)>>12);
669     result[2]=0x80+((unicode&0x000FC0)>>6);
670     result[3]=0x80+ (unicode&0x00003F);
671     result[4]=0;
672     }
673     else
674     {
675     result[0]=0xFF;
676     result[1]=0xFD;
677     result[2]=0;
678     }
679 amb 356
680     return(result);
681     }
682    
683    
684     /*++++++++++++++++++++++++++++++++++++++
685     Convert a string into something that is safe to output in an XML file.
686    
687 amb 377 char *ParseXML_Encode_Safe_XML Returns a pointer to the replacement encoded string (or the original if no change needed).
688 amb 356
689     const char *string The string to convert.
690     ++++++++++++++++++++++++++++++++++++++*/
691    
692 amb 377 char *ParseXML_Encode_Safe_XML(const char *string)
693 amb 356 {
694     static const char hexstring[17]="0123456789ABCDEF";
695     int i=0,j=0,len;
696     char *result;
697    
698     for(i=0;string[i];i++)
699 amb 509 if(string[i]=='<' || string[i]=='>' || string[i]=='&' || string[i]=='\'' || string[i]=='"' || string[i]<32 || (unsigned char)string[i]>127)
700 amb 356 break;
701    
702     if(!string[i])
703 amb 377 return((char*)string);
704 amb 356
705     len=i+256-6;
706    
707     result=(char*)malloc(len+7);
708 amb 404 strncpy(result,string,j=i);
709 amb 356
710     do
711     {
712     for(;j<len && string[i];i++)
713     if(string[i]=='<')
714     {
715     result[j++]='&';
716     result[j++]='l';
717     result[j++]='t';
718     result[j++]=';';
719     }
720     else if(string[i]=='>')
721     {
722     result[j++]='&';
723     result[j++]='g';
724     result[j++]='t';
725     result[j++]=';';
726     }
727     else if(string[i]=='&')
728     {
729     result[j++]='&';
730     result[j++]='a';
731     result[j++]='m';
732     result[j++]='p';
733     result[j++]=';';
734     }
735     else if(string[i]=='\'')
736     {
737     result[j++]='&';
738     result[j++]='a';
739     result[j++]='p';
740     result[j++]='o';
741     result[j++]='s';
742     result[j++]=';';
743     }
744     else if(string[i]=='"')
745     {
746     result[j++]='&';
747     result[j++]='q';
748     result[j++]='u';
749     result[j++]='o';
750     result[j++]='t';
751     result[j++]=';';
752     }
753 amb 509 else if(string[i]>=32 && (unsigned char)string[i]<=127)
754 amb 487 result[j++]=string[i];
755     else
756 amb 356 {
757 amb 487 unsigned int unicode;
758    
759     /* Decode the UTF-8 */
760    
761 amb 662 if((string[i]&0x80)==0)
762 amb 487 {
763 amb 662 /* 0000 0000-0000 007F => 0xxxxxxx */
764     unicode=string[i];
765     }
766     else if((string[i]&0xE0)==0xC0 && (string[i]&0x1F)>=2 && (string[i+1]&0xC0)==0x80)
767     {
768     /* 0000 0080-0000 07FF => 110xxxxx 10xxxxxx */
769 amb 487 unicode =(string[i++]&0x1F)<<6;
770     unicode|= string[i ]&0x3F;
771     }
772     else if((string[i]&0xF0)==0xE0 && (string[i+1]&0xC0)==0x80 && (string[i+2]&0xC0)==0x80)
773     {
774 amb 662 /* 0000 0800-0000 FFFF => 1110xxxx 10xxxxxx 10xxxxxx */
775 amb 487 unicode =(string[i++]&0x0F)<<12;
776     unicode|=(string[i++]&0x3F)<<6;
777     unicode|= string[i ]&0x3F;
778     }
779     else if((string[i]&0xF8)==0xF0 && (string[i+1]&0xC0)==0x80 && (string[i+2]&0xC0)==0x80 && (string[i+3]&0xC0)==0x80)
780     {
781 amb 662 /* 0001 0000-001F FFFF => 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */
782 amb 487 unicode =(string[i++]&0x07)<<18;
783     unicode|=(string[i++]&0x3F)<<12;
784     unicode|=(string[i++]&0x3F)<<6;
785     unicode|= string[i ]&0x3F;
786     }
787     else
788     unicode=0xFFFD;
789    
790     /* Output the character entity */
791    
792 amb 356 result[j++]='&';
793     result[j++]='#';
794     result[j++]='x';
795 amb 487
796     if(unicode&0x00FF0000)
797     {
798     result[j++]=hexstring[((unicode>>16)&0xf0)>>4];
799     result[j++]=hexstring[((unicode>>16)&0x0f) ];
800     }
801     if(unicode&0x00FFFF00)
802     {
803     result[j++]=hexstring[((unicode>>8)&0xf0)>>4];
804     result[j++]=hexstring[((unicode>>8)&0x0f) ];
805     }
806     result[j++]=hexstring[(unicode&0xf0)>>4];
807     result[j++]=hexstring[(unicode&0x0f) ];
808    
809 amb 356 result[j++]=';';
810     }
811    
812     if(string[i]) /* Not finished */
813     {
814     len+=256;
815     result=(char*)realloc((void*)result,len+7);
816     }
817     }
818     while(string[i]);
819    
820     result[j]=0;
821    
822     return(result);
823     }
824 amb 363
825    
826     /*++++++++++++++++++++++++++++++++++++++
827 amb 773 Check that a string really is an integer.
828 amb 363
829 amb 773 int ParseXML_IsInteger Returns 1 if an integer could be found or 0 otherwise.
830 amb 363
831     const char *string The string to be parsed.
832     ++++++++++++++++++++++++++++++++++++++*/
833    
834 amb 773 int ParseXML_IsInteger(const char *string)
835 amb 363 {
836     const char *p=string;
837    
838     if(*p=='-' || *p=='+')
839     p++;
840    
841     while(isdigit(*p))
842     p++;
843    
844     if(*p)
845     return(0);
846 amb 773 else
847     return(1);
848 amb 363 }
849    
850    
851     /*++++++++++++++++++++++++++++++++++++++
852 amb 773 Check that a string really is a floating point number.
853 amb 363
854 amb 773 int ParseXML_IsFloating Returns 1 if a floating point number could be found or 0 otherwise.
855 amb 363
856     const char *string The string to be parsed.
857     ++++++++++++++++++++++++++++++++++++++*/
858    
859 amb 773 int ParseXML_IsFloating(const char *string)
860 amb 363 {
861     const char *p=string;
862    
863     if(*p=='-' || *p=='+')
864     p++;
865    
866     while(isdigit(*p) || *p=='.')
867     p++;
868    
869 amb 396 if(*p=='e' || *p=='E')
870     {
871     p++;
872    
873     if(*p=='-' || *p=='+')
874     p++;
875    
876     while(isdigit(*p))
877     p++;
878     }
879    
880 amb 363 if(*p)
881     return(0);
882 amb 773 else
883     return(1);
884 amb 363 }

Properties

Name Value
cvs:description A simple generic XML parser.