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

Subversion Repositories openrisc

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

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 747 jeremybenn
// 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
        "errors"
9
        "os"
10
        "sort"
11
        "strings"
12
        "unicode/utf8"
13
)
14
 
15
var ErrBadPattern = errors.New("syntax error in pattern")
16
 
17
// Match returns true if name matches the shell file name pattern.
18
// The pattern syntax is:
19
//
20
//      pattern:
21
//              { term }
22
//      term:
23
//              '*'         matches any sequence of non-Separator characters
24
//              '?'         matches any single non-Separator character
25
//              '[' [ '^' ] { character-range } ']'
26
//                          character class (must be non-empty)
27
//              c           matches character c (c != '*', '?', '\\', '[')
28
//              '\\' c      matches character c
29
//
30
//      character-range:
31
//              c           matches character c (c != '\\', '-', ']')
32
//              '\\' c      matches character c
33
//              lo '-' hi   matches character c for lo <= c <= hi
34
//
35
// Match requires pattern to match all of name, not just a substring.
36
// The only possible error return occurs when the pattern is malformed.
37
//
38
func Match(pattern, name string) (matched bool, err error) {
39
Pattern:
40
        for len(pattern) > 0 {
41
                var star bool
42
                var chunk string
43
                star, chunk, pattern = scanChunk(pattern)
44
                if star && chunk == "" {
45
                        // Trailing * matches rest of string unless it has a /.
46
                        return strings.Index(name, string(Separator)) < 0, nil
47
                }
48
                // Look for match at current position.
49
                t, ok, err := matchChunk(chunk, name)
50
                // if we're the last chunk, make sure we've exhausted the name
51
                // otherwise we'll give a false result even if we could still match
52
                // using the star
53
                if ok && (len(t) == 0 || len(pattern) > 0) {
54
                        name = t
55
                        continue
56
                }
57
                if err != nil {
58
                        return false, err
59
                }
60
                if star {
61
                        // Look for match skipping i+1 bytes.
62
                        // Cannot skip /.
63
                        for i := 0; i < len(name) && name[i] != Separator; i++ {
64
                                t, ok, err := matchChunk(chunk, name[i+1:])
65
                                if ok {
66
                                        // if we're the last chunk, make sure we exhausted the name
67
                                        if len(pattern) == 0 && len(t) > 0 {
68
                                                continue
69
                                        }
70
                                        name = t
71
                                        continue Pattern
72
                                }
73
                                if err != nil {
74
                                        return false, err
75
                                }
76
                        }
77
                }
78
                return false, nil
79
        }
80
        return len(name) == 0, nil
81
}
82
 
83
// scanChunk gets the next segment of pattern, which is a non-star string
84
// possibly preceded by a star.
85
func scanChunk(pattern string) (star bool, chunk, rest string) {
86
        for len(pattern) > 0 && pattern[0] == '*' {
87
                pattern = pattern[1:]
88
                star = true
89
        }
90
        inrange := false
91
        var i int
92
Scan:
93
        for i = 0; i < len(pattern); i++ {
94
                switch pattern[i] {
95
                case '\\':
96
                        // error check handled in matchChunk: bad pattern.
97
                        if i+1 < len(pattern) {
98
                                i++
99
                        }
100
                case '[':
101
                        inrange = true
102
                case ']':
103
                        inrange = false
104
                case '*':
105
                        if !inrange {
106
                                break Scan
107
                        }
108
                }
109
        }
110
        return star, pattern[0:i], pattern[i:]
111
}
112
 
113
// matchChunk checks whether chunk matches the beginning of s.
114
// If so, it returns the remainder of s (after the match).
115
// Chunk is all single-character operators: literals, char classes, and ?.
116
func matchChunk(chunk, s string) (rest string, ok bool, err error) {
117
        for len(chunk) > 0 {
118
                if len(s) == 0 {
119
                        return
120
                }
121
                switch chunk[0] {
122
                case '[':
123
                        // character class
124
                        r, n := utf8.DecodeRuneInString(s)
125
                        s = s[n:]
126
                        chunk = chunk[1:]
127
                        // possibly negated
128
                        negated := chunk[0] == '^'
129
                        if negated {
130
                                chunk = chunk[1:]
131
                        }
132
                        // parse all ranges
133
                        match := false
134
                        nrange := 0
135
                        for {
136
                                if len(chunk) > 0 && chunk[0] == ']' && nrange > 0 {
137
                                        chunk = chunk[1:]
138
                                        break
139
                                }
140
                                var lo, hi rune
141
                                if lo, chunk, err = getEsc(chunk); err != nil {
142
                                        return
143
                                }
144
                                hi = lo
145
                                if chunk[0] == '-' {
146
                                        if hi, chunk, err = getEsc(chunk[1:]); err != nil {
147
                                                return
148
                                        }
149
                                }
150
                                if lo <= r && r <= hi {
151
                                        match = true
152
                                }
153
                                nrange++
154
                        }
155
                        if match == negated {
156
                                return
157
                        }
158
 
159
                case '?':
160
                        if s[0] == Separator {
161
                                return
162
                        }
163
                        _, n := utf8.DecodeRuneInString(s)
164
                        s = s[n:]
165
                        chunk = chunk[1:]
166
 
167
                case '\\':
168
                        chunk = chunk[1:]
169
                        if len(chunk) == 0 {
170
                                err = ErrBadPattern
171
                                return
172
                        }
173
                        fallthrough
174
 
175
                default:
176
                        if chunk[0] != s[0] {
177
                                return
178
                        }
179
                        s = s[1:]
180
                        chunk = chunk[1:]
181
                }
182
        }
183
        return s, true, nil
184
}
185
 
186
// getEsc gets a possibly-escaped character from chunk, for a character class.
187
func getEsc(chunk string) (r rune, nchunk string, err error) {
188
        if len(chunk) == 0 || chunk[0] == '-' || chunk[0] == ']' {
189
                err = ErrBadPattern
190
                return
191
        }
192
        if chunk[0] == '\\' {
193
                chunk = chunk[1:]
194
                if len(chunk) == 0 {
195
                        err = ErrBadPattern
196
                        return
197
                }
198
        }
199
        r, n := utf8.DecodeRuneInString(chunk)
200
        if r == utf8.RuneError && n == 1 {
201
                err = ErrBadPattern
202
        }
203
        nchunk = chunk[n:]
204
        if len(nchunk) == 0 {
205
                err = ErrBadPattern
206
        }
207
        return
208
}
209
 
210
// Glob returns the names of all files matching pattern or nil
211
// if there is no matching file. The syntax of patterns is the same
212
// as in Match. The pattern may describe hierarchical names such as
213
// /usr/*/bin/ed (assuming the Separator is '/').
214
// The only possible error return occurs when the pattern is malformed.
215
//
216
func Glob(pattern string) (matches []string, err error) {
217
        if !hasMeta(pattern) {
218
                if _, err = os.Stat(pattern); err != nil {
219
                        return nil, nil
220
                }
221
                return []string{pattern}, nil
222
        }
223
 
224
        dir, file := Split(pattern)
225
        switch dir {
226
        case "":
227
                dir = "."
228
        case string(Separator):
229
                // nothing
230
        default:
231
                dir = dir[0 : len(dir)-1] // chop off trailing separator
232
        }
233
 
234
        if !hasMeta(dir) {
235
                return glob(dir, file, nil)
236
        }
237
 
238
        var m []string
239
        m, err = Glob(dir)
240
        if err != nil {
241
                return
242
        }
243
        for _, d := range m {
244
                matches, err = glob(d, file, matches)
245
                if err != nil {
246
                        return
247
                }
248
        }
249
        return
250
}
251
 
252
// glob searches for files matching pattern in the directory dir
253
// and appends them to matches. If the directory cannot be
254
// opened, it returns the existing matches. New matches are
255
// added in lexicographical order.
256
// The only possible error return occurs when the pattern is malformed.
257
func glob(dir, pattern string, matches []string) (m []string, e error) {
258
        m = matches
259
        fi, err := os.Stat(dir)
260
        if err != nil {
261
                return
262
        }
263
        if !fi.IsDir() {
264
                return
265
        }
266
        d, err := os.Open(dir)
267
        if err != nil {
268
                return
269
        }
270
        defer d.Close()
271
 
272
        names, err := d.Readdirnames(-1)
273
        if err != nil {
274
                return
275
        }
276
        sort.Strings(names)
277
 
278
        for _, n := range names {
279
                matched, err := Match(pattern, n)
280
                if err != nil {
281
                        return m, err
282
                }
283
                if matched {
284
                        m = append(m, Join(dir, n))
285
                }
286
        }
287
        return
288
}
289
 
290
// hasMeta returns true if path contains any of the magic characters
291
// recognized by Match.
292
func hasMeta(path string) bool {
293
        // TODO(niemeyer): Should other magic characters be added here?
294
        return strings.IndexAny(path, "*?[") >= 0
295
}

powered by: WebSVN 2.1.0

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