diff options
| author | Bobby <[email protected]> | 2026-02-15 21:44:15 +0530 |
|---|---|---|
| committer | Bobby <[email protected]> | 2026-02-15 21:44:15 +0530 |
| commit | 85ea61c58c96b5ae052e40fce777f8e3d2b7ca62 (patch) | |
| tree | ab7e84dd64e8600d6c102ed12a8f598962b88aff /system | |
| parent | 71e5250b05d06505612dc5a0fcf3d25fb5277cf5 (diff) | |
| download | akiba-85ea61c58c96b5ae052e40fce777f8e3d2b7ca62.tar.xz akiba-85ea61c58c96b5ae052e40fce777f8e3d2b7ca62.zip | |
feat: Add core libraries for color, formatting, I/O, string manipulation, and memory utilities
Diffstat (limited to 'system')
27 files changed, 838 insertions, 0 deletions
diff --git a/system/libraries/colors/colors.zig b/system/libraries/colors/colors.zig new file mode 100644 index 0000000..1e151da --- /dev/null +++ b/system/libraries/colors/colors.zig @@ -0,0 +1,12 @@ +//! Display colors + +pub const white: u32 = 0x00FFFFFF; +pub const black: u32 = 0x00000000; +pub const red: u32 = 0x00FF4444; +pub const green: u32 = 0x0088FF88; +pub const blue: u32 = 0x004488DD; +pub const yellow: u32 = 0x00DDDD00; +pub const cyan: u32 = 0x0000FFFF; +pub const magenta: u32 = 0x00FF00FF; +pub const gray: u32 = 0x00888888; +pub const purple: u32 = 0x00BB88FF; diff --git a/system/libraries/colors/colors.zon b/system/libraries/colors/colors.zon new file mode 100644 index 0000000..8a0a157 --- /dev/null +++ b/system/libraries/colors/colors.zon @@ -0,0 +1,6 @@ +.{ + .name = "colors", + .version = "1.0.0", + .type = .library, + .entry = "colors.zig", +} diff --git a/system/libraries/format/date.zig b/system/libraries/format/date.zig new file mode 100644 index 0000000..d90adec --- /dev/null +++ b/system/libraries/format/date.zig @@ -0,0 +1,108 @@ +//! 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 new file mode 100644 index 0000000..f764ebd --- /dev/null +++ b/system/libraries/format/format.zig @@ -0,0 +1,17 @@ +//! Formatting utilities + +pub const int = @import("int.zig"); +pub const size = @import("size.zig"); +pub const date = @import("date.zig"); +pub const printmod = @import("print.zig"); + +pub const intToStr = int.toStr; +pub const formatSize = size.format; +pub const formatDate = date.format; + +pub const print = printmod.print; +pub const println = printmod.println; +pub const printf = printmod.printf; +pub const color = printmod.color; +pub const colorln = printmod.colorln; +pub const colorf = printmod.colorf; diff --git a/system/libraries/format/format.zon b/system/libraries/format/format.zon new file mode 100644 index 0000000..2fff0a7 --- /dev/null +++ b/system/libraries/format/format.zon @@ -0,0 +1,10 @@ +.{ + .name = "format", + .version = "1.0.0", + .type = .library, + .entry = "format.zig", + .dependencies = .{ + .io = .{ .path = "../io" }, + .colors = .{ .path = "../colors" }, + }, +} diff --git a/system/libraries/format/int.zig b/system/libraries/format/int.zig new file mode 100644 index 0000000..17cf4c3 --- /dev/null +++ b/system/libraries/format/int.zig @@ -0,0 +1,25 @@ +//! Integer formatting + +pub fn toStr(num: u64, buf: []u8) []u8 { + if (num == 0) { + buf[0] = '0'; + return buf[0..1]; + } + + var n = num; + var i: usize = 0; + + while (n > 0) : (i += 1) { + buf[i] = @as(u8, @intCast(n % 10)) + '0'; + n /= 10; + } + + var j: usize = 0; + while (j < i / 2) : (j += 1) { + const tmp = buf[j]; + buf[j] = buf[i - 1 - j]; + buf[i - 1 - j] = tmp; + } + + return buf[0..i]; +} diff --git a/system/libraries/format/print.zig b/system/libraries/format/print.zig new file mode 100644 index 0000000..473d651 --- /dev/null +++ b/system/libraries/format/print.zig @@ -0,0 +1,94 @@ +//! Print utilities + +const colors = @import("colors"); +const io = @import("io"); + +pub fn print(text: []const u8) void { + _ = io.mark(io.stream, text, colors.white) catch {}; +} + +pub fn println(text: []const u8) void { + _ = io.mark(io.stream, text, colors.white) catch {}; + _ = io.mark(io.stream, "\n", colors.white) catch {}; +} + +pub fn color(text: []const u8, col: u32) void { + _ = io.mark(io.stream, text, col) catch {}; +} + +pub fn colorln(text: []const u8, col: u32) void { + _ = io.mark(io.stream, text, col) catch {}; + _ = io.mark(io.stream, "\n", colors.white) catch {}; +} + +pub fn printf(comptime fmt: []const u8, args: anytype, buf: []u8) void { + const len = formatBuf(fmt, args, buf); + _ = io.mark(io.stream, buf[0..len], colors.white) catch {}; +} + +pub fn colorf(comptime fmt: []const u8, args: anytype, buf: []u8, col: u32) void { + const len = formatBuf(fmt, args, buf); + _ = io.mark(io.stream, buf[0..len], col) catch {}; +} + +fn formatBuf(comptime fmt: []const u8, args: anytype, buf: []u8) usize { + var pos: usize = 0; + comptime var arg_idx: usize = 0; + + comptime var i: usize = 0; + inline while (i < fmt.len) { + if (fmt[i] == '{' and i + 1 < fmt.len and fmt[i + 1] == '}') { + const arg = args[arg_idx]; + const T = @TypeOf(arg); + + if (T == []const u8 or T == []u8) { + for (arg) |c| { + if (pos >= buf.len) break; + buf[pos] = c; + pos += 1; + } + } else if (@typeInfo(T) == .int or @typeInfo(T) == .comptime_int) { + pos += writeInt(@intCast(arg), buf[pos..]); + } + + arg_idx += 1; + i += 2; + } else { + if (pos < buf.len) { + buf[pos] = fmt[i]; + pos += 1; + } + i += 1; + } + } + + return pos; +} + +fn writeInt(num: u64, buf: []u8) usize { + if (num == 0) { + if (buf.len > 0) { + buf[0] = '0'; + return 1; + } + return 0; + } + + var temp: [20]u8 = undefined; + var n = num; + var i: usize = 0; + + while (n > 0) : (i += 1) { + temp[i] = @as(u8, @intCast(n % 10)) + '0'; + n /= 10; + } + + var written: usize = 0; + while (i > 0 and written < buf.len) { + i -= 1; + buf[written] = temp[i]; + written += 1; + } + + return written; +} diff --git a/system/libraries/format/size.zig b/system/libraries/format/size.zig new file mode 100644 index 0000000..a38c0c8 --- /dev/null +++ b/system/libraries/format/size.zig @@ -0,0 +1,33 @@ +//! Size formatting + +const int = @import("int.zig"); + +const KB: u64 = 1024; +const MB: u64 = 1024 * 1024; +const GB: u64 = 1024 * 1024 * 1024; + +pub fn format(bytes: u64, buf: []u8) []u8 { + if (bytes < KB) { + const s = int.toStr(bytes, buf); + buf[s.len] = 'B'; + return buf[0 .. s.len + 1]; + } else if (bytes < MB) { + const kb = bytes / KB; + const s = int.toStr(kb, buf); + buf[s.len] = 'K'; + buf[s.len + 1] = 'B'; + return buf[0 .. s.len + 2]; + } else if (bytes < GB) { + const mb = bytes / MB; + const s = int.toStr(mb, buf); + buf[s.len] = 'M'; + buf[s.len + 1] = 'B'; + return buf[0 .. s.len + 2]; + } else { + const gb = bytes / GB; + const s = int.toStr(gb, buf); + buf[s.len] = 'G'; + buf[s.len + 1] = 'B'; + return buf[0 .. s.len + 2]; + } +} diff --git a/system/libraries/io/attachment.zig b/system/libraries/io/attachment.zig new file mode 100644 index 0000000..c68adf8 --- /dev/null +++ b/system/libraries/io/attachment.zig @@ -0,0 +1,33 @@ +//! Attachment operations + +const sys = @import("sys"); +const types = @import("types.zig"); + +const ERROR_RESULT: u64 = @bitCast(@as(i64, -1)); + +pub fn attach(path: []const u8, flags: u32) types.Error!types.FileDescriptor { + const result = sys.syscall(.attach, .{ @intFromPtr(path.ptr), flags }); + if (result == ERROR_RESULT) { + return types.Error.NotFound; + } + return @truncate(result); +} + +pub fn seal(fd: types.FileDescriptor) void { + _ = sys.syscall(.seal, .{fd}); +} + +pub fn viewstack(path: []const u8, entries: []types.StackEntry) types.Error!usize { + const result = sys.syscall(.viewstack, .{ + @intFromPtr(path.ptr), + path.len, + @intFromPtr(entries.ptr), + entries.len, + }); + + if (result == ERROR_RESULT) { + return types.Error.InvalidPath; + } + + return @intCast(result); +} diff --git a/system/libraries/io/io.zig b/system/libraries/io/io.zig new file mode 100644 index 0000000..588ff0c --- /dev/null +++ b/system/libraries/io/io.zig @@ -0,0 +1,36 @@ +//! I/O operations + +pub const attachment = @import("attachment.zig"); +pub const stream_ops = @import("stream.zig"); +pub const location = @import("location.zig"); +pub const letter = @import("letter.zig"); +pub const types = @import("types.zig"); + +pub const attach = attachment.attach; +pub const seal = attachment.seal; +pub const viewstack = attachment.viewstack; + +pub const view = stream_ops.view; +pub const mark = stream_ops.mark; +pub const getchar = stream_ops.getchar; +pub const wipe = stream_ops.wipe; + +pub const getlocation = location.get; +pub const setlocation = location.set; + +pub const sendLetter = letter.send; +pub const readLetter = letter.read; + +pub const StackEntry = types.StackEntry; +pub const FileDescriptor = types.FileDescriptor; +pub const Letter = types.Letter; +pub const Error = types.Error; + +pub const source = types.source; +pub const stream = types.stream; +pub const trace = types.trace; + +pub const VIEW_ONLY = types.VIEW_ONLY; +pub const MARK_ONLY = types.MARK_ONLY; +pub const BOTH = types.BOTH; +pub const CREATE = types.CREATE; diff --git a/system/libraries/io/io.zon b/system/libraries/io/io.zon new file mode 100644 index 0000000..124ef55 --- /dev/null +++ b/system/libraries/io/io.zon @@ -0,0 +1,10 @@ +.{ + .name = "io", + .version = "1.0.0", + .type = .library, + .entry = "io.zig", + .dependencies = .{ + .sys = .{ .path = "../sys" }, + .kata = .{ .path = "../kata" }, + }, +} diff --git a/system/libraries/io/letter.zig b/system/libraries/io/letter.zig new file mode 100644 index 0000000..3cde330 --- /dev/null +++ b/system/libraries/io/letter.zig @@ -0,0 +1,36 @@ +//! Letter (postman) operations + +const sys = @import("sys"); +const types = @import("types.zig"); + +const ERROR_RESULT: u64 = @bitCast(@as(i64, -1)); + +const MODE_SEND: u64 = 0; +const MODE_READ: u64 = 1; + +pub fn send(letter_type: u8, data: []const u8) types.Error!void { + const result = sys.syscall(.postman, .{ + MODE_SEND, + @as(u64, letter_type), + @intFromPtr(data.ptr), + data.len, + }); + + if (result == ERROR_RESULT) { + return types.Error.SendFailed; + } +} + +pub fn read(buffer: []u8) types.Error!u8 { + const result = sys.syscall(.postman, .{ + MODE_READ, + @intFromPtr(buffer.ptr), + buffer.len, + }); + + if (result == ERROR_RESULT) { + return types.Error.ReadFailed; + } + + return @intCast(result); +} diff --git a/system/libraries/io/location.zig b/system/libraries/io/location.zig new file mode 100644 index 0000000..37d3115 --- /dev/null +++ b/system/libraries/io/location.zig @@ -0,0 +1,30 @@ +//! Location operations + +const sys = @import("sys"); +const types = @import("types.zig"); + +const ERROR_RESULT: u64 = @bitCast(@as(i64, -1)); + +pub fn get(buffer: []u8) types.Error![]u8 { + const result = sys.syscall(.getlocation, .{ + @intFromPtr(buffer.ptr), + buffer.len, + }); + + if (result == ERROR_RESULT) { + return types.Error.GetLocationFailed; + } + + return buffer[0..@intCast(result)]; +} + +pub fn set(path: []const u8) types.Error!void { + const result = sys.syscall(.setlocation, .{ + @intFromPtr(path.ptr), + path.len, + }); + + if (result == ERROR_RESULT) { + return types.Error.InvalidPath; + } +} diff --git a/system/libraries/io/stream.zig b/system/libraries/io/stream.zig new file mode 100644 index 0000000..7f93c9d --- /dev/null +++ b/system/libraries/io/stream.zig @@ -0,0 +1,41 @@ +//! Stream operations + +const kata = @import("kata"); +const sys = @import("sys"); +const types = @import("types.zig"); + +const ERROR_RESULT: u64 = @bitCast(@as(i64, -1)); +const EAGAIN_RESULT: u64 = @bitCast(@as(i64, -2)); + +pub fn view(fd: types.FileDescriptor, buffer: []u8) types.Error!usize { + const result = sys.syscall(.view, .{ fd, @intFromPtr(buffer.ptr), buffer.len }); + if (result == ERROR_RESULT) { + return types.Error.ReadFailed; + } + return result; +} + +pub fn mark(fd: types.FileDescriptor, data: []const u8, color: u32) types.Error!usize { + const result = sys.syscall(.mark, .{ fd, @intFromPtr(data.ptr), data.len, color }); + if (result == ERROR_RESULT) { + return types.Error.WriteFailed; + } + return result; +} + +pub fn getchar() types.Error!u8 { + while (true) { + const result = sys.syscall(.getkeychar, .{}); + if (result != EAGAIN_RESULT) { + if (result != ERROR_RESULT) { + return @truncate(result); + } + return types.Error.ReadFailed; + } + kata.yield(); + } +} + +pub fn wipe() void { + _ = sys.syscall(.wipe, .{}); +} diff --git a/system/libraries/io/types.zig b/system/libraries/io/types.zig new file mode 100644 index 0000000..d2ddb91 --- /dev/null +++ b/system/libraries/io/types.zig @@ -0,0 +1,39 @@ +//! I/O types and constants + +pub const Error = error{ + NotFound, + PermissionDenied, + InvalidDescriptor, + ReadFailed, + WriteFailed, + InvalidPath, + SendFailed, + GetLocationFailed, +}; + +pub const FileDescriptor = u32; + +pub const source: FileDescriptor = 0; +pub const stream: FileDescriptor = 1; +pub const trace: FileDescriptor = 2; + +pub const VIEW_ONLY: u32 = 0x01; +pub const MARK_ONLY: u32 = 0x02; +pub const BOTH: u32 = 0x03; +pub const CREATE: u32 = 0x0100; + +pub const StackEntry = extern struct { + identity: [64]u8, + identity_len: u8, + is_stack: bool, + owner_name_len: u8, + permission_type: u8, + size: u32, + modified_time: u64, + owner_name: [64]u8, +}; + +pub const Letter = struct { + pub const NONE: u8 = 0; + pub const NAVIGATE: u8 = 1; +}; diff --git a/system/libraries/kata/kata.zig b/system/libraries/kata/kata.zig new file mode 100644 index 0000000..951a742 --- /dev/null +++ b/system/libraries/kata/kata.zig @@ -0,0 +1,45 @@ +//! Kata (process) control + +const sys = @import("sys"); + +const ERROR_RESULT: u64 = @bitCast(@as(i64, -1)); + +pub const Error = error{ + SpawnFailed, + WaitFailed, +}; + +pub fn yield() void { + _ = sys.syscall(.yield, .{}); +} + +pub fn exit(code: u64) noreturn { + _ = sys.syscall(.exit, .{code}); + unreachable; +} + +pub fn spawn(path: []const u8) Error!u32 { + const result = sys.syscall(.spawn, .{ @intFromPtr(path.ptr), path.len, @as(u64, 0), @as(u64, 0) }); + if (result == ERROR_RESULT) { + return Error.SpawnFailed; + } + return @truncate(result); +} + +pub fn spawnWithArgs(path: []const u8, argv: [][*:0]const u8) Error!u32 { + const result = sys.syscall(.spawn, .{ @intFromPtr(path.ptr), path.len, @intFromPtr(argv.ptr), argv.len }); + if (result == ERROR_RESULT) { + return Error.SpawnFailed; + } + return @truncate(result); +} + +pub fn wait(pid: u32) Error!u64 { + while (true) { + const result = sys.syscall(.wait, .{pid}); + if (result != ERROR_RESULT) { + return result; + } + yield(); + } +} diff --git a/system/libraries/kata/kata.zon b/system/libraries/kata/kata.zon new file mode 100644 index 0000000..f792175 --- /dev/null +++ b/system/libraries/kata/kata.zon @@ -0,0 +1,9 @@ +.{ + .name = "kata", + .version = "1.0.0", + .type = .library, + .entry = "kata.zig", + .dependencies = .{ + .sys = .{ .path = "../sys" }, + }, +} diff --git a/system/libraries/mem/mem.zig b/system/libraries/mem/mem.zig new file mode 100644 index 0000000..b513567 --- /dev/null +++ b/system/libraries/mem/mem.zig @@ -0,0 +1,22 @@ +//! Memory utilities + +pub fn copy(dest: []u8, src: []const u8) void { + const len = @min(dest.len, src.len); + for (0..len) |i| { + dest[i] = src[i]; + } +} + +pub fn zero(buf: []u8) void { + for (buf) |*b| { + b.* = 0; + } +} + +pub fn equals(a: []const u8, b: []const u8) bool { + if (a.len != b.len) return false; + for (a, b) |ac, bc| { + if (ac != bc) return false; + } + return true; +} diff --git a/system/libraries/mem/mem.zon b/system/libraries/mem/mem.zon new file mode 100644 index 0000000..18e964f --- /dev/null +++ b/system/libraries/mem/mem.zon @@ -0,0 +1,6 @@ +.{ + .name = "mem", + .version = "1.0.0", + .type = .library, + .entry = "mem.zig", +} diff --git a/system/libraries/string/builder.zig b/system/libraries/string/builder.zig new file mode 100644 index 0000000..16bd35c --- /dev/null +++ b/system/libraries/string/builder.zig @@ -0,0 +1,48 @@ +//! String building + +pub fn build(buf: []u8, parts: anytype) []const u8 { + var pos: usize = 0; + inline for (parts) |part| { + for (part) |c| { + if (pos >= buf.len) break; + buf[pos] = c; + pos += 1; + } + } + return buf[0..pos]; +} + +pub fn concat(buf: []u8, a: []const u8, b: []const u8) []const u8 { + var pos: usize = 0; + for (a) |c| { + if (pos >= buf.len) break; + buf[pos] = c; + pos += 1; + } + for (b) |c| { + if (pos >= buf.len) break; + buf[pos] = c; + pos += 1; + } + return buf[0..pos]; +} + +pub fn concat3(buf: []u8, a: []const u8, b: []const u8, c: []const u8) []const u8 { + var pos: usize = 0; + for (a) |ch| { + if (pos >= buf.len) break; + buf[pos] = ch; + pos += 1; + } + for (b) |ch| { + if (pos >= buf.len) break; + buf[pos] = ch; + pos += 1; + } + for (c) |ch| { + if (pos >= buf.len) break; + buf[pos] = ch; + pos += 1; + } + return buf[0..pos]; +} diff --git a/system/libraries/string/cstring.zig b/system/libraries/string/cstring.zig new file mode 100644 index 0000000..32ad60f --- /dev/null +++ b/system/libraries/string/cstring.zig @@ -0,0 +1,17 @@ +//! C-string utilities + +pub fn len(str: [*:0]const u8) usize { + var i: usize = 0; + while (str[i] != 0) : (i += 1) {} + return i; +} + +pub fn toSlice(str: [*:0]const u8) []const u8 { + return str[0..len(str)]; +} + +pub fn findNull(buf: []const u8) usize { + var i: usize = 0; + while (i < buf.len and buf[i] != 0) : (i += 1) {} + return i; +} diff --git a/system/libraries/string/location.zig b/system/libraries/string/location.zig new file mode 100644 index 0000000..ff1c915 --- /dev/null +++ b/system/libraries/string/location.zig @@ -0,0 +1,59 @@ +//! Location utilities + +pub fn getStackName(location: []const u8) []const u8 { + if (location.len == 0 or (location.len == 1 and location[0] == '/')) { + return "/"; + } + + var last_slash: usize = 0; + for (location, 0..) |c, i| { + if (c == '/') { + last_slash = i; + } + } + + if (last_slash == location.len - 1 and location.len > 1) { + var i: usize = location.len - 2; + while (i > 0) : (i -= 1) { + if (location[i] == '/') { + return location[i + 1 .. location.len - 1]; + } + } + return location[1 .. location.len - 1]; + } + + if (last_slash + 1 < location.len) { + return location[last_slash + 1 ..]; + } + + return location; +} + +pub fn parent(location: []const u8, buf: []u8) []const u8 { + if (location.len <= 1) { + buf[0] = '/'; + return buf[0..1]; + } + + var end = location.len; + if (location[end - 1] == '/') { + end -= 1; + } + + var i: usize = end; + while (i > 0) : (i -= 1) { + if (location[i - 1] == '/') { + if (i == 1) { + buf[0] = '/'; + return buf[0..1]; + } + for (location[0 .. i - 1], 0..) |c, j| { + buf[j] = c; + } + return buf[0 .. i - 1]; + } + } + + buf[0] = '/'; + return buf[0..1]; +} diff --git a/system/libraries/string/string.zig b/system/libraries/string/string.zig new file mode 100644 index 0000000..1d7c798 --- /dev/null +++ b/system/libraries/string/string.zig @@ -0,0 +1,16 @@ +//! String utilities + +pub const cstring = @import("cstring.zig"); +pub const location = @import("location.zig"); +pub const builder = @import("builder.zig"); + +pub const len = cstring.len; +pub const toSlice = cstring.toSlice; +pub const findNull = cstring.findNull; + +pub const getStackName = location.getStackName; +pub const parent = location.parent; + +pub const build = builder.build; +pub const concat = builder.concat; +pub const concat3 = builder.concat3; diff --git a/system/libraries/string/string.zon b/system/libraries/string/string.zon new file mode 100644 index 0000000..e722bf8 --- /dev/null +++ b/system/libraries/string/string.zon @@ -0,0 +1,6 @@ +.{ + .name = "string", + .version = "1.0.0", + .type = .library, + .entry = "string.zig", +} diff --git a/system/libraries/sys/start.zig b/system/libraries/sys/start.zig new file mode 100644 index 0000000..a65eec8 --- /dev/null +++ b/system/libraries/sys/start.zig @@ -0,0 +1,16 @@ +//! Entry point + +extern fn main(pc: u32, pv: [*]const [*:0]const u8) u8; + +export fn _start() callconv(.naked) noreturn { + asm volatile ( + \\mov (%%rsp), %%edi + \\mov 8(%%rsp), %%rsi + \\and $-16, %%rsp + \\call main + \\movzbl %%al, %%edi + \\mov $0x01, %%eax + \\syscall + \\ud2 + ); +} diff --git a/system/libraries/sys/sys.zig b/system/libraries/sys/sys.zig new file mode 100644 index 0000000..d37e4c8 --- /dev/null +++ b/system/libraries/sys/sys.zig @@ -0,0 +1,58 @@ +//! System runtime + +pub const start = @import("start.zig"); + +comptime { + _ = start; +} + +pub const Invocation = enum(u64) { + exit = 0x01, + attach = 0x02, + seal = 0x03, + view = 0x04, + mark = 0x05, + spawn = 0x06, + wait = 0x07, + yield = 0x08, + getkeychar = 0x09, + viewstack = 0x0A, + getlocation = 0x0B, + setlocation = 0x0C, + postman = 0x0D, + wipe = 0x0E, +}; + +pub inline fn syscall(invocation: Invocation, args: anytype) u64 { + const Args = @TypeOf(args); + const fields = @typeInfo(Args).@"struct".fields; + + const arg0: u64 = if (fields.len > 0) toU64(args[0]) else 0; + const arg1: u64 = if (fields.len > 1) toU64(args[1]) else 0; + const arg2: u64 = if (fields.len > 2) toU64(args[2]) else 0; + const arg3: u64 = if (fields.len > 3) toU64(args[3]) else 0; + const arg4: u64 = if (fields.len > 4) toU64(args[4]) else 0; + const arg5: u64 = if (fields.len > 5) toU64(args[5]) else 0; + + return asm volatile ("syscall" + : [ret] "={rax}" (-> u64), + : [number] "{rax}" (@intFromEnum(invocation)), + [arg0] "{rdi}" (arg0), + [arg1] "{rsi}" (arg1), + [arg2] "{rdx}" (arg2), + [arg3] "{r10}" (arg3), + [arg4] "{r8}" (arg4), + [arg5] "{r9}" (arg5), + : .{ .rcx = true, .r11 = true, .memory = true } + ); +} + +inline fn toU64(value: anytype) u64 { + const T = @TypeOf(value); + return switch (@typeInfo(T)) { + .int, .comptime_int => @intCast(value), + .pointer => @intFromPtr(value), + .@"enum" => @intFromEnum(value), + else => @bitCast(value), + }; +} diff --git a/system/libraries/sys/sys.zon b/system/libraries/sys/sys.zon new file mode 100644 index 0000000..35d065e --- /dev/null +++ b/system/libraries/sys/sys.zon @@ -0,0 +1,6 @@ +.{ + .name = "sys", + .version = "1.0.0", + .type = .library, + .entry = "sys.zig", +} |
