327 lines
11 KiB
Python
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
|