Files
ViperOS/Apps/Terminal/main.vp
T

328 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.syscall as _syscall
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):
_syscall._syscall1(uint64(18), uint64(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