-- Hoogle documentation, generated by Haddock
-- See Hoogle, http://www.haskell.org/hoogle/

-- | Library for manipulating RawFilePaths in a cross platform way.
--   
--   This package provides functionality for manipulating
--   RawFilePath values. It can be used as a drop in replacement
--   for the filepath library to get the benefits of using ByteStrings. It
--   provides three modules:
--   
--   
--   
- System.FilePath.Posix.ByteString manipulates POSIX/Linux
--   style RawFilePath values (with / as the path
--   separator).
--   
- System.FilePath.Windows.ByteString manipulates Windows
--   style RawFilePath values (with either \ or
--   / as the path separator, and deals with drives).
--   
- System.FilePath.ByteString is an alias for the module
--   appropriate to your platform.
--   
--   
--   All three modules provide the same API, and the same documentation
--   (calling out differences in the different variants).
--   
--   This package is now deprecated, since filepath 1.4.100.0 provides an
--   OsPath type that is based on a bytestring. See
--   https:/hasufell.github.ioposts/2022-06-29-fixing-haskell-filepaths.html
@package filepath-bytestring
@version 1.5.2.0.3

-- | A library for RawFilePath manipulations, using Posix style
--   paths on all platforms. Importing System.FilePath.ByteString is
--   usually better.
--   
--   This module is the same as System.FilePath.Posix from the filepath
--   library, except it uses RawFilePath.
--   
--   Given the example RawFilePath: /directory/file.ext
--   
--   We can use the following functions to extract pieces.
--   
--   
--   
- takeFileName gives "file.ext"
--   
- takeDirectory gives "/directory"
--   
- takeExtension gives ".ext"
--   
- dropExtension gives "/directory/file"
--   
- takeBaseName gives "file"
--   
--   
--   And we could have built an equivalent path with the following
--   expressions:
--   
--   
--   
- "/directory" </> "file.ext".
--   
- "/directory/file" <.> "ext".
--   
- "/directory/file.txt" -<.> "ext".
--   
--   
--   Each function in this module is documented with several examples,
--   which are also used as tests.
--   
--   Here are a few examples of using the filepath functions
--   together:
--   
--   Example 1: Find the possible locations of a Haskell module
--   Test imported from module Main:
--   
--   
--   [replaceFileName path_to_main "Test" <.> ext | ext <- ["hs","lhs"] ]
--   
--   
--   Example 2: Compile a Haskell file, putting the .hi
--   file under interface:
--   
--   
--   takeDirectory file </> "interface" </> (takeFileName file -<.> "hi")
--   
--   
--   References: [1] Naming Files, Paths and Namespaces (Microsoft
--   MSDN)
module System.FilePath.Posix.ByteString

-- | A literal POSIX file path
type RawFilePath = ByteString

-- | Convert from FilePath to RawFilePath.
--   
--   When run on Unix, this applies the filesystem encoding (see
--   getFileSystemEncoding).
--   
--   When run on Windows, this encodes as UTF-8.
--   
--   the implementation of this function assumes that the filesystem
--   encoding will not be changed while the program is running.
encodeFilePath :: FilePath -> RawFilePath

-- | Convert from RawFilePath to FilePath
--   
--   When run on Unix, this applies the filesystem encoding (see
--   getFileSystemEncoding).
--   
--   When run on Windows, this decodes UTF-8.
decodeFilePath :: RawFilePath -> FilePath

-- | The character that separates directories. In the case where more than
--   one character is possible, pathSeparator is the 'ideal' one.
--   
--   
--   Windows: pathSeparator == fromIntegral (ord '\\')
--   Posix:   pathSeparator == fromIntegral (ord '/')
--   isPathSeparator pathSeparator
--   
pathSeparator :: Word8

-- | The list of all possible separators.
--   
--   
--   Windows: pathSeparators == [fromIntegral (ord '\\'), fromIntegral (ord '/')]
--   Posix:   pathSeparators == [fromIntegral (ord '/')]
--   pathSeparator `elem` pathSeparators
--   
pathSeparators :: [Word8]

-- | Rather than using (== pathSeparator), use this. Test
--   if something is a path separator.
--   
--   
--   isPathSeparator a == (a `elem` pathSeparators)
--   
isPathSeparator :: Word8 -> Bool

-- | The character that is used to separate the entries in the $PATH
--   environment variable.
--   
--   
--   Windows: searchPathSeparator == fromIntegral (ord ';')
--   Posix:   searchPathSeparator == fromIntegral (ord ':')
--   
searchPathSeparator :: Word8

-- | Is the character a file separator?
--   
--   
--   isSearchPathSeparator a == (a == searchPathSeparator)
--   
isSearchPathSeparator :: Word8 -> Bool

-- | File extension character
--   
--   
--   extSeparator == fromIntegral (ord '.')
--   
extSeparator :: Word8

-- | Is the character an extension character?
--   
--   
--   isExtSeparator a == (a == extSeparator)
--   
isExtSeparator :: Word8 -> Bool

-- | Take a string, split it on the searchPathSeparator character.
--   Blank items are ignored on Windows, and converted to . on
--   Posix. On Windows path elements are stripped of quotes.
--   
--   Follows the recommendations in
--   http://www.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap08.html
--   
--   
--   Posix:   splitSearchPath "File1:File2:File3"  == ["File1","File2","File3"]
--   Posix:   splitSearchPath "File1::File2:File3" == ["File1",".","File2","File3"]
--   Windows: splitSearchPath "File1;File2;File3"  == ["File1","File2","File3"]
--   Windows: splitSearchPath "File1;;File2;File3" == ["File1","File2","File3"]
--   Windows: splitSearchPath "File1;\"File2\";File3" == ["File1","File2","File3"]
--   
splitSearchPath :: ByteString -> [RawFilePath]

-- | Get a list of RawFilePaths in the $PATH variable.
getSearchPath :: IO [RawFilePath]

-- | Split on the extension. addExtension is the inverse.
--   
--   
--   splitExtension "/directory/path.ext" == ("/directory/path",".ext")
--   uncurry (<>) (splitExtension x) == x
--   Valid x => uncurry addExtension (splitExtension x) == x
--   splitExtension "file.txt" == ("file",".txt")
--   splitExtension "file" == ("file","")
--   splitExtension "file/file.txt" == ("file/file",".txt")
--   splitExtension "file.txt/boris" == ("file.txt/boris","")
--   splitExtension "file.txt/boris.ext" == ("file.txt/boris",".ext")
--   splitExtension "file/path.txt.bob.fred" == ("file/path.txt.bob",".fred")
--   splitExtension "file/path.txt/" == ("file/path.txt/","")
--   
splitExtension :: RawFilePath -> (ByteString, ByteString)

-- | Get the extension of a file, returns "" for no extension,
--   .ext otherwise.
--   
--   
--   takeExtension "/directory/path.ext" == ".ext"
--   takeExtension x == snd (splitExtension x)
--   Valid x => takeExtension (addExtension x "ext") == ".ext"
--   Valid x => takeExtension (replaceExtension x "ext") == ".ext"
--   
takeExtension :: RawFilePath -> ByteString

-- | Set the extension of a file, overwriting one if already present,
--   equivalent to -<.>.
--   
--   
--   replaceExtension "/directory/path.txt" "ext" == "/directory/path.ext"
--   replaceExtension "/directory/path.txt" ".ext" == "/directory/path.ext"
--   replaceExtension "file.txt" ".bob" == "file.bob"
--   replaceExtension "file.txt" "bob" == "file.bob"
--   replaceExtension "file" ".bob" == "file.bob"
--   replaceExtension "file.txt" "" == "file"
--   replaceExtension "file.fred.bob" "txt" == "file.fred.txt"
--   replaceExtension x y == addExtension (dropExtension x) y
--   
replaceExtension :: RawFilePath -> ByteString -> RawFilePath

-- | Remove the current extension and add another, equivalent to
--   replaceExtension.
--   
--   
--   "/directory/path.txt" -<.> "ext" == "/directory/path.ext"
--   "/directory/path.txt" -<.> ".ext" == "/directory/path.ext"
--   "foo.o" -<.> "c" == "foo.c"
--   
(-<.>) :: RawFilePath -> ByteString -> RawFilePath
infixr 7 -<.>

-- | Remove last extension, and the "." preceding it.
--   
--   
--   dropExtension "/directory/path.ext" == "/directory/path"
--   dropExtension x == fst (splitExtension x)
--   
dropExtension :: RawFilePath -> RawFilePath

-- | Add an extension, even if there is already one there, equivalent to
--   <.>.
--   
--   
--   addExtension "/directory/path" "ext" == "/directory/path.ext"
--   addExtension "file.txt" "bib" == "file.txt.bib"
--   addExtension "file." ".bib" == "file..bib"
--   addExtension "file" ".bib" == "file.bib"
--   addExtension "/" "x" == "/.x"
--   addExtension x "" == x
--   Valid x => takeFileName (addExtension (addTrailingPathSeparator x) "ext") == ".ext"
--   Windows: addExtension "\\\\share" ".txt" == "\\\\share\\.txt"
--   
addExtension :: RawFilePath -> ByteString -> RawFilePath

-- | Does the given filename have an extension?
--   
--   
--   hasExtension "/directory/path.ext" == True
--   hasExtension "/directory/path" == False
--   null (takeExtension x) == not (hasExtension x)
--   
hasExtension :: RawFilePath -> Bool

-- | Add an extension, even if there is already one there, equivalent to
--   addExtension.
--   
--   
--   "/directory/path" <.> "ext" == "/directory/path.ext"
--   "/directory/path" <.> ".ext" == "/directory/path.ext"
--   
(<.>) :: RawFilePath -> ByteString -> RawFilePath
infixr 7 <.>

-- | Split on all extensions.
--   
--   
--   splitExtensions "/directory/path.ext" == ("/directory/path",".ext")
--   splitExtensions "file.tar.gz" == ("file",".tar.gz")
--   uncurry (<>) (splitExtensions x) == x
--   Valid x => uncurry addExtension (splitExtensions x) == x
--   splitExtensions "file.tar.gz" == ("file",".tar.gz")
--   
splitExtensions :: RawFilePath -> (RawFilePath, ByteString)

-- | Drop all extensions.
--   
--   
--   dropExtensions "/directory/path.ext" == "/directory/path"
--   dropExtensions "file.tar.gz" == "file"
--   not $ hasExtension $ dropExtensions x
--   not $ any isExtSeparator $ takeFileName $ dropExtensions x
--   
dropExtensions :: RawFilePath -> RawFilePath

-- | Get all extensions.
--   
--   
--   takeExtensions "/directory/path.ext" == ".ext"
--   takeExtensions "file.tar.gz" == ".tar.gz"
--   
takeExtensions :: RawFilePath -> ByteString

-- | Replace all extensions of a file with a new extension. Note that
--   replaceExtension and addExtension both work for adding
--   multiple extensions, so only required when you need to drop all
--   extensions first.
--   
--   
--   replaceExtensions "file.fred.bob" "txt" == "file.txt"
--   replaceExtensions "file.fred.bob" "tar.gz" == "file.tar.gz"
--   
replaceExtensions :: RawFilePath -> ByteString -> RawFilePath

-- | Does the given filename have the specified extension?
--   
--   
--   "png" `isExtensionOf` "/directory/file.png" == True
--   ".png" `isExtensionOf` "/directory/file.png" == True
--   ".tar.gz" `isExtensionOf` "bar/foo.tar.gz" == True
--   "ar.gz" `isExtensionOf` "bar/foo.tar.gz" == False
--   "png" `isExtensionOf` "/directory/file.png.jpg" == False
--   "csv/table.csv" `isExtensionOf` "/data/csv/table.csv" == False
--   
isExtensionOf :: ByteString -> RawFilePath -> Bool

-- | Drop the given extension from a FilePath, and the "."
--   preceding it. Returns Nothing if the FilePath does not have the
--   given extension, or Just and the part before the extension if
--   it does.
--   
--   This function can be more predictable than dropExtensions,
--   especially if the filename might itself contain . characters.
--   
--   
--   stripExtension "hs.o" "foo.x.hs.o" == Just "foo.x"
--   stripExtension "hi.o" "foo.x.hs.o" == Nothing
--   dropExtension x == fromJust (stripExtension (takeExtension x) x)
--   dropExtensions x == fromJust (stripExtension (takeExtensions x) x)
--   stripExtension ".c.d" "a.b.c.d"  == Just "a.b"
--   stripExtension ".c.d" "a.b..c.d" == Just "a.b."
--   stripExtension "baz"  "foo.bar"  == Nothing
--   stripExtension "bar"  "foobar"   == Nothing
--   stripExtension ""     x          == Just x
--   
stripExtension :: ByteString -> RawFilePath -> Maybe RawFilePath

-- | Split a filename into directory and file. </> is the
--   inverse. The first component will often end with a trailing slash.
--   
--   
--   splitFileName "/directory/file.ext" == ("/directory/","file.ext")
--   Valid x => uncurry (</>) (splitFileName x) == x || fst (splitFileName x) == "./"
--   Valid x => isValid (fst (splitFileName x))
--   splitFileName "file/bob.txt" == ("file/", "bob.txt")
--   splitFileName "file/" == ("file/", "")
--   splitFileName "bob" == ("./", "bob")
--   Posix:   splitFileName "/" == ("/","")
--   Windows: splitFileName "c:" == ("c:","")
--   
splitFileName :: RawFilePath -> (ByteString, ByteString)

-- | Get the file name.
--   
--   
--   takeFileName "/directory/file.ext" == "file.ext"
--   takeFileName "test/" == ""
--   takeFileName x `isSuffixOf` x
--   takeFileName x == snd (splitFileName x)
--   Valid x => takeFileName (replaceFileName x "fred") == "fred"
--   Valid x => takeFileName (x </> "fred") == "fred"
--   Valid x => isRelative (takeFileName x)
--   
takeFileName :: RawFilePath -> RawFilePath

-- | Set the filename.
--   
--   
--   replaceFileName "/directory/other.txt" "file.ext" == "/directory/file.ext"
--   Valid x => replaceFileName x (takeFileName x) == x
--   
replaceFileName :: RawFilePath -> ByteString -> RawFilePath

-- | Drop the filename. Unlike takeDirectory, this function will
--   leave a trailing path separator on the directory.
--   
--   
--   dropFileName "/directory/file.ext" == "/directory/"
--   dropFileName x == fst (splitFileName x)
--   
dropFileName :: RawFilePath -> RawFilePath

-- | Get the base name, without an extension or path.
--   
--   
--   takeBaseName "/directory/file.ext" == "file"
--   takeBaseName "file/test.txt" == "test"
--   takeBaseName "dave.ext" == "dave"
--   takeBaseName "" == ""
--   takeBaseName "test" == "test"
--   takeBaseName (addTrailingPathSeparator x) == ""
--   takeBaseName "file/file.tar.gz" == "file.tar"
--   
takeBaseName :: RawFilePath -> ByteString

-- | Set the base name.
--   
--   
--   replaceBaseName "/directory/other.ext" "file" == "/directory/file.ext"
--   replaceBaseName "file/test.txt" "bob" == "file/bob.txt"
--   replaceBaseName "fred" "bill" == "bill"
--   replaceBaseName "/dave/fred/bob.gz.tar" "new" == "/dave/fred/new.tar"
--   Valid x => replaceBaseName x (takeBaseName x) == x
--   
replaceBaseName :: RawFilePath -> ByteString -> RawFilePath

-- | Get the directory name, move up one level.
--   
--   
--             takeDirectory "/directory/other.ext" == "/directory"
--             takeDirectory x `isPrefixOf` x || takeDirectory x == "."
--             takeDirectory "foo" == "."
--             takeDirectory "/" == "/"
--             takeDirectory "/foo" == "/"
--             takeDirectory "/foo/bar/baz" == "/foo/bar"
--             takeDirectory "/foo/bar/baz/" == "/foo/bar/baz"
--             takeDirectory "foo/bar/baz" == "foo/bar"
--   Windows:  takeDirectory "foo\\bar" == "foo"
--   Windows:  takeDirectory "foo\\bar\\\\" == "foo\\bar"
--   Windows:  takeDirectory "C:\\" == "C:\\"
--   
takeDirectory :: RawFilePath -> RawFilePath

-- | Set the directory, keeping the filename the same.
--   
--   
--   replaceDirectory "root/file.ext" "/directory/" == "/directory/file.ext"
--   Valid x => replaceDirectory x (takeDirectory x) `equalFilePath` x
--   
replaceDirectory :: RawFilePath -> ByteString -> RawFilePath

-- | An alias for </>.
combine :: RawFilePath -> RawFilePath -> RawFilePath

-- | Combine two paths with a path separator. If the second path starts
--   with a path separator or a drive letter, then it returns the second.
--   The intention is that readFile (dir </> file)
--   will access the same file as setCurrentDirectory dir; readFile
--   file.
--   
--   
--   Posix:   "/directory" </> "file.ext" == "/directory/file.ext"
--   Windows: "/directory" </> "file.ext" == "/directory\\file.ext"
--            "directory" </> "/file.ext" == "/file.ext"
--   Valid x => (takeDirectory x </> takeFileName x) `equalFilePath` x
--   
--   
--   Combined:
--   
--   
--   Posix:   "/" </> "test" == "/test"
--   Posix:   "home" </> "bob" == "home/bob"
--   Posix:   "x:" </> "foo" == "x:/foo"
--   Windows: "C:\\foo" </> "bar" == "C:\\foo\\bar"
--   Windows: "home" </> "bob" == "home\\bob"
--   
--   
--   Not combined:
--   
--   
--   Posix:   "home" </> "/bob" == "/bob"
--   Windows: "home" </> "C:\\bob" == "C:\\bob"
--   
--   
--   Not combined (tricky):
--   
--   On Windows, if a filepath starts with a single slash, it is relative
--   to the root of the current drive. In [1], this is (confusingly)
--   referred to as an absolute path. The current behavior of
--   </> is to never combine these forms.
--   
--   
--   Windows: "home" </> "/bob" == "/bob"
--   Windows: "home" </> "\\bob" == "\\bob"
--   Windows: "C:\\home" </> "\\bob" == "\\bob"
--   
--   
--   On Windows, from [1]: "If a file name begins with only a disk
--   designator but not the backslash after the colon, it is interpreted as
--   a relative path to the current directory on the drive with the
--   specified letter." The current behavior of </> is to
--   never combine these forms.
--   
--   
--   Windows: "D:\\foo" </> "C:bar" == "C:bar"
--   Windows: "C:\\foo" </> "C:bar" == "C:bar"
--   
(</>) :: RawFilePath -> RawFilePath -> RawFilePath
infixr 5 </>

-- | Split a path by the directory separator.
--   
--   
--   splitPath "/directory/file.ext" == ["/","directory/","file.ext"]
--   mconcat (splitPath x) == x
--   splitPath "test//item/" == ["test//","item/"]
--   splitPath "test/item/file" == ["test/","item/","file"]
--   splitPath "" == []
--   Windows: splitPath "c:\\test\\path" == ["c:\\","test\\","path"]
--   Posix:   splitPath "/file/test" == ["/","file/","test"]
--   
splitPath :: RawFilePath -> [RawFilePath]

-- | Join path elements back together.
--   
--   
--   joinPath ["/","directory/","file.ext"] == "/directory/file.ext"
--   Valid x => joinPath (splitPath x) == x
--   joinPath [] == ""
--   Posix: joinPath ["test","file","path"] == "test/file/path"
--   
joinPath :: [RawFilePath] -> RawFilePath

-- | Just as splitPath, but don't add the trailing slashes to each
--   element.
--   
--   
--            splitDirectories "/directory/file.ext" == ["/","directory","file.ext"]
--            splitDirectories "test/file" == ["test","file"]
--            splitDirectories "/test/file" == ["/","test","file"]
--   Windows: splitDirectories "C:\\test\\file" == ["C:\\", "test", "file"]
--            Valid x => joinPath (splitDirectories x) `equalFilePath` x
--            splitDirectories "" == []
--   Windows: splitDirectories "C:\\test\\\\\\file" == ["C:\\", "test", "file"]
--            splitDirectories "/test///file" == ["/","test","file"]
--   
splitDirectories :: RawFilePath -> [RawFilePath]

-- | Split a path into a drive and a path. On Posix, / is a Drive.
--   
--   
--   uncurry (<>) (splitDrive x) == x
--   Windows: splitDrive "file" == ("","file")
--   Windows: splitDrive "c:/file" == ("c:/","file")
--   Windows: splitDrive "c:\\file" == ("c:\\","file")
--   Windows: splitDrive "\\\\shared\\test" == ("\\\\shared\\","test")
--   Windows: splitDrive "\\\\shared" == ("\\\\shared","")
--   Windows: splitDrive "\\\\?\\UNC\\shared\\file" == ("\\\\?\\UNC\\shared\\","file")
--   Windows: splitDrive "\\\\?\\UNCshared\\file" == ("\\\\?\\","UNCshared\\file")
--   Windows: splitDrive "\\\\?\\d:\\file" == ("\\\\?\\d:\\","file")
--   Windows: splitDrive "/d" == ("","/d")
--   Posix:   splitDrive "/test" == ("/","test")
--   Posix:   splitDrive "//test" == ("//","test")
--   Posix:   splitDrive "test/file" == ("","test/file")
--   Posix:   splitDrive "file" == ("","file")
--   
splitDrive :: RawFilePath -> (RawFilePath, RawFilePath)

-- | Join a drive and the rest of the path.
--   
--   
--   Valid x => uncurry joinDrive (splitDrive x) == x
--   Windows: joinDrive "C:" "foo" == "C:foo"
--   Windows: joinDrive "C:\\" "bar" == "C:\\bar"
--   Windows: joinDrive "\\\\share" "foo" == "\\\\share\\foo"
--   Windows: joinDrive "/:" "foo" == "/:\\foo"
--   
joinDrive :: RawFilePath -> RawFilePath -> RawFilePath

-- | Get the drive from a filepath.
--   
--   
--   takeDrive x == fst (splitDrive x)
--   
takeDrive :: RawFilePath -> RawFilePath

-- | Does a path have a drive.
--   
--   
--   not (hasDrive x) == null (takeDrive x)
--   Posix:   hasDrive "/foo" == True
--   Windows: hasDrive "C:\\foo" == True
--   Windows: hasDrive "C:foo" == True
--            hasDrive "foo" == False
--            hasDrive "" == False
--   
hasDrive :: RawFilePath -> Bool

-- | Delete the drive, if it exists.
--   
--   
--   dropDrive x == snd (splitDrive x)
--   
dropDrive :: RawFilePath -> RawFilePath

-- | Is an element a drive
--   
--   
--   Posix:   isDrive "/" == True
--   Posix:   isDrive "/foo" == False
--   Windows: isDrive "C:\\" == True
--   Windows: isDrive "C:\\foo" == False
--            isDrive "" == False
--   
isDrive :: RawFilePath -> Bool

-- | Is an item either a directory or the last character a path separator?
--   
--   
--   hasTrailingPathSeparator "test" == False
--   hasTrailingPathSeparator "test/" == True
--   
hasTrailingPathSeparator :: RawFilePath -> Bool

-- | Add a trailing file path separator if one is not already present.
--   
--   
--   hasTrailingPathSeparator (addTrailingPathSeparator x)
--   hasTrailingPathSeparator x ==> addTrailingPathSeparator x == x
--   Posix:    addTrailingPathSeparator "test/rest" == "test/rest/"
--   
addTrailingPathSeparator :: RawFilePath -> RawFilePath

-- | Remove any trailing path separators
--   
--   
--   dropTrailingPathSeparator "file/test/" == "file/test"
--             dropTrailingPathSeparator "/" == "/"
--   Windows:  dropTrailingPathSeparator "\\" == "\\"
--   Posix:    not (hasTrailingPathSeparator (dropTrailingPathSeparator x)) || isDrive x
--   
dropTrailingPathSeparator :: RawFilePath -> RawFilePath

-- | Normalise a file
--   
--   
--   
- // outside of the drive can be made blank
--   
- / -> pathSeparator
--   
- ./ -> ""
--   
--   
--   
--   Posix:   normalise "/file/\\test////" == "/file/\\test/"
--   Posix:   normalise "/file/./test" == "/file/test"
--   Posix:   normalise "/test/file/../bob/fred/" == "/test/file/../bob/fred/"
--   Posix:   normalise "../bob/fred/" == "../bob/fred/"
--   Posix:   normalise "./bob/fred/" == "bob/fred/"
--   Windows: normalise "c:\\file/bob\\" == "C:\\file\\bob\\"
--   Windows: normalise "c:\\" == "C:\\"
--   Windows: normalise "c:\\\\\\\\" == "C:\\"
--   Windows: normalise "C:.\\" == "C:"
--   Windows: normalise "\\\\server\\test" == "\\\\server\\test"
--   Windows: normalise "//server/test" == "\\\\server\\test"
--   Windows: normalise "c:/file" == "C:\\file"
--   Windows: normalise "/file" == "\\file"
--   Windows: normalise "\\" == "\\"
--   Windows: normalise "/./" == "\\"
--            normalise "." == "."
--   Posix:   normalise "./" == "./"
--   Posix:   normalise "./." == "./"
--   Posix:   normalise "/./" == "/"
--   Posix:   normalise "/" == "/"
--   Posix:   normalise "bob/fred/." == "bob/fred/"
--   Posix:   normalise "//home" == "/home"
--   
normalise :: RawFilePath -> RawFilePath

-- | 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
--   DOSNAM~1s.
--   
--   
--            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"
--   Windows: not (equalFilePath "C:" "C:/")
--   
equalFilePath :: RawFilePath -> RawFilePath -> Bool

-- | 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
--   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"
--   Windows: makeRelative "/" "//" == "//"
--   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"
--   
makeRelative :: RawFilePath -> RawFilePath -> RawFilePath

-- | Is a path relative, or is it fixed to the root?
--   
--   
--   Windows: isRelative "path\\test" == True
--   Windows: isRelative "c:\\test" == False
--   Windows: isRelative "c:test" == True
--   Windows: isRelative "c:\\" == False
--   Windows: isRelative "c:/" == False
--   Windows: isRelative "c:" == True
--   Windows: isRelative "\\\\foo" == False
--   Windows: isRelative "\\\\?\\foo" == False
--   Windows: isRelative "\\\\?\\UNC\\foo" == False
--   Windows: isRelative "/foo" == True
--   Windows: isRelative "\\foo" == True
--   Posix:   isRelative "test/path" == True
--   Posix:   isRelative "/test" == False
--   Posix:   isRelative "/" == False
--   
--   
--   According to [1]:
--   
--   
--   
- "A UNC name of any format [is never relative]."
--   
- "You cannot use the "\?" prefix with a relative path."
--   
isRelative :: RawFilePath -> Bool

-- | 
--   not . isRelative
--   
--   
--   
--   isAbsolute x == not (isRelative x)
--   
isAbsolute :: RawFilePath -> Bool

-- | Is a RawFilePath valid, i.e. could you create a file like it? This
--   function checks for invalid names, and invalid characters, but does
--   not check if length limits are exceeded, as these are typically
--   filesystem dependent.
--   
--   
--            isValid "" == False
--            isValid "\0" == False
--   Posix:   isValid "/random_ path:*" == True
--   Posix:   isValid x == (x /= mempty)
--   Windows: isValid "c:\\test" == True
--   Windows: isValid "c:\\test:of_test" == False
--   Windows: isValid "test*" == False
--   Windows: isValid "c:\\test\\nul" == False
--   Windows: isValid "c:\\test\\prn.txt" == False
--   Windows: isValid "c:\\nul\\file" == False
--   Windows: isValid "\\\\" == False
--   Windows: isValid "\\\\\\foo" == False
--   Windows: isValid "\\\\?\\D:file" == False
--   Windows: isValid "foo\tbar" == False
--   Windows: isValid "nul .txt" == False
--   Windows: isValid " nul.txt" == True
--   
isValid :: RawFilePath -> Bool

-- | Take a FilePath and make it valid; does not change already valid
--   FilePaths.
--   
--   
--   isValid (makeValid x)
--   isValid x ==> makeValid x == x
--   makeValid "" == "_"
--   makeValid "file\0name" == "file_name"
--   Windows: makeValid "c:\\already\\/valid" == "c:\\already\\/valid"
--   Windows: makeValid "c:\\test:of_test" == "c:\\test_of_test"
--   Windows: makeValid "test*" == "test_"
--   Windows: makeValid "c:\\test\\nul" == "c:\\test\\nul_"
--   Windows: makeValid "c:\\test\\prn.txt" == "c:\\test\\prn_.txt"
--   Windows: makeValid "c:\\test/prn.txt" == "c:\\test/prn_.txt"
--   Windows: makeValid "c:\\nul\\file" == "c:\\nul_\\file"
--   Windows: makeValid "\\\\\\foo" == "\\\\drive"
--   Windows: makeValid "\\\\?\\D:file" == "\\\\?\\D:\\file"
--   Windows: makeValid "nul .txt" == "nul _.txt"
--   
makeValid :: RawFilePath -> RawFilePath

-- | A library for RawFilePath manipulations, using Posix or Windows
--   filepaths depending on the platform.
--   
--   Both System.FilePath.Posix.ByteString and
--   System.FilePath.Windows.ByteString provide the same interface.
--   See either for examples and a list of the available functions.
module System.FilePath.ByteString

-- | A library for RawFilePath manipulations, using Windows style
--   paths on all platforms. Importing System.FilePath.ByteString is
--   usually better.
--   
--   This module is the same as System.FilePath.Windows from the filepath
--   library, except it uses RawFilePath.
--   
--   Given the example RawFilePath: /directory/file.ext
--   
--   We can use the following functions to extract pieces.
--   
--   
--   
- takeFileName gives "file.ext"
--   
- takeDirectory gives "/directory"
--   
- takeExtension gives ".ext"
--   
- dropExtension gives "/directory/file"
--   
- takeBaseName gives "file"
--   
--   
--   And we could have built an equivalent path with the following
--   expressions:
--   
--   
--   
- "/directory" </> "file.ext".
--   
- "/directory/file" <.> "ext".
--   
- "/directory/file.txt" -<.> "ext".
--   
--   
--   Each function in this module is documented with several examples,
--   which are also used as tests.
--   
--   Here are a few examples of using the filepath functions
--   together:
--   
--   Example 1: Find the possible locations of a Haskell module
--   Test imported from module Main:
--   
--   
--   [replaceFileName path_to_main "Test" <.> ext | ext <- ["hs","lhs"] ]
--   
--   
--   Example 2: Compile a Haskell file, putting the .hi
--   file under interface:
--   
--   
--   takeDirectory file </> "interface" </> (takeFileName file -<.> "hi")
--   
--   
--   References: [1] Naming Files, Paths and Namespaces (Microsoft
--   MSDN)
module System.FilePath.Windows.ByteString

-- | A literal POSIX file path
type RawFilePath = ByteString

-- | Convert from FilePath to RawFilePath.
--   
--   When run on Unix, this applies the filesystem encoding (see
--   getFileSystemEncoding).
--   
--   When run on Windows, this encodes as UTF-8.
--   
--   the implementation of this function assumes that the filesystem
--   encoding will not be changed while the program is running.
encodeFilePath :: FilePath -> RawFilePath

-- | Convert from RawFilePath to FilePath
--   
--   When run on Unix, this applies the filesystem encoding (see
--   getFileSystemEncoding).
--   
--   When run on Windows, this decodes UTF-8.
decodeFilePath :: RawFilePath -> FilePath

-- | The character that separates directories. In the case where more than
--   one character is possible, pathSeparator is the 'ideal' one.
--   
--   
--   Windows: pathSeparator == fromIntegral (ord '\\')
--   Posix:   pathSeparator == fromIntegral (ord '/')
--   isPathSeparator pathSeparator
--   
pathSeparator :: Word8

-- | The list of all possible separators.
--   
--   
--   Windows: pathSeparators == [fromIntegral (ord '\\'), fromIntegral (ord '/')]
--   Posix:   pathSeparators == [fromIntegral (ord '/')]
--   pathSeparator `elem` pathSeparators
--   
pathSeparators :: [Word8]

-- | Rather than using (== pathSeparator), use this. Test
--   if something is a path separator.
--   
--   
--   isPathSeparator a == (a `elem` pathSeparators)
--   
isPathSeparator :: Word8 -> Bool

-- | The character that is used to separate the entries in the $PATH
--   environment variable.
--   
--   
--   Windows: searchPathSeparator == fromIntegral (ord ';')
--   Posix:   searchPathSeparator == fromIntegral (ord ':')
--   
searchPathSeparator :: Word8

-- | Is the character a file separator?
--   
--   
--   isSearchPathSeparator a == (a == searchPathSeparator)
--   
isSearchPathSeparator :: Word8 -> Bool

-- | File extension character
--   
--   
--   extSeparator == fromIntegral (ord '.')
--   
extSeparator :: Word8

-- | Is the character an extension character?
--   
--   
--   isExtSeparator a == (a == extSeparator)
--   
isExtSeparator :: Word8 -> Bool

-- | Take a string, split it on the searchPathSeparator character.
--   Blank items are ignored on Windows, and converted to . on
--   Posix. On Windows path elements are stripped of quotes.
--   
--   Follows the recommendations in
--   http://www.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap08.html
--   
--   
--   Posix:   splitSearchPath "File1:File2:File3"  == ["File1","File2","File3"]
--   Posix:   splitSearchPath "File1::File2:File3" == ["File1",".","File2","File3"]
--   Windows: splitSearchPath "File1;File2;File3"  == ["File1","File2","File3"]
--   Windows: splitSearchPath "File1;;File2;File3" == ["File1","File2","File3"]
--   Windows: splitSearchPath "File1;\"File2\";File3" == ["File1","File2","File3"]
--   
splitSearchPath :: ByteString -> [RawFilePath]

-- | Get a list of RawFilePaths in the $PATH variable.
getSearchPath :: IO [RawFilePath]

-- | Split on the extension. addExtension is the inverse.
--   
--   
--   splitExtension "/directory/path.ext" == ("/directory/path",".ext")
--   uncurry (<>) (splitExtension x) == x
--   Valid x => uncurry addExtension (splitExtension x) == x
--   splitExtension "file.txt" == ("file",".txt")
--   splitExtension "file" == ("file","")
--   splitExtension "file/file.txt" == ("file/file",".txt")
--   splitExtension "file.txt/boris" == ("file.txt/boris","")
--   splitExtension "file.txt/boris.ext" == ("file.txt/boris",".ext")
--   splitExtension "file/path.txt.bob.fred" == ("file/path.txt.bob",".fred")
--   splitExtension "file/path.txt/" == ("file/path.txt/","")
--   
splitExtension :: RawFilePath -> (ByteString, ByteString)

-- | Get the extension of a file, returns "" for no extension,
--   .ext otherwise.
--   
--   
--   takeExtension "/directory/path.ext" == ".ext"
--   takeExtension x == snd (splitExtension x)
--   Valid x => takeExtension (addExtension x "ext") == ".ext"
--   Valid x => takeExtension (replaceExtension x "ext") == ".ext"
--   
takeExtension :: RawFilePath -> ByteString

-- | Set the extension of a file, overwriting one if already present,
--   equivalent to -<.>.
--   
--   
--   replaceExtension "/directory/path.txt" "ext" == "/directory/path.ext"
--   replaceExtension "/directory/path.txt" ".ext" == "/directory/path.ext"
--   replaceExtension "file.txt" ".bob" == "file.bob"
--   replaceExtension "file.txt" "bob" == "file.bob"
--   replaceExtension "file" ".bob" == "file.bob"
--   replaceExtension "file.txt" "" == "file"
--   replaceExtension "file.fred.bob" "txt" == "file.fred.txt"
--   replaceExtension x y == addExtension (dropExtension x) y
--   
replaceExtension :: RawFilePath -> ByteString -> RawFilePath

-- | Remove the current extension and add another, equivalent to
--   replaceExtension.
--   
--   
--   "/directory/path.txt" -<.> "ext" == "/directory/path.ext"
--   "/directory/path.txt" -<.> ".ext" == "/directory/path.ext"
--   "foo.o" -<.> "c" == "foo.c"
--   
(-<.>) :: RawFilePath -> ByteString -> RawFilePath
infixr 7 -<.>

-- | Remove last extension, and the "." preceding it.
--   
--   
--   dropExtension "/directory/path.ext" == "/directory/path"
--   dropExtension x == fst (splitExtension x)
--   
dropExtension :: RawFilePath -> RawFilePath

-- | Add an extension, even if there is already one there, equivalent to
--   <.>.
--   
--   
--   addExtension "/directory/path" "ext" == "/directory/path.ext"
--   addExtension "file.txt" "bib" == "file.txt.bib"
--   addExtension "file." ".bib" == "file..bib"
--   addExtension "file" ".bib" == "file.bib"
--   addExtension "/" "x" == "/.x"
--   addExtension x "" == x
--   Valid x => takeFileName (addExtension (addTrailingPathSeparator x) "ext") == ".ext"
--   Windows: addExtension "\\\\share" ".txt" == "\\\\share\\.txt"
--   
addExtension :: RawFilePath -> ByteString -> RawFilePath

-- | Does the given filename have an extension?
--   
--   
--   hasExtension "/directory/path.ext" == True
--   hasExtension "/directory/path" == False
--   null (takeExtension x) == not (hasExtension x)
--   
hasExtension :: RawFilePath -> Bool

-- | Add an extension, even if there is already one there, equivalent to
--   addExtension.
--   
--   
--   "/directory/path" <.> "ext" == "/directory/path.ext"
--   "/directory/path" <.> ".ext" == "/directory/path.ext"
--   
(<.>) :: RawFilePath -> ByteString -> RawFilePath
infixr 7 <.>

-- | Split on all extensions.
--   
--   
--   splitExtensions "/directory/path.ext" == ("/directory/path",".ext")
--   splitExtensions "file.tar.gz" == ("file",".tar.gz")
--   uncurry (<>) (splitExtensions x) == x
--   Valid x => uncurry addExtension (splitExtensions x) == x
--   splitExtensions "file.tar.gz" == ("file",".tar.gz")
--   
splitExtensions :: RawFilePath -> (RawFilePath, ByteString)

-- | Drop all extensions.
--   
--   
--   dropExtensions "/directory/path.ext" == "/directory/path"
--   dropExtensions "file.tar.gz" == "file"
--   not $ hasExtension $ dropExtensions x
--   not $ any isExtSeparator $ takeFileName $ dropExtensions x
--   
dropExtensions :: RawFilePath -> RawFilePath

-- | Get all extensions.
--   
--   
--   takeExtensions "/directory/path.ext" == ".ext"
--   takeExtensions "file.tar.gz" == ".tar.gz"
--   
takeExtensions :: RawFilePath -> ByteString

-- | Replace all extensions of a file with a new extension. Note that
--   replaceExtension and addExtension both work for adding
--   multiple extensions, so only required when you need to drop all
--   extensions first.
--   
--   
--   replaceExtensions "file.fred.bob" "txt" == "file.txt"
--   replaceExtensions "file.fred.bob" "tar.gz" == "file.tar.gz"
--   
replaceExtensions :: RawFilePath -> ByteString -> RawFilePath

-- | Does the given filename have the specified extension?
--   
--   
--   "png" `isExtensionOf` "/directory/file.png" == True
--   ".png" `isExtensionOf` "/directory/file.png" == True
--   ".tar.gz" `isExtensionOf` "bar/foo.tar.gz" == True
--   "ar.gz" `isExtensionOf` "bar/foo.tar.gz" == False
--   "png" `isExtensionOf` "/directory/file.png.jpg" == False
--   "csv/table.csv" `isExtensionOf` "/data/csv/table.csv" == False
--   
isExtensionOf :: ByteString -> RawFilePath -> Bool

-- | Drop the given extension from a FilePath, and the "."
--   preceding it. Returns Nothing if the FilePath does not have the
--   given extension, or Just and the part before the extension if
--   it does.
--   
--   This function can be more predictable than dropExtensions,
--   especially if the filename might itself contain . characters.
--   
--   
--   stripExtension "hs.o" "foo.x.hs.o" == Just "foo.x"
--   stripExtension "hi.o" "foo.x.hs.o" == Nothing
--   dropExtension x == fromJust (stripExtension (takeExtension x) x)
--   dropExtensions x == fromJust (stripExtension (takeExtensions x) x)
--   stripExtension ".c.d" "a.b.c.d"  == Just "a.b"
--   stripExtension ".c.d" "a.b..c.d" == Just "a.b."
--   stripExtension "baz"  "foo.bar"  == Nothing
--   stripExtension "bar"  "foobar"   == Nothing
--   stripExtension ""     x          == Just x
--   
stripExtension :: ByteString -> RawFilePath -> Maybe RawFilePath

-- | Split a filename into directory and file. </> is the
--   inverse. The first component will often end with a trailing slash.
--   
--   
--   splitFileName "/directory/file.ext" == ("/directory/","file.ext")
--   Valid x => uncurry (</>) (splitFileName x) == x || fst (splitFileName x) == "./"
--   Valid x => isValid (fst (splitFileName x))
--   splitFileName "file/bob.txt" == ("file/", "bob.txt")
--   splitFileName "file/" == ("file/", "")
--   splitFileName "bob" == ("./", "bob")
--   Posix:   splitFileName "/" == ("/","")
--   Windows: splitFileName "c:" == ("c:","")
--   
splitFileName :: RawFilePath -> (ByteString, ByteString)

-- | Get the file name.
--   
--   
--   takeFileName "/directory/file.ext" == "file.ext"
--   takeFileName "test/" == ""
--   takeFileName x `isSuffixOf` x
--   takeFileName x == snd (splitFileName x)
--   Valid x => takeFileName (replaceFileName x "fred") == "fred"
--   Valid x => takeFileName (x </> "fred") == "fred"
--   Valid x => isRelative (takeFileName x)
--   
takeFileName :: RawFilePath -> RawFilePath

-- | Set the filename.
--   
--   
--   replaceFileName "/directory/other.txt" "file.ext" == "/directory/file.ext"
--   Valid x => replaceFileName x (takeFileName x) == x
--   
replaceFileName :: RawFilePath -> ByteString -> RawFilePath

-- | Drop the filename. Unlike takeDirectory, this function will
--   leave a trailing path separator on the directory.
--   
--   
--   dropFileName "/directory/file.ext" == "/directory/"
--   dropFileName x == fst (splitFileName x)
--   
dropFileName :: RawFilePath -> RawFilePath

-- | Get the base name, without an extension or path.
--   
--   
--   takeBaseName "/directory/file.ext" == "file"
--   takeBaseName "file/test.txt" == "test"
--   takeBaseName "dave.ext" == "dave"
--   takeBaseName "" == ""
--   takeBaseName "test" == "test"
--   takeBaseName (addTrailingPathSeparator x) == ""
--   takeBaseName "file/file.tar.gz" == "file.tar"
--   
takeBaseName :: RawFilePath -> ByteString

-- | Set the base name.
--   
--   
--   replaceBaseName "/directory/other.ext" "file" == "/directory/file.ext"
--   replaceBaseName "file/test.txt" "bob" == "file/bob.txt"
--   replaceBaseName "fred" "bill" == "bill"
--   replaceBaseName "/dave/fred/bob.gz.tar" "new" == "/dave/fred/new.tar"
--   Valid x => replaceBaseName x (takeBaseName x) == x
--   
replaceBaseName :: RawFilePath -> ByteString -> RawFilePath

-- | Get the directory name, move up one level.
--   
--   
--             takeDirectory "/directory/other.ext" == "/directory"
--             takeDirectory x `isPrefixOf` x || takeDirectory x == "."
--             takeDirectory "foo" == "."
--             takeDirectory "/" == "/"
--             takeDirectory "/foo" == "/"
--             takeDirectory "/foo/bar/baz" == "/foo/bar"
--             takeDirectory "/foo/bar/baz/" == "/foo/bar/baz"
--             takeDirectory "foo/bar/baz" == "foo/bar"
--   Windows:  takeDirectory "foo\\bar" == "foo"
--   Windows:  takeDirectory "foo\\bar\\\\" == "foo\\bar"
--   Windows:  takeDirectory "C:\\" == "C:\\"
--   
takeDirectory :: RawFilePath -> RawFilePath

-- | Set the directory, keeping the filename the same.
--   
--   
--   replaceDirectory "root/file.ext" "/directory/" == "/directory/file.ext"
--   Valid x => replaceDirectory x (takeDirectory x) `equalFilePath` x
--   
replaceDirectory :: RawFilePath -> ByteString -> RawFilePath

-- | An alias for </>.
combine :: RawFilePath -> RawFilePath -> RawFilePath

-- | Combine two paths with a path separator. If the second path starts
--   with a path separator or a drive letter, then it returns the second.
--   The intention is that readFile (dir </> file)
--   will access the same file as setCurrentDirectory dir; readFile
--   file.
--   
--   
--   Posix:   "/directory" </> "file.ext" == "/directory/file.ext"
--   Windows: "/directory" </> "file.ext" == "/directory\\file.ext"
--            "directory" </> "/file.ext" == "/file.ext"
--   Valid x => (takeDirectory x </> takeFileName x) `equalFilePath` x
--   
--   
--   Combined:
--   
--   
--   Posix:   "/" </> "test" == "/test"
--   Posix:   "home" </> "bob" == "home/bob"
--   Posix:   "x:" </> "foo" == "x:/foo"
--   Windows: "C:\\foo" </> "bar" == "C:\\foo\\bar"
--   Windows: "home" </> "bob" == "home\\bob"
--   
--   
--   Not combined:
--   
--   
--   Posix:   "home" </> "/bob" == "/bob"
--   Windows: "home" </> "C:\\bob" == "C:\\bob"
--   
--   
--   Not combined (tricky):
--   
--   On Windows, if a filepath starts with a single slash, it is relative
--   to the root of the current drive. In [1], this is (confusingly)
--   referred to as an absolute path. The current behavior of
--   </> is to never combine these forms.
--   
--   
--   Windows: "home" </> "/bob" == "/bob"
--   Windows: "home" </> "\\bob" == "\\bob"
--   Windows: "C:\\home" </> "\\bob" == "\\bob"
--   
--   
--   On Windows, from [1]: "If a file name begins with only a disk
--   designator but not the backslash after the colon, it is interpreted as
--   a relative path to the current directory on the drive with the
--   specified letter." The current behavior of </> is to
--   never combine these forms.
--   
--   
--   Windows: "D:\\foo" </> "C:bar" == "C:bar"
--   Windows: "C:\\foo" </> "C:bar" == "C:bar"
--   
(</>) :: RawFilePath -> RawFilePath -> RawFilePath
infixr 5 </>

-- | Split a path by the directory separator.
--   
--   
--   splitPath "/directory/file.ext" == ["/","directory/","file.ext"]
--   mconcat (splitPath x) == x
--   splitPath "test//item/" == ["test//","item/"]
--   splitPath "test/item/file" == ["test/","item/","file"]
--   splitPath "" == []
--   Windows: splitPath "c:\\test\\path" == ["c:\\","test\\","path"]
--   Posix:   splitPath "/file/test" == ["/","file/","test"]
--   
splitPath :: RawFilePath -> [RawFilePath]

-- | Join path elements back together.
--   
--   
--   joinPath ["/","directory/","file.ext"] == "/directory/file.ext"
--   Valid x => joinPath (splitPath x) == x
--   joinPath [] == ""
--   Posix: joinPath ["test","file","path"] == "test/file/path"
--   
joinPath :: [RawFilePath] -> RawFilePath

-- | Just as splitPath, but don't add the trailing slashes to each
--   element.
--   
--   
--            splitDirectories "/directory/file.ext" == ["/","directory","file.ext"]
--            splitDirectories "test/file" == ["test","file"]
--            splitDirectories "/test/file" == ["/","test","file"]
--   Windows: splitDirectories "C:\\test\\file" == ["C:\\", "test", "file"]
--            Valid x => joinPath (splitDirectories x) `equalFilePath` x
--            splitDirectories "" == []
--   Windows: splitDirectories "C:\\test\\\\\\file" == ["C:\\", "test", "file"]
--            splitDirectories "/test///file" == ["/","test","file"]
--   
splitDirectories :: RawFilePath -> [RawFilePath]

-- | Split a path into a drive and a path. On Posix, / is a Drive.
--   
--   
--   uncurry (<>) (splitDrive x) == x
--   Windows: splitDrive "file" == ("","file")
--   Windows: splitDrive "c:/file" == ("c:/","file")
--   Windows: splitDrive "c:\\file" == ("c:\\","file")
--   Windows: splitDrive "\\\\shared\\test" == ("\\\\shared\\","test")
--   Windows: splitDrive "\\\\shared" == ("\\\\shared","")
--   Windows: splitDrive "\\\\?\\UNC\\shared\\file" == ("\\\\?\\UNC\\shared\\","file")
--   Windows: splitDrive "\\\\?\\UNCshared\\file" == ("\\\\?\\","UNCshared\\file")
--   Windows: splitDrive "\\\\?\\d:\\file" == ("\\\\?\\d:\\","file")
--   Windows: splitDrive "/d" == ("","/d")
--   Posix:   splitDrive "/test" == ("/","test")
--   Posix:   splitDrive "//test" == ("//","test")
--   Posix:   splitDrive "test/file" == ("","test/file")
--   Posix:   splitDrive "file" == ("","file")
--   
splitDrive :: RawFilePath -> (RawFilePath, RawFilePath)

-- | Join a drive and the rest of the path.
--   
--   
--   Valid x => uncurry joinDrive (splitDrive x) == x
--   Windows: joinDrive "C:" "foo" == "C:foo"
--   Windows: joinDrive "C:\\" "bar" == "C:\\bar"
--   Windows: joinDrive "\\\\share" "foo" == "\\\\share\\foo"
--   Windows: joinDrive "/:" "foo" == "/:\\foo"
--   
joinDrive :: RawFilePath -> RawFilePath -> RawFilePath

-- | Get the drive from a filepath.
--   
--   
--   takeDrive x == fst (splitDrive x)
--   
takeDrive :: RawFilePath -> RawFilePath

-- | Does a path have a drive.
--   
--   
--   not (hasDrive x) == null (takeDrive x)
--   Posix:   hasDrive "/foo" == True
--   Windows: hasDrive "C:\\foo" == True
--   Windows: hasDrive "C:foo" == True
--            hasDrive "foo" == False
--            hasDrive "" == False
--   
hasDrive :: RawFilePath -> Bool

-- | Delete the drive, if it exists.
--   
--   
--   dropDrive x == snd (splitDrive x)
--   
dropDrive :: RawFilePath -> RawFilePath

-- | Is an element a drive
--   
--   
--   Posix:   isDrive "/" == True
--   Posix:   isDrive "/foo" == False
--   Windows: isDrive "C:\\" == True
--   Windows: isDrive "C:\\foo" == False
--            isDrive "" == False
--   
isDrive :: RawFilePath -> Bool

-- | Is an item either a directory or the last character a path separator?
--   
--   
--   hasTrailingPathSeparator "test" == False
--   hasTrailingPathSeparator "test/" == True
--   
hasTrailingPathSeparator :: RawFilePath -> Bool

-- | Add a trailing file path separator if one is not already present.
--   
--   
--   hasTrailingPathSeparator (addTrailingPathSeparator x)
--   hasTrailingPathSeparator x ==> addTrailingPathSeparator x == x
--   Posix:    addTrailingPathSeparator "test/rest" == "test/rest/"
--   
addTrailingPathSeparator :: RawFilePath -> RawFilePath

-- | Remove any trailing path separators
--   
--   
--   dropTrailingPathSeparator "file/test/" == "file/test"
--             dropTrailingPathSeparator "/" == "/"
--   Windows:  dropTrailingPathSeparator "\\" == "\\"
--   Posix:    not (hasTrailingPathSeparator (dropTrailingPathSeparator x)) || isDrive x
--   
dropTrailingPathSeparator :: RawFilePath -> RawFilePath

-- | Normalise a file
--   
--   
--   
- // outside of the drive can be made blank
--   
- / -> pathSeparator
--   
- ./ -> ""
--   
--   
--   
--   Posix:   normalise "/file/\\test////" == "/file/\\test/"
--   Posix:   normalise "/file/./test" == "/file/test"
--   Posix:   normalise "/test/file/../bob/fred/" == "/test/file/../bob/fred/"
--   Posix:   normalise "../bob/fred/" == "../bob/fred/"
--   Posix:   normalise "./bob/fred/" == "bob/fred/"
--   Windows: normalise "c:\\file/bob\\" == "C:\\file\\bob\\"
--   Windows: normalise "c:\\" == "C:\\"
--   Windows: normalise "c:\\\\\\\\" == "C:\\"
--   Windows: normalise "C:.\\" == "C:"
--   Windows: normalise "\\\\server\\test" == "\\\\server\\test"
--   Windows: normalise "//server/test" == "\\\\server\\test"
--   Windows: normalise "c:/file" == "C:\\file"
--   Windows: normalise "/file" == "\\file"
--   Windows: normalise "\\" == "\\"
--   Windows: normalise "/./" == "\\"
--            normalise "." == "."
--   Posix:   normalise "./" == "./"
--   Posix:   normalise "./." == "./"
--   Posix:   normalise "/./" == "/"
--   Posix:   normalise "/" == "/"
--   Posix:   normalise "bob/fred/." == "bob/fred/"
--   Posix:   normalise "//home" == "/home"
--   
normalise :: RawFilePath -> RawFilePath

-- | 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
--   DOSNAM~1s.
--   
--   
--            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"
--   Windows: not (equalFilePath "C:" "C:/")
--   
equalFilePath :: RawFilePath -> RawFilePath -> Bool

-- | 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
--   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"
--   Windows: makeRelative "/" "//" == "//"
--   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"
--   
makeRelative :: RawFilePath -> RawFilePath -> RawFilePath

-- | Is a path relative, or is it fixed to the root?
--   
--   
--   Windows: isRelative "path\\test" == True
--   Windows: isRelative "c:\\test" == False
--   Windows: isRelative "c:test" == True
--   Windows: isRelative "c:\\" == False
--   Windows: isRelative "c:/" == False
--   Windows: isRelative "c:" == True
--   Windows: isRelative "\\\\foo" == False
--   Windows: isRelative "\\\\?\\foo" == False
--   Windows: isRelative "\\\\?\\UNC\\foo" == False
--   Windows: isRelative "/foo" == True
--   Windows: isRelative "\\foo" == True
--   Posix:   isRelative "test/path" == True
--   Posix:   isRelative "/test" == False
--   Posix:   isRelative "/" == False
--   
--   
--   According to [1]:
--   
--   
--   
- "A UNC name of any format [is never relative]."
--   
- "You cannot use the "\?" prefix with a relative path."
--   
isRelative :: RawFilePath -> Bool

-- | 
--   not . isRelative
--   
--   
--   
--   isAbsolute x == not (isRelative x)
--   
isAbsolute :: RawFilePath -> Bool

-- | Is a RawFilePath valid, i.e. could you create a file like it? This
--   function checks for invalid names, and invalid characters, but does
--   not check if length limits are exceeded, as these are typically
--   filesystem dependent.
--   
--   
--            isValid "" == False
--            isValid "\0" == False
--   Posix:   isValid "/random_ path:*" == True
--   Posix:   isValid x == (x /= mempty)
--   Windows: isValid "c:\\test" == True
--   Windows: isValid "c:\\test:of_test" == False
--   Windows: isValid "test*" == False
--   Windows: isValid "c:\\test\\nul" == False
--   Windows: isValid "c:\\test\\prn.txt" == False
--   Windows: isValid "c:\\nul\\file" == False
--   Windows: isValid "\\\\" == False
--   Windows: isValid "\\\\\\foo" == False
--   Windows: isValid "\\\\?\\D:file" == False
--   Windows: isValid "foo\tbar" == False
--   Windows: isValid "nul .txt" == False
--   Windows: isValid " nul.txt" == True
--   
isValid :: RawFilePath -> Bool

-- | Take a FilePath and make it valid; does not change already valid
--   FilePaths.
--   
--   
--   isValid (makeValid x)
--   isValid x ==> makeValid x == x
--   makeValid "" == "_"
--   makeValid "file\0name" == "file_name"
--   Windows: makeValid "c:\\already\\/valid" == "c:\\already\\/valid"
--   Windows: makeValid "c:\\test:of_test" == "c:\\test_of_test"
--   Windows: makeValid "test*" == "test_"
--   Windows: makeValid "c:\\test\\nul" == "c:\\test\\nul_"
--   Windows: makeValid "c:\\test\\prn.txt" == "c:\\test\\prn_.txt"
--   Windows: makeValid "c:\\test/prn.txt" == "c:\\test/prn_.txt"
--   Windows: makeValid "c:\\nul\\file" == "c:\\nul_\\file"
--   Windows: makeValid "\\\\\\foo" == "\\\\drive"
--   Windows: makeValid "\\\\?\\D:file" == "\\\\?\\D:\\file"
--   Windows: makeValid "nul .txt" == "nul _.txt"
--   
makeValid :: RawFilePath -> RawFilePath
