@@ -6,6 +6,7 @@ import Prelude.Maybe
6import Prelude.Monad
6import Prelude.Monad
7import Prelude.Chars
7import Prelude.Chars
8import Prelude.Strings
8import Prelude.Strings
9import Prelude.Cast
10import Prelude.Cast
10import Prelude.Bool
11import Prelude.Bool
11import Prelude.Basics
12import Prelude.Basics
@@ -26,11 +27,12 @@ data File : Type where
26||| An error from a file operation
27||| An error from a file operation
27-- This is built in idris_mkFileError() in rts/idris_stdfgn.c. Make sure
28-- This is built in idris_mkFileError() in rts/idris_stdfgn.c. Make sure
28-- the values correspond!
29-- the values correspond!
31+data FileError = GenericFileError Int -- errno
29−data FileError = FileReadError
32+ | FileReadError
30 | FileWriteError
33 | FileWriteError
31 | FileNotFound
34 | FileNotFound
32 | PermissionDenied
35 | PermissionDenied
33− | GenericFileError Int -- errno
36strError : Int -> String
38strError : Int -> String
@@ -133,6 +135,22 @@ export
133closeFile : File -> IO ()
135closeFile : File -> IO ()
134closeFile (FHandle h) = do_fclose h
136closeFile (FHandle h) = do_fclose h
139+do_getFileSize : Ptr -> IO Int
140+do_getFileSize h = foreign FFI_C "fileSize" (Ptr -> IO Int) h
142+||| Return the size of a File
143+||| Returns an error if the File is not an ordinary file (e.g. a directory)
144+||| Also note that this currently returns an Int, which may overflow if the
147+fileSize : File -> IO (Either FileError Int)
148+fileSize (FHandle h) = do s <- do_getFileSize h
150+ then do err <- getFileError
152+ else return (Right s)
137do_fread : Ptr -> IO' l String
155do_fread : Ptr -> IO' l String
138do_fread h = prim_fread h
156do_fread h = prim_fread h
@@ -233,22 +251,28 @@ fpoll (FHandle h) = do p <- foreign FFI_C "fpoll" (Ptr -> IO Int) h
233 return (p > 0)
251 return (p > 0)
235||| Read the contents of a file into a string
253||| Read the contents of a file into a string
236−-- might be reading something infinitely long like /dev/null ...
254+||| This checks the size of the file before beginning to read, and only
255+||| reads that many bytes, to ensure that it remains a total function if
256+||| the file is appended to while being read.
257+||| Returns an error if filepath is not a normal file.
237−covering export
258+export
238−readFile : String -> IO (Either FileError String)
259+readFile : (filepath : String) -> IO (Either FileError String)
239readFile fn = do Right h <- openFile fn Read
260readFile fn = do Right h <- openFile fn Read
240 | Left err => return (Left err)
261 | Left err => return (Left err)
262+ Right max <- fileSize h
263+ | Left err => return (Left err)
241− c <- readFile' h ""
264+ c <- readFile' h max ""
242 closeFile h
265 closeFile h
246− readFile' : File -> String -> IO (Either FileError String)
268+ readFile' : File -> Int -> String -> IO (Either FileError String)
247− readFile' h contents =
269+ readFile' h max contents =
248 do x <- fEOF h
270 do x <- fEOF h
249− if not x then do Right l <- fGetLine h
272+ then do Right l <- fGetLine h
250 | Left err => return (Left err)
273 | Left err => return (Left err)
251− readFile' h (contents ++ l)
275+ readFile' h (max - cast (length l)) (contents ++ l)
252 else return (Right contents)
276 else return (Right contents)
254||| Write a string to a file
278||| Write a string to a file