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