module System.File.OsPath where

import qualified System.File.Platform as P

import Control.Exception (bracket)
import System.IO (IOMode(..), Handle, hSetBinaryMode, hClose)
import System.OsPath
import System.OsString.Internal.Types

import qualified Data.ByteString as BS
import qualified Data.ByteString.Lazy as BSL

-- | Like 'openFile', but open the file in binary mode.
-- On Windows, reading a file in text mode (which is the default)
-- will translate CRLF to LF, and writing will translate LF to CRLF.
-- This is usually what you want with text files.  With binary files
-- this is undesirable; also, as usual under Microsoft operating systems,
-- text mode treats control-Z as EOF.  Binary mode turns off all special
-- treatment of end-of-line and end-of-file characters.
-- (See also 'System.IO.hSetBinaryMode'.)

-- On POSIX systems, 'openBinaryFile' is an /interruptible operation/ as
-- described in "Control.Exception".
openBinaryFile :: OsPath -> IOMode -> IO Handle
openBinaryFile :: OsPath -> IOMode -> IO Handle
openBinaryFile OsPath
fp IOMode
iomode = do
  Handle
h <- OsPath -> IOMode -> IO Handle
openFile OsPath
fp IOMode
iomode
  Handle -> Bool -> IO ()
hSetBinaryMode Handle
h Bool
True
  Handle -> IO Handle
forall a. a -> IO a
forall (f :: * -> *) a. Applicative f => a -> f a
pure Handle
h

-- | Run an action on a file.
--
-- The 'Handle' is automatically closed afther the action.
withFile :: OsPath -> IOMode -> (Handle -> IO r) -> IO r
withFile :: forall r. OsPath -> IOMode -> (Handle -> IO r) -> IO r
withFile OsPath
fp IOMode
iomode Handle -> IO r
action = IO Handle -> (Handle -> IO ()) -> (Handle -> IO r) -> IO r
forall a b c. IO a -> (a -> IO b) -> (a -> IO c) -> IO c
bracket
  (OsPath -> IOMode -> IO Handle
openFile OsPath
fp IOMode
iomode)
  Handle -> IO ()
hClose
  Handle -> IO r
action

withBinaryFile :: OsPath -> IOMode -> (Handle -> IO r) -> IO r
withBinaryFile :: forall r. OsPath -> IOMode -> (Handle -> IO r) -> IO r
withBinaryFile OsPath
fp IOMode
iomode Handle -> IO r
action = IO Handle -> (Handle -> IO ()) -> (Handle -> IO r) -> IO r
forall a b c. IO a -> (a -> IO b) -> (a -> IO c) -> IO c
bracket
  (OsPath -> IOMode -> IO Handle
openBinaryFile OsPath
fp IOMode
iomode)
  Handle -> IO ()
hClose
  Handle -> IO r
action

-- | Run an action on a file.
--
-- The 'Handle' is not automatically closed to allow lazy IO. Use this
-- with caution.
withFile'
  :: OsPath -> IOMode -> (Handle -> IO r) -> IO r
withFile' :: forall r. OsPath -> IOMode -> (Handle -> IO r) -> IO r
withFile' OsPath
fp IOMode
iomode Handle -> IO r
action = do
  Handle
h <- OsPath -> IOMode -> IO Handle
openFile OsPath
fp IOMode
iomode
  Handle -> IO r
action Handle
h

withBinaryFile'
  :: OsPath -> IOMode -> (Handle -> IO r) -> IO r
withBinaryFile' :: forall r. OsPath -> IOMode -> (Handle -> IO r) -> IO r
withBinaryFile' OsPath
fp IOMode
iomode Handle -> IO r
action = do
  Handle
h <- OsPath -> IOMode -> IO Handle
openBinaryFile OsPath
fp IOMode
iomode
  Handle -> IO r
action Handle
h

-- | The 'readFile' function reads a file and returns the contents of the file
-- as a 'ByteString'. The file is read lazily, on demand.
readFile :: OsPath -> IO BSL.ByteString
readFile :: OsPath -> IO ByteString
readFile OsPath
fp = OsPath -> IOMode -> (Handle -> IO ByteString) -> IO ByteString
forall r. OsPath -> IOMode -> (Handle -> IO r) -> IO r
withFile' OsPath
fp IOMode
ReadMode Handle -> IO ByteString
BSL.hGetContents

-- | The 'readFile'' function reads a file and returns the contents of the file
-- as a 'ByteString'. The file is fully read before being returned.
readFile'
  :: OsPath -> IO BS.ByteString
readFile' :: OsPath -> IO ByteString
readFile' OsPath
fp = OsPath -> IOMode -> (Handle -> IO ByteString) -> IO ByteString
forall r. OsPath -> IOMode -> (Handle -> IO r) -> IO r
withFile OsPath
fp IOMode
ReadMode Handle -> IO ByteString
BS.hGetContents

-- | The computation 'writeFile' @file str@ function writes the lazy 'ByteString' @str@,
-- to the file @file@.
writeFile :: OsPath -> BSL.ByteString -> IO ()
writeFile :: OsPath -> ByteString -> IO ()
writeFile OsPath
fp ByteString
contents = OsPath -> IOMode -> (Handle -> IO ()) -> IO ()
forall r. OsPath -> IOMode -> (Handle -> IO r) -> IO r
withFile OsPath
fp IOMode
WriteMode (Handle -> ByteString -> IO ()
`BSL.hPut` ByteString
contents)

-- | The computation 'writeFile' @file str@ function writes the strict 'ByteString' @str@,
-- to the file @file@.
writeFile'
  :: OsPath -> BS.ByteString -> IO ()
writeFile' :: OsPath -> ByteString -> IO ()
writeFile' OsPath
fp ByteString
contents = OsPath -> IOMode -> (Handle -> IO ()) -> IO ()
forall r. OsPath -> IOMode -> (Handle -> IO r) -> IO r
withFile OsPath
fp IOMode
WriteMode (Handle -> ByteString -> IO ()
`BS.hPut` ByteString
contents)

-- | The computation 'appendFile' @file str@ function appends the lazy 'ByteString' @str@,
-- to the file @file@.
appendFile :: OsPath -> BSL.ByteString -> IO ()
appendFile :: OsPath -> ByteString -> IO ()
appendFile OsPath
fp ByteString
contents = OsPath -> IOMode -> (Handle -> IO ()) -> IO ()
forall r. OsPath -> IOMode -> (Handle -> IO r) -> IO r
withFile OsPath
fp IOMode
AppendMode (Handle -> ByteString -> IO ()
`BSL.hPut` ByteString
contents)

-- | The computation 'appendFile' @file str@ function appends the strict 'ByteString' @str@,
-- to the file @file@.
appendFile'
  :: OsPath -> BS.ByteString -> IO ()
appendFile' :: OsPath -> ByteString -> IO ()
appendFile' OsPath
fp ByteString
contents = OsPath -> IOMode -> (Handle -> IO ()) -> IO ()
forall r. OsPath -> IOMode -> (Handle -> IO r) -> IO r
withFile OsPath
fp IOMode
AppendMode (Handle -> ByteString -> IO ()
`BS.hPut` ByteString
contents)

-- | Open a file and return the 'Handle'.
openFile :: OsPath -> IOMode -> IO Handle
openFile :: OsPath -> IOMode -> IO Handle
openFile (OsString PlatformString
fp) = PlatformString -> IOMode -> IO Handle
P.openFile PlatformString
fp

-- | Open an existing file and return the 'Handle'.
openExistingFile :: OsPath -> IOMode -> IO Handle
openExistingFile :: OsPath -> IOMode -> IO Handle
openExistingFile (OsString PlatformString
fp) = PlatformString -> IOMode -> IO Handle
P.openExistingFile PlatformString
fp