Merge branch 'patch-sdl'
[nit.git] / lib / standard / stream.nit
index 3204e84..9e2b494 100644 (file)
 # You  are  allowed  to  redistribute it and sell it, alone or is a part of
 # another product.
 
-# This module handle abstract input and output streams
-package stream
+# Input and output streams of characters
+module stream
 
 import string
 
 # Abstract stream class
-class IOS
+interface IOS
        # close the stream
-       meth close is abstract
+       fun close is abstract
 end
 
 # Abstract input streams
-class IStream
-special IOS
+interface IStream
+       super IOS
        # Read a character. Return its ASCII value, -1 on EOF or timeout
-       meth read_char: Int is abstract
+       fun read_char: Int is abstract
 
        # Read at most i bytes
-       meth read(i: Int): String
+       fun read(i: Int): String
        do
                var s = new Buffer.with_capacity(i)
                while i > 0 and not eof do
@@ -42,7 +42,7 @@ special IOS
        end
 
        # Read a string until the end of the line.
-       meth read_line: String
+       fun read_line: String
        do
                assert not eof
                var s = new Buffer
@@ -51,7 +51,7 @@ special IOS
        end
 
        # Read all the stream until the eof.
-       meth read_all: String
+       fun read_all: String
        do
                var s = new Buffer
                while not eof do
@@ -61,10 +61,10 @@ special IOS
                return s.to_s
        end
 
-       # Read a string until the end of the line and append it to `s'.
-       meth append_line_to(s: Buffer)
+       # Read a string until the end of the line and append it to `s`.
+       fun append_line_to(s: Buffer)
        do
-               while true do
+               loop
                        var x = read_char
                        if x == -1 then
                                if eof then return
@@ -77,23 +77,24 @@ special IOS
        end
 
        # Is there something to read.
-       meth eof: Bool is abstract
+       # This function returns 'false' if there is something to read.
+       fun eof: Bool is abstract
 end
 
 # Abstract output stream
-class OStream
-special IOS
+interface OStream
+       super IOS
        # write a string
-       meth write(s: String) is abstract
+       fun write(s: String) is abstract
 
        # Can the stream be used to write
-       meth is_writable: Bool is abstract
+       fun is_writable: Bool is abstract
 end
 
 # Input streams with a buffer
-class BufferedIStream
-special IStream
-       redef meth read_char
+abstract class BufferedIStream
+       super IStream
+       redef fun read_char
        do
                assert not eof
                if _buffer_pos >= _buffer.length then
@@ -107,7 +108,7 @@ special IStream
                return c.ascii
        end
 
-       redef meth read(i)
+       redef fun read(i)
        do
                var s = new Buffer.with_capacity(i)
                var j = _buffer_pos
@@ -129,7 +130,7 @@ special IStream
                return s.to_s
        end
 
-       redef meth read_all
+       redef fun read_all
        do
                var s = new Buffer
                while not eof do
@@ -145,9 +146,9 @@ special IStream
                return s.to_s
        end   
 
-       redef meth append_line_to(s)
+       redef fun append_line_to(s)
        do
-               while true do
+               loop
                        # First phase: look for a '\n'
                        var i = _buffer_pos
                        while i < _buffer.length and _buffer[i] != '\n' do i += 1
@@ -181,59 +182,60 @@ special IStream
                end
        end
 
-       redef meth eof do return _buffer_pos >= _buffer.length and end_reached
+       redef fun eof do return _buffer_pos >= _buffer.length and end_reached
 
        # The buffer
-       attr _buffer: Buffer = null
+       var _buffer: nullable Buffer = null
 
        # The current position in the buffer
-       attr _buffer_pos: Int = 0
+       var _buffer_pos: Int = 0
 
        # Fill the buffer
-       protected meth fill_buffer is abstract
+       protected fun fill_buffer is abstract
 
        # Is the last fill_buffer reach the end 
-       protected meth end_reached: Bool is abstract
+       protected fun end_reached: Bool is abstract
 
-       # Allocate a `_buffer' for a given `capacity'.
-       protected meth prepare_buffer(capacity: Int)
+       # Allocate a `_buffer` for a given `capacity`.
+       protected fun prepare_buffer(capacity: Int)
        do
                _buffer = new Buffer.with_capacity(capacity)
                _buffer_pos = 0 # need to read
        end
 end
 
-class IOStream
-special IStream
-special OStream
+interface IOStream
+       super IStream
+       super OStream
 end
 
 ##############################################################"
 
-class FDStream
-special IOS
+abstract class FDStream
+       super IOS
        # File description
-       attr _fd: Int
+       var fd: Int
 
-       redef meth close do native_close(_fd)
+       redef fun close do native_close(fd)
 
-       private meth native_close(i: Int): Int is extern "stream_FDStream_FDStream_native_close_1"
-       private meth native_read_char(i: Int): Int is extern "stream_FDStream_FDStream_native_read_char_1"
-       private meth native_read(i: Int, buf: NativeString, len: Int): Int is extern "stream_FDStream_FDStream_native_read_3"
-       private meth native_write(i: Int, buf: NativeString, len: Int): Int is extern "stream_FDStream_FDStream_native_write_3"
+       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"
 
-       init(fd: Int) do _fd = fd
+       init(fd: Int) do self.fd = fd
 end
 
 class FDIStream
-special FDStream
-special IStream
-       redef readable attr _eof: Bool = false
+       super FDStream
+       super IStream
+       redef var eof: Bool = false
        
-       redef meth read_char
+       redef fun read_char
        do
-               var nb = native_read_char(_fd)
-               if nb == -1 then _eof = true
+               var nb = native_read_char(fd)
+               if nb == -1 then eof = true
                return nb
        end
 
@@ -241,29 +243,57 @@ special IStream
 end
 
 class FDOStream
-special FDStream
-special OStream
-       redef readable attr _is_writable: Bool
+       super FDStream
+       super OStream
+       redef var is_writable: Bool
 
-       redef meth write(s)
+       redef fun write(s)
        do
-               var nb = native_write(_fd, s.to_cstring, s.length)
-               if nb < s.length then _is_writable = false
+               var nb = native_write(fd, s.to_cstring, s.length)
+               if nb < s.length then is_writable = false
        end
 
        init(fd: Int)
        do
-               _is_writable = true
+               is_writable = true
        end
 end
 
 class FDIOStream
-special FDIStream
-special FDOStream
-special IOStream
+       super FDIStream
+       super FDOStream
+       super IOStream
        init(fd: Int)
        do
-               _fd = fd
-               _is_writable = true
+               self.fd = fd
+               is_writable = true
        end
 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::length, Array::[], nullable Object as ( Int ), Int as nullable
+end