summaryrefslogtreecommitdiff
path: root/src/pkg/fmt
diff options
context:
space:
mode:
Diffstat (limited to 'src/pkg/fmt')
-rw-r--r--src/pkg/fmt/doc.go29
-rw-r--r--src/pkg/fmt/fmt_test.go196
-rw-r--r--src/pkg/fmt/format.go105
-rw-r--r--src/pkg/fmt/print.go417
-rw-r--r--src/pkg/fmt/scan.go208
-rw-r--r--src/pkg/fmt/scan_test.go77
6 files changed, 590 insertions, 442 deletions
diff --git a/src/pkg/fmt/doc.go b/src/pkg/fmt/doc.go
index 35a11e19f..7d4178da7 100644
--- a/src/pkg/fmt/doc.go
+++ b/src/pkg/fmt/doc.go
@@ -30,8 +30,9 @@
%X base 16, with upper-case letters for A-F
%U Unicode format: U+1234; same as "U+%04X"
Floating-point and complex constituents:
- %b decimalless scientific notation with exponent a power
- of two, in the manner of strconv.Ftoa32, e.g. -123456p-78
+ %b decimalless scientific notation with exponent a power of two,
+ in the manner of strconv.FormatFloat with the 'b' format,
+ e.g. -123456p-78
%e scientific notation, e.g. -1234.456e+78
%E scientific notation, e.g. -1234.456E+78
%f decimal point but no exponent, e.g. 123.456
@@ -89,14 +90,22 @@
If an operand implements interface Formatter, that interface
can be used for fine control of formatting.
- If an operand implements method String() string that method
+ If the format (which is implicitly %v for Println etc.) is valid
+ for a string (%s %q %v %x %X), the following two rules also apply:
+
+ 1. If an operand implements the error interface, the Error method
+ will be used to convert the object to a string, which will then
+ be formatted as required by the verb (if any).
+
+ 2. If an operand implements method String() string, that method
will be used to convert the object to a string, which will then
- be formatted as required by the verb (if any). To avoid
- recursion in cases such as
- type X int
- func (x X) String() string { return Sprintf("%d", x) }
- cast the value before recurring:
- func (x X) String() string { return Sprintf("%d", int(x)) }
+ be formatted as required by the verb (if any).
+
+ To avoid recursion in cases such as
+ type X string
+ func (x X) String() string { return Sprintf("<%s>", x) }
+ convert the value before recurring:
+ func (x X) String() string { return Sprintf("<%s>", string(x)) }
Format errors:
@@ -122,7 +131,7 @@
An analogous set of functions scans formatted text to yield
values. Scan, Scanf and Scanln read from os.Stdin; Fscan,
- Fscanf and Fscanln read from a specified os.Reader; Sscan,
+ Fscanf and Fscanln read from a specified io.Reader; Sscan,
Sscanf and Sscanln read from an argument string. Scanln,
Fscanln and Sscanln stop scanning at a newline and require that
the items be followed by one; Sscanf, Fscanf and Sscanf require
diff --git a/src/pkg/fmt/fmt_test.go b/src/pkg/fmt/fmt_test.go
index b1ad34518..2f92f947c 100644
--- a/src/pkg/fmt/fmt_test.go
+++ b/src/pkg/fmt/fmt_test.go
@@ -12,6 +12,7 @@ import (
"runtime" // for the malloc count test only
"strings"
"testing"
+ "time"
)
type (
@@ -47,8 +48,10 @@ func TestFmtInterface(t *testing.T) {
const b32 uint32 = 1<<32 - 1
const b64 uint64 = 1<<64 - 1
-var array = []int{1, 2, 3, 4, 5}
-var iarray = []interface{}{1, "hello", 2.5, nil}
+var array = [5]int{1, 2, 3, 4, 5}
+var iarray = [4]interface{}{1, "hello", 2.5, nil}
+var slice = array[:]
+var islice = iarray[:]
type A struct {
i int
@@ -62,7 +65,7 @@ type I int
func (i I) String() string { return Sprintf("<%d>", int(i)) }
type B struct {
- i I
+ I I
j int
}
@@ -73,7 +76,7 @@ type C struct {
type F int
-func (f F) Format(s State, c int) {
+func (f F) Format(s State, c rune) {
Fprintf(s, "<%c=F(%d)>", c, int(f))
}
@@ -84,8 +87,12 @@ func (g G) GoString() string {
}
type S struct {
- f F // a struct field that Formats
- g G // a struct field that GoStrings
+ F F // a struct field that Formats
+ G G // a struct field that GoStrings
+}
+
+type SI struct {
+ I interface{}
}
// A type with a String method with pointer receiver for testing %p
@@ -323,6 +330,12 @@ var fmttests = []struct {
{"%v", &array, "&[1 2 3 4 5]"},
{"%v", &iarray, "&[1 hello 2.5 <nil>]"},
+ // slices
+ {"%v", slice, "[1 2 3 4 5]"},
+ {"%v", islice, "[1 hello 2.5 <nil>]"},
+ {"%v", &slice, "&[1 2 3 4 5]"},
+ {"%v", &islice, "&[1 hello 2.5 <nil>]"},
+
// complexes with %v
{"%v", 1 + 2i, "(1+2i)"},
{"%v", complex64(1 + 2i), "(1+2i)"},
@@ -333,14 +346,14 @@ var fmttests = []struct {
{"%+v", A{1, 2, "a", []int{1, 2}}, `{i:1 j:2 s:a x:[1 2]}`},
// +v on structs with Stringable items
- {"%+v", B{1, 2}, `{i:<1> j:2}`},
- {"%+v", C{1, B{2, 3}}, `{i:1 B:{i:<2> j:3}}`},
+ {"%+v", B{1, 2}, `{I:<1> j:2}`},
+ {"%+v", C{1, B{2, 3}}, `{i:1 B:{I:<2> j:3}}`},
// q on Stringable items
{"%s", I(23), `<23>`},
{"%q", I(23), `"<23>"`},
{"%x", I(23), `3c32333e`},
- {"%d", I(23), `%!d(string=<23>)`},
+ {"%d", I(23), `23`}, // Stringer applies only to string formats.
// go syntax
{"%#v", A{1, 2, "a", []int{1, 2}}, `fmt_test.A{i:1, j:0x2, s:"a", x:[]int{1, 2}}`},
@@ -349,9 +362,18 @@ var fmttests = []struct {
{"%#v", make(chan int), "(chan int)(0xPTR)"},
{"%#v", uint64(1<<64 - 1), "0xffffffffffffffff"},
{"%#v", 1000000000, "1000000000"},
- {"%#v", map[string]int{"a": 1, "b": 2}, `map[string] int{"a":1, "b":2}`},
- {"%#v", map[string]B{"a": {1, 2}, "b": {3, 4}}, `map[string] fmt_test.B{"a":fmt_test.B{i:1, j:2}, "b":fmt_test.B{i:3, j:4}}`},
+ {"%#v", map[string]int{"a": 1}, `map[string]int{"a":1}`},
+ {"%#v", map[string]B{"a": {1, 2}}, `map[string]fmt_test.B{"a":fmt_test.B{I:1, j:2}}`},
{"%#v", []string{"a", "b"}, `[]string{"a", "b"}`},
+ {"%#v", SI{}, `fmt_test.SI{I:interface {}(nil)}`},
+ {"%#v", []int(nil), `[]int(nil)`},
+ {"%#v", []int{}, `[]int{}`},
+ {"%#v", array, `[5]int{1, 2, 3, 4, 5}`},
+ {"%#v", &array, `&[5]int{1, 2, 3, 4, 5}`},
+ {"%#v", iarray, `[4]interface {}{1, "hello", 2.5, interface {}(nil)}`},
+ {"%#v", &iarray, `&[4]interface {}{1, "hello", 2.5, interface {}(nil)}`},
+ {"%#v", map[int]byte(nil), `map[int]uint8(nil)`},
+ {"%#v", map[int]byte{}, `map[int]uint8{}`},
// slices with other formats
{"%#x", []int{1, 2, 15}, `[0x1 0x2 0xf]`},
@@ -385,11 +407,11 @@ var fmttests = []struct {
// Formatter
{"%x", F(1), "<x=F(1)>"},
{"%x", G(2), "2"},
- {"%+v", S{F(4), G(5)}, "{f:<v=F(4)> g:5}"},
+ {"%+v", S{F(4), G(5)}, "{F:<v=F(4)> G:5}"},
// GoStringer
{"%#v", G(6), "GoString(6)"},
- {"%#v", S{F(7), G(8)}, "fmt_test.S{f:<v=F(7)>, g:GoString(8)}"},
+ {"%#v", S{F(7), G(8)}, "fmt_test.S{F:<v=F(7)>, G:GoString(8)}"},
// %T
{"%T", (4 - 3i), "complex128"},
@@ -409,6 +431,10 @@ var fmttests = []struct {
{"%p", make([]int, 1), "0xPTR"},
{"%p", 27, "%!p(int=27)"}, // not a pointer at all
+ // %d on Stringer should give integer if possible
+ {"%s", time.Time{}.Month(), "January"},
+ {"%d", time.Time{}.Month(), "1"},
+
// erroneous things
{"%s %", "hello", "hello %!(NOVERB)"},
{"%s %.2", "hello", "hello %!(NOVERB)"},
@@ -474,74 +500,52 @@ func BenchmarkSprintfPrefixedInt(b *testing.B) {
}
}
-func TestCountMallocs(t *testing.T) {
- if testing.Short() {
- return
- }
- runtime.UpdateMemStats()
- mallocs := 0 - runtime.MemStats.Mallocs
- for i := 0; i < 100; i++ {
- Sprintf("")
- }
- runtime.UpdateMemStats()
- mallocs += runtime.MemStats.Mallocs
- Printf("mallocs per Sprintf(\"\"): %d\n", mallocs/100)
- runtime.UpdateMemStats()
- mallocs = 0 - runtime.MemStats.Mallocs
- for i := 0; i < 100; i++ {
- Sprintf("xxx")
- }
- runtime.UpdateMemStats()
- mallocs += runtime.MemStats.Mallocs
- Printf("mallocs per Sprintf(\"xxx\"): %d\n", mallocs/100)
- runtime.UpdateMemStats()
- mallocs = 0 - runtime.MemStats.Mallocs
- for i := 0; i < 100; i++ {
- Sprintf("%x", i)
- }
- runtime.UpdateMemStats()
- mallocs += runtime.MemStats.Mallocs
- Printf("mallocs per Sprintf(\"%%x\"): %d\n", mallocs/100)
- runtime.UpdateMemStats()
- mallocs = 0 - runtime.MemStats.Mallocs
- for i := 0; i < 100; i++ {
- Sprintf("%s", "hello")
- }
- runtime.UpdateMemStats()
- mallocs += runtime.MemStats.Mallocs
- Printf("mallocs per Sprintf(\"%%s\"): %d\n", mallocs/100)
- runtime.UpdateMemStats()
- mallocs = 0 - runtime.MemStats.Mallocs
- for i := 0; i < 100; i++ {
- Sprintf("%x %x", i, i)
- }
- runtime.UpdateMemStats()
- mallocs += runtime.MemStats.Mallocs
- Printf("mallocs per Sprintf(\"%%x %%x\"): %d\n", mallocs/100)
- buf := new(bytes.Buffer)
- runtime.UpdateMemStats()
- mallocs = 0 - runtime.MemStats.Mallocs
- for i := 0; i < 100; i++ {
- buf.Reset()
- Fprintf(buf, "%x %x %x", i, i, i)
+func BenchmarkSprintfFloat(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ Sprintf("%g", 5.23184)
}
- runtime.UpdateMemStats()
- mallocs += runtime.MemStats.Mallocs
- Printf("mallocs per Fprintf(buf, \"%%x %%x %%x\"): %d\n", mallocs/100)
- runtime.UpdateMemStats()
- mallocs = 0 - runtime.MemStats.Mallocs
- for i := 0; i < 100; i++ {
- buf.Reset()
- Fprintf(buf, "%s", "hello")
+}
+
+var mallocBuf bytes.Buffer
+
+var mallocTest = []struct {
+ count int
+ desc string
+ fn func()
+}{
+ {0, `Sprintf("")`, func() { Sprintf("") }},
+ {1, `Sprintf("xxx")`, func() { Sprintf("xxx") }},
+ {1, `Sprintf("%x")`, func() { Sprintf("%x", 7) }},
+ {2, `Sprintf("%s")`, func() { Sprintf("%s", "hello") }},
+ {1, `Sprintf("%x %x")`, func() { Sprintf("%x %x", 7, 112) }},
+ // For %g we use a float32, not float64, to guarantee passing the argument
+ // does not need to allocate memory to store the result in a pointer-sized word.
+ {2, `Sprintf("%g")`, func() { Sprintf("%g", float32(3.14159)) }},
+ {0, `Fprintf(buf, "%x %x %x")`, func() { mallocBuf.Reset(); Fprintf(&mallocBuf, "%x %x %x", 7, 8, 9) }},
+ {1, `Fprintf(buf, "%s")`, func() { mallocBuf.Reset(); Fprintf(&mallocBuf, "%s", "hello") }},
+}
+
+var _ bytes.Buffer
+
+func TestCountMallocs(t *testing.T) {
+ for _, mt := range mallocTest {
+ const N = 100
+ runtime.UpdateMemStats()
+ mallocs := 0 - runtime.MemStats.Mallocs
+ for i := 0; i < N; i++ {
+ mt.fn()
+ }
+ runtime.UpdateMemStats()
+ mallocs += runtime.MemStats.Mallocs
+ if mallocs/N > uint64(mt.count) {
+ t.Errorf("%s: expected %d mallocs, got %d", mt.desc, mt.count, mallocs/N)
+ }
}
- runtime.UpdateMemStats()
- mallocs += runtime.MemStats.Mallocs
- Printf("mallocs per Fprintf(buf, \"%%s\"): %d\n", mallocs/100)
}
type flagPrinter struct{}
-func (*flagPrinter) Format(f State, c int) {
+func (*flagPrinter) Format(f State, c rune) {
s := "%"
for i := 0; i < 128; i++ {
if f.Flag(i) {
@@ -741,7 +745,7 @@ type PanicF struct {
}
// Value receiver.
-func (p PanicF) Format(f State, c int) {
+func (p PanicF) Format(f State, c rune) {
panic(p.message)
}
@@ -751,9 +755,9 @@ var panictests = []struct {
out string
}{
// String
- {"%d", (*Panic)(nil), "<nil>"}, // nil pointer special case
- {"%d", Panic{io.ErrUnexpectedEOF}, "%d(PANIC=unexpected EOF)"},
- {"%d", Panic{3}, "%d(PANIC=3)"},
+ {"%s", (*Panic)(nil), "<nil>"}, // nil pointer special case
+ {"%s", Panic{io.ErrUnexpectedEOF}, "%s(PANIC=unexpected EOF)"},
+ {"%s", Panic{3}, "%s(PANIC=3)"},
// GoString
{"%#v", (*Panic)(nil), "<nil>"}, // nil pointer special case
{"%#v", Panic{io.ErrUnexpectedEOF}, "%v(PANIC=unexpected EOF)"},
@@ -772,3 +776,37 @@ func TestPanics(t *testing.T) {
}
}
}
+
+// Test that erroneous String routine doesn't cause fatal recursion.
+var recurCount = 0
+
+type Recur struct {
+ i int
+ failed *bool
+}
+
+func (r Recur) String() string {
+ if recurCount++; recurCount > 10 {
+ *r.failed = true
+ return "FAIL"
+ }
+ // This will call badVerb. Before the fix, that would cause us to recur into
+ // this routine to print %!p(value). Now we don't call the user's method
+ // during an error.
+ return Sprintf("recur@%p value: %d", r, r.i)
+}
+
+func TestBadVerbRecursion(t *testing.T) {
+ failed := false
+ r := Recur{3, &failed}
+ Sprintf("recur@%p value: %d\n", &r, r.i)
+ if failed {
+ t.Error("fail with pointer")
+ }
+ failed = false
+ r = Recur{4, &failed}
+ Sprintf("recur@%p, value: %d\n", r, r.i)
+ if failed {
+ t.Error("fail with value")
+ }
+}
diff --git a/src/pkg/fmt/format.go b/src/pkg/fmt/format.go
index 24b15a286..78d9e998b 100644
--- a/src/pkg/fmt/format.go
+++ b/src/pkg/fmt/format.go
@@ -8,7 +8,7 @@ import (
"bytes"
"strconv"
"unicode"
- "utf8"
+ "unicode/utf8"
)
const (
@@ -154,12 +154,17 @@ func putint(buf []byte, base, val uint64, digits string) int {
return i - 1
}
+var (
+ trueBytes = []byte("true")
+ falseBytes = []byte("false")
+)
+
// fmt_boolean formats a boolean.
func (f *fmt) fmt_boolean(v bool) {
if v {
- f.padString("true")
+ f.pad(trueBytes)
} else {
- f.padString("false")
+ f.pad(falseBytes)
}
}
@@ -242,8 +247,8 @@ func (f *fmt) integer(a int64, base uint64, signedness bool, digits string) {
}
// If we want a quoted char for %#U, move the data up to make room.
- if f.unicode && f.uniQuote && a >= 0 && a <= unicode.MaxRune && unicode.IsPrint(int(a)) {
- runeWidth := utf8.RuneLen(int(a))
+ if f.unicode && f.uniQuote && a >= 0 && a <= unicode.MaxRune && unicode.IsPrint(rune(a)) {
+ runeWidth := utf8.RuneLen(rune(a))
width := 1 + 1 + runeWidth + 1 // space, quote, rune, quote
copy(buf[i-width:], buf[i:]) // guaranteed to have enough room.
i -= width
@@ -253,7 +258,7 @@ func (f *fmt) integer(a int64, base uint64, signedness bool, digits string) {
j++
buf[j] = '\''
j++
- utf8.EncodeRune(buf[j:], int(a))
+ utf8.EncodeRune(buf[j:], rune(a))
j += runeWidth
buf[j] = '\''
}
@@ -283,31 +288,18 @@ func (f *fmt) fmt_s(s string) {
}
// fmt_sx formats a string as a hexadecimal encoding of its bytes.
-func (f *fmt) fmt_sx(s string) {
- t := ""
+func (f *fmt) fmt_sx(s, digits string) {
+ // TODO: Avoid buffer by pre-padding.
+ var b bytes.Buffer
for i := 0; i < len(s); i++ {
if i > 0 && f.space {
- t += " "
+ b.WriteByte(' ')
}
v := s[i]
- t += string(ldigits[v>>4])
- t += string(ldigits[v&0xF])
+ b.WriteByte(digits[v>>4])
+ b.WriteByte(digits[v&0xF])
}
- f.padString(t)
-}
-
-// fmt_sX formats a string as an uppercase hexadecimal encoding of its bytes.
-func (f *fmt) fmt_sX(s string) {
- t := ""
- for i := 0; i < len(s); i++ {
- if i > 0 && f.space {
- t += " "
- }
- v := s[i]
- t += string(udigits[v>>4])
- t += string(udigits[v&0xF])
- }
- f.padString(t)
+ f.pad(b.Bytes())
}
// fmt_q formats a string as a double-quoted, escaped Go string constant.
@@ -329,13 +321,13 @@ func (f *fmt) fmt_q(s string) {
// fmt_qc formats the integer as a single-quoted, escaped Go character constant.
// If the character is not valid Unicode, it will print '\ufffd'.
func (f *fmt) fmt_qc(c int64) {
- var quoted string
+ var quoted []byte
if f.plus {
- quoted = strconv.QuoteRuneToASCII(int(c))
+ quoted = strconv.AppendQuoteRuneToASCII(f.intbuf[0:0], rune(c))
} else {
- quoted = strconv.QuoteRune(int(c))
+ quoted = strconv.AppendQuoteRune(f.intbuf[0:0], rune(c))
}
- f.padString(quoted)
+ f.pad(quoted)
}
// floating-point
@@ -347,60 +339,73 @@ func doPrec(f *fmt, def int) int {
return def
}
-// Add a plus sign or space to the floating-point string representation if missing and required.
-func (f *fmt) plusSpace(s string) {
- if s[0] != '-' {
+// formatFloat formats a float64; it is an efficient equivalent to f.pad(strconv.FormatFloat()...).
+func (f *fmt) formatFloat(v float64, verb byte, prec, n int) {
+ // We leave one byte at the beginning of f.intbuf for a sign if needed,
+ // and make it a space, which we might be able to use.
+ f.intbuf[0] = ' '
+ slice := strconv.AppendFloat(f.intbuf[0:1], v, verb, prec, n)
+ // Add a plus sign or space to the floating-point string representation if missing and required.
+ // The formatted number starts at slice[1].
+ switch slice[1] {
+ case '-', '+':
+ // We're set; drop the leading space.
+ slice = slice[1:]
+ default:
+ // There's no sign, but we might need one.
if f.plus {
- s = "+" + s
+ slice[0] = '+'
} else if f.space {
- s = " " + s
+ // space is already there
+ } else {
+ slice = slice[1:]
}
}
- f.padString(s)
+ f.pad(slice)
}
// fmt_e64 formats a float64 in the form -1.23e+12.
-func (f *fmt) fmt_e64(v float64) { f.plusSpace(strconv.Ftoa64(v, 'e', doPrec(f, 6))) }
+func (f *fmt) fmt_e64(v float64) { f.formatFloat(v, 'e', doPrec(f, 6), 64) }
// fmt_E64 formats a float64 in the form -1.23E+12.
-func (f *fmt) fmt_E64(v float64) { f.plusSpace(strconv.Ftoa64(v, 'E', doPrec(f, 6))) }
+func (f *fmt) fmt_E64(v float64) { f.formatFloat(v, 'E', doPrec(f, 6), 64) }
// fmt_f64 formats a float64 in the form -1.23.
-func (f *fmt) fmt_f64(v float64) { f.plusSpace(strconv.Ftoa64(v, 'f', doPrec(f, 6))) }
+func (f *fmt) fmt_f64(v float64) { f.formatFloat(v, 'f', doPrec(f, 6), 64) }
// fmt_g64 formats a float64 in the 'f' or 'e' form according to size.
-func (f *fmt) fmt_g64(v float64) { f.plusSpace(strconv.Ftoa64(v, 'g', doPrec(f, -1))) }
+func (f *fmt) fmt_g64(v float64) { f.formatFloat(v, 'g', doPrec(f, -1), 64) }
// fmt_g64 formats a float64 in the 'f' or 'E' form according to size.
-func (f *fmt) fmt_G64(v float64) { f.plusSpace(strconv.Ftoa64(v, 'G', doPrec(f, -1))) }
+func (f *fmt) fmt_G64(v float64) { f.formatFloat(v, 'G', doPrec(f, -1), 64) }
// fmt_fb64 formats a float64 in the form -123p3 (exponent is power of 2).
-func (f *fmt) fmt_fb64(v float64) { f.plusSpace(strconv.Ftoa64(v, 'b', 0)) }
+func (f *fmt) fmt_fb64(v float64) { f.formatFloat(v, 'b', 0, 64) }
// float32
// cannot defer to float64 versions
// because it will get rounding wrong in corner cases.
// fmt_e32 formats a float32 in the form -1.23e+12.
-func (f *fmt) fmt_e32(v float32) { f.plusSpace(strconv.Ftoa32(v, 'e', doPrec(f, 6))) }
+func (f *fmt) fmt_e32(v float32) { f.formatFloat(float64(v), 'e', doPrec(f, 6), 32) }
// fmt_E32 formats a float32 in the form -1.23E+12.
-func (f *fmt) fmt_E32(v float32) { f.plusSpace(strconv.Ftoa32(v, 'E', doPrec(f, 6))) }
+func (f *fmt) fmt_E32(v float32) { f.formatFloat(float64(v), 'E', doPrec(f, 6), 32) }
// fmt_f32 formats a float32 in the form -1.23.
-func (f *fmt) fmt_f32(v float32) { f.plusSpace(strconv.Ftoa32(v, 'f', doPrec(f, 6))) }
+func (f *fmt) fmt_f32(v float32) { f.formatFloat(float64(v), 'f', doPrec(f, 6), 32) }
// fmt_g32 formats a float32 in the 'f' or 'e' form according to size.
-func (f *fmt) fmt_g32(v float32) { f.plusSpace(strconv.Ftoa32(v, 'g', doPrec(f, -1))) }
+func (f *fmt) fmt_g32(v float32) { f.formatFloat(float64(v), 'g', doPrec(f, -1), 32) }
// fmt_G32 formats a float32 in the 'f' or 'E' form according to size.
-func (f *fmt) fmt_G32(v float32) { f.plusSpace(strconv.Ftoa32(v, 'G', doPrec(f, -1))) }
+func (f *fmt) fmt_G32(v float32) { f.formatFloat(float64(v), 'G', doPrec(f, -1), 32) }
// fmt_fb32 formats a float32 in the form -123p3 (exponent is power of 2).
-func (f *fmt) fmt_fb32(v float32) { f.padString(strconv.Ftoa32(v, 'b', 0)) }
+func (f *fmt) fmt_fb32(v float32) { f.formatFloat(float64(v), 'b', 0, 32) }
// fmt_c64 formats a complex64 according to the verb.
-func (f *fmt) fmt_c64(v complex64, verb int) {
+func (f *fmt) fmt_c64(v complex64, verb rune) {
f.buf.WriteByte('(')
r := real(v)
for i := 0; ; i++ {
@@ -426,7 +431,7 @@ func (f *fmt) fmt_c64(v complex64, verb int) {
}
// fmt_c128 formats a complex128 according to the verb.
-func (f *fmt) fmt_c128(v complex128, verb int) {
+func (f *fmt) fmt_c128(v complex128, verb rune) {
f.buf.WriteByte('(')
r := real(v)
for i := 0; ; i++ {
diff --git a/src/pkg/fmt/print.go b/src/pkg/fmt/print.go
index 738734908..3b7d3464e 100644
--- a/src/pkg/fmt/print.go
+++ b/src/pkg/fmt/print.go
@@ -6,11 +6,13 @@ package fmt
import (
"bytes"
+ "errors"
"io"
"os"
"reflect"
+ "sync"
"unicode"
- "utf8"
+ "unicode/utf8"
)
// Some constants in the form of bytes, to avoid string overhead.
@@ -36,7 +38,7 @@ var (
// the flags and options for the operand's format specifier.
type State interface {
// Write is the function to call to emit formatted output to be printed.
- Write(b []byte) (ret int, err os.Error)
+ Write(b []byte) (ret int, err error)
// Width returns the value of the width option and whether it has been set.
Width() (wid int, ok bool)
// Precision returns the value of the precision option and whether it has been set.
@@ -50,7 +52,7 @@ type State interface {
// The implementation of Format may call Sprintf or Fprintf(f) etc.
// to generate its output.
type Formatter interface {
- Format(f State, c int)
+ Format(f State, c rune)
}
// Stringer is implemented by any value that has a String method,
@@ -72,40 +74,49 @@ type GoStringer interface {
type pp struct {
n int
panicking bool
+ erroring bool // printing an error condition
buf bytes.Buffer
- runeBuf [utf8.UTFMax]byte
- fmt fmt
+ // field holds the current item, as an interface{}.
+ field interface{}
+ // value holds the current item, as a reflect.Value, and will be
+ // the zero Value if the item has not been reflected.
+ value reflect.Value
+ runeBuf [utf8.UTFMax]byte
+ fmt fmt
}
// A cache holds a set of reusable objects.
-// The buffered channel holds the currently available objects.
+// The slice is a stack (LIFO).
// If more are needed, the cache creates them by calling new.
type cache struct {
- saved chan interface{}
+ mu sync.Mutex
+ saved []interface{}
new func() interface{}
}
func (c *cache) put(x interface{}) {
- select {
- case c.saved <- x:
- // saved in cache
- default:
- // discard
+ c.mu.Lock()
+ if len(c.saved) < cap(c.saved) {
+ c.saved = append(c.saved, x)
}
+ c.mu.Unlock()
}
func (c *cache) get() interface{} {
- select {
- case x := <-c.saved:
- return x // reused from cache
- default:
+ c.mu.Lock()
+ n := len(c.saved)
+ if n == 0 {
+ c.mu.Unlock()
return c.new()
}
- panic("not reached")
+ x := c.saved[n-1]
+ c.saved = c.saved[0 : n-1]
+ c.mu.Unlock()
+ return x
}
func newCache(f func() interface{}) *cache {
- return &cache{make(chan interface{}, 100), f}
+ return &cache{saved: make([]interface{}, 0, 100), new: f}
}
var ppFree = newCache(func() interface{} { return new(pp) })
@@ -114,6 +125,7 @@ var ppFree = newCache(func() interface{} { return new(pp) })
func newPrinter() *pp {
p := ppFree.get().(*pp)
p.panicking = false
+ p.erroring = false
p.fmt.init(&p.buf)
return p
}
@@ -125,6 +137,8 @@ func (p *pp) free() {
return
}
p.buf.Reset()
+ p.field = nil
+ p.value = reflect.Value{}
ppFree.put(p)
}
@@ -148,13 +162,13 @@ func (p *pp) Flag(b int) bool {
return false
}
-func (p *pp) add(c int) {
+func (p *pp) add(c rune) {
p.buf.WriteRune(c)
}
// Implement Write so we can call Fprintf on a pp (through State), for
// recursive use in custom verbs.
-func (p *pp) Write(b []byte) (ret int, err os.Error) {
+func (p *pp) Write(b []byte) (ret int, err error) {
return p.buf.Write(b)
}
@@ -162,7 +176,7 @@ func (p *pp) Write(b []byte) (ret int, err os.Error) {
// Fprintf formats according to a format specifier and writes to w.
// It returns the number of bytes written and any write error encountered.
-func Fprintf(w io.Writer, format string, a ...interface{}) (n int, err os.Error) {
+func Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error) {
p := newPrinter()
p.doPrintf(format, a)
n64, err := p.buf.WriteTo(w)
@@ -172,7 +186,7 @@ func Fprintf(w io.Writer, format string, a ...interface{}) (n int, err os.Error)
// Printf formats according to a format specifier and writes to standard output.
// It returns the number of bytes written and any write error encountered.
-func Printf(format string, a ...interface{}) (n int, err os.Error) {
+func Printf(format string, a ...interface{}) (n int, err error) {
return Fprintf(os.Stdout, format, a...)
}
@@ -186,9 +200,9 @@ func Sprintf(format string, a ...interface{}) string {
}
// Errorf formats according to a format specifier and returns the string
-// converted to an os.ErrorString, which satisfies the os.Error interface.
-func Errorf(format string, a ...interface{}) os.Error {
- return os.NewError(Sprintf(format, a...))
+// as a value that satisfies error.
+func Errorf(format string, a ...interface{}) error {
+ return errors.New(Sprintf(format, a...))
}
// These routines do not take a format string
@@ -196,7 +210,7 @@ func Errorf(format string, a ...interface{}) os.Error {
// Fprint formats using the default formats for its operands and writes to w.
// Spaces are added between operands when neither is a string.
// It returns the number of bytes written and any write error encountered.
-func Fprint(w io.Writer, a ...interface{}) (n int, err os.Error) {
+func Fprint(w io.Writer, a ...interface{}) (n int, err error) {
p := newPrinter()
p.doPrint(a, false, false)
n64, err := p.buf.WriteTo(w)
@@ -207,7 +221,7 @@ func Fprint(w io.Writer, a ...interface{}) (n int, err os.Error) {
// Print formats using the default formats for its operands and writes to standard output.
// Spaces are added between operands when neither is a string.
// It returns the number of bytes written and any write error encountered.
-func Print(a ...interface{}) (n int, err os.Error) {
+func Print(a ...interface{}) (n int, err error) {
return Fprint(os.Stdout, a...)
}
@@ -228,7 +242,7 @@ func Sprint(a ...interface{}) string {
// Fprintln formats using the default formats for its operands and writes to w.
// Spaces are always added between operands and a newline is appended.
// It returns the number of bytes written and any write error encountered.
-func Fprintln(w io.Writer, a ...interface{}) (n int, err os.Error) {
+func Fprintln(w io.Writer, a ...interface{}) (n int, err error) {
p := newPrinter()
p.doPrint(a, true, true)
n64, err := p.buf.WriteTo(w)
@@ -239,7 +253,7 @@ func Fprintln(w io.Writer, a ...interface{}) (n int, err os.Error) {
// Println formats using the default formats for its operands and writes to standard output.
// Spaces are always added between operands and a newline is appended.
// It returns the number of bytes written and any write error encountered.
-func Println(a ...interface{}) (n int, err os.Error) {
+func Println(a ...interface{}) (n int, err error) {
return Fprintln(os.Stdout, a...)
}
@@ -258,10 +272,8 @@ func Sprintln(a ...interface{}) string {
// the thing inside the interface, not the interface itself.
func getField(v reflect.Value, i int) reflect.Value {
val := v.Field(i)
- if i := val; i.Kind() == reflect.Interface {
- if inter := i.Interface(); inter != nil {
- return reflect.ValueOf(inter)
- }
+ if val.Kind() == reflect.Interface && !val.IsNil() {
+ val = val.Elem()
}
return val
}
@@ -288,41 +300,48 @@ func (p *pp) unknownType(v interface{}) {
p.buf.WriteByte('?')
}
-func (p *pp) badVerb(verb int, val interface{}) {
+func (p *pp) badVerb(verb rune) {
+ p.erroring = true
p.add('%')
p.add('!')
p.add(verb)
p.add('(')
- if val == nil {
- p.buf.Write(nilAngleBytes)
- } else {
- p.buf.WriteString(reflect.TypeOf(val).String())
+ switch {
+ case p.field != nil:
+ p.buf.WriteString(reflect.TypeOf(p.field).String())
+ p.add('=')
+ p.printField(p.field, 'v', false, false, 0)
+ case p.value.IsValid():
+ p.buf.WriteString(p.value.Type().String())
p.add('=')
- p.printField(val, 'v', false, false, 0)
+ p.printValue(p.value, 'v', false, false, 0)
+ default:
+ p.buf.Write(nilAngleBytes)
}
p.add(')')
+ p.erroring = false
}
-func (p *pp) fmtBool(v bool, verb int, value interface{}) {
+func (p *pp) fmtBool(v bool, verb rune) {
switch verb {
case 't', 'v':
p.fmt.fmt_boolean(v)
default:
- p.badVerb(verb, value)
+ p.badVerb(verb)
}
}
// fmtC formats a rune for the 'c' format.
func (p *pp) fmtC(c int64) {
- rune := int(c) // Check for overflow.
- if int64(rune) != c {
- rune = utf8.RuneError
+ r := rune(c) // Check for overflow.
+ if int64(r) != c {
+ r = utf8.RuneError
}
- w := utf8.EncodeRune(p.runeBuf[0:utf8.UTFMax], rune)
+ w := utf8.EncodeRune(p.runeBuf[0:utf8.UTFMax], r)
p.fmt.pad(p.runeBuf[0:w])
}
-func (p *pp) fmtInt64(v int64, verb int, value interface{}) {
+func (p *pp) fmtInt64(v int64, verb rune) {
switch verb {
case 'b':
p.fmt.integer(v, 2, signed, ldigits)
@@ -336,7 +355,7 @@ func (p *pp) fmtInt64(v int64, verb int, value interface{}) {
if 0 <= v && v <= unicode.MaxRune {
p.fmt.fmt_qc(v)
} else {
- p.badVerb(verb, value)
+ p.badVerb(verb)
}
case 'x':
p.fmt.integer(v, 16, signed, ldigits)
@@ -345,7 +364,7 @@ func (p *pp) fmtInt64(v int64, verb int, value interface{}) {
case 'X':
p.fmt.integer(v, 16, signed, udigits)
default:
- p.badVerb(verb, value)
+ p.badVerb(verb)
}
}
@@ -380,7 +399,7 @@ func (p *pp) fmtUnicode(v int64) {
p.fmt.sharp = sharp
}
-func (p *pp) fmtUint64(v uint64, verb int, goSyntax bool, value interface{}) {
+func (p *pp) fmtUint64(v uint64, verb rune, goSyntax bool) {
switch verb {
case 'b':
p.fmt.integer(int64(v), 2, unsigned, ldigits)
@@ -400,7 +419,7 @@ func (p *pp) fmtUint64(v uint64, verb int, goSyntax bool, value interface{}) {
if 0 <= v && v <= unicode.MaxRune {
p.fmt.fmt_qc(int64(v))
} else {
- p.badVerb(verb, value)
+ p.badVerb(verb)
}
case 'x':
p.fmt.integer(int64(v), 16, unsigned, ldigits)
@@ -409,11 +428,11 @@ func (p *pp) fmtUint64(v uint64, verb int, goSyntax bool, value interface{}) {
case 'U':
p.fmtUnicode(int64(v))
default:
- p.badVerb(verb, value)
+ p.badVerb(verb)
}
}
-func (p *pp) fmtFloat32(v float32, verb int, value interface{}) {
+func (p *pp) fmtFloat32(v float32, verb rune) {
switch verb {
case 'b':
p.fmt.fmt_fb32(v)
@@ -428,11 +447,11 @@ func (p *pp) fmtFloat32(v float32, verb int, value interface{}) {
case 'G':
p.fmt.fmt_G32(v)
default:
- p.badVerb(verb, value)
+ p.badVerb(verb)
}
}
-func (p *pp) fmtFloat64(v float64, verb int, value interface{}) {
+func (p *pp) fmtFloat64(v float64, verb rune) {
switch verb {
case 'b':
p.fmt.fmt_fb64(v)
@@ -447,33 +466,33 @@ func (p *pp) fmtFloat64(v float64, verb int, value interface{}) {
case 'G':
p.fmt.fmt_G64(v)
default:
- p.badVerb(verb, value)
+ p.badVerb(verb)
}
}
-func (p *pp) fmtComplex64(v complex64, verb int, value interface{}) {
+func (p *pp) fmtComplex64(v complex64, verb rune) {
switch verb {
case 'e', 'E', 'f', 'F', 'g', 'G':
p.fmt.fmt_c64(v, verb)
case 'v':
p.fmt.fmt_c64(v, 'g')
default:
- p.badVerb(verb, value)
+ p.badVerb(verb)
}
}
-func (p *pp) fmtComplex128(v complex128, verb int, value interface{}) {
+func (p *pp) fmtComplex128(v complex128, verb rune) {
switch verb {
case 'e', 'E', 'f', 'F', 'g', 'G':
p.fmt.fmt_c128(v, verb)
case 'v':
p.fmt.fmt_c128(v, 'g')
default:
- p.badVerb(verb, value)
+ p.badVerb(verb)
}
}
-func (p *pp) fmtString(v string, verb int, goSyntax bool, value interface{}) {
+func (p *pp) fmtString(v string, verb rune, goSyntax bool) {
switch verb {
case 'v':
if goSyntax {
@@ -484,17 +503,17 @@ func (p *pp) fmtString(v string, verb int, goSyntax bool, value interface{}) {
case 's':
p.fmt.fmt_s(v)
case 'x':
- p.fmt.fmt_sx(v)
+ p.fmt.fmt_sx(v, ldigits)
case 'X':
- p.fmt.fmt_sX(v)
+ p.fmt.fmt_sx(v, udigits)
case 'q':
p.fmt.fmt_q(v)
default:
- p.badVerb(verb, value)
+ p.badVerb(verb)
}
}
-func (p *pp) fmtBytes(v []byte, verb int, goSyntax bool, depth int, value interface{}) {
+func (p *pp) fmtBytes(v []byte, verb rune, goSyntax bool, depth int) {
if verb == 'v' || verb == 'd' {
if goSyntax {
p.buf.Write(bytesBytes)
@@ -523,28 +542,28 @@ func (p *pp) fmtBytes(v []byte, verb int, goSyntax bool, depth int, value interf
case 's':
p.fmt.fmt_s(s)
case 'x':
- p.fmt.fmt_sx(s)
+ p.fmt.fmt_sx(s, ldigits)
case 'X':
- p.fmt.fmt_sX(s)
+ p.fmt.fmt_sx(s, udigits)
case 'q':
p.fmt.fmt_q(s)
default:
- p.badVerb(verb, value)
+ p.badVerb(verb)
}
}
-func (p *pp) fmtPointer(field interface{}, value reflect.Value, verb int, goSyntax bool) {
+func (p *pp) fmtPointer(value reflect.Value, verb rune, goSyntax bool) {
var u uintptr
switch value.Kind() {
case reflect.Chan, reflect.Func, reflect.Map, reflect.Ptr, reflect.Slice, reflect.UnsafePointer:
u = value.Pointer()
default:
- p.badVerb(verb, field)
+ p.badVerb(verb)
return
}
if goSyntax {
p.add('(')
- p.buf.WriteString(reflect.TypeOf(field).String())
+ p.buf.WriteString(value.Type().String())
p.add(')')
p.add('(')
if u == 0 {
@@ -565,12 +584,12 @@ var (
uintptrBits = reflect.TypeOf(uintptr(0)).Bits()
)
-func (p *pp) catchPanic(val interface{}, verb int) {
+func (p *pp) catchPanic(field interface{}, verb rune) {
if err := recover(); err != nil {
// If it's a nil pointer, just say "<nil>". The likeliest causes are a
// Stringer that fails to guard against nil or a nil pointer for a
// value receiver, and in either case, "<nil>" is a nice result.
- if v := reflect.ValueOf(val); v.Kind() == reflect.Ptr && v.IsNil() {
+ if v := reflect.ValueOf(field); v.Kind() == reflect.Ptr && v.IsNil() {
p.buf.Write(nilAngleBytes)
return
}
@@ -590,16 +609,77 @@ func (p *pp) catchPanic(val interface{}, verb int) {
}
}
-func (p *pp) printField(field interface{}, verb int, plus, goSyntax bool, depth int) (wasString bool) {
+func (p *pp) handleMethods(verb rune, plus, goSyntax bool, depth int) (wasString, handled bool) {
+ if p.erroring {
+ return
+ }
+ // Is it a Formatter?
+ if formatter, ok := p.field.(Formatter); ok {
+ handled = true
+ wasString = false
+ defer p.catchPanic(p.field, verb)
+ formatter.Format(p, verb)
+ return
+ }
+ // Must not touch flags before Formatter looks at them.
+ if plus {
+ p.fmt.plus = false
+ }
+
+ // If we're doing Go syntax and the field knows how to supply it, take care of it now.
+ if goSyntax {
+ p.fmt.sharp = false
+ if stringer, ok := p.field.(GoStringer); ok {
+ wasString = false
+ handled = true
+ defer p.catchPanic(p.field, verb)
+ // Print the result of GoString unadorned.
+ p.fmtString(stringer.GoString(), 's', false)
+ return
+ }
+ } else {
+ // If a string is acceptable according to the format, see if
+ // the value satisfies one of the string-valued interfaces.
+ // Println etc. set verb to %v, which is "stringable".
+ switch verb {
+ case 'v', 's', 'x', 'X', 'q':
+ // Is it an error or Stringer?
+ // The duplication in the bodies is necessary:
+ // setting wasString and handled, and deferring catchPanic,
+ // must happen before calling the method.
+ switch v := p.field.(type) {
+ case error:
+ wasString = false
+ handled = true
+ defer p.catchPanic(p.field, verb)
+ p.printField(v.Error(), verb, plus, false, depth)
+ return
+
+ case Stringer:
+ wasString = false
+ handled = true
+ defer p.catchPanic(p.field, verb)
+ p.printField(v.String(), verb, plus, false, depth)
+ return
+ }
+ }
+ }
+ handled = false
+ return
+}
+
+func (p *pp) printField(field interface{}, verb rune, plus, goSyntax bool, depth int) (wasString bool) {
if field == nil {
if verb == 'T' || verb == 'v' {
p.buf.Write(nilAngleBytes)
} else {
- p.badVerb(verb, field)
+ p.badVerb(verb)
}
return false
}
+ p.field = field
+ p.value = reflect.Value{}
// Special processing considerations.
// %T (the value's type) and %p (its address) are special; we always do them first.
switch verb {
@@ -607,124 +687,131 @@ func (p *pp) printField(field interface{}, verb int, plus, goSyntax bool, depth
p.printField(reflect.TypeOf(field).String(), 's', false, false, 0)
return false
case 'p':
- p.fmtPointer(field, reflect.ValueOf(field), verb, goSyntax)
+ p.fmtPointer(reflect.ValueOf(field), verb, goSyntax)
return false
}
- // Is it a Formatter?
- if formatter, ok := field.(Formatter); ok {
- defer p.catchPanic(field, verb)
- formatter.Format(p, verb)
- return false // this value is not a string
- }
- // Must not touch flags before Formatter looks at them.
- if plus {
- p.fmt.plus = false
- }
- // If we're doing Go syntax and the field knows how to supply it, take care of it now.
- if goSyntax {
- p.fmt.sharp = false
- if stringer, ok := field.(GoStringer); ok {
- defer p.catchPanic(field, verb)
- // Print the result of GoString unadorned.
- p.fmtString(stringer.GoString(), 's', false, field)
- return false // this value is not a string
- }
- } else {
- // Is it a Stringer?
- if stringer, ok := field.(Stringer); ok {
- defer p.catchPanic(field, verb)
- p.printField(stringer.String(), verb, plus, false, depth)
- return false // this value is not a string
- }
+ if wasString, handled := p.handleMethods(verb, plus, goSyntax, depth); handled {
+ return wasString
}
// Some types can be done without reflection.
switch f := field.(type) {
case bool:
- p.fmtBool(f, verb, field)
- return false
+ p.fmtBool(f, verb)
case float32:
- p.fmtFloat32(f, verb, field)
- return false
+ p.fmtFloat32(f, verb)
case float64:
- p.fmtFloat64(f, verb, field)
- return false
+ p.fmtFloat64(f, verb)
case complex64:
- p.fmtComplex64(complex64(f), verb, field)
- return false
+ p.fmtComplex64(complex64(f), verb)
case complex128:
- p.fmtComplex128(f, verb, field)
- return false
+ p.fmtComplex128(f, verb)
case int:
- p.fmtInt64(int64(f), verb, field)
- return false
+ p.fmtInt64(int64(f), verb)
case int8:
- p.fmtInt64(int64(f), verb, field)
- return false
+ p.fmtInt64(int64(f), verb)
case int16:
- p.fmtInt64(int64(f), verb, field)
- return false
+ p.fmtInt64(int64(f), verb)
case int32:
- p.fmtInt64(int64(f), verb, field)
- return false
+ p.fmtInt64(int64(f), verb)
case int64:
- p.fmtInt64(f, verb, field)
- return false
+ p.fmtInt64(f, verb)
case uint:
- p.fmtUint64(uint64(f), verb, goSyntax, field)
- return false
+ p.fmtUint64(uint64(f), verb, goSyntax)
case uint8:
- p.fmtUint64(uint64(f), verb, goSyntax, field)
- return false
+ p.fmtUint64(uint64(f), verb, goSyntax)
case uint16:
- p.fmtUint64(uint64(f), verb, goSyntax, field)
- return false
+ p.fmtUint64(uint64(f), verb, goSyntax)
case uint32:
- p.fmtUint64(uint64(f), verb, goSyntax, field)
- return false
+ p.fmtUint64(uint64(f), verb, goSyntax)
case uint64:
- p.fmtUint64(f, verb, goSyntax, field)
- return false
+ p.fmtUint64(f, verb, goSyntax)
case uintptr:
- p.fmtUint64(uint64(f), verb, goSyntax, field)
- return false
+ p.fmtUint64(uint64(f), verb, goSyntax)
case string:
- p.fmtString(f, verb, goSyntax, field)
- return verb == 's' || verb == 'v'
+ p.fmtString(f, verb, goSyntax)
+ wasString = verb == 's' || verb == 'v'
case []byte:
- p.fmtBytes(f, verb, goSyntax, depth, field)
- return verb == 's'
+ p.fmtBytes(f, verb, goSyntax, depth)
+ wasString = verb == 's'
+ default:
+ // Need to use reflection
+ return p.printReflectValue(reflect.ValueOf(field), verb, plus, goSyntax, depth)
}
+ p.field = nil
+ return
+}
- // Need to use reflection
- value := reflect.ValueOf(field)
+// printValue is like printField but starts with a reflect value, not an interface{} value.
+func (p *pp) printValue(value reflect.Value, verb rune, plus, goSyntax bool, depth int) (wasString bool) {
+ if !value.IsValid() {
+ if verb == 'T' || verb == 'v' {
+ p.buf.Write(nilAngleBytes)
+ } else {
+ p.badVerb(verb)
+ }
+ return false
+ }
+
+ // Special processing considerations.
+ // %T (the value's type) and %p (its address) are special; we always do them first.
+ switch verb {
+ case 'T':
+ p.printField(value.Type().String(), 's', false, false, 0)
+ return false
+ case 'p':
+ p.fmtPointer(value, verb, goSyntax)
+ return false
+ }
+
+ // Handle values with special methods.
+ // Call always, even when field == nil, because handleMethods clears p.fmt.plus for us.
+ p.field = nil // Make sure it's cleared, for safety.
+ if value.CanInterface() {
+ p.field = value.Interface()
+ }
+ if wasString, handled := p.handleMethods(verb, plus, goSyntax, depth); handled {
+ return wasString
+ }
+
+ return p.printReflectValue(value, verb, plus, goSyntax, depth)
+}
+// printReflectValue is the fallback for both printField and printValue.
+// It uses reflect to print the value.
+func (p *pp) printReflectValue(value reflect.Value, verb rune, plus, goSyntax bool, depth int) (wasString bool) {
+ oldValue := p.value
+ p.value = value
BigSwitch:
switch f := value; f.Kind() {
case reflect.Bool:
- p.fmtBool(f.Bool(), verb, field)
+ p.fmtBool(f.Bool(), verb)
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
- p.fmtInt64(f.Int(), verb, field)
+ p.fmtInt64(f.Int(), verb)
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
- p.fmtUint64(uint64(f.Uint()), verb, goSyntax, field)
+ p.fmtUint64(uint64(f.Uint()), verb, goSyntax)
case reflect.Float32, reflect.Float64:
if f.Type().Size() == 4 {
- p.fmtFloat32(float32(f.Float()), verb, field)
+ p.fmtFloat32(float32(f.Float()), verb)
} else {
- p.fmtFloat64(float64(f.Float()), verb, field)
+ p.fmtFloat64(float64(f.Float()), verb)
}
case reflect.Complex64, reflect.Complex128:
if f.Type().Size() == 8 {
- p.fmtComplex64(complex64(f.Complex()), verb, field)
+ p.fmtComplex64(complex64(f.Complex()), verb)
} else {
- p.fmtComplex128(complex128(f.Complex()), verb, field)
+ p.fmtComplex128(complex128(f.Complex()), verb)
}
case reflect.String:
- p.fmtString(f.String(), verb, goSyntax, field)
+ p.fmtString(f.String(), verb, goSyntax)
case reflect.Map:
if goSyntax {
p.buf.WriteString(f.Type().String())
+ if f.IsNil() {
+ p.buf.WriteString("(nil)")
+ break
+ }
p.buf.WriteByte('{')
} else {
p.buf.Write(mapBytes)
@@ -738,9 +825,9 @@ BigSwitch:
p.buf.WriteByte(' ')
}
}
- p.printField(key.Interface(), verb, plus, goSyntax, depth+1)
+ p.printValue(key, verb, plus, goSyntax, depth+1)
p.buf.WriteByte(':')
- p.printField(f.MapIndex(key).Interface(), verb, plus, goSyntax, depth+1)
+ p.printValue(f.MapIndex(key), verb, plus, goSyntax, depth+1)
}
if goSyntax {
p.buf.WriteByte('}')
@@ -749,7 +836,7 @@ BigSwitch:
}
case reflect.Struct:
if goSyntax {
- p.buf.WriteString(reflect.TypeOf(field).String())
+ p.buf.WriteString(value.Type().String())
}
p.add('{')
v := f
@@ -768,20 +855,20 @@ BigSwitch:
p.buf.WriteByte(':')
}
}
- p.printField(getField(v, i).Interface(), verb, plus, goSyntax, depth+1)
+ p.printValue(getField(v, i), verb, plus, goSyntax, depth+1)
}
p.buf.WriteByte('}')
case reflect.Interface:
value := f.Elem()
if !value.IsValid() {
if goSyntax {
- p.buf.WriteString(reflect.TypeOf(field).String())
+ p.buf.WriteString(f.Type().String())
p.buf.Write(nilParenBytes)
} else {
p.buf.Write(nilAngleBytes)
}
} else {
- return p.printField(value.Interface(), verb, plus, goSyntax, depth+1)
+ wasString = p.printValue(value, verb, plus, goSyntax, depth+1)
}
case reflect.Array, reflect.Slice:
// Byte slices are special.
@@ -797,11 +884,16 @@ BigSwitch:
for i := range bytes {
bytes[i] = byte(f.Index(i).Uint())
}
- p.fmtBytes(bytes, verb, goSyntax, depth, field)
- return verb == 's'
+ p.fmtBytes(bytes, verb, goSyntax, depth)
+ wasString = verb == 's'
+ break
}
if goSyntax {
- p.buf.WriteString(reflect.TypeOf(field).String())
+ p.buf.WriteString(value.Type().String())
+ if f.Kind() == reflect.Slice && f.IsNil() {
+ p.buf.WriteString("(nil)")
+ break
+ }
p.buf.WriteByte('{')
} else {
p.buf.WriteByte('[')
@@ -814,7 +906,7 @@ BigSwitch:
p.buf.WriteByte(' ')
}
}
- p.printField(f.Index(i).Interface(), verb, plus, goSyntax, depth+1)
+ p.printValue(f.Index(i), verb, plus, goSyntax, depth+1)
}
if goSyntax {
p.buf.WriteByte('}')
@@ -829,17 +921,17 @@ BigSwitch:
switch a := f.Elem(); a.Kind() {
case reflect.Array, reflect.Slice:
p.buf.WriteByte('&')
- p.printField(a.Interface(), verb, plus, goSyntax, depth+1)
+ p.printValue(a, verb, plus, goSyntax, depth+1)
break BigSwitch
case reflect.Struct:
p.buf.WriteByte('&')
- p.printField(a.Interface(), verb, plus, goSyntax, depth+1)
+ p.printValue(a, verb, plus, goSyntax, depth+1)
break BigSwitch
}
}
if goSyntax {
p.buf.WriteByte('(')
- p.buf.WriteString(reflect.TypeOf(field).String())
+ p.buf.WriteString(value.Type().String())
p.buf.WriteByte(')')
p.buf.WriteByte('(')
if v == 0 {
@@ -856,11 +948,12 @@ BigSwitch:
}
p.fmt0x64(uint64(v), true)
case reflect.Chan, reflect.Func, reflect.UnsafePointer:
- p.fmtPointer(field, value, verb, goSyntax)
+ p.fmtPointer(value, verb, goSyntax)
default:
p.unknownType(f)
}
- return false
+ p.value = oldValue
+ return wasString
}
// intFromArg gets the fieldnumth element of a. On return, isInt reports whether the argument has type int.
diff --git a/src/pkg/fmt/scan.go b/src/pkg/fmt/scan.go
index 259451d02..281525112 100644
--- a/src/pkg/fmt/scan.go
+++ b/src/pkg/fmt/scan.go
@@ -6,6 +6,7 @@ package fmt
import (
"bytes"
+ "errors"
"io"
"math"
"os"
@@ -13,7 +14,7 @@ import (
"strconv"
"strings"
"unicode"
- "utf8"
+ "unicode/utf8"
)
// runeUnreader is the interface to something that can unread runes.
@@ -21,7 +22,7 @@ import (
// a local buffer will be used to back up the input, but its contents
// will be lost when Scan returns.
type runeUnreader interface {
- UnreadRune() os.Error
+ UnreadRune() error
}
// ScanState represents the scanner state passed to custom scanners.
@@ -32,9 +33,9 @@ type ScanState interface {
// If invoked during Scanln, Fscanln, or Sscanln, ReadRune() will
// return EOF after returning the first '\n' or when reading beyond
// the specified width.
- ReadRune() (rune int, size int, err os.Error)
+ ReadRune() (r rune, size int, err error)
// UnreadRune causes the next call to ReadRune to return the same rune.
- UnreadRune() os.Error
+ UnreadRune() error
// SkipSpace skips space in the input. Newlines are treated as space
// unless the scan operation is Scanln, Fscanln or Sscanln, in which case
// a newline is treated as EOF.
@@ -47,14 +48,14 @@ type ScanState interface {
// EOF. The returned slice points to shared data that may be overwritten
// by the next call to Token, a call to a Scan function using the ScanState
// as input, or when the calling Scan method returns.
- Token(skipSpace bool, f func(int) bool) (token []byte, err os.Error)
+ Token(skipSpace bool, f func(rune) bool) (token []byte, err error)
// 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)
// Because ReadRune is implemented by the interface, Read should never be
// called by the scanning routines and a valid implementation of
// ScanState may choose always to return an error from Read.
- Read(buf []byte) (n int, err os.Error)
+ Read(buf []byte) (n int, err error)
}
// Scanner is implemented by any value that has a Scan method, which scans
@@ -62,27 +63,27 @@ type ScanState interface {
// receiver, which must be a pointer to be useful. The Scan method is called
// for any argument to Scan, Scanf, or Scanln that implements it.
type Scanner interface {
- Scan(state ScanState, verb int) os.Error
+ Scan(state ScanState, verb rune) error
}
// Scan scans text read from standard input, storing successive
// space-separated values into successive arguments. Newlines count
// as space. It returns the number of items successfully scanned.
// If that is less than the number of arguments, err will report why.
-func Scan(a ...interface{}) (n int, err os.Error) {
+func Scan(a ...interface{}) (n int, err error) {
return Fscan(os.Stdin, a...)
}
// Scanln is similar to Scan, but stops scanning at a newline and
// after the final item there must be a newline or EOF.
-func Scanln(a ...interface{}) (n int, err os.Error) {
+func Scanln(a ...interface{}) (n int, err error) {
return Fscanln(os.Stdin, a...)
}
// Scanf scans text read from standard input, storing successive
// space-separated values into successive arguments as determined by
// the format. It returns the number of items successfully scanned.
-func Scanf(format string, a ...interface{}) (n int, err os.Error) {
+func Scanf(format string, a ...interface{}) (n int, err error) {
return Fscanf(os.Stdin, format, a...)
}
@@ -90,20 +91,20 @@ func Scanf(format string, a ...interface{}) (n int, err os.Error) {
// values into successive arguments. Newlines count as space. It
// returns the number of items successfully scanned. If that is less
// than the number of arguments, err will report why.
-func Sscan(str string, a ...interface{}) (n int, err os.Error) {
+func Sscan(str string, a ...interface{}) (n int, err error) {
return Fscan(strings.NewReader(str), a...)
}
// Sscanln is similar to Sscan, but stops scanning at a newline and
// after the final item there must be a newline or EOF.
-func Sscanln(str string, a ...interface{}) (n int, err os.Error) {
+func Sscanln(str string, a ...interface{}) (n int, err error) {
return Fscanln(strings.NewReader(str), a...)
}
// Sscanf scans the argument string, storing successive space-separated
// values into successive arguments as determined by the format. It
// returns the number of items successfully parsed.
-func Sscanf(str string, format string, a ...interface{}) (n int, err os.Error) {
+func Sscanf(str string, format string, a ...interface{}) (n int, err error) {
return Fscanf(strings.NewReader(str), format, a...)
}
@@ -111,7 +112,7 @@ func Sscanf(str string, format string, a ...interface{}) (n int, err os.Error) {
// values into successive arguments. Newlines count as space. It
// returns the number of items successfully scanned. If that is less
// than the number of arguments, err will report why.
-func Fscan(r io.Reader, a ...interface{}) (n int, err os.Error) {
+func Fscan(r io.Reader, a ...interface{}) (n int, err error) {
s, old := newScanState(r, true, false)
n, err = s.doScan(a)
s.free(old)
@@ -120,7 +121,7 @@ func Fscan(r io.Reader, a ...interface{}) (n int, err os.Error) {
// Fscanln is similar to Fscan, but stops scanning at a newline and
// after the final item there must be a newline or EOF.
-func Fscanln(r io.Reader, a ...interface{}) (n int, err os.Error) {
+func Fscanln(r io.Reader, a ...interface{}) (n int, err error) {
s, old := newScanState(r, false, true)
n, err = s.doScan(a)
s.free(old)
@@ -130,7 +131,7 @@ func Fscanln(r io.Reader, a ...interface{}) (n int, err os.Error) {
// Fscanf scans text read from r, storing successive space-separated
// values into successive arguments as determined by the format. It
// returns the number of items successfully parsed.
-func Fscanf(r io.Reader, format string, a ...interface{}) (n int, err os.Error) {
+func Fscanf(r io.Reader, format string, a ...interface{}) (n int, err error) {
s, old := newScanState(r, false, false)
n, err = s.doScanf(format, a)
s.free(old)
@@ -140,7 +141,7 @@ func Fscanf(r io.Reader, format string, a ...interface{}) (n int, err os.Error)
// scanError represents an error generated by the scanning software.
// It's used as a unique signature to identify such errors when recovering.
type scanError struct {
- err os.Error
+ err error
}
const eof = -1
@@ -149,8 +150,8 @@ const eof = -1
type ss struct {
rr io.RuneReader // where to read input
buf bytes.Buffer // token accumulator
- peekRune int // one-rune lookahead
- prevRune int // last rune returned by ReadRune
+ peekRune rune // one-rune lookahead
+ prevRune rune // last rune returned by ReadRune
count int // runes consumed so far.
atEOF bool // already read EOF
ssave
@@ -170,29 +171,29 @@ type ssave struct {
// The Read method is only in ScanState so that ScanState
// satisfies io.Reader. It will never be called when used as
// intended, so there is no need to make it actually work.
-func (s *ss) Read(buf []byte) (n int, err os.Error) {
- return 0, os.NewError("ScanState's Read should not be called. Use ReadRune")
+func (s *ss) Read(buf []byte) (n int, err error) {
+ return 0, errors.New("ScanState's Read should not be called. Use ReadRune")
}
-func (s *ss) ReadRune() (rune int, size int, err os.Error) {
+func (s *ss) ReadRune() (r rune, size int, err error) {
if s.peekRune >= 0 {
s.count++
- rune = s.peekRune
- size = utf8.RuneLen(rune)
- s.prevRune = rune
+ r = s.peekRune
+ size = utf8.RuneLen(r)
+ s.prevRune = r
s.peekRune = -1
return
}
if s.atEOF || s.nlIsEnd && s.prevRune == '\n' || s.count >= s.fieldLimit {
- err = os.EOF
+ err = io.EOF
return
}
- rune, size, err = s.rr.ReadRune()
+ r, size, err = s.rr.ReadRune()
if err == nil {
s.count++
- s.prevRune = rune
- } else if err == os.EOF {
+ s.prevRune = r
+ } else if err == io.EOF {
s.atEOF = true
}
return
@@ -207,10 +208,10 @@ func (s *ss) Width() (wid int, ok bool) {
// 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) {
- rune, _, err := s.ReadRune()
+func (s *ss) getRune() (r rune) {
+ r, _, err := s.ReadRune()
if err != nil {
- if err == os.EOF {
+ if err == io.EOF {
return eof
}
s.error(err)
@@ -218,18 +219,18 @@ func (s *ss) getRune() (rune int) {
return
}
-// mustReadRune turns os.EOF into a panic(io.ErrUnexpectedEOF).
+// mustReadRune turns io.EOF into a panic(io.ErrUnexpectedEOF).
// It is called in cases such as string scanning where an EOF is a
// syntax error.
-func (s *ss) mustReadRune() (rune int) {
- rune = s.getRune()
- if rune == eof {
+func (s *ss) mustReadRune() (r rune) {
+ r = s.getRune()
+ if r == eof {
s.error(io.ErrUnexpectedEOF)
}
return
}
-func (s *ss) UnreadRune() os.Error {
+func (s *ss) UnreadRune() error {
if u, ok := s.rr.(runeUnreader); ok {
u.UnreadRune()
} else {
@@ -240,15 +241,15 @@ func (s *ss) UnreadRune() os.Error {
return nil
}
-func (s *ss) error(err os.Error) {
+func (s *ss) error(err error) {
panic(scanError{err})
}
func (s *ss) errorString(err string) {
- panic(scanError{os.NewError(err)})
+ panic(scanError{errors.New(err)})
}
-func (s *ss) Token(skipSpace bool, f func(int) bool) (tok []byte, err os.Error) {
+func (s *ss) Token(skipSpace bool, f func(rune) bool) (tok []byte, err error) {
defer func() {
if e := recover(); e != nil {
if se, ok := e.(scanError); ok {
@@ -267,7 +268,7 @@ func (s *ss) Token(skipSpace bool, f func(int) bool) (tok []byte, err os.Error)
}
// notSpace is the default scanning function used in Token.
-func notSpace(r int) bool {
+func notSpace(r rune) bool {
return !unicode.IsSpace(r)
}
@@ -289,7 +290,7 @@ type readRune struct {
// readByte returns the next byte from the input, which may be
// left over from a previous read if the UTF-8 was ill-formed.
-func (r *readRune) readByte() (b byte, err os.Error) {
+func (r *readRune) readByte() (b byte, err error) {
if r.pending > 0 {
b = r.pendBuf[0]
copy(r.pendBuf[0:], r.pendBuf[1:])
@@ -308,27 +309,27 @@ func (r *readRune) unread(buf []byte) {
// ReadRune returns the next UTF-8 encoded code point from the
// io.Reader inside r.
-func (r *readRune) ReadRune() (rune int, size int, err os.Error) {
+func (r *readRune) ReadRune() (rr rune, size int, err error) {
r.buf[0], err = r.readByte()
if err != nil {
return 0, 0, err
}
if r.buf[0] < utf8.RuneSelf { // fast check for common ASCII case
- rune = int(r.buf[0])
+ rr = rune(r.buf[0])
return
}
var n int
for n = 1; !utf8.FullRune(r.buf[0:n]); n++ {
r.buf[n], err = r.readByte()
if err != nil {
- if err == os.EOF {
+ if err == io.EOF {
err = nil
break
}
return
}
}
- rune, size = utf8.DecodeRune(r.buf[0:n])
+ rr, size = utf8.DecodeRune(r.buf[0:n])
if size < n { // an error
r.unread(r.buf[size:n])
}
@@ -387,11 +388,11 @@ func (s *ss) free(old ssave) {
// skipSpace skips spaces and maybe newlines.
func (s *ss) skipSpace(stopAtNewline bool) {
for {
- rune := s.getRune()
- if rune == eof {
+ r := s.getRune()
+ if r == eof {
return
}
- if rune == '\n' {
+ if r == '\n' {
if stopAtNewline {
break
}
@@ -401,7 +402,7 @@ func (s *ss) skipSpace(stopAtNewline bool) {
s.errorString("unexpected newline")
return
}
- if !unicode.IsSpace(rune) {
+ if !unicode.IsSpace(r) {
s.UnreadRune()
break
}
@@ -411,21 +412,21 @@ func (s *ss) skipSpace(stopAtNewline bool) {
// token returns the next space-delimited string from the input. It
// skips white space. For Scanln, it stops at newlines. For Scan,
// newlines are treated as spaces.
-func (s *ss) token(skipSpace bool, f func(int) bool) []byte {
+func (s *ss) token(skipSpace bool, f func(rune) bool) []byte {
if skipSpace {
s.skipSpace(false)
}
// read until white space or newline
for {
- rune := s.getRune()
- if rune == eof {
+ r := s.getRune()
+ if r == eof {
break
}
- if !f(rune) {
+ if !f(r) {
s.UnreadRune()
break
}
- s.buf.WriteRune(rune)
+ s.buf.WriteRune(r)
}
return s.buf.Bytes()
}
@@ -435,23 +436,23 @@ func (s *ss) typeError(field interface{}, expected string) {
s.errorString("expected field of type pointer to " + expected + "; found " + reflect.TypeOf(field).String())
}
-var complexError = os.NewError("syntax error scanning complex number")
-var boolError = os.NewError("syntax error scanning boolean")
+var complexError = errors.New("syntax error scanning complex number")
+var boolError = errors.New("syntax error scanning boolean")
// consume reads the next rune in the input and reports whether it is in the ok string.
// If accept is true, it puts the character into the input token.
func (s *ss) consume(ok string, accept bool) bool {
- rune := s.getRune()
- if rune == eof {
+ r := s.getRune()
+ if r == eof {
return false
}
- if strings.IndexRune(ok, rune) >= 0 {
+ if strings.IndexRune(ok, r) >= 0 {
if accept {
- s.buf.WriteRune(rune)
+ s.buf.WriteRune(r)
}
return true
}
- if rune != eof && accept {
+ if r != eof && accept {
s.UnreadRune()
}
return false
@@ -459,17 +460,17 @@ func (s *ss) consume(ok string, accept bool) bool {
// peek reports whether the next character is in the ok string, without consuming it.
func (s *ss) peek(ok string) bool {
- rune := s.getRune()
- if rune != eof {
+ r := s.getRune()
+ if r != eof {
s.UnreadRune()
}
- return strings.IndexRune(ok, rune) >= 0
+ return strings.IndexRune(ok, r) >= 0
}
func (s *ss) notEOF() {
// Guarantee there is data to be read.
- if rune := s.getRune(); rune == eof {
- panic(os.EOF)
+ if r := s.getRune(); r == eof {
+ panic(io.EOF)
}
s.UnreadRune()
}
@@ -481,7 +482,7 @@ func (s *ss) accept(ok string) bool {
}
// okVerb verifies that the verb is present in the list, setting s.err appropriately if not.
-func (s *ss) okVerb(verb int, okVerbs, typ string) bool {
+func (s *ss) okVerb(verb rune, okVerbs, typ string) bool {
for _, v := range okVerbs {
if v == verb {
return true
@@ -492,7 +493,7 @@ func (s *ss) okVerb(verb int, okVerbs, typ string) bool {
}
// scanBool returns the value of the boolean represented by the next token.
-func (s *ss) scanBool(verb int) bool {
+func (s *ss) scanBool(verb rune) bool {
s.skipSpace(false)
s.notEOF()
if !s.okVerb(verb, "tv", "boolean") {
@@ -530,7 +531,7 @@ const (
)
// getBase returns the numeric base represented by the verb and its digit string.
-func (s *ss) getBase(verb int) (base int, digits string) {
+func (s *ss) getBase(verb rune) (base int, digits string) {
s.okVerb(verb, "bdoUxXv", "integer") // sets s.err
base = 10
digits = decimalDigits
@@ -564,13 +565,13 @@ func (s *ss) scanNumber(digits string, haveDigits bool) string {
// scanRune returns the next rune value in the input.
func (s *ss) scanRune(bitSize int) int64 {
s.notEOF()
- rune := int64(s.getRune())
+ r := int64(s.getRune())
n := uint(bitSize)
- x := (rune << (64 - n)) >> (64 - n)
- if x != rune {
- s.errorString("overflow on character value " + string(rune))
+ x := (r << (64 - n)) >> (64 - n)
+ if x != r {
+ s.errorString("overflow on character value " + string(r))
}
- return rune
+ return r
}
// scanBasePrefix reports whether the integer begins with a 0 or 0x,
@@ -593,7 +594,7 @@ func (s *ss) scanBasePrefix() (base int, digits string, found bool) {
// scanInt returns the value of the integer represented by the next
// token, checking for overflow. Any error is stored in s.err.
-func (s *ss) scanInt(verb int, bitSize int) int64 {
+func (s *ss) scanInt(verb rune, bitSize int) int64 {
if verb == 'c' {
return s.scanRune(bitSize)
}
@@ -612,7 +613,7 @@ func (s *ss) scanInt(verb int, bitSize int) int64 {
}
}
tok := s.scanNumber(digits, haveDigits)
- i, err := strconv.Btoi64(tok, base)
+ i, err := strconv.ParseInt(tok, base, 64)
if err != nil {
s.error(err)
}
@@ -626,7 +627,7 @@ func (s *ss) scanInt(verb int, bitSize int) int64 {
// scanUint returns the value of the unsigned integer represented
// by the next token, checking for overflow. Any error is stored in s.err.
-func (s *ss) scanUint(verb int, bitSize int) uint64 {
+func (s *ss) scanUint(verb rune, bitSize int) uint64 {
if verb == 'c' {
return uint64(s.scanRune(bitSize))
}
@@ -642,7 +643,7 @@ func (s *ss) scanUint(verb int, bitSize int) uint64 {
base, digits, haveDigits = s.scanBasePrefix()
}
tok := s.scanNumber(digits, haveDigits)
- i, err := strconv.Btoui64(tok, base)
+ i, err := strconv.ParseUint(tok, base, 64)
if err != nil {
s.error(err)
}
@@ -718,7 +719,7 @@ func (s *ss) convertFloat(str string, n int) float64 {
if p := strings.Index(str, "p"); p >= 0 {
// Atof doesn't handle power-of-2 exponents,
// but they're easy to evaluate.
- f, err := strconv.AtofN(str[:p], n)
+ f, err := strconv.ParseFloat(str[:p], n)
if err != nil {
// Put full string into error.
if e, ok := err.(*strconv.NumError); ok {
@@ -736,7 +737,7 @@ func (s *ss) convertFloat(str string, n int) float64 {
}
return math.Ldexp(f, n)
}
- f, err := strconv.AtofN(str, n)
+ f, err := strconv.ParseFloat(str, n)
if err != nil {
s.error(err)
}
@@ -747,7 +748,7 @@ func (s *ss) convertFloat(str string, n int) float64 {
// The atof argument is a type-specific reader for the underlying type.
// If we're reading complex64, atof will parse float32s and convert them
// to float64's to avoid reproducing this code for each complex type.
-func (s *ss) scanComplex(verb int, n int) complex128 {
+func (s *ss) scanComplex(verb rune, n int) complex128 {
if !s.okVerb(verb, floatVerbs, "complex") {
return 0
}
@@ -761,7 +762,7 @@ func (s *ss) scanComplex(verb int, n int) complex128 {
// convertString returns the string represented by the next input characters.
// The format of the input is determined by the verb.
-func (s *ss) convertString(verb int) (str string) {
+func (s *ss) convertString(verb rune) (str string) {
if !s.okVerb(verb, "svqx", "string") {
return ""
}
@@ -786,26 +787,26 @@ func (s *ss) quotedString() string {
case '`':
// Back-quoted: Anything goes until EOF or back quote.
for {
- rune := s.mustReadRune()
- if rune == quote {
+ r := s.mustReadRune()
+ if r == quote {
break
}
- s.buf.WriteRune(rune)
+ s.buf.WriteRune(r)
}
return s.buf.String()
case '"':
// Double-quoted: Include the quotes and let strconv.Unquote do the backslash escapes.
s.buf.WriteRune(quote)
for {
- rune := s.mustReadRune()
- s.buf.WriteRune(rune)
- if rune == '\\' {
+ r := s.mustReadRune()
+ s.buf.WriteRune(r)
+ if r == '\\' {
// In a legal backslash escape, no matter how long, only the character
// immediately after the escape can itself be a backslash or quote.
// Thus we only need to protect the first character after the backslash.
- rune := s.mustReadRune()
- s.buf.WriteRune(rune)
- } else if rune == '"' {
+ r := s.mustReadRune()
+ s.buf.WriteRune(r)
+ } else if r == '"' {
break
}
}
@@ -821,7 +822,8 @@ func (s *ss) quotedString() string {
}
// hexDigit returns the value of the hexadecimal digit
-func (s *ss) hexDigit(digit int) int {
+func (s *ss) hexDigit(d rune) int {
+ digit := int(d)
switch digit {
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
return digit - '0'
@@ -871,14 +873,14 @@ const floatVerbs = "beEfFgGv"
const hugeWid = 1 << 30
// scanOne scans a single value, deriving the scanner from the type of the argument.
-func (s *ss) scanOne(verb int, field interface{}) {
+func (s *ss) scanOne(verb rune, field interface{}) {
s.buf.Reset()
- var err os.Error
+ var err error
// If the parameter has its own Scan method, use that.
if v, ok := field.(Scanner); ok {
err = v.Scan(s, verb)
if err != nil {
- if err == os.EOF {
+ if err == io.EOF {
err = io.ErrUnexpectedEOF
}
s.error(err)
@@ -975,11 +977,11 @@ func (s *ss) scanOne(verb int, field interface{}) {
}
// errorHandler turns local panics into error returns.
-func errorHandler(errp *os.Error) {
+func errorHandler(errp *error) {
if e := recover(); e != nil {
if se, ok := e.(scanError); ok { // catch local error
*errp = se.err
- } else if eof, ok := e.(os.Error); ok && eof == os.EOF { // out of input
+ } else if eof, ok := e.(error); ok && eof == io.EOF { // out of input
*errp = eof
} else {
panic(e)
@@ -988,7 +990,7 @@ func errorHandler(errp *os.Error) {
}
// doScan does the real work for scanning without a format string.
-func (s *ss) doScan(a []interface{}) (numProcessed int, err os.Error) {
+func (s *ss) doScan(a []interface{}) (numProcessed int, err error) {
defer errorHandler(&err)
for _, field := range a {
s.scanOne('v', field)
@@ -997,11 +999,11 @@ func (s *ss) doScan(a []interface{}) (numProcessed int, err os.Error) {
// Check for newline if required.
if !s.nlIsSpace {
for {
- rune := s.getRune()
- if rune == '\n' || rune == eof {
+ r := s.getRune()
+ if r == '\n' || r == eof {
break
}
- if !unicode.IsSpace(rune) {
+ if !unicode.IsSpace(r) {
s.errorString("Scan: expected newline")
break
}
@@ -1060,7 +1062,7 @@ func (s *ss) advance(format string) (i int) {
// doScanf does the real work when scanning with a format string.
// At the moment, it handles only pointers to basic types.
-func (s *ss) doScanf(format string, a []interface{}) (numProcessed int, err os.Error) {
+func (s *ss) doScanf(format string, a []interface{}) (numProcessed int, err error) {
defer errorHandler(&err)
end := len(format) - 1
// We process one item per non-trivial format
diff --git a/src/pkg/fmt/scan_test.go b/src/pkg/fmt/scan_test.go
index 3f06e5725..b26c828cb 100644
--- a/src/pkg/fmt/scan_test.go
+++ b/src/pkg/fmt/scan_test.go
@@ -7,15 +7,15 @@ package fmt_test
import (
"bufio"
"bytes"
+ "errors"
. "fmt"
"io"
"math"
- "os"
"reflect"
"regexp"
"strings"
"testing"
- "utf8"
+ "unicode/utf8"
)
type ScanTest struct {
@@ -56,6 +56,7 @@ var (
stringVal string
stringVal1 string
bytesVal []byte
+ runeVal rune
complex64Val complex64
complex128Val complex128
renamedBoolVal renamedBool
@@ -87,14 +88,14 @@ type FloatTest struct {
// Xs accepts any non-empty run of the verb character
type Xs string
-func (x *Xs) Scan(state ScanState, verb int) os.Error {
- tok, err := state.Token(true, func(r int) bool { return r == verb })
+func (x *Xs) Scan(state ScanState, verb rune) error {
+ tok, err := state.Token(true, func(r rune) bool { return r == verb })
if err != nil {
return err
}
s := string(tok)
if !regexp.MustCompile("^" + string(verb) + "+$").MatchString(s) {
- return os.NewError("syntax error for xs")
+ return errors.New("syntax error for xs")
}
*x = Xs(s)
return nil
@@ -109,7 +110,7 @@ type IntString struct {
s string
}
-func (s *IntString) Scan(state ScanState, verb int) os.Error {
+func (s *IntString) Scan(state ScanState, verb rune) error {
if _, err := Fscan(state, &s.i); err != nil {
return err
}
@@ -130,7 +131,7 @@ type myStringReader struct {
r *strings.Reader
}
-func (s *myStringReader) Read(p []byte) (n int, err os.Error) {
+func (s *myStringReader) Read(p []byte) (n int, err error) {
return s.r.Read(p)
}
@@ -225,9 +226,9 @@ var scanfTests = []ScanfTest{
{"%v", "0377\n", &intVal, 0377},
{"%v", "0x44\n", &intVal, 0x44},
{"%d", "72\n", &intVal, 72},
- {"%c", "a\n", &intVal, 'a'},
- {"%c", "\u5072\n", &intVal, 0x5072},
- {"%c", "\u1234\n", &intVal, '\u1234'},
+ {"%c", "a\n", &runeVal, 'a'},
+ {"%c", "\u5072\n", &runeVal, '\u5072'},
+ {"%c", "\u1234\n", &runeVal, '\u1234'},
{"%d", "73\n", &int8Val, int8(73)},
{"%d", "+74\n", &int16Val, int16(74)},
{"%d", "75\n", &int32Val, int32(75)},
@@ -322,9 +323,10 @@ var s, t string
var c complex128
var x, y Xs
var z IntString
+var r1, r2, r3 rune
var multiTests = []ScanfMultiTest{
- {"", "", nil, nil, ""},
+ {"", "", []interface{}{}, []interface{}{}, ""},
{"%d", "23", args(&i), args(23), ""},
{"%2s%3s", "22333", args(&s, &t), args("22", "333"), ""},
{"%2d%3d", "44555", args(&i, &j), args(44, 555), ""},
@@ -333,7 +335,7 @@ var multiTests = []ScanfMultiTest{
{"%3d22%3d", "33322333", args(&i, &j), args(333, 333), ""},
{"%6vX=%3fY", "3+2iX=2.5Y", args(&c, &f), args((3 + 2i), 2.5), ""},
{"%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(&r1, &r2, &r3), args('2', '\u50c2', 'X'), ""},
// Custom scanners.
{"%e%f", "eefffff", args(&x, &y), args(Xs("ee"), Xs("fffff")), ""},
@@ -347,10 +349,10 @@ var multiTests = []ScanfMultiTest{
{"X%d", "10X", args(&intVal), nil, "input does not match format"},
// Bad UTF-8: should see every byte.
- {"%c%c%c", "\xc2X\xc2", args(&i, &j, &k), args(utf8.RuneError, 'X', utf8.RuneError), ""},
+ {"%c%c%c", "\xc2X\xc2", args(&r1, &r2, &r3), args(utf8.RuneError, 'X', utf8.RuneError), ""},
}
-func testScan(name string, t *testing.T, scan func(r io.Reader, a ...interface{}) (int, os.Error)) {
+func testScan(name string, t *testing.T, scan func(r io.Reader, a ...interface{}) (int, error)) {
for _, test := range scanTests {
var r io.Reader
if name == "StringReader" {
@@ -378,7 +380,7 @@ func testScan(name string, t *testing.T, scan func(r io.Reader, a ...interface{}
}
val := v.Interface()
if !reflect.DeepEqual(val, test.out) {
- t.Errorf("%s scanning %q: expected %v got %v, type %T", name, test.text, test.out, val, val)
+ t.Errorf("%s scanning %q: expected %#v got %#v, type %T", name, test.text, test.out, val, val)
}
}
}
@@ -417,7 +419,7 @@ func TestScanf(t *testing.T) {
}
val := v.Interface()
if !reflect.DeepEqual(val, test.out) {
- t.Errorf("scanning (%q, %q): expected %v got %v, type %T", test.format, test.text, test.out, val, val)
+ t.Errorf("scanning (%q, %q): expected %#v got %#v, type %T", test.format, test.text, test.out, val, val)
}
}
}
@@ -431,7 +433,7 @@ func TestScanOverflow(t *testing.T) {
t.Errorf("expected overflow scanning %q", test.text)
continue
}
- if !re.MatchString(err.String()) {
+ if !re.MatchString(err.Error()) {
t.Errorf("expected overflow error scanning %q: %s", test.text, err)
}
}
@@ -500,7 +502,7 @@ func testScanfMulti(name string, t *testing.T) {
if err != nil {
if test.err == "" {
t.Errorf("got error scanning (%q, %q): %q", test.format, test.text, err)
- } else if strings.Index(err.String(), test.err) < 0 {
+ } else if strings.Index(err.Error(), test.err) < 0 {
t.Errorf("got wrong error scanning (%q, %q): %q; expected %q", test.format, test.text, err, test.err)
}
continue
@@ -520,7 +522,7 @@ func testScanfMulti(name string, t *testing.T) {
}
result := resultVal.Interface()
if !reflect.DeepEqual(result, test.out) {
- t.Errorf("scanning (%q, %q): expected %v got %v", test.format, test.text, test.out, result)
+ t.Errorf("scanning (%q, %q): expected %#v got %#v", test.format, test.text, test.out, result)
}
}
}
@@ -594,7 +596,7 @@ func TestScanNotPointer(t *testing.T) {
_, err := Fscan(r, a)
if err == nil {
t.Error("expected error scanning non-pointer")
- } else if strings.Index(err.String(), "pointer") < 0 {
+ } else if strings.Index(err.Error(), "pointer") < 0 {
t.Errorf("expected pointer error scanning non-pointer, got: %s", err)
}
}
@@ -604,7 +606,7 @@ func TestScanlnNoNewline(t *testing.T) {
_, err := Sscanln("1 x\n", &a)
if err == nil {
t.Error("expected error scanning string missing newline")
- } else if strings.Index(err.String(), "newline") < 0 {
+ } else if strings.Index(err.Error(), "newline") < 0 {
t.Errorf("expected newline error scanning string missing newline, got: %s", err)
}
}
@@ -615,7 +617,7 @@ func TestScanlnWithMiddleNewline(t *testing.T) {
_, err := Fscanln(r, &a, &b)
if err == nil {
t.Error("expected error scanning string with extra newline")
- } else if strings.Index(err.String(), "newline") < 0 {
+ } else if strings.Index(err.Error(), "newline") < 0 {
t.Errorf("expected newline error scanning string with extra newline, got: %s", err)
}
}
@@ -626,7 +628,7 @@ type eofCounter struct {
eofCount int
}
-func (ec *eofCounter) Read(b []byte) (n int, err os.Error) {
+func (ec *eofCounter) Read(b []byte) (n int, err error) {
n, err = ec.reader.Read(b)
if n == 0 {
ec.eofCount++
@@ -670,14 +672,14 @@ func TestEOFAtEndOfInput(t *testing.T) {
if n != 1 || i != 23 {
t.Errorf("Sscanf expected one value of 23; got %d %d", n, i)
}
- if err != os.EOF {
+ if err != io.EOF {
t.Errorf("Sscanf expected EOF; got %q", err)
}
n, err = Sscan("234", &i, &j)
if n != 1 || i != 234 {
t.Errorf("Sscan expected one value of 234; got %d %d", n, i)
}
- if err != os.EOF {
+ if err != io.EOF {
t.Errorf("Sscan expected EOF; got %q", err)
}
// Trailing space is tougher.
@@ -685,7 +687,7 @@ func TestEOFAtEndOfInput(t *testing.T) {
if n != 1 || i != 234 {
t.Errorf("Sscan expected one value of 234; got %d %d", n, i)
}
- if err != os.EOF {
+ if err != io.EOF {
t.Errorf("Sscan expected EOF; got %q", err)
}
}
@@ -715,10 +717,10 @@ var eofTests = []struct {
func TestEOFAllTypes(t *testing.T) {
for i, test := range eofTests {
- if _, err := Sscanf("", test.format, test.v); err != os.EOF {
+ if _, err := Sscanf("", test.format, test.v); err != io.EOF {
t.Errorf("#%d: %s %T not eof on empty string: %s", i, test.format, test.v, err)
}
- if _, err := Sscanf(" ", test.format, test.v); err != os.EOF {
+ if _, err := Sscanf(" ", test.format, test.v); err != io.EOF {
t.Errorf("#%d: %s %T not eof on trailing blanks: %s", i, test.format, test.v, err)
}
}
@@ -749,8 +751,8 @@ type TwoLines string
// Attempt to read two lines into the object. Scanln should prevent this
// because it stops at newline; Scan and Scanf should be fine.
-func (t *TwoLines) Scan(state ScanState, verb int) os.Error {
- chars := make([]int, 0, 100)
+func (t *TwoLines) Scan(state ScanState, verb rune) error {
+ chars := make([]rune, 0, 100)
for nlCount := 0; nlCount < 2; {
c, _, err := state.ReadRune()
if err != nil {
@@ -812,7 +814,7 @@ type RecursiveInt struct {
next *RecursiveInt
}
-func (r *RecursiveInt) Scan(state ScanState, verb int) (err os.Error) {
+func (r *RecursiveInt) Scan(state ScanState, verb rune) (err error) {
_, err = Fscan(state, &r.i)
if err != nil {
return
@@ -820,7 +822,7 @@ func (r *RecursiveInt) Scan(state ScanState, verb int) (err os.Error) {
next := new(RecursiveInt)
_, err = Fscanf(state, ".%v", next)
if err != nil {
- if err == os.NewError("input does not match format") || err == io.ErrUnexpectedEOF {
+ if err == errors.New("input does not match format") || err == io.ErrUnexpectedEOF {
err = nil
}
return
@@ -832,16 +834,15 @@ func (r *RecursiveInt) Scan(state ScanState, verb int) (err os.Error) {
// Perform the same scanning task as RecursiveInt.Scan
// but without recurring through scanner, so we can compare
// performance more directly.
-func scanInts(r *RecursiveInt, b *bytes.Buffer) (err os.Error) {
+func scanInts(r *RecursiveInt, b *bytes.Buffer) (err error) {
r.next = nil
_, err = Fscan(b, &r.i)
if err != nil {
return
}
- var c int
- c, _, err = b.ReadRune()
+ c, _, err := b.ReadRune()
if err != nil {
- if err == os.EOF {
+ if err == io.EOF {
err = nil
}
return
@@ -868,7 +869,7 @@ func makeInts(n int) []byte {
func TestScanInts(t *testing.T) {
testScanInts(t, scanInts)
- testScanInts(t, func(r *RecursiveInt, b *bytes.Buffer) (err os.Error) {
+ testScanInts(t, func(r *RecursiveInt, b *bytes.Buffer) (err error) {
_, err = Fscan(b, r)
return
})
@@ -878,7 +879,7 @@ func TestScanInts(t *testing.T) {
// platform that does not support split stack.
const intCount = 800
-func testScanInts(t *testing.T, scan func(*RecursiveInt, *bytes.Buffer) os.Error) {
+func testScanInts(t *testing.T, scan func(*RecursiveInt, *bytes.Buffer) error) {
r := new(RecursiveInt)
ints := makeInts(intCount)
buf := bytes.NewBuffer(ints)