aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--binaries/mi/mi.zig230
-rw-r--r--binaries/mi/mi.zon9
-rw-r--r--binaries/nav/nav.zig35
-rw-r--r--binaries/nav/nav.zon9
-rw-r--r--binaries/rd/rd.zig48
-rw-r--r--binaries/rd/rd.zon9
-rw-r--r--binaries/wipe/wipe.zig5
-rw-r--r--binaries/wipe/wipe.zon7
-rw-r--r--system/ash/ash.zig110
-rw-r--r--system/ash/ash.zon9
-rw-r--r--system/libraries/akiba/akiba.zig10
-rw-r--r--system/libraries/akiba/akiba.zon6
-rw-r--r--system/libraries/akiba/io.zig168
-rw-r--r--system/libraries/akiba/kata.zig38
-rw-r--r--system/libraries/akiba/start.zig31
-rw-r--r--system/libraries/akiba/sys.zig40
-rw-r--r--system/pulse/pulse.zig22
-rw-r--r--system/pulse/pulse.zon8
18 files changed, 138 insertions, 656 deletions
diff --git a/binaries/mi/mi.zig b/binaries/mi/mi.zig
index 1e158a9..ca9e46f 100644
--- a/binaries/mi/mi.zig
+++ b/binaries/mi/mi.zig
@@ -1,28 +1,18 @@
-//! mi - Professional stack viewer for Akiba OS
+//! mi - Stack viewer for Akiba OS
-const akiba = @import("akiba");
-
-const Color = struct {
- const white: u32 = 0x00FFFFFF;
- const cyan: u32 = 0x0000FFFF;
- const blue: u32 = 0x004488DD;
- const green: u32 = 0x0000DD88;
- const yellow: u32 = 0x00DDDD00;
- const gray: u32 = 0x00777777;
- const purple: u32 = 0x00BB88FF;
- const red: u32 = 0x00FF4444;
-};
+const colors = @import("colors");
+const format = @import("format");
+const io = @import("io");
+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 {
- // Use first argument as path, or default to ""
var target_path: []const u8 = "";
if (pc > 1) {
- // Get pv[1] as the target path
const arg = pv[1];
var len: usize = 0;
while (arg[len] != 0) : (len += 1) {}
@@ -30,7 +20,9 @@ export fn main(pc: u32, pv: [*]const [*:0]const u8) u8 {
}
display_stack(target_path) catch |err| {
- mark_error(@errorName(err));
+ format.color("mi: ", colors.white);
+ format.color(@errorName(err), colors.red);
+ format.print("\n");
return 1;
};
@@ -38,29 +30,24 @@ export fn main(pc: u32, pv: [*]const [*:0]const u8) u8 {
}
fn display_stack(path: []const u8) !void {
- var entries: [128]akiba.io.StackEntry = undefined;
- const count = akiba.io.viewstack(path, &entries) catch {
- // Path doesn't exist or isn't a directory
- _ = akiba.io.mark(akiba.io.stream, "mi: cannot access '", Color.red) catch 0;
- _ = akiba.io.mark(akiba.io.stream, path, Color.white) catch 0;
- _ = akiba.io.mark(akiba.io.stream, "': No such stack.\n", Color.red) catch 0;
+ 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;
};
- // Check for empty directory (valid directory with 0 entries)
if (count == 0) {
- _ = akiba.io.mark(akiba.io.stream, path, Color.cyan) catch 0;
- _ = akiba.io.mark(akiba.io.stream, " is empty.\n", Color.gray) catch 0;
+ format.color(path, colors.cyan);
+ format.colorln(" is empty.", colors.gray);
return;
}
- // Calculate max widths for each column
var max_access_len: usize = 6;
var max_size_len: usize = 4;
var max_owner_len: usize = 7;
- var max_date_len: usize = 8;
- const formatted_date_len: usize = 19;
- if (formatted_date_len > max_date_len) max_date_len = formatted_date_len;
+ const max_date_len: usize = 19;
for (0..count) |i| {
const entry = &entries[i];
@@ -68,7 +55,7 @@ fn display_stack(path: []const u8) !void {
if (perms.len > max_access_len) max_access_len = perms.len;
var size_buf: [32]u8 = undefined;
- const size_str = format_size(entry.size, &size_buf);
+ const size_str = format.formatSize(entry.size, &size_buf);
if (size_str.len > max_size_len) max_size_len = size_str.len;
if (entry.owner_name_len > max_owner_len) {
@@ -76,16 +63,15 @@ fn display_stack(path: []const u8) !void {
}
}
- // Print header
- _ = akiba.io.mark(akiba.io.stream, "Access", Color.white) catch 0;
+ format.print("Access");
print_padding(max_access_len - 6 + 2);
- _ = akiba.io.mark(akiba.io.stream, "Size", Color.white) catch 0;
+ format.print("Size");
print_padding(max_size_len - 4 + 2);
- _ = akiba.io.mark(akiba.io.stream, "Persona", Color.white) catch 0;
+ format.print("Persona");
print_padding(max_owner_len - 7 + 3);
- _ = akiba.io.mark(akiba.io.stream, "Modified", Color.white) catch 0;
+ format.print("Modified");
print_padding(max_date_len - 8 + 1);
- _ = akiba.io.mark(akiba.io.stream, "Name\n", Color.white) catch 0;
+ format.println("Name");
var stack_count: usize = 0;
var unit_count: usize = 0;
@@ -97,43 +83,44 @@ fn display_stack(path: []const u8) !void {
const owner = entry.owner_name[0..entry.owner_name_len];
const perms = get_permissions(entry.permission_type);
- _ = akiba.io.mark(akiba.io.stream, perms, Color.cyan) catch 0;
+ format.color(perms, colors.cyan);
print_padding(max_access_len - perms.len + 2);
var size_buf: [32]u8 = undefined;
- const size_str = format_size(entry.size, &size_buf);
- _ = akiba.io.mark(akiba.io.stream, size_str, Color.green) catch 0;
+ const size_str = format.formatSize(entry.size, &size_buf);
+ format.color(size_str, colors.green);
print_padding(max_size_len - size_str.len + 2);
- _ = akiba.io.mark(akiba.io.stream, owner, Color.yellow) catch 0;
+ format.color(owner, colors.yellow);
print_padding(max_owner_len - owner.len + 3);
- format_date(entry.modified_time);
- print_padding(1);
+ var date_buf: [32]u8 = undefined;
+ const date_str = format.formatDate(entry.modified_time, &date_buf);
+ format.color(date_str, colors.blue);
+ print_padding(max_date_len - date_str.len + 2);
if (entry.is_stack) {
stack_count += 1;
total_size += entry.size;
- _ = akiba.io.mark(akiba.io.stream, identity, Color.cyan) catch 0;
- _ = akiba.io.mark(akiba.io.stream, "/", Color.blue) catch 0;
+ format.color(identity, colors.cyan);
+ format.color("/", colors.blue);
} else {
unit_count += 1;
total_size += entry.size;
- _ = akiba.io.mark(akiba.io.stream, identity, Color.white) catch 0;
+ format.print(identity);
}
- _ = akiba.io.mark(akiba.io.stream, "\n", Color.white) catch 0;
+ format.print("\n");
}
- _ = akiba.io.mark(akiba.io.stream, "\n", Color.white) catch 0;
- // Summary
+ format.print("\n");
+
var buf: [16]u8 = undefined;
- _ = akiba.io.mark(akiba.io.stream, int_to_str(stack_count, &buf), Color.gray) catch 0;
- _ = akiba.io.mark(akiba.io.stream, " stacks ", Color.gray) catch 0;
- _ = akiba.io.mark(akiba.io.stream, int_to_str(unit_count, &buf), Color.gray) catch 0;
- _ = akiba.io.mark(akiba.io.stream, " units ", Color.gray) catch 0;
+ 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;
- _ = akiba.io.mark(akiba.io.stream, format_size(total_size, &size_buf), Color.gray) catch 0;
- _ = akiba.io.mark(akiba.io.stream, "\n", Color.white) catch 0;
+ format.colorln(format.formatSize(total_size, &size_buf), colors.gray);
}
fn get_permissions(perm_type: u8) []const u8 {
@@ -148,139 +135,6 @@ fn get_permissions(perm_type: u8) []const u8 {
fn print_padding(count: usize) void {
var i: usize = 0;
while (i < count) : (i += 1) {
- _ = akiba.io.mark(akiba.io.stream, " ", Color.white) catch {};
- }
-}
-
-fn format_date(timestamp: u64) void {
- if (timestamp == 0) {
- _ = akiba.io.mark(akiba.io.stream, " 1 Jan 1970 00:00 ", Color.blue) catch 0;
- return;
- }
- const SECONDS_PER_DAY: u64 = 86400;
- const SECONDS_PER_HOUR: u64 = 3600;
- const SECONDS_PER_MINUTE: u64 = 60;
- 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 DAYS_PER_4_YEARS: u64 = 1461;
- 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 = (year % 4 == 0 and year % 100 != 0) or (year % 400 == 0);
- 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 = (year % 4 == 0 and year % 100 != 0) or (year % 400 == 0);
- const days_in_months = if (is_leap) [_]u64{ 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } else [_]u64{ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
- const month_names = [_][]const u8{ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
- 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 buf: [20]u8 = undefined;
- var pos: usize = 0;
- if (day < 10) {
- buf[pos] = '0';
- pos += 1;
- }
- const day_str = int_to_str(day, buf[pos..]);
- pos += day_str.len;
- buf[pos] = ' ';
- pos += 1;
- for (month_names[month]) |c| {
- buf[pos] = c;
- pos += 1;
+ format.print(" ");
}
- buf[pos] = ' ';
- pos += 1;
- const year_str = int_to_str(year, buf[pos..]);
- pos += year_str.len;
- buf[pos] = ' ';
- pos += 1;
- if (hours < 10) {
- buf[pos] = '0';
- pos += 1;
- }
- const hour_str = int_to_str(hours, buf[pos..]);
- pos += hour_str.len;
- buf[pos] = ':';
- pos += 1;
- if (minutes < 10) {
- buf[pos] = '0';
- pos += 1;
- }
- const min_str = int_to_str(minutes, buf[pos..]);
- pos += min_str.len;
- buf[pos] = ' ';
- pos += 1;
- buf[pos] = ' ';
- pos += 1;
- _ = akiba.io.mark(akiba.io.stream, buf[0..pos], Color.blue) catch 0;
-}
-
-fn format_size(size: u64, buf: []u8) []u8 {
- if (size < 1024) {
- const s = int_to_str(size, buf);
- buf[s.len] = 'B';
- return buf[0 .. s.len + 1];
- } else if (size < 1024 * 1024) {
- const kb = size / 1024;
- const s = int_to_str(kb, buf);
- buf[s.len] = 'K';
- buf[s.len + 1] = 'B';
- return buf[0 .. s.len + 2];
- } else if (size < 1024 * 1024 * 1024) {
- const mb = size / (1024 * 1024);
- const s = int_to_str(mb, buf);
- buf[s.len] = 'M';
- buf[s.len + 1] = 'B';
- return buf[0 .. s.len + 2];
- } else {
- const gb = size / (1024 * 1024 * 1024);
- const s = int_to_str(gb, buf);
- buf[s.len] = 'G';
- buf[s.len + 1] = 'B';
- return buf[0 .. s.len + 2];
- }
-}
-
-fn int_to_str(num: usize, 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];
-}
-
-fn mark_error(msg: []const u8) void {
- _ = akiba.io.mark(akiba.io.trace, "mi: ", Color.white) catch 0;
- _ = akiba.io.mark(akiba.io.trace, msg, Color.white) catch 0;
- _ = akiba.io.mark(akiba.io.trace, "\n", Color.white) catch 0;
}
diff --git a/binaries/mi/mi.zon b/binaries/mi/mi.zon
index b7faaf0..352d31e 100644
--- a/binaries/mi/mi.zon
+++ b/binaries/mi/mi.zon
@@ -2,9 +2,10 @@
.name = "mi",
.version = "0.1.0",
.dependencies = .{
- .akiba = .{ .path = "../../system/libraries/akiba" },
- },
- .paths = .{
- "mi.zig",
+ .sys,
+ .io,
+ .colors,
+ .format,
},
+ .entry = "mi.zig",
}
diff --git a/binaries/nav/nav.zig b/binaries/nav/nav.zig
index 98883d0..acdeeb6 100644
--- a/binaries/nav/nav.zig
+++ b/binaries/nav/nav.zig
@@ -1,44 +1,31 @@
//! nav - Navigate the filesystem
-//!
-//! nav - Print current location
-//! nav <path> - Navigate to path
-//! nav ^ - Navigate to parent
-//! nav / - Navigate to root
-const akiba = @import("akiba");
+const colors = @import("colors");
+const format = @import("format");
+const io = @import("io");
+const sys = @import("sys");
-const Color = struct {
- const white: u32 = 0x00FFFFFF;
- const green: u32 = 0x0088FF88;
- const red: u32 = 0x00FF4444;
-};
-
-// Global buffer
var location_buf: [256]u8 = undefined;
export fn main(pc: u32, pv: [*]const [*:0]const u8) u8 {
- // No arguments - print current location
if (pc <= 1) {
- const location = akiba.io.getlocation(&location_buf) catch {
- _ = akiba.io.mark(akiba.io.stream, "nav: cannot get current location.\n", Color.red) catch 0;
+ const location = io.getlocation(&location_buf) catch {
+ format.colorln("nav: cannot get current location.", colors.red);
return 1;
};
- _ = akiba.io.mark(akiba.io.stream, location, Color.green) catch 0;
- _ = akiba.io.mark(akiba.io.stream, "\n", Color.white) catch 0;
+ format.colorln(location, colors.green);
return 0;
}
- // Get target path from argument
const arg = pv[1];
var target_len: usize = 0;
while (arg[target_len] != 0) : (target_len += 1) {}
const target = arg[0..target_len];
- // Navigate - setlocation auto-sends letter to parent
- akiba.io.setlocation(target) catch {
- _ = akiba.io.mark(akiba.io.stream, "nav: cannot navigate to '", Color.red) catch 0;
- _ = akiba.io.mark(akiba.io.stream, target, Color.white) catch 0;
- _ = akiba.io.mark(akiba.io.stream, "': No such stack.\n", Color.red) catch 0;
+ io.setlocation(target) catch {
+ format.color("nav: cannot navigate to '", colors.red);
+ format.print(target);
+ format.colorln("': No such stack.", colors.red);
return 1;
};
diff --git a/binaries/nav/nav.zon b/binaries/nav/nav.zon
index 8597b44..21d50a4 100644
--- a/binaries/nav/nav.zon
+++ b/binaries/nav/nav.zon
@@ -2,9 +2,10 @@
.name = "nav",
.version = "0.1.0",
.dependencies = .{
- .akiba = .{ .path = "../../system/libraries/akiba" },
- },
- .paths = .{
- "nav.zig",
+ .sys,
+ .io,
+ .colors,
+ .format,
},
+ .entry = "nav.zig",
}
diff --git a/binaries/rd/rd.zig b/binaries/rd/rd.zig
index e16f7cc..008cb54 100644
--- a/binaries/rd/rd.zig
+++ b/binaries/rd/rd.zig
@@ -1,61 +1,47 @@
//! rd - Read unit contents
-//!
-//! rd <location> - Display contents of a unit (file)
-//! rd - Error: no location specified
-const akiba = @import("akiba");
+const colors = @import("colors");
+const format = @import("format");
+const io = @import("io");
+const sys = @import("sys");
-const Color = struct {
- const white: u32 = 0x00FFFFFF;
- const red: u32 = 0x00FF4444;
- const gray: u32 = 0x00888888;
-};
-
-// Buffer for file contents (64KB max)
var file_buffer: [64 * 1024]u8 = undefined;
export fn main(pc: u32, pv: [*]const [*:0]const u8) u8 {
- // No arguments - show error
if (pc <= 1) {
- _ = akiba.io.mark(akiba.io.stream, "rd: missing unit location.\n", Color.red) catch 0;
+ format.colorln("rd: missing unit location.", colors.red);
return 1;
}
- // Get location from argument
const arg = pv[1];
var location_len: usize = 0;
while (arg[location_len] != 0) : (location_len += 1) {}
const location = arg[0..location_len];
- // Open the file
- const fd = akiba.io.attach(location, akiba.io.VIEW_ONLY) catch {
- _ = akiba.io.mark(akiba.io.stream, "rd: cannot access '", Color.red) catch 0;
- _ = akiba.io.mark(akiba.io.stream, location, Color.white) catch 0;
- _ = akiba.io.mark(akiba.io.stream, "': No such unit.\n", Color.red) catch 0;
+ const fd = io.attach(location, io.VIEW_ONLY) catch {
+ format.color("rd: cannot access '", colors.red);
+ format.print(location);
+ format.colorln("': No such unit.", colors.red);
return 1;
};
- // Read contents
- const bytes_read = akiba.io.view(fd, &file_buffer) catch {
- _ = akiba.io.mark(akiba.io.stream, "rd: cannot read '", Color.red) catch 0;
- _ = akiba.io.mark(akiba.io.stream, location, Color.white) catch 0;
- _ = akiba.io.mark(akiba.io.stream, "'.\n", Color.red) catch 0;
- akiba.io.seal(fd);
+ const bytes_read = io.view(fd, &file_buffer) catch {
+ format.color("rd: cannot read '", colors.red);
+ format.print(location);
+ format.colorln("'.", colors.red);
+ io.seal(fd);
return 1;
};
- // Display contents
if (bytes_read > 0) {
- _ = akiba.io.mark(akiba.io.stream, file_buffer[0..bytes_read], Color.white) catch 0;
+ format.print(file_buffer[0..bytes_read]);
- // Add newline if file doesn't end with one
if (file_buffer[bytes_read - 1] != '\n') {
- _ = akiba.io.mark(akiba.io.stream, "\n", Color.white) catch 0;
+ format.print("\n");
}
}
- // Close file
- akiba.io.seal(fd);
+ io.seal(fd);
return 0;
}
diff --git a/binaries/rd/rd.zon b/binaries/rd/rd.zon
index 0480840..47cddc8 100644
--- a/binaries/rd/rd.zon
+++ b/binaries/rd/rd.zon
@@ -2,9 +2,10 @@
.name = "rd",
.version = "0.1.0",
.dependencies = .{
- .akiba = .{ .path = "../../system/libraries/akiba" },
- },
- .paths = .{
- "rd.zig",
+ .sys,
+ .io,
+ .colors,
+ .format,
},
+ .entry = "rd.zig",
}
diff --git a/binaries/wipe/wipe.zig b/binaries/wipe/wipe.zig
index 34c6f95..8bdc336 100644
--- a/binaries/wipe/wipe.zig
+++ b/binaries/wipe/wipe.zig
@@ -1,10 +1,11 @@
//! wipe - Clear the terminal screen
-const akiba = @import("akiba");
+const io = @import("io");
+const sys = @import("sys");
export fn main(pc: u32, pv: [*]const [*:0]const u8) u8 {
_ = pc;
_ = pv;
- akiba.io.wipe();
+ io.wipe();
return 0;
}
diff --git a/binaries/wipe/wipe.zon b/binaries/wipe/wipe.zon
index 0c6f141..4c90d6c 100644
--- a/binaries/wipe/wipe.zon
+++ b/binaries/wipe/wipe.zon
@@ -2,9 +2,8 @@
.name = "wipe",
.version = "0.1.0",
.dependencies = .{
- .akiba = .{ .path = "../../system/libraries/akiba" },
- },
- .paths = .{
- "wipe.zig",
+ .sys,
+ .io,
},
+ .entry = "wipe.zig",
}
diff --git a/system/ash/ash.zig b/system/ash/ash.zig
index 013de87..5149ab8 100644
--- a/system/ash/ash.zig
+++ b/system/ash/ash.zig
@@ -1,6 +1,11 @@
//! Ash - Akiba Shell
-const akiba = @import("akiba");
+const colors = @import("colors");
+const format = @import("format");
+const io = @import("io");
+const kata = @import("kata");
+const string = @import("string");
+const sys = @import("sys");
const MAX_INPUT = 256;
const MAX_ARGS = 16;
@@ -14,41 +19,35 @@ var letter_buffer: [256]u8 = undefined;
var arg_ptrs: [MAX_ARGS][*:0]const u8 = undefined;
var arg_storage: [MAX_ARGS][128]u8 = undefined;
-const Color = struct {
- const white: u32 = 0x00FFFFFF;
- const green: u32 = 0x0088FF88;
- const red: u32 = 0x00FF4444;
-};
-
export fn main(pc: u32, pv: [*]const [*:0]const u8) u8 {
_ = pc;
_ = pv;
while (true) {
- const location = akiba.io.getlocation(&location_buffer) catch "/";
- const stack_name = get_stack_name(location);
+ const location = io.getlocation(&location_buffer) catch "/";
+ const stack_name = string.getStackName(location);
- _ = akiba.io.mark(akiba.io.stream, "(", Color.white) catch {};
- _ = akiba.io.mark(akiba.io.stream, stack_name, Color.green) catch {};
- _ = akiba.io.mark(akiba.io.stream, ") >>> ", Color.white) catch {};
+ format.print("(");
+ format.color(stack_name, colors.green);
+ format.print(") >>> ");
input_len = 0;
while (true) {
- const char = akiba.io.getchar() catch continue;
+ const char = io.getchar() catch continue;
if (char == '\n') {
- _ = akiba.io.mark(akiba.io.stream, "\n", Color.white) catch {};
+ format.print("\n");
break;
} else if (char == '\x08') {
if (input_len > 0) {
input_len -= 1;
- _ = akiba.io.mark(akiba.io.stream, "\x08", Color.white) catch {};
+ format.print("\x08");
}
} else if (char >= 32 and char <= 126 and input_len < MAX_INPUT - 1) {
input_buffer[input_len] = char;
input_len += 1;
char_buffer[0] = char;
- _ = akiba.io.mark(akiba.io.stream, &char_buffer, Color.white) catch {};
+ format.print(&char_buffer);
}
}
@@ -87,99 +86,40 @@ fn execute_command(input: []const u8) void {
if (argc == 0) return;
- const cmd = arg_storage[0][0..find_null(&arg_storage[0])];
+ const cmd = arg_storage[0][0..string.findNull(&arg_storage[0])];
var path_buf: [512]u8 = undefined;
+ const path = string.concat3(&path_buf, "/binaries/", cmd, ".akiba");
- const path = build_path(&path_buf, "/binaries/", cmd, ".akiba");
if (try_spawn_with_args(path, arg_ptrs[0..argc])) {
process_letters();
return;
}
- _ = akiba.io.mark(akiba.io.stream, "ash: binary not found: ", Color.red) catch {};
- _ = akiba.io.mark(akiba.io.stream, cmd, Color.white) catch {};
- _ = akiba.io.mark(akiba.io.stream, ".\n", Color.white) catch {};
+ format.color("ash: binary not found: ", colors.red);
+ format.print(cmd);
+ format.println(".");
}
fn try_spawn_with_args(path: []const u8, argv: [][*:0]const u8) bool {
- const pid = akiba.kata.spawn_with_args(path, argv) catch {
+ const pid = kata.spawnWithArgs(path, argv) catch {
return false;
};
- _ = akiba.kata.wait(pid) catch {};
+ _ = kata.wait(pid) catch {};
return true;
}
fn process_letters() void {
- const letter_type = akiba.io.read_letter(&letter_buffer) catch return;
+ const letter_type = io.readLetter(&letter_buffer) catch return;
- if (letter_type == akiba.io.Letter.NAVIGATE) {
+ if (letter_type == io.Letter.NAVIGATE) {
var len: usize = 0;
while (len < letter_buffer.len and letter_buffer[len] != 0) : (len += 1) {}
if (len > 0) {
- akiba.io.setlocation(letter_buffer[0..len]) catch {};
+ io.setlocation(letter_buffer[0..len]) catch {};
}
}
}
-
-fn find_null(buf: []const u8) usize {
- var len: usize = 0;
- while (len < buf.len and buf[len] != 0) : (len += 1) {}
- return len;
-}
-
-fn build_path(buf: []u8, prefix: []const u8, name: []const u8, suffix: []const u8) []const u8 {
- var pos: usize = 0;
- for (prefix) |c| {
- if (pos >= buf.len) break;
- buf[pos] = c;
- pos += 1;
- }
- for (name) |c| {
- if (pos >= buf.len) break;
- buf[pos] = c;
- pos += 1;
- }
- for (suffix) |c| {
- if (pos >= buf.len) break;
- buf[pos] = c;
- pos += 1;
- }
- return buf[0..pos];
-}
-
-fn get_stack_name(location: []const u8) []const u8 {
- // Root case
- if (location.len == 0 or (location.len == 1 and location[0] == '/')) {
- return "/";
- }
-
- // Find last '/' and return everything after it
- var last_slash: usize = 0;
- for (location, 0..) |c, i| {
- if (c == '/') {
- last_slash = i;
- }
- }
-
- // If path ends with '/', look for second-to-last slash
- 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];
- }
-
- // Return part after last slash
- if (last_slash + 1 < location.len) {
- return location[last_slash + 1 ..];
- }
-
- return location;
-}
diff --git a/system/ash/ash.zon b/system/ash/ash.zon
index 0c72775..e96488a 100644
--- a/system/ash/ash.zon
+++ b/system/ash/ash.zon
@@ -1,8 +1,13 @@
.{
.name = "ash",
.version = "0.1.0",
- .paths = .{""},
.dependencies = .{
- .akiba = .{ .path = "../libraries/akiba" },
+ .sys,
+ .io,
+ .kata,
+ .colors,
+ .string,
+ .format,
},
+ .entry = "ash.zig",
}
diff --git a/system/libraries/akiba/akiba.zig b/system/libraries/akiba/akiba.zig
deleted file mode 100644
index 77911e1..0000000
--- a/system/libraries/akiba/akiba.zig
+++ /dev/null
@@ -1,10 +0,0 @@
-//! Akiba Runtime - Core system library
-
-pub const kata = @import("kata.zig");
-pub const io = @import("io.zig");
-pub const sys = @import("sys.zig");
-pub const start = @import("start.zig");
-
-comptime {
- _ = start;
-}
diff --git a/system/libraries/akiba/akiba.zon b/system/libraries/akiba/akiba.zon
deleted file mode 100644
index aad4a03..0000000
--- a/system/libraries/akiba/akiba.zon
+++ /dev/null
@@ -1,6 +0,0 @@
-.{
- .name = "akiba",
- .version = "1.0.0",
- .type = .library,
- .entry = "akiba.zig",
-}
diff --git a/system/libraries/akiba/io.zig b/system/libraries/akiba/io.zig
deleted file mode 100644
index 155ac70..0000000
--- a/system/libraries/akiba/io.zig
+++ /dev/null
@@ -1,168 +0,0 @@
-//! File I/O operations
-
-const sys = @import("sys.zig");
-const kata = @import("kata.zig");
-
-pub const Error = error{
- NotFound,
- PermissionDenied,
- InvalidDescriptor,
- ReadFailed,
- WriteFailed,
-};
-
-pub const FileDescriptor = u32;
-
-// Standard file descriptors
-pub const source: FileDescriptor = 0; // Input stream
-pub const stream: FileDescriptor = 1; // Output stream
-pub const trace: FileDescriptor = 2; // Error/trace stream
-
-// Open modes
-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,
-};
-
-// Letter types
-pub const Letter = struct {
- pub const NONE: u8 = 0;
- pub const NAVIGATE: u8 = 1;
-};
-
-pub fn attach(path: []const u8, flags: u32) Error!FileDescriptor {
- const result = sys.syscall(.attach, .{ @intFromPtr(path.ptr), flags });
- if (result == @as(u64, @bitCast(@as(i64, -1)))) {
- return Error.NotFound;
- }
- return @truncate(result);
-}
-
-pub fn seal(fd: FileDescriptor) void {
- _ = sys.syscall(.seal, .{fd});
-}
-
-pub fn view(fd: FileDescriptor, buffer: []u8) Error!usize {
- const result = sys.syscall(.view, .{ fd, @intFromPtr(buffer.ptr), buffer.len });
- if (result == @as(u64, @bitCast(@as(i64, -1)))) {
- return Error.ReadFailed;
- }
- return result;
-}
-
-pub fn viewstack(path: []const u8, entries: []StackEntry) !usize {
- const result = sys.syscall(.viewstack, .{
- @intFromPtr(path.ptr),
- path.len,
- @intFromPtr(entries.ptr),
- entries.len,
- });
-
- // Check for error (-1)
- if (result == @as(u64, @bitCast(@as(i64, -1)))) {
- return error.InvalidPath;
- }
-
- return @intCast(result);
-}
-
-pub fn mark(fd: FileDescriptor, data: []const u8, color: u32) Error!usize {
- const result = sys.syscall(.mark, .{ fd, @intFromPtr(data.ptr), data.len, color });
- if (result == @as(u64, @bitCast(@as(i64, -1)))) {
- return Error.WriteFailed;
- }
- return result;
-}
-
-pub fn getchar() !u8 {
- // Loop until character is available
- while (true) {
- const result = sys.syscall(.getkeychar, .{});
- if (result != @as(u64, @bitCast(@as(i64, -2)))) {
- if (result != @as(u64, @bitCast(@as(i64, -1)))) {
- return @truncate(result);
- }
- return error.ReadFailed;
- }
- // No input yet (-2 = EAGAIN), yield to kernel
- kata.yield();
- }
-}
-
-pub fn getlocation(buffer: []u8) ![]u8 {
- const result = sys.syscall(.getlocation, .{
- @intFromPtr(buffer.ptr),
- buffer.len,
- });
-
- if (result == @as(u64, @bitCast(@as(i64, -1)))) {
- return error.GetLocationFailed;
- }
-
- return buffer[0..@intCast(result)];
-}
-
-pub fn setlocation(path: []const u8) !void {
- const result = sys.syscall(.setlocation, .{
- @intFromPtr(path.ptr),
- path.len,
- });
-
- if (result == @as(u64, @bitCast(@as(i64, -1)))) {
- return error.InvalidPath;
- }
-}
-
-/// Send a letter to parent Kata
-pub fn send_letter(letter_type: u8, data: []const u8) !void {
- const result = sys.syscall(.postman, .{
- @as(u64, 0), // MODE_SEND
- @as(u64, letter_type),
- @intFromPtr(data.ptr),
- data.len,
- });
-
- if (result == @as(u64, @bitCast(@as(i64, -1)))) {
- return error.SendFailed;
- }
-}
-
-/// Read letter from inbox
-/// Returns letter type (0 = no letter), copies data to buffer
-pub fn read_letter(buffer: []u8) !u8 {
- const result = sys.syscall(.postman, .{
- @as(u64, 1), // MODE_READ
- @intFromPtr(buffer.ptr),
- buffer.len,
- });
-
- if (result == @as(u64, @bitCast(@as(i64, -1)))) {
- return error.ReadFailed;
- }
-
- return @intCast(result);
-}
-
-pub fn wipe() void {
- _ = sys.syscall(.wipe, .{});
-}
-
-pub fn print(text: []const u8) Error!void {
- _ = try mark(stream, text, 0x00FFFFFF);
-}
-
-pub fn println(text: []const u8) Error!void {
- _ = try mark(stream, text, 0x00FFFFFF);
- _ = try mark(stream, "\n", 0x00FFFFFF);
-}
diff --git a/system/libraries/akiba/kata.zig b/system/libraries/akiba/kata.zig
deleted file mode 100644
index be3189b..0000000
--- a/system/libraries/akiba/kata.zig
+++ /dev/null
@@ -1,38 +0,0 @@
-//! Kata (process) control functions
-
-const sys = @import("sys.zig");
-
-pub fn yield() void {
- _ = sys.syscall(.yield, .{});
-}
-
-pub fn exit(code: u64) noreturn {
- _ = sys.syscall(.exit, .{code});
- unreachable;
-}
-
-pub fn spawn(path: []const u8) !u32 {
- const result = sys.syscall(.spawn, .{ @intFromPtr(path.ptr), path.len, @as(u64, 0), @as(u64, 0) });
- if (result == @as(u64, @bitCast(@as(i64, -1)))) {
- return error.SpawnFailed;
- }
- return @truncate(result);
-}
-
-pub fn spawn_with_args(path: []const u8, argv: [][*:0]const u8) !u32 {
- const result = sys.syscall(.spawn, .{ @intFromPtr(path.ptr), path.len, @intFromPtr(argv.ptr), argv.len });
- if (result == @as(u64, @bitCast(@as(i64, -1)))) {
- return error.SpawnFailed;
- }
- return @truncate(result);
-}
-
-pub fn wait(pid: u32) !u64 {
- while (true) {
- const result = sys.syscall(.wait, .{pid});
- if (result != @as(u64, @bitCast(@as(i64, -1)))) {
- return result;
- }
- yield();
- }
-}
diff --git a/system/libraries/akiba/start.zig b/system/libraries/akiba/start.zig
deleted file mode 100644
index fbe11e2..0000000
--- a/system/libraries/akiba/start.zig
+++ /dev/null
@@ -1,31 +0,0 @@
-//! Akiba Runtime Entry Point
-//! Provides _start that calls user's main(pc, pv) and handles exit
-
-// User must provide this
-extern fn main(pc: u32, pv: [*]const [*:0]const u8) u8;
-
-export fn _start() callconv(.naked) noreturn {
- // At entry, stack layout is:
- // [RSP + 0] = pc (parameter count, 64-bit but only low 32 used)
- // [RSP + 8] = pv (pointer to parameter vector)
- //
- // x86-64 calling convention:
- // First arg (u32) -> EDI
- // Second arg (ptr) -> RSI
-
- asm volatile (
- // Load arguments for main(pc, pv)
- \\mov (%%rsp), %%edi
- \\mov 8(%%rsp), %%rsi
- // Align stack to 16 bytes before call (required by ABI)
- \\and $-16, %%rsp
- \\call main
- // main returned exit code in AL, zero-extend to RDI for exit syscall
- \\movzbl %%al, %%edi
- // exit syscall (0x01)
- \\mov $0x01, %%eax
- \\syscall
- // Should never reach here
- \\ud2
- );
-}
diff --git a/system/libraries/akiba/sys.zig b/system/libraries/akiba/sys.zig
deleted file mode 100644
index b2da4f1..0000000
--- a/system/libraries/akiba/sys.zig
+++ /dev/null
@@ -1,40 +0,0 @@
-//! Low-level invocation interface
-
-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 };
-
-/// Perform a system invocation with variable arguments
-/// Uses comptime to handle different argument counts
-pub inline fn syscall(invocation: Invocation, args: anytype) u64 {
- const Args = @TypeOf(args);
- const fields = @typeInfo(Args).@"struct".fields;
-
- // Always set all 6 argument registers, defaulting unused ones to 0
- const arg0: u64 = if (fields.len > 0) @as(u64, @bitCast(toU64(args[0]))) else 0;
- const arg1: u64 = if (fields.len > 1) @as(u64, @bitCast(toU64(args[1]))) else 0;
- const arg2: u64 = if (fields.len > 2) @as(u64, @bitCast(toU64(args[2]))) else 0;
- const arg3: u64 = if (fields.len > 3) @as(u64, @bitCast(toU64(args[3]))) else 0;
- const arg4: u64 = if (fields.len > 4) @as(u64, @bitCast(toU64(args[4]))) else 0;
- const arg5: u64 = if (fields.len > 5) @as(u64, @bitCast(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 });
-}
-
-/// Convert various types to u64 for syscall arguments
-inline fn toU64(value: anytype) u64 {
- const T = @TypeOf(value);
- return switch (@typeInfo(T)) {
- .int, .comptime_int => @as(u64, @intCast(value)),
- .pointer => @intFromPtr(value),
- .@"enum" => @intFromEnum(value),
- else => @as(u64, @bitCast(value)),
- };
-}
diff --git a/system/pulse/pulse.zig b/system/pulse/pulse.zig
index d0f3dd2..3ef1091 100644
--- a/system/pulse/pulse.zig
+++ b/system/pulse/pulse.zig
@@ -1,29 +1,27 @@
//! Pulse - Akiba OS Init System
-//! First Kata to run (PID 1), manages system lifecycle
-const akiba = @import("akiba");
+const format = @import("format");
+const kata = @import("kata");
+const sys = @import("sys");
export fn main(pc: u32, pv: [*]const [*:0]const u8) u8 {
_ = pc;
_ = pv;
- // Init loop - respawn shell when it exits
while (true) {
- const shell_pid = akiba.kata.spawn("/system/ash/ash.akiba") catch {
- akiba.io.println("Pulse: Failed to spawn shell") catch {};
- akiba.kata.yield();
+ const shell_pid = kata.spawn("/system/ash/ash.akiba") catch {
+ format.println("Pulse: Failed to spawn shell");
+ kata.yield();
continue;
};
- // Wait for shell to exit
- _ = akiba.kata.wait(shell_pid) catch {
- akiba.io.println("Pulse: Shell wait failed") catch {};
- akiba.kata.yield();
+ _ = kata.wait(shell_pid) catch {
+ format.println("Pulse: Shell wait failed");
+ kata.yield();
continue;
};
- // Shell exited, respawn
- akiba.io.println("\nPulse: Shell exited, respawning...\n") catch {};
+ format.println("\nPulse: Shell exited, respawning...\n");
}
return 0;
diff --git a/system/pulse/pulse.zon b/system/pulse/pulse.zon
index d35e8c9..6a8da7f 100644
--- a/system/pulse/pulse.zon
+++ b/system/pulse/pulse.zon
@@ -1,8 +1,10 @@
.{
.name = "pulse",
- .version = "1.0.0",
- .type = .init,
+ .version = "0.1.0",
.dependencies = .{
- "akiba",
+ .sys,
+ .kata,
+ .format,
},
+ .entry = "pulse.zig",
}