Post edited for Zig 0.15.1.
We can read the input line with the method streamDelimiterLimit of stdin.reader(buf) .interface.
// On the top of your file
const std = @import("std");
// Inside your function
// Initialize the stdin
// There is no global variables, so you need to do it
var stdin_buffer: [1024]u8 = undefined;
var stdin = std.fs.File.stdin().reader(&stdin_buffer);
// A fix size is fine:
// you don't always want the user to exhaust all the system memory
var line_buffer: [1024]u8 = undefined;
var w: std.io.Writer = .fixed(&line_buffer);
// Read an input until "\n" or end of file, and write it to the buffer
const line_length = try stdin.interface.streamDelimiterLimit(&w, "\n", .unlimited);
// Your input line:
const input_line = line_buffer[0..line_length];
If you want to work on windows as well, you can use the following function:
const std = @import("std");
const builtin = @import("builtin");
fn read_line(line_buffer: []u8, input: *std.io.Reader) ![]u8 {
var w: std.Io.Writer = .fixed(line_buffer);
var line_length = try input.streamDelimiterLimit(&w, '\n', .unlimited);
std.debug.assert(line_length <= line_buffer.len);
// Consume the '\n' with takeByte and throw it away
var next_byte: ?u8 = null;
if (input.takeByte()) |value| {
next_byte = value;
} else |err| switch (err) {
error.EndOfStream => {
std.debug.assert(next_byte == null);
},
else => return err,
}
std.debug.assert(next_byte == '\n' or next_byte == null);
// Trim \r on windows
// @see @Sawcce's answer: https://stackoverflow.com/a/75912768/9959510
// @see https://en.wikipedia.org/wiki/Newline#Representation
if (builtin.os.tag == .windows) {
if (line_length > 0) {
if (next_byte == '\n' and line_buffer[line_length - 1] == '\r') {
line_length -= 1;
}
}
}
return line_buffer[0..line_length];
}
Example
fn ask_number(line_buffer: []u8, input: *std.io.Reader, output: *std.io.Writer) !i64 {
try output.writeAll("A number please: ");
// Flush to write all the message before read the line
try output.flush();
const input_line = try read_line(line_buffer, input);
// Attempt to parse the line into an i64 in base 10.
// If parsing fails (not a valid number or overflow),
// propagates the parsing error.
return std.fmt.parseInt(i64, input_line, 10);
}
pub fn main() !void {
var stdin_buffer: [1024]u8 = undefined;
var stdout_buffer: [1024]u8 = undefined;
var stdin = std.fs.File.stdin().reader(&stdin_buffer);
var stdout = std.fs.File.stdout().writer(&stdout_buffer);
// A capacity to hold any i64 + '\r'
var line_buffer: [1024]u8 = undefined;
const num = try ask_number(line_buffer[0..], &stdin.interface, &stdout.interface);
try stdout.interface.print("Your number: {}.", .{num});
// Flush only in success path, no defer
try stdout.interface.flush();
}
For the new/upcoming IO API, see Don't Forget To Flush by Andrew Kelley.
For the CRLF, see @Sawcce's answer.
See also: Zig 0.15.1 documentation, std.fs.File and std.io.Reader.