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 for i := 0; i < len(pattern); i++ {
99 switch pattern[i] {
100 case '\\':
101
102 if i+1 < len(pattern) {
103 i++
104 }
105 case '[':
106 inrange = true
107 case ']':
108 inrange = false
109 case '*':
110 if !inrange {
111 return star, pattern[:i], pattern[i:]
112 }
113 }
114 }
115 return star, pattern, ""
116 }
117
118
119
120
121 func matchChunk(chunk, s string) (rest string, ok bool, err error) {
122
123
124
125 failed := false
126 for len(chunk) > 0 {
127 failed = failed || len(s) == 0
128 switch chunk[0] {
129 case '[':
130
131 var r rune
132 if !failed {
133 var n int
134 r, n = utf8.DecodeRuneInString(s)
135 s = s[n:]
136 }
137 chunk = chunk[1:]
138
139 negated := false
140 if len(chunk) > 0 && chunk[0] == '^' {
141 negated = true
142 chunk = chunk[1:]
143 }
144
145 match := false
146 nrange := 0
147 for {
148 if len(chunk) > 0 && chunk[0] == ']' && nrange > 0 {
149 chunk = chunk[1:]
150 break
151 }
152 var lo, hi rune
153 if lo, chunk, err = getEsc(chunk); err != nil {
154 return "", false, err
155 }
156 hi = lo
157 if chunk[0] == '-' {
158 if hi, chunk, err = getEsc(chunk[1:]); err != nil {
159 return "", false, err
160 }
161 }
162 match = match || lo <= r && r <= hi
163 nrange++
164 }
165 failed = failed || match == negated
166
167 case '?':
168 if !failed {
169 failed = s[0] == '/'
170 _, n := utf8.DecodeRuneInString(s)
171 s = s[n:]
172 }
173 chunk = chunk[1:]
174
175 case '\\':
176 chunk = chunk[1:]
177 if len(chunk) == 0 {
178 return "", false, ErrBadPattern
179 }
180 fallthrough
181
182 default:
183 if !failed {
184 failed = chunk[0] != s[0]
185 s = s[1:]
186 }
187 chunk = chunk[1:]
188 }
189 }
190 if failed {
191 return "", false, nil
192 }
193 return s, true, nil
194 }
195
196
197 func getEsc(chunk string) (r rune, nchunk string, err error) {
198 if len(chunk) == 0 || chunk[0] == '-' || chunk[0] == ']' {
199 err = ErrBadPattern
200 return
201 }
202 if chunk[0] == '\\' {
203 chunk = chunk[1:]
204 if len(chunk) == 0 {
205 err = ErrBadPattern
206 return
207 }
208 }
209 r, n := utf8.DecodeRuneInString(chunk)
210 if r == utf8.RuneError && n == 1 {
211 err = ErrBadPattern
212 }
213 nchunk = chunk[n:]
214 if len(nchunk) == 0 {
215 err = ErrBadPattern
216 }
217 return
218 }
219
View as plain text