Reads a character. Returns null on EOF or timeout

Returns unicode replacement character '�' if an invalid byte sequence is read.

read_char may block if:

  • No byte could be read from the current buffer
  • An incomplete char is partially read, and more bytes are required for full decoding.

Property definitions

core $ Reader :: read_char
	# Reads a character. Returns `null` on EOF or timeout
	#
	# Returns unicode replacement character '�' if an
	# invalid byte sequence is read.
	#
	# `read_char` may block if:
	#
	# * No byte could be read from the current buffer
	# * An incomplete char is partially read, and more bytes are
	#   required for full decoding.
	fun read_char: nullable Char do
		if eof then return null
		var cod = codec
		var codet_sz = cod.codet_size
		var lk = lookahead
		var llen = lookahead_length
		if llen < codet_sz then
			llen += raw_read_bytes(lk.fast_cstring(llen), codet_sz - llen)
		end
		if llen < codet_sz then
			lookahead_length = 0
			return 0xFFFD.code_point
		end
		var ret = cod.is_valid_char(lk, codet_sz)
		var max_llen = cod.max_lookahead
		while ret == 1 and llen < max_llen do
			var rd = raw_read_bytes(lk.fast_cstring(llen), codet_sz)
			if rd < codet_sz then
				llen -= codet_sz
				if llen > 0 then
					lookahead.lshift(codet_sz, llen, codet_sz)
				end
				lookahead_length = llen.max(0)
				return 0xFFFD.code_point
			end
			llen += codet_sz
			ret = cod.is_valid_char(lk, llen)
		end
		if ret == 0 then
			var c = cod.decode_char(lk)
			var clen = c.u8char_len
			llen -= clen
			if llen > 0 then
				lookahead.lshift(clen, llen, clen)
			end
			lookahead_length = llen
			return c
		end
		if ret == 2 or ret == 1 then
			llen -= codet_sz
			if llen > 0 then
				lookahead.lshift(codet_sz, llen, codet_sz)
			end
			lookahead_length = llen
			return 0xFFFD.code_point
		end
		# Should not happen if the decoder works properly
		var arr = new Array[Object]
		arr.push "Decoder error: could not decode nor recover from byte sequence ["
		for i in [0 .. llen[ do
			arr.push lk[i]
			arr.push ", "
		end
		arr.push "]"
		var err = new IOError(arr.plain_to_s)
		err.cause = last_error
		last_error = err
		return 0xFFFD.code_point
	end
lib/core/stream.nit:131,2--199,4

core $ ProcessReader :: read_char
	redef fun read_char do return stream_in.read_char
lib/core/exec.nit:350,2--50

filter_stream $ StreamCat :: read_char
	redef fun read_char
	do
		assert not eof
		return stream.read_char
	end
lib/filter_stream/filter_stream.nit:68,2--72,4