lib/standard/streams: Added simple error management for streams
authorLucas Bajolet <r4pass@hotmail.com>
Fri, 21 Nov 2014 15:50:59 +0000 (10:50 -0500)
committerLucas Bajolet <r4pass@hotmail.com>
Tue, 9 Dec 2014 15:24:22 +0000 (10:24 -0500)
Signed-off-by: Lucas Bajolet <r4pass@hotmail.com>

lib/io/push_back_reader.nit
lib/standard/exec_nit.c
lib/standard/file.nit
lib/standard/stream.nit
tests/sav/test_file_open_fail.res [new file with mode: 0644]
tests/test_file_open_fail.nit [new file with mode: 0644]

index 257c662..5453901 100644 (file)
@@ -12,7 +12,7 @@
 module io::push_back_reader
 
 # Input stream that permits to push bytes back to the stream.
-interface PushBackReader
+class PushBackReader
        super IStream
 
        # Push the specified byte back to the stream.
index c808105..c69ba64 100644 (file)
@@ -26,22 +26,19 @@ se_exec_data_t* exec_Process_Process_basic_exec_execute_4(void *s, char *prog, c
        if (pipeflag & 1) {
                int res = pipe(in_fd);
                if ( res == -1 ) {
-                       fprintf( stderr, "Pipe init failed in Process:basic_exec_execute: %s\n", strerror( errno ) );
-                       exit(1);
+                       return NULL;
                }
        }
        if (pipeflag & 2) {
                int res = pipe(out_fd);
                if ( res == -1 ) {
-                       fprintf( stderr, "Pipe init failed in Process:basic_exec_execute: %s\n", strerror( errno ) );
-                       exit(1);
+                       return NULL;
                }
        }
        if (pipeflag & 4) {
                int res = pipe(err_fd);
                if ( res == -1 ) {
-                       fprintf( stderr, "Pipe init failed in Process:basic_exec_execute: %s\n", strerror( errno ) );
-                       exit(1);
+                       return NULL;
                }
        }
                                        
index fb89882..1fffc18 100644 (file)
@@ -55,8 +55,14 @@ class IFStream
        # The original path is reused, therefore the reopened file can be a different file.
        fun reopen
        do
-               if not eof then close
+               if not eof and not _file.address_is_null then close
+               last_error = null
                _file = new NativeFile.io_open_read(path.to_cstring)
+               if _file.address_is_null then
+                       last_error = new IOError("Error: Opening file at '{path.as(not null)}' failed with '{sys.errno.strerror}'")
+                       end_reached = true
+                       return
+               end
                end_reached = false
                _buffer_pos = 0
                _buffer.clear
@@ -64,6 +70,7 @@ class IFStream
 
        redef fun close
        do
+               if _file.address_is_null then return
                var i = _file.io_close
                _buffer.clear
                end_reached = true
@@ -79,7 +86,7 @@ class IFStream
                _buffer.length = nb
                _buffer_pos = 0
        end
-       
+
        # End of file?
        redef var end_reached: Bool = false
 
@@ -89,8 +96,9 @@ class IFStream
                self.path = path
                prepare_buffer(10)
                _file = new NativeFile.io_open_read(path.to_cstring)
-               assert not _file.address_is_null else
-                       print "Error: Opening file at '{path}' failed with '{sys.errno.strerror}'"
+               if _file.address_is_null then
+                       last_error = new IOError("Error: Opening file at '{path}' failed with '{sys.errno.strerror}'")
+                       end_reached = true
                end
        end
 
@@ -103,7 +111,11 @@ class OFStream
        
        redef fun write(s)
        do
-               assert _is_writable
+               if last_error != null then return
+               if not _is_writable then
+                       last_error = new IOError("Cannot write to non-writable stream")
+                       return
+               end
                if s isa FlatText then
                        write_native(s.to_cstring, s.length)
                else
@@ -113,20 +125,37 @@ class OFStream
 
        redef fun close
        do
+               if _file.address_is_null then
+                       if last_error != null then return
+                       last_error = new IOError("Cannot close unopened write stream")
+                       _is_writable = false
+                       return
+               end
                var i = _file.io_close
+               if i != 0 then
+                       last_error = new IOError("Close failed due to error {sys.errno.strerror}")
+               end
                _is_writable = false
        end
-
        redef var is_writable = false
        
        # Write `len` bytes from `native`.
        private fun write_native(native: NativeString, len: Int)
        do
-               assert _is_writable
+               if last_error != null then return
+               if not _is_writable then
+                       last_error = new IOError("Cannot write to non-writable stream")
+                       return
+               end
+               if _file.address_is_null then
+                       last_error = new IOError("Writing on a null stream")
+                       _is_writable = false
+                       return
+               end
                var err = _file.io_write(native, len)
                if err != len then
                        # Big problem
-                       printn("Problem in writing : ", err, " ", len, "\n")
+                       last_error = new IOError("Problem in writing : {err} {len} \n")
                end
        end
        
@@ -134,11 +163,12 @@ class OFStream
        init open(path: String)
        do
                _file = new NativeFile.io_open_write(path.to_cstring)
-               assert not _file.address_is_null else
-                       print "Error: Opening file at '{path}' failed with '{sys.errno.strerror}'"
-               end
                self.path = path
                _is_writable = true
+               if _file.address_is_null then
+                       last_error = new IOError("Error: Opening file at '{path}' failed with '{sys.errno.strerror}'")
+                       is_writable = false
+               end
        end
 end
 
index 84b167a..0c7a1a3 100644 (file)
@@ -12,6 +12,7 @@
 module stream
 
 intrude import ropes
+import error
 
 in "C" `{
        #include <unistd.h>
@@ -21,14 +22,27 @@ in "C" `{
        #include <signal.h>
 `}
 
+# Any kind of error that could be produced by an operation on Streams
+class IOError
+       super Error
+end
+
 # Abstract stream class
-interface IOS
+abstract class IOS
+       # Error produced by the file stream
+       #
+       #     var ifs = new IFStream.open("donotmakethisfile.binx")
+       #     ifs.read_all
+       #     ifs.close
+       #     assert ifs.last_error != null
+       var last_error: nullable IOError = null
+
        # close the stream
        fun close is abstract
 end
 
 # Abstract input streams
-interface IStream
+abstract class IStream
        super IOS
        # Read a character. Return its ASCII value, -1 on EOF or timeout
        fun read_char: Int is abstract
@@ -36,6 +50,7 @@ interface IStream
        # Read at most i bytes
        fun read(i: Int): String
        do
+               if last_error != null then return ""
                var s = new FlatBuffer.with_capacity(i)
                while i > 0 and not eof do
                        var c = read_char
@@ -50,6 +65,7 @@ interface IStream
        # Read a string until the end of the line.
        fun read_line: String
        do
+               if last_error != null then return ""
                assert not eof
                var s = new FlatBuffer
                append_line_to(s)
@@ -59,6 +75,7 @@ interface IStream
        # Read all the stream until the eof.
        fun read_all: String
        do
+               if last_error != null then return ""
                var s = new FlatBuffer
                while not eof do
                        var c = read_char
@@ -70,6 +87,7 @@ interface IStream
        # Read a string until the end of the line and append it to `s`.
        fun append_line_to(s: Buffer)
        do
+               if last_error != null then return
                loop
                        var x = read_char
                        if x == -1 then
@@ -88,7 +106,7 @@ interface IStream
 end
 
 # IStream capable of declaring if readable without blocking
-interface PollableIStream
+abstract class PollableIStream
        super IStream
 
        # Is there something to read? (without blocking)
@@ -97,7 +115,7 @@ interface PollableIStream
 end
 
 # Abstract output stream
-interface OStream
+abstract class OStream
        super IOS
        # write a string
        fun write(s: Text) is abstract
@@ -140,7 +158,8 @@ abstract class BufferedIStream
        super IStream
        redef fun read_char
        do
-               assert not eof
+               if last_error != null then return 0
+               if eof then last_error = new IOError("Stream has reached eof")
                if _buffer_pos >= _buffer.length then
                        fill_buffer
                end
@@ -154,6 +173,7 @@ abstract class BufferedIStream
 
        redef fun read(i)
        do
+               if last_error != null then return ""
                if _buffer.length == _buffer_pos then
                        if not eof then
                                fill_buffer
@@ -172,6 +192,7 @@ abstract class BufferedIStream
 
        redef fun read_all
        do
+               if last_error != null then return ""
                var s = new FlatBuffer
                while not eof do
                        var j = _buffer_pos
@@ -244,7 +265,7 @@ abstract class BufferedIStream
        end
 end
 
-interface IOStream
+abstract class IOStream
        super IStream
        super OStream
 end
diff --git a/tests/sav/test_file_open_fail.res b/tests/sav/test_file_open_fail.res
new file mode 100644 (file)
index 0000000..613542b
--- /dev/null
@@ -0,0 +1,2 @@
+Error: Opening file at 'donotcreate.bing' failed with 'No such file or directory'
+Error: Opening file at 'donotcreate.bing' failed with 'No such file or directory'
diff --git a/tests/test_file_open_fail.nit b/tests/test_file_open_fail.nit
new file mode 100644 (file)
index 0000000..f71ed82
--- /dev/null
@@ -0,0 +1,29 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+var ifs = new IFStream.open("donotcreate.bing")
+
+var s = ifs.read_all
+
+ifs.close
+
+if ifs.last_error != null then print ifs.last_error.as(not null)
+
+ifs.reopen
+
+s = ifs.read_all
+
+ifs.close
+
+if ifs.last_error != null then print ifs.last_error.as(not null)