diff options
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/console.rv | 94 | ||||
| -rw-r--r-- | kernel/fs.rv | 49 | ||||
| -rw-r--r-- | kernel/io.rv | 37 | ||||
| -rw-r--r-- | kernel/main.rv | 4 | ||||
| -rw-r--r-- | kernel/proc.rv | 4 | ||||
| -rw-r--r-- | kernel/seed.rv | 10 | ||||
| -rw-r--r-- | kernel/shell.rv | 81 |
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 |
