mirror of
https://github.com/therootcompany/golib.git
synced 2026-03-29 03:24:07 +00:00
Derived from Go standard library internal/filepathlite and path/filepath. Provides Windows-style path operations that work on any platform. Exports: Clean, Join, Split, Ext, Base, Dir, IsAbs, VolumeName, VolumeNameLen, ToSlash, FromSlash, Separator, ListSeparator, IsPathSeparator.
124 lines
2.4 KiB
Go
124 lines
2.4 KiB
Go
// Copyright 2010 The Go Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
package winpath
|
|
|
|
const (
|
|
Separator = '\\' // OS-specific path separator
|
|
ListSeparator = ';' // OS-specific path list separator
|
|
)
|
|
|
|
func IsPathSeparator(c uint8) bool {
|
|
return c == '\\' || c == '/'
|
|
}
|
|
|
|
func toUpper(c byte) byte {
|
|
if 'a' <= c && c <= 'z' {
|
|
return c - ('a' - 'A')
|
|
}
|
|
return c
|
|
}
|
|
|
|
func IsAbs(path string) (b bool) {
|
|
l := volumeNameLen(path)
|
|
if l == 0 {
|
|
return false
|
|
}
|
|
if IsPathSeparator(path[0]) && IsPathSeparator(path[1]) {
|
|
return true
|
|
}
|
|
path = path[l:]
|
|
if path == "" {
|
|
return false
|
|
}
|
|
return IsPathSeparator(path[0])
|
|
}
|
|
|
|
func volumeNameLen(path string) int {
|
|
switch {
|
|
case len(path) >= 2 && path[1] == ':':
|
|
return 2
|
|
|
|
case len(path) == 0 || !IsPathSeparator(path[0]):
|
|
return 0
|
|
|
|
case pathHasPrefixFold(path, `\\.\UNC`):
|
|
return uncLen(path, len(`\\.\UNC\`))
|
|
|
|
case pathHasPrefixFold(path, `\\.`) ||
|
|
pathHasPrefixFold(path, `\\?`) || pathHasPrefixFold(path, `\??`):
|
|
if len(path) == 3 {
|
|
return 3
|
|
}
|
|
_, rest, ok := cutPath(path[4:])
|
|
if !ok {
|
|
return len(path)
|
|
}
|
|
return len(path) - len(rest) - 1
|
|
|
|
case len(path) >= 2 && IsPathSeparator(path[1]):
|
|
return uncLen(path, 2)
|
|
}
|
|
return 0
|
|
}
|
|
|
|
func pathHasPrefixFold(s, prefix string) bool {
|
|
if len(s) < len(prefix) {
|
|
return false
|
|
}
|
|
for i := 0; i < len(prefix); i++ {
|
|
if IsPathSeparator(prefix[i]) {
|
|
if !IsPathSeparator(s[i]) {
|
|
return false
|
|
}
|
|
} else if toUpper(prefix[i]) != toUpper(s[i]) {
|
|
return false
|
|
}
|
|
}
|
|
if len(s) > len(prefix) && !IsPathSeparator(s[len(prefix)]) {
|
|
return false
|
|
}
|
|
return true
|
|
}
|
|
|
|
func uncLen(path string, prefixLen int) int {
|
|
count := 0
|
|
for i := prefixLen; i < len(path); i++ {
|
|
if IsPathSeparator(path[i]) {
|
|
count++
|
|
if count == 2 {
|
|
return i
|
|
}
|
|
}
|
|
}
|
|
return len(path)
|
|
}
|
|
|
|
func cutPath(path string) (before, after string, found bool) {
|
|
for i := range path {
|
|
if IsPathSeparator(path[i]) {
|
|
return path[:i], path[i+1:], true
|
|
}
|
|
}
|
|
return path, "", false
|
|
}
|
|
|
|
func postClean(out *lazybuf) {
|
|
if out.volLen != 0 || out.buf == nil {
|
|
return
|
|
}
|
|
for _, c := range out.buf {
|
|
if IsPathSeparator(c) {
|
|
break
|
|
}
|
|
if c == ':' {
|
|
out.prepend('.', Separator)
|
|
return
|
|
}
|
|
}
|
|
if len(out.buf) >= 3 && IsPathSeparator(out.buf[0]) && out.buf[1] == '?' && out.buf[2] == '?' {
|
|
out.prepend(Separator, '.')
|
|
}
|
|
}
|