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 662 - (hide annotations) (download)
Sun Mar 20 16:37:15 2011 UTC (14 years ago) by amb
File size: 27257 byte(s)
Ensure that UTF-8 is used internally when reading in a numeric entity.

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

Properties

Name Value
cvs:description A simple generic XML parser.