1package dns
2
3// Implement a simple scanner, return a byte stream from an io reader.
4
5import (
6	"bufio"
7	"context"
8	"io"
9	"text/scanner"
10)
11
12type scan struct {
13	src      *bufio.Reader
14	position scanner.Position
15	eof      bool // Have we just seen a eof
16	ctx      context.Context
17}
18
19func scanInit(r io.Reader) (*scan, context.CancelFunc) {
20	s := new(scan)
21	s.src = bufio.NewReader(r)
22	s.position.Line = 1
23
24	ctx, cancel := context.WithCancel(context.Background())
25	s.ctx = ctx
26
27	return s, cancel
28}
29
30// tokenText returns the next byte from the input
31func (s *scan) tokenText() (byte, error) {
32	c, err := s.src.ReadByte()
33	if err != nil {
34		return c, err
35	}
36	select {
37	case <-s.ctx.Done():
38		return c, context.Canceled
39	default:
40		break
41	}
42
43	// delay the newline handling until the next token is delivered,
44	// fixes off-by-one errors when reporting a parse error.
45	if s.eof == true {
46		s.position.Line++
47		s.position.Column = 0
48		s.eof = false
49	}
50	if c == '\n' {
51		s.eof = true
52		return c, nil
53	}
54	s.position.Column++
55	return c, nil
56}
57