{-# LANGUAGE CPP #-} {-# LANGUAGE FlexibleInstances #-} #if __GLASGOW_HASKELL__ >= 702 {-# LANGUAGE Trustworthy #-} #endif -- | Input and output streams for file 'Handle's. module System.IO.Streams.Handle ( -- * Handle conversions handleToInputStream , handleToOutputStream , handleToStreams , inputStreamToHandle , outputStreamToHandle , streamPairToHandle -- * Standard system handles , stdin , stdout , stderr ) where ------------------------------------------------------------------------------ import Data.ByteString (ByteString) import qualified Data.ByteString as S import qualified GHC.IO.Handle as H import System.IO (Handle, hFlush) import qualified System.IO as IO import System.IO.Unsafe (unsafePerformIO) ------------------------------------------------------------------------------ import System.IO.Streams.Internal (InputStream, OutputStream, SP (..), lockingInputStream, lockingOutputStream, makeInputStream, makeOutputStream) ------------------------------------------------------------------------------ bUFSIZ :: Int bUFSIZ = 32752 ------------------------------------------------------------------------------ -- | Converts a read-only handle into an 'InputStream' of strict 'ByteString's. -- -- Note that the wrapped handle is /not/ closed when it yields end-of-stream; -- you can use 'System.IO.Streams.Combinators.atEndOfInput' to close the handle -- if you would like this behaviour. handleToInputStream :: Handle -> IO (InputStream ByteString) handleToInputStream h = makeInputStream f where f = do x <- S.hGetSome h bUFSIZ return $! if S.null x then Nothing else Just x ------------------------------------------------------------------------------ -- | Converts a writable handle into an 'OutputStream' of strict 'ByteString's. -- -- Note that the wrapped handle is /not/ closed when it receives end-of-stream; -- you can use 'System.IO.Streams.Combinators.atEndOfOutput' to close the -- handle if you would like this behaviour. -- -- /Note/: to force the 'Handle' to be flushed, you can write a null string to -- the returned 'OutputStream': -- -- > Streams.write (Just "") os handleToOutputStream :: Handle -> IO (OutputStream ByteString) handleToOutputStream h = makeOutputStream f where f Nothing = hFlush h f (Just x) = if S.null x then hFlush h else S.hPut h x ------------------------------------------------------------------------------ -- | Converts a readable and writable handle into an 'InputStream'/'OutputStream' -- of strict 'ByteString's. -- -- Note that the wrapped handle is /not/ closed when it receives -- end-of-stream; you can use -- 'System.IO.Streams.Combinators.atEndOfOutput' to close the handle -- if you would like this behaviour. -- -- /Note/: to force the 'Handle' to be flushed, you can write a null string to -- the returned 'OutputStream': -- -- > Streams.write (Just "") os -- -- /Since: 1.3.4.0./ handleToStreams :: Handle -> IO (InputStream ByteString, OutputStream ByteString) handleToStreams h = do is <- handleToInputStream h os <- handleToOutputStream h return $! (is, os) ------------------------------------------------------------------------------ -- | Converts an 'InputStream' over bytestrings to a read-only 'Handle'. Note -- that the generated handle is opened unbuffered in binary mode (i.e. no -- newline translation is performed). -- -- Note: the 'InputStream' passed into this function is wrapped in -- 'lockingInputStream' to make it thread-safe. -- -- /Since: 1.0.2.0./ inputStreamToHandle :: InputStream ByteString -> IO Handle inputStreamToHandle is0 = do is <- lockingInputStream is0 h <- H.mkDuplexHandle is "*input-stream*" Nothing $! H.noNewlineTranslation H.hSetBuffering h H.NoBuffering return h ------------------------------------------------------------------------------ -- | Converts an 'OutputStream' over bytestrings to a write-only 'Handle'. Note -- that the 'Handle' will be opened in non-buffering mode; if you buffer the -- 'OutputStream' using the 'Handle' buffering then @io-streams@ will copy the -- 'Handle' buffer when sending 'ByteString' values to the output, which might -- not be what you want. -- -- When the output buffer, if used, is flushed (using 'System.IO.hFlush'), an -- empty string is written to the provided 'OutputStream'. -- -- /Note/: the 'OutputStream' passed into this function is wrapped in -- 'lockingOutputStream' to make it thread-safe. -- -- /Since: 1.0.2.0./ outputStreamToHandle :: OutputStream ByteString -> IO Handle outputStreamToHandle os0 = do os <- lockingOutputStream os0 h <- H.mkDuplexHandle os "*output-stream*" Nothing $! H.noNewlineTranslation H.hSetBuffering h H.NoBuffering return $! h ------------------------------------------------------------------------------ -- | Converts a pair of 'InputStream' and 'OutputStream' over bytestrings to a -- read-write 'Handle'. -- -- Note: the streams passed into this function are wrapped in -- locking primitives to make them thread-safe. -- -- /Since: 1.0.2.0./ streamPairToHandle :: InputStream ByteString -> OutputStream ByteString -> IO Handle streamPairToHandle is0 os0 = do is <- lockingInputStream is0 os <- lockingOutputStream os0 h <- H.mkDuplexHandle (SP is os) "*stream*" Nothing $! H.noNewlineTranslation H.hSetBuffering h H.NoBuffering return $! h ------------------------------------------------------------------------------ -- | An 'InputStream' for 'IO.stdin'. stdin :: InputStream ByteString stdin = unsafePerformIO (handleToInputStream IO.stdin >>= lockingInputStream) {-# NOINLINE stdin #-} ------------------------------------------------------------------------------ -- | An 'OutputStream' for 'IO.stdout'. stdout :: OutputStream ByteString stdout = unsafePerformIO (handleToOutputStream IO.stdout >>= lockingOutputStream) {-# NOINLINE stdout #-} ------------------------------------------------------------------------------ -- | An 'OutputStream' for 'IO.stderr'. stderr :: OutputStream ByteString stderr = unsafePerformIO (handleToOutputStream IO.stderr >>= lockingOutputStream) {-# NOINLINE stderr #-}