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 344 - (hide annotations) (download)
Wed Mar 31 17:19:22 2010 UTC (14 years, 11 months ago) by amb
File size: 11597 byte(s)
Call the XML tag functions for the end tags as well as the start tags.

1 amb 334 %{
2     /***************************************
3 amb 344 $Header: /home/amb/CVS/routino/src/xmlparse.l,v 1.3 2010-03-31 17:18:27 amb Exp $
4 amb 334
5     A simple generic XML parser where the structure comes from the function parameters.
6    
7     Part of the Routino routing software.
8     ******************/ /******************
9     This file Copyright 2010 Andrew M. Bishop
10    
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     #include <string.h>
29    
30     /* Parser outputs */
31    
32     #define LEX_TAG_BEGIN 1
33     #define LEX_TAG_POP 2
34     #define LEX_TAG_PUSH 3
35     #define LEX_TAG_FINISH 4
36     #define LEX_ATTR_KEY 5
37     #define LEX_ATTR_VAL 6
38    
39    
40     /* Lexer definitions */
41    
42     #define YY_SKIP_YYWRAP 1 /* Remove error with prototype of ..._yywrap */
43     #ifndef yywrap
44     /*+ Needed in lex but does nothing. +*/
45     #define yywrap() 1
46     #endif
47    
48     /*+ Reset the current string. +*/
49     #define reset_string \
50     if(string) *string=0; \
51     stringused=0;
52    
53     /*+ append information to the current string. +*/
54     #define append_string(xx) \
55     newlen=strlen(xx); \
56     if((stringused+newlen)>=stringlen) \
57     string=(char*)realloc((void*)string,stringlen=(stringused+newlen+16)); \
58     strcpy(string+stringused,xx); \
59     stringused+=newlen;
60    
61     #define YY_NO_INPUT
62    
63    
64     /* Lexer functions and variables */
65    
66     extern int yylex(void);
67    
68     static char *yylval=NULL;
69    
70     %}
71    
72 amb 344 %option 8bit
73     %option batch
74     %option yylineno
75     %option nodefault
76     %option perf-report
77     %option fast
78    
79 amb 334 W [ \t]
80    
81     nonascii [\200-\377]
82     ascii [ -~]
83     alphanum [a-zA-Z0-9]
84     punct [][!\"#$%&\'()*+,-./:;<=>?@\\^_`{|}~]
85     safepunct [][!\#$%\()*+,-./:;=?@\\^_`{|}~]
86    
87     tag ({alphanum}|[-:])+
88     key ({alphanum}|[-:])+
89     val ({alphanum}|{nonascii}|{safepunct})+
90    
91     %x COMMENT
92     %x TAG_START TAG TAG_ATTR_KEY TAG_ATTR_VAL
93     %x DQUOTED SQUOTED
94    
95     %%
96     /* Must use static variables since the parser returns often. */
97     static char *string=NULL;
98     static int stringlen=0,stringused=0;
99     int newlen;
100    
101     /* Handle comments and other tags */
102    
103     "<!--" { BEGIN(COMMENT); }
104     "<" { BEGIN(TAG_START); }
105 amb 344 [^<]+ { }
106 amb 334
107     /* Comments - not strictly correct. */
108    
109     <COMMENT>"--"{W}*">" { BEGIN(INITIAL); }
110     <COMMENT>">" { }
111     <COMMENT>"-" { }
112 amb 344 <COMMENT>[^->]+ { }
113 amb 334
114     /* Tags */
115    
116     <TAG_START>{W}+ { }
117     <TAG_START>"?xml" { BEGIN(TAG); yylval=yytext; return(LEX_TAG_BEGIN); }
118     <TAG_START>{tag} { BEGIN(TAG); yylval=yytext; return(LEX_TAG_BEGIN); }
119    
120     <TAG_START>"/"{tag}">" { BEGIN(INITIAL); return(LEX_TAG_POP); }
121    
122 amb 344 <TAG_START>.|\n { BEGIN(INITIAL); }
123 amb 334
124     <TAG>{W}+ { }
125     <TAG>"/>" { BEGIN(INITIAL); return(LEX_TAG_FINISH); }
126     <TAG>"?>" { BEGIN(INITIAL); return(LEX_TAG_FINISH); }
127     <TAG>">" { BEGIN(INITIAL); return(LEX_TAG_PUSH); }
128     <TAG>{key} { BEGIN(TAG_ATTR_KEY); yylval=yytext; return(LEX_ATTR_KEY); }
129 amb 344 <TAG>.|\n { }
130 amb 334
131     <TAG_ATTR_KEY>{W}*= { BEGIN(TAG_ATTR_VAL); }
132 amb 344 <TAG_ATTR_KEY>.|\n { BEGIN(TAG); unput(yytext[0]); yylval=NULL; return(LEX_ATTR_VAL); }
133 amb 334
134     <TAG_ATTR_VAL>{W}+ { }
135     <TAG_ATTR_VAL>\" { BEGIN(DQUOTED); reset_string; }
136     <TAG_ATTR_VAL>\' { BEGIN(SQUOTED); reset_string; }
137     <TAG_ATTR_VAL>{val} { BEGIN(TAG); yylval=yytext; return(LEX_ATTR_VAL); }
138 amb 344 <TAG_ATTR_VAL>.|\n { BEGIN(TAG); unput(yytext[0]); yylval=NULL; return(LEX_ATTR_VAL); }
139 amb 334
140     /* Quoted strings */
141    
142     <DQUOTED>\\\\ { append_string(yytext); }
143     <DQUOTED>\\\" { append_string(yytext); }
144     <DQUOTED>\\ { append_string(yytext); }
145     <DQUOTED>\" { BEGIN(TAG); yylval=string; return(LEX_ATTR_VAL); }
146 amb 344 <DQUOTED>[^\\\"]+ { append_string(yytext); }
147 amb 334
148     <SQUOTED>\\\\ { append_string(yytext); }
149     <SQUOTED>\\\' { append_string(yytext); }
150     <SQUOTED>\\ { append_string(yytext); }
151     <SQUOTED>\' { BEGIN(TAG); yylval=string; return(LEX_ATTR_VAL); }
152 amb 344 <SQUOTED>[^\\\']+ { append_string(yytext); }
153 amb 334
154     /* End of file */
155    
156     <<EOF>> { free(string); string=NULL; BEGIN(INITIAL); return(0); }
157    
158     %%
159    
160     #include "xmlparse.h"
161    
162 amb 344 static inline void call_callback(char *name,void (*callback)(),int type,int nattributes,char *attributes[XMLPARSE_MAX_ATTRS])
163     {
164     switch(nattributes)
165     {
166     case 0: (*callback)(type); break;
167     case 1: (*callback)(type,attributes[0]); break;
168     case 2: (*callback)(type,attributes[0],attributes[1]); break;
169     case 3: (*callback)(type,attributes[0],attributes[1],attributes[2]); break;
170     case 4: (*callback)(type,attributes[0],attributes[1],attributes[2],attributes[3]); break;
171     case 5: (*callback)(type,attributes[0],attributes[1],attributes[2],attributes[3],attributes[4]); break;
172     case 6: (*callback)(type,attributes[0],attributes[1],attributes[2],attributes[3],attributes[4],attributes[5]); break;
173     case 7: (*callback)(type,attributes[0],attributes[1],attributes[2],attributes[3],attributes[4],attributes[5],attributes[6]); break;
174     case 8: (*callback)(type,attributes[0],attributes[1],attributes[2],attributes[3],attributes[4],attributes[5],attributes[6],attributes[7]); break;
175     case 9: (*callback)(type,attributes[0],attributes[1],attributes[2],attributes[3],attributes[4],attributes[5],attributes[6],attributes[7],attributes[8]); break;
176     case 10: (*callback)(type,attributes[0],attributes[1],attributes[2],attributes[3],attributes[4],attributes[5],attributes[6],attributes[7],attributes[8],attributes[9]); break;
177     case 11: (*callback)(type,attributes[0],attributes[1],attributes[2],attributes[3],attributes[4],attributes[5],attributes[6],attributes[7],attributes[8],attributes[9],attributes[10]); break;
178     case 12: (*callback)(type,attributes[0],attributes[1],attributes[2],attributes[3],attributes[4],attributes[5],attributes[6],attributes[7],attributes[8],attributes[9],attributes[10],attributes[11]); break;
179     case 13: (*callback)(type,attributes[0],attributes[1],attributes[2],attributes[3],attributes[4],attributes[5],attributes[6],attributes[7],attributes[8],attributes[9],attributes[10],attributes[11],attributes[12]); break;
180     case 14: (*callback)(type,attributes[0],attributes[1],attributes[2],attributes[3],attributes[4],attributes[5],attributes[6],attributes[7],attributes[8],attributes[9],attributes[10],attributes[11],attributes[12],attributes[13]); break;
181     case 15: (*callback)(type,attributes[0],attributes[1],attributes[2],attributes[3],attributes[4],attributes[5],attributes[6],attributes[7],attributes[8],attributes[9],attributes[10],attributes[11],attributes[12],attributes[13],attributes[14]); break;
182     case 16: (*callback)(type,attributes[0],attributes[1],attributes[2],attributes[3],attributes[4],attributes[5],attributes[6],attributes[7],attributes[8],attributes[9],attributes[10],attributes[11],attributes[12],attributes[13],attributes[14],attributes[15]); break;
183 amb 334
184 amb 344 default:
185     fprintf(stderr,"XML Parser: Error too many attributes for tag '%s' on line %d.\n",name,yylineno);
186     exit(1);
187     }
188     }
189    
190    
191 amb 334 /*++++++++++++++++++++++++++++++++++++++
192     Parse the XML and call the functions for each tag as seen.
193    
194     FILE *file The file to parse.
195    
196     xmltag **tags The array of pointers to tags for the top level.
197 amb 337
198     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.
199 amb 334 ++++++++++++++++++++++++++++++++++++++*/
200    
201 amb 337 void ParseXML(FILE *file,xmltag **tags,int ignore_unknown_attributes)
202 amb 334 {
203     int yychar,i;
204    
205     int nattributes=0;
206     char *attributes[XMLPARSE_MAX_ATTRS];
207     int attribute=0;
208    
209     int stackdepth=0,stackused=0;
210 amb 344 xmltag ***tags_stack=NULL;
211     xmltag **tag_stack=NULL;
212 amb 334 xmltag *tag=NULL;
213    
214     static int first=1;
215    
216     /* Parser (re)-initialisation */
217    
218     yyin=file;
219    
220     if(!first)
221     yyrestart(NULL);
222    
223     first=0;
224    
225     /* The actual parser. */
226    
227     while((yychar=yylex()))
228     switch(yychar)
229     {
230     /* The start of a tag for an element */
231    
232     case LEX_TAG_BEGIN:
233    
234     tag=NULL;
235    
236     for(i=0;tags[i];i++)
237     if(!strcasecmp(yylval,tags[i]->name))
238     {
239     tag=tags[i];
240    
241     for(i=0;i<nattributes;i++)
242     free(attributes[i]);
243    
244     for(i=0;i<XMLPARSE_MAX_ATTRS;i++)
245     if(!tag->attributes[i])
246     break;
247    
248     nattributes=i;
249    
250     for(i=0;i<nattributes;i++)
251     attributes[i]=NULL;
252    
253     break;
254     }
255    
256     if(tag==NULL)
257     {
258 amb 344 fprintf(stderr,"XML Parser: Error unexpected tag '%s' on line %d.\n",yylval,yylineno);
259 amb 334 exit(1);
260     }
261     break;
262    
263     /* The end of the start-tag for an element */
264    
265     case LEX_TAG_PUSH:
266    
267     if(stackused==stackdepth)
268 amb 344 {
269     tag_stack =(xmltag**) realloc((void*)tag_stack ,(stackdepth+=8)*sizeof(xmltag*));
270     tags_stack=(xmltag***)realloc((void*)tags_stack,(stackdepth+=8)*sizeof(xmltag**));
271     }
272 amb 334
273 amb 344 tag_stack [stackused]=tag;
274     tags_stack[stackused]=tags;
275     stackused++;
276    
277     if(tag->callback)
278     call_callback(tag->name,tag->callback,XMLPARSE_TAG_START,nattributes,attributes);
279    
280 amb 334 tags=tag->subtags;
281    
282 amb 344 break;
283    
284 amb 334 /* The end of the empty-element-tag for an element */
285    
286     case LEX_TAG_FINISH:
287    
288     if(tag->callback)
289 amb 344 call_callback(tag->name,tag->callback,XMLPARSE_TAG_START|XMLPARSE_TAG_END,nattributes,attributes);
290 amb 334
291 amb 344 if(stackused>0)
292     tag=tag_stack[stackused-1];
293     else
294     tag=NULL;
295 amb 334
296     break;
297    
298     /* The end of the end-tag for an element */
299    
300     case LEX_TAG_POP:
301    
302 amb 344 stackused--;
303     tags=tags_stack[stackused];
304     tag =tag_stack [stackused];
305 amb 334
306 amb 344 if(tag->callback)
307     call_callback(tag->name,tag->callback,XMLPARSE_TAG_END,nattributes,attributes);
308    
309     tag=tag_stack[stackused-1];
310    
311 amb 334 break;
312    
313     /* An attribute key */
314    
315     case LEX_ATTR_KEY:
316    
317     attribute=-1;
318    
319     for(i=0;i<nattributes;i++)
320     if(!strcasecmp(yylval,tag->attributes[i]))
321     {
322     attribute=i;
323    
324     break;
325     }
326    
327     if(attribute==-1)
328     {
329 amb 337 if(ignore_unknown_attributes==0)
330     {
331 amb 344 fprintf(stderr,"XML Parser: Error unexpected attribute '%s' for tag '%s' on line %d.\n",yylval,tag->name,yylineno);
332 amb 337 exit(1);
333     }
334     else if(ignore_unknown_attributes==1)
335 amb 344 fprintf(stderr,"XML Parser: Warning unexpected attribute '%s' for tag '%s' on line %d.\n",yylval,tag->name,yylineno);
336 amb 334 }
337     break;
338    
339     /* An attribute value */
340    
341     case LEX_ATTR_VAL:
342    
343 amb 337 if(yylval && attribute!=-1)
344 amb 334 attributes[attribute]=strcpy(malloc(strlen(yylval)+1),yylval);
345     }
346    
347     /* Delete the tagdata */
348    
349     for(i=0;i<nattributes;i++)
350     if(attributes[i])
351     free(attributes[i]);
352    
353     if(stackdepth)
354 amb 344 free(tags_stack);
355 amb 334 }

Properties

Name Value
cvs:description A simple generic XML parser.