! Copyright (C) 2007, 2009 Slava Pestov, Daniel Ehrenberg.
! See http://factorcode.org/license.txt for BSD license.
USING: accessors arrays combinators combinators.short-circuit
-io.directories io.files io.files.info io.pathnames kernel locals
-make peg.ebnf regexp regexp.combinators sequences splitting
-strings system unicode.case ;
+io.directories io.files io.files.info io.pathnames kernel
+make peg.ebnf regexp regexp.combinators sequences strings system
+unicode multiline ;
IN: globs
: not-path-separator ( -- sep )
- os windows? R/ [^\\/\\]/ R/ [^\\/]/ ? ; foldable
+ os windows? R/ [^\/\\]/ R/ [^\/]/ ? ; foldable
-EBNF: <glob>
+: wild-path-separator ( -- sep )
+ os windows? R/ [^\/\\][\/\\]|[^\/\\]/ R/ [^\/][\/]|[^\/]/ ? ; foldable
+
+EBNF: <glob> [=[
Character = "\\" .:c => [[ c 1string <literal> ]]
| !(","|"}") . => [[ 1string <literal> ]]
AlternationBody = Concatenation:c "," AlternationBody:a => [[ a c prefix ]]
| Concatenation => [[ 1array ]]
-Element = "*" => [[ not-path-separator <zero-or-more> ]]
+Element = "**" => [[ wild-path-separator <zero-or-more> ]]
+ | "*" => [[ not-path-separator <zero-or-more> ]]
| "?" => [[ not-path-separator ]]
| "[" CharClass:c "]" => [[ c ]]
| "{" AlternationBody:b "}" => [[ b <or> ]]
Main = Concatenation End
-;EBNF
+]=]
: glob-matches? ( input glob -- ? )
[ >case-fold ] bi@ <glob> matches? ;
! TODO: make case-fold an option, off by default
! TODO: maybe make case-fold an option on regexp
-DEFER: glob-directory%
+DEFER: glob%
: glob-entries ( path -- entries )
directory-entries [ name>> "." head? ] reject ;
-: ?glob-directory% ( root remaining entry -- )
- directory? [
- glob-directory%
+: ?glob% ( root remaining entry -- )
+ over empty? [
+ 2drop ,
] [
- empty? [ , ] [ drop ] if
+ directory? [ glob% ] [ 2drop ] if
] if ;
:: glob-wildcard% ( root globs -- )
dup ,
] [
entry directory? [
- dupd glob-directory%
+ dupd glob%
] [
drop
] if
} cond
{ [ entry directory? ] [ next-glob ] } 0&& [
- globs glob-directory%
+ globs glob%
] [
drop
] if
root glob-entries [| entry |
entry name>> >case-fold glob matches? [
root entry name>> append-path
- remaining entry ?glob-directory%
+ remaining entry ?glob%
] when
] each ;
:: glob-literal% ( root globs -- )
globs unclip :> ( remaining glob )
- root glob append-path dup exists? [
- remaining over file-info ?glob-directory%
+ root glob append-path dup file-exists? [
+ remaining over file-info ?glob%
] [
drop
] if ;
-: glob-directory% ( root globs -- )
+: glob% ( root globs -- )
dup ?first {
{ f [ 2drop ] }
{ "**" [ glob-wildcard% ] }
PRIVATE>
-: glob-directory ( glob -- files )
- glob-path [ glob-directory% ] { } make ;
+: glob ( glob -- files )
+ glob-path [
+ [ 1array f swap ] when-empty glob%
+ ] { } make ;