hachem.wtf
aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--boot/elf.zig1
-rw-r--r--boot/sched.zig59
-rw-r--r--boot/user.zig172
-rw-r--r--bridge/bridge.zig12
-rw-r--r--build.zig5
-rw-r--r--gils/cat.rv6
-rw-r--r--gils/cp.rv4
-rw-r--r--gils/gils.rv2
-rw-r--r--gils/head.rv4
-rw-r--r--gils/mkdir.rv2
-rw-r--r--gils/mv.rv4
-rw-r--r--gils/rm.rv2
-rw-r--r--gils/tail.rv4
-rw-r--r--gils/touch.rv4
-rw-r--r--gils/tree.rv4
-rw-r--r--gils/wc.rv4
-rw-r--r--kernel/console.rv94
-rw-r--r--kernel/fs.rv49
-rw-r--r--kernel/io.rv37
-rw-r--r--kernel/main.rv4
-rw-r--r--kernel/proc.rv4
-rw-r--r--kernel/seed.rv10
-rw-r--r--kernel/shell.rv81
-rw-r--r--user/chat.c33
-rw-r--r--user/hexview.c16
-rw-r--r--user/save.c34
-rw-r--r--user/user.h58
27 files changed, 530 insertions, 179 deletions
diff --git a/boot/elf.zig b/boot/elf.zig
index 2070db6..a6e621c 100644
--- a/boot/elf.zig
+++ b/boot/elf.zig
@@ -4,4 +4,5 @@ pub const programs = [_]Program{
.{ .name = "calc", .bytes = @embedFile("user_calc") },
.{ .name = "primes", .bytes = @embedFile("user_primes") },
.{ .name = "save", .bytes = @embedFile("user_save") },
+ .{ .name = "chat", .bytes = @embedFile("user_chat") },
};
diff --git a/boot/sched.zig b/boot/sched.zig
index 383b40d..30d5698 100644
--- a/boot/sched.zig
+++ b/boot/sched.zig
@@ -8,9 +8,20 @@ const bridge = @import("bridge");
const MAX_TASKS = 8;
const KSTACK_SIZE = 16 * 1024;
+const MAX_FDS = 8;
+const MAX_PATH = 128;
const State = enum { free, ready, dead, blocked };
+// file descriptor not "foid decimator"
+pub const FdKind = enum { closed, keyboard, console, file };
+pub const Fd = struct {
+ kind: FdKind = .closed,
+ offset: u64 = 0,
+ path_len: usize = 0,
+ path: [MAX_PATH]u8 = @splat(0),
+};
+
const Task = struct {
frame: Frame = std.mem.zeroes(Frame),
cr3: u64 = 0,
@@ -20,6 +31,7 @@ const Task = struct {
var tasks: [MAX_TASKS]Task = @splat(.{});
var kstacks: [MAX_TASKS][KSTACK_SIZE]u8 align(16) = undefined;
+var fdtabs: [MAX_TASKS][MAX_FDS]Fd = @splat(@splat(.{}));
var current: usize = 0;
var blocked_reader: ?usize = null;
@@ -53,10 +65,10 @@ pub fn spawn(cr3: u64, entry: u64, ustack: u64, arg: u64, arglen: u64) void {
var f = std.mem.zeroes(Frame);
f.rip = entry;
f.cs = 0x1b; // user code (0x18) | rpl 3
- f.rflags = 0x202; // reserved bit + if=1, so its preemptible
+ f.rflags = 0x202; // reserved bit + if=1 so its preemptible
f.rsp = ustack;
f.ss = 0x23; // user data (0x20) | rpl 3
- f.rdi = arg; // _start(arg_ptr, arg_len), the sysv first two args
+ f.rdi = arg; // _start(arg_ptr, arg_len) the sysv first two args
f.rsi = arglen;
tasks[i] = .{
.frame = f,
@@ -64,10 +76,51 @@ pub fn spawn(cr3: u64, entry: u64, ustack: u64, arg: u64, arglen: u64) void {
.kstack_top = @intFromPtr(&kstacks[i]) + KSTACK_SIZE,
.state = .ready,
};
+ initFds(i);
return;
}
}
+// stdin at keyboard
+fn initFds(i: usize) void {
+ for (&fdtabs[i]) |*f| f.* = .{};
+ fdtabs[i][0].kind = .keyboard;
+ fdtabs[i][1].kind = .console;
+ fdtabs[i][2].kind = .console;
+}
+
+// foid decimator open
+pub fn fdOpen(path: []const u8) i64 {
+ var i: usize = 3;
+ while (i < MAX_FDS) : (i += 1) {
+ const f = &fdtabs[current][i];
+ if (f.kind == .closed) {
+ f.kind = .file;
+ f.offset = 0;
+ const n = @min(path.len, MAX_PATH);
+ @memcpy(f.path[0..n], path[0..n]);
+ f.path_len = n;
+ return @intCast(i);
+ }
+ }
+ return -1;
+}
+
+// foid decimator get
+pub fn fdGet(fd: i64) ?*Fd {
+ if (fd < 0 or fd >= MAX_FDS) return null;
+ const f = &fdtabs[current][@intCast(fd)];
+ if (f.kind == .closed) return null;
+ return f;
+}
+
+// foid decimator close
+pub fn fdClose(fd: i64) i64 {
+ const f = fdGet(fd) orelse return -1;
+ f.kind = .closed;
+ return 0;
+}
+
pub fn procCount() u64 {
var count: u64 = 0;
var i: usize = 1;
@@ -122,7 +175,7 @@ pub fn blockCurrentOnRead(resume_frame: Frame) void {
pub fn deliverInput(byte: u8) bool {
if (blocked_reader) |task| {
- tasks[task].frame.rax = byte;
+ stdinPush(byte);
tasks[task].state = .ready;
blocked_reader = null;
return true;
diff --git a/boot/user.zig b/boot/user.zig
index 9bce9e9..78d20ff 100644
--- a/boot/user.zig
+++ b/boot/user.zig
@@ -8,8 +8,17 @@ const regs = @import("regs.zig");
const bridge = @import("bridge");
const Frame = regs.Frame;
-// scratch for a filename copied out of the caller legit one static buffer is fine
-var name_buf: [64]u8 = undefined;
+// what a syscall returns in rax on failure
+const SYS_ERR: u64 = @bitCast(@as(i64, -1));
+
+// open() flags (linux values lmao)
+const O_CREAT: u64 = 0x40;
+const O_TRUNC: u64 = 0x200;
+const O_APPEND: u64 = 0x400;
+
+// scratch for a filename copied out of the caller
+// legit one static buffer is fine
+var name_buf: [128]u8 = undefined;
fn userName(ptr: u64) []const u8 {
const p: [*]const u8 = @ptrFromInt(ptr);
var i: usize = 0;
@@ -62,63 +71,144 @@ export fn syscallStub() callconv(.naked) void {
}
export fn syscallHandler(frame: *SyscallFrame) callconv(.c) void {
+ // i js reorganized half of these so if anyone wrote code in asm
+ // for this (me), your syscalled are fucked
switch (frame.rax) {
0 => { // exit(code): code in rdi
sched.exitCurrent();
asm volatile ("sti");
while (true) asm volatile ("hlt");
},
- 1 => { // write(ptr, len): rdi = user pointer, rsi = length
- const len = frame.rsi;
- if (len > 0 and len <= 4096) {
- const bytes: [*]const u8 = @ptrFromInt(frame.rdi);
- serial.write(bytes[0..len]);
+ 1 => { // write(fd, ptr, len)
+ const len = frame.rdx;
+ if (sched.fdGet(@bitCast(frame.rdi))) |f| {
+ if (f.kind == .console) {
+ if (len > 0 and len <= 4096) {
+ const bytes: [*]const u8 = @ptrFromInt(frame.rsi);
+ serial.write(bytes[0..len]);
+ }
+ frame.rax = len;
+ } else if (f.kind == .file) {
+ const n = @min(len, 4096);
+ const src: [*]const u8 = @ptrFromInt(frame.rsi);
+ if (bridge.fsWriteAt(f.path[0..f.path_len], f.offset, src[0..n])) {
+ f.offset += n;
+ frame.rax = n;
+ } else frame.rax = SYS_ERR;
+ } else {
+ frame.rax = SYS_ERR; // keyboard isnt writable
+ }
+ } else frame.rax = SYS_ERR;
+ },
+ 2 => { // read(fd, buf, count)
+ const count = frame.rdx;
+ const f = sched.fdGet(@bitCast(frame.rdi)) orelse {
+ frame.rax = SYS_ERR;
+ return;
+ };
+ switch (f.kind) {
+ .keyboard => {
+ if (count == 0) {
+ frame.rax = 0;
+ return;
+ }
+ if (sched.readReady()) |byte| {
+ const dst: [*]u8 = @ptrFromInt(frame.rsi);
+ dst[0] = byte;
+ frame.rax = 1;
+ return;
+ }
+ // nothn buffered
+ const resume_frame: Frame = .{
+ .r15 = frame.r15,
+ .r14 = frame.r14,
+ .r13 = frame.r13,
+ .r12 = frame.r12,
+ .r11 = frame.r11,
+ .r10 = frame.r10,
+ .r9 = frame.r9,
+ .r8 = frame.r8,
+ .rbp = frame.rbp,
+ .rdi = frame.rdi,
+ .rsi = frame.rsi,
+ .rdx = frame.rdx,
+ .rcx = frame.rcx,
+ .rbx = frame.rbx,
+ .rax = frame.rax,
+ .vector = 0,
+ .error_code = 0,
+ .rip = frame.rip - 2,
+ .cs = frame.cs,
+ .rflags = frame.rflags,
+ .rsp = frame.rsp,
+ .ss = frame.ss,
+ };
+ sched.blockCurrentOnRead(resume_frame);
+ asm volatile ("sti");
+ while (true) asm volatile ("hlt");
+ },
+ .file => {
+ const n = @min(count, 4096);
+ const dst: [*]u8 = @ptrFromInt(frame.rsi);
+ const got = bridge.fsReadInto(f.path[0..f.path_len], f.offset, dst[0..n]);
+ f.offset += got;
+ frame.rax = got;
+ },
+ else => frame.rax = SYS_ERR,
}
- frame.rax = len; // syscall return value
},
- 2 => { // read(): return a buffered byte, else block for one
- if (sched.readReady()) |byte| {
- frame.rax = byte;
+ 7 => { // open(path_ptr, flags)
+ const name = userName(frame.rdi);
+ const flags = frame.rsi;
+ var size = bridge.fsSize(name);
+ if (size < 0) {
+ if (flags & O_CREAT != 0 and bridge.fsStore(name, "")) {
+ size = 0;
+ } else {
+ frame.rax = SYS_ERR;
+ return;
+ }
+ } else if (flags & O_TRUNC != 0) {
+ _ = bridge.fsStore(name, "");
+ size = 0;
+ }
+ const fd = sched.fdOpen(name);
+ if (fd < 0) {
+ frame.rax = SYS_ERR;
return;
}
- const resume_frame: Frame = .{
- .r15 = frame.r15,
- .r14 = frame.r14,
- .r13 = frame.r13,
- .r12 = frame.r12,
- .r11 = frame.r11,
- .r10 = frame.r10,
- .r9 = frame.r9,
- .r8 = frame.r8,
- .rbp = frame.rbp,
- .rdi = frame.rdi,
- .rsi = frame.rsi,
- .rdx = frame.rdx,
- .rcx = frame.rcx,
- .rbx = frame.rbx,
- .rax = frame.rax,
- .vector = 0,
- .error_code = 0,
- .rip = frame.rip,
- .cs = frame.cs,
- .rflags = frame.rflags,
- .rsp = frame.rsp,
- .ss = frame.ss,
- };
- sched.blockCurrentOnRead(resume_frame);
- asm volatile ("sti");
- while (true) asm volatile ("hlt");
+ if (flags & O_APPEND != 0) {
+ if (sched.fdGet(fd)) |f| f.offset = @intCast(size);
+ }
+ frame.rax = @bitCast(fd);
+ },
+ 8 => { // close(fd)
+ frame.rax = @bitCast(sched.fdClose(@bitCast(frame.rdi)));
+ },
+ 9 => { // lseek(fd, offset, whence)
+ if (sched.fdGet(@bitCast(frame.rdi))) |f| {
+ switch (frame.rdx) {
+ 0 => f.offset = frame.rsi, // SEEK_SET
+ 1 => f.offset += frame.rsi, // SEEK_CUR
+ 2 => { // SEEK_END
+ const sz = bridge.fsSize(f.path[0..f.path_len]);
+ if (sz >= 0) f.offset = @as(u64, @intCast(sz)) +% frame.rsi;
+ },
+ else => {},
+ }
+ frame.rax = f.offset;
+ } else frame.rax = SYS_ERR;
},
- 4 => { // fs_size(name_ptr): returns size (like obv), or -1
+ 4 => { // fs_size(name_ptr)
frame.rax = @bitCast(bridge.fsSize(userName(frame.rdi)));
},
- 5 => { // fs_read(name_ptr, offset, buf_ptr, len): returns bytes read
+ 5 => { // fs_read(name_ptr, offset, buf_ptr, len)
const len = @min(frame.rcx, 4096);
const name = userName(frame.rdi);
const dst: [*]u8 = @ptrFromInt(frame.rdx);
frame.rax = bridge.fsReadInto(name, frame.rsi, dst[0..len]);
},
- 6 => { // fs_write(name_ptr, buf_ptr, len): returns 1 ok / 0 fail
+ 6 => { // fs_write(name_ptr, buf_ptr, len)
const len = @min(frame.rdx, 64 * 1024);
const name = userName(frame.rdi);
const src: [*]const u8 = @ptrFromInt(frame.rsi);
diff --git a/bridge/bridge.zig b/bridge/bridge.zig
index 56cfc7f..4570e3d 100644
--- a/bridge/bridge.zig
+++ b/bridge/bridge.zig
@@ -21,6 +21,7 @@ const init_program = blk: {
@embedFile("k_console") ++ "\n" ++
@embedFile("k_vmm") ++ "\n" ++
@embedFile("k_fs") ++ "\n" ++
+ @embedFile("k_io") ++ "\n" ++
@embedFile("k_vfs") ++ "\n" ++
@embedFile("k_seed") ++ "\n";
@@ -179,3 +180,14 @@ pub fn fsStore(name: []const u8, data: []const u8) bool {
const r = vm.callFunctionParts(func, null, &[_]revo.Value{ name_val, data_val }, null) catch return false;
return (r.asNumOpt() orelse 0) == 1;
}
+
+pub fn fsWriteAt(name: []const u8, offset: u64, data: []const u8) bool {
+ const vm = g_vm orelse return false;
+ const func = vm.getGlobal("fs_write_at") orelse return false;
+ const name_val = vm.ownValueString(name) catch return false;
+ const data_val = vm.ownValueString(data) catch return false;
+ g_vm_running = true;
+ defer g_vm_running = false;
+ const r = vm.callFunctionParts(func, null, &[_]revo.Value{ name_val, revo.Value.new.num(@as(f64, @floatFromInt(offset))), data_val }, null) catch return false;
+ return (r.asNumOpt() orelse 0) == 1;
+}
diff --git a/build.zig b/build.zig
index 2a4466e..b8683c5 100644
--- a/build.zig
+++ b/build.zig
@@ -71,6 +71,7 @@ pub fn build(b: *std.Build) void {
.{ "k_console", "kernel/console.rv" },
.{ "k_vmm", "kernel/vmm.rv" },
.{ "k_fs", "kernel/fs.rv" },
+ .{ "k_io", "kernel/io.rv" },
.{ "k_vfs", "kernel/vfs.rv" },
.{ "k_seed", "kernel/seed.rv" },
.{ "k_proc", "kernel/proc.rv" },
@@ -102,7 +103,7 @@ pub fn build(b: *std.Build) void {
kernel.root_module.addAnonymousImport(e[0], .{ .root_source_file = b.path(e[1]) });
}
- inline for (.{ "hexview", "calc", "primes", "save" }) |prog| {
+ inline for (.{ "hexview", "calc", "primes", "save", "chat" }) |prog| {
const cc = b.addSystemCommand(&.{
"zig", "cc",
"-target", "x86_64-freestanding",
@@ -114,6 +115,8 @@ pub fn build(b: *std.Build) void {
});
const prog_elf = cc.addOutputFileArg(prog ++ ".elf");
cc.addFileArg(b.path("user/" ++ prog ++ ".c"));
+ cc.addFileInput(b.path("user/user.h"));
+ cc.addFileInput(b.path("user/link.ld"));
kernel.root_module.addAnonymousImport("user_" ++ prog, .{ .root_source_file = prog_elf });
}
diff --git a/gils/cat.rv b/gils/cat.rv
index 05ab418..0666304 100644
--- a/gils/cat.rv
+++ b/gils/cat.rv
@@ -2,10 +2,8 @@
const context = env.ctx
const parsed = arg_name(context.rest, 0)
-
-if parsed.name:len() == 0 do
- puts("usage: cat <path>\n")
-end else do
+if parsed.name:len() == 0 do fail("usage: cat <path>\n") end
+else do
const path = expand_path(parsed.name)
if vfs_owns(path) do vfs_cat(path) end
else do fs:cat(path) end
diff --git a/gils/cp.rv b/gils/cp.rv
index 5006acb..20d4ae3 100644
--- a/gils/cp.rv
+++ b/gils/cp.rv
@@ -2,12 +2,12 @@
# HAAAAAANNNNKKKK
const context = env.ctx
-if context.argv:len() < 3 do puts("usage: cp <source> <destination>\n") end
+if context.argv:len() < 3 do fail("usage: cp <source> <destination>\n") end
else do
const source = expand_path(context.argv[1])
const destination = expand_path(context.argv[2])
const size = fs:size(source)
- if size < 0 do puts("cp: #{source}: no such file\n") end
+ if size < 0 do fail("cp: #{source}: no such file\n") end
else do
const contents = if size > 0 fs:read_bytes(source, 0, size) else ""
if fs:store(destination, contents) == 1 do puts("#{source} -> #{destination}\n") end
diff --git a/gils/gils.rv b/gils/gils.rv
index 08c97cd..a500322 100644
--- a/gils/gils.rv
+++ b/gils/gils.rv
@@ -39,7 +39,7 @@ fn run_script_path(path, label, ctx) do
if size < 0 return :false
env.ctx = ctx
const error_msg = eval_script(fs:read_bytes(path, 0, size))
- if error_msg != :nil do puts("#{label}: #{error_msg}\n") end
+ if error_msg != :nil do fail("#{label}: #{error_msg}\n") end
return :true
end
diff --git a/gils/head.rv b/gils/head.rv
index addd11a..2c2a82f 100644
--- a/gils/head.rv
+++ b/gils/head.rv
@@ -13,13 +13,13 @@ fn file_lines(path) do
end
const context = env.ctx
-if context.argv:len() < 2 do puts("usage: head [n] <path>\n") end
+if context.argv:len() < 2 do fail("usage: head [n] <path>\n") end
else do
let limit = 10
let path_arg = context.argv[1]
if (context.argv:len() >= 3 and parse_pid(context.argv[1]) >= 0) do limit = parse_pid(context.argv[1]) path_arg = context.argv[2] end
const lines = file_lines(expand_path(path_arg))
- if lines == :nil do puts("head: no such file\n") end
+ if lines == :nil do fail("head: no such file\n") end
else do
let index = 0
while (index < lines:len() and index < limit) do puts("#{lines[index]}\n") index += 1 end
diff --git a/gils/mkdir.rv b/gils/mkdir.rv
index 759544e..c7d12f7 100644
--- a/gils/mkdir.rv
+++ b/gils/mkdir.rv
@@ -1,5 +1,5 @@
# make a directory
const context = env.ctx
-if context.argv:len() < 2 do puts("usage: mkdir <path>\n") end
+if context.argv:len() < 2 do fail("usage: mkdir <path>\n") end
else do fs:mkdir(expand_path(context.argv[1])) end
diff --git a/gils/mv.rv b/gils/mv.rv
index d3ecf47..b44995b 100644
--- a/gils/mv.rv
+++ b/gils/mv.rv
@@ -1,12 +1,12 @@
# move or rename a file
const context = env.ctx
-if context.argv:len() < 3 do puts("usage: mv <source> <destination>\n") end
+if context.argv:len() < 3 do fail("usage: mv <source> <destination>\n") end
else do
const source = expand_path(context.argv[1])
const destination = expand_path(context.argv[2])
const size = fs:size(source)
- if size < 0 do puts("mv: #{source}: no such file\n") end
+ if size < 0 do fail("mv: #{source}: no such file\n") end
else do
const contents = if size > 0 fs:read_bytes(source, 0, size) else ""
if fs:store(destination, contents) == 1 do fs:unlink(source) puts("#{source} -> #{destination}\n") end
diff --git a/gils/rm.rv b/gils/rm.rv
index 891dc27..236d2ba 100644
--- a/gils/rm.rv
+++ b/gils/rm.rv
@@ -2,5 +2,5 @@
const context = env.ctx
const parsed = arg_name(context.rest, 0)
-if parsed.name:len() == 0 do puts("usage: rm <path>\n") end
+if parsed.name:len() == 0 do fail("usage: rm <path>\n") end
else do fs:rm(expand_path(parsed.name)) end
diff --git a/gils/tail.rv b/gils/tail.rv
index 4a661b4..c1ca124 100644
--- a/gils/tail.rv
+++ b/gils/tail.rv
@@ -14,13 +14,13 @@ fn file_lines(path) do
end
const context = env.ctx
-if context.argv:len() < 2 do puts("usage: tail [n] <path>\n") end
+if context.argv:len() < 2 do fail("usage: tail [n] <path>\n") end
else do
let limit = 10
let path_arg = context.argv[1]
if (context.argv:len() >= 3 and parse_pid(context.argv[1]) >= 0) do limit = parse_pid(context.argv[1]) path_arg = context.argv[2] end
const lines = file_lines(expand_path(path_arg))
- if lines == :nil do puts("tail: no such file\n") end
+ if lines == :nil do fail("tail: no such file\n") end
else do
let start = lines:len() - limit
if start < 0 do start = 0 end
diff --git a/gils/touch.rv b/gils/touch.rv
index 84ecca8..f8e3e18 100644
--- a/gils/touch.rv
+++ b/gils/touch.rv
@@ -1,9 +1,9 @@
# dont touch my nono square
const context = env.ctx
-if context.argv:len() < 2 do puts("usage: touch <path>\n") end
+if context.argv:len() < 2 do fail("usage: touch <path>\n") end
else do
const path = expand_path(context.argv[1])
- if fs:is_dir(path) do puts("touch: #{path}: is a directory\n") end
+ if fs:is_dir(path) do fail("touch: #{path}: is a directory\n") end
else if fs:size(path) < 0 do fs:store(path, "") end
end
diff --git a/gils/tree.rv b/gils/tree.rv
index cc41601..d1a6af6 100644
--- a/gils/tree.rv
+++ b/gils/tree.rv
@@ -21,8 +21,8 @@ end
const context = env.ctx
const target = if context.argv:len() > 1 expand_path(context.argv[1]) else wd.path
-if (vfs_owns(target) and target != "/") do puts("tree: #{target}: virtual dir\n") end
-else if (target != "/" and fs:is_dir(target) == :false) do puts("tree: #{target}: not a directory\n") end
+if (vfs_owns(target) and target != "/") do fail("tree: #{target}: virtual dir\n") end
+else if (target != "/" and fs:is_dir(target) == :false) do fail("tree: #{target}: not a directory\n") end
else do
puts("#{target}\n")
tree_walk(target, "")
diff --git a/gils/wc.rv b/gils/wc.rv
index 9a184ca..1127299 100644
--- a/gils/wc.rv
+++ b/gils/wc.rv
@@ -1,11 +1,11 @@
# word count
const context = env.ctx
-if context.argv:len() < 2 do puts("usage: wc <path>\n") end
+if context.argv:len() < 2 do fail("usage: wc <path>\n") end
else do
const path = expand_path(context.argv[1])
const size = fs:size(path)
- if size < 0 do puts("wc: #{path}: no such file\n") end
+ if size < 0 do fail("wc: #{path}: no such file\n") end
else do
const contents = if size > 0 fs:read_bytes(path, 0, size) else ""
let line_count = 0
diff --git a/kernel/console.rv b/kernel/console.rv
index 3bff6de..9447860 100644
--- a/kernel/console.rv
+++ b/kernel/console.rv
@@ -1,11 +1,54 @@
const FONT_WIDTH = 8 # glyph width in pixels
const FONT_HEIGHT = 16 # glyph height in pixels (8x16 vga bitmap font)
-const FG_COLOR = 0xd0d0d0
-const BG_COLOR = 0x101018
-const CURSOR_COLOR = 0x50fa7b
+
+# base16 from lung
+const BASE00 = 0x101010 # background
+const BASE03 = 0x505050 # bright black
+const BASE05 = 0xd0d0d0 # default foreground
+const BASE07 = 0xfafafa # bright white
+const BASE08 = 0xab4642 # red
+const BASE09 = 0xdc9656 # orange
+const BASE0A = 0xf7ca88 # yellow
+const BASE0B = 0xa1b56c # green
+const BASE0C = 0x86c1b9 # cyan
+const BASE0D = 0x7cafc2 # blue
+const BASE0E = 0xba8baf # magenta
+const FG_COLOR = BASE05
+const BG_COLOR = BASE00
+const CURSOR_COLOR = BASE0B
global wd = { path = "/" }
-global prompt = fn() "revel:#{wd.path}$ "
+global shell_status = { code = 0 }
+
+global prompt = fn() do
+ let mid = ""
+ unless (shell_status.code == 0) do mid = "\x1b[31m#{shell_status.code} " end
+ return "\x1b[33m#{wd.path} #{mid}\x1b[97m$\x1b[0m "
+end
+
+fn parse_int(text) do
+ let value = 0
+ for index in 0..text:len() do
+ const digit = text[index]:ascii()
+ if (digit >= 48 and digit <= 57) do value = value * 10 + (digit - 48) end
+ end
+ return value
+end
+
+fn sgr_color(code, current) do
+ if (code == 0 or code == 39) return BASE05
+ if code == 30 return BASE00
+ if code == 90 return BASE03
+ if (code == 31 or code == 91) return BASE08
+ if (code == 32 or code == 92) return BASE0B
+ if (code == 33 or code == 93) return BASE0A
+ if (code == 34 or code == 94) return BASE0D
+ if (code == 35 or code == 95) return BASE0E
+ if (code == 36 or code == 96) return BASE0C
+ if code == 37 return BASE05
+ if code == 97 return BASE07
+ return current
+end
# runtime font bs
fn embolden(byte, row) do return (byte bor (byte shl 1)) band 0xFF end
@@ -58,7 +101,23 @@ add_font("italic", remap_glyphs(slant), FONT_WIDTH, FONT_HEIGHT, :bitmap, :nil,
add_font("bolditalic", remap_glyphs(fn(byte, row) do return slant(embolden(byte, row), row) end), FONT_WIDTH, FONT_HEIGHT, :bitmap, :nil, 0)
global console = {
- column = 0, row = 0, scale = 1, shown = :false, cursor_x = 0, cursor_y = 0, blink = 0, font = FONT, font_width = FONT_WIDTH, font_height = FONT_HEIGHT, font_entry = find_font("vga"),
+ column = 0,
+ row = 0,
+ scale = 1,
+
+ shown = :false,
+ cursor_x = 0,
+ cursor_y = 0,
+ blink = 0,
+
+ font = FONT,
+ font_width = FONT_WIDTH,
+ font_height = FONT_HEIGHT,
+ font_entry = find_font("vga"),
+
+ fg = FG_COLOR,
+ ansi = 0,
+ ansi_param = "",
# this is now font dependent
cell_width = fn(self) self.font_width * self.scale,
@@ -87,7 +146,7 @@ global console = {
for glyph_row in 0..self.font_height do
const bits = glyph[glyph_row]
for glyph_col in 0..self.font_width do
- if (bits shr glyph_col) band 1 == 1 fill_rect(origin_x + glyph_col * self.scale, origin_y + glyph_row * self.scale, self.scale, self.scale, FG_COLOR)
+ if (bits shr glyph_col) band 1 == 1 fill_rect(origin_x + glyph_col * self.scale, origin_y + glyph_row * self.scale, self.scale, self.scale, self.fg)
end
end
end,
@@ -103,8 +162,26 @@ global console = {
# we dont do shift/cntrl, thats a job for future me lmao
# NOTE: future me kinda delt with it, i was mad drunk
+ apply_sgr = fn(self, param) do
+ if param:len() == 0 do self.fg = BASE05 return :nil end
+ const parts = param:split(";")
+ for index in 0..parts:len() do self.fg = sgr_color(parse_int(parts[index]), self.fg) end
+ end,
+
putc = fn(self, character) do
const code = character:ascii()
+ if self.ansi == 1 do
+ if code == 91 do self.ansi = 2 self.ansi_param = "" end
+ else do self.ansi = 0 end
+ return :nil
+ end
+ if self.ansi == 2 do
+ if (code >= 48 and code <= 57) or code == 59 do self.ansi_param = self.ansi_param ~ character return :nil end
+ if code == 109 do self:apply_sgr(self.ansi_param) end
+ self.ansi = 0
+ return :nil
+ end
+ if code == 27 do self.ansi = 1 return :nil end # ESC, start a sequence
if code == 10 do self:newline() return :nil end # \n
if code == 13 do self.column = 0 return :nil end # \r
if code == 8 do # backspace: move left
@@ -146,6 +223,11 @@ global console = {
global puts = fn(text) serial_puts(text)
+global fail = fn(message) do
+ puts(message)
+ shell_status.code = 1
+end
+
global flush_console = fn() do
console:cursor_clear()
console:drain()
diff --git a/kernel/fs.rv b/kernel/fs.rv
index b23be7f..f732573 100644
--- a/kernel/fs.rv
+++ b/kernel/fs.rv
@@ -364,24 +364,24 @@ global fs = {
const parent = self:resolve_parent(path)
if parent == :nil do
- puts("mkdir: #{path}: bad path\n")
+ fail("mkdir: #{path}: bad path\n")
return :nil
end
if parent.name:len() > NAME_MAX do
- puts("name too long (max #{NAME_MAX})\n")
+ fail("name too long (max #{NAME_MAX})\n")
return :nil
end
if self:dir_lookup(parent.dir, parent.name) != :nil do
- puts("mkdir: #{parent.name}: already exists\n")
+ fail("mkdir: #{parent.name}: already exists\n")
return :nil
end
const new_block = self:fat_alloc()
if new_block == 0 do
- puts("disk full\n")
+ fail("disk full\n")
return :nil
end
@@ -412,7 +412,7 @@ global fs = {
if existing != :nil do
if existing.type == T_DIR do
- puts("#{parent.name}: is a directory\n")
+ fail("#{parent.name}: is a directory\n")
return 0
end
@@ -428,7 +428,7 @@ global fs = {
const block = self:fat_alloc()
if block == 0 do
- puts("disk full\n")
+ fail("disk full\n")
return 0
end
@@ -534,6 +534,30 @@ global fs = {
return entry.size
end,
+ # TODO: ts needs a rewrite its not cheap and rewrites every file from scratch
+ fn write_at(self, path, offset, bytes) -> num do
+ const size = self:size(path)
+ let base = ""
+
+ if size > 0 do base = self:read_bytes(path, 0, size) end
+
+ let prefix = ""
+
+ if offset <= base:len() do
+ prefix = base[0..offset]
+ end else do
+ prefix = base
+ while (prefix:len() < offset) do prefix = prefix ~ string.of_ascii(0) end
+ end
+
+ const after = offset + bytes:len()
+ let tail = ""
+
+ if after < base:len() do tail = base[after..] end
+
+ return self:store(path, prefix ~ bytes ~ tail)
+ end,
+
fn cat(self, path) do
if self:ensure() == :false do
return :nil
@@ -542,12 +566,12 @@ global fs = {
const entry = self:resolve(path)
if entry == :nil do
- puts("cat: #{path}: no such file\n")
+ fail("cat: #{path}: no such file\n")
return :nil
end
if entry.type == T_DIR do
- puts("cat: #{path}: is a directory\n")
+ fail("cat: #{path}: is a directory\n")
return :nil
end
@@ -582,7 +606,7 @@ global fs = {
const entry = self:resolve(path)
if entry == :nil do
- puts("ls: #{path}: no such file\n")
+ fail("ls: #{path}: no such file\n")
return -1
end
@@ -630,19 +654,19 @@ global fs = {
const parent = self:resolve_parent(path)
if parent == :nil do
- puts("rm: #{path}: no such file\n")
+ fail("rm: #{path}: no such file\n")
return :nil
end
const entry = self:dir_lookup(parent.dir, parent.name)
if entry == :nil do
- puts("rm: #{path}: no such file\n")
+ fail("rm: #{path}: no such file\n")
return :nil
end
if entry.type == T_DIR and self:dir_empty(entry.first) == :false do
- puts("rm: #{parent.name}: directory not empty\n")
+ fail("rm: #{parent.name}: directory not empty\n")
return :nil
end
@@ -718,3 +742,4 @@ global fs = {
global fs_store = fn(name, text) fs:store(name, text)
global fs_size = fn(name) fs:size(name)
global fs_read_bytes = fn(name, offset, length) fs:read_bytes(name, offset, length)
+global fs_write_at = fn(name, offset, bytes) fs:write_at(name, offset, bytes)
diff --git a/kernel/io.rv b/kernel/io.rv
new file mode 100644
index 0000000..68b7039
--- /dev/null
+++ b/kernel/io.rv
@@ -0,0 +1,37 @@
+# stdio stuff
+
+global io = {
+ open = fn(self, path, mode) do
+ if mode == "w" do fs:store(path, "") end
+ let offset = 0
+ if mode == "a" do
+ const size = fs:size(path)
+ if size > 0 do offset = size end
+ end
+ return { path = path, offset = offset }
+ end,
+
+ read = fn(self, handle, count) do
+ const data = fs:read_bytes(handle.path, handle.offset, count)
+ handle.offset += data:len()
+ return data
+ end,
+
+ read_all = fn(self, handle) do
+ const size = fs:size(handle.path)
+ if size <= handle.offset return ""
+ const data = fs:read_bytes(handle.path, handle.offset, size - handle.offset)
+ handle.offset += data:len()
+ return data
+ end,
+
+ write = fn(self, handle, data) do
+ fs:write_at(handle.path, handle.offset, data)
+ handle.offset += data:len()
+ return data:len()
+ end,
+
+ seek = fn(self, handle, offset) do handle.offset = offset end,
+ tell = fn(self, handle) handle.offset,
+ close = fn(self, handle) :nil,
+}
diff --git a/kernel/main.rv b/kernel/main.rv
index 67850d5..3547665 100644
--- a/kernel/main.rv
+++ b/kernel/main.rv
@@ -20,9 +20,9 @@ if fs:size("/etc/profile") >= 0 do
end
# lung will be happy
-const default_face = load_ttf("/fonts/terminess.ttf", 32)
+const default_face = load_ttf("/usr/share/terminess.ttf", 32)
if default_face != :nil do
- add_font("terminess", default_face.glyphs, default_face.width, default_face.height, :ttf, "/fonts/terminess.ttf", 32)
+ add_font("terminess", default_face.glyphs, default_face.width, default_face.height, :ttf, "/usr/share/terminess.ttf", 32)
console:set_font(find_font("terminess"))
end
diff --git a/kernel/proc.rv b/kernel/proc.rv
index 5019fa8..92d48f1 100644
--- a/kernel/proc.rv
+++ b/kernel/proc.rv
@@ -67,8 +67,8 @@ end
fn run_prog(name, arg) do
let bare_name = name
- if bare_name:starts_with?("/bin/") bare_name = bare_name[5..]
- const path = "/bin/#{bare_name}"
+ if bare_name:starts_with?("/usr/bin/") bare_name = bare_name[9..]
+ const path = "/usr/bin/#{bare_name}"
if fs:size(path) < 0 return :false
return load_file_elf(path, arg)
end
diff --git a/kernel/seed.rv b/kernel/seed.rv
index cbb96e0..9dc2dc5 100644
--- a/kernel/seed.rv
+++ b/kernel/seed.rv
@@ -2,8 +2,9 @@
fn seed_bin() do
fs:mkdir("/bin")
+ fs:mkdir("/usr/bin")
for index in 0..prog_count() do
- fs:store("/bin/#{prog_name(index)}", phys_to_str(prog_phys(index), prog_size(index)))
+ fs:store("/usr/bin/#{prog_name(index)}", phys_to_str(prog_phys(index), prog_size(index)))
end
for index in 0..script_count() do
fs:store("/bin/#{script_name(index)}.rv", script_src(index))
@@ -11,9 +12,9 @@ fn seed_bin() do
end
fn seed_fonts() do
- fs:mkdir("/fonts")
+ fs:mkdir("/usr/share")
for index in 0..font_count() do
- fs:store("/fonts/#{font_name(index)}", phys_to_str(font_phys(index), font_size(index)))
+ fs:store("/usr/share/#{font_name(index)}", phys_to_str(font_phys(index), font_size(index)))
end
end
@@ -26,7 +27,8 @@ fn seed_fs() do
fs:store("/etc/profile", """
# /etc/profile runs once at shell startup, keep it quick
- if fs:size("/etc/motd") > 0 do
+ const motd_size = fs:size("/etc/motd")
+ if motd_size > 0 do
puts(fs:read_bytes("/etc/motd", 0, motd_size))
puts("\n")
end
diff --git a/kernel/shell.rv b/kernel/shell.rv
index 4940b34..99ead73 100644
--- a/kernel/shell.rv
+++ b/kernel/shell.rv
@@ -32,46 +32,27 @@ end
fn cmd_help(context) do
help_group("shell", "shell")
help_group("gils (builtin)", "gils")
-
- # the rest of gils, and the programs, are real files in /bin now
- const items = fs:entries("/bin")
-
- if items != :nil do
+ # gils scripts are real files in /bin, native programs in /usr/bin
+ const scripts = fs:entries("/bin")
+ if scripts != :nil do
puts("\n gils (/bin scripts)\n")
-
- for index in 0..items:len() do
- const name = items[index].name
-
- if name:len() > 3 and name[(name:len() - 3)..] == ".rv" do
- help_row(name[0..(name:len() - 3)], "")
- end
- end
-
- puts("\n programs (/bin)\n")
-
- for index in 0..items:len() do
- const name = items[index].name
-
- if name:len() <= 3 or name[(name:len() - 3)..] != ".rv" do
- help_row(name, "")
- end
+ for index in 0..scripts:len() do
+ const name = scripts[index].name
+ if (name:len() > 3 and name[(name:len() - 3)..] == ".rv") do help_row(name[0..(name:len() - 3)], "") end
end
end
-
- puts("\n fonts (font <name>)\n")
-
- for index in 0..fonts:len() do
- help_row(fonts[index].name, "8x#{fonts[index].height}")
+ const progs = fs:entries("/usr/bin")
+ if progs != :nil do
+ puts("\n programs (/usr/bin)\n")
+ for index in 0..progs:len() do help_row(progs[index].name, "") end
end
- const font_files = fs:entries("/fonts")
-
+ puts("\n fonts (font <name>)\n")
+ for index in 0..fonts:len() do help_row(fonts[index].name, "8x#{fonts[index].height}") end
+ const font_files = fs:entries("/usr/share")
if font_files != :nil do
- puts("\n fonts on disk (font load /fonts/x.psf)\n")
-
- for index in 0..font_files:len() do
- help_row(font_files[index].name, "")
- end
+ puts("\n fonts on disk (font load /usr/share/x.psf)\n")
+ for index in 0..font_files:len() do help_row(font_files[index].name, "") end
end
puts("\n")
@@ -152,7 +133,7 @@ fn cmd_cd(context) do
or fs:is_dir(target) do
wd.path = target
end else do
- puts("cd: #{arg}: not a directory\n")
+ fail("cd: #{arg}: not a directory\n")
end
end
@@ -334,8 +315,8 @@ fn font_file(name) -> { path: string, kind: ( :ttf | :psf | :none ) } do
return { path = p, kind = :none }
end
- | fs:size("/fonts/#{name}.psf") >= 0 => { path = "/fonts/#{name}.psf", kind = :psf }
- | fs:size("/fonts/#{name}.ttf") >= 0 => { path = "/fonts/#{name}.ttf", kind = :ttf }
+ | fs:size("/usr/share/#{name}.psf") >= 0 => { path = "/usr/share/#{name}.psf", kind = :psf }
+ | fs:size("/usr/share/#{name}.ttf") >= 0 => { path = "/usr/share/#{name}.ttf", kind = :ttf }
| _ => { path = name, kind = :none }
end
@@ -348,9 +329,7 @@ fn cmd_font(context) do
end
puts("\n")
-
- const font_files = fs:entries("/fonts")
-
+ const font_files = fs:entries("/usr/share")
if font_files != :nil do
puts("on disk:")
@@ -519,17 +498,13 @@ fn exec_file(target) -> { path: string, kind: ( :elf | :script | :none ) } do
let candidates = {}
if has_slash(target) do
- candidates:push(
- expand_path(target),
- expand_path(target) ~ ".rv",
- )
+ candidates:push(expand_path(target))
+ candidates:push(expand_path(target) ~ ".rv")
end else do
- candidates:push(
- expand_path(target),
- expand_path(target) ~ ".rv",
- "/bin/#{target}",
- "/bin/#{target}.rv",
- )
+ candidates:push(expand_path(target))
+ candidates:push(expand_path(target) ~ ".rv")
+ candidates:push("/usr/bin/#{target}")
+ candidates:push("/bin/#{target}.rv")
end
for index in 0..candidates:len() do
@@ -563,7 +538,7 @@ fn cmd_run(context) do
const info = exec_file(target)
if info.kind == :none do
- puts("run: #{target}: not found\n")
+ fail("run: #{target}: not found\n")
return :nil
end
@@ -580,7 +555,7 @@ fn cmd_run(context) do
return :hold
end
- puts("run: #{target}: not executable\n")
+ fail("run: #{target}: not executable\n")
return :nil
end
@@ -601,6 +576,7 @@ fn run(line) -> :nil do
const argv = line:split(" ")
const context = make_ctx(line, argv)
+ shell_status.code = 0
const command = lookup(argv[0])
if command != :nil do
@@ -624,6 +600,7 @@ fn run(line) -> :nil do
return :nil
end
+ shell_status.code = 127
puts("#{argv[0]}: command not found\n")
puts(prompt())
end
diff --git a/user/chat.c b/user/chat.c
new file mode 100644
index 0000000..67bc727
--- /dev/null
+++ b/user/chat.c
@@ -0,0 +1,33 @@
+#include "user.h"
+
+void _start(const char* arg, unsigned long arglen)
+{
+ if (arglen == 0)
+ {
+ put("usage: run chat <path>\n");
+ sys_exit(1);
+ }
+
+ char path[128];
+ unsigned long i = 0;
+ for (; i < arglen && i < sizeof(path) - 1; i++)
+ path[i] = arg[i];
+ path[i] = 0;
+
+ long fd = sys_open(path, 0);
+ if (fd < 0)
+ {
+ put("chat: ");
+ put(path);
+ put(": cannot open\n");
+ sys_exit(1);
+ }
+
+ char buffer[256];
+ long n;
+ while ((n = sys_read(fd, buffer, sizeof(buffer))) > 0)
+ sys_write(1, buffer, (unsigned long)n);
+
+ sys_close(fd);
+ sys_exit(0);
+}
diff --git a/user/hexview.c b/user/hexview.c
index c211b44..5eac27c 100644
--- a/user/hexview.c
+++ b/user/hexview.c
@@ -5,7 +5,7 @@ static const char HEX[] = "0123456789abcdef";
static void put_hex8(unsigned char byte)
{
char digits[2] = { HEX[byte >> 4], HEX[byte & 15] };
- sys_write(digits, 2);
+ sys_write(1, digits, 2);
}
static void put_hex32(unsigned long value)
@@ -13,7 +13,7 @@ static void put_hex32(unsigned long value)
char digits[8];
for (int nibble = 0; nibble < 8; nibble++)
digits[nibble] = HEX[(value >> ((7 - nibble) * 4)) & 15];
- sys_write(digits, 8);
+ sys_write(1, digits, 8);
}
#define PAGE 256
@@ -67,7 +67,7 @@ void _start(const char* arg, unsigned long arglen)
if (row + column < count)
{
put_hex8((unsigned char)buffer[row + column]);
- sys_write(" ", 1);
+ sys_write(1, " ", 1);
}
else
put(" ");
@@ -78,19 +78,19 @@ void _start(const char* arg, unsigned long arglen)
{
char character = buffer[row + column];
if (character >= 32 && character < 127)
- sys_write(&character, 1);
+ sys_write(1, &character, 1);
else
- sys_write(".", 1);
+ sys_write(1, ".", 1);
}
put("\n");
}
put("[n]ext [p]rev [q]uit (or up/down arrows) > ");
- char key = (char)sys_read();
+ char key = (char)get_char();
if (key == 27) // ESC
{
- sys_read();
- char final = (char)sys_read();
+ get_char();
+ char final = (char)get_char();
if (final == 'A')
key = 'p';
else if (final == 'B')
diff --git a/user/save.c b/user/save.c
index b3664f4..48e1930 100644
--- a/user/save.c
+++ b/user/save.c
@@ -2,23 +2,30 @@
void _start(const char* arg, unsigned long arglen)
{
- if (arglen == 0 || arglen >= 64)
+ if (arglen == 0 || arglen >= 120)
{
put("usage: run save <path>\n");
sys_exit(1);
}
- char name[64];
+ char name[128];
for (unsigned long i = 0; i < arglen; i++)
name[i] = arg[i];
name[arglen] = 0;
+ long fd = sys_open(name, O_CREAT | O_TRUNC | O_WRONLY);
+ if (fd < 0)
+ {
+ put("save: ");
+ put(name);
+ put(": cannot open\n");
+ sys_exit(1);
+ }
+
put("saving to ");
put(name);
put(" -- type lines, a single . saves\n");
- char buffer[4096];
- int length = 0;
for (;;)
{
char line[256];
@@ -26,20 +33,13 @@ void _start(const char* arg, unsigned long arglen)
put("\n");
if (n == 1 && line[0] == '.')
break;
- for (int i = 0; i < n && length < 4000; i++)
- buffer[length++] = line[i];
- if (length < 4000)
- buffer[length++] = '\n';
+ sys_write(fd, line, (unsigned long)n);
+ sys_write(fd, "\n", 1);
}
- if (sys_fs_write(name, buffer, (unsigned long)length))
- {
- put("saved ");
- put(name);
- put("\n");
- }
- else
- put("write failed\n");
-
+ sys_close(fd);
+ put("saved ");
+ put(name);
+ put("\n");
sys_exit(0);
}
diff --git a/user/user.h b/user/user.h
index 635dc86..34710ac 100644
--- a/user/user.h
+++ b/user/user.h
@@ -1,16 +1,44 @@
-// shared syscall stubs
+#define SEEK_SET 0
+#define SEEK_CUR 1
+#define SEEK_END 2
-static long sys_write(const char* buffer, unsigned long length)
+#define O_WRONLY 1
+#define O_CREAT 0x40
+#define O_TRUNC 0x200
+#define O_APPEND 0x400
+
+static long sys_write(long fd, const char* buffer, unsigned long length)
+{
+ long result;
+ __asm__ volatile("int $0x80" : "=a"(result) : "a"(1L), "D"(fd), "S"(buffer), "d"(length) : "memory");
+ return result;
+}
+
+static long sys_read(long fd, char* buffer, unsigned long length)
+{
+ long result;
+ __asm__ volatile("int $0x80" : "=a"(result) : "a"(2L), "D"(fd), "S"(buffer), "d"(length) : "memory");
+ return result;
+}
+
+static long sys_open(const char* path, long flags)
+{
+ long result;
+ __asm__ volatile("int $0x80" : "=a"(result) : "a"(7L), "D"(path), "S"(flags) : "memory");
+ return result;
+}
+
+static long sys_close(long fd)
{
long result;
- __asm__ volatile("int $0x80" : "=a"(result) : "a"(1L), "D"(buffer), "S"(length) : "memory");
+ __asm__ volatile("int $0x80" : "=a"(result) : "a"(8L), "D"(fd) : "memory");
return result;
}
-static long sys_read(void)
+static long sys_lseek(long fd, long offset, long whence)
{
long result;
- __asm__ volatile("int $0x80" : "=a"(result) : "a"(2L) : "memory");
+ __asm__ volatile("int $0x80" : "=a"(result) : "a"(9L), "D"(fd), "S"(offset), "d"(whence) : "memory");
return result;
}
@@ -52,7 +80,15 @@ static void put(const char* string)
unsigned long length = 0;
while (string[length])
length++;
- sys_write(string, length);
+ sys_write(1, string, length);
+}
+
+static int get_char(void)
+{
+ char c;
+ if (sys_read(0, &c, 1) <= 0)
+ return -1;
+ return (unsigned char)c;
}
static int read_line(char* buffer, int max_length)
@@ -60,7 +96,9 @@ static int read_line(char* buffer, int max_length)
int length = 0;
for (;;)
{
- char character = (char)sys_read();
+ char character;
+ if (sys_read(0, &character, 1) <= 0)
+ break;
if (character == '\n')
break;
if (character == '\b')
@@ -68,14 +106,14 @@ static int read_line(char* buffer, int max_length)
if (length > 0)
{
length--;
- sys_write("\b \b", 3);
+ sys_write(1, "\b \b", 3);
}
continue;
}
if (length < max_length - 1)
{
buffer[length++] = character;
- sys_write(&character, 1);
+ sys_write(1, &character, 1);
}
}
buffer[length] = 0;
@@ -108,5 +146,5 @@ static void put_int(long value)
buffer[right] = swap;
}
- sys_write(buffer, length);
+ sys_write(1, buffer, length);
}