Hi guys!
I’ve been getting my hands dirty on the new Io reader and I think I need some help understanding the behavior of the takeByte function. Long story short, I’m trying to read from stdin byte by byte using the takeByte function, and it unexpectedly throws EndOfStream.
but if I were to use either std.posix.read or std.c.read the code works like I expected it too, am I missing something important here?
while (true) // this works
var buf: [1]u8 = undefined;
_ = c_api.read(c_api.STDIN_FILENO, &buf, 1);
}
while (true) // this does not (stdin is my std.Io.Reader)
const c = try stdin.takeByte();
}
any help is appreciated!
Hi @elyfheim, welcome to Ziggit!
Can you share what the input for stdin you expect? It would also help to see how you set up the stdin Reader.
Reader.takeByte will return EndOfStream when you reach the end of the file, or in this case, when stdin gets closed. So you may want to catch the error here and use it to break out of the loop.
i’m assuming that the stdin is a pipe input from a different process, that error will be returned if there’s no more data cuz there’s no other way to comunicate that info, think of it like EOF. so you may have to do something like this to ignore that one error
while (true) {
const c = stdin.takeByte() catch |err| {
// here we're returning an error only if it's an error other than error.EndOfStream
if (err != error.EndOfStream) return err;
};
}
It’s actually terminal input (keypresses), and I’m waiting for each of the byte from there so I’m not really sure why it immediately goes to EndOfStream (because the program should technically be blocking while waiting for the keypress)
I’m working with uncooked terminal IO here, as mentioned above I’m basically trying to read each keypresses as bytes so I can proceed accordingly.
var stdin_buffer: [1024]u8 = undefined;
var stdout_writer = std.Io.File.stdout().writer(init.io, &stdout_buffer);
const stdin = &stdin_reader.interface;
here is how I setup my stdin
This setup works for me. I
pub fn main(init: std.process.Init) !void {
const io = init.io;
const stdin_file = std.Io.File.stdin();
const stdout_file = std.Io.File.stdout();
var stdin_buf: [64]u8 = undefined;
var stdout_buf: [64]u8 = undefined;
var stdin = stdin_file.reader(io, &stdin_buf);
var stdout = stdout_file.writer(io, &stdout_buf);
defer stdout.flush() catch {};
while (true) {
const c = try stdin.interface.takeByte();
log.debug("C: {d}", .{c});
}
}
My guess is that there is something in how you are setting the tty to raw mode that is causing a mismatch. Maybe you need to change the file from positional to streaming mode (stdin_file.readerStreaming(io, &stdin_buf);)?
this is what i tried and it works as intended. i got that error only after hitting ctrl-d
const std = @import("std");
pub fn main(init: std.process.Init) !void {
const io = init.io;
var buf: [1024]u8 = undefined;
var stdin = std.Io.File.stdin().reader(io, &buf);
while (true) {
const c = stdin.interface.takeByte() catch |err| {
if (err != error.EndOfStream) return err;
break;
};
std.log.debug("read: {c}", .{c});
}
}
what os are you using
I also have a feeling that the raw mode flags do have some sort of weird interaction I’m not aware of, sadly the streaming mode also does not work
. I’m still reading the reader implementation on the std documentation hopefully I can find something that can help.
I tried catching the error just like in your code snippet and it does catch the error but the issue is the EndOfStream here is unexpected, it’s not supposed to exit that early
. I’m using NixOS (and Zig 0.16.0 for more context)