1 // Copyright 2010 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.
12 func isSlash(c
uint8) bool {
13 return c
== '\\' || c
== '/'
16 // IsAbs reports whether the path is absolute.
17 func IsAbs(path
string) (b
bool) {
18 l
:= volumeNameLen(path
)
26 return isSlash(path
[0])
29 // volumeNameLen returns length of the leading volume name on Windows.
30 // It returns 0 elsewhere.
31 func volumeNameLen(path
string) int {
37 if path
[1] == ':' && ('a' <= c
&& c
<= 'z' ||
'A' <= c
&& c
<= 'Z') {
40 // is it UNC? https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx
41 if l
:= len(path
); l
>= 5 && isSlash(path
[0]) && isSlash(path
[1]) &&
42 !isSlash(path
[2]) && path
[2] != '.' {
43 // first, leading `\\` and next shouldn't be `\`. its server name.
44 for n
:= 3; n
< l
-1; n
++ {
45 // second, next '\' shouldn't be repeated.
48 // third, following something characters. its share name.
49 if !isSlash(path
[n
]) {
67 // HasPrefix exists for historical compatibility and should not be used.
69 // Deprecated: HasPrefix does not respect path boundaries and
70 // does not ignore case when required.
71 func HasPrefix(p
, prefix
string) bool {
72 if strings
.HasPrefix(p
, prefix
) {
75 return strings
.HasPrefix(strings
.ToLower(p
), strings
.ToLower(prefix
))
78 func splitList(path
string) []string {
79 // The same implementation is used in LookPath in os/exec;
80 // consider changing os/exec when changing this.
86 // Split path, respecting but preserving quotes.
90 for i
:= 0; i
< len(path
); i
++ {
91 switch c
:= path
[i
]; {
94 case c
== ListSeparator
&& !quo
:
95 list
= append(list
, path
[start
:i
])
99 list
= append(list
, path
[start
:])
102 for i
, s
:= range list
{
103 if strings
.Contains(s
, `"`) {
104 list
[i
] = strings
.Replace(s
, `"`, ``, -1)
111 func abs(path
string) (string, error
) {
112 fullPath
, err
:= syscall
.FullPath(path
)
116 return Clean(fullPath
), nil
119 func join(elem
[]string) string {
120 for i
, e
:= range elem
{
122 return joinNonEmpty(elem
[i
:])
128 // joinNonEmpty is like join, but it assumes that the first element is non-empty.
129 func joinNonEmpty(elem
[]string) string {
130 if len(elem
[0]) == 2 && elem
[0][1] == ':' {
131 // First element is drive letter without terminating slash.
132 // Keep path relative to current directory on that drive.
133 return Clean(elem
[0] + strings
.Join(elem
[1:], string(Separator
)))
135 // The following logic prevents Join from inadvertently creating a
136 // UNC path on Windows. Unless the first element is a UNC path, Join
137 // shouldn't create a UNC path. See golang.org/issue/9167.
138 p
:= Clean(strings
.Join(elem
, string(Separator
)))
142 // p == UNC only allowed when the first element is a UNC path.
143 head
:= Clean(elem
[0])
147 // head + tail == UNC, but joining two non-UNC paths should not result
148 // in a UNC path. Undo creation of UNC path.
149 tail
:= Clean(strings
.Join(elem
[1:], string(Separator
)))
150 if head
[len(head
)-1] == Separator
{
153 return head
+ string(Separator
) + tail
156 // isUNC reports whether path is a UNC path.
157 func isUNC(path
string) bool {
158 return volumeNameLen(path
) > 2
161 func sameWord(a
, b
string) bool {
162 return strings
.EqualFold(a
, b
)