This repository has been archived by the owner on May 21, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 69
/
Copy pathscanner.go
144 lines (123 loc) · 2.63 KB
/
scanner.go
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
package octetcounting
import (
"bufio"
"bytes"
"io"
"strconv"
)
// eof represents a marker byte for the end of the reader
var eof = byte(0)
// ws represents the whitespace
var ws = byte(32)
// lt represents the "<" character
var lt = byte(60)
// isDigit returns true if the byte represents a number in [0,9]
func isDigit(ch byte) bool {
return (ch >= 47 && ch <= 57)
}
// isNonZeroDigit returns true if the byte represents a number in ]0,9]
func isNonZeroDigit(ch byte) bool {
return (ch >= 48 && ch <= 57)
}
// Scanner represents the lexical scanner for octet counting transport.
type Scanner struct {
r *bufio.Reader
msglen uint64
ready bool
}
// NewScanner returns a pointer to a new instance of Scanner.
func NewScanner(r io.Reader, maxLength int) *Scanner {
return &Scanner{
r: bufio.NewReaderSize(r, maxLength+20), // max uint64 is 19 characters + a space
}
}
// read reads the next byte from the buffered reader
// it returns the byte(0) if an error occurs (or io.EOF is returned)
func (s *Scanner) read() byte {
b, err := s.r.ReadByte()
if err != nil {
return eof
}
return b
}
// unread places the previously read byte back on the reader
func (s *Scanner) unread() {
_ = s.r.UnreadByte()
}
// Scan returns the next token.
func (s *Scanner) Scan() (tok Token) {
// Read the next byte.
b := s.read()
if isNonZeroDigit(b) {
s.unread()
s.ready = false
return s.scanMsgLen()
}
// Otherwise read the individual character
switch b {
case eof:
s.ready = false
return Token{
typ: EOF,
}
case ws:
s.ready = true
return Token{
typ: WS,
lit: []byte{ws},
}
case lt:
if s.msglen > 0 && s.ready {
s.unread()
return s.scanSyslogMsg()
}
}
return Token{
typ: ILLEGAL,
lit: []byte{b},
}
}
func (s *Scanner) scanMsgLen() Token {
// Create a buffer and read the current character into it
var buf bytes.Buffer
buf.WriteByte(s.read())
// Read every subsequent digit character into the buffer
// Non-digit characters and EOF will cause the loop to exit
for {
if b := s.read(); b == eof {
break
} else if !isDigit(b) {
s.unread()
break
} else {
buf.WriteByte(b)
}
}
msglen := buf.String()
s.msglen, _ = strconv.ParseUint(msglen, 10, 64)
return Token{
typ: MSGLEN,
lit: buf.Bytes(),
}
}
func (s *Scanner) scanSyslogMsg() Token {
// Check the reader contains almost MSGLEN characters
n := int(s.msglen)
b, err := s.r.Peek(n)
if err != nil {
return Token{
typ: EOF,
lit: b,
}
}
// Advance the reader of MSGLEN characters
s.r.Discard(n)
// Reset status
s.ready = false
s.msglen = 0
// Return SYSLOGMSG token
return Token{
typ: SYSLOGMSG,
lit: b,
}
}