Files
ViperOS/Apps/Terminal/main.py
2026-07-19 12:38:20 +08:00

327 lines
11 KiB
Python

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