16
// A lazybuf is a lazily constructed path buffer.
17
// It supports append, reading previously appended bytes,
18
// and retrieving the final string. It does not allocate a buffer
19
// to hold the output until that output diverges from s.
28
func (b *lazybuf) index(i int) byte {
35
func (b *lazybuf) append(c byte) {
37
if b.w < len(b.path) && b.path[b.w] == c {
41
b.buf = make([]byte, len(b.path))
42
copy(b.buf, b.path[:b.w])
48
func (b *lazybuf) string() string {
50
return b.volAndPath[:b.volLen+b.w]
52
return b.volAndPath[:b.volLen] + string(b.buf[:b.w])
17
56
Separator = os.PathSeparator
18
57
ListSeparator = os.PathListSeparator
40
79
// Getting Dot-Dot Right,''
41
80
// http://plan9.bell-labs.com/sys/doc/lexnames.html
42
81
func Clean(path string) string {
43
vol := VolumeName(path)
44
path = path[len(vol):]
83
volLen := volumeNameLen(path)
46
if len(vol) > 1 && vol[1] != ':' {
86
if volLen > 1 && originalPath[1] != ':' {
88
return FromSlash(originalPath)
90
return originalPath + "."
52
92
rooted := os.IsPathSeparator(path[0])
57
97
// dotdot is index in buf where .. must stop, either because
58
98
// it is the leading slash or it is a leading ../../.. prefix.
61
r, w, dotdot := 0, 0, 0
100
out := lazybuf{path: path, volAndPath: originalPath, volLen: volLen}
64
r, w, dotdot = 1, 1, 1
103
out.append(Separator)
76
116
// .. element: remove to last separator
82
for w > dotdot && !os.IsPathSeparator(buf[w]) {
122
for out.w > dotdot && !os.IsPathSeparator(out.index(out.w)) {
86
126
// cannot backtrack, but not rooted, so append .. element.
128
out.append(Separator)
98
135
// real path element.
99
136
// add slash if needed
100
if rooted && w != 1 || !rooted && w != 0 {
137
if rooted && out.w != 1 || !rooted && out.w != 0 {
138
out.append(Separator)
105
141
for ; r < n && !os.IsPathSeparator(path[r]); r++ {
112
147
// Turn empty string into "."
118
return FromSlash(vol + string(buf[0:w]))
152
return FromSlash(out.string())
121
155
// ToSlash returns the result of replacing each separator character
142
176
// usually found in PATH or GOPATH environment variables.
143
177
// Unlike strings.Split, SplitList returns an empty slice when passed an empty string.
144
178
func SplitList(path string) []string {
148
return strings.Split(path, string(ListSeparator))
179
return splitList(path)
151
182
// Split splits path immediately following the final Separator,
291
322
var SkipDir = errors.New("skip this directory")
293
324
// WalkFunc is the type of the function called for each file or directory
294
// visited by Walk. If there was a problem walking to the file or directory
295
// named by path, the incoming error will describe the problem and the
296
// function can decide how to handle that error (and Walk will not descend
297
// into that directory). If an error is returned, processing stops. The
298
// sole exception is that if path is a directory and the function returns the
299
// special value SkipDir, the contents of the directory are skipped
300
// and processing continues as usual on the next file.
325
// visited by Walk. The path argument contains the argument to Walk as a
326
// prefix; that is, if Walk is called with "dir", which is a directory
327
// containing the file "a", the walk function will be called with argument
328
// "dir/a". The info argument is the os.FileInfo for the named path.
330
// If there was a problem walking to the file or directory named by path, the
331
// incoming error will describe the problem and the function can decide how
332
// to handle that error (and Walk will not descend into that directory). If
333
// an error is returned, processing stops. The sole exception is that if path
334
// is a directory and the function returns the special value SkipDir, the
335
// contents of the directory are skipped and processing continues as usual on
301
337
type WalkFunc func(path string, info os.FileInfo, err error) error
303
339
// walk recursively descends path, calling w.
335
371
// and directories are filtered by walkFn. The files are walked in lexical
336
372
// order, which makes the output deterministic but means that for very
337
373
// large directories Walk can be inefficient.
374
// Walk does not follow symbolic links.
338
375
func Walk(root string, walkFn WalkFunc) error {
339
376
info, err := os.Lstat(root)
399
436
// Dir returns all but the last element of path, typically the path's directory.
400
// Trailing path separators are removed before processing.
437
// After dropping the final element, the path is Cleaned and trailing
438
// slashes are removed.
401
439
// If the path is empty, Dir returns ".".
402
440
// If the path consists entirely of separators, Dir returns a single separator.
403
441
// The returned path does not end in a separator unless it is the root directory.
459
// VolumeName returns leading volume name.
460
// Given "C:\foo\bar" it returns "C:" under windows.
461
// Given "\\host\share\foo" it returns "\\host\share".
462
// On other platforms it returns "".
463
func VolumeName(path string) (v string) {
464
return path[:volumeNameLen(path)]