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