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 }