Merge pull request #618 from sdilts/fopen-safe

Add open-file function
This commit is contained in:
Erik Svedäng 2019-11-25 12:42:42 +01:00 committed by GitHub
commit 34c314e6fe
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 63 additions and 14 deletions

View File

@ -31,8 +31,8 @@
(load "Array.carp")
(load "Char.carp")
(load "String.carp")
(load "IO.carp")
(load "System.carp")
(load "IO.carp")
(load "Pattern.carp")
(load "Debug.carp")
(load "Pointer.carp")

View File

@ -24,8 +24,17 @@
(register exit (Fn [Int] a))
(register EOF Char)
(doc EOF "the End-Of-File character as a literal.")
(doc fopen "opens a file by name using a mode (one or multiple of [r]ead, [w]rite, and [a]ppend), returns a file pointer.")
(doc fopen "opens a file by name using a mode (one or multiple of [r]ead, [w]rite, and [a]ppend), returns a file pointer. Consider using the function open-file instead.")
(register fopen (Fn [&String &String] (Ptr FILE)))
(doc open-file "opens a file by name using a mode (one or multiple of [r]ead, [w]rite, and [a]ppend), returns a Result type that contains an error string or a file pointer.")
(defn open-file [filename mode]
(let [ptr (IO.fopen filename mode)]
(if (null? ptr)
(do
(Result.Error System.errno))
(Result.Success ptr))))
(doc fclose "closes a file pointer.")
(register fclose (Fn [(Ptr FILE)] ()))
(doc fgetc "gets a character from a file pointer.")
@ -51,15 +60,15 @@
(doc read->EOF "reads a file given by name until the End-Of-File character is reached.")
(defn read->EOF [filename]
(let [f (IO.fopen filename "rb")]
(if (null? f)
(Result.Error (fmt "File “%s” couldnt be opened!" filename))
(let [c (zero)
r []]
(do
(while (do (set! c (IO.fgetc f))
(/= c IO.EOF))
(set! r (Array.push-back r c)))
(IO.fclose f)
(Result.Success (String.from-chars &r)))))))
(let [maybe (IO.open-file filename "rb")]
(match maybe
(Result.Error x) (Result.Error x)
(Result.Success f) (let [c (zero)
r []]
(do
(while (do (set! c (IO.fgetc f))
(/= c IO.EOF))
(set! r (Array.push-back r c)))
(IO.fclose f)
(Result.Success (String.from-chars &r)))))))
)

View File

@ -1,4 +1,5 @@
(system-include "carp_system.h")
(system-include "errno.h")
(defmodule System
(doc free "Frees an object. Should not be called except in direst circumstances.")
@ -28,4 +29,24 @@
(register signal-segv Int "SIGSEGV")
(register signal-term Int "SIGTERM")
(register abort (Fn [] ()) "abort")
(register errno Int "errno")
(register EACCES Int "EACCES")
(register EEXIST Int "EEXIST")
(register EINVAL Int "EINVAL")
(register EIO Int "EIO")
(register EISDIR Int "EISDIR")
(register ELOOP Int "ELOOP")
(register EMFILE Int "EMFILE")
(register ENAMETOOLONG Int "ENAMETOOLONG")
(register ENOENT Int "ENOENT")
(register ENOMEM Int "EINVAL")
(register ENOSPC Int "ENOSPC")
(register ENOSR Int "ENOSR")
(register ENOTDIR Int "ENOTDIR")
(register ENXIO Int "ENXIO")
(register EOVERFLOW Int "EOVERFLOW")
(register EROFS Int "EROFS")
(register EINTR Int "EINTR")
)

View File

@ -34,7 +34,7 @@
@&Int.MAX
"test that the address of Int.MAX can be taken")
(assert-equal test
&(Result.Error @"File “foobar” couldnt be opened!")
&(Result.Error System.ENOENT)
&(IO.read->EOF "foobar")
"test that reading from an undefined file works")
(assert-equal test

19
test/system.carp Normal file
View File

@ -0,0 +1,19 @@
(load "Test.carp")
(use-all Test IO Result)
(defn open-existing-file? [filename]
(let [f (open-file filename "r")]
(match f
(Error _) false
(Success x) (do
(fclose x)
true))))
(deftest test
(assert-true test
(error? &(open-file "asfasdfafs.txt" "r"))
"An error is given when the file doesn't exist")
(assert-true test
(open-existing-file? "test/system.carp")
"files that exist are opened properly"))