From 462ad1d66548f6c4fbf3b7b2fe0380b2459a56e0 Mon Sep 17 00:00:00 2001 From: Jordan Orelli Date: Sun, 27 Dec 2020 20:33:36 -0600 Subject: [PATCH] cat takes filename args --- cat/build.zig | 27 ++++++++++++++++ cat/src/main.zig | 82 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 109 insertions(+) create mode 100644 cat/build.zig create mode 100644 cat/src/main.zig diff --git a/cat/build.zig b/cat/build.zig new file mode 100644 index 0000000..4e4389d --- /dev/null +++ b/cat/build.zig @@ -0,0 +1,27 @@ +const Builder = @import("std").build.Builder; + +pub fn build(b: *Builder) void { + // Standard target options allows the person running `zig build` to choose + // what target to build for. Here we do not override the defaults, which + // means any target is allowed, and the default is native. Other options + // for restricting supported target set are available. + const target = b.standardTargetOptions(.{}); + + // Standard release options allow the person running `zig build` to select + // between Debug, ReleaseSafe, ReleaseFast, and ReleaseSmall. + const mode = b.standardReleaseOptions(); + + const exe = b.addExecutable("cat", "src/main.zig"); + exe.setTarget(target); + exe.setBuildMode(mode); + exe.install(); + + const run_cmd = exe.run(); + run_cmd.step.dependOn(b.getInstallStep()); + if (b.args) |args| { + run_cmd.addArgs(args); + } + + const run_step = b.step("run", "Run the app"); + run_step.dependOn(&run_cmd.step); +} diff --git a/cat/src/main.zig b/cat/src/main.zig new file mode 100644 index 0000000..f2c100a --- /dev/null +++ b/cat/src/main.zig @@ -0,0 +1,82 @@ +const std = @import("std"); +const page_allocator = std.heap.page_allocator; +const format = std.fmt.format; +const Allocator = std.mem.Allocator; +const File = std.fs.File; +const ArrayList = std.ArrayList; +const stdout = std.io.getStdOut(); + +pub fn main() !void { + var mem_root = std.heap.GeneralPurposeAllocator(.{}){}; + defer _ = mem_root.deinit(); + + try run(&mem_root.allocator); +} + +fn run(mem: *Allocator) !void { + const stdin = std.io.getStdIn(); + const stderr = std.io.getStdErr(); + + var handles = ArrayList(File).init(mem); + defer handles.deinit(); + + defer { + for (handles.items) |f| { + f.close(); + } + } + + var args = std.process.args(); + defer args.deinit(); + + var path_buffer: [std.fs.MAX_PATH_BYTES]u8 = undefined; + + _ = args.skip(); + while (args.next(mem)) |maybe| { + const arg = try maybe; + defer mem.free(arg); + + if (std.mem.eql(u8, arg, "-")) { + try handles.append(stdin); + } else { + const path = std.fs.realpath(arg, &path_buffer) catch |err| { + stderr.writer().print("Path Error with path {}: {}\n", .{ arg, err }) catch {}; + std.os.exit(1); + }; + const f = std.fs.openFileAbsolute(path, .{ .read = true }) catch |err| { + stderr.writer().print("Open Error with path {}: {}\n", .{ arg, err }) catch {}; + std.os.exit(1); + }; + const fi = try f.stat(); + if (fi.kind != .File) { + stderr.writer().print("File at path {} is not regular file, is: {}\n", .{ arg, fi.kind }) catch {}; + std.os.exit(1); + } + try handles.append(f); + } + } + + const page = try page_allocator.alloc(u8, std.mem.page_size); + defer page_allocator.free(page); + + if (handles.items.len == 0) { + try dump(page, stdin); + return; + } + + for (handles.items) |f| { + try dump(page, f); + } +} + +// dump dumps a file to stdout, utilizing the provided page of memory as a +// transfer buffer. +fn dump(page: []u8, f: File) !void { + while (true) { + var n = try f.read(page); + if (n <= 0) { + return; + } + _ = try stdout.write(page[0..n]); + } +}