1
2
3
4
5
6
7 package in_toto
8
9 import (
10 "errors"
11 "unicode/utf8"
12 )
13
14
15 var errBadPattern = errors.New("syntax error in pattern")
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 true, 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 for i := 0; i < len(name); 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 _, n := utf8.DecodeRuneInString(s)
178 s = s[n:]
179 }
180 chunk = chunk[1:]
181
182 case '\\':
183 chunk = chunk[1:]
184 if len(chunk) == 0 {
185 return "", false, errBadPattern
186 }
187 fallthrough
188
189 default:
190 if !failed {
191 if chunk[0] != s[0] {
192 failed = true
193 }
194 s = s[1:]
195 }
196 chunk = chunk[1:]
197 }
198 }
199 if failed {
200 return "", false, nil
201 }
202 return s, true, nil
203 }
204
205
206 func getEsc(chunk string) (r rune, nchunk string, err error) {
207 if len(chunk) == 0 || chunk[0] == '-' || chunk[0] == ']' {
208 err = errBadPattern
209 return
210 }
211 if chunk[0] == '\\' {
212 chunk = chunk[1:]
213 if len(chunk) == 0 {
214 err = errBadPattern
215 return
216 }
217 }
218 r, n := utf8.DecodeRuneInString(chunk)
219 if r == utf8.RuneError && n == 1 {
220 err = errBadPattern
221 }
222 nchunk = chunk[n:]
223 if len(nchunk) == 0 {
224 err = errBadPattern
225 }
226 return
227 }
228
View as plain text