Source file
src/path/match.go
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 func Match(pattern, name string) (matched bool, err error) {
38 Pattern:
39 for len(pattern) > 0 {
40 var star bool
41 var chunk string
42 star, chunk, pattern = scanChunk(pattern)
43 if star && chunk == "" {
44
45 return bytealg.IndexByteString(name, '/') < 0, nil
46 }
47
48 t, ok, err := matchChunk(chunk, name)
49
50
51
52 if ok && (len(t) == 0 || len(pattern) > 0) {
53 name = t
54 continue
55 }
56 if err != nil {
57 return false, err
58 }
59 if star {
60
61
62 for i := 0; i < len(name) && name[i] != '/'; i++ {
63 t, ok, err := matchChunk(chunk, name[i+1:])
64 if ok {
65
66 if len(pattern) == 0 && len(t) > 0 {
67 continue
68 }
69 name = t
70 continue Pattern
71 }
72 if err != nil {
73 return false, err
74 }
75 }
76 }
77
78
79 for len(pattern) > 0 {
80 _, chunk, pattern = scanChunk(pattern)
81 if _, _, err := matchChunk(chunk, ""); err != nil {
82 return false, err
83 }
84 }
85 return false, nil
86 }
87 return len(name) == 0, nil
88 }
89
90
91
92 func scanChunk(pattern string) (star bool, chunk, rest string) {
93 for len(pattern) > 0 && pattern[0] == '*' {
94 pattern = pattern[1:]
95 star = true
96 }
97 inrange := false
98 var i int
99 Scan:
100 for i = 0; i < len(pattern); i++ {
101 switch pattern[i] {
102 case '\\':
103
104 if i+1 < len(pattern) {
105 i++
106 }
107 case '[':
108 inrange = true
109 case ']':
110 inrange = false
111 case '*':
112 if !inrange {
113 break Scan
114 }
115 }
116 }
117 return star, pattern[0:i], pattern[i:]
118 }
119
120
121
122
123 func matchChunk(chunk, s string) (rest string, ok bool, err error) {
124
125
126
127 failed := false
128 for len(chunk) > 0 {
129 if !failed && len(s) == 0 {
130 failed = true
131 }
132 switch chunk[0] {
133 case '[':
134
135 var r rune
136 if !failed {
137 var n int
138 r, n = utf8.DecodeRuneInString(s)
139 s = s[n:]
140 }
141 chunk = chunk[1:]
142
143 negated := false
144 if len(chunk) > 0 && chunk[0] == '^' {
145 negated = true
146 chunk = chunk[1:]
147 }
148
149 match := false
150 nrange := 0
151 for {
152 if len(chunk) > 0 && chunk[0] == ']' && nrange > 0 {
153 chunk = chunk[1:]
154 break
155 }
156 var lo, hi rune
157 if lo, chunk, err = getEsc(chunk); err != nil {
158 return "", false, err
159 }
160 hi = lo
161 if chunk[0] == '-' {
162 if hi, chunk, err = getEsc(chunk[1:]); err != nil {
163 return "", false, err
164 }
165 }
166 if lo <= r && r <= hi {
167 match = true
168 }
169 nrange++
170 }
171 if match == negated {
172 failed = true
173 }
174
175 case '?':
176 if !failed {
177 if s[0] == '/' {
178 failed = true
179 }
180 _, n := utf8.DecodeRuneInString(s)
181 s = s[n:]
182 }
183 chunk = chunk[1:]
184
185 case '\\':
186 chunk = chunk[1:]
187 if len(chunk) == 0 {
188 return "", false, ErrBadPattern
189 }
190 fallthrough
191
192 default:
193 if !failed {
194 if chunk[0] != s[0] {
195 failed = true
196 }
197 s = s[1:]
198 }
199 chunk = chunk[1:]
200 }
201 }
202 if failed {
203 return "", false, nil
204 }
205 return s, true, nil
206 }
207
208
209 func getEsc(chunk string) (r rune, nchunk string, err error) {
210 if len(chunk) == 0 || chunk[0] == '-' || chunk[0] == ']' {
211 err = ErrBadPattern
212 return
213 }
214 if chunk[0] == '\\' {
215 chunk = chunk[1:]
216 if len(chunk) == 0 {
217 err = ErrBadPattern
218 return
219 }
220 }
221 r, n := utf8.DecodeRuneInString(chunk)
222 if r == utf8.RuneError && n == 1 {
223 err = ErrBadPattern
224 }
225 nchunk = chunk[n:]
226 if len(nchunk) == 0 {
227 err = ErrBadPattern
228 }
229 return
230 }
231
View as plain text