1 # This file is part of NIT ( http://www.nitlanguage.org ).
3 # Copyright 2004-2008 Jean Privat <jean@pryen.org>
5 # This file is free software, which comes along with NIT. This software is
6 # distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
7 # without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
8 # PARTICULAR PURPOSE. You can modify it is you want, provided this header
9 # is kept unaltered, and a notification of the changes is added.
10 # You are allowed to redistribute it and sell it, alone or is a part of
13 # Input and output streams of characters
18 # Abstract stream class
24 # Abstract input streams
27 # Read a character. Return its ASCII value, -1 on EOF or timeout
28 fun read_char
: Int is abstract
30 # Read at most i bytes
31 fun read
(i
: Int): String
33 var s
= new Buffer.with_capacity
(i
)
34 while i
> 0 and not eof
do
44 # Read a string until the end of the line.
53 # Read all the stream until the eof.
59 if c
>= 0 then s
.add
(c
.ascii
)
64 # Read a string until the end of the line and append it to `s`.
65 fun append_line_to
(s
: Buffer)
74 if c
== '\n' then return
79 # Is there something to read.
80 # This function returns 'false' if there is something to read.
81 fun eof
: Bool is abstract
84 # Abstract output stream
88 fun write
(s
: String) is abstract
90 # Can the stream be used to write
91 fun is_writable
: Bool is abstract
94 # Input streams with a buffer
95 abstract class BufferedIStream
100 if _buffer_pos
>= _buffer
.length
then
103 if _buffer_pos
>= _buffer
.length
then
106 var c
= _buffer
[_buffer_pos
]
113 var s
= new Buffer.with_capacity
(i
)
115 var k
= _buffer
.length
119 if eof
then return s
.to_s
123 while j
< k
and i
> 0 do
138 var k
= _buffer
.length
149 redef fun append_line_to
(s
)
152 # First phase: look for a '\n'
154 while i
< _buffer
.length
and _buffer
[i
] != '\n' do i
+= 1
156 # if there is something to append
157 if i
> _buffer_pos
then
158 # Enlarge the string (if needed)
159 s
.enlarge
(s
.length
+ i
- _buffer_pos
)
161 # Copy from the buffer to the string
169 if i
< _buffer
.length
then
170 # so \n is in _buffer[i]
171 _buffer_pos
= i
+ 1 # skip \n
185 redef fun eof
do return _buffer_pos
>= _buffer
.length
and end_reached
188 var _buffer
: nullable Buffer = null
190 # The current position in the buffer
191 var _buffer_pos
: Int = 0
194 protected fun fill_buffer
is abstract
196 # Is the last fill_buffer reach the end
197 protected fun end_reached
: Bool is abstract
199 # Allocate a `_buffer` for a given `capacity`.
200 protected fun prepare_buffer
(capacity
: Int)
202 _buffer
= new Buffer.with_capacity
(capacity
)
203 _buffer_pos
= 0 # need to read
212 ##############################################################"
214 abstract class FDStream
219 redef fun close
do native_close
(fd
)
221 private fun native_close
(i
: Int): Int is extern "stream_FDStream_FDStream_native_close_1"
222 private fun native_read_char
(i
: Int): Int is extern "stream_FDStream_FDStream_native_read_char_1"
223 private fun native_read
(i
: Int, buf
: NativeString, len
: Int): Int is extern "stream_FDStream_FDStream_native_read_3"
224 private fun native_write
(i
: Int, buf
: NativeString, len
: Int): Int is extern "stream_FDStream_FDStream_native_write_3"
225 private fun native_write_char
(i
: Int, c
: Char): Int is extern "stream_FDStream_FDStream_native_write_char_2"
227 init(fd
: Int) do self.fd
= fd
233 redef var eof
: Bool = false
237 var nb
= native_read_char
(fd
)
238 if nb
== -1 then eof
= true
248 redef var is_writable
: Bool
252 var nb
= native_write
(fd
, s
.to_cstring
, s
.length
)
253 if nb
< s
.length
then is_writable
= false
273 redef interface Object
274 # returns first available stream to read or write to
275 # return null on interruption (possibly a signal)
276 protected fun poll
( streams
: Sequence[FDStream] ) : nullable FDStream
278 var in_fds
= new Array[Int]
279 var out_fds
= new Array[Int]
280 var fd_to_stream
= new HashMap[Int,FDStream]
283 if s
isa FDIStream then in_fds
.add
( fd
)
284 if s
isa FDOStream then out_fds
.add
( fd
)
289 var polled_fd
= intern_poll
( in_fds
, out_fds
)
291 if polled_fd
== null then
294 return fd_to_stream
[polled_fd
]
298 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