    {-# LANGUAGE Trustworthy #-}
    {-# LANGUAGE NoImplicitPrelude
               , RecordWildCards
               , BangPatterns
               , NondecreasingIndentation
               , RankNTypes
      #-}
    {-# OPTIONS_GHC -Wno-unused-matches #-}
    {-# OPTIONS_GHC -Wno-name-shadowing #-}
    {-# OPTIONS_GHC -Wno-incomplete-uni-patterns #-}
    {-# OPTIONS_HADDOCK not-home #-}

    -----------------------------------------------------------------------------
    -- |
    -- Module      :  GHC.Internal.IO.Handle.Internals
    -- Copyright   :  (c) The University of Glasgow, 1994-2001
    -- License     :  see libraries/base/LICENSE
    --
    -- Maintainer  :  libraries@haskell.org
    -- Stability   :  internal
    -- Portability :  non-portable
    --
    -- This module defines the basic operations on I\/O \"handles\".  All
    -- of the operations defined here are independent of the underlying
    -- device.
    --
    -- /The API of this module is unstable and not meant to be consumed by the general public./
    -- If you absolutely must depend on it, make sure to use a tight upper
    -- bound, e.g., @base < 4.X@ rather than @base < 5@, because the interface can
    -- change rapidly without much warning.
    --
    -----------------------------------------------------------------------------

    module GHC.Internal.IO.Handle.Internals (
      withHandle, withHandle', withHandle_,
      withHandle__', withHandle_', withAllHandles__,
      wantWritableHandle, wantReadableHandle, wantReadableHandle_,
      wantSeekableHandle,

      mkHandle,
      mkFileHandle, mkFileHandleNoFinalizer, mkDuplexHandle, mkDuplexHandleNoFinalizer,
      addHandleFinalizer,
      openTextEncoding, closeTextCodecs, initBufferState,
      dEFAULT_CHAR_BUFFER_SIZE,

      flushBuffer, flushWriteBuffer, flushCharReadBuffer,
      flushCharBuffer, flushByteReadBuffer, flushByteWriteBuffer,

      readTextDevice, writeCharBuffer, readTextDeviceNonBlocking,
      decodeByteBuf,

      augmentIOError,
      ioe_closedHandle, ioe_semiclosedHandle,
      ioe_EOF, ioe_notReadable, ioe_notWritable,
      ioe_finalizedHandle, ioe_bufsiz,

      hClose_impl, hClose_help, hLookAhead_,

      HandleFinalizer, handleFinalizer,

      debugIO, traceIO
     ) where

    import GHC.Internal.IO
    import GHC.Internal.IO.IOMode
    import GHC.Internal.IO.Encoding as Encoding
    import GHC.Internal.IO.Encoding.Types (CodeBuffer)
    import GHC.Internal.IO.Handle.Types
    import GHC.Internal.IO.Buffer
    import GHC.Internal.IO.BufferedIO (BufferedIO)
    import GHC.Internal.IO.Exception
    import GHC.Internal.IO.Device (IODevice, RawIO, SeekMode(..))
    import GHC.Internal.IO.SubSystem ((<!>), isWindowsNativeIO)
    import qualified GHC.Internal.IO.Device as IODevice
    import qualified GHC.Internal.IO.BufferedIO as Buffered

    import GHC.Internal.Conc.Sync
    import GHC.Internal.Real
    import GHC.Internal.Word
    import GHC.Internal.Base
    import GHC.Internal.Exception
    import GHC.Internal.Exception.Type
    import GHC.Internal.Num          ( Num(..) )
    import GHC.Internal.Show
    import GHC.Internal.IORef
    import GHC.Internal.MVar
    import GHC.Internal.Ptr (castPtr)
    import GHC.Internal.Data.Typeable
    import GHC.Internal.Data.Maybe
    import GHC.Internal.System.Posix.Internals hiding (FD)

    import GHC.Internal.Foreign.C.String

    c_DEBUG_DUMP :: Bool
    c_DEBUG_DUMP :: Bool
    c_DEBUG_DUMP = Bool
    False

    -- ---------------------------------------------------------------------------
    -- Creating a new handle

    type HandleFinalizer = FilePath -> MVar Handle__ -> IO ()

    -- | Add a finalizer to a 'Handle'. Specifically, the finalizer
    -- will be added to the 'MVar' of a file handle or the write-side
    -- 'MVar' of a duplex handle. See Handle Finalizers for details.
    addHandleFinalizer :: Handle -> HandleFinalizer -> IO ()
    addHandleFinalizer :: Handle -> HandleFinalizer -> IO ()
    addHandleFinalizer Handle
    handle HandleFinalizer
    finalizer = do
      [Char] -> IO ()
    debugIO ([Char] -> IO ()) -> [Char] -> IO ()
    forall a b. (a -> b) -> a -> b
    $ [Char]
    "Registering finalizer: " [Char] -> [Char] -> [Char]
    forall a. [a] -> [a] -> [a]
    ++ [Char] -> [Char]
    forall a. Show a => a -> [Char]
    show [Char]
    filepath
      MVar Handle__ -> IO () -> IO ()
    forall a. MVar a -> IO () -> IO ()
    addMVarFinalizer MVar Handle__
    mv (HandleFinalizer
    finalizer [Char]
    filepath MVar Handle__
    mv)
      where
        !([Char]
    filepath, !MVar Handle__
    mv) = case Handle
    handle of
          FileHandle [Char]
    fp MVar Handle__
    m -> ([Char]
    fp, MVar Handle__
    m)
          DuplexHandle [Char]
    fp MVar Handle__
    _ MVar Handle__
    write_m -> ([Char]
    fp, MVar Handle__
    write_m)

    -- ---------------------------------------------------------------------------
    -- Working with Handles

    {-
    In the concurrent world, handles are locked during use.  This is done
    by wrapping an MVar around the handle which acts as a mutex over
    operations on the handle.

    To avoid races, we use the following bracketing operations.  The idea
    is to obtain the lock, do some operation and replace the lock again,
    whether the operation succeeded or failed.  We also want to handle the
    case where the thread receives an exception while processing the IO
    operation: in these cases we also want to relinquish the lock.

    There are three versions of @withHandle@: corresponding to the three
    possible combinations of:

            - the operation may side-effect the handle
            - the operation may return a result

    If the operation generates an error or an exception is raised, the
    original handle is always replaced.
    -}

    {-# INLINE withHandle #-}
    withHandle :: String -> Handle -> (Handle__ -> IO (Handle__,a)) -> IO a
    withHandle :: forall a.
    [Char] -> Handle -> (Handle__ -> IO (Handle__, a)) -> IO a
    withHandle [Char]
    fun h :: Handle
    h@(FileHandle [Char]
    _ MVar Handle__
    m)     Handle__ -> IO (Handle__, a)
    act = [Char]
    -> Handle
    -> MVar Handle__
    -> (Handle__ -> IO (Handle__, a))
    -> IO a
    forall a.
    [Char]
    -> Handle
    -> MVar Handle__
    -> (Handle__ -> IO (Handle__, a))
    -> IO a
    withHandle' [Char]
    fun Handle
    h MVar Handle__
    m Handle__ -> IO (Handle__, a)
    act
    withHandle [Char]
    fun h :: Handle
    h@(DuplexHandle [Char]
    _ MVar Handle__
    m MVar Handle__
    _) Handle__ -> IO (Handle__, a)
    act = [Char]
    -> Handle
    -> MVar Handle__
    -> (Handle__ -> IO (Handle__, a))
    -> IO a
    forall a.
    [Char]
    -> Handle
    -> MVar Handle__
    -> (Handle__ -> IO (Handle__, a))
    -> IO a
    withHandle' [Char]
    fun Handle
    h MVar Handle__
    m Handle__ -> IO (Handle__, a)
    act

    withHandle' :: String -> Handle -> MVar Handle__
       -> (Handle__ -> IO (Handle__,a)) -> IO a
    withHandle' :: forall a.
    [Char]
    -> Handle
    -> MVar Handle__
    -> (Handle__ -> IO (Handle__, a))
    -> IO a
    withHandle' [Char]
    fun Handle
    h MVar Handle__
    m Handle__ -> IO (Handle__, a)
    act =
     IO a -> IO a
    forall a. IO a -> IO a
    mask_ (IO a -> IO a) -> IO a -> IO a
    forall a b. (a -> b) -> a -> b
    $ do
       (h',v)  <- [Char]
    -> Handle
    -> (Handle__ -> IO (Handle__, a))
    -> MVar Handle__
    -> IO (Handle__, a)
    forall a.
    [Char] -> Handle -> (Handle__ -> IO a) -> MVar Handle__ -> IO a
    do_operation [Char]
    fun Handle
    h Handle__ -> IO (Handle__, a)
    act MVar Handle__
    m
       checkHandleInvariants h'
       putMVar m h'
       return v

    {-# INLINE withHandle_ #-}
    withHandle_ :: String -> Handle -> (Handle__ -> IO a) -> IO a
    withHandle_ :: forall a. [Char] -> Handle -> (Handle__ -> IO a) -> IO a
    withHandle_ [Char]
    fun h :: Handle
    h@(FileHandle [Char]
    _ MVar Handle__
    m)     Handle__ -> IO a
    act = [Char] -> Handle -> MVar Handle__ -> (Handle__ -> IO a) -> IO a
    forall a.
    [Char] -> Handle -> MVar Handle__ -> (Handle__ -> IO a) -> IO a
    withHandle_' [Char]
    fun Handle
    h MVar Handle__
    m Handle__ -> IO a
    act
    withHandle_ [Char]
    fun h :: Handle
    h@(DuplexHandle [Char]
    _ MVar Handle__
    m MVar Handle__
    _) Handle__ -> IO a
    act = [Char] -> Handle -> MVar Handle__ -> (Handle__ -> IO a) -> IO a
    forall a.
    [Char] -> Handle -> MVar Handle__ -> (Handle__ -> IO a) -> IO a
    withHandle_' [Char]
    fun Handle
    h MVar Handle__
    m Handle__ -> IO a
    act

    withHandle_' :: String -> Handle -> MVar Handle__ -> (Handle__ -> IO a) -> IO a
    withHandle_' :: forall a.
    [Char] -> Handle -> MVar Handle__ -> (Handle__ -> IO a) -> IO a
    withHandle_' [Char]
    fun Handle
    h MVar Handle__
    m Handle__ -> IO a
    act = [Char]
    -> Handle
    -> MVar Handle__
    -> (Handle__ -> IO (Handle__, a))
    -> IO a
    forall a.
    [Char]
    -> Handle
    -> MVar Handle__
    -> (Handle__ -> IO (Handle__, a))
    -> IO a
    withHandle' [Char]
    fun Handle
    h MVar Handle__
    m ((Handle__ -> IO (Handle__, a)) -> IO a)
    -> (Handle__ -> IO (Handle__, a)) -> IO a
    forall a b. (a -> b) -> a -> b
    $ \Handle__
    h_ -> do
                                  a <- Handle__ -> IO a
    act Handle__
    h_
                                  return (h_,a)

    withAllHandles__ :: String -> Handle -> (Handle__ -> IO Handle__) -> IO ()
    withAllHandles__ :: [Char] -> Handle -> (Handle__ -> IO Handle__) -> IO ()
    withAllHandles__ [Char]
    fun h :: Handle
    h@(FileHandle [Char]
    _ MVar Handle__
    m)     Handle__ -> IO Handle__
    act = [Char]
    -> Handle -> MVar Handle__ -> (Handle__ -> IO Handle__) -> IO ()
    withHandle__' [Char]
    fun Handle
    h MVar Handle__
    m Handle__ -> IO Handle__
    act
    withAllHandles__ [Char]
    fun h :: Handle
    h@(DuplexHandle [Char]
    _ MVar Handle__
    r MVar Handle__
    w) Handle__ -> IO Handle__
    act = do
      [Char]
    -> Handle -> MVar Handle__ -> (Handle__ -> IO Handle__) -> IO ()
    withHandle__' [Char]
    fun Handle
    h MVar Handle__
    r Handle__ -> IO Handle__
    act
      [Char]
    -> Handle -> MVar Handle__ -> (Handle__ -> IO Handle__) -> IO ()
    withHandle__' [Char]
    fun Handle
    h MVar Handle__
    w Handle__ -> IO Handle__
    act

    withHandle__' :: String -> Handle -> MVar Handle__ -> (Handle__ -> IO Handle__)
                  -> IO ()
    withHandle__' :: [Char]
    -> Handle -> MVar Handle__ -> (Handle__ -> IO Handle__) -> IO ()
    withHandle__' [Char]
    fun Handle
    h MVar Handle__
    m Handle__ -> IO Handle__
    act =
     IO () -> IO ()
    forall a. IO a -> IO a
    mask_ (IO () -> IO ()) -> IO () -> IO ()
    forall a b. (a -> b) -> a -> b
    $ do
       h'  <- [Char]
    -> Handle
    -> (Handle__ -> IO Handle__)
    -> MVar Handle__
    -> IO Handle__
    forall a.
    [Char] -> Handle -> (Handle__ -> IO a) -> MVar Handle__ -> IO a
    do_operation [Char]
    fun Handle
    h Handle__ -> IO Handle__
    act MVar Handle__
    m
       checkHandleInvariants h'
       putMVar m h'
       return ()

    do_operation :: String -> Handle -> (Handle__ -> IO a) -> MVar Handle__ -> IO a
    do_operation :: forall a.
    [Char] -> Handle -> (Handle__ -> IO a) -> MVar Handle__ -> IO a
    do_operation [Char]
    fun Handle
    h Handle__ -> IO a
    act MVar Handle__
    m = do
      h_ <- MVar Handle__ -> IO Handle__
    forall a. MVar a -> IO a
    takeMVar MVar Handle__
    m
      checkHandleInvariants h_
      act h_ `catchExceptionNoPropagate` handler h_
      where
        handler :: Handle__ -> ExceptionWithContext SomeException -> IO a
    handler Handle__
    h_ (ExceptionWithContext ExceptionContext
    c SomeException
    e) = do
          MVar Handle__ -> Handle__ -> IO ()
    forall a. MVar a -> a -> IO ()
    putMVar MVar Handle__
    m Handle__
    h_
          case () of
            ()
    _ | Just IOException
    ioe <- SomeException -> Maybe IOException
    forall e. Exception e => SomeException -> Maybe e
    fromException SomeException
    e ->
                ExceptionWithContext IOException -> IO a
    forall e a. Exception e => ExceptionWithContext e -> IO a
    rethrowIO (ExceptionContext -> IOException -> ExceptionWithContext IOException
    forall a. ExceptionContext -> a -> ExceptionWithContext a
    ExceptionWithContext ExceptionContext
    c (IOException -> ExceptionWithContext IOException)
    -> IOException -> ExceptionWithContext IOException
    forall a b. (a -> b) -> a -> b
    $ IOException -> [Char] -> Handle -> IOException
    augmentIOError IOException
    ioe [Char]
    fun Handle
    h)
            ()
    _ | Just SomeAsyncException
    async_ex <- SomeException -> Maybe SomeAsyncException
    forall e. Exception e => SomeException -> Maybe e
    fromException SomeException
    e -> do -- see Note [async]
                let SomeAsyncException
    _ = SomeAsyncException
    async_ex :: SomeAsyncException
                t <- IO ThreadId
    myThreadId
                throwTo t e
                do_operation fun h act m
            ()
    _otherwise ->
                SomeException -> IO a
    forall e a. (HasCallStack, Exception e) => e -> IO a
    throwIO SomeException
    e

    -- Note [async]
    -- ~~~~~~~~~~~~
    -- If an asynchronous exception is raised during an I/O operation,
    -- normally it is fine to just re-throw the exception synchronously.
    -- However, if we are inside an unsafePerformIO or an
    -- unsafeInterleaveIO, this would replace the enclosing thunk with the
    -- exception raised, which is wrong (#3997).  We have to release the
    -- lock on the Handle, but what do we replace the thunk with?  What
    -- should happen when the thunk is subsequently demanded again?
    --
    -- The only sensible choice we have is to re-do the IO operation on
    -- resumption, but then we have to be careful in the IO library that
    -- this is always safe to do.  In particular we should
    --
    --    never perform any side-effects before an interruptible operation
    --
    -- because the interruptible operation may raise an asynchronous
    -- exception, which may cause the operation and its side effects to be
    -- subsequently performed again.
    --
    -- Re-doing the IO operation is achieved by:
    --   - using throwTo to re-throw the asynchronous exception asynchronously
    --     in the current thread
    --   - on resumption, it will be as if throwTo returns.  In that case, we
    --     recursively invoke the original operation (see do_operation above).
    --
    -- Interruptible operations in the I/O library are:
    --    - threadWaitRead/threadWaitWrite
    --    - fillReadBuffer/flushWriteBuffer
    --    - readTextDevice/writeTextDevice

    augmentIOError :: IOException -> String -> Handle -> IOException
    augmentIOError :: IOException -> [Char] -> Handle -> IOException
    augmentIOError ioe :: IOException
    ioe@IOError{ ioe_filename :: IOException -> Maybe [Char]
    ioe_filename = Maybe [Char]
    fp } [Char]
    fun Handle
    h
      = IOException
    ioe { ioe_handle = Just h, ioe_location = fun, ioe_filename = filepath }
      where filepath :: Maybe [Char]
    filepath
              | Just [Char]
    _ <- Maybe [Char]
    fp = Maybe [Char]
    fp
              | Bool
    otherwise = case Handle
    h of
                              FileHandle [Char]
    path MVar Handle__
    _     -> [Char] -> Maybe [Char]
    forall a. a -> Maybe a
    Just [Char]
    path
                              DuplexHandle [Char]
    path MVar Handle__
    _ MVar Handle__
    _ -> [Char] -> Maybe [Char]
    forall a. a -> Maybe a
    Just [Char]
    path

    -- ---------------------------------------------------------------------------
    -- Wrapper for write operations.

    -- If we already have a writeable handle just run the action.
    -- If we have a read only handle we throw an exception.
    -- If we have a read/write handle in read mode we:
    -- * Seek to the unread (from the users PoV) position and
    --   change the handles buffer to a write buffer.
    wantWritableHandle :: String -> Handle -> (Handle__ -> IO a) -> IO a
    wantWritableHandle :: forall a. [Char] -> Handle -> (Handle__ -> IO a) -> IO a
    wantWritableHandle [Char]
    fun h :: Handle
    h@(FileHandle [Char]
    _ MVar Handle__
    m) Handle__ -> IO a
    act
      = [Char] -> Handle -> MVar Handle__ -> (Handle__ -> IO a) -> IO a
    forall a.
    [Char] -> Handle -> MVar Handle__ -> (Handle__ -> IO a) -> IO a
    wantWritableHandle' [Char]
    fun Handle
    h MVar Handle__
    m Handle__ -> IO a
    act
    wantWritableHandle [Char]
    fun h :: Handle
    h@(DuplexHandle [Char]
    _ MVar Handle__
    _ MVar Handle__
    m) Handle__ -> IO a
    act
      = [Char] -> Handle -> MVar Handle__ -> (Handle__ -> IO a) -> IO a
    forall a.
    [Char] -> Handle -> MVar Handle__ -> (Handle__ -> IO a) -> IO a
    wantWritableHandle' [Char]
    fun Handle
    h MVar Handle__
    m Handle__ -> IO a
    act
        -- we know it's not a ReadHandle or ReadWriteHandle, but we have to
        -- check for ClosedHandle/SemiClosedHandle. (#4808)

    wantWritableHandle'
            :: String -> Handle -> MVar Handle__
            -> (Handle__ -> IO a) -> IO a
    wantWritableHandle' :: forall a.
    [Char] -> Handle -> MVar Handle__ -> (Handle__ -> IO a) -> IO a
    wantWritableHandle' [Char]
    fun Handle
    h MVar Handle__
    m Handle__ -> IO a
    act
       = [Char] -> Handle -> MVar Handle__ -> (Handle__ -> IO a) -> IO a
    forall a.
    [Char] -> Handle -> MVar Handle__ -> (Handle__ -> IO a) -> IO a
    withHandle_' [Char]
    fun Handle
    h MVar Handle__
    m ((Handle__ -> IO a) -> Handle__ -> IO a
    forall a. (Handle__ -> IO a) -> Handle__ -> IO a
    checkWritableHandle Handle__ -> IO a
    act)

    checkWritableHandle :: (Handle__ -> IO a) -> Handle__ -> IO a
    checkWritableHandle :: forall a. (Handle__ -> IO a) -> Handle__ -> IO a
    checkWritableHandle Handle__ -> IO a
    act h_ :: Handle__
    h_@Handle__{dev
    Maybe (MVar Handle__)
    Maybe TextEncoding
    Maybe (TextEncoder enc_state)
    Maybe (TextDecoder dec_state)
    IORef (dec_state, Buffer Word8)
    IORef (Buffer Char)
    IORef (Buffer Word8)
    IORef (BufferList Char)
    Newline
    BufferMode
    HandleType
    haDevice :: dev
    haType :: HandleType
    haByteBuffer :: IORef (Buffer Word8)
    haBufferMode :: BufferMode
    haLastDecode :: IORef (dec_state, Buffer Word8)
    haCharBuffer :: IORef (Buffer Char)
    haBuffers :: IORef (BufferList Char)
    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 Char)
    haCharBuffer :: Handle__ -> IORef (Buffer Char)
    haLastDecode :: ()
    haBufferMode :: Handle__ -> BufferMode
    haByteBuffer :: Handle__ -> IORef (Buffer Word8)
    haType :: Handle__ -> HandleType
    haDevice :: ()
    ..}
      = case HandleType
    haType of
          HandleType
    ClosedHandle         -> IO a
    forall a. IO a
    ioe_closedHandle
          HandleType
    SemiClosedHandle     -> IO a
    forall a. IO a
    ioe_semiclosedHandle
          HandleType
    ReadHandle           -> IO a
    forall a. IO a
    ioe_notWritable
          HandleType
    ReadWriteHandle      -> do
            buf <- IORef (Buffer Char) -> IO (Buffer Char)
    forall a. IORef a -> IO a
    readIORef IORef (Buffer Char)
    haCharBuffer
            when (not (isWriteBuffer buf)) $ do
               flushCharReadBuffer h_
               flushByteReadBuffer h_
               buf <- readIORef haCharBuffer
               writeIORef haCharBuffer buf{ bufState = WriteBuffer }
               buf <- readIORef haByteBuffer
               buf' <- Buffered.emptyWriteBuffer haDevice buf
               writeIORef haByteBuffer buf'
            act h_
          HandleType
    AppendHandle         -> Handle__ -> IO a
    act Handle__
    h_
          HandleType
    WriteHandle          -> Handle__ -> IO a
    act Handle__
    h_

    -- ---------------------------------------------------------------------------
    -- Wrapper for read operations.

    wantReadableHandle :: String -> Handle -> (Handle__ -> IO (Handle__,a)) -> IO a
    wantReadableHandle :: forall a.
    [Char] -> Handle -> (Handle__ -> IO (Handle__, a)) -> IO a
    wantReadableHandle [Char]
    fun Handle
    h Handle__ -> IO (Handle__, a)
    act =
      [Char] -> Handle -> (Handle__ -> IO (Handle__, a)) -> IO a
    forall a.
    [Char] -> Handle -> (Handle__ -> IO (Handle__, a)) -> IO a
    withHandle [Char]
    fun Handle
    h ((Handle__ -> IO (Handle__, a)) -> Handle__ -> IO (Handle__, a)
    forall a. (Handle__ -> IO a) -> Handle__ -> IO a
    checkReadableHandle Handle__ -> IO (Handle__, a)
    act)

    wantReadableHandle_ :: String -> Handle -> (Handle__ -> IO a) -> IO a
    wantReadableHandle_ :: forall a. [Char] -> Handle -> (Handle__ -> IO a) -> IO a
    wantReadableHandle_ [Char]
    fun h :: Handle
    h@(FileHandle  [Char]
    _ MVar Handle__
    m)   Handle__ -> IO a
    act
      = [Char] -> Handle -> MVar Handle__ -> (Handle__ -> IO a) -> IO a
    forall a.
    [Char] -> Handle -> MVar Handle__ -> (Handle__ -> IO a) -> IO a
    wantReadableHandle' [Char]
    fun Handle
    h MVar Handle__
    m Handle__ -> IO a
    act
    wantReadableHandle_ [Char]
    fun h :: Handle
    h@(DuplexHandle [Char]
    _ MVar Handle__
    m MVar Handle__
    _) Handle__ -> IO a
    act
      = [Char] -> Handle -> MVar Handle__ -> (Handle__ -> IO a) -> IO a
    forall a.
    [Char] -> Handle -> MVar Handle__ -> (Handle__ -> IO a) -> IO a
    wantReadableHandle' [Char]
    fun Handle
    h MVar Handle__
    m Handle__ -> IO a
    act
        -- we know it's not a WriteHandle or ReadWriteHandle, but we have to
        -- check for ClosedHandle/SemiClosedHandle. (#4808)

    wantReadableHandle'
            :: String -> Handle -> MVar Handle__
            -> (Handle__ -> IO a) -> IO a
    wantReadableHandle' :: forall a.
    [Char] -> Handle -> MVar Handle__ -> (Handle__ -> IO a) -> IO a
    wantReadableHandle' [Char]
    fun Handle
    h MVar Handle__
    m Handle__ -> IO a
    act
      = [Char] -> Handle -> MVar Handle__ -> (Handle__ -> IO a) -> IO a
    forall a.
    [Char] -> Handle -> MVar Handle__ -> (Handle__ -> IO a) -> IO a
    withHandle_' [Char]
    fun Handle
    h MVar Handle__
    m ((Handle__ -> IO a) -> Handle__ -> IO a
    forall a. (Handle__ -> IO a) -> Handle__ -> IO a
    checkReadableHandle Handle__ -> IO a
    act)

    checkReadableHandle :: (Handle__ -> IO a) -> Handle__ -> IO a
    checkReadableHandle :: forall a. (Handle__ -> IO a) -> Handle__ -> IO a
    checkReadableHandle Handle__ -> IO a
    act h_ :: Handle__
    h_@Handle__{dev
    Maybe (MVar Handle__)
    Maybe TextEncoding
    Maybe (TextEncoder enc_state)
    Maybe (TextDecoder dec_state)
    IORef (dec_state, Buffer Word8)
    IORef (Buffer Char)
    IORef (Buffer Word8)
    IORef (BufferList Char)
    Newline
    BufferMode
    HandleType
    haOtherSide :: Handle__ -> Maybe (MVar Handle__)
    haOutputNL :: Handle__ -> Newline
    haInputNL :: Handle__ -> Newline
    haCodec :: Handle__ -> Maybe TextEncoding
    haDecoder :: ()
    haEncoder :: ()
    haBuffers :: Handle__ -> IORef (BufferList Char)
    haCharBuffer :: Handle__ -> IORef (Buffer Char)
    haLastDecode :: ()
    haBufferMode :: Handle__ -> BufferMode
    haByteBuffer :: Handle__ -> IORef (Buffer Word8)
    haType :: Handle__ -> HandleType
    haDevice :: ()
    haDevice :: dev
    haType :: HandleType
    haByteBuffer :: IORef (Buffer Word8)
    haBufferMode :: BufferMode
    haLastDecode :: IORef (dec_state, Buffer Word8)
    haCharBuffer :: IORef (Buffer Char)
    haBuffers :: IORef (BufferList Char)
    haEncoder :: Maybe (TextEncoder enc_state)
    haDecoder :: Maybe (TextDecoder dec_state)
    haCodec :: Maybe TextEncoding
    haInputNL :: Newline
    haOutputNL :: Newline
    haOtherSide :: Maybe (MVar Handle__)
    ..} =
        case HandleType
    haType of
          HandleType
    ClosedHandle         -> IO a
    forall a. IO a
    ioe_closedHandle
          HandleType
    SemiClosedHandle     -> IO a
    forall a. IO a
    ioe_semiclosedHandle
          HandleType
    AppendHandle         -> IO a
    forall a. IO a
    ioe_notReadable
          HandleType
    WriteHandle          -> IO a
    forall a. IO a
    ioe_notReadable
          HandleType
    ReadWriteHandle      -> do
              -- a read/write handle and we want to read from it.  We must
              -- flush all buffered write data first.
              bbuf <- IORef (Buffer Word8) -> IO (Buffer Word8)
    forall a. IORef a -> IO a
    readIORef IORef (Buffer Word8)
    haByteBuffer
              when (isWriteBuffer bbuf) $ do
                 when (not (isEmptyBuffer bbuf)) $ flushByteWriteBuffer h_
                 cbuf' <- readIORef haCharBuffer
                 writeIORef haCharBuffer cbuf'{ bufState = ReadBuffer }
                 bbuf <- readIORef haByteBuffer
                 writeIORef haByteBuffer bbuf{ bufState = ReadBuffer }
              act h_
          HandleType
    _other               -> Handle__ -> IO a
    act Handle__
    h_

    -- ---------------------------------------------------------------------------
    -- Wrapper for seek operations.

    wantSeekableHandle :: String -> Handle -> (Handle__ -> IO a) -> IO a
    wantSeekableHandle :: forall a. [Char] -> Handle -> (Handle__ -> IO a) -> IO a
    wantSeekableHandle [Char]
    fun h :: Handle
    h@(DuplexHandle [Char]
    _ MVar Handle__
    _ MVar Handle__
    _) Handle__ -> IO a
    _act =
      IOException -> IO a
    forall a. HasCallStack => IOException -> IO a
    ioException (Maybe Handle
    -> IOErrorType
    -> [Char]
    -> [Char]
    -> Maybe CInt
    -> Maybe [Char]
    -> IOException
    IOError (Handle -> Maybe Handle
    forall a. a -> Maybe a
    Just Handle
    h) IOErrorType
    IllegalOperation [Char]
    fun
                       [Char]
    "handle is not seekable" Maybe CInt
    forall a. Maybe a
    Nothing Maybe [Char]
    forall a. Maybe a
    Nothing)
    wantSeekableHandle [Char]
    fun h :: Handle
    h@(FileHandle [Char]
    _ MVar Handle__
    m) Handle__ -> IO a
    act =
      [Char] -> Handle -> MVar Handle__ -> (Handle__ -> IO a) -> IO a
    forall a.
    [Char] -> Handle -> MVar Handle__ -> (Handle__ -> IO a) -> IO a
    withHandle_' [Char]
    fun Handle
    h MVar Handle__
    m ((Handle__ -> IO a) -> Handle__ -> IO a
    forall a. (Handle__ -> IO a) -> Handle__ -> IO a
    checkSeekableHandle Handle__ -> IO a
    act)

    checkSeekableHandle :: (Handle__ -> IO a) -> Handle__ -> IO a
    checkSeekableHandle :: forall a. (Handle__ -> IO a) -> Handle__ -> IO a
    checkSeekableHandle Handle__ -> IO a
    act handle_ :: Handle__
    handle_@Handle__{haDevice :: ()
    haDevice=dev
    dev} =
        case Handle__ -> HandleType
    haType Handle__
    handle_ of
          HandleType
    ClosedHandle      -> IO a
    forall a. IO a
    ioe_closedHandle
          HandleType
    SemiClosedHandle  -> IO a
    forall a. IO a
    ioe_semiclosedHandle
          HandleType
    AppendHandle      -> IO a
    forall a. IO a
    ioe_notSeekable
          HandleType
    _ -> do b <- dev -> IO Bool
    forall a. IODevice a => a -> IO Bool
    IODevice.isSeekable dev
    dev
                  if b then act handle_
                       else ioe_notSeekable

    -- -----------------------------------------------------------------------------
    -- Handy IOErrors

    ioe_closedHandle, ioe_semiclosedHandle, ioe_EOF,
      ioe_notReadable, ioe_notWritable, ioe_cannotFlushNotSeekable,
      ioe_notSeekable :: IO a

    ioe_closedHandle :: forall a. IO a
    ioe_closedHandle = IOException -> IO a
    forall a. HasCallStack => IOException -> IO a
    ioException
       (Maybe Handle
    -> IOErrorType
    -> [Char]
    -> [Char]
    -> Maybe CInt
    -> Maybe [Char]
    -> IOException
    IOError Maybe Handle
    forall a. Maybe a
    Nothing IOErrorType
    IllegalOperation [Char]
    ""
            [Char]
    "handle is closed" Maybe CInt
    forall a. Maybe a
    Nothing Maybe [Char]
    forall a. Maybe a
    Nothing)
    ioe_semiclosedHandle :: forall a. IO a
    ioe_semiclosedHandle = IOException -> IO a
    forall a. HasCallStack => IOException -> IO a
    ioException
       (Maybe Handle
    -> IOErrorType
    -> [Char]
    -> [Char]
    -> Maybe CInt
    -> Maybe [Char]
    -> IOException
    IOError Maybe Handle
    forall a. Maybe a
    Nothing IOErrorType
    IllegalOperation [Char]
    ""
            [Char]
    "handle is semi-closed" Maybe CInt
    forall a. Maybe a
    Nothing Maybe [Char]
    forall a. Maybe a
    Nothing)
    ioe_EOF :: forall a. IO a
    ioe_EOF = IOException -> IO a
    forall a. HasCallStack => IOException -> IO a
    ioException
       (Maybe Handle
    -> IOErrorType
    -> [Char]
    -> [Char]
    -> Maybe CInt
    -> Maybe [Char]
    -> IOException
    IOError Maybe Handle
    forall a. Maybe a
    Nothing IOErrorType
    EOF [Char]
    "" [Char]
    "" Maybe CInt
    forall a. Maybe a
    Nothing Maybe [Char]
    forall a. Maybe a
    Nothing)
    ioe_notReadable :: forall a. IO a
    ioe_notReadable = IOException -> IO a
    forall a. HasCallStack => IOException -> IO a
    ioException
       (Maybe Handle
    -> IOErrorType
    -> [Char]
    -> [Char]
    -> Maybe CInt
    -> Maybe [Char]
    -> IOException
    IOError Maybe Handle
    forall a. Maybe a
    Nothing IOErrorType
    IllegalOperation [Char]
    ""
            [Char]
    "handle is not open for reading" Maybe CInt
    forall a. Maybe a
    Nothing Maybe [Char]
    forall a. Maybe a
    Nothing)
    ioe_notWritable :: forall a. IO a
    ioe_notWritable = IOException -> IO a
    forall a. HasCallStack => IOException -> IO a
    ioException
       (Maybe Handle
    -> IOErrorType
    -> [Char]
    -> [Char]
    -> Maybe CInt
    -> Maybe [Char]
    -> IOException
    IOError Maybe Handle
    forall a. Maybe a
    Nothing IOErrorType
    IllegalOperation [Char]
    ""
            [Char]
    "handle is not open for writing" Maybe CInt
    forall a. Maybe a
    Nothing Maybe [Char]
    forall a. Maybe a
    Nothing)
    ioe_notSeekable :: forall a. IO a
    ioe_notSeekable = IOException -> IO a
    forall a. HasCallStack => IOException -> IO a
    ioException
       (Maybe Handle
    -> IOErrorType
    -> [Char]
    -> [Char]
    -> Maybe CInt
    -> Maybe [Char]
    -> IOException
    IOError Maybe Handle
    forall a. Maybe a
    Nothing IOErrorType
    IllegalOperation [Char]
    ""
            [Char]
    "handle is not seekable" Maybe CInt
    forall a. Maybe a
    Nothing Maybe [Char]
    forall a. Maybe a
    Nothing)
    ioe_cannotFlushNotSeekable :: forall a. IO a
    ioe_cannotFlushNotSeekable = IOException -> IO a
    forall a. HasCallStack => IOException -> IO a
    ioException
       (Maybe Handle
    -> IOErrorType
    -> [Char]
    -> [Char]
    -> Maybe CInt
    -> Maybe [Char]
    -> IOException
    IOError Maybe Handle
    forall a. Maybe a
    Nothing IOErrorType
    IllegalOperation [Char]
    ""
          [Char]
    "cannot flush the read buffer: underlying device is not seekable"
            Maybe CInt
    forall a. Maybe a
    Nothing Maybe [Char]
    forall a. Maybe a
    Nothing)

    ioe_finalizedHandle :: FilePath -> Handle__
    ioe_finalizedHandle :: [Char] -> Handle__
    ioe_finalizedHandle [Char]
    fp = IOException -> Handle__
    forall a e. (HasCallStack, Exception e) => e -> a
    throw
       (Maybe Handle
    -> IOErrorType
    -> [Char]
    -> [Char]
    -> Maybe CInt
    -> Maybe [Char]
    -> IOException
    IOError Maybe Handle
    forall a. Maybe a
    Nothing IOErrorType
    IllegalOperation [Char]
    ""
            [Char]
    "handle is finalized" Maybe CInt
    forall a. Maybe a
    Nothing ([Char] -> Maybe [Char]
    forall a. a -> Maybe a
    Just [Char]
    fp))

    ioe_bufsiz :: Int -> IO a
    ioe_bufsiz :: forall a. Int -> IO a
    ioe_bufsiz Int
    n = IOException -> IO a
    forall a. HasCallStack => IOException -> IO a
    ioException
       (Maybe Handle
    -> IOErrorType
    -> [Char]
    -> [Char]
    -> Maybe CInt
    -> Maybe [Char]
    -> IOException
    IOError Maybe Handle
    forall a. Maybe a
    Nothing IOErrorType
    InvalidArgument [Char]
    "hSetBuffering"
            ([Char]
    "illegal buffer size " [Char] -> [Char] -> [Char]
    forall a. [a] -> [a] -> [a]
    ++ Int -> Int -> [Char] -> [Char]
    forall a. Show a => Int -> a -> [Char] -> [Char]
    showsPrec Int
    9 Int
    n []) Maybe CInt
    forall a. Maybe a
    Nothing Maybe [Char]
    forall a. Maybe a
    Nothing)
                                    -- 9 => should be parens'ified.

    -- ---------------------------------------------------------------------------
    -- Wrapper for Handle encoding/decoding.

    -- The interface for TextEncoding changed so that a TextEncoding doesn't raise
    -- an exception if it encounters an invalid sequence. Furthermore, encoding
    -- returns a reason as to why encoding stopped, letting us know if it was due
    -- to input/output underflow or an invalid sequence.
    --
    -- This code adapts this elaborated interface back to the original TextEncoding
    -- interface.
    --
    -- FIXME: it is possible that Handle code using the haDecoder/haEncoder fields
    -- could be made clearer by using the 'encode' interface directly. I have not
    -- looked into this.

    streamEncode :: BufferCodec from to state
                 -> Buffer from -> Buffer to
                 -> IO (Buffer from, Buffer to)
    streamEncode :: forall from to state.
    BufferCodec from to state
    -> Buffer from -> Buffer to -> IO (Buffer from, Buffer to)
    streamEncode BufferCodec from to state
    codec Buffer from
    from Buffer to
    to = ((CodingProgress, Buffer from, Buffer to)
     -> (Buffer from, Buffer to))
    -> IO (CodingProgress, Buffer from, Buffer to)
    -> IO (Buffer from, Buffer to)
    forall a b. (a -> b) -> IO a -> IO b
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    fmap (\(CodingProgress
    _, Buffer from
    from', Buffer to
    to') -> (Buffer from
    from', Buffer to
    to')) (IO (CodingProgress, Buffer from, Buffer to)
     -> IO (Buffer from, Buffer to))
    -> IO (CodingProgress, Buffer from, Buffer to)
    -> IO (Buffer from, Buffer to)
    forall a b. (a -> b) -> a -> b
    $ BufferCodec from to state -> CodeBuffer from to
    forall from to state.
    BufferCodec from to state -> CodeBuffer from to
    recoveringEncode BufferCodec from to state
    codec Buffer from
    from Buffer to
    to

    -- | Just like 'encode', but interleaves calls to 'encode' with calls to 'recover' in order to make as much progress as possible
    recoveringEncode :: BufferCodec from to state -> CodeBuffer from to
    recoveringEncode :: forall from to state.
    BufferCodec from to state -> CodeBuffer from to
    recoveringEncode BufferCodec from to state
    codec Buffer from
    from Buffer to
    to = Buffer from
    -> Buffer to -> IO (CodingProgress, Buffer from, Buffer to)
    go Buffer from
    from Buffer to
    to
      where
        go :: Buffer from
    -> Buffer to -> IO (CodingProgress, Buffer from, Buffer to)
    go Buffer from
    from Buffer to
    to = do
          (why, from', to') <- BufferCodec from to state
    -> Buffer from
    -> Buffer to
    -> IO (CodingProgress, Buffer from, Buffer to)
    forall from to state.
    BufferCodec from to state -> CodeBuffer from to
    encode BufferCodec from to state
    codec Buffer from
    from Buffer to
    to
          -- When we are dealing with Handles, we don't care about input/output
          -- underflow particularly, and we want to delay errors about invalid
          -- sequences as far as possible.
          case why of
            CodingProgress
    InvalidSequence | Buffer from -> Int
    forall e. Buffer e -> Int
    bufL Buffer from
    from Int -> Int -> Bool
    forall a. Eq a => a -> a -> Bool
    == Buffer from -> Int
    forall e. Buffer e -> Int
    bufL Buffer from
    from' -> do
              -- NB: it is OK to call recover here. Because we saw InvalidSequence, by the invariants
              -- on "encode" it must be the case that there is at least one elements available in the output
              -- buffer. Furthermore, clearly there is at least one element in the input buffer since we found
              -- something invalid there!
              (from', to') <- BufferCodec from to state
    -> Buffer from -> Buffer to -> IO (Buffer from, Buffer to)
    forall from to state.
    BufferCodec from to state
    -> Buffer from -> Buffer to -> IO (Buffer from, Buffer to)
    recover BufferCodec from to state
    codec Buffer from
    from' Buffer to
    to'
              go from' to'
            CodingProgress
    _ -> (CodingProgress, Buffer from, Buffer to)
    -> IO (CodingProgress, Buffer from, Buffer to)
    forall a. a -> IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (CodingProgress
    why, Buffer from
    from', Buffer to
    to')

    -- -----------------------------------------------------------------------------
    -- Handle Finalizers

    -- For a duplex handle, we arrange that the read side points to the write side
    -- (and hence keeps it alive if the read side is alive).  This is done by
    -- having the haOtherSide field of the read side point to the read side.
    -- The finalizer is then placed on the write side, and the handle only gets
    -- finalized once, when both sides are no longer required.

    -- NOTE about finalized handles: It's possible that a handle can be
    -- finalized and then we try to use it later, for example if the
    -- handle is referenced from another finalizer, or from a thread that
    -- has become unreferenced and then resurrected (arguably in the
    -- latter case we shouldn't finalize the Handle...).  Anyway,
    -- we try to emit a helpful message which is better than nothing.
    --
    -- [later; 8/2010] However, a program like this can yield a strange
    -- error message:
    --
    --   main = writeFile "out" loop
    --   loop = let x = x in x
    --
    -- because the main thread and the Handle are both unreachable at the
    -- same time, the Handle may get finalized before the main thread
    -- receives the NonTermination exception, and the exception handler
    -- will then report an error.  We'd rather this was not an error and
    -- the program just prints "<<loop>>".

    handleFinalizer :: FilePath -> MVar Handle__ -> IO ()
    handleFinalizer :: HandleFinalizer
    handleFinalizer [Char]
    fp MVar Handle__
    m = do
      handle_ <- MVar Handle__ -> IO Handle__
    forall a. MVar a -> IO a
    takeMVar MVar Handle__
    m
      (handle_', mb_exc) <- hClose_help handle_
      putMVar m handle_'
      case mb_exc of
        Just SomeException
    exc -> SomeException -> IO ()
    forall e a. (HasCallStack, Exception e) => e -> IO a
    throwIO SomeException
    exc
        Maybe SomeException
    Nothing -> () -> IO ()
    forall a. a -> IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return ()

    {-
       Note [Handling exceptions during Handle finalization]
       ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
       Handles which become unreachable are flushed closed automatically by the
       garbage collector, which calls 'GHC.Internal.IO.Handle.Internals.handleFinalizer'.
       However, numerous things can go wrong during this process. For instance,
       while we are flushing we may find that the handle's device is full. What to
       do in this case?

       For a long time we would simply ignore the failure. However, silently
       ignoring failures is rarely a good option. For this reason the
       'GHC.Weak.Finalizer.runFinalizerBatch' now catches exceptions and
       dispatches them to a notification action (which can be set via
       'GHC.Internal.Weak.Finalize.setFinalizerExceptionHandler').

       This then poses the question of what happens if the exception notification
       action itself throws an exception. We currently ignore such second-order
       exceptions.

       Note that stdout/stderr are handled a bit differently, since they are never
       finalized by the GC. Instead, 'GHC.Internal.TopHandler.flushStdHandles' explicitly
       catches exceptions from hFlush and dispatches them to the usual Weak
       finalization exception notifier.

       See #21336.

     -}

    -- ---------------------------------------------------------------------------
    -- Allocating buffers

    -- using an 8k char buffer instead of 32k improved performance for a
    -- basic "cat" program by ~30% for me.  --SDM
    dEFAULT_CHAR_BUFFER_SIZE :: Int
    dEFAULT_CHAR_BUFFER_SIZE :: Int
    dEFAULT_CHAR_BUFFER_SIZE = Int
    2048 -- 8k/sizeof(HsChar)

    getCharBuffer :: IODevice dev => dev -> BufferState
                  -> IO (IORef CharBuffer, BufferMode)
    getCharBuffer :: forall dev.
    IODevice dev =>
    dev -> BufferState -> IO (IORef (Buffer Char), BufferMode)
    getCharBuffer dev
    dev BufferState
    state = do
      buffer <- Int -> BufferState -> IO (Buffer Char)
    newCharBuffer Int
    dEFAULT_CHAR_BUFFER_SIZE BufferState
    state
      ioref  <- newIORef buffer
      is_tty <- IODevice.isTerminal dev

      let buffer_mode
             | Bool
    is_tty    = BufferMode
    LineBuffering
             | Bool
    otherwise = Maybe Int -> BufferMode
    BlockBuffering Maybe Int
    forall a. Maybe a
    Nothing

      return (ioref, buffer_mode)

    mkUnBuffer :: BufferState -> IO (IORef CharBuffer, BufferMode)
    mkUnBuffer :: BufferState -> IO (IORef (Buffer Char), BufferMode)
    mkUnBuffer BufferState
    state = do
      buffer <- Int -> BufferState -> IO (Buffer Char)
    newCharBuffer Int
    dEFAULT_CHAR_BUFFER_SIZE BufferState
    state
                  --  See [note Buffer Sizing], GHC.Internal.IO.Handle.Types
      ref <- newIORef buffer
      return (ref, NoBuffering)

    -- -----------------------------------------------------------------------------
    -- Flushing buffers

    -- | syncs the file with the buffer, including moving the
    -- file pointer backwards in the case of a read buffer.  This can fail
    -- on a non-seekable read Handle.
    flushBuffer :: Handle__ -> IO ()
    flushBuffer :: Handle__ -> IO ()
    flushBuffer h_ :: Handle__
    h_@Handle__{dev
    Maybe (MVar Handle__)
    Maybe TextEncoding
    Maybe (TextEncoder enc_state)
    Maybe (TextDecoder dec_state)
    IORef (dec_state, Buffer Word8)
    IORef (Buffer Char)
    IORef (Buffer Word8)
    IORef (BufferList Char)
    Newline
    BufferMode
    HandleType
    haOtherSide :: Handle__ -> Maybe (MVar Handle__)
    haOutputNL :: Handle__ -> Newline
    haInputNL :: Handle__ -> Newline
    haCodec :: Handle__ -> Maybe TextEncoding
    haDecoder :: ()
    haEncoder :: ()
    haBuffers :: Handle__ -> IORef (BufferList Char)
    haCharBuffer :: Handle__ -> IORef (Buffer Char)
    haLastDecode :: ()
    haBufferMode :: Handle__ -> BufferMode
    haByteBuffer :: Handle__ -> IORef (Buffer Word8)
    haType :: Handle__ -> HandleType
    haDevice :: ()
    haDevice :: dev
    haType :: HandleType
    haByteBuffer :: IORef (Buffer Word8)
    haBufferMode :: BufferMode
    haLastDecode :: IORef (dec_state, Buffer Word8)
    haCharBuffer :: IORef (Buffer Char)
    haBuffers :: IORef (BufferList Char)
    haEncoder :: Maybe (TextEncoder enc_state)
    haDecoder :: Maybe (TextDecoder dec_state)
    haCodec :: Maybe TextEncoding
    haInputNL :: Newline
    haOutputNL :: Newline
    haOtherSide :: Maybe (MVar Handle__)
    ..} = do
      buf <- IORef (Buffer Char) -> IO (Buffer Char)
    forall a. IORef a -> IO a
    readIORef IORef (Buffer Char)
    haCharBuffer
      case bufState buf of
        BufferState
    ReadBuffer -> do
            Handle__ -> IO ()
    flushCharReadBuffer Handle__
    h_
            Handle__ -> IO ()
    flushByteReadBuffer Handle__
    h_
        BufferState
    WriteBuffer ->
            Handle__ -> IO ()
    flushByteWriteBuffer Handle__
    h_

    -- | flushes the Char buffer only.  Works on all Handles.
    flushCharBuffer :: Handle__ -> IO ()
    flushCharBuffer :: Handle__ -> IO ()
    flushCharBuffer h_ :: Handle__
    h_@Handle__{dev
    Maybe (MVar Handle__)
    Maybe TextEncoding
    Maybe (TextEncoder enc_state)
    Maybe (TextDecoder dec_state)
    IORef (dec_state, Buffer Word8)
    IORef (Buffer Char)
    IORef (Buffer Word8)
    IORef (BufferList Char)
    Newline
    BufferMode
    HandleType
    haOtherSide :: Handle__ -> Maybe (MVar Handle__)
    haOutputNL :: Handle__ -> Newline
    haInputNL :: Handle__ -> Newline
    haCodec :: Handle__ -> Maybe TextEncoding
    haDecoder :: ()
    haEncoder :: ()
    haBuffers :: Handle__ -> IORef (BufferList Char)
    haCharBuffer :: Handle__ -> IORef (Buffer Char)
    haLastDecode :: ()
    haBufferMode :: Handle__ -> BufferMode
    haByteBuffer :: Handle__ -> IORef (Buffer Word8)
    haType :: Handle__ -> HandleType
    haDevice :: ()
    haDevice :: dev
    haType :: HandleType
    haByteBuffer :: IORef (Buffer Word8)
    haBufferMode :: BufferMode
    haLastDecode :: IORef (dec_state, Buffer Word8)
    haCharBuffer :: IORef (Buffer Char)
    haBuffers :: IORef (BufferList Char)
    haEncoder :: Maybe (TextEncoder enc_state)
    haDecoder :: Maybe (TextDecoder dec_state)
    haCodec :: Maybe TextEncoding
    haInputNL :: Newline
    haOutputNL :: Newline
    haOtherSide :: Maybe (MVar Handle__)
    ..} = do
      cbuf <- IORef (Buffer Char) -> IO (Buffer Char)
    forall a. IORef a -> IO a
    readIORef IORef (Buffer Char)
    haCharBuffer
      case bufState cbuf of
        BufferState
    ReadBuffer ->
            Handle__ -> IO ()
    flushCharReadBuffer Handle__
    h_
        BufferState
    WriteBuffer ->
            -- Nothing to do here. Char buffer on a write Handle is always empty
            -- between Handle operations.
            -- See [note Buffer Flushing], GHC.IO.Handle.Types.
            Bool -> IO () -> IO ()
    forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
    when (Bool -> Bool
    not (Buffer Char -> Bool
    forall e. Buffer e -> Bool
    isEmptyBuffer Buffer Char
    cbuf)) (IO () -> IO ()) -> IO () -> IO ()
    forall a b. (a -> b) -> a -> b
    $
               [Char] -> IO ()
    forall a. HasCallStack => [Char] -> a
    error [Char]
    "internal IO library error: Char buffer non-empty"

    -- -----------------------------------------------------------------------------
    -- Writing data (flushing write buffers)

    -- flushWriteBuffer flushes the byte buffer iff it contains pending write
    -- data. Because the Char buffer on a write Handle is always empty between
    -- Handle operations (see [note Buffer Flushing], GHC.IO.Handle.Types),
    -- both buffers are empty after this.
    flushWriteBuffer :: Handle__ -> IO ()
    flushWriteBuffer :: Handle__ -> IO ()
    flushWriteBuffer h_ :: Handle__
    h_@Handle__{dev
    Maybe (MVar Handle__)
    Maybe TextEncoding
    Maybe (TextEncoder enc_state)
    Maybe (TextDecoder dec_state)
    IORef (dec_state, Buffer Word8)
    IORef (Buffer Char)
    IORef (Buffer Word8)
    IORef (BufferList Char)
    Newline
    BufferMode
    HandleType
    haOtherSide :: Handle__ -> Maybe (MVar Handle__)
    haOutputNL :: Handle__ -> Newline
    haInputNL :: Handle__ -> Newline
    haCodec :: Handle__ -> Maybe TextEncoding
    haDecoder :: ()
    haEncoder :: ()
    haBuffers :: Handle__ -> IORef (BufferList Char)
    haCharBuffer :: Handle__ -> IORef (Buffer Char)
    haLastDecode :: ()
    haBufferMode :: Handle__ -> BufferMode
    haByteBuffer :: Handle__ -> IORef (Buffer Word8)
    haType :: Handle__ -> HandleType
    haDevice :: ()
    haDevice :: dev
    haType :: HandleType
    haByteBuffer :: IORef (Buffer Word8)
    haBufferMode :: BufferMode
    haLastDecode :: IORef (dec_state, Buffer Word8)
    haCharBuffer :: IORef (Buffer Char)
    haBuffers :: IORef (BufferList Char)
    haEncoder :: Maybe (TextEncoder enc_state)
    haDecoder :: Maybe (TextDecoder dec_state)
    haCodec :: Maybe TextEncoding
    haInputNL :: Newline
    haOutputNL :: Newline
    haOtherSide :: Maybe (MVar Handle__)
    ..} = do
      buf <- IORef (Buffer Word8) -> IO (Buffer Word8)
    forall a. IORef a -> IO a
    readIORef IORef (Buffer Word8)
    haByteBuffer
      when (isWriteBuffer buf) $ flushByteWriteBuffer h_

    flushByteWriteBuffer :: Handle__ -> IO ()
    flushByteWriteBuffer :: Handle__ -> IO ()
    flushByteWriteBuffer h_ :: Handle__
    h_@Handle__{dev
    Maybe (MVar Handle__)
    Maybe TextEncoding
    Maybe (TextEncoder enc_state)
    Maybe (TextDecoder dec_state)
    IORef (dec_state, Buffer Word8)
    IORef (Buffer Char)
    IORef (Buffer Word8)
    IORef (BufferList Char)
    Newline
    BufferMode
    HandleType
    haOtherSide :: Handle__ -> Maybe (MVar Handle__)
    haOutputNL :: Handle__ -> Newline
    haInputNL :: Handle__ -> Newline
    haCodec :: Handle__ -> Maybe TextEncoding
    haDecoder :: ()
    haEncoder :: ()
    haBuffers :: Handle__ -> IORef (BufferList Char)
    haCharBuffer :: Handle__ -> IORef (Buffer Char)
    haLastDecode :: ()
    haBufferMode :: Handle__ -> BufferMode
    haByteBuffer :: Handle__ -> IORef (Buffer Word8)
    haType :: Handle__ -> HandleType
    haDevice :: ()
    haDevice :: dev
    haType :: HandleType
    haByteBuffer :: IORef (Buffer Word8)
    haBufferMode :: BufferMode
    haLastDecode :: IORef (dec_state, Buffer Word8)
    haCharBuffer :: IORef (Buffer Char)
    haBuffers :: IORef (BufferList Char)
    haEncoder :: Maybe (TextEncoder enc_state)
    haDecoder :: Maybe (TextDecoder dec_state)
    haCodec :: Maybe TextEncoding
    haInputNL :: Newline
    haOutputNL :: Newline
    haOtherSide :: Maybe (MVar Handle__)
    ..} = do
      bbuf <- IORef (Buffer Word8) -> IO (Buffer Word8)
    forall a. IORef a -> IO a
    readIORef IORef (Buffer Word8)
    haByteBuffer
      when (not (isEmptyBuffer bbuf)) $ do
        bbuf' <- Buffered.flushWriteBuffer haDevice bbuf
        debugIO ("flushByteWriteBuffer: bbuf=" ++ summaryBuffer bbuf')
        writeIORef haByteBuffer bbuf'

    -- write the contents of the CharBuffer to the Handle__.
    -- The data will be encoded and pushed to the byte buffer,
    -- flushing if the buffer becomes full.
    -- Data is written to the handles current buffer offset.
    writeCharBuffer :: Handle__ -> CharBuffer -> IO ()
    writeCharBuffer :: Handle__ -> Buffer Char -> IO ()
    writeCharBuffer h_ :: Handle__
    h_@Handle__{dev
    Maybe (MVar Handle__)
    Maybe TextEncoding
    Maybe (TextEncoder enc_state)
    Maybe (TextDecoder dec_state)
    IORef (dec_state, Buffer Word8)
    IORef (Buffer Char)
    IORef (Buffer Word8)
    IORef (BufferList Char)
    Newline
    BufferMode
    HandleType
    haOtherSide :: Handle__ -> Maybe (MVar Handle__)
    haOutputNL :: Handle__ -> Newline
    haInputNL :: Handle__ -> Newline
    haCodec :: Handle__ -> Maybe TextEncoding
    haDecoder :: ()
    haEncoder :: ()
    haBuffers :: Handle__ -> IORef (BufferList Char)
    haCharBuffer :: Handle__ -> IORef (Buffer Char)
    haLastDecode :: ()
    haBufferMode :: Handle__ -> BufferMode
    haByteBuffer :: Handle__ -> IORef (Buffer Word8)
    haType :: Handle__ -> HandleType
    haDevice :: ()
    haDevice :: dev
    haType :: HandleType
    haByteBuffer :: IORef (Buffer Word8)
    haBufferMode :: BufferMode
    haLastDecode :: IORef (dec_state, Buffer Word8)
    haCharBuffer :: IORef (Buffer Char)
    haBuffers :: IORef (BufferList Char)
    haEncoder :: Maybe (TextEncoder enc_state)
    haDecoder :: Maybe (TextDecoder dec_state)
    haCodec :: Maybe TextEncoding
    haInputNL :: Newline
    haOutputNL :: Newline
    haOtherSide :: Maybe (MVar Handle__)
    ..} !Buffer Char
    cbuf = do
      --
      bbuf <- IORef (Buffer Word8) -> IO (Buffer Word8)
    forall a. IORef a -> IO a
    readIORef IORef (Buffer Word8)
    haByteBuffer

      debugIO ("writeCharBuffer: cbuf=" ++ summaryBuffer cbuf ++
            " bbuf=" ++ summaryBuffer bbuf)

      (cbuf',bbuf') <- case haEncoder of
        Maybe (TextEncoder enc_state)
    Nothing      -> Buffer Char -> Buffer Word8 -> IO (Buffer Char, Buffer Word8)
    latin1_encode Buffer Char
    cbuf Buffer Word8
    bbuf
        Just TextEncoder enc_state
    encoder -> (TextEncoder enc_state
    -> Buffer Char -> Buffer Word8 -> IO (Buffer Char, Buffer Word8)
    forall from to state.
    BufferCodec from to state
    -> Buffer from -> Buffer to -> IO (Buffer from, Buffer to)
    streamEncode TextEncoder enc_state
    encoder) Buffer Char
    cbuf Buffer Word8
    bbuf

      debugIO ("writeCharBuffer after encoding: cbuf=" ++ summaryBuffer cbuf' ++
            " bbuf=" ++ summaryBuffer bbuf')

              -- flush the byte buffer if it is full
      if isFullBuffer bbuf'
              --  or we made no progress
         || not (isEmptyBuffer cbuf') && bufL cbuf' == bufL cbuf
              -- or the byte buffer has more elements than the user wanted buffered
         || (case haBufferMode of
              BlockBuffering (Just Int
    s) -> Buffer Word8 -> Int
    forall e. Buffer e -> Int
    bufferElems Buffer Word8
    bbuf' Int -> Int -> Bool
    forall a. Ord a => a -> a -> Bool
    >= Int
    s
              BufferMode
    NoBuffering -> Bool
    True
              BufferMode
    _other -> Bool
    False)
        then do
          bbuf'' <- Buffered.flushWriteBuffer haDevice bbuf'
          writeIORef haByteBuffer bbuf''
          debugIO ("writeCharBuffer after flushing: cbuf=" ++ summaryBuffer bbuf'')
        else
          writeIORef haByteBuffer bbuf'

      if not (isEmptyBuffer cbuf')
         then writeCharBuffer h_ cbuf'
         else return ()

    -- -----------------------------------------------------------------------------
    -- Flushing read buffers

    -- It is always possible to flush the Char buffer back to the byte buffer.
    flushCharReadBuffer :: Handle__ -> IO ()
    flushCharReadBuffer :: Handle__ -> IO ()
    flushCharReadBuffer Handle__{dev
    Maybe (MVar Handle__)
    Maybe TextEncoding
    Maybe (TextEncoder enc_state)
    Maybe (TextDecoder dec_state)
    IORef (dec_state, Buffer Word8)
    IORef (Buffer Char)
    IORef (Buffer Word8)
    IORef (BufferList Char)
    Newline
    BufferMode
    HandleType
    haOtherSide :: Handle__ -> Maybe (MVar Handle__)
    haOutputNL :: Handle__ -> Newline
    haInputNL :: Handle__ -> Newline
    haCodec :: Handle__ -> Maybe TextEncoding
    haDecoder :: ()
    haEncoder :: ()
    haBuffers :: Handle__ -> IORef (BufferList Char)
    haCharBuffer :: Handle__ -> IORef (Buffer Char)
    haLastDecode :: ()
    haBufferMode :: Handle__ -> BufferMode
    haByteBuffer :: Handle__ -> IORef (Buffer Word8)
    haType :: Handle__ -> HandleType
    haDevice :: ()
    haDevice :: dev
    haType :: HandleType
    haByteBuffer :: IORef (Buffer Word8)
    haBufferMode :: BufferMode
    haLastDecode :: IORef (dec_state, Buffer Word8)
    haCharBuffer :: IORef (Buffer Char)
    haBuffers :: IORef (BufferList Char)
    haEncoder :: Maybe (TextEncoder enc_state)
    haDecoder :: Maybe (TextDecoder dec_state)
    haCodec :: Maybe TextEncoding
    haInputNL :: Newline
    haOutputNL :: Newline
    haOtherSide :: Maybe (MVar Handle__)
    ..} = do
      cbuf <- IORef (Buffer Char) -> IO (Buffer Char)
    forall a. IORef a -> IO a
    readIORef IORef (Buffer Char)
    haCharBuffer
      if isWriteBuffer cbuf || isEmptyBuffer cbuf then return () else do

      -- haLastDecode is the byte buffer just before we did our last batch of
      -- decoding.  We're going to re-decode the bytes up to the current char,
      -- to find out where we should revert the byte buffer to.
      (codec_state, bbuf0) <- readIORef haLastDecode

      cbuf0 <- readIORef haCharBuffer
      writeIORef haCharBuffer cbuf0{ bufL=0, bufR=0 }

      -- if we haven't used any characters from the char buffer, then just
      -- re-install the old byte buffer.
      if bufL cbuf0 == 0
         then do writeIORef haByteBuffer bbuf0
                 return ()
         else do

      case haDecoder of
        Maybe (TextDecoder dec_state)
    Nothing ->
          IORef (Buffer Word8) -> Buffer Word8 -> IO ()
    forall a. IORef a -> a -> IO ()
    writeIORef IORef (Buffer Word8)
    haByteBuffer Buffer Word8
    bbuf0 { bufL = bufL bbuf0 + bufL cbuf0 }
          -- no decoder: the number of bytes to decode is the same as the
          -- number of chars we have used up.

        Just TextDecoder dec_state
    decoder -> do
          [Char] -> IO ()
    debugIO ([Char]
    "flushCharReadBuffer re-decode, bbuf=" [Char] -> [Char] -> [Char]
    forall a. [a] -> [a] -> [a]
    ++ Buffer Word8 -> [Char]
    forall a. Buffer a -> [Char]
    summaryBuffer Buffer Word8
    bbuf0 [Char] -> [Char] -> [Char]
    forall a. [a] -> [a] -> [a]
    ++
                   [Char]
    " cbuf=" [Char] -> [Char] -> [Char]
    forall a. [a] -> [a] -> [a]
    ++ Buffer Char -> [Char]
    forall a. Buffer a -> [Char]
    summaryBuffer Buffer Char
    cbuf0)

          -- restore the codec state
          TextDecoder dec_state -> dec_state -> IO ()
    forall from to state. BufferCodec from to state -> state -> IO ()
    setState TextDecoder dec_state
    decoder dec_state
    codec_state

          (bbuf1,cbuf1) <- (TextDecoder dec_state
    -> Buffer Word8 -> Buffer Char -> IO (Buffer Word8, Buffer Char)
    forall from to state.
    BufferCodec from to state
    -> Buffer from -> Buffer to -> IO (Buffer from, Buffer to)
    streamEncode TextDecoder dec_state
    decoder) Buffer Word8
    bbuf0
                                   Buffer Char
    cbuf0{ bufL=0, bufR=0, bufSize = bufL cbuf0 }

          -- We should not need to update the offset here. The bytebuffer contains the
          -- offset for the next read after it's used up. But this function only flushes
          -- the char buffer.
          -- let bbuf2 = bbuf1 -- {bufOffset = bufOffset bbuf1 - fromIntegral (bufL bbuf1)}
          -- debugIO ("finished, bbuf=" ++ summaryBuffer bbuf2 ++
          --          " cbuf=" ++ summaryBuffer cbuf1)

          writeIORef haByteBuffer bbuf1

    -- When flushing the byte read buffer, we seek backwards by the number
    -- of characters in the buffer.  The file descriptor must therefore be
    -- seekable: attempting to flush the read buffer on an unseekable
    -- handle is not allowed.

    flushByteReadBuffer :: Handle__ -> IO ()
    flushByteReadBuffer :: Handle__ -> IO ()
    flushByteReadBuffer h_ :: Handle__
    h_@Handle__{dev
    Maybe (MVar Handle__)
    Maybe TextEncoding
    Maybe (TextEncoder enc_state)
    Maybe (TextDecoder dec_state)
    IORef (dec_state, Buffer Word8)
    IORef (Buffer Char)
    IORef (Buffer Word8)
    IORef (BufferList Char)
    Newline
    BufferMode
    HandleType
    haOtherSide :: Handle__ -> Maybe (MVar Handle__)
    haOutputNL :: Handle__ -> Newline
    haInputNL :: Handle__ -> Newline
    haCodec :: Handle__ -> Maybe TextEncoding
    haDecoder :: ()
    haEncoder :: ()
    haBuffers :: Handle__ -> IORef (BufferList Char)
    haCharBuffer :: Handle__ -> IORef (Buffer Char)
    haLastDecode :: ()
    haBufferMode :: Handle__ -> BufferMode
    haByteBuffer :: Handle__ -> IORef (Buffer Word8)
    haType :: Handle__ -> HandleType
    haDevice :: ()
    haDevice :: dev
    haType :: HandleType
    haByteBuffer :: IORef (Buffer Word8)
    haBufferMode :: BufferMode
    haLastDecode :: IORef (dec_state, Buffer Word8)
    haCharBuffer :: IORef (Buffer Char)
    haBuffers :: IORef (BufferList Char)
    haEncoder :: Maybe (TextEncoder enc_state)
    haDecoder :: Maybe (TextDecoder dec_state)
    haCodec :: Maybe TextEncoding
    haInputNL :: Newline
    haOutputNL :: Newline
    haOtherSide :: Maybe (MVar Handle__)
    ..} = do
      bbuf <- IORef (Buffer Word8) -> IO (Buffer Word8)
    forall a. IORef a -> IO a
    readIORef IORef (Buffer Word8)
    haByteBuffer

      if isEmptyBuffer bbuf then return () else do

      seekable <- IODevice.isSeekable haDevice
      when (not seekable) $ ioe_cannotFlushNotSeekable

      let seek = Int -> Int
    forall a. Num a => a -> a
    negate (Buffer Word8 -> Int
    forall e. Buffer e -> Int
    bufR Buffer Word8
    bbuf Int -> Int -> Int
    forall a. Num a => a -> a -> a
    - Buffer Word8 -> Int
    forall e. Buffer e -> Int
    bufL Buffer Word8
    bbuf)
      let offset = Buffer Word8 -> Word64
    forall e. Buffer e -> Word64
    bufOffset Buffer Word8
    bbuf Word64 -> Word64 -> Word64
    forall a. Num a => a -> a -> a
    - Int -> Word64
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral (Buffer Word8 -> Int
    forall e. Buffer e -> Int
    bufR Buffer Word8
    bbuf Int -> Int -> Int
    forall a. Num a => a -> a -> a
    - Buffer Word8 -> Int
    forall e. Buffer e -> Int
    bufL Buffer Word8
    bbuf)

      debugIO ("flushByteReadBuffer: new file offset = " ++ show seek)
      debugIO ("flushByteReadBuffer: " ++ summaryBuffer bbuf)

      let mIOSeek   = dev -> SeekMode -> Integer -> IO Integer
    forall a. IODevice a => a -> SeekMode -> Integer -> IO Integer
    IODevice.seek dev
    haDevice SeekMode
    RelativeSeek (Int -> Integer
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral Int
    seek)
      -- win-io doesn't need this, but it allows us to error out on invalid offsets
      let winIOSeek = dev -> SeekMode -> Integer -> IO Integer
    forall a. IODevice a => a -> SeekMode -> Integer -> IO Integer
    IODevice.seek dev
    haDevice SeekMode
    AbsoluteSeek (Word64 -> Integer
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral Word64
    offset)

      _ <- mIOSeek <!> winIOSeek  -- execute one of these two seek functions

      writeIORef haByteBuffer bbuf{ bufL=0, bufR=0, bufOffset=offset }

    -- ----------------------------------------------------------------------------
    -- Making Handles

    {- Note [Making offsets for append]
       ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
      The WINIO subysstem keeps track of offsets for handles
      on the Haskell side of things instead of letting the OS
      handle it. This requires us to establish the correct offset
      for a handle on creation. This is usually zero but slightly
      more tedious for append modes. There we fall back on IODevice
      functionality to establish the size of the file and then set
      the offset accordingly. This is only required for WINIO.
    -}

    -- | Make an @'MVar' 'Handle__'@ for use in a 'Handle'. This function
    -- does not install a finalizer; that must be done by the caller.
    mkHandleMVar :: (RawIO dev, IODevice dev, BufferedIO dev, Typeable dev) => dev
             -> FilePath
             -> HandleType
             -> Bool                     -- buffered?
             -> Maybe TextEncoding
             -> NewlineMode
             -> Maybe (MVar Handle__)
             -> IO (MVar Handle__)
    mkHandleMVar :: forall dev.
    (RawIO dev, IODevice dev, BufferedIO dev, Typeable dev) =>
    dev
    -> [Char]
    -> HandleType
    -> Bool
    -> Maybe TextEncoding
    -> NewlineMode
    -> Maybe (MVar Handle__)
    -> IO (MVar Handle__)
    mkHandleMVar dev
    dev [Char]
    filepath HandleType
    ha_type Bool
    buffered Maybe TextEncoding
    mb_codec NewlineMode
    nl Maybe (MVar Handle__)
    other_side =
       Maybe TextEncoding
    -> HandleType
    -> (forall es ds.
        Maybe (TextEncoder es)
        -> Maybe (TextDecoder ds) -> IO (MVar Handle__))
    -> IO (MVar Handle__)
    forall a.
    Maybe TextEncoding
    -> HandleType
    -> (forall es ds.
        Maybe (TextEncoder es) -> Maybe (TextDecoder ds) -> IO a)
    -> IO a
    openTextEncoding Maybe TextEncoding
    mb_codec HandleType
    ha_type ((forall es ds.
      Maybe (TextEncoder es)
      -> Maybe (TextDecoder ds) -> IO (MVar Handle__))
     -> IO (MVar Handle__))
    -> (forall es ds.
        Maybe (TextEncoder es)
        -> Maybe (TextDecoder ds) -> IO (MVar Handle__))
    -> IO (MVar Handle__)
    forall a b. (a -> b) -> a -> b
    $ \ Maybe (TextEncoder es)
    mb_encoder Maybe (TextDecoder ds)
    mb_decoder -> do

       let !buf_state :: BufferState
    buf_state = HandleType -> BufferState
    initBufferState HandleType
    ha_type
       !bbuf_no_offset <- (dev -> BufferState -> IO (Buffer Word8)
    forall dev.
    BufferedIO dev =>
    dev -> BufferState -> IO (Buffer Word8)
    Buffered.newBuffer dev
    dev BufferState
    buf_state)
       !buf_offset <- initHandleOffset
       let !bbuf = Buffer Word8
    bbuf_no_offset { bufOffset = buf_offset}

       bbufref <- newIORef bbuf
       last_decode <- newIORef (errorWithoutStackTrace "codec_state", bbuf)

       (cbufref,bmode) <-
             if buffered then getCharBuffer dev buf_state
                         else mkUnBuffer buf_state

       spares <- newIORef BufferListNil
       debugIO $ "making handle for " ++ filepath
       newMVar $ Handle__ { haDevice = dev,
                            haType = ha_type,
                            haBufferMode = bmode,
                            haByteBuffer = bbufref,
                            haLastDecode = last_decode,
                            haCharBuffer = cbufref,
                            haBuffers = spares,
                            haEncoder = mb_encoder,
                            haDecoder = mb_decoder,
                            haCodec = mb_codec,
                            haInputNL = inputNL nl,
                            haOutputNL = outputNL nl,
                            haOtherSide = other_side
                          }
      where
        -- See Note [Making offsets for append]
        initHandleOffset :: IO Word64
    initHandleOffset
          | HandleType -> Bool
    isAppendHandleType HandleType
    ha_type
          , Bool
    isWindowsNativeIO = do
              size <- dev -> IO Integer
    forall a. IODevice a => a -> IO Integer
    IODevice.getSize dev
    dev
              return (fromIntegral size :: Word64)
          | Bool
    otherwise = Word64 -> IO Word64
    forall a. a -> IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return Word64
    0

    mkHandle :: (RawIO dev, IODevice dev, BufferedIO dev, Typeable dev) => dev
             -> FilePath
             -> HandleType
             -> Bool                     -- buffered?
             -> Maybe TextEncoding
             -> NewlineMode
             -> Maybe HandleFinalizer
             -> Maybe (MVar Handle__)
             -> IO Handle
    mkHandle :: forall dev.
    (RawIO dev, IODevice dev, BufferedIO dev, Typeable dev) =>
    dev
    -> [Char]
    -> HandleType
    -> Bool
    -> Maybe TextEncoding
    -> NewlineMode
    -> Maybe HandleFinalizer
    -> Maybe (MVar Handle__)
    -> IO Handle
    mkHandle dev
    dev [Char]
    filepath HandleType
    ha_type Bool
    buffered Maybe TextEncoding
    mb_codec NewlineMode
    nl Maybe HandleFinalizer
    mb_finalizer Maybe (MVar Handle__)
    other_side = do
      mv <- dev
    -> [Char]
    -> HandleType
    -> Bool
    -> Maybe TextEncoding
    -> NewlineMode
    -> Maybe (MVar Handle__)
    -> IO (MVar Handle__)
    forall dev.
    (RawIO dev, IODevice dev, BufferedIO dev, Typeable dev) =>
    dev
    -> [Char]
    -> HandleType
    -> Bool
    -> Maybe TextEncoding
    -> NewlineMode
    -> Maybe (MVar Handle__)
    -> IO (MVar Handle__)
    mkHandleMVar dev
    dev [Char]
    filepath HandleType
    ha_type Bool
    buffered Maybe TextEncoding
    mb_codec NewlineMode
    nl Maybe (MVar Handle__)
    other_side
      let handle = [Char] -> MVar Handle__ -> Handle
    FileHandle [Char]
    filepath MVar Handle__
    mv
      case mb_finalizer of
        Maybe HandleFinalizer
    Nothing -> () -> IO ()
    forall a. a -> IO a
    forall (f :: * -> *) a. Applicative f => a -> f a
    pure ()
        Just HandleFinalizer
    finalizer -> Handle -> HandleFinalizer -> IO ()
    addHandleFinalizer Handle
    handle HandleFinalizer
    finalizer
      pure handle

    -- | makes a new 'Handle' without a finalizer.
    mkFileHandleNoFinalizer
                 :: (RawIO dev, IODevice dev, BufferedIO dev, Typeable dev)
                 => dev -- ^ the underlying IO device, which must support
                        -- 'IODevice', 'BufferedIO' and 'Typeable'
                 -> FilePath
                        -- ^ a string describing the 'Handle', e.g. the file
                        -- path for a file.  Used in error messages.
                 -> IOMode
                        -- The mode in which the 'Handle' is to be used
                 -> Maybe TextEncoding
                        -- Create the 'Handle' with no text encoding?
                 -> NewlineMode
                        -- Translate newlines?
                 -> IO Handle
    mkFileHandleNoFinalizer :: forall dev.
    (RawIO dev, IODevice dev, BufferedIO dev, Typeable dev) =>
    dev
    -> [Char]
    -> IOMode
    -> Maybe TextEncoding
    -> NewlineMode
    -> IO Handle
    mkFileHandleNoFinalizer dev
    dev [Char]
    filepath IOMode
    iomode Maybe TextEncoding
    mb_codec NewlineMode
    tr_newlines = do
       mv <- dev
    -> [Char]
    -> HandleType
    -> Bool
    -> Maybe TextEncoding
    -> NewlineMode
    -> Maybe (MVar Handle__)
    -> IO (MVar Handle__)
    forall dev.
    (RawIO dev, IODevice dev, BufferedIO dev, Typeable dev) =>
    dev
    -> [Char]
    -> HandleType
    -> Bool
    -> Maybe TextEncoding
    -> NewlineMode
    -> Maybe (MVar Handle__)
    -> IO (MVar Handle__)
    mkHandleMVar dev
    dev [Char]
    filepath (IOMode -> HandleType
    ioModeToHandleType IOMode
    iomode) Bool
    True{-buffered-}
                          Maybe TextEncoding
    mb_codec
                          NewlineMode
    tr_newlines
                          Maybe (MVar Handle__)
    forall a. Maybe a
    Nothing{-other_side-}
       pure (FileHandle filepath mv)

    -- | makes a new 'Handle'
    mkFileHandle :: (RawIO dev, IODevice dev, BufferedIO dev, Typeable dev)
                 => dev -- ^ the underlying IO device, which must support
                        -- 'IODevice', 'BufferedIO' and 'Typeable'
                 -> FilePath
                        -- ^ a string describing the 'Handle', e.g. the file
                        -- path for a file.  Used in error messages.
                 -> IOMode
                        -- The mode in which the 'Handle' is to be used
                 -> Maybe TextEncoding
                        -- Create the 'Handle' with no text encoding?
                 -> NewlineMode
                        -- Translate newlines?
                 -> IO Handle

    mkFileHandle :: forall dev.
    (RawIO dev, IODevice dev, BufferedIO dev, Typeable dev) =>
    dev
    -> [Char]
    -> IOMode
    -> Maybe TextEncoding
    -> NewlineMode
    -> IO Handle
    mkFileHandle dev
    dev [Char]
    filepath IOMode
    iomode Maybe TextEncoding
    mb_codec NewlineMode
    tr_newlines = do
       h <- dev
    -> [Char]
    -> IOMode
    -> Maybe TextEncoding
    -> NewlineMode
    -> IO Handle
    forall dev.
    (RawIO dev, IODevice dev, BufferedIO dev, Typeable dev) =>
    dev
    -> [Char]
    -> IOMode
    -> Maybe TextEncoding
    -> NewlineMode
    -> IO Handle
    mkFileHandleNoFinalizer dev
    dev [Char]
    filepath IOMode
    iomode Maybe TextEncoding
    mb_codec NewlineMode
    tr_newlines
       addHandleFinalizer h handleFinalizer
       pure h

    -- | like 'mkFileHandle', except that a 'Handle' is created with two
    -- independent buffers, one for reading and one for writing.  Used for
    -- full-duplex streams, such as network sockets.
    mkDuplexHandleNoFinalizer ::
      (RawIO dev, IODevice dev, BufferedIO dev, Typeable dev)
         => dev -> FilePath -> Maybe TextEncoding -> NewlineMode -> IO Handle
    mkDuplexHandleNoFinalizer :: forall dev.
    (RawIO dev, IODevice dev, BufferedIO dev, Typeable dev) =>
    dev -> [Char] -> Maybe TextEncoding -> NewlineMode -> IO Handle
    mkDuplexHandleNoFinalizer dev
    dev [Char]
    filepath Maybe TextEncoding
    mb_codec NewlineMode
    tr_newlines = do

      write_m <-
           dev
    -> [Char]
    -> HandleType
    -> Bool
    -> Maybe TextEncoding
    -> NewlineMode
    -> Maybe (MVar Handle__)
    -> IO (MVar Handle__)
    forall dev.
    (RawIO dev, IODevice dev, BufferedIO dev, Typeable dev) =>
    dev
    -> [Char]
    -> HandleType
    -> Bool
    -> Maybe TextEncoding
    -> NewlineMode
    -> Maybe (MVar Handle__)
    -> IO (MVar Handle__)
    mkHandleMVar dev
    dev [Char]
    filepath HandleType
    WriteHandle Bool
    True Maybe TextEncoding
    mb_codec
                            NewlineMode
    tr_newlines
                            Maybe (MVar Handle__)
    forall a. Maybe a
    Nothing -- no other side

      read_m <-
          mkHandleMVar dev filepath ReadHandle True mb_codec
                            tr_newlines
                            (Just write_m)

      return (DuplexHandle filepath read_m write_m)

    -- | like 'mkFileHandle', except that a 'Handle' is created with two
    -- independent buffers, one for reading and one for writing.  Used for
    -- full-duplex streams, such as network sockets.
    mkDuplexHandle :: (RawIO dev, IODevice dev, BufferedIO dev, Typeable dev) => dev
                   -> FilePath -> Maybe TextEncoding -> NewlineMode -> IO Handle
    mkDuplexHandle :: forall dev.
    (RawIO dev, IODevice dev, BufferedIO dev, Typeable dev) =>
    dev -> [Char] -> Maybe TextEncoding -> NewlineMode -> IO Handle
    mkDuplexHandle dev
    dev [Char]
    filepath Maybe TextEncoding
    mb_codec NewlineMode
    tr_newlines = do
      handle <- dev -> [Char] -> Maybe TextEncoding -> NewlineMode -> IO Handle
    forall dev.
    (RawIO dev, IODevice dev, BufferedIO dev, Typeable dev) =>
    dev -> [Char] -> Maybe TextEncoding -> NewlineMode -> IO Handle
    mkDuplexHandleNoFinalizer dev
    dev [Char]
    filepath Maybe TextEncoding
    mb_codec NewlineMode
    tr_newlines
      addHandleFinalizer handle handleFinalizer
      pure handle

    ioModeToHandleType :: IOMode -> HandleType
    ioModeToHandleType :: IOMode -> HandleType
    ioModeToHandleType IOMode
    ReadMode      = HandleType
    ReadHandle
    ioModeToHandleType IOMode
    WriteMode     = HandleType
    WriteHandle
    ioModeToHandleType IOMode
    ReadWriteMode = HandleType
    ReadWriteHandle
    ioModeToHandleType IOMode
    AppendMode    = HandleType
    AppendHandle

    initBufferState :: HandleType -> BufferState
    initBufferState :: HandleType -> BufferState
    initBufferState HandleType
    ReadHandle = BufferState
    ReadBuffer
    initBufferState HandleType
    _          = BufferState
    WriteBuffer

    openTextEncoding
       :: Maybe TextEncoding
       -> HandleType
       -> (forall es ds . Maybe (TextEncoder es) -> Maybe (TextDecoder ds) -> IO a)
       -> IO a

    openTextEncoding :: forall a.
    Maybe TextEncoding
    -> HandleType
    -> (forall es ds.
        Maybe (TextEncoder es) -> Maybe (TextDecoder ds) -> IO a)
    -> IO a
    openTextEncoding Maybe TextEncoding
    Nothing   HandleType
    ha_type forall es ds.
    Maybe (TextEncoder es) -> Maybe (TextDecoder ds) -> IO a
    cont = Maybe (TextEncoder (ZonkAny 1))
    -> Maybe (TextDecoder (ZonkAny 0)) -> IO a
    forall es ds.
    Maybe (TextEncoder es) -> Maybe (TextDecoder ds) -> IO a
    cont Maybe (TextEncoder (ZonkAny 1))
    forall a. Maybe a
    Nothing Maybe (TextDecoder (ZonkAny 0))
    forall a. Maybe a
    Nothing
    openTextEncoding (Just TextEncoding{[Char]
    IO (TextEncoder estate)
    IO (TextDecoder dstate)
    textEncodingName :: [Char]
    mkTextDecoder :: IO (TextDecoder dstate)
    mkTextEncoder :: IO (TextEncoder estate)
    mkTextEncoder :: ()
    mkTextDecoder :: ()
    textEncodingName :: TextEncoding -> [Char]
    ..}) HandleType
    ha_type forall es ds.
    Maybe (TextEncoder es) -> Maybe (TextDecoder ds) -> IO a
    cont = do
        mb_decoder <- if HandleType -> Bool
    isReadableHandleType HandleType
    ha_type then do
                         decoder <- IO (TextDecoder dstate)
    mkTextDecoder
                         return (Just decoder)
                      else
                         Maybe (TextDecoder dstate) -> IO (Maybe (TextDecoder dstate))
    forall a. a -> IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return Maybe (TextDecoder dstate)
    forall a. Maybe a
    Nothing
        mb_encoder <- if isWritableHandleType ha_type then do
                         encoder <- mkTextEncoder
                         return (Just encoder)
                      else
                         return Nothing
        cont mb_encoder mb_decoder

    closeTextCodecs :: Handle__ -> IO ()
    closeTextCodecs :: Handle__ -> IO ()
    closeTextCodecs Handle__{dev
    Maybe (MVar Handle__)
    Maybe TextEncoding
    Maybe (TextEncoder enc_state)
    Maybe (TextDecoder dec_state)
    IORef (dec_state, Buffer Word8)
    IORef (Buffer Char)
    IORef (Buffer Word8)
    IORef (BufferList Char)
    Newline
    BufferMode
    HandleType
    haOtherSide :: Handle__ -> Maybe (MVar Handle__)
    haOutputNL :: Handle__ -> Newline
    haInputNL :: Handle__ -> Newline
    haCodec :: Handle__ -> Maybe TextEncoding
    haDecoder :: ()
    haEncoder :: ()
    haBuffers :: Handle__ -> IORef (BufferList Char)
    haCharBuffer :: Handle__ -> IORef (Buffer Char)
    haLastDecode :: ()
    haBufferMode :: Handle__ -> BufferMode
    haByteBuffer :: Handle__ -> IORef (Buffer Word8)
    haType :: Handle__ -> HandleType
    haDevice :: ()
    haDevice :: dev
    haType :: HandleType
    haByteBuffer :: IORef (Buffer Word8)
    haBufferMode :: BufferMode
    haLastDecode :: IORef (dec_state, Buffer Word8)
    haCharBuffer :: IORef (Buffer Char)
    haBuffers :: IORef (BufferList Char)
    haEncoder :: Maybe (TextEncoder enc_state)
    haDecoder :: Maybe (TextDecoder dec_state)
    haCodec :: Maybe TextEncoding
    haInputNL :: Newline
    haOutputNL :: Newline
    haOtherSide :: Maybe (MVar Handle__)
    ..} = do
      case Maybe (TextDecoder dec_state)
    haDecoder of Maybe (TextDecoder dec_state)
    Nothing -> () -> IO ()
    forall a. a -> IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (); Just TextDecoder dec_state
    d -> TextDecoder dec_state -> IO ()
    forall from to state. BufferCodec from to state -> IO ()
    Encoding.close TextDecoder dec_state
    d
      case Maybe (TextEncoder enc_state)
    haEncoder of Maybe (TextEncoder enc_state)
    Nothing -> () -> IO ()
    forall a. a -> IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (); Just TextEncoder enc_state
    d -> TextEncoder enc_state -> IO ()
    forall from to state. BufferCodec from to state -> IO ()
    Encoding.close TextEncoder enc_state
    d

    -- ---------------------------------------------------------------------------
    -- Closing a handle

    -- | This function exists temporarily to avoid an unused import warning in
    -- `bytestring`.
    hClose_impl :: Handle -> IO ()
    hClose_impl :: Handle -> IO ()
    hClose_impl h :: Handle
    h@(FileHandle [Char]
    _ MVar Handle__
    m)     = do
      mb_exc <- Handle -> MVar Handle__ -> IO (Maybe SomeException)
    hClose' Handle
    h MVar Handle__
    m
      hClose_maybethrow mb_exc h
    hClose_impl h :: Handle
    h@(DuplexHandle [Char]
    _ MVar Handle__
    r MVar Handle__
    w) = do
      excs <- (MVar Handle__ -> IO (Maybe SomeException))
    -> [MVar Handle__] -> IO [Maybe SomeException]
    forall (m :: * -> *) a b. Monad m => (a -> m b) -> [a] -> m [b]
    mapM (Handle -> MVar Handle__ -> IO (Maybe SomeException)
    hClose' Handle
    h) [MVar Handle__
    r,MVar Handle__
    w]
      hClose_maybethrow (listToMaybe (catMaybes excs)) h

    hClose_maybethrow :: Maybe SomeException -> Handle -> IO ()
    hClose_maybethrow :: Maybe SomeException -> Handle -> IO ()
    hClose_maybethrow Maybe SomeException
    Nothing  Handle
    h = () -> IO ()
    forall a. a -> IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return ()
    hClose_maybethrow (Just SomeException
    e) Handle
    h = SomeException -> Handle -> IO ()
    hClose_rethrow SomeException
    e Handle
    h

    hClose_rethrow :: SomeException -> Handle -> IO ()
    hClose_rethrow :: SomeException -> Handle -> IO ()
    hClose_rethrow SomeException
    e Handle
    h =
      case SomeException -> Maybe IOException
    forall e. Exception e => SomeException -> Maybe e
    fromException SomeException
    e of
        Just IOException
    ioe -> IOException -> IO ()
    forall a. HasCallStack => IOException -> IO a
    ioError (IOException -> [Char] -> Handle -> IOException
    augmentIOError IOException
    ioe [Char]
    "hClose" Handle
    h)
        Maybe IOException
    Nothing  -> SomeException -> IO ()
    forall e a. (HasCallStack, Exception e) => e -> IO a
    throwIO SomeException
    e

    hClose' :: Handle -> MVar Handle__ -> IO (Maybe SomeException)
    hClose' :: Handle -> MVar Handle__ -> IO (Maybe SomeException)
    hClose' Handle
    h MVar Handle__
    m = [Char]
    -> Handle
    -> MVar Handle__
    -> (Handle__ -> IO (Handle__, Maybe SomeException))
    -> IO (Maybe SomeException)
    forall a.
    [Char]
    -> Handle
    -> MVar Handle__
    -> (Handle__ -> IO (Handle__, a))
    -> IO a
    withHandle' [Char]
    "hClose" Handle
    h MVar Handle__
    m ((Handle__ -> IO (Handle__, Maybe SomeException))
     -> IO (Maybe SomeException))
    -> (Handle__ -> IO (Handle__, Maybe SomeException))
    -> IO (Maybe SomeException)
    forall a b. (a -> b) -> a -> b
    $ Handle__ -> IO (Handle__, Maybe SomeException)
    hClose_help

    -- hClose_help is also called by lazyRead (in GHC.IO.Handle.Text) when
    -- EOF is read or an IO error occurs on a lazy stream.  The
    -- semi-closed Handle is then closed immediately.  We have to be
    -- careful with DuplexHandles though: we have to leave the closing to
    -- the finalizer in that case, because the write side may still be in
    -- use.
    hClose_help :: Handle__ -> IO (Handle__, Maybe SomeException)
    hClose_help :: Handle__ -> IO (Handle__, Maybe SomeException)
    hClose_help Handle__
    handle_ =
      case Handle__ -> HandleType
    haType Handle__
    handle_ of
          HandleType
    ClosedHandle -> (Handle__, Maybe SomeException)
    -> IO (Handle__, Maybe SomeException)
    forall a. a -> IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (Handle__
    handle_,Maybe SomeException
    forall a. Maybe a
    Nothing)
          HandleType
    _ -> do mb_exc1 <- IO () -> IO (Maybe SomeException)
    trymaybe (IO () -> IO (Maybe SomeException))
    -> IO () -> IO (Maybe SomeException)
    forall a b. (a -> b) -> a -> b
    $ Handle__ -> IO ()
    flushWriteBuffer Handle__
    handle_ -- interruptible
                        -- it is important that hClose doesn't fail and
                        -- leave the Handle open (#3128), so we catch
                        -- exceptions when flushing the buffer.
                  (h_, mb_exc2) <- hClose_handle_ handle_
                  return (h_, if isJust mb_exc1 then mb_exc1 else mb_exc2)

    trymaybe :: IO () -> IO (Maybe SomeException)
    trymaybe :: IO () -> IO (Maybe SomeException)
    trymaybe IO ()
    io = (do IO ()
    io; Maybe SomeException -> IO (Maybe SomeException)
    forall a. a -> IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return Maybe SomeException
    forall a. Maybe a
    Nothing) IO (Maybe SomeException)
    -> (SomeException -> IO (Maybe SomeException))
    -> IO (Maybe SomeException)
    forall e a. Exception e => IO a -> (e -> IO a) -> IO a
    `catchException` \SomeException
    e -> Maybe SomeException -> IO (Maybe SomeException)
    forall a. a -> IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (SomeException -> Maybe SomeException
    forall a. a -> Maybe a
    Just SomeException
    e)

    hClose_handle_ :: Handle__ -> IO (Handle__, Maybe SomeException)
    hClose_handle_ :: Handle__ -> IO (Handle__, Maybe SomeException)
    hClose_handle_ h_ :: Handle__
    h_@Handle__{dev
    Maybe (MVar Handle__)
    Maybe TextEncoding
    Maybe (TextEncoder enc_state)
    Maybe (TextDecoder dec_state)
    IORef (dec_state, Buffer Word8)
    IORef (Buffer Char)
    IORef (Buffer Word8)
    IORef (BufferList Char)
    Newline
    BufferMode
    HandleType
    haOtherSide :: Handle__ -> Maybe (MVar Handle__)
    haOutputNL :: Handle__ -> Newline
    haInputNL :: Handle__ -> Newline
    haCodec :: Handle__ -> Maybe TextEncoding
    haDecoder :: ()
    haEncoder :: ()
    haBuffers :: Handle__ -> IORef (BufferList Char)
    haCharBuffer :: Handle__ -> IORef (Buffer Char)
    haLastDecode :: ()
    haBufferMode :: Handle__ -> BufferMode
    haByteBuffer :: Handle__ -> IORef (Buffer Word8)
    haType :: Handle__ -> HandleType
    haDevice :: ()
    haDevice :: dev
    haType :: HandleType
    haByteBuffer :: IORef (Buffer Word8)
    haBufferMode :: BufferMode
    haLastDecode :: IORef (dec_state, Buffer Word8)
    haCharBuffer :: IORef (Buffer Char)
    haBuffers :: IORef (BufferList Char)
    haEncoder :: Maybe (TextEncoder enc_state)
    haDecoder :: Maybe (TextDecoder dec_state)
    haCodec :: Maybe TextEncoding
    haInputNL :: Newline
    haOutputNL :: Newline
    haOtherSide :: Maybe (MVar Handle__)
    ..} = do

        -- close the file descriptor, but not when this is the read
        -- side of a duplex handle.
        -- If an exception is raised by the close(), we want to continue
        -- to close the handle and release the lock if it has one, then
        -- we return the exception to the caller of hClose_help which can
        -- raise it if necessary.
        maybe_exception <-
          case Maybe (MVar Handle__)
    haOtherSide of
            Maybe (MVar Handle__)
    Nothing -> IO () -> IO (Maybe SomeException)
    trymaybe (IO () -> IO (Maybe SomeException))
    -> IO () -> IO (Maybe SomeException)
    forall a b. (a -> b) -> a -> b
    $ dev -> IO ()
    forall a. IODevice a => a -> IO ()
    IODevice.close dev
    haDevice
            Just MVar Handle__
    _  -> Maybe SomeException -> IO (Maybe SomeException)
    forall a. a -> IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return Maybe SomeException
    forall a. Maybe a
    Nothing

        -- free the spare buffers
        writeIORef haBuffers BufferListNil
        writeIORef haCharBuffer noCharBuffer
        writeIORef haByteBuffer noByteBuffer

        -- release our encoder/decoder
        closeTextCodecs h_

        -- we must set the fd to -1, because the finalizer is going
        -- to run eventually and try to close/unlock it.
        -- ToDo: necessary?  the handle will be marked ClosedHandle
        -- XXX GHC won't let us use record update here, hence wildcards
        return (Handle__{ haType = ClosedHandle, .. }, maybe_exception)

    {-# NOINLINE noCharBuffer #-}
    noCharBuffer :: CharBuffer
    noCharBuffer :: Buffer Char
    noCharBuffer = IO (Buffer Char) -> Buffer Char
    forall a. IO a -> a
    unsafePerformIO (IO (Buffer Char) -> Buffer Char)
    -> IO (Buffer Char) -> Buffer Char
    forall a b. (a -> b) -> a -> b
    $ Int -> BufferState -> IO (Buffer Char)
    newCharBuffer Int
    1 BufferState
    ReadBuffer

    {-# NOINLINE noByteBuffer #-}
    noByteBuffer :: Buffer Word8
    noByteBuffer :: Buffer Word8
    noByteBuffer = IO (Buffer Word8) -> Buffer Word8
    forall a. IO a -> a
    unsafePerformIO (IO (Buffer Word8) -> Buffer Word8)
    -> IO (Buffer Word8) -> Buffer Word8
    forall a b. (a -> b) -> a -> b
    $ Int -> BufferState -> IO (Buffer Word8)
    newByteBuffer Int
    1 BufferState
    ReadBuffer

    -- ---------------------------------------------------------------------------
    -- Looking ahead

    hLookAhead_ :: Handle__ -> IO Char
    hLookAhead_ :: Handle__ -> IO Char
    hLookAhead_ handle_ :: Handle__
    handle_@Handle__{dev
    Maybe (MVar Handle__)
    Maybe TextEncoding
    Maybe (TextEncoder enc_state)
    Maybe (TextDecoder dec_state)
    IORef (dec_state, Buffer Word8)
    IORef (Buffer Char)
    IORef (Buffer Word8)
    IORef (BufferList Char)
    Newline
    BufferMode
    HandleType
    haOtherSide :: Handle__ -> Maybe (MVar Handle__)
    haOutputNL :: Handle__ -> Newline
    haInputNL :: Handle__ -> Newline
    haCodec :: Handle__ -> Maybe TextEncoding
    haDecoder :: ()
    haEncoder :: ()
    haBuffers :: Handle__ -> IORef (BufferList Char)
    haCharBuffer :: Handle__ -> IORef (Buffer Char)
    haLastDecode :: ()
    haBufferMode :: Handle__ -> BufferMode
    haByteBuffer :: Handle__ -> IORef (Buffer Word8)
    haType :: Handle__ -> HandleType
    haDevice :: ()
    haDevice :: dev
    haType :: HandleType
    haByteBuffer :: IORef (Buffer Word8)
    haBufferMode :: BufferMode
    haLastDecode :: IORef (dec_state, Buffer Word8)
    haCharBuffer :: IORef (Buffer Char)
    haBuffers :: IORef (BufferList Char)
    haEncoder :: Maybe (TextEncoder enc_state)
    haDecoder :: Maybe (TextDecoder dec_state)
    haCodec :: Maybe TextEncoding
    haInputNL :: Newline
    haOutputNL :: Newline
    haOtherSide :: Maybe (MVar Handle__)
    ..} = do
        buf <- IORef (Buffer Char) -> IO (Buffer Char)
    forall a. IORef a -> IO a
    readIORef IORef (Buffer Char)
    haCharBuffer

        -- fill up the read buffer if necessary
        new_buf <- if isEmptyBuffer buf
                      then readTextDevice handle_ buf
                      else return buf
        writeIORef haCharBuffer new_buf

        peekCharBuf (bufRaw buf) (bufL buf)

    -- ---------------------------------------------------------------------------
    -- debugging

    debugIO :: String -> IO ()
    -- debugIO s = traceEventIO s
    debugIO :: [Char] -> IO ()
    debugIO [Char]
    s
     | Bool
    c_DEBUG_DUMP
        = do _ <- [Char] -> (CStringLen -> IO CSsize) -> IO CSsize
    forall a. [Char] -> (CStringLen -> IO a) -> IO a
    withCStringLen ([Char]
    s [Char] -> [Char] -> [Char]
    forall a. [a] -> [a] -> [a]
    ++ [Char]
    "\n") ((CStringLen -> IO CSsize) -> IO CSsize)
    -> (CStringLen -> IO CSsize) -> IO CSsize
    forall a b. (a -> b) -> a -> b
    $
                      \(Ptr CChar
    p, Int
    len) -> CInt -> Ptr Word8 -> CSize -> IO CSsize
    c_write CInt
    1 (Ptr CChar -> Ptr Word8
    forall a b. Ptr a -> Ptr b
    castPtr Ptr CChar
    p) (Int -> CSize
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral Int
    len)
             return ()
     | Bool
    otherwise = () -> IO ()
    forall a. a -> IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return ()

    -- For development, like debugIO but always on.
    traceIO :: String -> IO ()
    traceIO :: [Char] -> IO ()
    traceIO [Char]
    s = do
             _ <- [Char] -> (CStringLen -> IO CSsize) -> IO CSsize
    forall a. [Char] -> (CStringLen -> IO a) -> IO a
    withCStringLen ([Char]
    s [Char] -> [Char] -> [Char]
    forall a. [a] -> [a] -> [a]
    ++ [Char]
    "\n") ((CStringLen -> IO CSsize) -> IO CSsize)
    -> (CStringLen -> IO CSsize) -> IO CSsize
    forall a b. (a -> b) -> a -> b
    $
                      \(Ptr CChar
    p, Int
    len) -> CInt -> Ptr Word8 -> CSize -> IO CSsize
    c_write CInt
    1 (Ptr CChar -> Ptr Word8
    forall a b. Ptr a -> Ptr b
    castPtr Ptr CChar
    p) (Int -> CSize
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral Int
    len)
             return ()

    -- ----------------------------------------------------------------------------
    -- Text input/output

    -- Read characters into the provided buffer.  Return when any
    -- characters are available; raise an exception if the end of
    -- file is reached.
    --
    -- In uses of readTextDevice within base, the input buffer is either:
    --   * empty
    --   * or contains a single \r (when doing newline translation)
    --
    -- The input character buffer must have a capacity at least 1 greater
    -- than the number of elements it currently contains.
    --
    -- Users of this function expect that the buffer returned contains
    -- at least 1 more character than the input buffer.
    readTextDevice :: Handle__ -> CharBuffer -> IO CharBuffer
    readTextDevice :: Handle__ -> Buffer Char -> IO (Buffer Char)
    readTextDevice h_ :: Handle__
    h_@Handle__{dev
    Maybe (MVar Handle__)
    Maybe TextEncoding
    Maybe (TextEncoder enc_state)
    Maybe (TextDecoder dec_state)
    IORef (dec_state, Buffer Word8)
    IORef (Buffer Char)
    IORef (Buffer Word8)
    IORef (BufferList Char)
    Newline
    BufferMode
    HandleType
    haOtherSide :: Handle__ -> Maybe (MVar Handle__)
    haOutputNL :: Handle__ -> Newline
    haInputNL :: Handle__ -> Newline
    haCodec :: Handle__ -> Maybe TextEncoding
    haDecoder :: ()
    haEncoder :: ()
    haBuffers :: Handle__ -> IORef (BufferList Char)
    haCharBuffer :: Handle__ -> IORef (Buffer Char)
    haLastDecode :: ()
    haBufferMode :: Handle__ -> BufferMode
    haByteBuffer :: Handle__ -> IORef (Buffer Word8)
    haType :: Handle__ -> HandleType
    haDevice :: ()
    haDevice :: dev
    haType :: HandleType
    haByteBuffer :: IORef (Buffer Word8)
    haBufferMode :: BufferMode
    haLastDecode :: IORef (dec_state, Buffer Word8)
    haCharBuffer :: IORef (Buffer Char)
    haBuffers :: IORef (BufferList Char)
    haEncoder :: Maybe (TextEncoder enc_state)
    haDecoder :: Maybe (TextDecoder dec_state)
    haCodec :: Maybe TextEncoding
    haInputNL :: Newline
    haOutputNL :: Newline
    haOtherSide :: Maybe (MVar Handle__)
    ..} Buffer Char
    cbuf = do
      --
      bbuf0 <- IORef (Buffer Word8) -> IO (Buffer Word8)
    forall a. IORef a -> IO a
    readIORef IORef (Buffer Word8)
    haByteBuffer

      debugIO ("readTextDevice: cbuf=" ++ summaryBuffer cbuf ++
            " bbuf=" ++ summaryBuffer bbuf0)

      bbuf1 <- if not (isEmptyBuffer bbuf0)
                  then return bbuf0
                  else do
                       debugIO $ "readBuf at " ++ show (bufferOffset bbuf0)
                       (r,bbuf1) <- Buffered.fillReadBuffer haDevice bbuf0
                       debugIO $ "readBuf after " ++ show (bufferOffset bbuf1)
                       if r == 0 then ioe_EOF else do  -- raise EOF
                       return bbuf1

      debugIO ("readTextDevice after reading: bbuf=" ++ summaryBuffer bbuf1)

      (bbuf2,cbuf') <-
          case haDecoder of
              Maybe (TextDecoder dec_state)
    Nothing      -> do
                   IORef (dec_state, Buffer Word8)
    -> (dec_state, Buffer Word8) -> IO ()
    forall a. IORef a -> a -> IO ()
    writeIORef IORef (dec_state, Buffer Word8)
    haLastDecode ([Char] -> dec_state
    forall a. [Char] -> a
    errorWithoutStackTrace [Char]
    "codec_state", Buffer Word8
    bbuf1)
                   Buffer Word8 -> Buffer Char -> IO (Buffer Word8, Buffer Char)
    latin1_decode Buffer Word8
    bbuf1 Buffer Char
    cbuf
              Just TextDecoder dec_state
    decoder -> do
                   state <- TextDecoder dec_state -> IO dec_state
    forall from to state. BufferCodec from to state -> IO state
    getState TextDecoder dec_state
    decoder
                   writeIORef haLastDecode (state, bbuf1)
                   (streamEncode decoder) bbuf1 cbuf

      debugIO ("readTextDevice after decoding: cbuf=" ++ summaryBuffer cbuf' ++
            " bbuf=" ++ summaryBuffer bbuf2)

      -- We can't return from readTextDevice without reading at least a single extra character,
      -- so check that we have managed to achieve that
      writeIORef haByteBuffer bbuf2
      if bufR cbuf' == bufR cbuf
         -- we need more bytes to make a Char. NB: bbuf2 may be empty (even though bbuf1 wasn't) when we
         -- are using an encoding that can skip bytes without outputting characters, such as UTF8//IGNORE
         then readTextDevice' h_ bbuf2 cbuf
         else return cbuf'

    -- we have an incomplete byte sequence at the end of the buffer: try to
    -- read more bytes.
    readTextDevice' :: Handle__ -> Buffer Word8 -> CharBuffer -> IO CharBuffer
    readTextDevice' :: Handle__ -> Buffer Word8 -> Buffer Char -> IO (Buffer Char)
    readTextDevice' h_ :: Handle__
    h_@Handle__{dev
    Maybe (MVar Handle__)
    Maybe TextEncoding
    Maybe (TextEncoder enc_state)
    Maybe (TextDecoder dec_state)
    IORef (dec_state, Buffer Word8)
    IORef (Buffer Char)
    IORef (Buffer Word8)
    IORef (BufferList Char)
    Newline
    BufferMode
    HandleType
    haOtherSide :: Handle__ -> Maybe (MVar Handle__)
    haOutputNL :: Handle__ -> Newline
    haInputNL :: Handle__ -> Newline
    haCodec :: Handle__ -> Maybe TextEncoding
    haDecoder :: ()
    haEncoder :: ()
    haBuffers :: Handle__ -> IORef (BufferList Char)
    haCharBuffer :: Handle__ -> IORef (Buffer Char)
    haLastDecode :: ()
    haBufferMode :: Handle__ -> BufferMode
    haByteBuffer :: Handle__ -> IORef (Buffer Word8)
    haType :: Handle__ -> HandleType
    haDevice :: ()
    haDevice :: dev
    haType :: HandleType
    haByteBuffer :: IORef (Buffer Word8)
    haBufferMode :: BufferMode
    haLastDecode :: IORef (dec_state, Buffer Word8)
    haCharBuffer :: IORef (Buffer Char)
    haBuffers :: IORef (BufferList Char)
    haEncoder :: Maybe (TextEncoder enc_state)
    haDecoder :: Maybe (TextDecoder dec_state)
    haCodec :: Maybe TextEncoding
    haInputNL :: Newline
    haOutputNL :: Newline
    haOtherSide :: Maybe (MVar Handle__)
    ..} Buffer Word8
    bbuf0 Buffer Char
    cbuf0 = do
      --
      -- copy the partial sequence to the beginning of the buffer, so we have
      -- room to read more bytes.
      bbuf1 <- Buffer Word8 -> IO (Buffer Word8)
    slideContents Buffer Word8
    bbuf0

      -- readTextDevice only calls us if we got some bytes but not some characters.
      -- This can't occur if haDecoder is Nothing because latin1_decode accepts all bytes.
      let Just decoder = haDecoder

      (r,bbuf2) <- Buffered.fillReadBuffer haDevice bbuf1
      if r == 0
       then do
         -- bbuf2 can be empty here when we encounter an invalid byte sequence at the end of the input
         -- with a //IGNORE codec which consumes bytes without outputting characters
         if isEmptyBuffer bbuf2 then ioe_EOF else do
         (bbuf3, cbuf1) <- recover decoder bbuf2 cbuf0
         debugIO ("readTextDevice' after recovery: bbuf=" ++ summaryBuffer bbuf3 ++ ", cbuf=" ++ summaryBuffer cbuf1)
         writeIORef haByteBuffer bbuf3
         -- We should recursively invoke readTextDevice after recovery,
         -- if recovery did not add at least one new character to the buffer:
         --  1. If we were using IgnoreCodingFailure it might be the case that
         --     cbuf1 is the same length as cbuf0 and we need to raise ioe_EOF
         --  2. If we were using TransliterateCodingFailure we might have *mutated*
         --     the byte buffer without changing the pointers into either buffer.
         --     We need to try and decode it again - it might just go through this time.
         if bufR cbuf1 == bufR cbuf0
          then readTextDevice h_ cbuf1
          else return cbuf1
       else do
        debugIO ("readTextDevice' after reading: bbuf=" ++ summaryBuffer bbuf2)

        (bbuf3,cbuf1) <- do
           state <- getState decoder
           writeIORef haLastDecode (state, bbuf2)
           (streamEncode decoder) bbuf2 cbuf0

        debugIO ("readTextDevice' after decoding: cbuf=" ++ summaryBuffer cbuf1 ++
              " bbuf=" ++ summaryBuffer bbuf3)

        writeIORef haByteBuffer bbuf3
        if bufR cbuf0 == bufR cbuf1
           then readTextDevice' h_ bbuf3 cbuf1
           else return cbuf1

    -- Read characters into the provided buffer.  Do not block;
    -- return zero characters instead.  Raises an exception on end-of-file.
    readTextDeviceNonBlocking :: Handle__ -> CharBuffer -> IO CharBuffer
    readTextDeviceNonBlocking :: Handle__ -> Buffer Char -> IO (Buffer Char)
    readTextDeviceNonBlocking h_ :: Handle__
    h_@Handle__{dev
    Maybe (MVar Handle__)
    Maybe TextEncoding
    Maybe (TextEncoder enc_state)
    Maybe (TextDecoder dec_state)
    IORef (dec_state, Buffer Word8)
    IORef (Buffer Char)
    IORef (Buffer Word8)
    IORef (BufferList Char)
    Newline
    BufferMode
    HandleType
    haOtherSide :: Handle__ -> Maybe (MVar Handle__)
    haOutputNL :: Handle__ -> Newline
    haInputNL :: Handle__ -> Newline
    haCodec :: Handle__ -> Maybe TextEncoding
    haDecoder :: ()
    haEncoder :: ()
    haBuffers :: Handle__ -> IORef (BufferList Char)
    haCharBuffer :: Handle__ -> IORef (Buffer Char)
    haLastDecode :: ()
    haBufferMode :: Handle__ -> BufferMode
    haByteBuffer :: Handle__ -> IORef (Buffer Word8)
    haType :: Handle__ -> HandleType
    haDevice :: ()
    haDevice :: dev
    haType :: HandleType
    haByteBuffer :: IORef (Buffer Word8)
    haBufferMode :: BufferMode
    haLastDecode :: IORef (dec_state, Buffer Word8)
    haCharBuffer :: IORef (Buffer Char)
    haBuffers :: IORef (BufferList Char)
    haEncoder :: Maybe (TextEncoder enc_state)
    haDecoder :: Maybe (TextDecoder dec_state)
    haCodec :: Maybe TextEncoding
    haInputNL :: Newline
    haOutputNL :: Newline
    haOtherSide :: Maybe (MVar Handle__)
    ..} Buffer Char
    cbuf = do
      --
      bbuf0 <- IORef (Buffer Word8) -> IO (Buffer Word8)
    forall a. IORef a -> IO a
    readIORef IORef (Buffer Word8)
    haByteBuffer
      when (isEmptyBuffer bbuf0) $ do
         (r,bbuf1) <- Buffered.fillReadBuffer0 haDevice bbuf0
         if isNothing r then ioe_EOF else do  -- raise EOF
         writeIORef haByteBuffer bbuf1

      decodeByteBuf h_ cbuf

    -- Decode bytes from the byte buffer into the supplied CharBuffer.
    decodeByteBuf :: Handle__ -> CharBuffer -> IO CharBuffer
    decodeByteBuf :: Handle__ -> Buffer Char -> IO (Buffer Char)
    decodeByteBuf h_ :: Handle__
    h_@Handle__{dev
    Maybe (MVar Handle__)
    Maybe TextEncoding
    Maybe (TextEncoder enc_state)
    Maybe (TextDecoder dec_state)
    IORef (dec_state, Buffer Word8)
    IORef (Buffer Char)
    IORef (Buffer Word8)
    IORef (BufferList Char)
    Newline
    BufferMode
    HandleType
    haOtherSide :: Handle__ -> Maybe (MVar Handle__)
    haOutputNL :: Handle__ -> Newline
    haInputNL :: Handle__ -> Newline
    haCodec :: Handle__ -> Maybe TextEncoding
    haDecoder :: ()
    haEncoder :: ()
    haBuffers :: Handle__ -> IORef (BufferList Char)
    haCharBuffer :: Handle__ -> IORef (Buffer Char)
    haLastDecode :: ()
    haBufferMode :: Handle__ -> BufferMode
    haByteBuffer :: Handle__ -> IORef (Buffer Word8)
    haType :: Handle__ -> HandleType
    haDevice :: ()
    haDevice :: dev
    haType :: HandleType
    haByteBuffer :: IORef (Buffer Word8)
    haBufferMode :: BufferMode
    haLastDecode :: IORef (dec_state, Buffer Word8)
    haCharBuffer :: IORef (Buffer Char)
    haBuffers :: IORef (BufferList Char)
    haEncoder :: Maybe (TextEncoder enc_state)
    haDecoder :: Maybe (TextDecoder dec_state)
    haCodec :: Maybe TextEncoding
    haInputNL :: Newline
    haOutputNL :: Newline
    haOtherSide :: Maybe (MVar Handle__)
    ..} Buffer Char
    cbuf = do
      --
      bbuf0 <- IORef (Buffer Word8) -> IO (Buffer Word8)
    forall a. IORef a -> IO a
    readIORef IORef (Buffer Word8)
    haByteBuffer

      (bbuf2,cbuf') <-
          case haDecoder of
              Maybe (TextDecoder dec_state)
    Nothing      -> do
                   IORef (dec_state, Buffer Word8)
    -> (dec_state, Buffer Word8) -> IO ()
    forall a. IORef a -> a -> IO ()
    writeIORef IORef (dec_state, Buffer Word8)
    haLastDecode ([Char] -> dec_state
    forall a. [Char] -> a
    errorWithoutStackTrace [Char]
    "codec_state", Buffer Word8
    bbuf0)
                   Buffer Word8 -> Buffer Char -> IO (Buffer Word8, Buffer Char)
    latin1_decode Buffer Word8
    bbuf0 Buffer Char
    cbuf
              Just TextDecoder dec_state
    decoder -> do
                   state <- TextDecoder dec_state -> IO dec_state
    forall from to state. BufferCodec from to state -> IO state
    getState TextDecoder dec_state
    decoder
                   writeIORef haLastDecode (state, bbuf0)
                   (streamEncode decoder) bbuf0 cbuf

      writeIORef haByteBuffer bbuf2
      return cbuf'