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

-----------------------------------------------------------------------------
-- |
-- Module      :  GHC.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.
--
-----------------------------------------------------------------------------

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

  mkHandle, mkFileHandle, mkDuplexHandle,
  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_help, hLookAhead_,

  HandleFinalizer, handleFinalizer,

  debugIO,
 ) where

import GHC.IO
import GHC.IO.IOMode
import GHC.IO.Encoding as Encoding
import GHC.IO.Encoding.Types (CodeBuffer)
import GHC.IO.Handle.Types
import GHC.IO.Buffer
import GHC.IO.BufferedIO (BufferedIO)
import GHC.IO.Exception
import GHC.IO.Device (IODevice, SeekMode(..))
import qualified GHC.IO.Device as IODevice
import qualified GHC.IO.BufferedIO as Buffered

import GHC.Conc.Sync
import GHC.Real
import GHC.Base
import GHC.Exception
import GHC.Num          ( Num(..) )
import GHC.Show
import GHC.IORef
import GHC.MVar
import Data.Typeable
import Data.Maybe
import Foreign
import System.Posix.Internals hiding (FD)

import Foreign.C

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

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

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

newFileHandle :: FilePath -> Maybe HandleFinalizer -> Handle__ -> IO Handle
newFileHandle :: FilePath -> Maybe HandleFinalizer -> Handle__ -> IO Handle
newFileHandle filepath :: FilePath
filepath mb_finalizer :: Maybe HandleFinalizer
mb_finalizer hc :: Handle__
hc = do
  MVar Handle__
m <- Handle__ -> IO (MVar Handle__)
forall a. a -> IO (MVar a)
newMVar Handle__
hc
  case Maybe HandleFinalizer
mb_finalizer of
    Just finalizer :: HandleFinalizer
finalizer -> MVar Handle__ -> IO () -> IO ()
forall a. MVar a -> IO () -> IO ()
addMVarFinalizer MVar Handle__
m (HandleFinalizer
finalizer FilePath
filepath MVar Handle__
m)
    Nothing        -> () -> IO ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
  Handle -> IO Handle
forall (m :: * -> *) a. Monad m => a -> m a
return (FilePath -> MVar Handle__ -> Handle
FileHandle FilePath
filepath MVar Handle__
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 :: FilePath -> Handle -> (Handle__ -> IO (Handle__, a)) -> IO a
withHandle fun :: FilePath
fun h :: Handle
h@(FileHandle _ m :: MVar Handle__
m)     act :: Handle__ -> IO (Handle__, a)
act = FilePath
-> Handle
-> MVar Handle__
-> (Handle__ -> IO (Handle__, a))
-> IO a
forall a.
FilePath
-> Handle
-> MVar Handle__
-> (Handle__ -> IO (Handle__, a))
-> IO a
withHandle' FilePath
fun Handle
h MVar Handle__
m Handle__ -> IO (Handle__, a)
act
withHandle fun :: FilePath
fun h :: Handle
h@(DuplexHandle _ m :: MVar Handle__
m _) act :: Handle__ -> IO (Handle__, a)
act = FilePath
-> Handle
-> MVar Handle__
-> (Handle__ -> IO (Handle__, a))
-> IO a
forall a.
FilePath
-> Handle
-> MVar Handle__
-> (Handle__ -> IO (Handle__, a))
-> IO a
withHandle' FilePath
fun Handle
h MVar Handle__
m Handle__ -> IO (Handle__, a)
act

withHandle' :: String -> Handle -> MVar Handle__
   -> (Handle__ -> IO (Handle__,a)) -> IO a
withHandle' :: FilePath
-> Handle
-> MVar Handle__
-> (Handle__ -> IO (Handle__, a))
-> IO a
withHandle' fun :: FilePath
fun h :: Handle
h m :: MVar Handle__
m act :: 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' :: Handle__
h',v :: a
v)  <- FilePath
-> Handle
-> (Handle__ -> IO (Handle__, a))
-> MVar Handle__
-> IO (Handle__, a)
forall a.
FilePath -> Handle -> (Handle__ -> IO a) -> MVar Handle__ -> IO a
do_operation FilePath
fun Handle
h Handle__ -> IO (Handle__, a)
act MVar Handle__
m
   Handle__ -> IO ()
checkHandleInvariants Handle__
h'
   MVar Handle__ -> Handle__ -> IO ()
forall a. MVar a -> a -> IO ()
putMVar MVar Handle__
m Handle__
h'
   a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return a
v

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

withHandle_' :: String -> Handle -> MVar Handle__ -> (Handle__ -> IO a) -> IO a
withHandle_' :: FilePath -> Handle -> MVar Handle__ -> (Handle__ -> IO a) -> IO a
withHandle_' fun :: FilePath
fun h :: Handle
h m :: MVar Handle__
m act :: Handle__ -> IO a
act = FilePath
-> Handle
-> MVar Handle__
-> (Handle__ -> IO (Handle__, a))
-> IO a
forall a.
FilePath
-> Handle
-> MVar Handle__
-> (Handle__ -> IO (Handle__, a))
-> IO a
withHandle' FilePath
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
$ \h_ :: Handle__
h_ -> do
                              a
a <- Handle__ -> IO a
act Handle__
h_
                              (Handle__, a) -> IO (Handle__, a)
forall (m :: * -> *) a. Monad m => a -> m a
return (Handle__
h_,a
a)

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

withHandle__' :: String -> Handle -> MVar Handle__ -> (Handle__ -> IO Handle__)
              -> IO ()
withHandle__' :: FilePath
-> Handle -> MVar Handle__ -> (Handle__ -> IO Handle__) -> IO ()
withHandle__' fun :: FilePath
fun h :: Handle
h m :: MVar Handle__
m act :: 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
   Handle__
h'  <- FilePath
-> Handle
-> (Handle__ -> IO Handle__)
-> MVar Handle__
-> IO Handle__
forall a.
FilePath -> Handle -> (Handle__ -> IO a) -> MVar Handle__ -> IO a
do_operation FilePath
fun Handle
h Handle__ -> IO Handle__
act MVar Handle__
m
   Handle__ -> IO ()
checkHandleInvariants Handle__
h'
   MVar Handle__ -> Handle__ -> IO ()
forall a. MVar a -> a -> IO ()
putMVar MVar Handle__
m Handle__
h'
   () -> IO ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()

do_operation :: String -> Handle -> (Handle__ -> IO a) -> MVar Handle__ -> IO a
do_operation :: FilePath -> Handle -> (Handle__ -> IO a) -> MVar Handle__ -> IO a
do_operation fun :: FilePath
fun h :: Handle
h act :: Handle__ -> IO a
act m :: MVar Handle__
m = do
  Handle__
h_ <- MVar Handle__ -> IO Handle__
forall a. MVar a -> IO a
takeMVar MVar Handle__
m
  Handle__ -> IO ()
checkHandleInvariants Handle__
h_
  Handle__ -> IO a
act Handle__
h_ IO a -> (SomeException -> IO a) -> IO a
forall e a. Exception e => IO a -> (e -> IO a) -> IO a
`catchException` Handle__ -> SomeException -> IO a
handler Handle__
h_
  where
    handler :: Handle__ -> SomeException -> IO a
handler h_ :: Handle__
h_ e :: SomeException
e = do
      MVar Handle__ -> Handle__ -> IO ()
forall a. MVar a -> a -> IO ()
putMVar MVar Handle__
m Handle__
h_
      case () of
        _ | Just ioe :: IOException
ioe <- SomeException -> Maybe IOException
forall e. Exception e => SomeException -> Maybe e
fromException SomeException
e ->
            IOException -> IO a
forall a. IOException -> IO a
ioError (IOException -> FilePath -> Handle -> IOException
augmentIOError IOException
ioe FilePath
fun Handle
h)
        _ | Just async_ex :: 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
            ThreadId
t <- IO ThreadId
myThreadId
            ThreadId -> SomeException -> IO ()
forall e. Exception e => ThreadId -> e -> IO ()
throwTo ThreadId
t SomeException
e
            FilePath -> Handle -> (Handle__ -> IO a) -> MVar Handle__ -> IO a
forall a.
FilePath -> Handle -> (Handle__ -> IO a) -> MVar Handle__ -> IO a
do_operation FilePath
fun Handle
h Handle__ -> IO a
act MVar Handle__
m
        _otherwise :: ()
_otherwise ->
            SomeException -> IO a
forall e a. 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 -> FilePath -> Handle -> IOException
augmentIOError ioe :: IOException
ioe@IOError{ ioe_filename :: IOException -> Maybe FilePath
ioe_filename = Maybe FilePath
fp } fun :: FilePath
fun h :: Handle
h
  = IOException
ioe { ioe_handle :: Maybe Handle
ioe_handle = Handle -> Maybe Handle
forall a. a -> Maybe a
Just Handle
h, ioe_location :: FilePath
ioe_location = FilePath
fun, ioe_filename :: Maybe FilePath
ioe_filename = Maybe FilePath
filepath }
  where filepath :: Maybe FilePath
filepath
          | Just _ <- Maybe FilePath
fp = Maybe FilePath
fp
          | Bool
otherwise = case Handle
h of
                          FileHandle path :: FilePath
path _     -> FilePath -> Maybe FilePath
forall a. a -> Maybe a
Just FilePath
path
                          DuplexHandle path :: FilePath
path _ _ -> FilePath -> Maybe FilePath
forall a. a -> Maybe a
Just FilePath
path

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

wantWritableHandle :: String -> Handle -> (Handle__ -> IO a) -> IO a
wantWritableHandle :: FilePath -> Handle -> (Handle__ -> IO a) -> IO a
wantWritableHandle fun :: FilePath
fun h :: Handle
h@(FileHandle _ m :: MVar Handle__
m) act :: Handle__ -> IO a
act
  = FilePath -> Handle -> MVar Handle__ -> (Handle__ -> IO a) -> IO a
forall a.
FilePath -> Handle -> MVar Handle__ -> (Handle__ -> IO a) -> IO a
wantWritableHandle' FilePath
fun Handle
h MVar Handle__
m Handle__ -> IO a
act
wantWritableHandle fun :: FilePath
fun h :: Handle
h@(DuplexHandle _ _ m :: MVar Handle__
m) act :: Handle__ -> IO a
act
  = FilePath -> Handle -> MVar Handle__ -> (Handle__ -> IO a) -> IO a
forall a.
FilePath -> Handle -> MVar Handle__ -> (Handle__ -> IO a) -> IO a
wantWritableHandle' FilePath
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' :: FilePath -> Handle -> MVar Handle__ -> (Handle__ -> IO a) -> IO a
wantWritableHandle' fun :: FilePath
fun h :: Handle
h m :: MVar Handle__
m act :: Handle__ -> IO a
act
   = FilePath -> Handle -> MVar Handle__ -> (Handle__ -> IO a) -> IO a
forall a.
FilePath -> Handle -> MVar Handle__ -> (Handle__ -> IO a) -> IO a
withHandle_' FilePath
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 :: (Handle__ -> IO a) -> Handle__ -> IO a
checkWritableHandle act :: Handle__ -> IO a
act h_ :: Handle__
h_@Handle__{..}
  = case HandleType
haType of
      ClosedHandle         -> IO a
forall a. IO a
ioe_closedHandle
      SemiClosedHandle     -> IO a
forall a. IO a
ioe_semiclosedHandle
      ReadHandle           -> IO a
forall a. IO a
ioe_notWritable
      ReadWriteHandle      -> do
        Buffer CharBufElem
buf <- IORef (Buffer CharBufElem) -> IO (Buffer CharBufElem)
forall a. IORef a -> IO a
readIORef IORef (Buffer CharBufElem)
haCharBuffer
        Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Bool -> Bool
not (Buffer CharBufElem -> Bool
forall e. Buffer e -> Bool
isWriteBuffer Buffer CharBufElem
buf)) (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ do
           Handle__ -> IO ()
flushCharReadBuffer Handle__
h_
           Handle__ -> IO ()
flushByteReadBuffer Handle__
h_
           Buffer CharBufElem
buf <- IORef (Buffer CharBufElem) -> IO (Buffer CharBufElem)
forall a. IORef a -> IO a
readIORef IORef (Buffer CharBufElem)
haCharBuffer
           IORef (Buffer CharBufElem) -> Buffer CharBufElem -> IO ()
forall a. IORef a -> a -> IO ()
writeIORef IORef (Buffer CharBufElem)
haCharBuffer Buffer CharBufElem
buf{ bufState :: BufferState
bufState = BufferState
WriteBuffer }
           Buffer Word8
buf <- IORef (Buffer Word8) -> IO (Buffer Word8)
forall a. IORef a -> IO a
readIORef IORef (Buffer Word8)
haByteBuffer
           Buffer Word8
buf' <- dev -> Buffer Word8 -> IO (Buffer Word8)
forall dev.
BufferedIO dev =>
dev -> Buffer Word8 -> IO (Buffer Word8)
Buffered.emptyWriteBuffer dev
haDevice Buffer Word8
buf
           IORef (Buffer Word8) -> Buffer Word8 -> IO ()
forall a. IORef a -> a -> IO ()
writeIORef IORef (Buffer Word8)
haByteBuffer Buffer Word8
buf'
        Handle__ -> IO a
act Handle__
h_
      _other :: HandleType
_other               -> Handle__ -> IO a
act Handle__
h_

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

wantReadableHandle :: String -> Handle -> (Handle__ -> IO (Handle__,a)) -> IO a
wantReadableHandle :: FilePath -> Handle -> (Handle__ -> IO (Handle__, a)) -> IO a
wantReadableHandle fun :: FilePath
fun h :: Handle
h act :: Handle__ -> IO (Handle__, a)
act = FilePath -> Handle -> (Handle__ -> IO (Handle__, a)) -> IO a
forall a.
FilePath -> Handle -> (Handle__ -> IO (Handle__, a)) -> IO a
withHandle FilePath
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_ :: FilePath -> Handle -> (Handle__ -> IO a) -> IO a
wantReadableHandle_ fun :: FilePath
fun h :: Handle
h@(FileHandle  _ m :: MVar Handle__
m)   act :: Handle__ -> IO a
act
  = FilePath -> Handle -> MVar Handle__ -> (Handle__ -> IO a) -> IO a
forall a.
FilePath -> Handle -> MVar Handle__ -> (Handle__ -> IO a) -> IO a
wantReadableHandle' FilePath
fun Handle
h MVar Handle__
m Handle__ -> IO a
act
wantReadableHandle_ fun :: FilePath
fun h :: Handle
h@(DuplexHandle _ m :: MVar Handle__
m _) act :: Handle__ -> IO a
act
  = FilePath -> Handle -> MVar Handle__ -> (Handle__ -> IO a) -> IO a
forall a.
FilePath -> Handle -> MVar Handle__ -> (Handle__ -> IO a) -> IO a
wantReadableHandle' FilePath
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' :: FilePath -> Handle -> MVar Handle__ -> (Handle__ -> IO a) -> IO a
wantReadableHandle' fun :: FilePath
fun h :: Handle
h m :: MVar Handle__
m act :: Handle__ -> IO a
act
  = FilePath -> Handle -> MVar Handle__ -> (Handle__ -> IO a) -> IO a
forall a.
FilePath -> Handle -> MVar Handle__ -> (Handle__ -> IO a) -> IO a
withHandle_' FilePath
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 :: (Handle__ -> IO a) -> Handle__ -> IO a
checkReadableHandle act :: Handle__ -> IO a
act h_ :: Handle__
h_@Handle__{..} =
    case HandleType
haType of
      ClosedHandle         -> IO a
forall a. IO a
ioe_closedHandle
      SemiClosedHandle     -> IO a
forall a. IO a
ioe_semiclosedHandle
      AppendHandle         -> IO a
forall a. IO a
ioe_notReadable
      WriteHandle          -> IO a
forall a. IO a
ioe_notReadable
      ReadWriteHandle      -> do
          -- a read/write handle and we want to read from it.  We must
          -- flush all buffered write data first.
          Buffer Word8
bbuf <- IORef (Buffer Word8) -> IO (Buffer Word8)
forall a. IORef a -> IO a
readIORef IORef (Buffer Word8)
haByteBuffer
          Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Buffer Word8 -> Bool
forall e. Buffer e -> Bool
isWriteBuffer Buffer Word8
bbuf) (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ do
             Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Bool -> Bool
not (Buffer Word8 -> Bool
forall e. Buffer e -> Bool
isEmptyBuffer Buffer Word8
bbuf)) (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ Handle__ -> IO ()
flushByteWriteBuffer Handle__
h_
             Buffer CharBufElem
cbuf' <- IORef (Buffer CharBufElem) -> IO (Buffer CharBufElem)
forall a. IORef a -> IO a
readIORef IORef (Buffer CharBufElem)
haCharBuffer
             IORef (Buffer CharBufElem) -> Buffer CharBufElem -> IO ()
forall a. IORef a -> a -> IO ()
writeIORef IORef (Buffer CharBufElem)
haCharBuffer Buffer CharBufElem
cbuf'{ bufState :: BufferState
bufState = BufferState
ReadBuffer }
             Buffer Word8
bbuf <- IORef (Buffer Word8) -> IO (Buffer Word8)
forall a. IORef a -> IO a
readIORef IORef (Buffer Word8)
haByteBuffer
             IORef (Buffer Word8) -> Buffer Word8 -> IO ()
forall a. IORef a -> a -> IO ()
writeIORef IORef (Buffer Word8)
haByteBuffer Buffer Word8
bbuf{ bufState :: BufferState
bufState = BufferState
ReadBuffer }
          Handle__ -> IO a
act Handle__
h_
      _other :: HandleType
_other               -> Handle__ -> IO a
act Handle__
h_

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

wantSeekableHandle :: String -> Handle -> (Handle__ -> IO a) -> IO a
wantSeekableHandle :: FilePath -> Handle -> (Handle__ -> IO a) -> IO a
wantSeekableHandle fun :: FilePath
fun h :: Handle
h@(DuplexHandle _ _ _) _act :: Handle__ -> IO a
_act =
  IOException -> IO a
forall a. IOException -> IO a
ioException (Maybe Handle
-> IOErrorType
-> FilePath
-> FilePath
-> Maybe CInt
-> Maybe FilePath
-> IOException
IOError (Handle -> Maybe Handle
forall a. a -> Maybe a
Just Handle
h) IOErrorType
IllegalOperation FilePath
fun
                   "handle is not seekable" Maybe CInt
forall a. Maybe a
Nothing Maybe FilePath
forall a. Maybe a
Nothing)
wantSeekableHandle fun :: FilePath
fun h :: Handle
h@(FileHandle _ m :: MVar Handle__
m) act :: Handle__ -> IO a
act =
  FilePath -> Handle -> MVar Handle__ -> (Handle__ -> IO a) -> IO a
forall a.
FilePath -> Handle -> MVar Handle__ -> (Handle__ -> IO a) -> IO a
withHandle_' FilePath
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 :: (Handle__ -> IO a) -> Handle__ -> IO a
checkSeekableHandle act :: Handle__ -> IO a
act handle_ :: Handle__
handle_@Handle__{haDevice :: ()
haDevice=dev
dev} =
    case Handle__ -> HandleType
haType Handle__
handle_ of
      ClosedHandle      -> IO a
forall a. IO a
ioe_closedHandle
      SemiClosedHandle  -> IO a
forall a. IO a
ioe_semiclosedHandle
      AppendHandle      -> IO a
forall a. IO a
ioe_notSeekable
      _ -> do Bool
b <- dev -> IO Bool
forall a. IODevice a => a -> IO Bool
IODevice.isSeekable dev
dev
              if Bool
b then Handle__ -> IO a
act Handle__
handle_
                   else IO a
forall a. IO a
ioe_notSeekable

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

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

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

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

ioe_bufsiz :: Int -> IO a
ioe_bufsiz :: Int -> IO a
ioe_bufsiz n :: Int
n = IOException -> IO a
forall a. IOException -> IO a
ioException
   (Maybe Handle
-> IOErrorType
-> FilePath
-> FilePath
-> Maybe CInt
-> Maybe FilePath
-> IOException
IOError Maybe Handle
forall a. Maybe a
Nothing IOErrorType
InvalidArgument "hSetBuffering"
        ("illegal buffer size " FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ Int -> Int -> FilePath -> FilePath
forall a. Show a => Int -> a -> FilePath -> FilePath
showsPrec 9 Int
n []) Maybe CInt
forall a. Maybe a
Nothing Maybe FilePath
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 sequnce. 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 :: BufferCodec from to state
-> Buffer from -> Buffer to -> IO (Buffer from, Buffer to)
streamEncode codec :: BufferCodec from to state
codec from :: Buffer from
from to :: Buffer to
to = ((CodingProgress, Buffer from, Buffer to)
 -> (Buffer from, Buffer to))
-> IO (CodingProgress, Buffer from, Buffer to)
-> IO (Buffer from, Buffer to)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (\(_, from' :: Buffer from
from', to' :: 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 :: BufferCodec from to state -> CodeBuffer from to
recoveringEncode codec :: BufferCodec from to state
codec from :: Buffer from
from to :: Buffer to
to = CodeBuffer from to
go Buffer from
from Buffer to
to
  where
    go :: CodeBuffer from to
go from :: Buffer from
from to :: Buffer to
to = do
      (why :: CodingProgress
why, from' :: Buffer from
from', to' :: Buffer to
to') <- BufferCodec from to state -> CodeBuffer from 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 CodingProgress
why of
        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' :: Buffer from
from', to' :: Buffer to
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'
          CodeBuffer from to
go Buffer from
from' Buffer to
to'
        _ -> (CodingProgress, Buffer from, Buffer to)
-> IO (CodingProgress, Buffer from, Buffer to)
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 fp :: FilePath
fp m :: MVar Handle__
m = do
  Handle__
handle_ <- MVar Handle__ -> IO Handle__
forall a. MVar a -> IO a
takeMVar MVar Handle__
m
  (handle_' :: Handle__
handle_', _) <- Handle__ -> IO (Handle__, Maybe SomeException)
hClose_help Handle__
handle_
  MVar Handle__ -> Handle__ -> IO ()
forall a. MVar a -> a -> IO ()
putMVar MVar Handle__
m Handle__
handle_'
  () -> IO ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()

-- ---------------------------------------------------------------------------
-- 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 = 2048 -- 8k/sizeof(HsChar)

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

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

  (IORef (Buffer CharBufElem), BufferMode)
-> IO (IORef (Buffer CharBufElem), BufferMode)
forall (m :: * -> *) a. Monad m => a -> m a
return (IORef (Buffer CharBufElem)
ioref, BufferMode
buffer_mode)

mkUnBuffer :: BufferState -> IO (IORef CharBuffer, BufferMode)
mkUnBuffer :: BufferState -> IO (IORef (Buffer CharBufElem), BufferMode)
mkUnBuffer state :: BufferState
state = do
  Buffer CharBufElem
buffer <- Int -> BufferState -> IO (Buffer CharBufElem)
newCharBuffer Int
dEFAULT_CHAR_BUFFER_SIZE BufferState
state
              --  See [note Buffer Sizing], GHC.IO.Handle.Types
  IORef (Buffer CharBufElem)
ref <- Buffer CharBufElem -> IO (IORef (Buffer CharBufElem))
forall a. a -> IO (IORef a)
newIORef Buffer CharBufElem
buffer
  (IORef (Buffer CharBufElem), BufferMode)
-> IO (IORef (Buffer CharBufElem), BufferMode)
forall (m :: * -> *) a. Monad m => a -> m a
return (IORef (Buffer CharBufElem)
ref, BufferMode
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__{..} = do
  Buffer CharBufElem
buf <- IORef (Buffer CharBufElem) -> IO (Buffer CharBufElem)
forall a. IORef a -> IO a
readIORef IORef (Buffer CharBufElem)
haCharBuffer
  case Buffer CharBufElem -> BufferState
forall e. Buffer e -> BufferState
bufState Buffer CharBufElem
buf of
    ReadBuffer  -> do
        Handle__ -> IO ()
flushCharReadBuffer Handle__
h_
        Handle__ -> IO ()
flushByteReadBuffer Handle__
h_
    WriteBuffer -> do
        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__{..} = do
  Buffer CharBufElem
cbuf <- IORef (Buffer CharBufElem) -> IO (Buffer CharBufElem)
forall a. IORef a -> IO a
readIORef IORef (Buffer CharBufElem)
haCharBuffer
  case Buffer CharBufElem -> BufferState
forall e. Buffer e -> BufferState
bufState Buffer CharBufElem
cbuf of
    ReadBuffer  -> do
        Handle__ -> IO ()
flushCharReadBuffer Handle__
h_
    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 CharBufElem -> Bool
forall e. Buffer e -> Bool
isEmptyBuffer Buffer CharBufElem
cbuf)) (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$
           FilePath -> IO ()
forall a. HasCallStack => FilePath -> a
error "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__{..} = do
  Buffer Word8
buf <- IORef (Buffer Word8) -> IO (Buffer Word8)
forall a. IORef a -> IO a
readIORef IORef (Buffer Word8)
haByteBuffer
  Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Buffer Word8 -> Bool
forall e. Buffer e -> Bool
isWriteBuffer Buffer Word8
buf) (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ Handle__ -> IO ()
flushByteWriteBuffer Handle__
h_

flushByteWriteBuffer :: Handle__ -> IO ()
flushByteWriteBuffer :: Handle__ -> IO ()
flushByteWriteBuffer h_ :: Handle__
h_@Handle__{..} = do
  Buffer Word8
bbuf <- IORef (Buffer Word8) -> IO (Buffer Word8)
forall a. IORef a -> IO a
readIORef IORef (Buffer Word8)
haByteBuffer
  Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Bool -> Bool
not (Buffer Word8 -> Bool
forall e. Buffer e -> Bool
isEmptyBuffer Buffer Word8
bbuf)) (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ do
    Buffer Word8
bbuf' <- dev -> Buffer Word8 -> IO (Buffer Word8)
forall dev.
BufferedIO dev =>
dev -> Buffer Word8 -> IO (Buffer Word8)
Buffered.flushWriteBuffer dev
haDevice Buffer Word8
bbuf
    IORef (Buffer Word8) -> Buffer Word8 -> IO ()
forall a. IORef a -> a -> IO ()
writeIORef IORef (Buffer Word8)
haByteBuffer Buffer Word8
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.
writeCharBuffer :: Handle__ -> CharBuffer -> IO ()
writeCharBuffer :: Handle__ -> Buffer CharBufElem -> IO ()
writeCharBuffer h_ :: Handle__
h_@Handle__{..} !Buffer CharBufElem
cbuf = do
  --
  Buffer Word8
bbuf <- IORef (Buffer Word8) -> IO (Buffer Word8)
forall a. IORef a -> IO a
readIORef IORef (Buffer Word8)
haByteBuffer

  FilePath -> IO ()
debugIO ("writeCharBuffer: cbuf=" FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ Buffer CharBufElem -> FilePath
forall a. Buffer a -> FilePath
summaryBuffer Buffer CharBufElem
cbuf FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++
        " bbuf=" FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ Buffer Word8 -> FilePath
forall a. Buffer a -> FilePath
summaryBuffer Buffer Word8
bbuf)

  (cbuf' :: Buffer CharBufElem
cbuf',bbuf' :: Buffer Word8
bbuf') <- case Maybe (TextEncoder enc_state)
haEncoder of
    Nothing      -> Buffer CharBufElem
-> Buffer Word8 -> IO (Buffer CharBufElem, Buffer Word8)
latin1_encode Buffer CharBufElem
cbuf Buffer Word8
bbuf
    Just encoder :: TextEncoder enc_state
encoder -> (TextEncoder enc_state
-> Buffer CharBufElem
-> Buffer Word8
-> IO (Buffer CharBufElem, 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 CharBufElem
cbuf Buffer Word8
bbuf

  FilePath -> IO ()
debugIO ("writeCharBuffer after encoding: cbuf=" FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ Buffer CharBufElem -> FilePath
forall a. Buffer a -> FilePath
summaryBuffer Buffer CharBufElem
cbuf' FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++
        " bbuf=" FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ Buffer Word8 -> FilePath
forall a. Buffer a -> FilePath
summaryBuffer Buffer Word8
bbuf')

          -- flush the byte buffer if it is full
  if Buffer Word8 -> Bool
forall e. Buffer e -> Bool
isFullBuffer Buffer Word8
bbuf'
          --  or we made no progress
     Bool -> Bool -> Bool
|| Bool -> Bool
not (Buffer CharBufElem -> Bool
forall e. Buffer e -> Bool
isEmptyBuffer Buffer CharBufElem
cbuf') Bool -> Bool -> Bool
&& Buffer CharBufElem -> Int
forall e. Buffer e -> Int
bufL Buffer CharBufElem
cbuf' Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Buffer CharBufElem -> Int
forall e. Buffer e -> Int
bufL Buffer CharBufElem
cbuf
          -- or the byte buffer has more elements than the user wanted buffered
     Bool -> Bool -> Bool
|| (case BufferMode
haBufferMode of
          BlockBuffering (Just s :: 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
          NoBuffering -> Bool
True
          _other :: BufferMode
_other -> Bool
False)
    then do
      Buffer Word8
bbuf'' <- dev -> Buffer Word8 -> IO (Buffer Word8)
forall dev.
BufferedIO dev =>
dev -> Buffer Word8 -> IO (Buffer Word8)
Buffered.flushWriteBuffer dev
haDevice Buffer Word8
bbuf'
      IORef (Buffer Word8) -> Buffer Word8 -> IO ()
forall a. IORef a -> a -> IO ()
writeIORef IORef (Buffer Word8)
haByteBuffer Buffer Word8
bbuf''
    else
      IORef (Buffer Word8) -> Buffer Word8 -> IO ()
forall a. IORef a -> a -> IO ()
writeIORef IORef (Buffer Word8)
haByteBuffer Buffer Word8
bbuf'

  if Bool -> Bool
not (Buffer CharBufElem -> Bool
forall e. Buffer e -> Bool
isEmptyBuffer Buffer CharBufElem
cbuf')
     then Handle__ -> Buffer CharBufElem -> IO ()
writeCharBuffer Handle__
h_ Buffer CharBufElem
cbuf'
     else () -> IO ()
forall (m :: * -> *) a. Monad m => a -> m a
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__{..} = do
  Buffer CharBufElem
cbuf <- IORef (Buffer CharBufElem) -> IO (Buffer CharBufElem)
forall a. IORef a -> IO a
readIORef IORef (Buffer CharBufElem)
haCharBuffer
  if Buffer CharBufElem -> Bool
forall e. Buffer e -> Bool
isWriteBuffer Buffer CharBufElem
cbuf Bool -> Bool -> Bool
|| Buffer CharBufElem -> Bool
forall e. Buffer e -> Bool
isEmptyBuffer Buffer CharBufElem
cbuf then () -> IO ()
forall (m :: * -> *) a. Monad m => a -> m a
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 :: dec_state
codec_state, bbuf0 :: Buffer Word8
bbuf0) <- IORef (dec_state, Buffer Word8) -> IO (dec_state, Buffer Word8)
forall a. IORef a -> IO a
readIORef IORef (dec_state, Buffer Word8)
haLastDecode

  Buffer CharBufElem
cbuf0 <- IORef (Buffer CharBufElem) -> IO (Buffer CharBufElem)
forall a. IORef a -> IO a
readIORef IORef (Buffer CharBufElem)
haCharBuffer
  IORef (Buffer CharBufElem) -> Buffer CharBufElem -> IO ()
forall a. IORef a -> a -> IO ()
writeIORef IORef (Buffer CharBufElem)
haCharBuffer Buffer CharBufElem
cbuf0{ bufL :: Int
bufL=0, bufR :: Int
bufR=0 }

  -- if we haven't used any characters from the char buffer, then just
  -- re-install the old byte buffer.
  if Buffer CharBufElem -> Int
forall e. Buffer e -> Int
bufL Buffer CharBufElem
cbuf0 Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== 0
     then do IORef (Buffer Word8) -> Buffer Word8 -> IO ()
forall a. IORef a -> a -> IO ()
writeIORef IORef (Buffer Word8)
haByteBuffer Buffer Word8
bbuf0
             () -> IO ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
     else do

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

    Just decoder :: TextDecoder dec_state
decoder -> do
      FilePath -> IO ()
debugIO ("flushCharReadBuffer re-decode, bbuf=" FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ Buffer Word8 -> FilePath
forall a. Buffer a -> FilePath
summaryBuffer Buffer Word8
bbuf0 FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++
               " cbuf=" FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ Buffer CharBufElem -> FilePath
forall a. Buffer a -> FilePath
summaryBuffer Buffer CharBufElem
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 :: Buffer Word8
bbuf1,cbuf1 :: Buffer CharBufElem
cbuf1) <- (TextDecoder dec_state
-> Buffer Word8
-> Buffer CharBufElem
-> IO (Buffer Word8, Buffer CharBufElem)
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 CharBufElem
cbuf0{ bufL :: Int
bufL=0, bufR :: Int
bufR=0, bufSize :: Int
bufSize = Buffer CharBufElem -> Int
forall e. Buffer e -> Int
bufL Buffer CharBufElem
cbuf0 }

      FilePath -> IO ()
debugIO ("finished, bbuf=" FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ Buffer Word8 -> FilePath
forall a. Buffer a -> FilePath
summaryBuffer Buffer Word8
bbuf1 FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++
               " cbuf=" FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ Buffer CharBufElem -> FilePath
forall a. Buffer a -> FilePath
summaryBuffer Buffer CharBufElem
cbuf1)

      IORef (Buffer Word8) -> Buffer Word8 -> IO ()
forall a. IORef a -> a -> IO ()
writeIORef IORef (Buffer Word8)
haByteBuffer Buffer Word8
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__{..} = do
  Buffer Word8
bbuf <- IORef (Buffer Word8) -> IO (Buffer Word8)
forall a. IORef a -> IO a
readIORef IORef (Buffer Word8)
haByteBuffer

  if Buffer Word8 -> Bool
forall e. Buffer e -> Bool
isEmptyBuffer Buffer Word8
bbuf then () -> IO ()
forall (m :: * -> *) a. Monad m => a -> m a
return () else do

  Bool
seekable <- dev -> IO Bool
forall a. IODevice a => a -> IO Bool
IODevice.isSeekable dev
haDevice
  Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Bool -> Bool
not Bool
seekable) (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ IO ()
forall a. IO a
ioe_cannotFlushNotSeekable

  let seek :: Int
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)

  FilePath -> IO ()
debugIO ("flushByteReadBuffer: new file offset = " FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ Int -> FilePath
forall a. Show a => a -> FilePath
show Int
seek)
  dev -> SeekMode -> Integer -> IO ()
forall a. IODevice a => a -> SeekMode -> Integer -> IO ()
IODevice.seek dev
haDevice SeekMode
RelativeSeek (Int -> Integer
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
seek)

  IORef (Buffer Word8) -> Buffer Word8 -> IO ()
forall a. IORef a -> a -> IO ()
writeIORef IORef (Buffer Word8)
haByteBuffer Buffer Word8
bbuf{ bufL :: Int
bufL=0, bufR :: Int
bufR=0 }

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

mkHandle :: (IODevice dev, BufferedIO dev, Typeable dev) => dev
            -> FilePath
            -> HandleType
            -> Bool                     -- buffered?
            -> Maybe TextEncoding
            -> NewlineMode
            -> Maybe HandleFinalizer
            -> Maybe (MVar Handle__)
            -> IO Handle

mkHandle :: dev
-> FilePath
-> HandleType
-> Bool
-> Maybe TextEncoding
-> NewlineMode
-> Maybe HandleFinalizer
-> Maybe (MVar Handle__)
-> IO Handle
mkHandle dev :: dev
dev filepath :: FilePath
filepath ha_type :: HandleType
ha_type buffered :: Bool
buffered mb_codec :: Maybe TextEncoding
mb_codec nl :: NewlineMode
nl finalizer :: Maybe HandleFinalizer
finalizer other_side :: Maybe (MVar Handle__)
other_side = do
   Maybe TextEncoding
-> HandleType
-> (forall es ds.
    Maybe (TextEncoder es) -> Maybe (TextDecoder ds) -> IO Handle)
-> IO 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 Handle)
 -> IO Handle)
-> (forall es ds.
    Maybe (TextEncoder es) -> Maybe (TextDecoder ds) -> IO Handle)
-> IO Handle
forall a b. (a -> b) -> a -> b
$ \ mb_encoder :: Maybe (TextEncoder es)
mb_encoder mb_decoder :: Maybe (TextDecoder ds)
mb_decoder -> do

   let buf_state :: BufferState
buf_state = HandleType -> BufferState
initBufferState HandleType
ha_type
   Buffer Word8
bbuf <- dev -> BufferState -> IO (Buffer Word8)
forall dev.
BufferedIO dev =>
dev -> BufferState -> IO (Buffer Word8)
Buffered.newBuffer dev
dev BufferState
buf_state
   IORef (Buffer Word8)
bbufref <- Buffer Word8 -> IO (IORef (Buffer Word8))
forall a. a -> IO (IORef a)
newIORef Buffer Word8
bbuf
   IORef (ds, Buffer Word8)
last_decode <- (ds, Buffer Word8) -> IO (IORef (ds, Buffer Word8))
forall a. a -> IO (IORef a)
newIORef (FilePath -> ds
forall a. FilePath -> a
errorWithoutStackTrace "codec_state", Buffer Word8
bbuf)

   (cbufref :: IORef (Buffer CharBufElem)
cbufref,bmode :: BufferMode
bmode) <-
         if Bool
buffered then dev -> BufferState -> IO (IORef (Buffer CharBufElem), BufferMode)
forall dev.
IODevice dev =>
dev -> BufferState -> IO (IORef (Buffer CharBufElem), BufferMode)
getCharBuffer dev
dev BufferState
buf_state
                     else BufferState -> IO (IORef (Buffer CharBufElem), BufferMode)
mkUnBuffer BufferState
buf_state

   IORef (BufferList CharBufElem)
spares <- BufferList CharBufElem -> IO (IORef (BufferList CharBufElem))
forall a. a -> IO (IORef a)
newIORef BufferList CharBufElem
forall e. BufferList e
BufferListNil
   FilePath -> Maybe HandleFinalizer -> Handle__ -> IO Handle
newFileHandle FilePath
filepath Maybe HandleFinalizer
finalizer
            ($WHandle__ :: forall dev enc_state dec_state.
(IODevice dev, BufferedIO dev, Typeable dev) =>
dev
-> HandleType
-> IORef (Buffer Word8)
-> BufferMode
-> IORef (dec_state, Buffer Word8)
-> IORef (Buffer CharBufElem)
-> IORef (BufferList CharBufElem)
-> Maybe (TextEncoder enc_state)
-> Maybe (TextDecoder dec_state)
-> Maybe TextEncoding
-> Newline
-> Newline
-> Maybe (MVar Handle__)
-> Handle__
Handle__ { haDevice :: dev
haDevice = dev
dev,
                        haType :: HandleType
haType = HandleType
ha_type,
                        haBufferMode :: BufferMode
haBufferMode = BufferMode
bmode,
                        haByteBuffer :: IORef (Buffer Word8)
haByteBuffer = IORef (Buffer Word8)
bbufref,
                        haLastDecode :: IORef (ds, Buffer Word8)
haLastDecode = IORef (ds, Buffer Word8)
last_decode,
                        haCharBuffer :: IORef (Buffer CharBufElem)
haCharBuffer = IORef (Buffer CharBufElem)
cbufref,
                        haBuffers :: IORef (BufferList CharBufElem)
haBuffers = IORef (BufferList CharBufElem)
spares,
                        haEncoder :: Maybe (TextEncoder es)
haEncoder = Maybe (TextEncoder es)
mb_encoder,
                        haDecoder :: Maybe (TextDecoder ds)
haDecoder = Maybe (TextDecoder ds)
mb_decoder,
                        haCodec :: Maybe TextEncoding
haCodec = Maybe TextEncoding
mb_codec,
                        haInputNL :: Newline
haInputNL = NewlineMode -> Newline
inputNL NewlineMode
nl,
                        haOutputNL :: Newline
haOutputNL = NewlineMode -> Newline
outputNL NewlineMode
nl,
                        haOtherSide :: Maybe (MVar Handle__)
haOtherSide = Maybe (MVar Handle__)
other_side
                      })

-- | makes a new 'Handle'
mkFileHandle :: (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 :: dev
-> FilePath
-> IOMode
-> Maybe TextEncoding
-> NewlineMode
-> IO Handle
mkFileHandle dev :: dev
dev filepath :: FilePath
filepath iomode :: IOMode
iomode mb_codec :: Maybe TextEncoding
mb_codec tr_newlines :: NewlineMode
tr_newlines = do
   dev
-> FilePath
-> HandleType
-> Bool
-> Maybe TextEncoding
-> NewlineMode
-> Maybe HandleFinalizer
-> Maybe (MVar Handle__)
-> IO Handle
forall dev.
(IODevice dev, BufferedIO dev, Typeable dev) =>
dev
-> FilePath
-> HandleType
-> Bool
-> Maybe TextEncoding
-> NewlineMode
-> Maybe HandleFinalizer
-> Maybe (MVar Handle__)
-> IO Handle
mkHandle dev
dev FilePath
filepath (IOMode -> HandleType
ioModeToHandleType IOMode
iomode) Bool
True{-buffered-} Maybe TextEncoding
mb_codec
            NewlineMode
tr_newlines
            (HandleFinalizer -> Maybe HandleFinalizer
forall a. a -> Maybe a
Just HandleFinalizer
handleFinalizer) Maybe (MVar Handle__)
forall a. Maybe a
Nothing{-other_side-}

-- | 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 :: (IODevice dev, BufferedIO dev, Typeable dev) => dev
               -> FilePath -> Maybe TextEncoding -> NewlineMode -> IO Handle
mkDuplexHandle :: dev -> FilePath -> Maybe TextEncoding -> NewlineMode -> IO Handle
mkDuplexHandle dev :: dev
dev filepath :: FilePath
filepath mb_codec :: Maybe TextEncoding
mb_codec tr_newlines :: NewlineMode
tr_newlines = do

  write_side :: Handle
write_side@(FileHandle _ write_m :: MVar Handle__
write_m) <-
       dev
-> FilePath
-> HandleType
-> Bool
-> Maybe TextEncoding
-> NewlineMode
-> Maybe HandleFinalizer
-> Maybe (MVar Handle__)
-> IO Handle
forall dev.
(IODevice dev, BufferedIO dev, Typeable dev) =>
dev
-> FilePath
-> HandleType
-> Bool
-> Maybe TextEncoding
-> NewlineMode
-> Maybe HandleFinalizer
-> Maybe (MVar Handle__)
-> IO Handle
mkHandle dev
dev FilePath
filepath HandleType
WriteHandle Bool
True Maybe TextEncoding
mb_codec
                        NewlineMode
tr_newlines
                        (HandleFinalizer -> Maybe HandleFinalizer
forall a. a -> Maybe a
Just HandleFinalizer
handleFinalizer)
                        Maybe (MVar Handle__)
forall a. Maybe a
Nothing -- no othersie

  read_side :: Handle
read_side@(FileHandle _ read_m :: MVar Handle__
read_m) <-
      dev
-> FilePath
-> HandleType
-> Bool
-> Maybe TextEncoding
-> NewlineMode
-> Maybe HandleFinalizer
-> Maybe (MVar Handle__)
-> IO Handle
forall dev.
(IODevice dev, BufferedIO dev, Typeable dev) =>
dev
-> FilePath
-> HandleType
-> Bool
-> Maybe TextEncoding
-> NewlineMode
-> Maybe HandleFinalizer
-> Maybe (MVar Handle__)
-> IO Handle
mkHandle dev
dev FilePath
filepath HandleType
ReadHandle Bool
True Maybe TextEncoding
mb_codec
                        NewlineMode
tr_newlines
                        Maybe HandleFinalizer
forall a. Maybe a
Nothing -- no finalizer
                        (MVar Handle__ -> Maybe (MVar Handle__)
forall a. a -> Maybe a
Just MVar Handle__
write_m)

  Handle -> IO Handle
forall (m :: * -> *) a. Monad m => a -> m a
return (FilePath -> MVar Handle__ -> MVar Handle__ -> Handle
DuplexHandle FilePath
filepath MVar Handle__
read_m MVar Handle__
write_m)

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

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

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

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

closeTextCodecs :: Handle__ -> IO ()
closeTextCodecs :: Handle__ -> IO ()
closeTextCodecs Handle__{..} = do
  case Maybe (TextDecoder dec_state)
haDecoder of Nothing -> () -> IO ()
forall (m :: * -> *) a. Monad m => a -> m a
return (); Just d :: 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 Nothing -> () -> IO ()
forall (m :: * -> *) a. Monad m => a -> m a
return (); Just d :: TextEncoder enc_state
d -> TextEncoder enc_state -> IO ()
forall from to state. BufferCodec from to state -> IO ()
Encoding.close TextEncoder enc_state
d

-- ---------------------------------------------------------------------------
-- closing Handles

-- 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__
handle_ =
  case Handle__ -> HandleType
haType Handle__
handle_ of
      ClosedHandle -> (Handle__, Maybe SomeException)
-> IO (Handle__, Maybe SomeException)
forall (m :: * -> *) a. Monad m => a -> m a
return (Handle__
handle_,Maybe SomeException
forall a. Maybe a
Nothing)
      _ -> do Maybe SomeException
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_ :: Handle__
h_, mb_exc2 :: Maybe SomeException
mb_exc2) <- Handle__ -> IO (Handle__, Maybe SomeException)
hClose_handle_ Handle__
handle_
              (Handle__, Maybe SomeException)
-> IO (Handle__, Maybe SomeException)
forall (m :: * -> *) a. Monad m => a -> m a
return (Handle__
h_, if Maybe SomeException -> Bool
forall a. Maybe a -> Bool
isJust Maybe SomeException
mb_exc1 then Maybe SomeException
mb_exc1 else Maybe SomeException
mb_exc2)


trymaybe :: IO () -> IO (Maybe SomeException)
trymaybe :: IO () -> IO (Maybe SomeException)
trymaybe io :: IO ()
io = (do IO ()
io; Maybe SomeException -> IO (Maybe SomeException)
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` \e :: SomeException
e -> Maybe SomeException -> IO (Maybe SomeException)
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__{..} = 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 SomeException
maybe_exception <-
      case Maybe (MVar Handle__)
haOtherSide of
        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 _  -> Maybe SomeException -> IO (Maybe SomeException)
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe SomeException
forall a. Maybe a
Nothing

    -- free the spare buffers
    IORef (BufferList CharBufElem) -> BufferList CharBufElem -> IO ()
forall a. IORef a -> a -> IO ()
writeIORef IORef (BufferList CharBufElem)
haBuffers BufferList CharBufElem
forall e. BufferList e
BufferListNil
    IORef (Buffer CharBufElem) -> Buffer CharBufElem -> IO ()
forall a. IORef a -> a -> IO ()
writeIORef IORef (Buffer CharBufElem)
haCharBuffer Buffer CharBufElem
noCharBuffer
    IORef (Buffer Word8) -> Buffer Word8 -> IO ()
forall a. IORef a -> a -> IO ()
writeIORef IORef (Buffer Word8)
haByteBuffer Buffer Word8
noByteBuffer

    -- release our encoder/decoder
    Handle__ -> IO ()
closeTextCodecs Handle__
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
    (Handle__, Maybe SomeException)
-> IO (Handle__, Maybe SomeException)
forall (m :: * -> *) a. Monad m => a -> m a
return ($WHandle__ :: forall dev enc_state dec_state.
(IODevice dev, BufferedIO dev, Typeable dev) =>
dev
-> HandleType
-> IORef (Buffer Word8)
-> BufferMode
-> IORef (dec_state, Buffer Word8)
-> IORef (Buffer CharBufElem)
-> IORef (BufferList CharBufElem)
-> Maybe (TextEncoder enc_state)
-> Maybe (TextDecoder dec_state)
-> Maybe TextEncoding
-> Newline
-> Newline
-> Maybe (MVar Handle__)
-> Handle__
Handle__{ haType :: HandleType
haType = HandleType
ClosedHandle, .. }, Maybe SomeException
maybe_exception)

{-# NOINLINE noCharBuffer #-}
noCharBuffer :: CharBuffer
noCharBuffer :: Buffer CharBufElem
noCharBuffer = IO (Buffer CharBufElem) -> Buffer CharBufElem
forall a. IO a -> a
unsafePerformIO (IO (Buffer CharBufElem) -> Buffer CharBufElem)
-> IO (Buffer CharBufElem) -> Buffer CharBufElem
forall a b. (a -> b) -> a -> b
$ Int -> BufferState -> IO (Buffer CharBufElem)
newCharBuffer 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 1 BufferState
ReadBuffer

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

hLookAhead_ :: Handle__ -> IO Char
hLookAhead_ :: Handle__ -> IO CharBufElem
hLookAhead_ handle_ :: Handle__
handle_@Handle__{..} = do
    Buffer CharBufElem
buf <- IORef (Buffer CharBufElem) -> IO (Buffer CharBufElem)
forall a. IORef a -> IO a
readIORef IORef (Buffer CharBufElem)
haCharBuffer

    -- fill up the read buffer if necessary
    Buffer CharBufElem
new_buf <- if Buffer CharBufElem -> Bool
forall e. Buffer e -> Bool
isEmptyBuffer Buffer CharBufElem
buf
                  then Handle__ -> Buffer CharBufElem -> IO (Buffer CharBufElem)
readTextDevice Handle__
handle_ Buffer CharBufElem
buf
                  else Buffer CharBufElem -> IO (Buffer CharBufElem)
forall (m :: * -> *) a. Monad m => a -> m a
return Buffer CharBufElem
buf
    IORef (Buffer CharBufElem) -> Buffer CharBufElem -> IO ()
forall a. IORef a -> a -> IO ()
writeIORef IORef (Buffer CharBufElem)
haCharBuffer Buffer CharBufElem
new_buf

    RawCharBuffer -> Int -> IO CharBufElem
peekCharBuf (Buffer CharBufElem -> RawCharBuffer
forall e. Buffer e -> RawBuffer e
bufRaw Buffer CharBufElem
buf) (Buffer CharBufElem -> Int
forall e. Buffer e -> Int
bufL Buffer CharBufElem
buf)

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

debugIO :: String -> IO ()
debugIO :: FilePath -> IO ()
debugIO s :: FilePath
s
 | Bool
c_DEBUG_DUMP
    = do CSsize
_ <- FilePath -> (CStringLen -> IO CSsize) -> IO CSsize
forall a. FilePath -> (CStringLen -> IO a) -> IO a
withCStringLen (FilePath
s FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ "\n") ((CStringLen -> IO CSsize) -> IO CSsize)
-> (CStringLen -> IO CSsize) -> IO CSsize
forall a b. (a -> b) -> a -> b
$
                  \(p :: Ptr CChar
p, len :: Int
len) -> CInt -> Ptr Word8 -> CSize -> IO CSsize
c_write 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)
         () -> IO ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
 | Bool
otherwise = () -> IO ()
forall (m :: * -> *) a. Monad m => a -> m a
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 CharBufElem -> IO (Buffer CharBufElem)
readTextDevice h_ :: Handle__
h_@Handle__{..} cbuf :: Buffer CharBufElem
cbuf = do
  --
  Buffer Word8
bbuf0 <- IORef (Buffer Word8) -> IO (Buffer Word8)
forall a. IORef a -> IO a
readIORef IORef (Buffer Word8)
haByteBuffer

  FilePath -> IO ()
debugIO ("readTextDevice: cbuf=" FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ Buffer CharBufElem -> FilePath
forall a. Buffer a -> FilePath
summaryBuffer Buffer CharBufElem
cbuf FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++
        " bbuf=" FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ Buffer Word8 -> FilePath
forall a. Buffer a -> FilePath
summaryBuffer Buffer Word8
bbuf0)

  Buffer Word8
bbuf1 <- if Bool -> Bool
not (Buffer Word8 -> Bool
forall e. Buffer e -> Bool
isEmptyBuffer Buffer Word8
bbuf0)
              then Buffer Word8 -> IO (Buffer Word8)
forall (m :: * -> *) a. Monad m => a -> m a
return Buffer Word8
bbuf0
              else do
                   (r :: Int
r,bbuf1 :: Buffer Word8
bbuf1) <- dev -> Buffer Word8 -> IO (Int, Buffer Word8)
forall dev.
BufferedIO dev =>
dev -> Buffer Word8 -> IO (Int, Buffer Word8)
Buffered.fillReadBuffer dev
haDevice Buffer Word8
bbuf0
                   if Int
r Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== 0 then IO (Buffer Word8)
forall a. IO a
ioe_EOF else do  -- raise EOF
                   Buffer Word8 -> IO (Buffer Word8)
forall (m :: * -> *) a. Monad m => a -> m a
return Buffer Word8
bbuf1

  FilePath -> IO ()
debugIO ("readTextDevice after reading: bbuf=" FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ Buffer Word8 -> FilePath
forall a. Buffer a -> FilePath
summaryBuffer Buffer Word8
bbuf1)

  (bbuf2 :: Buffer Word8
bbuf2,cbuf' :: Buffer CharBufElem
cbuf') <-
      case Maybe (TextDecoder dec_state)
haDecoder of
          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 (FilePath -> dec_state
forall a. FilePath -> a
errorWithoutStackTrace "codec_state", Buffer Word8
bbuf1)
               Buffer Word8
-> Buffer CharBufElem -> IO (Buffer Word8, Buffer CharBufElem)
latin1_decode Buffer Word8
bbuf1 Buffer CharBufElem
cbuf
          Just decoder :: TextDecoder dec_state
decoder -> do
               dec_state
state <- TextDecoder dec_state -> IO dec_state
forall from to state. BufferCodec from to state -> IO state
getState TextDecoder dec_state
decoder
               IORef (dec_state, Buffer Word8)
-> (dec_state, Buffer Word8) -> IO ()
forall a. IORef a -> a -> IO ()
writeIORef IORef (dec_state, Buffer Word8)
haLastDecode (dec_state
state, Buffer Word8
bbuf1)
               (TextDecoder dec_state
-> Buffer Word8
-> Buffer CharBufElem
-> IO (Buffer Word8, Buffer CharBufElem)
forall from to state.
BufferCodec from to state
-> Buffer from -> Buffer to -> IO (Buffer from, Buffer to)
streamEncode TextDecoder dec_state
decoder) Buffer Word8
bbuf1 Buffer CharBufElem
cbuf

  FilePath -> IO ()
debugIO ("readTextDevice after decoding: cbuf=" FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ Buffer CharBufElem -> FilePath
forall a. Buffer a -> FilePath
summaryBuffer Buffer CharBufElem
cbuf' FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++
        " bbuf=" FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ Buffer Word8 -> FilePath
forall a. Buffer a -> FilePath
summaryBuffer Buffer Word8
bbuf2)

  -- We can't return from readTextDevice without reading at least a single extra character,
  -- so check that we have managed to achieve that
  IORef (Buffer Word8) -> Buffer Word8 -> IO ()
forall a. IORef a -> a -> IO ()
writeIORef IORef (Buffer Word8)
haByteBuffer Buffer Word8
bbuf2
  if Buffer CharBufElem -> Int
forall e. Buffer e -> Int
bufR Buffer CharBufElem
cbuf' Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Buffer CharBufElem -> Int
forall e. Buffer e -> Int
bufR Buffer CharBufElem
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 Handle__
-> Buffer Word8 -> Buffer CharBufElem -> IO (Buffer CharBufElem)
readTextDevice' Handle__
h_ Buffer Word8
bbuf2 Buffer CharBufElem
cbuf
     else Buffer CharBufElem -> IO (Buffer CharBufElem)
forall (m :: * -> *) a. Monad m => a -> m a
return Buffer CharBufElem
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 CharBufElem -> IO (Buffer CharBufElem)
readTextDevice' h_ :: Handle__
h_@Handle__{..} bbuf0 :: Buffer Word8
bbuf0 cbuf0 :: Buffer CharBufElem
cbuf0 = do
  --
  -- copy the partial sequence to the beginning of the buffer, so we have
  -- room to read more bytes.
  Buffer Word8
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 :: TextDecoder dec_state
decoder = Maybe (TextDecoder dec_state)
haDecoder

  (r :: Int
r,bbuf2 :: Buffer Word8
bbuf2) <- dev -> Buffer Word8 -> IO (Int, Buffer Word8)
forall dev.
BufferedIO dev =>
dev -> Buffer Word8 -> IO (Int, Buffer Word8)
Buffered.fillReadBuffer dev
haDevice Buffer Word8
bbuf1
  if Int
r Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== 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 Buffer Word8 -> Bool
forall e. Buffer e -> Bool
isEmptyBuffer Buffer Word8
bbuf2 then IO (Buffer CharBufElem)
forall a. IO a
ioe_EOF else do
     (bbuf3 :: Buffer Word8
bbuf3, cbuf1 :: Buffer CharBufElem
cbuf1) <- TextDecoder dec_state
-> Buffer Word8
-> Buffer CharBufElem
-> IO (Buffer Word8, Buffer CharBufElem)
forall from to state.
BufferCodec from to state
-> Buffer from -> Buffer to -> IO (Buffer from, Buffer to)
recover TextDecoder dec_state
decoder Buffer Word8
bbuf2 Buffer CharBufElem
cbuf0
     FilePath -> IO ()
debugIO ("readTextDevice' after recovery: bbuf=" FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ Buffer Word8 -> FilePath
forall a. Buffer a -> FilePath
summaryBuffer Buffer Word8
bbuf3 FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ ", cbuf=" FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ Buffer CharBufElem -> FilePath
forall a. Buffer a -> FilePath
summaryBuffer Buffer CharBufElem
cbuf1)
     IORef (Buffer Word8) -> Buffer Word8 -> IO ()
forall a. IORef a -> a -> IO ()
writeIORef IORef (Buffer Word8)
haByteBuffer Buffer Word8
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 Buffer CharBufElem -> Int
forall e. Buffer e -> Int
bufR Buffer CharBufElem
cbuf1 Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Buffer CharBufElem -> Int
forall e. Buffer e -> Int
bufR Buffer CharBufElem
cbuf0
      then Handle__ -> Buffer CharBufElem -> IO (Buffer CharBufElem)
readTextDevice Handle__
h_ Buffer CharBufElem
cbuf1
      else Buffer CharBufElem -> IO (Buffer CharBufElem)
forall (m :: * -> *) a. Monad m => a -> m a
return Buffer CharBufElem
cbuf1
   else do
    FilePath -> IO ()
debugIO ("readTextDevice' after reading: bbuf=" FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ Buffer Word8 -> FilePath
forall a. Buffer a -> FilePath
summaryBuffer Buffer Word8
bbuf2)

    (bbuf3 :: Buffer Word8
bbuf3,cbuf1 :: Buffer CharBufElem
cbuf1) <- do
       dec_state
state <- TextDecoder dec_state -> IO dec_state
forall from to state. BufferCodec from to state -> IO state
getState TextDecoder dec_state
decoder
       IORef (dec_state, Buffer Word8)
-> (dec_state, Buffer Word8) -> IO ()
forall a. IORef a -> a -> IO ()
writeIORef IORef (dec_state, Buffer Word8)
haLastDecode (dec_state
state, Buffer Word8
bbuf2)
       (TextDecoder dec_state
-> Buffer Word8
-> Buffer CharBufElem
-> IO (Buffer Word8, Buffer CharBufElem)
forall from to state.
BufferCodec from to state
-> Buffer from -> Buffer to -> IO (Buffer from, Buffer to)
streamEncode TextDecoder dec_state
decoder) Buffer Word8
bbuf2 Buffer CharBufElem
cbuf0

    FilePath -> IO ()
debugIO ("readTextDevice' after decoding: cbuf=" FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ Buffer CharBufElem -> FilePath
forall a. Buffer a -> FilePath
summaryBuffer Buffer CharBufElem
cbuf1 FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++
          " bbuf=" FilePath -> FilePath -> FilePath
forall a. [a] -> [a] -> [a]
++ Buffer Word8 -> FilePath
forall a. Buffer a -> FilePath
summaryBuffer Buffer Word8
bbuf3)

    IORef (Buffer Word8) -> Buffer Word8 -> IO ()
forall a. IORef a -> a -> IO ()
writeIORef IORef (Buffer Word8)
haByteBuffer Buffer Word8
bbuf3
    if Buffer CharBufElem -> Int
forall e. Buffer e -> Int
bufR Buffer CharBufElem
cbuf0 Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Buffer CharBufElem -> Int
forall e. Buffer e -> Int
bufR Buffer CharBufElem
cbuf1
       then Handle__
-> Buffer Word8 -> Buffer CharBufElem -> IO (Buffer CharBufElem)
readTextDevice' Handle__
h_ Buffer Word8
bbuf3 Buffer CharBufElem
cbuf1
       else Buffer CharBufElem -> IO (Buffer CharBufElem)
forall (m :: * -> *) a. Monad m => a -> m a
return Buffer CharBufElem
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 CharBufElem -> IO (Buffer CharBufElem)
readTextDeviceNonBlocking h_ :: Handle__
h_@Handle__{..} cbuf :: Buffer CharBufElem
cbuf = do
  --
  Buffer Word8
bbuf0 <- IORef (Buffer Word8) -> IO (Buffer Word8)
forall a. IORef a -> IO a
readIORef IORef (Buffer Word8)
haByteBuffer
  Bool -> IO () -> IO ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Buffer Word8 -> Bool
forall e. Buffer e -> Bool
isEmptyBuffer Buffer Word8
bbuf0) (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ do
     (r :: Maybe Int
r,bbuf1 :: Buffer Word8
bbuf1) <- dev -> Buffer Word8 -> IO (Maybe Int, Buffer Word8)
forall dev.
BufferedIO dev =>
dev -> Buffer Word8 -> IO (Maybe Int, Buffer Word8)
Buffered.fillReadBuffer0 dev
haDevice Buffer Word8
bbuf0
     if Maybe Int -> Bool
forall a. Maybe a -> Bool
isNothing Maybe Int
r then IO ()
forall a. IO a
ioe_EOF else do  -- raise EOF
     IORef (Buffer Word8) -> Buffer Word8 -> IO ()
forall a. IORef a -> a -> IO ()
writeIORef IORef (Buffer Word8)
haByteBuffer Buffer Word8
bbuf1

  Handle__ -> Buffer CharBufElem -> IO (Buffer CharBufElem)
decodeByteBuf Handle__
h_ Buffer CharBufElem
cbuf

-- Decode bytes from the byte buffer into the supplied CharBuffer.
decodeByteBuf :: Handle__ -> CharBuffer -> IO CharBuffer
decodeByteBuf :: Handle__ -> Buffer CharBufElem -> IO (Buffer CharBufElem)
decodeByteBuf h_ :: Handle__
h_@Handle__{..} cbuf :: Buffer CharBufElem
cbuf = do
  --
  Buffer Word8
bbuf0 <- IORef (Buffer Word8) -> IO (Buffer Word8)
forall a. IORef a -> IO a
readIORef IORef (Buffer Word8)
haByteBuffer

  (bbuf2 :: Buffer Word8
bbuf2,cbuf' :: Buffer CharBufElem
cbuf') <-
      case Maybe (TextDecoder dec_state)
haDecoder of
          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 (FilePath -> dec_state
forall a. FilePath -> a
errorWithoutStackTrace "codec_state", Buffer Word8
bbuf0)
               Buffer Word8
-> Buffer CharBufElem -> IO (Buffer Word8, Buffer CharBufElem)
latin1_decode Buffer Word8
bbuf0 Buffer CharBufElem
cbuf
          Just decoder :: TextDecoder dec_state
decoder -> do
               dec_state
state <- TextDecoder dec_state -> IO dec_state
forall from to state. BufferCodec from to state -> IO state
getState TextDecoder dec_state
decoder
               IORef (dec_state, Buffer Word8)
-> (dec_state, Buffer Word8) -> IO ()
forall a. IORef a -> a -> IO ()
writeIORef IORef (dec_state, Buffer Word8)
haLastDecode (dec_state
state, Buffer Word8
bbuf0)
               (TextDecoder dec_state
-> Buffer Word8
-> Buffer CharBufElem
-> IO (Buffer Word8, Buffer CharBufElem)
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 CharBufElem
cbuf

  IORef (Buffer Word8) -> Buffer Word8 -> IO ()
forall a. IORef a -> a -> IO ()
writeIORef IORef (Buffer Word8)
haByteBuffer Buffer Word8
bbuf2
  Buffer CharBufElem -> IO (Buffer CharBufElem)
forall (m :: * -> *) a. Monad m => a -> m a
return Buffer CharBufElem
cbuf'