Skip to content

Commit 823969a

Browse files
authored
Implemented new more flexible readLineFrom (#1801)
1 parent b297695 commit 823969a

File tree

2 files changed

+66
-18
lines changed

2 files changed

+66
-18
lines changed

example/guess_number/main.zig

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,15 +24,15 @@ pub fn main() !void {
2424
try stdout.print("\nGuess a number between 1 and 100: ");
2525
var line_buf: [20]u8 = undefined;
2626

27-
const line_len = io.readLine(line_buf[0..]) catch |err| switch (err) {
28-
error.InputTooLong => {
27+
const line = io.readLineSlice(line_buf[0..]) catch |err| switch (err) {
28+
error.OutOfMemory => {
2929
try stdout.print("Input too long.\n");
3030
continue;
3131
},
32-
error.EndOfFile, error.StdInUnavailable => return err,
32+
else => return err,
3333
};
3434

35-
const guess = fmt.parseUnsigned(u8, line_buf[0..line_len], 10) catch {
35+
const guess = fmt.parseUnsigned(u8, line, 10) catch {
3636
try stdout.print("Invalid number.\n");
3737
continue;
3838
};

std/io.zig

Lines changed: 62 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -683,25 +683,73 @@ test "import io tests" {
683683
}
684684
}
685685

686-
pub fn readLine(buf: []u8) !usize {
687-
var stdin = getStdIn() catch return error.StdInUnavailable;
688-
var adapter = stdin.inStream();
689-
var stream = &adapter.stream;
690-
var index: usize = 0;
686+
pub fn readLine(buf: *std.Buffer) ![]u8 {
687+
var stdin = try getStdIn();
688+
var stdin_stream = stdin.inStream();
689+
return readLineFrom(&stdin_stream.stream, buf);
690+
}
691+
692+
/// Reads all characters until the next newline into buf, and returns
693+
/// a slice of the characters read (excluding the newline character(s)).
694+
pub fn readLineFrom(stream: var, buf: *std.Buffer) ![]u8 {
695+
const start = buf.len();
691696
while (true) {
692-
const byte = stream.readByte() catch return error.EndOfFile;
697+
const byte = try stream.readByte();
693698
switch (byte) {
694699
'\r' => {
695700
// trash the following \n
696-
_ = stream.readByte() catch return error.EndOfFile;
697-
return index;
698-
},
699-
'\n' => return index,
700-
else => {
701-
if (index == buf.len) return error.InputTooLong;
702-
buf[index] = byte;
703-
index += 1;
701+
_ = try stream.readByte();
702+
return buf.toSlice()[start..];
704703
},
704+
'\n' => return buf.toSlice()[start..],
705+
else => try buf.appendByte(byte),
705706
}
706707
}
707708
}
709+
710+
test "io.readLineFrom" {
711+
var bytes: [128]u8 = undefined;
712+
const allocator = &std.heap.FixedBufferAllocator.init(bytes[0..]).allocator;
713+
714+
var buf = try std.Buffer.initSize(allocator, 0);
715+
var mem_stream = SliceInStream.init(
716+
\\Line 1
717+
\\Line 22
718+
\\Line 333
719+
);
720+
const stream = &mem_stream.stream;
721+
722+
debug.assert(mem.eql(u8, "Line 1", try readLineFrom(stream, &buf)));
723+
debug.assert(mem.eql(u8, "Line 22", try readLineFrom(stream, &buf)));
724+
debug.assertError(readLineFrom(stream, &buf), error.EndOfStream);
725+
debug.assert(mem.eql(u8, buf.toSlice(), "Line 1Line 22Line 333"));
726+
}
727+
728+
pub fn readLineSlice(slice: []u8) ![]u8 {
729+
var stdin = try getStdIn();
730+
var stdin_stream = stdin.inStream();
731+
return readLineSliceFrom(&stdin_stream.stream, slice);
732+
}
733+
734+
/// Reads all characters until the next newline into slice, and returns
735+
/// a slice of the characters read (excluding the newline character(s)).
736+
pub fn readLineSliceFrom(stream: var, slice: []u8) ![]u8 {
737+
// We cannot use Buffer.fromOwnedSlice, as it wants to append a null byte
738+
// after taking ownership, which would always require an allocation.
739+
var buf = std.Buffer{ .list = std.ArrayList(u8).fromOwnedSlice(debug.failing_allocator, slice) };
740+
try buf.resize(0);
741+
return try readLineFrom(stream, &buf);
742+
}
743+
744+
test "io.readLineSliceFrom" {
745+
var buf: [7]u8 = undefined;
746+
var mem_stream = SliceInStream.init(
747+
\\Line 1
748+
\\Line 22
749+
\\Line 333
750+
);
751+
const stream = &mem_stream.stream;
752+
753+
debug.assert(mem.eql(u8, "Line 1", try readLineSliceFrom(stream, buf[0..])));
754+
debug.assertError(readLineSliceFrom(stream, buf[0..]), error.OutOfMemory);
755+
}

0 commit comments

Comments
 (0)