{-# LANGUAGE PatternGuards #-}
module System.FilePath.Posix
(
FilePath,
pathSeparator, pathSeparators, isPathSeparator,
searchPathSeparator, isSearchPathSeparator,
extSeparator, isExtSeparator,
splitSearchPath, getSearchPath,
splitExtension,
takeExtension, replaceExtension, (-<.>), dropExtension, addExtension, hasExtension, (<.>),
splitExtensions, dropExtensions, takeExtensions, replaceExtensions, isExtensionOf,
stripExtension,
splitFileName,
takeFileName, replaceFileName, dropFileName,
takeBaseName, replaceBaseName,
takeDirectory, replaceDirectory,
combine, (</>),
splitPath, joinPath, splitDirectories,
splitDrive, joinDrive,
takeDrive, hasDrive, dropDrive, isDrive,
hasTrailingPathSeparator,
addTrailingPathSeparator,
dropTrailingPathSeparator,
normalise, equalFilePath,
makeRelative,
isRelative, isAbsolute,
isValid, makeValid
)
where
import Data.Char(toLower, toUpper, isAsciiLower, isAsciiUpper)
import Data.Maybe(isJust)
import Data.List(stripPrefix, isSuffixOf)
import System.Environment(getEnv)
infixr 7 <.>, -<.>
infixr 5 </>
isPosix :: Bool
isPosix :: Bool
isPosix = Bool -> Bool
not Bool
isWindows
isWindows :: Bool
isWindows :: Bool
isWindows = Bool
False
pathSeparator :: Char
pathSeparator :: Char
pathSeparator = if Bool
isWindows then Char
'\\' else Char
'/'
pathSeparators :: [Char]
pathSeparators :: [Char]
pathSeparators = if Bool
isWindows then [Char]
"\\/" else [Char]
"/"
isPathSeparator :: Char -> Bool
isPathSeparator :: Char -> Bool
isPathSeparator Char
'/' = Bool
True
isPathSeparator Char
'\\' = Bool
isWindows
isPathSeparator Char
_ = Bool
False
searchPathSeparator :: Char
searchPathSeparator :: Char
searchPathSeparator = if Bool
isWindows then Char
';' else Char
':'
isSearchPathSeparator :: Char -> Bool
isSearchPathSeparator :: Char -> Bool
isSearchPathSeparator = (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
searchPathSeparator)
extSeparator :: Char
extSeparator :: Char
extSeparator = Char
'.'
isExtSeparator :: Char -> Bool
isExtSeparator :: Char -> Bool
isExtSeparator = (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
extSeparator)
splitSearchPath :: String -> [FilePath]
splitSearchPath :: [Char] -> [[Char]]
splitSearchPath = [Char] -> [[Char]]
f
where
f :: [Char] -> [[Char]]
f [Char]
xs = case (Char -> Bool) -> [Char] -> ([Char], [Char])
forall a. (a -> Bool) -> [a] -> ([a], [a])
break Char -> Bool
isSearchPathSeparator [Char]
xs of
([Char]
pre, [] ) -> [Char] -> [[Char]]
g [Char]
pre
([Char]
pre, Char
_:[Char]
post) -> [Char] -> [[Char]]
g [Char]
pre [[Char]] -> [[Char]] -> [[Char]]
forall a. [a] -> [a] -> [a]
++ [Char] -> [[Char]]
f [Char]
post
g :: [Char] -> [[Char]]
g [Char]
"" = [[Char]
"." | Bool
isPosix]
g (Char
'\"':x :: [Char]
x@(Char
_:[Char]
_)) | Bool
isWindows Bool -> Bool -> Bool
&& [Char] -> Char
forall a. [a] -> a
last [Char]
x Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
'\"' = [[Char] -> [Char]
forall a. [a] -> [a]
init [Char]
x]
g [Char]
x = [[Char]
x]
getSearchPath :: IO [FilePath]
getSearchPath :: IO [[Char]]
getSearchPath = ([Char] -> [[Char]]) -> IO [Char] -> IO [[Char]]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap [Char] -> [[Char]]
splitSearchPath ([Char] -> IO [Char]
getEnv [Char]
"PATH")
splitExtension :: FilePath -> (String, String)
splitExtension :: [Char] -> ([Char], [Char])
splitExtension [Char]
x = case [Char]
nameDot of
[Char]
"" -> ([Char]
x,[Char]
"")
[Char]
_ -> ([Char]
dir [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char] -> [Char]
forall a. [a] -> [a]
init [Char]
nameDot, Char
extSeparator Char -> [Char] -> [Char]
forall a. a -> [a] -> [a]
: [Char]
ext)
where
([Char]
dir,[Char]
file) = [Char] -> ([Char], [Char])
splitFileName_ [Char]
x
([Char]
nameDot,[Char]
ext) = (Char -> Bool) -> [Char] -> ([Char], [Char])
forall a. (a -> Bool) -> [a] -> ([a], [a])
breakEnd Char -> Bool
isExtSeparator [Char]
file
takeExtension :: FilePath -> String
takeExtension :: [Char] -> [Char]
takeExtension = ([Char], [Char]) -> [Char]
forall a b. (a, b) -> b
snd (([Char], [Char]) -> [Char])
-> ([Char] -> ([Char], [Char])) -> [Char] -> [Char]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Char] -> ([Char], [Char])
splitExtension
(-<.>) :: FilePath -> String -> FilePath
-<.> :: [Char] -> [Char] -> [Char]
(-<.>) = [Char] -> [Char] -> [Char]
replaceExtension
replaceExtension :: FilePath -> String -> FilePath
replaceExtension :: [Char] -> [Char] -> [Char]
replaceExtension [Char]
x [Char]
y = [Char] -> [Char]
dropExtension [Char]
x [Char] -> [Char] -> [Char]
<.> [Char]
y
(<.>) :: FilePath -> String -> FilePath
<.> :: [Char] -> [Char] -> [Char]
(<.>) = [Char] -> [Char] -> [Char]
addExtension
dropExtension :: FilePath -> FilePath
dropExtension :: [Char] -> [Char]
dropExtension = ([Char], [Char]) -> [Char]
forall a b. (a, b) -> a
fst (([Char], [Char]) -> [Char])
-> ([Char] -> ([Char], [Char])) -> [Char] -> [Char]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Char] -> ([Char], [Char])
splitExtension
addExtension :: FilePath -> String -> FilePath
addExtension :: [Char] -> [Char] -> [Char]
addExtension [Char]
file [Char]
"" = [Char]
file
addExtension [Char]
file xs :: [Char]
xs@(Char
x:[Char]
_) = [Char] -> [Char] -> [Char]
joinDrive [Char]
a [Char]
res
where
res :: [Char]
res = if Char -> Bool
isExtSeparator Char
x then [Char]
b [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
xs
else [Char]
b [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char
extSeparator] [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
xs
([Char]
a,[Char]
b) = [Char] -> ([Char], [Char])
splitDrive [Char]
file
hasExtension :: FilePath -> Bool
hasExtension :: [Char] -> Bool
hasExtension = (Char -> Bool) -> [Char] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any Char -> Bool
isExtSeparator ([Char] -> Bool) -> ([Char] -> [Char]) -> [Char] -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Char] -> [Char]
takeFileName
isExtensionOf :: String -> FilePath -> Bool
isExtensionOf :: [Char] -> [Char] -> Bool
isExtensionOf ext :: [Char]
ext@(Char
'.':[Char]
_) = [Char] -> [Char] -> Bool
forall a. Eq a => [a] -> [a] -> Bool
isSuffixOf [Char]
ext ([Char] -> Bool) -> ([Char] -> [Char]) -> [Char] -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Char] -> [Char]
takeExtensions
isExtensionOf [Char]
ext = [Char] -> [Char] -> Bool
forall a. Eq a => [a] -> [a] -> Bool
isSuffixOf (Char
'.'Char -> [Char] -> [Char]
forall a. a -> [a] -> [a]
:[Char]
ext) ([Char] -> Bool) -> ([Char] -> [Char]) -> [Char] -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Char] -> [Char]
takeExtensions
stripExtension :: String -> FilePath -> Maybe FilePath
stripExtension :: [Char] -> [Char] -> Maybe [Char]
stripExtension [] [Char]
path = [Char] -> Maybe [Char]
forall a. a -> Maybe a
Just [Char]
path
stripExtension ext :: [Char]
ext@(Char
x:[Char]
_) [Char]
path = [Char] -> [Char] -> Maybe [Char]
forall a. Eq a => [a] -> [a] -> Maybe [a]
stripSuffix [Char]
dotExt [Char]
path
where dotExt :: [Char]
dotExt = if Char -> Bool
isExtSeparator Char
x then [Char]
ext else Char
'.'Char -> [Char] -> [Char]
forall a. a -> [a] -> [a]
:[Char]
ext
splitExtensions :: FilePath -> (FilePath, String)
splitExtensions :: [Char] -> ([Char], [Char])
splitExtensions [Char]
x = ([Char]
a [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
c, [Char]
d)
where
([Char]
a,[Char]
b) = [Char] -> ([Char], [Char])
splitFileName_ [Char]
x
([Char]
c,[Char]
d) = (Char -> Bool) -> [Char] -> ([Char], [Char])
forall a. (a -> Bool) -> [a] -> ([a], [a])
break Char -> Bool
isExtSeparator [Char]
b
dropExtensions :: FilePath -> FilePath
dropExtensions :: [Char] -> [Char]
dropExtensions = ([Char], [Char]) -> [Char]
forall a b. (a, b) -> a
fst (([Char], [Char]) -> [Char])
-> ([Char] -> ([Char], [Char])) -> [Char] -> [Char]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Char] -> ([Char], [Char])
splitExtensions
takeExtensions :: FilePath -> String
takeExtensions :: [Char] -> [Char]
takeExtensions = ([Char], [Char]) -> [Char]
forall a b. (a, b) -> b
snd (([Char], [Char]) -> [Char])
-> ([Char] -> ([Char], [Char])) -> [Char] -> [Char]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Char] -> ([Char], [Char])
splitExtensions
replaceExtensions :: FilePath -> String -> FilePath
replaceExtensions :: [Char] -> [Char] -> [Char]
replaceExtensions [Char]
x [Char]
y = [Char] -> [Char]
dropExtensions [Char]
x [Char] -> [Char] -> [Char]
<.> [Char]
y
isLetter :: Char -> Bool
isLetter :: Char -> Bool
isLetter Char
x = Char -> Bool
isAsciiLower Char
x Bool -> Bool -> Bool
|| Char -> Bool
isAsciiUpper Char
x
splitDrive :: FilePath -> (FilePath, FilePath)
splitDrive :: [Char] -> ([Char], [Char])
splitDrive [Char]
x | Bool
isPosix = (Char -> Bool) -> [Char] -> ([Char], [Char])
forall a. (a -> Bool) -> [a] -> ([a], [a])
span (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
'/') [Char]
x
splitDrive [Char]
x | Just ([Char], [Char])
y <- [Char] -> Maybe ([Char], [Char])
readDriveLetter [Char]
x = ([Char], [Char])
y
splitDrive [Char]
x | Just ([Char], [Char])
y <- [Char] -> Maybe ([Char], [Char])
readDriveUNC [Char]
x = ([Char], [Char])
y
splitDrive [Char]
x | Just ([Char], [Char])
y <- [Char] -> Maybe ([Char], [Char])
readDriveShare [Char]
x = ([Char], [Char])
y
splitDrive [Char]
x = ([Char]
"",[Char]
x)
addSlash :: FilePath -> FilePath -> (FilePath, FilePath)
addSlash :: [Char] -> [Char] -> ([Char], [Char])
addSlash [Char]
a [Char]
xs = ([Char]
a[Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++[Char]
c,[Char]
d)
where ([Char]
c,[Char]
d) = (Char -> Bool) -> [Char] -> ([Char], [Char])
forall a. (a -> Bool) -> [a] -> ([a], [a])
span Char -> Bool
isPathSeparator [Char]
xs
readDriveUNC :: FilePath -> Maybe (FilePath, FilePath)
readDriveUNC :: [Char] -> Maybe ([Char], [Char])
readDriveUNC (Char
s1:Char
s2:Char
'?':Char
s3:[Char]
xs) | (Char -> Bool) -> [Char] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all Char -> Bool
isPathSeparator [Char
s1,Char
s2,Char
s3] =
case (Char -> Char) -> [Char] -> [Char]
forall a b. (a -> b) -> [a] -> [b]
map Char -> Char
toUpper [Char]
xs of
(Char
'U':Char
'N':Char
'C':Char
s4:[Char]
_) | Char -> Bool
isPathSeparator Char
s4 ->
let ([Char]
a,[Char]
b) = [Char] -> ([Char], [Char])
readDriveShareName (Int -> [Char] -> [Char]
forall a. Int -> [a] -> [a]
drop Int
4 [Char]
xs)
in ([Char], [Char]) -> Maybe ([Char], [Char])
forall a. a -> Maybe a
Just (Char
s1Char -> [Char] -> [Char]
forall a. a -> [a] -> [a]
:Char
s2Char -> [Char] -> [Char]
forall a. a -> [a] -> [a]
:Char
'?'Char -> [Char] -> [Char]
forall a. a -> [a] -> [a]
:Char
s3Char -> [Char] -> [Char]
forall a. a -> [a] -> [a]
:Int -> [Char] -> [Char]
forall a. Int -> [a] -> [a]
take Int
4 [Char]
xs [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
a, [Char]
b)
[Char]
_ -> case [Char] -> Maybe ([Char], [Char])
readDriveLetter [Char]
xs of
Just ([Char]
a,[Char]
b) -> ([Char], [Char]) -> Maybe ([Char], [Char])
forall a. a -> Maybe a
Just (Char
s1Char -> [Char] -> [Char]
forall a. a -> [a] -> [a]
:Char
s2Char -> [Char] -> [Char]
forall a. a -> [a] -> [a]
:Char
'?'Char -> [Char] -> [Char]
forall a. a -> [a] -> [a]
:Char
s3Char -> [Char] -> [Char]
forall a. a -> [a] -> [a]
:[Char]
a,[Char]
b)
Maybe ([Char], [Char])
Nothing -> Maybe ([Char], [Char])
forall a. Maybe a
Nothing
readDriveUNC [Char]
_ = Maybe ([Char], [Char])
forall a. Maybe a
Nothing
readDriveLetter :: String -> Maybe (FilePath, FilePath)
readDriveLetter :: [Char] -> Maybe ([Char], [Char])
readDriveLetter (Char
x:Char
':':Char
y:[Char]
xs) | Char -> Bool
isLetter Char
x Bool -> Bool -> Bool
&& Char -> Bool
isPathSeparator Char
y = ([Char], [Char]) -> Maybe ([Char], [Char])
forall a. a -> Maybe a
Just (([Char], [Char]) -> Maybe ([Char], [Char]))
-> ([Char], [Char]) -> Maybe ([Char], [Char])
forall a b. (a -> b) -> a -> b
$ [Char] -> [Char] -> ([Char], [Char])
addSlash [Char
x,Char
':'] (Char
yChar -> [Char] -> [Char]
forall a. a -> [a] -> [a]
:[Char]
xs)
readDriveLetter (Char
x:Char
':':[Char]
xs) | Char -> Bool
isLetter Char
x = ([Char], [Char]) -> Maybe ([Char], [Char])
forall a. a -> Maybe a
Just ([Char
x,Char
':'], [Char]
xs)
readDriveLetter [Char]
_ = Maybe ([Char], [Char])
forall a. Maybe a
Nothing
readDriveShare :: String -> Maybe (FilePath, FilePath)
readDriveShare :: [Char] -> Maybe ([Char], [Char])
readDriveShare (Char
s1:Char
s2:[Char]
xs) | Char -> Bool
isPathSeparator Char
s1 Bool -> Bool -> Bool
&& Char -> Bool
isPathSeparator Char
s2 =
([Char], [Char]) -> Maybe ([Char], [Char])
forall a. a -> Maybe a
Just (Char
s1Char -> [Char] -> [Char]
forall a. a -> [a] -> [a]
:Char
s2Char -> [Char] -> [Char]
forall a. a -> [a] -> [a]
:[Char]
a,[Char]
b)
where ([Char]
a,[Char]
b) = [Char] -> ([Char], [Char])
readDriveShareName [Char]
xs
readDriveShare [Char]
_ = Maybe ([Char], [Char])
forall a. Maybe a
Nothing
readDriveShareName :: String -> (FilePath, FilePath)
readDriveShareName :: [Char] -> ([Char], [Char])
readDriveShareName [Char]
name = [Char] -> [Char] -> ([Char], [Char])
addSlash [Char]
a [Char]
b
where ([Char]
a,[Char]
b) = (Char -> Bool) -> [Char] -> ([Char], [Char])
forall a. (a -> Bool) -> [a] -> ([a], [a])
break Char -> Bool
isPathSeparator [Char]
name
joinDrive :: FilePath -> FilePath -> FilePath
joinDrive :: [Char] -> [Char] -> [Char]
joinDrive = [Char] -> [Char] -> [Char]
combineAlways
takeDrive :: FilePath -> FilePath
takeDrive :: [Char] -> [Char]
takeDrive = ([Char], [Char]) -> [Char]
forall a b. (a, b) -> a
fst (([Char], [Char]) -> [Char])
-> ([Char] -> ([Char], [Char])) -> [Char] -> [Char]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Char] -> ([Char], [Char])
splitDrive
dropDrive :: FilePath -> FilePath
dropDrive :: [Char] -> [Char]
dropDrive = ([Char], [Char]) -> [Char]
forall a b. (a, b) -> b
snd (([Char], [Char]) -> [Char])
-> ([Char] -> ([Char], [Char])) -> [Char] -> [Char]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Char] -> ([Char], [Char])
splitDrive
hasDrive :: FilePath -> Bool
hasDrive :: [Char] -> Bool
hasDrive = Bool -> Bool
not (Bool -> Bool) -> ([Char] -> Bool) -> [Char] -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Char] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null ([Char] -> Bool) -> ([Char] -> [Char]) -> [Char] -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Char] -> [Char]
takeDrive
isDrive :: FilePath -> Bool
isDrive :: [Char] -> Bool
isDrive [Char]
x = Bool -> Bool
not ([Char] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [Char]
x) Bool -> Bool -> Bool
&& [Char] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null ([Char] -> [Char]
dropDrive [Char]
x)
splitFileName :: FilePath -> (String, String)
splitFileName :: [Char] -> ([Char], [Char])
splitFileName [Char]
x = (if [Char] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [Char]
dir then [Char]
"./" else [Char]
dir, [Char]
name)
where
([Char]
dir, [Char]
name) = [Char] -> ([Char], [Char])
splitFileName_ [Char]
x
splitFileName_ :: FilePath -> (String, String)
splitFileName_ :: [Char] -> ([Char], [Char])
splitFileName_ [Char]
x = ([Char]
drv [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
dir, [Char]
file)
where
([Char]
drv,[Char]
pth) = [Char] -> ([Char], [Char])
splitDrive [Char]
x
([Char]
dir,[Char]
file) = (Char -> Bool) -> [Char] -> ([Char], [Char])
forall a. (a -> Bool) -> [a] -> ([a], [a])
breakEnd Char -> Bool
isPathSeparator [Char]
pth
replaceFileName :: FilePath -> String -> FilePath
replaceFileName :: [Char] -> [Char] -> [Char]
replaceFileName [Char]
x [Char]
y = [Char]
a [Char] -> [Char] -> [Char]
</> [Char]
y where ([Char]
a,[Char]
_) = [Char] -> ([Char], [Char])
splitFileName_ [Char]
x
dropFileName :: FilePath -> FilePath
dropFileName :: [Char] -> [Char]
dropFileName = ([Char], [Char]) -> [Char]
forall a b. (a, b) -> a
fst (([Char], [Char]) -> [Char])
-> ([Char] -> ([Char], [Char])) -> [Char] -> [Char]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Char] -> ([Char], [Char])
splitFileName
takeFileName :: FilePath -> FilePath
takeFileName :: [Char] -> [Char]
takeFileName = ([Char], [Char]) -> [Char]
forall a b. (a, b) -> b
snd (([Char], [Char]) -> [Char])
-> ([Char] -> ([Char], [Char])) -> [Char] -> [Char]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Char] -> ([Char], [Char])
splitFileName
takeBaseName :: FilePath -> String
takeBaseName :: [Char] -> [Char]
takeBaseName = [Char] -> [Char]
dropExtension ([Char] -> [Char]) -> ([Char] -> [Char]) -> [Char] -> [Char]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Char] -> [Char]
takeFileName
replaceBaseName :: FilePath -> String -> FilePath
replaceBaseName :: [Char] -> [Char] -> [Char]
replaceBaseName [Char]
pth [Char]
nam = [Char] -> [Char] -> [Char]
combineAlways [Char]
a ([Char]
nam [Char] -> [Char] -> [Char]
<.> [Char]
ext)
where
([Char]
a,[Char]
b) = [Char] -> ([Char], [Char])
splitFileName_ [Char]
pth
ext :: [Char]
ext = [Char] -> [Char]
takeExtension [Char]
b
hasTrailingPathSeparator :: FilePath -> Bool
hasTrailingPathSeparator :: [Char] -> Bool
hasTrailingPathSeparator [Char]
"" = Bool
False
hasTrailingPathSeparator [Char]
x = Char -> Bool
isPathSeparator ([Char] -> Char
forall a. [a] -> a
last [Char]
x)
hasLeadingPathSeparator :: FilePath -> Bool
hasLeadingPathSeparator :: [Char] -> Bool
hasLeadingPathSeparator [Char]
"" = Bool
False
hasLeadingPathSeparator [Char]
x = Char -> Bool
isPathSeparator ([Char] -> Char
forall a. [a] -> a
head [Char]
x)
addTrailingPathSeparator :: FilePath -> FilePath
addTrailingPathSeparator :: [Char] -> [Char]
addTrailingPathSeparator [Char]
x = if [Char] -> Bool
hasTrailingPathSeparator [Char]
x then [Char]
x else [Char]
x [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char
pathSeparator]
dropTrailingPathSeparator :: FilePath -> FilePath
dropTrailingPathSeparator :: [Char] -> [Char]
dropTrailingPathSeparator [Char]
x =
if [Char] -> Bool
hasTrailingPathSeparator [Char]
x Bool -> Bool -> Bool
&& Bool -> Bool
not ([Char] -> Bool
isDrive [Char]
x)
then let x' :: [Char]
x' = (Char -> Bool) -> [Char] -> [Char]
forall a. (a -> Bool) -> [a] -> [a]
dropWhileEnd Char -> Bool
isPathSeparator [Char]
x
in if [Char] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [Char]
x' then [[Char] -> Char
forall a. [a] -> a
last [Char]
x] else [Char]
x'
else [Char]
x
takeDirectory :: FilePath -> FilePath
takeDirectory :: [Char] -> [Char]
takeDirectory = [Char] -> [Char]
dropTrailingPathSeparator ([Char] -> [Char]) -> ([Char] -> [Char]) -> [Char] -> [Char]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Char] -> [Char]
dropFileName
replaceDirectory :: FilePath -> String -> FilePath
replaceDirectory :: [Char] -> [Char] -> [Char]
replaceDirectory [Char]
x [Char]
dir = [Char] -> [Char] -> [Char]
combineAlways [Char]
dir ([Char] -> [Char]
takeFileName [Char]
x)
combine :: FilePath -> FilePath -> FilePath
combine :: [Char] -> [Char] -> [Char]
combine [Char]
a [Char]
b | [Char] -> Bool
hasLeadingPathSeparator [Char]
b Bool -> Bool -> Bool
|| [Char] -> Bool
hasDrive [Char]
b = [Char]
b
| Bool
otherwise = [Char] -> [Char] -> [Char]
combineAlways [Char]
a [Char]
b
combineAlways :: FilePath -> FilePath -> FilePath
combineAlways :: [Char] -> [Char] -> [Char]
combineAlways [Char]
a [Char]
b | [Char] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [Char]
a = [Char]
b
| [Char] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [Char]
b = [Char]
a
| [Char] -> Bool
hasTrailingPathSeparator [Char]
a = [Char]
a [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
b
| Bool
otherwise = case [Char]
a of
[Char
a1,Char
':'] | Bool
isWindows Bool -> Bool -> Bool
&& Char -> Bool
isLetter Char
a1 -> [Char]
a [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
b
[Char]
_ -> [Char]
a [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char
pathSeparator] [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
b
(</>) :: FilePath -> FilePath -> FilePath
</> :: [Char] -> [Char] -> [Char]
(</>) = [Char] -> [Char] -> [Char]
combine
splitPath :: FilePath -> [FilePath]
splitPath :: [Char] -> [[Char]]
splitPath [Char]
x = [[Char]
drive | [Char]
drive [Char] -> [Char] -> Bool
forall a. Eq a => a -> a -> Bool
/= [Char]
""] [[Char]] -> [[Char]] -> [[Char]]
forall a. [a] -> [a] -> [a]
++ [Char] -> [[Char]]
f [Char]
path
where
([Char]
drive,[Char]
path) = [Char] -> ([Char], [Char])
splitDrive [Char]
x
f :: [Char] -> [[Char]]
f [Char]
"" = []
f [Char]
y = ([Char]
a[Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++[Char]
c) [Char] -> [[Char]] -> [[Char]]
forall a. a -> [a] -> [a]
: [Char] -> [[Char]]
f [Char]
d
where
([Char]
a,[Char]
b) = (Char -> Bool) -> [Char] -> ([Char], [Char])
forall a. (a -> Bool) -> [a] -> ([a], [a])
break Char -> Bool
isPathSeparator [Char]
y
([Char]
c,[Char]
d) = (Char -> Bool) -> [Char] -> ([Char], [Char])
forall a. (a -> Bool) -> [a] -> ([a], [a])
span Char -> Bool
isPathSeparator [Char]
b
splitDirectories :: FilePath -> [FilePath]
splitDirectories :: [Char] -> [[Char]]
splitDirectories = ([Char] -> [Char]) -> [[Char]] -> [[Char]]
forall a b. (a -> b) -> [a] -> [b]
map [Char] -> [Char]
dropTrailingPathSeparator ([[Char]] -> [[Char]])
-> ([Char] -> [[Char]]) -> [Char] -> [[Char]]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Char] -> [[Char]]
splitPath
joinPath :: [FilePath] -> FilePath
joinPath :: [[Char]] -> [Char]
joinPath = ([Char] -> [Char] -> [Char]) -> [Char] -> [[Char]] -> [Char]
forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
foldr [Char] -> [Char] -> [Char]
combine [Char]
""
equalFilePath :: FilePath -> FilePath -> Bool
equalFilePath :: [Char] -> [Char] -> Bool
equalFilePath [Char]
a [Char]
b = [Char] -> [Char]
f [Char]
a [Char] -> [Char] -> Bool
forall a. Eq a => a -> a -> Bool
== [Char] -> [Char]
f [Char]
b
where
f :: [Char] -> [Char]
f [Char]
x | Bool
isWindows = [Char] -> [Char]
dropTrailingPathSeparator ([Char] -> [Char]) -> [Char] -> [Char]
forall a b. (a -> b) -> a -> b
$ (Char -> Char) -> [Char] -> [Char]
forall a b. (a -> b) -> [a] -> [b]
map Char -> Char
toLower ([Char] -> [Char]) -> [Char] -> [Char]
forall a b. (a -> b) -> a -> b
$ [Char] -> [Char]
normalise [Char]
x
| Bool
otherwise = [Char] -> [Char]
dropTrailingPathSeparator ([Char] -> [Char]) -> [Char] -> [Char]
forall a b. (a -> b) -> a -> b
$ [Char] -> [Char]
normalise [Char]
x
makeRelative :: FilePath -> FilePath -> FilePath
makeRelative :: [Char] -> [Char] -> [Char]
makeRelative [Char]
root [Char]
path
| [Char] -> [Char] -> Bool
equalFilePath [Char]
root [Char]
path = [Char]
"."
| [Char] -> [Char]
takeAbs [Char]
root [Char] -> [Char] -> Bool
forall a. Eq a => a -> a -> Bool
/= [Char] -> [Char]
takeAbs [Char]
path = [Char]
path
| Bool
otherwise = [Char] -> [Char] -> [Char]
f ([Char] -> [Char]
dropAbs [Char]
root) ([Char] -> [Char]
dropAbs [Char]
path)
where
f :: [Char] -> [Char] -> [Char]
f [Char]
"" [Char]
y = (Char -> Bool) -> [Char] -> [Char]
forall a. (a -> Bool) -> [a] -> [a]
dropWhile Char -> Bool
isPathSeparator [Char]
y
f [Char]
x [Char]
y = let ([Char]
x1,[Char]
x2) = [Char] -> ([Char], [Char])
g [Char]
x
([Char]
y1,[Char]
y2) = [Char] -> ([Char], [Char])
g [Char]
y
in if [Char] -> [Char] -> Bool
equalFilePath [Char]
x1 [Char]
y1 then [Char] -> [Char] -> [Char]
f [Char]
x2 [Char]
y2 else [Char]
path
g :: [Char] -> ([Char], [Char])
g [Char]
x = ((Char -> Bool) -> [Char] -> [Char]
forall a. (a -> Bool) -> [a] -> [a]
dropWhile Char -> Bool
isPathSeparator [Char]
a, (Char -> Bool) -> [Char] -> [Char]
forall a. (a -> Bool) -> [a] -> [a]
dropWhile Char -> Bool
isPathSeparator [Char]
b)
where ([Char]
a,[Char]
b) = (Char -> Bool) -> [Char] -> ([Char], [Char])
forall a. (a -> Bool) -> [a] -> ([a], [a])
break Char -> Bool
isPathSeparator ([Char] -> ([Char], [Char])) -> [Char] -> ([Char], [Char])
forall a b. (a -> b) -> a -> b
$ (Char -> Bool) -> [Char] -> [Char]
forall a. (a -> Bool) -> [a] -> [a]
dropWhile Char -> Bool
isPathSeparator [Char]
x
dropAbs :: [Char] -> [Char]
dropAbs [Char]
x | [Char] -> Bool
hasLeadingPathSeparator [Char]
x Bool -> Bool -> Bool
&& Bool -> Bool
not ([Char] -> Bool
hasDrive [Char]
x) = [Char] -> [Char]
forall a. [a] -> [a]
tail [Char]
x
dropAbs [Char]
x = [Char] -> [Char]
dropDrive [Char]
x
takeAbs :: [Char] -> [Char]
takeAbs [Char]
x | [Char] -> Bool
hasLeadingPathSeparator [Char]
x Bool -> Bool -> Bool
&& Bool -> Bool
not ([Char] -> Bool
hasDrive [Char]
x) = [Char
pathSeparator]
takeAbs [Char]
x = (Char -> Char) -> [Char] -> [Char]
forall a b. (a -> b) -> [a] -> [b]
map (\Char
y -> if Char -> Bool
isPathSeparator Char
y then Char
pathSeparator else Char -> Char
toLower Char
y) ([Char] -> [Char]) -> [Char] -> [Char]
forall a b. (a -> b) -> a -> b
$ [Char] -> [Char]
takeDrive [Char]
x
normalise :: FilePath -> FilePath
normalise :: [Char] -> [Char]
normalise [Char]
path = [Char]
result [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char
pathSeparator | Bool
addPathSeparator]
where
([Char]
drv,[Char]
pth) = [Char] -> ([Char], [Char])
splitDrive [Char]
path
result :: [Char]
result = [Char] -> [Char] -> [Char]
joinDrive' ([Char] -> [Char]
normaliseDrive [Char]
drv) ([Char] -> [Char]
f [Char]
pth)
joinDrive' :: [Char] -> [Char] -> [Char]
joinDrive' [Char]
"" [Char]
"" = [Char]
"."
joinDrive' [Char]
d [Char]
p = [Char] -> [Char] -> [Char]
joinDrive [Char]
d [Char]
p
addPathSeparator :: Bool
addPathSeparator = [Char] -> Bool
isDirPath [Char]
pth
Bool -> Bool -> Bool
&& Bool -> Bool
not ([Char] -> Bool
hasTrailingPathSeparator [Char]
result)
Bool -> Bool -> Bool
&& Bool -> Bool
not ([Char] -> Bool
isRelativeDrive [Char]
drv)
isDirPath :: [Char] -> Bool
isDirPath [Char]
xs = [Char] -> Bool
hasTrailingPathSeparator [Char]
xs
Bool -> Bool -> Bool
|| Bool -> Bool
not ([Char] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [Char]
xs) Bool -> Bool -> Bool
&& [Char] -> Char
forall a. [a] -> a
last [Char]
xs Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
'.' Bool -> Bool -> Bool
&& [Char] -> Bool
hasTrailingPathSeparator ([Char] -> [Char]
forall a. [a] -> [a]
init [Char]
xs)
f :: [Char] -> [Char]
f = [[Char]] -> [Char]
joinPath ([[Char]] -> [Char]) -> ([Char] -> [[Char]]) -> [Char] -> [Char]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [[Char]] -> [[Char]]
dropDots ([[Char]] -> [[Char]])
-> ([Char] -> [[Char]]) -> [Char] -> [[Char]]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [[Char]] -> [[Char]]
propSep ([[Char]] -> [[Char]])
-> ([Char] -> [[Char]]) -> [Char] -> [[Char]]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Char] -> [[Char]]
splitDirectories
propSep :: [[Char]] -> [[Char]]
propSep ([Char]
x:[[Char]]
xs) | (Char -> Bool) -> [Char] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all Char -> Bool
isPathSeparator [Char]
x = [Char
pathSeparator] [Char] -> [[Char]] -> [[Char]]
forall a. a -> [a] -> [a]
: [[Char]]
xs
| Bool
otherwise = [Char]
x [Char] -> [[Char]] -> [[Char]]
forall a. a -> [a] -> [a]
: [[Char]]
xs
propSep [] = []
dropDots :: [[Char]] -> [[Char]]
dropDots = ([Char] -> Bool) -> [[Char]] -> [[Char]]
forall a. (a -> Bool) -> [a] -> [a]
filter ([Char]
"." [Char] -> [Char] -> Bool
forall a. Eq a => a -> a -> Bool
/=)
normaliseDrive :: FilePath -> FilePath
normaliseDrive :: [Char] -> [Char]
normaliseDrive [Char]
"" = [Char]
""
normaliseDrive [Char]
_ | Bool
isPosix = [Char
pathSeparator]
normaliseDrive [Char]
drive = if Maybe ([Char], [Char]) -> Bool
forall a. Maybe a -> Bool
isJust (Maybe ([Char], [Char]) -> Bool) -> Maybe ([Char], [Char]) -> Bool
forall a b. (a -> b) -> a -> b
$ [Char] -> Maybe ([Char], [Char])
readDriveLetter [Char]
x2
then (Char -> Char) -> [Char] -> [Char]
forall a b. (a -> b) -> [a] -> [b]
map Char -> Char
toUpper [Char]
x2
else [Char]
x2
where
x2 :: [Char]
x2 = (Char -> Char) -> [Char] -> [Char]
forall a b. (a -> b) -> [a] -> [b]
map Char -> Char
repSlash [Char]
drive
repSlash :: Char -> Char
repSlash Char
x = if Char -> Bool
isPathSeparator Char
x then Char
pathSeparator else Char
x
isBadCharacter :: Char -> Bool
isBadCharacter :: Char -> Bool
isBadCharacter Char
x = Char
x Char -> Char -> Bool
forall a. Ord a => a -> a -> Bool
>= Char
'\0' Bool -> Bool -> Bool
&& Char
x Char -> Char -> Bool
forall a. Ord a => a -> a -> Bool
<= Char
'\31' Bool -> Bool -> Bool
|| Char
x Char -> [Char] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [Char]
":*?><|\""
badElements :: [FilePath]
badElements :: [[Char]]
badElements =
[[Char]
"CON",[Char]
"PRN",[Char]
"AUX",[Char]
"NUL",[Char]
"CLOCK$"
,[Char]
"COM1",[Char]
"COM2",[Char]
"COM3",[Char]
"COM4",[Char]
"COM5",[Char]
"COM6",[Char]
"COM7",[Char]
"COM8",[Char]
"COM9"
,[Char]
"LPT1",[Char]
"LPT2",[Char]
"LPT3",[Char]
"LPT4",[Char]
"LPT5",[Char]
"LPT6",[Char]
"LPT7",[Char]
"LPT8",[Char]
"LPT9"]
isValid :: FilePath -> Bool
isValid :: [Char] -> Bool
isValid [Char]
"" = Bool
False
isValid [Char]
x | Char
'\0' Char -> [Char] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [Char]
x = Bool
False
isValid [Char]
_ | Bool
isPosix = Bool
True
isValid [Char]
path =
Bool -> Bool
not ((Char -> Bool) -> [Char] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any Char -> Bool
isBadCharacter [Char]
x2) Bool -> Bool -> Bool
&&
Bool -> Bool
not (([Char] -> Bool) -> [[Char]] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
any [Char] -> Bool
f ([[Char]] -> Bool) -> [[Char]] -> Bool
forall a b. (a -> b) -> a -> b
$ [Char] -> [[Char]]
splitDirectories [Char]
x2) Bool -> Bool -> Bool
&&
Bool -> Bool
not (Maybe ([Char], [Char]) -> Bool
forall a. Maybe a -> Bool
isJust ([Char] -> Maybe ([Char], [Char])
readDriveShare [Char]
x1) Bool -> Bool -> Bool
&& (Char -> Bool) -> [Char] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all Char -> Bool
isPathSeparator [Char]
x1) Bool -> Bool -> Bool
&&
Bool -> Bool
not (Maybe ([Char], [Char]) -> Bool
forall a. Maybe a -> Bool
isJust ([Char] -> Maybe ([Char], [Char])
readDriveUNC [Char]
x1) Bool -> Bool -> Bool
&& Bool -> Bool
not ([Char] -> Bool
hasTrailingPathSeparator [Char]
x1))
where
([Char]
x1,[Char]
x2) = [Char] -> ([Char], [Char])
splitDrive [Char]
path
f :: [Char] -> Bool
f [Char]
x = (Char -> Char) -> [Char] -> [Char]
forall a b. (a -> b) -> [a] -> [b]
map Char -> Char
toUpper ((Char -> Bool) -> [Char] -> [Char]
forall a. (a -> Bool) -> [a] -> [a]
dropWhileEnd (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
' ') ([Char] -> [Char]) -> [Char] -> [Char]
forall a b. (a -> b) -> a -> b
$ [Char] -> [Char]
dropExtensions [Char]
x) [Char] -> [[Char]] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [[Char]]
badElements
makeValid :: FilePath -> FilePath
makeValid :: [Char] -> [Char]
makeValid [Char]
"" = [Char]
"_"
makeValid [Char]
path
| Bool
isPosix = (Char -> Char) -> [Char] -> [Char]
forall a b. (a -> b) -> [a] -> [b]
map (\Char
x -> if Char
x Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
'\0' then Char
'_' else Char
x) [Char]
path
| Maybe ([Char], [Char]) -> Bool
forall a. Maybe a -> Bool
isJust ([Char] -> Maybe ([Char], [Char])
readDriveShare [Char]
drv) Bool -> Bool -> Bool
&& (Char -> Bool) -> [Char] -> Bool
forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
all Char -> Bool
isPathSeparator [Char]
drv = Int -> [Char] -> [Char]
forall a. Int -> [a] -> [a]
take Int
2 [Char]
drv [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
"drive"
| Maybe ([Char], [Char]) -> Bool
forall a. Maybe a -> Bool
isJust ([Char] -> Maybe ([Char], [Char])
readDriveUNC [Char]
drv) Bool -> Bool -> Bool
&& Bool -> Bool
not ([Char] -> Bool
hasTrailingPathSeparator [Char]
drv) =
[Char] -> [Char]
makeValid ([Char]
drv [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char
pathSeparator] [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
pth)
| Bool
otherwise = [Char] -> [Char] -> [Char]
joinDrive [Char]
drv ([Char] -> [Char]) -> [Char] -> [Char]
forall a b. (a -> b) -> a -> b
$ [Char] -> [Char]
validElements ([Char] -> [Char]) -> [Char] -> [Char]
forall a b. (a -> b) -> a -> b
$ [Char] -> [Char]
validChars [Char]
pth
where
([Char]
drv,[Char]
pth) = [Char] -> ([Char], [Char])
splitDrive [Char]
path
validChars :: [Char] -> [Char]
validChars = (Char -> Char) -> [Char] -> [Char]
forall a b. (a -> b) -> [a] -> [b]
map Char -> Char
f
f :: Char -> Char
f Char
x = if Char -> Bool
isBadCharacter Char
x then Char
'_' else Char
x
validElements :: [Char] -> [Char]
validElements [Char]
x = [[Char]] -> [Char]
joinPath ([[Char]] -> [Char]) -> [[Char]] -> [Char]
forall a b. (a -> b) -> a -> b
$ ([Char] -> [Char]) -> [[Char]] -> [[Char]]
forall a b. (a -> b) -> [a] -> [b]
map [Char] -> [Char]
g ([[Char]] -> [[Char]]) -> [[Char]] -> [[Char]]
forall a b. (a -> b) -> a -> b
$ [Char] -> [[Char]]
splitPath [Char]
x
g :: [Char] -> [Char]
g [Char]
x = [Char] -> [Char]
h [Char]
a [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
b
where ([Char]
a,[Char]
b) = (Char -> Bool) -> [Char] -> ([Char], [Char])
forall a. (a -> Bool) -> [a] -> ([a], [a])
break Char -> Bool
isPathSeparator [Char]
x
h :: [Char] -> [Char]
h [Char]
x = if (Char -> Char) -> [Char] -> [Char]
forall a b. (a -> b) -> [a] -> [b]
map Char -> Char
toUpper ((Char -> Bool) -> [Char] -> [Char]
forall a. (a -> Bool) -> [a] -> [a]
dropWhileEnd (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
' ') [Char]
a) [Char] -> [[Char]] -> Bool
forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` [[Char]]
badElements then [Char]
a [Char] -> [Char] -> [Char]
forall a. [a] -> [a] -> [a]
++ [Char]
"_" [Char] -> [Char] -> [Char]
<.> [Char]
b else [Char]
x
where ([Char]
a,[Char]
b) = [Char] -> ([Char], [Char])
splitExtensions [Char]
x
isRelative :: FilePath -> Bool
isRelative :: [Char] -> Bool
isRelative [Char]
x = [Char] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [Char]
drive Bool -> Bool -> Bool
|| [Char] -> Bool
isRelativeDrive [Char]
drive
where drive :: [Char]
drive = [Char] -> [Char]
takeDrive [Char]
x
isRelativeDrive :: String -> Bool
isRelativeDrive :: [Char] -> Bool
isRelativeDrive [Char]
x =
Bool
-> (([Char], [Char]) -> Bool) -> Maybe ([Char], [Char]) -> Bool
forall b a. b -> (a -> b) -> Maybe a -> b
maybe Bool
False (Bool -> Bool
not (Bool -> Bool)
-> (([Char], [Char]) -> Bool) -> ([Char], [Char]) -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Char] -> Bool
hasTrailingPathSeparator ([Char] -> Bool)
-> (([Char], [Char]) -> [Char]) -> ([Char], [Char]) -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ([Char], [Char]) -> [Char]
forall a b. (a, b) -> a
fst) ([Char] -> Maybe ([Char], [Char])
readDriveLetter [Char]
x)
isAbsolute :: FilePath -> Bool
isAbsolute :: [Char] -> Bool
isAbsolute = Bool -> Bool
not (Bool -> Bool) -> ([Char] -> Bool) -> [Char] -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Char] -> Bool
isRelative
dropWhileEnd :: (a -> Bool) -> [a] -> [a]
dropWhileEnd :: (a -> Bool) -> [a] -> [a]
dropWhileEnd a -> Bool
p = [a] -> [a]
forall a. [a] -> [a]
reverse ([a] -> [a]) -> ([a] -> [a]) -> [a] -> [a]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (a -> Bool) -> [a] -> [a]
forall a. (a -> Bool) -> [a] -> [a]
dropWhile a -> Bool
p ([a] -> [a]) -> ([a] -> [a]) -> [a] -> [a]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [a] -> [a]
forall a. [a] -> [a]
reverse
takeWhileEnd :: (a -> Bool) -> [a] -> [a]
takeWhileEnd :: (a -> Bool) -> [a] -> [a]
takeWhileEnd a -> Bool
p = [a] -> [a]
forall a. [a] -> [a]
reverse ([a] -> [a]) -> ([a] -> [a]) -> [a] -> [a]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (a -> Bool) -> [a] -> [a]
forall a. (a -> Bool) -> [a] -> [a]
takeWhile a -> Bool
p ([a] -> [a]) -> ([a] -> [a]) -> [a] -> [a]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [a] -> [a]
forall a. [a] -> [a]
reverse
spanEnd :: (a -> Bool) -> [a] -> ([a], [a])
spanEnd :: (a -> Bool) -> [a] -> ([a], [a])
spanEnd a -> Bool
p [a]
xs = ((a -> Bool) -> [a] -> [a]
forall a. (a -> Bool) -> [a] -> [a]
dropWhileEnd a -> Bool
p [a]
xs, (a -> Bool) -> [a] -> [a]
forall a. (a -> Bool) -> [a] -> [a]
takeWhileEnd a -> Bool
p [a]
xs)
breakEnd :: (a -> Bool) -> [a] -> ([a], [a])
breakEnd :: (a -> Bool) -> [a] -> ([a], [a])
breakEnd a -> Bool
p = (a -> Bool) -> [a] -> ([a], [a])
forall a. (a -> Bool) -> [a] -> ([a], [a])
spanEnd (Bool -> Bool
not (Bool -> Bool) -> (a -> Bool) -> a -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> Bool
p)
stripSuffix :: Eq a => [a] -> [a] -> Maybe [a]
stripSuffix :: [a] -> [a] -> Maybe [a]
stripSuffix [a]
xs [a]
ys = ([a] -> [a]) -> Maybe [a] -> Maybe [a]
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap [a] -> [a]
forall a. [a] -> [a]
reverse (Maybe [a] -> Maybe [a]) -> Maybe [a] -> Maybe [a]
forall a b. (a -> b) -> a -> b
$ [a] -> [a] -> Maybe [a]
forall a. Eq a => [a] -> [a] -> Maybe [a]
stripPrefix ([a] -> [a]
forall a. [a] -> [a]
reverse [a]
xs) ([a] -> [a]
forall a. [a] -> [a]
reverse [a]
ys)