| ... | ... | @@ -683,25 +683,73 @@ test "import io tests" { |
| 683 | 683 | } |
| 684 | 684 | } |
| 685 | 685 | |
| 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(); |
| 691 | 696 | while (true) { |
| 692 | | const byte = stream.readByte() catch return error.EndOfFile; |
| 697 | const byte = try stream.readByte(); |
| 693 | 698 | switch (byte) { |
| 694 | 699 | '\r' => { |
| 695 | 700 | // 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..]; |
| 704 | 703 | }, |
| 704 | '\n' => return buf.toSlice()[start..], |
| 705 | else => try buf.appendByte(byte), |
| 705 | 706 | } |
| 706 | 707 | } |
| 707 | 708 | } |
| 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 | } |