blob 65cd2b1e (1905B) - Raw
1 const std = @import("std"); 2 const io = std.io; 3 const process = std.process; 4 const fs = std.fs; 5 const mem = std.mem; 6 const warn = std.log.warn; 7 8 var general_purpose_allocator = std.heap.GeneralPurposeAllocator(.{}){}; 9 const allocator = &general_purpose_allocator.allocator; 10 11 pub fn main() !void { 12 defer _ = general_purpose_allocator.deinit(); 13 14 var args_it = process.args(); 15 const exe = try unwrapArg(args_it.next(allocator).?); 16 defer allocator.free(exe); 17 var catted_anything = false; 18 const stdout_file = io.getStdOut(); 19 20 const cwd = fs.cwd(); 21 22 while (args_it.next(allocator)) |arg_or_err| { 23 const arg = try unwrapArg(arg_or_err); 24 defer allocator.free(arg); 25 if (mem.eql(u8, arg, "-")) { 26 catted_anything = true; 27 try cat_file(stdout_file, io.getStdIn()); 28 } else if (arg[0] == '-') { 29 return usage(exe); 30 } else { 31 const file = cwd.openFile(arg, .{}) catch |err| { 32 warn("Unable to open file: {}\n", .{@errorName(err)}); 33 return err; 34 }; 35 defer file.close(); 36 37 catted_anything = true; 38 try cat_file(stdout_file, file); 39 } 40 } 41 if (!catted_anything) { 42 try cat_file(stdout_file, io.getStdIn()); 43 } 44 } 45 46 fn usage(exe: []const u8) !void { 47 warn("Usage: {} [FILE]...\n", .{exe}); 48 return error.Invalid; 49 } 50 51 // TODO use copy_file_range 52 fn cat_file(stdout: fs.File, file: fs.File) !void { 53 var fifo = std.fifo.LinearFifo(u8, .{ .Static = 1024 * 4 }).init(); 54 55 fifo.pump(file.reader(), stdout.writer()) catch |err| { 56 warn("Unable to read from stream or write to stdout: {}\n", .{@errorName(err)}); 57 return err; 58 }; 59 } 60 61 fn unwrapArg(arg: anyerror![]u8) ![]u8 { 62 return arg catch |err| { 63 warn("Unable to parse command line: {}\n", .{err}); 64 return err; 65 }; 66 }