# `Stream` that can read from a File
class FileReader
super FileStream
- super BufferedReader
super PollableReader
# Misc
# assert l == f.read_line
fun reopen
do
- if not eof and not _file.as(not null).address_is_null then close
+ var fl = _file
+ if fl != null and not fl.address_is_null then close
last_error = null
_file = new NativeFile.io_open_read(path.as(not null).to_cstring)
if _file.as(not null).address_is_null then
last_error = new IOError("Cannot open `{path.as(not null)}`: {sys.errno.strerror}")
- end_reached = true
return
end
- end_reached = false
- buffer_reset
end
- redef fun close
+ redef fun raw_read_byte
do
- super
- buffer_reset
- end_reached = true
+ var nb = _file.as(not null).io_read(write_buffer, 1)
+ if last_error == null and _file.as(not null).ferror then
+ last_error = new IOError("Cannot read `{path.as(not null)}`: {sys.errno.strerror}")
+ end
+ if nb == 0 then return -1
+ return write_buffer[0].to_i
end
- redef fun fill_buffer
+ redef fun raw_read_bytes(cstr, max)
do
- var nb = _file.as(not null).io_read(_buffer, _buffer_capacity)
+ var nb = _file.as(not null).io_read(cstr, max)
if last_error == null and _file.as(not null).ferror then
last_error = new IOError("Cannot read `{path.as(not null)}`: {sys.errno.strerror}")
- end_reached = true
end
- if nb <= 0 then
- end_reached = true
- nb = 0
- end
- _buffer_length = nb
- _buffer_pos = 0
+ return nb
end
- # End of file?
- redef var end_reached = false
+ redef fun eof do
+ var fl = _file
+ if fl == null then return true
+ if fl.address_is_null then return true
+ if last_error != null then return true
+ if super then
+ if last_error != null then return true
+ return fl.feof
+ end
+ return false
+ end
# Open the file at `path` for reading.
#
# var f = new FileReader.open("/etc/issue")
- # assert not f.end_reached
+ # assert not f.eof
# f.close
#
# In case of error, `last_error` is set
#
# f = new FileReader.open("/fail/does not/exist")
- # assert f.end_reached
+ # assert f.eof
# assert f.last_error != null
init open(path: String)
do
self.path = path
- prepare_buffer(100)
_file = new NativeFile.io_open_read(path.to_cstring)
if _file.as(not null).address_is_null then
last_error = new IOError("Cannot open `{path}`: {sys.errno.strerror}")
- end_reached = true
end
end
# This is a low-level method.
init from_fd(fd: Int) do
self.path = ""
- prepare_buffer(1)
_file = fd.fd_to_stream(read_only)
if _file.as(not null).address_is_null then
last_error = new IOError("Error: Converting fd {fd} to stream failed with '{sys.errno.strerror}'")
- end_reached = true
end
end
super FileStream
super Writer
- redef fun write_bytes(s) do
+ redef fun write_bytes_from_cstring(cs, len) do
if last_error != null then return
if not _is_writable then
last_error = new IOError("cannot write to non-writable stream")
return
end
- write_native(s.items, 0, s.length)
+ write_native(cs, 0, len)
end
redef fun write(s)
private fun fd_to_stream(mode: CString): NativeFile `{
return fdopen((int)self, mode);
`}
+
+ # Does the file descriptor `self` refer to a terminal?
+ fun isatty: Bool `{ return isatty(self); `}
end
# Constant for read-only file streams
init do
_file = new NativeFile.native_stdin
path = "/dev/stdin"
- prepare_buffer(1)
end
end
var input = open_ro
var output = dest.open_wo
+ var buffer = new CString(4096)
while not input.eof do
- var buffer = input.read_bytes(4096)
- output.write_bytes buffer
+ var read = input.read_bytes_to_cstring(buffer, 4096)
+ output.write_bytes_from_cstring(buffer, read)
end
input.close
var p = last_byte
var c = its[p]
var st = _first_byte
- while p >= st and c != '.'.ascii do
+ while p >= st and c != u'.' do
p -= 1
c = its[p]
end
var l = s.last_byte
var its = s._items
var min = s._first_byte
- var sl = '/'.ascii
+ var sl = u'/'
while l > min and its[l] == sl do l -= 1
if l == min then return "/"
var ns = l
return (long)res;
`}
- fun write_byte(value: Byte): Int `{
+ fun write_byte(value: Int): Int `{
unsigned char b = (unsigned char)value;
return fwrite(&b, 1, 1, self);
`}
fun ferror: Bool `{ return ferror(self); `}
+ fun feof: Bool `{ return feof(self); `}
+
fun fileno: Int `{ return fileno(self); `}
# Flushes the buffer, forcing the write operation