Tips on handling input from stdin

Hi! I’ve really been enjoying learning Zig, but the lack of good examples and documentation (understandable for a pre-1.0 project, hoping that changes in the future) has been driving me insane so I decided to turn to y’all.

Is there a way to simplify this function or does it look okay (aka is the memcpy necessary here)? The goal is to have the input in a stable buffer (not a slice in the stdin reader’s own internal buffer).

// Reading user input from stdin
fn getInput(stdout: *std.Io.Writer, stdin: *std.Io.Reader, buffer: []u8, prompt: []const u8) ![]u8 {
    try stdout.writeAll(prompt);
    try stdout.flush();

    // Reading up to (but not including) the first newline character
    const input = stdin.takeDelimiterExclusive('\n') catch |err| {
        switch (err) {
            error.StreamTooLong => {
                try stdout.writeAll("Input is too long. Defaulting field to empty.\n");
                // Discarding anything that's left until the intended newline character
                _ = stdin.discardDelimiterInclusive('\n') catch {};
                return "";
            },
            else => return err,
        }
    };
    // Discarding the next character in stdin (the newline character)
    stdin.toss(1);

    // Making sure the received input isn't larger than the buffer to avoid a crash
    if (input.len > buffer.len) {
        try stdout.writeAll("Input is too long. Defaulting field to empty.\n");
        return "";
    }

    // Copying the input into a stable buffer
    const len = @min(input.len, buffer.len);
    @memcpy(buffer[0..len], input[0..len]);
    return buffer[0..len];
}

Looks mostly fine to me, the only thing I can see here is a small redundancy: you check twice if the input is bigger than the buffer - once with if(input.len > buffer.len) and once with @min(input.len, buffer.len).

2 Likes

Oh, yep. Thanks!

1 Like