Commit 81bfbe93 authored by Roger Peppe's avatar Roger Peppe Committed by Rob Pike

fmt: allow recursive calls to Fscan etc.

Add a new Read method to ScanState so that it
satisfies the io.Reader interface; rename
Getrune and Ungetrune to ReadRune and UnreadRune.
Make sure ReadRune does not read past width restrictions;
remove now-unnecessary Width method from ScanState.
Also make the documentation a little clearer as to
how ReadRune and UnreadRune are used.

R=r, r2
CC=golang-dev
https://golang.org/cl/4240056
parent 324cc3d0
...@@ -164,13 +164,15 @@ ...@@ -164,13 +164,15 @@
All arguments to be scanned must be either pointers to basic All arguments to be scanned must be either pointers to basic
types or implementations of the Scanner interface. types or implementations of the Scanner interface.
Note: Fscan etc. can read one character (rune) past the Note: Fscan etc. can read one character (rune) past the input
input they return, which means that a loop calling a scan they return, which means that a loop calling a scan routine
routine may skip some of the input. This is usually a may skip some of the input. This is usually a problem only
problem only when there is no space between input values. when there is no space between input values. If the reader
However, if the reader provided to Fscan implements UnreadRune, provided to Fscan implements ReadRune, that method will be used
to read characters. If the reader also implements UnreadRune,
that method will be used to save the character and successive that method will be used to save the character and successive
calls will not lose data. To attach an UnreadRune method calls will not lose data. To attach ReadRune and UnreadRune
to a reader without that capability, use bufio.NewReader. methods to a reader without that capability, use
bufio.NewReader.
*/ */
package fmt package fmt
This diff is collapsed.
...@@ -87,21 +87,7 @@ type FloatTest struct { ...@@ -87,21 +87,7 @@ type FloatTest struct {
type Xs string type Xs string
func (x *Xs) Scan(state ScanState, verb int) os.Error { func (x *Xs) Scan(state ScanState, verb int) os.Error {
var tok string tok, err := state.Token()
var c int
var err os.Error
wid, present := state.Width()
if !present {
tok, err = state.Token()
} else {
for i := 0; i < wid; i++ {
c, err = state.GetRune()
if err != nil {
break
}
tok += string(c)
}
}
if err != nil { if err != nil {
return err return err
} }
...@@ -114,6 +100,26 @@ func (x *Xs) Scan(state ScanState, verb int) os.Error { ...@@ -114,6 +100,26 @@ func (x *Xs) Scan(state ScanState, verb int) os.Error {
var xVal Xs var xVal Xs
// IntString accepts an integer followed immediately by a string.
// It tests the embedding of a scan within a scan.
type IntString struct {
i int
s string
}
func (s *IntString) Scan(state ScanState, verb int) os.Error {
if _, err := Fscan(state, &s.i); err != nil {
return err
}
if _, err := Fscan(state, &s.s); err != nil {
return err
}
return nil
}
var intStringVal IntString
// myStringReader implements Read but not ReadRune, allowing us to test our readRune wrapper // myStringReader implements Read but not ReadRune, allowing us to test our readRune wrapper
// type that creates something that can read runes given only Read(). // type that creates something that can read runes given only Read().
type myStringReader struct { type myStringReader struct {
...@@ -200,8 +206,9 @@ var scanTests = []ScanTest{ ...@@ -200,8 +206,9 @@ var scanTests = []ScanTest{
{"114\n", &renamedStringVal, renamedString("114")}, {"114\n", &renamedStringVal, renamedString("114")},
{"115\n", &renamedBytesVal, renamedBytes([]byte("115"))}, {"115\n", &renamedBytesVal, renamedBytes([]byte("115"))},
// Custom scanner. // Custom scanners.
{" vvv ", &xVal, Xs("vvv")}, {" vvv ", &xVal, Xs("vvv")},
{" 1234hello", &intStringVal, IntString{1234, "hello"}},
// Fixed bugs // Fixed bugs
{"2147483648\n", &int64Val, int64(2147483648)}, // was: integer overflow {"2147483648\n", &int64Val, int64(2147483648)}, // was: integer overflow
...@@ -308,6 +315,7 @@ var f float64 ...@@ -308,6 +315,7 @@ var f float64
var s, t string var s, t string
var c complex128 var c complex128
var x, y Xs var x, y Xs
var z IntString
var multiTests = []ScanfMultiTest{ var multiTests = []ScanfMultiTest{
{"", "", nil, nil, ""}, {"", "", nil, nil, ""},
...@@ -321,8 +329,9 @@ var multiTests = []ScanfMultiTest{ ...@@ -321,8 +329,9 @@ var multiTests = []ScanfMultiTest{
{"%d%s", "123abc", args(&i, &s), args(123, "abc"), ""}, {"%d%s", "123abc", args(&i, &s), args(123, "abc"), ""},
{"%c%c%c", "2\u50c2X", args(&i, &j, &k), args('2', '\u50c2', 'X'), ""}, {"%c%c%c", "2\u50c2X", args(&i, &j, &k), args('2', '\u50c2', 'X'), ""},
// Custom scanner. // Custom scanners.
{"%2e%f", "eefffff", args(&x, &y), args(Xs("ee"), Xs("fffff")), ""}, {"%2e%f", "eefffff", args(&x, &y), args(Xs("ee"), Xs("fffff")), ""},
{"%4v%s", "12abcd", args(&z, &s), args(IntString{12, "ab"}, "cd"), ""},
// Errors // Errors
{"%t", "23 18", args(&i), nil, "bad verb"}, {"%t", "23 18", args(&i), nil, "bad verb"},
...@@ -345,7 +354,11 @@ func testScan(name string, t *testing.T, scan func(r io.Reader, a ...interface{} ...@@ -345,7 +354,11 @@ func testScan(name string, t *testing.T, scan func(r io.Reader, a ...interface{}
} }
n, err := scan(r, test.in) n, err := scan(r, test.in)
if err != nil { if err != nil {
t.Errorf("%s got error scanning %q: %s", name, test.text, err) m := ""
if n > 0 {
m = Sprintf(" (%d fields ok)", n)
}
t.Errorf("%s got error scanning %q: %s%s", name, test.text, err, m)
continue continue
} }
if n != 1 { if n != 1 {
...@@ -681,7 +694,7 @@ type TwoLines string ...@@ -681,7 +694,7 @@ type TwoLines string
func (t *TwoLines) Scan(state ScanState, verb int) os.Error { func (t *TwoLines) Scan(state ScanState, verb int) os.Error {
chars := make([]int, 0, 100) chars := make([]int, 0, 100)
for nlCount := 0; nlCount < 2; { for nlCount := 0; nlCount < 2; {
c, err := state.GetRune() c, _, err := state.ReadRune()
if err != nil { if err != nil {
return err return err
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment