Update readDirStream to use Maybe readdirstream-maybe-patch
authorEric Mertens <emertens@galois.com>
Wed, 7 Dec 2016 07:22:53 +0000 (23:22 -0800)
committerEric Mertens <emertens@galois.com>
Wed, 7 Dec 2016 07:22:53 +0000 (23:22 -0800)
This patch changes `readDirStream` to signal end of directory with a
Nothing value. In addition it changes the wrapped readdir function to
only return -1 in the case of an actual error. This change allows the
errno handling logic to take advantage of helpers from Foreign.C.Error,
simplifying the logic.

Fixes #81

System/Posix/Directory.hsc
System/Posix/Directory/ByteString.hsc
cbits/HsUnix.c
changelog.md

index 10dcbb4..7273f30 100644 (file)
@@ -87,28 +87,18 @@ foreign import capi unsafe "HsUnix.h opendir"
 -- | @readDirStream dp@ calls @readdir@ to obtain the
 --   next directory entry (@struct dirent@) for the open directory
 --   stream @dp@, and returns the @d_name@ member of that
---  structure.
-readDirStream :: DirStream -> IO FilePath
+--  structure. 'Nothing' is returned upon reaching the end
+--  of the directory.
+readDirStream :: DirStream -> IO (Maybe FilePath)
 readDirStream (DirStream dirp) =
-  alloca $ \ptr_dEnt  -> loop ptr_dEnt
- where
-  loop ptr_dEnt = do
-    resetErrno
-    r <- c_readdir dirp ptr_dEnt
-    if (r == 0)
-         then do dEnt <- peek ptr_dEnt
-                 if (dEnt == nullPtr)
-                    then return []
-                    else do
-                     entry <- (d_name dEnt >>= peekFilePath)
-                     c_freeDirEnt dEnt
-                     return entry
-         else do errno <- getErrno
-                 if (errno == eINTR) then loop ptr_dEnt else do
-                 let (Errno eo) = errno
-                 if (eo == 0)
-                    then return []
-                    else throwErrno "readDirStream"
+  alloca $ \ptr_dEnt ->
+    do throwErrnoIfMinus1Retry_ "readdir" (c_readdir dirp ptr_dEnt)
+       dEnt <- peek ptr_dEnt
+       if dEnt == nullPtr
+         then return Nothing
+         else do entry <- peekFilePath =<< d_name dEnt
+                 c_freeDirEnt dEnt
+                 return (Just entry)
 
 -- traversing directories
 foreign import ccall unsafe "__hscore_readdir"
index b5ea462..dc03212 100644 (file)
@@ -88,28 +88,18 @@ foreign import capi unsafe "HsUnix.h opendir"
 -- | @readDirStream dp@ calls @readdir@ to obtain the
 --   next directory entry (@struct dirent@) for the open directory
 --   stream @dp@, and returns the @d_name@ member of that
---  structure.
-readDirStream :: DirStream -> IO RawFilePath
+--  structure. 'Nothing' is returned upon reaching the end
+--  of the directory.
+readDirStream :: DirStream -> IO (Maybe RawFilePath)
 readDirStream (DirStream dirp) =
-  alloca $ \ptr_dEnt  -> loop ptr_dEnt
- where
-  loop ptr_dEnt = do
-    resetErrno
-    r <- c_readdir dirp ptr_dEnt
-    if (r == 0)
-         then do dEnt <- peek ptr_dEnt
-                 if (dEnt == nullPtr)
-                    then return BC.empty
-                    else do
-                     entry <- (d_name dEnt >>= peekFilePath)
-                     c_freeDirEnt dEnt
-                     return entry
-         else do errno <- getErrno
-                 if (errno == eINTR) then loop ptr_dEnt else do
-                 let (Errno eo) = errno
-                 if (eo == 0)
-                    then return BC.empty
-                    else throwErrno "readDirStream"
+  alloca $ \ptr_dEnt ->
+    do throwErrnoIfMinus1Retry_ "readdir" (c_readdir dirp ptr_dEnt)
+       dEnt <- peek ptr_dEnt
+       if dEnt == nullPtr
+         then return Nothing
+         else do entry <- peekFilePath =<< d_name dEnt
+                 c_freeDirEnt dEnt
+                 return (Just entry)
 
 -- traversing directories
 foreign import ccall unsafe "__hscore_readdir"
index 7c72a34..5ba9fdc 100644 (file)
@@ -94,8 +94,9 @@ int __hscore_readdir( DIR *dirPtr, struct dirent **pDirEnt )
     return -1;
   }
 
+  errno = 0;
   *pDirEnt = readdir(dirPtr);
-  if (*pDirEnt == NULL) {
+  if (*pDirEnt == NULL && errno != 0) {
     return -1;
   } else {
     return 0;
index 4bbeeb3..d1bc198 100644 (file)
@@ -1,5 +1,9 @@
 # Changelog for [`unix` package](http://hackage.haskell.org/package/unix)
 
+## next
+
+  * Change type of `readDirStream` and use `Nothing` to signal end of directory
+
 ## 2.7.2.1  *Sep 2016*
 
   * Don't use `readdir_r` if its deprecated.