| ... | @@ -683,25 +683,73 @@ test "import io tests" { | ... | @@ -683,25 +683,73 @@ test "import io tests" { |
| 683 | } | 683 | } |
| 684 | } | 684 | } |
| 685 | | 685 | |
| 686 | pub fn readLine(buf: []u8) !usize { | 686 | pub fn readLine(buf: *std.Buffer) ![]u8 { |
| 687 | var stdin = getStdIn() catch return error.StdInUnavailable; | 687 | var stdin = try getStdIn(); |
| 688 | var adapter = stdin.inStream(); | 688 | var stdin_stream = stdin.inStream(); |
| 689 | var stream = &adapter.stream; | 689 | return readLineFrom(&stdin_stream.stream, buf); |
| 690 | var index: usize = 0; | 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 | while (true) { | 696 | while (true) { |
| 692 | const byte = stream.readByte() catch return error.EndOfFile; | 697 | const byte = try stream.readByte(); |
| 693 | switch (byte) { | 698 | switch (byte) { |
| 694 | '\r' => { | 699 | '\r' => { |
| 695 | // trash the following \n | 700 | // trash the following \n |
| 696 | _ = stream.readByte() catch return error.EndOfFile; | 701 | _ = try stream.readByte(); |
| 697 | return index; | 702 | return buf.toSlice()[start..]; |
| 698 | }, | | |
| 699 | '\n' => return index, | | |
| 700 | else => { | | |
| 701 | if (index == buf.len) return error.InputTooLong; | | |
| 702 | buf[index] = byte; | | |
| 703 | index += 1; | | |
| 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 | } |