OSDN Git Service

new repo
[bytom/vapor.git] / vendor / github.com / go-logfmt / logfmt / decode.go
1 package logfmt
2
3 import (
4         "bufio"
5         "bytes"
6         "fmt"
7         "io"
8         "unicode/utf8"
9 )
10
11 // A Decoder reads and decodes logfmt records from an input stream.
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 // NewDecoder returns a new decoder that reads from r.
22 //
23 // The decoder introduces its own buffering and may read data from r beyond
24 // the logfmt records requested.
25 func NewDecoder(r io.Reader) *Decoder {
26         dec := &Decoder{
27                 s: bufio.NewScanner(r),
28         }
29         return dec
30 }
31
32 // ScanRecord advances the Decoder to the next record, which can then be
33 // parsed with the ScanKeyval method. It returns false when decoding stops,
34 // either by reaching the end of the input or an error. After ScanRecord
35 // returns false, the Err method will return any error that occurred during
36 // decoding, except that if it was io.EOF, Err will return nil.
37 func (dec *Decoder) ScanRecord() bool {
38         if dec.err != nil {
39                 return false
40         }
41         if !dec.s.Scan() {
42                 dec.err = dec.s.Err()
43                 return false
44         }
45         dec.lineNum++
46         dec.pos = 0
47         return true
48 }
49
50 // ScanKeyval advances the Decoder to the next key/value pair of the current
51 // record, which can then be retrieved with the Key and Value methods. It
52 // returns false when decoding stops, either by reaching the end of the
53 // current record or an error.
54 func (dec *Decoder) ScanKeyval() bool {
55         dec.key, dec.value = nil, nil
56         if dec.err != nil {
57                 return false
58         }
59
60         line := dec.s.Bytes()
61
62         // garbage
63         for p, c := range line[dec.pos:] {
64                 if c > ' ' {
65                         dec.pos += p
66                         goto key
67                 }
68         }
69         dec.pos = len(line)
70         return false
71
72 key:
73         const invalidKeyError = "invalid key"
74
75         start, multibyte := dec.pos, false
76         for p, c := range line[dec.pos:] {
77                 switch {
78                 case c == '=':
79                         dec.pos += p
80                         if dec.pos > start {
81                                 dec.key = line[start:dec.pos]
82                                 if multibyte && bytes.IndexRune(dec.key, utf8.RuneError) != -1 {
83                                         dec.syntaxError(invalidKeyError)
84                                         return false
85                                 }
86                         }
87                         if dec.key == nil {
88                                 dec.unexpectedByte(c)
89                                 return false
90                         }
91                         goto equal
92                 case c == '"':
93                         dec.pos += p
94                         dec.unexpectedByte(c)
95                         return false
96                 case c <= ' ':
97                         dec.pos += p
98                         if dec.pos > start {
99                                 dec.key = line[start:dec.pos]
100                                 if multibyte && bytes.IndexRune(dec.key, utf8.RuneError) != -1 {
101                                         dec.syntaxError(invalidKeyError)
102                                         return false
103                                 }
104                         }
105                         return true
106                 case c >= utf8.RuneSelf:
107                         multibyte = true
108                 }
109         }
110         dec.pos = len(line)
111         if dec.pos > start {
112                 dec.key = line[start:dec.pos]
113                 if multibyte && bytes.IndexRune(dec.key, utf8.RuneError) != -1 {
114                         dec.syntaxError(invalidKeyError)
115                         return false
116                 }
117         }
118         return true
119
120 equal:
121         dec.pos++
122         if dec.pos >= len(line) {
123                 return true
124         }
125         switch c := line[dec.pos]; {
126         case c <= ' ':
127                 return true
128         case c == '"':
129                 goto qvalue
130         }
131
132         // value
133         start = dec.pos
134         for p, c := range line[dec.pos:] {
135                 switch {
136                 case c == '=' || c == '"':
137                         dec.pos += p
138                         dec.unexpectedByte(c)
139                         return false
140                 case c <= ' ':
141                         dec.pos += p
142                         if dec.pos > start {
143                                 dec.value = line[start:dec.pos]
144                         }
145                         return true
146                 }
147         }
148         dec.pos = len(line)
149         if dec.pos > start {
150                 dec.value = line[start:dec.pos]
151         }
152         return true
153
154 qvalue:
155         const (
156                 untermQuote  = "unterminated quoted value"
157                 invalidQuote = "invalid quoted value"
158         )
159
160         hasEsc, esc := false, false
161         start = dec.pos
162         for p, c := range line[dec.pos+1:] {
163                 switch {
164                 case esc:
165                         esc = false
166                 case c == '\\':
167                         hasEsc, esc = true, true
168                 case c == '"':
169                         dec.pos += p + 2
170                         if hasEsc {
171                                 v, ok := unquoteBytes(line[start:dec.pos])
172                                 if !ok {
173                                         dec.syntaxError(invalidQuote)
174                                         return false
175                                 }
176                                 dec.value = v
177                         } else {
178                                 start++
179                                 end := dec.pos - 1
180                                 if end > start {
181                                         dec.value = line[start:end]
182                                 }
183                         }
184                         return true
185                 }
186         }
187         dec.pos = len(line)
188         dec.syntaxError(untermQuote)
189         return false
190 }
191
192 // Key returns the most recent key found by a call to ScanKeyval. The returned
193 // slice may point to internal buffers and is only valid until the next call
194 // to ScanRecord.  It does no allocation.
195 func (dec *Decoder) Key() []byte {
196         return dec.key
197 }
198
199 // Value returns the most recent value found by a call to ScanKeyval. The
200 // returned slice may point to internal buffers and is only valid until the
201 // next call to ScanRecord.  It does no allocation when the value has no
202 // escape sequences.
203 func (dec *Decoder) Value() []byte {
204         return dec.value
205 }
206
207 // Err returns the first non-EOF error that was encountered by the Scanner.
208 func (dec *Decoder) Err() error {
209         return dec.err
210 }
211
212 func (dec *Decoder) syntaxError(msg string) {
213         dec.err = &SyntaxError{
214                 Msg:  msg,
215                 Line: dec.lineNum,
216                 Pos:  dec.pos + 1,
217         }
218 }
219
220 func (dec *Decoder) unexpectedByte(c byte) {
221         dec.err = &SyntaxError{
222                 Msg:  fmt.Sprintf("unexpected %q", c),
223                 Line: dec.lineNum,
224                 Pos:  dec.pos + 1,
225         }
226 }
227
228 // A SyntaxError represents a syntax error in the logfmt input stream.
229 type SyntaxError struct {
230         Msg  string
231         Line int
232         Pos  int
233 }
234
235 func (e *SyntaxError) Error() string {
236         return fmt.Sprintf("logfmt syntax error at pos %d on line %d: %s", e.Pos, e.Line, e.Msg)
237 }