diff options
| author | Ondřej Surý <ondrej@sury.org> | 2011-06-28 15:28:34 +0200 |
|---|---|---|
| committer | Ondřej Surý <ondrej@sury.org> | 2011-06-28 15:28:34 +0200 |
| commit | 8d00b02d82d86abe51773dc2c1751843bb538ae5 (patch) | |
| tree | 6656d166a046fc751548e88f071fedbeb9355443 /src/pkg/fmt/print.go | |
| parent | c29cace1e8f3260389ea78fa4ef86d80cd5e5275 (diff) | |
| download | golang-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.go | 46 |
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 } |
