Skip to content

Commit

Permalink
Expose dirent pointer and added readDirStreamWith
Browse files Browse the repository at this point in the history
This commit exposes the dirent pointer used in the directory stream
functions wrapped in a newtype called `DirEnt`. It also adds a new
function `readDirStreamWith` that takes a callback that is used to
obtain the result from the pointer to the directory entry.
  • Loading branch information
mmhat committed Oct 1, 2022
1 parent 236f562 commit 3f5c348
Show file tree
Hide file tree
Showing 2 changed files with 24 additions and 6 deletions.
26 changes: 21 additions & 5 deletions System/Posix/Directory.hsc
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,11 @@ module System.Posix.Directory (

-- * Reading directories
DirStream,
DirEnt(..),
openDirStream,
readDirStream,
readDirStreamMaybe,
readDirStreamWith,
rewindDirStream,
closeDirStream,
DirStreamOffset,
Expand Down Expand Up @@ -95,10 +97,24 @@ readDirStream = fmap (fromMaybe "") . readDirStreamMaybe
-- | @readDirStreamMaybe dp@ calls @readdir@ to obtain the
-- next directory entry (@struct dirent@) for the open directory
-- stream @dp@. It returns the @d_name@ member of that
-- structure wrapped in a @Just d_name@ if an entry was read and @Nothing@ if
-- the end of the directory stream was reached.
-- structure wrapped in a @Just d_name@ if an entry was read and @Nothing@ if
-- the end of the directory stream was reached.
readDirStreamMaybe :: DirStream -> IO (Maybe FilePath)
readDirStreamMaybe (DirStream dirp) =
readDirStreamMaybe = readDirStreamWith
(\(DirEnt dEnt) -> d_name dEnt >>= peekFilePath)

-- | @readDirStreamWith f dp@ calls @readdir@ to obtain the next directory entry
-- (@struct dirent@) for the open directory stream @dp@. If an entry is read,
-- it passes the pointer to that structure to the provided function @f@ for
-- processing. It returns the result of that function call wrapped in a @Just@
-- if an entry was read and @Nothing@ if the end of the directory stream was
-- reached.
--
-- __NOTE:__ The lifetime of the pointer wrapped in the `DirEnt` is limited to
-- invocation of the callback and it will be freed automatically after. Do not
-- pass it to the outside world!
readDirStreamWith :: (DirEnt -> IO a) -> DirStream -> IO (Maybe a)
readDirStreamWith f (DirStream dirp) =
alloca $ \ptr_dEnt -> loop ptr_dEnt
where
loop ptr_dEnt = do
Expand All @@ -109,9 +125,9 @@ readDirStreamMaybe (DirStream dirp) =
if (dEnt == nullPtr)
then return Nothing
else do
entry <- (d_name dEnt >>= peekFilePath)
res <- f (DirEnt dEnt)
c_freeDirEnt dEnt
return $ Just entry
return (Just res)
else do errno <- getErrno
if (errno == eINTR) then loop ptr_dEnt else do
let (Errno eo) = errno
Expand Down
4 changes: 3 additions & 1 deletion System/Posix/Directory/Common.hsc
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
#include "HsUnix.h"

module System.Posix.Directory.Common (
DirStream(..), CDir, CDirent, DirStreamOffset(..),
DirStream(..), DirEnt(..), CDir, CDirent, DirStreamOffset(..),
unsafeOpenDirStreamFd,
rewindDirStream,
closeDirStream,
Expand All @@ -38,6 +38,8 @@ import Foreign.C

newtype DirStream = DirStream (Ptr CDir)

newtype DirEnt = DirEnt (Ptr CDirent)

data {-# CTYPE "DIR" #-} CDir
data {-# CTYPE "struct dirent" #-} CDirent

Expand Down

0 comments on commit 3f5c348

Please sign in to comment.