message: use merged in fmt code

Differences in copied code:
- fmt renamed to formatInfo (avoid conflict with package)
- pp renamed to and merged with printer (existing type)
- printer supports Language: this gets rid of bind code!!!
- allow arguments with empty format string (required)
- added args as field to printer (allows incremental argument
  counting for Render)
- use inlined bytes.Buffer

Expected modifications in future CLs and for which this merge
was necessary:
- use localized number formatting
- different handling of lists
- localized formatting of values within complex data types
- non-number argument references.

Change-Id: I497053e5a343ed0bc5694d68e7d04b3cefe9eae2
Edit
Reviewed-on: https://go-review.googlesource.com/44955
Run-TryBot: Marcel van Lohuizen <mpvl@golang.org>
Reviewed-by: Nigel Tao <nigeltao@golang.org>
diff --git a/message/fmt_test.go b/message/fmt_test.go
old mode 100644
new mode 100755
index 7f2db5e..d02808a
--- a/message/fmt_test.go
+++ b/message/fmt_test.go
@@ -1,21 +1,21 @@
-// +build ignore
-// Copyright 2009 The Go Authors. All rights reserved.
+// Copyright 2017 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.
 
-package fmt_test
+package message
 
 import (
 	"bytes"
-	. "fmt"
-	"internal/race"
+	"fmt"
+	"io"
 	"math"
 	"reflect"
 	"runtime"
 	"strings"
 	"testing"
 	"time"
-	"unicode"
+
+	"golang.org/x/text/language"
 )
 
 type (
@@ -40,9 +40,10 @@
 )
 
 func TestFmtInterface(t *testing.T) {
+	p := NewPrinter(language.Und)
 	var i1 interface{}
 	i1 = "abc"
-	s := Sprintf("%s", i1)
+	s := p.Sprintf("%s", i1)
 	if s != "abc" {
 		t.Errorf(`Sprintf("%%s", empty("abc")) = %q want %q`, s, "abc")
 	}
@@ -70,7 +71,10 @@
 
 type I int
 
-func (i I) String() string { return Sprintf("<%d>", int(i)) }
+func (i I) String() string {
+	p := NewPrinter(language.Und)
+	return p.Sprintf("<%d>", int(i))
+}
 
 type B struct {
 	I I
@@ -84,14 +88,16 @@
 
 type F int
 
-func (f F) Format(s State, c rune) {
-	Fprintf(s, "<%c=F(%d)>", c, int(f))
+func (f F) Format(s fmt.State, c rune) {
+	p := NewPrinter(language.Und)
+	p.Fprintf(s, "<%c=F(%d)>", c, int(f))
 }
 
 type G int
 
 func (g G) GoString() string {
-	return Sprintf("GoString(%d)", int(g))
+	p := NewPrinter(language.Und)
+	return p.Sprintf("GoString(%d)", int(g))
 }
 
 type S struct {
@@ -125,8 +131,9 @@
 
 type byteFormatter byte
 
-func (byteFormatter) Format(f State, _ rune) {
-	Fprint(f, "X")
+func (byteFormatter) Format(f fmt.State, _ rune) {
+	p := NewPrinter(language.Und)
+	p.Fprint(f, "X")
 }
 
 var byteFormatterSlice = []byteFormatter{'h', 'e', 'l', 'l', 'o'}
@@ -136,6 +143,22 @@
 	val interface{}
 	out string
 }{
+	// The behavior of the following tests differs from that of the fmt package.
+
+	// Unlike with the fmt package, it is okay to have extra arguments for
+	// strings without format parameters. This is because it is impossible to
+	// distinguish between reordered or ordered format strings in this case.
+	// (For reordered format strings it is okay to not use arguments.)
+	{"", nil, ""},
+	{"", 2, ""},
+	{"no args", "hello", "no args"},
+
+	{"%017091901790959340919092959340919017929593813360", 0, "%!(NOVERB)"},
+	{"%184467440737095516170v", 0, "%!(NOVERB)"},
+	// Extra argument errors should format without flags set.
+	{"%010.2", "12345", "%!(NOVERB)"},
+
+	// All following tests are identical to that of the fmt package.
 	{"%d", 12345, "12345"},
 	{"%v", 12345, "12345"},
 	{"%t", true, "true"},
@@ -653,16 +676,16 @@
 	{"%s", reflect.ValueOf(I(23)), `<23>`},
 
 	// go syntax
-	{"%#v", A{1, 2, "a", []int{1, 2}}, `fmt_test.A{i:1, j:0x2, s:"a", x:[]int{1, 2}}`},
+	{"%#v", A{1, 2, "a", []int{1, 2}}, `message.A{i:1, j:0x2, s:"a", x:[]int{1, 2}}`},
 	{"%#v", new(byte), "(*uint8)(0xPTR)"},
 	{"%#v", TestFmtInterface, "(func(*testing.T))(0xPTR)"},
 	{"%#v", make(chan int), "(chan int)(0xPTR)"},
 	{"%#v", uint64(1<<64 - 1), "0xffffffffffffffff"},
 	{"%#v", 1000000000, "1000000000"},
 	{"%#v", map[string]int{"a": 1}, `map[string]int{"a":1}`},
-	{"%#v", map[string]B{"a": {1, 2}}, `map[string]fmt_test.B{"a":fmt_test.B{I:1, j:2}}`},
+	{"%#v", map[string]B{"a": {1, 2}}, `map[string]message.B{"a":message.B{I:1, j:2}}`},
 	{"%#v", []string{"a", "b"}, `[]string{"a", "b"}`},
-	{"%#v", SI{}, `fmt_test.SI{I:interface {}(nil)}`},
+	{"%#v", SI{}, `message.SI{I:interface {}(nil)}`},
 	{"%#v", []int(nil), `[]int(nil)`},
 	{"%#v", []int{}, `[]int{}`},
 	{"%#v", array, `[5]int{1, 2, 3, 4, 5}`},
@@ -672,8 +695,8 @@
 	{"%#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}`},
+	{"%#v", barray, `[5]message.renamedUint8{0x1, 0x2, 0x3, 0x4, 0x5}`},
+	{"%#v", bslice, `[]message.renamedUint8{0x1, 0x2, 0x3, 0x4, 0x5}`},
 	{"%#v", []int32(nil), "[]int32(nil)"},
 	{"%#v", 1.2345678, "1.2345678"},
 	{"%#v", float32(1.2345678), "1.2345678"},
@@ -755,7 +778,7 @@
 
 	// renamings
 	{"%v", renamedBool(true), "true"},
-	{"%d", renamedBool(true), "%!d(fmt_test.renamedBool=true)"},
+	{"%d", renamedBool(true), "%!d(message.renamedBool=true)"},
 	{"%o", renamedInt(8), "10"},
 	{"%d", renamedInt8(-9), "-9"},
 	{"%v", renamedInt16(10), "10"},
@@ -786,13 +809,13 @@
 
 	// GoStringer
 	{"%#v", G(6), "GoString(6)"},
-	{"%#v", S{F(7), G(8)}, "fmt_test.S{F:<v=F(7)>, G:GoString(8)}"},
+	{"%#v", S{F(7), G(8)}, "message.S{F:<v=F(7)>, G:GoString(8)}"},
 
 	// %T
 	{"%T", byte(0), "uint8"},
 	{"%T", reflect.ValueOf(nil), "reflect.Value"},
 	{"%T", (4 - 3i), "complex128"},
-	{"%T", renamedComplex128(4 - 3i), "fmt_test.renamedComplex128"},
+	{"%T", renamedComplex128(4 - 3i), "message.renamedComplex128"},
 	{"%T", intVar, "int"},
 	{"%6T", &intVar, "  *int"},
 	{"%10T", nil, "     <nil>"},
@@ -838,15 +861,8 @@
 	{"%d", time.Time{}.Month(), "1"},
 
 	// erroneous things
-	{"", nil, "%!(EXTRA <nil>)"},
-	{"", 2, "%!(EXTRA int=2)"},
-	{"no args", "hello", "no args%!(EXTRA string=hello)"},
 	{"%s %", "hello", "hello %!(NOVERB)"},
 	{"%s %.2", "hello", "hello %!(NOVERB)"},
-	{"%017091901790959340919092959340919017929593813360", 0, "%!(NOVERB)%!(EXTRA int=0)"},
-	{"%184467440737095516170v", 0, "%!(NOVERB)%!(EXTRA int=0)"},
-	// Extra argument errors should format without flags set.
-	{"%010.2", "12345", "%!(NOVERB)%!(EXTRA string=12345)"},
 
 	// The "<nil>" show up because maps are printed by
 	// first obtaining a list of keys and then looking up
@@ -966,7 +982,7 @@
 	{"%q", byteStringerSlice, "\"hello\""},
 	{"%x", byteStringerSlice, "68656c6c6f"},
 	{"%X", byteStringerSlice, "68656C6C6F"},
-	{"%#v", byteStringerSlice, "[]fmt_test.byteStringer{0x68, 0x65, 0x6c, 0x6c, 0x6f}"},
+	{"%#v", byteStringerSlice, "[]message.byteStringer{0x68, 0x65, 0x6c, 0x6c, 0x6f}"},
 
 	// And the same for Formatter.
 	{"%v", byteFormatterSlice, "[X X X X X]"},
@@ -975,7 +991,7 @@
 	{"%x", byteFormatterSlice, "68656c6c6f"},
 	{"%X", byteFormatterSlice, "68656C6C6F"},
 	// This next case seems wrong, but the docs say the Formatter wins here.
-	{"%#v", byteFormatterSlice, "[]fmt_test.byteFormatter{X, X, X, X, X}"},
+	{"%#v", byteFormatterSlice, "[]message.byteFormatter{X, 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()).
@@ -1010,9 +1026,9 @@
 	{"%☠", &intVar, "%!☠(*int=0xPTR)"},
 	{"%☠", make(chan int), "%!☠(chan int=0xPTR)"},
 	{"%☠", func() {}, "%!☠(func()=0xPTR)"},
-	{"%☠", reflect.ValueOf(renamedInt(0)), "%!☠(fmt_test.renamedInt=0)"},
-	{"%☠", SI{renamedInt(0)}, "{%!☠(fmt_test.renamedInt=0)}"},
-	{"%☠", &[]interface{}{I(1), G(2)}, "&[%!☠(fmt_test.I=1) %!☠(fmt_test.G=2)]"},
+	{"%☠", reflect.ValueOf(renamedInt(0)), "%!☠(message.renamedInt=0)"},
+	{"%☠", SI{renamedInt(0)}, "{%!☠(message.renamedInt=0)}"},
+	{"%☠", &[]interface{}{I(1), G(2)}, "&[%!☠(message.I=1) %!☠(message.G=2)]"},
 	{"%☠", SI{&[]interface{}{I(1), G(2)}}, "{%!☠(*[]interface {}=&[1 2])}"},
 	{"%☠", reflect.Value{}, "<invalid reflect.Value>"},
 	{"%☠", map[float64]int{NaN: 1}, "map[%!☠(float64=NaN):%!☠(<nil>)]"},
@@ -1025,57 +1041,63 @@
 }
 
 func TestSprintf(t *testing.T) {
+	p := NewPrinter(language.Und)
 	for _, tt := range fmtTests {
-		s := Sprintf(tt.fmt, tt.val)
-		i := strings.Index(tt.out, "PTR")
-		if i >= 0 && i < len(s) {
-			var pattern, chars string
-			switch {
-			case strings.HasPrefix(tt.out[i:], "PTR_b"):
-				pattern = "PTR_b"
-				chars = "01"
-			case strings.HasPrefix(tt.out[i:], "PTR_o"):
-				pattern = "PTR_o"
-				chars = "01234567"
-			case strings.HasPrefix(tt.out[i:], "PTR_d"):
-				pattern = "PTR_d"
-				chars = "0123456789"
-			case strings.HasPrefix(tt.out[i:], "PTR_x"):
-				pattern = "PTR_x"
-				chars = "0123456789abcdef"
-			case strings.HasPrefix(tt.out[i:], "PTR_X"):
-				pattern = "PTR_X"
-				chars = "0123456789ABCDEF"
-			default:
-				pattern = "PTR"
-				chars = "0123456789abcdefABCDEF"
+		t.Run(fmt.Sprint(tt.fmt, tt.val), func(t *testing.T) {
+			s := p.Sprintf(tt.fmt, tt.val)
+			i := strings.Index(tt.out, "PTR")
+			if i >= 0 && i < len(s) {
+				var pattern, chars string
+				switch {
+				case strings.HasPrefix(tt.out[i:], "PTR_b"):
+					pattern = "PTR_b"
+					chars = "01"
+				case strings.HasPrefix(tt.out[i:], "PTR_o"):
+					pattern = "PTR_o"
+					chars = "01234567"
+				case strings.HasPrefix(tt.out[i:], "PTR_d"):
+					pattern = "PTR_d"
+					chars = "0123456789"
+				case strings.HasPrefix(tt.out[i:], "PTR_x"):
+					pattern = "PTR_x"
+					chars = "0123456789abcdef"
+				case strings.HasPrefix(tt.out[i:], "PTR_X"):
+					pattern = "PTR_X"
+					chars = "0123456789ABCDEF"
+				default:
+					pattern = "PTR"
+					chars = "0123456789abcdefABCDEF"
+				}
+				p := s[:i] + pattern
+				for j := i; j < len(s); j++ {
+					if !strings.ContainsRune(chars, rune(s[j])) {
+						p += s[j:]
+						break
+					}
+				}
+				s = p
 			}
-			p := s[:i] + pattern
-			for j := i; j < len(s); j++ {
-				if !strings.ContainsRune(chars, rune(s[j])) {
-					p += s[j:]
-					break
+			if s != tt.out {
+				if _, ok := tt.val.(string); ok {
+					// Don't requote the already-quoted strings.
+					// It's too confusing to read the errors.
+					t.Errorf("Sprintf(%q, %q) = <%s> want <%s>", tt.fmt, tt.val, s, tt.out)
+				} else {
+					t.Errorf("Sprintf(%q, %v) = %q want %q", tt.fmt, tt.val, s, tt.out)
 				}
 			}
-			s = p
-		}
-		if s != tt.out {
-			if _, ok := tt.val.(string); ok {
-				// Don't requote the already-quoted strings.
-				// It's too confusing to read the errors.
-				t.Errorf("Sprintf(%q, %q) = <%s> want <%s>", tt.fmt, tt.val, s, tt.out)
-			} else {
-				t.Errorf("Sprintf(%q, %v) = %q want %q", tt.fmt, tt.val, s, tt.out)
-			}
-		}
+		})
 	}
 }
 
+var f float64
+
 // TestComplexFormatting checks that a complex always formats to the same
 // thing as if done by hand with two singleton prints.
 func TestComplexFormatting(t *testing.T) {
 	var yesNo = []bool{true, false}
 	var values = []float64{1, 0, -1, posInf, negInf, NaN}
+	p := NewPrinter(language.Und)
 	for _, plus := range yesNo {
 		for _, zero := range yesNo {
 			for _, space := range yesNo {
@@ -1102,8 +1124,8 @@
 					imagFmt += string(char)
 					for _, realValue := range values {
 						for _, imagValue := range values {
-							one := Sprintf(realFmt, complex(realValue, imagValue))
-							two := Sprintf("("+realFmt+imagFmt+"i)", realValue, imagValue)
+							one := p.Sprintf(realFmt, complex(realValue, imagValue))
+							two := p.Sprintf("("+realFmt+imagFmt+"i)", realValue, imagValue)
 							if one != two {
 								t.Error(f, one, two)
 							}
@@ -1118,9 +1140,9 @@
 type SE []interface{} // slice of empty; notational compactness.
 
 var reorderTests = []struct {
-	fmt string
-	val SE
-	out string
+	format string
+	args   SE
+	out    string
 }{
 	{"%[1]d", SE{1}, "1"},
 	{"%[2]d", SE{2, 1}, "1"},
@@ -1154,113 +1176,130 @@
 	{"%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)"},
+	// The following messages are interpreted as if there is no substitution,
+	// in which case it is okay to have extra arguments. This is different
+	// semantics from the fmt package.
+	{"%2147483648d", SE{42}, "%!(NOVERB)"},
+	{"%-2147483648d", SE{42}, "%!(NOVERB)"},
+	{"%.2147483648d", SE{42}, "%!(NOVERB)"},
 }
 
 func TestReorder(t *testing.T) {
-	for _, tt := range reorderTests {
-		s := Sprintf(tt.fmt, tt.val...)
-		if s != tt.out {
-			t.Errorf("Sprintf(%q, %v) = <%s> want <%s>", tt.fmt, tt.val, s, tt.out)
-		} else {
-		}
+	p := NewPrinter(language.Und)
+	for _, tc := range reorderTests {
+		t.Run(fmt.Sprint(tc.format, "/", tc.args), func(t *testing.T) {
+			s := p.Sprintf(tc.format, tc.args...)
+			if s != tc.out {
+				t.Errorf("Sprintf(%q, %v) = %q want %q", tc.format, tc.args, s, tc.out)
+			}
+		})
 	}
 }
 
 func BenchmarkSprintfPadding(b *testing.B) {
 	b.RunParallel(func(pb *testing.PB) {
+		p := NewPrinter(language.English)
 		for pb.Next() {
-			Sprintf("%16f", 1.0)
+			p.Sprintf("%16f", 1.0)
 		}
 	})
 }
 
 func BenchmarkSprintfEmpty(b *testing.B) {
 	b.RunParallel(func(pb *testing.PB) {
+		p := NewPrinter(language.English)
 		for pb.Next() {
-			Sprintf("")
+			p.Sprintf("")
 		}
 	})
 }
 
 func BenchmarkSprintfString(b *testing.B) {
 	b.RunParallel(func(pb *testing.PB) {
+		p := NewPrinter(language.English)
 		for pb.Next() {
-			Sprintf("%s", "hello")
+			p.Sprintf("%s", "hello")
 		}
 	})
 }
 
 func BenchmarkSprintfTruncateString(b *testing.B) {
 	b.RunParallel(func(pb *testing.PB) {
+		p := NewPrinter(language.English)
 		for pb.Next() {
-			Sprintf("%.3s", "日本語日本語日本語")
+			p.Sprintf("%.3s", "日本語日本語日本語")
 		}
 	})
 }
 
 func BenchmarkSprintfQuoteString(b *testing.B) {
 	b.RunParallel(func(pb *testing.PB) {
+		p := NewPrinter(language.English)
 		for pb.Next() {
-			Sprintf("%q", "日本語日本語日本語")
+			p.Sprintf("%q", "日本語日本語日本語")
 		}
 	})
 }
 
 func BenchmarkSprintfInt(b *testing.B) {
 	b.RunParallel(func(pb *testing.PB) {
+		p := NewPrinter(language.English)
 		for pb.Next() {
-			Sprintf("%d", 5)
+			p.Sprintf("%d", 5)
 		}
 	})
 }
 
 func BenchmarkSprintfIntInt(b *testing.B) {
 	b.RunParallel(func(pb *testing.PB) {
+		p := NewPrinter(language.English)
 		for pb.Next() {
-			Sprintf("%d %d", 5, 6)
+			p.Sprintf("%d %d", 5, 6)
 		}
 	})
 }
 
 func BenchmarkSprintfPrefixedInt(b *testing.B) {
 	b.RunParallel(func(pb *testing.PB) {
+		p := NewPrinter(language.English)
 		for pb.Next() {
-			Sprintf("This is some meaningless prefix text that needs to be scanned %d", 6)
+			p.Sprintf("This is some meaningless prefix text that needs to be scanned %d", 6)
 		}
 	})
 }
 
 func BenchmarkSprintfFloat(b *testing.B) {
 	b.RunParallel(func(pb *testing.PB) {
+		p := NewPrinter(language.English)
 		for pb.Next() {
-			Sprintf("%g", 5.23184)
+			p.Sprintf("%g", 5.23184)
 		}
 	})
 }
 
 func BenchmarkSprintfComplex(b *testing.B) {
 	b.RunParallel(func(pb *testing.PB) {
+		p := NewPrinter(language.English)
 		for pb.Next() {
-			Sprintf("%f", 5.23184+5.23184i)
+			p.Sprintf("%f", 5.23184+5.23184i)
 		}
 	})
 }
 
 func BenchmarkSprintfBoolean(b *testing.B) {
 	b.RunParallel(func(pb *testing.PB) {
+		p := NewPrinter(language.English)
 		for pb.Next() {
-			Sprintf("%t", true)
+			p.Sprintf("%t", true)
 		}
 	})
 }
 
 func BenchmarkSprintfHexString(b *testing.B) {
 	b.RunParallel(func(pb *testing.PB) {
+		p := NewPrinter(language.English)
 		for pb.Next() {
-			Sprintf("% #x", "0123456789abcdef")
+			p.Sprintf("% #x", "0123456789abcdef")
 		}
 	})
 }
@@ -1268,8 +1307,9 @@
 func BenchmarkSprintfHexBytes(b *testing.B) {
 	data := []byte("0123456789abcdef")
 	b.RunParallel(func(pb *testing.PB) {
+		p := NewPrinter(language.English)
 		for pb.Next() {
-			Sprintf("% #x", data)
+			p.Sprintf("% #x", data)
 		}
 	})
 }
@@ -1277,8 +1317,9 @@
 func BenchmarkSprintfBytes(b *testing.B) {
 	data := []byte("0123456789abcdef")
 	b.RunParallel(func(pb *testing.PB) {
+		p := NewPrinter(language.English)
 		for pb.Next() {
-			Sprintf("%v", data)
+			p.Sprintf("%v", data)
 		}
 	})
 }
@@ -1286,8 +1327,9 @@
 func BenchmarkSprintfStringer(b *testing.B) {
 	stringer := I(12345)
 	b.RunParallel(func(pb *testing.PB) {
+		p := NewPrinter(language.English)
 		for pb.Next() {
-			Sprintf("%v", stringer)
+			p.Sprintf("%v", stringer)
 		}
 	})
 }
@@ -1295,8 +1337,9 @@
 func BenchmarkSprintfStructure(b *testing.B) {
 	s := &[]interface{}{SI{12345}, map[int]string{0: "hello"}}
 	b.RunParallel(func(pb *testing.PB) {
+		p := NewPrinter(language.English)
 		for pb.Next() {
-			Sprintf("%#v", s)
+			p.Sprintf("%#v", s)
 		}
 	})
 }
@@ -1304,36 +1347,40 @@
 func BenchmarkManyArgs(b *testing.B) {
 	b.RunParallel(func(pb *testing.PB) {
 		var buf bytes.Buffer
+		p := NewPrinter(language.English)
 		for pb.Next() {
 			buf.Reset()
-			Fprintf(&buf, "%2d/%2d/%2d %d:%d:%d %s %s\n", 3, 4, 5, 11, 12, 13, "hello", "world")
+			p.Fprintf(&buf, "%2d/%2d/%2d %d:%d:%d %s %s\n", 3, 4, 5, 11, 12, 13, "hello", "world")
 		}
 	})
 }
 
 func BenchmarkFprintInt(b *testing.B) {
 	var buf bytes.Buffer
+	p := NewPrinter(language.English)
 	for i := 0; i < b.N; i++ {
 		buf.Reset()
-		Fprint(&buf, 123456)
+		p.Fprint(&buf, 123456)
 	}
 }
 
 func BenchmarkFprintfBytes(b *testing.B) {
 	data := []byte(string("0123456789"))
 	var buf bytes.Buffer
+	p := NewPrinter(language.English)
 	for i := 0; i < b.N; i++ {
 		buf.Reset()
-		Fprintf(&buf, "%s", data)
+		p.Fprintf(&buf, "%s", data)
 	}
 }
 
 func BenchmarkFprintIntNoAlloc(b *testing.B) {
 	var x interface{} = 123456
 	var buf bytes.Buffer
+	p := NewPrinter(language.English)
 	for i := 0; i < b.N; i++ {
 		buf.Reset()
-		Fprint(&buf, x)
+		p.Fprint(&buf, x)
 	}
 }
 
@@ -1343,19 +1390,19 @@
 var mallocTest = []struct {
 	count int
 	desc  string
-	fn    func()
+	fn    func(p *Printer)
 }{
-	{0, `Sprintf("")`, func() { Sprintf("") }},
-	{1, `Sprintf("xxx")`, func() { Sprintf("xxx") }},
-	{2, `Sprintf("%x")`, func() { Sprintf("%x", 7) }},
-	{2, `Sprintf("%s")`, func() { Sprintf("%s", "hello") }},
-	{3, `Sprintf("%x %x")`, func() { Sprintf("%x %x", 7, 112) }},
-	{2, `Sprintf("%g")`, func() { Sprintf("%g", float32(3.14159)) }}, // TODO: Can this be 1?
-	{1, `Fprintf(buf, "%s")`, func() { mallocBuf.Reset(); Fprintf(&mallocBuf, "%s", "hello") }},
+	{0, `Sprintf("")`, func(p *Printer) { p.Sprintf("") }},
+	{1, `Sprintf("xxx")`, func(p *Printer) { p.Sprintf("xxx") }},
+	{2, `Sprintf("%x")`, func(p *Printer) { p.Sprintf("%x", 7) }},
+	{2, `Sprintf("%s")`, func(p *Printer) { p.Sprintf("%s", "hello") }},
+	{3, `Sprintf("%x %x")`, func(p *Printer) { p.Sprintf("%x %x", 7, 112) }},
+	{2, `Sprintf("%g")`, func(p *Printer) { p.Sprintf("%g", float32(3.14159)) }}, // TODO: Can this be 1?
+	{1, `Fprintf(buf, "%s")`, func(p *Printer) { mallocBuf.Reset(); p.Fprintf(&mallocBuf, "%s", "hello") }},
 	// If the interface value doesn't need to allocate, amortized allocation overhead should be zero.
-	{0, `Fprintf(buf, "%x %x %x")`, func() {
+	{0, `Fprintf(buf, "%x %x %x")`, func(p *Printer) {
 		mallocBuf.Reset()
-		Fprintf(&mallocBuf, "%x %x %x", mallocPointer, mallocPointer, mallocPointer)
+		p.Fprintf(&mallocBuf, "%x %x %x", mallocPointer, mallocPointer, mallocPointer)
 	}},
 }
 
@@ -1367,11 +1414,13 @@
 		t.Skip("skipping malloc count in short mode")
 	case runtime.GOMAXPROCS(0) > 1:
 		t.Skip("skipping; GOMAXPROCS>1")
-	case race.Enabled:
-		t.Skip("skipping malloc count under race detector")
+		// TODO: detect race detecter enabled.
+		// case race.Enabled:
+		// 	t.Skip("skipping malloc count under race detector")
 	}
+	p := NewPrinter(language.English)
 	for _, mt := range mallocTest {
-		mallocs := testing.AllocsPerRun(100, mt.fn)
+		mallocs := testing.AllocsPerRun(100, func() { mt.fn(p) })
 		if got, max := mallocs, float64(mt.count); got > max {
 			t.Errorf("%s: got %v allocs, want <=%v", mt.desc, got, max)
 		}
@@ -1380,7 +1429,7 @@
 
 type flagPrinter struct{}
 
-func (flagPrinter) Format(f State, c rune) {
+func (flagPrinter) Format(f fmt.State, c rune) {
 	s := "%"
 	for i := 0; i < 128; i++ {
 		if f.Flag(i) {
@@ -1388,10 +1437,10 @@
 		}
 	}
 	if w, ok := f.Width(); ok {
-		s += Sprintf("%d", w)
+		s += fmt.Sprintf("%d", w)
 	}
 	if p, ok := f.Precision(); ok {
-		s += Sprintf(".%d", p)
+		s += fmt.Sprintf(".%d", p)
 	}
 	s += string(c)
 	io.WriteString(f, "["+s+"]")
@@ -1418,7 +1467,7 @@
 func TestFlagParser(t *testing.T) {
 	var flagprinter flagPrinter
 	for _, tt := range flagtests {
-		s := Sprintf(tt.in, &flagprinter)
+		s := NewPrinter(language.Und).Sprintf(tt.in, &flagprinter)
 		if s != tt.out {
 			t.Errorf("Sprintf(%q, &flagprinter) => %q, want %q", tt.in, s, tt.out)
 		}
@@ -1441,15 +1490,16 @@
 	}{
 		{"%v", "{abc def 123}"},
 		{"%+v", "{a:abc b:def c:123}"},
-		{"%#v", `fmt_test.T{a:"abc", b:"def", c:123}`},
+		{"%#v", `message.T{a:"abc", b:"def", c:123}`},
 	}
+	p := NewPrinter(language.Und)
 	for _, tt := range tests {
-		out := Sprintf(tt.fmt, s)
+		out := p.Sprintf(tt.fmt, s)
 		if out != tt.out {
 			t.Errorf("Sprintf(%q, s) = %#q, want %#q", tt.fmt, out, tt.out)
 		}
 		// The same but with a pointer.
-		out = Sprintf(tt.fmt, &s)
+		out = p.Sprintf(tt.fmt, &s)
 		if out != "&"+tt.out {
 			t.Errorf("Sprintf(%q, &s) = %#q, want %#q", tt.fmt, out, "&"+tt.out)
 		}
@@ -1457,17 +1507,18 @@
 }
 
 func TestSlicePrinter(t *testing.T) {
+	p := NewPrinter(language.Und)
 	slice := []int{}
-	s := Sprint(slice)
+	s := p.Sprint(slice)
 	if s != "[]" {
 		t.Errorf("empty slice printed as %q not %q", s, "[]")
 	}
 	slice = []int{1, 2, 3}
-	s = Sprint(slice)
+	s = p.Sprint(slice)
 	if s != "[1 2 3]" {
 		t.Errorf("slice: got %q expected %q", s, "[1 2 3]")
 	}
-	s = Sprint(&slice)
+	s = p.Sprint(&slice)
 	if s != "&[1 2 3]" {
 		t.Errorf("&slice: got %q expected %q", s, "&[1 2 3]")
 	}
@@ -1490,32 +1541,34 @@
 }
 
 func TestMapPrinter(t *testing.T) {
+	p := NewPrinter(language.Und)
 	m0 := make(map[int]string)
-	s := Sprint(m0)
+	s := p.Sprint(m0)
 	if s != "map[]" {
 		t.Errorf("empty map printed as %q not %q", s, "map[]")
 	}
 	m1 := map[int]string{1: "one", 2: "two", 3: "three"}
 	a := []string{"1:one", "2:two", "3:three"}
-	presentInMap(Sprintf("%v", m1), a, t)
-	presentInMap(Sprint(m1), a, t)
+	presentInMap(p.Sprintf("%v", m1), a, t)
+	presentInMap(p.Sprint(m1), a, t)
 	// Pointer to map prints the same but with initial &.
-	if !strings.HasPrefix(Sprint(&m1), "&") {
+	if !strings.HasPrefix(p.Sprint(&m1), "&") {
 		t.Errorf("no initial & for address of map")
 	}
-	presentInMap(Sprintf("%v", &m1), a, t)
-	presentInMap(Sprint(&m1), a, t)
+	presentInMap(p.Sprintf("%v", &m1), a, t)
+	presentInMap(p.Sprint(&m1), a, t)
 }
 
 func TestEmptyMap(t *testing.T) {
 	const emptyMapStr = "map[]"
 	var m map[string]int
-	s := Sprint(m)
+	p := NewPrinter(language.Und)
+	s := p.Sprint(m)
 	if s != emptyMapStr {
 		t.Errorf("nil map printed as %q not %q", s, emptyMapStr)
 	}
 	m = make(map[string]int)
-	s = Sprint(m)
+	s = p.Sprint(m)
 	if s != emptyMapStr {
 		t.Errorf("empty map printed as %q not %q", s, emptyMapStr)
 	}
@@ -1524,7 +1577,8 @@
 // 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, "!")
+	p := NewPrinter(language.Und)
+	got := p.Sprint("<", 1, ">:", 1, 2, 3, "!")
 	expect := "<1>:1 2 3!"
 	if got != expect {
 		t.Errorf("got %q expected %q", got, expect)
@@ -1534,7 +1588,8 @@
 // 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, "!")
+	p := NewPrinter(language.Und)
+	got := p.Sprintln("<", 1, ">:", 1, 2, 3, "!")
 	expect := "< 1 >: 1 2 3 !\n"
 	if got != expect {
 		t.Errorf("got %q expected %q", got, expect)
@@ -1543,17 +1598,18 @@
 
 // TestFormatterPrintln checks Formatter with Sprint, Sprintln, Sprintf.
 func TestFormatterPrintln(t *testing.T) {
+	p := NewPrinter(language.Und)
 	f := F(1)
 	expect := "<v=F(1)>\n"
-	s := Sprint(f, "\n")
+	s := p.Sprint(f, "\n")
 	if s != expect {
 		t.Errorf("Sprint wrong with Formatter: expected %q got %q", expect, s)
 	}
-	s = Sprintln(f)
+	s = p.Sprintln(f)
 	if s != expect {
 		t.Errorf("Sprintln wrong with Formatter: expected %q got %q", expect, s)
 	}
-	s = Sprintf("%v\n", f)
+	s = p.Sprintf("%v\n", f)
 	if s != expect {
 		t.Errorf("Sprintf wrong with Formatter: expected %q got %q", expect, s)
 	}
@@ -1595,11 +1651,14 @@
 }
 
 func TestWidthAndPrecision(t *testing.T) {
+	p := NewPrinter(language.Und)
 	for i, tt := range startests {
-		s := Sprintf(tt.fmt, tt.in...)
-		if s != tt.out {
-			t.Errorf("#%d: %q: got %q expected %q", i, tt.fmt, s, tt.out)
-		}
+		t.Run(fmt.Sprint(tt.fmt, tt.in), func(t *testing.T) {
+			s := p.Sprintf(tt.fmt, tt.in...)
+			if s != tt.out {
+				t.Errorf("#%d: %q: got %q expected %q", i, tt.fmt, s, tt.out)
+			}
+		})
 	}
 }
 
@@ -1629,37 +1688,41 @@
 }
 
 // Value receiver.
-func (p PanicF) Format(f State, c rune) {
+func (p PanicF) Format(f fmt.State, c rune) {
 	panic(p.message)
 }
 
 var panictests = []struct {
-	fmt string
-	in  interface{}
-	out string
+	desc string
+	fmt  string
+	in   interface{}
+	out  string
 }{
 	// String
-	{"%s", (*PanicS)(nil), "<nil>"}, // nil pointer special case
-	{"%s", PanicS{io.ErrUnexpectedEOF}, "%!s(PANIC=unexpected EOF)"},
-	{"%s", PanicS{3}, "%!s(PANIC=3)"},
+	{"String", "%s", (*PanicS)(nil), "<nil>"}, // nil pointer special case
+	{"String", "%s", PanicS{io.ErrUnexpectedEOF}, "%!s(PANIC=unexpected EOF)"},
+	{"String", "%s", PanicS{3}, "%!s(PANIC=3)"},
 	// GoString
-	{"%#v", (*PanicGo)(nil), "<nil>"}, // nil pointer special case
-	{"%#v", PanicGo{io.ErrUnexpectedEOF}, "%!v(PANIC=unexpected EOF)"},
-	{"%#v", PanicGo{3}, "%!v(PANIC=3)"},
+	{"GoString", "%#v", (*PanicGo)(nil), "<nil>"}, // nil pointer special case
+	{"GoString", "%#v", PanicGo{io.ErrUnexpectedEOF}, "%!v(PANIC=unexpected EOF)"},
+	{"GoString", "%#v", PanicGo{3}, "%!v(PANIC=3)"},
 	// Issue 18282. catchPanic should not clear fmtFlags permanently.
-	{"%#v", []interface{}{PanicGo{3}, PanicGo{3}}, "[]interface {}{%!v(PANIC=3), %!v(PANIC=3)}"},
+	{"Issue 18282", "%#v", []interface{}{PanicGo{3}, PanicGo{3}}, "[]interface {}{%!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)"},
+	{"Format", "%s", (*PanicF)(nil), "<nil>"}, // nil pointer special case
+	{"Format", "%s", PanicF{io.ErrUnexpectedEOF}, "%!s(PANIC=unexpected EOF)"},
+	{"Format", "%s", PanicF{3}, "%!s(PANIC=3)"},
 }
 
 func TestPanics(t *testing.T) {
+	p := NewPrinter(language.Und)
 	for i, tt := range panictests {
-		s := Sprintf(tt.fmt, tt.in)
-		if s != tt.out {
-			t.Errorf("%d: %q: got %q expected %q", i, tt.fmt, s, tt.out)
-		}
+		t.Run(fmt.Sprint(tt.desc, "/", tt.fmt, "/", tt.in), func(t *testing.T) {
+			s := p.Sprintf(tt.fmt, tt.in)
+			if s != tt.out {
+				t.Errorf("%d: %q: got %q expected %q", i, tt.fmt, s, tt.out)
+			}
+		})
 	}
 }
 
@@ -1672,6 +1735,7 @@
 }
 
 func (r *Recur) String() string {
+	p := NewPrinter(language.Und)
 	if recurCount++; recurCount > 10 {
 		*r.failed = true
 		return "FAIL"
@@ -1679,41 +1743,33 @@
 	// This will call badVerb. Before the fix, that would cause us to recur into
 	// this routine to print %!p(value). Now we don't call the user's method
 	// during an error.
-	return Sprintf("recur@%p value: %d", r, r.i)
+	return p.Sprintf("recur@%p value: %d", r, r.i)
 }
 
 func TestBadVerbRecursion(t *testing.T) {
+	p := NewPrinter(language.Und)
 	failed := false
 	r := &Recur{3, &failed}
-	Sprintf("recur@%p value: %d\n", &r, r.i)
+	p.Sprintf("recur@%p value: %d\n", &r, r.i)
 	if failed {
 		t.Error("fail with pointer")
 	}
 	failed = false
 	r = &Recur{4, &failed}
-	Sprintf("recur@%p, value: %d\n", r, r.i)
+	p.Sprintf("recur@%p, value: %d\n", r, r.i)
 	if failed {
 		t.Error("fail with value")
 	}
 }
 
-func TestIsSpace(t *testing.T) {
-	// This tests the internal isSpace function.
-	// IsSpace = isSpace is defined in export_test.go.
-	for i := rune(0); i <= unicode.MaxRune; i++ {
-		if IsSpace(i) != unicode.IsSpace(i) {
-			t.Errorf("isSpace(%U) = %v, want %v", i, IsSpace(i), unicode.IsSpace(i))
-		}
-	}
-}
-
 func TestNilDoesNotBecomeTyped(t *testing.T) {
+	p := NewPrinter(language.Und)
 	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) // go vet should complain about this line.
-	const expect = "%!s(<nil>) %!s(*fmt_test.A=<nil>) %!s(<nil>) {} %!s(<nil>)"
+	got := p.Sprintf("%s %s %s %s %s", nil, a, nil, b, nil) // go vet should complain about this line.
+	const expect = "%!s(<nil>) %!s(*message.A=<nil>) %!s(<nil>) {} %!s(<nil>)"
 	if got != expect {
 		t.Errorf("expected:\n\t%q\ngot:\n\t%q", expect, got)
 	}
@@ -1770,7 +1826,7 @@
 	{"%v", [1]flagPrinter{}, "[[%v]]"},
 	{"%-v", [1]flagPrinter{}, "[[%-v]]"},
 	{"%+v", [1]flagPrinter{}, "[[%+v]]"},
-	{"%#v", [1]flagPrinter{}, "[1]fmt_test.flagPrinter{[%#v]}"},
+	{"%#v", [1]flagPrinter{}, "[1]message.flagPrinter{[%#v]}"},
 	{"% v", [1]flagPrinter{}, "[[% v]]"},
 	{"%0v", [1]flagPrinter{}, "[[%0v]]"},
 	{"%1.2v", [1]flagPrinter{}, "[[%1.2v]]"},
@@ -1782,8 +1838,9 @@
 }
 
 func TestFormatterFlags(t *testing.T) {
+	p := NewPrinter(language.Und)
 	for _, tt := range formatterFlagTests {
-		s := Sprintf(tt.in, tt.val)
+		s := p.Sprintf(tt.in, tt.val)
 		if s != tt.out {
 			t.Errorf("Sprintf(%q, %T) = %q, want %q", tt.in, tt.val, s, tt.out)
 		}
@@ -1806,7 +1863,7 @@
 		{"1a234", 1, 3, 0, false, 1},
 	}
 	for _, tt := range testCases {
-		num, isnum, newi := Parsenum(tt.s, tt.start, tt.end)
+		num, isnum, newi := parsenum(tt.s, tt.start, tt.end)
 		if num != tt.num || isnum != tt.isnum || newi != tt.newi {
 			t.Errorf("parsenum(%q, %d, %d) = %d, %v, %d, want %d, %v, %d", tt.s, tt.start, tt.end, num, isnum, newi, tt.num, tt.isnum, tt.newi)
 		}
diff --git a/message/format.go b/message/format.go
index f80082b..d3340d1 100644
--- a/message/format.go
+++ b/message/format.go
@@ -1,11 +1,11 @@
-// +build ignore
-// Copyright 2009 The Go Authors. All rights reserved.
+// Copyright 2017 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.
 
-package fmt
+package message
 
 import (
+	"bytes"
 	"strconv"
 	"unicode/utf8"
 )
@@ -37,10 +37,10 @@
 	sharpV bool
 }
 
-// A fmt is the raw formatter used by Printf etc.
+// A formatInfo is the raw formatter used by Printf etc.
 // It prints into a buffer that must be set up separately.
-type fmt struct {
-	buf *buffer
+type formatInfo struct {
+	buf *bytes.Buffer
 
 	fmtFlags
 
@@ -52,43 +52,34 @@
 	intbuf [68]byte
 }
 
-func (f *fmt) clearflags() {
+func (f *formatInfo) clearflags() {
 	f.fmtFlags = fmtFlags{}
 }
 
-func (f *fmt) init(buf *buffer) {
+func (f *formatInfo) init(buf *bytes.Buffer) {
 	f.buf = buf
 	f.clearflags()
 }
 
 // writePadding generates n bytes of padding.
-func (f *fmt) writePadding(n int) {
+func (f *formatInfo) writePadding(n int) {
 	if n <= 0 { // No padding bytes needed.
 		return
 	}
-	buf := *f.buf
-	oldLen := len(buf)
-	newLen := oldLen + n
-	// Make enough room for padding.
-	if newLen > cap(buf) {
-		buf = make(buffer, cap(buf)*2+n)
-		copy(buf, *f.buf)
-	}
+	f.buf.Grow(n)
 	// Decide which byte the padding should be filled with.
 	padByte := byte(' ')
 	if f.zero {
 		padByte = byte('0')
 	}
 	// Fill padding with padByte.
-	padding := buf[oldLen:newLen]
-	for i := range padding {
-		padding[i] = padByte
+	for i := 0; i < n; i++ {
+		f.buf.WriteByte(padByte) // TODO: make more efficient.
 	}
-	*f.buf = buf[:newLen]
 }
 
 // pad appends b to f.buf, padded on left (!f.minus) or right (f.minus).
-func (f *fmt) pad(b []byte) {
+func (f *formatInfo) pad(b []byte) {
 	if !f.widPresent || f.wid == 0 {
 		f.buf.Write(b)
 		return
@@ -106,7 +97,7 @@
 }
 
 // padString appends s to f.buf, padded on left (!f.minus) or right (f.minus).
-func (f *fmt) padString(s string) {
+func (f *formatInfo) padString(s string) {
 	if !f.widPresent || f.wid == 0 {
 		f.buf.WriteString(s)
 		return
@@ -124,7 +115,7 @@
 }
 
 // fmt_boolean formats a boolean.
-func (f *fmt) fmt_boolean(v bool) {
+func (f *formatInfo) fmt_boolean(v bool) {
 	if v {
 		f.padString("true")
 	} else {
@@ -133,7 +124,7 @@
 }
 
 // fmt_unicode formats a uint64 as "U+0078" or with f.sharp set as "U+0078 'x'".
-func (f *fmt) fmt_unicode(u uint64) {
+func (f *formatInfo) fmt_unicode(u uint64) {
 	buf := f.intbuf[0:]
 
 	// With default precision set the maximum needed buf length is 18
@@ -192,7 +183,7 @@
 }
 
 // fmt_integer formats signed and unsigned integers.
-func (f *fmt) fmt_integer(u uint64, base int, isSigned bool, digits string) {
+func (f *formatInfo) fmt_integer(u uint64, base int, isSigned bool, digits string) {
 	negative := isSigned && int64(u) < 0
 	if negative {
 		u = -u
@@ -310,7 +301,7 @@
 }
 
 // truncate truncates the string to the specified precision, if present.
-func (f *fmt) truncate(s string) string {
+func (f *formatInfo) truncate(s string) string {
 	if f.precPresent {
 		n := f.prec
 		for i := range s {
@@ -324,13 +315,13 @@
 }
 
 // fmt_s formats a string.
-func (f *fmt) fmt_s(s string) {
+func (f *formatInfo) fmt_s(s string) {
 	s = f.truncate(s)
 	f.padString(s)
 }
 
 // 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) {
+func (f *formatInfo) fmt_sbx(s string, b []byte, digits string) {
 	length := len(b)
 	if b == nil {
 		// No byte slice present. Assume string s should be encoded.
@@ -365,19 +356,21 @@
 		f.writePadding(f.wid - width)
 	}
 	// Write the encoding directly into the output buffer.
-	buf := *f.buf
+	buf := f.buf
 	if f.sharp {
 		// Add leading 0x or 0X.
-		buf = append(buf, '0', digits[16])
+		buf.WriteByte('0')
+		buf.WriteByte(digits[16])
 	}
 	var c byte
 	for i := 0; i < length; i++ {
 		if f.space && i > 0 {
 			// Separate elements with a space.
-			buf = append(buf, ' ')
+			buf.WriteByte(' ')
 			if f.sharp {
 				// Add leading 0x or 0X for each element.
-				buf = append(buf, '0', digits[16])
+				buf.WriteByte('0')
+				buf.WriteByte(digits[16])
 			}
 		}
 		if b != nil {
@@ -386,9 +379,9 @@
 			c = s[i] // Take a byte from the input string.
 		}
 		// Encode each byte as two hexadecimal digits.
-		buf = append(buf, digits[c>>4], digits[c&0xF])
+		buf.WriteByte(digits[c>>4])
+		buf.WriteByte(digits[c&0xF])
 	}
-	*f.buf = buf
 	// Handle padding to the right.
 	if f.widPresent && f.wid > width && f.minus {
 		f.writePadding(f.wid - width)
@@ -396,19 +389,19 @@
 }
 
 // fmt_sx formats a string as a hexadecimal encoding of its bytes.
-func (f *fmt) fmt_sx(s, digits string) {
+func (f *formatInfo) 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) {
+func (f *formatInfo) fmt_bx(b []byte, digits string) {
 	f.fmt_sbx("", b, digits)
 }
 
 // fmt_q formats a string as a double-quoted, escaped Go string constant.
 // If f.sharp is set a raw (backquoted) string may be returned instead
 // if the string does not contain any control characters other than tab.
-func (f *fmt) fmt_q(s string) {
+func (f *formatInfo) fmt_q(s string) {
 	s = f.truncate(s)
 	if f.sharp && strconv.CanBackquote(s) {
 		f.padString("`" + s + "`")
@@ -424,7 +417,7 @@
 
 // fmt_c formats an integer as a Unicode character.
 // If the character is not valid Unicode, it will print '\ufffd'.
-func (f *fmt) fmt_c(c uint64) {
+func (f *formatInfo) fmt_c(c uint64) {
 	r := rune(c)
 	if c > utf8.MaxRune {
 		r = utf8.RuneError
@@ -436,7 +429,7 @@
 
 // fmt_qc formats an 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 uint64) {
+func (f *formatInfo) fmt_qc(c uint64) {
 	r := rune(c)
 	if c > utf8.MaxRune {
 		r = utf8.RuneError
@@ -451,7 +444,7 @@
 
 // fmt_float formats a float64. It assumes that verb is a valid format specifier
 // for strconv.AppendFloat and therefore fits into a byte.
-func (f *fmt) fmt_float(v float64, size int, verb rune, prec int) {
+func (f *formatInfo) fmt_float(v float64, size int, verb rune, prec int) {
 	// Explicit precision in format specifier overrules default precision.
 	if f.precPresent {
 		prec = f.prec
diff --git a/message/message.go b/message/message.go
index 92c7a93..edcd3bf 100644
--- a/message/message.go
+++ b/message/message.go
@@ -10,13 +10,9 @@
 package message // import "golang.org/x/text/message"
 
 import (
-	"bytes"
-	"fmt"
 	"io"
 	"os"
-	"strings"
 
-	"golang.org/x/text/internal/format"
 	"golang.org/x/text/language"
 	"golang.org/x/text/message/catalog"
 )
@@ -32,16 +28,6 @@
 	// road if it the benefits do not seem to outweigh the disadvantages.
 }
 
-type printer struct {
-	tag language.Tag
-
-	catContext *catalog.Context
-
-	buf bytes.Buffer
-
-	args []interface{}
-}
-
 // NewPrinter returns a Printer that formats messages tailored to language t.
 func NewPrinter(t language.Tag) *Printer {
 	p := &Printer{printer{
@@ -53,55 +39,65 @@
 
 // Sprint is like fmt.Sprint, but using language-specific formatting.
 func (p *Printer) Sprint(a ...interface{}) string {
-	return fmt.Sprint(p.bindArgs(a)...)
+	p.printer.reset()
+	p.printer.doPrint(a)
+	return p.printer.String()
 }
 
 // Fprint is like fmt.Fprint, but using language-specific formatting.
 func (p *Printer) Fprint(w io.Writer, a ...interface{}) (n int, err error) {
-	return fmt.Fprint(w, p.bindArgs(a)...)
+	p.printer.reset()
+	p.printer.doPrint(a)
+	n64, err := io.Copy(w, &p.printer.Buffer)
+	return int(n64), err
 }
 
 // Print is like fmt.Print, but using language-specific formatting.
 func (p *Printer) Print(a ...interface{}) (n int, err error) {
-	return fmt.Print(p.bindArgs(a)...)
+	return p.Fprint(os.Stdout, a...)
 }
 
 // Sprintln is like fmt.Sprintln, but using language-specific formatting.
 func (p *Printer) Sprintln(a ...interface{}) string {
-	return fmt.Sprintln(p.bindArgs(a)...)
+	p.printer.reset()
+	p.printer.doPrintln(a)
+	return p.printer.String()
 }
 
 // Fprintln is like fmt.Fprintln, but using language-specific formatting.
 func (p *Printer) Fprintln(w io.Writer, a ...interface{}) (n int, err error) {
-	return fmt.Fprintln(w, p.bindArgs(a)...)
+	p.printer.reset()
+	p.printer.doPrintln(a)
+	n64, err := io.Copy(w, &p.printer.Buffer)
+	return int(n64), err
 }
 
 // Println is like fmt.Println, but using language-specific formatting.
 func (p *Printer) Println(a ...interface{}) (n int, err error) {
-	return fmt.Println(p.bindArgs(a)...)
+	return p.Fprintln(os.Stdout, a...)
 }
 
 // Sprintf is like fmt.Sprintf, but using language-specific formatting.
 func (p *Printer) Sprintf(key Reference, a ...interface{}) string {
 	lookupAndFormat(p, key, a)
-	return p.printer.buf.String()
+	return p.printer.String()
 }
 
 // Fprintf is like fmt.Fprintf, but using language-specific formatting.
 func (p *Printer) Fprintf(w io.Writer, key Reference, a ...interface{}) (n int, err error) {
 	lookupAndFormat(p, key, a)
-	return w.Write(p.printer.buf.Bytes())
+	return w.Write(p.printer.Bytes())
 }
 
 // Printf is like fmt.Printf, but using language-specific formatting.
 func (p *Printer) Printf(key Reference, a ...interface{}) (n int, err error) {
 	lookupAndFormat(p, key, a)
-	return os.Stdout.Write(p.printer.buf.Bytes())
+	return os.Stdout.Write(p.printer.Bytes())
 }
 
 func lookupAndFormat(p *Printer, r Reference, a []interface{}) {
-	p.printer.buf.Reset()
-	p.printer.args = p.bindArgs(a)
+	p.printer.reset()
+	p.printer.args = a
 	var id, msg string
 	switch v := r.(type) {
 	case string:
@@ -121,7 +117,7 @@
 }
 
 // Arg implements catmsg.Renderer.
-func (p *printer) Arg(i int) interface{} {
+func (p *printer) Arg(i int) interface{} { // TODO, also return "ok" bool
 	if uint(i) < uint(len(p.args)) {
 		return p.args[i]
 	}
@@ -130,31 +126,7 @@
 
 // Render implements catmsg.Renderer.
 func (p *printer) Render(msg string) {
-	// fmt does not allow all arguments to be dropped in a format string. It
-	// only allows arguments to be dropped if at least one of the substitutions
-	// uses the positional marker (e.g. %[1]s). This hack works around this.
-	// TODO: This is only an approximation of the parsing of substitution
-	// patterns. Make more precise once we know if we can get by with fmt's
-	// formatting, which may not be the case.
-	var hasSub bool
-	for i := 0; i < len(msg)-1; i++ {
-		if msg[i] == '%' {
-			for i++; i < len(msg); i++ {
-				if strings.IndexByte("[]#+- *01234567890.", msg[i]) < 0 {
-					break
-				}
-			}
-			if i < len(msg) && msg[i] != '%' {
-				hasSub = true
-				break
-			}
-		}
-	}
-	if !hasSub {
-		fmt.Fprintf(&p.buf, msg)
-		return
-	}
-	fmt.Fprintf(&p.buf, msg, p.args...)
+	p.doPrintf(msg)
 }
 
 // A Reference is a string or a message reference.
@@ -171,46 +143,3 @@
 type key struct {
 	id, fallback string
 }
-
-// bindArgs wraps arguments with implementation of fmt.Formatter, if needed.
-func (p *Printer) bindArgs(a []interface{}) []interface{} {
-	out := make([]interface{}, len(a))
-	for i, x := range a {
-		switch v := x.(type) {
-		case fmt.Formatter:
-			// Wrap the value with a Formatter that augments the State with
-			// language-specific attributes.
-			out[i] = &value{v, p}
-
-			// NOTE: as we use fmt.Formatter, we can't distinguish between
-			// regular and localized formatters, so we always need to wrap it.
-
-			// TODO: handle
-			// - numbers
-			// - lists
-			// - time?
-		default:
-			out[i] = x
-		}
-	}
-	return out
-}
-
-// state implements "golang.org/x/text/internal/format".State.
-type state struct {
-	fmt.State
-	p *Printer
-}
-
-func (s *state) Language() language.Tag { return s.p.printer.tag }
-
-var _ format.State = &state{}
-
-type value struct {
-	x fmt.Formatter
-	p *Printer
-}
-
-func (v *value) Format(s fmt.State, verb rune) {
-	v.x.Format(&state{s, v.p}, verb)
-}
diff --git a/message/message_test.go b/message/message_test.go
index 73afd64..9c14813 100644
--- a/message/message_test.go
+++ b/message/message_test.go
@@ -132,24 +132,26 @@
 		cat, _ := initCat(tc.cat)
 
 		for i, pt := range tc.test {
-			tag := language.MustParse(pt.tag)
-			p := Printer{printer{
-				tag: tag,
-			}}
-			p.printer.catContext = cat.Context(tag, &p.printer)
+			t.Run(fmt.Sprintf("%s:%d", tc.desc, i), func(t *testing.T) {
+				tag := language.MustParse(pt.tag)
+				p := Printer{printer{
+					tag: tag,
+				}}
+				p.printer.catContext = cat.Context(tag, &p.printer)
 
-			if got := p.Sprintf(pt.key, pt.args...); got != pt.want {
-				t.Errorf("%s:%d:Sprintf(%s, %v) = %s; want %s",
-					tc.desc, i, pt.key, pt.args, got, pt.want)
-				continue // Next error will likely be the same.
-			}
+				if got := p.Sprintf(pt.key, pt.args...); got != pt.want {
+					t.Errorf("Sprintf(%q, %v) = %s; want %s",
+						pt.key, pt.args, got, pt.want)
+					return // Next error will likely be the same.
+				}
 
-			w := &bytes.Buffer{}
-			p.Fprintf(w, pt.key, pt.args...)
-			if got := w.String(); got != pt.want {
-				t.Errorf("%s:%d:Fprintf(%s, %v) = %s; want %s",
-					tc.desc, i, pt.key, pt.args, got, pt.want)
-			}
+				w := &bytes.Buffer{}
+				p.Fprintf(w, pt.key, pt.args...)
+				if got := w.String(); got != pt.want {
+					t.Errorf("Fprintf(%q, %v) = %s; want %s",
+						pt.key, pt.args, got, pt.want)
+				}
+			})
 		}
 	}
 }
diff --git a/message/print.go b/message/print.go
index 305b7e5..caa50b6 100644
--- a/message/print.go
+++ b/message/print.go
@@ -1,17 +1,18 @@
-// +build ignore
-// Copyright 2009 The Go Authors. All rights reserved.
+// Copyright 2017 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.
 
-package fmt
+package message
 
 import (
-	"errors"
-	"io"
-	"os"
+	"bytes"
+	// TODO: consider copying interfaces from package fmt to avoid dependency.
+	"fmt"
 	"reflect"
-	"sync"
 	"unicode/utf8"
+
+	"golang.org/x/text/language"
+	"golang.org/x/text/message/catalog"
 )
 
 // Strings for use with buffer.WriteString.
@@ -30,90 +31,32 @@
 	badWidthString    = "%!(BADWIDTH)"
 	badPrecString     = "%!(BADPREC)"
 	noVerbString      = "%!(NOVERB)"
-	invReflectString  = "<invalid reflect.Value>"
+
+	invReflectString = "<invalid reflect.Value>"
 )
 
-// State represents the printer state passed to custom formatters.
-// It provides access to the io.Writer interface plus information about
-// the flags and options for the operand's format specifier.
-type State interface {
-	// Write is the function to call to emit formatted output to be printed.
-	Write(b []byte) (n int, err error)
-	// Width returns the value of the width option and whether it has been set.
-	Width() (wid int, ok bool)
-	// Precision returns the value of the precision option and whether it has been set.
-	Precision() (prec int, ok bool)
+// printer is used to store a printer's state.
+// It implements "golang.org/x/text/internal/format".State.
+type printer struct {
+	// the context for looking up message translations
+	catContext *catalog.Context
+	// the language
+	tag language.Tag
 
-	// Flag reports whether the flag c, a character, has been set.
-	Flag(c int) bool
-}
+	// buffer for accumulating output.
+	bytes.Buffer
 
-// Formatter is the interface implemented by values with a custom formatter.
-// The implementation of Format may call Sprint(f) or Fprint(f) etc.
-// to generate its output.
-type Formatter interface {
-	Format(f State, c rune)
-}
-
-// 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 any format that accepts a string or to an unformatted printer
-// such as Print.
-type Stringer interface {
-	String() string
-}
-
-// 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.
-type GoStringer interface {
-	GoString() string
-}
-
-// Use simple []byte instead of bytes.Buffer to avoid large dependency.
-type buffer []byte
-
-func (b *buffer) Write(p []byte) {
-	*b = append(*b, p...)
-}
-
-func (b *buffer) WriteString(s string) {
-	*b = append(*b, s...)
-}
-
-func (b *buffer) WriteByte(c byte) {
-	*b = append(*b, c)
-}
-
-func (bp *buffer) WriteRune(r rune) {
-	if r < utf8.RuneSelf {
-		*bp = append(*bp, byte(r))
-		return
-	}
-
-	b := *bp
-	n := len(b)
-	for n+utf8.UTFMax > cap(b) {
-		b = append(b, 0)
-	}
-	w := utf8.EncodeRune(b[n:n+utf8.UTFMax], r)
-	*bp = b[:n+w]
-}
-
-// pp is used to store a printer's state and is reused with sync.Pool to avoid allocations.
-type pp struct {
-	buf buffer
-
+	// retain arguments across calls.
+	args []interface{}
+	// retain current argument number across calls
+	argNum int
 	// arg holds the current item, as an interface{}.
 	arg interface{}
-
 	// value is used instead of arg for reflect values.
 	value reflect.Value
 
 	// fmt is used to format basic items such as integers or strings.
-	fmt fmt
+	fmt formatInfo
 
 	// reordered records whether the format string used argument reordering.
 	reordered bool
@@ -125,32 +68,23 @@
 	erroring bool
 }
 
-var ppFree = sync.Pool{
-	New: func() interface{} { return new(pp) },
-}
-
-// newPrinter allocates a new pp struct or grabs a cached one.
-func newPrinter() *pp {
-	p := ppFree.Get().(*pp)
+func (p *printer) reset() {
+	p.Buffer.Reset()
+	p.argNum = 0
+	p.reordered = false
 	p.panicking = false
 	p.erroring = false
-	p.fmt.init(&p.buf)
-	return p
+	p.fmt.init(&p.Buffer)
 }
 
-// free saves used pp structs in ppFree; avoids an allocation per invocation.
-func (p *pp) free() {
-	p.buf = p.buf[:0]
-	p.arg = nil
-	p.value = reflect.Value{}
-	ppFree.Put(p)
-}
+// Language implements "golang.org/x/text/internal/format".State.
+func (p *printer) Language() language.Tag { return p.tag }
 
-func (p *pp) Width() (wid int, ok bool) { return p.fmt.wid, p.fmt.widPresent }
+func (p *printer) Width() (wid int, ok bool) { return p.fmt.wid, p.fmt.widPresent }
 
-func (p *pp) Precision() (prec int, ok bool) { return p.fmt.prec, p.fmt.precPresent }
+func (p *printer) Precision() (prec int, ok bool) { return p.fmt.prec, p.fmt.precPresent }
 
-func (p *pp) Flag(b int) bool {
+func (p *printer) Flag(b int) bool {
 	switch b {
 	case '-':
 		return p.fmt.minus
@@ -166,108 +100,6 @@
 	return false
 }
 
-// Implement Write so we can call Fprintf on a pp (through State), for
-// recursive use in custom verbs.
-func (p *pp) Write(b []byte) (ret int, err error) {
-	p.buf.Write(b)
-	return len(b), nil
-}
-
-// These routines end in 'f' and take a format string.
-
-// Fprintf formats according to a format specifier and writes to w.
-// It returns the number of bytes written and any write error encountered.
-func Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error) {
-	p := newPrinter()
-	p.doPrintf(format, a)
-	n, err = w.Write(p.buf)
-	p.free()
-	return
-}
-
-// Printf formats according to a format specifier and writes to standard output.
-// It returns the number of bytes written and any write error encountered.
-func Printf(format string, a ...interface{}) (n int, err error) {
-	return Fprintf(os.Stdout, format, a...)
-}
-
-// Sprintf formats according to a format specifier and returns the resulting string.
-func Sprintf(format string, a ...interface{}) string {
-	p := newPrinter()
-	p.doPrintf(format, a)
-	s := string(p.buf)
-	p.free()
-	return s
-}
-
-// 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...))
-}
-
-// These routines do not take a format string
-
-// Fprint formats using the default formats for its operands and writes to w.
-// Spaces are added between operands when neither is a string.
-// It returns the number of bytes written and any write error encountered.
-func Fprint(w io.Writer, a ...interface{}) (n int, err error) {
-	p := newPrinter()
-	p.doPrint(a)
-	n, err = w.Write(p.buf)
-	p.free()
-	return
-}
-
-// Print formats using the default formats for its operands and writes to standard output.
-// Spaces are added between operands when neither is a string.
-// It returns the number of bytes written and any write error encountered.
-func Print(a ...interface{}) (n int, err error) {
-	return Fprint(os.Stdout, a...)
-}
-
-// Sprint formats using the default formats for its operands and returns the resulting string.
-// Spaces are added between operands when neither is a string.
-func Sprint(a ...interface{}) string {
-	p := newPrinter()
-	p.doPrint(a)
-	s := string(p.buf)
-	p.free()
-	return s
-}
-
-// These routines end in 'ln', do not take a format string,
-// always add spaces between operands, and add a newline
-// after the last operand.
-
-// Fprintln formats using the default formats for its operands and writes to w.
-// Spaces are always added between operands and a newline is appended.
-// It returns the number of bytes written and any write error encountered.
-func Fprintln(w io.Writer, a ...interface{}) (n int, err error) {
-	p := newPrinter()
-	p.doPrintln(a)
-	n, err = w.Write(p.buf)
-	p.free()
-	return
-}
-
-// Println formats using the default formats for its operands and writes to standard output.
-// Spaces are always added between operands and a newline is appended.
-// It returns the number of bytes written and any write error encountered.
-func Println(a ...interface{}) (n int, err error) {
-	return Fprintln(os.Stdout, a...)
-}
-
-// Sprintln formats using the default formats for its operands and returns the resulting string.
-// Spaces are always added between operands and a newline is appended.
-func Sprintln(a ...interface{}) string {
-	p := newPrinter()
-	p.doPrintln(a)
-	s := string(p.buf)
-	p.free()
-	return s
-}
-
 // getField gets the i'th field of the struct value.
 // If the field is itself is an interface, return a value for
 // the thing inside the interface, not the interface itself.
@@ -301,38 +133,38 @@
 	return
 }
 
-func (p *pp) unknownType(v reflect.Value) {
+func (p *printer) unknownType(v reflect.Value) {
 	if !v.IsValid() {
-		p.buf.WriteString(nilAngleString)
+		p.WriteString(nilAngleString)
 		return
 	}
-	p.buf.WriteByte('?')
-	p.buf.WriteString(v.Type().String())
-	p.buf.WriteByte('?')
+	p.WriteByte('?')
+	p.WriteString(v.Type().String())
+	p.WriteByte('?')
 }
 
-func (p *pp) badVerb(verb rune) {
+func (p *printer) badVerb(verb rune) {
 	p.erroring = true
-	p.buf.WriteString(percentBangString)
-	p.buf.WriteRune(verb)
-	p.buf.WriteByte('(')
+	p.WriteString(percentBangString)
+	p.WriteRune(verb)
+	p.WriteByte('(')
 	switch {
 	case p.arg != nil:
-		p.buf.WriteString(reflect.TypeOf(p.arg).String())
-		p.buf.WriteByte('=')
+		p.WriteString(reflect.TypeOf(p.arg).String())
+		p.WriteByte('=')
 		p.printArg(p.arg, 'v')
 	case p.value.IsValid():
-		p.buf.WriteString(p.value.Type().String())
-		p.buf.WriteByte('=')
+		p.WriteString(p.value.Type().String())
+		p.WriteByte('=')
 		p.printValue(p.value, 'v', 0)
 	default:
-		p.buf.WriteString(nilAngleString)
+		p.WriteString(nilAngleString)
 	}
-	p.buf.WriteByte(')')
+	p.WriteByte(')')
 	p.erroring = false
 }
 
-func (p *pp) fmtBool(v bool, verb rune) {
+func (p *printer) fmtBool(v bool, verb rune) {
 	switch verb {
 	case 't', 'v':
 		p.fmt.fmt_boolean(v)
@@ -343,7 +175,7 @@
 
 // fmt0x64 formats a uint64 in hexadecimal and prefixes it with 0x or
 // not, as requested, by temporarily setting the sharp flag.
-func (p *pp) fmt0x64(v uint64, leading0x bool) {
+func (p *printer) fmt0x64(v uint64, leading0x bool) {
 	sharp := p.fmt.sharp
 	p.fmt.sharp = leading0x
 	p.fmt.fmt_integer(v, 16, unsigned, ldigits)
@@ -351,7 +183,7 @@
 }
 
 // fmtInteger formats a signed or unsigned integer.
-func (p *pp) fmtInteger(v uint64, isSigned bool, verb rune) {
+func (p *printer) fmtInteger(v uint64, isSigned bool, verb rune) {
 	switch verb {
 	case 'v':
 		if p.fmt.sharpV && !isSigned {
@@ -386,7 +218,7 @@
 
 // fmtFloat formats a float. The default precision for each verb
 // is specified as last argument in the call to fmt_float.
-func (p *pp) fmtFloat(v float64, size int, verb rune) {
+func (p *printer) fmtFloat(v float64, size int, verb rune) {
 	switch verb {
 	case 'v':
 		p.fmt.fmt_float(v, size, 'g', -1)
@@ -404,25 +236,25 @@
 // fmtComplex formats a complex number v with
 // r = real(v) and j = imag(v) as (r+ji) using
 // fmtFloat for r and j formatting.
-func (p *pp) fmtComplex(v complex128, size int, verb rune) {
+func (p *printer) fmtComplex(v complex128, size int, verb rune) {
 	// Make sure any unsupported verbs are found before the
 	// calls to fmtFloat to not generate an incorrect error string.
 	switch verb {
 	case 'v', 'b', 'g', 'G', 'f', 'F', 'e', 'E':
 		oldPlus := p.fmt.plus
-		p.buf.WriteByte('(')
+		p.WriteByte('(')
 		p.fmtFloat(real(v), size/2, verb)
 		// Imaginary part always has a sign.
 		p.fmt.plus = true
 		p.fmtFloat(imag(v), size/2, verb)
-		p.buf.WriteString("i)")
+		p.WriteString("i)")
 		p.fmt.plus = oldPlus
 	default:
 		p.badVerb(verb)
 	}
 }
 
-func (p *pp) fmtString(v string, verb rune) {
+func (p *printer) fmtString(v string, verb rune) {
 	switch verb {
 	case 'v':
 		if p.fmt.sharpV {
@@ -443,32 +275,32 @@
 	}
 }
 
-func (p *pp) fmtBytes(v []byte, verb rune, typeString string) {
+func (p *printer) fmtBytes(v []byte, verb rune, typeString string) {
 	switch verb {
 	case 'v', 'd':
 		if p.fmt.sharpV {
-			p.buf.WriteString(typeString)
+			p.WriteString(typeString)
 			if v == nil {
-				p.buf.WriteString(nilParenString)
+				p.WriteString(nilParenString)
 				return
 			}
-			p.buf.WriteByte('{')
+			p.WriteByte('{')
 			for i, c := range v {
 				if i > 0 {
-					p.buf.WriteString(commaSpaceString)
+					p.WriteString(commaSpaceString)
 				}
 				p.fmt0x64(uint64(c), true)
 			}
-			p.buf.WriteByte('}')
+			p.WriteByte('}')
 		} else {
-			p.buf.WriteByte('[')
+			p.WriteByte('[')
 			for i, c := range v {
 				if i > 0 {
-					p.buf.WriteByte(' ')
+					p.WriteByte(' ')
 				}
 				p.fmt.fmt_integer(uint64(c), 10, unsigned, ldigits)
 			}
-			p.buf.WriteByte(']')
+			p.WriteByte(']')
 		}
 	case 's':
 		p.fmt.fmt_s(string(v))
@@ -483,7 +315,7 @@
 	}
 }
 
-func (p *pp) fmtPointer(value reflect.Value, verb rune) {
+func (p *printer) fmtPointer(value reflect.Value, verb rune) {
 	var u uintptr
 	switch value.Kind() {
 	case reflect.Chan, reflect.Func, reflect.Map, reflect.Ptr, reflect.Slice, reflect.UnsafePointer:
@@ -496,15 +328,15 @@
 	switch verb {
 	case 'v':
 		if p.fmt.sharpV {
-			p.buf.WriteByte('(')
-			p.buf.WriteString(value.Type().String())
-			p.buf.WriteString(")(")
+			p.WriteByte('(')
+			p.WriteString(value.Type().String())
+			p.WriteString(")(")
 			if u == 0 {
-				p.buf.WriteString(nilString)
+				p.WriteString(nilString)
 			} else {
 				p.fmt0x64(uint64(u), true)
 			}
-			p.buf.WriteByte(')')
+			p.WriteByte(')')
 		} else {
 			if u == 0 {
 				p.fmt.padString(nilAngleString)
@@ -521,13 +353,13 @@
 	}
 }
 
-func (p *pp) catchPanic(arg interface{}, verb rune) {
+func (p *printer) catchPanic(arg interface{}, verb rune) {
 	if err := recover(); err != nil {
 		// If it's a nil pointer, just say "<nil>". The likeliest causes are a
 		// Stringer that fails to guard against nil or a nil pointer for a
 		// value receiver, and in either case, "<nil>" is a nice result.
 		if v := reflect.ValueOf(arg); v.Kind() == reflect.Ptr && v.IsNil() {
-			p.buf.WriteString(nilAngleString)
+			p.WriteString(nilAngleString)
 			return
 		}
 		// Otherwise print a concise panic message. Most of the time the panic
@@ -541,24 +373,24 @@
 		// For this output we want default behavior.
 		p.fmt.clearflags()
 
-		p.buf.WriteString(percentBangString)
-		p.buf.WriteRune(verb)
-		p.buf.WriteString(panicString)
+		p.WriteString(percentBangString)
+		p.WriteRune(verb)
+		p.WriteString(panicString)
 		p.panicking = true
 		p.printArg(err, 'v')
 		p.panicking = false
-		p.buf.WriteByte(')')
+		p.WriteByte(')')
 
 		p.fmt.fmtFlags = oldFlags
 	}
 }
 
-func (p *pp) handleMethods(verb rune) (handled bool) {
+func (p *printer) handleMethods(verb rune) (handled bool) {
 	if p.erroring {
 		return
 	}
 	// Is it a Formatter?
-	if formatter, ok := p.arg.(Formatter); ok {
+	if formatter, ok := p.arg.(fmt.Formatter); ok {
 		handled = true
 		defer p.catchPanic(p.arg, verb)
 		formatter.Format(p, verb)
@@ -567,7 +399,7 @@
 
 	// If we're doing Go syntax and the argument knows how to supply it, take care of it now.
 	if p.fmt.sharpV {
-		if stringer, ok := p.arg.(GoStringer); ok {
+		if stringer, ok := p.arg.(fmt.GoStringer); ok {
 			handled = true
 			defer p.catchPanic(p.arg, verb)
 			// Print the result of GoString unadorned.
@@ -591,7 +423,7 @@
 				p.fmtString(v.Error(), verb)
 				return
 
-			case Stringer:
+			case fmt.Stringer:
 				handled = true
 				defer p.catchPanic(p.arg, verb)
 				p.fmtString(v.String(), verb)
@@ -602,7 +434,7 @@
 	return false
 }
 
-func (p *pp) printArg(arg interface{}, verb rune) {
+func (p *printer) printArg(arg interface{}, verb rune) {
 	p.arg = arg
 	p.value = reflect.Value{}
 
@@ -687,7 +519,7 @@
 
 // printValue is similar to printArg but starts with a reflect value, not an interface{} value.
 // It does not handle 'p' and 'T' verbs because these should have been already handled by printArg.
-func (p *pp) printValue(value reflect.Value, verb rune, depth int) {
+func (p *printer) printValue(value reflect.Value, verb rune, depth int) {
 	// Handle values with special methods if not already handled by printArg (depth == 0).
 	if depth > 0 && value.IsValid() && value.CanInterface() {
 		p.arg = value.Interface()
@@ -701,11 +533,11 @@
 	switch f := value; value.Kind() {
 	case reflect.Invalid:
 		if depth == 0 {
-			p.buf.WriteString(invReflectString)
+			p.WriteString(invReflectString)
 		} else {
 			switch verb {
 			case 'v':
-				p.buf.WriteString(nilAngleString)
+				p.WriteString(nilAngleString)
 			default:
 				p.badVerb(verb)
 			}
@@ -728,63 +560,63 @@
 		p.fmtString(f.String(), verb)
 	case reflect.Map:
 		if p.fmt.sharpV {
-			p.buf.WriteString(f.Type().String())
+			p.WriteString(f.Type().String())
 			if f.IsNil() {
-				p.buf.WriteString(nilParenString)
+				p.WriteString(nilParenString)
 				return
 			}
-			p.buf.WriteByte('{')
+			p.WriteByte('{')
 		} else {
-			p.buf.WriteString(mapString)
+			p.WriteString(mapString)
 		}
 		keys := f.MapKeys()
 		for i, key := range keys {
 			if i > 0 {
 				if p.fmt.sharpV {
-					p.buf.WriteString(commaSpaceString)
+					p.WriteString(commaSpaceString)
 				} else {
-					p.buf.WriteByte(' ')
+					p.WriteByte(' ')
 				}
 			}
 			p.printValue(key, verb, depth+1)
-			p.buf.WriteByte(':')
+			p.WriteByte(':')
 			p.printValue(f.MapIndex(key), verb, depth+1)
 		}
 		if p.fmt.sharpV {
-			p.buf.WriteByte('}')
+			p.WriteByte('}')
 		} else {
-			p.buf.WriteByte(']')
+			p.WriteByte(']')
 		}
 	case reflect.Struct:
 		if p.fmt.sharpV {
-			p.buf.WriteString(f.Type().String())
+			p.WriteString(f.Type().String())
 		}
-		p.buf.WriteByte('{')
+		p.WriteByte('{')
 		for i := 0; i < f.NumField(); i++ {
 			if i > 0 {
 				if p.fmt.sharpV {
-					p.buf.WriteString(commaSpaceString)
+					p.WriteString(commaSpaceString)
 				} else {
-					p.buf.WriteByte(' ')
+					p.WriteByte(' ')
 				}
 			}
 			if p.fmt.plusV || p.fmt.sharpV {
 				if name := f.Type().Field(i).Name; name != "" {
-					p.buf.WriteString(name)
-					p.buf.WriteByte(':')
+					p.WriteString(name)
+					p.WriteByte(':')
 				}
 			}
 			p.printValue(getField(f, i), verb, depth+1)
 		}
-		p.buf.WriteByte('}')
+		p.WriteByte('}')
 	case reflect.Interface:
 		value := f.Elem()
 		if !value.IsValid() {
 			if p.fmt.sharpV {
-				p.buf.WriteString(f.Type().String())
-				p.buf.WriteString(nilParenString)
+				p.WriteString(f.Type().String())
+				p.WriteString(nilParenString)
 			} else {
-				p.buf.WriteString(nilAngleString)
+				p.WriteString(nilAngleString)
 			}
 		} else {
 			p.printValue(value, verb, depth+1)
@@ -814,28 +646,28 @@
 			}
 		}
 		if p.fmt.sharpV {
-			p.buf.WriteString(f.Type().String())
+			p.WriteString(f.Type().String())
 			if f.Kind() == reflect.Slice && f.IsNil() {
-				p.buf.WriteString(nilParenString)
+				p.WriteString(nilParenString)
 				return
 			}
-			p.buf.WriteByte('{')
+			p.WriteByte('{')
 			for i := 0; i < f.Len(); i++ {
 				if i > 0 {
-					p.buf.WriteString(commaSpaceString)
+					p.WriteString(commaSpaceString)
 				}
 				p.printValue(f.Index(i), verb, depth+1)
 			}
-			p.buf.WriteByte('}')
+			p.WriteByte('}')
 		} else {
-			p.buf.WriteByte('[')
+			p.WriteByte('[')
 			for i := 0; i < f.Len(); i++ {
 				if i > 0 {
-					p.buf.WriteByte(' ')
+					p.WriteByte(' ')
 				}
 				p.printValue(f.Index(i), verb, depth+1)
 			}
-			p.buf.WriteByte(']')
+			p.WriteByte(']')
 		}
 	case reflect.Ptr:
 		// pointer to array or slice or struct?  ok at top level
@@ -843,7 +675,7 @@
 		if depth == 0 && f.Pointer() != 0 {
 			switch a := f.Elem(); a.Kind() {
 			case reflect.Array, reflect.Slice, reflect.Struct, reflect.Map:
-				p.buf.WriteByte('&')
+				p.WriteByte('&')
 				p.printValue(a, verb, depth+1)
 				return
 			}
@@ -857,13 +689,13 @@
 }
 
 // intFromArg gets the argNumth element of a. On return, isInt reports whether the argument has integer type.
-func intFromArg(a []interface{}, argNum int) (num int, isInt bool, newArgNum int) {
-	newArgNum = argNum
-	if argNum < len(a) {
-		num, isInt = a[argNum].(int) // Almost always OK.
+func (p *printer) intFromArg() (num int, isInt bool) {
+	if p.argNum < len(p.args) {
+		arg := p.args[p.argNum]
+		num, isInt = arg.(int) // Almost always OK.
 		if !isInt {
 			// Work harder.
-			switch v := reflect.ValueOf(a[argNum]); v.Kind() {
+			switch v := reflect.ValueOf(arg); v.Kind() {
 			case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
 				n := v.Int()
 				if int64(int(n)) == n {
@@ -880,7 +712,7 @@
 				// Already 0, false.
 			}
 		}
-		newArgNum = argNum + 1
+		p.argNum++
 		if tooLarge(num) {
 			num = 0
 			isInt = false
@@ -914,39 +746,38 @@
 	return 0, 1, false
 }
 
-// argNumber returns the next argument to evaluate, which is either the value of the passed-in
+// updateArgNumber returns the next argument to evaluate, which is either the value of the passed-in
 // argNum or the value of the bracketed integer that begins format[i:]. It also returns
 // the new value of i, that is, the index of the next byte of the format to process.
-func (p *pp) argNumber(argNum int, format string, i int, numArgs int) (newArgNum, newi int, found bool) {
+func (p *printer) updateArgNumber(format string, i int) (newi int, found bool) {
 	if len(format) <= i || format[i] != '[' {
-		return argNum, i, false
+		return i, false
 	}
 	p.reordered = true
 	index, wid, ok := parseArgNumber(format[i:])
-	if ok && 0 <= index && index < numArgs {
-		return index, i + wid, true
+	if ok && 0 <= index && index < len(p.args) {
+		p.argNum = index
+		return i + wid, true
 	}
 	p.goodArgNum = false
-	return argNum, i + wid, ok
+	return i + wid, ok
 }
 
-func (p *pp) badArgNum(verb rune) {
-	p.buf.WriteString(percentBangString)
-	p.buf.WriteRune(verb)
-	p.buf.WriteString(badIndexString)
+func (p *printer) badArgNum(verb rune) {
+	p.WriteString(percentBangString)
+	p.WriteRune(verb)
+	p.WriteString(badIndexString)
 }
 
-func (p *pp) missingArg(verb rune) {
-	p.buf.WriteString(percentBangString)
-	p.buf.WriteRune(verb)
-	p.buf.WriteString(missingString)
+func (p *printer) missingArg(verb rune) {
+	p.WriteString(percentBangString)
+	p.WriteRune(verb)
+	p.WriteString(missingString)
 }
 
-func (p *pp) doPrintf(format string, a []interface{}) {
+func (p *printer) doPrintf(format string) {
 	end := len(format)
-	argNum := 0         // we process one argument per non-trivial format
 	afterIndex := false // previous item in format was an index like [3].
-	p.reordered = false
 formatLoop:
 	for i := 0; i < end; {
 		p.goodArgNum = true
@@ -955,7 +786,7 @@
 			i++
 		}
 		if i > lasti {
-			p.buf.WriteString(format[lasti:i])
+			p.WriteString(format[lasti:i])
 		}
 		if i >= end {
 			// done processing format string
@@ -985,7 +816,7 @@
 			default:
 				// Fast path for common case of ascii lower case simple verbs
 				// without precision or width or argument indices.
-				if 'a' <= c && c <= 'z' && argNum < len(a) {
+				if 'a' <= c && c <= 'z' && p.argNum < len(p.args) {
 					if c == 'v' {
 						// Go syntax
 						p.fmt.sharpV = p.fmt.sharp
@@ -994,8 +825,8 @@
 						p.fmt.plusV = p.fmt.plus
 						p.fmt.plus = false
 					}
-					p.printArg(a[argNum], rune(c))
-					argNum++
+					p.printArg(p.Arg(p.argNum), rune(c))
+					p.argNum++
 					i++
 					continue formatLoop
 				}
@@ -1005,15 +836,15 @@
 		}
 
 		// Do we have an explicit argument index?
-		argNum, i, afterIndex = p.argNumber(argNum, format, i, len(a))
+		i, afterIndex = p.updateArgNumber(format, i)
 
 		// Do we have width?
 		if i < end && format[i] == '*' {
 			i++
-			p.fmt.wid, p.fmt.widPresent, argNum = intFromArg(a, argNum)
+			p.fmt.wid, p.fmt.widPresent = p.intFromArg()
 
 			if !p.fmt.widPresent {
-				p.buf.WriteString(badWidthString)
+				p.WriteString(badWidthString)
 			}
 
 			// We have a negative width, so take its value and ensure
@@ -1037,17 +868,17 @@
 			if afterIndex { // "%[3].2d"
 				p.goodArgNum = false
 			}
-			argNum, i, afterIndex = p.argNumber(argNum, format, i, len(a))
+			i, afterIndex = p.updateArgNumber(format, i)
 			if i < end && format[i] == '*' {
 				i++
-				p.fmt.prec, p.fmt.precPresent, argNum = intFromArg(a, argNum)
+				p.fmt.prec, p.fmt.precPresent = p.intFromArg()
 				// 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.WriteString(badPrecString)
+					p.WriteString(badPrecString)
 				}
 				afterIndex = false
 			} else {
@@ -1060,11 +891,11 @@
 		}
 
 		if !afterIndex {
-			argNum, i, afterIndex = p.argNumber(argNum, format, i, len(a))
+			i, afterIndex = p.updateArgNumber(format, i)
 		}
 
 		if i >= end {
-			p.buf.WriteString(noVerbString)
+			p.WriteString(noVerbString)
 			break
 		}
 
@@ -1073,10 +904,10 @@
 
 		switch {
 		case verb == '%': // Percent does not absorb operands and ignores f.wid and f.prec.
-			p.buf.WriteByte('%')
+			p.WriteByte('%')
 		case !p.goodArgNum:
 			p.badArgNum(verb)
-		case argNum >= len(a): // No argument left over to print for the current verb.
+		case p.argNum >= len(p.args): // No argument left over to print for the current verb.
 			p.missingArg(verb)
 		case verb == 'v':
 			// Go syntax
@@ -1087,40 +918,41 @@
 			p.fmt.plus = false
 			fallthrough
 		default:
-			p.printArg(a[argNum], verb)
-			argNum++
+			p.printArg(p.args[p.argNum], verb)
+			p.argNum++
 		}
 	}
 
-	// Check for extra arguments unless the call accessed the arguments
-	// out of order, in which case it's too expensive to detect if they've all
-	// been used and arguably OK if they're not.
-	if !p.reordered && argNum < len(a) {
+	// Check for extra arguments, but only if there was at least one ordered
+	// argument. Note that this behavior is necessarily different from fmt:
+	// different variants of messages may opt to drop some or all of the
+	// arguments.
+	if !p.reordered && p.argNum < len(p.args) && p.argNum != 0 {
 		p.fmt.clearflags()
-		p.buf.WriteString(extraString)
-		for i, arg := range a[argNum:] {
+		p.WriteString(extraString)
+		for i, arg := range p.args[p.argNum:] {
 			if i > 0 {
-				p.buf.WriteString(commaSpaceString)
+				p.WriteString(commaSpaceString)
 			}
 			if arg == nil {
-				p.buf.WriteString(nilAngleString)
+				p.WriteString(nilAngleString)
 			} else {
-				p.buf.WriteString(reflect.TypeOf(arg).String())
-				p.buf.WriteByte('=')
+				p.WriteString(reflect.TypeOf(arg).String())
+				p.WriteByte('=')
 				p.printArg(arg, 'v')
 			}
 		}
-		p.buf.WriteByte(')')
+		p.WriteByte(')')
 	}
 }
 
-func (p *pp) doPrint(a []interface{}) {
+func (p *printer) doPrint(a []interface{}) {
 	prevString := false
 	for argNum, arg := range a {
 		isString := arg != nil && reflect.TypeOf(arg).Kind() == reflect.String
 		// Add a space between two non-string arguments.
 		if argNum > 0 && !isString && !prevString {
-			p.buf.WriteByte(' ')
+			p.WriteByte(' ')
 		}
 		p.printArg(arg, 'v')
 		prevString = isString
@@ -1129,12 +961,12 @@
 
 // doPrintln is like doPrint but always adds a space between arguments
 // and a newline after the last argument.
-func (p *pp) doPrintln(a []interface{}) {
+func (p *printer) doPrintln(a []interface{}) {
 	for argNum, arg := range a {
 		if argNum > 0 {
-			p.buf.WriteByte(' ')
+			p.WriteByte(' ')
 		}
 		p.printArg(arg, 'v')
 	}
-	p.buf.WriteByte('\n')
+	p.WriteByte('\n')
 }