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

View as plain text