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