    {-# 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(..), hPutChar, openFile, stdin, stdout,
                      withFile)
    import qualified Data.Text.IO as T
    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)
    import Data.Text.Internal.Lazy (chunk, empty)
    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 = (Text -> IO ()) -> [Text] -> IO ()
    forall (t :: * -> *) (m :: * -> *) a b.
    (Foldable t, Monad m) =>
    (a -> m b) -> t a -> m ()
    mapM_ (Handle -> Text -> IO ()
    T.hPutStr Handle
    h) ([Text] -> IO ()) -> (Text -> [Text]) -> Text -> IO ()
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Text -> [Text]
    L.toChunks

    -- | Write a string to a handle, followed by a newline.
    hPutStrLn :: Handle -> Text -> IO ()
    hPutStrLn :: Handle -> Text -> IO ()
    hPutStrLn Handle
    h Text
    t = Handle -> Text -> IO ()
    hPutStr Handle
    h Text
    t IO () -> IO () -> IO ()
    forall a b. IO a -> IO b -> IO b
    forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
    >> Handle -> CharBufElem -> IO ()
    hPutChar Handle
    h CharBufElem
    '\n'

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