From Slava:
[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         BEGIN START_OF_LINE;
224 }
225
226 <SEPARATOR>. {
227         ERROR(("unexpected char '%s' while looking for field %s",yytext,uat->fields[colnum].name));
228         BEGIN ERRORED;
229 }
230
231 <END_OF_RECORD>{separator} {
232         ERROR(("more fields than required"));
233         BEGIN ERRORED;
234 }
235
236 <END_OF_RECORD>{newline} {
237         void* rec;
238         const gchar* err = NULL;
239
240         linenum++;
241
242         DUMP_FIELD("newline->start");
243
244         SET_FIELD();
245
246         rec = uat_add_record(uat, record);
247
248         if (uat->update_cb)
249                 uat->update_cb(rec,&err);
250
251         if (err) {
252                 ERROR(("%s",err));
253         }
254
255         colnum = 0;;
256         ptr = NULL;
257         len = 0;
258         memset(record,0,uat->record_size);
259
260         BEGIN START_OF_LINE;
261  }
262
263 <END_OF_RECORD>. {
264         ERROR(("unexpected char while looking for end of line"));
265         BEGIN ERRORED;
266 }
267
268 <ERRORED>{newline} { linenum++; BEGIN START_OF_LINE; }
269 <ERRORED>. ;
270
271 {newline} { linenum++; ERROR(("incomplete record")); BEGIN START_OF_LINE; }
272 . { ERROR(("unexpected input")); }
273
274 %%
275
276
277
278
279 gboolean uat_load(uat_t* uat_in, char** err) {
280         gchar* fname = uat_get_actual_filename(uat_in, FALSE);
281
282         uat = uat_in;
283         parse_str = NULL;
284
285         if (!fname) {
286                 UAT_UPDATE(uat);
287                 return TRUE;
288         }
289
290
291         if (!(yyin = ws_fopen(fname,"r"))) {
292                 *err = strerror(errno);
293                 g_free(fname);
294                 return FALSE;
295         }
296
297         error = NULL;
298         colnum = 0;
299         record = g_malloc0(uat->record_size);
300         linenum = 1;
301
302         BEGIN START_OF_LINE;
303         DUMP(fname);
304         g_free(fname);  /* we're done with the file name now */
305
306         yylex();
307         yyrestart(NULL);
308
309         uat->changed = FALSE;
310         uat->loaded = TRUE;
311         UAT_UPDATE(uat);
312
313         if (error) {
314                 *err = ep_strdup(error);
315                 return FALSE;
316         }
317
318         if (uat->post_update_cb) 
319                 uat->post_update_cb();
320
321         *err = NULL;
322         return TRUE;
323 }
324
325 gboolean uat_load_str(uat_t* uat_in, char* entry, char** err) {
326         uat = uat_in;
327         parse_str = g_strdup_printf("%s\n", entry); /* Records must end with a newline */
328         parse_str_pos = 0;
329         yyin = NULL;
330
331         error = NULL;
332         colnum = 0;
333         record = g_malloc0(uat->record_size);
334         linenum = 1;
335
336         BEGIN START_OF_LINE;
337         DUMP(entry);
338
339         yylex();
340         yyrestart(NULL);
341         g_free(parse_str);
342         parse_str = NULL;
343
344         uat->changed = TRUE;
345         uat->loaded = TRUE;
346         if (error) {
347                 UAT_UPDATE(uat);
348                 *err = ep_strdup(error);
349                 return FALSE;
350         } else {
351                 UAT_UPDATE(uat);
352                 *err = NULL;
353                 return TRUE;
354         }
355         
356         if (uat->post_update_cb) 
357                         uat->post_update_cb();
358
359 }
360
361 /*
362  * We want to stop processing when we get to the end of the input.
363  * (%option noyywrap is not used because if used then
364  * some flex versions (eg: 2.5.35) generate code which causes
365  * warnings by the Windows VC compiler).
366  */
367
368 int yywrap(void) {
369     return 1;
370 }