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 787 - (hide annotations) (download)
Sat Jun 18 10:44:05 2011 UTC (13 years, 9 months ago) by amb
File size: 26925 byte(s)
Use flex %options instead of #defines, force clean compilation with C99.

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 334 %}
98    
99 amb 344 %option 8bit
100 amb 348 %option pointer
101 amb 344 %option batch
102 amb 787 %option never-interactive
103    
104 amb 344 %option yylineno
105 amb 348
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 348 S [ \t\r\n]
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     [^<>]+ { }
176 amb 334
177 amb 348 /* Comments */
178 amb 334
179 amb 348 <COMMENT>"--->" { return(LEX_ERROR_COMMENT); }
180     <COMMENT>"-->" { BEGIN(INITIAL); }
181     <COMMENT>"--"[^->]+ { }
182     <COMMENT>[^-]+ { }
183 amb 334 <COMMENT>"-" { }
184    
185 amb 348 /* CDATA */
186 amb 334
187 amb 348 <CDATA>"]]>" { BEGIN(INITIAL); }
188     <CDATA>"]" { }
189     <CDATA>[^]]+ { }
190 amb 334
191 amb 348 /* CDATA */
192 amb 334
193 amb 348 <DOCTYPE>"<" { doctype_depth++; }
194     <DOCTYPE>">" { if(doctype_depth==0) BEGIN(INITIAL); else doctype_depth--; }
195     <DOCTYPE>[^<>]+ { }
196 amb 334
197 amb 348 /* XML Declaration start */
198    
199 amb 483 <XML_DECL_START>xml { BEGIN(XML_DECL); yylval=yytext; return(LEX_XML_DECL_BEGIN); }
200     <XML_DECL_START>.|{N} { return(LEX_ERROR_XML_DECL_START); }
201 amb 348
202     /* Tag middle */
203    
204     <XML_DECL>"?>" { BEGIN(INITIAL); return(LEX_XML_DECL_FINISH); }
205     <XML_DECL>{S}+ { }
206     <XML_DECL>{name} { after_attr=XML_DECL; BEGIN(ATTR_KEY); yylval=yytext; return(LEX_ATTR_KEY); }
207 amb 483 <XML_DECL>.|{N} { return(LEX_ERROR_XML_DECL); }
208 amb 348
209     /* Any tag start */
210    
211     <TAG_START>{name} { BEGIN(TAG); yylval=yytext; return(LEX_TAG_BEGIN); }
212 amb 483 <TAG_START>.|{N} { return(LEX_ERROR_TAG_START); }
213 amb 348
214     /* End-tag start */
215    
216     <END_TAG1>{name} { BEGIN(END_TAG2); yylval=yytext; return(LEX_TAG_POP); }
217 amb 483 <END_TAG1>.|{N} { return(LEX_ERROR_END_TAG); }
218 amb 348
219     <END_TAG2>">" { BEGIN(INITIAL); }
220 amb 483 <END_TAG2>.|{N} { return(LEX_ERROR_END_TAG); }
221 amb 348
222     /* Any tag middle */
223    
224 amb 334 <TAG>"/>" { BEGIN(INITIAL); return(LEX_TAG_FINISH); }
225     <TAG>">" { BEGIN(INITIAL); return(LEX_TAG_PUSH); }
226 amb 348 <TAG>{S}+ { }
227     <TAG>{name} { after_attr=TAG; BEGIN(ATTR_KEY); yylval=yytext; return(LEX_ATTR_KEY); }
228 amb 483 <TAG>.|{N} { return(LEX_ERROR_TAG); }
229 amb 334
230 amb 348 /* Attributes */
231 amb 334
232 amb 348 <ATTR_KEY>= { BEGIN(ATTR_VAL); }
233 amb 483 <ATTR_KEY>.|{N} { return(LEX_ERROR_ATTR); }
234 amb 334
235 amb 348 <ATTR_VAL>\" { BEGIN(DQUOTED); reset_string; }
236     <ATTR_VAL>\' { BEGIN(SQUOTED); reset_string; }
237 amb 483 <ATTR_VAL>.|{N} { return(LEX_ERROR_ATTR); }
238 amb 348
239 amb 334 /* Quoted strings */
240    
241 amb 348 <DQUOTED>\" { BEGIN(after_attr); yylval=string; return(LEX_ATTR_VAL); }
242 amb 374 <DQUOTED>{entityref} { if(xmlparse_options&XMLPARSE_RETURN_ATTR_ENCODED) {append_string(yytext);}
243     else { const char *str=ParseXML_Decode_Entity_Ref(yytext); if(str) {append_string(str);} else {yylval=yytext; return(LEX_ERROR_ENTITY_REF);} } }
244     <DQUOTED>{charref} { if(xmlparse_options&XMLPARSE_RETURN_ATTR_ENCODED) {append_string(yytext);}
245     else { const char *str=ParseXML_Decode_Char_Ref(yytext); if(str) {append_string(str);} else {yylval=yytext; return(LEX_ERROR_CHAR_REF);} } }
246 amb 487 <DQUOTED>[<>&\"] { yylval=yytext; return(LEX_ERROR_ATTR_VAL); }
247     <DQUOTED>{UquotedD}+ { append_string(yytext); }
248     <DQUOTED>. { yylval=yytext; return(LEX_ERROR_ATTR_VAL); }
249 amb 334
250 amb 348 <SQUOTED>\' { BEGIN(after_attr); yylval=string; return(LEX_ATTR_VAL); }
251 amb 374 <SQUOTED>{entityref} { if(xmlparse_options&XMLPARSE_RETURN_ATTR_ENCODED) {append_string(yytext);}
252     else { const char *str=ParseXML_Decode_Entity_Ref(yytext); if(str) {append_string(str);} else {yylval=yytext; return(LEX_ERROR_ENTITY_REF);} } }
253     <SQUOTED>{charref} { if(xmlparse_options&XMLPARSE_RETURN_ATTR_ENCODED) {append_string(yytext);}
254     else { const char *str=ParseXML_Decode_Char_Ref(yytext); if(str) {append_string(str);} else {yylval=yytext; return(LEX_ERROR_CHAR_REF);} } }
255 amb 356 <SQUOTED>[<>&] { yylval=yytext; return(LEX_ERROR_ATTR_VAL); }
256 amb 487 <SQUOTED>{UquotedS}+ { append_string(yytext); }
257     <SQUOTED>. { yylval=yytext; return(LEX_ERROR_ATTR_VAL); }
258 amb 334
259     /* End of file */
260    
261 amb 368 <<EOF>> { free(string); string=NULL; stringlen=stringused=0; BEGIN(INITIAL); return(LEX_EOF); }
262 amb 334
263     %%
264    
265    
266 amb 348 /*++++++++++++++++++++++++++++++++++++++
267     A function to call the callback function with the parameters needed.
268    
269 amb 363 int call_callback Returns 1 if the callback returned with an error.
270    
271 amb 356 const char *name The name of the tag.
272 amb 348
273 amb 363 int (*callback)() The callback function.
274 amb 348
275     int type The type of tag (start and/or end).
276    
277     int nattributes The number of attributes collected.
278    
279     char *attributes[XMLPARSE_MAX_ATTRS] The list of attributes.
280     ++++++++++++++++++++++++++++++++++++++*/
281    
282 amb 363 static inline int call_callback(const char *name,int (*callback)(),int type,int nattributes,char *attributes[XMLPARSE_MAX_ATTRS])
283 amb 344 {
284     switch(nattributes)
285     {
286 amb 373 case 0: return (*callback)(name,type);
287     case 1: return (*callback)(name,type,attributes[0]);
288     case 2: return (*callback)(name,type,attributes[0],attributes[1]);
289     case 3: return (*callback)(name,type,attributes[0],attributes[1],attributes[2]);
290     case 4: return (*callback)(name,type,attributes[0],attributes[1],attributes[2],attributes[3]);
291     case 5: return (*callback)(name,type,attributes[0],attributes[1],attributes[2],attributes[3],attributes[4]);
292     case 6: return (*callback)(name,type,attributes[0],attributes[1],attributes[2],attributes[3],attributes[4],attributes[5]);
293     case 7: return (*callback)(name,type,attributes[0],attributes[1],attributes[2],attributes[3],attributes[4],attributes[5],attributes[6]);
294     case 8: return (*callback)(name,type,attributes[0],attributes[1],attributes[2],attributes[3],attributes[4],attributes[5],attributes[6],attributes[7]);
295     case 9: return (*callback)(name,type,attributes[0],attributes[1],attributes[2],attributes[3],attributes[4],attributes[5],attributes[6],attributes[7],attributes[8]);
296     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]);
297     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]);
298     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]);
299     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]);
300     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]);
301     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]);
302     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]);
303 amb 334
304 amb 344 default:
305 amb 363 fprintf(stderr,"XML Parser: Error on line %d: too many attributes for tag '%s' source code needs changing.\n",yylineno,name);
306 amb 344 exit(1);
307     }
308     }
309    
310    
311 amb 334 /*++++++++++++++++++++++++++++++++++++++
312     Parse the XML and call the functions for each tag as seen.
313    
314 amb 348 int ParseXML Returns 0 if OK or something else in case of an error.
315    
316 amb 334 FILE *file The file to parse.
317    
318     xmltag **tags The array of pointers to tags for the top level.
319 amb 337
320 amb 366 int options A list of XML Parser options OR-ed together.
321 amb 334 ++++++++++++++++++++++++++++++++++++++*/
322    
323 amb 366 int ParseXML(FILE *file,xmltag **tags,int options)
324 amb 334 {
325     int yychar,i;
326    
327 amb 351 char *attributes[XMLPARSE_MAX_ATTRS]={NULL};
328 amb 334 int attribute=0;
329    
330     int stackdepth=0,stackused=0;
331 amb 344 xmltag ***tags_stack=NULL;
332     xmltag **tag_stack=NULL;
333 amb 334 xmltag *tag=NULL;
334    
335 amb 368 /* The actual parser. */
336 amb 334
337 amb 374 xmlparse_options=options;
338    
339 amb 334 yyin=file;
340    
341 amb 368 yyrestart(yyin);
342 amb 334
343 amb 396 yylineno=1;
344    
345 amb 368 BEGIN(INITIAL);
346 amb 334
347 amb 348 do
348     {
349     yychar=yylex();
350    
351 amb 334 switch(yychar)
352     {
353 amb 348 /* The start of a tag for an XML declaration */
354    
355     case LEX_XML_DECL_BEGIN:
356    
357     if(tag_stack)
358     {
359     fprintf(stderr,"XML Parser: Error on line %d: XML declaration not before all other tags.\n",yylineno);
360     yychar=LEX_ERROR_XML_NOT_FIRST;
361     break;
362     }
363    
364 amb 334 /* The start of a tag for an element */
365    
366     case LEX_TAG_BEGIN:
367    
368     tag=NULL;
369    
370     for(i=0;tags[i];i++)
371     if(!strcasecmp(yylval,tags[i]->name))
372     {
373     tag=tags[i];
374    
375 amb 356 for(i=0;i<tag->nattributes;i++)
376 amb 351 if(attributes[i])
377     {
378     free(attributes[i]);
379     attributes[i]=NULL;
380     }
381 amb 334
382     break;
383     }
384    
385     if(tag==NULL)
386     {
387 amb 348 fprintf(stderr,"XML Parser: Error on line %d: unexpected tag '%s'.\n",yylineno,yylval);
388     yychar=LEX_ERROR_UNEXP_TAG;
389 amb 334 }
390 amb 348
391 amb 334 break;
392    
393     /* The end of the start-tag for an element */
394    
395     case LEX_TAG_PUSH:
396    
397     if(stackused==stackdepth)
398 amb 344 {
399     tag_stack =(xmltag**) realloc((void*)tag_stack ,(stackdepth+=8)*sizeof(xmltag*));
400     tags_stack=(xmltag***)realloc((void*)tags_stack,(stackdepth+=8)*sizeof(xmltag**));
401     }
402 amb 334
403 amb 344 tag_stack [stackused]=tag;
404     tags_stack[stackused]=tags;
405     stackused++;
406    
407     if(tag->callback)
408 amb 363 if(call_callback(tag->name,tag->callback,XMLPARSE_TAG_START,tag->nattributes,attributes))
409     yychar=LEX_ERROR_CALLBACK;
410 amb 344
411 amb 334 tags=tag->subtags;
412    
413 amb 344 break;
414    
415 amb 348 /* The end of the empty-element-tag for an XML declaration */
416    
417     case LEX_XML_DECL_FINISH:
418    
419 amb 334 /* The end of the empty-element-tag for an element */
420    
421     case LEX_TAG_FINISH:
422    
423     if(tag->callback)
424 amb 363 if(call_callback(tag->name,tag->callback,XMLPARSE_TAG_START|XMLPARSE_TAG_END,tag->nattributes,attributes))
425     yychar=LEX_ERROR_CALLBACK;
426 amb 334
427 amb 344 if(stackused>0)
428     tag=tag_stack[stackused-1];
429     else
430     tag=NULL;
431 amb 334
432     break;
433    
434     /* The end of the end-tag for an element */
435    
436     case LEX_TAG_POP:
437    
438 amb 344 stackused--;
439     tags=tags_stack[stackused];
440     tag =tag_stack [stackused];
441 amb 334
442 amb 348 if(strcmp(tag->name,yylval))
443     {
444     fprintf(stderr,"XML Parser: Error on line %d: end tag '</%s>' doesn't match start tag '<%s ...>'.\n",yylineno,yylval,tag->name);
445     yychar=LEX_ERROR_UNBALANCED;
446     }
447    
448     if(stackused<0)
449     {
450     fprintf(stderr,"XML Parser: Error on line %d: end tag '</%s>' seen but there was no start tag '<%s ...>'.\n",yylineno,yylval,yylval);
451     yychar=LEX_ERROR_NO_START;
452     }
453    
454 amb 356 for(i=0;i<tag->nattributes;i++)
455 amb 351 if(attributes[i])
456     {
457     free(attributes[i]);
458     attributes[i]=NULL;
459     }
460    
461 amb 344 if(tag->callback)
462 amb 363 if(call_callback(tag->name,tag->callback,XMLPARSE_TAG_END,tag->nattributes,attributes))
463     yychar=LEX_ERROR_CALLBACK;
464 amb 344
465 amb 348 if(stackused>0)
466     tag=tag_stack[stackused-1];
467     else
468     tag=NULL;
469 amb 344
470 amb 334 break;
471    
472     /* An attribute key */
473    
474     case LEX_ATTR_KEY:
475    
476     attribute=-1;
477    
478 amb 356 for(i=0;i<tag->nattributes;i++)
479 amb 334 if(!strcasecmp(yylval,tag->attributes[i]))
480     {
481     attribute=i;
482    
483     break;
484     }
485    
486     if(attribute==-1)
487     {
488 amb 366 if((options&XMLPARSE_UNKNOWN_ATTRIBUTES)==XMLPARSE_UNKNOWN_ATTR_ERROR ||
489     ((options&XMLPARSE_UNKNOWN_ATTRIBUTES)==XMLPARSE_UNKNOWN_ATTR_ERRNONAME && !strchr(yylval,':')))
490 amb 337 {
491 amb 348 fprintf(stderr,"XML Parser: Error on line %d: unexpected attribute '%s' for tag '%s'.\n",yylineno,yylval,tag->name);
492     yychar=LEX_ERROR_UNEXP_ATT;
493 amb 337 }
494 amb 366 else if((options&XMLPARSE_UNKNOWN_ATTRIBUTES)==XMLPARSE_UNKNOWN_ATTR_WARN)
495 amb 348 fprintf(stderr,"XML Parser: Warning on line %d: unexpected attribute '%s' for tag '%s'.\n",yylineno,yylval,tag->name);
496 amb 334 }
497 amb 348
498 amb 334 break;
499    
500     /* An attribute value */
501    
502     case LEX_ATTR_VAL:
503    
504 amb 363 if(tag->callback && attribute!=-1 && yylval)
505 amb 334 attributes[attribute]=strcpy(malloc(strlen(yylval)+1),yylval);
506 amb 348
507     break;
508    
509     /* End of file */
510    
511     case LEX_EOF:
512    
513     if(tag)
514     {
515     fprintf(stderr,"XML Parser: Error on line %d: end of file seen without end tag '</%s>'.\n",yylineno,tag->name);
516     yychar=LEX_ERROR_UNEXP_EOF;
517     }
518    
519     break;
520    
521     case LEX_ERROR_TAG_START:
522     fprintf(stderr,"XML Parser: Error on line %d: character '<' seen not at start of tag.\n",yylineno);
523     break;
524    
525     case LEX_ERROR_XML_DECL_START:
526     fprintf(stderr,"XML Parser: Error on line %d: characters '<?' seen not at start of XML declaration.\n",yylineno);
527     break;
528    
529     case LEX_ERROR_TAG:
530     fprintf(stderr,"XML Parser: Error on line %d: invalid character seen inside tag '<%s...>'.\n",yylineno,tag->name);
531     break;
532    
533     case LEX_ERROR_XML_DECL:
534     fprintf(stderr,"XML Parser: Error on line %d: invalid character seen inside XML declaration '<?%s...>'.\n",yylineno,tag->name);
535     break;
536    
537     case LEX_ERROR_ATTR:
538     fprintf(stderr,"XML Parser: Error on line %d: invalid attribute definition seen in tag.\n",yylineno);
539     break;
540    
541     case LEX_ERROR_END_TAG:
542     fprintf(stderr,"XML Parser: Error on line %d: invalid character seen in end-tag.\n",yylineno);
543     break;
544    
545     case LEX_ERROR_COMMENT:
546     fprintf(stderr,"XML Parser: Error on line %d: invalid comment seen.\n",yylineno);
547     break;
548    
549     case LEX_ERROR_CLOSE:
550     fprintf(stderr,"XML Parser: Error on line %d: character '>' seen not at end of tag.\n",yylineno);
551     break;
552 amb 351
553     case LEX_ERROR_ATTR_VAL:
554 amb 356 fprintf(stderr,"XML Parser: Error on line %d: invalid character '%s' seen in attribute value.\n",yylineno,yylval);
555 amb 351 break;
556 amb 356
557     case LEX_ERROR_ENTITY_REF:
558     fprintf(stderr,"XML Parser: Error on line %d: invalid entity reference '%s' seen in attribute value.\n",yylineno,yylval);
559     break;
560    
561     case LEX_ERROR_CHAR_REF:
562     fprintf(stderr,"XML Parser: Error on line %d: invalid character reference '%s' seen in attribute value.\n",yylineno,yylval);
563     break;
564 amb 334 }
565 amb 348 }
566     while(yychar>LEX_EOF && yychar<LEX_ERROR);
567 amb 334
568     /* Delete the tagdata */
569    
570 amb 356 for(i=0;i<XMLPARSE_MAX_ATTRS;i++)
571 amb 334 if(attributes[i])
572     free(attributes[i]);
573    
574     if(stackdepth)
575 amb 401 {
576     free(tag_stack);
577 amb 344 free(tags_stack);
578 amb 401 }
579 amb 348
580     return(yychar);
581 amb 334 }
582 amb 348
583    
584     /*++++++++++++++++++++++++++++++++++++++
585     Return the current parser line number.
586    
587 amb 388 unsigned long ParseXML_LineNumber Returns the line number.
588 amb 348 ++++++++++++++++++++++++++++++++++++++*/
589    
590 amb 388 unsigned long ParseXML_LineNumber(void)
591 amb 348 {
592     return(yylineno);
593     }
594 amb 356
595    
596     /*++++++++++++++++++++++++++++++++++++++
597     Convert an XML entity reference into an ASCII string.
598    
599 amb 377 char *ParseXML_Decode_Entity_Ref Returns a pointer to the replacement decoded string.
600 amb 356
601     const char *string The entity reference string.
602     ++++++++++++++++++++++++++++++++++++++*/
603    
604 amb 377 char *ParseXML_Decode_Entity_Ref(const char *string)
605 amb 356 {
606     if(!strcmp(string,"&amp;")) return("&");
607     if(!strcmp(string,"&lt;")) return("<");
608     if(!strcmp(string,"&gt;")) return(">");
609     if(!strcmp(string,"&apos;")) return("'");
610     if(!strcmp(string,"&quot;")) return("\"");
611     return(NULL);
612     }
613    
614    
615     /*++++++++++++++++++++++++++++++++++++++
616     Convert an XML character reference into an ASCII string.
617    
618 amb 377 char *ParseXML_Decode_Char_Ref Returns a pointer to the replacement decoded string.
619 amb 356
620     const char *string The character reference string.
621     ++++++++++++++++++++++++++++++++++++++*/
622    
623 amb 377 char *ParseXML_Decode_Char_Ref(const char *string)
624 amb 356 {
625 amb 662 static char result[5]="";
626     long int unicode;
627 amb 356
628 amb 662 if(string[2]=='x') unicode=strtol(string+3,NULL,16);
629     else unicode=strtol(string+2,NULL,10);
630 amb 356
631 amb 662 if(unicode<0x80)
632     {
633     /* 0000 0000-0000 007F => 0xxxxxxx */
634     result[0]=unicode;
635     result[1]=0;
636     }
637     else if(unicode<0x07FF)
638     {
639     /* 0000 0080-0000 07FF => 110xxxxx 10xxxxxx */
640     result[0]=0xC0+((unicode&0x07C0)>>6);
641     result[1]=0x80+ (unicode&0x003F);
642     result[2]=0;
643     }
644     else if(unicode<0xFFFF)
645     {
646     /* 0000 0800-0000 FFFF => 1110xxxx 10xxxxxx 10xxxxxx */
647     result[0]=0xE0+((unicode&0xF000)>>12);
648     result[1]=0x80+((unicode&0x0FC0)>>6);
649     result[2]=0x80+ (unicode&0x003F);
650     result[3]=0;
651     }
652     else if(unicode<0x1FFFFF)
653     {
654     /* 0001 0000-001F FFFF => 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */
655     result[0]=0xF0+((unicode&0x1C0000)>>18);
656     result[1]=0x80+((unicode&0x03F000)>>12);
657     result[2]=0x80+((unicode&0x000FC0)>>6);
658     result[3]=0x80+ (unicode&0x00003F);
659     result[4]=0;
660     }
661     else
662     {
663     result[0]=0xFF;
664     result[1]=0xFD;
665     result[2]=0;
666     }
667 amb 356
668     return(result);
669     }
670    
671    
672     /*++++++++++++++++++++++++++++++++++++++
673     Convert a string into something that is safe to output in an XML file.
674    
675 amb 377 char *ParseXML_Encode_Safe_XML Returns a pointer to the replacement encoded string (or the original if no change needed).
676 amb 356
677     const char *string The string to convert.
678     ++++++++++++++++++++++++++++++++++++++*/
679    
680 amb 377 char *ParseXML_Encode_Safe_XML(const char *string)
681 amb 356 {
682     static const char hexstring[17]="0123456789ABCDEF";
683     int i=0,j=0,len;
684     char *result;
685    
686     for(i=0;string[i];i++)
687 amb 509 if(string[i]=='<' || string[i]=='>' || string[i]=='&' || string[i]=='\'' || string[i]=='"' || string[i]<32 || (unsigned char)string[i]>127)
688 amb 356 break;
689    
690     if(!string[i])
691 amb 377 return((char*)string);
692 amb 356
693     len=i+256-6;
694    
695     result=(char*)malloc(len+7);
696 amb 404 strncpy(result,string,j=i);
697 amb 356
698     do
699     {
700     for(;j<len && string[i];i++)
701     if(string[i]=='<')
702     {
703     result[j++]='&';
704     result[j++]='l';
705     result[j++]='t';
706     result[j++]=';';
707     }
708     else if(string[i]=='>')
709     {
710     result[j++]='&';
711     result[j++]='g';
712     result[j++]='t';
713     result[j++]=';';
714     }
715     else if(string[i]=='&')
716     {
717     result[j++]='&';
718     result[j++]='a';
719     result[j++]='m';
720     result[j++]='p';
721     result[j++]=';';
722     }
723     else if(string[i]=='\'')
724     {
725     result[j++]='&';
726     result[j++]='a';
727     result[j++]='p';
728     result[j++]='o';
729     result[j++]='s';
730     result[j++]=';';
731     }
732     else if(string[i]=='"')
733     {
734     result[j++]='&';
735     result[j++]='q';
736     result[j++]='u';
737     result[j++]='o';
738     result[j++]='t';
739     result[j++]=';';
740     }
741 amb 509 else if(string[i]>=32 && (unsigned char)string[i]<=127)
742 amb 487 result[j++]=string[i];
743     else
744 amb 356 {
745 amb 487 unsigned int unicode;
746    
747     /* Decode the UTF-8 */
748    
749 amb 662 if((string[i]&0x80)==0)
750 amb 487 {
751 amb 662 /* 0000 0000-0000 007F => 0xxxxxxx */
752     unicode=string[i];
753     }
754     else if((string[i]&0xE0)==0xC0 && (string[i]&0x1F)>=2 && (string[i+1]&0xC0)==0x80)
755     {
756     /* 0000 0080-0000 07FF => 110xxxxx 10xxxxxx */
757 amb 487 unicode =(string[i++]&0x1F)<<6;
758     unicode|= string[i ]&0x3F;
759     }
760     else if((string[i]&0xF0)==0xE0 && (string[i+1]&0xC0)==0x80 && (string[i+2]&0xC0)==0x80)
761     {
762 amb 662 /* 0000 0800-0000 FFFF => 1110xxxx 10xxxxxx 10xxxxxx */
763 amb 487 unicode =(string[i++]&0x0F)<<12;
764     unicode|=(string[i++]&0x3F)<<6;
765     unicode|= string[i ]&0x3F;
766     }
767     else if((string[i]&0xF8)==0xF0 && (string[i+1]&0xC0)==0x80 && (string[i+2]&0xC0)==0x80 && (string[i+3]&0xC0)==0x80)
768     {
769 amb 662 /* 0001 0000-001F FFFF => 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */
770 amb 487 unicode =(string[i++]&0x07)<<18;
771     unicode|=(string[i++]&0x3F)<<12;
772     unicode|=(string[i++]&0x3F)<<6;
773     unicode|= string[i ]&0x3F;
774     }
775     else
776     unicode=0xFFFD;
777    
778     /* Output the character entity */
779    
780 amb 356 result[j++]='&';
781     result[j++]='#';
782     result[j++]='x';
783 amb 487
784     if(unicode&0x00FF0000)
785     {
786     result[j++]=hexstring[((unicode>>16)&0xf0)>>4];
787     result[j++]=hexstring[((unicode>>16)&0x0f) ];
788     }
789     if(unicode&0x00FFFF00)
790     {
791     result[j++]=hexstring[((unicode>>8)&0xf0)>>4];
792     result[j++]=hexstring[((unicode>>8)&0x0f) ];
793     }
794     result[j++]=hexstring[(unicode&0xf0)>>4];
795     result[j++]=hexstring[(unicode&0x0f) ];
796    
797 amb 356 result[j++]=';';
798     }
799    
800     if(string[i]) /* Not finished */
801     {
802     len+=256;
803     result=(char*)realloc((void*)result,len+7);
804     }
805     }
806     while(string[i]);
807    
808     result[j]=0;
809    
810     return(result);
811     }
812 amb 363
813    
814     /*++++++++++++++++++++++++++++++++++++++
815 amb 773 Check that a string really is an integer.
816 amb 363
817 amb 773 int ParseXML_IsInteger Returns 1 if an integer could be found or 0 otherwise.
818 amb 363
819     const char *string The string to be parsed.
820     ++++++++++++++++++++++++++++++++++++++*/
821    
822 amb 773 int ParseXML_IsInteger(const char *string)
823 amb 363 {
824     const char *p=string;
825    
826     if(*p=='-' || *p=='+')
827     p++;
828    
829     while(isdigit(*p))
830     p++;
831    
832     if(*p)
833     return(0);
834 amb 773 else
835     return(1);
836 amb 363 }
837    
838    
839     /*++++++++++++++++++++++++++++++++++++++
840 amb 773 Check that a string really is a floating point number.
841 amb 363
842 amb 773 int ParseXML_IsFloating Returns 1 if a floating point number could be found or 0 otherwise.
843 amb 363
844     const char *string The string to be parsed.
845     ++++++++++++++++++++++++++++++++++++++*/
846    
847 amb 773 int ParseXML_IsFloating(const char *string)
848 amb 363 {
849     const char *p=string;
850    
851     if(*p=='-' || *p=='+')
852     p++;
853    
854     while(isdigit(*p) || *p=='.')
855     p++;
856    
857 amb 396 if(*p=='e' || *p=='E')
858     {
859     p++;
860    
861     if(*p=='-' || *p=='+')
862     p++;
863    
864     while(isdigit(*p))
865     p++;
866     }
867    
868 amb 363 if(*p)
869     return(0);
870 amb 773 else
871     return(1);
872 amb 363 }

Properties

Name Value
cvs:description A simple generic XML parser.