~ubuntu-branches/ubuntu/utopic/golang/utopic

« back to all changes in this revision

Viewing changes to src/pkg/path/filepath/path.go

  • Committer: Package Import Robot
  • Author(s): James Page
  • Date: 2013-08-20 14:06:23 UTC
  • mfrom: (14.1.23 saucy-proposed)
  • Revision ID: package-import@ubuntu.com-20130820140623-b414jfxi3m0qkmrq
Tags: 2:1.1.2-2ubuntu1
* Merge from Debian unstable (LP: #1211749, #1202027). Remaining changes:
  - 016-armhf-elf-header.patch: Use correct ELF header for armhf binaries.
  - d/control,control.cross: Update Breaks/Replaces for Ubuntu
    versions to ensure smooth upgrades, regenerate control file.

Show diffs side-by-side

added added

removed removed

Lines of Context:
13
13
        "strings"
14
14
)
15
15
 
 
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.
 
20
type lazybuf struct {
 
21
        path       string
 
22
        buf        []byte
 
23
        w          int
 
24
        volAndPath string
 
25
        volLen     int
 
26
}
 
27
 
 
28
func (b *lazybuf) index(i int) byte {
 
29
        if b.buf != nil {
 
30
                return b.buf[i]
 
31
        }
 
32
        return b.path[i]
 
33
}
 
34
 
 
35
func (b *lazybuf) append(c byte) {
 
36
        if b.buf == nil {
 
37
                if b.w < len(b.path) && b.path[b.w] == c {
 
38
                        b.w++
 
39
                        return
 
40
                }
 
41
                b.buf = make([]byte, len(b.path))
 
42
                copy(b.buf, b.path[:b.w])
 
43
        }
 
44
        b.buf[b.w] = c
 
45
        b.w++
 
46
}
 
47
 
 
48
func (b *lazybuf) string() string {
 
49
        if b.buf == nil {
 
50
                return b.volAndPath[:b.volLen+b.w]
 
51
        }
 
52
        return b.volAndPath[:b.volLen] + string(b.buf[:b.w])
 
53
}
 
54
 
16
55
const (
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):]
 
82
        originalPath := path
 
83
        volLen := volumeNameLen(path)
 
84
        path = path[volLen:]
45
85
        if path == "" {
46
 
                if len(vol) > 1 && vol[1] != ':' {
 
86
                if volLen > 1 && originalPath[1] != ':' {
47
87
                        // should be UNC
48
 
                        return FromSlash(vol)
 
88
                        return FromSlash(originalPath)
49
89
                }
50
 
                return vol + "."
 
90
                return originalPath + "."
51
91
        }
52
92
        rooted := os.IsPathSeparator(path[0])
53
93
 
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.
59
99
        n := len(path)
60
 
        buf := []byte(path)
61
 
        r, w, dotdot := 0, 0, 0
 
100
        out := lazybuf{path: path, volAndPath: originalPath, volLen: volLen}
 
101
        r, dotdot := 0, 0
62
102
        if rooted {
63
 
                buf[0] = Separator
64
 
                r, w, dotdot = 1, 1, 1
 
103
                out.append(Separator)
 
104
                r, dotdot = 1, 1
65
105
        }
66
106
 
67
107
        for r < n {
76
116
                        // .. element: remove to last separator
77
117
                        r += 2
78
118
                        switch {
79
 
                        case w > dotdot:
 
119
                        case out.w > dotdot:
80
120
                                // can backtrack
81
 
                                w--
82
 
                                for w > dotdot && !os.IsPathSeparator(buf[w]) {
83
 
                                        w--
 
121
                                out.w--
 
122
                                for out.w > dotdot && !os.IsPathSeparator(out.index(out.w)) {
 
123
                                        out.w--
84
124
                                }
85
125
                        case !rooted:
86
126
                                // cannot backtrack, but not rooted, so append .. element.
87
 
                                if w > 0 {
88
 
                                        buf[w] = Separator
89
 
                                        w++
 
127
                                if out.w > 0 {
 
128
                                        out.append(Separator)
90
129
                                }
91
 
                                buf[w] = '.'
92
 
                                w++
93
 
                                buf[w] = '.'
94
 
                                w++
95
 
                                dotdot = w
 
130
                                out.append('.')
 
131
                                out.append('.')
 
132
                                dotdot = out.w
96
133
                        }
97
134
                default:
98
135
                        // real path element.
99
136
                        // add slash if needed
100
 
                        if rooted && w != 1 || !rooted && w != 0 {
101
 
                                buf[w] = Separator
102
 
                                w++
 
137
                        if rooted && out.w != 1 || !rooted && out.w != 0 {
 
138
                                out.append(Separator)
103
139
                        }
104
140
                        // copy element
105
141
                        for ; r < n && !os.IsPathSeparator(path[r]); r++ {
106
 
                                buf[w] = path[r]
107
 
                                w++
 
142
                                out.append(path[r])
108
143
                        }
109
144
                }
110
145
        }
111
146
 
112
147
        // Turn empty string into "."
113
 
        if w == 0 {
114
 
                buf[w] = '.'
115
 
                w++
 
148
        if out.w == 0 {
 
149
                out.append('.')
116
150
        }
117
151
 
118
 
        return FromSlash(vol + string(buf[0:w]))
 
152
        return FromSlash(out.string())
119
153
}
120
154
 
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 {
145
 
        if path == "" {
146
 
                return []string{}
147
 
        }
148
 
        return strings.Split(path, string(ListSeparator))
 
179
        return splitList(path)
149
180
}
150
181
 
151
182
// Split splits path immediately following the final Separator,
291
322
var SkipDir = errors.New("skip this directory")
292
323
 
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.
 
329
//
 
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
 
336
// the next file.
301
337
type WalkFunc func(path string, info os.FileInfo, err error) error
302
338
 
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)
340
377
        if err != nil {
397
434
}
398
435
 
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.
417
455
        }
418
456
        return vol + dir
419
457
}
 
458
 
 
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)]
 
465
}