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 }