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  }