line.go raw

   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