Source file
src/path/match.go
Documentation: path
1
2
3
4
5 package path
6
7 import (
8 "errors"
9 "internal/bytealg"
10 "unicode/utf8"
11 )
12
13
14 var ErrBadPattern = errors.New("syntax error in pattern")
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
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
46 return bytealg.IndexByteString(name, '/') < 0, nil
47 }
48
49 t, ok, err := matchChunk(chunk, name)
50
51
52
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
62
63 for i := 0; i < len(name) && name[i] != '/'; i++ {
64 t, ok, err := matchChunk(chunk, name[i+1:])
65 if ok {
66
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
79
80 for len(pattern) > 0 {
81 _, chunk, pattern = scanChunk(pattern)
82 if _, _, err := matchChunk(chunk, ""); err != nil {
83 return false, err
84 }
85 }
86 return false, nil
87 }
88 return len(name) == 0, nil
89 }
90
91
92
93 func scanChunk(pattern string) (star bool, chunk, rest string) {
94 for len(pattern) > 0 && pattern[0] == '*' {
95 pattern = pattern[1:]
96 star = true
97 }
98 inrange := false
99 var i int
100 Scan:
101 for i = 0; i < len(pattern); i++ {
102 switch pattern[i] {
103 case '\\':
104
105 if i+1 < len(pattern) {
106 i++
107 }
108 case '[':
109 inrange = true
110 case ']':
111 inrange = false
112 case '*':
113 if !inrange {
114 break Scan
115 }
116 }
117 }
118 return star, pattern[0:i], pattern[i:]
119 }
120
121
122
123
124 func matchChunk(chunk, s string) (rest string, ok bool, err error) {
125
126
127
128 failed := false
129 for len(chunk) > 0 {
130 if !failed && len(s) == 0 {
131 failed = true
132 }
133 switch chunk[0] {
134 case '[':
135
136 var r rune
137 if !failed {
138 var n int
139 r, n = utf8.DecodeRuneInString(s)
140 s = s[n:]
141 }
142 chunk = chunk[1:]
143
144 negated := false
145 if len(chunk) > 0 && chunk[0] == '^' {
146 negated = true
147 chunk = chunk[1:]
148 }
149
150 match := false
151 nrange := 0
152 for {
153 if len(chunk) > 0 && chunk[0] == ']' && nrange > 0 {
154 chunk = chunk[1:]
155 break
156 }
157 var lo, hi rune
158 if lo, chunk, err = getEsc(chunk); err != nil {
159 return "", false, err
160 }
161 hi = lo
162 if chunk[0] == '-' {
163 if hi, chunk, err = getEsc(chunk[1:]); err != nil {
164 return "", false, err
165 }
166 }
167 if lo <= r && r <= hi {
168 match = true
169 }
170 nrange++
171 }
172 if match == negated {
173 failed = true
174 }
175
176 case '?':
177 if !failed {
178 if s[0] == '/' {
179 failed = true
180 }
181 _, n := utf8.DecodeRuneInString(s)
182 s = s[n:]
183 }
184 chunk = chunk[1:]
185
186 case '\\':
187 chunk = chunk[1:]
188 if len(chunk) == 0 {
189 return "", false, ErrBadPattern
190 }
191 fallthrough
192
193 default:
194 if !failed {
195 if chunk[0] != s[0] {
196 failed = true
197 }
198 s = s[1:]
199 }
200 chunk = chunk[1:]
201 }
202 }
203 if failed {
204 return "", false, nil
205 }
206 return s, true, nil
207 }
208
209
210 func getEsc(chunk string) (r rune, nchunk string, err error) {
211 if len(chunk) == 0 || chunk[0] == '-' || chunk[0] == ']' {
212 err = ErrBadPattern
213 return
214 }
215 if chunk[0] == '\\' {
216 chunk = chunk[1:]
217 if len(chunk) == 0 {
218 err = ErrBadPattern
219 return
220 }
221 }
222 r, n := utf8.DecodeRuneInString(chunk)
223 if r == utf8.RuneError && n == 1 {
224 err = ErrBadPattern
225 }
226 nchunk = chunk[n:]
227 if len(nchunk) == 0 {
228 err = ErrBadPattern
229 }
230 return
231 }
232
View as plain text