aboutsummaryrefslogtreecommitdiffstats
path: root/wiretap/busmaster_scanner.l
blob: 4a352b961ca19f53c185eb97337ab5c1d897794f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
/* busmaster_scanner.l
 *
 * Wiretap Library
 * Copyright (c) 1998 by Gilbert Ramirez <gram@alumni.rice.edu>
 *
 * Support for Busmaster log file format
 * Copyright (c) 2019 by Maksim Salau <maksim.salau@gmail.com>
 *
 * SPDX-License-Identifier: GPL-2.0-or-later
 */

%top {
/* Include this before everything else, for various large-file definitions */
#include "config.h"
}

%option noyywrap
%option noinput
%option nounput
%option batch
%option never-interactive
%option nodefault
%option prefix="busmaster_"
%option reentrant
%option extra-type="busmaster_state_t *"

%option noyy_scan_buffer
%option noyy_scan_bytes
%option noyy_scan_string

/*
 * We have to override the memory allocators so that we don't get
 * "unused argument" warnings from the yyscanner argument (which
 * we don't use, as we have a global memory allocator).
 *
 * We provide, as macros, our own versions of the routines generated by Flex,
 * which just call malloc()/realloc()/free() (as the Flex versions do),
 * discarding the extra argument.
 */
%option noyyalloc
%option noyyrealloc
%option noyyfree

%{

#include <ws_diag_control.h>
#include <wiretap/file_wrappers.h>
#include "busmaster_parser.h"
#include "busmaster_priv.h"

#ifndef HAVE_UNISTD_H
#define YY_NO_UNISTD_H
#endif

static int busmaster_yyinput(void *buf, unsigned int length, busmaster_state_t *state)
{
    int ret = file_read(buf, length, state->fh);

    if (ret < 0)
    {
        state->err = file_error(state->fh, &state->err_info);
        return YY_NULL;
    }

    return ret;
}

#define YY_INPUT(buf, result, max_size) \
    do { (result) = busmaster_yyinput((buf), (max_size), yyextra); } while (0)

/* Count bytes read. This is required in order to rewind the file
 * to the beginning of the next packet, since flex reads more bytes
 * before executing the action that does yyterminate(). */
#define YY_USER_ACTION do { yyextra->file_bytes_read += yyleng; } while (0);

/*
 * Sleazy hack to suppress compiler warnings in yy_fatal_error().
 */
#define YY_EXIT_FAILURE ((void)yyscanner, 2)

/*
 * Macros for the allocators, to discard the extra argument.
 */
#define busmaster_alloc(size, yyscanner)          (void *)malloc(size)
#define busmaster_realloc(ptr, size, yyscanner)   (void *)realloc((char *)(ptr), (size))
#define busmaster_free(ptr, yyscanner)            free((char *)(ptr))

DIAG_OFF_FLEX

%}

SPC [ \t]+
ENDL [\r\n][ \t\r\n]*
INT [0-9]+
NUM (0x)?[0-9A-Fa-f]+

%x HEADER TIME
%x HEADER_CHANNELS HEADER_DB_FILES

%%

<*>{SPC}   ;
<INITIAL>{ENDL}               { yyterminate(); };
<HEADER,TIME>{ENDL}           { YY_FATAL_ERROR("Unterminated header statement"); }

"***"                         { BEGIN(HEADER); }
<HEADER,TIME>"***"{ENDL}"***" { BEGIN(HEADER); return TOKEN_ENDL; }
<HEADER>"***"{ENDL}           { BEGIN(INITIAL); yyterminate(); }
<HEADER>"BUSMASTER"           { return TOKEN_HEADER_VER; }
<HEADER>"PROTOCOL CAN"        { yyextra->token.v0 = PROTOCOL_CAN;   return TOKEN_PROTOCOL_TYPE; }
<HEADER>"PROTOCOL J1939"      { yyextra->token.v0 = PROTOCOL_J1939; return TOKEN_PROTOCOL_TYPE; }
<HEADER>"PROTOCOL LIN"        { yyextra->token.v0 = PROTOCOL_LIN;   return TOKEN_PROTOCOL_TYPE; }
<HEADER>"START DATE AND TIME" { BEGIN(TIME); return TOKEN_START_TIME; }
<HEADER>"END DATE AND TIME"   { BEGIN(TIME); return TOKEN_END_TIME; }
<HEADER>"DEC"                 { yyextra->token.v0 = DATA_MODE_DEC; return TOKEN_DATA_MODE; }
<HEADER>"HEX"                 { yyextra->token.v0 = DATA_MODE_HEX; return TOKEN_DATA_MODE; }
<HEADER>"ABSOLUTE MODE"       { yyextra->token.v0 = TIME_MODE_ABSOLUTE; return TOKEN_TIME_MODE; }
<HEADER>"SYSTEM MODE"         { yyextra->token.v0 = TIME_MODE_SYSTEM;   return TOKEN_TIME_MODE; }
<HEADER>"RELATIVE MODE"       { yyextra->token.v0 = TIME_MODE_RELATIVE; return TOKEN_TIME_MODE; }
<HEADER>"[START LOGGING SESSION]" { return TOKEN_START_SESSION; }
<HEADER>"[STOP LOGGING SESSION]" { return TOKEN_STOP_SESSION; }
<HEADER>"START CHANNEL BAUD RATE***" { BEGIN(HEADER_CHANNELS); }
<HEADER>"START DATABASE FILES (DBF/DBC)***" { BEGIN(HEADER_DB_FILES); }
<HEADER>.                     { return TOKEN_HEADER_CHAR; }

<HEADER_CHANNELS>"***END CHANNEL BAUD RATE***"{ENDL}"***" { BEGIN(HEADER); }
<HEADER_CHANNELS>.+           ;
<HEADER_CHANNELS>{ENDL}       ;

<HEADER_DB_FILES>"***END DATABASE FILES (DBF/DBC)***"{ENDL}"***" { BEGIN(HEADER); }
<HEADER_DB_FILES>"***END OF DATABASE FILES (DBF/DBC)***"{ENDL}"***" { BEGIN(HEADER); }
<HEADER_DB_FILES>.+           ;
<HEADER_DB_FILES>{ENDL}       ;

<TIME>{INT} { yyextra->token.v0 = strtoul(yytext, NULL, 10); return TOKEN_INT; }
<TIME>:     { return TOKEN_COLON; }
<TIME>.     { return TOKEN_INVALID_CHAR; }

<INITIAL>{INT}:{INT}:{INT}:{INT} {
                    char *endp;
                    char *strp;

                    yyextra->token.v0 = strtoul(yytext, &endp, 10);
                    if (*endp != ':' || endp == yytext)
                        return TOKEN_INVALID_NUMBER;

                    strp = endp + 1;
                    yyextra->token.v1 = strtoul(strp, &endp, 10);
                    if (*endp != ':' || endp == strp)
                        return TOKEN_INVALID_NUMBER;

                    strp = endp + 1;
                    yyextra->token.v2 = strtoul(strp, &endp, 10);
                    if (*endp != ':' || endp == strp)
                        return TOKEN_INVALID_NUMBER;

                    strp = endp + 1;
                    yyextra->token.v3 = strtoul(strp, &endp, 10);
                    if (*endp != '\0' || endp == strp)
                        return TOKEN_INVALID_NUMBER;

                    return TOKEN_MSG_TIME;
                }

<INITIAL>{NUM}  {
                    char *endp;

                    if (yyextra->header.data_mode == DATA_MODE_HEX)
                        yyextra->token.v0 = strtoul(yytext, &endp, 16);
                    else if (yyextra->header.data_mode == DATA_MODE_DEC)
                        yyextra->token.v0 = strtoul(yytext, &endp, 10);
                    else
                        return TOKEN_INVALID_NUMBER;

                    if (*endp != '\0' || endp == yytext)
                        return TOKEN_INVALID_NUMBER;

                    return TOKEN_INT;
                }

<INITIAL>[RT]x  { return TOKEN_MSG_DIR; }
<INITIAL>s      { yyextra->token.v0 = MSG_TYPE_STD;     return TOKEN_MSG_TYPE; }
<INITIAL>sr     { yyextra->token.v0 = MSG_TYPE_STD_RTR; return TOKEN_MSG_TYPE; }
<INITIAL>x      { yyextra->token.v0 = MSG_TYPE_EXT;     return TOKEN_MSG_TYPE; }
<INITIAL>xr     { yyextra->token.v0 = MSG_TYPE_EXT_RTR; return TOKEN_MSG_TYPE; }
<INITIAL>s-fd   { yyextra->token.v0 = MSG_TYPE_STD_FD;  return TOKEN_MSG_TYPE; }
<INITIAL>x-fd   { yyextra->token.v0 = MSG_TYPE_EXT_FD;  return TOKEN_MSG_TYPE; }
<INITIAL>ERR.*  { yyextra->token.v0 = MSG_TYPE_ERR;     return TOKEN_ERR_MSG_TYPE; }

<INITIAL>("NONE"|"CMD"|"RQST"|"DATA"|"BROADCAST"|"ACK"|"GRP_FUNC"|"ACL"|"RQST_ACL"|"CA"|"BAM"|"RTS"|"CTS"|"EOM"|"CON_ABORT"|"TPDT") {
    return TOKEN_J1939_MSG_TYPE;
}

<INITIAL>.      { return TOKEN_INVALID_CHAR; }

%%

DIAG_ON_FLEX