master
 1const std = @import("std");
 2const fs = std.fs;
 3const mem = std.mem;
 4const warn = std.log.warn;
 5const fatal = std.process.fatal;
 6
 7pub fn main() !void {
 8    var arena_instance = std.heap.ArenaAllocator.init(std.heap.page_allocator);
 9    defer arena_instance.deinit();
10    const arena = arena_instance.allocator();
11
12    var threaded: std.Io.Threaded = .init(arena);
13    defer threaded.deinit();
14    const io = threaded.io();
15
16    const args = try std.process.argsAlloc(arena);
17
18    const exe = args[0];
19    var catted_anything = false;
20    var stdout_buffer: [4096]u8 = undefined;
21    var stdout_writer = fs.File.stdout().writerStreaming(&stdout_buffer);
22    const stdout = &stdout_writer.interface;
23    var stdin_reader = fs.File.stdin().readerStreaming(io, &.{});
24
25    const cwd = fs.cwd();
26
27    for (args[1..]) |arg| {
28        if (mem.eql(u8, arg, "-")) {
29            catted_anything = true;
30            _ = try stdout.sendFileAll(&stdin_reader, .unlimited);
31            try stdout.flush();
32        } else if (mem.startsWith(u8, arg, "-")) {
33            return usage(exe);
34        } else {
35            const file = cwd.openFile(arg, .{}) catch |err| fatal("unable to open file: {t}\n", .{err});
36            defer file.close();
37
38            catted_anything = true;
39            var file_reader = file.reader(io, &.{});
40            _ = try stdout.sendFileAll(&file_reader, .unlimited);
41            try stdout.flush();
42        }
43    }
44    if (!catted_anything) {
45        _ = try stdout.sendFileAll(&stdin_reader, .unlimited);
46        try stdout.flush();
47    }
48}
49
50fn usage(exe: []const u8) !void {
51    warn("Usage: {s} [FILE]...\n", .{exe});
52    return error.Invalid;
53}