| ... | ... | @@ -3,37 +3,40 @@ const io = std.io; |
| 3 | 3 | const process = std.process; |
| 4 | 4 | const fs = std.fs; |
| 5 | 5 | const mem = std.mem; |
| 6 | | const warn = std.debug.warn; |
| 7 | | const allocator = std.testing.allocator; |
| 6 | const warn = std.log.warn; |
| 8 | 7 | |
| 9 | 8 | pub fn main() !void { |
| 10 | | var args_it = process.args(); |
| 11 | | const exe = try unwrapArg(args_it.next(allocator).?); |
| 9 | var arena_instance = std.heap.ArenaAllocator.init(std.heap.page_allocator); |
| 10 | defer arena_instance.deinit(); |
| 11 | const arena = &arena_instance.allocator; |
| 12 | |
| 13 | const args = try process.argsAlloc(arena); |
| 14 | |
| 15 | const exe = args[0]; |
| 12 | 16 | var catted_anything = false; |
| 13 | 17 | const stdout_file = io.getStdOut(); |
| 14 | 18 | |
| 15 | 19 | const cwd = fs.cwd(); |
| 16 | 20 | |
| 17 | | while (args_it.next(allocator)) |arg_or_err| { |
| 18 | | const arg = try unwrapArg(arg_or_err); |
| 21 | for (args[1..]) |arg| { |
| 19 | 22 | if (mem.eql(u8, arg, "-")) { |
| 20 | 23 | catted_anything = true; |
| 21 | | try cat_file(stdout_file, io.getStdIn()); |
| 22 | | } else if (arg[0] == '-') { |
| 24 | try stdout_file.writeFileAll(io.getStdIn(), .{}); |
| 25 | } else if (mem.startsWith(u8, arg, "-")) { |
| 23 | 26 | return usage(exe); |
| 24 | 27 | } else { |
| 25 | 28 | const file = cwd.openFile(arg, .{}) catch |err| { |
| 26 | | warn("Unable to open file: {}\n", .{@errorName(err)}); |
| 29 | warn("Unable to open file: {s}\n", .{@errorName(err)}); |
| 27 | 30 | return err; |
| 28 | 31 | }; |
| 29 | 32 | defer file.close(); |
| 30 | 33 | |
| 31 | 34 | catted_anything = true; |
| 32 | | try cat_file(stdout_file, file); |
| 35 | try stdout_file.writeFileAll(file, .{}); |
| 33 | 36 | } |
| 34 | 37 | } |
| 35 | 38 | if (!catted_anything) { |
| 36 | | try cat_file(stdout_file, io.getStdIn()); |
| 39 | try stdout_file.writeFileAll(io.getStdIn(), .{}); |
| 37 | 40 | } |
| 38 | 41 | } |
| 39 | 42 | |
| ... | ... | @@ -41,31 +44,3 @@ fn usage(exe: []const u8) !void { |
| 41 | 44 | warn("Usage: {} [FILE]...\n", .{exe}); |
| 42 | 45 | return error.Invalid; |
| 43 | 46 | } |
| 44 | | |
| 45 | | // TODO use copy_file_range |
| 46 | | fn cat_file(stdout: fs.File, file: fs.File) !void { |
| 47 | | var buf: [1024 * 4]u8 = undefined; |
| 48 | | |
| 49 | | while (true) { |
| 50 | | const bytes_read = file.read(buf[0..]) catch |err| { |
| 51 | | warn("Unable to read from stream: {}\n", .{@errorName(err)}); |
| 52 | | return err; |
| 53 | | }; |
| 54 | | |
| 55 | | if (bytes_read == 0) { |
| 56 | | break; |
| 57 | | } |
| 58 | | |
| 59 | | stdout.writeAll(buf[0..bytes_read]) catch |err| { |
| 60 | | warn("Unable to write to stdout: {}\n", .{@errorName(err)}); |
| 61 | | return err; |
| 62 | | }; |
| 63 | | } |
| 64 | | } |
| 65 | | |
| 66 | | fn unwrapArg(arg: anyerror![]u8) ![]u8 { |
| 67 | | return arg catch |err| { |
| 68 | | warn("Unable to parse command line: {}\n", .{err}); |
| 69 | | return err; |
| 70 | | }; |
| 71 | | } |