1
0
mirror of https://github.com/golang/go synced 2024-11-25 06:57:58 -07:00

fmt.Scan: fix handling of EOFs.

Fixes #876.

R=rsc
CC=golang-dev
https://golang.org/cl/1675048
This commit is contained in:
Rob Pike 2010-06-24 15:24:25 -07:00
parent 37a6bc838b
commit 56f3c70111
2 changed files with 53 additions and 2 deletions

View File

@ -125,12 +125,15 @@ type scanError struct {
err os.Error
}
const EOF = -1
// ss is the internal implementation of ScanState.
type ss struct {
rr readRuner // where to read input
buf bytes.Buffer // token accumulator
nlIsSpace bool // whether newline counts as white space
peekRune int // one-rune lookahead
atEOF bool // already read EOF
maxWid int // max width of field, in runes
widPresent bool // width was specified
wid int // width consumed so far; used in accept()
@ -150,11 +153,12 @@ func (s *ss) Width() (wid int, ok bool) {
return s.maxWid, s.widPresent
}
const EOF = -1
// The public method returns an error; this private one panics.
// If getRune reaches EOF, the return value is EOF (-1).
func (s *ss) getRune() (rune int) {
if s.atEOF {
return EOF
}
if s.peekRune >= 0 {
rune = s.peekRune
s.peekRune = -1
@ -163,6 +167,7 @@ func (s *ss) getRune() (rune int) {
rune, _, err := s.rr.ReadRune()
if err != nil {
if err == os.EOF {
s.atEOF = true
return EOF
}
s.error(err)
@ -174,6 +179,9 @@ func (s *ss) getRune() (rune int) {
// It is called in cases such as string scanning where an EOF is a
// syntax error.
func (s *ss) mustGetRune() (rune int) {
if s.atEOF {
s.error(io.ErrUnexpectedEOF)
}
if s.peekRune >= 0 {
rune = s.peekRune
s.peekRune = -1
@ -291,6 +299,7 @@ func newScanState(r io.Reader, nlIsSpace bool) *ss {
}
s.nlIsSpace = nlIsSpace
s.peekRune = -1
s.atEOF = false
s.maxWid = 0
s.widPresent = false
return s

View File

@ -493,3 +493,45 @@ func TestScanlnWithMiddleNewline(t *testing.T) {
t.Errorf("expected newline error scanning string with extra newline, got: %s", err)
}
}
// Special Reader that counts reads at end of file.
type eofCounter struct {
reader *strings.Reader
eofCount int
}
func (ec *eofCounter) Read(b []byte) (n int, err os.Error) {
n, err = ec.reader.Read(b)
if n == 0 {
ec.eofCount++
}
return
}
// Verify that when we scan, we see at most EOF once per call to a Scan function,
// and then only when it's really an EOF
func TestEOF(t *testing.T) {
ec := &eofCounter{strings.NewReader("123\n"), 0}
var a int
n, err := Fscanln(ec, &a)
if err != nil {
t.Error("unexpected error", err)
}
if n != 1 {
t.Error("expected to scan one item, got", n)
}
if ec.eofCount != 0 {
t.Error("expected zero EOFs", ec.eofCount)
ec.eofCount = 0 // reset for next test
}
n, err = Fscanln(ec, &a)
if err == nil {
t.Error("expected error scanning empty string")
}
if n != 0 {
t.Error("expected to scan zero items, got", n)
}
if ec.eofCount != 1 {
t.Error("expected one EOF, got", ec.eofCount)
}
}