Browse Source

Add ch08/02ex02.hs

Piotr Orzechowski 2 years ago
parent
commit
9af96ad002
1 changed files with 94 additions and 0 deletions
  1. 94
    0
      ch08/02ex02.hs

+ 94
- 0
ch08/02ex02.hs View File

@@ -0,0 +1,94 @@
1
+-- file ch08/02ex02.hs
2
+
3
+
4
+module Glob (namesMatching) where
5
+
6
+
7
+import System.Directory
8
+    ( doesDirectoryExist
9
+    , doesFileExist
10
+    , getCurrentDirectory
11
+    , getDirectoryContents
12
+    )
13
+import System.FilePath
14
+    ( dropTrailingPathSeparator
15
+    , splitFileName
16
+    , (</>)
17
+    )
18
+import Control.Exception (handle)
19
+import Control.Monad (forM)
20
+import GlobRegex (matchesGlob)
21
+
22
+
23
+isPattern :: String -> Bool
24
+isPattern = any (`elem` "[*?")
25
+
26
+
27
+namesMatching :: String -> IO [String]
28
+namesMatching pat
29
+    | not (isPattern pat) =
30
+      do
31
+          exists <- doesNameExist pat
32
+          return (if exists then [pat] else [])
33
+    | otherwise =
34
+      do
35
+          case splitFileName pat of
36
+              ("", baseName) ->
37
+                  do
38
+                      curDir <- getCurrentDirectory
39
+                      listMatches curDir baseName
40
+
41
+              (dirName, baseName) ->
42
+                  do
43
+                      dirs <- if isPattern dirName
44
+                                  then namesMatching (dropTrailingPathSeparator dirName)
45
+                                  else return [dirName]
46
+                      let listDir = if isPattern baseName
47
+                                        then listMatches
48
+                                        else listPlain
49
+                      pathNames <- forM dirs $ \dir ->
50
+                          do
51
+                              baseNames <- listDir dir baseName
52
+                              return (map (dir </>) baseNames)
53
+                      return (concat pathNames)
54
+
55
+
56
+doesNameExist :: FilePath -> IO Bool
57
+doesNameExist name =
58
+    do
59
+        fileExists <- doesFileExist name
60
+        if fileExists
61
+            then return True
62
+            else doesDirectoryExist name
63
+-- doesNameExist = System.Posix.Files.fileExist
64
+
65
+
66
+listMatches :: FilePath -> String -> IO [String]
67
+listMatches dirName pat =
68
+    do
69
+        dirName' <- if null dirName
70
+                        then getCurrentDirectory
71
+                        else return dirName
72
+        handle (const (return []) :: IOError -> IO [String]) $
73
+            do
74
+                names <- getDirectoryContents dirName'
75
+                let names' = if isHidden pat
76
+                                 then filter isHidden names
77
+                                 else filter (not . isHidden) names
78
+                return (filter (`matchesGlob` pat) names')
79
+
80
+
81
+isHidden :: String -> Bool
82
+isHidden ('.':_) = True
83
+isHidden _       = False
84
+
85
+
86
+listPlain :: FilePath -> String -> IO [String]
87
+listPlain dirName baseName =
88
+    do
89
+        exists <- if null baseName
90
+                      then doesDirectoryExist dirName
91
+                      else doesNameExist (dirName </> baseName)
92
+        return (if exists then [baseName] else [])
93
+
94
+