...
Run Format

Source file src/path/filepath/path_windows.go

Documentation: path/filepath

     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.
     4  
     5  package filepath
     6  
     7  import (
     8  	"strings"
     9  	"syscall"
    10  )
    11  
    12  func isSlash(c uint8) bool {
    13  	return c == '\\' || c == '/'
    14  }
    15  
    16  // IsAbs reports whether the path is absolute.
    17  func IsAbs(path string) (b bool) {
    18  	l := volumeNameLen(path)
    19  	if l == 0 {
    20  		return false
    21  	}
    22  	path = path[l:]
    23  	if path == "" {
    24  		return false
    25  	}
    26  	return isSlash(path[0])
    27  }
    28  
    29  // volumeNameLen returns length of the leading volume name on Windows.
    30  // It returns 0 elsewhere.
    31  func volumeNameLen(path string) int {
    32  	if len(path) < 2 {
    33  		return 0
    34  	}
    35  	// with drive letter
    36  	c := path[0]
    37  	if path[1] == ':' && ('a' <= c && c <= 'z' || 'A' <= c && c <= 'Z') {
    38  		return 2
    39  	}
    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.
    46  			if isSlash(path[n]) {
    47  				n++
    48  				// third, following something characters. its share name.
    49  				if !isSlash(path[n]) {
    50  					if path[n] == '.' {
    51  						break
    52  					}
    53  					for ; n < l; n++ {
    54  						if isSlash(path[n]) {
    55  							break
    56  						}
    57  					}
    58  					return n
    59  				}
    60  				break
    61  			}
    62  		}
    63  	}
    64  	return 0
    65  }
    66  
    67  // HasPrefix exists for historical compatibility and should not be used.
    68  //
    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) {
    73  		return true
    74  	}
    75  	return strings.HasPrefix(strings.ToLower(p), strings.ToLower(prefix))
    76  }
    77  
    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.
    81  
    82  	if path == "" {
    83  		return []string{}
    84  	}
    85  
    86  	// Split path, respecting but preserving quotes.
    87  	list := []string{}
    88  	start := 0
    89  	quo := false
    90  	for i := 0; i < len(path); i++ {
    91  		switch c := path[i]; {
    92  		case c == '"':
    93  			quo = !quo
    94  		case c == ListSeparator && !quo:
    95  			list = append(list, path[start:i])
    96  			start = i + 1
    97  		}
    98  	}
    99  	list = append(list, path[start:])
   100  
   101  	// Remove quotes.
   102  	for i, s := range list {
   103  		list[i] = strings.Replace(s, `"`, ``, -1)
   104  	}
   105  
   106  	return list
   107  }
   108  
   109  func abs(path string) (string, error) {
   110  	if path == "" {
   111  		// syscall.FullPath returns an error on empty path, because it's not a valid path.
   112  		// To implement Abs behavior of returning working directory on empty string input,
   113  		// special-case empty path by changing it to "." path. See golang.org/issue/24441.
   114  		path = "."
   115  	}
   116  	fullPath, err := syscall.FullPath(path)
   117  	if err != nil {
   118  		return "", err
   119  	}
   120  	return Clean(fullPath), nil
   121  }
   122  
   123  func join(elem []string) string {
   124  	for i, e := range elem {
   125  		if e != "" {
   126  			return joinNonEmpty(elem[i:])
   127  		}
   128  	}
   129  	return ""
   130  }
   131  
   132  // joinNonEmpty is like join, but it assumes that the first element is non-empty.
   133  func joinNonEmpty(elem []string) string {
   134  	if len(elem[0]) == 2 && elem[0][1] == ':' {
   135  		// First element is drive letter without terminating slash.
   136  		// Keep path relative to current directory on that drive.
   137  		return Clean(elem[0] + strings.Join(elem[1:], string(Separator)))
   138  	}
   139  	// The following logic prevents Join from inadvertently creating a
   140  	// UNC path on Windows. Unless the first element is a UNC path, Join
   141  	// shouldn't create a UNC path. See golang.org/issue/9167.
   142  	p := Clean(strings.Join(elem, string(Separator)))
   143  	if !isUNC(p) {
   144  		return p
   145  	}
   146  	// p == UNC only allowed when the first element is a UNC path.
   147  	head := Clean(elem[0])
   148  	if isUNC(head) {
   149  		return p
   150  	}
   151  	// head + tail == UNC, but joining two non-UNC paths should not result
   152  	// in a UNC path. Undo creation of UNC path.
   153  	tail := Clean(strings.Join(elem[1:], string(Separator)))
   154  	if head[len(head)-1] == Separator {
   155  		return head + tail
   156  	}
   157  	return head + string(Separator) + tail
   158  }
   159  
   160  // isUNC reports whether path is a UNC path.
   161  func isUNC(path string) bool {
   162  	return volumeNameLen(path) > 2
   163  }
   164  
   165  func sameWord(a, b string) bool {
   166  	return strings.EqualFold(a, b)
   167  }
   168  

View as plain text