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 }
115