scanner.go 2.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. package logfmt
  2. import (
  3. "errors"
  4. "fmt"
  5. )
  6. var ErrUnterminatedString = errors.New("logfmt: unterminated string")
  7. func gotoScanner(data []byte, h Handler) (err error) {
  8. saveError := func(e error) {
  9. if err == nil {
  10. err = e
  11. }
  12. }
  13. var c byte
  14. var i int
  15. var m int
  16. var key []byte
  17. var val []byte
  18. var ok bool
  19. var esc bool
  20. garbage:
  21. if i == len(data) {
  22. return
  23. }
  24. c = data[i]
  25. switch {
  26. case c > ' ' && c != '"' && c != '=':
  27. key, val = nil, nil
  28. m = i
  29. i++
  30. goto key
  31. default:
  32. i++
  33. goto garbage
  34. }
  35. key:
  36. if i >= len(data) {
  37. if m >= 0 {
  38. key = data[m:i]
  39. saveError(h.HandleLogfmt(key, nil))
  40. }
  41. return
  42. }
  43. c = data[i]
  44. switch {
  45. case c > ' ' && c != '"' && c != '=':
  46. i++
  47. goto key
  48. case c == '=':
  49. key = data[m:i]
  50. i++
  51. goto equal
  52. default:
  53. key = data[m:i]
  54. i++
  55. saveError(h.HandleLogfmt(key, nil))
  56. goto garbage
  57. }
  58. equal:
  59. if i >= len(data) {
  60. if m >= 0 {
  61. i--
  62. key = data[m:i]
  63. saveError(h.HandleLogfmt(key, nil))
  64. }
  65. return
  66. }
  67. c = data[i]
  68. switch {
  69. case c > ' ' && c != '"' && c != '=':
  70. m = i
  71. i++
  72. goto ivalue
  73. case c == '"':
  74. m = i
  75. i++
  76. esc = false
  77. goto qvalue
  78. default:
  79. if key != nil {
  80. saveError(h.HandleLogfmt(key, val))
  81. }
  82. i++
  83. goto garbage
  84. }
  85. ivalue:
  86. if i >= len(data) {
  87. if m >= 0 {
  88. val = data[m:i]
  89. saveError(h.HandleLogfmt(key, val))
  90. }
  91. return
  92. }
  93. c = data[i]
  94. switch {
  95. case c > ' ' && c != '"' && c != '=':
  96. i++
  97. goto ivalue
  98. default:
  99. val = data[m:i]
  100. saveError(h.HandleLogfmt(key, val))
  101. i++
  102. goto garbage
  103. }
  104. qvalue:
  105. if i >= len(data) {
  106. if m >= 0 {
  107. saveError(ErrUnterminatedString)
  108. }
  109. return
  110. }
  111. c = data[i]
  112. switch c {
  113. case '\\':
  114. i += 2
  115. esc = true
  116. goto qvalue
  117. case '"':
  118. i++
  119. val = data[m:i]
  120. if esc {
  121. val, ok = unquoteBytes(val)
  122. if !ok {
  123. saveError(fmt.Errorf("logfmt: error unquoting bytes %q", string(val)))
  124. goto garbage
  125. }
  126. } else {
  127. val = val[1 : len(val)-1]
  128. }
  129. saveError(h.HandleLogfmt(key, val))
  130. goto garbage
  131. default:
  132. i++
  133. goto qvalue
  134. }
  135. }