definition:
|
makeRelative :: FilePath -> FilePath -> FilePath
makeRelative root path
| equalFilePath root path = "."
| takeAbs root /= takeAbs path = path
| otherwise = f (dropAbs root) (dropAbs path)
where
f [] y = dropWhile isPathSeparator y
f x@(_:_) y = let (x1,x2) = g x
(y1,y2) = g y
in if equalFilePath x1 y1 then f x2 y2 else path
g x = (dropWhile isPathSeparator a, dropWhile isPathSeparator b)
where (a,b) = break isPathSeparator $ dropWhile isPathSeparator x
-- on windows, need to drop '/' which is kind of absolute, but not a drive
dropAbs [] = dropDrive []
dropAbs (x:xs) | isPathSeparator x = xs
| otherwise = dropDrive (x:xs)
takeAbs [] = map (\y -> if isPathSeparator y then pathSeparator else toLower y) $ takeDrive []
takeAbs xs@(x:_)
| isPathSeparator x = [pathSeparator]
| otherwise = map (\y -> if isPathSeparator y then pathSeparator else toLower y) $ takeDrive xs
|
documentation:
|
-- | Contract a filename, based on a relative path.
--
-- There is no corresponding @makeAbsolute@ function, instead use
-- @System.Directory.canonicalizePath@ which has the same effect.
--
-- > Valid y => equalFilePath x y || (isRelative x && makeRelative y x == x) || equalFilePath (y </> makeRelative y x) x
-- > makeRelative x x == "."
-- > null y || equalFilePath (makeRelative x (x </> y)) y || null (takeFileName x)
-- > Windows: makeRelative "C:\\Home" "c:\\home\\bob" == "bob"
-- > Windows: makeRelative "C:\\Home" "c:/home/bob" == "bob"
-- > Windows: makeRelative "C:\\Home" "D:\\Home\\Bob" == "D:\\Home\\Bob"
-- > Windows: makeRelative "C:\\Home" "C:Home\\Bob" == "C:Home\\Bob"
-- > Windows: makeRelative "/Home" "/home/bob" == "bob"
-- > Posix: makeRelative "/Home" "/home/bob" == "/home/bob"
-- > Posix: makeRelative "/home/" "/home/bob/foo/bar" == "bob/foo/bar"
-- > Posix: makeRelative "/fred" "bob" == "bob"
-- > Posix: makeRelative "/file/test" "/file/test/fred" == "fred"
-- > Posix: makeRelative "/file/test" "/file/test/fred/" == "fred/"
-- > Posix: makeRelative "some/path" "some/path/a/b/c" == "a/b/c"
|