OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libgo/] [go/] [path/] [filepath/] [path.go] - Blame information for rev 747

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 747 jeremybenn
// Copyright 2009 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 implements utility routines for manipulating filename paths
6
// in a way compatible with the target operating system-defined file paths.
7
package filepath
8
 
9
import (
10
        "bytes"
11
        "errors"
12
        "os"
13
        "runtime"
14
        "sort"
15
        "strings"
16
)
17
 
18
const (
19
        Separator     = os.PathSeparator
20
        ListSeparator = os.PathListSeparator
21
)
22
 
23
// Clean returns the shortest path name equivalent to path
24
// by purely lexical processing.  It applies the following rules
25
// iteratively until no further processing can be done:
26
//
27
//      1. Replace multiple Separator elements with a single one.
28
//      2. Eliminate each . path name element (the current directory).
29
//      3. Eliminate each inner .. path name element (the parent directory)
30
//         along with the non-.. element that precedes it.
31
//      4. Eliminate .. elements that begin a rooted path:
32
//         that is, replace "/.." by "/" at the beginning of a path,
33
//         assuming Separator is '/'.
34
//
35
// If the result of this process is an empty string, Clean
36
// returns the string ".".
37
//
38
// See also Rob Pike, ``Lexical File Names in Plan 9 or
39
// Getting Dot-Dot right,''
40
// http://plan9.bell-labs.com/sys/doc/lexnames.html
41
func Clean(path string) string {
42
        vol := VolumeName(path)
43
        path = path[len(vol):]
44
        if path == "" {
45
                if len(vol) > 1 && vol[1] != ':' {
46
                        // should be UNC
47
                        return FromSlash(vol)
48
                }
49
                return vol + "."
50
        }
51
        rooted := os.IsPathSeparator(path[0])
52
 
53
        // Invariants:
54
        //      reading from path; r is index of next byte to process.
55
        //      writing to buf; w is index of next byte to write.
56
        //      dotdot is index in buf where .. must stop, either because
57
        //              it is the leading slash or it is a leading ../../.. prefix.
58
        n := len(path)
59
        buf := []byte(path)
60
        r, w, dotdot := 0, 0, 0
61
        if rooted {
62
                buf[0] = Separator
63
                r, w, dotdot = 1, 1, 1
64
        }
65
 
66
        for r < n {
67
                switch {
68
                case os.IsPathSeparator(path[r]):
69
                        // empty path element
70
                        r++
71
                case path[r] == '.' && (r+1 == n || os.IsPathSeparator(path[r+1])):
72
                        // . element
73
                        r++
74
                case path[r] == '.' && path[r+1] == '.' && (r+2 == n || os.IsPathSeparator(path[r+2])):
75
                        // .. element: remove to last separator
76
                        r += 2
77
                        switch {
78
                        case w > dotdot:
79
                                // can backtrack
80
                                w--
81
                                for w > dotdot && !os.IsPathSeparator(buf[w]) {
82
                                        w--
83
                                }
84
                        case !rooted:
85
                                // cannot backtrack, but not rooted, so append .. element.
86
                                if w > 0 {
87
                                        buf[w] = Separator
88
                                        w++
89
                                }
90
                                buf[w] = '.'
91
                                w++
92
                                buf[w] = '.'
93
                                w++
94
                                dotdot = w
95
                        }
96
                default:
97
                        // real path element.
98
                        // add slash if needed
99
                        if rooted && w != 1 || !rooted && w != 0 {
100
                                buf[w] = Separator
101
                                w++
102
                        }
103
                        // copy element
104
                        for ; r < n && !os.IsPathSeparator(path[r]); r++ {
105
                                buf[w] = path[r]
106
                                w++
107
                        }
108
                }
109
        }
110
 
111
        // Turn empty string into "."
112
        if w == 0 {
113
                buf[w] = '.'
114
                w++
115
        }
116
 
117
        return FromSlash(vol + string(buf[0:w]))
118
}
119
 
120
// ToSlash returns the result of replacing each separator character
121
// in path with a slash ('/') character.
122
func ToSlash(path string) string {
123
        if Separator == '/' {
124
                return path
125
        }
126
        return strings.Replace(path, string(Separator), "/", -1)
127
}
128
 
129
// FromSlash returns the result of replacing each slash ('/') character
130
// in path with a separator character.
131
func FromSlash(path string) string {
132
        if Separator == '/' {
133
                return path
134
        }
135
        return strings.Replace(path, "/", string(Separator), -1)
136
}
137
 
138
// SplitList splits a list of paths joined by the OS-specific ListSeparator.
139
func SplitList(path string) []string {
140
        if path == "" {
141
                return []string{}
142
        }
143
        return strings.Split(path, string(ListSeparator))
144
}
145
 
146
// Split splits path immediately following the final Separator,
147
// separating it into a directory and file name component.
148
// If there is no Separator in path, Split returns an empty dir
149
// and file set to path.
150
// The returned values have the property that path = dir+file.
151
func Split(path string) (dir, file string) {
152
        vol := VolumeName(path)
153
        i := len(path) - 1
154
        for i >= len(vol) && !os.IsPathSeparator(path[i]) {
155
                i--
156
        }
157
        return path[:i+1], path[i+1:]
158
}
159
 
160
// Join joins any number of path elements into a single path, adding
161
// a Separator if necessary.  All empty strings are ignored.
162
func Join(elem ...string) string {
163
        for i, e := range elem {
164
                if e != "" {
165
                        return Clean(strings.Join(elem[i:], string(Separator)))
166
                }
167
        }
168
        return ""
169
}
170
 
171
// Ext returns the file name extension used by path.
172
// The extension is the suffix beginning at the final dot
173
// in the final element of path; it is empty if there is
174
// no dot.
175
func Ext(path string) string {
176
        for i := len(path) - 1; i >= 0 && !os.IsPathSeparator(path[i]); i-- {
177
                if path[i] == '.' {
178
                        return path[i:]
179
                }
180
        }
181
        return ""
182
}
183
 
184
// EvalSymlinks returns the path name after the evaluation of any symbolic
185
// links.
186
// If path is relative it will be evaluated relative to the current directory.
187
func EvalSymlinks(path string) (string, error) {
188
        if runtime.GOOS == "windows" {
189
                // Symlinks are not supported under windows.
190
                _, err := os.Lstat(path)
191
                if err != nil {
192
                        return "", err
193
                }
194
                return Clean(path), nil
195
        }
196
        const maxIter = 255
197
        originalPath := path
198
        // consume path by taking each frontmost path element,
199
        // expanding it if it's a symlink, and appending it to b
200
        var b bytes.Buffer
201
        for n := 0; path != ""; n++ {
202
                if n > maxIter {
203
                        return "", errors.New("EvalSymlinks: too many links in " + originalPath)
204
                }
205
 
206
                // find next path component, p
207
                i := strings.IndexRune(path, Separator)
208
                var p string
209
                if i == -1 {
210
                        p, path = path, ""
211
                } else {
212
                        p, path = path[:i], path[i+1:]
213
                }
214
 
215
                if p == "" {
216
                        if b.Len() == 0 {
217
                                // must be absolute path
218
                                b.WriteRune(Separator)
219
                        }
220
                        continue
221
                }
222
 
223
                fi, err := os.Lstat(b.String() + p)
224
                if err != nil {
225
                        return "", err
226
                }
227
                if fi.Mode()&os.ModeSymlink == 0 {
228
                        b.WriteString(p)
229
                        if path != "" {
230
                                b.WriteRune(Separator)
231
                        }
232
                        continue
233
                }
234
 
235
                // it's a symlink, put it at the front of path
236
                dest, err := os.Readlink(b.String() + p)
237
                if err != nil {
238
                        return "", err
239
                }
240
                if IsAbs(dest) {
241
                        b.Reset()
242
                }
243
                path = dest + string(Separator) + path
244
        }
245
        return Clean(b.String()), nil
246
}
247
 
248
// Abs returns an absolute representation of path.
249
// If the path is not absolute it will be joined with the current
250
// working directory to turn it into an absolute path.  The absolute
251
// path name for a given file is not guaranteed to be unique.
252
func Abs(path string) (string, error) {
253
        if IsAbs(path) {
254
                return Clean(path), nil
255
        }
256
        wd, err := os.Getwd()
257
        if err != nil {
258
                return "", err
259
        }
260
        return Join(wd, path), nil
261
}
262
 
263
// Rel returns a relative path that is lexically equivalent to targpath when
264
// joined to basepath with an intervening separator. That is,
265
// Join(basepath, Rel(basepath, targpath)) is equivalent to targpath itself.
266
// On success, the returned path will always be relative to basepath,
267
// even if basepath and targpath share no elements.
268
// An error is returned if targpath can't be made relative to basepath or if
269
// knowing the current working directory would be necessary to compute it.
270
func Rel(basepath, targpath string) (string, error) {
271
        baseVol := VolumeName(basepath)
272
        targVol := VolumeName(targpath)
273
        base := Clean(basepath)
274
        targ := Clean(targpath)
275
        if targ == base {
276
                return ".", nil
277
        }
278
        base = base[len(baseVol):]
279
        targ = targ[len(targVol):]
280
        if base == "." {
281
                base = ""
282
        }
283
        // Can't use IsAbs - `\a` and `a` are both relative in Windows.
284
        baseSlashed := len(base) > 0 && base[0] == Separator
285
        targSlashed := len(targ) > 0 && targ[0] == Separator
286
        if baseSlashed != targSlashed || baseVol != targVol {
287
                return "", errors.New("Rel: can't make " + targ + " relative to " + base)
288
        }
289
        // Position base[b0:bi] and targ[t0:ti] at the first differing elements.
290
        bl := len(base)
291
        tl := len(targ)
292
        var b0, bi, t0, ti int
293
        for {
294
                for bi < bl && base[bi] != Separator {
295
                        bi++
296
                }
297
                for ti < tl && targ[ti] != Separator {
298
                        ti++
299
                }
300
                if targ[t0:ti] != base[b0:bi] {
301
                        break
302
                }
303
                if bi < bl {
304
                        bi++
305
                }
306
                if ti < tl {
307
                        ti++
308
                }
309
                b0 = bi
310
                t0 = ti
311
        }
312
        if base[b0:bi] == ".." {
313
                return "", errors.New("Rel: can't make " + targ + " relative to " + base)
314
        }
315
        if b0 != bl {
316
                // Base elements left. Must go up before going down.
317
                seps := strings.Count(base[b0:bl], string(Separator))
318
                size := 2 + seps*3
319
                if tl != t0 {
320
                        size += 1 + tl - t0
321
                }
322
                buf := make([]byte, size)
323
                n := copy(buf, "..")
324
                for i := 0; i < seps; i++ {
325
                        buf[n] = Separator
326
                        copy(buf[n+1:], "..")
327
                        n += 3
328
                }
329
                if t0 != tl {
330
                        buf[n] = Separator
331
                        copy(buf[n+1:], targ[t0:])
332
                }
333
                return string(buf), nil
334
        }
335
        return targ[t0:], nil
336
}
337
 
338
// SkipDir is used as a return value from WalkFuncs to indicate that
339
// the directory named in the call is to be skipped. It is not returned
340
// as an error by any function.
341
var SkipDir = errors.New("skip this directory")
342
 
343
// WalkFunc is the type of the function called for each file or directory
344
// visited by Walk.  If there was a problem walking to the file or directory
345
// named by path, the incoming error will describe the problem and the
346
// function can decide how to handle that error (and Walk will not descend
347
// into that directory).  If an error is returned, processing stops.  The
348
// sole exception is that if path is a directory and the function returns the
349
// special value SkipDir, the contents of the directory are skipped
350
// and processing continues as usual on the next file.
351
type WalkFunc func(path string, info os.FileInfo, err error) error
352
 
353
// walk recursively descends path, calling w.
354
func walk(path string, info os.FileInfo, walkFn WalkFunc) error {
355
        err := walkFn(path, info, nil)
356
        if err != nil {
357
                if info.IsDir() && err == SkipDir {
358
                        return nil
359
                }
360
                return err
361
        }
362
 
363
        if !info.IsDir() {
364
                return nil
365
        }
366
 
367
        list, err := readDir(path)
368
        if err != nil {
369
                return walkFn(path, info, err)
370
        }
371
 
372
        for _, fileInfo := range list {
373
                if err = walk(Join(path, fileInfo.Name()), fileInfo, walkFn); err != nil {
374
                        return err
375
                }
376
        }
377
        return nil
378
}
379
 
380
// Walk walks the file tree rooted at root, calling walkFn for each file or
381
// directory in the tree, including root. All errors that arise visiting files
382
// and directories are filtered by walkFn. The files are walked in lexical
383
// order, which makes the output deterministic but means that for very
384
// large directories Walk can be inefficient.
385
func Walk(root string, walkFn WalkFunc) error {
386
        info, err := os.Lstat(root)
387
        if err != nil {
388
                return walkFn(root, nil, err)
389
        }
390
        return walk(root, info, walkFn)
391
}
392
 
393
// readDir reads the directory named by dirname and returns
394
// a sorted list of directory entries.
395
// Copied from io/ioutil to avoid the circular import.
396
func readDir(dirname string) ([]os.FileInfo, error) {
397
        f, err := os.Open(dirname)
398
        if err != nil {
399
                return nil, err
400
        }
401
        list, err := f.Readdir(-1)
402
        f.Close()
403
        if err != nil {
404
                return nil, err
405
        }
406
        sort.Sort(byName(list))
407
        return list, nil
408
}
409
 
410
// byName implements sort.Interface.
411
type byName []os.FileInfo
412
 
413
func (f byName) Len() int           { return len(f) }
414
func (f byName) Less(i, j int) bool { return f[i].Name() < f[j].Name() }
415
func (f byName) Swap(i, j int)      { f[i], f[j] = f[j], f[i] }
416
 
417
// Base returns the last element of path.
418
// Trailing path separators are removed before extracting the last element.
419
// If the path is empty, Base returns ".".
420
// If the path consists entirely of separators, Base returns a single separator.
421
func Base(path string) string {
422
        if path == "" {
423
                return "."
424
        }
425
        // Strip trailing slashes.
426
        for len(path) > 0 && os.IsPathSeparator(path[len(path)-1]) {
427
                path = path[0 : len(path)-1]
428
        }
429
        // Throw away volume name
430
        path = path[len(VolumeName(path)):]
431
        // Find the last element
432
        i := len(path) - 1
433
        for i >= 0 && !os.IsPathSeparator(path[i]) {
434
                i--
435
        }
436
        if i >= 0 {
437
                path = path[i+1:]
438
        }
439
        // If empty now, it had only slashes.
440
        if path == "" {
441
                return string(Separator)
442
        }
443
        return path
444
}
445
 
446
// Dir returns the all but the last element of path, typically the path's directory.
447
// Trailing path separators are removed before processing.
448
// If the path is empty, Dir returns ".".
449
// If the path consists entirely of separators, Dir returns a single separator.
450
// The returned path does not end in a separator unless it is the root directory.
451
func Dir(path string) string {
452
        vol := VolumeName(path)
453
        i := len(path) - 1
454
        for i >= len(vol) && !os.IsPathSeparator(path[i]) {
455
                i--
456
        }
457
        dir := Clean(path[len(vol) : i+1])
458
        last := len(dir) - 1
459
        if last > 0 && os.IsPathSeparator(dir[last]) {
460
                dir = dir[:last]
461
        }
462
        if dir == "" {
463
                dir = "."
464
        }
465
        return vol + dir
466
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.