tlog.app/go/loc@v0.6.2-0.20231112073106-b6382a0ac518/fmt.go (about) 1 package loc 2 3 import ( 4 "fmt" 5 "path" 6 "path/filepath" 7 ) 8 9 type ( 10 buf []byte 11 12 locFmtState struct { 13 buf 14 flags string 15 } 16 ) 17 18 var spaces = []byte(" ") //nolint:lll 19 20 // String formats PC as base_name.go:line. 21 // 22 // Works only in the same binary where Caller of FuncEntry was called. 23 // Or if PC.SetCache was called. 24 func (l PC) String() string { 25 _, file, line := l.NameFileLine() 26 file = filepath.Base(file) 27 28 b := append([]byte(file), ": "...) 29 30 i := len(file) 31 n := 1 + width(line) 32 33 b = b[:i+n] 34 35 for q, j := line, n-1; j >= 1; j-- { 36 b[i+j] = byte(q%10) + '0' 37 q /= 10 38 } 39 40 return string(b) 41 } 42 43 // Format is fmt.Formatter interface implementation. 44 func (l PC) Format(s fmt.State, c rune) { 45 switch c { 46 default: // v 47 l.formatV(s) 48 case 'n', 's': 49 l.formatName(s) 50 case 'f': 51 l.formatFile(s) 52 case 'd', 'l': 53 l.formatLine(s) 54 case 'x', 'X', 'p', 'P': 55 l.formatPC(s, c) 56 } 57 } 58 59 func (l PC) formatV(s fmt.State) { 60 name, file, line := l.NameFileLine() 61 62 if !s.Flag('+') { 63 file = filepath.Base(file) 64 name = path.Base(name) 65 } 66 67 if s.Flag('#') { 68 file = name 69 } 70 71 prec, ok := s.Precision() 72 if lw := width(line); !ok || lw > prec { 73 prec = lw 74 } 75 76 if prec > 20 { 77 prec = 20 78 } 79 80 width, ok := s.Width() 81 if !ok { 82 width = len(file) + 1 + prec 83 } 84 85 fwidth := width - 1 - prec 86 if fwidth < 0 { 87 fwidth = 0 88 } 89 90 var bufdata [128]byte 91 // buf := bufdata[:0] 92 buf := noescapeSlize(&bufdata[0], len(bufdata)) 93 94 buf = l.appendStr(buf, s, fwidth, file) 95 96 if fwidth+1+prec > width { 97 prec = width - fwidth - 1 98 } 99 100 buf = append(buf, ": "[:1+prec]...) 101 102 for q, j := line, prec; q != 0 && j >= 0; j-- { 103 buf[fwidth+j] = byte(q%10) + '0' 104 q /= 10 105 } 106 107 _, _ = s.Write(buf) 108 } 109 110 func (l PC) formatName(s fmt.State) { 111 name, _, _ := l.NameFileLine() 112 113 if !s.Flag('+') { 114 name = path.Base(name) 115 } 116 117 w, ok := s.Width() 118 if !ok { 119 w = len(name) 120 } 121 122 var bufdata [128]byte 123 buf := noescapeSlize(&bufdata[0], len(bufdata)) 124 125 buf = l.appendStr(buf, s, w, name) 126 127 _, _ = s.Write(buf) 128 } 129 130 func (l PC) formatFile(s fmt.State) { 131 _, file, _ := l.NameFileLine() 132 133 if !s.Flag('+') { 134 file = filepath.Base(file) 135 } 136 137 w, ok := s.Width() 138 if !ok { 139 w = len(file) 140 } 141 142 var bufdata [128]byte 143 buf := noescapeSlize(&bufdata[0], len(bufdata)) 144 145 buf = l.appendStr(buf, s, w, file) 146 147 _, _ = s.Write(buf) 148 } 149 150 func (l PC) appendStr(buf []byte, s fmt.State, w int, name string) []byte { 151 if w > len(name) { 152 if s.Flag('-') { 153 buf = append(buf, spaces[:w-len(name)]...) 154 } 155 156 buf = append(buf, name...) 157 158 if !s.Flag('-') { 159 buf = append(buf, spaces[:w-len(name)]...) 160 } 161 } else { 162 buf = append(buf, name[:w]...) 163 } 164 165 return buf 166 } 167 168 func (l PC) formatLine(s fmt.State) { 169 _, _, line := l.NameFileLine() 170 171 lineW := width(line) 172 173 w, ok := s.Width() 174 if !ok || w < lineW { 175 w = lineW 176 } 177 178 if w > 20 { 179 w = 20 180 } 181 182 var bufdata [32]byte 183 buf := noescapeSlize(&bufdata[0], len(bufdata)) 184 185 buf = append(buf, " "[:w]...) 186 187 j := w - 1 188 for q := line; q != 0 && j >= 0; j-- { 189 buf[j] = byte(q%10) + '0' 190 q /= 10 191 } 192 193 for j >= 1 && s.Flag('0') { 194 buf[j] = '0' 195 j-- 196 } 197 198 _, _ = s.Write(buf) 199 } 200 201 func (l PC) formatPC(s fmt.State, c rune) { 202 lineW := 1 203 for x := l >> 4; x != 0; x >>= 4 { 204 lineW++ 205 } 206 207 w, ok := s.Width() 208 if !ok || w < lineW { 209 w = lineW 210 } 211 212 w += len("0x") 213 214 if w > 20 { 215 w = 20 216 } 217 218 var bufdata [32]byte 219 buf := noescapeSlize(&bufdata[0], len(bufdata)) 220 221 buf = append(buf, " "[:w]...) 222 223 const ( 224 hexc = "0123456789abcdef" 225 hexC = "0123456789ABCDEF" 226 ) 227 228 hex := hexc 229 if c >= 'A' && c <= 'Z' { 230 hex = hexC 231 } 232 233 j := w - 1 234 for q := uint64(l); q != 0 && j >= 0; j-- { 235 buf[j] = hex[q&0xf] 236 q /= 16 237 } 238 239 for j > 1 && s.Flag('0') { 240 buf[j] = '0' 241 j-- 242 } 243 244 if j > 0 { 245 buf[j-1] = '0' 246 buf[j] = 'x' 247 } 248 249 _, _ = s.Write(buf) 250 } 251 252 func width(v int) (n int) { 253 n = 0 254 for v != 0 { 255 v /= 10 256 n++ 257 } 258 return 259 } 260 261 // String formats PCs as list of type_name (file.go:line) 262 // 263 // Works only in the same binary where Caller of FuncEntry was called. 264 // Or if PC.SetCache was called. 265 func (t PCs) String() string { 266 var b buf 267 268 for i, l := range t { 269 if i != 0 { 270 b = append(b, " at "...) 271 } 272 273 _, file, line := l.NameFileLine() 274 file = filepath.Base(file) 275 276 i := len(b) + len(file) 277 n := 1 + width(line) 278 279 b = append(b, file...) 280 b = append(b, ": "...) 281 282 b = b[:i+n] 283 284 for q, j := line, n-1; j >= 1; j-- { 285 b[i+j] = byte(q%10) + '0' 286 q /= 10 287 } 288 } 289 290 return string(b) 291 } 292 293 // FormatString formats PCs as list of type_name (file.go:line) 294 // 295 // Works only in the same binary where Caller of FuncEntry was called. 296 // Or if PC.SetCache was called. 297 func (t PCs) FormatString(flags string) string { 298 s := locFmtState{flags: flags} 299 300 t.Format(&s, 'v') 301 302 return string(s.buf) 303 } 304 305 func (t PCs) Format(s fmt.State, c rune) { 306 switch { 307 case s.Flag('+'): 308 for _, l := range t { 309 s.Write([]byte("at ")) 310 l.Format(s, c) 311 s.Write([]byte("\n")) 312 } 313 default: 314 for i, l := range t { 315 if i != 0 { 316 s.Write([]byte(" at ")) 317 } 318 l.Format(s, c) 319 } 320 } 321 } 322 323 func (s *locFmtState) Flag(c int) bool { 324 for _, f := range s.flags { 325 if f == rune(c) { 326 return true 327 } 328 } 329 330 return false 331 } 332 333 func (b *buf) Write(p []byte) (int, error) { 334 *b = append(*b, p...) 335 336 return len(p), nil 337 } 338 339 func (s *locFmtState) Width() (int, bool) { return 0, false } 340 func (s *locFmtState) Precision() (int, bool) { return 0, false }