import vpsdk.vpui as vpui import vpsdk.window as window import vpsdk.process as process import vpsdk.fs as fs import vpsdk.syscall as _syscall import vpsdk.stdlib as stdlib import string import viperlib from stdint import * import t, c @c.Attribute(t.attr.section(".text.startup"), t.attr.aligned(16)) def _start() -> t.CInt | t.CExport: root: vpui.Tk = vpui.Tk() root.title("Terminal") root.set_style(window.STYLE_WIN7) root.geometry(80, 30, 640, 480) root.bg_color = t.CUInt32T(0x0C0C0C) master: vpui.Tk | t.CPtr = c.Addr(root) def _sdbg(msg: str): _syscall._syscall1(t.CUInt64T(18), t.CUInt64T(msg)) _sdbg("[term] start\n") _cwd: t.CArray[t.CChar, 64] _cwd[0] = 47 for i in range(1, 64): _cwd[i] = 0 sbar: vpui.Scrollbar = vpui.Scrollbar(master, 16, 446, vpui.VERTICAL) root.pack(0, vpui.PACK_RIGHT, vpui.FILL_Y, 0, 0, 0) term: vpui.Text = vpui.Text(master, 624, 446) root.pack(1, vpui.PACK_LEFT, vpui.FILL_BOTH, 1, 0, 0) term.insert("ViperOS Terminal v1.1") term.insert("Type 'help' for commands.") term.insert("") term.yscrollbar = t.CType(sbar, vpui.Widget, t.CPtr) def _on_scroll(): act: t.CInt = sbar.action if act == 1: term.scroll_offset -= 1 elif act == 2: term.scroll_offset += 1 elif act == 3: vis: t.CInt = term._visible_lines() term.scroll_offset -= vis elif act == 4: vis2: t.CInt = term._visible_lines() term.scroll_offset += vis2 elif act == 5: aval: t.CInt = sbar.action_value if term.line_count > 0: term.scroll_offset = aval * term.line_count / 1000 vis3: t.CInt = term._visible_lines() max_off: t.CInt = term.line_count - vis3 if max_off < 0: max_off = 0 if term.scroll_offset < 0: term.scroll_offset = 0 if term.scroll_offset > max_off: term.scroll_offset = max_off term._update_scrollbar() sbar.command = c.Addr(_on_scroll) def _startswith(s: str, prefix: str) -> t.CInt: plen: t.CSizeT = string.strlen(prefix) if string.strncmp(s, prefix, plen) == 0: return 1 return 0 def _build_path(out: str, out_size: t.CInt, rel: str): if c.Deref(rel) == 47: string.strncpy(out, rel, out_size - 1) else: i: t.CInt = 0 for i in range(63): ch: t.CChar = _cwd[i] c.DerefAs(out + i, ch) if ch == 0: break cwd_len: t.CInt = i if cwd_len > 0 and _cwd[cwd_len - 1] != 47: c.DerefAs(out + cwd_len, t.CChar(47)) cwd_len += 1 j: t.CInt = 0 for j in range(out_size - 1 - cwd_len): ch2: t.CChar = c.Deref(rel + j) c.DerefAs(out + cwd_len + j, ch2) if ch2 == 0: break c.DerefAs(out + out_size - 1, t.CChar(0)) def _print_dir_entry(name: str, is_dir: t.CInt): buf: t.CArray[t.CChar, 80] j: t.CInt = 0 for j in range(78): ch: t.CChar = c.Deref(name + j) buf[j] = ch if ch == 0: break if is_dir and j < 78: buf[j] = 47 j += 1 buf[j] = 0 term.insert_ptr(c.Addr(buf[0])) def _cmd_cd(path: str): if path is None or c.Deref(path) == 0: _cwd[0] = 47 for i in range(1, 64): _cwd[i] = 0 return full: t.CArray[t.CChar, 256] _build_path(c.Addr(full[0]), 256, path) dd: t.CInt = fs.opendir(c.Addr(full[0])) if dd < 0: term.insert("Error: dir not found") return fs.closedir(dd) string.strncpy(c.Addr(_cwd[0]), c.Addr(full[0]), 63) _cwd[63] = 0 def _cmd_ls(): dd: t.CInt = fs.opendir(c.Addr(_cwd[0])) if dd < 0: term.insert("Error: cannot open dir") return info: t.CArray[t.CChar, 320] string.memset(c.Addr(info[0]), 0, 320) while True: result: t.CInt = fs.readdir(dd, c.Addr(info[0])) if result != 0: break attr_val: t.CUInt8T = t.CUInt8T(c.Deref(c.Addr(info[4]))) name_off: t.CInt = 16 name_ptr: str = c.Addr(info[name_off]) if c.Deref(name_ptr) == 0: break if c.Deref(name_ptr) == 46: if c.Deref(name_ptr + 1) == 0: string.memset(c.Addr(info[0]), 0, 320) continue if c.Deref(name_ptr + 1) == 46 and c.Deref(name_ptr + 2) == 0: string.memset(c.Addr(info[0]), 0, 320) continue if (attr_val & 0x10) != 0: _print_dir_entry(name_ptr, 1) else: _print_dir_entry(name_ptr, 0) string.memset(c.Addr(info[0]), 0, 320) fs.closedir(dd) def _cmd_cat(path: str): full: t.CArray[t.CChar, 256] _build_path(c.Addr(full[0]), 256, path) fd: t.CInt = fs.open(c.Addr(full[0]), fs.O_RDONLY) if fd < 0: term.insert("Error: file not found") return buf: t.CArray[t.CChar, 80] while True: string.memset(c.Addr(buf[0]), 0, 80) n: t.CInt = fs.read(fd, c.Addr(buf[0]), 78) if n <= 0: break if n > 78: n = 78 buf[n] = 0 term.insert_ptr(c.Addr(buf[0])) fs.close(fd) def _cmd_mkdir(path: str): full: t.CArray[t.CChar, 256] _build_path(c.Addr(full[0]), 256, path) result: t.CInt = fs.mkdir(c.Addr(full[0])) if result < 0: term.insert("Error: mkdir failed") else: term.insert("Directory created") def _cmd_rm(path: str): full: t.CArray[t.CChar, 256] _build_path(c.Addr(full[0]), 256, path) result: t.CInt = fs.remove(c.Addr(full[0])) if result < 0: term.insert("Error: remove failed") else: term.insert("Removed") def _cmd_touch(path: str): full: t.CArray[t.CChar, 256] _build_path(c.Addr(full[0]), 256, path) fd: t.CInt = fs.open(c.Addr(full[0]), fs.O_WRONLY | fs.O_CREAT) if fd < 0: term.insert("Error: touch failed") return fs.close(fd) term.insert("File created") def _cmd_sysinfo(): term.insert("ViperOS v1.0 (x86_64)") term.insert("Framebuffer: 32bpp") term.insert("Compiler: TransPyC") def _cmd_hexdump(path: str): full: t.CArray[t.CChar, 256] _build_path(c.Addr(full[0]), 256, path) fd: t.CInt = fs.open(c.Addr(full[0]), fs.O_RDONLY) if fd < 0: term.insert("Error: file not found") return offset: t.CInt = 0 buf: t.CArray[t.CChar, 16] while True: string.memset(c.Addr(buf[0]), 0, 16) n: t.CInt = fs.read(fd, c.Addr(buf[0]), 16) if n <= 0: break if n > 16: n = 16 line: t.CArray[t.CChar, 80] string.memset(c.Addr(line[0]), 0, 80) viperlib.snprintf(c.Addr(line[0]), 80, "%08x: ", offset) pos: t.CInt = 10 j: t.CInt = 0 for j in range(16): if j < n: ub: t.CUInt32T = t.CUInt32T(buf[j]) & 0xFF hi: t.CInt = t.CInt(ub >> 4) lo: t.CInt = t.CInt(ub & 0xF) if hi < 10: line[pos] = t.CChar(48 + hi) else: line[pos] = t.CChar(65 + hi - 10) pos += 1 if lo < 10: line[pos] = t.CChar(48 + lo) else: line[pos] = t.CChar(65 + lo - 10) pos += 1 else: line[pos] = 32 pos += 1 line[pos] = 32 pos += 1 line[pos] = 32 pos += 1 if j == 7: line[pos] = 32 pos += 1 line[pos] = 124 pos += 1 for j in range(n): b2: t.CUInt32T = t.CUInt32T(buf[j]) & 0xFF if b2 >= 32 and b2 < 127: line[pos] = t.CChar(b2) else: line[pos] = 46 pos += 1 line[pos] = 0 term.insert_ptr(c.Addr(line[0])) offset += n fs.close(fd) def _cmd_run(path: str, blocking: t.CInt): full: t.CArray[t.CChar, 256] _build_path(c.Addr(full[0]), 256, path) pid: t.CInt = process.spawn(c.Addr(full[0]), blocking) if pid < 0: term.insert("Error: cannot spawn") elif blocking: term.insert("Process exited") else: msg: t.CArray[t.CChar, 32] viperlib.snprintf(c.Addr(msg[0]), 32, "Spawned pid=%d", pid) term.insert_ptr(c.Addr(msg[0])) def _on_command() -> t.CInt: _sdbg("[cmd] enter\n") text: str = term.get() _sdbg("[cmd] text=") _sdbg(text) _sdbg("\n") if _startswith(text, "echo "): term.insert_ptr(text + 5) elif string.samestr(text, "echo"): pass elif string.samestr(text, "clear"): term.delete(0, -1) elif string.samestr(text, "help"): term.insert("File: ls cd cat pwd mkdir rm touch") term.insert("Sys: ver about sysinfo reboot") term.insert("Util: echo clear help hexdump run runb") elif string.samestr(text, "ver"): term.insert("ViperOS Terminal v1.1") elif string.samestr(text, "about"): term.insert("ViperOS - A tiny OS in Viper lang") elif string.samestr(text, "pwd"): term.insert_ptr(c.Addr(_cwd[0])) elif string.samestr(text, "ls"): _cmd_ls() elif string.samestr(text, "cd"): _cmd_cd("") elif _startswith(text, "cd "): _cmd_cd(text + 3) elif _startswith(text, "cat "): _cmd_cat(text + 4) elif _startswith(text, "mkdir "): _cmd_mkdir(text + 6) elif _startswith(text, "rm "): _cmd_rm(text + 3) elif _startswith(text, "touch "): _cmd_touch(text + 6) elif string.samestr(text, "sysinfo"): _cmd_sysinfo() elif string.samestr(text, "reboot"): process.exit(0) elif _startswith(text, "hexdump "): _cmd_hexdump(text + 8) elif _startswith(text, "run "): _cmd_run(text + 4, 0) elif _startswith(text, "runb "): _cmd_run(text + 5, 1) else: if text is not None and c.Deref(text) != 0: term.insert("Unknown command. Type 'help'.") return 0 term.on_command = c.Addr(_on_command) root.mainloop() process.exit(0) return 0