summaryrefslogtreecommitdiff
path: root/src/pkg/fmt
diff options
context:
space:
mode:
Diffstat (limited to 'src/pkg/fmt')
-rw-r--r--src/pkg/fmt/doc.go31
-rw-r--r--src/pkg/fmt/fmt_test.go107
-rw-r--r--src/pkg/fmt/format.go82
-rw-r--r--src/pkg/fmt/print.go106
-rw-r--r--src/pkg/fmt/scan.go21
-rw-r--r--src/pkg/fmt/scan_test.go43
6 files changed, 269 insertions, 121 deletions
diff --git a/src/pkg/fmt/doc.go b/src/pkg/fmt/doc.go
index a9b9c9d0c..3cd02d7ed 100644
--- a/src/pkg/fmt/doc.go
+++ b/src/pkg/fmt/doc.go
@@ -31,8 +31,8 @@
%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.FormatFloat with the 'b' format,
+ %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
@@ -56,13 +56,17 @@
character '*', causing their values to be obtained from the next
operand, which must be of type int.
- For numeric values, width sets the width of the field and precision
- sets the number of places after the decimal, if appropriate. For
- example, the format %6.2f prints 123.45.
+ For numeric values, width sets the minimum width of the field and
+ precision sets the number of places after the decimal, if appropriate,
+ except that for %g/%G it sets the total number of digits. For example,
+ given 123.45 the format %6.2f prints 123.45 while %.4g prints 123.5.
+ The default precision for %e and %f is 6; for %g it is the smallest
+ number of digits necessary to identify the value uniquely.
- For strings, width is the minimum number of characters to output,
- padding with spaces if necessary, and precision is the maximum
- number of characters to output, truncating if necessary.
+ For most values, width is the minimum number of characters to output,
+ padding the formatted form with spaces if necessary.
+ For strings, precision is the maximum number of characters to output,
+ truncating if necessary.
Other flags:
+ always print a sign for numeric values;
@@ -70,11 +74,17 @@
- pad with spaces on the right rather than the left (left-justify the field)
# alternate format: add leading 0 for octal (%#o), 0x for hex (%#x);
0X for hex (%#X); suppress 0x for %p (%#p);
- print a raw (backquoted) string if possible for %q (%#q);
+ for %q, print a raw (backquoted) string if strconv.CanBackquote
+ returns true;
write e.g. U+0078 'x' if the character is printable for %U (%#U).
' ' (space) leave a space for elided sign in numbers (% d);
put spaces between bytes printing strings or slices in hex (% x, % X)
- 0 pad with leading zeros rather than spaces
+ 0 pad with leading zeros rather than spaces;
+ for numbers, this moves the padding after the sign
+
+ Flags are ignored by verbs that do not expect them.
+ For example there is no alternate decimal format, so %#d and %d
+ behave identically.
For each Printf-like function, there is also a Print function
that takes no format and is equivalent to saying %v for every
@@ -152,6 +162,7 @@
%T is not implemented
%e %E %f %F %g %G are all equivalent and scan any floating point or complex value
%s and %v on strings scan a space-delimited token
+ Flags # and + are not implemented.
The familiar base-setting prefixes 0 (octal) and 0x
(hexadecimal) are accepted when scanning integers without a
diff --git a/src/pkg/fmt/fmt_test.go b/src/pkg/fmt/fmt_test.go
index de0342967..af4b5c8f8 100644
--- a/src/pkg/fmt/fmt_test.go
+++ b/src/pkg/fmt/fmt_test.go
@@ -9,7 +9,6 @@ import (
. "fmt"
"io"
"math"
- "runtime" // for the malloc count test only
"strings"
"testing"
"time"
@@ -96,7 +95,7 @@ type SI struct {
I interface{}
}
-// A type with a String method with pointer receiver for testing %p
+// P is a type with a String method with pointer receiver for testing %p.
type P int
var pValue P
@@ -105,6 +104,9 @@ func (p *P) String() string {
return "String(p)"
}
+var barray = [5]renamedUint8{1, 2, 3, 4, 5}
+var bslice = barray[:]
+
var b byte
var fmttests = []struct {
@@ -127,6 +129,10 @@ var fmttests = []struct {
{"%s", []byte("abc"), "abc"},
{"%x", []byte("abc"), "616263"},
{"% x", []byte("abc\xff"), "61 62 63 ff"},
+ {"%#x", []byte("abc\xff"), "0x610x620x630xff"},
+ {"%#X", []byte("abc\xff"), "0X610X620X630XFF"},
+ {"%# x", []byte("abc\xff"), "0x61 0x62 0x63 0xff"},
+ {"%# X", []byte("abc\xff"), "0X61 0X62 0X63 0XFF"},
{"% X", []byte("abc\xff"), "61 62 63 FF"},
{"%x", []byte("xyz"), "78797a"},
{"%X", []byte("xyz"), "78797A"},
@@ -172,6 +178,8 @@ var fmttests = []struct {
{"%.3q", "日本語日本語", `"日本語"`},
{"%.3q", []byte("日本語日本語"), `"日本語"`},
{"%10.1q", "日本語日本語", ` "日"`},
+ {"%10v", nil, " <nil>"},
+ {"%-10v", nil, "<nil> "},
// integers
{"%d", 12345, "12345"},
@@ -328,14 +336,18 @@ var fmttests = []struct {
// arrays
{"%v", array, "[1 2 3 4 5]"},
{"%v", iarray, "[1 hello 2.5 <nil>]"},
+ {"%v", barray, "[1 2 3 4 5]"},
{"%v", &array, "&[1 2 3 4 5]"},
{"%v", &iarray, "&[1 hello 2.5 <nil>]"},
+ {"%v", &barray, "&[1 2 3 4 5]"},
// slices
{"%v", slice, "[1 2 3 4 5]"},
{"%v", islice, "[1 hello 2.5 <nil>]"},
+ {"%v", bslice, "[1 2 3 4 5]"},
{"%v", &slice, "&[1 2 3 4 5]"},
{"%v", &islice, "&[1 hello 2.5 <nil>]"},
+ {"%v", &bslice, "&[1 2 3 4 5]"},
// complexes with %v
{"%v", 1 + 2i, "(1+2i)"},
@@ -350,10 +362,12 @@ var fmttests = []struct {
{"%+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
+ // other formats on Stringable items
{"%s", I(23), `<23>`},
{"%q", I(23), `"<23>"`},
{"%x", I(23), `3c32333e`},
+ {"%#x", I(23), `0x3c0x320x330x3e`},
+ {"%# x", I(23), `0x3c 0x32 0x33 0x3e`},
{"%d", I(23), `23`}, // Stringer applies only to string formats.
// go syntax
@@ -375,6 +389,9 @@ var fmttests = []struct {
{"%#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{}`},
+ {"%#v", "foo", `"foo"`},
+ {"%#v", barray, `[5]fmt_test.renamedUint8{0x1, 0x2, 0x3, 0x4, 0x5}`},
+ {"%#v", bslice, `[]fmt_test.renamedUint8{0x1, 0x2, 0x3, 0x4, 0x5}`},
// slices with other formats
{"%#x", []int{1, 2, 15}, `[0x1 0x2 0xf]`},
@@ -400,6 +417,9 @@ var fmttests = []struct {
{"%x", renamedString("thing"), "7468696e67"},
{"%d", renamedBytes([]byte{1, 2, 15}), `[1 2 15]`},
{"%q", renamedBytes([]byte("hello")), `"hello"`},
+ {"%x", []renamedUint8{'a', 'b', 'c'}, "616263"},
+ {"%s", []renamedUint8{'h', 'e', 'l', 'l', 'o'}, "hello"},
+ {"%q", []renamedUint8{'h', 'e', 'l', 'l', 'o'}, `"hello"`},
{"%v", renamedFloat32(22), "22"},
{"%v", renamedFloat64(33), "33"},
{"%v", renamedComplex64(3 + 4i), "(3+4i)"},
@@ -419,6 +439,8 @@ var fmttests = []struct {
{"%T", renamedComplex128(4 - 3i), "fmt_test.renamedComplex128"},
{"%T", intVal, "int"},
{"%6T", &intVal, " *int"},
+ {"%10T", nil, " <nil>"},
+ {"%-10T", nil, "<nil> "},
// %p
{"p0=%p", new(int), "p0=0xPTR"},
@@ -441,6 +463,11 @@ var fmttests = []struct {
{"%v", (*int)(nil), "<nil>"},
{"%v", new(int), "0xPTR"},
+ // %d etc. pointers use specified base.
+ {"%d", new(int), "PTR_d"},
+ {"%o", new(int), "PTR_o"},
+ {"%x", new(int), "PTR_x"},
+
// %d on Stringer should give integer if possible
{"%s", time.Time{}.Month(), "January"},
{"%d", time.Time{}.Month(), "1"},
@@ -464,20 +491,37 @@ var fmttests = []struct {
// Used to crash because nByte didn't allow for a sign.
{"%b", int64(-1 << 63), "-1000000000000000000000000000000000000000000000000000000000000000"},
+
+ // Complex fmt used to leave the plus flag set for future entries in the array
+ // causing +2+0i and +3+0i instead of 2+0i and 3+0i.
+ {"%v", []complex64{1, 2, 3}, "[(1+0i) (2+0i) (3+0i)]"},
+ {"%v", []complex128{1, 2, 3}, "[(1+0i) (2+0i) (3+0i)]"},
}
func TestSprintf(t *testing.T) {
for _, tt := range fmttests {
s := Sprintf(tt.fmt, tt.val)
if i := strings.Index(tt.out, "PTR"); i >= 0 {
+ pattern := "PTR"
+ chars := "0123456789abcdefABCDEF"
+ switch {
+ case strings.HasPrefix(tt.out[i:], "PTR_d"):
+ pattern = "PTR_d"
+ chars = chars[:10]
+ case strings.HasPrefix(tt.out[i:], "PTR_o"):
+ pattern = "PTR_o"
+ chars = chars[:8]
+ case strings.HasPrefix(tt.out[i:], "PTR_x"):
+ pattern = "PTR_x"
+ }
j := i
for ; j < len(s); j++ {
c := s[j]
- if (c < '0' || c > '9') && (c < 'a' || c > 'f') && (c < 'A' || c > 'F') {
+ if !strings.ContainsRune(chars, rune(c)) {
break
}
}
- s = s[0:i] + "PTR" + s[j:]
+ s = s[0:i] + pattern + s[j:]
}
if s != tt.out {
if _, ok := tt.val.(string); ok {
@@ -527,6 +571,14 @@ func BenchmarkSprintfFloat(b *testing.B) {
}
}
+func BenchmarkManyArgs(b *testing.B) {
+ var buf bytes.Buffer
+ for i := 0; i < b.N; i++ {
+ buf.Reset()
+ Fprintf(&buf, "%2d/%2d/%2d %d:%d:%d %s %s\n", 3, 4, 5, 11, 12, 13, "hello", "world")
+ }
+}
+
var mallocBuf bytes.Buffer
var mallocTest = []struct {
@@ -550,17 +602,9 @@ var _ bytes.Buffer
func TestCountMallocs(t *testing.T) {
for _, mt := range mallocTest {
- const N = 100
- memstats := new(runtime.MemStats)
- runtime.ReadMemStats(memstats)
- mallocs := 0 - memstats.Mallocs
- for i := 0; i < N; i++ {
- mt.fn()
- }
- runtime.ReadMemStats(memstats)
- mallocs += memstats.Mallocs
- if mallocs/N > uint64(mt.count) {
- t.Errorf("%s: expected %d mallocs, got %d", mt.desc, mt.count, mallocs/N)
+ mallocs := testing.AllocsPerRun(100, mt.fn)
+ if got, max := mallocs, float64(mt.count); got > max {
+ t.Errorf("%s: got %v allocs, want <=%v", mt.desc, got, max)
}
}
}
@@ -636,7 +680,8 @@ func TestStructPrinter(t *testing.T) {
}
}
-// Check map printing using substrings so we don't depend on the print order.
+// presentInMap checks map printing using substrings so we don't depend on the
+// print order.
func presentInMap(s string, a []string, t *testing.T) {
for i := 0; i < len(a); i++ {
loc := strings.Index(s, a[i])
@@ -677,8 +722,8 @@ func TestEmptyMap(t *testing.T) {
}
}
-// Check that Sprint (and hence Print, Fprint) puts spaces in the right places,
-// that is, between arg pairs in which neither is a string.
+// TestBlank checks that Sprint (and hence Print, Fprint) puts spaces in the
+// right places, that is, between arg pairs in which neither is a string.
func TestBlank(t *testing.T) {
got := Sprint("<", 1, ">:", 1, 2, 3, "!")
expect := "<1>:1 2 3!"
@@ -687,8 +732,8 @@ func TestBlank(t *testing.T) {
}
}
-// Check that Sprintln (and hence Println, Fprintln) puts spaces in the right places,
-// that is, between all arg pairs.
+// TestBlankln checks that Sprintln (and hence Println, Fprintln) puts spaces in
+// the right places, that is, between all arg pairs.
func TestBlankln(t *testing.T) {
got := Sprintln("<", 1, ">:", 1, 2, 3, "!")
expect := "< 1 >: 1 2 3 !\n"
@@ -697,7 +742,7 @@ func TestBlankln(t *testing.T) {
}
}
-// Check Formatter with Sprint, Sprintln, Sprintf
+// TestFormatterPrintln checks Formatter with Sprint, Sprintln, Sprintf.
func TestFormatterPrintln(t *testing.T) {
f := F(1)
expect := "<v=F(1)>\n"
@@ -746,7 +791,7 @@ func TestWidthAndPrecision(t *testing.T) {
}
}
-// A type that panics in String.
+// Panic is a type that panics in String.
type Panic struct {
message interface{}
}
@@ -761,7 +806,7 @@ func (p Panic) String() string {
panic(p.message)
}
-// A type that panics in Format.
+// PanicF is a type that panics in Format.
type PanicF struct {
message interface{}
}
@@ -799,7 +844,7 @@ func TestPanics(t *testing.T) {
}
}
-// Test that erroneous String routine doesn't cause fatal recursion.
+// recurCount tests that erroneous String routine doesn't cause fatal recursion.
var recurCount = 0
type Recur struct {
@@ -842,3 +887,15 @@ func TestIsSpace(t *testing.T) {
}
}
}
+
+func TestNilDoesNotBecomeTyped(t *testing.T) {
+ type A struct{}
+ type B struct{}
+ var a *A = nil
+ var b B = B{}
+ got := Sprintf("%s %s %s %s %s", nil, a, nil, b, nil)
+ const expect = "%!s(<nil>) %!s(*fmt_test.A=<nil>) %!s(<nil>) {} %!s(<nil>)"
+ if got != expect {
+ t.Errorf("expected:\n\t%q\ngot:\n\t%q", expect, got)
+ }
+}
diff --git a/src/pkg/fmt/format.go b/src/pkg/fmt/format.go
index caf900d5c..5665db12c 100644
--- a/src/pkg/fmt/format.go
+++ b/src/pkg/fmt/format.go
@@ -72,7 +72,7 @@ func (f *fmt) init(buf *buffer) {
f.clearflags()
}
-// Compute left and right padding widths (only one will be non-zero).
+// computePadding computes left and right padding widths (only one will be non-zero).
func (f *fmt) computePadding(width int) (padding []byte, leftWidth, rightWidth int) {
left := !f.minus
w := f.wid
@@ -95,7 +95,7 @@ func (f *fmt) computePadding(width int) (padding []byte, leftWidth, rightWidth i
return
}
-// Generate n bytes of padding.
+// writePadding generates n bytes of padding.
func (f *fmt) writePadding(n int, padding []byte) {
for n > 0 {
m := n
@@ -107,14 +107,13 @@ func (f *fmt) writePadding(n int, padding []byte) {
}
}
-// Append b to f.buf, padded on left (w > 0) or right (w < 0 or f.minus)
-// clear flags afterwards.
+// pad appends b to f.buf, padded on left (w > 0) or right (w < 0 or f.minus).
func (f *fmt) pad(b []byte) {
- var padding []byte
- var left, right int
- if f.widPresent && f.wid != 0 {
- padding, left, right = f.computePadding(len(b))
+ if !f.widPresent || f.wid == 0 {
+ f.buf.Write(b)
+ return
}
+ padding, left, right := f.computePadding(len(b))
if left > 0 {
f.writePadding(left, padding)
}
@@ -124,14 +123,13 @@ func (f *fmt) pad(b []byte) {
}
}
-// append s to buf, padded on left (w > 0) or right (w < 0 or f.minus).
-// clear flags afterwards.
+// padString appends s to buf, padded on left (w > 0) or right (w < 0 or f.minus).
func (f *fmt) padString(s string) {
- var padding []byte
- var left, right int
- if f.widPresent && f.wid != 0 {
- padding, left, right = f.computePadding(utf8.RuneCountInString(s))
+ if !f.widPresent || f.wid == 0 {
+ f.buf.WriteString(s)
+ return
}
+ padding, left, right := f.computePadding(utf8.RuneCountInString(s))
if left > 0 {
f.writePadding(left, padding)
}
@@ -141,17 +139,6 @@ func (f *fmt) padString(s string) {
}
}
-func putint(buf []byte, base, val uint64, digits string) int {
- i := len(buf) - 1
- for val >= base {
- buf[i] = digits[val%base]
- i--
- val /= base
- }
- buf[i] = digits[val]
- return i - 1
-}
-
var (
trueBytes = []byte("true")
falseBytes = []byte("false")
@@ -285,18 +272,41 @@ func (f *fmt) fmt_s(s string) {
f.padString(s)
}
-// fmt_sx formats a string as a hexadecimal encoding of its bytes.
-func (f *fmt) fmt_sx(s, digits string) {
+// fmt_sbx formats a string or byte slice as a hexadecimal encoding of its bytes.
+func (f *fmt) fmt_sbx(s string, b []byte, digits string) {
+ n := len(b)
+ if b == nil {
+ n = len(s)
+ }
+ x := digits[10] - 'a' + 'x'
// TODO: Avoid buffer by pre-padding.
- var b []byte
- for i := 0; i < len(s); i++ {
+ var buf []byte
+ for i := 0; i < n; i++ {
if i > 0 && f.space {
- b = append(b, ' ')
+ buf = append(buf, ' ')
}
- v := s[i]
- b = append(b, digits[v>>4], digits[v&0xF])
+ if f.sharp {
+ buf = append(buf, '0', x)
+ }
+ var c byte
+ if b == nil {
+ c = s[i]
+ } else {
+ c = b[i]
+ }
+ buf = append(buf, digits[c>>4], digits[c&0xF])
}
- f.pad(b)
+ f.pad(buf)
+}
+
+// fmt_sx formats a string as a hexadecimal encoding of its bytes.
+func (f *fmt) fmt_sx(s, digits string) {
+ f.fmt_sbx(s, nil, digits)
+}
+
+// fmt_bx formats a byte slice as a hexadecimal encoding of its bytes.
+func (f *fmt) fmt_bx(b []byte, digits string) {
+ f.fmt_sbx("", b, digits)
}
// fmt_q formats a string as a double-quoted, escaped Go string constant.
@@ -373,7 +383,7 @@ 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.formatFloat(v, 'g', doPrec(f, -1), 64) }
-// fmt_g64 formats a float64 in the 'f' or 'E' form according to size.
+// fmt_G64 formats a float64 in the 'f' or 'E' form according to size.
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).
@@ -405,6 +415,7 @@ func (f *fmt) fmt_fb32(v float32) { f.formatFloat(float64(v), 'b', 0, 32) }
func (f *fmt) fmt_c64(v complex64, verb rune) {
f.buf.WriteByte('(')
r := real(v)
+ oldPlus := f.plus
for i := 0; ; i++ {
switch verb {
case 'e':
@@ -424,6 +435,7 @@ func (f *fmt) fmt_c64(v complex64, verb rune) {
f.plus = true
r = imag(v)
}
+ f.plus = oldPlus
f.buf.Write(irparenBytes)
}
@@ -431,6 +443,7 @@ func (f *fmt) fmt_c64(v complex64, verb rune) {
func (f *fmt) fmt_c128(v complex128, verb rune) {
f.buf.WriteByte('(')
r := real(v)
+ oldPlus := f.plus
for i := 0; ; i++ {
switch verb {
case 'e':
@@ -450,5 +463,6 @@ func (f *fmt) fmt_c128(v complex128, verb rune) {
f.plus = true
r = imag(v)
}
+ f.plus = oldPlus
f.buf.Write(irparenBytes)
}
diff --git a/src/pkg/fmt/print.go b/src/pkg/fmt/print.go
index 13438243c..7d7aa93b2 100644
--- a/src/pkg/fmt/print.go
+++ b/src/pkg/fmt/print.go
@@ -26,8 +26,8 @@ var (
extraBytes = []byte("%!(EXTRA ")
irparenBytes = []byte("i)")
bytesBytes = []byte("[]byte{")
- widthBytes = []byte("%!(BADWIDTH)")
- precBytes = []byte("%!(BADPREC)")
+ badWidthBytes = []byte("%!(BADWIDTH)")
+ badPrecBytes = []byte("%!(BADPREC)")
noVerbBytes = []byte("%!(NOVERB)")
)
@@ -153,7 +153,7 @@ func newCache(f func() interface{}) *cache {
var ppFree = newCache(func() interface{} { return new(pp) })
-// Allocate a new pp struct or grab a cached one.
+// newPrinter allocates a new pp struct or grab a cached one.
func newPrinter() *pp {
p := ppFree.get().(*pp)
p.panicking = false
@@ -162,7 +162,7 @@ func newPrinter() *pp {
return p
}
-// Save used pp structs in ppFree; avoids an allocation per invocation.
+// free saves used pp structs in ppFree; avoids an allocation per invocation.
func (p *pp) free() {
// Don't hold on to pp structs with large buffers.
if cap(p.buf) > 1024 {
@@ -231,7 +231,7 @@ func Sprintf(format string, a ...interface{}) string {
return s
}
-// Errorf formats according to a format specifier and returns the string
+// Errorf formats according to a format specifier and returns the string
// as a value that satisfies error.
func Errorf(format string, a ...interface{}) error {
return errors.New(Sprintf(format, a...))
@@ -299,7 +299,7 @@ func Sprintln(a ...interface{}) string {
return s
}
-// Get the i'th arg of the struct value.
+// getField gets the i'th arg of the struct value.
// If the arg itself is an interface, return a value for
// the thing inside the interface, not the interface itself.
func getField(v reflect.Value, i int) reflect.Value {
@@ -310,7 +310,7 @@ func getField(v reflect.Value, i int) reflect.Value {
return val
}
-// Convert ASCII to integer. n is 0 (and got is false) if no number present.
+// parsenum converts ASCII to integer. num is 0 (and isnum is false) if no number present.
func parsenum(s string, start, end int) (num int, isnum bool, newi int) {
if start >= end {
return 0, false, end
@@ -545,10 +545,15 @@ func (p *pp) fmtString(v string, verb rune, goSyntax bool) {
}
}
-func (p *pp) fmtBytes(v []byte, verb rune, goSyntax bool, depth int) {
+func (p *pp) fmtBytes(v []byte, verb rune, goSyntax bool, typ reflect.Type, depth int) {
if verb == 'v' || verb == 'd' {
if goSyntax {
- p.buf.Write(bytesBytes)
+ if typ == nil {
+ p.buf.Write(bytesBytes)
+ } else {
+ p.buf.WriteString(typ.String())
+ p.buf.WriteByte('{')
+ }
} else {
p.buf.WriteByte('[')
}
@@ -569,24 +574,27 @@ func (p *pp) fmtBytes(v []byte, verb rune, goSyntax bool, depth int) {
}
return
}
- s := string(v)
switch verb {
case 's':
- p.fmt.fmt_s(s)
+ p.fmt.fmt_s(string(v))
case 'x':
- p.fmt.fmt_sx(s, ldigits)
+ p.fmt.fmt_bx(v, ldigits)
case 'X':
- p.fmt.fmt_sx(s, udigits)
+ p.fmt.fmt_bx(v, udigits)
case 'q':
- p.fmt.fmt_q(s)
+ p.fmt.fmt_q(string(v))
default:
p.badVerb(verb)
}
}
func (p *pp) fmtPointer(value reflect.Value, verb rune, goSyntax bool) {
+ use0x64 := true
switch verb {
- case 'p', 'v', 'b', 'd', 'o', 'x', 'X':
+ case 'p', 'v':
+ // ok
+ case 'b', 'd', 'o', 'x', 'X':
+ use0x64 = false
// ok
default:
p.badVerb(verb)
@@ -616,7 +624,11 @@ func (p *pp) fmtPointer(value reflect.Value, verb rune, goSyntax bool) {
} else if verb == 'v' && u == 0 {
p.buf.Write(nilAngleBytes)
} else {
- p.fmt0x64(uint64(u), !p.fmt.sharp)
+ if use0x64 {
+ p.fmt0x64(uint64(u), !p.fmt.sharp)
+ } else {
+ p.fmtUint64(uint64(u), verb, false)
+ }
}
}
@@ -712,17 +724,18 @@ func (p *pp) handleMethods(verb rune, plus, goSyntax bool, depth int) (wasString
}
func (p *pp) printField(field interface{}, verb rune, plus, goSyntax bool, depth int) (wasString bool) {
+ p.field = field
+ p.value = reflect.Value{}
+
if field == nil {
if verb == 'T' || verb == 'v' {
- p.buf.Write(nilAngleBytes)
+ p.fmt.pad(nilAngleBytes)
} else {
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 {
@@ -734,8 +747,17 @@ func (p *pp) printField(field interface{}, verb rune, plus, goSyntax bool, depth
return false
}
- if wasString, handled := p.handleMethods(verb, plus, goSyntax, depth); handled {
- return wasString
+ // Clear flags for base formatters.
+ // handleMethods needs them, so we must restore them later.
+ // We could call handleMethods here and avoid this work, but
+ // handleMethods is expensive enough to be worth delaying.
+ oldPlus := p.fmt.plus
+ oldSharp := p.fmt.sharp
+ if plus {
+ p.fmt.plus = false
+ }
+ if goSyntax {
+ p.fmt.sharp = false
}
// Some types can be done without reflection.
@@ -776,9 +798,16 @@ func (p *pp) printField(field interface{}, verb rune, plus, goSyntax bool, depth
p.fmtString(f, verb, goSyntax)
wasString = verb == 's' || verb == 'v'
case []byte:
- p.fmtBytes(f, verb, goSyntax, depth)
+ p.fmtBytes(f, verb, goSyntax, nil, depth)
wasString = verb == 's'
default:
+ // Restore flags in case handleMethods finds a Formatter.
+ p.fmt.plus = oldPlus
+ p.fmt.sharp = oldSharp
+ // If the type is not simple, it might have methods.
+ if wasString, handled := p.handleMethods(verb, plus, goSyntax, depth); handled {
+ return wasString
+ }
// Need to use reflection
return p.printReflectValue(reflect.ValueOf(field), verb, plus, goSyntax, depth)
}
@@ -915,19 +944,22 @@ BigSwitch:
}
case reflect.Array, reflect.Slice:
// Byte slices are special.
- if f.Type().Elem().Kind() == reflect.Uint8 {
- // We know it's a slice of bytes, but we also know it does not have static type
- // []byte, or it would have been caught above. Therefore we cannot convert
- // it directly in the (slightly) obvious way: f.Interface().([]byte); it doesn't have
- // that type, and we can't write an expression of the right type and do a
- // conversion because we don't have a static way to write the right type.
- // So we build a slice by hand. This is a rare case but it would be nice
- // if reflection could help a little more.
- bytes := make([]byte, f.Len())
- for i := range bytes {
- bytes[i] = byte(f.Index(i).Uint())
+ if typ := f.Type(); typ.Elem().Kind() == reflect.Uint8 {
+ var bytes []byte
+ if f.Kind() == reflect.Slice {
+ bytes = f.Bytes()
+ } else if f.CanAddr() {
+ bytes = f.Slice(0, f.Len()).Bytes()
+ } else {
+ // We have an array, but we cannot Slice() a non-addressable array,
+ // so we build a slice by hand. This is a rare case but it would be nice
+ // if reflection could help a little more.
+ bytes = make([]byte, f.Len())
+ for i := range bytes {
+ bytes[i] = byte(f.Index(i).Uint())
+ }
}
- p.fmtBytes(bytes, verb, goSyntax, depth)
+ p.fmtBytes(bytes, verb, goSyntax, typ, depth)
wasString = verb == 's'
break
}
@@ -1033,7 +1065,7 @@ func (p *pp) doPrintf(format string, a []interface{}) {
if i < end && format[i] == '*' {
p.fmt.wid, p.fmt.widPresent, i, fieldnum = intFromArg(a, end, i, fieldnum)
if !p.fmt.widPresent {
- p.buf.Write(widthBytes)
+ p.buf.Write(badWidthBytes)
}
} else {
p.fmt.wid, p.fmt.widPresent, i = parsenum(format, i, end)
@@ -1043,7 +1075,7 @@ func (p *pp) doPrintf(format string, a []interface{}) {
if format[i+1] == '*' {
p.fmt.prec, p.fmt.precPresent, i, fieldnum = intFromArg(a, end, i+1, fieldnum)
if !p.fmt.precPresent {
- p.buf.Write(precBytes)
+ p.buf.Write(badPrecBytes)
}
} else {
p.fmt.prec, p.fmt.precPresent, i = parsenum(format, i+1, end)
@@ -1099,7 +1131,7 @@ func (p *pp) doPrint(a []interface{}, addspace, addnewline bool) {
prevString := false
for fieldnum := 0; fieldnum < len(a); fieldnum++ {
p.fmt.clearflags()
- // always add spaces if we're doing println
+ // always add spaces if we're doing Println
field := a[fieldnum]
if fieldnum > 0 {
isString := field != nil && reflect.TypeOf(field).Kind() == reflect.String
diff --git a/src/pkg/fmt/scan.go b/src/pkg/fmt/scan.go
index 0b3e04069..bf888c4d8 100644
--- a/src/pkg/fmt/scan.go
+++ b/src/pkg/fmt/scan.go
@@ -33,8 +33,8 @@ type ScanState interface {
ReadRune() (r rune, size int, err error)
// UnreadRune causes the next call to ReadRune to return the same rune.
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
+ // 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.
SkipSpace()
// Token skips space in the input if skipSpace is true, then returns the
@@ -312,8 +312,9 @@ func notSpace(r rune) bool {
return !isSpace(r)
}
-// skipSpace provides Scan() methods the ability to skip space and newline characters
-// in keeping with the current scanning mode set by format strings and Scan()/Scanln().
+// SkipSpace provides Scan methods the ability to skip space and newline
+// characters in keeping with the current scanning mode set by format strings
+// and Scan/Scanln.
func (s *ss) SkipSpace() {
s.skipSpace(false)
}
@@ -337,7 +338,10 @@ func (r *readRune) readByte() (b byte, err error) {
r.pending--
return
}
- _, err = r.reader.Read(r.pendBuf[0:1])
+ n, err := io.ReadFull(r.reader, r.pendBuf[0:1])
+ if n != 1 {
+ return 0, err
+ }
return r.pendBuf[0], err
}
@@ -378,7 +382,7 @@ func (r *readRune) ReadRune() (rr rune, size int, err error) {
var ssFree = newCache(func() interface{} { return new(ss) })
-// Allocate a new ss struct or grab a cached one.
+// newScanState allocates a new ss struct or grab a cached one.
func newScanState(r io.Reader, nlIsSpace, nlIsEnd bool) (s *ss, old ssave) {
// If the reader is a *ss, then we've got a recursive
// call to Scan, so re-use the scan state.
@@ -410,7 +414,7 @@ func newScanState(r io.Reader, nlIsSpace, nlIsEnd bool) (s *ss, old ssave) {
return
}
-// Save used ss structs in ssFree; avoid an allocation per invocation.
+// free saves used ss structs in ssFree; avoid an allocation per invocation.
func (s *ss) free(old ssave) {
// If it was used recursively, just restore the old state.
if old.validSave {
@@ -1090,7 +1094,8 @@ func (s *ss) advance(format string) (i int) {
// There was space in the format, so there should be space (EOF)
// in the input.
inputc := s.getRune()
- if inputc == eof {
+ if inputc == eof || inputc == '\n' {
+ // If we've reached a newline, stop now; don't read ahead.
return
}
if !isSpace(inputc) {
diff --git a/src/pkg/fmt/scan_test.go b/src/pkg/fmt/scan_test.go
index 320857b73..4e2c0feb2 100644
--- a/src/pkg/fmt/scan_test.go
+++ b/src/pkg/fmt/scan_test.go
@@ -626,7 +626,7 @@ func TestScanlnWithMiddleNewline(t *testing.T) {
}
}
-// Special Reader that counts reads at end of file.
+// eofCounter is a special Reader that counts reads at end of file.
type eofCounter struct {
reader *strings.Reader
eofCount int
@@ -640,8 +640,8 @@ func (ec *eofCounter) Read(b []byte) (n int, err error) {
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
+// TestEOF verifies 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
@@ -668,7 +668,7 @@ func TestEOF(t *testing.T) {
}
}
-// Verify that we see an EOF error if we run out of input.
+// TestEOFAtEndOfInput verifies that we see an EOF error if we run out of input.
// This was a buglet: we used to get "expected integer".
func TestEOFAtEndOfInput(t *testing.T) {
var i, j int
@@ -730,7 +730,8 @@ func TestEOFAllTypes(t *testing.T) {
}
}
-// Verify that, at least when using bufio, successive calls to Fscan do not lose runes.
+// TestUnreadRuneWithBufio verifies 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
@@ -753,7 +754,7 @@ func TestUnreadRuneWithBufio(t *testing.T) {
type TwoLines string
-// Attempt to read two lines into the object. Scanln should prevent this
+// Scan attempts 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 rune) error {
chars := make([]rune, 0, 100)
@@ -810,6 +811,34 @@ func TestMultiLine(t *testing.T) {
}
}
+// simpleReader is a strings.Reader that implements only Read, not ReadRune.
+// Good for testing readahead.
+type simpleReader struct {
+ sr *strings.Reader
+}
+
+func (s *simpleReader) Read(b []byte) (n int, err error) {
+ return s.sr.Read(b)
+}
+
+// TestLineByLineFscanf tests that Fscanf does not read past newline. Issue
+// 3481.
+func TestLineByLineFscanf(t *testing.T) {
+ r := &simpleReader{strings.NewReader("1\n2\n")}
+ var i, j int
+ n, err := Fscanf(r, "%v\n", &i)
+ if n != 1 || err != nil {
+ t.Fatalf("first read: %d %q", n, err)
+ }
+ n, err = Fscanf(r, "%v\n", &j)
+ if n != 1 || err != nil {
+ t.Fatalf("second read: %d %q", n, err)
+ }
+ if i != 1 || j != 2 {
+ t.Errorf("wrong values; wanted 1 2 got %d %d", i, j)
+ }
+}
+
// RecursiveInt accepts a string matching %d.%d.%d....
// and parses it into a linked list.
// It allows us to benchmark recursive descent style scanners.
@@ -835,7 +864,7 @@ func (r *RecursiveInt) Scan(state ScanState, verb rune) (err error) {
return
}
-// Perform the same scanning task as RecursiveInt.Scan
+// scanInts performs 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 error) {