e82220e70f17325cfea89825cf58bbbf0976f85b
[jelmer/wireshark.git] / epan / uat_load.l
1 /*
2  * We want to stop processing when we get to the end of the input.
3  */
4 %option noyywrap
5
6 /*
7  * We don't use unput, so don't generate code for it.
8  */
9 %option nounput
10
11 /*
12  * We don't read from the terminal.
13  */
14 %option never-interactive
15
16 /*
17  * Prefix scanner routines with "uat_load_" rather than "yy", so this scanner
18  * can coexist with other scanners.
19  */
20 %option prefix="uat_load_"
21
22 %{
23         /*
24          * uat_load.l
25          *
26          * $Id$
27          *
28          *  User Accessible Tables
29          *  Mantain an array of user accessible data strucures
30          *  One parser to fit them all
31          *
32          * (c) 2007, Luis E. Garcia Ontanon <luis.ontanon@gmail.com>
33          *
34          * Wireshark - Network traffic analyzer
35          * By Gerald Combs <gerald@wireshark.org>
36          * Copyright 2001 Gerald Combs
37          * 
38          * This program is free software; you can redistribute it and/or
39          * modify it under the terms of the GNU General Public License
40          * as published by the Free Software Foundation; either version 2
41          * of the License, or (at your option) any later version.
42          * 
43          * This program is distributed in the hope that it will be useful,
44          * but WITHOUT ANY WARRANTY; without even the implied warranty of
45          * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
46          * GNU General Public License for more details.
47          * 
48          * You should have received a copy of the GNU General Public License
49          * along with this program; if not, write to the Free Software
50          * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
51          */
52 #ifdef HAVE_CONFIG_H
53 # include "config.h"
54 #endif
55         
56 #include <stdlib.h>
57 #include <stdio.h>
58 #include <string.h>
59 #include <errno.h>
60 #include <ctype.h>
61         
62 #include <glib.h>
63
64 #include <epan/emem.h>
65 #include "uat-int.h"
66         
67         static uat_t* uat;
68         static guint colnum;
69         static gchar* ptr;
70         static guint len;
71         static gchar* error;
72         static void* record;
73         static guint linenum;
74
75 #define ERROR(fmtd) do { error = ep_strdup_printf("%s:%d: %s",uat->filename,linenum,ep_strdup_printf fmtd); yyterminate(); } while(0)
76
77 #define SET_FIELD() \
78         { const gchar* err; \
79         if (uat->fields[colnum].cb.chk) { \
80                 if ( ! uat->fields[colnum].cb.chk(record, ptr, len, uat->fields[colnum].cbdata.chk, uat->fields[colnum].fld_data, &err) ) { \
81                         ERROR(("%s",err)); \
82                 }\
83         }\
84         uat->fields[colnum].cb.set(record, ptr, len, uat->fields[colnum].cbdata.chk, uat->fields[colnum].fld_data);\
85         g_free(ptr);\
86         colnum++; \
87         } while(0)
88
89 #ifdef DEBUG_UAT_LOAD
90 #define DUMP_FIELD(str) \
91                 { guint i; printf("%s: %s='",str,uat->fields[colnum].name); for(i=0;i<len;i++) if (uat->fields[colnum].mode == PT_TXTMOD_HEXBYTES) { printf("%.2x ",((guint8*)ptr)[i]); } else putc(ptr[i],stdout); printf("'[%d]\n",len); }
92
93 #define DUMP(str) printf("%s\n",str)
94 #else
95 #define DUMP_FIELD(s)
96 #define DUMP(s)
97 #endif
98                 /*
99                  * XXX
100                  * quoted_string below fails badly on "...\\"
101                  * workarround in uat_save(), using /x5c and /x22
102                  */
103 %}
104
105 quoted_string \042([^\042]|\134\042)*\042
106 binstring ([0-9a-zA-Z][0-9a-zA-Z])*
107 separator [ \t]*,
108 newline [ \t]*[\r]?\n
109 ws [ \t]+
110 comment #[^\n]*\n
111
112 %x START_OF_LINE NEXT_FIELD SEPARATOR END_OF_RECORD ERRORED
113 %%
114 <START_OF_LINE,NEXT_FIELD>{ws} ;
115 <START_OF_LINE>{newline} linenum++;
116 <START_OF_LINE>{comment} linenum++;
117
118 <START_OF_LINE,NEXT_FIELD>{separator} {
119         ptr = g_strdup("");
120         len = 0;
121         
122         DUMP_FIELD("empty->next");
123         
124         SET_FIELD();
125         
126         if ( colnum >= uat->ncols ) {
127                 ERROR(("more fields than required"));
128         }
129         
130         BEGIN NEXT_FIELD;
131 }
132
133 <START_OF_LINE,NEXT_FIELD>{newline}   {
134         ptr = "";
135         len = 0;
136         
137         BEGIN END_OF_RECORD;
138
139         yyless(yyleng);
140 }
141
142 <START_OF_LINE,NEXT_FIELD>{quoted_string} {
143         ptr = uat_undquote(yytext,yyleng,&len);
144         
145         
146         if (colnum < uat->ncols - 1) {
147                 DUMP("quoted_str->s");
148                 BEGIN SEPARATOR;
149         } else {
150                 DUMP("quoted_str->eor");
151                 BEGIN END_OF_RECORD;
152         }
153 }
154
155 <START_OF_LINE,NEXT_FIELD>{binstring} {
156         ptr = uat_unbinstring(yytext,yyleng,&len);
157
158         if (!ptr) {
159                 ERROR(("uneven hexstring for field %s",uat->fields[colnum].name));
160         }
161         
162         if ( colnum < uat->ncols - 1 ) {
163                 DUMP("binstring->s");
164                 BEGIN SEPARATOR;
165         } else {
166                 DUMP("binstring->eor");
167                 BEGIN END_OF_RECORD;
168         }
169 }
170
171 <SEPARATOR>{separator} {
172         
173         DUMP_FIELD("separator->next");
174
175         SET_FIELD();
176
177         if ( colnum >= uat->ncols ) {
178                 ERROR(("more fields than required"));
179         }
180         
181         BEGIN NEXT_FIELD;
182 }
183
184 <SEPARATOR>{newline} {
185         linenum++;
186         ERROR(("expecting field %s in previuos line",uat->fields[colnum].name));
187         BEGIN START_OF_LINE;
188 }
189
190 <SEPARATOR>. {
191         ERROR(("unexpected char '%s' while looking for field %s",yytext,uat->fields[colnum].name));
192         BEGIN ERRORED;
193 }
194
195 <END_OF_RECORD>{separator} {
196         ERROR(("more fields than required"));
197         BEGIN ERRORED;
198 }
199
200 <END_OF_RECORD>{newline} {
201         void* rec;
202         const gchar* err = NULL;
203         
204         linenum++;
205
206         DUMP_FIELD("newline->start");
207
208         SET_FIELD();
209         
210         rec = uat_add_record(uat, record);
211
212         if (uat->update_cb)
213                 uat->update_cb(rec,&err);
214         
215         if (err) {
216                 ERROR(("%s",err));
217         }
218         
219         colnum = 0;;
220         ptr = NULL;
221         len = 0;
222         memset(record,0,uat->record_size);
223         
224         BEGIN START_OF_LINE;
225  }
226
227 <END_OF_RECORD>. {
228         ERROR(("unexpected char while looking for end of line"));
229         BEGIN ERRORED;
230 }
231
232 <ERRORED>{newline} { linenum++; BEGIN START_OF_LINE; }
233 <ERRORED>. ;
234
235 {newline} { linenum++; ERROR(("incomplete record")); BEGIN START_OF_LINE; }
236 . { ERROR(("unexpected input")); }
237
238 %%
239
240
241
242
243 gboolean uat_load(uat_t* uat_in, char** err) {
244         gchar* fname = uat_get_actual_filename(uat_in, FALSE);
245
246         uat = uat_in;
247
248         if (!fname) {
249                 UAT_UPDATE(uat);
250                 return TRUE;
251         }
252         
253
254         if (!(yyin = fopen(fname,"r"))) {
255                 *err = strerror(errno);
256                 return FALSE;
257         }
258         
259         error = NULL;
260         colnum = 0;
261         record = g_malloc0(uat->record_size);
262         linenum = 1;
263         
264         BEGIN START_OF_LINE;
265         DUMP(fname);
266         
267         yylex();
268         yyrestart(NULL);
269
270         uat->changed = FALSE;
271
272         if (error) {
273                 UAT_UPDATE(uat);
274                 *err = ep_strdup(error);
275                 return FALSE;
276         } else {
277                 UAT_UPDATE(uat);                
278                 *err = NULL;
279                 return TRUE;
280         }
281 }