| 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 |
}
|