scanner.go 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. package ini
  2. // Scan a databuffer of INI-formatted data.
  3. import (
  4. "fmt"
  5. )
  6. type scanState int
  7. type scanFunction func(c byte, e *element) scanState
  8. const (
  9. scanContinue scanState = 1 << iota
  10. scanEOL
  11. scanEOF
  12. scanError
  13. scanBegin
  14. scanSection
  15. scanVariable
  16. scanVariableValue
  17. )
  18. var (
  19. EOF = fmt.Errorf("END OF FILE")
  20. EOL = fmt.Errorf("END OF LINE")
  21. )
  22. // SyntaxError is returned when the formatting is wrong.
  23. type SyntaxError struct {
  24. got byte
  25. exp byte
  26. msg string
  27. off int
  28. }
  29. // Error returns the error as a string
  30. func (s SyntaxError) Error() string {
  31. if s.got == 0 {
  32. return fmt.Sprintf("Error on position '%d: %s'", s.off, s.msg)
  33. }
  34. if s.exp == 0 {
  35. return fmt.Sprintf("Error on position '%d': %s. Got '%c'.", s.off, s.msg, s.got)
  36. }
  37. return fmt.Sprintf("Error on position '%d': %s. Got '%c' while expecting '%c'.", s.off, s.msg, s.got, s.exp)
  38. }
  39. type scanner struct {
  40. data []byte
  41. prev byte
  42. scan scanFunction
  43. read int
  44. len int
  45. err error
  46. }
  47. func newScanner(d []byte) *scanner {
  48. s := &scanner{
  49. data: d,
  50. prev: 0,
  51. read: 0,
  52. len: len(d),
  53. }
  54. s.scan = s.begin
  55. return s
  56. }
  57. func (s *scanner) reset() {
  58. s.prev = 0
  59. s.scan = s.begin
  60. s.read = 0
  61. s.err = nil
  62. }
  63. // loop assists next-method
  64. func (s *scanner) loop() (*element, error) {
  65. e := newElement()
  66. for _, c := range s.data[s.read:] {
  67. s.read++
  68. state := s.scan(c, e)
  69. s.prev = c
  70. if s.err != nil {
  71. return nil, s.err
  72. }
  73. switch state {
  74. case scanEOL:
  75. return e, EOL
  76. case scanEOF:
  77. return e, EOF
  78. }
  79. }
  80. return e, nil
  81. }
  82. // Just quickly loops through the INI and returns an error on error
  83. func (s *scanner) valid() error {
  84. defer s.reset()
  85. for _, err := s.next(); ; _, err = s.next() {
  86. switch err {
  87. case EOL:
  88. continue
  89. case EOF:
  90. return nil
  91. default:
  92. if err != nil {
  93. return err
  94. }
  95. }
  96. }
  97. return nil
  98. }
  99. // next returns one element and most likely an error (typically EOF/EOL) on every iteration
  100. func (s *scanner) next() (*element, error) {
  101. e, err := s.loop()
  102. if e != nil {
  103. e.trim()
  104. }
  105. return e, err
  106. }
  107. // ret ensures that we return the proper error
  108. func (s *scanner) ret(state scanState) scanState {
  109. if state != scanEOF && s.read == s.len {
  110. state = scanEOF
  111. }
  112. if state == scanEOL || state == scanEOF {
  113. s.scan = s.begin
  114. }
  115. return state
  116. }
  117. func (s *scanner) space(c byte) bool {
  118. return c == ' ' || c == '\n' || c == '\t' || c == '\r'
  119. }
  120. func (s *scanner) begin(c byte, e *element) scanState {
  121. switch {
  122. case s.space(c):
  123. return s.ret(scanContinue)
  124. case c == '[':
  125. e.setType(section)
  126. s.scan = s.section
  127. return s.ret(scanContinue)
  128. default:
  129. e.setType(variable)
  130. s.scan = s.variable
  131. return s.scan(c, e)
  132. }
  133. }
  134. func (s *scanner) section(c byte, e *element) scanState {
  135. switch {
  136. case s.space(c):
  137. s.err = SyntaxError{
  138. got: c,
  139. exp: ']',
  140. off: s.read,
  141. msg: "Invalid space character.",
  142. }
  143. return scanError
  144. case s.read == s.len:
  145. s.err = SyntaxError{
  146. got: 0x3,
  147. exp: ']',
  148. off: s.read,
  149. msg: "Invalid EOF",
  150. }
  151. return scanError
  152. case c == ']':
  153. return s.ret(scanEOL)
  154. default:
  155. e.key.add(c)
  156. return s.ret(scanContinue)
  157. }
  158. }
  159. func (s *scanner) variable(c byte, e *element) scanState {
  160. switch c {
  161. case '\n', '\r':
  162. return s.ret(scanEOL)
  163. case '=':
  164. s.scan = s.variableValue
  165. return s.ret(scanContinue)
  166. default:
  167. e.key.add(c)
  168. return s.ret(scanContinue)
  169. }
  170. }
  171. func (s *scanner) variableValue(c byte, e *element) scanState {
  172. switch c {
  173. case '\n', '\r':
  174. if e.val.lastByteMatching('\\') >= 0 {
  175. e.val.removeLastByteMatching('\\')
  176. e.val.add('\n')
  177. return s.ret(scanContinue)
  178. }
  179. return s.ret(scanEOL)
  180. default:
  181. e.val.add(c)
  182. return s.ret(scanContinue)
  183. }
  184. }