sdp-io-0.2: SDP IO extension
Copyright(c) Andrey Mulik 2020
LicenseBSD-style
Maintainerwork.a.mulik@gmail.com
Portabilitynon-portable (GHC extensions)
Safe HaskellSafe-Inferred
LanguageHaskell2010

Data.FilePath

Description

Data.FilePath provides pattern synonyms similar to System.FilePath functions. So you don't need the filepath package, when use sdp-io.

Synopsis

FilePath

type FilePath = String #

File and directory names are values of type String, whose precise meaning is operating system dependent. Files can be opened, yielding a handle which can then be used to operate on the contents of that file.

isPathSep :: Char -> Bool Source #

Separator check.

isValid :: FilePath -> Bool Source #

Is a FilePath valid? This function checks for invalid names, invalid characters, but doesn't check if length limits are exceeded, as these are typically filesystem dependent.

isValid "" == False
isValid "\0" == False

Posix: > isValid "/random_ path:*" == True > isValid x => not (null x)

Windows: > isValid "c:\test" == True > isValid "c:\test:of_test" == False > isValid "test*" == False > isValid "c:\test\nul" == False > isValid "c:\test\prn.txt" == False > isValid "c:\nul\file" == False > isValid "\\" == False > isValid "\\\foo" == False > isValid "\\?\D:file" == False > isValid "footbar" == False > isValid "nul .txt" == False > isValid " nul.txt" == True

isRelative :: FilePath -> Bool Source #

Is a path relative, or is it fixed to the root?

Posix: > isRelative "test/path" == True > isRelative "/test" == False > isRelative "/" == False

Windows:

isRelative "path\\test" == True
isRelative "c:\\test" == False
isRelative "c:test" == True
isRelative "c:\\" == False
isRelative "c:/" == False
isRelative "c:" == True
isRelative "\\\\foo" == False
isRelative "\\\\?\\foo" == False
isRelative "\\\\?\\UNC\\foo" == False
isRelative "/foo" == True
isRelative "\\foo" == True
  • "A UNC name of any format [is never relative]."
  • "You can't use the "\?" prefix with a relative path."

makeValid :: FilePath -> FilePath Source #

Take a FilePath and make it vali, doesn't change already valid FilePaths:

isValid (makeValid x) == True
isValid x => makeValid x == x
makeValid "" == "_"
makeValid "file\0name" == "file_name"

Windows: > makeValid "c:\already\valid" == "c:\already\valid" > makeValid "c:\test:of_test" == "c:\test_of_test" > makeValid "test*" == "test_" > makeValid "c:\test\nul" == "c:\test\nul_" > makeValid "c:\test\prn.txt" == "c:\test\prn_.txt" > makeValid "c:\testprn.txt" == "c:\testprn_.txt" > makeValid "c:\nul\file" == "c:\nul_\file" > makeValid "\\\foo" == "\\drive" > makeValid "\\?\D:file" == "\\?\D:\file" > makeValid "nul .txt" == "nul _.txt"

normalise :: FilePath -> FilePath Source #

Normalise a file name: * // outside of the drive can be made blank * / -> PathSep * ./ -> ""

normalise "." == "."

Posix: > normalise "file\test///" == "file\test" > normalise "file.test" == "file/test" > normalise "testfile..bobfred" == "testfile..bobfred" > normalise "..bobfred" == "..bobfred" > normalise ".bobfred" == "bobfred/"

normalise "./" == "./"
normalise "./." == "./"
normalise "/./" == "/"
normalise "/" == "/"
normalise "bob/fred/." == "bob/fred/"
normalise "//home" == "/home"

Windows: > normalise "c:\file/bob\" == "C:\file\bob\" > normalise "c:\" == "C:\" > normalise "C:.\" == "C:" > normalise "\\server\test" == "\\server\test" > normalise "/servertest" == "\\server\test" > normalise "c:/file" == "C:\file" > normalise "/file" == "\file" > normalise "\" == "\" > normalise "." == "\"

equalFilePath :: FilePath -> FilePath -> Bool Source #

Equality of two FilePaths. If you call System.Directory.canonicalizePath first this has a much better chance of working. Note that this doesn't follow symlinks or DOSNAMEs.

x == y ==> equalFilePath x y
normalise x == normalise y ==> equalFilePath x y
equalFilePath "foo" "foo/"
not (equalFilePath "foo" "/foo")

Posix: > not (equalFilePath "foo" FOO)

Windows: > equalFilePath "foo" FOO > not (equalFilePath "C:" "C:/")

makeRelative :: FilePath -> FilePath -> FilePath Source #

Contract a filename, based on a relative path. Note that the resulting path will never introduce .. paths, as the presence of symlinks means ../b may not reach a/b if it starts from a/c. For a worked example see this blog post.

The corresponding makeAbsolute function can be found in System.Directory.

makeRelative "/directory" "/directory/file.ext" == "file.ext"
Valid x => makeRelative (takeDirectory x) x `equalFilePath` takeFileName x
makeRelative x x == "."
Valid x y => equalFilePath x y || (isRelative x && makeRelative y x == x) || equalFilePath (y </> makeRelative y x) x

Posix: > makeRelative "Home" "homebob" == "home/bob" > makeRelative "home" "homebobfoobar" == "bobfoobar" > makeRelative "/fred" "bob" == "bob" > makeRelative "filetest" "filetest/fred" == "fred" > makeRelative "filetest" "filetestfred" == "fred/" > makeRelative "somepath" "somepathabc" == "ab/c"

Windows: > makeRelative "C:\Home" "c:\home\bob" == "bob" > makeRelative "C:\Home" "c:homebob" == "bob" > makeRelative "C:\Home" "D:\Home\Bob" == "D:\Home\Bob" > makeRelative "C:\Home" "C:Home\Bob" == "C:Home\Bob" > makeRelative "Home" "home/bob" == "bob" > makeRelative "" "" == "/"

$PATH

getPath :: IO [FilePath] Source #

Get a list of FilePaths in the $PATH.

Patterns

pattern PathSep :: Char Source #

Default path separator.

Drive

pattern (:\\) :: FilePath -> FilePath -> FilePath Source #

Windows: > "" :\ "file" <- "file" > "c:" :\ "file" <- "c:file" > "c:\" :\ "file" <- "c:\file" > "\\shared\" :\ "test" <- "\\shared\test" > "\\shared" :\ "" <- "\\shared" > "\\?\UNC\shared\" :\ "file" <- "\\?\UNC\shared\file" > "\\?\" :\ UNCshared\\file <- "\\?\UNCshared\file" > "\\?\d:\" :\ "file" <- "\\?\d:\file" > "" :\ "d" <- "d"

Posix: > "" :\ "test" <- "test" > "/" :\ "test" <- "/test" > "" :\ "testfile" <- "testfile" > "" :\ "file" <- "file"

Extensions

pattern (:.) :: FilePath -> String -> FilePath infixr 7 Source #

Add an extension.

"/directory/path" :. "ext" == "/directory/path.ext"
"file.txt" :. "tar" == "file.txt.tar"
"file." :. ".tar" == "file..tar"
"file" :. ".xml" == "file.xml"
"/" :. "d" == "/.d"

Windows: > "\\share" :. ".txt" == "\\share\.txt"

Split on the extension. Note that points are discarded.

("file" :. "") <- "file"
("out" :. "txt") <- "out.txt"
("/etc/pam.d/" :. "") <- "/etc/pam.d/"
("dir.d/fnya" :. "") <- "dir.d/fnya"
("dir.d/data" :. "bak") <- "dir.d/data.bak"
("/directory/path" :. "ext") <- "/directory/path.ext"
("file/path.txt.alice" :. "bob") <- "file/path.txt.alice.bob"

Note that filenames starting with a . are handled correctly:

(".bashrc" :. "") <- ".bashrc"

pattern (:..) :: FilePath -> [String] -> FilePath infixr 7 Source #

Add an extensions.

x :.. [] = x -- forall x
path :.. [ext] = path :. ext -- forall path ext
"dir/file" :.. ["fb2", "zip"] == "dir/file.fb2.zip"
"dir/file" :.. ["fb2", ".zip"] == "dir/file.fb2.zip"
"pacman" :.. ["pkg", "tar", "xz"] == "pacman.pkg.tar.xz"

Split on the extensions. Note that points are discarded.

("file" :.. []) <- "file"
("out" :.. ["txt"]) <- "out.txt"
("/etc/pam.d/" :.. []) <- "/etc/pam.d/"
("dir.d/fnya" :.. []) <- "dir.d/fnya"
("dir.d/data" :.. ["bak"]) <- "dir.d/data.bak"
("/directory/path" :.. ["ext"]) <- "/directory/path.ext"
("file/path." :.. ["txt", "alice", "bob"]) <- "file/path.txt.alice.bob"

This function separates the extensions and also considers the case when the file name begins with a period.

splitExtensions "file/.path.txt.alice.bob" == ("file/", ".path.txt.alice.bob")
("file/.path" :.. [txt, alice, bob]) <- "file/.path.txt.alice.bob"
splitExtensions ".bashrc" == ("", ".bashrc")
(".bashrc" :.. []) <- ".bashrc"

Split path

pattern (:/) :: FilePath -> FilePath -> FilePath infixr 5 Source #

Split a filename into directory and file. The first component will often end with a trailing slash.

"/directory/" :/ "file.ext" <- "/directory/file.ext"
"file/" :/ "bob.txt" <- "file/bob.txt"
"./" :/ "bob" <- "bob"

Posix: > "" : "" <- "/"

Windows: > "c:" :/ "" <- "c:"

Combine two paths with a path separator.

If the second path looks like an absolute path or a drive, then it returns the second.

"directory" :/ "/file.ext" == "/file.ext"

Posix: > "directory" : "file.ext" == "directoryfile.ext" > "" : "tmp" == "/tmp" > "x:" : "foo" == "x:foo" > "home" : "user" == "/user" > "home" : "user" == "homeuser"

Windows: > "directory" : "file.ext" == "/directory\file.ext" > "C:\foo" :/ "bar" == "C:\foo\bar" > "home" :/ "C:\bob" == "C:\bob" > "home" :/ "bob" == "home\bob"

"C:\\home" :/ "\\bob" == "\\bob"
"home" :/ "\\bob" == "\\bob"
"home" :/ "/bob" == "/bob"
"D:\\foo" :/ "C:bar" == "C:bar"
"C:\\foo" :/ "C:bar" == "C:bar"

pattern (://) :: [FilePath] -> FilePath -> FilePath infixr 5 Source #

Splits/joins directories and a file name.

pattern Path :: [FilePath] -> FilePath Source #

Separates filepath into a search path - list of ancestors with trailing separators and file name (if any):

Posix: > Path ["", "home", "user", ".ghci"] <- "homeuser.ghci" > Path ["", "home", "user"] <- "homeuser" > Path ["", "home", "user"] <- "homeuser"

Windows: > Path ["C:\", "home\", "user\"] <- "C:\home\user\" > Path ["C:\", "home\", "user"] <- "C:\home\user"

Path concatenates the file path regardless of a trailing separator.

pattern Dirs :: [FilePath] -> FilePath Source #

Separates filepath into a search path - list of ancestors without trailing separators and file name (if any):

Posix: > Dirs ["", "home", "user", ".ghci"] <- "homeuser.ghci" > Dirs ["", "home", "user"] <- "homeuser" > Dirs ["", "home", "user"] <- "home/user"

Windows: > Dirs ["C:\", "home", "user"] <- "C:\home\user\" > Dirs ["C:\","home","user"] <- "C:\home\user"

Dirs concatenates the file path regardless of a trailing separator.