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) }