aboutsummaryrefslogtreecommitdiff
path: root/binaries/mi/mi.zig
blob: 6b7c2a89f9e3b4dfa66af6b59b949b33bd832b1e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
//! mi - Stack viewer for Akiba OS

const colors = @import("colors");
const format = @import("format");
const io = @import("io");
const params = @import("params");
const sys = @import("sys");

const PERM_OWNER: u8 = 1;
const PERM_WORLD: u8 = 2;
const PERM_READ_ONLY: u8 = 3;

export fn main(pc: u32, pv: [*]const [*:0]const u8) u8 {
    const p = params.parse(pc, pv) catch |err| {
        format.color("mi: ", colors.red);
        format.println(@errorName(err));
        return 1;
    };

    var target_path: []const u8 = "";

    if (p.positionals.len > 1) {
        format.colorln("mi: invalid number of positional parameters.", colors.red);
        return 1;
    }

    if (p.named.len > 0) {
        format.colorln("mi: named parameters are not supported.", colors.red);
        return 1;
    }

    if (p.positional(0)) |val| {
        switch (val) {
            .scalar => |s| target_path = s,
            .list => {
                format.colorln("mi: only one location allowed", colors.red);
                return 1;
            },
        }
    }

    display_stack(target_path) catch {
        return 1;
    };

    return 0;
}

fn display_stack(path: []const u8) !void {
    var entries: [128]io.StackEntry = undefined;
    const count = io.viewstack(path, &entries) catch {
        format.color("mi: cannot access '", colors.red);
        format.print(path);
        format.colorln("': No such stack.", colors.red);
        return error.Failed;
    };

    if (count == 0) {
        format.color(path, colors.cyan);
        format.colorln(" is empty.", colors.gray);
        return;
    }

    var table = format.Table.init(&[_]format.Column{
        .{ .name = "Access", .color = colors.cyan },
        .{ .name = "Size", .color = colors.green },
        .{ .name = "Persona", .color = colors.yellow },
        .{ .name = "Modified", .color = colors.blue },
        .{ .name = "Name", .color = colors.white },
    });

    var stack_count: usize = 0;
    var unit_count: usize = 0;
    var total_size: u64 = 0;

    var size_bufs: [128][32]u8 = undefined;
    var date_bufs: [128][32]u8 = undefined;
    var name_bufs: [128][65]u8 = undefined;

    for (0..count) |i| {
        const entry = &entries[i];

        const perms = get_permissions(entry.permission_type);
        const size_str = format.formatSize(entry.size, &size_bufs[i]);
        const date_str = format.formatDate(entry.modified_time, &date_bufs[i]);
        const owner = entry.owner_name[0..entry.owner_name_len];
        const identity = entry.identity[0..entry.identity_len];

        // Build name with optional /
        var name_len: usize = identity.len;
        @memcpy(name_bufs[i][0..identity.len], identity);
        if (entry.is_stack) {
            name_bufs[i][name_len] = '/';
            name_len += 1;
            stack_count += 1;
        } else {
            unit_count += 1;
        }
        total_size += entry.size;

        const name_color: u32 = if (entry.is_stack) colors.cyan else colors.white;

        table.rowColored(
            &[_][]const u8{ perms, size_str, owner, date_str, name_bufs[i][0..name_len] },
            &[_]u32{ colors.cyan, colors.green, colors.yellow, colors.blue, name_color },
        );
    }

    table.print();

    format.print("\n");

    var buf: [16]u8 = undefined;
    format.color(format.intToStr(stack_count, &buf), colors.gray);
    format.color(" stacks  ", colors.gray);
    format.color(format.intToStr(unit_count, &buf), colors.gray);
    format.color(" units  ", colors.gray);
    var size_buf: [32]u8 = undefined;
    format.colorln(format.formatSize(total_size, &size_buf), colors.gray);
}

fn get_permissions(perm_type: u8) []const u8 {
    return switch (perm_type) {
        PERM_OWNER => "Owner",
        PERM_WORLD => "World",
        PERM_READ_ONLY => "Read Only",
        else => "Owner",
    };
}