summaryrefslogtreecommitdiff
path: root/src/pkg/fmt/print.go
diff options
context:
space:
mode:
authorOndřej Surý <ondrej@sury.org>2011-06-28 15:28:34 +0200
committerOndřej Surý <ondrej@sury.org>2011-06-28 15:28:34 +0200
commit8d00b02d82d86abe51773dc2c1751843bb538ae5 (patch)
tree6656d166a046fc751548e88f071fedbeb9355443 /src/pkg/fmt/print.go
parentc29cace1e8f3260389ea78fa4ef86d80cd5e5275 (diff)
downloadgolang-8d00b02d82d86abe51773dc2c1751843bb538ae5.tar.gz
Imported Upstream version 2011.06.23upstream-weekly/2011.06.23
Diffstat (limited to 'src/pkg/fmt/print.go')
-rw-r--r--src/pkg/fmt/print.go46
1 files changed, 41 insertions, 5 deletions
diff --git a/src/pkg/fmt/print.go b/src/pkg/fmt/print.go
index c18a8ea38..438e0ae26 100644
--- a/src/pkg/fmt/print.go
+++ b/src/pkg/fmt/print.go
@@ -22,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{")
@@ -69,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.
@@ -111,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
}
@@ -186,7 +189,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
@@ -363,6 +366,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.
@@ -370,10 +375,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{}) {
@@ -561,6 +569,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' {
@@ -583,6 +616,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
@@ -595,6 +629,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
@@ -602,6 +637,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
}