内核:删掉 SERIAL_PUTS 的枚举项/派发分支/处理函数(内核自身的 serial.puts 是直接驱动调用,不受影响)。SDK:vpsdk/devfs.vp 新增 serial_puts()(惰性 open /dev/serial0 一次 + write),syscall.vp 删掉该成员。 调用点全部切到 devfs.serial_puts:vpsdk/stdio.vp 的 printf、vpsdk/vpui.vp 的 _serial_puts、Apps/Terminal 的 _sdbg、Apps/Explorer 的 _dbg、Libs/SerialLogger 的 log_info/log_warn(.so 同样走设备节点)。顺带清掉因此失效的 import(vpui 的 _syscall、Terminal 的 _syscall、Explorer 的 syscall)。 至此私有段只剩 7 项:TELL/SIZE/OPENDIR/READDIR/CLOSEDIR(可由 lseek/fstat/openat+getdents64 表达)与 LOAD_SO/SO_CALL1(动态库加载待下沉用户层)。
329 lines
11 KiB
Plaintext
329 lines
11 KiB
Plaintext
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
|