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