#How to `readUntilDelimiter` on `stdin` in 0.15.1?

1 messages · Page 1 of 1 (latest)

void terrace
#

Heyall! I need a bit of help switching to 0.15.1. What's the new way to do stdin.readUntilDelimiter?

My old code was:

const std = @import("std");
const Config = @import("../lib/config.zig");
const Clap = @import("../lib/clap.zig");

const stdout_handle = std.io.getStdOut();
const stdout = stdout_handle.writer();
const stdin = std.io.getStdIn().reader();

pub fn run(config: *Config, name: []const u8) !void {
    try stdout.print("RPC URL for {s}? ", .{name});
    try config.file.seekFromEnd(0);
    var line_buf: [2048]u8 = undefined;
    const url = try stdin.readUntilDelimiter(&line_buf, '\n');
    const line = try std.fmt.allocPrint(config.allocator, "{s}|{s}\n", .{ name, url });
    defer config.allocator.free(line);
    try config.file.writeAll(line);
}

My new code so far:

const std = @import("std");
const Config = @import("../lib/config.zig");
const Clap = @import("../lib/clap.zig");

var stdout_buffer: [1024]u8 = undefined;
var stdin_buffer: [1024]u8 = undefined;
var stdout_writer = std.fs.File.stdout().writer(&stdout_buffer);
const stdout = &stdout_writer.interface;
const stdin = std.fs.File.stdin().reader(&stdin_buffer);

pub fn run(config: *Config, name: []const u8) !void {
    try stdout.print("RPC URL for {s}? ", .{name});
    try stdout.flush();
    try config.file.seekFromEnd(0);
    var line_buf: [2048]u8 = undefined;
    const url = try stdin.readUntilDelimiter(&line_buf, '\n'); // <-- what do I do here?
    const line = try std.fmt.allocPrint(config.allocator, "{s}|{s}\n", .{ name, url });
    defer config.allocator.free(line);
    try config.file.writeAll(line);
}
smoky jungle
#

Make a stream to read the line into and use stdin.streamDelimiter(it, '\n').

#

Consider std.Io.Writer.Allocating or std.Io.Writer.fixed([]u8)

#

You can .written() or .buffered() to get the result respectively

sacred tapir
#

Here is some sample code that works for me:

test "chunked file read" {
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};

    const f = try std.fs.openFileAbsolute("/home/hugefile.txt", .{ .mode = .read_only });
    defer f.close();

    std.debug.print("File is open.\n", .{});

    // 1K buffer on the heap
    const read_buf = try gpa.allocator().alloc(u8, 1024);
    defer gpa.allocator().free(read_buf);

    var reader = f.reader(read_buf);
    var cr_count: usize = 0;
    var char_count: usize = 0;

    // NOTE: work with the buffer (an array list) that the reader streams into
    var allocating_writer = std.Io.Writer.Allocating.init(gpa.allocator());
    blk: while (true) {
        // NOTE: reader buffer can be as small as [1]u8 since the reader will resize the writter buffer as needed

        allocating_writer.clearRetainingCapacity();

        _ = reader.interface.streamDelimiter(&allocating_writer.writer, '\n') catch |e| {
            switch (e) {
                std.Io.Reader.StreamError.EndOfStream => break :blk,
                else => return e,
            }
        };
        try reader.interface.discardAll(1);

        const line_buf = allocating_writer.written();
        //std.debug.print("Line: {s}\n", .{line_buf});
        cr_count += 1;
        char_count += line_buf.len;
    }

    std.debug.print("CR Count = {d}\n", .{cr_count});
    std.debug.print("Char Count = {d}\n", .{char_count});
}
versed timber
#
pub fn main() !void {
    var stdin_buffer: [2048]u8 = undefined;
    var stdin_reader = std.fs.File.stdin().reader(&stdin_buffer);
    const stdin = &stdin_reader.interface;

    var stdout_buffer: [1024]u8 = undefined;
    var stdout_writer = std.fs.File.stdout().writer(&stdout_buffer);
    const stdout = &stdout_writer.interface;

    while (stdin.takeDelimiterExclusive('\n')) |line| {
        try stdout.print("Got : `{s}'\n", .{line});
        try stdout.flush();
    } else |err| switch (err) {
        error.EndOfStream, // stream ended not on a line break
        error.StreamTooLong, // line could not fit in buffer
        error.ReadFailed, // caller can check reader implementation for diagnostics
        => |e| return e,
    }
}

const std = @import("std");
#

This uses the buffer held by stdin already, if you'd like

#

If you want to use a separate buffer, then you'll need to do what Tetralux suggested

weak leaf
#

@versed timber that would not work. takeDelimiterExclusive doesn't return an optional

abstract igloo
#

it does work with error unions and an else |err| on the loop

versed timber
weak leaf