1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
|
package gophermap
import (
"bufio"
"bytes"
"errors"
"fmt"
"io"
"strconv"
sr "tildegit.org/tjp/sliderule"
"tildegit.org/tjp/sliderule/gopher"
)
// Parse reads a gophermap document from a reader.
func Parse(input io.Reader) (gopher.MapDocument, error) {
rdr := bufio.NewReader(input)
doc := gopher.MapDocument{}
for num := 1; ; num += 1 {
line, err := rdr.ReadBytes('\n')
isEOF := errors.Is(err, io.EOF)
if err != nil && !isEOF {
return nil, err
}
line = bytes.TrimSuffix(bytes.TrimSuffix(line, []byte{'\n'}), []byte{'\r'})
if len(line) > 0 && !bytes.Equal(line, []byte(".")) {
item := gopher.MapItem{Type: sr.Status(line[0])}
spl := bytes.Split(line[1:], []byte{'\t'})
if item.Type != gopher.InfoMessageType && len(spl) != 4 {
return nil, InvalidLine(num)
}
item.Display = string(spl[0])
if len(spl) > 1 {
item.Selector = string(spl[1])
}
if len(spl) > 2 {
item.Hostname = string(spl[2])
}
if len(spl) > 3 {
item.Port = string(spl[3])
if _, err = strconv.Atoi(item.Port); err != nil {
return nil, InvalidLine(num)
}
}
doc = append(doc, item)
}
if isEOF {
break
}
}
return doc, nil
}
// InvalidLine is returned from Parse when the reader contains a line which is invalid gophermap.
type InvalidLine int
// Error implements the error interface.
func (il InvalidLine) Error() string {
return fmt.Sprintf("Invalid gophermap on line %d.", il)
}
|