github.com/go-asm/go@v1.21.1-0.20240213172139-40c5ead50c48/cmd/objabi/line.go (about)

     1  // Copyright 2009 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package objabi
     6  
     7  import (
     8  	"os"
     9  	"path/filepath"
    10  	"runtime"
    11  	"strings"
    12  
    13  	"github.com/go-asm/go/buildcfg"
    14  )
    15  
    16  // WorkingDir returns the current working directory
    17  // (or "/???" if the directory cannot be identified),
    18  // with "/" as separator.
    19  func WorkingDir() string {
    20  	var path string
    21  	path, _ = os.Getwd()
    22  	if path == "" {
    23  		path = "/???"
    24  	}
    25  	return filepath.ToSlash(path)
    26  }
    27  
    28  // AbsFile returns the absolute filename for file in the given directory,
    29  // as rewritten by the rewrites argument.
    30  // For unrewritten paths, AbsFile rewrites a leading $GOROOT prefix to the literal "$GOROOT".
    31  // If the resulting path is the empty string, the result is "??".
    32  //
    33  // The rewrites argument is a ;-separated list of rewrites.
    34  // Each rewrite is of the form "prefix" or "prefix=>replace",
    35  // where prefix must match a leading sequence of path elements
    36  // and is either removed entirely or replaced by the replacement.
    37  func AbsFile(dir, file, rewrites string) string {
    38  	abs := file
    39  	if dir != "" && !filepath.IsAbs(file) {
    40  		abs = filepath.Join(dir, file)
    41  	}
    42  
    43  	abs, rewritten := ApplyRewrites(abs, rewrites)
    44  	if !rewritten && buildcfg.GOROOT != "" && hasPathPrefix(abs, buildcfg.GOROOT) {
    45  		abs = "$GOROOT" + abs[len(buildcfg.GOROOT):]
    46  	}
    47  
    48  	// Rewrite paths to match the slash convention of the target.
    49  	// This helps ensure that cross-compiled distributions remain
    50  	// bit-for-bit identical to natively compiled distributions.
    51  	if runtime.GOOS == "windows" {
    52  		abs = strings.ReplaceAll(abs, `\`, "/")
    53  	}
    54  
    55  	if abs == "" {
    56  		abs = "??"
    57  	}
    58  	return abs
    59  }
    60  
    61  // ApplyRewrites returns the filename for file in the given directory,
    62  // as rewritten by the rewrites argument.
    63  //
    64  // The rewrites argument is a ;-separated list of rewrites.
    65  // Each rewrite is of the form "prefix" or "prefix=>replace",
    66  // where prefix must match a leading sequence of path elements
    67  // and is either removed entirely or replaced by the replacement.
    68  func ApplyRewrites(file, rewrites string) (string, bool) {
    69  	start := 0
    70  	for i := 0; i <= len(rewrites); i++ {
    71  		if i == len(rewrites) || rewrites[i] == ';' {
    72  			if new, ok := applyRewrite(file, rewrites[start:i]); ok {
    73  				return new, true
    74  			}
    75  			start = i + 1
    76  		}
    77  	}
    78  
    79  	return file, false
    80  }
    81  
    82  // applyRewrite applies the rewrite to the path,
    83  // returning the rewritten path and a boolean
    84  // indicating whether the rewrite applied at all.
    85  func applyRewrite(path, rewrite string) (string, bool) {
    86  	prefix, replace := rewrite, ""
    87  	if j := strings.LastIndex(rewrite, "=>"); j >= 0 {
    88  		prefix, replace = rewrite[:j], rewrite[j+len("=>"):]
    89  	}
    90  
    91  	if prefix == "" || !hasPathPrefix(path, prefix) {
    92  		return path, false
    93  	}
    94  	if len(path) == len(prefix) {
    95  		return replace, true
    96  	}
    97  	if replace == "" {
    98  		return path[len(prefix)+1:], true
    99  	}
   100  	return replace + path[len(prefix):], true
   101  }
   102  
   103  // Does s have t as a path prefix?
   104  // That is, does s == t or does s begin with t followed by a slash?
   105  // For portability, we allow ASCII case folding, so that hasPathPrefix("a/b/c", "A/B") is true.
   106  // Similarly, we allow slash folding, so that hasPathPrefix("a/b/c", "a\\b") is true.
   107  // We do not allow full Unicode case folding, for fear of causing more confusion
   108  // or harm than good. (For an example of the kinds of things that can go wrong,
   109  // see http://article.gmane.org/gmane.linux.kernel/1853266.)
   110  func hasPathPrefix(s string, t string) bool {
   111  	if len(t) > len(s) {
   112  		return false
   113  	}
   114  	var i int
   115  	for i = 0; i < len(t); i++ {
   116  		cs := int(s[i])
   117  		ct := int(t[i])
   118  		if 'A' <= cs && cs <= 'Z' {
   119  			cs += 'a' - 'A'
   120  		}
   121  		if 'A' <= ct && ct <= 'Z' {
   122  			ct += 'a' - 'A'
   123  		}
   124  		if cs == '\\' {
   125  			cs = '/'
   126  		}
   127  		if ct == '\\' {
   128  			ct = '/'
   129  		}
   130  		if cs != ct {
   131  			return false
   132  		}
   133  	}
   134  	return i >= len(s) || s[i] == '/' || s[i] == '\\'
   135  }