Black Lives Matter. Support the Equal Justice Initiative.

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

Documentation: cmd/internal/objabi

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

View as plain text