Merge: Newstreams
authorJean Privat <jean@pryen.org>
Sat, 13 Dec 2014 07:49:28 +0000 (02:49 -0500)
committerJean Privat <jean@pryen.org>
Sat, 13 Dec 2014 07:49:28 +0000 (02:49 -0500)
Small refactoring of Streams/Files:
- Added a simple error management system
- Removed FDStreams, reified under FStream

Next PR to come: Proposition for renaming of the classes of the stream hierarchy (as requested in #466)

Pull-Request: #932
Reviewed-by: Alexis Laferrière <alexis.laf@xymus.net>
Reviewed-by: Alexandre Terrasa <alexandre@moz-code.org>
Reviewed-by: Jean Privat <jean@pryen.org>

23 files changed:
lib/io/push_back_reader.nit
lib/pnacl.nit
lib/standard/exec.nit
lib/standard/exec_nit.c
lib/standard/file.nit
lib/standard/file_nit.c
lib/standard/file_nit.h
lib/standard/stream.nit
lib/standard/stream_nit.c [deleted file]
lib/standard/stream_nit.h [deleted file]
src/interpreter/naive_interpreter.nit
src/interpreter/primitive_types.nit [new file with mode: 0644]
tests/sav/nitserial_args1.res
tests/sav/test_exec.res
tests/sav/test_ffi_java_callbacks.res
tests/sav/test_ffi_java_generics.res
tests/sav/test_ffi_java_string.res
tests/sav/test_ffi_java_use_module.res
tests/sav/test_file_open_fail.res [new file with mode: 0644]
tests/sav/test_jvm.res
tests/test_fdstream.nit
tests/test_file_open_fail.nit [new file with mode: 0644]
tests/test_stream_poll.nit

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 4008422..70b8e7c 100644 (file)
@@ -44,6 +44,7 @@ in "C Header" `{
        #include <string.h>
        #include <stdlib.h>
        #include <pthread.h>
+       #include <poll.h>
 
        #define MAX_DICTIONARY_QUEUE_SIZE 200
        #define MAX_MESSAGE_QUEUE_SIZE 10
@@ -358,7 +359,7 @@ in "C Header" `{
        }
 
        /* Hack in order to avoid the problem with file. */
-       int poll(void *fds, int nfds, int timeout) { return 0; }
+       int poll(struct pollfd* fds, nfds_t nfds, int timeout) { return 0; }
 `}
 
 # Nit class representing a Pepper C API PP_Var typed as a Dictionary.
index 2495800..79f9bfd 100644 (file)
@@ -15,7 +15,7 @@
 # Standard input and output can be handled through streams.
 module exec
 
-import stream
+import file
 
 # Simple sub-process
 class Process
@@ -93,7 +93,7 @@ class IProcess
        super IStream
 
        # File Descriptor used for the input.
-       var stream_in: FDIStream is noinit
+       var stream_in: IFStream is noinit
 
        redef fun close do stream_in.close
 
@@ -106,7 +106,7 @@ class IProcess
        redef fun execute
        do
                super
-               stream_in = new FDIStream(data.out_fd)
+               stream_in = new IFStream.from_fd(data.out_fd)
        end
 end
 
@@ -129,7 +129,7 @@ class OProcess
        redef fun execute
        do
                super
-               stream_out = new FDOStream(data.in_fd)
+               stream_out = new OFStream.from_fd(data.in_fd)
        end
 end
 
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 88fb3c8..a7c48db 100644 (file)
@@ -27,6 +27,8 @@ in "C Header" `{
        #include <sys/stat.h>
        #include <unistd.h>
        #include <stdio.h>
+       #include <poll.h>
+       #include <errno.h>
 `}
 
 # File Abstract Stream
@@ -43,6 +45,21 @@ abstract class FStream
 
        # File descriptor of this file
        fun fd: Int do return _file.fileno
+
+       # Sets the buffering mode for the current FStream
+       #
+       # If the buf_size is <= 0, its value will be 512 by default
+       #
+       # The mode is any of the buffer_mode enumeration in `Sys`:
+       #       - buffer_mode_full
+       #       - buffer_mode_line
+       #       - buffer_mode_none
+       fun set_buffering_mode(buf_size, mode: Int) do
+               if buf_size <= 0 then buf_size = 512
+               if _file.set_buffering_type(buf_size, mode) != 0 then
+                       last_error = new IOError("Error while changing buffering type for FStream, returned error {sys.errno.strerror}")
+               end
+       end
 end
 
 # File input stream
@@ -56,8 +73,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
@@ -65,7 +88,8 @@ class IFStream
 
        redef fun close
        do
-               _file.io_close
+               if _file.address_is_null then return
+               var i = _file.io_close
                _buffer.clear
                end_reached = true
        end
@@ -80,7 +104,7 @@ class IFStream
                _buffer.length = nb
                _buffer_pos = 0
        end
-       
+
        # End of file?
        redef var end_reached: Bool = false
 
@@ -90,11 +114,21 @@ 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
 
+       init from_fd(fd: Int) do
+               self.path = ""
+               prepare_buffer(1)
+               _file = fd.fd_to_stream(read_only)
+               if _file.address_is_null then
+                       last_error = new IOError("Error: Converting fd {fd} to stream failed with '{sys.errno.strerror}'")
+                       end_reached = true
+               end
+       end
 end
 
 # File output stream
@@ -104,30 +138,52 @@ 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
                        for i in s.substrings do write_native(i.to_cstring, i.length)
                end
+               _file.flush
        end
 
        redef fun close
        do
-               _file.io_close
+               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
        
@@ -135,14 +191,43 @@ 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
+
+       # Creates a new File stream from a file descriptor
+       init from_fd(fd: Int) do
+               self.path = ""
+               _file = fd.fd_to_stream(wipe_write)
+               _is_writable = true
+                if _file.address_is_null then
+                        last_error = new IOError("Error: Opening stream from file descriptor {fd} failed with '{sys.errno.strerror}'")
+                       _is_writable = false
+               end
        end
 end
 
+redef class Int
+       # Creates a file stream from a file descriptor `fd` using the file access `mode`.
+       #
+       # NOTE: The `mode` specified must be compatible with the one used in the file descriptor.
+       private fun fd_to_stream(mode: NativeString): NativeFile is extern "file_int_fdtostream"
+end
+
+# Constant for read-only file streams
+private fun read_only: NativeString do return "r".to_cstring
+
+# Constant for write-only file streams
+#
+# If a stream is opened on a file with this method,
+# it will wipe the previous file if any.
+# Else, it will create the file.
+private fun wipe_write: NativeString do return "w".to_cstring
+
 ###############################################################################
 
 # Standard input stream.
@@ -617,6 +702,10 @@ private extern class NativeFile `{ FILE* `}
        fun io_close: Int is extern "file_NativeFile_NativeFile_io_close_0"
        fun file_stat: FileStat is extern "file_NativeFile_NativeFile_file_stat_0"
        fun fileno: Int `{ return fileno(recv); `}
+       # Flushes the buffer, forcing the write operation
+       fun flush: Int is extern "fflush"
+       # Used to specify how the buffering will be handled for the current stream.
+       fun set_buffering_type(buf_length: Int, mode: Int): Int is extern "file_NativeFile_NativeFile_set_buffering_type_0"
 
        new io_open_read(path: NativeString) is extern "file_NativeFileCapable_NativeFileCapable_io_open_read_1"
        new io_open_write(path: NativeString) is extern "file_NativeFileCapable_NativeFileCapable_io_open_write_1"
@@ -627,6 +716,10 @@ end
 
 redef class Sys
 
+       init do
+               if stdout isa FStream then stdout.as(FStream).set_buffering_mode(256, buffer_mode_line)
+       end
+
        # Standard input
        var stdin: PollableIStream = new Stdin is protected writable
 
@@ -636,6 +729,89 @@ redef class Sys
        # Standard output for errors
        var stderr: OStream = new Stderr is protected writable
 
+       # Enumeration for buffer mode full (flushes when buffer is full)
+       fun buffer_mode_full: Int is extern "file_Sys_Sys_buffer_mode_full_0"
+       # Enumeration for buffer mode line (flushes when a `\n` is encountered)
+       fun buffer_mode_line: Int is extern "file_Sys_Sys_buffer_mode_line_0"
+       # Enumeration for buffer mode none (flushes ASAP when something is written)
+       fun buffer_mode_none: Int is extern "file_Sys_Sys_buffer_mode_none_0"
+
+       # returns first available stream to read or write to
+       # return null on interruption (possibly a signal)
+       protected fun poll( streams : Sequence[FStream] ) : nullable FStream
+       do
+               var in_fds = new Array[Int]
+               var out_fds = new Array[Int]
+               var fd_to_stream = new HashMap[Int,FStream]
+               for s in streams do
+                       var fd = s.fd
+                       if s isa IFStream then in_fds.add( fd )
+                       if s isa OFStream then out_fds.add( fd )
+
+                       fd_to_stream[fd] = s
+               end
+
+               var polled_fd = intern_poll( in_fds, out_fds )
+
+               if polled_fd == null then
+                       return null
+               else
+                       return fd_to_stream[polled_fd]
+               end
+       end
+
+       private fun intern_poll(in_fds: Array[Int], out_fds: Array[Int]) : nullable Int is extern import Array[Int].length, Array[Int].[], Int.as(nullable Int) `{
+               int in_len, out_len, total_len;
+               struct pollfd *c_fds;
+               sigset_t sigmask;
+               int i;
+               int first_polled_fd = -1;
+               int result;
+
+               in_len = Array_of_Int_length( in_fds );
+               out_len = Array_of_Int_length( out_fds );
+               total_len = in_len + out_len;
+               c_fds = malloc( sizeof(struct pollfd) * total_len );
+
+               /* input streams */
+               for ( i=0; i<in_len; i ++ ) {
+                       int fd;
+                       fd = Array_of_Int__index( in_fds, i );
+
+                       c_fds[i].fd = fd;
+                       c_fds[i].events = POLLIN;
+               }
+
+               /* output streams */
+               for ( i=0; i<out_len; i ++ ) {
+                       int fd;
+                       fd = Array_of_Int__index( out_fds, i );
+
+                       c_fds[i].fd = fd;
+                       c_fds[i].events = POLLOUT;
+               }
+
+               /* poll all fds, unlimited timeout */
+               result = poll( c_fds, total_len, -1 );
+
+               if ( result > 0 ) {
+                       /* analyse results */
+                       for ( i=0; i<total_len; i++ )
+                               if ( c_fds[i].revents & c_fds[i].events || /* awaited event */
+                                        c_fds[i].revents & POLLHUP ) /* closed */
+                               {
+                                       first_polled_fd = c_fds[i].fd;
+                                       break;
+                               }
+
+                       return Int_as_nullable( first_polled_fd );
+               }
+               else if ( result < 0 )
+                       fprintf( stderr, "Error in Stream:poll: %s\n", strerror( errno ) );
+
+               return null_Int();
+       `}
+
 end
 
 # Print `objects` on the standard output (`stdout`).
index 06f5e2e..f6a6987 100644 (file)
@@ -65,3 +65,11 @@ int file_stdin_poll_in_(void) {
        }
        return res > 0;
 }
+
+FILE* file_int_fdtostream(int fd, char* mode){
+       return fdopen(fd, mode);
+}
+
+int file_NativeFile_NativeFile_set_buffering_type_0(FILE* f, int buf_sz, int mode){
+       return setvbuf(f, NULL, mode, buf_sz);
+}
index 1f5b183..d8d9b4b 100644 (file)
@@ -24,6 +24,8 @@ extern int string_NativeString_NativeString_file_exists_0(char *f);
 extern void *string_NativeString_NativeString_file_stat_0(char *f);
 extern void *file_NativeFile_NativeFile_file_stat_0(FILE *f);
 extern int string_NativeString_NativeString_file_delete_0(char *f);
+FILE* file_int_fdtostream(int fd, char* mode);
+int file_NativeFile_NativeFile_set_buffering_type_0(FILE* f, int buf_sz, int mode);
 
 #define file_NativeFile_NativeFile_io_read_2(p, b, l) fread((b), 1, (l), (FILE*)(p))
 #define file_NativeFile_NativeFile_io_write_2(p, b, l) fwrite((b), 1, (l), (FILE*)(p))
@@ -40,6 +42,9 @@ extern int string_NativeString_NativeString_file_delete_0(char *f);
 #define file_FileStat_FileStat_ctime_0(self) (((struct stat*)self)->st_ctime)
 #define file_FileStat_FileStat_mtime_0(self) (((struct stat*)self)->st_mtime)
 #define file_FileStat_FileStat_size_0(self) (((struct stat*)self)->st_size)
+#define file_Sys_Sys_buffer_mode_full_0(self) _IOFBF
+#define file_Sys_Sys_buffer_mode_line_0(self) _IOLBF
+#define file_Sys_Sys_buffer_mode_none_0(self) _IONBF
 
 #define string_NativeString_NativeString_file_mkdir_0(p) (mkdir(p, 0777))
 #define string_NativeString_NativeString_file_getcwd_0(p) (getcwd(NULL, 0))
index 4139e45..933523a 100644 (file)
 module stream
 
 intrude import ropes
+import error
 
 in "C" `{
        #include <unistd.h>
-       #include <poll.h>
-       #include <errno.h>
        #include <string.h>
        #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 +48,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
@@ -74,6 +87,7 @@ interface IStream
        # NOTE: Only LINE FEED (`\n`) is considered to delimit the end of lines.
        fun read_line: String
        do
+               if last_error != null then return ""
                assert not eof
                var s = new FlatBuffer
                append_line_to(s)
@@ -106,6 +120,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
@@ -119,6 +134,7 @@ interface IStream
        # SEE: `read_line` for details.
        fun append_line_to(s: Buffer)
        do
+               if last_error != null then return
                loop
                        var x = read_char
                        if x == -1 then
@@ -137,7 +153,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)
@@ -146,7 +162,7 @@ interface PollableIStream
 end
 
 # Abstract output stream
-interface OStream
+abstract class OStream
        super IOS
        # write a string
        fun write(s: Text) is abstract
@@ -189,7 +205,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
@@ -203,6 +220,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
@@ -221,6 +239,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
@@ -294,140 +313,11 @@ abstract class BufferedIStream
 end
 
 # An Input/Output Stream
-interface IOStream
+abstract class IOStream
        super IStream
        super OStream
 end
 
-##############################################################"
-
-# A File Descriptor Stream.
-abstract class FDStream
-       super IOS
-       # File description
-       var fd: Int
-
-       redef fun close do native_close(fd)
-
-       private fun native_close(i: Int): Int is extern "stream_FDStream_FDStream_native_close_1"
-       private fun native_read_char(i: Int): Int is extern "stream_FDStream_FDStream_native_read_char_1"
-       private fun native_read(i: Int, buf: NativeString, len: Int): Int is extern "stream_FDStream_FDStream_native_read_3"
-       private fun native_write(i: Int, buf: NativeString, len: Int): Int is extern "stream_FDStream_FDStream_native_write_3"
-       private fun native_write_char(i: Int, c: Char): Int is extern "stream_FDStream_FDStream_native_write_char_2"
-end
-
-# An Input File Descriptor Stream.
-class FDIStream
-       super FDStream
-       super IStream
-       redef var eof: Bool = false
-       
-       redef fun read_char
-       do
-               var nb = native_read_char(fd)
-               if nb == -1 then eof = true
-               return nb
-       end
-end
-
-# An Output File Descriptor Stream.
-class FDOStream
-       super FDStream
-       super OStream
-       redef var is_writable = true
-
-       redef fun write(s)
-       do
-               var nb = native_write(fd, s.to_cstring, s.length)
-               if nb < s.length then is_writable = false
-       end
-end
-
-# An Input/Output File Descriptor Stream.
-class FDIOStream
-       super FDIStream
-       super FDOStream
-       super IOStream
-end
-
-redef interface Object
-       # returns first available stream to read or write to
-       # return null on interruption (possibly a signal)
-       protected fun poll( streams : Sequence[FDStream] ) : nullable FDStream
-       do
-               var in_fds = new Array[Int]
-               var out_fds = new Array[Int]
-               var fd_to_stream = new HashMap[Int,FDStream]
-               for s in streams do
-                       var fd = s.fd
-                       if s isa FDIStream then in_fds.add( fd )
-                       if s isa FDOStream then out_fds.add( fd )
-
-                       fd_to_stream[fd] = s
-               end
-
-               var polled_fd = intern_poll( in_fds, out_fds )
-
-               if polled_fd == null then
-                       return null
-               else
-                       return fd_to_stream[polled_fd]
-               end
-       end
-
-       private fun intern_poll(in_fds: Array[Int], out_fds: Array[Int]) : nullable Int is extern import Array[Int].length, Array[Int].[], Int.as(nullable Int) `{
-               int in_len, out_len, total_len;
-               struct pollfd *c_fds;
-               sigset_t sigmask;
-               int i;
-               int first_polled_fd = -1;
-               int result;
-
-               in_len = Array_of_Int_length( in_fds );
-               out_len = Array_of_Int_length( out_fds );
-               total_len = in_len + out_len;
-               c_fds = malloc( sizeof(struct pollfd) * total_len );
-
-               /* input streams */
-               for ( i=0; i<in_len; i ++ ) {
-                       int fd;
-                       fd = Array_of_Int__index( in_fds, i );
-
-                       c_fds[i].fd = fd;
-                       c_fds[i].events = POLLIN;
-               }
-
-               /* output streams */
-               for ( i=0; i<out_len; i ++ ) {
-                       int fd;
-                       fd = Array_of_Int__index( out_fds, i );
-
-                       c_fds[i].fd = fd;
-                       c_fds[i].events = POLLOUT;
-               }
-
-               /* poll all fds, unlimited timeout */
-               result = poll( c_fds, total_len, -1 );
-
-               if ( result > 0 ) {
-                       /* analyse results */
-                       for ( i=0; i<total_len; i++ )
-                               if ( c_fds[i].revents & c_fds[i].events || /* awaited event */
-                                        c_fds[i].revents & POLLHUP ) /* closed */
-                               {
-                                       first_polled_fd = c_fds[i].fd;
-                                       break;
-                               }
-
-                       return Int_as_nullable( first_polled_fd );
-               }
-               else if ( result < 0 )
-                       fprintf( stderr, "Error in Stream:poll: %s\n", strerror( errno ) );
-
-               return null_Int();
-       `}
-end
-
 # Stream to a String.
 #
 # Mainly used for compatibility with OStream type and tests.
diff --git a/lib/standard/stream_nit.c b/lib/standard/stream_nit.c
deleted file mode 100644 (file)
index 14bfece..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-/* This file is part of NIT ( http://www.nitlanguage.org ).
- *
- * Copyright 2004-2008 Jean Privat <jean@pryen.org>
- *
- * This file is free software, which comes along with NIT.  This software is
- * distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
- * without  even  the implied warranty of  MERCHANTABILITY or  FITNESS FOR A 
- * PARTICULAR PURPOSE.  You can modify it is you want,  provided this header
- * is kept unaltered, and a notification of the changes is added.
- * You  are  allowed  to  redistribute it and sell it, alone or is a part of
- * another product.
- */
-
-#include "stream_nit.h"
-
-int stream_FDStream_FDStream_native_read_char_1(void *s, int fd) {
-       int result;
-       char buf;
-       ssize_t r = read(fd, &buf, 1);
-       if (r == 0)
-               result = -1;
-       else
-               result = buf;
-       return result;
-}
diff --git a/lib/standard/stream_nit.h b/lib/standard/stream_nit.h
deleted file mode 100644 (file)
index 3a4d51e..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-#ifndef __STREAM_NIT_H
-#define __STREAM_NIT_H
-/* This file is part of NIT ( http://www.nitlanguage.org ).
- *
- * Copyright 2004-2008 Jean Privat <jean@pryen.org>
- *
- * This file is free software, which comes along with NIT.  This software is
- * distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
- * without  even  the implied warranty of  MERCHANTABILITY or  FITNESS FOR A 
- * PARTICULAR PURPOSE.  You can modify it is you want,  provided this header
- * is kept unaltered, and a notification of the changes is added.
- * You  are  allowed  to  redistribute it and sell it, alone or is a part of
- * another product.
- */
-
-#include <unistd.h>
-
-int stream_FDStream_FDStream_native_read_char_1(void *s, int fd);
-
-#define stream_FDStream_FDStream_native_close_1(self, p0) (close(p0))
-#define stream_FDStream_FDStream_native_read_3(s, i, b, l) read((i), ((b)), ((l)))
-#define stream_FDStream_FDStream_native_write_3(s, i, b, l) write((i), ((b)), ((l)))
-#define stream_FDStream_FDStream_native_write_char_2(s, i, c) write((i), (char[]){(c)}, 1 )
-
-#endif
index e3cc1ca..064395d 100644 (file)
@@ -21,6 +21,7 @@ import literal
 import semantize
 private import parser::tables
 import mixin
+import primitive_types
 
 redef class ToolContext
        # --discover-call-trace
@@ -796,6 +797,12 @@ redef class AMethPropdef
                else if pname == "exit" then
                        exit(args[1].to_i)
                        abort
+               else if pname == "buffer_mode_full" then
+                       return v.int_instance(sys.buffer_mode_full)
+               else if pname == "buffer_mode_line" then
+                       return v.int_instance(sys.buffer_mode_line)
+               else if pname == "buffer_mode_none" then
+                       return v.int_instance(sys.buffer_mode_none)
                else if pname == "sys" then
                        return v.mainobj
                else if cname == "Int" then
@@ -1013,43 +1020,51 @@ redef class AMethPropdef
                        end
                else if cname == "NativeFile" then
                        if pname == "native_stdout" then
-                               var instance = new PrimitiveInstance[OStream](mpropdef.mclassdef.mclass.mclass_type, sys.stdout)
+                               var inst = new PrimitiveNativeFile.native_stdout
+                               var instance = new PrimitiveInstance[PrimitiveNativeFile](mpropdef.mclassdef.mclass.mclass_type, inst)
                                v.init_instance_primitive(instance)
                                return instance
                        else if pname == "native_stdin" then
-                               var instance = new PrimitiveInstance[IStream](mpropdef.mclassdef.mclass.mclass_type, sys.stdin)
+                               var inst = new PrimitiveNativeFile.native_stdin
+                               var instance = new PrimitiveInstance[PrimitiveNativeFile](mpropdef.mclassdef.mclass.mclass_type, inst)
                                v.init_instance_primitive(instance)
                                return instance
                        else if pname == "native_stderr" then
-                               var instance = new PrimitiveInstance[OStream](mpropdef.mclassdef.mclass.mclass_type, sys.stderr)
+                               var inst = new PrimitiveNativeFile.native_stderr
+                               var instance = new PrimitiveInstance[PrimitiveNativeFile](mpropdef.mclassdef.mclass.mclass_type, inst)
                                v.init_instance_primitive(instance)
                                return instance
                        else if pname == "io_open_read" then
                                var a1 = args[1].val.as(Buffer)
-                               var instance = new PrimitiveInstance[IStream](mpropdef.mclassdef.mclass.mclass_type, new IFStream.open(a1.to_s))
+                               var inst = new PrimitiveNativeFile.io_open_read(a1.to_s)
+                               var instance = new PrimitiveInstance[PrimitiveNativeFile](mpropdef.mclassdef.mclass.mclass_type, inst)
                                v.init_instance_primitive(instance)
                                return instance
                        else if pname == "io_open_write" then
                                var a1 = args[1].val.as(Buffer)
-                               var instance = new PrimitiveInstance[OStream](mpropdef.mclassdef.mclass.mclass_type, new OFStream.open(a1.to_s))
+                               var inst = new PrimitiveNativeFile.io_open_write(a1.to_s)
+                               var instance = new PrimitiveInstance[PrimitiveNativeFile](mpropdef.mclassdef.mclass.mclass_type, inst)
                                v.init_instance_primitive(instance)
                                return instance
                        end
                        var recvval = args.first.val
                        if pname == "io_write" then
                                var a1 = args[1].val.as(Buffer)
-                               recvval.as(OStream).write(a1.substring(0, args[2].to_i).to_s)
-                               return args[2]
+                               return v.int_instance(recvval.as(PrimitiveNativeFile).io_write(a1.to_cstring, args[2].to_i))
                        else if pname == "io_read" then
-                               var str = recvval.as(IStream).read(args[2].to_i)
                                var a1 = args[1].val.as(Buffer)
-                               new FlatBuffer.from(str).copy(0, str.length, a1.as(FlatBuffer), 0)
-                               return v.int_instance(str.length)
+                               var ns = new NativeString(a1.length)
+                               var len = recvval.as(PrimitiveNativeFile).io_read(ns, args[2].to_i)
+                               a1.clear
+                               a1.append(ns.to_s_with_length(len))
+                               return v.int_instance(len)
+                       else if pname == "flush" then
+                               recvval.as(PrimitiveNativeFile).flush
+                               return null
                        else if pname == "io_close" then
-                               recvval.as(IOS).close
-                               return v.int_instance(0)
-                       else if pname == "address_is_null" then
-                               return v.false_instance
+                               return v.int_instance(recvval.as(PrimitiveNativeFile).io_close)
+                       else if pname == "set_buffering_type" then
+                               return v.int_instance(recvval.as(PrimitiveNativeFile).set_buffering_type(args[1].to_i, args[2].to_i))
                        end
                else if pname == "calloc_array" then
                        var recvtype = args.first.mtype.as(MClassType)
@@ -1095,6 +1110,10 @@ redef class AMethPropdef
                else if pname == "errno" then
                        return v.int_instance(sys.errno)
                else if pname == "address_is_null" then
+                       var recv = args[0]
+                       if recv isa PrimitiveInstance[PrimitiveNativeFile] then
+                               return v.bool_instance(recv.val.address_is_null)
+                       end
                        return v.false_instance
                end
                return v.error_instance
diff --git a/src/interpreter/primitive_types.nit b/src/interpreter/primitive_types.nit
new file mode 100644 (file)
index 0000000..8fe483d
--- /dev/null
@@ -0,0 +1,61 @@
+# This file is part of NIT ( http://www.nitlanguage.org ).
+#
+# This file is free software, which comes along with NIT. This software is
+# distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+# without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE. You can modify it is you want, provided this header
+# is kept unaltered, and a notification of the changes is added.
+# You are allowed to redistribute it and sell it, alone or is a part of
+# another product.
+
+# Encapsulates all primitive data types of nit
+#
+# Ensures that the use in the interpreter is independant of the
+# underlying implementation and that the services are semantically correct.
+module primitive_types
+
+intrude import standard::file
+
+# Wrapper for `NativeFile`
+class PrimitiveNativeFile
+
+       var file: FStream
+
+       init native_stdin do
+               file = new IFStream.from_fd(0)
+       end
+
+       init native_stdout do
+               file = new OFStream.from_fd(1)
+       end
+
+       init native_stderr do
+               file = new OFStream.from_fd(2)
+       end
+
+       init io_open_read(path: String) do
+               file = new IFStream.open(path.to_s)
+       end
+
+       init io_open_write(path: String) do
+               file = new OFStream.open(path.to_s)
+       end
+
+       fun address_is_null: Bool do return file._file.address_is_null
+
+       fun io_read(buf: NativeString, len: Int): Int do return file._file.io_read(buf, len)
+
+       fun io_write(buf: NativeString, len: Int): Int do return file._file.io_write(buf, len)
+
+       fun io_close: Int do return file._file.io_close
+
+       fun file_stat: FileStat do return file._file.file_stat
+
+       fun fileno: Int do return file._file.fileno
+
+       fun flush: Int do return file._file.flush
+
+       fun set_buffering_type(size, mode: Int): Int do
+               return file._file.set_buffering_type(size, mode)
+       end
+end
index e95605c..62be912 100644 (file)
@@ -8,10 +8,10 @@ import serialization
 redef class Deserializer
        redef fun deserialize_class(name)
        do
+               if name == "Array[Object]" then return new Array[Object].from_deserializer(self)
                if name == "Array[nullable Object]" then return new Array[nullable Object].from_deserializer(self)
                if name == "Array[Serializable]" then return new Array[Serializable].from_deserializer(self)
                if name == "Array[String]" then return new Array[String].from_deserializer(self)
-               if name == "Array[Object]" then return new Array[Object].from_deserializer(self)
                return super
        end
 end
index 2529d3a..5f9676c 100644 (file)
@@ -1,4 +1,4 @@
 A hello world!
-C hello world!
 B hello world!
+C hello world!
 D hello world!
index 514b4d6..6803f77 100644 (file)
@@ -4,9 +4,9 @@ c
 d
 e
 f
-e
-f
 remove: a
 remove: b
 remove: c
 remove: d
+e
+f
index e11e7e7..fb6d6df 100644 (file)
@@ -1,4 +1,4 @@
 Created in Nit
-Also created in Nit
 Created in Java
+Also created in Nit
 Also created in Java
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'
index 2972528..9fb5305 100644 (file)
@@ -1,14 +1,14 @@
+Compilation des classes Java ...
+Initialisation de la JVM ...
+---------------------Test 1----------------------
 From java, pushing premier
 From java, pushing deuxi?me
 From java, pushing troisi?me
 From java, popping premier
-From java, popping deuxi?me
-From java, popping troisi?me
-Compilation des classes Java ...
-Initialisation de la JVM ...
----------------------Test 1----------------------
 premier
+From java, popping deuxi?me
 deuxième
+From java, popping troisi?me
 troisième
 --------------------Test 2---------------------
 true
index c1e3e84..6de686a 100644 (file)
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-import stream
+import file
 
-var fd_in = new FDIStream(0)
-var fd_out = new FDOStream(1)
-var fd_err = new FDOStream(2)
+var fd_in = new IFStream.from_fd(0)
+var fd_out = new OFStream.from_fd(1)
+var fd_err = new OFStream.from_fd(2)
 
 fd_out.write("Hello\n")
 
 var s = fd_in.read_line
 fd_out.write(s)
+fd_out.write("\n")
 
 fd_err.write("World\n")
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)
index a893976..7981d06 100644 (file)
@@ -25,7 +25,7 @@ p1 = new IProcess( "sleep", "0.2" )
 p2 = new IProcess( "sleep", "0.1" )
 p3 = new IProcess( "sleep", "0.4" )
 
-var order = new Array[FDStream]
+var order = new Array[FStream]
 var streams = [p1.stream_in, p2.stream_in, p3.stream_in]
 
 while not streams.is_empty do
@@ -33,7 +33,7 @@ while not streams.is_empty do
        if s == null then continue # may have been interrupted
 
        order.add( s )
-       streams.remove( s.as(FDIStream ) )
+       streams.remove( s.as(IFStream ) )
 end
 
 print order[0] == p2.stream_in