hachem.wtf
aboutsummaryrefslogtreecommitdiff
path: root/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'kernel')
-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
7 files changed, 201 insertions, 78 deletions
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