github.com/searKing/golang/go@v1.2.117/path/path.go (about) 1 package path 2 3 import ( 4 "errors" 5 "path" 6 "strings" 7 ) 8 9 const ( 10 Separator = '/' // OS-specific path separator 11 ListSeparator = ':' // OS-specific path list separator 12 ) 13 14 // IsSeparator reports whether c is a directory separator character. 15 func IsSeparator(c uint8) bool { 16 return Separator == c 17 } 18 19 // Rel returns a relative path that is lexically equivalent to targpath when 20 // joined to basepath with an intervening separator. That is, 21 // Join(basepath, Rel(basepath, targpath)) is equivalent to targpath itself. 22 // On success, the returned path will always be relative to basepath, 23 // even if basepath and targpath share no elements. 24 // An error is returned if targpath can't be made relative to basepath or if 25 // knowing the current working directory would be necessary to compute it. 26 // Rel calls Clean on the result. 27 // Code borrowed from path/filpath/path.go 28 func Rel(basepath, targpath string) (string, error) { 29 base := path.Clean(basepath) 30 targ := path.Clean(targpath) 31 if targ == base { 32 return ".", nil 33 } 34 if base == "." { 35 base = "" 36 } 37 // Can't use IsAbs - `\a` and `a` are both relative in Windows. 38 baseSlashed := len(base) > 0 && base[0] == Separator 39 targSlashed := len(targ) > 0 && targ[0] == Separator 40 if baseSlashed != targSlashed { 41 return "", errors.New("Rel: can't make " + targpath + " relative to " + basepath) 42 } 43 // Position base[b0:bi] and targ[t0:ti] at the first differing elements. 44 bl := len(base) 45 tl := len(targ) 46 var b0, bi, t0, ti int 47 for { 48 for bi < bl && base[bi] != Separator { 49 bi++ 50 } 51 for ti < tl && targ[ti] != Separator { 52 ti++ 53 } 54 if !(targ[t0:ti] == base[b0:bi]) { 55 break 56 } 57 if bi < bl { 58 bi++ 59 } 60 if ti < tl { 61 ti++ 62 } 63 b0 = bi 64 t0 = ti 65 } 66 if base[b0:bi] == ".." { 67 return "", errors.New("Rel: can't make " + targpath + " relative to " + basepath) 68 } 69 if b0 != bl { 70 // Base elements left. Must go up before going down. 71 seps := strings.Count(base[b0:bl], string(Separator)) 72 size := 2 + seps*3 73 if tl != t0 { 74 size += 1 + tl - t0 75 } 76 buf := make([]byte, size) 77 n := copy(buf, "..") 78 for i := 0; i < seps; i++ { 79 buf[n] = Separator 80 copy(buf[n+1:], "..") 81 n += 3 82 } 83 if t0 != tl { 84 buf[n] = Separator 85 copy(buf[n+1:], targ[t0:]) 86 } 87 return string(buf), nil 88 } 89 return targ[t0:], nil 90 } 91 92 // ResolveReference resolves a path reference to a target base path from a base path. 93 // If path_ is not under frombasepath, then ResolveReference ignores frombasepath and return a path under tobasepath. 94 func ResolveReference(path_, frombasepath, tobasepath string) string { 95 relPath, err := Rel(frombasepath, path_) 96 if err != nil { 97 return path.Clean(path.Join(tobasepath, path_)) 98 } 99 return path.Clean(path.Join(tobasepath, relPath)) 100 }