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


-- | Cross-platform File handling
--   
--   Cross-platform File handling for Unix/Mac/Windows
@package easy-file
@version 0.2.1


-- | This is a module of cross-platform file handling for Unix/Mac/Windows.
--   
--   The standard module <a>System.Directory</a> and <a>System.FilePath</a>
--   have following shortcomings:
--   
--   <ul>
--   <li>getModificationTime exists in <a>System.Directory</a>. But
--   getAccessTime, getChangeTime, getCreationTime do not exist.</li>
--   <li>getModificationTime returns obsoleted type, <tt>ClockTime</tt>. It
--   should return modern type, <tt>UTCTime</tt>, I believe.</li>
--   <li>Some file functions are missing. A function to tell the link
--   counter, for instance.</li>
--   <li>Path separator is not unified. Even though Windows accepts '/' as
--   a file separator, getCurrentDirectory in <a>System.Directory</a>
--   returns '\' as a file separator. So, we need to specify regular
--   expression like this: "[/\\]foo[/\\]bar[/\\]baz".</li>
--   <li>getHomeDirectory returns <tt>HOMEDRIVE</tt>/<tt>HOMEPATH</tt>
--   instead of the <tt>HOME</tt> environment variable on Windows.</li>
--   </ul>
--   
--   This module aims to resolve these problems and provides:
--   
--   <ul>
--   <li><a>getModificationTime</a>, <a>getAccessTime</a>,
--   <a>getChangeTime</a>, and <a>getCreationTime</a>. They return
--   <tt>UTCTime</tt>.</li>
--   <li><a>isSymlink</a>, <a>getLinkCount</a>, and
--   <a>hasSubDirectories</a>.</li>
--   <li>'/' as the single <a>pathSeparator</a>. For instance,
--   <a>getCurrentDirectory</a> returns a path whose separator is '/' even
--   on Windows.</li>
--   <li><a>getHomeDirectory2</a> which refers the <tt>HOME</tt>
--   environment variable.</li>
--   <li>Necessary functions in <a>System.Directory</a> and
--   <a>System.FilePath</a>.</li>
--   </ul>
module System.EasyFile

-- | <tt><a>createDirectory</a> dir</tt> creates a new directory
--   <tt>dir</tt> which is initially empty, or as near to empty as the
--   operating system allows.
--   
--   The operation may fail with:
--   
--   <ul>
--   <li><a>isPermissionError</a> / <tt>PermissionDenied</tt> The process
--   has insufficient privileges to perform the operation. <tt>[EROFS,
--   EACCES]</tt></li>
--   <li><a>isAlreadyExistsError</a> / <tt>AlreadyExists</tt> The operand
--   refers to a directory that already exists. <tt> [EEXIST]</tt></li>
--   <li><tt>HardwareFault</tt> A physical I/O error has occurred.
--   <tt>[EIO]</tt></li>
--   <li><tt>InvalidArgument</tt> The operand is not a valid directory
--   name. <tt>[ENAMETOOLONG, ELOOP]</tt></li>
--   <li><tt>NoSuchThing</tt> There is no path to the directory.
--   <tt>[ENOENT, ENOTDIR]</tt></li>
--   <li><tt>ResourceExhausted</tt> Insufficient resources (virtual memory,
--   process file descriptors, physical disk space, etc.) are available to
--   perform the operation. <tt>[EDQUOT, ENOSPC, ENOMEM, EMLINK]</tt></li>
--   <li><a>InappropriateType</a> The path refers to an existing
--   non-directory object. <tt>[EEXIST]</tt></li>
--   </ul>
createDirectory :: FilePath -> IO ()

-- | <tt><a>createDirectoryIfMissing</a> parents dir</tt> creates a new
--   directory <tt>dir</tt> if it doesn't exist. If the first argument is
--   <a>True</a> the function will also create all parent directories if
--   they are missing.
createDirectoryIfMissing :: Bool -> FilePath -> IO ()

-- | <tt><a>removeDirectory</a> dir</tt> removes an existing directory
--   <i>dir</i>. The implementation may specify additional constraints
--   which must be satisfied before a directory can be removed (e.g. the
--   directory has to be empty, or may not be in use by other processes).
--   It is not legal for an implementation to partially remove a directory
--   unless the entire directory is removed. A conformant implementation
--   need not support directory removal in all situations (e.g. removal of
--   the root directory).
--   
--   The operation may fail with:
--   
--   <ul>
--   <li><tt>HardwareFault</tt> A physical I/O error has occurred.
--   <tt>[EIO]</tt></li>
--   <li><tt>InvalidArgument</tt> The operand is not a valid directory
--   name. <tt>[ENAMETOOLONG, ELOOP]</tt></li>
--   <li><a>isDoesNotExistError</a> / <tt>NoSuchThing</tt> The directory
--   does not exist. <tt>[ENOENT, ENOTDIR]</tt></li>
--   <li><a>isPermissionError</a> / <tt>PermissionDenied</tt> The process
--   has insufficient privileges to perform the operation. <tt>[EROFS,
--   EACCES, EPERM]</tt></li>
--   <li><tt>UnsatisfiedConstraints</tt> Implementation-dependent
--   constraints are not satisfied. <tt>[EBUSY, ENOTEMPTY,
--   EEXIST]</tt></li>
--   <li><a>UnsupportedOperation</a> The implementation does not support
--   removal in this situation. <tt>[EINVAL]</tt></li>
--   <li><a>InappropriateType</a> The operand refers to an existing
--   non-directory object. <tt>[ENOTDIR]</tt></li>
--   </ul>
removeDirectory :: FilePath -> IO ()

-- | <tt><a>removeDirectoryRecursive</a> dir</tt> removes an existing
--   directory <i>dir</i> together with its contents and subdirectories.
--   Within this directory, symbolic links are removed without affecting
--   their targets.
--   
--   On Windows, the operation fails if <i>dir</i> is a directory symbolic
--   link.
removeDirectoryRecursive :: FilePath -> IO ()

-- | <tt><a>renameDirectory</a> old new</tt> changes the name of an
--   existing directory from <i>old</i> to <i>new</i>. If the <i>new</i>
--   directory already exists, it is atomically replaced by the <i>old</i>
--   directory. If the <i>new</i> directory is neither the <i>old</i>
--   directory nor an alias of the <i>old</i> directory, it is removed as
--   if by <a>removeDirectory</a>. A conformant implementation need not
--   support renaming directories in all situations (e.g. renaming to an
--   existing directory, or across different physical devices), but the
--   constraints must be documented.
--   
--   On Win32 platforms, <tt>renameDirectory</tt> fails if the <i>new</i>
--   directory already exists.
--   
--   The operation may fail with:
--   
--   <ul>
--   <li><tt>HardwareFault</tt> A physical I/O error has occurred.
--   <tt>[EIO]</tt></li>
--   <li><tt>InvalidArgument</tt> Either operand is not a valid directory
--   name. <tt>[ENAMETOOLONG, ELOOP]</tt></li>
--   <li><a>isDoesNotExistError</a> / <tt>NoSuchThing</tt> The original
--   directory does not exist, or there is no path to the target.
--   <tt>[ENOENT, ENOTDIR]</tt></li>
--   <li><a>isPermissionError</a> / <tt>PermissionDenied</tt> The process
--   has insufficient privileges to perform the operation. <tt>[EROFS,
--   EACCES, EPERM]</tt></li>
--   <li><tt>ResourceExhausted</tt> Insufficient resources are available to
--   perform the operation. <tt>[EDQUOT, ENOSPC, ENOMEM, EMLINK]</tt></li>
--   <li><tt>UnsatisfiedConstraints</tt> Implementation-dependent
--   constraints are not satisfied. <tt>[EBUSY, ENOTEMPTY,
--   EEXIST]</tt></li>
--   <li><a>UnsupportedOperation</a> The implementation does not support
--   renaming in this situation. <tt>[EINVAL, EXDEV]</tt></li>
--   <li><a>InappropriateType</a> Either path refers to an existing
--   non-directory object. <tt>[ENOTDIR, EISDIR]</tt></li>
--   </ul>
renameDirectory :: FilePath -> FilePath -> IO ()

-- | Similar to <a>listDirectory</a>, but always includes the special
--   entries (<tt>.</tt> and <tt>..</tt>). (This applies to Windows as
--   well.)
--   
--   The operation may fail with the same exceptions as
--   <a>listDirectory</a>.
getDirectoryContents :: FilePath -> IO [FilePath]

-- | If the operating system has a notion of current directories,
--   <a>getCurrentDirectory</a> returns an absolute path to the current
--   directory of the calling process.
--   
--   The operation may fail with:
--   
--   <ul>
--   <li><tt>HardwareFault</tt> A physical I/O error has occurred.
--   <tt>[EIO]</tt></li>
--   <li><tt>isDoesNotExistError</tt> / <tt>NoSuchThing</tt> There is no
--   path referring to the current directory. <tt>[EPERM, ENOENT,
--   ESTALE...]</tt></li>
--   <li><tt>isPermissionError</tt> / <tt>PermissionDenied</tt> The process
--   has insufficient privileges to perform the operation.
--   <tt>[EACCES]</tt></li>
--   <li><tt>ResourceExhausted</tt> Insufficient resources are available to
--   perform the operation.</li>
--   <li><tt>UnsupportedOperation</tt> The operating system has no notion
--   of current directory.</li>
--   </ul>
getCurrentDirectory :: IO FilePath

-- | Change the working directory to the given path.
--   
--   In a multithreaded program, the current working directory is a global
--   state shared among all threads of the process. Therefore, when
--   performing filesystem operations from multiple threads, it is highly
--   recommended to use absolute rather than relative paths (see:
--   <a>makeAbsolute</a>).
--   
--   The operation may fail with:
--   
--   <ul>
--   <li><tt>HardwareFault</tt> A physical I/O error has occurred.
--   <tt>[EIO]</tt></li>
--   <li><tt>InvalidArgument</tt> The operand is not a valid directory
--   name. <tt>[ENAMETOOLONG, ELOOP]</tt></li>
--   <li><a>isDoesNotExistError</a> or <tt>NoSuchThing</tt> The directory
--   does not exist. <tt>[ENOENT, ENOTDIR]</tt></li>
--   <li><a>isPermissionError</a> or <tt>PermissionDenied</tt> The process
--   has insufficient privileges to perform the operation.
--   <tt>[EACCES]</tt></li>
--   <li><a>UnsupportedOperation</a> The operating system has no notion of
--   current working directory, or the working directory cannot be
--   dynamically changed.</li>
--   <li><a>InappropriateType</a> The path refers to an existing
--   non-directory object. <tt>[ENOTDIR]</tt></li>
--   </ul>
setCurrentDirectory :: FilePath -> IO ()

-- | Returns the current user's home directory.
--   
--   The directory returned is expected to be writable by the current user,
--   but note that it isn't generally considered good practice to store
--   application-specific data here; use <a>getAppUserDataDirectory</a>
--   instead.
--   
--   On Unix, <a>getHomeDirectory</a> returns the value of the
--   <tt>HOME</tt> environment variable. On Windows, the system is queried
--   for a suitable path; a typical path might be <tt>C:<i>Documents And
--   Settings</i>user</tt>.
--   
--   The operation may fail with:
--   
--   <ul>
--   <li><tt>UnsupportedOperation</tt> The operating system has no notion
--   of home directory.</li>
--   <li><tt>isDoesNotExistError</tt> The home directory for the current
--   user does not exist, or cannot be found.</li>
--   </ul>
getHomeDirectory :: IO FilePath

-- | Returns the current user's home directory from the <tt>HOME</tt>
--   environment variable.
getHomeDirectory2 :: IO (Maybe FilePath)

-- | Returns the pathname of a directory in which application-specific data
--   for the current user can be stored. The result of
--   <a>getAppUserDataDirectory</a> for a given application is specific to
--   the current user.
--   
--   The argument should be the name of the application, which will be used
--   to construct the pathname (so avoid using unusual characters that
--   might result in an invalid pathname).
--   
--   Note: the directory may not actually exist, and may need to be created
--   first. It is expected that the parent directory exists and is
--   writable.
--   
--   On Unix, this function returns <tt>$HOME/.appName</tt>. On Windows, a
--   typical path might be
--   
--   <pre>
--   C:/Documents And Settings/user/Application Data/appName
--   </pre>
--   
--   The operation may fail with:
--   
--   <ul>
--   <li><tt>UnsupportedOperation</tt> The operating system has no notion
--   of application-specific data directory.</li>
--   <li><tt>isDoesNotExistError</tt> The home directory for the current
--   user does not exist, or cannot be found.</li>
--   </ul>
getAppUserDataDirectory :: String -> IO FilePath

-- | Returns the current user's document directory.
--   
--   The directory returned is expected to be writable by the current user,
--   but note that it isn't generally considered good practice to store
--   application-specific data here; use <a>getAppUserDataDirectory</a>
--   instead.
--   
--   On Unix, <a>getUserDocumentsDirectory</a> returns the value of the
--   <tt>HOME</tt> environment variable. On Windows, the system is queried
--   for a suitable path; a typical path might be <tt>C:/Documents and
--   Settings/user/My Documents</tt>.
--   
--   The operation may fail with:
--   
--   <ul>
--   <li><tt>UnsupportedOperation</tt> The operating system has no notion
--   of document directory.</li>
--   <li><tt>isDoesNotExistError</tt> The document directory for the
--   current user does not exist, or cannot be found.</li>
--   </ul>
getUserDocumentsDirectory :: IO FilePath

-- | Returns the current directory for temporary files.
--   
--   On Unix, <a>getTemporaryDirectory</a> returns the value of the
--   <tt>TMPDIR</tt> environment variable or "/tmp" if the variable isn't
--   defined. On Windows, the function checks for the existence of
--   environment variables in the following order and uses the first path
--   found:
--   
--   <ul>
--   <li>TMP environment variable.</li>
--   <li>TEMP environment variable.</li>
--   <li>USERPROFILE environment variable.</li>
--   <li>The Windows directory</li>
--   </ul>
--   
--   The operation may fail with:
--   
--   <ul>
--   <li><tt>UnsupportedOperation</tt> The operating system has no notion
--   of temporary directory.</li>
--   </ul>
--   
--   The function doesn't verify whether the path exists.
getTemporaryDirectory :: IO FilePath

-- | <a>removeFile</a> <i>file</i> removes the directory entry for an
--   existing file <i>file</i>, where <i>file</i> is not itself a
--   directory. The implementation may specify additional constraints which
--   must be satisfied before a file can be removed (e.g. the file may not
--   be in use by other processes).
--   
--   The operation may fail with:
--   
--   <ul>
--   <li><tt>HardwareFault</tt> A physical I/O error has occurred.
--   <tt>[EIO]</tt></li>
--   <li><tt>InvalidArgument</tt> The operand is not a valid file name.
--   <tt>[ENAMETOOLONG, ELOOP]</tt></li>
--   <li><a>isDoesNotExistError</a> / <tt>NoSuchThing</tt> The file does
--   not exist. <tt>[ENOENT, ENOTDIR]</tt></li>
--   <li><a>isPermissionError</a> / <tt>PermissionDenied</tt> The process
--   has insufficient privileges to perform the operation. <tt>[EROFS,
--   EACCES, EPERM]</tt></li>
--   <li><tt>UnsatisfiedConstraints</tt> Implementation-dependent
--   constraints are not satisfied. <tt>[EBUSY]</tt></li>
--   <li><a>InappropriateType</a> The operand refers to an existing
--   directory. <tt>[EPERM, EINVAL]</tt></li>
--   </ul>
removeFile :: FilePath -> IO ()

-- | <tt><a>renameFile</a> old new</tt> changes the name of an existing
--   file system object from <i>old</i> to <i>new</i>. If the <i>new</i>
--   object already exists, it is atomically replaced by the <i>old</i>
--   object. Neither path may refer to an existing directory. A conformant
--   implementation need not support renaming files in all situations (e.g.
--   renaming across different physical devices), but the constraints must
--   be documented.
--   
--   The operation may fail with:
--   
--   <ul>
--   <li><tt>HardwareFault</tt> A physical I/O error has occurred.
--   <tt>[EIO]</tt></li>
--   <li><tt>InvalidArgument</tt> Either operand is not a valid file name.
--   <tt>[ENAMETOOLONG, ELOOP]</tt></li>
--   <li><a>isDoesNotExistError</a> / <tt>NoSuchThing</tt> The original
--   file does not exist, or there is no path to the target. <tt>[ENOENT,
--   ENOTDIR]</tt></li>
--   <li><a>isPermissionError</a> / <tt>PermissionDenied</tt> The process
--   has insufficient privileges to perform the operation. <tt>[EROFS,
--   EACCES, EPERM]</tt></li>
--   <li><tt>ResourceExhausted</tt> Insufficient resources are available to
--   perform the operation. <tt>[EDQUOT, ENOSPC, ENOMEM, EMLINK]</tt></li>
--   <li><tt>UnsatisfiedConstraints</tt> Implementation-dependent
--   constraints are not satisfied. <tt>[EBUSY]</tt></li>
--   <li><a>UnsupportedOperation</a> The implementation does not support
--   renaming in this situation. <tt>[EXDEV]</tt></li>
--   <li><a>InappropriateType</a> Either path refers to an existing
--   directory. <tt>[ENOTDIR, EISDIR, EINVAL, EEXIST, ENOTEMPTY]</tt></li>
--   </ul>
renameFile :: FilePath -> FilePath -> IO ()

-- | Copy a file with its permissions. If the destination file already
--   exists, it is replaced atomically. Neither path may refer to an
--   existing directory. No exceptions are thrown if the permissions could
--   not be copied.
copyFile :: FilePath -> FilePath -> IO ()

-- | Make a path absolute, <a>normalise</a> the path, and remove as many
--   indirections from it as possible. Any trailing path separators are
--   discarded via <a>dropTrailingPathSeparator</a>. Additionally, on
--   Windows the letter case of the path is canonicalized.
--   
--   <b>Note</b>: This function is a very big hammer. If you only need an
--   absolute path, <a>makeAbsolute</a> is sufficient for removing
--   dependence on the current working directory.
--   
--   Indirections include the two special directories <tt>.</tt> and
--   <tt>..</tt>, as well as any symbolic links. The input path need not
--   point to an existing file or directory. Canonicalization is performed
--   on the longest prefix of the path that points to an existing file or
--   directory. The remaining portion of the path that does not point to an
--   existing file or directory will still undergo <a>normalise</a>, but
--   case canonicalization and indirection removal are skipped as they are
--   impossible to do on a nonexistent path.
--   
--   Most programs should not worry about the canonicity of a path. In
--   particular, despite the name, the function does not truly guarantee
--   canonicity of the returned path due to the presence of hard links,
--   mount points, etc.
--   
--   If the path points to an existing file or directory, then the output
--   path shall also point to the same file or directory, subject to the
--   condition that the relevant parts of the file system do not change
--   while the function is still running. In other words, the function is
--   definitively not atomic. The results can be utterly wrong if the
--   portions of the path change while this function is running.
--   
--   Since symbolic links (and, on non-Windows systems, parent directories
--   <tt>..</tt>) are dependent on the state of the existing filesystem,
--   the function can only make a conservative attempt by removing such
--   indirections from the longest prefix of the path that still points to
--   an existing file or directory.
--   
--   Note that on Windows parent directories <tt>..</tt> are always fully
--   expanded before the symbolic links, as consistent with the rest of the
--   Windows API (such as <tt>GetFullPathName</tt>). In contrast, on POSIX
--   systems parent directories <tt>..</tt> are expanded alongside symbolic
--   links from left to right. To put this more concretely: if <tt>L</tt>
--   is a symbolic link for <tt>R/P</tt>, then on Windows <tt>L\..</tt>
--   refers to <tt>.</tt>, whereas on other operating systems <tt>L/..</tt>
--   refers to <tt>R</tt>.
--   
--   Similar to <a>normalise</a>, passing an empty path is equivalent to
--   passing the current directory.
--   
--   <i>Known bugs</i>: When the path contains an existing symbolic link,
--   but the target of the link does not exist, then the path is not
--   dereferenced (bug #64). Symbolic link expansion is not performed on
--   Windows XP or earlier due to the absence of
--   <tt>GetFinalPathNameByHandle</tt>.
--   
--   <i>Changes since 1.2.3.0:</i> The function has been altered to be more
--   robust and has the same exception behavior as <a>makeAbsolute</a>.
--   
--   <i>Changes since 1.3.0.0:</i> The function no longer preserves the
--   trailing path separator. File symbolic links that appear in the middle
--   of a path are properly dereferenced. Case canonicalization and
--   symbolic link expansion are now performed on Windows.
canonicalizePath :: FilePath -> IO FilePath

-- | The operation <a>doesFileExist</a> returns <a>True</a> if the argument
--   file exists and is not a directory, and <a>False</a> otherwise.
doesFileExist :: FilePath -> IO Bool

-- | The operation <a>doesDirectoryExist</a> returns <a>True</a> if the
--   argument file exists and is either a directory or a symbolic link to a
--   directory, and <a>False</a> otherwise.
doesDirectoryExist :: FilePath -> IO Bool
data Permissions :: *

-- | The <a>getPermissions</a> operation returns the permissions for the
--   file or directory.
--   
--   The operation may fail with:
--   
--   <ul>
--   <li><a>isPermissionError</a> if the user is not permitted to access
--   the permissions; or</li>
--   <li><a>isDoesNotExistError</a> if the file or directory does not
--   exist.</li>
--   </ul>
getPermissions :: FilePath -> IO Permissions

-- | The <a>setPermissions</a> operation sets the permissions for the file
--   or directory.
--   
--   The operation may fail with:
--   
--   <ul>
--   <li><a>isPermissionError</a> if the user is not permitted to set the
--   permissions; or</li>
--   <li><a>isDoesNotExistError</a> if the file or directory does not
--   exist.</li>
--   </ul>
setPermissions :: FilePath -> Permissions -> IO ()

-- | This function copy the permission of the first file to the second.
copyPermissions :: FilePath -> FilePath -> IO ()

-- | The <a>getCreationTime</a> operation returns the UTC time at which the
--   file or directory was created. The time is only available on Windows.
getCreationTime :: FilePath -> IO (Maybe UTCTime)

-- | The <a>getChangeTime</a> operation returns the UTC time at which the
--   file or directory was changed. The time is only available on Unix and
--   Mac. Note that Unix's rename() does not change ctime but MacOS's
--   rename() does.
getChangeTime :: FilePath -> IO (Maybe UTCTime)

-- | The <a>getModificationTime</a> operation returns the UTC time at which
--   the file or directory was last modified.
--   
--   The operation may fail with:
--   
--   <ul>
--   <li><tt>isPermissionError</tt> if the user is not permitted to access
--   the modification time; or</li>
--   <li><tt>isDoesNotExistError</tt> if the file or directory does not
--   exist.</li>
--   </ul>
getModificationTime :: FilePath -> IO UTCTime

-- | The <a>getModificationTime</a> operation returns the UTC time at which
--   the file or directory was last accessed.
getAccessTime :: FilePath -> IO UTCTime

-- | Getting the size of the file.
getFileSize :: FilePath -> IO Word64

-- | This function tells whether or not a file/directory is symbolic link.
isSymlink :: FilePath -> IO Bool

-- | This function returns the link counter of a file/directory.
getLinkCount :: FilePath -> IO (Maybe Int)

-- | This function returns whether or not a directory has sub-directories.
hasSubDirectories :: FilePath -> IO (Maybe Bool)

-- | 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.
--   
--   <pre>
--   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

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

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

-- | Split on the extension. <a>addExtension</a> is the inverse.
--   
--   <pre>
--   uncurry (++) (splitExtension x) == x
--   uncurry addExtension (splitExtension x) == x
--   splitExtension "file.txt" == ("file",".txt")
--   splitExtension "file" == ("file","")
--   splitExtension "file/file.txt" == ("file/file",".txt")
--   splitExtension "file.txt/boris" == ("file.txt/boris","")
--   splitExtension "file.txt/boris.ext" == ("file.txt/boris",".ext")
--   splitExtension "file/path.txt.bob.fred" == ("file/path.txt.bob",".fred")
--   splitExtension "file/path.txt/" == ("file/path.txt/","")
--   </pre>
splitExtension :: FilePath -> (String, String)

-- | Get the extension of a file, returns <tt>""</tt> for no extension,
--   <tt>.ext</tt> otherwise.
--   
--   <pre>
--   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.
--   
--   <pre>
--   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"
--   </pre>
replaceExtension :: FilePath -> String -> FilePath

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

-- | Add an extension, even if there is already one there. E.g.
--   <tt>addExtension "foo.txt" "bat" -&gt; "foo.txt.bat"</tt>.
--   
--   <pre>
--   addExtension "file.txt" "bib" == "file.txt.bib"
--   addExtension "file." ".bib" == "file..bib"
--   addExtension "file" ".bib" == "file.bib"
--   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>
--   null (takeExtension x) == not (hasExtension x)
--   </pre>
hasExtension :: FilePath -> Bool

-- | Alias to <a>addExtension</a>, for people who like that sort of thing.
(<.>) :: FilePath -> String -> FilePath
infixr 7 <.>

-- | Split on all extensions
--   
--   <pre>
--   splitExtensions "file.tar.gz" == ("file",".tar.gz")
--   </pre>
splitExtensions :: FilePath -> (FilePath, String)

-- | Drop all extensions
--   
--   <pre>
--   not $ hasExtension (dropExtensions x)
--   </pre>
dropExtensions :: FilePath -> FilePath

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

-- | Split a path into a drive and a path. On Unix, / is a Drive.
--   
--   <pre>
--   uncurry (++) (splitDrive x) == x
--   Windows: splitDrive "file" == ("","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") -- xxx
--   Posix:   splitDrive "/test" == ("/","test") -- xxx
--   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>
--            uncurry joinDrive (splitDrive x) == x
--   Windows: joinDrive "C:" "foo" == "C:foo"
--   Windows: joinDrive "C:/" "bar" == "C:/bar"
--   Windows: joinDrive "\\\\share" "foo" == "\\\\share/foo" -- xxx
--   Windows: joinDrive "/:" "foo" == "/:/foo" -- xxx
--   </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)
--   </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
isDrive :: FilePath -> Bool

-- | Split a filename into directory and file. <a>combine</a> is the
--   inverse.
--   
--   <pre>
--   uncurry (++) (splitFileName x) == x
--   Valid x =&gt; uncurry combine (splitFileName x) == x
--   splitFileName "file/bob.txt" == ("file/", "bob.txt")
--   splitFileName "file/" == ("file/", "")
--   splitFileName "bob" == ("", "bob")
--   Posix:   splitFileName "/" == ("/","")
--   Windows: splitFileName "c:" == ("c:","")
--   </pre>
splitFileName :: FilePath -> (String, String)

-- | Get the file name.
--   
--   <pre>
--   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 :: FilePath -> FilePath

-- | Set the filename.
--   
--   <pre>
--   Valid x =&gt; replaceFileName x (takeFileName x) == x
--   </pre>
replaceFileName :: FilePath -> String -> FilePath

-- | Drop the filename.
--   
--   <pre>
--   dropFileName x == fst (splitFileName x)
--   </pre>
dropFileName :: FilePath -> FilePath

-- | Get the base name, without an extension or path.
--   
--   <pre>
--   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 "file/test.txt" "bob" == "file/bob.txt"
--   replaceBaseName "fred" "bill" == "bill"
--   replaceBaseName "/dave/fred/bob.gz.tar" "new" == "/dave/fred/new.tar"
--   replaceBaseName x (takeBaseName x) == x
--   </pre>
replaceBaseName :: FilePath -> String -> FilePath

-- | Get the directory name, move up one level.
--   
--   <pre>
--             takeDirectory x `isPrefixOf` x
--             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\\bar" -- xxx
--   Windows:  takeDirectory "C:/" == "C:/"
--   </pre>
takeDirectory :: FilePath -> FilePath

-- | Set the directory, keeping the filename the same.
--   
--   <pre>
--   replaceDirectory x (takeDirectory x) `equalFilePath` x
--   </pre>
replaceDirectory :: FilePath -> String -> FilePath

-- | Combine two paths, if the second path <a>isAbsolute</a>, then it
--   returns the second.
--   
--   <pre>
--   Valid x =&gt; combine (takeDirectory x) (takeFileName x) `equalFilePath` x
--   combine "/" "test" == "/test"
--   combine "home" "bob" == "home/bob"
--   </pre>
combine :: FilePath -> FilePath -> FilePath

-- | A nice alias for <a>combine</a>.
(</>) :: FilePath -> FilePath -> FilePath
infixr 5 </>

-- | Split a path by the directory separator.
--   
--   <pre>
--   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>
--   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 "test/file" == ["test","file"]
--   splitDirectories "/test/file" == ["/","test","file"]
--   Valid x =&gt; joinPath (splitDirectories x) `equalFilePath` x
--   splitDirectories "" == []
--   </pre>
splitDirectories :: FilePath -> [FilePath]

-- | 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
--   addTrailingPathSeparator "test/rest" == "test/rest/"
--   </pre>
addTrailingPathSeparator :: FilePath -> FilePath

-- | Remove any trailing path separators
--   
--   <pre>
--   dropTrailingPathSeparator "file/test/" == "file/test"
--   not (hasTrailingPathSeparator (dropTrailingPathSeparator x)) || isDrive x
--   dropTrailingPathSeparator "/" == "/"
--   </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>
--   
--   <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 "./bob/fred/" == "bob/fred/"
--   Windows: normalise "c:\\file/bob\\" == "C:/file/bob/"
--   Windows: normalise "c:/" == "C:/"
--   Windows: normalise "\\\\server\\test" == "\\\\server\\test" -- xxx
--   Windows: normalise "." == "."
--   Posix:   normalise "./" == "./"
--   </pre>
normalise :: FilePath -> FilePath

-- | Equality of two <a>FilePath</a>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.
--   
--   <pre>
--            x == y ==&gt; equalFilePath x y
--            normalise x == normalise y ==&gt; equalFilePath x y
--   Posix:   equalFilePath "foo" "foo/"
--   Posix:   not (equalFilePath "foo" "/foo")
--   Posix:   not (equalFilePath "foo" "FOO")
--   Windows: equalFilePath "foo" "FOO"
--   </pre>
equalFilePath :: FilePath -> FilePath -> Bool

-- | Contract a filename, based on a relative path.
--   
--   There is no corresponding <tt>makeAbsolute</tt> function, instead use
--   <tt>System.Directory.canonicalizePath</tt> which has the same effect.
--   
--   <pre>
--            Valid y =&gt; equalFilePath x y || (isRelative x &amp;&amp; makeRelative y x == x) || equalFilePath (y &lt;/&gt; makeRelative y x) x
--            makeRelative x x == "."
--            null y || equalFilePath (makeRelative x (x &lt;/&gt; y)) y || null (takeFileName x)
--   Windows: makeRelative "C:/Home" "c:/home/bob" == "bob"
--   Windows: makeRelative "C:/Home" "D:/Home/Bob" == "D:/Home/Bob"
--   Windows: makeRelative "C:/Home" "C:Home/Bob" == "C:Home/Bob"
--   Windows: makeRelative "/Home" "/home/bob" == "bob"
--   Posix:   makeRelative "/Home" "/home/bob" == "/home/bob"
--   Posix:   makeRelative "/home/" "/home/bob/foo/bar" == "bob/foo/bar"
--   Posix:   makeRelative "/fred" "bob" == "bob"
--   Posix:   makeRelative "/file/test" "/file/test/fred" == "fred"
--   Posix:   makeRelative "/file/test" "/file/test/fred/" == "fred/"
--   Posix:   makeRelative "some/path" "some/path/a/b/c" == "a/b/c"
--   </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:" == True
--   Windows: isRelative "\\\\foo" == False
--   Windows: isRelative "/foo" == True
--   Posix:   isRelative "test/path" == True
--   Posix:   isRelative "/test" == False
--   </pre>
isRelative :: FilePath -> Bool

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