|
Packit Service |
4d2de5 |
/*
|
|
Packit Service |
4d2de5 |
* Copyright (c) 2013-2016 Dave Collins <dave@davec.name>
|
|
Packit Service |
4d2de5 |
*
|
|
Packit Service |
4d2de5 |
* Permission to use, copy, modify, and distribute this software for any
|
|
Packit Service |
4d2de5 |
* purpose with or without fee is hereby granted, provided that the above
|
|
Packit Service |
4d2de5 |
* copyright notice and this permission notice appear in all copies.
|
|
Packit Service |
4d2de5 |
*
|
|
Packit Service |
4d2de5 |
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
Packit Service |
4d2de5 |
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
Packit Service |
4d2de5 |
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
Packit Service |
4d2de5 |
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
Packit Service |
4d2de5 |
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
Packit Service |
4d2de5 |
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
Packit Service |
4d2de5 |
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
Packit Service |
4d2de5 |
*/
|
|
Packit Service |
4d2de5 |
|
|
Packit Service |
4d2de5 |
package spew
|
|
Packit Service |
4d2de5 |
|
|
Packit Service |
4d2de5 |
import (
|
|
Packit Service |
4d2de5 |
"bytes"
|
|
Packit Service |
4d2de5 |
"encoding/hex"
|
|
Packit Service |
4d2de5 |
"fmt"
|
|
Packit Service |
4d2de5 |
"io"
|
|
Packit Service |
4d2de5 |
"os"
|
|
Packit Service |
4d2de5 |
"reflect"
|
|
Packit Service |
4d2de5 |
"regexp"
|
|
Packit Service |
4d2de5 |
"strconv"
|
|
Packit Service |
4d2de5 |
"strings"
|
|
Packit Service |
4d2de5 |
)
|
|
Packit Service |
4d2de5 |
|
|
Packit Service |
4d2de5 |
var (
|
|
Packit Service |
4d2de5 |
// uint8Type is a reflect.Type representing a uint8. It is used to
|
|
Packit Service |
4d2de5 |
// convert cgo types to uint8 slices for hexdumping.
|
|
Packit Service |
4d2de5 |
uint8Type = reflect.TypeOf(uint8(0))
|
|
Packit Service |
4d2de5 |
|
|
Packit Service |
4d2de5 |
// cCharRE is a regular expression that matches a cgo char.
|
|
Packit Service |
4d2de5 |
// It is used to detect character arrays to hexdump them.
|
|
Packit Service |
4d2de5 |
cCharRE = regexp.MustCompile("^.*\\._Ctype_char$")
|
|
Packit Service |
4d2de5 |
|
|
Packit Service |
4d2de5 |
// cUnsignedCharRE is a regular expression that matches a cgo unsigned
|
|
Packit Service |
4d2de5 |
// char. It is used to detect unsigned character arrays to hexdump
|
|
Packit Service |
4d2de5 |
// them.
|
|
Packit Service |
4d2de5 |
cUnsignedCharRE = regexp.MustCompile("^.*\\._Ctype_unsignedchar$")
|
|
Packit Service |
4d2de5 |
|
|
Packit Service |
4d2de5 |
// cUint8tCharRE is a regular expression that matches a cgo uint8_t.
|
|
Packit Service |
4d2de5 |
// It is used to detect uint8_t arrays to hexdump them.
|
|
Packit Service |
4d2de5 |
cUint8tCharRE = regexp.MustCompile("^.*\\._Ctype_uint8_t$")
|
|
Packit Service |
4d2de5 |
)
|
|
Packit Service |
4d2de5 |
|
|
Packit Service |
4d2de5 |
// dumpState contains information about the state of a dump operation.
|
|
Packit Service |
4d2de5 |
type dumpState struct {
|
|
Packit Service |
4d2de5 |
w io.Writer
|
|
Packit Service |
4d2de5 |
depth int
|
|
Packit Service |
4d2de5 |
pointers map[uintptr]int
|
|
Packit Service |
4d2de5 |
ignoreNextType bool
|
|
Packit Service |
4d2de5 |
ignoreNextIndent bool
|
|
Packit Service |
4d2de5 |
cs *ConfigState
|
|
Packit Service |
4d2de5 |
}
|
|
Packit Service |
4d2de5 |
|
|
Packit Service |
4d2de5 |
// indent performs indentation according to the depth level and cs.Indent
|
|
Packit Service |
4d2de5 |
// option.
|
|
Packit Service |
4d2de5 |
func (d *dumpState) indent() {
|
|
Packit Service |
4d2de5 |
if d.ignoreNextIndent {
|
|
Packit Service |
4d2de5 |
d.ignoreNextIndent = false
|
|
Packit Service |
4d2de5 |
return
|
|
Packit Service |
4d2de5 |
}
|
|
Packit Service |
4d2de5 |
d.w.Write(bytes.Repeat([]byte(d.cs.Indent), d.depth))
|
|
Packit Service |
4d2de5 |
}
|
|
Packit Service |
4d2de5 |
|
|
Packit Service |
4d2de5 |
// unpackValue returns values inside of non-nil interfaces when possible.
|
|
Packit Service |
4d2de5 |
// This is useful for data types like structs, arrays, slices, and maps which
|
|
Packit Service |
4d2de5 |
// can contain varying types packed inside an interface.
|
|
Packit Service |
4d2de5 |
func (d *dumpState) unpackValue(v reflect.Value) reflect.Value {
|
|
Packit Service |
4d2de5 |
if v.Kind() == reflect.Interface && !v.IsNil() {
|
|
Packit Service |
4d2de5 |
v = v.Elem()
|
|
Packit Service |
4d2de5 |
}
|
|
Packit Service |
4d2de5 |
return v
|
|
Packit Service |
4d2de5 |
}
|
|
Packit Service |
4d2de5 |
|
|
Packit Service |
4d2de5 |
// dumpPtr handles formatting of pointers by indirecting them as necessary.
|
|
Packit Service |
4d2de5 |
func (d *dumpState) dumpPtr(v reflect.Value) {
|
|
Packit Service |
4d2de5 |
// Remove pointers at or below the current depth from map used to detect
|
|
Packit Service |
4d2de5 |
// circular refs.
|
|
Packit Service |
4d2de5 |
for k, depth := range d.pointers {
|
|
Packit Service |
4d2de5 |
if depth >= d.depth {
|
|
Packit Service |
4d2de5 |
delete(d.pointers, k)
|
|
Packit Service |
4d2de5 |
}
|
|
Packit Service |
4d2de5 |
}
|
|
Packit Service |
4d2de5 |
|
|
Packit Service |
4d2de5 |
// Keep list of all dereferenced pointers to show later.
|
|
Packit Service |
4d2de5 |
pointerChain := make([]uintptr, 0)
|
|
Packit Service |
4d2de5 |
|
|
Packit Service |
4d2de5 |
// Figure out how many levels of indirection there are by dereferencing
|
|
Packit Service |
4d2de5 |
// pointers and unpacking interfaces down the chain while detecting circular
|
|
Packit Service |
4d2de5 |
// references.
|
|
Packit Service |
4d2de5 |
nilFound := false
|
|
Packit Service |
4d2de5 |
cycleFound := false
|
|
Packit Service |
4d2de5 |
indirects := 0
|
|
Packit Service |
4d2de5 |
ve := v
|
|
Packit Service |
4d2de5 |
for ve.Kind() == reflect.Ptr {
|
|
Packit Service |
4d2de5 |
if ve.IsNil() {
|
|
Packit Service |
4d2de5 |
nilFound = true
|
|
Packit Service |
4d2de5 |
break
|
|
Packit Service |
4d2de5 |
}
|
|
Packit Service |
4d2de5 |
indirects++
|
|
Packit Service |
4d2de5 |
addr := ve.Pointer()
|
|
Packit Service |
4d2de5 |
pointerChain = append(pointerChain, addr)
|
|
Packit Service |
4d2de5 |
if pd, ok := d.pointers[addr]; ok && pd < d.depth {
|
|
Packit Service |
4d2de5 |
cycleFound = true
|
|
Packit Service |
4d2de5 |
indirects--
|
|
Packit Service |
4d2de5 |
break
|
|
Packit Service |
4d2de5 |
}
|
|
Packit Service |
4d2de5 |
d.pointers[addr] = d.depth
|
|
Packit Service |
4d2de5 |
|
|
Packit Service |
4d2de5 |
ve = ve.Elem()
|
|
Packit Service |
4d2de5 |
if ve.Kind() == reflect.Interface {
|
|
Packit Service |
4d2de5 |
if ve.IsNil() {
|
|
Packit Service |
4d2de5 |
nilFound = true
|
|
Packit Service |
4d2de5 |
break
|
|
Packit Service |
4d2de5 |
}
|
|
Packit Service |
4d2de5 |
ve = ve.Elem()
|
|
Packit Service |
4d2de5 |
}
|
|
Packit Service |
4d2de5 |
}
|
|
Packit Service |
4d2de5 |
|
|
Packit Service |
4d2de5 |
// Display type information.
|
|
Packit Service |
4d2de5 |
d.w.Write(openParenBytes)
|
|
Packit Service |
4d2de5 |
d.w.Write(bytes.Repeat(asteriskBytes, indirects))
|
|
Packit Service |
4d2de5 |
d.w.Write([]byte(ve.Type().String()))
|
|
Packit Service |
4d2de5 |
d.w.Write(closeParenBytes)
|
|
Packit Service |
4d2de5 |
|
|
Packit Service |
4d2de5 |
// Display pointer information.
|
|
Packit Service |
4d2de5 |
if !d.cs.DisablePointerAddresses && len(pointerChain) > 0 {
|
|
Packit Service |
4d2de5 |
d.w.Write(openParenBytes)
|
|
Packit Service |
4d2de5 |
for i, addr := range pointerChain {
|
|
Packit Service |
4d2de5 |
if i > 0 {
|
|
Packit Service |
4d2de5 |
d.w.Write(pointerChainBytes)
|
|
Packit Service |
4d2de5 |
}
|
|
Packit Service |
4d2de5 |
printHexPtr(d.w, addr)
|
|
Packit Service |
4d2de5 |
}
|
|
Packit Service |
4d2de5 |
d.w.Write(closeParenBytes)
|
|
Packit Service |
4d2de5 |
}
|
|
Packit Service |
4d2de5 |
|
|
Packit Service |
4d2de5 |
// Display dereferenced value.
|
|
Packit Service |
4d2de5 |
d.w.Write(openParenBytes)
|
|
Packit Service |
4d2de5 |
switch {
|
|
Packit Service |
4d2de5 |
case nilFound == true:
|
|
Packit Service |
4d2de5 |
d.w.Write(nilAngleBytes)
|
|
Packit Service |
4d2de5 |
|
|
Packit Service |
4d2de5 |
case cycleFound == true:
|
|
Packit Service |
4d2de5 |
d.w.Write(circularBytes)
|
|
Packit Service |
4d2de5 |
|
|
Packit Service |
4d2de5 |
default:
|
|
Packit Service |
4d2de5 |
d.ignoreNextType = true
|
|
Packit Service |
4d2de5 |
d.dump(ve)
|
|
Packit Service |
4d2de5 |
}
|
|
Packit Service |
4d2de5 |
d.w.Write(closeParenBytes)
|
|
Packit Service |
4d2de5 |
}
|
|
Packit Service |
4d2de5 |
|
|
Packit Service |
4d2de5 |
// dumpSlice handles formatting of arrays and slices. Byte (uint8 under
|
|
Packit Service |
4d2de5 |
// reflection) arrays and slices are dumped in hexdump -C fashion.
|
|
Packit Service |
4d2de5 |
func (d *dumpState) dumpSlice(v reflect.Value) {
|
|
Packit Service |
4d2de5 |
// Determine whether this type should be hex dumped or not. Also,
|
|
Packit Service |
4d2de5 |
// for types which should be hexdumped, try to use the underlying data
|
|
Packit Service |
4d2de5 |
// first, then fall back to trying to convert them to a uint8 slice.
|
|
Packit Service |
4d2de5 |
var buf []uint8
|
|
Packit Service |
4d2de5 |
doConvert := false
|
|
Packit Service |
4d2de5 |
doHexDump := false
|
|
Packit Service |
4d2de5 |
numEntries := v.Len()
|
|
Packit Service |
4d2de5 |
if numEntries > 0 {
|
|
Packit Service |
4d2de5 |
vt := v.Index(0).Type()
|
|
Packit Service |
4d2de5 |
vts := vt.String()
|
|
Packit Service |
4d2de5 |
switch {
|
|
Packit Service |
4d2de5 |
// C types that need to be converted.
|
|
Packit Service |
4d2de5 |
case cCharRE.MatchString(vts):
|
|
Packit Service |
4d2de5 |
fallthrough
|
|
Packit Service |
4d2de5 |
case cUnsignedCharRE.MatchString(vts):
|
|
Packit Service |
4d2de5 |
fallthrough
|
|
Packit Service |
4d2de5 |
case cUint8tCharRE.MatchString(vts):
|
|
Packit Service |
4d2de5 |
doConvert = true
|
|
Packit Service |
4d2de5 |
|
|
Packit Service |
4d2de5 |
// Try to use existing uint8 slices and fall back to converting
|
|
Packit Service |
4d2de5 |
// and copying if that fails.
|
|
Packit Service |
4d2de5 |
case vt.Kind() == reflect.Uint8:
|
|
Packit Service |
4d2de5 |
// We need an addressable interface to convert the type
|
|
Packit Service |
4d2de5 |
// to a byte slice. However, the reflect package won't
|
|
Packit Service |
4d2de5 |
// give us an interface on certain things like
|
|
Packit Service |
4d2de5 |
// unexported struct fields in order to enforce
|
|
Packit Service |
4d2de5 |
// visibility rules. We use unsafe, when available, to
|
|
Packit Service |
4d2de5 |
// bypass these restrictions since this package does not
|
|
Packit Service |
4d2de5 |
// mutate the values.
|
|
Packit Service |
4d2de5 |
vs := v
|
|
Packit Service |
4d2de5 |
if !vs.CanInterface() || !vs.CanAddr() {
|
|
Packit Service |
4d2de5 |
vs = unsafeReflectValue(vs)
|
|
Packit Service |
4d2de5 |
}
|
|
Packit Service |
4d2de5 |
if !UnsafeDisabled {
|
|
Packit Service |
4d2de5 |
vs = vs.Slice(0, numEntries)
|
|
Packit Service |
4d2de5 |
|
|
Packit Service |
4d2de5 |
// Use the existing uint8 slice if it can be
|
|
Packit Service |
4d2de5 |
// type asserted.
|
|
Packit Service |
4d2de5 |
iface := vs.Interface()
|
|
Packit Service |
4d2de5 |
if slice, ok := iface.([]uint8); ok {
|
|
Packit Service |
4d2de5 |
buf = slice
|
|
Packit Service |
4d2de5 |
doHexDump = true
|
|
Packit Service |
4d2de5 |
break
|
|
Packit Service |
4d2de5 |
}
|
|
Packit Service |
4d2de5 |
}
|
|
Packit Service |
4d2de5 |
|
|
Packit Service |
4d2de5 |
// The underlying data needs to be converted if it can't
|
|
Packit Service |
4d2de5 |
// be type asserted to a uint8 slice.
|
|
Packit Service |
4d2de5 |
doConvert = true
|
|
Packit Service |
4d2de5 |
}
|
|
Packit Service |
4d2de5 |
|
|
Packit Service |
4d2de5 |
// Copy and convert the underlying type if needed.
|
|
Packit Service |
4d2de5 |
if doConvert && vt.ConvertibleTo(uint8Type) {
|
|
Packit Service |
4d2de5 |
// Convert and copy each element into a uint8 byte
|
|
Packit Service |
4d2de5 |
// slice.
|
|
Packit Service |
4d2de5 |
buf = make([]uint8, numEntries)
|
|
Packit Service |
4d2de5 |
for i := 0; i < numEntries; i++ {
|
|
Packit Service |
4d2de5 |
vv := v.Index(i)
|
|
Packit Service |
4d2de5 |
buf[i] = uint8(vv.Convert(uint8Type).Uint())
|
|
Packit Service |
4d2de5 |
}
|
|
Packit Service |
4d2de5 |
doHexDump = true
|
|
Packit Service |
4d2de5 |
}
|
|
Packit Service |
4d2de5 |
}
|
|
Packit Service |
4d2de5 |
|
|
Packit Service |
4d2de5 |
// Hexdump the entire slice as needed.
|
|
Packit Service |
4d2de5 |
if doHexDump {
|
|
Packit Service |
4d2de5 |
indent := strings.Repeat(d.cs.Indent, d.depth)
|
|
Packit Service |
4d2de5 |
str := indent + hex.Dump(buf)
|
|
Packit Service |
4d2de5 |
str = strings.Replace(str, "\n", "\n"+indent, -1)
|
|
Packit Service |
4d2de5 |
str = strings.TrimRight(str, d.cs.Indent)
|
|
Packit Service |
4d2de5 |
d.w.Write([]byte(str))
|
|
Packit Service |
4d2de5 |
return
|
|
Packit Service |
4d2de5 |
}
|
|
Packit Service |
4d2de5 |
|
|
Packit Service |
4d2de5 |
// Recursively call dump for each item.
|
|
Packit Service |
4d2de5 |
for i := 0; i < numEntries; i++ {
|
|
Packit Service |
4d2de5 |
d.dump(d.unpackValue(v.Index(i)))
|
|
Packit Service |
4d2de5 |
if i < (numEntries - 1) {
|
|
Packit Service |
4d2de5 |
d.w.Write(commaNewlineBytes)
|
|
Packit Service |
4d2de5 |
} else {
|
|
Packit Service |
4d2de5 |
d.w.Write(newlineBytes)
|
|
Packit Service |
4d2de5 |
}
|
|
Packit Service |
4d2de5 |
}
|
|
Packit Service |
4d2de5 |
}
|
|
Packit Service |
4d2de5 |
|
|
Packit Service |
4d2de5 |
// dump is the main workhorse for dumping a value. It uses the passed reflect
|
|
Packit Service |
4d2de5 |
// value to figure out what kind of object we are dealing with and formats it
|
|
Packit Service |
4d2de5 |
// appropriately. It is a recursive function, however circular data structures
|
|
Packit Service |
4d2de5 |
// are detected and handled properly.
|
|
Packit Service |
4d2de5 |
func (d *dumpState) dump(v reflect.Value) {
|
|
Packit Service |
4d2de5 |
// Handle invalid reflect values immediately.
|
|
Packit Service |
4d2de5 |
kind := v.Kind()
|
|
Packit Service |
4d2de5 |
if kind == reflect.Invalid {
|
|
Packit Service |
4d2de5 |
d.w.Write(invalidAngleBytes)
|
|
Packit Service |
4d2de5 |
return
|
|
Packit Service |
4d2de5 |
}
|
|
Packit Service |
4d2de5 |
|
|
Packit Service |
4d2de5 |
// Handle pointers specially.
|
|
Packit Service |
4d2de5 |
if kind == reflect.Ptr {
|
|
Packit Service |
4d2de5 |
d.indent()
|
|
Packit Service |
4d2de5 |
d.dumpPtr(v)
|
|
Packit Service |
4d2de5 |
return
|
|
Packit Service |
4d2de5 |
}
|
|
Packit Service |
4d2de5 |
|
|
Packit Service |
4d2de5 |
// Print type information unless already handled elsewhere.
|
|
Packit Service |
4d2de5 |
if !d.ignoreNextType {
|
|
Packit Service |
4d2de5 |
d.indent()
|
|
Packit Service |
4d2de5 |
d.w.Write(openParenBytes)
|
|
Packit Service |
4d2de5 |
d.w.Write([]byte(v.Type().String()))
|
|
Packit Service |
4d2de5 |
d.w.Write(closeParenBytes)
|
|
Packit Service |
4d2de5 |
d.w.Write(spaceBytes)
|
|
Packit Service |
4d2de5 |
}
|
|
Packit Service |
4d2de5 |
d.ignoreNextType = false
|
|
Packit Service |
4d2de5 |
|
|
Packit Service |
4d2de5 |
// Display length and capacity if the built-in len and cap functions
|
|
Packit Service |
4d2de5 |
// work with the value's kind and the len/cap itself is non-zero.
|
|
Packit Service |
4d2de5 |
valueLen, valueCap := 0, 0
|
|
Packit Service |
4d2de5 |
switch v.Kind() {
|
|
Packit Service |
4d2de5 |
case reflect.Array, reflect.Slice, reflect.Chan:
|
|
Packit Service |
4d2de5 |
valueLen, valueCap = v.Len(), v.Cap()
|
|
Packit Service |
4d2de5 |
case reflect.Map, reflect.String:
|
|
Packit Service |
4d2de5 |
valueLen = v.Len()
|
|
Packit Service |
4d2de5 |
}
|
|
Packit Service |
4d2de5 |
if valueLen != 0 || !d.cs.DisableCapacities && valueCap != 0 {
|
|
Packit Service |
4d2de5 |
d.w.Write(openParenBytes)
|
|
Packit Service |
4d2de5 |
if valueLen != 0 {
|
|
Packit Service |
4d2de5 |
d.w.Write(lenEqualsBytes)
|
|
Packit Service |
4d2de5 |
printInt(d.w, int64(valueLen), 10)
|
|
Packit Service |
4d2de5 |
}
|
|
Packit Service |
4d2de5 |
if !d.cs.DisableCapacities && valueCap != 0 {
|
|
Packit Service |
4d2de5 |
if valueLen != 0 {
|
|
Packit Service |
4d2de5 |
d.w.Write(spaceBytes)
|
|
Packit Service |
4d2de5 |
}
|
|
Packit Service |
4d2de5 |
d.w.Write(capEqualsBytes)
|
|
Packit Service |
4d2de5 |
printInt(d.w, int64(valueCap), 10)
|
|
Packit Service |
4d2de5 |
}
|
|
Packit Service |
4d2de5 |
d.w.Write(closeParenBytes)
|
|
Packit Service |
4d2de5 |
d.w.Write(spaceBytes)
|
|
Packit Service |
4d2de5 |
}
|
|
Packit Service |
4d2de5 |
|
|
Packit Service |
4d2de5 |
// Call Stringer/error interfaces if they exist and the handle methods flag
|
|
Packit Service |
4d2de5 |
// is enabled
|
|
Packit Service |
4d2de5 |
if !d.cs.DisableMethods {
|
|
Packit Service |
4d2de5 |
if (kind != reflect.Invalid) && (kind != reflect.Interface) {
|
|
Packit Service |
4d2de5 |
if handled := handleMethods(d.cs, d.w, v); handled {
|
|
Packit Service |
4d2de5 |
return
|
|
Packit Service |
4d2de5 |
}
|
|
Packit Service |
4d2de5 |
}
|
|
Packit Service |
4d2de5 |
}
|
|
Packit Service |
4d2de5 |
|
|
Packit Service |
4d2de5 |
switch kind {
|
|
Packit Service |
4d2de5 |
case reflect.Invalid:
|
|
Packit Service |
4d2de5 |
// Do nothing. We should never get here since invalid has already
|
|
Packit Service |
4d2de5 |
// been handled above.
|
|
Packit Service |
4d2de5 |
|
|
Packit Service |
4d2de5 |
case reflect.Bool:
|
|
Packit Service |
4d2de5 |
printBool(d.w, v.Bool())
|
|
Packit Service |
4d2de5 |
|
|
Packit Service |
4d2de5 |
case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int:
|
|
Packit Service |
4d2de5 |
printInt(d.w, v.Int(), 10)
|
|
Packit Service |
4d2de5 |
|
|
Packit Service |
4d2de5 |
case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
|
|
Packit Service |
4d2de5 |
printUint(d.w, v.Uint(), 10)
|
|
Packit Service |
4d2de5 |
|
|
Packit Service |
4d2de5 |
case reflect.Float32:
|
|
Packit Service |
4d2de5 |
printFloat(d.w, v.Float(), 32)
|
|
Packit Service |
4d2de5 |
|
|
Packit Service |
4d2de5 |
case reflect.Float64:
|
|
Packit Service |
4d2de5 |
printFloat(d.w, v.Float(), 64)
|
|
Packit Service |
4d2de5 |
|
|
Packit Service |
4d2de5 |
case reflect.Complex64:
|
|
Packit Service |
4d2de5 |
printComplex(d.w, v.Complex(), 32)
|
|
Packit Service |
4d2de5 |
|
|
Packit Service |
4d2de5 |
case reflect.Complex128:
|
|
Packit Service |
4d2de5 |
printComplex(d.w, v.Complex(), 64)
|
|
Packit Service |
4d2de5 |
|
|
Packit Service |
4d2de5 |
case reflect.Slice:
|
|
Packit Service |
4d2de5 |
if v.IsNil() {
|
|
Packit Service |
4d2de5 |
d.w.Write(nilAngleBytes)
|
|
Packit Service |
4d2de5 |
break
|
|
Packit Service |
4d2de5 |
}
|
|
Packit Service |
4d2de5 |
fallthrough
|
|
Packit Service |
4d2de5 |
|
|
Packit Service |
4d2de5 |
case reflect.Array:
|
|
Packit Service |
4d2de5 |
d.w.Write(openBraceNewlineBytes)
|
|
Packit Service |
4d2de5 |
d.depth++
|
|
Packit Service |
4d2de5 |
if (d.cs.MaxDepth != 0) && (d.depth > d.cs.MaxDepth) {
|
|
Packit Service |
4d2de5 |
d.indent()
|
|
Packit Service |
4d2de5 |
d.w.Write(maxNewlineBytes)
|
|
Packit Service |
4d2de5 |
} else {
|
|
Packit Service |
4d2de5 |
d.dumpSlice(v)
|
|
Packit Service |
4d2de5 |
}
|
|
Packit Service |
4d2de5 |
d.depth--
|
|
Packit Service |
4d2de5 |
d.indent()
|
|
Packit Service |
4d2de5 |
d.w.Write(closeBraceBytes)
|
|
Packit Service |
4d2de5 |
|
|
Packit Service |
4d2de5 |
case reflect.String:
|
|
Packit Service |
4d2de5 |
d.w.Write([]byte(strconv.Quote(v.String())))
|
|
Packit Service |
4d2de5 |
|
|
Packit Service |
4d2de5 |
case reflect.Interface:
|
|
Packit Service |
4d2de5 |
// The only time we should get here is for nil interfaces due to
|
|
Packit Service |
4d2de5 |
// unpackValue calls.
|
|
Packit Service |
4d2de5 |
if v.IsNil() {
|
|
Packit Service |
4d2de5 |
d.w.Write(nilAngleBytes)
|
|
Packit Service |
4d2de5 |
}
|
|
Packit Service |
4d2de5 |
|
|
Packit Service |
4d2de5 |
case reflect.Ptr:
|
|
Packit Service |
4d2de5 |
// Do nothing. We should never get here since pointers have already
|
|
Packit Service |
4d2de5 |
// been handled above.
|
|
Packit Service |
4d2de5 |
|
|
Packit Service |
4d2de5 |
case reflect.Map:
|
|
Packit Service |
4d2de5 |
// nil maps should be indicated as different than empty maps
|
|
Packit Service |
4d2de5 |
if v.IsNil() {
|
|
Packit Service |
4d2de5 |
d.w.Write(nilAngleBytes)
|
|
Packit Service |
4d2de5 |
break
|
|
Packit Service |
4d2de5 |
}
|
|
Packit Service |
4d2de5 |
|
|
Packit Service |
4d2de5 |
d.w.Write(openBraceNewlineBytes)
|
|
Packit Service |
4d2de5 |
d.depth++
|
|
Packit Service |
4d2de5 |
if (d.cs.MaxDepth != 0) && (d.depth > d.cs.MaxDepth) {
|
|
Packit Service |
4d2de5 |
d.indent()
|
|
Packit Service |
4d2de5 |
d.w.Write(maxNewlineBytes)
|
|
Packit Service |
4d2de5 |
} else {
|
|
Packit Service |
4d2de5 |
numEntries := v.Len()
|
|
Packit Service |
4d2de5 |
keys := v.MapKeys()
|
|
Packit Service |
4d2de5 |
if d.cs.SortKeys {
|
|
Packit Service |
4d2de5 |
sortValues(keys, d.cs)
|
|
Packit Service |
4d2de5 |
}
|
|
Packit Service |
4d2de5 |
for i, key := range keys {
|
|
Packit Service |
4d2de5 |
d.dump(d.unpackValue(key))
|
|
Packit Service |
4d2de5 |
d.w.Write(colonSpaceBytes)
|
|
Packit Service |
4d2de5 |
d.ignoreNextIndent = true
|
|
Packit Service |
4d2de5 |
d.dump(d.unpackValue(v.MapIndex(key)))
|
|
Packit Service |
4d2de5 |
if i < (numEntries - 1) {
|
|
Packit Service |
4d2de5 |
d.w.Write(commaNewlineBytes)
|
|
Packit Service |
4d2de5 |
} else {
|
|
Packit Service |
4d2de5 |
d.w.Write(newlineBytes)
|
|
Packit Service |
4d2de5 |
}
|
|
Packit Service |
4d2de5 |
}
|
|
Packit Service |
4d2de5 |
}
|
|
Packit Service |
4d2de5 |
d.depth--
|
|
Packit Service |
4d2de5 |
d.indent()
|
|
Packit Service |
4d2de5 |
d.w.Write(closeBraceBytes)
|
|
Packit Service |
4d2de5 |
|
|
Packit Service |
4d2de5 |
case reflect.Struct:
|
|
Packit Service |
4d2de5 |
d.w.Write(openBraceNewlineBytes)
|
|
Packit Service |
4d2de5 |
d.depth++
|
|
Packit Service |
4d2de5 |
if (d.cs.MaxDepth != 0) && (d.depth > d.cs.MaxDepth) {
|
|
Packit Service |
4d2de5 |
d.indent()
|
|
Packit Service |
4d2de5 |
d.w.Write(maxNewlineBytes)
|
|
Packit Service |
4d2de5 |
} else {
|
|
Packit Service |
4d2de5 |
vt := v.Type()
|
|
Packit Service |
4d2de5 |
numFields := v.NumField()
|
|
Packit Service |
4d2de5 |
for i := 0; i < numFields; i++ {
|
|
Packit Service |
4d2de5 |
d.indent()
|
|
Packit Service |
4d2de5 |
vtf := vt.Field(i)
|
|
Packit Service |
4d2de5 |
d.w.Write([]byte(vtf.Name))
|
|
Packit Service |
4d2de5 |
d.w.Write(colonSpaceBytes)
|
|
Packit Service |
4d2de5 |
d.ignoreNextIndent = true
|
|
Packit Service |
4d2de5 |
d.dump(d.unpackValue(v.Field(i)))
|
|
Packit Service |
4d2de5 |
if i < (numFields - 1) {
|
|
Packit Service |
4d2de5 |
d.w.Write(commaNewlineBytes)
|
|
Packit Service |
4d2de5 |
} else {
|
|
Packit Service |
4d2de5 |
d.w.Write(newlineBytes)
|
|
Packit Service |
4d2de5 |
}
|
|
Packit Service |
4d2de5 |
}
|
|
Packit Service |
4d2de5 |
}
|
|
Packit Service |
4d2de5 |
d.depth--
|
|
Packit Service |
4d2de5 |
d.indent()
|
|
Packit Service |
4d2de5 |
d.w.Write(closeBraceBytes)
|
|
Packit Service |
4d2de5 |
|
|
Packit Service |
4d2de5 |
case reflect.Uintptr:
|
|
Packit Service |
4d2de5 |
printHexPtr(d.w, uintptr(v.Uint()))
|
|
Packit Service |
4d2de5 |
|
|
Packit Service |
4d2de5 |
case reflect.UnsafePointer, reflect.Chan, reflect.Func:
|
|
Packit Service |
4d2de5 |
printHexPtr(d.w, v.Pointer())
|
|
Packit Service |
4d2de5 |
|
|
Packit Service |
4d2de5 |
// There were not any other types at the time this code was written, but
|
|
Packit Service |
4d2de5 |
// fall back to letting the default fmt package handle it in case any new
|
|
Packit Service |
4d2de5 |
// types are added.
|
|
Packit Service |
4d2de5 |
default:
|
|
Packit Service |
4d2de5 |
if v.CanInterface() {
|
|
Packit Service |
4d2de5 |
fmt.Fprintf(d.w, "%v", v.Interface())
|
|
Packit Service |
4d2de5 |
} else {
|
|
Packit Service |
4d2de5 |
fmt.Fprintf(d.w, "%v", v.String())
|
|
Packit Service |
4d2de5 |
}
|
|
Packit Service |
4d2de5 |
}
|
|
Packit Service |
4d2de5 |
}
|
|
Packit Service |
4d2de5 |
|
|
Packit Service |
4d2de5 |
// fdump is a helper function to consolidate the logic from the various public
|
|
Packit Service |
4d2de5 |
// methods which take varying writers and config states.
|
|
Packit Service |
4d2de5 |
func fdump(cs *ConfigState, w io.Writer, a ...interface{}) {
|
|
Packit Service |
4d2de5 |
for _, arg := range a {
|
|
Packit Service |
4d2de5 |
if arg == nil {
|
|
Packit Service |
4d2de5 |
w.Write(interfaceBytes)
|
|
Packit Service |
4d2de5 |
w.Write(spaceBytes)
|
|
Packit Service |
4d2de5 |
w.Write(nilAngleBytes)
|
|
Packit Service |
4d2de5 |
w.Write(newlineBytes)
|
|
Packit Service |
4d2de5 |
continue
|
|
Packit Service |
4d2de5 |
}
|
|
Packit Service |
4d2de5 |
|
|
Packit Service |
4d2de5 |
d := dumpState{w: w, cs: cs}
|
|
Packit Service |
4d2de5 |
d.pointers = make(map[uintptr]int)
|
|
Packit Service |
4d2de5 |
d.dump(reflect.ValueOf(arg))
|
|
Packit Service |
4d2de5 |
d.w.Write(newlineBytes)
|
|
Packit Service |
4d2de5 |
}
|
|
Packit Service |
4d2de5 |
}
|
|
Packit Service |
4d2de5 |
|
|
Packit Service |
4d2de5 |
// Fdump formats and displays the passed arguments to io.Writer w. It formats
|
|
Packit Service |
4d2de5 |
// exactly the same as Dump.
|
|
Packit Service |
4d2de5 |
func Fdump(w io.Writer, a ...interface{}) {
|
|
Packit Service |
4d2de5 |
fdump(&Config, w, a...)
|
|
Packit Service |
4d2de5 |
}
|
|
Packit Service |
4d2de5 |
|
|
Packit Service |
4d2de5 |
// Sdump returns a string with the passed arguments formatted exactly the same
|
|
Packit Service |
4d2de5 |
// as Dump.
|
|
Packit Service |
4d2de5 |
func Sdump(a ...interface{}) string {
|
|
Packit Service |
4d2de5 |
var buf bytes.Buffer
|
|
Packit Service |
4d2de5 |
fdump(&Config, &buf, a...)
|
|
Packit Service |
4d2de5 |
return buf.String()
|
|
Packit Service |
4d2de5 |
}
|
|
Packit Service |
4d2de5 |
|
|
Packit Service |
4d2de5 |
/*
|
|
Packit Service |
4d2de5 |
Dump displays the passed parameters to standard out with newlines, customizable
|
|
Packit Service |
4d2de5 |
indentation, and additional debug information such as complete types and all
|
|
Packit Service |
4d2de5 |
pointer addresses used to indirect to the final value. It provides the
|
|
Packit Service |
4d2de5 |
following features over the built-in printing facilities provided by the fmt
|
|
Packit Service |
4d2de5 |
package:
|
|
Packit Service |
4d2de5 |
|
|
Packit Service |
4d2de5 |
* Pointers are dereferenced and followed
|
|
Packit Service |
4d2de5 |
* Circular data structures are detected and handled properly
|
|
Packit Service |
4d2de5 |
* Custom Stringer/error interfaces are optionally invoked, including
|
|
Packit Service |
4d2de5 |
on unexported types
|
|
Packit Service |
4d2de5 |
* Custom types which only implement the Stringer/error interfaces via
|
|
Packit Service |
4d2de5 |
a pointer receiver are optionally invoked when passing non-pointer
|
|
Packit Service |
4d2de5 |
variables
|
|
Packit Service |
4d2de5 |
* Byte arrays and slices are dumped like the hexdump -C command which
|
|
Packit Service |
4d2de5 |
includes offsets, byte values in hex, and ASCII output
|
|
Packit Service |
4d2de5 |
|
|
Packit Service |
4d2de5 |
The configuration options are controlled by an exported package global,
|
|
Packit Service |
4d2de5 |
spew.Config. See ConfigState for options documentation.
|
|
Packit Service |
4d2de5 |
|
|
Packit Service |
4d2de5 |
See Fdump if you would prefer dumping to an arbitrary io.Writer or Sdump to
|
|
Packit Service |
4d2de5 |
get the formatted result as a string.
|
|
Packit Service |
4d2de5 |
*/
|
|
Packit Service |
4d2de5 |
func Dump(a ...interface{}) {
|
|
Packit Service |
4d2de5 |
fdump(&Config, os.Stdout, a...)
|
|
Packit Service |
4d2de5 |
}
|