@@ -10,7 +10,8 @@ import Prelude.Cast
10import Prelude.Bool
10import Prelude.Bool
11import Prelude.Basics
11import Prelude.Basics
12import Prelude.Classes
12import Prelude.Classes
13−import Prelude.Monad
13+import Prelude.Either
16%access public
17%access public
@@ -19,6 +20,30 @@ import IO
20data File = FHandle Ptr
21data File = FHandle Ptr
23+||| An error from a file operation
24+-- This is built in idris_mkFileError() in rts/idris_stdfgn.c. Make sure
25+-- the values correspond!
26+data FileError = FileReadError
30+ | GenericFileError Int -- errno
33+strError : Int -> String
34+strError err = unsafePerformIO -- yeah, yeah...
35+ (foreign FFI_C "idris_showerror" (Int -> IO String) err)
37+getFileError : IO FileError
38+getFileError = do MkRaw err <- foreign FFI_C "idris_mkFileError"
39+ (Ptr -> IO (Raw FileError)) prim__vm
42+instance Show FileError where
43+ show FileNotFound = "File Not Found"
44+ show PermissionDenied = "Permission Denied"
45+ show (GenericFileError errno) = strError errno
22||| Standard input
47||| Standard input
23stdin : File
48stdin : File
24stdin = FHandle prim__stdin
49stdin = FHandle prim__stdin
@@ -31,6 +56,13 @@ stdout = FHandle prim__stdout
31stderr : File
56stderr : File
32stderr = FHandle prim__stderr
57stderr = FHandle prim__stderr
59+do_ferror : Ptr -> IO Int
60+do_ferror h = foreign FFI_C "fileError" (Ptr -> IO Int) h
62+ferror : File -> IO Bool
63+ferror (FHandle h) = do err <- do_ferror h
64+ return (not (err == 0))
34||| Call the RTS's file opening function
66||| Call the RTS's file opening function
35do_fopen : String -> String -> IO Ptr
67do_fopen : String -> String -> IO Ptr
36do_fopen f m
68do_fopen f m
@@ -39,12 +71,14 @@ do_fopen f m
39||| Open a file
71||| Open a file
40||| @ f the filename
72||| @ f the filename
41||| @ m the mode as a String (`"r"`, `"w"`, or `"r+"`)
73||| @ m the mode as a String (`"r"`, `"w"`, or `"r+"`)
42−fopen : (f : String) -> (m : String) -> IO File
74+fopen : (f : String) -> (m : String) -> IO (Either FileError File)
43fopen f m = do h <- do_fopen f m
75fopen f m = do h <- do_fopen f m
77+ then do err <- getFileError
44− return (FHandle h)
78+ return (Left err)
79+ else return (Right (FHandle h))
46||| Check whether a file handle is actually a null pointer
81||| Check whether a file handle is actually a null pointer
48validFile : File -> IO Bool
82validFile : File -> IO Bool
49validFile (FHandle h) = do x <- nullPtr h
83validFile (FHandle h) = do x <- nullPtr h
50 return (not x)
84 return (not x)
@@ -55,33 +89,26 @@ data Mode = Read | Write | ReadWrite
55||| Open a file
89||| Open a file
56||| @ f the filename
90||| @ f the filename
57||| @ m the mode
91||| @ m the mode
59−openFile : (f : String) -> (m : Mode) -> IO File
92+openFile : (f : String) -> (m : Mode) -> IO (Either FileError File)
60openFile f m = fopen f (modeStr m) where
93openFile f m = fopen f (modeStr m) where
61 modeStr Read = "r"
94 modeStr Read = "r"
62 modeStr Write = "w"
95 modeStr Write = "w"
63 modeStr ReadWrite = "r+"
96 modeStr ReadWrite = "r+"
66do_fclose : Ptr -> IO ()
98do_fclose : Ptr -> IO ()
67do_fclose h = foreign FFI_C "fileClose" (Ptr -> IO ()) h
99do_fclose h = foreign FFI_C "fileClose" (Ptr -> IO ()) h
70closeFile : File -> IO ()
101closeFile : File -> IO ()
71closeFile (FHandle h) = do_fclose h
102closeFile (FHandle h) = do_fclose h
74do_fread : Ptr -> IO' l String
104do_fread : Ptr -> IO' l String
75do_fread h = prim_fread h
105do_fread h = prim_fread h
77−fgetc : File -> IO Char
107+fgetc : File -> IO (Either FileError Char)
78−fgetc (FHandle h) = return (cast !(foreign FFI_C "fgetc" (Ptr -> IO Int) h))
80−fgetc' : File -> IO (Maybe Char)
82− = do x <- foreign FFI_C "fgetc" (Ptr -> IO Int) h
108+fgetc (FHandle h) = do let c = cast !(foreign FFI_C "fgetc" (Ptr -> IO Int) h)
109+ if !(ferror (FHandle h))
83− if (x < 0) then return Nothing
110+ then return (Left FileReadError)
84− else return (Just (cast x))
111+ else return (Right c)
86fflush : File -> IO ()
113fflush : File -> IO ()
87fflush (FHandle h) = foreign FFI_C "fflush" (Ptr -> IO ()) h
114fflush (FHandle h) = foreign FFI_C "fflush" (Ptr -> IO ()) h
@@ -89,9 +116,12 @@ fflush (FHandle h) = foreign FFI_C "fflush" (Ptr -> IO ()) h
89do_popen : String -> String -> IO Ptr
116do_popen : String -> String -> IO Ptr
90do_popen f m = foreign FFI_C "do_popen" (String -> String -> IO Ptr) f m
117do_popen f m = foreign FFI_C "do_popen" (String -> String -> IO Ptr) f m
92−popen : String -> Mode -> IO File
119+popen : String -> Mode -> IO (Either FileError File)
93popen f m = do ptr <- do_popen f (modeStr m)
120popen f m = do ptr <- do_popen f (modeStr m)
122+ then do err <- getFileError
94− return (FHandle ptr)
124+ else return (Right (FHandle ptr))
96 modeStr Read = "r"
126 modeStr Read = "r"
97 modeStr Write = "w"
127 modeStr Write = "w"
@@ -103,20 +133,25 @@ pclose (FHandle h) = foreign FFI_C "pclose" (Ptr -> IO ()) h
103-- mkForeign (FFun "idris_readStr" [FPtr, FPtr] (FAny String))
133-- mkForeign (FFun "idris_readStr" [FPtr, FPtr] (FAny String))
104-- prim__vm h
134-- prim__vm h
107−fread : File -> IO' l String
136+fread : File -> IO (Either FileError String)
108−fread (FHandle h) = do_fread h
137+fread (FHandle h) = do str <- do_fread h
109−
138+ if !(ferror (FHandle h))
110−partial
139+ then return (Left FileReadError)
140+ else return (Right str)
111−do_fwrite : Ptr -> String -> IO ()
142+do_fwrite : Ptr -> String -> IO (Either FileError ())
112−do_fwrite h s = do prim_fwrite h s
143+do_fwrite h s = do res <- prim_fwrite h s
113− return ()
144+ if (res /= 0)
114−
145+ then do errno <- getErrno
115−partial
146+ if errno == 0
147+ then return (Left FileWriteError)
148+ else do err <- getFileError
150+ else return (Right ())
116−fwrite : File -> String -> IO ()
152+fwrite : File -> String -> IO (Either FileError ())
117fwrite (FHandle h) s = do_fwrite h s
153fwrite (FHandle h) s = do_fwrite h s
120do_feof : Ptr -> IO Int
155do_feof : Ptr -> IO Int
121do_feof h = foreign FFI_C "fileEOF" (Ptr -> IO Int) h
156do_feof h = foreign FFI_C "fileEOF" (Ptr -> IO Int) h
@@ -125,32 +160,34 @@ feof : File -> IO Bool
125feof (FHandle h) = do eof <- do_feof h
160feof (FHandle h) = do eof <- do_feof h
126 return (not (eof == 0))
161 return (not (eof == 0))
129−do_ferror : Ptr -> IO Int
130−do_ferror h = foreign FFI_C "fileError" (Ptr -> IO Int) h
132−ferror : File -> IO Bool
133−ferror (FHandle h) = do err <- do_ferror h
134− return (not (err == 0))
136fpoll : File -> IO Bool
163fpoll : File -> IO Bool
137fpoll (FHandle h) = do p <- foreign FFI_C "fpoll" (Ptr -> IO Int) h
164fpoll (FHandle h) = do p <- foreign FFI_C "fpoll" (Ptr -> IO Int) h
138 return (p > 0)
165 return (p > 0)
140||| Read the contents of a file into a string
167||| Read the contents of a file into a string
141−partial -- no error checking!
168+partial -- might be reading something infinitely long like /dev/null ...
142−readFile : String -> IO String
170+readFile : String -> IO (Either FileError String)
143−readFile fn = do h <- openFile fn Read
171+readFile fn = do Right h <- openFile fn Read
172+ | Left err => return (Left err)
144 c <- readFile' h ""
173 c <- readFile' h ""
145 closeFile h
174 closeFile h
149− readFile' : File -> String -> IO String
178+ readFile' : File -> String -> IO (Either FileError String)
150 readFile' h contents =
179 readFile' h contents =
151 do x <- feof h
180 do x <- feof h
152− if not x then do l <- fread h
181+ if not x then do Right l <- fread h
182+ | Left err => return (Left err)
153 readFile' h (contents ++ l)
183 readFile' h (contents ++ l)
154− else return contents
184+ else return (Right contents)
156−
186+||| Write a string to a file
187+writeFile : (filepath : String) -> (contents : String) ->
188+ IO (Either FileError ())
189+writeFile fn contents = do
190+ Right h <- openFile fn Write | Left err => return (Left err)
191+ Right () <- fwrite h contents | Left err => return (Left err)