...
1 package logfmt
2
3 import (
4 "bufio"
5 "bytes"
6 "fmt"
7 "io"
8 "unicode/utf8"
9 )
10
11
12 type Decoder struct {
13 pos int
14 key []byte
15 value []byte
16 lineNum int
17 s *bufio.Scanner
18 err error
19 }
20
21
22
23
24
25 func NewDecoder(r io.Reader) *Decoder {
26 dec := &Decoder{
27 s: bufio.NewScanner(r),
28 }
29 return dec
30 }
31
32
33
34
35
36
37
38
39
40 func NewDecoderSize(r io.Reader, size int) *Decoder {
41 scanner := bufio.NewScanner(r)
42 scanner.Buffer(make([]byte, 0, size), size)
43 dec := &Decoder{
44 s: scanner,
45 }
46 return dec
47 }
48
49
50
51
52
53
54 func (dec *Decoder) ScanRecord() bool {
55 if dec.err != nil {
56 return false
57 }
58 if !dec.s.Scan() {
59 dec.err = dec.s.Err()
60 return false
61 }
62 dec.lineNum++
63 dec.pos = 0
64 return true
65 }
66
67
68
69
70
71 func (dec *Decoder) ScanKeyval() bool {
72 dec.key, dec.value = nil, nil
73 if dec.err != nil {
74 return false
75 }
76
77 line := dec.s.Bytes()
78
79
80 for p, c := range line[dec.pos:] {
81 if c > ' ' {
82 dec.pos += p
83 goto key
84 }
85 }
86 dec.pos = len(line)
87 return false
88
89 key:
90 const invalidKeyError = "invalid key"
91
92 start, multibyte := dec.pos, false
93 for p, c := range line[dec.pos:] {
94 switch {
95 case c == '=':
96 dec.pos += p
97 if dec.pos > start {
98 dec.key = line[start:dec.pos]
99 if multibyte && bytes.ContainsRune(dec.key, utf8.RuneError) {
100 dec.syntaxError(invalidKeyError)
101 return false
102 }
103 }
104 if dec.key == nil {
105 dec.unexpectedByte(c)
106 return false
107 }
108 goto equal
109 case c == '"':
110 dec.pos += p
111 dec.unexpectedByte(c)
112 return false
113 case c <= ' ':
114 dec.pos += p
115 if dec.pos > start {
116 dec.key = line[start:dec.pos]
117 if multibyte && bytes.ContainsRune(dec.key, utf8.RuneError) {
118 dec.syntaxError(invalidKeyError)
119 return false
120 }
121 }
122 return true
123 case c >= utf8.RuneSelf:
124 multibyte = true
125 }
126 }
127 dec.pos = len(line)
128 if dec.pos > start {
129 dec.key = line[start:dec.pos]
130 if multibyte && bytes.ContainsRune(dec.key, utf8.RuneError) {
131 dec.syntaxError(invalidKeyError)
132 return false
133 }
134 }
135 return true
136
137 equal:
138 dec.pos++
139 if dec.pos >= len(line) {
140 return true
141 }
142 switch c := line[dec.pos]; {
143 case c <= ' ':
144 return true
145 case c == '"':
146 goto qvalue
147 }
148
149
150 start = dec.pos
151 for p, c := range line[dec.pos:] {
152 switch {
153 case c == '=' || c == '"':
154 dec.pos += p
155 dec.unexpectedByte(c)
156 return false
157 case c <= ' ':
158 dec.pos += p
159 if dec.pos > start {
160 dec.value = line[start:dec.pos]
161 }
162 return true
163 }
164 }
165 dec.pos = len(line)
166 if dec.pos > start {
167 dec.value = line[start:dec.pos]
168 }
169 return true
170
171 qvalue:
172 const (
173 untermQuote = "unterminated quoted value"
174 invalidQuote = "invalid quoted value"
175 )
176
177 hasEsc, esc := false, false
178 start = dec.pos
179 for p, c := range line[dec.pos+1:] {
180 switch {
181 case esc:
182 esc = false
183 case c == '\\':
184 hasEsc, esc = true, true
185 case c == '"':
186 dec.pos += p + 2
187 if hasEsc {
188 v, ok := unquoteBytes(line[start:dec.pos])
189 if !ok {
190 dec.syntaxError(invalidQuote)
191 return false
192 }
193 dec.value = v
194 } else {
195 start++
196 end := dec.pos - 1
197 if end > start {
198 dec.value = line[start:end]
199 }
200 }
201 return true
202 }
203 }
204 dec.pos = len(line)
205 dec.syntaxError(untermQuote)
206 return false
207 }
208
209
210
211
212 func (dec *Decoder) Key() []byte {
213 return dec.key
214 }
215
216
217
218
219
220 func (dec *Decoder) Value() []byte {
221 return dec.value
222 }
223
224
225 func (dec *Decoder) Err() error {
226 return dec.err
227 }
228
229 func (dec *Decoder) syntaxError(msg string) {
230 dec.err = &SyntaxError{
231 Msg: msg,
232 Line: dec.lineNum,
233 Pos: dec.pos + 1,
234 }
235 }
236
237 func (dec *Decoder) unexpectedByte(c byte) {
238 dec.err = &SyntaxError{
239 Msg: fmt.Sprintf("unexpected %q", c),
240 Line: dec.lineNum,
241 Pos: dec.pos + 1,
242 }
243 }
244
245
246 type SyntaxError struct {
247 Msg string
248 Line int
249 Pos int
250 }
251
252 func (e *SyntaxError) Error() string {
253 return fmt.Sprintf("logfmt syntax error at pos %d on line %d: %s", e.Pos, e.Line, e.Msg)
254 }
255
View as plain text