File: reader.go

package info (click to toggle)
golang-github-cilium-ebpf 0.17.3%2Bds1-1
  • links: PTS, VCS
  • area: main
  • in suites: experimental
  • size: 4,684 kB
  • sloc: ansic: 1,259; makefile: 127; python: 113; awk: 29; sh: 24
file content (118 lines) | stat: -rw-r--r-- 2,655 bytes parent folder | download
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
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
package kallsyms

import (
	"bufio"
	"io"
	"unicode"
	"unicode/utf8"
)

// reader is a line and word-oriented reader built for reading /proc/kallsyms.
// It takes an io.Reader and iterates its contents line by line, then word by
// word.
//
// It's designed to allow partial reading of lines without paying the cost of
// allocating objects that will never be accessed, resulting in less work for
// the garbage collector.
type reader struct {
	s    *bufio.Scanner
	line []byte
	word []byte

	err error
}

func newReader(r io.Reader) *reader {
	return &reader{
		s: bufio.NewScanner(r),
	}
}

// Bytes returns the current word as a byte slice.
func (r *reader) Bytes() []byte {
	return r.word
}

// Text returns the output of Bytes as a string.
func (r *reader) Text() string {
	return string(r.Bytes())
}

// Line advances the reader to the next line in the input. Calling Line resets
// the current word, making [reader.Bytes] and [reader.Text] return empty
// values. Follow this up with a call to [reader.Word].
//
// Like [bufio.Scanner], [reader.Err] needs to be checked after Line returns
// false to determine if an error occurred during reading.
//
// Returns true if Line can be called again. Returns false if all lines in the
// input have been read.
func (r *reader) Line() bool {
	for r.s.Scan() {
		line := r.s.Bytes()
		if len(line) == 0 {
			continue
		}

		r.line = line
		r.word = nil

		return true
	}
	if err := r.s.Err(); err != nil {
		r.err = err
	}

	return false
}

// Word advances the reader to the next word in the current line.
//
// Returns true if a word is found and Word should be called again. Returns
// false when all words on the line have been read.
func (r *reader) Word() bool {
	if len(r.line) == 0 {
		return false
	}

	// Find next word start, skipping leading spaces.
	start := 0
	for width := 0; start < len(r.line); start += width {
		var c rune
		c, width = utf8.DecodeRune(r.line[start:])
		if !unicode.IsSpace(c) {
			break
		}
	}

	// Whitespace scanning reached the end of the line due to trailing whitespace,
	// meaning there are no more words to read
	if start == len(r.line) {
		return false
	}

	// Find next word end.
	for width, i := 0, start; i < len(r.line); i += width {
		var c rune
		c, width = utf8.DecodeRune(r.line[i:])
		if unicode.IsSpace(c) {
			r.word = r.line[start:i]
			r.line = r.line[i:]
			return true
		}
	}

	// The line contains data, but no end-of-word boundary was found. This is the
	// last, unterminated word in the line.
	if len(r.line) > start {
		r.word = r.line[start:]
		r.line = nil
		return true
	}

	return false
}

func (r *reader) Err() error {
	return r.err
}