diff options
| author | hachem <im@hachem.wtf> | 2026-10-09 11:08:09 +0200 |
|---|---|---|
| committer | hachem <im@hachem.wtf> | 2026-10-09 11:08:09 +0200 |
| commit | e0572c37d970d601c17085bdb082cc6ef4356891 (patch) | |
| tree | f0b4d71c92978e74d127d7090d3e11380378a8b3 | |
| parent | 8cb66100fe802c38d180ea29a11a902decf0fd8b (diff) | |
chore: fmt some revo code based on lung's example
| -rw-r--r-- | gils/cp.rv | 17 | ||||
| -rw-r--r-- | gils/gils.rv | 35 | ||||
| -rw-r--r-- | gils/head.rv | 33 | ||||
| -rw-r--r-- | gils/ls.rv | 15 | ||||
| -rw-r--r-- | gils/mkdir.rv | 8 | ||||
| -rw-r--r-- | gils/mv.rv | 18 | ||||
| -rw-r--r-- | gils/rm.rv | 8 | ||||
| -rw-r--r-- | gils/tail.rv | 32 | ||||
| -rw-r--r-- | gils/touch.rv | 12 | ||||
| -rw-r--r-- | gils/tree.rv | 30 | ||||
| -rw-r--r-- | gils/wc.rv | 26 | ||||
| -rw-r--r-- | kernel/console.rv | 176 | ||||
| -rw-r--r-- | kernel/fs.rv | 4 | ||||
| -rw-r--r-- | kernel/input.rv | 86 | ||||
| -rw-r--r-- | kernel/io.rv | 27 | ||||
| -rw-r--r-- | kernel/main.rv | 2 | ||||
| -rw-r--r-- | kernel/proc.rv | 55 | ||||
| -rw-r--r-- | kernel/shell.rv | 6 | ||||
| -rw-r--r-- | kernel/ttf.rv | 459 | ||||
| -rw-r--r-- | kernel/tty.rv | 167 | ||||
| -rw-r--r-- | kernel/vfs.rv | 35 | ||||
| -rw-r--r-- | kernel/vmm.rv | 14 |
22 files changed, 847 insertions, 418 deletions
@@ -2,14 +2,19 @@ # HAAAAAANNNNKKKK const context = env.ctx -if context.argv:len() < 3 do fail("usage: cp <source> <destination>\n") end -else do + +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 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 + + 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) + puts("#{source} -> #{destination}\n") end end diff --git a/gils/gils.rv b/gils/gils.rv index a500322..2432890 100644 --- a/gils/gils.rv +++ b/gils/gils.rv @@ -6,41 +6,54 @@ fn register(usage, group, help, handler) do commands:push({ name = name, usage = usage, group = group, help = help, handler = handler }) end -fn lookup(name) do +fn lookup(name) -> table | :nil do for index in 0..commands:len() do - if commands[index].name == name return commands[index] + if (commands[index].name == name) + return commands[index] end return :nil end -fn make_ctx(line, argv) do +fn make_ctx(line, argv) -> { line: string, argv: table, rest: string } do const name = argv[0] let rest = "" + const cut = name:len() + 1 - if line:len() > cut do rest = line[cut..] end + if (line:len() > cut) + rest = line[cut..] + return { line = line, argv = argv, rest = rest } end # scripts read their args off env.ctx, stashed here before eval global env = { ctx = :nil } -# first use of unless in history -global expand_path = fn(path) do - if path:len() == 0 return wd.path +# first use of unless in revo history +global expand_path = fn(path) -> string do + if (path:len() == 0) + return wd.path + unless (path[0] == "/") do const slash = unless (wd.path == "/") "/" else "" path = "#{wd.path}#{slash}#{path}" end + return path end -fn run_script_path(path, label, ctx) do +fn run_script_path(path, label, ctx) -> bool do const size = fs:size(path) - if size < 0 return :false + if (size < 0) + return :false + env.ctx = ctx const error_msg = eval_script(fs:read_bytes(path, 0, size)) - if error_msg != :nil do fail("#{label}: #{error_msg}\n") end + if (error_msg != :nil) + fail("#{label}: #{error_msg}\n") + return :true end -fn run_script(name, ctx) run_script_path("/bin/#{name}.rv", name, ctx) +fn run_script(name, ctx) -> bool do + return run_script_path("/bin/#{name}.rv", name, ctx) +end diff --git a/gils/head.rv b/gils/head.rv index 2c2a82f..eb50087 100644 --- a/gils/head.rv +++ b/gils/head.rv @@ -1,27 +1,40 @@ # gimme some head lung -fn file_lines(path) do +fn file_lines(path) -> table | :nil do const size = fs:size(path) - if size < 0 return :nil - const contents = if size > 0 fs:read_bytes(path, 0, size) else "" + if (size < 0) + return :nil + + const contents = if (size > 0) fs:read_bytes(path, 0, size) else "" const raw_lines = contents:split("\n") let result = {} for index in 0..raw_lines:len() do - if (index < raw_lines:len() - 1 or raw_lines[index]:len() > 0) result:push(raw_lines[index]) + if (index < raw_lines:len() - 1 or raw_lines[index]:len() > 0) + result:push(raw_lines[index]) end return result end const context = env.ctx -if context.argv:len() < 2 do fail("usage: head [n] <path>\n") end -else do + +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 + 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 fail("head: no such file\n") end - else do + 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 + while (index < lines:len() and index < limit) do + puts("#{lines[index]}\n") + index += 1 + end end end @@ -1,10 +1,15 @@ # list a directory const context = env.ctx -const target = if context.argv:len() > 1 expand_path(context.argv[1]) else wd.path -if vfs_owns(target) do vfs_ls(target) end -else do +const target = if (context.argv:len() > 1) expand_path(context.argv[1]) else wd.path + +if vfs_owns(target) do + vfs_ls(target) +end else do const count = fs:ls(target) - if target == "/" do puts(" proc/\n") end - else if count == 0 do puts(" (empty)\n") end + if target == "/" do + puts(" proc/\n") + end else if count == 0 do + puts(" (empty)\n") + end end diff --git a/gils/mkdir.rv b/gils/mkdir.rv index c7d12f7..9da7689 100644 --- a/gils/mkdir.rv +++ b/gils/mkdir.rv @@ -1,5 +1,9 @@ # make a directory const context = env.ctx -if context.argv:len() < 2 do fail("usage: mkdir <path>\n") end -else do fs:mkdir(expand_path(context.argv[1])) end + +if context.argv:len() < 2 do + fail("usage: mkdir <path>\n") +end else do + fs:mkdir(expand_path(context.argv[1])) +end @@ -1,14 +1,20 @@ # move or rename a file const context = env.ctx -if context.argv:len() < 3 do fail("usage: mv <source> <destination>\n") end -else do +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 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 + + 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 end end @@ -2,5 +2,9 @@ const context = env.ctx const parsed = arg_name(context.rest, 0) -if parsed.name:len() == 0 do fail("usage: rm <path>\n") end -else do fs:rm(expand_path(parsed.name)) 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 c1ca124..c0ce1df 100644 --- a/gils/tail.rv +++ b/gils/tail.rv @@ -1,29 +1,41 @@ # my tail is 16 inches long # and its between my legs -fn file_lines(path) do +fn file_lines(path) -> table | :nil do const size = fs:size(path) - if size < 0 return :nil - const contents = if size > 0 fs:read_bytes(path, 0, size) else "" + if (size < 0) + return :nil + + const contents = if (size > 0) fs:read_bytes(path, 0, size) else "" const raw_lines = contents:split("\n") let result = {} + for index in 0..raw_lines:len() do - if (index < raw_lines:len() - 1 or raw_lines[index]:len() > 0) result:push(raw_lines[index]) + if (index < raw_lines:len() - 1 or raw_lines[index]:len() > 0) + result:push(raw_lines[index]) end return result end const context = env.ctx -if context.argv:len() < 2 do fail("usage: tail [n] <path>\n") end -else do +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 + 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 fail("tail: no such file\n") end - else do + 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 + if (start < 0) + start = 0 + for index in start..lines:len() do puts("#{lines[index]}\n") end end end diff --git a/gils/touch.rv b/gils/touch.rv index f8e3e18..3032e96 100644 --- a/gils/touch.rv +++ b/gils/touch.rv @@ -1,9 +1,13 @@ # dont touch my nono square const context = env.ctx -if context.argv:len() < 2 do fail("usage: touch <path>\n") end -else do +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 fail("touch: #{path}: is a directory\n") end - else if fs:size(path) < 0 do fs:store(path, "") 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 d1a6af6..d146403 100644 --- a/gils/tree.rv +++ b/gils/tree.rv @@ -1,29 +1,39 @@ -# recursive directory listing. +# recursive directory listing fn tree_walk(path, prefix) do const items = fs:entries(path) - if items == :nil return :nil + if (items == :nil) + return :nil + for index in 0..items:len() do const entry = items[index] const last = index == items:len() - 1 let branch = "|-- " - if last do branch = "`-- " end # font doesnt support fancy ascii symbols - const slash = if entry.type == 2 "/" else "" + # font doesnt support fancy ascii symbols + if (last) + branch = "`-- " + + const slash = if (entry.type == 2) "/" else "" puts("#{prefix}#{branch}#{entry.name}#{slash}\n") + if entry.type == 2 do - const child = if path == "/" "/#{entry.name}" else "#{path}/#{entry.name}" + const child = if (path == "/") "/#{entry.name}" else "#{path}/#{entry.name}" let indent = "| " - if last do indent = " " end + if (last) + indent = " " tree_walk(child, prefix ~ indent) end end 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 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 +const target = if (context.argv:len() > 1) expand_path(context.argv[1]) else wd.path + +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, "") # /proc is the one thing not on disk so tack it on at root @@ -1,22 +1,32 @@ # word count const context = env.ctx -if context.argv:len() < 2 do fail("usage: wc <path>\n") end -else do +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 fail("wc: #{path}: no such file\n") end - else do - const contents = if size > 0 fs:read_bytes(path, 0, size) else "" + + 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 let word_count = 0 let in_word = :false + for index in 0..contents:len() do const character = contents[index] - if character == "\n" do line_count += 1 end - if (character == " " or character == "\n" or character == "\t") do in_word = :false end - else if in_word == :false do word_count += 1 in_word = :true end + if (character == "\n") + line_count += 1 + if character == " " or character == "\n" or character == "\t" do + in_word = :false + end else if in_word == :false do + word_count += 1 + in_word = :true + end end + puts(" #{line_count} #{word_count} #{size} #{context.argv[1]}\n") end end diff --git a/kernel/console.rv b/kernel/console.rv index 9447860..ba322f9 100644 --- a/kernel/console.rv +++ b/kernel/console.rv @@ -20,41 +20,50 @@ const CURSOR_COLOR = BASE0B global 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 " +global prompt = fn() -> string do + let middle = "" + unless (shell_status.code == 0) do + middle = "\x1b[31m#{shell_status.code} " + end + return "\x1b[33m#{wd.path} #{middle}\x1b[97m$\x1b[0m " end -fn parse_int(text) do +fn parse_int(text) -> num 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 + if (digit >= 48 and digit <= 57) + value = value * 10 + (digit - 48) 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 +fn sgr_color(code, current) -> num do + return match code + | 0, 39 => BASE05 + | 30 => BASE00 + | 90 => BASE03 + | 31, 91 => BASE08 + | 32, 92 => BASE0B + | 33, 93 => BASE0A + | 34, 94 => BASE0D + | 35, 95 => BASE0E + | 36, 96 => BASE0C + | 37 => BASE05 + | 97 => BASE07 + | _ => current end # runtime font bs -fn embolden(byte, row) do return (byte bor (byte shl 1)) band 0xFF end -fn slant(byte, row) do return (byte shl ((FONT_HEIGHT - 1 - row) shr 2)) band 0xFF end +fn embolden(byte, row) -> num do + return (byte bor (byte shl 1)) band 0xFF +end -fn remap_glyphs(transform) do +fn slant(byte, row) -> num do + return (byte shl ((FONT_HEIGHT - 1 - row) shr 2)) band 0xFF +end + +fn remap_glyphs(transform) -> table do let out = {} for glyph_index in 0..FONT:len() do const glyph = FONT[glyph_index] @@ -65,15 +74,18 @@ fn remap_glyphs(transform) do return out end -global reverse8 = fn(byte) do +global reverse8 = fn(byte) -> num do let out = 0 for bit in 0..8 do - if (byte shr bit) band 1 == 1 do out = out bor (1 shl (7 - bit)) end + if (byte shr bit) band 1 == 1 do + out = out bor (1 shl (7 - bit)) + end end return out end global fonts = {} + global add_font = fn(name, glyphs, width, height, kind, path, size) do for index in 0..fonts:len() do if fonts[index].name == name do @@ -86,11 +98,14 @@ global add_font = fn(name, glyphs, width, height, kind, path, size) do return :nil end end + fonts:push({ name = name, glyphs = glyphs, width = width, height = height, kind = kind, path = path, size = size }) end -global find_font = fn(name) do + +global find_font = fn(name) -> table | :nil do for index in 0..fonts:len() do - if fonts[index].name == name return fonts[index] + if (fonts[index].name == name) + return fonts[index] end return :nil end @@ -120,40 +135,49 @@ global console = { ansi_param = "", # this is now font dependent - cell_width = fn(self) self.font_width * self.scale, - cell_height = fn(self) self.font_height * self.scale, - columns = fn(self) fb_width() / self:cell_width(), - rows = fn(self) fb_height() / self:cell_height(), + fn cell_width(self) self.font_width * self.scale, + fn cell_height(self) self.font_height * self.scale, + fn columns(self) fb_width() / self:cell_width(), + fn rows(self) fb_height() / self:cell_height(), - set_font = fn(self, entry) do + fn set_font(self, entry) do self.font = entry.glyphs self.font_width = entry.width self.font_height = entry.height self.font_entry = entry + # a ttf renders at its true pixel size so we js bitmap zoom scale - if entry.kind == :ttf do self.scale = 1 end + if (entry.kind == :ttf) + self.scale = 1 self:clear() end, - draw_glyph = fn(self, column, row, character) do + fn draw_glyph(self, column, row, character) do const origin_x = column * self:cell_width() const origin_y = row * self:cell_height() fill_rect(origin_x, origin_y, self:cell_width(), self:cell_height(), BG_COLOR) # clear the cell + const code = character:ascii() - if code < 32 return :nil - if code > 127 return :nil + if (code < 32) + return :nil + if (code > 127) + return :nil + const glyph = self.font[code - 32] 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, self.fg) + if (bits shr glyph_col) band 1 == 1 do + fill_rect(origin_x + glyph_col * self.scale, origin_y + glyph_row * self.scale, self.scale, self.scale, self.fg) + end end end end, - newline = fn(self) do + fn newline(self) do self.column = 0 self.row += 1 + if self.row >= self:rows() do fb_scroll(self:cell_height(), BG_COLOR) self.row = self:rows() - 1 @@ -162,52 +186,84 @@ 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 + fn apply_sgr(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 + fn putc(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 + 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 + if (code >= 48 and code <= 57) or code == 59 do + self.ansi_param = self.ansi_param ~ character + return :nil + end + + if (code == 109) + self:apply_sgr(self.ansi_param) self.ansi = 0 + + return :nil + end + + if code == 27 do # ESC + self.ansi = 1 + return :nil + end + # \n + if code == 10 do # \n + self:newline() 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 - if self.column > 0 self.column -= 1 + if code == 13 do # \r + self.column = 0 return :nil end - if code < 32 return :nil + if code == 8 do # backspace + if (self.column > 0) + self.column -= 1 + return :nil + end + if (code < 32) + return :nil + self:draw_glyph(self.column, self.row, character) self.column += 1 - if self.column >= self:columns() self:newline() + + if (self.column >= self:columns()) + self:newline() end, - clear = fn(self) do + fn clear(self) do fill_rect(0, 0, fb_width(), fb_height(), BG_COLOR) self.column = 0 self.row = 0 end, - cursor_clear = fn(self) do + fn cursor_clear(self) do if self.shown do fill_rect(self.cursor_x * self:cell_width(), self.cursor_y * self:cell_height(), self:cell_width(), self:cell_height(), BG_COLOR) self.shown = :false end end, - cursor_show = fn(self) do + fn cursor_show(self) do self.cursor_x = self.column self.cursor_y = self.row fill_rect(self.cursor_x * self:cell_width(), self.cursor_y * self:cell_height(), self:cell_width(), self:cell_height(), CURSOR_COLOR) @@ -215,9 +271,12 @@ global console = { end, # render every byte the serial mirror has buffered - drain = fn(self) do + fn drain(self) do let byte = serial_next() - while byte >= 0 do self:putc(string.of_ascii(byte)) byte = serial_next() end + while (byte >= 0) do + self:putc(string.of_ascii(byte)) + byte = serial_next() + end end, } @@ -237,6 +296,7 @@ end global on_tick = fn(ticks) do let byte = serial_next() + if byte >= 0 do console:cursor_clear() console:putc(string.of_ascii(byte)) @@ -245,6 +305,7 @@ global on_tick = fn(ticks) do console:cursor_show() return :nil end + if proc_exited() do console:cursor_clear() puts(prompt()) @@ -253,9 +314,10 @@ global on_tick = fn(ticks) do console:cursor_show() return :nil end + console.blink += 1 if console.blink >= 50 do console.blink = 0 - if console.shown console:cursor_clear() else console:cursor_show() + if (console.shown) console:cursor_clear() else console:cursor_show() end end diff --git a/kernel/fs.rv b/kernel/fs.rv index f732573..63442cd 100644 --- a/kernel/fs.rv +++ b/kernel/fs.rv @@ -511,7 +511,7 @@ global fs = { return result end, - fn read_into(self, path, dest) -> num do + fn read_into(self, path, destination) -> num do const entry = self:resolve(path) if entry == :nil or entry.type == T_DIR do @@ -525,7 +525,7 @@ global fs = { while (block != 0 and block != END and remaining > 0) do const next_block = self:fat_get(block) - disk_read(block, dest + offset) + disk_read(block, destination + offset) offset += BLOCK remaining -= BLOCK block = next_block diff --git a/kernel/input.rv b/kernel/input.rv index 139edf0..68313b7 100644 --- a/kernel/input.rv +++ b/kernel/input.rv @@ -12,7 +12,9 @@ fn pic_remap() do outb(0x21, 0x01) outb(0xa1, 0x01) outb(0x21, 0xff) outb(0xa1, 0xff) end -fn pic_unmask(line) outb(0x21, inb(0x21) band (255 bxor (1 shl line))) + +fn pic_unmask(line) + outb(0x21, inb(0x21) band (255 bxor (1 shl line))) # 8253/8254 pit channel 0, mode 3 (square wave) # divisor 11931 -> ~100 hz (1193182 / 11931) @@ -27,46 +29,82 @@ end # no fr this is just a key stroke handler global shell = { shift = :false, extended = :false, ctrl = :false } -fn decode_key(code) do - if code == 0x2a or code == 0x36 do shell.shift = :true return :nil end # shift down - if code == 0xaa or code == 0xb6 do shell.shift = :false return :nil end # shift up - if code == 0x1d do shell.ctrl = :true return :nil end # ctrl down - if code == 0x9d do shell.ctrl = :false return :nil end # ctrl up - if code >= 128 return :nil # other releases - if code == 28 return "\n" # enter +fn decode_key(code) -> string | :nil do + # shift down + if code == 0x2a or code == 0x36 do + shell.shift = :true + return :nil + end + # shift up + if code == 0xaa or code == 0xb6 do + shell.shift = :false + return :nil + end + # ctrl down + if code == 0x1d do + shell.ctrl = :true + return :nil + end + # ctrl up + if code == 0x9d do + shell.ctrl = :false + return :nil + end + # other releases + if (code >= 128) + return :nil + # enter + if (code == 28) + return "\n" + # backspace if code == 14 do if shell.ctrl do return "\x7f" end - return "\x08" - end # backspace (ctrl: word erase) - if code < 2 return :nil - if code >= KEYMAP:len() return :nil - const character = if shell.shift KEYMAP_SHIFT[code] else KEYMAP[code] - if character == " " and code != 0x39 return :nil # blank cells = modifiers/unmapped - if shell.ctrl return string.of_ascii(character:ascii() band 0x1f) + end + if (code < 2) + return :nil + if (code >= KEYMAP:len()) + return :nil + + const character = if (shell.shift) KEYMAP_SHIFT[code] else KEYMAP[code] + # blank cells = modifiers/unmapped + if (character == " " and code != 0x39) + return :nil + if (shell.ctrl) + return string.of_ascii(character:ascii() band 0x1f) return character end global on_key = fn(code) do - if code == 0xe0 do shell.extended = :true return :nil end + if code == 0xe0 do + shell.extended = :true + return :nil + end + if shell.extended do shell.extended = :false let final = 0 - if code == 0x48 do final = 65 end # up - else if code == 0x50 do final = 66 end # down - else if code == 0x4d do final = 67 end # right - else if code == 0x4b do final = 68 end # left - else if code == 0x47 do final = 72 end # home - else if code == 0x4f do final = 70 end # end + + match code + | 0x48 => final = 65 # up + | 0x50 => final = 66 # down + | 0x4d => final = 67 # right + | 0x4b => final = 68 # left + | 0x47 => final = 72 # home + | 0x4f => final = 70 # end + | _ => :nil + if final != 0 do tty:feed(27) tty:feed(91) tty:feed(final) end return :nil end + const character = decode_key(code) - if character == :nil return :nil + + if (character == :nil) + return :nil tty:feed(character:ascii()) end - diff --git a/kernel/io.rv b/kernel/io.rv index 68b7039..af28403 100644 --- a/kernel/io.rv +++ b/kernel/io.rv @@ -1,37 +1,44 @@ # stdio stuff global io = { - open = fn(self, path, mode) do - if mode == "w" do fs:store(path, "") end + fn open(self, path, mode) -> { path: string, offset: num } 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 + if (size > 0) + offset = size end + return { path = path, offset = offset } end, - read = fn(self, handle, count) do + fn read(self, handle, count) -> string do const data = fs:read_bytes(handle.path, handle.offset, count) handle.offset += data:len() return data end, - read_all = fn(self, handle) do + fn read_all(self, handle) -> string do const size = fs:size(handle.path) - if size <= handle.offset return "" + 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 + fn write(self, handle, data) -> num 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, + fn seek(self, handle, offset) do handle.offset = offset end, + fn tell(self, handle) -> num do return handle.offset end, + fn close(self, handle) :nil, } diff --git a/kernel/main.rv b/kernel/main.rv index 3547665..64af212 100644 --- a/kernel/main.rv +++ b/kernel/main.rv @@ -9,7 +9,7 @@ wipe() dump_memmap() fs:mount() -if (disk_sectors() != 0 and fs.ready == :false) do +if disk_sectors() != 0 and fs.ready == :false do puts("blank disk, formatting + seeding default files\n") fs:format() seed_fs() diff --git a/kernel/proc.rv b/kernel/proc.rv index 92d48f1..8d7827a 100644 --- a/kernel/proc.rv +++ b/kernel/proc.rv @@ -9,35 +9,45 @@ fn load_elf(base, arg) do puts("not an ELF\n") return :nil end + const entry = mem_read(base + 24, 8) const program_header_offset = mem_read(base + 32, 8) const program_header_count = mem_read(base + 56, 2) const program_header_size = mem_read(base + 54, 2) const space = as_create() + for index in 0..program_header_count do const header = base + program_header_offset + index * program_header_size + if mem_read(header, 4) == PT_LOAD do const file_offset = mem_read(header + 8, 8) const virtual_address = mem_read(header + 16, 8) const file_size = mem_read(header + 32, 8) const memory_size = mem_read(header + 40, 8) let segment_offset = 0 - while segment_offset < memory_size do + + while (segment_offset < memory_size) do const frame = frame_alloc() mem_zero(frame, 4096) + if segment_offset < file_size do const remaining = file_size - segment_offset - mem_copy(frame, base + file_offset + segment_offset, if remaining > 4096 4096 else remaining) + mem_copy(frame, base + file_offset + segment_offset, if (remaining > 4096) 4096 else remaining) end + as_map(space, virtual_address + segment_offset, frame, PAGE_FLAGS) segment_offset = segment_offset + 4096 end end end + const stack_top = 0x7fff0000 + for page in 0..4 do as_map(space, stack_top - (page + 1) * 4096, frame_alloc(), PAGE_FLAGS) end + let arg_ptr = 0 const arg_len = arg:len() + if arg_len > 0 do const arg_frame = frame_alloc() mem_zero(arg_frame, 4096) @@ -45,31 +55,50 @@ fn load_elf(base, arg) do as_map(space, ARG_VADDR, arg_frame, PAGE_FLAGS) arg_ptr = ARG_VADDR end + proc_run(space, entry, stack_top, arg_ptr, arg_len) end -# one reused contiguous buffer to stage an elf image read off the disk, since -# load_elf wants a flat base to mem_read from and a file lands in scattered frames -# its a weird arch but wtv +#* one reused contiguous buffer to stage an elf image read off the disk, since + load_elf wants a flat base to mem_read from and a file lands in scattered frames + its a weird arch but wtv *# global loader = { scratch = 0 } const SCRATCH_PAGES = 64 -fn load_file_elf(path, arg) do +fn load_file_elf(path, arg) -> bool do const size = fs:size(path) - if size < 0 do puts("#{path}: not found\n") return :false end - if size > SCRATCH_PAGES * 4096 do puts("#{path}: too big to load\n") return :false end - if loader.scratch == 0 do loader.scratch = alloc_contig(SCRATCH_PAGES) end - if loader.scratch == 0 do puts("no memory for elf load\n") return :false end + if size < 0 do + puts("#{path}: not found\n") + return :false + end + if size > SCRATCH_PAGES * 4096 do + puts("#{path}: too big to load\n") + return :false + end + + if loader.scratch == 0 do + loader.scratch = alloc_contig(SCRATCH_PAGES) + end + if loader.scratch == 0 do + puts("no memory for elf load\n") + return :false + end + blit_str(loader.scratch, fs:read_bytes(path, 0, size)) load_elf(loader.scratch, arg) + return :true end -fn run_prog(name, arg) do +fn run_prog(name, arg) -> bool do let bare_name = name - if bare_name:starts_with?("/usr/bin/") bare_name = bare_name[9..] + 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 + if (fs:size(path) < 0) + return :false + return load_file_elf(path, arg) end diff --git a/kernel/shell.rv b/kernel/shell.rv index 99ead73..e016d18 100644 --- a/kernel/shell.rv +++ b/kernel/shell.rv @@ -10,13 +10,13 @@ fn pad(text, width) -> string do end fn help_row(label, description) do - let col = pad(label, 22) + let column = pad(label, 22) if label:len() >= 22 do - col = label ~ " " + column = label ~ " " end - puts(" #{col}#{description}\n") + puts(" #{column}#{description}\n") end fn help_group(title, group_name) do diff --git a/kernel/ttf.rv b/kernel/ttf.rv index 17d1a19..fb1bab7 100644 --- a/kernel/ttf.rv +++ b/kernel/ttf.rv @@ -6,84 +6,120 @@ # fuck lung # fuck me # im like 90% confident this works, but im like 10% confident its fucked -fn ttf_mod(a, b) a - math.floor(a / b) * b +fn ttf_mod(value, modulus) -> num do + return value - math.floor(value / modulus) * modulus +end + +fn ttf_u8(data, offset) -> num do + return mem_read(data + offset, 1) +end -fn ttf_u8(d, o) mem_read(d + o, 1) -fn ttf_u16(d, o) mem_read(d + o, 1) * 256 + mem_read(d + o + 1, 1) -fn ttf_i16(d, o) do - const v = ttf_u16(d, o) - if v >= 32768 return v - 65536 - return v +fn ttf_u16(data, offset) -> num do + return mem_read(data + offset, 1) * 256 + mem_read(data + offset + 1, 1) end -fn ttf_u32(d, o) ((mem_read(d + o, 1) * 256 + mem_read(d + o + 1, 1)) * 256 + mem_read(d + o + 2, 1)) * 256 + mem_read(d + o + 3, 1) -fn ttf_tag_eq(d, o, tag) do - for i in 0..4 do if mem_read(d + o + i, 1) != tag[i]:ascii() return :false end +fn ttf_i16(data, offset) -> num do + const value = ttf_u16(data, offset) + if (value >= 32768) + return value - 65536 + return value +end + +fn ttf_u32(data, offset) -> num do + return ((mem_read(data + offset, 1) * 256 + mem_read(data + offset + 1, 1)) * 256 + mem_read(data + offset + 2, 1)) * 256 + mem_read(data + offset + 3, 1) +end + +fn ttf_tag_eq(data, offset, tag) -> bool do + for i in 0..4 do + if (mem_read(data + offset + i, 1) != tag[i]:ascii()) + return :false + end + return :true end -fn ttf_table(d, tag) do - const n = ttf_u16(d, 4) - for i in 0..n do - const rec = 12 + i * 16 - if ttf_tag_eq(d, rec, tag) return ttf_u32(d, rec + 8) +fn ttf_table(data, tag) -> num do + const count = ttf_u16(data, 4) + for i in 0..count do + const record = 12 + i * 16 + if (ttf_tag_eq(data, record, tag)) + return ttf_u32(data, record + 8) end return -1 end -fn ttf_cmap_sub(d, cmap_off) do - const n = ttf_u16(d, cmap_off + 2) +fn ttf_cmap_sub(data, cmap_off) -> num do + const count = ttf_u16(data, cmap_off + 2) let best = -1 - for i in 0..n do - const rec = cmap_off + 4 + i * 8 - const plat = ttf_u16(d, rec) - const enc = ttf_u16(d, rec + 2) - if (plat == 3 and (enc == 1 or enc == 0)) or plat == 0 do best = cmap_off + ttf_u32(d, rec + 4) end + + for i in 0..count do + const record = cmap_off + 4 + i * 8 + const platform = ttf_u16(data, record) + const encoding = ttf_u16(data, record + 2) + if (platform == 3 and (encoding == 1 or encoding == 0)) or platform == 0 do + best = cmap_off + ttf_u32(data, record + 4) + end end + return best end -fn ttf_glyph_of(d, sub, c) do - if ttf_u16(d, sub) != 4 return 0 - const segCount = ttf_u16(d, sub + 6) / 2 - const endBase = sub + 14 - const startBase = endBase + segCount * 2 + 2 - const deltaBase = startBase + segCount * 2 - const rangeBase = deltaBase + segCount * 2 - for i in 0..segCount do - if c <= ttf_u16(d, endBase + i * 2) do - const startC = ttf_u16(d, startBase + i * 2) - if c < startC return 0 - const idro = ttf_u16(d, rangeBase + i * 2) - if idro == 0 return (c + ttf_i16(d, deltaBase + i * 2)) band 0xFFFF - const g = ttf_u16(d, rangeBase + i * 2 + idro + (c - startC) * 2) - if g == 0 return 0 - return (g + ttf_i16(d, deltaBase + i * 2)) band 0xFFFF +fn ttf_glyph_of(data, subtable, code) -> num do + if (ttf_u16(data, subtable) != 4) + return 0 + + const segment_count = ttf_u16(data, subtable + 6) / 2 + const end_base = subtable + 14 + const start_base = end_base + segment_count * 2 + 2 + const delta_base = start_base + segment_count * 2 + const range_base = delta_base + segment_count * 2 + + for i in 0..segment_count do + if code <= ttf_u16(data, end_base + i * 2) do + const start_code = ttf_u16(data, start_base + i * 2) + if (code < start_code) + return 0 + + const idro = ttf_u16(data, range_base + i * 2) + if (idro == 0) + return (code + ttf_i16(data, delta_base + i * 2)) band 0xFFFF + + const glyph_id = ttf_u16(data, range_base + i * 2 + idro + (code - start_code) * 2) + if (glyph_id == 0) + return 0 + + return (glyph_id + ttf_i16(data, delta_base + i * 2)) band 0xFFFF end end + return 0 end -fn ttf_glyph_offset(d, loca, long, g) do - if long return ttf_u32(d, loca + g * 4) - return ttf_u16(d, loca + g * 2) * 2 +fn ttf_glyph_offset(data, loca, long, glyph_id) -> num do + if (long) + return ttf_u32(data, loca + glyph_id * 4) + return ttf_u16(data, loca + glyph_id * 2) * 2 end -fn ttf_advance(d, hmtx, numH, g) do - if g < numH return ttf_u16(d, hmtx + g * 4) - return ttf_u16(d, hmtx + (numH - 1) * 4) +fn ttf_advance(data, hmtx, num_hmetrics, glyph_id) -> num do + if (glyph_id < num_hmetrics) + return ttf_u16(data, hmtx + glyph_id * 4) + return ttf_u16(data, hmtx + (num_hmetrics - 1) * 4) end -fn ttf_add_line(edges, x0, y0, x1, y1) edges:push({ ax = x0, ay = y0, bx = x1, by = y1 }) +fn ttf_add_line(edges, x0, y0, x1, y1) + edges:push({ ax = x0, ay = y0, bx = x1, by = y1 }) -fn ttf_add_quad(edges, x0, y0, cx, cy, x1, y1, n) do +fn ttf_add_quad(edges, x0, y0, cx, cy, x1, y1, steps) do let px = x0 let py = y0 - for i in 1..(n + 1) do - const t = i / n + + for i in 1..(steps + 1) do + const t = i / steps const mt = 1 - t const qx = mt * mt * x0 + 2 * mt * t * cx + t * t * x1 const qy = mt * mt * y0 + 2 * mt * t * cy + t * t * y1 + ttf_add_line(edges, px, py, qx, qy) px = qx py = qy @@ -91,196 +127,289 @@ fn ttf_add_quad(edges, x0, y0, cx, cy, x1, y1, n) do end fn ttf_contour(pts, edges, nsub) do - const m = pts:len() - if m < 2 return :nil - let exp = {} - for i in 0..m do - exp:push(pts[i]) - const j = ttf_mod(i + 1, m) - if (pts[i].on == :false and pts[j].on == :false) do - exp:push({ x = (pts[i].x + pts[j].x) / 2, y = (pts[i].y + pts[j].y) / 2, on = :true }) + const point_count = pts:len() + if (point_count < 2) + return :nil + + let expanded = {} + for i in 0..point_count do + expanded:push(pts[i]) + const j = ttf_mod(i + 1, point_count) + + if pts[i].on == :false and pts[j].on == :false do + expanded:push({ x = (pts[i].x + pts[j].x) / 2, y = (pts[i].y + pts[j].y) / 2, on = :true }) end end - const n = exp:len() - let s = -1 - for i in 0..n do if (s < 0 and exp[i].on) do s = i end end - if s < 0 return :nil - let cx = exp[s].x - let cy = exp[s].y + + const expanded_count = expanded:len() + let start = -1 + for i in 0..expanded_count do + if (start < 0 and expanded[i].on) + start = i + end + + if (start < 0) + return :nil + + let cx = expanded[start].x + let cy = expanded[start].y let k = 1 - while k <= n do - const a = exp[ttf_mod(s + k, n)] - if a.on do - ttf_add_line(edges, cx, cy, a.x, a.y) - cx = a.x - cy = a.y + + while (k <= expanded_count) do + const point = expanded[ttf_mod(start + k, expanded_count)] + + if point.on do + ttf_add_line(edges, cx, cy, point.x, point.y) + cx = point.x + cy = point.y k += 1 - end - else do - const b = exp[ttf_mod(s + k + 1, n)] - ttf_add_quad(edges, cx, cy, a.x, a.y, b.x, b.y, nsub) - cx = b.x - cy = b.y + end else do + const endpoint = expanded[ttf_mod(start + k + 1, expanded_count)] + ttf_add_quad(edges, cx, cy, point.x, point.y, endpoint.x, endpoint.y, nsub) + cx = endpoint.x + cy = endpoint.y k += 2 end end end # how about you contour my fucking asshole -fn ttf_glyph_edges(d, glyf, loca, long, g, scale, ox, baseline, edges, nsub) do - const off = ttf_glyph_offset(d, loca, long, g) - const next = ttf_glyph_offset(d, loca, long, g + 1) - if next <= off return :nil # empty glyph - const base = glyf + off - const nc = ttf_i16(d, base) - if nc < 0 return :nil # skip +fn ttf_glyph_edges(data, glyf, loca, long, glyph_id, scale, ox, baseline, edges, nsub) do + const offset = ttf_glyph_offset(data, loca, long, glyph_id) + const next = ttf_glyph_offset(data, loca, long, glyph_id + 1) + + # empty glyph + if (next <= offset) + return :nil + const base = glyf + offset + const contour_count = ttf_i16(data, base) + + # skip + if (contour_count < 0) + return :nil + let ends = {} - for i in 0..nc do ends:push(ttf_u16(d, base + 10 + i * 2)) end - const npts = ends[nc - 1] + 1 - let p = base + 10 + nc * 2 - p += 2 + ttf_u16(d, p) # skip instructions + for i in 0..contour_count do ends:push(ttf_u16(data, base + 10 + i * 2)) end + + const point_count = ends[contour_count - 1] + 1 + let pos = base + 10 + contour_count * 2 + + pos += 2 + ttf_u16(data, pos) # skip instructions let flags = {} - while flags:len() < npts do - const f = ttf_u8(d, p) - p += 1 - flags:push(f) - if (f band 0x08) != 0 do - let rep = ttf_u8(d, p) - p += 1 - while rep > 0 do flags:push(f) rep -= 1 end + while (flags:len() < point_count) do + const flag = ttf_u8(data, pos) + + pos += 1 + flags:push(flag) + + if (flag band 0x08) != 0 do + let repeat = ttf_u8(data, pos) + pos += 1 + + while (repeat > 0) do + flags:push(flag) + repeat -= 1 + end end end + let xs = {} let x = 0 - for i in 0..npts do - const f = flags[i] - if (f band 0x02) != 0 do - const dx = ttf_u8(d, p) - p += 1 - if (f band 0x10) != 0 do x += dx end else do x -= dx end - end - else do - if (f band 0x10) == 0 do x += ttf_i16(d, p) p += 2 end + + for i in 0..point_count do + const flag = flags[i] + + if (flag band 0x02) != 0 do + const dx = ttf_u8(data, pos) + pos += 1 + + if (flag band 0x10) != 0 do + x += dx + end else do + x -= dx + end + end else do + if (flag band 0x10) == 0 do + x += ttf_i16(data, pos) + pos += 2 + end end + xs:push(x) end + let ys = {} let y = 0 - for i in 0..npts do - const f = flags[i] - if (f band 0x04) != 0 do - const dy = ttf_u8(d, p) - p += 1 - if (f band 0x20) != 0 do y += dy end else do y -= dy end - end - else do - if (f band 0x20) == 0 do y += ttf_i16(d, p) p += 2 end + + for i in 0..point_count do + const flag = flags[i] + + if (flag band 0x04) != 0 do + const dy = ttf_u8(data, pos) + pos += 1 + + if (flag band 0x20) != 0 do + y += dy + end else do + y -= dy + end + end else do + if (flag band 0x20) == 0 do + y += ttf_i16(data, pos) + pos += 2 + end end + ys:push(y) end + # split into contours let start = 0 - for ci in 0..nc do + + for ci in 0..contour_count do const stop = ends[ci] let pts = {} + for i in start..(stop + 1) do pts:push({ x = xs[i] * scale + ox, y = baseline - ys[i] * scale, on = (flags[i] band 0x01) != 0 }) end + ttf_contour(pts, edges, nsub) start = stop + 1 end end -fn ttf_fill(edges, w, h) do +fn ttf_fill(edges, width, height) -> table do let rows = {} - for py in 0..h do + + for py in 0..height do const yc = py + 0.5 let cross = {} - for e in 0..edges:len() do - const ed = edges[e] - const y0 = ed.ay - const y1 = ed.by - if ((y0 <= yc and yc < y1) or (y1 <= yc and yc < y0)) do + + for i in 0..edges:len() do + const edge = edges[i] + const y0 = edge.ay + const y1 = edge.by + + if (y0 <= yc and yc < y1) or (y1 <= yc and yc < y0) do const t = (yc - y0) / (y1 - y0) - let dir = 1 - if y1 < y0 do dir = -1 end - cross:push({ x = ed.ax + t * (ed.bx - ed.ax), dir = dir }) + let direction = 1 + + if y1 < y0 do + direction = -1 + end + + cross:push({ x = edge.ax + t * (edge.bx - edge.ax), dir = direction }) end end + # sort crossings left to right # insertion sort - for a in 1..cross:len() do - const key = cross[a] - let b = a - 1 - while (b >= 0 and cross[b].x > key.x) do - cross[b + 1] = cross[b] - b -= 1 + for i in 1..cross:len() do + const key = cross[i] + let j = i - 1 + while (j >= 0 and cross[j].x > key.x) do + cross[j + 1] = cross[j] + j -= 1 end - cross[b + 1] = key + + cross[j + 1] = key end + let bits = 0 - let wind = 0 + let winding = 0 + for k in 0..cross:len() do - wind += cross[k].dir - if (wind != 0 and k + 1 < cross:len()) do + winding += cross[k].dir + + if (winding != 0 and k + 1 < cross:len()) do const xa = cross[k].x const xb = cross[k + 1].x + if xb > xa do let any = :false - for px in 0..w do - if (px + 0.5 >= xa and px + 0.5 < xb) do bits = bits bor (1 shl px) any = :true end + for px in 0..width do + if (px + 0.5 >= xa and px + 0.5 < xb) do + bits = bits bor (1 shl px) + any = :true + end end + if any == :false do - const mid = math.floor((xa + xb) / 2) - if (mid >= 0 and mid < w) do bits = bits bor (1 shl mid) end + const midpoint = math.floor((xa + xb) / 2) + if (midpoint >= 0 and midpoint < width) + bits = bits bor (1 shl midpoint) end end end end + rows:push(bits) end + return rows end -global ttf_io = { buf = 0, pages = 512 } +global ttf_io = { buffer = 0, pages = 512 } -global load_ttf = fn(path, size) do +global load_ttf = fn(path, size) -> { glyphs: table, width: num, height: num } | :nil do const total = fs:size(path) - if total < 12 return :nil - if ttf_io.buf == 0 do ttf_io.buf = alloc_contig(ttf_io.pages) end - if ttf_io.buf == 0 return :nil - if total > ttf_io.pages * 4096 return :nil - fs:read_into(path, ttf_io.buf) - const d = ttf_io.buf - const head = ttf_table(d, "head") - const maxp = ttf_table(d, "maxp") - const cmap = ttf_table(d, "cmap") - const loca = ttf_table(d, "loca") - const glyf = ttf_table(d, "glyf") - const hhea = ttf_table(d, "hhea") - const hmtx = ttf_table(d, "hmtx") - if (head < 0 or cmap < 0 or loca < 0 or glyf < 0 or hhea < 0) return :nil - const upm = ttf_u16(d, head + 18) - if upm == 0 return :nil - const long = ttf_i16(d, head + 50) == 1 - const ascent = ttf_i16(d, hhea + 4) - const descent = ttf_i16(d, hhea + 6) - const numH = ttf_u16(d, hhea + 34) + if (total < 12) + return :nil + + if ttf_io.buffer == 0 do + ttf_io.buffer = alloc_contig(ttf_io.pages) + end + if (ttf_io.buffer == 0) + return :nil + if (total > ttf_io.pages * 4096) + return :nil + + fs:read_into(path, ttf_io.buffer) + + const data = ttf_io.buffer + const head = ttf_table(data, "head") + const maxp = ttf_table(data, "maxp") + const cmap = ttf_table(data, "cmap") + const loca = ttf_table(data, "loca") + const glyf = ttf_table(data, "glyf") + const hhea = ttf_table(data, "hhea") + const hmtx = ttf_table(data, "hmtx") + + if (head < 0 or cmap < 0 or loca < 0 or glyf < 0 or hhea < 0) + return :nil + + const upm = ttf_u16(data, head + 18) + if (upm == 0) + return :nil + + const long = ttf_i16(data, head + 50) == 1 + const ascent = ttf_i16(data, hhea + 4) + const descent = ttf_i16(data, hhea + 6) + const num_hmetrics = ttf_u16(data, hhea + 34) const scale = size / upm const baseline = math.floor(ascent * scale) let height = math.floor((ascent - descent) * scale) + 1 - const sub = ttf_cmap_sub(d, cmap) - if sub < 0 return :nil - const mgate = ttf_glyph_of(d, sub, 77) # 'M' - let width = math.floor(ttf_advance(d, hmtx, numH, mgate) * scale) + 1 - if width < 2 do width = math.floor(size * 0.6) + 1 end + + const subtable = ttf_cmap_sub(data, cmap) + if (subtable < 0) + return :nil + + const mgate = ttf_glyph_of(data, subtable, 77) # 'M' + let width = math.floor(ttf_advance(data, hmtx, num_hmetrics, mgate) * scale) + 1 + if (width < 2) + width = math.floor(size * 0.6) + 1 + const nsub = 5 let glyphs = {} + for code in 32..128 do - const g = ttf_glyph_of(d, sub, code) + const glyph_id = ttf_glyph_of(data, subtable, code) let edges = {} - ttf_glyph_edges(d, glyf, loca, long, g, scale, 1, baseline, edges, nsub) + + ttf_glyph_edges(data, glyf, loca, long, glyph_id, scale, 1, baseline, edges, nsub) glyphs:push(ttf_fill(edges, width, height)) end + return { glyphs = glyphs, width = width, height = height } end diff --git a/kernel/tty.rv b/kernel/tty.rv index 680289f..7ea2492 100644 --- a/kernel/tty.rv +++ b/kernel/tty.rv @@ -6,51 +6,70 @@ global tty = { line = "", cursor = 0, esc = 0, history = {}, hist_index = 0, - back = fn(self, n) do + fn back(self, n) do let i = 0 - while i < n do puts("\x08") i += 1 end + while (i < n) do + puts("\x08") + i += 1 + end end, - blanks = fn(self, n) do + + fn blanks(self, n) do let i = 0 - while i < n do puts(" ") i += 1 end + while (i < n) do + puts(" ") + i += 1 + end end, - insert = fn(self, ch) do + fn insert(self, character) do const pre = self.line[0..self.cursor] const post = self.line[self.cursor..] - self.line = pre ~ ch ~ post - puts(ch ~ post) + self.line = pre ~ character ~ post + puts(character ~ post) self:back(post:len()) self.cursor += 1 end, - backspace = fn(self) do - if self.cursor == 0 return :nil + fn backspace(self) do + if (self.cursor == 0) + return :nil + const pre = self.line[0..(self.cursor - 1)] const post = self.line[self.cursor..] self.line = pre ~ post self.cursor -= 1 + puts("\x08") puts(post ~ " ") self:back(post:len() + 1) end, - move_left = fn(self) do - if self.cursor > 0 do puts("\x08") self.cursor -= 1 end + fn move_left(self) do + if self.cursor > 0 do + puts("\x08") + self.cursor -= 1 + end end, - move_right = fn(self) do - if self.cursor < self.line:len() do puts(self.line[self.cursor]) self.cursor += 1 end + + fn move_right(self) do + if self.cursor < self.line:len() do + puts(self.line[self.cursor]) + self.cursor += 1 + end end, - home = fn(self) do + + fn home(self) do self:back(self.cursor) self.cursor = 0 end, - to_end = fn(self) do + + fn to_end(self) do puts(self.line[self.cursor..]) self.cursor = self.line:len() end, - kill = fn(self) do + fn kill(self) do self:back(self.cursor) self:blanks(self.line:len()) self:back(self.line:len()) @@ -58,50 +77,65 @@ global tty = { self.cursor = 0 end, - erase_word = fn(self) do - if self.cursor == 0 return :nil + fn erase_word(self) do + if (self.cursor == 0) + return :nil + let at = self.cursor - while (at > 0 and self.line[at - 1] == " ") do at -= 1 end - while (at > 0 and self.line[at - 1] != " ") do at -= 1 end + while (at > 0 and self.line[at - 1] == " ") + at -= 1 + while (at > 0 and self.line[at - 1] != " ") + at -= 1 + let count = self.cursor - at - while count > 0 do self:backspace() count -= 1 end + while (count > 0) do + self:backspace() + count -= 1 + end end, - replace_line = fn(self, text) do + fn replace_line(self, text) do self:kill() self.line = text puts(text) self.cursor = text:len() end, - history_prev = fn(self) do - if self.history:len() == 0 return :nil - if self.hist_index > 0 do self.hist_index -= 1 end + fn history_prev(self) do + if (self.history:len() == 0) + return :nil + if (self.hist_index > 0) + self.hist_index -= 1 + self:replace_line(self.history[self.hist_index]) end, - history_next = fn(self) do - if self.history:len() == 0 return :nil + + fn history_next(self) do + if (self.history:len() == 0) + return :nil + if self.hist_index < self.history:len() - 1 do self.hist_index += 1 self:replace_line(self.history[self.hist_index]) - end - else do + end else do self.hist_index = self.history:len() self:replace_line("") end end, - submit = fn(self) do + fn submit(self) do puts("\n") const entered = self.line - if entered:len() > 0 do self.history:push(entered) end + if (entered:len() > 0) + self.history:push(entered) + self.hist_index = self.history:len() self.line = "" self.cursor = 0 run(entered) end, - cancel = fn(self) do + fn cancel(self) do puts("^C\n") self.line = "" self.cursor = 0 @@ -109,44 +143,65 @@ global tty = { puts(prompt()) end, - clear_screen = fn(self) do + fn clear_screen(self) do console:clear() puts(prompt()) puts(self.line) self:back(self.line:len() - self.cursor) end, - feed = fn(self, byte) do - if stdin_deliver(byte) return :nil + fn feed(self, byte) do + if (stdin_deliver(byte)) + return :nil if self.esc == 1 do - if byte == 91 do self.esc = 2 end - else do self.esc = 0 end + if byte == 91 do + self.esc = 2 + end else do + self.esc = 0 + end + return :nil end + if self.esc == 2 do self.esc = 0 - if byte == 65 do self:history_prev() end # up - else if byte == 66 do self:history_next() end # down - else if byte == 67 do self:move_right() end # right - else if byte == 68 do self:move_left() end # left - else if byte == 72 do self:home() end # home - else if byte == 70 do self:to_end() end # end + + match byte + | 65 => self:history_prev() # up + | 66 => self:history_next() # down + | 67 => self:move_right() # right + | 68 => self:move_left() # left + | 72 => self:home() # home + | 70 => self:to_end() # end + | _ => :nil + + return :nil + end + + # ESC, start a sequence + if byte == 27 do + self.esc = 1 return :nil end - if byte == 27 do self.esc = 1 return :nil end # ESC, start a sequence - if byte == 10 do self:submit() return :nil end # enter - if byte == 8 do self:backspace() return :nil end # bs - if byte == 127 do self:erase_word() return :nil end # del (ctrl-bs): erase word - if byte == 1 do self:home() return :nil end # ctrl-a - if byte == 5 do self:to_end() return :nil end # ctrl-e - if byte == 3 do self:cancel() return :nil end # ctrl-c - if byte == 12 do self:clear_screen() return :nil end # ctrl-l - if byte == 21 do self:kill() return :nil end # ctrl-u - if byte == 23 do self:erase_word() return :nil end # ctrl-w - if byte < 32 return :nil # ctrl-d and other ctrls: ignore - if byte > 126 return :nil - self:insert(string.of_ascii(byte)) + match byte + | 10 => self:submit() # enter + | 8 => self:backspace() # bs + | 127 => self:erase_word() # del (ctrl-bs) + | 1 => self:home() # ctrl-a + | 5 => self:to_end() # ctrl-e + | 3 => self:cancel() # ctrl-c + | 12 => self:clear_screen() # ctrl-l + | 21 => self:kill() # ctrl-u + | 23 => self:erase_word() # ctrl-w + | _ => do + # ctrl-d and other shits + if (byte < 32) + return :nil + if (byte > 126) + return :nil + self:insert(string.of_ascii(byte)) + end end, } diff --git a/kernel/vfs.rv b/kernel/vfs.rv index 22c399e..6df71cc 100644 --- a/kernel/vfs.rv +++ b/kernel/vfs.rv @@ -3,35 +3,51 @@ const TASK_STATES = { "free", "ready", "dead", "blocked" } -global vfs_owns = fn(path) do - if path == "/proc" or path:starts_with?("/proc/") return :true +global vfs_owns = fn(path) -> bool do + if (path == "/proc" or path:starts_with?("/proc/")) + return :true return :false end -global parse_pid = fn(text) do - if text:len() == 0 return -1 +global parse_pid = fn(text) -> num do + if (text:len() == 0) + return -1 + let number = 0 for index in 0..text:len() do const code = text[index]:ascii() - if code < 48 or code > 57 return -1 + if (code < 48 or code > 57) + return -1 number = number * 10 + (code - 48) end + return number end global vfs_ls = fn(path) do if path == "/proc" do puts(" uptime\n meminfo\n") + for pid in 0..task_max() do - if task_state(pid) != 0 puts(" #{pid}\n") + if (task_state(pid) != 0) + puts(" #{pid}\n") end + end else do + puts("ls: #{path}: no such directory\n") end - else do puts("ls: #{path}: no such directory\n") end end global vfs_cat = fn(path) do - if path == "/proc/uptime" do puts("#{math.floor(uptime() / 100)}s\n") return :nil end - if path == "/proc/meminfo" do puts("#{(mem_free() shr 20)} MiB free / #{(mem_total() shr 20)} MiB total\n") return :nil end + if path == "/proc/uptime" do + puts("#{math.floor(uptime() / 100)}s\n") + return :nil + end + + if path == "/proc/meminfo" do + puts("#{(mem_free() shr 20)} MiB free / #{(mem_total() shr 20)} MiB total\n") + return :nil + end + if path:starts_with?("/proc/") do const pid = parse_pid(path[6..]) if pid >= 0 and pid < task_max() and task_state(pid) != 0 do @@ -41,5 +57,6 @@ global vfs_cat = fn(path) do puts("cat: #{path}: no such file\n") return :nil end + puts("cat: #{path}: no such file\n") end diff --git a/kernel/vmm.rv b/kernel/vmm.rv index 0de5f33..54d1695 100644 --- a/kernel/vmm.rv +++ b/kernel/vmm.rv @@ -2,22 +2,28 @@ # everything here only writes small entries we construct, so its f64 safe const PTE_ADDR = 0x000FFFFFFFFFF000 -fn pte_index(virtual_address, level) (virtual_address shr (12 + 9 * level)) band 0x1ff +fn pte_index(virtual_address, level) -> num do + return (virtual_address shr (12 + 9 * level)) band 0x1ff +end -fn next_table(table, index) do +fn next_table(table, index) -> num do const slot = table + index * 8 const entry = mem_read(slot, 8) - if (entry band 1) != 0 return entry band PTE_ADDR + if (entry band 1) != 0 do + return entry band PTE_ADDR + end + const frame = frame_alloc() mem_zero(frame, 4096) mem_write(slot, frame bor 7, 8) # present | write | user - frame + return frame end fn as_map(pml4, virtual_address, physical_address, flags) do const pdpt = next_table(pml4, pte_index(virtual_address, 3)) const pd = next_table(pdpt, pte_index(virtual_address, 2)) const pt = next_table(pd, pte_index(virtual_address, 1)) + mem_write(pt + pte_index(virtual_address, 0) * 8, (physical_address band PTE_ADDR) bor flags bor 1, 8) invlpg(virtual_address) end |
