1 {-# OPTIONS_GHC -fno-implicit-prelude #-}
2 -----------------------------------------------------------------------------
4 -- Module : System.Directory.Internals
5 -- Copyright : (c) The University of Glasgow 2005
6 -- License : BSD-style (see the file libraries/base/LICENSE)
8 -- Maintainer : libraries@haskell.org
10 -- Portability : portable
12 -- System-independent pathname manipulations.
14 -----------------------------------------------------------------------------
17 module System.Directory.Internals (
25 #if __GLASGOW_HASKELL__
27 import GHC.IOBase (FilePath)
31 -- | The 'joinFileName' function is the opposite of 'splitFileName'.
32 -- It joins directory and file names to form a complete file path.
34 -- The general rule is:
36 -- > dir `joinFileName` basename == path
38 -- > (dir,basename) = splitFileName path
40 -- There might be an exceptions to the rule but in any case the
41 -- reconstructed path will refer to the same object (file or directory).
42 -- An example exception is that on Windows some slashes might be converted
44 joinFileName :: String -> String -> FilePath
45 joinFileName "" fname = fname
46 joinFileName "." fname = fname
47 joinFileName dir "" = dir
48 joinFileName dir fname
49 | isPathSeparator (last dir) = dir++fname
50 | otherwise = dir++pathSeparator:fname
52 -- | The 'joinFileExt' function is the opposite of 'splitFileExt'.
53 -- It joins a file name and an extension to form a complete file path.
55 -- The general rule is:
57 -- > filename `joinFileExt` ext == path
59 -- > (filename,ext) = splitFileExt path
60 joinFileExt :: String -> String -> FilePath
61 joinFileExt path "" = path
62 joinFileExt path ext = path ++ '.':ext
64 -- | Gets this path and all its parents.
65 -- The function is useful in case if you want to create
66 -- some file but you aren\'t sure whether all directories
67 -- in the path exist or if you want to search upward for some file.
73 -- > pathParents "/" == ["/"]
74 -- > pathParents "/dir1" == ["/", "/dir1"]
75 -- > pathParents "/dir1/dir2" == ["/", "/dir1", "/dir1/dir2"]
76 -- > pathParents "dir1" == [".", "dir1"]
77 -- > pathParents "dir1/dir2" == [".", "dir1", "dir1/dir2"]
81 -- > pathParents "c:" == ["c:."]
82 -- > pathParents "c:\\" == ["c:\\"]
83 -- > pathParents "c:\\dir1" == ["c:\\", "c:\\dir1"]
84 -- > pathParents "c:\\dir1\\dir2" == ["c:\\", "c:\\dir1", "c:\\dir1\\dir2"]
85 -- > pathParents "c:dir1" == ["c:.","c:dir1"]
86 -- > pathParents "dir1\\dir2" == [".", "dir1", "dir1\\dir2"]
88 -- Note that if the file is relative then the current directory (\".\")
89 -- will be explicitly listed.
90 pathParents :: FilePath -> [FilePath]
92 root'' : map ((++) root') (dropEmptyPath $ inits path')
94 #ifdef mingw32_HOST_OS
95 (root,path) = case break (== ':') p of
96 (path, "") -> ("",path)
97 (root,_:path) -> (root++":",path)
101 (root',root'',path') = case path of
102 (c:path) | isPathSeparator c -> (root++[pathSeparator],root++[pathSeparator],path)
103 _ -> (root ,root++"." ,path)
105 dropEmptyPath ("":paths) = paths
106 dropEmptyPath paths = paths
108 inits :: String -> [String]
113 ".." -> map (joinFileName pre) (dropEmptyPath $ inits suf)
114 _ -> "" : map (joinFileName pre) (inits suf)
116 (pre,suf) = case break isPathSeparator cs of
117 (pre,"") -> (pre, "")
118 (pre,_:suf) -> (pre,suf)
120 --------------------------------------------------------------
122 --------------------------------------------------------------
124 -- | The function splits the given string to substrings
125 -- using the 'searchPathSeparator'.
126 parseSearchPath :: String -> [FilePath]
127 parseSearchPath path = split searchPathSeparator path
129 split :: Char -> String -> [String]
133 _:rest' -> chunk : split c rest'
135 (chunk, rest) = break (==c) s
137 --------------------------------------------------------------
139 --------------------------------------------------------------
141 -- | Checks whether the character is a valid path separator for the host
142 -- platform. The valid character is a 'pathSeparator' but since the Windows
143 -- operating system also accepts a slash (\"\/\") since DOS 2, the function
144 -- checks for it on this platform, too.
145 isPathSeparator :: Char -> Bool
146 isPathSeparator ch = ch == pathSeparator || ch == '/'
148 -- | Provides a platform-specific character used to separate directory levels in
149 -- a path string that reflects a hierarchical file system organization. The
150 -- separator is a slash (@\"\/\"@) on Unix and Macintosh, and a backslash
151 -- (@\"\\\"@) on the Windows operating system.
152 pathSeparator :: Char
153 #ifdef mingw32_HOST_OS
159 -- ToDo: This should be determined via autoconf (PATH_SEPARATOR)
160 -- | A platform-specific character used to separate search path strings in
161 -- environment variables. The separator is a colon (@\":\"@) on Unix and
162 -- Macintosh, and a semicolon (@\";\"@) on the Windows operating system.
163 searchPathSeparator :: Char
164 #ifdef mingw32_HOST_OS
165 searchPathSeparator = ';'
167 searchPathSeparator = ':'
170 -- ToDo: This should be determined via autoconf (AC_EXEEXT)
171 -- | Extension for executable files
172 -- (typically @\"\"@ on Unix and @\"exe\"@ on Windows or OS\/2)
173 exeExtension :: String
174 #ifdef mingw32_HOST_OS