1
1
package errors
2
2
3
3
import (
4
- "bytes"
5
4
"fmt"
6
5
"io"
7
6
"path"
@@ -11,6 +10,8 @@ import (
11
10
)
12
11
13
12
// Frame represents a program counter inside a stack frame.
13
+ // For historical reasons if Frame is interpreted as a uintptr
14
+ // its value represents the program counter + 1.
14
15
type Frame uintptr
15
16
16
17
// pc returns the program counter for this frame;
@@ -61,29 +62,24 @@ func (f Frame) name() string {
61
62
// GOPATH separated by \n\t (<funcname>\n\t<path>)
62
63
// %+v equivalent to %+s:%d
63
64
func (f Frame ) Format (s fmt.State , verb rune ) {
64
- f .format (s , s , verb )
65
- }
66
-
67
- // format allows stack trace printing calls to be made with a bytes.Buffer.
68
- func (f Frame ) format (w io.Writer , s fmt.State , verb rune ) {
69
65
switch verb {
70
66
case 's' :
71
67
switch {
72
68
case s .Flag ('+' ):
73
- io .WriteString (w , f .name ())
74
- io .WriteString (w , "\n \t " )
75
- io .WriteString (w , f .file ())
69
+ io .WriteString (s , f .name ())
70
+ io .WriteString (s , "\n \t " )
71
+ io .WriteString (s , f .file ())
76
72
default :
77
- io .WriteString (w , path .Base (f .file ()))
73
+ io .WriteString (s , path .Base (f .file ()))
78
74
}
79
75
case 'd' :
80
- io .WriteString (w , strconv .Itoa (f .line ()))
76
+ io .WriteString (s , strconv .Itoa (f .line ()))
81
77
case 'n' :
82
- io .WriteString (w , funcname (f .name ()))
78
+ io .WriteString (s , funcname (f .name ()))
83
79
case 'v' :
84
- f .format ( w , s , 's' )
85
- io .WriteString (w , ":" )
86
- f .format ( w , s , 'd' )
80
+ f .Format ( s , 's' )
81
+ io .WriteString (s , ":" )
82
+ f .Format ( s , 'd' )
87
83
}
88
84
}
89
85
@@ -99,50 +95,37 @@ type StackTrace []Frame
99
95
//
100
96
// %+v Prints filename, function, and line number for each Frame in the stack.
101
97
func (st StackTrace ) Format (s fmt.State , verb rune ) {
102
- var b bytes.Buffer
103
98
switch verb {
104
99
case 'v' :
105
100
switch {
106
101
case s .Flag ('+' ):
107
- b .Grow (len (st ) * stackMinLen )
108
102
for _ , f := range st {
109
- b . WriteByte ( '\n' )
110
- f .format ( & b , s , verb )
103
+ io . WriteString ( s , " \n " )
104
+ f .Format ( s , verb )
111
105
}
112
106
case s .Flag ('#' ):
113
- fmt .Fprintf (& b , "%#v" , []Frame (st ))
107
+ fmt .Fprintf (s , "%#v" , []Frame (st ))
114
108
default :
115
- st .formatSlice (& b , s , verb )
109
+ st .formatSlice (s , verb )
116
110
}
117
111
case 's' :
118
- st .formatSlice (& b , s , verb )
112
+ st .formatSlice (s , verb )
119
113
}
120
- io .Copy (s , & b )
121
114
}
122
115
123
116
// formatSlice will format this StackTrace into the given buffer as a slice of
124
117
// Frame, only valid when called with '%s' or '%v'.
125
- func (st StackTrace ) formatSlice (b * bytes.Buffer , s fmt.State , verb rune ) {
126
- b .WriteByte ('[' )
127
- if len (st ) == 0 {
128
- b .WriteByte (']' )
129
- return
130
- }
131
-
132
- b .Grow (len (st ) * (stackMinLen / 4 ))
133
- st [0 ].format (b , s , verb )
134
- for _ , fr := range st [1 :] {
135
- b .WriteByte (' ' )
136
- fr .format (b , s , verb )
118
+ func (st StackTrace ) formatSlice (s fmt.State , verb rune ) {
119
+ io .WriteString (s , "[" )
120
+ for i , f := range st {
121
+ if i > 0 {
122
+ io .WriteString (s , " " )
123
+ }
124
+ f .Format (s , verb )
137
125
}
138
- b . WriteByte ( ']' )
126
+ io . WriteString ( s , "]" )
139
127
}
140
128
141
- // stackMinLen is a best-guess at the minimum length of a stack trace. It
142
- // doesn't need to be exact, just give a good enough head start for the buffer
143
- // to avoid the expensive early growth.
144
- const stackMinLen = 96
145
-
146
129
// stack represents a stack of program counters.
147
130
type stack []uintptr
148
131
0 commit comments