    {-# LANGUAGE BangPatterns, CPP, RecordWildCards #-}
    {-# LANGUAGE Trustworthy #-}
    -- |
    -- Module      : Data.Text.Lazy.IO
    -- Copyright   : (c) 2009, 2010 Bryan O'Sullivan,
    --               (c) 2009 Simon Marlow
    -- License     : BSD-style
    -- Maintainer  : bos@serpentine.com
    -- Portability : GHC
    --
    -- Efficient locale-sensitive support for lazy text I\/O.
    --
    -- The functions in this module obey the runtime system's locale,
    -- character set encoding, and line ending conversion settings.
    --
    -- If you know in advance that you will be working with data that has
    -- a specific encoding (e.g. UTF-8), and your application is highly
    -- performance sensitive, you may find that it is faster to perform
    -- I\/O with bytestrings and to encode and decode yourself than to use
    -- the functions in this module.

    module Data.Text.Lazy.IO
        (
        -- * File-at-a-time operations
          readFile
        , writeFile
        , appendFile
        -- * Operations on handles
        , hGetContents
        , hGetLine
        , hPutStr
        , hPutStrLn
        -- * Special cases for standard input and output
        , interact
        , getContents
        , getLine
        , putStr
        , putStrLn
        ) where

    import Data.Text.Lazy (Text)
    import Prelude hiding (appendFile, getContents, getLine, interact,
                           putStr, putStrLn, readFile, writeFile)
    import System.IO (Handle, IOMode(..), openFile, stdin, stdout,
                      withFile)
    import qualified Data.Text.Lazy as L
    import qualified Control.Exception as E
    import Control.Monad (when)
    import Data.IORef (readIORef)
    import Data.Text.Internal.IO (hGetLineWith, readChunk, hPutStream)
    import Data.Text.Internal.Lazy (chunk, empty)
    import Data.Text.Internal.Lazy.Fusion (stream, streamLn)
    import GHC.IO.Buffer (isEmptyBuffer)
    import GHC.IO.Exception (IOException(..), IOErrorType(..), ioException)
    import GHC.IO.Handle.Internals (augmentIOError, hClose_help,
                                    wantReadableHandle, withHandle)
    import GHC.IO.Handle.Types (Handle__(..), HandleType(..))
    import System.IO (BufferMode(..), hGetBuffering, hSetBuffering)
    import System.IO.Error (isEOFError)
    import System.IO.Unsafe (unsafeInterleaveIO)

    -- | Read a file and return its contents as a string.  The file is
    -- read lazily, as with 'getContents'.
    --
    -- Beware that this function (similarly to 'Prelude.readFile') is locale-dependent.
    -- Unexpected system locale may cause your application to read corrupted data or
    -- throw runtime exceptions about "invalid argument (invalid byte sequence)"
    -- or "invalid argument (invalid character)". This is also slow, because GHC
    -- first converts an entire input to UTF-32, which is afterwards converted to UTF-8.
    --
    -- If your data is UTF-8,
    -- using 'Data.Text.Lazy.Encoding.decodeUtf8' '.' 'Data.ByteString.Lazy.readFile'
    -- is a much faster and safer alternative.
    readFile :: FilePath -> IO Text
    readFile :: FilePath -> IO Text
    readFile FilePath
    name = FilePath -> IOMode -> IO Handle
    openFile FilePath
    name IOMode
    ReadMode IO Handle -> (Handle -> IO Text) -> IO Text
    forall a b. IO a -> (a -> IO b) -> IO b
    forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
    >>= Handle -> IO Text
    hGetContents

    -- | Write a string to a file.  The file is truncated to zero length
    -- before writing begins.
    writeFile :: FilePath -> Text -> IO ()
    writeFile :: FilePath -> Text -> IO ()
    writeFile FilePath
    p = FilePath -> IOMode -> (Handle -> IO ()) -> IO ()
    forall r. FilePath -> IOMode -> (Handle -> IO r) -> IO r
    withFile FilePath
    p IOMode
    WriteMode ((Handle -> IO ()) -> IO ())
    -> (Text -> Handle -> IO ()) -> Text -> IO ()
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (Handle -> Text -> IO ()) -> Text -> Handle -> IO ()
    forall a b c. (a -> b -> c) -> b -> a -> c
    flip Handle -> Text -> IO ()
    hPutStr

    -- | Write a string to the end of a file.
    appendFile :: FilePath -> Text -> IO ()
    appendFile :: FilePath -> Text -> IO ()
    appendFile FilePath
    p = FilePath -> IOMode -> (Handle -> IO ()) -> IO ()
    forall r. FilePath -> IOMode -> (Handle -> IO r) -> IO r
    withFile FilePath
    p IOMode
    AppendMode ((Handle -> IO ()) -> IO ())
    -> (Text -> Handle -> IO ()) -> Text -> IO ()
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (Handle -> Text -> IO ()) -> Text -> Handle -> IO ()
    forall a b c. (a -> b -> c) -> b -> a -> c
    flip Handle -> Text -> IO ()
    hPutStr

    -- | Lazily read the remaining contents of a 'Handle'.  The 'Handle'
    -- will be closed after the read completes, or on error.
    hGetContents :: Handle -> IO Text
    hGetContents :: Handle -> IO Text
    hGetContents Handle
    h = do
      Handle -> IO ()
    chooseGoodBuffering Handle
    h
      FilePath -> Handle -> (Handle__ -> IO (Handle__, Text)) -> IO Text
    forall a.
    FilePath -> Handle -> (Handle__ -> IO (Handle__, a)) -> IO a
    wantReadableHandle FilePath
    "hGetContents" Handle
    h ((Handle__ -> IO (Handle__, Text)) -> IO Text)
    -> (Handle__ -> IO (Handle__, Text)) -> IO Text
    forall a b. (a -> b) -> a -> b
    $ \Handle__
    hh -> do
        ts <- Handle -> IO Text
    lazyRead Handle
    h
        return (hh{haType=SemiClosedHandle}, ts)

    -- | Use a more efficient buffer size if we're reading in
    -- block-buffered mode with the default buffer size.
    chooseGoodBuffering :: Handle -> IO ()
    chooseGoodBuffering :: Handle -> IO ()
    chooseGoodBuffering Handle
    h = do
      bufMode <- Handle -> IO BufferMode
    hGetBuffering Handle
    h
      when (bufMode == BlockBuffering Nothing) $
        hSetBuffering h (BlockBuffering (Just 16384))

    lazyRead :: Handle -> IO Text
    lazyRead :: Handle -> IO Text
    lazyRead Handle
    h = IO Text -> IO Text
    forall a. IO a -> IO a
    unsafeInterleaveIO (IO Text -> IO Text) -> IO Text -> IO Text
    forall a b. (a -> b) -> a -> b
    $
      FilePath -> Handle -> (Handle__ -> IO (Handle__, Text)) -> IO Text
    forall a.
    FilePath -> Handle -> (Handle__ -> IO (Handle__, a)) -> IO a
    withHandle FilePath
    "hGetContents" Handle
    h ((Handle__ -> IO (Handle__, Text)) -> IO Text)
    -> (Handle__ -> IO (Handle__, Text)) -> IO Text
    forall a b. (a -> b) -> a -> b
    $ \Handle__
    hh -> do
        case Handle__ -> HandleType
    haType Handle__
    hh of
          HandleType
    ClosedHandle     -> (Handle__, Text) -> IO (Handle__, Text)
    forall a. a -> IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (Handle__
    hh, Text
    L.empty)
          HandleType
    SemiClosedHandle -> Handle -> Handle__ -> IO (Handle__, Text)
    lazyReadBuffered Handle
    h Handle__
    hh
          HandleType
    _                -> IOException -> IO (Handle__, Text)
    forall a. HasCallStack => IOException -> IO a
    ioException
                              (Maybe Handle
    -> IOErrorType
    -> FilePath
    -> FilePath
    -> Maybe CInt
    -> Maybe FilePath
    -> IOException
    IOError (Handle -> Maybe Handle
    forall a. a -> Maybe a
    Just Handle
    h) IOErrorType
    IllegalOperation FilePath
    "hGetContents"
                               FilePath
    "illegal handle type" Maybe CInt
    forall a. Maybe a
    Nothing Maybe FilePath
    forall a. Maybe a
    Nothing)

    lazyReadBuffered :: Handle -> Handle__ -> IO (Handle__, Text)
    lazyReadBuffered :: Handle -> Handle__ -> IO (Handle__, Text)
    lazyReadBuffered Handle
    h hh :: Handle__
    hh@Handle__{dev
    Maybe (MVar Handle__)
    Maybe TextEncoding
    Maybe (TextEncoder enc_state)
    Maybe (TextDecoder dec_state)
    IORef (dec_state, Buffer Word8)
    IORef (Buffer CharBufElem)
    IORef (Buffer Word8)
    IORef (BufferList CharBufElem)
    Newline
    BufferMode
    HandleType
    haType :: Handle__ -> HandleType
    haDevice :: dev
    haType :: HandleType
    haByteBuffer :: IORef (Buffer Word8)
    haBufferMode :: BufferMode
    haLastDecode :: IORef (dec_state, Buffer Word8)
    haCharBuffer :: IORef (Buffer CharBufElem)
    haBuffers :: IORef (BufferList CharBufElem)
    haEncoder :: Maybe (TextEncoder enc_state)
    haDecoder :: Maybe (TextDecoder dec_state)
    haCodec :: Maybe TextEncoding
    haInputNL :: Newline
    haOutputNL :: Newline
    haOtherSide :: Maybe (MVar Handle__)
    haOtherSide :: Handle__ -> Maybe (MVar Handle__)
    haOutputNL :: Handle__ -> Newline
    haInputNL :: Handle__ -> Newline
    haCodec :: Handle__ -> Maybe TextEncoding
    haDecoder :: ()
    haEncoder :: ()
    haBuffers :: Handle__ -> IORef (BufferList CharBufElem)
    haCharBuffer :: Handle__ -> IORef (Buffer CharBufElem)
    haLastDecode :: ()
    haBufferMode :: Handle__ -> BufferMode
    haByteBuffer :: Handle__ -> IORef (Buffer Word8)
    haDevice :: ()
    ..} = do
       buf <- IORef (Buffer CharBufElem) -> IO (Buffer CharBufElem)
    forall a. IORef a -> IO a
    readIORef IORef (Buffer CharBufElem)
    haCharBuffer
       (do t <- readChunk hh buf
           ts <- lazyRead h
           return (hh, chunk t ts)) `E.catch` \IOException
    e -> do
             (hh', _) <- Handle__ -> IO (Handle__, Maybe SomeException)
    hClose_help Handle__
    hh
             if isEOFError e
               then return $ if isEmptyBuffer buf
                             then (hh', empty)
                             else (hh', L.singleton '\r')
               else E.throwIO (augmentIOError e "hGetContents" h)

    -- | Read a single line from a handle.
    hGetLine :: Handle -> IO Text
    hGetLine :: Handle -> IO Text
    hGetLine = ([Text] -> Text) -> Handle -> IO Text
    forall t. ([Text] -> t) -> Handle -> IO t
    hGetLineWith [Text] -> Text
    L.fromChunks

    -- | Write a string to a handle.
    hPutStr :: Handle -> Text -> IO ()
    hPutStr :: Handle -> Text -> IO ()
    hPutStr Handle
    h = Handle -> Stream CharBufElem -> IO ()
    hPutStream Handle
    h (Stream CharBufElem -> IO ())
    -> (Text -> Stream CharBufElem) -> Text -> IO ()
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Text -> Stream CharBufElem
    stream

    -- | Write a string to a handle, followed by a newline.
    hPutStrLn :: Handle -> Text -> IO ()
    hPutStrLn :: Handle -> Text -> IO ()
    hPutStrLn Handle
    h = Handle -> Stream CharBufElem -> IO ()
    hPutStream Handle
    h (Stream CharBufElem -> IO ())
    -> (Text -> Stream CharBufElem) -> Text -> IO ()
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Text -> Stream CharBufElem
    streamLn

    -- | The 'interact' function takes a function of type @Text -> Text@
    -- as its argument. The entire input from the standard input device is
    -- passed (lazily) to this function as its argument, and the resulting
    -- string is output on the standard output device.
    interact :: (Text -> Text) -> IO ()
    interact :: (Text -> Text) -> IO ()
    interact Text -> Text
    f = Text -> IO ()
    putStr (Text -> IO ()) -> (Text -> Text) -> Text -> IO ()
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Text -> Text
    f (Text -> IO ()) -> IO Text -> IO ()
    forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
    =<< IO Text
    getContents

    -- | Lazily read all user input on 'stdin' as a single string.
    getContents :: IO Text
    getContents :: IO Text
    getContents = Handle -> IO Text
    hGetContents Handle
    stdin

    -- | Read a single line of user input from 'stdin'.
    getLine :: IO Text
    getLine :: IO Text
    getLine = Handle -> IO Text
    hGetLine Handle
    stdin

    -- | Write a string to 'stdout'.
    putStr :: Text -> IO ()
    putStr :: Text -> IO ()
    putStr = Handle -> Text -> IO ()
    hPutStr Handle
    stdout

    -- | Write a string to 'stdout', followed by a newline.
    putStrLn :: Text -> IO ()
    putStrLn :: Text -> IO ()
    putStrLn = Handle -> Text -> IO ()
    hPutStrLn Handle
    stdout