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 363 - (hide annotations) (download)
Sun Apr 11 13:01:38 2010 UTC (14 years, 11 months ago) by amb
File size: 22955 byte(s)
Added helper functions for parsing strings into numbers.
Added macros to perform common error checking.
Change XML parser callback functions to return an error status.

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

Properties

Name Value
cvs:description A simple generic XML parser.