prometheus/vendor/github.com/kr/logfmt/scanner.go

150 lines
2.0 KiB
Go

package logfmt
import (
"errors"
"fmt"
)
var ErrUnterminatedString = errors.New("logfmt: unterminated string")
func gotoScanner(data []byte, h Handler) (err error) {
saveError := func(e error) {
if err == nil {
err = e
}
}
var c byte
var i int
var m int
var key []byte
var val []byte
var ok bool
var esc bool
garbage:
if i == len(data) {
return
}
c = data[i]
switch {
case c > ' ' && c != '"' && c != '=':
key, val = nil, nil
m = i
i++
goto key
default:
i++
goto garbage
}
key:
if i >= len(data) {
if m >= 0 {
key = data[m:i]
saveError(h.HandleLogfmt(key, nil))
}
return
}
c = data[i]
switch {
case c > ' ' && c != '"' && c != '=':
i++
goto key
case c == '=':
key = data[m:i]
i++
goto equal
default:
key = data[m:i]
i++
saveError(h.HandleLogfmt(key, nil))
goto garbage
}
equal:
if i >= len(data) {
if m >= 0 {
i--
key = data[m:i]
saveError(h.HandleLogfmt(key, nil))
}
return
}
c = data[i]
switch {
case c > ' ' && c != '"' && c != '=':
m = i
i++
goto ivalue
case c == '"':
m = i
i++
esc = false
goto qvalue
default:
if key != nil {
saveError(h.HandleLogfmt(key, val))
}
i++
goto garbage
}
ivalue:
if i >= len(data) {
if m >= 0 {
val = data[m:i]
saveError(h.HandleLogfmt(key, val))
}
return
}
c = data[i]
switch {
case c > ' ' && c != '"' && c != '=':
i++
goto ivalue
default:
val = data[m:i]
saveError(h.HandleLogfmt(key, val))
i++
goto garbage
}
qvalue:
if i >= len(data) {
if m >= 0 {
saveError(ErrUnterminatedString)
}
return
}
c = data[i]
switch c {
case '\\':
i += 2
esc = true
goto qvalue
case '"':
i++
val = data[m:i]
if esc {
val, ok = unquoteBytes(val)
if !ok {
saveError(fmt.Errorf("logfmt: error unquoting bytes %q", string(val)))
goto garbage
}
} else {
val = val[1 : len(val)-1]
}
saveError(h.HandleLogfmt(key, val))
goto garbage
default:
i++
goto qvalue
}
}