package gut import ( "errors" "io" "io/ioutil" "strings" ) type LineParser struct { lines []string i int err error } var ErrUnexpectedEnd = errors.New("unexpected end of file") func (p *LineParser) EOF() bool { return p.i == len(p.lines) } func (p *LineParser) EmitErr(err error) ParseLineFn { p.err = err return nil } func (p *LineParser) Next() string { i := p.i p.i++ return p.lines[i] } func (p *LineParser) Peek() string { return p.lines[p.i] } func (p *LineParser) SkipSpaceEOF() bool { for !p.EOF() && len(strings.TrimSpace(p.Peek())) == 0 { p.Next() } return p.EOF() } func SkipSpaceBeforeContent(next ParseLineFn) ParseLineFn { return func(p *LineParser) ParseLineFn { if p.SkipSpaceEOF() { return p.EmitErr(ErrUnexpectedEnd) } return next } } type ParseLineFn func(p *LineParser) ParseLineFn func ParseLines(r io.Reader, fn ParseLineFn) error { content, err := ioutil.ReadAll(r) if err != nil { return err } lines := strings.Split(string(content), "\n") for i, line := range lines { lines[i] = strings.TrimRight(line, "\r\n") } parser := &LineParser{lines: lines} for fn != nil { fn = fn(parser) } return parser.err }