123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183 |
- package ini
- import (
- "fmt"
- )
- type scanState int
- type scanFunction func(c byte, e *element) scanState
- const (
- scanContinue scanState = 1 << iota
- scanEOL
- scanEOF
- scanBegin
- scanSection
- scanVariable
- scanVariableValue
- )
- var (
- EOF = fmt.Errorf("END OF FILE")
- EOL = fmt.Errorf("END OF LINE")
- )
- type SyntaxError struct {
- got byte
- exp byte
- msg string
- off int
- }
- func (s *SyntaxError) Error() string {
- if s.got == 0 {
- return fmt.Sprintf("Error on position '%d: %s'", s.off, s.msg)
- }
- if s.exp == 0 {
- return fmt.Sprintf("Error on position '%d': %s. Got '%c'.", s.off, s.msg, s.got)
- }
- return fmt.Sprintf("Error on position '%d': %s. Got '%c' while expecting '%c'.", s.off, s.msg, s.got, s.exp)
- }
- type scanner struct {
- data []byte
- prev byte
- scan scanFunction
- read int
- len int
- err error
- }
- func newScanner(d []byte) *scanner {
- s := &scanner{
- data: d,
- prev: 0,
- read: 0,
- len: len(d),
- }
- s.scan = s.begin
- return s
- }
- func (s *scanner) loop() (*element, error) {
- e := newElement()
- for _, c := range s.data[s.read:] {
- s.read++
- state := s.scan(c, e)
- s.prev = c
- if s.err != nil {
- return nil, s.err
- }
- switch state {
- case scanEOL:
- return e, EOL
- case scanEOF:
- return e, EOF
- }
- }
- return e, nil
- }
- func (s *scanner) valid() error {
- for _, err := s.next(); ; _, err = s.next() {
- if err != EOF && err != EOL {
- return err
- }
- }
- return nil
- }
- func (s *scanner) next() (*element, error) {
- e, err := s.loop()
- return e, err
- }
- func (s *scanner) ret(state scanState) scanState {
- if state != scanEOF && s.read == s.len {
- s.scan = s.begin
- return scanEOF
- }
- if state == scanEOL {
- s.scan = s.begin
- }
- return state
- }
- func (s *scanner) begin(c byte, e *element) scanState {
- switch c {
- case ' ', '\n', '\t', '\r':
- return s.ret(scanContinue)
- case '[':
- e.setType(section)
- s.scan = s.section
- return s.ret(scanContinue)
- default:
- e.setType(variable)
- s.scan = s.variable
- return s.scan(c, e)
- }
- }
- func (s *scanner) section(c byte, e *element) scanState {
- switch c {
- case '\n':
- s.err = &SyntaxError{
- msg: "Missing valid character",
- got: c,
- exp: ']',
- off: s.read,
- }
- fallthrough
- case ']':
- return s.ret(scanEOL)
- default:
- e.setKey(c)
- return s.ret(scanContinue)
- }
- }
- func (s *scanner) variable(c byte, e *element) scanState {
- switch c {
- case '\n', '\r':
- return s.ret(scanEOL)
- case '=':
- e.removeLastKeyByteMatching(' ')
- s.scan = s.variableValue
- return s.ret(scanContinue)
- default:
- e.setKey(c)
- return s.ret(scanContinue)
- }
- }
- func (s *scanner) variableValue(c byte, e *element) scanState {
- switch c {
- case '"', '\'':
- return s.ret(scanContinue)
- case '\n', '\r':
- if s.prev == '\\' {
- e.setValue(byte('n'))
- return s.ret(scanContinue)
- }
- return s.ret(scanEOL)
- default:
- if s.prev == '=' && c == ' ' {
- return scanContinue
- }
- e.setValue(c)
- return s.ret(scanContinue)
- }
- }
|