oxwm

https://git.tonybtw.com/oxwm.git git://git.tonybtw.com/oxwm.git
3,633 bytes raw
1
const std = @import("std");
2
3
pub const Ram = struct {
4
    format: []const u8,
5
    interval_secs: u64,
6
    color: c_ulong,
7
8
    pub fn init(format: []const u8, interval_secs: u64, color: c_ulong) Ram {
9
        return .{
10
            .format = format,
11
            .interval_secs = interval_secs,
12
            .color = color,
13
        };
14
    }
15
16
    pub fn content(self: *Ram, buffer: []u8) []const u8 {
17
        const file = std.fs.openFileAbsolute("/proc/meminfo", .{}) catch return buffer[0..0];
18
        defer file.close();
19
20
        var read_buffer: [512]u8 = undefined;
21
        const bytes_read = file.read(&read_buffer) catch return buffer[0..0];
22
        const file_content = read_buffer[0..bytes_read];
23
24
        var total: u64 = 0;
25
        var available: u64 = 0;
26
27
        var lines = std.mem.splitScalar(u8, file_content, '\n');
28
        while (lines.next()) |line| {
29
            if (std.mem.startsWith(u8, line, "MemTotal:")) {
30
                total = parse_mem_value(line);
31
            } else if (std.mem.startsWith(u8, line, "MemAvailable:")) {
32
                available = parse_mem_value(line);
33
            }
34
        }
35
36
        if (total == 0) return buffer[0..0];
37
38
        const used = total - available;
39
        const used_gb = @as(f32, @floatFromInt(used)) / 1024.0 / 1024.0;
40
        const total_gb = @as(f32, @floatFromInt(total)) / 1024.0 / 1024.0;
41
        const percent = (@as(f32, @floatFromInt(used)) / @as(f32, @floatFromInt(total))) * 100.0;
42
43
        var val_bufs: [3][16]u8 = undefined;
44
        const used_str = std.fmt.bufPrint(&val_bufs[0], "{d:.1}", .{used_gb}) catch return buffer[0..0];
45
        const total_str = std.fmt.bufPrint(&val_bufs[1], "{d:.1}", .{total_gb}) catch return buffer[0..0];
46
        const percent_str = std.fmt.bufPrint(&val_bufs[2], "{d:.1}", .{percent}) catch return buffer[0..0];
47
48
        return substitute(self.format, buffer, .{
49
            .used = used_str,
50
            .total = total_str,
51
            .percent = percent_str,
52
        });
53
    }
54
55
    pub fn interval(self: *Ram) u64 {
56
        return self.interval_secs;
57
    }
58
59
    pub fn get_color(self: *Ram) c_ulong {
60
        return self.color;
61
    }
62
};
63
64
fn parse_mem_value(line: []const u8) u64 {
65
    var iter = std.mem.tokenizeAny(u8, line, ": \tkB");
66
    _ = iter.next();
67
    if (iter.next()) |value_str| {
68
        return std.fmt.parseInt(u64, value_str, 10) catch 0;
69
    }
70
    return 0;
71
}
72
73
fn substitute(format: []const u8, buffer: []u8, values: struct {
74
    used: []const u8,
75
    total: []const u8,
76
    percent: []const u8,
77
}) []const u8 {
78
    var pos: usize = 0;
79
    var i: usize = 0;
80
81
    while (i < format.len) {
82
        if (format[i] == '{' and i + 1 < format.len) {
83
            const rest = format[i..];
84
            const repl = if (std.mem.startsWith(u8, rest, "{used}")) blk: {
85
                i += 6;
86
                break :blk values.used;
87
            } else if (std.mem.startsWith(u8, rest, "{total}")) blk: {
88
                i += 7;
89
                break :blk values.total;
90
            } else if (std.mem.startsWith(u8, rest, "{percent}")) blk: {
91
                i += 9;
92
                break :blk values.percent;
93
            } else if (std.mem.startsWith(u8, rest, "{}")) blk: {
94
                i += 2;
95
                break :blk values.used;
96
            } else null;
97
98
            if (repl) |r| {
99
                if (pos + r.len > buffer.len) break;
100
                @memcpy(buffer[pos..][0..r.len], r);
101
                pos += r.len;
102
                continue;
103
            }
104
        }
105
        if (pos >= buffer.len) break;
106
        buffer[pos] = format[i];
107
        pos += 1;
108
        i += 1;
109
    }
110
    return buffer[0..pos];
111
}