summaryrefslogtreecommitdiff
path: root/src/pkg/bufio/scan.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/pkg/bufio/scan.go')
-rw-r--r--src/pkg/bufio/scan.go34
1 files changed, 21 insertions, 13 deletions
diff --git a/src/pkg/bufio/scan.go b/src/pkg/bufio/scan.go
index 268ce6d1d..2e1a2e999 100644
--- a/src/pkg/bufio/scan.go
+++ b/src/pkg/bufio/scan.go
@@ -16,7 +16,7 @@ import (
// the Scan method will step through the 'tokens' of a file, skipping
// the bytes between the tokens. The specification of a token is
// defined by a split function of type SplitFunc; the default split
-// function breaks the input into lines with newlines stripped. Split
+// function breaks the input into lines with line termination stripped. Split
// functions are defined in this package for scanning a file into
// lines, bytes, UTF-8-encoded runes, and space-delimited words. The
// client may instead provide a custom split function.
@@ -27,8 +27,6 @@ import (
// control over error handling or large tokens, or must run sequential scans
// on a reader, should use bufio.Reader instead.
//
-// TODO(r): Provide executable examples.
-//
type Scanner struct {
r io.Reader // The reader provided by the client.
split SplitFunc // The function to split the tokens.
@@ -72,6 +70,7 @@ const (
)
// NewScanner returns a new Scanner to read from r.
+// The split function defaults to ScanLines.
func NewScanner(r io.Reader) *Scanner {
return &Scanner{
r: r,
@@ -159,17 +158,26 @@ func (s *Scanner) Scan() bool {
s.start = 0
continue
}
- // Finally we can read some input.
- n, err := s.r.Read(s.buf[s.end:len(s.buf)])
- if err != nil {
- s.setErr(err)
- }
- if n == 0 { // Don't loop forever if Reader doesn't deliver EOF.
- s.err = io.EOF
+ // Finally we can read some input. Make sure we don't get stuck with
+ // a misbehaving Reader. Officially we don't need to do this, but let's
+ // be extra careful: Scanner is for safe, simple jobs.
+ for loop := 0; ; {
+ n, err := s.r.Read(s.buf[s.end:len(s.buf)])
+ s.end += n
+ if err != nil {
+ s.setErr(err)
+ break
+ }
+ if n > 0 {
+ break
+ }
+ loop++
+ if loop > 100 {
+ s.setErr(io.ErrNoProgress)
+ break
+ }
}
- s.end += n
}
- panic("not reached")
}
// advance consumes n bytes of the buffer. It reports whether the advance was legal.
@@ -260,7 +268,7 @@ func dropCR(data []byte) []byte {
// ScanLines is a split function for a Scanner that returns each line of
// text, stripped of any trailing end-of-line marker. The returned line may
// be empty. The end-of-line marker is one optional carriage return followed
-// by one mandatory newline. In regular expression notation, it is `\r?\n'.
+// by one mandatory newline. In regular expression notation, it is `\r?\n`.
// The last non-empty line of input will be returned even if it has no
// newline.
func ScanLines(data []byte, atEOF bool) (advance int, token []byte, err error) {