...
1
2
3
4
5 package xerrors
6
7 import (
8 "fmt"
9 "strings"
10 "unicode"
11 "unicode/utf8"
12
13 "golang.org/x/xerrors/internal"
14 )
15
16 const percentBangString = "%!"
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39 func Errorf(format string, a ...interface{}) error {
40 format = formatPlusW(format)
41
42 wrap := strings.HasSuffix(format, ": %w")
43 idx, format2, ok := parsePercentW(format)
44 percentWElsewhere := !wrap && idx >= 0
45 if !percentWElsewhere && (wrap || strings.HasSuffix(format, ": %s") || strings.HasSuffix(format, ": %v")) {
46 err := errorAt(a, len(a)-1)
47 if err == nil {
48 return &noWrapError{fmt.Sprintf(format, a...), nil, Caller(1)}
49 }
50
51
52
53
54
55 msg := fmt.Sprintf(format[:len(format)-len(": %s")], a[:len(a)-1]...)
56 frame := Frame{}
57 if internal.EnableTrace {
58 frame = Caller(1)
59 }
60 if wrap {
61 return &wrapError{msg, err, frame}
62 }
63 return &noWrapError{msg, err, frame}
64 }
65
66
67 msg := fmt.Sprintf(format2, a...)
68 if idx < 0 {
69 return &noWrapError{msg, nil, Caller(1)}
70 }
71 err := errorAt(a, idx)
72 if !ok || err == nil {
73
74
75 return &noWrapError{fmt.Sprintf("%sw(%s)", percentBangString, msg), nil, Caller(1)}
76 }
77 frame := Frame{}
78 if internal.EnableTrace {
79 frame = Caller(1)
80 }
81 return &wrapError{msg, err, frame}
82 }
83
84 func errorAt(args []interface{}, i int) error {
85 if i < 0 || i >= len(args) {
86 return nil
87 }
88 err, ok := args[i].(error)
89 if !ok {
90 return nil
91 }
92 return err
93 }
94
95
96 func formatPlusW(s string) string {
97 return s
98 }
99
100
101
102
103
104 func parsePercentW(format string) (idx int, newFormat string, ok bool) {
105
106 idx = -1
107 ok = true
108 n := 0
109 sz := 0
110 var isW bool
111 for i := 0; i < len(format); i += sz {
112 if format[i] != '%' {
113 sz = 1
114 continue
115 }
116
117 if i+1 < len(format) && format[i+1] == '%' {
118 sz = 2
119 continue
120 }
121 sz, isW = parsePrintfVerb(format[i:])
122 if isW {
123 if idx >= 0 {
124 ok = false
125 } else {
126 idx = n
127 }
128
129 p := i + sz - 1
130 format = format[:p] + "v" + format[p+1:]
131 }
132 n++
133 }
134 return idx, format, ok
135 }
136
137
138
139 func parsePrintfVerb(s string) (int, bool) {
140
141 sz := 0
142 var r rune
143 for i := 1; i < len(s); i += sz {
144 r, sz = utf8.DecodeRuneInString(s[i:])
145 if unicode.IsLetter(r) {
146 return i + sz, r == 'w'
147 }
148 }
149 return len(s), false
150 }
151
152 type noWrapError struct {
153 msg string
154 err error
155 frame Frame
156 }
157
158 func (e *noWrapError) Error() string {
159 return fmt.Sprint(e)
160 }
161
162 func (e *noWrapError) Format(s fmt.State, v rune) { FormatError(e, s, v) }
163
164 func (e *noWrapError) FormatError(p Printer) (next error) {
165 p.Print(e.msg)
166 e.frame.Format(p)
167 return e.err
168 }
169
170 type wrapError struct {
171 msg string
172 err error
173 frame Frame
174 }
175
176 func (e *wrapError) Error() string {
177 return fmt.Sprint(e)
178 }
179
180 func (e *wrapError) Format(s fmt.State, v rune) { FormatError(e, s, v) }
181
182 func (e *wrapError) FormatError(p Printer) (next error) {
183 p.Print(e.msg)
184 e.frame.Format(p)
185 return e.err
186 }
187
188 func (e *wrapError) Unwrap() error {
189 return e.err
190 }
191
View as plain text