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