1// Copyright 2020 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 5package main 6 7import ( 8 "path/filepath" 9 "strings" 10) 11 12// hasPathPrefix reports whether the slash-separated path s 13// begins with the elements in prefix. 14// Copied from cmd/go/internal/str.HasPathPrefix. 15func hasPathPrefix(s, prefix string) bool { 16 if len(s) == len(prefix) { 17 return s == prefix 18 } 19 if prefix == "" { 20 return true 21 } 22 if len(s) > len(prefix) { 23 if prefix[len(prefix)-1] == '/' || s[len(prefix)] == '/' { 24 return s[:len(prefix)] == prefix 25 } 26 } 27 return false 28} 29 30// hasFilePathPrefix reports whether the filesystem path s 31// begins with the elements in prefix. 32// Copied from cmd/go/internal/str.HasFilePathPrefix. 33func hasFilePathPrefix(s, prefix string) bool { 34 sv := strings.ToUpper(filepath.VolumeName(s)) 35 pv := strings.ToUpper(filepath.VolumeName(prefix)) 36 s = s[len(sv):] 37 prefix = prefix[len(pv):] 38 switch { 39 default: 40 return false 41 case pv != "" && sv != pv: 42 return false 43 case len(s) == len(prefix): 44 return s == prefix 45 case prefix == "": 46 return true 47 case len(s) > len(prefix): 48 if prefix[len(prefix)-1] == filepath.Separator { 49 return strings.HasPrefix(s, prefix) 50 } 51 return s[len(prefix)] == filepath.Separator && s[:len(prefix)] == prefix 52 } 53} 54 55// trimFilePathPrefix returns the given filesystem path s without the leading 56// prefix. 57func trimFilePathPrefix(s, prefix string) string { 58 sv := strings.ToUpper(filepath.VolumeName(s)) 59 pv := strings.ToUpper(filepath.VolumeName(prefix)) 60 s = s[len(sv):] 61 prefix = prefix[len(pv):] 62 63 if !hasFilePathPrefix(s, prefix) || len(prefix) == 0 { 64 return s 65 } 66 if len(s) == len(prefix) { 67 return "" 68 } 69 if prefix[len(prefix)-1] == filepath.Separator { 70 return strings.TrimPrefix(s, prefix) 71 } 72 return s[len(prefix)+1:] 73} 74 75// trimPathPrefix returns p without the leading prefix. Unlike 76// strings.TrimPrefix, the prefix will only match on slash-separted component 77// boundaries, so trimPathPrefix("aa/b", "aa") returns "b", but 78// trimPathPrefix("aa/b", "a") returns "aa/b". 79func trimPathPrefix(p, prefix string) string { 80 if prefix == "" { 81 return p 82 } 83 if prefix == p { 84 return "" 85 } 86 return strings.TrimPrefix(p, prefix+"/") 87} 88