# Reads a String of at most `i` length
fun read(i: Int): String do
+ assert i >= 0
var cs = new CString(i)
var rd = read_bytes_to_cstring(cs, i)
+ if rd < 0 then return ""
return codec.decode_string(cs, rd)
end
# Reads up to `max` bytes from source
fun read_bytes(max: Int): Bytes do
+ assert max >= 0
var cs = new CString(max)
var rd = read_bytes_to_cstring(cs, max)
return new Bytes(cs, rd, max)
else
lookahead_length = 0
end
- return rd + raw_read_bytes(bytes, max - rd)
+ return rd + raw_read_bytes(bytes.fast_cstring(rd), max - rd)
end
# Read a string until the end of the line.
# Is there something to read.
# This function returns 'false' if there is something to read.
- fun eof: Bool is abstract
+ fun eof: Bool do
+ if lookahead_length > 0 then return false
+ lookahead_length = raw_read_bytes(lookahead, 1)
+ return lookahead_length <= 0
+ end
# Read the next sequence of non whitespace characters.
#
redef fun write_to(stream) do stream.write(self)
end
-# Input streams with a buffered input for efficiency purposes
-abstract class BufferedReader
- super Reader
-
- redef fun raw_read_byte
- do
- if last_error != null then return -1
- if eof then
- last_error = new IOError("Stream has reached eof")
- return -1
- end
- var c = _buffer[_buffer_pos]
- _buffer_pos += 1
- return c.to_i
- end
-
- # Resets the internal buffer
- fun buffer_reset do
- _buffer_length = 0
- _buffer_pos = 0
- end
-
- # Peeks up to `n` bytes in the buffer
- #
- # The operation does not consume the buffer
- #
- # ~~~nitish
- # var x = new FileReader.open("File.txt")
- # assert x.peek(5) == x.read(5)
- # ~~~
- fun peek(i: Int): Bytes do
- if eof then return new Bytes.empty
- var remsp = _buffer_length - _buffer_pos
- if i <= remsp then
- var bf = new Bytes.with_capacity(i)
- bf.append_ns_from(_buffer, i, _buffer_pos)
- return bf
- end
- var bf = new Bytes.with_capacity(i)
- bf.append_ns_from(_buffer, remsp, _buffer_pos)
- _buffer_pos = _buffer_length
- read_intern(i - bf.length, bf)
- remsp = _buffer_length - _buffer_pos
- var full_len = bf.length + remsp
- if full_len > _buffer_capacity then
- var c = _buffer_capacity
- while c < full_len do c = c * 2 + 2
- _buffer_capacity = c
- end
- var nns = new CString(_buffer_capacity)
- bf.items.copy_to(nns, bf.length, 0, 0)
- _buffer.copy_to(nns, remsp, _buffer_pos, bf.length)
- _buffer = nns
- _buffer_pos = 0
- _buffer_length = full_len
- return bf
- end
-
- redef fun read_bytes_to_cstring(buf, i)
- do
- if last_error != null then return 0
- var bbf = new Bytes(buf, 0, i)
- return read_intern(i, bbf)
- end
-
- # Fills `buf` with at most `i` bytes read from `self`
- private fun read_intern(i: Int, buf: Bytes): Int do
- if eof then return 0
- var p = _buffer_pos
- var bufsp = _buffer_length - p
- if bufsp >= i then
- _buffer_pos += i
- buf.append_ns_from(_buffer, i, p)
- return i
- end
- _buffer_pos = _buffer_length
- var readln = _buffer_length - p
- buf.append_ns_from(_buffer, readln, p)
- var rd = read_intern(i - readln, buf)
- return rd + readln
- end
-
- redef fun read_all_bytes
- do
- if last_error != null then return new Bytes.empty
- var s = new Bytes.with_capacity(10)
- var b = _buffer
- while not eof do
- var j = _buffer_pos
- var k = _buffer_length
- var rd_sz = k - j
- s.append_ns_from(b, rd_sz, j)
- _buffer_pos = k
- fill_buffer
- end
- return s
- end
-
- redef fun append_line_to(s)
- do
- var lb = new Bytes.with_capacity(10)
- loop
- # First phase: look for a '\n'
- var i = _buffer_pos
- while i < _buffer_length and _buffer[i] != 0xAu8 do
- i += 1
- end
-
- var eol
- if i < _buffer_length then
- assert _buffer[i] == 0xAu8
- i += 1
- eol = true
- else
- eol = false
- end
-
- # if there is something to append
- if i > _buffer_pos then
- # Copy from the buffer to the string
- var j = _buffer_pos
- while j < i do
- lb.add(_buffer[j])
- j += 1
- end
- _buffer_pos = i
- else
- assert end_reached
- s.append lb.to_s
- return
- end
-
- if eol then
- # so \n is found
- s.append lb.to_s
- return
- else
- # so \n is not found
- if end_reached then
- s.append lb.to_s
- return
- end
- fill_buffer
- end
- end
- end
-
- redef fun eof
- do
- if _buffer_pos < _buffer_length then return false
- if end_reached then return true
- fill_buffer
- return _buffer_pos >= _buffer_length and end_reached
- end
-
- # The buffer
- private var buffer: CString = new CString(0)
-
- # The current position in the buffer
- private var buffer_pos = 0
-
- # Length of the current buffer (i.e. nuber of bytes in the buffer)
- private var buffer_length = 0
-
- # Capacity of the buffer
- private var buffer_capacity = 0
-
- # Fill the buffer
- protected fun fill_buffer is abstract
-
- # Has the last fill_buffer reached the end
- protected fun end_reached: Bool is abstract
-
- # Allocate a `_buffer` for a given `capacity`.
- protected fun prepare_buffer(capacity: Int)
- do
- _buffer = new CString(capacity)
- _buffer_pos = 0 # need to read
- _buffer_length = 0
- _buffer_capacity = capacity
- end
-end
-
# A `Stream` that can be written to and read from
abstract class Duplex
super Reader