module Data.Iteratee.IO.Fd(
#if defined(USE_POSIX)
enumFd
,enumFdCatch
,enumFdRandom
,enumFile
,enumFileRandom
,fileDriverFd
,fileDriverRandomFd
#endif
)
where
#if defined(USE_POSIX)
import Data.Iteratee.Base.ReadableChunk
import Data.Iteratee.Iteratee
import Data.Iteratee.Binary()
import Data.Iteratee.IO.Base
import Control.Concurrent (yield)
import Control.Monad
import Control.Monad.Trans.Control
import Control.Exception.Lifted
import Control.Monad.IO.Class
import Foreign.C.Error
import Foreign.Ptr
import Foreign.Storable
import Foreign.Marshal.Alloc
import System.IO (SeekMode(..))
import "unix-bytestring" System.Posix.IO.ByteString
makefdCallback ::
(MonadIO m, NullPoint s, ReadableChunk s el) =>
Ptr el
-> ByteCount
-> Fd
-> Callback st m s
makefdCallback p bufsize fd st = do
n <- liftIO $ tryFdReadBuf fd (castPtr p) bufsize
case n of
Left (Errno err) -> return $ Left (error $ "read failed: " ++ show err)
Right 0 -> liftIO yield >> return (Right ((Finished, st), empty))
Right n' -> liftM (\s -> Right ((HasMore, st), s)) $
readFromPtr p (fromIntegral n')
enumFd
:: forall s el m a.(NullPoint s, ReadableChunk s el, MonadIO m, MonadBaseControl IO m) =>
Int
-> Fd
-> Enumerator s m a
enumFd bs fd iter =
let bufsize = bs * (sizeOf (undefined :: el))
in bracket (liftIO $ mallocBytes bufsize)
(liftIO . free)
(\p -> enumFromCallback (makefdCallback p (fromIntegral bufsize) fd) () iter)
enumFdCatch
:: forall e s el m a.(IException e, NullPoint s, ReadableChunk s el, MonadIO m, MonadBaseControl IO m)
=> Int
-> Fd
-> (e -> m (Maybe EnumException))
-> Enumerator s m a
enumFdCatch bs fd handler iter =
let bufsize = bs * (sizeOf (undefined :: el))
in bracket (liftIO $ mallocBytes bufsize)
(liftIO . free)
(\p -> enumFromCallbackCatch (makefdCallback p (fromIntegral bufsize) fd) handler () iter)
enumFdRandom
:: forall s el m a.(NullPoint s, ReadableChunk s el, MonadIO m, MonadBaseControl IO m) =>
Int
-> Fd
-> Enumerator s m a
enumFdRandom bs fd iter = enumFdCatch bs fd handler iter
where
handler (SeekException off) =
liftM (either
(const . Just $ enStrExc "Error seeking within file descriptor")
(const Nothing))
. liftIO . tryFdSeek fd AbsoluteSeek $ fromIntegral off
fileDriver
:: (MonadIO m, MonadBaseControl IO m, ReadableChunk s el) =>
(Int -> Fd -> Enumerator s m a)
-> Int
-> Iteratee s m a
-> FilePath
-> m a
fileDriver enumf bufsize iter filepath = bracket
(liftIO $ openFd filepath ReadOnly Nothing defaultFileFlags)
(liftIO . closeFd)
(run <=< flip (enumf bufsize) iter)
fileDriverFd
:: (NullPoint s, MonadIO m, MonadBaseControl IO m, ReadableChunk s el) =>
Int
-> Iteratee s m a
-> FilePath
-> m a
fileDriverFd = fileDriver enumFd
fileDriverRandomFd
:: (NullPoint s, MonadIO m, MonadBaseControl IO m, ReadableChunk s el) =>
Int
-> Iteratee s m a
-> FilePath
-> m a
fileDriverRandomFd = fileDriver enumFdRandom
enumFile' :: (NullPoint s, MonadIO m, MonadBaseControl IO m, ReadableChunk s el) =>
(Int -> Fd -> Enumerator s m a)
-> Int
-> FilePath
-> Enumerator s m a
enumFile' enumf bufsize filepath iter = bracket
(liftIO $ openFd filepath ReadOnly Nothing defaultFileFlags)
(liftIO . closeFd)
(flip (enumf bufsize) iter)
enumFile ::
(NullPoint s, MonadIO m, MonadBaseControl IO m, ReadableChunk s el)
=> Int
-> FilePath
-> Enumerator s m a
enumFile = enumFile' enumFd
enumFileRandom ::
(NullPoint s, MonadIO m, MonadBaseControl IO m, ReadableChunk s el)
=> Int
-> FilePath
-> Enumerator s m a
enumFileRandom = enumFile' enumFdRandom
#endif