From Harald Welte:
[obnox/wireshark/wip.git] / epan / uat_load.l
1 /*
2  * We don't use unput, so don't generate code for it.
3  */
4 %option nounput
5
6 /*
7  * We don't read from the terminal.
8  */
9 %option never-interactive
10
11 /*
12  * Prefix scanner routines with "uat_load_" rather than "yy", so this scanner
13  * can coexist with other scanners.
14  */
15 %option prefix="uat_load_"
16
17 %{
18         /*
19          * uat_load.l
20          *
21          * $Id$
22          *
23          *  User Accessible Tables
24          *  Mantain an array of user accessible data strucures
25          *  One parser to fit them all
26          *
27          * (c) 2007, Luis E. Garcia Ontanon <luis@ontanon.org>
28          *
29          * Wireshark - Network traffic analyzer
30          * By Gerald Combs <gerald@wireshark.org>
31          * Copyright 2001 Gerald Combs
32          *
33          * This program is free software; you can redistribute it and/or
34          * modify it under the terms of the GNU General Public License
35          * as published by the Free Software Foundation; either version 2
36          * of the License, or (at your option) any later version.
37          *
38          * This program is distributed in the hope that it will be useful,
39          * but WITHOUT ANY WARRANTY; without even the implied warranty of
40          * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
41          * GNU General Public License for more details.
42          *
43          * You should have received a copy of the GNU General Public License
44          * along with this program; if not, write to the Free Software
45          * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
46          */
47 #ifdef HAVE_CONFIG_H
48 # include "config.h"
49 #endif
50
51 #include <stdlib.h>
52 #include <stdio.h>
53 #include <string.h>
54 #include <errno.h>
55 #include <ctype.h>
56
57 #include <glib.h>
58
59 #include <epan/emem.h>
60 #include "uat-int.h"
61 #include "uat_load_lex.h"
62 #include <wsutil/file_util.h>
63
64 #ifdef _WIN32
65 /* disable Windows VC compiler warning "signed/unsigned mismatch" associated  */
66 /* with YY_INPUT code generated by flex versions such as 2.5.35.              */
67 #pragma warning (disable:4018)
68 #endif
69
70         static uat_t* uat;
71         static guint colnum;
72         static gchar* ptr;
73         static guint len;
74         static gchar* error;
75         static void* record;
76         static guint linenum;
77         static gchar *parse_str;
78         static guint parse_str_pos;
79
80 #define ERROR(fmtd) do { error = ep_strdup_printf("%s:%d: %s",uat->filename,linenum,ep_strdup_printf fmtd); yyterminate(); } while(0)
81
82 #define SET_FIELD() \
83         { const gchar* err; \
84         if (uat->fields[colnum].cb.chk) { \
85                 if ( ! uat->fields[colnum].cb.chk(record, ptr, len, uat->fields[colnum].cbdata.chk, uat->fields[colnum].fld_data, &err) ) { \
86                         ERROR(("%s",err)); \
87                 }\
88         }\
89         uat->fields[colnum].cb.set(record, ptr, len, uat->fields[colnum].cbdata.chk, uat->fields[colnum].fld_data);\
90         g_free(ptr);\
91         colnum++; \
92         } while(0)
93
94 #ifdef DEBUG_UAT_LOAD
95 #define DUMP_FIELD(str) \
96                 { 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); }
97
98 #define DUMP(str) printf("%s\n",str)
99 #else
100 #define DUMP_FIELD(s)
101 #define DUMP(s)
102 #endif
103
104 /* Modified version of YY_INPUT generated by Flex 2.91 */
105 #define YY_INPUT(buf,result,max_size) \
106         if ( parse_str ) \
107                 { \
108                 int n = 0; \
109                 guint pslen = strlen(parse_str); \
110                 if (parse_str_pos < pslen) \
111                         { \
112                         n = pslen - parse_str_pos; \
113                         if (n > max_size) n = max_size; \
114                         memcpy(buf, parse_str + parse_str_pos, n); \
115                         parse_str_pos += n; \
116                         } \
117                 result = n; \
118                 } \
119         else \
120                 { \
121                 errno=0; \
122                 while ( (result = fread(buf, 1, max_size, yyin))==0 && ferror(yyin)) \
123                         { \
124                         if( errno != EINTR) \
125                                 { \
126                                 YY_FATAL_ERROR( "input in flex scanner failed" ); \
127                                 break; \
128                                 } \
129                         errno=0; \
130                         clearerr(yyin); \
131                         } \
132                 }
133
134                 /*
135                  * XXX
136                  * quoted_string below fails badly on "...\\"
137                  * workarround in uat_save(), using /x5c and /x22
138                  */
139 %}
140
141 quoted_string \042([^\042]|\134\042)*\042
142 binstring ([0-9a-zA-Z][0-9a-zA-Z])*
143 separator [ \t]*,
144 newline [ \t]*[\r]?\n
145 ws [ \t]+
146 comment #[^\n]*\n
147
148 %x START_OF_LINE NEXT_FIELD SEPARATOR END_OF_RECORD ERRORED
149 %%
150 <START_OF_LINE,NEXT_FIELD>{ws} ;
151 <START_OF_LINE>{newline} linenum++;
152 <START_OF_LINE>{comment} linenum++;
153
154 <START_OF_LINE,NEXT_FIELD>{separator} {
155         ptr = g_strdup("");
156         len = 0;
157
158         DUMP_FIELD("empty->next");
159
160         SET_FIELD();
161
162         if ( colnum >= uat->ncols ) {
163                 ERROR(("more fields than required"));
164         }
165
166         BEGIN NEXT_FIELD;
167 }
168
169 <START_OF_LINE,NEXT_FIELD>{newline}   {
170         ptr = "";
171         len = 0;
172
173         BEGIN END_OF_RECORD;
174
175         yyless(yyleng);
176 }
177
178 <START_OF_LINE,NEXT_FIELD>{quoted_string} {
179         ptr = uat_undquote(yytext,yyleng,&len);
180
181
182         if (colnum < uat->ncols - 1) {
183                 DUMP("quoted_str->s");
184                 BEGIN SEPARATOR;
185         } else {
186                 DUMP("quoted_str->eor");
187                 BEGIN END_OF_RECORD;
188         }
189 }
190
191 <START_OF_LINE,NEXT_FIELD>{binstring} {
192         ptr = uat_unbinstring(yytext,yyleng,&len);
193
194         if (!ptr) {
195                 ERROR(("uneven hexstring for field %s",uat->fields[colnum].name));
196         }
197
198         if ( colnum < uat->ncols - 1 ) {
199                 DUMP("binstring->s");
200                 BEGIN SEPARATOR;
201         } else {
202                 DUMP("binstring->eor");
203                 BEGIN END_OF_RECORD;
204         }
205 }
206
207 <SEPARATOR>{separator} {
208
209         DUMP_FIELD("separator->next");
210
211         SET_FIELD();
212
213         if ( colnum >= uat->ncols ) {
214                 ERROR(("more fields than required"));
215         }
216
217         BEGIN NEXT_FIELD;
218 }
219
220 <SEPARATOR>{newline} {
221         linenum++;
222         ERROR(("expecting field %s in previous line",uat->fields[colnum].name));
223 }
224
225 <SEPARATOR>. {
226         ERROR(("unexpected char '%s' while looking for field %s",yytext,uat->fields[colnum].name));
227 }
228
229 <END_OF_RECORD>{separator} {
230         ERROR(("more fields than required"));
231 }
232
233 <END_OF_RECORD>{newline} {
234         void* rec;
235         const gchar* err = NULL;
236
237         linenum++;
238
239         DUMP_FIELD("newline->start");
240
241         SET_FIELD();
242
243         rec = uat_add_record(uat, record);
244
245         if (uat->update_cb)
246                 uat->update_cb(rec,&err);
247
248         if (err) {
249                 ERROR(("%s",err));
250         }
251
252         colnum = 0;;
253         ptr = NULL;
254         len = 0;
255         memset(record,0,uat->record_size);
256
257         BEGIN START_OF_LINE;
258  }
259
260 <END_OF_RECORD>. {
261         ERROR(("unexpected char while looking for end of line"));
262 }
263
264 <ERRORED>{newline} { linenum++; BEGIN START_OF_LINE; }
265 <ERRORED>. ;
266
267 {newline} { linenum++; ERROR(("incomplete record")); BEGIN START_OF_LINE; }
268 . { ERROR(("unexpected input")); }
269
270 %%
271
272
273
274
275 gboolean uat_load(uat_t* uat_in, char** err) {
276         gchar* fname = uat_get_actual_filename(uat_in, FALSE);
277
278         uat = uat_in;
279         parse_str = NULL;
280
281         if (!fname) {
282                 UAT_UPDATE(uat);
283                 return TRUE;
284         }
285
286
287         if (!(yyin = ws_fopen(fname,"r"))) {
288                 *err = g_strerror(errno);
289                 g_free(fname);
290                 return FALSE;
291         }
292
293         error = NULL;
294         colnum = 0;
295         record = g_malloc0(uat->record_size);
296         linenum = 1;
297
298         BEGIN START_OF_LINE;
299         DUMP(fname);
300         g_free(fname);  /* we're done with the file name now */
301
302         yylex();
303         fclose(yyin);
304         yyrestart(NULL);
305
306         uat->changed = FALSE;
307         uat->loaded = TRUE;
308         UAT_UPDATE(uat);
309
310         if (error) {
311                 *err = ep_strdup(error);
312                 return FALSE;
313         }
314
315         if (uat->post_update_cb) 
316                 uat->post_update_cb();
317
318         *err = NULL;
319         return TRUE;
320 }
321
322 gboolean uat_load_str(uat_t* uat_in, char* entry, char** err) {
323         uat = uat_in;
324         parse_str = g_strdup_printf("%s\n", entry); /* Records must end with a newline */
325         parse_str_pos = 0;
326         yyin = NULL;
327
328         error = NULL;
329         colnum = 0;
330         record = g_malloc0(uat->record_size);
331         linenum = 1;
332
333         BEGIN START_OF_LINE;
334         DUMP(entry);
335
336         yylex();
337         yyrestart(NULL);
338         g_free(parse_str);
339         parse_str = NULL;
340
341         uat->changed = TRUE;
342         uat->loaded = TRUE;
343         UAT_UPDATE(uat);
344
345         if (error) {
346                 *err = ep_strdup(error);
347                 return FALSE;
348         }
349
350         if (uat->post_update_cb) 
351                 uat->post_update_cb();
352
353         *err = NULL;
354         return TRUE;
355 }
356
357 /*
358  * We want to stop processing when we get to the end of the input.
359  * (%option noyywrap is not used because if used then
360  * some flex versions (eg: 2.5.35) generate code which causes
361  * warnings by the Windows VC compiler).
362  */
363
364 int yywrap(void) {
365     return 1;
366 }