// and retrieving the final string. It does not allocate a buffer
// to hold the output until that output diverges from s.
type lazybuf struct {
- s string
- buf []byte
- w int
+ path string
+ buf []byte
+ w int
+ volAndPath string
+ volLen int
}
func (b *lazybuf) index(i int) byte {
if b.buf != nil {
return b.buf[i]
}
- return b.s[i]
+ return b.path[i]
}
func (b *lazybuf) append(c byte) {
if b.buf == nil {
- if b.w < len(b.s) && b.s[b.w] == c {
+ if b.w < len(b.path) && b.path[b.w] == c {
b.w++
return
}
- b.buf = make([]byte, len(b.s))
- copy(b.buf, b.s[:b.w])
+ b.buf = make([]byte, len(b.path))
+ copy(b.buf, b.path[:b.w])
}
b.buf[b.w] = c
b.w++
func (b *lazybuf) string() string {
if b.buf == nil {
- return b.s[:b.w]
+ return b.volAndPath[:b.volLen+b.w]
}
- return string(b.buf[:b.w])
+ return b.volAndPath[:b.volLen] + string(b.buf[:b.w])
}
const (
// Getting Dot-Dot Right,''
// http://plan9.bell-labs.com/sys/doc/lexnames.html
func Clean(path string) string {
- vol := VolumeName(path)
- path = path[len(vol):]
+ originalPath := path
+ volLen := volumeNameLen(path)
+ path = path[volLen:]
if path == "" {
- if len(vol) > 1 && vol[1] != ':' {
+ if volLen > 1 && originalPath[1] != ':' {
// should be UNC
- return FromSlash(vol)
+ return FromSlash(originalPath)
}
- return vol + "."
+ return originalPath + "."
}
rooted := os.IsPathSeparator(path[0])
// dotdot is index in buf where .. must stop, either because
// it is the leading slash or it is a leading ../../.. prefix.
n := len(path)
- out := lazybuf{s: path}
+ out := lazybuf{path: path, volAndPath: originalPath, volLen: volLen}
r, dotdot := 0, 0
if rooted {
out.append(Separator)
out.append('.')
}
- return FromSlash(vol + out.string())
+ return FromSlash(out.string())
}
// ToSlash returns the result of replacing each separator character
}
return vol + dir
}
+
+// VolumeName returns leading volume name.
+// Given "C:\foo\bar" it returns "C:" under windows.
+// Given "\\host\share\foo" it returns "\\host\share".
+// On other platforms it returns "".
+func VolumeName(path string) (v string) {
+ return path[:volumeNameLen(path)]
+}
return strings.HasPrefix(path, "/") || strings.HasPrefix(path, "#")
}
-// VolumeName returns the leading volume name on Windows.
-// It returns "" elsewhere.
-func VolumeName(path string) string {
- return ""
+// volumeNameLen returns length of the leading volume name on Windows.
+// It returns 0 elsewhere.
+func volumeNameLen(path string) int {
+ return 0
}
// HasPrefix exists for historical compatibility and should not be used.
return strings.HasPrefix(path, "/")
}
-// VolumeName returns the leading volume name on Windows.
-// It returns "" elsewhere.
-func VolumeName(path string) string {
- return ""
+// volumeNameLen returns length of the leading volume name on Windows.
+// It returns 0 elsewhere.
+func volumeNameLen(path string) int {
+ return 0
}
// HasPrefix exists for historical compatibility and should not be used.
// IsAbs returns true if the path is absolute.
func IsAbs(path string) (b bool) {
- v := VolumeName(path)
- if v == "" {
+ l := volumeNameLen(path)
+ if l == 0 {
return false
}
- path = path[len(v):]
+ path = path[l:]
if path == "" {
return false
}
return isSlash(path[0])
}
-// VolumeName returns leading volume name.
-// Given "C:\foo\bar" it returns "C:" under windows.
-// Given "\\host\share\foo" it returns "\\host\share".
-// On other platforms it returns "".
-func VolumeName(path string) (v string) {
+// volumeNameLen returns length of the leading volume name on Windows.
+// It returns 0 elsewhere.
+func volumeNameLen(path string) int {
if len(path) < 2 {
- return ""
+ return 0
}
// with drive letter
c := path[0]
if path[1] == ':' && ('a' <= c && c <= 'z' || 'A' <= c && c <= 'Z') {
- return path[:2]
+ return 2
}
// is it UNC
if l := len(path); l >= 5 && isSlash(path[0]) && isSlash(path[1]) &&
break
}
}
- return path[:n]
+ return n
}
break
}
}
}
- return ""
+ return 0
}
// HasPrefix exists for historical compatibility and should not be used.