diff --git a/System/Posix/IO.hsc b/System/Posix/IO.hsc index 40cdda4f..c7f4ea28 100644 --- a/System/Posix/IO.hsc +++ b/System/Posix/IO.hsc @@ -63,6 +63,13 @@ module System.Posix.IO ( ) where +import Foreign ( allocaBytes, castPtr ) +import Foreign.C ( peekCStringLen, withCStringLen ) + +import GHC.IO.Exception ( IOErrorType(EOF) ) + +import System.IO.Error ( ioeSetErrorString, mkIOError ) + import System.Posix.Types import System.Posix.Error import System.Posix.IO.Common @@ -88,9 +95,9 @@ openFdAt :: Maybe Fd -- ^ Optional directory file descriptor -> OpenFileFlags -- ^ Append, exclusive, truncate, etc. -> IO Fd openFdAt fdMay name how flags = - withFilePath name $ \str -> - throwErrnoPathIfMinus1Retry "openFdAt" name $ - openat_ fdMay str how flags + withFilePath name $ \str -> + throwErrnoPathIfMinus1Retry "openFdAt" name $ + openat_ fdMay str how flags -- |Create and open this file in WriteOnly mode. A special case of -- 'openFd'. See 'System.Posix.Files' for information on how to use @@ -111,3 +118,25 @@ createFileAt :: Maybe Fd -- ^ Optional directory file descriptor -> IO Fd createFileAt fdMay name mode = openFdAt fdMay name WriteOnly defaultFileFlags{ trunc=True, creat=(Just mode) } + +-- | Read data from an 'Fd' and convert it to a 'String' using the locale encoding. +-- Throws an exception if this is an invalid descriptor, or EOF has been +-- reached. +fdRead :: Fd + -> ByteCount -- ^How many bytes to read + -> IO (String, ByteCount) -- ^The bytes read, how many bytes were read. +fdRead _fd 0 = return ("", 0) +fdRead fd nbytes = + allocaBytes (fromIntegral nbytes) $ \ buf -> do + rc <- fdReadBuf fd buf nbytes + case rc of + 0 -> ioError (ioeSetErrorString (mkIOError EOF "fdRead" Nothing Nothing) "EOF") + n -> do + s <- peekCStringLen (castPtr buf, fromIntegral n) + return (s, n) + +-- | Write a 'String' to an 'Fd' using the locale encoding. +fdWrite :: Fd -> String -> IO ByteCount +fdWrite fd str = + withCStringLen str $ \ (buf,len) -> + fdWriteBuf fd (castPtr buf) (fromIntegral len) diff --git a/System/Posix/IO/ByteString.hsc b/System/Posix/IO/ByteString.hsc index 1d6a904b..4b1e70ab 100644 --- a/System/Posix/IO/ByteString.hsc +++ b/System/Posix/IO/ByteString.hsc @@ -1,4 +1,4 @@ -{-# LANGUAGE Safe #-} +{-# LANGUAGE Trustworthy #-} ----------------------------------------------------------------------------- -- | -- Module : System.Posix.IO.ByteString @@ -63,6 +63,16 @@ module System.Posix.IO.ByteString ( ) where +import Data.ByteString ( ByteString, empty ) +import qualified Data.ByteString.Internal as BI +import qualified Data.ByteString.Unsafe as BU + +import Foreign ( castPtr ) + +import GHC.IO.Exception ( IOErrorType(EOF) ) + +import System.IO.Error ( ioeSetErrorString, mkIOError ) + import System.Posix.Types import System.Posix.IO.Common @@ -88,9 +98,9 @@ openFdAt :: Maybe Fd -- ^ Optional directory file descriptor -> OpenFileFlags -- ^ Append, exclusive, truncate, etc. -> IO Fd openFdAt fdMay name how flags = - withFilePath name $ \str -> - throwErrnoPathIfMinus1Retry "openFdAt" name $ - openat_ fdMay str how flags + withFilePath name $ \str -> + throwErrnoPathIfMinus1Retry "openFdAt" name $ + openat_ fdMay str how flags -- |Create and open this file in WriteOnly mode. A special case of -- 'openFd'. See 'System.Posix.Files' for information on how to use @@ -111,3 +121,23 @@ createFileAt :: Maybe Fd -- ^ Optional directory file descriptor -> IO Fd createFileAt fdMay name mode = openFdAt fdMay name WriteOnly defaultFileFlags{ trunc=True, creat=(Just mode) } + +-- | Read data from an 'Fd' and return it as a 'ByteString'. +-- Throws an exception if this is an invalid descriptor, or EOF has been +-- reached. +fdRead :: Fd + -> ByteCount -- ^How many bytes to read + -> IO ByteString -- ^The bytes read +fdRead _fd 0 = return empty +fdRead fd nbytes = + BI.createUptoN (fromIntegral nbytes) $ \ buf -> do + rc <- fdReadBuf fd buf nbytes + case rc of + 0 -> ioError (ioeSetErrorString (mkIOError EOF "fdRead" Nothing Nothing) "EOF") + n -> return (fromIntegral n) + +-- | Write a 'ByteString' to an 'Fd'. +fdWrite :: Fd -> ByteString -> IO ByteCount +fdWrite fd bs = + BU.unsafeUseAsCStringLen bs $ \ (buf,len) -> + fdWriteBuf fd (castPtr buf) (fromIntegral len) diff --git a/System/Posix/IO/Common.hsc b/System/Posix/IO/Common.hsc index 560be4ed..f8f625b1 100644 --- a/System/Posix/IO/Common.hsc +++ b/System/Posix/IO/Common.hsc @@ -31,7 +31,6 @@ module System.Posix.IO.Common ( -- |Programmers using the 'fdRead' and 'fdWrite' API should be aware that -- EAGAIN exceptions may occur for non-blocking IO! - fdRead, fdWrite, fdReadBuf, fdWriteBuf, -- ** Seeking @@ -447,23 +446,7 @@ waitToSetLock (Fd fd) lock = do #endif // HAVE_F_GETLK -- ----------------------------------------------------------------------------- --- fd{Read,Write} - --- | Read data from an 'Fd' and convert it to a 'String' using the locale encoding. --- Throws an exception if this is an invalid descriptor, or EOF has been --- reached. -fdRead :: Fd - -> ByteCount -- ^How many bytes to read - -> IO (String, ByteCount) -- ^The bytes read, how many bytes were read. -fdRead _fd 0 = return ("", 0) -fdRead fd nbytes = do - allocaBytes (fromIntegral nbytes) $ \ buf -> do - rc <- fdReadBuf fd buf nbytes - case rc of - 0 -> ioError (ioeSetErrorString (mkIOError EOF "fdRead" Nothing Nothing) "EOF") - n -> do - s <- peekCStringLen (castPtr buf, fromIntegral n) - return (s, n) +-- fd{Read,Write}Buf -- | Read data from an 'Fd' into memory. This is exactly equivalent -- to the POSIX @read@ function. @@ -480,12 +463,6 @@ fdReadBuf fd buf nbytes = foreign import ccall safe "read" c_safe_read :: CInt -> Ptr CChar -> CSize -> IO CSsize --- | Write a 'String' to an 'Fd' using the locale encoding. -fdWrite :: Fd -> String -> IO ByteCount -fdWrite fd str = - withCStringLen str $ \ (buf,len) -> - fdWriteBuf fd (castPtr buf) (fromIntegral len) - -- | Write data from memory to an 'Fd'. This is exactly equivalent -- to the POSIX @write@ function. fdWriteBuf :: Fd