Skip to content

Commit 0ecf74e

Browse files
committed
System.Directory.nextDirEntry
* add `nextDirEntry` which returns `Maybe String`, so `Nothing` on the end of directory unlike `dirEntry` which returns unspecified error on the end of directory * `dirEntry` is deprecated now, but not removed because compiler depends on it * native implementation of `dirEntry` is patched to explicitly reset `errno` before the `readdir` call: without it end of directory and error were indistinguishable * test added
1 parent ce44d3b commit 0ecf74e

File tree

8 files changed

+50
-4
lines changed

8 files changed

+50
-4
lines changed

libs/base/System/Directory.idr

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
module System.Directory
22

3+
import System.Errno
34
import public System.File
45

56
%default total
@@ -97,9 +98,20 @@ removeDir : HasIO io => String -> io ()
9798
removeDir dirName = primIO (prim__removeDir dirName)
9899

99100
export
100-
dirEntry : HasIO io => Directory -> io (Either FileError String)
101-
dirEntry (MkDir d)
101+
nextDirEntry : HasIO io => Directory -> io (Either FileError (Maybe String))
102+
nextDirEntry (MkDir d)
102103
= do res <- primIO (prim__dirEntry d)
103104
if prim__nullPtr res /= 0
104-
then returnError
105-
else ok (prim__getString res)
105+
then if !(getErrno) /= 0
106+
then returnError
107+
else pure $ Right Nothing
108+
else pure $ Right (Just (prim__getString res))
109+
110+
-- This function is deprecated; to be removed after the next version bump
111+
export
112+
dirEntry : HasIO io => Directory -> io (Either FileError String)
113+
dirEntry d = do r <- nextDirEntry d
114+
pure $ case r of
115+
Left e => Left e
116+
Right (Just n) => Right n
117+
Right Nothing => Left FileNotFound

support/c/idris_directory.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,10 @@ int idris2_removeDir(char* path) {
6060

6161
char* idris2_nextDirEntry(void* d) {
6262
DirInfo* di = (DirInfo*)d;
63+
// `readdir` keeps `errno` unchanged on end of stream
64+
// so we need to reset `errno` to distinguish between
65+
// end of stream and failure.
66+
errno = 0;
6367
struct dirent* de = readdir(di->dirptr);
6468

6569
if (de == NULL) {

tests/Main.idr

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,7 @@ baseLibraryTests = MkTestPool "Base library" [Chez, Node] Nothing
298298
, "data_bits001"
299299
, "data_string_lines001"
300300
, "data_string_unlines001"
301+
, "system_directory"
301302
, "system_errno"
302303
, "system_info001"
303304
, "system_signal001", "system_signal002", "system_signal003", "system_signal004"
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import System
2+
import System.Directory
3+
4+
panic : String -> IO a
5+
panic s = do putStrLn s
6+
exitFailure
7+
8+
collectEntries : Directory -> IO (List String)
9+
collectEntries d = do Right (Just n) <- nextDirEntry d
10+
| Right Nothing => pure []
11+
| Left e => panic (show e)
12+
ns <- collectEntries d
13+
if n == "." || n == ".."
14+
then pure ns
15+
else pure (n :: ns)
16+
17+
main : IO ()
18+
main = do Right d <- openDir "dir"
19+
| Left e => panic (show e)
20+
["a"] <- collectEntries d
21+
| x => panic ("wrong entries: " ++ (show x))
22+
pure ()

tests/base/system_directory/dir/a

Whitespace-only changes.

tests/base/system_directory/expected

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
1/1: Building ReadDir (ReadDir.idr)
2+
Main> Main> Bye for now!

tests/base/system_directory/input

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
:exec main
2+
:q

tests/base/system_directory/run

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
rm -rf build
2+
3+
$1 --no-color --console-width 0 --no-banner ReadDir.idr < input

0 commit comments

Comments
 (0)