2008-10-24 17:33:29 -06:00
|
|
|
// Copyright 2009 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
|
|
|
|
|
|
|
|
import (
|
2009-12-15 16:27:16 -07:00
|
|
|
"bytes"
|
2011-11-01 20:04:37 -06:00
|
|
|
"errors"
|
2009-12-15 16:27:16 -07:00
|
|
|
"io"
|
|
|
|
"os"
|
|
|
|
"reflect"
|
2011-09-29 12:23:06 -06:00
|
|
|
"sync"
|
2011-05-25 05:25:15 -06:00
|
|
|
"unicode"
|
2011-11-08 16:40:58 -07:00
|
|
|
"unicode/utf8"
|
2008-10-24 17:33:29 -06:00
|
|
|
)
|
|
|
|
|
2009-12-06 13:03:52 -07:00
|
|
|
// Some constants in the form of bytes, to avoid string overhead.
|
|
|
|
// Needlessly fastidious, I suppose.
|
|
|
|
var (
|
2010-02-25 17:43:43 -07:00
|
|
|
commaSpaceBytes = []byte(", ")
|
|
|
|
nilAngleBytes = []byte("<nil>")
|
|
|
|
nilParenBytes = []byte("(nil)")
|
|
|
|
nilBytes = []byte("nil")
|
|
|
|
mapBytes = []byte("map[")
|
2010-09-23 19:53:26 -06:00
|
|
|
missingBytes = []byte("(MISSING)")
|
fmt: catch panics from calls to String etc.
This change causes Print et al. to catch panics generated by
calls to String, GoString, and Format. The panic is formatted
into the output stream as an error, but the program continues.
As a special case, if the argument was a nil pointer, the
result is just "<nil>", because that's almost certainly enough
information and handles the very common case of String
methods that don't guard against nil.
Scan does not want this change. Input must work; output can
be for debugging and it's nice to get output even when you
make a mistake.
R=dsymonds, r, adg, gri, rsc, gri
CC=golang-dev
https://golang.org/cl/4640043
2011-06-20 16:31:02 -06:00
|
|
|
panicBytes = []byte("(PANIC=")
|
2010-09-23 19:53:26 -06:00
|
|
|
extraBytes = []byte("%!(EXTRA ")
|
2010-03-05 21:16:04 -07:00
|
|
|
irparenBytes = []byte("i)")
|
2010-06-14 18:16:35 -06:00
|
|
|
bytesBytes = []byte("[]byte{")
|
2010-09-23 19:53:26 -06:00
|
|
|
widthBytes = []byte("%!(BADWIDTH)")
|
|
|
|
precBytes = []byte("%!(BADPREC)")
|
2011-01-05 11:11:34 -07:00
|
|
|
noVerbBytes = []byte("%!(NOVERB)")
|
2009-12-06 13:03:52 -07:00
|
|
|
)
|
|
|
|
|
2009-06-23 16:20:30 -06:00
|
|
|
// State represents the printer state passed to custom formatters.
|
2009-05-08 12:22:57 -06:00
|
|
|
// It provides access to the io.Writer interface plus information about
|
2009-03-06 04:35:38 -07:00
|
|
|
// the flags and options for the operand's format specifier.
|
2009-06-23 16:20:30 -06:00
|
|
|
type State interface {
|
2009-03-06 04:35:38 -07:00
|
|
|
// Write is the function to call to emit formatted output to be printed.
|
2011-11-01 20:04:37 -06:00
|
|
|
Write(b []byte) (ret int, err error)
|
2009-03-06 04:35:38 -07:00
|
|
|
// Width returns the value of the width option and whether it has been set.
|
2009-12-15 16:27:16 -07:00
|
|
|
Width() (wid int, ok bool)
|
2009-03-06 04:35:38 -07:00
|
|
|
// Precision returns the value of the precision option and whether it has been set.
|
2009-12-15 16:27:16 -07:00
|
|
|
Precision() (prec int, ok bool)
|
2008-12-11 17:53:33 -07:00
|
|
|
|
2009-03-06 04:35:38 -07:00
|
|
|
// Flag returns whether the flag c, a character, has been set.
|
2011-05-18 12:34:19 -06:00
|
|
|
Flag(c int) bool
|
2008-11-06 11:40:57 -07:00
|
|
|
}
|
|
|
|
|
2009-08-31 17:38:30 -06:00
|
|
|
// Formatter is the interface implemented by values with a custom formatter.
|
2009-03-06 04:35:38 -07:00
|
|
|
// The implementation of Format may call Sprintf or Fprintf(f) etc.
|
|
|
|
// to generate its output.
|
2009-06-23 16:20:30 -06:00
|
|
|
type Formatter interface {
|
2011-10-25 23:21:33 -06:00
|
|
|
Format(f State, c rune)
|
2008-11-06 12:38:44 -07:00
|
|
|
}
|
|
|
|
|
2011-07-17 19:44:27 -06:00
|
|
|
// Stringer is implemented by any value that has a String method,
|
2009-08-31 17:38:30 -06:00
|
|
|
// 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.
|
2009-05-08 12:22:57 -06:00
|
|
|
type Stringer interface {
|
2009-12-15 16:27:16 -07:00
|
|
|
String() string
|
2008-11-06 11:40:57 -07:00
|
|
|
}
|
|
|
|
|
2011-07-17 19:44:27 -06:00
|
|
|
// GoStringer is implemented by any value that has a GoString method,
|
2009-08-31 17:38:30 -06:00
|
|
|
// 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 {
|
2009-12-15 16:27:16 -07:00
|
|
|
GoString() string
|
2009-08-31 17:38:30 -06:00
|
|
|
}
|
|
|
|
|
2009-01-15 16:40:27 -07:00
|
|
|
type pp struct {
|
fmt: catch panics from calls to String etc.
This change causes Print et al. to catch panics generated by
calls to String, GoString, and Format. The panic is formatted
into the output stream as an error, but the program continues.
As a special case, if the argument was a nil pointer, the
result is just "<nil>", because that's almost certainly enough
information and handles the very common case of String
methods that don't guard against nil.
Scan does not want this change. Input must work; output can
be for debugging and it's nice to get output even when you
make a mistake.
R=dsymonds, r, adg, gri, rsc, gri
CC=golang-dev
https://golang.org/cl/4640043
2011-06-20 16:31:02 -06:00
|
|
|
n int
|
|
|
|
panicking bool
|
|
|
|
buf bytes.Buffer
|
2011-10-21 14:59:27 -06:00
|
|
|
// field holds the current item, as an interface{}.
|
|
|
|
field interface{}
|
2011-10-18 17:23:07 -06:00
|
|
|
// value holds the current item, as a reflect.Value, and will be
|
|
|
|
// the zero Value if the item has not been reflected.
|
|
|
|
value reflect.Value
|
|
|
|
runeBuf [utf8.UTFMax]byte
|
|
|
|
fmt fmt
|
2008-10-24 17:33:29 -06:00
|
|
|
}
|
|
|
|
|
2011-01-31 16:36:28 -07:00
|
|
|
// A cache holds a set of reusable objects.
|
2011-09-29 12:23:06 -06:00
|
|
|
// The slice is a stack (LIFO).
|
2011-01-31 16:36:28 -07:00
|
|
|
// If more are needed, the cache creates them by calling new.
|
|
|
|
type cache struct {
|
2011-09-29 12:23:06 -06:00
|
|
|
mu sync.Mutex
|
|
|
|
saved []interface{}
|
2011-01-31 16:36:28 -07:00
|
|
|
new func() interface{}
|
|
|
|
}
|
2009-12-06 13:03:52 -07:00
|
|
|
|
2011-01-31 16:36:28 -07:00
|
|
|
func (c *cache) put(x interface{}) {
|
2011-09-29 12:23:06 -06:00
|
|
|
c.mu.Lock()
|
|
|
|
if len(c.saved) < cap(c.saved) {
|
|
|
|
c.saved = append(c.saved, x)
|
2011-01-31 16:36:28 -07:00
|
|
|
}
|
2011-09-29 12:23:06 -06:00
|
|
|
c.mu.Unlock()
|
2011-01-31 16:36:28 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
func (c *cache) get() interface{} {
|
2011-09-29 12:23:06 -06:00
|
|
|
c.mu.Lock()
|
|
|
|
n := len(c.saved)
|
|
|
|
if n == 0 {
|
|
|
|
c.mu.Unlock()
|
2011-01-31 16:36:28 -07:00
|
|
|
return c.new()
|
2009-12-06 13:03:52 -07:00
|
|
|
}
|
2011-09-29 12:23:06 -06:00
|
|
|
x := c.saved[n-1]
|
|
|
|
c.saved = c.saved[0 : n-1]
|
|
|
|
c.mu.Unlock()
|
|
|
|
return x
|
2011-01-31 16:36:28 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
func newCache(f func() interface{}) *cache {
|
2011-09-29 12:23:06 -06:00
|
|
|
return &cache{saved: make([]interface{}, 0, 100), new: f}
|
2011-01-31 16:36:28 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
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)
|
fmt: catch panics from calls to String etc.
This change causes Print et al. to catch panics generated by
calls to String, GoString, and Format. The panic is formatted
into the output stream as an error, but the program continues.
As a special case, if the argument was a nil pointer, the
result is just "<nil>", because that's almost certainly enough
information and handles the very common case of String
methods that don't guard against nil.
Scan does not want this change. Input must work; output can
be for debugging and it's nice to get output even when you
make a mistake.
R=dsymonds, r, adg, gri, rsc, gri
CC=golang-dev
https://golang.org/cl/4640043
2011-06-20 16:31:02 -06:00
|
|
|
p.panicking = false
|
2009-12-15 16:27:16 -07:00
|
|
|
p.fmt.init(&p.buf)
|
|
|
|
return p
|
2008-10-24 17:33:29 -06:00
|
|
|
}
|
|
|
|
|
2009-12-06 16:01:07 -07:00
|
|
|
// Save used pp structs in ppFree; avoids an allocation per invocation.
|
|
|
|
func (p *pp) free() {
|
|
|
|
// Don't hold on to pp structs with large buffers.
|
|
|
|
if cap(p.buf.Bytes()) > 1024 {
|
|
|
|
return
|
|
|
|
}
|
2009-12-15 16:27:16 -07:00
|
|
|
p.buf.Reset()
|
2011-10-21 14:59:27 -06:00
|
|
|
p.field = nil
|
2011-10-18 17:23:07 -06:00
|
|
|
p.value = reflect.Value{}
|
2011-01-31 16:36:28 -07:00
|
|
|
ppFree.put(p)
|
2009-12-06 16:01:07 -07:00
|
|
|
}
|
2009-12-06 13:03:52 -07:00
|
|
|
|
2009-12-15 16:27:16 -07:00
|
|
|
func (p *pp) Width() (wid int, ok bool) { return p.fmt.wid, p.fmt.widPresent }
|
2008-11-06 11:40:57 -07:00
|
|
|
|
2009-12-15 16:27:16 -07:00
|
|
|
func (p *pp) Precision() (prec int, ok bool) { return p.fmt.prec, p.fmt.precPresent }
|
2008-12-11 17:53:33 -07:00
|
|
|
|
2009-01-15 16:40:27 -07:00
|
|
|
func (p *pp) Flag(b int) bool {
|
2008-12-11 17:53:33 -07:00
|
|
|
switch b {
|
|
|
|
case '-':
|
2009-11-09 13:07:39 -07:00
|
|
|
return p.fmt.minus
|
2008-12-11 17:53:33 -07:00
|
|
|
case '+':
|
2009-11-09 13:07:39 -07:00
|
|
|
return p.fmt.plus
|
2008-12-11 17:53:33 -07:00
|
|
|
case '#':
|
2009-11-09 13:07:39 -07:00
|
|
|
return p.fmt.sharp
|
2008-12-11 17:53:33 -07:00
|
|
|
case ' ':
|
2009-11-09 13:07:39 -07:00
|
|
|
return p.fmt.space
|
2008-12-11 17:53:33 -07:00
|
|
|
case '0':
|
2009-11-09 13:07:39 -07:00
|
|
|
return p.fmt.zero
|
2008-12-11 17:53:33 -07:00
|
|
|
}
|
2009-12-15 16:27:16 -07:00
|
|
|
return false
|
2008-11-06 11:40:57 -07:00
|
|
|
}
|
|
|
|
|
2011-10-25 23:21:33 -06:00
|
|
|
func (p *pp) add(c rune) {
|
2011-01-05 12:42:35 -07:00
|
|
|
p.buf.WriteRune(c)
|
2008-10-24 17:33:29 -06:00
|
|
|
}
|
|
|
|
|
2009-12-06 13:03:52 -07:00
|
|
|
// Implement Write so we can call Fprintf on a pp (through State), for
|
2008-11-04 14:57:21 -07:00
|
|
|
// recursive use in custom verbs.
|
2011-11-01 20:04:37 -06:00
|
|
|
func (p *pp) Write(b []byte) (ret int, err error) {
|
2009-12-06 13:03:52 -07:00
|
|
|
return p.buf.Write(b)
|
2008-10-24 17:33:29 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
// These routines end in 'f' and take a format string.
|
|
|
|
|
2009-03-06 04:35:38 -07:00
|
|
|
// Fprintf formats according to a format specifier and writes to w.
|
2010-08-18 20:07:24 -06:00
|
|
|
// It returns the number of bytes written and any write error encountered.
|
2011-11-01 20:04:37 -06:00
|
|
|
func Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error) {
|
2009-12-15 16:27:16 -07:00
|
|
|
p := newPrinter()
|
2010-06-14 18:16:35 -06:00
|
|
|
p.doPrintf(format, a)
|
2011-06-28 12:00:31 -06:00
|
|
|
n64, err := p.buf.WriteTo(w)
|
2009-12-15 16:27:16 -07:00
|
|
|
p.free()
|
2011-06-28 12:00:31 -06:00
|
|
|
return int(n64), err
|
2008-10-24 17:33:29 -06:00
|
|
|
}
|
|
|
|
|
2009-03-06 04:35:38 -07:00
|
|
|
// Printf formats according to a format specifier and writes to standard output.
|
2010-08-18 20:07:24 -06:00
|
|
|
// It returns the number of bytes written and any write error encountered.
|
2011-11-01 20:04:37 -06:00
|
|
|
func Printf(format string, a ...interface{}) (n int, err error) {
|
2011-06-28 12:00:31 -06:00
|
|
|
return Fprintf(os.Stdout, format, a...)
|
2008-10-24 17:33:29 -06:00
|
|
|
}
|
|
|
|
|
2009-03-06 04:35:38 -07:00
|
|
|
// Sprintf formats according to a format specifier and returns the resulting string.
|
2010-02-01 16:53:37 -07:00
|
|
|
func Sprintf(format string, a ...interface{}) string {
|
2009-12-15 16:27:16 -07:00
|
|
|
p := newPrinter()
|
2010-06-14 18:16:35 -06:00
|
|
|
p.doPrintf(format, a)
|
2009-12-15 16:27:16 -07:00
|
|
|
s := p.buf.String()
|
|
|
|
p.free()
|
|
|
|
return s
|
2008-10-24 17:33:29 -06:00
|
|
|
}
|
|
|
|
|
2010-09-30 22:04:55 -06:00
|
|
|
// Errorf formats according to a format specifier and returns the string
|
2011-11-01 20:58:09 -06:00
|
|
|
// as a value that satisfies error.
|
2011-11-01 20:04:37 -06:00
|
|
|
func Errorf(format string, a ...interface{}) error {
|
|
|
|
return errors.New(Sprintf(format, a...))
|
2010-09-30 22:04:55 -06:00
|
|
|
}
|
|
|
|
|
2009-03-06 04:35:38 -07:00
|
|
|
// These routines do not take a format string
|
2008-10-24 17:33:29 -06:00
|
|
|
|
2009-03-06 04:35:38 -07:00
|
|
|
// Fprint formats using the default formats for its operands and writes to w.
|
|
|
|
// Spaces are added between operands when neither is a string.
|
2010-08-18 20:07:24 -06:00
|
|
|
// It returns the number of bytes written and any write error encountered.
|
2011-11-01 20:04:37 -06:00
|
|
|
func Fprint(w io.Writer, a ...interface{}) (n int, err error) {
|
2009-12-15 16:27:16 -07:00
|
|
|
p := newPrinter()
|
2010-06-14 18:16:35 -06:00
|
|
|
p.doPrint(a, false, false)
|
2011-06-28 12:00:31 -06:00
|
|
|
n64, err := p.buf.WriteTo(w)
|
2009-12-15 16:27:16 -07:00
|
|
|
p.free()
|
2011-06-28 12:00:31 -06:00
|
|
|
return int(n64), err
|
2008-10-24 17:33:29 -06:00
|
|
|
}
|
|
|
|
|
2009-03-06 04:35:38 -07:00
|
|
|
// Print formats using the default formats for its operands and writes to standard output.
|
|
|
|
// Spaces are added between operands when neither is a string.
|
2010-08-18 20:07:24 -06:00
|
|
|
// It returns the number of bytes written and any write error encountered.
|
2011-11-01 20:04:37 -06:00
|
|
|
func Print(a ...interface{}) (n int, err error) {
|
2011-06-28 12:00:31 -06:00
|
|
|
return Fprint(os.Stdout, a...)
|
2008-10-24 17:33:29 -06:00
|
|
|
}
|
|
|
|
|
2009-03-06 04:35:38 -07:00
|
|
|
// Sprint formats using the default formats for its operands and returns the resulting string.
|
|
|
|
// Spaces are added between operands when neither is a string.
|
2010-02-01 16:53:37 -07:00
|
|
|
func Sprint(a ...interface{}) string {
|
2009-12-15 16:27:16 -07:00
|
|
|
p := newPrinter()
|
2010-06-14 18:16:35 -06:00
|
|
|
p.doPrint(a, false, false)
|
2009-12-15 16:27:16 -07:00
|
|
|
s := p.buf.String()
|
|
|
|
p.free()
|
|
|
|
return s
|
2008-10-24 17:33:29 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
// These routines end in 'ln', do not take a format string,
|
|
|
|
// always add spaces between operands, and add a newline
|
|
|
|
// after the last operand.
|
|
|
|
|
2009-03-06 04:35:38 -07:00
|
|
|
// Fprintln formats using the default formats for its operands and writes to w.
|
|
|
|
// Spaces are always added between operands and a newline is appended.
|
2010-08-18 20:07:24 -06:00
|
|
|
// It returns the number of bytes written and any write error encountered.
|
2011-11-01 20:04:37 -06:00
|
|
|
func Fprintln(w io.Writer, a ...interface{}) (n int, err error) {
|
2009-12-15 16:27:16 -07:00
|
|
|
p := newPrinter()
|
2010-06-14 18:16:35 -06:00
|
|
|
p.doPrint(a, true, true)
|
2011-06-28 12:00:31 -06:00
|
|
|
n64, err := p.buf.WriteTo(w)
|
2009-12-15 16:27:16 -07:00
|
|
|
p.free()
|
2011-06-28 12:00:31 -06:00
|
|
|
return int(n64), err
|
2008-10-24 17:33:29 -06:00
|
|
|
}
|
|
|
|
|
2009-03-06 04:35:38 -07:00
|
|
|
// 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.
|
2010-08-18 20:07:24 -06:00
|
|
|
// It returns the number of bytes written and any write error encountered.
|
2011-11-01 20:04:37 -06:00
|
|
|
func Println(a ...interface{}) (n int, err error) {
|
2011-06-28 12:00:31 -06:00
|
|
|
return Fprintln(os.Stdout, a...)
|
2008-10-24 17:33:29 -06:00
|
|
|
}
|
|
|
|
|
2009-03-06 04:35:38 -07:00
|
|
|
// 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.
|
2010-02-01 16:53:37 -07:00
|
|
|
func Sprintln(a ...interface{}) string {
|
2009-12-15 16:27:16 -07:00
|
|
|
p := newPrinter()
|
2010-06-14 18:16:35 -06:00
|
|
|
p.doPrint(a, true, true)
|
2009-12-15 16:27:16 -07:00
|
|
|
s := p.buf.String()
|
|
|
|
p.free()
|
|
|
|
return s
|
2008-10-24 17:33:29 -06:00
|
|
|
}
|
|
|
|
|
2008-11-24 15:51:33 -07:00
|
|
|
// 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.
|
2011-04-08 10:27:58 -06:00
|
|
|
func getField(v reflect.Value, i int) reflect.Value {
|
2009-12-15 16:27:16 -07:00
|
|
|
val := v.Field(i)
|
2011-10-17 16:48:45 -06:00
|
|
|
if val.Kind() == reflect.Interface && !val.IsNil() {
|
|
|
|
val = val.Elem()
|
2008-11-24 15:51:33 -07:00
|
|
|
}
|
2009-12-15 16:27:16 -07:00
|
|
|
return val
|
2008-11-24 15:51:33 -07:00
|
|
|
}
|
|
|
|
|
2010-06-14 18:16:35 -06:00
|
|
|
// Convert ASCII to integer. n is 0 (and got is false) if no number present.
|
|
|
|
func parsenum(s string, start, end int) (num int, isnum bool, newi int) {
|
|
|
|
if start >= end {
|
|
|
|
return 0, false, end
|
2010-02-01 16:53:37 -07:00
|
|
|
}
|
2010-06-14 18:16:35 -06:00
|
|
|
for newi = start; newi < end && '0' <= s[newi] && s[newi] <= '9'; newi++ {
|
|
|
|
num = num*10 + int(s[newi]-'0')
|
|
|
|
isnum = true
|
2008-11-06 11:40:57 -07:00
|
|
|
}
|
2009-12-15 16:27:16 -07:00
|
|
|
return
|
2008-11-06 11:40:57 -07:00
|
|
|
}
|
|
|
|
|
2010-06-14 18:16:35 -06:00
|
|
|
func (p *pp) unknownType(v interface{}) {
|
|
|
|
if v == nil {
|
|
|
|
p.buf.Write(nilAngleBytes)
|
|
|
|
return
|
2010-02-01 16:53:37 -07:00
|
|
|
}
|
2010-06-14 18:16:35 -06:00
|
|
|
p.buf.WriteByte('?')
|
2011-04-25 11:39:36 -06:00
|
|
|
p.buf.WriteString(reflect.TypeOf(v).String())
|
2010-06-14 18:16:35 -06:00
|
|
|
p.buf.WriteByte('?')
|
|
|
|
}
|
|
|
|
|
2011-10-25 23:21:33 -06:00
|
|
|
func (p *pp) badVerb(verb rune) {
|
2010-06-14 18:16:35 -06:00
|
|
|
p.add('%')
|
2010-09-23 19:53:26 -06:00
|
|
|
p.add('!')
|
2010-06-14 18:16:35 -06:00
|
|
|
p.add(verb)
|
|
|
|
p.add('(')
|
2011-10-17 16:48:45 -06:00
|
|
|
switch {
|
2011-10-21 14:59:27 -06:00
|
|
|
case p.field != nil:
|
|
|
|
p.buf.WriteString(reflect.TypeOf(p.field).String())
|
2010-06-14 18:16:35 -06:00
|
|
|
p.add('=')
|
2011-10-21 14:59:27 -06:00
|
|
|
p.printField(p.field, 'v', false, false, 0)
|
2011-10-18 17:23:07 -06:00
|
|
|
case p.value.IsValid():
|
|
|
|
p.buf.WriteString(p.value.Type().String())
|
2011-10-17 16:48:45 -06:00
|
|
|
p.add('=')
|
2011-10-18 17:23:07 -06:00
|
|
|
p.printValue(p.value, 'v', false, false, 0)
|
2011-10-17 16:48:45 -06:00
|
|
|
default:
|
|
|
|
p.buf.Write(nilAngleBytes)
|
2008-10-24 17:33:29 -06:00
|
|
|
}
|
2010-06-14 18:16:35 -06:00
|
|
|
p.add(')')
|
2008-10-24 17:33:29 -06:00
|
|
|
}
|
|
|
|
|
2011-10-25 23:21:33 -06:00
|
|
|
func (p *pp) fmtBool(v bool, verb rune) {
|
2010-06-14 18:16:35 -06:00
|
|
|
switch verb {
|
|
|
|
case 't', 'v':
|
|
|
|
p.fmt.fmt_boolean(v)
|
|
|
|
default:
|
2011-10-21 14:59:27 -06:00
|
|
|
p.badVerb(verb)
|
2010-02-04 17:23:25 -07:00
|
|
|
}
|
2010-06-14 18:16:35 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
// fmtC formats a rune for the 'c' format.
|
|
|
|
func (p *pp) fmtC(c int64) {
|
2011-10-25 23:21:33 -06:00
|
|
|
r := rune(c) // Check for overflow.
|
|
|
|
if int64(r) != c {
|
|
|
|
r = utf8.RuneError
|
2010-02-01 16:53:37 -07:00
|
|
|
}
|
2011-10-25 23:21:33 -06:00
|
|
|
w := utf8.EncodeRune(p.runeBuf[0:utf8.UTFMax], r)
|
2010-06-14 18:16:35 -06:00
|
|
|
p.fmt.pad(p.runeBuf[0:w])
|
|
|
|
}
|
|
|
|
|
2011-10-25 23:21:33 -06:00
|
|
|
func (p *pp) fmtInt64(v int64, verb rune) {
|
2010-06-14 18:16:35 -06:00
|
|
|
switch verb {
|
|
|
|
case 'b':
|
|
|
|
p.fmt.integer(v, 2, signed, ldigits)
|
|
|
|
case 'c':
|
|
|
|
p.fmtC(v)
|
|
|
|
case 'd', 'v':
|
|
|
|
p.fmt.integer(v, 10, signed, ldigits)
|
|
|
|
case 'o':
|
|
|
|
p.fmt.integer(v, 8, signed, ldigits)
|
2011-05-25 05:25:15 -06:00
|
|
|
case 'q':
|
|
|
|
if 0 <= v && v <= unicode.MaxRune {
|
|
|
|
p.fmt.fmt_qc(v)
|
|
|
|
} else {
|
2011-10-21 14:59:27 -06:00
|
|
|
p.badVerb(verb)
|
2011-05-25 05:25:15 -06:00
|
|
|
}
|
2010-06-14 18:16:35 -06:00
|
|
|
case 'x':
|
|
|
|
p.fmt.integer(v, 16, signed, ldigits)
|
2010-12-06 12:23:37 -07:00
|
|
|
case 'U':
|
|
|
|
p.fmtUnicode(v)
|
2010-06-14 18:16:35 -06:00
|
|
|
case 'X':
|
|
|
|
p.fmt.integer(v, 16, signed, udigits)
|
|
|
|
default:
|
2011-10-21 14:59:27 -06:00
|
|
|
p.badVerb(verb)
|
2009-07-07 12:03:31 -06:00
|
|
|
}
|
2010-06-14 18:16:35 -06:00
|
|
|
}
|
|
|
|
|
2011-03-01 14:25:52 -07:00
|
|
|
// 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) {
|
2010-06-14 18:16:35 -06:00
|
|
|
sharp := p.fmt.sharp
|
2011-03-01 14:25:52 -07:00
|
|
|
p.fmt.sharp = leading0x
|
2010-06-14 18:16:35 -06:00
|
|
|
p.fmt.integer(int64(v), 16, unsigned, ldigits)
|
|
|
|
p.fmt.sharp = sharp
|
|
|
|
}
|
|
|
|
|
2010-12-06 12:23:37 -07:00
|
|
|
// fmtUnicode formats a uint64 in U+1234 form by
|
|
|
|
// temporarily turning on the unicode flag and tweaking the precision.
|
|
|
|
func (p *pp) fmtUnicode(v int64) {
|
|
|
|
precPresent := p.fmt.precPresent
|
2011-06-10 18:03:02 -06:00
|
|
|
sharp := p.fmt.sharp
|
|
|
|
p.fmt.sharp = false
|
2010-12-06 12:23:37 -07:00
|
|
|
prec := p.fmt.prec
|
|
|
|
if !precPresent {
|
|
|
|
// If prec is already set, leave it alone; otherwise 4 is minimum.
|
|
|
|
p.fmt.prec = 4
|
|
|
|
p.fmt.precPresent = true
|
|
|
|
}
|
|
|
|
p.fmt.unicode = true // turn on U+
|
2011-06-10 18:03:02 -06:00
|
|
|
p.fmt.uniQuote = sharp
|
2010-12-06 12:23:37 -07:00
|
|
|
p.fmt.integer(int64(v), 16, unsigned, udigits)
|
|
|
|
p.fmt.unicode = false
|
2011-06-10 18:03:02 -06:00
|
|
|
p.fmt.uniQuote = false
|
2010-12-06 12:23:37 -07:00
|
|
|
p.fmt.prec = prec
|
|
|
|
p.fmt.precPresent = precPresent
|
2011-06-10 18:03:02 -06:00
|
|
|
p.fmt.sharp = sharp
|
2010-12-06 12:23:37 -07:00
|
|
|
}
|
|
|
|
|
2011-10-25 23:21:33 -06:00
|
|
|
func (p *pp) fmtUint64(v uint64, verb rune, goSyntax bool) {
|
2010-06-14 18:16:35 -06:00
|
|
|
switch verb {
|
|
|
|
case 'b':
|
|
|
|
p.fmt.integer(int64(v), 2, unsigned, ldigits)
|
|
|
|
case 'c':
|
|
|
|
p.fmtC(int64(v))
|
|
|
|
case 'd':
|
|
|
|
p.fmt.integer(int64(v), 10, unsigned, ldigits)
|
|
|
|
case 'v':
|
2010-06-28 15:11:38 -06:00
|
|
|
if goSyntax {
|
2011-03-01 14:25:52 -07:00
|
|
|
p.fmt0x64(v, true)
|
2010-06-14 18:16:35 -06:00
|
|
|
} else {
|
|
|
|
p.fmt.integer(int64(v), 10, unsigned, ldigits)
|
|
|
|
}
|
|
|
|
case 'o':
|
|
|
|
p.fmt.integer(int64(v), 8, unsigned, ldigits)
|
2011-05-25 05:25:15 -06:00
|
|
|
case 'q':
|
|
|
|
if 0 <= v && v <= unicode.MaxRune {
|
|
|
|
p.fmt.fmt_qc(int64(v))
|
|
|
|
} else {
|
2011-10-21 14:59:27 -06:00
|
|
|
p.badVerb(verb)
|
2011-05-25 05:25:15 -06:00
|
|
|
}
|
2010-06-14 18:16:35 -06:00
|
|
|
case 'x':
|
|
|
|
p.fmt.integer(int64(v), 16, unsigned, ldigits)
|
|
|
|
case 'X':
|
|
|
|
p.fmt.integer(int64(v), 16, unsigned, udigits)
|
2011-04-12 12:03:05 -06:00
|
|
|
case 'U':
|
|
|
|
p.fmtUnicode(int64(v))
|
2010-06-14 18:16:35 -06:00
|
|
|
default:
|
2011-10-21 14:59:27 -06:00
|
|
|
p.badVerb(verb)
|
2008-10-24 17:33:29 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-10-25 23:21:33 -06:00
|
|
|
func (p *pp) fmtFloat32(v float32, verb rune) {
|
2010-06-14 18:16:35 -06:00
|
|
|
switch verb {
|
|
|
|
case 'b':
|
|
|
|
p.fmt.fmt_fb32(v)
|
|
|
|
case 'e':
|
|
|
|
p.fmt.fmt_e32(v)
|
|
|
|
case 'E':
|
|
|
|
p.fmt.fmt_E32(v)
|
|
|
|
case 'f':
|
|
|
|
p.fmt.fmt_f32(v)
|
|
|
|
case 'g', 'v':
|
|
|
|
p.fmt.fmt_g32(v)
|
|
|
|
case 'G':
|
|
|
|
p.fmt.fmt_G32(v)
|
|
|
|
default:
|
2011-10-21 14:59:27 -06:00
|
|
|
p.badVerb(verb)
|
2008-11-17 13:34:03 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-10-25 23:21:33 -06:00
|
|
|
func (p *pp) fmtFloat64(v float64, verb rune) {
|
2010-06-14 18:16:35 -06:00
|
|
|
switch verb {
|
|
|
|
case 'b':
|
|
|
|
p.fmt.fmt_fb64(v)
|
|
|
|
case 'e':
|
|
|
|
p.fmt.fmt_e64(v)
|
|
|
|
case 'E':
|
|
|
|
p.fmt.fmt_E64(v)
|
|
|
|
case 'f':
|
|
|
|
p.fmt.fmt_f64(v)
|
|
|
|
case 'g', 'v':
|
|
|
|
p.fmt.fmt_g64(v)
|
|
|
|
case 'G':
|
|
|
|
p.fmt.fmt_G64(v)
|
|
|
|
default:
|
2011-10-21 14:59:27 -06:00
|
|
|
p.badVerb(verb)
|
2008-10-24 17:33:29 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-10-25 23:21:33 -06:00
|
|
|
func (p *pp) fmtComplex64(v complex64, verb rune) {
|
2010-06-14 18:16:35 -06:00
|
|
|
switch verb {
|
|
|
|
case 'e', 'E', 'f', 'F', 'g', 'G':
|
|
|
|
p.fmt.fmt_c64(v, verb)
|
|
|
|
case 'v':
|
|
|
|
p.fmt.fmt_c64(v, 'g')
|
|
|
|
default:
|
2011-10-21 14:59:27 -06:00
|
|
|
p.badVerb(verb)
|
2010-03-05 21:16:04 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-10-25 23:21:33 -06:00
|
|
|
func (p *pp) fmtComplex128(v complex128, verb rune) {
|
2010-06-14 18:16:35 -06:00
|
|
|
switch verb {
|
|
|
|
case 'e', 'E', 'f', 'F', 'g', 'G':
|
|
|
|
p.fmt.fmt_c128(v, verb)
|
|
|
|
case 'v':
|
|
|
|
p.fmt.fmt_c128(v, 'g')
|
|
|
|
default:
|
2011-10-21 14:59:27 -06:00
|
|
|
p.badVerb(verb)
|
2010-03-05 21:16:04 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-10-25 23:21:33 -06:00
|
|
|
func (p *pp) fmtString(v string, verb rune, goSyntax bool) {
|
2010-06-14 18:16:35 -06:00
|
|
|
switch verb {
|
|
|
|
case 'v':
|
2010-06-28 15:11:38 -06:00
|
|
|
if goSyntax {
|
2010-06-14 18:16:35 -06:00
|
|
|
p.fmt.fmt_q(v)
|
|
|
|
} else {
|
|
|
|
p.fmt.fmt_s(v)
|
|
|
|
}
|
|
|
|
case 's':
|
|
|
|
p.fmt.fmt_s(v)
|
|
|
|
case 'x':
|
|
|
|
p.fmt.fmt_sx(v)
|
|
|
|
case 'X':
|
|
|
|
p.fmt.fmt_sX(v)
|
|
|
|
case 'q':
|
|
|
|
p.fmt.fmt_q(v)
|
|
|
|
default:
|
2011-10-21 14:59:27 -06:00
|
|
|
p.badVerb(verb)
|
2008-10-24 17:33:29 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-10-25 23:21:33 -06:00
|
|
|
func (p *pp) fmtBytes(v []byte, verb rune, goSyntax bool, depth int) {
|
2010-10-04 03:57:48 -06:00
|
|
|
if verb == 'v' || verb == 'd' {
|
2010-06-28 15:11:38 -06:00
|
|
|
if goSyntax {
|
2010-06-14 18:16:35 -06:00
|
|
|
p.buf.Write(bytesBytes)
|
|
|
|
} else {
|
|
|
|
p.buf.WriteByte('[')
|
|
|
|
}
|
|
|
|
for i, c := range v {
|
|
|
|
if i > 0 {
|
2010-06-28 15:11:38 -06:00
|
|
|
if goSyntax {
|
2010-06-14 18:16:35 -06:00
|
|
|
p.buf.Write(commaSpaceBytes)
|
|
|
|
} else {
|
|
|
|
p.buf.WriteByte(' ')
|
|
|
|
}
|
|
|
|
}
|
2010-06-28 15:11:38 -06:00
|
|
|
p.printField(c, 'v', p.fmt.plus, goSyntax, depth+1)
|
2010-06-14 18:16:35 -06:00
|
|
|
}
|
2010-06-28 15:11:38 -06:00
|
|
|
if goSyntax {
|
2010-06-14 18:16:35 -06:00
|
|
|
p.buf.WriteByte('}')
|
|
|
|
} else {
|
|
|
|
p.buf.WriteByte(']')
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
s := string(v)
|
|
|
|
switch verb {
|
|
|
|
case 's':
|
|
|
|
p.fmt.fmt_s(s)
|
|
|
|
case 'x':
|
|
|
|
p.fmt.fmt_sx(s)
|
|
|
|
case 'X':
|
|
|
|
p.fmt.fmt_sX(s)
|
|
|
|
case 'q':
|
|
|
|
p.fmt.fmt_q(s)
|
|
|
|
default:
|
2011-10-21 14:59:27 -06:00
|
|
|
p.badVerb(verb)
|
2010-06-14 18:16:35 -06:00
|
|
|
}
|
2009-08-31 17:38:30 -06:00
|
|
|
}
|
|
|
|
|
2011-10-25 23:21:33 -06:00
|
|
|
func (p *pp) fmtPointer(value reflect.Value, verb rune, goSyntax bool) {
|
2011-03-30 20:12:30 -06:00
|
|
|
var u uintptr
|
2011-04-08 10:27:58 -06:00
|
|
|
switch value.Kind() {
|
|
|
|
case reflect.Chan, reflect.Func, reflect.Map, reflect.Ptr, reflect.Slice, reflect.UnsafePointer:
|
|
|
|
u = value.Pointer()
|
2011-03-30 20:12:30 -06:00
|
|
|
default:
|
2011-10-21 14:59:27 -06:00
|
|
|
p.badVerb(verb)
|
2010-08-13 15:37:03 -06:00
|
|
|
return
|
2010-02-01 16:53:37 -07:00
|
|
|
}
|
2010-08-13 15:37:03 -06:00
|
|
|
if goSyntax {
|
2010-06-14 18:16:35 -06:00
|
|
|
p.add('(')
|
2011-10-17 16:48:45 -06:00
|
|
|
p.buf.WriteString(value.Type().String())
|
2010-06-14 18:16:35 -06:00
|
|
|
p.add(')')
|
|
|
|
p.add('(')
|
|
|
|
if u == 0 {
|
|
|
|
p.buf.Write(nilBytes)
|
|
|
|
} else {
|
2011-03-30 20:12:30 -06:00
|
|
|
p.fmt0x64(uint64(u), true)
|
2010-06-14 18:16:35 -06:00
|
|
|
}
|
|
|
|
p.add(')')
|
|
|
|
} else {
|
2011-03-01 14:25:52 -07:00
|
|
|
p.fmt0x64(uint64(u), !p.fmt.sharp)
|
2010-06-14 18:16:35 -06:00
|
|
|
}
|
2010-02-01 16:53:37 -07:00
|
|
|
}
|
|
|
|
|
2010-06-20 13:16:25 -06:00
|
|
|
var (
|
2011-04-25 11:39:36 -06:00
|
|
|
intBits = reflect.TypeOf(0).Bits()
|
|
|
|
floatBits = reflect.TypeOf(0.0).Bits()
|
|
|
|
complexBits = reflect.TypeOf(1i).Bits()
|
|
|
|
uintptrBits = reflect.TypeOf(uintptr(0)).Bits()
|
2010-06-20 13:16:25 -06:00
|
|
|
)
|
|
|
|
|
2011-10-25 23:21:33 -06:00
|
|
|
func (p *pp) catchPanic(field interface{}, verb rune) {
|
fmt: catch panics from calls to String etc.
This change causes Print et al. to catch panics generated by
calls to String, GoString, and Format. The panic is formatted
into the output stream as an error, but the program continues.
As a special case, if the argument was a nil pointer, the
result is just "<nil>", because that's almost certainly enough
information and handles the very common case of String
methods that don't guard against nil.
Scan does not want this change. Input must work; output can
be for debugging and it's nice to get output even when you
make a mistake.
R=dsymonds, r, adg, gri, rsc, gri
CC=golang-dev
https://golang.org/cl/4640043
2011-06-20 16:31:02 -06:00
|
|
|
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.
|
2011-10-21 14:59:27 -06:00
|
|
|
if v := reflect.ValueOf(field); v.Kind() == reflect.Ptr && v.IsNil() {
|
fmt: catch panics from calls to String etc.
This change causes Print et al. to catch panics generated by
calls to String, GoString, and Format. The panic is formatted
into the output stream as an error, but the program continues.
As a special case, if the argument was a nil pointer, the
result is just "<nil>", because that's almost certainly enough
information and handles the very common case of String
methods that don't guard against nil.
Scan does not want this change. Input must work; output can
be for debugging and it's nice to get output even when you
make a mistake.
R=dsymonds, r, adg, gri, rsc, gri
CC=golang-dev
https://golang.org/cl/4640043
2011-06-20 16:31:02 -06:00
|
|
|
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(')')
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-10-25 23:21:33 -06:00
|
|
|
func (p *pp) handleMethods(verb rune, plus, goSyntax bool, depth int) (wasString, handled bool) {
|
2010-08-13 01:26:32 -06:00
|
|
|
// Is it a Formatter?
|
2011-10-21 14:59:27 -06:00
|
|
|
if formatter, ok := p.field.(Formatter); ok {
|
2011-10-17 16:48:45 -06:00
|
|
|
handled = true
|
|
|
|
wasString = false
|
2011-10-21 14:59:27 -06:00
|
|
|
defer p.catchPanic(p.field, verb)
|
2010-08-13 01:26:32 -06:00
|
|
|
formatter.Format(p, verb)
|
2011-10-17 16:48:45 -06:00
|
|
|
return
|
2010-08-13 01:26:32 -06:00
|
|
|
}
|
|
|
|
// Must not touch flags before Formatter looks at them.
|
|
|
|
if plus {
|
|
|
|
p.fmt.plus = false
|
|
|
|
}
|
2011-10-17 16:48:45 -06:00
|
|
|
|
2010-08-13 01:26:32 -06:00
|
|
|
// If we're doing Go syntax and the field knows how to supply it, take care of it now.
|
|
|
|
if goSyntax {
|
|
|
|
p.fmt.sharp = false
|
2011-10-21 14:59:27 -06:00
|
|
|
if stringer, ok := p.field.(GoStringer); ok {
|
2011-10-17 16:48:45 -06:00
|
|
|
wasString = false
|
|
|
|
handled = true
|
2011-10-21 14:59:27 -06:00
|
|
|
defer p.catchPanic(p.field, verb)
|
2010-08-13 01:26:32 -06:00
|
|
|
// Print the result of GoString unadorned.
|
2011-10-21 14:59:27 -06:00
|
|
|
p.fmtString(stringer.GoString(), 's', false)
|
2011-10-17 16:48:45 -06:00
|
|
|
return
|
2010-08-13 01:26:32 -06:00
|
|
|
}
|
|
|
|
} else {
|
2011-10-27 22:20:44 -06:00
|
|
|
// Is it an error or Stringer?
|
|
|
|
// The duplication in the bodies is necessary:
|
|
|
|
// setting wasString and handled and deferring catchPanic
|
|
|
|
// must happen before calling the method.
|
|
|
|
switch v := p.field.(type) {
|
2011-11-01 20:04:37 -06:00
|
|
|
case error:
|
2011-10-17 16:48:45 -06:00
|
|
|
wasString = false
|
|
|
|
handled = true
|
2011-10-21 14:59:27 -06:00
|
|
|
defer p.catchPanic(p.field, verb)
|
2011-11-01 20:04:37 -06:00
|
|
|
p.printField(v.Error(), verb, plus, false, depth)
|
2011-10-27 22:20:44 -06:00
|
|
|
return
|
|
|
|
|
|
|
|
case Stringer:
|
|
|
|
wasString = false
|
|
|
|
handled = true
|
|
|
|
defer p.catchPanic(p.field, verb)
|
|
|
|
p.printField(v.String(), verb, plus, false, depth)
|
2011-10-17 16:48:45 -06:00
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
handled = false
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2011-10-25 23:21:33 -06:00
|
|
|
func (p *pp) printField(field interface{}, verb rune, plus, goSyntax bool, depth int) (wasString bool) {
|
2011-10-17 16:48:45 -06:00
|
|
|
if field == nil {
|
|
|
|
if verb == 'T' || verb == 'v' {
|
|
|
|
p.buf.Write(nilAngleBytes)
|
|
|
|
} else {
|
2011-10-21 14:59:27 -06:00
|
|
|
p.badVerb(verb)
|
2008-12-11 13:59:49 -07:00
|
|
|
}
|
2011-10-17 16:48:45 -06:00
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2011-10-21 14:59:27 -06:00
|
|
|
p.field = field
|
|
|
|
p.value = reflect.Value{}
|
2011-10-17 16:48:45 -06:00
|
|
|
// Special processing considerations.
|
|
|
|
// %T (the value's type) and %p (its address) are special; we always do them first.
|
|
|
|
switch verb {
|
|
|
|
case 'T':
|
|
|
|
p.printField(reflect.TypeOf(field).String(), 's', false, false, 0)
|
|
|
|
return false
|
|
|
|
case 'p':
|
2011-10-21 14:59:27 -06:00
|
|
|
p.fmtPointer(reflect.ValueOf(field), verb, goSyntax)
|
2011-10-17 16:48:45 -06:00
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2011-10-21 14:59:27 -06:00
|
|
|
if wasString, handled := p.handleMethods(verb, plus, goSyntax, depth); handled {
|
2011-10-17 16:48:45 -06:00
|
|
|
return wasString
|
2009-11-05 10:40:28 -07:00
|
|
|
}
|
2010-02-01 16:53:37 -07:00
|
|
|
|
|
|
|
// Some types can be done without reflection.
|
2009-07-07 12:03:31 -06:00
|
|
|
switch f := field.(type) {
|
2010-02-01 16:53:37 -07:00
|
|
|
case bool:
|
2011-10-21 14:59:27 -06:00
|
|
|
p.fmtBool(f, verb)
|
2010-06-14 18:16:35 -06:00
|
|
|
case float32:
|
2011-10-21 14:59:27 -06:00
|
|
|
p.fmtFloat32(f, verb)
|
2010-06-14 18:16:35 -06:00
|
|
|
case float64:
|
2011-10-21 14:59:27 -06:00
|
|
|
p.fmtFloat64(f, verb)
|
2010-06-14 18:16:35 -06:00
|
|
|
case complex64:
|
2011-10-21 14:59:27 -06:00
|
|
|
p.fmtComplex64(complex64(f), verb)
|
2010-06-14 18:16:35 -06:00
|
|
|
case complex128:
|
2011-10-21 14:59:27 -06:00
|
|
|
p.fmtComplex128(f, verb)
|
2010-06-14 18:16:35 -06:00
|
|
|
case int:
|
2011-10-21 14:59:27 -06:00
|
|
|
p.fmtInt64(int64(f), verb)
|
2010-06-14 18:16:35 -06:00
|
|
|
case int8:
|
2011-10-21 14:59:27 -06:00
|
|
|
p.fmtInt64(int64(f), verb)
|
2010-06-14 18:16:35 -06:00
|
|
|
case int16:
|
2011-10-21 14:59:27 -06:00
|
|
|
p.fmtInt64(int64(f), verb)
|
2010-06-14 18:16:35 -06:00
|
|
|
case int32:
|
2011-10-21 14:59:27 -06:00
|
|
|
p.fmtInt64(int64(f), verb)
|
2010-06-14 18:16:35 -06:00
|
|
|
case int64:
|
2011-10-21 14:59:27 -06:00
|
|
|
p.fmtInt64(f, verb)
|
2010-06-14 18:16:35 -06:00
|
|
|
case uint:
|
2011-10-21 14:59:27 -06:00
|
|
|
p.fmtUint64(uint64(f), verb, goSyntax)
|
2010-06-14 18:16:35 -06:00
|
|
|
case uint8:
|
2011-10-21 14:59:27 -06:00
|
|
|
p.fmtUint64(uint64(f), verb, goSyntax)
|
2010-06-14 18:16:35 -06:00
|
|
|
case uint16:
|
2011-10-21 14:59:27 -06:00
|
|
|
p.fmtUint64(uint64(f), verb, goSyntax)
|
2010-06-14 18:16:35 -06:00
|
|
|
case uint32:
|
2011-10-21 14:59:27 -06:00
|
|
|
p.fmtUint64(uint64(f), verb, goSyntax)
|
2010-06-14 18:16:35 -06:00
|
|
|
case uint64:
|
2011-10-21 14:59:27 -06:00
|
|
|
p.fmtUint64(f, verb, goSyntax)
|
2010-06-14 18:16:35 -06:00
|
|
|
case uintptr:
|
2011-10-21 14:59:27 -06:00
|
|
|
p.fmtUint64(uint64(f), verb, goSyntax)
|
2010-02-01 16:53:37 -07:00
|
|
|
case string:
|
2011-10-21 14:59:27 -06:00
|
|
|
p.fmtString(f, verb, goSyntax)
|
|
|
|
wasString = verb == 's' || verb == 'v'
|
2010-06-14 18:16:35 -06:00
|
|
|
case []byte:
|
2011-10-21 14:59:27 -06:00
|
|
|
p.fmtBytes(f, verb, goSyntax, depth)
|
|
|
|
wasString = verb == 's'
|
|
|
|
default:
|
|
|
|
// Need to use reflection
|
|
|
|
return p.printReflectValue(reflect.ValueOf(field), verb, plus, goSyntax, depth)
|
2010-06-14 18:16:35 -06:00
|
|
|
}
|
2011-10-21 14:59:27 -06:00
|
|
|
p.field = nil
|
|
|
|
return
|
2011-10-17 16:48:45 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
// printValue is like printField but starts with a reflect value, not an interface{} value.
|
2011-10-25 23:21:33 -06:00
|
|
|
func (p *pp) printValue(value reflect.Value, verb rune, plus, goSyntax bool, depth int) (wasString bool) {
|
2011-10-17 16:48:45 -06:00
|
|
|
if !value.IsValid() {
|
|
|
|
if verb == 'T' || verb == 'v' {
|
|
|
|
p.buf.Write(nilAngleBytes)
|
|
|
|
} else {
|
2011-10-21 14:59:27 -06:00
|
|
|
p.badVerb(verb)
|
2011-10-17 16:48:45 -06:00
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
// Special processing considerations.
|
|
|
|
// %T (the value's type) and %p (its address) are special; we always do them first.
|
|
|
|
switch verb {
|
|
|
|
case 'T':
|
|
|
|
p.printField(value.Type().String(), 's', false, false, 0)
|
|
|
|
return false
|
|
|
|
case 'p':
|
2011-10-21 14:59:27 -06:00
|
|
|
p.fmtPointer(value, verb, goSyntax)
|
2011-10-17 16:48:45 -06:00
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
// Handle values with special methods.
|
|
|
|
// Call always, even when field == nil, because handleMethods clears p.fmt.plus for us.
|
2011-10-21 14:59:27 -06:00
|
|
|
p.field = nil // Make sure it's cleared, for safety.
|
2011-10-17 16:48:45 -06:00
|
|
|
if value.CanInterface() {
|
2011-10-21 14:59:27 -06:00
|
|
|
p.field = value.Interface()
|
2011-10-17 16:48:45 -06:00
|
|
|
}
|
2011-10-21 14:59:27 -06:00
|
|
|
if wasString, handled := p.handleMethods(verb, plus, goSyntax, depth); handled {
|
2011-10-17 16:48:45 -06:00
|
|
|
return wasString
|
|
|
|
}
|
|
|
|
|
|
|
|
return p.printReflectValue(value, verb, plus, goSyntax, depth)
|
|
|
|
}
|
2010-06-14 18:16:35 -06:00
|
|
|
|
2011-10-17 16:48:45 -06:00
|
|
|
// printReflectValue is the fallback for both printField and printValue.
|
|
|
|
// It uses reflect to print the value.
|
2011-10-25 23:21:33 -06:00
|
|
|
func (p *pp) printReflectValue(value reflect.Value, verb rune, plus, goSyntax bool, depth int) (wasString bool) {
|
2011-10-18 17:23:07 -06:00
|
|
|
oldValue := p.value
|
|
|
|
p.value = value
|
2010-02-01 16:53:37 -07:00
|
|
|
BigSwitch:
|
2011-04-08 10:27:58 -06:00
|
|
|
switch f := value; f.Kind() {
|
|
|
|
case reflect.Bool:
|
2011-10-21 14:59:27 -06:00
|
|
|
p.fmtBool(f.Bool(), verb)
|
2011-04-08 10:27:58 -06:00
|
|
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
2011-10-21 14:59:27 -06:00
|
|
|
p.fmtInt64(f.Int(), verb)
|
2011-04-08 10:27:58 -06:00
|
|
|
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
2011-10-21 14:59:27 -06:00
|
|
|
p.fmtUint64(uint64(f.Uint()), verb, goSyntax)
|
2011-04-08 10:27:58 -06:00
|
|
|
case reflect.Float32, reflect.Float64:
|
2010-06-20 13:16:25 -06:00
|
|
|
if f.Type().Size() == 4 {
|
2011-10-21 14:59:27 -06:00
|
|
|
p.fmtFloat32(float32(f.Float()), verb)
|
2008-11-17 13:34:03 -07:00
|
|
|
} else {
|
2011-10-21 14:59:27 -06:00
|
|
|
p.fmtFloat64(float64(f.Float()), verb)
|
2008-11-17 13:34:03 -07:00
|
|
|
}
|
2011-04-08 10:27:58 -06:00
|
|
|
case reflect.Complex64, reflect.Complex128:
|
2010-06-20 13:16:25 -06:00
|
|
|
if f.Type().Size() == 8 {
|
2011-10-21 14:59:27 -06:00
|
|
|
p.fmtComplex64(complex64(f.Complex()), verb)
|
2009-08-31 17:38:30 -06:00
|
|
|
} else {
|
2011-10-21 14:59:27 -06:00
|
|
|
p.fmtComplex128(complex128(f.Complex()), verb)
|
2008-12-22 12:04:17 -07:00
|
|
|
}
|
2011-04-08 10:27:58 -06:00
|
|
|
case reflect.String:
|
2011-10-21 14:59:27 -06:00
|
|
|
p.fmtString(f.String(), verb, goSyntax)
|
2011-04-08 10:27:58 -06:00
|
|
|
case reflect.Map:
|
2010-06-28 15:11:38 -06:00
|
|
|
if goSyntax {
|
2010-02-01 16:53:37 -07:00
|
|
|
p.buf.WriteString(f.Type().String())
|
2011-11-14 14:10:58 -07:00
|
|
|
if f.IsNil() {
|
|
|
|
p.buf.WriteString("(nil)")
|
|
|
|
break
|
|
|
|
}
|
2009-12-15 16:27:16 -07:00
|
|
|
p.buf.WriteByte('{')
|
2009-08-31 17:38:30 -06:00
|
|
|
} else {
|
2009-12-06 13:03:52 -07:00
|
|
|
p.buf.Write(mapBytes)
|
2009-08-31 17:38:30 -06:00
|
|
|
}
|
2011-04-08 10:27:58 -06:00
|
|
|
keys := f.MapKeys()
|
2009-07-09 18:30:07 -06:00
|
|
|
for i, key := range keys {
|
|
|
|
if i > 0 {
|
2010-06-28 15:11:38 -06:00
|
|
|
if goSyntax {
|
2009-12-06 13:03:52 -07:00
|
|
|
p.buf.Write(commaSpaceBytes)
|
2009-08-31 17:38:30 -06:00
|
|
|
} else {
|
2009-12-06 13:03:52 -07:00
|
|
|
p.buf.WriteByte(' ')
|
2009-08-31 17:38:30 -06:00
|
|
|
}
|
2009-07-09 18:30:07 -06:00
|
|
|
}
|
2011-10-17 16:48:45 -06:00
|
|
|
p.printValue(key, verb, plus, goSyntax, depth+1)
|
2009-12-15 16:27:16 -07:00
|
|
|
p.buf.WriteByte(':')
|
2011-10-17 16:48:45 -06:00
|
|
|
p.printValue(f.MapIndex(key), verb, plus, goSyntax, depth+1)
|
2009-08-31 17:38:30 -06:00
|
|
|
}
|
2010-06-28 15:11:38 -06:00
|
|
|
if goSyntax {
|
2009-12-06 13:03:52 -07:00
|
|
|
p.buf.WriteByte('}')
|
2009-08-31 17:38:30 -06:00
|
|
|
} else {
|
2009-12-06 13:03:52 -07:00
|
|
|
p.buf.WriteByte(']')
|
2009-07-09 18:30:07 -06:00
|
|
|
}
|
2011-04-08 10:27:58 -06:00
|
|
|
case reflect.Struct:
|
2010-06-28 15:11:38 -06:00
|
|
|
if goSyntax {
|
2011-10-17 16:48:45 -06:00
|
|
|
p.buf.WriteString(value.Type().String())
|
2009-08-31 17:38:30 -06:00
|
|
|
}
|
2009-12-15 16:27:16 -07:00
|
|
|
p.add('{')
|
|
|
|
v := f
|
2011-04-08 10:27:58 -06:00
|
|
|
t := v.Type()
|
2009-10-06 16:38:57 -06:00
|
|
|
for i := 0; i < v.NumField(); i++ {
|
2008-12-11 17:53:33 -07:00
|
|
|
if i > 0 {
|
2010-06-28 15:11:38 -06:00
|
|
|
if goSyntax {
|
2009-12-06 13:03:52 -07:00
|
|
|
p.buf.Write(commaSpaceBytes)
|
2009-08-31 17:38:30 -06:00
|
|
|
} else {
|
2009-12-06 13:03:52 -07:00
|
|
|
p.buf.WriteByte(' ')
|
2009-08-31 17:38:30 -06:00
|
|
|
}
|
2008-12-11 17:53:33 -07:00
|
|
|
}
|
2010-06-28 15:11:38 -06:00
|
|
|
if plus || goSyntax {
|
2009-07-07 12:03:31 -06:00
|
|
|
if f := t.Field(i); f.Name != "" {
|
2009-12-15 16:27:16 -07:00
|
|
|
p.buf.WriteString(f.Name)
|
|
|
|
p.buf.WriteByte(':')
|
2008-12-11 17:53:33 -07:00
|
|
|
}
|
|
|
|
}
|
2011-10-17 16:48:45 -06:00
|
|
|
p.printValue(getField(v, i), verb, plus, goSyntax, depth+1)
|
2008-12-11 17:53:33 -07:00
|
|
|
}
|
2009-12-15 16:27:16 -07:00
|
|
|
p.buf.WriteByte('}')
|
2011-04-08 10:27:58 -06:00
|
|
|
case reflect.Interface:
|
2009-12-15 16:27:16 -07:00
|
|
|
value := f.Elem()
|
2011-04-08 10:27:58 -06:00
|
|
|
if !value.IsValid() {
|
2010-06-28 15:11:38 -06:00
|
|
|
if goSyntax {
|
2011-10-19 14:26:08 -06:00
|
|
|
p.buf.WriteString(f.Type().String())
|
2009-12-15 16:27:16 -07:00
|
|
|
p.buf.Write(nilParenBytes)
|
2009-08-31 17:38:30 -06:00
|
|
|
} else {
|
2009-12-06 13:03:52 -07:00
|
|
|
p.buf.Write(nilAngleBytes)
|
2009-08-31 17:38:30 -06:00
|
|
|
}
|
2008-12-11 13:59:49 -07:00
|
|
|
} else {
|
2011-10-18 17:23:07 -06:00
|
|
|
wasString = p.printValue(value, verb, plus, goSyntax, depth+1)
|
2009-08-31 17:38:30 -06:00
|
|
|
}
|
2011-04-08 10:27:58 -06:00
|
|
|
case reflect.Array, reflect.Slice:
|
2010-08-16 16:34:40 -06:00
|
|
|
// Byte slices are special.
|
2011-04-08 10:27:58 -06:00
|
|
|
if f.Type().Elem().Kind() == reflect.Uint8 {
|
2010-08-16 16:34:40 -06:00
|
|
|
// We know it's a slice of bytes, but we also know it does not have static type
|
|
|
|
// []byte, or it would have been caught above. Therefore we cannot convert
|
|
|
|
// it directly in the (slightly) obvious way: f.Interface().([]byte); it doesn't have
|
|
|
|
// that type, and we can't write an expression of the right type and do a
|
|
|
|
// conversion because we don't have a static way to write the right type.
|
|
|
|
// So we build a slice by hand. This is a rare case but it would be nice
|
|
|
|
// if reflection could help a little more.
|
|
|
|
bytes := make([]byte, f.Len())
|
|
|
|
for i := range bytes {
|
2011-04-08 10:27:58 -06:00
|
|
|
bytes[i] = byte(f.Index(i).Uint())
|
2010-08-16 16:34:40 -06:00
|
|
|
}
|
2011-10-21 14:59:27 -06:00
|
|
|
p.fmtBytes(bytes, verb, goSyntax, depth)
|
2011-10-18 17:23:07 -06:00
|
|
|
wasString = verb == 's'
|
|
|
|
break
|
2010-08-16 16:34:40 -06:00
|
|
|
}
|
2010-06-28 15:11:38 -06:00
|
|
|
if goSyntax {
|
2011-10-17 16:48:45 -06:00
|
|
|
p.buf.WriteString(value.Type().String())
|
2011-11-14 14:10:58 -07:00
|
|
|
if f.IsNil() {
|
|
|
|
p.buf.WriteString("(nil)")
|
|
|
|
break
|
|
|
|
}
|
2009-12-15 16:27:16 -07:00
|
|
|
p.buf.WriteByte('{')
|
2009-08-31 17:38:30 -06:00
|
|
|
} else {
|
2009-12-06 13:03:52 -07:00
|
|
|
p.buf.WriteByte('[')
|
2009-08-31 17:38:30 -06:00
|
|
|
}
|
|
|
|
for i := 0; i < f.Len(); i++ {
|
|
|
|
if i > 0 {
|
2010-06-28 15:11:38 -06:00
|
|
|
if goSyntax {
|
2009-12-06 13:03:52 -07:00
|
|
|
p.buf.Write(commaSpaceBytes)
|
2009-08-31 17:38:30 -06:00
|
|
|
} else {
|
2009-12-06 13:03:52 -07:00
|
|
|
p.buf.WriteByte(' ')
|
2009-08-31 17:38:30 -06:00
|
|
|
}
|
|
|
|
}
|
2011-10-17 16:48:45 -06:00
|
|
|
p.printValue(f.Index(i), verb, plus, goSyntax, depth+1)
|
2009-08-31 17:38:30 -06:00
|
|
|
}
|
2010-06-28 15:11:38 -06:00
|
|
|
if goSyntax {
|
2009-12-06 13:03:52 -07:00
|
|
|
p.buf.WriteByte('}')
|
2009-08-31 17:38:30 -06:00
|
|
|
} else {
|
2009-12-06 13:03:52 -07:00
|
|
|
p.buf.WriteByte(']')
|
2009-08-31 17:38:30 -06:00
|
|
|
}
|
2011-04-08 10:27:58 -06:00
|
|
|
case reflect.Ptr:
|
|
|
|
v := f.Pointer()
|
2009-08-31 17:38:30 -06:00
|
|
|
// pointer to array or slice or struct? ok at top level
|
|
|
|
// but not embedded (avoid loops)
|
|
|
|
if v != 0 && depth == 0 {
|
2011-04-08 10:27:58 -06:00
|
|
|
switch a := f.Elem(); a.Kind() {
|
|
|
|
case reflect.Array, reflect.Slice:
|
2009-12-15 16:27:16 -07:00
|
|
|
p.buf.WriteByte('&')
|
2011-10-17 16:48:45 -06:00
|
|
|
p.printValue(a, verb, plus, goSyntax, depth+1)
|
2009-12-15 16:27:16 -07:00
|
|
|
break BigSwitch
|
2011-04-08 10:27:58 -06:00
|
|
|
case reflect.Struct:
|
2009-12-15 16:27:16 -07:00
|
|
|
p.buf.WriteByte('&')
|
2011-10-17 16:48:45 -06:00
|
|
|
p.printValue(a, verb, plus, goSyntax, depth+1)
|
2009-12-15 16:27:16 -07:00
|
|
|
break BigSwitch
|
2009-08-31 17:38:30 -06:00
|
|
|
}
|
|
|
|
}
|
2010-06-28 15:11:38 -06:00
|
|
|
if goSyntax {
|
2009-12-15 16:27:16 -07:00
|
|
|
p.buf.WriteByte('(')
|
2011-10-17 16:48:45 -06:00
|
|
|
p.buf.WriteString(value.Type().String())
|
2009-12-15 16:27:16 -07:00
|
|
|
p.buf.WriteByte(')')
|
|
|
|
p.buf.WriteByte('(')
|
2009-08-31 17:38:30 -06:00
|
|
|
if v == 0 {
|
2009-12-06 13:03:52 -07:00
|
|
|
p.buf.Write(nilBytes)
|
2009-08-31 17:38:30 -06:00
|
|
|
} else {
|
2011-03-01 14:25:52 -07:00
|
|
|
p.fmt0x64(uint64(v), true)
|
2009-08-31 17:38:30 -06:00
|
|
|
}
|
2009-12-15 16:27:16 -07:00
|
|
|
p.buf.WriteByte(')')
|
|
|
|
break
|
2009-08-31 17:38:30 -06:00
|
|
|
}
|
|
|
|
if v == 0 {
|
2009-12-15 16:27:16 -07:00
|
|
|
p.buf.Write(nilAngleBytes)
|
|
|
|
break
|
2009-08-31 17:38:30 -06:00
|
|
|
}
|
2011-03-01 14:25:52 -07:00
|
|
|
p.fmt0x64(uint64(v), true)
|
2011-04-08 10:27:58 -06:00
|
|
|
case reflect.Chan, reflect.Func, reflect.UnsafePointer:
|
2011-10-21 14:59:27 -06:00
|
|
|
p.fmtPointer(value, verb, goSyntax)
|
2010-06-14 18:16:35 -06:00
|
|
|
default:
|
|
|
|
p.unknownType(f)
|
2008-11-13 16:20:52 -07:00
|
|
|
}
|
2011-10-18 17:23:07 -06:00
|
|
|
p.value = oldValue
|
|
|
|
return wasString
|
2008-11-13 16:20:52 -07:00
|
|
|
}
|
|
|
|
|
2010-09-22 00:10:38 -06:00
|
|
|
// intFromArg gets the fieldnumth element of a. On return, isInt reports whether the argument has type int.
|
|
|
|
func intFromArg(a []interface{}, end, i, fieldnum int) (num int, isInt bool, newi, newfieldnum int) {
|
|
|
|
newi, newfieldnum = end, fieldnum
|
|
|
|
if i < end && fieldnum < len(a) {
|
|
|
|
num, isInt = a[fieldnum].(int)
|
|
|
|
newi, newfieldnum = i+1, fieldnum+1
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2010-06-14 18:16:35 -06:00
|
|
|
func (p *pp) doPrintf(format string, a []interface{}) {
|
2011-01-05 11:11:34 -07:00
|
|
|
end := len(format)
|
2009-12-15 16:27:16 -07:00
|
|
|
fieldnum := 0 // we process one field per non-trivial format
|
2011-01-05 11:11:34 -07:00
|
|
|
for i := 0; i < end; {
|
2011-01-05 12:42:35 -07:00
|
|
|
lasti := i
|
|
|
|
for i < end && format[i] != '%' {
|
|
|
|
i++
|
|
|
|
}
|
|
|
|
if i > lasti {
|
|
|
|
p.buf.WriteString(format[lasti:i])
|
2008-10-24 17:33:29 -06:00
|
|
|
}
|
2011-01-05 12:42:35 -07:00
|
|
|
if i >= end {
|
|
|
|
// done processing format string
|
|
|
|
break
|
|
|
|
}
|
|
|
|
|
2011-01-05 11:11:34 -07:00
|
|
|
// Process one verb
|
2009-12-15 16:27:16 -07:00
|
|
|
i++
|
2008-12-11 17:53:33 -07:00
|
|
|
// flags and widths
|
2009-12-15 16:27:16 -07:00
|
|
|
p.fmt.clearflags()
|
2010-05-21 21:25:08 -06:00
|
|
|
F:
|
|
|
|
for ; i < end; i++ {
|
2008-11-24 15:51:33 -07:00
|
|
|
switch format[i] {
|
|
|
|
case '#':
|
2009-11-09 13:07:39 -07:00
|
|
|
p.fmt.sharp = true
|
2008-11-24 15:51:33 -07:00
|
|
|
case '0':
|
2009-11-09 13:07:39 -07:00
|
|
|
p.fmt.zero = true
|
2008-11-24 15:51:33 -07:00
|
|
|
case '+':
|
2009-11-09 13:07:39 -07:00
|
|
|
p.fmt.plus = true
|
2008-11-24 15:51:33 -07:00
|
|
|
case '-':
|
2009-11-09 13:07:39 -07:00
|
|
|
p.fmt.minus = true
|
2008-11-24 15:51:33 -07:00
|
|
|
case ' ':
|
2009-11-09 13:07:39 -07:00
|
|
|
p.fmt.space = true
|
2008-11-24 15:51:33 -07:00
|
|
|
default:
|
2009-11-09 13:07:39 -07:00
|
|
|
break F
|
2008-11-24 15:51:33 -07:00
|
|
|
}
|
|
|
|
}
|
2010-09-22 00:10:38 -06:00
|
|
|
// do we have width?
|
2011-01-05 11:11:34 -07:00
|
|
|
if i < end && format[i] == '*' {
|
2010-09-22 00:10:38 -06:00
|
|
|
p.fmt.wid, p.fmt.widPresent, i, fieldnum = intFromArg(a, end, i, fieldnum)
|
|
|
|
if !p.fmt.widPresent {
|
|
|
|
p.buf.Write(widthBytes)
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
p.fmt.wid, p.fmt.widPresent, i = parsenum(format, i, end)
|
|
|
|
}
|
|
|
|
// do we have precision?
|
2008-10-24 17:33:29 -06:00
|
|
|
if i < end && format[i] == '.' {
|
2010-09-22 00:10:38 -06:00
|
|
|
if format[i+1] == '*' {
|
|
|
|
p.fmt.prec, p.fmt.precPresent, i, fieldnum = intFromArg(a, end, i+1, fieldnum)
|
|
|
|
if !p.fmt.precPresent {
|
|
|
|
p.buf.Write(precBytes)
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
p.fmt.prec, p.fmt.precPresent, i = parsenum(format, i+1, end)
|
2011-07-21 00:46:51 -06:00
|
|
|
if !p.fmt.precPresent {
|
|
|
|
p.fmt.prec = 0
|
|
|
|
p.fmt.precPresent = true
|
|
|
|
}
|
2010-09-22 00:10:38 -06:00
|
|
|
}
|
2008-10-24 17:33:29 -06:00
|
|
|
}
|
2011-01-05 11:11:34 -07:00
|
|
|
if i >= end {
|
|
|
|
p.buf.Write(noVerbBytes)
|
|
|
|
continue
|
|
|
|
}
|
2011-01-05 12:42:35 -07:00
|
|
|
c, w := utf8.DecodeRuneInString(format[i:])
|
2009-12-15 16:27:16 -07:00
|
|
|
i += w
|
2008-10-24 17:33:29 -06:00
|
|
|
// percent is special - absorbs no operand
|
|
|
|
if c == '%' {
|
2010-08-16 16:34:40 -06:00
|
|
|
p.buf.WriteByte('%') // We ignore width and prec.
|
2009-12-15 16:27:16 -07:00
|
|
|
continue
|
2008-10-24 17:33:29 -06:00
|
|
|
}
|
2010-02-01 16:53:37 -07:00
|
|
|
if fieldnum >= len(a) { // out of operands
|
2009-12-15 16:27:16 -07:00
|
|
|
p.buf.WriteByte('%')
|
|
|
|
p.add(c)
|
|
|
|
p.buf.Write(missingBytes)
|
|
|
|
continue
|
2008-10-24 17:33:29 -06:00
|
|
|
}
|
2010-02-01 16:53:37 -07:00
|
|
|
field := a[fieldnum]
|
2009-12-15 16:27:16 -07:00
|
|
|
fieldnum++
|
2009-08-31 17:38:30 -06:00
|
|
|
|
2010-06-28 15:11:38 -06:00
|
|
|
goSyntax := c == 'v' && p.fmt.sharp
|
|
|
|
plus := c == 'v' && p.fmt.plus
|
|
|
|
p.printField(field, c, plus, goSyntax, 0)
|
2008-10-24 17:33:29 -06:00
|
|
|
}
|
2010-06-14 18:16:35 -06:00
|
|
|
|
2010-02-01 16:53:37 -07:00
|
|
|
if fieldnum < len(a) {
|
2009-12-15 16:27:16 -07:00
|
|
|
p.buf.Write(extraBytes)
|
2010-02-01 16:53:37 -07:00
|
|
|
for ; fieldnum < len(a); fieldnum++ {
|
|
|
|
field := a[fieldnum]
|
2010-05-13 13:49:48 -06:00
|
|
|
if field != nil {
|
2011-04-25 11:39:36 -06:00
|
|
|
p.buf.WriteString(reflect.TypeOf(field).String())
|
2010-05-13 13:49:48 -06:00
|
|
|
p.buf.WriteByte('=')
|
|
|
|
}
|
2010-06-14 18:16:35 -06:00
|
|
|
p.printField(field, 'v', false, false, 0)
|
2010-02-01 16:53:37 -07:00
|
|
|
if fieldnum+1 < len(a) {
|
2009-12-06 13:03:52 -07:00
|
|
|
p.buf.Write(commaSpaceBytes)
|
2008-11-06 11:40:57 -07:00
|
|
|
}
|
|
|
|
}
|
2009-12-15 16:27:16 -07:00
|
|
|
p.buf.WriteByte(')')
|
2008-11-06 11:40:57 -07:00
|
|
|
}
|
2008-10-24 17:33:29 -06:00
|
|
|
}
|
|
|
|
|
2010-06-14 18:16:35 -06:00
|
|
|
func (p *pp) doPrint(a []interface{}, addspace, addnewline bool) {
|
2010-07-29 11:50:09 -06:00
|
|
|
prevString := false
|
2010-02-01 16:53:37 -07:00
|
|
|
for fieldnum := 0; fieldnum < len(a); fieldnum++ {
|
2010-06-28 15:11:38 -06:00
|
|
|
p.fmt.clearflags()
|
2008-10-24 17:33:29 -06:00
|
|
|
// always add spaces if we're doing println
|
2010-02-01 16:53:37 -07:00
|
|
|
field := a[fieldnum]
|
printf as we know and love it.
Plus print[ln] with the ability to print struct values.
Note for language mavens: if a "..." function passes its argument
to another "..." function, the argument is not wrapped again. This
allows printf to call fprintf without extra manipulation. It's good
but needs to go in the spec.
This code works:
///
package main
import fmt "fmt"
import os "os"
type T struct { s string; a, b int }
func main() {
P := fmt.Printer();
P.printf("%s = %d with float value %.4f\n", "hi there", 7, 123.456);
P.println("hi there", 7, 123.456);
P.fprintf(os.Stdout, "%s = %d with float value %.4f\n", "hi there", 7, 123.456);
P.println(T{"x", 7, 234}, "end of struct", 8, 9);
}
R=rsc
DELTA=28 (7 added, 3 deleted, 18 changed)
OCL=18321
CL=18324
2008-11-02 13:33:02 -07:00
|
|
|
if fieldnum > 0 {
|
2011-04-25 11:39:36 -06:00
|
|
|
isString := field != nil && reflect.TypeOf(field).Kind() == reflect.String
|
2010-07-29 11:50:09 -06:00
|
|
|
if addspace || !isString && !prevString {
|
2009-12-06 13:03:52 -07:00
|
|
|
p.buf.WriteByte(' ')
|
2008-10-24 17:33:29 -06:00
|
|
|
}
|
|
|
|
}
|
2010-07-29 11:50:09 -06:00
|
|
|
prevString = p.printField(field, 'v', false, false, 0)
|
2008-10-24 17:33:29 -06:00
|
|
|
}
|
printf as we know and love it.
Plus print[ln] with the ability to print struct values.
Note for language mavens: if a "..." function passes its argument
to another "..." function, the argument is not wrapped again. This
allows printf to call fprintf without extra manipulation. It's good
but needs to go in the spec.
This code works:
///
package main
import fmt "fmt"
import os "os"
type T struct { s string; a, b int }
func main() {
P := fmt.Printer();
P.printf("%s = %d with float value %.4f\n", "hi there", 7, 123.456);
P.println("hi there", 7, 123.456);
P.fprintf(os.Stdout, "%s = %d with float value %.4f\n", "hi there", 7, 123.456);
P.println(T{"x", 7, 234}, "end of struct", 8, 9);
}
R=rsc
DELTA=28 (7 added, 3 deleted, 18 changed)
OCL=18321
CL=18324
2008-11-02 13:33:02 -07:00
|
|
|
if addnewline {
|
2009-12-06 13:03:52 -07:00
|
|
|
p.buf.WriteByte('\n')
|
2008-10-24 17:33:29 -06:00
|
|
|
}
|
|
|
|
}
|