stdin_reader.takeDelimiterExclusive returns immediately in a loop instead of blocking for input (Zig 0.16, new Io interface)

I’m building a simple REPL using the new std.Io reader/writer interface in Zig 0.16. The loop is supposed to print a prompt, then block waiting for a line of input:

const std = @import("std");
const Io = std.Io;
pub fn main(init: std.process.Init) !void {
    const arena: std.mem.Allocator = init.arena.allocator();
    const io = init.io;
    _ = try init.minimal.args.toSlice(arena);

    var stdout_buffer: [1024]u8 = undefined;
    var stdout_file_writer: Io.File.Writer = .init(.stdout(), io, &stdout_buffer);
    const stdout_writer = &stdout_file_writer.interface;

    var stdin_buffer: [1024]u8 = undefined;
    var stdin_file_reader: Io.File.Reader = .init(.stdin(), io, &stdin_buffer);
    const stdin_reader = &stdin_file_reader.interface;
    while (true) {
        try stdout_writer.print("db > ", .{});
        try stdout_writer.flush();
        _ = try stdin_reader.takeDelimiterExclusive('\n');
    }
}
PS C:\Users\user\CLionProjects\project> .\zig-out\bin\project.exe
db > example
db > db > db > db > db > db > db > db > db > db > db > db > db > db > db > db > db > db > db > db > db > db > db > db > db > db > db > db > db > db > db > db > db > db > db > db > db > db > db > db > db > db > db > db > db > db > db > db > db > db > db > db > db > db 

Zig 0.16 Windows, same issue with wsl

To progress, you must ‘take’ (or drop) that delimiter you excluded.

its not an issue since this behaviour is described in documentation
https://ziglang.org/documentation/0.16.0/std/#std.Io.Reader.takeDelimiterExclusive

you should probably look at Zig Documentation
for the behaviour you expect

thank you so much
_ = try stdin_reader.takeDelimiterInclusive(‘\n’);
changing Exclusive to Inclusive solved the problem

Consider also just using takeDelimiter('\n') instead:

Returns a slice of the next bytes of buffered data from the stream until delimiter is found, advancing the seek position past the delimiter.

The differences are that takeDelimiterInclusive gives you the delimiter, takeDelimiterExclusive stops right before it, and takeDelimiter doesn’t give you the delimiter, but does move past it, which is often the most useful function.

Edit: So that means that takeDelimiter gives you "example", while takeDelimiterInclusive gives you "example\n".

Another difference is what happens at EndOfStream. takeDelimiterInclusive('\n') does not return the last line if there is no '\n' after it.

test {
    var r: std.Io.Reader = .fixed("example");
    try std.testing.expectEqual(error.EndOfStream, r.takeDelimiterInclusive('\n'));
}
1 Like