summaryrefslogtreecommitdiff
path: root/libgo/go/fmt/print.go
diff options
context:
space:
mode:
Diffstat (limited to 'libgo/go/fmt/print.go')
-rw-r--r--libgo/go/fmt/print.go103
1 files changed, 76 insertions, 27 deletions
diff --git a/libgo/go/fmt/print.go b/libgo/go/fmt/print.go
index 10e0fe7c85b..73873490807 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 {