golang.org/x/arch@v0.17.0/x86/xeddata/readlines.go (about) 1 // Copyright 2025 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package xeddata 6 7 import ( 8 "bufio" 9 "bytes" 10 "fmt" 11 "io" 12 "iter" 13 "path/filepath" 14 "strings" 15 ) 16 17 type lineInfo struct { 18 Pos 19 data []byte 20 } 21 22 type Pos struct { 23 Path string 24 Line int 25 } 26 27 func (p Pos) String() string { 28 if p.Line == 0 { 29 if p.Path == "" { 30 return "?:?" 31 } 32 return p.Path 33 } else if p.Path == "" { 34 return fmt.Sprintf("?:%d", p.Line) 35 } 36 return fmt.Sprintf("%s:%d", p.Path, p.Line) 37 } 38 39 func (p Pos) ShortString() string { 40 p2 := p 41 p2.Path = filepath.Base(p.Path) 42 return p2.String() 43 } 44 45 // readLines yields lines from r, with continuation lines folded, comments and 46 // trailing whitespace removed, and blank lines omitted. 47 // 48 // The returned lineInfo.data buffer may be reused between yields. 49 // 50 // If r has a Name() string method, this is used to populate lineInfo.Path. 51 func readLines(r io.Reader) iter.Seq2[lineInfo, error] { 52 type Named interface { 53 Name() string // Matches os.File 54 } 55 path := "" 56 if f, ok := r.(Named); ok { 57 path = f.Name() 58 } 59 60 s := bufio.NewScanner(r) 61 return func(yield func(lineInfo, error) bool) { 62 var info lineInfo 63 info.Path = path 64 var lineBuf []byte 65 for s.Scan() { 66 info.Line++ 67 68 lineBuf = append(lineBuf, s.Bytes()...) 69 if len(lineBuf) > 0 && lineBuf[len(lineBuf)-1] == '\\' { 70 // Continuation line. Drop the \ and keep reading. 71 lineBuf = lineBuf[:len(lineBuf)-1] 72 continue 73 } 74 // Remove comments and trailing whitespace 75 if i := strings.IndexByte(string(lineBuf), '#'); i >= 0 { 76 lineBuf = lineBuf[:i] 77 } 78 lineBuf = bytes.TrimRight(lineBuf, " \t") 79 // Don't yield blank lines 80 if len(lineBuf) == 0 { 81 continue 82 } 83 84 info.data = lineBuf 85 if !yield(info, nil) { 86 return 87 } 88 lineBuf = lineBuf[:0] 89 } 90 91 if err := s.Err(); err != nil { 92 yield(lineInfo{}, err) 93 return 94 } 95 if len(lineBuf) > 0 { 96 yield(lineInfo{}, fmt.Errorf("continuation line at EOF")) 97 } 98 } 99 }