From 91e2c4202a6772a3e3de4cae8c671d4d79cb7af0 Mon Sep 17 00:00:00 2001 From: Bobby <30593201+luciferreeves@users.noreply.github.com> Date: Fri, 20 Feb 2026 16:01:59 +0530 Subject: feat: Add datetime and OS information libraries with formatting and retrieval functions --- system/libraries/datetime/datetime.zig | 13 ++++ system/libraries/datetime/datetime.zon | 9 +++ system/libraries/datetime/format.zig | 111 +++++++++++++++++++++++++++++++++ system/libraries/datetime/time.zig | 77 +++++++++++++++++++++++ system/libraries/datetime/types.zig | 10 +++ system/libraries/format/bytes.zig | 47 ++++++++++++++ system/libraries/format/date.zig | 108 -------------------------------- system/libraries/format/format.zig | 4 +- system/libraries/os/cpu.zig | 19 ++++++ system/libraries/os/disk.zig | 25 ++++++++ system/libraries/os/memory.zig | 28 +++++++++ system/libraries/os/os.zig | 15 +++++ system/libraries/os/os.zon | 9 +++ system/libraries/os/types.zig | 12 ++++ system/libraries/os/uptime.zig | 15 +++++ system/libraries/sys/sys.zig | 5 ++ 16 files changed, 397 insertions(+), 110 deletions(-) create mode 100644 system/libraries/datetime/datetime.zig create mode 100644 system/libraries/datetime/datetime.zon create mode 100644 system/libraries/datetime/format.zig create mode 100644 system/libraries/datetime/time.zig create mode 100644 system/libraries/datetime/types.zig create mode 100644 system/libraries/format/bytes.zig delete mode 100644 system/libraries/format/date.zig create mode 100644 system/libraries/os/cpu.zig create mode 100644 system/libraries/os/disk.zig create mode 100644 system/libraries/os/memory.zig create mode 100644 system/libraries/os/os.zig create mode 100644 system/libraries/os/os.zon create mode 100644 system/libraries/os/types.zig create mode 100644 system/libraries/os/uptime.zig diff --git a/system/libraries/datetime/datetime.zig b/system/libraries/datetime/datetime.zig new file mode 100644 index 0000000..d72d679 --- /dev/null +++ b/system/libraries/datetime/datetime.zig @@ -0,0 +1,13 @@ +//! Date and time utilities + +pub const time = @import("time.zig"); +pub const fmt = @import("format.zig"); +pub const types = @import("types.zig"); + +pub const now = time.now; +pub const parts = time.parts; + +pub const formatDate = fmt.date; +pub const formatDuration = fmt.duration; + +pub const DateTime = types.DateTime; diff --git a/system/libraries/datetime/datetime.zon b/system/libraries/datetime/datetime.zon new file mode 100644 index 0000000..a55aede --- /dev/null +++ b/system/libraries/datetime/datetime.zon @@ -0,0 +1,9 @@ +.{ + .name = "datetime", + .version = "1.0.0", + .type = .library, + .dependencies = .{ + .sys, + }, + .entry = "datetime.zig", +} diff --git a/system/libraries/datetime/format.zig b/system/libraries/datetime/format.zig new file mode 100644 index 0000000..daebd10 --- /dev/null +++ b/system/libraries/datetime/format.zig @@ -0,0 +1,111 @@ +//! Date/time formatting + +const time = @import("time.zig"); + +const MONTH_NAMES = [_][]const u8{ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; + +pub fn date(timestamp: u64, buf: []u8) []const u8 { + if (timestamp == 0) { + const default = "01 Jan 1970 00:00"; + for (default, 0..) |c, i| { + buf[i] = c; + } + return buf[0..default.len]; + } + + const dt = time.parts(timestamp); + var pos: usize = 0; + + // Day + if (dt.day < 10) { + buf[pos] = '0'; + pos += 1; + } + pos += writeInt(dt.day, buf[pos..]); + + buf[pos] = ' '; + pos += 1; + + // Month name + const month_idx = if (dt.month > 0 and dt.month <= 12) dt.month - 1 else 0; + for (MONTH_NAMES[month_idx]) |c| { + buf[pos] = c; + pos += 1; + } + + buf[pos] = ' '; + pos += 1; + + // Year + pos += writeInt(dt.year, buf[pos..]); + + buf[pos] = ' '; + pos += 1; + + // Hour + if (dt.hour < 10) { + buf[pos] = '0'; + pos += 1; + } + pos += writeInt(dt.hour, buf[pos..]); + + buf[pos] = ':'; + pos += 1; + + // Minute + if (dt.minute < 10) { + buf[pos] = '0'; + pos += 1; + } + pos += writeInt(dt.minute, buf[pos..]); + + return buf[0..pos]; +} + +pub fn duration(total_secs: u64, buf: []u8) []const u8 { + const hours = total_secs / 3600; + const mins = (total_secs % 3600) / 60; + const secs = total_secs % 60; + + var pos: usize = 0; + + pos += writeInt(hours, buf[pos..]); + buf[pos] = 'h'; + pos += 1; + buf[pos] = ' '; + pos += 1; + + pos += writeInt(mins, buf[pos..]); + buf[pos] = 'm'; + pos += 1; + buf[pos] = ' '; + pos += 1; + + pos += writeInt(secs, buf[pos..]); + buf[pos] = 's'; + pos += 1; + + return buf[0..pos]; +} + +fn writeInt(value: u64, buf: []u8) usize { + if (value == 0) { + buf[0] = '0'; + return 1; + } + + var temp: [20]u8 = undefined; + var len: usize = 0; + var v = value; + + while (v > 0) : (v /= 10) { + temp[len] = @intCast('0' + (v % 10)); + len += 1; + } + + for (0..len) |i| { + buf[i] = temp[len - 1 - i]; + } + + return len; +} diff --git a/system/libraries/datetime/time.zig b/system/libraries/datetime/time.zig new file mode 100644 index 0000000..9634ace --- /dev/null +++ b/system/libraries/datetime/time.zig @@ -0,0 +1,77 @@ +//! Time operations + +const sys = @import("sys"); +const types = @import("types.zig"); + +const ERROR_RESULT: u64 = @bitCast(@as(i64, -1)); + +const SECONDS_PER_DAY: u64 = 86400; +const SECONDS_PER_HOUR: u64 = 3600; +const SECONDS_PER_MINUTE: u64 = 60; +const DAYS_PER_4_YEARS: u64 = 1461; + +const DAYS_NORMAL = [_]u64{ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; +const DAYS_LEAP = [_]u64{ 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; + +pub fn now() ?u64 { + const result = sys.syscall(.gettime, .{}); + + if (result == ERROR_RESULT) { + return null; + } + + return result; +} + +pub fn parts(timestamp: u64) types.DateTime { + const days_since_epoch = timestamp / SECONDS_PER_DAY; + const seconds_today = timestamp % SECONDS_PER_DAY; + const hours = seconds_today / SECONDS_PER_HOUR; + const minutes = (seconds_today % SECONDS_PER_HOUR) / SECONDS_PER_MINUTE; + const seconds = seconds_today % SECONDS_PER_MINUTE; + + var year: u64 = 1970; + var remaining_days = days_since_epoch; + + const four_year_cycles = remaining_days / DAYS_PER_4_YEARS; + year += four_year_cycles * 4; + remaining_days = remaining_days % DAYS_PER_4_YEARS; + + while (remaining_days >= 365) { + const is_leap = isLeapYear(year); + const days_this_year: u64 = if (is_leap) 366 else 365; + if (remaining_days >= days_this_year) { + remaining_days -= days_this_year; + year += 1; + } else { + break; + } + } + + const is_leap = isLeapYear(year); + const days_in_months = if (is_leap) DAYS_LEAP else DAYS_NORMAL; + + var month: u8 = 1; + var day: u64 = remaining_days + 1; + + for (days_in_months, 0..) |days, m| { + if (day <= days) { + month = @intCast(m + 1); + break; + } + day -= days; + } + + return types.DateTime{ + .year = year, + .month = month, + .day = @intCast(day), + .hour = @intCast(hours), + .minute = @intCast(minutes), + .second = @intCast(seconds), + }; +} + +fn isLeapYear(year: u64) bool { + return (year % 4 == 0 and year % 100 != 0) or (year % 400 == 0); +} diff --git a/system/libraries/datetime/types.zig b/system/libraries/datetime/types.zig new file mode 100644 index 0000000..5024e3a --- /dev/null +++ b/system/libraries/datetime/types.zig @@ -0,0 +1,10 @@ +//! DateTime types + +pub const DateTime = struct { + year: u64, + month: u8, + day: u8, + hour: u8, + minute: u8, + second: u8, +}; diff --git a/system/libraries/format/bytes.zig b/system/libraries/format/bytes.zig new file mode 100644 index 0000000..9d4cb86 --- /dev/null +++ b/system/libraries/format/bytes.zig @@ -0,0 +1,47 @@ +//! Byte size formatting + +const int = @import("int.zig"); + +pub fn format(bytes: u64, buf: []u8) []const u8 { + const kb = bytes / 1024; + const mb = kb / 1024; + + if (mb >= 1024) { + // Round: add 512 (half of 1024) before dividing + const gb_tenths = (mb * 10 + 512) / 1024; + const gb_whole = gb_tenths / 10; + const gb_frac = gb_tenths % 10; + + var pos: usize = 0; + const whole_str = int.toStr(gb_whole, buf[pos..]); + pos += whole_str.len; + buf[pos] = '.'; + pos += 1; + buf[pos] = '0' + @as(u8, @intCast(gb_frac)); + pos += 1; + buf[pos] = ' '; + pos += 1; + buf[pos] = 'G'; + pos += 1; + buf[pos] = 'B'; + pos += 1; + return buf[0..pos]; + } else if (mb > 0) { + const num_str = int.toStr(mb, buf); + buf[num_str.len] = ' '; + buf[num_str.len + 1] = 'M'; + buf[num_str.len + 2] = 'B'; + return buf[0 .. num_str.len + 3]; + } else if (kb > 0) { + const num_str = int.toStr(kb, buf); + buf[num_str.len] = ' '; + buf[num_str.len + 1] = 'K'; + buf[num_str.len + 2] = 'B'; + return buf[0 .. num_str.len + 3]; + } else { + const num_str = int.toStr(bytes, buf); + buf[num_str.len] = ' '; + buf[num_str.len + 1] = 'B'; + return buf[0 .. num_str.len + 2]; + } +} diff --git a/system/libraries/format/date.zig b/system/libraries/format/date.zig deleted file mode 100644 index d90adec..0000000 --- a/system/libraries/format/date.zig +++ /dev/null @@ -1,108 +0,0 @@ -//! Date formatting - -const int = @import("int.zig"); - -const SECONDS_PER_DAY: u64 = 86400; -const SECONDS_PER_HOUR: u64 = 3600; -const SECONDS_PER_MINUTE: u64 = 60; -const DAYS_PER_4_YEARS: u64 = 1461; - -const MONTH_NAMES = [_][]const u8{ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; -const DAYS_NORMAL = [_]u64{ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; -const DAYS_LEAP = [_]u64{ 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; - -pub fn format(timestamp: u64, buf: []u8) []u8 { - if (timestamp == 0) { - const default = "01 Jan 1970 00:00"; - for (default, 0..) |c, i| { - buf[i] = c; - } - return buf[0..default.len]; - } - - const days_since_epoch = timestamp / SECONDS_PER_DAY; - const seconds_today = timestamp % SECONDS_PER_DAY; - const hours = seconds_today / SECONDS_PER_HOUR; - const minutes = (seconds_today % SECONDS_PER_HOUR) / SECONDS_PER_MINUTE; - - var year: u64 = 1970; - var remaining_days = days_since_epoch; - - const four_year_cycles = remaining_days / DAYS_PER_4_YEARS; - year += four_year_cycles * 4; - remaining_days = remaining_days % DAYS_PER_4_YEARS; - - while (remaining_days >= 365) { - const is_leap = isLeapYear(year); - const days_this_year: u64 = if (is_leap) 366 else 365; - if (remaining_days >= days_this_year) { - remaining_days -= days_this_year; - year += 1; - } else { - break; - } - } - - const is_leap = isLeapYear(year); - const days_in_months = if (is_leap) DAYS_LEAP else DAYS_NORMAL; - - var month: usize = 0; - var day: u64 = remaining_days + 1; - - for (days_in_months, 0..) |days, m| { - if (day <= days) { - month = m; - break; - } - day -= days; - } - - var pos: usize = 0; - - if (day < 10) { - buf[pos] = '0'; - pos += 1; - } - const day_str = int.toStr(day, buf[pos..]); - pos += day_str.len; - - buf[pos] = ' '; - pos += 1; - - for (MONTH_NAMES[month]) |c| { - buf[pos] = c; - pos += 1; - } - - buf[pos] = ' '; - pos += 1; - - const year_str = int.toStr(year, buf[pos..]); - pos += year_str.len; - - buf[pos] = ' '; - pos += 1; - - if (hours < 10) { - buf[pos] = '0'; - pos += 1; - } - const hour_str = int.toStr(hours, buf[pos..]); - pos += hour_str.len; - - buf[pos] = ':'; - pos += 1; - - if (minutes < 10) { - buf[pos] = '0'; - pos += 1; - } - const min_str = int.toStr(minutes, buf[pos..]); - pos += min_str.len; - - return buf[0..pos]; -} - -fn isLeapYear(year: u64) bool { - return (year % 4 == 0 and year % 100 != 0) or (year % 400 == 0); -} diff --git a/system/libraries/format/format.zig b/system/libraries/format/format.zig index e516017..02a5632 100644 --- a/system/libraries/format/format.zig +++ b/system/libraries/format/format.zig @@ -2,13 +2,13 @@ pub const int = @import("int.zig"); pub const size = @import("size.zig"); -pub const date = @import("date.zig"); +pub const bytes = @import("bytes.zig"); pub const printmod = @import("print.zig"); pub const tablemod = @import("table.zig"); pub const intToStr = int.toStr; pub const formatSize = size.format; -pub const formatDate = date.format; +pub const formatBytes = bytes.format; pub const print = printmod.print; pub const println = printmod.println; diff --git a/system/libraries/os/cpu.zig b/system/libraries/os/cpu.zig new file mode 100644 index 0000000..1f3ea53 --- /dev/null +++ b/system/libraries/os/cpu.zig @@ -0,0 +1,19 @@ +//! CPU information + +const sys = @import("sys"); +const types = @import("types.zig"); + +const ERROR_RESULT: u64 = @bitCast(@as(i64, -1)); + +pub fn info(buffer: []u8) ?[]const u8 { + const result = sys.syscall(.cpuinfo, .{ + @intFromPtr(buffer.ptr), + buffer.len, + }); + + if (result == ERROR_RESULT or result == 0) { + return null; + } + + return buffer[0..@intCast(result)]; +} diff --git a/system/libraries/os/disk.zig b/system/libraries/os/disk.zig new file mode 100644 index 0000000..9a43c26 --- /dev/null +++ b/system/libraries/os/disk.zig @@ -0,0 +1,25 @@ +//! Disk information + +const sys = @import("sys"); +const types = @import("types.zig"); + +const ERROR_RESULT: u64 = @bitCast(@as(i64, -1)); + +pub fn info() ?types.DiskInfo { + var total: u64 = 0; + var used: u64 = 0; + + const result = sys.syscall(.diskinfo, .{ + @intFromPtr(&total), + @intFromPtr(&used), + }); + + if (result == ERROR_RESULT) { + return null; + } + + return types.DiskInfo{ + .total = total, + .used = used, + }; +} diff --git a/system/libraries/os/memory.zig b/system/libraries/os/memory.zig new file mode 100644 index 0000000..86c2a08 --- /dev/null +++ b/system/libraries/os/memory.zig @@ -0,0 +1,28 @@ +//! Memory information + +const sys = @import("sys"); +const types = @import("types.zig"); + +const ERROR_RESULT: u64 = @bitCast(@as(i64, -1)); + +pub fn info() ?types.MemInfo { + var total: u64 = 0; + var used: u64 = 0; + var free: u64 = 0; + + const result = sys.syscall(.meminfo, .{ + @intFromPtr(&total), + @intFromPtr(&used), + @intFromPtr(&free), + }); + + if (result == ERROR_RESULT) { + return null; + } + + return types.MemInfo{ + .total = total, + .used = used, + .free = free, + }; +} diff --git a/system/libraries/os/os.zig b/system/libraries/os/os.zig new file mode 100644 index 0000000..18b8730 --- /dev/null +++ b/system/libraries/os/os.zig @@ -0,0 +1,15 @@ +//! OS information utilities + +pub const cpu = @import("cpu.zig"); +pub const disk = @import("disk.zig"); +pub const mem = @import("memory.zig"); +pub const up = @import("uptime.zig"); +pub const types = @import("types.zig"); + +pub const cpuinfo = cpu.info; +pub const meminfo = mem.info; +pub const diskinfo = disk.info; +pub const uptime = up.get; + +pub const MemInfo = types.MemInfo; +pub const DiskInfo = types.DiskInfo; diff --git a/system/libraries/os/os.zon b/system/libraries/os/os.zon new file mode 100644 index 0000000..e1bc062 --- /dev/null +++ b/system/libraries/os/os.zon @@ -0,0 +1,9 @@ +.{ + .name = "os", + .version = "1.0.0", + .type = .library, + .dependencies = .{ + .sys, + }, + .entry = "os.zig", +} diff --git a/system/libraries/os/types.zig b/system/libraries/os/types.zig new file mode 100644 index 0000000..1b06af9 --- /dev/null +++ b/system/libraries/os/types.zig @@ -0,0 +1,12 @@ +//! OS types + +pub const MemInfo = struct { + total: u64, + used: u64, + free: u64, +}; + +pub const DiskInfo = struct { + total: u64, + used: u64, +}; diff --git a/system/libraries/os/uptime.zig b/system/libraries/os/uptime.zig new file mode 100644 index 0000000..0f499ff --- /dev/null +++ b/system/libraries/os/uptime.zig @@ -0,0 +1,15 @@ +//! Uptime information + +const sys = @import("sys"); + +const ERROR_RESULT: u64 = @bitCast(@as(i64, -1)); + +pub fn get() ?u64 { + const result = sys.syscall(.uptime, .{}); + + if (result == ERROR_RESULT) { + return null; + } + + return result; +} diff --git a/system/libraries/sys/sys.zig b/system/libraries/sys/sys.zig index d37e4c8..b080a90 100644 --- a/system/libraries/sys/sys.zig +++ b/system/libraries/sys/sys.zig @@ -21,6 +21,11 @@ pub const Invocation = enum(u64) { setlocation = 0x0C, postman = 0x0D, wipe = 0x0E, + cpuinfo = 0x0F, + meminfo = 0x10, + uptime = 0x11, + gettime = 0x12, + diskinfo = 0x13, }; pub inline fn syscall(invocation: Invocation, args: anytype) u64 { -- cgit v1.2.3