Skip to content

Commit befa232

Browse files
mmhathasufell
authored andcommitted
Added readDirStream version that returns the entry type as well.
* Added `readDirStream`/`readDirStream` for ByteString, PosixPath * Removed `DirEnt`, `readDirStreamWith`, `readDirStreamWithPtr` from public API
1 parent 8171e25 commit befa232

File tree

7 files changed

+326
-131
lines changed

7 files changed

+326
-131
lines changed

System/Posix/Directory.hsc

Lines changed: 46 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,36 @@ module System.Posix.Directory (
2929

3030
-- * Reading directories
3131
DirStream,
32-
DirEnt(..),
32+
DirType( DtUnknown
33+
#ifdef CONST_DT_FIFO
34+
, DtFifo
35+
#endif
36+
#ifdef CONST_DT_CHR
37+
, DtChr
38+
#endif
39+
#ifdef CONST_DT_DIR
40+
, DtDir
41+
#endif
42+
#ifdef CONST_DT_BLK
43+
, DtBlk
44+
#endif
45+
#ifdef CONST_DT_REG
46+
, DtReg
47+
#endif
48+
#ifdef CONST_DT_LNK
49+
, DtLnk
50+
#endif
51+
#ifdef CONST_DT_SOCK
52+
, DtSock
53+
#endif
54+
#ifdef CONST_DT_WHT
55+
, DtWht
56+
#endif
57+
),
3358
openDirStream,
3459
readDirStream,
3560
readDirStreamMaybe,
36-
readDirStreamWith,
37-
readDirStreamWithPtr,
61+
readDirStreamWithType,
3862
rewindDirStream,
3963
closeDirStream,
4064
DirStreamOffset,
@@ -87,11 +111,11 @@ foreign import capi unsafe "HsUnix.h opendir"
87111
-- | @readDirStream dp@ calls @readdir@ to obtain the
88112
-- next directory entry (@struct dirent@) for the open directory
89113
-- stream @dp@, and returns the @d_name@ member of that
90-
-- structure.
114+
-- structure.
91115
--
92-
-- Note that this function returns an empty filepath if the end of the
93-
-- directory stream is reached. For a safer alternative use
94-
-- 'readDirStreamMaybe'.
116+
-- Note that this function returns an empty filepath if the end of the
117+
-- directory stream is reached. For a safer alternative use
118+
-- 'readDirStreamMaybe'.
95119
readDirStream :: DirStream -> IO FilePath
96120
readDirStream = fmap (fromMaybe "") . readDirStreamMaybe
97121

@@ -104,60 +128,25 @@ readDirStreamMaybe :: DirStream -> IO (Maybe FilePath)
104128
readDirStreamMaybe = readDirStreamWith
105129
(\(DirEnt dEnt) -> d_name dEnt >>= peekFilePath)
106130

107-
-- | @readDirStreamWith f dp@ calls @readdir@ to obtain the next directory entry
108-
-- (@struct dirent@) for the open directory stream @dp@. If an entry is read,
109-
-- it passes the pointer to that structure to the provided function @f@ for
110-
-- processing. It returns the result of that function call wrapped in a @Just@
111-
-- if an entry was read and @Nothing@ if the end of the directory stream was
112-
-- reached.
113-
--
114-
-- __NOTE:__ The lifetime of the pointer wrapped in the `DirEnt` is limited to
115-
-- invocation of the callback and it will be freed automatically after. Do not
116-
-- pass it to the outside world!
117-
readDirStreamWith :: (DirEnt -> IO a) -> DirStream -> IO (Maybe a)
118-
readDirStreamWith f dstream = alloca
119-
(\ptr_dEnt -> readDirStreamWithPtr ptr_dEnt f dstream)
120-
121-
-- | A version of 'readDirStreamWith' that takes a pre-allocated pointer in
122-
-- addition to the other arguments. This pointer is used to store the pointer
123-
-- to the next directory entry, if there is any. This function is intended for
124-
-- usecases where you need to read a lot of directory entries and want to
125-
-- reuse the pointer for each of them. Using for example 'readDirStream' or
126-
-- 'readDirStreamWith' in this scenario would allocate a new pointer for each
127-
-- call of these functions.
128-
--
129-
-- __NOTE__: You are responsible for releasing the pointer after you are done.
130-
readDirStreamWithPtr :: Ptr DirEnt -> (DirEnt -> IO a) -> DirStream -> IO (Maybe a)
131-
readDirStreamWithPtr ptr_dEnt f dstream@(DirStream dirp) = do
132-
resetErrno
133-
r <- c_readdir dirp (castPtr ptr_dEnt)
134-
if (r == 0)
135-
then do dEnt@(DirEnt dEntPtr) <- peek ptr_dEnt
136-
if (dEntPtr == nullPtr)
137-
then return Nothing
138-
else do
139-
res <- f dEnt
140-
c_freeDirEnt dEntPtr
141-
return (Just res)
142-
else do errno <- getErrno
143-
if (errno == eINTR)
144-
then readDirStreamWithPtr ptr_dEnt f dstream
145-
else do
146-
let (Errno eo) = errno
147-
if (eo == 0)
148-
then return Nothing
149-
else throwErrno "readDirStream"
150-
151-
-- traversing directories
152-
foreign import ccall unsafe "__hscore_readdir"
153-
c_readdir :: Ptr CDir -> Ptr (Ptr CDirent) -> IO CInt
154-
155-
foreign import ccall unsafe "__hscore_free_dirent"
156-
c_freeDirEnt :: Ptr CDirent -> IO ()
131+
-- | @readDirStreamWithType dp@ calls @readdir@ to obtain the
132+
-- next directory entry (@struct dirent@) for the open directory
133+
-- stream @dp@. It returns the @d_name@ member of that
134+
-- structure together with the entry's type (@d_type@) wrapped in a
135+
-- @Just (d_name, d_type)@ if an entry was read and @Nothing@ if
136+
-- the end of the directory stream was reached.
137+
readDirStreamWithType :: DirStream -> IO (Maybe (FilePath, DirType))
138+
readDirStreamWithType = readDirStreamWith
139+
(\(DirEnt dEnt) -> (,)
140+
<$> (d_name dEnt >>= peekFilePath)
141+
<*> (DirType <$> d_type dEnt)
142+
)
157143

158144
foreign import ccall unsafe "__hscore_d_name"
159145
d_name :: Ptr CDirent -> IO CString
160146

147+
foreign import ccall unsafe "__hscore_d_type"
148+
d_type :: Ptr CDirent -> IO CChar
149+
161150

162151
-- | @getWorkingDirectory@ calls @getcwd@ to obtain the name
163152
-- of the current working directory.

System/Posix/Directory/ByteString.hsc

Lines changed: 52 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,36 @@ module System.Posix.Directory.ByteString (
2929

3030
-- * Reading directories
3131
DirStream,
32+
DirType( DtUnknown
33+
#ifdef CONST_DT_FIFO
34+
, DtFifo
35+
#endif
36+
#ifdef CONST_DT_CHR
37+
, DtChr
38+
#endif
39+
#ifdef CONST_DT_DIR
40+
, DtDir
41+
#endif
42+
#ifdef CONST_DT_BLK
43+
, DtBlk
44+
#endif
45+
#ifdef CONST_DT_REG
46+
, DtReg
47+
#endif
48+
#ifdef CONST_DT_LNK
49+
, DtLnk
50+
#endif
51+
#ifdef CONST_DT_SOCK
52+
, DtSock
53+
#endif
54+
#ifdef CONST_DT_WHT
55+
, DtWht
56+
#endif
57+
),
3258
openDirStream,
3359
readDirStream,
3460
readDirStreamMaybe,
61+
readDirStreamWithType,
3562
rewindDirStream,
3663
closeDirStream,
3764
DirStreamOffset,
@@ -60,7 +87,7 @@ import System.Posix.ByteString.FilePath
6087

6188
-- | @createDirectory dir mode@ calls @mkdir@ to
6289
-- create a new directory, @dir@, with permissions based on
63-
-- @mode@.
90+
-- @mode@.
6491
createDirectory :: RawFilePath -> FileMode -> IO ()
6592
createDirectory name mode =
6693
withFilePath name $ \s ->
@@ -85,51 +112,42 @@ foreign import capi unsafe "HsUnix.h opendir"
85112
-- | @readDirStream dp@ calls @readdir@ to obtain the
86113
-- next directory entry (@struct dirent@) for the open directory
87114
-- stream @dp@, and returns the @d_name@ member of that
88-
-- structure.
115+
-- structure.
89116
--
90-
-- Note that this function returns an empty filepath if the end of the
91-
-- directory stream is reached. For a safer alternative use
92-
-- 'readDirStreamMaybe'.
117+
-- Note that this function returns an empty filepath if the end of the
118+
-- directory stream is reached. For a safer alternative use
119+
-- 'readDirStreamMaybe'.
93120
readDirStream :: DirStream -> IO RawFilePath
94121
readDirStream = fmap (fromMaybe BC.empty) . readDirStreamMaybe
95122

96123
-- | @readDirStreamMaybe dp@ calls @readdir@ to obtain the
97124
-- next directory entry (@struct dirent@) for the open directory
98125
-- stream @dp@. It returns the @d_name@ member of that
99-
-- structure wrapped in a @Just d_name@ if an entry was read and @Nothing@ if
100-
-- the end of the directory stream was reached.
126+
-- structure wrapped in a @Just d_name@ if an entry was read and @Nothing@ if
127+
-- the end of the directory stream was reached.
101128
readDirStreamMaybe :: DirStream -> IO (Maybe RawFilePath)
102-
readDirStreamMaybe (DirStream dirp) =
103-
alloca $ \ptr_dEnt -> loop ptr_dEnt
104-
where
105-
loop ptr_dEnt = do
106-
resetErrno
107-
r <- c_readdir dirp ptr_dEnt
108-
if (r == 0)
109-
then do dEnt <- peek ptr_dEnt
110-
if (dEnt == nullPtr)
111-
then return Nothing
112-
else do
113-
entry <- (d_name dEnt >>= peekFilePath)
114-
c_freeDirEnt dEnt
115-
return $ Just entry
116-
else do errno <- getErrno
117-
if (errno == eINTR) then loop ptr_dEnt else do
118-
let (Errno eo) = errno
119-
if (eo == 0)
120-
then return Nothing
121-
else throwErrno "readDirStream"
122-
123-
-- traversing directories
124-
foreign import ccall unsafe "__hscore_readdir"
125-
c_readdir :: Ptr CDir -> Ptr (Ptr CDirent) -> IO CInt
126-
127-
foreign import ccall unsafe "__hscore_free_dirent"
128-
c_freeDirEnt :: Ptr CDirent -> IO ()
129+
readDirStreamMaybe = readDirStreamWith
130+
(\(DirEnt dEnt) -> d_name dEnt >>= peekFilePath)
131+
132+
-- | @readDirStreamWithType dp@ calls @readdir@ to obtain the
133+
-- next directory entry (@struct dirent@) for the open directory
134+
-- stream @dp@. It returns the @d_name@ member of that
135+
-- structure together with the entry's type (@d_type@) wrapped in a
136+
-- @Just (d_name, d_type)@ if an entry was read and @Nothing@ if
137+
-- the end of the directory stream was reached.
138+
readDirStreamWithType :: DirStream -> IO (Maybe (RawFilePath, DirType))
139+
readDirStreamWithType = readDirStreamWith
140+
(\(DirEnt dEnt) -> (,)
141+
<$> (d_name dEnt >>= peekFilePath)
142+
<*> (DirType <$> d_type dEnt)
143+
)
129144

130145
foreign import ccall unsafe "__hscore_d_name"
131146
d_name :: Ptr CDirent -> IO CString
132147

148+
foreign import ccall unsafe "__hscore_d_type"
149+
d_type :: Ptr CDirent -> IO CChar
150+
133151

134152
-- | @getWorkingDirectory@ calls @getcwd@ to obtain the name
135153
-- of the current working directory.

0 commit comments

Comments
 (0)