aboutsummaryrefslogtreecommitdiff
path: root/libgo/go/fmt
diff options
context:
space:
mode:
authorIan Lance Taylor <ian@gcc.gnu.org>2015-10-31 00:59:47 +0000
committerIan Lance Taylor <ian@gcc.gnu.org>2015-10-31 00:59:47 +0000
commitaf146490bb04205107cb23e301ec7a8ff927b5fc (patch)
tree13beeaed3698c61903fe93fb1ce70bd9b18d4e7f /libgo/go/fmt
parent725e1be3406315d9bcc8195d7eef0a7082b3c7cc (diff)
downloadgcc-af146490bb04205107cb23e301ec7a8ff927b5fc.zip
gcc-af146490bb04205107cb23e301ec7a8ff927b5fc.tar.gz
gcc-af146490bb04205107cb23e301ec7a8ff927b5fc.tar.bz2
runtime: Remove now unnecessary pad field from ParFor.
It is not needed due to the removal of the ctx field. Reviewed-on: https://go-review.googlesource.com/16525 From-SVN: r229616
Diffstat (limited to 'libgo/go/fmt')
-rw-r--r--libgo/go/fmt/doc.go77
-rw-r--r--libgo/go/fmt/fmt_test.go116
-rw-r--r--libgo/go/fmt/format.go25
-rw-r--r--libgo/go/fmt/norace_test.go9
-rw-r--r--libgo/go/fmt/print.go40
-rw-r--r--libgo/go/fmt/race_test.go9
-rw-r--r--libgo/go/fmt/scan.go103
-rw-r--r--libgo/go/fmt/scan_test.go168
8 files changed, 450 insertions, 97 deletions
diff --git a/libgo/go/fmt/doc.go b/libgo/go/fmt/doc.go
index ee54463..ef91368 100644
--- a/libgo/go/fmt/doc.go
+++ b/libgo/go/fmt/doc.go
@@ -40,7 +40,7 @@
%F synonym for %f
%g %e for large exponents, %f otherwise
%G %E for large exponents, %F otherwise
- String and slice of bytes:
+ String and slice of bytes (treated equivalently with these verbs):
%s the uninterpreted bytes of the string or slice
%q a double-quoted string safely escaped with Go syntax
%x base 16, lower-case, two characters per byte
@@ -66,13 +66,13 @@
maps: map[key1:value1 key2:value2]
pointer to above: &{}, &[], &map[]
- Width is specified by an optional decimal number immediately following the verb.
+ Width is specified by an optional decimal number immediately preceding the verb.
If absent, the width is whatever is necessary to represent the value.
Precision is specified after the (optional) width by a period followed by a
decimal number. If no period is present, a default precision is used.
A period with no following number specifies a precision of zero.
Examples:
- %f: default width, default precision
+ %f default width, default precision
%9f width 9, default precision
%.2f default width, precision 2
%9.2f width 9, precision 2
@@ -138,20 +138,23 @@
formatting considerations apply for operands that implement
certain interfaces. In order of application:
- 1. If an operand implements the Formatter interface, it will
+ 1. If the operand is a reflect.Value, the concrete value it
+ holds is printed as if it was the operand.
+
+ 2. If an operand implements the Formatter interface, it will
be invoked. Formatter provides fine control of formatting.
- 2. If the %v verb is used with the # flag (%#v) and the operand
+ 3. If the %v verb is used with the # flag (%#v) and the operand
implements the GoStringer interface, that will be invoked.
If the format (which is implicitly %v for Println etc.) is valid
for a string (%s %q %v %x %X), the following two rules apply:
- 3. If an operand implements the error interface, the Error method
+ 4. If an operand implements the error interface, the Error method
will be invoked to convert the object to a string, which will then
be formatted as required by the verb (if any).
- 4. If an operand implements method String() string, that method
+ 5. If an operand implements method String() string, that method
will be invoked to convert the object to a string, which will then
be formatted as required by the verb (if any).
@@ -161,6 +164,9 @@
of strings, and %6.2f will control formatting for each element
of a floating-point array.
+ However, when printing a byte slice with a string-like verb
+ (%s %q %x %X), it is treated identically to a string, as a single item.
+
To avoid recursion in cases such as
type X string
func (x X) String() string { return Sprintf("<%s>", x) }
@@ -178,8 +184,8 @@
However, the notation [n] immediately before the verb indicates that the
nth one-indexed argument is to be formatted instead. The same notation
before a '*' for a width or precision selects the argument index holding
- the value. After processing a bracketed expression [n], arguments n+1,
- n+2, etc. will be processed unless otherwise directed.
+ the value. After processing a bracketed expression [n], subsequent verbs
+ will use arguments n+1, n+2, etc. unless otherwise directed.
For example,
fmt.Sprintf("%[2]d %[1]d\n", 11, 22)
@@ -225,18 +231,33 @@
%!s(PANIC=bad)
The %!s just shows the print verb in use when the failure
- occurred.
+ occurred. If the panic is caused by a nil receiver to an Error
+ or String method, however, the output is the undecorated
+ string, "<nil>".
Scanning
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 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; Scanf, Fscanf and Sscanf require
- newlines in the input to match newlines in the format; the other
- routines treat newlines as spaces.
+ Sscanf and Sscanln read from an argument string.
+
+ Scan, Fscan, Sscan treat newlines in the input as spaces.
+
+ Scanln, Fscanln and Sscanln stop scanning at a newline and
+ require that the items be followed by a newline or EOF.
+
+ Scanf, Fscanf and Sscanf require that (after skipping spaces)
+ newlines in the format are matched by newlines in the input
+ and vice versa. This behavior differs from the corresponding
+ routines in C, which uniformly treat newlines as spaces.
+
+ When scanning with Scanf, Fscanf, and Sscanf, all non-empty
+ runs of space characters (except newline) are equivalent
+ to a single space in both the format and the input. With
+ that proviso, text in the format string must match the input
+ text; scanning stops if it does not, with the return value
+ of the function indicating the number of arguments scanned.
Scanf, Fscanf, and Sscanf parse the arguments according to a
format string, analogous to that of Printf. For example, %x
@@ -253,20 +274,18 @@
Flags # and + are not implemented.
The familiar base-setting prefixes 0 (octal) and 0x
- (hexadecimal) are accepted when scanning integers without a
- format or with the %v verb.
-
- Width is interpreted in the input text (%5s means at most
- five runes of input will be read to scan a string) but there
- is no syntax for scanning with a precision (no %5.2f, just
- %5f).
-
- When scanning with a format, all non-empty runs of space
- characters (except newline) are equivalent to a single
- space in both the format and the input. With that proviso,
- text in the format string must match the input text; scanning
- stops if it does not, with the return value of the function
- indicating the number of arguments scanned.
+ (hexadecimal) are accepted when scanning integers without
+ a format or with the %v verb.
+
+ Width is interpreted in the input text but there is no
+ syntax for scanning with a precision (no %5.2f, just %5f).
+ If width is provided, it applies after leading spaces are
+ trimmed and specifies the maximum number of runes to read
+ to satisfy the verb. For example,
+ Sscanf(" 1234567 ", "%5s%d", &s, &i)
+ will set s to "12345" and i to 67 while
+ Sscanf(" 12 34 567 ", "%5s%d", &s, &i)
+ will set s to "12" and i to 34.
In all the scanning functions, a carriage return followed
immediately by a newline is treated as a plain newline
diff --git a/libgo/go/fmt/fmt_test.go b/libgo/go/fmt/fmt_test.go
index ccd8090..8f3587b 100644
--- a/libgo/go/fmt/fmt_test.go
+++ b/libgo/go/fmt/fmt_test.go
@@ -9,6 +9,7 @@ import (
. "fmt"
"io"
"math"
+ "reflect"
"runtime"
"strings"
"testing"
@@ -135,27 +136,33 @@ var fmtTests = []struct {
// basic string
{"%s", "abc", "abc"},
+ {"%q", "abc", `"abc"`},
{"%x", "abc", "616263"},
+ {"%x", "\xff\xf0\x0f\xff", "fff00fff"},
+ {"%X", "\xff\xf0\x0f\xff", "FFF00FFF"},
{"%x", "xyz", "78797a"},
{"%X", "xyz", "78797A"},
- {"%q", "abc", `"abc"`},
- {"%#x", []byte("abc\xff"), "0x616263ff"},
- {"%#X", []byte("abc\xff"), "0X616263FF"},
- {"%# x", []byte("abc\xff"), "0x61 0x62 0x63 0xff"},
- {"%# X", []byte("abc\xff"), "0X61 0X62 0X63 0XFF"},
+ {"% x", "xyz", "78 79 7a"},
+ {"% X", "xyz", "78 79 7A"},
+ {"%#x", "xyz", "0x78797a"},
+ {"%#X", "xyz", "0X78797A"},
+ {"%# x", "xyz", "0x78 0x79 0x7a"},
+ {"%# X", "xyz", "0X78 0X79 0X7A"},
// basic bytes
{"%s", []byte("abc"), "abc"},
+ {"%q", []byte("abc"), `"abc"`},
{"%x", []byte("abc"), "616263"},
- {"% x", []byte("abc\xff"), "61 62 63 ff"},
- {"%#x", []byte("abc\xff"), "0x616263ff"},
- {"%#X", []byte("abc\xff"), "0X616263FF"},
- {"%# 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("\xff\xf0\x0f\xff"), "fff00fff"},
+ {"%X", []byte("\xff\xf0\x0f\xff"), "FFF00FFF"},
{"%x", []byte("xyz"), "78797a"},
{"%X", []byte("xyz"), "78797A"},
- {"%q", []byte("abc"), `"abc"`},
+ {"% x", []byte("xyz"), "78 79 7a"},
+ {"% X", []byte("xyz"), "78 79 7A"},
+ {"%#x", []byte("xyz"), "0x78797a"},
+ {"%#X", []byte("xyz"), "0X78797A"},
+ {"%# x", []byte("xyz"), "0x78 0x79 0x7a"},
+ {"%# X", []byte("xyz"), "0X78 0X79 0X7A"},
// escaped strings
{"%#q", `abc`, "`abc`"},
@@ -388,6 +395,8 @@ var fmtTests = []struct {
{"%v", &slice, "&[1 2 3 4 5]"},
{"%v", &islice, "&[1 hello 2.5 <nil>]"},
{"%v", &bslice, "&[1 2 3 4 5]"},
+ {"%v", []byte{1}, "[1]"},
+ {"%v", []byte{}, "[]"},
// complexes with %v
{"%v", 1 + 2i, "(1+2i)"},
@@ -441,6 +450,32 @@ var fmtTests = []struct {
{"%d", []int{1, 2, 15}, `[1 2 15]`},
{"%d", []byte{1, 2, 15}, `[1 2 15]`},
{"%q", []string{"a", "b"}, `["a" "b"]`},
+ {"% 02x", []byte{1}, "01"},
+ {"% 02x", []byte{1, 2, 3}, "01 02 03"},
+ // Padding with byte slices.
+ {"%x", []byte{}, ""},
+ {"%02x", []byte{}, "00"},
+ {"% 02x", []byte{}, "00"},
+ {"%08x", []byte{0xab}, "000000ab"},
+ {"% 08x", []byte{0xab}, "000000ab"},
+ {"%08x", []byte{0xab, 0xcd}, "0000abcd"},
+ {"% 08x", []byte{0xab, 0xcd}, "000ab cd"},
+ {"%8x", []byte{0xab}, " ab"},
+ {"% 8x", []byte{0xab}, " ab"},
+ {"%8x", []byte{0xab, 0xcd}, " abcd"},
+ {"% 8x", []byte{0xab, 0xcd}, " ab cd"},
+ // Same for strings
+ {"%x", "", ""},
+ {"%02x", "", "00"},
+ {"% 02x", "", "00"},
+ {"%08x", "\xab", "000000ab"},
+ {"% 08x", "\xab", "000000ab"},
+ {"%08x", "\xab\xcd", "0000abcd"},
+ {"% 08x", "\xab\xcd", "000ab cd"},
+ {"%8x", "\xab", " ab"},
+ {"% 8x", "\xab", " ab"},
+ {"%8x", "\xab\xcd", " abcd"},
+ {"% 8x", "\xab\xcd", " ab cd"},
// renamings
{"%v", renamedBool(true), "true"},
@@ -522,6 +557,8 @@ var fmtTests = []struct {
{"%s", nil, "%!s(<nil>)"},
{"%T", nil, "<nil>"},
{"%-1", 100, "%!(NOVERB)%!(EXTRA int=100)"},
+ {"%017091901790959340919092959340919017929593813360", 0, "%!(NOVERB)%!(EXTRA int=0)"},
+ {"%184467440737095516170v", 0, "%!(NOVERB)%!(EXTRA int=0)"},
// The "<nil>" show up because maps are printed by
// first obtaining a list of keys and then looking up
@@ -540,6 +577,15 @@ var fmtTests = []struct {
{"%0.100f", 1.0, zeroFill("1.", 100, "")},
{"%0.100f", -1.0, zeroFill("-1.", 100, "")},
+ // Used to panic: integer function didn't look at f.prec, f.unicode, f.width or sign.
+ {"%#.80x", 42, "0x0000000000000000000000000000000000000000000000000000000000000000000000000000002a"},
+ {"%.80U", 42, "U+0000000000000000000000000000000000000000000000000000000000000000000000000000002A"},
+ {"%#.80U", '日', "U+000000000000000000000000000000000000000000000000000000000000000000000000000065E5 '日'"},
+ {"%.65d", -44, "-00000000000000000000000000000000000000000000000000000000000000044"},
+ {"%+.65d", 44, "+00000000000000000000000000000000000000000000000000000000000000044"},
+ {"% .65d", 44, " 00000000000000000000000000000000000000000000000000000000000000044"},
+ {"% +.65d", 44, "+00000000000000000000000000000000000000000000000000000000000000044"},
+
// Comparison of padding rules with C printf.
/*
C program:
@@ -665,6 +711,20 @@ var fmtTests = []struct {
{"%x", byteFormatterSlice, "61626364"},
// This next case seems wrong, but the docs say the Formatter wins here.
{"%#v", byteFormatterSlice, "[]fmt_test.byteFormatter{X, X, X, X}"},
+
+ // reflect.Value handled specially in Go 1.5, making it possible to
+ // see inside non-exported fields (which cannot be accessed with Interface()).
+ // Issue 8965.
+ {"%v", reflect.ValueOf(A{}).Field(0).String(), "<int Value>"}, // Equivalent to the old way.
+ {"%v", reflect.ValueOf(A{}).Field(0), "0"}, // Sees inside the field.
+
+ // verbs apply to the extracted value too.
+ {"%s", reflect.ValueOf("hello"), "hello"},
+ {"%q", reflect.ValueOf("hello"), `"hello"`},
+ {"%#04x", reflect.ValueOf(256), "0x0100"},
+
+ // invalid reflect.Value doesn't crash.
+ {"%v", reflect.Value{}, "<invalid reflect.Value>"},
}
// zeroFill generates zero-filled strings of the specified width. The length
@@ -791,6 +851,11 @@ var reorderTests = []struct {
{"%d %d %d %#[1]o %#o %#o %#o", SE{11, 12, 13}, "11 12 13 013 014 015 %!o(MISSING)"},
{"%[5]d %[2]d %d", SE{1, 2, 3}, "%!d(BADINDEX) 2 3"},
{"%d %[3]d %d", SE{1, 2}, "1 %!d(BADINDEX) 2"}, // Erroneous index does not affect sequence.
+ {"%.[]", SE{}, "%!](BADINDEX)"}, // Issue 10675
+ {"%.-3d", SE{42}, "%!-(int=42)3d"}, // TODO: Should this set return better error messages?
+ {"%2147483648d", SE{42}, "%!(NOVERB)%!(EXTRA int=42)"},
+ {"%-2147483648d", SE{42}, "%!(NOVERB)%!(EXTRA int=42)"},
+ {"%.2147483648d", SE{42}, "%!(NOVERB)%!(EXTRA int=42)"},
}
func TestReorder(t *testing.T) {
@@ -869,6 +934,15 @@ func BenchmarkFprintInt(b *testing.B) {
}
}
+func BenchmarkFprintfBytes(b *testing.B) {
+ data := []byte(string("0123456789"))
+ var buf bytes.Buffer
+ for i := 0; i < b.N; i++ {
+ buf.Reset()
+ Fprintf(&buf, "%s", data)
+ }
+}
+
func BenchmarkFprintIntNoAlloc(b *testing.B) {
var x interface{} = 123456
var buf bytes.Buffer
@@ -905,11 +979,13 @@ var mallocTest = []struct {
var _ bytes.Buffer
func TestCountMallocs(t *testing.T) {
- if testing.Short() {
+ switch {
+ case testing.Short():
t.Skip("skipping malloc count in short mode")
- }
- if runtime.GOMAXPROCS(0) > 1 {
+ case runtime.GOMAXPROCS(0) > 1:
t.Skip("skipping; GOMAXPROCS>1")
+ case raceenabled:
+ t.Skip("skipping malloc count under race detector")
}
for _, mt := range mallocTest {
mallocs := testing.AllocsPerRun(100, mt.fn)
@@ -1108,14 +1184,20 @@ var startests = []struct {
out string
}{
{"%*d", args(4, 42), " 42"},
+ {"%-*d", args(4, 42), "42 "},
+ {"%*d", args(-4, 42), "42 "},
+ {"%-*d", args(-4, 42), "42 "},
{"%.*d", args(4, 42), "0042"},
{"%*.*d", args(8, 4, 42), " 0042"},
{"%0*d", args(4, 42), "0042"},
- {"%-*d", args(4, 42), "42 "},
// erroneous
{"%*d", args(nil, 42), "%!(BADWIDTH)42"},
+ {"%*d", args(int(1e7), 42), "%!(BADWIDTH)42"},
+ {"%*d", args(int(-1e7), 42), "%!(BADWIDTH)42"},
{"%.*d", args(nil, 42), "%!(BADPREC)42"},
+ {"%.*d", args(-1, 42), "%!(BADPREC)42"},
+ {"%.*d", args(int(1e7), 42), "%!(BADPREC)42"},
{"%*d", args(5, "foo"), "%!d(string= foo)"},
{"%*% %d", args(20, 5), "% 5"},
{"%*", args(4), "%!(NOVERB)"},
@@ -1233,7 +1315,7 @@ func TestNilDoesNotBecomeTyped(t *testing.T) {
type B struct{}
var a *A = nil
var b B = B{}
- got := Sprintf("%s %s %s %s %s", nil, a, nil, b, nil)
+ got := Sprintf("%s %s %s %s %s", nil, a, nil, b, nil) // go vet should complain about this line.
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/libgo/go/fmt/format.go b/libgo/go/fmt/format.go
index 4d97d14..517b18f 100644
--- a/libgo/go/fmt/format.go
+++ b/libgo/go/fmt/format.go
@@ -162,24 +162,35 @@ func (f *fmt) integer(a int64, base uint64, signedness bool, digits string) {
return
}
+ negative := signedness == signed && a < 0
+ if negative {
+ a = -a
+ }
+
var buf []byte = f.intbuf[0:]
- if f.widPresent {
- width := f.wid
+ if f.widPresent || f.precPresent || f.plus || f.space {
+ width := f.wid + f.prec // Only one will be set, both are positive; this provides the maximum.
if base == 16 && f.sharp {
// Also adds "0x".
width += 2
}
+ if f.unicode {
+ // Also adds "U+".
+ width += 2
+ if f.uniQuote {
+ // Also adds " 'x'".
+ width += 1 + 1 + utf8.UTFMax + 1
+ }
+ }
+ if negative || f.plus || f.space {
+ width++
+ }
if width > nByte {
// We're going to need a bigger boat.
buf = make([]byte, width)
}
}
- negative := signedness == signed && a < 0
- if negative {
- a = -a
- }
-
// two ways to ask for extra leading zero digits: %.3d or %03d.
// apparently the first cancels the second.
prec := 0
diff --git a/libgo/go/fmt/norace_test.go b/libgo/go/fmt/norace_test.go
new file mode 100644
index 0000000..1267cc3
--- /dev/null
+++ b/libgo/go/fmt/norace_test.go
@@ -0,0 +1,9 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build !race
+
+package fmt_test
+
+const raceenabled = false
diff --git a/libgo/go/fmt/print.go b/libgo/go/fmt/print.go
index 59a30d2..8d3e97c 100644
--- a/libgo/go/fmt/print.go
+++ b/libgo/go/fmt/print.go
@@ -285,12 +285,22 @@ func getField(v reflect.Value, i int) reflect.Value {
return val
}
+// tooLarge reports whether the magnitude of the integer is
+// too large to be used as a formatting width or precision.
+func tooLarge(x int) bool {
+ const max int = 1e6
+ return x > max || x < -max
+}
+
// 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
}
for newi = start; newi < end && '0' <= s[newi] && s[newi] <= '9'; newi++ {
+ if tooLarge(num) {
+ return 0, false, end // Overflow; crazy long number most likely.
+ }
num = num*10 + int(s[newi]-'0')
isnum = true
}
@@ -789,6 +799,8 @@ func (p *pp) printArg(arg interface{}, verb rune, depth int) (wasString bool) {
case []byte:
p.fmtBytes(f, verb, nil, depth)
wasString = verb == 's'
+ case reflect.Value:
+ return p.printReflectValue(f, verb, depth)
default:
// If the type is not simple, it might have methods.
if handled := p.handleMethods(verb, depth); handled {
@@ -845,6 +857,8 @@ func (p *pp) printReflectValue(value reflect.Value, verb rune, depth int) (wasSt
p.value = value
BigSwitch:
switch f := value; f.Kind() {
+ case reflect.Invalid:
+ p.buf.WriteString("<invalid reflect.Value>")
case reflect.Bool:
p.fmtBool(f.Bool(), verb)
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
@@ -1016,6 +1030,10 @@ func intFromArg(a []interface{}, argNum int) (num int, isInt bool, newArgNum int
if argNum < len(a) {
num, isInt = a[argNum].(int)
newArgNum = argNum + 1
+ if tooLarge(num) {
+ num = 0
+ isInt = false
+ }
}
return
}
@@ -1027,6 +1045,11 @@ func intFromArg(a []interface{}, argNum int) (num int, isInt bool, newArgNum int
// up to the closing paren, if present, and whether the number parsed
// ok. The bytes to consume will be 1 if no closing paren is present.
func parseArgNumber(format string) (index int, wid int, ok bool) {
+ // There must be at least 3 bytes: [n].
+ if len(format) < 3 {
+ return 0, 1, false
+ }
+
// Find closing bracket.
for i := 1; i < len(format); i++ {
if format[i] == ']' {
@@ -1053,7 +1076,7 @@ func (p *pp) argNumber(argNum int, format string, i int, numArgs int) (newArgNum
return index, i + wid, true
}
p.goodArgNum = false
- return argNum, i + wid, true
+ return argNum, i + wid, ok
}
func (p *pp) doPrintf(format string, a []interface{}) {
@@ -1105,9 +1128,17 @@ func (p *pp) doPrintf(format string, a []interface{}) {
if i < end && format[i] == '*' {
i++
p.fmt.wid, p.fmt.widPresent, argNum = intFromArg(a, argNum)
+
if !p.fmt.widPresent {
p.buf.Write(badWidthBytes)
}
+
+ // We have a negative width, so take its value and ensure
+ // that the minus flag is set
+ if p.fmt.wid < 0 {
+ p.fmt.wid = -p.fmt.wid
+ p.fmt.minus = true
+ }
afterIndex = false
} else {
p.fmt.wid, p.fmt.widPresent, i = parsenum(format, i, end)
@@ -1123,9 +1154,14 @@ func (p *pp) doPrintf(format string, a []interface{}) {
p.goodArgNum = false
}
argNum, i, afterIndex = p.argNumber(argNum, format, i, len(a))
- if format[i] == '*' {
+ if i < end && format[i] == '*' {
i++
p.fmt.prec, p.fmt.precPresent, argNum = intFromArg(a, argNum)
+ // Negative precision arguments don't make sense
+ if p.fmt.prec < 0 {
+ p.fmt.prec = 0
+ p.fmt.precPresent = false
+ }
if !p.fmt.precPresent {
p.buf.Write(badPrecBytes)
}
diff --git a/libgo/go/fmt/race_test.go b/libgo/go/fmt/race_test.go
new file mode 100644
index 0000000..ae3147a
--- /dev/null
+++ b/libgo/go/fmt/race_test.go
@@ -0,0 +1,9 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build race
+
+package fmt_test
+
+const raceenabled = true
diff --git a/libgo/go/fmt/scan.go b/libgo/go/fmt/scan.go
index d7befea..5b9b516 100644
--- a/libgo/go/fmt/scan.go
+++ b/libgo/go/fmt/scan.go
@@ -34,16 +34,16 @@ 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
- // a newline is treated as EOF.
+ // SkipSpace skips space in the input. Newlines are treated appropriately
+ // for the operation being performed; see the package documentation
+ // for more information.
SkipSpace()
// Token skips space in the input if skipSpace is true, then returns the
// run of Unicode code points c satisfying f(c). If f is nil,
// !unicode.IsSpace(c) is used; that is, the token will hold non-space
- // characters. Newlines are treated as space unless the scan operation
- // is Scanln, Fscanln or Sscanln, in which case a newline is treated as
- // EOF. The returned slice points to shared data that may be overwritten
+ // characters. Newlines are treated appropriately for the operation being
+ // performed; see the package documentation for more information.
+ // 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(rune) bool) (token []byte, err error)
@@ -81,6 +81,8 @@ func Scanln(a ...interface{}) (n int, err error) {
// 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.
+// If that is less than the number of arguments, err will report why.
+// Newlines in the input must match newlines in the format.
func Scanf(format string, a ...interface{}) (n int, err error) {
return Fscanf(os.Stdin, format, a...)
}
@@ -113,6 +115,7 @@ func Sscanln(str string, a ...interface{}) (n int, err error) {
// 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.
+// Newlines in the input must match newlines in the format.
func Sscanf(str string, format string, a ...interface{}) (n int, err error) {
return Fscanf((*stringReader)(&str), format, a...)
}
@@ -140,6 +143,7 @@ func Fscanln(r io.Reader, a ...interface{}) (n int, err 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.
+// Newlines in the input must match newlines in the format.
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)
@@ -387,17 +391,6 @@ var ssFree = sync.Pool{
// 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.
- s, ok := r.(*ss)
- if ok {
- old = s.ssave
- s.limit = s.argLimit
- s.nlIsEnd = nlIsEnd || s.nlIsEnd
- s.nlIsSpace = nlIsSpace
- return
- }
-
s = ssFree.Get().(*ss)
if rr, ok := r.(io.RuneReader); ok {
s.rr = rr
@@ -875,34 +868,39 @@ func (s *ss) quotedString() string {
return ""
}
-// hexDigit returns the value of the hexadecimal digit
-func (s *ss) hexDigit(d rune) int {
+// hexDigit returns the value of the hexadecimal digit.
+func hexDigit(d rune) (int, bool) {
digit := int(d)
switch digit {
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9':
- return digit - '0'
+ return digit - '0', true
case 'a', 'b', 'c', 'd', 'e', 'f':
- return 10 + digit - 'a'
+ return 10 + digit - 'a', true
case 'A', 'B', 'C', 'D', 'E', 'F':
- return 10 + digit - 'A'
+ return 10 + digit - 'A', true
}
- s.errorString("illegal hex digit")
- return 0
+ return -1, false
}
// hexByte returns the next hex-encoded (two-character) byte from the input.
-// There must be either two hexadecimal digits or a space character in the input.
+// It returns ok==false if the next bytes in the input do not encode a hex byte.
+// If the first byte is hex and the second is not, processing stops.
func (s *ss) hexByte() (b byte, ok bool) {
rune1 := s.getRune()
if rune1 == eof {
return
}
- if isSpace(rune1) {
+ value1, ok := hexDigit(rune1)
+ if !ok {
s.UnreadRune()
return
}
- rune2 := s.mustReadRune()
- return byte(s.hexDigit(rune1)<<4 | s.hexDigit(rune2)), true
+ value2, ok := hexDigit(s.mustReadRune())
+ if !ok {
+ s.errorString("illegal hex digit")
+ return
+ }
+ return byte(value1<<4 | value2), true
}
// hexString returns the space-delimited hexpair-encoded string.
@@ -1050,8 +1048,8 @@ func (s *ss) doScan(a []interface{}) (numProcessed int, err error) {
s.scanOne('v', arg)
numProcessed++
}
- // Check for newline if required.
- if !s.nlIsSpace {
+ // Check for newline (or EOF) if required (Scanln etc.).
+ if s.nlIsEnd {
for {
r := s.getRune()
if r == '\n' || r == eof {
@@ -1067,12 +1065,13 @@ func (s *ss) doScan(a []interface{}) (numProcessed int, err error) {
}
// advance determines whether the next characters in the input match
-// those of the format. It returns the number of bytes (sic) consumed
-// in the format. Newlines included, all runs of space characters in
-// either input or format behave as a single space. This routine also
-// handles the %% case. If the return value is zero, either format
-// starts with a % (with no following %) or the input is empty.
-// If it is negative, the input did not match the string.
+// those of the format. It returns the number of bytes (sic) consumed
+// in the format. All runs of space characters in either input or
+// format behave as a single space. Newlines are special, though:
+// newlines in the format must match those in the input and vice versa.
+// This routine also handles the %% case. If the return value is zero,
+// either format starts with a % (with no following %) or the input
+// is empty. If it is negative, the input did not match the string.
func (s *ss) advance(format string) (i int) {
for i < len(format) {
fmtc, w := utf8.DecodeRuneInString(format[i:])
@@ -1085,24 +1084,45 @@ func (s *ss) advance(format string) (i int) {
i += w // skip the first %
}
sawSpace := false
+ wasNewline := false
+ // Skip spaces in format but absorb at most one newline.
for isSpace(fmtc) && i < len(format) {
+ if fmtc == '\n' {
+ if wasNewline { // Already saw one; stop here.
+ break
+ }
+ wasNewline = true
+ }
sawSpace = true
i += w
fmtc, w = utf8.DecodeRuneInString(format[i:])
}
if sawSpace {
- // There was space in the format, so there should be space (EOF)
+ // There was space in the format, so there should be space
// in the input.
inputc := s.getRune()
- if inputc == eof || inputc == '\n' {
- // If we've reached a newline, stop now; don't read ahead.
+ if inputc == eof {
return
}
if !isSpace(inputc) {
- // Space in format but not in input: error
+ // Space in format but not in input.
s.errorString("expected space in input to match format")
}
- s.skipSpace(true)
+ // Skip spaces but stop at newline.
+ for inputc != '\n' && isSpace(inputc) {
+ inputc = s.getRune()
+ }
+ if inputc == '\n' {
+ if !wasNewline {
+ s.errorString("newline in input does not match format")
+ }
+ // We've reached a newline, stop now; don't read further.
+ return
+ }
+ s.UnreadRune()
+ if wasNewline {
+ s.errorString("newline in format does not match input")
+ }
continue
}
inputc := s.mustReadRune()
@@ -1144,6 +1164,7 @@ func (s *ss) doScanf(format string, a []interface{}) (numProcessed int, err erro
if !widPresent {
s.maxWid = hugeWid
}
+ s.SkipSpace()
s.argLimit = s.limit
if f := s.count + s.maxWid; f < s.argLimit {
s.argLimit = f
diff --git a/libgo/go/fmt/scan_test.go b/libgo/go/fmt/scan_test.go
index 541e12d..a378436 100644
--- a/libgo/go/fmt/scan_test.go
+++ b/libgo/go/fmt/scan_test.go
@@ -340,6 +340,8 @@ var multiTests = []ScanfMultiTest{
{"%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(&r1, &r2, &r3), args('2', '\u50c2', 'X'), ""},
+ {"%5s%d", " 1234567 ", args(&s, &i), args("12345", 67), ""},
+ {"%5s%d", " 12 34 567 ", args(&s, &i), args("12", 34), ""},
// Custom scanners.
{"%e%f", "eefffff", args(&x, &y), args(Xs("ee"), Xs("fffff")), ""},
@@ -864,7 +866,7 @@ func TestScanStateCount(t *testing.T) {
t.Fatal(err)
}
if n != 3 {
- t.Fatalf("expected 3 items consumed, got %d")
+ t.Fatalf("expected 3 items consumed, got %d", n)
}
if a.rune != '1' || b.rune != '2' || c.rune != '➂' {
t.Errorf("bad scan rune: %q %q %q should be '1' '2' '➂'", a.rune, b.rune, c.rune)
@@ -990,3 +992,167 @@ func BenchmarkScanRecursiveInt(b *testing.B) {
b.StopTimer()
}
}
+
+// Issue 9124.
+// %x on bytes couldn't handle non-space bytes terminating the scan.
+func TestHexBytes(t *testing.T) {
+ var a, b []byte
+ n, err := Sscanf("00010203", "%x", &a)
+ if n != 1 || err != nil {
+ t.Errorf("simple: got count, err = %d, %v; expected 1, nil", n, err)
+ }
+ check := func(msg string, x []byte) {
+ if len(x) != 4 {
+ t.Errorf("%s: bad length %d", msg, len(x))
+ }
+ for i, b := range x {
+ if int(b) != i {
+ t.Errorf("%s: bad x[%d] = %x", msg, i, x[i])
+ }
+ }
+ }
+ check("simple", a)
+ a = nil
+
+ n, err = Sscanf("00010203 00010203", "%x %x", &a, &b)
+ if n != 2 || err != nil {
+ t.Errorf("simple pair: got count, err = %d, %v; expected 2, nil", n, err)
+ }
+ check("simple pair a", a)
+ check("simple pair b", b)
+ a = nil
+ b = nil
+
+ n, err = Sscanf("00010203:", "%x", &a)
+ if n != 1 || err != nil {
+ t.Errorf("colon: got count, err = %d, %v; expected 1, nil", n, err)
+ }
+ check("colon", a)
+ a = nil
+
+ n, err = Sscanf("00010203:00010203", "%x:%x", &a, &b)
+ if n != 2 || err != nil {
+ t.Errorf("colon pair: got count, err = %d, %v; expected 2, nil", n, err)
+ }
+ check("colon pair a", a)
+ check("colon pair b", b)
+ a = nil
+ b = nil
+
+ // This one fails because there is a hex byte after the data,
+ // that is, an odd number of hex input bytes.
+ n, err = Sscanf("000102034:", "%x", &a)
+ if n != 0 || err == nil {
+ t.Errorf("odd count: got count, err = %d, %v; expected 0, error", n, err)
+ }
+}
+
+func TestScanNewlinesAreSpaces(t *testing.T) {
+ var a, b int
+ var tests = []struct {
+ name string
+ text string
+ count int
+ }{
+ {"newlines", "1\n2\n", 2},
+ {"no final newline", "1\n2", 2},
+ {"newlines with spaces ", "1 \n 2 \n", 2},
+ {"no final newline with spaces", "1 \n 2", 2},
+ }
+ for _, test := range tests {
+ n, err := Sscan(test.text, &a, &b)
+ if n != test.count {
+ t.Errorf("%s: expected to scan %d item(s), scanned %d", test.name, test.count, n)
+ }
+ if err != nil {
+ t.Errorf("%s: unexpected error: %s", test.name, err)
+ }
+ }
+}
+
+func TestScanlnNewlinesTerminate(t *testing.T) {
+ var a, b int
+ var tests = []struct {
+ name string
+ text string
+ count int
+ ok bool
+ }{
+ {"one line one item", "1\n", 1, false},
+ {"one line two items with spaces ", " 1 2 \n", 2, true},
+ {"one line two items no newline", " 1 2", 2, true},
+ {"two lines two items", "1\n2\n", 1, false},
+ }
+ for _, test := range tests {
+ n, err := Sscanln(test.text, &a, &b)
+ if n != test.count {
+ t.Errorf("%s: expected to scan %d item(s), scanned %d", test.name, test.count, n)
+ }
+ if test.ok && err != nil {
+ t.Errorf("%s: unexpected error: %s", test.name, err)
+ }
+ if !test.ok && err == nil {
+ t.Errorf("%s: expected error; got none", test.name)
+ }
+ }
+}
+
+func TestScanfNewlineMatchFormat(t *testing.T) {
+ var a, b int
+ var tests = []struct {
+ name string
+ text string
+ format string
+ count int
+ ok bool
+ }{
+ {"newline in both", "1\n2", "%d\n%d\n", 2, true},
+ {"newline in input", "1\n2", "%d %d", 1, false},
+ {"space-newline in input", "1 \n2", "%d %d", 1, false},
+ {"newline in format", "1 2", "%d\n%d", 1, false},
+ {"space-newline in format", "1 2", "%d \n%d", 1, false},
+ {"space-newline in both", "1 \n2", "%d \n%d", 2, true},
+ {"extra space in format", "1\n2", "%d\n %d", 2, true},
+ {"two extra spaces in format", "1\n2", "%d \n %d", 2, true},
+ }
+ for _, test := range tests {
+ n, err := Sscanf(test.text, test.format, &a, &b)
+ if n != test.count {
+ t.Errorf("%s: expected to scan %d item(s), scanned %d", test.name, test.count, n)
+ }
+ if test.ok && err != nil {
+ t.Errorf("%s: unexpected error: %s", test.name, err)
+ }
+ if !test.ok && err == nil {
+ t.Errorf("%s: expected error; got none", test.name)
+ }
+ }
+}
+
+// Test for issue 12090: Was unreading at EOF, double-scanning a byte.
+
+type hexBytes [2]byte
+
+func (h *hexBytes) Scan(ss ScanState, verb rune) error {
+ var b []byte
+ _, err := Fscanf(ss, "%4x", &b)
+ if err != nil {
+ panic(err) // Really shouldn't happen.
+ }
+ copy((*h)[:], b)
+ return err
+}
+
+func TestHexByte(t *testing.T) {
+ var h hexBytes
+ n, err := Sscanln("0123\n", &h)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if n != 1 {
+ t.Fatalf("expected 1 item; scanned %d", n)
+ }
+ if h[0] != 0x01 || h[1] != 0x23 {
+ t.Fatalf("expected 0123 got %x", h)
+ }
+}