All arguments to be scanned must be either pointers to basic
types or implementations of the Scanner interface.
- Note: Fscan etc. can read one character past the input
- they return, which means that a loop calling a scan routine
- may skip some of the input. This is usually a problem only
- when there is no space between input values.
+ Note: Fscan etc. can read one character (rune) past the
+ input they return, which means that a loop calling a scan
+ routine may skip some of the input. This is usually a
+ problem only when there is no space between input values.
+ However, if the reader provided to Fscan implements UnreadRune,
+ that method will be used to save the character and successive
+ calls will not lose data. To attach an UnreadRune method
+ to a reader without that capability, use bufio.NewReader.
*/
package fmt
ReadRune() (rune int, size int, err os.Error)
}
+// unreadRuner is the interface to something that can unread runes.
+// If the object provided to Scan does not satisfy this interface,
+// a local buffer will be used to back up the input, but its contents
+// will be lost when Scan returns.
+type unreadRuner interface {
+ UnreadRune() os.Error
+}
+
// ScanState represents the scanner state passed to custom scanners.
// Scanners may do rune-at-a-time scanning or ask the ScanState
// to discover the next space-delimited token.
// GetRune reads the next rune (Unicode code point) from the input.
GetRune() (rune int, err os.Error)
// UngetRune causes the next call to GetRune to return the rune.
- UngetRune(rune int)
+ UngetRune()
// Width returns the value of the width option and whether it has been set.
// The unit is Unicode code points.
Width() (wid int, ok bool)
buf bytes.Buffer // token accumulator
nlIsSpace bool // whether newline counts as white space
peekRune int // one-rune lookahead
+ prevRune int // last rune returned by GetRune
atEOF bool // already read EOF
maxWid int // max width of field, in runes
widPresent bool // width was specified
func (s *ss) GetRune() (rune int, err os.Error) {
if s.peekRune >= 0 {
rune = s.peekRune
+ s.prevRune = rune
s.peekRune = -1
return
}
rune, _, err = s.rr.ReadRune()
+ if err == nil {
+ s.prevRune = rune
+ }
return
}
}
if s.peekRune >= 0 {
rune = s.peekRune
+ s.prevRune = rune
s.peekRune = -1
return
}
rune, _, err := s.rr.ReadRune()
- if err != nil {
+ if err == nil {
+ s.prevRune = rune
+ } else if err != nil {
if err == os.EOF {
s.atEOF = true
return EOF
}
-func (s *ss) UngetRune(rune int) {
- s.peekRune = rune
+func (s *ss) UngetRune() {
+ if u, ok := s.rr.(unreadRuner); ok {
+ u.UnreadRune()
+ } else {
+ s.peekRune = s.prevRune
+ }
}
func (s *ss) error(err os.Error) {
return
}
if !unicode.IsSpace(rune) {
- s.UngetRune(rune)
+ s.UngetRune()
break
}
}
break
}
if unicode.IsSpace(rune) {
- s.UngetRune(rune)
+ s.UngetRune()
break
}
s.buf.WriteRune(rune)
}
}
if rune != EOF {
- s.UngetRune(rune)
+ s.UngetRune()
}
return false
}
return
}
if unicode.IsSpace(rune1) {
- s.UngetRune(rune1)
+ s.UngetRune()
return
}
rune2 := s.mustGetRune()
}
inputc := s.mustGetRune()
if fmtc != inputc {
- s.UngetRune(inputc)
+ s.UngetRune()
return -1
}
i += w
package fmt_test
import (
+ "bufio"
. "fmt"
"io"
"os"
t.Error("expected one EOF, got", ec.eofCount)
}
}
+
+// Verify that, at least when using bufio, successive calls to Fscan do not lose runes.
+func TestUnreadRuneWithBufio(t *testing.T) {
+ r := bufio.NewReader(strings.NewReader("123αb"))
+ var i int
+ var a string
+ n, err := Fscanf(r, "%d", &i)
+ if n != 1 || err != nil {
+ t.Errorf("reading int expected one item, no errors; got %d %q", n, err)
+ }
+ if i != 123 {
+ t.Errorf("expected 123; got %d", i)
+ }
+ n, err = Fscanf(r, "%s", &a)
+ if n != 1 || err != nil {
+ t.Errorf("reading string expected one item, no errors; got %d %q", n, err)
+ }
+ if a != "αb" {
+ t.Errorf("expected αb; got %q", a)
+ }
+}