| 
									
										
										
										
											2009-03-02 16:31:28 -05:00
										 |  |  | ! Copyright (C) 2007, 2009 Slava Pestov, Daniel Ehrenberg. | 
					
						
							| 
									
										
										
										
											2007-11-28 02:12:42 -05:00
										 |  |  | ! See http://factorcode.org/license.txt for BSD license. | 
					
						
							| 
									
										
										
										
											2016-03-27 21:52:20 -04:00
										 |  |  | USING: accessors arrays combinators combinators.short-circuit | 
					
						
							|  |  |  | io.directories io.files io.files.info io.pathnames kernel locals | 
					
						
							| 
									
										
										
										
											2016-04-06 16:10:24 -04:00
										 |  |  | make peg.ebnf regexp regexp.combinators sequences strings system | 
					
						
							| 
									
										
										
										
											2017-08-05 23:23:57 -04:00
										 |  |  | unicode multiline ;
 | 
					
						
							| 
									
										
										
										
											2007-11-28 02:12:42 -05:00
										 |  |  | IN: globs | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-02-13 16:35:04 -05:00
										 |  |  | : not-path-separator ( -- sep )
 | 
					
						
							| 
									
										
										
										
											2019-03-21 16:29:15 -04:00
										 |  |  |     os windows? R/ [^\/\\]/ R/ [^\/]/ ? ; foldable
 | 
					
						
							| 
									
										
										
										
											2010-02-13 16:35:04 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-06 17:02:48 -04:00
										 |  |  | : wild-path-separator ( -- sep )
 | 
					
						
							| 
									
										
										
										
											2019-03-21 16:29:15 -04:00
										 |  |  |     os windows? R/ [^\/\\][\/\\]|[^\/\\]/ R/ [^\/][\/]|[^\/]/ ? ; foldable
 | 
					
						
							| 
									
										
										
										
											2016-04-06 17:02:48 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-05 23:23:57 -04:00
										 |  |  | EBNF: <glob> [=[ | 
					
						
							| 
									
										
										
										
											2007-11-28 02:12:42 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-03-02 16:31:28 -05:00
										 |  |  | Character = "\\" .:c => [[ c 1string <literal> ]] | 
					
						
							|  |  |  |           | !(","|"}") . => [[ 1string <literal> ]] | 
					
						
							| 
									
										
										
										
											2007-11-28 02:12:42 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-03-02 16:31:28 -05:00
										 |  |  | RangeCharacter = !("]") .
 | 
					
						
							| 
									
										
										
										
											2007-11-28 02:12:42 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-03-02 16:31:28 -05:00
										 |  |  | Range = RangeCharacter:a "-" RangeCharacter:b => [[ a b <char-range> ]] | 
					
						
							|  |  |  |       | RangeCharacter => [[ 1string <literal> ]] | 
					
						
							| 
									
										
										
										
											2007-11-28 02:12:42 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-03-02 16:31:28 -05:00
										 |  |  | StartRange = .:a "-" RangeCharacter:b => [[ a b <char-range> ]] | 
					
						
							|  |  |  |            | . => [[ 1string <literal> ]] | 
					
						
							| 
									
										
										
										
											2007-11-28 02:12:42 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-03-02 16:31:28 -05:00
										 |  |  | Ranges = StartRange:s Range*:r => [[ r s prefix ]] | 
					
						
							| 
									
										
										
										
											2007-11-28 02:12:42 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-03-02 16:31:28 -05:00
										 |  |  | CharClass = "^"?:n Ranges:e => [[ e <or> n [ <not> ] when ]] | 
					
						
							| 
									
										
										
										
											2007-11-28 02:12:42 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-03-02 16:31:28 -05:00
										 |  |  | AlternationBody = Concatenation:c "," AlternationBody:a => [[ a c prefix ]] | 
					
						
							|  |  |  |                 | Concatenation => [[ 1array ]] | 
					
						
							| 
									
										
										
										
											2007-11-28 02:12:42 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-06 17:02:48 -04:00
										 |  |  | Element = "**" => [[ wild-path-separator <zero-or-more> ]] | 
					
						
							|  |  |  |         | "*" => [[ not-path-separator <zero-or-more> ]] | 
					
						
							| 
									
										
										
										
											2010-02-13 16:35:04 -05:00
										 |  |  |         | "?" => [[ not-path-separator ]] | 
					
						
							| 
									
										
										
										
											2009-03-02 16:31:28 -05:00
										 |  |  |         | "[" CharClass:c "]" => [[ c ]] | 
					
						
							|  |  |  |         | "{" AlternationBody:b "}" => [[ b <or> ]] | 
					
						
							|  |  |  |         | Character | 
					
						
							| 
									
										
										
										
											2007-11-28 02:12:42 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-03-02 16:31:28 -05:00
										 |  |  | Concatenation = Element* => [[ <sequence> ]] | 
					
						
							| 
									
										
										
										
											2007-11-28 02:12:42 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2009-03-02 16:31:28 -05:00
										 |  |  | End = !(.) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Main = Concatenation End | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-05 23:23:57 -04:00
										 |  |  | ]=] | 
					
						
							| 
									
										
										
										
											2007-11-28 02:12:42 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | : glob-matches? ( input glob -- ? )
 | 
					
						
							| 
									
										
										
										
											2009-03-02 16:31:28 -05:00
										 |  |  |     [ >case-fold ] bi@ <glob> matches? ;
 | 
					
						
							| 
									
										
										
										
											2010-02-14 14:49:33 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | : glob-pattern? ( string -- ? )
 | 
					
						
							|  |  |  |     [ "\\*?[{" member? ] any? ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-27 21:52:20 -04:00
										 |  |  | <PRIVATE
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-28 09:38:05 -04:00
										 |  |  | ! TODO: simplify | 
					
						
							|  |  |  | ! TODO: handle two more test cases | 
					
						
							|  |  |  | ! TODO: make case-fold an option, off by default | 
					
						
							|  |  |  | ! TODO: maybe make case-fold an option on regexp | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-06 17:04:21 -04:00
										 |  |  | DEFER: glob% | 
					
						
							| 
									
										
										
										
											2016-03-27 21:52:20 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-28 11:01:28 -04:00
										 |  |  | : glob-entries ( path -- entries )
 | 
					
						
							|  |  |  |     directory-entries [ name>> "." head? ] reject ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-06 17:04:21 -04:00
										 |  |  | : ?glob% ( root remaining entry -- )
 | 
					
						
							| 
									
										
										
										
											2016-04-06 16:10:24 -04:00
										 |  |  |     over empty? [ | 
					
						
							|  |  |  |         2drop , | 
					
						
							| 
									
										
										
										
											2016-03-27 21:52:20 -04:00
										 |  |  |     ] [ | 
					
						
							| 
									
										
										
										
											2016-04-06 17:04:21 -04:00
										 |  |  |         directory? [ glob% ] [ 2drop ] if
 | 
					
						
							| 
									
										
										
										
											2016-03-27 21:52:20 -04:00
										 |  |  |     ] if ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | :: glob-wildcard% ( root globs -- )
 | 
					
						
							|  |  |  |     globs ?second :> next-glob | 
					
						
							|  |  |  |     next-glob dup pair? [ second ] [ drop f ] if :> next-glob-regexp | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-28 11:01:28 -04:00
										 |  |  |     root glob-entries [| entry | | 
					
						
							| 
									
										
										
										
											2016-03-27 21:52:20 -04:00
										 |  |  |         root entry name>> append-path | 
					
						
							|  |  |  |         { | 
					
						
							|  |  |  |             { [ next-glob not ] [ dup , ] } | 
					
						
							|  |  |  |             { [ next-glob empty? ] [ entry directory? [ dup , ] when ] } | 
					
						
							|  |  |  |             [ | 
					
						
							|  |  |  |                 next-glob-regexp [ | 
					
						
							|  |  |  |                     entry name>> >case-fold next-glob-regexp matches? | 
					
						
							|  |  |  |                 ] [ | 
					
						
							|  |  |  |                     { | 
					
						
							|  |  |  |                         [ next-glob "**" = ] | 
					
						
							|  |  |  |                         [ entry name>> next-glob = ] | 
					
						
							|  |  |  |                     } 0|| | 
					
						
							|  |  |  |                 ] if [ | 
					
						
							|  |  |  |                     globs 2 tail [ | 
					
						
							|  |  |  |                          dup , | 
					
						
							|  |  |  |                     ] [ | 
					
						
							|  |  |  |                         entry directory? [ | 
					
						
							| 
									
										
										
										
											2016-04-06 17:04:21 -04:00
										 |  |  |                             dupd glob% | 
					
						
							| 
									
										
										
										
											2016-03-27 21:52:20 -04:00
										 |  |  |                         ] [ | 
					
						
							|  |  |  |                             drop
 | 
					
						
							|  |  |  |                         ] if
 | 
					
						
							|  |  |  |                     ] if-empty
 | 
					
						
							|  |  |  |                 ] when
 | 
					
						
							|  |  |  |             ] | 
					
						
							|  |  |  |         } cond
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         { [ entry directory? ] [ next-glob ] } 0&& [ | 
					
						
							| 
									
										
										
										
											2016-04-06 17:04:21 -04:00
										 |  |  |             globs glob% | 
					
						
							| 
									
										
										
										
											2016-03-27 21:52:20 -04:00
										 |  |  |         ] [ | 
					
						
							|  |  |  |             drop
 | 
					
						
							|  |  |  |         ] if
 | 
					
						
							|  |  |  |     ] each ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | :: glob-pattern% ( root globs -- )
 | 
					
						
							|  |  |  |     globs unclip second :> ( remaining glob )
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-28 11:01:28 -04:00
										 |  |  |     root glob-entries [| entry | | 
					
						
							| 
									
										
										
										
											2016-03-27 21:52:20 -04:00
										 |  |  |         entry name>> >case-fold glob matches? [ | 
					
						
							|  |  |  |             root entry name>> append-path | 
					
						
							| 
									
										
										
										
											2016-04-06 17:04:21 -04:00
										 |  |  |             remaining entry ?glob% | 
					
						
							| 
									
										
										
										
											2016-03-27 21:52:20 -04:00
										 |  |  |         ] when
 | 
					
						
							|  |  |  |     ] each ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | :: glob-literal% ( root globs -- )
 | 
					
						
							|  |  |  |     globs unclip :> ( remaining glob )
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     root glob append-path dup exists? [ | 
					
						
							| 
									
										
										
										
											2016-04-06 17:04:21 -04:00
										 |  |  |         remaining over file-info ?glob% | 
					
						
							| 
									
										
										
										
											2016-03-27 21:52:20 -04:00
										 |  |  |     ] [ | 
					
						
							|  |  |  |         drop
 | 
					
						
							|  |  |  |     ] if ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-06 17:04:21 -04:00
										 |  |  | : glob% ( root globs -- )
 | 
					
						
							| 
									
										
										
										
											2016-03-27 21:52:20 -04:00
										 |  |  |     dup ?first { | 
					
						
							|  |  |  |         { f [ 2drop ] } | 
					
						
							|  |  |  |         { "**" [ glob-wildcard% ] } | 
					
						
							|  |  |  |         [ pair? [ glob-pattern% ] [ glob-literal% ] if ] | 
					
						
							|  |  |  |     } case ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | : split-glob ( glob -- path globs )
 | 
					
						
							|  |  |  |     { } [ | 
					
						
							|  |  |  |         over glob-pattern? | 
					
						
							|  |  |  |     ] [ | 
					
						
							|  |  |  |         [ | 
					
						
							| 
									
										
										
										
											2016-03-28 09:38:05 -04:00
										 |  |  |             dup [ path-separator? ] find-last drop
 | 
					
						
							| 
									
										
										
										
											2016-03-27 21:52:20 -04:00
										 |  |  |             [ cut rest ] [ "" swap ] if*
 | 
					
						
							|  |  |  |         ] dip swap prefix
 | 
					
						
							|  |  |  |     ] while ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | : glob-path ( glob -- path globs )
 | 
					
						
							|  |  |  |     split-glob [ | 
					
						
							|  |  |  |         dup { [ "**" = not ] [ glob-pattern? ] } 1&& [ | 
					
						
							|  |  |  |             dup >case-fold <glob> 2array
 | 
					
						
							|  |  |  |         ] when
 | 
					
						
							|  |  |  |     ] map ;
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | PRIVATE>
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-06 17:04:21 -04:00
										 |  |  | : glob ( glob -- files )
 | 
					
						
							| 
									
										
										
										
											2016-09-16 20:41:31 -04:00
										 |  |  |     glob-path [ | 
					
						
							|  |  |  |         [ 1array f swap ] when-empty glob% | 
					
						
							|  |  |  |     ] { } make ;
 |