aboutsummaryrefslogtreecommitdiff
path: root/libgo/go/fmt
diff options
context:
space:
mode:
authorIan Lance Taylor <ian@gcc.gnu.org>2011-09-16 15:47:21 +0000
committerIan Lance Taylor <ian@gcc.gnu.org>2011-09-16 15:47:21 +0000
commitadb0401dac41c81571722312d4586b2693f95aa6 (patch)
treeea2b52e3c258d6b6d9356977c683c7f72a4a5fd5 /libgo/go/fmt
parent5548ca3540bccbc908a45942896d635ea5f1c23f (diff)
downloadgcc-adb0401dac41c81571722312d4586b2693f95aa6.zip
gcc-adb0401dac41c81571722312d4586b2693f95aa6.tar.gz
gcc-adb0401dac41c81571722312d4586b2693f95aa6.tar.bz2
Update Go library to r60.
From-SVN: r178910
Diffstat (limited to 'libgo/go/fmt')
-rw-r--r--libgo/go/fmt/doc.go17
-rw-r--r--libgo/go/fmt/fmt_test.go95
-rw-r--r--libgo/go/fmt/format.go44
-rw-r--r--libgo/go/fmt/print.go103
-rw-r--r--libgo/go/fmt/scan.go70
-rw-r--r--libgo/go/fmt/scan_test.go68
6 files changed, 332 insertions, 65 deletions
diff --git a/libgo/go/fmt/doc.go b/libgo/go/fmt/doc.go
index e4d4f18..35a11e1 100644
--- a/libgo/go/fmt/doc.go
+++ b/libgo/go/fmt/doc.go
@@ -25,9 +25,10 @@
%c the character represented by the corresponding Unicode code point
%d base 10
%o base 8
+ %q a single-quoted character literal safely escaped with Go syntax.
%x base 16, with lower-case letters for a-f
%X base 16, with upper-case letters for A-F
- %U Unicode format: U+1234; same as "U+%0.4X"
+ %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
@@ -62,11 +63,13 @@
number of characters to output, truncating if necessary.
Other flags:
- + always print a sign for numeric values
+ + always print a sign for numeric values;
+ guarantee ASCII-only output for %q (%+q)
- 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)
+ print a raw (backquoted) string if possible for %q (%#q);
+ 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
@@ -134,10 +137,10 @@
The formats behave analogously to those of Printf with the
following exceptions:
- %p is not implemented
- %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
+ %p is not implemented
+ %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
The familiar base-setting prefixes 0 (octal) and 0x
(hexadecimal) are accepted when scanning integers without a
diff --git a/libgo/go/fmt/fmt_test.go b/libgo/go/fmt/fmt_test.go
index b3c0c5a..1142c9f 100644
--- a/libgo/go/fmt/fmt_test.go
+++ b/libgo/go/fmt/fmt_test.go
@@ -43,7 +43,6 @@ func TestFmtInterface(t *testing.T) {
}
}
-
const b32 uint32 = 1<<32 - 1
const b64 uint64 = 1<<64 - 1
@@ -132,12 +131,26 @@ var fmttests = []struct {
{"%q", `"`, `"\""`},
{"%q", "\a\b\f\r\n\t\v", `"\a\b\f\r\n\t\v"`},
{"%q", "abc\xffdef", `"abc\xffdef"`},
- {"%q", "\u263a", `"\u263a"`},
+ {"%q", "\u263a", `"☺"`},
+ {"%+q", "\u263a", `"\u263a"`},
{"%q", "\U0010ffff", `"\U0010ffff"`},
+ // escaped characters
+ {"%q", 'x', `'x'`},
+ {"%q", 0, `'\x00'`},
+ {"%q", '\n', `'\n'`},
+ {"%q", '\u0e00', `'\u0e00'`}, // not a printable rune.
+ {"%q", '\U000c2345', `'\U000c2345'`}, // not a printable rune.
+ {"%q", int64(0x7FFFFFFF), `%!q(int64=2147483647)`},
+ {"%q", uint64(0xFFFFFFFF), `%!q(uint64=4294967295)`},
+ {"%q", '"', `'"'`},
+ {"%q", '\'', `'\''`},
+ {"%q", "\u263a", `"☺"`},
+ {"%+q", "\u263a", `"\u263a"`},
+
// width
{"%5s", "abc", " abc"},
- {"%2s", "\u263a", " \u263a"},
+ {"%2s", "\u263a", " ☺"},
{"%-5s", "abc", "abc "},
{"%-8q", "abc", `"abc" `},
{"%05s", "abc", "00abc"},
@@ -147,9 +160,9 @@ var fmttests = []struct {
{"%.5s", "日本語日本語", "日本語日本"},
{"%.5s", []byte("日本語日本語"), "日本語日本"},
{"%.5q", "abcdefghijklmnopqrstuvwxyz", `"abcde"`},
- {"%.3q", "日本語日本語", `"\u65e5\u672c\u8a9e"`},
- {"%.3q", []byte("日本語日本語"), `"\u65e5\u672c\u8a9e"`},
- {"%10.1q", "日本語日本語", ` "\u65e5"`},
+ {"%.3q", "日本語日本語", `"日本語"`},
+ {"%.3q", []byte("日本語日本語"), `"日本語"`},
+ {"%10.1q", "日本語日本語", ` "日"`},
// integers
{"%d", 12345, "12345"},
@@ -167,6 +180,8 @@ var fmttests = []struct {
{"%+d", 0, "+0"},
{"% d", 0, " 0"},
{"% d", 12345, " 12345"},
+ {"%.0d", 0, ""},
+ {"%.d", 0, ""},
// unicode format
{"%U", 0x1, "U+0001"},
@@ -176,6 +191,12 @@ var fmttests = []struct {
{"%U", 0x12345, "U+12345"},
{"%10.6U", 0xABC, " U+000ABC"},
{"%-10.6U", 0xABC, "U+000ABC "},
+ {"%U", '\n', `U+000A`},
+ {"%#U", '\n', `U+000A`},
+ {"%U", 'x', `U+0078`},
+ {"%#U", 'x', `U+0078 'x'`},
+ {"%U", '\u263a', `U+263A`},
+ {"%#U", '\u263a', `U+263A '☺'`},
// floats
{"%+.3e", 0.0, "+0.000e+00"},
@@ -456,28 +477,36 @@ 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("%x %x", i, i)
}
+ runtime.UpdateMemStats()
mallocs += runtime.MemStats.Mallocs
Printf("mallocs per Sprintf(\"%%x %%x\"): %d\n", mallocs/100)
}
@@ -614,7 +643,6 @@ func TestBlankln(t *testing.T) {
}
}
-
// Check Formatter with Sprint, Sprintln, Sprintf
func TestFormatterPrintln(t *testing.T) {
f := F(1)
@@ -663,3 +691,56 @@ func TestWidthAndPrecision(t *testing.T) {
}
}
}
+
+// A type that panics in String.
+type Panic struct {
+ message interface{}
+}
+
+// Value receiver.
+func (p Panic) GoString() string {
+ panic(p.message)
+}
+
+// Value receiver.
+func (p Panic) String() string {
+ panic(p.message)
+}
+
+// A type that panics in Format.
+type PanicF struct {
+ message interface{}
+}
+
+// Value receiver.
+func (p PanicF) Format(f State, c int) {
+ panic(p.message)
+}
+
+var panictests = []struct {
+ fmt string
+ in interface{}
+ 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)"},
+ // GoString
+ {"%#v", (*Panic)(nil), "<nil>"}, // nil pointer special case
+ {"%#v", Panic{io.ErrUnexpectedEOF}, "%v(PANIC=unexpected EOF)"},
+ {"%#v", Panic{3}, "%v(PANIC=3)"},
+ // Format
+ {"%s", (*PanicF)(nil), "<nil>"}, // nil pointer special case
+ {"%s", PanicF{io.ErrUnexpectedEOF}, "%s(PANIC=unexpected EOF)"},
+ {"%s", PanicF{3}, "%s(PANIC=3)"},
+}
+
+func TestPanics(t *testing.T) {
+ for _, tt := range panictests {
+ s := Sprintf(tt.fmt, tt.in)
+ if s != tt.out {
+ t.Errorf("%q: got %q expected %q", tt.fmt, s, tt.out)
+ }
+ }
+}
diff --git a/libgo/go/fmt/format.go b/libgo/go/fmt/format.go
index f9d2b4f..24b15a2 100644
--- a/libgo/go/fmt/format.go
+++ b/libgo/go/fmt/format.go
@@ -7,6 +7,7 @@ package fmt
import (
"bytes"
"strconv"
+ "unicode"
"utf8"
)
@@ -50,6 +51,7 @@ type fmt struct {
sharp bool
space bool
unicode bool
+ uniQuote bool // Use 'x'= prefix for %U if printable.
zero bool
}
@@ -63,6 +65,7 @@ func (f *fmt) clearflags() {
f.sharp = false
f.space = false
f.unicode = false
+ f.uniQuote = false
f.zero = false
}
@@ -163,6 +166,11 @@ func (f *fmt) fmt_boolean(v bool) {
// integer; interprets prec but not wid. Once formatted, result is sent to pad()
// and then flags are cleared.
func (f *fmt) integer(a int64, base uint64, signedness bool, digits string) {
+ // precision of 0 and value of 0 means "print nothing"
+ if f.precPresent && f.prec == 0 && a == 0 {
+ return
+ }
+
var buf []byte = f.intbuf[0:]
negative := signedness == signed && a < 0
if negative {
@@ -232,6 +240,24 @@ func (f *fmt) integer(a int64, base uint64, signedness bool, digits string) {
i--
buf[i] = ' '
}
+
+ // 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))
+ width := 1 + 1 + runeWidth + 1 // space, quote, rune, quote
+ copy(buf[i-width:], buf[i:]) // guaranteed to have enough room.
+ i -= width
+ // Now put " 'x'" at the end.
+ j := len(buf) - width
+ buf[j] = ' '
+ j++
+ buf[j] = '\''
+ j++
+ utf8.EncodeRune(buf[j:], int(a))
+ j += runeWidth
+ buf[j] = '\''
+ }
+
f.pad(buf[i:])
}
@@ -291,7 +317,23 @@ func (f *fmt) fmt_q(s string) {
if f.sharp && strconv.CanBackquote(s) {
quoted = "`" + s + "`"
} else {
- quoted = strconv.Quote(s)
+ if f.plus {
+ quoted = strconv.QuoteToASCII(s)
+ } else {
+ quoted = strconv.Quote(s)
+ }
+ }
+ f.padString(quoted)
+}
+
+// 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
+ if f.plus {
+ quoted = strconv.QuoteRuneToASCII(int(c))
+ } else {
+ quoted = strconv.QuoteRune(int(c))
}
f.padString(quoted)
}
diff --git a/libgo/go/fmt/print.go b/libgo/go/fmt/print.go
index 10e0fe7..7387349 100644
--- a/libgo/go/fmt/print.go
+++ b/libgo/go/fmt/print.go
@@ -9,6 +9,7 @@ import (
"io"
"os"
"reflect"
+ "unicode"
"utf8"
)
@@ -21,6 +22,7 @@ var (
nilBytes = []byte("nil")
mapBytes = []byte("map[")
missingBytes = []byte("(MISSING)")
+ panicBytes = []byte("(PANIC=")
extraBytes = []byte("%!(EXTRA ")
irparenBytes = []byte("i)")
bytesBytes = []byte("[]byte{")
@@ -41,7 +43,7 @@ type State interface {
Precision() (prec int, ok bool)
// Flag returns whether the flag c, a character, has been set.
- Flag(int) bool
+ Flag(c int) bool
}
// Formatter is the interface implemented by values with a custom formatter.
@@ -51,7 +53,7 @@ type Formatter interface {
Format(f State, c int)
}
-// Stringer is implemented by any value that has a String method(),
+// Stringer is implemented by any value that has a String method,
// which defines the ``native'' format for that value.
// The String method is used to print values passed as an operand
// to a %s or %v format or to an unformatted printer such as Print.
@@ -59,7 +61,7 @@ type Stringer interface {
String() string
}
-// GoStringer is implemented by any value that has a GoString() method,
+// GoStringer is implemented by any value that has a GoString method,
// which defines the Go syntax for that value.
// The GoString method is used to print values passed as an operand
// to a %#v format.
@@ -68,10 +70,11 @@ type GoStringer interface {
}
type pp struct {
- n int
- buf bytes.Buffer
- runeBuf [utf8.UTFMax]byte
- fmt fmt
+ n int
+ panicking bool
+ buf bytes.Buffer
+ runeBuf [utf8.UTFMax]byte
+ fmt fmt
}
// A cache holds a set of reusable objects.
@@ -110,6 +113,7 @@ var ppFree = newCache(func() interface{} { return new(pp) })
// Allocate a new pp struct or grab a cached one.
func newPrinter() *pp {
p := ppFree.get().(*pp)
+ p.panicking = false
p.fmt.init(&p.buf)
return p
}
@@ -158,19 +162,18 @@ 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, error os.Error) {
+func Fprintf(w io.Writer, format string, a ...interface{}) (n int, err os.Error) {
p := newPrinter()
p.doPrintf(format, a)
- n64, error := p.buf.WriteTo(w)
+ n64, err := p.buf.WriteTo(w)
p.free()
- return int(n64), error
+ return int(n64), err
}
// 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, errno os.Error) {
- n, errno = Fprintf(os.Stdout, format, a...)
- return n, errno
+func Printf(format string, a ...interface{}) (n int, err os.Error) {
+ return Fprintf(os.Stdout, format, a...)
}
// Sprintf formats according to a format specifier and returns the resulting string.
@@ -185,7 +188,7 @@ 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.ErrorString(Sprintf(format, a...))
+ return os.NewError(Sprintf(format, a...))
}
// These routines do not take a format string
@@ -193,20 +196,19 @@ 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, error os.Error) {
+func Fprint(w io.Writer, a ...interface{}) (n int, err os.Error) {
p := newPrinter()
p.doPrint(a, false, false)
- n64, error := p.buf.WriteTo(w)
+ n64, err := p.buf.WriteTo(w)
p.free()
- return int(n64), error
+ return int(n64), err
}
// 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, errno os.Error) {
- n, errno = Fprint(os.Stdout, a...)
- return n, errno
+func Print(a ...interface{}) (n int, err os.Error) {
+ return Fprint(os.Stdout, a...)
}
// Sprint formats using the default formats for its operands and returns the resulting string.
@@ -226,20 +228,19 @@ 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, error os.Error) {
+func Fprintln(w io.Writer, a ...interface{}) (n int, err os.Error) {
p := newPrinter()
p.doPrint(a, true, true)
- n64, error := p.buf.WriteTo(w)
+ n64, err := p.buf.WriteTo(w)
p.free()
- return int(n64), error
+ return int(n64), err
}
// 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, errno os.Error) {
- n, errno = Fprintln(os.Stdout, a...)
- return n, errno
+func Println(a ...interface{}) (n int, err os.Error) {
+ return Fprintln(os.Stdout, a...)
}
// Sprintln formats using the default formats for its operands and returns the resulting string.
@@ -252,7 +253,6 @@ func Sprintln(a ...interface{}) string {
return s
}
-
// Get 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.
@@ -332,6 +332,12 @@ func (p *pp) fmtInt64(v int64, verb int, value interface{}) {
p.fmt.integer(v, 10, signed, ldigits)
case 'o':
p.fmt.integer(v, 8, signed, ldigits)
+ case 'q':
+ if 0 <= v && v <= unicode.MaxRune {
+ p.fmt.fmt_qc(v)
+ } else {
+ p.badVerb(verb, value)
+ }
case 'x':
p.fmt.integer(v, 16, signed, ldigits)
case 'U':
@@ -356,6 +362,8 @@ func (p *pp) fmt0x64(v uint64, leading0x bool) {
// temporarily turning on the unicode flag and tweaking the precision.
func (p *pp) fmtUnicode(v int64) {
precPresent := p.fmt.precPresent
+ sharp := p.fmt.sharp
+ p.fmt.sharp = false
prec := p.fmt.prec
if !precPresent {
// If prec is already set, leave it alone; otherwise 4 is minimum.
@@ -363,10 +371,13 @@ func (p *pp) fmtUnicode(v int64) {
p.fmt.precPresent = true
}
p.fmt.unicode = true // turn on U+
+ p.fmt.uniQuote = sharp
p.fmt.integer(int64(v), 16, unsigned, udigits)
p.fmt.unicode = false
+ p.fmt.uniQuote = false
p.fmt.prec = prec
p.fmt.precPresent = precPresent
+ p.fmt.sharp = sharp
}
func (p *pp) fmtUint64(v uint64, verb int, goSyntax bool, value interface{}) {
@@ -385,6 +396,12 @@ func (p *pp) fmtUint64(v uint64, verb int, goSyntax bool, value interface{}) {
}
case 'o':
p.fmt.integer(int64(v), 8, unsigned, ldigits)
+ case 'q':
+ if 0 <= v && v <= unicode.MaxRune {
+ p.fmt.fmt_qc(int64(v))
+ } else {
+ p.badVerb(verb, value)
+ }
case 'x':
p.fmt.integer(int64(v), 16, unsigned, ldigits)
case 'X':
@@ -548,6 +565,31 @@ var (
uintptrBits = reflect.TypeOf(uintptr(0)).Bits()
)
+func (p *pp) catchPanic(val interface{}, verb int) {
+ 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() {
+ p.buf.Write(nilAngleBytes)
+ return
+ }
+ // Otherwise print a concise panic message. Most of the time the panic
+ // value will print itself nicely.
+ if p.panicking {
+ // Nested panics; the recursion in printField cannot succeed.
+ panic(err)
+ }
+ p.buf.WriteByte('%')
+ p.add(verb)
+ p.buf.Write(panicBytes)
+ p.panicking = true
+ p.printField(err, 'v', false, false, 0)
+ p.panicking = false
+ p.buf.WriteByte(')')
+ }
+}
+
func (p *pp) printField(field interface{}, verb int, plus, goSyntax bool, depth int) (wasString bool) {
if field == nil {
if verb == 'T' || verb == 'v' {
@@ -570,6 +612,7 @@ func (p *pp) printField(field interface{}, verb int, plus, goSyntax bool, depth
}
// 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
@@ -582,6 +625,7 @@ func (p *pp) printField(field interface{}, verb int, plus, goSyntax bool, depth
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
@@ -589,6 +633,7 @@ func (p *pp) printField(field interface{}, verb int, plus, goSyntax bool, depth
} 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
}
@@ -883,6 +928,10 @@ func (p *pp) doPrintf(format string, a []interface{}) {
}
} else {
p.fmt.prec, p.fmt.precPresent, i = parsenum(format, i+1, end)
+ if !p.fmt.precPresent {
+ p.fmt.prec = 0
+ p.fmt.precPresent = true
+ }
}
}
if i >= end {
diff --git a/libgo/go/fmt/scan.go b/libgo/go/fmt/scan.go
index 42bc52c..259451d 100644
--- a/libgo/go/fmt/scan.go
+++ b/libgo/go/fmt/scan.go
@@ -35,6 +35,10 @@ type ScanState interface {
ReadRune() (rune int, size int, err os.Error)
// UnreadRune causes the next call to ReadRune to return the same rune.
UnreadRune() os.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()
// 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
@@ -167,7 +171,7 @@ type ssave struct {
// 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.ErrorString("ScanState's Read should not be called. Use ReadRune")
+ return 0, os.NewError("ScanState's Read should not be called. Use ReadRune")
}
func (s *ss) ReadRune() (rune int, size int, err os.Error) {
@@ -231,6 +235,7 @@ func (s *ss) UnreadRune() os.Error {
} else {
s.peekRune = s.prevRune
}
+ s.prevRune = -1
s.count--
return nil
}
@@ -240,7 +245,7 @@ func (s *ss) error(err os.Error) {
}
func (s *ss) errorString(err string) {
- panic(scanError{os.ErrorString(err)})
+ panic(scanError{os.NewError(err)})
}
func (s *ss) Token(skipSpace bool, f func(int) bool) (tok []byte, err os.Error) {
@@ -266,6 +271,12 @@ func notSpace(r int) bool {
return !unicode.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().
+func (s *ss) SkipSpace() {
+ s.skipSpace(false)
+}
+
// readRune is a structure to enable reading UTF-8 encoded code points
// from an io.Reader. It is used if the Reader given to the scanner does
// not already implement io.RuneReader.
@@ -324,7 +335,6 @@ func (r *readRune) ReadRune() (rune int, size int, err os.Error) {
return
}
-
var ssFree = newCache(func() interface{} { return new(ss) })
// Allocate a new ss struct or grab a cached one.
@@ -398,7 +408,6 @@ 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.
@@ -426,8 +435,8 @@ 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.ErrorString("syntax error scanning complex number")
-var boolError = os.ErrorString("syntax error scanning boolean")
+var complexError = os.NewError("syntax error scanning complex number")
+var boolError = os.NewError("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.
@@ -457,6 +466,14 @@ func (s *ss) peek(ok string) bool {
return strings.IndexRune(ok, rune) >= 0
}
+func (s *ss) notEOF() {
+ // Guarantee there is data to be read.
+ if rune := s.getRune(); rune == eof {
+ panic(os.EOF)
+ }
+ s.UnreadRune()
+}
+
// accept checks the next rune in the input. If it's a byte (sic) in the string, it puts it in the
// buffer and returns true. Otherwise it return false.
func (s *ss) accept(ok string) bool {
@@ -476,11 +493,13 @@ 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 {
+ s.skipSpace(false)
+ s.notEOF()
if !s.okVerb(verb, "tv", "boolean") {
return false
}
// Syntax-checking a boolean is annoying. We're not fastidious about case.
- switch s.mustReadRune() {
+ switch s.getRune() {
case '0':
return false
case '1':
@@ -531,8 +550,11 @@ func (s *ss) getBase(verb int) (base int, digits string) {
// scanNumber returns the numerical string with specified digits starting here.
func (s *ss) scanNumber(digits string, haveDigits bool) string {
- if !haveDigits && !s.accept(digits) {
- s.errorString("expected integer")
+ if !haveDigits {
+ s.notEOF()
+ if !s.accept(digits) {
+ s.errorString("expected integer")
+ }
}
for s.accept(digits) {
}
@@ -541,7 +563,8 @@ 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 {
- rune := int64(s.mustReadRune())
+ s.notEOF()
+ rune := int64(s.getRune())
n := uint(bitSize)
x := (rune << (64 - n)) >> (64 - n)
if x != rune {
@@ -575,6 +598,7 @@ func (s *ss) scanInt(verb int, bitSize int) int64 {
return s.scanRune(bitSize)
}
s.skipSpace(false)
+ s.notEOF()
base, digits := s.getBase(verb)
haveDigits := false
if verb == 'U' {
@@ -607,6 +631,7 @@ func (s *ss) scanUint(verb int, bitSize int) uint64 {
return uint64(s.scanRune(bitSize))
}
s.skipSpace(false)
+ s.notEOF()
base, digits := s.getBase(verb)
haveDigits := false
if verb == 'U' {
@@ -727,6 +752,7 @@ func (s *ss) scanComplex(verb int, n int) complex128 {
return 0
}
s.skipSpace(false)
+ s.notEOF()
sreal, simag := s.complexTokens()
real := s.convertFloat(sreal, n/2)
imag := s.convertFloat(simag, n/2)
@@ -740,6 +766,7 @@ func (s *ss) convertString(verb int) (str string) {
return ""
}
s.skipSpace(false)
+ s.notEOF()
switch verb {
case 'q':
str = s.quotedString()
@@ -748,16 +775,13 @@ func (s *ss) convertString(verb int) (str string) {
default:
str = string(s.token(true, notSpace)) // %s and %v just return the next word
}
- // Empty strings other than with %q are not OK.
- if len(str) == 0 && verb != 'q' && s.maxWid > 0 {
- s.errorString("Scan: no data for string")
- }
return
}
// quotedString returns the double- or back-quoted string represented by the next input characters.
func (s *ss) quotedString() string {
- quote := s.mustReadRune()
+ s.notEOF()
+ quote := s.getRune()
switch quote {
case '`':
// Back-quoted: Anything goes until EOF or back quote.
@@ -827,6 +851,7 @@ func (s *ss) hexByte() (b byte, ok bool) {
// hexString returns the space-delimited hexpair-encoded string.
func (s *ss) hexString() string {
+ s.notEOF()
for {
b, ok := s.hexByte()
if !ok {
@@ -860,6 +885,7 @@ func (s *ss) scanOne(verb int, field interface{}) {
}
return
}
+
switch v := field.(type) {
case *bool:
*v = s.scanBool(verb)
@@ -894,11 +920,13 @@ func (s *ss) scanOne(verb int, field interface{}) {
case *float32:
if s.okVerb(verb, floatVerbs, "float32") {
s.skipSpace(false)
+ s.notEOF()
*v = float32(s.convertFloat(s.floatToken(), 32))
}
case *float64:
if s.okVerb(verb, floatVerbs, "float64") {
s.skipSpace(false)
+ s.notEOF()
*v = s.convertFloat(s.floatToken(), 64)
}
case *string:
@@ -927,7 +955,7 @@ func (s *ss) scanOne(verb int, field interface{}) {
// For now, can only handle (renamed) []byte.
typ := v.Type()
if typ.Elem().Kind() != reflect.Uint8 {
- goto CantHandle
+ s.errorString("Scan: can't handle type: " + val.Type().String())
}
str := s.convertString(verb)
v.Set(reflect.MakeSlice(typ, len(str), len(str)))
@@ -936,23 +964,23 @@ func (s *ss) scanOne(verb int, field interface{}) {
}
case reflect.Float32, reflect.Float64:
s.skipSpace(false)
+ s.notEOF()
v.SetFloat(s.convertFloat(s.floatToken(), v.Type().Bits()))
case reflect.Complex64, reflect.Complex128:
v.SetComplex(s.scanComplex(verb, v.Type().Bits()))
default:
- CantHandle:
s.errorString("Scan: can't handle type: " + val.Type().String())
}
}
}
-// errorHandler turns local panics into error returns. EOFs are benign.
+// errorHandler turns local panics into error returns.
func errorHandler(errp *os.Error) {
if e := recover(); e != nil {
if se, ok := e.(scanError); ok { // catch local error
- if se.err != os.EOF {
- *errp = se.err
- }
+ *errp = se.err
+ } else if eof, ok := e.(os.Error); ok && eof == os.EOF { // out of input
+ *errp = eof
} else {
panic(e)
}
diff --git a/libgo/go/fmt/scan_test.go b/libgo/go/fmt/scan_test.go
index da13eb2..3f06e57 100644
--- a/libgo/go/fmt/scan_test.go
+++ b/libgo/go/fmt/scan_test.go
@@ -94,7 +94,7 @@ func (x *Xs) Scan(state ScanState, verb int) os.Error {
}
s := string(tok)
if !regexp.MustCompile("^" + string(verb) + "+$").MatchString(s) {
- return os.ErrorString("syntax error for xs")
+ return os.NewError("syntax error for xs")
}
*x = Xs(s)
return nil
@@ -298,6 +298,8 @@ var scanfTests = []ScanfTest{
// Fixed bugs
{"%d\n", "27\n", &intVal, 27}, // ok
{"%d\n", "28 \n", &intVal, 28}, // was: "unexpected newline"
+ {"%v", "0", &intVal, 0}, // was: "EOF"; 0 was taken as base prefix and not counted.
+ {"%v", "0", &uintVal, uint(0)}, // was: "EOF"; 0 was taken as base prefix and not counted.
}
var overflowTests = []ScanTest{
@@ -660,6 +662,68 @@ func TestEOF(t *testing.T) {
}
}
+// Verify 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
+ n, err := Sscanf("23", "%d %d", &i, &j)
+ if n != 1 || i != 23 {
+ t.Errorf("Sscanf expected one value of 23; got %d %d", n, i)
+ }
+ if err != os.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 {
+ t.Errorf("Sscan expected EOF; got %q", err)
+ }
+ // Trailing space is tougher.
+ 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 {
+ t.Errorf("Sscan expected EOF; got %q", err)
+ }
+}
+
+var eofTests = []struct {
+ format string
+ v interface{}
+}{
+ {"%s", &stringVal},
+ {"%q", &stringVal},
+ {"%x", &stringVal},
+ {"%v", &stringVal},
+ {"%v", &bytesVal},
+ {"%v", &intVal},
+ {"%v", &uintVal},
+ {"%v", &boolVal},
+ {"%v", &float32Val},
+ {"%v", &complex64Val},
+ {"%v", &renamedStringVal},
+ {"%v", &renamedBytesVal},
+ {"%v", &renamedIntVal},
+ {"%v", &renamedUintVal},
+ {"%v", &renamedBoolVal},
+ {"%v", &renamedFloat32Val},
+ {"%v", &renamedComplex64Val},
+}
+
+func TestEOFAllTypes(t *testing.T) {
+ for i, test := range eofTests {
+ if _, err := Sscanf("", test.format, test.v); err != os.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 {
+ t.Errorf("#%d: %s %T not eof on trailing blanks: %s", i, test.format, test.v, err)
+ }
+ }
+}
+
// Verify that, at least when using bufio, successive calls to Fscan do not lose runes.
func TestUnreadRuneWithBufio(t *testing.T) {
r := bufio.NewReader(strings.NewReader("123αb"))
@@ -756,7 +820,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.ErrorString("input does not match format") || err == io.ErrUnexpectedEOF {
+ if err == os.NewError("input does not match format") || err == io.ErrUnexpectedEOF {
err = nil
}
return