Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implemented new more flexible readLineFrom #1801

Merged
merged 4 commits into from
Nov 29, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions example/guess_number/main.zig
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,15 @@ pub fn main() !void {
try stdout.print("\nGuess a number between 1 and 100: ");
var line_buf: [20]u8 = undefined;

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

const guess = fmt.parseUnsigned(u8, line_buf[0..line_len], 10) catch {
const guess = fmt.parseUnsigned(u8, line, 10) catch {
try stdout.print("Invalid number.\n");
continue;
};
Expand Down
76 changes: 62 additions & 14 deletions std/io.zig
Original file line number Diff line number Diff line change
Expand Up @@ -683,25 +683,73 @@ test "import io tests" {
}
}

pub fn readLine(buf: []u8) !usize {
var stdin = getStdIn() catch return error.StdInUnavailable;
var adapter = stdin.inStream();
var stream = &adapter.stream;
var index: usize = 0;
pub fn readLine(buf: *std.Buffer) ![]u8 {
var stdin = try getStdIn();
var stdin_stream = stdin.inStream();
return readLineFrom(&stdin_stream.stream, buf);
}

/// Reads all characters until the next newline into buf, and returns
/// a slice of the characters read (excluding the newline character(s)).
pub fn readLineFrom(stream: var, buf: *std.Buffer) ![]u8 {
const start = buf.len();
while (true) {
const byte = stream.readByte() catch return error.EndOfFile;
const byte = try stream.readByte();
switch (byte) {
'\r' => {
// trash the following \n
_ = stream.readByte() catch return error.EndOfFile;
return index;
},
'\n' => return index,
else => {
if (index == buf.len) return error.InputTooLong;
buf[index] = byte;
index += 1;
_ = try stream.readByte();
return buf.toSlice()[start..];
},
'\n' => return buf.toSlice()[start..],
else => try buf.appendByte(byte),
}
}
}

test "io.readLineFrom" {
var bytes: [128]u8 = undefined;
const allocator = &std.heap.FixedBufferAllocator.init(bytes[0..]).allocator;

var buf = try std.Buffer.initSize(allocator, 0);
var mem_stream = SliceInStream.init(
\\Line 1
\\Line 22
\\Line 333
);
const stream = &mem_stream.stream;

debug.assert(mem.eql(u8, "Line 1", try readLineFrom(stream, &buf)));
debug.assert(mem.eql(u8, "Line 22", try readLineFrom(stream, &buf)));
debug.assertError(readLineFrom(stream, &buf), error.EndOfStream);
debug.assert(mem.eql(u8, buf.toSlice(), "Line 1Line 22Line 333"));
}

pub fn readLineSlice(slice: []u8) ![]u8 {
var stdin = try getStdIn();
var stdin_stream = stdin.inStream();
return readLineSliceFrom(&stdin_stream.stream, slice);
}

/// Reads all characters until the next newline into slice, and returns
/// a slice of the characters read (excluding the newline character(s)).
pub fn readLineSliceFrom(stream: var, slice: []u8) ![]u8 {
// We cannot use Buffer.fromOwnedSlice, as it wants to append a null byte
// after taking ownership, which would always require an allocation.
var buf = std.Buffer{ .list = std.ArrayList(u8).fromOwnedSlice(debug.failing_allocator, slice) };
try buf.resize(0);
return try readLineFrom(stream, &buf);
}

test "io.readLineSliceFrom" {
var buf: [7]u8 = undefined;
var mem_stream = SliceInStream.init(
\\Line 1
\\Line 22
\\Line 333
);
const stream = &mem_stream.stream;

debug.assert(mem.eql(u8, "Line 1", try readLineSliceFrom(stream, buf[0..])));
debug.assertError(readLineSliceFrom(stream, buf[0..]), error.OutOfMemory);
}