packages feed

unix-bytestring 0.3.2.1 → 0.3.3

raw patch · 3 files changed

+423/−152 lines, 3 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

+ System.Posix.IO.ByteString: tryFdPreadBuf :: Fd -> Ptr Word8 -> ByteCount -> FileOffset -> IO (Either Errno ByteCount)
+ System.Posix.IO.ByteString: tryFdPwriteBuf :: Fd -> Ptr Word8 -> ByteCount -> FileOffset -> IO (Either Errno ByteCount)
+ System.Posix.IO.ByteString: tryFdReadBuf :: Fd -> Ptr Word8 -> ByteCount -> IO (Either Errno ByteCount)
+ System.Posix.IO.ByteString: tryFdReadvBuf :: Fd -> Ptr CIovec -> Int -> IO (Either Errno ByteCount)
+ System.Posix.IO.ByteString: tryFdWriteBuf :: Fd -> Ptr Word8 -> ByteCount -> IO (Either Errno ByteCount)
+ System.Posix.IO.ByteString: tryFdWritevBuf :: Fd -> Ptr CIovec -> Int -> IO (Either Errno ByteCount)

Files

src/System/Posix/IO/ByteString.hsc view
@@ -34,26 +34,32 @@     -- *** The POSIX.1 @read(2)@ syscall       fdRead     , fdReadBuf+    , tryFdReadBuf     , fdReads     -- *** The XPG4.2 @readv(2)@ syscall     -- , fdReadv     , fdReadvBuf+    , tryFdReadvBuf     -- *** The XPG4.2 @pread(2)@ syscall     , fdPread     , fdPreadBuf+    , tryFdPreadBuf     , fdPreads          -- ** Writing     -- *** The POSIX.1 @write(2)@ syscall     , fdWrite     , fdWriteBuf+    , tryFdWriteBuf     , fdWrites     -- *** The XPG4.2 @writev(2)@ syscall     , fdWritev     , fdWritevBuf+    , tryFdWritevBuf     -- *** The XPG4.2 @pwrite(2)@ syscall     , fdPwrite     , fdPwriteBuf+    , tryFdPwriteBuf     ) where  import           Data.Word                (Word8)@@ -62,21 +68,17 @@ import qualified Data.ByteString.Unsafe   as BSU  import qualified System.IO.Error          as IOE-{---- /N.B./, hsc2hs doesn't like this...-#if (MIN_VERSION_unix(2,4,0))-import           System.Posix.IO          (fdReadBuf, fdWriteBuf)-#endif--} import           System.Posix.Types.Iovec import           System.Posix.Types       (Fd, ByteCount, FileOffset                                           , CSsize, COff) import           Foreign.C.Types          (CInt, CSize, CChar)-import qualified Foreign.C.Error          as FFI (throwErrnoIfMinus1Retry)-import           Foreign.Ptr              (Ptr)-import qualified Foreign.Ptr              as FFI (castPtr, plusPtr)+import qualified Foreign.C.Error          as C+import           Foreign.Ptr              (Ptr, castPtr, plusPtr) import qualified Foreign.Marshal.Array    as FMA (withArrayLen) +-- For the functor instance of 'Either', aka 'right' for ArrowChoice(->)+import Control.Arrow (ArrowChoice(..))+ -- iovec, writev, and readv are in <sys/uio.h>, but we must include -- <sys/types.h> and <unistd.h> for legacy reasons. #include <sys/types.h>@@ -93,58 +95,108 @@             "EOF")  +-- | A variant of 'C.throwErrnoIfMinus1Retry' which returns 'Either'+-- instead of throwing an errno error.+eitherErrnoIfMinus1Retry :: (Num a) => IO a -> IO (Either C.Errno a)+eitherErrnoIfMinus1Retry = eitherErrnoIfRetry (-1 ==)+++-- | A variant of 'C.throwErrnoIfRetry' which returns 'Either'+-- instead of throwing an errno error.+eitherErrnoIfRetry :: (a -> Bool) -> IO a -> IO (Either C.Errno a)+eitherErrnoIfRetry p io = loop+    where+    loop = do+        a <- io+        if p a+            then do+                errno <- C.getErrno+                if errno == C.eINTR+                    then loop+                    else return (Left errno)+            else return (Right a)+ ------------------------------------------------------------------- /N.B./, hsc2hs doesn't like this...--- #if ! (MIN_VERSION_unix(2,4,0))--- This version was copied from unix-2.4.2.0+foreign import ccall safe "read"+    -- ssize_t read(int fildes, void *buf, size_t nbyte);+    c_safe_read :: CInt -> Ptr CChar -> CSize -> IO CSsize++ -- | Read data from an 'Fd' into memory. This is exactly equivalent--- to the POSIX.1 @read(2)@ system call.+-- to the POSIX.1 @read(2)@ system call, except that we return 0+-- bytes read if the @ByteCount@ argument is less than or equal to+-- zero (instead of throwing an errno exception). /N.B./, this+-- behavior is different from the version in @unix-2.4.2.0@ which+-- only checks for equality to zero. If there are any errors, then+-- they are thrown as 'IOE.IOError' exceptions. ----- TODO: better documentation.+-- /Since: 0.3.0/ fdReadBuf     :: Fd     -> Ptr Word8    -- ^ Memory in which to put the data.     -> ByteCount    -- ^ How many bytes to try to read.     -> IO ByteCount -- ^ How many bytes were actually read (zero for EOF).-fdReadBuf _  _   0      = return 0-fdReadBuf fd buf nbytes = -    fmap fromIntegral-        $ FFI.throwErrnoIfMinus1Retry-            "System.Posix.IO.ByteString.fdReadBuf"-            $ c_safe_read-                (fromIntegral fd)-                (FFI.castPtr  buf)-                (fromIntegral nbytes)+fdReadBuf fd buf nbytes+    | nbytes <= 0 = return 0+    | otherwise   =+        fmap fromIntegral+            $ C.throwErrnoIfMinus1Retry _fdReadBuf+                $ c_safe_read+                    (fromIntegral fd)+                    (castPtr buf)+                    (fromIntegral nbytes) -foreign import ccall safe "read"-    -- ssize_t read(int fildes, void *buf, size_t nbyte);-    c_safe_read :: CInt -> Ptr CChar -> CSize -> IO CSsize--- #endif+_fdReadBuf :: String+_fdReadBuf = "System.Posix.IO.ByteString.fdReadBuf"+{-# NOINLINE _fdReadBuf #-}  +-- | Read data from an 'Fd' into memory. This is a variation of+-- 'fdReadBuf' which returns errors with an 'Either' instead of+-- throwing exceptions.+--+-- /Since: 0.3.3/+tryFdReadBuf+    :: Fd+    -> Ptr Word8    -- ^ Memory in which to put the data.+    -> ByteCount    -- ^ How many bytes to try to read.+    -> IO (Either C.Errno ByteCount)+        -- ^ How many bytes were actually read (zero for EOF).+tryFdReadBuf fd buf nbytes+    | nbytes <= 0 = return (Right 0)+    | otherwise   =+        fmap (right fromIntegral)+            $ eitherErrnoIfMinus1Retry+                $ c_safe_read+                    (fromIntegral fd)+                    (castPtr buf)+                    (fromIntegral nbytes)++ ---------------------------------------------------------------- -- | Read data from an 'Fd' and convert it to a 'BS.ByteString'. -- Throws an exception if this is an invalid descriptor, or EOF has--- been reached.------ This is essentially equivalent to the POSIX.1 @read(2)@ system--- call; the differences are that we allocate a byte buffer for the--- @ByteString@ (and then pass its underlying @Ptr Word8@ and--- @ByteCount@ components to 'fdReadBuf'), and that we detect EOF--- and throw an 'IOE.IOError'.+-- been reached. This is essentially equivalent to 'fdReadBuf'; the+-- differences are that we allocate a byte buffer for the @ByteString@,+-- and that we detect EOF and throw an 'IOE.IOError'. fdRead     :: Fd     -> ByteCount        -- ^ How many bytes to try to read.     -> IO BS.ByteString -- ^ The bytes read.-fdRead _  0 = return BS.empty-fdRead fd n =-    BSI.createAndTrim (fromIntegral n) $ \buf -> do-        rc <- fdReadBuf fd buf n-        if 0 == rc-            then ioErrorEOF "System.Posix.IO.ByteString.fdRead"-            else return (fromIntegral rc)+fdRead fd nbytes+    | nbytes <= 0 = return BS.empty+    | otherwise   = +        BSI.createAndTrim (fromIntegral nbytes) $ \buf -> do+            rc <- fdReadBuf fd buf nbytes+            if 0 == rc+                then ioErrorEOF _fdRead+                else return (fromIntegral rc) +_fdRead :: String+_fdRead = "System.Posix.IO.ByteString.fdRead"+{-# NOINLINE _fdRead #-} + ---------------------------------------------------------------- -- | Read data from an 'Fd' and convert it to a 'BS.ByteString'. -- Throws an exception if this is an invalid descriptor, or EOF has@@ -163,9 +215,7 @@ -- we can use: -- -- > fdReadUptoNTimes :: Int -> Fd -> ByteCount -> IO ByteString--- > fdReadUptoNTimes n0--- >     | n0 <= 0   = \_ _ -> return empty--- >     | otherwise = fdReads retry n0+-- > fdReadUptoNTimes n0 = fdReads retry n0 -- >     where -- >     retry _ 0 = Nothing -- >     retry _ n = Just $! n-1@@ -176,111 +226,223 @@ -- would allocate a buffer, trim it to the number of bytes read, -- and then concatenate with the previous one (another allocation, -- plus copying everything over) for each time around the loop.+--+-- /Since: 0.2.1/ fdReads     :: (ByteCount -> a -> Maybe a) -- ^ A stateful predicate for retrying.     -> a                           -- ^ An initial state for the predicate.     -> Fd     -> ByteCount                   -- ^ How many bytes to try to read.     -> IO BS.ByteString            -- ^ The bytes read.-fdReads _ _  _  0  = return BS.empty-fdReads f z0 fd n0 = BSI.createAndTrim (fromIntegral n0) (go z0 0 n0)+fdReads f z0 fd n0+    | n0 <= 0   = return BS.empty+    | otherwise = BSI.createAndTrim (fromIntegral n0) (go z0 0 n0)     where     go _ len n buf | len `seq` n `seq` buf `seq` False = undefined     go z len n buf = do         rc <- fdReadBuf fd buf n         let len' = len + rc         case rc of-          _ | rc == 0 -> ioErrorEOF "System.Posix.IO.ByteString.fdReads"+          _ | rc == 0 -> ioErrorEOF _fdReads             | rc == n -> return (fromIntegral len') -- Finished.             | otherwise ->                 case f len' z of                 Nothing -> return (fromIntegral len') -- Gave up.                 Just z' ->-                    go z' len' (n - rc) (buf `FFI.plusPtr` fromIntegral rc)+                    go z' len' (n - rc) (buf `plusPtr` fromIntegral rc) +_fdReads :: String+_fdReads = "System.Posix.IO.ByteString.fdReads"+{-# NOINLINE _fdReads #-} + ----------------------------------------------------------------+foreign import ccall safe "readv"+    -- ssize_t readv(int fildes, const struct iovec *iov, int iovcnt);+    c_safe_readv :: CInt -> Ptr CIovec -> CInt -> IO CSsize+{-+-- N.B., c_safe_readv will throw errno=EINVAL+-- if iovcnt <= 0 || > 16,+-- if one of the iov_len values in the iov array was negative,+-- if the sum of the iov_len values in the iov array overflowed a 32-bit integer.+    +fdReadvBufSafe :: Fd -> Ptr CIovec -> Int -> IO ByteCount+fdReadvBufSafe fd = go 0+    where+    go rc bufs len+        | len <= 0  = return rc+        | otherwise = do+            m <- checkIovecs bufs (min 16 len)+            case m of+                Nothing                 -> error+                Just (bufs', l, nbytes) -> do+                    rc' <- fdReadvBuf fd bufs l+                    if rc' == nbytes+                        then go (rc+rc') bufs' (len-l)+                        else return (rc+rc')++checkIovecs :: Ptr CIovec -> Int -> IO (Maybe (Ptr CIovec, Int, ByteCount))+checkIovecs = go (0 :: Int32) 0+    where+    go nbytes n p len+        | nbytes `seq` n `seq` p `seq` len `seq` False = undefined+        | len == 0  = return (Just (p, n, fromIntegral nbytes)+        | otherwise = do+            l <- iov_len <$> peek p+            if l < 0+                then return Nothing+                else do+                    let nbytes' = nbytes+l+                    if nbytes' < 0+                        then return (Just (p, n, fromIntegral nbytes)+                        else go nbytes' (n+1) (p++) (len-1)+-}++ -- | Read data from an 'Fd' and scatter it into memory. This is--- exactly equivalent to the XPG4.2 @readv(2)@ system call.+-- exactly equivalent to the XPG4.2 @readv(2)@ system call, except+-- that we return 0 bytes read if the @Int@ argument is less than+-- or equal to zero (instead of throwing an 'C.eINVAL' exception).+-- If there are any errors, then they are thrown as 'IOE.IOError'+-- exceptions. -- -- TODO: better documentation.+--+-- /Since: 0.3.0/ fdReadvBuf     :: Fd     -> Ptr CIovec   -- ^ A C-style array of buffers to fill.     -> Int          -- ^ How many buffers there are.     -> IO ByteCount -- ^ How many bytes were actually read (zero for EOF).-fdReadvBuf _  _    0   = return 0-fdReadvBuf fd bufs len =-    fmap fromIntegral-        $ FFI.throwErrnoIfMinus1Retry-            "System.Posix.IO.ByteString.fdReadvBuf"-            $ c_safe_readv (fromIntegral fd) bufs (fromIntegral len)+fdReadvBuf fd bufs len+    | len <= 0  = return 0+    | otherwise =+        fmap fromIntegral+            $ C.throwErrnoIfMinus1Retry _fdReadvBuf+                $ c_safe_readv (fromIntegral fd) bufs (fromIntegral len) -foreign import ccall safe "readv"-    -- ssize_t readv(int fildes, const struct iovec *iov, int iovcnt);-    c_safe_readv :: CInt -> Ptr CIovec -> CInt -> IO CSsize+_fdReadvBuf :: String+_fdReadvBuf = "System.Posix.IO.ByteString.fdReadvBuf"+{-# NOINLINE _fdReadvBuf #-}  +-- | Read data from an 'Fd' and scatter it into memory. This is a+-- variation of 'fdReadvBuf' which returns errors with an 'Either'+-- instead of throwing exceptions.+--+-- /Since: 0.3.3/+tryFdReadvBuf+    :: Fd+    -> Ptr CIovec   -- ^ A C-style array of buffers to fill.+    -> Int          -- ^ How many buffers there are.+    -> IO (Either C.Errno ByteCount)+        -- ^ How many bytes were actually read (zero for EOF).+tryFdReadvBuf fd bufs len+    | len <= 0  = return (Right 0)+    | otherwise =+        fmap (right fromIntegral)+            $ eitherErrnoIfMinus1Retry+                $ c_safe_readv (fromIntegral fd) bufs (fromIntegral len)++ -- TODO: What's a reasonable wrapper for fdReadvBuf to make it Haskellish?  ----------------------------------------------------------------+foreign import ccall safe "pread"+    -- ssize_t pread(int fildes, void *buf, size_t nbyte, off_t offset);+    c_safe_pread :: CInt -> Ptr Word8 -> CSize -> COff -> IO CSsize++ -- | Read data from a specified position in the 'Fd' into memory, -- without altering the position stored in the @Fd@. This is exactly--- equivalent to the XPG4.2 @pread(2)@ system call.+-- equivalent to the XPG4.2 @pread(2)@ system call, except that we+-- return 0 bytes read if the @Int@ argument is less than or equal+-- to zero (instead of throwing an errno exception). If there are+-- any errors, then they are thrown as 'IOE.IOError' exceptions. ----- TODO: better documentation.+-- /Since: 0.3.0/ fdPreadBuf     :: Fd     -> Ptr Word8    -- ^ Memory in which to put the data.     -> ByteCount    -- ^ How many bytes to try to read.     -> FileOffset   -- ^ Where to read the data from.     -> IO ByteCount -- ^ How many bytes were actually read (zero for EOF).-fdPreadBuf _  _   0      _      = return 0-fdPreadBuf fd buf nbytes offset =-    fmap fromIntegral-        $ FFI.throwErrnoIfMinus1Retry-            "System.Posix.IO.ByteString.fdPreadBuf"-            $ c_safe_pread-                (fromIntegral fd)-                (FFI.castPtr  buf)-                (fromIntegral nbytes)-                (fromIntegral offset)+fdPreadBuf fd buf nbytes offset+    | nbytes <= 0 = return 0+    | otherwise   =+        fmap fromIntegral+            $ C.throwErrnoIfMinus1Retry _fdPreadBuf+                $ c_safe_pread+                    (fromIntegral fd)+                    buf+                    (fromIntegral nbytes)+                    (fromIntegral offset) -foreign import ccall safe "pread"-    -- ssize_t pread(int fildes, void *buf, size_t nbyte, off_t offset);-    c_safe_pread :: CInt -> Ptr Word8 -> CSize -> COff -> IO CSsize+_fdPreadBuf :: String+_fdPreadBuf = "System.Posix.IO.ByteString.fdPreadBuf"+{-# NOINLINE _fdPreadBuf #-}  +-- | Read data from a specified position in the 'Fd' into memory,+-- without altering the position stored in the @Fd@. This is a+-- variation of 'fdPreadBuf' which returns errors with an 'Either'+-- instead of throwing exceptions.+--+-- /Since: 0.3.3/+tryFdPreadBuf+    :: Fd+    -> Ptr Word8    -- ^ Memory in which to put the data.+    -> ByteCount    -- ^ How many bytes to try to read.+    -> FileOffset   -- ^ Where to read the data from.+    -> IO (Either C.Errno ByteCount)+        -- ^ How many bytes were actually read (zero for EOF).+tryFdPreadBuf fd buf nbytes offset+    | nbytes <= 0 = return (Right 0)+    | otherwise   =+        fmap (right fromIntegral)+            $ eitherErrnoIfMinus1Retry+                $ c_safe_pread+                    (fromIntegral fd)+                    buf+                    (fromIntegral nbytes)+                    (fromIntegral offset)+ ---------------------------------------------------------------- -- | Read data from a specified position in the 'Fd' and convert -- it to a 'BS.ByteString', without altering the position stored -- in the @Fd@. Throws an exception if this is an invalid descriptor,--- or EOF has been reached.+-- or EOF has been reached. This is essentially equivalent to+-- 'fdPreadBuf'; the differences are that we allocate a byte buffer+-- for the @ByteString@, and that we detect EOF and throw an+-- 'IOE.IOError'. ----- This is essentially equivalent to the XPG4.2 @pread(2)@ system--- call; the differences are that we allocate a byte buffer for the--- @ByteString@ (and then pass its underlying @Ptr Word8@ and--- @ByteCount@ components to 'fdPreadBuf'), and that we detect EOF--- and throw an 'IOE.IOError'.+-- /Since: 0.3.0/ fdPread     :: Fd     -> ByteCount        -- ^ How many bytes to try to read.     -> FileOffset       -- ^ Where to read the data from.     -> IO BS.ByteString -- ^ The bytes read.-fdPread _  0 _      = return BS.empty-fdPread fd n offset =-    BSI.createAndTrim (fromIntegral n) $ \buf -> do-        rc <- fdPreadBuf fd buf n offset-        if 0 == rc-            then ioErrorEOF "System.Posix.IO.ByteString.fdPread"-            else return (fromIntegral rc)+fdPread fd nbytes offset+    | nbytes <= 0 = return BS.empty+    | otherwise   =+        BSI.createAndTrim (fromIntegral nbytes) $ \buf -> do+            rc <- fdPreadBuf fd buf nbytes offset+            if 0 == rc+                then ioErrorEOF _fdPread+                else return (fromIntegral rc) +_fdPread :: String+_fdPread = "System.Posix.IO.ByteString.fdPread"+{-# NOINLINE _fdPread #-}+ ---------------------------------------------------------------- -- | Read data from a specified position in the 'Fd' and convert -- it to a 'BS.ByteString', without altering the position stored -- in the @Fd@. Throws an exception if this is an invalid descriptor,--- or EOF has been reached. This is a @pread(2)@ based version of--- 'fdReads'; see that function for more details.+-- or EOF has been reached. This is a 'fdPreadBuf' based version+-- of 'fdReads'; see those functions for more details.+--+-- /Since: 0.3.1/ fdPreads     :: (ByteCount -> a -> Maybe a) -- ^ A stateful predicate for retrying.     -> a                           -- ^ An initial state for the predicate.@@ -288,57 +450,90 @@     -> ByteCount                   -- ^ How many bytes to try to read.     -> FileOffset                  -- ^ Where to read the data from.     -> IO BS.ByteString            -- ^ The bytes read.-fdPreads _ _  _  0  _      = return BS.empty-fdPreads f z0 fd n0 offset = BSI.createAndTrim (fromIntegral n0) (go z0 0 n0)+fdPreads f z0 fd n0 offset+    | n0 <= 0   = return BS.empty+    | otherwise = BSI.createAndTrim (fromIntegral n0) (go z0 0 n0)     where     go _ len n buf | len `seq` n `seq` buf `seq` False = undefined     go z len n buf = do         rc <- fdPreadBuf fd buf n (offset + fromIntegral len)         let len' = len + rc         case rc of-          _ | rc == 0 -> ioErrorEOF "System.Posix.IO.ByteString.fdPreads"+          _ | rc == 0 -> ioErrorEOF _fdPreads             | rc == n -> return (fromIntegral len') -- Finished.             | otherwise ->                 case f len' z of                 Nothing -> return (fromIntegral len') -- Gave up.                 Just z' ->-                    go z' len' (n - rc) (buf `FFI.plusPtr` fromIntegral rc)+                    go z' len' (n - rc) (buf `plusPtr` fromIntegral rc) +_fdPreads :: String+_fdPreads = "System.Posix.IO.ByteString.fdPreads"+{-# NOINLINE _fdPreads #-}+ ---------------------------------------------------------------- ------------------------------------------------------------------- /N.B./, hsc2hs doesn't like this...--- #if ! (MIN_VERSION_unix(2,4,0))--- This version was copied from unix-2.4.2.0+foreign import ccall safe "write" +    -- ssize_t write(int fildes, const void *buf, size_t nbyte);+    c_safe_write :: CInt -> Ptr CChar -> CSize -> IO CSsize++ -- | Write data from memory to an 'Fd'. This is exactly equivalent--- to the POSIX.1 @write(2)@ system call.+-- to the POSIX.1 @write(2)@ system call, except that we return 0+-- bytes written if the @ByteCount@ argument is less than or equal+-- to zero (instead of throwing an errno exception). /N.B./, this+-- behavior is different from the version in @unix-2.4.2.0@ which+-- doesn't check the byte count. If there are any errors, then they+-- are thrown as 'IOE.IOError' exceptions. ----- TODO: better documentation.+-- /Since: 0.3.0/ fdWriteBuf     :: Fd     -> Ptr Word8    -- ^ Memory containing the data to write.     -> ByteCount    -- ^ How many bytes to try to write.     -> IO ByteCount -- ^ How many bytes were actually written.-fdWriteBuf fd buf nbytes =-    fmap fromIntegral-        $ FFI.throwErrnoIfMinus1Retry-            "System.Posix.IO.ByteString.fdWriteBuf"-            $ c_safe_write-                (fromIntegral fd)-                (FFI.castPtr  buf)-                (fromIntegral nbytes)+fdWriteBuf fd buf nbytes+    | nbytes <= 0 = return 0+    | otherwise   = +        fmap fromIntegral+            $ C.throwErrnoIfMinus1Retry _fdWriteBuf+                $ c_safe_write+                    (fromIntegral fd)+                    (castPtr buf)+                    (fromIntegral nbytes) -foreign import ccall safe "write" -    -- ssize_t write(int fildes, const void *buf, size_t nbyte);-    c_safe_write :: CInt -> Ptr CChar -> CSize -> IO CSsize--- #endif+_fdWriteBuf :: String+_fdWriteBuf = "System.Posix.IO.ByteString.fdWriteBuf"+{-# NOINLINE _fdWriteBuf #-}  +-- | Write data from memory to an 'Fd'. This is a variation of+-- 'fdWriteBuf' which returns errors with an 'Either' instead of+-- throwing exceptions.+--+-- /Since: 0.3.3/+tryFdWriteBuf+    :: Fd+    -> Ptr Word8    -- ^ Memory containing the data to write.+    -> ByteCount    -- ^ How many bytes to try to write.+    -> IO (Either C.Errno ByteCount)+        -- ^ How many bytes were actually read (zero for EOF).+tryFdWriteBuf fd buf nbytes+    | nbytes <= 0 = return (Right 0)+    | otherwise   =+        fmap (right fromIntegral)+            $ eitherErrnoIfMinus1Retry+                $ c_safe_write+                    (fromIntegral fd)+                    (castPtr buf)+                    (fromIntegral nbytes)+ ---------------------------------------------------------------- -- | Write a 'BS.ByteString' to an 'Fd'. The return value is the -- total number of bytes actually written. This is exactly equivalent--- to the POSIX.1 @write(2)@ system call; we just convert the--- @ByteString@ into its underlying @Ptr Word8@ and @ByteCount@--- components for passing to 'fdWriteBuf'.+-- to 'fdWriteBuf'; we just convert the @ByteString@ into its+-- underlying @Ptr Word8@ and @ByteCount@ components for passing+-- to 'fdWriteBuf'. fdWrite     :: Fd     -> BS.ByteString -- ^ The string to write.@@ -348,7 +543,7 @@     -- BS.useAsCStringLen if there's any chance fdWriteBuf might     -- alter the buffer.     BSU.unsafeUseAsCStringLen s $ \(buf,len) -> do-        fdWriteBuf fd (FFI.castPtr buf) (fromIntegral len)+        fdWriteBuf fd (castPtr buf) (fromIntegral len)   ----------------------------------------------------------------@@ -360,11 +555,11 @@ -- (i.e., removing the bytes already written) in case there is some -- semantic significance to the way the input is split into chunks. ----- This version consumes the list lazily and will call the @write(2)@--- system call once for each @ByteString@. This laziness allows the--- early parts of the list to be garbage collected and prevents--- needing to hold the whole list of @ByteString@s in memory at--- once. Compare against 'fdWritev'.+-- This version consumes the list lazily and will call 'fdWrite'+-- once for each @ByteString@, thus making /O(n)/ system calls.+-- This laziness allows the early parts of the list to be garbage+-- collected and prevents needing to hold the whole list of+-- @ByteString@s in memory at once. Compare against 'fdWritev'. fdWrites     :: Fd     -> [BS.ByteString]@@ -388,36 +583,74 @@   ----------------------------------------------------------------+foreign import ccall safe "writev"+    -- ssize_t writev(int fildes, const struct iovec *iov, int iovcnt);+    c_safe_writev :: CInt -> Ptr CIovec -> CInt -> IO CSsize+{-+-- N.B., c_safe_readv will throw errno=EINVAL+-- if iovcnt is less than or equal to 0, or greater than UIO_MAXIOV. (BUG: I have no idea where UIO_MAXIOV is defined! The web says it's in <linux/uio.h>, and some suggest using <limits.h>IOV_MAX or <limits.h>_XOPEN_IOV_MAX instead.)+-- <http://www.mail-archive.com/freebsd-current@freebsd.org/msg27878.html>+-- <http://www.mail-archive.com/naviserver-devel@lists.sourceforge.net/msg02237.html>+-- -- That last link says that glibc might transparently chop up larger values before sending to the kernel.+-- if one of the iov_len values in the iov array is negative.+-- if the sum of the iov_len values in the iov array overflows a 32-bit integer.+-}++ -- | Write data from memory to an 'Fd'. This is exactly equivalent--- to the XPG4.2 @writev(2)@ system call.+-- to the XPG4.2 @writev(2)@ system call, except that we return 0+-- bytes written if the @Int@ argument is less than or equal to+-- zero (instead of throwing an 'C.eINVAL' exception). If there are+-- any errors, then they are thrown as 'IOE.IOError' exceptions. -- -- TODO: better documentation.+--+-- /Since: 0.3.0/ fdWritevBuf     :: Fd     -> Ptr CIovec   -- ^ A C-style array of buffers to write.     -> Int          -- ^ How many buffers there are.     -> IO ByteCount -- ^ How many bytes were actually written.-fdWritevBuf _  _    0   = return 0-fdWritevBuf fd bufs len =-    fmap fromIntegral-        $ FFI.throwErrnoIfMinus1Retry-            "System.Posix.IO.ByteString.fdWritevBuf"-            $ c_safe_writev (fromIntegral fd) bufs (fromIntegral len)+fdWritevBuf fd bufs len+    | len <= 0  = return 0+    | otherwise =+        fmap fromIntegral+            $ C.throwErrnoIfMinus1Retry _fdWritevBuf+                $ c_safe_writev (fromIntegral fd) bufs (fromIntegral len) -foreign import ccall safe "writev"-    -- ssize_t writev(int fildes, const struct iovec *iov, int iovcnt);-    c_safe_writev :: CInt -> Ptr CIovec -> CInt -> IO CSsize+_fdWritevBuf :: String+_fdWritevBuf = "System.Posix.IO.ByteString.fdWritevBuf"+{-# NOINLINE _fdWritevBuf #-}  +-- | Write data from memory to an 'Fd'. This is a variation of+-- 'fdWritevBuf' which returns errors with an 'Either' instead of+-- throwing exceptions.+--+-- /Since: 0.3.3/+tryFdWritevBuf+    :: Fd+    -> Ptr CIovec   -- ^ A C-style array of buffers to write.+    -> Int          -- ^ How many buffers there are.+    -> IO (Either C.Errno ByteCount)+        -- ^ How many bytes were actually read (zero for EOF).+tryFdWritevBuf fd bufs len+    | len <= 0  = return (Right 0)+    | otherwise =+        fmap (right fromIntegral)+            $ eitherErrnoIfMinus1Retry+                $ c_safe_writev (fromIntegral fd) bufs (fromIntegral len)++ ---------------------------------------------------------------- -- | Write a sequence of 'BS.ByteString's to an 'Fd'. The return -- value is the total number of bytes written. Unfortunately the -- @writev(2)@ system call does not provide enough information to -- return the triple that 'fdWrites' does. ----- This version will force the spine of the list, convert each--- @ByteString@ into an @iovec@, and then call the @writev(2)@--- system call. This means we only make one system call, which+-- This version will force the spine of the list, converting each+-- @ByteString@ into an @iovec@ (see 'CIovec'), and then call+-- 'fdWritevBuf'. This means we only make one system call, which -- reduces the overhead of performing context switches. But it also -- means that we must store the whole list of @ByteString@s in -- memory at once, and that we must perform some allocation and@@ -435,39 +668,75 @@   ----------------------------------------------------------------+foreign import ccall safe "pwrite"+    -- ssize_t pwrite(int fildes, const void *buf, size_t nbyte, off_t offset);+    c_safe_pwrite :: CInt -> Ptr Word8 -> CSize -> COff -> IO CSsize++ -- | Write data from memory to a specified position in the 'Fd', -- but without altering the position stored in the @Fd@. This is--- exactly equivalent to the XPG4.2 @pwrite(2)@ system call.+-- exactly equivalent to the XPG4.2 @pwrite(2)@ system call, except+-- that we return 0 bytes written if the @ByteCount@ argument is+-- less than or equal to zero (instead of throwing an errno exception).+-- If there are any errors, then they are thrown as 'IOE.IOError'+-- exceptions. ----- TODO: better documentation.+-- /Since: 0.3.0/ fdPwriteBuf     :: Fd     -> Ptr Word8    -- ^ Memory containing the data to write.     -> ByteCount    -- ^ How many bytes to try to write.     -> FileOffset   -- ^ Where to write the data to.     -> IO ByteCount -- ^ How many bytes were actually written.-fdPwriteBuf _  _   0      _      = return 0-fdPwriteBuf fd buf nbytes offset =-    fmap fromIntegral-        $ FFI.throwErrnoIfMinus1Retry-            "System.Posix.IO.ByteString.fdPwriteBuf"-            $ c_safe_pwrite-                (fromIntegral fd)-                (FFI.castPtr  buf)-                (fromIntegral nbytes)-                (fromIntegral offset)+fdPwriteBuf fd buf nbytes offset+    | nbytes <= 0 = return 0+    | otherwise   =+        fmap fromIntegral+            $ C.throwErrnoIfMinus1Retry _fdPwriteBuf+                $ c_safe_pwrite+                    (fromIntegral fd)+                    (castPtr buf)+                    (fromIntegral nbytes)+                    (fromIntegral offset) -foreign import ccall safe "pwrite"-    -- ssize_t pwrite(int fildes, const void *buf, size_t nbyte, off_t offset);-    c_safe_pwrite :: CInt -> Ptr Word8 -> CSize -> COff -> IO CSsize+_fdPwriteBuf :: String+_fdPwriteBuf = "System.Posix.IO.ByteString.fdPwriteBuf"+{-# NOINLINE _fdPwriteBuf #-}  +-- | Write data from memory to a specified position in the 'Fd',+-- but without altering the position stored in the @Fd@. This is a+-- variation of 'fdPwriteBuf' which returns errors with an 'Either'+-- instead of throwing exceptions.+--+-- /Since: 0.3.3/+tryFdPwriteBuf+    :: Fd+    -> Ptr Word8    -- ^ Memory containing the data to write.+    -> ByteCount    -- ^ How many bytes to try to write.+    -> FileOffset   -- ^ Where to write the data to.+    -> IO (Either C.Errno ByteCount)+        -- ^ How many bytes were actually written.+tryFdPwriteBuf fd buf nbytes offset+    | nbytes <= 0 = return (Right 0)+    | otherwise   =+        fmap (right fromIntegral)+            $ eitherErrnoIfMinus1Retry+                $ c_safe_pwrite+                    (fromIntegral fd)+                    (castPtr buf)+                    (fromIntegral nbytes)+                    (fromIntegral offset)++ ---------------------------------------------------------------- -- | Write data from memory to a specified position in the 'Fd', -- but without altering the position stored in the @Fd@. This is--- exactly equivalent to the XPG4.2 @pwrite(2)@ system call; we--- just convert the @ByteString@ into its underlying @Ptr Word8@--- and @ByteCount@ components for passing to 'fdPwriteBuf'.+-- exactly equivalent to 'fdPwriteBuf'; we just convert the+-- @ByteString@ into its underlying @Ptr Word8@ and @ByteCount@+-- components for passing to 'fdPwriteBuf'.+--+-- /Since: 0.3.0/ fdPwrite     :: Fd     -> BS.ByteString -- ^ The string to write.@@ -478,7 +747,7 @@     -- BS.useAsCStringLen if there's any chance fdPwriteBuf might     -- alter the buffer.     BSU.unsafeUseAsCStringLen s $ \(buf,len) -> do-        fdPwriteBuf fd (FFI.castPtr buf) (fromIntegral len) offset+        fdPwriteBuf fd (castPtr buf) (fromIntegral len) offset  ---------------------------------------------------------------- ----------------------------------------------------------- fin.
src/System/Posix/IO/ByteString/Lazy.hs view
@@ -57,6 +57,8 @@ -- in the @Fd@. Throws an exception if this is an invalid descriptor, -- or EOF has been reached. This is a thin wrapper around -- 'PosixBS.fdPread'.+--+-- /Since: 0.3.1/ fdPread     :: Fd     -> ByteCount        -- ^ How many bytes to try to read.
unix-bytestring.cabal view
@@ -1,9 +1,9 @@ ------------------------------------------------------------------- wren ng thornton <wren@community.haskell.org>    ~ 2011.03.17+-- wren ng thornton <wren@community.haskell.org>    ~ 2011.03.26 ----------------------------------------------------------------  Name:           unix-bytestring-Version:        0.3.2.1+Version:        0.3.3 -- Source-Repository requires version 1.6 Cabal-Version:  >= 1.6 -- We need a custom build in order to define __HADDOCK__