import vpsdk.vpui as vpui import vpsdk.window as window import vpsdk.process as process import vpsdk.fs as fs import vpsdk.devfs as devfs import vpsdk.stdlib as stdlib import vpsdk.stdio as stdio import string import viperlib from stdint import * import t, c @__attribute__(section(".text.startup"), aligned(16)) export def _start() -> int: root: vpui.Tk = vpui.Tk() root.title("Terminal") root.set_style(window.STYLE_WIN7) root.geometry(80, 30, 640, 480) root.bg_color = uint32(0x0C0C0C) master: vpui.Tk* = &root def _sdbg(msg: str): # S4:改走 /dev/serial0(SERIAL_PUTS 私有 syscall 已删除) devfs.serial_puts(msg) _sdbg("[term] start\n") _cwd: [64]char _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 = vpui.Widget*(sbar) def _on_scroll(): act: int = sbar.action if act == 1: term.scroll_offset -= 1 elif act == 2: term.scroll_offset += 1 elif act == 3: vis: int = term._visible_lines() term.scroll_offset -= vis elif act == 4: vis2: int = term._visible_lines() term.scroll_offset += vis2 elif act == 5: aval: int = sbar.action_value if term.line_count > 0: term.scroll_offset = aval * term.line_count / 1000 vis3: int = term._visible_lines() max_off: int = 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 = _on_scroll def _startswith(s: str, prefix: str) -> int: plen: sizet = string.strlen(prefix) if string.strncmp(s, prefix, plen) == 0: return 1 return 0 def _build_path(out: str, out_size: int, rel: str): if *rel == 47: string.strncpy(out, rel, out_size - 1) else: i: int = 0 for i in range(63): ch: char = _cwd[i] *(out + i) = ch if ch == 0: break cwd_len: int = i if cwd_len > 0 and _cwd[cwd_len - 1] != 47: *(out + cwd_len) = char(47) cwd_len += 1 j: int = 0 for j in range(out_size - 1 - cwd_len): ch2: char = *(rel + j) *(out + cwd_len + j) = ch2 if ch2 == 0: break *(out + out_size - 1) = char(0) def _print_dir_entry(name: str, is_dir: int): buf: [80]char j: int = 0 for j in range(78): ch: char = *(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(&buf[0]) def _cmd_cd(path: str): if path is None or *path == 0: _cwd[0] = 47 for i in range(1, 64): _cwd[i] = 0 return full: [256]char _build_path(&full[0], 256, path) dd: int = fs.opendir(&full[0]) if dd < 0: term.insert("Error: dir not found") return fs.closedir(dd) string.strncpy(&_cwd[0], &full[0], 63) _cwd[63] = 0 def _cmd_ls(): dd: int = fs.opendir(&_cwd[0]) if dd < 0: term.insert("Error: cannot open dir") return info: [320]char string.memset(&info[0], 0, 320) while True: result: int = fs.readdir(dd, &info[0]) if result != 0: break attr_val: uint8 = uint8(*(&info[4])) name_off: int = 16 name_ptr: str = &info[name_off] if *name_ptr == 0: break if *name_ptr == 46: if *(name_ptr + 1) == 0: string.memset(&info[0], 0, 320) continue if *(name_ptr + 1) == 46 and *(name_ptr + 2) == 0: string.memset(&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(&info[0], 0, 320) fs.closedir(dd) def _cmd_cat(path: str): full: [256]char _build_path(&full[0], 256, path) fd: int = fs.open(&full[0], fs.O_RDONLY) if fd < 0: term.insert("Error: file not found") return buf: [80]char while True: string.memset(&buf[0], 0, 80) n: int = fs.read(fd, &buf[0], 78) if n <= 0: break if n > 78: n = 78 buf[n] = 0 term.insert_ptr(&buf[0]) fs.close(fd) def _cmd_mkdir(path: str): full: [256]char _build_path(&full[0], 256, path) result: int = fs.mkdir(&full[0]) if result < 0: term.insert("Error: mkdir failed") else: term.insert("Directory created") def _cmd_rm(path: str): full: [256]char _build_path(&full[0], 256, path) result: int = fs.remove(&full[0]) if result < 0: term.insert("Error: remove failed") else: term.insert("Removed") def _cmd_touch(path: str): full: [256]char _build_path(&full[0], 256, path) fd: int = fs.open(&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: [256]char _build_path(&full[0], 256, path) fd: int = fs.open(&full[0], fs.O_RDONLY) if fd < 0: term.insert("Error: file not found") return offset: int = 0 buf: [16]char while True: string.memset(&buf[0], 0, 16) n: int = fs.read(fd, &buf[0], 16) if n <= 0: break if n > 16: n = 16 line: [80]char string.memset(&line[0], 0, 80) viperlib.snprintf(&line[0], 80, "%08x: ", offset) pos: int = 10 j: int = 0 for j in range(16): if j < n: ub: uint32 = uint32(buf[j]) & 0xFF hi: int = int(ub >> 4) lo: int = int(ub & 0xF) if hi < 10: line[pos] = char(48 + hi) else: line[pos] = char(65 + hi - 10) pos += 1 if lo < 10: line[pos] = char(48 + lo) else: line[pos] = char(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: uint32 = uint32(buf[j]) & 0xFF if b2 >= 32 and b2 < 127: line[pos] = char(b2) else: line[pos] = 46 pos += 1 line[pos] = 0 term.insert_ptr(&line[0]) offset += n fs.close(fd) def _cmd_run(path: str, blocking: int): full: [256]char _build_path(&full[0], 256, path) pid: int = process.spawn(&full[0], blocking) if pid < 0: term.insert("Error: cannot spawn") elif blocking: term.insert("Process exited") else: msg: [32]char viperlib.snprintf(&msg[0], 32, "Spawned pid=%d", pid) term.insert_ptr(&msg[0]) def _on_command() -> int: _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(&_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 *text != 0: term.insert("Unknown command. Type 'help'.") return 0 term.on_command = _on_command root.mainloop() process.exit(0) return 0