Fix some gcc 'old-style function definition' warnings.
[obnox/wireshark/wip.git] / wiretap / k12text.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 "K12Text_" rather than "yy", so this scanner
13  * can coexist with other scanners.
14  */
15 %option prefix="K12Text_"
16
17 %option outfile="k12text.c"
18
19 /* Options useful for debugging                         */
20 /* noline:  Prevent generation of #line directives      */
21 /*          Seems to be required when using the         */
22 /*          Windows VS debugger so as to be able        */
23 /*          to properly step through the code and       */
24 /*          set breakpoints & etc using the             */
25 /*          k12text.c file rather than the              */
26 /*          k12text.l file                              */
27 /*      XXX: %option noline gives an error message:     */
28 /*          "unrecognized %option: line"                */
29 /*          with flex 2.5.35; the --noline              */
30 /*          command-line option works OK.               */
31 /*                                                      */
32 /* debug:   Do output of "rule acceptance" info         */
33 /*          during parse                                */
34 /*                                                      */
35 /* %option noline  */
36 /* %option debug   */
37
38 %{
39 /* k12text.l
40  *
41  * $Id$
42  *
43  * Wiretap Library
44  * Copyright (c) 1998 by Gilbert Ramirez <gram@alumni.rice.edu>
45  *
46  * This program is free software; you can redistribute it and/or
47  * modify it under the terms of the GNU General Public License
48  * as published by the Free Software Foundation; either version 2
49  * of the License, or (at your option) any later version.
50  *
51  * This program is distributed in the hope that it will be useful,
52  * but WITHOUT ANY WARRANTY; without even the implied warranty of
53  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
54  * GNU General Public License for more details.
55  *
56  * You should have received a copy of the GNU General Public License
57  * along with this program; if not, write to the Free Software
58  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
59  */
60
61  /*
62   * TODO:
63   *   - fix timestamps after midnight
64   *   - verify encapsulations
65   */
66
67 #ifdef HAVE_CONFIG_H
68 #include "config.h"
69 #endif
70 #include <stdlib.h>
71 #include <string.h>
72 #include <errno.h>
73 #include <time.h>
74 #include "wtap-int.h"
75 #include "wtap.h"
76 #include "file_wrappers.h"
77 #include "buffer.h"
78 #include "k12.h"
79 #include "k12text_lex.h"
80
81 #ifndef HAVE_UNISTD_H
82 #define YY_NO_UNISTD_H
83 #endif
84
85 static guint g_h;
86 static guint g_m;
87 static guint g_s;
88 static guint g_ms;
89 static guint g_ns;
90 static gint g_encap;
91 static guint8 bb[WTAP_MAX_PACKET_SIZE];
92 static guint ii;
93 static gboolean is_k12text;
94 static gboolean at_eof;
95 static guint junk_chars;
96 static void finalize_frame(void);
97 static gchar* error_str;
98 static guint file_bytes_read;
99 static gboolean ok_frame;
100 static FILE_T yy_fh;
101
102 #define KERROR(text) do { error_str = g_strdup(text); yyterminate(); } while(0)
103 #define SET_HOURS(text) g_h = strtoul(text,NULL,10)
104 #define SET_MINUTES(text) g_m = strtoul(text,NULL,10)
105 #define SET_SECONDS(text) g_s = strtoul(text,NULL,10)
106 #define SET_MS(text) g_ms = strtoul(text,NULL,10)
107 #define SET_NS(text) g_ns = strtoul(text,NULL,10)
108 #define ADD_BYTE(text) do {if (ii >= WTAP_MAX_PACKET_SIZE) {KERROR("frame too large");} bb[ii++] = (guint8)strtoul(text,NULL,16); } while(0)
109 #define FINALIZE_FRAME() finalize_frame()
110 /*~ #define ECHO*/
111 #define YY_USER_ACTION file_bytes_read += yyleng;
112 #define YY_INPUT(buf,result,max_size) { int c = file_getc(yy_fh);  result = (c==EOF) ? YY_NULL : (buf[0] = c, 1); }
113
114 #define MAX_JUNK 400000
115 #define ECHO
116 %}
117 start_timestamp \053[\055]{9}\053[\055]{15,100}\053[\055]{10,100}\053
118 oneormoredigits [0-9]+:
119 twodigits [0-9][0-9]
120 colon :
121 comma ,
122 threedigits [0-9][0-9][0-9]
123 start_bytes \174\060\040\040\040\174
124 bytes_junk \174[A-F0-9][A-F0-9\040][A-F0-9\040][A-F0-9\040]\174
125 byte [a-f0-9][a-f0-9]\174
126 end_bytes \015?\012\015?\012
127 eth ETHER
128  /* mtp2 MTP-L2 ;; XXX: Not supported until it's determined how to fill in the pseudo_header req'd by packet-mtp2 */
129  /* sscop SSCOP ;; XXX: Not supported until it's determined how to fill in the pseudo_header req'd by packet-atm  */
130 sscfnni SSCF
131 hdlc HDLC
132
133 %START MAGIC NEXT_FRAME HOURS MINUTES M2S SECONDS S2M MS M2N NS ENCAP STARTBYTES BYTE
134 %%
135 <MAGIC>{start_timestamp}  { is_k12text = TRUE; yyterminate(); }
136
137 <MAGIC>. { if (++ junk_chars > MAX_JUNK) { is_k12text = FALSE;  yyterminate(); } }
138
139 <NEXT_FRAME>{start_timestamp} {BEGIN(HOURS); }
140 <HOURS>{oneormoredigits} { SET_HOURS(yytext); BEGIN(MINUTES); }
141 <MINUTES>{twodigits} { SET_MINUTES(yytext); BEGIN(M2S);}
142 <M2S>{colon} { BEGIN(SECONDS);}
143 <SECONDS>{twodigits} { SET_SECONDS(yytext); BEGIN(S2M); }
144 <S2M>{comma}  { BEGIN(MS); }
145 <MS>{threedigits} { SET_MS(yytext); BEGIN(M2N);  }
146 <M2N>{comma}  { BEGIN(NS); }
147 <NS>{threedigits} { SET_NS(yytext); BEGIN(ENCAP);}
148 <ENCAP>{eth} {g_encap = WTAP_ENCAP_ETHERNET; BEGIN(STARTBYTES); }
149  /* <ENCAP>{mtp2} {g_encap = WTAP_ENCAP_MTP2; BEGIN(STARTBYTES); }      Not supported as yet */
150  /* <ENCAP>{sscop} {g_encap = WTAP_ENCAP_ATM_PDUS; BEGIN(STARTBYTES); } Not supported as yet */
151 <ENCAP>{sscfnni} {g_encap = WTAP_ENCAP_MTP3; BEGIN(STARTBYTES); }
152 <ENCAP>{hdlc} {g_encap = WTAP_ENCAP_CHDLC; BEGIN(STARTBYTES); }
153 <ENCAP,STARTBYTES>{start_bytes} { BEGIN(BYTE); }
154 <BYTE>{byte} { ADD_BYTE(yytext); }
155 <BYTE>{bytes_junk} ;
156 <BYTE>{end_bytes} { FINALIZE_FRAME(); yyterminate(); }
157
158 . {  if (++junk_chars > MAX_JUNK) { KERROR("too much junk");  } }
159 <<EOF>> { at_eof = TRUE; yyterminate(); }
160
161 %%
162
163 static void finalize_frame(void) {
164         ok_frame = TRUE;
165 }
166
167 /* Fill in pseudo-header according to the encapsulation type    */
168
169 static void
170 k12text_set_pseudo_header(wtap *wth, union wtap_pseudo_header *pseudo_header)
171 {
172         /* The file-encap is WTAP_ENCAP_PER_PACKET */
173         switch(wth->phdr.pkt_encap) {
174             case WTAP_ENCAP_ETHERNET:
175                     pseudo_header->eth.fcs_len = 0;
176                     break;
177             case WTAP_ENCAP_MTP3:
178             case WTAP_ENCAP_CHDLC:
179                     /* no pseudo_header to fill in for these types */
180                     break;
181 #if 0
182             case WTAP_ENCAP_MTP2:      /* not (yet) supported           */
183             case WTAP_ENCAP_ATM_PDUS:  /* not (yet) supported           */
184                     /* XXX: I don't know how to fill in the             */
185                     /* pseudo_header for these types. So: The Lexer     */
186                     /* has recognition for these types commented        */
187                     /* out ....                                         */
188                     break;
189 #endif
190             case WTAP_ENCAP_UNKNOWN:
191             default:
192                     break;
193         }
194 }
195
196 /* Note: k12text_reset is called each time data is to be processed from */
197 /*       a file. This ensures that no "state" from a previous read is   */
198 /*       used (such as the lexer look-ahead buffer, file_handle, file   */
199 /*       position and so on. This allows a single lexer buffer to be    */
200 /*       used even when multiple files are open simultaneously (as for  */
201 /*       a file merge).                                                 */
202
203 static void
204 k12text_reset(FILE_T fh)
205 {
206         yy_fh = fh;
207         yyrestart(0);
208         g_encap = WTAP_ENCAP_UNKNOWN;
209         ok_frame = FALSE;
210         is_k12text = FALSE;
211         at_eof = FALSE;
212         junk_chars = 0;
213         error_str = NULL;
214         file_bytes_read=0;
215         g_h=0;
216         g_m=0;
217         g_s=0;
218         g_ns=0;
219         g_ms=0;
220         ii=0;
221 }
222
223 static gboolean
224 k12text_read(wtap *wth, int *err, char ** err_info, gint64 *data_offset)
225 {
226
227         /* We seek to the file position after the end of the previous frame processed by                */
228         /* k12text_read (kept in wth->data_offset). We do this each time since the lexer                */
229         /* undoubtedly did some amount of look-ahead when processing the previous frame.                */
230         /* We also clear out any lexer state (eg: look-ahead buffer) and init vars set by lexer.        */
231
232         if ( file_seek(wth->fh, wth->data_offset, SEEK_SET, err) == -1) {
233                 return FALSE;
234         }
235         k12text_reset(wth->fh);         /* init lexer buffer and vars set by lexer */
236
237         BEGIN(NEXT_FRAME);
238         yylex();
239
240         if (ok_frame == FALSE) {
241                 if (at_eof) {
242                         *err = 0;
243                         *err_info = NULL;
244                 } else {
245                         *err = WTAP_ERR_BAD_RECORD;
246                         *err_info = error_str;
247                 }
248                 return FALSE;
249         }
250
251         *data_offset = wth->data_offset;       /* file position for beginning of this frame   */
252         wth->data_offset += file_bytes_read;   /* file position after end of this frame       */
253
254         wth->phdr.ts.secs = 946681200 + (3600*g_h) + (60*g_m) + g_s;
255         wth->phdr.ts.nsecs = 1000000*g_ms + 1000*g_ns;
256
257         wth->phdr.caplen = wth->phdr.len = ii;
258
259         wth->phdr.pkt_encap = g_encap;
260         k12text_set_pseudo_header(wth, &wth->pseudo_header);
261
262         buffer_assure_space(wth->frame_buffer, wth->phdr.caplen);
263         memcpy(buffer_start_ptr(wth->frame_buffer), bb, wth->phdr.caplen);
264
265         return TRUE;
266 }
267
268 static gboolean
269 k12text_seek_read(wtap *wth, gint64 seek_off, union wtap_pseudo_header *pseudo_header, guint8 *pd, int length, int *err, char **err_info)
270 {
271
272         if ( file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1) {
273                 return FALSE;
274         }
275         k12text_reset(wth->random_fh);          /* init lexer buffer and vars set by lexer */
276
277         BEGIN(NEXT_FRAME);
278         yylex();
279
280         if (ok_frame == FALSE) {
281                 *err = WTAP_ERR_BAD_RECORD;
282                 if (at_eof) {
283                         /* What happened ? The desired frame was previously read without a problem */
284                         *err_info = g_strdup("Unexpected EOF (program error ?)");
285                 } else {
286                         *err_info = error_str;
287                 }
288                 return FALSE;
289         }
290
291         /* verify frame length parsed this time against original frame length */
292         if (ii != (guint)length) {
293                 /* What happened ? This now seems to have a different length than originally */
294                 *err = WTAP_ERR_BAD_RECORD;
295                 *err_info = g_strdup("Incorrect frame length (program error ?)");
296                 return FALSE;
297         }
298
299         k12text_set_pseudo_header(wth, pseudo_header);
300
301         memcpy(pd, bb, length);
302
303         return TRUE;
304 }
305
306 int
307 k12text_open(wtap *wth, int *err, gchar **err_info _U_)
308 {
309
310         k12text_reset(wth->fh);       /* init lexer buffer and vars set by lexer */
311
312         BEGIN(MAGIC);
313         yylex();
314
315         if (! is_k12text) return 0;
316
317         if ( file_seek(wth->fh, 0, SEEK_SET, err) == -1) {
318                 return -1;
319         }
320
321         wth->data_offset = 0;
322         wth->file_type = WTAP_FILE_K12TEXT;
323         wth->file_encap = WTAP_ENCAP_PER_PACKET;
324         wth->snapshot_length = 0;
325         wth->subtype_read = k12text_read;
326         wth->subtype_seek_read = k12text_seek_read;
327         wth->tsprecision = WTAP_FILE_TSPREC_NSEC;
328
329         return 1;
330 }
331
332
333 static const struct { int e; const char* s; } encaps[] = {
334         { WTAP_ENCAP_ETHERNET, "ETHER" },
335         { WTAP_ENCAP_MTP2, "MTP-L2" },
336         { WTAP_ENCAP_ATM_PDUS, "SSCOP" },
337         { WTAP_ENCAP_MTP3, "SSCF" },
338         { WTAP_ENCAP_CHDLC, "HDLC" },
339         /* ... */
340         { WTAP_ENCAP_UNKNOWN, "UNKNOWN" },
341         { 0, NULL }
342 };
343
344 static gboolean
345 k12text_dump(wtap_dumper *wdh _U_, const struct wtap_pkthdr *phdr,
346              const union wtap_pseudo_header *pseudo_header _U_,
347              const guchar *pd, int *err) {
348 #define K12BUF_SIZE 196808
349         char *buf;
350         size_t left = K12BUF_SIZE;
351         gint wl;
352         char *p;
353         const char* str_enc = "";
354         guint i;
355         guint ns;
356         guint ms;
357         gboolean ret;
358
359         buf = g_malloc(K12BUF_SIZE);
360         p = buf;
361
362         ms = phdr->ts.nsecs / 1000000;
363         ns = (phdr->ts.nsecs - (1000000*ms))/1000;
364
365         for(i=0; encaps[i].s; i++) {
366                 str_enc = encaps[i].s;
367                 if (phdr->pkt_encap == encaps[i].e) break;
368         }
369
370         strftime(p, 90, "+---------+---------------+----------+\r\n%H:%M:%S,",
371                  gmtime(&phdr->ts.secs));
372         wl = strlen(p);
373         p += wl;
374         left -= wl;
375
376         wl = g_snprintf(p, left, "%.3d,%.3d   %s\r\n|0   |", ms, ns, str_enc);
377         p += wl;
378         left -= wl;
379
380         for(i = 0; i < phdr->caplen && left > 2; i++) {
381                 wl = g_snprintf(p, left, "%.2x|", pd[i]);
382                 p += wl;
383                 left -= wl;
384         }
385
386         wl = g_snprintf(p, left, "\r\n\r\n");
387         p+= wl;
388         left -= wl;
389
390         ret = wtap_dump_file_write(wdh, buf, K12BUF_SIZE - left, err);
391
392         g_free(buf);
393         return ret;
394 }
395
396
397 gboolean
398 k12text_dump_open(wtap_dumper *wdh, int *err _U_)
399 {
400     wdh->subtype_write = k12text_dump;
401
402     return TRUE;
403 }
404
405 int
406 k12text_dump_can_write_encap(int encap)
407 {
408     switch (encap) {
409         case WTAP_ENCAP_PER_PACKET:
410         case WTAP_ENCAP_ETHERNET:
411         case WTAP_ENCAP_MTP3:
412         case WTAP_ENCAP_CHDLC:
413         case WTAP_ENCAP_UNKNOWN:
414                 return 0;
415         case WTAP_ENCAP_MTP2:
416         case WTAP_ENCAP_ATM_PDUS:
417         default:
418                 return WTAP_ERR_UNSUPPORTED_ENCAP;
419     }
420 }
421
422 /*
423  * We want to stop processing when we get to the end of the input.
424  * (%option noyywrap is not used because if used then
425  * some flex versions (eg: 2.5.35) generate code which causes
426  * warnings by the Windows VC compiler).
427  */
428
429 int yywrap(void) {
430     return 1;
431 }