Source file src/cmd/internal/objabi/line.go

     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  	"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.
    18  func 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.
    36  func 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.
    67  func 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.
    84  func 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.)
   109  func 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  

View as plain text