1 # This file is part of Nit Language ( http://nitlanguage.org ).
3 # Copyright 2008 Etienne M. Gagnon <egagnon@j-meg.com>
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
9 # http://www.apache.org/licenses/LICENSE-2.0
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
19 { A glob
is a string pattern where
:
20 "*" is 0 or more character except
"/" (cannot be adjacent to another
"*")
21 "**/" is 0 or more directory levels
(must be preceded by
"/" or the start
)
22 "?" : any character except
"/"
26 "**/*.prm" => any
*.prm file
in current directory
or below
27 "/**/*.nit" => any
*.nit file
in the entire file system
28 "src/**/*.bak" => any
*.bak file
in the src subdirectory
29 "a**/" => invalid glob
(instead
, you might want to write
"a*/**/")
30 "a?*/" => any direct subdirectory that starts with an
"a",
31 and is at least
2 characters long
35 printn
("toto".match_glob
("t*o")) # prints => true
40 # class that encapsulates a glob pattern
42 var _chars
= new Array[GlobChar]
44 # the glob-chars of the pattern
49 # cached string representation
52 with error
(message
: String)
55 # contructor that expects the glob is a string
57 # calls error when the glob string is invalid
62 if not pattern
.valid_glob
then
63 error
("invalid glob pattern")
67 for c
in pattern
.chars
do
87 fun match
(string
: String): boolean
89 var pat_pos
= new GlobPosition(_chars
)
90 var str_pos
= new StringPosition(string
.chars
)
92 pat_pos
.match
(str_pos
)
93 on success
do return true
101 fun match_glob
(pattern
: String): Bool
102 with error
(message
: String)
105 # returns true if self matches the given glob pattern
107 # calls error when the glob pattern is invalid
110 var pat
= new Glob(pattern
)
111 on error
(message
) do error
(message
)
113 return pat
.match
(self)
119 # returns true if self is a valid glob
125 state
= state
.target
(c
.to_symbol
)
126 if state
== null then return false
136 # Char has a new super class
138 fun to_symbol
: Symbol
141 # converts self into a Symbol
144 if self == '/' then return slash
145 if self == '*' then return star
146 if self == '?' then return qmark
155 # super class of Char, which has an additional constant for '**'
159 # the constant for '**'
166 # class that encapsulate a position
170 fun next
do _pos
+= 1
171 fun prev
do _pos
-= 1
178 # class that encapsulate a position in a pattern
180 var _chars
: Array[GlobChar]
187 # class that encapsulate a position in a string
189 var _chars
: Array[Char]
191 fun match
(pattern
: GlobPosition)
195 # match the rest of this string with the rest of the given pattern
197 # calls success when there is a match
199 # the implemented algorithm does a recursive exhaustive search
200 # until a match is found.
203 if _pos
== _chars
.len
then
206 if pattern
._pos
== pattern
._chars
.len
then success
210 var pc
= pattern
._chars
[pattern
._pos
]
211 if pc
== '*' or pc
== dstar
or pc
== '/' then
217 else if pattern
._pos
!= pattern
._chars
.len
then
220 var sc
= _chars
[_pos
]
221 var pc
= pattern
._chars
[pattern
._pos
]
233 else if pc
== '*' then
241 else if pc
== '?' or sc
== pc
then
253 # Automaton for Glob validation
260 # automaton state class
262 const state0
, state1
, state2
, state3
, state4
, state5
, state6
264 # states of the automaton
266 fun target
(symbol
: Symbol): nullable State
268 # returns the target state, given a symbol
270 case state0
do return symbol
.state0_target
271 case state1
do return symbol
.state1_target
272 case state2
do return symbol
.state2_target
273 case state3
do return symbol
.state3_target
274 case state4
do return symbol
.state4_target
275 case state5
do return symbol
.state5_target
276 case state6
do return symbol
.state6_target
281 # returns true if self is an accept state
283 case state5
do return false
284 default
do return true
291 # automaton symbol class
293 const slash
, star
, qmark
, other
295 fun state0_target
: nullable State
297 # returns the target of state0 (start)
299 case slash
do return state1
300 case star
do return state2
301 case qmark
do return state3
302 case other
do return state4
303 default
do return null
305 fun state1_target
: nullable State
307 # returns the target of state1 (".../")
309 case star
do return state2
310 case qmark
do return state3
311 case other
do return state4
312 default
do return null
314 fun state2_target
: nullable State
316 # returns the target of state2 (".../*")
318 case slash
do return state1
319 case star
do return state5
320 case qmark
do return state3
321 case other
do return state4
322 default
do return null
324 fun state3_target
: nullable State
326 # returns the target of state3 ("...?")
328 case slash
do return state1
329 case star
do return state6
330 case qmark
do return state3
331 case other
do return state4
332 default
do return null
334 fun state4_target
: nullable State
336 # returns the target of state4 ("...o")
338 case slash
do return state1
339 case star
do return state6
340 case qmark
do return state3
341 case other
do return state4
342 default
do return null
344 fun state5_target
: nullable State
346 # returns the target of state5 (".../**")
348 case slash
do return state1
349 default
do return null
351 fun state6_target
: nullable State
353 # returns the target of state6 ("...o*" or "...?*")
355 case slash
do return state1
356 case qmark
do return state3
357 case other
do return state4
358 default
do return null