From 98d88e8cd4d11fbfc3b2a73cab12fa81d4ff4a24 Mon Sep 17 00:00:00 2001
From: Philippe Pittoli <karchnu@karchnu.fr>
Date: Sat, 7 May 2022 03:22:10 +0200
Subject: [PATCH] New structure to manage printing into basic memory segments.

---
 src/lib.zig  | 35 ++++++++++++++++++++-
 src/ls.zig   | 86 ++++++++++++++--------------------------------------
 src/test.zig |  8 +++++
 3 files changed, 65 insertions(+), 64 deletions(-)

diff --git a/src/lib.zig b/src/lib.zig
index 51e607c..4b204d7 100644
--- a/src/lib.zig
+++ b/src/lib.zig
@@ -2,14 +2,47 @@ const std   = @import("std");
 const mem   = std.mem;
 const stdout = std.io.getStdOut().writer();
 const process = std.process;
-
+const fmt = std.fmt;
 const fs = std.fs;
+const io = std.io;
 
 pub const warn  = std.debug.print;
 pub fn print(comptime format: []const u8, args: anytype) void {
     nosuspend stdout.print(format, args) catch return;
 }
 
+// const depth = 3;
+
+pub const FixedBufferWriter = struct {
+    const Self = @This();
+
+    depth: u32 = 3,
+    fbs: io.FixedBufferStream([]u8),
+    fmtopts: fmt.FormatOptions = fmt.FormatOptions{},
+
+    pub fn put(self: *Self, str: []const u8) !void {
+        var writer = self.fbs.writer();
+        try fmt.formatType(str, "s", self.fmtopts, writer, self.depth);
+    }
+
+    pub fn putf(self: *Self, comptime format: []const u8, args: anytype) !void {
+        var writer = self.fbs.writer();
+        try fmt.format(writer, format, args);
+    }
+
+    pub fn init(buffer: []u8) Self {
+        return Self{
+            .fbs = io.fixedBufferStream(buffer),
+        };
+    }
+
+    pub fn getWritten(self: *Self) []u8 {
+        defer self.fbs.reset();
+        return self.fbs.getWritten();
+    }
+};
+
+
 pub const CLI = struct {
     const Self = @This();
 
diff --git a/src/ls.zig b/src/ls.zig
index 3b119c8..85d40f2 100644
--- a/src/ls.zig
+++ b/src/ls.zig
@@ -6,7 +6,6 @@ const fs = std.fs;
 const lib = @import("./lib.zig");
 
 const fmt = std.fmt;
-const depth = 3;
 
 const Kind = std.fs.File.Kind;
 const PermissionsUnix = std.fs.File.PermissionsUnix;
@@ -48,29 +47,23 @@ var options: Options = Options {};
 
 fn print_stats(fpath: []const u8, stats: os.system.Stat) !void {
     var buffer = [_]u8 {0} ** (std.fs.MAX_PATH_BYTES + 100);
-    // var it: u16 = 0;
-    var fbs = std.io.fixedBufferStream(&buffer);
-    var writer = fbs.writer();
-
-    const fmtopts = fmt.FormatOptions{};
-    // try std.testing.expect(mem.eql(u8, fbs.getWritten(), "1234"));
-    // fbs.reset();
+    var writer = lib.FixedBufferWriter.init(&buffer);
 
     // print kind (directory, file, pipe, etc.)
-    const kind = fs.File.Stat.system_stat_kind_to_fs_kind(stats);
+    const kind = fs.File.Stat.systemStatKindToFsKind(stats);
     switch (kind) {
-        .File             => try fmt.formatType('-', "c", fmtopts, writer, depth),
-        .Directory        => try fmt.formatType('d', "c", fmtopts, writer, depth),
-        .CharacterDevice  => try fmt.formatType('c', "c", fmtopts, writer, depth),
-        .BlockDevice      => try fmt.formatType('b', "c", fmtopts, writer, depth),
-        .NamedPipe        => try fmt.formatType('p', "c", fmtopts, writer, depth),
-        .SymLink          => try fmt.formatType('s', "c", fmtopts, writer, depth),
-        .UnixDomainSocket => try fmt.formatType('s', "c", fmtopts, writer, depth),
+        .File             => try writer.put("-"),
+        .Directory        => try writer.put("d"),
+        .CharacterDevice  => try writer.put("c"),
+        .BlockDevice      => try writer.put("b"),
+        .NamedPipe        => try writer.put("p"),
+        .SymLink          => try writer.put("s"),
+        .UnixDomainSocket => try writer.put("s"),
         else              => {
             if (builtin.os.tag == .solaris) switch (kind) {
-                .Door      => try fmt.formatType('D', "c", fmtopts, writer, depth), // TODO: what to print here?
-                .EventPort => try fmt.formatType('e', "c", fmtopts, writer, depth), // TODO: what to print here?
-                else       => try fmt.formatType('?', "c", fmtopts, writer, depth),
+                .Door      => try writer.put("D"), // TODO: what to print here?
+                .EventPort => try writer.put("e"), // TODO: what to print here?
+                else       => try writer.put("?"),
             };
         },
     }
@@ -91,40 +84,24 @@ fn print_stats(fpath: []const u8, stats: os.system.Stat) !void {
         for (rights) |r| {
              if (perms.unixHas(c,r)) {
                  switch(r) {
-                     .read    => try fmt.formatType('r', "c", fmtopts, writer, depth),
-                     .write   => try fmt.formatType('w', "c", fmtopts, writer, depth),
-                     .execute => try fmt.formatType('x', "c", fmtopts, writer, depth),
+                     .read    => try writer.put("r"),
+                     .write   => try writer.put("w"),
+                     .execute => try writer.put("x"),
                  }
              }
              else {
-                 try fmt.formatType('-', "c", fmtopts, writer, depth);
+                 try writer.put("-");
              }
         }
     }
 
-    // TODO: print user & group
-    try fmt.formatType('\t',       "c", fmtopts, writer, depth);
-    try fmt.formatType(stats.uid,  "",  fmtopts, writer, depth);
-    try fmt.formatType('\t',       "c", fmtopts, writer, depth);
-    try fmt.formatType(stats.gid,  "",  fmtopts, writer, depth);
+    // TODO: print user & group, not just uid and gid
+    try writer.putf("\t{}\t{}\t", .{stats.uid, stats.gid});
+    try writer.putf("{}\t",       .{stats.size});
+    try writer.putf("{}\t",       .{stats.mtim.tv_sec});
+    try writer.putf("{s}\n",      .{fpath});
 
-    // TODO: print size
-    // TODO: print date last write
-
-    // lib.print("{s}: {}\n", .{fpath, stats});
-
-    // std.mem.copy (u8, buffer[it..], fpath);
-    try fmt.formatType('\t',  "c", fmtopts, writer, depth);
-    try fmt.formatType(fpath, "s", fmtopts, writer, depth);
-    try fmt.formatType('\n',  "c", fmtopts, writer, depth);
-
-    // TODO: print user & group
-    // TODO: print size
-    // TODO: print date last write
-
-    // lib.print("{s}: {}\n", .{fpath, stats});
-
-    return lib.print("{s}", .{fbs.getWritten()});
+    return lib.print("{s}", .{writer.getWritten()});
 }
 
 fn print_file (fpath: []const u8) !void {
@@ -140,24 +117,6 @@ fn print_file (fpath: []const u8) !void {
 
     const bname = path.basename(fpath);
     try print_file_in_dir (dir, bname);
-
-//    // First, try to open the file to stat it.
-//    var f: std.fs.File = undefined;
-//    f = switch (path.isAbsolute(fpath)) {
-//        true => std.fs.openFileAbsolute(fpath, .{.mode = .read_only}),
-//        else => cwd.openFile(fpath, .{.mode = .read_only}),
-//    } catch |err| switch(err) {
-//        error.AccessDenied => {
-//            lib.print("access denied\n", .{});
-//            // try to read the content of the parent directory
-//            return err;
-//        },
-//        else => return err,
-//    };
-//    defer f.close();
-//
-//    const stats = try f.stat();
-//    return print_stats (fpath, stats);
 }
 
 fn print_file_in_dir (dir: fs.Dir, entryname: []const u8) !void {
@@ -165,6 +124,7 @@ fn print_file_in_dir (dir: fs.Dir, entryname: []const u8) !void {
         return lib.print("{s}\n", .{entryname});
     }
 
+    // lib.print("{}\n", .{try dir.statFile(entryname)});
     return try print_stats (entryname, try dir.fstatat(entryname));
 }
 
diff --git a/src/test.zig b/src/test.zig
index fb588d4..12c517a 100644
--- a/src/test.zig
+++ b/src/test.zig
@@ -5,6 +5,14 @@ const fmt = std.fmt;
 
 const default_max_depth = 3;
 
+test "print type" {
+    lib.print("hello\n", .{});
+
+    var buffer = [_]u8{0} ** 3;
+    const T = @TypeOf(std.io.fixedBufferStream(&buffer));
+    lib.print("hello: {}\n", .{T});
+}
+
 test "buffer stuff" {
     var buffer = [_]u8 {0} ** (std.fs.MAX_PATH_BYTES + 100);
     var fbs = std.io.fixedBufferStream(&buffer);