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


-- | Library for manipulating FilePaths in a cross platform way.
--   
--   This package provides functionality for manipulating <tt>FilePath</tt>
--   values, and is shipped with <a>GHC</a>. It provides two variants for
--   filepaths:
--   
--   <ol>
--   <li>legacy filepaths: <tt>type FilePath = String</tt></li>
--   <li>operating system abstracted filepaths (<tt>OsPath</tt>):
--   internally unpinned <tt>ShortByteString</tt> (platform-dependent
--   encoding)</li>
--   </ol>
--   
--   It is recommended to use <tt>OsPath</tt> when possible, because it is
--   more correct.
--   
--   For each variant there are three main modules:
--   
--   <ul>
--   <li><a>System.FilePath.Posix</a> / <a>System.OsPath.Posix</a>
--   manipulates POSIX/Linux style <tt>FilePath</tt> values (with
--   <tt>/</tt> as the path separator).</li>
--   <li><a>System.FilePath.Windows</a> / <a>System.OsPath.Windows</a>
--   manipulates Windows style <tt>FilePath</tt> values (with either
--   <tt>\</tt> or <tt>/</tt> as the path separator, and deals with
--   drives).</li>
--   <li><a>System.FilePath</a> / <a>System.OsPath</a> for dealing with
--   current platform-specific filepaths</li>
--   </ul>
--   
--   <a>System.OsString</a> is like <a>System.OsPath</a>, but more general
--   purpose. Refer to the documentation of those modules for more
--   information.
--   
--   An introduction into the new API can be found in this <a>blog
--   post</a>. Code examples for the new API can be found <a>here</a>.
@package filepath
@version 1.4.300.1


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

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

-- | The character that separates directories. In the case where more than
--   one character is possible, <a>pathSeparator</a> is the 'ideal' one.
--   
--   <pre>
--   Windows: pathSeparator == '\\'
--   Posix:   pathSeparator ==  '/'
--   isPathSeparator pathSeparator
--   </pre>
pathSeparator :: Char

-- | The list of all possible separators.
--   
--   <pre>
--   Windows: pathSeparators == ['\\', '/']
--   Posix:   pathSeparators == ['/']
--   pathSeparator `elem` pathSeparators
--   </pre>
pathSeparators :: [Char]

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

-- | The character that is used to separate the entries in the $PATH
--   environment variable.
--   
--   <pre>
--   Windows: searchPathSeparator == ';'
--   Posix:   searchPathSeparator == ':'
--   </pre>
searchPathSeparator :: Char

-- | Is the character a file separator?
--   
--   <pre>
--   isSearchPathSeparator a == (a == searchPathSeparator)
--   </pre>
isSearchPathSeparator :: Char -> Bool

-- | File extension character
--   
--   <pre>
--   extSeparator == '.'
--   </pre>
extSeparator :: Char

-- | Is the character an extension character?
--   
--   <pre>
--   isExtSeparator a == (a == extSeparator)
--   </pre>
isExtSeparator :: Char -> Bool

-- | Take a string, split it on the <a>searchPathSeparator</a> character.
--   Blank items are ignored on Windows, and converted to <tt>.</tt> on
--   Posix. On Windows path elements are stripped of quotes.
--   
--   Follows the recommendations in
--   <a>http://www.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap08.html</a>
--   
--   <pre>
--   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"]
--   </pre>
splitSearchPath :: String -> [FilePath]

-- | Get a list of <tt>FILEPATH</tt>s in the $PATH variable.
getSearchPath :: IO [FilePath]

-- | Split on the extension. <a>addExtension</a> is the inverse.
--   
--   <pre>
--   splitExtension "/directory/path.ext" == ("/directory/path",".ext")
--   uncurry (&lt;&gt;) (splitExtension x) == x
--   Valid x =&gt; 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/","")
--   </pre>
splitExtension :: FilePath -> (String, String)

-- | Get the extension of a file, returns <tt>""</tt> for no extension,
--   <tt>.ext</tt> otherwise.
--   
--   <pre>
--   takeExtension "/directory/path.ext" == ".ext"
--   takeExtension x == snd (splitExtension x)
--   Valid x =&gt; takeExtension (addExtension x "ext") == ".ext"
--   Valid x =&gt; takeExtension (replaceExtension x "ext") == ".ext"
--   </pre>
takeExtension :: FilePath -> String

-- | Set the extension of a file, overwriting one if already present,
--   equivalent to <a>-&lt;.&gt;</a>.
--   
--   <pre>
--   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
--   </pre>
replaceExtension :: FilePath -> String -> FilePath

-- | Remove the current extension and add another, equivalent to
--   <a>replaceExtension</a>.
--   
--   <pre>
--   "/directory/path.txt" -&lt;.&gt; "ext" == "/directory/path.ext"
--   "/directory/path.txt" -&lt;.&gt; ".ext" == "/directory/path.ext"
--   "foo.o" -&lt;.&gt; "c" == "foo.c"
--   </pre>
(-<.>) :: FilePath -> String -> FilePath
infixr 7 -<.>

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

-- | Add an extension, even if there is already one there, equivalent to
--   <a>&lt;.&gt;</a>.
--   
--   <pre>
--   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 =&gt; takeFileName (addExtension (addTrailingPathSeparator x) "ext") == ".ext"
--   Windows: addExtension "\\\\share" ".txt" == "\\\\share\\.txt"
--   </pre>
addExtension :: FilePath -> String -> FilePath

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

-- | Add an extension, even if there is already one there, equivalent to
--   <a>addExtension</a>.
--   
--   <pre>
--   "/directory/path" &lt;.&gt; "ext" == "/directory/path.ext"
--   "/directory/path" &lt;.&gt; ".ext" == "/directory/path.ext"
--   </pre>
(<.>) :: FilePath -> String -> FilePath
infixr 7 <.>

-- | Split on all extensions.
--   
--   <pre>
--   splitExtensions "/directory/path.ext" == ("/directory/path",".ext")
--   splitExtensions "file.tar.gz" == ("file",".tar.gz")
--   uncurry (&lt;&gt;) (splitExtensions x) == x
--   Valid x =&gt; uncurry addExtension (splitExtensions x) == x
--   splitExtensions "file.tar.gz" == ("file",".tar.gz")
--   </pre>
splitExtensions :: FilePath -> (FilePath, String)

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

-- | Get all extensions.
--   
--   <pre>
--   takeExtensions "/directory/path.ext" == ".ext"
--   takeExtensions "file.tar.gz" == ".tar.gz"
--   </pre>
takeExtensions :: FilePath -> String

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

-- | Does the given filename have the specified extension?
--   
--   <pre>
--   "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
--   </pre>
isExtensionOf :: String -> FilePath -> Bool

-- | Drop the given extension from a FilePath, and the <tt>"."</tt>
--   preceding it. Returns <a>Nothing</a> if the FilePath does not have the
--   given extension, or <a>Just</a> and the part before the extension if
--   it does.
--   
--   This function can be more predictable than <a>dropExtensions</a>,
--   especially if the filename might itself contain <tt>.</tt> characters.
--   
--   <pre>
--   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
--   </pre>
stripExtension :: String -> FilePath -> Maybe FilePath

-- | Split a filename into directory and file. <a>&lt;/&gt;</a> is the
--   inverse. The first component will often end with a trailing slash.
--   
--   <pre>
--   splitFileName "/directory/file.ext" == ("/directory/","file.ext")
--   Valid x =&gt; uncurry (&lt;/&gt;) (splitFileName x) == x || fst (splitFileName x) == "./"
--   Valid x =&gt; isValid (fst (splitFileName x))
--   splitFileName "file/bob.txt" == ("file/", "bob.txt")
--   splitFileName "file/" == ("file/", "")
--   splitFileName "bob" == ("./", "bob")
--   Posix:   splitFileName "/" == ("/","")
--   Windows: splitFileName "c:" == ("c:","")
--   Windows: splitFileName "\\\\?\\A:\\fred" == ("\\\\?\\A:\\","fred")
--   Windows: splitFileName "\\\\?\\A:" == ("\\\\?\\A:","")
--   </pre>
splitFileName :: FilePath -> (String, String)

-- | Get the file name.
--   
--   <pre>
--   takeFileName "/directory/file.ext" == "file.ext"
--   takeFileName "test/" == ""
--   isSuffixOf (takeFileName x) x
--   takeFileName x == snd (splitFileName x)
--   Valid x =&gt; takeFileName (replaceFileName x "fred") == "fred"
--   Valid x =&gt; takeFileName (x &lt;/&gt; "fred") == "fred"
--   Valid x =&gt; isRelative (takeFileName x)
--   </pre>
takeFileName :: FilePath -> FilePath

-- | Set the filename.
--   
--   <pre>
--   replaceFileName "/directory/other.txt" "file.ext" == "/directory/file.ext"
--   Valid x =&gt; replaceFileName x (takeFileName x) == x
--   </pre>
replaceFileName :: FilePath -> String -> FilePath

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

-- | Get the base name, without an extension or path.
--   
--   <pre>
--   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"
--   </pre>
takeBaseName :: FilePath -> String

-- | Set the base name.
--   
--   <pre>
--   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 =&gt; replaceBaseName x (takeBaseName x) == x
--   </pre>
replaceBaseName :: FilePath -> String -> FilePath

-- | Get the directory name, move up one level.
--   
--   <pre>
--             takeDirectory "/directory/other.ext" == "/directory"
--             isPrefixOf (takeDirectory x) 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:\\"
--   </pre>
takeDirectory :: FilePath -> FilePath

-- | Set the directory, keeping the filename the same.
--   
--   <pre>
--   replaceDirectory "root/file.ext" "/directory/" == "/directory/file.ext"
--   Valid x =&gt; replaceDirectory x (takeDirectory x) `equalFilePath` x
--   </pre>
replaceDirectory :: FilePath -> String -> FilePath

-- | An alias for <a>&lt;/&gt;</a>.
combine :: FilePath -> FilePath -> FilePath

-- | 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 <tt>readFile (dir <a>&lt;/&gt;</a> file)</tt>
--   will access the same file as <tt>setCurrentDirectory dir; readFile
--   file</tt>.
--   
--   <pre>
--   Posix:   "/directory" &lt;/&gt; "file.ext" == "/directory/file.ext"
--   Windows: "/directory" &lt;/&gt; "file.ext" == "/directory\\file.ext"
--            "directory" &lt;/&gt; "/file.ext" == "/file.ext"
--   Valid x =&gt; (takeDirectory x &lt;/&gt; takeFileName x) `equalFilePath` x
--   </pre>
--   
--   Combined:
--   
--   <pre>
--   Posix:   "/" &lt;/&gt; "test" == "/test"
--   Posix:   "home" &lt;/&gt; "bob" == "home/bob"
--   Posix:   "x:" &lt;/&gt; "foo" == "x:/foo"
--   Windows: "C:\\foo" &lt;/&gt; "bar" == "C:\\foo\\bar"
--   Windows: "home" &lt;/&gt; "bob" == "home\\bob"
--   </pre>
--   
--   Not combined:
--   
--   <pre>
--   Posix:   "home" &lt;/&gt; "/bob" == "/bob"
--   Windows: "home" &lt;/&gt; "C:\\bob" == "C:\\bob"
--   </pre>
--   
--   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
--   <a>&lt;/&gt;</a> is to never combine these forms.
--   
--   <pre>
--   Windows: "home" &lt;/&gt; "/bob" == "/bob"
--   Windows: "home" &lt;/&gt; "\\bob" == "\\bob"
--   Windows: "C:\\home" &lt;/&gt; "\\bob" == "\\bob"
--   </pre>
--   
--   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 <a>&lt;/&gt;</a> is to
--   never combine these forms.
--   
--   <pre>
--   Windows: "D:\\foo" &lt;/&gt; "C:bar" == "C:bar"
--   Windows: "C:\\foo" &lt;/&gt; "C:bar" == "C:bar"
--   </pre>
(</>) :: FilePath -> FilePath -> FilePath
infixr 5 </>

-- | Split a path by the directory separator.
--   
--   <pre>
--   splitPath "/directory/file.ext" == ["/","directory/","file.ext"]
--   concat (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"]
--   </pre>
splitPath :: FilePath -> [FilePath]

-- | Join path elements back together.
--   
--   <pre>
--   joinPath z == foldr (&lt;/&gt;) "" z
--   joinPath ["/","directory/","file.ext"] == "/directory/file.ext"
--   Valid x =&gt; joinPath (splitPath x) == x
--   joinPath [] == ""
--   Posix: joinPath ["test","file","path"] == "test/file/path"
--   </pre>
joinPath :: [FilePath] -> FilePath

-- | Just as <a>splitPath</a>, but don't add the trailing slashes to each
--   element.
--   
--   <pre>
--            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 =&gt; joinPath (splitDirectories x) `equalFilePath` x
--            splitDirectories "" == []
--   Windows: splitDirectories "C:\\test\\\\\\file" == ["C:\\", "test", "file"]
--            splitDirectories "/test///file" == ["/","test","file"]
--   </pre>
splitDirectories :: FilePath -> [FilePath]

-- | Split a path into a drive and a path. On Posix, / is a Drive.
--   
--   <pre>
--   uncurry (&lt;&gt;) (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")
--   </pre>
splitDrive :: FilePath -> (FilePath, FilePath)

-- | Join a drive and the rest of the path.
--   
--   <pre>
--   Valid x =&gt; 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"
--   </pre>
joinDrive :: FilePath -> FilePath -> FilePath

-- | Get the drive from a filepath.
--   
--   <pre>
--   takeDrive x == fst (splitDrive x)
--   </pre>
takeDrive :: FilePath -> FilePath

-- | Does a path have a drive.
--   
--   <pre>
--   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
--   </pre>
hasDrive :: FilePath -> Bool

-- | Delete the drive, if it exists.
--   
--   <pre>
--   dropDrive x == snd (splitDrive x)
--   </pre>
dropDrive :: FilePath -> FilePath

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

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

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

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

-- | Normalise a file
--   
--   <ul>
--   <li>// outside of the drive can be made blank</li>
--   <li>/ -&gt; <a>pathSeparator</a></li>
--   <li>./ -&gt; ""</li>
--   </ul>
--   
--   Does not remove <tt>".."</tt>, because of symlinks.
--   
--   <pre>
--   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 "/a/../c" == "/a/../c"
--   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"
--   </pre>
normalise :: FilePath -> FilePath

-- | Equality of two <tt>FILEPATH</tt>s. If you call
--   <tt>System.Directory.canonicalizePath</tt> first this has a much
--   better chance of working. Note that this doesn't follow symlinks or
--   DOSNAM~1s.
--   
--   Similar to <a>normalise</a>, this does not expand <tt>".."</tt>,
--   because of symlinks.
--   
--   <pre>
--            x == y ==&gt; equalFilePath x y
--            normalise x == normalise y ==&gt; equalFilePath x y
--            equalFilePath "foo" "foo/"
--            not (equalFilePath "/a/../c" "/c")
--            not (equalFilePath "foo" "/foo")
--   Posix:   not (equalFilePath "foo" "FOO")
--   Windows: equalFilePath "foo" "FOO"
--   Windows: not (equalFilePath "C:" "C:/")
--   </pre>
equalFilePath :: FilePath -> FilePath -> Bool

-- | Contract a filename, based on a relative path. Note that the resulting
--   path will never introduce <tt>..</tt> paths, as the presence of
--   symlinks means <tt>../b</tt> may not reach <tt>a/b</tt> if it starts
--   from <tt>a/c</tt>. For a worked example see <a>this blog post</a>.
--   
--   The corresponding <tt>makeAbsolute</tt> function can be found in
--   <tt>System.Directory</tt>.
--   
--   <pre>
--            makeRelative "/directory" "/directory/file.ext" == "file.ext"
--            Valid x =&gt; makeRelative (takeDirectory x) x `equalFilePath` takeFileName x
--            makeRelative x x == "."
--            Valid x y =&gt; equalFilePath x y || (isRelative x &amp;&amp; makeRelative y x == x) || equalFilePath (y &lt;/&gt; 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"
--   </pre>
makeRelative :: FilePath -> FilePath -> FilePath

-- | Is a path relative, or is it fixed to the root?
--   
--   <pre>
--   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
--   </pre>
--   
--   According to [1]:
--   
--   <ul>
--   <li>"A UNC name of any format [is never relative]."</li>
--   <li>"You cannot use the "\?" prefix with a relative path."</li>
--   </ul>
isRelative :: FilePath -> Bool

-- | <pre>
--   not . <a>isRelative</a>
--   </pre>
--   
--   <pre>
--   isAbsolute x == not (isRelative x)
--   </pre>
isAbsolute :: FilePath -> Bool

-- | Is a FilePath 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.
--   
--   <pre>
--            isValid "" == False
--            isValid "\0" == False
--   Posix:   isValid "/random_ path:*" == True
--   Posix:   isValid x == not (null x)
--   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
--   </pre>
isValid :: FilePath -> Bool

-- | Take a FilePath and make it valid; does not change already valid
--   FILEPATHs.
--   
--   <pre>
--   isValid (makeValid x)
--   isValid x ==&gt; 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"
--   </pre>
makeValid :: FilePath -> FilePath


-- | A library for <a>FilePath</a> manipulations, using Posix or Windows
--   filepaths depending on the platform.
--   
--   Both <a>System.FilePath.Posix</a> and <a>System.FilePath.Windows</a>
--   provide the same interface.
--   
--   Given the example <a>FilePath</a>: <tt>/directory/file.ext</tt>
--   
--   We can use the following functions to extract pieces.
--   
--   <ul>
--   <li><a>takeFileName</a> gives <tt>"file.ext"</tt></li>
--   <li><a>takeDirectory</a> gives <tt>"/directory"</tt></li>
--   <li><a>takeExtension</a> gives <tt>".ext"</tt></li>
--   <li><a>dropExtension</a> gives <tt>"/directory/file"</tt></li>
--   <li><a>takeBaseName</a> gives <tt>"file"</tt></li>
--   </ul>
--   
--   And we could have built an equivalent path with the following
--   expressions:
--   
--   <ul>
--   <li><tt>"/directory" <a>&lt;/&gt;</a> "file.ext"</tt>.</li>
--   <li><tt>"/directory/file" <a>&lt;.&gt;</a> "ext"</tt>.</li>
--   <li><tt>"/directory/file.txt" <a>-&lt;.&gt;</a> "ext"</tt>.</li>
--   </ul>
--   
--   Each function in this module is documented with several examples,
--   which are also used as tests.
--   
--   Here are a few examples of using the <tt>filepath</tt> functions
--   together:
--   
--   <i>Example 1:</i> Find the possible locations of a Haskell module
--   <tt>Test</tt> imported from module <tt>Main</tt>:
--   
--   <pre>
--   [<a>replaceFileName</a> path_to_main "Test" <a>&lt;.&gt;</a> ext | ext &lt;- ["hs","lhs"] ]
--   </pre>
--   
--   <i>Example 2:</i> Download a file from <tt>url</tt> and save it to
--   disk:
--   
--   <pre>
--   do let file = <a>makeValid</a> url
--     System.Directory.createDirectoryIfMissing True (<a>takeDirectory</a> file)
--   </pre>
--   
--   <i>Example 3:</i> Compile a Haskell file, putting the <tt>.hi</tt>
--   file under <tt>interface</tt>:
--   
--   <pre>
--   <a>takeDirectory</a> file <a>&lt;/&gt;</a> "interface" <a>&lt;/&gt;</a> (<a>takeFileName</a> file <a>-&lt;.&gt;</a> "hi")
--   </pre>
--   
--   References: [1] <a>Naming Files, Paths and Namespaces</a> (Microsoft
--   MSDN)
module System.FilePath

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

-- | The character that separates directories. In the case where more than
--   one character is possible, <a>pathSeparator</a> is the 'ideal' one.
--   
--   <pre>
--   Windows: pathSeparator == '\\'
--   Posix:   pathSeparator ==  '/'
--   isPathSeparator pathSeparator
--   </pre>
pathSeparator :: Char

-- | The list of all possible separators.
--   
--   <pre>
--   Windows: pathSeparators == ['\\', '/']
--   Posix:   pathSeparators == ['/']
--   pathSeparator `elem` pathSeparators
--   </pre>
pathSeparators :: [Char]

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

-- | The character that is used to separate the entries in the $PATH
--   environment variable.
--   
--   <pre>
--   Windows: searchPathSeparator == ';'
--   Posix:   searchPathSeparator == ':'
--   </pre>
searchPathSeparator :: Char

-- | Is the character a file separator?
--   
--   <pre>
--   isSearchPathSeparator a == (a == searchPathSeparator)
--   </pre>
isSearchPathSeparator :: Char -> Bool

-- | File extension character
--   
--   <pre>
--   extSeparator == '.'
--   </pre>
extSeparator :: Char

-- | Is the character an extension character?
--   
--   <pre>
--   isExtSeparator a == (a == extSeparator)
--   </pre>
isExtSeparator :: Char -> Bool

-- | Take a string, split it on the <a>searchPathSeparator</a> character.
--   Blank items are ignored on Windows, and converted to <tt>.</tt> on
--   Posix. On Windows path elements are stripped of quotes.
--   
--   Follows the recommendations in
--   <a>http://www.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap08.html</a>
--   
--   <pre>
--   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"]
--   </pre>
splitSearchPath :: String -> [FilePath]

-- | Get a list of <tt>FILEPATH</tt>s in the $PATH variable.
getSearchPath :: IO [FilePath]

-- | Split on the extension. <a>addExtension</a> is the inverse.
--   
--   <pre>
--   splitExtension "/directory/path.ext" == ("/directory/path",".ext")
--   uncurry (&lt;&gt;) (splitExtension x) == x
--   Valid x =&gt; 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/","")
--   </pre>
splitExtension :: FilePath -> (String, String)

-- | Get the extension of a file, returns <tt>""</tt> for no extension,
--   <tt>.ext</tt> otherwise.
--   
--   <pre>
--   takeExtension "/directory/path.ext" == ".ext"
--   takeExtension x == snd (splitExtension x)
--   Valid x =&gt; takeExtension (addExtension x "ext") == ".ext"
--   Valid x =&gt; takeExtension (replaceExtension x "ext") == ".ext"
--   </pre>
takeExtension :: FilePath -> String

-- | Set the extension of a file, overwriting one if already present,
--   equivalent to <a>-&lt;.&gt;</a>.
--   
--   <pre>
--   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
--   </pre>
replaceExtension :: FilePath -> String -> FilePath

-- | Remove the current extension and add another, equivalent to
--   <a>replaceExtension</a>.
--   
--   <pre>
--   "/directory/path.txt" -&lt;.&gt; "ext" == "/directory/path.ext"
--   "/directory/path.txt" -&lt;.&gt; ".ext" == "/directory/path.ext"
--   "foo.o" -&lt;.&gt; "c" == "foo.c"
--   </pre>
(-<.>) :: FilePath -> String -> FilePath
infixr 7 -<.>

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

-- | Add an extension, even if there is already one there, equivalent to
--   <a>&lt;.&gt;</a>.
--   
--   <pre>
--   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 =&gt; takeFileName (addExtension (addTrailingPathSeparator x) "ext") == ".ext"
--   Windows: addExtension "\\\\share" ".txt" == "\\\\share\\.txt"
--   </pre>
addExtension :: FilePath -> String -> FilePath

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

-- | Add an extension, even if there is already one there, equivalent to
--   <a>addExtension</a>.
--   
--   <pre>
--   "/directory/path" &lt;.&gt; "ext" == "/directory/path.ext"
--   "/directory/path" &lt;.&gt; ".ext" == "/directory/path.ext"
--   </pre>
(<.>) :: FilePath -> String -> FilePath
infixr 7 <.>

-- | Split on all extensions.
--   
--   <pre>
--   splitExtensions "/directory/path.ext" == ("/directory/path",".ext")
--   splitExtensions "file.tar.gz" == ("file",".tar.gz")
--   uncurry (&lt;&gt;) (splitExtensions x) == x
--   Valid x =&gt; uncurry addExtension (splitExtensions x) == x
--   splitExtensions "file.tar.gz" == ("file",".tar.gz")
--   </pre>
splitExtensions :: FilePath -> (FilePath, String)

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

-- | Get all extensions.
--   
--   <pre>
--   takeExtensions "/directory/path.ext" == ".ext"
--   takeExtensions "file.tar.gz" == ".tar.gz"
--   </pre>
takeExtensions :: FilePath -> String

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

-- | Does the given filename have the specified extension?
--   
--   <pre>
--   "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
--   </pre>
isExtensionOf :: String -> FilePath -> Bool

-- | Drop the given extension from a FilePath, and the <tt>"."</tt>
--   preceding it. Returns <a>Nothing</a> if the FilePath does not have the
--   given extension, or <a>Just</a> and the part before the extension if
--   it does.
--   
--   This function can be more predictable than <a>dropExtensions</a>,
--   especially if the filename might itself contain <tt>.</tt> characters.
--   
--   <pre>
--   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
--   </pre>
stripExtension :: String -> FilePath -> Maybe FilePath

-- | Split a filename into directory and file. <a>&lt;/&gt;</a> is the
--   inverse. The first component will often end with a trailing slash.
--   
--   <pre>
--   splitFileName "/directory/file.ext" == ("/directory/","file.ext")
--   Valid x =&gt; uncurry (&lt;/&gt;) (splitFileName x) == x || fst (splitFileName x) == "./"
--   Valid x =&gt; isValid (fst (splitFileName x))
--   splitFileName "file/bob.txt" == ("file/", "bob.txt")
--   splitFileName "file/" == ("file/", "")
--   splitFileName "bob" == ("./", "bob")
--   Posix:   splitFileName "/" == ("/","")
--   Windows: splitFileName "c:" == ("c:","")
--   Windows: splitFileName "\\\\?\\A:\\fred" == ("\\\\?\\A:\\","fred")
--   Windows: splitFileName "\\\\?\\A:" == ("\\\\?\\A:","")
--   </pre>
splitFileName :: FilePath -> (String, String)

-- | Get the file name.
--   
--   <pre>
--   takeFileName "/directory/file.ext" == "file.ext"
--   takeFileName "test/" == ""
--   isSuffixOf (takeFileName x) x
--   takeFileName x == snd (splitFileName x)
--   Valid x =&gt; takeFileName (replaceFileName x "fred") == "fred"
--   Valid x =&gt; takeFileName (x &lt;/&gt; "fred") == "fred"
--   Valid x =&gt; isRelative (takeFileName x)
--   </pre>
takeFileName :: FilePath -> FilePath

-- | Set the filename.
--   
--   <pre>
--   replaceFileName "/directory/other.txt" "file.ext" == "/directory/file.ext"
--   Valid x =&gt; replaceFileName x (takeFileName x) == x
--   </pre>
replaceFileName :: FilePath -> String -> FilePath

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

-- | Get the base name, without an extension or path.
--   
--   <pre>
--   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"
--   </pre>
takeBaseName :: FilePath -> String

-- | Set the base name.
--   
--   <pre>
--   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 =&gt; replaceBaseName x (takeBaseName x) == x
--   </pre>
replaceBaseName :: FilePath -> String -> FilePath

-- | Get the directory name, move up one level.
--   
--   <pre>
--             takeDirectory "/directory/other.ext" == "/directory"
--             isPrefixOf (takeDirectory x) 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:\\"
--   </pre>
takeDirectory :: FilePath -> FilePath

-- | Set the directory, keeping the filename the same.
--   
--   <pre>
--   replaceDirectory "root/file.ext" "/directory/" == "/directory/file.ext"
--   Valid x =&gt; replaceDirectory x (takeDirectory x) `equalFilePath` x
--   </pre>
replaceDirectory :: FilePath -> String -> FilePath

-- | An alias for <a>&lt;/&gt;</a>.
combine :: FilePath -> FilePath -> FilePath

-- | 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 <tt>readFile (dir <a>&lt;/&gt;</a> file)</tt>
--   will access the same file as <tt>setCurrentDirectory dir; readFile
--   file</tt>.
--   
--   <pre>
--   Posix:   "/directory" &lt;/&gt; "file.ext" == "/directory/file.ext"
--   Windows: "/directory" &lt;/&gt; "file.ext" == "/directory\\file.ext"
--            "directory" &lt;/&gt; "/file.ext" == "/file.ext"
--   Valid x =&gt; (takeDirectory x &lt;/&gt; takeFileName x) `equalFilePath` x
--   </pre>
--   
--   Combined:
--   
--   <pre>
--   Posix:   "/" &lt;/&gt; "test" == "/test"
--   Posix:   "home" &lt;/&gt; "bob" == "home/bob"
--   Posix:   "x:" &lt;/&gt; "foo" == "x:/foo"
--   Windows: "C:\\foo" &lt;/&gt; "bar" == "C:\\foo\\bar"
--   Windows: "home" &lt;/&gt; "bob" == "home\\bob"
--   </pre>
--   
--   Not combined:
--   
--   <pre>
--   Posix:   "home" &lt;/&gt; "/bob" == "/bob"
--   Windows: "home" &lt;/&gt; "C:\\bob" == "C:\\bob"
--   </pre>
--   
--   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
--   <a>&lt;/&gt;</a> is to never combine these forms.
--   
--   <pre>
--   Windows: "home" &lt;/&gt; "/bob" == "/bob"
--   Windows: "home" &lt;/&gt; "\\bob" == "\\bob"
--   Windows: "C:\\home" &lt;/&gt; "\\bob" == "\\bob"
--   </pre>
--   
--   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 <a>&lt;/&gt;</a> is to
--   never combine these forms.
--   
--   <pre>
--   Windows: "D:\\foo" &lt;/&gt; "C:bar" == "C:bar"
--   Windows: "C:\\foo" &lt;/&gt; "C:bar" == "C:bar"
--   </pre>
(</>) :: FilePath -> FilePath -> FilePath
infixr 5 </>

-- | Split a path by the directory separator.
--   
--   <pre>
--   splitPath "/directory/file.ext" == ["/","directory/","file.ext"]
--   concat (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"]
--   </pre>
splitPath :: FilePath -> [FilePath]

-- | Join path elements back together.
--   
--   <pre>
--   joinPath z == foldr (&lt;/&gt;) "" z
--   joinPath ["/","directory/","file.ext"] == "/directory/file.ext"
--   Valid x =&gt; joinPath (splitPath x) == x
--   joinPath [] == ""
--   Posix: joinPath ["test","file","path"] == "test/file/path"
--   </pre>
joinPath :: [FilePath] -> FilePath

-- | Just as <a>splitPath</a>, but don't add the trailing slashes to each
--   element.
--   
--   <pre>
--            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 =&gt; joinPath (splitDirectories x) `equalFilePath` x
--            splitDirectories "" == []
--   Windows: splitDirectories "C:\\test\\\\\\file" == ["C:\\", "test", "file"]
--            splitDirectories "/test///file" == ["/","test","file"]
--   </pre>
splitDirectories :: FilePath -> [FilePath]

-- | Split a path into a drive and a path. On Posix, / is a Drive.
--   
--   <pre>
--   uncurry (&lt;&gt;) (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")
--   </pre>
splitDrive :: FilePath -> (FilePath, FilePath)

-- | Join a drive and the rest of the path.
--   
--   <pre>
--   Valid x =&gt; 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"
--   </pre>
joinDrive :: FilePath -> FilePath -> FilePath

-- | Get the drive from a filepath.
--   
--   <pre>
--   takeDrive x == fst (splitDrive x)
--   </pre>
takeDrive :: FilePath -> FilePath

-- | Does a path have a drive.
--   
--   <pre>
--   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
--   </pre>
hasDrive :: FilePath -> Bool

-- | Delete the drive, if it exists.
--   
--   <pre>
--   dropDrive x == snd (splitDrive x)
--   </pre>
dropDrive :: FilePath -> FilePath

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

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

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

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

-- | Normalise a file
--   
--   <ul>
--   <li>// outside of the drive can be made blank</li>
--   <li>/ -&gt; <a>pathSeparator</a></li>
--   <li>./ -&gt; ""</li>
--   </ul>
--   
--   Does not remove <tt>".."</tt>, because of symlinks.
--   
--   <pre>
--   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 "/a/../c" == "/a/../c"
--   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"
--   </pre>
normalise :: FilePath -> FilePath

-- | Equality of two <tt>FILEPATH</tt>s. If you call
--   <tt>System.Directory.canonicalizePath</tt> first this has a much
--   better chance of working. Note that this doesn't follow symlinks or
--   DOSNAM~1s.
--   
--   Similar to <a>normalise</a>, this does not expand <tt>".."</tt>,
--   because of symlinks.
--   
--   <pre>
--            x == y ==&gt; equalFilePath x y
--            normalise x == normalise y ==&gt; equalFilePath x y
--            equalFilePath "foo" "foo/"
--            not (equalFilePath "/a/../c" "/c")
--            not (equalFilePath "foo" "/foo")
--   Posix:   not (equalFilePath "foo" "FOO")
--   Windows: equalFilePath "foo" "FOO"
--   Windows: not (equalFilePath "C:" "C:/")
--   </pre>
equalFilePath :: FilePath -> FilePath -> Bool

-- | Contract a filename, based on a relative path. Note that the resulting
--   path will never introduce <tt>..</tt> paths, as the presence of
--   symlinks means <tt>../b</tt> may not reach <tt>a/b</tt> if it starts
--   from <tt>a/c</tt>. For a worked example see <a>this blog post</a>.
--   
--   The corresponding <tt>makeAbsolute</tt> function can be found in
--   <tt>System.Directory</tt>.
--   
--   <pre>
--            makeRelative "/directory" "/directory/file.ext" == "file.ext"
--            Valid x =&gt; makeRelative (takeDirectory x) x `equalFilePath` takeFileName x
--            makeRelative x x == "."
--            Valid x y =&gt; equalFilePath x y || (isRelative x &amp;&amp; makeRelative y x == x) || equalFilePath (y &lt;/&gt; 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"
--   </pre>
makeRelative :: FilePath -> FilePath -> FilePath

-- | Is a path relative, or is it fixed to the root?
--   
--   <pre>
--   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
--   </pre>
--   
--   According to [1]:
--   
--   <ul>
--   <li>"A UNC name of any format [is never relative]."</li>
--   <li>"You cannot use the "\?" prefix with a relative path."</li>
--   </ul>
isRelative :: FilePath -> Bool

-- | <pre>
--   not . <a>isRelative</a>
--   </pre>
--   
--   <pre>
--   isAbsolute x == not (isRelative x)
--   </pre>
isAbsolute :: FilePath -> Bool

-- | Is a FilePath 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.
--   
--   <pre>
--            isValid "" == False
--            isValid "\0" == False
--   Posix:   isValid "/random_ path:*" == True
--   Posix:   isValid x == not (null x)
--   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
--   </pre>
isValid :: FilePath -> Bool

-- | Take a FilePath and make it valid; does not change already valid
--   FILEPATHs.
--   
--   <pre>
--   isValid (makeValid x)
--   isValid x ==&gt; 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"
--   </pre>
makeValid :: FilePath -> FilePath


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

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

-- | The character that separates directories. In the case where more than
--   one character is possible, <a>pathSeparator</a> is the 'ideal' one.
--   
--   <pre>
--   Windows: pathSeparator == '\\'
--   Posix:   pathSeparator ==  '/'
--   isPathSeparator pathSeparator
--   </pre>
pathSeparator :: Char

-- | The list of all possible separators.
--   
--   <pre>
--   Windows: pathSeparators == ['\\', '/']
--   Posix:   pathSeparators == ['/']
--   pathSeparator `elem` pathSeparators
--   </pre>
pathSeparators :: [Char]

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

-- | The character that is used to separate the entries in the $PATH
--   environment variable.
--   
--   <pre>
--   Windows: searchPathSeparator == ';'
--   Posix:   searchPathSeparator == ':'
--   </pre>
searchPathSeparator :: Char

-- | Is the character a file separator?
--   
--   <pre>
--   isSearchPathSeparator a == (a == searchPathSeparator)
--   </pre>
isSearchPathSeparator :: Char -> Bool

-- | File extension character
--   
--   <pre>
--   extSeparator == '.'
--   </pre>
extSeparator :: Char

-- | Is the character an extension character?
--   
--   <pre>
--   isExtSeparator a == (a == extSeparator)
--   </pre>
isExtSeparator :: Char -> Bool

-- | Take a string, split it on the <a>searchPathSeparator</a> character.
--   Blank items are ignored on Windows, and converted to <tt>.</tt> on
--   Posix. On Windows path elements are stripped of quotes.
--   
--   Follows the recommendations in
--   <a>http://www.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap08.html</a>
--   
--   <pre>
--   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"]
--   </pre>
splitSearchPath :: String -> [FilePath]

-- | Get a list of <tt>FILEPATH</tt>s in the $PATH variable.
getSearchPath :: IO [FilePath]

-- | Split on the extension. <a>addExtension</a> is the inverse.
--   
--   <pre>
--   splitExtension "/directory/path.ext" == ("/directory/path",".ext")
--   uncurry (&lt;&gt;) (splitExtension x) == x
--   Valid x =&gt; 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/","")
--   </pre>
splitExtension :: FilePath -> (String, String)

-- | Get the extension of a file, returns <tt>""</tt> for no extension,
--   <tt>.ext</tt> otherwise.
--   
--   <pre>
--   takeExtension "/directory/path.ext" == ".ext"
--   takeExtension x == snd (splitExtension x)
--   Valid x =&gt; takeExtension (addExtension x "ext") == ".ext"
--   Valid x =&gt; takeExtension (replaceExtension x "ext") == ".ext"
--   </pre>
takeExtension :: FilePath -> String

-- | Set the extension of a file, overwriting one if already present,
--   equivalent to <a>-&lt;.&gt;</a>.
--   
--   <pre>
--   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
--   </pre>
replaceExtension :: FilePath -> String -> FilePath

-- | Remove the current extension and add another, equivalent to
--   <a>replaceExtension</a>.
--   
--   <pre>
--   "/directory/path.txt" -&lt;.&gt; "ext" == "/directory/path.ext"
--   "/directory/path.txt" -&lt;.&gt; ".ext" == "/directory/path.ext"
--   "foo.o" -&lt;.&gt; "c" == "foo.c"
--   </pre>
(-<.>) :: FilePath -> String -> FilePath
infixr 7 -<.>

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

-- | Add an extension, even if there is already one there, equivalent to
--   <a>&lt;.&gt;</a>.
--   
--   <pre>
--   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 =&gt; takeFileName (addExtension (addTrailingPathSeparator x) "ext") == ".ext"
--   Windows: addExtension "\\\\share" ".txt" == "\\\\share\\.txt"
--   </pre>
addExtension :: FilePath -> String -> FilePath

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

-- | Add an extension, even if there is already one there, equivalent to
--   <a>addExtension</a>.
--   
--   <pre>
--   "/directory/path" &lt;.&gt; "ext" == "/directory/path.ext"
--   "/directory/path" &lt;.&gt; ".ext" == "/directory/path.ext"
--   </pre>
(<.>) :: FilePath -> String -> FilePath
infixr 7 <.>

-- | Split on all extensions.
--   
--   <pre>
--   splitExtensions "/directory/path.ext" == ("/directory/path",".ext")
--   splitExtensions "file.tar.gz" == ("file",".tar.gz")
--   uncurry (&lt;&gt;) (splitExtensions x) == x
--   Valid x =&gt; uncurry addExtension (splitExtensions x) == x
--   splitExtensions "file.tar.gz" == ("file",".tar.gz")
--   </pre>
splitExtensions :: FilePath -> (FilePath, String)

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

-- | Get all extensions.
--   
--   <pre>
--   takeExtensions "/directory/path.ext" == ".ext"
--   takeExtensions "file.tar.gz" == ".tar.gz"
--   </pre>
takeExtensions :: FilePath -> String

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

-- | Does the given filename have the specified extension?
--   
--   <pre>
--   "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
--   </pre>
isExtensionOf :: String -> FilePath -> Bool

-- | Drop the given extension from a FilePath, and the <tt>"."</tt>
--   preceding it. Returns <a>Nothing</a> if the FilePath does not have the
--   given extension, or <a>Just</a> and the part before the extension if
--   it does.
--   
--   This function can be more predictable than <a>dropExtensions</a>,
--   especially if the filename might itself contain <tt>.</tt> characters.
--   
--   <pre>
--   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
--   </pre>
stripExtension :: String -> FilePath -> Maybe FilePath

-- | Split a filename into directory and file. <a>&lt;/&gt;</a> is the
--   inverse. The first component will often end with a trailing slash.
--   
--   <pre>
--   splitFileName "/directory/file.ext" == ("/directory/","file.ext")
--   Valid x =&gt; uncurry (&lt;/&gt;) (splitFileName x) == x || fst (splitFileName x) == "./"
--   Valid x =&gt; isValid (fst (splitFileName x))
--   splitFileName "file/bob.txt" == ("file/", "bob.txt")
--   splitFileName "file/" == ("file/", "")
--   splitFileName "bob" == ("./", "bob")
--   Posix:   splitFileName "/" == ("/","")
--   Windows: splitFileName "c:" == ("c:","")
--   Windows: splitFileName "\\\\?\\A:\\fred" == ("\\\\?\\A:\\","fred")
--   Windows: splitFileName "\\\\?\\A:" == ("\\\\?\\A:","")
--   </pre>
splitFileName :: FilePath -> (String, String)

-- | Get the file name.
--   
--   <pre>
--   takeFileName "/directory/file.ext" == "file.ext"
--   takeFileName "test/" == ""
--   isSuffixOf (takeFileName x) x
--   takeFileName x == snd (splitFileName x)
--   Valid x =&gt; takeFileName (replaceFileName x "fred") == "fred"
--   Valid x =&gt; takeFileName (x &lt;/&gt; "fred") == "fred"
--   Valid x =&gt; isRelative (takeFileName x)
--   </pre>
takeFileName :: FilePath -> FilePath

-- | Set the filename.
--   
--   <pre>
--   replaceFileName "/directory/other.txt" "file.ext" == "/directory/file.ext"
--   Valid x =&gt; replaceFileName x (takeFileName x) == x
--   </pre>
replaceFileName :: FilePath -> String -> FilePath

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

-- | Get the base name, without an extension or path.
--   
--   <pre>
--   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"
--   </pre>
takeBaseName :: FilePath -> String

-- | Set the base name.
--   
--   <pre>
--   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 =&gt; replaceBaseName x (takeBaseName x) == x
--   </pre>
replaceBaseName :: FilePath -> String -> FilePath

-- | Get the directory name, move up one level.
--   
--   <pre>
--             takeDirectory "/directory/other.ext" == "/directory"
--             isPrefixOf (takeDirectory x) 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:\\"
--   </pre>
takeDirectory :: FilePath -> FilePath

-- | Set the directory, keeping the filename the same.
--   
--   <pre>
--   replaceDirectory "root/file.ext" "/directory/" == "/directory/file.ext"
--   Valid x =&gt; replaceDirectory x (takeDirectory x) `equalFilePath` x
--   </pre>
replaceDirectory :: FilePath -> String -> FilePath

-- | An alias for <a>&lt;/&gt;</a>.
combine :: FilePath -> FilePath -> FilePath

-- | 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 <tt>readFile (dir <a>&lt;/&gt;</a> file)</tt>
--   will access the same file as <tt>setCurrentDirectory dir; readFile
--   file</tt>.
--   
--   <pre>
--   Posix:   "/directory" &lt;/&gt; "file.ext" == "/directory/file.ext"
--   Windows: "/directory" &lt;/&gt; "file.ext" == "/directory\\file.ext"
--            "directory" &lt;/&gt; "/file.ext" == "/file.ext"
--   Valid x =&gt; (takeDirectory x &lt;/&gt; takeFileName x) `equalFilePath` x
--   </pre>
--   
--   Combined:
--   
--   <pre>
--   Posix:   "/" &lt;/&gt; "test" == "/test"
--   Posix:   "home" &lt;/&gt; "bob" == "home/bob"
--   Posix:   "x:" &lt;/&gt; "foo" == "x:/foo"
--   Windows: "C:\\foo" &lt;/&gt; "bar" == "C:\\foo\\bar"
--   Windows: "home" &lt;/&gt; "bob" == "home\\bob"
--   </pre>
--   
--   Not combined:
--   
--   <pre>
--   Posix:   "home" &lt;/&gt; "/bob" == "/bob"
--   Windows: "home" &lt;/&gt; "C:\\bob" == "C:\\bob"
--   </pre>
--   
--   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
--   <a>&lt;/&gt;</a> is to never combine these forms.
--   
--   <pre>
--   Windows: "home" &lt;/&gt; "/bob" == "/bob"
--   Windows: "home" &lt;/&gt; "\\bob" == "\\bob"
--   Windows: "C:\\home" &lt;/&gt; "\\bob" == "\\bob"
--   </pre>
--   
--   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 <a>&lt;/&gt;</a> is to
--   never combine these forms.
--   
--   <pre>
--   Windows: "D:\\foo" &lt;/&gt; "C:bar" == "C:bar"
--   Windows: "C:\\foo" &lt;/&gt; "C:bar" == "C:bar"
--   </pre>
(</>) :: FilePath -> FilePath -> FilePath
infixr 5 </>

-- | Split a path by the directory separator.
--   
--   <pre>
--   splitPath "/directory/file.ext" == ["/","directory/","file.ext"]
--   concat (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"]
--   </pre>
splitPath :: FilePath -> [FilePath]

-- | Join path elements back together.
--   
--   <pre>
--   joinPath z == foldr (&lt;/&gt;) "" z
--   joinPath ["/","directory/","file.ext"] == "/directory/file.ext"
--   Valid x =&gt; joinPath (splitPath x) == x
--   joinPath [] == ""
--   Posix: joinPath ["test","file","path"] == "test/file/path"
--   </pre>
joinPath :: [FilePath] -> FilePath

-- | Just as <a>splitPath</a>, but don't add the trailing slashes to each
--   element.
--   
--   <pre>
--            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 =&gt; joinPath (splitDirectories x) `equalFilePath` x
--            splitDirectories "" == []
--   Windows: splitDirectories "C:\\test\\\\\\file" == ["C:\\", "test", "file"]
--            splitDirectories "/test///file" == ["/","test","file"]
--   </pre>
splitDirectories :: FilePath -> [FilePath]

-- | Split a path into a drive and a path. On Posix, / is a Drive.
--   
--   <pre>
--   uncurry (&lt;&gt;) (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")
--   </pre>
splitDrive :: FilePath -> (FilePath, FilePath)

-- | Join a drive and the rest of the path.
--   
--   <pre>
--   Valid x =&gt; 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"
--   </pre>
joinDrive :: FilePath -> FilePath -> FilePath

-- | Get the drive from a filepath.
--   
--   <pre>
--   takeDrive x == fst (splitDrive x)
--   </pre>
takeDrive :: FilePath -> FilePath

-- | Does a path have a drive.
--   
--   <pre>
--   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
--   </pre>
hasDrive :: FilePath -> Bool

-- | Delete the drive, if it exists.
--   
--   <pre>
--   dropDrive x == snd (splitDrive x)
--   </pre>
dropDrive :: FilePath -> FilePath

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

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

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

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

-- | Normalise a file
--   
--   <ul>
--   <li>// outside of the drive can be made blank</li>
--   <li>/ -&gt; <a>pathSeparator</a></li>
--   <li>./ -&gt; ""</li>
--   </ul>
--   
--   Does not remove <tt>".."</tt>, because of symlinks.
--   
--   <pre>
--   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 "/a/../c" == "/a/../c"
--   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"
--   </pre>
normalise :: FilePath -> FilePath

-- | Equality of two <tt>FILEPATH</tt>s. If you call
--   <tt>System.Directory.canonicalizePath</tt> first this has a much
--   better chance of working. Note that this doesn't follow symlinks or
--   DOSNAM~1s.
--   
--   Similar to <a>normalise</a>, this does not expand <tt>".."</tt>,
--   because of symlinks.
--   
--   <pre>
--            x == y ==&gt; equalFilePath x y
--            normalise x == normalise y ==&gt; equalFilePath x y
--            equalFilePath "foo" "foo/"
--            not (equalFilePath "/a/../c" "/c")
--            not (equalFilePath "foo" "/foo")
--   Posix:   not (equalFilePath "foo" "FOO")
--   Windows: equalFilePath "foo" "FOO"
--   Windows: not (equalFilePath "C:" "C:/")
--   </pre>
equalFilePath :: FilePath -> FilePath -> Bool

-- | Contract a filename, based on a relative path. Note that the resulting
--   path will never introduce <tt>..</tt> paths, as the presence of
--   symlinks means <tt>../b</tt> may not reach <tt>a/b</tt> if it starts
--   from <tt>a/c</tt>. For a worked example see <a>this blog post</a>.
--   
--   The corresponding <tt>makeAbsolute</tt> function can be found in
--   <tt>System.Directory</tt>.
--   
--   <pre>
--            makeRelative "/directory" "/directory/file.ext" == "file.ext"
--            Valid x =&gt; makeRelative (takeDirectory x) x `equalFilePath` takeFileName x
--            makeRelative x x == "."
--            Valid x y =&gt; equalFilePath x y || (isRelative x &amp;&amp; makeRelative y x == x) || equalFilePath (y &lt;/&gt; 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"
--   </pre>
makeRelative :: FilePath -> FilePath -> FilePath

-- | Is a path relative, or is it fixed to the root?
--   
--   <pre>
--   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
--   </pre>
--   
--   According to [1]:
--   
--   <ul>
--   <li>"A UNC name of any format [is never relative]."</li>
--   <li>"You cannot use the "\?" prefix with a relative path."</li>
--   </ul>
isRelative :: FilePath -> Bool

-- | <pre>
--   not . <a>isRelative</a>
--   </pre>
--   
--   <pre>
--   isAbsolute x == not (isRelative x)
--   </pre>
isAbsolute :: FilePath -> Bool

-- | Is a FilePath 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.
--   
--   <pre>
--            isValid "" == False
--            isValid "\0" == False
--   Posix:   isValid "/random_ path:*" == True
--   Posix:   isValid x == not (null x)
--   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
--   </pre>
isValid :: FilePath -> Bool

-- | Take a FilePath and make it valid; does not change already valid
--   FILEPATHs.
--   
--   <pre>
--   isValid (makeValid x)
--   isValid x ==&gt; 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"
--   </pre>
makeValid :: FilePath -> FilePath


-- | Internal low-level utilities mostly for <a>Word16</a>, such as
--   byte-array operations and other stuff not meant to be exported from
--   Word16 module.

-- | <i>Deprecated: Use System.OsString.Data.ByteString.Short.Internal from
--   os-string &gt;= 2.0.0 package instead. This module will be removed in
--   filepath &gt;= 1.5.</i>
module System.OsPath.Data.ByteString.Short.Internal
_nul :: Word16
isSpace :: Word16 -> Bool

-- | Total conversion to char.
word16ToChar :: Word16 -> Char
create :: Int -> (forall s. MBA s -> ST s ()) -> ShortByteString
asBA :: ShortByteString -> BA
data BA
BA# :: ByteArray# -> BA
data MBA s
MBA# :: MutableByteArray# s -> MBA s
newPinnedByteArray :: Int -> ST s (MBA s)
newByteArray :: Int -> ST s (MBA s)
copyByteArray :: BA -> Int -> MBA s -> Int -> Int -> ST s ()
unsafeFreezeByteArray :: MBA s -> ST s BA
copyAddrToByteArray :: Ptr a -> MBA RealWorld -> Int -> Int -> ST RealWorld ()

-- | <i>O(n).</i> Construct a new <tt>ShortByteString</tt> from a
--   <tt>CWString</tt>. The resulting <tt>ShortByteString</tt> is an
--   immutable copy of the original <tt>CWString</tt>, and is managed on
--   the Haskell heap. The original <tt>CWString</tt> must be null
--   terminated.
packCWString :: Ptr Word16 -> IO ShortByteString

-- | <i>O(n).</i> Construct a new <tt>ShortByteString</tt> from a
--   <tt>CWStringLen</tt>. The resulting <tt>ShortByteString</tt> is an
--   immutable copy of the original <tt>CWStringLen</tt>. The
--   <tt>ShortByteString</tt> is a normal Haskell value and will be managed
--   on the Haskell heap.
packCWStringLen :: (Ptr Word16, Int) -> IO ShortByteString

-- | <i>O(n) construction.</i> Use a <tt>ShortByteString</tt> with a
--   function requiring a null-terminated <tt>CWString</tt>. The
--   <tt>CWString</tt> is a copy and will be freed automatically; it must
--   not be stored or used after the subcomputation finishes.
useAsCWString :: ShortByteString -> (Ptr Word16 -> IO a) -> IO a

-- | <i>O(n) construction.</i> Use a <tt>ShortByteString</tt> with a
--   function requiring a <tt>CWStringLen</tt>. As for
--   <tt>useAsCWString</tt> this function makes a copy of the original
--   <tt>ShortByteString</tt>. It must not be stored or used after the
--   subcomputation finishes.
useAsCWStringLen :: ShortByteString -> ((Ptr Word16, Int) -> IO a) -> IO a

-- | <i>O(n) construction.</i> Use a <tt>ShortByteString</tt> with a
--   function requiring a <tt>CWStringLen</tt>. As for
--   <tt>useAsCWString</tt> this function makes a copy of the original
--   <tt>ShortByteString</tt>. It must not be stored or used after the
--   subcomputation finishes.
newCWString :: ShortByteString -> IO (Ptr Word16)
moduleErrorIO :: String -> String -> IO a
moduleErrorMsg :: String -> String -> String
packWord16 :: [Word16] -> ShortByteString
packLenWord16 :: Int -> [Word16] -> ShortByteString
unpackWord16 :: ShortByteString -> [Word16]
packWord16Rev :: [Word16] -> ShortByteString
packLenWord16Rev :: Int -> [Word16] -> ShortByteString

-- | This isn't strictly Word16 array write. Instead it's two consecutive
--   Word8 array writes to avoid endianness issues due to primops doing
--   automatic alignment based on host platform. We want to always write LE
--   to the byte array.
writeWord16Array :: MBA s -> Int -> Word16 -> ST s ()
indexWord8Array :: BA -> Int -> Word8

-- | This isn't strictly Word16 array read. Instead it's two Word8 array
--   reads to avoid endianness issues due to primops doing automatic
--   alignment based on host platform. We expect the byte array to be LE
--   always.
indexWord16Array :: BA -> Int -> Word16
encodeWord16LE# :: Word16# -> (# Word8#, Word8# #)
decodeWord16LE# :: (# Word8#, Word8# #) -> Word16#
setByteArray :: MBA s -> Int -> Int -> Int -> ST s ()
copyMutableByteArray :: MBA s -> Int -> MBA s -> Int -> Int -> ST s ()

-- | Given the maximum size needed and a function to make the contents of a
--   ShortByteString, createAndTrim makes the <a>ShortByteString</a>. The
--   generating function is required to return the actual final size (&lt;=
--   the maximum size) and the result value. The resulting byte array is
--   realloced to this size.
createAndTrim :: Int -> (forall s. MBA s -> ST s (Int, a)) -> (ShortByteString, a)
createAndTrim' :: Int -> (forall s. MBA s -> ST s Int) -> ShortByteString
createAndTrim'' :: Int -> (forall s. MBA s -> MBA s -> ST s (Int, Int)) -> (ShortByteString, ShortByteString)
findIndexOrLength :: (Word16 -> Bool) -> ShortByteString -> Int

-- | Returns the length of the substring matching, not the index. If no
--   match, returns 0.
findFromEndUntil :: (Word16 -> Bool) -> ShortByteString -> Int
assertEven :: ShortByteString -> ShortByteString
errorEmptySBS :: HasCallStack => String -> a
moduleError :: HasCallStack => String -> String -> a
compareByteArraysOff :: BA -> Int -> BA -> Int -> Int -> Int


-- | A compact representation suitable for storing short byte strings in
--   memory.
--   
--   In typical use cases it can be imported alongside
--   <a>Data.ByteString</a>, e.g.
--   
--   <pre>
--   import qualified Data.ByteString       as B
--   import qualified Data.ByteString.Short as B
--            (ShortByteString, toShort, fromShort)
--   </pre>
--   
--   Other <a>ShortByteString</a> operations clash with
--   <a>Data.ByteString</a> or <a>Prelude</a> functions however, so they
--   should be imported <tt>qualified</tt> with a different alias e.g.
--   
--   <pre>
--   import qualified Data.ByteString.Short as B.Short
--   </pre>

-- | <i>Deprecated: Use System.OsString.Data.ByteString.Short from
--   os-string &gt;= 2.0.0 package instead. This module will be removed in
--   filepath &gt;= 1.5.</i>
module System.OsPath.Data.ByteString.Short

-- | A compact representation of a <a>Word8</a> vector.
--   
--   It has a lower memory overhead than a <a>ByteString</a> and does not
--   contribute to heap fragmentation. It can be converted to or from a
--   <a>ByteString</a> (at the cost of copying the string data). It
--   supports very few other operations.
data () => ShortByteString
SBS :: ByteArray# -> ShortByteString

-- | <i>O(1)</i>. The empty <a>ShortByteString</a>.
empty :: ShortByteString

-- | <i>O(1)</i> Convert a <a>Word8</a> into a <a>ShortByteString</a>
singleton :: Word8 -> ShortByteString

-- | <i>O(n)</i>. Convert a list into a <a>ShortByteString</a>
pack :: [Word8] -> ShortByteString

-- | <i>O(n)</i>. Convert a <a>ShortByteString</a> into a list.
unpack :: ShortByteString -> [Word8]

-- | <i>O(n)</i>. Convert a <a>ShortByteString</a> into a
--   <a>ByteString</a>.
fromShort :: ShortByteString -> ByteString

-- | <i>O(n)</i>. Convert a <a>ByteString</a> into a
--   <a>ShortByteString</a>.
--   
--   This makes a copy, so does not retain the input string.
toShort :: ByteString -> ShortByteString

-- | <i>O(n)</i> Append a byte to the end of a <a>ShortByteString</a>
--   
--   Note: copies the entire byte array
snoc :: ShortByteString -> Word8 -> ShortByteString
infixl 5 `snoc`

-- | <i>O(n)</i> <a>cons</a> is analogous to (:) for lists.
--   
--   Note: copies the entire byte array
cons :: Word8 -> ShortByteString -> ShortByteString
infixr 5 `cons`
append :: ShortByteString -> ShortByteString -> ShortByteString

-- | <i>O(1)</i> Extract the last element of a ShortByteString, which must
--   be finite and non-empty. An exception will be thrown in the case of an
--   empty ShortByteString.
--   
--   This is a partial function, consider using <a>unsnoc</a> instead.
last :: HasCallStack => ShortByteString -> Word8

-- | <i>O(n)</i> Extract the elements after the head of a ShortByteString,
--   which must be non-empty. An exception will be thrown in the case of an
--   empty ShortByteString.
--   
--   This is a partial function, consider using <a>uncons</a> instead.
--   
--   Note: copies the entire byte array
tail :: HasCallStack => ShortByteString -> ShortByteString

-- | <i>O(n)</i> Extract the <a>head</a> and <a>tail</a> of a
--   ShortByteString, returning <a>Nothing</a> if it is empty.
uncons :: ShortByteString -> Maybe (Word8, ShortByteString)
uncons2 :: ShortByteString -> Maybe (Word8, Word8, ShortByteString)

-- | <i>O(1)</i> Extract the first element of a ShortByteString, which must
--   be non-empty. An exception will be thrown in the case of an empty
--   ShortByteString.
--   
--   This is a partial function, consider using <a>uncons</a> instead.
head :: HasCallStack => ShortByteString -> Word8

-- | <i>O(n)</i> Return all the elements of a <a>ShortByteString</a> except
--   the last one. An exception will be thrown in the case of an empty
--   ShortByteString.
--   
--   This is a partial function, consider using <a>unsnoc</a> instead.
--   
--   Note: copies the entire byte array
init :: HasCallStack => ShortByteString -> ShortByteString

-- | <i>O(n)</i> Extract the <a>init</a> and <a>last</a> of a
--   ShortByteString, returning <a>Nothing</a> if it is empty.
unsnoc :: ShortByteString -> Maybe (ShortByteString, Word8)

-- | <i>O(1)</i> Test whether a <a>ShortByteString</a> is empty.
null :: ShortByteString -> Bool

-- | <i>O(1)</i> The length of a <a>ShortByteString</a>.
length :: ShortByteString -> Int

-- | <i>O(n)</i> <a>map</a> <tt>f xs</tt> is the ShortByteString obtained
--   by applying <tt>f</tt> to each element of <tt>xs</tt>.
map :: (Word8 -> Word8) -> ShortByteString -> ShortByteString

-- | <i>O(n)</i> <a>reverse</a> <tt>xs</tt> efficiently returns the
--   elements of <tt>xs</tt> in reverse order.
reverse :: ShortByteString -> ShortByteString

-- | <i>O(n)</i> The <a>intercalate</a> function takes a
--   <a>ShortByteString</a> and a list of <a>ShortByteString</a>s and
--   concatenates the list after interspersing the first argument between
--   each element of the list.
intercalate :: ShortByteString -> [ShortByteString] -> ShortByteString

-- | <a>foldl</a>, applied to a binary operator, a starting value
--   (typically the left-identity of the operator), and a ShortByteString,
--   reduces the ShortByteString using the binary operator, from left to
--   right.
foldl :: (a -> Word8 -> a) -> a -> ShortByteString -> a

-- | <a>foldl'</a> is like <a>foldl</a>, but strict in the accumulator.
foldl' :: (a -> Word8 -> a) -> a -> ShortByteString -> a

-- | <a>foldl1</a> is a variant of <a>foldl</a> that has no starting value
--   argument, and thus must be applied to non-empty
--   <a>ShortByteString</a>s. An exception will be thrown in the case of an
--   empty ShortByteString.
foldl1 :: HasCallStack => (Word8 -> Word8 -> Word8) -> ShortByteString -> Word8

-- | <a>foldl1'</a> is like <a>foldl1</a>, but strict in the accumulator.
--   An exception will be thrown in the case of an empty ShortByteString.
foldl1' :: HasCallStack => (Word8 -> Word8 -> Word8) -> ShortByteString -> Word8

-- | <a>foldr</a>, applied to a binary operator, a starting value
--   (typically the right-identity of the operator), and a ShortByteString,
--   reduces the ShortByteString using the binary operator, from right to
--   left.
foldr :: (Word8 -> a -> a) -> a -> ShortByteString -> a

-- | <a>foldr'</a> is like <a>foldr</a>, but strict in the accumulator.
foldr' :: (Word8 -> a -> a) -> a -> ShortByteString -> a

-- | <a>foldr1</a> is a variant of <a>foldr</a> that has no starting value
--   argument, and thus must be applied to non-empty
--   <a>ShortByteString</a>s An exception will be thrown in the case of an
--   empty ShortByteString.
foldr1 :: HasCallStack => (Word8 -> Word8 -> Word8) -> ShortByteString -> Word8

-- | <a>foldr1'</a> is a variant of <a>foldr1</a>, but is strict in the
--   accumulator.
foldr1' :: HasCallStack => (Word8 -> Word8 -> Word8) -> ShortByteString -> Word8

-- | <i>O(n)</i> Applied to a predicate and a <a>ShortByteString</a>,
--   <a>all</a> determines if all elements of the <a>ShortByteString</a>
--   satisfy the predicate.
all :: (Word8 -> Bool) -> ShortByteString -> Bool

-- | <i>O(n)</i> Applied to a predicate and a <a>ShortByteString</a>,
--   <a>any</a> determines if any element of the <a>ShortByteString</a>
--   satisfies the predicate.
any :: (Word8 -> Bool) -> ShortByteString -> Bool
concat :: [ShortByteString] -> ShortByteString

-- | <i>O(n)</i> <a>replicate</a> <tt>n x</tt> is a ShortByteString of
--   length <tt>n</tt> with <tt>x</tt> the value of every element. The
--   following holds:
--   
--   <pre>
--   replicate w c = unfoldr w (\u -&gt; Just (u,u)) c
--   </pre>
replicate :: Int -> Word8 -> ShortByteString

-- | <i>O(n)</i>, where <i>n</i> is the length of the result. The
--   <a>unfoldr</a> function is analogous to the List 'unfoldr'.
--   <a>unfoldr</a> builds a ShortByteString from a seed value. The
--   function takes the element and returns <a>Nothing</a> if it is done
--   producing the ShortByteString or returns <a>Just</a> <tt>(a,b)</tt>,
--   in which case, <tt>a</tt> is the next byte in the string, and
--   <tt>b</tt> is the seed value for further production.
--   
--   This function is not efficient/safe. It will build a list of
--   <tt>[Word8]</tt> and run the generator until it returns
--   <a>Nothing</a>, otherwise recurse infinitely, then finally create a
--   <a>ShortByteString</a>.
--   
--   If you know the maximum length, consider using <a>unfoldrN</a>.
--   
--   Examples:
--   
--   <pre>
--      unfoldr (\x -&gt; if x &lt;= 5 then Just (x, x + 1) else Nothing) 0
--   == pack [0, 1, 2, 3, 4, 5]
--   </pre>
unfoldr :: (a -> Maybe (Word8, a)) -> a -> ShortByteString

-- | <i>O(n)</i> Like <a>unfoldr</a>, <a>unfoldrN</a> builds a
--   ShortByteString from a seed value. However, the length of the result
--   is limited by the first argument to <a>unfoldrN</a>. This function is
--   more efficient than <a>unfoldr</a> when the maximum length of the
--   result is known.
--   
--   The following equation relates <a>unfoldrN</a> and <a>unfoldr</a>:
--   
--   <pre>
--   fst (unfoldrN n f s) == take n (unfoldr f s)
--   </pre>
unfoldrN :: Int -> (a -> Maybe (Word8, a)) -> a -> (ShortByteString, Maybe a)

-- | <i>O(n)</i> <a>take</a> <tt>n</tt>, applied to a ShortByteString
--   <tt>xs</tt>, returns the prefix of <tt>xs</tt> of length <tt>n</tt>,
--   or <tt>xs</tt> itself if <tt>n &gt; <a>length</a> xs</tt>.
--   
--   Note: copies the entire byte array
take :: Int -> ShortByteString -> ShortByteString

-- | <i>O(n)</i> <tt><a>takeEnd</a> n xs</tt> is equivalent to
--   <tt><a>drop</a> (<a>length</a> xs - n) xs</tt>. Takes <tt>n</tt>
--   elements from end of bytestring.
--   
--   <pre>
--   &gt;&gt;&gt; takeEnd 3 "abcdefg"
--   "efg"
--   
--   &gt;&gt;&gt; takeEnd 0 "abcdefg"
--   ""
--   
--   &gt;&gt;&gt; takeEnd 4 "abc"
--   "abc"
--   </pre>
takeEnd :: Int -> ShortByteString -> ShortByteString

-- | Returns the longest (possibly empty) suffix of elements satisfying the
--   predicate.
--   
--   <tt><a>takeWhileEnd</a> p</tt> is equivalent to <tt><a>reverse</a> .
--   <a>takeWhile</a> p . <a>reverse</a></tt>.
takeWhileEnd :: (Word8 -> Bool) -> ShortByteString -> ShortByteString

-- | Similar to <a>takeWhile</a>, returns the longest (possibly empty)
--   prefix of elements satisfying the predicate.
takeWhile :: (Word8 -> Bool) -> ShortByteString -> ShortByteString

-- | <i>O(n)</i> <a>drop</a> <tt>n</tt> <tt>xs</tt> returns the suffix of
--   <tt>xs</tt> after the first n elements, or <a>empty</a> if <tt>n &gt;
--   <a>length</a> xs</tt>.
--   
--   Note: copies the entire byte array
drop :: Int -> ShortByteString -> ShortByteString

-- | <i>O(n)</i> <tt><a>dropEnd</a> n xs</tt> is equivalent to
--   <tt><a>take</a> (<a>length</a> xs - n) xs</tt>. Drops <tt>n</tt>
--   elements from end of bytestring.
--   
--   <pre>
--   &gt;&gt;&gt; dropEnd 3 "abcdefg"
--   "abcd"
--   
--   &gt;&gt;&gt; dropEnd 0 "abcdefg"
--   "abcdefg"
--   
--   &gt;&gt;&gt; dropEnd 4 "abc"
--   ""
--   </pre>
dropEnd :: Int -> ShortByteString -> ShortByteString

-- | Similar to <a>dropWhile</a>, drops the longest (possibly empty) prefix
--   of elements satisfying the predicate and returns the remainder.
--   
--   Note: copies the entire byte array
dropWhile :: (Word8 -> Bool) -> ShortByteString -> ShortByteString

-- | Similar to <a>dropWhileEnd</a>, drops the longest (possibly empty)
--   suffix of elements satisfying the predicate and returns the remainder.
--   
--   <tt><a>dropWhileEnd</a> p</tt> is equivalent to <tt><a>reverse</a> .
--   <a>dropWhile</a> p . <a>reverse</a></tt>.
dropWhileEnd :: (Word8 -> Bool) -> ShortByteString -> ShortByteString

-- | Returns the longest (possibly empty) suffix of elements which <b>do
--   not</b> satisfy the predicate and the remainder of the string.
--   
--   <a>breakEnd</a> <tt>p</tt> is equivalent to <tt><a>spanEnd</a> (not .
--   p)</tt> and to <tt>(<a>takeWhileEnd</a> (not . p) &amp;&amp;&amp;
--   <a>dropWhileEnd</a> (not . p))</tt>.
breakEnd :: (Word8 -> Bool) -> ShortByteString -> (ShortByteString, ShortByteString)

-- | Similar to <a>break</a>, returns the longest (possibly empty) prefix
--   of elements which <b>do not</b> satisfy the predicate and the
--   remainder of the string.
--   
--   <a>break</a> <tt>p</tt> is equivalent to <tt><a>span</a> (not .
--   p)</tt> and to <tt>(<a>takeWhile</a> (not . p) &amp;&amp;&amp;
--   <a>dropWhile</a> (not . p))</tt>.
break :: (Word8 -> Bool) -> ShortByteString -> (ShortByteString, ShortByteString)

-- | Similar to <a>span</a>, returns the longest (possibly empty) prefix of
--   elements satisfying the predicate and the remainder of the string.
--   
--   <a>span</a> <tt>p</tt> is equivalent to <tt><a>break</a> (not .
--   p)</tt> and to <tt>(<a>takeWhile</a> p &amp;&amp;&amp;
--   <a>dropWhile</a> p)</tt>.
span :: (Word8 -> Bool) -> ShortByteString -> (ShortByteString, ShortByteString)

-- | Returns the longest (possibly empty) suffix of elements satisfying the
--   predicate and the remainder of the string.
--   
--   <a>spanEnd</a> <tt>p</tt> is equivalent to <tt><a>breakEnd</a> (not .
--   p)</tt> and to <tt>(<a>takeWhileEnd</a> p &amp;&amp;&amp;
--   <a>dropWhileEnd</a> p)</tt>.
--   
--   We have
--   
--   <pre>
--   spanEnd (not . isSpace) "x y z" == ("x y ", "z")
--   </pre>
--   
--   and
--   
--   <pre>
--   spanEnd (not . isSpace) sbs
--      ==
--   let (x, y) = span (not . isSpace) (reverse sbs) in (reverse y, reverse x)
--   </pre>
spanEnd :: (Word8 -> Bool) -> ShortByteString -> (ShortByteString, ShortByteString)

-- | <i>O(n)</i> <a>splitAt</a> <tt>n sbs</tt> is equivalent to
--   <tt>(<a>take</a> n sbs, <a>drop</a> n sbs)</tt>.
--   
--   Note: copies the substrings
splitAt :: Int -> ShortByteString -> (ShortByteString, ShortByteString)

-- | <i>O(n)</i> Break a <a>ShortByteString</a> into pieces separated by
--   the byte argument, consuming the delimiter. I.e.
--   
--   <pre>
--   split 10  "a\nb\nd\ne" == ["a","b","d","e"]   -- fromEnum '\n' == 10
--   split 97  "aXaXaXa"    == ["","X","X","X",""] -- fromEnum 'a' == 97
--   split 120 "x"          == ["",""]             -- fromEnum 'x' == 120
--   split undefined ""     == []                  -- and not [""]
--   </pre>
--   
--   and
--   
--   <pre>
--   intercalate [c] . split c == id
--   split == splitWith . (==)
--   </pre>
--   
--   Note: copies the substrings
split :: Word8 -> ShortByteString -> [ShortByteString]

-- | <i>O(n)</i> Splits a <a>ShortByteString</a> into components delimited
--   by separators, where the predicate returns True for a separator
--   element. The resulting components do not contain the separators. Two
--   adjacent separators result in an empty component in the output. eg.
--   
--   <pre>
--   splitWith (==97) "aabbaca" == ["","","bb","c",""] -- fromEnum 'a' == 97
--   splitWith undefined ""     == []                  -- and not [""]
--   </pre>
splitWith :: (Word8 -> Bool) -> ShortByteString -> [ShortByteString]

-- | <i>O(n)</i> The <a>stripSuffix</a> function takes two ShortByteStrings
--   and returns <a>Just</a> the remainder of the second iff the first is
--   its suffix, and otherwise <a>Nothing</a>.
stripSuffix :: ShortByteString -> ShortByteString -> Maybe ShortByteString

-- | <i>O(n)</i> The <a>stripPrefix</a> function takes two ShortByteStrings
--   and returns <a>Just</a> the remainder of the second iff the first is
--   its prefix, and otherwise <a>Nothing</a>.
stripPrefix :: ShortByteString -> ShortByteString -> Maybe ShortByteString

-- | Check whether one string is a substring of another.
isInfixOf :: ShortByteString -> ShortByteString -> Bool

-- | <i>O(n)</i> The <a>isPrefixOf</a> function takes two ShortByteStrings
--   and returns <a>True</a>
isPrefixOf :: ShortByteString -> ShortByteString -> Bool

-- | <i>O(n)</i> The <a>isSuffixOf</a> function takes two ShortByteStrings
--   and returns <a>True</a> iff the first is a suffix of the second.
--   
--   The following holds:
--   
--   <pre>
--   isSuffixOf x y == reverse x `isPrefixOf` reverse y
--   </pre>
isSuffixOf :: ShortByteString -> ShortByteString -> Bool

-- | Break a string on a substring, returning a pair of the part of the
--   string prior to the match, and the rest of the string.
--   
--   The following relationships hold:
--   
--   <pre>
--   break (== c) l == breakSubstring (singleton c) l
--   </pre>
--   
--   For example, to tokenise a string, dropping delimiters:
--   
--   <pre>
--   tokenise x y = h : if null t then [] else tokenise x (drop (length x) t)
--       where (h,t) = breakSubstring x y
--   </pre>
--   
--   To skip to the first occurrence of a string:
--   
--   <pre>
--   snd (breakSubstring x y)
--   </pre>
--   
--   To take the parts of a string before a delimiter:
--   
--   <pre>
--   fst (breakSubstring x y)
--   </pre>
--   
--   Note that calling `breakSubstring x` does some preprocessing work, so
--   you should avoid unnecessarily duplicating breakSubstring calls with
--   the same pattern.
breakSubstring :: ShortByteString -> ShortByteString -> (ShortByteString, ShortByteString)

-- | <i>O(n)</i> <a>elem</a> is the <a>ShortByteString</a> membership
--   predicate.
elem :: Word8 -> ShortByteString -> Bool

-- | <i>O(n)</i> The <a>find</a> function takes a predicate and a
--   ShortByteString, and returns the first element in matching the
--   predicate, or <a>Nothing</a> if there is no such element.
--   
--   <pre>
--   find f p = case findIndex f p of Just n -&gt; Just (p ! n) ; _ -&gt; Nothing
--   </pre>
find :: (Word8 -> Bool) -> ShortByteString -> Maybe Word8

-- | <i>O(n)</i> <a>filter</a>, applied to a predicate and a
--   ShortByteString, returns a ShortByteString containing those characters
--   that satisfy the predicate.
filter :: (Word8 -> Bool) -> ShortByteString -> ShortByteString

-- | <i>O(n)</i> The <a>partition</a> function takes a predicate a
--   ShortByteString and returns the pair of ShortByteStrings with elements
--   which do and do not satisfy the predicate, respectively; i.e.,
--   
--   <pre>
--   partition p bs == (filter p sbs, filter (not . p) sbs)
--   </pre>
partition :: (Word8 -> Bool) -> ShortByteString -> (ShortByteString, ShortByteString)

-- | <i>O(1)</i> <a>ShortByteString</a> index (subscript) operator,
--   starting from 0.
--   
--   This is a partial function, consider using <a>indexMaybe</a> instead.
index :: HasCallStack => ShortByteString -> Int -> Word8

-- | <i>O(1)</i> <a>ShortByteString</a> index, starting from 0, that
--   returns <a>Just</a> if:
--   
--   <pre>
--   0 &lt;= n &lt; length bs
--   </pre>
indexMaybe :: ShortByteString -> Int -> Maybe Word8

-- | <i>O(1)</i> <a>ShortByteString</a> index, starting from 0, that
--   returns <a>Just</a> if:
--   
--   <pre>
--   0 &lt;= n &lt; length bs
--   </pre>
(!?) :: ShortByteString -> Int -> Maybe Word8

-- | <i>O(n)</i> The <a>elemIndex</a> function returns the index of the
--   first element in the given <a>ShortByteString</a> which is equal to
--   the query element, or <a>Nothing</a> if there is no such element.
elemIndex :: Word8 -> ShortByteString -> Maybe Int

-- | <i>O(n)</i> The <a>elemIndices</a> function extends <a>elemIndex</a>,
--   by returning the indices of all elements equal to the query element,
--   in ascending order.
elemIndices :: Word8 -> ShortByteString -> [Int]

-- | count returns the number of times its argument appears in the
--   ShortByteString
count :: Word8 -> ShortByteString -> Int

-- | <i>O(n)</i> The <a>findIndex</a> function takes a predicate and a
--   <a>ShortByteString</a> and returns the index of the first element in
--   the ShortByteString satisfying the predicate.
findIndex :: (Word8 -> Bool) -> ShortByteString -> Maybe Int

-- | <i>O(n)</i> The <a>findIndices</a> function extends <a>findIndex</a>,
--   by returning the indices of all elements satisfying the predicate, in
--   ascending order.
findIndices :: (Word8 -> Bool) -> ShortByteString -> [Int]

-- | <i>O(n).</i> Construct a new <tt>ShortByteString</tt> from a
--   <tt>CString</tt>. The resulting <tt>ShortByteString</tt> is an
--   immutable copy of the original <tt>CString</tt>, and is managed on the
--   Haskell heap. The original <tt>CString</tt> must be null terminated.
packCString :: CString -> IO ShortByteString

-- | <i>O(n).</i> Construct a new <tt>ShortByteString</tt> from a
--   <tt>CStringLen</tt>. The resulting <tt>ShortByteString</tt> is an
--   immutable copy of the original <tt>CStringLen</tt>. The
--   <tt>ShortByteString</tt> is a normal Haskell value and will be managed
--   on the Haskell heap.
packCStringLen :: CStringLen -> IO ShortByteString

-- | <i>O(n) construction.</i> Use a <tt>ShortByteString</tt> with a
--   function requiring a null-terminated <tt>CString</tt>. The
--   <tt>CString</tt> is a copy and will be freed automatically; it must
--   not be stored or used after the subcomputation finishes.
useAsCString :: ShortByteString -> (CString -> IO a) -> IO a

-- | <i>O(n) construction.</i> Use a <tt>ShortByteString</tt> with a
--   function requiring a <tt>CStringLen</tt>. As for <tt>useAsCString</tt>
--   this function makes a copy of the original <tt>ShortByteString</tt>.
--   It must not be stored or used after the subcomputation finishes.
useAsCStringLen :: ShortByteString -> (CStringLen -> IO a) -> IO a


-- | ShortByteStrings encoded as UTF16-LE, suitable for windows FFI calls.
--   
--   Word16s are *always* in BE encoding (both input and output), so e.g.
--   <a>pack</a> takes a list of BE encoded <tt>[Word16]</tt> and produces
--   a UTF16-LE encoded ShortByteString.
--   
--   Likewise, <a>unpack</a> takes a UTF16-LE encoded ShortByteString and
--   produces a list of BE encoded <tt>[Word16]</tt>.
--   
--   Indices and lengths are always in respect to Word16, not Word8.
--   
--   All functions will error out if the input string is not a valid UTF16
--   stream (uneven number of bytes). So use this module with caution.

-- | <i>Deprecated: Use System.OsString.Data.ByteString.Short.Word16 from
--   os-string &gt;= 2.0.0 package instead. This module will be removed in
--   filepath &gt;= 1.5.</i>
module System.OsPath.Data.ByteString.Short.Word16

-- | A compact representation of a <a>Word8</a> vector.
--   
--   It has a lower memory overhead than a <a>ByteString</a> and does not
--   contribute to heap fragmentation. It can be converted to or from a
--   <a>ByteString</a> (at the cost of copying the string data). It
--   supports very few other operations.
data () => ShortByteString
SBS :: ByteArray# -> ShortByteString

-- | <i>O(1)</i>. The empty <a>ShortByteString</a>.
empty :: ShortByteString

-- | <i>O(1)</i> Convert a <a>Word16</a> into a <a>ShortByteString</a>
singleton :: Word16 -> ShortByteString

-- | <i>O(n)</i>. Convert a list into a <a>ShortByteString</a>
pack :: [Word16] -> ShortByteString

-- | <i>O(n)</i>. Convert a <a>ShortByteString</a> into a list.
unpack :: ShortByteString -> [Word16]

-- | <i>O(n)</i>. Convert a <a>ShortByteString</a> into a
--   <a>ByteString</a>.
fromShort :: ShortByteString -> ByteString

-- | <i>O(n)</i>. Convert a <a>ByteString</a> into a
--   <a>ShortByteString</a>.
--   
--   This makes a copy, so does not retain the input string.
toShort :: ByteString -> ShortByteString

-- | <i>O(n)</i> Append a Word16 to the end of a <a>ShortByteString</a>
--   
--   Note: copies the entire byte array
snoc :: ShortByteString -> Word16 -> ShortByteString
infixl 5 `snoc`

-- | <i>O(n)</i> <a>cons</a> is analogous to (:) for lists.
--   
--   Note: copies the entire byte array
cons :: Word16 -> ShortByteString -> ShortByteString
infixr 5 `cons`
append :: ShortByteString -> ShortByteString -> ShortByteString

-- | <i>O(1)</i> Extract the last element of a ShortByteString, which must
--   be finite and at least one Word16. An exception will be thrown in the
--   case of an empty ShortByteString.
last :: HasCallStack => ShortByteString -> Word16

-- | <i>O(n)</i> Extract the elements after the head of a ShortByteString,
--   which must at least one Word16. An exception will be thrown in the
--   case of an empty ShortByteString.
--   
--   Note: copies the entire byte array
tail :: HasCallStack => ShortByteString -> ShortByteString

-- | <i>O(n)</i> Extract the head and tail of a ByteString, returning
--   Nothing if it is empty.
uncons :: ShortByteString -> Maybe (Word16, ShortByteString)

-- | <i>O(n)</i> Extract first two elements and the rest of a ByteString,
--   returning Nothing if it is shorter than two elements.
uncons2 :: ShortByteString -> Maybe (Word16, Word16, ShortByteString)

-- | <i>O(1)</i> Extract the first element of a ShortByteString, which must
--   be at least one Word16. An exception will be thrown in the case of an
--   empty ShortByteString.
head :: HasCallStack => ShortByteString -> Word16

-- | <i>O(n)</i> Return all the elements of a <a>ShortByteString</a> except
--   the last one. An exception will be thrown in the case of an empty
--   ShortByteString.
--   
--   Note: copies the entire byte array
init :: HasCallStack => ShortByteString -> ShortByteString

-- | <i>O(n)</i> Extract the <a>init</a> and <a>last</a> of a ByteString,
--   returning Nothing if it is empty.
unsnoc :: ShortByteString -> Maybe (ShortByteString, Word16)

-- | <i>O(1)</i> Test whether a <a>ShortByteString</a> is empty.
null :: ShortByteString -> Bool

-- | <i>O(1)</i> The length of a <a>ShortByteString</a>.
length :: ShortByteString -> Int

-- | This is like <a>length</a>, but the number of <a>Word16</a>, not
--   <a>Word8</a>.
numWord16 :: ShortByteString -> Int

-- | <i>O(n)</i> <a>map</a> <tt>f xs</tt> is the ShortByteString obtained
--   by applying <tt>f</tt> to each element of <tt>xs</tt>.
map :: (Word16 -> Word16) -> ShortByteString -> ShortByteString

-- | <i>O(n)</i> <a>reverse</a> <tt>xs</tt> efficiently returns the
--   elements of <tt>xs</tt> in reverse order.
reverse :: ShortByteString -> ShortByteString

-- | <i>O(n)</i> The <a>intercalate</a> function takes a
--   <a>ShortByteString</a> and a list of <a>ShortByteString</a>s and
--   concatenates the list after interspersing the first argument between
--   each element of the list.
intercalate :: ShortByteString -> [ShortByteString] -> ShortByteString

-- | <a>foldl</a>, applied to a binary operator, a starting value
--   (typically the left-identity of the operator), and a ShortByteString,
--   reduces the ShortByteString using the binary operator, from left to
--   right.
foldl :: (a -> Word16 -> a) -> a -> ShortByteString -> a

-- | <a>foldl'</a> is like <a>foldl</a>, but strict in the accumulator.
foldl' :: (a -> Word16 -> a) -> a -> ShortByteString -> a

-- | <a>foldl1</a> is a variant of <a>foldl</a> that has no starting value
--   argument, and thus must be applied to non-empty
--   <a>ShortByteString</a>s. An exception will be thrown in the case of an
--   empty ShortByteString.
foldl1 :: HasCallStack => (Word16 -> Word16 -> Word16) -> ShortByteString -> Word16

-- | <a>foldl1'</a> is like <a>foldl1</a>, but strict in the accumulator.
--   An exception will be thrown in the case of an empty ShortByteString.
foldl1' :: HasCallStack => (Word16 -> Word16 -> Word16) -> ShortByteString -> Word16

-- | <a>foldr</a>, applied to a binary operator, a starting value
--   (typically the right-identity of the operator), and a ShortByteString,
--   reduces the ShortByteString using the binary operator, from right to
--   left.
foldr :: (Word16 -> a -> a) -> a -> ShortByteString -> a

-- | <a>foldr'</a> is like <a>foldr</a>, but strict in the accumulator.
foldr' :: (Word16 -> a -> a) -> a -> ShortByteString -> a

-- | <a>foldr1</a> is a variant of <a>foldr</a> that has no starting value
--   argument, and thus must be applied to non-empty
--   <a>ShortByteString</a>s An exception will be thrown in the case of an
--   empty ShortByteString.
foldr1 :: HasCallStack => (Word16 -> Word16 -> Word16) -> ShortByteString -> Word16

-- | <a>foldr1'</a> is a variant of <a>foldr1</a>, but is strict in the
--   accumulator.
foldr1' :: HasCallStack => (Word16 -> Word16 -> Word16) -> ShortByteString -> Word16

-- | <i>O(n)</i> Applied to a predicate and a <a>ShortByteString</a>,
--   <a>all</a> determines if all elements of the <a>ShortByteString</a>
--   satisfy the predicate.
all :: (Word16 -> Bool) -> ShortByteString -> Bool

-- | <i>O(n)</i> Applied to a predicate and a ByteString, <a>any</a>
--   determines if any element of the <tt>ByteString</tt> satisfies the
--   predicate.
any :: (Word16 -> Bool) -> ShortByteString -> Bool
concat :: [ShortByteString] -> ShortByteString

-- | <i>O(n)</i> <a>replicate</a> <tt>n x</tt> is a ByteString of length
--   <tt>n</tt> with <tt>x</tt> the value of every element. The following
--   holds:
--   
--   <pre>
--   replicate w c = unfoldr w (\u -&gt; Just (u,u)) c
--   </pre>
replicate :: Int -> Word16 -> ShortByteString

-- | <i>O(n)</i>, where <i>n</i> is the length of the result. The
--   <a>unfoldr</a> function is analogous to the List 'unfoldr'.
--   <a>unfoldr</a> builds a ShortByteString from a seed value. The
--   function takes the element and returns <a>Nothing</a> if it is done
--   producing the ShortByteString or returns <a>Just</a> <tt>(a,b)</tt>,
--   in which case, <tt>a</tt> is the next byte in the string, and
--   <tt>b</tt> is the seed value for further production.
--   
--   This function is not efficient/safe. It will build a list of
--   <tt>[Word16]</tt> and run the generator until it returns
--   <a>Nothing</a>, otherwise recurse infinitely, then finally create a
--   <a>ShortByteString</a>.
--   
--   Examples:
--   
--   <pre>
--      unfoldr (\x -&gt; if x &lt;= 5 then Just (x, x + 1) else Nothing) 0
--   == pack [0, 1, 2, 3, 4, 5]
--   </pre>
unfoldr :: (a -> Maybe (Word16, a)) -> a -> ShortByteString

-- | <i>O(n)</i> Like <a>unfoldr</a>, <a>unfoldrN</a> builds a
--   ShortByteString from a seed value. However, the length of the result
--   is limited by the first argument to <a>unfoldrN</a>. This function is
--   more efficient than <a>unfoldr</a> when the maximum length of the
--   result is known.
--   
--   The following equation relates <a>unfoldrN</a> and <a>unfoldr</a>:
--   
--   <pre>
--   fst (unfoldrN n f s) == take n (unfoldr f s)
--   </pre>
unfoldrN :: forall a. Int -> (a -> Maybe (Word16, a)) -> a -> (ShortByteString, Maybe a)

-- | <i>O(n)</i> <a>take</a> <tt>n</tt>, applied to a ShortByteString
--   <tt>xs</tt>, returns the prefix of <tt>xs</tt> of length <tt>n</tt>,
--   or <tt>xs</tt> itself if <tt>n &gt; <a>length</a> xs</tt>.
--   
--   Note: copies the entire byte array
take :: Int -> ShortByteString -> ShortByteString

-- | <i>O(1)</i> <tt><a>takeEnd</a> n xs</tt> is equivalent to
--   <tt><a>drop</a> (<a>length</a> xs - n) xs</tt>. Takes <tt>n</tt>
--   elements from end of bytestring.
--   
--   <pre>
--   &gt;&gt;&gt; takeEnd 3 "a\NULb\NULc\NULd\NULe\NULf\NULg\NUL"
--   "e\NULf\NULg\NUL"
--   
--   &gt;&gt;&gt; takeEnd 0 "a\NULb\NULc\NULd\NULe\NULf\NULg\NUL"
--   ""
--   
--   &gt;&gt;&gt; takeEnd 4 "a\NULb\NULc\NUL"
--   "a\NULb\NULc\NUL"
--   </pre>
takeEnd :: Int -> ShortByteString -> ShortByteString

-- | Returns the longest (possibly empty) suffix of elements satisfying the
--   predicate.
--   
--   <tt><a>takeWhileEnd</a> p</tt> is equivalent to <tt><a>reverse</a> .
--   <a>takeWhile</a> p . <a>reverse</a></tt>.
takeWhileEnd :: (Word16 -> Bool) -> ShortByteString -> ShortByteString

-- | Similar to <a>takeWhile</a>, returns the longest (possibly empty)
--   prefix of elements satisfying the predicate.
takeWhile :: (Word16 -> Bool) -> ShortByteString -> ShortByteString

-- | <i>O(n)</i> <a>drop</a> <tt>n</tt> <tt>xs</tt> returns the suffix of
--   <tt>xs</tt> after the first n elements, or <tt>[]</tt> if <tt>n &gt;
--   <a>length</a> xs</tt>.
--   
--   Note: copies the entire byte array
drop :: Int -> ShortByteString -> ShortByteString

-- | <i>O(1)</i> <tt><a>dropEnd</a> n xs</tt> is equivalent to
--   <tt><a>take</a> (<a>length</a> xs - n) xs</tt>. Drops <tt>n</tt>
--   elements from end of bytestring.
--   
--   <pre>
--   &gt;&gt;&gt; dropEnd 3 "a\NULb\NULc\NULd\NULe\NULf\NULg\NUL"
--   "a\NULb\NULc\NULd\NUL"
--   
--   &gt;&gt;&gt; dropEnd 0 "a\NULb\NULc\NULd\NULe\NULf\NULg\NUL"
--   "a\NULb\NULc\NULd\NULe\NULf\NULg\NUL"
--   
--   &gt;&gt;&gt; dropEnd 4 "a\NULb\NULc\NUL"
--   ""
--   </pre>
dropEnd :: Int -> ShortByteString -> ShortByteString

-- | Similar to <a>dropWhile</a>, drops the longest (possibly empty) prefix
--   of elements satisfying the predicate and returns the remainder.
--   
--   Note: copies the entire byte array
dropWhile :: (Word16 -> Bool) -> ShortByteString -> ShortByteString

-- | Similar to <a>dropWhileEnd</a>, drops the longest (possibly empty)
--   suffix of elements satisfying the predicate and returns the remainder.
--   
--   <tt><a>dropWhileEnd</a> p</tt> is equivalent to <tt><a>reverse</a> .
--   <a>dropWhile</a> p . <a>reverse</a></tt>.
dropWhileEnd :: (Word16 -> Bool) -> ShortByteString -> ShortByteString

-- | Returns the longest (possibly empty) suffix of elements which <b>do
--   not</b> satisfy the predicate and the remainder of the string.
--   
--   <a>breakEnd</a> <tt>p</tt> is equivalent to <tt><a>spanEnd</a> (not .
--   p)</tt> and to <tt>(<a>takeWhileEnd</a> (not . p) &amp;&amp;&amp;
--   <a>dropWhileEnd</a> (not . p))</tt>.
breakEnd :: (Word16 -> Bool) -> ShortByteString -> (ShortByteString, ShortByteString)

-- | Similar to <a>break</a>, returns the longest (possibly empty) prefix
--   of elements which <b>do not</b> satisfy the predicate and the
--   remainder of the string.
--   
--   <a>break</a> <tt>p</tt> is equivalent to <tt><a>span</a> (not .
--   p)</tt> and to <tt>(<a>takeWhile</a> (not . p) &amp;&amp;&amp;
--   <a>dropWhile</a> (not . p))</tt>.
break :: (Word16 -> Bool) -> ShortByteString -> (ShortByteString, ShortByteString)

-- | Similar to <a>span</a>, returns the longest (possibly empty) prefix of
--   elements satisfying the predicate and the remainder of the string.
--   
--   <a>span</a> <tt>p</tt> is equivalent to <tt><a>break</a> (not .
--   p)</tt> and to <tt>(<a>takeWhile</a> p &amp;&amp;&amp;
--   <a>dropWhile</a> p)</tt>.
span :: (Word16 -> Bool) -> ShortByteString -> (ShortByteString, ShortByteString)

-- | Returns the longest (possibly empty) suffix of elements satisfying the
--   predicate and the remainder of the string.
--   
--   <a>spanEnd</a> <tt>p</tt> is equivalent to <tt><a>breakEnd</a> (not .
--   p)</tt> and to <tt>(<a>takeWhileEnd</a> p &amp;&amp;&amp;
--   <a>dropWhileEnd</a> p)</tt>.
--   
--   We have
--   
--   <pre>
--   spanEnd (not . isSpace) "x y z" == ("x y ", "z")
--   </pre>
--   
--   and
--   
--   <pre>
--   spanEnd (not . isSpace) ps
--      ==
--   let (x, y) = span (not . isSpace) (reverse ps) in (reverse y, reverse x)
--   </pre>
spanEnd :: (Word16 -> Bool) -> ShortByteString -> (ShortByteString, ShortByteString)

-- | <i>O(n)</i> <a>splitAt</a> <tt>n xs</tt> is equivalent to
--   <tt>(<a>take</a> n xs, <a>drop</a> n xs)</tt>.
--   
--   Note: copies the substrings
splitAt :: Int -> ShortByteString -> (ShortByteString, ShortByteString)

-- | <i>O(n)</i> Break a <a>ShortByteString</a> into pieces separated by
--   the byte argument, consuming the delimiter. I.e.
--   
--   <pre>
--   split 10  "a\nb\nd\ne" == ["a","b","d","e"]   -- fromEnum '\n' == 10
--   split 97  "aXaXaXa"    == ["","X","X","X",""] -- fromEnum 'a' == 97
--   split 120 "x"          == ["",""]             -- fromEnum 'x' == 120
--   split undefined ""     == []                  -- and not [""]
--   </pre>
--   
--   and
--   
--   <pre>
--   intercalate [c] . split c == id
--   split == splitWith . (==)
--   </pre>
--   
--   Note: copies the substrings
split :: Word16 -> ShortByteString -> [ShortByteString]

-- | <i>O(n)</i> Splits a <a>ShortByteString</a> into components delimited
--   by separators, where the predicate returns True for a separator
--   element. The resulting components do not contain the separators. Two
--   adjacent separators result in an empty component in the output. eg.
--   
--   <pre>
--   splitWith (==97) "aabbaca" == ["","","bb","c",""] -- fromEnum 'a' == 97
--   splitWith undefined ""     == []                  -- and not [""]
--   </pre>
splitWith :: (Word16 -> Bool) -> ShortByteString -> [ShortByteString]

-- | <i>O(n)</i> The <a>stripSuffix</a> function takes two ShortByteStrings
--   and returns <a>Just</a> the remainder of the second iff the first is
--   its suffix, and otherwise <a>Nothing</a>.
stripSuffix :: ShortByteString -> ShortByteString -> Maybe ShortByteString

-- | <i>O(n)</i> The <a>stripPrefix</a> function takes two ShortByteStrings
--   and returns <a>Just</a> the remainder of the second iff the first is
--   its prefix, and otherwise <a>Nothing</a>.
stripPrefix :: ShortByteString -> ShortByteString -> Maybe ShortByteString

-- | Check whether one string is a substring of another.
isInfixOf :: ShortByteString -> ShortByteString -> Bool

-- | <i>O(n)</i> The <a>isPrefixOf</a> function takes two ShortByteStrings
--   and returns <a>True</a>
isPrefixOf :: ShortByteString -> ShortByteString -> Bool

-- | <i>O(n)</i> The <a>isSuffixOf</a> function takes two ShortByteStrings
--   and returns <a>True</a> iff the first is a suffix of the second.
--   
--   The following holds:
--   
--   <pre>
--   isSuffixOf x y == reverse x `isPrefixOf` reverse y
--   </pre>
isSuffixOf :: ShortByteString -> ShortByteString -> Bool
breakSubstring :: ShortByteString -> ShortByteString -> (ShortByteString, ShortByteString)

-- | <i>O(n)</i> <a>elem</a> is the <a>ShortByteString</a> membership
--   predicate.
elem :: Word16 -> ShortByteString -> Bool

-- | <i>O(n)</i> The <a>find</a> function takes a predicate and a
--   ByteString, and returns the first element in matching the predicate,
--   or <a>Nothing</a> if there is no such element.
--   
--   <pre>
--   find f p = case findIndex f p of Just n -&gt; Just (p ! n) ; _ -&gt; Nothing
--   </pre>
find :: (Word16 -> Bool) -> ShortByteString -> Maybe Word16

-- | <i>O(n)</i> <a>filter</a>, applied to a predicate and a ByteString,
--   returns a ByteString containing those characters that satisfy the
--   predicate.
filter :: (Word16 -> Bool) -> ShortByteString -> ShortByteString

-- | <i>O(n)</i> The <a>partition</a> function takes a predicate a
--   ByteString and returns the pair of ByteStrings with elements which do
--   and do not satisfy the predicate, respectively; i.e.,
--   
--   <pre>
--   partition p bs == (filter p xs, filter (not . p) xs)
--   </pre>
partition :: (Word16 -> Bool) -> ShortByteString -> (ShortByteString, ShortByteString)

-- | <i>O(1)</i> <a>ShortByteString</a> index (subscript) operator,
--   starting from 0.
index :: HasCallStack => ShortByteString -> Int -> Word16

-- | <i>O(1)</i> <a>ShortByteString</a> index, starting from 0, that
--   returns <a>Just</a> if:
--   
--   <pre>
--   0 &lt;= n &lt; length bs
--   </pre>
indexMaybe :: ShortByteString -> Int -> Maybe Word16

-- | <i>O(1)</i> <a>ShortByteString</a> index, starting from 0, that
--   returns <a>Just</a> if:
--   
--   <pre>
--   0 &lt;= n &lt; length bs
--   </pre>
(!?) :: ShortByteString -> Int -> Maybe Word16

-- | <i>O(n)</i> The <a>elemIndex</a> function returns the index of the
--   first element in the given <a>ShortByteString</a> which is equal to
--   the query element, or <a>Nothing</a> if there is no such element.
elemIndex :: Word16 -> ShortByteString -> Maybe Int

-- | <i>O(n)</i> The <a>elemIndices</a> function extends <a>elemIndex</a>,
--   by returning the indices of all elements equal to the query element,
--   in ascending order.
elemIndices :: Word16 -> ShortByteString -> [Int]

-- | count returns the number of times its argument appears in the
--   ShortByteString
count :: Word16 -> ShortByteString -> Int

-- | <i>O(n)</i> The <a>findIndex</a> function takes a predicate and a
--   <a>ShortByteString</a> and returns the index of the first element in
--   the ByteString satisfying the predicate.
findIndex :: (Word16 -> Bool) -> ShortByteString -> Maybe Int

-- | <i>O(n)</i> The <a>findIndices</a> function extends <a>findIndex</a>,
--   by returning the indices of all elements satisfying the predicate, in
--   ascending order.
findIndices :: (Word16 -> Bool) -> ShortByteString -> [Int]

-- | <i>O(n).</i> Construct a new <tt>ShortByteString</tt> from a
--   <tt>CWString</tt>. The resulting <tt>ShortByteString</tt> is an
--   immutable copy of the original <tt>CWString</tt>, and is managed on
--   the Haskell heap. The original <tt>CWString</tt> must be null
--   terminated.
packCWString :: Ptr Word16 -> IO ShortByteString

-- | <i>O(n).</i> Construct a new <tt>ShortByteString</tt> from a
--   <tt>CWStringLen</tt>. The resulting <tt>ShortByteString</tt> is an
--   immutable copy of the original <tt>CWStringLen</tt>. The
--   <tt>ShortByteString</tt> is a normal Haskell value and will be managed
--   on the Haskell heap.
packCWStringLen :: (Ptr Word16, Int) -> IO ShortByteString

-- | <i>O(n) construction.</i> Use a <tt>ShortByteString</tt> with a
--   function requiring a <tt>CWStringLen</tt>. As for
--   <tt>useAsCWString</tt> this function makes a copy of the original
--   <tt>ShortByteString</tt>. It must not be stored or used after the
--   subcomputation finishes.
newCWString :: ShortByteString -> IO (Ptr Word16)

-- | <i>O(n) construction.</i> Use a <tt>ShortByteString</tt> with a
--   function requiring a null-terminated <tt>CWString</tt>. The
--   <tt>CWString</tt> is a copy and will be freed automatically; it must
--   not be stored or used after the subcomputation finishes.
useAsCWString :: ShortByteString -> (Ptr Word16 -> IO a) -> IO a

-- | <i>O(n) construction.</i> Use a <tt>ShortByteString</tt> with a
--   function requiring a <tt>CWStringLen</tt>. As for
--   <tt>useAsCWString</tt> this function makes a copy of the original
--   <tt>ShortByteString</tt>. It must not be stored or used after the
--   subcomputation finishes.
useAsCWStringLen :: ShortByteString -> ((Ptr Word16, Int) -> IO a) -> IO a


-- | <i>Deprecated: Use System.OsString.Encoding.Internal from os-string
--   &gt;= 2.0.0 package instead. This module will be removed in filepath
--   &gt;= 1.5.</i>
module System.OsPath.Encoding.Internal
ucs2le :: TextEncoding
mkUcs2le :: CodingFailureMode -> TextEncoding
ucs2le_DF :: CodingFailureMode -> IO (TextDecoder ())
ucs2le_EF :: CodingFailureMode -> IO (TextEncoder ())
ucs2le_decode :: DecodeBuffer
ucs2le_encode :: EncodeBuffer

-- | Mimics the base encoding for filesystem operations. This should be
--   total on all inputs (word16 byte arrays).
--   
--   Note that this has a subtle difference to
--   <a>encodeWithBaseWindows</a>/<a>decodeWithBaseWindows</a>: it doesn't
--   care for the <tt>0x0000</tt> end marker and will as such produce
--   different results. Use <tt>takeWhile (/= 'NUL')</tt> on the input to
--   recover this behavior.
utf16le_b :: TextEncoding
mkUTF16le_b :: CodingFailureMode -> TextEncoding
utf16le_b_DF :: CodingFailureMode -> IO (TextDecoder ())
utf16le_b_EF :: CodingFailureMode -> IO (TextEncoder ())
utf16le_b_decode :: DecodeBuffer
utf16le_b_encode :: EncodeBuffer
cWcharsToChars_UCS2 :: [Word16] -> [Char]
cWcharsToChars :: [Word16] -> [Char]
charsToCWchars :: [Char] -> [Word16]
withFilePathWin :: FilePath -> (Int -> Ptr Word16 -> IO a) -> IO a
peekFilePathWin :: (Ptr Word16, Int) -> IO FilePath
withFilePathPosix :: FilePath -> (CStringLen -> IO a) -> IO a
peekFilePathPosix :: CStringLen -> IO FilePath

-- | Decode with the given <a>TextEncoding</a>.
decodeWithTE :: TextEncoding -> ShortByteString -> Either EncodingException String

-- | Encode with the given <a>TextEncoding</a>.
encodeWithTE :: TextEncoding -> String -> Either EncodingException ShortByteString

-- | This mimics the filepath decoder base uses on unix, with the small
--   distinction that we're not truncating at NUL bytes (because we're not
--   at the outer FFI layer).
decodeWithBasePosix :: ShortByteString -> IO String

-- | This mimics the filepath dencoder base uses on unix, with the small
--   distinction that we're not truncating at NUL bytes (because we're not
--   at the outer FFI layer).
encodeWithBasePosix :: String -> IO ShortByteString

-- | This mimics the filepath decoder base uses on windows, with the small
--   distinction that we're not truncating at NUL bytes (because we're not
--   at the outer FFI layer).
decodeWithBaseWindows :: ShortByteString -> IO String

-- | This mimics the filepath dencoder base uses on windows, with the small
--   distinction that we're not truncating at NUL bytes (because we're not
--   at the outer FFI layer).
encodeWithBaseWindows :: String -> IO ShortByteString
data EncodingException

-- | Could not decode a byte sequence because it was invalid under the
--   given encoding, or ran out of input in mid-decode.
EncodingError :: String -> Maybe Word8 -> EncodingException
showEncodingException :: EncodingException -> String
wNUL :: Word16

module System.OsPath.Encoding
data EncodingException

-- | Could not decode a byte sequence because it was invalid under the
--   given encoding, or ran out of input in mid-decode.
EncodingError :: String -> Maybe Word8 -> EncodingException
showEncodingException :: EncodingException -> String
ucs2le :: TextEncoding
mkUcs2le :: CodingFailureMode -> TextEncoding
ucs2le_DF :: CodingFailureMode -> IO (TextDecoder ())
ucs2le_EF :: CodingFailureMode -> IO (TextEncoder ())
ucs2le_decode :: DecodeBuffer
ucs2le_encode :: EncodeBuffer

-- | Mimics the base encoding for filesystem operations. This should be
--   total on all inputs (word16 byte arrays).
--   
--   Note that this has a subtle difference to
--   <a>encodeWithBaseWindows</a>/<a>decodeWithBaseWindows</a>: it doesn't
--   care for the <tt>0x0000</tt> end marker and will as such produce
--   different results. Use <tt>takeWhile (/= 'NUL')</tt> on the input to
--   recover this behavior.
utf16le_b :: TextEncoding
mkUTF16le_b :: CodingFailureMode -> TextEncoding
utf16le_b_DF :: CodingFailureMode -> IO (TextDecoder ())
utf16le_b_EF :: CodingFailureMode -> IO (TextEncoder ())
utf16le_b_decode :: DecodeBuffer
utf16le_b_encode :: EncodeBuffer

-- | This mimics the filepath dencoder base uses on unix, with the small
--   distinction that we're not truncating at NUL bytes (because we're not
--   at the outer FFI layer).
encodeWithBasePosix :: String -> IO ShortByteString

-- | This mimics the filepath decoder base uses on unix, with the small
--   distinction that we're not truncating at NUL bytes (because we're not
--   at the outer FFI layer).
decodeWithBasePosix :: ShortByteString -> IO String

-- | This mimics the filepath dencoder base uses on windows, with the small
--   distinction that we're not truncating at NUL bytes (because we're not
--   at the outer FFI layer).
encodeWithBaseWindows :: String -> IO ShortByteString

-- | This mimics the filepath decoder base uses on windows, with the small
--   distinction that we're not truncating at NUL bytes (because we're not
--   at the outer FFI layer).
decodeWithBaseWindows :: ShortByteString -> IO String


-- | A library for <tt>FilePath</tt> manipulations, using Posix style paths
--   on all platforms. Importing <a>System.FilePath</a> is usually better.
--   
--   Given the example <tt>FilePath</tt>: <tt>/directory/file.ext</tt>
--   
--   We can use the following functions to extract pieces.
--   
--   <ul>
--   <li><a>takeFileName</a> gives <tt>"file.ext"</tt></li>
--   <li><a>takeDirectory</a> gives <tt>"/directory"</tt></li>
--   <li><a>takeExtension</a> gives <tt>".ext"</tt></li>
--   <li><a>dropExtension</a> gives <tt>"/directory/file"</tt></li>
--   <li><a>takeBaseName</a> gives <tt>"file"</tt></li>
--   </ul>
--   
--   And we could have built an equivalent path with the following
--   expressions:
--   
--   <ul>
--   <li><tt>"/directory" <a>&lt;/&gt;</a> "file.ext"</tt>.</li>
--   <li><tt>"/directory/file" <a>&lt;.&gt;</a> "ext"</tt>.</li>
--   <li><tt>"/directory/file.txt" <a>-&lt;.&gt;</a> "ext"</tt>.</li>
--   </ul>
--   
--   Each function in this module is documented with several examples,
--   which are also used as tests.
--   
--   Here are a few examples of using the <tt>filepath</tt> functions
--   together:
--   
--   <i>Example 1:</i> Find the possible locations of a Haskell module
--   <tt>Test</tt> imported from module <tt>Main</tt>:
--   
--   <pre>
--   [<a>replaceFileName</a> path_to_main "Test" <a>&lt;.&gt;</a> ext | ext &lt;- ["hs","lhs"] ]
--   </pre>
--   
--   <i>Example 2:</i> Download a file from <tt>url</tt> and save it to
--   disk:
--   
--   <pre>
--   do let file = <a>makeValid</a> url
--      System.Directory.createDirectoryIfMissing True (<a>takeDirectory</a> file)
--   </pre>
--   
--   <i>Example 3:</i> Compile a Haskell file, putting the <tt>.hi</tt>
--   file under <tt>interface</tt>:
--   
--   <pre>
--   <a>takeDirectory</a> file <a>&lt;/&gt;</a> "interface" <a>&lt;/&gt;</a> (<a>takeFileName</a> file <a>-&lt;.&gt;</a> "hi")
--   </pre>
--   
--   References: [1] <a>Naming Files, Paths and Namespaces</a> (Microsoft
--   MSDN)
module System.OsPath.Posix.Internal

-- | The character that separates directories. In the case where more than
--   one character is possible, <a>pathSeparator</a> is the 'ideal' one.
--   
--   <pre>
--   Windows: pathSeparator == '\\'
--   Posix:   pathSeparator ==  '/'
--   isPathSeparator pathSeparator
--   </pre>
pathSeparator :: Word8

-- | The list of all possible separators.
--   
--   <pre>
--   Windows: pathSeparators == ['\\', '/']
--   Posix:   pathSeparators == ['/']
--   pathSeparator `elem` pathSeparators
--   </pre>
pathSeparators :: [Word8]

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

-- | The character that is used to separate the entries in the $PATH
--   environment variable.
--   
--   <pre>
--   Windows: searchPathSeparator == ';'
--   Posix:   searchPathSeparator == ':'
--   </pre>
searchPathSeparator :: Word8

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

-- | File extension character
--   
--   <pre>
--   extSeparator == '.'
--   </pre>
extSeparator :: Word8

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

-- | Take a string, split it on the <a>searchPathSeparator</a> character.
--   Blank items are ignored on Windows, and converted to <tt>.</tt> on
--   Posix. On Windows path elements are stripped of quotes.
--   
--   Follows the recommendations in
--   <a>http://www.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap08.html</a>
--   
--   <pre>
--   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"]
--   </pre>
splitSearchPath :: ShortByteString -> [ShortByteString]

-- | Split on the extension. <a>addExtension</a> is the inverse.
--   
--   <pre>
--   splitExtension "/directory/path.ext" == ("/directory/path",".ext")
--   uncurry (&lt;&gt;) (splitExtension x) == x
--   Valid x =&gt; 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/","")
--   </pre>
splitExtension :: ShortByteString -> (ShortByteString, ShortByteString)

-- | Get the extension of a file, returns <tt>""</tt> for no extension,
--   <tt>.ext</tt> otherwise.
--   
--   <pre>
--   takeExtension "/directory/path.ext" == ".ext"
--   takeExtension x == snd (splitExtension x)
--   Valid x =&gt; takeExtension (addExtension x "ext") == ".ext"
--   Valid x =&gt; takeExtension (replaceExtension x "ext") == ".ext"
--   </pre>
takeExtension :: ShortByteString -> ShortByteString

-- | Set the extension of a file, overwriting one if already present,
--   equivalent to <a>-&lt;.&gt;</a>.
--   
--   <pre>
--   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
--   </pre>
replaceExtension :: ShortByteString -> ShortByteString -> ShortByteString

-- | Remove the current extension and add another, equivalent to
--   <a>replaceExtension</a>.
--   
--   <pre>
--   "/directory/path.txt" -&lt;.&gt; "ext" == "/directory/path.ext"
--   "/directory/path.txt" -&lt;.&gt; ".ext" == "/directory/path.ext"
--   "foo.o" -&lt;.&gt; "c" == "foo.c"
--   </pre>
(-<.>) :: ShortByteString -> ShortByteString -> ShortByteString
infixr 7 -<.>

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

-- | Add an extension, even if there is already one there, equivalent to
--   <a>&lt;.&gt;</a>.
--   
--   <pre>
--   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 =&gt; takeFileName (addExtension (addTrailingPathSeparator x) "ext") == ".ext"
--   Windows: addExtension "\\\\share" ".txt" == "\\\\share\\.txt"
--   </pre>
addExtension :: ShortByteString -> ShortByteString -> ShortByteString

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

-- | Add an extension, even if there is already one there, equivalent to
--   <a>addExtension</a>.
--   
--   <pre>
--   "/directory/path" &lt;.&gt; "ext" == "/directory/path.ext"
--   "/directory/path" &lt;.&gt; ".ext" == "/directory/path.ext"
--   </pre>
(<.>) :: ShortByteString -> ShortByteString -> ShortByteString
infixr 7 <.>

-- | Split on all extensions.
--   
--   <pre>
--   splitExtensions "/directory/path.ext" == ("/directory/path",".ext")
--   splitExtensions "file.tar.gz" == ("file",".tar.gz")
--   uncurry (&lt;&gt;) (splitExtensions x) == x
--   Valid x =&gt; uncurry addExtension (splitExtensions x) == x
--   splitExtensions "file.tar.gz" == ("file",".tar.gz")
--   </pre>
splitExtensions :: ShortByteString -> (ShortByteString, ShortByteString)

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

-- | Get all extensions.
--   
--   <pre>
--   takeExtensions "/directory/path.ext" == ".ext"
--   takeExtensions "file.tar.gz" == ".tar.gz"
--   </pre>
takeExtensions :: ShortByteString -> ShortByteString

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

-- | Does the given filename have the specified extension?
--   
--   <pre>
--   "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
--   </pre>
isExtensionOf :: ShortByteString -> ShortByteString -> Bool

-- | Drop the given extension from a ShortByteString, and the <tt>"."</tt>
--   preceding it. Returns <a>Nothing</a> if the ShortByteString does not
--   have the given extension, or <a>Just</a> and the part before the
--   extension if it does.
--   
--   This function can be more predictable than <a>dropExtensions</a>,
--   especially if the filename might itself contain <tt>.</tt> characters.
--   
--   <pre>
--   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
--   </pre>
stripExtension :: ShortByteString -> ShortByteString -> Maybe ShortByteString

-- | Split a filename into directory and file. <a>&lt;/&gt;</a> is the
--   inverse. The first component will often end with a trailing slash.
--   
--   <pre>
--   splitFileName "/directory/file.ext" == ("/directory/","file.ext")
--   Valid x =&gt; uncurry (&lt;/&gt;) (splitFileName x) == x || fst (splitFileName x) == "./"
--   Valid x =&gt; isValid (fst (splitFileName x))
--   splitFileName "file/bob.txt" == ("file/", "bob.txt")
--   splitFileName "file/" == ("file/", "")
--   splitFileName "bob" == ("./", "bob")
--   Posix:   splitFileName "/" == ("/","")
--   Windows: splitFileName "c:" == ("c:","")
--   Windows: splitFileName "\\\\?\\A:\\fred" == ("\\\\?\\A:\\","fred")
--   Windows: splitFileName "\\\\?\\A:" == ("\\\\?\\A:","")
--   </pre>
splitFileName :: ShortByteString -> (ShortByteString, ShortByteString)

-- | Get the file name.
--   
--   <pre>
--   takeFileName "/directory/file.ext" == "file.ext"
--   takeFileName "test/" == ""
--   isSuffixOf (takeFileName x) x
--   takeFileName x == snd (splitFileName x)
--   Valid x =&gt; takeFileName (replaceFileName x "fred") == "fred"
--   Valid x =&gt; takeFileName (x &lt;/&gt; "fred") == "fred"
--   Valid x =&gt; isRelative (takeFileName x)
--   </pre>
takeFileName :: ShortByteString -> ShortByteString

-- | Set the filename.
--   
--   <pre>
--   replaceFileName "/directory/other.txt" "file.ext" == "/directory/file.ext"
--   Valid x =&gt; replaceFileName x (takeFileName x) == x
--   </pre>
replaceFileName :: ShortByteString -> ShortByteString -> ShortByteString

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

-- | Get the base name, without an extension or path.
--   
--   <pre>
--   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"
--   </pre>
takeBaseName :: ShortByteString -> ShortByteString

-- | Set the base name.
--   
--   <pre>
--   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 =&gt; replaceBaseName x (takeBaseName x) == x
--   </pre>
replaceBaseName :: ShortByteString -> ShortByteString -> ShortByteString

-- | Get the directory name, move up one level.
--   
--   <pre>
--             takeDirectory "/directory/other.ext" == "/directory"
--             isPrefixOf (takeDirectory x) 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:\\"
--   </pre>
takeDirectory :: ShortByteString -> ShortByteString

-- | Set the directory, keeping the filename the same.
--   
--   <pre>
--   replaceDirectory "root/file.ext" "/directory/" == "/directory/file.ext"
--   Valid x =&gt; replaceDirectory x (takeDirectory x) `equalFilePath` x
--   </pre>
replaceDirectory :: ShortByteString -> ShortByteString -> ShortByteString

-- | An alias for <a>&lt;/&gt;</a>.
combine :: ShortByteString -> ShortByteString -> ShortByteString

-- | 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 <tt>readFile (dir <a>&lt;/&gt;</a> file)</tt>
--   will access the same file as <tt>setCurrentDirectory dir; readFile
--   file</tt>.
--   
--   <pre>
--   Posix:   "/directory" &lt;/&gt; "file.ext" == "/directory/file.ext"
--   Windows: "/directory" &lt;/&gt; "file.ext" == "/directory\\file.ext"
--            "directory" &lt;/&gt; "/file.ext" == "/file.ext"
--   Valid x =&gt; (takeDirectory x &lt;/&gt; takeFileName x) `equalFilePath` x
--   </pre>
--   
--   Combined:
--   
--   <pre>
--   Posix:   "/" &lt;/&gt; "test" == "/test"
--   Posix:   "home" &lt;/&gt; "bob" == "home/bob"
--   Posix:   "x:" &lt;/&gt; "foo" == "x:/foo"
--   Windows: "C:\\foo" &lt;/&gt; "bar" == "C:\\foo\\bar"
--   Windows: "home" &lt;/&gt; "bob" == "home\\bob"
--   </pre>
--   
--   Not combined:
--   
--   <pre>
--   Posix:   "home" &lt;/&gt; "/bob" == "/bob"
--   Windows: "home" &lt;/&gt; "C:\\bob" == "C:\\bob"
--   </pre>
--   
--   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
--   <a>&lt;/&gt;</a> is to never combine these forms.
--   
--   <pre>
--   Windows: "home" &lt;/&gt; "/bob" == "/bob"
--   Windows: "home" &lt;/&gt; "\\bob" == "\\bob"
--   Windows: "C:\\home" &lt;/&gt; "\\bob" == "\\bob"
--   </pre>
--   
--   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 <a>&lt;/&gt;</a> is to
--   never combine these forms.
--   
--   <pre>
--   Windows: "D:\\foo" &lt;/&gt; "C:bar" == "C:bar"
--   Windows: "C:\\foo" &lt;/&gt; "C:bar" == "C:bar"
--   </pre>
(</>) :: ShortByteString -> ShortByteString -> ShortByteString
infixr 5 </>

-- | Split a path by the directory separator.
--   
--   <pre>
--   splitPath "/directory/file.ext" == ["/","directory/","file.ext"]
--   concat (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"]
--   </pre>
splitPath :: ShortByteString -> [ShortByteString]

-- | Join path elements back together.
--   
--   <pre>
--   joinPath z == foldr (&lt;/&gt;) "" z
--   joinPath ["/","directory/","file.ext"] == "/directory/file.ext"
--   Valid x =&gt; joinPath (splitPath x) == x
--   joinPath [] == ""
--   Posix: joinPath ["test","file","path"] == "test/file/path"
--   </pre>
joinPath :: [ShortByteString] -> ShortByteString

-- | Just as <a>splitPath</a>, but don't add the trailing slashes to each
--   element.
--   
--   <pre>
--            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 =&gt; joinPath (splitDirectories x) `equalFilePath` x
--            splitDirectories "" == []
--   Windows: splitDirectories "C:\\test\\\\\\file" == ["C:\\", "test", "file"]
--            splitDirectories "/test///file" == ["/","test","file"]
--   </pre>
splitDirectories :: ShortByteString -> [ShortByteString]

-- | Split a path into a drive and a path. On Posix, / is a Drive.
--   
--   <pre>
--   uncurry (&lt;&gt;) (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")
--   </pre>
splitDrive :: ShortByteString -> (ShortByteString, ShortByteString)

-- | Join a drive and the rest of the path.
--   
--   <pre>
--   Valid x =&gt; 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"
--   </pre>
joinDrive :: ShortByteString -> ShortByteString -> ShortByteString

-- | Get the drive from a filepath.
--   
--   <pre>
--   takeDrive x == fst (splitDrive x)
--   </pre>
takeDrive :: ShortByteString -> ShortByteString

-- | Does a path have a drive.
--   
--   <pre>
--   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
--   </pre>
hasDrive :: ShortByteString -> Bool

-- | Delete the drive, if it exists.
--   
--   <pre>
--   dropDrive x == snd (splitDrive x)
--   </pre>
dropDrive :: ShortByteString -> ShortByteString

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

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

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

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

-- | Normalise a file
--   
--   <ul>
--   <li>// outside of the drive can be made blank</li>
--   <li>/ -&gt; <a>pathSeparator</a></li>
--   <li>./ -&gt; ""</li>
--   </ul>
--   
--   Does not remove <tt>".."</tt>, because of symlinks.
--   
--   <pre>
--   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 "/a/../c" == "/a/../c"
--   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"
--   </pre>
normalise :: ShortByteString -> ShortByteString

-- | Equality of two <tt>FILEPATH</tt>s. If you call
--   <tt>System.Directory.canonicalizePath</tt> first this has a much
--   better chance of working. Note that this doesn't follow symlinks or
--   DOSNAM~1s.
--   
--   Similar to <a>normalise</a>, this does not expand <tt>".."</tt>,
--   because of symlinks.
--   
--   <pre>
--            x == y ==&gt; equalFilePath x y
--            normalise x == normalise y ==&gt; equalFilePath x y
--            equalFilePath "foo" "foo/"
--            not (equalFilePath "/a/../c" "/c")
--            not (equalFilePath "foo" "/foo")
--   Posix:   not (equalFilePath "foo" "FOO")
--   Windows: equalFilePath "foo" "FOO"
--   Windows: not (equalFilePath "C:" "C:/")
--   </pre>
equalFilePath :: ShortByteString -> ShortByteString -> Bool

-- | Contract a filename, based on a relative path. Note that the resulting
--   path will never introduce <tt>..</tt> paths, as the presence of
--   symlinks means <tt>../b</tt> may not reach <tt>a/b</tt> if it starts
--   from <tt>a/c</tt>. For a worked example see <a>this blog post</a>.
--   
--   The corresponding <tt>makeAbsolute</tt> function can be found in
--   <tt>System.Directory</tt>.
--   
--   <pre>
--            makeRelative "/directory" "/directory/file.ext" == "file.ext"
--            Valid x =&gt; makeRelative (takeDirectory x) x `equalFilePath` takeFileName x
--            makeRelative x x == "."
--            Valid x y =&gt; equalFilePath x y || (isRelative x &amp;&amp; makeRelative y x == x) || equalFilePath (y &lt;/&gt; 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"
--   </pre>
makeRelative :: ShortByteString -> ShortByteString -> ShortByteString

-- | Is a path relative, or is it fixed to the root?
--   
--   <pre>
--   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
--   </pre>
--   
--   According to [1]:
--   
--   <ul>
--   <li>"A UNC name of any format [is never relative]."</li>
--   <li>"You cannot use the "\?" prefix with a relative path."</li>
--   </ul>
isRelative :: ShortByteString -> Bool

-- | <pre>
--   not . <a>isRelative</a>
--   </pre>
--   
--   <pre>
--   isAbsolute x == not (isRelative x)
--   </pre>
isAbsolute :: ShortByteString -> Bool

-- | Is a ShortByteString 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.
--   
--   <pre>
--            isValid "" == False
--            isValid "\0" == False
--   Posix:   isValid "/random_ path:*" == True
--   Posix:   isValid x == not (null x)
--   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
--   </pre>
isValid :: ShortByteString -> Bool

-- | Take a ShortByteString and make it valid; does not change already
--   valid FILEPATHs.
--   
--   <pre>
--   isValid (makeValid x)
--   isValid x ==&gt; 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"
--   </pre>
makeValid :: ShortByteString -> ShortByteString


-- | A library for <tt>FilePath</tt> manipulations, using Windows style
--   paths on all platforms. Importing <a>System.FilePath</a> is usually
--   better.
--   
--   Given the example <tt>FilePath</tt>: <tt>/directory/file.ext</tt>
--   
--   We can use the following functions to extract pieces.
--   
--   <ul>
--   <li><a>takeFileName</a> gives <tt>"file.ext"</tt></li>
--   <li><a>takeDirectory</a> gives <tt>"/directory"</tt></li>
--   <li><a>takeExtension</a> gives <tt>".ext"</tt></li>
--   <li><a>dropExtension</a> gives <tt>"/directory/file"</tt></li>
--   <li><a>takeBaseName</a> gives <tt>"file"</tt></li>
--   </ul>
--   
--   And we could have built an equivalent path with the following
--   expressions:
--   
--   <ul>
--   <li><tt>"/directory" <a>&lt;/&gt;</a> "file.ext"</tt>.</li>
--   <li><tt>"/directory/file" <a>&lt;.&gt;</a> "ext"</tt>.</li>
--   <li><tt>"/directory/file.txt" <a>-&lt;.&gt;</a> "ext"</tt>.</li>
--   </ul>
--   
--   Each function in this module is documented with several examples,
--   which are also used as tests.
--   
--   Here are a few examples of using the <tt>filepath</tt> functions
--   together:
--   
--   <i>Example 1:</i> Find the possible locations of a Haskell module
--   <tt>Test</tt> imported from module <tt>Main</tt>:
--   
--   <pre>
--   [<a>replaceFileName</a> path_to_main "Test" <a>&lt;.&gt;</a> ext | ext &lt;- ["hs","lhs"] ]
--   </pre>
--   
--   <i>Example 2:</i> Download a file from <tt>url</tt> and save it to
--   disk:
--   
--   <pre>
--   do let file = <a>makeValid</a> url
--      System.Directory.createDirectoryIfMissing True (<a>takeDirectory</a> file)
--   </pre>
--   
--   <i>Example 3:</i> Compile a Haskell file, putting the <tt>.hi</tt>
--   file under <tt>interface</tt>:
--   
--   <pre>
--   <a>takeDirectory</a> file <a>&lt;/&gt;</a> "interface" <a>&lt;/&gt;</a> (<a>takeFileName</a> file <a>-&lt;.&gt;</a> "hi")
--   </pre>
--   
--   References: [1] <a>Naming Files, Paths and Namespaces</a> (Microsoft
--   MSDN)
module System.OsPath.Windows.Internal

-- | The character that separates directories. In the case where more than
--   one character is possible, <a>pathSeparator</a> is the 'ideal' one.
--   
--   <pre>
--   Windows: pathSeparator == '\\'
--   Posix:   pathSeparator ==  '/'
--   isPathSeparator pathSeparator
--   </pre>
pathSeparator :: Word16

-- | The list of all possible separators.
--   
--   <pre>
--   Windows: pathSeparators == ['\\', '/']
--   Posix:   pathSeparators == ['/']
--   pathSeparator `elem` pathSeparators
--   </pre>
pathSeparators :: [Word16]

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

-- | The character that is used to separate the entries in the $PATH
--   environment variable.
--   
--   <pre>
--   Windows: searchPathSeparator == ';'
--   Posix:   searchPathSeparator == ':'
--   </pre>
searchPathSeparator :: Word16

-- | Is the character a file separator?
--   
--   <pre>
--   isSearchPathSeparator a == (a == searchPathSeparator)
--   </pre>
isSearchPathSeparator :: Word16 -> Bool

-- | File extension character
--   
--   <pre>
--   extSeparator == '.'
--   </pre>
extSeparator :: Word16

-- | Is the character an extension character?
--   
--   <pre>
--   isExtSeparator a == (a == extSeparator)
--   </pre>
isExtSeparator :: Word16 -> Bool

-- | Take a string, split it on the <a>searchPathSeparator</a> character.
--   Blank items are ignored on Windows, and converted to <tt>.</tt> on
--   Posix. On Windows path elements are stripped of quotes.
--   
--   Follows the recommendations in
--   <a>http://www.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap08.html</a>
--   
--   <pre>
--   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"]
--   </pre>
splitSearchPath :: ShortByteString -> [ShortByteString]

-- | Split on the extension. <a>addExtension</a> is the inverse.
--   
--   <pre>
--   splitExtension "/directory/path.ext" == ("/directory/path",".ext")
--   uncurry (&lt;&gt;) (splitExtension x) == x
--   Valid x =&gt; 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/","")
--   </pre>
splitExtension :: ShortByteString -> (ShortByteString, ShortByteString)

-- | Get the extension of a file, returns <tt>""</tt> for no extension,
--   <tt>.ext</tt> otherwise.
--   
--   <pre>
--   takeExtension "/directory/path.ext" == ".ext"
--   takeExtension x == snd (splitExtension x)
--   Valid x =&gt; takeExtension (addExtension x "ext") == ".ext"
--   Valid x =&gt; takeExtension (replaceExtension x "ext") == ".ext"
--   </pre>
takeExtension :: ShortByteString -> ShortByteString

-- | Set the extension of a file, overwriting one if already present,
--   equivalent to <a>-&lt;.&gt;</a>.
--   
--   <pre>
--   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
--   </pre>
replaceExtension :: ShortByteString -> ShortByteString -> ShortByteString

-- | Remove the current extension and add another, equivalent to
--   <a>replaceExtension</a>.
--   
--   <pre>
--   "/directory/path.txt" -&lt;.&gt; "ext" == "/directory/path.ext"
--   "/directory/path.txt" -&lt;.&gt; ".ext" == "/directory/path.ext"
--   "foo.o" -&lt;.&gt; "c" == "foo.c"
--   </pre>
(-<.>) :: ShortByteString -> ShortByteString -> ShortByteString
infixr 7 -<.>

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

-- | Add an extension, even if there is already one there, equivalent to
--   <a>&lt;.&gt;</a>.
--   
--   <pre>
--   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 =&gt; takeFileName (addExtension (addTrailingPathSeparator x) "ext") == ".ext"
--   Windows: addExtension "\\\\share" ".txt" == "\\\\share\\.txt"
--   </pre>
addExtension :: ShortByteString -> ShortByteString -> ShortByteString

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

-- | Add an extension, even if there is already one there, equivalent to
--   <a>addExtension</a>.
--   
--   <pre>
--   "/directory/path" &lt;.&gt; "ext" == "/directory/path.ext"
--   "/directory/path" &lt;.&gt; ".ext" == "/directory/path.ext"
--   </pre>
(<.>) :: ShortByteString -> ShortByteString -> ShortByteString
infixr 7 <.>

-- | Split on all extensions.
--   
--   <pre>
--   splitExtensions "/directory/path.ext" == ("/directory/path",".ext")
--   splitExtensions "file.tar.gz" == ("file",".tar.gz")
--   uncurry (&lt;&gt;) (splitExtensions x) == x
--   Valid x =&gt; uncurry addExtension (splitExtensions x) == x
--   splitExtensions "file.tar.gz" == ("file",".tar.gz")
--   </pre>
splitExtensions :: ShortByteString -> (ShortByteString, ShortByteString)

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

-- | Get all extensions.
--   
--   <pre>
--   takeExtensions "/directory/path.ext" == ".ext"
--   takeExtensions "file.tar.gz" == ".tar.gz"
--   </pre>
takeExtensions :: ShortByteString -> ShortByteString

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

-- | Does the given filename have the specified extension?
--   
--   <pre>
--   "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
--   </pre>
isExtensionOf :: ShortByteString -> ShortByteString -> Bool

-- | Drop the given extension from a ShortByteString, and the <tt>"."</tt>
--   preceding it. Returns <a>Nothing</a> if the ShortByteString does not
--   have the given extension, or <a>Just</a> and the part before the
--   extension if it does.
--   
--   This function can be more predictable than <a>dropExtensions</a>,
--   especially if the filename might itself contain <tt>.</tt> characters.
--   
--   <pre>
--   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
--   </pre>
stripExtension :: ShortByteString -> ShortByteString -> Maybe ShortByteString

-- | Split a filename into directory and file. <a>&lt;/&gt;</a> is the
--   inverse. The first component will often end with a trailing slash.
--   
--   <pre>
--   splitFileName "/directory/file.ext" == ("/directory/","file.ext")
--   Valid x =&gt; uncurry (&lt;/&gt;) (splitFileName x) == x || fst (splitFileName x) == "./"
--   Valid x =&gt; isValid (fst (splitFileName x))
--   splitFileName "file/bob.txt" == ("file/", "bob.txt")
--   splitFileName "file/" == ("file/", "")
--   splitFileName "bob" == ("./", "bob")
--   Posix:   splitFileName "/" == ("/","")
--   Windows: splitFileName "c:" == ("c:","")
--   Windows: splitFileName "\\\\?\\A:\\fred" == ("\\\\?\\A:\\","fred")
--   Windows: splitFileName "\\\\?\\A:" == ("\\\\?\\A:","")
--   </pre>
splitFileName :: ShortByteString -> (ShortByteString, ShortByteString)

-- | Get the file name.
--   
--   <pre>
--   takeFileName "/directory/file.ext" == "file.ext"
--   takeFileName "test/" == ""
--   isSuffixOf (takeFileName x) x
--   takeFileName x == snd (splitFileName x)
--   Valid x =&gt; takeFileName (replaceFileName x "fred") == "fred"
--   Valid x =&gt; takeFileName (x &lt;/&gt; "fred") == "fred"
--   Valid x =&gt; isRelative (takeFileName x)
--   </pre>
takeFileName :: ShortByteString -> ShortByteString

-- | Set the filename.
--   
--   <pre>
--   replaceFileName "/directory/other.txt" "file.ext" == "/directory/file.ext"
--   Valid x =&gt; replaceFileName x (takeFileName x) == x
--   </pre>
replaceFileName :: ShortByteString -> ShortByteString -> ShortByteString

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

-- | Get the base name, without an extension or path.
--   
--   <pre>
--   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"
--   </pre>
takeBaseName :: ShortByteString -> ShortByteString

-- | Set the base name.
--   
--   <pre>
--   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 =&gt; replaceBaseName x (takeBaseName x) == x
--   </pre>
replaceBaseName :: ShortByteString -> ShortByteString -> ShortByteString

-- | Get the directory name, move up one level.
--   
--   <pre>
--             takeDirectory "/directory/other.ext" == "/directory"
--             isPrefixOf (takeDirectory x) 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:\\"
--   </pre>
takeDirectory :: ShortByteString -> ShortByteString

-- | Set the directory, keeping the filename the same.
--   
--   <pre>
--   replaceDirectory "root/file.ext" "/directory/" == "/directory/file.ext"
--   Valid x =&gt; replaceDirectory x (takeDirectory x) `equalFilePath` x
--   </pre>
replaceDirectory :: ShortByteString -> ShortByteString -> ShortByteString

-- | An alias for <a>&lt;/&gt;</a>.
combine :: ShortByteString -> ShortByteString -> ShortByteString

-- | 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 <tt>readFile (dir <a>&lt;/&gt;</a> file)</tt>
--   will access the same file as <tt>setCurrentDirectory dir; readFile
--   file</tt>.
--   
--   <pre>
--   Posix:   "/directory" &lt;/&gt; "file.ext" == "/directory/file.ext"
--   Windows: "/directory" &lt;/&gt; "file.ext" == "/directory\\file.ext"
--            "directory" &lt;/&gt; "/file.ext" == "/file.ext"
--   Valid x =&gt; (takeDirectory x &lt;/&gt; takeFileName x) `equalFilePath` x
--   </pre>
--   
--   Combined:
--   
--   <pre>
--   Posix:   "/" &lt;/&gt; "test" == "/test"
--   Posix:   "home" &lt;/&gt; "bob" == "home/bob"
--   Posix:   "x:" &lt;/&gt; "foo" == "x:/foo"
--   Windows: "C:\\foo" &lt;/&gt; "bar" == "C:\\foo\\bar"
--   Windows: "home" &lt;/&gt; "bob" == "home\\bob"
--   </pre>
--   
--   Not combined:
--   
--   <pre>
--   Posix:   "home" &lt;/&gt; "/bob" == "/bob"
--   Windows: "home" &lt;/&gt; "C:\\bob" == "C:\\bob"
--   </pre>
--   
--   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
--   <a>&lt;/&gt;</a> is to never combine these forms.
--   
--   <pre>
--   Windows: "home" &lt;/&gt; "/bob" == "/bob"
--   Windows: "home" &lt;/&gt; "\\bob" == "\\bob"
--   Windows: "C:\\home" &lt;/&gt; "\\bob" == "\\bob"
--   </pre>
--   
--   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 <a>&lt;/&gt;</a> is to
--   never combine these forms.
--   
--   <pre>
--   Windows: "D:\\foo" &lt;/&gt; "C:bar" == "C:bar"
--   Windows: "C:\\foo" &lt;/&gt; "C:bar" == "C:bar"
--   </pre>
(</>) :: ShortByteString -> ShortByteString -> ShortByteString
infixr 5 </>

-- | Split a path by the directory separator.
--   
--   <pre>
--   splitPath "/directory/file.ext" == ["/","directory/","file.ext"]
--   concat (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"]
--   </pre>
splitPath :: ShortByteString -> [ShortByteString]

-- | Join path elements back together.
--   
--   <pre>
--   joinPath z == foldr (&lt;/&gt;) "" z
--   joinPath ["/","directory/","file.ext"] == "/directory/file.ext"
--   Valid x =&gt; joinPath (splitPath x) == x
--   joinPath [] == ""
--   Posix: joinPath ["test","file","path"] == "test/file/path"
--   </pre>
joinPath :: [ShortByteString] -> ShortByteString

-- | Just as <a>splitPath</a>, but don't add the trailing slashes to each
--   element.
--   
--   <pre>
--            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 =&gt; joinPath (splitDirectories x) `equalFilePath` x
--            splitDirectories "" == []
--   Windows: splitDirectories "C:\\test\\\\\\file" == ["C:\\", "test", "file"]
--            splitDirectories "/test///file" == ["/","test","file"]
--   </pre>
splitDirectories :: ShortByteString -> [ShortByteString]

-- | Split a path into a drive and a path. On Posix, / is a Drive.
--   
--   <pre>
--   uncurry (&lt;&gt;) (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")
--   </pre>
splitDrive :: ShortByteString -> (ShortByteString, ShortByteString)

-- | Join a drive and the rest of the path.
--   
--   <pre>
--   Valid x =&gt; 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"
--   </pre>
joinDrive :: ShortByteString -> ShortByteString -> ShortByteString

-- | Get the drive from a filepath.
--   
--   <pre>
--   takeDrive x == fst (splitDrive x)
--   </pre>
takeDrive :: ShortByteString -> ShortByteString

-- | Does a path have a drive.
--   
--   <pre>
--   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
--   </pre>
hasDrive :: ShortByteString -> Bool

-- | Delete the drive, if it exists.
--   
--   <pre>
--   dropDrive x == snd (splitDrive x)
--   </pre>
dropDrive :: ShortByteString -> ShortByteString

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

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

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

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

-- | Normalise a file
--   
--   <ul>
--   <li>// outside of the drive can be made blank</li>
--   <li>/ -&gt; <a>pathSeparator</a></li>
--   <li>./ -&gt; ""</li>
--   </ul>
--   
--   Does not remove <tt>".."</tt>, because of symlinks.
--   
--   <pre>
--   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 "/a/../c" == "/a/../c"
--   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"
--   </pre>
normalise :: ShortByteString -> ShortByteString

-- | Equality of two <tt>FILEPATH</tt>s. If you call
--   <tt>System.Directory.canonicalizePath</tt> first this has a much
--   better chance of working. Note that this doesn't follow symlinks or
--   DOSNAM~1s.
--   
--   Similar to <a>normalise</a>, this does not expand <tt>".."</tt>,
--   because of symlinks.
--   
--   <pre>
--            x == y ==&gt; equalFilePath x y
--            normalise x == normalise y ==&gt; equalFilePath x y
--            equalFilePath "foo" "foo/"
--            not (equalFilePath "/a/../c" "/c")
--            not (equalFilePath "foo" "/foo")
--   Posix:   not (equalFilePath "foo" "FOO")
--   Windows: equalFilePath "foo" "FOO"
--   Windows: not (equalFilePath "C:" "C:/")
--   </pre>
equalFilePath :: ShortByteString -> ShortByteString -> Bool

-- | Contract a filename, based on a relative path. Note that the resulting
--   path will never introduce <tt>..</tt> paths, as the presence of
--   symlinks means <tt>../b</tt> may not reach <tt>a/b</tt> if it starts
--   from <tt>a/c</tt>. For a worked example see <a>this blog post</a>.
--   
--   The corresponding <tt>makeAbsolute</tt> function can be found in
--   <tt>System.Directory</tt>.
--   
--   <pre>
--            makeRelative "/directory" "/directory/file.ext" == "file.ext"
--            Valid x =&gt; makeRelative (takeDirectory x) x `equalFilePath` takeFileName x
--            makeRelative x x == "."
--            Valid x y =&gt; equalFilePath x y || (isRelative x &amp;&amp; makeRelative y x == x) || equalFilePath (y &lt;/&gt; 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"
--   </pre>
makeRelative :: ShortByteString -> ShortByteString -> ShortByteString

-- | Is a path relative, or is it fixed to the root?
--   
--   <pre>
--   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
--   </pre>
--   
--   According to [1]:
--   
--   <ul>
--   <li>"A UNC name of any format [is never relative]."</li>
--   <li>"You cannot use the "\?" prefix with a relative path."</li>
--   </ul>
isRelative :: ShortByteString -> Bool

-- | <pre>
--   not . <a>isRelative</a>
--   </pre>
--   
--   <pre>
--   isAbsolute x == not (isRelative x)
--   </pre>
isAbsolute :: ShortByteString -> Bool

-- | Is a ShortByteString 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.
--   
--   <pre>
--            isValid "" == False
--            isValid "\0" == False
--   Posix:   isValid "/random_ path:*" == True
--   Posix:   isValid x == not (null x)
--   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
--   </pre>
isValid :: ShortByteString -> Bool

-- | Take a ShortByteString and make it valid; does not change already
--   valid FILEPATHs.
--   
--   <pre>
--   isValid (makeValid x)
--   isValid x ==&gt; 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"
--   </pre>
makeValid :: ShortByteString -> ShortByteString


-- | <i>Deprecated: Use System.OsString.Internal.Types from os-string &gt;=
--   2.0.0 package instead. This module will be removed in filepath &gt;=
--   1.5.</i>
module System.OsString.Internal.Types

-- | Commonly used windows string as wide character bytes.
newtype WindowsString
WindowsString :: ShortByteString -> WindowsString
[getWindowsString] :: WindowsString -> ShortByteString

-- | Just a short bidirectional synonym for <a>WindowsString</a>
--   constructor.
pattern WS :: ShortByteString -> WindowsString
unWS :: WindowsString -> ShortByteString

-- | Commonly used Posix string as uninterpreted <tt>char[]</tt> array.
newtype PosixString
PosixString :: ShortByteString -> PosixString
[getPosixString] :: PosixString -> ShortByteString
unPS :: PosixString -> ShortByteString

-- | Just a short bidirectional synonym for <a>PosixString</a> constructor.
pattern PS :: ShortByteString -> PosixString
type PlatformString = PosixString
newtype WindowsChar
WindowsChar :: Word16 -> WindowsChar
[getWindowsChar] :: WindowsChar -> Word16
unWW :: WindowsChar -> Word16

-- | Just a short bidirectional synonym for <a>WindowsChar</a> constructor.
pattern WW :: Word16 -> WindowsChar
newtype PosixChar
PosixChar :: Word8 -> PosixChar
[getPosixChar] :: PosixChar -> Word8
unPW :: PosixChar -> Word8

-- | Just a short bidirectional synonym for <a>PosixChar</a> constructor.
pattern PW :: Word8 -> PosixChar
type PlatformChar = PosixChar

-- | Newtype representing short operating system specific strings.
--   
--   Internally this is either <a>WindowsString</a> or <a>PosixString</a>,
--   depending on the platform. Both use unpinned <tt>ShortByteString</tt>
--   for efficiency.
--   
--   The constructor is only exported via
--   <a>System.OsString.Internal.Types</a>, since dealing with the
--   internals isn't generally recommended, but supported in case you need
--   to write platform specific code.
newtype OsString
OsString :: PlatformString -> OsString
[getOsString] :: OsString -> PlatformString

-- | Newtype representing a code unit.
--   
--   On Windows, this is restricted to two-octet codepoints <a>Word16</a>,
--   on POSIX one-octet (<a>Word8</a>).
newtype OsChar
OsChar :: PlatformChar -> OsChar
[getOsChar] :: OsChar -> PlatformChar

module System.OsPath.Types

-- | Type representing filenames/pathnames.
--   
--   This type doesn't add any guarantees over <a>OsString</a>.
type OsPath = OsString

-- | Filepaths are <tt>wchar_t*</tt> data on windows as passed to syscalls.
type WindowsPath = WindowsString

-- | Filepaths are <tt>char[]</tt> data on unix as passed to syscalls.
type PosixPath = PosixString

-- | Ifdef around current platform (either <a>WindowsPath</a> or
--   <a>PosixPath</a>).
type PlatformPath = PosixPath

-- | Commonly used windows string as wide character bytes.
data WindowsString

-- | Commonly used Posix string as uninterpreted <tt>char[]</tt> array.
data PosixString
data WindowsChar
data PosixChar

-- | Newtype representing short operating system specific strings.
--   
--   Internally this is either <a>WindowsString</a> or <a>PosixString</a>,
--   depending on the platform. Both use unpinned <tt>ShortByteString</tt>
--   for efficiency.
--   
--   The constructor is only exported via
--   <a>System.OsString.Internal.Types</a>, since dealing with the
--   internals isn't generally recommended, but supported in case you need
--   to write platform specific code.
data OsString

-- | Newtype representing a code unit.
--   
--   On Windows, this is restricted to two-octet codepoints <a>Word16</a>,
--   on POSIX one-octet (<a>Word8</a>).
data OsChar


-- | <i>Deprecated: Use System.OsString.Posix from os-string &gt;= 2.0.0
--   package instead. This module will be removed in filepath &gt;=
--   1.5.</i>
module System.OsString.Posix

-- | Commonly used Posix string as uninterpreted <tt>char[]</tt> array.
data PosixString
data PosixChar

-- | Partial unicode friendly encoding.
--   
--   This encodes as UTF8 (strictly), which is a good guess.
--   
--   Throws an <a>EncodingException</a> if encoding fails.
encodeUtf :: MonadThrow m => String -> m PosixString

-- | Encode a <a>String</a> with the specified encoding.
encodeWith :: TextEncoding -> String -> Either EncodingException PosixString

-- | This mimics the behavior of the base library when doing filesystem
--   operations, which uses shady PEP 383 style encoding (based on the
--   current locale, but PEP 383 only works properly on UTF-8 encodings, so
--   good luck).
--   
--   Looking up the locale requires IO. If you're not worried about calls
--   to <tt>setFileSystemEncoding</tt>, then <a>unsafePerformIO</a> may be
--   feasible (make sure to deeply evaluate the result to catch
--   exceptions).
encodeFS :: String -> IO PosixString

-- | Constructs a platform string from a ByteString.
--   
--   This is a no-op.
fromBytes :: MonadThrow m => ByteString -> m PosixString

-- | QuasiQuote a <a>PosixString</a>. This accepts Unicode characters and
--   encodes as UTF-8 on unix.
pstr :: QuasiQuoter

-- | Pack a list of platform words to a platform string.
--   
--   Note that using this in conjunction with <a>unsafeFromChar</a> to
--   convert from <tt>[Char]</tt> to platform string is probably not what
--   you want, because it will truncate unicode code points.
pack :: [PosixChar] -> PosixString

-- | Partial unicode friendly decoding.
--   
--   This decodes as UTF8 (strictly), which is a good guess. Note that
--   filenames on unix are encoding agnostic char arrays.
--   
--   Throws a <a>EncodingException</a> if decoding fails.
decodeUtf :: MonadThrow m => PosixString -> m String

-- | Decode a <a>PosixString</a> with the specified encoding.
--   
--   The String is forced into memory to catch all exceptions.
decodeWith :: TextEncoding -> PosixString -> Either EncodingException String

-- | This mimics the behavior of the base library when doing filesystem
--   operations, which uses shady PEP 383 style encoding (based on the
--   current locale, but PEP 383 only works properly on UTF-8 encodings, so
--   good luck).
--   
--   Looking up the locale requires IO. If you're not worried about calls
--   to <tt>setFileSystemEncoding</tt>, then <a>unsafePerformIO</a> may be
--   feasible (make sure to deeply evaluate the result to catch
--   exceptions).
decodeFS :: PosixString -> IO String

-- | Unpack a platform string to a list of platform words.
unpack :: PosixString -> [PosixChar]

-- | Truncates to 1 octet.
unsafeFromChar :: Char -> PosixChar

-- | Converts back to a unicode codepoint (total).
toChar :: PosixChar -> Char


-- | <i>Deprecated: Use System.OsString.Internal from os-string &gt;= 2.0.0
--   package instead. This module will be removed in filepath &gt;=
--   1.5.</i>
module System.OsString.Internal

-- | Partial unicode friendly encoding.
--   
--   On windows this encodes as UTF16-LE (strictly), which is a pretty good
--   guess. On unix this encodes as UTF8 (strictly), which is a good guess.
--   
--   Throws a <a>EncodingException</a> if encoding fails.
encodeUtf :: MonadThrow m => String -> m OsString

-- | Encode an <a>OsString</a> given the platform specific encodings.
encodeWith :: TextEncoding -> TextEncoding -> String -> Either EncodingException OsString

-- | Like <a>encodeUtf</a>, except this mimics the behavior of the base
--   library when doing filesystem operations, which is:
--   
--   <ol>
--   <li>on unix, uses shady PEP 383 style encoding (based on the current
--   locale, but PEP 383 only works properly on UTF-8 encodings, so good
--   luck)</li>
--   <li>on windows does permissive UTF-16 encoding, where coding errors
--   generate Chars in the surrogate range</li>
--   </ol>
--   
--   Looking up the locale requires IO. If you're not worried about calls
--   to <tt>setFileSystemEncoding</tt>, then <tt>unsafePerformIO</tt> may
--   be feasible (make sure to deeply evaluate the result to catch
--   exceptions).
encodeFS :: String -> IO OsString

-- | Partial unicode friendly decoding.
--   
--   On windows this decodes as UTF16-LE (strictly), which is a pretty good
--   guess. On unix this decodes as UTF8 (strictly), which is a good guess.
--   Note that filenames on unix are encoding agnostic char arrays.
--   
--   Throws a <a>EncodingException</a> if decoding fails.
decodeUtf :: MonadThrow m => OsString -> m String

-- | Decode an <a>OsString</a> with the specified encoding.
--   
--   The String is forced into memory to catch all exceptions.
decodeWith :: TextEncoding -> TextEncoding -> OsString -> Either EncodingException String

-- | Like <a>decodeUtf</a>, except this mimics the behavior of the base
--   library when doing filesystem operations, which is:
--   
--   <ol>
--   <li>on unix, uses shady PEP 383 style encoding (based on the current
--   locale, but PEP 383 only works properly on UTF-8 encodings, so good
--   luck)</li>
--   <li>on windows does permissive UTF-16 encoding, where coding errors
--   generate Chars in the surrogate range</li>
--   </ol>
--   
--   Looking up the locale requires IO. If you're not worried about calls
--   to <tt>setFileSystemEncoding</tt>, then <tt>unsafePerformIO</tt> may
--   be feasible (make sure to deeply evaluate the result to catch
--   exceptions).
decodeFS :: OsString -> IO String

-- | Constructs an <tt>OsString</tt> from a ByteString.
--   
--   On windows, this ensures valid UCS-2LE, on unix it is passed
--   unchanged/unchecked.
--   
--   Throws <a>EncodingException</a> on invalid UCS-2LE on windows
--   (although unlikely).
fromBytes :: MonadThrow m => ByteString -> m OsString

-- | QuasiQuote an <a>OsString</a>. This accepts Unicode characters and
--   encodes as UTF-8 on unix and UTF-16 on windows.
osstr :: QuasiQuoter

-- | Unpack an <a>OsString</a> to a list of <a>OsChar</a>.
unpack :: OsString -> [OsChar]

-- | Pack a list of <a>OsChar</a> to an <a>OsString</a>
--   
--   Note that using this in conjunction with <a>unsafeFromChar</a> to
--   convert from <tt>[Char]</tt> to <a>OsString</a> is probably not what
--   you want, because it will truncate unicode code points.
pack :: [OsChar] -> OsString

-- | Truncates on unix to 1 and on Windows to 2 octets.
unsafeFromChar :: Char -> OsChar

-- | Converts back to a unicode codepoint (total).
toChar :: OsChar -> Char


-- | An implementation of platform specific short <a>OsString</a>, which
--   is:
--   
--   <ol>
--   <li>on windows wide char bytes (<tt>[Word16]</tt>)</li>
--   <li>on unix char bytes (<tt>[Word8]</tt>)</li>
--   </ol>
--   
--   It captures the notion of syscall specific encoding (or the lack
--   thereof) to avoid roundtrip issues and memory fragmentation by using
--   unpinned byte arrays. Bytes are not touched or interpreted.

-- | <i>Deprecated: Use System.OsString from os-string &gt;= 2.0.0 package
--   instead. This module will be removed in filepath &gt;= 1.5.</i>
module System.OsString

-- | Newtype representing short operating system specific strings.
--   
--   Internally this is either <a>WindowsString</a> or <a>PosixString</a>,
--   depending on the platform. Both use unpinned <tt>ShortByteString</tt>
--   for efficiency.
--   
--   The constructor is only exported via
--   <a>System.OsString.Internal.Types</a>, since dealing with the
--   internals isn't generally recommended, but supported in case you need
--   to write platform specific code.
data OsString

-- | Partial unicode friendly encoding.
--   
--   On windows this encodes as UTF16-LE (strictly), which is a pretty good
--   guess. On unix this encodes as UTF8 (strictly), which is a good guess.
--   
--   Throws a <a>EncodingException</a> if encoding fails.
encodeUtf :: MonadThrow m => String -> m OsString

-- | Encode an <a>OsString</a> given the platform specific encodings.
encodeWith :: TextEncoding -> TextEncoding -> String -> Either EncodingException OsString

-- | Like <a>encodeUtf</a>, except this mimics the behavior of the base
--   library when doing filesystem operations, which is:
--   
--   <ol>
--   <li>on unix, uses shady PEP 383 style encoding (based on the current
--   locale, but PEP 383 only works properly on UTF-8 encodings, so good
--   luck)</li>
--   <li>on windows does permissive UTF-16 encoding, where coding errors
--   generate Chars in the surrogate range</li>
--   </ol>
--   
--   Looking up the locale requires IO. If you're not worried about calls
--   to <tt>setFileSystemEncoding</tt>, then <tt>unsafePerformIO</tt> may
--   be feasible (make sure to deeply evaluate the result to catch
--   exceptions).
encodeFS :: String -> IO OsString

-- | QuasiQuote an <a>OsString</a>. This accepts Unicode characters and
--   encodes as UTF-8 on unix and UTF-16 on windows.
osstr :: QuasiQuoter

-- | Pack a list of <a>OsChar</a> to an <a>OsString</a>
--   
--   Note that using this in conjunction with <a>unsafeFromChar</a> to
--   convert from <tt>[Char]</tt> to <a>OsString</a> is probably not what
--   you want, because it will truncate unicode code points.
pack :: [OsChar] -> OsString

-- | Partial unicode friendly decoding.
--   
--   On windows this decodes as UTF16-LE (strictly), which is a pretty good
--   guess. On unix this decodes as UTF8 (strictly), which is a good guess.
--   Note that filenames on unix are encoding agnostic char arrays.
--   
--   Throws a <a>EncodingException</a> if decoding fails.
decodeUtf :: MonadThrow m => OsString -> m String

-- | Decode an <a>OsString</a> with the specified encoding.
--   
--   The String is forced into memory to catch all exceptions.
decodeWith :: TextEncoding -> TextEncoding -> OsString -> Either EncodingException String

-- | Like <a>decodeUtf</a>, except this mimics the behavior of the base
--   library when doing filesystem operations, which is:
--   
--   <ol>
--   <li>on unix, uses shady PEP 383 style encoding (based on the current
--   locale, but PEP 383 only works properly on UTF-8 encodings, so good
--   luck)</li>
--   <li>on windows does permissive UTF-16 encoding, where coding errors
--   generate Chars in the surrogate range</li>
--   </ol>
--   
--   Looking up the locale requires IO. If you're not worried about calls
--   to <tt>setFileSystemEncoding</tt>, then <tt>unsafePerformIO</tt> may
--   be feasible (make sure to deeply evaluate the result to catch
--   exceptions).
decodeFS :: OsString -> IO String

-- | Unpack an <a>OsString</a> to a list of <a>OsChar</a>.
unpack :: OsString -> [OsChar]

-- | Newtype representing a code unit.
--   
--   On Windows, this is restricted to two-octet codepoints <a>Word16</a>,
--   on POSIX one-octet (<a>Word8</a>).
data OsChar

-- | Truncates on unix to 1 and on Windows to 2 octets.
unsafeFromChar :: Char -> OsChar

-- | Converts back to a unicode codepoint (total).
toChar :: OsChar -> Char

module System.OsPath.Posix

-- | Commonly used Posix string as uninterpreted <tt>char[]</tt> array.
data PosixString
data PosixChar

-- | Filepaths are <tt>char[]</tt> data on unix as passed to syscalls.
type PosixPath = PosixString

-- | Partial unicode friendly encoding.
--   
--   This encodes as UTF8 (strictly), which is a good guess.
--   
--   Throws an <a>EncodingException</a> if encoding fails.
encodeUtf :: MonadThrow m => String -> m PosixString

-- | Encode a <a>String</a> with the specified encoding.
encodeWith :: TextEncoding -> String -> Either EncodingException PosixString

-- | This mimics the behavior of the base library when doing filesystem
--   operations, which uses shady PEP 383 style encoding (based on the
--   current locale, but PEP 383 only works properly on UTF-8 encodings, so
--   good luck).
--   
--   Looking up the locale requires IO. If you're not worried about calls
--   to <tt>setFileSystemEncoding</tt>, then <a>unsafePerformIO</a> may be
--   feasible (make sure to deeply evaluate the result to catch
--   exceptions).
encodeFS :: String -> IO PosixString

-- | QuasiQuote a <a>PosixPath</a>. This accepts Unicode characters and
--   encodes as UTF-8. Runs <a>isValid</a> on the input.
pstr :: QuasiQuoter

-- | Pack a list of platform words to a platform string.
--   
--   Note that using this in conjunction with <a>unsafeFromChar</a> to
--   convert from <tt>[Char]</tt> to platform string is probably not what
--   you want, because it will truncate unicode code points.
pack :: [PosixChar] -> PosixString

-- | Partial unicode friendly decoding.
--   
--   This decodes as UTF8 (strictly), which is a good guess. Note that
--   filenames on unix are encoding agnostic char arrays.
--   
--   Throws a <a>EncodingException</a> if decoding fails.
decodeUtf :: MonadThrow m => PosixString -> m String

-- | Decode a <a>PosixString</a> with the specified encoding.
--   
--   The String is forced into memory to catch all exceptions.
decodeWith :: TextEncoding -> PosixString -> Either EncodingException String

-- | This mimics the behavior of the base library when doing filesystem
--   operations, which uses shady PEP 383 style encoding (based on the
--   current locale, but PEP 383 only works properly on UTF-8 encodings, so
--   good luck).
--   
--   Looking up the locale requires IO. If you're not worried about calls
--   to <tt>setFileSystemEncoding</tt>, then <a>unsafePerformIO</a> may be
--   feasible (make sure to deeply evaluate the result to catch
--   exceptions).
decodeFS :: PosixString -> IO String

-- | Unpack a platform string to a list of platform words.
unpack :: PosixString -> [PosixChar]

-- | Truncates to 1 octet.
unsafeFromChar :: Char -> PosixChar

-- | Converts back to a unicode codepoint (total).
toChar :: PosixChar -> Char

-- | The character that separates directories. In the case where more than
--   one character is possible, <a>pathSeparator</a> is the 'ideal' one.
--   
--   <pre>
--   pathSeparator ==  '/'
--   </pre>
pathSeparator :: PosixChar

-- | The list of all possible separators.
--   
--   <pre>
--   pathSeparators == ['/']
--   pathSeparator `elem` pathSeparators
--   </pre>
pathSeparators :: [PosixChar]

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

-- | The character that is used to separate the entries in the $PATH
--   environment variable.
--   
--   <pre>
--   searchPathSeparator == ':'
--   </pre>
searchPathSeparator :: PosixChar

-- | Is the character a file separator?
--   
--   <pre>
--   isSearchPathSeparator a == (a == searchPathSeparator)
--   </pre>
isSearchPathSeparator :: PosixChar -> Bool

-- | File extension character
--   
--   <pre>
--   extSeparator == '.'
--   </pre>
extSeparator :: PosixChar

-- | Is the character an extension character?
--   
--   <pre>
--   isExtSeparator a == (a == extSeparator)
--   </pre>
isExtSeparator :: PosixChar -> Bool

-- | Take a string, split it on the <a>searchPathSeparator</a> character.
--   
--   Blank items are converted to <tt>.</tt> on , and quotes are not
--   treated specially.
--   
--   Follows the recommendations in
--   <a>http://www.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap08.html</a>
--   
--   <pre>
--   splitSearchPath "File1:File2:File3"  == ["File1","File2","File3"]
--   splitSearchPath "File1::File2:File3" == ["File1",".","File2","File3"]
--   </pre>
splitSearchPath :: PosixString -> [PosixPath]

-- | Split on the extension. <a>addExtension</a> is the inverse.
--   
--   <pre>
--   splitExtension "/directory/path.ext" == ("/directory/path",".ext")
--   uncurry (&lt;&gt;) (splitExtension x) == x
--   Valid x =&gt; 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/","")
--   </pre>
splitExtension :: PosixPath -> (PosixPath, PosixString)

-- | Get the extension of a file, returns <tt>""</tt> for no extension,
--   <tt>.ext</tt> otherwise.
--   
--   <pre>
--   takeExtension "/directory/path.ext" == ".ext"
--   takeExtension x == snd (splitExtension x)
--   Valid x =&gt; takeExtension (addExtension x "ext") == ".ext"
--   Valid x =&gt; takeExtension (replaceExtension x "ext") == ".ext"
--   </pre>
takeExtension :: PosixPath -> PosixString

-- | Set the extension of a file, overwriting one if already present,
--   equivalent to <a>-&lt;.&gt;</a>.
--   
--   <pre>
--   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
--   </pre>
replaceExtension :: PosixPath -> PosixString -> PosixPath

-- | Remove the current extension and add another, equivalent to
--   <a>replaceExtension</a>.
--   
--   <pre>
--   "/directory/path.txt" -&lt;.&gt; "ext" == "/directory/path.ext"
--   "/directory/path.txt" -&lt;.&gt; ".ext" == "/directory/path.ext"
--   "foo.o" -&lt;.&gt; "c" == "foo.c"
--   </pre>
(-<.>) :: PosixPath -> PosixString -> PosixPath

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

-- | Add an extension, even if there is already one there, equivalent to
--   <a>&lt;.&gt;</a>.
--   
--   <pre>
--   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 =&gt; takeFileName (addExtension (addTrailingPathSeparator x) "ext") == ".ext"
--   Windows: addExtension "\\\\share" ".txt" == "\\\\share\\.txt"
--   </pre>
--   
--   Add an extension, even if there is already one there, equivalent to
--   <a>&lt;.&gt;</a>.
--   
--   <pre>
--   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 =&gt; takeFileName (addExtension (addTrailingPathSeparator x) "ext") == ".ext"
--   </pre>
addExtension :: PosixPath -> PosixString -> PosixPath

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

-- | Add an extension, even if there is already one there, equivalent to
--   <a>addExtension</a>.
--   
--   <pre>
--   "/directory/path" &lt;.&gt; "ext" == "/directory/path.ext"
--   "/directory/path" &lt;.&gt; ".ext" == "/directory/path.ext"
--   </pre>
(<.>) :: PosixPath -> PosixString -> PosixPath

-- | Split on all extensions.
--   
--   <pre>
--   splitExtensions "/directory/path.ext" == ("/directory/path",".ext")
--   splitExtensions "file.tar.gz" == ("file",".tar.gz")
--   uncurry (&lt;&gt;) (splitExtensions x) == x
--   Valid x =&gt; uncurry addExtension (splitExtensions x) == x
--   splitExtensions "file.tar.gz" == ("file",".tar.gz")
--   </pre>
splitExtensions :: PosixPath -> (PosixPath, PosixString)

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

-- | Get all extensions.
--   
--   <pre>
--   takeExtensions "/directory/path.ext" == ".ext"
--   takeExtensions "file.tar.gz" == ".tar.gz"
--   </pre>
takeExtensions :: PosixPath -> PosixString

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

-- | Does the given filename have the specified extension?
--   
--   <pre>
--   "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
--   </pre>
isExtensionOf :: PosixString -> PosixPath -> Bool

-- | Drop the given extension from a filepath, and the <tt>"."</tt>
--   preceding it. Returns <a>Nothing</a> if the filepath does not have the
--   given extension, or <a>Just</a> and the part before the extension if
--   it does.
--   
--   This function can be more predictable than <a>dropExtensions</a>,
--   especially if the filename might itself contain <tt>.</tt> characters.
--   
--   <pre>
--   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
--   </pre>
stripExtension :: PosixString -> PosixPath -> Maybe PosixPath

-- | Split a filename into directory and file. <a>&lt;/&gt;</a> is the
--   inverse. The first component will often end with a trailing slash.
--   
--   <pre>
--   splitFileName "/directory/file.ext" == ("/directory/","file.ext")
--   Valid x =&gt; uncurry (&lt;/&gt;) (splitFileName x) == x || fst (splitFileName x) == "./"
--   Valid x =&gt; isValid (fst (splitFileName x))
--   splitFileName "file/bob.txt" == ("file/", "bob.txt")
--   splitFileName "file/" == ("file/", "")
--   splitFileName "bob" == ("./", "bob")
--   splitFileName "/" == ("/","")
--   </pre>
splitFileName :: PosixPath -> (PosixPath, PosixPath)

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

-- | Set the filename.
--   
--   <pre>
--   replaceFileName "/directory/other.txt" "file.ext" == "/directory/file.ext"
--   Valid x =&gt; replaceFileName x (takeFileName x) == x
--   </pre>
replaceFileName :: PosixPath -> PosixString -> PosixPath

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

-- | Get the base name, without an extension or path.
--   
--   <pre>
--   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"
--   </pre>
takeBaseName :: PosixPath -> PosixPath

-- | Set the base name.
--   
--   <pre>
--   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 =&gt; replaceBaseName x (takeBaseName x) == x
--   </pre>
replaceBaseName :: PosixPath -> PosixString -> PosixPath

-- | Get the directory name, move up one level.
--   
--   <pre>
--   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"
--   </pre>
takeDirectory :: PosixPath -> PosixPath

-- | Set the directory, keeping the filename the same.
--   
--   <pre>
--   replaceDirectory "root/file.ext" "/directory/" == "/directory/file.ext"
--   Valid x =&gt; replaceDirectory x (takeDirectory x) `equalFilePath` x
--   </pre>
replaceDirectory :: PosixPath -> PosixPath -> PosixPath

-- | An alias for <a>&lt;/&gt;</a>.
combine :: PosixPath -> PosixPath -> PosixPath

-- | 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 <tt>readFile (dir <a>&lt;/&gt;</a> file)</tt>
--   will access the same file as <tt>setCurrentDirectory dir; readFile
--   file</tt>.
--   
--   <pre>
--   "/directory" &lt;/&gt; "file.ext" == "/directory/file.ext"
--   Valid x =&gt; (takeDirectory x &lt;/&gt; takeFileName x) `equalFilePath` x
--   </pre>
--   
--   Combined:
--   
--   <pre>
--   "/" &lt;/&gt; "test" == "/test"
--   "home" &lt;/&gt; "bob" == "home/bob"
--   "x:" &lt;/&gt; "foo" == "x:/foo"
--   </pre>
--   
--   Not combined:
--   
--   <pre>
--   "home" &lt;/&gt; "/bob" == "/bob"
--   </pre>
(</>) :: PosixPath -> PosixPath -> PosixPath

-- | Split a path by the directory separator.
--   
--   <pre>
--   splitPath "/directory/file.ext" == ["/","directory/","file.ext"]
--   concat (splitPath x) == x
--   splitPath "test//item/" == ["test//","item/"]
--   splitPath "test/item/file" == ["test/","item/","file"]
--   splitPath "" == []
--   splitPath "/file/test" == ["/","file/","test"]
--   </pre>
splitPath :: PosixPath -> [PosixPath]

-- | Join path elements back together.
--   
--   <pre>
--   joinPath z == foldr (&lt;/&gt;) "" z
--   joinPath ["/","directory/","file.ext"] == "/directory/file.ext"
--   Valid x =&gt; joinPath (splitPath x) == x
--   joinPath [] == ""
--   joinPath ["test","file","path"] == "test/file/path"
--   </pre>
joinPath :: [PosixPath] -> PosixPath

-- | Just as <a>splitPath</a>, but don't add the trailing slashes to each
--   element.
--   
--   <pre>
--   splitDirectories "/directory/file.ext" == ["/","directory","file.ext"]
--   splitDirectories "test/file" == ["test","file"]
--   splitDirectories "/test/file" == ["/","test","file"]
--   Valid x =&gt; joinPath (splitDirectories x) `equalFilePath` x
--   splitDirectories "" == []
--   splitDirectories "/test///file" == ["/","test","file"]
--   </pre>
splitDirectories :: PosixPath -> [PosixPath]

-- | Split a path into a drive and a path. / is a Drive.
--   
--   <pre>
--   uncurry (&lt;&gt;) (splitDrive x) == x
--   splitDrive "/test" == ("/","test")
--   splitDrive "//test" == ("//","test")
--   splitDrive "test/file" == ("","test/file")
--   splitDrive "file" == ("","file")
--   </pre>
splitDrive :: PosixPath -> (PosixPath, PosixPath)

-- | Join a drive and the rest of the path.
--   
--   <pre>
--   Valid x =&gt; 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"
--   </pre>
--   
--   Join a drive and the rest of the path.
--   
--   <pre>
--   Valid x =&gt; uncurry joinDrive (splitDrive x) == x
--   </pre>
joinDrive :: PosixPath -> PosixPath -> PosixPath

-- | Get the drive from a filepath.
--   
--   <pre>
--   takeDrive x == fst (splitDrive x)
--   </pre>
takeDrive :: PosixPath -> PosixPath

-- | Does a path have a drive.
--   
--   <pre>
--   not (hasDrive x) == null (takeDrive x)
--   hasDrive "/foo" == True
--   hasDrive "foo" == False
--   hasDrive "" == False
--   </pre>
hasDrive :: PosixPath -> Bool

-- | Delete the drive, if it exists.
--   
--   <pre>
--   dropDrive x == snd (splitDrive x)
--   </pre>
dropDrive :: PosixPath -> PosixPath

-- | Is an element a drive
--   
--   <pre>
--   isDrive "/" == True
--   isDrive "/foo" == False
--   isDrive "" == False
--   </pre>
isDrive :: PosixPath -> Bool

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

-- | Add a trailing file path separator if one is not already present.
--   
--   <pre>
--   hasTrailingPathSeparator (addTrailingPathSeparator x)
--   hasTrailingPathSeparator x ==&gt; addTrailingPathSeparator x == x
--   addTrailingPathSeparator "test/rest" == "test/rest/"
--   </pre>
addTrailingPathSeparator :: PosixPath -> PosixPath

-- | Remove any trailing path separators
--   
--   <pre>
--   dropTrailingPathSeparator "file/test/" == "file/test"
--   dropTrailingPathSeparator "/" == "/"
--   not (hasTrailingPathSeparator (dropTrailingPathSeparator x)) || isDrive x
--   </pre>
dropTrailingPathSeparator :: PosixPath -> PosixPath

-- | Normalise a file
--   
--   <ul>
--   <li>// outside of the drive can be made blank</li>
--   <li>/ -&gt; <a>pathSeparator</a></li>
--   <li>./ -&gt; ""</li>
--   </ul>
--   
--   Does not remove <tt>".."</tt>, because of symlinks.
--   
--   <pre>
--   normalise "/file/\\test////" == "/file/\\test/"
--   normalise "/file/./test" == "/file/test"
--   normalise "/test/file/../bob/fred/" == "/test/file/../bob/fred/"
--   normalise "../bob/fred/" == "../bob/fred/"
--   normalise "/a/../c" == "/a/../c"
--   normalise "./bob/fred/" == "bob/fred/"
--   normalise "." == "."
--   normalise "./" == "./"
--   normalise "./." == "./"
--   normalise "/./" == "/"
--   normalise "/" == "/"
--   normalise "bob/fred/." == "bob/fred/"
--   normalise "//home" == "/home"
--   </pre>
normalise :: PosixPath -> PosixPath

-- | Equality of two filepaths. If you call
--   <tt>System.Directory.canonicalizePath</tt> first this has a much
--   better chance of working. Note that this doesn't follow symlinks or
--   DOSNAM~1s.
--   
--   Similar to <a>normalise</a>, this does not expand <tt>".."</tt>,
--   because of symlinks.
--   
--   <pre>
--   x == y ==&gt; equalFilePath x y
--   normalise x == normalise y ==&gt; equalFilePath x y
--   equalFilePath "foo" "foo/"
--   not (equalFilePath "/a/../c" "/c")
--   not (equalFilePath "foo" "/foo")
--   not (equalFilePath "foo" "FOO")
--   </pre>
equalFilePath :: PosixPath -> PosixPath -> Bool

-- | Contract a filename, based on a relative path. Note that the resulting
--   path will never introduce <tt>..</tt> paths, as the presence of
--   symlinks means <tt>../b</tt> may not reach <tt>a/b</tt> if it starts
--   from <tt>a/c</tt>. For a worked example see <a>this blog post</a>.
--   
--   The corresponding <tt>makeAbsolute</tt> function can be found in
--   <tt>System.Directory</tt>.
--   
--   <pre>
--   makeRelative "/directory" "/directory/file.ext" == "file.ext"
--   Valid x =&gt; makeRelative (takeDirectory x) x `equalFilePath` takeFileName x
--   makeRelative x x == "."
--   Valid x y =&gt; equalFilePath x y || (isRelative x &amp;&amp; makeRelative y x == x) || equalFilePath (y &lt;/&gt; makeRelative y x) x
--   makeRelative "/Home" "/home/bob" == "/home/bob"
--   makeRelative "/home/" "/home/bob/foo/bar" == "bob/foo/bar"
--   makeRelative "/fred" "bob" == "bob"
--   makeRelative "/file/test" "/file/test/fred" == "fred"
--   makeRelative "/file/test" "/file/test/fred/" == "fred/"
--   makeRelative "some/path" "some/path/a/b/c" == "a/b/c"
--   </pre>
makeRelative :: PosixPath -> PosixPath -> PosixPath

-- | Is a path relative, or is it fixed to the root?
--   
--   <pre>
--   isRelative "test/path" == True
--   isRelative "/test" == False
--   isRelative "/" == False
--   </pre>
isRelative :: PosixPath -> Bool

-- | <pre>
--   not . <a>isRelative</a>
--   </pre>
--   
--   <pre>
--   isAbsolute x == not (isRelative x)
--   </pre>
isAbsolute :: PosixPath -> Bool

-- | Is a filepath 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.
--   
--   <pre>
--   isValid "" == False
--   isValid "\0" == False
--   isValid "/random_ path:*" == True
--   isValid x == not (null x)
--   </pre>
isValid :: PosixPath -> Bool

-- | Take a filepath and make it valid; does not change already valid
--   filepaths.
--   
--   <pre>
--   isValid (makeValid x)
--   isValid x ==&gt; makeValid x == x
--   makeValid "" == "_"
--   makeValid "file\0name" == "file_name"
--   </pre>
makeValid :: PosixPath -> PosixPath

module System.OsPath.Internal

-- | Partial unicode friendly encoding.
--   
--   On windows this encodes as UTF16-LE (strictly), which is a pretty good
--   guess. On unix this encodes as UTF8 (strictly), which is a good guess.
--   
--   Throws a <a>EncodingException</a> if encoding fails.
encodeUtf :: MonadThrow m => FilePath -> m OsPath

-- | Encode a <a>FilePath</a> with the specified encoding.
encodeWith :: TextEncoding -> TextEncoding -> FilePath -> Either EncodingException OsPath

-- | Like <a>encodeUtf</a>, except this mimics the behavior of the base
--   library when doing filesystem operations, which is:
--   
--   <ol>
--   <li>on unix, uses shady PEP 383 style encoding (based on the current
--   locale, but PEP 383 only works properly on UTF-8 encodings, so good
--   luck)</li>
--   <li>on windows does permissive UTF-16 encoding, where coding errors
--   generate Chars in the surrogate range</li>
--   </ol>
--   
--   Looking up the locale requires IO. If you're not worried about calls
--   to <tt>setFileSystemEncoding</tt>, then <tt>unsafePerformIO</tt> may
--   be feasible (make sure to deeply evaluate the result to catch
--   exceptions).
encodeFS :: FilePath -> IO OsPath

-- | Partial unicode friendly decoding.
--   
--   On windows this decodes as UTF16-LE (strictly), which is a pretty good
--   guess. On unix this decodes as UTF8 (strictly), which is a good guess.
--   
--   Throws a <a>EncodingException</a> if decoding fails.
decodeUtf :: MonadThrow m => OsPath -> m FilePath

-- | Decode an <a>OsPath</a> with the specified encoding.
decodeWith :: TextEncoding -> TextEncoding -> OsPath -> Either EncodingException FilePath

-- | Like <a>decodeUtf</a>, except this mimics the behavior of the base
--   library when doing filesystem operations, which is:
--   
--   <ol>
--   <li>on unix, uses shady PEP 383 style encoding (based on the current
--   locale, but PEP 383 only works properly on UTF-8 encodings, so good
--   luck)</li>
--   <li>on windows does permissive UTF-16 encoding, where coding errors
--   generate Chars in the surrogate range</li>
--   </ol>
--   
--   Looking up the locale requires IO. If you're not worried about calls
--   to <tt>setFileSystemEncoding</tt>, then <tt>unsafePerformIO</tt> may
--   be feasible (make sure to deeply evaluate the result to catch
--   exceptions).
decodeFS :: OsPath -> IO FilePath

-- | Constructs an <tt>OsPath</tt> from a ByteString.
--   
--   On windows, this ensures valid UCS-2LE, on unix it is passed
--   unchanged/unchecked.
--   
--   Throws <a>EncodingException</a> on invalid UCS-2LE on windows
--   (although unlikely).
fromBytes :: MonadThrow m => ByteString -> m OsPath

-- | QuasiQuote an <a>OsPath</a>. This accepts Unicode characters and
--   encodes as UTF-8 on unix and UTF-16LE on windows. Runs <a>isValid</a>
--   on the input.
osp :: QuasiQuoter

-- | Unpack an <a>OsPath</a> to a list of <a>OsChar</a>.
unpack :: OsPath -> [OsChar]

-- | Pack a list of <a>OsChar</a> to an <a>OsPath</a>.
--   
--   Note that using this in conjunction with <tt>unsafeFromChar</tt> to
--   convert from <tt>[Char]</tt> to <a>OsPath</a> is probably not what you
--   want, because it will truncate unicode code points.
pack :: [OsChar] -> OsPath


-- | An implementation of the <a>Abstract FilePath Proposal</a>, which aims
--   to supersede <tt>type FilePath = String</tt> for various reasons:
--   
--   <ol>
--   <li>it is more efficient and avoids memory fragmentation (uses
--   unpinned <tt>ShortByteString</tt> under the hood)</li>
--   <li>it is more type-safe (newtype over <tt>ShortByteString</tt>)</li>
--   <li>avoids round-tripping issues by not converting to String (which is
--   not total and loses the encoding)</li>
--   <li>abstracts over unix and windows while keeping the original
--   bytes</li>
--   </ol>
--   
--   It is important to know that filenames/filepaths have different
--   representations across platforms:
--   
--   <ul>
--   <li>On <i>Windows</i>, filepaths are expected to be encoded as
--   UTF16-LE <a>as per the documentation</a>, but may also include invalid
--   surrogate pairs, in which case UCS-2 can be used. They are passed as
--   <tt>wchar_t*</tt> to syscalls. <a>OsPath</a> only maintains the wide
--   character invariant.</li>
--   <li>On <i>Unix</i>, filepaths don't have a predefined encoding
--   (although they are often interpreted as UTF8) as per the <a>POSIX
--   specification</a> and are passed as <tt>char[]</tt> to syscalls.
--   <a>OsPath</a> maintains no invariant here.</li>
--   </ul>
--   
--   Apart from encoding, filepaths have additional restrictions per
--   platform:
--   
--   <ul>
--   <li>On <i>Windows</i> the <a>naming convention</a> may apply</li>
--   <li>On <i>Unix</i>, only <tt>NUL</tt> bytes are disallowed as per the
--   <a>POSIX specification</a></li>
--   </ul>
--   
--   Use <a>isValid</a> to check for these restrictions (<a>OsPath</a>
--   doesn't maintain this invariant).
--   
--   Also note that these restrictions are not exhaustive and further
--   filesystem specific restrictions may apply on all platforms. This
--   library makes no attempt at satisfying these. Library users may need
--   to account for that, depending on what filesystems they want to
--   support.
--   
--   It is advised to follow these principles when dealing with
--   filepaths/filenames:
--   
--   <ol>
--   <li>Avoid interpreting filenames that the OS returns, unless
--   absolutely necessary. For example, the filepath separator is usually a
--   predefined <tt>Word8</tt>/<tt>Word16</tt>, regardless of encoding. So
--   even if we need to split filepaths, it might still not be necessary to
--   understand the encoding of the filename.</li>
--   <li>When interpreting OS returned filenames consider that these might
--   not be UTF8 on <i>unix</i> or at worst don't have an ASCII compatible
--   encoding. The are 3 available strategies fer decoding/encoding: a)
--   pick the best UTF (UTF-8 on unix, UTF-16LE on windows), b) decode with
--   an explicitly defined <tt>TextEncoding</tt>, c) mimic the behavior of
--   the <tt>base</tt> library (permissive UTF16 on windows, current
--   filesystem encoding on unix).</li>
--   <li>Avoid comparing <tt>String</tt> based filepaths, because filenames
--   of different encodings may have the same <tt>String</tt>
--   representation, although they're not the same byte-wise.</li>
--   </ol>
module System.OsPath

-- | Type representing filenames/pathnames.
--   
--   This type doesn't add any guarantees over <a>OsString</a>.
type OsPath = OsString

-- | Newtype representing short operating system specific strings.
--   
--   Internally this is either <a>WindowsString</a> or <a>PosixString</a>,
--   depending on the platform. Both use unpinned <tt>ShortByteString</tt>
--   for efficiency.
--   
--   The constructor is only exported via
--   <a>System.OsString.Internal.Types</a>, since dealing with the
--   internals isn't generally recommended, but supported in case you need
--   to write platform specific code.
data OsString

-- | Newtype representing a code unit.
--   
--   On Windows, this is restricted to two-octet codepoints <a>Word16</a>,
--   on POSIX one-octet (<a>Word8</a>).
data OsChar

-- | Partial unicode friendly encoding.
--   
--   On windows this encodes as UTF16-LE (strictly), which is a pretty good
--   guess. On unix this encodes as UTF8 (strictly), which is a good guess.
--   
--   Throws a <a>EncodingException</a> if encoding fails.
encodeUtf :: MonadThrow m => FilePath -> m OsPath

-- | Encode a <a>FilePath</a> with the specified encoding.
encodeWith :: TextEncoding -> TextEncoding -> FilePath -> Either EncodingException OsPath

-- | Like <a>encodeUtf</a>, except this mimics the behavior of the base
--   library when doing filesystem operations, which is:
--   
--   <ol>
--   <li>on unix, uses shady PEP 383 style encoding (based on the current
--   locale, but PEP 383 only works properly on UTF-8 encodings, so good
--   luck)</li>
--   <li>on windows does permissive UTF-16 encoding, where coding errors
--   generate Chars in the surrogate range</li>
--   </ol>
--   
--   Looking up the locale requires IO. If you're not worried about calls
--   to <tt>setFileSystemEncoding</tt>, then <tt>unsafePerformIO</tt> may
--   be feasible (make sure to deeply evaluate the result to catch
--   exceptions).
encodeFS :: FilePath -> IO OsPath

-- | QuasiQuote an <a>OsPath</a>. This accepts Unicode characters and
--   encodes as UTF-8 on unix and UTF-16LE on windows. Runs <a>isValid</a>
--   on the input.
osp :: QuasiQuoter

-- | Pack a list of <a>OsChar</a> to an <a>OsPath</a>.
--   
--   Note that using this in conjunction with <tt>unsafeFromChar</tt> to
--   convert from <tt>[Char]</tt> to <a>OsPath</a> is probably not what you
--   want, because it will truncate unicode code points.
pack :: [OsChar] -> OsPath

-- | Partial unicode friendly decoding.
--   
--   On windows this decodes as UTF16-LE (strictly), which is a pretty good
--   guess. On unix this decodes as UTF8 (strictly), which is a good guess.
--   
--   Throws a <a>EncodingException</a> if decoding fails.
decodeUtf :: MonadThrow m => OsPath -> m FilePath

-- | Decode an <a>OsPath</a> with the specified encoding.
decodeWith :: TextEncoding -> TextEncoding -> OsPath -> Either EncodingException FilePath

-- | Like <a>decodeUtf</a>, except this mimics the behavior of the base
--   library when doing filesystem operations, which is:
--   
--   <ol>
--   <li>on unix, uses shady PEP 383 style encoding (based on the current
--   locale, but PEP 383 only works properly on UTF-8 encodings, so good
--   luck)</li>
--   <li>on windows does permissive UTF-16 encoding, where coding errors
--   generate Chars in the surrogate range</li>
--   </ol>
--   
--   Looking up the locale requires IO. If you're not worried about calls
--   to <tt>setFileSystemEncoding</tt>, then <tt>unsafePerformIO</tt> may
--   be feasible (make sure to deeply evaluate the result to catch
--   exceptions).
decodeFS :: OsPath -> IO FilePath

-- | Unpack an <a>OsPath</a> to a list of <a>OsChar</a>.
unpack :: OsPath -> [OsChar]

-- | Truncates on unix to 1 and on Windows to 2 octets.
unsafeFromChar :: Char -> OsChar

-- | Converts back to a unicode codepoint (total).
toChar :: OsChar -> Char

-- | The character that separates directories. In the case where more than
--   one character is possible, <a>pathSeparator</a> is the 'ideal' one.
--   
--   <pre>
--   Windows: pathSeparator == '\\'S
--   Posix:   pathSeparator ==  '/'
--   </pre>
pathSeparator :: OsChar

-- | The list of all possible separators.
--   
--   <pre>
--   Windows: pathSeparators == ['\\', '/']
--   Posix:   pathSeparators == ['/']
--   pathSeparator `elem` pathSeparators
--   </pre>
pathSeparators :: [OsChar]

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

-- | The character that is used to separate the entries in the $PATH
--   environment variable.
--   
--   <pre>
--   Posix:   searchPathSeparator == ':'
--   Windows: searchPathSeparator == ';'
--   </pre>
searchPathSeparator :: OsChar

-- | Is the character a file separator?
--   
--   <pre>
--   isSearchPathSeparator a == (a == searchPathSeparator)
--   </pre>
isSearchPathSeparator :: OsChar -> Bool

-- | File extension character
--   
--   <pre>
--   extSeparator == '.'
--   </pre>
extSeparator :: OsChar

-- | Is the character an extension character?
--   
--   <pre>
--   isExtSeparator a == (a == extSeparator)
--   </pre>
isExtSeparator :: OsChar -> Bool

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

-- | Split on the extension. <a>addExtension</a> is the inverse.
--   
--   <pre>
--   splitExtension "/directory/path.ext" == ("/directory/path",".ext")
--   uncurry (&lt;&gt;) (splitExtension x) == x
--   Valid x =&gt; 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/","")
--   </pre>
splitExtension :: OsPath -> (OsPath, OsString)

-- | Get the extension of a file, returns <tt>""</tt> for no extension,
--   <tt>.ext</tt> otherwise.
--   
--   <pre>
--   takeExtension "/directory/path.ext" == ".ext"
--   takeExtension x == snd (splitExtension x)
--   Valid x =&gt; takeExtension (addExtension x "ext") == ".ext"
--   Valid x =&gt; takeExtension (replaceExtension x "ext") == ".ext"
--   </pre>
takeExtension :: OsPath -> OsString

-- | Set the extension of a file, overwriting one if already present,
--   equivalent to <a>-&lt;.&gt;</a>.
--   
--   <pre>
--   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
--   </pre>
replaceExtension :: OsPath -> OsString -> OsPath

-- | Remove the current extension and add another, equivalent to
--   <a>replaceExtension</a>.
--   
--   <pre>
--   "/directory/path.txt" -&lt;.&gt; "ext" == "/directory/path.ext"
--   "/directory/path.txt" -&lt;.&gt; ".ext" == "/directory/path.ext"
--   "foo.o" -&lt;.&gt; "c" == "foo.c"
--   </pre>
(-<.>) :: OsPath -> OsString -> OsPath

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

-- | Add an extension, even if there is already one there, equivalent to
--   <a>&lt;.&gt;</a>.
--   
--   <pre>
--   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 =&gt; takeFileName (addExtension (addTrailingPathSeparator x) "ext") == ".ext"
--   Windows: addExtension "\\\\share" ".txt" == "\\\\share\\.txt"
--   </pre>
--   
--   Add an extension, even if there is already one there, equivalent to
--   <a>&lt;.&gt;</a>.
--   
--   <pre>
--   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 =&gt; takeFileName (addExtension (addTrailingPathSeparator x) "ext") == ".ext"
--   Windows: addExtension "\\\\share" ".txt" == "\\\\share\\.txt"
--   </pre>
addExtension :: OsPath -> OsString -> OsPath

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

-- | Add an extension, even if there is already one there, equivalent to
--   <a>addExtension</a>.
--   
--   <pre>
--   "/directory/path" &lt;.&gt; "ext" == "/directory/path.ext"
--   "/directory/path" &lt;.&gt; ".ext" == "/directory/path.ext"
--   </pre>
(<.>) :: OsPath -> OsString -> OsPath

-- | Split on all extensions.
--   
--   <pre>
--   splitExtensions "/directory/path.ext" == ("/directory/path",".ext")
--   splitExtensions "file.tar.gz" == ("file",".tar.gz")
--   uncurry (&lt;&gt;) (splitExtensions x) == x
--   Valid x =&gt; uncurry addExtension (splitExtensions x) == x
--   splitExtensions "file.tar.gz" == ("file",".tar.gz")
--   </pre>
splitExtensions :: OsPath -> (OsPath, OsString)

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

-- | Get all extensions.
--   
--   <pre>
--   takeExtensions "/directory/path.ext" == ".ext"
--   takeExtensions "file.tar.gz" == ".tar.gz"
--   </pre>
takeExtensions :: OsPath -> OsString

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

-- | Does the given filename have the specified extension?
--   
--   <pre>
--   "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
--   </pre>
isExtensionOf :: OsString -> OsPath -> Bool

-- | Drop the given extension from a filepath, and the <tt>"."</tt>
--   preceding it. Returns <a>Nothing</a> if the filepath does not have the
--   given extension, or <a>Just</a> and the part before the extension if
--   it does.
--   
--   This function can be more predictable than <a>dropExtensions</a>,
--   especially if the filename might itself contain <tt>.</tt> characters.
--   
--   <pre>
--   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
--   </pre>
stripExtension :: OsString -> OsPath -> Maybe OsPath

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

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

-- | Set the filename.
--   
--   <pre>
--   replaceFileName "/directory/other.txt" "file.ext" == "/directory/file.ext"
--   Valid x =&gt; replaceFileName x (takeFileName x) == x
--   </pre>
replaceFileName :: OsPath -> OsString -> OsPath

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

-- | Get the base name, without an extension or path.
--   
--   <pre>
--   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"
--   </pre>
takeBaseName :: OsPath -> OsPath

-- | Set the base name.
--   
--   <pre>
--   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 =&gt; replaceBaseName x (takeBaseName x) == x
--   </pre>
replaceBaseName :: OsPath -> OsString -> OsPath

-- | Get the directory name, move up one level.
--   
--   <pre>
--             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:\\"
--   </pre>
takeDirectory :: OsPath -> OsPath

-- | Set the directory, keeping the filename the same.
--   
--   <pre>
--   replaceDirectory "root/file.ext" "/directory/" == "/directory/file.ext"
--   Valid x =&gt; replaceDirectory x (takeDirectory x) `equalFilePath` x
--   </pre>
replaceDirectory :: OsPath -> OsPath -> OsPath

-- | An alias for <a>&lt;/&gt;</a>.
combine :: OsPath -> OsPath -> OsPath

-- | 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 <tt>readFile (dir <a>&lt;/&gt;</a> file)</tt>
--   will access the same file as <tt>setCurrentDirectory dir; readFile
--   file</tt>.
--   
--   <pre>
--   Posix:   "/directory" &lt;/&gt; "file.ext" == "/directory/file.ext"
--   Windows: "/directory" &lt;/&gt; "file.ext" == "/directory\\file.ext"
--            "directory" &lt;/&gt; "/file.ext" == "/file.ext"
--   Valid x =&gt; (takeDirectory x &lt;/&gt; takeFileName x) `equalFilePath` x
--   </pre>
--   
--   Combined:
--   
--   <pre>
--   Posix:   "/" &lt;/&gt; "test" == "/test"
--   Posix:   "home" &lt;/&gt; "bob" == "home/bob"
--   Posix:   "x:" &lt;/&gt; "foo" == "x:/foo"
--   Windows: "C:\\foo" &lt;/&gt; "bar" == "C:\\foo\\bar"
--   Windows: "home" &lt;/&gt; "bob" == "home\\bob"
--   </pre>
--   
--   Not combined:
--   
--   <pre>
--   Posix:   "home" &lt;/&gt; "/bob" == "/bob"
--   Windows: "home" &lt;/&gt; "C:\\bob" == "C:\\bob"
--   </pre>
--   
--   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
--   <a>&lt;/&gt;</a> is to never combine these forms.
--   
--   <pre>
--   Windows: "home" &lt;/&gt; "/bob" == "/bob"
--   Windows: "home" &lt;/&gt; "\\bob" == "\\bob"
--   Windows: "C:\\home" &lt;/&gt; "\\bob" == "\\bob"
--   </pre>
--   
--   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 <a>&lt;/&gt;</a> is to
--   never combine these forms.
--   
--   <pre>
--   Windows: "D:\\foo" &lt;/&gt; "C:bar" == "C:bar"
--   Windows: "C:\\foo" &lt;/&gt; "C:bar" == "C:bar"
--   </pre>
(</>) :: OsPath -> OsPath -> OsPath

-- | Split a path by the directory separator.
--   
--   <pre>
--   splitPath "/directory/file.ext" == ["/","directory/","file.ext"]
--   concat (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"]
--   </pre>
splitPath :: OsPath -> [OsPath]

-- | Join path elements back together.
--   
--   <pre>
--   joinPath z == foldr (&lt;/&gt;) "" z
--   joinPath ["/","directory/","file.ext"] == "/directory/file.ext"
--   Valid x =&gt; joinPath (splitPath x) == x
--   joinPath [] == ""
--   Posix: joinPath ["test","file","path"] == "test/file/path"
--   </pre>
joinPath :: [OsPath] -> OsPath

-- | Just as <a>splitPath</a>, but don't add the trailing slashes to each
--   element.
--   
--   <pre>
--            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 =&gt; joinPath (splitDirectories x) `equalFilePath` x
--            splitDirectories "" == []
--   Windows: splitDirectories "C:\\test\\\\\\file" == ["C:\\", "test", "file"]
--            splitDirectories "/test///file" == ["/","test","file"]
--   </pre>
splitDirectories :: OsPath -> [OsPath]

-- | Split a path into a drive and a path. On Posix, / is a Drive.
--   
--   <pre>
--   uncurry (&lt;&gt;) (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")
--   </pre>
splitDrive :: OsPath -> (OsPath, OsPath)

-- | Join a drive and the rest of the path.
--   
--   <pre>
--   Valid x =&gt; 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"
--   </pre>
--   
--   Join a drive and the rest of the path.
--   
--   <pre>
--   Valid x =&gt; 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"
--   </pre>
joinDrive :: OsPath -> OsPath -> OsPath

-- | Get the drive from a filepath.
--   
--   <pre>
--   takeDrive x == fst (splitDrive x)
--   </pre>
takeDrive :: OsPath -> OsPath

-- | Does a path have a drive.
--   
--   <pre>
--   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
--   </pre>
hasDrive :: OsPath -> Bool

-- | Delete the drive, if it exists.
--   
--   <pre>
--   dropDrive x == snd (splitDrive x)
--   </pre>
dropDrive :: OsPath -> OsPath

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

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

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

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

-- | Normalise a file
--   
--   <ul>
--   <li>// outside of the drive can be made blank</li>
--   <li>/ -&gt; <a>pathSeparator</a></li>
--   <li>./ -&gt; ""</li>
--   </ul>
--   
--   Does not remove <tt>".."</tt>, because of symlinks.
--   
--   <pre>
--   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 "/a/../c" == "/a/../c"
--   Posix:   normalise "./bob/fred/" == "bob/fred/"
--   Windows: normalise "c:\\file/bob\\" == "C:\\file\\bob\\"
--   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"
--   </pre>
normalise :: OsPath -> OsPath

-- | Equality of two filepaths. If you call
--   <tt>System.Directory.canonicalizePath</tt> first this has a much
--   better chance of working. Note that this doesn't follow symlinks or
--   DOSNAM~1s.
--   
--   Similar to <a>normalise</a>, this does not expand <tt>".."</tt>,
--   because of symlinks.
--   
--   <pre>
--            x == y ==&gt; equalFilePath x y
--            normalise x == normalise y ==&gt; equalFilePath x y
--            equalFilePath "foo" "foo/"
--            not (equalFilePath "/a/../c" "/c")
--            not (equalFilePath "foo" "/foo")
--   Posix:   not (equalFilePath "foo" "FOO")
--   Windows: equalFilePath "foo" "FOO"
--   Windows: not (equalFilePath "C:" "C:/")
--   </pre>
equalFilePath :: OsPath -> OsPath -> Bool

-- | Contract a filename, based on a relative path. Note that the resulting
--   path will never introduce <tt>..</tt> paths, as the presence of
--   symlinks means <tt>../b</tt> may not reach <tt>a/b</tt> if it starts
--   from <tt>a/c</tt>. For a worked example see <a>this blog post</a>.
--   
--   The corresponding <tt>makeAbsolute</tt> function can be found in
--   <tt>System.Directory</tt>.
--   
--   <pre>
--            makeRelative "/directory" "/directory/file.ext" == "file.ext"
--            Valid x =&gt; makeRelative (takeDirectory x) x `equalFilePath` takeFileName x
--            makeRelative x x == "."
--            Valid x y =&gt; equalFilePath x y || (isRelative x &amp;&amp; makeRelative y x == x) || equalFilePath (y &lt;/&gt; 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"
--   </pre>
makeRelative :: OsPath -> OsPath -> OsPath

-- | Is a path relative, or is it fixed to the root?
--   
--   <pre>
--   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
--   </pre>
--   
--   According to [1]:
--   
--   <ul>
--   <li>"A UNC name of any format [is never relative]."</li>
--   <li>"You cannot use the "\?" prefix with a relative path."</li>
--   </ul>
isRelative :: OsPath -> Bool

-- | <pre>
--   not . <a>isRelative</a>
--   </pre>
--   
--   <pre>
--   isAbsolute x == not (isRelative x)
--   </pre>
isAbsolute :: OsPath -> Bool

-- | Is a filepath 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.
--   
--   <pre>
--            isValid "" == False
--            isValid "\0" == False
--   Posix:   isValid "/random_ path:*" == True
--   Posix:   isValid x == not (null x)
--   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
--   </pre>
isValid :: OsPath -> Bool

-- | Take a filepath and make it valid; does not change already valid
--   filepaths.
--   
--   <pre>
--   isValid (makeValid x)
--   isValid x ==&gt; 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"
--   </pre>
makeValid :: OsPath -> OsPath


-- | <i>Deprecated: Use System.OsString.Posix from os-string &gt;= 2.0.0
--   package instead. This module will be removed in filepath &gt;=
--   1.5.</i>
module System.OsString.Windows

-- | Commonly used windows string as wide character bytes.
data WindowsString
data WindowsChar

-- | Partial unicode friendly encoding.
--   
--   This encodes as UTF16-LE (strictly), which is a pretty good guess.
--   
--   Throws an <a>EncodingException</a> if encoding fails.
encodeUtf :: MonadThrow m => String -> m WindowsString

-- | Encode a <a>String</a> with the specified encoding.
encodeWith :: TextEncoding -> String -> Either EncodingException WindowsString

-- | This mimics the behavior of the base library when doing filesystem
--   operations, which does permissive UTF-16 encoding, where coding errors
--   generate Chars in the surrogate range.
--   
--   The reason this is in IO is because it unifies with the Posix
--   counterpart, which does require IO. This is safe to
--   <a>unsafePerformIO</a>/<tt>unsafeDupablePerformIO</tt>.
encodeFS :: String -> IO WindowsString

-- | Constructs a platform string from a ByteString.
--   
--   This ensures valid UCS-2LE. Note that this doesn't expand Word8 to
--   Word16 on windows, so you may get invalid UTF-16.
--   
--   Throws <a>EncodingException</a> on invalid UCS-2LE (although
--   unlikely).
fromBytes :: MonadThrow m => ByteString -> m WindowsString

-- | QuasiQuote a <a>WindowsString</a>. This accepts Unicode characters and
--   encodes as UTF-16LE on windows.
pstr :: QuasiQuoter

-- | Pack a list of platform words to a platform string.
--   
--   Note that using this in conjunction with <a>unsafeFromChar</a> to
--   convert from <tt>[Char]</tt> to platform string is probably not what
--   you want, because it will truncate unicode code points.
pack :: [WindowsChar] -> WindowsString

-- | Partial unicode friendly decoding.
--   
--   This decodes as UTF16-LE (strictly), which is a pretty good.
--   
--   Throws a <a>EncodingException</a> if decoding fails.
decodeUtf :: MonadThrow m => WindowsString -> m String

-- | Decode a <a>WindowsString</a> with the specified encoding.
--   
--   The String is forced into memory to catch all exceptions.
decodeWith :: TextEncoding -> WindowsString -> Either EncodingException String

-- | Like <a>decodeUtf</a>, except this mimics the behavior of the base
--   library when doing filesystem operations, which does permissive UTF-16
--   encoding, where coding errors generate Chars in the surrogate range.
--   
--   The reason this is in IO is because it unifies with the Posix
--   counterpart, which does require IO.
--   <a>unsafePerformIO</a>/<tt>unsafeDupablePerformIO</tt> are safe,
--   however.
decodeFS :: WindowsString -> IO String

-- | Unpack a platform string to a list of platform words.
unpack :: WindowsString -> [WindowsChar]

-- | Truncates to 2 octets.
unsafeFromChar :: Char -> WindowsChar

-- | Converts back to a unicode codepoint (total).
toChar :: WindowsChar -> Char

module System.OsPath.Windows

-- | Commonly used windows string as wide character bytes.
data WindowsString
data WindowsChar

-- | Filepaths are <tt>wchar_t*</tt> data on windows as passed to syscalls.
type WindowsPath = WindowsString

-- | Partial unicode friendly encoding.
--   
--   This encodes as UTF16-LE (strictly), which is a pretty good guess.
--   
--   Throws an <a>EncodingException</a> if encoding fails.
encodeUtf :: MonadThrow m => String -> m WindowsString

-- | Encode a <a>String</a> with the specified encoding.
encodeWith :: TextEncoding -> String -> Either EncodingException WindowsString

-- | This mimics the behavior of the base library when doing filesystem
--   operations, which does permissive UTF-16 encoding, where coding errors
--   generate Chars in the surrogate range.
--   
--   The reason this is in IO is because it unifies with the Posix
--   counterpart, which does require IO. This is safe to
--   <a>unsafePerformIO</a>/<tt>unsafeDupablePerformIO</tt>.
encodeFS :: String -> IO WindowsString

-- | QuasiQuote a <a>WindowsPath</a>. This accepts Unicode characters and
--   encodes as UTF-16LE. Runs <a>isValid</a> on the input.
pstr :: QuasiQuoter

-- | Pack a list of platform words to a platform string.
--   
--   Note that using this in conjunction with <a>unsafeFromChar</a> to
--   convert from <tt>[Char]</tt> to platform string is probably not what
--   you want, because it will truncate unicode code points.
pack :: [WindowsChar] -> WindowsString

-- | Partial unicode friendly decoding.
--   
--   This decodes as UTF16-LE (strictly), which is a pretty good.
--   
--   Throws a <a>EncodingException</a> if decoding fails.
decodeUtf :: MonadThrow m => WindowsString -> m String

-- | Decode a <a>WindowsString</a> with the specified encoding.
--   
--   The String is forced into memory to catch all exceptions.
decodeWith :: TextEncoding -> WindowsString -> Either EncodingException String

-- | Like <a>decodeUtf</a>, except this mimics the behavior of the base
--   library when doing filesystem operations, which does permissive UTF-16
--   encoding, where coding errors generate Chars in the surrogate range.
--   
--   The reason this is in IO is because it unifies with the Posix
--   counterpart, which does require IO.
--   <a>unsafePerformIO</a>/<tt>unsafeDupablePerformIO</tt> are safe,
--   however.
decodeFS :: WindowsString -> IO String

-- | Unpack a platform string to a list of platform words.
unpack :: WindowsString -> [WindowsChar]

-- | Truncates to 2 octets.
unsafeFromChar :: Char -> WindowsChar

-- | Converts back to a unicode codepoint (total).
toChar :: WindowsChar -> Char

-- | The character that separates directories. In the case where more than
--   one character is possible, <a>pathSeparator</a> is the 'ideal' one.
--   
--   <pre>
--   pathSeparator == '\\'S
--   </pre>
pathSeparator :: WindowsChar

-- | The list of all possible separators.
--   
--   <pre>
--   pathSeparators == ['\\', '/']
--   pathSeparator `elem` pathSeparators
--   </pre>
pathSeparators :: [WindowsChar]

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

-- | The character that is used to separate the entries in the $PATH
--   environment variable.
--   
--   <pre>
--   searchPathSeparator == ';'
--   </pre>
searchPathSeparator :: WindowsChar

-- | Is the character a file separator?
--   
--   <pre>
--   isSearchPathSeparator a == (a == searchPathSeparator)
--   </pre>
isSearchPathSeparator :: WindowsChar -> Bool

-- | File extension character
--   
--   <pre>
--   extSeparator == '.'
--   </pre>
extSeparator :: WindowsChar

-- | Is the character an extension character?
--   
--   <pre>
--   isExtSeparator a == (a == extSeparator)
--   </pre>
isExtSeparator :: WindowsChar -> Bool

-- | Take a string, split it on the <a>searchPathSeparator</a> character.
--   
--   Blank items are ignored and path elements are stripped of quotes.
--   
--   <pre>
--   splitSearchPath "File1;File2;File3"  == ["File1","File2","File3"]
--   splitSearchPath "File1;;File2;File3" == ["File1","File2","File3"]
--   splitSearchPath "File1;\"File2\";File3" == ["File1","File2","File3"]
--   </pre>
splitSearchPath :: WindowsString -> [WindowsPath]

-- | Split on the extension. <a>addExtension</a> is the inverse.
--   
--   <pre>
--   splitExtension "/directory/path.ext" == ("/directory/path",".ext")
--   uncurry (&lt;&gt;) (splitExtension x) == x
--   Valid x =&gt; 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/","")
--   </pre>
splitExtension :: WindowsPath -> (WindowsPath, WindowsString)

-- | Get the extension of a file, returns <tt>""</tt> for no extension,
--   <tt>.ext</tt> otherwise.
--   
--   <pre>
--   takeExtension "/directory/path.ext" == ".ext"
--   takeExtension x == snd (splitExtension x)
--   Valid x =&gt; takeExtension (addExtension x "ext") == ".ext"
--   Valid x =&gt; takeExtension (replaceExtension x "ext") == ".ext"
--   </pre>
takeExtension :: WindowsPath -> WindowsString

-- | Set the extension of a file, overwriting one if already present,
--   equivalent to <a>-&lt;.&gt;</a>.
--   
--   <pre>
--   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
--   </pre>
replaceExtension :: WindowsPath -> WindowsString -> WindowsPath

-- | Remove the current extension and add another, equivalent to
--   <a>replaceExtension</a>.
--   
--   <pre>
--   "/directory/path.txt" -&lt;.&gt; "ext" == "/directory/path.ext"
--   "/directory/path.txt" -&lt;.&gt; ".ext" == "/directory/path.ext"
--   "foo.o" -&lt;.&gt; "c" == "foo.c"
--   </pre>
(-<.>) :: WindowsPath -> WindowsString -> WindowsPath

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

-- | Add an extension, even if there is already one there, equivalent to
--   <a>&lt;.&gt;</a>.
--   
--   <pre>
--   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 =&gt; takeFileName (addExtension (addTrailingPathSeparator x) "ext") == ".ext"
--   Windows: addExtension "\\\\share" ".txt" == "\\\\share\\.txt"
--   </pre>
--   
--   Add an extension, even if there is already one there, equivalent to
--   <a>&lt;.&gt;</a>.
--   
--   <pre>
--   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 =&gt; takeFileName (addExtension (addTrailingPathSeparator x) "ext") == ".ext"
--   addExtension "\\\\share" ".txt" == "\\\\share\\.txt"
--   </pre>
addExtension :: WindowsPath -> WindowsString -> WindowsPath

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

-- | Add an extension, even if there is already one there, equivalent to
--   <a>addExtension</a>.
--   
--   <pre>
--   "/directory/path" &lt;.&gt; "ext" == "/directory/path.ext"
--   "/directory/path" &lt;.&gt; ".ext" == "/directory/path.ext"
--   </pre>
(<.>) :: WindowsPath -> WindowsString -> WindowsPath

-- | Split on all extensions.
--   
--   <pre>
--   splitExtensions "/directory/path.ext" == ("/directory/path",".ext")
--   splitExtensions "file.tar.gz" == ("file",".tar.gz")
--   uncurry (&lt;&gt;) (splitExtensions x) == x
--   Valid x =&gt; uncurry addExtension (splitExtensions x) == x
--   splitExtensions "file.tar.gz" == ("file",".tar.gz")
--   </pre>
splitExtensions :: WindowsPath -> (WindowsPath, WindowsString)

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

-- | Get all extensions.
--   
--   <pre>
--   takeExtensions "/directory/path.ext" == ".ext"
--   takeExtensions "file.tar.gz" == ".tar.gz"
--   </pre>
takeExtensions :: WindowsPath -> WindowsString

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

-- | Does the given filename have the specified extension?
--   
--   <pre>
--   "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
--   </pre>
isExtensionOf :: WindowsString -> WindowsPath -> Bool

-- | Drop the given extension from a filepath, and the <tt>"."</tt>
--   preceding it. Returns <a>Nothing</a> if the filepath does not have the
--   given extension, or <a>Just</a> and the part before the extension if
--   it does.
--   
--   This function can be more predictable than <a>dropExtensions</a>,
--   especially if the filename might itself contain <tt>.</tt> characters.
--   
--   <pre>
--   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
--   </pre>
stripExtension :: WindowsString -> WindowsPath -> Maybe WindowsPath

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

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

-- | Set the filename.
--   
--   <pre>
--   replaceFileName "/directory/other.txt" "file.ext" == "/directory/file.ext"
--   Valid x =&gt; replaceFileName x (takeFileName x) == x
--   </pre>
replaceFileName :: WindowsPath -> WindowsString -> WindowsPath

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

-- | Get the base name, without an extension or path.
--   
--   <pre>
--   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"
--   </pre>
takeBaseName :: WindowsPath -> WindowsPath

-- | Set the base name.
--   
--   <pre>
--   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 =&gt; replaceBaseName x (takeBaseName x) == x
--   </pre>
replaceBaseName :: WindowsPath -> WindowsString -> WindowsPath

-- | Get the directory name, move up one level.
--   
--   <pre>
--   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"
--   takeDirectory "foo\\bar" == "foo"
--   takeDirectory "foo\\bar\\\\" == "foo\\bar"
--   takeDirectory "C:\\" == "C:\\"
--   </pre>
takeDirectory :: WindowsPath -> WindowsPath

-- | Set the directory, keeping the filename the same.
--   
--   <pre>
--   replaceDirectory "root/file.ext" "/directory/" == "/directory/file.ext"
--   Valid x =&gt; replaceDirectory x (takeDirectory x) `equalFilePath` x
--   </pre>
replaceDirectory :: WindowsPath -> WindowsPath -> WindowsPath

-- | An alias for <a>&lt;/&gt;</a>.
combine :: WindowsPath -> WindowsPath -> WindowsPath

-- | 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 <tt>readFile (dir <a>&lt;/&gt;</a> file)</tt>
--   will access the same file as <tt>setCurrentDirectory dir; readFile
--   file</tt>.
--   
--   <pre>
--   "/directory" &lt;/&gt; "file.ext" == "/directory\\file.ext"
--   "directory" &lt;/&gt; "/file.ext" == "/file.ext"
--   Valid x =&gt; (takeDirectory x &lt;/&gt; takeFileName x) `equalFilePath` x
--   </pre>
--   
--   Combined:
--   
--   <pre>
--   "C:\\foo" &lt;/&gt; "bar" == "C:\\foo\\bar"
--   "home" &lt;/&gt; "bob" == "home\\bob"
--   </pre>
--   
--   Not combined:
--   
--   <pre>
--   "home" &lt;/&gt; "C:\\bob" == "C:\\bob"
--   </pre>
--   
--   Not combined (tricky):
--   
--   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 <a>&lt;/&gt;</a> is to never
--   combine these forms.
--   
--   <pre>
--   "home" &lt;/&gt; "/bob" == "/bob"
--   "home" &lt;/&gt; "\\bob" == "\\bob"
--   "C:\\home" &lt;/&gt; "\\bob" == "\\bob"
--   </pre>
--   
--   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 <a>&lt;/&gt;</a> is to never combine these forms.
--   
--   <pre>
--   "D:\\foo" &lt;/&gt; "C:bar" == "C:bar"
--   "C:\\foo" &lt;/&gt; "C:bar" == "C:bar"
--   </pre>
(</>) :: WindowsPath -> WindowsPath -> WindowsPath

-- | Split a path by the directory separator.
--   
--   <pre>
--   splitPath "/directory/file.ext" == ["/","directory/","file.ext"]
--   concat (splitPath x) == x
--   splitPath "test//item/" == ["test//","item/"]
--   splitPath "test/item/file" == ["test/","item/","file"]
--   splitPath "" == []
--   splitPath "c:\\test\\path" == ["c:\\","test\\","path"]
--   </pre>
splitPath :: WindowsPath -> [WindowsPath]

-- | Join path elements back together.
--   
--   <pre>
--   joinPath z == foldr (&lt;/&gt;) "" z
--   joinPath ["/","directory/","file.ext"] == "/directory/file.ext"
--   Valid x =&gt; joinPath (splitPath x) == x
--   joinPath [] == ""
--   </pre>
joinPath :: [WindowsPath] -> WindowsPath

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

-- | Split a path into a drive and a path.
--   
--   <pre>
--   uncurry (&lt;&gt;) (splitDrive x) == x
--   splitDrive "file" == ("","file")
--   splitDrive "c:/file" == ("c:/","file")
--   splitDrive "c:\\file" == ("c:\\","file")
--   splitDrive "\\\\shared\\test" == ("\\\\shared\\","test")
--   splitDrive "\\\\shared" == ("\\\\shared","")
--   splitDrive "\\\\?\\UNC\\shared\\file" == ("\\\\?\\UNC\\shared\\","file")
--   splitDrive "\\\\?\\UNCshared\\file" == ("\\\\?\\","UNCshared\\file")
--   splitDrive "\\\\?\\d:\\file" == ("\\\\?\\d:\\","file")
--   splitDrive "/d" == ("","/d")
--   </pre>
splitDrive :: WindowsPath -> (WindowsPath, WindowsPath)

-- | Join a drive and the rest of the path.
--   
--   <pre>
--   Valid x =&gt; 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"
--   </pre>
--   
--   Join a drive and the rest of the path.
--   
--   <pre>
--   Valid x =&gt; uncurry joinDrive (splitDrive x) == x
--   joinDrive "C:" "foo" == "C:foo"
--   joinDrive "C:\\" "bar" == "C:\\bar"
--   joinDrive "\\\\share" "foo" == "\\\\share\\foo"
--   joinDrive "/:" "foo" == "/:\\foo"
--   </pre>
joinDrive :: WindowsPath -> WindowsPath -> WindowsPath

-- | Get the drive from a filepath.
--   
--   <pre>
--   takeDrive x == fst (splitDrive x)
--   </pre>
takeDrive :: WindowsPath -> WindowsPath

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

-- | Delete the drive, if it exists.
--   
--   <pre>
--   dropDrive x == snd (splitDrive x)
--   </pre>
dropDrive :: WindowsPath -> WindowsPath

-- | Is an element a drive
--   
--   <pre>
--   isDrive "C:\\" == True
--   isDrive "C:\\foo" == False
--   isDrive "" == False
--   </pre>
isDrive :: WindowsPath -> Bool

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

-- | Add a trailing file path separator if one is not already present.
--   
--   <pre>
--   hasTrailingPathSeparator (addTrailingPathSeparator x)
--   hasTrailingPathSeparator x ==&gt; addTrailingPathSeparator x == x
--   </pre>
addTrailingPathSeparator :: WindowsPath -> WindowsPath

-- | Remove any trailing path separators
--   
--   <pre>
--   dropTrailingPathSeparator "file/test/" == "file/test"
--   dropTrailingPathSeparator "/" == "/"
--   dropTrailingPathSeparator "\\" == "\\"
--   </pre>
dropTrailingPathSeparator :: WindowsPath -> WindowsPath

-- | Normalise a file
--   
--   <ul>
--   <li>// outside of the drive can be made blank</li>
--   <li>/ -&gt; <a>pathSeparator</a></li>
--   <li>./ -&gt; ""</li>
--   </ul>
--   
--   Does not remove <tt>".."</tt>, because of symlinks.
--   
--   <pre>
--   normalise "c:\\file/bob\\" == "C:\\file\\bob\\"
--   normalise "c:\\" == "C:\\"
--   normalise "C:.\\" == "C:"
--   normalise "\\\\server\\test" == "\\\\server\\test"
--   normalise "//server/test" == "\\\\server\\test"
--   normalise "c:/file" == "C:\\file"
--   normalise "/file" == "\\file"
--   normalise "\\" == "\\"
--   normalise "/./" == "\\"
--   normalise "." == "."
--   </pre>
normalise :: WindowsPath -> WindowsPath

-- | Equality of two filepaths. If you call
--   <tt>System.Directory.canonicalizePath</tt> first this has a much
--   better chance of working. Note that this doesn't follow symlinks or
--   DOSNAM~1s.
--   
--   Similar to <a>normalise</a>, this does not expand <tt>".."</tt>,
--   because of symlinks.
--   
--   <pre>
--   x == y ==&gt; equalFilePath x y
--   normalise x == normalise y ==&gt; equalFilePath x y
--   equalFilePath "foo" "foo/"
--   not (equalFilePath "/a/../c" "/c")
--   not (equalFilePath "foo" "/foo")
--   equalFilePath "foo" "FOO"
--   not (equalFilePath "C:" "C:/")
--   </pre>
equalFilePath :: WindowsPath -> WindowsPath -> Bool

-- | Contract a filename, based on a relative path. Note that the resulting
--   path will never introduce <tt>..</tt> paths, as the presence of
--   symlinks means <tt>../b</tt> may not reach <tt>a/b</tt> if it starts
--   from <tt>a/c</tt>. For a worked example see <a>this blog post</a>.
--   
--   The corresponding <tt>makeAbsolute</tt> function can be found in
--   <tt>System.Directory</tt>.
--   
--   <pre>
--   makeRelative "/directory" "/directory/file.ext" == "file.ext"
--   Valid x =&gt; makeRelative (takeDirectory x) x `equalFilePath` takeFileName x
--   makeRelative x x == "."
--   Valid x y =&gt; equalFilePath x y || (isRelative x &amp;&amp; makeRelative y x == x) || equalFilePath (y &lt;/&gt; makeRelative y x) x
--   makeRelative "C:\\Home" "c:\\home\\bob" == "bob"
--   makeRelative "C:\\Home" "c:/home/bob" == "bob"
--   makeRelative "C:\\Home" "D:\\Home\\Bob" == "D:\\Home\\Bob"
--   makeRelative "C:\\Home" "C:Home\\Bob" == "C:Home\\Bob"
--   makeRelative "/Home" "/home/bob" == "bob"
--   makeRelative "/" "//" == "//"
--   </pre>
makeRelative :: WindowsPath -> WindowsPath -> WindowsPath

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

-- | <pre>
--   not . <a>isRelative</a>
--   </pre>
--   
--   <pre>
--   isAbsolute x == not (isRelative x)
--   </pre>
isAbsolute :: WindowsPath -> Bool

-- | Is a filepath 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.
--   
--   <pre>
--   isValid "" == False
--   isValid "\0" == False
--   isValid "c:\\test" == True
--   isValid "c:\\test:of_test" == False
--   isValid "test*" == False
--   isValid "c:\\test\\nul" == False
--   isValid "c:\\test\\prn.txt" == False
--   isValid "c:\\nul\\file" == False
--   isValid "\\\\" == False
--   isValid "\\\\\\foo" == False
--   isValid "\\\\?\\D:file" == False
--   isValid "foo\tbar" == False
--   isValid "nul .txt" == False
--   isValid " nul.txt" == True
--   </pre>
isValid :: WindowsPath -> Bool

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