Working snapshot.

--HG--
extra : convert_revision : 49a538240310e9c819a2ad33fc4589ca824a8c3f
This commit is contained in:
Bryan O'Sullivan 2007-04-30 07:29:32 +00:00
parent 791977cd5c
commit 4a365311e6
2 changed files with 41 additions and 34 deletions

View file

@ -38,7 +38,7 @@ module System.FilePath.Find (
, linkTarget , linkTarget
, (~?) , (~~?)
, (/~?) , (/~?)
, (==?) , (==?)
, (/=?) , (/=?)
@ -52,7 +52,6 @@ module System.FilePath.Find (
, (.&.?) , (.&.?)
) where ) where
import qualified Control.Exception as E
import Control.Monad (foldM, forM, liftM, liftM2) import Control.Monad (foldM, forM, liftM, liftM2)
import Control.Monad.Fix (MonadFix) import Control.Monad.Fix (MonadFix)
import Control.Monad.State (State(..), evalState) import Control.Monad.State (State(..), evalState)
@ -60,11 +59,12 @@ import Data.Bits (Bits, (.&.))
import Data.List (sort) import Data.List (sort)
import System.Directory (getDirectoryContents) import System.Directory (getDirectoryContents)
import System.FilePath ((</>), takeDirectory, takeExtension, takeFileName) import System.FilePath ((</>), takeDirectory, takeExtension, takeFileName)
import System.IO.Unsafe (unsafeInterleaveIO, unsafePerformIO) import System.FilePath.Glob (GlobPattern, (~~), (/~))
import System.IO (hPutStrLn, stderr) import System.IO (hPutStrLn, stderr)
import System.IO.Unsafe (unsafeInterleaveIO, unsafePerformIO)
import qualified Control.Exception as E
import qualified System.Posix.Files as F import qualified System.Posix.Files as F
import qualified System.Posix.Types as T import qualified System.Posix.Types as T
import qualified System.FilePath.Glob as G
type Info = (FilePath, Int, F.FileStatus) type Info = (FilePath, Int, F.FileStatus)
@ -79,20 +79,22 @@ evalFI :: FindClause a
evalFI m p d s = evalState (runFI m) (p, d, s) evalFI m p d s = evalState (runFI m) (p, d, s)
mkFI :: (Info -> (a, Info)) -> FindClause a
mkFI = FI . State mkFI = FI . State
filePath :: FindClause FilePath filePath :: FindClause FilePath
filePath = mkFI $ \st@(p, _, _) -> (p, st) filePath = mkFI $ \st@(p, _, _) -> (p, st)
fileStatus :: FindClause F.FileStatus
fileStatus = mkFI $ \st@(_, _, s) -> (s, st)
depth :: FindClause Int depth :: FindClause Int
depth = mkFI $ \st@(_, d, _) -> (d, st) depth = mkFI $ \st@(_, d, _) -> (d, st)
fileStatus :: FindClause F.FileStatus
fileStatus = mkFI $ \st@(_, _, s) -> (s, st)
type FilterPredicate = FindClause Bool type FilterPredicate = FindClause Bool
type RecursionPredicate = FindClause Bool type RecursionPredicate = FindClause Bool
@ -254,18 +256,18 @@ liftOp :: Monad m => (a -> b -> c) -> m a -> b -> m c
liftOp f a b = a >>= \a' -> return (f a' b) liftOp f a b = a >>= \a' -> return (f a' b)
(~?) :: FindClause FilePath (~~?) :: FindClause FilePath
-> G.GlobPattern -> GlobPattern
-> FindClause Bool -> FindClause Bool
(~?) = liftOp G.match (~~?) = liftOp (~~)
infix 4 ~? infix 4 ~~?
(/~?) :: FindClause FilePath (/~?) :: FindClause FilePath
-> G.GlobPattern -> GlobPattern
-> FindClause Bool -> FindClause Bool
(/~?) = liftOp (\s p -> not (s `G.match` p)) (/~?) = liftOp (/~)
infix 4 /~? infix 4 /~?

View file

@ -1,6 +1,7 @@
module System.FilePath.Glob ( module System.FilePath.Glob (
GlobPattern GlobPattern
, match , (~~)
, (/~)
) where ) where
import Control.Arrow (second) import Control.Arrow (second)
@ -21,8 +22,6 @@ spanClass c = gs []
_ -> error "unterminated escape" _ -> error "unterminated escape"
| otherwise = gs (d:acc) ds | otherwise = gs (d:acc) ds
type CharRange = (Char, Char)
data Ix a => SRange a = SRange [a] [(a, a)] data Ix a => SRange a = SRange [a] [(a, a)]
deriving (Show) deriving (Show)
@ -57,7 +56,7 @@ parseGlob ('*':cs) = MatchDir : parseGlob cs
parseGlob ('?':cs) = MatchChar : parseGlob cs parseGlob ('?':cs) = MatchChar : parseGlob cs
parseGlob ('[':cs) = let (cc, ccs) = spanClass ']' cs parseGlob ('[':cs) = let (cc, ccs) = spanClass ']' cs
cls = case cc of cls = case cc of
('!':ccs) -> MatchClass False $ makeClass ccs ('!':ccs') -> MatchClass False $ makeClass ccs'
_ -> MatchClass True $ makeClass cc _ -> MatchClass True $ makeClass cc
in cls : parseGlob ccs in cls : parseGlob ccs
parseGlob ('(':cs) = let (gg, ggs) = spanClass ')' cs parseGlob ('(':cs) = let (gg, ggs) = spanClass ')' cs
@ -65,9 +64,9 @@ parseGlob ('(':cs) = let (gg, ggs) = spanClass ')' cs
where breakGroup :: String -> String -> [String] where breakGroup :: String -> String -> [String]
breakGroup acc [] = [reverse acc] breakGroup acc [] = [reverse acc]
breakGroup _ ['\\'] = error "group: unterminated escape" breakGroup _ ['\\'] = error "group: unterminated escape"
breakGroup acc ('\\':c:cs) = breakGroup (c:acc) cs breakGroup acc ('\\':c:cs') = breakGroup (c:acc) cs'
breakGroup acc ('|':cs) = reverse acc : breakGroup [] cs breakGroup acc ('|':cs') = reverse acc : breakGroup [] cs'
breakGroup acc (c:cs) = breakGroup (c:acc) cs breakGroup acc (c:cs') = breakGroup (c:acc) cs'
parseGlob ['\\'] = error "glob: unterminated escape" parseGlob ['\\'] = error "glob: unterminated escape"
parseGlob ('\\':c:cs) = MatchLiteral [c] : parseGlob cs parseGlob ('\\':c:cs) = MatchLiteral [c] : parseGlob cs
parseGlob (c:cs) = MatchLiteral [c] : parseGlob cs parseGlob (c:cs) = MatchLiteral [c] : parseGlob cs
@ -112,26 +111,32 @@ matchTerms (MatchClass k c:ts) cs = matchClass cs >>= matchTerms ts
where inClass = b `inSRange` c where inClass = b `inSRange` c
matchClass _ = fail "no match" matchClass _ = fail "no match"
matchTerms (MatchGroup g:ts) cs = matchGroup g cs >>= matchTerms ts matchTerms (MatchGroup g:ts) cs = matchGroup g cs >>= matchTerms ts
where matchGroup g as | any null g = return as where matchGroup g' as | any null g' = return as
matchGroup g (a:as) | a `elem` map head g = matchGroup g' (a:as) | a `elem` map head g' =
matchGroup (map tail g) as matchGroup (map tail g') as
matchGroup _ _ = fail "not in group" matchGroup _ _ = fail "not in group"
matchTerms [MatchAny] _ = return () matchTerms [MatchAny] _ = return ()
matchTerms (MatchAny:ts) cs = matchAny cs >>= matchTerms ts matchTerms (MatchAny:ts) cs = matchAny cs >>= matchTerms ts
where matchAny [] = fail "no match" where matchAny [] = fail "no match"
matchAny cs = case matchTerms ts cs of matchAny cs' = case matchTerms ts cs' of
Nothing -> matchAny (tail cs) Nothing -> matchAny (tail cs')
_ -> return cs _ -> return cs
matchTerms [MatchDir] cs | pathSeparator `elem` cs = fail "path separator" matchTerms [MatchDir] cs | pathSeparator `elem` cs = fail "path separator"
| otherwise = return () | otherwise = return ()
matchTerms (MatchDir:ts) cs = matchDir cs >>= matchTerms ts matchTerms (MatchDir:ts) cs = matchDir cs >>= matchTerms ts
where matchDir [] = fail "no match" where matchDir [] = fail "no match"
matchDir (c:_) | c == pathSeparator = fail "path separator" matchDir (c:_) | c == pathSeparator = fail "path separator"
matchDir cs = case matchTerms ts cs of matchDir cs' = case matchTerms ts cs' of
Nothing -> matchDir $ tail cs Nothing -> matchDir $ tail cs'
_ -> return cs _ -> return cs'
matchTerms (MatchChar:_) [] = fail "end of input"
matchTerms (MatchChar:ts) (_:cs) = matchTerms ts cs
match :: GlobPattern -> FilePath -> Bool (~~) :: FilePath -> GlobPattern -> Bool
match pat name = let terms = simplifyTerms (parseGlob pat) name ~~ pat = let terms = simplifyTerms (parseGlob pat)
in (isJust . matchTerms terms) name in (isJust . matchTerms terms) name
(/~) :: FilePath -> GlobPattern -> Bool
(/~) = (not . ) . (~~)